xref: /OpenGrok/opengrok-indexer/src/main/jflex/analysis/tcl/TclXref.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) 2008, 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 Tcl file
27  */
28 
29 package org.opengrok.indexer.analysis.tcl;
30 
31 import java.io.IOException;
32 import org.opengrok.indexer.analysis.JFlexSymbolMatcher;
33 import org.opengrok.indexer.web.HtmlConsts;
34 %%
35 %public
36 %class TclXref
37 %extends JFlexSymbolMatcher
38 %unicode
39 %int
40 %char
41 %include ../CommonLexer.lexh
42 %include ../CommonXref.lexh
43 %{
44   private int braceCount;
45 
46   @Override
reset()47   public void reset() {
48       super.reset();
49       braceCount = 0;
50   }
51 
52   @Override
yypop()53   public void yypop() throws IOException {
54       onDisjointSpanChanged(null, yychar);
55       super.yypop();
56   }
57 
58   /**
59    * Write {@code whsp} to the {@code xref} output -- if the whitespace does
60    * not contain any LFs then the full String is written; otherwise, pre-LF
61    * spaces are condensed as usual.
62    * @param xref the target instance
63    * @param whsp a defined whitespace capture
64    * @throws java.io.IOException if an output error occurs
65    */
writeWhitespace(String whsp)66   private void writeWhitespace(String whsp) throws IOException {
67       int i;
68       if ((i = whsp.indexOf("\n")) == -1) {
69           onNonSymbolMatched(whsp, yychar);
70       } else {
71           int numlf = 1, off = i + 1;
72           while ((i = whsp.indexOf("\n", off)) != -1) {
73               ++numlf;
74               off = i + 1;
75           }
76           while (numlf-- > 0) onEndOfLineMatched("\n", yychar);
77           if (off < whsp.length()) {
78               onNonSymbolMatched(whsp.substring(off), yychar);
79           }
80       }
81   }
82 
chkLOC()83   protected void chkLOC() {
84       switch (yystate()) {
85           case COMMENT:
86           case SCOMMENT:
87               break;
88           default:
89               phLOC();
90               break;
91       }
92   }
93 %}
94 
95 File = [a-zA-Z] {FNameChar}+ "." ([a-zA-Z]+)
96 
97 %state STRING COMMENT SCOMMENT BRACES VARSUB2
98 
99 %include ../Common.lexh
100 %include ../CommonURI.lexh
101 %include ../CommonPath.lexh
102 %include Tcl.lexh
103 %%
104 <YYINITIAL>{
105 
106  [\{]    {
107     chkLOC();
108     onNonSymbolMatched(yytext(), yychar);
109     ++braceCount;
110     yypush(BRACES);
111  }
112 }
113 
114 <YYINITIAL, BRACES> {
115  {Number}    {
116     chkLOC();
117     onDisjointSpanChanged(HtmlConsts.NUMBER_CLASS, yychar);
118     onNonSymbolMatched(yytext(), yychar);
119     onDisjointSpanChanged(null, yychar);
120  }
121  \"     {
122     chkLOC();
123     yypush(STRING);
124     onDisjointSpanChanged(HtmlConsts.STRING_CLASS, yychar);
125     onNonSymbolMatched(yytext(), yychar);
126  }
127  "#"    {
128     yypush(SCOMMENT);
129     onDisjointSpanChanged(HtmlConsts.COMMENT_CLASS, yychar);
130     onNonSymbolMatched(yytext(), yychar);
131  }
132  {WordOperators}    {
133     chkLOC();
134     onNonSymbolMatched(yytext(), yychar);
135  }
136 }
137 
138 <YYINITIAL, STRING, BRACES> {
139     {Backslash_sub}    {
140         chkLOC();
141         onNonSymbolMatched(yytext(), yychar);
142     }
143     {Backslash_nl}    {
144         chkLOC();
145         String capture = yytext();
146         String esc = capture.substring(0, 1);
147         String whsp = capture.substring(1);
148         onNonSymbolMatched(esc, yychar);
149         writeWhitespace(whsp);
150     }
151     {Varsub1}    {
152         chkLOC();
153         String capture = yytext();
154         String sigil = capture.substring(0, 1);
155         String name = capture.substring(1);
156         onNonSymbolMatched(sigil, yychar);
157         onFilteredSymbolMatched(name, yychar, Consts.kwd);
158     }
159     {Varsub2}    {
160         chkLOC();
161         // TclXref could get away without VARSUB2 as a state, but for ease in
162         // comparing to TclSymbolTokenizer, it is modeled here too.
163         yypush(VARSUB2);
164         String capture = yytext();
165         String sigil = capture.substring(0, 1);
166         int lparen_i = capture.indexOf("(");
167         String name1 = capture.substring(1, lparen_i);
168         yypushback(capture.length() - lparen_i - 1);
169         onNonSymbolMatched(sigil, yychar);
170         if (name1.length() > 0) {
171             onFilteredSymbolMatched(name1, yychar, Consts.kwd);
172         }
173         onNonSymbolMatched("(", yychar);
174     }
175     {Varsub3}    {
176         chkLOC();
177         String capture = yytext();
178         String sigil = capture.substring(0, 2);
179         String name = capture.substring(2, capture.length() - 1);
180         String endtoken = capture.substring(capture.length() - 1);
181         onNonSymbolMatched(sigil, yychar);
182         onFilteredSymbolMatched(name, yychar, Consts.kwd);
183         onNonSymbolMatched(endtoken, yychar);
184     }
185 }
186 
187 <VARSUB2> {
188     {name_unit}+    {
189         chkLOC();
190         String name2 = yytext();
191         yypop();
192         onFilteredSymbolMatched(name2, yychar, Consts.kwd);
193     }
194 }
195 
196 <YYINITIAL, BRACES> {
197     {OrdinaryWord}    {
198         chkLOC();
199         String id = yytext();
200         onFilteredSymbolMatched(id, yychar, Consts.kwd);
201     }
202 }
203 
204 <STRING> {
205  \"     {
206     chkLOC();
207     onNonSymbolMatched(yytext(), yychar);
208     yypop();
209  }
210 }
211 
212 <BRACES> {
213     [\}]    {
214         chkLOC();
215         if (--braceCount == 0) {
216             yypop();
217         }
218         onNonSymbolMatched(yytext(), yychar);
219     }
220     [\{]    {
221         chkLOC();
222         ++braceCount;
223         onNonSymbolMatched(yytext(), yychar);
224     }
225 }
226 
227 <SCOMMENT> {
228   {WhspChar}*{EOL}    {
229     yypop();
230     onEndOfLineMatched(yytext(), yychar);
231   }
232 }
233 
234 <YYINITIAL, STRING, COMMENT, SCOMMENT, BRACES> {
235 {WhspChar}*{EOL}    { onEndOfLineMatched(yytext(), yychar); }
236  [[\s]--[\n]]    { onNonSymbolMatched(yytext(), yychar); }
237  [^\n]    { chkLOC(); onNonSymbolMatched(yytext(), yychar); }
238 }
239 
240 <STRING, COMMENT, SCOMMENT> {
241  {FPath}    {
242     chkLOC();
243     onPathlikeMatched(yytext(), '/', false, yychar);
244  }
245 
246 {File}
247         {
248         chkLOC();
249         String path = yytext();
250         onFilelikeMatched(path, yychar);
251  }
252 
253 {BrowseableURI}    {
254           chkLOC();
255           onUriMatched(yytext(), yychar);
256         }
257 
258 {FNameChar}+ "@" {FNameChar}+ "." {FNameChar}+
259         {
260           chkLOC();
261           onEmailAddressMatched(yytext(), yychar);
262         }
263 }
264