[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/media/vendor/codemirror/mode/erlang/ -> erlang.js (source)

   1  // CodeMirror, copyright (c) by Marijn Haverbeke and others
   2  // Distributed under an MIT license: https://codemirror.net/5/LICENSE
   3  
   4  /*jshint unused:true, eqnull:true, curly:true, bitwise:true */
   5  /*jshint undef:true, latedef:true, trailing:true */
   6  /*global CodeMirror:true */
   7  
   8  // erlang mode.
   9  // tokenizer -> token types -> CodeMirror styles
  10  // tokenizer maintains a parse stack
  11  // indenter uses the parse stack
  12  
  13  // TODO indenter:
  14  //   bit syntax
  15  //   old guard/bif/conversion clashes (e.g. "float/1")
  16  //   type/spec/opaque
  17  
  18  (function(mod) {
  19    if (typeof exports == "object" && typeof module == "object") // CommonJS
  20      mod(require("../../lib/codemirror"));
  21    else if (typeof define == "function" && define.amd) // AMD
  22      define(["../../lib/codemirror"], mod);
  23    else // Plain browser env
  24      mod(CodeMirror);
  25  })(function(CodeMirror) {
  26  "use strict";
  27  
  28  CodeMirror.defineMIME("text/x-erlang", "erlang");
  29  
  30  CodeMirror.defineMode("erlang", function(cmCfg) {
  31    "use strict";
  32  
  33  /////////////////////////////////////////////////////////////////////////////
  34  // constants
  35  
  36    var typeWords = [
  37      "-type", "-spec", "-export_type", "-opaque"];
  38  
  39    var keywordWords = [
  40      "after","begin","catch","case","cond","end","fun","if",
  41      "let","of","query","receive","try","when"];
  42  
  43    var separatorRE    = /[\->,;]/;
  44    var separatorWords = [
  45      "->",";",","];
  46  
  47    var operatorAtomWords = [
  48      "and","andalso","band","bnot","bor","bsl","bsr","bxor",
  49      "div","not","or","orelse","rem","xor"];
  50  
  51    var operatorSymbolRE    = /[\+\-\*\/<>=\|:!]/;
  52    var operatorSymbolWords = [
  53      "=","+","-","*","/",">",">=","<","=<","=:=","==","=/=","/=","||","<-","!"];
  54  
  55    var openParenRE    = /[<\(\[\{]/;
  56    var openParenWords = [
  57      "<<","(","[","{"];
  58  
  59    var closeParenRE    = /[>\)\]\}]/;
  60    var closeParenWords = [
  61      "}","]",")",">>"];
  62  
  63    var guardWords = [
  64      "is_atom","is_binary","is_bitstring","is_boolean","is_float",
  65      "is_function","is_integer","is_list","is_number","is_pid",
  66      "is_port","is_record","is_reference","is_tuple",
  67      "atom","binary","bitstring","boolean","function","integer","list",
  68      "number","pid","port","record","reference","tuple"];
  69  
  70    var bifWords = [
  71      "abs","adler32","adler32_combine","alive","apply","atom_to_binary",
  72      "atom_to_list","binary_to_atom","binary_to_existing_atom",
  73      "binary_to_list","binary_to_term","bit_size","bitstring_to_list",
  74      "byte_size","check_process_code","contact_binary","crc32",
  75      "crc32_combine","date","decode_packet","delete_module",
  76      "disconnect_node","element","erase","exit","float","float_to_list",
  77      "garbage_collect","get","get_keys","group_leader","halt","hd",
  78      "integer_to_list","internal_bif","iolist_size","iolist_to_binary",
  79      "is_alive","is_atom","is_binary","is_bitstring","is_boolean",
  80      "is_float","is_function","is_integer","is_list","is_number","is_pid",
  81      "is_port","is_process_alive","is_record","is_reference","is_tuple",
  82      "length","link","list_to_atom","list_to_binary","list_to_bitstring",
  83      "list_to_existing_atom","list_to_float","list_to_integer",
  84      "list_to_pid","list_to_tuple","load_module","make_ref","module_loaded",
  85      "monitor_node","node","node_link","node_unlink","nodes","notalive",
  86      "now","open_port","pid_to_list","port_close","port_command",
  87      "port_connect","port_control","pre_loaded","process_flag",
  88      "process_info","processes","purge_module","put","register",
  89      "registered","round","self","setelement","size","spawn","spawn_link",
  90      "spawn_monitor","spawn_opt","split_binary","statistics",
  91      "term_to_binary","time","throw","tl","trunc","tuple_size",
  92      "tuple_to_list","unlink","unregister","whereis"];
  93  
  94  // upper case: [A-Z] [Ø-Þ] [À-Ö]
  95  // lower case: [a-z] [ß-ö] [ø-ÿ]
  96    var anumRE       = /[\w@Ø-ÞÀ-Öß-öø-ÿ]/;
  97    var escapesRE    =
  98      /[0-7]{1,3}|[bdefnrstv\\"']|\^[a-zA-Z]|x[0-9a-zA-Z]{2}|x{[0-9a-zA-Z]+}/;
  99  
 100  /////////////////////////////////////////////////////////////////////////////
 101  // tokenizer
 102  
 103    function tokenizer(stream,state) {
 104      // in multi-line string
 105      if (state.in_string) {
 106        state.in_string = (!doubleQuote(stream));
 107        return rval(state,stream,"string");
 108      }
 109  
 110      // in multi-line atom
 111      if (state.in_atom) {
 112        state.in_atom = (!singleQuote(stream));
 113        return rval(state,stream,"atom");
 114      }
 115  
 116      // whitespace
 117      if (stream.eatSpace()) {
 118        return rval(state,stream,"whitespace");
 119      }
 120  
 121      // attributes and type specs
 122      if (!peekToken(state) &&
 123          stream.match(/-\s*[a-zß-öø-ÿ][\wØ-ÞÀ-Öß-öø-ÿ]*/)) {
 124        if (is_member(stream.current(),typeWords)) {
 125          return rval(state,stream,"type");
 126        }else{
 127          return rval(state,stream,"attribute");
 128        }
 129      }
 130  
 131      var ch = stream.next();
 132  
 133      // comment
 134      if (ch == '%') {
 135        stream.skipToEnd();
 136        return rval(state,stream,"comment");
 137      }
 138  
 139      // colon
 140      if (ch == ":") {
 141        return rval(state,stream,"colon");
 142      }
 143  
 144      // macro
 145      if (ch == '?') {
 146        stream.eatSpace();
 147        stream.eatWhile(anumRE);
 148        return rval(state,stream,"macro");
 149      }
 150  
 151      // record
 152      if (ch == "#") {
 153        stream.eatSpace();
 154        stream.eatWhile(anumRE);
 155        return rval(state,stream,"record");
 156      }
 157  
 158      // dollar escape
 159      if (ch == "$") {
 160        if (stream.next() == "\\" && !stream.match(escapesRE)) {
 161          return rval(state,stream,"error");
 162        }
 163        return rval(state,stream,"number");
 164      }
 165  
 166      // dot
 167      if (ch == ".") {
 168        return rval(state,stream,"dot");
 169      }
 170  
 171      // quoted atom
 172      if (ch == '\'') {
 173        if (!(state.in_atom = (!singleQuote(stream)))) {
 174          if (stream.match(/\s*\/\s*[0-9]/,false)) {
 175            stream.match(/\s*\/\s*[0-9]/,true);
 176            return rval(state,stream,"fun");      // 'f'/0 style fun
 177          }
 178          if (stream.match(/\s*\(/,false) || stream.match(/\s*:/,false)) {
 179            return rval(state,stream,"function");
 180          }
 181        }
 182        return rval(state,stream,"atom");
 183      }
 184  
 185      // string
 186      if (ch == '"') {
 187        state.in_string = (!doubleQuote(stream));
 188        return rval(state,stream,"string");
 189      }
 190  
 191      // variable
 192      if (/[A-Z_Ø-ÞÀ-Ö]/.test(ch)) {
 193        stream.eatWhile(anumRE);
 194        return rval(state,stream,"variable");
 195      }
 196  
 197      // atom/keyword/BIF/function
 198      if (/[a-z_ß-öø-ÿ]/.test(ch)) {
 199        stream.eatWhile(anumRE);
 200  
 201        if (stream.match(/\s*\/\s*[0-9]/,false)) {
 202          stream.match(/\s*\/\s*[0-9]/,true);
 203          return rval(state,stream,"fun");      // f/0 style fun
 204        }
 205  
 206        var w = stream.current();
 207  
 208        if (is_member(w,keywordWords)) {
 209          return rval(state,stream,"keyword");
 210        }else if (is_member(w,operatorAtomWords)) {
 211          return rval(state,stream,"operator");
 212        }else if (stream.match(/\s*\(/,false)) {
 213          // 'put' and 'erlang:put' are bifs, 'foo:put' is not
 214          if (is_member(w,bifWords) &&
 215              ((peekToken(state).token != ":") ||
 216               (peekToken(state,2).token == "erlang"))) {
 217            return rval(state,stream,"builtin");
 218          }else if (is_member(w,guardWords)) {
 219            return rval(state,stream,"guard");
 220          }else{
 221            return rval(state,stream,"function");
 222          }
 223        }else if (lookahead(stream) == ":") {
 224          if (w == "erlang") {
 225            return rval(state,stream,"builtin");
 226          } else {
 227            return rval(state,stream,"function");
 228          }
 229        }else if (is_member(w,["true","false"])) {
 230          return rval(state,stream,"boolean");
 231        }else{
 232          return rval(state,stream,"atom");
 233        }
 234      }
 235  
 236      // number
 237      var digitRE      = /[0-9]/;
 238      var radixRE      = /[0-9a-zA-Z]/;         // 36#zZ style int
 239      if (digitRE.test(ch)) {
 240        stream.eatWhile(digitRE);
 241        if (stream.eat('#')) {                // 36#aZ  style integer
 242          if (!stream.eatWhile(radixRE)) {
 243            stream.backUp(1);                 //"36#" - syntax error
 244          }
 245        } else if (stream.eat('.')) {       // float
 246          if (!stream.eatWhile(digitRE)) {
 247            stream.backUp(1);        // "3." - probably end of function
 248          } else {
 249            if (stream.eat(/[eE]/)) {        // float with exponent
 250              if (stream.eat(/[-+]/)) {
 251                if (!stream.eatWhile(digitRE)) {
 252                  stream.backUp(2);            // "2e-" - syntax error
 253                }
 254              } else {
 255                if (!stream.eatWhile(digitRE)) {
 256                  stream.backUp(1);            // "2e" - syntax error
 257                }
 258              }
 259            }
 260          }
 261        }
 262        return rval(state,stream,"number");   // normal integer
 263      }
 264  
 265      // open parens
 266      if (nongreedy(stream,openParenRE,openParenWords)) {
 267        return rval(state,stream,"open_paren");
 268      }
 269  
 270      // close parens
 271      if (nongreedy(stream,closeParenRE,closeParenWords)) {
 272        return rval(state,stream,"close_paren");
 273      }
 274  
 275      // separators
 276      if (greedy(stream,separatorRE,separatorWords)) {
 277        return rval(state,stream,"separator");
 278      }
 279  
 280      // operators
 281      if (greedy(stream,operatorSymbolRE,operatorSymbolWords)) {
 282        return rval(state,stream,"operator");
 283      }
 284  
 285      return rval(state,stream,null);
 286    }
 287  
 288  /////////////////////////////////////////////////////////////////////////////
 289  // utilities
 290    function nongreedy(stream,re,words) {
 291      if (stream.current().length == 1 && re.test(stream.current())) {
 292        stream.backUp(1);
 293        while (re.test(stream.peek())) {
 294          stream.next();
 295          if (is_member(stream.current(),words)) {
 296            return true;
 297          }
 298        }
 299        stream.backUp(stream.current().length-1);
 300      }
 301      return false;
 302    }
 303  
 304    function greedy(stream,re,words) {
 305      if (stream.current().length == 1 && re.test(stream.current())) {
 306        while (re.test(stream.peek())) {
 307          stream.next();
 308        }
 309        while (0 < stream.current().length) {
 310          if (is_member(stream.current(),words)) {
 311            return true;
 312          }else{
 313            stream.backUp(1);
 314          }
 315        }
 316        stream.next();
 317      }
 318      return false;
 319    }
 320  
 321    function doubleQuote(stream) {
 322      return quote(stream, '"', '\\');
 323    }
 324  
 325    function singleQuote(stream) {
 326      return quote(stream,'\'','\\');
 327    }
 328  
 329    function quote(stream,quoteChar,escapeChar) {
 330      while (!stream.eol()) {
 331        var ch = stream.next();
 332        if (ch == quoteChar) {
 333          return true;
 334        }else if (ch == escapeChar) {
 335          stream.next();
 336        }
 337      }
 338      return false;
 339    }
 340  
 341    function lookahead(stream) {
 342      var m = stream.match(/^\s*([^\s%])/, false)
 343      return m ? m[1] : "";
 344    }
 345  
 346    function is_member(element,list) {
 347      return (-1 < list.indexOf(element));
 348    }
 349  
 350    function rval(state,stream,type) {
 351  
 352      // parse stack
 353      pushToken(state,realToken(type,stream));
 354  
 355      // map erlang token type to CodeMirror style class
 356      //     erlang             -> CodeMirror tag
 357      switch (type) {
 358        case "atom":        return "atom";
 359        case "attribute":   return "attribute";
 360        case "boolean":     return "atom";
 361        case "builtin":     return "builtin";
 362        case "close_paren": return null;
 363        case "colon":       return null;
 364        case "comment":     return "comment";
 365        case "dot":         return null;
 366        case "error":       return "error";
 367        case "fun":         return "meta";
 368        case "function":    return "tag";
 369        case "guard":       return "property";
 370        case "keyword":     return "keyword";
 371        case "macro":       return "variable-2";
 372        case "number":      return "number";
 373        case "open_paren":  return null;
 374        case "operator":    return "operator";
 375        case "record":      return "bracket";
 376        case "separator":   return null;
 377        case "string":      return "string";
 378        case "type":        return "def";
 379        case "variable":    return "variable";
 380        default:            return null;
 381      }
 382    }
 383  
 384    function aToken(tok,col,ind,typ) {
 385      return {token:  tok,
 386              column: col,
 387              indent: ind,
 388              type:   typ};
 389    }
 390  
 391    function realToken(type,stream) {
 392      return aToken(stream.current(),
 393                   stream.column(),
 394                   stream.indentation(),
 395                   type);
 396    }
 397  
 398    function fakeToken(type) {
 399      return aToken(type,0,0,type);
 400    }
 401  
 402    function peekToken(state,depth) {
 403      var len = state.tokenStack.length;
 404      var dep = (depth ? depth : 1);
 405  
 406      if (len < dep) {
 407        return false;
 408      }else{
 409        return state.tokenStack[len-dep];
 410      }
 411    }
 412  
 413    function pushToken(state,token) {
 414  
 415      if (!(token.type == "comment" || token.type == "whitespace")) {
 416        state.tokenStack = maybe_drop_pre(state.tokenStack,token);
 417        state.tokenStack = maybe_drop_post(state.tokenStack);
 418      }
 419    }
 420  
 421    function maybe_drop_pre(s,token) {
 422      var last = s.length-1;
 423  
 424      if (0 < last && s[last].type === "record" && token.type === "dot") {
 425        s.pop();
 426      }else if (0 < last && s[last].type === "group") {
 427        s.pop();
 428        s.push(token);
 429      }else{
 430        s.push(token);
 431      }
 432      return s;
 433    }
 434  
 435    function maybe_drop_post(s) {
 436      if (!s.length) return s
 437      var last = s.length-1;
 438  
 439      if (s[last].type === "dot") {
 440        return [];
 441      }
 442      if (last > 1 && s[last].type === "fun" && s[last-1].token === "fun") {
 443        return s.slice(0,last-1);
 444      }
 445      switch (s[last].token) {
 446        case "}":    return d(s,{g:["{"]});
 447        case "]":    return d(s,{i:["["]});
 448        case ")":    return d(s,{i:["("]});
 449        case ">>":   return d(s,{i:["<<"]});
 450        case "end":  return d(s,{i:["begin","case","fun","if","receive","try"]});
 451        case ",":    return d(s,{e:["begin","try","when","->",
 452                                    ",","(","[","{","<<"]});
 453        case "->":   return d(s,{r:["when"],
 454                                 m:["try","if","case","receive"]});
 455        case ";":    return d(s,{E:["case","fun","if","receive","try","when"]});
 456        case "catch":return d(s,{e:["try"]});
 457        case "of":   return d(s,{e:["case"]});
 458        case "after":return d(s,{e:["receive","try"]});
 459        default:     return s;
 460      }
 461    }
 462  
 463    function d(stack,tt) {
 464      // stack is a stack of Token objects.
 465      // tt is an object; {type:tokens}
 466      // type is a char, tokens is a list of token strings.
 467      // The function returns (possibly truncated) stack.
 468      // It will descend the stack, looking for a Token such that Token.token
 469      //  is a member of tokens. If it does not find that, it will normally (but
 470      //  see "E" below) return stack. If it does find a match, it will remove
 471      //  all the Tokens between the top and the matched Token.
 472      // If type is "m", that is all it does.
 473      // If type is "i", it will also remove the matched Token and the top Token.
 474      // If type is "g", like "i", but add a fake "group" token at the top.
 475      // If type is "r", it will remove the matched Token, but not the top Token.
 476      // If type is "e", it will keep the matched Token but not the top Token.
 477      // If type is "E", it behaves as for type "e", except if there is no match,
 478      //  in which case it will return an empty stack.
 479  
 480      for (var type in tt) {
 481        var len = stack.length-1;
 482        var tokens = tt[type];
 483        for (var i = len-1; -1 < i ; i--) {
 484          if (is_member(stack[i].token,tokens)) {
 485            var ss = stack.slice(0,i);
 486            switch (type) {
 487                case "m": return ss.concat(stack[i]).concat(stack[len]);
 488                case "r": return ss.concat(stack[len]);
 489                case "i": return ss;
 490                case "g": return ss.concat(fakeToken("group"));
 491                case "E": return ss.concat(stack[i]);
 492                case "e": return ss.concat(stack[i]);
 493            }
 494          }
 495        }
 496      }
 497      return (type == "E" ? [] : stack);
 498    }
 499  
 500  /////////////////////////////////////////////////////////////////////////////
 501  // indenter
 502  
 503    function indenter(state,textAfter) {
 504      var t;
 505      var unit = cmCfg.indentUnit;
 506      var wordAfter = wordafter(textAfter);
 507      var currT = peekToken(state,1);
 508      var prevT = peekToken(state,2);
 509  
 510      if (state.in_string || state.in_atom) {
 511        return CodeMirror.Pass;
 512      }else if (!prevT) {
 513        return 0;
 514      }else if (currT.token == "when") {
 515        return currT.column+unit;
 516      }else if (wordAfter === "when" && prevT.type === "function") {
 517        return prevT.indent+unit;
 518      }else if (wordAfter === "(" && currT.token === "fun") {
 519        return  currT.column+3;
 520      }else if (wordAfter === "catch" && (t = getToken(state,["try"]))) {
 521        return t.column;
 522      }else if (is_member(wordAfter,["end","after","of"])) {
 523        t = getToken(state,["begin","case","fun","if","receive","try"]);
 524        return t ? t.column : CodeMirror.Pass;
 525      }else if (is_member(wordAfter,closeParenWords)) {
 526        t = getToken(state,openParenWords);
 527        return t ? t.column : CodeMirror.Pass;
 528      }else if (is_member(currT.token,[",","|","||"]) ||
 529                is_member(wordAfter,[",","|","||"])) {
 530        t = postcommaToken(state);
 531        return t ? t.column+t.token.length : unit;
 532      }else if (currT.token == "->") {
 533        if (is_member(prevT.token, ["receive","case","if","try"])) {
 534          return prevT.column+unit+unit;
 535        }else{
 536          return prevT.column+unit;
 537        }
 538      }else if (is_member(currT.token,openParenWords)) {
 539        return currT.column+currT.token.length;
 540      }else{
 541        t = defaultToken(state);
 542        return truthy(t) ? t.column+unit : 0;
 543      }
 544    }
 545  
 546    function wordafter(str) {
 547      var m = str.match(/,|[a-z]+|\}|\]|\)|>>|\|+|\(/);
 548  
 549      return truthy(m) && (m.index === 0) ? m[0] : "";
 550    }
 551  
 552    function postcommaToken(state) {
 553      var objs = state.tokenStack.slice(0,-1);
 554      var i = getTokenIndex(objs,"type",["open_paren"]);
 555  
 556      return truthy(objs[i]) ? objs[i] : false;
 557    }
 558  
 559    function defaultToken(state) {
 560      var objs = state.tokenStack;
 561      var stop = getTokenIndex(objs,"type",["open_paren","separator","keyword"]);
 562      var oper = getTokenIndex(objs,"type",["operator"]);
 563  
 564      if (truthy(stop) && truthy(oper) && stop < oper) {
 565        return objs[stop+1];
 566      } else if (truthy(stop)) {
 567        return objs[stop];
 568      } else {
 569        return false;
 570      }
 571    }
 572  
 573    function getToken(state,tokens) {
 574      var objs = state.tokenStack;
 575      var i = getTokenIndex(objs,"token",tokens);
 576  
 577      return truthy(objs[i]) ? objs[i] : false;
 578    }
 579  
 580    function getTokenIndex(objs,propname,propvals) {
 581  
 582      for (var i = objs.length-1; -1 < i ; i--) {
 583        if (is_member(objs[i][propname],propvals)) {
 584          return i;
 585        }
 586      }
 587      return false;
 588    }
 589  
 590    function truthy(x) {
 591      return (x !== false) && (x != null);
 592    }
 593  
 594  /////////////////////////////////////////////////////////////////////////////
 595  // this object defines the mode
 596  
 597    return {
 598      startState:
 599        function() {
 600          return {tokenStack: [],
 601                  in_string:  false,
 602                  in_atom:    false};
 603        },
 604  
 605      token:
 606        function(stream, state) {
 607          return tokenizer(stream, state);
 608        },
 609  
 610      indent:
 611        function(state, textAfter) {
 612          return indenter(state,textAfter);
 613        },
 614  
 615      lineComment: "%"
 616    };
 617  });
 618  
 619  });


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer