@harmoniclabs/pebble 0.1.3-dev1 → 0.1.3-dev3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/IR/tree_utils/intToUtf8Bytes.d.ts +8 -0
- package/dist/IR/tree_utils/intToUtf8Bytes.js +49 -0
- package/dist/ast/nodes/statements/PebbleStmt.d.ts +2 -1
- package/dist/ast/nodes/statements/PebbleStmt.js +2 -0
- package/dist/ast/nodes/statements/TraceStmt.d.ts +11 -0
- package/dist/ast/nodes/statements/TraceStmt.js +10 -0
- package/dist/compiler/AstCompiler/AstCompiler.d.ts +11 -0
- package/dist/compiler/AstCompiler/AstCompiler.js +185 -0
- package/dist/compiler/AstCompiler/internal/_deriveContractBody/_deriveContractBody.js +8 -0
- package/dist/compiler/AstCompiler/internal/statements/_compileStatement.js +4 -0
- package/dist/compiler/AstCompiler/internal/statements/_compileTraceStmt.d.ts +4 -0
- package/dist/compiler/AstCompiler/internal/statements/_compileTraceStmt.js +15 -0
- package/dist/compiler/Compiler.d.ts +5 -0
- package/dist/compiler/Compiler.js +25 -1
- package/dist/compiler/TirCompiler/expressify/determineReassignedVariablesAndReturn.js +5 -3
- package/dist/compiler/TirCompiler/expressify/expressify.js +8 -0
- package/dist/compiler/TirCompiler/expressify/expressifyIfBranch.js +2 -0
- package/dist/compiler/TirCompiler/expressify/expressifyVars.js +10 -1
- package/dist/compiler/tir/expressions/TirExpr.d.ts +2 -1
- package/dist/compiler/tir/expressions/TirExpr.js +2 -0
- package/dist/compiler/tir/expressions/TirTraceExpr.d.ts +22 -0
- package/dist/compiler/tir/expressions/TirTraceExpr.js +53 -0
- package/dist/compiler/tir/expressions/TirTypeConversionExpr.js +6 -0
- package/dist/compiler/tir/statements/TirStmt.d.ts +2 -1
- package/dist/compiler/tir/statements/TirStmt.js +2 -0
- package/dist/compiler/tir/statements/TirTraceStmt.d.ts +15 -0
- package/dist/compiler/tir/statements/TirTraceStmt.js +20 -0
- package/dist/parser/Parser.d.ts +2 -0
- package/dist/parser/Parser.js +15 -0
- package/dist/tokenizer/Token.d.ts +82 -81
- package/dist/tokenizer/Token.js +82 -81
- package/dist/tokenizer/utils/tokenFromKeyword.js +2 -0
- package/dist/utils/array/keepSortedArrInplace.js +15 -0
- package/package.json +1 -1
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { IRHoisted } from "../IRNodes/IRHoisted.js";
|
|
2
|
+
/**
|
|
3
|
+
* Hoisted IR term: `int -> bytes`
|
|
4
|
+
*
|
|
5
|
+
* Converts an integer to its decimal UTF-8 byte representation.
|
|
6
|
+
* Handles negative numbers by prepending '-' (0x2d).
|
|
7
|
+
*/
|
|
8
|
+
export declare const hoisted_intToUtf8Bytes: IRHoisted;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { IRApp, _ir_apps } from "../IRNodes/IRApp.js";
|
|
2
|
+
import { IRConst } from "../IRNodes/IRConst.js";
|
|
3
|
+
import { IRFunc } from "../IRNodes/IRFunc.js";
|
|
4
|
+
import { IRHoisted } from "../IRNodes/IRHoisted.js";
|
|
5
|
+
import { IRNative } from "../IRNodes/IRNative/index.js";
|
|
6
|
+
import { IRRecursive } from "../IRNodes/IRRecursive.js";
|
|
7
|
+
import { IRSelfCall } from "../IRNodes/IRSelfCall.js";
|
|
8
|
+
import { IRVar } from "../IRNodes/IRVar.js";
|
|
9
|
+
import { _ir_lazyIfThenElse } from "./_ir_lazyIfThenElse.js";
|
|
10
|
+
// digitToBytes(n) = consByteString( addInteger(n, 48), #"" )
|
|
11
|
+
// positiveIntToBs = fix \self \n ->
|
|
12
|
+
// ifThenElse (lessThanInteger n 10)
|
|
13
|
+
// (consByteString (addInteger n 48) #"")
|
|
14
|
+
// (appendByteString (self (divideInteger n 10)) (consByteString (addInteger (modInteger n 10) 48) #""))
|
|
15
|
+
// intToUtf8Bytes(n) =
|
|
16
|
+
// ifThenElse (lessThanEqualInteger 0 n)
|
|
17
|
+
// (positiveIntToBs n)
|
|
18
|
+
// (appendByteString (consByteString 45 #"") (positiveIntToBs (subtractInteger 0 n)))
|
|
19
|
+
const self_sym = Symbol("intToUtf8Bytes_self");
|
|
20
|
+
const n_sym = Symbol("intToUtf8Bytes_n");
|
|
21
|
+
const outer_n_sym = Symbol("intToUtf8Bytes_outer_n");
|
|
22
|
+
const emptyBs = IRConst.bytes(new Uint8Array(0));
|
|
23
|
+
function digitToBytes(n) {
|
|
24
|
+
return _ir_apps(IRNative.consByteString, _ir_apps(IRNative.addInteger, n, IRConst.int(48)), emptyBs.clone());
|
|
25
|
+
}
|
|
26
|
+
const hoisted_positiveIntToBs = new IRHoisted(new IRRecursive(self_sym, new IRFunc([n_sym], _ir_lazyIfThenElse(
|
|
27
|
+
// condition: n < 10
|
|
28
|
+
_ir_apps(IRNative.lessThanInteger, new IRVar(n_sym), IRConst.int(10)),
|
|
29
|
+
// then: digitToBytes(n)
|
|
30
|
+
digitToBytes(new IRVar(n_sym)),
|
|
31
|
+
// else: appendByteString( self(n / 10), digitToBytes(n % 10) )
|
|
32
|
+
_ir_apps(IRNative.appendByteString, new IRApp(new IRSelfCall(self_sym), _ir_apps(IRNative.divideInteger, new IRVar(n_sym), IRConst.int(10))), digitToBytes(_ir_apps(IRNative.modInteger, new IRVar(n_sym), IRConst.int(10))))))));
|
|
33
|
+
hoisted_positiveIntToBs.hash;
|
|
34
|
+
/**
|
|
35
|
+
* Hoisted IR term: `int -> bytes`
|
|
36
|
+
*
|
|
37
|
+
* Converts an integer to its decimal UTF-8 byte representation.
|
|
38
|
+
* Handles negative numbers by prepending '-' (0x2d).
|
|
39
|
+
*/
|
|
40
|
+
export const hoisted_intToUtf8Bytes = new IRHoisted(new IRFunc([outer_n_sym], _ir_lazyIfThenElse(
|
|
41
|
+
// condition: 0 <= n
|
|
42
|
+
_ir_apps(IRNative.lessThanEqualInteger, IRConst.int(0), new IRVar(outer_n_sym)),
|
|
43
|
+
// then: positiveIntToBs(n)
|
|
44
|
+
_ir_apps(hoisted_positiveIntToBs.clone(), new IRVar(outer_n_sym)),
|
|
45
|
+
// else: appendByteString( consByteString(45, #""), positiveIntToBs(0 - n) )
|
|
46
|
+
_ir_apps(IRNative.appendByteString,
|
|
47
|
+
// "-" as bytes
|
|
48
|
+
_ir_apps(IRNative.consByteString, IRConst.int(45), emptyBs.clone()), _ir_apps(hoisted_positiveIntToBs.clone(), _ir_apps(IRNative.subtractInteger, IRConst.int(0), new IRVar(outer_n_sym)))))));
|
|
49
|
+
hoisted_intToUtf8Bytes.hash;
|
|
@@ -24,7 +24,8 @@ import { FuncDecl } from "./declarations/FuncDecl.js";
|
|
|
24
24
|
import { ExportStmt } from "./ExportStmt.js";
|
|
25
25
|
import { InterfaceDecl } from "./declarations/InterfaceDecl.js";
|
|
26
26
|
import { ContractDecl } from "./declarations/ContractDecl.js";
|
|
27
|
+
import { TraceStmt } from "./TraceStmt.js";
|
|
27
28
|
export type TopLevelStmt = EmptyStmt | VarStmt | PebbleTypeDecl | InterfaceDecl | FuncDecl | TestStmt | ExportStmt | ExportStarStmt | ExportImportStmt | ImportStmt | ImportStarStmt | TypeImplementsStmt | UsingStmt | ContractDecl;
|
|
28
29
|
export declare function isTopLevelStmt(stmt: any): stmt is TopLevelStmt;
|
|
29
|
-
export type BodyStmt = IfStmt | VarStmt | ForStmt | ForOfStmt | WhileStmt | ReturnStmt | BlockStmt | BreakStmt | ContinueStmt | EmptyStmt | FailStmt | AssertStmt | MatchStmt | AssignmentStmt | UsingStmt;
|
|
30
|
+
export type BodyStmt = IfStmt | VarStmt | ForStmt | ForOfStmt | WhileStmt | ReturnStmt | BlockStmt | BreakStmt | ContinueStmt | EmptyStmt | FailStmt | AssertStmt | TraceStmt | MatchStmt | AssignmentStmt | UsingStmt;
|
|
30
31
|
export declare function isBodyStmt(stmt: any): stmt is BodyStmt;
|
|
@@ -26,6 +26,7 @@ import { UsingStmt } from "./UsingStmt.js";
|
|
|
26
26
|
import { FuncDecl } from "./declarations/FuncDecl.js";
|
|
27
27
|
import { ExportStmt } from "./ExportStmt.js";
|
|
28
28
|
import { ContractDecl } from "./declarations/ContractDecl.js";
|
|
29
|
+
import { TraceStmt } from "./TraceStmt.js";
|
|
29
30
|
export function isTopLevelStmt(stmt) {
|
|
30
31
|
return (stmt instanceof EmptyStmt
|
|
31
32
|
|| stmt instanceof VarStmt
|
|
@@ -55,6 +56,7 @@ export function isBodyStmt(stmt) {
|
|
|
55
56
|
|| stmt instanceof EmptyStmt
|
|
56
57
|
|| stmt instanceof FailStmt
|
|
57
58
|
|| stmt instanceof AssertStmt
|
|
59
|
+
|| stmt instanceof TraceStmt
|
|
58
60
|
|| stmt instanceof MatchStmt
|
|
59
61
|
|| isAssignmentStmt(stmt)
|
|
60
62
|
// || stmt instanceof ExprStmt
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { SourceRange } from "../../Source/SourceRange.js";
|
|
2
|
+
import { PebbleExpr } from "../expr/PebbleExpr.js";
|
|
3
|
+
import { HasSourceRange } from "../HasSourceRange.js";
|
|
4
|
+
export declare class TraceStmt implements HasSourceRange {
|
|
5
|
+
/** expression to trace (must be string) */
|
|
6
|
+
expr: PebbleExpr;
|
|
7
|
+
readonly range: SourceRange;
|
|
8
|
+
constructor(
|
|
9
|
+
/** expression to trace (must be string) */
|
|
10
|
+
expr: PebbleExpr, range: SourceRange);
|
|
11
|
+
}
|
|
@@ -43,6 +43,17 @@ export declare class AstCompiler extends DiagnosticEmitter {
|
|
|
43
43
|
constructor(cfg: CompilerOptions, io?: CompilerIoApi, diagnostics?: DiagnosticMessage[]);
|
|
44
44
|
private _isExporting;
|
|
45
45
|
export(funcName: string, modulePath?: string): Promise<TypedProgram>;
|
|
46
|
+
/**
|
|
47
|
+
* Parses the entry file, wraps all top-level statements
|
|
48
|
+
* (except functions, contracts, type declarations, imports, and exports)
|
|
49
|
+
* into a synthetic function, then compiles via export.
|
|
50
|
+
*
|
|
51
|
+
* The wrapping is done at the source text level (before parsing)
|
|
52
|
+
* so that statements which are not parseable at the top level
|
|
53
|
+
* (e.g. for loops, assignments, trace calls) become valid
|
|
54
|
+
* inside a function body.
|
|
55
|
+
*/
|
|
56
|
+
run(): Promise<TypedProgram>;
|
|
46
57
|
/**
|
|
47
58
|
* compiles the entry file specified in the config
|
|
48
59
|
*
|
|
@@ -104,6 +104,38 @@ export class AstCompiler extends DiagnosticEmitter {
|
|
|
104
104
|
this.program.contractTirFuncName = funcName;
|
|
105
105
|
return await this.compile();
|
|
106
106
|
}
|
|
107
|
+
/**
|
|
108
|
+
* Parses the entry file, wraps all top-level statements
|
|
109
|
+
* (except functions, contracts, type declarations, imports, and exports)
|
|
110
|
+
* into a synthetic function, then compiles via export.
|
|
111
|
+
*
|
|
112
|
+
* The wrapping is done at the source text level (before parsing)
|
|
113
|
+
* so that statements which are not parseable at the top level
|
|
114
|
+
* (e.g. for loops, assignments, trace calls) become valid
|
|
115
|
+
* inside a function body.
|
|
116
|
+
*/
|
|
117
|
+
async run() {
|
|
118
|
+
const RUN_FUNC_NAME = "__pebble_run__";
|
|
119
|
+
this._isExporting = true;
|
|
120
|
+
this.program.contractTirFuncName = RUN_FUNC_NAME;
|
|
121
|
+
const filePath = this.cfg.entry;
|
|
122
|
+
if (!filePath) {
|
|
123
|
+
this.error(DiagnosticCode.File_0_not_found, undefined, this.cfg.entry);
|
|
124
|
+
throw new Error("entry file not found");
|
|
125
|
+
}
|
|
126
|
+
if (!this.io.exsistSync(filePath))
|
|
127
|
+
throw new Error("AstCompiler.run: entry file does not exist: " + filePath);
|
|
128
|
+
const src = await this.getAbsoulteProjPathSource(filePath);
|
|
129
|
+
if (!src)
|
|
130
|
+
throw new Error("AstCompiler.run: could not read source: " + filePath);
|
|
131
|
+
// 1) Rewrite the source text: wrap non-declaration statements in a function
|
|
132
|
+
src.text = _wrapSourceTextForRun(src.text, RUN_FUNC_NAME);
|
|
133
|
+
// update range to match the new text length
|
|
134
|
+
src.range.end = src.text.length;
|
|
135
|
+
// 2) Use the normal compilation pipeline (parse + semantic analysis)
|
|
136
|
+
// which now sees the entry source as having a top-level function
|
|
137
|
+
return await this.compile();
|
|
138
|
+
}
|
|
107
139
|
/**
|
|
108
140
|
* compiles the entry file specified in the config
|
|
109
141
|
*
|
|
@@ -676,3 +708,156 @@ function isImportStmtLike(stmt) {
|
|
|
676
708
|
|| stmt instanceof ImportStarStmt
|
|
677
709
|
|| stmt instanceof ExportStarStmt);
|
|
678
710
|
}
|
|
711
|
+
/** Keywords that start a top-level declaration (kept outside the run wrapper). */
|
|
712
|
+
const _declKeywords = new Set([
|
|
713
|
+
"import",
|
|
714
|
+
"export",
|
|
715
|
+
"function",
|
|
716
|
+
"struct",
|
|
717
|
+
"enum",
|
|
718
|
+
"type",
|
|
719
|
+
"interface",
|
|
720
|
+
"contract",
|
|
721
|
+
"data",
|
|
722
|
+
"runtime",
|
|
723
|
+
]);
|
|
724
|
+
/**
|
|
725
|
+
* Splits source text into declaration blocks and body blocks
|
|
726
|
+
* using a simple character scanner, then wraps body blocks
|
|
727
|
+
* in a `function <funcName>(): void { ... }`.
|
|
728
|
+
*
|
|
729
|
+
* Declaration keywords (import, export, function, struct, enum, type, interface,
|
|
730
|
+
* contract, data, runtime) are recognized at the start of each top-level statement
|
|
731
|
+
* and kept outside the wrapper. Everything else goes inside the wrapper function.
|
|
732
|
+
*/
|
|
733
|
+
function _wrapSourceTextForRun(text, funcName) {
|
|
734
|
+
const len = text.length;
|
|
735
|
+
const ranges = [];
|
|
736
|
+
let pos = 0;
|
|
737
|
+
while (pos < len) {
|
|
738
|
+
// skip whitespace
|
|
739
|
+
while (pos < len && _isWhitespace(text.charCodeAt(pos)))
|
|
740
|
+
pos++;
|
|
741
|
+
if (pos >= len)
|
|
742
|
+
break;
|
|
743
|
+
const stmtStart = pos;
|
|
744
|
+
// read the first word to determine if this is a declaration
|
|
745
|
+
const word = _readWord(text, pos);
|
|
746
|
+
const isDecl = _declKeywords.has(word);
|
|
747
|
+
// find the end of this statement:
|
|
748
|
+
// track brace/paren depth, respect strings and comments
|
|
749
|
+
let braceDepth = 0;
|
|
750
|
+
let parenDepth = 0;
|
|
751
|
+
let ended = false;
|
|
752
|
+
while (pos < len && !ended) {
|
|
753
|
+
const ch = text.charCodeAt(pos);
|
|
754
|
+
// single-line comment
|
|
755
|
+
if (ch === 0x2F /* / */ && pos + 1 < len && text.charCodeAt(pos + 1) === 0x2F /* / */) {
|
|
756
|
+
pos += 2;
|
|
757
|
+
while (pos < len && text.charCodeAt(pos) !== 0x0A /* \n */)
|
|
758
|
+
pos++;
|
|
759
|
+
continue;
|
|
760
|
+
}
|
|
761
|
+
// multi-line comment
|
|
762
|
+
if (ch === 0x2F /* / */ && pos + 1 < len && text.charCodeAt(pos + 1) === 0x2A /* * */) {
|
|
763
|
+
pos += 2;
|
|
764
|
+
while (pos < len && !(text.charCodeAt(pos) === 0x2A && pos + 1 < len && text.charCodeAt(pos + 1) === 0x2F))
|
|
765
|
+
pos++;
|
|
766
|
+
pos += 2; // skip */
|
|
767
|
+
continue;
|
|
768
|
+
}
|
|
769
|
+
// string literals
|
|
770
|
+
if (ch === 0x22 /* " */ || ch === 0x27 /* ' */ || ch === 0x60 /* ` */) {
|
|
771
|
+
pos++;
|
|
772
|
+
while (pos < len) {
|
|
773
|
+
const sc = text.charCodeAt(pos);
|
|
774
|
+
if (sc === 0x5C /* \ */) {
|
|
775
|
+
pos += 2;
|
|
776
|
+
continue;
|
|
777
|
+
} // escaped char
|
|
778
|
+
if (sc === ch) {
|
|
779
|
+
pos++;
|
|
780
|
+
break;
|
|
781
|
+
}
|
|
782
|
+
pos++;
|
|
783
|
+
}
|
|
784
|
+
continue;
|
|
785
|
+
}
|
|
786
|
+
if (ch === 0x28 /* ( */) {
|
|
787
|
+
parenDepth++;
|
|
788
|
+
pos++;
|
|
789
|
+
}
|
|
790
|
+
else if (ch === 0x29 /* ) */) {
|
|
791
|
+
parenDepth--;
|
|
792
|
+
pos++;
|
|
793
|
+
}
|
|
794
|
+
else if (ch === 0x7B /* { */) {
|
|
795
|
+
braceDepth++;
|
|
796
|
+
pos++;
|
|
797
|
+
}
|
|
798
|
+
else if (ch === 0x7D /* } */) {
|
|
799
|
+
braceDepth--;
|
|
800
|
+
pos++;
|
|
801
|
+
if (braceDepth <= 0 && parenDepth <= 0) {
|
|
802
|
+
// consume optional trailing semicolon
|
|
803
|
+
let p2 = pos;
|
|
804
|
+
while (p2 < len && _isWhitespace(text.charCodeAt(p2)))
|
|
805
|
+
p2++;
|
|
806
|
+
if (p2 < len && text.charCodeAt(p2) === 0x3B /* ; */)
|
|
807
|
+
pos = p2 + 1;
|
|
808
|
+
ended = true;
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
else if (ch === 0x3B /* ; */ && braceDepth === 0 && parenDepth === 0) {
|
|
812
|
+
pos++;
|
|
813
|
+
ended = true;
|
|
814
|
+
}
|
|
815
|
+
else {
|
|
816
|
+
pos++;
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
const stmtEnd = pos;
|
|
820
|
+
// skip empty ranges
|
|
821
|
+
if (stmtEnd > stmtStart) {
|
|
822
|
+
ranges.push({ start: stmtStart, end: stmtEnd, isDecl });
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
// If there are no body ranges, nothing to wrap
|
|
826
|
+
if (ranges.every(r => r.isDecl)) {
|
|
827
|
+
return text;
|
|
828
|
+
}
|
|
829
|
+
// Build the new source text
|
|
830
|
+
const declarations = [];
|
|
831
|
+
const bodyParts = [];
|
|
832
|
+
for (const r of ranges) {
|
|
833
|
+
const slice = text.substring(r.start, r.end);
|
|
834
|
+
if (r.isDecl)
|
|
835
|
+
declarations.push(slice);
|
|
836
|
+
else
|
|
837
|
+
bodyParts.push(slice);
|
|
838
|
+
}
|
|
839
|
+
return (declarations.join("\n") +
|
|
840
|
+
(declarations.length > 0 ? "\n" : "") +
|
|
841
|
+
"function " + funcName + "(): void {\n" +
|
|
842
|
+
bodyParts.join("\n") + "\n" +
|
|
843
|
+
"}\n");
|
|
844
|
+
}
|
|
845
|
+
function _isWhitespace(ch) {
|
|
846
|
+
return ch === 0x20 || ch === 0x09 || ch === 0x0A || ch === 0x0D;
|
|
847
|
+
}
|
|
848
|
+
function _readWord(text, pos) {
|
|
849
|
+
const start = pos;
|
|
850
|
+
const len = text.length;
|
|
851
|
+
while (pos < len) {
|
|
852
|
+
const ch = text.charCodeAt(pos);
|
|
853
|
+
if ((ch >= 0x61 && ch <= 0x7A) || // a-z
|
|
854
|
+
(ch >= 0x41 && ch <= 0x5A) || // A-Z
|
|
855
|
+
(ch >= 0x30 && ch <= 0x39) || // 0-9
|
|
856
|
+
ch === 0x5F // _
|
|
857
|
+
)
|
|
858
|
+
pos++;
|
|
859
|
+
else
|
|
860
|
+
break;
|
|
861
|
+
}
|
|
862
|
+
return text.substring(start, pos);
|
|
863
|
+
}
|
|
@@ -40,6 +40,7 @@ import { ForStmt } from "../../../../ast/nodes/statements/ForStmt.js";
|
|
|
40
40
|
import { IfStmt } from "../../../../ast/nodes/statements/IfStmt.js";
|
|
41
41
|
import { MatchStmtCase, MatchStmt, MatchStmtElseCase } from "../../../../ast/nodes/statements/MatchStmt.js";
|
|
42
42
|
import { ReturnStmt } from "../../../../ast/nodes/statements/ReturnStmt.js";
|
|
43
|
+
import { TraceStmt } from "../../../../ast/nodes/statements/TraceStmt.js";
|
|
43
44
|
import { UsingStmt } from "../../../../ast/nodes/statements/UsingStmt.js";
|
|
44
45
|
import { VarStmt } from "../../../../ast/nodes/statements/VarStmt.js";
|
|
45
46
|
import { WhileStmt } from "../../../../ast/nodes/statements/WhileStmt.js";
|
|
@@ -589,6 +590,13 @@ function _getMatchedRedeemerBlockStatements(compiler, stmts, paramsInternalNames
|
|
|
589
590
|
stmt.body = new BlockStmt(nextBodyStmts, stmt.body.range);
|
|
590
591
|
continue;
|
|
591
592
|
}
|
|
593
|
+
if (stmt instanceof TraceStmt) {
|
|
594
|
+
const newExpr = _exprReplaceParamsAndAssertNoLitContext(compiler, stmt.expr, paramsInternalNamesMap, renamedVariables);
|
|
595
|
+
if (!newExpr)
|
|
596
|
+
return undefined;
|
|
597
|
+
stmt.expr = newExpr;
|
|
598
|
+
continue;
|
|
599
|
+
}
|
|
592
600
|
const tsEnsureExhaustiveCheck = stmt;
|
|
593
601
|
console.error(stmt);
|
|
594
602
|
throw new Error("unreachable::_getMatchedRedeemerBlockStatements::stmt::");
|
|
@@ -6,6 +6,7 @@ import { ContinueStmt } from "../../../../ast/nodes/statements/ContinueStmt.js";
|
|
|
6
6
|
import { isVarDecl } from "../../../../ast/nodes/statements/declarations/VarDecl/VarDecl.js";
|
|
7
7
|
import { EmptyStmt } from "../../../../ast/nodes/statements/EmptyStmt.js";
|
|
8
8
|
import { FailStmt } from "../../../../ast/nodes/statements/FailStmt.js";
|
|
9
|
+
import { TraceStmt } from "../../../../ast/nodes/statements/TraceStmt.js";
|
|
9
10
|
import { ForOfStmt } from "../../../../ast/nodes/statements/ForOfStmt.js";
|
|
10
11
|
import { ForStmt } from "../../../../ast/nodes/statements/ForStmt.js";
|
|
11
12
|
import { IfStmt } from "../../../../ast/nodes/statements/IfStmt.js";
|
|
@@ -20,6 +21,7 @@ import { _compileBlockStmt } from "./_compileBlockStmt.js";
|
|
|
20
21
|
import { _compileBreakStmt } from "./_compileBreakStmt.js";
|
|
21
22
|
import { _compileContinueStmt } from "./_compileContinueStmt.js";
|
|
22
23
|
import { _compileFailStmt } from "./_compileFailStmt.js";
|
|
24
|
+
import { _compileTraceStmt } from "./_compileTraceStmt.js";
|
|
23
25
|
import { _compileForOfStmt } from "./_compileForOfStmt.js";
|
|
24
26
|
import { _compileForStmt } from "./_compileForStmt.js";
|
|
25
27
|
import { _compileIfStmt } from "./_compileIfStmt.js";
|
|
@@ -62,6 +64,8 @@ export function _compileStatement(ctx, stmt) {
|
|
|
62
64
|
return _compileFailStmt(ctx, stmt);
|
|
63
65
|
if (stmt instanceof AssertStmt)
|
|
64
66
|
return _compileAssertStmt(ctx, stmt);
|
|
67
|
+
if (stmt instanceof TraceStmt)
|
|
68
|
+
return _compileTraceStmt(ctx, stmt);
|
|
65
69
|
// if( stmt instanceof TestStmt ) return _compileTestStmt( ctx, stmt );
|
|
66
70
|
if (stmt instanceof MatchStmt)
|
|
67
71
|
return _compileMatchStmt(ctx, stmt);
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { TraceStmt } from "../../../../ast/nodes/statements/TraceStmt.js";
|
|
2
|
+
import { TirTraceStmt } from "../../../tir/statements/TirTraceStmt.js";
|
|
3
|
+
import { AstCompilationCtx } from "../../AstCompilationCtx.js";
|
|
4
|
+
export declare function _compileTraceStmt(ctx: AstCompilationCtx, stmt: TraceStmt): [TirTraceStmt] | undefined;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { DiagnosticCode } from "../../../../diagnostics/diagnosticMessages.generated.js";
|
|
2
|
+
import { TirTraceStmt } from "../../../tir/statements/TirTraceStmt.js";
|
|
3
|
+
import { canAssignTo } from "../../../tir/types/utils/canAssignTo.js";
|
|
4
|
+
import { _compileExpr } from "../exprs/_compileExpr.js";
|
|
5
|
+
export function _compileTraceStmt(ctx, stmt) {
|
|
6
|
+
const bytes_t = ctx.program.stdTypes.bytes;
|
|
7
|
+
const int_t = ctx.program.stdTypes.int;
|
|
8
|
+
let expr = _compileExpr(ctx, stmt.expr, undefined);
|
|
9
|
+
if (!expr)
|
|
10
|
+
return undefined;
|
|
11
|
+
if (!canAssignTo(expr.type, bytes_t) &&
|
|
12
|
+
!canAssignTo(expr.type, int_t))
|
|
13
|
+
return ctx.error(DiagnosticCode.Type_0_is_not_assignable_to_type_1, stmt.expr.range, expr.type.toString(), "bytes | int");
|
|
14
|
+
return [new TirTraceStmt(expr, stmt.range)];
|
|
15
|
+
}
|
|
@@ -8,6 +8,11 @@ export declare class Compiler extends DiagnosticEmitter {
|
|
|
8
8
|
constructor(io?: CompilerIoApi, cfg?: CompilerOptions, diagnostics?: DiagnosticMessage[]);
|
|
9
9
|
compile(config?: Partial<CompilerOptions>): Promise<Uint8Array>;
|
|
10
10
|
export(config: Partial<ExportOptions> & HasFuncitonName): Promise<Uint8Array>;
|
|
11
|
+
run(config?: Partial<CompilerOptions>): Promise<{
|
|
12
|
+
result: import("@harmoniclabs/plutus-machine").CEKValueObj;
|
|
13
|
+
budgetSpent: import("@harmoniclabs/plutus-machine").ExBudget;
|
|
14
|
+
logs: string[];
|
|
15
|
+
}>;
|
|
11
16
|
private _compileBackend;
|
|
12
17
|
}
|
|
13
18
|
interface HasFuncitonName {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { compileUPLC, UPLCProgram } from "@harmoniclabs/uplc";
|
|
1
|
+
import { compileUPLC, parseUPLC, UPLCProgram } from "@harmoniclabs/uplc";
|
|
2
|
+
import { Machine } from "@harmoniclabs/plutus-machine";
|
|
2
3
|
import { DiagnosticEmitter } from "../diagnostics/DiagnosticEmitter.js";
|
|
3
4
|
import { defaultOptions } from "../IR/toUPLC/CompilerOptions.js";
|
|
4
5
|
import { AstCompiler } from "./AstCompiler/AstCompiler.js";
|
|
@@ -60,6 +61,29 @@ export class Compiler extends DiagnosticEmitter {
|
|
|
60
61
|
}
|
|
61
62
|
return this._compileBackend(cfg, program);
|
|
62
63
|
}
|
|
64
|
+
async run(config) {
|
|
65
|
+
const cfg = {
|
|
66
|
+
...this.cfg,
|
|
67
|
+
...config,
|
|
68
|
+
// NEVER generate markers when running
|
|
69
|
+
addMarker: false,
|
|
70
|
+
};
|
|
71
|
+
const astCompiler = new AstCompiler(cfg, this.io, this.diagnostics);
|
|
72
|
+
const program = await astCompiler.run();
|
|
73
|
+
if (this.diagnostics.length > 0) {
|
|
74
|
+
let msg;
|
|
75
|
+
globalThis.console && console.log(this.diagnostics);
|
|
76
|
+
const fstErrorMsg = this.diagnostics[0].toString();
|
|
77
|
+
const nDiags = this.diagnostics.length;
|
|
78
|
+
while (msg = this.diagnostics.shift()) {
|
|
79
|
+
this.io.stdout.write(msg.toString() + "\n");
|
|
80
|
+
}
|
|
81
|
+
throw new Error("compilation failed with " + nDiags + " diagnostic messages; first message: " + fstErrorMsg);
|
|
82
|
+
}
|
|
83
|
+
const serialized = this._compileBackend(cfg, program);
|
|
84
|
+
const uplcProgram = parseUPLC(serialized);
|
|
85
|
+
return Machine.eval(uplcProgram.body);
|
|
86
|
+
}
|
|
63
87
|
_compileBackend(cfg, program) {
|
|
64
88
|
// backend starts here
|
|
65
89
|
const ir = compileTypedProgram(cfg, program);
|
|
@@ -9,6 +9,7 @@ import { TirBlockStmt } from "../../tir/statements/TirBlockStmt.js";
|
|
|
9
9
|
import { TirBreakStmt } from "../../tir/statements/TirBreakStmt.js";
|
|
10
10
|
import { TirContinueStmt } from "../../tir/statements/TirContinueStmt.js";
|
|
11
11
|
import { TirFailStmt } from "../../tir/statements/TirFailStmt.js";
|
|
12
|
+
import { TirTraceStmt } from "../../tir/statements/TirTraceStmt.js";
|
|
12
13
|
import { TirForOfStmt } from "../../tir/statements/TirForOfStmt.js";
|
|
13
14
|
import { TirForStmt } from "../../tir/statements/TirForStmt.js";
|
|
14
15
|
import { TirIfStmt } from "../../tir/statements/TirIfStmt.js";
|
|
@@ -25,6 +26,7 @@ export function determineReassignedVariablesAndReturn(stmt) {
|
|
|
25
26
|
let returns = false;
|
|
26
27
|
while (stmt = stack.pop()) {
|
|
27
28
|
if (stmt instanceof TirFailStmt
|
|
29
|
+
|| stmt instanceof TirTraceStmt
|
|
28
30
|
|| isTirVarDecl(stmt)
|
|
29
31
|
|| stmt instanceof TirBreakStmt
|
|
30
32
|
|| stmt instanceof TirContinueStmt
|
|
@@ -84,9 +86,8 @@ export function determineReassignedVariablesAndFlowInfos(stmt) {
|
|
|
84
86
|
let canContinue = false;
|
|
85
87
|
while (stmt = stack.pop()) {
|
|
86
88
|
if (stmt instanceof TirFailStmt
|
|
89
|
+
|| stmt instanceof TirTraceStmt
|
|
87
90
|
|| isTirVarDecl(stmt)
|
|
88
|
-
|| stmt instanceof TirBreakStmt
|
|
89
|
-
|| stmt instanceof TirContinueStmt
|
|
90
91
|
|| stmt instanceof TirAssertStmt)
|
|
91
92
|
continue;
|
|
92
93
|
if (stmt instanceof TirBreakStmt) {
|
|
@@ -193,7 +194,8 @@ export function definitelyFails(stmt) {
|
|
|
193
194
|
|| stmt instanceof TirBreakStmt
|
|
194
195
|
|| stmt instanceof TirContinueStmt
|
|
195
196
|
|| stmt instanceof TirAssertStmt
|
|
196
|
-
|| stmt instanceof TirAssignmentStmt
|
|
197
|
+
|| stmt instanceof TirAssignmentStmt
|
|
198
|
+
|| stmt instanceof TirTraceStmt)
|
|
197
199
|
continue;
|
|
198
200
|
// const tsEnsureExsaustiveCheck: never = stmt;
|
|
199
201
|
}
|
|
@@ -3,6 +3,7 @@ import { getUniqueInternalName } from "../../internalVar.js";
|
|
|
3
3
|
import { TirLitVoidExpr } from "../../tir/expressions/litteral/TirLitVoidExpr.js";
|
|
4
4
|
import { TirCaseExpr, TirCaseMatcher, TirWildcardCaseMatcher } from "../../tir/expressions/TirCaseExpr.js";
|
|
5
5
|
import { TirFailExpr } from "../../tir/expressions/TirFailExpr.js";
|
|
6
|
+
import { TirTraceExpr } from "../../tir/expressions/TirTraceExpr.js";
|
|
6
7
|
import { TirLettedExpr } from "../../tir/expressions/TirLettedExpr.js";
|
|
7
8
|
import { TirVariableAccessExpr } from "../../tir/expressions/TirVariableAccessExpr.js";
|
|
8
9
|
import { TirAssertStmt } from "../../tir/statements/TirAssertStmt.js";
|
|
@@ -11,6 +12,7 @@ import { TirBlockStmt } from "../../tir/statements/TirBlockStmt.js";
|
|
|
11
12
|
import { TirBreakStmt } from "../../tir/statements/TirBreakStmt.js";
|
|
12
13
|
import { TirContinueStmt } from "../../tir/statements/TirContinueStmt.js";
|
|
13
14
|
import { TirFailStmt } from "../../tir/statements/TirFailStmt.js";
|
|
15
|
+
import { TirTraceStmt } from "../../tir/statements/TirTraceStmt.js";
|
|
14
16
|
import { TirForOfStmt } from "../../tir/statements/TirForOfStmt.js";
|
|
15
17
|
import { TirForStmt } from "../../tir/statements/TirForStmt.js";
|
|
16
18
|
import { TirIfStmt } from "../../tir/statements/TirIfStmt.js";
|
|
@@ -217,6 +219,12 @@ loopReplacements, assertions = []) {
|
|
|
217
219
|
return TirAssertAndContinueExpr.fromStmtsAndContinuation(assertions, new TirFailExpr(undefined, ctx.returnType, stmt.range));
|
|
218
220
|
}
|
|
219
221
|
}
|
|
222
|
+
else if (stmt instanceof TirTraceStmt) {
|
|
223
|
+
const modifiedExpr = expressifyVars(ctx, stmt.expr);
|
|
224
|
+
stmt.expr = modifiedExpr;
|
|
225
|
+
const continuation = expressifyFuncBody(ctx, bodyStmts, loopReplacements);
|
|
226
|
+
return TirAssertAndContinueExpr.fromStmtsAndContinuation(assertions, new TirTraceExpr(modifiedExpr, continuation, stmt.range));
|
|
227
|
+
}
|
|
220
228
|
else if (stmt instanceof TirAssertStmt) {
|
|
221
229
|
const condition = expressifyVars(ctx, stmt.condition);
|
|
222
230
|
stmt.condition = condition;
|
|
@@ -8,6 +8,7 @@ import { TirBlockStmt } from "../../tir/statements/TirBlockStmt.js";
|
|
|
8
8
|
import { TirBreakStmt } from "../../tir/statements/TirBreakStmt.js";
|
|
9
9
|
import { TirContinueStmt } from "../../tir/statements/TirContinueStmt.js";
|
|
10
10
|
import { TirFailStmt } from "../../tir/statements/TirFailStmt.js";
|
|
11
|
+
import { TirTraceStmt } from "../../tir/statements/TirTraceStmt.js";
|
|
11
12
|
import { TirForOfStmt } from "../../tir/statements/TirForOfStmt.js";
|
|
12
13
|
import { TirForStmt } from "../../tir/statements/TirForStmt.js";
|
|
13
14
|
import { TirIfStmt } from "../../tir/statements/TirIfStmt.js";
|
|
@@ -60,6 +61,7 @@ function replaceReturnStatements(body, wrapReturnExpr, sopType) {
|
|
|
60
61
|
|| stmt instanceof TirBreakStmt
|
|
61
62
|
|| stmt instanceof TirContinueStmt
|
|
62
63
|
|| stmt instanceof TirFailStmt
|
|
64
|
+
|| stmt instanceof TirTraceStmt
|
|
63
65
|
|| stmt instanceof TirAssertStmt
|
|
64
66
|
|| stmt instanceof TirAssignmentStmt)
|
|
65
67
|
continue;
|
|
@@ -28,6 +28,7 @@ import { TirPropAccessExpr } from "../../tir/expressions/TirPropAccessExpr.js";
|
|
|
28
28
|
import { TirTernaryExpr } from "../../tir/expressions/TirTernaryExpr.js";
|
|
29
29
|
import { TirToDataExpr } from "../../tir/expressions/TirToDataExpr.js";
|
|
30
30
|
import { TirTraceIfFalseExpr } from "../../tir/expressions/TirTraceIfFalseExpr.js";
|
|
31
|
+
import { TirTraceExpr } from "../../tir/expressions/TirTraceExpr.js";
|
|
31
32
|
import { TirTypeConversionExpr } from "../../tir/expressions/TirTypeConversionExpr.js";
|
|
32
33
|
import { TirVariableAccessExpr } from "../../tir/expressions/TirVariableAccessExpr.js";
|
|
33
34
|
import { TirUnaryExclamation } from "../../tir/expressions/unary/TirUnaryExclamation.js";
|
|
@@ -212,6 +213,13 @@ export function expressifyVars(ctx, expr) {
|
|
|
212
213
|
expr.traceStrExpr = modifiedTraceStrExpr;
|
|
213
214
|
return expr;
|
|
214
215
|
}
|
|
216
|
+
if (expr instanceof TirTraceExpr) {
|
|
217
|
+
const modifiedTraceExpr = expressifyVars(ctx, expr.traceExpr);
|
|
218
|
+
const modifiedContinuation = expressifyVars(ctx, expr.continuation);
|
|
219
|
+
expr.traceExpr = modifiedTraceExpr;
|
|
220
|
+
expr.continuation = modifiedContinuation;
|
|
221
|
+
return expr;
|
|
222
|
+
}
|
|
215
223
|
if (expr instanceof TirInlineClosedIR)
|
|
216
224
|
return expr;
|
|
217
225
|
const tsEnsureExhautstiveCheck = expr;
|
|
@@ -243,9 +251,10 @@ function expressifyPropAccess(ctx, propAccessExpr) {
|
|
|
243
251
|
|| expr instanceof TirFuncExpr // functions have no properties
|
|
244
252
|
|| expr instanceof TirParentesizedExpr // typescript being stupid
|
|
245
253
|
|| isTirBinaryExpr(expr) // all of these return either int, bytes or boolean
|
|
246
|
-
// TirAssertAndContinueExpr | TirTraceIfFalseExpr | TirInlineClosedIR
|
|
254
|
+
// TirAssertAndContinueExpr | TirTraceIfFalseExpr | TirTraceExpr | TirInlineClosedIR
|
|
247
255
|
|| expr instanceof TirAssertAndContinueExpr
|
|
248
256
|
|| expr instanceof TirTraceIfFalseExpr
|
|
257
|
+
|| expr instanceof TirTraceExpr
|
|
249
258
|
|| expr instanceof TirInlineClosedIR)
|
|
250
259
|
throw new Error("Invalid property access expression");
|
|
251
260
|
if (expr instanceof TirLitThisExpr) {
|
|
@@ -17,7 +17,8 @@ import { TirHoistedExpr } from "./TirHoistedExpr.js";
|
|
|
17
17
|
import { TirToDataExpr } from "./TirToDataExpr.js";
|
|
18
18
|
import { TirAssertAndContinueExpr } from "./TirAssertAndContinueExpr.js";
|
|
19
19
|
import { TirTraceIfFalseExpr } from "./TirTraceIfFalseExpr.js";
|
|
20
|
+
import { TirTraceExpr } from "./TirTraceExpr.js";
|
|
20
21
|
import { TirNativeFunc } from "./TirNativeFunc.js";
|
|
21
22
|
import { TirInlineClosedIR } from "./TirInlineClosedIR.js";
|
|
22
|
-
export type TirExpr = (TirUnaryPrefixExpr | TirLitteralExpr | TirParentesizedExpr | TirFuncExpr | TirCallExpr | TirCaseExpr | TirTypeConversionExpr | TirElemAccessExpr | TirTernaryExpr | TirPropAccessExpr | TirBinaryExpr | TirVariableAccessExpr | TirLettedExpr | TirNativeFunc | TirFailExpr | TirHoistedExpr | TirFromDataExpr | TirToDataExpr | TirAssertAndContinueExpr | TirTraceIfFalseExpr | TirInlineClosedIR);
|
|
23
|
+
export type TirExpr = (TirUnaryPrefixExpr | TirLitteralExpr | TirParentesizedExpr | TirFuncExpr | TirCallExpr | TirCaseExpr | TirTypeConversionExpr | TirElemAccessExpr | TirTernaryExpr | TirPropAccessExpr | TirBinaryExpr | TirVariableAccessExpr | TirLettedExpr | TirNativeFunc | TirFailExpr | TirHoistedExpr | TirFromDataExpr | TirToDataExpr | TirAssertAndContinueExpr | TirTraceIfFalseExpr | TirTraceExpr | TirInlineClosedIR);
|
|
23
24
|
export declare function isTirExpr(thing: any): thing is TirExpr;
|
|
@@ -18,6 +18,7 @@ import { TirHoistedExpr } from "./TirHoistedExpr.js";
|
|
|
18
18
|
import { TirToDataExpr } from "./TirToDataExpr.js";
|
|
19
19
|
import { TirAssertAndContinueExpr } from "./TirAssertAndContinueExpr.js";
|
|
20
20
|
import { TirTraceIfFalseExpr } from "./TirTraceIfFalseExpr.js";
|
|
21
|
+
import { TirTraceExpr } from "./TirTraceExpr.js";
|
|
21
22
|
import { TirNativeFunc } from "./TirNativeFunc.js";
|
|
22
23
|
import { TirInlineClosedIR } from "./TirInlineClosedIR.js";
|
|
23
24
|
export function isTirExpr(thing) {
|
|
@@ -42,5 +43,6 @@ export function isTirExpr(thing) {
|
|
|
42
43
|
|| thing instanceof TirToDataExpr
|
|
43
44
|
|| thing instanceof TirAssertAndContinueExpr
|
|
44
45
|
|| thing instanceof TirTraceIfFalseExpr
|
|
46
|
+
|| thing instanceof TirTraceExpr
|
|
45
47
|
|| thing instanceof TirInlineClosedIR);
|
|
46
48
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { SourceRange } from "../../../ast/Source/SourceRange.js";
|
|
2
|
+
import type { IRTerm } from "../../../IR/IRTerm.js";
|
|
3
|
+
import { TirType } from "../types/TirType.js";
|
|
4
|
+
import { ITirExpr } from "./ITirExpr.js";
|
|
5
|
+
import { TirExpr } from "./TirExpr.js";
|
|
6
|
+
import { ToIRTermCtx } from "./ToIRTermCtx.js";
|
|
7
|
+
export declare class TirTraceExpr implements ITirExpr {
|
|
8
|
+
/** must be bytes or int (converted to string via decodeUtf8 in toIR) */
|
|
9
|
+
traceExpr: TirExpr;
|
|
10
|
+
continuation: TirExpr;
|
|
11
|
+
readonly range: SourceRange;
|
|
12
|
+
get type(): TirType;
|
|
13
|
+
constructor(
|
|
14
|
+
/** must be bytes or int (converted to string via decodeUtf8 in toIR) */
|
|
15
|
+
traceExpr: TirExpr, continuation: TirExpr, range: SourceRange);
|
|
16
|
+
toString(): string;
|
|
17
|
+
pretty(indent: number): string;
|
|
18
|
+
clone(): TirExpr;
|
|
19
|
+
deps(): string[];
|
|
20
|
+
get isConstant(): boolean;
|
|
21
|
+
toIR(ctx: ToIRTermCtx): IRTerm;
|
|
22
|
+
}
|