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