@grey-ts/transpiler 1.3.0 → 1.4.1

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 +290 -235
  2. package/package.json +5 -6
package/dist/index.js CHANGED
@@ -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",
@@ -389,6 +388,25 @@ function callUtilFunction(functionName, ...params) {
389
388
  utilitiesToInsert.set(functionName, utilFunctions[functionName]);
390
389
  return `${functionName}(${params.join(", ")})`;
391
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
+ }
392
410
 
393
411
  // src/visitors/assignments.ts
394
412
  import ts4 from "typescript";
@@ -497,7 +515,7 @@ end function`;
497
515
  });
498
516
 
499
517
  // src/visitors/expressions.ts
500
- import ts8 from "typescript";
518
+ import ts7 from "typescript";
501
519
 
502
520
  // src/call_transformers/callTransformer.ts
503
521
  import path2 from "node:path";
@@ -510,10 +528,10 @@ class CallTransformer {
510
528
  this.handlers.set(symbolFullName, handler);
511
529
  }
512
530
  static handle(symbolFullName, functionName, callArgs, node, ctx) {
513
- if (symbolFullName in utilFunctions) {
531
+ if (symbolFullName in extensionFunctions) {
514
532
  if (symbolFullName.startsWith("Math"))
515
533
  utilitiesToInsert.set("create_math", "Math = {}");
516
- utilitiesToInsert.set(symbolFullName, utilFunctions[symbolFullName]);
534
+ utilitiesToInsert.set(symbolFullName, extensionFunctions[symbolFullName]);
517
535
  const params = callArgs.length ? `(${callArgs.join(",")})` : "";
518
536
  return `${functionName}${params}`;
519
537
  }
@@ -544,6 +562,9 @@ CallTransformer.register("GreyHack.include", (name, args, node, ctx) => {
544
562
  }
545
563
  return "";
546
564
  });
565
+ CallTransformer.register("GreyHack.isType", (name, args) => {
566
+ return callUtilFunction("is_type", args.join(","));
567
+ });
547
568
  CallTransformer.register("Boolean", (name, args) => {
548
569
  if (!args.length)
549
570
  return "0";
@@ -560,129 +581,12 @@ CallTransformer.register("String", (name, args) => {
560
581
  return `str(${args[0]})`;
561
582
  });
562
583
 
563
- // src/visitors/objects.ts
564
- import ts7 from "typescript";
565
- var assignmentOperators = new Set([
566
- "=",
567
- "??=",
568
- "||=",
569
- "-=",
570
- "+="
571
- ]);
572
- function valueIsBeingAssignedToNode(node) {
573
- const assignAncestor = ts7.findAncestor(node, (ancestor) => {
574
- if (ancestor.parent && ts7.isBinaryExpression(ancestor.parent) && ancestor === ancestor.parent.left) {
575
- const token = ts7.tokenToString(ancestor.parent.operatorToken.kind) || ancestor.parent.operatorToken.getText();
576
- return assignmentOperators.has(token);
577
- }
578
- return false;
579
- });
580
- return !!assignAncestor;
581
- }
582
- NodeHandler.register(ts7.SyntaxKind.PropertyAccessExpression, (node, ctx) => {
583
- const left = NodeHandler.handle(node.expression);
584
- let right = NodeHandler.handle(node.name);
585
- right = replaceIdentifier(right, checker.getTypeAtLocation(node.expression), right);
586
- const nodeSymbol = checker.getSymbolAtLocation(node);
587
- if (ctx.namespaceImports[ctx.currentFilePath]?.has(left))
588
- return right;
589
- let getSafely = !!node.questionDotToken && !ts7.isNonNullExpression(node.parent);
590
- const rightType = checker.getTypeAtLocation(node.name);
591
- if (rightType.isUnion()) {
592
- const hasUndefined = rightType.types.some((t) => t.flags === ts7.TypeFlags.Undefined);
593
- if (hasUndefined)
594
- getSafely = true;
595
- }
596
- if (!valueIsBeingAssignedToNode(node) && getSafely)
597
- return callUtilFunction("get_property", left, `"${right}"`);
598
- let output = `${left}.${right}`;
599
- output = replacePropertyAccess(output, nodeSymbol);
600
- if (nodeIsFunctionReference(node))
601
- output = asRef(output);
602
- return output;
603
- });
604
- NodeHandler.register(ts7.SyntaxKind.ElementAccessExpression, (node, ctx) => {
605
- const left = NodeHandler.handle(node.expression);
606
- let right;
607
- if (ts7.isStringLiteral(node.argumentExpression)) {
608
- const leftType = checker.getTypeAtLocation(node.expression);
609
- right = `"${replaceIdentifier(node.argumentExpression.text, leftType, node.argumentExpression.text)}"`;
610
- } else {
611
- right = NodeHandler.handle(node.argumentExpression);
612
- }
613
- if (!valueIsBeingAssignedToNode(node) && !ts7.isNumericLiteral(node.argumentExpression)) {
614
- return callUtilFunction("get_property", left, `${right}`);
615
- }
616
- return `${left}[${right}]`;
617
- });
618
- function handleObjectLiteralExpression(node, ctx, currObj, outObjects, funcs) {
619
- currObj ??= [];
620
- outObjects ??= [];
621
- funcs ??= [];
622
- const objectName = ts7.hasOnlyExpressionInitializer(node.parent) ? NodeHandler.handle(node.parent.name) : ts7.isBinaryExpression(node.parent) && node === node.parent.right ? NodeHandler.handle(node.parent.left) : "";
623
- function pushObj() {
624
- if (!currObj?.length)
625
- return "";
626
- const res = currObj.filter((s) => s != "").join(",");
627
- if (res) {
628
- outObjects?.push(`{ ${res} }`);
629
- }
630
- currObj.length = 0;
631
- return res;
632
- }
633
- for (const item of node.properties) {
634
- if (ts7.isFunctionLike(item)) {
635
- if (!objectName)
636
- throw "You can't have method declarations inside an object that is not being assigned to a variable";
637
- funcs.push(`${objectName}.${NodeHandler.handle(item)}`);
638
- continue;
639
- }
640
- if (ts7.isPropertyAssignment(item) && ts7.isFunctionLike(item.initializer)) {
641
- if (!objectName)
642
- throw "You can't have method declarations inside an object that is not being assigned to a variable";
643
- funcs.push(`${objectName}.${NodeHandler.handle(item.name)} = ${NodeHandler.handle(item.initializer)}`);
644
- continue;
645
- }
646
- if (ts7.isSpreadAssignment(item)) {
647
- if (ts7.isObjectLiteralExpression(item.expression)) {
648
- handleObjectLiteralExpression(item.expression, ctx, currObj, outObjects);
649
- continue;
650
- }
651
- if (ts7.isIdentifier(item.expression)) {
652
- pushObj();
653
- outObjects.push(NodeHandler.handle(item.expression));
654
- continue;
655
- }
656
- if (ts7.isArrayLiteralExpression(item.expression)) {
657
- pushObj();
658
- outObjects.push(NodeHandler.handle(item.expression));
659
- continue;
660
- }
661
- }
662
- currObj.push(NodeHandler.handle(item));
663
- }
664
- pushObj();
665
- if (!outObjects.length)
666
- outObjects.push("{}");
667
- let output = outObjects[0];
668
- if (outObjects.length > 1) {
669
- output = callUtilFunction("assign_objects", output, `[${outObjects.slice(1).join(",")}]`);
670
- }
671
- if (funcs.length) {
672
- output += `
673
- ` + funcs.join(`
674
- `);
675
- }
676
- return output;
677
- }
678
- NodeHandler.register(ts7.SyntaxKind.ObjectLiteralExpression, handleObjectLiteralExpression);
679
-
680
584
  // src/visitors/expressions.ts
681
585
  function hasRestParam(params) {
682
586
  if (!params.length)
683
587
  return false;
684
588
  const lastParam = params[params.length - 1];
685
- return !!(lastParam.valueDeclaration && ts8.isParameter(lastParam.valueDeclaration) && lastParam.valueDeclaration.dotDotDotToken);
589
+ return !!(lastParam.valueDeclaration && ts7.isParameter(lastParam.valueDeclaration) && lastParam.valueDeclaration.dotDotDotToken);
686
590
  }
687
591
  function handleCallArgs(callNode, ctx) {
688
592
  const args = callNode.arguments;
@@ -706,11 +610,11 @@ function handleCallArgs(callNode, ctx) {
706
610
  }
707
611
  }
708
612
  for (const arg of args) {
709
- if (!ts8.isSpreadElement(arg)) {
613
+ if (!ts7.isSpreadElement(arg)) {
710
614
  pushArgs(false, NodeHandler.handle(arg));
711
615
  continue;
712
616
  }
713
- if (ts8.isArrayLiteralExpression(arg.expression)) {
617
+ if (ts7.isArrayLiteralExpression(arg.expression)) {
714
618
  const arrayItems = [];
715
619
  const outArrs = [];
716
620
  handleArrayLiteralExpression(arg.expression, ctx, arrayItems, outArrs);
@@ -762,7 +666,7 @@ function handleCallArgs(callNode, ctx) {
762
666
  result.push("[]");
763
667
  return result;
764
668
  }
765
- NodeHandler.register(ts8.SyntaxKind.CallExpression, (node, ctx) => {
669
+ NodeHandler.register(ts7.SyntaxKind.CallExpression, (node, ctx) => {
766
670
  const args = handleCallArgs(node, ctx);
767
671
  let name = NodeHandler.handle(node.expression);
768
672
  const type = checker.getTypeAtLocation(node.expression);
@@ -774,14 +678,11 @@ NodeHandler.register(ts8.SyntaxKind.CallExpression, (node, ctx) => {
774
678
  const transformed = CallTransformer.handle(symbolFullName, name, args, node, ctx);
775
679
  if (transformed !== null)
776
680
  return transformed;
777
- if (name === "is_type" && !utilitiesToInsert.has("is_type")) {
778
- utilitiesToInsert.set("is_type", utilFunctions["is_type"]);
779
- }
780
681
  if (!args.length)
781
682
  return name;
782
683
  return `${name}(${args.join(", ")})`;
783
684
  });
784
- NodeHandler.register(ts8.SyntaxKind.NewExpression, (node, ctx) => {
685
+ NodeHandler.register(ts7.SyntaxKind.NewExpression, (node, ctx) => {
785
686
  const args = handleCallArgs(node, ctx);
786
687
  let output = `(new ${NodeHandler.handle(node.expression)}).constructor`;
787
688
  if (args.length)
@@ -791,12 +692,12 @@ NodeHandler.register(ts8.SyntaxKind.NewExpression, (node, ctx) => {
791
692
  function shouldHaveOuterPrefix(node, operator) {
792
693
  if (!assignmentOperators.has(operator))
793
694
  return false;
794
- if (!ts8.isIdentifier(node.left))
695
+ if (!ts7.isIdentifier(node.left))
795
696
  return false;
796
- const functionAncestor = ts8.findAncestor(node.parent, (n) => ts8.isFunctionLike(n));
697
+ const functionAncestor = ts7.findAncestor(node.parent, (n) => ts7.isFunctionLike(n));
797
698
  if (!functionAncestor)
798
699
  return false;
799
- if (!ts8.findAncestor(functionAncestor.parent, (n) => ts8.isFunctionLike(n)))
700
+ if (!ts7.findAncestor(functionAncestor.parent, (n) => ts7.isFunctionLike(n)))
800
701
  return false;
801
702
  const leftSymbol = checker.getSymbolAtLocation(node.left);
802
703
  if (!leftSymbol?.valueDeclaration)
@@ -806,26 +707,26 @@ function shouldHaveOuterPrefix(node, operator) {
806
707
  function isAssignmentChain(node, operator) {
807
708
  if (!assignmentOperators.has(operator))
808
709
  return false;
809
- 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) || ""))
810
711
  return true;
811
- if (ts8.hasOnlyExpressionInitializer(node.parent))
712
+ if (ts7.hasOnlyExpressionInitializer(node.parent))
812
713
  return true;
813
714
  return false;
814
715
  }
815
- NodeHandler.register(ts8.SyntaxKind.BinaryExpression, (node) => {
716
+ NodeHandler.register(ts7.SyntaxKind.BinaryExpression, (node) => {
816
717
  let operatorToken = getOperatorToken(node.operatorToken) || node.operatorToken.getText();
817
718
  if (isAssignmentChain(node, operatorToken))
818
719
  throw `Assignment chaining is not supported`;
819
720
  let right = NodeHandler.handle(node.right);
820
721
  if (nodeIsFunctionReference(node.right))
821
722
  right = asRef(right);
822
- if (ts8.isPropertyAccessExpression(node.left)) {
723
+ if (ts7.isPropertyAccessExpression(node.left)) {
823
724
  const leftType = checker.getTypeAtLocation(node.left.expression);
824
725
  const symbol = leftType.getProperty(node.left.name.text);
825
- if (symbol?.declarations?.some((decl) => ts8.isSetAccessor(decl))) {
726
+ if (symbol?.declarations?.some((decl) => ts7.isSetAccessor(decl))) {
826
727
  const objName = NodeHandler.handle(node.left.expression);
827
728
  const key = node.left.name.text;
828
- if (operatorToken !== "=" && symbol.declarations.some((decl) => ts8.isGetAccessor(decl)))
729
+ if (operatorToken !== "=" && symbol.declarations.some((decl) => ts7.isGetAccessor(decl)))
829
730
  throw `Can't handle '${operatorToken}' because '${objName}' doesn't have a getter '${key}'`;
830
731
  if (operatorToken === "+=" || operatorToken === "-=") {
831
732
  right = `${objName}.${key} ${operatorToken[0]} ${right}`;
@@ -840,22 +741,12 @@ NodeHandler.register(ts8.SyntaxKind.BinaryExpression, (node) => {
840
741
  left = "outer." + left;
841
742
  if (nodeIsFunctionReference(node.left))
842
743
  left = asRef(left);
843
- if (operatorToken === "or" && ts8.hasOnlyExpressionInitializer(node.parent)) {
744
+ if (operatorToken === "or" && ts7.hasOnlyExpressionInitializer(node.parent)) {
844
745
  return callUtilFunction("or_op", left, right);
845
746
  }
846
- if (operatorToken === "instanceof") {
847
- const rightSymbol = checker.getSymbolAtLocation(node.right);
848
- const classIdMember = rightSymbol?.members?.get(ts8.escapeLeadingUnderscores("classID"));
849
- if (!classIdMember) {
850
- throw `Can't handle this 'instanceof' operator because '${right}' doesn't have a 'classID' member, which is needed in GreyScript to check a type`;
851
- }
852
- const declaration = classIdMember.valueDeclaration;
853
- if (!declaration || !("initializer" in declaration) || !declaration.initializer) {
854
- throw `The 'classID' property of '${right}' isn't initialized`;
855
- }
856
- return `${left}.classID == typeof(${right})`;
857
- }
858
747
  switch (operatorToken) {
748
+ case "instanceof":
749
+ return `${left} isa ${right}`;
859
750
  case "??":
860
751
  return callUtilFunction("nullish_coalescing_op", left, right);
861
752
  case "??=":
@@ -882,41 +773,44 @@ NodeHandler.register(ts8.SyntaxKind.BinaryExpression, (node) => {
882
773
  operatorToken = "^";
883
774
  return `${left} ${operatorToken} ${right}`;
884
775
  });
885
- NodeHandler.register(ts8.SyntaxKind.ParenthesizedExpression, (node) => {
776
+ NodeHandler.register(ts7.SyntaxKind.ParenthesizedExpression, (node) => {
886
777
  return `(${NodeHandler.handle(node.expression)})`;
887
778
  });
888
779
  function handleUnaryExpression(node) {
889
780
  const operand = NodeHandler.handle(node.operand);
890
- const operator = ts8.tokenToString(node.operator);
891
- if (operator === "++")
892
- return `${operand} = ${operand} + 1`;
893
- if (operator === "--")
894
- return `${operand} = ${operand} - 1`;
895
- if (operator === "!") {
896
- if (ts8.isPrefixUnaryExpression(node.parent) && ts8.tokenToString(node.parent.operator) === "!") {
897
- return `(not ${operand})`;
898
- }
899
- return `not ${operand}`;
900
- }
901
- if (operator === "-")
902
- return `-${operand}`;
903
- if (operator === "+")
904
- return `str(${operand}).val()`;
905
- if (operator === "~")
906
- return `bitwise("~", ${operand})`;
907
- 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
+ }
908
802
  }
909
- NodeHandler.register(ts8.SyntaxKind.PrefixUnaryExpression, handleUnaryExpression);
910
- NodeHandler.register(ts8.SyntaxKind.PostfixUnaryExpression, handleUnaryExpression);
803
+ NodeHandler.register(ts7.SyntaxKind.PrefixUnaryExpression, handleUnaryExpression);
804
+ NodeHandler.register(ts7.SyntaxKind.PostfixUnaryExpression, handleUnaryExpression);
911
805
  function handleArrayLiteralExpression(node, ctx, itemStrings, out) {
912
806
  itemStrings ??= [];
913
807
  out ??= [];
914
808
  for (const item of node.elements) {
915
- if (!ts8.isSpreadElement(item)) {
809
+ if (!ts7.isSpreadElement(item)) {
916
810
  itemStrings.push(NodeHandler.handle(item));
917
811
  continue;
918
812
  }
919
- if (ts8.isArrayLiteralExpression(item.expression)) {
813
+ if (ts7.isArrayLiteralExpression(item.expression)) {
920
814
  handleArrayLiteralExpression(item.expression, ctx, itemStrings, out);
921
815
  continue;
922
816
  }
@@ -926,14 +820,14 @@ function handleArrayLiteralExpression(node, ctx, itemStrings, out) {
926
820
  }
927
821
  out.push(NodeHandler.handle(item.expression));
928
822
  }
929
- if ((!out.length || itemStrings.length) && !ts8.isSpreadElement(node.parent)) {
823
+ if ((!out.length || itemStrings.length) && !ts7.isSpreadElement(node.parent)) {
930
824
  out.push(`[${itemStrings.join(",")}]`);
931
825
  itemStrings.length = 0;
932
826
  }
933
827
  return out.join(" + ");
934
828
  }
935
- NodeHandler.register(ts8.SyntaxKind.ArrayLiteralExpression, handleArrayLiteralExpression);
936
- NodeHandler.register(ts8.SyntaxKind.TemplateExpression, (node) => {
829
+ NodeHandler.register(ts7.SyntaxKind.ArrayLiteralExpression, handleArrayLiteralExpression);
830
+ NodeHandler.register(ts7.SyntaxKind.TemplateExpression, (node) => {
937
831
  const head = NodeHandler.handle(node.head);
938
832
  const strings = [
939
833
  ...head ? [`"${head}"`] : [],
@@ -942,22 +836,22 @@ NodeHandler.register(ts8.SyntaxKind.TemplateExpression, (node) => {
942
836
  const output = strings.join(" + ");
943
837
  return output;
944
838
  });
945
- NodeHandler.register(ts8.SyntaxKind.TemplateHead, (node) => {
839
+ NodeHandler.register(ts7.SyntaxKind.TemplateHead, (node) => {
946
840
  return transformString(node.text);
947
841
  });
948
- NodeHandler.register(ts8.SyntaxKind.TemplateSpan, (node) => {
842
+ NodeHandler.register(ts7.SyntaxKind.TemplateSpan, (node) => {
949
843
  let output = NodeHandler.handle(node.expression);
950
- if (ts8.isBinaryExpression(node.expression))
844
+ if (ts7.isBinaryExpression(node.expression))
951
845
  output = `str(${output})`;
952
846
  if (node.literal.text)
953
847
  output += ` + "${transformString(node.literal.text)}"`;
954
848
  return output;
955
849
  });
956
- NodeHandler.register(ts8.SyntaxKind.NoSubstitutionTemplateLiteral, (node) => {
850
+ NodeHandler.register(ts7.SyntaxKind.NoSubstitutionTemplateLiteral, (node) => {
957
851
  return `"${transformString(node.text)}"`;
958
852
  });
959
- NodeHandler.register(ts8.SyntaxKind.ConditionalExpression, (node) => {
960
- 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)) {
961
855
  throw "Call expressions are not supported inside conditional expressions yet";
962
856
  }
963
857
  const condition = NodeHandler.handle(node.condition);
@@ -965,28 +859,28 @@ NodeHandler.register(ts8.SyntaxKind.ConditionalExpression, (node) => {
965
859
  const whenFalse = NodeHandler.handle(node.whenFalse);
966
860
  return callUtilFunction("conditional_expr", condition, whenTrue, whenFalse);
967
861
  });
968
- NodeHandler.register(ts8.SyntaxKind.ExpressionStatement, (node) => {
862
+ NodeHandler.register(ts7.SyntaxKind.ExpressionStatement, (node) => {
969
863
  return NodeHandler.handle(node.expression);
970
864
  });
971
- NodeHandler.register(ts8.SyntaxKind.NonNullExpression, (node) => {
865
+ NodeHandler.register(ts7.SyntaxKind.NonNullExpression, (node) => {
972
866
  return NodeHandler.handle(node.expression);
973
867
  });
974
- NodeHandler.register(ts8.SyntaxKind.AsExpression, (node) => {
868
+ NodeHandler.register(ts7.SyntaxKind.AsExpression, (node) => {
975
869
  return NodeHandler.handle(node.expression);
976
870
  });
977
- NodeHandler.register(ts8.SyntaxKind.DeleteExpression, (node) => {
978
- if (ts8.isPropertyAccessExpression(node.expression)) {
871
+ NodeHandler.register(ts7.SyntaxKind.DeleteExpression, (node) => {
872
+ if (ts7.isPropertyAccessExpression(node.expression)) {
979
873
  const pnode = node.expression;
980
874
  const left = NodeHandler.handle(pnode.expression);
981
875
  const leftType = checker.getTypeAtLocation(pnode.expression);
982
876
  const right = replaceIdentifier(NodeHandler.handle(pnode.name), leftType, pnode.name.text);
983
877
  return `${left}.remove("${right}")`;
984
878
  }
985
- if (ts8.isElementAccessExpression(node.expression)) {
879
+ if (ts7.isElementAccessExpression(node.expression)) {
986
880
  const pnode = node.expression;
987
881
  const left = NodeHandler.handle(pnode.expression);
988
882
  let right;
989
- if (ts8.isStringLiteral(pnode.argumentExpression)) {
883
+ if (ts7.isStringLiteral(pnode.argumentExpression)) {
990
884
  const leftType = checker.getTypeAtLocation(pnode.expression);
991
885
  right = `"${replaceIdentifier(pnode.argumentExpression.text, leftType, pnode.argumentExpression.text)}"`;
992
886
  } else {
@@ -994,11 +888,11 @@ NodeHandler.register(ts8.SyntaxKind.DeleteExpression, (node) => {
994
888
  }
995
889
  return `${left}.remove(${right})`;
996
890
  }
997
- throw `Cant handle delete expression for ${ts8.SyntaxKind[node.expression.kind]}`;
891
+ throw `Cant handle delete expression for ${ts7.SyntaxKind[node.expression.kind]}`;
998
892
  });
999
893
 
1000
894
  // src/visitors/functions.ts
1001
- import ts9 from "typescript";
895
+ import ts8 from "typescript";
1002
896
  function transpileFunctionBody(node) {
1003
897
  const params = node.parameters.map((param) => NodeHandler.handle(param)).join(", ");
1004
898
  const body = node.body ? NodeHandler.handle(node.body) : "";
@@ -1006,7 +900,7 @@ function transpileFunctionBody(node) {
1006
900
  ${body}
1007
901
  end function`;
1008
902
  }
1009
- NodeHandler.register(ts9.SyntaxKind.Block, (node) => {
903
+ NodeHandler.register(ts8.SyntaxKind.Block, (node) => {
1010
904
  const output = node.statements.map((val) => {
1011
905
  let statement = NodeHandler.handle(val);
1012
906
  statement = statement.split(`
@@ -1017,38 +911,38 @@ NodeHandler.register(ts9.SyntaxKind.Block, (node) => {
1017
911
  `);
1018
912
  return output;
1019
913
  });
1020
- NodeHandler.register(ts9.SyntaxKind.MethodDeclaration, (node) => {
914
+ NodeHandler.register(ts8.SyntaxKind.MethodDeclaration, (node) => {
1021
915
  return `${NodeHandler.handle(node.name)} = ${transpileFunctionBody(node)}`;
1022
916
  });
1023
- NodeHandler.register(ts9.SyntaxKind.FunctionDeclaration, (node) => {
917
+ NodeHandler.register(ts8.SyntaxKind.FunctionDeclaration, (node) => {
1024
918
  if (!node.body)
1025
919
  return "";
1026
- if (node.modifiers?.some((m) => m.kind === ts9.SyntaxKind.DeclareKeyword))
920
+ if (node.modifiers?.some((m) => m.kind === ts8.SyntaxKind.DeclareKeyword))
1027
921
  return "";
1028
922
  const name = node.name ? node.name.text : "anon";
1029
923
  return `${name} = ${transpileFunctionBody(node)}`;
1030
924
  });
1031
- NodeHandler.register(ts9.SyntaxKind.ArrowFunction, (node) => {
925
+ NodeHandler.register(ts8.SyntaxKind.ArrowFunction, (node) => {
1032
926
  const params = node.parameters.map((param) => NodeHandler.handle(param));
1033
- const body = ts9.isBlock(node.body) ? NodeHandler.handle(node.body) : ` return ${NodeHandler.handle(node.body)}`;
1034
- 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)) {
1035
929
  return "@" + createAnonFunction(body, params).name;
1036
930
  }
1037
- 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)) {
1038
932
  return `function(${params.join(", ")})
1039
933
  ${body}
1040
934
  end function`;
1041
935
  }
1042
- const kind = ts9.SyntaxKind[node.parent.kind];
936
+ const kind = ts8.SyntaxKind[node.parent.kind];
1043
937
  throw `This kind of arrow function is not yet supported (parent: ${kind} (${node.parent.kind}))`;
1044
938
  });
1045
- NodeHandler.register(ts9.SyntaxKind.FunctionExpression, (node) => {
939
+ NodeHandler.register(ts8.SyntaxKind.FunctionExpression, (node) => {
1046
940
  return transpileFunctionBody(node);
1047
941
  });
1048
942
 
1049
943
  // src/visitors/identifiers.ts
1050
- import ts10 from "typescript";
1051
- NodeHandler.register(ts10.SyntaxKind.Identifier, (node, ctx) => {
944
+ import ts9 from "typescript";
945
+ NodeHandler.register(ts9.SyntaxKind.Identifier, (node, ctx) => {
1052
946
  const type = checker.getTypeAtLocation(node);
1053
947
  let name = node.text;
1054
948
  if (name === "undefined")
@@ -1066,31 +960,31 @@ NodeHandler.register(ts10.SyntaxKind.Identifier, (node, ctx) => {
1066
960
  if (ctx.namedImports[ctx.currentFilePath]?.[name]) {
1067
961
  name = ctx.namedImports[ctx.currentFilePath][name];
1068
962
  }
1069
- if (ts10.isCallOrNewExpression(node.parent) && node != node.parent.expression) {
963
+ if (ts9.isCallOrNewExpression(node.parent) && node != node.parent.expression) {
1070
964
  if (nodeIsFunctionReference(node, type))
1071
965
  name = asRef(name);
1072
966
  }
1073
967
  return name;
1074
968
  });
1075
- NodeHandler.register(ts10.SyntaxKind.Parameter, (node) => {
969
+ NodeHandler.register(ts9.SyntaxKind.Parameter, (node) => {
1076
970
  const name = NodeHandler.handle(node.name);
1077
971
  if (!node.initializer)
1078
972
  return name;
1079
973
  const initializer = NodeHandler.handle(node.initializer);
1080
974
  const initializerType = checker.getTypeAtLocation(node.initializer);
1081
- if (initializerType.flags === ts10.TypeFlags.Object) {
975
+ if (initializerType.flags === ts9.TypeFlags.Object) {
1082
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`;
1083
977
  }
1084
978
  return `${name} = ${initializer}`;
1085
979
  });
1086
- NodeHandler.register(ts10.SyntaxKind.NumericLiteral, (node) => node.text);
1087
- NodeHandler.register(ts10.SyntaxKind.StringLiteral, (node) => `"${transformString(node.text)}"`);
1088
- NodeHandler.register(ts10.SyntaxKind.NullKeyword, () => "null");
1089
- NodeHandler.register(ts10.SyntaxKind.UndefinedKeyword, () => "null");
1090
- NodeHandler.register(ts10.SyntaxKind.FalseKeyword, () => "0");
1091
- NodeHandler.register(ts10.SyntaxKind.TrueKeyword, () => "1");
1092
- NodeHandler.register(ts10.SyntaxKind.ThisKeyword, (node) => {
1093
- 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));
1094
988
  if (propDeclarationAncestor) {
1095
989
  if (!propDeclarationAncestor.parent.name)
1096
990
  throw `Can't handle this 'this' keyword becuase the class doesn't have a name and it's needed for this case`;
@@ -1098,12 +992,12 @@ NodeHandler.register(ts10.SyntaxKind.ThisKeyword, (node) => {
1098
992
  }
1099
993
  return "self";
1100
994
  });
1101
- NodeHandler.register(ts10.SyntaxKind.SuperKeyword, (node) => {
1102
- 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))
1103
997
  return "super";
1104
998
  return "super.constructor";
1105
999
  });
1106
- NodeHandler.register(ts10.SyntaxKind.RegularExpressionLiteral, (node) => {
1000
+ NodeHandler.register(ts9.SyntaxKind.RegularExpressionLiteral, (node) => {
1107
1001
  const start = node.text.indexOf("/") + 1;
1108
1002
  const end = node.text.lastIndexOf("/");
1109
1003
  const flags = node.text.slice(end + 1);
@@ -1114,7 +1008,7 @@ NodeHandler.register(ts10.SyntaxKind.RegularExpressionLiteral, (node) => {
1114
1008
 
1115
1009
  // src/visitors/imports.ts
1116
1010
  import path3 from "node:path";
1117
- import ts11 from "typescript";
1011
+ import ts10 from "typescript";
1118
1012
  function importFile(filePath, ctx, returnResult) {
1119
1013
  let srcPath = path3.resolve(ctx.currentFolder, filePath);
1120
1014
  if (!path3.extname(srcPath))
@@ -1126,7 +1020,7 @@ function importFile(filePath, ctx, returnResult) {
1126
1020
  }
1127
1021
  return transpileSourceFile(source, ctx, returnResult);
1128
1022
  }
1129
- NodeHandler.register(ts11.SyntaxKind.ImportDeclaration, (node, ctx) => {
1023
+ NodeHandler.register(ts10.SyntaxKind.ImportDeclaration, (node, ctx) => {
1130
1024
  if (!node.importClause) {
1131
1025
  const moduleName = node.moduleSpecifier.text;
1132
1026
  const transpiledFile = importFile(moduleName, ctx, true);
@@ -1149,7 +1043,7 @@ NodeHandler.register(ts11.SyntaxKind.ImportDeclaration, (node, ctx) => {
1149
1043
  throw `Can't import default exports yet (imported as ${node.importClause.name.text})`;
1150
1044
  const bindings = node.importClause.namedBindings;
1151
1045
  if (bindings) {
1152
- if (ts11.isNamespaceImport(bindings)) {
1046
+ if (ts10.isNamespaceImport(bindings)) {
1153
1047
  ctx.namespaceImports[ctx.currentFilePath]?.add(bindings.name.text);
1154
1048
  } else {
1155
1049
  bindings.elements.forEach((el) => {
@@ -1163,6 +1057,125 @@ NodeHandler.register(ts11.SyntaxKind.ImportDeclaration, (node, ctx) => {
1163
1057
  return importFile(moduleSpecifier, ctx);
1164
1058
  });
1165
1059
 
1060
+ // src/visitors/objects.ts
1061
+ import ts11 from "typescript";
1062
+ function shouldGetSafely(node) {
1063
+ if (ts11.isNonNullExpression(node.parent))
1064
+ return false;
1065
+ if (valueIsBeingAssignedToNode(node))
1066
+ return false;
1067
+ const hasQuestionDot = !!node.questionDotToken;
1068
+ if (ts11.isPropertyAccessExpression(node)) {
1069
+ const rightType = checker.getTypeAtLocation(node.name);
1070
+ if (!rightType.isUnion())
1071
+ return hasQuestionDot;
1072
+ const hasUndefined = rightType.types.some((t) => t.flags === ts11.TypeFlags.Undefined);
1073
+ if (!hasUndefined)
1074
+ return false;
1075
+ if (!ts11.isCallExpression(node.parent))
1076
+ return true;
1077
+ if (node.parent.arguments.length)
1078
+ return false;
1079
+ } else {
1080
+ if (ts11.isNumericLiteral(node.argumentExpression))
1081
+ return false;
1082
+ }
1083
+ return hasQuestionDot;
1084
+ }
1085
+ NodeHandler.register(ts11.SyntaxKind.PropertyAccessExpression, (node, ctx) => {
1086
+ const left = NodeHandler.handle(node.expression);
1087
+ let right = NodeHandler.handle(node.name);
1088
+ right = replaceIdentifier(right, checker.getTypeAtLocation(node.expression), right);
1089
+ const nodeSymbol = checker.getSymbolAtLocation(node);
1090
+ if (ctx.namespaceImports[ctx.currentFilePath]?.has(left))
1091
+ return right;
1092
+ if (shouldGetSafely(node))
1093
+ return callUtilFunction("get_property", left, `"${right}"`);
1094
+ let output = `${left}.${right}`;
1095
+ output = replacePropertyAccess(output, nodeSymbol);
1096
+ if (nodeIsFunctionReference(node))
1097
+ output = asRef(output);
1098
+ return output;
1099
+ });
1100
+ NodeHandler.register(ts11.SyntaxKind.ElementAccessExpression, (node, ctx) => {
1101
+ const left = NodeHandler.handle(node.expression);
1102
+ let right;
1103
+ if (ts11.isStringLiteral(node.argumentExpression)) {
1104
+ const leftType = checker.getTypeAtLocation(node.expression);
1105
+ right = `"${replaceIdentifier(node.argumentExpression.text, leftType, node.argumentExpression.text)}"`;
1106
+ } else {
1107
+ right = NodeHandler.handle(node.argumentExpression);
1108
+ }
1109
+ if (shouldGetSafely(node)) {
1110
+ return callUtilFunction("get_property", left, `${right}`);
1111
+ }
1112
+ return `${left}[${right}]`;
1113
+ });
1114
+ function handleObjectLiteralExpression(node, ctx, currObj, outObjects, funcs) {
1115
+ currObj ??= [];
1116
+ outObjects ??= [];
1117
+ funcs ??= [];
1118
+ let objectName = "";
1119
+ if (ts11.hasOnlyExpressionInitializer(node.parent))
1120
+ objectName = NodeHandler.handle(node.parent.name);
1121
+ else if (ts11.isBinaryExpression(node.parent) && node === node.parent.right)
1122
+ objectName = NodeHandler.handle(node.parent.left);
1123
+ function pushObj() {
1124
+ if (!currObj?.length)
1125
+ return "";
1126
+ const res = currObj.filter((s) => s != "").join(",");
1127
+ if (res) {
1128
+ outObjects?.push(`{ ${res} }`);
1129
+ }
1130
+ currObj.length = 0;
1131
+ return res;
1132
+ }
1133
+ for (const item of node.properties) {
1134
+ if (ts11.isFunctionLike(item)) {
1135
+ funcs.push(NodeHandler.handle(item));
1136
+ continue;
1137
+ }
1138
+ if (ts11.isPropertyAssignment(item) && ts11.isFunctionLike(item.initializer)) {
1139
+ funcs.push(`${NodeHandler.handle(item.name)} = ${NodeHandler.handle(item.initializer)}`);
1140
+ continue;
1141
+ }
1142
+ if (ts11.isSpreadAssignment(item)) {
1143
+ if (ts11.isObjectLiteralExpression(item.expression)) {
1144
+ handleObjectLiteralExpression(item.expression, ctx, currObj, outObjects);
1145
+ continue;
1146
+ }
1147
+ if (ts11.isIdentifier(item.expression)) {
1148
+ pushObj();
1149
+ outObjects.push(NodeHandler.handle(item.expression));
1150
+ continue;
1151
+ }
1152
+ if (ts11.isArrayLiteralExpression(item.expression)) {
1153
+ pushObj();
1154
+ outObjects.push(NodeHandler.handle(item.expression));
1155
+ continue;
1156
+ }
1157
+ }
1158
+ currObj.push(NodeHandler.handle(item));
1159
+ }
1160
+ pushObj();
1161
+ if (!outObjects.length)
1162
+ outObjects.push("{}");
1163
+ let output = outObjects[0];
1164
+ if (outObjects.length > 1) {
1165
+ output = callUtilFunction("assign_objects", output, `[${outObjects.slice(1).join(",")}]`);
1166
+ }
1167
+ if (funcs.length) {
1168
+ if (ts11.isPropertyAssignment(node.parent) || !objectName) {
1169
+ throw "You can't have method declarations inside an object that is not being assigned to a variable";
1170
+ }
1171
+ output += `
1172
+ ` + funcs.map((func) => `${objectName}.${func}`).join(`
1173
+ `);
1174
+ }
1175
+ return output;
1176
+ }
1177
+ NodeHandler.register(ts11.SyntaxKind.ObjectLiteralExpression, handleObjectLiteralExpression);
1178
+
1166
1179
  // src/visitors/statements.ts
1167
1180
  import ts12 from "typescript";
1168
1181
  NodeHandler.register(ts12.SyntaxKind.ForStatement, (node) => {
@@ -1540,7 +1553,7 @@ var extensionFunctions = {
1540
1553
  "Array.includes": [
1541
1554
  "list.includes = function(value, pos = 0)",
1542
1555
  "\tindex = self.indexOf(value)",
1543
- "\tif index == null then return false",
1556
+ "\tif index == null then return 0",
1544
1557
  "\tif pos < 0 then pos = 0",
1545
1558
  "\treturn index >= pos",
1546
1559
  "end function"
@@ -1561,6 +1574,24 @@ var extensionFunctions = {
1561
1574
  "\treturn deleted",
1562
1575
  "end function"
1563
1576
  ].join(`
1577
+ `),
1578
+ "Array.fill": [
1579
+ "list.fill = function(value, start, endI)",
1580
+ "\tlen = self.len",
1581
+ "\tif not len then return self",
1582
+ "\tif start == null then start = 0",
1583
+ "\tif endI == null then endI = len - 1",
1584
+ "\tif start < 0 then start = len + start",
1585
+ "\tif start < 0 then start = 0",
1586
+ "\tif endI < 0 then endI = len + endI",
1587
+ "\tif endI < 0 then endI = 0",
1588
+ "\tfor i in range(start, endI-1, 1)",
1589
+ "\t\tif i >= len then break",
1590
+ "\t\tself[i] = value",
1591
+ "\tend for",
1592
+ "\treturn self",
1593
+ "end function"
1594
+ ].join(`
1564
1595
  `),
1565
1596
  "String.startsWith": [
1566
1597
  "string.startsWith = function(search, pos = 0)",
@@ -1586,7 +1617,7 @@ var extensionFunctions = {
1586
1617
  "String.includes": [
1587
1618
  "string.includes = function(search, pos = 0)",
1588
1619
  "\tindex = self.indexOf(search)",
1589
- "\tif index == null then return false",
1620
+ "\tif index == null then return 0",
1590
1621
  "\tif pos < 0 then pos = 0",
1591
1622
  "\treturn index >= pos",
1592
1623
  "end function"
@@ -1719,14 +1750,12 @@ end function`,
1719
1750
  return @left
1720
1751
  end function`,
1721
1752
  is_type: `is_type = function(value, type)
1722
- if typeof(value) == type then return 1
1723
- return 0
1753
+ return typeof(value) == type
1724
1754
  end function`,
1725
1755
  conditional_expr: `conditional_expr = function(cond, when_true, when_false)
1726
1756
  if cond then return when_true
1727
1757
  return when_false
1728
- end function`,
1729
- ...extensionFunctions
1758
+ end function`
1730
1759
  };
1731
1760
  function createAnonFunction(body, params) {
1732
1761
  const defaultParams = new Array(3).fill(0).map((_, i) => `param${i}`);
@@ -1781,8 +1810,7 @@ function transpileProgram(entryFileRelativePath) {
1781
1810
  utilitiesToInsert.clear();
1782
1811
  }
1783
1812
  console.log(`Transpiling took ${Date.now() - start} ms`);
1784
- return ctx.output.join(`
1785
- `);
1813
+ return ctx.output;
1786
1814
  }
1787
1815
  function transpileSourceFile(sourceFile, ctx, returnResult) {
1788
1816
  if (ctx.visitedFiles[sourceFile.fileName])
@@ -1834,27 +1862,54 @@ for (let i = 2;i < process.argv.length; i++) {
1834
1862
  args.push(arg);
1835
1863
  }
1836
1864
  var root = findProjectRoot(process.cwd());
1865
+ var outDirPath = `${root}/out`;
1837
1866
  if (!command) {
1838
1867
  console.error("No command specified.");
1839
1868
  process.exit(2);
1840
1869
  }
1870
+ function createOutputFile(fileIndex, basename, content) {
1871
+ if (fileIndex > 0)
1872
+ basename = `${basename}-${fileIndex}`;
1873
+ const outFileName = args.length > 1 ? args[1] : `${basename}.src`;
1874
+ const outFilePath = path5.join(outDirPath, outFileName);
1875
+ fs3.writeFileSync(outFilePath, content);
1876
+ }
1841
1877
  if (command === "transpile") {
1842
1878
  if (!args.length) {
1843
1879
  console.error("No entry file specified.");
1844
1880
  process.exit(2);
1845
1881
  }
1846
1882
  const entryFile = args[0];
1847
- const output = transpileProgram(entryFile);
1883
+ const basename = path5.basename(entryFile, ".ts");
1884
+ const transpiledStatements = transpileProgram(entryFile);
1848
1885
  if (flags.includes("--print") || flags.includes("-p")) {
1849
- console.log(output);
1886
+ console.log(transpiledStatements.join(`
1887
+ `));
1850
1888
  process.exit(0);
1851
1889
  }
1852
- const outDirPath = `${root}/out`;
1853
1890
  if (!fs3.existsSync(outDirPath))
1854
1891
  fs3.mkdirSync(outDirPath);
1855
- const outFileName = args.length > 1 ? args[1] : `${path5.basename(entryFile).replace(".ts", ".src")}`;
1856
- const outFilePath = path5.join(outDirPath, outFileName);
1857
- fs3.writeFileSync(outFilePath, output);
1892
+ let content = "";
1893
+ const fileContents = [];
1894
+ while (transpiledStatements.length) {
1895
+ const statement = transpiledStatements.shift();
1896
+ if (content.length + statement.length > 155000 && content.length) {
1897
+ fileContents.push(content);
1898
+ content = "";
1899
+ continue;
1900
+ }
1901
+ content += statement + `
1902
+ `;
1903
+ }
1904
+ if (content.length)
1905
+ fileContents.push(content);
1906
+ for (let i = 0;i < fileContents.length; i++) {
1907
+ if (i + 1 < fileContents.length) {
1908
+ const nextFileName = `${basename}-${i + 1}.src`;
1909
+ fileContents[i] += `import_code("${nextFileName}")`;
1910
+ }
1911
+ createOutputFile(i, basename, fileContents[i]);
1912
+ }
1858
1913
  } else {
1859
1914
  console.log(`Invalid command: ${command}`);
1860
1915
  process.exit(127);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grey-ts/transpiler",
3
- "version": "1.3.0",
3
+ "version": "1.4.1",
4
4
  "description": "Transpiles TypeScript into GreyScript",
5
5
  "author": "Okka",
6
6
  "module": "src/index.ts",
@@ -34,12 +34,11 @@
34
34
  "build": "bun run scripts/build.ts"
35
35
  },
36
36
  "devDependencies": {
37
- "@types/bun": "latest"
37
+ "@types/bun": "latest",
38
+ "@grey-ts/types": "latest"
38
39
  },
39
40
  "peerDependencies": {
40
- "typescript": "^5"
41
- },
42
- "dependencies": {
43
- "@grey-ts/types": "^2.1.0"
41
+ "typescript": "^5",
42
+ "@grey-ts/types": "^2.2.0"
44
43
  }
45
44
  }