@ugo-studio/jspp 0.1.3 → 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 +2 -2
- package/dist/analysis/scope.js +16 -4
- package/dist/analysis/typeAnalyzer.js +253 -20
- package/dist/ast/types.js +6 -0
- package/dist/cli.js +1 -2
- 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 +429 -117
- package/dist/core/codegen/function-handlers.js +91 -15
- package/dist/core/codegen/helpers.js +66 -2
- package/dist/core/codegen/index.js +17 -6
- package/dist/core/codegen/literal-handlers.js +3 -0
- package/dist/core/codegen/statement-handlers.js +133 -204
- package/dist/core/codegen/visitor.js +29 -3
- package/package.json +3 -3
- package/src/prelude/any_value.hpp +658 -634
- 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 -225
- package/src/prelude/exception.hpp +31 -0
- package/src/prelude/exception_helpers.hpp +49 -0
- package/src/prelude/index.hpp +18 -9
- package/src/prelude/library/console.hpp +13 -13
- package/src/prelude/library/error.hpp +111 -0
- package/src/prelude/library/global.hpp +15 -4
- package/src/prelude/library/performance.hpp +2 -2
- package/src/prelude/library/promise.hpp +121 -0
- package/src/prelude/library/symbol.hpp +3 -4
- package/src/prelude/library/timer.hpp +92 -0
- package/src/prelude/scheduler.hpp +145 -0
- package/src/prelude/types.hpp +10 -1
- 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} +29 -10
- package/src/prelude/{well_known_symbols.hpp → utils/well_known_symbols.hpp} +0 -1
- package/src/prelude/values/array.hpp +3 -2
- package/src/prelude/{descriptors.hpp → values/descriptors.hpp} +2 -2
- package/src/prelude/values/function.hpp +76 -51
- package/src/prelude/values/helpers/array.hpp +20 -11
- package/src/prelude/values/helpers/function.hpp +125 -77
- package/src/prelude/values/helpers/iterator.hpp +13 -7
- package/src/prelude/values/helpers/object.hpp +36 -6
- package/src/prelude/values/helpers/promise.hpp +181 -0
- package/src/prelude/values/helpers/string.hpp +3 -3
- package/src/prelude/values/helpers/symbol.hpp +2 -2
- package/src/prelude/values/iterator.hpp +13 -5
- package/src/prelude/values/object.hpp +6 -2
- package/src/prelude/values/promise.hpp +73 -0
- package/src/prelude/values/prototypes/array.hpp +16 -16
- package/src/prelude/values/prototypes/function.hpp +4 -4
- package/src/prelude/values/prototypes/iterator.hpp +11 -10
- 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 +26 -26
- package/src/prelude/values/prototypes/symbol.hpp +5 -3
- package/src/prelude/values/string.hpp +1 -1
- package/src/prelude/values/symbol.hpp +1 -1
- package/src/prelude/access.hpp +0 -91
- package/src/prelude/error.hpp +0 -31
- package/src/prelude/error_helpers.hpp +0 -59
- package/src/prelude/log_string.hpp +0 -407
|
@@ -1,52 +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
4
|
if (ts.isNumericLiteral(node)) {
|
|
5
|
-
return
|
|
5
|
+
return context.isBracketNotationPropertyAccess
|
|
6
|
+
? node.getText()
|
|
7
|
+
: `"${node.getText()}"`;
|
|
6
8
|
}
|
|
7
|
-
|
|
9
|
+
if (ts.isStringLiteral(node)) {
|
|
8
10
|
return `"${node.getText().substring(1, node.getText().length - 1) // remove trailing "' from original name
|
|
9
11
|
}"`;
|
|
10
12
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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;
|
|
17
22
|
}
|
|
18
|
-
|
|
23
|
+
if (context.isBracketNotationPropertyAccess) {
|
|
19
24
|
return this.visit(node, context);
|
|
20
25
|
}
|
|
21
|
-
|
|
22
|
-
return `"${node.getText()}"`;
|
|
23
|
-
}
|
|
26
|
+
return `"${node.getText()}"`;
|
|
24
27
|
}
|
|
25
28
|
export function visitObjectLiteralExpression(node, context) {
|
|
26
29
|
const obj = node;
|
|
27
|
-
|
|
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++;
|
|
28
34
|
for (const prop of obj.properties) {
|
|
29
|
-
// console.log("Property kind:", ts.SyntaxKind[prop.kind]);
|
|
30
35
|
if (ts.isPropertyAssignment(prop)) {
|
|
31
|
-
const key = visitObjectPropertyName.call(this, prop.name,
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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`;
|
|
36
51
|
}
|
|
37
52
|
else if (ts.isShorthandPropertyAssignment(prop)) {
|
|
38
|
-
const key = visitObjectPropertyName.call(this, prop.name,
|
|
39
|
-
|
|
40
|
-
|
|
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`;
|
|
41
101
|
}
|
|
42
102
|
}
|
|
43
|
-
|
|
103
|
+
this.indentationLevel--;
|
|
104
|
+
code += `${this.indent()} return ${objVar};\n${this.indent()}})()`;
|
|
105
|
+
return code;
|
|
44
106
|
}
|
|
45
107
|
export function visitArrayLiteralExpression(node, context) {
|
|
46
108
|
const elements = node.elements
|
|
47
|
-
.map((elem) =>
|
|
48
|
-
|
|
49
|
-
|
|
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
|
+
})
|
|
50
120
|
.join(", ");
|
|
51
121
|
return `jspp::AnyValue::make_array({${elements}})`;
|
|
52
122
|
}
|
|
@@ -55,10 +125,32 @@ export function visitPrefixUnaryExpression(node, context) {
|
|
|
55
125
|
const operand = this.visit(prefixUnaryExpr.operand, context);
|
|
56
126
|
const operator = ts.tokenToString(prefixUnaryExpr.operator);
|
|
57
127
|
if (operator === "++" || operator === "--") {
|
|
58
|
-
|
|
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})`;
|
|
59
140
|
}
|
|
60
141
|
if (operator === "~") {
|
|
61
|
-
|
|
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})`;
|
|
62
154
|
}
|
|
63
155
|
return `${operator}${operand}`;
|
|
64
156
|
}
|
|
@@ -66,7 +158,18 @@ export function visitPostfixUnaryExpression(node, context) {
|
|
|
66
158
|
const postfixUnaryExpr = node;
|
|
67
159
|
const operand = this.visit(postfixUnaryExpr.operand, context);
|
|
68
160
|
const operator = ts.tokenToString(postfixUnaryExpr.operator);
|
|
69
|
-
|
|
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}`;
|
|
70
173
|
}
|
|
71
174
|
export function visitParenthesizedExpression(node, context) {
|
|
72
175
|
const parenExpr = node;
|
|
@@ -74,6 +177,13 @@ export function visitParenthesizedExpression(node, context) {
|
|
|
74
177
|
}
|
|
75
178
|
export function visitPropertyAccessExpression(node, context) {
|
|
76
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
|
+
}
|
|
77
187
|
const exprText = this.visit(propAccess.expression, context);
|
|
78
188
|
const propName = propAccess.name.getText();
|
|
79
189
|
const scope = this.getScopeForNode(propAccess.expression);
|
|
@@ -82,21 +192,21 @@ export function visitPropertyAccessExpression(node, context) {
|
|
|
82
192
|
: null;
|
|
83
193
|
if (ts.isIdentifier(propAccess.expression) && !typeInfo &&
|
|
84
194
|
!this.isBuiltinObject(propAccess.expression)) {
|
|
85
|
-
return `jspp::
|
|
86
|
-
}
|
|
87
|
-
let finalExpr = "";
|
|
88
|
-
if (typeInfo && !typeInfo.isParameter && !typeInfo.isBuiltin) {
|
|
89
|
-
finalExpr = `jspp::Access::deref(${exprText}, ${this.getJsVarName(propAccess.expression)})`;
|
|
195
|
+
return `jspp::Exception::throw_unresolved_reference(${this.getJsVarName(propAccess.expression)})`;
|
|
90
196
|
}
|
|
91
|
-
|
|
92
|
-
|
|
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);
|
|
93
203
|
}
|
|
94
204
|
return `${finalExpr}.get_own_property("${propName}")`;
|
|
95
205
|
}
|
|
96
206
|
export function visitElementAccessExpression(node, context) {
|
|
97
207
|
const elemAccess = node;
|
|
98
208
|
const exprText = this.visit(elemAccess.expression, context);
|
|
99
|
-
let argText = visitObjectPropertyName.call(this, elemAccess.argumentExpression, { ...context,
|
|
209
|
+
let argText = visitObjectPropertyName.call(this, elemAccess.argumentExpression, { ...context, isBracketNotationPropertyAccess: true });
|
|
100
210
|
// Dereference the expression being accessed
|
|
101
211
|
const exprScope = this.getScopeForNode(elemAccess.expression);
|
|
102
212
|
const exprTypeInfo = ts.isIdentifier(elemAccess.expression)
|
|
@@ -104,20 +214,26 @@ export function visitElementAccessExpression(node, context) {
|
|
|
104
214
|
: null;
|
|
105
215
|
if (ts.isIdentifier(elemAccess.expression) && !exprTypeInfo &&
|
|
106
216
|
!this.isBuiltinObject(elemAccess.expression)) {
|
|
107
|
-
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);
|
|
108
225
|
}
|
|
109
|
-
const finalExpr = exprTypeInfo && !exprTypeInfo.isParameter && !exprTypeInfo.isBuiltin
|
|
110
|
-
? `jspp::Access::deref(${exprText}, ${this.getJsVarName(elemAccess.expression)})`
|
|
111
|
-
: exprText;
|
|
112
226
|
// Dereference the argument expression if it's an identifier
|
|
113
227
|
if (ts.isIdentifier(elemAccess.argumentExpression)) {
|
|
114
228
|
const argScope = this.getScopeForNode(elemAccess.argumentExpression);
|
|
115
229
|
const argTypeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(elemAccess.argumentExpression.getText(), argScope);
|
|
116
230
|
if (!argTypeInfo && !this.isBuiltinObject(elemAccess.argumentExpression)) {
|
|
117
|
-
return `jspp::
|
|
231
|
+
return `jspp::Exception::throw_unresolved_reference(${this.getJsVarName(elemAccess.argumentExpression)})`;
|
|
118
232
|
}
|
|
119
|
-
if (argTypeInfo &&
|
|
120
|
-
|
|
233
|
+
if (argTypeInfo &&
|
|
234
|
+
!argTypeInfo.isParameter &&
|
|
235
|
+
!argTypeInfo.isBuiltin) {
|
|
236
|
+
argText = this.getDerefCode(argText, this.getJsVarName(elemAccess.argumentExpression), argTypeInfo);
|
|
121
237
|
}
|
|
122
238
|
}
|
|
123
239
|
return `${finalExpr}.get_own_property(${argText})`;
|
|
@@ -126,28 +242,65 @@ export function visitBinaryExpression(node, context) {
|
|
|
126
242
|
const binExpr = node;
|
|
127
243
|
const opToken = binExpr.operatorToken;
|
|
128
244
|
let op = opToken.getText();
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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)) {
|
|
134
253
|
const leftText = this.visit(binExpr.left, context);
|
|
135
|
-
|
|
136
|
-
|
|
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}`;
|
|
137
272
|
}
|
|
138
273
|
if (opToken.kind === ts.SyntaxKind.EqualsToken) {
|
|
139
274
|
const rightText = this.visit(binExpr.right, context);
|
|
140
275
|
if (ts.isPropertyAccessExpression(binExpr.left)) {
|
|
141
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
|
+
}
|
|
142
294
|
const objExprText = this.visit(propAccess.expression, context);
|
|
143
295
|
const propName = propAccess.name.getText();
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
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
|
+
}
|
|
151
304
|
let finalRightText = rightText;
|
|
152
305
|
if (ts.isIdentifier(binExpr.right)) {
|
|
153
306
|
const rightScope = this.getScopeForNode(binExpr.right);
|
|
@@ -156,23 +309,23 @@ export function visitBinaryExpression(node, context) {
|
|
|
156
309
|
if (rightTypeInfo &&
|
|
157
310
|
!rightTypeInfo.isParameter &&
|
|
158
311
|
!rightTypeInfo.isBuiltin) {
|
|
159
|
-
finalRightText =
|
|
312
|
+
finalRightText = this.getDerefCode(rightText, this.getJsVarName(binExpr.right), rightTypeInfo);
|
|
160
313
|
}
|
|
161
314
|
}
|
|
162
315
|
return `${finalObjExpr}.set_own_property("${propName}", ${finalRightText})`;
|
|
163
|
-
// return `${finalObjExpr}["${propName}"] = ${finalRightText}`;
|
|
164
316
|
}
|
|
165
317
|
else if (ts.isElementAccessExpression(binExpr.left)) {
|
|
166
318
|
const elemAccess = binExpr.left;
|
|
167
319
|
const objExprText = this.visit(elemAccess.expression, context);
|
|
168
|
-
let argText = visitObjectPropertyName.call(this, elemAccess.argumentExpression, { ...context,
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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
|
+
}
|
|
176
329
|
if (ts.isIdentifier(elemAccess.argumentExpression)) {
|
|
177
330
|
const argScope = this.getScopeForNode(elemAccess.argumentExpression);
|
|
178
331
|
const argTypeInfo = this.typeAnalyzer.scopeManager
|
|
@@ -180,7 +333,7 @@ export function visitBinaryExpression(node, context) {
|
|
|
180
333
|
if (argTypeInfo &&
|
|
181
334
|
!argTypeInfo.isParameter &&
|
|
182
335
|
!argTypeInfo.isBuiltin) {
|
|
183
|
-
argText =
|
|
336
|
+
argText = this.getDerefCode(argText, this.getJsVarName(elemAccess.argumentExpression), argTypeInfo);
|
|
184
337
|
}
|
|
185
338
|
}
|
|
186
339
|
let finalRightText = rightText;
|
|
@@ -191,61 +344,61 @@ export function visitBinaryExpression(node, context) {
|
|
|
191
344
|
if (rightTypeInfo &&
|
|
192
345
|
!rightTypeInfo.isParameter &&
|
|
193
346
|
!rightTypeInfo.isBuiltin) {
|
|
194
|
-
finalRightText =
|
|
347
|
+
finalRightText = this.getDerefCode(rightText, this.getJsVarName(binExpr.right), rightTypeInfo);
|
|
195
348
|
}
|
|
196
349
|
}
|
|
197
350
|
return `${finalObjExpr}.set_own_property(${argText}, ${finalRightText})`;
|
|
198
|
-
// return `${finalObjExpr}[${argText}] = ${finalRightText}`;
|
|
199
351
|
}
|
|
200
352
|
const leftText = this.visit(binExpr.left, context);
|
|
201
353
|
const scope = this.getScopeForNode(binExpr.left);
|
|
202
354
|
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(binExpr.left.text, scope);
|
|
203
355
|
if (!typeInfo && !this.isBuiltinObject(binExpr.left)) {
|
|
204
|
-
return `jspp::
|
|
356
|
+
return `jspp::Exception::throw_unresolved_reference(${this.getJsVarName(binExpr.left)})`;
|
|
205
357
|
}
|
|
206
358
|
if (typeInfo?.isConst) {
|
|
207
|
-
return `jspp::
|
|
359
|
+
return `jspp::Exception::throw_immutable_assignment()`;
|
|
208
360
|
}
|
|
209
|
-
|
|
361
|
+
const target = context.derefBeforeAssignment
|
|
362
|
+
? this.getDerefCode(leftText, leftText, typeInfo)
|
|
363
|
+
: (typeInfo.needsHeapAllocation ? `*${leftText}` : leftText);
|
|
364
|
+
return `${target} ${op} ${rightText}`;
|
|
210
365
|
}
|
|
211
366
|
const leftText = this.visit(binExpr.left, context);
|
|
212
367
|
const rightText = this.visit(binExpr.right, context);
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
!this.isBuiltinObject(binExpr.right)) {
|
|
236
|
-
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
|
+
}
|
|
237
390
|
}
|
|
238
391
|
if (opToken.kind === ts.SyntaxKind.EqualsEqualsEqualsToken) {
|
|
239
|
-
return `${finalLeft}.
|
|
392
|
+
return `${finalLeft}.is_strictly_equal_to(${finalRight})`;
|
|
240
393
|
}
|
|
241
394
|
if (opToken.kind === ts.SyntaxKind.EqualsEqualsToken) {
|
|
242
|
-
return `${finalLeft}.
|
|
395
|
+
return `${finalLeft}.is_equal_to(${finalRight})`;
|
|
243
396
|
}
|
|
244
397
|
if (opToken.kind === ts.SyntaxKind.ExclamationEqualsEqualsToken) {
|
|
245
|
-
return `${finalLeft}.
|
|
398
|
+
return `${finalLeft}.not_strictly_equal_to(${finalRight})`;
|
|
246
399
|
}
|
|
247
400
|
if (opToken.kind === ts.SyntaxKind.ExclamationEqualsToken) {
|
|
248
|
-
return `${finalLeft}.
|
|
401
|
+
return `${finalLeft}.not_equal_to(${finalRight})`;
|
|
249
402
|
}
|
|
250
403
|
if (opToken.kind === ts.SyntaxKind.AsteriskAsteriskToken) {
|
|
251
404
|
return `jspp::pow(${finalLeft}, ${finalRight})`;
|
|
@@ -262,10 +415,30 @@ export function visitBinaryExpression(node, context) {
|
|
|
262
415
|
}
|
|
263
416
|
return `${finalLeft} ${op} ${finalRight}`;
|
|
264
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
|
+
}
|
|
265
431
|
export function visitCallExpression(node, context) {
|
|
266
432
|
const callExpr = node;
|
|
267
433
|
const callee = callExpr.expression;
|
|
268
|
-
|
|
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
|
+
}
|
|
269
442
|
const args = callExpr.arguments
|
|
270
443
|
.map((arg) => {
|
|
271
444
|
const argText = this.visit(arg, context);
|
|
@@ -273,35 +446,100 @@ export function visitCallExpression(node, context) {
|
|
|
273
446
|
const scope = this.getScopeForNode(arg);
|
|
274
447
|
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(arg.text, scope);
|
|
275
448
|
if (!typeInfo) {
|
|
276
|
-
return `jspp::
|
|
449
|
+
return `jspp::Exception::throw_unresolved_reference(${this.getJsVarName(arg)})`;
|
|
277
450
|
}
|
|
278
451
|
if (typeInfo && !typeInfo.isParameter && !typeInfo.isBuiltin) {
|
|
279
|
-
return
|
|
452
|
+
return this.getDerefCode(argText, this.getJsVarName(arg), typeInfo);
|
|
280
453
|
}
|
|
281
454
|
}
|
|
282
455
|
return argText;
|
|
283
456
|
})
|
|
284
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
|
+
}
|
|
285
517
|
const calleeCode = this.visit(callee, context);
|
|
286
|
-
let derefCallee;
|
|
518
|
+
let derefCallee = calleeCode;
|
|
287
519
|
if (ts.isIdentifier(callee)) {
|
|
288
520
|
const scope = this.getScopeForNode(callee);
|
|
289
521
|
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(callee.text, scope);
|
|
290
522
|
if (!typeInfo && !this.isBuiltinObject(callee)) {
|
|
291
|
-
return `jspp::
|
|
523
|
+
return `jspp::Exception::throw_unresolved_reference(${this.getJsVarName(callee)})`;
|
|
292
524
|
}
|
|
293
525
|
if (typeInfo?.isBuiltin) {
|
|
294
526
|
derefCallee = calleeCode;
|
|
295
527
|
}
|
|
296
|
-
else {
|
|
297
|
-
derefCallee =
|
|
528
|
+
else if (typeInfo) {
|
|
529
|
+
derefCallee = this.getDerefCode(calleeCode, this.getJsVarName(callee), typeInfo);
|
|
298
530
|
}
|
|
299
531
|
}
|
|
300
|
-
|
|
301
|
-
|
|
532
|
+
let calleeName = "";
|
|
533
|
+
if (ts.isIdentifier(callee) || ts.isPropertyAccessExpression(callee)) {
|
|
534
|
+
calleeName = this.escapeString(callee.getText());
|
|
302
535
|
}
|
|
303
|
-
|
|
304
|
-
|
|
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}})`;
|
|
305
543
|
}
|
|
306
544
|
export function visitVoidExpression(node, context) {
|
|
307
545
|
const voidExpr = node;
|
|
@@ -319,13 +557,12 @@ export function visitTemplateExpression(node, context) {
|
|
|
319
557
|
const scope = this.getScopeForNode(expr);
|
|
320
558
|
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(expr.text, scope);
|
|
321
559
|
if (!typeInfo && !this.isBuiltinObject(expr)) {
|
|
322
|
-
finalExpr =
|
|
323
|
-
`jspp::RuntimeError::throw_unresolved_reference_error(${this.getJsVarName(expr)})`;
|
|
560
|
+
finalExpr = `jspp::Exception::throw_unresolved_reference(${this.getJsVarName(expr)})`;
|
|
324
561
|
}
|
|
325
562
|
else if (typeInfo &&
|
|
326
563
|
!typeInfo.isParameter &&
|
|
327
564
|
!typeInfo.isBuiltin) {
|
|
328
|
-
finalExpr =
|
|
565
|
+
finalExpr = this.getDerefCode(exprText, this.getJsVarName(expr), typeInfo);
|
|
329
566
|
}
|
|
330
567
|
}
|
|
331
568
|
result += ` + (${finalExpr})`;
|
|
@@ -335,3 +572,78 @@ export function visitTemplateExpression(node, context) {
|
|
|
335
572
|
}
|
|
336
573
|
return result;
|
|
337
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
|
+
}
|