@grey-ts/transpiler 0.3.0 → 0.3.2

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 +628 -624
  2. package/package.json +2 -1
package/dist/index.js CHANGED
@@ -6,20 +6,58 @@ import path5 from "node:path";
6
6
 
7
7
  // src/transpiler.ts
8
8
  import * as fs2 from "node:fs";
9
- import * as path2 from "node:path";
10
- import ts3 from "typescript";
9
+ import * as path4 from "node:path";
10
+ import ts14 from "typescript";
11
11
 
12
- // src/parser.ts
12
+ // src/nodeHandler.ts
13
13
  import ts from "typescript";
14
+
15
+ class NodeHandler {
16
+ static handlers = new Map;
17
+ static transpileContext;
18
+ static register(kind, handler) {
19
+ if (this.handlers.has(kind))
20
+ throw `${ts.SyntaxKind[kind]} (${kind}) is already registered`;
21
+ this.handlers.set(kind, handler);
22
+ }
23
+ static handle(node) {
24
+ const handler = this.handlers.get(node.kind);
25
+ if (!handler) {
26
+ console.log(`Unsupported syntax ${ts.SyntaxKind[node.kind]} (kind ${node.kind}) was not transpiled: ${node.getText()}`);
27
+ this.printLineAndCol(node);
28
+ return "null";
29
+ }
30
+ try {
31
+ const result = handler(node, this.transpileContext);
32
+ return result;
33
+ } catch (error) {
34
+ console.error(error);
35
+ this.printLineAndCol(node);
36
+ return "null";
37
+ }
38
+ }
39
+ static printLineAndCol(node) {
40
+ const source = node.getSourceFile();
41
+ const lineAndChar = source.getLineAndCharacterOfPosition(node.pos);
42
+ console.log(`At ${source.fileName}: line ${lineAndChar.line + 1}, col ${lineAndChar.character + 1}`);
43
+ }
44
+ }
45
+ NodeHandler.register(ts.SyntaxKind.TypeAliasDeclaration, () => "");
46
+ NodeHandler.register(ts.SyntaxKind.InterfaceDeclaration, () => "");
47
+ NodeHandler.register(ts.SyntaxKind.EndOfFileToken, () => "");
48
+ NodeHandler.register(ts.SyntaxKind.EmptyStatement, () => "");
49
+
50
+ // src/parser.ts
51
+ import ts2 from "typescript";
14
52
  function parseCode(fileName, code) {
15
- return ts.createSourceFile(fileName, code, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
53
+ return ts2.createSourceFile(fileName, code, ts2.ScriptTarget.Latest, true, ts2.ScriptKind.TS);
16
54
  }
17
55
  var parser_default = parseCode;
18
56
 
19
57
  // src/utils.ts
20
58
  import fs from "node:fs";
21
59
  import path from "node:path";
22
- import ts2 from "typescript";
60
+ import ts3 from "typescript";
23
61
 
24
62
  // src/replaceKeywords.ts
25
63
  var apiNameMap = {
@@ -240,7 +278,7 @@ var knownOperators = new Set([
240
278
  "instanceof"
241
279
  ]);
242
280
  function getOperatorToken(node) {
243
- let operatorToken = ts2.tokenToString(node.kind);
281
+ let operatorToken = ts3.tokenToString(node.kind);
244
282
  if (!operatorToken)
245
283
  return null;
246
284
  if (!knownOperators.has(operatorToken))
@@ -261,9 +299,9 @@ function transformString(value) {
261
299
  return value;
262
300
  }
263
301
  function nodeIsFunctionReference(node, type) {
264
- if (ts2.isCallOrNewExpression(node) || ts2.isCallOrNewExpression(node.parent) && node === node.parent.expression)
302
+ if (ts3.isCallOrNewExpression(node) || ts3.isCallOrNewExpression(node.parent) && node === node.parent.expression)
265
303
  return false;
266
- if (ts2.isFunctionLike(node))
304
+ if (ts3.isFunctionLike(node))
267
305
  return false;
268
306
  type ??= checker.getTypeAtLocation(node);
269
307
  if (!type.getCallSignatures().length)
@@ -307,7 +345,7 @@ function replaceIdentifier(original, type, propertyName) {
307
345
  break;
308
346
  }
309
347
  } else {
310
- symbol = type.types.find((t) => t.flags !== ts2.TypeFlags.Undefined && t.symbol)?.symbol;
348
+ symbol = type.types.find((t) => t.flags !== ts3.TypeFlags.Undefined && t.symbol)?.symbol;
311
349
  }
312
350
  } else {
313
351
  symbol = propertyName ? type.getProperty(propertyName) : type.symbol;
@@ -347,443 +385,96 @@ function callUtilFunction(functionName, ...params) {
347
385
  return `${functionName}(${params.join(", ")})`;
348
386
  }
349
387
 
350
- // src/transpiler.ts
351
- class NodeHandler {
352
- static handlers = new Map;
353
- static transpileContext;
354
- static register(kind, handler) {
355
- if (this.handlers.has(kind))
356
- throw `${ts3.SyntaxKind[kind]} (${kind}) is already registered`;
357
- this.handlers.set(kind, handler);
358
- }
359
- static handle(node) {
360
- const handler = this.handlers.get(node.kind);
361
- if (!handler) {
362
- console.log(`Unsupported syntax ${ts3.SyntaxKind[node.kind]} (kind ${node.kind}) was not transpiled: ${node.getText()}`);
363
- this.printLineAndCol(node);
364
- return "null";
365
- }
366
- try {
367
- const result = handler(node, this.transpileContext);
368
- return result;
369
- } catch (error) {
370
- console.error(error);
371
- this.printLineAndCol(node);
372
- return "null";
388
+ // src/visitors/assignments.ts
389
+ import ts4 from "typescript";
390
+ NodeHandler.register(ts4.SyntaxKind.PropertyAssignment, (node) => {
391
+ let right = NodeHandler.handle(node.initializer);
392
+ if (nodeIsFunctionReference(node.initializer))
393
+ right = asRef(right);
394
+ if (ts4.isNumericLiteral(node.name) || ts4.isStringLiteral(node.name) || ts4.isComputedPropertyName(node.name))
395
+ return `${NodeHandler.handle(node.name)}: ${right}`;
396
+ return `"${NodeHandler.handle(node.name)}": ${right}`;
397
+ });
398
+ NodeHandler.register(ts4.SyntaxKind.ShorthandPropertyAssignment, (node) => {
399
+ const name = NodeHandler.handle(node.name);
400
+ return `"${name}": ${nodeIsFunctionReference(node.name) ? asRef(name) : name}`;
401
+ });
402
+ NodeHandler.register(ts4.SyntaxKind.ComputedPropertyName, (node) => {
403
+ return NodeHandler.handle(node.expression);
404
+ });
405
+
406
+ // src/visitors/classes.ts
407
+ import ts5 from "typescript";
408
+ NodeHandler.register(ts5.SyntaxKind.ClassDeclaration, (node) => {
409
+ if (node.modifiers?.some((m) => m.kind === ts5.SyntaxKind.DeclareKeyword))
410
+ return "";
411
+ const name = node.name ? node.name.text : "anon";
412
+ const extensions = node.heritageClauses?.filter((h) => h.token === ts5.SyntaxKind.ExtendsKeyword);
413
+ let output = `${name} = {}`;
414
+ if (extensions && extensions.length && extensions[0].types.length)
415
+ output = `${name} = new ${NodeHandler.handle(extensions[0].types[0].expression)}`;
416
+ for (const member of node.members) {
417
+ if (ts5.isMethodDeclaration(member) || ts5.isConstructorDeclaration(member)) {
418
+ if (!member.body)
419
+ continue;
420
+ output += `
421
+ ${name}.${NodeHandler.handle(member)}`;
422
+ } else if (ts5.isPropertyDeclaration(member)) {
423
+ output += `
424
+ ${name}.${NodeHandler.handle(member)}`;
425
+ } else {
426
+ output += `
427
+ ${name}.${NodeHandler.handle(member)}`;
373
428
  }
374
429
  }
375
- static printLineAndCol(node) {
376
- const source = node.getSourceFile();
377
- const lineAndChar = source.getLineAndCharacterOfPosition(node.pos);
378
- console.log(`At ${source.fileName}: line ${lineAndChar.line + 1}, col ${lineAndChar.character + 1}`);
379
- }
380
- }
381
- NodeHandler.register(ts3.SyntaxKind.TypeAliasDeclaration, () => "");
382
- NodeHandler.register(ts3.SyntaxKind.InterfaceDeclaration, () => "");
383
- NodeHandler.register(ts3.SyntaxKind.EndOfFileToken, () => "");
384
- NodeHandler.register(ts3.SyntaxKind.EmptyStatement, () => "");
385
- var program;
386
- var checker;
387
- var anonFunctions = new Map;
388
- var calledUtilFunctions = new Set;
389
- var utilFunctions2 = {
390
- get_property: [
391
- "get_property = function(obj, key)",
392
- "\tif not obj then return null",
393
- "\tif obj.hasIndex(key) then return obj[key]",
394
- "\tisaobj = obj",
395
- '\twhile isaobj.hasIndex("__isa")',
396
- '\t\tisaobj = obj["__isa"]',
397
- "\t\tif isaobj.hasIndex(key) then",
398
- "\t\t\tval = obj[key]",
399
- "\t\t\treturn val",
400
- "\t\tend if",
401
- "\tend while",
402
- "\treturn null",
403
- "end function"
404
- ].join(`
405
- `),
406
- assign_objects: [
407
- "assign_objects = function(target, source1, source2, source3)",
408
- "\tassign_to_list = function(target, source)",
409
- "\t\tif source isa list then",
410
- "\t\t\tfor i in range(0, source.len - 1, 1)",
411
- "\t\t\t\tif target.len <= i then target.push(null)",
412
- "\t\t\t\ttarget[i] = source[i]",
413
- "\t\t\tend for",
414
- "\t\telse if source isa map then",
415
- "\t\t\tfor item in source",
416
- "\t\t\t\tkey = str(item.key).to_int",
417
- "\t\t\t\tif key isa number then target[key] = item.value",
418
- "\t\t\tend for",
419
- "\t\tend if",
420
- "\t\treturn target",
421
- "\tend function",
422
- "\tcounter = 0",
423
- "\tassign_object = function(target, source)",
424
- "\t\tif target isa list then return assign_to_list(target, source)",
425
- "\t\tif source isa list then",
426
- "\t\t\tfor i in range(0, source.len - 1, 1)",
427
- "\t\t\t\ttarget[str(i)] = source[i]",
428
- "\t\t\tend for",
429
- "\t\telse if source isa map then",
430
- "\t\t\tfor item in source",
431
- "\t\t\t\ttarget[item.key] = item.value",
432
- "\t\t\tend for",
433
- "\t\telse",
434
- "\t\t\ttarget[str(outer.counter)] = source",
435
- "\t\t\touter.counter = outer.counter + 1",
436
- "\t\tend if",
437
- "\tend function",
438
- "\tif source1 isa list then",
439
- "\t\tif target isa list then return assign_to_list(target, source1)",
440
- "\t\tfor source in source1",
441
- "\t\t\tassign_object(target, source)",
442
- "\t\tend for",
443
- "\t\treturn target",
444
- "\tend if",
445
- "\tif source1 then assign_object(target, source1)",
446
- "\tif source2 then assign_object(target, source2)",
447
- "\tif source3 then assign_object(target, source3)",
448
- "\treturn target",
449
- "end function"
450
- ].join(`
451
- `),
452
- array_map: [
453
- "array_map = function(array, callback)",
454
- "\tindex = 0",
455
- "\tout = []",
456
- "\tfor item in array",
457
- "\t\tout.push(callback(item, index, array))",
458
- "\t\tindex = index + 1",
459
- "\tend for",
460
- "\treturn out",
461
- "end function"
462
- ].join(`
463
- `),
464
- array_filter: [
465
- "array_filter = function(array, predicate)",
466
- "\tindex = 0",
467
- "\tout = []",
468
- "\tfor item in array",
469
- "\t\tif predicate(item, index, array) then out.push(item)",
470
- "\t\tindex = index + 1",
471
- "\tend for",
472
- "\treturn out",
473
- "end function"
474
- ].join(`
475
- `),
476
- array_find: [
477
- "array_find = function(array, predicate)",
478
- "\tindex = 0",
479
- "\tfor item in array",
480
- "\t\tif predicate(item, index, array) then return item",
481
- "\t\tindex = index + 1",
482
- "\tend for",
483
- "\treturn null",
484
- "end function"
485
- ].join(`
486
- `),
487
- array_some: [
488
- "array_some = function(array, predicate)",
489
- "\tindex = 0",
490
- "\tfor item in array",
491
- "\t\tif predicate(item, index, array) then return 1",
492
- "\t\tindex = index + 1",
493
- "\tend for",
494
- "\treturn 0",
495
- "end function"
496
- ].join(`
497
- `),
498
- array_every: [
499
- "array_every = function(array, predicate)",
500
- "\tindex = 0",
501
- "\tfor item in array",
502
- "\t\tif not predicate(item, index, array) then return 0",
503
- "\t\tindex = index + 1",
504
- "\tend for",
505
- "\treturn 1",
506
- "end function"
507
- ].join(`
508
- `),
509
- array_concat: [
510
- "array_concat = function(target, items)",
511
- "\tout = target[0:]",
512
- "\tfor item in items",
513
- "\t\tif item isa list then out = out + item else out.push(item)",
514
- "\tend for",
515
- "\treturn out",
516
- "end function"
517
- ].join(`
518
- `),
519
- array_push: [
520
- "array_push = function(target, items)",
521
- "\tfor item in items",
522
- "\t\ttarget.push(item)",
523
- "\tend for",
524
- "\treturn target.len",
525
- "end function"
526
- ].join(`
527
- `),
528
- array_unshift: [
529
- "array_unshift = function(target, items)",
530
- "\tif not items.len then return target.len",
531
- "\tfor i in range(items.len-1)",
532
- "\t\ttarget.insert(0, items[i])",
533
- "\tend for",
534
- "\treturn target.len",
535
- "end function"
536
- ].join(`
537
- `),
538
- array_reverse: `array_reverse = function(arr)
539
- arr.reverse
540
- return arr
541
- end function`,
542
- str_starts_with: [
543
- "str_starts_with = function(str, search, pos = 0)",
544
- "\tif pos < 0 then pos = 0",
545
- "\treturn str.indexOf(search) == pos",
546
- "end function"
547
- ].join(`
548
- `),
549
- str_ends_with: [
550
- "str_ends_with = function(str, search, pos = null)",
551
- "\tif pos == null then pos = str.len",
552
- "\tif pos < 0 then pos = 0",
553
- "\treturn str.indexOf(search) + search.len == pos",
554
- "end function"
555
- ].join(`
556
- `),
557
- str_repeat: [
558
- "str_repeat = function(str, count = 0)",
559
- '\tif count <= 0 then return ""',
560
- "\tif count == 1 then return str",
561
- "\tout = str",
562
- "\tfor i in range(count-2)",
563
- "\t\tout = out + str",
564
- "\tend for",
565
- "\treturn out",
566
- "end function"
567
- ].join(`
568
- `),
569
- math_min: [
570
- "math_min = function(numbers)",
571
- "\tcurr_min = null",
572
- "\tfor num in numbers",
573
- "\t\tif curr_min == null or num < curr_min then curr_min = num",
574
- "\tend for",
575
- "\treturn curr_min",
576
- "end function"
577
- ].join(`
578
- `),
579
- math_max: [
580
- "math_max = function(numbers)",
581
- "\tcurr_max = null",
582
- "\tfor num in numbers",
583
- "\t\tif curr_max == null or num > curr_max then curr_max = num",
584
- "\tend for",
585
- "\treturn curr_max",
586
- "end function"
587
- ].join(`
588
- `),
589
- nullish_coalescing_op: `nullish_coalescing_op = function(left, right)
590
- if left == null then return @right
591
- return @left
592
- end function`,
593
- or_op: `or_op = function(left, right)
594
- if not left then return @right
595
- return @left
596
- end function`,
597
- is_type: `is_type = function(value, type)
598
- if typeof(value) == type then return 1
599
- return 0
600
- end function`,
601
- conditional_expr: `conditional_expr = function(cond, when_true, when_false)
602
- if cond then return when_true
603
- return when_false
604
- end function`
605
- };
606
- function createAnonFunction(body, params) {
607
- const defaultParams = new Array(3).fill(0).map((_, i) => `param${i}`);
608
- const nextName = `func_${anonFunctions.size}`;
609
- const paramString = Object.assign(defaultParams, params).join(",");
610
- const result = `${nextName} = function(${paramString})
611
- ${body}
612
- end function`;
613
- anonFunctions.set(nextName, result);
614
- return { name: nextName, str: result };
615
- }
616
- function transpileProgram(entryFileRelativePath) {
617
- const ctx = {
618
- currentFolder: "",
619
- currentFilePath: path2.resolve(process.cwd(), entryFileRelativePath),
620
- namedImports: {},
621
- namespaceImports: {},
622
- visitedFiles: {},
623
- output: []
624
- };
625
- NodeHandler.transpileContext = ctx;
626
- ctx.currentFolder = path2.dirname(ctx.currentFilePath);
627
- if (!fs2.existsSync(ctx.currentFilePath)) {
628
- console.error(`Error: file '${ctx.currentFilePath}' doesn't exist`);
629
- process.exit(1);
630
- }
631
- let start = Date.now();
632
- const tsconfigPath = findProjectRoot(process.cwd(), "tsconfig.json") + "/tsconfig.json";
633
- const res = ts3.readConfigFile(tsconfigPath, ts3.sys.readFile);
634
- const parsed = ts3.parseJsonConfigFileContent(res.config, ts3.sys, path2.dirname(tsconfigPath));
635
- if (!parsed.options.types)
636
- parsed.options.types = [];
637
- if (!parsed.options.types.includes("@grey-ts/types")) {
638
- parsed.options.types.push("@grey-ts/types");
639
- }
640
- parsed.options.noLib = true;
641
- program = ts3.createProgram({
642
- rootNames: parsed.fileNames,
643
- options: parsed.options
644
- });
645
- console.log(`Program creation took ${Date.now() - start} ms`);
646
- start = Date.now();
647
- checker = program.getTypeChecker();
648
- const entry = program.getSourceFile(ctx.currentFilePath);
649
- if (!entry) {
650
- console.error(`Error: failed to find '${ctx.currentFilePath}' from the included sources`);
651
- process.exit(1);
652
- }
653
- transpileSourceFile(entry, ctx);
654
- if (anonFunctions.size) {
655
- for (const declaration of anonFunctions.values())
656
- ctx.output.unshift(declaration);
657
- anonFunctions.clear();
658
- }
659
- if (calledUtilFunctions.size) {
660
- for (const call of calledUtilFunctions.keys())
661
- ctx.output.unshift(utilFunctions2[call]);
662
- calledUtilFunctions.clear();
663
- }
664
- console.log(`Transpiling took ${Date.now() - start} ms`);
665
- return ctx.output.join(`
666
- `);
667
- }
668
- function transpileSourceFile(sourceFile, ctx, returnResult) {
669
- if (ctx.visitedFiles[sourceFile.fileName])
670
- return "";
671
- ctx.visitedFiles[sourceFile.fileName] = true;
672
- if (sourceFile.isDeclarationFile)
673
- return "";
674
- if (program.isSourceFileDefaultLibrary(sourceFile) || program.isSourceFileFromExternalLibrary(sourceFile))
675
- return "";
676
- const prevFile = ctx.currentFilePath;
677
- ctx.currentFilePath = sourceFile.fileName;
678
- ctx.currentFolder = path2.dirname(sourceFile.fileName);
679
- ctx.namedImports[sourceFile.fileName] = {};
680
- ctx.namespaceImports[sourceFile.fileName] = new Set;
681
- const output = [];
682
- sourceFile.forEachChild((node) => {
683
- const result = NodeHandler.handle(node);
684
- if (!result)
685
- return;
686
- if (!returnResult)
687
- ctx.output.push(result);
688
- else
689
- output.push(result);
690
- });
691
- ctx.currentFilePath = prevFile;
692
- ctx.currentFolder = path2.dirname(prevFile);
693
- return output.join(`
694
- `);
695
- }
696
-
697
- // src/visitors/assignments.ts
698
- import ts4 from "typescript";
699
- NodeHandler.register(ts4.SyntaxKind.PropertyAssignment, (node) => {
700
- let right = NodeHandler.handle(node.initializer);
701
- if (nodeIsFunctionReference(node.initializer))
702
- right = asRef(right);
703
- if (ts4.isNumericLiteral(node.name) || ts4.isStringLiteral(node.name) || ts4.isComputedPropertyName(node.name))
704
- return `${NodeHandler.handle(node.name)}: ${right}`;
705
- return `"${NodeHandler.handle(node.name)}": ${right}`;
706
- });
707
- NodeHandler.register(ts4.SyntaxKind.ShorthandPropertyAssignment, (node) => {
708
- const name = NodeHandler.handle(node.name);
709
- return `"${name}": ${nodeIsFunctionReference(node.name) ? asRef(name) : name}`;
710
- });
711
- NodeHandler.register(ts4.SyntaxKind.ComputedPropertyName, (node) => {
712
- return NodeHandler.handle(node.expression);
713
- });
714
-
715
- // src/visitors/classes.ts
716
- import ts5 from "typescript";
717
- NodeHandler.register(ts5.SyntaxKind.ClassDeclaration, (node) => {
718
- if (node.modifiers?.some((m) => m.kind === ts5.SyntaxKind.DeclareKeyword))
719
- return "";
720
- const name = node.name ? node.name.text : "anon";
721
- const extensions = node.heritageClauses?.filter((h) => h.token === ts5.SyntaxKind.ExtendsKeyword);
722
- let output = `${name} = {}`;
723
- if (extensions && extensions.length && extensions[0].types.length)
724
- output = `${name} = new ${NodeHandler.handle(extensions[0].types[0].expression)}`;
725
- for (const member of node.members) {
726
- if (ts5.isMethodDeclaration(member) || ts5.isConstructorDeclaration(member)) {
727
- if (!member.body)
728
- continue;
729
- output += `
730
- ${name}.${NodeHandler.handle(member)}`;
731
- } else if (ts5.isPropertyDeclaration(member)) {
732
- output += `
733
- ${name}.${NodeHandler.handle(member)}`;
734
- } else {
735
- output += `
736
- ${name}.${NodeHandler.handle(member)}`;
737
- }
738
- }
739
- return output;
740
- });
741
- NodeHandler.register(ts5.SyntaxKind.Constructor, (node) => {
742
- if (!node.body)
743
- return "";
744
- const params = node.parameters.map((param) => NodeHandler.handle(param)).join(", ");
745
- const body = NodeHandler.handle(node.body);
746
- return `constructor = function(${params})
747
- ${body}
748
- return self
749
- end function`;
750
- });
751
- NodeHandler.register(ts5.SyntaxKind.GetAccessor, (node) => {
752
- if (!node.body)
753
- return "";
754
- const body = NodeHandler.handle(node.body);
755
- return `${NodeHandler.handle(node.name)} = function
756
- ${body}
757
- end function`;
758
- });
759
- NodeHandler.register(ts5.SyntaxKind.SetAccessor, (node) => {
760
- if (!node.body)
761
- return "";
762
- const body = NodeHandler.handle(node.body);
763
- const params = node.parameters.map((param) => NodeHandler.handle(param));
764
- return `set_${NodeHandler.handle(node.name)} = function(${params.join(", ")})
765
- ${body}
766
- end function`;
767
- });
768
-
769
- // src/visitors/expressions.ts
770
- import ts7 from "typescript";
771
-
772
- // src/callTransformer.ts
773
- import path3 from "node:path";
774
- import ts6 from "typescript";
775
- class CallTransformer {
776
- static handlers = new Map;
777
- static register(symbolFullName, handler) {
778
- if (this.handlers.has(symbolFullName))
779
- throw `Handler for '${symbolFullName}' was already registered`;
780
- this.handlers.set(symbolFullName, handler);
781
- }
782
- static handle(symbolFullName, functionName, callArgs, node, ctx) {
783
- const handler = this.handlers.get(symbolFullName);
784
- if (!handler)
785
- return null;
786
- return handler(functionName, callArgs, node, ctx);
430
+ return output;
431
+ });
432
+ NodeHandler.register(ts5.SyntaxKind.Constructor, (node) => {
433
+ if (!node.body)
434
+ return "";
435
+ const params = node.parameters.map((param) => NodeHandler.handle(param)).join(", ");
436
+ const body = NodeHandler.handle(node.body);
437
+ return `constructor = function(${params})
438
+ ${body}
439
+ return self
440
+ end function`;
441
+ });
442
+ NodeHandler.register(ts5.SyntaxKind.GetAccessor, (node) => {
443
+ if (!node.body)
444
+ return "";
445
+ const body = NodeHandler.handle(node.body);
446
+ return `${NodeHandler.handle(node.name)} = function
447
+ ${body}
448
+ end function`;
449
+ });
450
+ NodeHandler.register(ts5.SyntaxKind.SetAccessor, (node) => {
451
+ if (!node.body)
452
+ return "";
453
+ const body = NodeHandler.handle(node.body);
454
+ const params = node.parameters.map((param) => NodeHandler.handle(param));
455
+ return `set_${NodeHandler.handle(node.name)} = function(${params.join(", ")})
456
+ ${body}
457
+ end function`;
458
+ });
459
+
460
+ // src/visitors/expressions.ts
461
+ import ts7 from "typescript";
462
+
463
+ // src/callTransformer.ts
464
+ import path2 from "node:path";
465
+ import ts6 from "typescript";
466
+ class CallTransformer {
467
+ static handlers = new Map;
468
+ static register(symbolFullName, handler) {
469
+ if (this.handlers.has(symbolFullName))
470
+ throw `Handler for '${symbolFullName}' was already registered`;
471
+ this.handlers.set(symbolFullName, handler);
472
+ }
473
+ static handle(symbolFullName, functionName, callArgs, node, ctx) {
474
+ const handler = this.handlers.get(symbolFullName);
475
+ if (!handler)
476
+ return null;
477
+ return handler(functionName, callArgs, node, ctx);
787
478
  }
788
479
  }
789
480
  CallTransformer.register("Array.concat", (name, args) => {
@@ -897,7 +588,7 @@ CallTransformer.register("GreyHack.include", (name, args, node, ctx) => {
897
588
  const fileArg = node.arguments[0];
898
589
  if (!ts6.isStringLiteralLike(fileArg))
899
590
  throw "You can't include variables";
900
- const absPath = path3.resolve(ctx.currentFolder, fileArg.text);
591
+ const absPath = path2.resolve(ctx.currentFolder, fileArg.text);
901
592
  const sources = getSourceFiles(absPath);
902
593
  for (const source of sources) {
903
594
  transpileSourceFile(source, ctx);
@@ -938,19 +629,19 @@ function handleCallArgs(callNode, ctx) {
938
629
  const hasRestParameter = hasRestParam(params);
939
630
  const nonRestParamCount = params.length - Number(hasRestParameter);
940
631
  let remainingRequired = nonRestParamCount;
941
- function pushArgs(...items) {
632
+ function pushArgs(fromSpread, ...items) {
942
633
  for (const item of items) {
943
634
  if (remainingRequired > 0) {
944
635
  result.push(item);
945
636
  remainingRequired--;
946
637
  continue;
947
638
  }
948
- restItems.push(item);
639
+ restItems.push({ text: item, fromSpread });
949
640
  }
950
641
  }
951
642
  for (const arg of args) {
952
643
  if (!ts7.isSpreadElement(arg)) {
953
- pushArgs(NodeHandler.handle(arg));
644
+ pushArgs(false, NodeHandler.handle(arg));
954
645
  continue;
955
646
  }
956
647
  if (ts7.isArrayLiteralExpression(arg.expression)) {
@@ -959,7 +650,7 @@ function handleCallArgs(callNode, ctx) {
959
650
  handleArrayLiteralExpression(arg.expression, ctx, arrayItems, outArrs);
960
651
  if (outArrs.length > 1)
961
652
  throw "The transpiler can't handle it yet if there are nested spread elements as parameters";
962
- pushArgs(...arrayItems);
653
+ pushArgs(true, ...arrayItems);
963
654
  continue;
964
655
  }
965
656
  const arrayName = NodeHandler.handle(arg.expression);
@@ -973,26 +664,26 @@ function handleCallArgs(callNode, ctx) {
973
664
  continue;
974
665
  }
975
666
  if (restItems.length) {
976
- restArrays.push(`[${restItems.join(",")}]`);
667
+ restArrays.push(`[${restItems.map((el) => el.text).join(",")}]`);
977
668
  restItems.length = 0;
978
669
  }
979
670
  restArrays.push(arrayName);
980
671
  }
981
672
  if (restItems.length) {
982
673
  if (remainingRequired > 0 || !hasRestParameter) {
983
- result.push(...restItems);
674
+ result.push(...restItems.map((el) => el.text));
984
675
  } else {
985
676
  const processedItems = [];
986
677
  for (const item of restItems) {
987
- if (item[0] !== "[") {
988
- processedItems.push(item);
678
+ if (!item.fromSpread || !item.text.startsWith("[") || !item.text.endsWith("]")) {
679
+ processedItems.push(item.text);
989
680
  continue;
990
681
  }
991
682
  if (processedItems.length) {
992
683
  restArrays.push(`[${processedItems.join(",")}]`);
993
684
  processedItems.length = 0;
994
685
  }
995
- restArrays.push(item);
686
+ restArrays.push(item.text);
996
687
  }
997
688
  if (processedItems.length)
998
689
  restArrays.push(`[${processedItems.join(",")}]`);
@@ -1115,7 +806,7 @@ function handleUnaryExpression(node) {
1115
806
  if (operator === "-")
1116
807
  return `-${operand}`;
1117
808
  if (operator === "+")
1118
- return `${operand}.val()`;
809
+ return `str(${operand}).val()`;
1119
810
  if (operator === "~")
1120
811
  return `bitwise("~", ${operand})`;
1121
812
  throw `Couldn't handle this UnaryExpression: ${node.getText()}`;
@@ -1301,11 +992,11 @@ NodeHandler.register(ts9.SyntaxKind.RegularExpressionLiteral, (node) => {
1301
992
  });
1302
993
 
1303
994
  // src/visitors/imports.ts
1304
- import path4 from "node:path";
995
+ import path3 from "node:path";
1305
996
  import ts10 from "typescript";
1306
997
  function importFile(filePath, ctx, returnResult) {
1307
- let srcPath = path4.resolve(ctx.currentFolder, filePath);
1308
- if (!path4.extname(srcPath))
998
+ let srcPath = path3.resolve(ctx.currentFolder, filePath);
999
+ if (!path3.extname(srcPath))
1309
1000
  srcPath += ".ts";
1310
1001
  const source = program.getSourceFile(srcPath);
1311
1002
  if (!source) {
@@ -1471,186 +1162,499 @@ function handleObjectLiteralExpression(node, ctx, currObj, outObjects, funcs) {
1471
1162
  ` + funcs.join(`
1472
1163
  `);
1473
1164
  }
1474
- return output;
1475
- }
1476
- NodeHandler.register(ts11.SyntaxKind.ObjectLiteralExpression, handleObjectLiteralExpression);
1165
+ return output;
1166
+ }
1167
+ NodeHandler.register(ts11.SyntaxKind.ObjectLiteralExpression, handleObjectLiteralExpression);
1168
+
1169
+ // src/visitors/statements.ts
1170
+ import ts12 from "typescript";
1171
+ NodeHandler.register(ts12.SyntaxKind.ForStatement, (node) => {
1172
+ if (!node.condition || !node.initializer || !node.incrementor) {
1173
+ throw "Can't transpile this type of for loop.";
1174
+ }
1175
+ const initializer = NodeHandler.handle(node.initializer);
1176
+ const condition = NodeHandler.handle(node.condition);
1177
+ const incrementor = NodeHandler.handle(node.incrementor);
1178
+ const statement = NodeHandler.handle(node.statement);
1179
+ function hasContinue(n) {
1180
+ if (n.getChildren().some((child) => {
1181
+ if (ts12.isContinueStatement(child))
1182
+ return true;
1183
+ return hasContinue(child);
1184
+ })) {
1185
+ return true;
1186
+ }
1187
+ return false;
1188
+ }
1189
+ if (!hasContinue(node)) {
1190
+ return [
1191
+ `${initializer}`,
1192
+ `while ${condition}`,
1193
+ ` ${statement.trimStart()}`,
1194
+ ` ${incrementor}`,
1195
+ `end while`
1196
+ ].join(`
1197
+ `);
1198
+ }
1199
+ const incrementedStateVarName = "state_" + (Date.now() * Math.random()).toFixed(0).slice(0, 6);
1200
+ const output = [
1201
+ `${incrementedStateVarName} = 1`,
1202
+ `${initializer}`,
1203
+ `while ${condition}`,
1204
+ ` if not ${incrementedStateVarName} then`,
1205
+ ` ${incrementor}`,
1206
+ ` if not ${condition} then break`,
1207
+ ` end if`,
1208
+ ` ${incrementedStateVarName} = 0`,
1209
+ ` ${statement.trimStart()}`,
1210
+ ` ${incrementor}`,
1211
+ ` ${incrementedStateVarName} = 1`,
1212
+ `end while`
1213
+ ].join(`
1214
+ `);
1215
+ return output;
1216
+ });
1217
+ NodeHandler.register(ts12.SyntaxKind.ForOfStatement, (node) => {
1218
+ if (!ts12.isVariableDeclarationList(node.initializer)) {
1219
+ throw `Can't handle this 'for of' statement as '${NodeHandler.handle(node.initializer)}' is not initialized there`;
1220
+ }
1221
+ if (node.initializer.declarations.length > 1) {
1222
+ throw "Can't have more than 1 variable declarations in a 'for of' statement";
1223
+ }
1224
+ const varName = NodeHandler.handle(node.initializer.declarations[0].name);
1225
+ const objToLoop = NodeHandler.handle(node.expression);
1226
+ return `for ${varName} in ${objToLoop}
1227
+ ${NodeHandler.handle(node.statement)}
1228
+ end for`;
1229
+ });
1230
+ NodeHandler.register(ts12.SyntaxKind.ForInStatement, (node) => {
1231
+ if (!ts12.isVariableDeclarationList(node.initializer)) {
1232
+ throw `Can't handle this 'for in' statement as '${NodeHandler.handle(node.initializer)}' is not initialized there`;
1233
+ }
1234
+ if (node.initializer.declarations.length > 1) {
1235
+ throw "Can't have more than 1 variable declarations in a 'for in' statement";
1236
+ }
1237
+ const varName = NodeHandler.handle(node.initializer.declarations[0].name);
1238
+ const objToLoop = NodeHandler.handle(node.expression);
1239
+ return `for ${varName} in ${objToLoop}.indexes
1240
+ ${NodeHandler.handle(node.statement)}
1241
+ end for`;
1242
+ });
1243
+ NodeHandler.register(ts12.SyntaxKind.IfStatement, (node) => {
1244
+ const condition = NodeHandler.handle(node.expression);
1245
+ const thenStatement = NodeHandler.handle(node.thenStatement);
1246
+ if (!ts12.isBlock(node.thenStatement) && !ts12.isIfStatement(node.thenStatement) && !ts12.isIfStatement(node.parent)) {
1247
+ if (!node.elseStatement)
1248
+ return `if ${condition} then ${thenStatement}`;
1249
+ else if (!ts12.isBlock(node.elseStatement) && !ts12.isIfStatement(node.elseStatement))
1250
+ return `if ${condition} then ${thenStatement} else ${NodeHandler.handle(node.elseStatement)}`;
1251
+ }
1252
+ let output = `if ${condition} then
1253
+ ${thenStatement.trimStart()}`;
1254
+ if (node.elseStatement) {
1255
+ if (ts12.isIfStatement(node.elseStatement)) {
1256
+ output += `
1257
+ else ${NodeHandler.handle(node.elseStatement)}`;
1258
+ return output;
1259
+ } else {
1260
+ output += `
1261
+ else
1262
+ ${NodeHandler.handle(node.elseStatement).trimStart()}`;
1263
+ }
1264
+ }
1265
+ output += `
1266
+ end if`;
1267
+ return output;
1268
+ });
1269
+ NodeHandler.register(ts12.SyntaxKind.WhileStatement, (node, ctx) => {
1270
+ const expression = NodeHandler.handle(node.expression);
1271
+ return [
1272
+ `while ${expression}`,
1273
+ ` ${NodeHandler.handle(node.statement).trimStart()}`,
1274
+ `end while`
1275
+ ].join(`
1276
+ `);
1277
+ });
1278
+ NodeHandler.register(ts12.SyntaxKind.DoStatement, (node, ctx) => {
1279
+ const expression = NodeHandler.handle(node.expression);
1280
+ return [
1281
+ `did_once = 0`,
1282
+ `while not did_once or ${expression}`,
1283
+ ` did_once = 1`,
1284
+ ` ${NodeHandler.handle(node.statement).trimStart()}`,
1285
+ `end while`
1286
+ ].join(`
1287
+ `);
1288
+ });
1289
+ NodeHandler.register(ts12.SyntaxKind.ContinueStatement, (node) => {
1290
+ return "continue";
1291
+ });
1292
+ NodeHandler.register(ts12.SyntaxKind.BreakStatement, (node) => {
1293
+ return "break";
1294
+ });
1295
+ NodeHandler.register(ts12.SyntaxKind.ReturnStatement, (node) => {
1296
+ if (!node.expression) {
1297
+ if (ts12.findAncestor(node, (n) => ts12.isConstructorDeclaration(n)) && !ts12.findAncestor(node, (n) => ts12.isFunctionLike(n))) {
1298
+ return "return self";
1299
+ }
1300
+ return "return";
1301
+ }
1302
+ return `return ${NodeHandler.handle(node.expression)}`;
1303
+ });
1477
1304
 
1478
- // src/visitors/statements.ts
1479
- import ts12 from "typescript";
1480
- NodeHandler.register(ts12.SyntaxKind.ForStatement, (node) => {
1481
- if (!node.condition || !node.initializer || !node.incrementor) {
1482
- throw "Can't transpile this type of for loop.";
1305
+ // src/visitors/variables.ts
1306
+ import ts13 from "typescript";
1307
+ function handleVariableDeclaration(node, ctx) {
1308
+ const left = NodeHandler.handle(node.name);
1309
+ const initializerType = node.initializer ? checker.getTypeAtLocation(node.initializer) : undefined;
1310
+ if (ts13.isPropertyDeclaration(node) && initializerType?.flags === ts13.TypeFlags.Object) {
1311
+ console.warn(`You shouldn't initialize '${left}' with an Array or an Object because in GreyScript, every instantiation refers to the same '${left}' variable.
1312
+ Initialize them in the constructor instead`);
1483
1313
  }
1484
- const initializer = NodeHandler.handle(node.initializer);
1485
- const condition = NodeHandler.handle(node.condition);
1486
- const incrementor = NodeHandler.handle(node.incrementor);
1487
- const statement = NodeHandler.handle(node.statement);
1488
- function hasContinue(n) {
1489
- if (n.getChildren().some((child) => {
1490
- if (ts12.isContinueStatement(child))
1491
- return true;
1492
- return hasContinue(child);
1493
- })) {
1494
- return true;
1495
- }
1496
- return false;
1314
+ let right = node.initializer ? NodeHandler.handle(node.initializer) || "null" : "null";
1315
+ if (right != "null" && nodeIsFunctionReference(node.initializer, initializerType)) {
1316
+ right = asRef(right);
1497
1317
  }
1498
- if (!hasContinue(node)) {
1499
- return [
1500
- `${initializer}`,
1501
- `while ${condition}`,
1502
- ` ${statement.trimStart()}`,
1503
- ` ${incrementor}`,
1504
- `end while`
1505
- ].join(`
1318
+ return `${left} = ${right}`;
1319
+ }
1320
+ NodeHandler.register(ts13.SyntaxKind.VariableDeclarationList, (node, ctx) => {
1321
+ return node.declarations.map((decl) => handleVariableDeclaration(decl, ctx)).join(`
1506
1322
  `);
1507
- }
1508
- const incrementedStateVarName = "state_" + (Date.now() * Math.random()).toFixed(0).slice(0, 6);
1509
- const output = [
1510
- `${incrementedStateVarName} = 1`,
1511
- `${initializer}`,
1512
- `while ${condition}`,
1513
- ` if not ${incrementedStateVarName} then`,
1514
- ` ${incrementor}`,
1515
- ` if not ${condition} then break`,
1516
- ` end if`,
1517
- ` ${incrementedStateVarName} = 0`,
1518
- ` ${statement.trimStart()}`,
1519
- ` ${incrementor}`,
1520
- ` ${incrementedStateVarName} = 1`,
1521
- `end while`
1323
+ });
1324
+ NodeHandler.register(ts13.SyntaxKind.VariableStatement, (node, ctx) => {
1325
+ if (node.modifiers?.some((modifier) => modifier.kind === ts13.SyntaxKind.DeclareKeyword))
1326
+ return "";
1327
+ return NodeHandler.handle(node.declarationList);
1328
+ });
1329
+ NodeHandler.register(ts13.SyntaxKind.VariableDeclaration, handleVariableDeclaration);
1330
+ NodeHandler.register(ts13.SyntaxKind.PropertyDeclaration, handleVariableDeclaration);
1331
+ NodeHandler.register(ts13.SyntaxKind.EnumDeclaration, (node) => {
1332
+ const members = node.members.map((member, index) => {
1333
+ const name = NodeHandler.handle(member.name);
1334
+ if (member.initializer) {
1335
+ return `${name}: ${NodeHandler.handle(member.initializer)}`;
1336
+ }
1337
+ const type = checker.getTypeAtLocation(member);
1338
+ if ("value" in type) {
1339
+ return `${name}: ${type.value}`;
1340
+ }
1341
+ return `${name}: ${index}`;
1342
+ });
1343
+ return `${node.name.text} = { ${members.join(", ")} }`;
1344
+ });
1345
+
1346
+ // src/transpiler.ts
1347
+ var program;
1348
+ var checker;
1349
+ var anonFunctions = new Map;
1350
+ var calledUtilFunctions = new Set;
1351
+ var utilFunctions2 = {
1352
+ get_property: [
1353
+ "get_property = function(obj, key)",
1354
+ "\tif not obj then return null",
1355
+ "\tif obj.hasIndex(key) then return obj[key]",
1356
+ "\tisaobj = obj",
1357
+ '\twhile isaobj.hasIndex("__isa")',
1358
+ '\t\tisaobj = obj["__isa"]',
1359
+ "\t\tif isaobj.hasIndex(key) then",
1360
+ "\t\t\tval = obj[key]",
1361
+ "\t\t\treturn val",
1362
+ "\t\tend if",
1363
+ "\tend while",
1364
+ "\treturn null",
1365
+ "end function"
1366
+ ].join(`
1367
+ `),
1368
+ assign_objects: [
1369
+ "assign_objects = function(target, source1, source2, source3)",
1370
+ "\tassign_to_list = function(target, source)",
1371
+ "\t\tif source isa list then",
1372
+ "\t\t\tfor i in range(0, source.len - 1, 1)",
1373
+ "\t\t\t\tif target.len <= i then target.push(null)",
1374
+ "\t\t\t\ttarget[i] = source[i]",
1375
+ "\t\t\tend for",
1376
+ "\t\telse if source isa map then",
1377
+ "\t\t\tfor item in source",
1378
+ "\t\t\t\tkey = str(item.key).to_int",
1379
+ "\t\t\t\tif key isa number then target[key] = item.value",
1380
+ "\t\t\tend for",
1381
+ "\t\tend if",
1382
+ "\t\treturn target",
1383
+ "\tend function",
1384
+ "\tcounter = 0",
1385
+ "\tassign_object = function(target, source)",
1386
+ "\t\tif target isa list then return assign_to_list(target, source)",
1387
+ "\t\tif source isa list then",
1388
+ "\t\t\tfor i in range(0, source.len - 1, 1)",
1389
+ "\t\t\t\ttarget[str(i)] = source[i]",
1390
+ "\t\t\tend for",
1391
+ "\t\telse if source isa map then",
1392
+ "\t\t\tfor item in source",
1393
+ "\t\t\t\ttarget[item.key] = item.value",
1394
+ "\t\t\tend for",
1395
+ "\t\telse",
1396
+ "\t\t\ttarget[str(outer.counter)] = source",
1397
+ "\t\t\touter.counter = outer.counter + 1",
1398
+ "\t\tend if",
1399
+ "\tend function",
1400
+ "\tif source1 isa list then",
1401
+ "\t\tif target isa list then return assign_to_list(target, source1)",
1402
+ "\t\tfor source in source1",
1403
+ "\t\t\tassign_object(target, source)",
1404
+ "\t\tend for",
1405
+ "\t\treturn target",
1406
+ "\tend if",
1407
+ "\tif source1 then assign_object(target, source1)",
1408
+ "\tif source2 then assign_object(target, source2)",
1409
+ "\tif source3 then assign_object(target, source3)",
1410
+ "\treturn target",
1411
+ "end function"
1412
+ ].join(`
1413
+ `),
1414
+ array_map: [
1415
+ "array_map = function(array, callback)",
1416
+ "\tindex = 0",
1417
+ "\tout = []",
1418
+ "\tfor item in array",
1419
+ "\t\tout.push(callback(item, index, array))",
1420
+ "\t\tindex = index + 1",
1421
+ "\tend for",
1422
+ "\treturn out",
1423
+ "end function"
1424
+ ].join(`
1425
+ `),
1426
+ array_filter: [
1427
+ "array_filter = function(array, predicate)",
1428
+ "\tindex = 0",
1429
+ "\tout = []",
1430
+ "\tfor item in array",
1431
+ "\t\tif predicate(item, index, array) then out.push(item)",
1432
+ "\t\tindex = index + 1",
1433
+ "\tend for",
1434
+ "\treturn out",
1435
+ "end function"
1436
+ ].join(`
1437
+ `),
1438
+ array_find: [
1439
+ "array_find = function(array, predicate)",
1440
+ "\tindex = 0",
1441
+ "\tfor item in array",
1442
+ "\t\tif predicate(item, index, array) then return item",
1443
+ "\t\tindex = index + 1",
1444
+ "\tend for",
1445
+ "\treturn null",
1446
+ "end function"
1447
+ ].join(`
1448
+ `),
1449
+ array_some: [
1450
+ "array_some = function(array, predicate)",
1451
+ "\tindex = 0",
1452
+ "\tfor item in array",
1453
+ "\t\tif predicate(item, index, array) then return 1",
1454
+ "\t\tindex = index + 1",
1455
+ "\tend for",
1456
+ "\treturn 0",
1457
+ "end function"
1458
+ ].join(`
1459
+ `),
1460
+ array_every: [
1461
+ "array_every = function(array, predicate)",
1462
+ "\tindex = 0",
1463
+ "\tfor item in array",
1464
+ "\t\tif not predicate(item, index, array) then return 0",
1465
+ "\t\tindex = index + 1",
1466
+ "\tend for",
1467
+ "\treturn 1",
1468
+ "end function"
1469
+ ].join(`
1470
+ `),
1471
+ array_concat: [
1472
+ "array_concat = function(target, items)",
1473
+ "\tout = target[0:]",
1474
+ "\tfor item in items",
1475
+ "\t\tif item isa list then out = out + item else out.push(item)",
1476
+ "\tend for",
1477
+ "\treturn out",
1478
+ "end function"
1479
+ ].join(`
1480
+ `),
1481
+ array_push: [
1482
+ "array_push = function(target, items)",
1483
+ "\tfor item in items[:]",
1484
+ "\t\ttarget.push(@item)",
1485
+ "\tend for",
1486
+ "\treturn target.len",
1487
+ "end function"
1488
+ ].join(`
1489
+ `),
1490
+ array_unshift: [
1491
+ "array_unshift = function(target, items)",
1492
+ "\tif not items.len then return target.len",
1493
+ "\tfor i in range(items.len-1)",
1494
+ "\t\ttarget.insert(0, @items[i])",
1495
+ "\tend for",
1496
+ "\treturn target.len",
1497
+ "end function"
1498
+ ].join(`
1499
+ `),
1500
+ array_reverse: `array_reverse = function(arr)
1501
+ arr.reverse
1502
+ return arr
1503
+ end function`,
1504
+ str_starts_with: [
1505
+ "str_starts_with = function(str, search, pos = 0)",
1506
+ "\tif pos < 0 then pos = 0",
1507
+ "\treturn str.indexOf(search) == pos",
1508
+ "end function"
1522
1509
  ].join(`
1523
- `);
1524
- return output;
1525
- });
1526
- NodeHandler.register(ts12.SyntaxKind.ForOfStatement, (node) => {
1527
- if (!ts12.isVariableDeclarationList(node.initializer)) {
1528
- throw `Can't handle this 'for of' statement as '${NodeHandler.handle(node.initializer)}' is not initialized there`;
1529
- }
1530
- if (node.initializer.declarations.length > 1) {
1531
- throw "Can't have more than 1 variable declarations in a 'for of' statement";
1510
+ `),
1511
+ str_ends_with: [
1512
+ "str_ends_with = function(str, search, pos = null)",
1513
+ "\tif pos == null then pos = str.len",
1514
+ "\tif pos < 0 then pos = 0",
1515
+ "\treturn str.indexOf(search) + search.len == pos",
1516
+ "end function"
1517
+ ].join(`
1518
+ `),
1519
+ str_repeat: [
1520
+ "str_repeat = function(str, count = 0)",
1521
+ '\tif count <= 0 then return ""',
1522
+ "\tif count == 1 then return str",
1523
+ "\tout = str",
1524
+ "\tfor i in range(count-2)",
1525
+ "\t\tout = out + str",
1526
+ "\tend for",
1527
+ "\treturn out",
1528
+ "end function"
1529
+ ].join(`
1530
+ `),
1531
+ math_min: [
1532
+ "math_min = function(numbers)",
1533
+ "\tcurr_min = null",
1534
+ "\tfor num in numbers",
1535
+ "\t\tif curr_min == null or num < curr_min then curr_min = num",
1536
+ "\tend for",
1537
+ "\treturn curr_min",
1538
+ "end function"
1539
+ ].join(`
1540
+ `),
1541
+ math_max: [
1542
+ "math_max = function(numbers)",
1543
+ "\tcurr_max = null",
1544
+ "\tfor num in numbers",
1545
+ "\t\tif curr_max == null or num > curr_max then curr_max = num",
1546
+ "\tend for",
1547
+ "\treturn curr_max",
1548
+ "end function"
1549
+ ].join(`
1550
+ `),
1551
+ nullish_coalescing_op: `nullish_coalescing_op = function(left, right)
1552
+ if left == null then return @right
1553
+ return @left
1554
+ end function`,
1555
+ or_op: `or_op = function(left, right)
1556
+ if not left then return @right
1557
+ return @left
1558
+ end function`,
1559
+ is_type: `is_type = function(value, type)
1560
+ if typeof(value) == type then return 1
1561
+ return 0
1562
+ end function`,
1563
+ conditional_expr: `conditional_expr = function(cond, when_true, when_false)
1564
+ if cond then return when_true
1565
+ return when_false
1566
+ end function`
1567
+ };
1568
+ function createAnonFunction(body, params) {
1569
+ const defaultParams = new Array(3).fill(0).map((_, i) => `param${i}`);
1570
+ const nextName = `func_${anonFunctions.size}`;
1571
+ const paramString = Object.assign(defaultParams, params).join(",");
1572
+ const result = `${nextName} = function(${paramString})
1573
+ ${body}
1574
+ end function`;
1575
+ anonFunctions.set(nextName, result);
1576
+ return { name: nextName, str: result };
1577
+ }
1578
+ function transpileProgram(entryFileRelativePath) {
1579
+ const ctx = {
1580
+ currentFolder: "",
1581
+ currentFilePath: path4.resolve(process.cwd(), entryFileRelativePath),
1582
+ namedImports: {},
1583
+ namespaceImports: {},
1584
+ visitedFiles: {},
1585
+ output: []
1586
+ };
1587
+ NodeHandler.transpileContext = ctx;
1588
+ ctx.currentFolder = path4.dirname(ctx.currentFilePath);
1589
+ if (!fs2.existsSync(ctx.currentFilePath)) {
1590
+ console.error(`Error: file '${ctx.currentFilePath}' doesn't exist`);
1591
+ process.exit(1);
1532
1592
  }
1533
- const varName = NodeHandler.handle(node.initializer.declarations[0].name);
1534
- const objToLoop = NodeHandler.handle(node.expression);
1535
- return `for ${varName} in ${objToLoop}
1536
- ${NodeHandler.handle(node.statement)}
1537
- end for`;
1538
- });
1539
- NodeHandler.register(ts12.SyntaxKind.ForInStatement, (node) => {
1540
- if (!ts12.isVariableDeclarationList(node.initializer)) {
1541
- throw `Can't handle this 'for in' statement as '${NodeHandler.handle(node.initializer)}' is not initialized there`;
1593
+ let start = Date.now();
1594
+ const tsconfigPath = findProjectRoot(process.cwd(), "tsconfig.json") + "/tsconfig.json";
1595
+ const res = ts14.readConfigFile(tsconfigPath, ts14.sys.readFile);
1596
+ const parsed = ts14.parseJsonConfigFileContent(res.config, ts14.sys, path4.dirname(tsconfigPath));
1597
+ if (!parsed.options.types)
1598
+ parsed.options.types = [];
1599
+ if (!parsed.options.types.includes("@grey-ts/types")) {
1600
+ parsed.options.types.push("@grey-ts/types");
1542
1601
  }
1543
- if (node.initializer.declarations.length > 1) {
1544
- throw "Can't have more than 1 variable declarations in a 'for in' statement";
1602
+ parsed.options.noLib = true;
1603
+ program = ts14.createProgram({
1604
+ rootNames: parsed.fileNames,
1605
+ options: parsed.options
1606
+ });
1607
+ console.log(`Program creation took ${Date.now() - start} ms`);
1608
+ start = Date.now();
1609
+ checker = program.getTypeChecker();
1610
+ const entry = program.getSourceFile(ctx.currentFilePath);
1611
+ if (!entry) {
1612
+ console.error(`Error: failed to find '${ctx.currentFilePath}' from the included sources`);
1613
+ process.exit(1);
1545
1614
  }
1546
- const varName = NodeHandler.handle(node.initializer.declarations[0].name);
1547
- const objToLoop = NodeHandler.handle(node.expression);
1548
- return `for ${varName} in ${objToLoop}.indexes
1549
- ${NodeHandler.handle(node.statement)}
1550
- end for`;
1551
- });
1552
- NodeHandler.register(ts12.SyntaxKind.IfStatement, (node) => {
1553
- const condition = NodeHandler.handle(node.expression);
1554
- const thenStatement = NodeHandler.handle(node.thenStatement);
1555
- if (!ts12.isBlock(node.thenStatement) && !ts12.isIfStatement(node.thenStatement) && !ts12.isIfStatement(node.parent)) {
1556
- if (!node.elseStatement)
1557
- return `if ${condition} then ${thenStatement}`;
1558
- else if (!ts12.isBlock(node.elseStatement) && !ts12.isIfStatement(node.elseStatement))
1559
- return `if ${condition} then ${thenStatement} else ${NodeHandler.handle(node.elseStatement)}`;
1615
+ transpileSourceFile(entry, ctx);
1616
+ if (anonFunctions.size) {
1617
+ for (const declaration of anonFunctions.values())
1618
+ ctx.output.unshift(declaration);
1619
+ anonFunctions.clear();
1560
1620
  }
1561
- let output = `if ${condition} then
1562
- ${thenStatement.trimStart()}`;
1563
- if (node.elseStatement) {
1564
- if (ts12.isIfStatement(node.elseStatement)) {
1565
- output += `
1566
- else ${NodeHandler.handle(node.elseStatement)}`;
1567
- return output;
1568
- } else {
1569
- output += `
1570
- else
1571
- ${NodeHandler.handle(node.elseStatement).trimStart()}`;
1572
- }
1621
+ if (calledUtilFunctions.size) {
1622
+ for (const call of calledUtilFunctions.keys())
1623
+ ctx.output.unshift(utilFunctions2[call]);
1624
+ calledUtilFunctions.clear();
1573
1625
  }
1574
- output += `
1575
- end if`;
1576
- return output;
1577
- });
1578
- NodeHandler.register(ts12.SyntaxKind.WhileStatement, (node, ctx) => {
1579
- const expression = NodeHandler.handle(node.expression);
1580
- return [
1581
- `while ${expression}`,
1582
- ` ${NodeHandler.handle(node.statement).trimStart()}`,
1583
- `end while`
1584
- ].join(`
1585
- `);
1586
- });
1587
- NodeHandler.register(ts12.SyntaxKind.DoStatement, (node, ctx) => {
1588
- const expression = NodeHandler.handle(node.expression);
1589
- return [
1590
- `did_once = 0`,
1591
- `while not did_once or ${expression}`,
1592
- ` did_once = 1`,
1593
- ` ${NodeHandler.handle(node.statement).trimStart()}`,
1594
- `end while`
1595
- ].join(`
1626
+ console.log(`Transpiling took ${Date.now() - start} ms`);
1627
+ return ctx.output.join(`
1596
1628
  `);
1597
- });
1598
- NodeHandler.register(ts12.SyntaxKind.ContinueStatement, (node) => {
1599
- return "continue";
1600
- });
1601
- NodeHandler.register(ts12.SyntaxKind.BreakStatement, (node) => {
1602
- return "break";
1603
- });
1604
- NodeHandler.register(ts12.SyntaxKind.ReturnStatement, (node) => {
1605
- if (!node.expression) {
1606
- if (ts12.findAncestor(node, (n) => ts12.isConstructorDeclaration(n)) && !ts12.findAncestor(node, (n) => ts12.isFunctionLike(n))) {
1607
- return "return self";
1608
- }
1609
- return "return";
1610
- }
1611
- return `return ${NodeHandler.handle(node.expression)}`;
1612
- });
1613
-
1614
- // src/visitors/variables.ts
1615
- import ts13 from "typescript";
1616
- function handleVariableDeclaration(node, ctx) {
1617
- const left = NodeHandler.handle(node.name);
1618
- const initializerType = node.initializer ? checker.getTypeAtLocation(node.initializer) : undefined;
1619
- if (ts13.isPropertyDeclaration(node) && initializerType?.flags === ts13.TypeFlags.Object) {
1620
- console.warn(`You shouldn't initialize '${left}' with an Array or an Object because in GreyScript, every instantiation refers to the same '${left}' variable.
1621
- Initialize them in the constructor instead`);
1622
- }
1623
- let right = node.initializer ? NodeHandler.handle(node.initializer) || "null" : "null";
1624
- if (right != "null" && nodeIsFunctionReference(node.initializer, initializerType)) {
1625
- right = asRef(right);
1626
- }
1627
- return `${left} = ${right}`;
1628
1629
  }
1629
- NodeHandler.register(ts13.SyntaxKind.VariableDeclarationList, (node, ctx) => {
1630
- return node.declarations.map((decl) => handleVariableDeclaration(decl, ctx)).join(`
1631
- `);
1632
- });
1633
- NodeHandler.register(ts13.SyntaxKind.VariableStatement, (node, ctx) => {
1634
- if (node.modifiers?.some((modifier) => modifier.kind === ts13.SyntaxKind.DeclareKeyword))
1630
+ function transpileSourceFile(sourceFile, ctx, returnResult) {
1631
+ if (ctx.visitedFiles[sourceFile.fileName])
1635
1632
  return "";
1636
- return NodeHandler.handle(node.declarationList);
1637
- });
1638
- NodeHandler.register(ts13.SyntaxKind.VariableDeclaration, handleVariableDeclaration);
1639
- NodeHandler.register(ts13.SyntaxKind.PropertyDeclaration, handleVariableDeclaration);
1640
- NodeHandler.register(ts13.SyntaxKind.EnumDeclaration, (node) => {
1641
- const members = node.members.map((member, index) => {
1642
- const name = NodeHandler.handle(member.name);
1643
- if (member.initializer) {
1644
- return `${name}: ${NodeHandler.handle(member.initializer)}`;
1645
- }
1646
- const type = checker.getTypeAtLocation(member);
1647
- if ("value" in type) {
1648
- return `${name}: ${type.value}`;
1649
- }
1650
- return `${name}: ${index}`;
1633
+ ctx.visitedFiles[sourceFile.fileName] = true;
1634
+ if (sourceFile.isDeclarationFile)
1635
+ return "";
1636
+ if (program.isSourceFileDefaultLibrary(sourceFile) || program.isSourceFileFromExternalLibrary(sourceFile))
1637
+ return "";
1638
+ const prevFile = ctx.currentFilePath;
1639
+ ctx.currentFilePath = sourceFile.fileName;
1640
+ ctx.currentFolder = path4.dirname(sourceFile.fileName);
1641
+ ctx.namedImports[sourceFile.fileName] = {};
1642
+ ctx.namespaceImports[sourceFile.fileName] = new Set;
1643
+ const output = [];
1644
+ sourceFile.forEachChild((node) => {
1645
+ const result = NodeHandler.handle(node);
1646
+ if (!result)
1647
+ return;
1648
+ if (!returnResult)
1649
+ ctx.output.push(result);
1650
+ else
1651
+ output.push(result);
1651
1652
  });
1652
- return `${node.name.text} = { ${members.join(", ")} }`;
1653
- });
1653
+ ctx.currentFilePath = prevFile;
1654
+ ctx.currentFolder = path4.dirname(prevFile);
1655
+ return output.join(`
1656
+ `);
1657
+ }
1654
1658
 
1655
1659
  // src/index.ts
1656
1660
  var noMoreFlags = false;