@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.
@@ -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 instanceof Pair &&
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), new ByteString(this.value));
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).toBuffer();
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,2 @@
1
+ import { IRTerm } from "../../../IRTerm.js";
2
+ export declare function ensureProperlyForcedBuiltinsAndReturnRoot(root: IRTerm): IRTerm;
@@ -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(...applicaitonTerms.args);
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)).toBuffer().buffer;
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
- // ByteString operations
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
- // ByteString manipulation
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 ByteString operations
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-dev0",
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/bytestring": "^1.0.0",
55
- "@harmoniclabs/cbor": "^1.6.6",
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/pair": "^1.0.0",
59
- "@harmoniclabs/plutus-data": "^1.2.6",
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": "^1.4.1"
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": "^29.4.3",
69
+ "jest-environment-jsdom": "^30.3.0",
73
70
  "tsc-alias": "^1.7.1",
74
71
  "typescript": "^4.6.3"
75
72
  },