spider-src 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +74 -0
- data/README.md +37 -0
- data/Rakefile +25 -0
- data/lib/spider-src/support/spider/.eslintrc +17 -0
- data/lib/spider-src/support/spider/.npmignore +9 -0
- data/lib/spider-src/support/spider/.travis.yml +7 -0
- data/lib/spider-src/support/spider/.yo-rc.json +3 -0
- data/lib/spider-src/support/spider/CHANGELOG.md +64 -0
- data/lib/spider-src/support/spider/Gruntfile.js +97 -0
- data/lib/spider-src/support/spider/Gruntfile.spider +93 -0
- data/lib/spider-src/support/spider/LICENSE +201 -0
- data/lib/spider-src/support/spider/README.md +50 -0
- data/lib/spider-src/support/spider/cli.js +119 -0
- data/lib/spider-src/support/spider/lib/ast/CaseClause.js +179 -0
- data/lib/spider-src/support/spider/lib/ast/CatchClause.js +26 -0
- data/lib/spider-src/support/spider/lib/ast/ExportBatchSpecifier.js +19 -0
- data/lib/spider-src/support/spider/lib/ast/ExportSpecifier.js +33 -0
- data/lib/spider-src/support/spider/lib/ast/ImportDefaultSpecifier.js +23 -0
- data/lib/spider-src/support/spider/lib/ast/ImportNamespaceSpecifier.js +23 -0
- data/lib/spider-src/support/spider/lib/ast/ImportSpecifier.js +40 -0
- data/lib/spider-src/support/spider/lib/ast/Node.js +93 -0
- data/lib/spider-src/support/spider/lib/ast/Parameter.js +229 -0
- data/lib/spider-src/support/spider/lib/ast/Program.js +58 -0
- data/lib/spider-src/support/spider/lib/ast/Property.js +32 -0
- data/lib/spider-src/support/spider/lib/ast/Range.js +257 -0
- data/lib/spider-src/support/spider/lib/ast/VariableDeclarator.js +29 -0
- data/lib/spider-src/support/spider/lib/ast/expressions/ArrayExpression.js +41 -0
- data/lib/spider-src/support/spider/lib/ast/expressions/ArrayPattern.js +45 -0
- data/lib/spider-src/support/spider/lib/ast/expressions/AssignmentExpression.js +29 -0
- data/lib/spider-src/support/spider/lib/ast/expressions/BinaryExpression.js +104 -0
- data/lib/spider-src/support/spider/lib/ast/expressions/CallExpression.js +139 -0
- data/lib/spider-src/support/spider/lib/ast/expressions/ConditionalExpression.js +31 -0
- data/lib/spider-src/support/spider/lib/ast/expressions/CurryCallExpression.js +102 -0
- data/lib/spider-src/support/spider/lib/ast/expressions/ExistentialExpression.js +83 -0
- data/lib/spider-src/support/spider/lib/ast/expressions/ForInExpression.js +116 -0
- data/lib/spider-src/support/spider/lib/ast/expressions/FunctionExpression.js +157 -0
- data/lib/spider-src/support/spider/lib/ast/expressions/InExpression.js +99 -0
- data/lib/spider-src/support/spider/lib/ast/expressions/LogicalExpression.js +50 -0
- data/lib/spider-src/support/spider/lib/ast/expressions/MemberExpression.js +43 -0
- data/lib/spider-src/support/spider/lib/ast/expressions/NewExpression.js +46 -0
- data/lib/spider-src/support/spider/lib/ast/expressions/NullCheckCallExpression.js +132 -0
- data/lib/spider-src/support/spider/lib/ast/expressions/NullCoalescingExpression.js +114 -0
- data/lib/spider-src/support/spider/lib/ast/expressions/NullPropagatingExpression.js +161 -0
- data/lib/spider-src/support/spider/lib/ast/expressions/ObjectExpression.js +39 -0
- data/lib/spider-src/support/spider/lib/ast/expressions/ObjectPattern.js +49 -0
- data/lib/spider-src/support/spider/lib/ast/expressions/RangeMemberExpression.js +157 -0
- data/lib/spider-src/support/spider/lib/ast/expressions/SplatExpression.js +48 -0
- data/lib/spider-src/support/spider/lib/ast/expressions/SuperExpression.js +170 -0
- data/lib/spider-src/support/spider/lib/ast/expressions/ThisExpression.js +22 -0
- data/lib/spider-src/support/spider/lib/ast/expressions/UnaryExpression.js +147 -0
- data/lib/spider-src/support/spider/lib/ast/expressions/UpdateExpression.js +26 -0
- data/lib/spider-src/support/spider/lib/ast/literals/BooleanLiteral.js +24 -0
- data/lib/spider-src/support/spider/lib/ast/literals/Identifier.js +60 -0
- data/lib/spider-src/support/spider/lib/ast/literals/NullLiteral.js +24 -0
- data/lib/spider-src/support/spider/lib/ast/literals/NumberLiteral.js +24 -0
- data/lib/spider-src/support/spider/lib/ast/literals/RegularExpressionLiteral.js +25 -0
- data/lib/spider-src/support/spider/lib/ast/literals/StringLiteral.js +90 -0
- data/lib/spider-src/support/spider/lib/ast/literals/UndefinedLiteral.js +30 -0
- data/lib/spider-src/support/spider/lib/ast/statements/BlockStatement.js +47 -0
- data/lib/spider-src/support/spider/lib/ast/statements/BreakStatement.js +19 -0
- data/lib/spider-src/support/spider/lib/ast/statements/ContinueStatement.js +19 -0
- data/lib/spider-src/support/spider/lib/ast/statements/DebuggerStatement.js +19 -0
- data/lib/spider-src/support/spider/lib/ast/statements/DoWhileStatement.js +25 -0
- data/lib/spider-src/support/spider/lib/ast/statements/ExportDeclarationStatement.js +51 -0
- data/lib/spider-src/support/spider/lib/ast/statements/ExpressionStatement.js +22 -0
- data/lib/spider-src/support/spider/lib/ast/statements/FallthroughStatement.js +74 -0
- data/lib/spider-src/support/spider/lib/ast/statements/ForInStatement.js +79 -0
- data/lib/spider-src/support/spider/lib/ast/statements/ForOfStatement.js +98 -0
- data/lib/spider-src/support/spider/lib/ast/statements/ForStatement.js +43 -0
- data/lib/spider-src/support/spider/lib/ast/statements/FunctionDeclarationStatement.js +104 -0
- data/lib/spider-src/support/spider/lib/ast/statements/GoStatement.js +41 -0
- data/lib/spider-src/support/spider/lib/ast/statements/IfStatement.js +32 -0
- data/lib/spider-src/support/spider/lib/ast/statements/ImportDeclarationStatement.js +40 -0
- data/lib/spider-src/support/spider/lib/ast/statements/PushStatement.js +37 -0
- data/lib/spider-src/support/spider/lib/ast/statements/ReturnStatement.js +26 -0
- data/lib/spider-src/support/spider/lib/ast/statements/SwitchStatement.js +159 -0
- data/lib/spider-src/support/spider/lib/ast/statements/ThrowStatement.js +22 -0
- data/lib/spider-src/support/spider/lib/ast/statements/TryStatement.js +36 -0
- data/lib/spider-src/support/spider/lib/ast/statements/UntilStatement.js +31 -0
- data/lib/spider-src/support/spider/lib/ast/statements/UseStatement.js +49 -0
- data/lib/spider-src/support/spider/lib/ast/statements/VariableDeclarationStatement.js +36 -0
- data/lib/spider-src/support/spider/lib/ast/statements/WhileStatement.js +25 -0
- data/lib/spider-src/support/spider/lib/ast.js +16 -0
- data/lib/spider-src/support/spider/lib/parser.js +14878 -0
- data/lib/spider-src/support/spider/lib/spider.js +217 -0
- data/lib/spider-src/support/spider/package.json +61 -0
- data/lib/spider-src/support/spider/spider-script.js +6 -0
- data/lib/spider-src/support/spider/src/ast/CaseClause.spider +179 -0
- data/lib/spider-src/support/spider/src/ast/CatchClause.spider +30 -0
- data/lib/spider-src/support/spider/src/ast/ExportBatchSpecifier.spider +19 -0
- data/lib/spider-src/support/spider/src/ast/ExportSpecifier.spider +37 -0
- data/lib/spider-src/support/spider/src/ast/ImportDefaultSpecifier.spider +25 -0
- data/lib/spider-src/support/spider/src/ast/ImportNamespaceSpecifier.spider +25 -0
- data/lib/spider-src/support/spider/src/ast/ImportSpecifier.spider +44 -0
- data/lib/spider-src/support/spider/src/ast/Node.spider +104 -0
- data/lib/spider-src/support/spider/src/ast/Parameter.spider +233 -0
- data/lib/spider-src/support/spider/src/ast/Program.spider +109 -0
- data/lib/spider-src/support/spider/src/ast/Property.spider +36 -0
- data/lib/spider-src/support/spider/src/ast/Range.spider +291 -0
- data/lib/spider-src/support/spider/src/ast/VariableDeclarator.spider +33 -0
- data/lib/spider-src/support/spider/src/ast/expressions/ArrayExpression.spider +32 -0
- data/lib/spider-src/support/spider/src/ast/expressions/ArrayPattern.spider +37 -0
- data/lib/spider-src/support/spider/src/ast/expressions/AssignmentExpression.spider +34 -0
- data/lib/spider-src/support/spider/src/ast/expressions/BinaryExpression.spider +125 -0
- data/lib/spider-src/support/spider/src/ast/expressions/CallExpression.spider +149 -0
- data/lib/spider-src/support/spider/src/ast/expressions/ConditionalExpression.spider +34 -0
- data/lib/spider-src/support/spider/src/ast/expressions/CurryCallExpression.spider +109 -0
- data/lib/spider-src/support/spider/src/ast/expressions/ExistentialExpression.spider +102 -0
- data/lib/spider-src/support/spider/src/ast/expressions/ForInExpression.spider +140 -0
- data/lib/spider-src/support/spider/src/ast/expressions/FunctionExpression.spider +183 -0
- data/lib/spider-src/support/spider/src/ast/expressions/InExpression.spider +114 -0
- data/lib/spider-src/support/spider/src/ast/expressions/LogicalExpression.spider +62 -0
- data/lib/spider-src/support/spider/src/ast/expressions/MemberExpression.spider +57 -0
- data/lib/spider-src/support/spider/src/ast/expressions/NewExpression.spider +40 -0
- data/lib/spider-src/support/spider/src/ast/expressions/NullCheckCallExpression.spider +151 -0
- data/lib/spider-src/support/spider/src/ast/expressions/NullCoalescingExpression.spider +151 -0
- data/lib/spider-src/support/spider/src/ast/expressions/NullPropagatingExpression.spider +190 -0
- data/lib/spider-src/support/spider/src/ast/expressions/ObjectExpression.spider +30 -0
- data/lib/spider-src/support/spider/src/ast/expressions/ObjectPattern.spider +42 -0
- data/lib/spider-src/support/spider/src/ast/expressions/RangeMemberExpression.spider +179 -0
- data/lib/spider-src/support/spider/src/ast/expressions/SplatExpression.spider +49 -0
- data/lib/spider-src/support/spider/src/ast/expressions/SuperExpression.spider +235 -0
- data/lib/spider-src/support/spider/src/ast/expressions/ThisExpression.spider +21 -0
- data/lib/spider-src/support/spider/src/ast/expressions/UnaryExpression.spider +158 -0
- data/lib/spider-src/support/spider/src/ast/expressions/UpdateExpression.spider +28 -0
- data/lib/spider-src/support/spider/src/ast/literals/BooleanLiteral.spider +23 -0
- data/lib/spider-src/support/spider/src/ast/literals/Identifier.spider +68 -0
- data/lib/spider-src/support/spider/src/ast/literals/NullLiteral.spider +23 -0
- data/lib/spider-src/support/spider/src/ast/literals/NumberLiteral.spider +23 -0
- data/lib/spider-src/support/spider/src/ast/literals/RegularExpressionLiteral.spider +24 -0
- data/lib/spider-src/support/spider/src/ast/literals/StringLiteral.spider +91 -0
- data/lib/spider-src/support/spider/src/ast/literals/UndefinedLiteral.spider +30 -0
- data/lib/spider-src/support/spider/src/ast/statements/BlockStatement.spider +45 -0
- data/lib/spider-src/support/spider/src/ast/statements/BreakStatement.spider +19 -0
- data/lib/spider-src/support/spider/src/ast/statements/ContinueStatement.spider +19 -0
- data/lib/spider-src/support/spider/src/ast/statements/DebuggerStatement.spider +19 -0
- data/lib/spider-src/support/spider/src/ast/statements/DoWhileStatement.spider +28 -0
- data/lib/spider-src/support/spider/src/ast/statements/ExportDeclarationStatement.spider +46 -0
- data/lib/spider-src/support/spider/src/ast/statements/ExpressionStatement.spider +22 -0
- data/lib/spider-src/support/spider/src/ast/statements/FallthroughStatement.spider +85 -0
- data/lib/spider-src/support/spider/src/ast/statements/ForInStatement.spider +92 -0
- data/lib/spider-src/support/spider/src/ast/statements/ForOfStatement.spider +117 -0
- data/lib/spider-src/support/spider/src/ast/statements/ForStatement.spider +51 -0
- data/lib/spider-src/support/spider/src/ast/statements/FunctionDeclarationStatement.spider +115 -0
- data/lib/spider-src/support/spider/src/ast/statements/GoStatement.spider +44 -0
- data/lib/spider-src/support/spider/src/ast/statements/IfStatement.spider +38 -0
- data/lib/spider-src/support/spider/src/ast/statements/ImportDeclarationStatement.spider +33 -0
- data/lib/spider-src/support/spider/src/ast/statements/PushStatement.spider +40 -0
- data/lib/spider-src/support/spider/src/ast/statements/ReturnStatement.spider +28 -0
- data/lib/spider-src/support/spider/src/ast/statements/SwitchStatement.spider +161 -0
- data/lib/spider-src/support/spider/src/ast/statements/ThrowStatement.spider +23 -0
- data/lib/spider-src/support/spider/src/ast/statements/TryStatement.spider +42 -0
- data/lib/spider-src/support/spider/src/ast/statements/UntilStatement.spider +36 -0
- data/lib/spider-src/support/spider/src/ast/statements/UseStatement.spider +62 -0
- data/lib/spider-src/support/spider/src/ast/statements/VariableDeclarationStatement.spider +34 -0
- data/lib/spider-src/support/spider/src/ast/statements/WhileStatement.spider +28 -0
- data/lib/spider-src/support/spider/src/ast.spider +80 -0
- data/lib/spider-src/support/spider/src/spider.pegjs +1434 -0
- data/lib/spider-src/support/spider/src/spider.spider +276 -0
- data/lib/spider-src/support/spider/test/spider_test.js +1787 -0
- data/lib/spider-src/version.rb +5 -0
- data/lib/spider-src.rb +37 -0
- data/spider-src.gemspec +24 -0
- data/test/test_spider_src.rb +33 -0
- metadata +225 -0
@@ -0,0 +1,62 @@
|
|
1
|
+
use :node;
|
2
|
+
|
3
|
+
var Node = module.require('../Node').Node;
|
4
|
+
|
5
|
+
fn LogicalExpression(left, operator, right)
|
6
|
+
extends Node {
|
7
|
+
|
8
|
+
this.type = 'LogicalExpression';
|
9
|
+
this.operator = operator;
|
10
|
+
|
11
|
+
switch this.operator {
|
12
|
+
case 'and': {
|
13
|
+
this.operator = '&&';
|
14
|
+
},
|
15
|
+
|
16
|
+
case 'or': {
|
17
|
+
this.operator = '||';
|
18
|
+
}
|
19
|
+
}
|
20
|
+
|
21
|
+
this.left = left;
|
22
|
+
this.left.parent = this;
|
23
|
+
|
24
|
+
this.right = right;
|
25
|
+
this.right.parent = this;
|
26
|
+
}
|
27
|
+
|
28
|
+
LogicalExpression.prototype.codegen = () -> {
|
29
|
+
if !super.codegen() {
|
30
|
+
return;
|
31
|
+
}
|
32
|
+
|
33
|
+
var enforceBooleanExpression = (o) -> {
|
34
|
+
if o.type == "UnaryExpression" and o.operator == "!" {
|
35
|
+
return o;
|
36
|
+
}
|
37
|
+
|
38
|
+
return {
|
39
|
+
"type": "UnaryExpression",
|
40
|
+
"operator": "!",
|
41
|
+
"argument": {
|
42
|
+
"type": "UnaryExpression",
|
43
|
+
"operator": "!",
|
44
|
+
"argument": o,
|
45
|
+
"prefix": true
|
46
|
+
},
|
47
|
+
"prefix": true
|
48
|
+
};
|
49
|
+
};
|
50
|
+
|
51
|
+
this.left = enforceBooleanExpression(this.left.codegen());
|
52
|
+
this.right = enforceBooleanExpression(this.right.codegen());
|
53
|
+
|
54
|
+
return this;
|
55
|
+
};
|
56
|
+
|
57
|
+
LogicalExpression.prototype.hasCallExpression = () -> {
|
58
|
+
return this.left?.hasCallExpression() ||
|
59
|
+
this.right?.hasCallExpression();
|
60
|
+
};
|
61
|
+
|
62
|
+
exports.LogicalExpression = LogicalExpression;
|
@@ -0,0 +1,57 @@
|
|
1
|
+
use :node;
|
2
|
+
|
3
|
+
var Node = module.require('../Node').Node;
|
4
|
+
|
5
|
+
fn MemberExpression(left, right, computed)
|
6
|
+
extends Node {
|
7
|
+
|
8
|
+
this.type = 'MemberExpression';
|
9
|
+
this.computed = computed;
|
10
|
+
|
11
|
+
this.object = left;
|
12
|
+
this.object.parent = this;
|
13
|
+
|
14
|
+
this.property = right;
|
15
|
+
this.property.parent = this;
|
16
|
+
}
|
17
|
+
|
18
|
+
MemberExpression.prototype.codegen = () -> {
|
19
|
+
if !super.codegen() {
|
20
|
+
return;
|
21
|
+
}
|
22
|
+
|
23
|
+
var objectType = this.object.type;
|
24
|
+
this.object = this.object.codegen();
|
25
|
+
|
26
|
+
if !this.property.codeGenerated {
|
27
|
+
this.property = this.property.codegen(false);
|
28
|
+
}
|
29
|
+
|
30
|
+
// compile an expression such as: b?.c?.d.e
|
31
|
+
// to: typeof b !== "undefined" && (b !== null && b.c !== null) ? b.c.d.e : null
|
32
|
+
// instead of: (typeof b !== "undefined" && (b !== null && b.c !== null) ? b.c.d : null).e;
|
33
|
+
if (this.object.type == 'ConditionalExpression' &&
|
34
|
+
(objectType == 'NullPropagatingExpression' || objectType == 'MemberExpression' ||
|
35
|
+
objectType == 'CallExpression' || objectType == 'NullCheckCallExpression')) {
|
36
|
+
this.type = this.object.type;
|
37
|
+
this.test = this.object.test;
|
38
|
+
this.alternate = this.object.alternate;
|
39
|
+
|
40
|
+
this.consequent = {
|
41
|
+
type: 'MemberExpression',
|
42
|
+
object: this.object.consequent,
|
43
|
+
property: this.property,
|
44
|
+
computed: this.computed
|
45
|
+
};
|
46
|
+
}
|
47
|
+
|
48
|
+
return this;
|
49
|
+
};
|
50
|
+
|
51
|
+
MemberExpression.prototype.hasCallExpression = () -> {
|
52
|
+
return this.object.__null_propagating ||
|
53
|
+
this.object?.hasCallExpression?() ||
|
54
|
+
this.property?.hasCallExpression();
|
55
|
+
};
|
56
|
+
|
57
|
+
exports.MemberExpression = MemberExpression;
|
@@ -0,0 +1,40 @@
|
|
1
|
+
use :node;
|
2
|
+
|
3
|
+
var Node = module.require('../Node').Node;
|
4
|
+
|
5
|
+
fn NewExpression(callee, args)
|
6
|
+
extends Node {
|
7
|
+
|
8
|
+
this.type = 'NewExpression';
|
9
|
+
|
10
|
+
this.callee = callee;
|
11
|
+
this.callee.parent = this;
|
12
|
+
|
13
|
+
::Object.defineProperty(this, 'arguments', {
|
14
|
+
value: args,
|
15
|
+
enumerable: true
|
16
|
+
});
|
17
|
+
|
18
|
+
for arg in args {
|
19
|
+
arg.parent = this;
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
23
|
+
NewExpression.prototype.codegen = () -> {
|
24
|
+
if !super.codegen() {
|
25
|
+
return;
|
26
|
+
}
|
27
|
+
|
28
|
+
this.callee = this.callee.codegen();
|
29
|
+
|
30
|
+
var args = this.arguments;
|
31
|
+
for arg, i in args {
|
32
|
+
args[i] = arg.codegen();
|
33
|
+
}
|
34
|
+
|
35
|
+
return this;
|
36
|
+
};
|
37
|
+
|
38
|
+
NewExpression.prototype.hasCallExpression = () -> true;
|
39
|
+
|
40
|
+
exports.NewExpression = NewExpression;
|
@@ -0,0 +1,151 @@
|
|
1
|
+
use :node;
|
2
|
+
|
3
|
+
var Node = module.require('../Node').Node,
|
4
|
+
CallExpression = module.require('./CallExpression').CallExpression;
|
5
|
+
|
6
|
+
fn NullCheckCallExpression(callee, args)
|
7
|
+
extends Node {
|
8
|
+
|
9
|
+
this.type = 'NullCheckCallExpression';
|
10
|
+
|
11
|
+
this.callee = callee;
|
12
|
+
this.callee.parent = this;
|
13
|
+
|
14
|
+
this.args = args;
|
15
|
+
|
16
|
+
for arg in args {
|
17
|
+
arg.parent = this;
|
18
|
+
}
|
19
|
+
}
|
20
|
+
|
21
|
+
NullCheckCallExpression.prototype.codegen = () -> {
|
22
|
+
if !super.codegen() {
|
23
|
+
return;
|
24
|
+
}
|
25
|
+
|
26
|
+
var calleeType = this.callee.type;
|
27
|
+
|
28
|
+
this.callee = this.callee.codegen();
|
29
|
+
|
30
|
+
var args = this.args;
|
31
|
+
for arg, i in args {
|
32
|
+
var isSplat = args[i].type == "SplatExpression";
|
33
|
+
args[i] = arg.codegen();
|
34
|
+
args[i].codeGenerated = true;
|
35
|
+
|
36
|
+
if isSplat {
|
37
|
+
args[i].__splat = true;
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
// If the callee has a function call (e.g: a().b)
|
42
|
+
// then store its value in a separate variable to avoid
|
43
|
+
// calling the function twice.
|
44
|
+
if this.callee.hasCallExpression?() {
|
45
|
+
var context = this.getContext();
|
46
|
+
|
47
|
+
var id = {
|
48
|
+
"type": "Identifier",
|
49
|
+
"name": NullCheckCallExpression.getNextVariableName(),
|
50
|
+
"codeGenerated": true
|
51
|
+
};
|
52
|
+
|
53
|
+
context.node.body.splice(context.position +
|
54
|
+
(NullCheckCallExpression.nullCheckIndex - 2), 0, {
|
55
|
+
"type": "VariableDeclaration",
|
56
|
+
"declarations": [
|
57
|
+
{
|
58
|
+
"type": "VariableDeclarator",
|
59
|
+
"id": id,
|
60
|
+
"init": this.callee
|
61
|
+
}
|
62
|
+
],
|
63
|
+
"kind": "let",
|
64
|
+
"codeGenerated": true
|
65
|
+
});
|
66
|
+
|
67
|
+
this.callee = id;
|
68
|
+
}
|
69
|
+
|
70
|
+
// Create a basic typeof callee !== "function" check
|
71
|
+
var test = {
|
72
|
+
"type": "BinaryExpression",
|
73
|
+
"operator": "===",
|
74
|
+
"left": {
|
75
|
+
"type": "UnaryExpression",
|
76
|
+
"operator": "typeof",
|
77
|
+
"argument": this.callee,
|
78
|
+
"prefix": true
|
79
|
+
},
|
80
|
+
"right": {
|
81
|
+
"type": "Literal",
|
82
|
+
"value": "function",
|
83
|
+
"raw": "\"function\""
|
84
|
+
}
|
85
|
+
};
|
86
|
+
|
87
|
+
var argument = test.left.argument;
|
88
|
+
|
89
|
+
// If we are null propagating (?.), then make sure to
|
90
|
+
// add the null propagating condition
|
91
|
+
if calleeType == 'NullPropagatingExpression' {
|
92
|
+
argument = argument.consequent;
|
93
|
+
test.left.argument = argument;
|
94
|
+
|
95
|
+
test = {
|
96
|
+
"type": "LogicalExpression",
|
97
|
+
"operator": "&&",
|
98
|
+
"left": this.callee.test,
|
99
|
+
"right": test
|
100
|
+
};
|
101
|
+
}
|
102
|
+
|
103
|
+
argument.codeGenerated = true;
|
104
|
+
var consequent = new CallExpression(argument, args).codegen();
|
105
|
+
|
106
|
+
if this.parent.type == 'ExpressionStatement' {
|
107
|
+
this.parent.type = 'IfStatement';
|
108
|
+
this.parent.test = test;
|
109
|
+
this.parent.consequent = {
|
110
|
+
type: 'BlockStatement',
|
111
|
+
body: [
|
112
|
+
{
|
113
|
+
type: 'ExpressionStatement',
|
114
|
+
expression: consequent
|
115
|
+
}
|
116
|
+
]
|
117
|
+
};
|
118
|
+
this.parent.alternate = null;
|
119
|
+
} else {
|
120
|
+
this.type = 'ConditionalExpression';
|
121
|
+
this.test = test;
|
122
|
+
this.consequent = consequent;
|
123
|
+
this.alternate = {
|
124
|
+
"type": "UnaryExpression",
|
125
|
+
"operator": "void",
|
126
|
+
"argument": {
|
127
|
+
"type": "Literal",
|
128
|
+
"value": 0,
|
129
|
+
"raw": "0"
|
130
|
+
},
|
131
|
+
"prefix": true
|
132
|
+
};
|
133
|
+
}
|
134
|
+
return this;
|
135
|
+
};
|
136
|
+
|
137
|
+
NullCheckCallExpression.prototype.hasCallExpression = () -> true;
|
138
|
+
|
139
|
+
NullCheckCallExpression.getNextVariableName = () -> {
|
140
|
+
if !this.nullCheckIndex? {
|
141
|
+
this.nullCheckIndex = 0;
|
142
|
+
}
|
143
|
+
|
144
|
+
return "nullCheck" + this.nullCheckIndex++;
|
145
|
+
};
|
146
|
+
|
147
|
+
NullCheckCallExpression.resetVariableNames = () -> {
|
148
|
+
this.nullCheckIndex = 0;
|
149
|
+
};
|
150
|
+
|
151
|
+
exports.NullCheckCallExpression = NullCheckCallExpression;
|
@@ -0,0 +1,151 @@
|
|
1
|
+
use :node;
|
2
|
+
|
3
|
+
var Node = module.require('../Node').Node;
|
4
|
+
|
5
|
+
fn NullCoalescingExpression(left, right)
|
6
|
+
extends Node {
|
7
|
+
|
8
|
+
this.type = 'NullCoalescingExpression';
|
9
|
+
|
10
|
+
this.left = left;
|
11
|
+
this.left.parent = this;
|
12
|
+
|
13
|
+
this.right = right;
|
14
|
+
this.right.parent = this;
|
15
|
+
}
|
16
|
+
|
17
|
+
NullCoalescingExpression.prototype.codegen = () -> {
|
18
|
+
if !super.codegen() {
|
19
|
+
return;
|
20
|
+
}
|
21
|
+
|
22
|
+
var leftType = this.left.type;
|
23
|
+
|
24
|
+
this.left = this.left.codegen();
|
25
|
+
this.right = this.right.codegen();
|
26
|
+
|
27
|
+
var context = this.getContext();
|
28
|
+
var addUndefinedCheck = true;
|
29
|
+
|
30
|
+
// If the left expression is a function call (e.g: f() ?? 5)
|
31
|
+
// then store its value in a separate variable to avoid
|
32
|
+
// calling the function twice.
|
33
|
+
if leftType == 'NullPropagatingExpression' ||
|
34
|
+
leftType == 'NullCoalescingExpression' ||
|
35
|
+
this.left.hasCallExpression?() {
|
36
|
+
|
37
|
+
var id = {
|
38
|
+
"type": "Identifier",
|
39
|
+
"name": NullCoalescingExpression.getNextLeftName()
|
40
|
+
};
|
41
|
+
|
42
|
+
context.node.body.splice(context.position, 0, {
|
43
|
+
"type": "VariableDeclaration",
|
44
|
+
"declarations": [
|
45
|
+
{
|
46
|
+
"type": "VariableDeclarator",
|
47
|
+
"id": id,
|
48
|
+
"init": this.left
|
49
|
+
}
|
50
|
+
],
|
51
|
+
"kind": "let",
|
52
|
+
"codeGenerated": true
|
53
|
+
});
|
54
|
+
|
55
|
+
this.left = id;
|
56
|
+
addUndefinedCheck = false;
|
57
|
+
}
|
58
|
+
|
59
|
+
var test = {
|
60
|
+
"type": "BinaryExpression",
|
61
|
+
"operator": "==",
|
62
|
+
"left": this.left,
|
63
|
+
"right": {
|
64
|
+
"type": "Literal",
|
65
|
+
"value": null,
|
66
|
+
"raw": "null"
|
67
|
+
}
|
68
|
+
};
|
69
|
+
|
70
|
+
if this.left.type != 'Identifier' {
|
71
|
+
addUndefinedCheck = false;
|
72
|
+
}
|
73
|
+
|
74
|
+
if addUndefinedCheck {
|
75
|
+
test = {
|
76
|
+
"type": "LogicalExpression",
|
77
|
+
"operator": "||",
|
78
|
+
"left": {
|
79
|
+
"type": "BinaryExpression",
|
80
|
+
"operator": "===",
|
81
|
+
"left": {
|
82
|
+
"type": "UnaryExpression",
|
83
|
+
"operator": "typeof",
|
84
|
+
"argument": this.left,
|
85
|
+
"prefix": true
|
86
|
+
},
|
87
|
+
"right": {
|
88
|
+
"type": "Literal",
|
89
|
+
"value": "undefined",
|
90
|
+
"raw": "'undefined'"
|
91
|
+
}
|
92
|
+
},
|
93
|
+
"right": test
|
94
|
+
};
|
95
|
+
}
|
96
|
+
|
97
|
+
// If the null coalescing operator is an expression
|
98
|
+
// statement child, the generated JS should be an if statement.
|
99
|
+
if this.parent?.type == 'ExpressionStatement' {
|
100
|
+
|
101
|
+
if !this.right.hasCallExpression() {
|
102
|
+
this.parent.type = 'EmptyStatement';
|
103
|
+
return this;
|
104
|
+
}
|
105
|
+
|
106
|
+
this.parent.type = 'IfStatement';
|
107
|
+
this.parent.test = test;
|
108
|
+
|
109
|
+
this.parent.consequent = {
|
110
|
+
"type": "BlockStatement",
|
111
|
+
"body": [
|
112
|
+
{
|
113
|
+
"type": "ExpressionStatement",
|
114
|
+
"expression": this.right
|
115
|
+
}
|
116
|
+
]
|
117
|
+
};
|
118
|
+
} else {
|
119
|
+
// Otherwise - if the null coalescing operator is
|
120
|
+
// inside an expression, the generated JS should
|
121
|
+
// look like:
|
122
|
+
//
|
123
|
+
// typeof left === 'undefined' || left === null ? right : left
|
124
|
+
|
125
|
+
return {
|
126
|
+
"type": "ConditionalExpression",
|
127
|
+
"test": test,
|
128
|
+
"consequent": this.right,
|
129
|
+
"alternate": this.left
|
130
|
+
};
|
131
|
+
}
|
132
|
+
};
|
133
|
+
|
134
|
+
NullCoalescingExpression.prototype.hasCallExpression = () -> {
|
135
|
+
return this.left?.hasCallExpression() ||
|
136
|
+
this.right?.hasCallExpression();
|
137
|
+
};
|
138
|
+
|
139
|
+
NullCoalescingExpression.getNextLeftName = () -> {
|
140
|
+
if (!this.nullCoalescingIndex?) {
|
141
|
+
this.nullCoalescingIndex = 0;
|
142
|
+
}
|
143
|
+
|
144
|
+
return "nullCoalescing" + this.nullCoalescingIndex++;
|
145
|
+
};
|
146
|
+
|
147
|
+
NullCoalescingExpression.resetVariableNames = () -> {
|
148
|
+
this.nullCoalescingIndex = 0;
|
149
|
+
};
|
150
|
+
|
151
|
+
exports.NullCoalescingExpression = NullCoalescingExpression;
|
@@ -0,0 +1,190 @@
|
|
1
|
+
use :node;
|
2
|
+
|
3
|
+
var Node = module.require('../Node').Node;
|
4
|
+
|
5
|
+
fn NullPropagatingExpression(left, right)
|
6
|
+
extends Node {
|
7
|
+
|
8
|
+
this.type = 'NullPropagatingExpression';
|
9
|
+
this.computed = false;
|
10
|
+
|
11
|
+
this.object = left;
|
12
|
+
this.object.parent = this;
|
13
|
+
|
14
|
+
this.property = right;
|
15
|
+
this.property.parent = this;
|
16
|
+
}
|
17
|
+
|
18
|
+
NullPropagatingExpression.prototype.codegen = () -> {
|
19
|
+
if !super.codegen() {
|
20
|
+
return;
|
21
|
+
}
|
22
|
+
|
23
|
+
var context = this.getContext();
|
24
|
+
var childType = this.object.type;
|
25
|
+
|
26
|
+
this.object = this.object.codegen();
|
27
|
+
this.property = this.property.codegen(false);
|
28
|
+
|
29
|
+
// If the left expression is a function call (e.g: a()?.b)
|
30
|
+
// then store its value in a separate variable to avoid
|
31
|
+
// calling the function twice.
|
32
|
+
if this.object.hasCallExpression?() {
|
33
|
+
var id = {
|
34
|
+
"type": "Identifier",
|
35
|
+
"name": NullPropagatingExpression.getNextObjectName(),
|
36
|
+
"__member_expression": {
|
37
|
+
"type": "MemberExpression",
|
38
|
+
"object": this.object,
|
39
|
+
"property": this.property,
|
40
|
+
"computed": false
|
41
|
+
},
|
42
|
+
};
|
43
|
+
|
44
|
+
context.node.body.splice(context.position +
|
45
|
+
(NullPropagatingExpression.nullPropagatingIndex - 1), 0, {
|
46
|
+
"type": "VariableDeclaration",
|
47
|
+
"declarations": [
|
48
|
+
{
|
49
|
+
"type": "VariableDeclarator",
|
50
|
+
"id": id,
|
51
|
+
"init": this.object
|
52
|
+
}
|
53
|
+
],
|
54
|
+
"kind": "let",
|
55
|
+
"codeGenerated": true
|
56
|
+
});
|
57
|
+
|
58
|
+
this.object = id;
|
59
|
+
}
|
60
|
+
|
61
|
+
var condition;
|
62
|
+
|
63
|
+
// If this node is the last NullPropagatingExpression in
|
64
|
+
// the tree, then just create a simple object !== null condition
|
65
|
+
if childType != 'NullPropagatingExpression' {
|
66
|
+
condition = {
|
67
|
+
"type": "BinaryExpression",
|
68
|
+
"operator": "!==",
|
69
|
+
"left": this.object,
|
70
|
+
"right": {
|
71
|
+
"type": "Literal",
|
72
|
+
"value": null,
|
73
|
+
"raw": "null"
|
74
|
+
},
|
75
|
+
"__member_expression": {
|
76
|
+
"type": "MemberExpression",
|
77
|
+
"object": this.object,
|
78
|
+
"property": this.property,
|
79
|
+
"computed": false
|
80
|
+
},
|
81
|
+
"__first_object": this.object
|
82
|
+
};
|
83
|
+
} else {
|
84
|
+
// Otherwise create an object !== null condition and add it
|
85
|
+
// with logical AND to the previous condition
|
86
|
+
condition = {
|
87
|
+
"type": 'LogicalExpression',
|
88
|
+
"operator": '&&',
|
89
|
+
"left": this.object,
|
90
|
+
"right": {
|
91
|
+
"type": "BinaryExpression",
|
92
|
+
"operator": "!==",
|
93
|
+
"left": {
|
94
|
+
"type": "MemberExpression",
|
95
|
+
"object": this.object.__member_expression.object,
|
96
|
+
"property": this.object.__member_expression.property,
|
97
|
+
"computed": false
|
98
|
+
},
|
99
|
+
"right": {
|
100
|
+
"type": "Literal",
|
101
|
+
"value": null,
|
102
|
+
"raw": "null"
|
103
|
+
},
|
104
|
+
},
|
105
|
+
"__member_expression": {
|
106
|
+
"type": "MemberExpression",
|
107
|
+
"object": this.object.__member_expression,
|
108
|
+
"property": this.property,
|
109
|
+
"computed": false
|
110
|
+
},
|
111
|
+
"__first_object": this.object.__first_object
|
112
|
+
};
|
113
|
+
}
|
114
|
+
|
115
|
+
// Return the condition if this isn't the first NullPropagatingExpression
|
116
|
+
if this.parent?.type == 'NullPropagatingExpression' {
|
117
|
+
return condition;
|
118
|
+
}
|
119
|
+
|
120
|
+
// Add typeof object !== undefined check
|
121
|
+
condition = {
|
122
|
+
"type": 'LogicalExpression',
|
123
|
+
"operator": '&&',
|
124
|
+
"left": {
|
125
|
+
"type": "BinaryExpression",
|
126
|
+
"operator": "!==",
|
127
|
+
"left": {
|
128
|
+
"type": "UnaryExpression",
|
129
|
+
"operator": "typeof",
|
130
|
+
"argument": this.object.__first_object ?? this.object
|
131
|
+
},
|
132
|
+
"right": {
|
133
|
+
"type": "Literal",
|
134
|
+
"value": "undefined",
|
135
|
+
"raw": "\"undefined\""
|
136
|
+
},
|
137
|
+
},
|
138
|
+
"right": condition
|
139
|
+
};
|
140
|
+
|
141
|
+
condition = {
|
142
|
+
"type": "ConditionalExpression",
|
143
|
+
"test": condition,
|
144
|
+
"consequent": {
|
145
|
+
"type": "MemberExpression",
|
146
|
+
"object": this.object if this.object.type == 'Identifier' || !this.object.__member_expression
|
147
|
+
else this.object.__member_expression,
|
148
|
+
"property": this.property,
|
149
|
+
"computed": false
|
150
|
+
},
|
151
|
+
"alternate": {
|
152
|
+
"type": "UnaryExpression",
|
153
|
+
"operator": "void",
|
154
|
+
"argument": {
|
155
|
+
"type": "Literal",
|
156
|
+
"value": 0,
|
157
|
+
"raw": "0"
|
158
|
+
},
|
159
|
+
"prefix": true
|
160
|
+
},
|
161
|
+
"__null_propagating": true
|
162
|
+
};
|
163
|
+
|
164
|
+
return condition;
|
165
|
+
};
|
166
|
+
|
167
|
+
NullPropagatingExpression.prototype.hasCallExpression = () -> true;
|
168
|
+
|
169
|
+
NullPropagatingExpression.getNextObjectName = () -> {
|
170
|
+
if !this.nullPropagatingIndex? {
|
171
|
+
this.nullPropagatingIndex = 0;
|
172
|
+
this.definedObjectNames = [];
|
173
|
+
}
|
174
|
+
|
175
|
+
var name = "nullPropagating" + this.nullPropagatingIndex++;
|
176
|
+
this.definedObjectNames.push(name);
|
177
|
+
|
178
|
+
return name;
|
179
|
+
};
|
180
|
+
|
181
|
+
NullPropagatingExpression.isObjectNameDefined = (name) -> {
|
182
|
+
return this.definedObjectNames.indexOf(name) != -1;
|
183
|
+
};
|
184
|
+
|
185
|
+
NullPropagatingExpression.resetVariableNames = () -> {
|
186
|
+
this.nullPropagatingIndex = 0;
|
187
|
+
this.definedObjectNames = [];
|
188
|
+
};
|
189
|
+
|
190
|
+
exports.NullPropagatingExpression = NullPropagatingExpression;
|
@@ -0,0 +1,30 @@
|
|
1
|
+
use :node;
|
2
|
+
|
3
|
+
var Node = module.require('../Node').Node;
|
4
|
+
|
5
|
+
fn ObjectExpression(properties)
|
6
|
+
extends Node {
|
7
|
+
|
8
|
+
this.type = 'ObjectExpression';
|
9
|
+
this.properties = properties;
|
10
|
+
|
11
|
+
for property in this.properties {
|
12
|
+
property.parent = this;
|
13
|
+
}
|
14
|
+
}
|
15
|
+
|
16
|
+
ObjectExpression.prototype.codegen = () -> {
|
17
|
+
if !super.codegen() {
|
18
|
+
return;
|
19
|
+
}
|
20
|
+
|
21
|
+
for property, i in this.properties {
|
22
|
+
this.properties[i] = property.codegen();
|
23
|
+
}
|
24
|
+
|
25
|
+
return this;
|
26
|
+
};
|
27
|
+
|
28
|
+
ObjectExpression.prototype.hasCallExpression = () -> true;
|
29
|
+
|
30
|
+
exports.ObjectExpression = ObjectExpression;
|