@grey-ts/transpiler 1.2.0 → 1.4.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 +487 -430
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -25,7 +25,7 @@ class NodeHandler {
25
25
  if (!handler) {
26
26
  console.log(`Unsupported syntax ${ts.SyntaxKind[node.kind]} (kind ${node.kind}) was not transpiled: ${node.getText()}`);
27
27
  this.printLineAndCol(node);
28
- return "null";
28
+ return ts.isBlock(node.parent) || ts.isSourceFile(node.parent) ? "" : "null";
29
29
  }
30
30
  try {
31
31
  const result = handler(node, this.transpileContext);
@@ -33,7 +33,7 @@ class NodeHandler {
33
33
  } catch (error) {
34
34
  console.error(error);
35
35
  this.printLineAndCol(node);
36
- return "null";
36
+ return ts.isBlock(node.parent) || ts.isSourceFile(node.parent) ? "" : "null";
37
37
  }
38
38
  }
39
39
  static printLineAndCol(node) {
@@ -149,7 +149,6 @@ var apiNameMap = {
149
149
  "GreyHack.programPath": "program_path",
150
150
  "GreyHack.resetCtfPassword": "reset_ctf_password",
151
151
  "GreyHack.getType": "typeof",
152
- "GreyHack.isType": "is_type",
153
152
  "GreyHack.userBankNumber": "user_bank_number",
154
153
  "GreyHack.userInput": "user_input",
155
154
  "GreyHack.userMailAddress": "user_mail_address",
@@ -215,9 +214,11 @@ var apiNameMap = {
215
214
  "String.length": "len",
216
215
  "String.toLowerCase": "lower",
217
216
  "String.toUpperCase": "upper",
217
+ "String.repeat": "repeatSelf",
218
218
  "Object.size": "len",
219
219
  "Array.length": "len",
220
- "Array.shift": "pull"
220
+ "Array.shift": "pull",
221
+ "Array.push": "push_many"
221
222
  };
222
223
  var propertyAccessReplacements = {
223
224
  "Math.PI": "pi",
@@ -384,9 +385,28 @@ function findProjectRoot(dir, fileToSearch = "package.json") {
384
385
  return dir;
385
386
  }
386
387
  function callUtilFunction(functionName, ...params) {
387
- calledUtilFunctions.add(functionName);
388
+ utilitiesToInsert.set(functionName, utilFunctions[functionName]);
388
389
  return `${functionName}(${params.join(", ")})`;
389
390
  }
391
+ var assignmentOperators = new Set([
392
+ "=",
393
+ "??=",
394
+ "||=",
395
+ "-=",
396
+ "+="
397
+ ]);
398
+ function valueIsBeingAssignedToNode(node) {
399
+ if (ts3.hasOnlyExpressionInitializer(node.parent) && node === node.parent.name)
400
+ return true;
401
+ const assignAncestor = ts3.findAncestor(node, (ancestor) => {
402
+ if (ancestor.parent && ts3.isBinaryExpression(ancestor.parent) && ancestor === ancestor.parent.left) {
403
+ const token = ts3.tokenToString(ancestor.parent.operatorToken.kind) || ancestor.parent.operatorToken.getText();
404
+ return assignmentOperators.has(token);
405
+ }
406
+ return false;
407
+ });
408
+ return !!assignAncestor;
409
+ }
390
410
 
391
411
  // src/visitors/assignments.ts
392
412
  import ts4 from "typescript";
@@ -495,7 +515,7 @@ end function`;
495
515
  });
496
516
 
497
517
  // src/visitors/expressions.ts
498
- import ts8 from "typescript";
518
+ import ts7 from "typescript";
499
519
 
500
520
  // src/call_transformers/callTransformer.ts
501
521
  import path2 from "node:path";
@@ -508,6 +528,13 @@ class CallTransformer {
508
528
  this.handlers.set(symbolFullName, handler);
509
529
  }
510
530
  static handle(symbolFullName, functionName, callArgs, node, ctx) {
531
+ if (symbolFullName in extensionFunctions) {
532
+ if (symbolFullName.startsWith("Math"))
533
+ utilitiesToInsert.set("create_math", "Math = {}");
534
+ utilitiesToInsert.set(symbolFullName, extensionFunctions[symbolFullName]);
535
+ const params = callArgs.length ? `(${callArgs.join(",")})` : "";
536
+ return `${functionName}${params}`;
537
+ }
511
538
  const handler = this.handlers.get(symbolFullName);
512
539
  if (!handler)
513
540
  return null;
@@ -522,12 +549,6 @@ CallTransformer.register("Function.toString", (name) => {
522
549
  const func = name.slice(0, name.lastIndexOf("."));
523
550
  return `str(@${func})`;
524
551
  });
525
- CallTransformer.register("Math.min", (name, args) => {
526
- return callUtilFunction("math_min", `${args.join(",")}`);
527
- });
528
- CallTransformer.register("Math.max", (name, args) => {
529
- return callUtilFunction("math_max", `${args.join(",")}`);
530
- });
531
552
  CallTransformer.register("GreyHack.include", (name, args, node, ctx) => {
532
553
  if (!node.arguments.length)
533
554
  return "";
@@ -541,6 +562,9 @@ CallTransformer.register("GreyHack.include", (name, args, node, ctx) => {
541
562
  }
542
563
  return "";
543
564
  });
565
+ CallTransformer.register("GreyHack.isType", (name, args) => {
566
+ return callUtilFunction("is_type", args.join(","));
567
+ });
544
568
  CallTransformer.register("Boolean", (name, args) => {
545
569
  if (!args.length)
546
570
  return "0";
@@ -557,129 +581,12 @@ CallTransformer.register("String", (name, args) => {
557
581
  return `str(${args[0]})`;
558
582
  });
559
583
 
560
- // src/visitors/objects.ts
561
- import ts7 from "typescript";
562
- var assignmentOperators = new Set([
563
- "=",
564
- "??=",
565
- "||=",
566
- "-=",
567
- "+="
568
- ]);
569
- function valueIsBeingAssignedToNode(node) {
570
- const assignAncestor = ts7.findAncestor(node, (ancestor) => {
571
- if (ancestor.parent && ts7.isBinaryExpression(ancestor.parent) && ancestor === ancestor.parent.left) {
572
- const token = ts7.tokenToString(ancestor.parent.operatorToken.kind) || ancestor.parent.operatorToken.getText();
573
- return assignmentOperators.has(token);
574
- }
575
- return false;
576
- });
577
- return !!assignAncestor;
578
- }
579
- NodeHandler.register(ts7.SyntaxKind.PropertyAccessExpression, (node, ctx) => {
580
- const left = NodeHandler.handle(node.expression);
581
- let right = NodeHandler.handle(node.name);
582
- right = replaceIdentifier(right, checker.getTypeAtLocation(node.expression), right);
583
- const nodeSymbol = checker.getSymbolAtLocation(node);
584
- if (ctx.namespaceImports[ctx.currentFilePath]?.has(left))
585
- return right;
586
- let getSafely = !!node.questionDotToken && !ts7.isNonNullExpression(node.parent);
587
- const rightType = checker.getTypeAtLocation(node.name);
588
- if (rightType.isUnion()) {
589
- const hasUndefined = rightType.types.some((t) => t.flags === ts7.TypeFlags.Undefined);
590
- if (hasUndefined)
591
- getSafely = true;
592
- }
593
- if (!valueIsBeingAssignedToNode(node) && getSafely)
594
- return callUtilFunction("get_property", left, `"${right}"`);
595
- let output = `${left}.${right}`;
596
- output = replacePropertyAccess(output, nodeSymbol);
597
- if (nodeIsFunctionReference(node))
598
- output = asRef(output);
599
- return output;
600
- });
601
- NodeHandler.register(ts7.SyntaxKind.ElementAccessExpression, (node, ctx) => {
602
- const left = NodeHandler.handle(node.expression);
603
- let right;
604
- if (ts7.isStringLiteral(node.argumentExpression)) {
605
- const leftType = checker.getTypeAtLocation(node.expression);
606
- right = `"${replaceIdentifier(node.argumentExpression.text, leftType, node.argumentExpression.text)}"`;
607
- } else {
608
- right = NodeHandler.handle(node.argumentExpression);
609
- }
610
- if (!valueIsBeingAssignedToNode(node) && !ts7.isNumericLiteral(node.argumentExpression)) {
611
- return callUtilFunction("get_property", left, `${right}`);
612
- }
613
- return `${left}[${right}]`;
614
- });
615
- function handleObjectLiteralExpression(node, ctx, currObj, outObjects, funcs) {
616
- currObj ??= [];
617
- outObjects ??= [];
618
- funcs ??= [];
619
- const objectName = ts7.hasOnlyExpressionInitializer(node.parent) ? NodeHandler.handle(node.parent.name) : ts7.isBinaryExpression(node.parent) && node === node.parent.right ? NodeHandler.handle(node.parent.left) : "";
620
- function pushObj() {
621
- if (!currObj?.length)
622
- return "";
623
- const res = currObj.filter((s) => s != "").join(",");
624
- if (res) {
625
- outObjects?.push(`{ ${res} }`);
626
- }
627
- currObj.length = 0;
628
- return res;
629
- }
630
- for (const item of node.properties) {
631
- if (ts7.isFunctionLike(item)) {
632
- if (!objectName)
633
- throw "You can't have method declarations inside an object that is not being assigned to a variable";
634
- funcs.push(`${objectName}.${NodeHandler.handle(item)}`);
635
- continue;
636
- }
637
- if (ts7.isPropertyAssignment(item) && ts7.isFunctionLike(item.initializer)) {
638
- if (!objectName)
639
- throw "You can't have method declarations inside an object that is not being assigned to a variable";
640
- funcs.push(`${objectName}.${NodeHandler.handle(item.name)} = ${NodeHandler.handle(item.initializer)}`);
641
- continue;
642
- }
643
- if (ts7.isSpreadAssignment(item)) {
644
- if (ts7.isObjectLiteralExpression(item.expression)) {
645
- handleObjectLiteralExpression(item.expression, ctx, currObj, outObjects);
646
- continue;
647
- }
648
- if (ts7.isIdentifier(item.expression)) {
649
- pushObj();
650
- outObjects.push(NodeHandler.handle(item.expression));
651
- continue;
652
- }
653
- if (ts7.isArrayLiteralExpression(item.expression)) {
654
- pushObj();
655
- outObjects.push(NodeHandler.handle(item.expression));
656
- continue;
657
- }
658
- }
659
- currObj.push(NodeHandler.handle(item));
660
- }
661
- pushObj();
662
- if (!outObjects.length)
663
- outObjects.push("{}");
664
- let output = outObjects[0];
665
- if (outObjects.length > 1) {
666
- output = callUtilFunction("assign_objects", output, `[${outObjects.slice(1).join(",")}]`);
667
- }
668
- if (funcs.length) {
669
- output += `
670
- ` + funcs.join(`
671
- `);
672
- }
673
- return output;
674
- }
675
- NodeHandler.register(ts7.SyntaxKind.ObjectLiteralExpression, handleObjectLiteralExpression);
676
-
677
584
  // src/visitors/expressions.ts
678
585
  function hasRestParam(params) {
679
586
  if (!params.length)
680
587
  return false;
681
588
  const lastParam = params[params.length - 1];
682
- return !!(lastParam.valueDeclaration && ts8.isParameter(lastParam.valueDeclaration) && lastParam.valueDeclaration.dotDotDotToken);
589
+ return !!(lastParam.valueDeclaration && ts7.isParameter(lastParam.valueDeclaration) && lastParam.valueDeclaration.dotDotDotToken);
683
590
  }
684
591
  function handleCallArgs(callNode, ctx) {
685
592
  const args = callNode.arguments;
@@ -703,11 +610,11 @@ function handleCallArgs(callNode, ctx) {
703
610
  }
704
611
  }
705
612
  for (const arg of args) {
706
- if (!ts8.isSpreadElement(arg)) {
613
+ if (!ts7.isSpreadElement(arg)) {
707
614
  pushArgs(false, NodeHandler.handle(arg));
708
615
  continue;
709
616
  }
710
- if (ts8.isArrayLiteralExpression(arg.expression)) {
617
+ if (ts7.isArrayLiteralExpression(arg.expression)) {
711
618
  const arrayItems = [];
712
619
  const outArrs = [];
713
620
  handleArrayLiteralExpression(arg.expression, ctx, arrayItems, outArrs);
@@ -759,7 +666,7 @@ function handleCallArgs(callNode, ctx) {
759
666
  result.push("[]");
760
667
  return result;
761
668
  }
762
- NodeHandler.register(ts8.SyntaxKind.CallExpression, (node, ctx) => {
669
+ NodeHandler.register(ts7.SyntaxKind.CallExpression, (node, ctx) => {
763
670
  const args = handleCallArgs(node, ctx);
764
671
  let name = NodeHandler.handle(node.expression);
765
672
  const type = checker.getTypeAtLocation(node.expression);
@@ -771,14 +678,11 @@ NodeHandler.register(ts8.SyntaxKind.CallExpression, (node, ctx) => {
771
678
  const transformed = CallTransformer.handle(symbolFullName, name, args, node, ctx);
772
679
  if (transformed !== null)
773
680
  return transformed;
774
- if (name === "is_type" && !calledUtilFunctions.has("is_type")) {
775
- calledUtilFunctions.add("is_type");
776
- }
777
681
  if (!args.length)
778
682
  return name;
779
683
  return `${name}(${args.join(", ")})`;
780
684
  });
781
- NodeHandler.register(ts8.SyntaxKind.NewExpression, (node, ctx) => {
685
+ NodeHandler.register(ts7.SyntaxKind.NewExpression, (node, ctx) => {
782
686
  const args = handleCallArgs(node, ctx);
783
687
  let output = `(new ${NodeHandler.handle(node.expression)}).constructor`;
784
688
  if (args.length)
@@ -788,12 +692,12 @@ NodeHandler.register(ts8.SyntaxKind.NewExpression, (node, ctx) => {
788
692
  function shouldHaveOuterPrefix(node, operator) {
789
693
  if (!assignmentOperators.has(operator))
790
694
  return false;
791
- if (!ts8.isIdentifier(node.left))
695
+ if (!ts7.isIdentifier(node.left))
792
696
  return false;
793
- const functionAncestor = ts8.findAncestor(node.parent, (n) => ts8.isFunctionLike(n));
697
+ const functionAncestor = ts7.findAncestor(node.parent, (n) => ts7.isFunctionLike(n));
794
698
  if (!functionAncestor)
795
699
  return false;
796
- if (!ts8.findAncestor(functionAncestor.parent, (n) => ts8.isFunctionLike(n)))
700
+ if (!ts7.findAncestor(functionAncestor.parent, (n) => ts7.isFunctionLike(n)))
797
701
  return false;
798
702
  const leftSymbol = checker.getSymbolAtLocation(node.left);
799
703
  if (!leftSymbol?.valueDeclaration)
@@ -803,26 +707,26 @@ function shouldHaveOuterPrefix(node, operator) {
803
707
  function isAssignmentChain(node, operator) {
804
708
  if (!assignmentOperators.has(operator))
805
709
  return false;
806
- if (ts8.isBinaryExpression(node.right) && assignmentOperators.has(ts8.tokenToString(node.right.operatorToken.kind) || ""))
710
+ if (ts7.isBinaryExpression(node.right) && assignmentOperators.has(ts7.tokenToString(node.right.operatorToken.kind) || ""))
807
711
  return true;
808
- if (ts8.hasOnlyExpressionInitializer(node.parent))
712
+ if (ts7.hasOnlyExpressionInitializer(node.parent))
809
713
  return true;
810
714
  return false;
811
715
  }
812
- NodeHandler.register(ts8.SyntaxKind.BinaryExpression, (node) => {
716
+ NodeHandler.register(ts7.SyntaxKind.BinaryExpression, (node) => {
813
717
  let operatorToken = getOperatorToken(node.operatorToken) || node.operatorToken.getText();
814
718
  if (isAssignmentChain(node, operatorToken))
815
719
  throw `Assignment chaining is not supported`;
816
720
  let right = NodeHandler.handle(node.right);
817
721
  if (nodeIsFunctionReference(node.right))
818
722
  right = asRef(right);
819
- if (ts8.isPropertyAccessExpression(node.left)) {
723
+ if (ts7.isPropertyAccessExpression(node.left)) {
820
724
  const leftType = checker.getTypeAtLocation(node.left.expression);
821
725
  const symbol = leftType.getProperty(node.left.name.text);
822
- if (symbol?.declarations?.some((decl) => ts8.isSetAccessor(decl))) {
726
+ if (symbol?.declarations?.some((decl) => ts7.isSetAccessor(decl))) {
823
727
  const objName = NodeHandler.handle(node.left.expression);
824
728
  const key = node.left.name.text;
825
- if (operatorToken !== "=" && symbol.declarations.some((decl) => ts8.isGetAccessor(decl)))
729
+ if (operatorToken !== "=" && symbol.declarations.some((decl) => ts7.isGetAccessor(decl)))
826
730
  throw `Can't handle '${operatorToken}' because '${objName}' doesn't have a getter '${key}'`;
827
731
  if (operatorToken === "+=" || operatorToken === "-=") {
828
732
  right = `${objName}.${key} ${operatorToken[0]} ${right}`;
@@ -837,22 +741,12 @@ NodeHandler.register(ts8.SyntaxKind.BinaryExpression, (node) => {
837
741
  left = "outer." + left;
838
742
  if (nodeIsFunctionReference(node.left))
839
743
  left = asRef(left);
840
- if (operatorToken === "or" && ts8.hasOnlyExpressionInitializer(node.parent)) {
744
+ if (operatorToken === "or" && ts7.hasOnlyExpressionInitializer(node.parent)) {
841
745
  return callUtilFunction("or_op", left, right);
842
746
  }
843
- if (operatorToken === "instanceof") {
844
- const rightSymbol = checker.getSymbolAtLocation(node.right);
845
- const classIdMember = rightSymbol?.members?.get(ts8.escapeLeadingUnderscores("classID"));
846
- if (!classIdMember) {
847
- throw `Can't handle this 'instanceof' operator because '${right}' doesn't have a 'classID' member, which is needed in GreyScript to check a type`;
848
- }
849
- const declaration = classIdMember.valueDeclaration;
850
- if (!declaration || !("initializer" in declaration) || !declaration.initializer) {
851
- throw `The 'classID' property of '${right}' isn't initialized`;
852
- }
853
- return `${left}.classID == typeof(${right})`;
854
- }
855
747
  switch (operatorToken) {
748
+ case "instanceof":
749
+ return callUtilFunction("instance_of", left, right);
856
750
  case "??":
857
751
  return callUtilFunction("nullish_coalescing_op", left, right);
858
752
  case "??=":
@@ -879,41 +773,44 @@ NodeHandler.register(ts8.SyntaxKind.BinaryExpression, (node) => {
879
773
  operatorToken = "^";
880
774
  return `${left} ${operatorToken} ${right}`;
881
775
  });
882
- NodeHandler.register(ts8.SyntaxKind.ParenthesizedExpression, (node) => {
776
+ NodeHandler.register(ts7.SyntaxKind.ParenthesizedExpression, (node) => {
883
777
  return `(${NodeHandler.handle(node.expression)})`;
884
778
  });
885
779
  function handleUnaryExpression(node) {
886
780
  const operand = NodeHandler.handle(node.operand);
887
- const operator = ts8.tokenToString(node.operator);
888
- if (operator === "++")
889
- return `${operand} = ${operand} + 1`;
890
- if (operator === "--")
891
- return `${operand} = ${operand} - 1`;
892
- if (operator === "!") {
893
- if (ts8.isPrefixUnaryExpression(node.parent) && ts8.tokenToString(node.parent.operator) === "!") {
894
- return `(not ${operand})`;
895
- }
896
- return `not ${operand}`;
897
- }
898
- if (operator === "-")
899
- return `-${operand}`;
900
- if (operator === "+")
901
- return `str(${operand}).val()`;
902
- if (operator === "~")
903
- return `bitwise("~", ${operand})`;
904
- throw `Couldn't handle this UnaryExpression: ${node.getText()}`;
781
+ const operator = ts7.tokenToString(node.operator);
782
+ switch (operator) {
783
+ case "++":
784
+ case "--":
785
+ if (ts7.hasOnlyExpressionInitializer(node.parent) || ts7.isBinaryExpression(node.parent))
786
+ throw `Operator ${operator} is not supported for this kind of expression yet`;
787
+ return `${operand} = ${operand} ${operator[0]} 1`;
788
+ case "!":
789
+ if (ts7.isPrefixUnaryExpression(node.parent) && ts7.tokenToString(node.parent.operator) === "!") {
790
+ return `(not ${operand})`;
791
+ }
792
+ return `not ${operand}`;
793
+ case "-":
794
+ return `-${operand}`;
795
+ case "+":
796
+ return `str(${operand}).val`;
797
+ case "~":
798
+ return `bitwise("~", ${operand})`;
799
+ default:
800
+ throw `Couldn't handle this UnaryExpression: ${node.getText()}`;
801
+ }
905
802
  }
906
- NodeHandler.register(ts8.SyntaxKind.PrefixUnaryExpression, handleUnaryExpression);
907
- NodeHandler.register(ts8.SyntaxKind.PostfixUnaryExpression, handleUnaryExpression);
803
+ NodeHandler.register(ts7.SyntaxKind.PrefixUnaryExpression, handleUnaryExpression);
804
+ NodeHandler.register(ts7.SyntaxKind.PostfixUnaryExpression, handleUnaryExpression);
908
805
  function handleArrayLiteralExpression(node, ctx, itemStrings, out) {
909
806
  itemStrings ??= [];
910
807
  out ??= [];
911
808
  for (const item of node.elements) {
912
- if (!ts8.isSpreadElement(item)) {
809
+ if (!ts7.isSpreadElement(item)) {
913
810
  itemStrings.push(NodeHandler.handle(item));
914
811
  continue;
915
812
  }
916
- if (ts8.isArrayLiteralExpression(item.expression)) {
813
+ if (ts7.isArrayLiteralExpression(item.expression)) {
917
814
  handleArrayLiteralExpression(item.expression, ctx, itemStrings, out);
918
815
  continue;
919
816
  }
@@ -923,14 +820,14 @@ function handleArrayLiteralExpression(node, ctx, itemStrings, out) {
923
820
  }
924
821
  out.push(NodeHandler.handle(item.expression));
925
822
  }
926
- if ((!out.length || itemStrings.length) && !ts8.isSpreadElement(node.parent)) {
823
+ if ((!out.length || itemStrings.length) && !ts7.isSpreadElement(node.parent)) {
927
824
  out.push(`[${itemStrings.join(",")}]`);
928
825
  itemStrings.length = 0;
929
826
  }
930
827
  return out.join(" + ");
931
828
  }
932
- NodeHandler.register(ts8.SyntaxKind.ArrayLiteralExpression, handleArrayLiteralExpression);
933
- NodeHandler.register(ts8.SyntaxKind.TemplateExpression, (node) => {
829
+ NodeHandler.register(ts7.SyntaxKind.ArrayLiteralExpression, handleArrayLiteralExpression);
830
+ NodeHandler.register(ts7.SyntaxKind.TemplateExpression, (node) => {
934
831
  const head = NodeHandler.handle(node.head);
935
832
  const strings = [
936
833
  ...head ? [`"${head}"`] : [],
@@ -939,22 +836,22 @@ NodeHandler.register(ts8.SyntaxKind.TemplateExpression, (node) => {
939
836
  const output = strings.join(" + ");
940
837
  return output;
941
838
  });
942
- NodeHandler.register(ts8.SyntaxKind.TemplateHead, (node) => {
839
+ NodeHandler.register(ts7.SyntaxKind.TemplateHead, (node) => {
943
840
  return transformString(node.text);
944
841
  });
945
- NodeHandler.register(ts8.SyntaxKind.TemplateSpan, (node) => {
842
+ NodeHandler.register(ts7.SyntaxKind.TemplateSpan, (node) => {
946
843
  let output = NodeHandler.handle(node.expression);
947
- if (ts8.isBinaryExpression(node.expression))
844
+ if (ts7.isBinaryExpression(node.expression))
948
845
  output = `str(${output})`;
949
846
  if (node.literal.text)
950
847
  output += ` + "${transformString(node.literal.text)}"`;
951
848
  return output;
952
849
  });
953
- NodeHandler.register(ts8.SyntaxKind.NoSubstitutionTemplateLiteral, (node) => {
850
+ NodeHandler.register(ts7.SyntaxKind.NoSubstitutionTemplateLiteral, (node) => {
954
851
  return `"${transformString(node.text)}"`;
955
852
  });
956
- NodeHandler.register(ts8.SyntaxKind.ConditionalExpression, (node) => {
957
- if (ts8.isCallExpression(node.whenTrue) || ts8.isCallExpression(node.whenFalse)) {
853
+ NodeHandler.register(ts7.SyntaxKind.ConditionalExpression, (node) => {
854
+ if (ts7.isCallExpression(node.whenTrue) || ts7.isCallExpression(node.whenFalse)) {
958
855
  throw "Call expressions are not supported inside conditional expressions yet";
959
856
  }
960
857
  const condition = NodeHandler.handle(node.condition);
@@ -962,28 +859,28 @@ NodeHandler.register(ts8.SyntaxKind.ConditionalExpression, (node) => {
962
859
  const whenFalse = NodeHandler.handle(node.whenFalse);
963
860
  return callUtilFunction("conditional_expr", condition, whenTrue, whenFalse);
964
861
  });
965
- NodeHandler.register(ts8.SyntaxKind.ExpressionStatement, (node) => {
862
+ NodeHandler.register(ts7.SyntaxKind.ExpressionStatement, (node) => {
966
863
  return NodeHandler.handle(node.expression);
967
864
  });
968
- NodeHandler.register(ts8.SyntaxKind.NonNullExpression, (node) => {
865
+ NodeHandler.register(ts7.SyntaxKind.NonNullExpression, (node) => {
969
866
  return NodeHandler.handle(node.expression);
970
867
  });
971
- NodeHandler.register(ts8.SyntaxKind.AsExpression, (node) => {
868
+ NodeHandler.register(ts7.SyntaxKind.AsExpression, (node) => {
972
869
  return NodeHandler.handle(node.expression);
973
870
  });
974
- NodeHandler.register(ts8.SyntaxKind.DeleteExpression, (node) => {
975
- if (ts8.isPropertyAccessExpression(node.expression)) {
871
+ NodeHandler.register(ts7.SyntaxKind.DeleteExpression, (node) => {
872
+ if (ts7.isPropertyAccessExpression(node.expression)) {
976
873
  const pnode = node.expression;
977
874
  const left = NodeHandler.handle(pnode.expression);
978
875
  const leftType = checker.getTypeAtLocation(pnode.expression);
979
876
  const right = replaceIdentifier(NodeHandler.handle(pnode.name), leftType, pnode.name.text);
980
877
  return `${left}.remove("${right}")`;
981
878
  }
982
- if (ts8.isElementAccessExpression(node.expression)) {
879
+ if (ts7.isElementAccessExpression(node.expression)) {
983
880
  const pnode = node.expression;
984
881
  const left = NodeHandler.handle(pnode.expression);
985
882
  let right;
986
- if (ts8.isStringLiteral(pnode.argumentExpression)) {
883
+ if (ts7.isStringLiteral(pnode.argumentExpression)) {
987
884
  const leftType = checker.getTypeAtLocation(pnode.expression);
988
885
  right = `"${replaceIdentifier(pnode.argumentExpression.text, leftType, pnode.argumentExpression.text)}"`;
989
886
  } else {
@@ -991,11 +888,11 @@ NodeHandler.register(ts8.SyntaxKind.DeleteExpression, (node) => {
991
888
  }
992
889
  return `${left}.remove(${right})`;
993
890
  }
994
- throw `Cant handle delete expression for ${ts8.SyntaxKind[node.expression.kind]}`;
891
+ throw `Cant handle delete expression for ${ts7.SyntaxKind[node.expression.kind]}`;
995
892
  });
996
893
 
997
894
  // src/visitors/functions.ts
998
- import ts9 from "typescript";
895
+ import ts8 from "typescript";
999
896
  function transpileFunctionBody(node) {
1000
897
  const params = node.parameters.map((param) => NodeHandler.handle(param)).join(", ");
1001
898
  const body = node.body ? NodeHandler.handle(node.body) : "";
@@ -1003,7 +900,7 @@ function transpileFunctionBody(node) {
1003
900
  ${body}
1004
901
  end function`;
1005
902
  }
1006
- NodeHandler.register(ts9.SyntaxKind.Block, (node) => {
903
+ NodeHandler.register(ts8.SyntaxKind.Block, (node) => {
1007
904
  const output = node.statements.map((val) => {
1008
905
  let statement = NodeHandler.handle(val);
1009
906
  statement = statement.split(`
@@ -1014,38 +911,38 @@ NodeHandler.register(ts9.SyntaxKind.Block, (node) => {
1014
911
  `);
1015
912
  return output;
1016
913
  });
1017
- NodeHandler.register(ts9.SyntaxKind.MethodDeclaration, (node) => {
914
+ NodeHandler.register(ts8.SyntaxKind.MethodDeclaration, (node) => {
1018
915
  return `${NodeHandler.handle(node.name)} = ${transpileFunctionBody(node)}`;
1019
916
  });
1020
- NodeHandler.register(ts9.SyntaxKind.FunctionDeclaration, (node) => {
917
+ NodeHandler.register(ts8.SyntaxKind.FunctionDeclaration, (node) => {
1021
918
  if (!node.body)
1022
919
  return "";
1023
- if (node.modifiers?.some((m) => m.kind === ts9.SyntaxKind.DeclareKeyword))
920
+ if (node.modifiers?.some((m) => m.kind === ts8.SyntaxKind.DeclareKeyword))
1024
921
  return "";
1025
922
  const name = node.name ? node.name.text : "anon";
1026
923
  return `${name} = ${transpileFunctionBody(node)}`;
1027
924
  });
1028
- NodeHandler.register(ts9.SyntaxKind.ArrowFunction, (node) => {
925
+ NodeHandler.register(ts8.SyntaxKind.ArrowFunction, (node) => {
1029
926
  const params = node.parameters.map((param) => NodeHandler.handle(param));
1030
- const body = ts9.isBlock(node.body) ? NodeHandler.handle(node.body) : ` return ${NodeHandler.handle(node.body)}`;
1031
- if (ts9.isCallOrNewExpression(node.parent) || ts9.isParenthesizedExpression(node.parent)) {
927
+ const body = ts8.isBlock(node.body) ? NodeHandler.handle(node.body) : ` return ${NodeHandler.handle(node.body)}`;
928
+ if (ts8.isCallOrNewExpression(node.parent) || ts8.isParenthesizedExpression(node.parent)) {
1032
929
  return "@" + createAnonFunction(body, params).name;
1033
930
  }
1034
- if (ts9.hasOnlyExpressionInitializer(node.parent) || ts9.isBinaryExpression(node.parent) || ts9.isReturnStatement(node.parent)) {
931
+ if (ts8.hasOnlyExpressionInitializer(node.parent) || ts8.isBinaryExpression(node.parent) || ts8.isReturnStatement(node.parent)) {
1035
932
  return `function(${params.join(", ")})
1036
933
  ${body}
1037
934
  end function`;
1038
935
  }
1039
- const kind = ts9.SyntaxKind[node.parent.kind];
936
+ const kind = ts8.SyntaxKind[node.parent.kind];
1040
937
  throw `This kind of arrow function is not yet supported (parent: ${kind} (${node.parent.kind}))`;
1041
938
  });
1042
- NodeHandler.register(ts9.SyntaxKind.FunctionExpression, (node) => {
939
+ NodeHandler.register(ts8.SyntaxKind.FunctionExpression, (node) => {
1043
940
  return transpileFunctionBody(node);
1044
941
  });
1045
942
 
1046
943
  // src/visitors/identifiers.ts
1047
- import ts10 from "typescript";
1048
- NodeHandler.register(ts10.SyntaxKind.Identifier, (node, ctx) => {
944
+ import ts9 from "typescript";
945
+ NodeHandler.register(ts9.SyntaxKind.Identifier, (node, ctx) => {
1049
946
  const type = checker.getTypeAtLocation(node);
1050
947
  let name = node.text;
1051
948
  if (name === "undefined")
@@ -1063,31 +960,31 @@ NodeHandler.register(ts10.SyntaxKind.Identifier, (node, ctx) => {
1063
960
  if (ctx.namedImports[ctx.currentFilePath]?.[name]) {
1064
961
  name = ctx.namedImports[ctx.currentFilePath][name];
1065
962
  }
1066
- if (ts10.isCallOrNewExpression(node.parent) && node != node.parent.expression) {
963
+ if (ts9.isCallOrNewExpression(node.parent) && node != node.parent.expression) {
1067
964
  if (nodeIsFunctionReference(node, type))
1068
965
  name = asRef(name);
1069
966
  }
1070
967
  return name;
1071
968
  });
1072
- NodeHandler.register(ts10.SyntaxKind.Parameter, (node) => {
969
+ NodeHandler.register(ts9.SyntaxKind.Parameter, (node) => {
1073
970
  const name = NodeHandler.handle(node.name);
1074
971
  if (!node.initializer)
1075
972
  return name;
1076
973
  const initializer = NodeHandler.handle(node.initializer);
1077
974
  const initializerType = checker.getTypeAtLocation(node.initializer);
1078
- if (initializerType.flags === ts10.TypeFlags.Object) {
975
+ if (initializerType.flags === ts9.TypeFlags.Object) {
1079
976
  throw `You can't initialize parameter '${name}' with an Array or an Object as that won't work in GreyScript and it would be null`;
1080
977
  }
1081
978
  return `${name} = ${initializer}`;
1082
979
  });
1083
- NodeHandler.register(ts10.SyntaxKind.NumericLiteral, (node) => node.text);
1084
- NodeHandler.register(ts10.SyntaxKind.StringLiteral, (node) => `"${transformString(node.text)}"`);
1085
- NodeHandler.register(ts10.SyntaxKind.NullKeyword, () => "null");
1086
- NodeHandler.register(ts10.SyntaxKind.UndefinedKeyword, () => "null");
1087
- NodeHandler.register(ts10.SyntaxKind.FalseKeyword, () => "0");
1088
- NodeHandler.register(ts10.SyntaxKind.TrueKeyword, () => "1");
1089
- NodeHandler.register(ts10.SyntaxKind.ThisKeyword, (node) => {
1090
- const propDeclarationAncestor = ts10.findAncestor(node.parent, (n) => ts10.isPropertyDeclaration(n));
980
+ NodeHandler.register(ts9.SyntaxKind.NumericLiteral, (node) => node.text);
981
+ NodeHandler.register(ts9.SyntaxKind.StringLiteral, (node) => `"${transformString(node.text)}"`);
982
+ NodeHandler.register(ts9.SyntaxKind.NullKeyword, () => "null");
983
+ NodeHandler.register(ts9.SyntaxKind.UndefinedKeyword, () => "null");
984
+ NodeHandler.register(ts9.SyntaxKind.FalseKeyword, () => "0");
985
+ NodeHandler.register(ts9.SyntaxKind.TrueKeyword, () => "1");
986
+ NodeHandler.register(ts9.SyntaxKind.ThisKeyword, (node) => {
987
+ const propDeclarationAncestor = ts9.findAncestor(node.parent, (n) => ts9.isPropertyDeclaration(n));
1091
988
  if (propDeclarationAncestor) {
1092
989
  if (!propDeclarationAncestor.parent.name)
1093
990
  throw `Can't handle this 'this' keyword becuase the class doesn't have a name and it's needed for this case`;
@@ -1095,12 +992,12 @@ NodeHandler.register(ts10.SyntaxKind.ThisKeyword, (node) => {
1095
992
  }
1096
993
  return "self";
1097
994
  });
1098
- NodeHandler.register(ts10.SyntaxKind.SuperKeyword, (node) => {
1099
- if (ts10.isPropertyAccessExpression(node.parent) || ts10.isElementAccessExpression(node.parent))
995
+ NodeHandler.register(ts9.SyntaxKind.SuperKeyword, (node) => {
996
+ if (ts9.isPropertyAccessExpression(node.parent) || ts9.isElementAccessExpression(node.parent))
1100
997
  return "super";
1101
998
  return "super.constructor";
1102
999
  });
1103
- NodeHandler.register(ts10.SyntaxKind.RegularExpressionLiteral, (node) => {
1000
+ NodeHandler.register(ts9.SyntaxKind.RegularExpressionLiteral, (node) => {
1104
1001
  const start = node.text.indexOf("/") + 1;
1105
1002
  const end = node.text.lastIndexOf("/");
1106
1003
  const flags = node.text.slice(end + 1);
@@ -1111,7 +1008,7 @@ NodeHandler.register(ts10.SyntaxKind.RegularExpressionLiteral, (node) => {
1111
1008
 
1112
1009
  // src/visitors/imports.ts
1113
1010
  import path3 from "node:path";
1114
- import ts11 from "typescript";
1011
+ import ts10 from "typescript";
1115
1012
  function importFile(filePath, ctx, returnResult) {
1116
1013
  let srcPath = path3.resolve(ctx.currentFolder, filePath);
1117
1014
  if (!path3.extname(srcPath))
@@ -1123,7 +1020,7 @@ function importFile(filePath, ctx, returnResult) {
1123
1020
  }
1124
1021
  return transpileSourceFile(source, ctx, returnResult);
1125
1022
  }
1126
- NodeHandler.register(ts11.SyntaxKind.ImportDeclaration, (node, ctx) => {
1023
+ NodeHandler.register(ts10.SyntaxKind.ImportDeclaration, (node, ctx) => {
1127
1024
  if (!node.importClause) {
1128
1025
  const moduleName = node.moduleSpecifier.text;
1129
1026
  const transpiledFile = importFile(moduleName, ctx, true);
@@ -1146,7 +1043,7 @@ NodeHandler.register(ts11.SyntaxKind.ImportDeclaration, (node, ctx) => {
1146
1043
  throw `Can't import default exports yet (imported as ${node.importClause.name.text})`;
1147
1044
  const bindings = node.importClause.namedBindings;
1148
1045
  if (bindings) {
1149
- if (ts11.isNamespaceImport(bindings)) {
1046
+ if (ts10.isNamespaceImport(bindings)) {
1150
1047
  ctx.namespaceImports[ctx.currentFilePath]?.add(bindings.name.text);
1151
1048
  } else {
1152
1049
  bindings.elements.forEach((el) => {
@@ -1160,6 +1057,109 @@ NodeHandler.register(ts11.SyntaxKind.ImportDeclaration, (node, ctx) => {
1160
1057
  return importFile(moduleSpecifier, ctx);
1161
1058
  });
1162
1059
 
1060
+ // src/visitors/objects.ts
1061
+ import ts11 from "typescript";
1062
+ NodeHandler.register(ts11.SyntaxKind.PropertyAccessExpression, (node, ctx) => {
1063
+ const left = NodeHandler.handle(node.expression);
1064
+ let right = NodeHandler.handle(node.name);
1065
+ right = replaceIdentifier(right, checker.getTypeAtLocation(node.expression), right);
1066
+ const nodeSymbol = checker.getSymbolAtLocation(node);
1067
+ if (ctx.namespaceImports[ctx.currentFilePath]?.has(left))
1068
+ return right;
1069
+ let getSafely = !!node.questionDotToken && !ts11.isNonNullExpression(node.parent);
1070
+ const rightType = checker.getTypeAtLocation(node.name);
1071
+ if (rightType.isUnion()) {
1072
+ const hasUndefined = rightType.types.some((t) => t.flags === ts11.TypeFlags.Undefined);
1073
+ if (hasUndefined)
1074
+ getSafely = true;
1075
+ }
1076
+ if (!valueIsBeingAssignedToNode(node) && getSafely)
1077
+ return callUtilFunction("get_property", left, `"${right}"`);
1078
+ let output = `${left}.${right}`;
1079
+ output = replacePropertyAccess(output, nodeSymbol);
1080
+ if (nodeIsFunctionReference(node))
1081
+ output = asRef(output);
1082
+ return output;
1083
+ });
1084
+ NodeHandler.register(ts11.SyntaxKind.ElementAccessExpression, (node, ctx) => {
1085
+ const left = NodeHandler.handle(node.expression);
1086
+ let right;
1087
+ if (ts11.isStringLiteral(node.argumentExpression)) {
1088
+ const leftType = checker.getTypeAtLocation(node.expression);
1089
+ right = `"${replaceIdentifier(node.argumentExpression.text, leftType, node.argumentExpression.text)}"`;
1090
+ } else {
1091
+ right = NodeHandler.handle(node.argumentExpression);
1092
+ }
1093
+ if (!valueIsBeingAssignedToNode(node) && !ts11.isNumericLiteral(node.argumentExpression)) {
1094
+ return callUtilFunction("get_property", left, `${right}`);
1095
+ }
1096
+ return `${left}[${right}]`;
1097
+ });
1098
+ function handleObjectLiteralExpression(node, ctx, currObj, outObjects, funcs) {
1099
+ currObj ??= [];
1100
+ outObjects ??= [];
1101
+ funcs ??= [];
1102
+ let objectName = "";
1103
+ if (ts11.hasOnlyExpressionInitializer(node.parent))
1104
+ objectName = NodeHandler.handle(node.parent.name);
1105
+ else if (ts11.isBinaryExpression(node.parent) && node === node.parent.right)
1106
+ objectName = NodeHandler.handle(node.parent.left);
1107
+ function pushObj() {
1108
+ if (!currObj?.length)
1109
+ return "";
1110
+ const res = currObj.filter((s) => s != "").join(",");
1111
+ if (res) {
1112
+ outObjects?.push(`{ ${res} }`);
1113
+ }
1114
+ currObj.length = 0;
1115
+ return res;
1116
+ }
1117
+ for (const item of node.properties) {
1118
+ if (ts11.isFunctionLike(item)) {
1119
+ funcs.push(NodeHandler.handle(item));
1120
+ continue;
1121
+ }
1122
+ if (ts11.isPropertyAssignment(item) && ts11.isFunctionLike(item.initializer)) {
1123
+ funcs.push(`${NodeHandler.handle(item.name)} = ${NodeHandler.handle(item.initializer)}`);
1124
+ continue;
1125
+ }
1126
+ if (ts11.isSpreadAssignment(item)) {
1127
+ if (ts11.isObjectLiteralExpression(item.expression)) {
1128
+ handleObjectLiteralExpression(item.expression, ctx, currObj, outObjects);
1129
+ continue;
1130
+ }
1131
+ if (ts11.isIdentifier(item.expression)) {
1132
+ pushObj();
1133
+ outObjects.push(NodeHandler.handle(item.expression));
1134
+ continue;
1135
+ }
1136
+ if (ts11.isArrayLiteralExpression(item.expression)) {
1137
+ pushObj();
1138
+ outObjects.push(NodeHandler.handle(item.expression));
1139
+ continue;
1140
+ }
1141
+ }
1142
+ currObj.push(NodeHandler.handle(item));
1143
+ }
1144
+ pushObj();
1145
+ if (!outObjects.length)
1146
+ outObjects.push("{}");
1147
+ let output = outObjects[0];
1148
+ if (outObjects.length > 1) {
1149
+ output = callUtilFunction("assign_objects", output, `[${outObjects.slice(1).join(",")}]`);
1150
+ }
1151
+ if (funcs.length) {
1152
+ if (ts11.isPropertyAssignment(node.parent) || !objectName) {
1153
+ throw "You can't have method declarations inside an object that is not being assigned to a variable";
1154
+ }
1155
+ output += `
1156
+ ` + funcs.map((func) => `${objectName}.${func}`).join(`
1157
+ `);
1158
+ }
1159
+ return output;
1160
+ }
1161
+ NodeHandler.register(ts11.SyntaxKind.ObjectLiteralExpression, handleObjectLiteralExpression);
1162
+
1163
1163
  // src/visitors/statements.ts
1164
1164
  import ts12 from "typescript";
1165
1165
  NodeHandler.register(ts12.SyntaxKind.ForStatement, (node) => {
@@ -1376,56 +1376,13 @@ NodeHandler.register(ts13.SyntaxKind.EnumDeclaration, (node) => {
1376
1376
  });
1377
1377
 
1378
1378
  // src/call_transformers/array.ts
1379
- CallTransformer.register("Array.concat", (name, args) => {
1380
- const dotI = name.lastIndexOf(".");
1381
- const arrayName = name.slice(0, dotI);
1382
- return callUtilFunction("array_concat", arrayName, args.join(","));
1383
- });
1384
- CallTransformer.register("Array.map", (name, args) => {
1385
- if (!args.length)
1386
- throw "Invalid argument count";
1387
- return callUtilFunction("array_map", name.slice(0, name.lastIndexOf(".")), args[0]);
1388
- });
1389
- CallTransformer.register("Array.filter", (name, args) => {
1390
- if (!args.length)
1391
- throw "Invalid argument count";
1392
- return callUtilFunction("array_filter", name.slice(0, name.lastIndexOf(".")), args[0]);
1393
- });
1394
- CallTransformer.register("Array.find", (name, args) => {
1395
- if (!args.length)
1396
- throw "Invalid argument count";
1397
- return callUtilFunction("array_find", name.slice(0, name.lastIndexOf(".")), args[0]);
1398
- });
1399
- CallTransformer.register("Array.some", (name, args) => {
1400
- if (!args.length)
1401
- throw "Invalid argument count";
1402
- return callUtilFunction("array_some", name.slice(0, name.lastIndexOf(".")), args[0]);
1403
- });
1404
- CallTransformer.register("Array.every", (name, args) => {
1405
- if (!args.length)
1406
- throw "Invalid argument count";
1407
- return callUtilFunction("array_every", name.slice(0, name.lastIndexOf(".")), args[0]);
1408
- });
1409
1379
  CallTransformer.register("Array.slice", (name, args) => {
1410
1380
  return name.slice(0, name.lastIndexOf(".")) + `[${args[0] ?? ""}:${args[1] ?? ""}]`;
1411
1381
  });
1412
- CallTransformer.register("Array.push", (name, args) => {
1413
- if (!args.length)
1414
- throw "Invalid argument count";
1415
- return callUtilFunction("array_push", name.slice(0, name.lastIndexOf(".")), args[0]);
1416
- });
1417
- CallTransformer.register("Array.unshift", (name, args) => {
1418
- if (!args.length)
1419
- throw "Invalid argument count";
1420
- return callUtilFunction("array_unshift", name.slice(0, name.lastIndexOf(".")), args[0]);
1421
- });
1422
1382
  CallTransformer.register("Array.toString", (name) => {
1423
1383
  const arrayName = name.slice(0, name.lastIndexOf("."));
1424
1384
  return `str(${arrayName})`;
1425
1385
  });
1426
- CallTransformer.register("Array.reverse", (name) => {
1427
- return callUtilFunction("array_reverse", name.slice(0, name.lastIndexOf(".")));
1428
- });
1429
1386
 
1430
1387
  // src/call_transformers/object.ts
1431
1388
  CallTransformer.register("ObjectConstructor.hasOwn", (name, args) => {
@@ -1471,21 +1428,6 @@ CallTransformer.register("Object.toString", (name) => {
1471
1428
  });
1472
1429
 
1473
1430
  // src/call_transformers/string.ts
1474
- CallTransformer.register("String.startsWith", (name, args) => {
1475
- if (!args.length)
1476
- throw "Invalid argument count";
1477
- return callUtilFunction("str_starts_with", name.slice(0, name.lastIndexOf(".")), ...args);
1478
- });
1479
- CallTransformer.register("String.endsWith", (name, args) => {
1480
- if (!args.length)
1481
- throw "Invalid argument count";
1482
- return callUtilFunction("str_ends_with", name.slice(0, name.lastIndexOf(".")), ...args);
1483
- });
1484
- CallTransformer.register("String.repeat", (name, args) => {
1485
- if (!args.length)
1486
- throw "Invalid argument count";
1487
- return callUtilFunction("str_repeat", name.slice(0, name.lastIndexOf(".")), ...args);
1488
- });
1489
1431
  CallTransformer.register("String.slice", (name, args) => {
1490
1432
  return name.slice(0, name.lastIndexOf(".")) + `[${args[0] ?? ""}:${args[1] ?? ""}]`;
1491
1433
  });
@@ -1496,132 +1438,68 @@ CallTransformer.register("String.toString", (name) => {
1496
1438
  // src/transpiler.ts
1497
1439
  var program;
1498
1440
  var checker;
1499
- var anonFunctions = new Map;
1500
- var calledUtilFunctions = new Set;
1501
- var utilFunctions2 = {
1502
- get_property: [
1503
- "get_property = function(obj, key)",
1504
- "\tif not obj then return null",
1505
- "\tif obj.hasIndex(key) then return obj[key]",
1506
- "\tisaobj = obj",
1507
- '\twhile isaobj.hasIndex("__isa")',
1508
- '\t\tisaobj = obj["__isa"]',
1509
- "\t\tif isaobj.hasIndex(key) then",
1510
- "\t\t\tres = obj[key]",
1511
- '\t\t\tif typeof(@res) == "function" and str(@res)[8:][1:-1].indexOf("self") == 0 then return res(obj)',
1512
- "\t\t\treturn obj[key]",
1513
- "\t\tend if",
1514
- "\tend while",
1515
- "\treturn null",
1516
- "end function"
1517
- ].join(`
1518
- `),
1519
- assign_objects: [
1520
- "assign_objects = function(target, source1, source2, source3)",
1521
- "\tassign_to_list = function(target, source)",
1522
- "\t\tif source isa list then",
1523
- "\t\t\tfor i in range(0, source.len - 1, 1)",
1524
- "\t\t\t\tif target.len <= i then target.push(null)",
1525
- "\t\t\t\ttarget[i] = source[i]",
1526
- "\t\t\tend for",
1527
- "\t\telse if source isa map then",
1528
- "\t\t\tfor item in source",
1529
- "\t\t\t\tkey = str(item.key).to_int",
1530
- "\t\t\t\tif key isa number then target[key] = item.value",
1531
- "\t\t\tend for",
1532
- "\t\tend if",
1533
- "\t\treturn target",
1534
- "\tend function",
1535
- "\tcounter = 0",
1536
- "\tassign_object = function(target, source)",
1537
- "\t\tif target isa list then return assign_to_list(target, source)",
1538
- "\t\tif source isa list then",
1539
- "\t\t\tfor i in range(0, source.len - 1, 1)",
1540
- "\t\t\t\ttarget[str(i)] = source[i]",
1541
- "\t\t\tend for",
1542
- "\t\telse if source isa map then",
1543
- "\t\t\tfor item in source",
1544
- "\t\t\t\ttarget[item.key] = item.value",
1545
- "\t\t\tend for",
1546
- "\t\telse",
1547
- "\t\t\ttarget[str(outer.counter)] = source",
1548
- "\t\t\touter.counter = outer.counter + 1",
1549
- "\t\tend if",
1550
- "\tend function",
1551
- "\tif source1 isa list then",
1552
- "\t\tif target isa list then return assign_to_list(target, source1)",
1553
- "\t\tfor source in source1",
1554
- "\t\t\tassign_object(target, source)",
1555
- "\t\tend for",
1556
- "\t\treturn target",
1557
- "\tend if",
1558
- "\tif source1 then assign_object(target, source1)",
1559
- "\tif source2 then assign_object(target, source2)",
1560
- "\tif source3 then assign_object(target, source3)",
1561
- "\treturn target",
1562
- "end function"
1563
- ].join(`
1564
- `),
1565
- array_map: [
1566
- "array_map = function(array, callback)",
1441
+ var utilitiesToInsert = new Map;
1442
+ var extensionFunctions = {
1443
+ "Array.map": [
1444
+ "list.map = function(callback)",
1567
1445
  "\tindex = 0",
1568
1446
  "\tout = []",
1569
- "\tfor item in array",
1570
- "\t\tout.push(callback(item, index, array))",
1447
+ "\tfor item in self",
1448
+ "\t\tout.push(callback(item, index, self))",
1571
1449
  "\t\tindex = index + 1",
1572
1450
  "\tend for",
1573
1451
  "\treturn out",
1574
1452
  "end function"
1575
1453
  ].join(`
1576
1454
  `),
1577
- array_filter: [
1578
- "array_filter = function(array, predicate)",
1455
+ "Array.filter": [
1456
+ "list.filter = function(predicate)",
1579
1457
  "\tindex = 0",
1580
1458
  "\tout = []",
1581
- "\tfor item in array",
1582
- "\t\tif predicate(item, index, array) then out.push(item)",
1459
+ "\tfor item in self",
1460
+ "\t\tif predicate(item, index, self) then out.push(item)",
1583
1461
  "\t\tindex = index + 1",
1584
1462
  "\tend for",
1585
1463
  "\treturn out",
1586
1464
  "end function"
1587
1465
  ].join(`
1588
1466
  `),
1589
- array_find: [
1590
- "array_find = function(array, predicate)",
1467
+ "Array.find": [
1468
+ "list.find = function(predicate)",
1591
1469
  "\tindex = 0",
1592
- "\tfor item in array",
1593
- "\t\tif predicate(item, index, array) then return item",
1470
+ "\tfor item in self",
1471
+ "\t\tif predicate(item, index, self) then return item",
1594
1472
  "\t\tindex = index + 1",
1595
1473
  "\tend for",
1596
1474
  "\treturn null",
1597
1475
  "end function"
1598
1476
  ].join(`
1599
1477
  `),
1600
- array_some: [
1601
- "array_some = function(array, predicate)",
1478
+ "Array.some": [
1479
+ "list.some = function(predicate)",
1602
1480
  "\tindex = 0",
1603
- "\tfor item in array",
1604
- "\t\tif predicate(item, index, array) then return 1",
1481
+ "\tfor item in self",
1482
+ "\t\tif predicate(item, index, self) then return 1",
1605
1483
  "\t\tindex = index + 1",
1606
1484
  "\tend for",
1607
1485
  "\treturn 0",
1608
1486
  "end function"
1609
1487
  ].join(`
1610
1488
  `),
1611
- array_every: [
1612
- "array_every = function(array, predicate)",
1489
+ "Array.every": [
1490
+ "list.every = function(predicate)",
1613
1491
  "\tindex = 0",
1614
- "\tfor item in array",
1615
- "\t\tif not predicate(item, index, array) then return 0",
1492
+ "\tfor item in self",
1493
+ "\t\tif not predicate(item, index, self) then return 0",
1616
1494
  "\t\tindex = index + 1",
1617
1495
  "\tend for",
1618
1496
  "\treturn 1",
1619
1497
  "end function"
1620
1498
  ].join(`
1621
1499
  `),
1622
- array_concat: [
1623
- "array_concat = function(target, items)",
1624
- "\tout = target[0:]",
1500
+ "Array.concat": [
1501
+ "list.concat = function(items)",
1502
+ "\tout = self[0:]",
1625
1503
  "\tfor item in items",
1626
1504
  "\t\tif item isa list then out = out + item else out.push(item)",
1627
1505
  "\tend for",
@@ -1629,58 +1507,141 @@ var utilFunctions2 = {
1629
1507
  "end function"
1630
1508
  ].join(`
1631
1509
  `),
1632
- array_push: [
1633
- "array_push = function(target, items)",
1510
+ "Array.push": [
1511
+ "list.push_many = function(items)",
1634
1512
  "\tfor item in items[:]",
1635
- "\t\ttarget.push(@item)",
1513
+ "\t\tself.push(@item)",
1636
1514
  "\tend for",
1637
- "\treturn target.len",
1515
+ "\treturn self.len",
1638
1516
  "end function"
1639
1517
  ].join(`
1640
1518
  `),
1641
- array_unshift: [
1642
- "array_unshift = function(target, items)",
1643
- "\tif not items.len then return target.len",
1519
+ "Array.unshift": [
1520
+ "list.unshift = function(items)",
1521
+ "\tif not items.len then return self.len",
1644
1522
  "\tfor i in range(items.len-1)",
1645
- "\t\ttarget.insert(0, @items[i])",
1523
+ "\t\tself.insert(0, items[i])",
1646
1524
  "\tend for",
1647
- "\treturn target.len",
1525
+ "\treturn self.len",
1648
1526
  "end function"
1649
1527
  ].join(`
1650
1528
  `),
1651
- array_reverse: `array_reverse = function(arr)
1652
- arr.reverse
1653
- return arr
1654
- end function`,
1655
- str_starts_with: [
1656
- "str_starts_with = function(str, search, pos = 0)",
1657
- "\tif pos < 0 then pos = 0",
1658
- "\treturn str.indexOf(search) == pos",
1529
+ "Array.reverse": [
1530
+ "list.old_reverse = @list.reverse",
1531
+ "list.reverse = function",
1532
+ "\tself.old_reverse",
1533
+ "\treturn self",
1659
1534
  "end function"
1660
1535
  ].join(`
1661
1536
  `),
1662
- str_ends_with: [
1663
- "str_ends_with = function(str, search, pos = null)",
1664
- "\tif pos == null then pos = str.len",
1537
+ "Array.includes": [
1538
+ "list.includes = function(value, pos = 0)",
1539
+ "\tindex = self.indexOf(value)",
1540
+ "\tif index == null then return 0",
1665
1541
  "\tif pos < 0 then pos = 0",
1666
- "\treturn str.indexOf(search) + search.len == pos",
1542
+ "\treturn index >= pos",
1667
1543
  "end function"
1668
1544
  ].join(`
1669
1545
  `),
1670
- str_repeat: [
1671
- "str_repeat = function(str, count = 0)",
1672
- '\tif count <= 0 then return ""',
1673
- "\tif count == 1 then return str",
1674
- "\tout = str",
1675
- "\tfor i in range(count-2)",
1676
- "\t\tout = out + str",
1546
+ "Array.splice": [
1547
+ "list.splice = function(start, count)",
1548
+ "\tdeleted = []",
1549
+ "\tif start < 0 then start = self.len + start",
1550
+ "\tif start < 0 then start = 0",
1551
+ "\tif count == null then count = self.len - start",
1552
+ "\tif count <= 0 then return deleted",
1553
+ "\twhile deleted.len < count",
1554
+ "\t\tif not self.hasIndex(start) then return deleted",
1555
+ "\t\tdeleted.push(self[start])",
1556
+ "\t\tself.remove(start)",
1557
+ "\tend while",
1558
+ "\treturn deleted",
1559
+ "end function"
1560
+ ].join(`
1561
+ `),
1562
+ "Array.fill": [
1563
+ "list.fill = function(value, start, endI)",
1564
+ "\tlen = self.len",
1565
+ "\tif not len then return self",
1566
+ "\tif start == null then start = 0",
1567
+ "\tif endI == null then endI = len - 1",
1568
+ "\tif start < 0 then start = len + start",
1569
+ "\tif start < 0 then start = 0",
1570
+ "\tif endI < 0 then endI = len + endI",
1571
+ "\tif endI < 0 then endI = 0",
1572
+ "\tfor i in range(start, endI-1, 1)",
1573
+ "\t\tif i >= len then break",
1574
+ "\t\tself[i] = value",
1677
1575
  "\tend for",
1678
- "\treturn out",
1576
+ "\treturn self",
1577
+ "end function"
1578
+ ].join(`
1579
+ `),
1580
+ "String.startsWith": [
1581
+ "string.startsWith = function(search, pos = 0)",
1582
+ "\tif pos < 0 then pos = 0",
1583
+ "\treturn self.indexOf(search) == pos",
1584
+ "end function"
1585
+ ].join(`
1586
+ `),
1587
+ "String.endsWith": [
1588
+ "string.endsWith = function(search, pos = null)",
1589
+ "\tif pos == null then pos = self.len",
1590
+ "\tif pos < 0 then pos = 0",
1591
+ "\treturn self.indexOf(search) + search.len == pos",
1592
+ "end function"
1593
+ ].join(`
1594
+ `),
1595
+ "String.repeat": [
1596
+ "string.repeatSelf = function(count = 0)",
1597
+ "\treturn self * count",
1598
+ "end function"
1599
+ ].join(`
1600
+ `),
1601
+ "String.includes": [
1602
+ "string.includes = function(search, pos = 0)",
1603
+ "\tindex = self.indexOf(search)",
1604
+ "\tif index == null then return 0",
1605
+ "\tif pos < 0 then pos = 0",
1606
+ "\treturn index >= pos",
1607
+ "end function"
1608
+ ].join(`
1609
+ `),
1610
+ "String.trimStart": [
1611
+ "string.trimStart = function()",
1612
+ '\treturn self.replace("^\\s+", "")',
1613
+ "end function"
1614
+ ].join(`
1615
+ `),
1616
+ "String.trimEnd": [
1617
+ "string.trimEnd = function()",
1618
+ '\treturn self.replace("\\s+$", "")',
1679
1619
  "end function"
1680
1620
  ].join(`
1681
1621
  `),
1682
- math_min: [
1683
- "math_min = function(numbers)",
1622
+ "Number.toFixed": [
1623
+ "number.toFixed = function(digits = 0)",
1624
+ "\tdigits = floor(digits)",
1625
+ "\tif digits <= 0 then return str(round(self))",
1626
+ "\tvalue = self",
1627
+ "\tvalue = value * (10 ^ digits)",
1628
+ "\tvalue = round(value)",
1629
+ "\tvalue = value / (10 ^ digits)",
1630
+ "\t",
1631
+ "\tstr_value = str(value)",
1632
+ '\tdot_index = str_value.indexOf(".")',
1633
+ "\tif dot_index == null then",
1634
+ '\t\tstr_value = str_value + "." + ("0" * digits)',
1635
+ "\telse if str_value[dot_index + 1:].len < digits then",
1636
+ "\t\trepeat_count = digits - str_value[dot_index + 1:].len",
1637
+ '\t\tstr_value = str_value + ("0" * repeat_count)',
1638
+ "\tend if",
1639
+ "\treturn str_value",
1640
+ "end function"
1641
+ ].join(`
1642
+ `),
1643
+ "Math.min": [
1644
+ "Math.min = function(numbers)",
1684
1645
  "\tcurr_min = null",
1685
1646
  "\tfor num in numbers",
1686
1647
  "\t\tif curr_min == null or num < curr_min then curr_min = num",
@@ -1689,8 +1650,8 @@ end function`,
1689
1650
  "end function"
1690
1651
  ].join(`
1691
1652
  `),
1692
- math_max: [
1693
- "math_max = function(numbers)",
1653
+ "Math.max": [
1654
+ "Math.max = function(numbers)",
1694
1655
  "\tcurr_max = null",
1695
1656
  "\tfor num in numbers",
1696
1657
  "\t\tif curr_max == null or num > curr_max then curr_max = num",
@@ -1698,6 +1659,83 @@ end function`,
1698
1659
  "\treturn curr_max",
1699
1660
  "end function"
1700
1661
  ].join(`
1662
+ `)
1663
+ };
1664
+ var utilFunctions = {
1665
+ get_property: [
1666
+ "get_property = function(obj, key)",
1667
+ "\tif not obj then return null",
1668
+ "\tif obj.hasIndex(key) then return obj[key]",
1669
+ "\tisaobj = obj",
1670
+ '\twhile isaobj.hasIndex("__isa")',
1671
+ '\t\tisaobj = obj["__isa"]',
1672
+ "\t\tif isaobj.hasIndex(key) then",
1673
+ "\t\t\tres = obj[key]",
1674
+ '\t\t\tif typeof(@res) == "function" and str(@res)[8:][1:-1].indexOf("self") == 0 then return res(obj)',
1675
+ "\t\t\treturn obj[key]",
1676
+ "\t\tend if",
1677
+ "\tend while",
1678
+ "\treturn null",
1679
+ "end function"
1680
+ ].join(`
1681
+ `),
1682
+ assign_objects: [
1683
+ "assign_objects = function(target, source1, source2, source3)",
1684
+ "\tassign_to_list = function(target, source)",
1685
+ "\t\tif source isa list then",
1686
+ "\t\t\tfor i in range(0, source.len - 1, 1)",
1687
+ "\t\t\t\tif target.len <= i then target.push(null)",
1688
+ "\t\t\t\ttarget[i] = source[i]",
1689
+ "\t\t\tend for",
1690
+ "\t\telse if source isa map then",
1691
+ "\t\t\tfor item in source",
1692
+ "\t\t\t\tkey = str(item.key).to_int",
1693
+ "\t\t\t\tif key isa number then target[key] = item.value",
1694
+ "\t\t\tend for",
1695
+ "\t\tend if",
1696
+ "\t\treturn target",
1697
+ "\tend function",
1698
+ "\tcounter = 0",
1699
+ "\tassign_object = function(target, source)",
1700
+ "\t\tif target isa list then return assign_to_list(target, source)",
1701
+ "\t\tif source isa list then",
1702
+ "\t\t\tfor i in range(0, source.len - 1, 1)",
1703
+ "\t\t\t\ttarget[str(i)] = source[i]",
1704
+ "\t\t\tend for",
1705
+ "\t\telse if source isa map then",
1706
+ "\t\t\tfor item in source",
1707
+ "\t\t\t\ttarget[item.key] = item.value",
1708
+ "\t\t\tend for",
1709
+ "\t\telse",
1710
+ "\t\t\ttarget[str(outer.counter)] = source",
1711
+ "\t\t\touter.counter = outer.counter + 1",
1712
+ "\t\tend if",
1713
+ "\tend function",
1714
+ "\tif source1 isa list then",
1715
+ "\t\tif target isa list then return assign_to_list(target, source1)",
1716
+ "\t\tfor source in source1",
1717
+ "\t\t\tassign_object(target, source)",
1718
+ "\t\tend for",
1719
+ "\t\treturn target",
1720
+ "\tend if",
1721
+ "\tif source1 then assign_object(target, source1)",
1722
+ "\tif source2 then assign_object(target, source2)",
1723
+ "\tif source3 then assign_object(target, source3)",
1724
+ "\treturn target",
1725
+ "end function"
1726
+ ].join(`
1727
+ `),
1728
+ instance_of: [
1729
+ "instance_of = function(obj, class)",
1730
+ '\tif not obj.hasIndex("__isa") then return 0',
1731
+ "\tisaobj = obj",
1732
+ '\twhile isaobj.hasIndex("__isa")',
1733
+ '\t\tif isaobj["__isa"] == class then return 1',
1734
+ '\t\tisaobj = isaobj["__isa"]',
1735
+ "\tend while",
1736
+ "\treturn 0",
1737
+ "end function"
1738
+ ].join(`
1701
1739
  `),
1702
1740
  nullish_coalescing_op: `nullish_coalescing_op = function(left, right)
1703
1741
  if left == null then return @right
@@ -1708,8 +1746,7 @@ end function`,
1708
1746
  return @left
1709
1747
  end function`,
1710
1748
  is_type: `is_type = function(value, type)
1711
- if typeof(value) == type then return 1
1712
- return 0
1749
+ return typeof(value) == type
1713
1750
  end function`,
1714
1751
  conditional_expr: `conditional_expr = function(cond, when_true, when_false)
1715
1752
  if cond then return when_true
@@ -1718,12 +1755,12 @@ end function`
1718
1755
  };
1719
1756
  function createAnonFunction(body, params) {
1720
1757
  const defaultParams = new Array(3).fill(0).map((_, i) => `param${i}`);
1721
- const nextName = `func_${anonFunctions.size}`;
1758
+ const nextName = `func_${utilitiesToInsert.size}`;
1722
1759
  const paramString = Object.assign(defaultParams, params).join(",");
1723
1760
  const result = `${nextName} = function(${paramString})
1724
1761
  ${body}
1725
1762
  end function`;
1726
- anonFunctions.set(nextName, result);
1763
+ utilitiesToInsert.set(nextName, result);
1727
1764
  return { name: nextName, str: result };
1728
1765
  }
1729
1766
  function transpileProgram(entryFileRelativePath) {
@@ -1764,19 +1801,12 @@ function transpileProgram(entryFileRelativePath) {
1764
1801
  process.exit(1);
1765
1802
  }
1766
1803
  transpileSourceFile(entry, ctx);
1767
- if (anonFunctions.size) {
1768
- for (const declaration of anonFunctions.values())
1769
- ctx.output.unshift(declaration);
1770
- anonFunctions.clear();
1771
- }
1772
- if (calledUtilFunctions.size) {
1773
- for (const call of calledUtilFunctions.keys())
1774
- ctx.output.unshift(utilFunctions2[call]);
1775
- calledUtilFunctions.clear();
1804
+ if (utilitiesToInsert.size) {
1805
+ ctx.output.unshift(...utilitiesToInsert.values());
1806
+ utilitiesToInsert.clear();
1776
1807
  }
1777
1808
  console.log(`Transpiling took ${Date.now() - start} ms`);
1778
- return ctx.output.join(`
1779
- `);
1809
+ return ctx.output;
1780
1810
  }
1781
1811
  function transpileSourceFile(sourceFile, ctx, returnResult) {
1782
1812
  if (ctx.visitedFiles[sourceFile.fileName])
@@ -1828,27 +1858,54 @@ for (let i = 2;i < process.argv.length; i++) {
1828
1858
  args.push(arg);
1829
1859
  }
1830
1860
  var root = findProjectRoot(process.cwd());
1861
+ var outDirPath = `${root}/out`;
1831
1862
  if (!command) {
1832
1863
  console.error("No command specified.");
1833
1864
  process.exit(2);
1834
1865
  }
1866
+ function createOutputFile(fileIndex, basename, content) {
1867
+ if (fileIndex > 0)
1868
+ basename = `${basename}-${fileIndex}`;
1869
+ const outFileName = args.length > 1 ? args[1] : `${basename}.src`;
1870
+ const outFilePath = path5.join(outDirPath, outFileName);
1871
+ fs3.writeFileSync(outFilePath, content);
1872
+ }
1835
1873
  if (command === "transpile") {
1836
1874
  if (!args.length) {
1837
1875
  console.error("No entry file specified.");
1838
1876
  process.exit(2);
1839
1877
  }
1840
1878
  const entryFile = args[0];
1841
- const output = transpileProgram(entryFile);
1879
+ const basename = path5.basename(entryFile, ".ts");
1880
+ const transpiledStatements = transpileProgram(entryFile);
1842
1881
  if (flags.includes("--print") || flags.includes("-p")) {
1843
- console.log(output);
1882
+ console.log(transpiledStatements.join(`
1883
+ `));
1844
1884
  process.exit(0);
1845
1885
  }
1846
- const outDirPath = `${root}/out`;
1847
1886
  if (!fs3.existsSync(outDirPath))
1848
1887
  fs3.mkdirSync(outDirPath);
1849
- const outFileName = args.length > 1 ? args[1] : `${path5.basename(entryFile).replace(".ts", ".src")}`;
1850
- const outFilePath = path5.join(outDirPath, outFileName);
1851
- fs3.writeFileSync(outFilePath, output);
1888
+ let content = "";
1889
+ const fileContents = [];
1890
+ while (transpiledStatements.length) {
1891
+ const statement = transpiledStatements.shift();
1892
+ if (content.length + statement.length > 155000 && content.length) {
1893
+ fileContents.push(content);
1894
+ content = "";
1895
+ continue;
1896
+ }
1897
+ content += statement + `
1898
+ `;
1899
+ }
1900
+ if (content.length)
1901
+ fileContents.push(content);
1902
+ for (let i = 0;i < fileContents.length; i++) {
1903
+ if (i + 1 < fileContents.length) {
1904
+ const nextFileName = `${basename}-${i + 1}.src`;
1905
+ fileContents[i] += `import_code("${nextFileName}")`;
1906
+ }
1907
+ createOutputFile(i, basename, fileContents[i]);
1908
+ }
1852
1909
  } else {
1853
1910
  console.log(`Invalid command: ${command}`);
1854
1911
  process.exit(127);