diff --git a/mode/erlang/erlang.js b/mode/erlang/erlang.js
index 77f4f76f25b36f3d76749dd0d86de72ee49feeec..5c094f8e534e331bc3a4e0d0f1611b6c4f15720a 100644
--- a/mode/erlang/erlang.js
+++ b/mode/erlang/erlang.js
@@ -30,8 +30,10 @@ CodeMirror.defineMode("erlang", function(cmCfg, modeCfg) {
 
   var operatorWords = [
     "and","andalso","band","bnot","bor","bsl","bsr","bxor",
-    "div","not","or","orelse","rem","xor",
-    "+","-","*","/",">",">=","<","=<","=:=","==","=/=","/="];
+    "div","not","or","orelse","rem","xor"];
+
+  var operatorSymbols = [
+    "+","-","*","/",">",">=","<","=<","=:=","==","=/=","/=","||","<-"];
 
   var guardWords = [
     "is_atom","is_binary","is_bitstring","is_boolean","is_float",
@@ -64,41 +66,45 @@ CodeMirror.defineMode("erlang", function(cmCfg, modeCfg) {
     "term_to_binary","time","throw","tl","trunc","tuple_size",
     "tuple_to_list","unlink","unregister","whereis"];
 
-  function switchState(stream, setState, f) {
-    setState(f);
-    return f(stream, setState);
-  }
-
   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 normal(stream, setState) {
+  function tokenize(stream, state) {
     if (stream.eatSpace()) {
       return null;
     }
 
     // attributes and type specs
     if (stream.sol() && stream.peek() == '-') {
-      if (stream.next()) {
-        if(stream.eatWhile(idRE)) {
-          if (stream.peek() == "(") {
-            return "attribute";
-          }else if (isMember(stream.current(),typeWords)) {
-            return "def";
-          }else{
-            return null;
-          }
+      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();
@@ -112,7 +118,7 @@ CodeMirror.defineMode("erlang", function(cmCfg, modeCfg) {
     // macro
     if (ch == '?') {
       stream.eatWhile(idRE);
-      return "variable-3";
+      return "variable-2";
     }
 
     // record
@@ -133,18 +139,18 @@ CodeMirror.defineMode("erlang", function(cmCfg, modeCfg) {
 
     // quoted atom
     if (ch == '\'') {
-      return switchState(stream, setState, singleQuote);
+      return singleQuote(stream);
     }
 
     // string
     if (ch == '"') {
-      return switchState(stream, setState, doubleQuote);
+      return doubleQuote(stream);
     }
 
     // variable
     if (largeRE.test(ch)) {
       stream.eatWhile(idRE);
-      return "variable-2";
+      return "variable";
     }
 
     // atom/keyword/BIF/function
@@ -162,12 +168,18 @@ CodeMirror.defineMode("erlang", function(cmCfg, modeCfg) {
       }
 
       var w = stream.current();
-      if (isMember(w,bifWords)) {
-        return "builtin";           // BIF
-      }
+
       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
       }
@@ -175,9 +187,6 @@ CodeMirror.defineMode("erlang", function(cmCfg, modeCfg) {
         return "operator";          // operator
       }
 
-      if (stream.peek() == "(") {
-        return "tag";               // function
-      }
 
       if (stream.peek() == ":") {
         if (w == "erlang") {         // f:now() is highlighted incorrectly
@@ -204,47 +213,39 @@ CodeMirror.defineMode("erlang", function(cmCfg, modeCfg) {
           stream.eatWhile(digitRE);
         }
       }
-      return "number";
+      return "number";               // normal integer
     }
 
     return null;
   }
 
-  function doubleQuote(stream, setState) {
-    while (!stream.eol()) {
-      var ch = stream.next();
-      if (ch == '"') {
-        setState(normal);
-        return "string";
-      }
-      if (ch == '\\') {
-        stream.next();
-      }
-    }
-    setState(normal);
-    return "error";
+  function doubleQuote(stream) {
+    return Quote(stream, '"', '\\', "string");
   }
 
-  function singleQuote(stream, setState) {
+  function singleQuote(stream) {
+    return Quote(stream,'\'','\\',"atom");
+  }
+
+  function Quote(stream,quoteChar,escapeChar,tag) {
     while (!stream.eol()) {
       var ch = stream.next();
-      if (ch == '\'') {
-        setState(normal);
-        return "atom";
-      }
-      if (ch == '\\') {
+      if (ch == quoteChar) {
+        return tag;
+      }else if (ch == escapeChar) {
         stream.next();
       }
     }
-    setState(normal);
     return "error";
   }
 
   return {
-    startState: function ()  { return { f: normal }; },
+    startState: function() {
+      return {};
+    },
 
     token: function(stream, state) {
-      return state.f(stream, function(s) { state.f = s; });
+      return tokenize(stream, state);
     }
   };
 });