@harmoniclabs/pebble 0.3.2 → 0.3.4

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.
@@ -292,6 +292,12 @@ export function tirTypeToUplcType(t) {
292
292
  }
293
293
  if (t instanceof TirValueT)
294
294
  return constT.value;
295
+ if (t instanceof TirBlsG1T)
296
+ return constT.bls12_381_G1_element;
297
+ if (t instanceof TirBlsG2T)
298
+ return constT.bls12_381_G2_element;
299
+ if (t instanceof TirMlResultT)
300
+ return constT.bls12_381_MlResult;
295
301
  if (t instanceof TirDataT
296
302
  || t instanceof TirDataOptT
297
303
  || t instanceof TirDataStructType)
@@ -308,10 +314,7 @@ export function tirTypeToUplcType(t) {
308
314
  || t instanceof TirFuncT
309
315
  || t instanceof TirSopOptT
310
316
  || t instanceof TirSoPStructType
311
- || t instanceof TirTypeParam
312
- || t instanceof TirBlsG1T
313
- || t instanceof TirBlsG2T
314
- || t instanceof TirMlResultT)
317
+ || t instanceof TirTypeParam)
315
318
  throw new Error("invalid uplc const type");
316
319
  const tsEnsureExsaustiveCheck = t;
317
320
  throw new Error("tirTypeToUplcType: unreachable");
@@ -32,8 +32,30 @@ export class ToUplcCtx {
32
32
  return ctx._parentDbn + idx + 1;
33
33
  }
34
34
  getVarAccessDbn(sym) {
35
- const declDbn = this.getVarDeclDbn(sym);
36
- return this.dbn - declDbn;
35
+ // Resolve the de Bruijn index LEXICALLY, against this access's own
36
+ // scope chain — i.e. the number of binders between the access and the
37
+ // NEAREST (innermost) enclosing binder of `sym`.
38
+ //
39
+ // The previous implementation looked `sym` up in a single tree-wide
40
+ // `ctxMap` (last writer wins). That is incorrect whenever the same
41
+ // binder symbol appears in sibling scopes — which happens routinely
42
+ // because cloned IR reuses its binder symbols (e.g. the shared
43
+ // `const { tx } = context` destructuring duplicated across a
44
+ // contract's purpose-match cases). An access in one branch would then
45
+ // resolve against another branch's binder, yielding a wrong and
46
+ // sometimes NEGATIVE index ("invalid deBruijn index").
47
+ let offset = 0;
48
+ let ctx = this;
49
+ while (ctx) {
50
+ const vars = ctx._variables;
51
+ for (let i = vars.length - 1; i >= 0; i--) {
52
+ if (vars[i] === sym)
53
+ return offset + (vars.length - 1 - i);
54
+ }
55
+ offset += vars.length;
56
+ ctx = ctx.parent;
57
+ }
58
+ throw new Error("Variable not found in scope chain: " + String(sym.description));
37
59
  }
38
60
  toJson() {
39
61
  let obj = {};
@@ -3,6 +3,7 @@ import { IRNative } from "../../../IRNodes/IRNative/index.js";
3
3
  import { IRTerm } from "../../../IRTerm.js";
4
4
  export declare const hoisted_id: IRHoisted;
5
5
  export declare const hoisted_not: IRHoisted;
6
+ export declare const hoisted_equalBoolean: IRHoisted;
6
7
  export declare const hoisted_incr: IRHoisted;
7
8
  export declare const hoisted_decr: IRHoisted;
8
9
  export declare const hoisted_isZero: IRHoisted;
@@ -28,6 +28,15 @@ export const hoisted_not = new IRHoisted((() => {
28
28
  return new IRFunc([someBool], _ir_apps(IRNative.strictIfThenElse, new IRVar(someBool), IRConst.bool(false), IRConst.bool(true)));
29
29
  })());
30
30
  hoisted_not.hash;
31
+ // boolean equality: `a == b` ≡ `if a then b else (not b)`
32
+ export const hoisted_equalBoolean = new IRHoisted((() => {
33
+ const a = Symbol("a");
34
+ const b = Symbol("b");
35
+ return new IRFunc([a, b], _ir_apps(IRNative.strictIfThenElse, new IRVar(a), new IRVar(b),
36
+ // not b
37
+ _ir_apps(IRNative.strictIfThenElse, new IRVar(b), IRConst.bool(false), IRConst.bool(true))));
38
+ })());
39
+ hoisted_equalBoolean.hash;
31
40
  export const hoisted_incr = new IRHoisted(new IRApp(IRNative.addInteger, IRConst.int(1)));
32
41
  hoisted_incr.hash;
33
42
  export const hoisted_decr = new IRHoisted(new IRApp(IRNative.addInteger, IRConst.int(-1)));
@@ -324,7 +333,7 @@ export function nativeToIR(native) {
324
333
  case IRNativeTag._increment: return hoisted_addOne.clone();
325
334
  case IRNativeTag._decrement: return hoisted_subOne.clone();
326
335
  // case IRNativeTag._bytesToIntBE: ;
327
- // case IRNativeTag._equalBoolean: ;
336
+ case IRNativeTag._equalBoolean: return hoisted_equalBoolean.clone();
328
337
  // case IRNativeTag._equalPairData: ;
329
338
  case IRNativeTag._mkEqualsList: return hoisted_mkEqualsList.clone();
330
339
  case IRNativeTag._negateInt: return hoisted_negateInteger.clone();
@@ -52,8 +52,14 @@ export class Source {
52
52
  lineColumn = 1;
53
53
  /** Determines the line number at the specified position. Starts at `1`. */
54
54
  lineAt(pos) {
55
- if (pos < 0 || pos >= 0x7fffffff)
56
- throw new Error("pos out of range");
55
+ // Synthetic / internal nodes carry mock ranges (`SourceRange.mock` uses
56
+ // -1) and some positions can point past the end of the text. Clamp
57
+ // instead of throwing, otherwise printing a single diagnostic on such a
58
+ // node crashes the whole diagnostic pass and hides every later error.
59
+ if (pos < 0)
60
+ pos = 0;
61
+ if (pos >= 0x7fffffff)
62
+ pos = Math.max(0, this.text.length);
57
63
  let lineCache = this.lineCache;
58
64
  if (!lineCache) {
59
65
  this.lineCache = lineCache = [0];
@@ -2,6 +2,8 @@ import { DiagnosticCode } from "../../../../../diagnostics/diagnosticMessages.ge
2
2
  import { TirGreaterThanEqualExpr } from "../../../../tir/expressions/binary/TirBinaryExpr.js";
3
3
  import { TirAliasType } from "../../../../tir/types/TirAliasType.js";
4
4
  import { canAssignTo } from "../../../../tir/types/utils/canAssignTo.js";
5
+ import { getUnaliased } from "../../../../tir/types/utils/getUnaliased.js";
6
+ import { TirValueT } from "../../../../tir/types/TirNativeType/native/value.js";
5
7
  import { normalizeEnumToInt } from "../../../../tir/types/utils/normalizeEnumToInt.js";
6
8
  import { _compileExpr } from "../_compileExpr.js";
7
9
  // only aviable for ints and bytes
@@ -11,7 +13,8 @@ export function _compileGreaterThanEqualExpr(ctx, expr, typeHint) {
11
13
  const left = _compileExpr(ctx, expr.left, typeHint);
12
14
  if (!left)
13
15
  return undefined;
14
- if (!canAssignTo(left.type, int_t)
16
+ if (!(getUnaliased(left.type) instanceof TirValueT)
17
+ && !canAssignTo(left.type, int_t)
15
18
  && !canAssignTo(left.type, bytes_t))
16
19
  return ctx.error(DiagnosticCode.Type_0_is_not_assignable_to_type_1, expr.left.range, left.type.toString(), int_t.toString());
17
20
  let leftType = normalizeEnumToInt(left.type, int_t);
@@ -2,6 +2,8 @@ import { DiagnosticCode } from "../../../../../diagnostics/diagnosticMessages.ge
2
2
  import { TirGreaterThanExpr } from "../../../../tir/expressions/binary/TirBinaryExpr.js";
3
3
  import { TirAliasType } from "../../../../tir/types/TirAliasType.js";
4
4
  import { canAssignTo } from "../../../../tir/types/utils/canAssignTo.js";
5
+ import { getUnaliased } from "../../../../tir/types/utils/getUnaliased.js";
6
+ import { TirValueT } from "../../../../tir/types/TirNativeType/native/value.js";
5
7
  import { normalizeEnumToInt } from "../../../../tir/types/utils/normalizeEnumToInt.js";
6
8
  import { _compileExpr } from "../_compileExpr.js";
7
9
  export function _compileGreaterThanExpr(ctx, expr, typeHint) {
@@ -10,7 +12,8 @@ export function _compileGreaterThanExpr(ctx, expr, typeHint) {
10
12
  const left = _compileExpr(ctx, expr.left, typeHint);
11
13
  if (!left)
12
14
  return undefined;
13
- if (!canAssignTo(left.type, int_t)
15
+ if (!(getUnaliased(left.type) instanceof TirValueT)
16
+ && !canAssignTo(left.type, int_t)
14
17
  && !canAssignTo(left.type, bytes_t))
15
18
  return ctx.error(DiagnosticCode.Type_0_is_not_assignable_to_type_1, expr.left.range, left.type.toString(), int_t.toString());
16
19
  let leftType = normalizeEnumToInt(left.type, int_t);
@@ -2,6 +2,8 @@ import { DiagnosticCode } from "../../../../../diagnostics/diagnosticMessages.ge
2
2
  import { TirLessThanEqualExpr } from "../../../../tir/expressions/binary/TirBinaryExpr.js";
3
3
  import { TirAliasType } from "../../../../tir/types/TirAliasType.js";
4
4
  import { canAssignTo } from "../../../../tir/types/utils/canAssignTo.js";
5
+ import { getUnaliased } from "../../../../tir/types/utils/getUnaliased.js";
6
+ import { TirValueT } from "../../../../tir/types/TirNativeType/native/value.js";
5
7
  import { normalizeEnumToInt } from "../../../../tir/types/utils/normalizeEnumToInt.js";
6
8
  import { int_t, bytes_t } from "../../../../tir/program/stdScope/stdScope.js";
7
9
  import { _compileExpr } from "../_compileExpr.js";
@@ -9,7 +11,8 @@ export function _compileLessThanEqualExpr(ctx, expr, typeHint) {
9
11
  const left = _compileExpr(ctx, expr.left, typeHint);
10
12
  if (!left)
11
13
  return undefined;
12
- if (!canAssignTo(left.type, int_t)
14
+ if (!(getUnaliased(left.type) instanceof TirValueT)
15
+ && !canAssignTo(left.type, int_t)
13
16
  && !canAssignTo(left.type, bytes_t))
14
17
  return ctx.error(DiagnosticCode.Type_0_is_not_assignable_to_type_1, expr.left.range, left.type.toString(), int_t.toString());
15
18
  let leftType = normalizeEnumToInt(left.type, int_t);
@@ -2,6 +2,8 @@ import { DiagnosticCode } from "../../../../../diagnostics/diagnosticMessages.ge
2
2
  import { TirLessThanExpr } from "../../../../tir/expressions/binary/TirBinaryExpr.js";
3
3
  import { TirAliasType } from "../../../../tir/types/TirAliasType.js";
4
4
  import { canAssignTo } from "../../../../tir/types/utils/canAssignTo.js";
5
+ import { getUnaliased } from "../../../../tir/types/utils/getUnaliased.js";
6
+ import { TirValueT } from "../../../../tir/types/TirNativeType/native/value.js";
5
7
  import { normalizeEnumToInt } from "../../../../tir/types/utils/normalizeEnumToInt.js";
6
8
  import { _compileExpr } from "../_compileExpr.js";
7
9
  export function _compileLessThanExpr(ctx, expr, typeHint) {
@@ -10,7 +12,8 @@ export function _compileLessThanExpr(ctx, expr, typeHint) {
10
12
  const left = _compileExpr(ctx, expr.left, typeHint);
11
13
  if (!left)
12
14
  return undefined;
13
- if (!canAssignTo(left.type, int_t)
15
+ if (!(getUnaliased(left.type) instanceof TirValueT)
16
+ && !canAssignTo(left.type, int_t)
14
17
  && !canAssignTo(left.type, bytes_t))
15
18
  return ctx.error(DiagnosticCode.Type_0_is_not_assignable_to_type_1, expr.left.range, left.type.toString(), int_t.toString());
16
19
  let leftType = normalizeEnumToInt(left.type, int_t);
@@ -20,7 +20,11 @@ import { TirWhileStmt } from "../../tir/statements/TirWhileStmt.js";
20
20
  import { TirSoPStructType, TirStructConstr, TirStructField } from "../../tir/types/TirStructType.js";
21
21
  import { isExpressifyFuncParam } from "./ExpressifyCtx.js";
22
22
  export function determineReassignedVariablesAndReturn(stmt) {
23
- const originalStmtDeps = stmt.deps();
23
+ // `keepSortedStrArrInplace` (used below) requires BOTH inputs sorted;
24
+ // `stmt.deps()` is NOT sorted, so sort a copy here. Without this, reassigned
25
+ // variables get spuriously dropped from the threaded loop/branch state —
26
+ // e.g. a `for` loop reassigning two accumulators would freeze all but one.
27
+ const originalStmtDeps = stmt.deps().slice().sort();
24
28
  const stack = [stmt];
25
29
  const reassignedSet = new Set();
26
30
  let returns = false;
@@ -78,7 +82,11 @@ export function determineReassignedVariablesAndReturn(stmt) {
78
82
  };
79
83
  }
80
84
  export function determineReassignedVariablesAndFlowInfos(stmt) {
81
- const originalStmtDeps = stmt.deps();
85
+ // `keepSortedStrArrInplace` (used below) requires BOTH inputs sorted;
86
+ // `stmt.deps()` is NOT sorted, so sort a copy here. Without this, reassigned
87
+ // variables get spuriously dropped from the threaded loop/branch state —
88
+ // e.g. a `for` loop reassigning two accumulators would freeze all but one.
89
+ const originalStmtDeps = stmt.deps().slice().sort();
82
90
  const stack = [stmt];
83
91
  const reassignedSet = new Set();
84
92
  let returns = false;
@@ -12,6 +12,31 @@ import { IRConst } from "../../../../IR/IRNodes/IRConst.js";
12
12
  import { compileIRToUPLC } from "../../../../IR/toUPLC/compileIRToUPLC.js";
13
13
  import { _ir_apps } from "../../../../IR/IRNodes/IRApp.js";
14
14
  import { _ir_lazyIfThenElse } from "../../../../IR/tree_utils/_ir_lazyIfThenElse.js";
15
+ import { IRFunc } from "../../../../IR/IRNodes/IRFunc.js";
16
+ import { IRVar } from "../../../../IR/IRNodes/IRVar.js";
17
+ /**
18
+ * Lowering for Value relational operators, in terms of the `valueContains`
19
+ * builtin (`valueContains(x, y)` ⟺ `x ≥ y`, componentwise):
20
+ *
21
+ * a <= b → valueContains(b, a)
22
+ * a >= b → valueContains(a, b)
23
+ * a < b → valueContains(a, b) ? false : valueContains(b, a)
24
+ * a > b → valueContains(b, a) ? false : valueContains(a, b)
25
+ *
26
+ * `<` / `>` reference each operand twice, so they are bound once via a lambda
27
+ * to avoid re-evaluating the operand subterms.
28
+ */
29
+ function _ir_valueContains(geIR, leIR) {
30
+ // valueContains(ge, le) ⟺ ge ≥ le
31
+ return _ir_apps(IRNative.valueContains, geIR, leIR);
32
+ }
33
+ /** strict Value `lo < hi` */
34
+ function _ir_valueStrictLess(loIR, hiIR) {
35
+ const lo = Symbol("vlt_lo");
36
+ const hi = Symbol("vlt_hi");
37
+ // (λ lo hi. valueContains(lo, hi) ? false : valueContains(hi, lo)) loIR hiIR
38
+ return _ir_apps(new IRFunc([lo, hi], _ir_lazyIfThenElse(_ir_valueContains(new IRVar(lo), new IRVar(hi)), IRConst.bool(false), _ir_valueContains(new IRVar(hi), new IRVar(lo)))), loIR, hiIR);
39
+ }
15
40
  export function isTirBinaryExpr(thing) {
16
41
  return isObject(thing) && (thing instanceof TirExponentiationExpr // int
17
42
  || thing instanceof TirLessThanExpr // bool
@@ -89,6 +114,9 @@ export class TirLessThanExpr {
89
114
  get isConstant() { return this.left.isConstant && this.right.isConstant; }
90
115
  toIR(ctx) {
91
116
  const type = getUnaliased(this.left.type);
117
+ // Value: a < b → valueContains(a,b) ? false : valueContains(b,a)
118
+ if (type instanceof TirValueT)
119
+ return _ir_valueStrictLess(this.left.toIR(ctx), this.right.toIR(ctx));
92
120
  const irFunc = ((type instanceof TirIntT || type instanceof TirEnumType) ? IRNative.lessThanInteger :
93
121
  type instanceof TirBytesT ? IRNative.lessThanByteString :
94
122
  undefined);
@@ -126,6 +154,9 @@ export class TirGreaterThanExpr {
126
154
  get isConstant() { return this.left.isConstant && this.right.isConstant; }
127
155
  toIR(ctx) {
128
156
  const type = getUnaliased(this.left.type);
157
+ // Value: a > b ≡ b < a
158
+ if (type instanceof TirValueT)
159
+ return _ir_valueStrictLess(this.right.toIR(ctx), this.left.toIR(ctx));
129
160
  const irFunc = ((type instanceof TirIntT || type instanceof TirEnumType) ? IRNative.lessThanInteger :
130
161
  type instanceof TirBytesT ? IRNative.lessThanByteString :
131
162
  undefined);
@@ -165,6 +196,9 @@ export class TirLessThanEqualExpr {
165
196
  get isConstant() { return this.left.isConstant && this.right.isConstant; }
166
197
  toIR(ctx) {
167
198
  const type = getUnaliased(this.left.type);
199
+ // Value: a <= b → valueContains(b, a) (b ≥ a)
200
+ if (type instanceof TirValueT)
201
+ return _ir_valueContains(this.right.toIR(ctx), this.left.toIR(ctx));
168
202
  const irFunc = ((type instanceof TirIntT || type instanceof TirEnumType) ? IRNative.lessThanEqualInteger :
169
203
  type instanceof TirBytesT ? IRNative.lessThanEqualsByteString :
170
204
  undefined);
@@ -202,6 +236,9 @@ export class TirGreaterThanEqualExpr {
202
236
  get isConstant() { return this.left.isConstant && this.right.isConstant; }
203
237
  toIR(ctx) {
204
238
  const type = getUnaliased(this.left.type);
239
+ // Value: a >= b → valueContains(a, b) (a ≥ b)
240
+ if (type instanceof TirValueT)
241
+ return _ir_valueContains(this.left.toIR(ctx), this.right.toIR(ctx));
205
242
  const irFunc = ((type instanceof TirIntT || type instanceof TirEnumType) ? IRNative.lessThanEqualInteger :
206
243
  type instanceof TirBytesT ? IRNative.lessThanEqualsByteString :
207
244
  undefined);
@@ -189,6 +189,8 @@ export function populateStdNamespace(program) {
189
189
  defineBuiltin(blsNsScope, "g1HashToGroup", IRNativeTag.bls12_381_G1_hashToGroup, new TirFuncT([bytes_t, bytes_t], g1_t), blsNs);
190
190
  defineBuiltin(blsNsScope, "g1Compress", IRNativeTag.bls12_381_G1_compress, new TirFuncT([g1_t], bytes_t), blsNs);
191
191
  defineBuiltin(blsNsScope, "g1Uncompress", IRNativeTag.bls12_381_G1_uncompress, new TirFuncT([bytes_t], g1_t), blsNs);
192
+ // CIP-0381 multi-scalar multiplication: Σ scalars[i] · points[i]
193
+ defineBuiltin(blsNsScope, "g1MultiScalarMul", IRNativeTag.bls12_381_G1_multiScalarMul, new TirFuncT([new TirListT(int_t), new TirListT(g1_t)], g1_t), blsNs);
192
194
  defineBuiltin(blsNsScope, "g2Add", IRNativeTag.bls12_381_G2_add, new TirFuncT([g2_t, g2_t], g2_t), blsNs);
193
195
  defineBuiltin(blsNsScope, "g2Neg", IRNativeTag.bls12_381_G2_neg, new TirFuncT([g2_t], g2_t), blsNs);
194
196
  defineBuiltin(blsNsScope, "g2ScalarMul", IRNativeTag.bls12_381_G2_scalarMul, new TirFuncT([int_t, g2_t], g2_t), blsNs);
@@ -196,6 +198,7 @@ export function populateStdNamespace(program) {
196
198
  defineBuiltin(blsNsScope, "g2HashToGroup", IRNativeTag.bls12_381_G2_hashToGroup, new TirFuncT([bytes_t, bytes_t], g2_t), blsNs);
197
199
  defineBuiltin(blsNsScope, "g2Compress", IRNativeTag.bls12_381_G2_compress, new TirFuncT([g2_t], bytes_t), blsNs);
198
200
  defineBuiltin(blsNsScope, "g2Uncompress", IRNativeTag.bls12_381_G2_uncompress, new TirFuncT([bytes_t], g2_t), blsNs);
201
+ defineBuiltin(blsNsScope, "g2MultiScalarMul", IRNativeTag.bls12_381_G2_multiScalarMul, new TirFuncT([new TirListT(int_t), new TirListT(g2_t)], g2_t), blsNs);
199
202
  defineBuiltin(blsNsScope, "millerLoop", IRNativeTag.bls12_381_millerLoop, new TirFuncT([g1_t, g2_t], ml_t), blsNs);
200
203
  defineBuiltin(blsNsScope, "mulMlResult", IRNativeTag.bls12_381_mulMlResult, new TirFuncT([ml_t, ml_t], ml_t), blsNs);
201
204
  defineBuiltin(blsNsScope, "finalVerify", IRNativeTag.bls12_381_finalVerify, new TirFuncT([ml_t, ml_t], bool_t), blsNs);
@@ -47,6 +47,8 @@ export function populateStdScope(program) {
47
47
  }
48
48
  _defineStdUnambigous(void_t);
49
49
  _defineStdUnambigous(bool_t);
50
+ // `bool` is a common spelling; accept it as an alias for `boolean`.
51
+ stdScope.defineUnambigousType("bool", bool_t.toTirTypeKey(), true, new Map());
50
52
  _defineStdUnambigous(int_t);
51
53
  _defineStdUnambigous(bytes_t);
52
54
  _defineStdUnambigous(string_t);
@@ -1 +1 @@
1
- export declare const COMPILER_VERSION = "0.3.2";
1
+ export declare const COMPILER_VERSION = "0.3.4";
@@ -1,2 +1,2 @@
1
1
  // This file is auto-generated by scripts/genVersion.js. Do not edit.
2
- export const COMPILER_VERSION = "0.3.2";
2
+ export const COMPILER_VERSION = "0.3.4";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@harmoniclabs/pebble",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
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",