github.com/jancarloviray/community@v0.41.1-0.20170124221257-33a66c87cf2f/app/public/codemirror/mode/verilog/verilog.js (about) 1 // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 // Distributed under an MIT license: http://codemirror.net/LICENSE 3 4 (function(mod) { 5 if (typeof exports == "object" && typeof module == "object") // CommonJS 6 mod(require("../../lib/codemirror")); 7 else if (typeof define == "function" && define.amd) // AMD 8 define(["../../lib/codemirror"], mod); 9 else // Plain browser env 10 mod(CodeMirror); 11 })(function(CodeMirror) { 12 "use strict"; 13 14 CodeMirror.defineMode("verilog", function(config, parserConfig) { 15 16 var indentUnit = config.indentUnit, 17 statementIndentUnit = parserConfig.statementIndentUnit || indentUnit, 18 dontAlignCalls = parserConfig.dontAlignCalls, 19 noIndentKeywords = parserConfig.noIndentKeywords || [], 20 multiLineStrings = parserConfig.multiLineStrings, 21 hooks = parserConfig.hooks || {}; 22 23 function words(str) { 24 var obj = {}, words = str.split(" "); 25 for (var i = 0; i < words.length; ++i) obj[words[i]] = true; 26 return obj; 27 } 28 29 /** 30 * Keywords from IEEE 1800-2012 31 */ 32 var keywords = words( 33 "accept_on alias always always_comb always_ff always_latch and assert assign assume automatic before begin bind " + 34 "bins binsof bit break buf bufif0 bufif1 byte case casex casez cell chandle checker class clocking cmos config " + 35 "const constraint context continue cover covergroup coverpoint cross deassign default defparam design disable " + 36 "dist do edge else end endcase endchecker endclass endclocking endconfig endfunction endgenerate endgroup " + 37 "endinterface endmodule endpackage endprimitive endprogram endproperty endspecify endsequence endtable endtask " + 38 "enum event eventually expect export extends extern final first_match for force foreach forever fork forkjoin " + 39 "function generate genvar global highz0 highz1 if iff ifnone ignore_bins illegal_bins implements implies import " + 40 "incdir include initial inout input inside instance int integer interconnect interface intersect join join_any " + 41 "join_none large let liblist library local localparam logic longint macromodule matches medium modport module " + 42 "nand negedge nettype new nexttime nmos nor noshowcancelled not notif0 notif1 null or output package packed " + 43 "parameter pmos posedge primitive priority program property protected pull0 pull1 pulldown pullup " + 44 "pulsestyle_ondetect pulsestyle_onevent pure rand randc randcase randsequence rcmos real realtime ref reg " + 45 "reject_on release repeat restrict return rnmos rpmos rtran rtranif0 rtranif1 s_always s_eventually s_nexttime " + 46 "s_until s_until_with scalared sequence shortint shortreal showcancelled signed small soft solve specify " + 47 "specparam static string strong strong0 strong1 struct super supply0 supply1 sync_accept_on sync_reject_on " + 48 "table tagged task this throughout time timeprecision timeunit tran tranif0 tranif1 tri tri0 tri1 triand trior " + 49 "trireg type typedef union unique unique0 unsigned until until_with untyped use uwire var vectored virtual void " + 50 "wait wait_order wand weak weak0 weak1 while wildcard wire with within wor xnor xor"); 51 52 /** Operators from IEEE 1800-2012 53 unary_operator ::= 54 + | - | ! | ~ | & | ~& | | | ~| | ^ | ~^ | ^~ 55 binary_operator ::= 56 + | - | * | / | % | == | != | === | !== | ==? | !=? | && | || | ** 57 | < | <= | > | >= | & | | | ^ | ^~ | ~^ | >> | << | >>> | <<< 58 | -> | <-> 59 inc_or_dec_operator ::= ++ | -- 60 unary_module_path_operator ::= 61 ! | ~ | & | ~& | | | ~| | ^ | ~^ | ^~ 62 binary_module_path_operator ::= 63 == | != | && | || | & | | | ^ | ^~ | ~^ 64 */ 65 var isOperatorChar = /[\+\-\*\/!~&|^%=?:]/; 66 var isBracketChar = /[\[\]{}()]/; 67 68 var unsignedNumber = /\d[0-9_]*/; 69 var decimalLiteral = /\d*\s*'s?d\s*\d[0-9_]*/i; 70 var binaryLiteral = /\d*\s*'s?b\s*[xz01][xz01_]*/i; 71 var octLiteral = /\d*\s*'s?o\s*[xz0-7][xz0-7_]*/i; 72 var hexLiteral = /\d*\s*'s?h\s*[0-9a-fxz?][0-9a-fxz?_]*/i; 73 var realLiteral = /(\d[\d_]*(\.\d[\d_]*)?E-?[\d_]+)|(\d[\d_]*\.\d[\d_]*)/i; 74 75 var closingBracketOrWord = /^((\w+)|[)}\]])/; 76 var closingBracket = /[)}\]]/; 77 78 var curPunc; 79 var curKeyword; 80 81 // Block openings which are closed by a matching keyword in the form of ("end" + keyword) 82 // E.g. "task" => "endtask" 83 var blockKeywords = words( 84 "case checker class clocking config function generate interface module package" + 85 "primitive program property specify sequence table task" 86 ); 87 88 // Opening/closing pairs 89 var openClose = {}; 90 for (var keyword in blockKeywords) { 91 openClose[keyword] = "end" + keyword; 92 } 93 openClose["begin"] = "end"; 94 openClose["casex"] = "endcase"; 95 openClose["casez"] = "endcase"; 96 openClose["do" ] = "while"; 97 openClose["fork" ] = "join;join_any;join_none"; 98 openClose["covergroup"] = "endgroup"; 99 100 for (var i in noIndentKeywords) { 101 var keyword = noIndentKeywords[i]; 102 if (openClose[keyword]) { 103 openClose[keyword] = undefined; 104 } 105 } 106 107 // Keywords which open statements that are ended with a semi-colon 108 var statementKeywords = words("always always_comb always_ff always_latch assert assign assume else export for foreach forever if import initial repeat while"); 109 110 function tokenBase(stream, state) { 111 var ch = stream.peek(), style; 112 if (hooks[ch] && (style = hooks[ch](stream, state)) != false) return style; 113 if (hooks.tokenBase && (style = hooks.tokenBase(stream, state)) != false) 114 return style; 115 116 if (/[,;:\.]/.test(ch)) { 117 curPunc = stream.next(); 118 return null; 119 } 120 if (isBracketChar.test(ch)) { 121 curPunc = stream.next(); 122 return "bracket"; 123 } 124 // Macros (tick-defines) 125 if (ch == '`') { 126 stream.next(); 127 if (stream.eatWhile(/[\w\$_]/)) { 128 return "def"; 129 } else { 130 return null; 131 } 132 } 133 // System calls 134 if (ch == '$') { 135 stream.next(); 136 if (stream.eatWhile(/[\w\$_]/)) { 137 return "meta"; 138 } else { 139 return null; 140 } 141 } 142 // Time literals 143 if (ch == '#') { 144 stream.next(); 145 stream.eatWhile(/[\d_.]/); 146 return "def"; 147 } 148 // Strings 149 if (ch == '"') { 150 stream.next(); 151 state.tokenize = tokenString(ch); 152 return state.tokenize(stream, state); 153 } 154 // Comments 155 if (ch == "/") { 156 stream.next(); 157 if (stream.eat("*")) { 158 state.tokenize = tokenComment; 159 return tokenComment(stream, state); 160 } 161 if (stream.eat("/")) { 162 stream.skipToEnd(); 163 return "comment"; 164 } 165 stream.backUp(1); 166 } 167 168 // Numeric literals 169 if (stream.match(realLiteral) || 170 stream.match(decimalLiteral) || 171 stream.match(binaryLiteral) || 172 stream.match(octLiteral) || 173 stream.match(hexLiteral) || 174 stream.match(unsignedNumber) || 175 stream.match(realLiteral)) { 176 return "number"; 177 } 178 179 // Operators 180 if (stream.eatWhile(isOperatorChar)) { 181 return "meta"; 182 } 183 184 // Keywords / plain variables 185 if (stream.eatWhile(/[\w\$_]/)) { 186 var cur = stream.current(); 187 if (keywords[cur]) { 188 if (openClose[cur]) { 189 curPunc = "newblock"; 190 } 191 if (statementKeywords[cur]) { 192 curPunc = "newstatement"; 193 } 194 curKeyword = cur; 195 return "keyword"; 196 } 197 return "variable"; 198 } 199 200 stream.next(); 201 return null; 202 } 203 204 function tokenString(quote) { 205 return function(stream, state) { 206 var escaped = false, next, end = false; 207 while ((next = stream.next()) != null) { 208 if (next == quote && !escaped) {end = true; break;} 209 escaped = !escaped && next == "\\"; 210 } 211 if (end || !(escaped || multiLineStrings)) 212 state.tokenize = tokenBase; 213 return "string"; 214 }; 215 } 216 217 function tokenComment(stream, state) { 218 var maybeEnd = false, ch; 219 while (ch = stream.next()) { 220 if (ch == "/" && maybeEnd) { 221 state.tokenize = tokenBase; 222 break; 223 } 224 maybeEnd = (ch == "*"); 225 } 226 return "comment"; 227 } 228 229 function Context(indented, column, type, align, prev) { 230 this.indented = indented; 231 this.column = column; 232 this.type = type; 233 this.align = align; 234 this.prev = prev; 235 } 236 function pushContext(state, col, type) { 237 var indent = state.indented; 238 var c = new Context(indent, col, type, null, state.context); 239 return state.context = c; 240 } 241 function popContext(state) { 242 var t = state.context.type; 243 if (t == ")" || t == "]" || t == "}") { 244 state.indented = state.context.indented; 245 } 246 return state.context = state.context.prev; 247 } 248 249 function isClosing(text, contextClosing) { 250 if (text == contextClosing) { 251 return true; 252 } else { 253 // contextClosing may be mulitple keywords separated by ; 254 var closingKeywords = contextClosing.split(";"); 255 for (var i in closingKeywords) { 256 if (text == closingKeywords[i]) { 257 return true; 258 } 259 } 260 return false; 261 } 262 } 263 264 function buildElectricInputRegEx() { 265 // Reindentation should occur on any bracket char: {}()[] 266 // or on a match of any of the block closing keywords, at 267 // the end of a line 268 var allClosings = []; 269 for (var i in openClose) { 270 if (openClose[i]) { 271 var closings = openClose[i].split(";"); 272 for (var j in closings) { 273 allClosings.push(closings[j]); 274 } 275 } 276 } 277 var re = new RegExp("[{}()\\[\\]]|(" + allClosings.join("|") + ")$"); 278 return re; 279 } 280 281 // Interface 282 return { 283 284 // Regex to force current line to reindent 285 electricInput: buildElectricInputRegEx(), 286 287 startState: function(basecolumn) { 288 var state = { 289 tokenize: null, 290 context: new Context((basecolumn || 0) - indentUnit, 0, "top", false), 291 indented: 0, 292 startOfLine: true 293 }; 294 if (hooks.startState) hooks.startState(state); 295 return state; 296 }, 297 298 token: function(stream, state) { 299 var ctx = state.context; 300 if (stream.sol()) { 301 if (ctx.align == null) ctx.align = false; 302 state.indented = stream.indentation(); 303 state.startOfLine = true; 304 } 305 if (hooks.token) hooks.token(stream, state); 306 if (stream.eatSpace()) return null; 307 curPunc = null; 308 curKeyword = null; 309 var style = (state.tokenize || tokenBase)(stream, state); 310 if (style == "comment" || style == "meta" || style == "variable") return style; 311 if (ctx.align == null) ctx.align = true; 312 313 if (curPunc == ctx.type) { 314 popContext(state); 315 } else if ((curPunc == ";" && ctx.type == "statement") || 316 (ctx.type && isClosing(curKeyword, ctx.type))) { 317 ctx = popContext(state); 318 while (ctx && ctx.type == "statement") ctx = popContext(state); 319 } else if (curPunc == "{") { 320 pushContext(state, stream.column(), "}"); 321 } else if (curPunc == "[") { 322 pushContext(state, stream.column(), "]"); 323 } else if (curPunc == "(") { 324 pushContext(state, stream.column(), ")"); 325 } else if (ctx && ctx.type == "endcase" && curPunc == ":") { 326 pushContext(state, stream.column(), "statement"); 327 } else if (curPunc == "newstatement") { 328 pushContext(state, stream.column(), "statement"); 329 } else if (curPunc == "newblock") { 330 if (curKeyword == "function" && ctx && (ctx.type == "statement" || ctx.type == "endgroup")) { 331 // The 'function' keyword can appear in some other contexts where it actually does not 332 // indicate a function (import/export DPI and covergroup definitions). 333 // Do nothing in this case 334 } else if (curKeyword == "task" && ctx && ctx.type == "statement") { 335 // Same thing for task 336 } else { 337 var close = openClose[curKeyword]; 338 pushContext(state, stream.column(), close); 339 } 340 } 341 342 state.startOfLine = false; 343 return style; 344 }, 345 346 indent: function(state, textAfter) { 347 if (state.tokenize != tokenBase && state.tokenize != null) return CodeMirror.Pass; 348 if (hooks.indent) { 349 var fromHook = hooks.indent(state); 350 if (fromHook >= 0) return fromHook; 351 } 352 var ctx = state.context, firstChar = textAfter && textAfter.charAt(0); 353 if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev; 354 var closing = false; 355 var possibleClosing = textAfter.match(closingBracketOrWord); 356 if (possibleClosing) 357 closing = isClosing(possibleClosing[0], ctx.type); 358 if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : statementIndentUnit); 359 else if (closingBracket.test(ctx.type) && ctx.align && !dontAlignCalls) return ctx.column + (closing ? 0 : 1); 360 else if (ctx.type == ")" && !closing) return ctx.indented + statementIndentUnit; 361 else return ctx.indented + (closing ? 0 : indentUnit); 362 }, 363 364 blockCommentStart: "/*", 365 blockCommentEnd: "*/", 366 lineComment: "//" 367 }; 368 }); 369 370 CodeMirror.defineMIME("text/x-verilog", { 371 name: "verilog" 372 }); 373 374 CodeMirror.defineMIME("text/x-systemverilog", { 375 name: "verilog" 376 }); 377 378 // TLVVerilog mode 379 380 var tlvchScopePrefixes = { 381 ">": "property", "->": "property", "-": "hr", "|": "link", "?$": "qualifier", "?*": "qualifier", 382 "@-": "variable-3", "@": "variable-3", "?": "qualifier" 383 }; 384 385 function tlvGenIndent(stream, state) { 386 var tlvindentUnit = 2; 387 var rtnIndent = -1, indentUnitRq = 0, curIndent = stream.indentation(); 388 switch (state.tlvCurCtlFlowChar) { 389 case "\\": 390 curIndent = 0; 391 break; 392 case "|": 393 if (state.tlvPrevPrevCtlFlowChar == "@") { 394 indentUnitRq = -2; //-2 new pipe rq after cur pipe 395 break; 396 } 397 if (tlvchScopePrefixes[state.tlvPrevCtlFlowChar]) 398 indentUnitRq = 1; // +1 new scope 399 break; 400 case "M": // m4 401 if (state.tlvPrevPrevCtlFlowChar == "@") { 402 indentUnitRq = -2; //-2 new inst rq after pipe 403 break; 404 } 405 if (tlvchScopePrefixes[state.tlvPrevCtlFlowChar]) 406 indentUnitRq = 1; // +1 new scope 407 break; 408 case "@": 409 if (state.tlvPrevCtlFlowChar == "S") 410 indentUnitRq = -1; // new pipe stage after stmts 411 if (state.tlvPrevCtlFlowChar == "|") 412 indentUnitRq = 1; // 1st pipe stage 413 break; 414 case "S": 415 if (state.tlvPrevCtlFlowChar == "@") 416 indentUnitRq = 1; // flow in pipe stage 417 if (tlvchScopePrefixes[state.tlvPrevCtlFlowChar]) 418 indentUnitRq = 1; // +1 new scope 419 break; 420 } 421 var statementIndentUnit = tlvindentUnit; 422 rtnIndent = curIndent + (indentUnitRq*statementIndentUnit); 423 return rtnIndent >= 0 ? rtnIndent : curIndent; 424 } 425 426 CodeMirror.defineMIME("text/x-tlv", { 427 name: "verilog", 428 hooks: { 429 "\\": function(stream, state) { 430 var vxIndent = 0, style = false; 431 var curPunc = stream.string; 432 if ((stream.sol()) && ((/\\SV/.test(stream.string)) || (/\\TLV/.test(stream.string)))) { 433 curPunc = (/\\TLV_version/.test(stream.string)) 434 ? "\\TLV_version" : stream.string; 435 stream.skipToEnd(); 436 if (curPunc == "\\SV" && state.vxCodeActive) {state.vxCodeActive = false;}; 437 if ((/\\TLV/.test(curPunc) && !state.vxCodeActive) 438 || (curPunc=="\\TLV_version" && state.vxCodeActive)) {state.vxCodeActive = true;}; 439 style = "keyword"; 440 state.tlvCurCtlFlowChar = state.tlvPrevPrevCtlFlowChar 441 = state.tlvPrevCtlFlowChar = ""; 442 if (state.vxCodeActive == true) { 443 state.tlvCurCtlFlowChar = "\\"; 444 vxIndent = tlvGenIndent(stream, state); 445 } 446 state.vxIndentRq = vxIndent; 447 } 448 return style; 449 }, 450 tokenBase: function(stream, state) { 451 var vxIndent = 0, style = false; 452 var tlvisOperatorChar = /[\[\]=:]/; 453 var tlvkpScopePrefixs = { 454 "**":"variable-2", "*":"variable-2", "$$":"variable", "$":"variable", 455 "^^":"attribute", "^":"attribute"}; 456 var ch = stream.peek(); 457 var vxCurCtlFlowCharValueAtStart = state.tlvCurCtlFlowChar; 458 if (state.vxCodeActive == true) { 459 if (/[\[\]{}\(\);\:]/.test(ch)) { 460 // bypass nesting and 1 char punc 461 style = "meta"; 462 stream.next(); 463 } else if (ch == "/") { 464 stream.next(); 465 if (stream.eat("/")) { 466 stream.skipToEnd(); 467 style = "comment"; 468 state.tlvCurCtlFlowChar = "S"; 469 } else { 470 stream.backUp(1); 471 } 472 } else if (ch == "@") { 473 // pipeline stage 474 style = tlvchScopePrefixes[ch]; 475 state.tlvCurCtlFlowChar = "@"; 476 stream.next(); 477 stream.eatWhile(/[\w\$_]/); 478 } else if (stream.match(/\b[mM]4+/, true)) { // match: function(pattern, consume, caseInsensitive) 479 // m4 pre proc 480 stream.skipTo("("); 481 style = "def"; 482 state.tlvCurCtlFlowChar = "M"; 483 } else if (ch == "!" && stream.sol()) { 484 // v stmt in tlv region 485 // state.tlvCurCtlFlowChar = "S"; 486 style = "comment"; 487 stream.next(); 488 } else if (tlvisOperatorChar.test(ch)) { 489 // operators 490 stream.eatWhile(tlvisOperatorChar); 491 style = "operator"; 492 } else if (ch == "#") { 493 // phy hier 494 state.tlvCurCtlFlowChar = (state.tlvCurCtlFlowChar == "") 495 ? ch : state.tlvCurCtlFlowChar; 496 stream.next(); 497 stream.eatWhile(/[+-]\d/); 498 style = "tag"; 499 } else if (tlvkpScopePrefixs.propertyIsEnumerable(ch)) { 500 // special TLV operators 501 style = tlvkpScopePrefixs[ch]; 502 state.tlvCurCtlFlowChar = state.tlvCurCtlFlowChar == "" ? "S" : state.tlvCurCtlFlowChar; // stmt 503 stream.next(); 504 stream.match(/[a-zA-Z_0-9]+/); 505 } else if (style = tlvchScopePrefixes[ch] || false) { 506 // special TLV operators 507 state.tlvCurCtlFlowChar = state.tlvCurCtlFlowChar == "" ? ch : state.tlvCurCtlFlowChar; 508 stream.next(); 509 stream.match(/[a-zA-Z_0-9]+/); 510 } 511 if (state.tlvCurCtlFlowChar != vxCurCtlFlowCharValueAtStart) { // flow change 512 vxIndent = tlvGenIndent(stream, state); 513 state.vxIndentRq = vxIndent; 514 } 515 } 516 return style; 517 }, 518 token: function(stream, state) { 519 if (state.vxCodeActive == true && stream.sol() && state.tlvCurCtlFlowChar != "") { 520 state.tlvPrevPrevCtlFlowChar = state.tlvPrevCtlFlowChar; 521 state.tlvPrevCtlFlowChar = state.tlvCurCtlFlowChar; 522 state.tlvCurCtlFlowChar = ""; 523 } 524 }, 525 indent: function(state) { 526 return (state.vxCodeActive == true) ? state.vxIndentRq : -1; 527 }, 528 startState: function(state) { 529 state.tlvCurCtlFlowChar = ""; 530 state.tlvPrevCtlFlowChar = ""; 531 state.tlvPrevPrevCtlFlowChar = ""; 532 state.vxCodeActive = true; 533 state.vxIndentRq = 0; 534 } 535 } 536 }); 537 });