UNPKG

10.8 kBJavaScriptView Raw
1var types = require("../lib/types");
2var Type = types.Type;
3var def = Type.def;
4var or = Type.or;
5var shared = require("../lib/shared");
6var defaults = shared.defaults;
7var geq = shared.geq;
8
9// Abstract supertype of all syntactic entities that are allowed to have a
10// .loc field.
11def("Printable")
12 .field("loc", or(
13 def("SourceLocation"),
14 null
15 ), defaults["null"], true);
16
17def("Node")
18 .bases("Printable")
19 .field("type", String)
20 .field("comments", or(
21 [def("Comment")],
22 null
23 ), defaults["null"], true);
24
25def("SourceLocation")
26 .build("start", "end", "source")
27 .field("start", def("Position"))
28 .field("end", def("Position"))
29 .field("source", or(String, null), defaults["null"]);
30
31def("Position")
32 .build("line", "column")
33 .field("line", geq(1))
34 .field("column", geq(0));
35
36def("File")
37 .bases("Node")
38 .build("program")
39 .field("program", def("Program"));
40
41def("Program")
42 .bases("Node")
43 .build("body")
44 .field("body", [def("Statement")]);
45
46def("Function")
47 .bases("Node")
48 .field("id", or(def("Identifier"), null), defaults["null"])
49 .field("params", [def("Pattern")])
50 .field("body", def("BlockStatement"));
51
52def("Statement").bases("Node");
53
54// The empty .build() here means that an EmptyStatement can be constructed
55// (i.e. it's not abstract) but that it needs no arguments.
56def("EmptyStatement").bases("Statement").build();
57
58def("BlockStatement")
59 .bases("Statement")
60 .build("body")
61 .field("body", [def("Statement")]);
62
63// TODO Figure out how to silently coerce Expressions to
64// ExpressionStatements where a Statement was expected.
65def("ExpressionStatement")
66 .bases("Statement")
67 .build("expression")
68 .field("expression", def("Expression"));
69
70def("IfStatement")
71 .bases("Statement")
72 .build("test", "consequent", "alternate")
73 .field("test", def("Expression"))
74 .field("consequent", def("Statement"))
75 .field("alternate", or(def("Statement"), null), defaults["null"]);
76
77def("LabeledStatement")
78 .bases("Statement")
79 .build("label", "body")
80 .field("label", def("Identifier"))
81 .field("body", def("Statement"));
82
83def("BreakStatement")
84 .bases("Statement")
85 .build("label")
86 .field("label", or(def("Identifier"), null), defaults["null"]);
87
88def("ContinueStatement")
89 .bases("Statement")
90 .build("label")
91 .field("label", or(def("Identifier"), null), defaults["null"]);
92
93def("WithStatement")
94 .bases("Statement")
95 .build("object", "body")
96 .field("object", def("Expression"))
97 .field("body", def("Statement"));
98
99def("SwitchStatement")
100 .bases("Statement")
101 .build("discriminant", "cases", "lexical")
102 .field("discriminant", def("Expression"))
103 .field("cases", [def("SwitchCase")])
104 .field("lexical", Boolean, defaults["false"]);
105
106def("ReturnStatement")
107 .bases("Statement")
108 .build("argument")
109 .field("argument", or(def("Expression"), null));
110
111def("ThrowStatement")
112 .bases("Statement")
113 .build("argument")
114 .field("argument", def("Expression"));
115
116def("TryStatement")
117 .bases("Statement")
118 .build("block", "handler", "finalizer")
119 .field("block", def("BlockStatement"))
120 .field("handler", or(def("CatchClause"), null), function() {
121 return this.handlers && this.handlers[0] || null;
122 })
123 .field("handlers", [def("CatchClause")], function() {
124 return this.handler ? [this.handler] : [];
125 }, true) // Indicates this field is hidden from eachField iteration.
126 .field("guardedHandlers", [def("CatchClause")], defaults.emptyArray)
127 .field("finalizer", or(def("BlockStatement"), null), defaults["null"]);
128
129def("CatchClause")
130 .bases("Node")
131 .build("param", "guard", "body")
132 .field("param", def("Pattern"))
133 .field("guard", or(def("Expression"), null), defaults["null"])
134 .field("body", def("BlockStatement"));
135
136def("WhileStatement")
137 .bases("Statement")
138 .build("test", "body")
139 .field("test", def("Expression"))
140 .field("body", def("Statement"));
141
142def("DoWhileStatement")
143 .bases("Statement")
144 .build("body", "test")
145 .field("body", def("Statement"))
146 .field("test", def("Expression"));
147
148def("ForStatement")
149 .bases("Statement")
150 .build("init", "test", "update", "body")
151 .field("init", or(
152 def("VariableDeclaration"),
153 def("Expression"),
154 null))
155 .field("test", or(def("Expression"), null))
156 .field("update", or(def("Expression"), null))
157 .field("body", def("Statement"));
158
159def("ForInStatement")
160 .bases("Statement")
161 .build("left", "right", "body")
162 .field("left", or(
163 def("VariableDeclaration"),
164 def("Expression")))
165 .field("right", def("Expression"))
166 .field("body", def("Statement"));
167
168def("DebuggerStatement").bases("Statement").build();
169
170def("Declaration").bases("Statement");
171
172def("FunctionDeclaration")
173 .bases("Function", "Declaration")
174 .build("id", "params", "body")
175 .field("id", def("Identifier"));
176
177def("FunctionExpression")
178 .bases("Function", "Expression")
179 .build("id", "params", "body");
180
181def("VariableDeclaration")
182 .bases("Declaration")
183 .build("kind", "declarations")
184 .field("kind", or("var", "let", "const"))
185 .field("declarations", [def("VariableDeclarator")]);
186
187def("VariableDeclarator")
188 .bases("Node")
189 .build("id", "init")
190 .field("id", def("Pattern"))
191 .field("init", or(def("Expression"), null));
192
193// TODO Are all Expressions really Patterns?
194def("Expression").bases("Node", "Pattern");
195
196def("ThisExpression").bases("Expression").build();
197
198def("ArrayExpression")
199 .bases("Expression")
200 .build("elements")
201 .field("elements", [or(def("Expression"), null)]);
202
203def("ObjectExpression")
204 .bases("Expression")
205 .build("properties")
206 .field("properties", [def("Property")]);
207
208// TODO Not in the Mozilla Parser API, but used by Esprima.
209def("Property")
210 .bases("Node") // Want to be able to visit Property Nodes.
211 .build("kind", "key", "value")
212 .field("kind", or("init", "get", "set"))
213 .field("key", or(def("Literal"), def("Identifier")))
214 .field("value", def("Expression"));
215
216def("SequenceExpression")
217 .bases("Expression")
218 .build("expressions")
219 .field("expressions", [def("Expression")]);
220
221var UnaryOperator = or(
222 "-", "+", "!", "~",
223 "typeof", "void", "delete");
224
225def("UnaryExpression")
226 .bases("Expression")
227 .build("operator", "argument", "prefix")
228 .field("operator", UnaryOperator)
229 .field("argument", def("Expression"))
230 // Esprima doesn't bother with this field, presumably because it's
231 // always true for unary operators.
232 .field("prefix", Boolean, defaults["true"]);
233
234var BinaryOperator = or(
235 "==", "!=", "===", "!==",
236 "<", "<=", ">", ">=",
237 "<<", ">>", ">>>",
238 "+", "-", "*", "/", "%",
239 "&", // TODO Missing from the Parser API.
240 "|", "^", "in",
241 "instanceof", "..");
242
243def("BinaryExpression")
244 .bases("Expression")
245 .build("operator", "left", "right")
246 .field("operator", BinaryOperator)
247 .field("left", def("Expression"))
248 .field("right", def("Expression"));
249
250var AssignmentOperator = or(
251 "=", "+=", "-=", "*=", "/=", "%=",
252 "<<=", ">>=", ">>>=",
253 "|=", "^=", "&=");
254
255def("AssignmentExpression")
256 .bases("Expression")
257 .build("operator", "left", "right")
258 .field("operator", AssignmentOperator)
259 .field("left", def("Pattern"))
260 .field("right", def("Expression"));
261
262var UpdateOperator = or("++", "--");
263
264def("UpdateExpression")
265 .bases("Expression")
266 .build("operator", "argument", "prefix")
267 .field("operator", UpdateOperator)
268 .field("argument", def("Expression"))
269 .field("prefix", Boolean);
270
271var LogicalOperator = or("||", "&&");
272
273def("LogicalExpression")
274 .bases("Expression")
275 .build("operator", "left", "right")
276 .field("operator", LogicalOperator)
277 .field("left", def("Expression"))
278 .field("right", def("Expression"));
279
280def("ConditionalExpression")
281 .bases("Expression")
282 .build("test", "consequent", "alternate")
283 .field("test", def("Expression"))
284 .field("consequent", def("Expression"))
285 .field("alternate", def("Expression"));
286
287def("NewExpression")
288 .bases("Expression")
289 .build("callee", "arguments")
290 .field("callee", def("Expression"))
291 // The Mozilla Parser API gives this type as [or(def("Expression"),
292 // null)], but null values don't really make sense at the call site.
293 // TODO Report this nonsense.
294 .field("arguments", [def("Expression")]);
295
296def("CallExpression")
297 .bases("Expression")
298 .build("callee", "arguments")
299 .field("callee", def("Expression"))
300 // See comment for NewExpression above.
301 .field("arguments", [def("Expression")]);
302
303def("MemberExpression")
304 .bases("Expression")
305 .build("object", "property", "computed")
306 .field("object", def("Expression"))
307 .field("property", or(def("Identifier"), def("Expression")))
308 .field("computed", Boolean, function(){
309 var type = this.property.type;
310 if (type === 'Literal' ||
311 type === 'MemberExpression' ||
312 type === 'BinaryExpression') {
313 return true;
314 }
315 return false;
316 });
317
318def("Pattern").bases("Node");
319
320def("SwitchCase")
321 .bases("Node")
322 .build("test", "consequent")
323 .field("test", or(def("Expression"), null))
324 .field("consequent", [def("Statement")]);
325
326def("Identifier")
327 // But aren't Expressions and Patterns already Nodes? TODO Report this.
328 .bases("Node", "Expression", "Pattern")
329 .build("name")
330 .field("name", String);
331
332def("Literal")
333 // But aren't Expressions already Nodes? TODO Report this.
334 .bases("Node", "Expression")
335 .build("value")
336 .field("value", or(String, Boolean, null, Number, RegExp))
337 .field("regex", or({
338 pattern: String,
339 flags: String
340 }, null), function() {
341 if (this.value instanceof RegExp) {
342 var flags = "";
343
344 if (this.value.ignoreCase) flags += "i";
345 if (this.value.multiline) flags += "m";
346 if (this.value.global) flags += "g";
347
348 return {
349 pattern: this.value.source,
350 flags: flags
351 };
352 }
353
354 return null;
355 });
356
357// Abstract (non-buildable) comment supertype. Not a Node.
358def("Comment")
359 .bases("Printable")
360 .field("value", String)
361 // A .leading comment comes before the node, whereas a .trailing
362 // comment comes after it. These two fields should not both be true,
363 // but they might both be false when the comment falls inside a node
364 // and the node has no children for the comment to lead or trail,
365 // e.g. { /*dangling*/ }.
366 .field("leading", Boolean, defaults["true"])
367 .field("trailing", Boolean, defaults["false"]);