@harmoniclabs/pebble 0.1.0-dev6 → 0.1.0-dev7

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 (67) hide show
  1. package/dist/IR/IRNodes/IRNative/IRNativeTag.d.ts +3 -1
  2. package/dist/IR/IRNodes/IRNative/IRNativeTag.js +4 -0
  3. package/dist/IR/IRNodes/IRNative/index.d.ts +1 -0
  4. package/dist/IR/IRNodes/IRNative/index.js +1 -0
  5. package/dist/IR/toUPLC/CompilerOptions.d.ts +5 -0
  6. package/dist/IR/toUPLC/CompilerOptions.js +10 -1
  7. package/dist/IR/toUPLC/compileIRToUPLC.js +1 -1
  8. package/dist/IR/toUPLC/ctx/ToUplcCtx.js +2 -10
  9. package/dist/IR/toUPLC/subRoutines/handleLetted/groupByScope.js +0 -2
  10. package/dist/IR/toUPLC/subRoutines/replaceNatives/nativeToIR.d.ts +2 -0
  11. package/dist/IR/toUPLC/subRoutines/replaceNatives/nativeToIR.js +23 -1
  12. package/dist/IR/utils/isClosedIRTerm.js +1 -1
  13. package/dist/IR/utils/positiveIntAsBytes.js +0 -4
  14. package/dist/compiler/AstCompiler/AstCompiler.d.ts +1 -0
  15. package/dist/compiler/AstCompiler/AstCompiler.js +39 -2
  16. package/dist/compiler/AstCompiler/internal/_deriveContractBody/_deriveContractBody.js +1 -1
  17. package/dist/compiler/AstCompiler/internal/exprs/_compileExpr.js +4 -0
  18. package/dist/compiler/AstCompiler/internal/exprs/_compileFuncExpr.js +7 -4
  19. package/dist/compiler/AstCompiler/internal/exprs/_compileTypeConversionExpr.js +0 -1
  20. package/dist/compiler/AstCompiler/internal/exprs/_compileVarAccessExpr.js +3 -1
  21. package/dist/compiler/AstCompiler/internal/statements/_compileAssignmentStmt.js +7 -7
  22. package/dist/compiler/AstCompiler/internal/statements/_compileVarStmt.d.ts +2 -1
  23. package/dist/compiler/AstCompiler/internal/statements/_compileVarStmt.js +2 -1
  24. package/dist/compiler/AstCompiler/scope/AstScope.d.ts +1 -0
  25. package/dist/compiler/AstCompiler/scope/AstScope.js +5 -0
  26. package/dist/compiler/Compiler.js +4 -0
  27. package/dist/compiler/TirCompiler/compileTirProgram.js +2 -1
  28. package/dist/compiler/TirCompiler/expressify/ExpressifyCtx.d.ts +4 -2
  29. package/dist/compiler/TirCompiler/expressify/ExpressifyCtx.js +42 -16
  30. package/dist/compiler/TirCompiler/expressify/determineReassignedVariablesAndReturn.js +2 -0
  31. package/dist/compiler/TirCompiler/expressify/expressify.js +24 -9
  32. package/dist/compiler/TirCompiler/expressify/expressifyForStmt.js +23 -7
  33. package/dist/compiler/TirCompiler/expressify/expressifyVarAssignmentStmt.d.ts +1 -2
  34. package/dist/compiler/TirCompiler/expressify/expressifyVarAssignmentStmt.js +15 -8
  35. package/dist/compiler/TirCompiler/expressify/expressifyVarDecl.js +6 -9
  36. package/dist/compiler/TirCompiler/expressify/expressifyVars.js +15 -4
  37. package/dist/compiler/TirCompiler/expressify/flattenSopNamedDeconstructInplace_addTopDestructToCtx_getNestedDeconstruct.js +1 -0
  38. package/dist/compiler/internalVar.d.ts +1 -1
  39. package/dist/compiler/internalVar.js +31 -24
  40. package/dist/compiler/io/CompilerIoApi.d.ts +1 -1
  41. package/dist/compiler/tir/expressions/TirCallExpr.d.ts +1 -1
  42. package/dist/compiler/tir/expressions/TirCallExpr.js +1 -1
  43. package/dist/compiler/tir/expressions/TirCaseExpr.js +2 -0
  44. package/dist/compiler/tir/expressions/TirFromDataExpr.js +2 -2
  45. package/dist/compiler/tir/expressions/TirFuncExpr.d.ts +1 -1
  46. package/dist/compiler/tir/expressions/TirFuncExpr.js +1 -1
  47. package/dist/compiler/tir/expressions/TirLettedExpr.d.ts +2 -2
  48. package/dist/compiler/tir/expressions/TirLettedExpr.js +4 -6
  49. package/dist/compiler/tir/expressions/TirNativeFunc.d.ts +1 -0
  50. package/dist/compiler/tir/expressions/TirNativeFunc.js +9 -1
  51. package/dist/compiler/tir/expressions/TirPropAccessExpr.js +1 -2
  52. package/dist/compiler/tir/expressions/TirVariableAccessExpr.d.ts +0 -1
  53. package/dist/compiler/tir/expressions/TirVariableAccessExpr.js +9 -5
  54. package/dist/compiler/tir/expressions/ToIRTermCtx.d.ts +3 -0
  55. package/dist/compiler/tir/expressions/ToIRTermCtx.js +8 -1
  56. package/dist/compiler/tir/expressions/binary/TirBinaryExpr.d.ts +1 -0
  57. package/dist/compiler/tir/expressions/binary/TirBinaryExpr.js +6 -1
  58. package/dist/compiler/tir/program/TypedProgram.d.ts +2 -2
  59. package/dist/compiler/tir/program/stdScope/stdScope.js +9 -23
  60. package/dist/compiler/tir/statements/TirIfStmt.d.ts +0 -1
  61. package/dist/compiler/tir/statements/TirIfStmt.js +0 -3
  62. package/dist/parser/Parser.js +18 -2
  63. package/dist/parser/Precedence.js +1 -0
  64. package/dist/utils/array/keepSortedArrInplace.js +1 -0
  65. package/package.json +2 -1
  66. package/dist/compiler/TirCompiler/internal/_compileHoistedDeps.d.ts +0 -5
  67. package/dist/compiler/TirCompiler/internal/_compileHoistedDeps.js +0 -39
@@ -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(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);
@@ -52,8 +52,9 @@ loopReplacements, assertions = []) {
52
52
  bodyStmts = bodyStmts.slice();
53
53
  let stmt;
54
54
  while (stmt = bodyStmts.shift()) {
55
- // console.log([stmt, ...bodyStmts].map(s => s.toString()));
56
- // console.log( stmt );
55
+ // const isEdgeCase = stmt instanceof TirForStmt || stmt instanceof TirForOfStmt || stmt instanceof TirWhileStmt;
56
+ // if( isEdgeCase ) console.log([stmt, ...bodyStmts].map(s => s.toString()));
57
+ // if( isEdgeCase ) console.log( stmt );
57
58
  if (stmt instanceof TirBreakStmt) {
58
59
  if (typeof loopReplacements?.compileBreak !== "function")
59
60
  throw new Error("break statement in function body.");
@@ -83,9 +84,8 @@ loopReplacements, assertions = []) {
83
84
  throw new Error("simple var decl without init expr");
84
85
  const initExpr = expressifyVars(ctx, stmt.initExpr);
85
86
  stmt.initExpr = initExpr;
86
- const lettedExpr = ctx.introduceLettedConstant(stmt.name, initExpr, stmt.range);
87
+ const lettedExpr = initExpr instanceof TirLettedExpr ? initExpr : ctx.introduceLettedConstant(stmt.name, initExpr, stmt.range);
87
88
  if (!stmt.isConst) {
88
- // console.log("setting variable")
89
89
  ctx.setNewVariableName(stmt.name, lettedExpr.varName);
90
90
  }
91
91
  if (!isSingleConstrStruct(stmt.type))
@@ -186,7 +186,18 @@ loopReplacements, assertions = []) {
186
186
  continue;
187
187
  }
188
188
  else if (stmt instanceof TirAssignmentStmt) {
189
- bodyStmts.unshift(expressifyVarAssignmentStmt(ctx, stmt));
189
+ void expressifyVarAssignmentStmt(ctx, stmt);
190
+ // !!! IMPORTANT BUG !!!
191
+ // .unshift the resulting `TirSimpleVarDecl` into bodyStmts
192
+ // will cause the assigned expression to be re-expressified
193
+ // meaning that variables that depend on themselves (e.g. `x = x + 1`) will be processed twice
194
+ //
195
+ // x = (x + 1) --> const x_i = (x + 1) --> const x_i = (x_i/*x + 1*/ */ + 1) (??? BUG ???)
196
+ //
197
+ // so ultimately `x = x + 1` would be compiled as `x = x + 1 + 1`
198
+ //
199
+ // const constDecl = expressifyVarAssignmentStmt( ctx, stmt );
200
+ // bodyStmts.unshift( constDecl );
190
201
  continue;
191
202
  }
192
203
  else if (stmt instanceof TirBlockStmt) {
@@ -354,8 +365,10 @@ loopReplacements, assertions = []) {
354
365
  const returnTypeAndInvalidInit = getBranchStmtReturnType(reassignedAndFlow, ctx, stmt.range);
355
366
  const forStmt = loopToForStmt(stmt);
356
367
  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));
368
+ const loopExprCtx = ctx.newChild();
369
+ const loopExpr = expressifyForStmt(loopExprCtx, forStmt, returnTypeAndInvalidInit.sop, bodyStateType, initState);
370
+ const result = TirAssertAndContinueExpr.fromStmtsAndContinuation(assertions, definitelyTerminates ? loopExpr : wrapNonTerminatingFinalStmtAsCaseExpr(loopExpr, returnTypeAndInvalidInit.sop, ctx, stmt.range, reassignedAndFlow, bodyStmts, loopReplacements));
371
+ return result;
359
372
  }
360
373
  else {
361
374
  // const tsEnsureExhautstiveCheck: never = stmt;
@@ -402,6 +415,7 @@ function getNestedDestructsInSingleSopDestructPattern(pattern) {
402
415
  return result;
403
416
  }
404
417
  function wrapNonTerminatingFinalStmtAsCaseExpr(finalStmtExpr, sop, ctx, stmtRange, reassignsAndReturns, nextBodyStmts, loopReplacements) {
418
+ nextBodyStmts = nextBodyStmts.slice();
405
419
  const continuations = [];
406
420
  const contBranchCtx = ctx.newChild();
407
421
  const contConstr = sop.constructors[0];
@@ -416,9 +430,10 @@ function wrapNonTerminatingFinalStmtAsCaseExpr(finalStmtExpr, sop, ctx, stmtRang
416
430
  false, // not a constant
417
431
  stmtRange);
418
432
  const nestedDeconstructs = flattenSopNamedDeconstructInplace_addTopDestructToCtx_getNestedDeconstruct(contPattern, contBranchCtx);
419
- continuations.push(new TirCaseMatcher(contPattern, expressifyFuncBody(contBranchCtx, nestedDeconstructs
433
+ const mainContinuaiton = expressifyFuncBody(contBranchCtx, nestedDeconstructs
420
434
  .concat(nextBodyStmts), loopReplacements, [] // assertions are added before if statement exectution
421
- ), stmtRange));
435
+ );
436
+ continuations.push(new TirCaseMatcher(contPattern, mainContinuaiton, stmtRange));
422
437
  if (reassignsAndReturns.returns) {
423
438
  const earlyRetConstr = sop.constructors[1];
424
439
  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
  }
@@ -90,13 +90,17 @@ export function expressifyVars(ctx, expr) {
90
90
  const resolvedVariable = ctx.getVariable(originalVarName);
91
91
  if (!resolvedVariable)
92
92
  return expr; // variable not found, keep the original expression
93
+ // if variable was shadowed
93
94
  if (isExpressifyFuncParam(resolvedVariable)) {
94
- // variable was shadowed
95
+ // !!! IMPORTANT !!!
96
+ // we must clone the expression to avoid modifying other instances of it elsewhere
97
+ // THIS IS CRUCIAL I SPENT A DAY DEBUGGING THIS
98
+ expr = expr.clone();
95
99
  expr.resolvedValue.variableInfos.name = resolvedVariable.name;
96
100
  return expr;
97
101
  }
98
102
  // resovledVariable instanceof TirVariableAccessExpr
99
- return resolvedVariable;
103
+ return resolvedVariable.clone();
100
104
  }
101
105
  if (isTirUnaryPrefixExpr(expr)) {
102
106
  const modifiedExpr = expressifyVars(ctx, expr.operand);
@@ -248,7 +252,7 @@ function expressifyPropAccess(ctx, propAccessExpr) {
248
252
  let varName = ctx.properties.get("this")?.get(prop);
249
253
  if (!varName)
250
254
  throw new Error(`Property '${prop}' does not exist on 'this'`);
251
- varName = ctx.variables.get(varName)?.latestName ?? varName;
255
+ varName = ctx.getVariableSSA(varName)?.latestName ?? varName;
252
256
  const expr = ctx.getVariable(varName);
253
257
  if (isExpressifyFuncParam(expr)) {
254
258
  return new TirVariableAccessExpr({
@@ -288,7 +292,7 @@ function expressifyPropAccess(ctx, propAccessExpr) {
288
292
  || expr instanceof TirVariableAccessExpr) {
289
293
  let varName = ctx.properties.get(expr.varName)?.get(prop);
290
294
  if (varName) {
291
- varName = ctx.variables.get(varName)?.latestName ?? varName;
295
+ varName = ctx.getVariableSSA(varName)?.latestName ?? varName;
292
296
  const result = ctx.getVariable(varName);
293
297
  if (isExpressifyFuncParam(result)) {
294
298
  return new TirVariableAccessExpr({
@@ -421,6 +425,13 @@ function expressifyListMethodCall(ctx, objectExpr, methodCall, methodName, listT
421
425
  throw new Error(`Method 'isEmpty' of type 'list' takes 0 arguments, ${methodCall.args.length} provided`);
422
426
  return new TirCallExpr(TirNativeFunc.nullList(elemsType), [objectExpr], methodCall.type, exprRange);
423
427
  }
428
+ if (methodName === "find") {
429
+ if (methodCall.args.length !== 1)
430
+ throw new Error(`Method 'find' of type 'list' takes 1 argument, ${methodCall.args.length} provided`);
431
+ // const finalType = getUnaliased( methodCall.type );
432
+ // console.log( finalType );
433
+ return new TirCallExpr(TirNativeFunc._findSopOptional(elemsType), [methodCall.args[0], objectExpr], methodCall.type, exprRange);
434
+ }
424
435
  // TODO
425
436
  /*
426
437
  {
@@ -15,6 +15,7 @@ export function flattenSopNamedDeconstructInplace_addTopDestructToCtx_getNestedD
15
15
  if (varDecl instanceof TirSimpleVarDecl) {
16
16
  restFields.set(fName, varDecl.name);
17
17
  ctx.introduceFuncParams([varDecl]);
18
+ ctx.setNewVariableName(fName, varDecl.name); // added to fix reassigned variables on non-terminating statements
18
19
  if (isSingleConstrStruct(varDecl.type)) {
19
20
  const structType = getUnaliased(varDecl.type);
20
21
  const constr = structType.constructors[0];
@@ -6,8 +6,8 @@ export declare const PEBBLE_INTERNAL_IDENTIFIER_SEPARATOR = "#";
6
6
  * Creates and tracks unique internal variable names for the Pebble compiler
7
7
  */
8
8
  export declare class UidGenerator {
9
+ private counter;
9
10
  constructor();
10
- private readonly uids;
11
11
  getUid(): string;
12
12
  /**
13
13
  * Generates a unique internal variable name
@@ -1,39 +1,46 @@
1
- import { isObject } from "@harmoniclabs/obj-utils";
2
- import { toHex } from "@harmoniclabs/uint8array-utils";
3
1
  /** invalid char for normal js identifiers */
4
2
  export const PEBBLE_INTERNAL_IDENTIFIER_PREFIX = "§";
5
3
  /** invalid char for normal js identifiers */
6
4
  export const PEBBLE_INTERNAL_IDENTIFIER_SEPARATOR = "#";
7
5
  // Keep getRandomBytes outside the class as requested
8
- let getRandomBytes = (bytes) => {
9
- for (let i = 0; i < bytes.length; i++)
10
- bytes[i] = ((Math.random() * 0x100) >>> 0);
11
- return bytes;
12
- };
13
- try {
14
- if (typeof globalThis !== "undefined"
15
- && typeof globalThis.crypto !== "undefined"
16
- && isObject(globalThis.crypto)
17
- && typeof globalThis.crypto.getRandomValues === "function")
18
- getRandomBytes = globalThis.crypto.getRandomValues.bind(globalThis.crypto);
19
- }
20
- catch { }
21
- const uidSet = new Set();
6
+ // let getRandomBytes = (bytes: Uint8Array) => {
7
+ // for (let i = 0; i < bytes.length; i++)
8
+ // bytes[i] = ((Math.random() * 0x100) >>> 0);
9
+ // return bytes;
10
+ // }
11
+ //
12
+ // try {
13
+ // if (
14
+ // typeof globalThis !== "undefined"
15
+ // && typeof globalThis.crypto !== "undefined"
16
+ // && isObject(globalThis.crypto)
17
+ // && typeof globalThis.crypto.getRandomValues === "function"
18
+ // ) getRandomBytes = globalThis.crypto.getRandomValues.bind(globalThis.crypto);
19
+ // } catch {}
20
+ //
21
+ // const uidSet = new Set<string>();
22
22
  /**
23
23
  * Creates and tracks unique internal variable names for the Pebble compiler
24
24
  */
25
25
  export class UidGenerator {
26
+ counter;
26
27
  constructor() {
27
- this.uids = uidSet;
28
+ // this.uids = uidSet;
29
+ this.counter = 0n;
28
30
  }
29
- uids;
31
+ // private readonly uids: Set<string>;
32
+ // getUid(): string {
33
+ // const bytes = new Uint8Array(Math.max(1, Math.log1p(this.uids.size) >>> 0));
34
+ // let uid: string;
35
+ // do {
36
+ // uid = toHex(getRandomBytes(bytes));
37
+ // } while( this.uids.has( uid ) );
38
+ // this.uids.add(uid);
39
+ // return uid;
40
+ // }
30
41
  getUid() {
31
- const bytes = new Uint8Array(Math.max(1, Math.log1p(this.uids.size) >>> 0));
32
- let uid;
33
- do {
34
- uid = toHex(getRandomBytes(bytes));
35
- } while (this.uids.has(uid));
36
- this.uids.add(uid);
42
+ const uid = this.counter.toString(36);
43
+ this.counter++;
37
44
  return uid;
38
45
  }
39
46
  /**
@@ -4,7 +4,7 @@ import { IOutputStream } from "./IOutputStream.js";
4
4
  /** Compiler API options. */
5
5
  export interface CompilerIoApi {
6
6
  /** Standard output stream to use. */
7
- readonly stdout: IOutputStream;
7
+ stdout: IOutputStream;
8
8
  /** Standard error stream to use. */
9
9
  readonly stderr: IOutputStream;
10
10
  /** Reads a file from disk (or memory). */
@@ -11,7 +11,7 @@ export declare class TirCallExpr implements ITirExpr {
11
11
  readonly range: SourceRange;
12
12
  constructor(func: TirExpr, args: TirExpr[], type: TirType, range: SourceRange);
13
13
  toString(): string;
14
- pretty(indent: number): string;
14
+ pretty(indent?: number): string;
15
15
  clone(): TirExpr;
16
16
  deps(): string[];
17
17
  get isConstant(): boolean;
@@ -14,7 +14,7 @@ export class TirCallExpr {
14
14
  toString() {
15
15
  return `${this.func.toString()}( ${this.args.map(a => a.toString()).join(", ")} )`;
16
16
  }
17
- pretty(indent) {
17
+ pretty(indent = 1) {
18
18
  const singleIndent = " ";
19
19
  const indent_base = singleIndent.repeat(indent);
20
20
  const indent_0 = "\n" + indent_base;
@@ -69,6 +69,7 @@ export class TirCaseExpr {
69
69
  }
70
70
  get isConstant() { return false; }
71
71
  toIR(ctx) {
72
+ // console.log( this.pretty(2) );
72
73
  const matchExprType = getUnaliased(this.matchExpr.type);
73
74
  if (matchExprType instanceof TirSoPStructType
74
75
  || matchExprType instanceof TirSopOptT)
@@ -128,6 +129,7 @@ export class TirCaseExpr {
128
129
  throw new Error("case pattern not expressified.");
129
130
  introducedVars[i] = branchCtx.defineVar(varDecl.name);
130
131
  }
132
+ // console.log( nFields, introducedVars, branchCtx.allVariables() );
131
133
  if (nFields <= 0)
132
134
  return branch.body.toIR(branchCtx);
133
135
  return new IRFunc(introducedVars, branch.body.toIR(branchCtx));
@@ -33,12 +33,12 @@ export class TirFromDataExpr {
33
33
  this.range = range;
34
34
  }
35
35
  toString() {
36
- return `fromData(${this.dataExpr.toString()}) as ${this.type.toString()}`;
36
+ return `fromData<${this.type.toString()}>(${this.dataExpr.toString()})`;
37
37
  }
38
38
  pretty(indent) {
39
39
  const singleIndent = " ";
40
40
  const indent_base = singleIndent.repeat(indent);
41
- return `fromData(${this.dataExpr.pretty(indent)}) as ${this.type.toString()}`;
41
+ return `fromData<${this.type.toString()}>(${this.dataExpr.pretty(indent)})`;
42
42
  }
43
43
  clone() {
44
44
  return new TirFromDataExpr(this.dataExpr.clone(), this.type.clone(), this.range.clone());
@@ -18,7 +18,7 @@ export declare class TirFuncExpr implements ITirExpr {
18
18
  sig(): TirFuncT;
19
19
  constructor(name: string, params: TirSimpleVarDecl[], returnType: TirType, body: TirBlockStmt, range: SourceRange, _isLoop?: boolean);
20
20
  toString(): string;
21
- pretty(indent: number): string;
21
+ pretty(indent?: number): string;
22
22
  clone(): TirExpr;
23
23
  isAnonymous(): boolean;
24
24
  private _deps;
@@ -39,7 +39,7 @@ export class TirFuncExpr {
39
39
  `: ${this.returnType.toString()} ` +
40
40
  `${this.body.toString()}`);
41
41
  }
42
- pretty(indent) {
42
+ pretty(indent = 1) {
43
43
  const singleIndent = " ";
44
44
  const indent_base = singleIndent.repeat(indent);
45
45
  const indent_0 = "\n" + indent_base;
@@ -8,14 +8,14 @@ export declare class TirLettedExpr implements ITirExpr {
8
8
  readonly varName: string;
9
9
  expr: TirExpr;
10
10
  readonly range: SourceRange;
11
+ private _creationStack;
11
12
  get type(): TirType;
12
13
  private readonly _irVarSym;
13
- constructor(varName: string, expr: TirExpr, range: SourceRange, _unsafeVarSym?: symbol | undefined);
14
+ constructor(varName: string, expr: TirExpr, range: SourceRange, _unsafeVarSym?: symbol | undefined, _creationStack?: string | undefined);
14
15
  toString(): string;
15
16
  pretty(indent: number): string;
16
17
  deps(): string[];
17
18
  clone(): TirExpr;
18
- unsafeClone(): TirLettedExpr;
19
19
  get isConstant(): boolean;
20
20
  toIR(ctx: ToIRTermCtx): IRTerm;
21
21
  }
@@ -3,17 +3,19 @@ export class TirLettedExpr {
3
3
  varName;
4
4
  expr;
5
5
  range;
6
+ _creationStack = undefined;
6
7
  get type() {
7
8
  return this.expr.type;
8
9
  }
9
10
  _irVarSym;
10
- constructor(varName, expr, range, _unsafeVarSym) {
11
+ constructor(varName, expr, range, _unsafeVarSym, _creationStack) {
11
12
  this.varName = varName;
12
13
  this.expr = expr;
13
14
  this.range = range;
14
15
  if (!(typeof varName === "string"
15
16
  && varName.length > 0))
16
17
  throw new Error("TirLettedExpr: varName must be a non empty string");
18
+ this._creationStack = _creationStack ?? (new Error()).stack;
17
19
  this._irVarSym = (typeof _unsafeVarSym === "symbol"
18
20
  && _unsafeVarSym.description === varName) ? _unsafeVarSym : Symbol(varName);
19
21
  }
@@ -30,11 +32,7 @@ export class TirLettedExpr {
30
32
  return this.expr.deps();
31
33
  }
32
34
  clone() {
33
- return new TirLettedExpr(this.varName, this.expr.clone(), this.range.clone(), this._irVarSym);
34
- }
35
- unsafeClone() {
36
- return new TirLettedExpr(this.varName, this.expr, // this.expr.clone(),
37
- this.range, this._irVarSym);
35
+ return new TirLettedExpr(this.varName, this.expr.clone(), this.range.clone(), this._irVarSym, this._creationStack);
38
36
  }
39
37
  get isConstant() { return this.expr.isConstant; }
40
38
  toIR(ctx) {