@harmoniclabs/pebble 0.1.3-dev0 → 0.1.3-dev1
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/IRConst.js +4 -6
- package/dist/IR/toUPLC/compileIRToUPLC.js +2 -0
- package/dist/IR/toUPLC/subRoutines/performUplcOptimizationsAndReturnRoot/ensureProperlyForcedBuiltinsAndReturnRoot.d.ts +2 -0
- package/dist/IR/toUPLC/subRoutines/performUplcOptimizationsAndReturnRoot/ensureProperlyForcedBuiltinsAndReturnRoot.js +163 -0
- package/dist/IR/toUPLC/subRoutines/performUplcOptimizationsAndReturnRoot/performUplcOptimizationsAndReturnRoot.js +12 -2
- package/dist/compiler/Compiler.js +1 -1
- package/dist/compiler/tir/expressions/TirNativeFunc.js +3 -3
- package/dist/index.d.ts +0 -2
- package/dist/index.js +0 -2
- package/package.json +7 -10
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Pair } from "@harmoniclabs/pair";
|
|
2
1
|
import { isData, dataToCbor } from "@harmoniclabs/plutus-data";
|
|
3
2
|
import { fromUtf8, toHex } from "@harmoniclabs/uint8array-utils";
|
|
4
3
|
import { BasePlutsError } from "../../utils/BasePlutsError.js";
|
|
@@ -11,7 +10,7 @@ import { TirAliasType } from "../../compiler/tir/types/TirAliasType.js";
|
|
|
11
10
|
import { TirDataStructType, TirSoPStructType } from "../../compiler/tir/types/TirStructType.js";
|
|
12
11
|
import { getListTypeArg } from "../../compiler/tir/types/utils/getListTypeArg.js";
|
|
13
12
|
import { TirTypeParam } from "../../compiler/tir/types/TirTypeParam.js";
|
|
14
|
-
import { constT, UPLCConst } from "@harmoniclabs/uplc";
|
|
13
|
+
import { constT, isPair, UPLCConst } from "@harmoniclabs/uplc";
|
|
15
14
|
import { TirPairDataT, TirUnConstrDataResultT } from "../../compiler/tir/types/TirNativeType/index.js";
|
|
16
15
|
import { TirBoolT } from "../../compiler/tir/types/TirNativeType/native/bool.js";
|
|
17
16
|
import { TirBytesT } from "../../compiler/tir/types/TirNativeType/native/bytes.js";
|
|
@@ -25,10 +24,9 @@ import { TirSopOptT } from "../../compiler/tir/types/TirNativeType/native/Option
|
|
|
25
24
|
import { TirStringT } from "../../compiler/tir/types/TirNativeType/native/string.js";
|
|
26
25
|
import { TirVoidT } from "../../compiler/tir/types/TirNativeType/native/void.js";
|
|
27
26
|
import { hashIrData, isIRHash } from "../IRHash.js";
|
|
28
|
-
import { ByteString } from "@harmoniclabs/bytestring";
|
|
29
27
|
import { UPLCFlatUtils } from "../../utils/UPLCFlatUtils/index.js";
|
|
30
28
|
export function isIRConstPair(value) {
|
|
31
|
-
return (value
|
|
29
|
+
return (isPair(value) &&
|
|
32
30
|
isIRConstValue(value.fst) &&
|
|
33
31
|
isIRConstValue(value.snd));
|
|
34
32
|
}
|
|
@@ -65,7 +63,7 @@ export class IRConst {
|
|
|
65
63
|
const type = getUnaliased(this.type);
|
|
66
64
|
if (type instanceof TirBytesT && this.value instanceof Uint8Array) {
|
|
67
65
|
// make a copy to prevent external mutation
|
|
68
|
-
return new UPLCConst(tirTypeToUplcType(type),
|
|
66
|
+
return new UPLCConst(tirTypeToUplcType(type), this.value);
|
|
69
67
|
}
|
|
70
68
|
return new UPLCConst(tirTypeToUplcType(type), this.value);
|
|
71
69
|
}
|
|
@@ -215,7 +213,7 @@ function serializeIRConstValue(value, type) {
|
|
|
215
213
|
if (type instanceof TirDataT
|
|
216
214
|
|| type instanceof TirDataOptT
|
|
217
215
|
|| type instanceof TirDataStructType)
|
|
218
|
-
return dataToCbor(value)
|
|
216
|
+
return dataToCbor(value);
|
|
219
217
|
if (type instanceof TirFuncT
|
|
220
218
|
|| type instanceof TirSopOptT
|
|
221
219
|
|| type instanceof TirSoPStructType
|
|
@@ -20,6 +20,7 @@ import { _debug_assertClosedIR } from "../utils/index.js";
|
|
|
20
20
|
import { ToUplcCtx } from "./ctx/ToUplcCtx.js";
|
|
21
21
|
import { removeUnusedVarsAndReturnRoot } from "./subRoutines/removeUnusuedVarsAndReturnRoot/removeUnusuedVarsAndReturnRoot.js";
|
|
22
22
|
import { IRRecursive } from "../IRNodes/IRRecursive.js";
|
|
23
|
+
import { ensureProperlyForcedBuiltinsAndReturnRoot } from "./subRoutines/performUplcOptimizationsAndReturnRoot/ensureProperlyForcedBuiltinsAndReturnRoot.js";
|
|
23
24
|
export function compileIRToUPLC(term, paritalOptions = defaultOptions) {
|
|
24
25
|
// most of the time we are just compiling small
|
|
25
26
|
// pre-execuded terms (hence constants)
|
|
@@ -144,6 +145,7 @@ export function compileIRToUPLC(term, paritalOptions = defaultOptions) {
|
|
|
144
145
|
// }
|
|
145
146
|
term = removeUnusedVarsAndReturnRoot(term);
|
|
146
147
|
term = performUplcOptimizationsAndReturnRoot(term, options);
|
|
148
|
+
term = ensureProperlyForcedBuiltinsAndReturnRoot(term);
|
|
147
149
|
if (options.addMarker &&
|
|
148
150
|
options.targetUplcVersion.major >= 1 &&
|
|
149
151
|
options.targetUplcVersion.minor >= 1 &&
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { IRConstr, IRNative } from "../../../IRNodes/index.js";
|
|
2
|
+
import { IRApp } from "../../../IRNodes/IRApp.js";
|
|
3
|
+
import { IRCase } from "../../../IRNodes/IRCase.js";
|
|
4
|
+
import { IRForced } from "../../../IRNodes/IRForced.js";
|
|
5
|
+
import { IRFunc } from "../../../IRNodes/IRFunc.js";
|
|
6
|
+
import { IRHoisted } from "../../../IRNodes/IRHoisted.js";
|
|
7
|
+
import { IRLetted } from "../../../IRNodes/IRLetted.js";
|
|
8
|
+
import { IRRecursive } from "../../../IRNodes/IRRecursive.js";
|
|
9
|
+
import { IRSelfCall } from "../../../IRNodes/IRSelfCall.js";
|
|
10
|
+
import { IRVar } from "../../../IRNodes/IRVar.js";
|
|
11
|
+
import { _modifyChildFromTo } from "../../_internal/_modifyChildFromTo.js";
|
|
12
|
+
import { getApplicationTerms } from "../../utils/getApplicationTerms.js";
|
|
13
|
+
import { getUnboundedVars } from "../handleLetted/groupByScope.js";
|
|
14
|
+
import { getNRequiredForces } from "@harmoniclabs/uplc";
|
|
15
|
+
export function ensureProperlyForcedBuiltinsAndReturnRoot(root) {
|
|
16
|
+
// const opts = options.uplcOptimizations;
|
|
17
|
+
// if( isDebugUplcOptimizations( opts ) ) return root;
|
|
18
|
+
// const {
|
|
19
|
+
// groupApplications,
|
|
20
|
+
// inlineSingleUse: shouldInlineSingleUse,
|
|
21
|
+
// simplifyWrappedPartialFuncApps,
|
|
22
|
+
// removeForceDelay
|
|
23
|
+
// } = opts;
|
|
24
|
+
const stack = [root];
|
|
25
|
+
let t = root;
|
|
26
|
+
while (t = stack.pop()) {
|
|
27
|
+
if (t instanceof IRNative) {
|
|
28
|
+
const expectedForces = getNRequiredForces(t.tag);
|
|
29
|
+
if (expectedForces <= 0)
|
|
30
|
+
continue;
|
|
31
|
+
let newNode = t;
|
|
32
|
+
let nDirectForces = 0;
|
|
33
|
+
// save the original parent before walking up through existing forces
|
|
34
|
+
// and before creating new IRForced wrappers (whose constructors
|
|
35
|
+
// overwrite the child's parent pointer)
|
|
36
|
+
const originalParent = t.parent;
|
|
37
|
+
while (t.parent instanceof IRForced) {
|
|
38
|
+
nDirectForces++;
|
|
39
|
+
t = t.parent;
|
|
40
|
+
}
|
|
41
|
+
if (nDirectForces === expectedForces)
|
|
42
|
+
continue;
|
|
43
|
+
// when nDirectForces > 0, t has walked up to the topmost IRForced;
|
|
44
|
+
// save its parent before wrapping overwrites parent pointers
|
|
45
|
+
const replaceInParent = nDirectForces > 0 ? t.parent : originalParent;
|
|
46
|
+
for (let i = 0; i < expectedForces - nDirectForces; i++) {
|
|
47
|
+
newNode = new IRForced(newNode);
|
|
48
|
+
}
|
|
49
|
+
if (replaceInParent)
|
|
50
|
+
_modifyChildFromTo(replaceInParent, t, newNode);
|
|
51
|
+
else
|
|
52
|
+
root = newNode;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (t instanceof IRRecursive ||
|
|
56
|
+
t instanceof IRHoisted ||
|
|
57
|
+
t instanceof IRLetted ||
|
|
58
|
+
t instanceof IRSelfCall)
|
|
59
|
+
throw new Error("Unexpected term while performing uplc optimizations");
|
|
60
|
+
stack.push(...t.children());
|
|
61
|
+
}
|
|
62
|
+
return root;
|
|
63
|
+
}
|
|
64
|
+
function isIdLike(term) {
|
|
65
|
+
return (term instanceof IRFunc &&
|
|
66
|
+
term.params.length === 1 &&
|
|
67
|
+
term.body instanceof IRVar &&
|
|
68
|
+
term.body.name === term.params[0]);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
*
|
|
72
|
+
* @returns either an object containing the new root, sorted args and next body
|
|
73
|
+
* or undefined if grouping wasnt possible (root is the same)
|
|
74
|
+
*/
|
|
75
|
+
function groupIndependentApplications(root) {
|
|
76
|
+
const parent = root.parent;
|
|
77
|
+
let applicaitonTerms = getApplicationTerms(root);
|
|
78
|
+
if (!applicaitonTerms)
|
|
79
|
+
return undefined;
|
|
80
|
+
let { func, args } = applicaitonTerms;
|
|
81
|
+
if (!(func instanceof IRFunc))
|
|
82
|
+
return undefined;
|
|
83
|
+
const params = func.params.slice();
|
|
84
|
+
while (true) {
|
|
85
|
+
applicaitonTerms = getApplicationTerms(func.body);
|
|
86
|
+
if (!applicaitonTerms)
|
|
87
|
+
break;
|
|
88
|
+
if (!(applicaitonTerms.func instanceof IRFunc))
|
|
89
|
+
break;
|
|
90
|
+
func = applicaitonTerms.func;
|
|
91
|
+
params.push(...func.params);
|
|
92
|
+
args.push(...applicaitonTerms.args);
|
|
93
|
+
if (params.length !== args.length)
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
const len = Math.min(params.length, args.length);
|
|
97
|
+
const finalParams = params.slice(len);
|
|
98
|
+
const finalArgs = args.slice(len);
|
|
99
|
+
params.length = len;
|
|
100
|
+
args.length = len;
|
|
101
|
+
const paramToArg = {};
|
|
102
|
+
for (let i = 0; i < len; i++) {
|
|
103
|
+
const p = params[i];
|
|
104
|
+
paramToArg[p] = args[i];
|
|
105
|
+
}
|
|
106
|
+
const globalUnbound = getUnboundedVars(root);
|
|
107
|
+
const groups = [[]];
|
|
108
|
+
for (let i = 0; i < len; i++) {
|
|
109
|
+
const p = params[i];
|
|
110
|
+
const arg = args[i];
|
|
111
|
+
const unbound = getUnboundedVars(arg, globalUnbound);
|
|
112
|
+
let highestIdx = -1;
|
|
113
|
+
for (let j = groups.length - 1; j >= 0; j--) {
|
|
114
|
+
const group = groups[j];
|
|
115
|
+
if (group.some(sym => unbound.has(sym))) {
|
|
116
|
+
highestIdx = j;
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (highestIdx === groups.length - 1) {
|
|
121
|
+
groups.push([p]);
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
groups[highestIdx + 1].push(p);
|
|
125
|
+
}
|
|
126
|
+
groups[groups.length - 1].push(...finalParams);
|
|
127
|
+
const sortedArgs = new Array(len);
|
|
128
|
+
const soretedParams = groups.flat();
|
|
129
|
+
for (let i = 0; i < len; i++) {
|
|
130
|
+
const p = soretedParams[i];
|
|
131
|
+
sortedArgs[i] = paramToArg[p];
|
|
132
|
+
}
|
|
133
|
+
let nextBody = func.body;
|
|
134
|
+
if (finalArgs.length > 0) {
|
|
135
|
+
if (finalArgs.length === 1) {
|
|
136
|
+
nextBody = new IRApp(nextBody, finalArgs[0]);
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
nextBody = new IRCase(new IRConstr(0, finalArgs), [nextBody]);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
let newTerm = nextBody;
|
|
143
|
+
for (let i = groups.length - 1; i >= 0; i--) {
|
|
144
|
+
const group = groups[i];
|
|
145
|
+
if (group.length === 1) {
|
|
146
|
+
newTerm = new IRApp(new IRFunc(group, newTerm), paramToArg[group[0]]);
|
|
147
|
+
}
|
|
148
|
+
else if (group.length <= 0)
|
|
149
|
+
continue;
|
|
150
|
+
else {
|
|
151
|
+
newTerm = new IRCase(new IRConstr(0, group.map(p => paramToArg[p])), [new IRFunc(group, newTerm)]);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (parent)
|
|
155
|
+
_modifyChildFromTo(parent, root, newTerm);
|
|
156
|
+
else
|
|
157
|
+
root = newTerm;
|
|
158
|
+
return {
|
|
159
|
+
newRoot: !parent ? root : undefined,
|
|
160
|
+
args: sortedArgs,
|
|
161
|
+
nextBody
|
|
162
|
+
};
|
|
163
|
+
}
|
|
@@ -89,6 +89,10 @@ function groupIndependentApplications(root) {
|
|
|
89
89
|
if (!(func instanceof IRFunc))
|
|
90
90
|
return undefined;
|
|
91
91
|
const params = func.params.slice();
|
|
92
|
+
// Separate excess outer args: getApplicationTerms may return more args
|
|
93
|
+
// than func.params (e.g. `(λp. body)(arg1)(arg2)` → 2 args, 1 param).
|
|
94
|
+
// Excess args are trailing applications applied after all param bindings.
|
|
95
|
+
const trailingArgs = args.splice(params.length);
|
|
92
96
|
while (true) {
|
|
93
97
|
applicaitonTerms = getApplicationTerms(func.body);
|
|
94
98
|
if (!applicaitonTerms)
|
|
@@ -96,14 +100,20 @@ function groupIndependentApplications(root) {
|
|
|
96
100
|
if (!(applicaitonTerms.func instanceof IRFunc))
|
|
97
101
|
break;
|
|
98
102
|
func = applicaitonTerms.func;
|
|
103
|
+
const nNewParams = func.params.length;
|
|
104
|
+
const innerArgs = applicaitonTerms.args;
|
|
99
105
|
params.push(...func.params);
|
|
100
|
-
args.push(...
|
|
106
|
+
args.push(...innerArgs.slice(0, nNewParams));
|
|
107
|
+
// Inner excess args are applied before outer excess args
|
|
108
|
+
if (innerArgs.length > nNewParams) {
|
|
109
|
+
trailingArgs.unshift(...innerArgs.slice(nNewParams));
|
|
110
|
+
}
|
|
101
111
|
if (params.length !== args.length)
|
|
102
112
|
break;
|
|
103
113
|
}
|
|
104
114
|
const len = Math.min(params.length, args.length);
|
|
105
115
|
const finalParams = params.slice(len);
|
|
106
|
-
const finalArgs = args.slice(len);
|
|
116
|
+
const finalArgs = [...args.slice(len), ...trailingArgs];
|
|
107
117
|
params.length = len;
|
|
108
118
|
args.length = len;
|
|
109
119
|
const paramToArg = {};
|
|
@@ -64,7 +64,7 @@ export class Compiler extends DiagnosticEmitter {
|
|
|
64
64
|
// backend starts here
|
|
65
65
|
const ir = compileTypedProgram(cfg, program);
|
|
66
66
|
const uplc = compileIRToUPLC(ir, cfg);
|
|
67
|
-
const serialized = compileUPLC(new UPLCProgram(cfg.targetUplcVersion, uplc))
|
|
67
|
+
const serialized = compileUPLC(new UPLCProgram(cfg.targetUplcVersion, uplc));
|
|
68
68
|
const outDir = cfg.outDir;
|
|
69
69
|
const outPath = outDir + (outDir.endsWith("/") ? "" : "/") + "out.flat";
|
|
70
70
|
this.io.writeFile(outPath, serialized, cfg.root);
|
|
@@ -117,7 +117,7 @@ export class TirNativeFunc {
|
|
|
117
117
|
int_t
|
|
118
118
|
], bool_t));
|
|
119
119
|
}
|
|
120
|
-
//
|
|
120
|
+
// bytes operations
|
|
121
121
|
static get appendByteString() {
|
|
122
122
|
return new TirNativeFunc(IRNativeTag.appendByteString, new TirFuncT([
|
|
123
123
|
// left
|
|
@@ -512,7 +512,7 @@ export class TirNativeFunc {
|
|
|
512
512
|
bytes_t
|
|
513
513
|
], bytes_t));
|
|
514
514
|
}
|
|
515
|
-
//
|
|
515
|
+
// bytes manipulation
|
|
516
516
|
static get integerToByteString() {
|
|
517
517
|
return new TirNativeFunc(IRNativeTag.integerToByteString, new TirFuncT([
|
|
518
518
|
// flag
|
|
@@ -585,7 +585,7 @@ export class TirNativeFunc {
|
|
|
585
585
|
bool_t
|
|
586
586
|
], bytes_t));
|
|
587
587
|
}
|
|
588
|
-
// Additional
|
|
588
|
+
// Additional bytes operations
|
|
589
589
|
static get replicateByte() {
|
|
590
590
|
return new TirNativeFunc(IRNativeTag.replicateByte, new TirFuncT([
|
|
591
591
|
// count
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
export * from "@harmoniclabs/bytestring";
|
|
2
1
|
export * from "@harmoniclabs/cbor";
|
|
3
2
|
export * from "@harmoniclabs/obj-utils";
|
|
4
|
-
export * from "@harmoniclabs/pair";
|
|
5
3
|
export * from "@harmoniclabs/plutus-data";
|
|
6
4
|
export * from "@harmoniclabs/plutus-machine";
|
|
7
5
|
export * from "@harmoniclabs/uint8array-utils";
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
export * from "@harmoniclabs/bytestring";
|
|
2
1
|
export * from "@harmoniclabs/cbor";
|
|
3
2
|
export * from "@harmoniclabs/obj-utils";
|
|
4
|
-
export * from "@harmoniclabs/pair";
|
|
5
3
|
export * from "@harmoniclabs/plutus-data";
|
|
6
4
|
export * from "@harmoniclabs/plutus-machine";
|
|
7
5
|
export * from "@harmoniclabs/uint8array-utils";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@harmoniclabs/pebble",
|
|
3
|
-
"version": "0.1.3-
|
|
3
|
+
"version": "0.1.3-dev1",
|
|
4
4
|
"description": "A simple, yet rock solid, functional language with an imperative bias, targeting UPLC",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -51,25 +51,22 @@
|
|
|
51
51
|
"homepage": "https://github.com/HarmonicLabs/pebble#readme",
|
|
52
52
|
"dependencies": {
|
|
53
53
|
"@harmoniclabs/bigint-utils": "^1.0.0",
|
|
54
|
-
"@harmoniclabs/
|
|
55
|
-
"@harmoniclabs/cbor": "^
|
|
54
|
+
"@harmoniclabs/cardano-costmodels-ts": "^1.4.0",
|
|
55
|
+
"@harmoniclabs/cbor": "^2.0.1",
|
|
56
56
|
"@harmoniclabs/crypto": "^0.3.0",
|
|
57
57
|
"@harmoniclabs/obj-utils": "^1.0.0",
|
|
58
|
-
"@harmoniclabs/
|
|
59
|
-
"@harmoniclabs/plutus-
|
|
60
|
-
"@harmoniclabs/plutus-machine": "^2.1.1",
|
|
58
|
+
"@harmoniclabs/plutus-data": "^2.0.1",
|
|
59
|
+
"@harmoniclabs/plutus-machine": "^3.0.0",
|
|
61
60
|
"@harmoniclabs/uint8array-utils": "^1.0.4",
|
|
62
|
-
"@harmoniclabs/uplc": "^
|
|
61
|
+
"@harmoniclabs/uplc": "^2.0.5"
|
|
63
62
|
},
|
|
64
63
|
"devDependencies": {
|
|
65
64
|
"@babel/preset-env": "^7.18.6",
|
|
66
65
|
"@babel/preset-typescript": "^7.18.6",
|
|
67
|
-
"@harmoniclabs/cardano-costmodels-ts": "^1.3.0",
|
|
68
|
-
"@harmoniclabs/cardano-ledger-ts": "^0.3.2",
|
|
69
66
|
"@types/jest": "^28.1.4",
|
|
70
67
|
"@types/node": "^18.14.6",
|
|
71
68
|
"jest": "^29.4.3",
|
|
72
|
-
"jest-environment-jsdom": "^
|
|
69
|
+
"jest-environment-jsdom": "^30.3.0",
|
|
73
70
|
"tsc-alias": "^1.7.1",
|
|
74
71
|
"typescript": "^4.6.3"
|
|
75
72
|
},
|