@harmoniclabs/pebble 0.1.0-dev7 → 0.1.0-dev8

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 (29) hide show
  1. package/dist/IR/IRNodes/IRConst.js +1 -1
  2. package/dist/IR/IRNodes/IRNative/IRNativeTag.d.ts +4 -3
  3. package/dist/IR/IRNodes/IRNative/IRNativeTag.js +8 -4
  4. package/dist/IR/IRNodes/IRNative/index.d.ts +4 -2
  5. package/dist/IR/IRNodes/IRNative/index.js +5 -2
  6. package/dist/IR/toUPLC/CompilerOptions.d.ts +1 -1
  7. package/dist/IR/toUPLC/CompilerOptions.js +2 -1
  8. package/dist/IR/toUPLC/compileIRToUPLC.js +33 -34
  9. package/dist/IR/toUPLC/subRoutines/handleLetted/index.js +69 -3
  10. package/dist/IR/toUPLC/subRoutines/replaceNatives/nativeToIR.d.ts +1 -1
  11. package/dist/IR/toUPLC/subRoutines/replaceNatives/nativeToIR.js +19 -9
  12. package/dist/IR/toUPLC/subRoutines/rewriteNativesAppliedToConstantsAndReturnRoot.js +292 -17
  13. package/dist/IR/utils/positiveIntAsBytes.js +1 -1
  14. package/dist/compiler/AstCompiler/AstCompiler.d.ts +2 -0
  15. package/dist/compiler/AstCompiler/AstCompiler.js +27 -1
  16. package/dist/compiler/AstCompiler/internal/exprs/_compileFuncExpr.js +6 -0
  17. package/dist/compiler/Compiler.d.ts +8 -1
  18. package/dist/compiler/Compiler.js +34 -1
  19. package/dist/compiler/TirCompiler/expressify/ExpressifyCtx.js +1 -1
  20. package/dist/compiler/TirCompiler/expressify/expressify.js +2 -0
  21. package/dist/compiler/TirCompiler/expressify/expressifyVars.js +36 -12
  22. package/dist/compiler/tir/expressions/TirNativeFunc.d.ts +2 -2
  23. package/dist/compiler/tir/expressions/TirNativeFunc.js +27 -14
  24. package/dist/utils/BitUtils/index.d.ts +1 -1
  25. package/dist/utils/BitUtils/index.js +1 -1
  26. package/dist/utils/IsSingleKey.d.ts +1 -1
  27. package/dist/utils/UPLCFlatUtils/index.d.ts +1 -1
  28. package/dist/utils/UPLCFlatUtils/index.js +2 -2
  29. package/package.json +6 -6
@@ -2,7 +2,6 @@ import { Pair } from "@harmoniclabs/pair";
2
2
  import { isData, dataToCbor } from "@harmoniclabs/plutus-data";
3
3
  import { fromUtf8, toHex } from "@harmoniclabs/uint8array-utils";
4
4
  import { BasePlutsError } from "../../utils/BasePlutsError.js";
5
- import UPLCFlatUtils from "../../utils/UPLCFlatUtils/index.js";
6
5
  import { concatUint8Arr } from "../utils/concatUint8Arr.js";
7
6
  import { positiveBigIntAsBytes } from "../utils/positiveIntAsBytes.js";
8
7
  import { isIRParentTerm } from "../utils/isIRParentTerm.js";
@@ -27,6 +26,7 @@ import { TirStringT } from "../../compiler/tir/types/TirNativeType/native/string
27
26
  import { TirVoidT } from "../../compiler/tir/types/TirNativeType/native/void.js";
28
27
  import { hashIrData, isIRHash } from "../IRHash.js";
29
28
  import { ByteString } from "@harmoniclabs/bytestring";
29
+ import { UPLCFlatUtils } from "../../utils/UPLCFlatUtils/index.js";
30
30
  export function isIRConstPair(value) {
31
31
  return (value instanceof Pair &&
32
32
  isIRConstValue(value.fst) &&
@@ -96,11 +96,10 @@ export declare enum IRNativeTag {
96
96
  _dropList = -4,
97
97
  _foldr = -6,
98
98
  _foldl = -7,
99
- _mkFindDataOptional = -8,
100
99
  _length = -9,
101
100
  _some = -10,
102
101
  _every = -11,
103
- _mkFilter = -12,
102
+ _filter = -12,
104
103
  _id = -15,
105
104
  _not = -16,
106
105
  _strictAnd = -17,
@@ -133,6 +132,8 @@ export declare enum IRNativeTag {
133
132
  _isZero = -42,
134
133
  _sortedValueLovelaces = -43,
135
134
  _getCredentialsHash = -44,
136
- _findSopOptional = -45
135
+ _findSopOptional = -45,
136
+ _increment = -46,
137
+ _decrement = -47
137
138
  }
138
139
  export declare function nativeTagToString(nativeTag: IRNativeTag): string;
@@ -116,11 +116,11 @@ export var IRNativeTag;
116
116
  IRNativeTag[IRNativeTag["_dropList"] = -4] = "_dropList";
117
117
  IRNativeTag[IRNativeTag["_foldr"] = -6] = "_foldr";
118
118
  IRNativeTag[IRNativeTag["_foldl"] = -7] = "_foldl";
119
- IRNativeTag[IRNativeTag["_mkFindDataOptional"] = -8] = "_mkFindDataOptional";
119
+ // _mkFindDataOptional = -8,
120
120
  IRNativeTag[IRNativeTag["_length"] = -9] = "_length";
121
121
  IRNativeTag[IRNativeTag["_some"] = -10] = "_some";
122
122
  IRNativeTag[IRNativeTag["_every"] = -11] = "_every";
123
- IRNativeTag[IRNativeTag["_mkFilter"] = -12] = "_mkFilter";
123
+ IRNativeTag[IRNativeTag["_filter"] = -12] = "_filter";
124
124
  // _fstPair = -13,
125
125
  // _sndPair = -14,
126
126
  IRNativeTag[IRNativeTag["_id"] = -15] = "_id";
@@ -156,6 +156,8 @@ export var IRNativeTag;
156
156
  IRNativeTag[IRNativeTag["_sortedValueLovelaces"] = -43] = "_sortedValueLovelaces";
157
157
  IRNativeTag[IRNativeTag["_getCredentialsHash"] = -44] = "_getCredentialsHash";
158
158
  IRNativeTag[IRNativeTag["_findSopOptional"] = -45] = "_findSopOptional";
159
+ IRNativeTag[IRNativeTag["_increment"] = -46] = "_increment";
160
+ IRNativeTag[IRNativeTag["_decrement"] = -47] = "_decrement";
159
161
  })(IRNativeTag || (IRNativeTag = {}));
160
162
  Object.freeze(IRNativeTag);
161
163
  export function nativeTagToString(nativeTag) {
@@ -165,12 +167,12 @@ export function nativeTagToString(nativeTag) {
165
167
  case IRNativeTag._dropList: return "dropList";
166
168
  case IRNativeTag._foldr: return "foldr";
167
169
  case IRNativeTag._foldl: return "foldl";
168
- case IRNativeTag._mkFindDataOptional: return "mkFind";
170
+ // case IRNativeTag._mkFindDataOptional : return "mkFind";
169
171
  case IRNativeTag._findSopOptional: return "findSopOptional";
170
172
  case IRNativeTag._length: return "length";
171
173
  case IRNativeTag._some: return "some";
172
174
  case IRNativeTag._every: return "every";
173
- case IRNativeTag._mkFilter: return "mkFilter";
175
+ case IRNativeTag._filter: return "mkFilter";
174
176
  // case IRNativeTag._fstPair : return "fstPair";
175
177
  // case IRNativeTag._sndPair : return "sndPair";
176
178
  case IRNativeTag._id: return "id";
@@ -199,6 +201,8 @@ export function nativeTagToString(nativeTag) {
199
201
  case IRNativeTag._isZero: return "isZero";
200
202
  case IRNativeTag._sortedValueLovelaces: return "sortedValueLovelaces";
201
203
  case IRNativeTag._getCredentialsHash: return "getCredentialHash";
204
+ case IRNativeTag._increment: return "increment";
205
+ case IRNativeTag._decrement: return "decrement";
202
206
  default: return "";
203
207
  }
204
208
  }
@@ -131,11 +131,10 @@ export declare class IRNative implements IIRTerm, Cloneable<IRNative>, IIRParent
131
131
  static get _dropList(): IRNative;
132
132
  static get _foldr(): IRNative;
133
133
  static get _foldl(): IRNative;
134
- static get _mkFindDataOptional(): IRNative;
135
134
  static get _length(): IRNative;
136
135
  static get _some(): IRNative;
137
136
  static get _every(): IRNative;
138
- static get _mkFilter(): IRNative;
137
+ static get _filter(): IRNative;
139
138
  static get _id(): IRNative;
140
139
  static get _not(): IRNative;
141
140
  static get _strictAnd(): IRNative;
@@ -162,6 +161,9 @@ export declare class IRNative implements IIRTerm, Cloneable<IRNative>, IIRParent
162
161
  static get _amountOfValue(): IRNative;
163
162
  static get _sortedValueLovelaces(): IRNative;
164
163
  static get _getCredentialsHash(): IRNative;
164
+ static get _increment(): IRNative;
165
+ static get _decrement(): IRNative;
166
+ static get _isZero(): IRNative;
165
167
  static equals(type: TirType): IRTerm;
166
168
  static equalListOf(type: TirType): IRHoisted;
167
169
  }
@@ -184,11 +184,11 @@ export class IRNative {
184
184
  static get _dropList() { return new IRNative(IRNativeTag._dropList); }
185
185
  static get _foldr() { return new IRNative(IRNativeTag._foldr); }
186
186
  static get _foldl() { return new IRNative(IRNativeTag._foldl); }
187
- static get _mkFindDataOptional() { return new IRNative(IRNativeTag._mkFindDataOptional); }
187
+ // static get _mkFindDataOptional() { return new IRNative( IRNativeTag._mkFindDataOptional ); }
188
188
  static get _length() { return new IRNative(IRNativeTag._length); }
189
189
  static get _some() { return new IRNative(IRNativeTag._some); }
190
190
  static get _every() { return new IRNative(IRNativeTag._every); }
191
- static get _mkFilter() { return new IRNative(IRNativeTag._mkFilter); }
191
+ static get _filter() { return new IRNative(IRNativeTag._filter); }
192
192
  // static get _fstPair() { return new IRNative( IRNativeTag._fstPair ); }
193
193
  // static get _sndPair() { return new IRNative( IRNativeTag._sndPair ); }
194
194
  static get _id() { return new IRNative(IRNativeTag._id); }
@@ -217,6 +217,9 @@ export class IRNative {
217
217
  static get _amountOfValue() { return new IRNative(IRNativeTag._amountOfValue); }
218
218
  static get _sortedValueLovelaces() { return new IRNative(IRNativeTag._sortedValueLovelaces); }
219
219
  static get _getCredentialsHash() { return new IRNative(IRNativeTag._getCredentialsHash); }
220
+ static get _increment() { return new IRNative(IRNativeTag._increment); }
221
+ static get _decrement() { return new IRNative(IRNativeTag._decrement); }
222
+ static get _isZero() { return new IRNative(IRNativeTag._isZero); }
220
223
  static equals(type) {
221
224
  type = getUnaliased(type);
222
225
  if (type instanceof TirAliasType)
@@ -24,7 +24,7 @@ export interface CompilerOptions {
24
24
  /**
25
25
  * path to the entry file
26
26
  */
27
- readonly entry: string;
27
+ entry: string;
28
28
  /**
29
29
  * path of the root of the project
30
30
  */
@@ -69,7 +69,8 @@ export const defaultOptions = Object.freeze({
69
69
  ...productionOptions,
70
70
  });
71
71
  export const testOptions = Object.freeze({
72
- ...debugOptions,
72
+ // ...debugOptions,
73
+ ...productionOptions,
73
74
  silent: true
74
75
  });
75
76
  export const defulatCompilerOptions = defaultOptions;
@@ -31,7 +31,7 @@ export function compileIRToUPLC(term, paritalOptions = defaultOptions) {
31
31
  // ------------------------------------------------------------------------- //
32
32
  ///////////////////////////////////////////////////////////////////////////////
33
33
  const options = completeCompilerOptions(paritalOptions);
34
- const debugAsserts = options.debugAsserts ?? false;
34
+ // const debugAsserts = (options as any).debugAsserts ?? false;
35
35
  // unwrap top level letted and hoisted;
36
36
  while (term instanceof IRLetted || term instanceof IRHoisted) {
37
37
  // replace with value
@@ -39,33 +39,24 @@ export function compileIRToUPLC(term, paritalOptions = defaultOptions) {
39
39
  // forget the parent; this is the new root
40
40
  term.parent = undefined;
41
41
  }
42
- debugAsserts && _debug_assertions(term);
42
+ // debugAsserts && _debug_assertions( term );
43
+ ///////////////////////////////////////////////////////////////////////////////
44
+ // ------------------------------------------------------------------------- //
45
+ // ----------------------------- optimizations ----------------------------- //
46
+ // ------------------------------------------------------------------------- //
47
+ ///////////////////////////////////////////////////////////////////////////////
43
48
  // term = preEvaluateDefinedTermsAndReturnRoot( term );
44
49
  term = rewriteNativesAppliedToConstantsAndReturnRoot(term);
45
- debugAsserts && _debug_assertions(term);
50
+ // debugAsserts && _debug_assertions( term );
46
51
  // removing unused variables BEFORE going into the rest of the compilation
47
52
  // helps letted terms to find a better spot (and possibly be inlined instead of hoisted)
48
53
  term = removeUnusedVarsAndReturnRoot(term);
49
- debugAsserts && _debug_assertions(term);
54
+ // debugAsserts && _debug_assertions( term );
50
55
  _makeAllNegativeNativesHoisted(term);
51
- ///////////////////////////////////////////////////////////////////////////////
52
- // ------------------------------------------------------------------------- //
53
- // ----------------------------- optimizations ----------------------------- //
54
- // ------------------------------------------------------------------------- //
55
- ///////////////////////////////////////////////////////////////////////////////
56
- // --------------------- optimize recursive functions --------------------- //
57
- // avoid passing whole structs
58
- // take letted terms outside
59
- // ----------------------- optimize normal functions ----------------------- //
60
- // avoid passing whole structs
61
- // reorganize function arguments to take advantage of partial applicaiton
62
- ///////////////////////////////////////////////////////////////////////////////
63
- // ------------------------------------------------------------------------- //
64
- // ------------------------------ final steps ------------------------------ //
65
- // ------------------------------------------------------------------------- //
66
- ///////////////////////////////////////////////////////////////////////////////
67
56
  term = replaceNativesAndReturnRoot(term);
68
- debugAsserts && _debug_assertions(term);
57
+ // re-call rewrite to optimize introduced hoisted
58
+ term = rewriteNativesAppliedToConstantsAndReturnRoot(term);
59
+ // debugAsserts && _debug_assertions( term );
69
60
  // unwrap top level letted and hoisted;
70
61
  // some natives may be converted to hoisted;
71
62
  // this is really just an edge case
@@ -79,31 +70,39 @@ export function compileIRToUPLC(term, paritalOptions = defaultOptions) {
79
70
  term instanceof IRConst // while we are at it
80
71
  )
81
72
  return term.toUPLC();
73
+ ///////////////////////////////////////////////////////////////////////////////
74
+ // ------------------------------------------------------------------------- //
75
+ // ------------------------------- hoisting -------------------------------- //
76
+ // ------------------------------------------------------------------------- //
77
+ ///////////////////////////////////////////////////////////////////////////////
78
+ // hoist `(force (builtin ifThenElse))` or `(force (force (builtin fstPair)))` etc
82
79
  replaceForcedNativesWithHoisted(term);
83
- debugAsserts && _debug_assertions(term);
80
+ // debugAsserts && _debug_assertions( term );
84
81
  if (options.delayHoists)
85
82
  replaceHoistedWithLetted(term);
86
83
  else
87
84
  replaceClosedLettedWithHoisted(term);
88
- debugAsserts && _debug_assertions(term);
89
- if (debugAsserts
90
- && options.delayHoists
91
- && includesNode(term, node => node instanceof IRHoisted)) {
92
- throw new Error("debug assertion failed: hoisted nodes found while delayHoists is true");
93
- }
85
+ // debugAsserts && _debug_assertions( term );
86
+ // if(
87
+ // // debugAsserts
88
+ // && options.delayHoists
89
+ // && includesNode( term, node => node instanceof IRHoisted )
90
+ // ) {
91
+ // throw new Error("debug assertion failed: hoisted nodes found while delayHoists is true");
92
+ // }
94
93
  // handle letted before hoisted because the tree is smaller
95
94
  // and we also have less letted dependecies to handle
96
95
  term = handleLettedAndReturnRoot(term);
97
- debugAsserts && _debug_assertions(term);
96
+ // debugAsserts && _debug_assertions( term );
98
97
  term = handleHoistedAndReturnRoot(term);
99
- debugAsserts && _debug_assertions(term);
98
+ // debugAsserts && _debug_assertions( term );
100
99
  // replaced hoisted terms might include new letted terms
101
100
  while (includesNode(term, node => node instanceof IRLetted
102
101
  || node instanceof IRHoisted)) {
103
102
  term = handleLettedAndReturnRoot(term);
104
103
  term = handleHoistedAndReturnRoot(term);
105
104
  }
106
- debugAsserts && _debug_assertions(term);
105
+ // debugAsserts && _debug_assertions( term );
107
106
  ///////////////////////////////////////////////////////////////////////////////
108
107
  // ------------------------------------------------------------------------- //
109
108
  // --------------------------- translate to UPLC --------------------------- //
@@ -117,13 +116,13 @@ export function compileIRToUPLC(term, paritalOptions = defaultOptions) {
117
116
  // if( options.delayHoists ) replaceHoistedWithLetted( term );
118
117
  // handle new hoisted terms
119
118
  term = handleHoistedAndReturnRoot(term);
120
- debugAsserts && _debug_assertions(term);
119
+ // debugAsserts && _debug_assertions( term );
121
120
  // strictly necessary to check the options
122
121
  // otherwise forced natives where already hoisted
123
122
  // will be re-hosited; causeing uselsess evaluations
124
123
  if (!options.delayHoists)
125
124
  term = hoistForcedNatives(term);
126
- debugAsserts && _debug_assertions(term);
125
+ // debugAsserts && _debug_assertions( term );
127
126
  // at this point we expect the IR to be translable 1:1 to UPLC
128
127
  // The loop is needed because after inlining some params,
129
128
  // new params in outer (or sibling) functions can become
@@ -161,7 +160,7 @@ export function compileIRToUPLC(term, paritalOptions = defaultOptions) {
161
160
  // irJson.text,
162
161
  // JSON.stringify( onlyHoistedAndLetted( irJson ) )
163
162
  // );
164
- debugAsserts && _debug_assertions(term);
163
+ // debugAsserts && _debug_assertions( term );
165
164
  // const srcmap = {};
166
165
  const uplc = term.toUPLC(ToUplcCtx.root());
167
166
  if (!isClosedTerm(uplc)) {
@@ -4,7 +4,7 @@ import { getSortedLettedSet, getLettedTerms, IRLetted } from "../../../IRNodes/I
4
4
  import { IRVar } from "../../../IRNodes/IRVar.js";
5
5
  import { _modifyChildFromTo } from "../../_internal/_modifyChildFromTo.js";
6
6
  import { findAllNoHoisted } from "../../_internal/findAll.js";
7
- import { getMaxScope } from "./groupByScope.js";
7
+ import { getMaxScope, getUnboundedVars } from "./groupByScope.js";
8
8
  import { IRDelayed } from "../../../IRNodes/IRDelayed.js";
9
9
  import { lowestCommonAncestor } from "../../_internal/lowestCommonAncestor.js";
10
10
  import { isIRTerm } from "../../../utils/isIRTerm.js";
@@ -47,9 +47,22 @@ export function handleLettedAndReturnRoot(term) {
47
47
  //
48
48
  // hence why `pop` (and not `shift`)
49
49
  const { letted, nReferences } = sortedLettedSet.pop();
50
+ // const shouldLog = (
51
+ // letted.value instanceof IRApp
52
+ // && letted.value.fn instanceof IRNative
53
+ // && letted.value.fn.tag === IRNativeTag.addInteger
54
+ // && letted.value.arg instanceof IRConst
55
+ // && letted.value.arg.value === -1n
56
+ // )
50
57
  // shouldLog && // console.log("nReferences", nReferences);
51
58
  // console.log(` ------------------ working with ${lettedToStr(letted)} ------------------ `);
52
- if (nReferences === 1) {
59
+ // console.log(` ------------------ working with ${lettedToStr(letted)} ------------------ `);
60
+ // if( shouldLog ) {
61
+ // console.log( prettyIRInline( letted ) );
62
+ // }
63
+ const wasSingleReferenceButRecursive = nReferences <= 1;
64
+ if (wasSingleReferenceButRecursive // nReferences <= 1
65
+ && !someParentIsRecursive(letted)) {
53
66
  // console.log("inlining letted (single reference) with value", prettyIRText( letted.value ) )
54
67
  _modifyChildFromTo(letted.parent, letted, letted.value);
55
68
  continue;
@@ -81,7 +94,9 @@ export function handleLettedAndReturnRoot(term) {
81
94
  continue;
82
95
  }
83
96
  // just in case
84
- if (sameLettedRefs.length === 1 && !minScope) {
97
+ if (sameLettedRefs.length === 1
98
+ && !minScope
99
+ && !wasSingleReferenceButRecursive) {
85
100
  // console.log("inlining letted (single reference pedantic) with value", prettyIRText( letted.value ) )
86
101
  _modifyChildFromTo(letted.parent, letted, letted.value);
87
102
  continue;
@@ -108,6 +123,47 @@ export function handleLettedAndReturnRoot(term) {
108
123
  }
109
124
  ;
110
125
  }
126
+ if (wasSingleReferenceButRecursive) {
127
+ // OPTIMIZATION:
128
+ // TODO:
129
+ // see the general case below
130
+ const unbounded = getUnboundedVars(letted.value);
131
+ if (unbounded.size === 0) {
132
+ // if closed
133
+ // handle as hoisted
134
+ for (const ref of sameLettedRefs) {
135
+ _modifyChildFromTo(ref.parent, ref, new IRVar(ref.name));
136
+ }
137
+ term = new IRApp(new IRFunc([letted.name], term), letted.value);
138
+ continue;
139
+ }
140
+ // else find highest common ancestor where all unbounded vars are defined
141
+ // OPTIMIZATION:
142
+ // TODO:
143
+ // only hoist outside the highest, but fully defined, IRRecursive
144
+ // and NOT the highest overall
145
+ // otherwise we risk paying for introducing stuff we don't use
146
+ let tmp = lca;
147
+ // let lowestOutsideRecursive: IRTerm = lca;
148
+ while (tmp = tmp.parent) {
149
+ if (tmp instanceof IRDelayed) {
150
+ lca = tmp;
151
+ // lowestOutsideRecursive = tmp;
152
+ continue;
153
+ }
154
+ if (tmp instanceof IRFunc || tmp instanceof IRRecursive) {
155
+ if (tmp.params.some(p => unbounded.has(p))) {
156
+ // some parameter is defined here
157
+ // so we stop
158
+ break;
159
+ }
160
+ else
161
+ lca = tmp;
162
+ // else lowestOutsideRecursive = tmp;
163
+ }
164
+ }
165
+ // lca = lowestOutsideRecursive;
166
+ }
111
167
  if (!isIRTerm(lca)) {
112
168
  throw new Error("letting nodes with hash " + irHashToHex(lettedHash) + " from different trees");
113
169
  }
@@ -176,3 +232,13 @@ function handleLettedAsHoistedAndReturnRoot(letted, lca, sameLettedRefs, current
176
232
  }
177
233
  return currentRoot;
178
234
  }
235
+ function someParentIsRecursive(term) {
236
+ let parent;
237
+ ;
238
+ while (parent = term.parent) {
239
+ if (parent instanceof IRRecursive)
240
+ return true;
241
+ term = parent;
242
+ }
243
+ return false;
244
+ }
@@ -28,7 +28,7 @@ export declare const hoisted_strictAnd: IRHoisted;
28
28
  export declare const hoisted_strictOr: IRHoisted;
29
29
  export declare const hoisted_some: IRHoisted;
30
30
  export declare const hoisted_every: IRHoisted;
31
- export declare const hoisted_mkFilter: IRHoisted;
31
+ export declare const hoisted_filter: IRHoisted;
32
32
  export declare const hoisted_gtBS: IRHoisted;
33
33
  export declare const hoisted_gtEqBS: IRHoisted;
34
34
  export declare const hoisted_gtInt: IRHoisted;
@@ -12,7 +12,7 @@ import { IRRecursive } from "../../../IRNodes/IRRecursive.js";
12
12
  import { IRSelfCall } from "../../../IRNodes/IRSelfCall.js";
13
13
  import { IRError } from "../../../IRNodes/IRError.js";
14
14
  import { _ir_apps } from "../../../IRNodes/IRApp.js";
15
- import { _ir_let } from "../../../tree_utils/_ir_let.js";
15
+ import { _ir_let, _ir_let_sym } from "../../../tree_utils/_ir_let.js";
16
16
  import { _ir_lazyChooseList } from "../../../tree_utils/_ir_lazyChooseList.js";
17
17
  import { _ir_lazyIfThenElse } from "../../../tree_utils/_ir_lazyIfThenElse.js";
18
18
  import { hoisted_drop4, hoisted_drop2, hoisted_drop3 } from "../_comptimeDropN.js";
@@ -156,13 +156,21 @@ const every_head = Symbol("head");
156
156
  const every_tail = Symbol("tail");
157
157
  export const hoisted_every = new IRHoisted(new IRFunc([every_pred], _ir_apps(hoisted_recursiveList.clone(), new IRFunc([every_dummy], new IRDelayed(IRConst.bool(true))), new IRFunc([every_self, every_head, every_tail], new IRForced(_ir_apps(hoisted_strictAnd.clone(), new IRDelayed(new IRApp(new IRVar(every_pred), new IRVar(every_head))), new IRDelayed(new IRApp(new IRVar(every_self), new IRVar(every_tail)))))))));
158
158
  hoisted_every.hash;
159
- // hoisted _mkFilter
160
- const filt_pnil = Symbol("pnilOfType");
159
+ // hoisted _filter
161
160
  const filt_pred = Symbol("predicate");
161
+ const filt_self = Symbol("filter_self");
162
+ const filt_list = Symbol("list");
162
163
  const filt_elem = Symbol("elem");
163
- const filt_acc = Symbol("accum");
164
- export const hoisted_mkFilter = new IRHoisted(new IRFunc([filt_pnil, filt_pred], _ir_apps(hoisted_foldr.clone(), new IRFunc([filt_elem, filt_acc], new IRForced(_ir_apps(IRNative.strictIfThenElse, new IRApp(new IRVar(filt_pred), new IRVar(filt_elem)), new IRDelayed(_ir_apps(IRNative.mkCons, new IRVar(filt_elem), new IRVar(filt_acc))), new IRDelayed(new IRVar(filt_acc))))), new IRVar(filt_pnil))));
165
- hoisted_mkFilter.hash;
164
+ export const hoisted_filter = new IRHoisted(new IRFunc([filt_pred], new IRRecursive(filt_self, new IRFunc([filt_list], _ir_lazyChooseList(new IRVar(filt_list),
165
+ // case nil
166
+ new IRVar(filt_list), // nil
167
+ // case cons
168
+ _ir_let_sym(filt_elem, _ir_apps(IRNative.headList, new IRVar(filt_list)), _ir_lazyIfThenElse(_ir_apps(new IRVar(filt_pred), new IRVar(filt_elem)),
169
+ // then => cons(elem, self(tail))
170
+ _ir_apps(IRNative.mkCons, new IRVar(filt_elem), _ir_apps(new IRSelfCall(filt_self), _ir_apps(IRNative.tailList, new IRVar(filt_list)))),
171
+ // else => self(tail)
172
+ _ir_apps(new IRSelfCall(filt_self), _ir_apps(IRNative.tailList, new IRVar(filt_list))))))))));
173
+ hoisted_filter.hash;
166
174
  // comparison & conversion hoisted (previously inline)
167
175
  const gtbs_a = Symbol("a"), gtbs_b = Symbol("b");
168
176
  export const hoisted_gtBS = new IRHoisted(new IRFunc([gtbs_a, gtbs_b], _ir_apps(IRNative.lessThanByteString, new IRVar(gtbs_b), new IRVar(gtbs_a))));
@@ -211,12 +219,12 @@ export function nativeToIR(native) {
211
219
  switch (native.tag) {
212
220
  case IRNativeTag._foldr: return hoisted_foldr.clone();
213
221
  case IRNativeTag._foldl: return hoiseted_foldl.clone();
214
- case IRNativeTag._mkFindDataOptional: return hoisted_mkFindDataOptional.clone();
222
+ // case IRNativeTag._mkFindDataOptional: return hoisted_mkFindDataOptional.clone();
215
223
  case IRNativeTag._findSopOptional: return hoisted_findSopOptional.clone();
216
224
  case IRNativeTag._length: return hoisted_length.clone();
217
225
  case IRNativeTag._some: return hoisted_some.clone();
218
226
  case IRNativeTag._every: return hoisted_every.clone();
219
- case IRNativeTag._mkFilter: return hoisted_mkFilter.clone();
227
+ case IRNativeTag._filter: return hoisted_filter.clone();
220
228
  case IRNativeTag._id: return hoisted_id.clone();
221
229
  case IRNativeTag._not: return hoisted_not.clone();
222
230
  case IRNativeTag._strictAnd: return hoisted_strictAnd.clone();
@@ -239,6 +247,8 @@ export function nativeToIR(native) {
239
247
  case IRNativeTag._getCredentialsHash: return hoisted_getCredentialsHash.clone();
240
248
  case IRNativeTag._dropList: return hoisted_dropList.clone();
241
249
  case IRNativeTag._mkMapList: return hoisted_mkMapList.clone();
250
+ case IRNativeTag._increment: return hoisted_addOne.clone();
251
+ case IRNativeTag._decrement: return hoisted_subOne.clone();
242
252
  // case IRNativeTag._mkEqualsList: return hoisted_mkEqualsList.clone();
243
253
  default:
244
254
  throw new Error("unknown (negative) native calling 'nativeToIR'; " +
@@ -260,7 +270,7 @@ IRConst.bool(false),
260
270
  // both lists are cons
261
271
  _ir_strictAnd(_ir_apps(new IRVar(eqList_eqFunc), new IRApp(IRNative.headList, new IRVar(eqList_listA)), new IRApp(IRNative.headList, new IRVar(eqList_listB))), _ir_apps(new IRSelfCall(eqList_self), new IRApp(IRNative.tailList, new IRVar(eqList_listA)), new IRApp(IRNative.tailList, new IRVar(eqList_listB))))))))));
262
272
  hoisted_mkEqualsList.hash;
263
- // (nil of type) => ( a => b ) => [a] => [b]
273
+ // (nil of type) [b] => ( a => b ) => [a] => [b]
264
274
  const mkMap_nil = Symbol("nilOfType");
265
275
  const mkMap_mapFunc = Symbol("mapFunc");
266
276
  const mkMap_map = Symbol("map_self");
@@ -1,3 +1,5 @@
1
+ import { TirBoolT, TirIntT } from "../../../compiler/tir/types/TirNativeType/index.js";
2
+ import { equalIrHash } from "../../IRHash.js";
1
3
  import { _ir_apps } from "../../IRNodes/IRApp.js";
2
4
  import { IRConst } from "../../IRNodes/IRConst.js";
3
5
  import { IRFunc } from "../../IRNodes/IRFunc.js";
@@ -9,13 +11,25 @@ import { IRVar } from "../../IRNodes/IRVar.js";
9
11
  import { _modifyChildFromTo } from "../_internal/_modifyChildFromTo.js";
10
12
  import { getApplicationTerms } from "../utils/getApplicationTerms.js";
11
13
  import { _compTimeDropN } from "./_comptimeDropN.js";
14
+ import { hoisted_isZero, hoisted_length, hoisted_not } from "./replaceNatives/nativeToIR.js";
12
15
  export function rewriteNativesAppliedToConstantsAndReturnRoot(term) {
13
16
  // traverse the tree, find applications of natives to constants
14
17
  // and replace them with the optimized equivalent
15
18
  const stack = [term];
19
+ function modifyTermAndPushToReprocess(current, newTerm) {
20
+ const parent = current.parent;
21
+ if (parent) {
22
+ _modifyChildFromTo(parent, current, newTerm);
23
+ }
24
+ else {
25
+ term = newTerm;
26
+ term.parent = undefined;
27
+ }
28
+ stack.unshift(newTerm); // reprocess new term for further optimizations (if any)
29
+ }
16
30
  while (stack.length > 0) {
17
31
  const current = stack.pop();
18
- const parent = current.parent;
32
+ // const parent = current.parent;
19
33
  const appTerms = getApplicationTerms(current);
20
34
  if (!appTerms) {
21
35
  stack.unshift(...current.children());
@@ -25,16 +39,196 @@ export function rewriteNativesAppliedToConstantsAndReturnRoot(term) {
25
39
  const [fstArg, ...restArgs] = args;
26
40
  if (isId(func)
27
41
  && restArgs.length === 0) {
28
- if (parent) {
29
- _modifyChildFromTo(parent, current, fstArg);
30
- }
31
- else {
32
- term = fstArg;
33
- term.parent = undefined;
34
- }
35
- stack.unshift(fstArg);
42
+ modifyTermAndPushToReprocess(current, fstArg);
36
43
  continue;
37
44
  }
45
+ if (func instanceof IRNative) {
46
+ const tag = func.tag;
47
+ if (tag === IRNativeTag.strictIfThenElse
48
+ && restArgs.length === 2) {
49
+ const conditionArg = fstArg;
50
+ const condtionAppTerms = getApplicationTerms(conditionArg);
51
+ if (!condtionAppTerms) {
52
+ const boolValue = getConstBool(conditionArg);
53
+ if (typeof boolValue === "boolean") {
54
+ const newTerm = boolValue ? restArgs[0] : restArgs[1];
55
+ modifyTermAndPushToReprocess(current, newTerm);
56
+ continue;
57
+ }
58
+ stack.unshift(...current.children()); // normal processing
59
+ continue;
60
+ }
61
+ const { func: condFunc, args: condArgs } = condtionAppTerms;
62
+ const thenArg = restArgs[0];
63
+ const elseArg = restArgs[1];
64
+ if (isNot(condFunc)
65
+ && condArgs.length === 1) {
66
+ // replace with swapped branches
67
+ const newTerm = _ir_apps(IRNative.strictIfThenElse, condArgs[0], elseArg, thenArg);
68
+ modifyTermAndPushToReprocess(current, newTerm);
69
+ continue;
70
+ }
71
+ else if (isLessThanOrEqualInteger(condFunc)
72
+ && condArgs.length === 2) {
73
+ const [lhs, rhs] = condArgs;
74
+ const lhsInt = getConstInt(lhs);
75
+ const rhsInt = getConstInt(rhs);
76
+ if (typeof lhsInt === "bigint" && typeof rhsInt === "bigint") {
77
+ // replace with constant
78
+ const newTerm = (lhsInt <= rhsInt) ? thenArg : elseArg;
79
+ modifyTermAndPushToReprocess(current, newTerm);
80
+ continue;
81
+ }
82
+ else if (typeof lhsInt === "bigint") {
83
+ const newTerm = _ir_apps(IRNative.strictIfThenElse, _ir_apps(new IRHoisted(_ir_apps(IRNative.lessThanEqualInteger, lhs)), rhs), thenArg, elseArg);
84
+ modifyTermAndPushToReprocess(current, newTerm);
85
+ continue;
86
+ }
87
+ else if (typeof rhsInt === "bigint") {
88
+ const newTerm = _ir_apps(IRNative.strictIfThenElse, _ir_apps(new IRHoisted(_ir_apps(IRNative.lessThanInteger, rhs)), lhs), elseArg, thenArg);
89
+ modifyTermAndPushToReprocess(current, newTerm);
90
+ continue;
91
+ }
92
+ }
93
+ else if (isLessThanInteger(condFunc)
94
+ && condArgs.length === 2) {
95
+ const [lhs, rhs] = condArgs;
96
+ const lhsInt = getConstInt(lhs);
97
+ const rhsInt = getConstInt(rhs);
98
+ if (typeof lhsInt === "bigint" && typeof rhsInt === "bigint") {
99
+ // replace with constant
100
+ const newTerm = (lhsInt < rhsInt) ? thenArg : elseArg;
101
+ modifyTermAndPushToReprocess(current, newTerm);
102
+ continue;
103
+ }
104
+ else if (typeof lhsInt === "bigint") {
105
+ const newTerm = _ir_apps(IRNative.strictIfThenElse, _ir_apps(new IRHoisted(_ir_apps(IRNative.lessThanInteger, lhs)), rhs), thenArg, elseArg);
106
+ modifyTermAndPushToReprocess(current, newTerm);
107
+ continue;
108
+ }
109
+ else if (typeof rhsInt === "bigint") {
110
+ const newTerm = _ir_apps(IRNative.strictIfThenElse, _ir_apps(new IRHoisted(_ir_apps(IRNative.lessThanEqualInteger, rhs)), lhs), elseArg, thenArg);
111
+ modifyTermAndPushToReprocess(current, newTerm);
112
+ continue;
113
+ }
114
+ }
115
+ else if (isEqualsZero(condFunc)
116
+ && condArgs.length === 1) {
117
+ const equalZeroArg = condArgs[0];
118
+ const equalZeroArgAppTerms = getApplicationTerms(equalZeroArg);
119
+ if (!equalZeroArgAppTerms) {
120
+ // standard continuation
121
+ stack.unshift(...current.children());
122
+ continue;
123
+ }
124
+ const { func: eqZeroArgFunc, args: eqZeroArgArgs } = equalZeroArgAppTerms;
125
+ if (isListLength(eqZeroArgFunc)
126
+ && eqZeroArgArgs.length === 1) {
127
+ const listTerm = eqZeroArgArgs[0];
128
+ // replace with isNullList
129
+ const newTerm = _ir_apps(IRNative.strictChooseList, listTerm, thenArg, elseArg);
130
+ modifyTermAndPushToReprocess(current, newTerm);
131
+ continue;
132
+ }
133
+ // standard continuation
134
+ stack.unshift(...current.children());
135
+ continue;
136
+ } // if( x.length() === 0 )
137
+ else if (isNullList(condFunc)
138
+ && condArgs.length === 1) {
139
+ const listTerm = condArgs[0];
140
+ // replace with isListLength
141
+ const newTerm = _ir_apps(IRNative.strictChooseList, listTerm, thenArg, elseArg);
142
+ modifyTermAndPushToReprocess(current, newTerm);
143
+ continue;
144
+ } // if( x.isEmpty() )
145
+ } // strictIfThenElse
146
+ else if (tag === IRNativeTag.equalsInteger
147
+ && restArgs.length === 1) {
148
+ const sndArg = restArgs[0];
149
+ const fstInt = getConstInt(fstArg);
150
+ const sndInt = getConstInt(sndArg);
151
+ if (fstInt === BigInt(0)) {
152
+ // replace as `isZero( sndArg )`
153
+ const newTerm = _ir_apps(IRNative._isZero, sndArg);
154
+ modifyTermAndPushToReprocess(current, newTerm);
155
+ continue;
156
+ }
157
+ else if (sndInt === BigInt(0)) {
158
+ // replace as `isZero( fstArg )`
159
+ const newTerm = _ir_apps(IRNative._isZero, fstArg);
160
+ modifyTermAndPushToReprocess(current, newTerm);
161
+ continue;
162
+ }
163
+ else if (typeof fstInt === "bigint" && typeof sndInt === "bigint") {
164
+ // replace as constant
165
+ const newTerm = IRConst.bool(fstInt === sndInt);
166
+ modifyTermAndPushToReprocess(current, newTerm);
167
+ continue;
168
+ }
169
+ else if (typeof fstInt === "bigint") {
170
+ const newTerm = _ir_apps(new IRHoisted(_ir_apps(IRNative.equalsInteger, fstArg)), sndArg);
171
+ modifyTermAndPushToReprocess(current, newTerm);
172
+ continue;
173
+ }
174
+ else if (typeof sndInt === "bigint") {
175
+ const newTerm = _ir_apps(new IRHoisted(_ir_apps(IRNative.equalsInteger, sndArg)), fstArg);
176
+ modifyTermAndPushToReprocess(current, newTerm);
177
+ continue;
178
+ }
179
+ } // equalsInteger
180
+ else if (tag === IRNativeTag.addInteger
181
+ && restArgs.length === 1) {
182
+ const sndArg = restArgs[0];
183
+ const fstInt = getConstInt(fstArg);
184
+ const sndInt = getConstInt(sndArg);
185
+ if (fstInt === BigInt(1)) {
186
+ // replace as `incr( sndArg )`
187
+ const newTerm = _ir_apps(IRNative._increment, sndArg);
188
+ modifyTermAndPushToReprocess(current, newTerm);
189
+ continue;
190
+ }
191
+ else if (sndInt === BigInt(1)) {
192
+ // replace as `incr( fstArg )`
193
+ const newTerm = _ir_apps(IRNative._increment, fstArg);
194
+ modifyTermAndPushToReprocess(current, newTerm);
195
+ continue;
196
+ }
197
+ else if (typeof fstInt === "bigint" && typeof sndInt === "bigint") {
198
+ // replace as constant
199
+ const newTerm = IRConst.int(fstInt + sndInt);
200
+ modifyTermAndPushToReprocess(current, newTerm);
201
+ continue;
202
+ }
203
+ else if (typeof fstInt === "bigint") {
204
+ const newTerm = _ir_apps(new IRHoisted(_ir_apps(IRNative.addInteger, fstArg)), sndArg);
205
+ modifyTermAndPushToReprocess(current, newTerm);
206
+ continue;
207
+ }
208
+ else if (typeof sndInt === "bigint") {
209
+ const newTerm = _ir_apps(new IRHoisted(_ir_apps(IRNative.addInteger, sndArg)), fstArg);
210
+ modifyTermAndPushToReprocess(current, newTerm);
211
+ continue;
212
+ }
213
+ } // addInteger
214
+ else if (tag === IRNativeTag.subtractInteger
215
+ && restArgs.length === 1) {
216
+ const sndArg = restArgs[0];
217
+ const sndInt = getConstInt(sndArg);
218
+ if (sndInt === BigInt(1)) {
219
+ // replace as `decr( fstArg )`
220
+ const newTerm = _ir_apps(IRNative._decrement, fstArg);
221
+ modifyTermAndPushToReprocess(current, newTerm);
222
+ continue;
223
+ }
224
+ else if (typeof sndInt === "bigint") {
225
+ const newTerm = _ir_apps(new IRHoisted(_ir_apps(IRNative.addInteger, IRConst.int(-sndInt))), fstArg);
226
+ modifyTermAndPushToReprocess(current, newTerm);
227
+ continue;
228
+ }
229
+ }
230
+ }
231
+ // only optimizations if first argument is constant after this point
38
232
  if (!(fstArg instanceof IRConst)) {
39
233
  stack.unshift(...current.children());
40
234
  continue;
@@ -43,14 +237,7 @@ export function rewriteNativesAppliedToConstantsAndReturnRoot(term) {
43
237
  && (typeof fstArg.value === "bigint"
44
238
  || typeof fstArg.value === "number")) {
45
239
  const newTerm = restArgs.length >= 1 ? _ir_apps(_compTimeDropN(fstArg.value), ...restArgs) : _compTimeDropN(fstArg.value);
46
- if (parent) {
47
- _modifyChildFromTo(parent, current, newTerm);
48
- }
49
- else {
50
- term = newTerm;
51
- term.parent = undefined;
52
- }
53
- stack.unshift(newTerm);
240
+ modifyTermAndPushToReprocess(current, newTerm);
54
241
  continue;
55
242
  }
56
243
  // const tsEnsureExhaustiveCheck: never = func;
@@ -83,3 +270,91 @@ function isId(term) {
83
270
  && term.body instanceof IRVar
84
271
  && term.body.name === term.params[0]));
85
272
  }
273
+ function isNot(term) {
274
+ while (term instanceof IRHoisted
275
+ || term instanceof IRLetted) {
276
+ if (term instanceof IRHoisted)
277
+ term = term.hoisted;
278
+ else if (term instanceof IRLetted)
279
+ term = term.value;
280
+ }
281
+ return (term instanceof IRNative
282
+ && term.tag === IRNativeTag._not) || (equalIrHash(hoisted_not.hoisted.hash, term.hash));
283
+ }
284
+ function isNullList(term) {
285
+ while (term instanceof IRHoisted
286
+ || term instanceof IRLetted) {
287
+ if (term instanceof IRHoisted)
288
+ term = term.hoisted;
289
+ else if (term instanceof IRLetted)
290
+ term = term.value;
291
+ }
292
+ return (term instanceof IRNative
293
+ && term.tag === IRNativeTag.nullList);
294
+ }
295
+ function isEqualsZero(term) {
296
+ while (term instanceof IRHoisted
297
+ || term instanceof IRLetted) {
298
+ if (term instanceof IRHoisted)
299
+ term = term.hoisted;
300
+ else if (term instanceof IRLetted)
301
+ term = term.value;
302
+ }
303
+ return (term instanceof IRNative
304
+ && term.tag === IRNativeTag._isZero) || (equalIrHash(hoisted_isZero.hash, term.hash));
305
+ }
306
+ function isLessThanOrEqualInteger(term) {
307
+ while (term instanceof IRHoisted
308
+ || term instanceof IRLetted) {
309
+ if (term instanceof IRHoisted)
310
+ term = term.hoisted;
311
+ else if (term instanceof IRLetted)
312
+ term = term.value;
313
+ }
314
+ return (term instanceof IRNative
315
+ && term.tag === IRNativeTag.lessThanEqualInteger);
316
+ }
317
+ function isLessThanInteger(term) {
318
+ while (term instanceof IRHoisted
319
+ || term instanceof IRLetted) {
320
+ if (term instanceof IRHoisted)
321
+ term = term.hoisted;
322
+ else if (term instanceof IRLetted)
323
+ term = term.value;
324
+ }
325
+ return (term instanceof IRNative
326
+ && term.tag === IRNativeTag.lessThanInteger);
327
+ }
328
+ function isListLength(term) {
329
+ while (term instanceof IRHoisted
330
+ || term instanceof IRLetted) {
331
+ if (term instanceof IRHoisted)
332
+ term = term.hoisted;
333
+ else if (term instanceof IRLetted)
334
+ term = term.value;
335
+ }
336
+ return (term instanceof IRNative
337
+ && term.tag === IRNativeTag._length) || equalIrHash(hoisted_length.hash, term.hash);
338
+ }
339
+ function getConstInt(term) {
340
+ if (term instanceof IRConst
341
+ && term.type instanceof TirIntT
342
+ && typeof term.value === "bigint")
343
+ return term.value;
344
+ return undefined;
345
+ }
346
+ // function isConstIntOne( term: IRTerm ): boolean
347
+ // {
348
+ // return (
349
+ // term instanceof IRConst
350
+ // && term.type instanceof TirIntT
351
+ // && term.value === BigInt( 1 )
352
+ // );
353
+ // }
354
+ function getConstBool(term) {
355
+ if (term instanceof IRConst
356
+ && term.type instanceof TirBoolT
357
+ && typeof term.value === "boolean")
358
+ return term.value;
359
+ return undefined;
360
+ }
@@ -1,5 +1,5 @@
1
1
  import { fromHex } from "@harmoniclabs/uint8array-utils";
2
- import UPLCFlatUtils from "../../utils/UPLCFlatUtils/index.js";
2
+ import { UPLCFlatUtils } from "../../utils/UPLCFlatUtils/index.js";
3
3
  /**
4
4
  * writes the number in a new `Uint8Array` Big Endian
5
5
  */
@@ -41,6 +41,8 @@ export declare class AstCompiler extends DiagnosticEmitter {
41
41
  readonly parsedAstSources: Map<string, Source>;
42
42
  get rootPath(): string;
43
43
  constructor(cfg: CompilerOptions, io?: CompilerIoApi, diagnostics?: DiagnosticMessage[]);
44
+ private _isExporting;
45
+ export(funcName: string, modulePath?: string): Promise<TypedProgram>;
44
46
  /**
45
47
  * compiles the entry file specified in the config
46
48
  *
@@ -35,6 +35,7 @@ import { _deriveContractBody } from "./internal/_deriveContractBody/_deriveContr
35
35
  import { DiagnosticCategory } from "../../diagnostics/DiagnosticCategory.js";
36
36
  import { VarStmt } from "../../ast/nodes/statements/VarStmt.js";
37
37
  import { _compileSimpleVarDecl } from "./internal/statements/_compileVarStmt.js";
38
+ import { isIdentifier } from "../../utils/text.js";
38
39
  /*
39
40
  Handling type expressions that depend on other types
40
41
  (such as generics, function return types, and inferred types from complex expressions)
@@ -84,6 +85,24 @@ export class AstCompiler extends DiagnosticEmitter {
84
85
  this.cfg = cfg;
85
86
  this.io = io;
86
87
  this.program = new TypedProgram(this.diagnostics);
88
+ this._isExporting = false;
89
+ }
90
+ _isExporting;
91
+ async export(funcName, modulePath) {
92
+ this._isExporting = true;
93
+ if (typeof funcName !== "string")
94
+ throw new Error("AstCompiler.export: funcName must be a string");
95
+ funcName = funcName.trim();
96
+ if (funcName === "" || !isIdentifier(funcName))
97
+ throw new Error("AstCompiler.export: funcName must be a valid function identifier");
98
+ if (typeof modulePath === "string") {
99
+ const nextEntryPath = modulePath;
100
+ if (!nextEntryPath)
101
+ throw new Error("AstCompiler.export: modulePath not found: " + modulePath);
102
+ this.cfg.entry = nextEntryPath;
103
+ }
104
+ this.program.contractTirFuncName = funcName;
105
+ return await this.compile();
87
106
  }
88
107
  /**
89
108
  * compiles the entry file specified in the config
@@ -115,6 +134,7 @@ export class AstCompiler extends DiagnosticEmitter {
115
134
  }
116
135
  const mainFuncExpr = this.program.functions.get(this.program.contractTirFuncName);
117
136
  if (this.program.contractTirFuncName === "" || !mainFuncExpr) {
137
+ console.log([...this.program.functions.keys()]);
118
138
  console.error(mainFuncExpr, `"${this.program.contractTirFuncName}"`);
119
139
  this.error(DiagnosticCode.Contract_is_missing, undefined);
120
140
  return this.program;
@@ -205,8 +225,11 @@ export class AstCompiler extends DiagnosticEmitter {
205
225
  if (exported && stmt instanceof TypeImplementsStmt)
206
226
  this.error(DiagnosticCode.Interface_implementations_cannot_be_exported, exportRange ?? stmt.range);
207
227
  if (stmt instanceof ContractDecl) {
228
+ if (!(
208
229
  // ignore contract declarations if not in the entry file
209
- if (!isEntryFile) {
230
+ isEntryFile
231
+ // ignore contract decalarations if we are exporting a specific function
232
+ || this._isExporting)) {
210
233
  // remove from array so we don't process it again
211
234
  void stmts.splice(i, 1);
212
235
  i--;
@@ -300,6 +323,9 @@ export class AstCompiler extends DiagnosticEmitter {
300
323
  const astFuncExpr = stmt.expr;
301
324
  const astFuncName = astFuncExpr.name.text;
302
325
  const tirFuncName = PEBBLE_INTERNAL_IDENTIFIER_PREFIX + astFuncName + "_" + srcUid;
326
+ if (this._isExporting && astFuncName === this.program.contractTirFuncName) {
327
+ this.program.contractTirFuncName = tirFuncName;
328
+ }
303
329
  const declContext = AstCompilationCtx.fromScope(this.program, topLevelScope);
304
330
  const funcExpr = _compileFuncExpr(declContext, astFuncExpr, undefined, // sig
305
331
  false // isMethod
@@ -74,6 +74,12 @@ export function _compileFuncExpr(ctx, expr, expectedFuncType, isMethod = false)
74
74
  }
75
75
  const returnType = expectedFuncType.returnType;
76
76
  const funcCtx = ctx.newFunctionChildScope(returnType, isMethod);
77
+ // define value in case of recursion
78
+ funcCtx.scope.defineValue({
79
+ name: expr.name.text,
80
+ type: expectedFuncType,
81
+ isConstant: true,
82
+ });
77
83
  // if( _hasDuplicateTypeParams( ctx, expr.typeParams ) ) return undefined;
78
84
  if (expr.typeParams.length > 0)
79
85
  return ctx.error(DiagnosticCode.Not_implemented_0, expr.typeParams[0].range, "generic functions");
@@ -6,5 +6,12 @@ export declare class Compiler extends DiagnosticEmitter {
6
6
  readonly io: CompilerIoApi;
7
7
  readonly cfg: CompilerOptions;
8
8
  constructor(io?: CompilerIoApi, cfg?: CompilerOptions, diagnostics?: DiagnosticMessage[]);
9
- compile(config?: Partial<CompilerOptions>): Promise<void>;
9
+ compile(config?: Partial<CompilerOptions>): Promise<Uint8Array>;
10
+ export(config: Partial<ExportOptions> & HasFuncitonName): Promise<Uint8Array>;
10
11
  }
12
+ interface HasFuncitonName {
13
+ functionName: string;
14
+ }
15
+ export interface ExportOptions extends CompilerOptions, HasFuncitonName {
16
+ }
17
+ export {};
@@ -43,6 +43,39 @@ export class Compiler extends DiagnosticEmitter {
43
43
  this.io.writeFile(outPath, serialized, cfg.root);
44
44
  this.io.stdout.write(`compiled program written to ${outPath}\n`);
45
45
  __VERY_UNSAFE_FORGET_IRHASH_ONLY_USE_AT_END_OF_UPLC_COMPILATION();
46
- return;
46
+ return serialized;
47
+ }
48
+ async export(config) {
49
+ const cfg = {
50
+ ...this.cfg,
51
+ ...config,
52
+ // NEVER generate markers when exporting a function
53
+ addMarker: false,
54
+ };
55
+ if (typeof cfg.functionName !== "string" || cfg.functionName.length === 0) {
56
+ throw new Error("Compiler::export - invalid function name in export options");
57
+ }
58
+ const astCompiler = new AstCompiler(cfg, this.io, this.diagnostics);
59
+ const program = await astCompiler.export(cfg.functionName, cfg.entry);
60
+ if (this.diagnostics.length > 0) {
61
+ let msg;
62
+ globalThis.console && console.log(this.diagnostics);
63
+ const fstErrorMsg = this.diagnostics[0].toString();
64
+ const nDiags = this.diagnostics.length;
65
+ while (msg = this.diagnostics.shift()) {
66
+ this.io.stdout.write(msg.toString() + "\n");
67
+ }
68
+ throw new Error("compilation failed with " + nDiags + " diagnostic messages; first message: " + fstErrorMsg);
69
+ }
70
+ // backend starts here
71
+ const ir = compileTypedProgram(cfg, program);
72
+ const uplc = compileIRToUPLC(ir, cfg);
73
+ const serialized = compileUPLC(new UPLCProgram(cfg.targetUplcVersion, uplc)).toBuffer().buffer;
74
+ const outDir = cfg.outDir;
75
+ const outPath = outDir + (outDir.endsWith("/") ? "" : "/") + "out.flat";
76
+ this.io.writeFile(outPath, serialized, cfg.root);
77
+ this.io.stdout.write(`compiled program written to ${outPath}\n`);
78
+ __VERY_UNSAFE_FORGET_IRHASH_ONLY_USE_AT_END_OF_UPLC_COMPILATION();
79
+ return serialized;
47
80
  }
48
81
  }
@@ -119,7 +119,7 @@ export class ExpressifyCtx {
119
119
  const result = (this._getNonHoistedVariable(name)
120
120
  ?? this.hoisted.get(name));
121
121
  if (!result) {
122
- console.log(this.allVariables());
122
+ console.log("[error log]: allVariables", this.allVariables());
123
123
  throw new Error(`variable '${name}' not found in the context`);
124
124
  }
125
125
  return result;
@@ -41,6 +41,8 @@ import { TirCallExpr } from "../../tir/expressions/TirCallExpr.js";
41
41
  import { TirNativeFunc } from "../../tir/expressions/TirNativeFunc.js";
42
42
  export function expressify(func, loopReplacements, program, parentCtx = undefined) {
43
43
  const ctx = new ExpressifyCtx(parentCtx, func.returnType, program);
44
+ // define in case of recursion
45
+ ctx.setFuncParam(func.name, func.type);
44
46
  ctx.introduceFuncParams(func.params);
45
47
  func.body.stmts = [
46
48
  new TirReturnStmt(expressifyFuncBody(ctx, func.body.stmts, loopReplacements), func.body.range)
@@ -384,7 +384,7 @@ function expressifyMethodCall(ctx, methodCall) {
384
384
  throw new Error(`Cannot call method '${methodName}' on non-struct type '${objectType.toString()}'`);
385
385
  }
386
386
  function expressifyListMethodCall(ctx, objectExpr, methodCall, methodName, listType, exprRange) {
387
- const elemsType = getListTypeArg(listType);
387
+ const elemsType = getUnaliased(getListTypeArg(listType));
388
388
  if (!elemsType)
389
389
  throw new Error("Invalid list type");
390
390
  if (methodName === "length") {
@@ -432,22 +432,46 @@ function expressifyListMethodCall(ctx, objectExpr, methodCall, methodName, listT
432
432
  // console.log( finalType );
433
433
  return new TirCallExpr(TirNativeFunc._findSopOptional(elemsType), [methodCall.args[0], objectExpr], methodCall.type, exprRange);
434
434
  }
435
+ if (methodName === "filter") {
436
+ if (methodCall.args.length !== 1)
437
+ throw new Error(`Method 'filter' of type 'list' takes 1 argument, ${methodCall.args.length} provided`);
438
+ return new TirCallExpr(TirNativeFunc._filter(elemsType), [methodCall.args[0], objectExpr], methodCall.type, exprRange);
439
+ }
440
+ if (methodName === "prepend") {
441
+ if (methodCall.args.length !== 1)
442
+ throw new Error(`Method 'prepend' of type 'list' takes 1 argument, ${methodCall.args.length} provided`);
443
+ return new TirCallExpr(TirNativeFunc.mkCons(elemsType), [methodCall.args[0], objectExpr], methodCall.type, exprRange);
444
+ }
445
+ if (methodName === "map") {
446
+ if (methodCall.args.length !== 1)
447
+ throw new Error(`Method 'map' of type 'list' takes 1 argument, ${methodCall.args.length} provided`);
448
+ const arg = methodCall.args[0];
449
+ const argFuncType = getUnaliased(arg.type);
450
+ if (!(argFuncType instanceof TirFuncT))
451
+ throw new Error(`Argument 1 of method 'map' of type 'list' must be a function, got '${arg.type.toString()}'`);
452
+ const mapReturnT = argFuncType.returnType;
453
+ const elemTypeTirName = elemsType.toTirTypeKey();
454
+ let base_mapToType = _base_mapToType_cache.get(elemTypeTirName)?.clone();
455
+ if (!base_mapToType) {
456
+ base_mapToType = new TirHoistedExpr("_map_to_list_of_" + elemTypeTirName, new TirCallExpr(TirNativeFunc._mkMap(elemsType, mapReturnT), [new TirLitArrExpr([], new TirListT(mapReturnT), SourceRange.unknown)], new TirFuncT([
457
+ // mapping function
458
+ new TirFuncT([
459
+ elemsType
460
+ ], mapReturnT),
461
+ // list to map over
462
+ new TirListT(elemsType)
463
+ ], new TirListT(mapReturnT)), SourceRange.unknown));
464
+ base_mapToType.varName; // precompute hash and symbol
465
+ _base_mapToType_cache.set(elemTypeTirName, base_mapToType.clone());
466
+ }
467
+ return new TirCallExpr(base_mapToType, [methodCall.args[0], objectExpr], methodCall.type, exprRange);
468
+ }
435
469
  // TODO
436
470
  /*
437
471
  {
438
- isEmpty: new TirFuncT( [], bool_t ),
439
472
  show: new TirFuncT( [], bytes_t ),
440
473
  reverse: new TirFuncT( [], new TirListT( elemsType ) ),
441
- find: new TirFuncT([
442
- new TirFuncT( [elemsType], bool_t )
443
- ], new TirSopOptT( elemsType ) ),
444
- filter: new TirFuncT([
445
- new TirFuncT( [elemsType], bool_t )
446
- ], new TirListT( elemsType ) ),
447
- prepend: new TirFuncT( [elemsType], new TirListT( elemsType ) ),
448
- map: new TirFuncT([
449
- new TirFuncT([ elemsType ], mapReturnT )
450
- ], new TirListT( mapReturnT ) ),
451
474
  };
452
475
  */
453
476
  }
477
+ const _base_mapToType_cache = new Map();
@@ -84,12 +84,12 @@ export declare class TirNativeFunc implements ITirExpr {
84
84
  static _dropList(elemT: TirType): TirNativeFunc;
85
85
  static _foldr(elemT: TirType, returnT: TirType): TirNativeFunc;
86
86
  static _foldl(elemT: TirType, returnT: TirType): TirNativeFunc;
87
- static _mkFindDataOptional(elems_t: TirType): TirNativeFunc;
88
87
  static _findSopOptional(elems_t: TirType): TirNativeFunc;
89
88
  static _length(elemT: TirType): TirNativeFunc;
90
89
  static _some(elemT: TirType): TirNativeFunc;
91
90
  static _every(elemT: TirType): TirNativeFunc;
92
- static _mkFilter(elemT: TirType): TirNativeFunc;
91
+ static _filter(elemT: TirType): TirNativeFunc;
92
+ static _mkMap(elemT: TirType, returnElemT: TirType): TirNativeFunc;
93
93
  static _id(t: TirType): TirNativeFunc;
94
94
  static get _not(): TirNativeFunc;
95
95
  static get _strictAnd(): TirNativeFunc;
@@ -663,16 +663,19 @@ export class TirNativeFunc {
663
663
  new TirListT(elemT)
664
664
  ], returnT));
665
665
  }
666
- static _mkFindDataOptional(elems_t) {
667
- return new TirNativeFunc(IRNativeTag._mkFindDataOptional, new TirFuncT([
668
- // elem -> data
669
- new TirFuncT([elems_t], data_t),
670
- // elem -> bool (predicate)
671
- new TirFuncT([elems_t], bool_t),
672
- // List<elem>
673
- new TirListT(elems_t)
674
- ], new TirDataOptT(elems_t)));
675
- }
666
+ // static _mkFindDataOptional(elems_t: TirType): TirNativeFunc {
667
+ // return new TirNativeFunc(
668
+ // IRNativeTag._mkFindDataOptional,
669
+ // new TirFuncT([
670
+ // // elem -> data
671
+ // new TirFuncT([ elems_t ], data_t),
672
+ // // elem -> bool (predicate)
673
+ // new TirFuncT([ elems_t ], bool_t),
674
+ // // List<elem>
675
+ // new TirListT(elems_t)
676
+ // ], new TirDataOptT(elems_t))
677
+ // );
678
+ // }
676
679
  static _findSopOptional(elems_t) {
677
680
  return new TirNativeFunc(IRNativeTag._findSopOptional, new TirFuncT([
678
681
  // predicate: (elemT) => bool
@@ -705,10 +708,8 @@ export class TirNativeFunc {
705
708
  new TirListT(elemT)
706
709
  ], bool_t));
707
710
  }
708
- static _mkFilter(elemT) {
709
- return new TirNativeFunc(IRNativeTag._mkFilter, new TirFuncT([
710
- // pnilOfType: an empty list with the right element type
711
- new TirListT(elemT),
711
+ static _filter(elemT) {
712
+ return new TirNativeFunc(IRNativeTag._filter, new TirFuncT([
712
713
  // predicate
713
714
  new TirFuncT([
714
715
  elemT
@@ -717,6 +718,18 @@ export class TirNativeFunc {
717
718
  new TirListT(elemT)
718
719
  ], new TirListT(elemT)));
719
720
  }
721
+ static _mkMap(elemT, returnElemT) {
722
+ return new TirNativeFunc(IRNativeTag._mkMapList, new TirFuncT([
723
+ // nil of return elem type
724
+ new TirListT(returnElemT),
725
+ // mapping function
726
+ new TirFuncT([
727
+ elemT
728
+ ], returnElemT),
729
+ // list to map over
730
+ new TirListT(elemT)
731
+ ], new TirListT(returnElemT)));
732
+ }
720
733
  static _id(t) {
721
734
  return new TirNativeFunc(IRNativeTag._id, new TirFuncT([t], t));
722
735
  }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @static
3
3
  */
4
- export default class BitUtils {
4
+ export declare class BitUtils {
5
5
  private constructor();
6
6
  /**
7
7
  * @deprecated not sure it has ever made sense to have it
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @static
3
3
  */
4
- export default class BitUtils {
4
+ export class BitUtils {
5
5
  constructor() { }
6
6
  /**
7
7
  * @deprecated not sure it has ever made sense to have it
@@ -3,5 +3,5 @@ type SingleKeyObj<K extends string | number | symbol, V = any> = {
3
3
  [Q in keyof O]: O[Q];
4
4
  } : never;
5
5
  }[K];
6
- export default SingleKeyObj;
7
6
  export type IsSingleKey<Obj extends object> = Obj extends SingleKeyObj<keyof Obj> ? true : false;
7
+ export {};
@@ -8,7 +8,7 @@ export interface BitStreamPadToByteOptions {
8
8
  /**
9
9
  * @static
10
10
  */
11
- export default class UPLCFlatUtils {
11
+ export declare class UPLCFlatUtils {
12
12
  /**
13
13
  * @deprecated this is a @static class, it is not supposed to have instances
14
14
  */
@@ -1,6 +1,6 @@
1
1
  import { BitStream } from "@harmoniclabs/bitstream";
2
- import BitUtils from "../BitUtils/index.js";
3
2
  import { assert } from "../assert.js";
3
+ import { BitUtils } from "../BitUtils/index.js";
4
4
  export function isInByteOffset(offset) {
5
5
  return (offset === 0 ||
6
6
  offset === 1 ||
@@ -14,7 +14,7 @@ export function isInByteOffset(offset) {
14
14
  /**
15
15
  * @static
16
16
  */
17
- export default class UPLCFlatUtils {
17
+ export class UPLCFlatUtils {
18
18
  /**
19
19
  * @deprecated this is a @static class, it is not supposed to have instances
20
20
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@harmoniclabs/pebble",
3
- "version": "0.1.0-dev7",
3
+ "version": "0.1.0-dev8",
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",
@@ -52,14 +52,14 @@
52
52
  "dependencies": {
53
53
  "@harmoniclabs/bigint-utils": "^1.0.0",
54
54
  "@harmoniclabs/bytestring": "^1.0.0",
55
- "@harmoniclabs/cbor": "^1.6.0",
56
- "@harmoniclabs/crypto": "^0.2.5",
55
+ "@harmoniclabs/cbor": "^1.6.6",
56
+ "@harmoniclabs/crypto": "^0.3.0",
57
57
  "@harmoniclabs/obj-utils": "^1.0.0",
58
58
  "@harmoniclabs/pair": "^1.0.0",
59
- "@harmoniclabs/plutus-data": "^1.2.4",
60
- "@harmoniclabs/plutus-machine": "^2.1.0",
59
+ "@harmoniclabs/plutus-data": "^1.2.6",
60
+ "@harmoniclabs/plutus-machine": "^2.1.1",
61
61
  "@harmoniclabs/uint8array-utils": "^1.0.4",
62
- "@harmoniclabs/uplc": "^1.4.0"
62
+ "@harmoniclabs/uplc": "^1.4.1"
63
63
  },
64
64
  "devDependencies": {
65
65
  "@babel/preset-env": "^7.18.6",