@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.
- package/dist/IR/IRNodes/IRNative/IRNativeTag.d.ts +3 -1
- package/dist/IR/IRNodes/IRNative/IRNativeTag.js +4 -0
- package/dist/IR/IRNodes/IRNative/index.d.ts +1 -0
- package/dist/IR/IRNodes/IRNative/index.js +1 -0
- package/dist/IR/toUPLC/CompilerOptions.d.ts +5 -0
- package/dist/IR/toUPLC/CompilerOptions.js +10 -1
- package/dist/IR/toUPLC/compileIRToUPLC.js +1 -1
- package/dist/IR/toUPLC/ctx/ToUplcCtx.js +2 -10
- package/dist/IR/toUPLC/subRoutines/handleLetted/groupByScope.js +0 -2
- package/dist/IR/toUPLC/subRoutines/replaceNatives/nativeToIR.d.ts +2 -0
- package/dist/IR/toUPLC/subRoutines/replaceNatives/nativeToIR.js +23 -1
- package/dist/IR/utils/isClosedIRTerm.js +1 -1
- package/dist/IR/utils/positiveIntAsBytes.js +0 -4
- package/dist/compiler/AstCompiler/AstCompiler.d.ts +1 -0
- package/dist/compiler/AstCompiler/AstCompiler.js +39 -2
- package/dist/compiler/AstCompiler/internal/_deriveContractBody/_deriveContractBody.js +1 -1
- package/dist/compiler/AstCompiler/internal/exprs/_compileExpr.js +4 -0
- package/dist/compiler/AstCompiler/internal/exprs/_compileFuncExpr.js +7 -4
- package/dist/compiler/AstCompiler/internal/exprs/_compileTypeConversionExpr.js +0 -1
- package/dist/compiler/AstCompiler/internal/exprs/_compileVarAccessExpr.js +3 -1
- package/dist/compiler/AstCompiler/internal/statements/_compileAssignmentStmt.js +7 -7
- package/dist/compiler/AstCompiler/internal/statements/_compileVarStmt.d.ts +2 -1
- package/dist/compiler/AstCompiler/internal/statements/_compileVarStmt.js +2 -1
- package/dist/compiler/AstCompiler/scope/AstScope.d.ts +1 -0
- package/dist/compiler/AstCompiler/scope/AstScope.js +5 -0
- package/dist/compiler/Compiler.js +4 -0
- package/dist/compiler/TirCompiler/compileTirProgram.js +2 -1
- package/dist/compiler/TirCompiler/expressify/ExpressifyCtx.d.ts +4 -2
- package/dist/compiler/TirCompiler/expressify/ExpressifyCtx.js +42 -16
- package/dist/compiler/TirCompiler/expressify/determineReassignedVariablesAndReturn.js +2 -0
- package/dist/compiler/TirCompiler/expressify/expressify.js +24 -9
- package/dist/compiler/TirCompiler/expressify/expressifyForStmt.js +23 -7
- package/dist/compiler/TirCompiler/expressify/expressifyVarAssignmentStmt.d.ts +1 -2
- package/dist/compiler/TirCompiler/expressify/expressifyVarAssignmentStmt.js +15 -8
- package/dist/compiler/TirCompiler/expressify/expressifyVarDecl.js +6 -9
- package/dist/compiler/TirCompiler/expressify/expressifyVars.js +15 -4
- package/dist/compiler/TirCompiler/expressify/flattenSopNamedDeconstructInplace_addTopDestructToCtx_getNestedDeconstruct.js +1 -0
- package/dist/compiler/internalVar.d.ts +1 -1
- package/dist/compiler/internalVar.js +31 -24
- package/dist/compiler/io/CompilerIoApi.d.ts +1 -1
- package/dist/compiler/tir/expressions/TirCallExpr.d.ts +1 -1
- package/dist/compiler/tir/expressions/TirCallExpr.js +1 -1
- package/dist/compiler/tir/expressions/TirCaseExpr.js +2 -0
- package/dist/compiler/tir/expressions/TirFromDataExpr.js +2 -2
- package/dist/compiler/tir/expressions/TirFuncExpr.d.ts +1 -1
- package/dist/compiler/tir/expressions/TirFuncExpr.js +1 -1
- package/dist/compiler/tir/expressions/TirLettedExpr.d.ts +2 -2
- package/dist/compiler/tir/expressions/TirLettedExpr.js +4 -6
- package/dist/compiler/tir/expressions/TirNativeFunc.d.ts +1 -0
- package/dist/compiler/tir/expressions/TirNativeFunc.js +9 -1
- package/dist/compiler/tir/expressions/TirPropAccessExpr.js +1 -2
- package/dist/compiler/tir/expressions/TirVariableAccessExpr.d.ts +0 -1
- package/dist/compiler/tir/expressions/TirVariableAccessExpr.js +9 -5
- package/dist/compiler/tir/expressions/ToIRTermCtx.d.ts +3 -0
- package/dist/compiler/tir/expressions/ToIRTermCtx.js +8 -1
- package/dist/compiler/tir/expressions/binary/TirBinaryExpr.d.ts +1 -0
- package/dist/compiler/tir/expressions/binary/TirBinaryExpr.js +6 -1
- package/dist/compiler/tir/program/TypedProgram.d.ts +2 -2
- package/dist/compiler/tir/program/stdScope/stdScope.js +9 -23
- package/dist/compiler/tir/statements/TirIfStmt.d.ts +0 -1
- package/dist/compiler/tir/statements/TirIfStmt.js +0 -3
- package/dist/parser/Parser.js +18 -2
- package/dist/parser/Precedence.js +1 -0
- package/dist/utils/array/keepSortedArrInplace.js +1 -0
- package/package.json +2 -1
- package/dist/compiler/TirCompiler/internal/_compileHoistedDeps.d.ts +0 -5
- 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
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
|
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.
|
|
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.
|
|
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
|
-
//
|
|
56
|
-
// console.log(
|
|
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
|
-
|
|
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
|
|
358
|
-
|
|
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
|
-
|
|
433
|
+
const mainContinuaiton = expressifyFuncBody(contBranchCtx, nestedDeconstructs
|
|
420
434
|
.concat(nextBodyStmts), loopReplacements, [] // assertions are added before if statement exectution
|
|
421
|
-
)
|
|
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
|
-
|
|
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)),
|
|
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),
|
|
163
|
-
|
|
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):
|
|
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.
|
|
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
|
-
|
|
16
|
+
ctx.setNewVariableName(originalName, newUniqueName);
|
|
14
17
|
// point to the same object
|
|
15
|
-
ctx.
|
|
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(
|
|
19
|
-
|
|
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.
|
|
15
|
-
|
|
16
|
-
stmt.isConst = true;
|
|
11
|
+
if (!stmt.isConst) {
|
|
12
|
+
void ctx.setNewVariableName(stmt.name, stmt.name);
|
|
13
|
+
// stmt.isConst = true;
|
|
17
14
|
}
|
|
18
|
-
ctx.
|
|
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.
|
|
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.
|
|
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
|
-
//
|
|
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.
|
|
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.
|
|
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
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
|
32
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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) {
|