@ugo-studio/jspp 0.1.2 → 0.1.4
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/README.md +5 -3
- package/dist/analysis/scope.js +38 -15
- package/dist/analysis/typeAnalyzer.js +257 -23
- package/dist/ast/types.js +6 -0
- package/dist/cli.js +3 -4
- package/dist/core/codegen/class-handlers.js +127 -0
- package/dist/core/codegen/control-flow-handlers.js +464 -0
- package/dist/core/codegen/declaration-handlers.js +31 -14
- package/dist/core/codegen/expression-handlers.js +432 -116
- package/dist/core/codegen/function-handlers.js +110 -13
- package/dist/core/codegen/helpers.js +76 -8
- package/dist/core/codegen/index.js +18 -5
- package/dist/core/codegen/literal-handlers.js +3 -0
- package/dist/core/codegen/statement-handlers.js +152 -186
- package/dist/core/codegen/visitor.js +35 -3
- package/package.json +3 -3
- package/src/prelude/any_value.hpp +658 -734
- package/src/prelude/any_value_access.hpp +103 -0
- package/src/prelude/any_value_defines.hpp +151 -0
- package/src/prelude/any_value_helpers.hpp +246 -0
- package/src/prelude/exception.hpp +31 -0
- package/src/prelude/exception_helpers.hpp +49 -0
- package/src/prelude/index.hpp +35 -12
- package/src/prelude/library/console.hpp +20 -20
- package/src/prelude/library/error.hpp +111 -0
- package/src/prelude/library/global.hpp +15 -4
- package/src/prelude/library/performance.hpp +25 -0
- package/src/prelude/library/promise.hpp +121 -0
- package/src/prelude/library/symbol.hpp +60 -4
- package/src/prelude/library/timer.hpp +92 -0
- package/src/prelude/scheduler.hpp +145 -0
- package/src/prelude/types.hpp +33 -6
- package/src/prelude/utils/access.hpp +174 -0
- package/src/prelude/utils/log_any_value/array.hpp +245 -0
- package/src/prelude/utils/log_any_value/config.hpp +32 -0
- package/src/prelude/utils/log_any_value/function.hpp +37 -0
- package/src/prelude/utils/log_any_value/fwd.hpp +15 -0
- package/src/prelude/utils/log_any_value/helpers.hpp +62 -0
- package/src/prelude/utils/log_any_value/log_any_value.hpp +94 -0
- package/src/prelude/utils/log_any_value/object.hpp +119 -0
- package/src/prelude/utils/log_any_value/primitives.hpp +41 -0
- package/src/prelude/{operators.hpp → utils/operators.hpp} +31 -12
- package/src/prelude/utils/well_known_symbols.hpp +13 -0
- package/src/prelude/values/array.hpp +5 -2
- package/src/prelude/{descriptors.hpp → values/descriptors.hpp} +2 -2
- package/src/prelude/values/function.hpp +76 -19
- package/src/prelude/values/{operators → helpers}/array.hpp +30 -14
- package/src/prelude/values/helpers/function.hpp +125 -0
- package/src/prelude/values/helpers/iterator.hpp +107 -0
- package/src/prelude/values/helpers/object.hpp +64 -0
- package/src/prelude/values/helpers/promise.hpp +181 -0
- package/src/prelude/values/helpers/string.hpp +50 -0
- package/src/prelude/values/helpers/symbol.hpp +23 -0
- package/src/prelude/values/iterator.hpp +96 -0
- package/src/prelude/values/object.hpp +8 -3
- package/src/prelude/values/promise.hpp +73 -0
- package/src/prelude/values/prototypes/array.hpp +23 -16
- package/src/prelude/values/prototypes/function.hpp +26 -0
- package/src/prelude/values/prototypes/iterator.hpp +58 -0
- package/src/prelude/values/prototypes/object.hpp +26 -0
- package/src/prelude/values/prototypes/promise.hpp +124 -0
- package/src/prelude/values/prototypes/string.hpp +366 -357
- package/src/prelude/values/prototypes/symbol.hpp +41 -0
- package/src/prelude/values/string.hpp +25 -0
- package/src/prelude/values/symbol.hpp +102 -0
- package/src/prelude/access.hpp +0 -86
- package/src/prelude/error.hpp +0 -31
- package/src/prelude/error_helpers.hpp +0 -59
- package/src/prelude/log_string.hpp +0 -403
- package/src/prelude/values/operators/function.hpp +0 -34
- package/src/prelude/values/operators/object.hpp +0 -34
- package/src/prelude/well_known_symbols.hpp +0 -10
|
@@ -1,46 +1,122 @@
|
|
|
1
1
|
import ts from "typescript";
|
|
2
2
|
import { CodeGenerator } from "./";
|
|
3
|
-
function visitObjectPropertyName(node, context) {
|
|
3
|
+
export function visitObjectPropertyName(node, context) {
|
|
4
|
+
if (ts.isNumericLiteral(node)) {
|
|
5
|
+
return context.isBracketNotationPropertyAccess
|
|
6
|
+
? node.getText()
|
|
7
|
+
: `"${node.getText()}"`;
|
|
8
|
+
}
|
|
4
9
|
if (ts.isStringLiteral(node)) {
|
|
5
10
|
return `"${node.getText().substring(1, node.getText().length - 1) // remove trailing "' from original name
|
|
6
11
|
}"`;
|
|
7
12
|
}
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
if (ts.isComputedPropertyName(node)) {
|
|
14
|
+
const compExpr = node.expression;
|
|
15
|
+
let propName = this.visit(compExpr, context);
|
|
16
|
+
if (ts.isIdentifier(compExpr)) {
|
|
17
|
+
const scope = this.getScopeForNode(compExpr);
|
|
18
|
+
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(compExpr.getText(), scope);
|
|
19
|
+
propName = this.getDerefCode(propName, this.getJsVarName(compExpr), typeInfo);
|
|
20
|
+
}
|
|
21
|
+
return propName;
|
|
22
|
+
}
|
|
23
|
+
if (context.isBracketNotationPropertyAccess) {
|
|
24
|
+
return this.visit(node, context);
|
|
14
25
|
}
|
|
15
|
-
return
|
|
16
|
-
? node.getText()
|
|
17
|
-
: `"${node.getText()}"`;
|
|
26
|
+
return `"${node.getText()}"`;
|
|
18
27
|
}
|
|
19
28
|
export function visitObjectLiteralExpression(node, context) {
|
|
20
29
|
const obj = node;
|
|
21
|
-
|
|
30
|
+
const objVar = this.generateUniqueName("__obj_", this.getDeclaredSymbols(node));
|
|
31
|
+
let code = `([&]() {
|
|
32
|
+
${this.indent()} auto ${objVar} = jspp::AnyValue::make_object({});\n`;
|
|
33
|
+
this.indentationLevel++;
|
|
22
34
|
for (const prop of obj.properties) {
|
|
23
|
-
// console.log("Property kind:", ts.SyntaxKind[prop.kind]);
|
|
24
35
|
if (ts.isPropertyAssignment(prop)) {
|
|
25
|
-
const key = visitObjectPropertyName.call(this, prop.name,
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
36
|
+
const key = visitObjectPropertyName.call(this, prop.name, {
|
|
37
|
+
...context,
|
|
38
|
+
isObjectLiteralExpression: true,
|
|
39
|
+
});
|
|
40
|
+
const initializer = prop.initializer;
|
|
41
|
+
let value = this.visit(initializer, context);
|
|
42
|
+
if (ts.isIdentifier(initializer)) {
|
|
43
|
+
const scope = this.getScopeForNode(initializer);
|
|
44
|
+
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(initializer.text, scope);
|
|
45
|
+
if (typeInfo && !typeInfo.isBuiltin && !typeInfo.isParameter) {
|
|
46
|
+
value = this.getDerefCode(value, this.getJsVarName(initializer), typeInfo);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
code +=
|
|
50
|
+
`${this.indent()}${objVar}.define_data_property(${key}, ${value});\n`;
|
|
30
51
|
}
|
|
31
52
|
else if (ts.isShorthandPropertyAssignment(prop)) {
|
|
32
|
-
const key = visitObjectPropertyName.call(this, prop.name,
|
|
33
|
-
|
|
34
|
-
|
|
53
|
+
const key = visitObjectPropertyName.call(this, prop.name, {
|
|
54
|
+
...context,
|
|
55
|
+
isObjectLiteralExpression: true,
|
|
56
|
+
});
|
|
57
|
+
const scope = this.getScopeForNode(prop.name);
|
|
58
|
+
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(prop.name.text, scope);
|
|
59
|
+
let value = this.visit(prop.name, context);
|
|
60
|
+
if (typeInfo && !typeInfo.isBuiltin && !typeInfo.isParameter) {
|
|
61
|
+
value = this.getDerefCode(value, this.getJsVarName(prop.name), typeInfo);
|
|
62
|
+
}
|
|
63
|
+
code +=
|
|
64
|
+
`${this.indent()}${objVar}.define_data_property(${key}, ${value});\n`;
|
|
65
|
+
}
|
|
66
|
+
else if (ts.isMethodDeclaration(prop)) {
|
|
67
|
+
const key = visitObjectPropertyName.call(this, prop.name, {
|
|
68
|
+
...context,
|
|
69
|
+
isObjectLiteralExpression: true,
|
|
70
|
+
});
|
|
71
|
+
const lambda = this.generateLambda(prop, {
|
|
72
|
+
...context,
|
|
73
|
+
isInsideFunction: true,
|
|
74
|
+
});
|
|
75
|
+
code +=
|
|
76
|
+
`${this.indent()}${objVar}.define_data_property(${key}, ${lambda});\n`;
|
|
77
|
+
}
|
|
78
|
+
else if (ts.isGetAccessor(prop)) {
|
|
79
|
+
const key = visitObjectPropertyName.call(this, prop.name, {
|
|
80
|
+
...context,
|
|
81
|
+
isObjectLiteralExpression: true,
|
|
82
|
+
});
|
|
83
|
+
const lambda = this.generateLambda(prop, {
|
|
84
|
+
...context,
|
|
85
|
+
isInsideFunction: true,
|
|
86
|
+
});
|
|
87
|
+
code +=
|
|
88
|
+
`${this.indent()}${objVar}.define_getter(${key}, ${lambda});\n`;
|
|
89
|
+
}
|
|
90
|
+
else if (ts.isSetAccessor(prop)) {
|
|
91
|
+
const key = visitObjectPropertyName.call(this, prop.name, {
|
|
92
|
+
...context,
|
|
93
|
+
isObjectLiteralExpression: true,
|
|
94
|
+
});
|
|
95
|
+
const lambda = this.generateLambda(prop, {
|
|
96
|
+
...context,
|
|
97
|
+
isInsideFunction: true,
|
|
98
|
+
});
|
|
99
|
+
code +=
|
|
100
|
+
`${this.indent()}${objVar}.define_setter(${key}, ${lambda});\n`;
|
|
35
101
|
}
|
|
36
102
|
}
|
|
37
|
-
|
|
103
|
+
this.indentationLevel--;
|
|
104
|
+
code += `${this.indent()} return ${objVar};\n${this.indent()}})()`;
|
|
105
|
+
return code;
|
|
38
106
|
}
|
|
39
107
|
export function visitArrayLiteralExpression(node, context) {
|
|
40
108
|
const elements = node.elements
|
|
41
|
-
.map((elem) =>
|
|
42
|
-
|
|
43
|
-
|
|
109
|
+
.map((elem) => {
|
|
110
|
+
let elemText = this.visit(elem, context);
|
|
111
|
+
if (ts.isIdentifier(elem)) {
|
|
112
|
+
const scope = this.getScopeForNode(elem);
|
|
113
|
+
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(elem.text, scope);
|
|
114
|
+
if (typeInfo && !typeInfo.isBuiltin && !typeInfo.isParameter) {
|
|
115
|
+
elemText = this.getDerefCode(elemText, this.getJsVarName(elem), typeInfo);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return elemText;
|
|
119
|
+
})
|
|
44
120
|
.join(", ");
|
|
45
121
|
return `jspp::AnyValue::make_array({${elements}})`;
|
|
46
122
|
}
|
|
@@ -49,10 +125,32 @@ export function visitPrefixUnaryExpression(node, context) {
|
|
|
49
125
|
const operand = this.visit(prefixUnaryExpr.operand, context);
|
|
50
126
|
const operator = ts.tokenToString(prefixUnaryExpr.operator);
|
|
51
127
|
if (operator === "++" || operator === "--") {
|
|
52
|
-
|
|
128
|
+
let target = operand;
|
|
129
|
+
if (ts.isIdentifier(prefixUnaryExpr.operand)) {
|
|
130
|
+
const scope = this.getScopeForNode(prefixUnaryExpr.operand);
|
|
131
|
+
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(prefixUnaryExpr.operand.getText(), scope);
|
|
132
|
+
if (context.derefBeforeAssignment) {
|
|
133
|
+
target = this.getDerefCode(operand, operand, typeInfo);
|
|
134
|
+
}
|
|
135
|
+
else if (typeInfo.needsHeapAllocation) {
|
|
136
|
+
target = `*${operand}`;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return `${operator}(${target})`;
|
|
53
140
|
}
|
|
54
141
|
if (operator === "~") {
|
|
55
|
-
|
|
142
|
+
let target = operand;
|
|
143
|
+
if (ts.isIdentifier(prefixUnaryExpr.operand)) {
|
|
144
|
+
const scope = this.getScopeForNode(prefixUnaryExpr.operand);
|
|
145
|
+
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(prefixUnaryExpr.operand.getText(), scope);
|
|
146
|
+
if (context.derefBeforeAssignment) {
|
|
147
|
+
target = this.getDerefCode(operand, operand, typeInfo);
|
|
148
|
+
}
|
|
149
|
+
else if (typeInfo.needsHeapAllocation) {
|
|
150
|
+
target = `*${operand}`;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return `${operator}(${target})`;
|
|
56
154
|
}
|
|
57
155
|
return `${operator}${operand}`;
|
|
58
156
|
}
|
|
@@ -60,7 +158,18 @@ export function visitPostfixUnaryExpression(node, context) {
|
|
|
60
158
|
const postfixUnaryExpr = node;
|
|
61
159
|
const operand = this.visit(postfixUnaryExpr.operand, context);
|
|
62
160
|
const operator = ts.tokenToString(postfixUnaryExpr.operator);
|
|
63
|
-
|
|
161
|
+
let target = operand;
|
|
162
|
+
if (ts.isIdentifier(postfixUnaryExpr.operand)) {
|
|
163
|
+
const scope = this.getScopeForNode(postfixUnaryExpr.operand);
|
|
164
|
+
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(postfixUnaryExpr.operand.getText(), scope);
|
|
165
|
+
if (context.derefBeforeAssignment) {
|
|
166
|
+
target = this.getDerefCode(operand, operand, typeInfo);
|
|
167
|
+
}
|
|
168
|
+
else if (typeInfo.needsHeapAllocation) {
|
|
169
|
+
target = `*${operand}`;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return `(${target})${operator}`;
|
|
64
173
|
}
|
|
65
174
|
export function visitParenthesizedExpression(node, context) {
|
|
66
175
|
const parenExpr = node;
|
|
@@ -68,6 +177,13 @@ export function visitParenthesizedExpression(node, context) {
|
|
|
68
177
|
}
|
|
69
178
|
export function visitPropertyAccessExpression(node, context) {
|
|
70
179
|
const propAccess = node;
|
|
180
|
+
if (propAccess.expression.kind === ts.SyntaxKind.SuperKeyword) {
|
|
181
|
+
if (!context.superClassVar) {
|
|
182
|
+
throw new Error("super.prop accessed but no super class variable found in context");
|
|
183
|
+
}
|
|
184
|
+
const propName = propAccess.name.getText();
|
|
185
|
+
return `jspp::AnyValue::resolve_property_for_read((${context.superClassVar}).get_own_property("prototype").get_own_property("${propName}"), ${this.globalThisVar}, "${this.escapeString(propName)}")`;
|
|
186
|
+
}
|
|
71
187
|
const exprText = this.visit(propAccess.expression, context);
|
|
72
188
|
const propName = propAccess.name.getText();
|
|
73
189
|
const scope = this.getScopeForNode(propAccess.expression);
|
|
@@ -76,22 +192,21 @@ export function visitPropertyAccessExpression(node, context) {
|
|
|
76
192
|
: null;
|
|
77
193
|
if (ts.isIdentifier(propAccess.expression) && !typeInfo &&
|
|
78
194
|
!this.isBuiltinObject(propAccess.expression)) {
|
|
79
|
-
return `jspp::
|
|
195
|
+
return `jspp::Exception::throw_unresolved_reference(${this.getJsVarName(propAccess.expression)})`;
|
|
80
196
|
}
|
|
81
|
-
let finalExpr =
|
|
82
|
-
if (typeInfo &&
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
finalExpr = exprText;
|
|
197
|
+
let finalExpr = exprText;
|
|
198
|
+
if (typeInfo &&
|
|
199
|
+
!typeInfo.isParameter &&
|
|
200
|
+
!typeInfo.isBuiltin &&
|
|
201
|
+
ts.isIdentifier(propAccess.expression)) {
|
|
202
|
+
finalExpr = this.getDerefCode(exprText, this.getJsVarName(propAccess.expression), typeInfo);
|
|
87
203
|
}
|
|
88
204
|
return `${finalExpr}.get_own_property("${propName}")`;
|
|
89
|
-
// return `${finalExpr}["${propName}"]`;
|
|
90
205
|
}
|
|
91
206
|
export function visitElementAccessExpression(node, context) {
|
|
92
207
|
const elemAccess = node;
|
|
93
208
|
const exprText = this.visit(elemAccess.expression, context);
|
|
94
|
-
let argText = visitObjectPropertyName.call(this, elemAccess.argumentExpression, { ...context,
|
|
209
|
+
let argText = visitObjectPropertyName.call(this, elemAccess.argumentExpression, { ...context, isBracketNotationPropertyAccess: true });
|
|
95
210
|
// Dereference the expression being accessed
|
|
96
211
|
const exprScope = this.getScopeForNode(elemAccess.expression);
|
|
97
212
|
const exprTypeInfo = ts.isIdentifier(elemAccess.expression)
|
|
@@ -99,51 +214,93 @@ export function visitElementAccessExpression(node, context) {
|
|
|
99
214
|
: null;
|
|
100
215
|
if (ts.isIdentifier(elemAccess.expression) && !exprTypeInfo &&
|
|
101
216
|
!this.isBuiltinObject(elemAccess.expression)) {
|
|
102
|
-
return `jspp::
|
|
217
|
+
return `jspp::Exception::throw_unresolved_reference(${this.getJsVarName(elemAccess.expression)})`;
|
|
218
|
+
}
|
|
219
|
+
let finalExpr = exprText;
|
|
220
|
+
if (exprTypeInfo &&
|
|
221
|
+
!exprTypeInfo.isParameter &&
|
|
222
|
+
!exprTypeInfo.isBuiltin &&
|
|
223
|
+
ts.isIdentifier(elemAccess.expression)) {
|
|
224
|
+
finalExpr = this.getDerefCode(exprText, this.getJsVarName(elemAccess.expression), exprTypeInfo);
|
|
103
225
|
}
|
|
104
|
-
const finalExpr = exprTypeInfo && !exprTypeInfo.isParameter && !exprTypeInfo.isBuiltin
|
|
105
|
-
? `jspp::Access::deref(${exprText}, ${this.getJsVarName(elemAccess.expression)})`
|
|
106
|
-
: exprText;
|
|
107
226
|
// Dereference the argument expression if it's an identifier
|
|
108
227
|
if (ts.isIdentifier(elemAccess.argumentExpression)) {
|
|
109
228
|
const argScope = this.getScopeForNode(elemAccess.argumentExpression);
|
|
110
229
|
const argTypeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(elemAccess.argumentExpression.getText(), argScope);
|
|
111
230
|
if (!argTypeInfo && !this.isBuiltinObject(elemAccess.argumentExpression)) {
|
|
112
|
-
return `jspp::
|
|
231
|
+
return `jspp::Exception::throw_unresolved_reference(${this.getJsVarName(elemAccess.argumentExpression)})`;
|
|
113
232
|
}
|
|
114
|
-
if (argTypeInfo &&
|
|
115
|
-
|
|
233
|
+
if (argTypeInfo &&
|
|
234
|
+
!argTypeInfo.isParameter &&
|
|
235
|
+
!argTypeInfo.isBuiltin) {
|
|
236
|
+
argText = this.getDerefCode(argText, this.getJsVarName(elemAccess.argumentExpression), argTypeInfo);
|
|
116
237
|
}
|
|
117
238
|
}
|
|
118
239
|
return `${finalExpr}.get_own_property(${argText})`;
|
|
119
|
-
// return `${finalExpr}[${argText}]`;
|
|
120
240
|
}
|
|
121
241
|
export function visitBinaryExpression(node, context) {
|
|
122
242
|
const binExpr = node;
|
|
123
243
|
const opToken = binExpr.operatorToken;
|
|
124
244
|
let op = opToken.getText();
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
245
|
+
const assignmentOperators = [
|
|
246
|
+
ts.SyntaxKind.PlusEqualsToken,
|
|
247
|
+
ts.SyntaxKind.MinusEqualsToken,
|
|
248
|
+
ts.SyntaxKind.AsteriskEqualsToken,
|
|
249
|
+
ts.SyntaxKind.SlashEqualsToken,
|
|
250
|
+
ts.SyntaxKind.PercentEqualsToken,
|
|
251
|
+
];
|
|
252
|
+
if (assignmentOperators.includes(opToken.kind)) {
|
|
130
253
|
const leftText = this.visit(binExpr.left, context);
|
|
131
|
-
|
|
132
|
-
|
|
254
|
+
let rightText = this.visit(binExpr.right, context);
|
|
255
|
+
if (ts.isIdentifier(binExpr.right)) {
|
|
256
|
+
const scope = this.getScopeForNode(binExpr.right);
|
|
257
|
+
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(binExpr.right.getText(), scope);
|
|
258
|
+
rightText = this.getDerefCode(rightText, this.getJsVarName(binExpr.right), typeInfo);
|
|
259
|
+
}
|
|
260
|
+
let target = leftText;
|
|
261
|
+
if (ts.isIdentifier(binExpr.left)) {
|
|
262
|
+
const scope = this.getScopeForNode(binExpr.left);
|
|
263
|
+
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(binExpr.left.getText(), scope);
|
|
264
|
+
if (context.derefBeforeAssignment) {
|
|
265
|
+
target = this.getDerefCode(leftText, leftText, typeInfo);
|
|
266
|
+
}
|
|
267
|
+
else if (typeInfo.needsHeapAllocation) {
|
|
268
|
+
target = `*${leftText}`;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return `${target} ${op} ${rightText}`;
|
|
133
272
|
}
|
|
134
273
|
if (opToken.kind === ts.SyntaxKind.EqualsToken) {
|
|
135
274
|
const rightText = this.visit(binExpr.right, context);
|
|
136
275
|
if (ts.isPropertyAccessExpression(binExpr.left)) {
|
|
137
276
|
const propAccess = binExpr.left;
|
|
277
|
+
if (propAccess.expression.kind === ts.SyntaxKind.SuperKeyword) {
|
|
278
|
+
const propName = propAccess.name.getText();
|
|
279
|
+
let finalRightText = rightText;
|
|
280
|
+
// Deref right text logic...
|
|
281
|
+
if (ts.isIdentifier(binExpr.right)) {
|
|
282
|
+
const rightScope = this.getScopeForNode(binExpr.right);
|
|
283
|
+
const rightTypeInfo = this.typeAnalyzer.scopeManager
|
|
284
|
+
.lookupFromScope(binExpr.right.getText(), rightScope);
|
|
285
|
+
if (rightTypeInfo &&
|
|
286
|
+
!rightTypeInfo.isParameter &&
|
|
287
|
+
!rightTypeInfo.isBuiltin) {
|
|
288
|
+
finalRightText = this.getDerefCode(rightText, this.getJsVarName(binExpr.right), rightTypeInfo);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
// Approximate super assignment as setting property on 'this'
|
|
292
|
+
return `(${this.globalThisVar}).set_own_property("${propName}", ${finalRightText})`;
|
|
293
|
+
}
|
|
138
294
|
const objExprText = this.visit(propAccess.expression, context);
|
|
139
295
|
const propName = propAccess.name.getText();
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
296
|
+
let finalObjExpr = objExprText;
|
|
297
|
+
if (ts.isIdentifier(propAccess.expression)) {
|
|
298
|
+
const scope = this.getScopeForNode(propAccess.expression);
|
|
299
|
+
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(propAccess.expression.getText(), scope);
|
|
300
|
+
if (typeInfo && !typeInfo.isParameter && !typeInfo.isBuiltin) {
|
|
301
|
+
finalObjExpr = this.getDerefCode(objExprText, this.getJsVarName(propAccess.expression), typeInfo);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
147
304
|
let finalRightText = rightText;
|
|
148
305
|
if (ts.isIdentifier(binExpr.right)) {
|
|
149
306
|
const rightScope = this.getScopeForNode(binExpr.right);
|
|
@@ -152,23 +309,23 @@ export function visitBinaryExpression(node, context) {
|
|
|
152
309
|
if (rightTypeInfo &&
|
|
153
310
|
!rightTypeInfo.isParameter &&
|
|
154
311
|
!rightTypeInfo.isBuiltin) {
|
|
155
|
-
finalRightText =
|
|
312
|
+
finalRightText = this.getDerefCode(rightText, this.getJsVarName(binExpr.right), rightTypeInfo);
|
|
156
313
|
}
|
|
157
314
|
}
|
|
158
315
|
return `${finalObjExpr}.set_own_property("${propName}", ${finalRightText})`;
|
|
159
|
-
// return `${finalObjExpr}["${propName}"] = ${finalRightText}`;
|
|
160
316
|
}
|
|
161
317
|
else if (ts.isElementAccessExpression(binExpr.left)) {
|
|
162
318
|
const elemAccess = binExpr.left;
|
|
163
319
|
const objExprText = this.visit(elemAccess.expression, context);
|
|
164
|
-
let argText = visitObjectPropertyName.call(this, elemAccess.argumentExpression, { ...context,
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
320
|
+
let argText = visitObjectPropertyName.call(this, elemAccess.argumentExpression, { ...context, isBracketNotationPropertyAccess: true });
|
|
321
|
+
let finalObjExpr = objExprText;
|
|
322
|
+
if (ts.isIdentifier(elemAccess.expression)) {
|
|
323
|
+
const scope = this.getScopeForNode(elemAccess.expression);
|
|
324
|
+
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(elemAccess.expression.getText(), scope);
|
|
325
|
+
if (typeInfo && !typeInfo.isParameter && !typeInfo.isBuiltin) {
|
|
326
|
+
finalObjExpr = this.getDerefCode(objExprText, this.getJsVarName(elemAccess.expression), typeInfo);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
172
329
|
if (ts.isIdentifier(elemAccess.argumentExpression)) {
|
|
173
330
|
const argScope = this.getScopeForNode(elemAccess.argumentExpression);
|
|
174
331
|
const argTypeInfo = this.typeAnalyzer.scopeManager
|
|
@@ -176,7 +333,7 @@ export function visitBinaryExpression(node, context) {
|
|
|
176
333
|
if (argTypeInfo &&
|
|
177
334
|
!argTypeInfo.isParameter &&
|
|
178
335
|
!argTypeInfo.isBuiltin) {
|
|
179
|
-
argText =
|
|
336
|
+
argText = this.getDerefCode(argText, this.getJsVarName(elemAccess.argumentExpression), argTypeInfo);
|
|
180
337
|
}
|
|
181
338
|
}
|
|
182
339
|
let finalRightText = rightText;
|
|
@@ -187,61 +344,61 @@ export function visitBinaryExpression(node, context) {
|
|
|
187
344
|
if (rightTypeInfo &&
|
|
188
345
|
!rightTypeInfo.isParameter &&
|
|
189
346
|
!rightTypeInfo.isBuiltin) {
|
|
190
|
-
finalRightText =
|
|
347
|
+
finalRightText = this.getDerefCode(rightText, this.getJsVarName(binExpr.right), rightTypeInfo);
|
|
191
348
|
}
|
|
192
349
|
}
|
|
193
350
|
return `${finalObjExpr}.set_own_property(${argText}, ${finalRightText})`;
|
|
194
|
-
// return `${finalObjExpr}[${argText}] = ${finalRightText}`;
|
|
195
351
|
}
|
|
196
352
|
const leftText = this.visit(binExpr.left, context);
|
|
197
353
|
const scope = this.getScopeForNode(binExpr.left);
|
|
198
354
|
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(binExpr.left.text, scope);
|
|
199
355
|
if (!typeInfo && !this.isBuiltinObject(binExpr.left)) {
|
|
200
|
-
return `jspp::
|
|
356
|
+
return `jspp::Exception::throw_unresolved_reference(${this.getJsVarName(binExpr.left)})`;
|
|
201
357
|
}
|
|
202
358
|
if (typeInfo?.isConst) {
|
|
203
|
-
return `jspp::
|
|
359
|
+
return `jspp::Exception::throw_immutable_assignment()`;
|
|
204
360
|
}
|
|
205
|
-
|
|
361
|
+
const target = context.derefBeforeAssignment
|
|
362
|
+
? this.getDerefCode(leftText, leftText, typeInfo)
|
|
363
|
+
: (typeInfo.needsHeapAllocation ? `*${leftText}` : leftText);
|
|
364
|
+
return `${target} ${op} ${rightText}`;
|
|
206
365
|
}
|
|
207
366
|
const leftText = this.visit(binExpr.left, context);
|
|
208
367
|
const rightText = this.visit(binExpr.right, context);
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
!this.isBuiltinObject(binExpr.right)) {
|
|
232
|
-
return `jspp::RuntimeError::throw_unresolved_reference_error(${this.getJsVarName(binExpr.right)})`;
|
|
368
|
+
let finalLeft = leftText;
|
|
369
|
+
if (ts.isIdentifier(binExpr.left)) {
|
|
370
|
+
const scope = this.getScopeForNode(binExpr.left);
|
|
371
|
+
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(binExpr.left.getText(), scope);
|
|
372
|
+
if (!typeInfo && !this.isBuiltinObject(binExpr.left)) {
|
|
373
|
+
return `jspp::Exception::throw_unresolved_reference(${this.getJsVarName(binExpr.left)})`;
|
|
374
|
+
}
|
|
375
|
+
if (typeInfo && !typeInfo.isParameter && !typeInfo.isBuiltin) {
|
|
376
|
+
finalLeft = this.getDerefCode(leftText, this.getJsVarName(binExpr.left), typeInfo);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
let finalRight = rightText;
|
|
380
|
+
if (ts.isIdentifier(binExpr.right)) {
|
|
381
|
+
const scope = this.getScopeForNode(binExpr.right);
|
|
382
|
+
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(binExpr.right.getText(), scope);
|
|
383
|
+
if (!typeInfo &&
|
|
384
|
+
!this.isBuiltinObject(binExpr.right)) {
|
|
385
|
+
return `jspp::Exception::throw_unresolved_reference(${this.getJsVarName(binExpr.right)})`;
|
|
386
|
+
}
|
|
387
|
+
if (typeInfo && !typeInfo.isParameter && !typeInfo.isBuiltin) {
|
|
388
|
+
finalRight = this.getDerefCode(rightText, this.getJsVarName(binExpr.right), typeInfo);
|
|
389
|
+
}
|
|
233
390
|
}
|
|
234
391
|
if (opToken.kind === ts.SyntaxKind.EqualsEqualsEqualsToken) {
|
|
235
|
-
return `${finalLeft}.
|
|
392
|
+
return `${finalLeft}.is_strictly_equal_to(${finalRight})`;
|
|
236
393
|
}
|
|
237
394
|
if (opToken.kind === ts.SyntaxKind.EqualsEqualsToken) {
|
|
238
|
-
return `${finalLeft}.
|
|
395
|
+
return `${finalLeft}.is_equal_to(${finalRight})`;
|
|
239
396
|
}
|
|
240
397
|
if (opToken.kind === ts.SyntaxKind.ExclamationEqualsEqualsToken) {
|
|
241
|
-
return `${finalLeft}.
|
|
398
|
+
return `${finalLeft}.not_strictly_equal_to(${finalRight})`;
|
|
242
399
|
}
|
|
243
400
|
if (opToken.kind === ts.SyntaxKind.ExclamationEqualsToken) {
|
|
244
|
-
return `${finalLeft}.
|
|
401
|
+
return `${finalLeft}.not_equal_to(${finalRight})`;
|
|
245
402
|
}
|
|
246
403
|
if (opToken.kind === ts.SyntaxKind.AsteriskAsteriskToken) {
|
|
247
404
|
return `jspp::pow(${finalLeft}, ${finalRight})`;
|
|
@@ -258,10 +415,30 @@ export function visitBinaryExpression(node, context) {
|
|
|
258
415
|
}
|
|
259
416
|
return `${finalLeft} ${op} ${finalRight}`;
|
|
260
417
|
}
|
|
418
|
+
export function visitConditionalExpression(node, context) {
|
|
419
|
+
const condExpr = node;
|
|
420
|
+
const condition = this.visit(condExpr.condition, context);
|
|
421
|
+
const whenTrueStmt = this.visit(condExpr.whenTrue, {
|
|
422
|
+
...context,
|
|
423
|
+
isFunctionBody: false,
|
|
424
|
+
});
|
|
425
|
+
const whenFalseStmt = this.visit(condExpr.whenFalse, {
|
|
426
|
+
...context,
|
|
427
|
+
isFunctionBody: false,
|
|
428
|
+
});
|
|
429
|
+
return `(${condition}).is_truthy() ? ${whenTrueStmt} : ${whenFalseStmt}`;
|
|
430
|
+
}
|
|
261
431
|
export function visitCallExpression(node, context) {
|
|
262
432
|
const callExpr = node;
|
|
263
433
|
const callee = callExpr.expression;
|
|
264
|
-
|
|
434
|
+
if (callee.kind === ts.SyntaxKind.SuperKeyword) {
|
|
435
|
+
if (!context.superClassVar) {
|
|
436
|
+
throw new Error("super() called but no super class variable found in context");
|
|
437
|
+
}
|
|
438
|
+
const args = callExpr.arguments.map((arg) => this.visit(arg, context))
|
|
439
|
+
.join(", ");
|
|
440
|
+
return `(${context.superClassVar}).as_function("super")->call(${this.globalThisVar}, {${args}})`;
|
|
441
|
+
}
|
|
265
442
|
const args = callExpr.arguments
|
|
266
443
|
.map((arg) => {
|
|
267
444
|
const argText = this.visit(arg, context);
|
|
@@ -269,35 +446,100 @@ export function visitCallExpression(node, context) {
|
|
|
269
446
|
const scope = this.getScopeForNode(arg);
|
|
270
447
|
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(arg.text, scope);
|
|
271
448
|
if (!typeInfo) {
|
|
272
|
-
return `jspp::
|
|
449
|
+
return `jspp::Exception::throw_unresolved_reference(${this.getJsVarName(arg)})`;
|
|
273
450
|
}
|
|
274
451
|
if (typeInfo && !typeInfo.isParameter && !typeInfo.isBuiltin) {
|
|
275
|
-
return
|
|
452
|
+
return this.getDerefCode(argText, this.getJsVarName(arg), typeInfo);
|
|
276
453
|
}
|
|
277
454
|
}
|
|
278
455
|
return argText;
|
|
279
456
|
})
|
|
280
457
|
.join(", ");
|
|
458
|
+
// Handle obj.method() -> pass obj as 'this'
|
|
459
|
+
if (ts.isPropertyAccessExpression(callee)) {
|
|
460
|
+
const propAccess = callee;
|
|
461
|
+
if (propAccess.expression.kind === ts.SyntaxKind.SuperKeyword) {
|
|
462
|
+
if (!context.superClassVar) {
|
|
463
|
+
throw new Error("super.method() called but no super class variable found in context");
|
|
464
|
+
}
|
|
465
|
+
const propName = propAccess.name.getText();
|
|
466
|
+
return `(${context.superClassVar}).get_own_property("prototype").get_own_property("${propName}").as_function("${this.escapeString(propName)}")->call(${this.globalThisVar}, {${args}})`;
|
|
467
|
+
}
|
|
468
|
+
const objExpr = propAccess.expression;
|
|
469
|
+
const propName = propAccess.name.getText();
|
|
470
|
+
const objCode = this.visit(objExpr, context);
|
|
471
|
+
// We need to dereference the object expression if it's a variable
|
|
472
|
+
let derefObj = objCode;
|
|
473
|
+
if (ts.isIdentifier(objExpr)) {
|
|
474
|
+
const scope = this.getScopeForNode(objExpr);
|
|
475
|
+
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(objExpr.getText(), scope);
|
|
476
|
+
if (!typeInfo && !this.isBuiltinObject(objExpr)) {
|
|
477
|
+
return `jspp::Exception::throw_unresolved_reference(${this.getJsVarName(objExpr)})`;
|
|
478
|
+
}
|
|
479
|
+
if (typeInfo && !typeInfo.isBuiltin && !typeInfo.isParameter) {
|
|
480
|
+
derefObj = this.getDerefCode(objCode, this.getJsVarName(objExpr), typeInfo);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
return `([&](){ auto __obj = ${derefObj}; return __obj.get_own_property("${propName}").as_function("${this.escapeString(propName)}")->call(__obj, {${args}}); })()`;
|
|
484
|
+
}
|
|
485
|
+
// Handle obj[method]() -> pass obj as 'this'
|
|
486
|
+
if (ts.isElementAccessExpression(callee)) {
|
|
487
|
+
const elemAccess = callee;
|
|
488
|
+
const objExpr = elemAccess.expression;
|
|
489
|
+
const objCode = this.visit(objExpr, context);
|
|
490
|
+
let derefObj = objCode;
|
|
491
|
+
if (ts.isIdentifier(objExpr)) {
|
|
492
|
+
const scope = this.getScopeForNode(objExpr);
|
|
493
|
+
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(objExpr.getText(), scope);
|
|
494
|
+
if (!typeInfo && !this.isBuiltinObject(objExpr)) {
|
|
495
|
+
return `jspp::Exception::throw_unresolved_reference(${this.getJsVarName(objExpr)})`;
|
|
496
|
+
}
|
|
497
|
+
if (typeInfo && !typeInfo.isBuiltin && !typeInfo.isParameter) {
|
|
498
|
+
derefObj = this.getDerefCode(objCode, this.getJsVarName(objExpr), typeInfo);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
let argText = visitObjectPropertyName.call(this, elemAccess.argumentExpression, { ...context, isBracketNotationPropertyAccess: true });
|
|
502
|
+
// Dereference argument if needed (logic copied from visitElementAccessExpression)
|
|
503
|
+
if (ts.isIdentifier(elemAccess.argumentExpression)) {
|
|
504
|
+
const argScope = this.getScopeForNode(elemAccess.argumentExpression);
|
|
505
|
+
const argTypeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(elemAccess.argumentExpression.getText(), argScope);
|
|
506
|
+
if (!argTypeInfo &&
|
|
507
|
+
!this.isBuiltinObject(elemAccess.argumentExpression)) {
|
|
508
|
+
return `jspp::Exception::throw_unresolved_reference(${this.getJsVarName(elemAccess.argumentExpression)})`;
|
|
509
|
+
}
|
|
510
|
+
if (argTypeInfo && !argTypeInfo.isParameter &&
|
|
511
|
+
!argTypeInfo.isBuiltin) {
|
|
512
|
+
argText = this.getDerefCode(argText, this.getJsVarName(elemAccess.argumentExpression), argTypeInfo);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
return `([&](){ auto __obj = ${derefObj}; return __obj.get_own_property(${argText}).as_function()->call(__obj, {${args}}); })()`;
|
|
516
|
+
}
|
|
281
517
|
const calleeCode = this.visit(callee, context);
|
|
282
|
-
let derefCallee;
|
|
518
|
+
let derefCallee = calleeCode;
|
|
283
519
|
if (ts.isIdentifier(callee)) {
|
|
284
520
|
const scope = this.getScopeForNode(callee);
|
|
285
521
|
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(callee.text, scope);
|
|
286
522
|
if (!typeInfo && !this.isBuiltinObject(callee)) {
|
|
287
|
-
return `jspp::
|
|
523
|
+
return `jspp::Exception::throw_unresolved_reference(${this.getJsVarName(callee)})`;
|
|
288
524
|
}
|
|
289
525
|
if (typeInfo?.isBuiltin) {
|
|
290
526
|
derefCallee = calleeCode;
|
|
291
527
|
}
|
|
292
|
-
else {
|
|
293
|
-
derefCallee =
|
|
528
|
+
else if (typeInfo) {
|
|
529
|
+
derefCallee = this.getDerefCode(calleeCode, this.getJsVarName(callee), typeInfo);
|
|
294
530
|
}
|
|
295
531
|
}
|
|
296
|
-
|
|
297
|
-
|
|
532
|
+
let calleeName = "";
|
|
533
|
+
if (ts.isIdentifier(callee) || ts.isPropertyAccessExpression(callee)) {
|
|
534
|
+
calleeName = this.escapeString(callee.getText());
|
|
298
535
|
}
|
|
299
|
-
|
|
300
|
-
|
|
536
|
+
else if (ts.isParenthesizedExpression(callee) &&
|
|
537
|
+
ts.isFunctionExpression(callee.expression)) {
|
|
538
|
+
const funcExpr = callee.expression;
|
|
539
|
+
calleeName = this.escapeString(funcExpr.name?.getText() || "");
|
|
540
|
+
}
|
|
541
|
+
// Pass undefined as 'this' for normal function calls
|
|
542
|
+
return `${derefCallee}.as_function("${calleeName}")->call(jspp::AnyValue::make_undefined(), {${args}})`;
|
|
301
543
|
}
|
|
302
544
|
export function visitVoidExpression(node, context) {
|
|
303
545
|
const voidExpr = node;
|
|
@@ -315,13 +557,12 @@ export function visitTemplateExpression(node, context) {
|
|
|
315
557
|
const scope = this.getScopeForNode(expr);
|
|
316
558
|
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(expr.text, scope);
|
|
317
559
|
if (!typeInfo && !this.isBuiltinObject(expr)) {
|
|
318
|
-
finalExpr =
|
|
319
|
-
`jspp::RuntimeError::throw_unresolved_reference_error(${this.getJsVarName(expr)})`;
|
|
560
|
+
finalExpr = `jspp::Exception::throw_unresolved_reference(${this.getJsVarName(expr)})`;
|
|
320
561
|
}
|
|
321
562
|
else if (typeInfo &&
|
|
322
563
|
!typeInfo.isParameter &&
|
|
323
564
|
!typeInfo.isBuiltin) {
|
|
324
|
-
finalExpr =
|
|
565
|
+
finalExpr = this.getDerefCode(exprText, this.getJsVarName(expr), typeInfo);
|
|
325
566
|
}
|
|
326
567
|
}
|
|
327
568
|
result += ` + (${finalExpr})`;
|
|
@@ -331,3 +572,78 @@ export function visitTemplateExpression(node, context) {
|
|
|
331
572
|
}
|
|
332
573
|
return result;
|
|
333
574
|
}
|
|
575
|
+
export function visitNewExpression(node, context) {
|
|
576
|
+
const newExpr = node;
|
|
577
|
+
const exprText = this.visit(newExpr.expression, context);
|
|
578
|
+
let derefExpr = exprText;
|
|
579
|
+
if (ts.isIdentifier(newExpr.expression)) {
|
|
580
|
+
const scope = this.getScopeForNode(newExpr.expression);
|
|
581
|
+
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(newExpr.expression.getText(), scope);
|
|
582
|
+
if (!typeInfo &&
|
|
583
|
+
!this.isBuiltinObject(newExpr.expression)) {
|
|
584
|
+
return `jspp::Exception::throw_unresolved_reference(${this.getJsVarName(newExpr.expression)})`;
|
|
585
|
+
}
|
|
586
|
+
if (typeInfo && !typeInfo.isParameter && !typeInfo.isBuiltin) {
|
|
587
|
+
derefExpr = this.getDerefCode(exprText, this.getJsVarName(newExpr.expression), typeInfo);
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
const args = newExpr.arguments
|
|
591
|
+
? newExpr.arguments
|
|
592
|
+
.map((arg) => {
|
|
593
|
+
const argText = this.visit(arg, context);
|
|
594
|
+
if (ts.isIdentifier(arg)) {
|
|
595
|
+
const scope = this.getScopeForNode(arg);
|
|
596
|
+
const typeInfo = this.typeAnalyzer.scopeManager
|
|
597
|
+
.lookupFromScope(arg.text, scope);
|
|
598
|
+
if (!typeInfo) {
|
|
599
|
+
return `jspp::Exception::throw_unresolved_reference(${this.getJsVarName(arg)})`;
|
|
600
|
+
}
|
|
601
|
+
if (typeInfo && !typeInfo.isParameter && !typeInfo.isBuiltin) {
|
|
602
|
+
return this.getDerefCode(argText, this.getJsVarName(arg), typeInfo);
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
return argText;
|
|
606
|
+
})
|
|
607
|
+
.join(", ")
|
|
608
|
+
: "";
|
|
609
|
+
return `${derefExpr}.construct({${args}})`;
|
|
610
|
+
}
|
|
611
|
+
export function visitTypeOfExpression(node, context) {
|
|
612
|
+
const typeOfExpr = node;
|
|
613
|
+
const exprText = this.visit(typeOfExpr.expression, context);
|
|
614
|
+
let derefExpr = exprText;
|
|
615
|
+
if (ts.isIdentifier(typeOfExpr.expression)) {
|
|
616
|
+
const scope = this.getScopeForNode(typeOfExpr.expression);
|
|
617
|
+
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(typeOfExpr.expression.getText(), scope);
|
|
618
|
+
if (!typeInfo &&
|
|
619
|
+
!this.isBuiltinObject(typeOfExpr.expression)) {
|
|
620
|
+
derefExpr = `/* undeclared variable: ${this.getJsVarName(typeOfExpr.expression)} */`; // typeof undeclared variable is 'undefined'
|
|
621
|
+
}
|
|
622
|
+
if (typeInfo && !typeInfo.isParameter && !typeInfo.isBuiltin) {
|
|
623
|
+
derefExpr = this.getDerefCode(exprText, this.getJsVarName(typeOfExpr.expression), typeInfo);
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
return `jspp::Access::typeof(${derefExpr})`;
|
|
627
|
+
}
|
|
628
|
+
export function visitAwaitExpression(node, context) {
|
|
629
|
+
const awaitExpr = node;
|
|
630
|
+
const exprText = this.visit(awaitExpr.expression, context);
|
|
631
|
+
let derefExpr = exprText;
|
|
632
|
+
if (ts.isIdentifier(awaitExpr.expression)) {
|
|
633
|
+
const scope = this.getScopeForNode(awaitExpr.expression);
|
|
634
|
+
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(awaitExpr.expression.getText(), scope);
|
|
635
|
+
if (!typeInfo &&
|
|
636
|
+
!this.isBuiltinObject(awaitExpr.expression)) {
|
|
637
|
+
// This assumes co_awaiting the result of throw_unresolved_reference (which throws)
|
|
638
|
+
// But throw_unresolved_reference returns AnyValue (void-ish).
|
|
639
|
+
// We can just throw before co_await.
|
|
640
|
+
// But we need to return a string expression.
|
|
641
|
+
// Using comma operator: (throw..., AnyValue())
|
|
642
|
+
return `(jspp::Exception::throw_unresolved_reference(${this.getJsVarName(awaitExpr.expression)}), co_await jspp::AnyValue::make_undefined())`;
|
|
643
|
+
}
|
|
644
|
+
if (typeInfo && !typeInfo.isParameter && !typeInfo.isBuiltin) {
|
|
645
|
+
derefExpr = this.getDerefCode(exprText, this.getJsVarName(awaitExpr.expression), typeInfo);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
return `co_await ${derefExpr}`;
|
|
649
|
+
}
|