aboutsummaryrefslogtreecommitdiff
path: root/js/codemirror/mode/javascript/javascript.js
diff options
context:
space:
mode:
authorPierre Frisch2011-12-22 07:25:50 -0800
committerValerio Virgillito2012-01-27 11:18:17 -0800
commitb89a7ee8b956c96a1dcee995ea840feddc5d4b27 (patch)
tree0f3136ab0ecdbbbed6a83576581af0a53124d6f1 /js/codemirror/mode/javascript/javascript.js
parent2401f05d1f4b94d45e4568b81fc73e67b969d980 (diff)
downloadninja-b89a7ee8b956c96a1dcee995ea840feddc5d4b27.tar.gz
First commit of Ninja to ninja-internal
Signed-off-by: Valerio Virgillito <rmwh84@motorola.com>
Diffstat (limited to 'js/codemirror/mode/javascript/javascript.js')
-rw-r--r--js/codemirror/mode/javascript/javascript.js348
1 files changed, 348 insertions, 0 deletions
diff --git a/js/codemirror/mode/javascript/javascript.js b/js/codemirror/mode/javascript/javascript.js
new file mode 100644
index 00000000..bdf99525
--- /dev/null
+++ b/js/codemirror/mode/javascript/javascript.js
@@ -0,0 +1,348 @@
1CodeMirror.defineMode("javascript", function(config, parserConfig) {
2 var indentUnit = config.indentUnit;
3 var jsonMode = parserConfig.json;
4
5 // Tokenizer
6
7 var keywords = function(){
8 function kw(type) {return {type: type, style: "keyword"};}
9 var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
10 var operator = kw("operator"), atom = {type: "atom", style: "atom"};
11 return {
12 "if": A, "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
13 "return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C,
14 "var": kw("var"), "function": kw("function"), "catch": kw("catch"),
15 "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
16 "in": operator, "typeof": operator, "instanceof": operator,
17 "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom
18 };
19 }();
20
21 var isOperatorChar = /[+\-*&%=<>!?|]/;
22
23 function chain(stream, state, f) {
24 state.tokenize = f;
25 return f(stream, state);
26 }
27
28 function nextUntilUnescaped(stream, end) {
29 var escaped = false, next;
30 while ((next = stream.next()) != null) {
31 if (next == end && !escaped)
32 return false;
33 escaped = !escaped && next == "\\";
34 }
35 return escaped;
36 }
37
38 // Used as scratch variables to communicate multiple values without
39 // consing up tons of objects.
40 var type, content;
41 function ret(tp, style, cont) {
42 type = tp; content = cont;
43 return style;
44 }
45
46 function jsTokenBase(stream, state) {
47 var ch = stream.next();
48 if (ch == '"' || ch == "'")
49 return chain(stream, state, jsTokenString(ch));
50 else if (/[\[\]{}\(\),;\:\.]/.test(ch))
51 return ret(ch);
52 else if (ch == "0" && stream.eat(/x/i)) {
53 stream.eatWhile(/[\da-f]/i);
54 return ret("number", "number");
55 }
56 else if (/\d/.test(ch)) {
57 stream.match(/^\d*(?:\.\d*)?(?:e[+\-]?\d+)?/);
58 return ret("number", "number");
59 }
60 else if (ch == "/") {
61 if (stream.eat("*")) {
62 return chain(stream, state, jsTokenComment);
63 }
64 else if (stream.eat("/")) {
65 stream.skipToEnd();
66 return ret("comment", "comment");
67 }
68 else if (state.reAllowed) {
69 nextUntilUnescaped(stream, "/");
70 stream.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla
71 return ret("regexp", "string");
72 }
73 else {
74 stream.eatWhile(isOperatorChar);
75 return ret("operator", null, stream.current());
76 }
77 }
78 else if (isOperatorChar.test(ch)) {
79 stream.eatWhile(isOperatorChar);
80 return ret("operator", null, stream.current());
81 }
82 else {
83 stream.eatWhile(/[\w\$_]/);
84 var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
85 return known ? ret(known.type, known.style, word) :
86 ret("variable", "variable", word);
87 }
88 }
89
90 function jsTokenString(quote) {
91 return function(stream, state) {
92 if (!nextUntilUnescaped(stream, quote))
93 state.tokenize = jsTokenBase;
94 return ret("string", "string");
95 };
96 }
97
98 function jsTokenComment(stream, state) {
99 var maybeEnd = false, ch;
100 while (ch = stream.next()) {
101 if (ch == "/" && maybeEnd) {
102 state.tokenize = jsTokenBase;
103 break;
104 }
105 maybeEnd = (ch == "*");
106 }
107 return ret("comment", "comment");
108 }
109
110 // Parser
111
112 var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true};
113
114 function JSLexical(indented, column, type, align, prev, info) {
115 this.indented = indented;
116 this.column = column;
117 this.type = type;
118 this.prev = prev;
119 this.info = info;
120 if (align != null) this.align = align;
121 }
122
123 function inScope(state, varname) {
124 for (var v = state.localVars; v; v = v.next)
125 if (v.name == varname) return true;
126 }
127
128 function parseJS(state, style, type, content, stream) {
129 var cc = state.cc;
130 // Communicate our context to the combinators.
131 // (Less wasteful than consing up a hundred closures on every call.)
132 cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc;
133
134 if (!state.lexical.hasOwnProperty("align"))
135 state.lexical.align = true;
136
137 while(true) {
138 var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;
139 if (combinator(type, content)) {
140 while(cc.length && cc[cc.length - 1].lex)
141 cc.pop()();
142 if (cx.marked) return cx.marked;
143 if (type == "variable" && inScope(state, content)) return "variable-2";
144 return style;
145 }
146 }
147 }
148
149 // Combinator utils
150
151 var cx = {state: null, column: null, marked: null, cc: null};
152 function pass() {
153 for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
154 }
155 function cont() {
156 pass.apply(null, arguments);
157 return true;
158 }
159 function register(varname) {
160 var state = cx.state;
161 if (state.context) {
162 cx.marked = "def";
163 for (var v = state.localVars; v; v = v.next)
164 if (v.name == varname) return;
165 state.localVars = {name: varname, next: state.localVars};
166 }
167 }
168
169 // Combinators
170
171 var defaultVars = {name: "this", next: {name: "arguments"}};
172 function pushcontext() {
173 if (!cx.state.context) cx.state.localVars = defaultVars;
174 cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
175 }
176 function popcontext() {
177 cx.state.localVars = cx.state.context.vars;
178 cx.state.context = cx.state.context.prev;
179 }
180 function pushlex(type, info) {
181 var result = function() {
182 var state = cx.state;
183 state.lexical = new JSLexical(state.indented, cx.stream.column(), type, null, state.lexical, info)
184 };
185 result.lex = true;
186 return result;
187 }
188 function poplex() {
189 var state = cx.state;
190 if (state.lexical.prev) {
191 if (state.lexical.type == ")")
192 state.indented = state.lexical.indented;
193 state.lexical = state.lexical.prev;
194 }
195 }
196 poplex.lex = true;
197
198 function expect(wanted) {
199 return function expecting(type) {
200 if (type == wanted) return cont();
201 else if (wanted == ";") return pass();
202 else return cont(arguments.callee);
203 };
204 }
205
206 function statement(type) {
207 if (type == "var") return cont(pushlex("vardef"), vardef1, expect(";"), poplex);
208 if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex);
209 if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
210 if (type == "{") return cont(pushlex("}"), block, poplex);
211 if (type == ";") return cont();
212 if (type == "function") return cont(functiondef);
213 if (type == "for") return cont(pushlex("form"), expect("("), pushlex(")"), forspec1, expect(")"),
214 poplex, statement, poplex);
215 if (type == "variable") return cont(pushlex("stat"), maybelabel);
216 if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"),
217 block, poplex, poplex);
218 if (type == "case") return cont(expression, expect(":"));
219 if (type == "default") return cont(expect(":"));
220 if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
221 statement, poplex, popcontext);