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