verilog.js 19 KB

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