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 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
- -f, --format <format> Specify the format of the output. (choices: "json", "ts", default:
40
- "json")
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);
@@ -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;
@@ -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
- const functionDefinition = new FunctionDefinitionNode(name, parameters, block);
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
- // const countBefore = this.output.length;
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 RULE_parameterList = 8;
95
- static readonly RULE_parameter = 9;
96
- static readonly RULE_block = 10;
97
- static readonly RULE_statement = 11;
98
- static readonly RULE_nonControlStatement = 12;
99
- static readonly RULE_controlStatement = 13;
100
- static readonly RULE_variableDefinition = 14;
101
- static readonly RULE_tupleAssignment = 15;
102
- static readonly RULE_assignStatement = 16;
103
- static readonly RULE_timeOpStatement = 17;
104
- static readonly RULE_requireStatement = 18;
105
- static readonly RULE_consoleStatement = 19;
106
- static readonly RULE_ifStatement = 20;
107
- static readonly RULE_loopStatement = 21;
108
- static readonly RULE_doWhileStatement = 22;
109
- static readonly RULE_whileStatement = 23;
110
- static readonly RULE_forStatement = 24;
111
- static readonly RULE_forInit = 25;
112
- static readonly RULE_requireMessage = 26;
113
- static readonly RULE_consoleParameter = 27;
114
- static readonly RULE_consoleParameterList = 28;
115
- static readonly RULE_functionCall = 29;
116
- static readonly RULE_expressionList = 30;
117
- static readonly RULE_expression = 31;
118
- static readonly RULE_modifier = 32;
119
- static readonly RULE_literal = 33;
120
- static readonly RULE_numberLiteral = 34;
121
- static readonly RULE_typeName = 35;
122
- static readonly RULE_typeCast = 36;
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;