@grey-ts/transpiler 1.4.4 → 2.1.0

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.
Files changed (2) hide show
  1. package/dist/index.js +478 -325
  2. package/package.json +5 -4
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ import path6 from "node:path";
7
7
  // src/transpiler.ts
8
8
  import * as fs2 from "node:fs";
9
9
  import * as path5 from "node:path";
10
- import ts14 from "typescript";
10
+ import ts15 from "typescript";
11
11
 
12
12
  // src/nodeHandler.ts
13
13
  import * as path from "node:path";
@@ -33,9 +33,9 @@ class NodeHandler {
33
33
  if (!extra)
34
34
  return result;
35
35
  return [
36
- ...extra.before ? [extra.before] : [],
36
+ ...extra.before,
37
37
  result,
38
- ...extra.after ? [extra.after] : []
38
+ ...extra.after
39
39
  ].join(`
40
40
  `);
41
41
  } catch (error) {
@@ -45,13 +45,15 @@ class NodeHandler {
45
45
  }
46
46
  }
47
47
  static addExtraOutput(node, before, after) {
48
- if (!this.transpileContext.extraOutput.has(node))
49
- this.transpileContext.extraOutput.set(node, { before: "", after: "" });
50
- const extra = this.transpileContext.extraOutput.get(node);
48
+ let extra = this.transpileContext.extraOutput.get(node);
49
+ if (!extra) {
50
+ extra = { before: [], after: [] };
51
+ this.transpileContext.extraOutput.set(node, extra);
52
+ }
51
53
  if (before)
52
- extra.before += before;
54
+ extra.before.push(before);
53
55
  if (after)
54
- extra.after += after;
56
+ extra.after.push(after);
55
57
  }
56
58
  static printLineAndCol(node) {
57
59
  const source = node.getSourceFile();
@@ -167,7 +169,6 @@ var apiNameMap = {
167
169
  "GreyHack.File.setGroup": "set_group",
168
170
  "GreyHack.File.setOwner": "set_owner",
169
171
  "GreyHack.activeUser": "active_user",
170
- "GreyHack.clearScreen": "clear_screen",
171
172
  "GreyHack.commandInfo": "command_info",
172
173
  "GreyHack.currentDate": "current_date",
173
174
  "GreyHack.currentPath": "current_path",
@@ -258,26 +259,11 @@ var apiNameMap = {
258
259
  "Object.size": "len",
259
260
  "Array.length": "len",
260
261
  "Array.shift": "pull",
261
- "Array.push": "push_many"
262
+ "Array.push": "push_many",
263
+ "Map.size": "data.len",
264
+ "Set.size": "data.len"
262
265
  };
263
266
  var propertyAccessReplacements = {
264
- "Math.PI": "pi",
265
- "Math.abs": "abs",
266
- "Math.acos": "acos",
267
- "Math.asin": "asin",
268
- "Math.atan": "atan",
269
- "Math.ceil": "ceil",
270
- "Math.floor": "floor",
271
- "Math.cos": "cos",
272
- "Math.sin": "sin",
273
- "Math.tan": "tan",
274
- "Math.sqrt": "sqrt",
275
- "Math.sign": "sign",
276
- "Math.round": "round",
277
- "Math.random": "rnd",
278
- "Math.log": "log",
279
- "console.log": "print",
280
- "console.clear": "clear_screen",
281
267
  "String.prototype": "string",
282
268
  "Number.prototype": "number",
283
269
  "Boolean.prototype": "number",
@@ -303,6 +289,7 @@ var knownOperators = new Set([
303
289
  "!==",
304
290
  "??",
305
291
  "??=",
292
+ "||=",
306
293
  "in",
307
294
  "||",
308
295
  "<",
@@ -312,6 +299,13 @@ var knownOperators = new Set([
312
299
  "*",
313
300
  "/",
314
301
  "%",
302
+ "*=",
303
+ "/=",
304
+ "%=",
305
+ "**=",
306
+ "<<=",
307
+ ">>=",
308
+ ">>>=",
315
309
  "~",
316
310
  "&",
317
311
  "|",
@@ -327,13 +321,13 @@ function getOperatorToken(node) {
327
321
  return null;
328
322
  if (!knownOperators.has(operatorToken))
329
323
  throw `Can't handle operator '${operatorToken}' yet`;
330
- if (operatorToken == "||")
324
+ if (operatorToken === "||")
331
325
  operatorToken = "or";
332
- else if (operatorToken == "&&")
326
+ else if (operatorToken === "&&")
333
327
  operatorToken = "and";
334
- else if (operatorToken == "===")
328
+ else if (operatorToken === "===")
335
329
  operatorToken = "==";
336
- else if (operatorToken == "!==")
330
+ else if (operatorToken === "!==")
337
331
  operatorToken = "!=";
338
332
  return operatorToken;
339
333
  }
@@ -355,7 +349,7 @@ function nodeIsFunctionReference(node, type) {
355
349
  function asRef(value) {
356
350
  if (value[0] === "@")
357
351
  return value;
358
- return "@" + value;
352
+ return `@${value}`;
359
353
  }
360
354
  function getSourceFiles(absPath) {
361
355
  if (!fs.existsSync(absPath))
@@ -380,20 +374,16 @@ function getSourceFiles(absPath) {
380
374
  return output;
381
375
  }
382
376
  function replaceIdentifier(original, type, propertyName) {
383
- let symbol;
384
377
  if (type.isUnion()) {
385
- if (propertyName) {
386
- for (const t of type.types) {
387
- symbol = t.getProperty(propertyName);
388
- if (symbol)
389
- break;
390
- }
391
- } else {
392
- symbol = type.types.find((t) => t.flags !== ts3.TypeFlags.Undefined && t.symbol)?.symbol;
378
+ let result = original;
379
+ for (const t of type.types) {
380
+ result = replaceIdentifier(original, t, propertyName);
381
+ if (result !== original)
382
+ return result;
393
383
  }
394
- } else {
395
- symbol = propertyName ? type.getProperty(propertyName) : type.symbol;
384
+ return result;
396
385
  }
386
+ const symbol = propertyName ? type.getProperty(propertyName) : type.symbol;
397
387
  if (!symbol)
398
388
  return original;
399
389
  const symbolFullName = checker.getFullyQualifiedName(symbol);
@@ -402,7 +392,7 @@ function replaceIdentifier(original, type, propertyName) {
402
392
  return original;
403
393
  const dotIndex = symbolFullName.lastIndexOf(".");
404
394
  const strToReplace = dotIndex !== null ? symbolFullName.slice(dotIndex + 1) : symbolFullName;
405
- if (strToReplace != original)
395
+ if (strToReplace !== original)
406
396
  return original;
407
397
  return replaceValue;
408
398
  }
@@ -433,7 +423,14 @@ var assignmentOperators = new Set([
433
423
  "??=",
434
424
  "||=",
435
425
  "-=",
436
- "+="
426
+ "+=",
427
+ "*=",
428
+ "/=",
429
+ "%=",
430
+ "**=",
431
+ "<<=",
432
+ ">>=",
433
+ ">>>="
437
434
  ]);
438
435
  function valueIsBeingAssignedToNode(node) {
439
436
  if (ts3.hasOnlyExpressionInitializer(node.parent) && node === node.parent.name)
@@ -467,21 +464,90 @@ NodeHandler.register(ts4.SyntaxKind.ComputedPropertyName, (node) => {
467
464
  });
468
465
 
469
466
  // src/visitors/classes.ts
467
+ import ts6 from "typescript";
468
+
469
+ // src/visitors/functions.ts
470
470
  import ts5 from "typescript";
471
- NodeHandler.register(ts5.SyntaxKind.ClassDeclaration, (node) => {
471
+ function handleFunctionBodyAndParams(node, ctx) {
472
+ const oldBindingElements = Object.keys(ctx.bindingElements);
473
+ const params = node.parameters.map((param) => NodeHandler.handle(param));
474
+ const newBindingElements = Object.keys(ctx.bindingElements).filter((b) => !oldBindingElements.includes(b));
475
+ const body = !node.body ? "" : ts5.isBlock(node.body) ? NodeHandler.handle(node.body) : ` return ${NodeHandler.handle(node.body)}`;
476
+ for (const bindingElement of newBindingElements) {
477
+ delete ctx.bindingElements[bindingElement];
478
+ }
479
+ const functionOutput = [
480
+ `function${params.length ? `(${params.join(", ")})` : ""}`,
481
+ ...body ? [body] : [],
482
+ `end function`
483
+ ].join(`
484
+ `);
485
+ return {
486
+ body,
487
+ params,
488
+ functionOutput
489
+ };
490
+ }
491
+ NodeHandler.register(ts5.SyntaxKind.Block, (node) => {
492
+ const output = node.statements.map((val) => {
493
+ let statement = NodeHandler.handle(val);
494
+ statement = statement.split(`
495
+ `).filter((s) => !!s).map((line) => ` ${line}`).join(`
496
+ `);
497
+ return statement;
498
+ }).filter((s) => !!s).join(`
499
+ `);
500
+ return output;
501
+ });
502
+ NodeHandler.register(ts5.SyntaxKind.MethodDeclaration, (node, ctx) => {
503
+ const func = handleFunctionBodyAndParams(node, ctx);
504
+ return `${NodeHandler.handle(node.name)} = ${func.functionOutput}`;
505
+ });
506
+ NodeHandler.register(ts5.SyntaxKind.FunctionDeclaration, (node, ctx) => {
507
+ if (!node.body)
508
+ return "";
472
509
  if (node.modifiers?.some((m) => m.kind === ts5.SyntaxKind.DeclareKeyword))
473
510
  return "";
511
+ const func = handleFunctionBodyAndParams(node, ctx);
512
+ const name = node.name ? node.name.text : "anon";
513
+ return `${name} = ${func.functionOutput}`;
514
+ });
515
+ NodeHandler.register(ts5.SyntaxKind.ArrowFunction, (node, ctx) => {
516
+ const func = handleFunctionBodyAndParams(node, ctx);
517
+ if (ts5.isCallOrNewExpression(node.parent) || ts5.isParenthesizedExpression(node.parent)) {
518
+ const mainNode = ts5.findAncestor(node.parent, (n) => n.parent && (ts5.isBlock(n.parent) || ts5.isSourceFile(n.parent)));
519
+ if (!mainNode) {
520
+ return `@${createAnonFunction(func.body, func.params).name}`;
521
+ }
522
+ const anon = createAnonFunction(func.body, func.params, false);
523
+ NodeHandler.addExtraOutput(mainNode, anon.str, null);
524
+ return `@${anon.name}`;
525
+ }
526
+ if (ts5.hasOnlyExpressionInitializer(node.parent) || ts5.isBinaryExpression(node.parent) || ts5.isReturnStatement(node.parent)) {
527
+ return func.functionOutput;
528
+ }
529
+ const kind = ts5.SyntaxKind[node.parent.kind];
530
+ throw `This kind of arrow function is not yet supported (parent: ${kind} (${node.parent.kind}))`;
531
+ });
532
+ NodeHandler.register(ts5.SyntaxKind.FunctionExpression, (node, ctx) => {
533
+ return handleFunctionBodyAndParams(node, ctx).functionOutput;
534
+ });
535
+
536
+ // src/visitors/classes.ts
537
+ NodeHandler.register(ts6.SyntaxKind.ClassDeclaration, (node) => {
538
+ if (node.modifiers?.some((m) => m.kind === ts6.SyntaxKind.DeclareKeyword))
539
+ return "";
474
540
  const name = node.name ? node.name.text : "anon";
475
- const extensions = node.heritageClauses?.filter((h) => h.token === ts5.SyntaxKind.ExtendsKeyword);
541
+ const extensions = node.heritageClauses?.filter((h) => h.token === ts6.SyntaxKind.ExtendsKeyword);
476
542
  let output = `${name} = {}`;
477
- if (extensions && extensions.length && extensions[0].types.length)
543
+ if (extensions?.length && extensions[0].types.length)
478
544
  output = `${name} = new ${NodeHandler.handle(extensions[0].types[0].expression)}`;
479
545
  const declaredNames = new Set;
480
546
  let hasConstructor = false;
481
547
  for (const member of node.members) {
482
- if (ts5.isFunctionLike(member) && "body" in member && !member.body)
548
+ if (ts6.isFunctionLike(member) && "body" in member && !member.body)
483
549
  continue;
484
- if (ts5.isSemicolonClassElement(member))
550
+ if (ts6.isSemicolonClassElement(member))
485
551
  continue;
486
552
  if (member.name) {
487
553
  const memberName = NodeHandler.handle(member.name);
@@ -490,78 +556,67 @@ NodeHandler.register(ts5.SyntaxKind.ClassDeclaration, (node) => {
490
556
  Modifiers such as 'static' are only for TypeScript for now and are not differentiated in the transpiled version from normal declarations for now`;
491
557
  declaredNames.add(memberName);
492
558
  }
493
- if (ts5.isConstructorDeclaration(member))
559
+ if (ts6.isConstructorDeclaration(member))
494
560
  hasConstructor = true;
495
561
  output += `
496
562
  ${name}.${NodeHandler.handle(member)}`;
497
563
  }
498
- if (!hasConstructor && !node.modifiers?.some((m) => m.kind === ts5.SyntaxKind.AbstractKeyword))
564
+ if (!hasConstructor && !node.modifiers?.some((m) => m.kind === ts6.SyntaxKind.AbstractKeyword))
499
565
  output += `
500
566
  ${name}.constructor = function
501
567
  return self
502
568
  end function`;
503
569
  return output;
504
570
  });
505
- NodeHandler.register(ts5.SyntaxKind.Constructor, (node) => {
571
+ NodeHandler.register(ts6.SyntaxKind.Constructor, (node, ctx) => {
506
572
  if (!node.body)
507
573
  return "";
508
- const declaredProperties = [];
509
- const params = node.parameters.map((param) => {
510
- const res = NodeHandler.handle(param);
511
- if (param.modifiers) {
512
- const paramName = NodeHandler.handle(param.name);
513
- const declaration = ` self.${paramName} = ${paramName}`;
514
- declaredProperties.push(declaration);
515
- }
516
- return res;
517
- }).join(", ");
518
- let body = NodeHandler.handle(node.body);
519
- if (declaredProperties.length) {
520
- const propertiesStr = declaredProperties.join(`
574
+ const func = handleFunctionBodyAndParams(node, ctx);
575
+ if (ctx.parameterProperties.length) {
576
+ const propertiesStr = ctx.parameterProperties.join(`
521
577
  `);
522
- const lines = body.split(`
578
+ ctx.parameterProperties.length = 0;
579
+ const lines = func.body.split(`
523
580
  `);
524
581
  const superIndex = lines.findIndex((line) => line.includes("super.constructor"));
525
582
  if (superIndex !== -1) {
526
- body = `${lines.slice(0, superIndex + 1).join(`
583
+ func.body = `${lines.slice(0, superIndex + 1).join(`
527
584
  `)}
528
585
  ${propertiesStr}
529
586
  ${lines.slice(superIndex + 1).join(`
530
587
  `)}`;
531
588
  } else {
532
- body = `${propertiesStr}
533
- ${body}`;
589
+ func.body = `${propertiesStr}
590
+ ${func.body}`;
534
591
  }
535
592
  }
536
- return `constructor = function(${params})
537
- ${body}
538
- return self
539
- end function`;
593
+ return [
594
+ `constructor = function${func.params.length ? `(${func.params.join(", ")})` : ""}`,
595
+ ...func.body ? [func.body] : [],
596
+ "\treturn self",
597
+ `end function`
598
+ ].join(`
599
+ `);
540
600
  });
541
- NodeHandler.register(ts5.SyntaxKind.GetAccessor, (node) => {
601
+ NodeHandler.register(ts6.SyntaxKind.GetAccessor, (node, ctx) => {
542
602
  if (!node.body)
543
603
  return "";
544
- const body = NodeHandler.handle(node.body);
545
- return `${NodeHandler.handle(node.name)} = function
546
- ${body}
547
- end function`;
604
+ const func = handleFunctionBodyAndParams(node, ctx);
605
+ return `${NodeHandler.handle(node.name)} = ${func.functionOutput}`;
548
606
  });
549
- NodeHandler.register(ts5.SyntaxKind.SetAccessor, (node) => {
607
+ NodeHandler.register(ts6.SyntaxKind.SetAccessor, (node, ctx) => {
550
608
  if (!node.body)
551
609
  return "";
552
- const body = NodeHandler.handle(node.body);
553
- const params = node.parameters.map((param) => NodeHandler.handle(param));
554
- return `set_${NodeHandler.handle(node.name)} = function(${params.join(", ")})
555
- ${body}
556
- end function`;
610
+ const func = handleFunctionBodyAndParams(node, ctx);
611
+ return `set_${NodeHandler.handle(node.name)} = ${func.functionOutput}`;
557
612
  });
558
613
 
559
614
  // src/visitors/expressions.ts
560
- import ts7 from "typescript";
615
+ import ts8 from "typescript";
561
616
 
562
617
  // src/call_transformers/callTransformer.ts
563
618
  import path3 from "node:path";
564
- import ts6 from "typescript";
619
+ import ts7 from "typescript";
565
620
  class CallTransformer {
566
621
  static handlers = new Map;
567
622
  static register(symbolFullName, handler) {
@@ -569,10 +624,23 @@ class CallTransformer {
569
624
  throw `Handler for '${symbolFullName}' was already registered`;
570
625
  this.handlers.set(symbolFullName, handler);
571
626
  }
572
- static handle(symbolFullName, functionName, callArgs, node, ctx) {
627
+ static handle(type, functionName, callArgs, node, ctx) {
628
+ let symbolFullName = "";
629
+ if (type.isUnion()) {
630
+ let result = null;
631
+ for (const t of type.types) {
632
+ const res = CallTransformer.handle(t, functionName, callArgs, node, ctx);
633
+ result ??= res;
634
+ }
635
+ return result;
636
+ } else if (type.symbol) {
637
+ symbolFullName = checker.getFullyQualifiedName(type.symbol);
638
+ }
639
+ if (!symbolFullName || symbolFullName.startsWith("__")) {
640
+ const symbol = checker.getSymbolAtLocation(node.expression);
641
+ symbolFullName = symbol ? checker.getFullyQualifiedName(symbol) : "";
642
+ }
573
643
  if (symbolFullName in extensionFunctions) {
574
- if (symbolFullName.startsWith("Math"))
575
- utilitiesToInsert.set("create_math", "Math = {}");
576
644
  utilitiesToInsert.set(symbolFullName, extensionFunctions[symbolFullName]);
577
645
  const params = callArgs.length ? `(${callArgs.join(",")})` : "";
578
646
  return `${functionName}${params}`;
@@ -583,19 +651,15 @@ class CallTransformer {
583
651
  return handler(functionName, callArgs, node, ctx);
584
652
  }
585
653
  }
586
- CallTransformer.register("Number.toString", (name) => {
587
- const number = name.slice(0, name.lastIndexOf("."));
588
- return `str(${number})`;
589
- });
590
654
  CallTransformer.register("Function.toString", (name) => {
591
655
  const func = name.slice(0, name.lastIndexOf("."));
592
656
  return `str(@${func})`;
593
657
  });
594
- CallTransformer.register("GreyHack.include", (name, args, node, ctx) => {
658
+ CallTransformer.register("GreyHack.include", (_name, _args, node, ctx) => {
595
659
  if (!node.arguments.length)
596
660
  return "";
597
661
  const fileArg = node.arguments[0];
598
- if (!ts6.isStringLiteralLike(fileArg))
662
+ if (!ts7.isStringLiteralLike(fileArg))
599
663
  throw "You can't include variables";
600
664
  const absPath = path3.resolve(ctx.currentFolder, fileArg.text);
601
665
  const sources = getSourceFiles(absPath);
@@ -604,20 +668,20 @@ CallTransformer.register("GreyHack.include", (name, args, node, ctx) => {
604
668
  }
605
669
  return "";
606
670
  });
607
- CallTransformer.register("GreyHack.isType", (name, args) => {
671
+ CallTransformer.register("GreyHack.isType", (_name, args) => {
608
672
  return callUtilFunction("is_type", args.join(","));
609
673
  });
610
- CallTransformer.register("Boolean", (name, args) => {
674
+ CallTransformer.register("Boolean", (_name, args) => {
611
675
  if (!args.length)
612
676
  return "0";
613
677
  return `(not (not ${args[0]}))`;
614
678
  });
615
- CallTransformer.register("Number", (name, args) => {
679
+ CallTransformer.register("Number", (_name, args) => {
616
680
  if (!args.length)
617
681
  return "0";
618
682
  return `str(${args[0]}).val`;
619
683
  });
620
- CallTransformer.register("String", (name, args) => {
684
+ CallTransformer.register("String", (_name, args) => {
621
685
  if (!args.length)
622
686
  return "";
623
687
  return `str(${args[0]})`;
@@ -628,7 +692,7 @@ function hasRestParam(params) {
628
692
  if (!params.length)
629
693
  return false;
630
694
  const lastParam = params[params.length - 1];
631
- return !!(lastParam.valueDeclaration && ts7.isParameter(lastParam.valueDeclaration) && lastParam.valueDeclaration.dotDotDotToken);
695
+ return !!(lastParam.valueDeclaration && ts8.isParameter(lastParam.valueDeclaration) && lastParam.valueDeclaration.dotDotDotToken);
632
696
  }
633
697
  function handleCallArgs(callNode, ctx) {
634
698
  const args = callNode.arguments;
@@ -652,11 +716,11 @@ function handleCallArgs(callNode, ctx) {
652
716
  }
653
717
  }
654
718
  for (const arg of args) {
655
- if (!ts7.isSpreadElement(arg)) {
719
+ if (!ts8.isSpreadElement(arg)) {
656
720
  pushArgs(false, NodeHandler.handle(arg));
657
721
  continue;
658
722
  }
659
- if (ts7.isArrayLiteralExpression(arg.expression)) {
723
+ if (ts8.isArrayLiteralExpression(arg.expression)) {
660
724
  const arrayItems = [];
661
725
  const outArrs = [];
662
726
  handleArrayLiteralExpression(arg.expression, ctx, arrayItems, outArrs);
@@ -708,38 +772,35 @@ function handleCallArgs(callNode, ctx) {
708
772
  result.push("[]");
709
773
  return result;
710
774
  }
711
- NodeHandler.register(ts7.SyntaxKind.CallExpression, (node, ctx) => {
775
+ NodeHandler.register(ts8.SyntaxKind.CallExpression, (node, ctx) => {
712
776
  const args = handleCallArgs(node, ctx);
713
- let name = NodeHandler.handle(node.expression);
777
+ const name = NodeHandler.handle(node.expression);
714
778
  const type = checker.getTypeAtLocation(node.expression);
715
- let symbolFullName = type.symbol ? checker.getFullyQualifiedName(type.symbol) : "";
716
- if (!symbolFullName || symbolFullName.startsWith("__")) {
717
- const symbol = checker.getSymbolAtLocation(node.expression);
718
- symbolFullName = symbol ? checker.getFullyQualifiedName(symbol) : "";
719
- }
720
- const transformed = CallTransformer.handle(symbolFullName, name, args, node, ctx);
779
+ const transformed = CallTransformer.handle(type, name, args, node, ctx);
721
780
  if (transformed !== null)
722
781
  return transformed;
723
- if (!args.length && !ts7.isParenthesizedExpression(node.expression))
782
+ if (!args.length && !ts8.isParenthesizedExpression(node.expression))
724
783
  return name;
725
784
  return `${name}(${args.join(", ")})`;
726
785
  });
727
- NodeHandler.register(ts7.SyntaxKind.NewExpression, (node, ctx) => {
786
+ NodeHandler.register(ts8.SyntaxKind.NewExpression, (node, ctx) => {
728
787
  const args = handleCallArgs(node, ctx);
729
788
  let output = `(new ${NodeHandler.handle(node.expression)}).constructor`;
730
789
  if (args.length)
731
790
  output += `(${args.join(",")})`;
732
791
  return output;
733
792
  });
734
- function shouldHaveOuterPrefix(node, operator) {
793
+ function shouldHaveOuterPrefix(node, operator, ctx) {
735
794
  if (!assignmentOperators.has(operator))
736
795
  return false;
737
- if (!ts7.isIdentifier(node.left))
796
+ if (!ts8.isIdentifier(node.left))
738
797
  return false;
739
- const functionAncestor = ts7.findAncestor(node.parent, (n) => ts7.isFunctionLike(n));
798
+ if (ctx.forceOuterPrefix)
799
+ return true;
800
+ const functionAncestor = ts8.findAncestor(node.parent, (n) => ts8.isFunctionLike(n));
740
801
  if (!functionAncestor)
741
802
  return false;
742
- if (!ts7.findAncestor(functionAncestor.parent, (n) => ts7.isFunctionLike(n)))
803
+ if (!ts8.findAncestor(functionAncestor.parent, (n) => ts8.isFunctionLike(n)))
743
804
  return false;
744
805
  const leftSymbol = checker.getSymbolAtLocation(node.left);
745
806
  if (!leftSymbol?.valueDeclaration)
@@ -749,26 +810,26 @@ function shouldHaveOuterPrefix(node, operator) {
749
810
  function isAssignmentChain(node, operator) {
750
811
  if (!assignmentOperators.has(operator))
751
812
  return false;
752
- if (ts7.isBinaryExpression(node.right) && assignmentOperators.has(ts7.tokenToString(node.right.operatorToken.kind) || ""))
813
+ if (ts8.isBinaryExpression(node.right) && assignmentOperators.has(ts8.tokenToString(node.right.operatorToken.kind) || ""))
753
814
  return true;
754
- if (ts7.hasOnlyExpressionInitializer(node.parent))
815
+ if (ts8.hasOnlyExpressionInitializer(node.parent))
755
816
  return true;
756
817
  return false;
757
818
  }
758
- NodeHandler.register(ts7.SyntaxKind.BinaryExpression, (node) => {
819
+ NodeHandler.register(ts8.SyntaxKind.BinaryExpression, (node, ctx) => {
759
820
  let operatorToken = getOperatorToken(node.operatorToken) || node.operatorToken.getText();
760
821
  if (isAssignmentChain(node, operatorToken))
761
822
  throw `Assignment chaining is not supported`;
762
823
  let right = NodeHandler.handle(node.right);
763
824
  if (nodeIsFunctionReference(node.right))
764
825
  right = asRef(right);
765
- if (ts7.isPropertyAccessExpression(node.left)) {
826
+ if (ts8.isPropertyAccessExpression(node.left)) {
766
827
  const leftType = checker.getTypeAtLocation(node.left.expression);
767
828
  const symbol = leftType.getProperty(node.left.name.text);
768
- if (symbol?.declarations?.some((decl) => ts7.isSetAccessor(decl))) {
829
+ if (symbol?.declarations?.some((decl) => ts8.isSetAccessor(decl))) {
769
830
  const objName = NodeHandler.handle(node.left.expression);
770
831
  const key = node.left.name.text;
771
- if (operatorToken !== "=" && symbol.declarations.some((decl) => ts7.isGetAccessor(decl)))
832
+ if (operatorToken !== "=" && symbol.declarations.some((decl) => ts8.isGetAccessor(decl)))
772
833
  throw `Can't handle '${operatorToken}' because '${objName}' doesn't have a getter '${key}'`;
773
834
  if (operatorToken === "+=" || operatorToken === "-=") {
774
835
  right = `${objName}.${key} ${operatorToken[0]} ${right}`;
@@ -779,11 +840,11 @@ NodeHandler.register(ts7.SyntaxKind.BinaryExpression, (node) => {
779
840
  }
780
841
  }
781
842
  let left = NodeHandler.handle(node.left);
782
- if (shouldHaveOuterPrefix(node, operatorToken))
783
- left = "outer." + left;
843
+ if (shouldHaveOuterPrefix(node, operatorToken, ctx))
844
+ left = `outer.${left}`;
784
845
  if (nodeIsFunctionReference(node.left))
785
846
  left = asRef(left);
786
- if (operatorToken === "or" && ts7.hasOnlyExpressionInitializer(node.parent)) {
847
+ if (operatorToken === "or" && ts8.hasOnlyExpressionInitializer(node.parent)) {
787
848
  return callUtilFunction("or_op", left, right);
788
849
  }
789
850
  switch (operatorToken) {
@@ -792,7 +853,15 @@ NodeHandler.register(ts7.SyntaxKind.BinaryExpression, (node) => {
792
853
  case "??":
793
854
  return callUtilFunction("nullish_coalescing_op", left, right);
794
855
  case "??=":
795
- return `${left} = ${callUtilFunction("nullish_coalescing_op", left, right)}`;
856
+ case "||=": {
857
+ const util = operatorToken === "??=" ? "nullish_coalescing_op" : "or_op";
858
+ ctx.forceSafeAccess = true;
859
+ let leftSafe = NodeHandler.handle(node.left);
860
+ ctx.forceSafeAccess = false;
861
+ if (nodeIsFunctionReference(node.left))
862
+ leftSafe = asRef(leftSafe);
863
+ return `${left} = ${callUtilFunction(util, leftSafe, right)}`;
864
+ }
796
865
  case "in":
797
866
  return `${right}.hasIndex(${left})`;
798
867
  case "&":
@@ -807,28 +876,37 @@ NodeHandler.register(ts7.SyntaxKind.BinaryExpression, (node) => {
807
876
  return `bitwise(">>", ${left}, ${right})`;
808
877
  case ">>>":
809
878
  return `bitwise(">>>", ${left}, ${right})`;
879
+ case "<<=":
880
+ case ">>=":
881
+ case ">>>=":
882
+ return `${left} = bitwise("${operatorToken.slice(0, -1)}", ${left}, ${right})`;
883
+ case "**=":
884
+ return `${left} = ${left} ^ ${right}`;
810
885
  case "+=":
811
886
  case "-=":
887
+ case "*=":
888
+ case "/=":
889
+ case "%=":
812
890
  return `${left} = ${left} ${operatorToken[0]} ${right}`;
813
891
  }
814
892
  if (operatorToken === "**")
815
893
  operatorToken = "^";
816
894
  return `${left} ${operatorToken} ${right}`;
817
895
  });
818
- NodeHandler.register(ts7.SyntaxKind.ParenthesizedExpression, (node) => {
896
+ NodeHandler.register(ts8.SyntaxKind.ParenthesizedExpression, (node) => {
819
897
  return `(${NodeHandler.handle(node.expression)})`;
820
898
  });
821
899
  function handleUnaryExpression(node) {
822
900
  const operand = NodeHandler.handle(node.operand);
823
- const operator = ts7.tokenToString(node.operator);
901
+ const operator = ts8.tokenToString(node.operator);
824
902
  switch (operator) {
825
903
  case "++":
826
904
  case "--":
827
- if (ts7.hasOnlyExpressionInitializer(node.parent) || ts7.isBinaryExpression(node.parent))
905
+ if (ts8.hasOnlyExpressionInitializer(node.parent) || ts8.isBinaryExpression(node.parent))
828
906
  throw `Operator ${operator} is not supported for this kind of expression yet`;
829
907
  return `${operand} = ${operand} ${operator[0]} 1`;
830
908
  case "!":
831
- if (ts7.isPrefixUnaryExpression(node.parent) && ts7.tokenToString(node.parent.operator) === "!") {
909
+ if (ts8.isPrefixUnaryExpression(node.parent) && ts8.tokenToString(node.parent.operator) === "!") {
832
910
  return `(not ${operand})`;
833
911
  }
834
912
  return `not ${operand}`;
@@ -842,17 +920,17 @@ function handleUnaryExpression(node) {
842
920
  throw `Couldn't handle this UnaryExpression: ${node.getText()}`;
843
921
  }
844
922
  }
845
- NodeHandler.register(ts7.SyntaxKind.PrefixUnaryExpression, handleUnaryExpression);
846
- NodeHandler.register(ts7.SyntaxKind.PostfixUnaryExpression, handleUnaryExpression);
923
+ NodeHandler.register(ts8.SyntaxKind.PrefixUnaryExpression, handleUnaryExpression);
924
+ NodeHandler.register(ts8.SyntaxKind.PostfixUnaryExpression, handleUnaryExpression);
847
925
  function handleArrayLiteralExpression(node, ctx, itemStrings, out) {
848
926
  itemStrings ??= [];
849
927
  out ??= [];
850
928
  for (const item of node.elements) {
851
- if (!ts7.isSpreadElement(item)) {
929
+ if (!ts8.isSpreadElement(item)) {
852
930
  itemStrings.push(NodeHandler.handle(item));
853
931
  continue;
854
932
  }
855
- if (ts7.isArrayLiteralExpression(item.expression)) {
933
+ if (ts8.isArrayLiteralExpression(item.expression)) {
856
934
  handleArrayLiteralExpression(item.expression, ctx, itemStrings, out);
857
935
  continue;
858
936
  }
@@ -862,14 +940,14 @@ function handleArrayLiteralExpression(node, ctx, itemStrings, out) {
862
940
  }
863
941
  out.push(NodeHandler.handle(item.expression));
864
942
  }
865
- if ((!out.length || itemStrings.length) && !ts7.isSpreadElement(node.parent)) {
943
+ if ((!out.length || itemStrings.length) && !ts8.isSpreadElement(node.parent)) {
866
944
  out.push(`[${itemStrings.join(",")}]`);
867
945
  itemStrings.length = 0;
868
946
  }
869
947
  return out.join(" + ");
870
948
  }
871
- NodeHandler.register(ts7.SyntaxKind.ArrayLiteralExpression, handleArrayLiteralExpression);
872
- NodeHandler.register(ts7.SyntaxKind.TemplateExpression, (node) => {
949
+ NodeHandler.register(ts8.SyntaxKind.ArrayLiteralExpression, handleArrayLiteralExpression);
950
+ NodeHandler.register(ts8.SyntaxKind.TemplateExpression, (node) => {
873
951
  const head = NodeHandler.handle(node.head);
874
952
  const strings = [
875
953
  ...head ? [`"${head}"`] : [],
@@ -878,51 +956,54 @@ NodeHandler.register(ts7.SyntaxKind.TemplateExpression, (node) => {
878
956
  const output = strings.join(" + ");
879
957
  return output;
880
958
  });
881
- NodeHandler.register(ts7.SyntaxKind.TemplateHead, (node) => {
959
+ NodeHandler.register(ts8.SyntaxKind.TemplateHead, (node) => {
882
960
  return transformString(node.text);
883
961
  });
884
- NodeHandler.register(ts7.SyntaxKind.TemplateSpan, (node) => {
962
+ NodeHandler.register(ts8.SyntaxKind.TemplateSpan, (node) => {
885
963
  let output = NodeHandler.handle(node.expression);
886
- if (ts7.isBinaryExpression(node.expression))
964
+ if (ts8.isBinaryExpression(node.expression))
887
965
  output = `str(${output})`;
888
966
  if (node.literal.text)
889
967
  output += ` + "${transformString(node.literal.text)}"`;
890
968
  return output;
891
969
  });
892
- NodeHandler.register(ts7.SyntaxKind.NoSubstitutionTemplateLiteral, (node) => {
970
+ NodeHandler.register(ts8.SyntaxKind.NoSubstitutionTemplateLiteral, (node) => {
893
971
  return `"${transformString(node.text)}"`;
894
972
  });
895
- NodeHandler.register(ts7.SyntaxKind.ConditionalExpression, (node) => {
896
- if (ts7.isCallExpression(node.whenTrue) || ts7.isCallExpression(node.whenFalse)) {
973
+ NodeHandler.register(ts8.SyntaxKind.ConditionalExpression, (node) => {
974
+ if (ts8.isCallExpression(node.whenTrue) || ts8.isCallExpression(node.whenFalse)) {
897
975
  throw "Call expressions are not supported inside conditional expressions yet";
898
976
  }
977
+ if (ts8.isBinaryExpression(node.whenTrue) || ts8.isBinaryExpression(node.whenFalse)) {
978
+ throw "Binary expressions are not supported inside conditional expressions yet";
979
+ }
899
980
  const condition = NodeHandler.handle(node.condition);
900
981
  const whenTrue = NodeHandler.handle(node.whenTrue);
901
982
  const whenFalse = NodeHandler.handle(node.whenFalse);
902
983
  return callUtilFunction("conditional_expr", condition, whenTrue, whenFalse);
903
984
  });
904
- NodeHandler.register(ts7.SyntaxKind.ExpressionStatement, (node) => {
985
+ NodeHandler.register(ts8.SyntaxKind.ExpressionStatement, (node) => {
905
986
  return NodeHandler.handle(node.expression);
906
987
  });
907
- NodeHandler.register(ts7.SyntaxKind.NonNullExpression, (node) => {
988
+ NodeHandler.register(ts8.SyntaxKind.NonNullExpression, (node) => {
908
989
  return NodeHandler.handle(node.expression);
909
990
  });
910
- NodeHandler.register(ts7.SyntaxKind.AsExpression, (node) => {
991
+ NodeHandler.register(ts8.SyntaxKind.AsExpression, (node) => {
911
992
  return NodeHandler.handle(node.expression);
912
993
  });
913
- NodeHandler.register(ts7.SyntaxKind.DeleteExpression, (node) => {
914
- if (ts7.isPropertyAccessExpression(node.expression)) {
994
+ NodeHandler.register(ts8.SyntaxKind.DeleteExpression, (node) => {
995
+ if (ts8.isPropertyAccessExpression(node.expression)) {
915
996
  const pnode = node.expression;
916
997
  const left = NodeHandler.handle(pnode.expression);
917
998
  const leftType = checker.getTypeAtLocation(pnode.expression);
918
999
  const right = replaceIdentifier(NodeHandler.handle(pnode.name), leftType, pnode.name.text);
919
1000
  return `${left}.remove("${right}")`;
920
1001
  }
921
- if (ts7.isElementAccessExpression(node.expression)) {
1002
+ if (ts8.isElementAccessExpression(node.expression)) {
922
1003
  const pnode = node.expression;
923
1004
  const left = NodeHandler.handle(pnode.expression);
924
1005
  let right;
925
- if (ts7.isStringLiteral(pnode.argumentExpression)) {
1006
+ if (ts8.isStringLiteral(pnode.argumentExpression)) {
926
1007
  const leftType = checker.getTypeAtLocation(pnode.expression);
927
1008
  right = `"${replaceIdentifier(pnode.argumentExpression.text, leftType, pnode.argumentExpression.text)}"`;
928
1009
  } else {
@@ -930,62 +1011,7 @@ NodeHandler.register(ts7.SyntaxKind.DeleteExpression, (node) => {
930
1011
  }
931
1012
  return `${left}.remove(${right})`;
932
1013
  }
933
- throw `Cant handle delete expression for ${ts7.SyntaxKind[node.expression.kind]}`;
934
- });
935
-
936
- // src/visitors/functions.ts
937
- import ts8 from "typescript";
938
- function transpileFunctionBody(node) {
939
- const params = node.parameters.map((param) => NodeHandler.handle(param)).join(", ");
940
- const body = node.body ? NodeHandler.handle(node.body) : "";
941
- return `function(${params})
942
- ${body}
943
- end function`;
944
- }
945
- NodeHandler.register(ts8.SyntaxKind.Block, (node) => {
946
- const output = node.statements.map((val) => {
947
- let statement = NodeHandler.handle(val);
948
- statement = statement.split(`
949
- `).filter((s) => !!s).map((line) => "\t" + line).join(`
950
- `);
951
- return statement;
952
- }).filter((s) => !!s).join(`
953
- `);
954
- return output;
955
- });
956
- NodeHandler.register(ts8.SyntaxKind.MethodDeclaration, (node) => {
957
- return `${NodeHandler.handle(node.name)} = ${transpileFunctionBody(node)}`;
958
- });
959
- NodeHandler.register(ts8.SyntaxKind.FunctionDeclaration, (node) => {
960
- if (!node.body)
961
- return "";
962
- if (node.modifiers?.some((m) => m.kind === ts8.SyntaxKind.DeclareKeyword))
963
- return "";
964
- const name = node.name ? node.name.text : "anon";
965
- return `${name} = ${transpileFunctionBody(node)}`;
966
- });
967
- NodeHandler.register(ts8.SyntaxKind.ArrowFunction, (node) => {
968
- const params = node.parameters.map((param) => NodeHandler.handle(param));
969
- const body = ts8.isBlock(node.body) ? NodeHandler.handle(node.body) : ` return ${NodeHandler.handle(node.body)}`;
970
- if (ts8.isCallOrNewExpression(node.parent) || ts8.isParenthesizedExpression(node.parent)) {
971
- const mainNode = ts8.findAncestor(node.parent, (n) => n.parent && (ts8.isBlock(n.parent) || ts8.isSourceFile(n.parent)));
972
- if (!mainNode) {
973
- return "@" + createAnonFunction(body, params).name;
974
- }
975
- const anon = createAnonFunction(body, params, false);
976
- NodeHandler.addExtraOutput(mainNode, anon.str, null);
977
- return "@" + anon.name;
978
- }
979
- if (ts8.hasOnlyExpressionInitializer(node.parent) || ts8.isBinaryExpression(node.parent) || ts8.isReturnStatement(node.parent)) {
980
- return `function(${params.join(", ")})
981
- ${body}
982
- end function`;
983
- }
984
- const kind = ts8.SyntaxKind[node.parent.kind];
985
- throw `This kind of arrow function is not yet supported (parent: ${kind} (${node.parent.kind}))`;
986
- });
987
- NodeHandler.register(ts8.SyntaxKind.FunctionExpression, (node) => {
988
- return transpileFunctionBody(node);
1014
+ throw `Cant handle delete expression for ${ts8.SyntaxKind[node.expression.kind]}`;
989
1015
  });
990
1016
 
991
1017
  // src/visitors/identifiers.ts
@@ -995,27 +1021,30 @@ NodeHandler.register(ts9.SyntaxKind.Identifier, (node, ctx) => {
995
1021
  let name = node.text;
996
1022
  if (name === "undefined")
997
1023
  return "null";
998
- if (type.isUnion()) {
999
- const original = node.text;
1000
- for (const t of type.types) {
1001
- name = replaceIdentifier(node.text, t);
1002
- if (name != original)
1003
- break;
1004
- }
1005
- } else {
1006
- name = replaceIdentifier(node.text, type);
1024
+ name = replaceIdentifier(node.text, type);
1025
+ const symbolFullName = type.symbol ? checker.getFullyQualifiedName(type.symbol) : "";
1026
+ if (symbolFullName in globalObjects) {
1027
+ utilitiesToInsert.set(symbolFullName, globalObjects[symbolFullName]);
1007
1028
  }
1008
- if (ctx.namedImports[ctx.currentFilePath]?.[name]) {
1029
+ if (ctx.namedImports[ctx.currentFilePath] && Object.hasOwn(ctx.namedImports[ctx.currentFilePath], name)) {
1009
1030
  name = ctx.namedImports[ctx.currentFilePath][name];
1010
1031
  }
1011
- if (ts9.isCallOrNewExpression(node.parent) && node != node.parent.expression) {
1032
+ if (Object.hasOwn(ctx.bindingElements, name)) {
1033
+ return ctx.bindingElements[name];
1034
+ }
1035
+ if (ts9.isCallOrNewExpression(node.parent) && node !== node.parent.expression) {
1012
1036
  if (nodeIsFunctionReference(node, type))
1013
1037
  name = asRef(name);
1014
1038
  }
1015
1039
  return name;
1016
1040
  });
1017
- NodeHandler.register(ts9.SyntaxKind.Parameter, (node) => {
1041
+ NodeHandler.register(ts9.SyntaxKind.Parameter, (node, ctx) => {
1018
1042
  const name = NodeHandler.handle(node.name);
1043
+ if (node.modifiers && ts9.isConstructorDeclaration(node.parent)) {
1044
+ const paramName = name;
1045
+ const declaration = ` self.${paramName} = ${paramName}`;
1046
+ ctx.parameterProperties.push(declaration);
1047
+ }
1019
1048
  if (!node.initializer)
1020
1049
  return name;
1021
1050
  const initializer = NodeHandler.handle(node.initializer);
@@ -1095,37 +1124,38 @@ NodeHandler.register(ts10.SyntaxKind.ImportDeclaration, (node, ctx) => {
1095
1124
 
1096
1125
  // src/visitors/objects.ts
1097
1126
  import ts11 from "typescript";
1098
- function shouldGetSafely(node) {
1127
+ function shouldGetSafely(node, ctx) {
1099
1128
  if (ts11.isNonNullExpression(node.parent))
1100
1129
  return false;
1130
+ const callParent = ts11.findAncestor(node, (n) => n.parent && ts11.isCallExpression(n.parent) && n.parent.expression === n);
1131
+ if (callParent)
1132
+ return false;
1133
+ if (ctx.forceSafeAccess)
1134
+ return true;
1101
1135
  if (valueIsBeingAssignedToNode(node))
1102
1136
  return false;
1103
- if (ts11.isPropertyAccessExpression(node)) {
1104
- const rightType = checker.getTypeAtLocation(node.name);
1105
- if (!rightType.isUnion())
1106
- return !!node.questionDotToken;
1107
- const hasUndefined = rightType.types.some((t) => t.flags === ts11.TypeFlags.Undefined);
1108
- if (!hasUndefined)
1109
- return false;
1110
- if (!ts11.isCallExpression(node.parent))
1111
- return true;
1112
- if (node.parent.arguments.length)
1113
- return false;
1114
- } else {
1137
+ if (ts11.isElementAccessExpression(node)) {
1115
1138
  if (ts11.isNumericLiteral(node.argumentExpression) && !node.questionDotToken)
1116
1139
  return false;
1140
+ return true;
1117
1141
  }
1142
+ const type = checker.getTypeAtLocation(node);
1143
+ if (!type.isUnion())
1144
+ return !!node.questionDotToken;
1145
+ const hasNullish = type.types.some((t) => t.flags === ts11.TypeFlags.Undefined || ts11.TypeFlags.Null);
1146
+ if (!hasNullish)
1147
+ return false;
1118
1148
  return true;
1119
1149
  }
1120
1150
  NodeHandler.register(ts11.SyntaxKind.PropertyAccessExpression, (node, ctx) => {
1121
1151
  const left = NodeHandler.handle(node.expression);
1122
1152
  let right = NodeHandler.handle(node.name);
1123
1153
  right = replaceIdentifier(right, checker.getTypeAtLocation(node.expression), right);
1124
- const nodeSymbol = checker.getSymbolAtLocation(node);
1125
1154
  if (ctx.namespaceImports[ctx.currentFilePath]?.has(left))
1126
1155
  return right;
1127
- if (shouldGetSafely(node))
1156
+ if (shouldGetSafely(node, ctx))
1128
1157
  return callUtilFunction("get_property", left, `"${right}"`);
1158
+ const nodeSymbol = checker.getSymbolAtLocation(node);
1129
1159
  let output = `${left}.${right}`;
1130
1160
  output = replacePropertyAccess(output, nodeSymbol);
1131
1161
  if (nodeIsFunctionReference(node))
@@ -1141,7 +1171,7 @@ NodeHandler.register(ts11.SyntaxKind.ElementAccessExpression, (node, ctx) => {
1141
1171
  } else {
1142
1172
  right = NodeHandler.handle(node.argumentExpression);
1143
1173
  }
1144
- if (shouldGetSafely(node)) {
1174
+ if (shouldGetSafely(node, ctx)) {
1145
1175
  return callUtilFunction("get_property", left, `${right}`);
1146
1176
  }
1147
1177
  return `${left}[${right}]`;
@@ -1158,7 +1188,7 @@ function handleObjectLiteralExpression(node, ctx, currObj, outObjects, funcs) {
1158
1188
  function pushObj() {
1159
1189
  if (!currObj?.length)
1160
1190
  return "";
1161
- const res = currObj.filter((s) => s != "").join(",");
1191
+ const res = currObj.filter((s) => s !== "").join(",");
1162
1192
  if (res) {
1163
1193
  outObjects?.push(`{ ${res} }`);
1164
1194
  }
@@ -1204,16 +1234,42 @@ function handleObjectLiteralExpression(node, ctx, currObj, outObjects, funcs) {
1204
1234
  throw "You can't have method declarations inside an object that is not being assigned to a variable";
1205
1235
  }
1206
1236
  output += `
1207
- ` + funcs.map((func) => `${objectName}.${func}`).join(`
1208
- `);
1237
+ ${funcs.map((func) => `${objectName}.${func}`).join(`
1238
+ `)}`;
1209
1239
  }
1210
1240
  return output;
1211
1241
  }
1212
1242
  NodeHandler.register(ts11.SyntaxKind.ObjectLiteralExpression, handleObjectLiteralExpression);
1213
1243
 
1214
- // src/visitors/statements.ts
1244
+ // src/visitors/patterns.ts
1215
1245
  import ts12 from "typescript";
1216
- NodeHandler.register(ts12.SyntaxKind.ForStatement, (node) => {
1246
+ NodeHandler.register(ts12.SyntaxKind.ArrayBindingPattern, (node, ctx) => {
1247
+ if (!ts12.isParameter(node.parent))
1248
+ throw `This kind of ArrayBindingPattern is not yet supported (parent: ${ts12.SyntaxKind[node.parent.kind]})`;
1249
+ const index = Object.entries(ctx.bindingElements).length;
1250
+ const paramName = `arr${index || ""}`;
1251
+ for (let i = 0;i < node.elements.length; i++) {
1252
+ const element = node.elements[i];
1253
+ if (ts12.isOmittedExpression(element))
1254
+ continue;
1255
+ const name = NodeHandler.handle(element);
1256
+ if (!name || name === "null")
1257
+ continue;
1258
+ ctx.bindingElements[name] = `${paramName}[${i}]`;
1259
+ }
1260
+ return paramName;
1261
+ });
1262
+ NodeHandler.register(ts12.SyntaxKind.BindingElement, (node) => {
1263
+ if (node.initializer)
1264
+ throw "Initializers in BindingElement are not yet supported";
1265
+ if (!ts12.isIdentifier(node.name))
1266
+ throw "Nested binding patterns are not supported";
1267
+ return NodeHandler.handle(node.name);
1268
+ });
1269
+
1270
+ // src/visitors/statements.ts
1271
+ import ts13 from "typescript";
1272
+ NodeHandler.register(ts13.SyntaxKind.ForStatement, (node) => {
1217
1273
  if (!node.condition || !node.initializer || !node.incrementor) {
1218
1274
  throw "Can't transpile this type of for loop.";
1219
1275
  }
@@ -1223,7 +1279,7 @@ NodeHandler.register(ts12.SyntaxKind.ForStatement, (node) => {
1223
1279
  const statement = NodeHandler.handle(node.statement);
1224
1280
  function hasContinue(n) {
1225
1281
  if (n.getChildren().some((child) => {
1226
- if (ts12.isContinueStatement(child))
1282
+ if (ts13.isContinueStatement(child))
1227
1283
  return true;
1228
1284
  return hasContinue(child);
1229
1285
  })) {
@@ -1231,7 +1287,7 @@ NodeHandler.register(ts12.SyntaxKind.ForStatement, (node) => {
1231
1287
  }
1232
1288
  return false;
1233
1289
  }
1234
- const labelIf = ts12.isLabeledStatement(node.parent) ? ` if ${node.parent.label.text}Broke then break` : "";
1290
+ const labelIf = ts13.isLabeledStatement(node.parent) ? ` if ${node.parent.label.text}Broke then break` : "";
1235
1291
  if (!hasContinue(node)) {
1236
1292
  return [
1237
1293
  `${initializer}`,
@@ -1243,7 +1299,7 @@ NodeHandler.register(ts12.SyntaxKind.ForStatement, (node) => {
1243
1299
  ].join(`
1244
1300
  `);
1245
1301
  }
1246
- const incrementedStateVarName = "state_" + (Date.now() * Math.random()).toFixed(0).slice(0, 6);
1302
+ const incrementedStateVarName = `state_${(Date.now() * Math.random()).toFixed(0).slice(0, 6)}`;
1247
1303
  const output = [
1248
1304
  `${incrementedStateVarName} = 1`,
1249
1305
  `${initializer}`,
@@ -1262,8 +1318,8 @@ NodeHandler.register(ts12.SyntaxKind.ForStatement, (node) => {
1262
1318
  `);
1263
1319
  return output;
1264
1320
  });
1265
- NodeHandler.register(ts12.SyntaxKind.ForOfStatement, (node) => {
1266
- if (!ts12.isVariableDeclarationList(node.initializer)) {
1321
+ NodeHandler.register(ts13.SyntaxKind.ForOfStatement, (node) => {
1322
+ if (!ts13.isVariableDeclarationList(node.initializer)) {
1267
1323
  throw `Can't handle this 'for of' statement as '${NodeHandler.handle(node.initializer)}' is not initialized there`;
1268
1324
  }
1269
1325
  if (node.initializer.declarations.length > 1) {
@@ -1271,7 +1327,7 @@ NodeHandler.register(ts12.SyntaxKind.ForOfStatement, (node) => {
1271
1327
  }
1272
1328
  const varName = NodeHandler.handle(node.initializer.declarations[0].name);
1273
1329
  const objToLoop = NodeHandler.handle(node.expression);
1274
- const labelIf = ts12.isLabeledStatement(node.parent) ? ` if ${node.parent.label.text}Broke then break` : "";
1330
+ const labelIf = ts13.isLabeledStatement(node.parent) ? ` if ${node.parent.label.text}Broke then break` : "";
1275
1331
  return [
1276
1332
  `for ${varName} in ${objToLoop}`,
1277
1333
  `${NodeHandler.handle(node.statement)}`,
@@ -1280,8 +1336,8 @@ NodeHandler.register(ts12.SyntaxKind.ForOfStatement, (node) => {
1280
1336
  ].join(`
1281
1337
  `);
1282
1338
  });
1283
- NodeHandler.register(ts12.SyntaxKind.ForInStatement, (node) => {
1284
- if (!ts12.isVariableDeclarationList(node.initializer)) {
1339
+ NodeHandler.register(ts13.SyntaxKind.ForInStatement, (node) => {
1340
+ if (!ts13.isVariableDeclarationList(node.initializer)) {
1285
1341
  throw `Can't handle this 'for in' statement as '${NodeHandler.handle(node.initializer)}' is not initialized there`;
1286
1342
  }
1287
1343
  if (node.initializer.declarations.length > 1) {
@@ -1289,7 +1345,7 @@ NodeHandler.register(ts12.SyntaxKind.ForInStatement, (node) => {
1289
1345
  }
1290
1346
  const varName = NodeHandler.handle(node.initializer.declarations[0].name);
1291
1347
  const objToLoop = NodeHandler.handle(node.expression);
1292
- const labelIf = ts12.isLabeledStatement(node.parent) ? ` if ${node.parent.label.text}Broke then break` : "";
1348
+ const labelIf = ts13.isLabeledStatement(node.parent) ? ` if ${node.parent.label.text}Broke then break` : "";
1293
1349
  return [
1294
1350
  `for ${varName} in ${objToLoop}.indexes`,
1295
1351
  `${NodeHandler.handle(node.statement)}`,
@@ -1298,19 +1354,19 @@ NodeHandler.register(ts12.SyntaxKind.ForInStatement, (node) => {
1298
1354
  ].join(`
1299
1355
  `);
1300
1356
  });
1301
- NodeHandler.register(ts12.SyntaxKind.IfStatement, (node) => {
1357
+ NodeHandler.register(ts13.SyntaxKind.IfStatement, (node) => {
1302
1358
  const condition = NodeHandler.handle(node.expression);
1303
1359
  const thenStatement = NodeHandler.handle(node.thenStatement);
1304
- if (!ts12.isBlock(node.thenStatement) && !ts12.isIfStatement(node.thenStatement) && !ts12.isIfStatement(node.parent)) {
1360
+ if (!ts13.isBlock(node.thenStatement) && !ts13.isIfStatement(node.thenStatement) && !ts13.isIfStatement(node.parent)) {
1305
1361
  if (!node.elseStatement)
1306
1362
  return `if ${condition} then ${thenStatement}`;
1307
- else if (!ts12.isBlock(node.elseStatement) && !ts12.isIfStatement(node.elseStatement))
1363
+ else if (!ts13.isBlock(node.elseStatement) && !ts13.isIfStatement(node.elseStatement))
1308
1364
  return `if ${condition} then ${thenStatement} else ${NodeHandler.handle(node.elseStatement)}`;
1309
1365
  }
1310
1366
  let output = `if ${condition} then
1311
1367
  ${thenStatement.trimStart()}`;
1312
1368
  if (node.elseStatement) {
1313
- if (ts12.isIfStatement(node.elseStatement)) {
1369
+ if (ts13.isIfStatement(node.elseStatement)) {
1314
1370
  output += `
1315
1371
  else ${NodeHandler.handle(node.elseStatement)}`;
1316
1372
  return output;
@@ -1324,9 +1380,9 @@ else
1324
1380
  end if`;
1325
1381
  return output;
1326
1382
  });
1327
- NodeHandler.register(ts12.SyntaxKind.WhileStatement, (node, ctx) => {
1383
+ NodeHandler.register(ts13.SyntaxKind.WhileStatement, (node) => {
1328
1384
  const expression = NodeHandler.handle(node.expression);
1329
- const labelIf = ts12.isLabeledStatement(node.parent) ? ` if ${node.parent.label.text}Broke then break` : "";
1385
+ const labelIf = ts13.isLabeledStatement(node.parent) ? ` if ${node.parent.label.text}Broke then break` : "";
1330
1386
  return [
1331
1387
  `while ${expression}`,
1332
1388
  ` ${NodeHandler.handle(node.statement).trimStart()}`,
@@ -1335,9 +1391,9 @@ NodeHandler.register(ts12.SyntaxKind.WhileStatement, (node, ctx) => {
1335
1391
  ].join(`
1336
1392
  `);
1337
1393
  });
1338
- NodeHandler.register(ts12.SyntaxKind.DoStatement, (node, ctx) => {
1394
+ NodeHandler.register(ts13.SyntaxKind.DoStatement, (node) => {
1339
1395
  const expression = NodeHandler.handle(node.expression);
1340
- const labelIf = ts12.isLabeledStatement(node.parent) ? ` if ${node.parent.label.text}Broke then break` : "";
1396
+ const labelIf = ts13.isLabeledStatement(node.parent) ? ` if ${node.parent.label.text}Broke then break` : "";
1341
1397
  return [
1342
1398
  `did_once = 0`,
1343
1399
  `while not did_once or ${expression}`,
@@ -1348,69 +1404,69 @@ NodeHandler.register(ts12.SyntaxKind.DoStatement, (node, ctx) => {
1348
1404
  ].join(`
1349
1405
  `);
1350
1406
  });
1351
- NodeHandler.register(ts12.SyntaxKind.ContinueStatement, (node) => {
1407
+ NodeHandler.register(ts13.SyntaxKind.ContinueStatement, (_node) => {
1352
1408
  return "continue";
1353
1409
  });
1354
- NodeHandler.register(ts12.SyntaxKind.BreakStatement, (node) => {
1410
+ NodeHandler.register(ts13.SyntaxKind.BreakStatement, (node) => {
1355
1411
  if (node.label) {
1356
- if (!ts12.isBlock(node.parent))
1412
+ if (!ts13.isBlock(node.parent))
1357
1413
  throw "A break statement with a label must be in a block";
1358
1414
  return `${NodeHandler.handle(node.label)}Broke = 1
1359
1415
  break`;
1360
1416
  }
1361
1417
  return "break";
1362
1418
  });
1363
- NodeHandler.register(ts12.SyntaxKind.ReturnStatement, (node) => {
1419
+ NodeHandler.register(ts13.SyntaxKind.ReturnStatement, (node) => {
1364
1420
  if (!node.expression) {
1365
- if (ts12.findAncestor(node, (n) => ts12.isConstructorDeclaration(n)) && !ts12.findAncestor(node, (n) => ts12.isFunctionLike(n))) {
1421
+ if (ts13.findAncestor(node, (n) => ts13.isConstructorDeclaration(n)) && !ts13.findAncestor(node, (n) => ts13.isFunctionLike(n))) {
1366
1422
  return "return self";
1367
1423
  }
1368
1424
  return "return";
1369
1425
  }
1370
1426
  return `return ${NodeHandler.handle(node.expression)}`;
1371
1427
  });
1372
- NodeHandler.register(ts12.SyntaxKind.LabeledStatement, (node) => {
1428
+ NodeHandler.register(ts13.SyntaxKind.LabeledStatement, (node) => {
1373
1429
  return `${NodeHandler.handle(node.label)}Broke = 0
1374
1430
  ${NodeHandler.handle(node.statement)}`;
1375
1431
  });
1376
1432
 
1377
1433
  // src/visitors/variables.ts
1378
- import ts13 from "typescript";
1379
- function handleVariableDeclaration(node, ctx) {
1434
+ import ts14 from "typescript";
1435
+ function handleVariableDeclaration(node) {
1380
1436
  const left = NodeHandler.handle(node.name);
1381
1437
  const initializerType = node.initializer ? checker.getTypeAtLocation(node.initializer) : undefined;
1382
- if (ts13.isPropertyDeclaration(node) && initializerType?.flags === ts13.TypeFlags.Object && !node.modifiers?.some((mod) => mod.kind === ts13.SyntaxKind.StaticKeyword) && !ts13.isFunctionLike(node.initializer)) {
1438
+ if (ts14.isPropertyDeclaration(node) && initializerType?.flags === ts14.TypeFlags.Object && !node.modifiers?.some((mod) => mod.kind === ts14.SyntaxKind.StaticKeyword) && !ts14.isFunctionLike(node.initializer)) {
1383
1439
  console.warn(`You shouldn't initialize '${left}' with an Array or an Object because in GreyScript, every instantiation refers to the same '${left}' variable.
1384
1440
  Initialize them in the constructor instead`);
1385
1441
  }
1386
1442
  let right = node.initializer ? NodeHandler.handle(node.initializer) || "null" : "null";
1387
- if (right != "null" && nodeIsFunctionReference(node.initializer, initializerType)) {
1443
+ if (right !== "null" && nodeIsFunctionReference(node.initializer, initializerType)) {
1388
1444
  right = asRef(right);
1389
1445
  }
1390
1446
  return `${left} = ${right}`;
1391
1447
  }
1392
- NodeHandler.register(ts13.SyntaxKind.VariableDeclarationList, (node, ctx) => {
1393
- return node.declarations.map((decl) => handleVariableDeclaration(decl, ctx)).join(`
1448
+ NodeHandler.register(ts14.SyntaxKind.VariableDeclarationList, (node) => {
1449
+ return node.declarations.map((decl) => handleVariableDeclaration(decl)).join(`
1394
1450
  `);
1395
1451
  });
1396
- NodeHandler.register(ts13.SyntaxKind.VariableStatement, (node, ctx) => {
1397
- if (node.modifiers?.some((modifier) => modifier.kind === ts13.SyntaxKind.DeclareKeyword))
1452
+ NodeHandler.register(ts14.SyntaxKind.VariableStatement, (node) => {
1453
+ if (node.modifiers?.some((modifier) => modifier.kind === ts14.SyntaxKind.DeclareKeyword))
1398
1454
  return "";
1399
1455
  return NodeHandler.handle(node.declarationList);
1400
1456
  });
1401
- NodeHandler.register(ts13.SyntaxKind.VariableDeclaration, handleVariableDeclaration);
1402
- NodeHandler.register(ts13.SyntaxKind.PropertyDeclaration, handleVariableDeclaration);
1403
- NodeHandler.register(ts13.SyntaxKind.EnumDeclaration, (node) => {
1457
+ NodeHandler.register(ts14.SyntaxKind.VariableDeclaration, handleVariableDeclaration);
1458
+ NodeHandler.register(ts14.SyntaxKind.PropertyDeclaration, handleVariableDeclaration);
1459
+ NodeHandler.register(ts14.SyntaxKind.EnumDeclaration, (node) => {
1404
1460
  const members = [];
1405
1461
  function addMember(name, initializer) {
1406
1462
  members.push(`${name}: ${initializer}`);
1407
- if (isNaN(+initializer))
1463
+ if (Number.isNaN(+initializer))
1408
1464
  return;
1409
1465
  members.push(`${initializer}: ${name}`);
1410
1466
  }
1411
1467
  node.members.forEach((member, index) => {
1412
1468
  let name = NodeHandler.handle(member.name);
1413
- if (!ts13.isStringLiteral(member.name))
1469
+ if (!ts14.isStringLiteral(member.name))
1414
1470
  name = `"${name}"`;
1415
1471
  if (member.initializer) {
1416
1472
  addMember(name, NodeHandler.handle(member.initializer));
@@ -1426,51 +1482,42 @@ NodeHandler.register(ts13.SyntaxKind.EnumDeclaration, (node) => {
1426
1482
  return `${node.name.text} = { ${members.join(", ")} }`;
1427
1483
  });
1428
1484
 
1429
- // src/call_transformers/array.ts
1430
- CallTransformer.register("Array.slice", (name, args) => {
1431
- return name.slice(0, name.lastIndexOf(".")) + `[${args[0] ?? ""}:${args[1] ?? ""}]`;
1432
- });
1433
- CallTransformer.register("Array.toString", (name) => {
1434
- const arrayName = name.slice(0, name.lastIndexOf("."));
1435
- return `str(${arrayName})`;
1436
- });
1437
-
1438
1485
  // src/call_transformers/object.ts
1439
- CallTransformer.register("ObjectConstructor.hasOwn", (name, args) => {
1486
+ CallTransformer.register("ObjectConstructor.hasOwn", (_name, args) => {
1440
1487
  if (args.length < 2)
1441
1488
  throw "Invalid argument count";
1442
1489
  return `${args[0]}.hasIndex(${args[1]})`;
1443
1490
  });
1444
- CallTransformer.register("ObjectConstructor.assign", (name, args) => {
1491
+ CallTransformer.register("ObjectConstructor.assign", (_name, args) => {
1445
1492
  if (args.length < 2)
1446
1493
  throw "Invalid argument count";
1447
1494
  return callUtilFunction("assign_objects", args.join(","));
1448
1495
  });
1449
- CallTransformer.register("ObjectConstructor.keys", (name, args) => {
1496
+ CallTransformer.register("ObjectConstructor.keys", (_name, args) => {
1450
1497
  return `${args[0]}.indexes`;
1451
1498
  });
1452
- CallTransformer.register("ObjectConstructor.values", (name, args) => {
1499
+ CallTransformer.register("ObjectConstructor.values", (_name, args) => {
1453
1500
  return `${args[0]}.values`;
1454
1501
  });
1455
- CallTransformer.register("ObjectConstructor.sum", (name, args) => {
1502
+ CallTransformer.register("ObjectConstructor.sum", (_name, args) => {
1456
1503
  return `${args[0]}.sum`;
1457
1504
  });
1458
- CallTransformer.register("ObjectConstructor.shuffle", (name, args) => {
1505
+ CallTransformer.register("ObjectConstructor.shuffle", (_name, args) => {
1459
1506
  return `${args[0]}.shuffle`;
1460
1507
  });
1461
- CallTransformer.register("ObjectConstructor.replace", (name, args) => {
1508
+ CallTransformer.register("ObjectConstructor.replace", (_name, args) => {
1462
1509
  return `${args[0]}.replace(${args.slice(1).join(",")})`;
1463
1510
  });
1464
- CallTransformer.register("ObjectConstructor.remove", (name, args) => {
1511
+ CallTransformer.register("ObjectConstructor.remove", (_name, args) => {
1465
1512
  return `${args[0]}.remove(${args[1]})`;
1466
1513
  });
1467
- CallTransformer.register("ObjectConstructor.shift", (name, args) => {
1514
+ CallTransformer.register("ObjectConstructor.shift", (_name, args) => {
1468
1515
  return `${args[0]}.pull`;
1469
1516
  });
1470
- CallTransformer.register("ObjectConstructor.size", (name, args) => {
1517
+ CallTransformer.register("ObjectConstructor.size", (_name, args) => {
1471
1518
  return `${args[0]}.len`;
1472
1519
  });
1473
- CallTransformer.register("ObjectConstructor.indexOf", (name, args) => {
1520
+ CallTransformer.register("ObjectConstructor.indexOf", (_name, args) => {
1474
1521
  return `${args[0]}.indexOf(${args[1]})`;
1475
1522
  });
1476
1523
  CallTransformer.register("Object.toString", (name) => {
@@ -1478,14 +1525,6 @@ CallTransformer.register("Object.toString", (name) => {
1478
1525
  return `str(${objectName})`;
1479
1526
  });
1480
1527
 
1481
- // src/call_transformers/string.ts
1482
- CallTransformer.register("String.slice", (name, args) => {
1483
- return name.slice(0, name.lastIndexOf(".")) + `[${args[0] ?? ""}:${args[1] ?? ""}]`;
1484
- });
1485
- CallTransformer.register("String.toString", (name) => {
1486
- return name.slice(0, name.lastIndexOf("."));
1487
- });
1488
-
1489
1528
  // src/transpiler.ts
1490
1529
  var program;
1491
1530
  var checker;
@@ -1628,6 +1667,12 @@ var extensionFunctions = {
1628
1667
  "end function"
1629
1668
  ].join(`
1630
1669
  `),
1670
+ "Array.toString": `list.toString = function
1671
+ return str(self)
1672
+ end function`,
1673
+ "Array.slice": `list.slice = function(a, b)
1674
+ return self[a:b]
1675
+ end function`,
1631
1676
  "String.startsWith": [
1632
1677
  "string.startsWith = function(search, pos = 0)",
1633
1678
  "\tif pos < 0 then pos = 0",
@@ -1670,6 +1715,12 @@ var extensionFunctions = {
1670
1715
  "end function"
1671
1716
  ].join(`
1672
1717
  `),
1718
+ "String.toString": `string.toString = function
1719
+ return str(self)
1720
+ end function`,
1721
+ "String.slice": `string.slice = function(a, b)
1722
+ return self[a:b]
1723
+ end function`,
1673
1724
  "Number.toFixed": [
1674
1725
  "number.toFixed = function(digits = 0)",
1675
1726
  "\tdigits = floor(digits)",
@@ -1691,23 +1742,120 @@ var extensionFunctions = {
1691
1742
  "end function"
1692
1743
  ].join(`
1693
1744
  `),
1694
- "Math.min": [
1695
- "Math.min = function(numbers)",
1696
- "\tcurr_min = null",
1697
- "\tfor num in numbers",
1698
- "\t\tif curr_min == null or num < curr_min then curr_min = num",
1745
+ "Number.toString": `number.toString = function
1746
+ return str(self)
1747
+ end function`,
1748
+ "Function.toString": `funcRef.toString = function
1749
+ return str(@self)
1750
+ end function`
1751
+ };
1752
+ var globalObjects = {
1753
+ MapConstructor: [
1754
+ "Map = {}",
1755
+ "Map.constructor = function(entries)",
1756
+ "\tself.data = {}",
1757
+ "\tif not entries then return self",
1758
+ "\tfor entry in entries",
1759
+ "\t\tself.data[entry[0]] = entry[1]",
1699
1760
  "\tend for",
1700
- "\treturn curr_min",
1761
+ "\treturn self",
1762
+ "end function",
1763
+ "Map.clear = function",
1764
+ "\tfor key in self.data.indexes",
1765
+ "\t\tself.data.remove(@key)",
1766
+ "\tend for",
1767
+ "end function",
1768
+ "Map.delete = function(key)",
1769
+ "\treturn self.data.remove(key)",
1770
+ "end function",
1771
+ "Map.forEach = function(callback)",
1772
+ "\tfor item in self.data",
1773
+ "\t\tcallback(@item.value, @item.key, self)",
1774
+ "\tend for",
1775
+ "end function",
1776
+ "Map.get = function(key)",
1777
+ "\tif not self.data.hasIndex(@key) then retun null",
1778
+ "\treturn self.data[@key]",
1779
+ "end function",
1780
+ "Map.has = function(key)",
1781
+ "\treturn self.data.hasIndex(@key)",
1782
+ "end function",
1783
+ "Map.set = function(key, value)",
1784
+ "\tself.data[@key] = @value",
1785
+ "\treturn self",
1786
+ "end function",
1787
+ "Map.entries = function",
1788
+ "\tentries = []",
1789
+ "\tfor item in self.data",
1790
+ "\t\tentries.push([@item.key, @item.value])",
1791
+ "\tend for",
1792
+ "\treturn entries",
1793
+ "end function",
1794
+ "Map.keys = function",
1795
+ "\treturn self.data.indexes",
1796
+ "end function",
1797
+ "Map.values = function",
1798
+ "\treturn self.data.values",
1701
1799
  "end function"
1702
1800
  ].join(`
1703
1801
  `),
1704
- "Math.max": [
1802
+ SetConstructor: [
1803
+ "Set = {}",
1804
+ "Set.constructor = function(values)",
1805
+ "\tself.data = {}",
1806
+ "\tif not values then return self",
1807
+ "\tfor v in values",
1808
+ "\t\tself.data[@v] = 1",
1809
+ "\tend for",
1810
+ "\treturn self",
1811
+ "end function",
1812
+ "Set.add = function(value)",
1813
+ "\tself.data[@value] = 1",
1814
+ "\treturn self",
1815
+ "end function",
1816
+ "Set.clear = function",
1817
+ "\tfor key in self.data.indexes",
1818
+ "\t\tself.data.remove(@key)",
1819
+ "\tend for",
1820
+ "end function",
1821
+ "Set.delete = function(key)",
1822
+ "\treturn self.data.remove(key)",
1823
+ "end function",
1824
+ "Set.forEach = function(callback)",
1825
+ "\tfor key in self.data.indexes",
1826
+ "\t\tcallback(@key, self)",
1827
+ "\tend for",
1828
+ "end function",
1829
+ "Set.has = function(key)",
1830
+ "\treturn self.data.hasIndex(@key)",
1831
+ "end function",
1832
+ "Set.values = function",
1833
+ "\treturn self.data.indexes",
1834
+ "end function"
1835
+ ].join(`
1836
+ `),
1837
+ Math: [
1838
+ 'Math = { "PI": @pi, "abs": @abs, "acos": @acos, "asin": @asin, "atan": @atan, "ceil": @ceil, "floor": @floor, "cos": @cos, "sin": @sin, "tan": @tan, "sqrt": @sqrt, "sign": @sign, "round": @round, "random": @rnd, "log": @log }',
1705
1839
  "Math.max = function(numbers)",
1706
1840
  "\tcurr_max = null",
1707
1841
  "\tfor num in numbers",
1708
1842
  "\t\tif curr_max == null or num > curr_max then curr_max = num",
1709
1843
  "\tend for",
1710
1844
  "\treturn curr_max",
1845
+ "end function",
1846
+ "Math.min = function(numbers)",
1847
+ "\tcurr_min = null",
1848
+ "\tfor num in numbers",
1849
+ "\t\tif curr_min == null or num < curr_min then curr_min = num",
1850
+ "\tend for",
1851
+ "\treturn curr_min",
1852
+ "end function"
1853
+ ].join(`
1854
+ `),
1855
+ Console: [
1856
+ 'console = { "clear": @clear_screen }',
1857
+ "console.log = function(data)",
1858
+ '\tprint(data.join(", "))',
1711
1859
  "end function"
1712
1860
  ].join(`
1713
1861
  `)
@@ -1777,19 +1925,19 @@ var utilFunctions = {
1777
1925
  ].join(`
1778
1926
  `),
1779
1927
  nullish_coalescing_op: `nullish_coalescing_op = function(left, right)
1780
- if left == null then return @right
1928
+ if @left == null then return @right
1781
1929
  return @left
1782
1930
  end function`,
1783
1931
  or_op: `or_op = function(left, right)
1784
- if not left then return @right
1932
+ if not @left then return @right
1785
1933
  return @left
1786
1934
  end function`,
1787
1935
  is_type: `is_type = function(value, type)
1788
- return typeof(value) == type
1936
+ return typeof(@value) == type
1789
1937
  end function`,
1790
1938
  conditional_expr: `conditional_expr = function(cond, when_true, when_false)
1791
- if cond then return when_true
1792
- return when_false
1939
+ if cond then return @when_true
1940
+ return @when_false
1793
1941
  end function`
1794
1942
  };
1795
1943
  var anonFunctionsCreated = 0;
@@ -1797,9 +1945,12 @@ function createAnonFunction(body, params, insertToUtils = true) {
1797
1945
  const defaultParams = new Array(3).fill(0).map((_, i) => `param${i}`);
1798
1946
  const nextName = `func_${anonFunctionsCreated}`;
1799
1947
  const paramString = Object.assign(defaultParams, params).join(",");
1800
- const result = `${nextName} = function(${paramString})
1801
- ${body}
1802
- end function`;
1948
+ const result = [
1949
+ `${nextName} = function(${paramString})`,
1950
+ ...body ? [body] : [],
1951
+ `end function`
1952
+ ].join(`
1953
+ `);
1803
1954
  anonFunctionsCreated++;
1804
1955
  if (insertToUtils)
1805
1956
  utilitiesToInsert.set(nextName, result);
@@ -1813,7 +1964,9 @@ function createContext(currentFileName = "file.ts") {
1813
1964
  namespaceImports: {},
1814
1965
  visitedFiles: new Set,
1815
1966
  output: [],
1816
- extraOutput: new Map
1967
+ extraOutput: new Map,
1968
+ bindingElements: {},
1969
+ parameterProperties: []
1817
1970
  };
1818
1971
  }
1819
1972
  function transpileProgram(entryFileRelativePath) {
@@ -1825,16 +1978,16 @@ function transpileProgram(entryFileRelativePath) {
1825
1978
  process.exit(1);
1826
1979
  }
1827
1980
  let start = Date.now();
1828
- const tsconfigPath = findProjectRoot(process.cwd(), "tsconfig.json") + "/tsconfig.json";
1829
- const res = ts14.readConfigFile(tsconfigPath, ts14.sys.readFile);
1830
- const parsed = ts14.parseJsonConfigFileContent(res.config, ts14.sys, path5.dirname(tsconfigPath));
1981
+ const tsconfigPath = `${findProjectRoot(process.cwd(), "tsconfig.json")}/tsconfig.json`;
1982
+ const res = ts15.readConfigFile(tsconfigPath, ts15.sys.readFile);
1983
+ const parsed = ts15.parseJsonConfigFileContent(res.config, ts15.sys, path5.dirname(tsconfigPath));
1831
1984
  if (!parsed.options.types)
1832
1985
  parsed.options.types = [];
1833
1986
  if (!parsed.options.types.includes("@grey-ts/types")) {
1834
1987
  parsed.options.types.push("@grey-ts/types");
1835
1988
  }
1836
1989
  parsed.options.noLib = true;
1837
- program = ts14.createProgram({
1990
+ program = ts15.createProgram({
1838
1991
  rootNames: parsed.fileNames,
1839
1992
  options: parsed.options
1840
1993
  });
@@ -1912,7 +2065,7 @@ if (command === "transpile") {
1912
2065
  content = "";
1913
2066
  continue;
1914
2067
  }
1915
- content += statement + `
2068
+ content += `${statement}
1916
2069
  `;
1917
2070
  }
1918
2071
  if (content.length)