xref: /OpenGrok/opengrok-indexer/src/main/jflex/analysis/scala/ScalaXref.lex (revision d219b4cea555a12b602d2d5518daa22134ad4879)
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) 2006, 2021, Oracle and/or its affiliates. All rights reserved.
22  * Portions Copyright (c) 2017, Chris Fraire <cfraire@me.com>.
23  */
24 
25 /*
26  * Cross reference a Scala file
27  */
28 
29 package org.opengrok.indexer.analysis.scala;
30 
31 import java.io.IOException;
32 import org.opengrok.indexer.analysis.JFlexSymbolMatcher;
33 import org.opengrok.indexer.analysis.EmphasisHint;
34 import org.opengrok.indexer.util.StringUtils;
35 import org.opengrok.indexer.web.HtmlConsts;
36 %%
37 %public
38 %class ScalaXref
39 %extends JFlexSymbolMatcher
40 %unicode
41 %int
42 %char
43 %include ../CommonLexer.lexh
44 %include ../CommonXref.lexh
45 %{
46   /* Must match {WhspChar}+ regex */
47   private final static String WHITE_SPACE = "[ \\t\\f]+";
48 
49   private int nestedComment;
50 
51   @Override
reset()52   public void reset() {
53       super.reset();
54       nestedComment = 0;
55   }
56 
57   @Override
yypop()58   public void yypop() throws IOException {
59       onDisjointSpanChanged(null, yychar);
60       super.yypop();
61   }
62 
pushQuotedString(int state,String capture)63   private void pushQuotedString(int state, String capture) throws IOException {
64       int qoff = capture.indexOf("\"");
65       String id = capture.substring(0, qoff);
66       String quotes = capture.substring(qoff);
67       onNonSymbolMatched(id, yychar);
68       yypush(state);
69       onDisjointSpanChanged(HtmlConsts.STRING_CLASS, yychar);
70       onNonSymbolMatched(quotes, yychar);
71   }
72 
chkLOC()73   protected void chkLOC() {
74       switch (yystate()) {
75           case SCOMMENT:
76           case COMMENT:
77           case JAVADOC:
78               break;
79           default:
80               phLOC();
81               break;
82       }
83   }
84 %}
85 
86 File = [a-zA-Z]{FNameChar}* "." ([Ss][Cc][Aa][Ll][Aa] |
87     [Pp][Rr][Oo][Pp][Ee][Rr][Tt][Ii][Ee][Ss] | [Pp][Rr][Oo][Pp][Ss] |
88     [Xx][Mm][Ll] | [Cc][Oo][Nn][Ff] | [Tt][Xx][Tt] | [Hh][Tt][Mm][Ll]? |
89     [Ii][Nn][Ii] | [Jj][Nn][Ll][Pp] | [Jj][Aa][Dd] | [Dd][Ii][Ff][Ff] |
90     [Pp][Aa][Tt][Cc][Hh])
91 
92 JavadocWithClassArg = "@throws" | "@exception"
93 JavadocWithParamNameArg = "@param"
94 
95 ClassName = ({Identifier} ".")* {Identifier}
96 ParamName = {Identifier} | "<" {Identifier} ">"
97 
98 /*
99  * STRING : string literal
100  * ISTRING : string literal with interpolation
101  * MSTRING : multi-line string literal
102  * IMSTRING : multi-line string literal with interpolation
103  * QSTRING : character literal
104  * SCOMMENT : single-line comment
105  * COMMENT : multi-line comment
106  * JAVADOC : multi-line comment with JavaDoc conventions
107  */
108 %state STRING ISTRING MSTRING IMSTRING QSTRING SCOMMENT COMMENT JAVADOC
109 
110 %include ../Common.lexh
111 %include ../CommonURI.lexh
112 %include ../CommonPath.lexh
113 %include Scala.lexh
114 %%
115 <YYINITIAL>{
116 
117 {Identifier} {
118     chkLOC();
119     String id = yytext();
120     onFilteredSymbolMatched(id, yychar, Consts.kwd);
121 }
122 
123  {BacktickIdentifier} {
124     chkLOC();
125     String capture = yytext();
126     String id = capture.substring(1, capture.length() - 1);
127     onNonSymbolMatched("`", yychar);
128     onFilteredSymbolMatched(id, yychar, null);
129     onNonSymbolMatched("`", yychar);
130  }
131 
132  {OpSuffixIdentifier}    {
133     chkLOC();
134     String capture = yytext();
135     int uoff = capture.lastIndexOf("_");
136     // ctags include the "_" in the symbol, so follow that too.
137     String id = capture.substring(0, uoff + 1);
138     String rest = capture.substring(uoff + 1);
139     onFilteredSymbolMatched(id, yychar, Consts.kwd);
140     onNonSymbolMatched(rest, yychar);
141  }
142 
143 "<" ({File}|{FPath}) ">" {
144         chkLOC();
145         onNonSymbolMatched("<", yychar);
146         String path = yytext();
147         path = path.substring(1, path.length() - 1);
148         onFilelikeMatched(path, yychar + 1);
149         onNonSymbolMatched(">", yychar + 1 + path.length());
150 }
151 
152 /*{Hier}
153         { onPathlikeMatched(yytext(), '.', false, yychar); }
154 */
155  {Number}        {
156     chkLOC();
157     onDisjointSpanChanged(HtmlConsts.NUMBER_CLASS, yychar);
158     onNonSymbolMatched(yytext(), yychar);
159     onDisjointSpanChanged(null, yychar);
160  }
161 
162  ([fs] | "raw") \"    {
163     chkLOC();
164     pushQuotedString(ISTRING, yytext());
165  }
166  {Identifier}? \"    {
167     chkLOC();
168     pushQuotedString(STRING, yytext());
169  }
170  \'     {
171     chkLOC();
172     yypush(QSTRING);
173     onDisjointSpanChanged(HtmlConsts.STRING_CLASS, yychar);
174     onNonSymbolMatched(yytext(), yychar);
175  }
176  ([fs] | "raw") \"\"\"    {
177     chkLOC();
178     pushQuotedString(IMSTRING, yytext());
179  }
180  {Identifier}? \"\"\"    {
181     chkLOC();
182     pushQuotedString(MSTRING, yytext());
183  }
184  "/*" "*"+ "/"    {
185     onDisjointSpanChanged(HtmlConsts.COMMENT_CLASS, yychar);
186     onNonSymbolMatched(yytext(), yychar);
187     onDisjointSpanChanged(null, yychar);
188  }
189  "/*" "*"+    {
190     if (nestedComment++ == 0) {
191         yypush(JAVADOC);
192         onDisjointSpanChanged(HtmlConsts.COMMENT_CLASS, yychar);
193     }
194     onNonSymbolMatched(yytext(), yychar);
195  }
196  "//"   {
197     yypush(SCOMMENT);
198     onDisjointSpanChanged(HtmlConsts.COMMENT_CLASS, yychar);
199     onNonSymbolMatched(yytext(), yychar);
200  }
201 }
202 
203 <STRING, ISTRING> {
204  \\[\"\\]    { chkLOC(); onNonSymbolMatched(yytext(), yychar); }
205  \"     {
206     chkLOC();
207     onNonSymbolMatched(yytext(), yychar);
208     yypop();
209  }
210 }
211 
212 <ISTRING, IMSTRING> {
213     /*
214      * TODO : support "arbitrary expressions" inside curly brackets
215      */
216     \$ {Identifier}    {
217         chkLOC();
218         String capture = yytext();
219         String sigil = capture.substring(0, 1);
220         String id = capture.substring(1);
221         onNonSymbolMatched(sigil, yychar);
222         onDisjointSpanChanged(null, yychar);
223         onFilteredSymbolMatched(id, yychar, Consts.kwd);
224         onDisjointSpanChanged(HtmlConsts.STRING_CLASS, yychar);
225     }
226 }
227 
228 <QSTRING> {
229  \\[\'\\]    { chkLOC(); onNonSymbolMatched(yytext(), yychar); }
230  \'     {
231     chkLOC();
232     onNonSymbolMatched(yytext(), yychar);
233     yypop();
234  }
235 }
236 
237 <MSTRING, IMSTRING> {
238  /*
239   * For multi-line string, "Unicode escapes work as everywhere else, but none
240   * of the escape sequences [in 'Escape Sequences'] are interpreted."
241   */
242  \"\"\"    {
243     chkLOC();
244     onNonSymbolMatched(yytext(), yychar);
245     yypop();
246  }
247 }
248 
249 <YYINITIAL, COMMENT, JAVADOC> {
250     "/*"    {
251         if (nestedComment++ == 0) {
252             yypush(COMMENT);
253             onDisjointSpanChanged(HtmlConsts.COMMENT_CLASS, yychar);
254         }
255         onNonSymbolMatched(yytext(), yychar);
256     }
257 }
258 
259 <COMMENT, JAVADOC> {
260  "*/"    {
261     onNonSymbolMatched(yytext(), yychar);
262     if (--nestedComment == 0) {
263         yypop();
264     }
265  }
266  {WhspChar}*{EOL}    {
267     onDisjointSpanChanged(null, yychar);
268     onEndOfLineMatched(yytext(), yychar);
269     onDisjointSpanChanged(HtmlConsts.COMMENT_CLASS, yychar);
270  }
271 }
272 
273 <JAVADOC> {
274   {JavadocWithParamNameArg} {WhspChar}+ {ParamName} |
275   {JavadocWithClassArg} {WhspChar}+ {ClassName} {
276     String text = yytext();
277     String[] tokens = text.split(WHITE_SPACE, 2);
278     onNonSymbolMatched(tokens[0], EmphasisHint.STRONG, yychar);
279     onNonSymbolMatched(text.substring(tokens[0].length(), text.length() -
280         tokens[1].length()), yychar);
281     onNonSymbolMatched(tokens[1], EmphasisHint.EM, yychar);
282   }
283   "@" {Identifier} {
284     onNonSymbolMatched(yytext(), EmphasisHint.STRONG, yychar);
285   }
286 }
287 
288 <SCOMMENT> {
289   {WhspChar}*{EOL} {
290     yypop();
291     onEndOfLineMatched(yytext(), yychar);
292   }
293 }
294 
295 <YYINITIAL> {
296  {OpIdentifier}    {
297     chkLOC();
298     onNonSymbolMatched(yytext(), yychar);
299  }
300 }
301 
302 <YYINITIAL, STRING, ISTRING, MSTRING, IMSTRING, COMMENT, SCOMMENT, QSTRING,
303     JAVADOC> {
304 {WhspChar}*{EOL}    { onEndOfLineMatched(yytext(), yychar); }
305  [[\s]--[\n]]    { onNonSymbolMatched(yytext(), yychar); }
306  [^\n]    { chkLOC(); onNonSymbolMatched(yytext(), yychar); }
307 }
308 
309 <STRING, MSTRING, COMMENT, SCOMMENT, QSTRING, JAVADOC> {
310  {FPath}    {
311     chkLOC();
312     onPathlikeMatched(yytext(), '/', false, yychar);
313  }
314 
315 {File}
316         {
317         chkLOC();
318         String path = yytext();
319         onFilelikeMatched(path, yychar);
320  }
321 
322 {FNameChar}+ "@" {FNameChar}+ "." {FNameChar}+
323         {
324           chkLOC();
325           onEmailAddressMatched(yytext(), yychar);
326         }
327 }
328 
329 <STRING, MSTRING, QSTRING, SCOMMENT> {
330     {BrowseableURI}    {
331         chkLOC();
332         onUriMatched(yytext(), yychar);
333     }
334 }
335 
336 <ISTRING, IMSTRING> {
337     {BrowseableURI}    {
338         chkLOC();
339         onUriMatched(yytext(), yychar, ScalaUtils.DOLLAR_SIGN);
340     }
341 }
342 
343 <COMMENT, JAVADOC> {
344     {BrowseableURI}    {
345         onUriMatched(yytext(), yychar, StringUtils.END_C_COMMENT);
346     }
347 }
348