xref: /OpenGrok/opengrok-indexer/src/main/jflex/analysis/rust/RustXref.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) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
22  * Portions Copyright (c) 2016 Nikolay Denev.
23  * Portions Copyright (c) 2017, Chris Fraire <cfraire@me.com>.
24  */
25 
26 /*
27  * Cross reference a Rust file
28  */
29 
30 package org.opengrok.indexer.analysis.rust;
31 
32 import java.io.IOException;
33 import org.opengrok.indexer.analysis.JFlexSymbolMatcher;
34 import org.opengrok.indexer.analysis.ScopeAction;
35 import org.opengrok.indexer.util.StringUtils;
36 import org.opengrok.indexer.web.HtmlConsts;
37 %%
38 %public
39 %class RustXref
40 %extends JFlexSymbolMatcher
41 %unicode
42 %int
43 %char
44 %include ../CommonLexer.lexh
45 %include ../CommonXref.lexh
46 %{
47   /**
48    * Stores the number of hashes beginning and ending a raw string or raw byte
49    * string. E.g., r##"blah"## has rawHashCount == 2.
50    */
51   int rawHashCount;
52 
53   int nestedComment;
54 
55   @Override
reset()56   public void reset() {
57       super.reset();
58       rawHashCount = 0;
59       nestedComment = 0;
60   }
61 
62   @Override
yypop()63   public void yypop() throws IOException {
64       onDisjointSpanChanged(null, yychar);
65       super.yypop();
66   }
67 
chkLOC()68   protected void chkLOC() {
69       switch (yystate()) {
70           case COMMENT:
71           case SCOMMENT:
72               break;
73           default:
74               phLOC();
75               break;
76       }
77   }
78 %}
79 
80 File = [a-zA-Z]{FNameChar}* "." ([Rr][Ss] | [Cc][Oo][Nn][Ff] | [Tt][Xx][Tt] |
81     [Hh][Tt][Mm][Ll]? | [Xx][Mm][Ll] | [Ii][Nn][Ii] | [Dd][Ii][Ff][Ff] |
82     [Pp][Aa][Tt][Cc][Hh])
83 
84 %state  STRING RSTRING COMMENT SCOMMENT
85 
86 %include ../Common.lexh
87 %include ../CommonURI.lexh
88 %include ../CommonPath.lexh
89 %include Rust.lexh
90 %%
91 <YYINITIAL> {
92     \{ { chkLOC(); onScopeChanged(ScopeAction.INC, yytext(), yychar); }
93     \} { chkLOC(); onScopeChanged(ScopeAction.DEC, yytext(), yychar); }
94     \; { chkLOC(); onScopeChanged(ScopeAction.END, yytext(), yychar); }
95     {Identifier} {
96         chkLOC();
97         String id = yytext();
98         onFilteredSymbolMatched(id, yychar, Consts.kwd);
99     }
100     "<" ({File}|{FPath}) ">" {
101         chkLOC();
102         onNonSymbolMatched("<", yychar);
103         String path = yytext();
104         path = path.substring(1, path.length() - 1);
105         onFilelikeMatched(path, yychar + 1);
106         onNonSymbolMatched(">", yychar + 1 + path.length());
107     }
108     {Number} {
109         chkLOC();
110         onDisjointSpanChanged(HtmlConsts.NUMBER_CLASS, yychar);
111         onNonSymbolMatched(yytext(), yychar);
112         onDisjointSpanChanged(null, yychar);
113     }
114     [b]?\" {
115         chkLOC();
116         yypush(STRING);
117         onDisjointSpanChanged(HtmlConsts.STRING_CLASS, yychar);
118         onNonSymbolMatched(yytext(), yychar);
119     }
120     [b]?[r][#]*\" {
121         chkLOC();
122         yypush(RSTRING);
123         onDisjointSpanChanged(HtmlConsts.STRING_CLASS, yychar);
124         String capture = yytext();
125         onNonSymbolMatched(capture, yychar);
126         rawHashCount = RustUtils.countRawHashes(capture);
127     }
128     [b]?\' ([^\n\r\'\\] | \\[^\n\r]) \' |
129     [b]?\' \\[xX]{HEXDIG}{HEXDIG} \' |
130     [b]?\' \\[uU]\{ {HEXDIG}{1,6} \}\'    {
131         chkLOC();
132         onDisjointSpanChanged(HtmlConsts.STRING_CLASS, yychar);
133         onNonSymbolMatched(yytext(), yychar);
134         onDisjointSpanChanged(null, yychar);
135     }
136     "//" {
137         yypush(SCOMMENT);
138         onDisjointSpanChanged(HtmlConsts.COMMENT_CLASS, yychar);
139         onNonSymbolMatched(yytext(), yychar);
140     }
141     "/*"  {
142         ++nestedComment;
143         yypush(COMMENT);
144         onDisjointSpanChanged(HtmlConsts.COMMENT_CLASS, yychar);
145         onNonSymbolMatched(yytext(), yychar);
146     }
147 }
148 
149 <STRING> {
150     \\[\"\\]    { chkLOC(); onNonSymbolMatched(yytext(), yychar); }
151     \"    {
152         chkLOC();
153         onNonSymbolMatched(yytext(), yychar);
154         yypop();
155     }
156 }
157 
158 <RSTRING> {
159     \"[#]*    {
160         chkLOC();
161         String capture = yytext();
162         if (RustUtils.isRawEnding(capture, rawHashCount)) {
163             String ender = capture.substring(0, 1 + rawHashCount);
164             onNonSymbolMatched(ender, yychar);
165             yypop();
166             int excess = capture.length() - ender.length();
167             if (excess > 0) yypushback(excess);
168         } else {
169             onNonSymbolMatched(capture, yychar);
170         }
171     }
172 }
173 
174 <STRING, RSTRING> {
175     {WhspChar}*{EOL}    {
176         onDisjointSpanChanged(null, yychar);
177         onEndOfLineMatched(yytext(), yychar);
178         onDisjointSpanChanged(HtmlConsts.STRING_CLASS, yychar);
179     }
180 }
181 
182 <COMMENT> {
183     "*/"    {
184         onNonSymbolMatched(yytext(), yychar);
185         if (--nestedComment == 0) yypop();
186     }
187     "/*"    {
188         ++nestedComment;
189         onNonSymbolMatched(yytext(), yychar);
190     }
191 }
192 
193 <SCOMMENT> {
194     {WhspChar}*{EOL} {
195         yypop();
196         onEndOfLineMatched(yytext(), yychar);
197     }
198 }
199 
200 <YYINITIAL, STRING, RSTRING, COMMENT, SCOMMENT> {
201     {WhspChar}*{EOL}    { onEndOfLineMatched(yytext(), yychar); }
202     [[\s]--[\n]]    { onNonSymbolMatched(yytext(), yychar); }
203     [^\n]    { chkLOC(); onNonSymbolMatched(yytext(), yychar); }
204 }
205 
206 <STRING, SCOMMENT> {
207     {FPath}    {
208         chkLOC();
209         onPathlikeMatched(yytext(), '/', false, yychar);
210     }
211 
212     {File} {
213         chkLOC();
214         String path = yytext();
215         onFilelikeMatched(path, yychar);
216     }
217 
218     {FNameChar}+ "@" {FNameChar}+ "." {FNameChar}+ {
219         chkLOC();
220         onEmailAddressMatched(yytext(), yychar);
221     }
222 }
223 
224 <STRING, RSTRING, SCOMMENT> {
225     {BrowseableURI}    {
226         chkLOC();
227         onUriMatched(yytext(), yychar);
228     }
229 }
230 
231 <COMMENT> {
232     {BrowseableURI}    {
233         onUriMatched(yytext(), yychar, StringUtils.END_C_COMMENT);
234     }
235 }
236