19
if (typeof exports == "object" && typeof module == "object")
20
mod(require("../../lib/codemirror"));
21
else if (typeof define == "function" && define.amd)
22
define(["../../lib/codemirror"], mod);
25
})(function(CodeMirror) {
28
CodeMirror.defineMIME("text/x-erlang", "erlang");
30
CodeMirror.defineMode("erlang", function(cmCfg) {
37
"-type", "-spec", "-export_type", "-opaque"];
40
"after","begin","catch","case","cond","end","fun","if",
41
"let","of","query","receive","try","when"];
43
var separatorRE = /[\->,;]/;
44
var separatorWords = [
47
var operatorAtomWords = [
48
"and","andalso","band","bnot","bor","bsl","bsr","bxor",
49
"div","not","or","orelse","rem","xor"];
51
var operatorSymbolRE = /[\+\-\*\/<>=\|:!]/;
52
var operatorSymbolWords = [
53
"=","+","-","*","/",">",">=","<","=<","=:=","==","=/=","/=","||","<-","!"];
55
var openParenRE = /[<\(\[\{]/;
56
var openParenWords = [
59
var closeParenRE = /[>\)\]\}]/;
60
var closeParenWords = [
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"];
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"];
96
var anumRE = /[\w@Ø-ÞÀ-Öß-öø-ÿ]/;
98
/[0-7]{1,3}|[bdefnrstv\\"']|\^[a-zA-Z]|x[0-9a-zA-Z]{2}|x{[0-9a-zA-Z]+}/;
103
function tokenizer(stream,state) {
105
if (state.in_string) {
106
state.in_string = (!doubleQuote(stream));
107
return rval(state,stream,"string");
112
state.in_atom = (!singleQuote(stream));
113
return rval(state,stream,"atom");
117
if (stream.eatSpace()) {
118
return rval(state,stream,"whitespace");
122
if (!peekToken(state) &&
123
stream.match(/-\s*[a-zß-öø-ÿ][\wØ-ÞÀ-Öß-öø-ÿ]*/)) {
124
if (is_member(stream.current(),typeWords)) {
125
return rval(state,stream,"type");
127
return rval(state,stream,"attribute");
131
var ch = stream.next();
136
return rval(state,stream,"comment");
141
return rval(state,stream,"colon");
147
stream.eatWhile(anumRE);
148
return rval(state,stream,"macro");
154
stream.eatWhile(anumRE);
155
return rval(state,stream,"record");
160
if (stream.next() == "\\" && !stream.match(escapesRE)) {
161
return rval(state,stream,"error");
163
return rval(state,stream,"number");
168
return rval(state,stream,"dot");
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");
178
if (stream.match(/\s*\(/,false) || stream.match(/\s*:/,false)) {
179
return rval(state,stream,"function");
182
return rval(state,stream,"atom");
187
state.in_string = (!doubleQuote(stream));
188
return rval(state,stream,"string");
192
if (/[A-Z_Ø-ÞÀ-Ö]/.test(ch)) {
193
stream.eatWhile(anumRE);
194
return rval(state,stream,"variable");
198
if (/[a-z_ß-öø-ÿ]/.test(ch)) {
199
stream.eatWhile(anumRE);
201
if (stream.match(/\s*\/\s*[0-9]/,false)) {
202
stream.match(/\s*\/\s*[0-9]/,true);
203
return rval(state,stream,"fun");
206
var w = stream.current();
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)) {
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");
221
return rval(state,stream,"function");
223
}else if (lookahead(stream) == ":") {
225
return rval(state,stream,"builtin");
227
return rval(state,stream,"function");
229
}else if (is_member(w,["true","false"])) {
230
return rval(state,stream,"boolean");
232
return rval(state,stream,"atom");
237
var digitRE = /[0-9]/;
238
var radixRE = /[0-9a-zA-Z]/;
239
if (digitRE.test(ch)) {
240
stream.eatWhile(digitRE);
241
if (stream.eat('#')) {
242
if (!stream.eatWhile(radixRE)) {
245
} else if (stream.eat('.')) {
246
if (!stream.eatWhile(digitRE)) {
249
if (stream.eat(/[eE]/)) {
250
if (stream.eat(/[-+]/)) {
251
if (!stream.eatWhile(digitRE)) {
255
if (!stream.eatWhile(digitRE)) {
262
return rval(state,stream,"number");
266
if (nongreedy(stream,openParenRE,openParenWords)) {
267
return rval(state,stream,"open_paren");
271
if (nongreedy(stream,closeParenRE,closeParenWords)) {
272
return rval(state,stream,"close_paren");
276
if (greedy(stream,separatorRE,separatorWords)) {
277
return rval(state,stream,"separator");
281
if (greedy(stream,operatorSymbolRE,operatorSymbolWords)) {
282
return rval(state,stream,"operator");
285
return rval(state,stream,null);
290
function nongreedy(stream,re,words) {
291
if (stream.current().length == 1 && re.test(stream.current())) {
293
while (re.test(stream.peek())) {
295
if (is_member(stream.current(),words)) {
299
stream.backUp(stream.current().length-1);
304
function greedy(stream,re,words) {
305
if (stream.current().length == 1 && re.test(stream.current())) {
306
while (re.test(stream.peek())) {
309
while (0 < stream.current().length) {
310
if (is_member(stream.current(),words)) {
321
function doubleQuote(stream) {
322
return quote(stream, '"', '\\');
325
function singleQuote(stream) {
326
return quote(stream,'\'','\\');
329
function quote(stream,quoteChar,escapeChar) {
330
while (!stream.eol()) {
331
var ch = stream.next();
332
if (ch == quoteChar) {
334
}else if (ch == escapeChar) {
341
function lookahead(stream) {
342
var m = stream.match(/^\s*([^\s%])/, false)
343
return m ? m[1] : "";
346
function is_member(element,list) {
347
return (-1 < list.indexOf(element));
350
function rval(state,stream,type) {
353
pushToken(state,realToken(type,stream));
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;
384
function aToken(tok,col,ind,typ) {
391
function realToken(type,stream) {
392
return aToken(stream.current(),
394
stream.indentation(),
398
function fakeToken(type) {
399
return aToken(type,0,0,type);
402
function peekToken(state,depth) {
403
var len = state.tokenStack.length;
404
var dep = (depth ? depth : 1);
409
return state.tokenStack[len-dep];
413
function pushToken(state,token) {
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);
421
function maybe_drop_pre(s,token) {
422
var last = s.length-1;
424
if (0 < last && s[last].type === "record" && token.type === "dot") {
426
}else if (0 < last && s[last].type === "group") {
435
function maybe_drop_post(s) {
436
if (!s.length) return s
437
var last = s.length-1;
439
if (s[last].type === "dot") {
442
if (last > 1 && s[last].type === "fun" && s[last-1].token === "fun") {
443
return s.slice(0,last-1);
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"]});
463
function d(stack,tt) {
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);
487
case "m": return ss.concat(stack[i]).concat(stack[len]);
488
case "r": return ss.concat(stack[len]);
490
case "g": return ss.concat(fakeToken("group"));
491
case "E": return ss.concat(stack[i]);
492
case "e": return ss.concat(stack[i]);
497
return (type == "E" ? [] : stack);
503
function indenter(state,textAfter) {
505
var unit = cmCfg.indentUnit;
506
var wordAfter = wordafter(textAfter);
507
var currT = peekToken(state,1);
508
var prevT = peekToken(state,2);
510
if (state.in_string || state.in_atom) {
511
return CodeMirror.Pass;
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"]))) {
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;
536
return prevT.column+unit;
538
}else if (is_member(currT.token,openParenWords)) {
539
return currT.column+currT.token.length;
541
t = defaultToken(state);
542
return truthy(t) ? t.column+unit : 0;
546
function wordafter(str) {
547
var m = str.match(/,|[a-z]+|\}|\]|\)|>>|\|+|\(/);
549
return truthy(m) && (m.index === 0) ? m[0] : "";
552
function postcommaToken(state) {
553
var objs = state.tokenStack.slice(0,-1);
554
var i = getTokenIndex(objs,"type",["open_paren"]);
556
return truthy(objs[i]) ? objs[i] : false;
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"]);
564
if (truthy(stop) && truthy(oper) && stop < oper) {
566
} else if (truthy(stop)) {
573
function getToken(state,tokens) {
574
var objs = state.tokenStack;
575
var i = getTokenIndex(objs,"token",tokens);
577
return truthy(objs[i]) ? objs[i] : false;
580
function getTokenIndex(objs,propname,propvals) {
582
for (var i = objs.length-1; -1 < i ; i--) {
583
if (is_member(objs[i][propname],propvals)) {
591
return (x !== false) && (x != null);
600
return {tokenStack: [],
606
function(stream, state) {
607
return tokenizer(stream, state);
611
function(state, textAfter) {
612
return indenter(state,textAfter);