Path: blob/master/web-gui/buildyourownbotnet/assets/js/codemirror/mode/erlang/erlang.js
1293 views
/*jshint unused:true, eqnull:true, curly:true, bitwise:true */1/*jshint undef:true, latedef:true, trailing:true */2/*global CodeMirror:true */34// erlang mode.5// tokenizer -> token types -> CodeMirror styles6// tokenizer maintains a parse stack7// indenter uses the parse stack89// TODO indenter:10// bit syntax11// old guard/bif/conversion clashes (e.g. "float/1")12// type/spec/opaque1314CodeMirror.defineMIME("text/x-erlang", "erlang");1516CodeMirror.defineMode("erlang", function(cmCfg) {17"use strict";1819/////////////////////////////////////////////////////////////////////////////20// constants2122var typeWords = [23"-type", "-spec", "-export_type", "-opaque"];2425var keywordWords = [26"after","begin","catch","case","cond","end","fun","if",27"let","of","query","receive","try","when"];2829var separatorRE = /[\->,;]/;30var separatorWords = [31"->",";",","];3233var operatorAtomWords = [34"and","andalso","band","bnot","bor","bsl","bsr","bxor",35"div","not","or","orelse","rem","xor"];3637var operatorSymbolRE = /[\+\-\*\/<>=\|:!]/;38var operatorSymbolWords = [39"=","+","-","*","/",">",">=","<","=<","=:=","==","=/=","/=","||","<-","!"];4041var openParenRE = /[<\(\[\{]/;42var openParenWords = [43"<<","(","[","{"];4445var closeParenRE = /[>\)\]\}]/;46var closeParenWords = [47"}","]",")",">>"];4849var guardWords = [50"is_atom","is_binary","is_bitstring","is_boolean","is_float",51"is_function","is_integer","is_list","is_number","is_pid",52"is_port","is_record","is_reference","is_tuple",53"atom","binary","bitstring","boolean","function","integer","list",54"number","pid","port","record","reference","tuple"];5556var bifWords = [57"abs","adler32","adler32_combine","alive","apply","atom_to_binary",58"atom_to_list","binary_to_atom","binary_to_existing_atom",59"binary_to_list","binary_to_term","bit_size","bitstring_to_list",60"byte_size","check_process_code","contact_binary","crc32",61"crc32_combine","date","decode_packet","delete_module",62"disconnect_node","element","erase","exit","float","float_to_list",63"garbage_collect","get","get_keys","group_leader","halt","hd",64"integer_to_list","internal_bif","iolist_size","iolist_to_binary",65"is_alive","is_atom","is_binary","is_bitstring","is_boolean",66"is_float","is_function","is_integer","is_list","is_number","is_pid",67"is_port","is_process_alive","is_record","is_reference","is_tuple",68"length","link","list_to_atom","list_to_binary","list_to_bitstring",69"list_to_existing_atom","list_to_float","list_to_integer",70"list_to_pid","list_to_tuple","load_module","make_ref","module_loaded",71"monitor_node","node","node_link","node_unlink","nodes","notalive",72"now","open_port","pid_to_list","port_close","port_command",73"port_connect","port_control","pre_loaded","process_flag",74"process_info","processes","purge_module","put","register",75"registered","round","self","setelement","size","spawn","spawn_link",76"spawn_monitor","spawn_opt","split_binary","statistics",77"term_to_binary","time","throw","tl","trunc","tuple_size",78"tuple_to_list","unlink","unregister","whereis"];7980// upper case: [A-Z] [Ø-Þ] [À-Ö]81// lower case: [a-z] [ß-ö] [ø-ÿ]82var anumRE = /[\w@Ø-ÞÀ-Öß-öø-ÿ]/;83var escapesRE =84/[0-7]{1,3}|[bdefnrstv\\"']|\^[a-zA-Z]|x[0-9a-zA-Z]{2}|x{[0-9a-zA-Z]+}/;8586/////////////////////////////////////////////////////////////////////////////87// tokenizer8889function tokenizer(stream,state) {90// in multi-line string91if (state.in_string) {92state.in_string = (!doubleQuote(stream));93return rval(state,stream,"string");94}9596// in multi-line atom97if (state.in_atom) {98state.in_atom = (!singleQuote(stream));99return rval(state,stream,"atom");100}101102// whitespace103if (stream.eatSpace()) {104return rval(state,stream,"whitespace");105}106107// attributes and type specs108if (!peekToken(state) &&109stream.match(/-\s*[a-zß-öø-ÿ][\wØ-ÞÀ-Öß-öø-ÿ]*/)) {110if (is_member(stream.current(),typeWords)) {111return rval(state,stream,"type");112}else{113return rval(state,stream,"attribute");114}115}116117var ch = stream.next();118119// comment120if (ch == '%') {121stream.skipToEnd();122return rval(state,stream,"comment");123}124125// colon126if (ch == ":") {127return rval(state,stream,"colon");128}129130// macro131if (ch == '?') {132stream.eatSpace();133stream.eatWhile(anumRE);134return rval(state,stream,"macro");135}136137// record138if (ch == "#") {139stream.eatSpace();140stream.eatWhile(anumRE);141return rval(state,stream,"record");142}143144// dollar escape145if (ch == "$") {146if (stream.next() == "\\" && !stream.match(escapesRE)) {147return rval(state,stream,"error");148}149return rval(state,stream,"number");150}151152// dot153if (ch == ".") {154return rval(state,stream,"dot");155}156157// quoted atom158if (ch == '\'') {159if (!(state.in_atom = (!singleQuote(stream)))) {160if (stream.match(/\s*\/\s*[0-9]/,false)) {161stream.match(/\s*\/\s*[0-9]/,true);162return rval(state,stream,"fun"); // 'f'/0 style fun163}164if (stream.match(/\s*\(/,false) || stream.match(/\s*:/,false)) {165return rval(state,stream,"function");166}167}168return rval(state,stream,"atom");169}170171// string172if (ch == '"') {173state.in_string = (!doubleQuote(stream));174return rval(state,stream,"string");175}176177// variable178if (/[A-Z_Ø-ÞÀ-Ö]/.test(ch)) {179stream.eatWhile(anumRE);180return rval(state,stream,"variable");181}182183// atom/keyword/BIF/function184if (/[a-z_ß-öø-ÿ]/.test(ch)) {185stream.eatWhile(anumRE);186187if (stream.match(/\s*\/\s*[0-9]/,false)) {188stream.match(/\s*\/\s*[0-9]/,true);189return rval(state,stream,"fun"); // f/0 style fun190}191192var w = stream.current();193194if (is_member(w,keywordWords)) {195return rval(state,stream,"keyword");196}else if (is_member(w,operatorAtomWords)) {197return rval(state,stream,"operator");198}else if (stream.match(/\s*\(/,false)) {199// 'put' and 'erlang:put' are bifs, 'foo:put' is not200if (is_member(w,bifWords) &&201((peekToken(state).token != ":") ||202(peekToken(state,2).token == "erlang"))) {203return rval(state,stream,"builtin");204}else if (is_member(w,guardWords)) {205return rval(state,stream,"guard");206}else{207return rval(state,stream,"function");208}209}else if (is_member(w,operatorAtomWords)) {210return rval(state,stream,"operator");211}else if (lookahead(stream) == ":") {212if (w == "erlang") {213return rval(state,stream,"builtin");214} else {215return rval(state,stream,"function");216}217}else if (is_member(w,["true","false"])) {218return rval(state,stream,"boolean");219}else if (is_member(w,["true","false"])) {220return rval(state,stream,"boolean");221}else{222return rval(state,stream,"atom");223}224}225226// number227var digitRE = /[0-9]/;228var radixRE = /[0-9a-zA-Z]/; // 36#zZ style int229if (digitRE.test(ch)) {230stream.eatWhile(digitRE);231if (stream.eat('#')) { // 36#aZ style integer232if (!stream.eatWhile(radixRE)) {233stream.backUp(1); //"36#" - syntax error234}235} else if (stream.eat('.')) { // float236if (!stream.eatWhile(digitRE)) {237stream.backUp(1); // "3." - probably end of function238} else {239if (stream.eat(/[eE]/)) { // float with exponent240if (stream.eat(/[-+]/)) {241if (!stream.eatWhile(digitRE)) {242stream.backUp(2); // "2e-" - syntax error243}244} else {245if (!stream.eatWhile(digitRE)) {246stream.backUp(1); // "2e" - syntax error247}248}249}250}251}252return rval(state,stream,"number"); // normal integer253}254255// open parens256if (nongreedy(stream,openParenRE,openParenWords)) {257return rval(state,stream,"open_paren");258}259260// close parens261if (nongreedy(stream,closeParenRE,closeParenWords)) {262return rval(state,stream,"close_paren");263}264265// separators266if (greedy(stream,separatorRE,separatorWords)) {267return rval(state,stream,"separator");268}269270// operators271if (greedy(stream,operatorSymbolRE,operatorSymbolWords)) {272return rval(state,stream,"operator");273}274275return rval(state,stream,null);276}277278/////////////////////////////////////////////////////////////////////////////279// utilities280function nongreedy(stream,re,words) {281if (stream.current().length == 1 && re.test(stream.current())) {282stream.backUp(1);283while (re.test(stream.peek())) {284stream.next();285if (is_member(stream.current(),words)) {286return true;287}288}289stream.backUp(stream.current().length-1);290}291return false;292}293294function greedy(stream,re,words) {295if (stream.current().length == 1 && re.test(stream.current())) {296while (re.test(stream.peek())) {297stream.next();298}299while (0 < stream.current().length) {300if (is_member(stream.current(),words)) {301return true;302}else{303stream.backUp(1);304}305}306stream.next();307}308return false;309}310311function doubleQuote(stream) {312return quote(stream, '"', '\\');313}314315function singleQuote(stream) {316return quote(stream,'\'','\\');317}318319function quote(stream,quoteChar,escapeChar) {320while (!stream.eol()) {321var ch = stream.next();322if (ch == quoteChar) {323return true;324}else if (ch == escapeChar) {325stream.next();326}327}328return false;329}330331function lookahead(stream) {332var m = stream.match(/([\n\s]+|%[^\n]*\n)*(.)/,false);333return m ? m.pop() : "";334}335336function is_member(element,list) {337return (-1 < list.indexOf(element));338}339340function rval(state,stream,type) {341342// parse stack343pushToken(state,realToken(type,stream));344345// map erlang token type to CodeMirror style class346// erlang -> CodeMirror tag347switch (type) {348case "atom": return "atom";349case "attribute": return "attribute";350case "boolean": return "special";351case "builtin": return "builtin";352case "close_paren": return null;353case "colon": return null;354case "comment": return "comment";355case "dot": return null;356case "error": return "error";357case "fun": return "meta";358case "function": return "tag";359case "guard": return "property";360case "keyword": return "keyword";361case "macro": return "variable-2";362case "number": return "number";363case "open_paren": return null;364case "operator": return "operator";365case "record": return "bracket";366case "separator": return null;367case "string": return "string";368case "type": return "def";369case "variable": return "variable";370default: return null;371}372}373374function aToken(tok,col,ind,typ) {375return {token: tok,376column: col,377indent: ind,378type: typ};379}380381function realToken(type,stream) {382return aToken(stream.current(),383stream.column(),384stream.indentation(),385type);386}387388function fakeToken(type) {389return aToken(type,0,0,type);390}391392function peekToken(state,depth) {393var len = state.tokenStack.length;394var dep = (depth ? depth : 1);395396if (len < dep) {397return false;398}else{399return state.tokenStack[len-dep];400}401}402403function pushToken(state,token) {404405if (!(token.type == "comment" || token.type == "whitespace")) {406state.tokenStack = maybe_drop_pre(state.tokenStack,token);407state.tokenStack = maybe_drop_post(state.tokenStack);408}409}410411function maybe_drop_pre(s,token) {412var last = s.length-1;413414if (0 < last && s[last].type === "record" && token.type === "dot") {415s.pop();416}else if (0 < last && s[last].type === "group") {417s.pop();418s.push(token);419}else{420s.push(token);421}422return s;423}424425function maybe_drop_post(s) {426var last = s.length-1;427428if (s[last].type === "dot") {429return [];430}431if (s[last].type === "fun" && s[last-1].token === "fun") {432return s.slice(0,last-1);433}434switch (s[s.length-1].token) {435case "}": return d(s,{g:["{"]});436case "]": return d(s,{i:["["]});437case ")": return d(s,{i:["("]});438case ">>": return d(s,{i:["<<"]});439case "end": return d(s,{i:["begin","case","fun","if","receive","try"]});440case ",": return d(s,{e:["begin","try","when","->",441",","(","[","{","<<"]});442case "->": return d(s,{r:["when"],443m:["try","if","case","receive"]});444case ";": return d(s,{E:["case","fun","if","receive","try","when"]});445case "catch":return d(s,{e:["try"]});446case "of": return d(s,{e:["case"]});447case "after":return d(s,{e:["receive","try"]});448default: return s;449}450}451452function d(stack,tt) {453// stack is a stack of Token objects.454// tt is an object; {type:tokens}455// type is a char, tokens is a list of token strings.456// The function returns (possibly truncated) stack.457// It will descend the stack, looking for a Token such that Token.token458// is a member of tokens. If it does not find that, it will normally (but459// see "E" below) return stack. If it does find a match, it will remove460// all the Tokens between the top and the matched Token.461// If type is "m", that is all it does.462// If type is "i", it will also remove the matched Token and the top Token.463// If type is "g", like "i", but add a fake "group" token at the top.464// If type is "r", it will remove the matched Token, but not the top Token.465// If type is "e", it will keep the matched Token but not the top Token.466// If type is "E", it behaves as for type "e", except if there is no match,467// in which case it will return an empty stack.468469for (var type in tt) {470var len = stack.length-1;471var tokens = tt[type];472for (var i = len-1; -1 < i ; i--) {473if (is_member(stack[i].token,tokens)) {474var ss = stack.slice(0,i);475switch (type) {476case "m": return ss.concat(stack[i]).concat(stack[len]);477case "r": return ss.concat(stack[len]);478case "i": return ss;479case "g": return ss.concat(fakeToken("group"));480case "E": return ss.concat(stack[i]);481case "e": return ss.concat(stack[i]);482}483}484}485}486return (type == "E" ? [] : stack);487}488489/////////////////////////////////////////////////////////////////////////////490// indenter491492function indenter(state,textAfter) {493var t;494var unit = cmCfg.indentUnit;495var wordAfter = wordafter(textAfter);496var currT = peekToken(state,1);497var prevT = peekToken(state,2);498499if (state.in_string || state.in_atom) {500return CodeMirror.Pass;501}else if (!prevT) {502return 0;503}else if (currT.token == "when") {504return currT.column+unit;505}else if (wordAfter === "when" && prevT.type === "function") {506return prevT.indent+unit;507}else if (wordAfter === "(" && currT.token === "fun") {508return currT.column+3;509}else if (wordAfter === "catch" && (t = getToken(state,["try"]))) {510return t.column;511}else if (is_member(wordAfter,["end","after","of"])) {512t = getToken(state,["begin","case","fun","if","receive","try"]);513return t ? t.column : CodeMirror.Pass;514}else if (is_member(wordAfter,closeParenWords)) {515t = getToken(state,openParenWords);516return t ? t.column : CodeMirror.Pass;517}else if (is_member(currT.token,[",","|","||"]) ||518is_member(wordAfter,[",","|","||"])) {519t = postcommaToken(state);520return t ? t.column+t.token.length : unit;521}else if (currT.token == "->") {522if (is_member(prevT.token, ["receive","case","if","try"])) {523return prevT.column+unit+unit;524}else{525return prevT.column+unit;526}527}else if (is_member(currT.token,openParenWords)) {528return currT.column+currT.token.length;529}else{530t = defaultToken(state);531return truthy(t) ? t.column+unit : 0;532}533}534535function wordafter(str) {536var m = str.match(/,|[a-z]+|\}|\]|\)|>>|\|+|\(/);537538return truthy(m) && (m.index === 0) ? m[0] : "";539}540541function postcommaToken(state) {542var objs = state.tokenStack.slice(0,-1);543var i = getTokenIndex(objs,"type",["open_paren"]);544545return truthy(objs[i]) ? objs[i] : false;546}547548function defaultToken(state) {549var objs = state.tokenStack;550var stop = getTokenIndex(objs,"type",["open_paren","separator","keyword"]);551var oper = getTokenIndex(objs,"type",["operator"]);552553if (truthy(stop) && truthy(oper) && stop < oper) {554return objs[stop+1];555} else if (truthy(stop)) {556return objs[stop];557} else {558return false;559}560}561562function getToken(state,tokens) {563var objs = state.tokenStack;564var i = getTokenIndex(objs,"token",tokens);565566return truthy(objs[i]) ? objs[i] : false;567}568569function getTokenIndex(objs,propname,propvals) {570571for (var i = objs.length-1; -1 < i ; i--) {572if (is_member(objs[i][propname],propvals)) {573return i;574}575}576return false;577}578579function truthy(x) {580return (x !== false) && (x != null);581}582583/////////////////////////////////////////////////////////////////////////////584// this object defines the mode585586return {587startState:588function() {589return {tokenStack: [],590in_string: false,591in_atom: false};592},593594token:595function(stream, state) {596return tokenizer(stream, state);597},598599indent:600function(state, textAfter) {601return indenter(state,textAfter);602},603604lineComment: "%"605};606});607608609