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  });