@harmoniclabs/pebble 0.1.0-dev6 → 0.1.0-dev8

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 (76) hide show
  1. package/dist/IR/IRNodes/IRConst.js +1 -1
  2. package/dist/IR/IRNodes/IRNative/IRNativeTag.d.ts +6 -3
  3. package/dist/IR/IRNodes/IRNative/IRNativeTag.js +12 -4
  4. package/dist/IR/IRNodes/IRNative/index.d.ts +5 -2
  5. package/dist/IR/IRNodes/IRNative/index.js +6 -2
  6. package/dist/IR/toUPLC/CompilerOptions.d.ts +6 -1
  7. package/dist/IR/toUPLC/CompilerOptions.js +11 -1
  8. package/dist/IR/toUPLC/compileIRToUPLC.js +34 -35
  9. package/dist/IR/toUPLC/ctx/ToUplcCtx.js +2 -10
  10. package/dist/IR/toUPLC/subRoutines/handleLetted/groupByScope.js +0 -2
  11. package/dist/IR/toUPLC/subRoutines/handleLetted/index.js +69 -3
  12. package/dist/IR/toUPLC/subRoutines/replaceNatives/nativeToIR.d.ts +3 -1
  13. package/dist/IR/toUPLC/subRoutines/replaceNatives/nativeToIR.js +42 -10
  14. package/dist/IR/toUPLC/subRoutines/rewriteNativesAppliedToConstantsAndReturnRoot.js +292 -17
  15. package/dist/IR/utils/isClosedIRTerm.js +1 -1
  16. package/dist/IR/utils/positiveIntAsBytes.js +1 -5
  17. package/dist/compiler/AstCompiler/AstCompiler.d.ts +3 -0
  18. package/dist/compiler/AstCompiler/AstCompiler.js +66 -3
  19. package/dist/compiler/AstCompiler/internal/_deriveContractBody/_deriveContractBody.js +1 -1
  20. package/dist/compiler/AstCompiler/internal/exprs/_compileExpr.js +4 -0
  21. package/dist/compiler/AstCompiler/internal/exprs/_compileFuncExpr.js +13 -4
  22. package/dist/compiler/AstCompiler/internal/exprs/_compileTypeConversionExpr.js +0 -1
  23. package/dist/compiler/AstCompiler/internal/exprs/_compileVarAccessExpr.js +3 -1
  24. package/dist/compiler/AstCompiler/internal/statements/_compileAssignmentStmt.js +7 -7
  25. package/dist/compiler/AstCompiler/internal/statements/_compileVarStmt.d.ts +2 -1
  26. package/dist/compiler/AstCompiler/internal/statements/_compileVarStmt.js +2 -1
  27. package/dist/compiler/AstCompiler/scope/AstScope.d.ts +1 -0
  28. package/dist/compiler/AstCompiler/scope/AstScope.js +5 -0
  29. package/dist/compiler/Compiler.d.ts +8 -1
  30. package/dist/compiler/Compiler.js +38 -1
  31. package/dist/compiler/TirCompiler/compileTirProgram.js +2 -1
  32. package/dist/compiler/TirCompiler/expressify/ExpressifyCtx.d.ts +4 -2
  33. package/dist/compiler/TirCompiler/expressify/ExpressifyCtx.js +42 -16
  34. package/dist/compiler/TirCompiler/expressify/determineReassignedVariablesAndReturn.js +2 -0
  35. package/dist/compiler/TirCompiler/expressify/expressify.js +26 -9
  36. package/dist/compiler/TirCompiler/expressify/expressifyForStmt.js +23 -7
  37. package/dist/compiler/TirCompiler/expressify/expressifyVarAssignmentStmt.d.ts +1 -2
  38. package/dist/compiler/TirCompiler/expressify/expressifyVarAssignmentStmt.js +15 -8
  39. package/dist/compiler/TirCompiler/expressify/expressifyVarDecl.js +6 -9
  40. package/dist/compiler/TirCompiler/expressify/expressifyVars.js +51 -16
  41. package/dist/compiler/TirCompiler/expressify/flattenSopNamedDeconstructInplace_addTopDestructToCtx_getNestedDeconstruct.js +1 -0
  42. package/dist/compiler/internalVar.d.ts +1 -1
  43. package/dist/compiler/internalVar.js +31 -24
  44. package/dist/compiler/io/CompilerIoApi.d.ts +1 -1
  45. package/dist/compiler/tir/expressions/TirCallExpr.d.ts +1 -1
  46. package/dist/compiler/tir/expressions/TirCallExpr.js +1 -1
  47. package/dist/compiler/tir/expressions/TirCaseExpr.js +2 -0
  48. package/dist/compiler/tir/expressions/TirFromDataExpr.js +2 -2
  49. package/dist/compiler/tir/expressions/TirFuncExpr.d.ts +1 -1
  50. package/dist/compiler/tir/expressions/TirFuncExpr.js +1 -1
  51. package/dist/compiler/tir/expressions/TirLettedExpr.d.ts +2 -2
  52. package/dist/compiler/tir/expressions/TirLettedExpr.js +4 -6
  53. package/dist/compiler/tir/expressions/TirNativeFunc.d.ts +3 -2
  54. package/dist/compiler/tir/expressions/TirNativeFunc.js +33 -12
  55. package/dist/compiler/tir/expressions/TirPropAccessExpr.js +1 -2
  56. package/dist/compiler/tir/expressions/TirVariableAccessExpr.d.ts +0 -1
  57. package/dist/compiler/tir/expressions/TirVariableAccessExpr.js +9 -5
  58. package/dist/compiler/tir/expressions/ToIRTermCtx.d.ts +3 -0
  59. package/dist/compiler/tir/expressions/ToIRTermCtx.js +8 -1
  60. package/dist/compiler/tir/expressions/binary/TirBinaryExpr.d.ts +1 -0
  61. package/dist/compiler/tir/expressions/binary/TirBinaryExpr.js +6 -1
  62. package/dist/compiler/tir/program/TypedProgram.d.ts +2 -2
  63. package/dist/compiler/tir/program/stdScope/stdScope.js +9 -23
  64. package/dist/compiler/tir/statements/TirIfStmt.d.ts +0 -1
  65. package/dist/compiler/tir/statements/TirIfStmt.js +0 -3
  66. package/dist/parser/Parser.js +18 -2
  67. package/dist/parser/Precedence.js +1 -0
  68. package/dist/utils/BitUtils/index.d.ts +1 -1
  69. package/dist/utils/BitUtils/index.js +1 -1
  70. package/dist/utils/IsSingleKey.d.ts +1 -1
  71. package/dist/utils/UPLCFlatUtils/index.d.ts +1 -1
  72. package/dist/utils/UPLCFlatUtils/index.js +2 -2
  73. package/dist/utils/array/keepSortedArrInplace.js +1 -0
  74. package/package.json +7 -6
  75. package/dist/compiler/TirCompiler/internal/_compileHoistedDeps.d.ts +0 -5
  76. package/dist/compiler/TirCompiler/internal/_compileHoistedDeps.js +0 -39
@@ -10,13 +10,14 @@ import { SourceRange } from "../../../../ast/Source/SourceRange.js";
10
10
  import { TirExpr } from "../../../tir/expressions/TirExpr.js";
11
11
  import { TirArrayLikeDeconstr } from "../../../tir/statements/TirVarDecl/TirArrayLikeDeconstr.js";
12
12
  import { TirNamedDeconstructVarDecl } from "../../../tir/statements/TirVarDecl/TirNamedDeconstructVarDecl.js";
13
+ import { TirSimpleVarDecl } from "../../../tir/statements/TirVarDecl/TirSimpleVarDecl.js";
13
14
  import { TirVarDecl } from "../../../tir/statements/TirVarDecl/TirVarDecl.js";
14
15
  import { TirStructConstr } from "../../../tir/types/TirStructType.js";
15
16
  import { TirType } from "../../../tir/types/TirType.js";
16
17
  import { AstCompilationCtx } from "../../AstCompilationCtx.js";
17
18
  export declare function _compileVarStmt(ctx: AstCompilationCtx, stmt: VarStmt): TirVarDecl[] | undefined;
18
19
  export declare function _compileVarDecl(ctx: AstCompilationCtx, decl: VarDecl, typeHint: TirType | undefined): TirVarDecl | undefined;
19
- export declare function _compileSimpleVarDecl(ctx: AstCompilationCtx, decl: SimpleVarDecl, typeHint: TirType | undefined): TirVarDecl | undefined;
20
+ export declare function _compileSimpleVarDecl(ctx: AstCompilationCtx, decl: SimpleVarDecl, typeHint: TirType | undefined): TirSimpleVarDecl | undefined;
20
21
  export declare function _compileNamedDeconstructVarDecl(ctx: AstCompilationCtx, decl: NamedDeconstructVarDecl, typeHint: TirType | undefined): TirNamedDeconstructVarDecl | undefined;
21
22
  export declare function _compileSingleDeconstructVarDecl(ctx: AstCompilationCtx, decl: SingleDeconstructVarDecl, typeHint: TirType | undefined): TirVarDecl | undefined;
22
23
  export declare function _compileArrayLikeDeconstr(ctx: AstCompilationCtx, decl: ArrayLikeDeconstr, typeHint: TirType | undefined): TirArrayLikeDeconstr | undefined;
@@ -27,8 +27,9 @@ export function _compileVarStmt(ctx, stmt) {
27
27
  return tirVarDecls;
28
28
  }
29
29
  export function _compileVarDecl(ctx, decl, typeHint) {
30
- if (decl instanceof SimpleVarDecl)
30
+ if (decl instanceof SimpleVarDecl) {
31
31
  return _compileSimpleVarDecl(ctx, decl, typeHint);
32
+ }
32
33
  if (decl instanceof NamedDeconstructVarDecl)
33
34
  return _compileNamedDeconstructVarDecl(ctx, decl, typeHint);
34
35
  if (decl instanceof SingleDeconstructVarDecl)
@@ -80,6 +80,7 @@ export declare class AstScope {
80
80
  constructor(parent: AstScope | undefined, program: TypedProgram, infos: Partial<ScopeInfos>);
81
81
  defineValue(valueInfos: IVariableInfos): boolean;
82
82
  resolveValue(name: string): ResolveValueResult | undefined;
83
+ allVariables(): string[];
83
84
  defineUnambigousType(name: string, tirTypeKey: string, allowsDataEncoding: boolean, methodsNames: Map<AstFuncName, TirFuncName>): boolean;
84
85
  defineType(name: string, possibleTirTypes: PossibleTirTypes): boolean;
85
86
  resolveLocalType(name: string): PossibleTirTypes | undefined;
@@ -62,6 +62,8 @@ export class AstScope {
62
62
  this.parent = parent;
63
63
  }
64
64
  defineValue(valueInfos) {
65
+ if (valueInfos.name === "§tx_3")
66
+ console.log("Defining variable tx3");
65
67
  if (this._isReadonly)
66
68
  return false;
67
69
  if (invalidSymbolNames.has(valueInfos.name)
@@ -90,6 +92,9 @@ export class AstScope {
90
92
  }
91
93
  return undefined;
92
94
  }
95
+ allVariables() {
96
+ return (this.parent?.allVariables() ?? []).concat(Array.from(this.variables.keys()));
97
+ }
93
98
  defineUnambigousType(name, tirTypeKey, allowsDataEncoding, methodsNames) {
94
99
  if (this._isReadonly)
95
100
  return false;
@@ -6,5 +6,12 @@ export declare class Compiler extends DiagnosticEmitter {
6
6
  readonly io: CompilerIoApi;
7
7
  readonly cfg: CompilerOptions;
8
8
  constructor(io?: CompilerIoApi, cfg?: CompilerOptions, diagnostics?: DiagnosticMessage[]);
9
- compile(config?: Partial<CompilerOptions>): Promise<void>;
9
+ compile(config?: Partial<CompilerOptions>): Promise<Uint8Array>;
10
+ export(config: Partial<ExportOptions> & HasFuncitonName): Promise<Uint8Array>;
10
11
  }
12
+ interface HasFuncitonName {
13
+ functionName: string;
14
+ }
15
+ export interface ExportOptions extends CompilerOptions, HasFuncitonName {
16
+ }
17
+ export {};
@@ -13,6 +13,9 @@ export class Compiler extends DiagnosticEmitter {
13
13
  super(diagnostics);
14
14
  this.io = io;
15
15
  this.cfg = cfg;
16
+ if (cfg.silent === true) {
17
+ this.io.stdout = { write() { } };
18
+ }
16
19
  }
17
20
  async compile(config) {
18
21
  const cfg = {
@@ -31,6 +34,7 @@ export class Compiler extends DiagnosticEmitter {
31
34
  }
32
35
  throw new Error("compilation failed with " + nDiags + " diagnostic messages; first message: " + fstErrorMsg);
33
36
  }
37
+ // backend starts here
34
38
  const ir = compileTypedProgram(cfg, program);
35
39
  const uplc = compileIRToUPLC(ir);
36
40
  const serialized = compileUPLC(new UPLCProgram(cfg.targetUplcVersion, uplc)).toBuffer().buffer;
@@ -39,6 +43,39 @@ export class Compiler extends DiagnosticEmitter {
39
43
  this.io.writeFile(outPath, serialized, cfg.root);
40
44
  this.io.stdout.write(`compiled program written to ${outPath}\n`);
41
45
  __VERY_UNSAFE_FORGET_IRHASH_ONLY_USE_AT_END_OF_UPLC_COMPILATION();
42
- return;
46
+ return serialized;
47
+ }
48
+ async export(config) {
49
+ const cfg = {
50
+ ...this.cfg,
51
+ ...config,
52
+ // NEVER generate markers when exporting a function
53
+ addMarker: false,
54
+ };
55
+ if (typeof cfg.functionName !== "string" || cfg.functionName.length === 0) {
56
+ throw new Error("Compiler::export - invalid function name in export options");
57
+ }
58
+ const astCompiler = new AstCompiler(cfg, this.io, this.diagnostics);
59
+ const program = await astCompiler.export(cfg.functionName, cfg.entry);
60
+ if (this.diagnostics.length > 0) {
61
+ let msg;
62
+ globalThis.console && console.log(this.diagnostics);
63
+ const fstErrorMsg = this.diagnostics[0].toString();
64
+ const nDiags = this.diagnostics.length;
65
+ while (msg = this.diagnostics.shift()) {
66
+ this.io.stdout.write(msg.toString() + "\n");
67
+ }
68
+ throw new Error("compilation failed with " + nDiags + " diagnostic messages; first message: " + fstErrorMsg);
69
+ }
70
+ // backend starts here
71
+ const ir = compileTypedProgram(cfg, program);
72
+ const uplc = compileIRToUPLC(ir, cfg);
73
+ const serialized = compileUPLC(new UPLCProgram(cfg.targetUplcVersion, uplc)).toBuffer().buffer;
74
+ const outDir = cfg.outDir;
75
+ const outPath = outDir + (outDir.endsWith("/") ? "" : "/") + "out.flat";
76
+ this.io.writeFile(outPath, serialized, cfg.root);
77
+ this.io.stdout.write(`compiled program written to ${outPath}\n`);
78
+ __VERY_UNSAFE_FORGET_IRHASH_ONLY_USE_AT_END_OF_UPLC_COMPILATION();
79
+ return serialized;
43
80
  }
44
81
  }
@@ -13,8 +13,9 @@ export function compileTypedProgram(cfg, tirProgram) {
13
13
  );
14
14
  //*/
15
15
  const mainFuncExpr = tirProgram.getMainOrThrow();
16
- // console.log("main func expr:", mainFuncExpr.toString() );
16
+ // console.log("main func:", mainFuncExpr.pretty() );
17
17
  void expressify(mainFuncExpr, undefined, // loopReplacements
18
18
  tirProgram);
19
+ // console.log("main func expressified:", mainFuncExpr.pretty() );
19
20
  return mainFuncExpr.toIR(ToIRTermCtx.root());
20
21
  }
@@ -33,11 +33,11 @@ export declare class ExpressifyCtx {
33
33
  returnType: TirType;
34
34
  readonly program: TypedProgram;
35
35
  /** var name -> latest constant name */
36
- readonly variables: Map<string, LatestVarNameSSA>;
36
+ private readonly variables;
37
37
  /** constant name -> func param name (to build var access) */
38
38
  readonly funcParams: Map<string, ExpressifyFuncParam>;
39
39
  /** constant name -> letted expr */
40
- readonly lettedConstants: Map<string, TirLettedExpr>;
40
+ private readonly lettedConstants;
41
41
  /** var name -> prop name -> constant name (letted field extraction expr or var access for SoP)*/
42
42
  readonly properties: Map<string, Map<string, string>>;
43
43
  readonly hoisted: Map<string, TirHoistedExpr | TirNativeFunc>;
@@ -50,6 +50,7 @@ export declare class ExpressifyCtx {
50
50
  lettedConstants?: Map<string, TirLettedExpr>,
51
51
  /** var name -> prop name -> constant name (letted field extraction expr or var access for SoP)*/
52
52
  properties?: Map<string, Map<string, string>>);
53
+ allVariablesNoLetted(): string[];
53
54
  allVariables(): string[];
54
55
  newChild(): ExpressifyCtx;
55
56
  setNewVariableName(oldName: string, newName: string): void;
@@ -66,6 +67,7 @@ export declare class ExpressifyCtx {
66
67
  */
67
68
  private _getNonHoistedVariable;
68
69
  getVariable(name: string): ExpressifyFuncParam | TirHoistedExpr | TirNativeFunc | TirLettedExpr;
70
+ getVariableSSA(name: string): LatestVarNameSSA | undefined;
69
71
  introduceFuncParams(params: readonly TirSimpleVarDecl[]): void;
70
72
  introduceLettedConstant(name: string, lettedExpr: TirExpr, declRange: SourceRange): TirLettedExpr;
71
73
  introduceSopConstrFieldsAsProperties(sopName: string, destructuredPattern: TirNamedDeconstructVarDecl): void;
@@ -5,6 +5,7 @@ import { TirLitIntExpr } from "../../tir/expressions/litteral/TirLitIntExpr.js";
5
5
  import { TirCallExpr } from "../../tir/expressions/TirCallExpr.js";
6
6
  import { TirElemAccessExpr } from "../../tir/expressions/TirElemAccessExpr.js";
7
7
  import { TirFromDataExpr } from "../../tir/expressions/TirFromDataExpr.js";
8
+ import { TirHoistedExpr } from "../../tir/expressions/TirHoistedExpr.js";
8
9
  import { TirLettedExpr } from "../../tir/expressions/TirLettedExpr.js";
9
10
  import { TirNativeFunc } from "../../tir/expressions/TirNativeFunc.js";
10
11
  import { data_t, int_t } from "../../tir/program/stdScope/stdScope.js";
@@ -48,12 +49,23 @@ export class ExpressifyCtx {
48
49
  this.funcParams = funcParams;
49
50
  this.lettedConstants = lettedConstants;
50
51
  this.properties = properties;
51
- this.hoisted = hoisted ?? this.parent?.hoisted ?? new Map();
52
+ this.hoisted = (hoisted
53
+ ?? this.parent?.hoisted
54
+ ?? new Map([...program.constants.entries()].map(([name, decl]) => {
55
+ if (!decl.initExpr)
56
+ throw new Error(`expected init expr in hoisted constant '${name}'`);
57
+ const expr = decl.initExpr instanceof TirHoistedExpr ? decl.initExpr : new TirHoistedExpr(name, decl.initExpr);
58
+ return [name, expr];
59
+ })));
60
+ }
61
+ allVariablesNoLetted() {
62
+ return (this.parent?.allVariablesNoLetted() ?? []).concat(...this.variables.keys());
52
63
  }
53
64
  allVariables() {
54
65
  const thisVars = new Set([
55
66
  ...this.variables.keys(),
56
- ...this.lettedConstants.keys()
67
+ ...this.lettedConstants.keys(),
68
+ ...this.hoisted.keys(),
57
69
  ]);
58
70
  return (this.parent?.allVariables() ?? []).concat(...thisVars);
59
71
  }
@@ -64,26 +76,32 @@ export class ExpressifyCtx {
64
76
  let latestNameSSA = this.variables.get(oldName);
65
77
  if (!latestNameSSA)
66
78
  this.variables.set(oldName, { latestName: newName });
67
- else
79
+ else {
80
+ const prevName = latestNameSSA.latestName;
81
+ if (prevName === newName)
82
+ return; // no change
68
83
  latestNameSSA.latestName = newName;
84
+ this.setNewVariableName(prevName, newName);
85
+ this.setNewVariableName(newName, newName);
86
+ }
69
87
  }
70
88
  setFuncParam(name, type) {
71
- this.variables.set(name, { latestName: name });
89
+ this.setNewVariableName(name, name);
72
90
  this.funcParams.set(name, { name, type });
73
91
  }
74
92
  /**
75
93
  * `undefined` means the variable is not in the local context.
76
94
  */
77
95
  getLocalVariable(name) {
78
- // declared as constant shortcut
79
- const constResult = this.lettedConstants.get(name);
80
- if (constResult)
81
- return constResult;
82
96
  // declared as variable or param
83
97
  const latestConstName = this.variables.get(name)?.latestName;
84
- // no such variable
85
- if (!latestConstName)
86
- return undefined;
98
+ // no such variable (mutable at least)
99
+ if (!latestConstName) {
100
+ // try to get var declared as constant
101
+ // return undefined if not present
102
+ return this.lettedConstants.get(name);
103
+ }
104
+ ;
87
105
  return (this.lettedConstants.get(latestConstName)
88
106
  ?? this.funcParams.get(latestConstName));
89
107
  }
@@ -101,11 +119,15 @@ export class ExpressifyCtx {
101
119
  const result = (this._getNonHoistedVariable(name)
102
120
  ?? this.hoisted.get(name));
103
121
  if (!result) {
104
- // console.log( this );
122
+ console.log("[error log]: allVariables", this.allVariables());
105
123
  throw new Error(`variable '${name}' not found in the context`);
106
124
  }
107
125
  return result;
108
126
  }
127
+ getVariableSSA(name) {
128
+ return (this.variables.get(name)
129
+ ?? this.parent?.getVariableSSA(name));
130
+ }
109
131
  introduceFuncParams(params) {
110
132
  for (const param of params) {
111
133
  param.isConst = true;
@@ -113,9 +135,13 @@ export class ExpressifyCtx {
113
135
  }
114
136
  }
115
137
  introduceLettedConstant(name, lettedExpr, declRange) {
138
+ // if( this.lettedConstants.has( name ) ) throw new Error(`constant '${name}' already introduced in the context`);
139
+ const existing = this.lettedConstants.get(name);
140
+ if (existing)
141
+ return existing.clone();
116
142
  const result = new TirLettedExpr(name, lettedExpr, declRange);
117
143
  this.lettedConstants.set(name, result);
118
- return result.unsafeClone();
144
+ return result.clone();
119
145
  }
120
146
  introduceSopConstrFieldsAsProperties(sopName, destructuredPattern) {
121
147
  const fieldsMap = new Map();
@@ -182,7 +208,7 @@ export class ExpressifyCtx {
182
208
  assertions.push(new TirAssertStmt(new TirEqualExpr(new TirCallExpr(TirNativeFunc.unConstrDataResultIndex, [lettedUnconstr], int_t, stmt.range), new TirLitIntExpr(BigInt(constrIdx), stmt.range), stmt.range), undefined, // no trace message
183
209
  stmt.range));
184
210
  const lettedRawFieldsName = getUniqueInternalName(`${varName}_fields`);
185
- const lettedFields = this.introduceLettedConstant(lettedRawFieldsName, new TirLettedExpr(lettedRawFieldsName, new TirCallExpr(TirNativeFunc.unConstrDataResultFields, [lettedUnconstr], new TirListT(data_t), stmt.range), stmt.range), stmt.range);
211
+ const lettedFields = this.introduceLettedConstant(lettedRawFieldsName, new TirCallExpr(TirNativeFunc.unConstrDataResultFields, [lettedUnconstr], new TirListT(data_t), stmt.range), stmt.range);
186
212
  const fieldsToIntroduce = [...stmt.fields.keys()];
187
213
  const hasRest = typeof stmt.rest === "string";
188
214
  const fieldsMap = new Map();
@@ -206,7 +232,7 @@ export class ExpressifyCtx {
206
232
  if (!fieldVarDecl)
207
233
  throw new Error(`field '${fieldName}' not found in deconstruct data statement`);
208
234
  if (fieldVarDecl instanceof TirSimpleVarDecl) {
209
- this.variables.set(fieldVarDecl.name, { latestName: lettedField.varName });
235
+ this.setNewVariableName(fieldVarDecl.name, lettedField.varName);
210
236
  }
211
237
  else {
212
238
  // fieldVarDecl.type ??= fieldType;
@@ -246,7 +272,7 @@ export class ExpressifyCtx {
246
272
  lettedExpr = new TirFromDataExpr(lettedExpr, elemVarDecl.type, elemVarDecl.range);
247
273
  const lettedElem = this.introduceLettedConstant(lettedElemName, lettedExpr, elemVarDecl.range);
248
274
  if (elemVarDecl instanceof TirSimpleVarDecl) {
249
- this.variables.set(elemVarDecl.name, { latestName: lettedElem.varName });
275
+ this.setNewVariableName(elemVarDecl.name, lettedElem.varName);
250
276
  if (lettedElem.type instanceof TirDataStructType
251
277
  && lettedElem.type.constructors.length === 1) {
252
278
  // if the element is a single-constructor data struct,
@@ -148,6 +148,8 @@ export function determineReassignedVariablesAndFlowInfos(stmt) {
148
148
  continue;
149
149
  }
150
150
  const tsEnsureExsaustiveCheck = stmt;
151
+ console.error("unexpected", stmt);
152
+ throw new Error("unexpected statement type");
151
153
  }
152
154
  let reassigned = [...reassignedSet].sort();
153
155
  reassigned = keepSortedStrArrInplace(reassigned, originalStmtDeps);
@@ -41,6 +41,8 @@ import { TirCallExpr } from "../../tir/expressions/TirCallExpr.js";
41
41
  import { TirNativeFunc } from "../../tir/expressions/TirNativeFunc.js";
42
42
  export function expressify(func, loopReplacements, program, parentCtx = undefined) {
43
43
  const ctx = new ExpressifyCtx(parentCtx, func.returnType, program);
44
+ // define in case of recursion
45
+ ctx.setFuncParam(func.name, func.type);
44
46
  ctx.introduceFuncParams(func.params);
45
47
  func.body.stmts = [
46
48
  new TirReturnStmt(expressifyFuncBody(ctx, func.body.stmts, loopReplacements), func.body.range)
@@ -52,8 +54,9 @@ loopReplacements, assertions = []) {
52
54
  bodyStmts = bodyStmts.slice();
53
55
  let stmt;
54
56
  while (stmt = bodyStmts.shift()) {
55
- // console.log([stmt, ...bodyStmts].map(s => s.toString()));
56
- // console.log( stmt );
57
+ // const isEdgeCase = stmt instanceof TirForStmt || stmt instanceof TirForOfStmt || stmt instanceof TirWhileStmt;
58
+ // if( isEdgeCase ) console.log([stmt, ...bodyStmts].map(s => s.toString()));
59
+ // if( isEdgeCase ) console.log( stmt );
57
60
  if (stmt instanceof TirBreakStmt) {
58
61
  if (typeof loopReplacements?.compileBreak !== "function")
59
62
  throw new Error("break statement in function body.");
@@ -83,9 +86,8 @@ loopReplacements, assertions = []) {
83
86
  throw new Error("simple var decl without init expr");
84
87
  const initExpr = expressifyVars(ctx, stmt.initExpr);
85
88
  stmt.initExpr = initExpr;
86
- const lettedExpr = ctx.introduceLettedConstant(stmt.name, initExpr, stmt.range);
89
+ const lettedExpr = initExpr instanceof TirLettedExpr ? initExpr : ctx.introduceLettedConstant(stmt.name, initExpr, stmt.range);
87
90
  if (!stmt.isConst) {
88
- // console.log("setting variable")
89
91
  ctx.setNewVariableName(stmt.name, lettedExpr.varName);
90
92
  }
91
93
  if (!isSingleConstrStruct(stmt.type))
@@ -186,7 +188,18 @@ loopReplacements, assertions = []) {
186
188
  continue;
187
189
  }
188
190
  else if (stmt instanceof TirAssignmentStmt) {
189
- bodyStmts.unshift(expressifyVarAssignmentStmt(ctx, stmt));
191
+ void expressifyVarAssignmentStmt(ctx, stmt);
192
+ // !!! IMPORTANT BUG !!!
193
+ // .unshift the resulting `TirSimpleVarDecl` into bodyStmts
194
+ // will cause the assigned expression to be re-expressified
195
+ // meaning that variables that depend on themselves (e.g. `x = x + 1`) will be processed twice
196
+ //
197
+ // x = (x + 1) --> const x_i = (x + 1) --> const x_i = (x_i/*x + 1*/ */ + 1) (??? BUG ???)
198
+ //
199
+ // so ultimately `x = x + 1` would be compiled as `x = x + 1 + 1`
200
+ //
201
+ // const constDecl = expressifyVarAssignmentStmt( ctx, stmt );
202
+ // bodyStmts.unshift( constDecl );
190
203
  continue;
191
204
  }
192
205
  else if (stmt instanceof TirBlockStmt) {
@@ -354,8 +367,10 @@ loopReplacements, assertions = []) {
354
367
  const returnTypeAndInvalidInit = getBranchStmtReturnType(reassignedAndFlow, ctx, stmt.range);
355
368
  const forStmt = loopToForStmt(stmt);
356
369
  const { bodyStateType, initState } = getBodyStateType(returnTypeAndInvalidInit, forStmt);
357
- const loopExpr = expressifyForStmt(ctx.newChild(), forStmt, returnTypeAndInvalidInit.sop, bodyStateType, initState);
358
- return TirAssertAndContinueExpr.fromStmtsAndContinuation(assertions, definitelyTerminates ? loopExpr : wrapNonTerminatingFinalStmtAsCaseExpr(loopExpr, returnTypeAndInvalidInit.sop, ctx, stmt.range, reassignedAndFlow, bodyStmts, loopReplacements));
370
+ const loopExprCtx = ctx.newChild();
371
+ const loopExpr = expressifyForStmt(loopExprCtx, forStmt, returnTypeAndInvalidInit.sop, bodyStateType, initState);
372
+ const result = TirAssertAndContinueExpr.fromStmtsAndContinuation(assertions, definitelyTerminates ? loopExpr : wrapNonTerminatingFinalStmtAsCaseExpr(loopExpr, returnTypeAndInvalidInit.sop, ctx, stmt.range, reassignedAndFlow, bodyStmts, loopReplacements));
373
+ return result;
359
374
  }
360
375
  else {
361
376
  // const tsEnsureExhautstiveCheck: never = stmt;
@@ -402,6 +417,7 @@ function getNestedDestructsInSingleSopDestructPattern(pattern) {
402
417
  return result;
403
418
  }
404
419
  function wrapNonTerminatingFinalStmtAsCaseExpr(finalStmtExpr, sop, ctx, stmtRange, reassignsAndReturns, nextBodyStmts, loopReplacements) {
420
+ nextBodyStmts = nextBodyStmts.slice();
405
421
  const continuations = [];
406
422
  const contBranchCtx = ctx.newChild();
407
423
  const contConstr = sop.constructors[0];
@@ -416,9 +432,10 @@ function wrapNonTerminatingFinalStmtAsCaseExpr(finalStmtExpr, sop, ctx, stmtRang
416
432
  false, // not a constant
417
433
  stmtRange);
418
434
  const nestedDeconstructs = flattenSopNamedDeconstructInplace_addTopDestructToCtx_getNestedDeconstruct(contPattern, contBranchCtx);
419
- continuations.push(new TirCaseMatcher(contPattern, expressifyFuncBody(contBranchCtx, nestedDeconstructs
435
+ const mainContinuaiton = expressifyFuncBody(contBranchCtx, nestedDeconstructs
420
436
  .concat(nextBodyStmts), loopReplacements, [] // assertions are added before if statement exectution
421
- ), stmtRange));
437
+ );
438
+ continuations.push(new TirCaseMatcher(contPattern, mainContinuaiton, stmtRange));
422
439
  if (reassignsAndReturns.returns) {
423
440
  const earlyRetConstr = sop.constructors[1];
424
441
  const earlyRetField = earlyRetConstr.fields[0];
@@ -20,6 +20,7 @@ import { TirFuncT } from "../../tir/types/TirNativeType/native/function.js";
20
20
  import { getListTypeArg } from "../../tir/types/utils/getListTypeArg.js";
21
21
  import { expressifyFuncBody } from "./expressify.js";
22
22
  import { isExpressifyFuncParam } from "./ExpressifyCtx.js";
23
+ import { expressifyVars } from "./expressifyVars.js";
23
24
  export function loopToForStmt(stmt) {
24
25
  if (stmt instanceof TirForStmt)
25
26
  return stmt;
@@ -70,8 +71,14 @@ export function loopToForStmt(stmt) {
70
71
  export function expressifyForStmt(ctx, stmt, returnType, bodyStateType, initState) {
71
72
  let loopBody = stmt.body instanceof TirBlockStmt ? stmt.body : new TirBlockStmt([stmt.body], stmt.range);
72
73
  loopBody = new TirBlockStmt(loopBody.stmts.slice(), loopBody.range);
74
+ // add final loop updates
75
+ if (Array.isArray(stmt.update))
76
+ for (const updateStmt of stmt.update) {
77
+ loopBody.stmts.push(updateStmt);
78
+ }
79
+ // ALWAYS add a final `continue;` to the end of the loop body
80
+ loopBody.stmts.push(new TirContinueStmt(loopBody.range.atEnd()));
73
81
  if (stmt.condition) {
74
- loopBody.stmts.push(new TirContinueStmt(loopBody.range.atEnd()));
75
82
  loopBody = new TirBlockStmt([
76
83
  new TirIfStmt(stmt.condition,
77
84
  // then
@@ -80,8 +87,6 @@ export function expressifyForStmt(ctx, stmt, returnType, bodyStateType, initStat
80
87
  new TirBlockStmt([new TirBreakStmt(stmt.condition.range)], stmt.condition.range), stmt.condition.range)
81
88
  ], loopBody.range);
82
89
  }
83
- // ALWAYS add a final `continue;` to the end of the loop body
84
- loopBody.stmts.push(new TirContinueStmt(loopBody.range.atEnd()));
85
90
  const loopFuncName = getUniqueInternalName("loop");
86
91
  const loopFuncType = new TirFuncT(bodyStateType.constructors[0].fields.map(f => f.type), returnType);
87
92
  const loopReplacements = {
@@ -154,11 +159,22 @@ export function expressifyForStmt(ctx, stmt, returnType, bodyStateType, initStat
154
159
  for (const { name, type } of bodyStateType.constructors[0].fields) {
155
160
  loopCompilationCtx.setFuncParam(name, type);
156
161
  }
157
- return new TirCallExpr(new TirFuncExpr(loopFuncName, bodyStateType.constructors[0].fields.map(f => new TirSimpleVarDecl(f.name, f.type, undefined, // no initial value
162
+ const loopFuncExpr = new TirFuncExpr(loopFuncName, // func name
163
+ // func params
164
+ bodyStateType.constructors[0].fields.map(f => new TirSimpleVarDecl(f.name, f.type, undefined, // no initial value
158
165
  false, // is constant
159
- stmt.range)), returnType, new TirBlockStmt([
166
+ stmt.range)),
167
+ // func return type
168
+ returnType,
169
+ // func body
170
+ new TirBlockStmt([
160
171
  new TirReturnStmt(expressifyFuncBody(loopCompilationCtx, loopBody.stmts, loopReplacements, [] // assertions
161
172
  ), stmt.range)
162
- ], stmt.range), stmt.range, true // is loop
163
- ), initState.values, returnType, stmt.range);
173
+ ], stmt.range),
174
+ // func range
175
+ stmt.range, true // is loop
176
+ );
177
+ return new TirCallExpr(loopFuncExpr,
178
+ // loop call init args
179
+ initState.values.map(v => expressifyVars(ctx, v.clone())), returnType, stmt.range);
164
180
  }
@@ -1,4 +1,3 @@
1
1
  import { TirAssignmentStmt } from "../../tir/statements/TirAssignmentStmt.js";
2
- import { TirSimpleVarDecl } from "../../tir/statements/TirVarDecl/TirSimpleVarDecl.js";
3
2
  import { ExpressifyCtx } from "./ExpressifyCtx.js";
4
- export declare function expressifyVarAssignmentStmt(ctx: ExpressifyCtx, stmt: TirAssignmentStmt): TirSimpleVarDecl;
3
+ export declare function expressifyVarAssignmentStmt(ctx: ExpressifyCtx, stmt: TirAssignmentStmt): void;
@@ -1,20 +1,27 @@
1
1
  import { getUniqueInternalName } from "../../internalVar.js";
2
- import { TirLettedExpr } from "../../tir/expressions/TirLettedExpr.js";
3
- import { TirSimpleVarDecl } from "../../tir/statements/TirVarDecl/TirSimpleVarDecl.js";
4
2
  import { expressifyVars } from "./expressifyVars.js";
5
3
  export function expressifyVarAssignmentStmt(ctx, stmt) {
4
+ // since we no longer return a new TirSimpleVarDecl,
5
+ // we need to expressify the assigned expression here
6
+ //
7
+ // !!! IMPORTANT !!! we MUST NOT do it if we instead returned a new TirSimpleVarDecl,
8
+ // otherwise it would be re-processed, casing bugs
6
9
  const assignedExpr = expressifyVars(ctx, stmt.assignedExpr);
7
10
  const originalName = stmt.varIdentifier.resolvedValue.variableInfos.name;
8
- const latestVarNameSSA = ctx.variables.get(originalName);
11
+ const latestVarNameSSA = ctx.getVariableSSA(originalName);
9
12
  if (!latestVarNameSSA) {
10
13
  throw new Error("re-assigning constant variable '" + originalName + "'");
11
14
  }
12
15
  const newUniqueName = getUniqueInternalName(originalName);
13
- latestVarNameSSA.latestName = newUniqueName;
16
+ ctx.setNewVariableName(originalName, newUniqueName);
14
17
  // point to the same object
15
- ctx.variables.set(newUniqueName, latestVarNameSSA);
16
- ctx.lettedConstants.set(newUniqueName, new TirLettedExpr(newUniqueName, assignedExpr, stmt.range));
18
+ ctx.introduceLettedConstant(newUniqueName, assignedExpr, stmt.range);
17
19
  // will replace re-assignment in body
18
- return new TirSimpleVarDecl(newUniqueName, stmt.varIdentifier.resolvedValue.variableInfos.type, assignedExpr, true, // isConst
19
- stmt.range);
20
+ // return new TirSimpleVarDecl(
21
+ // newUniqueName,
22
+ // stmt.varIdentifier.resolvedValue.variableInfos.type,
23
+ // assignedExpr,
24
+ // true, // isConst
25
+ // stmt.range,
26
+ // );
20
27
  }
@@ -1,4 +1,3 @@
1
- import { TirLettedExpr } from "../../tir/expressions/TirLettedExpr.js";
2
1
  import { TirArrayLikeDeconstr } from "../../tir/statements/TirVarDecl/TirArrayLikeDeconstr.js";
3
2
  import { TirNamedDeconstructVarDecl } from "../../tir/statements/TirVarDecl/TirNamedDeconstructVarDecl.js";
4
3
  import { TirSimpleVarDecl } from "../../tir/statements/TirVarDecl/TirSimpleVarDecl.js";
@@ -6,30 +5,28 @@ import { TirSingleDeconstructVarDecl } from "../../tir/statements/TirVarDecl/Tir
6
5
  import { expressifyVars } from "./expressifyVars.js";
7
6
  export function expressifyVarDecl(ctx, stmt) {
8
7
  const isConst = stmt.isConst;
9
- console.log("expressifyVarDecl", stmt);
10
8
  if (stmt.initExpr)
11
9
  expressifyVars(ctx, stmt.initExpr);
12
10
  if (stmt instanceof TirSimpleVarDecl) {
13
- if (stmt.isConst) {
14
- void ctx.variables.set(stmt.name, { latestName: stmt.name });
15
- /// @ts-ignore Cannot assign to 'isConst' because it is a read-only property.
16
- stmt.isConst = true;
11
+ if (!stmt.isConst) {
12
+ void ctx.setNewVariableName(stmt.name, stmt.name);
13
+ // stmt.isConst = true;
17
14
  }
18
- ctx.lettedConstants.set(stmt.name, new TirLettedExpr(stmt.name, stmt.initExpr, stmt.range));
15
+ ctx.introduceLettedConstant(stmt.name, stmt.initExpr, stmt.range);
19
16
  }
20
17
  if (stmt instanceof TirNamedDeconstructVarDecl
21
18
  || stmt instanceof TirSingleDeconstructVarDecl) {
22
19
  for (const [_field, varDecl] of stmt.fields)
23
20
  expressifyVarDecl(ctx, varDecl);
24
21
  if (stmt.rest)
25
- ctx.variables.set(stmt.rest, { latestName: stmt.rest });
22
+ ctx.setNewVariableName(stmt.rest, stmt.rest);
26
23
  return;
27
24
  }
28
25
  if (stmt instanceof TirArrayLikeDeconstr) {
29
26
  for (const varDecl of stmt.elements)
30
27
  expressifyVarDecl(ctx, varDecl);
31
28
  if (stmt.rest)
32
- ctx.variables.set(stmt.rest, { latestName: stmt.rest });
29
+ ctx.setNewVariableName(stmt.rest, stmt.rest);
33
30
  return;
34
31
  }
35
32
  }