cashc 0.13.0-next.8 → 0.13.0
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/README.md +2 -2
- package/dist/artifact/Artifact.js +1 -1
- package/dist/ast/AST.d.ts +1 -0
- package/dist/ast/AST.js +2 -0
- package/dist/ast/AstBuilder.d.ts +2 -1
- package/dist/ast/AstBuilder.js +7 -3
- package/dist/generation/GenerateTargetTraversal.js +25 -10
- package/dist/grammar/CashScriptParser.d.ts +37 -29
- package/dist/grammar/CashScriptParser.js +527 -477
- package/dist/grammar/CashScriptVisitor.d.ts +7 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/semantic/EnsureFinalRequireTraversal.js +9 -11
- package/dist/semantic/InjectLocktimeGuardTraversal.js +23 -12
- package/dist/semantic/TypeCheckTraversal.js +11 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -36,7 +36,7 @@ Options:
|
|
|
36
36
|
-c, --opcount Display the number of opcodes in the compiled bytecode.
|
|
37
37
|
-s, --size Display the size in bytes of the compiled bytecode.
|
|
38
38
|
-S, --skip-enforce-function-parameter-types Do not enforce function parameter types.
|
|
39
|
-
-
|
|
40
|
-
|
|
39
|
+
-L, --skip-enforce-locktime-guard Do not inject a tx.time guard when tx.locktime is used.
|
|
40
|
+
-f, --format <format> Specify the format of the output. (choices: "json", "ts", default: "json")
|
|
41
41
|
-?, --help Display help
|
|
42
42
|
```
|
|
@@ -18,6 +18,7 @@ export function generateArtifact(ast, script, source, debug, compilerOptions, fi
|
|
|
18
18
|
abi,
|
|
19
19
|
bytecode,
|
|
20
20
|
source,
|
|
21
|
+
fingerprint,
|
|
21
22
|
debug,
|
|
22
23
|
compiler: {
|
|
23
24
|
name: 'cashc',
|
|
@@ -25,7 +26,6 @@ export function generateArtifact(ast, script, source, debug, compilerOptions, fi
|
|
|
25
26
|
options: compilerOptions,
|
|
26
27
|
},
|
|
27
28
|
updatedAt: new Date().toISOString(),
|
|
28
|
-
fingerprint,
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
31
|
// strip verbose debug info from artifact for production use
|
package/dist/ast/AST.d.ts
CHANGED
|
@@ -86,6 +86,7 @@ export declare class TimeOpNode extends NonControlStatementNode {
|
|
|
86
86
|
timeOp: TimeOp;
|
|
87
87
|
expression: ExpressionNode;
|
|
88
88
|
message?: string | undefined;
|
|
89
|
+
isGuard: boolean;
|
|
89
90
|
constructor(timeOp: TimeOp, expression: ExpressionNode, message?: string | undefined);
|
|
90
91
|
accept<T>(visitor: AstVisitor<T>): T;
|
|
91
92
|
}
|
package/dist/ast/AST.js
CHANGED
|
@@ -91,6 +91,8 @@ export class TimeOpNode extends NonControlStatementNode {
|
|
|
91
91
|
this.timeOp = timeOp;
|
|
92
92
|
this.expression = expression;
|
|
93
93
|
this.message = message;
|
|
94
|
+
// True for the compiler-injected `tx.locktime` guard (no user source); see InjectLocktimeGuardTraversal.
|
|
95
|
+
this.isGuard = false;
|
|
94
96
|
}
|
|
95
97
|
accept(visitor) {
|
|
96
98
|
return visitor.visitTimeOp(this);
|
package/dist/ast/AstBuilder.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ParseTree, ParseTreeVisitor } from 'antlr4';
|
|
2
2
|
import { Node, SourceFileNode, ContractNode, ParameterNode, VariableDefinitionNode, FunctionDefinitionNode, AssignNode, IdentifierNode, BranchNode, CastNode, FunctionCallNode, UnaryOpNode, BinaryOpNode, BoolLiteralNode, IntLiteralNode, HexLiteralNode, StringLiteralNode, ExpressionNode, StatementNode, LiteralNode, BlockNode, TimeOpNode, ArrayNode, TupleIndexOpNode, RequireNode, InstantiationNode, TupleAssignmentNode, NullaryOpNode, ConsoleStatementNode, ConsoleParameterNode, SliceNode, DoWhileNode, WhileNode, ForNode } from './AST.js';
|
|
3
|
-
import type { ContractDefinitionContext, FunctionDefinitionContext, VariableDefinitionContext, TupleAssignmentContext, ParameterContext, AssignStatementContext, IfStatementContext, FunctionCallContext, CastContext, LiteralContext, SourceFileContext, BlockContext, TimeOpStatementContext, ArrayContext, ParenthesisedContext, FunctionCallExpressionContext, UnaryOpContext, BinaryOpContext, IdentifierContext, LiteralExpressionContext, TupleIndexOpContext, RequireStatementContext, PragmaDirectiveContext, InstantiationContext, NullaryOpContext, UnaryIntrospectionOpContext, ConsoleStatementContext, ConsoleParameterContext, StatementContext, NonControlStatementContext, ControlStatementContext, RequireMessageContext, SliceContext, DoWhileStatementContext, LoopStatementContext, WhileStatementContext, ForStatementContext, ForInitContext } from '../grammar/CashScriptParser.js';
|
|
3
|
+
import type { ContractDefinitionContext, FunctionDefinitionContext, VariableDefinitionContext, TupleAssignmentContext, ParameterContext, AssignStatementContext, IfStatementContext, FunctionCallContext, CastContext, LiteralContext, SourceFileContext, BlockContext, TimeOpStatementContext, ArrayContext, ParenthesisedContext, FunctionCallExpressionContext, UnaryOpContext, BinaryOpContext, IdentifierContext, LiteralExpressionContext, TupleIndexOpContext, RequireStatementContext, PragmaDirectiveContext, InstantiationContext, NullaryOpContext, UnaryIntrospectionOpContext, ConsoleStatementContext, ConsoleParameterContext, StatementContext, NonControlStatementContext, ControlStatementContext, RequireMessageContext, SliceContext, DoWhileStatementContext, LoopStatementContext, WhileStatementContext, ForStatementContext, ForInitContext, FunctionBodyContext } from '../grammar/CashScriptParser.js';
|
|
4
4
|
import CashScriptVisitor from '../grammar/CashScriptVisitor.js';
|
|
5
5
|
export default class AstBuilder extends ParseTreeVisitor<Node> implements CashScriptVisitor<Node> {
|
|
6
6
|
private tree;
|
|
@@ -11,6 +11,7 @@ export default class AstBuilder extends ParseTreeVisitor<Node> implements CashSc
|
|
|
11
11
|
processPragma(ctx: PragmaDirectiveContext): void;
|
|
12
12
|
visitContractDefinition(ctx: ContractDefinitionContext): ContractNode;
|
|
13
13
|
visitFunctionDefinition(ctx: FunctionDefinitionContext): FunctionDefinitionNode;
|
|
14
|
+
visitFunctionBody(ctx: FunctionBodyContext): BlockNode;
|
|
14
15
|
visitParameter(ctx: ParameterContext): ParameterNode;
|
|
15
16
|
visitStatement(ctx: StatementContext): StatementNode;
|
|
16
17
|
visitNonControlStatement(ctx: NonControlStatementContext): StatementNode;
|
package/dist/ast/AstBuilder.js
CHANGED
|
@@ -54,12 +54,16 @@ export default class AstBuilder extends ParseTreeVisitor {
|
|
|
54
54
|
visitFunctionDefinition(ctx) {
|
|
55
55
|
const name = ctx.Identifier().getText();
|
|
56
56
|
const parameters = ctx.parameterList().parameter_list().map((p) => this.visit(p));
|
|
57
|
+
const body = this.visit(ctx.functionBody());
|
|
58
|
+
const functionDefinition = new FunctionDefinitionNode(name, parameters, body);
|
|
59
|
+
functionDefinition.location = Location.fromCtx(ctx);
|
|
60
|
+
return functionDefinition;
|
|
61
|
+
}
|
|
62
|
+
visitFunctionBody(ctx) {
|
|
57
63
|
const statements = ctx.statement_list().map((s) => this.visit(s));
|
|
58
64
|
const block = new BlockNode(statements);
|
|
59
65
|
block.location = Location.fromCtx(ctx);
|
|
60
|
-
|
|
61
|
-
functionDefinition.location = Location.fromCtx(ctx);
|
|
62
|
-
return functionDefinition;
|
|
66
|
+
return block;
|
|
63
67
|
}
|
|
64
68
|
visitParameter(ctx) {
|
|
65
69
|
const type = parseType(ctx.typeName().getText());
|
|
@@ -163,25 +163,31 @@ export default class GenerateTargetTraversalWithLocation extends AstTraversal {
|
|
|
163
163
|
enforceFunctionParameterType(node) {
|
|
164
164
|
if (!this.shouldEnforceFunctionParameterType(node))
|
|
165
165
|
return;
|
|
166
|
+
const tagStartIndex = this.output.length;
|
|
166
167
|
const stackIndex = this.getStackIndex(node.name);
|
|
168
|
+
// We take the parameter from the stack and roll it to the top
|
|
167
169
|
this.emit(encodeInt(BigInt(stackIndex)), { location: node.location, positionHint: PositionHint.START });
|
|
170
|
+
this.emit(Op.OP_ROLL, { location: node.location, positionHint: PositionHint.START });
|
|
171
|
+
// We remove the original stack value and push the new value to the top of the stack
|
|
172
|
+
this.removeFromStack(stackIndex);
|
|
173
|
+
this.pushToStack(node.name);
|
|
174
|
+
// For booleans, we force-convert it to a boolean using OP_0NOTEQUAL
|
|
168
175
|
if (node.type === PrimitiveType.BOOL) {
|
|
169
|
-
// For booleans, we take it from the stack and force-convert it to a boolean using OP_0NOTEQUAL
|
|
170
|
-
this.emit(Op.OP_ROLL, { location: node.location, positionHint: PositionHint.START });
|
|
171
176
|
this.emit(Op.OP_0NOTEQUAL, { location: node.location, positionHint: PositionHint.START });
|
|
172
|
-
// We remove the original stack value and push the new boolean value to the top of the stack
|
|
173
|
-
this.removeFromStack(stackIndex);
|
|
174
|
-
this.pushToStack(node.name);
|
|
175
177
|
}
|
|
178
|
+
// For bounded bytes, we *check* that it is the correct size using OP_SIZE and OP_EQUALVERIFY
|
|
176
179
|
if (node.type instanceof BytesType && node.type.bound !== undefined) {
|
|
177
|
-
// For bounded bytes, we copy it from the stack and *check* that it is the correct size
|
|
178
|
-
this.emit(Op.OP_PICK, { location: node.location, positionHint: PositionHint.START });
|
|
179
180
|
this.emit(Op.OP_SIZE, { location: node.location, positionHint: PositionHint.START });
|
|
180
181
|
this.emit(encodeInt(BigInt(node.type.bound)), { location: node.location, positionHint: PositionHint.START });
|
|
181
182
|
this.emit(Op.OP_EQUALVERIFY, { location: node.location, positionHint: PositionHint.START });
|
|
182
|
-
this.emit(Op.OP_DROP, { location: node.location, positionHint: PositionHint.START });
|
|
183
|
-
// We don't perform any stack operations, because these ops leave the original stack unchanged
|
|
184
183
|
}
|
|
184
|
+
// These checks are compiler-injected (no user source); tag them so the debug reconstruction
|
|
185
|
+
// gives them their own annotation line positioned by bytecode order.
|
|
186
|
+
this.sourceTags.push({
|
|
187
|
+
startIndex: tagStartIndex,
|
|
188
|
+
endIndex: this.output.length - 1,
|
|
189
|
+
kind: SourceTagKind.PARAMETER_VALIDATION,
|
|
190
|
+
});
|
|
185
191
|
}
|
|
186
192
|
shouldEnforceFunctionParameterType(node) {
|
|
187
193
|
if (node.type === PrimitiveType.BOOL)
|
|
@@ -237,7 +243,7 @@ export default class GenerateTargetTraversalWithLocation extends AstTraversal {
|
|
|
237
243
|
}
|
|
238
244
|
}
|
|
239
245
|
visitTimeOp(node) {
|
|
240
|
-
|
|
246
|
+
const tagStartIndex = this.output.length;
|
|
241
247
|
node.expression = this.visit(node.expression);
|
|
242
248
|
this.emit(compileTimeOp(node.timeOp), { location: node.location, positionHint: PositionHint.END });
|
|
243
249
|
this.requires.push({
|
|
@@ -247,6 +253,15 @@ export default class GenerateTargetTraversalWithLocation extends AstTraversal {
|
|
|
247
253
|
line: node.location.start.line,
|
|
248
254
|
message: node.message,
|
|
249
255
|
});
|
|
256
|
+
// The auto-injected tx.locktime guard is emitted after the parameter prologue but has no
|
|
257
|
+
// user source; tag it so the debug reconstruction positions it by bytecode order.
|
|
258
|
+
if (node.isGuard) {
|
|
259
|
+
this.sourceTags.push({
|
|
260
|
+
startIndex: tagStartIndex,
|
|
261
|
+
endIndex: this.output.length - 1,
|
|
262
|
+
kind: SourceTagKind.LOCKTIME_GUARD,
|
|
263
|
+
});
|
|
264
|
+
}
|
|
250
265
|
this.popFromStack();
|
|
251
266
|
return node;
|
|
252
267
|
}
|
|
@@ -91,35 +91,36 @@ export default class CashScriptParser extends Parser {
|
|
|
91
91
|
static readonly RULE_versionOperator = 5;
|
|
92
92
|
static readonly RULE_contractDefinition = 6;
|
|
93
93
|
static readonly RULE_functionDefinition = 7;
|
|
94
|
-
static readonly
|
|
95
|
-
static readonly
|
|
96
|
-
static readonly
|
|
97
|
-
static readonly
|
|
98
|
-
static readonly
|
|
99
|
-
static readonly
|
|
100
|
-
static readonly
|
|
101
|
-
static readonly
|
|
102
|
-
static readonly
|
|
103
|
-
static readonly
|
|
104
|
-
static readonly
|
|
105
|
-
static readonly
|
|
106
|
-
static readonly
|
|
107
|
-
static readonly
|
|
108
|
-
static readonly
|
|
109
|
-
static readonly
|
|
110
|
-
static readonly
|
|
111
|
-
static readonly
|
|
112
|
-
static readonly
|
|
113
|
-
static readonly
|
|
114
|
-
static readonly
|
|
115
|
-
static readonly
|
|
116
|
-
static readonly
|
|
117
|
-
static readonly
|
|
118
|
-
static readonly
|
|
119
|
-
static readonly
|
|
120
|
-
static readonly
|
|
121
|
-
static readonly
|
|
122
|
-
static readonly
|
|
94
|
+
static readonly RULE_functionBody = 8;
|
|
95
|
+
static readonly RULE_parameterList = 9;
|
|
96
|
+
static readonly RULE_parameter = 10;
|
|
97
|
+
static readonly RULE_block = 11;
|
|
98
|
+
static readonly RULE_statement = 12;
|
|
99
|
+
static readonly RULE_nonControlStatement = 13;
|
|
100
|
+
static readonly RULE_controlStatement = 14;
|
|
101
|
+
static readonly RULE_variableDefinition = 15;
|
|
102
|
+
static readonly RULE_tupleAssignment = 16;
|
|
103
|
+
static readonly RULE_assignStatement = 17;
|
|
104
|
+
static readonly RULE_timeOpStatement = 18;
|
|
105
|
+
static readonly RULE_requireStatement = 19;
|
|
106
|
+
static readonly RULE_consoleStatement = 20;
|
|
107
|
+
static readonly RULE_ifStatement = 21;
|
|
108
|
+
static readonly RULE_loopStatement = 22;
|
|
109
|
+
static readonly RULE_doWhileStatement = 23;
|
|
110
|
+
static readonly RULE_whileStatement = 24;
|
|
111
|
+
static readonly RULE_forStatement = 25;
|
|
112
|
+
static readonly RULE_forInit = 26;
|
|
113
|
+
static readonly RULE_requireMessage = 27;
|
|
114
|
+
static readonly RULE_consoleParameter = 28;
|
|
115
|
+
static readonly RULE_consoleParameterList = 29;
|
|
116
|
+
static readonly RULE_functionCall = 30;
|
|
117
|
+
static readonly RULE_expressionList = 31;
|
|
118
|
+
static readonly RULE_expression = 32;
|
|
119
|
+
static readonly RULE_modifier = 33;
|
|
120
|
+
static readonly RULE_literal = 34;
|
|
121
|
+
static readonly RULE_numberLiteral = 35;
|
|
122
|
+
static readonly RULE_typeName = 36;
|
|
123
|
+
static readonly RULE_typeCast = 37;
|
|
123
124
|
static readonly literalNames: (string | null)[];
|
|
124
125
|
static readonly symbolicNames: (string | null)[];
|
|
125
126
|
static readonly ruleNames: string[];
|
|
@@ -138,6 +139,7 @@ export default class CashScriptParser extends Parser {
|
|
|
138
139
|
versionOperator(): VersionOperatorContext;
|
|
139
140
|
contractDefinition(): ContractDefinitionContext;
|
|
140
141
|
functionDefinition(): FunctionDefinitionContext;
|
|
142
|
+
functionBody(): FunctionBodyContext;
|
|
141
143
|
parameterList(): ParameterListContext;
|
|
142
144
|
parameter(): ParameterContext;
|
|
143
145
|
block(): BlockContext;
|
|
@@ -228,6 +230,12 @@ export declare class FunctionDefinitionContext extends ParserRuleContext {
|
|
|
228
230
|
constructor(parser?: CashScriptParser, parent?: ParserRuleContext, invokingState?: number);
|
|
229
231
|
Identifier(): TerminalNode;
|
|
230
232
|
parameterList(): ParameterListContext;
|
|
233
|
+
functionBody(): FunctionBodyContext;
|
|
234
|
+
get ruleIndex(): number;
|
|
235
|
+
accept<Result>(visitor: CashScriptVisitor<Result>): Result;
|
|
236
|
+
}
|
|
237
|
+
export declare class FunctionBodyContext extends ParserRuleContext {
|
|
238
|
+
constructor(parser?: CashScriptParser, parent?: ParserRuleContext, invokingState?: number);
|
|
231
239
|
statement_list(): StatementContext[];
|
|
232
240
|
statement(i: number): StatementContext;
|
|
233
241
|
get ruleIndex(): number;
|