@ugo-studio/jspp 0.2.4 → 0.2.5

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.
@@ -3,10 +3,10 @@ import { DeclaredSymbols } from "../../ast/symbols.js";
3
3
  import { collectFunctionScopedDeclarations } from "./helpers.js";
4
4
  import { CodeGenerator } from "./index.js";
5
5
  export function generateLambda(node, context, options) {
6
- const isAssignment = options?.isAssignment || false;
7
6
  const capture = options?.capture || "[=]";
7
+ const nativeName = options?.nativeName;
8
8
  const declaredSymbols = this.getDeclaredSymbols(node);
9
- const argsName = this.generateUniqueName("__args_", declaredSymbols);
9
+ const argsName = this.generateUniqueName("__args_", declaredSymbols, context.globalScopeSymbols, context.localScopeSymbols);
10
10
  const isInsideGeneratorFunction = this.isGeneratorFunction(node);
11
11
  const isInsideAsyncFunction = this.isAsyncFunction(node);
12
12
  const returnCmd = this.getReturnCommand({
@@ -23,26 +23,25 @@ export function generateLambda(node, context, options) {
23
23
  // For generators/async, we manually copy them inside the body.
24
24
  const paramThisType = "const jspp::AnyValue&";
25
25
  const paramArgsType = "std::span<const jspp::AnyValue>";
26
+ const selfParamPart = nativeName ? `this auto&& ${nativeName}, ` : "";
27
+ const mutablePart = nativeName ? "" : "mutable ";
26
28
  const thisArgParam = isArrow
27
29
  ? "const jspp::AnyValue&" // Arrow functions use captured 'this' or are never generators in this parser context
28
30
  : `${paramThisType} ${this.globalThisVar}`;
29
- let lambda = `${capture}(${thisArgParam}, ${paramArgsType} ${argsName}) mutable -> ${funcReturnType} `;
30
- const topLevelScopeSymbols = this.prepareScopeSymbolsForVisit(context.topLevelScopeSymbols, context.localScopeSymbols);
31
+ let lambda = `${capture}(${selfParamPart}${thisArgParam}, ${paramArgsType} ${argsName}) ${mutablePart}-> ${funcReturnType} `;
32
+ const globalScopeSymbols = this.prepareScopeSymbolsForVisit(context.globalScopeSymbols, context.localScopeSymbols);
31
33
  const visitContext = {
34
+ currentScopeNode: context.currentScopeNode,
32
35
  isMainContext: false,
33
36
  isInsideFunction: true,
34
37
  isFunctionBody: false,
35
38
  lambdaName: undefined,
36
- topLevelScopeSymbols,
39
+ globalScopeSymbols,
37
40
  localScopeSymbols: new DeclaredSymbols(),
38
41
  superClassVar: context.superClassVar,
39
42
  isInsideGeneratorFunction: isInsideGeneratorFunction,
40
43
  isInsideAsyncFunction: isInsideAsyncFunction,
41
44
  };
42
- // Name of 'this' and 'args' to be used in the body.
43
- // If generator/async, we use the copied versions.
44
- let bodyThisVar = this.globalThisVar;
45
- let bodyArgsVar = argsName;
46
45
  // Preamble to copy arguments for coroutines
47
46
  let preamble = "";
48
47
  if (isInsideGeneratorFunction || isInsideAsyncFunction) {
@@ -51,40 +50,9 @@ export function generateLambda(node, context, options) {
51
50
  if (!isArrow) {
52
51
  preamble +=
53
52
  `${this.indent()}jspp::AnyValue ${thisCopy} = ${this.globalThisVar};\n`;
54
- bodyThisVar = thisCopy;
55
53
  }
56
54
  preamble +=
57
55
  `${this.indent()}std::vector<jspp::AnyValue> ${argsCopy}(${argsName}.begin(), ${argsName}.end());\n`;
58
- bodyArgsVar = argsCopy;
59
- // Update visitContext to use the new 'this' variable if needed?
60
- // CodeGenerator.globalThisVar is a member of the class, so we can't easily change it for the recursive visit
61
- // without changing the class state or passing it down.
62
- // BUT: visitThisKeyword uses `this.globalThisVar`.
63
- // We need to temporarily swap `this.globalThisVar` or handle it.
64
- // Actually, `this.globalThisVar` is set once in `generate`.
65
- // Wait, `visitThisKeyword` uses `this.globalThisVar`.
66
- // If we change the variable name for 'this', we must ensure `visitThisKeyword` generates the correct name.
67
- // `generateLambda` does NOT create a new CodeGenerator instance, so `this.globalThisVar` is the global one.
68
- //
69
- // We need to support shadowing `globalThisVar` for the duration of the visit.
70
- // The current `CodeGenerator` doesn't seem to support changing `globalThisVar` recursively easily
71
- // because it's a property of the class, not `VisitContext`.
72
- //
73
- // However, `visitFunctionDeclaration` etc don't update `globalThisVar`.
74
- // `visitThisKeyword` just returns `this.globalThisVar`.
75
- //
76
- // If we are inside a function, `this` should refer to the function's `this`.
77
- // `this.globalThisVar` is generated in `generate()`: `__this_val__...`.
78
- // And `generateLambda` uses `this.globalThisVar` as the parameter name.
79
- //
80
- // So, if we copy it to `__this_copy`, `visitThisKeyword` will still print `__this_val__...`.
81
- // This is BAD for generators because `__this_val__...` is a reference that dies.
82
- //
83
- // FIX: We must reuse the SAME name for the local copy, and shadow the parameter.
84
- // But we can't declare a variable with the same name as the parameter in the same scope.
85
- //
86
- // We can rename the PARAMETER to something else, and declare the local variable with `this.globalThisVar`.
87
- //
88
56
  }
89
57
  // Adjust parameter names for generator/async to allow shadowing/copying
90
58
  let finalThisParamName = isArrow ? "" : this.globalThisVar;
@@ -100,7 +68,7 @@ export function generateLambda(node, context, options) {
100
68
  : `${paramThisType} ${finalThisParamName}`;
101
69
  // Re-construct lambda header with potentially new param names
102
70
  lambda =
103
- `${capture}(${thisArgParamFinal}, ${paramArgsType} ${finalArgsParamName}) mutable -> ${funcReturnType} `;
71
+ `${capture}(${selfParamPart}${thisArgParamFinal}, ${paramArgsType} ${finalArgsParamName}) ${mutablePart}-> ${funcReturnType} `;
104
72
  // Regenerate preamble
105
73
  preamble = "";
106
74
  if (isInsideGeneratorFunction || isInsideAsyncFunction) {
@@ -178,7 +146,7 @@ export function generateLambda(node, context, options) {
178
146
  // Hoist var declarations in the function body
179
147
  const varDecls = collectFunctionScopedDeclarations(node.body);
180
148
  varDecls.forEach((decl) => {
181
- preamble += this.hoistDeclaration(decl, visitContext.localScopeSymbols);
149
+ preamble += this.hoistDeclaration(decl, visitContext.localScopeSymbols, node.body);
182
150
  });
183
151
  this.indentationLevel++;
184
152
  const paramExtraction = paramExtractor(node.parameters);
@@ -215,34 +183,49 @@ export function generateLambda(node, context, options) {
215
183
  else {
216
184
  lambda += `{ ${preamble} ${returnCmd} jspp::Constants::UNDEFINED; }\n`;
217
185
  }
218
- let signature = "";
219
- let callable = "";
186
+ // Return only lambda if required
187
+ if (options?.generateOnlyLambda) {
188
+ return lambda.trimEnd();
189
+ }
190
+ return this.generateFullLambdaExpression(node, context, lambda, options);
191
+ }
192
+ export function generateFullLambdaExpression(node, context, lambda, options) {
193
+ const isAssignment = options?.isAssignment || false;
194
+ const noTypeSignature = options?.noTypeSignature || false;
195
+ const isInsideGeneratorFunction = this.isGeneratorFunction(node);
196
+ const isInsideAsyncFunction = this.isAsyncFunction(node);
197
+ const isArrow = ts.isArrowFunction(node);
198
+ let callable = lambda;
220
199
  let method = "";
221
200
  // Handle generator function
222
201
  if (isInsideGeneratorFunction) {
223
202
  if (isInsideAsyncFunction) {
224
- signature =
225
- "jspp::JsAsyncIterator<jspp::AnyValue>(const jspp::AnyValue&, std::span<const jspp::AnyValue>)";
226
- callable = `std::function<${signature}>(${lambda})`;
203
+ if (!noTypeSignature) {
204
+ const signature = "jspp::JsAsyncIterator<jspp::AnyValue>(const jspp::AnyValue&, std::span<const jspp::AnyValue>)";
205
+ callable = `std::function<${signature}>(${lambda})`;
206
+ }
227
207
  method = `jspp::AnyValue::make_async_generator`;
228
208
  }
229
209
  else {
230
- signature =
231
- "jspp::JsIterator<jspp::AnyValue>(const jspp::AnyValue&, std::span<const jspp::AnyValue>)";
232
- callable = `std::function<${signature}>(${lambda})`;
210
+ if (!noTypeSignature) {
211
+ const signature = "jspp::JsIterator<jspp::AnyValue>(const jspp::AnyValue&, std::span<const jspp::AnyValue>)";
212
+ callable = `std::function<${signature}>(${lambda})`;
213
+ }
233
214
  method = `jspp::AnyValue::make_generator`;
234
215
  }
235
216
  } // Handle async function
236
217
  else if (isInsideAsyncFunction) {
237
- signature =
238
- "jspp::JsPromise(const jspp::AnyValue&, std::span<const jspp::AnyValue>)";
239
- callable = `std::function<${signature}>(${lambda})`;
218
+ if (!noTypeSignature) {
219
+ const signature = "jspp::JsPromise(const jspp::AnyValue&, std::span<const jspp::AnyValue>)";
220
+ callable = `std::function<${signature}>(${lambda})`;
221
+ }
240
222
  method = `jspp::AnyValue::make_async_function`;
241
223
  } // Handle normal function
242
224
  else {
243
- signature =
244
- `jspp::AnyValue(const jspp::AnyValue&, std::span<const jspp::AnyValue>)`;
245
- callable = `std::function<${signature}>(${lambda})`;
225
+ if (!noTypeSignature) {
226
+ const signature = `jspp::AnyValue(const jspp::AnyValue&, std::span<const jspp::AnyValue>)`;
227
+ callable = `std::function<${signature}>(${lambda})`;
228
+ }
246
229
  if (options?.isClass) {
247
230
  method = `jspp::AnyValue::make_class`;
248
231
  }
@@ -1,6 +1,6 @@
1
1
  import ts from "typescript";
2
2
  import { BUILTIN_OBJECTS, Scope } from "../../analysis/scope.js";
3
- import { DeclaredSymbols, DeclaredSymbolType } from "../../ast/symbols.js";
3
+ import { DeclarationType, DeclaredSymbols } from "../../ast/symbols.js";
4
4
  import { CodeGenerator } from "./index.js";
5
5
  export function isBuiltinObject(node) {
6
6
  return BUILTIN_OBJECTS.values().some((obj) => obj.name === node.text);
@@ -73,7 +73,8 @@ export function escapeString(str) {
73
73
  .replace(/"/g, '\\"')
74
74
  .replace(/\n/g, "\\n")
75
75
  .replace(/\r/g, "\\r")
76
- .replace(/\t/g, "\\t");
76
+ .replace(/\t/g, "\\t")
77
+ .replace(/\?/g, "\\?");
77
78
  }
78
79
  export function getJsVarName(node) {
79
80
  return `"${node.text}"`;
@@ -86,13 +87,13 @@ export function getDerefCode(nodeText, varName, context, typeInfo) {
86
87
  varName = varName + '"';
87
88
  const symbolName = varName.slice(1).slice(0, -1);
88
89
  const symbol = context.localScopeSymbols.get(symbolName) ??
89
- context.topLevelScopeSymbols.get(symbolName);
90
- const checkedIfUninitialized = symbol?.checkedIfUninitialized ||
90
+ context.globalScopeSymbols.get(symbolName);
91
+ const isInitialized = symbol?.checked.initialized ||
91
92
  false;
92
93
  // Mark the symbol as checked
93
- this.markSymbolAsChecked(symbolName, context.topLevelScopeSymbols, context.localScopeSymbols);
94
+ this.markSymbolAsInitialized(symbolName, context.globalScopeSymbols, context.localScopeSymbols);
94
95
  // Apply deref code
95
- if (checkedIfUninitialized) {
96
+ if (isInitialized) {
96
97
  if (typeInfo && typeInfo.needsHeapAllocation) {
97
98
  return `(*${nodeText})`;
98
99
  }
@@ -105,15 +106,15 @@ export function getDerefCode(nodeText, varName, context, typeInfo) {
105
106
  return `jspp::Access::deref_stack(${nodeText}, ${varName})`;
106
107
  }
107
108
  }
108
- export function markSymbolAsChecked(name, topLevel, local) {
109
+ export function markSymbolAsInitialized(name, topLevel, local) {
109
110
  if (topLevel.has(name)) {
110
111
  topLevel.update(name, {
111
- checkedIfUninitialized: true,
112
+ checked: { initialized: true },
112
113
  });
113
114
  }
114
115
  else if (local.has(name)) {
115
116
  local.update(name, {
116
- checkedIfUninitialized: true,
117
+ checked: { initialized: true },
117
118
  });
118
119
  }
119
120
  }
@@ -122,39 +123,58 @@ export function getReturnCommand(context) {
122
123
  ? "co_return"
123
124
  : "return";
124
125
  }
125
- export function hoistDeclaration(decl, hoistedSymbols) {
126
+ export function hoistDeclaration(decl, hoistedSymbols, scopeNode) {
126
127
  const name = decl.name?.getText();
127
128
  if (!name) {
128
129
  return `/* Unknown declaration name: ${ts.SyntaxKind[decl.kind]} */`;
129
130
  }
130
- const isLetOrConst = (decl.parent.flags & (ts.NodeFlags.Let | ts.NodeFlags.Const)) !==
131
- 0;
132
- // if (name === "letVal") console.log("hoistDeclaration: letVal isLetOrConst=", isLetOrConst, " flags=", decl.parent.flags);
133
- const symbolType = isLetOrConst
134
- ? DeclaredSymbolType.letOrConst
135
- : (ts.isFunctionDeclaration(decl)
136
- ? DeclaredSymbolType.function
137
- : (ts.isClassDeclaration(decl)
138
- ? DeclaredSymbolType.letOrConst
139
- : DeclaredSymbolType.var));
131
+ const isLet = (decl.parent.flags & (ts.NodeFlags.Let)) !== 0;
132
+ const isConst = (decl.parent.flags & (ts.NodeFlags.Const)) !== 0;
133
+ const declType = isLet
134
+ ? DeclarationType.let
135
+ : isConst
136
+ ? DeclarationType.const
137
+ : ts.isFunctionDeclaration(decl)
138
+ ? DeclarationType.function
139
+ : ts.isClassDeclaration(decl)
140
+ ? DeclarationType.class
141
+ : DeclarationType.var;
140
142
  if (hoistedSymbols.has(name)) {
141
- const existingType = hoistedSymbols.get(name)?.type;
142
- // Don't allow multiple declaration of `letOrConst` or `function` or `class` variables
143
- if (existingType === DeclaredSymbolType.letOrConst ||
144
- existingType === DeclaredSymbolType.function ||
145
- existingType !== symbolType) {
146
- throw new SyntaxError(`Identifier '${name}' has already been declared`);
143
+ const existingSymbol = hoistedSymbols.get(name);
144
+ // Don't allow multiple declaration of `let`,`const`,`function` or `class` variables
145
+ if (existingSymbol?.type === DeclarationType.let ||
146
+ existingSymbol?.type === DeclarationType.const ||
147
+ existingSymbol?.type === DeclarationType.function ||
148
+ existingSymbol?.type === DeclarationType.class ||
149
+ existingSymbol?.type !== declType) {
150
+ throw new SyntaxError(`Identifier '${name}' has already been declared.\n\n${" ".repeat(6) + decl.getText()}\n`);
147
151
  }
148
152
  // `var` variables can be declared multiple times
149
153
  return "";
150
154
  }
151
- hoistedSymbols.set(name, {
152
- type: symbolType,
153
- checkedIfUninitialized: false,
154
- });
155
+ else {
156
+ // Add the symbol to the hoisted symbols
157
+ if (declType === DeclarationType.function) {
158
+ const isAsync = this.isAsyncFunction(decl);
159
+ const isGenerator = this.isGeneratorFunction(decl);
160
+ hoistedSymbols.add(name, {
161
+ type: declType,
162
+ func: { isAsync, isGenerator },
163
+ });
164
+ // Don't hoist functions not used as a variable
165
+ // they will be called with their native lambdas
166
+ if (!this.isFunctionUsedAsValue(decl, scopeNode) &&
167
+ !this.isFunctionUsedBeforeDeclaration(name, scopeNode)) {
168
+ return "";
169
+ }
170
+ }
171
+ else {
172
+ hoistedSymbols.add(name, { type: declType });
173
+ }
174
+ }
155
175
  const scope = this.getScopeForNode(decl);
156
176
  const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(name, scope);
157
- const initializer = isLetOrConst || ts.isClassDeclaration(decl)
177
+ const initializer = isLet || isConst || ts.isClassDeclaration(decl)
158
178
  ? "jspp::Constants::UNINITIALIZED"
159
179
  : "jspp::Constants::UNDEFINED";
160
180
  if (typeInfo.needsHeapAllocation) {
@@ -246,3 +266,121 @@ export function collectBlockScopedDeclarations(statements) {
246
266
  }
247
267
  return decls;
248
268
  }
269
+ export function isFunctionUsedAsValue(decl, root) {
270
+ const funcName = decl.name?.getText();
271
+ if (!funcName)
272
+ return false;
273
+ let isUsed = false;
274
+ const visitor = (node) => {
275
+ if (isUsed)
276
+ return;
277
+ if (ts.isIdentifier(node) && node.text === funcName) {
278
+ const scope = this.getScopeForNode(node);
279
+ const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(node.text, scope);
280
+ if (typeInfo?.declaration === decl) {
281
+ const parent = node.parent;
282
+ // Ignore declarations where the identifier is the name being declared
283
+ if ((ts.isFunctionDeclaration(parent) ||
284
+ ts.isVariableDeclaration(parent) ||
285
+ ts.isClassDeclaration(parent) ||
286
+ ts.isMethodDeclaration(parent) ||
287
+ ts.isParameter(parent) ||
288
+ ts.isImportSpecifier(parent)) &&
289
+ parent.name === node) {
290
+ // Declaration, do nothing
291
+ } // Ignore property names (e.g. obj.funcName)
292
+ else if ((ts.isPropertyAccessExpression(parent) &&
293
+ parent.name === node) ||
294
+ (ts.isPropertyAssignment(parent) && parent.name === node)) {
295
+ // Property name, do nothing
296
+ } // Ignore direct calls (e.g. funcName())
297
+ else if (ts.isCallExpression(parent) && parent.expression === node) {
298
+ // Call, do nothing
299
+ }
300
+ else {
301
+ // Used as a value
302
+ isUsed = true;
303
+ }
304
+ }
305
+ }
306
+ if (!isUsed) {
307
+ ts.forEachChild(node, visitor);
308
+ }
309
+ };
310
+ ts.forEachChild(root, visitor);
311
+ return isUsed;
312
+ }
313
+ export function isFunctionUsedBeforeDeclaration(funcName, root) {
314
+ let declPos = -1;
315
+ let foundDecl = false;
316
+ // Helper to find the function declaration position
317
+ function findDecl(node) {
318
+ if (foundDecl)
319
+ return;
320
+ if (ts.isFunctionDeclaration(node) && node.name?.text === funcName) {
321
+ declPos = node.getStart();
322
+ foundDecl = true;
323
+ }
324
+ else {
325
+ ts.forEachChild(node, findDecl);
326
+ }
327
+ }
328
+ findDecl(root);
329
+ // If not declared in this scope (or at least not found), assume it's not a local forward-ref issue
330
+ if (!foundDecl)
331
+ return false;
332
+ let isUsedBefore = false;
333
+ function visit(node) {
334
+ if (isUsedBefore)
335
+ return;
336
+ if (ts.isIdentifier(node) && node.text === funcName) {
337
+ const parent = node.parent;
338
+ // Ignore declarations where the identifier is the name being declared
339
+ if ((ts.isFunctionDeclaration(parent) ||
340
+ ts.isVariableDeclaration(parent) ||
341
+ ts.isClassDeclaration(parent) ||
342
+ ts.isMethodDeclaration(parent) ||
343
+ ts.isParameter(parent) ||
344
+ ts.isImportSpecifier(parent)) &&
345
+ parent.name === node) {
346
+ // Declaration (or shadowing), do nothing
347
+ } // Ignore property names (e.g. obj.funcName)
348
+ else if ((ts.isPropertyAccessExpression(parent) &&
349
+ parent.name === node) ||
350
+ (ts.isPropertyAssignment(parent) && parent.name === node)) {
351
+ // Property name, do nothing
352
+ }
353
+ else {
354
+ // It is a usage (call or value usage)
355
+ const usagePos = node.getStart();
356
+ // Check 1: Lexically before
357
+ if (usagePos < declPos) {
358
+ isUsedBefore = true;
359
+ return;
360
+ }
361
+ // Check 2: Inside a function declared before
362
+ let current = parent;
363
+ while (current && current !== root) {
364
+ if (ts.isFunctionDeclaration(current) ||
365
+ ts.isMethodDeclaration(current) ||
366
+ ts.isArrowFunction(current) ||
367
+ ts.isFunctionExpression(current) ||
368
+ ts.isGetAccessor(current) ||
369
+ ts.isSetAccessor(current) ||
370
+ ts.isConstructorDeclaration(current)) {
371
+ if (current.getStart() < declPos) {
372
+ isUsedBefore = true;
373
+ return;
374
+ }
375
+ // Once we hit a function boundary, we stop bubbling up for this usage.
376
+ break;
377
+ }
378
+ current = current.parent;
379
+ }
380
+ }
381
+ }
382
+ ts.forEachChild(node, visit);
383
+ }
384
+ visit(root);
385
+ return isUsedBefore;
386
+ }
@@ -1,6 +1,6 @@
1
1
  import { DeclaredSymbols } from "../../ast/symbols.js";
2
- import { generateLambda } from "./function-handlers.js";
3
- import { escapeString, generateUniqueExceptionName, generateUniqueName, getDeclaredSymbols, getDerefCode, getJsVarName, getReturnCommand, getScopeForNode, hoistDeclaration, indent, isAsyncFunction, isBuiltinObject, isGeneratorFunction, markSymbolAsChecked, prepareScopeSymbolsForVisit, } from "./helpers.js";
2
+ import { generateFullLambdaExpression, generateLambda, } from "./function-handlers.js";
3
+ import { escapeString, generateUniqueExceptionName, generateUniqueName, getDeclaredSymbols, getDerefCode, getJsVarName, getReturnCommand, getScopeForNode, hoistDeclaration, indent, isAsyncFunction, isBuiltinObject, isFunctionUsedAsValue, isFunctionUsedBeforeDeclaration, isGeneratorFunction, markSymbolAsInitialized, prepareScopeSymbolsForVisit, } from "./helpers.js";
4
4
  import { visit } from "./visitor.js";
5
5
  const MODULE_NAME = "__main_function__";
6
6
  export class CodeGenerator {
@@ -25,9 +25,12 @@ export class CodeGenerator {
25
25
  isGeneratorFunction = isGeneratorFunction;
26
26
  isAsyncFunction = isAsyncFunction;
27
27
  prepareScopeSymbolsForVisit = prepareScopeSymbolsForVisit;
28
- markSymbolAsChecked = markSymbolAsChecked;
28
+ markSymbolAsInitialized = markSymbolAsInitialized;
29
+ isFunctionUsedAsValue = isFunctionUsedAsValue;
30
+ isFunctionUsedBeforeDeclaration = isFunctionUsedBeforeDeclaration;
29
31
  // function handlers
30
32
  generateLambda = generateLambda;
33
+ generateFullLambdaExpression = generateFullLambdaExpression;
31
34
  /**
32
35
  * Main entry point for the code generation process.
33
36
  */
@@ -40,11 +43,12 @@ export class CodeGenerator {
40
43
  containerCode +=
41
44
  `${this.indent()}jspp::AnyValue ${this.globalThisVar} = global;\n`;
42
45
  containerCode += this.visit(ast, {
46
+ currentScopeNode: ast,
43
47
  isMainContext: true,
44
48
  isInsideFunction: true,
45
49
  isFunctionBody: true,
46
50
  isInsideAsyncFunction: true,
47
- topLevelScopeSymbols: new DeclaredSymbols(),
51
+ globalScopeSymbols: new DeclaredSymbols(),
48
52
  localScopeSymbols: new DeclaredSymbols(),
49
53
  });
50
54
  this.indentationLevel--;