@angular-wave/angular.ts 0.0.46 → 0.0.48
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/angular-ts.esm.js +2 -2
- package/dist/angular-ts.umd.js +2 -2
- package/package.json +1 -1
- package/src/angular.spec.js +1 -2
- package/src/animations/animate-css-driver.js +1 -1
- package/src/animations/animate-queue.js +3 -4
- package/src/animations/animation.js +1 -1
- package/src/animations/raf-scheduler.js +0 -1
- package/src/animations/shared.js +1 -1
- package/src/core/animate/animate.js +0 -1
- package/src/core/compile/compile.spec.js +1 -1
- package/src/core/filter/filter.js +2 -2
- package/src/core/location/location.js +1 -1
- package/src/core/location/location.spec.js +1 -1
- package/src/core/parser/ast-type.js +22 -0
- package/src/core/parser/ast.js +422 -0
- package/src/core/parser/compiler.js +561 -0
- package/src/core/parser/interpreter.js +422 -0
- package/src/core/parser/lexer.js +257 -0
- package/src/core/parser/parse.js +9 -1930
- package/src/core/parser/parse.spec.js +2 -2
- package/src/core/parser/parser.js +39 -0
- package/src/core/parser/shared.js +228 -0
- package/src/core/q/q.spec.js +0 -1
- package/src/core/sce/sce.js +3 -6
- package/src/core/scope/scope.js +19 -11
- package/src/core/task-tracker-factory.js +0 -1
- package/src/directive/attrs/attrs.js +4 -185
- package/src/directive/attrs/attrs.md +224 -0
- package/src/directive/class/class.js +0 -2
- package/src/directive/form/form.js +0 -3
- package/src/directive/include/include.js +1 -1
- package/src/directive/include/include.spec.js +0 -1
- package/src/directive/input/input.js +1 -2
- package/src/directive/model/model.js +1 -3
- package/src/directive/model/model.spec.js +0 -1
- package/src/directive/repeat/repeat.spec.js +0 -2
- package/src/exts/aria/aria.js +0 -1
- package/src/filters/filter.spec.js +0 -1
- package/src/injector.js +1 -1
- package/src/injector.spec.js +0 -5
- package/src/loader.js +0 -5
- package/src/services/cookie-reader.js +0 -1
- package/src/services/http/http.spec.js +0 -2
- package/src/shared/jqlite/jqlite.js +219 -140
- package/src/shared/utils.js +18 -7
- package/src/types.js +10 -0
- package/types/core/parser/ast-type.d.ts +20 -0
- package/types/core/parser/ast.d.ts +78 -0
- package/types/core/parser/compiler.d.ts +49 -0
- package/types/core/parser/interpreter.d.ts +57 -0
- package/types/core/parser/parse.d.ts +79 -0
- package/types/core/parser/parser.d.ts +22 -0
- package/types/core/parser/shared.d.ts +29 -0
- package/types/core/scope/scope.d.ts +9 -2
- package/types/directive/attrs/attrs.d.ts +0 -174
- package/types/shared/jqlite/jqlite.d.ts +33 -4
- package/types/shared/utils.d.ts +18 -5
- package/types/types.d.ts +1 -0
- package/types-back/index.d.ts +0 -12
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
import {
|
|
2
|
+
assignableAST,
|
|
3
|
+
findConstantAndWatchExpressions,
|
|
4
|
+
getInputs,
|
|
5
|
+
getStringValue,
|
|
6
|
+
plusFn,
|
|
7
|
+
} from "./shared";
|
|
8
|
+
import { forEach, isDefined } from "../../shared/utils";
|
|
9
|
+
import { ASTType } from "./ast-type";
|
|
10
|
+
|
|
11
|
+
export function ASTInterpreter($filter) {
|
|
12
|
+
this.$filter = $filter;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
ASTInterpreter.prototype = {
|
|
16
|
+
compile(ast) {
|
|
17
|
+
const self = this;
|
|
18
|
+
findConstantAndWatchExpressions(ast, self.$filter);
|
|
19
|
+
let assignable;
|
|
20
|
+
let assign;
|
|
21
|
+
if ((assignable = assignableAST(ast))) {
|
|
22
|
+
assign = this.recurse(assignable);
|
|
23
|
+
}
|
|
24
|
+
const toWatch = getInputs(ast.body);
|
|
25
|
+
let inputs;
|
|
26
|
+
if (toWatch) {
|
|
27
|
+
inputs = [];
|
|
28
|
+
forEach(toWatch, (watch, key) => {
|
|
29
|
+
const input = self.recurse(watch);
|
|
30
|
+
input.isPure = watch.isPure;
|
|
31
|
+
watch.input = input;
|
|
32
|
+
inputs.push(input);
|
|
33
|
+
watch.watchId = key;
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
const expressions = [];
|
|
37
|
+
forEach(ast.body, (expression) => {
|
|
38
|
+
expressions.push(self.recurse(expression.expression));
|
|
39
|
+
});
|
|
40
|
+
const fn =
|
|
41
|
+
ast.body.length === 0
|
|
42
|
+
? () => {}
|
|
43
|
+
: ast.body.length === 1
|
|
44
|
+
? expressions[0]
|
|
45
|
+
: function (scope, locals) {
|
|
46
|
+
let lastValue;
|
|
47
|
+
forEach(expressions, (exp) => {
|
|
48
|
+
lastValue = exp(scope, locals);
|
|
49
|
+
});
|
|
50
|
+
return lastValue;
|
|
51
|
+
};
|
|
52
|
+
if (assign) {
|
|
53
|
+
fn.assign = function (scope, value, locals) {
|
|
54
|
+
return assign(scope, locals, value);
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
if (inputs) {
|
|
58
|
+
fn.inputs = inputs;
|
|
59
|
+
}
|
|
60
|
+
return fn;
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
recurse(ast, context, create) {
|
|
64
|
+
let left;
|
|
65
|
+
let right;
|
|
66
|
+
const self = this;
|
|
67
|
+
let args;
|
|
68
|
+
if (ast.input) {
|
|
69
|
+
return this.inputs(ast.input, ast.watchId);
|
|
70
|
+
}
|
|
71
|
+
switch (ast.type) {
|
|
72
|
+
case ASTType.Literal:
|
|
73
|
+
return this.value(ast.value, context);
|
|
74
|
+
case ASTType.UnaryExpression:
|
|
75
|
+
right = this.recurse(ast.argument);
|
|
76
|
+
return this[`unary${ast.operator}`](right, context);
|
|
77
|
+
case ASTType.BinaryExpression:
|
|
78
|
+
left = this.recurse(ast.left);
|
|
79
|
+
right = this.recurse(ast.right);
|
|
80
|
+
return this[`binary${ast.operator}`](left, right, context);
|
|
81
|
+
case ASTType.LogicalExpression:
|
|
82
|
+
left = this.recurse(ast.left);
|
|
83
|
+
right = this.recurse(ast.right);
|
|
84
|
+
return this[`binary${ast.operator}`](left, right, context);
|
|
85
|
+
case ASTType.ConditionalExpression:
|
|
86
|
+
return this["ternary?:"](
|
|
87
|
+
this.recurse(ast.test),
|
|
88
|
+
this.recurse(ast.alternate),
|
|
89
|
+
this.recurse(ast.consequent),
|
|
90
|
+
context,
|
|
91
|
+
);
|
|
92
|
+
case ASTType.Identifier:
|
|
93
|
+
return self.identifier(ast.name, context, create);
|
|
94
|
+
case ASTType.MemberExpression:
|
|
95
|
+
left = this.recurse(ast.object, false, !!create);
|
|
96
|
+
if (!ast.computed) {
|
|
97
|
+
right = ast.property.name;
|
|
98
|
+
}
|
|
99
|
+
if (ast.computed) right = this.recurse(ast.property);
|
|
100
|
+
return ast.computed
|
|
101
|
+
? this.computedMember(left, right, context, create)
|
|
102
|
+
: this.nonComputedMember(left, right, context, create);
|
|
103
|
+
case ASTType.CallExpression:
|
|
104
|
+
args = [];
|
|
105
|
+
forEach(ast.arguments, (expr) => {
|
|
106
|
+
args.push(self.recurse(expr));
|
|
107
|
+
});
|
|
108
|
+
if (ast.filter) right = this.$filter(ast.callee.name);
|
|
109
|
+
if (!ast.filter) right = this.recurse(ast.callee, true);
|
|
110
|
+
return ast.filter
|
|
111
|
+
? function (scope, locals, assign, inputs) {
|
|
112
|
+
const values = [];
|
|
113
|
+
for (let i = 0; i < args.length; ++i) {
|
|
114
|
+
values.push(args[i](scope, locals, assign, inputs));
|
|
115
|
+
}
|
|
116
|
+
const value = right.apply(undefined, values, inputs);
|
|
117
|
+
return context
|
|
118
|
+
? { context: undefined, name: undefined, value }
|
|
119
|
+
: value;
|
|
120
|
+
}
|
|
121
|
+
: function (scope, locals, assign, inputs) {
|
|
122
|
+
const rhs = right(scope, locals, assign, inputs);
|
|
123
|
+
let value;
|
|
124
|
+
if (rhs.value != null) {
|
|
125
|
+
const values = [];
|
|
126
|
+
for (let i = 0; i < args.length; ++i) {
|
|
127
|
+
values.push(args[i](scope, locals, assign, inputs));
|
|
128
|
+
}
|
|
129
|
+
value = rhs.value.apply(rhs.context, values);
|
|
130
|
+
}
|
|
131
|
+
return context ? { value } : value;
|
|
132
|
+
};
|
|
133
|
+
case ASTType.AssignmentExpression:
|
|
134
|
+
left = this.recurse(ast.left, true, 1);
|
|
135
|
+
right = this.recurse(ast.right);
|
|
136
|
+
return function (scope, locals, assign, inputs) {
|
|
137
|
+
const lhs = left(scope, locals, assign, inputs);
|
|
138
|
+
const rhs = right(scope, locals, assign, inputs);
|
|
139
|
+
lhs.context[lhs.name] = rhs;
|
|
140
|
+
return context ? { value: rhs } : rhs;
|
|
141
|
+
};
|
|
142
|
+
case ASTType.ArrayExpression:
|
|
143
|
+
args = [];
|
|
144
|
+
forEach(ast.elements, (expr) => {
|
|
145
|
+
args.push(self.recurse(expr));
|
|
146
|
+
});
|
|
147
|
+
return function (scope, locals, assign, inputs) {
|
|
148
|
+
const value = [];
|
|
149
|
+
for (let i = 0; i < args.length; ++i) {
|
|
150
|
+
value.push(args[i](scope, locals, assign, inputs));
|
|
151
|
+
}
|
|
152
|
+
return context ? { value } : value;
|
|
153
|
+
};
|
|
154
|
+
case ASTType.ObjectExpression:
|
|
155
|
+
args = [];
|
|
156
|
+
forEach(ast.properties, (property) => {
|
|
157
|
+
if (property.computed) {
|
|
158
|
+
args.push({
|
|
159
|
+
key: self.recurse(property.key),
|
|
160
|
+
computed: true,
|
|
161
|
+
value: self.recurse(property.value),
|
|
162
|
+
});
|
|
163
|
+
} else {
|
|
164
|
+
args.push({
|
|
165
|
+
key:
|
|
166
|
+
property.key.type === ASTType.Identifier
|
|
167
|
+
? property.key.name
|
|
168
|
+
: `${property.key.value}`,
|
|
169
|
+
computed: false,
|
|
170
|
+
value: self.recurse(property.value),
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
return function (scope, locals, assign, inputs) {
|
|
175
|
+
const value = {};
|
|
176
|
+
for (let i = 0; i < args.length; ++i) {
|
|
177
|
+
if (args[i].computed) {
|
|
178
|
+
value[args[i].key(scope, locals, assign, inputs)] = args[i].value(
|
|
179
|
+
scope,
|
|
180
|
+
locals,
|
|
181
|
+
assign,
|
|
182
|
+
inputs,
|
|
183
|
+
);
|
|
184
|
+
} else {
|
|
185
|
+
value[args[i].key] = args[i].value(scope, locals, assign, inputs);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return context ? { value } : value;
|
|
189
|
+
};
|
|
190
|
+
case ASTType.ThisExpression:
|
|
191
|
+
return function (scope) {
|
|
192
|
+
return context ? { value: scope } : scope;
|
|
193
|
+
};
|
|
194
|
+
case ASTType.LocalsExpression:
|
|
195
|
+
return function (scope, locals) {
|
|
196
|
+
return context ? { value: locals } : locals;
|
|
197
|
+
};
|
|
198
|
+
case ASTType.NGValueParameter:
|
|
199
|
+
return function (scope, locals, assign) {
|
|
200
|
+
return context ? { value: assign } : assign;
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
|
|
205
|
+
"unary+": function (argument, context) {
|
|
206
|
+
return function (scope, locals, assign, inputs) {
|
|
207
|
+
let arg = argument(scope, locals, assign, inputs);
|
|
208
|
+
if (isDefined(arg)) {
|
|
209
|
+
arg = +arg;
|
|
210
|
+
} else {
|
|
211
|
+
arg = 0;
|
|
212
|
+
}
|
|
213
|
+
return context ? { value: arg } : arg;
|
|
214
|
+
};
|
|
215
|
+
},
|
|
216
|
+
|
|
217
|
+
"unary-": function (argument, context) {
|
|
218
|
+
return function (scope, locals, assign, inputs) {
|
|
219
|
+
let arg = argument(scope, locals, assign, inputs);
|
|
220
|
+
if (isDefined(arg)) {
|
|
221
|
+
arg = -arg;
|
|
222
|
+
} else {
|
|
223
|
+
arg = -0;
|
|
224
|
+
}
|
|
225
|
+
return context ? { value: arg } : arg;
|
|
226
|
+
};
|
|
227
|
+
},
|
|
228
|
+
"unary!": function (argument, context) {
|
|
229
|
+
return function (scope, locals, assign, inputs) {
|
|
230
|
+
const arg = !argument(scope, locals, assign, inputs);
|
|
231
|
+
return context ? { value: arg } : arg;
|
|
232
|
+
};
|
|
233
|
+
},
|
|
234
|
+
"binary+": function (left, right, context) {
|
|
235
|
+
return function (scope, locals, assign, inputs) {
|
|
236
|
+
const lhs = left(scope, locals, assign, inputs);
|
|
237
|
+
const rhs = right(scope, locals, assign, inputs);
|
|
238
|
+
const arg = plusFn(lhs, rhs);
|
|
239
|
+
return context ? { value: arg } : arg;
|
|
240
|
+
};
|
|
241
|
+
},
|
|
242
|
+
"binary-": function (left, right, context) {
|
|
243
|
+
return function (scope, locals, assign, inputs) {
|
|
244
|
+
const lhs = left(scope, locals, assign, inputs);
|
|
245
|
+
const rhs = right(scope, locals, assign, inputs);
|
|
246
|
+
const arg = (isDefined(lhs) ? lhs : 0) - (isDefined(rhs) ? rhs : 0);
|
|
247
|
+
return context ? { value: arg } : arg;
|
|
248
|
+
};
|
|
249
|
+
},
|
|
250
|
+
"binary*": function (left, right, context) {
|
|
251
|
+
return function (scope, locals, assign, inputs) {
|
|
252
|
+
const arg =
|
|
253
|
+
left(scope, locals, assign, inputs) *
|
|
254
|
+
right(scope, locals, assign, inputs);
|
|
255
|
+
return context ? { value: arg } : arg;
|
|
256
|
+
};
|
|
257
|
+
},
|
|
258
|
+
"binary/": function (left, right, context) {
|
|
259
|
+
return function (scope, locals, assign, inputs) {
|
|
260
|
+
const arg =
|
|
261
|
+
left(scope, locals, assign, inputs) /
|
|
262
|
+
right(scope, locals, assign, inputs);
|
|
263
|
+
return context ? { value: arg } : arg;
|
|
264
|
+
};
|
|
265
|
+
},
|
|
266
|
+
"binary%": function (left, right, context) {
|
|
267
|
+
return function (scope, locals, assign, inputs) {
|
|
268
|
+
const arg =
|
|
269
|
+
left(scope, locals, assign, inputs) %
|
|
270
|
+
right(scope, locals, assign, inputs);
|
|
271
|
+
return context ? { value: arg } : arg;
|
|
272
|
+
};
|
|
273
|
+
},
|
|
274
|
+
"binary===": function (left, right, context) {
|
|
275
|
+
return function (scope, locals, assign, inputs) {
|
|
276
|
+
const arg =
|
|
277
|
+
left(scope, locals, assign, inputs) ===
|
|
278
|
+
right(scope, locals, assign, inputs);
|
|
279
|
+
return context ? { value: arg } : arg;
|
|
280
|
+
};
|
|
281
|
+
},
|
|
282
|
+
"binary!==": function (left, right, context) {
|
|
283
|
+
return function (scope, locals, assign, inputs) {
|
|
284
|
+
const arg =
|
|
285
|
+
left(scope, locals, assign, inputs) !==
|
|
286
|
+
right(scope, locals, assign, inputs);
|
|
287
|
+
return context ? { value: arg } : arg;
|
|
288
|
+
};
|
|
289
|
+
},
|
|
290
|
+
"binary==": function (left, right, context) {
|
|
291
|
+
return function (scope, locals, assign, inputs) {
|
|
292
|
+
const arg =
|
|
293
|
+
left(scope, locals, assign, inputs) ==
|
|
294
|
+
right(scope, locals, assign, inputs);
|
|
295
|
+
return context ? { value: arg } : arg;
|
|
296
|
+
};
|
|
297
|
+
},
|
|
298
|
+
"binary!=": function (left, right, context) {
|
|
299
|
+
return function (scope, locals, assign, inputs) {
|
|
300
|
+
const arg =
|
|
301
|
+
left(scope, locals, assign, inputs) !=
|
|
302
|
+
right(scope, locals, assign, inputs);
|
|
303
|
+
return context ? { value: arg } : arg;
|
|
304
|
+
};
|
|
305
|
+
},
|
|
306
|
+
"binary<": function (left, right, context) {
|
|
307
|
+
return function (scope, locals, assign, inputs) {
|
|
308
|
+
const arg =
|
|
309
|
+
left(scope, locals, assign, inputs) <
|
|
310
|
+
right(scope, locals, assign, inputs);
|
|
311
|
+
return context ? { value: arg } : arg;
|
|
312
|
+
};
|
|
313
|
+
},
|
|
314
|
+
"binary>": function (left, right, context) {
|
|
315
|
+
return function (scope, locals, assign, inputs) {
|
|
316
|
+
const arg =
|
|
317
|
+
left(scope, locals, assign, inputs) >
|
|
318
|
+
right(scope, locals, assign, inputs);
|
|
319
|
+
return context ? { value: arg } : arg;
|
|
320
|
+
};
|
|
321
|
+
},
|
|
322
|
+
"binary<=": function (left, right, context) {
|
|
323
|
+
return function (scope, locals, assign, inputs) {
|
|
324
|
+
const arg =
|
|
325
|
+
left(scope, locals, assign, inputs) <=
|
|
326
|
+
right(scope, locals, assign, inputs);
|
|
327
|
+
return context ? { value: arg } : arg;
|
|
328
|
+
};
|
|
329
|
+
},
|
|
330
|
+
"binary>=": function (left, right, context) {
|
|
331
|
+
return function (scope, locals, assign, inputs) {
|
|
332
|
+
const arg =
|
|
333
|
+
left(scope, locals, assign, inputs) >=
|
|
334
|
+
right(scope, locals, assign, inputs);
|
|
335
|
+
return context ? { value: arg } : arg;
|
|
336
|
+
};
|
|
337
|
+
},
|
|
338
|
+
"binary&&": function (left, right, context) {
|
|
339
|
+
return function (scope, locals, assign, inputs) {
|
|
340
|
+
const arg =
|
|
341
|
+
left(scope, locals, assign, inputs) &&
|
|
342
|
+
right(scope, locals, assign, inputs);
|
|
343
|
+
return context ? { value: arg } : arg;
|
|
344
|
+
};
|
|
345
|
+
},
|
|
346
|
+
"binary||": function (left, right, context) {
|
|
347
|
+
return function (scope, locals, assign, inputs) {
|
|
348
|
+
const arg =
|
|
349
|
+
left(scope, locals, assign, inputs) ||
|
|
350
|
+
right(scope, locals, assign, inputs);
|
|
351
|
+
return context ? { value: arg } : arg;
|
|
352
|
+
};
|
|
353
|
+
},
|
|
354
|
+
"ternary?:": function (test, alternate, consequent, context) {
|
|
355
|
+
return function (scope, locals, assign, inputs) {
|
|
356
|
+
const arg = test(scope, locals, assign, inputs)
|
|
357
|
+
? alternate(scope, locals, assign, inputs)
|
|
358
|
+
: consequent(scope, locals, assign, inputs);
|
|
359
|
+
return context ? { value: arg } : arg;
|
|
360
|
+
};
|
|
361
|
+
},
|
|
362
|
+
value(value, context) {
|
|
363
|
+
return function () {
|
|
364
|
+
return context ? { context: undefined, name: undefined, value } : value;
|
|
365
|
+
};
|
|
366
|
+
},
|
|
367
|
+
identifier(name, context, create) {
|
|
368
|
+
return function (scope, locals) {
|
|
369
|
+
const base = locals && name in locals ? locals : scope;
|
|
370
|
+
if (create && create !== 1 && base && base[name] == null) {
|
|
371
|
+
base[name] = {};
|
|
372
|
+
}
|
|
373
|
+
const value = base ? base[name] : undefined;
|
|
374
|
+
if (context) {
|
|
375
|
+
return { context: base, name, value };
|
|
376
|
+
}
|
|
377
|
+
return value;
|
|
378
|
+
};
|
|
379
|
+
},
|
|
380
|
+
computedMember(left, right, context, create) {
|
|
381
|
+
return function (scope, locals, assign, inputs) {
|
|
382
|
+
const lhs = left(scope, locals, assign, inputs);
|
|
383
|
+
let rhs;
|
|
384
|
+
let value;
|
|
385
|
+
if (lhs != null) {
|
|
386
|
+
rhs = right(scope, locals, assign, inputs);
|
|
387
|
+
rhs = getStringValue(rhs);
|
|
388
|
+
if (create && create !== 1) {
|
|
389
|
+
if (lhs && !lhs[rhs]) {
|
|
390
|
+
lhs[rhs] = {};
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
value = lhs[rhs];
|
|
394
|
+
}
|
|
395
|
+
if (context) {
|
|
396
|
+
return { context: lhs, name: rhs, value };
|
|
397
|
+
}
|
|
398
|
+
return value;
|
|
399
|
+
};
|
|
400
|
+
},
|
|
401
|
+
nonComputedMember(left, right, context, create) {
|
|
402
|
+
return function (scope, locals, assign, inputs) {
|
|
403
|
+
const lhs = left(scope, locals, assign, inputs);
|
|
404
|
+
if (create && create !== 1) {
|
|
405
|
+
if (lhs && lhs[right] == null) {
|
|
406
|
+
lhs[right] = {};
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
const value = lhs != null ? lhs[right] : undefined;
|
|
410
|
+
if (context) {
|
|
411
|
+
return { context: lhs, name: right, value };
|
|
412
|
+
}
|
|
413
|
+
return value;
|
|
414
|
+
};
|
|
415
|
+
},
|
|
416
|
+
inputs(input, watchId) {
|
|
417
|
+
return function (scope, value, locals, inputs) {
|
|
418
|
+
if (inputs) return inputs[watchId];
|
|
419
|
+
return input(scope, value, locals);
|
|
420
|
+
};
|
|
421
|
+
},
|
|
422
|
+
};
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { $parseMinErr } from "./parse";
|
|
2
|
+
|
|
3
|
+
import { isDefined } from "../../shared/utils";
|
|
4
|
+
|
|
5
|
+
const ESCAPE = {
|
|
6
|
+
n: "\n",
|
|
7
|
+
f: "\f",
|
|
8
|
+
r: "\r",
|
|
9
|
+
t: "\t",
|
|
10
|
+
v: "\v",
|
|
11
|
+
"'": "'",
|
|
12
|
+
'"': '"',
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const OPERATORS = new Set(
|
|
16
|
+
"+ - * / % === !== == != < > <= >= && || ! = |".split(" "),
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @constructor
|
|
21
|
+
*/
|
|
22
|
+
export const Lexer = function Lexer(options) {
|
|
23
|
+
this.options = options;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
Lexer.prototype = {
|
|
27
|
+
constructor: Lexer,
|
|
28
|
+
|
|
29
|
+
lex(text) {
|
|
30
|
+
this.text = text;
|
|
31
|
+
this.index = 0;
|
|
32
|
+
this.tokens = [];
|
|
33
|
+
|
|
34
|
+
while (this.index < this.text.length) {
|
|
35
|
+
const ch = this.text.charAt(this.index);
|
|
36
|
+
if (ch === '"' || ch === "'") {
|
|
37
|
+
this.readString(ch);
|
|
38
|
+
} else if (
|
|
39
|
+
this.isNumber(ch) ||
|
|
40
|
+
(ch === "." && this.isNumber(this.peek()))
|
|
41
|
+
) {
|
|
42
|
+
this.readNumber();
|
|
43
|
+
} else if (this.isIdentifierStart(this.peekMultichar())) {
|
|
44
|
+
this.readIdent();
|
|
45
|
+
} else if (this.is(ch, "(){}[].,;:?")) {
|
|
46
|
+
this.tokens.push({ index: this.index, text: ch });
|
|
47
|
+
this.index++;
|
|
48
|
+
} else if (this.isWhitespace(ch)) {
|
|
49
|
+
this.index++;
|
|
50
|
+
} else {
|
|
51
|
+
const ch2 = ch + this.peek();
|
|
52
|
+
const ch3 = ch2 + this.peek(2);
|
|
53
|
+
const op1 = OPERATORS.has(ch);
|
|
54
|
+
const op2 = OPERATORS.has(ch2);
|
|
55
|
+
const op3 = OPERATORS.has(ch3);
|
|
56
|
+
if (op1 || op2 || op3) {
|
|
57
|
+
const token = op3 ? ch3 : op2 ? ch2 : ch;
|
|
58
|
+
this.tokens.push({ index: this.index, text: token, operator: true });
|
|
59
|
+
this.index += token.length;
|
|
60
|
+
} else {
|
|
61
|
+
this.throwError(
|
|
62
|
+
"Unexpected next character ",
|
|
63
|
+
this.index,
|
|
64
|
+
this.index + 1,
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return this.tokens;
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
is(ch, chars) {
|
|
73
|
+
return chars.indexOf(ch) !== -1;
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
peek(i) {
|
|
77
|
+
const num = i || 1;
|
|
78
|
+
return this.index + num < this.text.length
|
|
79
|
+
? this.text.charAt(this.index + num)
|
|
80
|
+
: false;
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
isNumber(ch) {
|
|
84
|
+
return ch >= "0" && ch <= "9" && typeof ch === "string";
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
isWhitespace(ch) {
|
|
88
|
+
// IE treats non-breaking space as \u00A0
|
|
89
|
+
return (
|
|
90
|
+
ch === " " ||
|
|
91
|
+
ch === "\r" ||
|
|
92
|
+
ch === "\t" ||
|
|
93
|
+
ch === "\n" ||
|
|
94
|
+
ch === "\v" ||
|
|
95
|
+
ch === "\u00A0"
|
|
96
|
+
);
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
isIdentifierStart(ch) {
|
|
100
|
+
return this.options.isIdentifierStart
|
|
101
|
+
? this.options.isIdentifierStart(ch, this.codePointAt(ch))
|
|
102
|
+
: this.isValidIdentifierStart(ch);
|
|
103
|
+
},
|
|
104
|
+
|
|
105
|
+
isValidIdentifierStart(ch) {
|
|
106
|
+
return (
|
|
107
|
+
(ch >= "a" && ch <= "z") ||
|
|
108
|
+
(ch >= "A" && ch <= "Z") ||
|
|
109
|
+
ch === "_" ||
|
|
110
|
+
ch === "$"
|
|
111
|
+
);
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
isIdentifierContinue(ch) {
|
|
115
|
+
return this.options.isIdentifierContinue
|
|
116
|
+
? this.options.isIdentifierContinue(ch, this.codePointAt(ch))
|
|
117
|
+
: this.isValidIdentifierContinue(ch);
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
isValidIdentifierContinue(ch) {
|
|
121
|
+
return this.isValidIdentifierStart(ch) || this.isNumber(ch);
|
|
122
|
+
},
|
|
123
|
+
|
|
124
|
+
codePointAt(ch) {
|
|
125
|
+
if (ch.length === 1) return ch.charCodeAt(0);
|
|
126
|
+
|
|
127
|
+
return (ch.charCodeAt(0) << 10) + ch.charCodeAt(1) - 0x35fdc00;
|
|
128
|
+
},
|
|
129
|
+
|
|
130
|
+
peekMultichar() {
|
|
131
|
+
const ch = this.text.charAt(this.index);
|
|
132
|
+
const peek = this.peek();
|
|
133
|
+
if (!peek) {
|
|
134
|
+
return ch;
|
|
135
|
+
}
|
|
136
|
+
const cp1 = ch.charCodeAt(0);
|
|
137
|
+
const cp2 = peek.charCodeAt(0);
|
|
138
|
+
if (cp1 >= 0xd800 && cp1 <= 0xdbff && cp2 >= 0xdc00 && cp2 <= 0xdfff) {
|
|
139
|
+
return ch + peek;
|
|
140
|
+
}
|
|
141
|
+
return ch;
|
|
142
|
+
},
|
|
143
|
+
|
|
144
|
+
isExpOperator(ch) {
|
|
145
|
+
return ch === "-" || ch === "+" || this.isNumber(ch);
|
|
146
|
+
},
|
|
147
|
+
|
|
148
|
+
throwError(error, start, end) {
|
|
149
|
+
end = end || this.index;
|
|
150
|
+
const colStr = isDefined(start)
|
|
151
|
+
? `s ${start}-${this.index} [${this.text.substring(start, end)}]`
|
|
152
|
+
: ` ${end}`;
|
|
153
|
+
throw $parseMinErr(
|
|
154
|
+
"lexerr",
|
|
155
|
+
"Lexer Error: {0} at column{1} in expression [{2}].",
|
|
156
|
+
error,
|
|
157
|
+
colStr,
|
|
158
|
+
this.text,
|
|
159
|
+
);
|
|
160
|
+
},
|
|
161
|
+
|
|
162
|
+
readNumber() {
|
|
163
|
+
let number = "";
|
|
164
|
+
const start = this.index;
|
|
165
|
+
while (this.index < this.text.length) {
|
|
166
|
+
const ch = this.text.charAt(this.index).toLowerCase();
|
|
167
|
+
if (ch === "." || this.isNumber(ch)) {
|
|
168
|
+
number += ch;
|
|
169
|
+
} else {
|
|
170
|
+
const peekCh = this.peek();
|
|
171
|
+
if (ch === "e" && this.isExpOperator(peekCh)) {
|
|
172
|
+
number += ch;
|
|
173
|
+
} else if (
|
|
174
|
+
this.isExpOperator(ch) &&
|
|
175
|
+
peekCh &&
|
|
176
|
+
this.isNumber(peekCh) &&
|
|
177
|
+
number.charAt(number.length - 1) === "e"
|
|
178
|
+
) {
|
|
179
|
+
number += ch;
|
|
180
|
+
} else if (
|
|
181
|
+
this.isExpOperator(ch) &&
|
|
182
|
+
(!peekCh || !this.isNumber(peekCh)) &&
|
|
183
|
+
number.charAt(number.length - 1) === "e"
|
|
184
|
+
) {
|
|
185
|
+
this.throwError("Invalid exponent");
|
|
186
|
+
} else {
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
this.index++;
|
|
191
|
+
}
|
|
192
|
+
this.tokens.push({
|
|
193
|
+
index: start,
|
|
194
|
+
text: number,
|
|
195
|
+
constant: true,
|
|
196
|
+
value: Number(number),
|
|
197
|
+
});
|
|
198
|
+
},
|
|
199
|
+
|
|
200
|
+
readIdent() {
|
|
201
|
+
const start = this.index;
|
|
202
|
+
this.index += this.peekMultichar().length;
|
|
203
|
+
while (this.index < this.text.length) {
|
|
204
|
+
const ch = this.peekMultichar();
|
|
205
|
+
if (!this.isIdentifierContinue(ch)) {
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
this.index += ch.length;
|
|
209
|
+
}
|
|
210
|
+
this.tokens.push({
|
|
211
|
+
index: start,
|
|
212
|
+
text: this.text.slice(start, this.index),
|
|
213
|
+
identifier: true,
|
|
214
|
+
});
|
|
215
|
+
},
|
|
216
|
+
|
|
217
|
+
readString(quote) {
|
|
218
|
+
const start = this.index;
|
|
219
|
+
this.index++;
|
|
220
|
+
let string = "";
|
|
221
|
+
let rawString = quote;
|
|
222
|
+
let escape = false;
|
|
223
|
+
while (this.index < this.text.length) {
|
|
224
|
+
const ch = this.text.charAt(this.index);
|
|
225
|
+
rawString += ch;
|
|
226
|
+
if (escape) {
|
|
227
|
+
if (ch === "u") {
|
|
228
|
+
const hex = this.text.substring(this.index + 1, this.index + 5);
|
|
229
|
+
if (!hex.match(/[\da-f]{4}/i)) {
|
|
230
|
+
this.throwError(`Invalid unicode escape [\\u${hex}]`);
|
|
231
|
+
}
|
|
232
|
+
this.index += 4;
|
|
233
|
+
string += String.fromCharCode(parseInt(hex, 16));
|
|
234
|
+
} else {
|
|
235
|
+
const rep = ESCAPE[ch];
|
|
236
|
+
string += rep || ch;
|
|
237
|
+
}
|
|
238
|
+
escape = false;
|
|
239
|
+
} else if (ch === "\\") {
|
|
240
|
+
escape = true;
|
|
241
|
+
} else if (ch === quote) {
|
|
242
|
+
this.index++;
|
|
243
|
+
this.tokens.push({
|
|
244
|
+
index: start,
|
|
245
|
+
text: rawString,
|
|
246
|
+
constant: true,
|
|
247
|
+
value: string,
|
|
248
|
+
});
|
|
249
|
+
return;
|
|
250
|
+
} else {
|
|
251
|
+
string += ch;
|
|
252
|
+
}
|
|
253
|
+
this.index++;
|
|
254
|
+
}
|
|
255
|
+
this.throwError("Unterminated quote", start);
|
|
256
|
+
},
|
|
257
|
+
};
|