2013-12-11 14:30:40 +01:00

252 lines
6.6 KiB
JavaScript

// erlang -> CodeMirror tag
//
// atom -> atom
// attribute -> attribute
// builtin -> builtin
// comment -> comment
// error -> error
// fun -> meta
// function -> tag
// guard -> property
// keyword -> keyword
// macro -> variable-2
// number -> number
// operator -> operator
// record -> bracket
// string -> string
// type -> def
// variable -> variable
CodeMirror.defineMIME("text/x-erlang", "erlang");
CodeMirror.defineMode("erlang", function(cmCfg, modeCfg) {
var typeWords = [
"-type", "-spec", "-export_type", "-opaque"];
var keywordWords = [
"after","begin","catch","case","cond","end","fun","if",
"let","of","query","receive","try","when"];
var operatorWords = [
"and","andalso","band","bnot","bor","bsl","bsr","bxor",
"div","not","or","orelse","rem","xor"];
var operatorSymbols = [
"+","-","*","/",">",">=","<","=<","=:=","==","=/=","/=","||","<-"];
var guardWords = [
"is_atom","is_binary","is_bitstring","is_boolean","is_float",
"is_function","is_integer","is_list","is_number","is_pid",
"is_port","is_record","is_reference","is_tuple",
"atom","binary","bitstring","boolean","function","integer","list",
"number","pid","port","record","reference","tuple"];
var bifWords = [
"abs","adler32","adler32_combine","alive","apply","atom_to_binary",
"atom_to_list","binary_to_atom","binary_to_existing_atom",
"binary_to_list","binary_to_term","bit_size","bitstring_to_list",
"byte_size","check_process_code","contact_binary","crc32",
"crc32_combine","date","decode_packet","delete_module",
"disconnect_node","element","erase","exit","float","float_to_list",
"garbage_collect","get","get_keys","group_leader","halt","hd",
"integer_to_list","internal_bif","iolist_size","iolist_to_binary",
"is_alive","is_atom","is_binary","is_bitstring","is_boolean",
"is_float","is_function","is_integer","is_list","is_number","is_pid",
"is_port","is_process_alive","is_record","is_reference","is_tuple",
"length","link","list_to_atom","list_to_binary","list_to_bitstring",
"list_to_existing_atom","list_to_float","list_to_integer",
"list_to_pid","list_to_tuple","load_module","make_ref","module_loaded",
"monitor_node","node","node_link","node_unlink","nodes","notalive",
"now","open_port","pid_to_list","port_close","port_command",
"port_connect","port_control","pre_loaded","process_flag",
"process_info","processes","purge_module","put","register",
"registered","round","self","setelement","size","spawn","spawn_link",
"spawn_monitor","spawn_opt","split_binary","statistics",
"term_to_binary","time","throw","tl","trunc","tuple_size",
"tuple_to_list","unlink","unregister","whereis"];
function isMember(element,list) {
return (-1 < list.indexOf(element));
}
function isPrev(stream,string) {
var start = stream.start;
var len = string.length;
if (len <= start) {
var word = stream.string.slice(start-len,start);
return word == string;
}else{
return false;
}
}
var smallRE = /[a-z_]/;
var largeRE = /[A-Z_]/;
var digitRE = /[0-9]/;
var octitRE = /[0-7]/;
var idRE = /[a-z_A-Z0-9]/;
function tokenize(stream, state) {
if (stream.eatSpace()) {
return null;
}
// attributes and type specs
if (stream.sol() && stream.peek() == '-') {
stream.next();
if (stream.eat(smallRE) && stream.eatWhile(idRE)) {
if (stream.peek() == "(") {
return "attribute";
}else if (isMember(stream.current(),typeWords)) {
return "def";
}else{
return null;
}
}
stream.backUp(1);
}
var ch = stream.next();
// comment
if (ch == '%') {
stream.skipToEnd();
return "comment";
}
// macro
if (ch == '?') {
stream.eatWhile(idRE);
return "variable-2";
}
// record
if ( ch == "#") {
stream.eatWhile(idRE);
return "bracket";
}
// char
if ( ch == "$") {
if (stream.next() == "\\") {
if (!stream.eatWhile(octitRE)) {
stream.next();
}
}
return "string";
}
// quoted atom
if (ch == '\'') {
return singleQuote(stream);
}
// string
if (ch == '"') {
return doubleQuote(stream);
}
// variable
if (largeRE.test(ch)) {
stream.eatWhile(idRE);
return "variable";
}
// atom/keyword/BIF/function
if (smallRE.test(ch)) {
stream.eatWhile(idRE);
if (stream.peek() == "/") {
stream.next();
if (stream.eatWhile(digitRE)) {
return "meta"; // f/0 style fun
}else{
stream.backUp(1);
return "atom";
}
}
var w = stream.current();
if (isMember(w,keywordWords)) {
return "keyword"; // keyword
}
if (stream.peek() == "(") {
if (isMember(w,bifWords) &&
(!isPrev(stream,":") || isPrev(stream,"erlang:"))) {
return "builtin"; // BIF
}else{
return "tag"; // function
}
}
if (isMember(w,guardWords)) {
return "property"; // guard
}
if (isMember(w,operatorWords)) {
return "operator"; // operator
}
if (stream.peek() == ":") {
if (w == "erlang") { // f:now() is highlighted incorrectly
return "builtin";
} else {
return "tag"; // function application
}
}
return "atom";
}
// number
if (digitRE.test(ch)) {
stream.eatWhile(digitRE);
if (stream.eat('#')) {
stream.eatWhile(digitRE); // 16#10 style integer
} else {
if (stream.eat('.')) { // float
stream.eatWhile(digitRE);
}
if (stream.eat(/[eE]/)) {
stream.eat(/[-+]/); // float with exponent
stream.eatWhile(digitRE);
}
}
return "number"; // normal integer
}
return null;
}
function doubleQuote(stream) {
return Quote(stream, '"', '\\', "string");
}
function singleQuote(stream) {
return Quote(stream,'\'','\\',"atom");
}
function Quote(stream,quoteChar,escapeChar,tag) {
while (!stream.eol()) {
var ch = stream.next();
if (ch == quoteChar) {
return tag;
}else if (ch == escapeChar) {
stream.next();
}
}
return "error";
}
return {
startState: function() {
return {};
},
token: function(stream, state) {
return tokenize(stream, state);
}
};
});