Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions packages/cashc/src/Errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
ContractNode,
SliceNode,
IntLiteralNode,
TupleAssignmentNode,
} from './ast/AST.js';
import { Symbol, SymbolType } from './ast/SymbolTable.js';
import { Location } from './ast/Location.js';
Expand Down Expand Up @@ -283,6 +284,15 @@ export class DivisionByZeroError extends CashScriptError {
}
}

export class DuplicateTupleTargetError extends CashScriptError {
constructor(
node: TupleAssignmentNode,
name: string,
) {
super(node, `Duplicate target '${name}' in tuple destructuring`);
}
}

export class ConstantModificationError extends CashScriptError {
constructor(node: VariableDefinitionNode | ConstantDefinitionNode);
constructor(node: Node, name: string);
Expand Down
6 changes: 3 additions & 3 deletions packages/cashc/src/ast/AST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,13 +155,13 @@ export class VariableDefinitionNode extends NonControlStatementNode implements N
}

export interface TupleAssignmentTarget {
name: string;
type: Type;
identifier: IdentifierNode;
type?: Type;
isReassignment?: boolean;
}

export class TupleAssignmentNode extends NonControlStatementNode {
constructor(
// TODO: Use IdentifierNodes instead of a custom type
public targets: TupleAssignmentTarget[],
public tuple: ExpressionNode,
) {
Expand Down
15 changes: 10 additions & 5 deletions packages/cashc/src/ast/AstBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,11 +249,16 @@ export default class AstBuilder

visitTupleAssignment(ctx: TupleAssignmentContext): TupleAssignmentNode {
const expression = this.visit(ctx.expression());
const types = ctx.typeName_list();
const targets = ctx.Identifier_list().map((name, i) => ({
name: name.getText(),
type: parseType(types[i].getText()),
}));
const targets = ctx.tupleTarget_list().map((target) => {
const typeName = target.typeName();
const identifier = new IdentifierNode(target.Identifier().getText());
identifier.location = Location.fromToken(target.Identifier().symbol);
return {
identifier,
type: typeName ? parseType(typeName.getText()) : undefined,
isReassignment: !typeName,
};
});
const tupleAssignment = new TupleAssignmentNode(targets, expression);
tupleAssignment.location = Location.fromCtx(ctx);
return tupleAssignment;
Expand Down
31 changes: 28 additions & 3 deletions packages/cashc/src/generation/GenerateTargetTraversal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -508,8 +508,34 @@ export default class GenerateTargetTraversal extends AstTraversal {

visitTupleAssignment(node: TupleAssignmentNode): Node {
node.tuple = this.visit(node.tuple);
this.popFromStack(node.targets.length);
node.targets.forEach((target) => this.pushToStack(target.name));

// Outside of a loop/branch, a reassignment is just a rename (the old value stays on the stack)
const scopedReassign = this.scopeDepth > 0 && node.targets.some((target) => target.isReassignment);
if (!scopedReassign) {
this.popFromStack(node.targets.length);
node.targets.forEach((target) => this.pushToStack(target.identifier.name));
return node;
}

const locationData = { location: node.location, positionHint: PositionHint.END };
const parkedDeclarations: string[] = [];

const reversedTargets = [...node.targets].reverse();
reversedTargets.forEach((target) => {
if (target.isReassignment) {
this.emitReplace(this.getStackIndex(target.identifier.name), node);
} else {
this.emit(Op.OP_TOALTSTACK, locationData);
parkedDeclarations.push(target.identifier.name);
}
this.popFromStack();
});

parkedDeclarations.reverse().forEach((name) => {
this.emit(Op.OP_FROMALTSTACK, locationData);
this.pushToStack(name);
});

return node;
}

Expand Down Expand Up @@ -1017,4 +1043,3 @@ export default class GenerateTargetTraversal extends AstTraversal {
return node;
}
}

12 changes: 9 additions & 3 deletions packages/cashc/src/grammar/CashScript.g4
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,13 @@ variableDefinition
;

tupleAssignment
: typeName Identifier (',' typeName Identifier)+ '=' expression
: tupleTarget (',' tupleTarget)+ '=' expression
| '(' tupleTarget (',' tupleTarget)+ ')' '=' expression
;

tupleTarget
: typeName Identifier
| Identifier
;

assignStatement
Expand Down Expand Up @@ -215,8 +221,8 @@ numberLiteral
;

typeName
: PrimitiveType
| BoundedBytes
: PrimitiveType
| BoundedBytes
| UnboundedBytes
;

Expand Down
3 changes: 2 additions & 1 deletion packages/cashc/src/grammar/CashScript.interp

Large diffs are not rendered by default.

Loading
Loading