Skip to content

Commit 1b2a77d

Browse files
committed
Add support for OCaml. fixes #4407
1 parent 0e9f93f commit 1b2a77d

File tree

15 files changed

+1184
-0
lines changed

15 files changed

+1184
-0
lines changed

opengrok-indexer/src/main/java/org/opengrok/indexer/analysis/AnalyzerGuru.java

+2
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@
8989
import org.opengrok.indexer.analysis.kotlin.KotlinAnalyzerFactory;
9090
import org.opengrok.indexer.analysis.lisp.LispAnalyzerFactory;
9191
import org.opengrok.indexer.analysis.lua.LuaAnalyzerFactory;
92+
import org.opengrok.indexer.analysis.ocaml.OCamlAnalyzerFactory;
9293
import org.opengrok.indexer.analysis.pascal.PascalAnalyzerFactory;
9394
import org.opengrok.indexer.analysis.perl.PerlAnalyzerFactory;
9495
import org.opengrok.indexer.analysis.php.PhpAnalyzerFactory;
@@ -298,6 +299,7 @@ public class AnalyzerGuru {
298299
new HaskellAnalyzerFactory(),
299300
new GolangAnalyzerFactory(),
300301
new LuaAnalyzerFactory(),
302+
new OCamlAnalyzerFactory(),
301303
new PascalAnalyzerFactory(),
302304
new AdaAnalyzerFactory(),
303305
new RubyAnalyzerFactory(),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/*
2+
* CDDL HEADER START
3+
*
4+
* The contents of this file are subject to the terms of the
5+
* Common Development and Distribution License (the "License").
6+
* You may not use this file except in compliance with the License.
7+
*
8+
* See LICENSE.txt included in this distribution for the specific
9+
* language governing permissions and limitations under the License.
10+
*
11+
* When distributing Covered Code, include this CDDL HEADER in each
12+
* file and include the License file at LICENSE.txt.
13+
* If applicable, add the following below this CDDL HEADER, with the
14+
* fields enclosed by brackets "[]" replaced with your own identifying
15+
* information: Portions Copyright [yyyy] [name of copyright owner]
16+
*
17+
* CDDL HEADER END
18+
*/
19+
20+
/*
21+
* Copyright (c) 2025, Yelisey Romanov <progoramur@gmail.com>.
22+
*/
23+
package org.opengrok.indexer.analysis.ocaml;
24+
25+
import java.util.HashSet;
26+
import java.util.Set;
27+
28+
/**
29+
* Represents a container for a set of OCaml keywords.
30+
*/
31+
public class Consts {
32+
33+
static final Set<String> kwd = new HashSet<>();
34+
35+
static {
36+
/* OCaml 5.3.0 keywords */
37+
kwd.add("and");
38+
kwd.add("as");
39+
kwd.add("assert");
40+
kwd.add("begin");
41+
kwd.add("class");
42+
kwd.add("constraint");
43+
kwd.add("do");
44+
kwd.add("done");
45+
kwd.add("downto");
46+
kwd.add("effect");
47+
kwd.add("else");
48+
kwd.add("end");
49+
kwd.add("exception");
50+
kwd.add("external");
51+
kwd.add("false");
52+
kwd.add("for");
53+
kwd.add("fun");
54+
kwd.add("function");
55+
kwd.add("functor");
56+
kwd.add("if");
57+
kwd.add("in");
58+
kwd.add("include");
59+
kwd.add("inherit");
60+
kwd.add("initializer");
61+
kwd.add("lazy");
62+
kwd.add("let");
63+
kwd.add("match");
64+
kwd.add("method");
65+
kwd.add("module");
66+
kwd.add("mutable");
67+
kwd.add("new");
68+
kwd.add("nonrec");
69+
kwd.add("object");
70+
kwd.add("of");
71+
kwd.add("open");
72+
kwd.add("or");
73+
kwd.add("parser");
74+
kwd.add("private");
75+
kwd.add("ref");
76+
kwd.add("rec");
77+
kwd.add("sig");
78+
kwd.add("struct");
79+
kwd.add("then");
80+
kwd.add("to");
81+
kwd.add("true");
82+
kwd.add("try");
83+
kwd.add("type");
84+
kwd.add("val");
85+
kwd.add("virtual");
86+
kwd.add("when");
87+
kwd.add("while");
88+
kwd.add("with");
89+
kwd.add("lor");
90+
kwd.add("lxor");
91+
kwd.add("mod");
92+
kwd.add("land");
93+
kwd.add("lsl");
94+
kwd.add("lsr");
95+
kwd.add("asr");
96+
97+
/* OCaml 5.3.0 predefined types */
98+
/* it is possible to make a variable of such a name,
99+
though people mostly do not use this opportunity */
100+
kwd.add("bool");
101+
kwd.add("char");
102+
kwd.add("float");
103+
kwd.add("int");
104+
105+
kwd.add("bytes");
106+
kwd.add("string");
107+
108+
kwd.add("array");
109+
kwd.add("list");
110+
kwd.add("option");
111+
/* "result" is often a variable, so not adding */
112+
113+
kwd.add("unit");
114+
}
115+
116+
/** Private to enforce static. */
117+
private Consts() {
118+
}
119+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* CDDL HEADER START
3+
*
4+
* The contents of this file are subject to the terms of the
5+
* Common Development and Distribution License (the "License").
6+
* You may not use this file except in compliance with the License.
7+
*
8+
* See LICENSE.txt included in this distribution for the specific
9+
* language governing permissions and limitations under the License.
10+
*
11+
* When distributing Covered Code, include this CDDL HEADER in each
12+
* file and include the License file at LICENSE.txt.
13+
* If applicable, add the following below this CDDL HEADER, with the
14+
* fields enclosed by brackets "[]" replaced with your own identifying
15+
* information: Portions Copyright [yyyy] [name of copyright owner]
16+
*
17+
* CDDL HEADER END
18+
*/
19+
20+
/*
21+
* Copyright (c) 2025, Yelisey Romanov <progoramur@gmail.com>.
22+
*/
23+
package org.opengrok.indexer.analysis.ocaml;
24+
25+
import org.opengrok.indexer.analysis.AbstractAnalyzer;
26+
import org.opengrok.indexer.analysis.FileAnalyzerFactory;
27+
import org.opengrok.indexer.analysis.JFlexTokenizer;
28+
import org.opengrok.indexer.analysis.JFlexXref;
29+
import org.opengrok.indexer.analysis.plain.AbstractSourceCodeAnalyzer;
30+
31+
import java.io.Reader;
32+
33+
/**
34+
* Represents an analyzer for the OCaml language.
35+
*/
36+
@SuppressWarnings("java:S110")
37+
public class OCamlAnalyzer extends AbstractSourceCodeAnalyzer {
38+
39+
/**
40+
* Creates a new instance of {@link OCamlAnalyzer}.
41+
* @param factory instance
42+
*/
43+
protected OCamlAnalyzer(FileAnalyzerFactory factory) {
44+
super(factory, () -> new JFlexTokenizer(new OCamlSymbolTokenizer(
45+
AbstractAnalyzer.DUMMY_READER)));
46+
}
47+
48+
/**
49+
* @return {@code "ocaml"}
50+
*/
51+
@Override
52+
public String getCtagsLang() {
53+
return "ocaml";
54+
}
55+
56+
/**
57+
* Gets a version number to be used to tag processed documents so that
58+
* re-analysis can be re-done later if a stored version number is different
59+
* from the current implementation.
60+
* @return 20250403_00
61+
*/
62+
@Override
63+
protected int getSpecializedVersionNo() {
64+
return 20250403_00; // Edit comment above too!
65+
}
66+
67+
/**
68+
* Creates a wrapped {@link OCamlXref} instance.
69+
* @return a defined instance
70+
*/
71+
@Override
72+
protected JFlexXref newXref(Reader reader) {
73+
return new JFlexXref(new OCamlXref(reader));
74+
}
75+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* CDDL HEADER START
3+
*
4+
* The contents of this file are subject to the terms of the
5+
* Common Development and Distribution License (the "License").
6+
* You may not use this file except in compliance with the License.
7+
*
8+
* See LICENSE.txt included in this distribution for the specific
9+
* language governing permissions and limitations under the License.
10+
*
11+
* When distributing Covered Code, include this CDDL HEADER in each
12+
* file and include the License file at LICENSE.txt.
13+
* If applicable, add the following below this CDDL HEADER, with the
14+
* fields enclosed by brackets "[]" replaced with your own identifying
15+
* information: Portions Copyright [yyyy] [name of copyright owner]
16+
*
17+
* CDDL HEADER END
18+
*/
19+
20+
/*
21+
* Copyright (c) 2025, Yelisey Romanov <progoramur@gmail.com>.
22+
*/
23+
package org.opengrok.indexer.analysis.ocaml;
24+
25+
import org.opengrok.indexer.analysis.AbstractAnalyzer.Genre;
26+
import org.opengrok.indexer.analysis.FileAnalyzer;
27+
import org.opengrok.indexer.analysis.FileAnalyzerFactory;
28+
29+
/**
30+
* Represents a factory to create {@link OCamlAnalyzer} instances.
31+
*/
32+
public class OCamlAnalyzerFactory extends FileAnalyzerFactory {
33+
34+
private static final String NAME = "OCaml";
35+
36+
private static final String[] SUFFIXES = {"ML", "MLI"};
37+
38+
/**
39+
* Initializes a factory instance to associate a file extensions ".ml",
40+
* ".mli" with {@link OCamlAnalyzer}.
41+
*/
42+
public OCamlAnalyzerFactory() {
43+
super(null, null, SUFFIXES, null, null, "text/plain", Genre.PLAIN,
44+
NAME, true);
45+
}
46+
47+
/**
48+
* Creates a new {@link OCamlAnalyzer} instance.
49+
* @return a defined instance
50+
*/
51+
@Override
52+
protected FileAnalyzer newAnalyzer() {
53+
return new OCamlAnalyzer(this);
54+
}
55+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* CDDL HEADER START
3+
*
4+
* The contents of this file are subject to the terms of the
5+
* Common Development and Distribution License (the "License").
6+
* You may not use this file except in compliance with the License.
7+
*
8+
* See LICENSE.txt included in this distribution for the specific
9+
* language governing permissions and limitations under the License.
10+
*
11+
* When distributing Covered Code, include this CDDL HEADER in each
12+
* file and include the License file at LICENSE.txt.
13+
* If applicable, add the following below this CDDL HEADER, with the
14+
* fields enclosed by brackets "[]" replaced with your own identifying
15+
* information: Portions Copyright [yyyy] [name of copyright owner]
16+
*
17+
* CDDL HEADER END
18+
*/
19+
20+
/*
21+
* Copyright (c) 2025, Yelisey Romanov <progoramur@gmail.com>.
22+
*/
23+
package org.opengrok.indexer.analysis.ocaml;
24+
25+
import org.opengrok.indexer.analysis.JFlexJointLexer;
26+
import org.opengrok.indexer.analysis.JFlexSymbolMatcher;
27+
import org.opengrok.indexer.analysis.Resettable;
28+
29+
/**
30+
* Represents an abstract base class for OCaml lexers.
31+
*/
32+
@SuppressWarnings("Duplicates")
33+
abstract class OCamlLexer extends JFlexSymbolMatcher
34+
implements JFlexJointLexer, Resettable {
35+
36+
/**
37+
* Calls {@link #phLOC()} if the yystate is not COMMENT or SCOMMENT.
38+
*/
39+
public void chkLOC() {
40+
if (yystate() != COMMENT() && yystate() != SCOMMENT()) {
41+
phLOC();
42+
}
43+
}
44+
45+
/**
46+
* Subclasses must override to get the constant value created by JFlex to
47+
* represent COMMENT.
48+
*/
49+
@SuppressWarnings("java:S100")
50+
abstract int COMMENT();
51+
52+
/**
53+
* Subclasses must override to get the constant value created by JFlex to
54+
* represent SCOMMENT.
55+
*/
56+
@SuppressWarnings("java:S100")
57+
abstract int SCOMMENT();
58+
}

0 commit comments

Comments
 (0)