From aca545e727d8d3ebe3f90d132703542c9de87ad0 Mon Sep 17 00:00:00 2001 From: Rosco Kalis Date: Tue, 14 Jul 2026 11:47:16 +0200 Subject: [PATCH 01/12] Add unused modifier support to cashc --- packages/cashc/src/Errors.ts | 2 + packages/cashc/src/ast/AstBuilder.ts | 3 +- packages/cashc/src/ast/Globals.ts | 1 + packages/cashc/src/ast/SymbolTable.ts | 2 + .../src/generation/GenerateTargetTraversal.ts | 31 +- packages/cashc/src/grammar/CashScript.g4 | 3 +- packages/cashc/src/grammar/CashScript.interp | 4 +- packages/cashc/src/grammar/CashScript.tokens | 44 +- .../cashc/src/grammar/CashScriptLexer.interp | 5 +- .../cashc/src/grammar/CashScriptLexer.tokens | 44 +- packages/cashc/src/grammar/CashScriptLexer.ts | 662 +++++++------ .../cashc/src/grammar/CashScriptParser.ts | 935 +++++++++--------- .../src/print/OutputSourceCodeTraversal.ts | 6 +- .../src/semantic/SymbolTableTraversal.ts | 38 +- .../constant_on_contract_parameter.cash | 5 + .../constant_on_function_parameter.cash | 5 + .../duplicate_modifier.cash | 5 + .../reference_unused_parameter.cash | 5 + .../unused_global_function_local.cash | 2 +- .../test/compiler/unused-modifier.test.ts | 197 ++++ .../cashc/test/global-definitions.test.ts | 6 +- .../valid-contract-files/unused_modifier.cash | 7 + website/docs/compiler/grammar.md | 3 +- website/docs/language/contracts.md | 20 +- 24 files changed, 1200 insertions(+), 835 deletions(-) create mode 100644 packages/cashc/test/compiler/InvalidModifierError/constant_on_contract_parameter.cash create mode 100644 packages/cashc/test/compiler/InvalidModifierError/constant_on_function_parameter.cash create mode 100644 packages/cashc/test/compiler/InvalidModifierError/duplicate_modifier.cash create mode 100644 packages/cashc/test/compiler/InvalidModifierError/reference_unused_parameter.cash create mode 100644 packages/cashc/test/compiler/unused-modifier.test.ts create mode 100644 packages/cashc/test/valid-contract-files/unused_modifier.cash diff --git a/packages/cashc/src/Errors.ts b/packages/cashc/src/Errors.ts index 04bf0808..adac9f44 100644 --- a/packages/cashc/src/Errors.ts +++ b/packages/cashc/src/Errors.ts @@ -275,6 +275,8 @@ export class ConstantModificationError extends CashScriptError { } } +export class InvalidModifierError extends CashScriptError { } + export class ArrayElementError extends CashScriptError { constructor( node: ArrayNode, diff --git a/packages/cashc/src/ast/AstBuilder.ts b/packages/cashc/src/ast/AstBuilder.ts index 07a7e99d..890f09c8 100644 --- a/packages/cashc/src/ast/AstBuilder.ts +++ b/packages/cashc/src/ast/AstBuilder.ts @@ -209,8 +209,9 @@ export default class AstBuilder visitParameter(ctx: ParameterContext): ParameterNode { const type = parseType(ctx.typeName().getText()); + const modifiers = ctx.modifier_list().map((modifier) => modifier.getText()); const name = ctx.Identifier().getText(); - const parameter = new ParameterNode(type, [], name); + const parameter = new ParameterNode(type, modifiers, name); parameter.location = Location.fromCtx(ctx); return parameter; } diff --git a/packages/cashc/src/ast/Globals.ts b/packages/cashc/src/ast/Globals.ts index 878475c6..70c7b429 100644 --- a/packages/cashc/src/ast/Globals.ts +++ b/packages/cashc/src/ast/Globals.ts @@ -44,6 +44,7 @@ export enum Class { export enum Modifier { CONSTANT = 'constant', + UNUSED = 'unused', } export const GLOBAL_SYMBOL_TABLE = new SymbolTable(); diff --git a/packages/cashc/src/ast/SymbolTable.ts b/packages/cashc/src/ast/SymbolTable.ts index 38baee7f..535d6a81 100644 --- a/packages/cashc/src/ast/SymbolTable.ts +++ b/packages/cashc/src/ast/SymbolTable.ts @@ -12,6 +12,7 @@ import { functionReturnType } from '../utils.js'; export class Symbol { references: IdentifierNode[] = []; inlinedFrame?: DebugFrame; + ignoreUnused: boolean = false; private constructor( public name: string, @@ -99,6 +100,7 @@ export class SymbolTable { unusedSymbols(): Symbol[] { return Array.from(this.symbols) .map((e) => e[1]) + .filter((s) => !s.ignoreUnused) .filter((s) => s.references.length === 0); } } diff --git a/packages/cashc/src/generation/GenerateTargetTraversal.ts b/packages/cashc/src/generation/GenerateTargetTraversal.ts index f283c0ca..9c8d0c0f 100644 --- a/packages/cashc/src/generation/GenerateTargetTraversal.ts +++ b/packages/cashc/src/generation/GenerateTargetTraversal.ts @@ -63,7 +63,7 @@ import { ForNode, } from '../ast/AST.js'; import AstTraversal from '../ast/AstTraversal.js'; -import { GlobalFunction, Class } from '../ast/Globals.js'; +import { GlobalFunction, Class, Modifier } from '../ast/Globals.js'; import { BinaryOperator } from '../ast/Operator.js'; import { compileBinaryOp, @@ -252,6 +252,7 @@ export default class GenerateTargetTraversal extends AstTraversal { for (let i = node.parameters.length - 1; i >= 0; i -= 1) { bodyTraversal.visit(node.parameters[i]); } + bodyTraversal.dropUnusedParameters(node.parameters); bodyTraversal.visit(node.body); bodyTraversal.cleanGlobalFunctionStack(node); @@ -301,6 +302,7 @@ export default class GenerateTargetTraversal extends AstTraversal { // Keep track of constructor parameter count for instructor pointer calculation this.constructorParameterCount = node.parameters.length; + this.dropUnusedParameters(node.parameters); if (node.functions.length === 1) { node.functions = this.visitList(node.functions) as FunctionDefinitionNode[]; @@ -356,6 +358,7 @@ export default class GenerateTargetTraversal extends AstTraversal { this.currentFunction = node; node.parameters = this.visitList(node.parameters) as ParameterNode[]; + this.dropUnusedParameters(node.parameters); if (this.compilerOptions.enforceFunctionParameterTypes) { this.enforceFunctionParameterTypes(node); @@ -423,6 +426,24 @@ export default class GenerateTargetTraversal extends AstTraversal { this.tagScopeCleanup(tagStartIndex); } + private dropUnusedParameters(parameters: ParameterNode[]): void { + parameters + .filter((parameter) => parameter.modifiers.includes(Modifier.UNUSED)) + .sort((a, b) => this.getStackIndex(a.name) - this.getStackIndex(b.name)) + .forEach((parameter) => { + const stackIndex = this.getStackIndex(parameter.name); + const locationData = { location: parameter.location, positionHint: PositionHint.START }; + + if (stackIndex > 0) { + this.emit(encodeInt(BigInt(stackIndex)), locationData); + this.emit(Op.OP_ROLL, locationData); + } + + this.emit(Op.OP_DROP, locationData); + this.removeFromStack(stackIndex); + }); + } + enforceFunctionParameterTypes(node: FunctionDefinitionNode): void { node.parameters.forEach((parameter) => this.enforceFunctionParameterType(parameter)); } @@ -463,6 +484,7 @@ export default class GenerateTargetTraversal extends AstTraversal { } shouldEnforceFunctionParameterType(node: ParameterNode): boolean { + if (node.modifiers.includes(Modifier.UNUSED)) return false; if (node.type === PrimitiveType.BOOL) return true; if (node.type instanceof BytesType && node.type.bound !== undefined) return true; return false; @@ -475,6 +497,13 @@ export default class GenerateTargetTraversal extends AstTraversal { visitVariableDefinition(node: VariableDefinitionNode): Node { node.expression = this.visit(node.expression); + + if (node.modifiers.includes(Modifier.UNUSED)) { + this.emit(Op.OP_DROP, { location: node.location, positionHint: PositionHint.END }); + this.popFromStack(); + return node; + } + this.popFromStack(); this.pushToStack(node.name); return node; diff --git a/packages/cashc/src/grammar/CashScript.g4 b/packages/cashc/src/grammar/CashScript.g4 index d3733ca9..0cd133ee 100644 --- a/packages/cashc/src/grammar/CashScript.g4 +++ b/packages/cashc/src/grammar/CashScript.g4 @@ -59,7 +59,7 @@ parameterList ; parameter - : typeName Identifier + : typeName modifier* Identifier ; block @@ -199,6 +199,7 @@ expression modifier : 'constant' + | 'unused' ; literal diff --git a/packages/cashc/src/grammar/CashScript.interp b/packages/cashc/src/grammar/CashScript.interp index ddd92038..35c314a3 100644 --- a/packages/cashc/src/grammar/CashScript.interp +++ b/packages/cashc/src/grammar/CashScript.interp @@ -64,6 +64,7 @@ null '|' '&&' '||' +'unused' null null null @@ -151,6 +152,7 @@ null null null null +null VersionLiteral BooleanLiteral NumberUnit @@ -220,4 +222,4 @@ typeCast atn: -[4, 1, 84, 509, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 1, 0, 5, 0, 90, 8, 0, 10, 0, 12, 0, 93, 9, 0, 1, 0, 5, 0, 96, 8, 0, 10, 0, 12, 0, 99, 9, 0, 1, 0, 5, 0, 102, 8, 0, 10, 0, 12, 0, 105, 9, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 3, 3, 3, 118, 8, 3, 1, 4, 3, 4, 121, 8, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 3, 7, 134, 8, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 5, 8, 144, 8, 8, 10, 8, 12, 8, 147, 9, 8, 1, 8, 1, 8, 3, 8, 151, 8, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 5, 10, 167, 8, 10, 10, 10, 12, 10, 170, 9, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 5, 12, 181, 8, 12, 10, 12, 12, 12, 184, 9, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 5, 13, 192, 8, 13, 10, 13, 12, 13, 195, 9, 13, 1, 13, 3, 13, 198, 8, 13, 3, 13, 200, 8, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 5, 15, 209, 8, 15, 10, 15, 12, 15, 212, 9, 15, 1, 15, 1, 15, 3, 15, 216, 8, 15, 1, 16, 1, 16, 1, 16, 1, 16, 3, 16, 222, 8, 16, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 3, 17, 232, 8, 17, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 19, 5, 19, 240, 8, 19, 10, 19, 12, 19, 243, 9, 19, 1, 20, 1, 20, 3, 20, 247, 8, 20, 1, 21, 1, 21, 5, 21, 251, 8, 21, 10, 21, 12, 21, 254, 9, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 4, 22, 266, 8, 22, 11, 22, 12, 22, 267, 1, 22, 1, 22, 1, 22, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 3, 23, 278, 8, 23, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 3, 24, 287, 8, 24, 1, 24, 1, 24, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 3, 25, 296, 8, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 26, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 3, 27, 310, 8, 27, 1, 28, 1, 28, 1, 28, 3, 28, 315, 8, 28, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 3, 32, 343, 8, 32, 1, 33, 1, 33, 1, 34, 1, 34, 3, 34, 349, 8, 34, 1, 35, 1, 35, 1, 35, 1, 35, 5, 35, 355, 8, 35, 10, 35, 12, 35, 358, 9, 35, 1, 35, 3, 35, 361, 8, 35, 3, 35, 363, 8, 35, 1, 35, 1, 35, 1, 36, 1, 36, 1, 36, 1, 37, 1, 37, 1, 37, 1, 37, 5, 37, 374, 8, 37, 10, 37, 12, 37, 377, 9, 37, 1, 37, 3, 37, 380, 8, 37, 3, 37, 382, 8, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 3, 38, 395, 8, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 5, 38, 421, 8, 38, 10, 38, 12, 38, 424, 9, 38, 1, 38, 3, 38, 427, 8, 38, 3, 38, 429, 8, 38, 1, 38, 1, 38, 1, 38, 1, 38, 3, 38, 435, 8, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 5, 38, 487, 8, 38, 10, 38, 12, 38, 490, 9, 38, 1, 39, 1, 39, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 3, 40, 499, 8, 40, 1, 41, 1, 41, 3, 41, 503, 8, 41, 1, 42, 1, 42, 1, 43, 1, 43, 1, 43, 0, 1, 76, 44, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 0, 14, 1, 0, 4, 10, 2, 0, 10, 10, 22, 23, 1, 0, 24, 25, 1, 0, 37, 41, 2, 0, 37, 41, 43, 46, 2, 0, 5, 5, 51, 52, 1, 0, 53, 55, 2, 0, 52, 52, 56, 56, 1, 0, 57, 58, 1, 0, 6, 9, 1, 0, 59, 60, 1, 0, 47, 48, 1, 0, 71, 73, 2, 0, 71, 72, 79, 79, 539, 0, 91, 1, 0, 0, 0, 2, 108, 1, 0, 0, 0, 4, 113, 1, 0, 0, 0, 6, 115, 1, 0, 0, 0, 8, 120, 1, 0, 0, 0, 10, 124, 1, 0, 0, 0, 12, 126, 1, 0, 0, 0, 14, 133, 1, 0, 0, 0, 16, 135, 1, 0, 0, 0, 18, 154, 1, 0, 0, 0, 20, 161, 1, 0, 0, 0, 22, 173, 1, 0, 0, 0, 24, 178, 1, 0, 0, 0, 26, 187, 1, 0, 0, 0, 28, 203, 1, 0, 0, 0, 30, 215, 1, 0, 0, 0, 32, 221, 1, 0, 0, 0, 34, 231, 1, 0, 0, 0, 36, 233, 1, 0, 0, 0, 38, 235, 1, 0, 0, 0, 40, 246, 1, 0, 0, 0, 42, 248, 1, 0, 0, 0, 44, 259, 1, 0, 0, 0, 46, 277, 1, 0, 0, 0, 48, 279, 1, 0, 0, 0, 50, 290, 1, 0, 0, 0, 52, 299, 1, 0, 0, 0, 54, 302, 1, 0, 0, 0, 56, 314, 1, 0, 0, 0, 58, 316, 1, 0, 0, 0, 60, 324, 1, 0, 0, 0, 62, 330, 1, 0, 0, 0, 64, 342, 1, 0, 0, 0, 66, 344, 1, 0, 0, 0, 68, 348, 1, 0, 0, 0, 70, 350, 1, 0, 0, 0, 72, 366, 1, 0, 0, 0, 74, 369, 1, 0, 0, 0, 76, 434, 1, 0, 0, 0, 78, 491, 1, 0, 0, 0, 80, 498, 1, 0, 0, 0, 82, 500, 1, 0, 0, 0, 84, 504, 1, 0, 0, 0, 86, 506, 1, 0, 0, 0, 88, 90, 3, 2, 1, 0, 89, 88, 1, 0, 0, 0, 90, 93, 1, 0, 0, 0, 91, 89, 1, 0, 0, 0, 91, 92, 1, 0, 0, 0, 92, 97, 1, 0, 0, 0, 93, 91, 1, 0, 0, 0, 94, 96, 3, 12, 6, 0, 95, 94, 1, 0, 0, 0, 96, 99, 1, 0, 0, 0, 97, 95, 1, 0, 0, 0, 97, 98, 1, 0, 0, 0, 98, 103, 1, 0, 0, 0, 99, 97, 1, 0, 0, 0, 100, 102, 3, 14, 7, 0, 101, 100, 1, 0, 0, 0, 102, 105, 1, 0, 0, 0, 103, 101, 1, 0, 0, 0, 103, 104, 1, 0, 0, 0, 104, 106, 1, 0, 0, 0, 105, 103, 1, 0, 0, 0, 106, 107, 5, 0, 0, 1, 107, 1, 1, 0, 0, 0, 108, 109, 5, 1, 0, 0, 109, 110, 3, 4, 2, 0, 110, 111, 3, 6, 3, 0, 111, 112, 5, 2, 0, 0, 112, 3, 1, 0, 0, 0, 113, 114, 5, 3, 0, 0, 114, 5, 1, 0, 0, 0, 115, 117, 3, 8, 4, 0, 116, 118, 3, 8, 4, 0, 117, 116, 1, 0, 0, 0, 117, 118, 1, 0, 0, 0, 118, 7, 1, 0, 0, 0, 119, 121, 3, 10, 5, 0, 120, 119, 1, 0, 0, 0, 120, 121, 1, 0, 0, 0, 121, 122, 1, 0, 0, 0, 122, 123, 5, 65, 0, 0, 123, 9, 1, 0, 0, 0, 124, 125, 7, 0, 0, 0, 125, 11, 1, 0, 0, 0, 126, 127, 5, 11, 0, 0, 127, 128, 5, 75, 0, 0, 128, 129, 5, 2, 0, 0, 129, 13, 1, 0, 0, 0, 130, 134, 3, 16, 8, 0, 131, 134, 3, 18, 9, 0, 132, 134, 3, 20, 10, 0, 133, 130, 1, 0, 0, 0, 133, 131, 1, 0, 0, 0, 133, 132, 1, 0, 0, 0, 134, 15, 1, 0, 0, 0, 135, 136, 5, 12, 0, 0, 136, 137, 5, 81, 0, 0, 137, 150, 3, 26, 13, 0, 138, 139, 5, 13, 0, 0, 139, 140, 5, 14, 0, 0, 140, 145, 3, 84, 42, 0, 141, 142, 5, 15, 0, 0, 142, 144, 3, 84, 42, 0, 143, 141, 1, 0, 0, 0, 144, 147, 1, 0, 0, 0, 145, 143, 1, 0, 0, 0, 145, 146, 1, 0, 0, 0, 146, 148, 1, 0, 0, 0, 147, 145, 1, 0, 0, 0, 148, 149, 5, 16, 0, 0, 149, 151, 1, 0, 0, 0, 150, 138, 1, 0, 0, 0, 150, 151, 1, 0, 0, 0, 151, 152, 1, 0, 0, 0, 152, 153, 3, 24, 12, 0, 153, 17, 1, 0, 0, 0, 154, 155, 3, 84, 42, 0, 155, 156, 5, 17, 0, 0, 156, 157, 5, 81, 0, 0, 157, 158, 5, 10, 0, 0, 158, 159, 3, 80, 40, 0, 159, 160, 5, 2, 0, 0, 160, 19, 1, 0, 0, 0, 161, 162, 5, 18, 0, 0, 162, 163, 5, 81, 0, 0, 163, 164, 3, 26, 13, 0, 164, 168, 5, 19, 0, 0, 165, 167, 3, 22, 11, 0, 166, 165, 1, 0, 0, 0, 167, 170, 1, 0, 0, 0, 168, 166, 1, 0, 0, 0, 168, 169, 1, 0, 0, 0, 169, 171, 1, 0, 0, 0, 170, 168, 1, 0, 0, 0, 171, 172, 5, 20, 0, 0, 172, 21, 1, 0, 0, 0, 173, 174, 5, 12, 0, 0, 174, 175, 5, 81, 0, 0, 175, 176, 3, 26, 13, 0, 176, 177, 3, 24, 12, 0, 177, 23, 1, 0, 0, 0, 178, 182, 5, 19, 0, 0, 179, 181, 3, 32, 16, 0, 180, 179, 1, 0, 0, 0, 181, 184, 1, 0, 0, 0, 182, 180, 1, 0, 0, 0, 182, 183, 1, 0, 0, 0, 183, 185, 1, 0, 0, 0, 184, 182, 1, 0, 0, 0, 185, 186, 5, 20, 0, 0, 186, 25, 1, 0, 0, 0, 187, 199, 5, 14, 0, 0, 188, 193, 3, 28, 14, 0, 189, 190, 5, 15, 0, 0, 190, 192, 3, 28, 14, 0, 191, 189, 1, 0, 0, 0, 192, 195, 1, 0, 0, 0, 193, 191, 1, 0, 0, 0, 193, 194, 1, 0, 0, 0, 194, 197, 1, 0, 0, 0, 195, 193, 1, 0, 0, 0, 196, 198, 5, 15, 0, 0, 197, 196, 1, 0, 0, 0, 197, 198, 1, 0, 0, 0, 198, 200, 1, 0, 0, 0, 199, 188, 1, 0, 0, 0, 199, 200, 1, 0, 0, 0, 200, 201, 1, 0, 0, 0, 201, 202, 5, 16, 0, 0, 202, 27, 1, 0, 0, 0, 203, 204, 3, 84, 42, 0, 204, 205, 5, 81, 0, 0, 205, 29, 1, 0, 0, 0, 206, 210, 5, 19, 0, 0, 207, 209, 3, 32, 16, 0, 208, 207, 1, 0, 0, 0, 209, 212, 1, 0, 0, 0, 210, 208, 1, 0, 0, 0, 210, 211, 1, 0, 0, 0, 211, 213, 1, 0, 0, 0, 212, 210, 1, 0, 0, 0, 213, 216, 5, 20, 0, 0, 214, 216, 3, 32, 16, 0, 215, 206, 1, 0, 0, 0, 215, 214, 1, 0, 0, 0, 216, 31, 1, 0, 0, 0, 217, 222, 3, 40, 20, 0, 218, 219, 3, 34, 17, 0, 219, 220, 5, 2, 0, 0, 220, 222, 1, 0, 0, 0, 221, 217, 1, 0, 0, 0, 221, 218, 1, 0, 0, 0, 222, 33, 1, 0, 0, 0, 223, 232, 3, 42, 21, 0, 224, 232, 3, 44, 22, 0, 225, 232, 3, 46, 23, 0, 226, 232, 3, 48, 24, 0, 227, 232, 3, 50, 25, 0, 228, 232, 3, 36, 18, 0, 229, 232, 3, 52, 26, 0, 230, 232, 3, 38, 19, 0, 231, 223, 1, 0, 0, 0, 231, 224, 1, 0, 0, 0, 231, 225, 1, 0, 0, 0, 231, 226, 1, 0, 0, 0, 231, 227, 1, 0, 0, 0, 231, 228, 1, 0, 0, 0, 231, 229, 1, 0, 0, 0, 231, 230, 1, 0, 0, 0, 232, 35, 1, 0, 0, 0, 233, 234, 3, 72, 36, 0, 234, 37, 1, 0, 0, 0, 235, 236, 5, 21, 0, 0, 236, 241, 3, 76, 38, 0, 237, 238, 5, 15, 0, 0, 238, 240, 3, 76, 38, 0, 239, 237, 1, 0, 0, 0, 240, 243, 1, 0, 0, 0, 241, 239, 1, 0, 0, 0, 241, 242, 1, 0, 0, 0, 242, 39, 1, 0, 0, 0, 243, 241, 1, 0, 0, 0, 244, 247, 3, 54, 27, 0, 245, 247, 3, 56, 28, 0, 246, 244, 1, 0, 0, 0, 246, 245, 1, 0, 0, 0, 247, 41, 1, 0, 0, 0, 248, 252, 3, 84, 42, 0, 249, 251, 3, 78, 39, 0, 250, 249, 1, 0, 0, 0, 251, 254, 1, 0, 0, 0, 252, 250, 1, 0, 0, 0, 252, 253, 1, 0, 0, 0, 253, 255, 1, 0, 0, 0, 254, 252, 1, 0, 0, 0, 255, 256, 5, 81, 0, 0, 256, 257, 5, 10, 0, 0, 257, 258, 3, 76, 38, 0, 258, 43, 1, 0, 0, 0, 259, 260, 3, 84, 42, 0, 260, 265, 5, 81, 0, 0, 261, 262, 5, 15, 0, 0, 262, 263, 3, 84, 42, 0, 263, 264, 5, 81, 0, 0, 264, 266, 1, 0, 0, 0, 265, 261, 1, 0, 0, 0, 266, 267, 1, 0, 0, 0, 267, 265, 1, 0, 0, 0, 267, 268, 1, 0, 0, 0, 268, 269, 1, 0, 0, 0, 269, 270, 5, 10, 0, 0, 270, 271, 3, 76, 38, 0, 271, 45, 1, 0, 0, 0, 272, 273, 5, 81, 0, 0, 273, 274, 7, 1, 0, 0, 274, 278, 3, 76, 38, 0, 275, 276, 5, 81, 0, 0, 276, 278, 7, 2, 0, 0, 277, 272, 1, 0, 0, 0, 277, 275, 1, 0, 0, 0, 278, 47, 1, 0, 0, 0, 279, 280, 5, 26, 0, 0, 280, 281, 5, 14, 0, 0, 281, 282, 5, 78, 0, 0, 282, 283, 5, 6, 0, 0, 283, 286, 3, 76, 38, 0, 284, 285, 5, 15, 0, 0, 285, 287, 3, 66, 33, 0, 286, 284, 1, 0, 0, 0, 286, 287, 1, 0, 0, 0, 287, 288, 1, 0, 0, 0, 288, 289, 5, 16, 0, 0, 289, 49, 1, 0, 0, 0, 290, 291, 5, 26, 0, 0, 291, 292, 5, 14, 0, 0, 292, 295, 3, 76, 38, 0, 293, 294, 5, 15, 0, 0, 294, 296, 3, 66, 33, 0, 295, 293, 1, 0, 0, 0, 295, 296, 1, 0, 0, 0, 296, 297, 1, 0, 0, 0, 297, 298, 5, 16, 0, 0, 298, 51, 1, 0, 0, 0, 299, 300, 5, 27, 0, 0, 300, 301, 3, 70, 35, 0, 301, 53, 1, 0, 0, 0, 302, 303, 5, 28, 0, 0, 303, 304, 5, 14, 0, 0, 304, 305, 3, 76, 38, 0, 305, 306, 5, 16, 0, 0, 306, 309, 3, 30, 15, 0, 307, 308, 5, 29, 0, 0, 308, 310, 3, 30, 15, 0, 309, 307, 1, 0, 0, 0, 309, 310, 1, 0, 0, 0, 310, 55, 1, 0, 0, 0, 311, 315, 3, 58, 29, 0, 312, 315, 3, 60, 30, 0, 313, 315, 3, 62, 31, 0, 314, 311, 1, 0, 0, 0, 314, 312, 1, 0, 0, 0, 314, 313, 1, 0, 0, 0, 315, 57, 1, 0, 0, 0, 316, 317, 5, 30, 0, 0, 317, 318, 3, 30, 15, 0, 318, 319, 5, 31, 0, 0, 319, 320, 5, 14, 0, 0, 320, 321, 3, 76, 38, 0, 321, 322, 5, 16, 0, 0, 322, 323, 5, 2, 0, 0, 323, 59, 1, 0, 0, 0, 324, 325, 5, 31, 0, 0, 325, 326, 5, 14, 0, 0, 326, 327, 3, 76, 38, 0, 327, 328, 5, 16, 0, 0, 328, 329, 3, 30, 15, 0, 329, 61, 1, 0, 0, 0, 330, 331, 5, 32, 0, 0, 331, 332, 5, 14, 0, 0, 332, 333, 3, 64, 32, 0, 333, 334, 5, 2, 0, 0, 334, 335, 3, 76, 38, 0, 335, 336, 5, 2, 0, 0, 336, 337, 3, 46, 23, 0, 337, 338, 5, 16, 0, 0, 338, 339, 3, 30, 15, 0, 339, 63, 1, 0, 0, 0, 340, 343, 3, 42, 21, 0, 341, 343, 3, 46, 23, 0, 342, 340, 1, 0, 0, 0, 342, 341, 1, 0, 0, 0, 343, 65, 1, 0, 0, 0, 344, 345, 5, 75, 0, 0, 345, 67, 1, 0, 0, 0, 346, 349, 5, 81, 0, 0, 347, 349, 3, 80, 40, 0, 348, 346, 1, 0, 0, 0, 348, 347, 1, 0, 0, 0, 349, 69, 1, 0, 0, 0, 350, 362, 5, 14, 0, 0, 351, 356, 3, 68, 34, 0, 352, 353, 5, 15, 0, 0, 353, 355, 3, 68, 34, 0, 354, 352, 1, 0, 0, 0, 355, 358, 1, 0, 0, 0, 356, 354, 1, 0, 0, 0, 356, 357, 1, 0, 0, 0, 357, 360, 1, 0, 0, 0, 358, 356, 1, 0, 0, 0, 359, 361, 5, 15, 0, 0, 360, 359, 1, 0, 0, 0, 360, 361, 1, 0, 0, 0, 361, 363, 1, 0, 0, 0, 362, 351, 1, 0, 0, 0, 362, 363, 1, 0, 0, 0, 363, 364, 1, 0, 0, 0, 364, 365, 5, 16, 0, 0, 365, 71, 1, 0, 0, 0, 366, 367, 5, 81, 0, 0, 367, 368, 3, 74, 37, 0, 368, 73, 1, 0, 0, 0, 369, 381, 5, 14, 0, 0, 370, 375, 3, 76, 38, 0, 371, 372, 5, 15, 0, 0, 372, 374, 3, 76, 38, 0, 373, 371, 1, 0, 0, 0, 374, 377, 1, 0, 0, 0, 375, 373, 1, 0, 0, 0, 375, 376, 1, 0, 0, 0, 376, 379, 1, 0, 0, 0, 377, 375, 1, 0, 0, 0, 378, 380, 5, 15, 0, 0, 379, 378, 1, 0, 0, 0, 379, 380, 1, 0, 0, 0, 380, 382, 1, 0, 0, 0, 381, 370, 1, 0, 0, 0, 381, 382, 1, 0, 0, 0, 382, 383, 1, 0, 0, 0, 383, 384, 5, 16, 0, 0, 384, 75, 1, 0, 0, 0, 385, 386, 6, 38, -1, 0, 386, 387, 5, 14, 0, 0, 387, 388, 3, 76, 38, 0, 388, 389, 5, 16, 0, 0, 389, 435, 1, 0, 0, 0, 390, 391, 3, 86, 43, 0, 391, 392, 5, 14, 0, 0, 392, 394, 3, 76, 38, 0, 393, 395, 5, 15, 0, 0, 394, 393, 1, 0, 0, 0, 394, 395, 1, 0, 0, 0, 395, 396, 1, 0, 0, 0, 396, 397, 5, 16, 0, 0, 397, 435, 1, 0, 0, 0, 398, 435, 3, 72, 36, 0, 399, 400, 5, 33, 0, 0, 400, 401, 5, 81, 0, 0, 401, 435, 3, 74, 37, 0, 402, 403, 5, 36, 0, 0, 403, 404, 5, 34, 0, 0, 404, 405, 3, 76, 38, 0, 405, 406, 5, 35, 0, 0, 406, 407, 7, 3, 0, 0, 407, 435, 1, 0, 0, 0, 408, 409, 5, 42, 0, 0, 409, 410, 5, 34, 0, 0, 410, 411, 3, 76, 38, 0, 411, 412, 5, 35, 0, 0, 412, 413, 7, 4, 0, 0, 413, 435, 1, 0, 0, 0, 414, 415, 7, 5, 0, 0, 415, 435, 3, 76, 38, 15, 416, 428, 5, 34, 0, 0, 417, 422, 3, 76, 38, 0, 418, 419, 5, 15, 0, 0, 419, 421, 3, 76, 38, 0, 420, 418, 1, 0, 0, 0, 421, 424, 1, 0, 0, 0, 422, 420, 1, 0, 0, 0, 422, 423, 1, 0, 0, 0, 423, 426, 1, 0, 0, 0, 424, 422, 1, 0, 0, 0, 425, 427, 5, 15, 0, 0, 426, 425, 1, 0, 0, 0, 426, 427, 1, 0, 0, 0, 427, 429, 1, 0, 0, 0, 428, 417, 1, 0, 0, 0, 428, 429, 1, 0, 0, 0, 429, 430, 1, 0, 0, 0, 430, 435, 5, 35, 0, 0, 431, 435, 5, 80, 0, 0, 432, 435, 5, 81, 0, 0, 433, 435, 3, 80, 40, 0, 434, 385, 1, 0, 0, 0, 434, 390, 1, 0, 0, 0, 434, 398, 1, 0, 0, 0, 434, 399, 1, 0, 0, 0, 434, 402, 1, 0, 0, 0, 434, 408, 1, 0, 0, 0, 434, 414, 1, 0, 0, 0, 434, 416, 1, 0, 0, 0, 434, 431, 1, 0, 0, 0, 434, 432, 1, 0, 0, 0, 434, 433, 1, 0, 0, 0, 435, 488, 1, 0, 0, 0, 436, 437, 10, 14, 0, 0, 437, 438, 7, 6, 0, 0, 438, 487, 3, 76, 38, 15, 439, 440, 10, 13, 0, 0, 440, 441, 7, 7, 0, 0, 441, 487, 3, 76, 38, 14, 442, 443, 10, 12, 0, 0, 443, 444, 7, 8, 0, 0, 444, 487, 3, 76, 38, 13, 445, 446, 10, 11, 0, 0, 446, 447, 7, 9, 0, 0, 447, 487, 3, 76, 38, 12, 448, 449, 10, 10, 0, 0, 449, 450, 7, 10, 0, 0, 450, 487, 3, 76, 38, 11, 451, 452, 10, 9, 0, 0, 452, 453, 5, 61, 0, 0, 453, 487, 3, 76, 38, 10, 454, 455, 10, 8, 0, 0, 455, 456, 5, 4, 0, 0, 456, 487, 3, 76, 38, 9, 457, 458, 10, 7, 0, 0, 458, 459, 5, 62, 0, 0, 459, 487, 3, 76, 38, 8, 460, 461, 10, 6, 0, 0, 461, 462, 5, 63, 0, 0, 462, 487, 3, 76, 38, 7, 463, 464, 10, 5, 0, 0, 464, 465, 5, 64, 0, 0, 465, 487, 3, 76, 38, 6, 466, 467, 10, 21, 0, 0, 467, 468, 5, 34, 0, 0, 468, 469, 5, 68, 0, 0, 469, 487, 5, 35, 0, 0, 470, 471, 10, 18, 0, 0, 471, 487, 7, 11, 0, 0, 472, 473, 10, 17, 0, 0, 473, 474, 5, 49, 0, 0, 474, 475, 5, 14, 0, 0, 475, 476, 3, 76, 38, 0, 476, 477, 5, 16, 0, 0, 477, 487, 1, 0, 0, 0, 478, 479, 10, 16, 0, 0, 479, 480, 5, 50, 0, 0, 480, 481, 5, 14, 0, 0, 481, 482, 3, 76, 38, 0, 482, 483, 5, 15, 0, 0, 483, 484, 3, 76, 38, 0, 484, 485, 5, 16, 0, 0, 485, 487, 1, 0, 0, 0, 486, 436, 1, 0, 0, 0, 486, 439, 1, 0, 0, 0, 486, 442, 1, 0, 0, 0, 486, 445, 1, 0, 0, 0, 486, 448, 1, 0, 0, 0, 486, 451, 1, 0, 0, 0, 486, 454, 1, 0, 0, 0, 486, 457, 1, 0, 0, 0, 486, 460, 1, 0, 0, 0, 486, 463, 1, 0, 0, 0, 486, 466, 1, 0, 0, 0, 486, 470, 1, 0, 0, 0, 486, 472, 1, 0, 0, 0, 486, 478, 1, 0, 0, 0, 487, 490, 1, 0, 0, 0, 488, 486, 1, 0, 0, 0, 488, 489, 1, 0, 0, 0, 489, 77, 1, 0, 0, 0, 490, 488, 1, 0, 0, 0, 491, 492, 5, 17, 0, 0, 492, 79, 1, 0, 0, 0, 493, 499, 5, 66, 0, 0, 494, 499, 3, 82, 41, 0, 495, 499, 5, 75, 0, 0, 496, 499, 5, 76, 0, 0, 497, 499, 5, 77, 0, 0, 498, 493, 1, 0, 0, 0, 498, 494, 1, 0, 0, 0, 498, 495, 1, 0, 0, 0, 498, 496, 1, 0, 0, 0, 498, 497, 1, 0, 0, 0, 499, 81, 1, 0, 0, 0, 500, 502, 5, 68, 0, 0, 501, 503, 5, 67, 0, 0, 502, 501, 1, 0, 0, 0, 502, 503, 1, 0, 0, 0, 503, 83, 1, 0, 0, 0, 504, 505, 7, 12, 0, 0, 505, 85, 1, 0, 0, 0, 506, 507, 7, 13, 0, 0, 507, 87, 1, 0, 0, 0, 43, 91, 97, 103, 117, 120, 133, 145, 150, 168, 182, 193, 197, 199, 210, 215, 221, 231, 241, 246, 252, 267, 277, 286, 295, 309, 314, 342, 348, 356, 360, 362, 375, 379, 381, 394, 422, 426, 428, 434, 486, 488, 498, 502] \ No newline at end of file +[4, 1, 85, 515, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 1, 0, 5, 0, 90, 8, 0, 10, 0, 12, 0, 93, 9, 0, 1, 0, 5, 0, 96, 8, 0, 10, 0, 12, 0, 99, 9, 0, 1, 0, 5, 0, 102, 8, 0, 10, 0, 12, 0, 105, 9, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 3, 3, 3, 118, 8, 3, 1, 4, 3, 4, 121, 8, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 3, 7, 134, 8, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 5, 8, 144, 8, 8, 10, 8, 12, 8, 147, 9, 8, 1, 8, 1, 8, 3, 8, 151, 8, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 5, 10, 167, 8, 10, 10, 10, 12, 10, 170, 9, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 5, 12, 181, 8, 12, 10, 12, 12, 12, 184, 9, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 5, 13, 192, 8, 13, 10, 13, 12, 13, 195, 9, 13, 1, 13, 3, 13, 198, 8, 13, 3, 13, 200, 8, 13, 1, 13, 1, 13, 1, 14, 1, 14, 5, 14, 206, 8, 14, 10, 14, 12, 14, 209, 9, 14, 1, 14, 1, 14, 1, 15, 1, 15, 5, 15, 215, 8, 15, 10, 15, 12, 15, 218, 9, 15, 1, 15, 1, 15, 3, 15, 222, 8, 15, 1, 16, 1, 16, 1, 16, 1, 16, 3, 16, 228, 8, 16, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 3, 17, 238, 8, 17, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 19, 5, 19, 246, 8, 19, 10, 19, 12, 19, 249, 9, 19, 1, 20, 1, 20, 3, 20, 253, 8, 20, 1, 21, 1, 21, 5, 21, 257, 8, 21, 10, 21, 12, 21, 260, 9, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 4, 22, 272, 8, 22, 11, 22, 12, 22, 273, 1, 22, 1, 22, 1, 22, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 3, 23, 284, 8, 23, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 3, 24, 293, 8, 24, 1, 24, 1, 24, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 3, 25, 302, 8, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 26, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 3, 27, 316, 8, 27, 1, 28, 1, 28, 1, 28, 3, 28, 321, 8, 28, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 3, 32, 349, 8, 32, 1, 33, 1, 33, 1, 34, 1, 34, 3, 34, 355, 8, 34, 1, 35, 1, 35, 1, 35, 1, 35, 5, 35, 361, 8, 35, 10, 35, 12, 35, 364, 9, 35, 1, 35, 3, 35, 367, 8, 35, 3, 35, 369, 8, 35, 1, 35, 1, 35, 1, 36, 1, 36, 1, 36, 1, 37, 1, 37, 1, 37, 1, 37, 5, 37, 380, 8, 37, 10, 37, 12, 37, 383, 9, 37, 1, 37, 3, 37, 386, 8, 37, 3, 37, 388, 8, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 3, 38, 401, 8, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 5, 38, 427, 8, 38, 10, 38, 12, 38, 430, 9, 38, 1, 38, 3, 38, 433, 8, 38, 3, 38, 435, 8, 38, 1, 38, 1, 38, 1, 38, 1, 38, 3, 38, 441, 8, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 5, 38, 493, 8, 38, 10, 38, 12, 38, 496, 9, 38, 1, 39, 1, 39, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 3, 40, 505, 8, 40, 1, 41, 1, 41, 3, 41, 509, 8, 41, 1, 42, 1, 42, 1, 43, 1, 43, 1, 43, 0, 1, 76, 44, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 0, 15, 1, 0, 4, 10, 2, 0, 10, 10, 22, 23, 1, 0, 24, 25, 1, 0, 37, 41, 2, 0, 37, 41, 43, 46, 2, 0, 5, 5, 51, 52, 1, 0, 53, 55, 2, 0, 52, 52, 56, 56, 1, 0, 57, 58, 1, 0, 6, 9, 1, 0, 59, 60, 1, 0, 47, 48, 2, 0, 17, 17, 65, 65, 1, 0, 72, 74, 2, 0, 72, 73, 80, 80, 546, 0, 91, 1, 0, 0, 0, 2, 108, 1, 0, 0, 0, 4, 113, 1, 0, 0, 0, 6, 115, 1, 0, 0, 0, 8, 120, 1, 0, 0, 0, 10, 124, 1, 0, 0, 0, 12, 126, 1, 0, 0, 0, 14, 133, 1, 0, 0, 0, 16, 135, 1, 0, 0, 0, 18, 154, 1, 0, 0, 0, 20, 161, 1, 0, 0, 0, 22, 173, 1, 0, 0, 0, 24, 178, 1, 0, 0, 0, 26, 187, 1, 0, 0, 0, 28, 203, 1, 0, 0, 0, 30, 221, 1, 0, 0, 0, 32, 227, 1, 0, 0, 0, 34, 237, 1, 0, 0, 0, 36, 239, 1, 0, 0, 0, 38, 241, 1, 0, 0, 0, 40, 252, 1, 0, 0, 0, 42, 254, 1, 0, 0, 0, 44, 265, 1, 0, 0, 0, 46, 283, 1, 0, 0, 0, 48, 285, 1, 0, 0, 0, 50, 296, 1, 0, 0, 0, 52, 305, 1, 0, 0, 0, 54, 308, 1, 0, 0, 0, 56, 320, 1, 0, 0, 0, 58, 322, 1, 0, 0, 0, 60, 330, 1, 0, 0, 0, 62, 336, 1, 0, 0, 0, 64, 348, 1, 0, 0, 0, 66, 350, 1, 0, 0, 0, 68, 354, 1, 0, 0, 0, 70, 356, 1, 0, 0, 0, 72, 372, 1, 0, 0, 0, 74, 375, 1, 0, 0, 0, 76, 440, 1, 0, 0, 0, 78, 497, 1, 0, 0, 0, 80, 504, 1, 0, 0, 0, 82, 506, 1, 0, 0, 0, 84, 510, 1, 0, 0, 0, 86, 512, 1, 0, 0, 0, 88, 90, 3, 2, 1, 0, 89, 88, 1, 0, 0, 0, 90, 93, 1, 0, 0, 0, 91, 89, 1, 0, 0, 0, 91, 92, 1, 0, 0, 0, 92, 97, 1, 0, 0, 0, 93, 91, 1, 0, 0, 0, 94, 96, 3, 12, 6, 0, 95, 94, 1, 0, 0, 0, 96, 99, 1, 0, 0, 0, 97, 95, 1, 0, 0, 0, 97, 98, 1, 0, 0, 0, 98, 103, 1, 0, 0, 0, 99, 97, 1, 0, 0, 0, 100, 102, 3, 14, 7, 0, 101, 100, 1, 0, 0, 0, 102, 105, 1, 0, 0, 0, 103, 101, 1, 0, 0, 0, 103, 104, 1, 0, 0, 0, 104, 106, 1, 0, 0, 0, 105, 103, 1, 0, 0, 0, 106, 107, 5, 0, 0, 1, 107, 1, 1, 0, 0, 0, 108, 109, 5, 1, 0, 0, 109, 110, 3, 4, 2, 0, 110, 111, 3, 6, 3, 0, 111, 112, 5, 2, 0, 0, 112, 3, 1, 0, 0, 0, 113, 114, 5, 3, 0, 0, 114, 5, 1, 0, 0, 0, 115, 117, 3, 8, 4, 0, 116, 118, 3, 8, 4, 0, 117, 116, 1, 0, 0, 0, 117, 118, 1, 0, 0, 0, 118, 7, 1, 0, 0, 0, 119, 121, 3, 10, 5, 0, 120, 119, 1, 0, 0, 0, 120, 121, 1, 0, 0, 0, 121, 122, 1, 0, 0, 0, 122, 123, 5, 66, 0, 0, 123, 9, 1, 0, 0, 0, 124, 125, 7, 0, 0, 0, 125, 11, 1, 0, 0, 0, 126, 127, 5, 11, 0, 0, 127, 128, 5, 76, 0, 0, 128, 129, 5, 2, 0, 0, 129, 13, 1, 0, 0, 0, 130, 134, 3, 16, 8, 0, 131, 134, 3, 18, 9, 0, 132, 134, 3, 20, 10, 0, 133, 130, 1, 0, 0, 0, 133, 131, 1, 0, 0, 0, 133, 132, 1, 0, 0, 0, 134, 15, 1, 0, 0, 0, 135, 136, 5, 12, 0, 0, 136, 137, 5, 82, 0, 0, 137, 150, 3, 26, 13, 0, 138, 139, 5, 13, 0, 0, 139, 140, 5, 14, 0, 0, 140, 145, 3, 84, 42, 0, 141, 142, 5, 15, 0, 0, 142, 144, 3, 84, 42, 0, 143, 141, 1, 0, 0, 0, 144, 147, 1, 0, 0, 0, 145, 143, 1, 0, 0, 0, 145, 146, 1, 0, 0, 0, 146, 148, 1, 0, 0, 0, 147, 145, 1, 0, 0, 0, 148, 149, 5, 16, 0, 0, 149, 151, 1, 0, 0, 0, 150, 138, 1, 0, 0, 0, 150, 151, 1, 0, 0, 0, 151, 152, 1, 0, 0, 0, 152, 153, 3, 24, 12, 0, 153, 17, 1, 0, 0, 0, 154, 155, 3, 84, 42, 0, 155, 156, 5, 17, 0, 0, 156, 157, 5, 82, 0, 0, 157, 158, 5, 10, 0, 0, 158, 159, 3, 80, 40, 0, 159, 160, 5, 2, 0, 0, 160, 19, 1, 0, 0, 0, 161, 162, 5, 18, 0, 0, 162, 163, 5, 82, 0, 0, 163, 164, 3, 26, 13, 0, 164, 168, 5, 19, 0, 0, 165, 167, 3, 22, 11, 0, 166, 165, 1, 0, 0, 0, 167, 170, 1, 0, 0, 0, 168, 166, 1, 0, 0, 0, 168, 169, 1, 0, 0, 0, 169, 171, 1, 0, 0, 0, 170, 168, 1, 0, 0, 0, 171, 172, 5, 20, 0, 0, 172, 21, 1, 0, 0, 0, 173, 174, 5, 12, 0, 0, 174, 175, 5, 82, 0, 0, 175, 176, 3, 26, 13, 0, 176, 177, 3, 24, 12, 0, 177, 23, 1, 0, 0, 0, 178, 182, 5, 19, 0, 0, 179, 181, 3, 32, 16, 0, 180, 179, 1, 0, 0, 0, 181, 184, 1, 0, 0, 0, 182, 180, 1, 0, 0, 0, 182, 183, 1, 0, 0, 0, 183, 185, 1, 0, 0, 0, 184, 182, 1, 0, 0, 0, 185, 186, 5, 20, 0, 0, 186, 25, 1, 0, 0, 0, 187, 199, 5, 14, 0, 0, 188, 193, 3, 28, 14, 0, 189, 190, 5, 15, 0, 0, 190, 192, 3, 28, 14, 0, 191, 189, 1, 0, 0, 0, 192, 195, 1, 0, 0, 0, 193, 191, 1, 0, 0, 0, 193, 194, 1, 0, 0, 0, 194, 197, 1, 0, 0, 0, 195, 193, 1, 0, 0, 0, 196, 198, 5, 15, 0, 0, 197, 196, 1, 0, 0, 0, 197, 198, 1, 0, 0, 0, 198, 200, 1, 0, 0, 0, 199, 188, 1, 0, 0, 0, 199, 200, 1, 0, 0, 0, 200, 201, 1, 0, 0, 0, 201, 202, 5, 16, 0, 0, 202, 27, 1, 0, 0, 0, 203, 207, 3, 84, 42, 0, 204, 206, 3, 78, 39, 0, 205, 204, 1, 0, 0, 0, 206, 209, 1, 0, 0, 0, 207, 205, 1, 0, 0, 0, 207, 208, 1, 0, 0, 0, 208, 210, 1, 0, 0, 0, 209, 207, 1, 0, 0, 0, 210, 211, 5, 82, 0, 0, 211, 29, 1, 0, 0, 0, 212, 216, 5, 19, 0, 0, 213, 215, 3, 32, 16, 0, 214, 213, 1, 0, 0, 0, 215, 218, 1, 0, 0, 0, 216, 214, 1, 0, 0, 0, 216, 217, 1, 0, 0, 0, 217, 219, 1, 0, 0, 0, 218, 216, 1, 0, 0, 0, 219, 222, 5, 20, 0, 0, 220, 222, 3, 32, 16, 0, 221, 212, 1, 0, 0, 0, 221, 220, 1, 0, 0, 0, 222, 31, 1, 0, 0, 0, 223, 228, 3, 40, 20, 0, 224, 225, 3, 34, 17, 0, 225, 226, 5, 2, 0, 0, 226, 228, 1, 0, 0, 0, 227, 223, 1, 0, 0, 0, 227, 224, 1, 0, 0, 0, 228, 33, 1, 0, 0, 0, 229, 238, 3, 42, 21, 0, 230, 238, 3, 44, 22, 0, 231, 238, 3, 46, 23, 0, 232, 238, 3, 48, 24, 0, 233, 238, 3, 50, 25, 0, 234, 238, 3, 36, 18, 0, 235, 238, 3, 52, 26, 0, 236, 238, 3, 38, 19, 0, 237, 229, 1, 0, 0, 0, 237, 230, 1, 0, 0, 0, 237, 231, 1, 0, 0, 0, 237, 232, 1, 0, 0, 0, 237, 233, 1, 0, 0, 0, 237, 234, 1, 0, 0, 0, 237, 235, 1, 0, 0, 0, 237, 236, 1, 0, 0, 0, 238, 35, 1, 0, 0, 0, 239, 240, 3, 72, 36, 0, 240, 37, 1, 0, 0, 0, 241, 242, 5, 21, 0, 0, 242, 247, 3, 76, 38, 0, 243, 244, 5, 15, 0, 0, 244, 246, 3, 76, 38, 0, 245, 243, 1, 0, 0, 0, 246, 249, 1, 0, 0, 0, 247, 245, 1, 0, 0, 0, 247, 248, 1, 0, 0, 0, 248, 39, 1, 0, 0, 0, 249, 247, 1, 0, 0, 0, 250, 253, 3, 54, 27, 0, 251, 253, 3, 56, 28, 0, 252, 250, 1, 0, 0, 0, 252, 251, 1, 0, 0, 0, 253, 41, 1, 0, 0, 0, 254, 258, 3, 84, 42, 0, 255, 257, 3, 78, 39, 0, 256, 255, 1, 0, 0, 0, 257, 260, 1, 0, 0, 0, 258, 256, 1, 0, 0, 0, 258, 259, 1, 0, 0, 0, 259, 261, 1, 0, 0, 0, 260, 258, 1, 0, 0, 0, 261, 262, 5, 82, 0, 0, 262, 263, 5, 10, 0, 0, 263, 264, 3, 76, 38, 0, 264, 43, 1, 0, 0, 0, 265, 266, 3, 84, 42, 0, 266, 271, 5, 82, 0, 0, 267, 268, 5, 15, 0, 0, 268, 269, 3, 84, 42, 0, 269, 270, 5, 82, 0, 0, 270, 272, 1, 0, 0, 0, 271, 267, 1, 0, 0, 0, 272, 273, 1, 0, 0, 0, 273, 271, 1, 0, 0, 0, 273, 274, 1, 0, 0, 0, 274, 275, 1, 0, 0, 0, 275, 276, 5, 10, 0, 0, 276, 277, 3, 76, 38, 0, 277, 45, 1, 0, 0, 0, 278, 279, 5, 82, 0, 0, 279, 280, 7, 1, 0, 0, 280, 284, 3, 76, 38, 0, 281, 282, 5, 82, 0, 0, 282, 284, 7, 2, 0, 0, 283, 278, 1, 0, 0, 0, 283, 281, 1, 0, 0, 0, 284, 47, 1, 0, 0, 0, 285, 286, 5, 26, 0, 0, 286, 287, 5, 14, 0, 0, 287, 288, 5, 79, 0, 0, 288, 289, 5, 6, 0, 0, 289, 292, 3, 76, 38, 0, 290, 291, 5, 15, 0, 0, 291, 293, 3, 66, 33, 0, 292, 290, 1, 0, 0, 0, 292, 293, 1, 0, 0, 0, 293, 294, 1, 0, 0, 0, 294, 295, 5, 16, 0, 0, 295, 49, 1, 0, 0, 0, 296, 297, 5, 26, 0, 0, 297, 298, 5, 14, 0, 0, 298, 301, 3, 76, 38, 0, 299, 300, 5, 15, 0, 0, 300, 302, 3, 66, 33, 0, 301, 299, 1, 0, 0, 0, 301, 302, 1, 0, 0, 0, 302, 303, 1, 0, 0, 0, 303, 304, 5, 16, 0, 0, 304, 51, 1, 0, 0, 0, 305, 306, 5, 27, 0, 0, 306, 307, 3, 70, 35, 0, 307, 53, 1, 0, 0, 0, 308, 309, 5, 28, 0, 0, 309, 310, 5, 14, 0, 0, 310, 311, 3, 76, 38, 0, 311, 312, 5, 16, 0, 0, 312, 315, 3, 30, 15, 0, 313, 314, 5, 29, 0, 0, 314, 316, 3, 30, 15, 0, 315, 313, 1, 0, 0, 0, 315, 316, 1, 0, 0, 0, 316, 55, 1, 0, 0, 0, 317, 321, 3, 58, 29, 0, 318, 321, 3, 60, 30, 0, 319, 321, 3, 62, 31, 0, 320, 317, 1, 0, 0, 0, 320, 318, 1, 0, 0, 0, 320, 319, 1, 0, 0, 0, 321, 57, 1, 0, 0, 0, 322, 323, 5, 30, 0, 0, 323, 324, 3, 30, 15, 0, 324, 325, 5, 31, 0, 0, 325, 326, 5, 14, 0, 0, 326, 327, 3, 76, 38, 0, 327, 328, 5, 16, 0, 0, 328, 329, 5, 2, 0, 0, 329, 59, 1, 0, 0, 0, 330, 331, 5, 31, 0, 0, 331, 332, 5, 14, 0, 0, 332, 333, 3, 76, 38, 0, 333, 334, 5, 16, 0, 0, 334, 335, 3, 30, 15, 0, 335, 61, 1, 0, 0, 0, 336, 337, 5, 32, 0, 0, 337, 338, 5, 14, 0, 0, 338, 339, 3, 64, 32, 0, 339, 340, 5, 2, 0, 0, 340, 341, 3, 76, 38, 0, 341, 342, 5, 2, 0, 0, 342, 343, 3, 46, 23, 0, 343, 344, 5, 16, 0, 0, 344, 345, 3, 30, 15, 0, 345, 63, 1, 0, 0, 0, 346, 349, 3, 42, 21, 0, 347, 349, 3, 46, 23, 0, 348, 346, 1, 0, 0, 0, 348, 347, 1, 0, 0, 0, 349, 65, 1, 0, 0, 0, 350, 351, 5, 76, 0, 0, 351, 67, 1, 0, 0, 0, 352, 355, 5, 82, 0, 0, 353, 355, 3, 80, 40, 0, 354, 352, 1, 0, 0, 0, 354, 353, 1, 0, 0, 0, 355, 69, 1, 0, 0, 0, 356, 368, 5, 14, 0, 0, 357, 362, 3, 68, 34, 0, 358, 359, 5, 15, 0, 0, 359, 361, 3, 68, 34, 0, 360, 358, 1, 0, 0, 0, 361, 364, 1, 0, 0, 0, 362, 360, 1, 0, 0, 0, 362, 363, 1, 0, 0, 0, 363, 366, 1, 0, 0, 0, 364, 362, 1, 0, 0, 0, 365, 367, 5, 15, 0, 0, 366, 365, 1, 0, 0, 0, 366, 367, 1, 0, 0, 0, 367, 369, 1, 0, 0, 0, 368, 357, 1, 0, 0, 0, 368, 369, 1, 0, 0, 0, 369, 370, 1, 0, 0, 0, 370, 371, 5, 16, 0, 0, 371, 71, 1, 0, 0, 0, 372, 373, 5, 82, 0, 0, 373, 374, 3, 74, 37, 0, 374, 73, 1, 0, 0, 0, 375, 387, 5, 14, 0, 0, 376, 381, 3, 76, 38, 0, 377, 378, 5, 15, 0, 0, 378, 380, 3, 76, 38, 0, 379, 377, 1, 0, 0, 0, 380, 383, 1, 0, 0, 0, 381, 379, 1, 0, 0, 0, 381, 382, 1, 0, 0, 0, 382, 385, 1, 0, 0, 0, 383, 381, 1, 0, 0, 0, 384, 386, 5, 15, 0, 0, 385, 384, 1, 0, 0, 0, 385, 386, 1, 0, 0, 0, 386, 388, 1, 0, 0, 0, 387, 376, 1, 0, 0, 0, 387, 388, 1, 0, 0, 0, 388, 389, 1, 0, 0, 0, 389, 390, 5, 16, 0, 0, 390, 75, 1, 0, 0, 0, 391, 392, 6, 38, -1, 0, 392, 393, 5, 14, 0, 0, 393, 394, 3, 76, 38, 0, 394, 395, 5, 16, 0, 0, 395, 441, 1, 0, 0, 0, 396, 397, 3, 86, 43, 0, 397, 398, 5, 14, 0, 0, 398, 400, 3, 76, 38, 0, 399, 401, 5, 15, 0, 0, 400, 399, 1, 0, 0, 0, 400, 401, 1, 0, 0, 0, 401, 402, 1, 0, 0, 0, 402, 403, 5, 16, 0, 0, 403, 441, 1, 0, 0, 0, 404, 441, 3, 72, 36, 0, 405, 406, 5, 33, 0, 0, 406, 407, 5, 82, 0, 0, 407, 441, 3, 74, 37, 0, 408, 409, 5, 36, 0, 0, 409, 410, 5, 34, 0, 0, 410, 411, 3, 76, 38, 0, 411, 412, 5, 35, 0, 0, 412, 413, 7, 3, 0, 0, 413, 441, 1, 0, 0, 0, 414, 415, 5, 42, 0, 0, 415, 416, 5, 34, 0, 0, 416, 417, 3, 76, 38, 0, 417, 418, 5, 35, 0, 0, 418, 419, 7, 4, 0, 0, 419, 441, 1, 0, 0, 0, 420, 421, 7, 5, 0, 0, 421, 441, 3, 76, 38, 15, 422, 434, 5, 34, 0, 0, 423, 428, 3, 76, 38, 0, 424, 425, 5, 15, 0, 0, 425, 427, 3, 76, 38, 0, 426, 424, 1, 0, 0, 0, 427, 430, 1, 0, 0, 0, 428, 426, 1, 0, 0, 0, 428, 429, 1, 0, 0, 0, 429, 432, 1, 0, 0, 0, 430, 428, 1, 0, 0, 0, 431, 433, 5, 15, 0, 0, 432, 431, 1, 0, 0, 0, 432, 433, 1, 0, 0, 0, 433, 435, 1, 0, 0, 0, 434, 423, 1, 0, 0, 0, 434, 435, 1, 0, 0, 0, 435, 436, 1, 0, 0, 0, 436, 441, 5, 35, 0, 0, 437, 441, 5, 81, 0, 0, 438, 441, 5, 82, 0, 0, 439, 441, 3, 80, 40, 0, 440, 391, 1, 0, 0, 0, 440, 396, 1, 0, 0, 0, 440, 404, 1, 0, 0, 0, 440, 405, 1, 0, 0, 0, 440, 408, 1, 0, 0, 0, 440, 414, 1, 0, 0, 0, 440, 420, 1, 0, 0, 0, 440, 422, 1, 0, 0, 0, 440, 437, 1, 0, 0, 0, 440, 438, 1, 0, 0, 0, 440, 439, 1, 0, 0, 0, 441, 494, 1, 0, 0, 0, 442, 443, 10, 14, 0, 0, 443, 444, 7, 6, 0, 0, 444, 493, 3, 76, 38, 15, 445, 446, 10, 13, 0, 0, 446, 447, 7, 7, 0, 0, 447, 493, 3, 76, 38, 14, 448, 449, 10, 12, 0, 0, 449, 450, 7, 8, 0, 0, 450, 493, 3, 76, 38, 13, 451, 452, 10, 11, 0, 0, 452, 453, 7, 9, 0, 0, 453, 493, 3, 76, 38, 12, 454, 455, 10, 10, 0, 0, 455, 456, 7, 10, 0, 0, 456, 493, 3, 76, 38, 11, 457, 458, 10, 9, 0, 0, 458, 459, 5, 61, 0, 0, 459, 493, 3, 76, 38, 10, 460, 461, 10, 8, 0, 0, 461, 462, 5, 4, 0, 0, 462, 493, 3, 76, 38, 9, 463, 464, 10, 7, 0, 0, 464, 465, 5, 62, 0, 0, 465, 493, 3, 76, 38, 8, 466, 467, 10, 6, 0, 0, 467, 468, 5, 63, 0, 0, 468, 493, 3, 76, 38, 7, 469, 470, 10, 5, 0, 0, 470, 471, 5, 64, 0, 0, 471, 493, 3, 76, 38, 6, 472, 473, 10, 21, 0, 0, 473, 474, 5, 34, 0, 0, 474, 475, 5, 69, 0, 0, 475, 493, 5, 35, 0, 0, 476, 477, 10, 18, 0, 0, 477, 493, 7, 11, 0, 0, 478, 479, 10, 17, 0, 0, 479, 480, 5, 49, 0, 0, 480, 481, 5, 14, 0, 0, 481, 482, 3, 76, 38, 0, 482, 483, 5, 16, 0, 0, 483, 493, 1, 0, 0, 0, 484, 485, 10, 16, 0, 0, 485, 486, 5, 50, 0, 0, 486, 487, 5, 14, 0, 0, 487, 488, 3, 76, 38, 0, 488, 489, 5, 15, 0, 0, 489, 490, 3, 76, 38, 0, 490, 491, 5, 16, 0, 0, 491, 493, 1, 0, 0, 0, 492, 442, 1, 0, 0, 0, 492, 445, 1, 0, 0, 0, 492, 448, 1, 0, 0, 0, 492, 451, 1, 0, 0, 0, 492, 454, 1, 0, 0, 0, 492, 457, 1, 0, 0, 0, 492, 460, 1, 0, 0, 0, 492, 463, 1, 0, 0, 0, 492, 466, 1, 0, 0, 0, 492, 469, 1, 0, 0, 0, 492, 472, 1, 0, 0, 0, 492, 476, 1, 0, 0, 0, 492, 478, 1, 0, 0, 0, 492, 484, 1, 0, 0, 0, 493, 496, 1, 0, 0, 0, 494, 492, 1, 0, 0, 0, 494, 495, 1, 0, 0, 0, 495, 77, 1, 0, 0, 0, 496, 494, 1, 0, 0, 0, 497, 498, 7, 12, 0, 0, 498, 79, 1, 0, 0, 0, 499, 505, 5, 67, 0, 0, 500, 505, 3, 82, 41, 0, 501, 505, 5, 76, 0, 0, 502, 505, 5, 77, 0, 0, 503, 505, 5, 78, 0, 0, 504, 499, 1, 0, 0, 0, 504, 500, 1, 0, 0, 0, 504, 501, 1, 0, 0, 0, 504, 502, 1, 0, 0, 0, 504, 503, 1, 0, 0, 0, 505, 81, 1, 0, 0, 0, 506, 508, 5, 69, 0, 0, 507, 509, 5, 68, 0, 0, 508, 507, 1, 0, 0, 0, 508, 509, 1, 0, 0, 0, 509, 83, 1, 0, 0, 0, 510, 511, 7, 13, 0, 0, 511, 85, 1, 0, 0, 0, 512, 513, 7, 14, 0, 0, 513, 87, 1, 0, 0, 0, 44, 91, 97, 103, 117, 120, 133, 145, 150, 168, 182, 193, 197, 199, 207, 216, 221, 227, 237, 247, 252, 258, 273, 283, 292, 301, 315, 320, 348, 354, 362, 366, 368, 381, 385, 387, 400, 428, 432, 434, 440, 492, 494, 504, 508] \ No newline at end of file diff --git a/packages/cashc/src/grammar/CashScript.tokens b/packages/cashc/src/grammar/CashScript.tokens index 074f0fc1..1ca45fe0 100644 --- a/packages/cashc/src/grammar/CashScript.tokens +++ b/packages/cashc/src/grammar/CashScript.tokens @@ -62,26 +62,27 @@ T__60=61 T__61=62 T__62=63 T__63=64 -VersionLiteral=65 -BooleanLiteral=66 -NumberUnit=67 -NumberLiteral=68 -NumberPart=69 -ExponentPart=70 -PrimitiveType=71 -UnboundedBytes=72 -BoundedBytes=73 -Bound=74 -StringLiteral=75 -DateLiteral=76 -HexLiteral=77 -TxVar=78 -UnsafeCast=79 -NullaryOp=80 -Identifier=81 -WHITESPACE=82 -COMMENT=83 -LINE_COMMENT=84 +T__64=65 +VersionLiteral=66 +BooleanLiteral=67 +NumberUnit=68 +NumberLiteral=69 +NumberPart=70 +ExponentPart=71 +PrimitiveType=72 +UnboundedBytes=73 +BoundedBytes=74 +Bound=75 +StringLiteral=76 +DateLiteral=77 +HexLiteral=78 +TxVar=79 +UnsafeCast=80 +NullaryOp=81 +Identifier=82 +WHITESPACE=83 +COMMENT=84 +LINE_COMMENT=85 'pragma'=1 ';'=2 'cashscript'=3 @@ -146,4 +147,5 @@ LINE_COMMENT=84 '|'=62 '&&'=63 '||'=64 -'bytes'=72 +'unused'=65 +'bytes'=73 diff --git a/packages/cashc/src/grammar/CashScriptLexer.interp b/packages/cashc/src/grammar/CashScriptLexer.interp index 8cd270bc..53253d13 100644 --- a/packages/cashc/src/grammar/CashScriptLexer.interp +++ b/packages/cashc/src/grammar/CashScriptLexer.interp @@ -64,6 +64,7 @@ null '|' '&&' '||' +'unused' null null null @@ -151,6 +152,7 @@ null null null null +null VersionLiteral BooleanLiteral NumberUnit @@ -237,6 +239,7 @@ T__60 T__61 T__62 T__63 +T__64 VersionLiteral BooleanLiteral NumberUnit @@ -266,4 +269,4 @@ mode names: DEFAULT_MODE atn: -[4, 0, 84, 966, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62, 7, 62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67, 2, 68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72, 2, 73, 7, 73, 2, 74, 7, 74, 2, 75, 7, 75, 2, 76, 7, 76, 2, 77, 7, 77, 2, 78, 7, 78, 2, 79, 7, 79, 2, 80, 7, 80, 2, 81, 7, 81, 2, 82, 7, 82, 2, 83, 7, 83, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 6, 1, 6, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 14, 1, 14, 1, 15, 1, 15, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 18, 1, 18, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 23, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 27, 1, 27, 1, 27, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 29, 1, 29, 1, 29, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 1, 32, 1, 32, 1, 33, 1, 33, 1, 34, 1, 34, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 50, 1, 50, 1, 51, 1, 51, 1, 52, 1, 52, 1, 53, 1, 53, 1, 54, 1, 54, 1, 55, 1, 55, 1, 56, 1, 56, 1, 56, 1, 57, 1, 57, 1, 57, 1, 58, 1, 58, 1, 58, 1, 59, 1, 59, 1, 59, 1, 60, 1, 60, 1, 61, 1, 61, 1, 62, 1, 62, 1, 62, 1, 63, 1, 63, 1, 63, 1, 64, 4, 64, 557, 8, 64, 11, 64, 12, 64, 558, 1, 64, 1, 64, 4, 64, 563, 8, 64, 11, 64, 12, 64, 564, 1, 64, 1, 64, 4, 64, 569, 8, 64, 11, 64, 12, 64, 570, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 3, 65, 582, 8, 65, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 3, 66, 641, 8, 66, 1, 67, 3, 67, 644, 8, 67, 1, 67, 1, 67, 3, 67, 648, 8, 67, 1, 68, 4, 68, 651, 8, 68, 11, 68, 12, 68, 652, 1, 68, 1, 68, 4, 68, 657, 8, 68, 11, 68, 12, 68, 658, 5, 68, 661, 8, 68, 10, 68, 12, 68, 664, 9, 68, 1, 69, 1, 69, 1, 69, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 3, 70, 698, 8, 70, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 3, 72, 717, 8, 72, 1, 73, 1, 73, 5, 73, 721, 8, 73, 10, 73, 12, 73, 724, 9, 73, 1, 74, 1, 74, 1, 74, 1, 74, 5, 74, 730, 8, 74, 10, 74, 12, 74, 733, 9, 74, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 5, 74, 740, 8, 74, 10, 74, 12, 74, 743, 9, 74, 1, 74, 3, 74, 746, 8, 74, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 76, 1, 76, 1, 76, 5, 76, 760, 8, 76, 10, 76, 12, 76, 763, 9, 76, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 3, 77, 780, 8, 77, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 3, 78, 817, 8, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 3, 78, 830, 8, 78, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 3, 79, 926, 8, 79, 1, 80, 1, 80, 5, 80, 930, 8, 80, 10, 80, 12, 80, 933, 9, 80, 1, 81, 4, 81, 936, 8, 81, 11, 81, 12, 81, 937, 1, 81, 1, 81, 1, 82, 1, 82, 1, 82, 1, 82, 5, 82, 946, 8, 82, 10, 82, 12, 82, 949, 9, 82, 1, 82, 1, 82, 1, 82, 1, 82, 1, 82, 1, 83, 1, 83, 1, 83, 1, 83, 5, 83, 960, 8, 83, 10, 83, 12, 83, 963, 9, 83, 1, 83, 1, 83, 3, 731, 741, 947, 0, 84, 1, 1, 3, 2, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, 17, 9, 19, 10, 21, 11, 23, 12, 25, 13, 27, 14, 29, 15, 31, 16, 33, 17, 35, 18, 37, 19, 39, 20, 41, 21, 43, 22, 45, 23, 47, 24, 49, 25, 51, 26, 53, 27, 55, 28, 57, 29, 59, 30, 61, 31, 63, 32, 65, 33, 67, 34, 69, 35, 71, 36, 73, 37, 75, 38, 77, 39, 79, 40, 81, 41, 83, 42, 85, 43, 87, 44, 89, 45, 91, 46, 93, 47, 95, 48, 97, 49, 99, 50, 101, 51, 103, 52, 105, 53, 107, 54, 109, 55, 111, 56, 113, 57, 115, 58, 117, 59, 119, 60, 121, 61, 123, 62, 125, 63, 127, 64, 129, 65, 131, 66, 133, 67, 135, 68, 137, 69, 139, 70, 141, 71, 143, 72, 145, 73, 147, 74, 149, 75, 151, 76, 153, 77, 155, 78, 157, 79, 159, 80, 161, 81, 163, 82, 165, 83, 167, 84, 1, 0, 11, 1, 0, 48, 57, 2, 0, 69, 69, 101, 101, 1, 0, 49, 57, 3, 0, 10, 10, 13, 13, 34, 34, 3, 0, 10, 10, 13, 13, 39, 39, 2, 0, 88, 88, 120, 120, 3, 0, 48, 57, 65, 70, 97, 102, 2, 0, 65, 90, 97, 122, 4, 0, 48, 57, 65, 90, 95, 95, 97, 122, 3, 0, 9, 10, 12, 13, 32, 32, 2, 0, 10, 10, 13, 13, 1010, 0, 1, 1, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 9, 1, 0, 0, 0, 0, 11, 1, 0, 0, 0, 0, 13, 1, 0, 0, 0, 0, 15, 1, 0, 0, 0, 0, 17, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 0, 21, 1, 0, 0, 0, 0, 23, 1, 0, 0, 0, 0, 25, 1, 0, 0, 0, 0, 27, 1, 0, 0, 0, 0, 29, 1, 0, 0, 0, 0, 31, 1, 0, 0, 0, 0, 33, 1, 0, 0, 0, 0, 35, 1, 0, 0, 0, 0, 37, 1, 0, 0, 0, 0, 39, 1, 0, 0, 0, 0, 41, 1, 0, 0, 0, 0, 43, 1, 0, 0, 0, 0, 45, 1, 0, 0, 0, 0, 47, 1, 0, 0, 0, 0, 49, 1, 0, 0, 0, 0, 51, 1, 0, 0, 0, 0, 53, 1, 0, 0, 0, 0, 55, 1, 0, 0, 0, 0, 57, 1, 0, 0, 0, 0, 59, 1, 0, 0, 0, 0, 61, 1, 0, 0, 0, 0, 63, 1, 0, 0, 0, 0, 65, 1, 0, 0, 0, 0, 67, 1, 0, 0, 0, 0, 69, 1, 0, 0, 0, 0, 71, 1, 0, 0, 0, 0, 73, 1, 0, 0, 0, 0, 75, 1, 0, 0, 0, 0, 77, 1, 0, 0, 0, 0, 79, 1, 0, 0, 0, 0, 81, 1, 0, 0, 0, 0, 83, 1, 0, 0, 0, 0, 85, 1, 0, 0, 0, 0, 87, 1, 0, 0, 0, 0, 89, 1, 0, 0, 0, 0, 91, 1, 0, 0, 0, 0, 93, 1, 0, 0, 0, 0, 95, 1, 0, 0, 0, 0, 97, 1, 0, 0, 0, 0, 99, 1, 0, 0, 0, 0, 101, 1, 0, 0, 0, 0, 103, 1, 0, 0, 0, 0, 105, 1, 0, 0, 0, 0, 107, 1, 0, 0, 0, 0, 109, 1, 0, 0, 0, 0, 111, 1, 0, 0, 0, 0, 113, 1, 0, 0, 0, 0, 115, 1, 0, 0, 0, 0, 117, 1, 0, 0, 0, 0, 119, 1, 0, 0, 0, 0, 121, 1, 0, 0, 0, 0, 123, 1, 0, 0, 0, 0, 125, 1, 0, 0, 0, 0, 127, 1, 0, 0, 0, 0, 129, 1, 0, 0, 0, 0, 131, 1, 0, 0, 0, 0, 133, 1, 0, 0, 0, 0, 135, 1, 0, 0, 0, 0, 137, 1, 0, 0, 0, 0, 139, 1, 0, 0, 0, 0, 141, 1, 0, 0, 0, 0, 143, 1, 0, 0, 0, 0, 145, 1, 0, 0, 0, 0, 147, 1, 0, 0, 0, 0, 149, 1, 0, 0, 0, 0, 151, 1, 0, 0, 0, 0, 153, 1, 0, 0, 0, 0, 155, 1, 0, 0, 0, 0, 157, 1, 0, 0, 0, 0, 159, 1, 0, 0, 0, 0, 161, 1, 0, 0, 0, 0, 163, 1, 0, 0, 0, 0, 165, 1, 0, 0, 0, 0, 167, 1, 0, 0, 0, 1, 169, 1, 0, 0, 0, 3, 176, 1, 0, 0, 0, 5, 178, 1, 0, 0, 0, 7, 189, 1, 0, 0, 0, 9, 191, 1, 0, 0, 0, 11, 193, 1, 0, 0, 0, 13, 196, 1, 0, 0, 0, 15, 198, 1, 0, 0, 0, 17, 200, 1, 0, 0, 0, 19, 203, 1, 0, 0, 0, 21, 205, 1, 0, 0, 0, 23, 212, 1, 0, 0, 0, 25, 221, 1, 0, 0, 0, 27, 229, 1, 0, 0, 0, 29, 231, 1, 0, 0, 0, 31, 233, 1, 0, 0, 0, 33, 235, 1, 0, 0, 0, 35, 244, 1, 0, 0, 0, 37, 253, 1, 0, 0, 0, 39, 255, 1, 0, 0, 0, 41, 257, 1, 0, 0, 0, 43, 264, 1, 0, 0, 0, 45, 267, 1, 0, 0, 0, 47, 270, 1, 0, 0, 0, 49, 273, 1, 0, 0, 0, 51, 276, 1, 0, 0, 0, 53, 284, 1, 0, 0, 0, 55, 296, 1, 0, 0, 0, 57, 299, 1, 0, 0, 0, 59, 304, 1, 0, 0, 0, 61, 307, 1, 0, 0, 0, 63, 313, 1, 0, 0, 0, 65, 317, 1, 0, 0, 0, 67, 321, 1, 0, 0, 0, 69, 323, 1, 0, 0, 0, 71, 325, 1, 0, 0, 0, 73, 336, 1, 0, 0, 0, 75, 343, 1, 0, 0, 0, 77, 360, 1, 0, 0, 0, 79, 375, 1, 0, 0, 0, 81, 390, 1, 0, 0, 0, 83, 403, 1, 0, 0, 0, 85, 413, 1, 0, 0, 0, 87, 438, 1, 0, 0, 0, 89, 453, 1, 0, 0, 0, 91, 472, 1, 0, 0, 0, 93, 488, 1, 0, 0, 0, 95, 499, 1, 0, 0, 0, 97, 507, 1, 0, 0, 0, 99, 514, 1, 0, 0, 0, 101, 521, 1, 0, 0, 0, 103, 523, 1, 0, 0, 0, 105, 525, 1, 0, 0, 0, 107, 527, 1, 0, 0, 0, 109, 529, 1, 0, 0, 0, 111, 531, 1, 0, 0, 0, 113, 533, 1, 0, 0, 0, 115, 536, 1, 0, 0, 0, 117, 539, 1, 0, 0, 0, 119, 542, 1, 0, 0, 0, 121, 545, 1, 0, 0, 0, 123, 547, 1, 0, 0, 0, 125, 549, 1, 0, 0, 0, 127, 552, 1, 0, 0, 0, 129, 556, 1, 0, 0, 0, 131, 581, 1, 0, 0, 0, 133, 640, 1, 0, 0, 0, 135, 643, 1, 0, 0, 0, 137, 650, 1, 0, 0, 0, 139, 665, 1, 0, 0, 0, 141, 697, 1, 0, 0, 0, 143, 699, 1, 0, 0, 0, 145, 716, 1, 0, 0, 0, 147, 718, 1, 0, 0, 0, 149, 745, 1, 0, 0, 0, 151, 747, 1, 0, 0, 0, 153, 756, 1, 0, 0, 0, 155, 779, 1, 0, 0, 0, 157, 829, 1, 0, 0, 0, 159, 925, 1, 0, 0, 0, 161, 927, 1, 0, 0, 0, 163, 935, 1, 0, 0, 0, 165, 941, 1, 0, 0, 0, 167, 955, 1, 0, 0, 0, 169, 170, 5, 112, 0, 0, 170, 171, 5, 114, 0, 0, 171, 172, 5, 97, 0, 0, 172, 173, 5, 103, 0, 0, 173, 174, 5, 109, 0, 0, 174, 175, 5, 97, 0, 0, 175, 2, 1, 0, 0, 0, 176, 177, 5, 59, 0, 0, 177, 4, 1, 0, 0, 0, 178, 179, 5, 99, 0, 0, 179, 180, 5, 97, 0, 0, 180, 181, 5, 115, 0, 0, 181, 182, 5, 104, 0, 0, 182, 183, 5, 115, 0, 0, 183, 184, 5, 99, 0, 0, 184, 185, 5, 114, 0, 0, 185, 186, 5, 105, 0, 0, 186, 187, 5, 112, 0, 0, 187, 188, 5, 116, 0, 0, 188, 6, 1, 0, 0, 0, 189, 190, 5, 94, 0, 0, 190, 8, 1, 0, 0, 0, 191, 192, 5, 126, 0, 0, 192, 10, 1, 0, 0, 0, 193, 194, 5, 62, 0, 0, 194, 195, 5, 61, 0, 0, 195, 12, 1, 0, 0, 0, 196, 197, 5, 62, 0, 0, 197, 14, 1, 0, 0, 0, 198, 199, 5, 60, 0, 0, 199, 16, 1, 0, 0, 0, 200, 201, 5, 60, 0, 0, 201, 202, 5, 61, 0, 0, 202, 18, 1, 0, 0, 0, 203, 204, 5, 61, 0, 0, 204, 20, 1, 0, 0, 0, 205, 206, 5, 105, 0, 0, 206, 207, 5, 109, 0, 0, 207, 208, 5, 112, 0, 0, 208, 209, 5, 111, 0, 0, 209, 210, 5, 114, 0, 0, 210, 211, 5, 116, 0, 0, 211, 22, 1, 0, 0, 0, 212, 213, 5, 102, 0, 0, 213, 214, 5, 117, 0, 0, 214, 215, 5, 110, 0, 0, 215, 216, 5, 99, 0, 0, 216, 217, 5, 116, 0, 0, 217, 218, 5, 105, 0, 0, 218, 219, 5, 111, 0, 0, 219, 220, 5, 110, 0, 0, 220, 24, 1, 0, 0, 0, 221, 222, 5, 114, 0, 0, 222, 223, 5, 101, 0, 0, 223, 224, 5, 116, 0, 0, 224, 225, 5, 117, 0, 0, 225, 226, 5, 114, 0, 0, 226, 227, 5, 110, 0, 0, 227, 228, 5, 115, 0, 0, 228, 26, 1, 0, 0, 0, 229, 230, 5, 40, 0, 0, 230, 28, 1, 0, 0, 0, 231, 232, 5, 44, 0, 0, 232, 30, 1, 0, 0, 0, 233, 234, 5, 41, 0, 0, 234, 32, 1, 0, 0, 0, 235, 236, 5, 99, 0, 0, 236, 237, 5, 111, 0, 0, 237, 238, 5, 110, 0, 0, 238, 239, 5, 115, 0, 0, 239, 240, 5, 116, 0, 0, 240, 241, 5, 97, 0, 0, 241, 242, 5, 110, 0, 0, 242, 243, 5, 116, 0, 0, 243, 34, 1, 0, 0, 0, 244, 245, 5, 99, 0, 0, 245, 246, 5, 111, 0, 0, 246, 247, 5, 110, 0, 0, 247, 248, 5, 116, 0, 0, 248, 249, 5, 114, 0, 0, 249, 250, 5, 97, 0, 0, 250, 251, 5, 99, 0, 0, 251, 252, 5, 116, 0, 0, 252, 36, 1, 0, 0, 0, 253, 254, 5, 123, 0, 0, 254, 38, 1, 0, 0, 0, 255, 256, 5, 125, 0, 0, 256, 40, 1, 0, 0, 0, 257, 258, 5, 114, 0, 0, 258, 259, 5, 101, 0, 0, 259, 260, 5, 116, 0, 0, 260, 261, 5, 117, 0, 0, 261, 262, 5, 114, 0, 0, 262, 263, 5, 110, 0, 0, 263, 42, 1, 0, 0, 0, 264, 265, 5, 43, 0, 0, 265, 266, 5, 61, 0, 0, 266, 44, 1, 0, 0, 0, 267, 268, 5, 45, 0, 0, 268, 269, 5, 61, 0, 0, 269, 46, 1, 0, 0, 0, 270, 271, 5, 43, 0, 0, 271, 272, 5, 43, 0, 0, 272, 48, 1, 0, 0, 0, 273, 274, 5, 45, 0, 0, 274, 275, 5, 45, 0, 0, 275, 50, 1, 0, 0, 0, 276, 277, 5, 114, 0, 0, 277, 278, 5, 101, 0, 0, 278, 279, 5, 113, 0, 0, 279, 280, 5, 117, 0, 0, 280, 281, 5, 105, 0, 0, 281, 282, 5, 114, 0, 0, 282, 283, 5, 101, 0, 0, 283, 52, 1, 0, 0, 0, 284, 285, 5, 99, 0, 0, 285, 286, 5, 111, 0, 0, 286, 287, 5, 110, 0, 0, 287, 288, 5, 115, 0, 0, 288, 289, 5, 111, 0, 0, 289, 290, 5, 108, 0, 0, 290, 291, 5, 101, 0, 0, 291, 292, 5, 46, 0, 0, 292, 293, 5, 108, 0, 0, 293, 294, 5, 111, 0, 0, 294, 295, 5, 103, 0, 0, 295, 54, 1, 0, 0, 0, 296, 297, 5, 105, 0, 0, 297, 298, 5, 102, 0, 0, 298, 56, 1, 0, 0, 0, 299, 300, 5, 101, 0, 0, 300, 301, 5, 108, 0, 0, 301, 302, 5, 115, 0, 0, 302, 303, 5, 101, 0, 0, 303, 58, 1, 0, 0, 0, 304, 305, 5, 100, 0, 0, 305, 306, 5, 111, 0, 0, 306, 60, 1, 0, 0, 0, 307, 308, 5, 119, 0, 0, 308, 309, 5, 104, 0, 0, 309, 310, 5, 105, 0, 0, 310, 311, 5, 108, 0, 0, 311, 312, 5, 101, 0, 0, 312, 62, 1, 0, 0, 0, 313, 314, 5, 102, 0, 0, 314, 315, 5, 111, 0, 0, 315, 316, 5, 114, 0, 0, 316, 64, 1, 0, 0, 0, 317, 318, 5, 110, 0, 0, 318, 319, 5, 101, 0, 0, 319, 320, 5, 119, 0, 0, 320, 66, 1, 0, 0, 0, 321, 322, 5, 91, 0, 0, 322, 68, 1, 0, 0, 0, 323, 324, 5, 93, 0, 0, 324, 70, 1, 0, 0, 0, 325, 326, 5, 116, 0, 0, 326, 327, 5, 120, 0, 0, 327, 328, 5, 46, 0, 0, 328, 329, 5, 111, 0, 0, 329, 330, 5, 117, 0, 0, 330, 331, 5, 116, 0, 0, 331, 332, 5, 112, 0, 0, 332, 333, 5, 117, 0, 0, 333, 334, 5, 116, 0, 0, 334, 335, 5, 115, 0, 0, 335, 72, 1, 0, 0, 0, 336, 337, 5, 46, 0, 0, 337, 338, 5, 118, 0, 0, 338, 339, 5, 97, 0, 0, 339, 340, 5, 108, 0, 0, 340, 341, 5, 117, 0, 0, 341, 342, 5, 101, 0, 0, 342, 74, 1, 0, 0, 0, 343, 344, 5, 46, 0, 0, 344, 345, 5, 108, 0, 0, 345, 346, 5, 111, 0, 0, 346, 347, 5, 99, 0, 0, 347, 348, 5, 107, 0, 0, 348, 349, 5, 105, 0, 0, 349, 350, 5, 110, 0, 0, 350, 351, 5, 103, 0, 0, 351, 352, 5, 66, 0, 0, 352, 353, 5, 121, 0, 0, 353, 354, 5, 116, 0, 0, 354, 355, 5, 101, 0, 0, 355, 356, 5, 99, 0, 0, 356, 357, 5, 111, 0, 0, 357, 358, 5, 100, 0, 0, 358, 359, 5, 101, 0, 0, 359, 76, 1, 0, 0, 0, 360, 361, 5, 46, 0, 0, 361, 362, 5, 116, 0, 0, 362, 363, 5, 111, 0, 0, 363, 364, 5, 107, 0, 0, 364, 365, 5, 101, 0, 0, 365, 366, 5, 110, 0, 0, 366, 367, 5, 67, 0, 0, 367, 368, 5, 97, 0, 0, 368, 369, 5, 116, 0, 0, 369, 370, 5, 101, 0, 0, 370, 371, 5, 103, 0, 0, 371, 372, 5, 111, 0, 0, 372, 373, 5, 114, 0, 0, 373, 374, 5, 121, 0, 0, 374, 78, 1, 0, 0, 0, 375, 376, 5, 46, 0, 0, 376, 377, 5, 110, 0, 0, 377, 378, 5, 102, 0, 0, 378, 379, 5, 116, 0, 0, 379, 380, 5, 67, 0, 0, 380, 381, 5, 111, 0, 0, 381, 382, 5, 109, 0, 0, 382, 383, 5, 109, 0, 0, 383, 384, 5, 105, 0, 0, 384, 385, 5, 116, 0, 0, 385, 386, 5, 109, 0, 0, 386, 387, 5, 101, 0, 0, 387, 388, 5, 110, 0, 0, 388, 389, 5, 116, 0, 0, 389, 80, 1, 0, 0, 0, 390, 391, 5, 46, 0, 0, 391, 392, 5, 116, 0, 0, 392, 393, 5, 111, 0, 0, 393, 394, 5, 107, 0, 0, 394, 395, 5, 101, 0, 0, 395, 396, 5, 110, 0, 0, 396, 397, 5, 65, 0, 0, 397, 398, 5, 109, 0, 0, 398, 399, 5, 111, 0, 0, 399, 400, 5, 117, 0, 0, 400, 401, 5, 110, 0, 0, 401, 402, 5, 116, 0, 0, 402, 82, 1, 0, 0, 0, 403, 404, 5, 116, 0, 0, 404, 405, 5, 120, 0, 0, 405, 406, 5, 46, 0, 0, 406, 407, 5, 105, 0, 0, 407, 408, 5, 110, 0, 0, 408, 409, 5, 112, 0, 0, 409, 410, 5, 117, 0, 0, 410, 411, 5, 116, 0, 0, 411, 412, 5, 115, 0, 0, 412, 84, 1, 0, 0, 0, 413, 414, 5, 46, 0, 0, 414, 415, 5, 111, 0, 0, 415, 416, 5, 117, 0, 0, 416, 417, 5, 116, 0, 0, 417, 418, 5, 112, 0, 0, 418, 419, 5, 111, 0, 0, 419, 420, 5, 105, 0, 0, 420, 421, 5, 110, 0, 0, 421, 422, 5, 116, 0, 0, 422, 423, 5, 84, 0, 0, 423, 424, 5, 114, 0, 0, 424, 425, 5, 97, 0, 0, 425, 426, 5, 110, 0, 0, 426, 427, 5, 115, 0, 0, 427, 428, 5, 97, 0, 0, 428, 429, 5, 99, 0, 0, 429, 430, 5, 116, 0, 0, 430, 431, 5, 105, 0, 0, 431, 432, 5, 111, 0, 0, 432, 433, 5, 110, 0, 0, 433, 434, 5, 72, 0, 0, 434, 435, 5, 97, 0, 0, 435, 436, 5, 115, 0, 0, 436, 437, 5, 104, 0, 0, 437, 86, 1, 0, 0, 0, 438, 439, 5, 46, 0, 0, 439, 440, 5, 111, 0, 0, 440, 441, 5, 117, 0, 0, 441, 442, 5, 116, 0, 0, 442, 443, 5, 112, 0, 0, 443, 444, 5, 111, 0, 0, 444, 445, 5, 105, 0, 0, 445, 446, 5, 110, 0, 0, 446, 447, 5, 116, 0, 0, 447, 448, 5, 73, 0, 0, 448, 449, 5, 110, 0, 0, 449, 450, 5, 100, 0, 0, 450, 451, 5, 101, 0, 0, 451, 452, 5, 120, 0, 0, 452, 88, 1, 0, 0, 0, 453, 454, 5, 46, 0, 0, 454, 455, 5, 117, 0, 0, 455, 456, 5, 110, 0, 0, 456, 457, 5, 108, 0, 0, 457, 458, 5, 111, 0, 0, 458, 459, 5, 99, 0, 0, 459, 460, 5, 107, 0, 0, 460, 461, 5, 105, 0, 0, 461, 462, 5, 110, 0, 0, 462, 463, 5, 103, 0, 0, 463, 464, 5, 66, 0, 0, 464, 465, 5, 121, 0, 0, 465, 466, 5, 116, 0, 0, 466, 467, 5, 101, 0, 0, 467, 468, 5, 99, 0, 0, 468, 469, 5, 111, 0, 0, 469, 470, 5, 100, 0, 0, 470, 471, 5, 101, 0, 0, 471, 90, 1, 0, 0, 0, 472, 473, 5, 46, 0, 0, 473, 474, 5, 115, 0, 0, 474, 475, 5, 101, 0, 0, 475, 476, 5, 113, 0, 0, 476, 477, 5, 117, 0, 0, 477, 478, 5, 101, 0, 0, 478, 479, 5, 110, 0, 0, 479, 480, 5, 99, 0, 0, 480, 481, 5, 101, 0, 0, 481, 482, 5, 78, 0, 0, 482, 483, 5, 117, 0, 0, 483, 484, 5, 109, 0, 0, 484, 485, 5, 98, 0, 0, 485, 486, 5, 101, 0, 0, 486, 487, 5, 114, 0, 0, 487, 92, 1, 0, 0, 0, 488, 489, 5, 46, 0, 0, 489, 490, 5, 114, 0, 0, 490, 491, 5, 101, 0, 0, 491, 492, 5, 118, 0, 0, 492, 493, 5, 101, 0, 0, 493, 494, 5, 114, 0, 0, 494, 495, 5, 115, 0, 0, 495, 496, 5, 101, 0, 0, 496, 497, 5, 40, 0, 0, 497, 498, 5, 41, 0, 0, 498, 94, 1, 0, 0, 0, 499, 500, 5, 46, 0, 0, 500, 501, 5, 108, 0, 0, 501, 502, 5, 101, 0, 0, 502, 503, 5, 110, 0, 0, 503, 504, 5, 103, 0, 0, 504, 505, 5, 116, 0, 0, 505, 506, 5, 104, 0, 0, 506, 96, 1, 0, 0, 0, 507, 508, 5, 46, 0, 0, 508, 509, 5, 115, 0, 0, 509, 510, 5, 112, 0, 0, 510, 511, 5, 108, 0, 0, 511, 512, 5, 105, 0, 0, 512, 513, 5, 116, 0, 0, 513, 98, 1, 0, 0, 0, 514, 515, 5, 46, 0, 0, 515, 516, 5, 115, 0, 0, 516, 517, 5, 108, 0, 0, 517, 518, 5, 105, 0, 0, 518, 519, 5, 99, 0, 0, 519, 520, 5, 101, 0, 0, 520, 100, 1, 0, 0, 0, 521, 522, 5, 33, 0, 0, 522, 102, 1, 0, 0, 0, 523, 524, 5, 45, 0, 0, 524, 104, 1, 0, 0, 0, 525, 526, 5, 42, 0, 0, 526, 106, 1, 0, 0, 0, 527, 528, 5, 47, 0, 0, 528, 108, 1, 0, 0, 0, 529, 530, 5, 37, 0, 0, 530, 110, 1, 0, 0, 0, 531, 532, 5, 43, 0, 0, 532, 112, 1, 0, 0, 0, 533, 534, 5, 62, 0, 0, 534, 535, 5, 62, 0, 0, 535, 114, 1, 0, 0, 0, 536, 537, 5, 60, 0, 0, 537, 538, 5, 60, 0, 0, 538, 116, 1, 0, 0, 0, 539, 540, 5, 61, 0, 0, 540, 541, 5, 61, 0, 0, 541, 118, 1, 0, 0, 0, 542, 543, 5, 33, 0, 0, 543, 544, 5, 61, 0, 0, 544, 120, 1, 0, 0, 0, 545, 546, 5, 38, 0, 0, 546, 122, 1, 0, 0, 0, 547, 548, 5, 124, 0, 0, 548, 124, 1, 0, 0, 0, 549, 550, 5, 38, 0, 0, 550, 551, 5, 38, 0, 0, 551, 126, 1, 0, 0, 0, 552, 553, 5, 124, 0, 0, 553, 554, 5, 124, 0, 0, 554, 128, 1, 0, 0, 0, 555, 557, 7, 0, 0, 0, 556, 555, 1, 0, 0, 0, 557, 558, 1, 0, 0, 0, 558, 556, 1, 0, 0, 0, 558, 559, 1, 0, 0, 0, 559, 560, 1, 0, 0, 0, 560, 562, 5, 46, 0, 0, 561, 563, 7, 0, 0, 0, 562, 561, 1, 0, 0, 0, 563, 564, 1, 0, 0, 0, 564, 562, 1, 0, 0, 0, 564, 565, 1, 0, 0, 0, 565, 566, 1, 0, 0, 0, 566, 568, 5, 46, 0, 0, 567, 569, 7, 0, 0, 0, 568, 567, 1, 0, 0, 0, 569, 570, 1, 0, 0, 0, 570, 568, 1, 0, 0, 0, 570, 571, 1, 0, 0, 0, 571, 130, 1, 0, 0, 0, 572, 573, 5, 116, 0, 0, 573, 574, 5, 114, 0, 0, 574, 575, 5, 117, 0, 0, 575, 582, 5, 101, 0, 0, 576, 577, 5, 102, 0, 0, 577, 578, 5, 97, 0, 0, 578, 579, 5, 108, 0, 0, 579, 580, 5, 115, 0, 0, 580, 582, 5, 101, 0, 0, 581, 572, 1, 0, 0, 0, 581, 576, 1, 0, 0, 0, 582, 132, 1, 0, 0, 0, 583, 584, 5, 115, 0, 0, 584, 585, 5, 97, 0, 0, 585, 586, 5, 116, 0, 0, 586, 587, 5, 111, 0, 0, 587, 588, 5, 115, 0, 0, 588, 589, 5, 104, 0, 0, 589, 590, 5, 105, 0, 0, 590, 641, 5, 115, 0, 0, 591, 592, 5, 115, 0, 0, 592, 593, 5, 97, 0, 0, 593, 594, 5, 116, 0, 0, 594, 641, 5, 115, 0, 0, 595, 596, 5, 102, 0, 0, 596, 597, 5, 105, 0, 0, 597, 598, 5, 110, 0, 0, 598, 599, 5, 110, 0, 0, 599, 600, 5, 101, 0, 0, 600, 641, 5, 121, 0, 0, 601, 602, 5, 98, 0, 0, 602, 603, 5, 105, 0, 0, 603, 604, 5, 116, 0, 0, 604, 641, 5, 115, 0, 0, 605, 606, 5, 98, 0, 0, 606, 607, 5, 105, 0, 0, 607, 608, 5, 116, 0, 0, 608, 609, 5, 99, 0, 0, 609, 610, 5, 111, 0, 0, 610, 611, 5, 105, 0, 0, 611, 641, 5, 110, 0, 0, 612, 613, 5, 115, 0, 0, 613, 614, 5, 101, 0, 0, 614, 615, 5, 99, 0, 0, 615, 616, 5, 111, 0, 0, 616, 617, 5, 110, 0, 0, 617, 618, 5, 100, 0, 0, 618, 641, 5, 115, 0, 0, 619, 620, 5, 109, 0, 0, 620, 621, 5, 105, 0, 0, 621, 622, 5, 110, 0, 0, 622, 623, 5, 117, 0, 0, 623, 624, 5, 116, 0, 0, 624, 625, 5, 101, 0, 0, 625, 641, 5, 115, 0, 0, 626, 627, 5, 104, 0, 0, 627, 628, 5, 111, 0, 0, 628, 629, 5, 117, 0, 0, 629, 630, 5, 114, 0, 0, 630, 641, 5, 115, 0, 0, 631, 632, 5, 100, 0, 0, 632, 633, 5, 97, 0, 0, 633, 634, 5, 121, 0, 0, 634, 641, 5, 115, 0, 0, 635, 636, 5, 119, 0, 0, 636, 637, 5, 101, 0, 0, 637, 638, 5, 101, 0, 0, 638, 639, 5, 107, 0, 0, 639, 641, 5, 115, 0, 0, 640, 583, 1, 0, 0, 0, 640, 591, 1, 0, 0, 0, 640, 595, 1, 0, 0, 0, 640, 601, 1, 0, 0, 0, 640, 605, 1, 0, 0, 0, 640, 612, 1, 0, 0, 0, 640, 619, 1, 0, 0, 0, 640, 626, 1, 0, 0, 0, 640, 631, 1, 0, 0, 0, 640, 635, 1, 0, 0, 0, 641, 134, 1, 0, 0, 0, 642, 644, 5, 45, 0, 0, 643, 642, 1, 0, 0, 0, 643, 644, 1, 0, 0, 0, 644, 645, 1, 0, 0, 0, 645, 647, 3, 137, 68, 0, 646, 648, 3, 139, 69, 0, 647, 646, 1, 0, 0, 0, 647, 648, 1, 0, 0, 0, 648, 136, 1, 0, 0, 0, 649, 651, 7, 0, 0, 0, 650, 649, 1, 0, 0, 0, 651, 652, 1, 0, 0, 0, 652, 650, 1, 0, 0, 0, 652, 653, 1, 0, 0, 0, 653, 662, 1, 0, 0, 0, 654, 656, 5, 95, 0, 0, 655, 657, 7, 0, 0, 0, 656, 655, 1, 0, 0, 0, 657, 658, 1, 0, 0, 0, 658, 656, 1, 0, 0, 0, 658, 659, 1, 0, 0, 0, 659, 661, 1, 0, 0, 0, 660, 654, 1, 0, 0, 0, 661, 664, 1, 0, 0, 0, 662, 660, 1, 0, 0, 0, 662, 663, 1, 0, 0, 0, 663, 138, 1, 0, 0, 0, 664, 662, 1, 0, 0, 0, 665, 666, 7, 1, 0, 0, 666, 667, 3, 137, 68, 0, 667, 140, 1, 0, 0, 0, 668, 669, 5, 105, 0, 0, 669, 670, 5, 110, 0, 0, 670, 698, 5, 116, 0, 0, 671, 672, 5, 98, 0, 0, 672, 673, 5, 111, 0, 0, 673, 674, 5, 111, 0, 0, 674, 698, 5, 108, 0, 0, 675, 676, 5, 115, 0, 0, 676, 677, 5, 116, 0, 0, 677, 678, 5, 114, 0, 0, 678, 679, 5, 105, 0, 0, 679, 680, 5, 110, 0, 0, 680, 698, 5, 103, 0, 0, 681, 682, 5, 112, 0, 0, 682, 683, 5, 117, 0, 0, 683, 684, 5, 98, 0, 0, 684, 685, 5, 107, 0, 0, 685, 686, 5, 101, 0, 0, 686, 698, 5, 121, 0, 0, 687, 688, 5, 115, 0, 0, 688, 689, 5, 105, 0, 0, 689, 698, 5, 103, 0, 0, 690, 691, 5, 100, 0, 0, 691, 692, 5, 97, 0, 0, 692, 693, 5, 116, 0, 0, 693, 694, 5, 97, 0, 0, 694, 695, 5, 115, 0, 0, 695, 696, 5, 105, 0, 0, 696, 698, 5, 103, 0, 0, 697, 668, 1, 0, 0, 0, 697, 671, 1, 0, 0, 0, 697, 675, 1, 0, 0, 0, 697, 681, 1, 0, 0, 0, 697, 687, 1, 0, 0, 0, 697, 690, 1, 0, 0, 0, 698, 142, 1, 0, 0, 0, 699, 700, 5, 98, 0, 0, 700, 701, 5, 121, 0, 0, 701, 702, 5, 116, 0, 0, 702, 703, 5, 101, 0, 0, 703, 704, 5, 115, 0, 0, 704, 144, 1, 0, 0, 0, 705, 706, 5, 98, 0, 0, 706, 707, 5, 121, 0, 0, 707, 708, 5, 116, 0, 0, 708, 709, 5, 101, 0, 0, 709, 710, 5, 115, 0, 0, 710, 711, 1, 0, 0, 0, 711, 717, 3, 147, 73, 0, 712, 713, 5, 98, 0, 0, 713, 714, 5, 121, 0, 0, 714, 715, 5, 116, 0, 0, 715, 717, 5, 101, 0, 0, 716, 705, 1, 0, 0, 0, 716, 712, 1, 0, 0, 0, 717, 146, 1, 0, 0, 0, 718, 722, 7, 2, 0, 0, 719, 721, 7, 0, 0, 0, 720, 719, 1, 0, 0, 0, 721, 724, 1, 0, 0, 0, 722, 720, 1, 0, 0, 0, 722, 723, 1, 0, 0, 0, 723, 148, 1, 0, 0, 0, 724, 722, 1, 0, 0, 0, 725, 731, 5, 34, 0, 0, 726, 727, 5, 92, 0, 0, 727, 730, 5, 34, 0, 0, 728, 730, 8, 3, 0, 0, 729, 726, 1, 0, 0, 0, 729, 728, 1, 0, 0, 0, 730, 733, 1, 0, 0, 0, 731, 732, 1, 0, 0, 0, 731, 729, 1, 0, 0, 0, 732, 734, 1, 0, 0, 0, 733, 731, 1, 0, 0, 0, 734, 746, 5, 34, 0, 0, 735, 741, 5, 39, 0, 0, 736, 737, 5, 92, 0, 0, 737, 740, 5, 39, 0, 0, 738, 740, 8, 4, 0, 0, 739, 736, 1, 0, 0, 0, 739, 738, 1, 0, 0, 0, 740, 743, 1, 0, 0, 0, 741, 742, 1, 0, 0, 0, 741, 739, 1, 0, 0, 0, 742, 744, 1, 0, 0, 0, 743, 741, 1, 0, 0, 0, 744, 746, 5, 39, 0, 0, 745, 725, 1, 0, 0, 0, 745, 735, 1, 0, 0, 0, 746, 150, 1, 0, 0, 0, 747, 748, 5, 100, 0, 0, 748, 749, 5, 97, 0, 0, 749, 750, 5, 116, 0, 0, 750, 751, 5, 101, 0, 0, 751, 752, 5, 40, 0, 0, 752, 753, 1, 0, 0, 0, 753, 754, 3, 149, 74, 0, 754, 755, 5, 41, 0, 0, 755, 152, 1, 0, 0, 0, 756, 757, 5, 48, 0, 0, 757, 761, 7, 5, 0, 0, 758, 760, 7, 6, 0, 0, 759, 758, 1, 0, 0, 0, 760, 763, 1, 0, 0, 0, 761, 759, 1, 0, 0, 0, 761, 762, 1, 0, 0, 0, 762, 154, 1, 0, 0, 0, 763, 761, 1, 0, 0, 0, 764, 765, 5, 116, 0, 0, 765, 766, 5, 104, 0, 0, 766, 767, 5, 105, 0, 0, 767, 768, 5, 115, 0, 0, 768, 769, 5, 46, 0, 0, 769, 770, 5, 97, 0, 0, 770, 771, 5, 103, 0, 0, 771, 780, 5, 101, 0, 0, 772, 773, 5, 116, 0, 0, 773, 774, 5, 120, 0, 0, 774, 775, 5, 46, 0, 0, 775, 776, 5, 116, 0, 0, 776, 777, 5, 105, 0, 0, 777, 778, 5, 109, 0, 0, 778, 780, 5, 101, 0, 0, 779, 764, 1, 0, 0, 0, 779, 772, 1, 0, 0, 0, 780, 156, 1, 0, 0, 0, 781, 782, 5, 117, 0, 0, 782, 783, 5, 110, 0, 0, 783, 784, 5, 115, 0, 0, 784, 785, 5, 97, 0, 0, 785, 786, 5, 102, 0, 0, 786, 787, 5, 101, 0, 0, 787, 788, 5, 95, 0, 0, 788, 789, 5, 105, 0, 0, 789, 790, 5, 110, 0, 0, 790, 830, 5, 116, 0, 0, 791, 792, 5, 117, 0, 0, 792, 793, 5, 110, 0, 0, 793, 794, 5, 115, 0, 0, 794, 795, 5, 97, 0, 0, 795, 796, 5, 102, 0, 0, 796, 797, 5, 101, 0, 0, 797, 798, 5, 95, 0, 0, 798, 799, 5, 98, 0, 0, 799, 800, 5, 111, 0, 0, 800, 801, 5, 111, 0, 0, 801, 830, 5, 108, 0, 0, 802, 803, 5, 117, 0, 0, 803, 804, 5, 110, 0, 0, 804, 805, 5, 115, 0, 0, 805, 806, 5, 97, 0, 0, 806, 807, 5, 102, 0, 0, 807, 808, 5, 101, 0, 0, 808, 809, 5, 95, 0, 0, 809, 810, 5, 98, 0, 0, 810, 811, 5, 121, 0, 0, 811, 812, 5, 116, 0, 0, 812, 813, 5, 101, 0, 0, 813, 814, 5, 115, 0, 0, 814, 816, 1, 0, 0, 0, 815, 817, 3, 147, 73, 0, 816, 815, 1, 0, 0, 0, 816, 817, 1, 0, 0, 0, 817, 830, 1, 0, 0, 0, 818, 819, 5, 117, 0, 0, 819, 820, 5, 110, 0, 0, 820, 821, 5, 115, 0, 0, 821, 822, 5, 97, 0, 0, 822, 823, 5, 102, 0, 0, 823, 824, 5, 101, 0, 0, 824, 825, 5, 95, 0, 0, 825, 826, 5, 98, 0, 0, 826, 827, 5, 121, 0, 0, 827, 828, 5, 116, 0, 0, 828, 830, 5, 101, 0, 0, 829, 781, 1, 0, 0, 0, 829, 791, 1, 0, 0, 0, 829, 802, 1, 0, 0, 0, 829, 818, 1, 0, 0, 0, 830, 158, 1, 0, 0, 0, 831, 832, 5, 116, 0, 0, 832, 833, 5, 104, 0, 0, 833, 834, 5, 105, 0, 0, 834, 835, 5, 115, 0, 0, 835, 836, 5, 46, 0, 0, 836, 837, 5, 97, 0, 0, 837, 838, 5, 99, 0, 0, 838, 839, 5, 116, 0, 0, 839, 840, 5, 105, 0, 0, 840, 841, 5, 118, 0, 0, 841, 842, 5, 101, 0, 0, 842, 843, 5, 73, 0, 0, 843, 844, 5, 110, 0, 0, 844, 845, 5, 112, 0, 0, 845, 846, 5, 117, 0, 0, 846, 847, 5, 116, 0, 0, 847, 848, 5, 73, 0, 0, 848, 849, 5, 110, 0, 0, 849, 850, 5, 100, 0, 0, 850, 851, 5, 101, 0, 0, 851, 926, 5, 120, 0, 0, 852, 853, 5, 116, 0, 0, 853, 854, 5, 104, 0, 0, 854, 855, 5, 105, 0, 0, 855, 856, 5, 115, 0, 0, 856, 857, 5, 46, 0, 0, 857, 858, 5, 97, 0, 0, 858, 859, 5, 99, 0, 0, 859, 860, 5, 116, 0, 0, 860, 861, 5, 105, 0, 0, 861, 862, 5, 118, 0, 0, 862, 863, 5, 101, 0, 0, 863, 864, 5, 66, 0, 0, 864, 865, 5, 121, 0, 0, 865, 866, 5, 116, 0, 0, 866, 867, 5, 101, 0, 0, 867, 868, 5, 99, 0, 0, 868, 869, 5, 111, 0, 0, 869, 870, 5, 100, 0, 0, 870, 926, 5, 101, 0, 0, 871, 872, 5, 116, 0, 0, 872, 873, 5, 120, 0, 0, 873, 874, 5, 46, 0, 0, 874, 875, 5, 105, 0, 0, 875, 876, 5, 110, 0, 0, 876, 877, 5, 112, 0, 0, 877, 878, 5, 117, 0, 0, 878, 879, 5, 116, 0, 0, 879, 880, 5, 115, 0, 0, 880, 881, 5, 46, 0, 0, 881, 882, 5, 108, 0, 0, 882, 883, 5, 101, 0, 0, 883, 884, 5, 110, 0, 0, 884, 885, 5, 103, 0, 0, 885, 886, 5, 116, 0, 0, 886, 926, 5, 104, 0, 0, 887, 888, 5, 116, 0, 0, 888, 889, 5, 120, 0, 0, 889, 890, 5, 46, 0, 0, 890, 891, 5, 111, 0, 0, 891, 892, 5, 117, 0, 0, 892, 893, 5, 116, 0, 0, 893, 894, 5, 112, 0, 0, 894, 895, 5, 117, 0, 0, 895, 896, 5, 116, 0, 0, 896, 897, 5, 115, 0, 0, 897, 898, 5, 46, 0, 0, 898, 899, 5, 108, 0, 0, 899, 900, 5, 101, 0, 0, 900, 901, 5, 110, 0, 0, 901, 902, 5, 103, 0, 0, 902, 903, 5, 116, 0, 0, 903, 926, 5, 104, 0, 0, 904, 905, 5, 116, 0, 0, 905, 906, 5, 120, 0, 0, 906, 907, 5, 46, 0, 0, 907, 908, 5, 118, 0, 0, 908, 909, 5, 101, 0, 0, 909, 910, 5, 114, 0, 0, 910, 911, 5, 115, 0, 0, 911, 912, 5, 105, 0, 0, 912, 913, 5, 111, 0, 0, 913, 926, 5, 110, 0, 0, 914, 915, 5, 116, 0, 0, 915, 916, 5, 120, 0, 0, 916, 917, 5, 46, 0, 0, 917, 918, 5, 108, 0, 0, 918, 919, 5, 111, 0, 0, 919, 920, 5, 99, 0, 0, 920, 921, 5, 107, 0, 0, 921, 922, 5, 116, 0, 0, 922, 923, 5, 105, 0, 0, 923, 924, 5, 109, 0, 0, 924, 926, 5, 101, 0, 0, 925, 831, 1, 0, 0, 0, 925, 852, 1, 0, 0, 0, 925, 871, 1, 0, 0, 0, 925, 887, 1, 0, 0, 0, 925, 904, 1, 0, 0, 0, 925, 914, 1, 0, 0, 0, 926, 160, 1, 0, 0, 0, 927, 931, 7, 7, 0, 0, 928, 930, 7, 8, 0, 0, 929, 928, 1, 0, 0, 0, 930, 933, 1, 0, 0, 0, 931, 929, 1, 0, 0, 0, 931, 932, 1, 0, 0, 0, 932, 162, 1, 0, 0, 0, 933, 931, 1, 0, 0, 0, 934, 936, 7, 9, 0, 0, 935, 934, 1, 0, 0, 0, 936, 937, 1, 0, 0, 0, 937, 935, 1, 0, 0, 0, 937, 938, 1, 0, 0, 0, 938, 939, 1, 0, 0, 0, 939, 940, 6, 81, 0, 0, 940, 164, 1, 0, 0, 0, 941, 942, 5, 47, 0, 0, 942, 943, 5, 42, 0, 0, 943, 947, 1, 0, 0, 0, 944, 946, 9, 0, 0, 0, 945, 944, 1, 0, 0, 0, 946, 949, 1, 0, 0, 0, 947, 948, 1, 0, 0, 0, 947, 945, 1, 0, 0, 0, 948, 950, 1, 0, 0, 0, 949, 947, 1, 0, 0, 0, 950, 951, 5, 42, 0, 0, 951, 952, 5, 47, 0, 0, 952, 953, 1, 0, 0, 0, 953, 954, 6, 82, 1, 0, 954, 166, 1, 0, 0, 0, 955, 956, 5, 47, 0, 0, 956, 957, 5, 47, 0, 0, 957, 961, 1, 0, 0, 0, 958, 960, 8, 10, 0, 0, 959, 958, 1, 0, 0, 0, 960, 963, 1, 0, 0, 0, 961, 959, 1, 0, 0, 0, 961, 962, 1, 0, 0, 0, 962, 964, 1, 0, 0, 0, 963, 961, 1, 0, 0, 0, 964, 965, 6, 83, 1, 0, 965, 168, 1, 0, 0, 0, 28, 0, 558, 564, 570, 581, 640, 643, 647, 652, 658, 662, 697, 716, 722, 729, 731, 739, 741, 745, 761, 779, 816, 829, 925, 931, 937, 947, 961, 2, 6, 0, 0, 0, 1, 0] \ No newline at end of file +[4, 0, 85, 975, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62, 7, 62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67, 2, 68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72, 2, 73, 7, 73, 2, 74, 7, 74, 2, 75, 7, 75, 2, 76, 7, 76, 2, 77, 7, 77, 2, 78, 7, 78, 2, 79, 7, 79, 2, 80, 7, 80, 2, 81, 7, 81, 2, 82, 7, 82, 2, 83, 7, 83, 2, 84, 7, 84, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 6, 1, 6, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 14, 1, 14, 1, 15, 1, 15, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 18, 1, 18, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 23, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 27, 1, 27, 1, 27, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 29, 1, 29, 1, 29, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 1, 32, 1, 32, 1, 33, 1, 33, 1, 34, 1, 34, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 50, 1, 50, 1, 51, 1, 51, 1, 52, 1, 52, 1, 53, 1, 53, 1, 54, 1, 54, 1, 55, 1, 55, 1, 56, 1, 56, 1, 56, 1, 57, 1, 57, 1, 57, 1, 58, 1, 58, 1, 58, 1, 59, 1, 59, 1, 59, 1, 60, 1, 60, 1, 61, 1, 61, 1, 62, 1, 62, 1, 62, 1, 63, 1, 63, 1, 63, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 65, 4, 65, 566, 8, 65, 11, 65, 12, 65, 567, 1, 65, 1, 65, 4, 65, 572, 8, 65, 11, 65, 12, 65, 573, 1, 65, 1, 65, 4, 65, 578, 8, 65, 11, 65, 12, 65, 579, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 3, 66, 591, 8, 66, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 3, 67, 650, 8, 67, 1, 68, 3, 68, 653, 8, 68, 1, 68, 1, 68, 3, 68, 657, 8, 68, 1, 69, 4, 69, 660, 8, 69, 11, 69, 12, 69, 661, 1, 69, 1, 69, 4, 69, 666, 8, 69, 11, 69, 12, 69, 667, 5, 69, 670, 8, 69, 10, 69, 12, 69, 673, 9, 69, 1, 70, 1, 70, 1, 70, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 3, 71, 707, 8, 71, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 3, 73, 726, 8, 73, 1, 74, 1, 74, 5, 74, 730, 8, 74, 10, 74, 12, 74, 733, 9, 74, 1, 75, 1, 75, 1, 75, 1, 75, 5, 75, 739, 8, 75, 10, 75, 12, 75, 742, 9, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 5, 75, 749, 8, 75, 10, 75, 12, 75, 752, 9, 75, 1, 75, 3, 75, 755, 8, 75, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 77, 1, 77, 1, 77, 5, 77, 769, 8, 77, 10, 77, 12, 77, 772, 9, 77, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 3, 78, 789, 8, 78, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 3, 79, 826, 8, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 3, 79, 839, 8, 79, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 3, 80, 935, 8, 80, 1, 81, 1, 81, 5, 81, 939, 8, 81, 10, 81, 12, 81, 942, 9, 81, 1, 82, 4, 82, 945, 8, 82, 11, 82, 12, 82, 946, 1, 82, 1, 82, 1, 83, 1, 83, 1, 83, 1, 83, 5, 83, 955, 8, 83, 10, 83, 12, 83, 958, 9, 83, 1, 83, 1, 83, 1, 83, 1, 83, 1, 83, 1, 84, 1, 84, 1, 84, 1, 84, 5, 84, 969, 8, 84, 10, 84, 12, 84, 972, 9, 84, 1, 84, 1, 84, 3, 740, 750, 956, 0, 85, 1, 1, 3, 2, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, 17, 9, 19, 10, 21, 11, 23, 12, 25, 13, 27, 14, 29, 15, 31, 16, 33, 17, 35, 18, 37, 19, 39, 20, 41, 21, 43, 22, 45, 23, 47, 24, 49, 25, 51, 26, 53, 27, 55, 28, 57, 29, 59, 30, 61, 31, 63, 32, 65, 33, 67, 34, 69, 35, 71, 36, 73, 37, 75, 38, 77, 39, 79, 40, 81, 41, 83, 42, 85, 43, 87, 44, 89, 45, 91, 46, 93, 47, 95, 48, 97, 49, 99, 50, 101, 51, 103, 52, 105, 53, 107, 54, 109, 55, 111, 56, 113, 57, 115, 58, 117, 59, 119, 60, 121, 61, 123, 62, 125, 63, 127, 64, 129, 65, 131, 66, 133, 67, 135, 68, 137, 69, 139, 70, 141, 71, 143, 72, 145, 73, 147, 74, 149, 75, 151, 76, 153, 77, 155, 78, 157, 79, 159, 80, 161, 81, 163, 82, 165, 83, 167, 84, 169, 85, 1, 0, 11, 1, 0, 48, 57, 2, 0, 69, 69, 101, 101, 1, 0, 49, 57, 3, 0, 10, 10, 13, 13, 34, 34, 3, 0, 10, 10, 13, 13, 39, 39, 2, 0, 88, 88, 120, 120, 3, 0, 48, 57, 65, 70, 97, 102, 2, 0, 65, 90, 97, 122, 4, 0, 48, 57, 65, 90, 95, 95, 97, 122, 3, 0, 9, 10, 12, 13, 32, 32, 2, 0, 10, 10, 13, 13, 1019, 0, 1, 1, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 9, 1, 0, 0, 0, 0, 11, 1, 0, 0, 0, 0, 13, 1, 0, 0, 0, 0, 15, 1, 0, 0, 0, 0, 17, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 0, 21, 1, 0, 0, 0, 0, 23, 1, 0, 0, 0, 0, 25, 1, 0, 0, 0, 0, 27, 1, 0, 0, 0, 0, 29, 1, 0, 0, 0, 0, 31, 1, 0, 0, 0, 0, 33, 1, 0, 0, 0, 0, 35, 1, 0, 0, 0, 0, 37, 1, 0, 0, 0, 0, 39, 1, 0, 0, 0, 0, 41, 1, 0, 0, 0, 0, 43, 1, 0, 0, 0, 0, 45, 1, 0, 0, 0, 0, 47, 1, 0, 0, 0, 0, 49, 1, 0, 0, 0, 0, 51, 1, 0, 0, 0, 0, 53, 1, 0, 0, 0, 0, 55, 1, 0, 0, 0, 0, 57, 1, 0, 0, 0, 0, 59, 1, 0, 0, 0, 0, 61, 1, 0, 0, 0, 0, 63, 1, 0, 0, 0, 0, 65, 1, 0, 0, 0, 0, 67, 1, 0, 0, 0, 0, 69, 1, 0, 0, 0, 0, 71, 1, 0, 0, 0, 0, 73, 1, 0, 0, 0, 0, 75, 1, 0, 0, 0, 0, 77, 1, 0, 0, 0, 0, 79, 1, 0, 0, 0, 0, 81, 1, 0, 0, 0, 0, 83, 1, 0, 0, 0, 0, 85, 1, 0, 0, 0, 0, 87, 1, 0, 0, 0, 0, 89, 1, 0, 0, 0, 0, 91, 1, 0, 0, 0, 0, 93, 1, 0, 0, 0, 0, 95, 1, 0, 0, 0, 0, 97, 1, 0, 0, 0, 0, 99, 1, 0, 0, 0, 0, 101, 1, 0, 0, 0, 0, 103, 1, 0, 0, 0, 0, 105, 1, 0, 0, 0, 0, 107, 1, 0, 0, 0, 0, 109, 1, 0, 0, 0, 0, 111, 1, 0, 0, 0, 0, 113, 1, 0, 0, 0, 0, 115, 1, 0, 0, 0, 0, 117, 1, 0, 0, 0, 0, 119, 1, 0, 0, 0, 0, 121, 1, 0, 0, 0, 0, 123, 1, 0, 0, 0, 0, 125, 1, 0, 0, 0, 0, 127, 1, 0, 0, 0, 0, 129, 1, 0, 0, 0, 0, 131, 1, 0, 0, 0, 0, 133, 1, 0, 0, 0, 0, 135, 1, 0, 0, 0, 0, 137, 1, 0, 0, 0, 0, 139, 1, 0, 0, 0, 0, 141, 1, 0, 0, 0, 0, 143, 1, 0, 0, 0, 0, 145, 1, 0, 0, 0, 0, 147, 1, 0, 0, 0, 0, 149, 1, 0, 0, 0, 0, 151, 1, 0, 0, 0, 0, 153, 1, 0, 0, 0, 0, 155, 1, 0, 0, 0, 0, 157, 1, 0, 0, 0, 0, 159, 1, 0, 0, 0, 0, 161, 1, 0, 0, 0, 0, 163, 1, 0, 0, 0, 0, 165, 1, 0, 0, 0, 0, 167, 1, 0, 0, 0, 0, 169, 1, 0, 0, 0, 1, 171, 1, 0, 0, 0, 3, 178, 1, 0, 0, 0, 5, 180, 1, 0, 0, 0, 7, 191, 1, 0, 0, 0, 9, 193, 1, 0, 0, 0, 11, 195, 1, 0, 0, 0, 13, 198, 1, 0, 0, 0, 15, 200, 1, 0, 0, 0, 17, 202, 1, 0, 0, 0, 19, 205, 1, 0, 0, 0, 21, 207, 1, 0, 0, 0, 23, 214, 1, 0, 0, 0, 25, 223, 1, 0, 0, 0, 27, 231, 1, 0, 0, 0, 29, 233, 1, 0, 0, 0, 31, 235, 1, 0, 0, 0, 33, 237, 1, 0, 0, 0, 35, 246, 1, 0, 0, 0, 37, 255, 1, 0, 0, 0, 39, 257, 1, 0, 0, 0, 41, 259, 1, 0, 0, 0, 43, 266, 1, 0, 0, 0, 45, 269, 1, 0, 0, 0, 47, 272, 1, 0, 0, 0, 49, 275, 1, 0, 0, 0, 51, 278, 1, 0, 0, 0, 53, 286, 1, 0, 0, 0, 55, 298, 1, 0, 0, 0, 57, 301, 1, 0, 0, 0, 59, 306, 1, 0, 0, 0, 61, 309, 1, 0, 0, 0, 63, 315, 1, 0, 0, 0, 65, 319, 1, 0, 0, 0, 67, 323, 1, 0, 0, 0, 69, 325, 1, 0, 0, 0, 71, 327, 1, 0, 0, 0, 73, 338, 1, 0, 0, 0, 75, 345, 1, 0, 0, 0, 77, 362, 1, 0, 0, 0, 79, 377, 1, 0, 0, 0, 81, 392, 1, 0, 0, 0, 83, 405, 1, 0, 0, 0, 85, 415, 1, 0, 0, 0, 87, 440, 1, 0, 0, 0, 89, 455, 1, 0, 0, 0, 91, 474, 1, 0, 0, 0, 93, 490, 1, 0, 0, 0, 95, 501, 1, 0, 0, 0, 97, 509, 1, 0, 0, 0, 99, 516, 1, 0, 0, 0, 101, 523, 1, 0, 0, 0, 103, 525, 1, 0, 0, 0, 105, 527, 1, 0, 0, 0, 107, 529, 1, 0, 0, 0, 109, 531, 1, 0, 0, 0, 111, 533, 1, 0, 0, 0, 113, 535, 1, 0, 0, 0, 115, 538, 1, 0, 0, 0, 117, 541, 1, 0, 0, 0, 119, 544, 1, 0, 0, 0, 121, 547, 1, 0, 0, 0, 123, 549, 1, 0, 0, 0, 125, 551, 1, 0, 0, 0, 127, 554, 1, 0, 0, 0, 129, 557, 1, 0, 0, 0, 131, 565, 1, 0, 0, 0, 133, 590, 1, 0, 0, 0, 135, 649, 1, 0, 0, 0, 137, 652, 1, 0, 0, 0, 139, 659, 1, 0, 0, 0, 141, 674, 1, 0, 0, 0, 143, 706, 1, 0, 0, 0, 145, 708, 1, 0, 0, 0, 147, 725, 1, 0, 0, 0, 149, 727, 1, 0, 0, 0, 151, 754, 1, 0, 0, 0, 153, 756, 1, 0, 0, 0, 155, 765, 1, 0, 0, 0, 157, 788, 1, 0, 0, 0, 159, 838, 1, 0, 0, 0, 161, 934, 1, 0, 0, 0, 163, 936, 1, 0, 0, 0, 165, 944, 1, 0, 0, 0, 167, 950, 1, 0, 0, 0, 169, 964, 1, 0, 0, 0, 171, 172, 5, 112, 0, 0, 172, 173, 5, 114, 0, 0, 173, 174, 5, 97, 0, 0, 174, 175, 5, 103, 0, 0, 175, 176, 5, 109, 0, 0, 176, 177, 5, 97, 0, 0, 177, 2, 1, 0, 0, 0, 178, 179, 5, 59, 0, 0, 179, 4, 1, 0, 0, 0, 180, 181, 5, 99, 0, 0, 181, 182, 5, 97, 0, 0, 182, 183, 5, 115, 0, 0, 183, 184, 5, 104, 0, 0, 184, 185, 5, 115, 0, 0, 185, 186, 5, 99, 0, 0, 186, 187, 5, 114, 0, 0, 187, 188, 5, 105, 0, 0, 188, 189, 5, 112, 0, 0, 189, 190, 5, 116, 0, 0, 190, 6, 1, 0, 0, 0, 191, 192, 5, 94, 0, 0, 192, 8, 1, 0, 0, 0, 193, 194, 5, 126, 0, 0, 194, 10, 1, 0, 0, 0, 195, 196, 5, 62, 0, 0, 196, 197, 5, 61, 0, 0, 197, 12, 1, 0, 0, 0, 198, 199, 5, 62, 0, 0, 199, 14, 1, 0, 0, 0, 200, 201, 5, 60, 0, 0, 201, 16, 1, 0, 0, 0, 202, 203, 5, 60, 0, 0, 203, 204, 5, 61, 0, 0, 204, 18, 1, 0, 0, 0, 205, 206, 5, 61, 0, 0, 206, 20, 1, 0, 0, 0, 207, 208, 5, 105, 0, 0, 208, 209, 5, 109, 0, 0, 209, 210, 5, 112, 0, 0, 210, 211, 5, 111, 0, 0, 211, 212, 5, 114, 0, 0, 212, 213, 5, 116, 0, 0, 213, 22, 1, 0, 0, 0, 214, 215, 5, 102, 0, 0, 215, 216, 5, 117, 0, 0, 216, 217, 5, 110, 0, 0, 217, 218, 5, 99, 0, 0, 218, 219, 5, 116, 0, 0, 219, 220, 5, 105, 0, 0, 220, 221, 5, 111, 0, 0, 221, 222, 5, 110, 0, 0, 222, 24, 1, 0, 0, 0, 223, 224, 5, 114, 0, 0, 224, 225, 5, 101, 0, 0, 225, 226, 5, 116, 0, 0, 226, 227, 5, 117, 0, 0, 227, 228, 5, 114, 0, 0, 228, 229, 5, 110, 0, 0, 229, 230, 5, 115, 0, 0, 230, 26, 1, 0, 0, 0, 231, 232, 5, 40, 0, 0, 232, 28, 1, 0, 0, 0, 233, 234, 5, 44, 0, 0, 234, 30, 1, 0, 0, 0, 235, 236, 5, 41, 0, 0, 236, 32, 1, 0, 0, 0, 237, 238, 5, 99, 0, 0, 238, 239, 5, 111, 0, 0, 239, 240, 5, 110, 0, 0, 240, 241, 5, 115, 0, 0, 241, 242, 5, 116, 0, 0, 242, 243, 5, 97, 0, 0, 243, 244, 5, 110, 0, 0, 244, 245, 5, 116, 0, 0, 245, 34, 1, 0, 0, 0, 246, 247, 5, 99, 0, 0, 247, 248, 5, 111, 0, 0, 248, 249, 5, 110, 0, 0, 249, 250, 5, 116, 0, 0, 250, 251, 5, 114, 0, 0, 251, 252, 5, 97, 0, 0, 252, 253, 5, 99, 0, 0, 253, 254, 5, 116, 0, 0, 254, 36, 1, 0, 0, 0, 255, 256, 5, 123, 0, 0, 256, 38, 1, 0, 0, 0, 257, 258, 5, 125, 0, 0, 258, 40, 1, 0, 0, 0, 259, 260, 5, 114, 0, 0, 260, 261, 5, 101, 0, 0, 261, 262, 5, 116, 0, 0, 262, 263, 5, 117, 0, 0, 263, 264, 5, 114, 0, 0, 264, 265, 5, 110, 0, 0, 265, 42, 1, 0, 0, 0, 266, 267, 5, 43, 0, 0, 267, 268, 5, 61, 0, 0, 268, 44, 1, 0, 0, 0, 269, 270, 5, 45, 0, 0, 270, 271, 5, 61, 0, 0, 271, 46, 1, 0, 0, 0, 272, 273, 5, 43, 0, 0, 273, 274, 5, 43, 0, 0, 274, 48, 1, 0, 0, 0, 275, 276, 5, 45, 0, 0, 276, 277, 5, 45, 0, 0, 277, 50, 1, 0, 0, 0, 278, 279, 5, 114, 0, 0, 279, 280, 5, 101, 0, 0, 280, 281, 5, 113, 0, 0, 281, 282, 5, 117, 0, 0, 282, 283, 5, 105, 0, 0, 283, 284, 5, 114, 0, 0, 284, 285, 5, 101, 0, 0, 285, 52, 1, 0, 0, 0, 286, 287, 5, 99, 0, 0, 287, 288, 5, 111, 0, 0, 288, 289, 5, 110, 0, 0, 289, 290, 5, 115, 0, 0, 290, 291, 5, 111, 0, 0, 291, 292, 5, 108, 0, 0, 292, 293, 5, 101, 0, 0, 293, 294, 5, 46, 0, 0, 294, 295, 5, 108, 0, 0, 295, 296, 5, 111, 0, 0, 296, 297, 5, 103, 0, 0, 297, 54, 1, 0, 0, 0, 298, 299, 5, 105, 0, 0, 299, 300, 5, 102, 0, 0, 300, 56, 1, 0, 0, 0, 301, 302, 5, 101, 0, 0, 302, 303, 5, 108, 0, 0, 303, 304, 5, 115, 0, 0, 304, 305, 5, 101, 0, 0, 305, 58, 1, 0, 0, 0, 306, 307, 5, 100, 0, 0, 307, 308, 5, 111, 0, 0, 308, 60, 1, 0, 0, 0, 309, 310, 5, 119, 0, 0, 310, 311, 5, 104, 0, 0, 311, 312, 5, 105, 0, 0, 312, 313, 5, 108, 0, 0, 313, 314, 5, 101, 0, 0, 314, 62, 1, 0, 0, 0, 315, 316, 5, 102, 0, 0, 316, 317, 5, 111, 0, 0, 317, 318, 5, 114, 0, 0, 318, 64, 1, 0, 0, 0, 319, 320, 5, 110, 0, 0, 320, 321, 5, 101, 0, 0, 321, 322, 5, 119, 0, 0, 322, 66, 1, 0, 0, 0, 323, 324, 5, 91, 0, 0, 324, 68, 1, 0, 0, 0, 325, 326, 5, 93, 0, 0, 326, 70, 1, 0, 0, 0, 327, 328, 5, 116, 0, 0, 328, 329, 5, 120, 0, 0, 329, 330, 5, 46, 0, 0, 330, 331, 5, 111, 0, 0, 331, 332, 5, 117, 0, 0, 332, 333, 5, 116, 0, 0, 333, 334, 5, 112, 0, 0, 334, 335, 5, 117, 0, 0, 335, 336, 5, 116, 0, 0, 336, 337, 5, 115, 0, 0, 337, 72, 1, 0, 0, 0, 338, 339, 5, 46, 0, 0, 339, 340, 5, 118, 0, 0, 340, 341, 5, 97, 0, 0, 341, 342, 5, 108, 0, 0, 342, 343, 5, 117, 0, 0, 343, 344, 5, 101, 0, 0, 344, 74, 1, 0, 0, 0, 345, 346, 5, 46, 0, 0, 346, 347, 5, 108, 0, 0, 347, 348, 5, 111, 0, 0, 348, 349, 5, 99, 0, 0, 349, 350, 5, 107, 0, 0, 350, 351, 5, 105, 0, 0, 351, 352, 5, 110, 0, 0, 352, 353, 5, 103, 0, 0, 353, 354, 5, 66, 0, 0, 354, 355, 5, 121, 0, 0, 355, 356, 5, 116, 0, 0, 356, 357, 5, 101, 0, 0, 357, 358, 5, 99, 0, 0, 358, 359, 5, 111, 0, 0, 359, 360, 5, 100, 0, 0, 360, 361, 5, 101, 0, 0, 361, 76, 1, 0, 0, 0, 362, 363, 5, 46, 0, 0, 363, 364, 5, 116, 0, 0, 364, 365, 5, 111, 0, 0, 365, 366, 5, 107, 0, 0, 366, 367, 5, 101, 0, 0, 367, 368, 5, 110, 0, 0, 368, 369, 5, 67, 0, 0, 369, 370, 5, 97, 0, 0, 370, 371, 5, 116, 0, 0, 371, 372, 5, 101, 0, 0, 372, 373, 5, 103, 0, 0, 373, 374, 5, 111, 0, 0, 374, 375, 5, 114, 0, 0, 375, 376, 5, 121, 0, 0, 376, 78, 1, 0, 0, 0, 377, 378, 5, 46, 0, 0, 378, 379, 5, 110, 0, 0, 379, 380, 5, 102, 0, 0, 380, 381, 5, 116, 0, 0, 381, 382, 5, 67, 0, 0, 382, 383, 5, 111, 0, 0, 383, 384, 5, 109, 0, 0, 384, 385, 5, 109, 0, 0, 385, 386, 5, 105, 0, 0, 386, 387, 5, 116, 0, 0, 387, 388, 5, 109, 0, 0, 388, 389, 5, 101, 0, 0, 389, 390, 5, 110, 0, 0, 390, 391, 5, 116, 0, 0, 391, 80, 1, 0, 0, 0, 392, 393, 5, 46, 0, 0, 393, 394, 5, 116, 0, 0, 394, 395, 5, 111, 0, 0, 395, 396, 5, 107, 0, 0, 396, 397, 5, 101, 0, 0, 397, 398, 5, 110, 0, 0, 398, 399, 5, 65, 0, 0, 399, 400, 5, 109, 0, 0, 400, 401, 5, 111, 0, 0, 401, 402, 5, 117, 0, 0, 402, 403, 5, 110, 0, 0, 403, 404, 5, 116, 0, 0, 404, 82, 1, 0, 0, 0, 405, 406, 5, 116, 0, 0, 406, 407, 5, 120, 0, 0, 407, 408, 5, 46, 0, 0, 408, 409, 5, 105, 0, 0, 409, 410, 5, 110, 0, 0, 410, 411, 5, 112, 0, 0, 411, 412, 5, 117, 0, 0, 412, 413, 5, 116, 0, 0, 413, 414, 5, 115, 0, 0, 414, 84, 1, 0, 0, 0, 415, 416, 5, 46, 0, 0, 416, 417, 5, 111, 0, 0, 417, 418, 5, 117, 0, 0, 418, 419, 5, 116, 0, 0, 419, 420, 5, 112, 0, 0, 420, 421, 5, 111, 0, 0, 421, 422, 5, 105, 0, 0, 422, 423, 5, 110, 0, 0, 423, 424, 5, 116, 0, 0, 424, 425, 5, 84, 0, 0, 425, 426, 5, 114, 0, 0, 426, 427, 5, 97, 0, 0, 427, 428, 5, 110, 0, 0, 428, 429, 5, 115, 0, 0, 429, 430, 5, 97, 0, 0, 430, 431, 5, 99, 0, 0, 431, 432, 5, 116, 0, 0, 432, 433, 5, 105, 0, 0, 433, 434, 5, 111, 0, 0, 434, 435, 5, 110, 0, 0, 435, 436, 5, 72, 0, 0, 436, 437, 5, 97, 0, 0, 437, 438, 5, 115, 0, 0, 438, 439, 5, 104, 0, 0, 439, 86, 1, 0, 0, 0, 440, 441, 5, 46, 0, 0, 441, 442, 5, 111, 0, 0, 442, 443, 5, 117, 0, 0, 443, 444, 5, 116, 0, 0, 444, 445, 5, 112, 0, 0, 445, 446, 5, 111, 0, 0, 446, 447, 5, 105, 0, 0, 447, 448, 5, 110, 0, 0, 448, 449, 5, 116, 0, 0, 449, 450, 5, 73, 0, 0, 450, 451, 5, 110, 0, 0, 451, 452, 5, 100, 0, 0, 452, 453, 5, 101, 0, 0, 453, 454, 5, 120, 0, 0, 454, 88, 1, 0, 0, 0, 455, 456, 5, 46, 0, 0, 456, 457, 5, 117, 0, 0, 457, 458, 5, 110, 0, 0, 458, 459, 5, 108, 0, 0, 459, 460, 5, 111, 0, 0, 460, 461, 5, 99, 0, 0, 461, 462, 5, 107, 0, 0, 462, 463, 5, 105, 0, 0, 463, 464, 5, 110, 0, 0, 464, 465, 5, 103, 0, 0, 465, 466, 5, 66, 0, 0, 466, 467, 5, 121, 0, 0, 467, 468, 5, 116, 0, 0, 468, 469, 5, 101, 0, 0, 469, 470, 5, 99, 0, 0, 470, 471, 5, 111, 0, 0, 471, 472, 5, 100, 0, 0, 472, 473, 5, 101, 0, 0, 473, 90, 1, 0, 0, 0, 474, 475, 5, 46, 0, 0, 475, 476, 5, 115, 0, 0, 476, 477, 5, 101, 0, 0, 477, 478, 5, 113, 0, 0, 478, 479, 5, 117, 0, 0, 479, 480, 5, 101, 0, 0, 480, 481, 5, 110, 0, 0, 481, 482, 5, 99, 0, 0, 482, 483, 5, 101, 0, 0, 483, 484, 5, 78, 0, 0, 484, 485, 5, 117, 0, 0, 485, 486, 5, 109, 0, 0, 486, 487, 5, 98, 0, 0, 487, 488, 5, 101, 0, 0, 488, 489, 5, 114, 0, 0, 489, 92, 1, 0, 0, 0, 490, 491, 5, 46, 0, 0, 491, 492, 5, 114, 0, 0, 492, 493, 5, 101, 0, 0, 493, 494, 5, 118, 0, 0, 494, 495, 5, 101, 0, 0, 495, 496, 5, 114, 0, 0, 496, 497, 5, 115, 0, 0, 497, 498, 5, 101, 0, 0, 498, 499, 5, 40, 0, 0, 499, 500, 5, 41, 0, 0, 500, 94, 1, 0, 0, 0, 501, 502, 5, 46, 0, 0, 502, 503, 5, 108, 0, 0, 503, 504, 5, 101, 0, 0, 504, 505, 5, 110, 0, 0, 505, 506, 5, 103, 0, 0, 506, 507, 5, 116, 0, 0, 507, 508, 5, 104, 0, 0, 508, 96, 1, 0, 0, 0, 509, 510, 5, 46, 0, 0, 510, 511, 5, 115, 0, 0, 511, 512, 5, 112, 0, 0, 512, 513, 5, 108, 0, 0, 513, 514, 5, 105, 0, 0, 514, 515, 5, 116, 0, 0, 515, 98, 1, 0, 0, 0, 516, 517, 5, 46, 0, 0, 517, 518, 5, 115, 0, 0, 518, 519, 5, 108, 0, 0, 519, 520, 5, 105, 0, 0, 520, 521, 5, 99, 0, 0, 521, 522, 5, 101, 0, 0, 522, 100, 1, 0, 0, 0, 523, 524, 5, 33, 0, 0, 524, 102, 1, 0, 0, 0, 525, 526, 5, 45, 0, 0, 526, 104, 1, 0, 0, 0, 527, 528, 5, 42, 0, 0, 528, 106, 1, 0, 0, 0, 529, 530, 5, 47, 0, 0, 530, 108, 1, 0, 0, 0, 531, 532, 5, 37, 0, 0, 532, 110, 1, 0, 0, 0, 533, 534, 5, 43, 0, 0, 534, 112, 1, 0, 0, 0, 535, 536, 5, 62, 0, 0, 536, 537, 5, 62, 0, 0, 537, 114, 1, 0, 0, 0, 538, 539, 5, 60, 0, 0, 539, 540, 5, 60, 0, 0, 540, 116, 1, 0, 0, 0, 541, 542, 5, 61, 0, 0, 542, 543, 5, 61, 0, 0, 543, 118, 1, 0, 0, 0, 544, 545, 5, 33, 0, 0, 545, 546, 5, 61, 0, 0, 546, 120, 1, 0, 0, 0, 547, 548, 5, 38, 0, 0, 548, 122, 1, 0, 0, 0, 549, 550, 5, 124, 0, 0, 550, 124, 1, 0, 0, 0, 551, 552, 5, 38, 0, 0, 552, 553, 5, 38, 0, 0, 553, 126, 1, 0, 0, 0, 554, 555, 5, 124, 0, 0, 555, 556, 5, 124, 0, 0, 556, 128, 1, 0, 0, 0, 557, 558, 5, 117, 0, 0, 558, 559, 5, 110, 0, 0, 559, 560, 5, 117, 0, 0, 560, 561, 5, 115, 0, 0, 561, 562, 5, 101, 0, 0, 562, 563, 5, 100, 0, 0, 563, 130, 1, 0, 0, 0, 564, 566, 7, 0, 0, 0, 565, 564, 1, 0, 0, 0, 566, 567, 1, 0, 0, 0, 567, 565, 1, 0, 0, 0, 567, 568, 1, 0, 0, 0, 568, 569, 1, 0, 0, 0, 569, 571, 5, 46, 0, 0, 570, 572, 7, 0, 0, 0, 571, 570, 1, 0, 0, 0, 572, 573, 1, 0, 0, 0, 573, 571, 1, 0, 0, 0, 573, 574, 1, 0, 0, 0, 574, 575, 1, 0, 0, 0, 575, 577, 5, 46, 0, 0, 576, 578, 7, 0, 0, 0, 577, 576, 1, 0, 0, 0, 578, 579, 1, 0, 0, 0, 579, 577, 1, 0, 0, 0, 579, 580, 1, 0, 0, 0, 580, 132, 1, 0, 0, 0, 581, 582, 5, 116, 0, 0, 582, 583, 5, 114, 0, 0, 583, 584, 5, 117, 0, 0, 584, 591, 5, 101, 0, 0, 585, 586, 5, 102, 0, 0, 586, 587, 5, 97, 0, 0, 587, 588, 5, 108, 0, 0, 588, 589, 5, 115, 0, 0, 589, 591, 5, 101, 0, 0, 590, 581, 1, 0, 0, 0, 590, 585, 1, 0, 0, 0, 591, 134, 1, 0, 0, 0, 592, 593, 5, 115, 0, 0, 593, 594, 5, 97, 0, 0, 594, 595, 5, 116, 0, 0, 595, 596, 5, 111, 0, 0, 596, 597, 5, 115, 0, 0, 597, 598, 5, 104, 0, 0, 598, 599, 5, 105, 0, 0, 599, 650, 5, 115, 0, 0, 600, 601, 5, 115, 0, 0, 601, 602, 5, 97, 0, 0, 602, 603, 5, 116, 0, 0, 603, 650, 5, 115, 0, 0, 604, 605, 5, 102, 0, 0, 605, 606, 5, 105, 0, 0, 606, 607, 5, 110, 0, 0, 607, 608, 5, 110, 0, 0, 608, 609, 5, 101, 0, 0, 609, 650, 5, 121, 0, 0, 610, 611, 5, 98, 0, 0, 611, 612, 5, 105, 0, 0, 612, 613, 5, 116, 0, 0, 613, 650, 5, 115, 0, 0, 614, 615, 5, 98, 0, 0, 615, 616, 5, 105, 0, 0, 616, 617, 5, 116, 0, 0, 617, 618, 5, 99, 0, 0, 618, 619, 5, 111, 0, 0, 619, 620, 5, 105, 0, 0, 620, 650, 5, 110, 0, 0, 621, 622, 5, 115, 0, 0, 622, 623, 5, 101, 0, 0, 623, 624, 5, 99, 0, 0, 624, 625, 5, 111, 0, 0, 625, 626, 5, 110, 0, 0, 626, 627, 5, 100, 0, 0, 627, 650, 5, 115, 0, 0, 628, 629, 5, 109, 0, 0, 629, 630, 5, 105, 0, 0, 630, 631, 5, 110, 0, 0, 631, 632, 5, 117, 0, 0, 632, 633, 5, 116, 0, 0, 633, 634, 5, 101, 0, 0, 634, 650, 5, 115, 0, 0, 635, 636, 5, 104, 0, 0, 636, 637, 5, 111, 0, 0, 637, 638, 5, 117, 0, 0, 638, 639, 5, 114, 0, 0, 639, 650, 5, 115, 0, 0, 640, 641, 5, 100, 0, 0, 641, 642, 5, 97, 0, 0, 642, 643, 5, 121, 0, 0, 643, 650, 5, 115, 0, 0, 644, 645, 5, 119, 0, 0, 645, 646, 5, 101, 0, 0, 646, 647, 5, 101, 0, 0, 647, 648, 5, 107, 0, 0, 648, 650, 5, 115, 0, 0, 649, 592, 1, 0, 0, 0, 649, 600, 1, 0, 0, 0, 649, 604, 1, 0, 0, 0, 649, 610, 1, 0, 0, 0, 649, 614, 1, 0, 0, 0, 649, 621, 1, 0, 0, 0, 649, 628, 1, 0, 0, 0, 649, 635, 1, 0, 0, 0, 649, 640, 1, 0, 0, 0, 649, 644, 1, 0, 0, 0, 650, 136, 1, 0, 0, 0, 651, 653, 5, 45, 0, 0, 652, 651, 1, 0, 0, 0, 652, 653, 1, 0, 0, 0, 653, 654, 1, 0, 0, 0, 654, 656, 3, 139, 69, 0, 655, 657, 3, 141, 70, 0, 656, 655, 1, 0, 0, 0, 656, 657, 1, 0, 0, 0, 657, 138, 1, 0, 0, 0, 658, 660, 7, 0, 0, 0, 659, 658, 1, 0, 0, 0, 660, 661, 1, 0, 0, 0, 661, 659, 1, 0, 0, 0, 661, 662, 1, 0, 0, 0, 662, 671, 1, 0, 0, 0, 663, 665, 5, 95, 0, 0, 664, 666, 7, 0, 0, 0, 665, 664, 1, 0, 0, 0, 666, 667, 1, 0, 0, 0, 667, 665, 1, 0, 0, 0, 667, 668, 1, 0, 0, 0, 668, 670, 1, 0, 0, 0, 669, 663, 1, 0, 0, 0, 670, 673, 1, 0, 0, 0, 671, 669, 1, 0, 0, 0, 671, 672, 1, 0, 0, 0, 672, 140, 1, 0, 0, 0, 673, 671, 1, 0, 0, 0, 674, 675, 7, 1, 0, 0, 675, 676, 3, 139, 69, 0, 676, 142, 1, 0, 0, 0, 677, 678, 5, 105, 0, 0, 678, 679, 5, 110, 0, 0, 679, 707, 5, 116, 0, 0, 680, 681, 5, 98, 0, 0, 681, 682, 5, 111, 0, 0, 682, 683, 5, 111, 0, 0, 683, 707, 5, 108, 0, 0, 684, 685, 5, 115, 0, 0, 685, 686, 5, 116, 0, 0, 686, 687, 5, 114, 0, 0, 687, 688, 5, 105, 0, 0, 688, 689, 5, 110, 0, 0, 689, 707, 5, 103, 0, 0, 690, 691, 5, 112, 0, 0, 691, 692, 5, 117, 0, 0, 692, 693, 5, 98, 0, 0, 693, 694, 5, 107, 0, 0, 694, 695, 5, 101, 0, 0, 695, 707, 5, 121, 0, 0, 696, 697, 5, 115, 0, 0, 697, 698, 5, 105, 0, 0, 698, 707, 5, 103, 0, 0, 699, 700, 5, 100, 0, 0, 700, 701, 5, 97, 0, 0, 701, 702, 5, 116, 0, 0, 702, 703, 5, 97, 0, 0, 703, 704, 5, 115, 0, 0, 704, 705, 5, 105, 0, 0, 705, 707, 5, 103, 0, 0, 706, 677, 1, 0, 0, 0, 706, 680, 1, 0, 0, 0, 706, 684, 1, 0, 0, 0, 706, 690, 1, 0, 0, 0, 706, 696, 1, 0, 0, 0, 706, 699, 1, 0, 0, 0, 707, 144, 1, 0, 0, 0, 708, 709, 5, 98, 0, 0, 709, 710, 5, 121, 0, 0, 710, 711, 5, 116, 0, 0, 711, 712, 5, 101, 0, 0, 712, 713, 5, 115, 0, 0, 713, 146, 1, 0, 0, 0, 714, 715, 5, 98, 0, 0, 715, 716, 5, 121, 0, 0, 716, 717, 5, 116, 0, 0, 717, 718, 5, 101, 0, 0, 718, 719, 5, 115, 0, 0, 719, 720, 1, 0, 0, 0, 720, 726, 3, 149, 74, 0, 721, 722, 5, 98, 0, 0, 722, 723, 5, 121, 0, 0, 723, 724, 5, 116, 0, 0, 724, 726, 5, 101, 0, 0, 725, 714, 1, 0, 0, 0, 725, 721, 1, 0, 0, 0, 726, 148, 1, 0, 0, 0, 727, 731, 7, 2, 0, 0, 728, 730, 7, 0, 0, 0, 729, 728, 1, 0, 0, 0, 730, 733, 1, 0, 0, 0, 731, 729, 1, 0, 0, 0, 731, 732, 1, 0, 0, 0, 732, 150, 1, 0, 0, 0, 733, 731, 1, 0, 0, 0, 734, 740, 5, 34, 0, 0, 735, 736, 5, 92, 0, 0, 736, 739, 5, 34, 0, 0, 737, 739, 8, 3, 0, 0, 738, 735, 1, 0, 0, 0, 738, 737, 1, 0, 0, 0, 739, 742, 1, 0, 0, 0, 740, 741, 1, 0, 0, 0, 740, 738, 1, 0, 0, 0, 741, 743, 1, 0, 0, 0, 742, 740, 1, 0, 0, 0, 743, 755, 5, 34, 0, 0, 744, 750, 5, 39, 0, 0, 745, 746, 5, 92, 0, 0, 746, 749, 5, 39, 0, 0, 747, 749, 8, 4, 0, 0, 748, 745, 1, 0, 0, 0, 748, 747, 1, 0, 0, 0, 749, 752, 1, 0, 0, 0, 750, 751, 1, 0, 0, 0, 750, 748, 1, 0, 0, 0, 751, 753, 1, 0, 0, 0, 752, 750, 1, 0, 0, 0, 753, 755, 5, 39, 0, 0, 754, 734, 1, 0, 0, 0, 754, 744, 1, 0, 0, 0, 755, 152, 1, 0, 0, 0, 756, 757, 5, 100, 0, 0, 757, 758, 5, 97, 0, 0, 758, 759, 5, 116, 0, 0, 759, 760, 5, 101, 0, 0, 760, 761, 5, 40, 0, 0, 761, 762, 1, 0, 0, 0, 762, 763, 3, 151, 75, 0, 763, 764, 5, 41, 0, 0, 764, 154, 1, 0, 0, 0, 765, 766, 5, 48, 0, 0, 766, 770, 7, 5, 0, 0, 767, 769, 7, 6, 0, 0, 768, 767, 1, 0, 0, 0, 769, 772, 1, 0, 0, 0, 770, 768, 1, 0, 0, 0, 770, 771, 1, 0, 0, 0, 771, 156, 1, 0, 0, 0, 772, 770, 1, 0, 0, 0, 773, 774, 5, 116, 0, 0, 774, 775, 5, 104, 0, 0, 775, 776, 5, 105, 0, 0, 776, 777, 5, 115, 0, 0, 777, 778, 5, 46, 0, 0, 778, 779, 5, 97, 0, 0, 779, 780, 5, 103, 0, 0, 780, 789, 5, 101, 0, 0, 781, 782, 5, 116, 0, 0, 782, 783, 5, 120, 0, 0, 783, 784, 5, 46, 0, 0, 784, 785, 5, 116, 0, 0, 785, 786, 5, 105, 0, 0, 786, 787, 5, 109, 0, 0, 787, 789, 5, 101, 0, 0, 788, 773, 1, 0, 0, 0, 788, 781, 1, 0, 0, 0, 789, 158, 1, 0, 0, 0, 790, 791, 5, 117, 0, 0, 791, 792, 5, 110, 0, 0, 792, 793, 5, 115, 0, 0, 793, 794, 5, 97, 0, 0, 794, 795, 5, 102, 0, 0, 795, 796, 5, 101, 0, 0, 796, 797, 5, 95, 0, 0, 797, 798, 5, 105, 0, 0, 798, 799, 5, 110, 0, 0, 799, 839, 5, 116, 0, 0, 800, 801, 5, 117, 0, 0, 801, 802, 5, 110, 0, 0, 802, 803, 5, 115, 0, 0, 803, 804, 5, 97, 0, 0, 804, 805, 5, 102, 0, 0, 805, 806, 5, 101, 0, 0, 806, 807, 5, 95, 0, 0, 807, 808, 5, 98, 0, 0, 808, 809, 5, 111, 0, 0, 809, 810, 5, 111, 0, 0, 810, 839, 5, 108, 0, 0, 811, 812, 5, 117, 0, 0, 812, 813, 5, 110, 0, 0, 813, 814, 5, 115, 0, 0, 814, 815, 5, 97, 0, 0, 815, 816, 5, 102, 0, 0, 816, 817, 5, 101, 0, 0, 817, 818, 5, 95, 0, 0, 818, 819, 5, 98, 0, 0, 819, 820, 5, 121, 0, 0, 820, 821, 5, 116, 0, 0, 821, 822, 5, 101, 0, 0, 822, 823, 5, 115, 0, 0, 823, 825, 1, 0, 0, 0, 824, 826, 3, 149, 74, 0, 825, 824, 1, 0, 0, 0, 825, 826, 1, 0, 0, 0, 826, 839, 1, 0, 0, 0, 827, 828, 5, 117, 0, 0, 828, 829, 5, 110, 0, 0, 829, 830, 5, 115, 0, 0, 830, 831, 5, 97, 0, 0, 831, 832, 5, 102, 0, 0, 832, 833, 5, 101, 0, 0, 833, 834, 5, 95, 0, 0, 834, 835, 5, 98, 0, 0, 835, 836, 5, 121, 0, 0, 836, 837, 5, 116, 0, 0, 837, 839, 5, 101, 0, 0, 838, 790, 1, 0, 0, 0, 838, 800, 1, 0, 0, 0, 838, 811, 1, 0, 0, 0, 838, 827, 1, 0, 0, 0, 839, 160, 1, 0, 0, 0, 840, 841, 5, 116, 0, 0, 841, 842, 5, 104, 0, 0, 842, 843, 5, 105, 0, 0, 843, 844, 5, 115, 0, 0, 844, 845, 5, 46, 0, 0, 845, 846, 5, 97, 0, 0, 846, 847, 5, 99, 0, 0, 847, 848, 5, 116, 0, 0, 848, 849, 5, 105, 0, 0, 849, 850, 5, 118, 0, 0, 850, 851, 5, 101, 0, 0, 851, 852, 5, 73, 0, 0, 852, 853, 5, 110, 0, 0, 853, 854, 5, 112, 0, 0, 854, 855, 5, 117, 0, 0, 855, 856, 5, 116, 0, 0, 856, 857, 5, 73, 0, 0, 857, 858, 5, 110, 0, 0, 858, 859, 5, 100, 0, 0, 859, 860, 5, 101, 0, 0, 860, 935, 5, 120, 0, 0, 861, 862, 5, 116, 0, 0, 862, 863, 5, 104, 0, 0, 863, 864, 5, 105, 0, 0, 864, 865, 5, 115, 0, 0, 865, 866, 5, 46, 0, 0, 866, 867, 5, 97, 0, 0, 867, 868, 5, 99, 0, 0, 868, 869, 5, 116, 0, 0, 869, 870, 5, 105, 0, 0, 870, 871, 5, 118, 0, 0, 871, 872, 5, 101, 0, 0, 872, 873, 5, 66, 0, 0, 873, 874, 5, 121, 0, 0, 874, 875, 5, 116, 0, 0, 875, 876, 5, 101, 0, 0, 876, 877, 5, 99, 0, 0, 877, 878, 5, 111, 0, 0, 878, 879, 5, 100, 0, 0, 879, 935, 5, 101, 0, 0, 880, 881, 5, 116, 0, 0, 881, 882, 5, 120, 0, 0, 882, 883, 5, 46, 0, 0, 883, 884, 5, 105, 0, 0, 884, 885, 5, 110, 0, 0, 885, 886, 5, 112, 0, 0, 886, 887, 5, 117, 0, 0, 887, 888, 5, 116, 0, 0, 888, 889, 5, 115, 0, 0, 889, 890, 5, 46, 0, 0, 890, 891, 5, 108, 0, 0, 891, 892, 5, 101, 0, 0, 892, 893, 5, 110, 0, 0, 893, 894, 5, 103, 0, 0, 894, 895, 5, 116, 0, 0, 895, 935, 5, 104, 0, 0, 896, 897, 5, 116, 0, 0, 897, 898, 5, 120, 0, 0, 898, 899, 5, 46, 0, 0, 899, 900, 5, 111, 0, 0, 900, 901, 5, 117, 0, 0, 901, 902, 5, 116, 0, 0, 902, 903, 5, 112, 0, 0, 903, 904, 5, 117, 0, 0, 904, 905, 5, 116, 0, 0, 905, 906, 5, 115, 0, 0, 906, 907, 5, 46, 0, 0, 907, 908, 5, 108, 0, 0, 908, 909, 5, 101, 0, 0, 909, 910, 5, 110, 0, 0, 910, 911, 5, 103, 0, 0, 911, 912, 5, 116, 0, 0, 912, 935, 5, 104, 0, 0, 913, 914, 5, 116, 0, 0, 914, 915, 5, 120, 0, 0, 915, 916, 5, 46, 0, 0, 916, 917, 5, 118, 0, 0, 917, 918, 5, 101, 0, 0, 918, 919, 5, 114, 0, 0, 919, 920, 5, 115, 0, 0, 920, 921, 5, 105, 0, 0, 921, 922, 5, 111, 0, 0, 922, 935, 5, 110, 0, 0, 923, 924, 5, 116, 0, 0, 924, 925, 5, 120, 0, 0, 925, 926, 5, 46, 0, 0, 926, 927, 5, 108, 0, 0, 927, 928, 5, 111, 0, 0, 928, 929, 5, 99, 0, 0, 929, 930, 5, 107, 0, 0, 930, 931, 5, 116, 0, 0, 931, 932, 5, 105, 0, 0, 932, 933, 5, 109, 0, 0, 933, 935, 5, 101, 0, 0, 934, 840, 1, 0, 0, 0, 934, 861, 1, 0, 0, 0, 934, 880, 1, 0, 0, 0, 934, 896, 1, 0, 0, 0, 934, 913, 1, 0, 0, 0, 934, 923, 1, 0, 0, 0, 935, 162, 1, 0, 0, 0, 936, 940, 7, 7, 0, 0, 937, 939, 7, 8, 0, 0, 938, 937, 1, 0, 0, 0, 939, 942, 1, 0, 0, 0, 940, 938, 1, 0, 0, 0, 940, 941, 1, 0, 0, 0, 941, 164, 1, 0, 0, 0, 942, 940, 1, 0, 0, 0, 943, 945, 7, 9, 0, 0, 944, 943, 1, 0, 0, 0, 945, 946, 1, 0, 0, 0, 946, 944, 1, 0, 0, 0, 946, 947, 1, 0, 0, 0, 947, 948, 1, 0, 0, 0, 948, 949, 6, 82, 0, 0, 949, 166, 1, 0, 0, 0, 950, 951, 5, 47, 0, 0, 951, 952, 5, 42, 0, 0, 952, 956, 1, 0, 0, 0, 953, 955, 9, 0, 0, 0, 954, 953, 1, 0, 0, 0, 955, 958, 1, 0, 0, 0, 956, 957, 1, 0, 0, 0, 956, 954, 1, 0, 0, 0, 957, 959, 1, 0, 0, 0, 958, 956, 1, 0, 0, 0, 959, 960, 5, 42, 0, 0, 960, 961, 5, 47, 0, 0, 961, 962, 1, 0, 0, 0, 962, 963, 6, 83, 1, 0, 963, 168, 1, 0, 0, 0, 964, 965, 5, 47, 0, 0, 965, 966, 5, 47, 0, 0, 966, 970, 1, 0, 0, 0, 967, 969, 8, 10, 0, 0, 968, 967, 1, 0, 0, 0, 969, 972, 1, 0, 0, 0, 970, 968, 1, 0, 0, 0, 970, 971, 1, 0, 0, 0, 971, 973, 1, 0, 0, 0, 972, 970, 1, 0, 0, 0, 973, 974, 6, 84, 1, 0, 974, 170, 1, 0, 0, 0, 28, 0, 567, 573, 579, 590, 649, 652, 656, 661, 667, 671, 706, 725, 731, 738, 740, 748, 750, 754, 770, 788, 825, 838, 934, 940, 946, 956, 970, 2, 6, 0, 0, 0, 1, 0] \ No newline at end of file diff --git a/packages/cashc/src/grammar/CashScriptLexer.tokens b/packages/cashc/src/grammar/CashScriptLexer.tokens index 074f0fc1..1ca45fe0 100644 --- a/packages/cashc/src/grammar/CashScriptLexer.tokens +++ b/packages/cashc/src/grammar/CashScriptLexer.tokens @@ -62,26 +62,27 @@ T__60=61 T__61=62 T__62=63 T__63=64 -VersionLiteral=65 -BooleanLiteral=66 -NumberUnit=67 -NumberLiteral=68 -NumberPart=69 -ExponentPart=70 -PrimitiveType=71 -UnboundedBytes=72 -BoundedBytes=73 -Bound=74 -StringLiteral=75 -DateLiteral=76 -HexLiteral=77 -TxVar=78 -UnsafeCast=79 -NullaryOp=80 -Identifier=81 -WHITESPACE=82 -COMMENT=83 -LINE_COMMENT=84 +T__64=65 +VersionLiteral=66 +BooleanLiteral=67 +NumberUnit=68 +NumberLiteral=69 +NumberPart=70 +ExponentPart=71 +PrimitiveType=72 +UnboundedBytes=73 +BoundedBytes=74 +Bound=75 +StringLiteral=76 +DateLiteral=77 +HexLiteral=78 +TxVar=79 +UnsafeCast=80 +NullaryOp=81 +Identifier=82 +WHITESPACE=83 +COMMENT=84 +LINE_COMMENT=85 'pragma'=1 ';'=2 'cashscript'=3 @@ -146,4 +147,5 @@ LINE_COMMENT=84 '|'=62 '&&'=63 '||'=64 -'bytes'=72 +'unused'=65 +'bytes'=73 diff --git a/packages/cashc/src/grammar/CashScriptLexer.ts b/packages/cashc/src/grammar/CashScriptLexer.ts index d384f897..e5634ac5 100644 --- a/packages/cashc/src/grammar/CashScriptLexer.ts +++ b/packages/cashc/src/grammar/CashScriptLexer.ts @@ -76,26 +76,27 @@ export default class CashScriptLexer extends Lexer { public static readonly T__61 = 62; public static readonly T__62 = 63; public static readonly T__63 = 64; - public static readonly VersionLiteral = 65; - public static readonly BooleanLiteral = 66; - public static readonly NumberUnit = 67; - public static readonly NumberLiteral = 68; - public static readonly NumberPart = 69; - public static readonly ExponentPart = 70; - public static readonly PrimitiveType = 71; - public static readonly UnboundedBytes = 72; - public static readonly BoundedBytes = 73; - public static readonly Bound = 74; - public static readonly StringLiteral = 75; - public static readonly DateLiteral = 76; - public static readonly HexLiteral = 77; - public static readonly TxVar = 78; - public static readonly UnsafeCast = 79; - public static readonly NullaryOp = 80; - public static readonly Identifier = 81; - public static readonly WHITESPACE = 82; - public static readonly COMMENT = 83; - public static readonly LINE_COMMENT = 84; + public static readonly T__64 = 65; + public static readonly VersionLiteral = 66; + public static readonly BooleanLiteral = 67; + public static readonly NumberUnit = 68; + public static readonly NumberLiteral = 69; + public static readonly NumberPart = 70; + public static readonly ExponentPart = 71; + public static readonly PrimitiveType = 72; + public static readonly UnboundedBytes = 73; + public static readonly BoundedBytes = 74; + public static readonly Bound = 75; + public static readonly StringLiteral = 76; + public static readonly DateLiteral = 77; + public static readonly HexLiteral = 78; + public static readonly TxVar = 79; + public static readonly UnsafeCast = 80; + public static readonly NullaryOp = 81; + public static readonly Identifier = 82; + public static readonly WHITESPACE = 83; + public static readonly COMMENT = 84; + public static readonly LINE_COMMENT = 85; public static readonly EOF = Token.EOF; public static readonly channelNames: string[] = [ "DEFAULT_TOKEN_CHANNEL", "HIDDEN" ]; @@ -142,6 +143,7 @@ export default class CashScriptLexer extends Lexer { "'=='", "'!='", "'&'", "'|'", "'&&'", "'||'", + "'unused'", null, null, null, null, null, null, @@ -178,7 +180,8 @@ export default class CashScriptLexer extends Lexer { null, null, null, null, null, null, - null, "VersionLiteral", + null, null, + "VersionLiteral", "BooleanLiteral", "NumberUnit", "NumberLiteral", @@ -206,11 +209,11 @@ export default class CashScriptLexer extends Lexer { "T__33", "T__34", "T__35", "T__36", "T__37", "T__38", "T__39", "T__40", "T__41", "T__42", "T__43", "T__44", "T__45", "T__46", "T__47", "T__48", "T__49", "T__50", "T__51", "T__52", "T__53", "T__54", "T__55", "T__56", - "T__57", "T__58", "T__59", "T__60", "T__61", "T__62", "T__63", "VersionLiteral", - "BooleanLiteral", "NumberUnit", "NumberLiteral", "NumberPart", "ExponentPart", - "PrimitiveType", "UnboundedBytes", "BoundedBytes", "Bound", "StringLiteral", - "DateLiteral", "HexLiteral", "TxVar", "UnsafeCast", "NullaryOp", "Identifier", - "WHITESPACE", "COMMENT", "LINE_COMMENT", + "T__57", "T__58", "T__59", "T__60", "T__61", "T__62", "T__63", "T__64", + "VersionLiteral", "BooleanLiteral", "NumberUnit", "NumberLiteral", "NumberPart", + "ExponentPart", "PrimitiveType", "UnboundedBytes", "BoundedBytes", "Bound", + "StringLiteral", "DateLiteral", "HexLiteral", "TxVar", "UnsafeCast", "NullaryOp", + "Identifier", "WHITESPACE", "COMMENT", "LINE_COMMENT", ]; @@ -231,7 +234,7 @@ export default class CashScriptLexer extends Lexer { public get modeNames(): string[] { return CashScriptLexer.modeNames; } - public static readonly _serializedATN: number[] = [4,0,84,966,6,-1,2,0, + public static readonly _serializedATN: number[] = [4,0,85,975,6,-1,2,0, 7,0,2,1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7,5,2,6,7,6,2,7,7,7,2,8,7,8,2,9, 7,9,2,10,7,10,2,11,7,11,2,12,7,12,2,13,7,13,2,14,7,14,2,15,7,15,2,16,7, 16,2,17,7,17,2,18,7,18,2,19,7,19,2,20,7,20,2,21,7,21,2,22,7,22,2,23,7,23, @@ -243,311 +246,314 @@ export default class CashScriptLexer extends Lexer { 60,7,60,2,61,7,61,2,62,7,62,2,63,7,63,2,64,7,64,2,65,7,65,2,66,7,66,2,67, 7,67,2,68,7,68,2,69,7,69,2,70,7,70,2,71,7,71,2,72,7,72,2,73,7,73,2,74,7, 74,2,75,7,75,2,76,7,76,2,77,7,77,2,78,7,78,2,79,7,79,2,80,7,80,2,81,7,81, - 2,82,7,82,2,83,7,83,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,2,1,2,1,2,1,2, - 1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,3,1,3,1,4,1,4,1,5,1,5,1,5,1,6,1,6,1,7,1,7, - 1,8,1,8,1,8,1,9,1,9,1,10,1,10,1,10,1,10,1,10,1,10,1,10,1,11,1,11,1,11,1, - 11,1,11,1,11,1,11,1,11,1,11,1,12,1,12,1,12,1,12,1,12,1,12,1,12,1,12,1,13, - 1,13,1,14,1,14,1,15,1,15,1,16,1,16,1,16,1,16,1,16,1,16,1,16,1,16,1,16,1, - 17,1,17,1,17,1,17,1,17,1,17,1,17,1,17,1,17,1,18,1,18,1,19,1,19,1,20,1,20, - 1,20,1,20,1,20,1,20,1,20,1,21,1,21,1,21,1,22,1,22,1,22,1,23,1,23,1,23,1, - 24,1,24,1,24,1,25,1,25,1,25,1,25,1,25,1,25,1,25,1,25,1,26,1,26,1,26,1,26, - 1,26,1,26,1,26,1,26,1,26,1,26,1,26,1,26,1,27,1,27,1,27,1,28,1,28,1,28,1, - 28,1,28,1,29,1,29,1,29,1,30,1,30,1,30,1,30,1,30,1,30,1,31,1,31,1,31,1,31, - 1,32,1,32,1,32,1,32,1,33,1,33,1,34,1,34,1,35,1,35,1,35,1,35,1,35,1,35,1, - 35,1,35,1,35,1,35,1,35,1,36,1,36,1,36,1,36,1,36,1,36,1,36,1,37,1,37,1,37, + 2,82,7,82,2,83,7,83,2,84,7,84,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,2,1, + 2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,3,1,3,1,4,1,4,1,5,1,5,1,5,1,6,1, + 6,1,7,1,7,1,8,1,8,1,8,1,9,1,9,1,10,1,10,1,10,1,10,1,10,1,10,1,10,1,11,1, + 11,1,11,1,11,1,11,1,11,1,11,1,11,1,11,1,12,1,12,1,12,1,12,1,12,1,12,1,12, + 1,12,1,13,1,13,1,14,1,14,1,15,1,15,1,16,1,16,1,16,1,16,1,16,1,16,1,16,1, + 16,1,16,1,17,1,17,1,17,1,17,1,17,1,17,1,17,1,17,1,17,1,18,1,18,1,19,1,19, + 1,20,1,20,1,20,1,20,1,20,1,20,1,20,1,21,1,21,1,21,1,22,1,22,1,22,1,23,1, + 23,1,23,1,24,1,24,1,24,1,25,1,25,1,25,1,25,1,25,1,25,1,25,1,25,1,26,1,26, + 1,26,1,26,1,26,1,26,1,26,1,26,1,26,1,26,1,26,1,26,1,27,1,27,1,27,1,28,1, + 28,1,28,1,28,1,28,1,29,1,29,1,29,1,30,1,30,1,30,1,30,1,30,1,30,1,31,1,31, + 1,31,1,31,1,32,1,32,1,32,1,32,1,33,1,33,1,34,1,34,1,35,1,35,1,35,1,35,1, + 35,1,35,1,35,1,35,1,35,1,35,1,35,1,36,1,36,1,36,1,36,1,36,1,36,1,36,1,37, 1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1, - 38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38, - 1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1, - 39,1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,41, - 1,41,1,41,1,41,1,41,1,41,1,41,1,41,1,41,1,41,1,42,1,42,1,42,1,42,1,42,1, + 37,1,37,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38, + 1,38,1,38,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1, + 39,1,39,1,39,1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,40, + 1,40,1,41,1,41,1,41,1,41,1,41,1,41,1,41,1,41,1,41,1,41,1,42,1,42,1,42,1, 42,1,42,1,42,1,42,1,42,1,42,1,42,1,42,1,42,1,42,1,42,1,42,1,42,1,42,1,42, - 1,42,1,42,1,42,1,42,1,42,1,43,1,43,1,43,1,43,1,43,1,43,1,43,1,43,1,43,1, - 43,1,43,1,43,1,43,1,43,1,43,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44, - 1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,45,1,45,1,45,1,45,1, - 45,1,45,1,45,1,45,1,45,1,45,1,45,1,45,1,45,1,45,1,45,1,45,1,46,1,46,1,46, - 1,46,1,46,1,46,1,46,1,46,1,46,1,46,1,46,1,47,1,47,1,47,1,47,1,47,1,47,1, - 47,1,47,1,48,1,48,1,48,1,48,1,48,1,48,1,48,1,49,1,49,1,49,1,49,1,49,1,49, - 1,49,1,50,1,50,1,51,1,51,1,52,1,52,1,53,1,53,1,54,1,54,1,55,1,55,1,56,1, - 56,1,56,1,57,1,57,1,57,1,58,1,58,1,58,1,59,1,59,1,59,1,60,1,60,1,61,1,61, - 1,62,1,62,1,62,1,63,1,63,1,63,1,64,4,64,557,8,64,11,64,12,64,558,1,64,1, - 64,4,64,563,8,64,11,64,12,64,564,1,64,1,64,4,64,569,8,64,11,64,12,64,570, - 1,65,1,65,1,65,1,65,1,65,1,65,1,65,1,65,1,65,3,65,582,8,65,1,66,1,66,1, - 66,1,66,1,66,1,66,1,66,1,66,1,66,1,66,1,66,1,66,1,66,1,66,1,66,1,66,1,66, - 1,66,1,66,1,66,1,66,1,66,1,66,1,66,1,66,1,66,1,66,1,66,1,66,1,66,1,66,1, - 66,1,66,1,66,1,66,1,66,1,66,1,66,1,66,1,66,1,66,1,66,1,66,1,66,1,66,1,66, - 1,66,1,66,1,66,1,66,1,66,1,66,1,66,1,66,1,66,1,66,1,66,3,66,641,8,66,1, - 67,3,67,644,8,67,1,67,1,67,3,67,648,8,67,1,68,4,68,651,8,68,11,68,12,68, - 652,1,68,1,68,4,68,657,8,68,11,68,12,68,658,5,68,661,8,68,10,68,12,68,664, - 9,68,1,69,1,69,1,69,1,70,1,70,1,70,1,70,1,70,1,70,1,70,1,70,1,70,1,70,1, - 70,1,70,1,70,1,70,1,70,1,70,1,70,1,70,1,70,1,70,1,70,1,70,1,70,1,70,1,70, - 1,70,1,70,1,70,1,70,3,70,698,8,70,1,71,1,71,1,71,1,71,1,71,1,71,1,72,1, - 72,1,72,1,72,1,72,1,72,1,72,1,72,1,72,1,72,1,72,3,72,717,8,72,1,73,1,73, - 5,73,721,8,73,10,73,12,73,724,9,73,1,74,1,74,1,74,1,74,5,74,730,8,74,10, - 74,12,74,733,9,74,1,74,1,74,1,74,1,74,1,74,5,74,740,8,74,10,74,12,74,743, - 9,74,1,74,3,74,746,8,74,1,75,1,75,1,75,1,75,1,75,1,75,1,75,1,75,1,75,1, - 76,1,76,1,76,5,76,760,8,76,10,76,12,76,763,9,76,1,77,1,77,1,77,1,77,1,77, - 1,77,1,77,1,77,1,77,1,77,1,77,1,77,1,77,1,77,1,77,3,77,780,8,77,1,78,1, - 78,1,78,1,78,1,78,1,78,1,78,1,78,1,78,1,78,1,78,1,78,1,78,1,78,1,78,1,78, - 1,78,1,78,1,78,1,78,1,78,1,78,1,78,1,78,1,78,1,78,1,78,1,78,1,78,1,78,1, - 78,1,78,1,78,1,78,1,78,3,78,817,8,78,1,78,1,78,1,78,1,78,1,78,1,78,1,78, - 1,78,1,78,1,78,1,78,3,78,830,8,78,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1, - 79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79, - 1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1, - 79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79, + 1,42,1,42,1,42,1,42,1,42,1,42,1,42,1,43,1,43,1,43,1,43,1,43,1,43,1,43,1, + 43,1,43,1,43,1,43,1,43,1,43,1,43,1,43,1,44,1,44,1,44,1,44,1,44,1,44,1,44, + 1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,45,1,45,1, + 45,1,45,1,45,1,45,1,45,1,45,1,45,1,45,1,45,1,45,1,45,1,45,1,45,1,45,1,46, + 1,46,1,46,1,46,1,46,1,46,1,46,1,46,1,46,1,46,1,46,1,47,1,47,1,47,1,47,1, + 47,1,47,1,47,1,47,1,48,1,48,1,48,1,48,1,48,1,48,1,48,1,49,1,49,1,49,1,49, + 1,49,1,49,1,49,1,50,1,50,1,51,1,51,1,52,1,52,1,53,1,53,1,54,1,54,1,55,1, + 55,1,56,1,56,1,56,1,57,1,57,1,57,1,58,1,58,1,58,1,59,1,59,1,59,1,60,1,60, + 1,61,1,61,1,62,1,62,1,62,1,63,1,63,1,63,1,64,1,64,1,64,1,64,1,64,1,64,1, + 64,1,65,4,65,566,8,65,11,65,12,65,567,1,65,1,65,4,65,572,8,65,11,65,12, + 65,573,1,65,1,65,4,65,578,8,65,11,65,12,65,579,1,66,1,66,1,66,1,66,1,66, + 1,66,1,66,1,66,1,66,3,66,591,8,66,1,67,1,67,1,67,1,67,1,67,1,67,1,67,1, + 67,1,67,1,67,1,67,1,67,1,67,1,67,1,67,1,67,1,67,1,67,1,67,1,67,1,67,1,67, + 1,67,1,67,1,67,1,67,1,67,1,67,1,67,1,67,1,67,1,67,1,67,1,67,1,67,1,67,1, + 67,1,67,1,67,1,67,1,67,1,67,1,67,1,67,1,67,1,67,1,67,1,67,1,67,1,67,1,67, + 1,67,1,67,1,67,1,67,1,67,1,67,3,67,650,8,67,1,68,3,68,653,8,68,1,68,1,68, + 3,68,657,8,68,1,69,4,69,660,8,69,11,69,12,69,661,1,69,1,69,4,69,666,8,69, + 11,69,12,69,667,5,69,670,8,69,10,69,12,69,673,9,69,1,70,1,70,1,70,1,71, + 1,71,1,71,1,71,1,71,1,71,1,71,1,71,1,71,1,71,1,71,1,71,1,71,1,71,1,71,1, + 71,1,71,1,71,1,71,1,71,1,71,1,71,1,71,1,71,1,71,1,71,1,71,1,71,1,71,3,71, + 707,8,71,1,72,1,72,1,72,1,72,1,72,1,72,1,73,1,73,1,73,1,73,1,73,1,73,1, + 73,1,73,1,73,1,73,1,73,3,73,726,8,73,1,74,1,74,5,74,730,8,74,10,74,12,74, + 733,9,74,1,75,1,75,1,75,1,75,5,75,739,8,75,10,75,12,75,742,9,75,1,75,1, + 75,1,75,1,75,1,75,5,75,749,8,75,10,75,12,75,752,9,75,1,75,3,75,755,8,75, + 1,76,1,76,1,76,1,76,1,76,1,76,1,76,1,76,1,76,1,77,1,77,1,77,5,77,769,8, + 77,10,77,12,77,772,9,77,1,78,1,78,1,78,1,78,1,78,1,78,1,78,1,78,1,78,1, + 78,1,78,1,78,1,78,1,78,1,78,3,78,789,8,78,1,79,1,79,1,79,1,79,1,79,1,79, 1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1, 79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79, - 1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,3, - 79,926,8,79,1,80,1,80,5,80,930,8,80,10,80,12,80,933,9,80,1,81,4,81,936, - 8,81,11,81,12,81,937,1,81,1,81,1,82,1,82,1,82,1,82,5,82,946,8,82,10,82, - 12,82,949,9,82,1,82,1,82,1,82,1,82,1,82,1,83,1,83,1,83,1,83,5,83,960,8, - 83,10,83,12,83,963,9,83,1,83,1,83,3,731,741,947,0,84,1,1,3,2,5,3,7,4,9, - 5,11,6,13,7,15,8,17,9,19,10,21,11,23,12,25,13,27,14,29,15,31,16,33,17,35, - 18,37,19,39,20,41,21,43,22,45,23,47,24,49,25,51,26,53,27,55,28,57,29,59, - 30,61,31,63,32,65,33,67,34,69,35,71,36,73,37,75,38,77,39,79,40,81,41,83, - 42,85,43,87,44,89,45,91,46,93,47,95,48,97,49,99,50,101,51,103,52,105,53, - 107,54,109,55,111,56,113,57,115,58,117,59,119,60,121,61,123,62,125,63,127, - 64,129,65,131,66,133,67,135,68,137,69,139,70,141,71,143,72,145,73,147,74, - 149,75,151,76,153,77,155,78,157,79,159,80,161,81,163,82,165,83,167,84,1, - 0,11,1,0,48,57,2,0,69,69,101,101,1,0,49,57,3,0,10,10,13,13,34,34,3,0,10, - 10,13,13,39,39,2,0,88,88,120,120,3,0,48,57,65,70,97,102,2,0,65,90,97,122, - 4,0,48,57,65,90,95,95,97,122,3,0,9,10,12,13,32,32,2,0,10,10,13,13,1010, - 0,1,1,0,0,0,0,3,1,0,0,0,0,5,1,0,0,0,0,7,1,0,0,0,0,9,1,0,0,0,0,11,1,0,0, - 0,0,13,1,0,0,0,0,15,1,0,0,0,0,17,1,0,0,0,0,19,1,0,0,0,0,21,1,0,0,0,0,23, - 1,0,0,0,0,25,1,0,0,0,0,27,1,0,0,0,0,29,1,0,0,0,0,31,1,0,0,0,0,33,1,0,0, - 0,0,35,1,0,0,0,0,37,1,0,0,0,0,39,1,0,0,0,0,41,1,0,0,0,0,43,1,0,0,0,0,45, - 1,0,0,0,0,47,1,0,0,0,0,49,1,0,0,0,0,51,1,0,0,0,0,53,1,0,0,0,0,55,1,0,0, - 0,0,57,1,0,0,0,0,59,1,0,0,0,0,61,1,0,0,0,0,63,1,0,0,0,0,65,1,0,0,0,0,67, - 1,0,0,0,0,69,1,0,0,0,0,71,1,0,0,0,0,73,1,0,0,0,0,75,1,0,0,0,0,77,1,0,0, - 0,0,79,1,0,0,0,0,81,1,0,0,0,0,83,1,0,0,0,0,85,1,0,0,0,0,87,1,0,0,0,0,89, - 1,0,0,0,0,91,1,0,0,0,0,93,1,0,0,0,0,95,1,0,0,0,0,97,1,0,0,0,0,99,1,0,0, - 0,0,101,1,0,0,0,0,103,1,0,0,0,0,105,1,0,0,0,0,107,1,0,0,0,0,109,1,0,0,0, - 0,111,1,0,0,0,0,113,1,0,0,0,0,115,1,0,0,0,0,117,1,0,0,0,0,119,1,0,0,0,0, - 121,1,0,0,0,0,123,1,0,0,0,0,125,1,0,0,0,0,127,1,0,0,0,0,129,1,0,0,0,0,131, - 1,0,0,0,0,133,1,0,0,0,0,135,1,0,0,0,0,137,1,0,0,0,0,139,1,0,0,0,0,141,1, - 0,0,0,0,143,1,0,0,0,0,145,1,0,0,0,0,147,1,0,0,0,0,149,1,0,0,0,0,151,1,0, - 0,0,0,153,1,0,0,0,0,155,1,0,0,0,0,157,1,0,0,0,0,159,1,0,0,0,0,161,1,0,0, - 0,0,163,1,0,0,0,0,165,1,0,0,0,0,167,1,0,0,0,1,169,1,0,0,0,3,176,1,0,0,0, - 5,178,1,0,0,0,7,189,1,0,0,0,9,191,1,0,0,0,11,193,1,0,0,0,13,196,1,0,0,0, - 15,198,1,0,0,0,17,200,1,0,0,0,19,203,1,0,0,0,21,205,1,0,0,0,23,212,1,0, - 0,0,25,221,1,0,0,0,27,229,1,0,0,0,29,231,1,0,0,0,31,233,1,0,0,0,33,235, - 1,0,0,0,35,244,1,0,0,0,37,253,1,0,0,0,39,255,1,0,0,0,41,257,1,0,0,0,43, - 264,1,0,0,0,45,267,1,0,0,0,47,270,1,0,0,0,49,273,1,0,0,0,51,276,1,0,0,0, - 53,284,1,0,0,0,55,296,1,0,0,0,57,299,1,0,0,0,59,304,1,0,0,0,61,307,1,0, - 0,0,63,313,1,0,0,0,65,317,1,0,0,0,67,321,1,0,0,0,69,323,1,0,0,0,71,325, - 1,0,0,0,73,336,1,0,0,0,75,343,1,0,0,0,77,360,1,0,0,0,79,375,1,0,0,0,81, - 390,1,0,0,0,83,403,1,0,0,0,85,413,1,0,0,0,87,438,1,0,0,0,89,453,1,0,0,0, - 91,472,1,0,0,0,93,488,1,0,0,0,95,499,1,0,0,0,97,507,1,0,0,0,99,514,1,0, - 0,0,101,521,1,0,0,0,103,523,1,0,0,0,105,525,1,0,0,0,107,527,1,0,0,0,109, - 529,1,0,0,0,111,531,1,0,0,0,113,533,1,0,0,0,115,536,1,0,0,0,117,539,1,0, - 0,0,119,542,1,0,0,0,121,545,1,0,0,0,123,547,1,0,0,0,125,549,1,0,0,0,127, - 552,1,0,0,0,129,556,1,0,0,0,131,581,1,0,0,0,133,640,1,0,0,0,135,643,1,0, - 0,0,137,650,1,0,0,0,139,665,1,0,0,0,141,697,1,0,0,0,143,699,1,0,0,0,145, - 716,1,0,0,0,147,718,1,0,0,0,149,745,1,0,0,0,151,747,1,0,0,0,153,756,1,0, - 0,0,155,779,1,0,0,0,157,829,1,0,0,0,159,925,1,0,0,0,161,927,1,0,0,0,163, - 935,1,0,0,0,165,941,1,0,0,0,167,955,1,0,0,0,169,170,5,112,0,0,170,171,5, - 114,0,0,171,172,5,97,0,0,172,173,5,103,0,0,173,174,5,109,0,0,174,175,5, - 97,0,0,175,2,1,0,0,0,176,177,5,59,0,0,177,4,1,0,0,0,178,179,5,99,0,0,179, - 180,5,97,0,0,180,181,5,115,0,0,181,182,5,104,0,0,182,183,5,115,0,0,183, - 184,5,99,0,0,184,185,5,114,0,0,185,186,5,105,0,0,186,187,5,112,0,0,187, - 188,5,116,0,0,188,6,1,0,0,0,189,190,5,94,0,0,190,8,1,0,0,0,191,192,5,126, - 0,0,192,10,1,0,0,0,193,194,5,62,0,0,194,195,5,61,0,0,195,12,1,0,0,0,196, - 197,5,62,0,0,197,14,1,0,0,0,198,199,5,60,0,0,199,16,1,0,0,0,200,201,5,60, - 0,0,201,202,5,61,0,0,202,18,1,0,0,0,203,204,5,61,0,0,204,20,1,0,0,0,205, - 206,5,105,0,0,206,207,5,109,0,0,207,208,5,112,0,0,208,209,5,111,0,0,209, - 210,5,114,0,0,210,211,5,116,0,0,211,22,1,0,0,0,212,213,5,102,0,0,213,214, - 5,117,0,0,214,215,5,110,0,0,215,216,5,99,0,0,216,217,5,116,0,0,217,218, - 5,105,0,0,218,219,5,111,0,0,219,220,5,110,0,0,220,24,1,0,0,0,221,222,5, - 114,0,0,222,223,5,101,0,0,223,224,5,116,0,0,224,225,5,117,0,0,225,226,5, - 114,0,0,226,227,5,110,0,0,227,228,5,115,0,0,228,26,1,0,0,0,229,230,5,40, - 0,0,230,28,1,0,0,0,231,232,5,44,0,0,232,30,1,0,0,0,233,234,5,41,0,0,234, - 32,1,0,0,0,235,236,5,99,0,0,236,237,5,111,0,0,237,238,5,110,0,0,238,239, - 5,115,0,0,239,240,5,116,0,0,240,241,5,97,0,0,241,242,5,110,0,0,242,243, - 5,116,0,0,243,34,1,0,0,0,244,245,5,99,0,0,245,246,5,111,0,0,246,247,5,110, - 0,0,247,248,5,116,0,0,248,249,5,114,0,0,249,250,5,97,0,0,250,251,5,99,0, - 0,251,252,5,116,0,0,252,36,1,0,0,0,253,254,5,123,0,0,254,38,1,0,0,0,255, - 256,5,125,0,0,256,40,1,0,0,0,257,258,5,114,0,0,258,259,5,101,0,0,259,260, - 5,116,0,0,260,261,5,117,0,0,261,262,5,114,0,0,262,263,5,110,0,0,263,42, - 1,0,0,0,264,265,5,43,0,0,265,266,5,61,0,0,266,44,1,0,0,0,267,268,5,45,0, - 0,268,269,5,61,0,0,269,46,1,0,0,0,270,271,5,43,0,0,271,272,5,43,0,0,272, - 48,1,0,0,0,273,274,5,45,0,0,274,275,5,45,0,0,275,50,1,0,0,0,276,277,5,114, - 0,0,277,278,5,101,0,0,278,279,5,113,0,0,279,280,5,117,0,0,280,281,5,105, - 0,0,281,282,5,114,0,0,282,283,5,101,0,0,283,52,1,0,0,0,284,285,5,99,0,0, - 285,286,5,111,0,0,286,287,5,110,0,0,287,288,5,115,0,0,288,289,5,111,0,0, - 289,290,5,108,0,0,290,291,5,101,0,0,291,292,5,46,0,0,292,293,5,108,0,0, - 293,294,5,111,0,0,294,295,5,103,0,0,295,54,1,0,0,0,296,297,5,105,0,0,297, - 298,5,102,0,0,298,56,1,0,0,0,299,300,5,101,0,0,300,301,5,108,0,0,301,302, - 5,115,0,0,302,303,5,101,0,0,303,58,1,0,0,0,304,305,5,100,0,0,305,306,5, - 111,0,0,306,60,1,0,0,0,307,308,5,119,0,0,308,309,5,104,0,0,309,310,5,105, - 0,0,310,311,5,108,0,0,311,312,5,101,0,0,312,62,1,0,0,0,313,314,5,102,0, - 0,314,315,5,111,0,0,315,316,5,114,0,0,316,64,1,0,0,0,317,318,5,110,0,0, - 318,319,5,101,0,0,319,320,5,119,0,0,320,66,1,0,0,0,321,322,5,91,0,0,322, - 68,1,0,0,0,323,324,5,93,0,0,324,70,1,0,0,0,325,326,5,116,0,0,326,327,5, - 120,0,0,327,328,5,46,0,0,328,329,5,111,0,0,329,330,5,117,0,0,330,331,5, - 116,0,0,331,332,5,112,0,0,332,333,5,117,0,0,333,334,5,116,0,0,334,335,5, - 115,0,0,335,72,1,0,0,0,336,337,5,46,0,0,337,338,5,118,0,0,338,339,5,97, - 0,0,339,340,5,108,0,0,340,341,5,117,0,0,341,342,5,101,0,0,342,74,1,0,0, - 0,343,344,5,46,0,0,344,345,5,108,0,0,345,346,5,111,0,0,346,347,5,99,0,0, - 347,348,5,107,0,0,348,349,5,105,0,0,349,350,5,110,0,0,350,351,5,103,0,0, - 351,352,5,66,0,0,352,353,5,121,0,0,353,354,5,116,0,0,354,355,5,101,0,0, - 355,356,5,99,0,0,356,357,5,111,0,0,357,358,5,100,0,0,358,359,5,101,0,0, - 359,76,1,0,0,0,360,361,5,46,0,0,361,362,5,116,0,0,362,363,5,111,0,0,363, - 364,5,107,0,0,364,365,5,101,0,0,365,366,5,110,0,0,366,367,5,67,0,0,367, - 368,5,97,0,0,368,369,5,116,0,0,369,370,5,101,0,0,370,371,5,103,0,0,371, - 372,5,111,0,0,372,373,5,114,0,0,373,374,5,121,0,0,374,78,1,0,0,0,375,376, - 5,46,0,0,376,377,5,110,0,0,377,378,5,102,0,0,378,379,5,116,0,0,379,380, - 5,67,0,0,380,381,5,111,0,0,381,382,5,109,0,0,382,383,5,109,0,0,383,384, - 5,105,0,0,384,385,5,116,0,0,385,386,5,109,0,0,386,387,5,101,0,0,387,388, - 5,110,0,0,388,389,5,116,0,0,389,80,1,0,0,0,390,391,5,46,0,0,391,392,5,116, - 0,0,392,393,5,111,0,0,393,394,5,107,0,0,394,395,5,101,0,0,395,396,5,110, - 0,0,396,397,5,65,0,0,397,398,5,109,0,0,398,399,5,111,0,0,399,400,5,117, - 0,0,400,401,5,110,0,0,401,402,5,116,0,0,402,82,1,0,0,0,403,404,5,116,0, - 0,404,405,5,120,0,0,405,406,5,46,0,0,406,407,5,105,0,0,407,408,5,110,0, - 0,408,409,5,112,0,0,409,410,5,117,0,0,410,411,5,116,0,0,411,412,5,115,0, - 0,412,84,1,0,0,0,413,414,5,46,0,0,414,415,5,111,0,0,415,416,5,117,0,0,416, - 417,5,116,0,0,417,418,5,112,0,0,418,419,5,111,0,0,419,420,5,105,0,0,420, - 421,5,110,0,0,421,422,5,116,0,0,422,423,5,84,0,0,423,424,5,114,0,0,424, - 425,5,97,0,0,425,426,5,110,0,0,426,427,5,115,0,0,427,428,5,97,0,0,428,429, - 5,99,0,0,429,430,5,116,0,0,430,431,5,105,0,0,431,432,5,111,0,0,432,433, - 5,110,0,0,433,434,5,72,0,0,434,435,5,97,0,0,435,436,5,115,0,0,436,437,5, - 104,0,0,437,86,1,0,0,0,438,439,5,46,0,0,439,440,5,111,0,0,440,441,5,117, - 0,0,441,442,5,116,0,0,442,443,5,112,0,0,443,444,5,111,0,0,444,445,5,105, - 0,0,445,446,5,110,0,0,446,447,5,116,0,0,447,448,5,73,0,0,448,449,5,110, - 0,0,449,450,5,100,0,0,450,451,5,101,0,0,451,452,5,120,0,0,452,88,1,0,0, - 0,453,454,5,46,0,0,454,455,5,117,0,0,455,456,5,110,0,0,456,457,5,108,0, - 0,457,458,5,111,0,0,458,459,5,99,0,0,459,460,5,107,0,0,460,461,5,105,0, - 0,461,462,5,110,0,0,462,463,5,103,0,0,463,464,5,66,0,0,464,465,5,121,0, - 0,465,466,5,116,0,0,466,467,5,101,0,0,467,468,5,99,0,0,468,469,5,111,0, - 0,469,470,5,100,0,0,470,471,5,101,0,0,471,90,1,0,0,0,472,473,5,46,0,0,473, - 474,5,115,0,0,474,475,5,101,0,0,475,476,5,113,0,0,476,477,5,117,0,0,477, - 478,5,101,0,0,478,479,5,110,0,0,479,480,5,99,0,0,480,481,5,101,0,0,481, - 482,5,78,0,0,482,483,5,117,0,0,483,484,5,109,0,0,484,485,5,98,0,0,485,486, - 5,101,0,0,486,487,5,114,0,0,487,92,1,0,0,0,488,489,5,46,0,0,489,490,5,114, - 0,0,490,491,5,101,0,0,491,492,5,118,0,0,492,493,5,101,0,0,493,494,5,114, - 0,0,494,495,5,115,0,0,495,496,5,101,0,0,496,497,5,40,0,0,497,498,5,41,0, - 0,498,94,1,0,0,0,499,500,5,46,0,0,500,501,5,108,0,0,501,502,5,101,0,0,502, - 503,5,110,0,0,503,504,5,103,0,0,504,505,5,116,0,0,505,506,5,104,0,0,506, - 96,1,0,0,0,507,508,5,46,0,0,508,509,5,115,0,0,509,510,5,112,0,0,510,511, - 5,108,0,0,511,512,5,105,0,0,512,513,5,116,0,0,513,98,1,0,0,0,514,515,5, - 46,0,0,515,516,5,115,0,0,516,517,5,108,0,0,517,518,5,105,0,0,518,519,5, - 99,0,0,519,520,5,101,0,0,520,100,1,0,0,0,521,522,5,33,0,0,522,102,1,0,0, - 0,523,524,5,45,0,0,524,104,1,0,0,0,525,526,5,42,0,0,526,106,1,0,0,0,527, - 528,5,47,0,0,528,108,1,0,0,0,529,530,5,37,0,0,530,110,1,0,0,0,531,532,5, - 43,0,0,532,112,1,0,0,0,533,534,5,62,0,0,534,535,5,62,0,0,535,114,1,0,0, - 0,536,537,5,60,0,0,537,538,5,60,0,0,538,116,1,0,0,0,539,540,5,61,0,0,540, - 541,5,61,0,0,541,118,1,0,0,0,542,543,5,33,0,0,543,544,5,61,0,0,544,120, - 1,0,0,0,545,546,5,38,0,0,546,122,1,0,0,0,547,548,5,124,0,0,548,124,1,0, - 0,0,549,550,5,38,0,0,550,551,5,38,0,0,551,126,1,0,0,0,552,553,5,124,0,0, - 553,554,5,124,0,0,554,128,1,0,0,0,555,557,7,0,0,0,556,555,1,0,0,0,557,558, - 1,0,0,0,558,556,1,0,0,0,558,559,1,0,0,0,559,560,1,0,0,0,560,562,5,46,0, - 0,561,563,7,0,0,0,562,561,1,0,0,0,563,564,1,0,0,0,564,562,1,0,0,0,564,565, - 1,0,0,0,565,566,1,0,0,0,566,568,5,46,0,0,567,569,7,0,0,0,568,567,1,0,0, - 0,569,570,1,0,0,0,570,568,1,0,0,0,570,571,1,0,0,0,571,130,1,0,0,0,572,573, - 5,116,0,0,573,574,5,114,0,0,574,575,5,117,0,0,575,582,5,101,0,0,576,577, - 5,102,0,0,577,578,5,97,0,0,578,579,5,108,0,0,579,580,5,115,0,0,580,582, - 5,101,0,0,581,572,1,0,0,0,581,576,1,0,0,0,582,132,1,0,0,0,583,584,5,115, - 0,0,584,585,5,97,0,0,585,586,5,116,0,0,586,587,5,111,0,0,587,588,5,115, - 0,0,588,589,5,104,0,0,589,590,5,105,0,0,590,641,5,115,0,0,591,592,5,115, - 0,0,592,593,5,97,0,0,593,594,5,116,0,0,594,641,5,115,0,0,595,596,5,102, - 0,0,596,597,5,105,0,0,597,598,5,110,0,0,598,599,5,110,0,0,599,600,5,101, - 0,0,600,641,5,121,0,0,601,602,5,98,0,0,602,603,5,105,0,0,603,604,5,116, - 0,0,604,641,5,115,0,0,605,606,5,98,0,0,606,607,5,105,0,0,607,608,5,116, - 0,0,608,609,5,99,0,0,609,610,5,111,0,0,610,611,5,105,0,0,611,641,5,110, - 0,0,612,613,5,115,0,0,613,614,5,101,0,0,614,615,5,99,0,0,615,616,5,111, - 0,0,616,617,5,110,0,0,617,618,5,100,0,0,618,641,5,115,0,0,619,620,5,109, - 0,0,620,621,5,105,0,0,621,622,5,110,0,0,622,623,5,117,0,0,623,624,5,116, - 0,0,624,625,5,101,0,0,625,641,5,115,0,0,626,627,5,104,0,0,627,628,5,111, - 0,0,628,629,5,117,0,0,629,630,5,114,0,0,630,641,5,115,0,0,631,632,5,100, - 0,0,632,633,5,97,0,0,633,634,5,121,0,0,634,641,5,115,0,0,635,636,5,119, - 0,0,636,637,5,101,0,0,637,638,5,101,0,0,638,639,5,107,0,0,639,641,5,115, - 0,0,640,583,1,0,0,0,640,591,1,0,0,0,640,595,1,0,0,0,640,601,1,0,0,0,640, - 605,1,0,0,0,640,612,1,0,0,0,640,619,1,0,0,0,640,626,1,0,0,0,640,631,1,0, - 0,0,640,635,1,0,0,0,641,134,1,0,0,0,642,644,5,45,0,0,643,642,1,0,0,0,643, - 644,1,0,0,0,644,645,1,0,0,0,645,647,3,137,68,0,646,648,3,139,69,0,647,646, - 1,0,0,0,647,648,1,0,0,0,648,136,1,0,0,0,649,651,7,0,0,0,650,649,1,0,0,0, - 651,652,1,0,0,0,652,650,1,0,0,0,652,653,1,0,0,0,653,662,1,0,0,0,654,656, - 5,95,0,0,655,657,7,0,0,0,656,655,1,0,0,0,657,658,1,0,0,0,658,656,1,0,0, - 0,658,659,1,0,0,0,659,661,1,0,0,0,660,654,1,0,0,0,661,664,1,0,0,0,662,660, - 1,0,0,0,662,663,1,0,0,0,663,138,1,0,0,0,664,662,1,0,0,0,665,666,7,1,0,0, - 666,667,3,137,68,0,667,140,1,0,0,0,668,669,5,105,0,0,669,670,5,110,0,0, - 670,698,5,116,0,0,671,672,5,98,0,0,672,673,5,111,0,0,673,674,5,111,0,0, - 674,698,5,108,0,0,675,676,5,115,0,0,676,677,5,116,0,0,677,678,5,114,0,0, - 678,679,5,105,0,0,679,680,5,110,0,0,680,698,5,103,0,0,681,682,5,112,0,0, - 682,683,5,117,0,0,683,684,5,98,0,0,684,685,5,107,0,0,685,686,5,101,0,0, - 686,698,5,121,0,0,687,688,5,115,0,0,688,689,5,105,0,0,689,698,5,103,0,0, - 690,691,5,100,0,0,691,692,5,97,0,0,692,693,5,116,0,0,693,694,5,97,0,0,694, - 695,5,115,0,0,695,696,5,105,0,0,696,698,5,103,0,0,697,668,1,0,0,0,697,671, - 1,0,0,0,697,675,1,0,0,0,697,681,1,0,0,0,697,687,1,0,0,0,697,690,1,0,0,0, - 698,142,1,0,0,0,699,700,5,98,0,0,700,701,5,121,0,0,701,702,5,116,0,0,702, - 703,5,101,0,0,703,704,5,115,0,0,704,144,1,0,0,0,705,706,5,98,0,0,706,707, - 5,121,0,0,707,708,5,116,0,0,708,709,5,101,0,0,709,710,5,115,0,0,710,711, - 1,0,0,0,711,717,3,147,73,0,712,713,5,98,0,0,713,714,5,121,0,0,714,715,5, - 116,0,0,715,717,5,101,0,0,716,705,1,0,0,0,716,712,1,0,0,0,717,146,1,0,0, - 0,718,722,7,2,0,0,719,721,7,0,0,0,720,719,1,0,0,0,721,724,1,0,0,0,722,720, - 1,0,0,0,722,723,1,0,0,0,723,148,1,0,0,0,724,722,1,0,0,0,725,731,5,34,0, - 0,726,727,5,92,0,0,727,730,5,34,0,0,728,730,8,3,0,0,729,726,1,0,0,0,729, - 728,1,0,0,0,730,733,1,0,0,0,731,732,1,0,0,0,731,729,1,0,0,0,732,734,1,0, - 0,0,733,731,1,0,0,0,734,746,5,34,0,0,735,741,5,39,0,0,736,737,5,92,0,0, - 737,740,5,39,0,0,738,740,8,4,0,0,739,736,1,0,0,0,739,738,1,0,0,0,740,743, - 1,0,0,0,741,742,1,0,0,0,741,739,1,0,0,0,742,744,1,0,0,0,743,741,1,0,0,0, - 744,746,5,39,0,0,745,725,1,0,0,0,745,735,1,0,0,0,746,150,1,0,0,0,747,748, - 5,100,0,0,748,749,5,97,0,0,749,750,5,116,0,0,750,751,5,101,0,0,751,752, - 5,40,0,0,752,753,1,0,0,0,753,754,3,149,74,0,754,755,5,41,0,0,755,152,1, - 0,0,0,756,757,5,48,0,0,757,761,7,5,0,0,758,760,7,6,0,0,759,758,1,0,0,0, - 760,763,1,0,0,0,761,759,1,0,0,0,761,762,1,0,0,0,762,154,1,0,0,0,763,761, - 1,0,0,0,764,765,5,116,0,0,765,766,5,104,0,0,766,767,5,105,0,0,767,768,5, - 115,0,0,768,769,5,46,0,0,769,770,5,97,0,0,770,771,5,103,0,0,771,780,5,101, - 0,0,772,773,5,116,0,0,773,774,5,120,0,0,774,775,5,46,0,0,775,776,5,116, - 0,0,776,777,5,105,0,0,777,778,5,109,0,0,778,780,5,101,0,0,779,764,1,0,0, - 0,779,772,1,0,0,0,780,156,1,0,0,0,781,782,5,117,0,0,782,783,5,110,0,0,783, - 784,5,115,0,0,784,785,5,97,0,0,785,786,5,102,0,0,786,787,5,101,0,0,787, - 788,5,95,0,0,788,789,5,105,0,0,789,790,5,110,0,0,790,830,5,116,0,0,791, - 792,5,117,0,0,792,793,5,110,0,0,793,794,5,115,0,0,794,795,5,97,0,0,795, - 796,5,102,0,0,796,797,5,101,0,0,797,798,5,95,0,0,798,799,5,98,0,0,799,800, - 5,111,0,0,800,801,5,111,0,0,801,830,5,108,0,0,802,803,5,117,0,0,803,804, - 5,110,0,0,804,805,5,115,0,0,805,806,5,97,0,0,806,807,5,102,0,0,807,808, - 5,101,0,0,808,809,5,95,0,0,809,810,5,98,0,0,810,811,5,121,0,0,811,812,5, - 116,0,0,812,813,5,101,0,0,813,814,5,115,0,0,814,816,1,0,0,0,815,817,3,147, - 73,0,816,815,1,0,0,0,816,817,1,0,0,0,817,830,1,0,0,0,818,819,5,117,0,0, - 819,820,5,110,0,0,820,821,5,115,0,0,821,822,5,97,0,0,822,823,5,102,0,0, - 823,824,5,101,0,0,824,825,5,95,0,0,825,826,5,98,0,0,826,827,5,121,0,0,827, - 828,5,116,0,0,828,830,5,101,0,0,829,781,1,0,0,0,829,791,1,0,0,0,829,802, - 1,0,0,0,829,818,1,0,0,0,830,158,1,0,0,0,831,832,5,116,0,0,832,833,5,104, - 0,0,833,834,5,105,0,0,834,835,5,115,0,0,835,836,5,46,0,0,836,837,5,97,0, - 0,837,838,5,99,0,0,838,839,5,116,0,0,839,840,5,105,0,0,840,841,5,118,0, - 0,841,842,5,101,0,0,842,843,5,73,0,0,843,844,5,110,0,0,844,845,5,112,0, - 0,845,846,5,117,0,0,846,847,5,116,0,0,847,848,5,73,0,0,848,849,5,110,0, - 0,849,850,5,100,0,0,850,851,5,101,0,0,851,926,5,120,0,0,852,853,5,116,0, - 0,853,854,5,104,0,0,854,855,5,105,0,0,855,856,5,115,0,0,856,857,5,46,0, - 0,857,858,5,97,0,0,858,859,5,99,0,0,859,860,5,116,0,0,860,861,5,105,0,0, - 861,862,5,118,0,0,862,863,5,101,0,0,863,864,5,66,0,0,864,865,5,121,0,0, - 865,866,5,116,0,0,866,867,5,101,0,0,867,868,5,99,0,0,868,869,5,111,0,0, - 869,870,5,100,0,0,870,926,5,101,0,0,871,872,5,116,0,0,872,873,5,120,0,0, - 873,874,5,46,0,0,874,875,5,105,0,0,875,876,5,110,0,0,876,877,5,112,0,0, - 877,878,5,117,0,0,878,879,5,116,0,0,879,880,5,115,0,0,880,881,5,46,0,0, - 881,882,5,108,0,0,882,883,5,101,0,0,883,884,5,110,0,0,884,885,5,103,0,0, - 885,886,5,116,0,0,886,926,5,104,0,0,887,888,5,116,0,0,888,889,5,120,0,0, - 889,890,5,46,0,0,890,891,5,111,0,0,891,892,5,117,0,0,892,893,5,116,0,0, - 893,894,5,112,0,0,894,895,5,117,0,0,895,896,5,116,0,0,896,897,5,115,0,0, - 897,898,5,46,0,0,898,899,5,108,0,0,899,900,5,101,0,0,900,901,5,110,0,0, - 901,902,5,103,0,0,902,903,5,116,0,0,903,926,5,104,0,0,904,905,5,116,0,0, - 905,906,5,120,0,0,906,907,5,46,0,0,907,908,5,118,0,0,908,909,5,101,0,0, - 909,910,5,114,0,0,910,911,5,115,0,0,911,912,5,105,0,0,912,913,5,111,0,0, - 913,926,5,110,0,0,914,915,5,116,0,0,915,916,5,120,0,0,916,917,5,46,0,0, - 917,918,5,108,0,0,918,919,5,111,0,0,919,920,5,99,0,0,920,921,5,107,0,0, - 921,922,5,116,0,0,922,923,5,105,0,0,923,924,5,109,0,0,924,926,5,101,0,0, - 925,831,1,0,0,0,925,852,1,0,0,0,925,871,1,0,0,0,925,887,1,0,0,0,925,904, - 1,0,0,0,925,914,1,0,0,0,926,160,1,0,0,0,927,931,7,7,0,0,928,930,7,8,0,0, - 929,928,1,0,0,0,930,933,1,0,0,0,931,929,1,0,0,0,931,932,1,0,0,0,932,162, - 1,0,0,0,933,931,1,0,0,0,934,936,7,9,0,0,935,934,1,0,0,0,936,937,1,0,0,0, - 937,935,1,0,0,0,937,938,1,0,0,0,938,939,1,0,0,0,939,940,6,81,0,0,940,164, - 1,0,0,0,941,942,5,47,0,0,942,943,5,42,0,0,943,947,1,0,0,0,944,946,9,0,0, - 0,945,944,1,0,0,0,946,949,1,0,0,0,947,948,1,0,0,0,947,945,1,0,0,0,948,950, - 1,0,0,0,949,947,1,0,0,0,950,951,5,42,0,0,951,952,5,47,0,0,952,953,1,0,0, - 0,953,954,6,82,1,0,954,166,1,0,0,0,955,956,5,47,0,0,956,957,5,47,0,0,957, - 961,1,0,0,0,958,960,8,10,0,0,959,958,1,0,0,0,960,963,1,0,0,0,961,959,1, - 0,0,0,961,962,1,0,0,0,962,964,1,0,0,0,963,961,1,0,0,0,964,965,6,83,1,0, - 965,168,1,0,0,0,28,0,558,564,570,581,640,643,647,652,658,662,697,716,722, - 729,731,739,741,745,761,779,816,829,925,931,937,947,961,2,6,0,0,0,1,0]; + 3,79,826,8,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,3, + 79,839,8,79,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80, + 1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1, + 80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80, + 1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1, + 80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80, + 1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1, + 80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,80,3,80,935,8,80,1,81,1,81, + 5,81,939,8,81,10,81,12,81,942,9,81,1,82,4,82,945,8,82,11,82,12,82,946,1, + 82,1,82,1,83,1,83,1,83,1,83,5,83,955,8,83,10,83,12,83,958,9,83,1,83,1,83, + 1,83,1,83,1,83,1,84,1,84,1,84,1,84,5,84,969,8,84,10,84,12,84,972,9,84,1, + 84,1,84,3,740,750,956,0,85,1,1,3,2,5,3,7,4,9,5,11,6,13,7,15,8,17,9,19,10, + 21,11,23,12,25,13,27,14,29,15,31,16,33,17,35,18,37,19,39,20,41,21,43,22, + 45,23,47,24,49,25,51,26,53,27,55,28,57,29,59,30,61,31,63,32,65,33,67,34, + 69,35,71,36,73,37,75,38,77,39,79,40,81,41,83,42,85,43,87,44,89,45,91,46, + 93,47,95,48,97,49,99,50,101,51,103,52,105,53,107,54,109,55,111,56,113,57, + 115,58,117,59,119,60,121,61,123,62,125,63,127,64,129,65,131,66,133,67,135, + 68,137,69,139,70,141,71,143,72,145,73,147,74,149,75,151,76,153,77,155,78, + 157,79,159,80,161,81,163,82,165,83,167,84,169,85,1,0,11,1,0,48,57,2,0,69, + 69,101,101,1,0,49,57,3,0,10,10,13,13,34,34,3,0,10,10,13,13,39,39,2,0,88, + 88,120,120,3,0,48,57,65,70,97,102,2,0,65,90,97,122,4,0,48,57,65,90,95,95, + 97,122,3,0,9,10,12,13,32,32,2,0,10,10,13,13,1019,0,1,1,0,0,0,0,3,1,0,0, + 0,0,5,1,0,0,0,0,7,1,0,0,0,0,9,1,0,0,0,0,11,1,0,0,0,0,13,1,0,0,0,0,15,1, + 0,0,0,0,17,1,0,0,0,0,19,1,0,0,0,0,21,1,0,0,0,0,23,1,0,0,0,0,25,1,0,0,0, + 0,27,1,0,0,0,0,29,1,0,0,0,0,31,1,0,0,0,0,33,1,0,0,0,0,35,1,0,0,0,0,37,1, + 0,0,0,0,39,1,0,0,0,0,41,1,0,0,0,0,43,1,0,0,0,0,45,1,0,0,0,0,47,1,0,0,0, + 0,49,1,0,0,0,0,51,1,0,0,0,0,53,1,0,0,0,0,55,1,0,0,0,0,57,1,0,0,0,0,59,1, + 0,0,0,0,61,1,0,0,0,0,63,1,0,0,0,0,65,1,0,0,0,0,67,1,0,0,0,0,69,1,0,0,0, + 0,71,1,0,0,0,0,73,1,0,0,0,0,75,1,0,0,0,0,77,1,0,0,0,0,79,1,0,0,0,0,81,1, + 0,0,0,0,83,1,0,0,0,0,85,1,0,0,0,0,87,1,0,0,0,0,89,1,0,0,0,0,91,1,0,0,0, + 0,93,1,0,0,0,0,95,1,0,0,0,0,97,1,0,0,0,0,99,1,0,0,0,0,101,1,0,0,0,0,103, + 1,0,0,0,0,105,1,0,0,0,0,107,1,0,0,0,0,109,1,0,0,0,0,111,1,0,0,0,0,113,1, + 0,0,0,0,115,1,0,0,0,0,117,1,0,0,0,0,119,1,0,0,0,0,121,1,0,0,0,0,123,1,0, + 0,0,0,125,1,0,0,0,0,127,1,0,0,0,0,129,1,0,0,0,0,131,1,0,0,0,0,133,1,0,0, + 0,0,135,1,0,0,0,0,137,1,0,0,0,0,139,1,0,0,0,0,141,1,0,0,0,0,143,1,0,0,0, + 0,145,1,0,0,0,0,147,1,0,0,0,0,149,1,0,0,0,0,151,1,0,0,0,0,153,1,0,0,0,0, + 155,1,0,0,0,0,157,1,0,0,0,0,159,1,0,0,0,0,161,1,0,0,0,0,163,1,0,0,0,0,165, + 1,0,0,0,0,167,1,0,0,0,0,169,1,0,0,0,1,171,1,0,0,0,3,178,1,0,0,0,5,180,1, + 0,0,0,7,191,1,0,0,0,9,193,1,0,0,0,11,195,1,0,0,0,13,198,1,0,0,0,15,200, + 1,0,0,0,17,202,1,0,0,0,19,205,1,0,0,0,21,207,1,0,0,0,23,214,1,0,0,0,25, + 223,1,0,0,0,27,231,1,0,0,0,29,233,1,0,0,0,31,235,1,0,0,0,33,237,1,0,0,0, + 35,246,1,0,0,0,37,255,1,0,0,0,39,257,1,0,0,0,41,259,1,0,0,0,43,266,1,0, + 0,0,45,269,1,0,0,0,47,272,1,0,0,0,49,275,1,0,0,0,51,278,1,0,0,0,53,286, + 1,0,0,0,55,298,1,0,0,0,57,301,1,0,0,0,59,306,1,0,0,0,61,309,1,0,0,0,63, + 315,1,0,0,0,65,319,1,0,0,0,67,323,1,0,0,0,69,325,1,0,0,0,71,327,1,0,0,0, + 73,338,1,0,0,0,75,345,1,0,0,0,77,362,1,0,0,0,79,377,1,0,0,0,81,392,1,0, + 0,0,83,405,1,0,0,0,85,415,1,0,0,0,87,440,1,0,0,0,89,455,1,0,0,0,91,474, + 1,0,0,0,93,490,1,0,0,0,95,501,1,0,0,0,97,509,1,0,0,0,99,516,1,0,0,0,101, + 523,1,0,0,0,103,525,1,0,0,0,105,527,1,0,0,0,107,529,1,0,0,0,109,531,1,0, + 0,0,111,533,1,0,0,0,113,535,1,0,0,0,115,538,1,0,0,0,117,541,1,0,0,0,119, + 544,1,0,0,0,121,547,1,0,0,0,123,549,1,0,0,0,125,551,1,0,0,0,127,554,1,0, + 0,0,129,557,1,0,0,0,131,565,1,0,0,0,133,590,1,0,0,0,135,649,1,0,0,0,137, + 652,1,0,0,0,139,659,1,0,0,0,141,674,1,0,0,0,143,706,1,0,0,0,145,708,1,0, + 0,0,147,725,1,0,0,0,149,727,1,0,0,0,151,754,1,0,0,0,153,756,1,0,0,0,155, + 765,1,0,0,0,157,788,1,0,0,0,159,838,1,0,0,0,161,934,1,0,0,0,163,936,1,0, + 0,0,165,944,1,0,0,0,167,950,1,0,0,0,169,964,1,0,0,0,171,172,5,112,0,0,172, + 173,5,114,0,0,173,174,5,97,0,0,174,175,5,103,0,0,175,176,5,109,0,0,176, + 177,5,97,0,0,177,2,1,0,0,0,178,179,5,59,0,0,179,4,1,0,0,0,180,181,5,99, + 0,0,181,182,5,97,0,0,182,183,5,115,0,0,183,184,5,104,0,0,184,185,5,115, + 0,0,185,186,5,99,0,0,186,187,5,114,0,0,187,188,5,105,0,0,188,189,5,112, + 0,0,189,190,5,116,0,0,190,6,1,0,0,0,191,192,5,94,0,0,192,8,1,0,0,0,193, + 194,5,126,0,0,194,10,1,0,0,0,195,196,5,62,0,0,196,197,5,61,0,0,197,12,1, + 0,0,0,198,199,5,62,0,0,199,14,1,0,0,0,200,201,5,60,0,0,201,16,1,0,0,0,202, + 203,5,60,0,0,203,204,5,61,0,0,204,18,1,0,0,0,205,206,5,61,0,0,206,20,1, + 0,0,0,207,208,5,105,0,0,208,209,5,109,0,0,209,210,5,112,0,0,210,211,5,111, + 0,0,211,212,5,114,0,0,212,213,5,116,0,0,213,22,1,0,0,0,214,215,5,102,0, + 0,215,216,5,117,0,0,216,217,5,110,0,0,217,218,5,99,0,0,218,219,5,116,0, + 0,219,220,5,105,0,0,220,221,5,111,0,0,221,222,5,110,0,0,222,24,1,0,0,0, + 223,224,5,114,0,0,224,225,5,101,0,0,225,226,5,116,0,0,226,227,5,117,0,0, + 227,228,5,114,0,0,228,229,5,110,0,0,229,230,5,115,0,0,230,26,1,0,0,0,231, + 232,5,40,0,0,232,28,1,0,0,0,233,234,5,44,0,0,234,30,1,0,0,0,235,236,5,41, + 0,0,236,32,1,0,0,0,237,238,5,99,0,0,238,239,5,111,0,0,239,240,5,110,0,0, + 240,241,5,115,0,0,241,242,5,116,0,0,242,243,5,97,0,0,243,244,5,110,0,0, + 244,245,5,116,0,0,245,34,1,0,0,0,246,247,5,99,0,0,247,248,5,111,0,0,248, + 249,5,110,0,0,249,250,5,116,0,0,250,251,5,114,0,0,251,252,5,97,0,0,252, + 253,5,99,0,0,253,254,5,116,0,0,254,36,1,0,0,0,255,256,5,123,0,0,256,38, + 1,0,0,0,257,258,5,125,0,0,258,40,1,0,0,0,259,260,5,114,0,0,260,261,5,101, + 0,0,261,262,5,116,0,0,262,263,5,117,0,0,263,264,5,114,0,0,264,265,5,110, + 0,0,265,42,1,0,0,0,266,267,5,43,0,0,267,268,5,61,0,0,268,44,1,0,0,0,269, + 270,5,45,0,0,270,271,5,61,0,0,271,46,1,0,0,0,272,273,5,43,0,0,273,274,5, + 43,0,0,274,48,1,0,0,0,275,276,5,45,0,0,276,277,5,45,0,0,277,50,1,0,0,0, + 278,279,5,114,0,0,279,280,5,101,0,0,280,281,5,113,0,0,281,282,5,117,0,0, + 282,283,5,105,0,0,283,284,5,114,0,0,284,285,5,101,0,0,285,52,1,0,0,0,286, + 287,5,99,0,0,287,288,5,111,0,0,288,289,5,110,0,0,289,290,5,115,0,0,290, + 291,5,111,0,0,291,292,5,108,0,0,292,293,5,101,0,0,293,294,5,46,0,0,294, + 295,5,108,0,0,295,296,5,111,0,0,296,297,5,103,0,0,297,54,1,0,0,0,298,299, + 5,105,0,0,299,300,5,102,0,0,300,56,1,0,0,0,301,302,5,101,0,0,302,303,5, + 108,0,0,303,304,5,115,0,0,304,305,5,101,0,0,305,58,1,0,0,0,306,307,5,100, + 0,0,307,308,5,111,0,0,308,60,1,0,0,0,309,310,5,119,0,0,310,311,5,104,0, + 0,311,312,5,105,0,0,312,313,5,108,0,0,313,314,5,101,0,0,314,62,1,0,0,0, + 315,316,5,102,0,0,316,317,5,111,0,0,317,318,5,114,0,0,318,64,1,0,0,0,319, + 320,5,110,0,0,320,321,5,101,0,0,321,322,5,119,0,0,322,66,1,0,0,0,323,324, + 5,91,0,0,324,68,1,0,0,0,325,326,5,93,0,0,326,70,1,0,0,0,327,328,5,116,0, + 0,328,329,5,120,0,0,329,330,5,46,0,0,330,331,5,111,0,0,331,332,5,117,0, + 0,332,333,5,116,0,0,333,334,5,112,0,0,334,335,5,117,0,0,335,336,5,116,0, + 0,336,337,5,115,0,0,337,72,1,0,0,0,338,339,5,46,0,0,339,340,5,118,0,0,340, + 341,5,97,0,0,341,342,5,108,0,0,342,343,5,117,0,0,343,344,5,101,0,0,344, + 74,1,0,0,0,345,346,5,46,0,0,346,347,5,108,0,0,347,348,5,111,0,0,348,349, + 5,99,0,0,349,350,5,107,0,0,350,351,5,105,0,0,351,352,5,110,0,0,352,353, + 5,103,0,0,353,354,5,66,0,0,354,355,5,121,0,0,355,356,5,116,0,0,356,357, + 5,101,0,0,357,358,5,99,0,0,358,359,5,111,0,0,359,360,5,100,0,0,360,361, + 5,101,0,0,361,76,1,0,0,0,362,363,5,46,0,0,363,364,5,116,0,0,364,365,5,111, + 0,0,365,366,5,107,0,0,366,367,5,101,0,0,367,368,5,110,0,0,368,369,5,67, + 0,0,369,370,5,97,0,0,370,371,5,116,0,0,371,372,5,101,0,0,372,373,5,103, + 0,0,373,374,5,111,0,0,374,375,5,114,0,0,375,376,5,121,0,0,376,78,1,0,0, + 0,377,378,5,46,0,0,378,379,5,110,0,0,379,380,5,102,0,0,380,381,5,116,0, + 0,381,382,5,67,0,0,382,383,5,111,0,0,383,384,5,109,0,0,384,385,5,109,0, + 0,385,386,5,105,0,0,386,387,5,116,0,0,387,388,5,109,0,0,388,389,5,101,0, + 0,389,390,5,110,0,0,390,391,5,116,0,0,391,80,1,0,0,0,392,393,5,46,0,0,393, + 394,5,116,0,0,394,395,5,111,0,0,395,396,5,107,0,0,396,397,5,101,0,0,397, + 398,5,110,0,0,398,399,5,65,0,0,399,400,5,109,0,0,400,401,5,111,0,0,401, + 402,5,117,0,0,402,403,5,110,0,0,403,404,5,116,0,0,404,82,1,0,0,0,405,406, + 5,116,0,0,406,407,5,120,0,0,407,408,5,46,0,0,408,409,5,105,0,0,409,410, + 5,110,0,0,410,411,5,112,0,0,411,412,5,117,0,0,412,413,5,116,0,0,413,414, + 5,115,0,0,414,84,1,0,0,0,415,416,5,46,0,0,416,417,5,111,0,0,417,418,5,117, + 0,0,418,419,5,116,0,0,419,420,5,112,0,0,420,421,5,111,0,0,421,422,5,105, + 0,0,422,423,5,110,0,0,423,424,5,116,0,0,424,425,5,84,0,0,425,426,5,114, + 0,0,426,427,5,97,0,0,427,428,5,110,0,0,428,429,5,115,0,0,429,430,5,97,0, + 0,430,431,5,99,0,0,431,432,5,116,0,0,432,433,5,105,0,0,433,434,5,111,0, + 0,434,435,5,110,0,0,435,436,5,72,0,0,436,437,5,97,0,0,437,438,5,115,0,0, + 438,439,5,104,0,0,439,86,1,0,0,0,440,441,5,46,0,0,441,442,5,111,0,0,442, + 443,5,117,0,0,443,444,5,116,0,0,444,445,5,112,0,0,445,446,5,111,0,0,446, + 447,5,105,0,0,447,448,5,110,0,0,448,449,5,116,0,0,449,450,5,73,0,0,450, + 451,5,110,0,0,451,452,5,100,0,0,452,453,5,101,0,0,453,454,5,120,0,0,454, + 88,1,0,0,0,455,456,5,46,0,0,456,457,5,117,0,0,457,458,5,110,0,0,458,459, + 5,108,0,0,459,460,5,111,0,0,460,461,5,99,0,0,461,462,5,107,0,0,462,463, + 5,105,0,0,463,464,5,110,0,0,464,465,5,103,0,0,465,466,5,66,0,0,466,467, + 5,121,0,0,467,468,5,116,0,0,468,469,5,101,0,0,469,470,5,99,0,0,470,471, + 5,111,0,0,471,472,5,100,0,0,472,473,5,101,0,0,473,90,1,0,0,0,474,475,5, + 46,0,0,475,476,5,115,0,0,476,477,5,101,0,0,477,478,5,113,0,0,478,479,5, + 117,0,0,479,480,5,101,0,0,480,481,5,110,0,0,481,482,5,99,0,0,482,483,5, + 101,0,0,483,484,5,78,0,0,484,485,5,117,0,0,485,486,5,109,0,0,486,487,5, + 98,0,0,487,488,5,101,0,0,488,489,5,114,0,0,489,92,1,0,0,0,490,491,5,46, + 0,0,491,492,5,114,0,0,492,493,5,101,0,0,493,494,5,118,0,0,494,495,5,101, + 0,0,495,496,5,114,0,0,496,497,5,115,0,0,497,498,5,101,0,0,498,499,5,40, + 0,0,499,500,5,41,0,0,500,94,1,0,0,0,501,502,5,46,0,0,502,503,5,108,0,0, + 503,504,5,101,0,0,504,505,5,110,0,0,505,506,5,103,0,0,506,507,5,116,0,0, + 507,508,5,104,0,0,508,96,1,0,0,0,509,510,5,46,0,0,510,511,5,115,0,0,511, + 512,5,112,0,0,512,513,5,108,0,0,513,514,5,105,0,0,514,515,5,116,0,0,515, + 98,1,0,0,0,516,517,5,46,0,0,517,518,5,115,0,0,518,519,5,108,0,0,519,520, + 5,105,0,0,520,521,5,99,0,0,521,522,5,101,0,0,522,100,1,0,0,0,523,524,5, + 33,0,0,524,102,1,0,0,0,525,526,5,45,0,0,526,104,1,0,0,0,527,528,5,42,0, + 0,528,106,1,0,0,0,529,530,5,47,0,0,530,108,1,0,0,0,531,532,5,37,0,0,532, + 110,1,0,0,0,533,534,5,43,0,0,534,112,1,0,0,0,535,536,5,62,0,0,536,537,5, + 62,0,0,537,114,1,0,0,0,538,539,5,60,0,0,539,540,5,60,0,0,540,116,1,0,0, + 0,541,542,5,61,0,0,542,543,5,61,0,0,543,118,1,0,0,0,544,545,5,33,0,0,545, + 546,5,61,0,0,546,120,1,0,0,0,547,548,5,38,0,0,548,122,1,0,0,0,549,550,5, + 124,0,0,550,124,1,0,0,0,551,552,5,38,0,0,552,553,5,38,0,0,553,126,1,0,0, + 0,554,555,5,124,0,0,555,556,5,124,0,0,556,128,1,0,0,0,557,558,5,117,0,0, + 558,559,5,110,0,0,559,560,5,117,0,0,560,561,5,115,0,0,561,562,5,101,0,0, + 562,563,5,100,0,0,563,130,1,0,0,0,564,566,7,0,0,0,565,564,1,0,0,0,566,567, + 1,0,0,0,567,565,1,0,0,0,567,568,1,0,0,0,568,569,1,0,0,0,569,571,5,46,0, + 0,570,572,7,0,0,0,571,570,1,0,0,0,572,573,1,0,0,0,573,571,1,0,0,0,573,574, + 1,0,0,0,574,575,1,0,0,0,575,577,5,46,0,0,576,578,7,0,0,0,577,576,1,0,0, + 0,578,579,1,0,0,0,579,577,1,0,0,0,579,580,1,0,0,0,580,132,1,0,0,0,581,582, + 5,116,0,0,582,583,5,114,0,0,583,584,5,117,0,0,584,591,5,101,0,0,585,586, + 5,102,0,0,586,587,5,97,0,0,587,588,5,108,0,0,588,589,5,115,0,0,589,591, + 5,101,0,0,590,581,1,0,0,0,590,585,1,0,0,0,591,134,1,0,0,0,592,593,5,115, + 0,0,593,594,5,97,0,0,594,595,5,116,0,0,595,596,5,111,0,0,596,597,5,115, + 0,0,597,598,5,104,0,0,598,599,5,105,0,0,599,650,5,115,0,0,600,601,5,115, + 0,0,601,602,5,97,0,0,602,603,5,116,0,0,603,650,5,115,0,0,604,605,5,102, + 0,0,605,606,5,105,0,0,606,607,5,110,0,0,607,608,5,110,0,0,608,609,5,101, + 0,0,609,650,5,121,0,0,610,611,5,98,0,0,611,612,5,105,0,0,612,613,5,116, + 0,0,613,650,5,115,0,0,614,615,5,98,0,0,615,616,5,105,0,0,616,617,5,116, + 0,0,617,618,5,99,0,0,618,619,5,111,0,0,619,620,5,105,0,0,620,650,5,110, + 0,0,621,622,5,115,0,0,622,623,5,101,0,0,623,624,5,99,0,0,624,625,5,111, + 0,0,625,626,5,110,0,0,626,627,5,100,0,0,627,650,5,115,0,0,628,629,5,109, + 0,0,629,630,5,105,0,0,630,631,5,110,0,0,631,632,5,117,0,0,632,633,5,116, + 0,0,633,634,5,101,0,0,634,650,5,115,0,0,635,636,5,104,0,0,636,637,5,111, + 0,0,637,638,5,117,0,0,638,639,5,114,0,0,639,650,5,115,0,0,640,641,5,100, + 0,0,641,642,5,97,0,0,642,643,5,121,0,0,643,650,5,115,0,0,644,645,5,119, + 0,0,645,646,5,101,0,0,646,647,5,101,0,0,647,648,5,107,0,0,648,650,5,115, + 0,0,649,592,1,0,0,0,649,600,1,0,0,0,649,604,1,0,0,0,649,610,1,0,0,0,649, + 614,1,0,0,0,649,621,1,0,0,0,649,628,1,0,0,0,649,635,1,0,0,0,649,640,1,0, + 0,0,649,644,1,0,0,0,650,136,1,0,0,0,651,653,5,45,0,0,652,651,1,0,0,0,652, + 653,1,0,0,0,653,654,1,0,0,0,654,656,3,139,69,0,655,657,3,141,70,0,656,655, + 1,0,0,0,656,657,1,0,0,0,657,138,1,0,0,0,658,660,7,0,0,0,659,658,1,0,0,0, + 660,661,1,0,0,0,661,659,1,0,0,0,661,662,1,0,0,0,662,671,1,0,0,0,663,665, + 5,95,0,0,664,666,7,0,0,0,665,664,1,0,0,0,666,667,1,0,0,0,667,665,1,0,0, + 0,667,668,1,0,0,0,668,670,1,0,0,0,669,663,1,0,0,0,670,673,1,0,0,0,671,669, + 1,0,0,0,671,672,1,0,0,0,672,140,1,0,0,0,673,671,1,0,0,0,674,675,7,1,0,0, + 675,676,3,139,69,0,676,142,1,0,0,0,677,678,5,105,0,0,678,679,5,110,0,0, + 679,707,5,116,0,0,680,681,5,98,0,0,681,682,5,111,0,0,682,683,5,111,0,0, + 683,707,5,108,0,0,684,685,5,115,0,0,685,686,5,116,0,0,686,687,5,114,0,0, + 687,688,5,105,0,0,688,689,5,110,0,0,689,707,5,103,0,0,690,691,5,112,0,0, + 691,692,5,117,0,0,692,693,5,98,0,0,693,694,5,107,0,0,694,695,5,101,0,0, + 695,707,5,121,0,0,696,697,5,115,0,0,697,698,5,105,0,0,698,707,5,103,0,0, + 699,700,5,100,0,0,700,701,5,97,0,0,701,702,5,116,0,0,702,703,5,97,0,0,703, + 704,5,115,0,0,704,705,5,105,0,0,705,707,5,103,0,0,706,677,1,0,0,0,706,680, + 1,0,0,0,706,684,1,0,0,0,706,690,1,0,0,0,706,696,1,0,0,0,706,699,1,0,0,0, + 707,144,1,0,0,0,708,709,5,98,0,0,709,710,5,121,0,0,710,711,5,116,0,0,711, + 712,5,101,0,0,712,713,5,115,0,0,713,146,1,0,0,0,714,715,5,98,0,0,715,716, + 5,121,0,0,716,717,5,116,0,0,717,718,5,101,0,0,718,719,5,115,0,0,719,720, + 1,0,0,0,720,726,3,149,74,0,721,722,5,98,0,0,722,723,5,121,0,0,723,724,5, + 116,0,0,724,726,5,101,0,0,725,714,1,0,0,0,725,721,1,0,0,0,726,148,1,0,0, + 0,727,731,7,2,0,0,728,730,7,0,0,0,729,728,1,0,0,0,730,733,1,0,0,0,731,729, + 1,0,0,0,731,732,1,0,0,0,732,150,1,0,0,0,733,731,1,0,0,0,734,740,5,34,0, + 0,735,736,5,92,0,0,736,739,5,34,0,0,737,739,8,3,0,0,738,735,1,0,0,0,738, + 737,1,0,0,0,739,742,1,0,0,0,740,741,1,0,0,0,740,738,1,0,0,0,741,743,1,0, + 0,0,742,740,1,0,0,0,743,755,5,34,0,0,744,750,5,39,0,0,745,746,5,92,0,0, + 746,749,5,39,0,0,747,749,8,4,0,0,748,745,1,0,0,0,748,747,1,0,0,0,749,752, + 1,0,0,0,750,751,1,0,0,0,750,748,1,0,0,0,751,753,1,0,0,0,752,750,1,0,0,0, + 753,755,5,39,0,0,754,734,1,0,0,0,754,744,1,0,0,0,755,152,1,0,0,0,756,757, + 5,100,0,0,757,758,5,97,0,0,758,759,5,116,0,0,759,760,5,101,0,0,760,761, + 5,40,0,0,761,762,1,0,0,0,762,763,3,151,75,0,763,764,5,41,0,0,764,154,1, + 0,0,0,765,766,5,48,0,0,766,770,7,5,0,0,767,769,7,6,0,0,768,767,1,0,0,0, + 769,772,1,0,0,0,770,768,1,0,0,0,770,771,1,0,0,0,771,156,1,0,0,0,772,770, + 1,0,0,0,773,774,5,116,0,0,774,775,5,104,0,0,775,776,5,105,0,0,776,777,5, + 115,0,0,777,778,5,46,0,0,778,779,5,97,0,0,779,780,5,103,0,0,780,789,5,101, + 0,0,781,782,5,116,0,0,782,783,5,120,0,0,783,784,5,46,0,0,784,785,5,116, + 0,0,785,786,5,105,0,0,786,787,5,109,0,0,787,789,5,101,0,0,788,773,1,0,0, + 0,788,781,1,0,0,0,789,158,1,0,0,0,790,791,5,117,0,0,791,792,5,110,0,0,792, + 793,5,115,0,0,793,794,5,97,0,0,794,795,5,102,0,0,795,796,5,101,0,0,796, + 797,5,95,0,0,797,798,5,105,0,0,798,799,5,110,0,0,799,839,5,116,0,0,800, + 801,5,117,0,0,801,802,5,110,0,0,802,803,5,115,0,0,803,804,5,97,0,0,804, + 805,5,102,0,0,805,806,5,101,0,0,806,807,5,95,0,0,807,808,5,98,0,0,808,809, + 5,111,0,0,809,810,5,111,0,0,810,839,5,108,0,0,811,812,5,117,0,0,812,813, + 5,110,0,0,813,814,5,115,0,0,814,815,5,97,0,0,815,816,5,102,0,0,816,817, + 5,101,0,0,817,818,5,95,0,0,818,819,5,98,0,0,819,820,5,121,0,0,820,821,5, + 116,0,0,821,822,5,101,0,0,822,823,5,115,0,0,823,825,1,0,0,0,824,826,3,149, + 74,0,825,824,1,0,0,0,825,826,1,0,0,0,826,839,1,0,0,0,827,828,5,117,0,0, + 828,829,5,110,0,0,829,830,5,115,0,0,830,831,5,97,0,0,831,832,5,102,0,0, + 832,833,5,101,0,0,833,834,5,95,0,0,834,835,5,98,0,0,835,836,5,121,0,0,836, + 837,5,116,0,0,837,839,5,101,0,0,838,790,1,0,0,0,838,800,1,0,0,0,838,811, + 1,0,0,0,838,827,1,0,0,0,839,160,1,0,0,0,840,841,5,116,0,0,841,842,5,104, + 0,0,842,843,5,105,0,0,843,844,5,115,0,0,844,845,5,46,0,0,845,846,5,97,0, + 0,846,847,5,99,0,0,847,848,5,116,0,0,848,849,5,105,0,0,849,850,5,118,0, + 0,850,851,5,101,0,0,851,852,5,73,0,0,852,853,5,110,0,0,853,854,5,112,0, + 0,854,855,5,117,0,0,855,856,5,116,0,0,856,857,5,73,0,0,857,858,5,110,0, + 0,858,859,5,100,0,0,859,860,5,101,0,0,860,935,5,120,0,0,861,862,5,116,0, + 0,862,863,5,104,0,0,863,864,5,105,0,0,864,865,5,115,0,0,865,866,5,46,0, + 0,866,867,5,97,0,0,867,868,5,99,0,0,868,869,5,116,0,0,869,870,5,105,0,0, + 870,871,5,118,0,0,871,872,5,101,0,0,872,873,5,66,0,0,873,874,5,121,0,0, + 874,875,5,116,0,0,875,876,5,101,0,0,876,877,5,99,0,0,877,878,5,111,0,0, + 878,879,5,100,0,0,879,935,5,101,0,0,880,881,5,116,0,0,881,882,5,120,0,0, + 882,883,5,46,0,0,883,884,5,105,0,0,884,885,5,110,0,0,885,886,5,112,0,0, + 886,887,5,117,0,0,887,888,5,116,0,0,888,889,5,115,0,0,889,890,5,46,0,0, + 890,891,5,108,0,0,891,892,5,101,0,0,892,893,5,110,0,0,893,894,5,103,0,0, + 894,895,5,116,0,0,895,935,5,104,0,0,896,897,5,116,0,0,897,898,5,120,0,0, + 898,899,5,46,0,0,899,900,5,111,0,0,900,901,5,117,0,0,901,902,5,116,0,0, + 902,903,5,112,0,0,903,904,5,117,0,0,904,905,5,116,0,0,905,906,5,115,0,0, + 906,907,5,46,0,0,907,908,5,108,0,0,908,909,5,101,0,0,909,910,5,110,0,0, + 910,911,5,103,0,0,911,912,5,116,0,0,912,935,5,104,0,0,913,914,5,116,0,0, + 914,915,5,120,0,0,915,916,5,46,0,0,916,917,5,118,0,0,917,918,5,101,0,0, + 918,919,5,114,0,0,919,920,5,115,0,0,920,921,5,105,0,0,921,922,5,111,0,0, + 922,935,5,110,0,0,923,924,5,116,0,0,924,925,5,120,0,0,925,926,5,46,0,0, + 926,927,5,108,0,0,927,928,5,111,0,0,928,929,5,99,0,0,929,930,5,107,0,0, + 930,931,5,116,0,0,931,932,5,105,0,0,932,933,5,109,0,0,933,935,5,101,0,0, + 934,840,1,0,0,0,934,861,1,0,0,0,934,880,1,0,0,0,934,896,1,0,0,0,934,913, + 1,0,0,0,934,923,1,0,0,0,935,162,1,0,0,0,936,940,7,7,0,0,937,939,7,8,0,0, + 938,937,1,0,0,0,939,942,1,0,0,0,940,938,1,0,0,0,940,941,1,0,0,0,941,164, + 1,0,0,0,942,940,1,0,0,0,943,945,7,9,0,0,944,943,1,0,0,0,945,946,1,0,0,0, + 946,944,1,0,0,0,946,947,1,0,0,0,947,948,1,0,0,0,948,949,6,82,0,0,949,166, + 1,0,0,0,950,951,5,47,0,0,951,952,5,42,0,0,952,956,1,0,0,0,953,955,9,0,0, + 0,954,953,1,0,0,0,955,958,1,0,0,0,956,957,1,0,0,0,956,954,1,0,0,0,957,959, + 1,0,0,0,958,956,1,0,0,0,959,960,5,42,0,0,960,961,5,47,0,0,961,962,1,0,0, + 0,962,963,6,83,1,0,963,168,1,0,0,0,964,965,5,47,0,0,965,966,5,47,0,0,966, + 970,1,0,0,0,967,969,8,10,0,0,968,967,1,0,0,0,969,972,1,0,0,0,970,968,1, + 0,0,0,970,971,1,0,0,0,971,973,1,0,0,0,972,970,1,0,0,0,973,974,6,84,1,0, + 974,170,1,0,0,0,28,0,567,573,579,590,649,652,656,661,667,671,706,725,731, + 738,740,748,750,754,770,788,825,838,934,940,946,956,970,2,6,0,0,0,1,0]; private static __ATN: ATN; public static get _ATN(): ATN { diff --git a/packages/cashc/src/grammar/CashScriptParser.ts b/packages/cashc/src/grammar/CashScriptParser.ts index f78d4031..668cd179 100644 --- a/packages/cashc/src/grammar/CashScriptParser.ts +++ b/packages/cashc/src/grammar/CashScriptParser.ts @@ -82,26 +82,27 @@ export default class CashScriptParser extends Parser { public static readonly T__61 = 62; public static readonly T__62 = 63; public static readonly T__63 = 64; - public static readonly VersionLiteral = 65; - public static readonly BooleanLiteral = 66; - public static readonly NumberUnit = 67; - public static readonly NumberLiteral = 68; - public static readonly NumberPart = 69; - public static readonly ExponentPart = 70; - public static readonly PrimitiveType = 71; - public static readonly UnboundedBytes = 72; - public static readonly BoundedBytes = 73; - public static readonly Bound = 74; - public static readonly StringLiteral = 75; - public static readonly DateLiteral = 76; - public static readonly HexLiteral = 77; - public static readonly TxVar = 78; - public static readonly UnsafeCast = 79; - public static readonly NullaryOp = 80; - public static readonly Identifier = 81; - public static readonly WHITESPACE = 82; - public static readonly COMMENT = 83; - public static readonly LINE_COMMENT = 84; + public static readonly T__64 = 65; + public static readonly VersionLiteral = 66; + public static readonly BooleanLiteral = 67; + public static readonly NumberUnit = 68; + public static readonly NumberLiteral = 69; + public static readonly NumberPart = 70; + public static readonly ExponentPart = 71; + public static readonly PrimitiveType = 72; + public static readonly UnboundedBytes = 73; + public static readonly BoundedBytes = 74; + public static readonly Bound = 75; + public static readonly StringLiteral = 76; + public static readonly DateLiteral = 77; + public static readonly HexLiteral = 78; + public static readonly TxVar = 79; + public static readonly UnsafeCast = 80; + public static readonly NullaryOp = 81; + public static readonly Identifier = 82; + public static readonly WHITESPACE = 83; + public static readonly COMMENT = 84; + public static readonly LINE_COMMENT = 85; public static readonly EOF = Token.EOF; public static readonly RULE_sourceFile = 0; public static readonly RULE_pragmaDirective = 1; @@ -190,6 +191,7 @@ export default class CashScriptParser extends Parser { "'=='", "'!='", "'&'", "'|'", "'&&'", "'||'", + "'unused'", null, null, null, null, null, null, @@ -226,7 +228,8 @@ export default class CashScriptParser extends Parser { null, null, null, null, null, null, - null, "VersionLiteral", + null, null, + "VersionLiteral", "BooleanLiteral", "NumberUnit", "NumberLiteral", @@ -310,7 +313,7 @@ export default class CashScriptParser extends Parser { this.state = 103; this._errHandler.sync(this); _la = this._input.LA(1); - while (_la===12 || _la===18 || ((((_la - 71)) & ~0x1F) === 0 && ((1 << (_la - 71)) & 7) !== 0)) { + while (_la===12 || _la===18 || ((((_la - 72)) & ~0x1F) === 0 && ((1 << (_la - 72)) & 7) !== 0)) { { { this.state = 100; @@ -408,7 +411,7 @@ export default class CashScriptParser extends Parser { this.state = 117; this._errHandler.sync(this); _la = this._input.LA(1); - if ((((_la) & ~0x1F) === 0 && ((1 << _la) & 2032) !== 0) || _la===65) { + if ((((_la) & ~0x1F) === 0 && ((1 << _la) & 2032) !== 0) || _la===66) { { this.state = 116; this.versionConstraint(); @@ -544,9 +547,9 @@ export default class CashScriptParser extends Parser { this.globalFunctionDefinition(); } break; - case 71: case 72: case 73: + case 74: this.enterOuterAlt(localctx, 2); { this.state = 131; @@ -769,7 +772,7 @@ export default class CashScriptParser extends Parser { this.state = 182; this._errHandler.sync(this); _la = this._input.LA(1); - while (((((_la - 21)) & ~0x1F) === 0 && ((1 << (_la - 21)) & 3809) !== 0) || ((((_la - 71)) & ~0x1F) === 0 && ((1 << (_la - 71)) & 1031) !== 0)) { + while (((((_la - 21)) & ~0x1F) === 0 && ((1 << (_la - 21)) & 3809) !== 0) || ((((_la - 72)) & ~0x1F) === 0 && ((1 << (_la - 72)) & 1031) !== 0)) { { { this.state = 179; @@ -812,7 +815,7 @@ export default class CashScriptParser extends Parser { this.state = 199; this._errHandler.sync(this); _la = this._input.LA(1); - if (((((_la - 71)) & ~0x1F) === 0 && ((1 << (_la - 71)) & 7) !== 0)) { + if (((((_la - 72)) & ~0x1F) === 0 && ((1 << (_la - 72)) & 7) !== 0)) { { this.state = 188; this.parameter(); @@ -869,12 +872,27 @@ export default class CashScriptParser extends Parser { public parameter(): ParameterContext { let localctx: ParameterContext = new ParameterContext(this, this._ctx, this.state); this.enterRule(localctx, 28, CashScriptParser.RULE_parameter); + let _la: number; try { this.enterOuterAlt(localctx, 1); { this.state = 203; this.typeName(); - this.state = 204; + this.state = 207; + this._errHandler.sync(this); + _la = this._input.LA(1); + while (_la===17 || _la===65) { + { + { + this.state = 204; + this.modifier(); + } + } + this.state = 209; + this._errHandler.sync(this); + _la = this._input.LA(1); + } + this.state = 210; this.match(CashScriptParser.Identifier); } } @@ -898,29 +916,29 @@ export default class CashScriptParser extends Parser { this.enterRule(localctx, 30, CashScriptParser.RULE_block); let _la: number; try { - this.state = 215; + this.state = 221; this._errHandler.sync(this); switch (this._input.LA(1)) { case 19: this.enterOuterAlt(localctx, 1); { - this.state = 206; + this.state = 212; this.match(CashScriptParser.T__18); - this.state = 210; + this.state = 216; this._errHandler.sync(this); _la = this._input.LA(1); - while (((((_la - 21)) & ~0x1F) === 0 && ((1 << (_la - 21)) & 3809) !== 0) || ((((_la - 71)) & ~0x1F) === 0 && ((1 << (_la - 71)) & 1031) !== 0)) { + while (((((_la - 21)) & ~0x1F) === 0 && ((1 << (_la - 21)) & 3809) !== 0) || ((((_la - 72)) & ~0x1F) === 0 && ((1 << (_la - 72)) & 1031) !== 0)) { { { - this.state = 207; + this.state = 213; this.statement(); } } - this.state = 212; + this.state = 218; this._errHandler.sync(this); _la = this._input.LA(1); } - this.state = 213; + this.state = 219; this.match(CashScriptParser.T__19); } break; @@ -931,13 +949,13 @@ export default class CashScriptParser extends Parser { case 30: case 31: case 32: - case 71: case 72: case 73: - case 81: + case 74: + case 82: this.enterOuterAlt(localctx, 2); { - this.state = 214; + this.state = 220; this.statement(); } break; @@ -964,7 +982,7 @@ export default class CashScriptParser extends Parser { let localctx: StatementContext = new StatementContext(this, this._ctx, this.state); this.enterRule(localctx, 32, CashScriptParser.RULE_statement); try { - this.state = 221; + this.state = 227; this._errHandler.sync(this); switch (this._input.LA(1)) { case 28: @@ -973,22 +991,22 @@ export default class CashScriptParser extends Parser { case 32: this.enterOuterAlt(localctx, 1); { - this.state = 217; + this.state = 223; this.controlStatement(); } break; case 21: case 26: case 27: - case 71: case 72: case 73: - case 81: + case 74: + case 82: this.enterOuterAlt(localctx, 2); { - this.state = 218; + this.state = 224; this.nonControlStatement(); - this.state = 219; + this.state = 225; this.match(CashScriptParser.T__1); } break; @@ -1015,62 +1033,62 @@ export default class CashScriptParser extends Parser { let localctx: NonControlStatementContext = new NonControlStatementContext(this, this._ctx, this.state); this.enterRule(localctx, 34, CashScriptParser.RULE_nonControlStatement); try { - this.state = 231; + this.state = 237; this._errHandler.sync(this); - switch ( this._interp.adaptivePredict(this._input, 16, this._ctx) ) { + switch ( this._interp.adaptivePredict(this._input, 17, this._ctx) ) { case 1: this.enterOuterAlt(localctx, 1); { - this.state = 223; + this.state = 229; this.variableDefinition(); } break; case 2: this.enterOuterAlt(localctx, 2); { - this.state = 224; + this.state = 230; this.tupleAssignment(); } break; case 3: this.enterOuterAlt(localctx, 3); { - this.state = 225; + this.state = 231; this.assignStatement(); } break; case 4: this.enterOuterAlt(localctx, 4); { - this.state = 226; + this.state = 232; this.timeOpStatement(); } break; case 5: this.enterOuterAlt(localctx, 5); { - this.state = 227; + this.state = 233; this.requireStatement(); } break; case 6: this.enterOuterAlt(localctx, 6); { - this.state = 228; + this.state = 234; this.functionCallStatement(); } break; case 7: this.enterOuterAlt(localctx, 7); { - this.state = 229; + this.state = 235; this.consoleStatement(); } break; case 8: this.enterOuterAlt(localctx, 8); { - this.state = 230; + this.state = 236; this.returnStatement(); } break; @@ -1097,7 +1115,7 @@ export default class CashScriptParser extends Parser { try { this.enterOuterAlt(localctx, 1); { - this.state = 233; + this.state = 239; this.functionCall(); } } @@ -1123,23 +1141,23 @@ export default class CashScriptParser extends Parser { try { this.enterOuterAlt(localctx, 1); { - this.state = 235; + this.state = 241; this.match(CashScriptParser.T__20); - this.state = 236; + this.state = 242; this.expression(0); - this.state = 241; + this.state = 247; this._errHandler.sync(this); _la = this._input.LA(1); while (_la===15) { { { - this.state = 237; + this.state = 243; this.match(CashScriptParser.T__14); - this.state = 238; + this.state = 244; this.expression(0); } } - this.state = 243; + this.state = 249; this._errHandler.sync(this); _la = this._input.LA(1); } @@ -1164,13 +1182,13 @@ export default class CashScriptParser extends Parser { let localctx: ControlStatementContext = new ControlStatementContext(this, this._ctx, this.state); this.enterRule(localctx, 40, CashScriptParser.RULE_controlStatement); try { - this.state = 246; + this.state = 252; this._errHandler.sync(this); switch (this._input.LA(1)) { case 28: this.enterOuterAlt(localctx, 1); { - this.state = 244; + this.state = 250; this.ifStatement(); } break; @@ -1179,7 +1197,7 @@ export default class CashScriptParser extends Parser { case 32: this.enterOuterAlt(localctx, 2); { - this.state = 245; + this.state = 251; this.loopStatement(); } break; @@ -1209,27 +1227,27 @@ export default class CashScriptParser extends Parser { try { this.enterOuterAlt(localctx, 1); { - this.state = 248; + this.state = 254; this.typeName(); - this.state = 252; + this.state = 258; this._errHandler.sync(this); _la = this._input.LA(1); - while (_la===17) { + while (_la===17 || _la===65) { { { - this.state = 249; + this.state = 255; this.modifier(); } } - this.state = 254; + this.state = 260; this._errHandler.sync(this); _la = this._input.LA(1); } - this.state = 255; + this.state = 261; this.match(CashScriptParser.Identifier); - this.state = 256; + this.state = 262; this.match(CashScriptParser.T__9); - this.state = 257; + this.state = 263; this.expression(0); } } @@ -1255,31 +1273,31 @@ export default class CashScriptParser extends Parser { try { this.enterOuterAlt(localctx, 1); { - this.state = 259; + this.state = 265; this.typeName(); - this.state = 260; + this.state = 266; this.match(CashScriptParser.Identifier); - this.state = 265; + this.state = 271; this._errHandler.sync(this); _la = this._input.LA(1); do { { { - this.state = 261; + this.state = 267; this.match(CashScriptParser.T__14); - this.state = 262; + this.state = 268; this.typeName(); - this.state = 263; + this.state = 269; this.match(CashScriptParser.Identifier); } } - this.state = 267; + this.state = 273; this._errHandler.sync(this); _la = this._input.LA(1); } while (_la===15); - this.state = 269; + this.state = 275; this.match(CashScriptParser.T__9); - this.state = 270; + this.state = 276; this.expression(0); } } @@ -1303,15 +1321,15 @@ export default class CashScriptParser extends Parser { this.enterRule(localctx, 46, CashScriptParser.RULE_assignStatement); let _la: number; try { - this.state = 277; + this.state = 283; this._errHandler.sync(this); - switch ( this._interp.adaptivePredict(this._input, 21, this._ctx) ) { + switch ( this._interp.adaptivePredict(this._input, 22, this._ctx) ) { case 1: this.enterOuterAlt(localctx, 1); { - this.state = 272; + this.state = 278; this.match(CashScriptParser.Identifier); - this.state = 273; + this.state = 279; localctx._op = this._input.LT(1); _la = this._input.LA(1); if(!((((_la) & ~0x1F) === 0 && ((1 << _la) & 12583936) !== 0))) { @@ -1321,16 +1339,16 @@ export default class CashScriptParser extends Parser { this._errHandler.reportMatch(this); this.consume(); } - this.state = 274; + this.state = 280; this.expression(0); } break; case 2: this.enterOuterAlt(localctx, 2); { - this.state = 275; + this.state = 281; this.match(CashScriptParser.Identifier); - this.state = 276; + this.state = 282; localctx._op = this._input.LT(1); _la = this._input.LA(1); if(!(_la===24 || _la===25)) { @@ -1366,29 +1384,29 @@ export default class CashScriptParser extends Parser { try { this.enterOuterAlt(localctx, 1); { - this.state = 279; + this.state = 285; this.match(CashScriptParser.T__25); - this.state = 280; + this.state = 286; this.match(CashScriptParser.T__13); - this.state = 281; + this.state = 287; this.match(CashScriptParser.TxVar); - this.state = 282; + this.state = 288; this.match(CashScriptParser.T__5); - this.state = 283; + this.state = 289; this.expression(0); - this.state = 286; + this.state = 292; this._errHandler.sync(this); _la = this._input.LA(1); if (_la===15) { { - this.state = 284; + this.state = 290; this.match(CashScriptParser.T__14); - this.state = 285; + this.state = 291; this.requireMessage(); } } - this.state = 288; + this.state = 294; this.match(CashScriptParser.T__15); } } @@ -1414,25 +1432,25 @@ export default class CashScriptParser extends Parser { try { this.enterOuterAlt(localctx, 1); { - this.state = 290; + this.state = 296; this.match(CashScriptParser.T__25); - this.state = 291; + this.state = 297; this.match(CashScriptParser.T__13); - this.state = 292; + this.state = 298; this.expression(0); - this.state = 295; + this.state = 301; this._errHandler.sync(this); _la = this._input.LA(1); if (_la===15) { { - this.state = 293; + this.state = 299; this.match(CashScriptParser.T__14); - this.state = 294; + this.state = 300; this.requireMessage(); } } - this.state = 297; + this.state = 303; this.match(CashScriptParser.T__15); } } @@ -1457,9 +1475,9 @@ export default class CashScriptParser extends Parser { try { this.enterOuterAlt(localctx, 1); { - this.state = 299; + this.state = 305; this.match(CashScriptParser.T__26); - this.state = 300; + this.state = 306; this.consoleParameterList(); } } @@ -1484,24 +1502,24 @@ export default class CashScriptParser extends Parser { try { this.enterOuterAlt(localctx, 1); { - this.state = 302; + this.state = 308; this.match(CashScriptParser.T__27); - this.state = 303; + this.state = 309; this.match(CashScriptParser.T__13); - this.state = 304; + this.state = 310; this.expression(0); - this.state = 305; + this.state = 311; this.match(CashScriptParser.T__15); - this.state = 306; + this.state = 312; localctx._ifBlock = this.block(); - this.state = 309; + this.state = 315; this._errHandler.sync(this); - switch ( this._interp.adaptivePredict(this._input, 24, this._ctx) ) { + switch ( this._interp.adaptivePredict(this._input, 25, this._ctx) ) { case 1: { - this.state = 307; + this.state = 313; this.match(CashScriptParser.T__28); - this.state = 308; + this.state = 314; localctx._elseBlock = this.block(); } break; @@ -1527,27 +1545,27 @@ export default class CashScriptParser extends Parser { let localctx: LoopStatementContext = new LoopStatementContext(this, this._ctx, this.state); this.enterRule(localctx, 56, CashScriptParser.RULE_loopStatement); try { - this.state = 314; + this.state = 320; this._errHandler.sync(this); switch (this._input.LA(1)) { case 30: this.enterOuterAlt(localctx, 1); { - this.state = 311; + this.state = 317; this.doWhileStatement(); } break; case 31: this.enterOuterAlt(localctx, 2); { - this.state = 312; + this.state = 318; this.whileStatement(); } break; case 32: this.enterOuterAlt(localctx, 3); { - this.state = 313; + this.state = 319; this.forStatement(); } break; @@ -1576,19 +1594,19 @@ export default class CashScriptParser extends Parser { try { this.enterOuterAlt(localctx, 1); { - this.state = 316; + this.state = 322; this.match(CashScriptParser.T__29); - this.state = 317; + this.state = 323; this.block(); - this.state = 318; + this.state = 324; this.match(CashScriptParser.T__30); - this.state = 319; + this.state = 325; this.match(CashScriptParser.T__13); - this.state = 320; + this.state = 326; this.expression(0); - this.state = 321; + this.state = 327; this.match(CashScriptParser.T__15); - this.state = 322; + this.state = 328; this.match(CashScriptParser.T__1); } } @@ -1613,15 +1631,15 @@ export default class CashScriptParser extends Parser { try { this.enterOuterAlt(localctx, 1); { - this.state = 324; + this.state = 330; this.match(CashScriptParser.T__30); - this.state = 325; + this.state = 331; this.match(CashScriptParser.T__13); - this.state = 326; + this.state = 332; this.expression(0); - this.state = 327; + this.state = 333; this.match(CashScriptParser.T__15); - this.state = 328; + this.state = 334; this.block(); } } @@ -1646,23 +1664,23 @@ export default class CashScriptParser extends Parser { try { this.enterOuterAlt(localctx, 1); { - this.state = 330; + this.state = 336; this.match(CashScriptParser.T__31); - this.state = 331; + this.state = 337; this.match(CashScriptParser.T__13); - this.state = 332; + this.state = 338; this.forInit(); - this.state = 333; + this.state = 339; this.match(CashScriptParser.T__1); - this.state = 334; + this.state = 340; this.expression(0); - this.state = 335; + this.state = 341; this.match(CashScriptParser.T__1); - this.state = 336; + this.state = 342; this.assignStatement(); - this.state = 337; + this.state = 343; this.match(CashScriptParser.T__15); - this.state = 338; + this.state = 344; this.block(); } } @@ -1685,22 +1703,22 @@ export default class CashScriptParser extends Parser { let localctx: ForInitContext = new ForInitContext(this, this._ctx, this.state); this.enterRule(localctx, 64, CashScriptParser.RULE_forInit); try { - this.state = 342; + this.state = 348; this._errHandler.sync(this); switch (this._input.LA(1)) { - case 71: case 72: case 73: + case 74: this.enterOuterAlt(localctx, 1); { - this.state = 340; + this.state = 346; this.variableDefinition(); } break; - case 81: + case 82: this.enterOuterAlt(localctx, 2); { - this.state = 341; + this.state = 347; this.assignStatement(); } break; @@ -1729,7 +1747,7 @@ export default class CashScriptParser extends Parser { try { this.enterOuterAlt(localctx, 1); { - this.state = 344; + this.state = 350; this.match(CashScriptParser.StringLiteral); } } @@ -1752,24 +1770,24 @@ export default class CashScriptParser extends Parser { let localctx: ConsoleParameterContext = new ConsoleParameterContext(this, this._ctx, this.state); this.enterRule(localctx, 68, CashScriptParser.RULE_consoleParameter); try { - this.state = 348; + this.state = 354; this._errHandler.sync(this); switch (this._input.LA(1)) { - case 81: + case 82: this.enterOuterAlt(localctx, 1); { - this.state = 346; + this.state = 352; this.match(CashScriptParser.Identifier); } break; - case 66: - case 68: - case 75: + case 67: + case 69: case 76: case 77: + case 78: this.enterOuterAlt(localctx, 2); { - this.state = 347; + this.state = 353; this.literal(); } break; @@ -1800,39 +1818,39 @@ export default class CashScriptParser extends Parser { let _alt: number; this.enterOuterAlt(localctx, 1); { - this.state = 350; + this.state = 356; this.match(CashScriptParser.T__13); - this.state = 362; + this.state = 368; this._errHandler.sync(this); _la = this._input.LA(1); - if (((((_la - 66)) & ~0x1F) === 0 && ((1 << (_la - 66)) & 36357) !== 0)) { + if (((((_la - 67)) & ~0x1F) === 0 && ((1 << (_la - 67)) & 36357) !== 0)) { { - this.state = 351; + this.state = 357; this.consoleParameter(); - this.state = 356; + this.state = 362; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 28, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 29, this._ctx); while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { if (_alt === 1) { { { - this.state = 352; + this.state = 358; this.match(CashScriptParser.T__14); - this.state = 353; + this.state = 359; this.consoleParameter(); } } } - this.state = 358; + this.state = 364; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 28, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 29, this._ctx); } - this.state = 360; + this.state = 366; this._errHandler.sync(this); _la = this._input.LA(1); if (_la===15) { { - this.state = 359; + this.state = 365; this.match(CashScriptParser.T__14); } } @@ -1840,7 +1858,7 @@ export default class CashScriptParser extends Parser { } } - this.state = 364; + this.state = 370; this.match(CashScriptParser.T__15); } } @@ -1865,9 +1883,9 @@ export default class CashScriptParser extends Parser { try { this.enterOuterAlt(localctx, 1); { - this.state = 366; + this.state = 372; this.match(CashScriptParser.Identifier); - this.state = 367; + this.state = 373; this.expressionList(); } } @@ -1894,39 +1912,39 @@ export default class CashScriptParser extends Parser { let _alt: number; this.enterOuterAlt(localctx, 1); { - this.state = 369; + this.state = 375; this.match(CashScriptParser.T__13); - this.state = 381; + this.state = 387; this._errHandler.sync(this); _la = this._input.LA(1); - if (_la===5 || _la===14 || ((((_la - 33)) & ~0x1F) === 0 && ((1 << (_la - 33)) & 786955) !== 0) || ((((_la - 66)) & ~0x1F) === 0 && ((1 << (_la - 66)) & 61029) !== 0)) { + if (_la===5 || _la===14 || ((((_la - 33)) & ~0x1F) === 0 && ((1 << (_la - 33)) & 786955) !== 0) || ((((_la - 67)) & ~0x1F) === 0 && ((1 << (_la - 67)) & 61029) !== 0)) { { - this.state = 370; + this.state = 376; this.expression(0); - this.state = 375; + this.state = 381; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 31, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 32, this._ctx); while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { if (_alt === 1) { { { - this.state = 371; + this.state = 377; this.match(CashScriptParser.T__14); - this.state = 372; + this.state = 378; this.expression(0); } } } - this.state = 377; + this.state = 383; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 31, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 32, this._ctx); } - this.state = 379; + this.state = 385; this._errHandler.sync(this); _la = this._input.LA(1); if (_la===15) { { - this.state = 378; + this.state = 384; this.match(CashScriptParser.T__14); } } @@ -1934,7 +1952,7 @@ export default class CashScriptParser extends Parser { } } - this.state = 383; + this.state = 389; this.match(CashScriptParser.T__15); } } @@ -1972,20 +1990,20 @@ export default class CashScriptParser extends Parser { let _alt: number; this.enterOuterAlt(localctx, 1); { - this.state = 434; + this.state = 440; this._errHandler.sync(this); - switch ( this._interp.adaptivePredict(this._input, 38, this._ctx) ) { + switch ( this._interp.adaptivePredict(this._input, 39, this._ctx) ) { case 1: { localctx = new ParenthesisedContext(this, localctx); this._ctx = localctx; _prevctx = localctx; - this.state = 386; + this.state = 392; this.match(CashScriptParser.T__13); - this.state = 387; + this.state = 393; this.expression(0); - this.state = 388; + this.state = 394; this.match(CashScriptParser.T__15); } break; @@ -1994,23 +2012,23 @@ export default class CashScriptParser extends Parser { localctx = new CastContext(this, localctx); this._ctx = localctx; _prevctx = localctx; - this.state = 390; + this.state = 396; this.typeCast(); - this.state = 391; + this.state = 397; this.match(CashScriptParser.T__13); - this.state = 392; + this.state = 398; (localctx as CastContext)._castable = this.expression(0); - this.state = 394; + this.state = 400; this._errHandler.sync(this); _la = this._input.LA(1); if (_la===15) { { - this.state = 393; + this.state = 399; this.match(CashScriptParser.T__14); } } - this.state = 396; + this.state = 402; this.match(CashScriptParser.T__15); } break; @@ -2019,7 +2037,7 @@ export default class CashScriptParser extends Parser { localctx = new FunctionCallExpressionContext(this, localctx); this._ctx = localctx; _prevctx = localctx; - this.state = 398; + this.state = 404; this.functionCall(); } break; @@ -2028,11 +2046,11 @@ export default class CashScriptParser extends Parser { localctx = new InstantiationContext(this, localctx); this._ctx = localctx; _prevctx = localctx; - this.state = 399; + this.state = 405; this.match(CashScriptParser.T__32); - this.state = 400; + this.state = 406; this.match(CashScriptParser.Identifier); - this.state = 401; + this.state = 407; this.expressionList(); } break; @@ -2041,15 +2059,15 @@ export default class CashScriptParser extends Parser { localctx = new UnaryIntrospectionOpContext(this, localctx); this._ctx = localctx; _prevctx = localctx; - this.state = 402; + this.state = 408; (localctx as UnaryIntrospectionOpContext)._scope = this.match(CashScriptParser.T__35); - this.state = 403; + this.state = 409; this.match(CashScriptParser.T__33); - this.state = 404; + this.state = 410; this.expression(0); - this.state = 405; + this.state = 411; this.match(CashScriptParser.T__34); - this.state = 406; + this.state = 412; (localctx as UnaryIntrospectionOpContext)._op = this._input.LT(1); _la = this._input.LA(1); if(!(((((_la - 37)) & ~0x1F) === 0 && ((1 << (_la - 37)) & 31) !== 0))) { @@ -2066,15 +2084,15 @@ export default class CashScriptParser extends Parser { localctx = new UnaryIntrospectionOpContext(this, localctx); this._ctx = localctx; _prevctx = localctx; - this.state = 408; + this.state = 414; (localctx as UnaryIntrospectionOpContext)._scope = this.match(CashScriptParser.T__41); - this.state = 409; + this.state = 415; this.match(CashScriptParser.T__33); - this.state = 410; + this.state = 416; this.expression(0); - this.state = 411; + this.state = 417; this.match(CashScriptParser.T__34); - this.state = 412; + this.state = 418; (localctx as UnaryIntrospectionOpContext)._op = this._input.LT(1); _la = this._input.LA(1); if(!(((((_la - 37)) & ~0x1F) === 0 && ((1 << (_la - 37)) & 991) !== 0))) { @@ -2091,7 +2109,7 @@ export default class CashScriptParser extends Parser { localctx = new UnaryOpContext(this, localctx); this._ctx = localctx; _prevctx = localctx; - this.state = 414; + this.state = 420; (localctx as UnaryOpContext)._op = this._input.LT(1); _la = this._input.LA(1); if(!(_la===5 || _la===51 || _la===52)) { @@ -2101,7 +2119,7 @@ export default class CashScriptParser extends Parser { this._errHandler.reportMatch(this); this.consume(); } - this.state = 415; + this.state = 421; this.expression(15); } break; @@ -2110,39 +2128,39 @@ export default class CashScriptParser extends Parser { localctx = new ArrayContext(this, localctx); this._ctx = localctx; _prevctx = localctx; - this.state = 416; + this.state = 422; this.match(CashScriptParser.T__33); - this.state = 428; + this.state = 434; this._errHandler.sync(this); _la = this._input.LA(1); - if (_la===5 || _la===14 || ((((_la - 33)) & ~0x1F) === 0 && ((1 << (_la - 33)) & 786955) !== 0) || ((((_la - 66)) & ~0x1F) === 0 && ((1 << (_la - 66)) & 61029) !== 0)) { + if (_la===5 || _la===14 || ((((_la - 33)) & ~0x1F) === 0 && ((1 << (_la - 33)) & 786955) !== 0) || ((((_la - 67)) & ~0x1F) === 0 && ((1 << (_la - 67)) & 61029) !== 0)) { { - this.state = 417; + this.state = 423; this.expression(0); - this.state = 422; + this.state = 428; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 35, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 36, this._ctx); while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { if (_alt === 1) { { { - this.state = 418; + this.state = 424; this.match(CashScriptParser.T__14); - this.state = 419; + this.state = 425; this.expression(0); } } } - this.state = 424; + this.state = 430; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 35, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 36, this._ctx); } - this.state = 426; + this.state = 432; this._errHandler.sync(this); _la = this._input.LA(1); if (_la===15) { { - this.state = 425; + this.state = 431; this.match(CashScriptParser.T__14); } } @@ -2150,7 +2168,7 @@ export default class CashScriptParser extends Parser { } } - this.state = 430; + this.state = 436; this.match(CashScriptParser.T__34); } break; @@ -2159,7 +2177,7 @@ export default class CashScriptParser extends Parser { localctx = new NullaryOpContext(this, localctx); this._ctx = localctx; _prevctx = localctx; - this.state = 431; + this.state = 437; this.match(CashScriptParser.NullaryOp); } break; @@ -2168,7 +2186,7 @@ export default class CashScriptParser extends Parser { localctx = new IdentifierContext(this, localctx); this._ctx = localctx; _prevctx = localctx; - this.state = 432; + this.state = 438; this.match(CashScriptParser.Identifier); } break; @@ -2177,15 +2195,15 @@ export default class CashScriptParser extends Parser { localctx = new LiteralExpressionContext(this, localctx); this._ctx = localctx; _prevctx = localctx; - this.state = 433; + this.state = 439; this.literal(); } break; } this._ctx.stop = this._input.LT(-1); - this.state = 488; + this.state = 494; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 40, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 41, this._ctx); while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { if (_alt === 1) { if (this._parseListeners != null) { @@ -2193,19 +2211,19 @@ export default class CashScriptParser extends Parser { } _prevctx = localctx; { - this.state = 486; + this.state = 492; this._errHandler.sync(this); - switch ( this._interp.adaptivePredict(this._input, 39, this._ctx) ) { + switch ( this._interp.adaptivePredict(this._input, 40, this._ctx) ) { case 1: { localctx = new BinaryOpContext(this, new ExpressionContext(this, _parentctx, _parentState)); (localctx as BinaryOpContext)._left = _prevctx; this.pushNewRecursionContext(localctx, _startState, CashScriptParser.RULE_expression); - this.state = 436; + this.state = 442; if (!(this.precpred(this._ctx, 14))) { throw this.createFailedPredicateException("this.precpred(this._ctx, 14)"); } - this.state = 437; + this.state = 443; (localctx as BinaryOpContext)._op = this._input.LT(1); _la = this._input.LA(1); if(!(((((_la - 53)) & ~0x1F) === 0 && ((1 << (_la - 53)) & 7) !== 0))) { @@ -2215,7 +2233,7 @@ export default class CashScriptParser extends Parser { this._errHandler.reportMatch(this); this.consume(); } - this.state = 438; + this.state = 444; (localctx as BinaryOpContext)._right = this.expression(15); } break; @@ -2224,11 +2242,11 @@ export default class CashScriptParser extends Parser { localctx = new BinaryOpContext(this, new ExpressionContext(this, _parentctx, _parentState)); (localctx as BinaryOpContext)._left = _prevctx; this.pushNewRecursionContext(localctx, _startState, CashScriptParser.RULE_expression); - this.state = 439; + this.state = 445; if (!(this.precpred(this._ctx, 13))) { throw this.createFailedPredicateException("this.precpred(this._ctx, 13)"); } - this.state = 440; + this.state = 446; (localctx as BinaryOpContext)._op = this._input.LT(1); _la = this._input.LA(1); if(!(_la===52 || _la===56)) { @@ -2238,7 +2256,7 @@ export default class CashScriptParser extends Parser { this._errHandler.reportMatch(this); this.consume(); } - this.state = 441; + this.state = 447; (localctx as BinaryOpContext)._right = this.expression(14); } break; @@ -2247,11 +2265,11 @@ export default class CashScriptParser extends Parser { localctx = new BinaryOpContext(this, new ExpressionContext(this, _parentctx, _parentState)); (localctx as BinaryOpContext)._left = _prevctx; this.pushNewRecursionContext(localctx, _startState, CashScriptParser.RULE_expression); - this.state = 442; + this.state = 448; if (!(this.precpred(this._ctx, 12))) { throw this.createFailedPredicateException("this.precpred(this._ctx, 12)"); } - this.state = 443; + this.state = 449; (localctx as BinaryOpContext)._op = this._input.LT(1); _la = this._input.LA(1); if(!(_la===57 || _la===58)) { @@ -2261,7 +2279,7 @@ export default class CashScriptParser extends Parser { this._errHandler.reportMatch(this); this.consume(); } - this.state = 444; + this.state = 450; (localctx as BinaryOpContext)._right = this.expression(13); } break; @@ -2270,11 +2288,11 @@ export default class CashScriptParser extends Parser { localctx = new BinaryOpContext(this, new ExpressionContext(this, _parentctx, _parentState)); (localctx as BinaryOpContext)._left = _prevctx; this.pushNewRecursionContext(localctx, _startState, CashScriptParser.RULE_expression); - this.state = 445; + this.state = 451; if (!(this.precpred(this._ctx, 11))) { throw this.createFailedPredicateException("this.precpred(this._ctx, 11)"); } - this.state = 446; + this.state = 452; (localctx as BinaryOpContext)._op = this._input.LT(1); _la = this._input.LA(1); if(!((((_la) & ~0x1F) === 0 && ((1 << _la) & 960) !== 0))) { @@ -2284,7 +2302,7 @@ export default class CashScriptParser extends Parser { this._errHandler.reportMatch(this); this.consume(); } - this.state = 447; + this.state = 453; (localctx as BinaryOpContext)._right = this.expression(12); } break; @@ -2293,11 +2311,11 @@ export default class CashScriptParser extends Parser { localctx = new BinaryOpContext(this, new ExpressionContext(this, _parentctx, _parentState)); (localctx as BinaryOpContext)._left = _prevctx; this.pushNewRecursionContext(localctx, _startState, CashScriptParser.RULE_expression); - this.state = 448; + this.state = 454; if (!(this.precpred(this._ctx, 10))) { throw this.createFailedPredicateException("this.precpred(this._ctx, 10)"); } - this.state = 449; + this.state = 455; (localctx as BinaryOpContext)._op = this._input.LT(1); _la = this._input.LA(1); if(!(_la===59 || _la===60)) { @@ -2307,7 +2325,7 @@ export default class CashScriptParser extends Parser { this._errHandler.reportMatch(this); this.consume(); } - this.state = 450; + this.state = 456; (localctx as BinaryOpContext)._right = this.expression(11); } break; @@ -2316,13 +2334,13 @@ export default class CashScriptParser extends Parser { localctx = new BinaryOpContext(this, new ExpressionContext(this, _parentctx, _parentState)); (localctx as BinaryOpContext)._left = _prevctx; this.pushNewRecursionContext(localctx, _startState, CashScriptParser.RULE_expression); - this.state = 451; + this.state = 457; if (!(this.precpred(this._ctx, 9))) { throw this.createFailedPredicateException("this.precpred(this._ctx, 9)"); } - this.state = 452; + this.state = 458; (localctx as BinaryOpContext)._op = this.match(CashScriptParser.T__60); - this.state = 453; + this.state = 459; (localctx as BinaryOpContext)._right = this.expression(10); } break; @@ -2331,13 +2349,13 @@ export default class CashScriptParser extends Parser { localctx = new BinaryOpContext(this, new ExpressionContext(this, _parentctx, _parentState)); (localctx as BinaryOpContext)._left = _prevctx; this.pushNewRecursionContext(localctx, _startState, CashScriptParser.RULE_expression); - this.state = 454; + this.state = 460; if (!(this.precpred(this._ctx, 8))) { throw this.createFailedPredicateException("this.precpred(this._ctx, 8)"); } - this.state = 455; + this.state = 461; (localctx as BinaryOpContext)._op = this.match(CashScriptParser.T__3); - this.state = 456; + this.state = 462; (localctx as BinaryOpContext)._right = this.expression(9); } break; @@ -2346,13 +2364,13 @@ export default class CashScriptParser extends Parser { localctx = new BinaryOpContext(this, new ExpressionContext(this, _parentctx, _parentState)); (localctx as BinaryOpContext)._left = _prevctx; this.pushNewRecursionContext(localctx, _startState, CashScriptParser.RULE_expression); - this.state = 457; + this.state = 463; if (!(this.precpred(this._ctx, 7))) { throw this.createFailedPredicateException("this.precpred(this._ctx, 7)"); } - this.state = 458; + this.state = 464; (localctx as BinaryOpContext)._op = this.match(CashScriptParser.T__61); - this.state = 459; + this.state = 465; (localctx as BinaryOpContext)._right = this.expression(8); } break; @@ -2361,13 +2379,13 @@ export default class CashScriptParser extends Parser { localctx = new BinaryOpContext(this, new ExpressionContext(this, _parentctx, _parentState)); (localctx as BinaryOpContext)._left = _prevctx; this.pushNewRecursionContext(localctx, _startState, CashScriptParser.RULE_expression); - this.state = 460; + this.state = 466; if (!(this.precpred(this._ctx, 6))) { throw this.createFailedPredicateException("this.precpred(this._ctx, 6)"); } - this.state = 461; + this.state = 467; (localctx as BinaryOpContext)._op = this.match(CashScriptParser.T__62); - this.state = 462; + this.state = 468; (localctx as BinaryOpContext)._right = this.expression(7); } break; @@ -2376,13 +2394,13 @@ export default class CashScriptParser extends Parser { localctx = new BinaryOpContext(this, new ExpressionContext(this, _parentctx, _parentState)); (localctx as BinaryOpContext)._left = _prevctx; this.pushNewRecursionContext(localctx, _startState, CashScriptParser.RULE_expression); - this.state = 463; + this.state = 469; if (!(this.precpred(this._ctx, 5))) { throw this.createFailedPredicateException("this.precpred(this._ctx, 5)"); } - this.state = 464; + this.state = 470; (localctx as BinaryOpContext)._op = this.match(CashScriptParser.T__63); - this.state = 465; + this.state = 471; (localctx as BinaryOpContext)._right = this.expression(6); } break; @@ -2390,15 +2408,15 @@ export default class CashScriptParser extends Parser { { localctx = new TupleIndexOpContext(this, new ExpressionContext(this, _parentctx, _parentState)); this.pushNewRecursionContext(localctx, _startState, CashScriptParser.RULE_expression); - this.state = 466; + this.state = 472; if (!(this.precpred(this._ctx, 21))) { throw this.createFailedPredicateException("this.precpred(this._ctx, 21)"); } - this.state = 467; + this.state = 473; this.match(CashScriptParser.T__33); - this.state = 468; + this.state = 474; (localctx as TupleIndexOpContext)._index = this.match(CashScriptParser.NumberLiteral); - this.state = 469; + this.state = 475; this.match(CashScriptParser.T__34); } break; @@ -2406,11 +2424,11 @@ export default class CashScriptParser extends Parser { { localctx = new UnaryOpContext(this, new ExpressionContext(this, _parentctx, _parentState)); this.pushNewRecursionContext(localctx, _startState, CashScriptParser.RULE_expression); - this.state = 470; + this.state = 476; if (!(this.precpred(this._ctx, 18))) { throw this.createFailedPredicateException("this.precpred(this._ctx, 18)"); } - this.state = 471; + this.state = 477; (localctx as UnaryOpContext)._op = this._input.LT(1); _la = this._input.LA(1); if(!(_la===47 || _la===48)) { @@ -2427,17 +2445,17 @@ export default class CashScriptParser extends Parser { localctx = new BinaryOpContext(this, new ExpressionContext(this, _parentctx, _parentState)); (localctx as BinaryOpContext)._left = _prevctx; this.pushNewRecursionContext(localctx, _startState, CashScriptParser.RULE_expression); - this.state = 472; + this.state = 478; if (!(this.precpred(this._ctx, 17))) { throw this.createFailedPredicateException("this.precpred(this._ctx, 17)"); } - this.state = 473; + this.state = 479; (localctx as BinaryOpContext)._op = this.match(CashScriptParser.T__48); - this.state = 474; + this.state = 480; this.match(CashScriptParser.T__13); - this.state = 475; + this.state = 481; (localctx as BinaryOpContext)._right = this.expression(0); - this.state = 476; + this.state = 482; this.match(CashScriptParser.T__15); } break; @@ -2446,30 +2464,30 @@ export default class CashScriptParser extends Parser { localctx = new SliceContext(this, new ExpressionContext(this, _parentctx, _parentState)); (localctx as SliceContext)._element = _prevctx; this.pushNewRecursionContext(localctx, _startState, CashScriptParser.RULE_expression); - this.state = 478; + this.state = 484; if (!(this.precpred(this._ctx, 16))) { throw this.createFailedPredicateException("this.precpred(this._ctx, 16)"); } - this.state = 479; + this.state = 485; this.match(CashScriptParser.T__49); - this.state = 480; + this.state = 486; this.match(CashScriptParser.T__13); - this.state = 481; + this.state = 487; (localctx as SliceContext)._start = this.expression(0); - this.state = 482; + this.state = 488; this.match(CashScriptParser.T__14); - this.state = 483; + this.state = 489; (localctx as SliceContext)._end = this.expression(0); - this.state = 484; + this.state = 490; this.match(CashScriptParser.T__15); } break; } } } - this.state = 490; + this.state = 496; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 40, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 41, this._ctx); } } } @@ -2491,11 +2509,19 @@ export default class CashScriptParser extends Parser { public modifier(): ModifierContext { let localctx: ModifierContext = new ModifierContext(this, this._ctx, this.state); this.enterRule(localctx, 78, CashScriptParser.RULE_modifier); + let _la: number; try { this.enterOuterAlt(localctx, 1); { - this.state = 491; - this.match(CashScriptParser.T__16); + this.state = 497; + _la = this._input.LA(1); + if(!(_la===17 || _la===65)) { + this._errHandler.recoverInline(this); + } + else { + this._errHandler.reportMatch(this); + this.consume(); + } } } catch (re) { @@ -2517,41 +2543,41 @@ export default class CashScriptParser extends Parser { let localctx: LiteralContext = new LiteralContext(this, this._ctx, this.state); this.enterRule(localctx, 80, CashScriptParser.RULE_literal); try { - this.state = 498; + this.state = 504; this._errHandler.sync(this); switch (this._input.LA(1)) { - case 66: + case 67: this.enterOuterAlt(localctx, 1); { - this.state = 493; + this.state = 499; this.match(CashScriptParser.BooleanLiteral); } break; - case 68: + case 69: this.enterOuterAlt(localctx, 2); { - this.state = 494; + this.state = 500; this.numberLiteral(); } break; - case 75: + case 76: this.enterOuterAlt(localctx, 3); { - this.state = 495; + this.state = 501; this.match(CashScriptParser.StringLiteral); } break; - case 76: + case 77: this.enterOuterAlt(localctx, 4); { - this.state = 496; + this.state = 502; this.match(CashScriptParser.DateLiteral); } break; - case 77: + case 78: this.enterOuterAlt(localctx, 5); { - this.state = 497; + this.state = 503; this.match(CashScriptParser.HexLiteral); } break; @@ -2580,14 +2606,14 @@ export default class CashScriptParser extends Parser { try { this.enterOuterAlt(localctx, 1); { - this.state = 500; + this.state = 506; this.match(CashScriptParser.NumberLiteral); - this.state = 502; + this.state = 508; this._errHandler.sync(this); - switch ( this._interp.adaptivePredict(this._input, 42, this._ctx) ) { + switch ( this._interp.adaptivePredict(this._input, 43, this._ctx) ) { case 1: { - this.state = 501; + this.state = 507; this.match(CashScriptParser.NumberUnit); } break; @@ -2616,9 +2642,9 @@ export default class CashScriptParser extends Parser { try { this.enterOuterAlt(localctx, 1); { - this.state = 504; + this.state = 510; _la = this._input.LA(1); - if(!(((((_la - 71)) & ~0x1F) === 0 && ((1 << (_la - 71)) & 7) !== 0))) { + if(!(((((_la - 72)) & ~0x1F) === 0 && ((1 << (_la - 72)) & 7) !== 0))) { this._errHandler.recoverInline(this); } else { @@ -2649,9 +2675,9 @@ export default class CashScriptParser extends Parser { try { this.enterOuterAlt(localctx, 1); { - this.state = 506; + this.state = 512; _la = this._input.LA(1); - if(!(((((_la - 71)) & ~0x1F) === 0 && ((1 << (_la - 71)) & 259) !== 0))) { + if(!(((((_la - 72)) & ~0x1F) === 0 && ((1 << (_la - 72)) & 259) !== 0))) { this._errHandler.recoverInline(this); } else { @@ -2716,7 +2742,7 @@ export default class CashScriptParser extends Parser { return true; } - public static readonly _serializedATN: number[] = [4,1,84,509,2,0,7,0,2, + public static readonly _serializedATN: number[] = [4,1,85,515,2,0,7,0,2, 1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7,5,2,6,7,6,2,7,7,7,2,8,7,8,2,9,7,9,2, 10,7,10,2,11,7,11,2,12,7,12,2,13,7,13,2,14,7,14,2,15,7,15,2,16,7,16,2,17, 7,17,2,18,7,18,2,19,7,19,2,20,7,20,2,21,7,21,2,22,7,22,2,23,7,23,2,24,7, @@ -2731,159 +2757,162 @@ export default class CashScriptParser extends Parser { 10,10,12,10,170,9,10,1,10,1,10,1,11,1,11,1,11,1,11,1,11,1,12,1,12,5,12, 181,8,12,10,12,12,12,184,9,12,1,12,1,12,1,13,1,13,1,13,1,13,5,13,192,8, 13,10,13,12,13,195,9,13,1,13,3,13,198,8,13,3,13,200,8,13,1,13,1,13,1,14, - 1,14,1,14,1,15,1,15,5,15,209,8,15,10,15,12,15,212,9,15,1,15,1,15,3,15,216, - 8,15,1,16,1,16,1,16,1,16,3,16,222,8,16,1,17,1,17,1,17,1,17,1,17,1,17,1, - 17,1,17,3,17,232,8,17,1,18,1,18,1,19,1,19,1,19,1,19,5,19,240,8,19,10,19, - 12,19,243,9,19,1,20,1,20,3,20,247,8,20,1,21,1,21,5,21,251,8,21,10,21,12, - 21,254,9,21,1,21,1,21,1,21,1,21,1,22,1,22,1,22,1,22,1,22,1,22,4,22,266, - 8,22,11,22,12,22,267,1,22,1,22,1,22,1,23,1,23,1,23,1,23,1,23,3,23,278,8, - 23,1,24,1,24,1,24,1,24,1,24,1,24,1,24,3,24,287,8,24,1,24,1,24,1,25,1,25, - 1,25,1,25,1,25,3,25,296,8,25,1,25,1,25,1,26,1,26,1,26,1,27,1,27,1,27,1, - 27,1,27,1,27,1,27,3,27,310,8,27,1,28,1,28,1,28,3,28,315,8,28,1,29,1,29, - 1,29,1,29,1,29,1,29,1,29,1,29,1,30,1,30,1,30,1,30,1,30,1,30,1,31,1,31,1, - 31,1,31,1,31,1,31,1,31,1,31,1,31,1,31,1,32,1,32,3,32,343,8,32,1,33,1,33, - 1,34,1,34,3,34,349,8,34,1,35,1,35,1,35,1,35,5,35,355,8,35,10,35,12,35,358, - 9,35,1,35,3,35,361,8,35,3,35,363,8,35,1,35,1,35,1,36,1,36,1,36,1,37,1,37, - 1,37,1,37,5,37,374,8,37,10,37,12,37,377,9,37,1,37,3,37,380,8,37,3,37,382, - 8,37,1,37,1,37,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,3,38,395,8, - 38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38, - 1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,5,38,421,8,38,10,38,12, - 38,424,9,38,1,38,3,38,427,8,38,3,38,429,8,38,1,38,1,38,1,38,1,38,3,38,435, - 8,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1, + 1,14,5,14,206,8,14,10,14,12,14,209,9,14,1,14,1,14,1,15,1,15,5,15,215,8, + 15,10,15,12,15,218,9,15,1,15,1,15,3,15,222,8,15,1,16,1,16,1,16,1,16,3,16, + 228,8,16,1,17,1,17,1,17,1,17,1,17,1,17,1,17,1,17,3,17,238,8,17,1,18,1,18, + 1,19,1,19,1,19,1,19,5,19,246,8,19,10,19,12,19,249,9,19,1,20,1,20,3,20,253, + 8,20,1,21,1,21,5,21,257,8,21,10,21,12,21,260,9,21,1,21,1,21,1,21,1,21,1, + 22,1,22,1,22,1,22,1,22,1,22,4,22,272,8,22,11,22,12,22,273,1,22,1,22,1,22, + 1,23,1,23,1,23,1,23,1,23,3,23,284,8,23,1,24,1,24,1,24,1,24,1,24,1,24,1, + 24,3,24,293,8,24,1,24,1,24,1,25,1,25,1,25,1,25,1,25,3,25,302,8,25,1,25, + 1,25,1,26,1,26,1,26,1,27,1,27,1,27,1,27,1,27,1,27,1,27,3,27,316,8,27,1, + 28,1,28,1,28,3,28,321,8,28,1,29,1,29,1,29,1,29,1,29,1,29,1,29,1,29,1,30, + 1,30,1,30,1,30,1,30,1,30,1,31,1,31,1,31,1,31,1,31,1,31,1,31,1,31,1,31,1, + 31,1,32,1,32,3,32,349,8,32,1,33,1,33,1,34,1,34,3,34,355,8,34,1,35,1,35, + 1,35,1,35,5,35,361,8,35,10,35,12,35,364,9,35,1,35,3,35,367,8,35,3,35,369, + 8,35,1,35,1,35,1,36,1,36,1,36,1,37,1,37,1,37,1,37,5,37,380,8,37,10,37,12, + 37,383,9,37,1,37,3,37,386,8,37,3,37,388,8,37,1,37,1,37,1,38,1,38,1,38,1, + 38,1,38,1,38,1,38,1,38,1,38,3,38,401,8,38,1,38,1,38,1,38,1,38,1,38,1,38, + 1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1, + 38,1,38,1,38,1,38,5,38,427,8,38,10,38,12,38,430,9,38,1,38,3,38,433,8,38, + 3,38,435,8,38,1,38,1,38,1,38,1,38,3,38,441,8,38,1,38,1,38,1,38,1,38,1,38, + 1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1, 38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38, 1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1, - 38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,5,38,487,8,38,10,38,12,38,490,9,38, - 1,39,1,39,1,40,1,40,1,40,1,40,1,40,3,40,499,8,40,1,41,1,41,3,41,503,8,41, - 1,42,1,42,1,43,1,43,1,43,0,1,76,44,0,2,4,6,8,10,12,14,16,18,20,22,24,26, - 28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72,74, - 76,78,80,82,84,86,0,14,1,0,4,10,2,0,10,10,22,23,1,0,24,25,1,0,37,41,2,0, - 37,41,43,46,2,0,5,5,51,52,1,0,53,55,2,0,52,52,56,56,1,0,57,58,1,0,6,9,1, - 0,59,60,1,0,47,48,1,0,71,73,2,0,71,72,79,79,539,0,91,1,0,0,0,2,108,1,0, - 0,0,4,113,1,0,0,0,6,115,1,0,0,0,8,120,1,0,0,0,10,124,1,0,0,0,12,126,1,0, - 0,0,14,133,1,0,0,0,16,135,1,0,0,0,18,154,1,0,0,0,20,161,1,0,0,0,22,173, - 1,0,0,0,24,178,1,0,0,0,26,187,1,0,0,0,28,203,1,0,0,0,30,215,1,0,0,0,32, - 221,1,0,0,0,34,231,1,0,0,0,36,233,1,0,0,0,38,235,1,0,0,0,40,246,1,0,0,0, - 42,248,1,0,0,0,44,259,1,0,0,0,46,277,1,0,0,0,48,279,1,0,0,0,50,290,1,0, - 0,0,52,299,1,0,0,0,54,302,1,0,0,0,56,314,1,0,0,0,58,316,1,0,0,0,60,324, - 1,0,0,0,62,330,1,0,0,0,64,342,1,0,0,0,66,344,1,0,0,0,68,348,1,0,0,0,70, - 350,1,0,0,0,72,366,1,0,0,0,74,369,1,0,0,0,76,434,1,0,0,0,78,491,1,0,0,0, - 80,498,1,0,0,0,82,500,1,0,0,0,84,504,1,0,0,0,86,506,1,0,0,0,88,90,3,2,1, - 0,89,88,1,0,0,0,90,93,1,0,0,0,91,89,1,0,0,0,91,92,1,0,0,0,92,97,1,0,0,0, - 93,91,1,0,0,0,94,96,3,12,6,0,95,94,1,0,0,0,96,99,1,0,0,0,97,95,1,0,0,0, - 97,98,1,0,0,0,98,103,1,0,0,0,99,97,1,0,0,0,100,102,3,14,7,0,101,100,1,0, - 0,0,102,105,1,0,0,0,103,101,1,0,0,0,103,104,1,0,0,0,104,106,1,0,0,0,105, - 103,1,0,0,0,106,107,5,0,0,1,107,1,1,0,0,0,108,109,5,1,0,0,109,110,3,4,2, - 0,110,111,3,6,3,0,111,112,5,2,0,0,112,3,1,0,0,0,113,114,5,3,0,0,114,5,1, - 0,0,0,115,117,3,8,4,0,116,118,3,8,4,0,117,116,1,0,0,0,117,118,1,0,0,0,118, - 7,1,0,0,0,119,121,3,10,5,0,120,119,1,0,0,0,120,121,1,0,0,0,121,122,1,0, - 0,0,122,123,5,65,0,0,123,9,1,0,0,0,124,125,7,0,0,0,125,11,1,0,0,0,126,127, - 5,11,0,0,127,128,5,75,0,0,128,129,5,2,0,0,129,13,1,0,0,0,130,134,3,16,8, - 0,131,134,3,18,9,0,132,134,3,20,10,0,133,130,1,0,0,0,133,131,1,0,0,0,133, - 132,1,0,0,0,134,15,1,0,0,0,135,136,5,12,0,0,136,137,5,81,0,0,137,150,3, - 26,13,0,138,139,5,13,0,0,139,140,5,14,0,0,140,145,3,84,42,0,141,142,5,15, - 0,0,142,144,3,84,42,0,143,141,1,0,0,0,144,147,1,0,0,0,145,143,1,0,0,0,145, - 146,1,0,0,0,146,148,1,0,0,0,147,145,1,0,0,0,148,149,5,16,0,0,149,151,1, - 0,0,0,150,138,1,0,0,0,150,151,1,0,0,0,151,152,1,0,0,0,152,153,3,24,12,0, - 153,17,1,0,0,0,154,155,3,84,42,0,155,156,5,17,0,0,156,157,5,81,0,0,157, - 158,5,10,0,0,158,159,3,80,40,0,159,160,5,2,0,0,160,19,1,0,0,0,161,162,5, - 18,0,0,162,163,5,81,0,0,163,164,3,26,13,0,164,168,5,19,0,0,165,167,3,22, - 11,0,166,165,1,0,0,0,167,170,1,0,0,0,168,166,1,0,0,0,168,169,1,0,0,0,169, - 171,1,0,0,0,170,168,1,0,0,0,171,172,5,20,0,0,172,21,1,0,0,0,173,174,5,12, - 0,0,174,175,5,81,0,0,175,176,3,26,13,0,176,177,3,24,12,0,177,23,1,0,0,0, - 178,182,5,19,0,0,179,181,3,32,16,0,180,179,1,0,0,0,181,184,1,0,0,0,182, - 180,1,0,0,0,182,183,1,0,0,0,183,185,1,0,0,0,184,182,1,0,0,0,185,186,5,20, - 0,0,186,25,1,0,0,0,187,199,5,14,0,0,188,193,3,28,14,0,189,190,5,15,0,0, - 190,192,3,28,14,0,191,189,1,0,0,0,192,195,1,0,0,0,193,191,1,0,0,0,193,194, - 1,0,0,0,194,197,1,0,0,0,195,193,1,0,0,0,196,198,5,15,0,0,197,196,1,0,0, - 0,197,198,1,0,0,0,198,200,1,0,0,0,199,188,1,0,0,0,199,200,1,0,0,0,200,201, - 1,0,0,0,201,202,5,16,0,0,202,27,1,0,0,0,203,204,3,84,42,0,204,205,5,81, - 0,0,205,29,1,0,0,0,206,210,5,19,0,0,207,209,3,32,16,0,208,207,1,0,0,0,209, - 212,1,0,0,0,210,208,1,0,0,0,210,211,1,0,0,0,211,213,1,0,0,0,212,210,1,0, - 0,0,213,216,5,20,0,0,214,216,3,32,16,0,215,206,1,0,0,0,215,214,1,0,0,0, - 216,31,1,0,0,0,217,222,3,40,20,0,218,219,3,34,17,0,219,220,5,2,0,0,220, - 222,1,0,0,0,221,217,1,0,0,0,221,218,1,0,0,0,222,33,1,0,0,0,223,232,3,42, - 21,0,224,232,3,44,22,0,225,232,3,46,23,0,226,232,3,48,24,0,227,232,3,50, - 25,0,228,232,3,36,18,0,229,232,3,52,26,0,230,232,3,38,19,0,231,223,1,0, - 0,0,231,224,1,0,0,0,231,225,1,0,0,0,231,226,1,0,0,0,231,227,1,0,0,0,231, - 228,1,0,0,0,231,229,1,0,0,0,231,230,1,0,0,0,232,35,1,0,0,0,233,234,3,72, - 36,0,234,37,1,0,0,0,235,236,5,21,0,0,236,241,3,76,38,0,237,238,5,15,0,0, - 238,240,3,76,38,0,239,237,1,0,0,0,240,243,1,0,0,0,241,239,1,0,0,0,241,242, - 1,0,0,0,242,39,1,0,0,0,243,241,1,0,0,0,244,247,3,54,27,0,245,247,3,56,28, - 0,246,244,1,0,0,0,246,245,1,0,0,0,247,41,1,0,0,0,248,252,3,84,42,0,249, - 251,3,78,39,0,250,249,1,0,0,0,251,254,1,0,0,0,252,250,1,0,0,0,252,253,1, - 0,0,0,253,255,1,0,0,0,254,252,1,0,0,0,255,256,5,81,0,0,256,257,5,10,0,0, - 257,258,3,76,38,0,258,43,1,0,0,0,259,260,3,84,42,0,260,265,5,81,0,0,261, - 262,5,15,0,0,262,263,3,84,42,0,263,264,5,81,0,0,264,266,1,0,0,0,265,261, - 1,0,0,0,266,267,1,0,0,0,267,265,1,0,0,0,267,268,1,0,0,0,268,269,1,0,0,0, - 269,270,5,10,0,0,270,271,3,76,38,0,271,45,1,0,0,0,272,273,5,81,0,0,273, - 274,7,1,0,0,274,278,3,76,38,0,275,276,5,81,0,0,276,278,7,2,0,0,277,272, - 1,0,0,0,277,275,1,0,0,0,278,47,1,0,0,0,279,280,5,26,0,0,280,281,5,14,0, - 0,281,282,5,78,0,0,282,283,5,6,0,0,283,286,3,76,38,0,284,285,5,15,0,0,285, - 287,3,66,33,0,286,284,1,0,0,0,286,287,1,0,0,0,287,288,1,0,0,0,288,289,5, - 16,0,0,289,49,1,0,0,0,290,291,5,26,0,0,291,292,5,14,0,0,292,295,3,76,38, - 0,293,294,5,15,0,0,294,296,3,66,33,0,295,293,1,0,0,0,295,296,1,0,0,0,296, - 297,1,0,0,0,297,298,5,16,0,0,298,51,1,0,0,0,299,300,5,27,0,0,300,301,3, - 70,35,0,301,53,1,0,0,0,302,303,5,28,0,0,303,304,5,14,0,0,304,305,3,76,38, - 0,305,306,5,16,0,0,306,309,3,30,15,0,307,308,5,29,0,0,308,310,3,30,15,0, - 309,307,1,0,0,0,309,310,1,0,0,0,310,55,1,0,0,0,311,315,3,58,29,0,312,315, - 3,60,30,0,313,315,3,62,31,0,314,311,1,0,0,0,314,312,1,0,0,0,314,313,1,0, - 0,0,315,57,1,0,0,0,316,317,5,30,0,0,317,318,3,30,15,0,318,319,5,31,0,0, - 319,320,5,14,0,0,320,321,3,76,38,0,321,322,5,16,0,0,322,323,5,2,0,0,323, - 59,1,0,0,0,324,325,5,31,0,0,325,326,5,14,0,0,326,327,3,76,38,0,327,328, - 5,16,0,0,328,329,3,30,15,0,329,61,1,0,0,0,330,331,5,32,0,0,331,332,5,14, - 0,0,332,333,3,64,32,0,333,334,5,2,0,0,334,335,3,76,38,0,335,336,5,2,0,0, - 336,337,3,46,23,0,337,338,5,16,0,0,338,339,3,30,15,0,339,63,1,0,0,0,340, - 343,3,42,21,0,341,343,3,46,23,0,342,340,1,0,0,0,342,341,1,0,0,0,343,65, - 1,0,0,0,344,345,5,75,0,0,345,67,1,0,0,0,346,349,5,81,0,0,347,349,3,80,40, - 0,348,346,1,0,0,0,348,347,1,0,0,0,349,69,1,0,0,0,350,362,5,14,0,0,351,356, - 3,68,34,0,352,353,5,15,0,0,353,355,3,68,34,0,354,352,1,0,0,0,355,358,1, - 0,0,0,356,354,1,0,0,0,356,357,1,0,0,0,357,360,1,0,0,0,358,356,1,0,0,0,359, - 361,5,15,0,0,360,359,1,0,0,0,360,361,1,0,0,0,361,363,1,0,0,0,362,351,1, - 0,0,0,362,363,1,0,0,0,363,364,1,0,0,0,364,365,5,16,0,0,365,71,1,0,0,0,366, - 367,5,81,0,0,367,368,3,74,37,0,368,73,1,0,0,0,369,381,5,14,0,0,370,375, - 3,76,38,0,371,372,5,15,0,0,372,374,3,76,38,0,373,371,1,0,0,0,374,377,1, - 0,0,0,375,373,1,0,0,0,375,376,1,0,0,0,376,379,1,0,0,0,377,375,1,0,0,0,378, - 380,5,15,0,0,379,378,1,0,0,0,379,380,1,0,0,0,380,382,1,0,0,0,381,370,1, - 0,0,0,381,382,1,0,0,0,382,383,1,0,0,0,383,384,5,16,0,0,384,75,1,0,0,0,385, - 386,6,38,-1,0,386,387,5,14,0,0,387,388,3,76,38,0,388,389,5,16,0,0,389,435, - 1,0,0,0,390,391,3,86,43,0,391,392,5,14,0,0,392,394,3,76,38,0,393,395,5, - 15,0,0,394,393,1,0,0,0,394,395,1,0,0,0,395,396,1,0,0,0,396,397,5,16,0,0, - 397,435,1,0,0,0,398,435,3,72,36,0,399,400,5,33,0,0,400,401,5,81,0,0,401, - 435,3,74,37,0,402,403,5,36,0,0,403,404,5,34,0,0,404,405,3,76,38,0,405,406, - 5,35,0,0,406,407,7,3,0,0,407,435,1,0,0,0,408,409,5,42,0,0,409,410,5,34, - 0,0,410,411,3,76,38,0,411,412,5,35,0,0,412,413,7,4,0,0,413,435,1,0,0,0, - 414,415,7,5,0,0,415,435,3,76,38,15,416,428,5,34,0,0,417,422,3,76,38,0,418, - 419,5,15,0,0,419,421,3,76,38,0,420,418,1,0,0,0,421,424,1,0,0,0,422,420, - 1,0,0,0,422,423,1,0,0,0,423,426,1,0,0,0,424,422,1,0,0,0,425,427,5,15,0, - 0,426,425,1,0,0,0,426,427,1,0,0,0,427,429,1,0,0,0,428,417,1,0,0,0,428,429, - 1,0,0,0,429,430,1,0,0,0,430,435,5,35,0,0,431,435,5,80,0,0,432,435,5,81, - 0,0,433,435,3,80,40,0,434,385,1,0,0,0,434,390,1,0,0,0,434,398,1,0,0,0,434, - 399,1,0,0,0,434,402,1,0,0,0,434,408,1,0,0,0,434,414,1,0,0,0,434,416,1,0, - 0,0,434,431,1,0,0,0,434,432,1,0,0,0,434,433,1,0,0,0,435,488,1,0,0,0,436, - 437,10,14,0,0,437,438,7,6,0,0,438,487,3,76,38,15,439,440,10,13,0,0,440, - 441,7,7,0,0,441,487,3,76,38,14,442,443,10,12,0,0,443,444,7,8,0,0,444,487, - 3,76,38,13,445,446,10,11,0,0,446,447,7,9,0,0,447,487,3,76,38,12,448,449, - 10,10,0,0,449,450,7,10,0,0,450,487,3,76,38,11,451,452,10,9,0,0,452,453, - 5,61,0,0,453,487,3,76,38,10,454,455,10,8,0,0,455,456,5,4,0,0,456,487,3, - 76,38,9,457,458,10,7,0,0,458,459,5,62,0,0,459,487,3,76,38,8,460,461,10, - 6,0,0,461,462,5,63,0,0,462,487,3,76,38,7,463,464,10,5,0,0,464,465,5,64, - 0,0,465,487,3,76,38,6,466,467,10,21,0,0,467,468,5,34,0,0,468,469,5,68,0, - 0,469,487,5,35,0,0,470,471,10,18,0,0,471,487,7,11,0,0,472,473,10,17,0,0, - 473,474,5,49,0,0,474,475,5,14,0,0,475,476,3,76,38,0,476,477,5,16,0,0,477, - 487,1,0,0,0,478,479,10,16,0,0,479,480,5,50,0,0,480,481,5,14,0,0,481,482, - 3,76,38,0,482,483,5,15,0,0,483,484,3,76,38,0,484,485,5,16,0,0,485,487,1, - 0,0,0,486,436,1,0,0,0,486,439,1,0,0,0,486,442,1,0,0,0,486,445,1,0,0,0,486, - 448,1,0,0,0,486,451,1,0,0,0,486,454,1,0,0,0,486,457,1,0,0,0,486,460,1,0, - 0,0,486,463,1,0,0,0,486,466,1,0,0,0,486,470,1,0,0,0,486,472,1,0,0,0,486, - 478,1,0,0,0,487,490,1,0,0,0,488,486,1,0,0,0,488,489,1,0,0,0,489,77,1,0, - 0,0,490,488,1,0,0,0,491,492,5,17,0,0,492,79,1,0,0,0,493,499,5,66,0,0,494, - 499,3,82,41,0,495,499,5,75,0,0,496,499,5,76,0,0,497,499,5,77,0,0,498,493, - 1,0,0,0,498,494,1,0,0,0,498,495,1,0,0,0,498,496,1,0,0,0,498,497,1,0,0,0, - 499,81,1,0,0,0,500,502,5,68,0,0,501,503,5,67,0,0,502,501,1,0,0,0,502,503, - 1,0,0,0,503,83,1,0,0,0,504,505,7,12,0,0,505,85,1,0,0,0,506,507,7,13,0,0, - 507,87,1,0,0,0,43,91,97,103,117,120,133,145,150,168,182,193,197,199,210, - 215,221,231,241,246,252,267,277,286,295,309,314,342,348,356,360,362,375, - 379,381,394,422,426,428,434,486,488,498,502]; + 38,1,38,5,38,493,8,38,10,38,12,38,496,9,38,1,39,1,39,1,40,1,40,1,40,1,40, + 1,40,3,40,505,8,40,1,41,1,41,3,41,509,8,41,1,42,1,42,1,43,1,43,1,43,0,1, + 76,44,0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46, + 48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,0,15,1,0,4, + 10,2,0,10,10,22,23,1,0,24,25,1,0,37,41,2,0,37,41,43,46,2,0,5,5,51,52,1, + 0,53,55,2,0,52,52,56,56,1,0,57,58,1,0,6,9,1,0,59,60,1,0,47,48,2,0,17,17, + 65,65,1,0,72,74,2,0,72,73,80,80,546,0,91,1,0,0,0,2,108,1,0,0,0,4,113,1, + 0,0,0,6,115,1,0,0,0,8,120,1,0,0,0,10,124,1,0,0,0,12,126,1,0,0,0,14,133, + 1,0,0,0,16,135,1,0,0,0,18,154,1,0,0,0,20,161,1,0,0,0,22,173,1,0,0,0,24, + 178,1,0,0,0,26,187,1,0,0,0,28,203,1,0,0,0,30,221,1,0,0,0,32,227,1,0,0,0, + 34,237,1,0,0,0,36,239,1,0,0,0,38,241,1,0,0,0,40,252,1,0,0,0,42,254,1,0, + 0,0,44,265,1,0,0,0,46,283,1,0,0,0,48,285,1,0,0,0,50,296,1,0,0,0,52,305, + 1,0,0,0,54,308,1,0,0,0,56,320,1,0,0,0,58,322,1,0,0,0,60,330,1,0,0,0,62, + 336,1,0,0,0,64,348,1,0,0,0,66,350,1,0,0,0,68,354,1,0,0,0,70,356,1,0,0,0, + 72,372,1,0,0,0,74,375,1,0,0,0,76,440,1,0,0,0,78,497,1,0,0,0,80,504,1,0, + 0,0,82,506,1,0,0,0,84,510,1,0,0,0,86,512,1,0,0,0,88,90,3,2,1,0,89,88,1, + 0,0,0,90,93,1,0,0,0,91,89,1,0,0,0,91,92,1,0,0,0,92,97,1,0,0,0,93,91,1,0, + 0,0,94,96,3,12,6,0,95,94,1,0,0,0,96,99,1,0,0,0,97,95,1,0,0,0,97,98,1,0, + 0,0,98,103,1,0,0,0,99,97,1,0,0,0,100,102,3,14,7,0,101,100,1,0,0,0,102,105, + 1,0,0,0,103,101,1,0,0,0,103,104,1,0,0,0,104,106,1,0,0,0,105,103,1,0,0,0, + 106,107,5,0,0,1,107,1,1,0,0,0,108,109,5,1,0,0,109,110,3,4,2,0,110,111,3, + 6,3,0,111,112,5,2,0,0,112,3,1,0,0,0,113,114,5,3,0,0,114,5,1,0,0,0,115,117, + 3,8,4,0,116,118,3,8,4,0,117,116,1,0,0,0,117,118,1,0,0,0,118,7,1,0,0,0,119, + 121,3,10,5,0,120,119,1,0,0,0,120,121,1,0,0,0,121,122,1,0,0,0,122,123,5, + 66,0,0,123,9,1,0,0,0,124,125,7,0,0,0,125,11,1,0,0,0,126,127,5,11,0,0,127, + 128,5,76,0,0,128,129,5,2,0,0,129,13,1,0,0,0,130,134,3,16,8,0,131,134,3, + 18,9,0,132,134,3,20,10,0,133,130,1,0,0,0,133,131,1,0,0,0,133,132,1,0,0, + 0,134,15,1,0,0,0,135,136,5,12,0,0,136,137,5,82,0,0,137,150,3,26,13,0,138, + 139,5,13,0,0,139,140,5,14,0,0,140,145,3,84,42,0,141,142,5,15,0,0,142,144, + 3,84,42,0,143,141,1,0,0,0,144,147,1,0,0,0,145,143,1,0,0,0,145,146,1,0,0, + 0,146,148,1,0,0,0,147,145,1,0,0,0,148,149,5,16,0,0,149,151,1,0,0,0,150, + 138,1,0,0,0,150,151,1,0,0,0,151,152,1,0,0,0,152,153,3,24,12,0,153,17,1, + 0,0,0,154,155,3,84,42,0,155,156,5,17,0,0,156,157,5,82,0,0,157,158,5,10, + 0,0,158,159,3,80,40,0,159,160,5,2,0,0,160,19,1,0,0,0,161,162,5,18,0,0,162, + 163,5,82,0,0,163,164,3,26,13,0,164,168,5,19,0,0,165,167,3,22,11,0,166,165, + 1,0,0,0,167,170,1,0,0,0,168,166,1,0,0,0,168,169,1,0,0,0,169,171,1,0,0,0, + 170,168,1,0,0,0,171,172,5,20,0,0,172,21,1,0,0,0,173,174,5,12,0,0,174,175, + 5,82,0,0,175,176,3,26,13,0,176,177,3,24,12,0,177,23,1,0,0,0,178,182,5,19, + 0,0,179,181,3,32,16,0,180,179,1,0,0,0,181,184,1,0,0,0,182,180,1,0,0,0,182, + 183,1,0,0,0,183,185,1,0,0,0,184,182,1,0,0,0,185,186,5,20,0,0,186,25,1,0, + 0,0,187,199,5,14,0,0,188,193,3,28,14,0,189,190,5,15,0,0,190,192,3,28,14, + 0,191,189,1,0,0,0,192,195,1,0,0,0,193,191,1,0,0,0,193,194,1,0,0,0,194,197, + 1,0,0,0,195,193,1,0,0,0,196,198,5,15,0,0,197,196,1,0,0,0,197,198,1,0,0, + 0,198,200,1,0,0,0,199,188,1,0,0,0,199,200,1,0,0,0,200,201,1,0,0,0,201,202, + 5,16,0,0,202,27,1,0,0,0,203,207,3,84,42,0,204,206,3,78,39,0,205,204,1,0, + 0,0,206,209,1,0,0,0,207,205,1,0,0,0,207,208,1,0,0,0,208,210,1,0,0,0,209, + 207,1,0,0,0,210,211,5,82,0,0,211,29,1,0,0,0,212,216,5,19,0,0,213,215,3, + 32,16,0,214,213,1,0,0,0,215,218,1,0,0,0,216,214,1,0,0,0,216,217,1,0,0,0, + 217,219,1,0,0,0,218,216,1,0,0,0,219,222,5,20,0,0,220,222,3,32,16,0,221, + 212,1,0,0,0,221,220,1,0,0,0,222,31,1,0,0,0,223,228,3,40,20,0,224,225,3, + 34,17,0,225,226,5,2,0,0,226,228,1,0,0,0,227,223,1,0,0,0,227,224,1,0,0,0, + 228,33,1,0,0,0,229,238,3,42,21,0,230,238,3,44,22,0,231,238,3,46,23,0,232, + 238,3,48,24,0,233,238,3,50,25,0,234,238,3,36,18,0,235,238,3,52,26,0,236, + 238,3,38,19,0,237,229,1,0,0,0,237,230,1,0,0,0,237,231,1,0,0,0,237,232,1, + 0,0,0,237,233,1,0,0,0,237,234,1,0,0,0,237,235,1,0,0,0,237,236,1,0,0,0,238, + 35,1,0,0,0,239,240,3,72,36,0,240,37,1,0,0,0,241,242,5,21,0,0,242,247,3, + 76,38,0,243,244,5,15,0,0,244,246,3,76,38,0,245,243,1,0,0,0,246,249,1,0, + 0,0,247,245,1,0,0,0,247,248,1,0,0,0,248,39,1,0,0,0,249,247,1,0,0,0,250, + 253,3,54,27,0,251,253,3,56,28,0,252,250,1,0,0,0,252,251,1,0,0,0,253,41, + 1,0,0,0,254,258,3,84,42,0,255,257,3,78,39,0,256,255,1,0,0,0,257,260,1,0, + 0,0,258,256,1,0,0,0,258,259,1,0,0,0,259,261,1,0,0,0,260,258,1,0,0,0,261, + 262,5,82,0,0,262,263,5,10,0,0,263,264,3,76,38,0,264,43,1,0,0,0,265,266, + 3,84,42,0,266,271,5,82,0,0,267,268,5,15,0,0,268,269,3,84,42,0,269,270,5, + 82,0,0,270,272,1,0,0,0,271,267,1,0,0,0,272,273,1,0,0,0,273,271,1,0,0,0, + 273,274,1,0,0,0,274,275,1,0,0,0,275,276,5,10,0,0,276,277,3,76,38,0,277, + 45,1,0,0,0,278,279,5,82,0,0,279,280,7,1,0,0,280,284,3,76,38,0,281,282,5, + 82,0,0,282,284,7,2,0,0,283,278,1,0,0,0,283,281,1,0,0,0,284,47,1,0,0,0,285, + 286,5,26,0,0,286,287,5,14,0,0,287,288,5,79,0,0,288,289,5,6,0,0,289,292, + 3,76,38,0,290,291,5,15,0,0,291,293,3,66,33,0,292,290,1,0,0,0,292,293,1, + 0,0,0,293,294,1,0,0,0,294,295,5,16,0,0,295,49,1,0,0,0,296,297,5,26,0,0, + 297,298,5,14,0,0,298,301,3,76,38,0,299,300,5,15,0,0,300,302,3,66,33,0,301, + 299,1,0,0,0,301,302,1,0,0,0,302,303,1,0,0,0,303,304,5,16,0,0,304,51,1,0, + 0,0,305,306,5,27,0,0,306,307,3,70,35,0,307,53,1,0,0,0,308,309,5,28,0,0, + 309,310,5,14,0,0,310,311,3,76,38,0,311,312,5,16,0,0,312,315,3,30,15,0,313, + 314,5,29,0,0,314,316,3,30,15,0,315,313,1,0,0,0,315,316,1,0,0,0,316,55,1, + 0,0,0,317,321,3,58,29,0,318,321,3,60,30,0,319,321,3,62,31,0,320,317,1,0, + 0,0,320,318,1,0,0,0,320,319,1,0,0,0,321,57,1,0,0,0,322,323,5,30,0,0,323, + 324,3,30,15,0,324,325,5,31,0,0,325,326,5,14,0,0,326,327,3,76,38,0,327,328, + 5,16,0,0,328,329,5,2,0,0,329,59,1,0,0,0,330,331,5,31,0,0,331,332,5,14,0, + 0,332,333,3,76,38,0,333,334,5,16,0,0,334,335,3,30,15,0,335,61,1,0,0,0,336, + 337,5,32,0,0,337,338,5,14,0,0,338,339,3,64,32,0,339,340,5,2,0,0,340,341, + 3,76,38,0,341,342,5,2,0,0,342,343,3,46,23,0,343,344,5,16,0,0,344,345,3, + 30,15,0,345,63,1,0,0,0,346,349,3,42,21,0,347,349,3,46,23,0,348,346,1,0, + 0,0,348,347,1,0,0,0,349,65,1,0,0,0,350,351,5,76,0,0,351,67,1,0,0,0,352, + 355,5,82,0,0,353,355,3,80,40,0,354,352,1,0,0,0,354,353,1,0,0,0,355,69,1, + 0,0,0,356,368,5,14,0,0,357,362,3,68,34,0,358,359,5,15,0,0,359,361,3,68, + 34,0,360,358,1,0,0,0,361,364,1,0,0,0,362,360,1,0,0,0,362,363,1,0,0,0,363, + 366,1,0,0,0,364,362,1,0,0,0,365,367,5,15,0,0,366,365,1,0,0,0,366,367,1, + 0,0,0,367,369,1,0,0,0,368,357,1,0,0,0,368,369,1,0,0,0,369,370,1,0,0,0,370, + 371,5,16,0,0,371,71,1,0,0,0,372,373,5,82,0,0,373,374,3,74,37,0,374,73,1, + 0,0,0,375,387,5,14,0,0,376,381,3,76,38,0,377,378,5,15,0,0,378,380,3,76, + 38,0,379,377,1,0,0,0,380,383,1,0,0,0,381,379,1,0,0,0,381,382,1,0,0,0,382, + 385,1,0,0,0,383,381,1,0,0,0,384,386,5,15,0,0,385,384,1,0,0,0,385,386,1, + 0,0,0,386,388,1,0,0,0,387,376,1,0,0,0,387,388,1,0,0,0,388,389,1,0,0,0,389, + 390,5,16,0,0,390,75,1,0,0,0,391,392,6,38,-1,0,392,393,5,14,0,0,393,394, + 3,76,38,0,394,395,5,16,0,0,395,441,1,0,0,0,396,397,3,86,43,0,397,398,5, + 14,0,0,398,400,3,76,38,0,399,401,5,15,0,0,400,399,1,0,0,0,400,401,1,0,0, + 0,401,402,1,0,0,0,402,403,5,16,0,0,403,441,1,0,0,0,404,441,3,72,36,0,405, + 406,5,33,0,0,406,407,5,82,0,0,407,441,3,74,37,0,408,409,5,36,0,0,409,410, + 5,34,0,0,410,411,3,76,38,0,411,412,5,35,0,0,412,413,7,3,0,0,413,441,1,0, + 0,0,414,415,5,42,0,0,415,416,5,34,0,0,416,417,3,76,38,0,417,418,5,35,0, + 0,418,419,7,4,0,0,419,441,1,0,0,0,420,421,7,5,0,0,421,441,3,76,38,15,422, + 434,5,34,0,0,423,428,3,76,38,0,424,425,5,15,0,0,425,427,3,76,38,0,426,424, + 1,0,0,0,427,430,1,0,0,0,428,426,1,0,0,0,428,429,1,0,0,0,429,432,1,0,0,0, + 430,428,1,0,0,0,431,433,5,15,0,0,432,431,1,0,0,0,432,433,1,0,0,0,433,435, + 1,0,0,0,434,423,1,0,0,0,434,435,1,0,0,0,435,436,1,0,0,0,436,441,5,35,0, + 0,437,441,5,81,0,0,438,441,5,82,0,0,439,441,3,80,40,0,440,391,1,0,0,0,440, + 396,1,0,0,0,440,404,1,0,0,0,440,405,1,0,0,0,440,408,1,0,0,0,440,414,1,0, + 0,0,440,420,1,0,0,0,440,422,1,0,0,0,440,437,1,0,0,0,440,438,1,0,0,0,440, + 439,1,0,0,0,441,494,1,0,0,0,442,443,10,14,0,0,443,444,7,6,0,0,444,493,3, + 76,38,15,445,446,10,13,0,0,446,447,7,7,0,0,447,493,3,76,38,14,448,449,10, + 12,0,0,449,450,7,8,0,0,450,493,3,76,38,13,451,452,10,11,0,0,452,453,7,9, + 0,0,453,493,3,76,38,12,454,455,10,10,0,0,455,456,7,10,0,0,456,493,3,76, + 38,11,457,458,10,9,0,0,458,459,5,61,0,0,459,493,3,76,38,10,460,461,10,8, + 0,0,461,462,5,4,0,0,462,493,3,76,38,9,463,464,10,7,0,0,464,465,5,62,0,0, + 465,493,3,76,38,8,466,467,10,6,0,0,467,468,5,63,0,0,468,493,3,76,38,7,469, + 470,10,5,0,0,470,471,5,64,0,0,471,493,3,76,38,6,472,473,10,21,0,0,473,474, + 5,34,0,0,474,475,5,69,0,0,475,493,5,35,0,0,476,477,10,18,0,0,477,493,7, + 11,0,0,478,479,10,17,0,0,479,480,5,49,0,0,480,481,5,14,0,0,481,482,3,76, + 38,0,482,483,5,16,0,0,483,493,1,0,0,0,484,485,10,16,0,0,485,486,5,50,0, + 0,486,487,5,14,0,0,487,488,3,76,38,0,488,489,5,15,0,0,489,490,3,76,38,0, + 490,491,5,16,0,0,491,493,1,0,0,0,492,442,1,0,0,0,492,445,1,0,0,0,492,448, + 1,0,0,0,492,451,1,0,0,0,492,454,1,0,0,0,492,457,1,0,0,0,492,460,1,0,0,0, + 492,463,1,0,0,0,492,466,1,0,0,0,492,469,1,0,0,0,492,472,1,0,0,0,492,476, + 1,0,0,0,492,478,1,0,0,0,492,484,1,0,0,0,493,496,1,0,0,0,494,492,1,0,0,0, + 494,495,1,0,0,0,495,77,1,0,0,0,496,494,1,0,0,0,497,498,7,12,0,0,498,79, + 1,0,0,0,499,505,5,67,0,0,500,505,3,82,41,0,501,505,5,76,0,0,502,505,5,77, + 0,0,503,505,5,78,0,0,504,499,1,0,0,0,504,500,1,0,0,0,504,501,1,0,0,0,504, + 502,1,0,0,0,504,503,1,0,0,0,505,81,1,0,0,0,506,508,5,69,0,0,507,509,5,68, + 0,0,508,507,1,0,0,0,508,509,1,0,0,0,509,83,1,0,0,0,510,511,7,13,0,0,511, + 85,1,0,0,0,512,513,7,14,0,0,513,87,1,0,0,0,44,91,97,103,117,120,133,145, + 150,168,182,193,197,199,207,216,221,227,237,247,252,258,273,283,292,301, + 315,320,348,354,362,366,368,381,385,387,400,428,432,434,440,492,494,504, + 508]; private static __ATN: ATN; public static get _ATN(): ATN { @@ -3284,6 +3313,12 @@ export class ParameterContext extends ParserRuleContext { public Identifier(): TerminalNode { return this.getToken(CashScriptParser.Identifier, 0); } + public modifier_list(): ModifierContext[] { + return this.getTypedRuleContexts(ModifierContext) as ModifierContext[]; + } + public modifier(i: number): ModifierContext { + return this.getTypedRuleContext(ModifierContext, i) as ModifierContext; + } public get ruleIndex(): number { return CashScriptParser.RULE_parameter; } diff --git a/packages/cashc/src/print/OutputSourceCodeTraversal.ts b/packages/cashc/src/print/OutputSourceCodeTraversal.ts index b9440612..bfb1e5a2 100644 --- a/packages/cashc/src/print/OutputSourceCodeTraversal.ts +++ b/packages/cashc/src/print/OutputSourceCodeTraversal.ts @@ -128,12 +128,14 @@ export default class OutputSourceCodeTraversal extends AstTraversal { } visitParameter(node: ParameterNode): Node { - this.addOutput(`${node.type} ${node.name}`); + const modifiers = node.modifiers.length > 0 ? `${node.modifiers.join(' ')} ` : ''; + this.addOutput(`${node.type} ${modifiers}${node.name}`); return node; } visitVariableDefinition(node: VariableDefinitionNode): Node { - this.addOutput(`${node.type} ${node.name} = `, true); + const modifiers = node.modifiers.length > 0 ? `${node.modifiers.join(' ')} ` : ''; + this.addOutput(`${node.type} ${modifiers}${node.name} = `, true); this.visit(node.expression); return node; diff --git a/packages/cashc/src/semantic/SymbolTableTraversal.ts b/packages/cashc/src/semantic/SymbolTableTraversal.ts index 29480b66..3c11c8c0 100644 --- a/packages/cashc/src/semantic/SymbolTableTraversal.ts +++ b/packages/cashc/src/semantic/SymbolTableTraversal.ts @@ -29,6 +29,7 @@ import { UnusedVariableError, InvalidSymbolTypeError, ConstantModificationError, + InvalidModifierError, } from '../Errors.js'; export default class SymbolTableTraversal extends AstTraversal { @@ -82,7 +83,11 @@ export default class SymbolTableTraversal extends AstTraversal { throw new RedefinitionError(node, node.name); } - this.symbolTables[0].set(Symbol.variable(node)); + validateModifiers(node, node.modifiers, [Modifier.UNUSED]); + + const symbol = Symbol.variable(node); + symbol.ignoreUnused = node.modifiers.includes(Modifier.UNUSED); + this.symbolTables[0].set(symbol); return node; } @@ -149,9 +154,13 @@ export default class SymbolTableTraversal extends AstTraversal { throw new RedefinitionError(node, node.name); } + validateModifiers(node, node.modifiers, [Modifier.CONSTANT, Modifier.UNUSED]); + node.expression = this.visit(node.expression); - this.symbolTables[0].set(Symbol.variable(node)); + const symbol = Symbol.variable(node); + symbol.ignoreUnused = node.modifiers.includes(Modifier.UNUSED); + this.symbolTables[0].set(symbol); return node; } @@ -227,6 +236,10 @@ export default class SymbolTableTraversal extends AstTraversal { throw new InvalidSymbolTypeError(node, this.expectedSymbolType); } + if (symbol.ignoreUnused) { + throw new InvalidModifierError(node, `Cannot reference variable '${node.name}' because it is marked 'unused'`); + } + // Global constant references are replaced by their literal value, so all later passes // (type checking, literal-driven analysis, codegen) see a plain literal at the use site. if (symbol.definition instanceof ConstantDefinitionNode) { @@ -245,6 +258,27 @@ export default class SymbolTableTraversal extends AstTraversal { } } +function validateModifiers( + node: ParameterNode | VariableDefinitionNode, + modifiers: string[], + allowed: Modifier[], +): void { + const seen = new Set(); + + modifiers.forEach((modifier) => { + if (seen.has(modifier)) { + throw new InvalidModifierError(node, `Duplicate modifier '${modifier}'`); + } + + if (!allowed.includes(modifier as Modifier)) { + const target = node instanceof ParameterNode ? 'parameters' : 'variables'; + throw new InvalidModifierError(node, `Modifier '${modifier}' is not allowed on ${target}`); + } + + seen.add(modifier); + }); +} + function createTupleVariableDefinition( node: TupleAssignmentNode, variable: TupleAssignmentTarget, diff --git a/packages/cashc/test/compiler/InvalidModifierError/constant_on_contract_parameter.cash b/packages/cashc/test/compiler/InvalidModifierError/constant_on_contract_parameter.cash new file mode 100644 index 00000000..bc070dfd --- /dev/null +++ b/packages/cashc/test/compiler/InvalidModifierError/constant_on_contract_parameter.cash @@ -0,0 +1,5 @@ +contract Test(int constant value) { + function spend() { + require(true); + } +} diff --git a/packages/cashc/test/compiler/InvalidModifierError/constant_on_function_parameter.cash b/packages/cashc/test/compiler/InvalidModifierError/constant_on_function_parameter.cash new file mode 100644 index 00000000..5f92f84a --- /dev/null +++ b/packages/cashc/test/compiler/InvalidModifierError/constant_on_function_parameter.cash @@ -0,0 +1,5 @@ +contract Test() { + function spend(int constant value) { + require(value == 1); + } +} diff --git a/packages/cashc/test/compiler/InvalidModifierError/duplicate_modifier.cash b/packages/cashc/test/compiler/InvalidModifierError/duplicate_modifier.cash new file mode 100644 index 00000000..42be6e64 --- /dev/null +++ b/packages/cashc/test/compiler/InvalidModifierError/duplicate_modifier.cash @@ -0,0 +1,5 @@ +contract Test() { + function spend(bytes unused unused padding) { + require(true); + } +} diff --git a/packages/cashc/test/compiler/InvalidModifierError/reference_unused_parameter.cash b/packages/cashc/test/compiler/InvalidModifierError/reference_unused_parameter.cash new file mode 100644 index 00000000..c36d4380 --- /dev/null +++ b/packages/cashc/test/compiler/InvalidModifierError/reference_unused_parameter.cash @@ -0,0 +1,5 @@ +contract Test() { + function spend(int unused value) { + require(value == 1); + } +} diff --git a/packages/cashc/test/compiler/UnusedVariableError/unused_global_function_local.cash b/packages/cashc/test/compiler/UnusedVariableError/unused_global_function_local.cash index a37120dd..f4966201 100644 --- a/packages/cashc/test/compiler/UnusedVariableError/unused_global_function_local.cash +++ b/packages/cashc/test/compiler/UnusedVariableError/unused_global_function_local.cash @@ -1,5 +1,5 @@ function withUnusedLocal(int a) returns (int) { - int unused = a + 1; + int scratch = a + 1; return a; } diff --git a/packages/cashc/test/compiler/unused-modifier.test.ts b/packages/cashc/test/compiler/unused-modifier.test.ts new file mode 100644 index 00000000..647d4d39 --- /dev/null +++ b/packages/cashc/test/compiler/unused-modifier.test.ts @@ -0,0 +1,197 @@ +import { + createTestAuthenticationProgramBch, + createVirtualMachineBch2026, + hexToBin, +} from '@bitauth/libauth'; +import { asmToScript, encodeInt, scriptToBytecode } from '@cashscript/utils'; +import { compileString } from '../../src/index.js'; +import { InvalidModifierError, UnusedVariableError } from '../../src/Errors.js'; + +const vm = createVirtualMachineBch2026(false); + +function evaluateSpend(source: string, unlockingItems: Uint8Array[]): boolean { + const artifact = compileString(source); + const lockingBytecode = scriptToBytecode(asmToScript(artifact.bytecode)); + const unlockingBytecode = scriptToBytecode(unlockingItems); + const program = createTestAuthenticationProgramBch({ lockingBytecode, unlockingBytecode, valueSatoshis: 1000n }); + const state = vm.evaluate(program); + const top = state.stack[state.stack.length - 1]; + + return state.error === undefined + && state.stack.length === 1 + && top !== undefined + && top.length === 1 + && top[0] === 1; +} + +describe('The `unused` modifier', () => { + it('allows unused parameters and variables while preserving input metadata', () => { + const artifact = compileString(` + function first(int value, int unused ignored) returns (int) { + int unused scratch = value + 1; + return value; + } + + contract Test(int unused salt) { + function spend(int value, bytes unused padding) { + int constant unused magic = 42; + require(first(value, 0) == 1); + } + } + `); + + expect(artifact.constructorInputs).toEqual([{ name: 'salt', type: 'int' }]); + expect(artifact.abi[0].inputs).toEqual([ + { name: 'value', type: 'int' }, + { name: 'padding', type: 'bytes' }, + ]); + expect(artifact.debug.functions?.[0].inputs).toEqual([ + { name: 'value', type: 'int' }, + { name: 'ignored', type: 'int' }, + ]); + }); + + it('drops a top function parameter before compiling the function body', () => { + const artifact = compileString(` + contract Test() { + function spend(int unused padding, int value) { + require(value == 1); + } + } + `); + + expect(artifact.bytecode).toBe('OP_DROP OP_1 OP_NUMEQUAL'); + }); + + it('rolls a buried function parameter to the top before dropping it', () => { + const artifact = compileString(` + contract Test() { + function spend(int value, int unused padding) { + require(value == 1); + } + } + `); + + expect(artifact.bytecode).toBe('OP_NIP OP_1 OP_NUMEQUAL'); + }); + + it('drops a local variable immediately after evaluating its initializer', () => { + const artifact = compileString(` + contract Test() { + function spend(int value) { + int unused scratch = value + 1; + require(value == 1); + } + } + `); + + expect(artifact.bytecode).toBe('OP_DUP OP_1ADD OP_DROP OP_1 OP_NUMEQUAL'); + }); + + it('drops constructor parameters before function execution', () => { + const artifact = compileString(` + contract Test(int value, int unused salt) { + function spend() { + require(value == 1); + } + } + `); + + expect(artifact.bytecode).toBe('OP_NIP OP_1 OP_NUMEQUAL'); + }); + + it('drops global-function parameters from the function frame prologue', () => { + const artifact = compileString(` + function first(int value, int unused ignored) returns (int) { + return value; + } + + contract Test() { + function spend() { + require(first(1, 2) == 1); + } + } + `); + + expect(artifact.debug.functions?.[0].bytecode).toBe('75'); + }); + + it('drops multiple global-function parameters from the top down', () => { + const artifact = compileString(` + function first(int value, int unused ignored, int unused padding) returns (int) { + return value; + } + + contract Test() { + function spend() { + require(first(1, 2, 3) == 1); + } + } + `); + + expect(artifact.debug.functions?.[0].bytecode).toBe('6d'); + }); + + it('does not validate the runtime type of a parameter that is immediately dropped', () => { + const artifact = compileString(` + contract Test() { + function spend(bytes20 unused padding, int value) { + require(value == 1); + } + } + `); + + expect(artifact.bytecode).toBe('OP_DROP OP_1 OP_NUMEQUAL'); + }); + + it('still rejects values that are unreferenced without the modifier', () => { + expect(() => compileString(` + contract Test() { + function spend(int value, int padding) { + require(value == 1); + } + } + `)).toThrow(UnusedVariableError); + }); + + it('rejects references to values marked unused during semantic analysis', () => { + expect(() => compileString(` + contract Test() { + function spend(int unused value) { + require(value == 1); + } + } + `)).toThrow(InvalidModifierError); + }); + + it('rejects modifiers that are invalid or duplicated for parameters', () => { + expect(() => compileString(` + contract Test() { + function spend(int constant value) { + require(value == 1); + } + } + `)).toThrow(InvalidModifierError); + + expect(() => compileString(` + contract Test() { + function spend(int unused unused padding) { + require(true); + } + } + `)).toThrow(InvalidModifierError); + }); + + it('executes with one final stack item regardless of the discarded padding value', () => { + const source = ` + contract Test() { + function spend(int value, bytes unused padding) { + require(value == 7); + } + } + `; + + expect(evaluateSpend(source, [hexToBin(''), encodeInt(7n)])).toBe(true); + expect(evaluateSpend(source, [hexToBin('00000000000000000000'), encodeInt(7n)])).toBe(true); + }); +}); diff --git a/packages/cashc/test/global-definitions.test.ts b/packages/cashc/test/global-definitions.test.ts index bbb735de..4c9ff5a2 100644 --- a/packages/cashc/test/global-definitions.test.ts +++ b/packages/cashc/test/global-definitions.test.ts @@ -18,7 +18,7 @@ describe('Dead-code elimination', () => { it('does not define a global function that is never invoked', () => { const code = ` function used(int a) returns (int) { return a + 1; } - function unused(int a) returns (int) { return a * 2; } + function notInvoked(int a) returns (int) { return a * 2; } contract Test() { function spend(int x) { @@ -180,11 +180,11 @@ describe('Inlining and shared definitions', () => { it('ignores call sites inside eliminated functions when deciding to inline', () => { const code = ` function big(int x) returns (int) { return (x * 7 + 3) * (x + 11) - 5; } - function unused(int x) returns (int) { return big(x) + big(x + 1) + big(x + 2); } + function notInvoked(int x) returns (int) { return big(x) + big(x + 1) + big(x + 2); } contract C() { function spend(int n) { require(big(n) > 0); } }`; // big is multi-use on paper, but all extra call sites live in the eliminated function - // unused — only the single reachable call counts, so big is inlined + // notInvoked — only the single reachable call counts, so big is inlined const { bytecode } = compileString(code); expect(bytecode).not.toContain('OP_DEFINE'); expect(bytecode).not.toContain('OP_INVOKE'); diff --git a/packages/cashc/test/valid-contract-files/unused_modifier.cash b/packages/cashc/test/valid-contract-files/unused_modifier.cash new file mode 100644 index 00000000..3e973704 --- /dev/null +++ b/packages/cashc/test/valid-contract-files/unused_modifier.cash @@ -0,0 +1,7 @@ +contract UnusedModifier(int unused salt) { + function spend(int a, int b, bytes unused zeroPadding) { + int unused scratch = a + b; + int constant unused magic = 42; + require(a + b == 5); + } +} diff --git a/website/docs/compiler/grammar.md b/website/docs/compiler/grammar.md index 6d28bb80..105345bd 100644 --- a/website/docs/compiler/grammar.md +++ b/website/docs/compiler/grammar.md @@ -61,7 +61,7 @@ parameterList ; parameter - : typeName Identifier + : typeName modifier* Identifier ; block @@ -201,6 +201,7 @@ expression modifier : 'constant' + | 'unused' ; literal diff --git a/website/docs/language/contracts.md b/website/docs/language/contracts.md index 3baba574..9c584224 100644 --- a/website/docs/language/contracts.md +++ b/website/docs/language/contracts.md @@ -243,7 +243,7 @@ contract P2PKH(bytes20 pkh) { Variables can be declared by specifying their type and name. All variables need to be initialised at the time of their declaration, but can be reassigned later on — unless specifying the `constant` keyword. Since CashScript is strongly typed and has no type inference, it is not possible to use keywords such as `var` or `let` to declare variables. :::note -CashScript disallows variable shadowing and unused variables. +CashScript disallows variable shadowing and unused variables unless they are explicitly marked `unused`. ::: #### Example @@ -252,6 +252,24 @@ int myNumber = 3000; string constant myString = 'Bitcoin Cash'; ``` +### Intentionally unused values + +Parameters and local variables that intentionally have no references can use the `unused` modifier between their type +and name. An unused parameter remains part of the contract inputs or function ABI, so callers still need to provide it, +but the compiler drops it from the stack before executing the function body. For a local variable, the initializer is +evaluated and its result is dropped immediately. A declaration marked `unused` cannot be referenced later. + +#### Example + +```solidity +contract Versioned(bytes unused reserved) { + function spend(int value, bytes unused padding) { + int unused discarded = value + 1; + require(value == 1); + } +} +``` + ### Variable assignment After their initial declaration, any variable can be reassigned later on. CashScript supports regular assignment with `=`, the compound assignment operators `+=` and `-=`, and the increment and decrement operators `++` and `--`. The compound and increment/decrement operators are only valid on `int` variables. From bfad22c23a80b401404873ddc81aa34c5b31d8e3 Mon Sep 17 00:00:00 2001 From: Mathieu Geukens Date: Thu, 23 Jul 2026 13:27:50 +0200 Subject: [PATCH 02/12] feat(cashc): destructure tuples into existing variables A destructuring target may now be a bare identifier (`x`) to reassign an already-declared variable, alongside fresh declarations (`int x`), in both `a, b = f()` and `(a, b) = f()` forms. Enables in-place update of loop-carried state without the fresh-temp + per-element rebind workaround. - Grammar: tupleTarget (typed declaration or bare identifier); parser regenerated. - AST: TupleAssignmentTarget gains optional type + isReassignment. - Symbol table: reassignment targets resolve the existing symbol, adopt its type, and register a reference instead of declaring a new variable. The reassignment also counts as the variable's latest use in the final-use bookkeeping (opRolls), so an earlier read can no longer roll the variable off the stack model and crash codegen when the reassignment sits after that read. - Codegen: outside a loop/branch, binding is a pure stack rename; inside one, reassignments are folded in place via emitReplace. The checking layer rejects every invalid form with a proper error: - undefined target -> UndefinedReferenceError - reassigning a constant (local or global) -> ConstantModificationError - reassigning a non-variable symbol (function name) -> InvalidSymbolTypeError - duplicate targets -> DuplicateTupleTargetError - reassignments before declarations -> TupleTargetOrderError, enforced in semantic analysis so statement legality does not depend on whether it sits inside a loop/branch (the codegen check remains as an internal invariant) Adds fixture tests for every rejection and VM execution tests for the scoped emitReplace fold (loop swap, branch fold, a fib-style mixed declaration+reassignment recurrence, and a regression for a scoped reassignment placed after the variable's final plain read). Removes the now-obsolete single_type_destructuring ParseError fixture (mixed typed/untyped targets are valid syntax now). Co-Authored-By: Claude Fable 5 --- packages/cashc/src/Errors.ts | 18 + packages/cashc/src/ast/AST.ts | 7 +- packages/cashc/src/ast/AstBuilder.ts | 16 +- .../src/generation/GenerateTargetTraversal.ts | 34 +- packages/cashc/src/grammar/CashScript.g4 | 11 +- packages/cashc/src/grammar/CashScript.interp | 3 +- .../cashc/src/grammar/CashScriptParser.ts | 1242 +++++++++-------- .../cashc/src/grammar/CashScriptVisitor.ts | 7 + .../src/print/OutputSourceCodeTraversal.ts | 5 +- .../src/semantic/SymbolTableTraversal.ts | 48 +- .../cashc/src/semantic/TypeCheckTraversal.ts | 4 +- .../tuple_reassign_constant.cash | 11 + .../declaration_then_reassignment.cash | 10 + .../duplicate_reassignment_targets.cash | 11 + .../tuple_reassign_function_name.cash | 10 + .../ParseError/single_type_destructuring.cash | 5 - .../reassignment_before_declaration.cash | 11 + .../tuple_reassign_undefined.cash | 12 + .../cashc/test/tuple-destructuring.test.ts | 131 ++ .../tuple_reassignment.cash | 40 + 20 files changed, 1052 insertions(+), 584 deletions(-) create mode 100644 packages/cashc/test/compiler/ConstantModificationError/tuple_reassign_constant.cash create mode 100644 packages/cashc/test/compiler/DuplicateTupleTargetError/declaration_then_reassignment.cash create mode 100644 packages/cashc/test/compiler/DuplicateTupleTargetError/duplicate_reassignment_targets.cash create mode 100644 packages/cashc/test/compiler/InvalidSymbolTypeError/tuple_reassign_function_name.cash delete mode 100644 packages/cashc/test/compiler/ParseError/single_type_destructuring.cash create mode 100644 packages/cashc/test/compiler/TupleTargetOrderError/reassignment_before_declaration.cash create mode 100644 packages/cashc/test/compiler/UndefinedReferenceError/tuple_reassign_undefined.cash create mode 100644 packages/cashc/test/tuple-destructuring.test.ts create mode 100644 packages/cashc/test/valid-contract-files/tuple_reassignment.cash diff --git a/packages/cashc/src/Errors.ts b/packages/cashc/src/Errors.ts index adac9f44..98a4dfa9 100644 --- a/packages/cashc/src/Errors.ts +++ b/packages/cashc/src/Errors.ts @@ -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'; @@ -263,6 +264,23 @@ export class AssignTypeError extends TypeError { } } +export class DuplicateTupleTargetError extends CashScriptError { + constructor( + node: TupleAssignmentNode, + name: string, + ) { + super(node, `Duplicate target '${name}' in tuple destructuring`); + } +} + +export class TupleTargetOrderError extends CashScriptError { + constructor( + node: TupleAssignmentNode, + ) { + super(node, 'Declaration targets must come before all reassignment targets in a tuple destructuring'); + } +} + export class ConstantModificationError extends CashScriptError { constructor(node: VariableDefinitionNode | ConstantDefinitionNode); constructor(node: Node, name: string); diff --git a/packages/cashc/src/ast/AST.ts b/packages/cashc/src/ast/AST.ts index 4b222d15..2fe1947a 100644 --- a/packages/cashc/src/ast/AST.ts +++ b/packages/cashc/src/ast/AST.ts @@ -154,7 +154,12 @@ export class VariableDefinitionNode extends NonControlStatementNode implements N export interface TupleAssignmentTarget { name: string; - type: Type; + // For a fresh-declaration target (`int x`) this is the declared type. For a reassignment target + // (`x`, no type) it is undefined at parse time and filled in from the existing variable's symbol + // during SymbolTableTraversal. + type?: Type; + // True for a reassignment of an already-declared variable (no `typeName` in source). + isReassignment?: boolean; } export class TupleAssignmentNode extends NonControlStatementNode { diff --git a/packages/cashc/src/ast/AstBuilder.ts b/packages/cashc/src/ast/AstBuilder.ts index 890f09c8..accfbae7 100644 --- a/packages/cashc/src/ast/AstBuilder.ts +++ b/packages/cashc/src/ast/AstBuilder.ts @@ -248,11 +248,17 @@ 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()), - })); + // Each target is either `typeName Identifier` (fresh declaration) or `Identifier` (reassignment + // of an existing variable). A reassignment target has no type at parse time; SymbolTableTraversal + // fills it in from the existing variable's symbol. + const targets = ctx.tupleTarget_list().map((target) => { + const typeName = target.typeName(); + return { + name: target.Identifier().getText(), + type: typeName ? parseType(typeName.getText()) : undefined, + isReassignment: typeName === null, + }; + }); const tupleAssignment = new TupleAssignmentNode(targets, expression); tupleAssignment.location = Location.fromCtx(ctx); return tupleAssignment; diff --git a/packages/cashc/src/generation/GenerateTargetTraversal.ts b/packages/cashc/src/generation/GenerateTargetTraversal.ts index 9c8d0c0f..d98e0ef5 100644 --- a/packages/cashc/src/generation/GenerateTargetTraversal.ts +++ b/packages/cashc/src/generation/GenerateTargetTraversal.ts @@ -510,9 +510,39 @@ export default class GenerateTargetTraversal extends AstTraversal { } visitTupleAssignment(node: TupleAssignmentNode): Node { + // The RHS leaves N values on the stack, last on top (as `.split` and multi-return calls do). node.tuple = this.visit(node.tuple); - this.popFromStack(node.targets.length); - node.targets.forEach((target) => this.pushToStack(target.name)); + const n = node.targets.length; + + // Outside a loop/branch, binding is a pure rename: the result entries take the target names, and + // a reassigned variable's old slot becomes a dead duplicate cleaned up at end of scope. + const scopedReassign = this.scopeDepth > 0 && node.targets.some((target) => target.isReassignment); + if (!scopedReassign) { + this.popFromStack(n); + node.targets.forEach((target) => this.pushToStack(target.name)); + return node; + } + + // In a loop/branch the stack layout must be preserved, so reassignments are folded in place. This + // requires declarations to form a contiguous block below all reassignments (the natural layout of + // a multi-return: fresh values, then updated accumulators). SymbolTableTraversal enforces this + // ordering for every tuple destructuring (TupleTargetOrderError), so the check here is an + // internal invariant only. + const firstReassign = node.targets.findIndex((target) => target.isReassignment); + const lastDeclaration = node.targets.reduce((acc, target, i) => (target.isReassignment ? acc : i), -1); + if (lastDeclaration > firstReassign) { + throw new Error('Declaration targets must come before all reassignment targets in a scoped tuple destructuring'); + } + + // Fold the trailing reassignment block into the existing slots top-down (each target's value is on + // top when processed), then rename the leading declaration values in place (no opcodes). + for (let i = n - 1; i >= firstReassign; i -= 1) { + this.emitReplace(this.getStackIndex(node.targets[i].name), node); + this.popFromStack(); + } + for (let s = 0; s < firstReassign; s += 1) { + this.stack[s] = node.targets[firstReassign - 1 - s].name; + } return node; } diff --git a/packages/cashc/src/grammar/CashScript.g4 b/packages/cashc/src/grammar/CashScript.g4 index 0cd133ee..caf15288 100644 --- a/packages/cashc/src/grammar/CashScript.g4 +++ b/packages/cashc/src/grammar/CashScript.g4 @@ -101,7 +101,16 @@ variableDefinition ; tupleAssignment - : typeName Identifier (',' typeName Identifier)+ '=' expression + : tupleTarget (',' tupleTarget)+ '=' expression + | '(' tupleTarget (',' tupleTarget)+ ')' '=' expression + ; + +// A destructuring target is either a fresh declaration (`int x`) or an existing variable to +// reassign (`x`, no type). Reassigning existing variables avoids the fresh-temp + per-element +// rebind workaround; the code generator lowers a top-level reassignment to a stack rename. +tupleTarget + : typeName Identifier + | Identifier ; assignStatement diff --git a/packages/cashc/src/grammar/CashScript.interp b/packages/cashc/src/grammar/CashScript.interp index 35c314a3..7d6d21e8 100644 --- a/packages/cashc/src/grammar/CashScript.interp +++ b/packages/cashc/src/grammar/CashScript.interp @@ -198,6 +198,7 @@ returnStatement controlStatement variableDefinition tupleAssignment +tupleTarget assignStatement timeOpStatement requireStatement @@ -222,4 +223,4 @@ typeCast atn: -[4, 1, 85, 515, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 1, 0, 5, 0, 90, 8, 0, 10, 0, 12, 0, 93, 9, 0, 1, 0, 5, 0, 96, 8, 0, 10, 0, 12, 0, 99, 9, 0, 1, 0, 5, 0, 102, 8, 0, 10, 0, 12, 0, 105, 9, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 3, 3, 3, 118, 8, 3, 1, 4, 3, 4, 121, 8, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 3, 7, 134, 8, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 5, 8, 144, 8, 8, 10, 8, 12, 8, 147, 9, 8, 1, 8, 1, 8, 3, 8, 151, 8, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 5, 10, 167, 8, 10, 10, 10, 12, 10, 170, 9, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 5, 12, 181, 8, 12, 10, 12, 12, 12, 184, 9, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 5, 13, 192, 8, 13, 10, 13, 12, 13, 195, 9, 13, 1, 13, 3, 13, 198, 8, 13, 3, 13, 200, 8, 13, 1, 13, 1, 13, 1, 14, 1, 14, 5, 14, 206, 8, 14, 10, 14, 12, 14, 209, 9, 14, 1, 14, 1, 14, 1, 15, 1, 15, 5, 15, 215, 8, 15, 10, 15, 12, 15, 218, 9, 15, 1, 15, 1, 15, 3, 15, 222, 8, 15, 1, 16, 1, 16, 1, 16, 1, 16, 3, 16, 228, 8, 16, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 3, 17, 238, 8, 17, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 19, 5, 19, 246, 8, 19, 10, 19, 12, 19, 249, 9, 19, 1, 20, 1, 20, 3, 20, 253, 8, 20, 1, 21, 1, 21, 5, 21, 257, 8, 21, 10, 21, 12, 21, 260, 9, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 4, 22, 272, 8, 22, 11, 22, 12, 22, 273, 1, 22, 1, 22, 1, 22, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 3, 23, 284, 8, 23, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 3, 24, 293, 8, 24, 1, 24, 1, 24, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 3, 25, 302, 8, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 26, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 3, 27, 316, 8, 27, 1, 28, 1, 28, 1, 28, 3, 28, 321, 8, 28, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 3, 32, 349, 8, 32, 1, 33, 1, 33, 1, 34, 1, 34, 3, 34, 355, 8, 34, 1, 35, 1, 35, 1, 35, 1, 35, 5, 35, 361, 8, 35, 10, 35, 12, 35, 364, 9, 35, 1, 35, 3, 35, 367, 8, 35, 3, 35, 369, 8, 35, 1, 35, 1, 35, 1, 36, 1, 36, 1, 36, 1, 37, 1, 37, 1, 37, 1, 37, 5, 37, 380, 8, 37, 10, 37, 12, 37, 383, 9, 37, 1, 37, 3, 37, 386, 8, 37, 3, 37, 388, 8, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 3, 38, 401, 8, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 5, 38, 427, 8, 38, 10, 38, 12, 38, 430, 9, 38, 1, 38, 3, 38, 433, 8, 38, 3, 38, 435, 8, 38, 1, 38, 1, 38, 1, 38, 1, 38, 3, 38, 441, 8, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 5, 38, 493, 8, 38, 10, 38, 12, 38, 496, 9, 38, 1, 39, 1, 39, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 3, 40, 505, 8, 40, 1, 41, 1, 41, 3, 41, 509, 8, 41, 1, 42, 1, 42, 1, 43, 1, 43, 1, 43, 0, 1, 76, 44, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 0, 15, 1, 0, 4, 10, 2, 0, 10, 10, 22, 23, 1, 0, 24, 25, 1, 0, 37, 41, 2, 0, 37, 41, 43, 46, 2, 0, 5, 5, 51, 52, 1, 0, 53, 55, 2, 0, 52, 52, 56, 56, 1, 0, 57, 58, 1, 0, 6, 9, 1, 0, 59, 60, 1, 0, 47, 48, 2, 0, 17, 17, 65, 65, 1, 0, 72, 74, 2, 0, 72, 73, 80, 80, 546, 0, 91, 1, 0, 0, 0, 2, 108, 1, 0, 0, 0, 4, 113, 1, 0, 0, 0, 6, 115, 1, 0, 0, 0, 8, 120, 1, 0, 0, 0, 10, 124, 1, 0, 0, 0, 12, 126, 1, 0, 0, 0, 14, 133, 1, 0, 0, 0, 16, 135, 1, 0, 0, 0, 18, 154, 1, 0, 0, 0, 20, 161, 1, 0, 0, 0, 22, 173, 1, 0, 0, 0, 24, 178, 1, 0, 0, 0, 26, 187, 1, 0, 0, 0, 28, 203, 1, 0, 0, 0, 30, 221, 1, 0, 0, 0, 32, 227, 1, 0, 0, 0, 34, 237, 1, 0, 0, 0, 36, 239, 1, 0, 0, 0, 38, 241, 1, 0, 0, 0, 40, 252, 1, 0, 0, 0, 42, 254, 1, 0, 0, 0, 44, 265, 1, 0, 0, 0, 46, 283, 1, 0, 0, 0, 48, 285, 1, 0, 0, 0, 50, 296, 1, 0, 0, 0, 52, 305, 1, 0, 0, 0, 54, 308, 1, 0, 0, 0, 56, 320, 1, 0, 0, 0, 58, 322, 1, 0, 0, 0, 60, 330, 1, 0, 0, 0, 62, 336, 1, 0, 0, 0, 64, 348, 1, 0, 0, 0, 66, 350, 1, 0, 0, 0, 68, 354, 1, 0, 0, 0, 70, 356, 1, 0, 0, 0, 72, 372, 1, 0, 0, 0, 74, 375, 1, 0, 0, 0, 76, 440, 1, 0, 0, 0, 78, 497, 1, 0, 0, 0, 80, 504, 1, 0, 0, 0, 82, 506, 1, 0, 0, 0, 84, 510, 1, 0, 0, 0, 86, 512, 1, 0, 0, 0, 88, 90, 3, 2, 1, 0, 89, 88, 1, 0, 0, 0, 90, 93, 1, 0, 0, 0, 91, 89, 1, 0, 0, 0, 91, 92, 1, 0, 0, 0, 92, 97, 1, 0, 0, 0, 93, 91, 1, 0, 0, 0, 94, 96, 3, 12, 6, 0, 95, 94, 1, 0, 0, 0, 96, 99, 1, 0, 0, 0, 97, 95, 1, 0, 0, 0, 97, 98, 1, 0, 0, 0, 98, 103, 1, 0, 0, 0, 99, 97, 1, 0, 0, 0, 100, 102, 3, 14, 7, 0, 101, 100, 1, 0, 0, 0, 102, 105, 1, 0, 0, 0, 103, 101, 1, 0, 0, 0, 103, 104, 1, 0, 0, 0, 104, 106, 1, 0, 0, 0, 105, 103, 1, 0, 0, 0, 106, 107, 5, 0, 0, 1, 107, 1, 1, 0, 0, 0, 108, 109, 5, 1, 0, 0, 109, 110, 3, 4, 2, 0, 110, 111, 3, 6, 3, 0, 111, 112, 5, 2, 0, 0, 112, 3, 1, 0, 0, 0, 113, 114, 5, 3, 0, 0, 114, 5, 1, 0, 0, 0, 115, 117, 3, 8, 4, 0, 116, 118, 3, 8, 4, 0, 117, 116, 1, 0, 0, 0, 117, 118, 1, 0, 0, 0, 118, 7, 1, 0, 0, 0, 119, 121, 3, 10, 5, 0, 120, 119, 1, 0, 0, 0, 120, 121, 1, 0, 0, 0, 121, 122, 1, 0, 0, 0, 122, 123, 5, 66, 0, 0, 123, 9, 1, 0, 0, 0, 124, 125, 7, 0, 0, 0, 125, 11, 1, 0, 0, 0, 126, 127, 5, 11, 0, 0, 127, 128, 5, 76, 0, 0, 128, 129, 5, 2, 0, 0, 129, 13, 1, 0, 0, 0, 130, 134, 3, 16, 8, 0, 131, 134, 3, 18, 9, 0, 132, 134, 3, 20, 10, 0, 133, 130, 1, 0, 0, 0, 133, 131, 1, 0, 0, 0, 133, 132, 1, 0, 0, 0, 134, 15, 1, 0, 0, 0, 135, 136, 5, 12, 0, 0, 136, 137, 5, 82, 0, 0, 137, 150, 3, 26, 13, 0, 138, 139, 5, 13, 0, 0, 139, 140, 5, 14, 0, 0, 140, 145, 3, 84, 42, 0, 141, 142, 5, 15, 0, 0, 142, 144, 3, 84, 42, 0, 143, 141, 1, 0, 0, 0, 144, 147, 1, 0, 0, 0, 145, 143, 1, 0, 0, 0, 145, 146, 1, 0, 0, 0, 146, 148, 1, 0, 0, 0, 147, 145, 1, 0, 0, 0, 148, 149, 5, 16, 0, 0, 149, 151, 1, 0, 0, 0, 150, 138, 1, 0, 0, 0, 150, 151, 1, 0, 0, 0, 151, 152, 1, 0, 0, 0, 152, 153, 3, 24, 12, 0, 153, 17, 1, 0, 0, 0, 154, 155, 3, 84, 42, 0, 155, 156, 5, 17, 0, 0, 156, 157, 5, 82, 0, 0, 157, 158, 5, 10, 0, 0, 158, 159, 3, 80, 40, 0, 159, 160, 5, 2, 0, 0, 160, 19, 1, 0, 0, 0, 161, 162, 5, 18, 0, 0, 162, 163, 5, 82, 0, 0, 163, 164, 3, 26, 13, 0, 164, 168, 5, 19, 0, 0, 165, 167, 3, 22, 11, 0, 166, 165, 1, 0, 0, 0, 167, 170, 1, 0, 0, 0, 168, 166, 1, 0, 0, 0, 168, 169, 1, 0, 0, 0, 169, 171, 1, 0, 0, 0, 170, 168, 1, 0, 0, 0, 171, 172, 5, 20, 0, 0, 172, 21, 1, 0, 0, 0, 173, 174, 5, 12, 0, 0, 174, 175, 5, 82, 0, 0, 175, 176, 3, 26, 13, 0, 176, 177, 3, 24, 12, 0, 177, 23, 1, 0, 0, 0, 178, 182, 5, 19, 0, 0, 179, 181, 3, 32, 16, 0, 180, 179, 1, 0, 0, 0, 181, 184, 1, 0, 0, 0, 182, 180, 1, 0, 0, 0, 182, 183, 1, 0, 0, 0, 183, 185, 1, 0, 0, 0, 184, 182, 1, 0, 0, 0, 185, 186, 5, 20, 0, 0, 186, 25, 1, 0, 0, 0, 187, 199, 5, 14, 0, 0, 188, 193, 3, 28, 14, 0, 189, 190, 5, 15, 0, 0, 190, 192, 3, 28, 14, 0, 191, 189, 1, 0, 0, 0, 192, 195, 1, 0, 0, 0, 193, 191, 1, 0, 0, 0, 193, 194, 1, 0, 0, 0, 194, 197, 1, 0, 0, 0, 195, 193, 1, 0, 0, 0, 196, 198, 5, 15, 0, 0, 197, 196, 1, 0, 0, 0, 197, 198, 1, 0, 0, 0, 198, 200, 1, 0, 0, 0, 199, 188, 1, 0, 0, 0, 199, 200, 1, 0, 0, 0, 200, 201, 1, 0, 0, 0, 201, 202, 5, 16, 0, 0, 202, 27, 1, 0, 0, 0, 203, 207, 3, 84, 42, 0, 204, 206, 3, 78, 39, 0, 205, 204, 1, 0, 0, 0, 206, 209, 1, 0, 0, 0, 207, 205, 1, 0, 0, 0, 207, 208, 1, 0, 0, 0, 208, 210, 1, 0, 0, 0, 209, 207, 1, 0, 0, 0, 210, 211, 5, 82, 0, 0, 211, 29, 1, 0, 0, 0, 212, 216, 5, 19, 0, 0, 213, 215, 3, 32, 16, 0, 214, 213, 1, 0, 0, 0, 215, 218, 1, 0, 0, 0, 216, 214, 1, 0, 0, 0, 216, 217, 1, 0, 0, 0, 217, 219, 1, 0, 0, 0, 218, 216, 1, 0, 0, 0, 219, 222, 5, 20, 0, 0, 220, 222, 3, 32, 16, 0, 221, 212, 1, 0, 0, 0, 221, 220, 1, 0, 0, 0, 222, 31, 1, 0, 0, 0, 223, 228, 3, 40, 20, 0, 224, 225, 3, 34, 17, 0, 225, 226, 5, 2, 0, 0, 226, 228, 1, 0, 0, 0, 227, 223, 1, 0, 0, 0, 227, 224, 1, 0, 0, 0, 228, 33, 1, 0, 0, 0, 229, 238, 3, 42, 21, 0, 230, 238, 3, 44, 22, 0, 231, 238, 3, 46, 23, 0, 232, 238, 3, 48, 24, 0, 233, 238, 3, 50, 25, 0, 234, 238, 3, 36, 18, 0, 235, 238, 3, 52, 26, 0, 236, 238, 3, 38, 19, 0, 237, 229, 1, 0, 0, 0, 237, 230, 1, 0, 0, 0, 237, 231, 1, 0, 0, 0, 237, 232, 1, 0, 0, 0, 237, 233, 1, 0, 0, 0, 237, 234, 1, 0, 0, 0, 237, 235, 1, 0, 0, 0, 237, 236, 1, 0, 0, 0, 238, 35, 1, 0, 0, 0, 239, 240, 3, 72, 36, 0, 240, 37, 1, 0, 0, 0, 241, 242, 5, 21, 0, 0, 242, 247, 3, 76, 38, 0, 243, 244, 5, 15, 0, 0, 244, 246, 3, 76, 38, 0, 245, 243, 1, 0, 0, 0, 246, 249, 1, 0, 0, 0, 247, 245, 1, 0, 0, 0, 247, 248, 1, 0, 0, 0, 248, 39, 1, 0, 0, 0, 249, 247, 1, 0, 0, 0, 250, 253, 3, 54, 27, 0, 251, 253, 3, 56, 28, 0, 252, 250, 1, 0, 0, 0, 252, 251, 1, 0, 0, 0, 253, 41, 1, 0, 0, 0, 254, 258, 3, 84, 42, 0, 255, 257, 3, 78, 39, 0, 256, 255, 1, 0, 0, 0, 257, 260, 1, 0, 0, 0, 258, 256, 1, 0, 0, 0, 258, 259, 1, 0, 0, 0, 259, 261, 1, 0, 0, 0, 260, 258, 1, 0, 0, 0, 261, 262, 5, 82, 0, 0, 262, 263, 5, 10, 0, 0, 263, 264, 3, 76, 38, 0, 264, 43, 1, 0, 0, 0, 265, 266, 3, 84, 42, 0, 266, 271, 5, 82, 0, 0, 267, 268, 5, 15, 0, 0, 268, 269, 3, 84, 42, 0, 269, 270, 5, 82, 0, 0, 270, 272, 1, 0, 0, 0, 271, 267, 1, 0, 0, 0, 272, 273, 1, 0, 0, 0, 273, 271, 1, 0, 0, 0, 273, 274, 1, 0, 0, 0, 274, 275, 1, 0, 0, 0, 275, 276, 5, 10, 0, 0, 276, 277, 3, 76, 38, 0, 277, 45, 1, 0, 0, 0, 278, 279, 5, 82, 0, 0, 279, 280, 7, 1, 0, 0, 280, 284, 3, 76, 38, 0, 281, 282, 5, 82, 0, 0, 282, 284, 7, 2, 0, 0, 283, 278, 1, 0, 0, 0, 283, 281, 1, 0, 0, 0, 284, 47, 1, 0, 0, 0, 285, 286, 5, 26, 0, 0, 286, 287, 5, 14, 0, 0, 287, 288, 5, 79, 0, 0, 288, 289, 5, 6, 0, 0, 289, 292, 3, 76, 38, 0, 290, 291, 5, 15, 0, 0, 291, 293, 3, 66, 33, 0, 292, 290, 1, 0, 0, 0, 292, 293, 1, 0, 0, 0, 293, 294, 1, 0, 0, 0, 294, 295, 5, 16, 0, 0, 295, 49, 1, 0, 0, 0, 296, 297, 5, 26, 0, 0, 297, 298, 5, 14, 0, 0, 298, 301, 3, 76, 38, 0, 299, 300, 5, 15, 0, 0, 300, 302, 3, 66, 33, 0, 301, 299, 1, 0, 0, 0, 301, 302, 1, 0, 0, 0, 302, 303, 1, 0, 0, 0, 303, 304, 5, 16, 0, 0, 304, 51, 1, 0, 0, 0, 305, 306, 5, 27, 0, 0, 306, 307, 3, 70, 35, 0, 307, 53, 1, 0, 0, 0, 308, 309, 5, 28, 0, 0, 309, 310, 5, 14, 0, 0, 310, 311, 3, 76, 38, 0, 311, 312, 5, 16, 0, 0, 312, 315, 3, 30, 15, 0, 313, 314, 5, 29, 0, 0, 314, 316, 3, 30, 15, 0, 315, 313, 1, 0, 0, 0, 315, 316, 1, 0, 0, 0, 316, 55, 1, 0, 0, 0, 317, 321, 3, 58, 29, 0, 318, 321, 3, 60, 30, 0, 319, 321, 3, 62, 31, 0, 320, 317, 1, 0, 0, 0, 320, 318, 1, 0, 0, 0, 320, 319, 1, 0, 0, 0, 321, 57, 1, 0, 0, 0, 322, 323, 5, 30, 0, 0, 323, 324, 3, 30, 15, 0, 324, 325, 5, 31, 0, 0, 325, 326, 5, 14, 0, 0, 326, 327, 3, 76, 38, 0, 327, 328, 5, 16, 0, 0, 328, 329, 5, 2, 0, 0, 329, 59, 1, 0, 0, 0, 330, 331, 5, 31, 0, 0, 331, 332, 5, 14, 0, 0, 332, 333, 3, 76, 38, 0, 333, 334, 5, 16, 0, 0, 334, 335, 3, 30, 15, 0, 335, 61, 1, 0, 0, 0, 336, 337, 5, 32, 0, 0, 337, 338, 5, 14, 0, 0, 338, 339, 3, 64, 32, 0, 339, 340, 5, 2, 0, 0, 340, 341, 3, 76, 38, 0, 341, 342, 5, 2, 0, 0, 342, 343, 3, 46, 23, 0, 343, 344, 5, 16, 0, 0, 344, 345, 3, 30, 15, 0, 345, 63, 1, 0, 0, 0, 346, 349, 3, 42, 21, 0, 347, 349, 3, 46, 23, 0, 348, 346, 1, 0, 0, 0, 348, 347, 1, 0, 0, 0, 349, 65, 1, 0, 0, 0, 350, 351, 5, 76, 0, 0, 351, 67, 1, 0, 0, 0, 352, 355, 5, 82, 0, 0, 353, 355, 3, 80, 40, 0, 354, 352, 1, 0, 0, 0, 354, 353, 1, 0, 0, 0, 355, 69, 1, 0, 0, 0, 356, 368, 5, 14, 0, 0, 357, 362, 3, 68, 34, 0, 358, 359, 5, 15, 0, 0, 359, 361, 3, 68, 34, 0, 360, 358, 1, 0, 0, 0, 361, 364, 1, 0, 0, 0, 362, 360, 1, 0, 0, 0, 362, 363, 1, 0, 0, 0, 363, 366, 1, 0, 0, 0, 364, 362, 1, 0, 0, 0, 365, 367, 5, 15, 0, 0, 366, 365, 1, 0, 0, 0, 366, 367, 1, 0, 0, 0, 367, 369, 1, 0, 0, 0, 368, 357, 1, 0, 0, 0, 368, 369, 1, 0, 0, 0, 369, 370, 1, 0, 0, 0, 370, 371, 5, 16, 0, 0, 371, 71, 1, 0, 0, 0, 372, 373, 5, 82, 0, 0, 373, 374, 3, 74, 37, 0, 374, 73, 1, 0, 0, 0, 375, 387, 5, 14, 0, 0, 376, 381, 3, 76, 38, 0, 377, 378, 5, 15, 0, 0, 378, 380, 3, 76, 38, 0, 379, 377, 1, 0, 0, 0, 380, 383, 1, 0, 0, 0, 381, 379, 1, 0, 0, 0, 381, 382, 1, 0, 0, 0, 382, 385, 1, 0, 0, 0, 383, 381, 1, 0, 0, 0, 384, 386, 5, 15, 0, 0, 385, 384, 1, 0, 0, 0, 385, 386, 1, 0, 0, 0, 386, 388, 1, 0, 0, 0, 387, 376, 1, 0, 0, 0, 387, 388, 1, 0, 0, 0, 388, 389, 1, 0, 0, 0, 389, 390, 5, 16, 0, 0, 390, 75, 1, 0, 0, 0, 391, 392, 6, 38, -1, 0, 392, 393, 5, 14, 0, 0, 393, 394, 3, 76, 38, 0, 394, 395, 5, 16, 0, 0, 395, 441, 1, 0, 0, 0, 396, 397, 3, 86, 43, 0, 397, 398, 5, 14, 0, 0, 398, 400, 3, 76, 38, 0, 399, 401, 5, 15, 0, 0, 400, 399, 1, 0, 0, 0, 400, 401, 1, 0, 0, 0, 401, 402, 1, 0, 0, 0, 402, 403, 5, 16, 0, 0, 403, 441, 1, 0, 0, 0, 404, 441, 3, 72, 36, 0, 405, 406, 5, 33, 0, 0, 406, 407, 5, 82, 0, 0, 407, 441, 3, 74, 37, 0, 408, 409, 5, 36, 0, 0, 409, 410, 5, 34, 0, 0, 410, 411, 3, 76, 38, 0, 411, 412, 5, 35, 0, 0, 412, 413, 7, 3, 0, 0, 413, 441, 1, 0, 0, 0, 414, 415, 5, 42, 0, 0, 415, 416, 5, 34, 0, 0, 416, 417, 3, 76, 38, 0, 417, 418, 5, 35, 0, 0, 418, 419, 7, 4, 0, 0, 419, 441, 1, 0, 0, 0, 420, 421, 7, 5, 0, 0, 421, 441, 3, 76, 38, 15, 422, 434, 5, 34, 0, 0, 423, 428, 3, 76, 38, 0, 424, 425, 5, 15, 0, 0, 425, 427, 3, 76, 38, 0, 426, 424, 1, 0, 0, 0, 427, 430, 1, 0, 0, 0, 428, 426, 1, 0, 0, 0, 428, 429, 1, 0, 0, 0, 429, 432, 1, 0, 0, 0, 430, 428, 1, 0, 0, 0, 431, 433, 5, 15, 0, 0, 432, 431, 1, 0, 0, 0, 432, 433, 1, 0, 0, 0, 433, 435, 1, 0, 0, 0, 434, 423, 1, 0, 0, 0, 434, 435, 1, 0, 0, 0, 435, 436, 1, 0, 0, 0, 436, 441, 5, 35, 0, 0, 437, 441, 5, 81, 0, 0, 438, 441, 5, 82, 0, 0, 439, 441, 3, 80, 40, 0, 440, 391, 1, 0, 0, 0, 440, 396, 1, 0, 0, 0, 440, 404, 1, 0, 0, 0, 440, 405, 1, 0, 0, 0, 440, 408, 1, 0, 0, 0, 440, 414, 1, 0, 0, 0, 440, 420, 1, 0, 0, 0, 440, 422, 1, 0, 0, 0, 440, 437, 1, 0, 0, 0, 440, 438, 1, 0, 0, 0, 440, 439, 1, 0, 0, 0, 441, 494, 1, 0, 0, 0, 442, 443, 10, 14, 0, 0, 443, 444, 7, 6, 0, 0, 444, 493, 3, 76, 38, 15, 445, 446, 10, 13, 0, 0, 446, 447, 7, 7, 0, 0, 447, 493, 3, 76, 38, 14, 448, 449, 10, 12, 0, 0, 449, 450, 7, 8, 0, 0, 450, 493, 3, 76, 38, 13, 451, 452, 10, 11, 0, 0, 452, 453, 7, 9, 0, 0, 453, 493, 3, 76, 38, 12, 454, 455, 10, 10, 0, 0, 455, 456, 7, 10, 0, 0, 456, 493, 3, 76, 38, 11, 457, 458, 10, 9, 0, 0, 458, 459, 5, 61, 0, 0, 459, 493, 3, 76, 38, 10, 460, 461, 10, 8, 0, 0, 461, 462, 5, 4, 0, 0, 462, 493, 3, 76, 38, 9, 463, 464, 10, 7, 0, 0, 464, 465, 5, 62, 0, 0, 465, 493, 3, 76, 38, 8, 466, 467, 10, 6, 0, 0, 467, 468, 5, 63, 0, 0, 468, 493, 3, 76, 38, 7, 469, 470, 10, 5, 0, 0, 470, 471, 5, 64, 0, 0, 471, 493, 3, 76, 38, 6, 472, 473, 10, 21, 0, 0, 473, 474, 5, 34, 0, 0, 474, 475, 5, 69, 0, 0, 475, 493, 5, 35, 0, 0, 476, 477, 10, 18, 0, 0, 477, 493, 7, 11, 0, 0, 478, 479, 10, 17, 0, 0, 479, 480, 5, 49, 0, 0, 480, 481, 5, 14, 0, 0, 481, 482, 3, 76, 38, 0, 482, 483, 5, 16, 0, 0, 483, 493, 1, 0, 0, 0, 484, 485, 10, 16, 0, 0, 485, 486, 5, 50, 0, 0, 486, 487, 5, 14, 0, 0, 487, 488, 3, 76, 38, 0, 488, 489, 5, 15, 0, 0, 489, 490, 3, 76, 38, 0, 490, 491, 5, 16, 0, 0, 491, 493, 1, 0, 0, 0, 492, 442, 1, 0, 0, 0, 492, 445, 1, 0, 0, 0, 492, 448, 1, 0, 0, 0, 492, 451, 1, 0, 0, 0, 492, 454, 1, 0, 0, 0, 492, 457, 1, 0, 0, 0, 492, 460, 1, 0, 0, 0, 492, 463, 1, 0, 0, 0, 492, 466, 1, 0, 0, 0, 492, 469, 1, 0, 0, 0, 492, 472, 1, 0, 0, 0, 492, 476, 1, 0, 0, 0, 492, 478, 1, 0, 0, 0, 492, 484, 1, 0, 0, 0, 493, 496, 1, 0, 0, 0, 494, 492, 1, 0, 0, 0, 494, 495, 1, 0, 0, 0, 495, 77, 1, 0, 0, 0, 496, 494, 1, 0, 0, 0, 497, 498, 7, 12, 0, 0, 498, 79, 1, 0, 0, 0, 499, 505, 5, 67, 0, 0, 500, 505, 3, 82, 41, 0, 501, 505, 5, 76, 0, 0, 502, 505, 5, 77, 0, 0, 503, 505, 5, 78, 0, 0, 504, 499, 1, 0, 0, 0, 504, 500, 1, 0, 0, 0, 504, 501, 1, 0, 0, 0, 504, 502, 1, 0, 0, 0, 504, 503, 1, 0, 0, 0, 505, 81, 1, 0, 0, 0, 506, 508, 5, 69, 0, 0, 507, 509, 5, 68, 0, 0, 508, 507, 1, 0, 0, 0, 508, 509, 1, 0, 0, 0, 509, 83, 1, 0, 0, 0, 510, 511, 7, 13, 0, 0, 511, 85, 1, 0, 0, 0, 512, 513, 7, 14, 0, 0, 513, 87, 1, 0, 0, 0, 44, 91, 97, 103, 117, 120, 133, 145, 150, 168, 182, 193, 197, 199, 207, 216, 221, 227, 237, 247, 252, 258, 273, 283, 292, 301, 315, 320, 348, 354, 362, 366, 368, 381, 385, 387, 400, 428, 432, 434, 440, 492, 494, 504, 508] \ No newline at end of file +[4, 1, 85, 534, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 1, 0, 5, 0, 92, 8, 0, 10, 0, 12, 0, 95, 9, 0, 1, 0, 5, 0, 98, 8, 0, 10, 0, 12, 0, 101, 9, 0, 1, 0, 5, 0, 104, 8, 0, 10, 0, 12, 0, 107, 9, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 3, 3, 3, 120, 8, 3, 1, 4, 3, 4, 123, 8, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 3, 7, 136, 8, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 5, 8, 146, 8, 8, 10, 8, 12, 8, 149, 9, 8, 1, 8, 1, 8, 3, 8, 153, 8, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 5, 10, 169, 8, 10, 10, 10, 12, 10, 172, 9, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 5, 12, 183, 8, 12, 10, 12, 12, 12, 186, 9, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 5, 13, 194, 8, 13, 10, 13, 12, 13, 197, 9, 13, 1, 13, 3, 13, 200, 8, 13, 3, 13, 202, 8, 13, 1, 13, 1, 13, 1, 14, 1, 14, 5, 14, 208, 8, 14, 10, 14, 12, 14, 211, 9, 14, 1, 14, 1, 14, 1, 15, 1, 15, 5, 15, 217, 8, 15, 10, 15, 12, 15, 220, 9, 15, 1, 15, 1, 15, 3, 15, 224, 8, 15, 1, 16, 1, 16, 1, 16, 1, 16, 3, 16, 230, 8, 16, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 3, 17, 240, 8, 17, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 19, 5, 19, 248, 8, 19, 10, 19, 12, 19, 251, 9, 19, 1, 20, 1, 20, 3, 20, 255, 8, 20, 1, 21, 1, 21, 5, 21, 259, 8, 21, 10, 21, 12, 21, 262, 9, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 4, 22, 271, 8, 22, 11, 22, 12, 22, 272, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 4, 22, 282, 8, 22, 11, 22, 12, 22, 283, 1, 22, 1, 22, 1, 22, 1, 22, 3, 22, 290, 8, 22, 1, 23, 1, 23, 1, 23, 1, 23, 3, 23, 296, 8, 23, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 3, 24, 303, 8, 24, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 3, 25, 312, 8, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 3, 26, 321, 8, 26, 1, 26, 1, 26, 1, 27, 1, 27, 1, 27, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 3, 28, 335, 8, 28, 1, 29, 1, 29, 1, 29, 3, 29, 340, 8, 29, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 33, 1, 33, 3, 33, 368, 8, 33, 1, 34, 1, 34, 1, 35, 1, 35, 3, 35, 374, 8, 35, 1, 36, 1, 36, 1, 36, 1, 36, 5, 36, 380, 8, 36, 10, 36, 12, 36, 383, 9, 36, 1, 36, 3, 36, 386, 8, 36, 3, 36, 388, 8, 36, 1, 36, 1, 36, 1, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 1, 38, 5, 38, 399, 8, 38, 10, 38, 12, 38, 402, 9, 38, 1, 38, 3, 38, 405, 8, 38, 3, 38, 407, 8, 38, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 3, 39, 420, 8, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 5, 39, 446, 8, 39, 10, 39, 12, 39, 449, 9, 39, 1, 39, 3, 39, 452, 8, 39, 3, 39, 454, 8, 39, 1, 39, 1, 39, 1, 39, 1, 39, 3, 39, 460, 8, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 5, 39, 512, 8, 39, 10, 39, 12, 39, 515, 9, 39, 1, 40, 1, 40, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 3, 41, 524, 8, 41, 1, 42, 1, 42, 3, 42, 528, 8, 42, 1, 43, 1, 43, 1, 44, 1, 44, 1, 44, 0, 1, 78, 45, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 0, 15, 1, 0, 4, 10, 2, 0, 10, 10, 22, 23, 1, 0, 24, 25, 1, 0, 37, 41, 2, 0, 37, 41, 43, 46, 2, 0, 5, 5, 51, 52, 1, 0, 53, 55, 2, 0, 52, 52, 56, 56, 1, 0, 57, 58, 1, 0, 6, 9, 1, 0, 59, 60, 1, 0, 47, 48, 2, 0, 17, 17, 65, 65, 1, 0, 72, 74, 2, 0, 72, 73, 80, 80, 567, 0, 93, 1, 0, 0, 0, 2, 110, 1, 0, 0, 0, 4, 115, 1, 0, 0, 0, 6, 117, 1, 0, 0, 0, 8, 122, 1, 0, 0, 0, 10, 126, 1, 0, 0, 0, 12, 128, 1, 0, 0, 0, 14, 135, 1, 0, 0, 0, 16, 137, 1, 0, 0, 0, 18, 156, 1, 0, 0, 0, 20, 163, 1, 0, 0, 0, 22, 175, 1, 0, 0, 0, 24, 180, 1, 0, 0, 0, 26, 189, 1, 0, 0, 0, 28, 205, 1, 0, 0, 0, 30, 223, 1, 0, 0, 0, 32, 229, 1, 0, 0, 0, 34, 239, 1, 0, 0, 0, 36, 241, 1, 0, 0, 0, 38, 243, 1, 0, 0, 0, 40, 254, 1, 0, 0, 0, 42, 256, 1, 0, 0, 0, 44, 289, 1, 0, 0, 0, 46, 295, 1, 0, 0, 0, 48, 302, 1, 0, 0, 0, 50, 304, 1, 0, 0, 0, 52, 315, 1, 0, 0, 0, 54, 324, 1, 0, 0, 0, 56, 327, 1, 0, 0, 0, 58, 339, 1, 0, 0, 0, 60, 341, 1, 0, 0, 0, 62, 349, 1, 0, 0, 0, 64, 355, 1, 0, 0, 0, 66, 367, 1, 0, 0, 0, 68, 369, 1, 0, 0, 0, 70, 373, 1, 0, 0, 0, 72, 375, 1, 0, 0, 0, 74, 391, 1, 0, 0, 0, 76, 394, 1, 0, 0, 0, 78, 459, 1, 0, 0, 0, 80, 516, 1, 0, 0, 0, 82, 523, 1, 0, 0, 0, 84, 525, 1, 0, 0, 0, 86, 529, 1, 0, 0, 0, 88, 531, 1, 0, 0, 0, 90, 92, 3, 2, 1, 0, 91, 90, 1, 0, 0, 0, 92, 95, 1, 0, 0, 0, 93, 91, 1, 0, 0, 0, 93, 94, 1, 0, 0, 0, 94, 99, 1, 0, 0, 0, 95, 93, 1, 0, 0, 0, 96, 98, 3, 12, 6, 0, 97, 96, 1, 0, 0, 0, 98, 101, 1, 0, 0, 0, 99, 97, 1, 0, 0, 0, 99, 100, 1, 0, 0, 0, 100, 105, 1, 0, 0, 0, 101, 99, 1, 0, 0, 0, 102, 104, 3, 14, 7, 0, 103, 102, 1, 0, 0, 0, 104, 107, 1, 0, 0, 0, 105, 103, 1, 0, 0, 0, 105, 106, 1, 0, 0, 0, 106, 108, 1, 0, 0, 0, 107, 105, 1, 0, 0, 0, 108, 109, 5, 0, 0, 1, 109, 1, 1, 0, 0, 0, 110, 111, 5, 1, 0, 0, 111, 112, 3, 4, 2, 0, 112, 113, 3, 6, 3, 0, 113, 114, 5, 2, 0, 0, 114, 3, 1, 0, 0, 0, 115, 116, 5, 3, 0, 0, 116, 5, 1, 0, 0, 0, 117, 119, 3, 8, 4, 0, 118, 120, 3, 8, 4, 0, 119, 118, 1, 0, 0, 0, 119, 120, 1, 0, 0, 0, 120, 7, 1, 0, 0, 0, 121, 123, 3, 10, 5, 0, 122, 121, 1, 0, 0, 0, 122, 123, 1, 0, 0, 0, 123, 124, 1, 0, 0, 0, 124, 125, 5, 66, 0, 0, 125, 9, 1, 0, 0, 0, 126, 127, 7, 0, 0, 0, 127, 11, 1, 0, 0, 0, 128, 129, 5, 11, 0, 0, 129, 130, 5, 76, 0, 0, 130, 131, 5, 2, 0, 0, 131, 13, 1, 0, 0, 0, 132, 136, 3, 16, 8, 0, 133, 136, 3, 18, 9, 0, 134, 136, 3, 20, 10, 0, 135, 132, 1, 0, 0, 0, 135, 133, 1, 0, 0, 0, 135, 134, 1, 0, 0, 0, 136, 15, 1, 0, 0, 0, 137, 138, 5, 12, 0, 0, 138, 139, 5, 82, 0, 0, 139, 152, 3, 26, 13, 0, 140, 141, 5, 13, 0, 0, 141, 142, 5, 14, 0, 0, 142, 147, 3, 86, 43, 0, 143, 144, 5, 15, 0, 0, 144, 146, 3, 86, 43, 0, 145, 143, 1, 0, 0, 0, 146, 149, 1, 0, 0, 0, 147, 145, 1, 0, 0, 0, 147, 148, 1, 0, 0, 0, 148, 150, 1, 0, 0, 0, 149, 147, 1, 0, 0, 0, 150, 151, 5, 16, 0, 0, 151, 153, 1, 0, 0, 0, 152, 140, 1, 0, 0, 0, 152, 153, 1, 0, 0, 0, 153, 154, 1, 0, 0, 0, 154, 155, 3, 24, 12, 0, 155, 17, 1, 0, 0, 0, 156, 157, 3, 86, 43, 0, 157, 158, 5, 17, 0, 0, 158, 159, 5, 82, 0, 0, 159, 160, 5, 10, 0, 0, 160, 161, 3, 82, 41, 0, 161, 162, 5, 2, 0, 0, 162, 19, 1, 0, 0, 0, 163, 164, 5, 18, 0, 0, 164, 165, 5, 82, 0, 0, 165, 166, 3, 26, 13, 0, 166, 170, 5, 19, 0, 0, 167, 169, 3, 22, 11, 0, 168, 167, 1, 0, 0, 0, 169, 172, 1, 0, 0, 0, 170, 168, 1, 0, 0, 0, 170, 171, 1, 0, 0, 0, 171, 173, 1, 0, 0, 0, 172, 170, 1, 0, 0, 0, 173, 174, 5, 20, 0, 0, 174, 21, 1, 0, 0, 0, 175, 176, 5, 12, 0, 0, 176, 177, 5, 82, 0, 0, 177, 178, 3, 26, 13, 0, 178, 179, 3, 24, 12, 0, 179, 23, 1, 0, 0, 0, 180, 184, 5, 19, 0, 0, 181, 183, 3, 32, 16, 0, 182, 181, 1, 0, 0, 0, 183, 186, 1, 0, 0, 0, 184, 182, 1, 0, 0, 0, 184, 185, 1, 0, 0, 0, 185, 187, 1, 0, 0, 0, 186, 184, 1, 0, 0, 0, 187, 188, 5, 20, 0, 0, 188, 25, 1, 0, 0, 0, 189, 201, 5, 14, 0, 0, 190, 195, 3, 28, 14, 0, 191, 192, 5, 15, 0, 0, 192, 194, 3, 28, 14, 0, 193, 191, 1, 0, 0, 0, 194, 197, 1, 0, 0, 0, 195, 193, 1, 0, 0, 0, 195, 196, 1, 0, 0, 0, 196, 199, 1, 0, 0, 0, 197, 195, 1, 0, 0, 0, 198, 200, 5, 15, 0, 0, 199, 198, 1, 0, 0, 0, 199, 200, 1, 0, 0, 0, 200, 202, 1, 0, 0, 0, 201, 190, 1, 0, 0, 0, 201, 202, 1, 0, 0, 0, 202, 203, 1, 0, 0, 0, 203, 204, 5, 16, 0, 0, 204, 27, 1, 0, 0, 0, 205, 209, 3, 86, 43, 0, 206, 208, 3, 80, 40, 0, 207, 206, 1, 0, 0, 0, 208, 211, 1, 0, 0, 0, 209, 207, 1, 0, 0, 0, 209, 210, 1, 0, 0, 0, 210, 212, 1, 0, 0, 0, 211, 209, 1, 0, 0, 0, 212, 213, 5, 82, 0, 0, 213, 29, 1, 0, 0, 0, 214, 218, 5, 19, 0, 0, 215, 217, 3, 32, 16, 0, 216, 215, 1, 0, 0, 0, 217, 220, 1, 0, 0, 0, 218, 216, 1, 0, 0, 0, 218, 219, 1, 0, 0, 0, 219, 221, 1, 0, 0, 0, 220, 218, 1, 0, 0, 0, 221, 224, 5, 20, 0, 0, 222, 224, 3, 32, 16, 0, 223, 214, 1, 0, 0, 0, 223, 222, 1, 0, 0, 0, 224, 31, 1, 0, 0, 0, 225, 230, 3, 40, 20, 0, 226, 227, 3, 34, 17, 0, 227, 228, 5, 2, 0, 0, 228, 230, 1, 0, 0, 0, 229, 225, 1, 0, 0, 0, 229, 226, 1, 0, 0, 0, 230, 33, 1, 0, 0, 0, 231, 240, 3, 42, 21, 0, 232, 240, 3, 44, 22, 0, 233, 240, 3, 48, 24, 0, 234, 240, 3, 50, 25, 0, 235, 240, 3, 52, 26, 0, 236, 240, 3, 36, 18, 0, 237, 240, 3, 54, 27, 0, 238, 240, 3, 38, 19, 0, 239, 231, 1, 0, 0, 0, 239, 232, 1, 0, 0, 0, 239, 233, 1, 0, 0, 0, 239, 234, 1, 0, 0, 0, 239, 235, 1, 0, 0, 0, 239, 236, 1, 0, 0, 0, 239, 237, 1, 0, 0, 0, 239, 238, 1, 0, 0, 0, 240, 35, 1, 0, 0, 0, 241, 242, 3, 74, 37, 0, 242, 37, 1, 0, 0, 0, 243, 244, 5, 21, 0, 0, 244, 249, 3, 78, 39, 0, 245, 246, 5, 15, 0, 0, 246, 248, 3, 78, 39, 0, 247, 245, 1, 0, 0, 0, 248, 251, 1, 0, 0, 0, 249, 247, 1, 0, 0, 0, 249, 250, 1, 0, 0, 0, 250, 39, 1, 0, 0, 0, 251, 249, 1, 0, 0, 0, 252, 255, 3, 56, 28, 0, 253, 255, 3, 58, 29, 0, 254, 252, 1, 0, 0, 0, 254, 253, 1, 0, 0, 0, 255, 41, 1, 0, 0, 0, 256, 260, 3, 86, 43, 0, 257, 259, 3, 80, 40, 0, 258, 257, 1, 0, 0, 0, 259, 262, 1, 0, 0, 0, 260, 258, 1, 0, 0, 0, 260, 261, 1, 0, 0, 0, 261, 263, 1, 0, 0, 0, 262, 260, 1, 0, 0, 0, 263, 264, 5, 82, 0, 0, 264, 265, 5, 10, 0, 0, 265, 266, 3, 78, 39, 0, 266, 43, 1, 0, 0, 0, 267, 270, 3, 46, 23, 0, 268, 269, 5, 15, 0, 0, 269, 271, 3, 46, 23, 0, 270, 268, 1, 0, 0, 0, 271, 272, 1, 0, 0, 0, 272, 270, 1, 0, 0, 0, 272, 273, 1, 0, 0, 0, 273, 274, 1, 0, 0, 0, 274, 275, 5, 10, 0, 0, 275, 276, 3, 78, 39, 0, 276, 290, 1, 0, 0, 0, 277, 278, 5, 14, 0, 0, 278, 281, 3, 46, 23, 0, 279, 280, 5, 15, 0, 0, 280, 282, 3, 46, 23, 0, 281, 279, 1, 0, 0, 0, 282, 283, 1, 0, 0, 0, 283, 281, 1, 0, 0, 0, 283, 284, 1, 0, 0, 0, 284, 285, 1, 0, 0, 0, 285, 286, 5, 16, 0, 0, 286, 287, 5, 10, 0, 0, 287, 288, 3, 78, 39, 0, 288, 290, 1, 0, 0, 0, 289, 267, 1, 0, 0, 0, 289, 277, 1, 0, 0, 0, 290, 45, 1, 0, 0, 0, 291, 292, 3, 86, 43, 0, 292, 293, 5, 82, 0, 0, 293, 296, 1, 0, 0, 0, 294, 296, 5, 82, 0, 0, 295, 291, 1, 0, 0, 0, 295, 294, 1, 0, 0, 0, 296, 47, 1, 0, 0, 0, 297, 298, 5, 82, 0, 0, 298, 299, 7, 1, 0, 0, 299, 303, 3, 78, 39, 0, 300, 301, 5, 82, 0, 0, 301, 303, 7, 2, 0, 0, 302, 297, 1, 0, 0, 0, 302, 300, 1, 0, 0, 0, 303, 49, 1, 0, 0, 0, 304, 305, 5, 26, 0, 0, 305, 306, 5, 14, 0, 0, 306, 307, 5, 79, 0, 0, 307, 308, 5, 6, 0, 0, 308, 311, 3, 78, 39, 0, 309, 310, 5, 15, 0, 0, 310, 312, 3, 68, 34, 0, 311, 309, 1, 0, 0, 0, 311, 312, 1, 0, 0, 0, 312, 313, 1, 0, 0, 0, 313, 314, 5, 16, 0, 0, 314, 51, 1, 0, 0, 0, 315, 316, 5, 26, 0, 0, 316, 317, 5, 14, 0, 0, 317, 320, 3, 78, 39, 0, 318, 319, 5, 15, 0, 0, 319, 321, 3, 68, 34, 0, 320, 318, 1, 0, 0, 0, 320, 321, 1, 0, 0, 0, 321, 322, 1, 0, 0, 0, 322, 323, 5, 16, 0, 0, 323, 53, 1, 0, 0, 0, 324, 325, 5, 27, 0, 0, 325, 326, 3, 72, 36, 0, 326, 55, 1, 0, 0, 0, 327, 328, 5, 28, 0, 0, 328, 329, 5, 14, 0, 0, 329, 330, 3, 78, 39, 0, 330, 331, 5, 16, 0, 0, 331, 334, 3, 30, 15, 0, 332, 333, 5, 29, 0, 0, 333, 335, 3, 30, 15, 0, 334, 332, 1, 0, 0, 0, 334, 335, 1, 0, 0, 0, 335, 57, 1, 0, 0, 0, 336, 340, 3, 60, 30, 0, 337, 340, 3, 62, 31, 0, 338, 340, 3, 64, 32, 0, 339, 336, 1, 0, 0, 0, 339, 337, 1, 0, 0, 0, 339, 338, 1, 0, 0, 0, 340, 59, 1, 0, 0, 0, 341, 342, 5, 30, 0, 0, 342, 343, 3, 30, 15, 0, 343, 344, 5, 31, 0, 0, 344, 345, 5, 14, 0, 0, 345, 346, 3, 78, 39, 0, 346, 347, 5, 16, 0, 0, 347, 348, 5, 2, 0, 0, 348, 61, 1, 0, 0, 0, 349, 350, 5, 31, 0, 0, 350, 351, 5, 14, 0, 0, 351, 352, 3, 78, 39, 0, 352, 353, 5, 16, 0, 0, 353, 354, 3, 30, 15, 0, 354, 63, 1, 0, 0, 0, 355, 356, 5, 32, 0, 0, 356, 357, 5, 14, 0, 0, 357, 358, 3, 66, 33, 0, 358, 359, 5, 2, 0, 0, 359, 360, 3, 78, 39, 0, 360, 361, 5, 2, 0, 0, 361, 362, 3, 48, 24, 0, 362, 363, 5, 16, 0, 0, 363, 364, 3, 30, 15, 0, 364, 65, 1, 0, 0, 0, 365, 368, 3, 42, 21, 0, 366, 368, 3, 48, 24, 0, 367, 365, 1, 0, 0, 0, 367, 366, 1, 0, 0, 0, 368, 67, 1, 0, 0, 0, 369, 370, 5, 76, 0, 0, 370, 69, 1, 0, 0, 0, 371, 374, 5, 82, 0, 0, 372, 374, 3, 82, 41, 0, 373, 371, 1, 0, 0, 0, 373, 372, 1, 0, 0, 0, 374, 71, 1, 0, 0, 0, 375, 387, 5, 14, 0, 0, 376, 381, 3, 70, 35, 0, 377, 378, 5, 15, 0, 0, 378, 380, 3, 70, 35, 0, 379, 377, 1, 0, 0, 0, 380, 383, 1, 0, 0, 0, 381, 379, 1, 0, 0, 0, 381, 382, 1, 0, 0, 0, 382, 385, 1, 0, 0, 0, 383, 381, 1, 0, 0, 0, 384, 386, 5, 15, 0, 0, 385, 384, 1, 0, 0, 0, 385, 386, 1, 0, 0, 0, 386, 388, 1, 0, 0, 0, 387, 376, 1, 0, 0, 0, 387, 388, 1, 0, 0, 0, 388, 389, 1, 0, 0, 0, 389, 390, 5, 16, 0, 0, 390, 73, 1, 0, 0, 0, 391, 392, 5, 82, 0, 0, 392, 393, 3, 76, 38, 0, 393, 75, 1, 0, 0, 0, 394, 406, 5, 14, 0, 0, 395, 400, 3, 78, 39, 0, 396, 397, 5, 15, 0, 0, 397, 399, 3, 78, 39, 0, 398, 396, 1, 0, 0, 0, 399, 402, 1, 0, 0, 0, 400, 398, 1, 0, 0, 0, 400, 401, 1, 0, 0, 0, 401, 404, 1, 0, 0, 0, 402, 400, 1, 0, 0, 0, 403, 405, 5, 15, 0, 0, 404, 403, 1, 0, 0, 0, 404, 405, 1, 0, 0, 0, 405, 407, 1, 0, 0, 0, 406, 395, 1, 0, 0, 0, 406, 407, 1, 0, 0, 0, 407, 408, 1, 0, 0, 0, 408, 409, 5, 16, 0, 0, 409, 77, 1, 0, 0, 0, 410, 411, 6, 39, -1, 0, 411, 412, 5, 14, 0, 0, 412, 413, 3, 78, 39, 0, 413, 414, 5, 16, 0, 0, 414, 460, 1, 0, 0, 0, 415, 416, 3, 88, 44, 0, 416, 417, 5, 14, 0, 0, 417, 419, 3, 78, 39, 0, 418, 420, 5, 15, 0, 0, 419, 418, 1, 0, 0, 0, 419, 420, 1, 0, 0, 0, 420, 421, 1, 0, 0, 0, 421, 422, 5, 16, 0, 0, 422, 460, 1, 0, 0, 0, 423, 460, 3, 74, 37, 0, 424, 425, 5, 33, 0, 0, 425, 426, 5, 82, 0, 0, 426, 460, 3, 76, 38, 0, 427, 428, 5, 36, 0, 0, 428, 429, 5, 34, 0, 0, 429, 430, 3, 78, 39, 0, 430, 431, 5, 35, 0, 0, 431, 432, 7, 3, 0, 0, 432, 460, 1, 0, 0, 0, 433, 434, 5, 42, 0, 0, 434, 435, 5, 34, 0, 0, 435, 436, 3, 78, 39, 0, 436, 437, 5, 35, 0, 0, 437, 438, 7, 4, 0, 0, 438, 460, 1, 0, 0, 0, 439, 440, 7, 5, 0, 0, 440, 460, 3, 78, 39, 15, 441, 453, 5, 34, 0, 0, 442, 447, 3, 78, 39, 0, 443, 444, 5, 15, 0, 0, 444, 446, 3, 78, 39, 0, 445, 443, 1, 0, 0, 0, 446, 449, 1, 0, 0, 0, 447, 445, 1, 0, 0, 0, 447, 448, 1, 0, 0, 0, 448, 451, 1, 0, 0, 0, 449, 447, 1, 0, 0, 0, 450, 452, 5, 15, 0, 0, 451, 450, 1, 0, 0, 0, 451, 452, 1, 0, 0, 0, 452, 454, 1, 0, 0, 0, 453, 442, 1, 0, 0, 0, 453, 454, 1, 0, 0, 0, 454, 455, 1, 0, 0, 0, 455, 460, 5, 35, 0, 0, 456, 460, 5, 81, 0, 0, 457, 460, 5, 82, 0, 0, 458, 460, 3, 82, 41, 0, 459, 410, 1, 0, 0, 0, 459, 415, 1, 0, 0, 0, 459, 423, 1, 0, 0, 0, 459, 424, 1, 0, 0, 0, 459, 427, 1, 0, 0, 0, 459, 433, 1, 0, 0, 0, 459, 439, 1, 0, 0, 0, 459, 441, 1, 0, 0, 0, 459, 456, 1, 0, 0, 0, 459, 457, 1, 0, 0, 0, 459, 458, 1, 0, 0, 0, 460, 513, 1, 0, 0, 0, 461, 462, 10, 14, 0, 0, 462, 463, 7, 6, 0, 0, 463, 512, 3, 78, 39, 15, 464, 465, 10, 13, 0, 0, 465, 466, 7, 7, 0, 0, 466, 512, 3, 78, 39, 14, 467, 468, 10, 12, 0, 0, 468, 469, 7, 8, 0, 0, 469, 512, 3, 78, 39, 13, 470, 471, 10, 11, 0, 0, 471, 472, 7, 9, 0, 0, 472, 512, 3, 78, 39, 12, 473, 474, 10, 10, 0, 0, 474, 475, 7, 10, 0, 0, 475, 512, 3, 78, 39, 11, 476, 477, 10, 9, 0, 0, 477, 478, 5, 61, 0, 0, 478, 512, 3, 78, 39, 10, 479, 480, 10, 8, 0, 0, 480, 481, 5, 4, 0, 0, 481, 512, 3, 78, 39, 9, 482, 483, 10, 7, 0, 0, 483, 484, 5, 62, 0, 0, 484, 512, 3, 78, 39, 8, 485, 486, 10, 6, 0, 0, 486, 487, 5, 63, 0, 0, 487, 512, 3, 78, 39, 7, 488, 489, 10, 5, 0, 0, 489, 490, 5, 64, 0, 0, 490, 512, 3, 78, 39, 6, 491, 492, 10, 21, 0, 0, 492, 493, 5, 34, 0, 0, 493, 494, 5, 69, 0, 0, 494, 512, 5, 35, 0, 0, 495, 496, 10, 18, 0, 0, 496, 512, 7, 11, 0, 0, 497, 498, 10, 17, 0, 0, 498, 499, 5, 49, 0, 0, 499, 500, 5, 14, 0, 0, 500, 501, 3, 78, 39, 0, 501, 502, 5, 16, 0, 0, 502, 512, 1, 0, 0, 0, 503, 504, 10, 16, 0, 0, 504, 505, 5, 50, 0, 0, 505, 506, 5, 14, 0, 0, 506, 507, 3, 78, 39, 0, 507, 508, 5, 15, 0, 0, 508, 509, 3, 78, 39, 0, 509, 510, 5, 16, 0, 0, 510, 512, 1, 0, 0, 0, 511, 461, 1, 0, 0, 0, 511, 464, 1, 0, 0, 0, 511, 467, 1, 0, 0, 0, 511, 470, 1, 0, 0, 0, 511, 473, 1, 0, 0, 0, 511, 476, 1, 0, 0, 0, 511, 479, 1, 0, 0, 0, 511, 482, 1, 0, 0, 0, 511, 485, 1, 0, 0, 0, 511, 488, 1, 0, 0, 0, 511, 491, 1, 0, 0, 0, 511, 495, 1, 0, 0, 0, 511, 497, 1, 0, 0, 0, 511, 503, 1, 0, 0, 0, 512, 515, 1, 0, 0, 0, 513, 511, 1, 0, 0, 0, 513, 514, 1, 0, 0, 0, 514, 79, 1, 0, 0, 0, 515, 513, 1, 0, 0, 0, 516, 517, 7, 12, 0, 0, 517, 81, 1, 0, 0, 0, 518, 524, 5, 67, 0, 0, 519, 524, 3, 84, 42, 0, 520, 524, 5, 76, 0, 0, 521, 524, 5, 77, 0, 0, 522, 524, 5, 78, 0, 0, 523, 518, 1, 0, 0, 0, 523, 519, 1, 0, 0, 0, 523, 520, 1, 0, 0, 0, 523, 521, 1, 0, 0, 0, 523, 522, 1, 0, 0, 0, 524, 83, 1, 0, 0, 0, 525, 527, 5, 69, 0, 0, 526, 528, 5, 68, 0, 0, 527, 526, 1, 0, 0, 0, 527, 528, 1, 0, 0, 0, 528, 85, 1, 0, 0, 0, 529, 530, 7, 13, 0, 0, 530, 87, 1, 0, 0, 0, 531, 532, 7, 14, 0, 0, 532, 89, 1, 0, 0, 0, 47, 93, 99, 105, 119, 122, 135, 147, 152, 170, 184, 195, 199, 201, 209, 218, 223, 229, 239, 249, 254, 260, 272, 283, 289, 295, 302, 311, 320, 334, 339, 367, 373, 381, 385, 387, 400, 404, 406, 419, 447, 451, 453, 459, 511, 513, 523, 527] \ No newline at end of file diff --git a/packages/cashc/src/grammar/CashScriptParser.ts b/packages/cashc/src/grammar/CashScriptParser.ts index 668cd179..a4c3222d 100644 --- a/packages/cashc/src/grammar/CashScriptParser.ts +++ b/packages/cashc/src/grammar/CashScriptParser.ts @@ -127,27 +127,28 @@ export default class CashScriptParser extends Parser { public static readonly RULE_controlStatement = 20; public static readonly RULE_variableDefinition = 21; public static readonly RULE_tupleAssignment = 22; - public static readonly RULE_assignStatement = 23; - public static readonly RULE_timeOpStatement = 24; - public static readonly RULE_requireStatement = 25; - public static readonly RULE_consoleStatement = 26; - public static readonly RULE_ifStatement = 27; - public static readonly RULE_loopStatement = 28; - public static readonly RULE_doWhileStatement = 29; - public static readonly RULE_whileStatement = 30; - public static readonly RULE_forStatement = 31; - public static readonly RULE_forInit = 32; - public static readonly RULE_requireMessage = 33; - public static readonly RULE_consoleParameter = 34; - public static readonly RULE_consoleParameterList = 35; - public static readonly RULE_functionCall = 36; - public static readonly RULE_expressionList = 37; - public static readonly RULE_expression = 38; - public static readonly RULE_modifier = 39; - public static readonly RULE_literal = 40; - public static readonly RULE_numberLiteral = 41; - public static readonly RULE_typeName = 42; - public static readonly RULE_typeCast = 43; + public static readonly RULE_tupleTarget = 23; + public static readonly RULE_assignStatement = 24; + public static readonly RULE_timeOpStatement = 25; + public static readonly RULE_requireStatement = 26; + public static readonly RULE_consoleStatement = 27; + public static readonly RULE_ifStatement = 28; + public static readonly RULE_loopStatement = 29; + public static readonly RULE_doWhileStatement = 30; + public static readonly RULE_whileStatement = 31; + public static readonly RULE_forStatement = 32; + public static readonly RULE_forInit = 33; + public static readonly RULE_requireMessage = 34; + public static readonly RULE_consoleParameter = 35; + public static readonly RULE_consoleParameterList = 36; + public static readonly RULE_functionCall = 37; + public static readonly RULE_expressionList = 38; + public static readonly RULE_expression = 39; + public static readonly RULE_modifier = 40; + public static readonly RULE_literal = 41; + public static readonly RULE_numberLiteral = 42; + public static readonly RULE_typeName = 43; + public static readonly RULE_typeCast = 44; public static readonly literalNames: (string | null)[] = [ null, "'pragma'", "';'", "'cashscript'", "'^'", "'~'", @@ -254,11 +255,11 @@ export default class CashScriptParser extends Parser { "constantDefinition", "contractDefinition", "contractFunctionDefinition", "functionBody", "parameterList", "parameter", "block", "statement", "nonControlStatement", "functionCallStatement", "returnStatement", "controlStatement", "variableDefinition", - "tupleAssignment", "assignStatement", "timeOpStatement", "requireStatement", - "consoleStatement", "ifStatement", "loopStatement", "doWhileStatement", - "whileStatement", "forStatement", "forInit", "requireMessage", "consoleParameter", - "consoleParameterList", "functionCall", "expressionList", "expression", - "modifier", "literal", "numberLiteral", "typeName", "typeCast", + "tupleAssignment", "tupleTarget", "assignStatement", "timeOpStatement", + "requireStatement", "consoleStatement", "ifStatement", "loopStatement", + "doWhileStatement", "whileStatement", "forStatement", "forInit", "requireMessage", + "consoleParameter", "consoleParameterList", "functionCall", "expressionList", + "expression", "modifier", "literal", "numberLiteral", "typeName", "typeCast", ]; public get grammarFileName(): string { return "CashScript.g4"; } public get literalNames(): (string | null)[] { return CashScriptParser.literalNames; } @@ -282,49 +283,49 @@ export default class CashScriptParser extends Parser { try { this.enterOuterAlt(localctx, 1); { - this.state = 91; + this.state = 93; this._errHandler.sync(this); _la = this._input.LA(1); while (_la===1) { { { - this.state = 88; + this.state = 90; this.pragmaDirective(); } } - this.state = 93; + this.state = 95; this._errHandler.sync(this); _la = this._input.LA(1); } - this.state = 97; + this.state = 99; this._errHandler.sync(this); _la = this._input.LA(1); while (_la===11) { { { - this.state = 94; + this.state = 96; this.importDirective(); } } - this.state = 99; + this.state = 101; this._errHandler.sync(this); _la = this._input.LA(1); } - this.state = 103; + this.state = 105; this._errHandler.sync(this); _la = this._input.LA(1); while (_la===12 || _la===18 || ((((_la - 72)) & ~0x1F) === 0 && ((1 << (_la - 72)) & 7) !== 0)) { { { - this.state = 100; + this.state = 102; this.topLevelDefinition(); } } - this.state = 105; + this.state = 107; this._errHandler.sync(this); _la = this._input.LA(1); } - this.state = 106; + this.state = 108; this.match(CashScriptParser.EOF); } } @@ -349,13 +350,13 @@ export default class CashScriptParser extends Parser { try { this.enterOuterAlt(localctx, 1); { - this.state = 108; + this.state = 110; this.match(CashScriptParser.T__0); - this.state = 109; + this.state = 111; this.pragmaName(); - this.state = 110; + this.state = 112; this.pragmaValue(); - this.state = 111; + this.state = 113; this.match(CashScriptParser.T__1); } } @@ -380,7 +381,7 @@ export default class CashScriptParser extends Parser { try { this.enterOuterAlt(localctx, 1); { - this.state = 113; + this.state = 115; this.match(CashScriptParser.T__2); } } @@ -406,14 +407,14 @@ export default class CashScriptParser extends Parser { try { this.enterOuterAlt(localctx, 1); { - this.state = 115; - this.versionConstraint(); this.state = 117; + this.versionConstraint(); + this.state = 119; this._errHandler.sync(this); _la = this._input.LA(1); if ((((_la) & ~0x1F) === 0 && ((1 << _la) & 2032) !== 0) || _la===66) { { - this.state = 116; + this.state = 118; this.versionConstraint(); } } @@ -442,17 +443,17 @@ export default class CashScriptParser extends Parser { try { this.enterOuterAlt(localctx, 1); { - this.state = 120; + this.state = 122; this._errHandler.sync(this); _la = this._input.LA(1); if ((((_la) & ~0x1F) === 0 && ((1 << _la) & 2032) !== 0)) { { - this.state = 119; + this.state = 121; this.versionOperator(); } } - this.state = 122; + this.state = 124; this.match(CashScriptParser.VersionLiteral); } } @@ -478,7 +479,7 @@ export default class CashScriptParser extends Parser { try { this.enterOuterAlt(localctx, 1); { - this.state = 124; + this.state = 126; _la = this._input.LA(1); if(!((((_la) & ~0x1F) === 0 && ((1 << _la) & 2032) !== 0))) { this._errHandler.recoverInline(this); @@ -510,11 +511,11 @@ export default class CashScriptParser extends Parser { try { this.enterOuterAlt(localctx, 1); { - this.state = 126; + this.state = 128; this.match(CashScriptParser.T__10); - this.state = 127; + this.state = 129; this.match(CashScriptParser.StringLiteral); - this.state = 128; + this.state = 130; this.match(CashScriptParser.T__1); } } @@ -537,13 +538,13 @@ export default class CashScriptParser extends Parser { let localctx: TopLevelDefinitionContext = new TopLevelDefinitionContext(this, this._ctx, this.state); this.enterRule(localctx, 14, CashScriptParser.RULE_topLevelDefinition); try { - this.state = 133; + this.state = 135; this._errHandler.sync(this); switch (this._input.LA(1)) { case 12: this.enterOuterAlt(localctx, 1); { - this.state = 130; + this.state = 132; this.globalFunctionDefinition(); } break; @@ -552,14 +553,14 @@ export default class CashScriptParser extends Parser { case 74: this.enterOuterAlt(localctx, 2); { - this.state = 131; + this.state = 133; this.constantDefinition(); } break; case 18: this.enterOuterAlt(localctx, 3); { - this.state = 132; + this.state = 134; this.contractDefinition(); } break; @@ -589,45 +590,45 @@ export default class CashScriptParser extends Parser { try { this.enterOuterAlt(localctx, 1); { - this.state = 135; + this.state = 137; this.match(CashScriptParser.T__11); - this.state = 136; + this.state = 138; this.match(CashScriptParser.Identifier); - this.state = 137; + this.state = 139; this.parameterList(); - this.state = 150; + this.state = 152; this._errHandler.sync(this); _la = this._input.LA(1); if (_la===13) { { - this.state = 138; + this.state = 140; this.match(CashScriptParser.T__12); - this.state = 139; + this.state = 141; this.match(CashScriptParser.T__13); - this.state = 140; + this.state = 142; this.typeName(); - this.state = 145; + this.state = 147; this._errHandler.sync(this); _la = this._input.LA(1); while (_la===15) { { { - this.state = 141; + this.state = 143; this.match(CashScriptParser.T__14); - this.state = 142; + this.state = 144; this.typeName(); } } - this.state = 147; + this.state = 149; this._errHandler.sync(this); _la = this._input.LA(1); } - this.state = 148; + this.state = 150; this.match(CashScriptParser.T__15); } } - this.state = 152; + this.state = 154; this.functionBody(); } } @@ -652,17 +653,17 @@ export default class CashScriptParser extends Parser { try { this.enterOuterAlt(localctx, 1); { - this.state = 154; + this.state = 156; this.typeName(); - this.state = 155; + this.state = 157; this.match(CashScriptParser.T__16); - this.state = 156; + this.state = 158; this.match(CashScriptParser.Identifier); - this.state = 157; + this.state = 159; this.match(CashScriptParser.T__9); - this.state = 158; + this.state = 160; this.literal(); - this.state = 159; + this.state = 161; this.match(CashScriptParser.T__1); } } @@ -688,29 +689,29 @@ export default class CashScriptParser extends Parser { try { this.enterOuterAlt(localctx, 1); { - this.state = 161; + this.state = 163; this.match(CashScriptParser.T__17); - this.state = 162; + this.state = 164; this.match(CashScriptParser.Identifier); - this.state = 163; + this.state = 165; this.parameterList(); - this.state = 164; + this.state = 166; this.match(CashScriptParser.T__18); - this.state = 168; + this.state = 170; this._errHandler.sync(this); _la = this._input.LA(1); while (_la===12) { { { - this.state = 165; + this.state = 167; this.contractFunctionDefinition(); } } - this.state = 170; + this.state = 172; this._errHandler.sync(this); _la = this._input.LA(1); } - this.state = 171; + this.state = 173; this.match(CashScriptParser.T__19); } } @@ -735,13 +736,13 @@ export default class CashScriptParser extends Parser { try { this.enterOuterAlt(localctx, 1); { - this.state = 173; + this.state = 175; this.match(CashScriptParser.T__11); - this.state = 174; + this.state = 176; this.match(CashScriptParser.Identifier); - this.state = 175; + this.state = 177; this.parameterList(); - this.state = 176; + this.state = 178; this.functionBody(); } } @@ -767,23 +768,23 @@ export default class CashScriptParser extends Parser { try { this.enterOuterAlt(localctx, 1); { - this.state = 178; + this.state = 180; this.match(CashScriptParser.T__18); - this.state = 182; + this.state = 184; this._errHandler.sync(this); _la = this._input.LA(1); - while (((((_la - 21)) & ~0x1F) === 0 && ((1 << (_la - 21)) & 3809) !== 0) || ((((_la - 72)) & ~0x1F) === 0 && ((1 << (_la - 72)) & 1031) !== 0)) { + while (((((_la - 14)) & ~0x1F) === 0 && ((1 << (_la - 14)) & 487553) !== 0) || ((((_la - 72)) & ~0x1F) === 0 && ((1 << (_la - 72)) & 1031) !== 0)) { { { - this.state = 179; + this.state = 181; this.statement(); } } - this.state = 184; + this.state = 186; this._errHandler.sync(this); _la = this._input.LA(1); } - this.state = 185; + this.state = 187; this.match(CashScriptParser.T__19); } } @@ -810,39 +811,39 @@ export default class CashScriptParser extends Parser { let _alt: number; this.enterOuterAlt(localctx, 1); { - this.state = 187; + this.state = 189; this.match(CashScriptParser.T__13); - this.state = 199; + this.state = 201; this._errHandler.sync(this); _la = this._input.LA(1); if (((((_la - 72)) & ~0x1F) === 0 && ((1 << (_la - 72)) & 7) !== 0)) { { - this.state = 188; + this.state = 190; this.parameter(); - this.state = 193; + this.state = 195; this._errHandler.sync(this); _alt = this._interp.adaptivePredict(this._input, 10, this._ctx); while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { if (_alt === 1) { { { - this.state = 189; + this.state = 191; this.match(CashScriptParser.T__14); - this.state = 190; + this.state = 192; this.parameter(); } } } - this.state = 195; + this.state = 197; this._errHandler.sync(this); _alt = this._interp.adaptivePredict(this._input, 10, this._ctx); } - this.state = 197; + this.state = 199; this._errHandler.sync(this); _la = this._input.LA(1); if (_la===15) { { - this.state = 196; + this.state = 198; this.match(CashScriptParser.T__14); } } @@ -850,7 +851,7 @@ export default class CashScriptParser extends Parser { } } - this.state = 201; + this.state = 203; this.match(CashScriptParser.T__15); } } @@ -876,23 +877,23 @@ export default class CashScriptParser extends Parser { try { this.enterOuterAlt(localctx, 1); { - this.state = 203; + this.state = 205; this.typeName(); - this.state = 207; + this.state = 209; this._errHandler.sync(this); _la = this._input.LA(1); while (_la===17 || _la===65) { { { - this.state = 204; + this.state = 206; this.modifier(); } } - this.state = 209; + this.state = 211; this._errHandler.sync(this); _la = this._input.LA(1); } - this.state = 210; + this.state = 212; this.match(CashScriptParser.Identifier); } } @@ -916,32 +917,33 @@ export default class CashScriptParser extends Parser { this.enterRule(localctx, 30, CashScriptParser.RULE_block); let _la: number; try { - this.state = 221; + this.state = 223; this._errHandler.sync(this); switch (this._input.LA(1)) { case 19: this.enterOuterAlt(localctx, 1); { - this.state = 212; + this.state = 214; this.match(CashScriptParser.T__18); - this.state = 216; + this.state = 218; this._errHandler.sync(this); _la = this._input.LA(1); - while (((((_la - 21)) & ~0x1F) === 0 && ((1 << (_la - 21)) & 3809) !== 0) || ((((_la - 72)) & ~0x1F) === 0 && ((1 << (_la - 72)) & 1031) !== 0)) { + while (((((_la - 14)) & ~0x1F) === 0 && ((1 << (_la - 14)) & 487553) !== 0) || ((((_la - 72)) & ~0x1F) === 0 && ((1 << (_la - 72)) & 1031) !== 0)) { { { - this.state = 213; + this.state = 215; this.statement(); } } - this.state = 218; + this.state = 220; this._errHandler.sync(this); _la = this._input.LA(1); } - this.state = 219; + this.state = 221; this.match(CashScriptParser.T__19); } break; + case 14: case 21: case 26: case 27: @@ -955,7 +957,7 @@ export default class CashScriptParser extends Parser { case 82: this.enterOuterAlt(localctx, 2); { - this.state = 220; + this.state = 222; this.statement(); } break; @@ -982,7 +984,7 @@ export default class CashScriptParser extends Parser { let localctx: StatementContext = new StatementContext(this, this._ctx, this.state); this.enterRule(localctx, 32, CashScriptParser.RULE_statement); try { - this.state = 227; + this.state = 229; this._errHandler.sync(this); switch (this._input.LA(1)) { case 28: @@ -991,10 +993,11 @@ export default class CashScriptParser extends Parser { case 32: this.enterOuterAlt(localctx, 1); { - this.state = 223; + this.state = 225; this.controlStatement(); } break; + case 14: case 21: case 26: case 27: @@ -1004,9 +1007,9 @@ export default class CashScriptParser extends Parser { case 82: this.enterOuterAlt(localctx, 2); { - this.state = 224; + this.state = 226; this.nonControlStatement(); - this.state = 225; + this.state = 227; this.match(CashScriptParser.T__1); } break; @@ -1033,62 +1036,62 @@ export default class CashScriptParser extends Parser { let localctx: NonControlStatementContext = new NonControlStatementContext(this, this._ctx, this.state); this.enterRule(localctx, 34, CashScriptParser.RULE_nonControlStatement); try { - this.state = 237; + this.state = 239; this._errHandler.sync(this); switch ( this._interp.adaptivePredict(this._input, 17, this._ctx) ) { case 1: this.enterOuterAlt(localctx, 1); { - this.state = 229; + this.state = 231; this.variableDefinition(); } break; case 2: this.enterOuterAlt(localctx, 2); { - this.state = 230; + this.state = 232; this.tupleAssignment(); } break; case 3: this.enterOuterAlt(localctx, 3); { - this.state = 231; + this.state = 233; this.assignStatement(); } break; case 4: this.enterOuterAlt(localctx, 4); { - this.state = 232; + this.state = 234; this.timeOpStatement(); } break; case 5: this.enterOuterAlt(localctx, 5); { - this.state = 233; + this.state = 235; this.requireStatement(); } break; case 6: this.enterOuterAlt(localctx, 6); { - this.state = 234; + this.state = 236; this.functionCallStatement(); } break; case 7: this.enterOuterAlt(localctx, 7); { - this.state = 235; + this.state = 237; this.consoleStatement(); } break; case 8: this.enterOuterAlt(localctx, 8); { - this.state = 236; + this.state = 238; this.returnStatement(); } break; @@ -1115,7 +1118,7 @@ export default class CashScriptParser extends Parser { try { this.enterOuterAlt(localctx, 1); { - this.state = 239; + this.state = 241; this.functionCall(); } } @@ -1141,23 +1144,23 @@ export default class CashScriptParser extends Parser { try { this.enterOuterAlt(localctx, 1); { - this.state = 241; + this.state = 243; this.match(CashScriptParser.T__20); - this.state = 242; + this.state = 244; this.expression(0); - this.state = 247; + this.state = 249; this._errHandler.sync(this); _la = this._input.LA(1); while (_la===15) { { { - this.state = 243; + this.state = 245; this.match(CashScriptParser.T__14); - this.state = 244; + this.state = 246; this.expression(0); } } - this.state = 249; + this.state = 251; this._errHandler.sync(this); _la = this._input.LA(1); } @@ -1182,13 +1185,13 @@ export default class CashScriptParser extends Parser { let localctx: ControlStatementContext = new ControlStatementContext(this, this._ctx, this.state); this.enterRule(localctx, 40, CashScriptParser.RULE_controlStatement); try { - this.state = 252; + this.state = 254; this._errHandler.sync(this); switch (this._input.LA(1)) { case 28: this.enterOuterAlt(localctx, 1); { - this.state = 250; + this.state = 252; this.ifStatement(); } break; @@ -1197,7 +1200,7 @@ export default class CashScriptParser extends Parser { case 32: this.enterOuterAlt(localctx, 2); { - this.state = 251; + this.state = 253; this.loopStatement(); } break; @@ -1227,27 +1230,27 @@ export default class CashScriptParser extends Parser { try { this.enterOuterAlt(localctx, 1); { - this.state = 254; + this.state = 256; this.typeName(); - this.state = 258; + this.state = 260; this._errHandler.sync(this); _la = this._input.LA(1); while (_la===17 || _la===65) { { { - this.state = 255; + this.state = 257; this.modifier(); } } - this.state = 260; + this.state = 262; this._errHandler.sync(this); _la = this._input.LA(1); } - this.state = 261; + this.state = 263; this.match(CashScriptParser.Identifier); - this.state = 262; + this.state = 264; this.match(CashScriptParser.T__9); - this.state = 263; + this.state = 265; this.expression(0); } } @@ -1271,34 +1274,116 @@ export default class CashScriptParser extends Parser { this.enterRule(localctx, 44, CashScriptParser.RULE_tupleAssignment); let _la: number; try { - this.enterOuterAlt(localctx, 1); - { - this.state = 265; - this.typeName(); - this.state = 266; - this.match(CashScriptParser.Identifier); - this.state = 271; + this.state = 289; this._errHandler.sync(this); - _la = this._input.LA(1); - do { - { + switch (this._input.LA(1)) { + case 72: + case 73: + case 74: + case 82: + this.enterOuterAlt(localctx, 1); { this.state = 267; - this.match(CashScriptParser.T__14); - this.state = 268; + this.tupleTarget(); + this.state = 270; + this._errHandler.sync(this); + _la = this._input.LA(1); + do { + { + { + this.state = 268; + this.match(CashScriptParser.T__14); + this.state = 269; + this.tupleTarget(); + } + } + this.state = 272; + this._errHandler.sync(this); + _la = this._input.LA(1); + } while (_la===15); + this.state = 274; + this.match(CashScriptParser.T__9); + this.state = 275; + this.expression(0); + } + break; + case 14: + this.enterOuterAlt(localctx, 2); + { + this.state = 277; + this.match(CashScriptParser.T__13); + this.state = 278; + this.tupleTarget(); + this.state = 281; + this._errHandler.sync(this); + _la = this._input.LA(1); + do { + { + { + this.state = 279; + this.match(CashScriptParser.T__14); + this.state = 280; + this.tupleTarget(); + } + } + this.state = 283; + this._errHandler.sync(this); + _la = this._input.LA(1); + } while (_la===15); + this.state = 285; + this.match(CashScriptParser.T__15); + this.state = 286; + this.match(CashScriptParser.T__9); + this.state = 287; + this.expression(0); + } + break; + default: + throw new NoViableAltException(this); + } + } + catch (re) { + if (re instanceof RecognitionException) { + localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localctx; + } + // @RuleVersion(0) + public tupleTarget(): TupleTargetContext { + let localctx: TupleTargetContext = new TupleTargetContext(this, this._ctx, this.state); + this.enterRule(localctx, 46, CashScriptParser.RULE_tupleTarget); + try { + this.state = 295; + this._errHandler.sync(this); + switch (this._input.LA(1)) { + case 72: + case 73: + case 74: + this.enterOuterAlt(localctx, 1); + { + this.state = 291; this.typeName(); - this.state = 269; + this.state = 292; this.match(CashScriptParser.Identifier); } + break; + case 82: + this.enterOuterAlt(localctx, 2); + { + this.state = 294; + this.match(CashScriptParser.Identifier); } - this.state = 273; - this._errHandler.sync(this); - _la = this._input.LA(1); - } while (_la===15); - this.state = 275; - this.match(CashScriptParser.T__9); - this.state = 276; - this.expression(0); + break; + default: + throw new NoViableAltException(this); } } catch (re) { @@ -1318,18 +1403,18 @@ export default class CashScriptParser extends Parser { // @RuleVersion(0) public assignStatement(): AssignStatementContext { let localctx: AssignStatementContext = new AssignStatementContext(this, this._ctx, this.state); - this.enterRule(localctx, 46, CashScriptParser.RULE_assignStatement); + this.enterRule(localctx, 48, CashScriptParser.RULE_assignStatement); let _la: number; try { - this.state = 283; + this.state = 302; this._errHandler.sync(this); - switch ( this._interp.adaptivePredict(this._input, 22, this._ctx) ) { + switch ( this._interp.adaptivePredict(this._input, 25, this._ctx) ) { case 1: this.enterOuterAlt(localctx, 1); { - this.state = 278; + this.state = 297; this.match(CashScriptParser.Identifier); - this.state = 279; + this.state = 298; localctx._op = this._input.LT(1); _la = this._input.LA(1); if(!((((_la) & ~0x1F) === 0 && ((1 << _la) & 12583936) !== 0))) { @@ -1339,16 +1424,16 @@ export default class CashScriptParser extends Parser { this._errHandler.reportMatch(this); this.consume(); } - this.state = 280; + this.state = 299; this.expression(0); } break; case 2: this.enterOuterAlt(localctx, 2); { - this.state = 281; + this.state = 300; this.match(CashScriptParser.Identifier); - this.state = 282; + this.state = 301; localctx._op = this._input.LT(1); _la = this._input.LA(1); if(!(_la===24 || _la===25)) { @@ -1379,34 +1464,34 @@ export default class CashScriptParser extends Parser { // @RuleVersion(0) public timeOpStatement(): TimeOpStatementContext { let localctx: TimeOpStatementContext = new TimeOpStatementContext(this, this._ctx, this.state); - this.enterRule(localctx, 48, CashScriptParser.RULE_timeOpStatement); + this.enterRule(localctx, 50, CashScriptParser.RULE_timeOpStatement); let _la: number; try { this.enterOuterAlt(localctx, 1); { - this.state = 285; + this.state = 304; this.match(CashScriptParser.T__25); - this.state = 286; + this.state = 305; this.match(CashScriptParser.T__13); - this.state = 287; + this.state = 306; this.match(CashScriptParser.TxVar); - this.state = 288; + this.state = 307; this.match(CashScriptParser.T__5); - this.state = 289; + this.state = 308; this.expression(0); - this.state = 292; + this.state = 311; this._errHandler.sync(this); _la = this._input.LA(1); if (_la===15) { { - this.state = 290; + this.state = 309; this.match(CashScriptParser.T__14); - this.state = 291; + this.state = 310; this.requireMessage(); } } - this.state = 294; + this.state = 313; this.match(CashScriptParser.T__15); } } @@ -1427,30 +1512,30 @@ export default class CashScriptParser extends Parser { // @RuleVersion(0) public requireStatement(): RequireStatementContext { let localctx: RequireStatementContext = new RequireStatementContext(this, this._ctx, this.state); - this.enterRule(localctx, 50, CashScriptParser.RULE_requireStatement); + this.enterRule(localctx, 52, CashScriptParser.RULE_requireStatement); let _la: number; try { this.enterOuterAlt(localctx, 1); { - this.state = 296; + this.state = 315; this.match(CashScriptParser.T__25); - this.state = 297; + this.state = 316; this.match(CashScriptParser.T__13); - this.state = 298; + this.state = 317; this.expression(0); - this.state = 301; + this.state = 320; this._errHandler.sync(this); _la = this._input.LA(1); if (_la===15) { { - this.state = 299; + this.state = 318; this.match(CashScriptParser.T__14); - this.state = 300; + this.state = 319; this.requireMessage(); } } - this.state = 303; + this.state = 322; this.match(CashScriptParser.T__15); } } @@ -1471,13 +1556,13 @@ export default class CashScriptParser extends Parser { // @RuleVersion(0) public consoleStatement(): ConsoleStatementContext { let localctx: ConsoleStatementContext = new ConsoleStatementContext(this, this._ctx, this.state); - this.enterRule(localctx, 52, CashScriptParser.RULE_consoleStatement); + this.enterRule(localctx, 54, CashScriptParser.RULE_consoleStatement); try { this.enterOuterAlt(localctx, 1); { - this.state = 305; + this.state = 324; this.match(CashScriptParser.T__26); - this.state = 306; + this.state = 325; this.consoleParameterList(); } } @@ -1498,28 +1583,28 @@ export default class CashScriptParser extends Parser { // @RuleVersion(0) public ifStatement(): IfStatementContext { let localctx: IfStatementContext = new IfStatementContext(this, this._ctx, this.state); - this.enterRule(localctx, 54, CashScriptParser.RULE_ifStatement); + this.enterRule(localctx, 56, CashScriptParser.RULE_ifStatement); try { this.enterOuterAlt(localctx, 1); { - this.state = 308; + this.state = 327; this.match(CashScriptParser.T__27); - this.state = 309; + this.state = 328; this.match(CashScriptParser.T__13); - this.state = 310; + this.state = 329; this.expression(0); - this.state = 311; + this.state = 330; this.match(CashScriptParser.T__15); - this.state = 312; + this.state = 331; localctx._ifBlock = this.block(); - this.state = 315; + this.state = 334; this._errHandler.sync(this); - switch ( this._interp.adaptivePredict(this._input, 25, this._ctx) ) { + switch ( this._interp.adaptivePredict(this._input, 28, this._ctx) ) { case 1: { - this.state = 313; + this.state = 332; this.match(CashScriptParser.T__28); - this.state = 314; + this.state = 333; localctx._elseBlock = this.block(); } break; @@ -1543,29 +1628,29 @@ export default class CashScriptParser extends Parser { // @RuleVersion(0) public loopStatement(): LoopStatementContext { let localctx: LoopStatementContext = new LoopStatementContext(this, this._ctx, this.state); - this.enterRule(localctx, 56, CashScriptParser.RULE_loopStatement); + this.enterRule(localctx, 58, CashScriptParser.RULE_loopStatement); try { - this.state = 320; + this.state = 339; this._errHandler.sync(this); switch (this._input.LA(1)) { case 30: this.enterOuterAlt(localctx, 1); { - this.state = 317; + this.state = 336; this.doWhileStatement(); } break; case 31: this.enterOuterAlt(localctx, 2); { - this.state = 318; + this.state = 337; this.whileStatement(); } break; case 32: this.enterOuterAlt(localctx, 3); { - this.state = 319; + this.state = 338; this.forStatement(); } break; @@ -1590,23 +1675,23 @@ export default class CashScriptParser extends Parser { // @RuleVersion(0) public doWhileStatement(): DoWhileStatementContext { let localctx: DoWhileStatementContext = new DoWhileStatementContext(this, this._ctx, this.state); - this.enterRule(localctx, 58, CashScriptParser.RULE_doWhileStatement); + this.enterRule(localctx, 60, CashScriptParser.RULE_doWhileStatement); try { this.enterOuterAlt(localctx, 1); { - this.state = 322; + this.state = 341; this.match(CashScriptParser.T__29); - this.state = 323; + this.state = 342; this.block(); - this.state = 324; + this.state = 343; this.match(CashScriptParser.T__30); - this.state = 325; + this.state = 344; this.match(CashScriptParser.T__13); - this.state = 326; + this.state = 345; this.expression(0); - this.state = 327; + this.state = 346; this.match(CashScriptParser.T__15); - this.state = 328; + this.state = 347; this.match(CashScriptParser.T__1); } } @@ -1627,19 +1712,19 @@ export default class CashScriptParser extends Parser { // @RuleVersion(0) public whileStatement(): WhileStatementContext { let localctx: WhileStatementContext = new WhileStatementContext(this, this._ctx, this.state); - this.enterRule(localctx, 60, CashScriptParser.RULE_whileStatement); + this.enterRule(localctx, 62, CashScriptParser.RULE_whileStatement); try { this.enterOuterAlt(localctx, 1); { - this.state = 330; + this.state = 349; this.match(CashScriptParser.T__30); - this.state = 331; + this.state = 350; this.match(CashScriptParser.T__13); - this.state = 332; + this.state = 351; this.expression(0); - this.state = 333; + this.state = 352; this.match(CashScriptParser.T__15); - this.state = 334; + this.state = 353; this.block(); } } @@ -1660,27 +1745,27 @@ export default class CashScriptParser extends Parser { // @RuleVersion(0) public forStatement(): ForStatementContext { let localctx: ForStatementContext = new ForStatementContext(this, this._ctx, this.state); - this.enterRule(localctx, 62, CashScriptParser.RULE_forStatement); + this.enterRule(localctx, 64, CashScriptParser.RULE_forStatement); try { this.enterOuterAlt(localctx, 1); { - this.state = 336; + this.state = 355; this.match(CashScriptParser.T__31); - this.state = 337; + this.state = 356; this.match(CashScriptParser.T__13); - this.state = 338; + this.state = 357; this.forInit(); - this.state = 339; + this.state = 358; this.match(CashScriptParser.T__1); - this.state = 340; + this.state = 359; this.expression(0); - this.state = 341; + this.state = 360; this.match(CashScriptParser.T__1); - this.state = 342; + this.state = 361; this.assignStatement(); - this.state = 343; + this.state = 362; this.match(CashScriptParser.T__15); - this.state = 344; + this.state = 363; this.block(); } } @@ -1701,9 +1786,9 @@ export default class CashScriptParser extends Parser { // @RuleVersion(0) public forInit(): ForInitContext { let localctx: ForInitContext = new ForInitContext(this, this._ctx, this.state); - this.enterRule(localctx, 64, CashScriptParser.RULE_forInit); + this.enterRule(localctx, 66, CashScriptParser.RULE_forInit); try { - this.state = 348; + this.state = 367; this._errHandler.sync(this); switch (this._input.LA(1)) { case 72: @@ -1711,14 +1796,14 @@ export default class CashScriptParser extends Parser { case 74: this.enterOuterAlt(localctx, 1); { - this.state = 346; + this.state = 365; this.variableDefinition(); } break; case 82: this.enterOuterAlt(localctx, 2); { - this.state = 347; + this.state = 366; this.assignStatement(); } break; @@ -1743,11 +1828,11 @@ export default class CashScriptParser extends Parser { // @RuleVersion(0) public requireMessage(): RequireMessageContext { let localctx: RequireMessageContext = new RequireMessageContext(this, this._ctx, this.state); - this.enterRule(localctx, 66, CashScriptParser.RULE_requireMessage); + this.enterRule(localctx, 68, CashScriptParser.RULE_requireMessage); try { this.enterOuterAlt(localctx, 1); { - this.state = 350; + this.state = 369; this.match(CashScriptParser.StringLiteral); } } @@ -1768,15 +1853,15 @@ export default class CashScriptParser extends Parser { // @RuleVersion(0) public consoleParameter(): ConsoleParameterContext { let localctx: ConsoleParameterContext = new ConsoleParameterContext(this, this._ctx, this.state); - this.enterRule(localctx, 68, CashScriptParser.RULE_consoleParameter); + this.enterRule(localctx, 70, CashScriptParser.RULE_consoleParameter); try { - this.state = 354; + this.state = 373; this._errHandler.sync(this); switch (this._input.LA(1)) { case 82: this.enterOuterAlt(localctx, 1); { - this.state = 352; + this.state = 371; this.match(CashScriptParser.Identifier); } break; @@ -1787,7 +1872,7 @@ export default class CashScriptParser extends Parser { case 78: this.enterOuterAlt(localctx, 2); { - this.state = 353; + this.state = 372; this.literal(); } break; @@ -1812,45 +1897,45 @@ export default class CashScriptParser extends Parser { // @RuleVersion(0) public consoleParameterList(): ConsoleParameterListContext { let localctx: ConsoleParameterListContext = new ConsoleParameterListContext(this, this._ctx, this.state); - this.enterRule(localctx, 70, CashScriptParser.RULE_consoleParameterList); + this.enterRule(localctx, 72, CashScriptParser.RULE_consoleParameterList); let _la: number; try { let _alt: number; this.enterOuterAlt(localctx, 1); { - this.state = 356; + this.state = 375; this.match(CashScriptParser.T__13); - this.state = 368; + this.state = 387; this._errHandler.sync(this); _la = this._input.LA(1); if (((((_la - 67)) & ~0x1F) === 0 && ((1 << (_la - 67)) & 36357) !== 0)) { { - this.state = 357; + this.state = 376; this.consoleParameter(); - this.state = 362; + this.state = 381; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 29, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 32, this._ctx); while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { if (_alt === 1) { { { - this.state = 358; + this.state = 377; this.match(CashScriptParser.T__14); - this.state = 359; + this.state = 378; this.consoleParameter(); } } } - this.state = 364; + this.state = 383; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 29, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 32, this._ctx); } - this.state = 366; + this.state = 385; this._errHandler.sync(this); _la = this._input.LA(1); if (_la===15) { { - this.state = 365; + this.state = 384; this.match(CashScriptParser.T__14); } } @@ -1858,7 +1943,7 @@ export default class CashScriptParser extends Parser { } } - this.state = 370; + this.state = 389; this.match(CashScriptParser.T__15); } } @@ -1879,13 +1964,13 @@ export default class CashScriptParser extends Parser { // @RuleVersion(0) public functionCall(): FunctionCallContext { let localctx: FunctionCallContext = new FunctionCallContext(this, this._ctx, this.state); - this.enterRule(localctx, 72, CashScriptParser.RULE_functionCall); + this.enterRule(localctx, 74, CashScriptParser.RULE_functionCall); try { this.enterOuterAlt(localctx, 1); { - this.state = 372; + this.state = 391; this.match(CashScriptParser.Identifier); - this.state = 373; + this.state = 392; this.expressionList(); } } @@ -1906,45 +1991,45 @@ export default class CashScriptParser extends Parser { // @RuleVersion(0) public expressionList(): ExpressionListContext { let localctx: ExpressionListContext = new ExpressionListContext(this, this._ctx, this.state); - this.enterRule(localctx, 74, CashScriptParser.RULE_expressionList); + this.enterRule(localctx, 76, CashScriptParser.RULE_expressionList); let _la: number; try { let _alt: number; this.enterOuterAlt(localctx, 1); { - this.state = 375; + this.state = 394; this.match(CashScriptParser.T__13); - this.state = 387; + this.state = 406; this._errHandler.sync(this); _la = this._input.LA(1); if (_la===5 || _la===14 || ((((_la - 33)) & ~0x1F) === 0 && ((1 << (_la - 33)) & 786955) !== 0) || ((((_la - 67)) & ~0x1F) === 0 && ((1 << (_la - 67)) & 61029) !== 0)) { { - this.state = 376; + this.state = 395; this.expression(0); - this.state = 381; + this.state = 400; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 32, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 35, this._ctx); while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { if (_alt === 1) { { { - this.state = 377; + this.state = 396; this.match(CashScriptParser.T__14); - this.state = 378; + this.state = 397; this.expression(0); } } } - this.state = 383; + this.state = 402; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 32, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 35, this._ctx); } - this.state = 385; + this.state = 404; this._errHandler.sync(this); _la = this._input.LA(1); if (_la===15) { { - this.state = 384; + this.state = 403; this.match(CashScriptParser.T__14); } } @@ -1952,7 +2037,7 @@ export default class CashScriptParser extends Parser { } } - this.state = 389; + this.state = 408; this.match(CashScriptParser.T__15); } } @@ -1983,27 +2068,27 @@ export default class CashScriptParser extends Parser { let _parentState: number = this.state; let localctx: ExpressionContext = new ExpressionContext(this, this._ctx, _parentState); let _prevctx: ExpressionContext = localctx; - let _startState: number = 76; - this.enterRecursionRule(localctx, 76, CashScriptParser.RULE_expression, _p); + let _startState: number = 78; + this.enterRecursionRule(localctx, 78, CashScriptParser.RULE_expression, _p); let _la: number; try { let _alt: number; this.enterOuterAlt(localctx, 1); { - this.state = 440; + this.state = 459; this._errHandler.sync(this); - switch ( this._interp.adaptivePredict(this._input, 39, this._ctx) ) { + switch ( this._interp.adaptivePredict(this._input, 42, this._ctx) ) { case 1: { localctx = new ParenthesisedContext(this, localctx); this._ctx = localctx; _prevctx = localctx; - this.state = 392; + this.state = 411; this.match(CashScriptParser.T__13); - this.state = 393; + this.state = 412; this.expression(0); - this.state = 394; + this.state = 413; this.match(CashScriptParser.T__15); } break; @@ -2012,23 +2097,23 @@ export default class CashScriptParser extends Parser { localctx = new CastContext(this, localctx); this._ctx = localctx; _prevctx = localctx; - this.state = 396; + this.state = 415; this.typeCast(); - this.state = 397; + this.state = 416; this.match(CashScriptParser.T__13); - this.state = 398; + this.state = 417; (localctx as CastContext)._castable = this.expression(0); - this.state = 400; + this.state = 419; this._errHandler.sync(this); _la = this._input.LA(1); if (_la===15) { { - this.state = 399; + this.state = 418; this.match(CashScriptParser.T__14); } } - this.state = 402; + this.state = 421; this.match(CashScriptParser.T__15); } break; @@ -2037,7 +2122,7 @@ export default class CashScriptParser extends Parser { localctx = new FunctionCallExpressionContext(this, localctx); this._ctx = localctx; _prevctx = localctx; - this.state = 404; + this.state = 423; this.functionCall(); } break; @@ -2046,11 +2131,11 @@ export default class CashScriptParser extends Parser { localctx = new InstantiationContext(this, localctx); this._ctx = localctx; _prevctx = localctx; - this.state = 405; + this.state = 424; this.match(CashScriptParser.T__32); - this.state = 406; + this.state = 425; this.match(CashScriptParser.Identifier); - this.state = 407; + this.state = 426; this.expressionList(); } break; @@ -2059,15 +2144,15 @@ export default class CashScriptParser extends Parser { localctx = new UnaryIntrospectionOpContext(this, localctx); this._ctx = localctx; _prevctx = localctx; - this.state = 408; + this.state = 427; (localctx as UnaryIntrospectionOpContext)._scope = this.match(CashScriptParser.T__35); - this.state = 409; + this.state = 428; this.match(CashScriptParser.T__33); - this.state = 410; + this.state = 429; this.expression(0); - this.state = 411; + this.state = 430; this.match(CashScriptParser.T__34); - this.state = 412; + this.state = 431; (localctx as UnaryIntrospectionOpContext)._op = this._input.LT(1); _la = this._input.LA(1); if(!(((((_la - 37)) & ~0x1F) === 0 && ((1 << (_la - 37)) & 31) !== 0))) { @@ -2084,15 +2169,15 @@ export default class CashScriptParser extends Parser { localctx = new UnaryIntrospectionOpContext(this, localctx); this._ctx = localctx; _prevctx = localctx; - this.state = 414; + this.state = 433; (localctx as UnaryIntrospectionOpContext)._scope = this.match(CashScriptParser.T__41); - this.state = 415; + this.state = 434; this.match(CashScriptParser.T__33); - this.state = 416; + this.state = 435; this.expression(0); - this.state = 417; + this.state = 436; this.match(CashScriptParser.T__34); - this.state = 418; + this.state = 437; (localctx as UnaryIntrospectionOpContext)._op = this._input.LT(1); _la = this._input.LA(1); if(!(((((_la - 37)) & ~0x1F) === 0 && ((1 << (_la - 37)) & 991) !== 0))) { @@ -2109,7 +2194,7 @@ export default class CashScriptParser extends Parser { localctx = new UnaryOpContext(this, localctx); this._ctx = localctx; _prevctx = localctx; - this.state = 420; + this.state = 439; (localctx as UnaryOpContext)._op = this._input.LT(1); _la = this._input.LA(1); if(!(_la===5 || _la===51 || _la===52)) { @@ -2119,7 +2204,7 @@ export default class CashScriptParser extends Parser { this._errHandler.reportMatch(this); this.consume(); } - this.state = 421; + this.state = 440; this.expression(15); } break; @@ -2128,39 +2213,39 @@ export default class CashScriptParser extends Parser { localctx = new ArrayContext(this, localctx); this._ctx = localctx; _prevctx = localctx; - this.state = 422; + this.state = 441; this.match(CashScriptParser.T__33); - this.state = 434; + this.state = 453; this._errHandler.sync(this); _la = this._input.LA(1); if (_la===5 || _la===14 || ((((_la - 33)) & ~0x1F) === 0 && ((1 << (_la - 33)) & 786955) !== 0) || ((((_la - 67)) & ~0x1F) === 0 && ((1 << (_la - 67)) & 61029) !== 0)) { { - this.state = 423; + this.state = 442; this.expression(0); - this.state = 428; + this.state = 447; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 36, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 39, this._ctx); while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { if (_alt === 1) { { { - this.state = 424; + this.state = 443; this.match(CashScriptParser.T__14); - this.state = 425; + this.state = 444; this.expression(0); } } } - this.state = 430; + this.state = 449; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 36, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 39, this._ctx); } - this.state = 432; + this.state = 451; this._errHandler.sync(this); _la = this._input.LA(1); if (_la===15) { { - this.state = 431; + this.state = 450; this.match(CashScriptParser.T__14); } } @@ -2168,7 +2253,7 @@ export default class CashScriptParser extends Parser { } } - this.state = 436; + this.state = 455; this.match(CashScriptParser.T__34); } break; @@ -2177,7 +2262,7 @@ export default class CashScriptParser extends Parser { localctx = new NullaryOpContext(this, localctx); this._ctx = localctx; _prevctx = localctx; - this.state = 437; + this.state = 456; this.match(CashScriptParser.NullaryOp); } break; @@ -2186,7 +2271,7 @@ export default class CashScriptParser extends Parser { localctx = new IdentifierContext(this, localctx); this._ctx = localctx; _prevctx = localctx; - this.state = 438; + this.state = 457; this.match(CashScriptParser.Identifier); } break; @@ -2195,15 +2280,15 @@ export default class CashScriptParser extends Parser { localctx = new LiteralExpressionContext(this, localctx); this._ctx = localctx; _prevctx = localctx; - this.state = 439; + this.state = 458; this.literal(); } break; } this._ctx.stop = this._input.LT(-1); - this.state = 494; + this.state = 513; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 41, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 44, this._ctx); while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { if (_alt === 1) { if (this._parseListeners != null) { @@ -2211,19 +2296,19 @@ export default class CashScriptParser extends Parser { } _prevctx = localctx; { - this.state = 492; + this.state = 511; this._errHandler.sync(this); - switch ( this._interp.adaptivePredict(this._input, 40, this._ctx) ) { + switch ( this._interp.adaptivePredict(this._input, 43, this._ctx) ) { case 1: { localctx = new BinaryOpContext(this, new ExpressionContext(this, _parentctx, _parentState)); (localctx as BinaryOpContext)._left = _prevctx; this.pushNewRecursionContext(localctx, _startState, CashScriptParser.RULE_expression); - this.state = 442; + this.state = 461; if (!(this.precpred(this._ctx, 14))) { throw this.createFailedPredicateException("this.precpred(this._ctx, 14)"); } - this.state = 443; + this.state = 462; (localctx as BinaryOpContext)._op = this._input.LT(1); _la = this._input.LA(1); if(!(((((_la - 53)) & ~0x1F) === 0 && ((1 << (_la - 53)) & 7) !== 0))) { @@ -2233,7 +2318,7 @@ export default class CashScriptParser extends Parser { this._errHandler.reportMatch(this); this.consume(); } - this.state = 444; + this.state = 463; (localctx as BinaryOpContext)._right = this.expression(15); } break; @@ -2242,11 +2327,11 @@ export default class CashScriptParser extends Parser { localctx = new BinaryOpContext(this, new ExpressionContext(this, _parentctx, _parentState)); (localctx as BinaryOpContext)._left = _prevctx; this.pushNewRecursionContext(localctx, _startState, CashScriptParser.RULE_expression); - this.state = 445; + this.state = 464; if (!(this.precpred(this._ctx, 13))) { throw this.createFailedPredicateException("this.precpred(this._ctx, 13)"); } - this.state = 446; + this.state = 465; (localctx as BinaryOpContext)._op = this._input.LT(1); _la = this._input.LA(1); if(!(_la===52 || _la===56)) { @@ -2256,7 +2341,7 @@ export default class CashScriptParser extends Parser { this._errHandler.reportMatch(this); this.consume(); } - this.state = 447; + this.state = 466; (localctx as BinaryOpContext)._right = this.expression(14); } break; @@ -2265,11 +2350,11 @@ export default class CashScriptParser extends Parser { localctx = new BinaryOpContext(this, new ExpressionContext(this, _parentctx, _parentState)); (localctx as BinaryOpContext)._left = _prevctx; this.pushNewRecursionContext(localctx, _startState, CashScriptParser.RULE_expression); - this.state = 448; + this.state = 467; if (!(this.precpred(this._ctx, 12))) { throw this.createFailedPredicateException("this.precpred(this._ctx, 12)"); } - this.state = 449; + this.state = 468; (localctx as BinaryOpContext)._op = this._input.LT(1); _la = this._input.LA(1); if(!(_la===57 || _la===58)) { @@ -2279,7 +2364,7 @@ export default class CashScriptParser extends Parser { this._errHandler.reportMatch(this); this.consume(); } - this.state = 450; + this.state = 469; (localctx as BinaryOpContext)._right = this.expression(13); } break; @@ -2288,11 +2373,11 @@ export default class CashScriptParser extends Parser { localctx = new BinaryOpContext(this, new ExpressionContext(this, _parentctx, _parentState)); (localctx as BinaryOpContext)._left = _prevctx; this.pushNewRecursionContext(localctx, _startState, CashScriptParser.RULE_expression); - this.state = 451; + this.state = 470; if (!(this.precpred(this._ctx, 11))) { throw this.createFailedPredicateException("this.precpred(this._ctx, 11)"); } - this.state = 452; + this.state = 471; (localctx as BinaryOpContext)._op = this._input.LT(1); _la = this._input.LA(1); if(!((((_la) & ~0x1F) === 0 && ((1 << _la) & 960) !== 0))) { @@ -2302,7 +2387,7 @@ export default class CashScriptParser extends Parser { this._errHandler.reportMatch(this); this.consume(); } - this.state = 453; + this.state = 472; (localctx as BinaryOpContext)._right = this.expression(12); } break; @@ -2311,11 +2396,11 @@ export default class CashScriptParser extends Parser { localctx = new BinaryOpContext(this, new ExpressionContext(this, _parentctx, _parentState)); (localctx as BinaryOpContext)._left = _prevctx; this.pushNewRecursionContext(localctx, _startState, CashScriptParser.RULE_expression); - this.state = 454; + this.state = 473; if (!(this.precpred(this._ctx, 10))) { throw this.createFailedPredicateException("this.precpred(this._ctx, 10)"); } - this.state = 455; + this.state = 474; (localctx as BinaryOpContext)._op = this._input.LT(1); _la = this._input.LA(1); if(!(_la===59 || _la===60)) { @@ -2325,7 +2410,7 @@ export default class CashScriptParser extends Parser { this._errHandler.reportMatch(this); this.consume(); } - this.state = 456; + this.state = 475; (localctx as BinaryOpContext)._right = this.expression(11); } break; @@ -2334,13 +2419,13 @@ export default class CashScriptParser extends Parser { localctx = new BinaryOpContext(this, new ExpressionContext(this, _parentctx, _parentState)); (localctx as BinaryOpContext)._left = _prevctx; this.pushNewRecursionContext(localctx, _startState, CashScriptParser.RULE_expression); - this.state = 457; + this.state = 476; if (!(this.precpred(this._ctx, 9))) { throw this.createFailedPredicateException("this.precpred(this._ctx, 9)"); } - this.state = 458; + this.state = 477; (localctx as BinaryOpContext)._op = this.match(CashScriptParser.T__60); - this.state = 459; + this.state = 478; (localctx as BinaryOpContext)._right = this.expression(10); } break; @@ -2349,13 +2434,13 @@ export default class CashScriptParser extends Parser { localctx = new BinaryOpContext(this, new ExpressionContext(this, _parentctx, _parentState)); (localctx as BinaryOpContext)._left = _prevctx; this.pushNewRecursionContext(localctx, _startState, CashScriptParser.RULE_expression); - this.state = 460; + this.state = 479; if (!(this.precpred(this._ctx, 8))) { throw this.createFailedPredicateException("this.precpred(this._ctx, 8)"); } - this.state = 461; + this.state = 480; (localctx as BinaryOpContext)._op = this.match(CashScriptParser.T__3); - this.state = 462; + this.state = 481; (localctx as BinaryOpContext)._right = this.expression(9); } break; @@ -2364,13 +2449,13 @@ export default class CashScriptParser extends Parser { localctx = new BinaryOpContext(this, new ExpressionContext(this, _parentctx, _parentState)); (localctx as BinaryOpContext)._left = _prevctx; this.pushNewRecursionContext(localctx, _startState, CashScriptParser.RULE_expression); - this.state = 463; + this.state = 482; if (!(this.precpred(this._ctx, 7))) { throw this.createFailedPredicateException("this.precpred(this._ctx, 7)"); } - this.state = 464; + this.state = 483; (localctx as BinaryOpContext)._op = this.match(CashScriptParser.T__61); - this.state = 465; + this.state = 484; (localctx as BinaryOpContext)._right = this.expression(8); } break; @@ -2379,13 +2464,13 @@ export default class CashScriptParser extends Parser { localctx = new BinaryOpContext(this, new ExpressionContext(this, _parentctx, _parentState)); (localctx as BinaryOpContext)._left = _prevctx; this.pushNewRecursionContext(localctx, _startState, CashScriptParser.RULE_expression); - this.state = 466; + this.state = 485; if (!(this.precpred(this._ctx, 6))) { throw this.createFailedPredicateException("this.precpred(this._ctx, 6)"); } - this.state = 467; + this.state = 486; (localctx as BinaryOpContext)._op = this.match(CashScriptParser.T__62); - this.state = 468; + this.state = 487; (localctx as BinaryOpContext)._right = this.expression(7); } break; @@ -2394,13 +2479,13 @@ export default class CashScriptParser extends Parser { localctx = new BinaryOpContext(this, new ExpressionContext(this, _parentctx, _parentState)); (localctx as BinaryOpContext)._left = _prevctx; this.pushNewRecursionContext(localctx, _startState, CashScriptParser.RULE_expression); - this.state = 469; + this.state = 488; if (!(this.precpred(this._ctx, 5))) { throw this.createFailedPredicateException("this.precpred(this._ctx, 5)"); } - this.state = 470; + this.state = 489; (localctx as BinaryOpContext)._op = this.match(CashScriptParser.T__63); - this.state = 471; + this.state = 490; (localctx as BinaryOpContext)._right = this.expression(6); } break; @@ -2408,15 +2493,15 @@ export default class CashScriptParser extends Parser { { localctx = new TupleIndexOpContext(this, new ExpressionContext(this, _parentctx, _parentState)); this.pushNewRecursionContext(localctx, _startState, CashScriptParser.RULE_expression); - this.state = 472; + this.state = 491; if (!(this.precpred(this._ctx, 21))) { throw this.createFailedPredicateException("this.precpred(this._ctx, 21)"); } - this.state = 473; + this.state = 492; this.match(CashScriptParser.T__33); - this.state = 474; + this.state = 493; (localctx as TupleIndexOpContext)._index = this.match(CashScriptParser.NumberLiteral); - this.state = 475; + this.state = 494; this.match(CashScriptParser.T__34); } break; @@ -2424,11 +2509,11 @@ export default class CashScriptParser extends Parser { { localctx = new UnaryOpContext(this, new ExpressionContext(this, _parentctx, _parentState)); this.pushNewRecursionContext(localctx, _startState, CashScriptParser.RULE_expression); - this.state = 476; + this.state = 495; if (!(this.precpred(this._ctx, 18))) { throw this.createFailedPredicateException("this.precpred(this._ctx, 18)"); } - this.state = 477; + this.state = 496; (localctx as UnaryOpContext)._op = this._input.LT(1); _la = this._input.LA(1); if(!(_la===47 || _la===48)) { @@ -2445,17 +2530,17 @@ export default class CashScriptParser extends Parser { localctx = new BinaryOpContext(this, new ExpressionContext(this, _parentctx, _parentState)); (localctx as BinaryOpContext)._left = _prevctx; this.pushNewRecursionContext(localctx, _startState, CashScriptParser.RULE_expression); - this.state = 478; + this.state = 497; if (!(this.precpred(this._ctx, 17))) { throw this.createFailedPredicateException("this.precpred(this._ctx, 17)"); } - this.state = 479; + this.state = 498; (localctx as BinaryOpContext)._op = this.match(CashScriptParser.T__48); - this.state = 480; + this.state = 499; this.match(CashScriptParser.T__13); - this.state = 481; + this.state = 500; (localctx as BinaryOpContext)._right = this.expression(0); - this.state = 482; + this.state = 501; this.match(CashScriptParser.T__15); } break; @@ -2464,30 +2549,30 @@ export default class CashScriptParser extends Parser { localctx = new SliceContext(this, new ExpressionContext(this, _parentctx, _parentState)); (localctx as SliceContext)._element = _prevctx; this.pushNewRecursionContext(localctx, _startState, CashScriptParser.RULE_expression); - this.state = 484; + this.state = 503; if (!(this.precpred(this._ctx, 16))) { throw this.createFailedPredicateException("this.precpred(this._ctx, 16)"); } - this.state = 485; + this.state = 504; this.match(CashScriptParser.T__49); - this.state = 486; + this.state = 505; this.match(CashScriptParser.T__13); - this.state = 487; + this.state = 506; (localctx as SliceContext)._start = this.expression(0); - this.state = 488; + this.state = 507; this.match(CashScriptParser.T__14); - this.state = 489; + this.state = 508; (localctx as SliceContext)._end = this.expression(0); - this.state = 490; + this.state = 509; this.match(CashScriptParser.T__15); } break; } } } - this.state = 496; + this.state = 515; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 41, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 44, this._ctx); } } } @@ -2508,12 +2593,12 @@ export default class CashScriptParser extends Parser { // @RuleVersion(0) public modifier(): ModifierContext { let localctx: ModifierContext = new ModifierContext(this, this._ctx, this.state); - this.enterRule(localctx, 78, CashScriptParser.RULE_modifier); + this.enterRule(localctx, 80, CashScriptParser.RULE_modifier); let _la: number; try { this.enterOuterAlt(localctx, 1); { - this.state = 497; + this.state = 516; _la = this._input.LA(1); if(!(_la===17 || _la===65)) { this._errHandler.recoverInline(this); @@ -2541,43 +2626,43 @@ export default class CashScriptParser extends Parser { // @RuleVersion(0) public literal(): LiteralContext { let localctx: LiteralContext = new LiteralContext(this, this._ctx, this.state); - this.enterRule(localctx, 80, CashScriptParser.RULE_literal); + this.enterRule(localctx, 82, CashScriptParser.RULE_literal); try { - this.state = 504; + this.state = 523; this._errHandler.sync(this); switch (this._input.LA(1)) { case 67: this.enterOuterAlt(localctx, 1); { - this.state = 499; + this.state = 518; this.match(CashScriptParser.BooleanLiteral); } break; case 69: this.enterOuterAlt(localctx, 2); { - this.state = 500; + this.state = 519; this.numberLiteral(); } break; case 76: this.enterOuterAlt(localctx, 3); { - this.state = 501; + this.state = 520; this.match(CashScriptParser.StringLiteral); } break; case 77: this.enterOuterAlt(localctx, 4); { - this.state = 502; + this.state = 521; this.match(CashScriptParser.DateLiteral); } break; case 78: this.enterOuterAlt(localctx, 5); { - this.state = 503; + this.state = 522; this.match(CashScriptParser.HexLiteral); } break; @@ -2602,18 +2687,18 @@ export default class CashScriptParser extends Parser { // @RuleVersion(0) public numberLiteral(): NumberLiteralContext { let localctx: NumberLiteralContext = new NumberLiteralContext(this, this._ctx, this.state); - this.enterRule(localctx, 82, CashScriptParser.RULE_numberLiteral); + this.enterRule(localctx, 84, CashScriptParser.RULE_numberLiteral); try { this.enterOuterAlt(localctx, 1); { - this.state = 506; + this.state = 525; this.match(CashScriptParser.NumberLiteral); - this.state = 508; + this.state = 527; this._errHandler.sync(this); - switch ( this._interp.adaptivePredict(this._input, 43, this._ctx) ) { + switch ( this._interp.adaptivePredict(this._input, 46, this._ctx) ) { case 1: { - this.state = 507; + this.state = 526; this.match(CashScriptParser.NumberUnit); } break; @@ -2637,12 +2722,12 @@ export default class CashScriptParser extends Parser { // @RuleVersion(0) public typeName(): TypeNameContext { let localctx: TypeNameContext = new TypeNameContext(this, this._ctx, this.state); - this.enterRule(localctx, 84, CashScriptParser.RULE_typeName); + this.enterRule(localctx, 86, CashScriptParser.RULE_typeName); let _la: number; try { this.enterOuterAlt(localctx, 1); { - this.state = 510; + this.state = 529; _la = this._input.LA(1); if(!(((((_la - 72)) & ~0x1F) === 0 && ((1 << (_la - 72)) & 7) !== 0))) { this._errHandler.recoverInline(this); @@ -2670,12 +2755,12 @@ export default class CashScriptParser extends Parser { // @RuleVersion(0) public typeCast(): TypeCastContext { let localctx: TypeCastContext = new TypeCastContext(this, this._ctx, this.state); - this.enterRule(localctx, 86, CashScriptParser.RULE_typeCast); + this.enterRule(localctx, 88, CashScriptParser.RULE_typeCast); let _la: number; try { this.enterOuterAlt(localctx, 1); { - this.state = 512; + this.state = 531; _la = this._input.LA(1); if(!(((((_la - 72)) & ~0x1F) === 0 && ((1 << (_la - 72)) & 259) !== 0))) { this._errHandler.recoverInline(this); @@ -2703,7 +2788,7 @@ export default class CashScriptParser extends Parser { public sempred(localctx: RuleContext, ruleIndex: number, predIndex: number): boolean { switch (ruleIndex) { - case 38: + case 39: return this.expression_sempred(localctx as ExpressionContext, predIndex); } return true; @@ -2742,177 +2827,183 @@ export default class CashScriptParser extends Parser { return true; } - public static readonly _serializedATN: number[] = [4,1,85,515,2,0,7,0,2, + public static readonly _serializedATN: number[] = [4,1,85,534,2,0,7,0,2, 1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7,5,2,6,7,6,2,7,7,7,2,8,7,8,2,9,7,9,2, 10,7,10,2,11,7,11,2,12,7,12,2,13,7,13,2,14,7,14,2,15,7,15,2,16,7,16,2,17, 7,17,2,18,7,18,2,19,7,19,2,20,7,20,2,21,7,21,2,22,7,22,2,23,7,23,2,24,7, 24,2,25,7,25,2,26,7,26,2,27,7,27,2,28,7,28,2,29,7,29,2,30,7,30,2,31,7,31, 2,32,7,32,2,33,7,33,2,34,7,34,2,35,7,35,2,36,7,36,2,37,7,37,2,38,7,38,2, - 39,7,39,2,40,7,40,2,41,7,41,2,42,7,42,2,43,7,43,1,0,5,0,90,8,0,10,0,12, - 0,93,9,0,1,0,5,0,96,8,0,10,0,12,0,99,9,0,1,0,5,0,102,8,0,10,0,12,0,105, - 9,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,2,1,2,1,3,1,3,3,3,118,8,3,1,4,3,4,121, - 8,4,1,4,1,4,1,5,1,5,1,6,1,6,1,6,1,6,1,7,1,7,1,7,3,7,134,8,7,1,8,1,8,1,8, - 1,8,1,8,1,8,1,8,1,8,5,8,144,8,8,10,8,12,8,147,9,8,1,8,1,8,3,8,151,8,8,1, - 8,1,8,1,9,1,9,1,9,1,9,1,9,1,9,1,9,1,10,1,10,1,10,1,10,1,10,5,10,167,8,10, - 10,10,12,10,170,9,10,1,10,1,10,1,11,1,11,1,11,1,11,1,11,1,12,1,12,5,12, - 181,8,12,10,12,12,12,184,9,12,1,12,1,12,1,13,1,13,1,13,1,13,5,13,192,8, - 13,10,13,12,13,195,9,13,1,13,3,13,198,8,13,3,13,200,8,13,1,13,1,13,1,14, - 1,14,5,14,206,8,14,10,14,12,14,209,9,14,1,14,1,14,1,15,1,15,5,15,215,8, - 15,10,15,12,15,218,9,15,1,15,1,15,3,15,222,8,15,1,16,1,16,1,16,1,16,3,16, - 228,8,16,1,17,1,17,1,17,1,17,1,17,1,17,1,17,1,17,3,17,238,8,17,1,18,1,18, - 1,19,1,19,1,19,1,19,5,19,246,8,19,10,19,12,19,249,9,19,1,20,1,20,3,20,253, - 8,20,1,21,1,21,5,21,257,8,21,10,21,12,21,260,9,21,1,21,1,21,1,21,1,21,1, - 22,1,22,1,22,1,22,1,22,1,22,4,22,272,8,22,11,22,12,22,273,1,22,1,22,1,22, - 1,23,1,23,1,23,1,23,1,23,3,23,284,8,23,1,24,1,24,1,24,1,24,1,24,1,24,1, - 24,3,24,293,8,24,1,24,1,24,1,25,1,25,1,25,1,25,1,25,3,25,302,8,25,1,25, - 1,25,1,26,1,26,1,26,1,27,1,27,1,27,1,27,1,27,1,27,1,27,3,27,316,8,27,1, - 28,1,28,1,28,3,28,321,8,28,1,29,1,29,1,29,1,29,1,29,1,29,1,29,1,29,1,30, - 1,30,1,30,1,30,1,30,1,30,1,31,1,31,1,31,1,31,1,31,1,31,1,31,1,31,1,31,1, - 31,1,32,1,32,3,32,349,8,32,1,33,1,33,1,34,1,34,3,34,355,8,34,1,35,1,35, - 1,35,1,35,5,35,361,8,35,10,35,12,35,364,9,35,1,35,3,35,367,8,35,3,35,369, - 8,35,1,35,1,35,1,36,1,36,1,36,1,37,1,37,1,37,1,37,5,37,380,8,37,10,37,12, - 37,383,9,37,1,37,3,37,386,8,37,3,37,388,8,37,1,37,1,37,1,38,1,38,1,38,1, - 38,1,38,1,38,1,38,1,38,1,38,3,38,401,8,38,1,38,1,38,1,38,1,38,1,38,1,38, - 1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1, - 38,1,38,1,38,1,38,5,38,427,8,38,10,38,12,38,430,9,38,1,38,3,38,433,8,38, - 3,38,435,8,38,1,38,1,38,1,38,1,38,3,38,441,8,38,1,38,1,38,1,38,1,38,1,38, - 1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1, - 38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38, - 1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1, - 38,1,38,5,38,493,8,38,10,38,12,38,496,9,38,1,39,1,39,1,40,1,40,1,40,1,40, - 1,40,3,40,505,8,40,1,41,1,41,3,41,509,8,41,1,42,1,42,1,43,1,43,1,43,0,1, - 76,44,0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46, - 48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,0,15,1,0,4, - 10,2,0,10,10,22,23,1,0,24,25,1,0,37,41,2,0,37,41,43,46,2,0,5,5,51,52,1, - 0,53,55,2,0,52,52,56,56,1,0,57,58,1,0,6,9,1,0,59,60,1,0,47,48,2,0,17,17, - 65,65,1,0,72,74,2,0,72,73,80,80,546,0,91,1,0,0,0,2,108,1,0,0,0,4,113,1, - 0,0,0,6,115,1,0,0,0,8,120,1,0,0,0,10,124,1,0,0,0,12,126,1,0,0,0,14,133, - 1,0,0,0,16,135,1,0,0,0,18,154,1,0,0,0,20,161,1,0,0,0,22,173,1,0,0,0,24, - 178,1,0,0,0,26,187,1,0,0,0,28,203,1,0,0,0,30,221,1,0,0,0,32,227,1,0,0,0, - 34,237,1,0,0,0,36,239,1,0,0,0,38,241,1,0,0,0,40,252,1,0,0,0,42,254,1,0, - 0,0,44,265,1,0,0,0,46,283,1,0,0,0,48,285,1,0,0,0,50,296,1,0,0,0,52,305, - 1,0,0,0,54,308,1,0,0,0,56,320,1,0,0,0,58,322,1,0,0,0,60,330,1,0,0,0,62, - 336,1,0,0,0,64,348,1,0,0,0,66,350,1,0,0,0,68,354,1,0,0,0,70,356,1,0,0,0, - 72,372,1,0,0,0,74,375,1,0,0,0,76,440,1,0,0,0,78,497,1,0,0,0,80,504,1,0, - 0,0,82,506,1,0,0,0,84,510,1,0,0,0,86,512,1,0,0,0,88,90,3,2,1,0,89,88,1, - 0,0,0,90,93,1,0,0,0,91,89,1,0,0,0,91,92,1,0,0,0,92,97,1,0,0,0,93,91,1,0, - 0,0,94,96,3,12,6,0,95,94,1,0,0,0,96,99,1,0,0,0,97,95,1,0,0,0,97,98,1,0, - 0,0,98,103,1,0,0,0,99,97,1,0,0,0,100,102,3,14,7,0,101,100,1,0,0,0,102,105, - 1,0,0,0,103,101,1,0,0,0,103,104,1,0,0,0,104,106,1,0,0,0,105,103,1,0,0,0, - 106,107,5,0,0,1,107,1,1,0,0,0,108,109,5,1,0,0,109,110,3,4,2,0,110,111,3, - 6,3,0,111,112,5,2,0,0,112,3,1,0,0,0,113,114,5,3,0,0,114,5,1,0,0,0,115,117, - 3,8,4,0,116,118,3,8,4,0,117,116,1,0,0,0,117,118,1,0,0,0,118,7,1,0,0,0,119, - 121,3,10,5,0,120,119,1,0,0,0,120,121,1,0,0,0,121,122,1,0,0,0,122,123,5, - 66,0,0,123,9,1,0,0,0,124,125,7,0,0,0,125,11,1,0,0,0,126,127,5,11,0,0,127, - 128,5,76,0,0,128,129,5,2,0,0,129,13,1,0,0,0,130,134,3,16,8,0,131,134,3, - 18,9,0,132,134,3,20,10,0,133,130,1,0,0,0,133,131,1,0,0,0,133,132,1,0,0, - 0,134,15,1,0,0,0,135,136,5,12,0,0,136,137,5,82,0,0,137,150,3,26,13,0,138, - 139,5,13,0,0,139,140,5,14,0,0,140,145,3,84,42,0,141,142,5,15,0,0,142,144, - 3,84,42,0,143,141,1,0,0,0,144,147,1,0,0,0,145,143,1,0,0,0,145,146,1,0,0, - 0,146,148,1,0,0,0,147,145,1,0,0,0,148,149,5,16,0,0,149,151,1,0,0,0,150, - 138,1,0,0,0,150,151,1,0,0,0,151,152,1,0,0,0,152,153,3,24,12,0,153,17,1, - 0,0,0,154,155,3,84,42,0,155,156,5,17,0,0,156,157,5,82,0,0,157,158,5,10, - 0,0,158,159,3,80,40,0,159,160,5,2,0,0,160,19,1,0,0,0,161,162,5,18,0,0,162, - 163,5,82,0,0,163,164,3,26,13,0,164,168,5,19,0,0,165,167,3,22,11,0,166,165, - 1,0,0,0,167,170,1,0,0,0,168,166,1,0,0,0,168,169,1,0,0,0,169,171,1,0,0,0, - 170,168,1,0,0,0,171,172,5,20,0,0,172,21,1,0,0,0,173,174,5,12,0,0,174,175, - 5,82,0,0,175,176,3,26,13,0,176,177,3,24,12,0,177,23,1,0,0,0,178,182,5,19, - 0,0,179,181,3,32,16,0,180,179,1,0,0,0,181,184,1,0,0,0,182,180,1,0,0,0,182, - 183,1,0,0,0,183,185,1,0,0,0,184,182,1,0,0,0,185,186,5,20,0,0,186,25,1,0, - 0,0,187,199,5,14,0,0,188,193,3,28,14,0,189,190,5,15,0,0,190,192,3,28,14, - 0,191,189,1,0,0,0,192,195,1,0,0,0,193,191,1,0,0,0,193,194,1,0,0,0,194,197, - 1,0,0,0,195,193,1,0,0,0,196,198,5,15,0,0,197,196,1,0,0,0,197,198,1,0,0, - 0,198,200,1,0,0,0,199,188,1,0,0,0,199,200,1,0,0,0,200,201,1,0,0,0,201,202, - 5,16,0,0,202,27,1,0,0,0,203,207,3,84,42,0,204,206,3,78,39,0,205,204,1,0, - 0,0,206,209,1,0,0,0,207,205,1,0,0,0,207,208,1,0,0,0,208,210,1,0,0,0,209, - 207,1,0,0,0,210,211,5,82,0,0,211,29,1,0,0,0,212,216,5,19,0,0,213,215,3, - 32,16,0,214,213,1,0,0,0,215,218,1,0,0,0,216,214,1,0,0,0,216,217,1,0,0,0, - 217,219,1,0,0,0,218,216,1,0,0,0,219,222,5,20,0,0,220,222,3,32,16,0,221, - 212,1,0,0,0,221,220,1,0,0,0,222,31,1,0,0,0,223,228,3,40,20,0,224,225,3, - 34,17,0,225,226,5,2,0,0,226,228,1,0,0,0,227,223,1,0,0,0,227,224,1,0,0,0, - 228,33,1,0,0,0,229,238,3,42,21,0,230,238,3,44,22,0,231,238,3,46,23,0,232, - 238,3,48,24,0,233,238,3,50,25,0,234,238,3,36,18,0,235,238,3,52,26,0,236, - 238,3,38,19,0,237,229,1,0,0,0,237,230,1,0,0,0,237,231,1,0,0,0,237,232,1, - 0,0,0,237,233,1,0,0,0,237,234,1,0,0,0,237,235,1,0,0,0,237,236,1,0,0,0,238, - 35,1,0,0,0,239,240,3,72,36,0,240,37,1,0,0,0,241,242,5,21,0,0,242,247,3, - 76,38,0,243,244,5,15,0,0,244,246,3,76,38,0,245,243,1,0,0,0,246,249,1,0, - 0,0,247,245,1,0,0,0,247,248,1,0,0,0,248,39,1,0,0,0,249,247,1,0,0,0,250, - 253,3,54,27,0,251,253,3,56,28,0,252,250,1,0,0,0,252,251,1,0,0,0,253,41, - 1,0,0,0,254,258,3,84,42,0,255,257,3,78,39,0,256,255,1,0,0,0,257,260,1,0, - 0,0,258,256,1,0,0,0,258,259,1,0,0,0,259,261,1,0,0,0,260,258,1,0,0,0,261, - 262,5,82,0,0,262,263,5,10,0,0,263,264,3,76,38,0,264,43,1,0,0,0,265,266, - 3,84,42,0,266,271,5,82,0,0,267,268,5,15,0,0,268,269,3,84,42,0,269,270,5, - 82,0,0,270,272,1,0,0,0,271,267,1,0,0,0,272,273,1,0,0,0,273,271,1,0,0,0, - 273,274,1,0,0,0,274,275,1,0,0,0,275,276,5,10,0,0,276,277,3,76,38,0,277, - 45,1,0,0,0,278,279,5,82,0,0,279,280,7,1,0,0,280,284,3,76,38,0,281,282,5, - 82,0,0,282,284,7,2,0,0,283,278,1,0,0,0,283,281,1,0,0,0,284,47,1,0,0,0,285, - 286,5,26,0,0,286,287,5,14,0,0,287,288,5,79,0,0,288,289,5,6,0,0,289,292, - 3,76,38,0,290,291,5,15,0,0,291,293,3,66,33,0,292,290,1,0,0,0,292,293,1, - 0,0,0,293,294,1,0,0,0,294,295,5,16,0,0,295,49,1,0,0,0,296,297,5,26,0,0, - 297,298,5,14,0,0,298,301,3,76,38,0,299,300,5,15,0,0,300,302,3,66,33,0,301, - 299,1,0,0,0,301,302,1,0,0,0,302,303,1,0,0,0,303,304,5,16,0,0,304,51,1,0, - 0,0,305,306,5,27,0,0,306,307,3,70,35,0,307,53,1,0,0,0,308,309,5,28,0,0, - 309,310,5,14,0,0,310,311,3,76,38,0,311,312,5,16,0,0,312,315,3,30,15,0,313, - 314,5,29,0,0,314,316,3,30,15,0,315,313,1,0,0,0,315,316,1,0,0,0,316,55,1, - 0,0,0,317,321,3,58,29,0,318,321,3,60,30,0,319,321,3,62,31,0,320,317,1,0, - 0,0,320,318,1,0,0,0,320,319,1,0,0,0,321,57,1,0,0,0,322,323,5,30,0,0,323, - 324,3,30,15,0,324,325,5,31,0,0,325,326,5,14,0,0,326,327,3,76,38,0,327,328, - 5,16,0,0,328,329,5,2,0,0,329,59,1,0,0,0,330,331,5,31,0,0,331,332,5,14,0, - 0,332,333,3,76,38,0,333,334,5,16,0,0,334,335,3,30,15,0,335,61,1,0,0,0,336, - 337,5,32,0,0,337,338,5,14,0,0,338,339,3,64,32,0,339,340,5,2,0,0,340,341, - 3,76,38,0,341,342,5,2,0,0,342,343,3,46,23,0,343,344,5,16,0,0,344,345,3, - 30,15,0,345,63,1,0,0,0,346,349,3,42,21,0,347,349,3,46,23,0,348,346,1,0, - 0,0,348,347,1,0,0,0,349,65,1,0,0,0,350,351,5,76,0,0,351,67,1,0,0,0,352, - 355,5,82,0,0,353,355,3,80,40,0,354,352,1,0,0,0,354,353,1,0,0,0,355,69,1, - 0,0,0,356,368,5,14,0,0,357,362,3,68,34,0,358,359,5,15,0,0,359,361,3,68, - 34,0,360,358,1,0,0,0,361,364,1,0,0,0,362,360,1,0,0,0,362,363,1,0,0,0,363, - 366,1,0,0,0,364,362,1,0,0,0,365,367,5,15,0,0,366,365,1,0,0,0,366,367,1, - 0,0,0,367,369,1,0,0,0,368,357,1,0,0,0,368,369,1,0,0,0,369,370,1,0,0,0,370, - 371,5,16,0,0,371,71,1,0,0,0,372,373,5,82,0,0,373,374,3,74,37,0,374,73,1, - 0,0,0,375,387,5,14,0,0,376,381,3,76,38,0,377,378,5,15,0,0,378,380,3,76, - 38,0,379,377,1,0,0,0,380,383,1,0,0,0,381,379,1,0,0,0,381,382,1,0,0,0,382, - 385,1,0,0,0,383,381,1,0,0,0,384,386,5,15,0,0,385,384,1,0,0,0,385,386,1, - 0,0,0,386,388,1,0,0,0,387,376,1,0,0,0,387,388,1,0,0,0,388,389,1,0,0,0,389, - 390,5,16,0,0,390,75,1,0,0,0,391,392,6,38,-1,0,392,393,5,14,0,0,393,394, - 3,76,38,0,394,395,5,16,0,0,395,441,1,0,0,0,396,397,3,86,43,0,397,398,5, - 14,0,0,398,400,3,76,38,0,399,401,5,15,0,0,400,399,1,0,0,0,400,401,1,0,0, - 0,401,402,1,0,0,0,402,403,5,16,0,0,403,441,1,0,0,0,404,441,3,72,36,0,405, - 406,5,33,0,0,406,407,5,82,0,0,407,441,3,74,37,0,408,409,5,36,0,0,409,410, - 5,34,0,0,410,411,3,76,38,0,411,412,5,35,0,0,412,413,7,3,0,0,413,441,1,0, - 0,0,414,415,5,42,0,0,415,416,5,34,0,0,416,417,3,76,38,0,417,418,5,35,0, - 0,418,419,7,4,0,0,419,441,1,0,0,0,420,421,7,5,0,0,421,441,3,76,38,15,422, - 434,5,34,0,0,423,428,3,76,38,0,424,425,5,15,0,0,425,427,3,76,38,0,426,424, - 1,0,0,0,427,430,1,0,0,0,428,426,1,0,0,0,428,429,1,0,0,0,429,432,1,0,0,0, - 430,428,1,0,0,0,431,433,5,15,0,0,432,431,1,0,0,0,432,433,1,0,0,0,433,435, - 1,0,0,0,434,423,1,0,0,0,434,435,1,0,0,0,435,436,1,0,0,0,436,441,5,35,0, - 0,437,441,5,81,0,0,438,441,5,82,0,0,439,441,3,80,40,0,440,391,1,0,0,0,440, - 396,1,0,0,0,440,404,1,0,0,0,440,405,1,0,0,0,440,408,1,0,0,0,440,414,1,0, - 0,0,440,420,1,0,0,0,440,422,1,0,0,0,440,437,1,0,0,0,440,438,1,0,0,0,440, - 439,1,0,0,0,441,494,1,0,0,0,442,443,10,14,0,0,443,444,7,6,0,0,444,493,3, - 76,38,15,445,446,10,13,0,0,446,447,7,7,0,0,447,493,3,76,38,14,448,449,10, - 12,0,0,449,450,7,8,0,0,450,493,3,76,38,13,451,452,10,11,0,0,452,453,7,9, - 0,0,453,493,3,76,38,12,454,455,10,10,0,0,455,456,7,10,0,0,456,493,3,76, - 38,11,457,458,10,9,0,0,458,459,5,61,0,0,459,493,3,76,38,10,460,461,10,8, - 0,0,461,462,5,4,0,0,462,493,3,76,38,9,463,464,10,7,0,0,464,465,5,62,0,0, - 465,493,3,76,38,8,466,467,10,6,0,0,467,468,5,63,0,0,468,493,3,76,38,7,469, - 470,10,5,0,0,470,471,5,64,0,0,471,493,3,76,38,6,472,473,10,21,0,0,473,474, - 5,34,0,0,474,475,5,69,0,0,475,493,5,35,0,0,476,477,10,18,0,0,477,493,7, - 11,0,0,478,479,10,17,0,0,479,480,5,49,0,0,480,481,5,14,0,0,481,482,3,76, - 38,0,482,483,5,16,0,0,483,493,1,0,0,0,484,485,10,16,0,0,485,486,5,50,0, - 0,486,487,5,14,0,0,487,488,3,76,38,0,488,489,5,15,0,0,489,490,3,76,38,0, - 490,491,5,16,0,0,491,493,1,0,0,0,492,442,1,0,0,0,492,445,1,0,0,0,492,448, - 1,0,0,0,492,451,1,0,0,0,492,454,1,0,0,0,492,457,1,0,0,0,492,460,1,0,0,0, - 492,463,1,0,0,0,492,466,1,0,0,0,492,469,1,0,0,0,492,472,1,0,0,0,492,476, - 1,0,0,0,492,478,1,0,0,0,492,484,1,0,0,0,493,496,1,0,0,0,494,492,1,0,0,0, - 494,495,1,0,0,0,495,77,1,0,0,0,496,494,1,0,0,0,497,498,7,12,0,0,498,79, - 1,0,0,0,499,505,5,67,0,0,500,505,3,82,41,0,501,505,5,76,0,0,502,505,5,77, - 0,0,503,505,5,78,0,0,504,499,1,0,0,0,504,500,1,0,0,0,504,501,1,0,0,0,504, - 502,1,0,0,0,504,503,1,0,0,0,505,81,1,0,0,0,506,508,5,69,0,0,507,509,5,68, - 0,0,508,507,1,0,0,0,508,509,1,0,0,0,509,83,1,0,0,0,510,511,7,13,0,0,511, - 85,1,0,0,0,512,513,7,14,0,0,513,87,1,0,0,0,44,91,97,103,117,120,133,145, - 150,168,182,193,197,199,207,216,221,227,237,247,252,258,273,283,292,301, - 315,320,348,354,362,366,368,381,385,387,400,428,432,434,440,492,494,504, - 508]; + 39,7,39,2,40,7,40,2,41,7,41,2,42,7,42,2,43,7,43,2,44,7,44,1,0,5,0,92,8, + 0,10,0,12,0,95,9,0,1,0,5,0,98,8,0,10,0,12,0,101,9,0,1,0,5,0,104,8,0,10, + 0,12,0,107,9,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,2,1,2,1,3,1,3,3,3,120,8,3, + 1,4,3,4,123,8,4,1,4,1,4,1,5,1,5,1,6,1,6,1,6,1,6,1,7,1,7,1,7,3,7,136,8,7, + 1,8,1,8,1,8,1,8,1,8,1,8,1,8,1,8,5,8,146,8,8,10,8,12,8,149,9,8,1,8,1,8,3, + 8,153,8,8,1,8,1,8,1,9,1,9,1,9,1,9,1,9,1,9,1,9,1,10,1,10,1,10,1,10,1,10, + 5,10,169,8,10,10,10,12,10,172,9,10,1,10,1,10,1,11,1,11,1,11,1,11,1,11,1, + 12,1,12,5,12,183,8,12,10,12,12,12,186,9,12,1,12,1,12,1,13,1,13,1,13,1,13, + 5,13,194,8,13,10,13,12,13,197,9,13,1,13,3,13,200,8,13,3,13,202,8,13,1,13, + 1,13,1,14,1,14,5,14,208,8,14,10,14,12,14,211,9,14,1,14,1,14,1,15,1,15,5, + 15,217,8,15,10,15,12,15,220,9,15,1,15,1,15,3,15,224,8,15,1,16,1,16,1,16, + 1,16,3,16,230,8,16,1,17,1,17,1,17,1,17,1,17,1,17,1,17,1,17,3,17,240,8,17, + 1,18,1,18,1,19,1,19,1,19,1,19,5,19,248,8,19,10,19,12,19,251,9,19,1,20,1, + 20,3,20,255,8,20,1,21,1,21,5,21,259,8,21,10,21,12,21,262,9,21,1,21,1,21, + 1,21,1,21,1,22,1,22,1,22,4,22,271,8,22,11,22,12,22,272,1,22,1,22,1,22,1, + 22,1,22,1,22,1,22,4,22,282,8,22,11,22,12,22,283,1,22,1,22,1,22,1,22,3,22, + 290,8,22,1,23,1,23,1,23,1,23,3,23,296,8,23,1,24,1,24,1,24,1,24,1,24,3,24, + 303,8,24,1,25,1,25,1,25,1,25,1,25,1,25,1,25,3,25,312,8,25,1,25,1,25,1,26, + 1,26,1,26,1,26,1,26,3,26,321,8,26,1,26,1,26,1,27,1,27,1,27,1,28,1,28,1, + 28,1,28,1,28,1,28,1,28,3,28,335,8,28,1,29,1,29,1,29,3,29,340,8,29,1,30, + 1,30,1,30,1,30,1,30,1,30,1,30,1,30,1,31,1,31,1,31,1,31,1,31,1,31,1,32,1, + 32,1,32,1,32,1,32,1,32,1,32,1,32,1,32,1,32,1,33,1,33,3,33,368,8,33,1,34, + 1,34,1,35,1,35,3,35,374,8,35,1,36,1,36,1,36,1,36,5,36,380,8,36,10,36,12, + 36,383,9,36,1,36,3,36,386,8,36,3,36,388,8,36,1,36,1,36,1,37,1,37,1,37,1, + 38,1,38,1,38,1,38,5,38,399,8,38,10,38,12,38,402,9,38,1,38,3,38,405,8,38, + 3,38,407,8,38,1,38,1,38,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,3, + 39,420,8,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39, + 1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,5,39,446,8, + 39,10,39,12,39,449,9,39,1,39,3,39,452,8,39,3,39,454,8,39,1,39,1,39,1,39, + 1,39,3,39,460,8,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1, + 39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39, + 1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1, + 39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,5,39,512,8,39,10,39, + 12,39,515,9,39,1,40,1,40,1,41,1,41,1,41,1,41,1,41,3,41,524,8,41,1,42,1, + 42,3,42,528,8,42,1,43,1,43,1,44,1,44,1,44,0,1,78,45,0,2,4,6,8,10,12,14, + 16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62, + 64,66,68,70,72,74,76,78,80,82,84,86,88,0,15,1,0,4,10,2,0,10,10,22,23,1, + 0,24,25,1,0,37,41,2,0,37,41,43,46,2,0,5,5,51,52,1,0,53,55,2,0,52,52,56, + 56,1,0,57,58,1,0,6,9,1,0,59,60,1,0,47,48,2,0,17,17,65,65,1,0,72,74,2,0, + 72,73,80,80,567,0,93,1,0,0,0,2,110,1,0,0,0,4,115,1,0,0,0,6,117,1,0,0,0, + 8,122,1,0,0,0,10,126,1,0,0,0,12,128,1,0,0,0,14,135,1,0,0,0,16,137,1,0,0, + 0,18,156,1,0,0,0,20,163,1,0,0,0,22,175,1,0,0,0,24,180,1,0,0,0,26,189,1, + 0,0,0,28,205,1,0,0,0,30,223,1,0,0,0,32,229,1,0,0,0,34,239,1,0,0,0,36,241, + 1,0,0,0,38,243,1,0,0,0,40,254,1,0,0,0,42,256,1,0,0,0,44,289,1,0,0,0,46, + 295,1,0,0,0,48,302,1,0,0,0,50,304,1,0,0,0,52,315,1,0,0,0,54,324,1,0,0,0, + 56,327,1,0,0,0,58,339,1,0,0,0,60,341,1,0,0,0,62,349,1,0,0,0,64,355,1,0, + 0,0,66,367,1,0,0,0,68,369,1,0,0,0,70,373,1,0,0,0,72,375,1,0,0,0,74,391, + 1,0,0,0,76,394,1,0,0,0,78,459,1,0,0,0,80,516,1,0,0,0,82,523,1,0,0,0,84, + 525,1,0,0,0,86,529,1,0,0,0,88,531,1,0,0,0,90,92,3,2,1,0,91,90,1,0,0,0,92, + 95,1,0,0,0,93,91,1,0,0,0,93,94,1,0,0,0,94,99,1,0,0,0,95,93,1,0,0,0,96,98, + 3,12,6,0,97,96,1,0,0,0,98,101,1,0,0,0,99,97,1,0,0,0,99,100,1,0,0,0,100, + 105,1,0,0,0,101,99,1,0,0,0,102,104,3,14,7,0,103,102,1,0,0,0,104,107,1,0, + 0,0,105,103,1,0,0,0,105,106,1,0,0,0,106,108,1,0,0,0,107,105,1,0,0,0,108, + 109,5,0,0,1,109,1,1,0,0,0,110,111,5,1,0,0,111,112,3,4,2,0,112,113,3,6,3, + 0,113,114,5,2,0,0,114,3,1,0,0,0,115,116,5,3,0,0,116,5,1,0,0,0,117,119,3, + 8,4,0,118,120,3,8,4,0,119,118,1,0,0,0,119,120,1,0,0,0,120,7,1,0,0,0,121, + 123,3,10,5,0,122,121,1,0,0,0,122,123,1,0,0,0,123,124,1,0,0,0,124,125,5, + 66,0,0,125,9,1,0,0,0,126,127,7,0,0,0,127,11,1,0,0,0,128,129,5,11,0,0,129, + 130,5,76,0,0,130,131,5,2,0,0,131,13,1,0,0,0,132,136,3,16,8,0,133,136,3, + 18,9,0,134,136,3,20,10,0,135,132,1,0,0,0,135,133,1,0,0,0,135,134,1,0,0, + 0,136,15,1,0,0,0,137,138,5,12,0,0,138,139,5,82,0,0,139,152,3,26,13,0,140, + 141,5,13,0,0,141,142,5,14,0,0,142,147,3,86,43,0,143,144,5,15,0,0,144,146, + 3,86,43,0,145,143,1,0,0,0,146,149,1,0,0,0,147,145,1,0,0,0,147,148,1,0,0, + 0,148,150,1,0,0,0,149,147,1,0,0,0,150,151,5,16,0,0,151,153,1,0,0,0,152, + 140,1,0,0,0,152,153,1,0,0,0,153,154,1,0,0,0,154,155,3,24,12,0,155,17,1, + 0,0,0,156,157,3,86,43,0,157,158,5,17,0,0,158,159,5,82,0,0,159,160,5,10, + 0,0,160,161,3,82,41,0,161,162,5,2,0,0,162,19,1,0,0,0,163,164,5,18,0,0,164, + 165,5,82,0,0,165,166,3,26,13,0,166,170,5,19,0,0,167,169,3,22,11,0,168,167, + 1,0,0,0,169,172,1,0,0,0,170,168,1,0,0,0,170,171,1,0,0,0,171,173,1,0,0,0, + 172,170,1,0,0,0,173,174,5,20,0,0,174,21,1,0,0,0,175,176,5,12,0,0,176,177, + 5,82,0,0,177,178,3,26,13,0,178,179,3,24,12,0,179,23,1,0,0,0,180,184,5,19, + 0,0,181,183,3,32,16,0,182,181,1,0,0,0,183,186,1,0,0,0,184,182,1,0,0,0,184, + 185,1,0,0,0,185,187,1,0,0,0,186,184,1,0,0,0,187,188,5,20,0,0,188,25,1,0, + 0,0,189,201,5,14,0,0,190,195,3,28,14,0,191,192,5,15,0,0,192,194,3,28,14, + 0,193,191,1,0,0,0,194,197,1,0,0,0,195,193,1,0,0,0,195,196,1,0,0,0,196,199, + 1,0,0,0,197,195,1,0,0,0,198,200,5,15,0,0,199,198,1,0,0,0,199,200,1,0,0, + 0,200,202,1,0,0,0,201,190,1,0,0,0,201,202,1,0,0,0,202,203,1,0,0,0,203,204, + 5,16,0,0,204,27,1,0,0,0,205,209,3,86,43,0,206,208,3,80,40,0,207,206,1,0, + 0,0,208,211,1,0,0,0,209,207,1,0,0,0,209,210,1,0,0,0,210,212,1,0,0,0,211, + 209,1,0,0,0,212,213,5,82,0,0,213,29,1,0,0,0,214,218,5,19,0,0,215,217,3, + 32,16,0,216,215,1,0,0,0,217,220,1,0,0,0,218,216,1,0,0,0,218,219,1,0,0,0, + 219,221,1,0,0,0,220,218,1,0,0,0,221,224,5,20,0,0,222,224,3,32,16,0,223, + 214,1,0,0,0,223,222,1,0,0,0,224,31,1,0,0,0,225,230,3,40,20,0,226,227,3, + 34,17,0,227,228,5,2,0,0,228,230,1,0,0,0,229,225,1,0,0,0,229,226,1,0,0,0, + 230,33,1,0,0,0,231,240,3,42,21,0,232,240,3,44,22,0,233,240,3,48,24,0,234, + 240,3,50,25,0,235,240,3,52,26,0,236,240,3,36,18,0,237,240,3,54,27,0,238, + 240,3,38,19,0,239,231,1,0,0,0,239,232,1,0,0,0,239,233,1,0,0,0,239,234,1, + 0,0,0,239,235,1,0,0,0,239,236,1,0,0,0,239,237,1,0,0,0,239,238,1,0,0,0,240, + 35,1,0,0,0,241,242,3,74,37,0,242,37,1,0,0,0,243,244,5,21,0,0,244,249,3, + 78,39,0,245,246,5,15,0,0,246,248,3,78,39,0,247,245,1,0,0,0,248,251,1,0, + 0,0,249,247,1,0,0,0,249,250,1,0,0,0,250,39,1,0,0,0,251,249,1,0,0,0,252, + 255,3,56,28,0,253,255,3,58,29,0,254,252,1,0,0,0,254,253,1,0,0,0,255,41, + 1,0,0,0,256,260,3,86,43,0,257,259,3,80,40,0,258,257,1,0,0,0,259,262,1,0, + 0,0,260,258,1,0,0,0,260,261,1,0,0,0,261,263,1,0,0,0,262,260,1,0,0,0,263, + 264,5,82,0,0,264,265,5,10,0,0,265,266,3,78,39,0,266,43,1,0,0,0,267,270, + 3,46,23,0,268,269,5,15,0,0,269,271,3,46,23,0,270,268,1,0,0,0,271,272,1, + 0,0,0,272,270,1,0,0,0,272,273,1,0,0,0,273,274,1,0,0,0,274,275,5,10,0,0, + 275,276,3,78,39,0,276,290,1,0,0,0,277,278,5,14,0,0,278,281,3,46,23,0,279, + 280,5,15,0,0,280,282,3,46,23,0,281,279,1,0,0,0,282,283,1,0,0,0,283,281, + 1,0,0,0,283,284,1,0,0,0,284,285,1,0,0,0,285,286,5,16,0,0,286,287,5,10,0, + 0,287,288,3,78,39,0,288,290,1,0,0,0,289,267,1,0,0,0,289,277,1,0,0,0,290, + 45,1,0,0,0,291,292,3,86,43,0,292,293,5,82,0,0,293,296,1,0,0,0,294,296,5, + 82,0,0,295,291,1,0,0,0,295,294,1,0,0,0,296,47,1,0,0,0,297,298,5,82,0,0, + 298,299,7,1,0,0,299,303,3,78,39,0,300,301,5,82,0,0,301,303,7,2,0,0,302, + 297,1,0,0,0,302,300,1,0,0,0,303,49,1,0,0,0,304,305,5,26,0,0,305,306,5,14, + 0,0,306,307,5,79,0,0,307,308,5,6,0,0,308,311,3,78,39,0,309,310,5,15,0,0, + 310,312,3,68,34,0,311,309,1,0,0,0,311,312,1,0,0,0,312,313,1,0,0,0,313,314, + 5,16,0,0,314,51,1,0,0,0,315,316,5,26,0,0,316,317,5,14,0,0,317,320,3,78, + 39,0,318,319,5,15,0,0,319,321,3,68,34,0,320,318,1,0,0,0,320,321,1,0,0,0, + 321,322,1,0,0,0,322,323,5,16,0,0,323,53,1,0,0,0,324,325,5,27,0,0,325,326, + 3,72,36,0,326,55,1,0,0,0,327,328,5,28,0,0,328,329,5,14,0,0,329,330,3,78, + 39,0,330,331,5,16,0,0,331,334,3,30,15,0,332,333,5,29,0,0,333,335,3,30,15, + 0,334,332,1,0,0,0,334,335,1,0,0,0,335,57,1,0,0,0,336,340,3,60,30,0,337, + 340,3,62,31,0,338,340,3,64,32,0,339,336,1,0,0,0,339,337,1,0,0,0,339,338, + 1,0,0,0,340,59,1,0,0,0,341,342,5,30,0,0,342,343,3,30,15,0,343,344,5,31, + 0,0,344,345,5,14,0,0,345,346,3,78,39,0,346,347,5,16,0,0,347,348,5,2,0,0, + 348,61,1,0,0,0,349,350,5,31,0,0,350,351,5,14,0,0,351,352,3,78,39,0,352, + 353,5,16,0,0,353,354,3,30,15,0,354,63,1,0,0,0,355,356,5,32,0,0,356,357, + 5,14,0,0,357,358,3,66,33,0,358,359,5,2,0,0,359,360,3,78,39,0,360,361,5, + 2,0,0,361,362,3,48,24,0,362,363,5,16,0,0,363,364,3,30,15,0,364,65,1,0,0, + 0,365,368,3,42,21,0,366,368,3,48,24,0,367,365,1,0,0,0,367,366,1,0,0,0,368, + 67,1,0,0,0,369,370,5,76,0,0,370,69,1,0,0,0,371,374,5,82,0,0,372,374,3,82, + 41,0,373,371,1,0,0,0,373,372,1,0,0,0,374,71,1,0,0,0,375,387,5,14,0,0,376, + 381,3,70,35,0,377,378,5,15,0,0,378,380,3,70,35,0,379,377,1,0,0,0,380,383, + 1,0,0,0,381,379,1,0,0,0,381,382,1,0,0,0,382,385,1,0,0,0,383,381,1,0,0,0, + 384,386,5,15,0,0,385,384,1,0,0,0,385,386,1,0,0,0,386,388,1,0,0,0,387,376, + 1,0,0,0,387,388,1,0,0,0,388,389,1,0,0,0,389,390,5,16,0,0,390,73,1,0,0,0, + 391,392,5,82,0,0,392,393,3,76,38,0,393,75,1,0,0,0,394,406,5,14,0,0,395, + 400,3,78,39,0,396,397,5,15,0,0,397,399,3,78,39,0,398,396,1,0,0,0,399,402, + 1,0,0,0,400,398,1,0,0,0,400,401,1,0,0,0,401,404,1,0,0,0,402,400,1,0,0,0, + 403,405,5,15,0,0,404,403,1,0,0,0,404,405,1,0,0,0,405,407,1,0,0,0,406,395, + 1,0,0,0,406,407,1,0,0,0,407,408,1,0,0,0,408,409,5,16,0,0,409,77,1,0,0,0, + 410,411,6,39,-1,0,411,412,5,14,0,0,412,413,3,78,39,0,413,414,5,16,0,0,414, + 460,1,0,0,0,415,416,3,88,44,0,416,417,5,14,0,0,417,419,3,78,39,0,418,420, + 5,15,0,0,419,418,1,0,0,0,419,420,1,0,0,0,420,421,1,0,0,0,421,422,5,16,0, + 0,422,460,1,0,0,0,423,460,3,74,37,0,424,425,5,33,0,0,425,426,5,82,0,0,426, + 460,3,76,38,0,427,428,5,36,0,0,428,429,5,34,0,0,429,430,3,78,39,0,430,431, + 5,35,0,0,431,432,7,3,0,0,432,460,1,0,0,0,433,434,5,42,0,0,434,435,5,34, + 0,0,435,436,3,78,39,0,436,437,5,35,0,0,437,438,7,4,0,0,438,460,1,0,0,0, + 439,440,7,5,0,0,440,460,3,78,39,15,441,453,5,34,0,0,442,447,3,78,39,0,443, + 444,5,15,0,0,444,446,3,78,39,0,445,443,1,0,0,0,446,449,1,0,0,0,447,445, + 1,0,0,0,447,448,1,0,0,0,448,451,1,0,0,0,449,447,1,0,0,0,450,452,5,15,0, + 0,451,450,1,0,0,0,451,452,1,0,0,0,452,454,1,0,0,0,453,442,1,0,0,0,453,454, + 1,0,0,0,454,455,1,0,0,0,455,460,5,35,0,0,456,460,5,81,0,0,457,460,5,82, + 0,0,458,460,3,82,41,0,459,410,1,0,0,0,459,415,1,0,0,0,459,423,1,0,0,0,459, + 424,1,0,0,0,459,427,1,0,0,0,459,433,1,0,0,0,459,439,1,0,0,0,459,441,1,0, + 0,0,459,456,1,0,0,0,459,457,1,0,0,0,459,458,1,0,0,0,460,513,1,0,0,0,461, + 462,10,14,0,0,462,463,7,6,0,0,463,512,3,78,39,15,464,465,10,13,0,0,465, + 466,7,7,0,0,466,512,3,78,39,14,467,468,10,12,0,0,468,469,7,8,0,0,469,512, + 3,78,39,13,470,471,10,11,0,0,471,472,7,9,0,0,472,512,3,78,39,12,473,474, + 10,10,0,0,474,475,7,10,0,0,475,512,3,78,39,11,476,477,10,9,0,0,477,478, + 5,61,0,0,478,512,3,78,39,10,479,480,10,8,0,0,480,481,5,4,0,0,481,512,3, + 78,39,9,482,483,10,7,0,0,483,484,5,62,0,0,484,512,3,78,39,8,485,486,10, + 6,0,0,486,487,5,63,0,0,487,512,3,78,39,7,488,489,10,5,0,0,489,490,5,64, + 0,0,490,512,3,78,39,6,491,492,10,21,0,0,492,493,5,34,0,0,493,494,5,69,0, + 0,494,512,5,35,0,0,495,496,10,18,0,0,496,512,7,11,0,0,497,498,10,17,0,0, + 498,499,5,49,0,0,499,500,5,14,0,0,500,501,3,78,39,0,501,502,5,16,0,0,502, + 512,1,0,0,0,503,504,10,16,0,0,504,505,5,50,0,0,505,506,5,14,0,0,506,507, + 3,78,39,0,507,508,5,15,0,0,508,509,3,78,39,0,509,510,5,16,0,0,510,512,1, + 0,0,0,511,461,1,0,0,0,511,464,1,0,0,0,511,467,1,0,0,0,511,470,1,0,0,0,511, + 473,1,0,0,0,511,476,1,0,0,0,511,479,1,0,0,0,511,482,1,0,0,0,511,485,1,0, + 0,0,511,488,1,0,0,0,511,491,1,0,0,0,511,495,1,0,0,0,511,497,1,0,0,0,511, + 503,1,0,0,0,512,515,1,0,0,0,513,511,1,0,0,0,513,514,1,0,0,0,514,79,1,0, + 0,0,515,513,1,0,0,0,516,517,7,12,0,0,517,81,1,0,0,0,518,524,5,67,0,0,519, + 524,3,84,42,0,520,524,5,76,0,0,521,524,5,77,0,0,522,524,5,78,0,0,523,518, + 1,0,0,0,523,519,1,0,0,0,523,520,1,0,0,0,523,521,1,0,0,0,523,522,1,0,0,0, + 524,83,1,0,0,0,525,527,5,69,0,0,526,528,5,68,0,0,527,526,1,0,0,0,527,528, + 1,0,0,0,528,85,1,0,0,0,529,530,7,13,0,0,530,87,1,0,0,0,531,532,7,14,0,0, + 532,89,1,0,0,0,47,93,99,105,119,122,135,147,152,170,184,195,199,201,209, + 218,223,229,239,249,254,260,272,283,289,295,302,311,320,334,339,367,373, + 381,385,387,400,404,406,419,447,451,453,459,511,513,523,527]; private static __ATN: ATN; public static get _ATN(): ATN { @@ -3537,17 +3628,11 @@ export class TupleAssignmentContext extends ParserRuleContext { super(parent, invokingState); this.parser = parser; } - public typeName_list(): TypeNameContext[] { - return this.getTypedRuleContexts(TypeNameContext) as TypeNameContext[]; - } - public typeName(i: number): TypeNameContext { - return this.getTypedRuleContext(TypeNameContext, i) as TypeNameContext; + public tupleTarget_list(): TupleTargetContext[] { + return this.getTypedRuleContexts(TupleTargetContext) as TupleTargetContext[]; } - public Identifier_list(): TerminalNode[] { - return this.getTokens(CashScriptParser.Identifier); - } - public Identifier(i: number): TerminalNode { - return this.getToken(CashScriptParser.Identifier, i); + public tupleTarget(i: number): TupleTargetContext { + return this.getTypedRuleContext(TupleTargetContext, i) as TupleTargetContext; } public expression(): ExpressionContext { return this.getTypedRuleContext(ExpressionContext, 0) as ExpressionContext; @@ -3566,6 +3651,31 @@ export class TupleAssignmentContext extends ParserRuleContext { } +export class TupleTargetContext extends ParserRuleContext { + constructor(parser?: CashScriptParser, parent?: ParserRuleContext, invokingState?: number) { + super(parent, invokingState); + this.parser = parser; + } + public typeName(): TypeNameContext { + return this.getTypedRuleContext(TypeNameContext, 0) as TypeNameContext; + } + public Identifier(): TerminalNode { + return this.getToken(CashScriptParser.Identifier, 0); + } + public get ruleIndex(): number { + return CashScriptParser.RULE_tupleTarget; + } + // @Override + public accept(visitor: CashScriptVisitor): Result { + if (visitor.visitTupleTarget) { + return visitor.visitTupleTarget(this); + } else { + return visitor.visitChildren(this); + } + } +} + + export class AssignStatementContext extends ParserRuleContext { public _op!: Token; constructor(parser?: CashScriptParser, parent?: ParserRuleContext, invokingState?: number) { diff --git a/packages/cashc/src/grammar/CashScriptVisitor.ts b/packages/cashc/src/grammar/CashScriptVisitor.ts index 187bf8c7..3c4d117b 100644 --- a/packages/cashc/src/grammar/CashScriptVisitor.ts +++ b/packages/cashc/src/grammar/CashScriptVisitor.ts @@ -26,6 +26,7 @@ import { ReturnStatementContext } from "./CashScriptParser.js"; import { ControlStatementContext } from "./CashScriptParser.js"; import { VariableDefinitionContext } from "./CashScriptParser.js"; import { TupleAssignmentContext } from "./CashScriptParser.js"; +import { TupleTargetContext } from "./CashScriptParser.js"; import { AssignStatementContext } from "./CashScriptParser.js"; import { TimeOpStatementContext } from "./CashScriptParser.js"; import { RequireStatementContext } from "./CashScriptParser.js"; @@ -207,6 +208,12 @@ export default class CashScriptVisitor extends ParseTreeVisitor * @return the visitor result */ visitTupleAssignment?: (ctx: TupleAssignmentContext) => Result; + /** + * Visit a parse tree produced by `CashScriptParser.tupleTarget`. + * @param ctx the parse tree + * @return the visitor result + */ + visitTupleTarget?: (ctx: TupleTargetContext) => Result; /** * Visit a parse tree produced by `CashScriptParser.assignStatement`. * @param ctx the parse tree diff --git a/packages/cashc/src/print/OutputSourceCodeTraversal.ts b/packages/cashc/src/print/OutputSourceCodeTraversal.ts index bfb1e5a2..07451e12 100644 --- a/packages/cashc/src/print/OutputSourceCodeTraversal.ts +++ b/packages/cashc/src/print/OutputSourceCodeTraversal.ts @@ -142,7 +142,10 @@ export default class OutputSourceCodeTraversal extends AstTraversal { } visitTupleAssignment(node: TupleAssignmentNode): Node { - const targets = node.targets.map((target) => `${target.type} ${target.name}`).join(', '); + // A reassignment target (no declared type) prints as a bare identifier; a declaration as `type name`. + const targets = node.targets + .map((target) => (target.isReassignment ? target.name : `${target.type} ${target.name}`)) + .join(', '); this.addOutput(`${targets} = `, true); this.visit(node.tuple); diff --git a/packages/cashc/src/semantic/SymbolTableTraversal.ts b/packages/cashc/src/semantic/SymbolTableTraversal.ts index 3c11c8c0..473b8f3b 100644 --- a/packages/cashc/src/semantic/SymbolTableTraversal.ts +++ b/packages/cashc/src/semantic/SymbolTableTraversal.ts @@ -29,6 +29,8 @@ import { UnusedVariableError, InvalidSymbolTypeError, ConstantModificationError, + DuplicateTupleTargetError, + TupleTargetOrderError, InvalidModifierError, } from '../Errors.js'; @@ -185,7 +187,49 @@ export default class SymbolTableTraversal extends AstTraversal { } visitTupleAssignment(node: TupleAssignmentNode): Node { + // Declarations must form a contiguous block before all reassignment targets — the one layout + // scoped codegen can fold in place (see GenerateTargetTraversal.visitTupleAssignment). Enforced + // uniformly so a statement's legality does not depend on whether it sits inside a loop/branch. + const firstReassignment = node.targets.findIndex((target) => target.isReassignment); + if (firstReassignment !== -1 && node.targets.slice(firstReassignment).some((target) => !target.isReassignment)) { + throw new TupleTargetOrderError(node); + } + + const seenTargetNames = new Set(); node.targets.forEach((variable) => { + if (seenTargetNames.has(variable.name)) { + throw new DuplicateTupleTargetError(node, variable.name); + } + seenTargetNames.add(variable.name); + + if (variable.isReassignment) { + // Reassignment of an existing variable (`x`, no type): adopt its type for the type-check and + // register a reference (so it isn't flagged unused). Do NOT create a new symbol. + const reference = new IdentifierNode(variable.name); + reference.location = node.location; + const existing = this.symbolTables[0].get(variable.name); + if (!existing) { + throw new UndefinedReferenceError(reference); + } + // only variables can be reassigned (not functions or classes) + if (existing.symbolType !== SymbolType.VARIABLE) { + throw new InvalidSymbolTypeError(reference, SymbolType.VARIABLE); + } + if (existing.definition instanceof ConstantDefinitionNode) { + throw new ConstantModificationError(node, variable.name); + } + const definition = existing.definition as VariableDefinitionNode | undefined; + if (definition?.modifiers?.includes(Modifier.CONSTANT)) { + throw new ConstantModificationError(node, variable.name); + } + variable.type = existing.type; + existing.references.push(reference); + // The reassignment is now the variable's latest use, so codegen must not roll it off the + // stack at an earlier read (mirrors visitIdentifier's bookkeeping for plain assignments). + this.currentFunction.opRolls.set(variable.name, reference); + return; + } + const definition = createTupleVariableDefinition(node, variable); const { name } = variable; @@ -283,7 +327,9 @@ function createTupleVariableDefinition( node: TupleAssignmentNode, variable: TupleAssignmentTarget, ): VariableDefinitionNode { - const definition = new VariableDefinitionNode(variable.type, [], variable.name, node.tuple); + // Only declaration targets reach here (reassignment targets are handled before this is called), + // so `type` is always defined. + const definition = new VariableDefinitionNode(variable.type!, [], variable.name, node.tuple); definition.location = node.location; return definition; } diff --git a/packages/cashc/src/semantic/TypeCheckTraversal.ts b/packages/cashc/src/semantic/TypeCheckTraversal.ts index f0b89b2a..cbb47aae 100644 --- a/packages/cashc/src/semantic/TypeCheckTraversal.ts +++ b/packages/cashc/src/semantic/TypeCheckTraversal.ts @@ -78,7 +78,9 @@ export default class TypeCheckTraversal extends AstTraversal { visitTupleAssignment(node: TupleAssignmentNode): Node { node.tuple = this.visit(node.tuple); - const targetsType = new TupleType(node.targets.map((target) => target.type)); + // target.type is resolved for every target by SymbolTableTraversal before this pass (declared + // targets carry their declared type; reassignment targets adopt the existing variable's type). + const targetsType = new TupleType(node.targets.map((target) => target.type!)); if (!implicitlyCastable(node.tuple.type, targetsType)) { const targetNames = node.targets.map((target) => target.name).join(', '); const syntheticAssignment = new VariableDefinitionNode(targetsType, [], targetNames, node.tuple); diff --git a/packages/cashc/test/compiler/ConstantModificationError/tuple_reassign_constant.cash b/packages/cashc/test/compiler/ConstantModificationError/tuple_reassign_constant.cash new file mode 100644 index 00000000..f439d564 --- /dev/null +++ b/packages/cashc/test/compiler/ConstantModificationError/tuple_reassign_constant.cash @@ -0,0 +1,11 @@ +function pair(int n) returns (int, int) { + return n + 1, n + 2; +} + +contract Test() { + function spend(int n) { + int constant f = 5; + int q, f = pair(n); + require(q > f); + } +} diff --git a/packages/cashc/test/compiler/DuplicateTupleTargetError/declaration_then_reassignment.cash b/packages/cashc/test/compiler/DuplicateTupleTargetError/declaration_then_reassignment.cash new file mode 100644 index 00000000..b1785eb5 --- /dev/null +++ b/packages/cashc/test/compiler/DuplicateTupleTargetError/declaration_then_reassignment.cash @@ -0,0 +1,10 @@ +function pair(int n) returns (int, int) { + return n + 1, n + 2; +} + +contract Test() { + function spend(int n) { + int a, a = pair(n); + require(a > 0); + } +} diff --git a/packages/cashc/test/compiler/DuplicateTupleTargetError/duplicate_reassignment_targets.cash b/packages/cashc/test/compiler/DuplicateTupleTargetError/duplicate_reassignment_targets.cash new file mode 100644 index 00000000..d4a72125 --- /dev/null +++ b/packages/cashc/test/compiler/DuplicateTupleTargetError/duplicate_reassignment_targets.cash @@ -0,0 +1,11 @@ +function pair(int n) returns (int, int) { + return n + 1, n + 2; +} + +contract Test() { + function spend(int n) { + int a = n; + (a, a) = pair(n); + require(a > 0); + } +} diff --git a/packages/cashc/test/compiler/InvalidSymbolTypeError/tuple_reassign_function_name.cash b/packages/cashc/test/compiler/InvalidSymbolTypeError/tuple_reassign_function_name.cash new file mode 100644 index 00000000..572e098e --- /dev/null +++ b/packages/cashc/test/compiler/InvalidSymbolTypeError/tuple_reassign_function_name.cash @@ -0,0 +1,10 @@ +function pair(int n) returns (int, int) { + return n + 1, n + 2; +} + +contract Test() { + function spend(int n) { + int q, pair = pair(n); + require(q > 0); + } +} diff --git a/packages/cashc/test/compiler/ParseError/single_type_destructuring.cash b/packages/cashc/test/compiler/ParseError/single_type_destructuring.cash deleted file mode 100644 index 89afb1bf..00000000 --- a/packages/cashc/test/compiler/ParseError/single_type_destructuring.cash +++ /dev/null @@ -1,5 +0,0 @@ -contract Test() { - function test1(string s) { - string x, y = s.split(5); - } -} diff --git a/packages/cashc/test/compiler/TupleTargetOrderError/reassignment_before_declaration.cash b/packages/cashc/test/compiler/TupleTargetOrderError/reassignment_before_declaration.cash new file mode 100644 index 00000000..72ae284f --- /dev/null +++ b/packages/cashc/test/compiler/TupleTargetOrderError/reassignment_before_declaration.cash @@ -0,0 +1,11 @@ +function pair(int n) returns (int, int) { + return n + 1, n + 2; +} + +contract Test() { + function spend(int n) { + int a = n; + a, int b = pair(n); + require(a > b); + } +} diff --git a/packages/cashc/test/compiler/UndefinedReferenceError/tuple_reassign_undefined.cash b/packages/cashc/test/compiler/UndefinedReferenceError/tuple_reassign_undefined.cash new file mode 100644 index 00000000..396dcf8a --- /dev/null +++ b/packages/cashc/test/compiler/UndefinedReferenceError/tuple_reassign_undefined.cash @@ -0,0 +1,12 @@ +function swap(int x, int y) returns (int, int) { + return y, x; +} + +contract Test() { + function spend(int seed) { + int a = seed; + // `b` is never declared, so reassigning it must fail + (a, b) = swap(a, seed); + require(a + b >= 0); + } +} diff --git a/packages/cashc/test/tuple-destructuring.test.ts b/packages/cashc/test/tuple-destructuring.test.ts new file mode 100644 index 00000000..15c82cf8 --- /dev/null +++ b/packages/cashc/test/tuple-destructuring.test.ts @@ -0,0 +1,131 @@ +import { + createTestAuthenticationProgramBch, + createVirtualMachineBch2026, +} from '@bitauth/libauth'; +import { asmToBytecode, encodeInt, scriptToBytecode } from '@cashscript/utils'; +import { compileString } from '../src/index.js'; + +const vm = createVirtualMachineBch2026(false); + +// evaluate a compiled contract (no constructor args) directly against pushed spend args +function evaluate(bytecodeAsm: string, args: bigint[]): boolean { + // spend args are pushed in reverse declaration order (first parameter on top) + const unlocking = scriptToBytecode([...args].reverse().map((arg) => encodeInt(arg))); + const state = vm.evaluate(createTestAuthenticationProgramBch({ + lockingBytecode: asmToBytecode(bytecodeAsm), + unlockingBytecode: unlocking, + valueSatoshis: 1000n, + })); + const top = state.stack[state.stack.length - 1]; + return state.error === undefined && state.stack.length === 1 && top !== undefined && top.length === 1 && top[0] === 1; +} + +// Execution coverage for the SCOPED destructuring fold (GenerateTargetTraversal +// visitTupleAssignment): inside a loop/branch the stack layout must be preserved, so +// reassignments are folded into the existing slots via emitReplace instead of the +// depth-0 pure-rename strategy. +describe('tuple destructuring into existing variables (scoped fold)', () => { + it.each([[true], [false]] as const)( + 'folds pure reassignment in a loop (disableInlining: %s)', + (disableInlining) => { + const code = ` + function swap(int x, int y) returns (int, int) { + return y, x; + } + contract LoopSwap() { + function spend(int a, int b) { + // odd iteration count: the net effect is one swap + for (int i = 0; i < 3; i = i + 1) { + (a, b) = swap(a, b); + } + require(a > b); + } + }`; + const artifact = compileString(code, { disableInlining }); + + // after the net swap, a holds the original b + expect(evaluate(artifact.bytecode, [2n, 5n])).toBe(true); + expect(evaluate(artifact.bytecode, [5n, 2n])).toBe(false); + }, + ); + + it('folds mixed declaration + reassignment inside a branch', () => { + const code = ` + function pair(int n) returns (int, int) { + return n * 2, n + 1; + } + contract BranchFold() { + function spend(int a) { + int total = 0; + if (a > 10) { + int d, total = pair(a); + require(d == a * 2); + } + require(total > 0); + } + }`; + const artifact = compileString(code); + + // branch taken: total is reassigned to a + 1 > 0 + expect(evaluate(artifact.bytecode, [11n])).toBe(true); + // branch not taken: total stays 0 and the final require fails + expect(evaluate(artifact.bytecode, [5n])).toBe(false); + }); + + it('folds mixed declaration + reassignment of loop-carried state', () => { + const code = ` + function step(int x, int y) returns (int, int, int) { + return x + y, x + y, y; + } + contract Fib() { + // pad buys op-cost budget for the loop (the budget scales with unlocking bytes) + function spend(int expected, int unused pad) { + int a = 0; + int b = 1; + int last = 0; + for (int i = 0; i < 5; i = i + 1) { + // fresh declaration first, then the two updated accumulators + (int next, b, a) = step(a, b); + last = next; + } + require(last == expected); + } + }`; + const artifact = compileString(code); + const pad = 1n << 4000n; // ~500-byte push + + // fib recurrence (a, b = b, a + b): iterations produce 1, 2, 3, 5, 8 + expect(evaluate(artifact.bytecode, [8n, pad])).toBe(true); + expect(evaluate(artifact.bytecode, [5n, pad])).toBe(false); + }); + + // Regression: a scoped reassignment is itself the variable's latest use, so the symbol pass must + // move the opRolls entry to it. Before the fix, the last plain read kept the roll, codegen rolled + // the variable off the stack model, and the reassignment crashed with a raw + // "Expected variable ... does not exist on the stack". + it.each([['if'], ['while']] as const)( + 'compiles a scoped reassignment after the variable\'s final plain read (%s)', + (construct) => { + const body = construct === 'if' + ? 'if (x == 1) { (p, q) = pair(x); }' + : 'while (x == 1) { (p, q) = pair(x); x = x + 1; }'; + const code = ` + function pair(int n) returns (int, int) { + return n * 2, n + 1; + } + contract ReassignAfterFinalRead() { + function spend(int x) { + int p = 10; + int q = 0; + require(p == 10); + ${body} + require(q == 0 || q == 2); + } + }`; + + const artifact = compileString(code); + expect(evaluate(artifact.bytecode, [1n])).toBe(true); + expect(evaluate(artifact.bytecode, [2n])).toBe(true); + }, + ); +}); diff --git a/packages/cashc/test/valid-contract-files/tuple_reassignment.cash b/packages/cashc/test/valid-contract-files/tuple_reassignment.cash new file mode 100644 index 00000000..f0aa91ec --- /dev/null +++ b/packages/cashc/test/valid-contract-files/tuple_reassignment.cash @@ -0,0 +1,40 @@ +// Destructuring into existing variables: a target without a type reassigns an already-declared +// variable instead of declaring a fresh one. Covers straight-line reassignment, mixed +// declaration+reassignment, and in-loop reassignment of loop-carried state (the case that previously +// needed a fresh-temp + per-element rebind workaround). + +function swap(int x, int y) returns (int, int) { + return y, x; +} + +// returns a fresh scalar followed by the two updated accumulators +function step(int x, int y) returns (int, int, int) { + return x * x + 1, y, x; +} + +contract TupleReassignment() { + function spend(int seed) { + int a = seed; + int b = seed + 1; + + // straight-line reassignment of both existing variables + (a, b) = swap(a, b); + + // mixed: declare c fresh, reassign a (allowed at the top level) + (int c, a) = swap(a, b); + + // loop-carried state reassigned in place each iteration + for (int i = 0; i < 4; i = i + 1) { + (a, b) = swap(a, b); + } + + // mixed declaration + reassignment IN A LOOP: declarations form a contiguous block at the + // front, the loop-carried reassignments trail at the end. + for (int j = 0; j < 4; j = j + 1) { + (int lo, a, b) = step(a, b); + require(lo >= 0); + } + + require(a + b + c >= 0); + } +} From 77ea8d46476e4842328cd3ff9c4dd84ef9703ba5 Mon Sep 17 00:00:00 2001 From: Mathieu Geukens Date: Wed, 1 Jul 2026 12:19:30 +0200 Subject: [PATCH 03/12] perf(utils): rewrite the peephole optimiser to match opcodes directly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Purely a compiler-speed change: the optimised bytecode that comes out is unchanged. Large generated contracts made optimisation slow because the optimiser round-tripped the whole program through an ASM string and regex-scanned a growing string for every match; matching opcodes directly against the Script array makes optimisation ~43x faster on 30k-element scripts (measured), turning multi-second compiles into tens of milliseconds. Mechanics: the ASM-string patterns are pre-parsed once into opcode-number sequences and matched element-wise. Small-integer pushes are matched exactly as disassembly would render them (elementOpcode derives OP_0/OP_1..OP_16/OP_1NEGATE via the same encodeDataPush used for serialization, so representations cannot diverge). The fixed-point check compares Script arrays structurally instead of stringifying both scripts every pass. Two string-engine behaviours deserve calling out: - Pass semantics are emulated exactly: regex /g computes matches against the sweep-start string (a replacement never cascades into another match within the same rule's sweep), and an empty replacement leaves a double space that no later single-space pattern can match across until the pass-end cleanup. The splice engine reproduces both: matches are collected up front per rule, and removal sites become match barriers for the remainder of the pass. - Partial-token safety is preserved: the replaced engine anchored pattern ends with (\s|$) ("no partial matches"), and element-wise matching is immune to partial-token matches by construction. (The legacy cashproof cross-check optimiser, optimiseBytecodeOld, has no such anchor and can corrupt adversarial scripts — after OP_NOT OP_IF -> OP_NOTIF its rule `OP_GREATERTHAN OP_NOT` matches inside `OP_GREATERTHAN OP_NOTIF`, yielding the invalid token OP_LESSTHANOREQUALIF — but that is a separate engine, unchanged by this commit.) Both behaviours are locked in by the seeded differential fuzz suite added in a follow-up commit. Unknown tokens in an optimisation pattern now throw at load instead of silently never matching. All debug metadata (source maps, requires, logs, source tags, inline ranges) is adjusted through the same position-adjustment path as before. Co-Authored-By: Claude Fable 5 --- packages/utils/src/script.ts | 176 +++++++++++++++++++++++++---------- 1 file changed, 129 insertions(+), 47 deletions(-) diff --git a/packages/utils/src/script.ts b/packages/utils/src/script.ts index 4d114a5e..365462c9 100644 --- a/packages/utils/src/script.ts +++ b/packages/utils/src/script.ts @@ -163,6 +163,77 @@ export interface OptimiseBytecodeResult { inlineRanges: InlineRange[]; } +// Pre-parse the ASM-string optimisation patterns into opcode-number sequences once, so the +// optimiser can match directly against the Script array instead of stringifying it to ASM and +// regex-scanning a growing string on every match. The old approach recovered each match's script +// index with [...processedAsm.matchAll(/\s+/g)].length over the growing prefix, making replaceOps +// O(asm-length) per match — quadratic in script size and pathological for large, constant-heavy +// contracts (e.g. the BN254 pairing chunks that bake dozens of 32-40 byte field constants). +interface ParsedOptimisation { + pattern: Op[]; + replacement: Op[]; + // The original pattern split into tokens, kept only for the console.log transformation bookkeeping. + patternTokens: string[]; +} + +function parseOpcodeTokens(asm: string): Op[] { + const trimmed = asm.trim(); + if (trimmed === '') return []; + return trimmed.split(/\s+/).map((token) => { + const op = Op[token as keyof typeof Op]; + // A typo'd token would otherwise parse to `undefined` and its pattern would silently never match + if (typeof op !== 'number') throw new Error(`Unknown opcode token '${token}' in optimisation pattern`); + return op; + }); +} + +const parsedOptimisations: ParsedOptimisation[] = optimisationReplacements.map(([pattern, replacement]) => ({ + pattern: parseOpcodeTokens(pattern), + replacement: parseOpcodeTokens(replacement), + patternTokens: pattern.trim() === '' ? [] : pattern.trim().split(/\s+/), +})); + +// Structural equality on Script arrays: opcodes by value, data pushes by byte content. Replaces the +// previous fixed-point check that compared scriptToAsm(old) === scriptToAsm(new) (a full stringify +// of both scripts every pass). +function scriptsEqual(a: Script, b: Script): boolean { + if (a.length !== b.length) return false; + for (let i = 0; i < a.length; i += 1) { + const x = a[i]; + const y = b[i]; + if (typeof x === 'number' || typeof y === 'number') { + if (x !== y) return false; + } else { + if (x.length !== y.length) return false; + for (let k = 0; k < x.length; k += 1) { + if (x[k] !== y[k]) return false; + } + } + } + return true; +} + +// The opcode a script element represents for matching purposes. Opcodes are stored as numbers, but +// small integer pushes are stored as data (encodeInt(0n) -> empty, 1n -> [1], -1n -> [0x81]); under +// minimal-push encoding these disassemble to OP_0 / OP_1..OP_16 / OP_1NEGATE, which the optimisation +// patterns reference. We derive that opcode exactly as scriptToBytecode/disassembly would: a data +// element whose minimal push is a single byte IS that opcode. Anything else (a genuine multi-byte +// data push) returns -1, which never equals a real opcode. +function elementOpcode(element: OpOrData): number { + if (typeof element === 'number') return element; + if (element.length >= 2) return -1; + const push = encodeDataPush(element); + return push.length === 1 ? push[0] : -1; +} + +// Does the optimisation pattern (a pure opcode sequence) match the script starting at `index`? +function patternMatchesAt(script: Script, index: number, pattern: Op[]): boolean { + for (let j = 0; j < pattern.length; j += 1) { + if (elementOpcode(script[index + j]) !== pattern[j]) return false; + } + return true; +} + export function optimiseBytecode( script: Script, locationData: FullLocationData, @@ -183,11 +254,11 @@ export function optimiseBytecode( sourceTags: newSourceTags, inlineRanges: newInlineRanges, } = replaceOps( - script, locationData, logs, requires, sourceTags, inlineRanges, constructorParamLength, optimisationReplacements, + script, locationData, logs, requires, sourceTags, inlineRanges, constructorParamLength, parsedOptimisations, ); // Break on fixed point - if (scriptToAsm(oldScript) === scriptToAsm(newScript)) break; + if (scriptsEqual(oldScript, newScript)) break; script = newScript; locationData = newLocationData; @@ -290,33 +361,54 @@ function replaceOps( sourceTags: SourceTagEntry[], inlineRanges: InlineRange[], constructorParamLength: number, - optimisations: string[][], + optimisations: ParsedOptimisation[], ): ReplaceOpsResult { - let asm = scriptToAsm(script); + const newScript: Script = [...script]; let newLocationData = [...locationData]; let newLogs = [...logs]; let newRequires = [...requires]; let newSourceTags = [...sourceTags]; let newInlineRanges = [...inlineRanges]; - optimisations.forEach(([pattern, replacement]) => { - let processedAsm = ''; - let asmToSearch = asm; + // Removal sites act as match barriers for the remainder of the pass, mirroring the string-based + // engine exactly: an empty replacement left a double space in the ASM, and no single-space + // pattern could match across it until the pass-end whitespace cleanup. A barrier value `b` + // blocks any match spanning the boundary between elements b-1 and b. + const barriers = new Set(); + const crossesBarrier = (index: number, length: number): boolean => { + for (const barrier of barriers) { + if (index < barrier && barrier < index + length) return true; + } + return false; + }; - // We add a space or end of string to the end of the pattern to ensure that we match the whole pattern - // (no partial matches) - const regex = new RegExp(`${pattern}(\\s|$)`, 'g'); + optimisations.forEach(({ pattern, replacement, patternTokens }) => { + const patternLength = pattern.length; + if (patternLength === 0) return; + const replacementLength = replacement.length; + const lengthDiff = patternLength - replacementLength; + + // Non-overlapping matches are collected up front against the sweep-start script (regex /g + // semantics): a replacement never participates in another match of the same rule, and neither + // does adjacency created by one of this rule's own removals. + const matchIndices: number[] = []; + let scanIndex = 0; + while (scanIndex <= newScript.length - patternLength) { + if (patternMatchesAt(newScript, scanIndex, pattern) && !crossesBarrier(scanIndex, patternLength)) { + matchIndices.push(scanIndex); + scanIndex += patternLength; + } else { + scanIndex += 1; + } + } - let matchIndex = asmToSearch.search(regex); - while (matchIndex !== -1) { - // We add the part before the match to the processed asm - processedAsm = mergeAsm(processedAsm, asmToSearch.slice(0, matchIndex)); + // Apply the splices left-to-right; earlier splices in this sweep shift later match positions. + let sweepShift = 0; + matchIndices.forEach((matchIndex) => { + const scriptIndex = matchIndex - sweepShift; - // We count the number of spaces in the processed asm + 1, which is equal to the script index - // We do the same thing to calculate the number of opcodes in the pattern and replacement - const scriptIndex = processedAsm === '' ? 0 : [...processedAsm.matchAll(/\s+/g)].length + 1; - const patternLength = [...pattern.matchAll(/\s+/g)].length + 1; - const replacementLength = replacement === '' ? 0 : [...replacement.matchAll(/\s+/g)].length + 1; + // Splice the matched pattern out of the script array, inserting the replacement opcodes. + newScript.splice(scriptIndex, patternLength, ...replacement); // We get the locationData entries for every opcode in the pattern const patternLocations = newLocationData.slice(scriptIndex, scriptIndex + patternLength); @@ -347,8 +439,6 @@ function replaceOps( const replacementLocations = new Array(replacementLength).fill(mergedLocation); newLocationData.splice(scriptIndex, patternLength, ...replacementLocations); - const lengthDiff = patternLength - replacementLength; // 2 or 1 - // The IP of an opcode in the script is its index within the script + the constructor parameters, because // the constructor parameters still have to get added to the front of the script when a new Contract is created. const scriptIp = scriptIndex + constructorParamLength; @@ -382,7 +472,7 @@ function replaceOps( } const addedTransformationsCount = data.ip - scriptIp; - const addedTransformations = [...pattern.split(/\s+/g)].slice(0, addedTransformationsCount).join(' '); + const addedTransformations = patternTokens.slice(0, addedTransformationsCount).join(' '); const newTransformations = data.transformations ? `${addedTransformations} ${data.transformations}` : addedTransformations; return { @@ -394,11 +484,13 @@ function replaceOps( }; }); - // Source tags use raw script indices (no constructor offset), so they adjust against scriptIndex + // Source tags use raw script indices (no constructor offset), so they adjust against the + // script index (snapshotted to a const since scriptIndex advances as the scan continues) + const tagIndex = scriptIndex; newSourceTags = newSourceTags.map((tag) => ({ ...tag, - startIndex: adjustPosition(tag.startIndex, scriptIndex), - endIndex: adjustPosition(tag.endIndex, scriptIndex), + startIndex: adjustPosition(tag.startIndex, tagIndex), + endIndex: adjustPosition(tag.endIndex, tagIndex), })); // Inline ranges use ip coordinates (like requires), so both bounds adjust against scriptIp @@ -408,27 +500,22 @@ function replaceOps( endIp: adjustPosition(inlineRange.endIp, scriptIp), })); - // We add the replacement to the processed asm - processedAsm = mergeAsm(processedAsm, replacement); - - // We do not add the matched pattern anywhere since it gets replaced - - // We set the asmToSearch to the part after the match - asmToSearch = asmToSearch.slice(matchIndex + pattern.length).trim(); - - // Find the next match - matchIndex = asmToSearch.search(regex); - } - - // We add the remaining asm to the processed asm - processedAsm = mergeAsm(processedAsm, asmToSearch); + // Keep barrier positions aligned with the spliced script (a barrier strictly inside the + // matched range is impossible — it would have blocked the match), then record the removal + // site of an empty replacement as a new barrier. + if (barriers.size > 0) { + const shifted = [...barriers].map((barrier) => (barrier > scriptIndex ? barrier - lengthDiff : barrier)); + barriers.clear(); + shifted.forEach((barrier) => barriers.add(barrier)); + } + if (replacementLength === 0) barriers.add(scriptIndex); - // We replace the original asm with the processed asm so that the next optimisation can use the updated asm - asm = processedAsm; + sweepShift += lengthDiff; + }); }); return { - script: asmToScript(asm), + script: newScript, locationData: newLocationData, logs: newLogs, requires: newRequires, @@ -469,8 +556,3 @@ const getLowestStartLocation = (locations: SingleLocationData[]): SingleLocation }, locations[0]); }; -const mergeAsm = (asm1: string, asm2: string): string => { - // We merge two ASM strings by adding a space between them, and removing any duplicate spaces - // or trailing/leading spaces, which might have been introduced due to regex matching / replacements / empty asm strings - return `${asm1} ${asm2}`.replace(/\s+/g, ' ').trim(); -}; From 7186fe18391f6f4a4b300f127e215363b7de98df Mon Sep 17 00:00:00 2001 From: Mathieu Geukens Date: Thu, 2 Jul 2026 22:44:43 +0200 Subject: [PATCH 04/12] perf(cashc): gate the legacy-optimiser cross-check by size and a compiler flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every compile currently optimises twice — once for real, once with the legacy ASM-regex optimiser purely to check that both produce the same bytecode. On very large generated contracts that redundant second pass measurably slows compiles (~0.15s at 10k elements, ~0.5s at 30-40k; near-linear in practice, not quadratic), so the check is now skipped automatically above 30k unoptimised ops and can be skipped explicitly with the new `disableOptimisationCrossCheck` option (e.g. for codegen pipelines that compile many contracts). The flag lives in InternalCompilerOptions (like disableInlining), not the public artifact CompilerOptions: it has zero effect on the produced bytecode, so it is neither public API nor serialized into artifacts. Above the gate, the new optimiser's correctness rests on the differential fuzz suite rather than the per-compile check. Co-Authored-By: Claude Fable 5 --- packages/cashc/src/compiler.ts | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/packages/cashc/src/compiler.ts b/packages/cashc/src/compiler.ts index 3a6b538c..9297e726 100644 --- a/packages/cashc/src/compiler.ts +++ b/packages/cashc/src/compiler.ts @@ -41,6 +41,12 @@ export const DEFAULT_COMPILER_OPTIONS: CompilerOptions = { enforceLocktimeGuard: true, }; +// Above this unoptimised op-count the legacy-optimiser cross-check is skipped automatically. +// The legacy optimiser is near-linear in practice (measured ~0.15s at 10k elements, ~0.5s at +// 30-40k), so this gate bounds the cost of a redundant second optimisation pass on very large +// generated contracts — it is not guarding against asymptotic blowup. +const OPTIMISATION_CROSS_CHECK_MAX_OPS = 30_000; + export interface CompileOptions extends CompilerOptions { errorListener?: CashScriptErrorListener; } @@ -76,6 +82,10 @@ export const compileFile: (codeFile: PathLike, compilerOptions?: CompileOptions) export interface InternalCompilerOptions extends CompilerOptions { disableInlining?: boolean; + // Skip the backwards-compat cross-check that re-optimises the bytecode with the legacy + // ASM-regex optimiser and compares the results. The check is also skipped automatically for + // very large scripts, where the redundant second optimisation pass measurably slows compiles. + disableOptimisationCrossCheck?: boolean; } export function compileStringInternal( @@ -102,7 +112,9 @@ function compileCode( resolver: ImportResolver, compilerOptions: CompileOptions & InternalCompilerOptions, ): Artifact { - const { errorListener, disableInlining, ...artifactCompilerOptions } = compilerOptions; + const { + errorListener, disableInlining, disableOptimisationCrossCheck, ...artifactCompilerOptions + } = compilerOptions; const mergedCompilerOptions = { ...DEFAULT_COMPILER_OPTIONS, ...artifactCompilerOptions }; // Lexing + parsing @@ -135,7 +147,6 @@ function compileCode( ast = ast.accept(traversal) as Ast; // Bytecode optimisation - const optimisedBytecodeOld = optimiseBytecodeOld(traversal.output); const optimisationResult = optimiseBytecode( traversal.output, sourceMapToLocationData(traversal.sourceMap), @@ -146,10 +157,18 @@ function compileCode( constructorParamLength, ); - if (scriptToAsm(optimisedBytecodeOld) !== scriptToAsm(optimisationResult.script)) { - console.error(scriptToAsm(optimisedBytecodeOld)); - console.error(scriptToAsm(optimisationResult.script)); - throw new Error('New bytecode optimisation is not backwards compatible, please report this issue to the CashScript team'); + // Backwards-compat cross-check against the legacy ASM-regex optimiser. The legacy optimiser is + // near-linear in practice (~0.15s at 10k elements, ~0.5s at 30-40k measured), so the size gate + // is about not paying a redundant second optimisation pass on very large generated contracts, + // not about asymptotic blowup; the new optimiser is exercised by the full test suite either + // way. Skippable explicitly via the disableOptimisationCrossCheck compiler option. + if (!disableOptimisationCrossCheck && traversal.output.length <= OPTIMISATION_CROSS_CHECK_MAX_OPS) { + const optimisedBytecodeOld = optimiseBytecodeOld(traversal.output); + if (scriptToAsm(optimisedBytecodeOld) !== scriptToAsm(optimisationResult.script)) { + console.error(scriptToAsm(optimisedBytecodeOld)); + console.error(scriptToAsm(optimisationResult.script)); + throw new Error('New bytecode optimisation is not backwards compatible, please report this issue to the CashScript team'); + } } const debug = { From f9816e71c1617b13b531ede2ee42f123bb71fcc1 Mon Sep 17 00:00:00 2001 From: Mathieu Geukens Date: Thu, 23 Jul 2026 13:36:53 +0200 Subject: [PATCH 05/12] perf(cashc): keep loop-resident functions OP_DEFINE'd to avoid stepping cost MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The VM charges for every opcode inside a loop on every iteration — including opcodes on branches that don't execute that iteration. Inlining a function body into a loop therefore multiplies its cost by the iteration count, while calling it as a defined function costs just 2 stepped opcodes per iteration at the call site. So functions with a call site inside a loop — directly, or via the callee chain of such a function — are excluded from inlining and stay shared via OP_DEFINE (measured ~2.8x op-cost regression from inlining on sparse-input double-and-add loops, where the body sits in a rarely-taken `if`). A for-loop's init statement runs once, before OP_BEGIN, so a call appearing only there is not loop-resident and stays inlinable. Tiny bodies (<= 2 script elements) stay exempt from the exclusion: inlined they step no more opcodes than the invoke site even when skipped and execute fewer when taken; whether they actually inline is still decided by the byte model. The exclusion is deliberately coarse rather than branch-aware: a callee on a loop-resident caller's always-path costs only ~2 stepped ops per invocation plus ~5 define bytes when kept defined, and the asymmetry (2 ops/iteration sacrificed vs ~100 x body-size/iteration protected) makes conservative the right default even for always-executed single-use loop calls, where inlining would save the 201/call invoke overhead. Co-Authored-By: Claude Fable 5 --- .../src/generation/GenerateTargetTraversal.ts | 10 +- packages/cashc/src/generation/inlining.ts | 98 ++++++++++++++++++- .../cashc/test/global-definitions.test.ts | 70 +++++++++++++ 3 files changed, 175 insertions(+), 3 deletions(-) diff --git a/packages/cashc/src/generation/GenerateTargetTraversal.ts b/packages/cashc/src/generation/GenerateTargetTraversal.ts index d98e0ef5..a8ff3cd7 100644 --- a/packages/cashc/src/generation/GenerateTargetTraversal.ts +++ b/packages/cashc/src/generation/GenerateTargetTraversal.ts @@ -73,7 +73,9 @@ import { compileUnaryOp, } from './utils.js'; import { isNumericType } from '../utils.js'; -import { collectFunctionCalls, isRecursive, shouldInline } from './inlining.js'; +import { + collectFunctionCalls, collectLoopResidentFunctions, isRecursive, shouldInline, +} from './inlining.js'; import type { InternalCompilerOptions } from '../compiler.js'; interface InlineRange { @@ -204,6 +206,7 @@ export default class GenerateTargetTraversal extends AstTraversal { }); const reachableCalls = [node.contract!, ...node.functions].flatMap((n) => collectFunctionCalls(n)); + const loopResidentFunctions = collectLoopResidentFunctions(node); const definedFunctions: Array<{ func: FunctionDefinitionNode, compiledResult: OptimiseBytecodeResult }> = []; let nextFunctionId = recursiveFunctions.length; @@ -212,7 +215,10 @@ export default class GenerateTargetTraversal extends AstTraversal { const compiledResult = this.compileGlobalFunctionBody(func); // If the function should be inlined, we ONLY update the symbol - if (shouldInline(symbol, compiledResult, reachableCalls, nextFunctionId, this.compilerOptions)) { + const inline = shouldInline( + symbol, compiledResult, reachableCalls, loopResidentFunctions, nextFunctionId, this.compilerOptions, + ); + if (inline) { symbol.setInlinedBytecode(compiledResult.script, this.buildDebugFrame(func, compiledResult)); return; } diff --git a/packages/cashc/src/generation/inlining.ts b/packages/cashc/src/generation/inlining.ts index 3ecad1f5..58c8ad91 100644 --- a/packages/cashc/src/generation/inlining.ts +++ b/packages/cashc/src/generation/inlining.ts @@ -4,7 +4,18 @@ import { Script, scriptToBytecode, } from '@cashscript/utils'; -import { FunctionCallNode, FunctionDefinitionNode, Node } from '../ast/AST.js'; +import { + AssignNode, + BlockNode, + DoWhileNode, + ForNode, + FunctionCallNode, + FunctionDefinitionNode, + Node, + SourceFileNode, + VariableDefinitionNode, + WhileNode, +} from '../ast/AST.js'; import AstTraversal from '../ast/AstTraversal.js'; import { Symbol } from '../ast/SymbolTable.js'; import type { InternalCompilerOptions } from '../compiler.js'; @@ -13,12 +24,27 @@ export const shouldInline = ( symbol: Symbol, optimisedResult: OptimiseBytecodeResult, reachableCalls: FunctionCallNode[], + loopResidentFunctions: Set, nextFunctionId: number, compilerOptions: InternalCompilerOptions, ): boolean => { if (compilerOptions.disableInlining) return false; if (symbol.functionId !== undefined) return false; + // Loop-resident functions stay OP_DEFINE'd to avoid stepping cost. Tiny bodies (<= 2 script + // elements) are exempt: inlined they step no more opcodes than the 2-op invoke site even when + // skipped and execute fewer when taken, so the op-cost axis cannot lose. Bytes can still lose + // (a 2-element body may carry a large push), so whether inlining actually happens is still + // decided by the byte model below. + const definition = symbol.definition; + if ( + definition instanceof FunctionDefinitionNode + && loopResidentFunctions.has(definition) + && optimisedResult.script.length > 2 + ) { + return false; + } + const callCount = reachableCalls.filter((call) => call.identifier.symbol === symbol).length; return isWorthInlining(nextFunctionId, optimisedResult.script, callCount); }; @@ -72,3 +98,73 @@ function calledFunctions(func: FunctionDefinitionNode): FunctionDefinitionNode[] .filter((definition): definition is FunctionDefinitionNode => definition instanceof FunctionDefinitionNode) .filter((definition, index, definitions) => definitions.indexOf(definition) === index); } + +// Functions that must stay OP_DEFINE'd because a call site sits inside a loop — directly, or via +// the callee chain of such a function. Splicing a body into a loop makes every iteration step over +// it, and the VM charges per-opcode cost even for opcodes in an untaken branch, so a small byte +// saving multiplies into a large op-cost regression (measured ~2.8x on sparse-input double-and-add +// loops, where the group-law body sits in a rarely-taken `if`). With OP_DEFINE the skipped call +// site costs 2 stepped opcodes instead of the whole body. +// +// The callee closure protects callees on CONDITIONAL paths inside a loop-resident caller: the +// caller's defined body is stepped end-to-end on every invoke, so a callee inlined into one of its +// untaken branches would be stepped per invocation too. A callee on the caller's always-path is +// stepped ≈ executed either way, so excluding it over-approximates — but the residual cost is only +// ~2 stepped ops per invocation (paid on every call) plus ~5 define bytes per function, so the +// closure is kept coarse rather than branch-aware. Same +// deliberate imprecision for always-executed call sites directly in loops: inlining there would +// actually save the 2 invoke ops per iteration, but the asymmetry (2 ops/iteration sacrificed vs +// ~100×body-size/iteration protected) makes conservative the right default. +export function collectLoopResidentFunctions(node: SourceFileNode): Set { + const loopResident = new Set(); + let loopDepth = 0; + + const collector = new class extends AstTraversal { + visitWhile(n: WhileNode): Node { + loopDepth += 1; + const result = super.visitWhile(n); + loopDepth -= 1; + return result; + } + + visitDoWhile(n: DoWhileNode): Node { + loopDepth += 1; + const result = super.visitDoWhile(n); + loopDepth -= 1; + return result; + } + + visitFor(n: ForNode): Node { + // The init statement runs once, before OP_BEGIN, so a call there is not loop-resident; + // only the condition, update, and body are re-stepped every iteration. + n.init = this.visit(n.init) as VariableDefinitionNode | AssignNode; + loopDepth += 1; + n.condition = this.visit(n.condition); + n.update = this.visit(n.update) as AssignNode; + n.block = this.visit(n.block) as BlockNode; + loopDepth -= 1; + return n; + } + + visitFunctionCall(n: FunctionCallNode): Node { + const definition = n.identifier.symbol?.definition; + if (loopDepth > 0 && definition instanceof FunctionDefinitionNode) loopResident.add(definition); + return super.visitFunctionCall(n); + } + }(); + + node.functions.forEach((func) => collector.visit(func.body)); + if (node.contract) collector.visit(node.contract); + + // Close over the callee chain of every loop-resident function. + const queue = [...loopResident]; + while (queue.length > 0) { + calledFunctions(queue.shift()!).forEach((callee) => { + if (loopResident.has(callee)) return; + loopResident.add(callee); + queue.push(callee); + }); + } + + return loopResident; +} diff --git a/packages/cashc/test/global-definitions.test.ts b/packages/cashc/test/global-definitions.test.ts index 4c9ff5a2..6cdcfb7b 100644 --- a/packages/cashc/test/global-definitions.test.ts +++ b/packages/cashc/test/global-definitions.test.ts @@ -177,6 +177,76 @@ describe('Inlining and shared definitions', () => { expect(bytecode).toContain('OP_INVOKE'); }); + it('keeps a function called inside a loop shared via OP_DEFINE (skipped-branch stepping cost)', () => { + const code = ` + function big(int x) returns (int) { return (x * 7 + 3) * (x + 11) - 5; } + contract C() { + function spend(int n) { + int acc = 0; + for (int i = 0; i < 10; i = i + 1) { + if (n > i) { acc = big(acc + i); } + } + require(acc > 0); + } + }`; + + const { bytecode } = compileString(code); + expect(bytecode).toContain('OP_DEFINE'); + expect(bytecode).toContain('OP_INVOKE'); + }); + + it('keeps the callees of a loop-called function shared too (they would be stepped per iteration)', () => { + const code = ` + function inner(int x) returns (int) { return (x * 7 + 3) * (x + 11) - 5; } + function outer(int x) returns (int) { if (x > 5) { x = inner(x); } return x; } + contract C() { + function spend(int n) { + int acc = 0; + for (int i = 0; i < 10; i = i + 1) { acc = outer(acc + n); } + require(acc > 0); + } + }`; + + // both outer and inner stay defined -> two OP_DEFINEs + const { bytecode } = compileString(code); + expect(countOp(bytecode, 'OP_DEFINE')).toEqual(2); + expect(bytecode).toContain('OP_INVOKE'); + }); + + it('inlines a function whose only call site is a for-loop initializer (runs before OP_BEGIN)', () => { + const code = ` + function calc(int x) returns (int) { return (x * 7 + 3) * (x + 11) - 5; } + contract C() { + function spend(int n) { + int acc = 0; + for (int i = calc(n); i < 10; i = i + 1) { acc = acc + i; } + require(acc > 0); + } + }`; + + const { bytecode } = compileString(code); + expect(bytecode).not.toContain('OP_DEFINE'); + expect(bytecode).not.toContain('OP_INVOKE'); + }); + + it('still inlines a tiny body inside a loop (steps no more than the invoke site would)', () => { + const code = ` + function inc(int x) returns (int) { return x + 1; } + contract C() { + function spend(int n) { + int acc = 0; + for (int i = 0; i < 10; i = i + 1) { + if (n > i) { acc = inc(acc); } + } + require(acc > 0); + } + }`; + + const { bytecode } = compileString(code); + expect(bytecode).not.toContain('OP_DEFINE'); + expect(bytecode).not.toContain('OP_INVOKE'); + }); + it('ignores call sites inside eliminated functions when deciding to inline', () => { const code = ` function big(int x) returns (int) { return (x * 7 + 3) * (x + 11) - 5; } From 70ff675a017a6e72d9d32c7b2b0d9ad07fb9feed Mon Sep 17 00:00:00 2001 From: Mathieu Geukens Date: Thu, 23 Jul 2026 13:41:43 +0200 Subject: [PATCH 06/12] feat(cashc): hoist repeated in-body constants under a new optimizeFor objective MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A contract that pushes the same 32-byte constant five times pays for it five times; binding it to a local once and picking it off the stack is much smaller. This commit adds that rewrite, plus the compiler objective that decides when trades like it are worth making. `optimizeFor: 'size' | 'opcost'` (default 'opcost', CLI: -O / --optimize-for) is the single switch for compiler decisions that trade bytecode size against executed op-cost, and the intended home for future decisions on the same axis (e.g. the function-call convention) — one objective option instead of an accumulating set of booleans that each secretly encode the same question. The objective is a property of the deployment context, not the source, hence an option. DEFAULT_COMPILER_OPTIONS carries it explicitly so artifacts always record the objective they were compiled under (a default-objective compile stays reproducible from its own recorded options if the default ever changes). Under 'size', an AST pass before semantic analysis binds a raw literal occurring two or more times within one function body to a local, turning later uses into stack picks instead of repeated pushes (~-30 bytes per duplicate of a 32-byte constant, ~+2 ops per execution of the binding). The default 'opcost' objective skips it: right for op-bound contracts, whose unlocking scripts are zero-padded to buy op budget — there byte savings are free anyway and the extra ops translate directly into more padding. Literal-sensitive positions are excluded from both counting and replacement, because several compiler analyses require a literal in place and replacing it with an identifier would break or silently disable them: split/slice bounds and toPaddedBytes sizes (bounded-type inference and the static IndexOutOfBoundsError), literals compared against .length (bytes narrowing), bit-shift counts, console.log parameters (debug-only data must not inflate real bytecode), and time-op operands (the locktime-guard heuristic keys on them). As defense in depth, the 'size' objective compiles both variants and keeps the hoisted compile only when it is strictly smaller — hoisting can never grow a contract or mask a compile error. - exact byte accounting gates each hoist ((count-1) x pushBytes vs pick+cleanup overhead), so small literals are never pessimised - covers int and hex literals; named top-level constants are already deduplicated by the shared-definition mechanism, so only raw literals are targeted - introduced locals borrow source locations from the body (source maps stay valid) and dodge every name already used in the body, including parameter names and tuple targets Co-Authored-By: Claude Fable 5 --- packages/cashc/src/cashc-cli.ts | 5 + packages/cashc/src/compiler.ts | 41 ++- packages/cashc/src/constant-hoisting.ts | 245 ++++++++++++++++++ packages/cashc/test/compiler/compiler.test.ts | 1 + packages/cashc/test/constant-hoisting.test.ts | 186 +++++++++++++ packages/cashc/test/generation/fixtures.ts | 42 +++ packages/utils/src/artifact.ts | 9 + 7 files changed, 528 insertions(+), 1 deletion(-) create mode 100644 packages/cashc/src/constant-hoisting.ts create mode 100644 packages/cashc/test/constant-hoisting.test.ts diff --git a/packages/cashc/src/cashc-cli.ts b/packages/cashc/src/cashc-cli.ts index 997b0a3e..e263eba9 100644 --- a/packages/cashc/src/cashc-cli.ts +++ b/packages/cashc/src/cashc-cli.ts @@ -27,6 +27,10 @@ program .option('-s, --size', 'Display the size in bytes of the compiled bytecode.') .option('-S, --skip-enforce-function-parameter-types', 'Do not enforce function parameter types.') .option('-L, --skip-enforce-locktime-guard', 'Do not inject a tx.time guard when tx.locktime is used.') + .addOption( + new Option('-O, --optimize-for ', 'Optimisation objective: minimise bytecode size or executed op-cost (default).') + .choices(['size', 'opcost']), + ) .addOption( new Option('-f, --format ', 'Specify the format of the output.') .choices(['json', 'ts']) @@ -53,6 +57,7 @@ function run(): void { const compilerOptions: CompilerOptions = { enforceFunctionParameterTypes: !opts.skipEnforceFunctionParameterTypes, enforceLocktimeGuard: !opts.skipEnforceLocktimeGuard, + ...(opts.optimizeFor ? { optimizeFor: opts.optimizeFor } : {}), }; try { diff --git a/packages/cashc/src/compiler.ts b/packages/cashc/src/compiler.ts index 9297e726..bfc176c5 100644 --- a/packages/cashc/src/compiler.ts +++ b/packages/cashc/src/compiler.ts @@ -35,10 +35,14 @@ import EnsureFunctionsSafeTraversal from './semantic/EnsureFunctionsSafeTraversa import InjectLocktimeGuardTraversal from './semantic/InjectLocktimeGuardTraversal.js'; import DeadCodeEliminationTraversal from './semantic/DeadCodeEliminationTraversal.js'; import { LowerGlobalConstantsTraversal } from './semantic/LowerGlobalConstantsTraversal.js'; +import { hoistRepeatedConstants } from './constant-hoisting.js'; export const DEFAULT_COMPILER_OPTIONS: CompilerOptions = { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + // recorded explicitly so artifacts always state the objective they were compiled under + // (see CompilerOptions in @cashscript/utils for the size/opcost trade-off) + optimizeFor: 'opcost', }; // Above this unoptimised op-count the legacy-optimiser cross-check is skipped automatically. @@ -86,6 +90,10 @@ export interface InternalCompilerOptions extends CompilerOptions { // ASM-regex optimiser and compares the results. The check is also skipped automatically for // very large scripts, where the redundant second optimisation pass measurably slows compiles. disableOptimisationCrossCheck?: boolean; + // Skip constant hoisting. Under `optimizeFor: 'size'`, repeated in-body literals are bound to + // locals when that shrinks the bytecode (the compiler keeps the hoisted compile only when it + // is strictly smaller). This flag is for tools that need the literal-shaped compile as input. + disableConstantHoisting?: boolean; } export function compileStringInternal( @@ -111,9 +119,33 @@ function compileCode( code: string, resolver: ImportResolver, compilerOptions: CompileOptions & InternalCompilerOptions, +): Artifact { + const optimizeFor = compilerOptions.optimizeFor ?? DEFAULT_COMPILER_OPTIONS.optimizeFor; + if (optimizeFor !== 'size' || compilerOptions.disableConstantHoisting) { + return compileImpl(code, resolver, compilerOptions, false); + } + + // Hoisting helps most contracts but can cost bytes on some, so the 'size' objective compiles + // both variants and keeps the hoisted compile only when it is strictly smaller. + const hoisted = compileImpl(code, resolver, compilerOptions, true); + const unhoisted = compileImpl(code, resolver, compilerOptions, false); + const compiledBytes = (artifact: Artifact): number => artifact.debug?.bytecode.length ?? artifact.bytecode.length; + return compiledBytes(hoisted) < compiledBytes(unhoisted) ? hoisted : unhoisted; +} + +function compileImpl( + code: string, + resolver: ImportResolver, + compilerOptions: CompileOptions & InternalCompilerOptions, + hoistConstants: boolean, ): Artifact { const { - errorListener, disableInlining, disableOptimisationCrossCheck, ...artifactCompilerOptions + errorListener, disableInlining, disableOptimisationCrossCheck, + // consumed in compileCode (which picks the hoisted or unhoisted compile); destructured here + // only to keep it out of the serialized artifact options + // eslint-disable-next-line @typescript-eslint/no-unused-vars + disableConstantHoisting, + ...artifactCompilerOptions } = compilerOptions; const mergedCompilerOptions = { ...DEFAULT_COMPILER_OPTIONS, ...artifactCompilerOptions }; @@ -122,6 +154,13 @@ function compileCode( checkVersionConstraints(ast.pragmas); ast = resolveDependencies(ast, resolver, errorListener) as Ast; + + // Under the 'size' objective, bind repeated in-body literals to locals (see CompilerOptions). + // Runs before semantic analysis so the introduced locals get symbols like any other variable. + if (hoistConstants) { + ast = hoistRepeatedConstants(ast) as Ast; + } + if (!ast.contract) throw new MissingContractError(); const constructorParamLength = ast.contract.parameters.length; diff --git a/packages/cashc/src/constant-hoisting.ts b/packages/cashc/src/constant-hoisting.ts new file mode 100644 index 00000000..bd561c9e --- /dev/null +++ b/packages/cashc/src/constant-hoisting.ts @@ -0,0 +1,245 @@ +import { binToHex } from '@bitauth/libauth'; +import { encodeInt, scriptToBytecode } from '@cashscript/utils'; +import { + SourceFileNode, + FunctionDefinitionNode, + BlockNode, + LiteralNode, + IntLiteralNode, + HexLiteralNode, + IdentifierNode, + VariableDefinitionNode, + ParameterNode, + TupleAssignmentNode, + BinaryOpNode, + UnaryOpNode, + SliceNode, + FunctionCallNode, + ConsoleStatementNode, + TimeOpNode, + ExpressionNode, + Node, +} from './ast/AST.js'; +import { BinaryOperator, UnaryOperator } from './ast/Operator.js'; +import { GlobalFunction } from './ast/Globals.js'; +import AstTraversal from './ast/AstTraversal.js'; + +// Byte-size optimisation with an op-cost trade-off, so gated behind `optimizeFor: 'size'`: +// a literal that occurs two or more times within one function body is bound to a local at the +// top of the body when that is cheaper by exact byte accounting, and the occurrences become +// identifier references. The second and later uses then cost a stack pick instead of re-pushing +// the literal (~-30 bytes per duplicate of a 32-byte field prime), at the price of a couple of +// extra ops per call for the binding and cleanup. +// +// That trade is right for size-scored contracts and wrong for op-bound ones (where unlocking +// scripts are zero-padded to buy op budget, byte savings are free anyway and the extra ops +// translate directly into more padding) — hence the default 'opcost' objective skips it. +// +// Runs before semantic analysis, so the introduced locals get symbols like any other variable. +// Only raw literals are targeted: uses of named top-level constants are still identifiers at +// this point, and repeated large constants are already deduplicated by the shared-definition +// mechanism (LowerGlobalConstantsTraversal + OP_DEFINE/OP_INVOKE sharing). +// +// Several later passes pattern-match literal nodes in specific syntactic positions, so those +// occurrences must keep their literal shape and are excluded from both counting and replacement +// (see ExcludedLiteralCollector). The pass is additionally guarded in compileCode: the hoisted +// compile is only kept when the final artifact is strictly smaller than the unhoisted one. + +export function hoistRepeatedConstants(ast: SourceFileNode): SourceFileNode { + ast.functions.forEach((func) => hoistInBody(func.body, func.parameters)); + ast.contract?.functions.forEach((func: FunctionDefinitionNode) => hoistInBody(func.body, func.parameters)); + return ast; +} + +// Exact byte accounting: replacing each duplicate push with an identifier access costs about +// 2 bytes (depth + OP_PICK; the declaration itself re-uses the first push) plus ~1 byte of +// end-of-scope cleanup, so hoisting pays when the duplicates' push bytes beat that overhead. +const worthHoisting = (pushBytes: number, count: number): boolean => (count - 1) * pushBytes > 2 * (count - 1) + 1; + +function hoistInBody(body: BlockNode, parameters: ParameterNode[]): void { + if (!body.statements || body.statements.length === 0) return; + + const excluded = collectExcludedLiterals(body); + + const counter = new LiteralCounter(excluded); + // Parameters live outside the body, so seed their names explicitly — a parameter named `hc0` + // must not collide with a generated local. + parameters.forEach((parameter) => counter.usedNames.add(parameter.name)); + counter.visit(body); + + const hoisted = [...counter.literals.values()] + .filter(({ pushBytes, count }) => worthHoisting(pushBytes, count)); + if (hoisted.length === 0) return; + + // Fresh local names that collide with nothing already named in the body. + const names = new Map(); + let n = 0; + for (const { key } of hoisted) { + while (counter.usedNames.has(`hc${n}`)) n += 1; + names.set(key, `hc${n}`); + n += 1; + } + + new LiteralReplacer(names, excluded).visit(body); + + // Declarations go at the very top of the body; source locations borrow from the first + // statement so source-map generation always has a valid location to point at. + const location = body.statements[0].location; + const declarations = hoisted.map(({ key, template }) => { + const literal = cloneLiteral(template); + literal.location = location; + const definition = new VariableDefinitionNode(template.type!, [], names.get(key)!, literal); + definition.location = location; + return definition; + }); + body.statements.unshift(...declarations); +} + +type Hoistable = IntLiteralNode | HexLiteralNode; + +const literalKey = (node: Hoistable): string => ( + node instanceof IntLiteralNode ? `i${node.value}` : `x${binToHex(node.value)}` +); + +const literalPushBytes = (node: Hoistable): number => ( + scriptToBytecode([node instanceof IntLiteralNode ? encodeInt(node.value) : node.value]).length +); + +function cloneLiteral(node: Hoistable): LiteralNode { + return node instanceof IntLiteralNode ? new IntLiteralNode(node.value) : new HexLiteralNode(node.value); +} + +function collectExcludedLiterals(body: BlockNode): Set { + const collector = new ExcludedLiteralCollector(); + collector.visit(body); + return collector.excluded; +} + +// Split bounds and bit-shift counts: TypeCheckTraversal keys bounded-type inference and the +// static IndexOutOfBoundsError / BitshiftBitcountNegativeError checks on a literal right operand. +const BOUND_SENSITIVE_OPERATORS = [BinaryOperator.SPLIT, BinaryOperator.SHIFT_LEFT, BinaryOperator.SHIFT_RIGHT]; + +const isSizeOp = (node: ExpressionNode): boolean => ( + node instanceof UnaryOpNode && node.operator === UnaryOperator.SIZE +); + +// Marks the literal occurrences that later passes pattern-match syntactically, and which must +// therefore stay literals (they take part in neither counting nor replacement): +// - split / bit-shift right operands and slice bounds — bounded-type inference and static +// bounds checks in TypeCheckTraversal require literal nodes there; +// - toPaddedBytes size arguments — inferPaddedBytesType reads a literal second parameter; +// - literals compared against `.length` — TypeCheckTraversal narrows unbounded bytes from them; +// - console statement parameters — logs are stripped from the real bytecode, so hoisting them +// would materialise debug-only data as live stack values; +// - tx.time / this.age operands — InjectLocktimeGuardTraversal's isLocktimeCheck heuristic +// keys on a literal operand, and replacing it triggers a synthetic guard. +class ExcludedLiteralCollector extends AstTraversal { + excluded = new Set(); + + private exclude(node: Node | undefined): void { + if (node instanceof IntLiteralNode || node instanceof HexLiteralNode) this.excluded.add(node); + } + + visitBinaryOp(node: BinaryOpNode): Node { + if (BOUND_SENSITIVE_OPERATORS.includes(node.operator)) this.exclude(node.right); + if (isSizeOp(node.left)) this.exclude(node.right); + if (isSizeOp(node.right)) this.exclude(node.left); + return super.visitBinaryOp(node); + } + + visitSlice(node: SliceNode): Node { + this.exclude(node.start); + this.exclude(node.end); + return super.visitSlice(node); + } + + visitFunctionCall(node: FunctionCallNode): Node { + if (node.identifier.name === GlobalFunction.TO_PADDED_BYTES) this.exclude(node.parameters[1]); + return super.visitFunctionCall(node); + } + + visitConsoleStatement(node: ConsoleStatementNode): Node { + node.parameters.forEach((parameter) => this.exclude(parameter)); + return node; + } + + visitTimeOp(node: TimeOpNode): Node { + this.exclude(node.expression); + return super.visitTimeOp(node); + } +} + +// Counts hoistable literals by value and records every name already used in the body +// (identifiers, parameters, definitions, tuple targets), so the introduced locals cannot +// shadow or be shadowed by anything. +class LiteralCounter extends AstTraversal { + literals = new Map(); + usedNames = new Set(); + + constructor(private excluded: Set) { + super(); + } + + private countLiteral(node: Hoistable): void { + if (this.excluded.has(node)) return; + const key = literalKey(node); + const entry = this.literals.get(key); + if (entry) entry.count += 1; + else this.literals.set(key, { key, template: node, pushBytes: literalPushBytes(node), count: 1 }); + } + + visitIntLiteral(node: IntLiteralNode): Node { + this.countLiteral(node); + return node; + } + + visitHexLiteral(node: HexLiteralNode): Node { + this.countLiteral(node); + return node; + } + + visitIdentifier(node: IdentifierNode): Node { + this.usedNames.add(node.name); + return node; + } + + visitParameter(node: ParameterNode): Node { + this.usedNames.add(node.name); + return node; + } + + visitVariableDefinition(node: VariableDefinitionNode): Node { + this.usedNames.add(node.name); + return super.visitVariableDefinition(node); + } + + visitTupleAssignment(node: TupleAssignmentNode): Node { + node.targets.forEach((target) => this.usedNames.add(target.name)); + return super.visitTupleAssignment(node); + } +} + +// Swaps each hoisted literal occurrence for a reference to its local. The identifier takes +// the literal's source location (same convention as constant inlining, in reverse). +class LiteralReplacer extends AstTraversal { + constructor(private names: Map, private excluded: Set) { + super(); + } + + private replace(node: Hoistable): Node { + if (this.excluded.has(node)) return node; + const name = this.names.get(literalKey(node)); + if (name === undefined) return node; + const identifier = new IdentifierNode(name); + identifier.location = node.location; + return identifier; + } + + visitIntLiteral(node: IntLiteralNode): Node { + return this.replace(node); + } + + visitHexLiteral(node: HexLiteralNode): Node { + return this.replace(node); + } +} diff --git a/packages/cashc/test/compiler/compiler.test.ts b/packages/cashc/test/compiler/compiler.test.ts index f121476c..d62c7ff1 100644 --- a/packages/cashc/test/compiler/compiler.test.ts +++ b/packages/cashc/test/compiler/compiler.test.ts @@ -86,6 +86,7 @@ describe('Compiler', () => { expect(artifact.compiler.options).toEqual({ enforceFunctionParameterTypes: true, enforceLocktimeGuard: false, + optimizeFor: 'opcost', }); }); }); diff --git a/packages/cashc/test/constant-hoisting.test.ts b/packages/cashc/test/constant-hoisting.test.ts new file mode 100644 index 00000000..6142f110 --- /dev/null +++ b/packages/cashc/test/constant-hoisting.test.ts @@ -0,0 +1,186 @@ +import { compileString } from '../src/index.js'; +import { IndexOutOfBoundsError } from '../src/Errors.js'; + +const P = '21888242871839275222246405745257275088696311157297823662689037894645226208583'; + +const asm = (code: string, hoist: boolean): string => ( + compileString(code, { optimizeFor: hoist ? 'size' : 'opcost' }).bytecode +); +const count = (haystack: string, needle: string): number => haystack.split(needle).length - 1; + +// The prime's minimal VM-number encoding as it appears in ASM (64 hex chars), derived +// from a single-use compile so the tests don't hardcode the encoding. +const PRIME_ASM = asm(`contract C() { function spend(int x) { require(x == ${P}); } }`, false) + .match(/[0-9a-f]{64}/)![0]; + +describe("Repeated-constant hoisting (optimizeFor: 'size')", () => { + const doubleUse = ` + contract C() { + function spend(int x, int y) { + require((x - y + ${P}) % ${P} == 1); + } + }`; + + it('is off by default: the duplicate literal is pushed twice', () => { + expect(count(asm(doubleUse, false), PRIME_ASM)).toBe(2); + }); + + it("defaults to the 'opcost' objective when the option is unset", () => { + expect(compileString(doubleUse).bytecode).toBe(asm(doubleUse, false)); + }); + + it('binds a duplicated big literal to a local under the flag', () => { + expect(count(asm(doubleUse, true), PRIME_ASM)).toBe(1); + }); + + it('shrinks the bytecode under the flag', () => { + expect(asm(doubleUse, true).length).toBeLessThan(asm(doubleUse, false).length); + }); + + it('hoists inside global function bodies too', () => { + const code = ` + function subFp(int x, int y) returns (int) { return (x - y + ${P}) % ${P}; } + contract C() { + function spend(int x, int y) { require(subFp(x, y) == 1); } + }`; + expect(count(asm(code, false), PRIME_ASM)).toBe(2); + expect(count(asm(code, true), PRIME_ASM)).toBe(1); + }); + + it('hoists a duplicated big hex literal', () => { + const blob = 'aa'.repeat(32); + const code = ` + contract C() { + function spend(bytes b) { + require(b.split(32)[0] == 0x${blob} || b.split(32)[1] == 0x${blob}); + } + }`; + expect(count(asm(code, false), blob)).toBe(2); + expect(count(asm(code, true), blob)).toBe(1); + }); + + it('leaves small repeated literals alone (hoisting would cost bytes)', () => { + const code = ` + contract C() { + function spend(int x) { require((x + 3) % 3 == 1); } + }`; + expect(asm(code, true)).toBe(asm(code, false)); + }); + + it('avoids colliding with existing names', () => { + const code = ` + contract C() { + function spend(int hc0, int y) { + require((hc0 - y + ${P}) % ${P} == 1); + } + }`; + expect(count(asm(code, true), PRIME_ASM)).toBe(1); // compiles (no shadowing), still hoisted + }); + + it('composes with named top-level constants', () => { + // A multi-use named constant is already deduplicated by the shared-definition mechanism + // (it compiles like a zero-argument function), so hoisting has nothing left to do — the + // prime appears once under either objective, and 'size' must not duplicate or break it. + const code = ` + int constant PRIME = ${P}; + contract C() { + function spend(int x, int y) { + require((x - y + PRIME) % PRIME == 1); + } + }`; + expect(count(asm(code, false), PRIME_ASM)).toBe(1); + expect(count(asm(code, true), PRIME_ASM)).toBe(1); + }); + + it('produces the same ABI either way', () => { + const a = compileString(doubleUse, { optimizeFor: 'size' }); + const b = compileString(doubleUse, { optimizeFor: 'opcost' }); + expect(a.abi).toEqual(b.abi); + }); +}); + +describe('Literal-sensitive positions are never hoisted', () => { + it('keeps split bounds literal so bounded-type inference survives', () => { + // Pre-exclusion, the repeated 500 was hoisted, split() lost its literal bound, the tuple + // degraded to (bytes, bytes) and the bytes500 assignment threw AssignTypeError. + const code = ` + contract C() { + function spend(bytes b, int i) { + require(i == 500); + require(i + 500 == 1000); + bytes500 x = b.split(500)[0]; + require(x.length == 500); + } + }`; + expect(() => asm(code, true)).not.toThrow(); + }); + + it("raises IndexOutOfBoundsError under 'size' exactly as under 'opcost'", () => { + // Pre-exclusion, hoisting the repeated 500 suppressed the static bounds check and the + // contract compiled into a script whose OP_SPLIT always fails at runtime. + const code = ` + contract C() { + function spend(bytes32 b, int i) { + require(i == 500); + require(i + 500 == 1000); + require(b.split(500)[0] != 0x00); + } + }`; + expect(() => asm(code, false)).toThrow(IndexOutOfBoundsError); + expect(() => asm(code, true)).toThrow(IndexOutOfBoundsError); + }); + + it('does not hoist literals that only appear in console.log statements', () => { + // Console logs are stripped from the real bytecode, so hoisting their literals would + // materialise debug-only data as live stack values and inflate the script. + const withConsole = ` + contract C() { + function spend(int x) { + console.log(${P}, ${P}); + require(x == 1); + } + }`; + const withoutConsole = ` + contract C() { + function spend(int x) { + require(x == 1); + } + }`; + expect(asm(withConsole, true)).toBe(asm(withoutConsole, true)); + }); + + it('keeps time-op operands literal so the locktime-guard heuristic still recognises them', () => { + // A require(this.age >= ) covers the tx.locktime read; hoisting the literal made + // the check unrecognisable and a synthetic guard (OP_CHECKLOCKTIMEVERIFY) was injected. + const code = ` + contract C() { + function spend(int x) { + require(this.age >= 100000); + require(x == 100000); + require(tx.locktime <= 100000 + x); + } + }`; + expect(count(asm(code, true), 'OP_CHECKLOCKTIMEVERIFY')).toBe(0); + }); +}); + +describe('Hoisting guardrail (compile-both-keep-smaller)', () => { + // LockingBytecodeNullData elements get cheaper codegen when they stay literals (the VarInt + // size prefix is computed at compile time), so hoisting the repeated element inflates the + // script — engineered inflation that the guardrail must reject. + const nulldata = ` + contract C() { + function spend() { + require(new LockingBytecodeNullData([0xaabbcc, 0xaabbcc]) != 0x00); + } + }`; + + it("never produces a 'size' artifact larger than the unhoisted compile", () => { + const unhoisted = compileString(nulldata, { optimizeFor: 'size', disableConstantHoisting: true }).bytecode; + expect(asm(nulldata, true).length).toBeLessThanOrEqual(unhoisted.length); + }); + + it('keeps the literal-shaped codegen when hoisting would inflate the script', () => { + expect(count(asm(nulldata, true), 'aabbcc')).toBe(2); // both stay literal element pushes + }); +}); diff --git a/packages/cashc/test/generation/fixtures.ts b/packages/cashc/test/generation/fixtures.ts index 3283c505..06972519 100644 --- a/packages/cashc/test/generation/fixtures.ts +++ b/packages/cashc/test/generation/fixtures.ts @@ -38,6 +38,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -84,6 +85,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -136,6 +138,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -182,6 +185,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -260,6 +264,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -288,6 +293,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -323,6 +329,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -356,6 +363,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -421,6 +429,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -458,6 +467,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -489,6 +499,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -527,6 +538,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -622,6 +634,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -705,6 +718,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -760,6 +774,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -788,6 +803,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -816,6 +832,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -847,6 +864,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -875,6 +893,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -905,6 +924,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -950,6 +970,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -981,6 +1002,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -1013,6 +1035,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -1045,6 +1068,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -1074,6 +1098,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -1103,6 +1128,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -1134,6 +1160,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -1176,6 +1203,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -1207,6 +1235,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -1239,6 +1268,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -1269,6 +1299,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -1298,6 +1329,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -1351,6 +1383,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -1403,6 +1436,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: false, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -1448,6 +1482,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -1494,6 +1529,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -1539,6 +1575,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -1615,6 +1652,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -1662,6 +1700,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -1709,6 +1748,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -1764,6 +1804,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', @@ -1811,6 +1852,7 @@ export const fixtures: Fixture[] = [ options: { enforceFunctionParameterTypes: true, enforceLocktimeGuard: true, + optimizeFor: 'opcost', }, }, updatedAt: '', diff --git a/packages/utils/src/artifact.ts b/packages/utils/src/artifact.ts index ba2c34d4..c2a4709f 100644 --- a/packages/utils/src/artifact.ts +++ b/packages/utils/src/artifact.ts @@ -1,8 +1,17 @@ export interface CompilerOptions { enforceFunctionParameterTypes?: boolean; enforceLocktimeGuard?: boolean; + // The optimisation objective for decisions that trade bytecode size against op-cost. + // 'size' minimises bytecode bytes (e.g. binds a literal repeated within one function body to a + // local, so later uses are ~2-byte stack picks instead of repeated pushes: ~-30 bytes per + // duplicate of a 32-byte constant, ~+2 ops per execution of the binding). 'opcost' (the + // default) minimises executed op-cost instead — right for op-bound contracts, whose unlocking + // scripts are zero-padded to buy op budget, making byte savings free and extra ops pure cost. + optimizeFor?: OptimizationTarget; } +export type OptimizationTarget = 'size' | 'opcost'; + export interface AbiInput { name: string; type: string; From 85fd7ef9e64797de222a200d36f6219b3ce9243a Mon Sep 17 00:00:00 2001 From: Mathieu Geukens Date: Thu, 23 Jul 2026 13:48:10 +0200 Subject: [PATCH 07/12] perf(cashc): stage user-function arguments right-to-left (first param on top) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Function bodies are now compiled against a first-parameter-on-top entry layout, and call sites stage arguments right-to-left. With arguments that are variables in declaration order (the overwhelmingly common case), the emitted ROLLs cancel to nothing in the optimiser — a typical call costs zero staging instructions, where the previous last-parameter-on-top convention paid reversal ops (OP_SWAP/OP_ROT chains growing with arity) at every call site. Reversed emission breaks the textual final-use order, so a variable is only ROLLed inside a call argument tree when it appears exactly once across the whole (possibly nested) tree (ArgIdentifierCounter / isOpRoll guard); everything else stays a PICK, with leftovers cleaned once per spend. Measured: on unrolled call-dense bodies (the BN254 lazy tower) the previous convention cost ~2 extra executed instructions per call x thousands of calls (~+2.9M op-cost on the groth16 residue pipeline, ~+5M on groth16-chunked). Static bytecode can grow slightly (per-spend cleanup replaces per-call staging); executed op-cost drops, which is what op-bound contracts price. Generation and bitauth-script fixtures updated to the new convention. Co-Authored-By: Claude Fable 5 --- .../src/generation/GenerateTargetTraversal.ts | 79 +++++++++++++++++-- .../test/compiler/unused-modifier.test.ts | 6 +- packages/cashc/test/generation/fixtures.ts | 45 ++++++----- .../test/fixtures/bitauth-script.fixture.ts | 4 +- 4 files changed, 102 insertions(+), 32 deletions(-) diff --git a/packages/cashc/src/generation/GenerateTargetTraversal.ts b/packages/cashc/src/generation/GenerateTargetTraversal.ts index a8ff3cd7..8097fb6a 100644 --- a/packages/cashc/src/generation/GenerateTargetTraversal.ts +++ b/packages/cashc/src/generation/GenerateTargetTraversal.ts @@ -101,6 +101,13 @@ export default class GenerateTargetTraversal extends AstTraversal { private constructorParameterCount: number; inlineRanges: InlineRange[] = []; + // Depth of nested user-function-call argument staging (see stageUserFunctionArguments). + private userCallArgDepth = 0; + // Per-variable occurrence counts across the outermost call's whole argument tree. Names appearing + // 2+ times stay OP_PICK (a ROLL under reversed emission would consume them too early). Populated + // when userCallArgDepth goes 0 -> 1 and cleared when it returns to 0. + private callArgNameCounts: Map | null = null; + constructor(private compilerOptions: InternalCompilerOptions) { super(); } @@ -253,11 +260,10 @@ export default class GenerateTargetTraversal extends AstTraversal { bodyTraversal.currentFunction = node; bodyTraversal.constructorParameterCount = 0; - // Seed the stack with parameters in reverse order so the last parameter is on top - // (similar to how builtin functions work) - for (let i = node.parameters.length - 1; i >= 0; i -= 1) { - bodyTraversal.visit(node.parameters[i]); - } + // Seed the stack with the parameters (visitParameter pushes them to the stack bottom in order, + // so the first parameter ends up on top) — matching the right-to-left argument staging at call + // sites, where declaration-order variable arguments then need no reordering at all. + node.parameters.forEach((parameter) => bodyTraversal.visit(parameter)); bodyTraversal.dropUnusedParameters(node.parameters); bodyTraversal.visit(node.body); @@ -814,7 +820,14 @@ export default class GenerateTargetTraversal extends AstTraversal { } const symbol = node.identifier.symbol!; - node.parameters = this.visitList(node.parameters); + + // User-defined function arguments are staged right-to-left (first argument on top, matching the + // body's parameter layout); built-in functions keep natural left-to-right evaluation. + if (symbol.definition instanceof FunctionDefinitionNode) { + this.stageUserFunctionArguments(node); + } else { + node.parameters = this.visitList(node.parameters); + } const startIp = this.output.length + this.constructorParameterCount; const endIp = startIp + symbol.bytecode!.length - 1; @@ -836,6 +849,30 @@ export default class GenerateTargetTraversal extends AstTraversal { return node; } + // Stages user-function call arguments right-to-left, so the first argument ends up on top of the + // stack — the layout the function body is compiled against. With arguments that are variables in + // declaration order (the common case), the emitted ROLLs then cancel to nothing in the optimiser, + // so a typical call costs zero staging instructions. Reversed emission breaks the textual + // final-use order, so at the outermost call each variable's occurrences are counted across the + // whole (possibly nested) argument tree: only names used exactly once may ROLL (see isOpRoll); + // everything else stays a PICK. + private stageUserFunctionArguments(node: FunctionCallNode): void { + const isOutermostCall = this.userCallArgDepth === 0; + if (isOutermostCall) { + const counter = new ArgIdentifierCounter(); + node.parameters.forEach((argument) => counter.visit(argument)); + this.callArgNameCounts = counter.counts; + } + + this.userCallArgDepth += 1; + for (let i = node.parameters.length - 1; i >= 0; i -= 1) { + node.parameters[i] = this.visit(node.parameters[i]); + } + this.userCallArgDepth -= 1; + + if (isOutermostCall) this.callArgNameCounts = null; + } + visitMultiSig(node: FunctionCallNode): Node { this.emit(encodeBool(false), { location: node.location, positionHint: PositionHint.START }); this.pushToStack('(value)'); @@ -1029,7 +1066,12 @@ export default class GenerateTargetTraversal extends AstTraversal { } isOpRoll(node: IdentifierNode): boolean { - return this.currentFunction.opRolls.get(node.name) === node && this.scopeDepth === 0; + // Must be the variable's final use (opRolls site) and not inside an if/loop scope. + if (this.currentFunction.opRolls.get(node.name) !== node || this.scopeDepth !== 0) return false; + // Inside a user-function-call argument list, ROLL is only safe when this variable appears exactly + // once across the whole argument tree; otherwise reversed emission would consume it too early. + if (this.userCallArgDepth > 0) return this.callArgNameCounts?.get(node.name) === 1; + return true; } visitBoolLiteral(node: BoolLiteralNode): Node { @@ -1057,3 +1099,26 @@ export default class GenerateTargetTraversal extends AstTraversal { } } +// Counts identifier reads across a user-function call's whole argument tree, used to decide whether +// a final-use variable in the argument list is safe to OP_ROLL: a name referenced exactly once has +// no other use that the reversed-emission ROLL could consume early. Function/instantiation callee +// identifiers are not stack-variable reads, so they are skipped (only the call arguments are counted). +class ArgIdentifierCounter extends AstTraversal { + counts: Map = new Map(); + + visitIdentifier(node: IdentifierNode): Node { + this.counts.set(node.name, (this.counts.get(node.name) ?? 0) + 1); + return node; + } + + visitFunctionCall(node: FunctionCallNode): Node { + node.parameters = this.visitList(node.parameters); + return node; + } + + visitInstantiation(node: InstantiationNode): Node { + node.parameters = this.visitList(node.parameters); + return node; + } +} + diff --git a/packages/cashc/test/compiler/unused-modifier.test.ts b/packages/cashc/test/compiler/unused-modifier.test.ts index 647d4d39..ecf2fc60 100644 --- a/packages/cashc/test/compiler/unused-modifier.test.ts +++ b/packages/cashc/test/compiler/unused-modifier.test.ts @@ -113,7 +113,8 @@ describe('The `unused` modifier', () => { } `); - expect(artifact.debug.functions?.[0].bytecode).toBe('75'); + // First parameter on top of the stack, so the trailing unused parameter sits below it (OP_NIP) + expect(artifact.debug.functions?.[0].bytecode).toBe('77'); }); it('drops multiple global-function parameters from the top down', () => { @@ -129,7 +130,8 @@ describe('The `unused` modifier', () => { } `); - expect(artifact.debug.functions?.[0].bytecode).toBe('6d'); + // First parameter on top of the stack, so both trailing unused parameters drop as OP_NIPs + expect(artifact.debug.functions?.[0].bytecode).toBe('7777'); }); it('does not validate the runtime type of a parameter that is immediately dropped', () => { diff --git a/packages/cashc/test/generation/fixtures.ts b/packages/cashc/test/generation/fixtures.ts index 06972519..d972d2f7 100644 --- a/packages/cashc/test/generation/fixtures.ts +++ b/packages/cashc/test/generation/fixtures.ts @@ -1491,7 +1491,8 @@ export const fixtures: Fixture[] = [ }, { // A multi-parameter global function — locks in the parameter stack-seeding and argument order - // (the contract OP_SWAPs x and y into place; the body computes a - b directly). + // (the body OP_SWAPs into place against the first-parameter-on-top entry layout; the + // declaration-order arguments at the call site then need no staging at all). fn: 'global_function_multi_param.cash', compilerOptions: { disableInlining: true }, artifact: { @@ -1499,24 +1500,24 @@ export const fixtures: Fixture[] = [ constructorInputs: [], abi: [{ name: 'spend', inputs: [{ name: 'x', type: 'int' }, { name: 'y', type: 'int' }] }], bytecode: - // OP_DEFINE sub (id 0): return a - b - '94 OP_0 OP_DEFINE ' - // require(sub(x, y) == 7) - + 'OP_SWAP OP_0 OP_INVOKE OP_7 OP_NUMEQUAL', + // OP_DEFINE sub (id 0): return a - b (entry layout: a on top, so OP_SWAP before OP_SUB) + '7c94 OP_0 OP_DEFINE ' + // require(sub(x, y) == 7) — x and y are in declaration order: zero staging instructions + + 'OP_0 OP_INVOKE OP_7 OP_NUMEQUAL', debug: { - bytecode: '019400897c008a579c', + bytecode: '027c940089008a579c', logs: [], requires: [ - { ip: 8, line: 7 }, + { ip: 7, line: 7 }, ], - sourceMap: '1::3:1;;::::1;7:23:7:24:0;:16::25:1;;:29::30:0;:8::32:1', + sourceMap: '1::3:1;;::::1;7:16:7:25;;:29::30:0;:8::32:1', functions: [ { id: 0, name: 'sub', inputs: [{ name: 'a', type: 'int' }, { name: 'b', type: 'int' }], - bytecode: '94', - sourceMap: '2:11:2:16:1', + bytecode: '7c94', + sourceMap: '2:15:2:16;:11:::1', logs: [], requires: [], }, @@ -1533,7 +1534,7 @@ export const fixtures: Fixture[] = [ }, }, updatedAt: '', - fingerprint: '8fc72a3f89ee3238266d6dd9ad3919f7238c8d6a31296cc8925968a31c78c7dc', + fingerprint: 'ef6dd7819e66a430286fe16f3d6dad7e026cf1970eda6bc620be7e7a3bdd2a4d', }, }, { @@ -1821,25 +1822,27 @@ export const fixtures: Fixture[] = [ constructorInputs: [], abi: [{ name: 'spend', inputs: [{ name: 'x', type: 'int' }] }], bytecode: - // OP_DEFINE divmod (id 0): return a / b, a % b — leaves [quotient, remainder], remainder on top - '6e967b7b97 OP_0 OP_DEFINE ' + // OP_DEFINE divmod (id 0): compiled against first-parameter-on-top entry — + // return a / b, a % b — leaves [quotient, remainder], remainder on top + '6e7c967c7b97 OP_0 OP_DEFINE ' // int q, int r = divmod(x, 3); require(q == 4); require(r == 1) - + 'OP_3 OP_0 OP_INVOKE OP_SWAP OP_4 OP_NUMEQUALVERIFY OP_1 OP_NUMEQUAL', + // (arguments staged right-to-left: 3 first, then x swapped on top) + + 'OP_3 OP_SWAP OP_0 OP_INVOKE OP_SWAP OP_4 OP_NUMEQUALVERIFY OP_1 OP_NUMEQUAL', debug: { - bytecode: '056e967b7b97008953008a7c549d519c', + bytecode: '066e7c967c7b970089537c008a7c549d519c', logs: [], requires: [ - { ip: 8, line: 8 }, - { ip: 11, line: 9 }, + { ip: 9, line: 8 }, + { ip: 12, line: 9 }, ], - sourceMap: '1::3:1;;::::1;7:33:7:34:0;:23::35:1;;8:16:8:17:0;:21::22;:8::24:1;9:21:9:22:0;:8::24:1', + sourceMap: '1::3:1;;::::1;7:33:7:34:0;:30::31;:23::35:1;;8:16:8:17:0;:21::22;:8::24:1;9:21:9:22:0;:8::24:1', functions: [ { id: 0, name: 'divmod', inputs: [{ name: 'a', type: 'int' }, { name: 'b', type: 'int' }], - bytecode: '6e967b7b97', - sourceMap: '2:11:2:16;::::1;:18::19:0;:22::23;:18:::1', + bytecode: '6e7c967c7b97', + sourceMap: '2:11:2:16;;::::1;:18::19:0;:22::23;:18:::1', logs: [], requires: [], }, @@ -1856,7 +1859,7 @@ export const fixtures: Fixture[] = [ }, }, updatedAt: '', - fingerprint: 'f747468c9408ec52949a22dc2f271a944ee5793eabaa913c9c2b1b4c3fbd0a56', + fingerprint: '13fdcb97e1a0f3546c30fb4f0c29338c1678c729db4e148151a026f93b27652d', }, }, ]; diff --git a/packages/utils/test/fixtures/bitauth-script.fixture.ts b/packages/utils/test/fixtures/bitauth-script.fixture.ts index eca0f858..e31ab118 100644 --- a/packages/utils/test/fixtures/bitauth-script.fixture.ts +++ b/packages/utils/test/fixtures/bitauth-script.fixture.ts @@ -485,7 +485,7 @@ OP_7 OP_0 OP_INVOKE OP_13 OP_NUMEQUAL /* */ /* >>> imported from helpers.cash */ < /* function addChecked(int a, int b) returns (int) { */ - OP_OVER OP_ADD /* int sum = a + b; */ + OP_DUP OP_ROT OP_ADD /* int sum = a + b; */ OP_DUP OP_ROT OP_GREATERTHANOREQUAL OP_VERIFY /* require(sum >= a, "overflow"); */ /* return sum; */ > OP_1 OP_DEFINE /* } */ @@ -495,7 +495,7 @@ OP_7 OP_0 OP_INVOKE OP_13 OP_NUMEQUAL /* contract ImportedFunctions() { */ /* function spend(int x) { */ OP_DUP OP_0 OP_INVOKE /* int doubled = double(x); */ -OP_SWAP OP_1 OP_INVOKE OP_15 OP_NUMEQUAL /* require(addChecked(doubled, x) == 15, "sum mismatch"); */ +OP_1 OP_INVOKE OP_15 OP_NUMEQUAL /* require(addChecked(doubled, x) == 15, "sum mismatch"); */ /* } */ /* } */ /* */ From 126cd7fc62069094ca78dfbd91fb27998cb3bea0 Mon Sep 17 00:00:00 2001 From: Mathieu Geukens Date: Thu, 23 Jul 2026 13:49:09 +0200 Subject: [PATCH 08/12] perf(cashc): inline small multi-use bodies under the 'opcost' objective MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Calling a defined function costs a fixed ~200 op-cost per call before the body even runs, so for tiny bodies the call overhead dwarfs the body itself. Under optimizeFor: 'opcost' (the default), any body of <= 6 bytes is now inlined regardless of use count, even when OP_DEFINE would be smaller by exact byte accounting. CHIP-2021-05 accounting (base 100 per evaluated instruction, +1 per stack-pushed byte): sharing a B-byte body pays 301 + 2B once per spend for the define plus 201 per call for OP_INVOKE, while the body executes at identical cost inlined or invoked — every EXECUTED call site therefore wins op-cost when inlined. Skipped call sites are the exception (an untaken branch steps an inlined body at 100/opcode where an invoke site steps 2 ops), so the rule is a bet on execution density with a small bounded downside per skipped site, not a universal op-cost win. The 6-byte bound is a byte-bloat guardrail, not an op-cost break-even: each inlined call site costs B bytes instead of the ~2-byte invoke site, and any body the byte model would inline at two uses stays inlined at every use count, capping the size regression at ~4 bytes per extra call site (the model omits the body push's length prefix, so the true 2-site break-even is 7 bytes — the cap deliberately stays under it). Locking-side bytes never consume op budget (the budget is derived from unlocking bytecode length), but they still cost fees and count against script size limits, hence the cap. The byte-exact model still governs under optimizeFor: 'size', and the loop-exclusion rule still overrides for loop-resident bodies. Co-Authored-By: Claude Fable 5 --- packages/cashc/src/generation/inlining.ts | 31 +++++++++++++++++-- .../cashc/test/global-definitions.test.ts | 19 ++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/packages/cashc/src/generation/inlining.ts b/packages/cashc/src/generation/inlining.ts index 58c8ad91..3c7a1d35 100644 --- a/packages/cashc/src/generation/inlining.ts +++ b/packages/cashc/src/generation/inlining.ts @@ -1,5 +1,6 @@ import { encodeInt, + OptimizationTarget, OptimiseBytecodeResult, Script, scriptToBytecode, @@ -46,11 +47,37 @@ export const shouldInline = ( } const callCount = reachableCalls.filter((call) => call.identifier.symbol === symbol).length; - return isWorthInlining(nextFunctionId, optimisedResult.script, callCount); + return isWorthInlining(nextFunctionId, optimisedResult.script, callCount, compilerOptions.optimizeFor); }; -function isWorthInlining(candidateFunctionId: number, bodyScript: Script, callCount: number): boolean { +// Op-cost accounting (CHIP-2021-05 VM limits): every evaluated instruction costs a base 100 and +// stack pushes add 1 per pushed byte, so sharing a body of B bytes (1-byte funcid) pays +// OP_DEFINE = 301 + 2B once per spend (OP_DEFINE re-prices the body's +// stack-pushed bytes) plus OP_INVOKE = 201 per call, while an inlined body executes at +// identical cost to an invoked one. For EXECUTED call sites inlining therefore always wins op-cost. +// That is not a universal win: a SKIPPED call site (untaken branch — e.g. a helper called once per +// entry function of a multi-function contract) steps the whole inlined body at 100/opcode where an +// invoke site steps 2 ops (a 6-element body: 600 vs 200; a helper shared across 4 entry functions +// measured ~686 op-cost worse AND +8 bytes when force-inlined). Forcing tiny bodies inline is thus +// a bet on execution density — that call sites usually execute — with the downside bounded small: +// each skipped site risks ~100 x (elements - 2) op-cost, while each executed site saves the +// 201/call invoke overhead plus the one-time 301 + 2B define. On bytes: the model below omits the +// body push's length prefix, so the true two-site break-even is 7 bytes, not 6 — the cap +// deliberately stays at 6 so any body forced inline here is one the byte model would also inline +// at two uses, capping the byte regression at ~4 bytes per extra call site. Loop-resident bodies +// are still excluded above: stepping a skipped inlined body costs 100/opcode per ITERATION, which +// quickly dwarfs the 201/call invoke saving. +const OPCOST_INLINE_MAX_BODY_BYTES = 6; + +function isWorthInlining( + candidateFunctionId: number, + bodyScript: Script, + callCount: number, + optimizeFor?: OptimizationTarget, +): boolean { const bodyBytes = scriptToBytecode(bodyScript).length; + if (optimizeFor !== 'size' && bodyBytes <= OPCOST_INLINE_MAX_BODY_BYTES) return true; + const idBytes = scriptToBytecode([encodeInt(BigInt(candidateFunctionId))]).length; const bytesWhenDefined = bodyBytes + idBytes + 1 + callCount * (idBytes + 1); diff --git a/packages/cashc/test/global-definitions.test.ts b/packages/cashc/test/global-definitions.test.ts index 6cdcfb7b..e654b59c 100644 --- a/packages/cashc/test/global-definitions.test.ts +++ b/packages/cashc/test/global-definitions.test.ts @@ -177,6 +177,25 @@ describe('Inlining and shared definitions', () => { expect(bytecode).toContain('OP_INVOKE'); }); + it("inlines a small multi-use body under 'opcost' (default) even when OP_DEFINE would be smaller", () => { + // 5-byte body used 4x: byte-exact accounting prefers OP_DEFINE, but every invocation costs + // ~2 executed instructions that splicing avoids — the 'opcost' objective (the default) takes + // the ops, the 'size' objective takes the bytes. + const code = ` + function addF(int x, int y) returns (int) { return (x + y) % 7919; } + contract C() { + function spend(int a, int b) { + int t1 = addF(a, b); + int t2 = addF(t1, a); + int t3 = addF(t2, b); + require(addF(t3, t1) >= 0); + } + }`; + expect(compileString(code).bytecode).not.toContain('OP_DEFINE'); + expect(compileString(code, { optimizeFor: 'opcost' }).bytecode).not.toContain('OP_DEFINE'); + expect(compileString(code, { optimizeFor: 'size' }).bytecode).toContain('OP_DEFINE'); + }); + it('keeps a function called inside a loop shared via OP_DEFINE (skipped-branch stepping cost)', () => { const code = ` function big(int x) returns (int) { return (x * 7 + 3) * (x + 11) - 5; } From 65de9ace9da40b98876acd3b28b3978421800112 Mon Sep 17 00:00:00 2001 From: Mathieu Geukens Date: Sat, 4 Jul 2026 17:53:31 +0200 Subject: [PATCH 09/12] perf(cashc): sink variable definitions to first use under the size objective MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The longer the gap between where a variable is defined and where it is first used, the deeper it sits on the stack in between and the more bytes every access pays to dig it out. Moving each definition down its block to just before its first use keeps values near the top of the stack, so contracts compile smaller. Mechanically: a definition compiles to a rename of the value its initializer leaves on top of the stack, so sinking shrinks live ranges — intervening reads get shallower depth arguments and a single-use definition's access pair collapses in the peephole. The size objective compiles both variants and keeps the smaller one, so the pass never costs bytes; the opcost objective skips it (relocating evaluation deepens the initializer's own input reads, and the executed-op balance of that trade is workload-dependent). Sinking can change which require() fails first on an invalid witness and the order of console.log output, never whether a transaction is accepted. Definitions count as assignments in the reorder analysis, so a sunk definition can never move past a later definition of one of its inputs — sinking cannot launder a use-before-definition program into one that compiles. The disableDefSinking escape hatch (for tools that need the source-ordered compile as input) lives in InternalCompilerOptions, like disableInlining, so it is not serialized into artifacts. Co-Authored-By: Claude Fable 5 --- packages/cashc/src/compiler.ts | 46 +++-- packages/cashc/src/def-sinking.ts | 215 ++++++++++++++++++++ packages/cashc/test/def-sinking.test.ts | 251 ++++++++++++++++++++++++ 3 files changed, 500 insertions(+), 12 deletions(-) create mode 100644 packages/cashc/src/def-sinking.ts create mode 100644 packages/cashc/test/def-sinking.test.ts diff --git a/packages/cashc/src/compiler.ts b/packages/cashc/src/compiler.ts index bfc176c5..9e1a3c56 100644 --- a/packages/cashc/src/compiler.ts +++ b/packages/cashc/src/compiler.ts @@ -27,6 +27,7 @@ import { ImportResolver, resolveDependencies, } from './dependency-resolution.js'; +import { sinkDefinitions } from './def-sinking.js'; import GenerateTargetTraversal from './generation/GenerateTargetTraversal.js'; import SymbolTableTraversal from './semantic/SymbolTableTraversal.js'; import TypeCheckTraversal from './semantic/TypeCheckTraversal.js'; @@ -90,12 +91,22 @@ export interface InternalCompilerOptions extends CompilerOptions { // ASM-regex optimiser and compares the results. The check is also skipped automatically for // very large scripts, where the redundant second optimisation pass measurably slows compiles. disableOptimisationCrossCheck?: boolean; + // Skip def-sinking. Under `optimizeFor: 'size'`, definitions move down to just before their + // first use when that shrinks the bytecode (the compiler keeps the smaller of the sunk and + // unsunk compiles). This flag is for tools that need the source-ordered compile as input. + disableDefSinking?: boolean; // Skip constant hoisting. Under `optimizeFor: 'size'`, repeated in-body literals are bound to // locals when that shrinks the bytecode (the compiler keeps the hoisted compile only when it // is strictly smaller). This flag is for tools that need the literal-shaped compile as input. disableConstantHoisting?: boolean; } +// The AST rewrites applied before semantic analysis in a single compile candidate. +interface RewriteFlags { + sinkDefs: boolean; + hoistConstants: boolean; +} + export function compileStringInternal( code: string, compilerOptions: CompileStringOptions & InternalCompilerOptions = {}, @@ -121,30 +132,36 @@ function compileCode( compilerOptions: CompileOptions & InternalCompilerOptions, ): Artifact { const optimizeFor = compilerOptions.optimizeFor ?? DEFAULT_COMPILER_OPTIONS.optimizeFor; - if (optimizeFor !== 'size' || compilerOptions.disableConstantHoisting) { - return compileImpl(code, resolver, compilerOptions, false); + if (optimizeFor !== 'size') { + return compileImpl(code, resolver, compilerOptions, { sinkDefs: false, hoistConstants: false }); } - // Hoisting helps most contracts but can cost bytes on some, so the 'size' objective compiles - // both variants and keeps the hoisted compile only when it is strictly smaller. - const hoisted = compileImpl(code, resolver, compilerOptions, true); - const unhoisted = compileImpl(code, resolver, compilerOptions, false); + // Each 'size' rewrite helps most contracts but can cost bytes on some, so the 'size' objective + // compiles every enabled combination and keeps the smallest artifact. Candidates are ordered + // so ties resolve conservatively: the sunk compile wins a def-sinking tie (established + // behaviour), and the hoisted compile is only kept when it is strictly smaller. + const sinkOptions = compilerOptions.disableDefSinking ? [false] : [true, false]; + const hoistOptions = compilerOptions.disableConstantHoisting ? [false] : [false, true]; + const candidates = sinkOptions + .flatMap((sinkDefs) => hoistOptions.map((hoistConstants) => ({ sinkDefs, hoistConstants }))); const compiledBytes = (artifact: Artifact): number => artifact.debug?.bytecode.length ?? artifact.bytecode.length; - return compiledBytes(hoisted) < compiledBytes(unhoisted) ? hoisted : unhoisted; + return candidates + .map((rewrites) => compileImpl(code, resolver, compilerOptions, rewrites)) + .reduce((best, candidate) => (compiledBytes(candidate) < compiledBytes(best) ? candidate : best)); } function compileImpl( code: string, resolver: ImportResolver, compilerOptions: CompileOptions & InternalCompilerOptions, - hoistConstants: boolean, + rewrites: RewriteFlags, ): Artifact { const { errorListener, disableInlining, disableOptimisationCrossCheck, - // consumed in compileCode (which picks the hoisted or unhoisted compile); destructured here - // only to keep it out of the serialized artifact options + // consumed in compileCode (which picks the smallest rewrite combination); destructured here + // only to keep them out of the serialized artifact options // eslint-disable-next-line @typescript-eslint/no-unused-vars - disableConstantHoisting, + disableDefSinking, disableConstantHoisting, ...artifactCompilerOptions } = compilerOptions; const mergedCompilerOptions = { ...DEFAULT_COMPILER_OPTIONS, ...artifactCompilerOptions }; @@ -157,10 +174,15 @@ function compileImpl( // Under the 'size' objective, bind repeated in-body literals to locals (see CompilerOptions). // Runs before semantic analysis so the introduced locals get symbols like any other variable. - if (hoistConstants) { + if (rewrites.hoistConstants) { ast = hoistRepeatedConstants(ast) as Ast; } + // Sink variable definitions to just before their first use + if (rewrites.sinkDefs) { + ast = sinkDefinitions(ast) as Ast; + } + if (!ast.contract) throw new MissingContractError(); const constructorParamLength = ast.contract.parameters.length; diff --git a/packages/cashc/src/def-sinking.ts b/packages/cashc/src/def-sinking.ts new file mode 100644 index 00000000..97b74f9f --- /dev/null +++ b/packages/cashc/src/def-sinking.ts @@ -0,0 +1,215 @@ +import { + SourceFileNode, + FunctionDefinitionNode, + BlockNode, + StatementNode, + Node, + VariableDefinitionNode, + TupleAssignmentNode, + AssignNode, + ReturnNode, + ConsoleStatementNode, + ControlStatementNode, + BranchNode, + DoWhileNode, + WhileNode, + ForNode, + ExpressionNode, + IdentifierNode, + FunctionCallNode, + InstantiationNode, +} from './ast/AST.js'; +import { Modifier } from './ast/Globals.js'; +import AstTraversal from './ast/AstTraversal.js'; + +// Moves each variable definition down its block to just before the statement that first uses +// it. A definition compiles to a rename of the value its initializer leaves on top of the +// stack, so sinking shrinks live ranges: intervening reads get shallower depth arguments and a +// single-use definition's access pair collapses in the peephole. The reorder can change which +// require() fails first on an invalid witness and the order of console.log output — never +// whether a transaction is accepted. +// +// Byte-size optimisation, gated behind `optimizeFor: 'size'`: relocating evaluation deepens the +// initializer's own input reads, and under ROLL/PICK depth metering the executed-op-cost +// balance of that trade is workload-dependent. Runs before semantic analysis so the final-use +// bookkeeping (opRolls) sees the reordered statements. + +export function sinkDefinitions(ast: SourceFileNode): SourceFileNode { + ast.functions.forEach(sinkInFunction); + ast.contract?.functions.forEach((func: FunctionDefinitionNode) => sinkInFunction(func)); + return ast; +} + +function sinkInFunction(func: FunctionDefinitionNode): void { + const reassigned = collectReassignedNames(func.body); + sinkInBlock(func.body, reassigned); +} + +// A definition (scalar, or tuple-destructure declaring only new variables) normalised to the +// names it introduces and the free variables its initializer reads. +interface SinkableDefinition { + names: Set; + freeVariables: Set; +} + +function asSinkableDefinition( + statement: StatementNode, + reassigned: Set, +): SinkableDefinition | undefined { + if (statement instanceof VariableDefinitionNode) { + // `unused` definitions have no use site; reassigned variables keep their definition point. + if (statement.modifiers.includes(Modifier.UNUSED)) return undefined; + if (reassigned.has(statement.name)) return undefined; + return { names: new Set([statement.name]), freeVariables: collectReferences(statement.expression).references }; + } + + if (statement instanceof TupleAssignmentNode) { + if (statement.targets.some((target) => target.isReassignment)) return undefined; + if (statement.targets.some((target) => reassigned.has(target.name))) return undefined; + return { + names: new Set(statement.targets.map((target) => target.name)), + freeVariables: collectReferences(statement.tuple).references, + }; + } + + return undefined; +} + +function sinkInBlock(block: BlockNode, reassigned: Set): void { + const statements = block.statements; + if (!statements) return; + + // Each nested block sinks independently; a definition never crosses a scope boundary. + statements.forEach((statement) => sinkInNestedBlocks(statement, reassigned)); + if (statements.length < 2) return; + + const facts = statements.map(computeStatementFacts); + + // Nothing may move past the block's last non-console statement, which semantic analysis + // requires to stay a require (contract functions) or return (returning global functions). + let lastEffective = statements.length - 1; + while (lastEffective >= 0 && statements[lastEffective] instanceof ConsoleStatementNode) { + lastEffective -= 1; + } + + // Bottom-up, so a chain `int a = ...; int b = f(a);` sinks as a whole in one pass. + for (let i = statements.length - 2; i >= 0; i -= 1) { + const definition = asSinkableDefinition(statements[i], reassigned); + if (definition === undefined) continue; + + let target = i; + while (target + 1 <= lastEffective) { + const next = facts[target + 1]; + if (intersects(next.references, definition.names)) break; // first use — land just above it + if (next.barrier) break; + if (intersects(next.assigns, definition.freeVariables)) break; // initializer input changes + if (target + 1 === lastEffective) break; + target += 1; + } + + if (target > i) { + const [statement] = statements.splice(i, 1); + statements.splice(target, 0, statement); + const [fact] = facts.splice(i, 1); + facts.splice(target, 0, fact); + } + } +} + +// Branch and loop children are typed as BlockNode but braceless bodies (`if (x) require(y);`, +// `else if` chains) are bare statements, so dispatch on the actual node. +function sinkInNestedBlocks(statement: StatementNode, reassigned: Set): void { + if (statement instanceof BranchNode) { + sinkInChild(statement.ifBlock, reassigned); + if (statement.elseBlock) sinkInChild(statement.elseBlock, reassigned); + } else if (statement instanceof DoWhileNode || statement instanceof WhileNode || statement instanceof ForNode) { + sinkInChild(statement.block, reassigned); + } +} + +function sinkInChild(child: Node, reassigned: Set): void { + if (child instanceof BlockNode) sinkInBlock(child, reassigned); + else sinkInNestedBlocks(child as StatementNode, reassigned); +} + +interface StatementFacts { + references: Set; + assigns: Set; + barrier: boolean; +} + +function computeStatementFacts(statement: StatementNode): StatementFacts { + const { references, assigns, defines } = collectReferences(statement); + const barrier = statement instanceof ControlStatementNode + || statement instanceof ReturnNode + || (statement instanceof TupleAssignmentNode && statement.targets.some((target) => target.isReassignment)); + return { references, assigns: new Set([...assigns, ...defines]), barrier }; +} + +function collectReferences(node: ExpressionNode | StatementNode): ReferenceCollector { + const collector = new ReferenceCollector(); + collector.visit(node); + return collector; +} + +const intersects = (a: Set, b: Set): boolean => { + for (const element of a) if (b.has(element)) return true; + return false; +}; + +// Records every variable referenced and every variable assigned anywhere in a statement. +// Console parameters count as references (codegen needs logged variables on the stack); +// callee names of calls and instantiations do not — they are not stack variables. +class ReferenceCollector extends AstTraversal { + references = new Set(); + assigns = new Set(); + defines = new Set(); + + visitIdentifier(node: IdentifierNode): Node { + this.references.add(node.name); + return node; + } + + visitFunctionCall(node: FunctionCallNode): Node { + node.parameters = this.visitList(node.parameters); + return node; + } + + visitInstantiation(node: InstantiationNode): Node { + node.parameters = this.visitList(node.parameters); + return node; + } + + visitAssign(node: AssignNode): Node { + this.assigns.add(node.identifier.name); + return super.visitAssign(node); + } + + // Definition-introduced names are tracked separately from reassignments: the sink barrier must + // treat them like assigns (a sunk definition may never move past a later definition of one of + // its inputs — otherwise sinking would launder a use-before-definition program, rejected by the + // source-ordered compile, into one that compiles), while collectReassignedNames must not (a + // definition alone does not pin a variable in place). + visitVariableDefinition(node: VariableDefinitionNode): Node { + this.defines.add(node.name); + return super.visitVariableDefinition(node); + } + + visitTupleAssignment(node: TupleAssignmentNode): Node { + node.targets.forEach((target) => { + if (target.isReassignment) { + this.assigns.add(target.name); + this.references.add(target.name); + } else { + this.defines.add(target.name); + } + }); + return super.visitTupleAssignment(node); + } +} + +function collectReassignedNames(body: BlockNode): Set { + const collector = new ReferenceCollector(); + collector.visit(body); + return collector.assigns; +} diff --git a/packages/cashc/test/def-sinking.test.ts b/packages/cashc/test/def-sinking.test.ts new file mode 100644 index 00000000..c3521ce2 --- /dev/null +++ b/packages/cashc/test/def-sinking.test.ts @@ -0,0 +1,251 @@ +import { compileString } from '../src/index.js'; + +// Def-sinking moves each definition down to just before its first use. It is a byte-size +// optimisation that only runs under the 'size' objective. The primary assertion idiom: +// compiling a source with sinking must produce the same bytecode as compiling the +// hand-reordered source with sinking disabled. +const sunk = (code: string): string => compileString(code, { optimizeFor: 'size' }).bytecode; +const unsunk = (code: string): string => ( + compileString(code, { optimizeFor: 'size', disableDefSinking: true }).bytecode +); +const count = (haystack: string, needle: string): number => haystack.split(needle).length - 1; + +const wrap = (body: string): string => ` + contract C() { + function spend(int a, int b) { + ${body} + } + }`; + +describe('Definition sinking', () => { + it('sinks a single-use definition to adjacency', () => { + const original = wrap(` + int x = a + 1; + require(b == 2); + require(x == 5);`); + const reordered = wrap(` + require(b == 2); + int x = a + 1; + require(x == 5);`); + expect(sunk(original)).toBe(unsunk(reordered)); + }); + + it('sinks a chain of dependent definitions together in one pass', () => { + const original = wrap(` + int x = a + 1; + int y = x + 2; + require(b == 3); + require(y == 9);`); + const reordered = wrap(` + require(b == 3); + int x = a + 1; + int y = x + 2; + require(y == 9);`); + expect(sunk(original)).toBe(unsunk(reordered)); + }); + + it('stops above a reassignment of an initializer input, and never sinks reassigned variables', () => { + const original = wrap(` + int y = a; + int x = y + 1; + y = b; + require(b == 2); + require(x + y == 3);`); + // `y` is reassigned, so its definition stays; `x` reads `y`, so it cannot cross `y = b`. + expect(sunk(original)).toBe(unsunk(original)); + }); + + it('treats a branch as a hard barrier: a partial sink lands just above it', () => { + const original = wrap(` + int x = a + 1; + require(b == 2); + if (b == 2) { + require(a == 1); + } + require(x == 5);`); + const reordered = wrap(` + require(b == 2); + int x = a + 1; + if (b == 2) { + require(a == 1); + } + require(x == 5);`); + expect(sunk(original)).toBe(unsunk(reordered)); + }); + + it('sinks to a first use inside a branch, landing just above it', () => { + const original = wrap(` + int x = a + 1; + require(b == 2); + if (x == 2) { + require(a == 1); + } else { + require(a == 0); + }`); + const reordered = wrap(` + require(b == 2); + int x = a + 1; + if (x == 2) { + require(a == 1); + } else { + require(a == 0); + }`); + expect(sunk(original)).toBe(unsunk(reordered)); + }); + + it('sinks within nested blocks independently', () => { + const original = wrap(` + if (b == 2) { + int x = a + 1; + require(b == 2); + require(x == 5); + } else { + require(a == 0); + }`); + const reordered = wrap(` + if (b == 2) { + require(b == 2); + int x = a + 1; + require(x == 5); + } else { + require(a == 0); + }`); + expect(sunk(original)).toBe(unsunk(reordered)); + }); + + it('sinks a tuple destructure that declares only new variables', () => { + const withTuple = (order: 'original' | 'reordered'): string => ` + function divmod(int x, int y) returns (int, int) { + return x / y, x % y; + } + contract C() { + function spend(int a, int b) { + ${order === 'original' + ? 'int q, int r = divmod(a, 3); require(b == 2);' + : 'require(b == 2); int q, int r = divmod(a, 3);'} + require(q + r == 5); + } + }`; + expect(sunk(withTuple('original'))).toBe(unsunk(withTuple('reordered'))); + }); + + it('treats a tuple reassignment as a hard barrier and never moves it', () => { + const original = ` + function divmod(int x, int y) returns (int, int) { + return x / y, x % y; + } + contract C() { + function spend(int a, int b) { + int q = a + 1; + int x = b + 1; + int r, q = divmod(a, 3); + require(b == 2); + require(x + q + r == 5); + } + }`; + // `q` is reassigned by the destructure, so its definition stays put; `x` cannot cross the + // mixed destructure (hard barrier) even though it does not touch `x`'s inputs. + expect(sunk(original)).toBe(unsunk(original)); + }); + + it('leaves unused-modified definitions in place', () => { + const original = wrap(` + int unused pad = a + 1; + require(b == 2); + require(a == 1);`); + expect(sunk(original)).toBe(unsunk(original)); + }); + + it('lands each of several definitions adjacent to its own require', () => { + const original = wrap(` + int x = a + 1; + int y = a + 2; + int z = a + 3; + require(x == 1); + require(y == 2); + require(z == b);`); + const reordered = wrap(` + int x = a + 1; + require(x == 1); + int y = a + 2; + require(y == 2); + int z = a + 3; + require(z == b);`); + expect(sunk(original)).toBe(unsunk(reordered)); + }); + + it('counts console.log parameters as uses', () => { + const original = wrap(` + int x = a + 1; + console.log(x); + require(b == 2); + require(x == 5);`); + // The log pins `x` in place (codegen needs the variable on the stack at the log's position). + expect(sunk(original)).toBe(unsunk(original)); + }); + + it('never sinks past the final require, even toward a trailing log', () => { + const original = wrap(` + int x = a + 1; + require(b == 2); + console.log(x);`); + // Without the cap, `x`'s first use (the trailing log) would pull its definition past the + // final require and trip EnsureFinalRequireTraversal. + expect(() => compileString(original, { optimizeFor: 'size' })).not.toThrow(); + expect(sunk(original)).toBe(unsunk(original)); + }); + + it('sinks inside global function bodies', () => { + const withGlobal = (order: 'original' | 'reordered'): string => ` + function f(int v, int w) returns (int) { + ${order === 'original' + ? 'int t = v + 1; require(w > 0);' + : 'require(w > 0); int t = v + 1;'} + return t + w; + } + contract C() { + function spend(int a, int b) { + require(f(a, b) == 3); + } + }`; + expect(sunk(withGlobal('original'))).toBe(unsunk(withGlobal('reordered'))); + }); + + it('erases the access pair of a definition sunk to adjacency and shrinks the bytecode', () => { + // Unsunk, `x` sits at depth 3 under p/q/r when it is read (`OP_3 OP_ROLL`). Sinking moves + // p/q/r below `x`'s use, so `x` resolves at depth 0 and the peephole erases the access pair. + const original = wrap(` + int x = a + 1; + int p = a + 2; + int q = a + 3; + int r = a + 4; + require(x == 5); + require(p + q + r == b);`); + expect(count(unsunk(original), 'OP_ROLL')).toBeGreaterThan(0); + expect(count(sunk(original), 'OP_ROLL')).toBeLessThan(count(unsunk(original), 'OP_ROLL')); + expect(sunk(original).length).toBeLessThan(unsunk(original).length); + }); + + it("only runs under the 'size' objective, and produces the same ABI either way", () => { + const original = wrap(` + int x = a + 1; + require(b == 2); + require(x == 5);`); + expect(sunk(original)).not.toBe(unsunk(original)); + // The default 'opcost' objective never sinks. + expect(compileString(original).bytecode).toBe(compileString(original, { disableDefSinking: true }).bytecode); + expect(compileString(original, { optimizeFor: 'size' }).abi).toEqual(compileString(original).abi); + }); + + it('still rejects use-before-definition under the size objective (no laundering by reordering)', () => { + // Sinking `int x = later + 1;` below `int later = 2;` would make this invalid program + // compile; definitions counting as assigns pins the sink above the redefinition. + const original = wrap(` + int x = later + 1; + int later = 2; + require(x == 3); + require(later == 2);`); + expect(() => compileString(original)).toThrow('Undefined reference to symbol later'); + expect(() => compileString(original, { optimizeFor: 'size' })).toThrow('Undefined reference to symbol later'); + }); +}); From 9c8864fefcdfcda239c9a07562c187f66abaa2fd Mon Sep 17 00:00:00 2001 From: Mathieu Geukens Date: Sun, 5 Jul 2026 16:25:34 +0200 Subject: [PATCH 10/12] perf(cashc): opt-in DAG stack rescheduling (rescheduleStacks) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Compiled contracts spend a large share of their bytes fetching values from deep in the stack (` OP_PICK/OP_ROLL`). This experimental, opt-in pass re-plans each straight-line region's computation order so operands tend to already be on top of the stack when needed, cutting much of that fetch traffic. Measured on the BN254 Groth16 verifier chunks: every chunked family improves 4.9-6.7% in benchmark score (grouped-residue flagship 257,810 -> 241,628; total op-cost 195.4M -> 181.5M), with all proof instances accepted and tampered runs rejected. New `rescheduleStacks` compiler option, applied after bytecode optimisation: split the compiled script into basic blocks at control/verify opcodes, lift each block to a value DAG over its entry stack slots, and re-emit it with a scheduler that computes operands onto the top of the stack instead of fetching every read with a slot access. The pass also chooses each OP_DEFINE'd function's argument-arrival order jointly with its schedule (call sites stage arguments explicitly, so a permuted convention is ~free at the caller; callers and main re-stage accordingly). Candidates — topo / byte-greedy / op-cost-greedy orders plus a small beam search, crossed with entry-order permutations — are ranked by the `optimizeFor` objective; per block the compiler keeps min(original, rescheduled), so no block gets worse. Function bodies are differentially tested on a loosened BCH2026 VM (random input vectors must reproduce the plain compile's output stack) and, under 'opcost', selected by MEASURED op-cost. The main routine relies on the per-block structural guarantee (exact entry->exit layout, boundaries kept verbatim and in order) plus static ranking. Dead computation is never eliminated: a node unreachable from its block's exit (a void guard call's zero-output invoke, an unused variable's failure-capable initializer) can only reject a spend, so re-emitting its block would accept witnesses the plain compile rejects. Such blocks keep their original ops verbatim; variants that cannot (permuted entry or callee conventions) are discarded. Covered by adversarial accept/reject tests on the real BCH2026 VM. Every unexpected condition fails closed to the plain compile: any layout-validation failure falls back to standard argument orders wholesale, a dead-ended beam search throws (callers keep the original body) instead of returning a no-computation schedule, and layout experiments are skipped entirely if any OP_INVOKE is not immediately preceded by its callee-id constant (such a call site would be invisible to the re-staging analysis). Inline debug ranges are dropped (not remapped) across a main rewrite, so debuggers degrade gracefully rather than pointing at wrong instructions. Off by default; single-function contracts only (a selector makes entry stack depth path-dependent). Scripts/bodies with console.log are left untouched; rescheduled regions keep statement-level debug info (merged block source spans, require ips re-anchored to preserved boundaries). Co-Authored-By: Claude Fable 5 --- packages/cashc/src/compiler.ts | 20 +- .../src/generation/GenerateTargetTraversal.ts | 6 + packages/cashc/src/stack-rescheduling.ts | 1226 +++++++++++++++++ .../cashc/test/stack-rescheduling.test.ts | 166 +++ packages/utils/src/artifact.ts | 9 + 5 files changed, 1425 insertions(+), 2 deletions(-) create mode 100644 packages/cashc/src/stack-rescheduling.ts create mode 100644 packages/cashc/test/stack-rescheduling.test.ts diff --git a/packages/cashc/src/compiler.ts b/packages/cashc/src/compiler.ts index 9e1a3c56..af1f45e3 100644 --- a/packages/cashc/src/compiler.ts +++ b/packages/cashc/src/compiler.ts @@ -28,6 +28,7 @@ import { resolveDependencies, } from './dependency-resolution.js'; import { sinkDefinitions } from './def-sinking.js'; +import { applyStackRescheduling } from './stack-rescheduling.js'; import GenerateTargetTraversal from './generation/GenerateTargetTraversal.js'; import SymbolTableTraversal from './semantic/SymbolTableTraversal.js'; import TypeCheckTraversal from './semantic/TypeCheckTraversal.js'; @@ -208,7 +209,7 @@ function compileImpl( ast = ast.accept(traversal) as Ast; // Bytecode optimisation - const optimisationResult = optimiseBytecode( + let optimisationResult = optimiseBytecode( traversal.output, sourceMapToLocationData(traversal.sourceMap), traversal.consoleLogs, @@ -232,13 +233,28 @@ function compileImpl( } } + // Stack rescheduling (opt-in): re-derive straight-line evaluation schedules from the + // dataflow DAG, ranked by the optimizeFor objective. Runs after the legacy-optimiser + // cross-check (which compares pre-reschedule outputs) and is restricted to + // single-function contracts (a function selector makes the entry stack depth + // path-dependent, which the block model does not represent). + let frames = traversal.frames; + if (mergedCompilerOptions.rescheduleStacks && ast.contract!.functions.length === 1) { + ({ result: optimisationResult, frames } = applyStackRescheduling(optimisationResult, frames, { + arities: traversal.definedFunctionArities, + mainInArity: ast.contract!.functions[0].parameters.length + constructorParamLength, + objective: mergedCompilerOptions.optimizeFor ?? 'opcost', + constructorParamLength, + })); + } + const debug = { bytecode: binToHex(scriptToBytecode(optimisationResult.script)), sourceMap: generateSourceMap(optimisationResult.locationData), logs: optimisationResult.logs, requires: optimisationResult.requires, sourceTags: generateSourceTags(optimisationResult.sourceTags) || undefined, - functions: traversal.frames.length > 0 ? traversal.frames : undefined, + functions: frames.length > 0 ? frames : undefined, inlineRanges: generateInlineRanges(optimisationResult.inlineRanges) || undefined, }; diff --git a/packages/cashc/src/generation/GenerateTargetTraversal.ts b/packages/cashc/src/generation/GenerateTargetTraversal.ts index 8097fb6a..464f17a1 100644 --- a/packages/cashc/src/generation/GenerateTargetTraversal.ts +++ b/packages/cashc/src/generation/GenerateTargetTraversal.ts @@ -101,6 +101,11 @@ export default class GenerateTargetTraversal extends AstTraversal { private constructorParameterCount: number; inlineRanges: InlineRange[] = []; + // Stack arity (parameter/return counts) of every OP_DEFINE'd function, keyed by its + // functionId — consumed by post-codegen passes (stack rescheduling) that need OP_INVOKE + // stack effects without re-deriving them from the bytecode. + definedFunctionArities: Map = new Map(); + // Depth of nested user-function-call argument staging (see stageUserFunctionArguments). private userCallArgDepth = 0; // Per-variable occurrence counts across the outermost call's whole argument tree. Names appearing @@ -243,6 +248,7 @@ export default class GenerateTargetTraversal extends AstTraversal { // Emit definitions in ID order so debug.functions[n] corresponds to the n-th define site (id n). definedFunctions.forEach(({ func, compiledResult }, functionId) => { this.frames.push(this.buildDebugFrame(func, compiledResult, functionId)); + this.definedFunctionArities.set(functionId, { in: func.parameters.length, out: func.returnTypes?.length ?? 0 }); const locationData = { location: func.location, positionHint: PositionHint.START }; this.emit(scriptToBytecode(compiledResult.script), locationData); // this.emit(encodeInt(BigInt(functionId)), locationData); // diff --git a/packages/cashc/src/stack-rescheduling.ts b/packages/cashc/src/stack-rescheduling.ts new file mode 100644 index 00000000..2fa4100f --- /dev/null +++ b/packages/cashc/src/stack-rescheduling.ts @@ -0,0 +1,1226 @@ +// Stack rescheduling: re-derive the evaluation schedule of straight-line code from its +// dataflow DAG so operands are on top of the stack when needed, instead of fetching every +// read from a variable slot with ` OP_PICK/OP_ROLL` pairs. +// +// The compiled script is split into basic blocks at control opcodes (IF/ELSE/ENDIF, +// BEGIN/UNTIL) and side-effecting checks (VERIFY-family, CLTV/CSV). Each block is lifted +// to a value DAG over its (opaque) entry stack slots, then re-emitted by a scheduler that +// walks the DAG in dependency order, choosing per operand between consuming moves +// (SWAP/ROT/ROLL), copies (DUP/OVER/PICK) and re-pushing constants. Because every block +// reproduces its exact entry->exit stack layout and the control opcodes are kept verbatim +// and in order, blocks compose and the transform is semantics-preserving by construction. +// Per block the compiler keeps min(original, rescheduled), so no block ever gets worse. +// +// The exit-layout guarantee alone does not cover DEAD COMPUTATION: a value computed but +// never reaching the block's exit. Script failure aborts the whole evaluation, so +// rejecting a spend is the only observable effect a dead node has — and the realistic +// instance is a VOID FUNCTION CALL, whose require() lives inside the OP_DEFINE'd body: +// the call site is an invoke node with zero outputs, dead by construction. The scheduler +// only emits nodes reachable from the exit, so a re-emitted block would silently delete +// the guard (and the well-formedness checks it performs on witness data), accepting +// spends the original rejects. Blocks containing dead computation are therefore never +// re-emitted: they keep their original ops verbatim (see hasDeadComputation), and any +// variant that cannot keep them (permuted entry layout or callee conventions) is +// discarded wholesale. +// +// Objectives (follows `optimizeFor`): +// 'size' — candidate schedules ranked by serialized bytes. +// 'opcost' — ranked by the BCH2026 op-cost meter (100 per evaluated instruction + the +// bytes it pushes; SWAP/ROT push 0, copies push the item, ROLL pushes +// item+depth, so e.g. re-pushing a 32-byte constant (~132) beats PICKing a +// stashed copy (~234)). Right for op-bound contracts whose unlocking scripts +// are zero-padded to buy op budget. +// +// OP_DEFINE'd function bodies are additionally validated by a differential test on a +// loosened VM (random input vectors; the rescheduled body must reproduce the original's +// output stack) and, under 'opcost', selected by MEASURED op-cost rather than the static +// estimate. The main routine cannot be executed standalone (it reads transaction context), +// so it relies on the per-block structural guarantee and static ranking. +// +// ENTRY-LAYOUT SEARCH: the pass also chooses, per OP_DEFINE'd function, the stack ORDER +// in which its arguments arrive — jointly with the schedule (the optimal order depends +// on the schedule and vice versa), including a small beam search over node orders. Call +// sites already stage arguments explicitly, so a permuted convention costs nothing extra +// there; every caller (and the main routine, when it invokes a permuted callee directly) +// is re-emitted to stage arguments in the callee's chosen order, and the plain-cashc +// variant of any block that invokes a permuted callee is invalid and excluded from the +// per-block min. If any validation fails, the pass falls back to identity layouts +// wholesale. +// +// This pass is opt-in (`rescheduleStacks`), runs after bytecode optimisation, and is +// restricted to single-function contracts (with a function selector, the entry stack +// depth differs per spend path, which this block model does not represent). Scripts and +// bodies containing console.log statements are left untouched (wholesale reordering +// cannot preserve per-instruction log data). Rescheduled regions keep coarse debug info: +// every emitted opcode of a rewritten block maps to the block's merged source span, and +// require() messages re-anchor to their (preserved) verify boundary. +import { + ConsensusBch2025, + binToHex, + createInstructionSetBch2026, + createTestAuthenticationProgramBch, + createVirtualMachine, + ripemd160, + secp256k1, + sha1, + sha256, + vmNumberToBigInt, +} from '@bitauth/libauth'; +import { + DebugFrame, + FullLocationData, + Op, + OpOrData, + OptimiseBytecodeResult, + PositionHint, + RequireStatement, + Script, + SingleLocationData, + SourceTagEntry, + bytecodeToScript, + calculateBytesize, + decodeInt, + encodeInt, + generateSourceMap, + scriptToBytecode, + sourceMapToLocationData, +} from '@cashscript/utils'; + +export interface FunctionArity { in: number; out: number } + +export interface RescheduleOptions { + arities: Map; // per OP_DEFINE'd functionId + mainInArity: number; // spend parameters + constructor parameters + objective: 'size' | 'opcost'; + constructorParamLength: number; +} + +export interface RescheduleOutcome { + result: OptimiseBytecodeResult; + frames: DebugFrame[]; +} + +// ---------- script-element helpers ---------- + +const elOpcode = (el: OpOrData): number => (typeof el === 'number' ? el : -1); + +// The constant a script element pushes, if it is a push. Small integers may be stored +// either as data (encodeInt) or as OP_0/OP_1..16/OP_1NEGATE opcode numbers (inserted by +// optimisation replacements) — normalise both to their byte content. +function constDataOf(el: OpOrData): Uint8Array | undefined { + if (el instanceof Uint8Array) return el; + if (el === Op.OP_0) return Uint8Array.of(); + if (el === Op.OP_1NEGATE) return Uint8Array.of(0x81); + if (el >= Op.OP_1 && el <= Op.OP_16) return Uint8Array.of(el - (Op.OP_1 - 1)); + return undefined; +} + +const constNumOf = (el: OpOrData): number | undefined => { + const data = constDataOf(el); + return data === undefined ? undefined : Number(decodeInt(data)); +}; + +// ---------- DAG model ---------- + +type Ref = + | { k: 'const'; data: Uint8Array } + | { k: 'in'; i: number } + | { k: 'ain'; i: number } + | { k: 'out'; node: DagNode; j: number }; + +interface DagNode { + id: number; + kind: 'prim' | 'invoke'; + code: number; // opcode for prim, functionId for invoke + ins: Ref[]; + nout: number; +} + +interface BasicBlock { + entryDepth: number; + entryAlt: number; + exit: Ref[]; + exitAlt: Ref[]; + nodes: DagNode[]; // every node created in this block, reachable from the exit or not + rawOps: Script; + rawStart: number; // element index range in the source script + rawEnd: number; // exclusive +} + +type Item = { block: BasicBlock } | { ctrl: number; index: number }; + +// value-producing ops that are pure within one transaction evaluation: opcode -> [in, out] +const VALOP = new Map([ + [Op.OP_1ADD, [1, 1]], [Op.OP_1SUB, [1, 1]], [Op.OP_NEGATE, [1, 1]], [Op.OP_ABS, [1, 1]], + [Op.OP_NOT, [1, 1]], [Op.OP_0NOTEQUAL, [1, 1]], + [Op.OP_ADD, [2, 1]], [Op.OP_SUB, [2, 1]], [Op.OP_MUL, [2, 1]], [Op.OP_DIV, [2, 1]], [Op.OP_MOD, [2, 1]], + [Op.OP_LSHIFTNUM, [2, 1]], [Op.OP_RSHIFTNUM, [2, 1]], + [Op.OP_BOOLAND, [2, 1]], [Op.OP_BOOLOR, [2, 1]], + [Op.OP_NUMEQUAL, [2, 1]], [Op.OP_NUMNOTEQUAL, [2, 1]], + [Op.OP_LESSTHAN, [2, 1]], [Op.OP_GREATERTHAN, [2, 1]], + [Op.OP_LESSTHANOREQUAL, [2, 1]], [Op.OP_GREATERTHANOREQUAL, [2, 1]], + [Op.OP_MIN, [2, 1]], [Op.OP_MAX, [2, 1]], [Op.OP_WITHIN, [3, 1]], + [Op.OP_CAT, [2, 1]], [Op.OP_SPLIT, [2, 2]], + [Op.OP_NUM2BIN, [2, 1]], [Op.OP_BIN2NUM, [1, 1]], [Op.OP_SIZE, [1, 2]], + [Op.OP_AND, [2, 1]], [Op.OP_OR, [2, 1]], [Op.OP_XOR, [2, 1]], [Op.OP_EQUAL, [2, 1]], + [Op.OP_REVERSEBYTES, [1, 1]], + [Op.OP_RIPEMD160, [1, 1]], [Op.OP_SHA1, [1, 1]], [Op.OP_SHA256, [1, 1]], + [Op.OP_HASH160, [1, 1]], [Op.OP_HASH256, [1, 1]], + [Op.OP_CHECKSIG, [2, 1]], [Op.OP_CHECKDATASIG, [3, 1]], + // introspection (constant within the evaluated transaction context) + [Op.OP_INPUTINDEX, [0, 1]], [Op.OP_ACTIVEBYTECODE, [0, 1]], + [Op.OP_TXVERSION, [0, 1]], [Op.OP_TXINPUTCOUNT, [0, 1]], [Op.OP_TXOUTPUTCOUNT, [0, 1]], [Op.OP_TXLOCKTIME, [0, 1]], + [Op.OP_UTXOVALUE, [1, 1]], [Op.OP_UTXOBYTECODE, [1, 1]], + [Op.OP_OUTPOINTTXHASH, [1, 1]], [Op.OP_OUTPOINTINDEX, [1, 1]], + [Op.OP_INPUTBYTECODE, [1, 1]], [Op.OP_INPUTSEQUENCENUMBER, [1, 1]], + [Op.OP_OUTPUTVALUE, [1, 1]], [Op.OP_OUTPUTBYTECODE, [1, 1]], + [Op.OP_UTXOTOKENCATEGORY, [1, 1]], [Op.OP_UTXOTOKENCOMMITMENT, [1, 1]], [Op.OP_UTXOTOKENAMOUNT, [1, 1]], + [Op.OP_OUTPUTTOKENCATEGORY, [1, 1]], [Op.OP_OUTPUTTOKENCOMMITMENT, [1, 1]], [Op.OP_OUTPUTTOKENAMOUNT, [1, 1]], +]); + +// control/side-effecting opcodes that bound basic blocks: opcode -> main-stack pops. +// (IF/NOTIF/UNTIL pop their condition; the VERIFY family consumes its operands; CLTV/CSV +// only peek. Emitted verbatim between blocks, so their relative order — and therefore +// which check fails first — is preserved.) +const CTRL = new Map([ + [Op.OP_IF, 1], [Op.OP_NOTIF, 1], [Op.OP_ELSE, 0], [Op.OP_ENDIF, 0], + [Op.OP_BEGIN, 0], [Op.OP_UNTIL, 1], + [Op.OP_VERIFY, 1], [Op.OP_EQUALVERIFY, 2], [Op.OP_NUMEQUALVERIFY, 2], + [Op.OP_CHECKSIGVERIFY, 2], [Op.OP_CHECKDATASIGVERIFY, 3], + [Op.OP_CHECKLOCKTIMEVERIFY, 0], [Op.OP_CHECKSEQUENCEVERIFY, 0], +]); + +let nodeCounter = 0; + +// Lift a script into [block | ctrl] items over a symbolic stack of `inArity` opaque +// entry slots. Throws on anything it cannot model (dynamic PICK depths, unknown opcodes, +// OP_DEPTH, ...) — callers treat a throw as "keep the original". +function decompile(script: Script, arities: Map, inArity: number): Item[] { + const items: Item[] = []; + let main: Ref[] = Array.from({ length: inArity }, (_, i) => ({ k: 'in', i } as Ref)); + let alt: Ref[] = []; + let entryDepth = inArity; + let entryAlt = 0; + let rawStart = 0; + let blockNodes: DagNode[] = []; + const ctrlDepth: { m: number; a: number }[] = []; + + const beginBlock = (): void => { + entryDepth = main.length; + entryAlt = alt.length; + main = main.map((_, i) => ({ k: 'in', i } as Ref)); + alt = alt.map((_, i) => ({ k: 'ain', i } as Ref)); + }; + const closeBlock = (end: number): void => { + items.push({ + block: { + entryDepth, + entryAlt, + exit: [...main], + exitAlt: [...alt], + nodes: blockNodes, + rawOps: script.slice(rawStart, end), + rawStart, + rawEnd: end, + }, + }); + blockNodes = []; + }; + const pop = (): Ref => { + const ref = main.pop(); + if (ref === undefined) throw new Error('stack underflow while decompiling'); + return ref; + }; + const popConstNum = (): number => { + const ref = pop(); + if (ref.k !== 'const') throw new Error('dynamic operand for PICK/ROLL/INVOKE'); + return Number(decodeInt(ref.data)); + }; + + for (let i = 0; i < script.length; i += 1) { + const el = script[i]; + const op = elOpcode(el); + + if (CTRL.has(op)) { + closeBlock(i); + if (op === Op.OP_IF || op === Op.OP_NOTIF) { + pop(); + ctrlDepth.push({ m: main.length, a: alt.length }); + } else if (op === Op.OP_ELSE) { + const s = ctrlDepth[ctrlDepth.length - 1]; + main.length = s.m; + alt.length = s.a; + } else if (op === Op.OP_ENDIF) { + ctrlDepth.pop(); + } else { + for (let k = 0; k < CTRL.get(op)!; k += 1) pop(); + } + items.push({ ctrl: op, index: i }); + rawStart = i + 1; + beginBlock(); + continue; + } + + const data = constDataOf(el); + if (data !== undefined) { + main.push({ k: 'const', data }); + continue; + } + + switch (op) { + case Op.OP_DUP: main.push(main[main.length - 1]); break; + case Op.OP_DROP: pop(); break; + case Op.OP_2DROP: pop(); pop(); break; + case Op.OP_2DUP: { const b = main[main.length - 1]; const a = main[main.length - 2]; main.push(a, b); break; } + case Op.OP_3DUP: { + const c = main[main.length - 1]; const b = main[main.length - 2]; const a = main[main.length - 3]; + main.push(a, b, c); break; + } + case Op.OP_OVER: main.push(main[main.length - 2]); break; + case Op.OP_2OVER: { const b = main[main.length - 3]; const a = main[main.length - 4]; main.push(a, b); break; } + case Op.OP_SWAP: { const n = main.length; [main[n - 1], main[n - 2]] = [main[n - 2], main[n - 1]]; break; } + case Op.OP_2SWAP: { + const n = main.length; const a = main[n - 4]; const b = main[n - 3]; + main[n - 4] = main[n - 2]; main[n - 3] = main[n - 1]; main[n - 2] = a; main[n - 1] = b; break; + } + case Op.OP_ROT: { + const n = main.length; const a = main[n - 3]; + main[n - 3] = main[n - 2]; main[n - 2] = main[n - 1]; main[n - 1] = a; break; + } + case Op.OP_2ROT: { + const n = main.length; const a = main[n - 6]; const b = main[n - 5]; + for (let k = n - 6; k < n - 2; k += 1) main[k] = main[k + 2]; + main[n - 2] = a; main[n - 1] = b; break; + } + case Op.OP_TUCK: { + const n = main.length; const b = main[n - 1]; const a = main[n - 2]; + main[n - 2] = b; main[n - 1] = a; main.push(b); break; + } + case Op.OP_NIP: main.splice(main.length - 2, 1); break; + case Op.OP_TOALTSTACK: alt.push(pop()); break; + case Op.OP_FROMALTSTACK: { const ref = alt.pop(); if (ref === undefined) throw new Error('alt underflow'); main.push(ref); break; } + case Op.OP_PICK: { + const n = popConstNum(); + const picked = main[main.length - 1 - n]; + if (picked === undefined) throw new Error('PICK past stack bottom'); + main.push(picked); break; + } + case Op.OP_ROLL: { + const n = popConstNum(); + const idx = main.length - 1 - n; + if (idx < 0) throw new Error('ROLL past stack bottom'); + const [v] = main.splice(idx, 1); + main.push(v); break; + } + case Op.OP_INVOKE: { + const id = popConstNum(); + const arity = arities.get(id); + if (arity === undefined) throw new Error(`unknown function id ${id}`); + const ins: Ref[] = []; + for (let k = 0; k < arity.in; k += 1) ins.unshift(pop()); + nodeCounter += 1; + const node: DagNode = { id: nodeCounter, kind: 'invoke', code: id, ins, nout: arity.out }; + blockNodes.push(node); + for (let j = 0; j < arity.out; j += 1) main.push({ k: 'out', node, j }); + break; + } + default: { + const valop = VALOP.get(op); + if (valop === undefined) throw new Error(`unsupported opcode 0x${op.toString(16)}`); + const [nin, nout] = valop; + const ins: Ref[] = []; + for (let k = 0; k < nin; k += 1) ins.unshift(pop()); + nodeCounter += 1; + const node: DagNode = { id: nodeCounter, kind: 'prim', code: op, ins, nout }; + blockNodes.push(node); + for (let j = 0; j < nout; j += 1) main.push({ k: 'out', node, j }); + break; + } + } + } + closeBlock(script.length); + return items; +} + +// ---------- scheduler ---------- + +type Strategy = 'topo' | 'greedy' | 'opcost' | 'beam'; + +const keyOf = (ref: Ref): string | undefined => { + if (ref.k === 'in') return `m${ref.i}`; + if (ref.k === 'ain') return `a${ref.i}`; + if (ref.k === 'out') return `n${ref.node.id}_${ref.j}`; + return undefined; +}; + +// nominal stack-item length for op-cost estimates (item sizes are unknown statically) +const NOMINAL_LEN = 33; + +// incremental per-element op-cost, mirroring opCostEstimate below +function costOfAppend(prev: OpOrData | undefined, el: OpOrData): number { + const data = constDataOf(el); + if (data !== undefined) return 100 + data.length; + switch (elOpcode(el)) { + case Op.OP_DUP: case Op.OP_OVER: case Op.OP_TUCK: case Op.OP_FROMALTSTACK: case Op.OP_PICK: + return 100 + NOMINAL_LEN; + case Op.OP_ROLL: return 100 + NOMINAL_LEN + (prev !== undefined ? (constNumOf(prev) ?? 0) : 0); + case Op.OP_2DUP: case Op.OP_2OVER: case Op.OP_2ROT: return 100 + 2 * NOMINAL_LEN; + case Op.OP_3DUP: return 100 + 3 * NOMINAL_LEN; + default: return 100; + } +} + +// mutable emission state; cloneable for the beam search +interface EmitState { + out: Script; + stk: string[]; + useCount: Map; + remaining: Set; + cost: number; // accumulated static op-cost of `out` +} + +const cloneState = (s: EmitState): EmitState => ({ + out: [...s.out], stk: [...s.stk], useCount: new Map(s.useCount), remaining: new Set(s.remaining), cost: s.cost, +}); + +const appendOp = (s: EmitState, el: OpOrData): void => { + s.cost += costOfAppend(s.out[s.out.length - 1], el); + s.out.push(el); +}; + +const topmostIndex = (stk: string[], key: string): number => stk.lastIndexOf(key); +const deepestIndex = (stk: string[], key: string): number => stk.indexOf(key); +const pushNum = (s: EmitState, value: number): void => { appendOp(s, encodeInt(BigInt(value))); }; + +// bring `key` to the top of the stack: a copy targets the shallowest occurrence +// (cheapest); a consuming move targets the deepest (original) so freshly staged copies +// above it are preserved +function bring(s: EmitState, key: string, move: boolean): void { + const idx = move ? deepestIndex(s.stk, key) : topmostIndex(s.stk, key); + if (idx < 0) throw new Error(`value not on stack: ${key}`); + const depth = s.stk.length - 1 - idx; + if (move) { + if (depth === 1) appendOp(s, Op.OP_SWAP); + else if (depth === 2) appendOp(s, Op.OP_ROT); + else if (depth > 2) { pushNum(s, depth); appendOp(s, Op.OP_ROLL); } + s.stk.splice(idx, 1); + s.stk.push(key); + } else { + if (depth === 0) appendOp(s, Op.OP_DUP); + else if (depth === 1) appendOp(s, Op.OP_OVER); + else { pushNum(s, depth); appendOp(s, Op.OP_PICK); } + s.stk.push(key); + } +} + +function bringRef(s: EmitState, ref: Ref, consumeContext: boolean, exitNeed: Map): void { + if (ref.k === 'const') { appendOp(s, ref.data); s.stk.push('#k'); return; } + const key = keyOf(ref)!; + if (consumeContext) { + const remNode = s.useCount.get(key) ?? 0; // node-input uses remaining (incl. this one) + const survives = remNode > 1 || (exitNeed.get(key) ?? 0) > 0; + bring(s, key, !survives); + s.useCount.set(key, remNode - 1); + } else { + const remExit = exitNeed.get(key) ?? 0; + bring(s, key, !(remExit > 1)); + exitNeed.set(key, remExit - 1); + } +} + +// compute one DAG node on top of the stack, staging arguments in the callee's chosen +// entry order for permuted OP_INVOKE targets +function computeNode(s: EmitState, node: DagNode, exitNeed: Map, calleePerms: Map): void { + s.remaining.delete(node.id); + const perm = node.kind === 'invoke' ? calleePerms.get(node.code) : undefined; + const staged = perm !== undefined ? perm.map((i) => node.ins[i]) : node.ins; + staged.forEach((r) => bringRef(s, r, true, exitNeed)); + if (node.kind === 'invoke') { pushNum(s, node.code); appendOp(s, Op.OP_INVOKE); } else appendOp(s, node.code); + s.stk.length -= node.ins.length; + for (let j = 0; j < node.nout; j += 1) s.stk.push(`n${node.id}_${j}`); +} + +interface EmitOptions { + entrySeed?: string[]; // stack labels at block entry, bottom -> top (defaults to m0..mN-1) + calleePerms?: Map; +} + +const NO_PERMS: Map = new Map(); +const BEAM_WIDTH = 4; +const BEAM_EXPAND = 3; + +// Re-emit one block: seed the entry slots, compute the DAG nodes in a strategy-chosen +// dependency order (fetching each operand with the cheapest available move/copy), then +// assemble the exact exit layout and clean leftover slots. +function emitBlock(block: BasicBlock, strategy: Strategy, options: EmitOptions = {}): Script { + const { entryDepth: n, entryAlt: p, exit, exitAlt } = block; + const calleePerms = options.calleePerms ?? NO_PERMS; + + // topo order of needed nodes (memoised — the DAGs share subtrees heavily) + const visited = new Set(); + const order: DagNode[] = []; + const visitNode = (node: DagNode): void => { + if (visited.has(node.id)) return; + visited.add(node.id); + node.ins.forEach((ref) => { if (ref.k === 'out') visitNode(ref.node); }); + order.push(node); + }; + [...exit, ...exitAlt].forEach((ref) => { if (ref.k === 'out') visitNode(ref.node); }); + + // altstack passthrough: if the entry altstack is returned untouched and never read, + // leave it there (emit zero alt ops) + const altReferenced = exit.some((r) => r.k === 'ain') || order.some((nd) => nd.ins.some((r) => r.k === 'ain')); + const exitAltPass = exitAlt.length === p && exitAlt.every((r, i) => r.k === 'ain' && r.i === i); + const altPass = exitAltPass && !altReferenced; + + const useCount = new Map(); + const exitNeed = new Map(); + const bump = (map: Map, key: string | undefined): void => { + if (key !== undefined) map.set(key, (map.get(key) ?? 0) + 1); + }; + order.forEach((nd) => nd.ins.forEach((r) => bump(useCount, keyOf(r)))); + [...exit, ...exitAlt].forEach((r) => bump(exitNeed, keyOf(r))); + + const initial: EmitState = { + out: [], stk: [], useCount, remaining: new Set(order.map((nd) => nd.id)), cost: 0, + }; + for (let i = 0; i < n; i += 1) initial.stk.push(options.entrySeed?.[i] ?? `m${i}`); + if (!altPass) for (let i = 0; i < p; i += 1) { appendOp(initial, Op.OP_FROMALTSTACK); initial.stk.push(`a${p - 1 - i}`); } + + // fetch-cost heuristics for choosing the next ready node + const pushBytesForDepth = (depth: number): number => (depth <= 16 ? 1 : 2); + const fetchCostBytes = (s: EmitState, nd: DagNode): number => nd.ins.reduce((sum, r) => { + if (r.k === 'const') return sum + Math.max(1, r.data.length); + const key = keyOf(r)!; + const idx = topmostIndex(s.stk, key); + if (idx < 0) return sum; + const depth = s.stk.length - 1 - idx; + const lastUse = (s.useCount.get(key) ?? 0) <= 1 && (exitNeed.get(key) ?? 0) === 0; + if (lastUse) return sum + (depth === 0 ? 0 : depth <= 2 ? 1 : pushBytesForDepth(depth) + 1); + return sum + (depth <= 1 ? 1 : pushBytesForDepth(depth) + 1); + }, 0); + const fetchCostOp = (s: EmitState, nd: DagNode): number => nd.ins.reduce((sum, r) => { + if (r.k === 'const') return sum + 100 + r.data.length; + const key = keyOf(r)!; + const idx = topmostIndex(s.stk, key); + if (idx < 0) return sum; + const depth = s.stk.length - 1 - idx; + const lastUse = (s.useCount.get(key) ?? 0) <= 1 && (exitNeed.get(key) ?? 0) === 0; + if (lastUse) return sum + (depth === 0 ? 0 : depth <= 2 ? 100 : 201 + NOMINAL_LEN + depth); + return sum + (depth <= 1 ? 100 + NOMINAL_LEN : 201 + NOMINAL_LEN); + }, 0); + + const inputNodeIds = (nd: DagNode): number[] => nd.ins.flatMap((r) => (r.k === 'out' ? [r.node.id] : [])); + const readyNodes = (s: EmitState): DagNode[] => order.filter( + (nd) => s.remaining.has(nd.id) && inputNodeIds(nd).every((id) => !s.remaining.has(id)), + ); + + // assemble the exit layout on top (exit-main ++ reverse(exit-alt) unless alt passes + // through), clean buried junk, and restore the altstack + const finish = (s: EmitState): void => { + const need = new Map(exitNeed); + const desired = altPass ? [...exit] : [...exit, ...[...exitAlt].reverse()]; + const desiredKeys = desired.map((r) => (r.k === 'const' ? undefined : keyOf(r))); + const inPlace = s.stk.length >= desired.length + && desiredKeys.every((dk, i) => dk !== undefined && s.stk[s.stk.length - desired.length + i] === dk); + if (!inPlace) desired.forEach((r) => bringRef(s, r, false, need)); + + const K = desired.length; + const junk = s.stk.length - K; + if (junk > 0) { + if (2 * K + junk <= 4 * junk) { + for (let i = 0; i < K; i += 1) appendOp(s, Op.OP_TOALTSTACK); + for (let i = 0; i < junk; i += 1) appendOp(s, Op.OP_DROP); + for (let i = 0; i < K; i += 1) appendOp(s, Op.OP_FROMALTSTACK); + s.stk = s.stk.slice(s.stk.length - K); + } else { + for (let i = 0; i < junk; i += 1) { + pushNum(s, s.stk.length - 1); appendOp(s, Op.OP_ROLL); appendOp(s, Op.OP_DROP); s.stk.splice(0, 1); + } + } + } + if (!altPass) for (let i = 0; i < exitAlt.length; i += 1) appendOp(s, Op.OP_TOALTSTACK); + }; + + if (strategy !== 'beam') { + const state = initial; + while (state.remaining.size > 0) { + const candidates = readyNodes(state); + let node = candidates[0]; + if (strategy !== 'topo') { + const cost = strategy === 'opcost' ? fetchCostOp : fetchCostBytes; + let best = cost(state, candidates[0]); + candidates.forEach((candidate) => { + const c = cost(state, candidate); + if (c < best) { best = c; node = candidate; } + }); + } + computeNode(state, node, exitNeed, calleePerms); + } + finish(state); + return state.out; + } + + // beam search: expand each surviving state by its BEAM_EXPAND cheapest ready nodes, + // keep the BEAM_WIDTH cheapest accumulated schedules (all states have computed the + // same number of nodes, so accumulated cost is comparable) + let beam: EmitState[] = [initial]; + for (let step = 0; step < order.length; step += 1) { + const next: EmitState[] = []; + beam.forEach((state) => { + const candidates = readyNodes(state) + .map((nd) => ({ nd, c: fetchCostOp(state, nd) })) + .sort((a, b) => a.c - b.c) + .slice(0, BEAM_EXPAND); + candidates.forEach(({ nd }) => { + const branch = cloneState(state); + computeNode(branch, nd, exitNeed, calleePerms); + next.push(branch); + }); + }); + next.sort((a, b) => a.cost - b.cost); + beam = next.slice(0, BEAM_WIDTH); + } + let best: Script | undefined; + let bestCost = Infinity; + beam.forEach((state) => { + finish(state); + if (state.cost < bestCost) { bestCost = state.cost; best = state.out; } + }); + // A dead-ended beam means no complete schedule was found; initial.out would be a script that + // computed nothing, so fail closed — every caller catches and keeps the original body. + if (best === undefined) throw new Error('beam search dead-ended without a complete schedule'); + return best; +} + +// collapse adjacent single-item stack ops into their multi-item forms (all provably +// stack-equivalent; the main optimiser applies the same families of rewrites) +function peephole(script: Script): Script { + const isN = (el: OpOrData | undefined, value: number): boolean => ( + el !== undefined && constNumOf(el) === value && constDataOf(el)!.length === 1 + ); + const isOp = (el: OpOrData | undefined, op: number): boolean => el !== undefined && typeof el === 'number' && el === op; + let ops = script; + let changed = true; + while (changed) { + changed = false; + const out: Script = []; + for (let i = 0; i < ops.length; i += 1) { + const [a, b, c, d, e, f] = [ops[i], ops[i + 1], ops[i + 2], ops[i + 3], ops[i + 4], ops[i + 5]]; + if (isN(a, 2) && isOp(b, Op.OP_PICK) && isN(c, 2) && isOp(d, Op.OP_PICK) && isN(e, 2) && isOp(f, Op.OP_PICK)) { + out.push(Op.OP_3DUP); i += 5; changed = true; continue; + } + if (isOp(a, Op.OP_OVER) && isOp(b, Op.OP_OVER)) { out.push(Op.OP_2DUP); i += 1; changed = true; continue; } + if (isOp(a, Op.OP_SWAP) && isOp(b, Op.OP_OVER)) { out.push(Op.OP_TUCK); i += 1; changed = true; continue; } + if (isOp(a, Op.OP_SWAP) && isOp(b, Op.OP_DROP)) { out.push(Op.OP_NIP); i += 1; changed = true; continue; } + if (isN(a, 3) && isOp(b, Op.OP_PICK) && isN(c, 3) && isOp(d, Op.OP_PICK)) { + out.push(Op.OP_2OVER); i += 3; changed = true; continue; + } + if (isN(a, 3) && isOp(b, Op.OP_ROLL) && isN(c, 3) && isOp(d, Op.OP_ROLL)) { + out.push(Op.OP_2SWAP); i += 3; changed = true; continue; + } + if (isN(a, 5) && isOp(b, Op.OP_ROLL) && isN(c, 5) && isOp(d, Op.OP_ROLL)) { + out.push(Op.OP_2ROT); i += 3; changed = true; continue; + } + out.push(a); + } + ops = out; + } + return ops; +} + +// ---------- cost models ---------- + +// Static estimate of the schedule-dependent part of the BCH2026 op-cost meter. Value ops' +// own result pushes are identical across schedules of the same DAG and are left out; this +// RANKS schedules, it does not predict absolute cost. +export function opCostEstimate(script: Script): number { + let cost = 0; + for (let i = 0; i < script.length; i += 1) { + cost += costOfAppend(i > 0 ? script[i - 1] : undefined, script[i]); + } + return cost; +} + +const scriptCost = (script: Script, objective: 'size' | 'opcost'): number => ( + // redeem bytes still cost 1 op each in the scriptSig push, which doubles as a tiebreak + objective === 'opcost' ? opCostEstimate(script) + calculateBytesize(script) : calculateBytesize(script) +); + +// ---------- per-script rescheduling ---------- + +interface ItemMapping { + oldStart: number; + oldEnd: number; // exclusive + newStart: number; + newEnd: number; // exclusive + rewritten: boolean; +} + +interface RecompiledScript { + script: Script; + mapping: ItemMapping[]; + changed: boolean; +} + +interface RecompileOptions { + entryPerm?: number[]; // permuted entry layout of the FIRST block (bottom -> top holds slot perm[j]) + calleePerms?: Map; +} + +const isIdentityPerm = (perm: number[] | undefined): boolean => perm === undefined || perm.every((v, i) => v === i); + +// over ALL block nodes (not just exit-reachable ones): a dead invoke of a permuted callee +// still stages its arguments in the raw ops, which would be the wrong order +const blockInvokesPermuted = (block: BasicBlock, calleePerms: Map): boolean => ( + calleePerms.size > 0 && block.nodes.some((nd) => nd.kind === 'invoke' && calleePerms.has(nd.code)) +); + +// A node unreachable from the block's exit stacks is dead computation: its result never +// leaves the block. Since script failure aborts evaluation, rejecting the spend is the +// only observable effect such a node has — deleting it widens the set of accepted +// witnesses. The realistic case is a void function call (its require lives in the callee, +// so the call site is a zero-output invoke node, dead by construction); an `unused` +// variable's failure-capable initializer (e.g. a division) is the same hole. Blocks +// containing dead computation keep their original ops verbatim. +const hasDeadComputation = (block: BasicBlock): boolean => { + if (block.nodes.length === 0) return false; + const reachable = new Set(); + const visitNode = (node: DagNode): void => { + if (reachable.has(node.id)) return; + reachable.add(node.id); + node.ins.forEach((ref) => { if (ref.k === 'out') visitNode(ref.node); }); + }; + [...block.exit, ...block.exitAlt].forEach((ref) => { if (ref.k === 'out') visitNode(ref.node); }); + return block.nodes.some((node) => !reachable.has(node.id)); +}; + +function recompileScript( + script: Script, + arities: Map, + inArity: number, + strategy: Strategy, + objective: 'size' | 'opcost', + options: RecompileOptions = {}, +): RecompiledScript { + const calleePerms = options.calleePerms ?? NO_PERMS; + const items = decompile(script, arities, inArity); + const out: Script = []; + const mapping: ItemMapping[] = []; + let changed = false; + let firstBlock = true; + items.forEach((item) => { + if ('ctrl' in item) { + mapping.push({ + oldStart: item.index, oldEnd: item.index + 1, newStart: out.length, newEnd: out.length + 1, rewritten: false, + }); + out.push(item.ctrl); + return; + } + const { block } = item; + const entryPerm = firstBlock ? options.entryPerm : undefined; + const entrySeed = entryPerm !== undefined ? entryPerm.map((slot) => `m${slot}`) : undefined; + firstBlock = false; + // the plain-cashc block is only a valid candidate under the standard entry layout + // and standard callee conventions + const rawValid = isIdentityPerm(entryPerm) && !blockInvokesPermuted(block, calleePerms); + // a block with dead computation has no valid re-emission (see hasDeadComputation); + // if the original ops are not valid either, this whole variant is unusable + const dead = hasDeadComputation(block); + if (dead && !rawValid) throw new Error('dead computation in a block that cannot keep its original ops'); + // per-block min(original, rescheduled): both reproduce the block's entry->exit + // transform AND its boundary layout, so they compose freely + const mine = dead ? undefined : peephole(emitBlock(block, strategy, { entrySeed, calleePerms })); + const useMine = mine !== undefined + && (!rawValid || scriptCost(mine, objective) < scriptCost(block.rawOps, objective)); + const chosen = useMine ? mine! : block.rawOps; + mapping.push({ + oldStart: block.rawStart, + oldEnd: block.rawEnd, + newStart: out.length, + newEnd: out.length + chosen.length, + rewritten: useMine, + }); + chosen.forEach((el) => out.push(el)); + if (useMine) changed = true; + }); + return { script: out, mapping, changed }; +} + +// ---------- OP_DEFINE table dissection ---------- + +interface Dissected { + order: number[]; + bodies: Map; + tableLength: number; // element count of the define table prefix + main: Script; +} + +function dissect(script: Script): Dissected { + const order: number[] = []; + const bodies = new Map(); + let i = 0; + while (i + 2 < script.length && script[i] instanceof Uint8Array && elOpcode(script[i + 2]) === Op.OP_DEFINE) { + const id = constNumOf(script[i + 1]); + if (id === undefined) break; + bodies.set(id, bytecodeToScript(script[i] as Uint8Array)); + order.push(id); + i += 3; + } + return { order, bodies, tableLength: i, main: script.slice(i) }; +} + +// function ids a body invokes (directly) +function bodyInvokes(body: Script): number[] { + const ids: number[] = []; + for (let i = 1; i < body.length; i += 1) { + if (elOpcode(body[i]) === Op.OP_INVOKE) { + const id = constNumOf(body[i - 1]); + if (id !== undefined) ids.push(id); + } + } + return ids; +} + +// An OP_INVOKE whose callee id is not the immediately preceding constant is invisible to +// bodyInvokes, so a permuted callee would silently receive its arguments in the old order at +// such a call site — layout experiments must not run when one exists anywhere in the program. +const hasAmbiguousInvoke = (script: Script): boolean => script.some((el, i) => ( + elOpcode(el) === Op.OP_INVOKE && (i === 0 || constNumOf(script[i - 1]) === undefined) +)); + +// callee-first processing order over the call graph (declaration order on cycles) +function calleeFirstOrder(d: Dissected): number[] { + const visited = new Set(); + const out: number[] = []; + const visit = (id: number): void => { + if (visited.has(id) || !d.bodies.has(id)) return; + visited.add(id); + bodyInvokes(d.bodies.get(id)!).forEach(visit); + out.push(id); + }; + d.order.forEach(visit); + return out; +} + +// ---------- differential testing + measurement on a loosened VM ---------- + +// Loosened BCH2026 VM: lifts size/op-cost/stack caps so any single function body can run +// to completion on random inputs regardless of contract-level limits. +/* eslint-disable @typescript-eslint/no-explicit-any */ +const loosenedConsensus: any = { + ...ConsensusBch2025, + baseInstructionCost: 100, + maximumFunctionIdentifierLength: 7, + maximumMemorySlots: Number.MAX_SAFE_INTEGER, + maximumStandardLockingBytecodeLength: -1, + maximumStandardUnlockingBytecodeLength: Number.MAX_SAFE_INTEGER, + maximumTokenCommitmentLength: 128, + operationCostBudgetPerByte: Number.MAX_SAFE_INTEGER, + maximumStackItemLength: Number.MAX_SAFE_INTEGER, + maximumVmNumberByteLength: Number.MAX_SAFE_INTEGER, + maximumStackDepth: Number.MAX_SAFE_INTEGER, + maximumControlStackDepth: Number.MAX_SAFE_INTEGER, + maximumBytecodeLength: Number.MAX_SAFE_INTEGER, + maximumOperationCount: Number.MAX_SAFE_INTEGER, +}; + +let cachedVm: any; +const looseVm = (): any => { + cachedVm ??= createVirtualMachine(createInstructionSetBch2026(false, { + consensus: loosenedConsensus, ripemd160, secp256k1, sha1, sha256, + } as any)); + return cachedVm; +}; +/* eslint-enable @typescript-eslint/no-explicit-any */ + +// deterministic pseudo-random test inputs (~254-bit values, matching wide int math) +const RND_MOD = 21888242871839275222246405745257275088696311157297823662689037894645226208583n; +const rnd = (seed: number): bigint => { + let x = BigInt(seed + 7); + for (let i = 0; i < 6; i += 1) x = (x * 6364136223846793005n + 1442695040888963407n) % RND_MOD; + return x; +}; + +interface BodyRun { stack?: string[]; opCost: number; error?: string } + +// run one function on the loosened VM. `inputPerm` stages the inputs in the target's +// (possibly permuted) entry order: stack position j receives inputs[perm[j]]. +function runBody( + d: Dissected, overrides: Map, targetId: number, inputs: bigint[], inputPerm?: number[], +): BodyRun { + const program: Script = []; + d.order.forEach((id) => { + program.push(scriptToBytecode(overrides.get(id) ?? d.bodies.get(id)!), encodeInt(BigInt(id)), Op.OP_DEFINE); + }); + const staged = inputPerm !== undefined ? inputPerm.map((i) => inputs[i]) : inputs; + staged.forEach((input) => program.push(encodeInt(input))); + program.push(encodeInt(BigInt(targetId)), Op.OP_INVOKE); + const state = looseVm().evaluate(createTestAuthenticationProgramBch({ + lockingBytecode: scriptToBytecode(program), unlockingBytecode: Uint8Array.of(), valueSatoshis: 1000n, + })); + // the only expected "error" is the benign post-evaluation clean-stack check + const benign = state.error === undefined || /Non-P2SH|clean stack|exactly one|single/i.test(String(state.error)); + return { + stack: benign + ? state.stack.map((item: Uint8Array) => ( + vmNumberToBigInt(item, { maximumVmNumberByteLength: Number.MAX_SAFE_INTEGER as never }).toString() + )) + : undefined, + opCost: Number(state.metrics.operationCost), + error: benign ? undefined : String(state.error), + }; +} + +// The candidate (with all chosen overrides and its entry permutation) must reproduce the +// ORIGINAL body's output stack — original bodies all the way down, standard input order — +// on K random vectors. +function bodyEquiv( + d: Dissected, overrides: Map, id: number, + candidate: Script, arity: FunctionArity, perm: number[] | undefined, K = 3, +): boolean { + for (let t = 0; t < K; t += 1) { + const inputs = Array.from({ length: arity.in }, (_, i) => rnd(i * 17 + t * 1009 + id)); + const reference = runBody(d, new Map(), id, inputs); + const candidateRun = runBody(d, new Map([...overrides, [id, candidate]]), id, inputs, perm); + if (reference.stack === undefined || candidateRun.stack === undefined) return false; + if (reference.stack.join() !== candidateRun.stack.join()) return false; + } + return true; +} + +// summed measured op-cost of a body over K fixed random vectors (Infinity on any error) +function measureBody( + d: Dissected, overrides: Map, id: number, + arity: FunctionArity, perm: number[] | undefined, K = 3, +): number { + let total = 0; + for (let t = 0; t < K; t += 1) { + const inputs = Array.from({ length: arity.in }, (_, i) => rnd(i * 23 + t * 811 + id)); + const run = runBody(d, overrides, id, inputs, perm); + if (run.error !== undefined || run.stack === undefined) return Infinity; + total += run.opCost; + } + return total; +} + +// ---------- entry-layout candidates ---------- + +// Candidate argument orders for a body, derived from its first block's DAG: identity, +// reverse, earliest-first-use nearest the top, and most-used nearest the top. A `perm` +// maps stack position j (bottom -> top) to the original entry slot held there. +function layoutCandidates(body: Script, arities: Map, inArity: number): number[][] { + const identity = Array.from({ length: inArity }, (_, i) => i); + if (inArity < 2) return [identity]; + let items: Item[]; + try { items = decompile(body, arities, inArity); } catch { return [identity]; } + const first = items.find((item): item is { block: BasicBlock } => 'block' in item); + if (first === undefined) return [identity]; + + const visited = new Set(); + const order: DagNode[] = []; + const visitNode = (node: DagNode): void => { + if (visited.has(node.id)) return; + visited.add(node.id); + node.ins.forEach((ref) => { if (ref.k === 'out') visitNode(ref.node); }); + order.push(node); + }; + [...first.block.exit, ...first.block.exitAlt].forEach((ref) => { if (ref.k === 'out') visitNode(ref.node); }); + + const firstUse = new Array(inArity).fill(Number.MAX_SAFE_INTEGER); + const useCount = new Array(inArity).fill(0); + order.forEach((nd, t) => nd.ins.forEach((r) => { + if (r.k !== 'in' || r.i >= inArity) return; + firstUse[r.i] = Math.min(firstUse[r.i], t); + useCount[r.i] += 1; + })); + + // stable sorts; the deepest position gets the FIRST element of the sorted list + const byFirstUseDesc = [...identity].sort((a, b) => (firstUse[b] - firstUse[a]) || (a - b)); + const byUseCountAsc = [...identity].sort((a, b) => (useCount[a] - useCount[b]) || (a - b)); + const reverse = [...identity].reverse(); + + const seen = new Set(); + return [identity, byFirstUseDesc, byUseCountAsc, reverse].filter((perm) => { + const key = perm.join(','); + if (seen.has(key)) return false; + seen.add(key); + return true; + }); +} + +// ---------- body selection ---------- + +const BODY_STRATEGIES: Strategy[] = ['topo', 'greedy', 'opcost']; +const MAIN_STRATEGIES: Strategy[] = ['topo', 'greedy', 'opcost']; +// adopt a non-identity entry layout only if it beats the best identity variant by >1% +// (its call-site staging costs are not visible in the body-level measurement) +const LAYOUT_HYSTERESIS = 1.01; + +interface BodyChoices { + overrides: Map; + perms: Map; +} + +// Reschedule every OP_DEFINE'd body; keep, per body, the best diff-test-equivalent +// candidate ('size': smallest bytes; 'opcost': smallest MEASURED op-cost). With +// `layouts`, entry-order permutations and a beam schedule join the candidate set, and +// bodies are processed callee-first so callers re-stage for their callees' chosen +// orders. Throws if a body whose callee was permuted has no valid replacement (the +// caller falls back to identity layouts wholesale). +function rescheduleBodies( + d: Dissected, arities: Map, objective: 'size' | 'opcost', layouts: boolean, +): BodyChoices { + const overrides = new Map(); + const perms = new Map(); + const strategies: Strategy[] = layouts ? [...BODY_STRATEGIES, 'beam'] : BODY_STRATEGIES; + const processing = layouts ? calleeFirstOrder(d) : d.order; + + processing.forEach((id) => { + const arity = arities.get(id); + const original = d.bodies.get(id)!; + const calleesPermuted = bodyInvokes(original).some((callee) => perms.has(callee)); + if (arity === undefined) { + if (calleesPermuted) throw new Error(`body ${id} invokes a permuted callee but has no arity`); + return; + } + const bodyCost = (candidate: Script, perm: number[] | undefined): number => ( + objective === 'opcost' + ? measureBody(d, new Map([...overrides, [id, candidate]]), id, arity, perm) + : calculateBytesize(candidate) + ); + + let best: Script | undefined; + let bestPerm: number[] | undefined; + let bestCost = Infinity; + // baseline: the untouched cashc body (only valid while its callees are unpermuted) + if (!calleesPermuted) { + bestCost = objective === 'opcost' ? measureBody(d, overrides, id, arity, undefined) : calculateBytesize(original); + } + + const candidatesPerms = layouts ? layoutCandidates(original, arities, arity.in) : [undefined]; + candidatesPerms.forEach((perm) => { + const identity = isIdentityPerm(perm as number[] | undefined); + strategies.forEach((strategy) => { + let candidate: Script; + try { + candidate = recompileScript(original, arities, arity.in, strategy, objective, { + entryPerm: perm as number[] | undefined, calleePerms: perms, + }).script; + } catch { return; } + const cost = bodyCost(candidate, identity ? undefined : (perm as number[])); + const effective = identity ? cost : cost * LAYOUT_HYSTERESIS; + const effectivePerm = identity ? undefined : (perm as number[]); + if (effective < bestCost && bodyEquiv(d, overrides, id, candidate, arity, effectivePerm)) { + best = candidate; + bestPerm = identity ? undefined : (perm as number[]); + bestCost = effective; + } + }); + }); + + if (best !== undefined) { + overrides.set(id, best); + if (bestPerm !== undefined) perms.set(id, bestPerm); + } else if (calleesPermuted) { + // the original body is invalid under the new callee conventions and no candidate + // validated — abort the layout experiment for this contract + throw new Error(`no valid re-emission for body ${id} under permuted callees`); + } + }); + + return { overrides, perms }; +} + +// ---------- debug-information remapping ---------- + +const mergeLocations = (locations: SingleLocationData[]): SingleLocationData => { + const lowest = locations.reduce((low, cur) => { + const { start: a } = low.location; const { start: b } = cur.location; + return (b.line < a.line || (b.line === a.line && b.column < a.column)) ? cur : low; + }); + const highest = locations.reduce((high, cur) => { + const { end: a } = high.location; const { end: b } = cur.location; + return (b.line > a.line || (b.line === a.line && b.column > a.column)) ? cur : high; + }); + return { + location: { start: lowest.location.start, end: highest.location.end }, + positionHint: locations[locations.length - 1]?.positionHint ?? PositionHint.START, + }; +}; + +// old element index -> new element index. Exact for untouched regions and preserved +// boundary opcodes; indices inside a rewritten block clamp to the block's last opcode +// (the closest instruction to the failing check for error attribution). +const indexRemapper = (mapping: ItemMapping[], offset: number) => (oldIndex: number): number => { + if (oldIndex < offset) return oldIndex; + const local = oldIndex - offset; + for (const m of mapping) { + if (local >= m.oldStart && local < m.oldEnd) { + return offset + (m.rewritten ? Math.max(m.newStart, m.newEnd - 1) : m.newStart + (local - m.oldStart)); + } + } + const last = mapping[mapping.length - 1]; + return offset + (last?.newEnd ?? 0) + (local - (last?.oldEnd ?? 0)); +}; + +function remapLocationData(locationData: FullLocationData, mapping: ItemMapping[], offset: number): FullLocationData { + const out: FullLocationData = locationData.slice(0, offset); + mapping.forEach((m) => { + const slice = locationData.slice(offset + m.oldStart, offset + m.oldEnd); + if (!m.rewritten) { slice.forEach((entry) => out.push(entry)); return; } + const merged = slice.length > 0 ? mergeLocations(slice) : locationData[offset + m.oldStart - 1]; + for (let i = m.newStart; i < m.newEnd; i += 1) out.push(merged); + }); + return out; +} + +// ---------- the pass ---------- + +export function applyStackRescheduling( + optimised: OptimiseBytecodeResult, + frames: DebugFrame[], + options: RescheduleOptions, +): RescheduleOutcome { + const { arities, objective, constructorParamLength } = options; + const d = dissect(optimised.script); + + // 1. bodies (skipped for a body with console.log entries — wholesale reordering cannot + // preserve per-instruction log data) + const framesByBytecode = new Map(frames.map((frame) => [frame.bytecode, frame])); + const loggedBodies = new Set( + d.order.filter((id) => { + const frame = framesByBytecode.get(binToHex(scriptToBytecode(d.bodies.get(id)!))); + return (frame?.logs.length ?? 0) > 0; + }), + ); + const loggableArities = new Map([...arities].filter(([id]) => !loggedBodies.has(id))); + + let choices: BodyChoices; + // The layout search needs main to be re-writable (it may have to re-stage arguments), and + // every call site in the whole program must be ` OP_INVOKE` — see hasAmbiguousInvoke. + const allScripts = [d.main, ...d.order.map((id) => d.bodies.get(id)!)]; + const layouts = optimised.logs.length === 0 && !allScripts.some(hasAmbiguousInvoke); + const debug = process.env.CASHC_DEBUG_RESCHEDULE !== undefined; + try { + choices = rescheduleBodies(d, loggableArities, objective, layouts); + if (debug && layouts) { + // eslint-disable-next-line no-console + console.error(`[reschedule] layouts: ${choices.perms.size} permuted of ${d.order.length} bodies (${[...choices.perms.keys()].join(',')})`); + } + } catch (e) { + if (debug) console.error(`[reschedule] layout experiment fell back to identity: ${(e as Error).message}`); // eslint-disable-line no-console + // the layout experiment failed validation somewhere — identity layouts wholesale + choices = rescheduleBodies(d, loggableArities, objective, false); + } + let { overrides } = choices; + let { perms } = choices; + + // 2. main routine (kept as-is when the contract logs to console). When any callee's + // entry layout changed, main MUST be re-emitted (its raw call sites stage the old + // order); if that fails, redo everything with identity layouts. + let main = d.main; + let mainMapping: ItemMapping[] | undefined; + const rescheduleMain = (): boolean => { + // main MUST be re-emitted only when it itself stages arguments for a permuted callee; + // permuted inner helpers (reached through other bodies) don't affect its call sites + const needsReemit = perms.size > 0 && bodyInvokes(d.main).some((id) => perms.has(id)); + let best: RecompiledScript | undefined; + let bestCost = needsReemit ? Infinity : scriptCost(d.main, objective); + MAIN_STRATEGIES.forEach((strategy) => { + let candidate: RecompiledScript; + try { + candidate = recompileScript(d.main, arities, options.mainInArity, strategy, objective, { calleePerms: perms }); + } catch (e) { + if (debug) console.error(`[reschedule] main (${strategy}) failed: ${(e as Error).message}`); // eslint-disable-line no-console + return; + } + const cost = scriptCost(candidate.script, objective); + if (cost < bestCost && candidate.changed) { best = candidate; bestCost = cost; } + }); + if (best !== undefined) { main = best.script; mainMapping = best.mapping; } + return best !== undefined || !needsReemit; + }; + if (optimised.logs.length === 0) { + if (!rescheduleMain() && perms.size > 0) { + ({ overrides, perms } = rescheduleBodies(d, loggableArities, objective, false)); + main = d.main; + mainMapping = undefined; + rescheduleMain(); + } + } else if (perms.size > 0) { + // main cannot be re-emitted (logs) so callee conventions must stay standard + ({ overrides, perms } = rescheduleBodies(d, loggableArities, objective, false)); + } + + if (debug) { + // eslint-disable-next-line no-console + console.error(`[reschedule] final: overrides=${overrides.size} perms=${perms.size} mainRewritten=${mainMapping !== undefined}`); + } + if (overrides.size === 0 && mainMapping === undefined) return { result: optimised, frames }; + + // 3. rebuild the script with the rescheduled bodies + main + const script: Script = []; + d.order.forEach((id) => { + script.push(scriptToBytecode(overrides.get(id) ?? d.bodies.get(id)!), encodeInt(BigInt(id)), Op.OP_DEFINE); + }); + main.forEach((el) => script.push(el)); + + // 4. remap top-level debug structures across the main rewrite (the define-table prefix + // is index-stable: body pushes change bytes, not element positions) + let { locationData, requires, sourceTags } = optimised; + if (mainMapping !== undefined) { + const remap = indexRemapper(mainMapping, d.tableLength); + locationData = remapLocationData(locationData, mainMapping, d.tableLength); + requires = requires.map((req: RequireStatement) => ({ + ...req, + ip: remap(req.ip - constructorParamLength) + constructorParamLength, + })); + sourceTags = sourceTags.map((tag: SourceTagEntry) => ({ + ...tag, + startIndex: remap(tag.startIndex), + endIndex: remap(tag.endIndex), + })); + } + + // 5. refresh the debug frames of rescheduled bodies: coarse (whole-function) source + // map, requires re-anchored to their preserved boundaries, tags dropped + const newFrames = frames.map((frame) => { + const id = d.order.find((candidate) => binToHex(scriptToBytecode(d.bodies.get(candidate)!)) === frame.bytecode); + if (id === undefined || !overrides.has(id)) return frame; + const body = overrides.get(id)!; + // The frame carries no whole-definition location, so span its own source map instead + // (first entry's start to last entry's end). + const frameLocations = sourceMapToLocationData(frame.sourceMap); + const wholeLocation: SingleLocationData = { + location: { + start: frameLocations[0].location.start, + end: frameLocations[frameLocations.length - 1].location.end, + }, + positionHint: PositionHint.START, + }; + const bodyLocationData: FullLocationData = new Array(body.length).fill(wholeLocation); + // block-accurate require remapping is not tracked per body (candidates are selected + // per strategy); clamp every ip into the new body's range instead + const maxIp = Math.max(0, body.length - 1); + return { + ...frame, + bytecode: binToHex(scriptToBytecode(body)), + sourceMap: generateSourceMap(bodyLocationData), + requires: frame.requires.map((req) => ({ ...req, ip: Math.min(req.ip, maxIp) })), + ...(frame.sourceTags !== undefined ? { sourceTags: undefined } : {}), + }; + }); + + // Inline ranges are not remapped across a main rewrite (TODO: remap them alongside requires); + // dropping them degrades inlined-callable attribution gracefully instead of pointing debuggers + // at the wrong instructions. + const inlineRanges = mainMapping === undefined ? optimised.inlineRanges : []; + + return { + result: { + ...optimised, script, locationData, requires, sourceTags, inlineRanges, + }, + frames: newFrames, + }; +} diff --git a/packages/cashc/test/stack-rescheduling.test.ts b/packages/cashc/test/stack-rescheduling.test.ts new file mode 100644 index 00000000..7deff170 --- /dev/null +++ b/packages/cashc/test/stack-rescheduling.test.ts @@ -0,0 +1,166 @@ +import { + createTestAuthenticationProgramBch, + createVirtualMachineBch2026, + hexToBin, +} from '@bitauth/libauth'; +import { asmToBytecode, bytecodeToScript, encodeInt, scriptToBytecode } from '@cashscript/utils'; +import { compileString } from '../src/index.js'; + +const vm = createVirtualMachineBch2026(false); + +// evaluate a compiled contract (no constructor args) directly against pushed spend args +function evaluate(bytecodeAsm: string, args: bigint[]): boolean { + // spend args are pushed in reverse declaration order (first parameter on top) + const unlocking = scriptToBytecode([...args].reverse().map((arg) => encodeInt(arg))); + const state = vm.evaluate(createTestAuthenticationProgramBch({ + lockingBytecode: asmToBytecode(bytecodeAsm), + unlockingBytecode: unlocking, + valueSatoshis: 1000n, + })); + const top = state.stack[state.stack.length - 1]; + return state.error === undefined && state.stack.length === 1 && top !== undefined && top.length === 1 && top[0] === 1; +} + +// slot-heavy single-function contract: many locals with interleaved, repeated reads +// (the access pattern the rescheduler exists to improve), plus a user function that +// stays OP_DEFINE'd, a loop, and a branch +const CONTRACT = ` + function mulmod(int a, int b, int m) returns (int) { + int p = (a * b) % m; + return p; + } + contract Sched() { + function spend(int x, int y, int z, int w) { + int a = x + y; + int b = y + z; + int c = z + w; + int d = a * b + b * c + c * a; + int e = mulmod(a, b, 1000000007) + mulmod(b, c, 1000000007); + int acc = 0; + for (int i = 0; i < 3; i = i + 1) { + acc = acc + d + e; + } + if (acc > 0) { + require(acc >= d); + } + require(a + b + c + d + e + acc > 0); + } + }`; + +describe('stack rescheduling (rescheduleStacks)', () => { + it('is off by default and leaves the bytecode unchanged', () => { + expect(compileString(CONTRACT).bytecode).toEqual(compileString(CONTRACT, {}).bytecode); + }); + + it.each([['opcost'], ['size']] as const)( + 'preserves accept/reject behaviour under the %s objective', + (optimizeFor) => { + const plain = compileString(CONTRACT, { optimizeFor }); + const rescheduled = compileString(CONTRACT, { optimizeFor, rescheduleStacks: true }); + + const accepts: bigint[][] = [ + [3n, 5n, 7n, 11n], + [1000n, 2000n, 3000n, 4000n], + [123456789n, 987654321n, 555555n, 42n], + ]; + accepts.forEach((args) => { + expect(evaluate(plain.bytecode, args)).toBe(true); + expect(evaluate(rescheduled.bytecode, args)).toBe(true); + }); + + // all-zero inputs fail the final require in both compiles + expect(evaluate(plain.bytecode, [0n, 0n, 0n, 0n])).toBe(false); + expect(evaluate(rescheduled.bytecode, [0n, 0n, 0n, 0n])).toBe(false); + }, + ); + + it('keeps the debug source map aligned with the script', () => { + const artifact = compileString(CONTRACT, { rescheduleStacks: true }); + const scriptLength = hexToBin(artifact.debug!.bytecode).length; + expect(scriptLength).toBeGreaterThan(0); + // one source-map entry per script element: entries are separated by ';' + const elementCount = artifact.debug!.sourceMap.split(';').length; + expect(elementCount).toEqual(bytecodeToScript(hexToBin(artifact.debug!.bytecode)).length); + }); + + it('skips multi-function contracts', () => { + const multi = ` + contract Multi() { + function a(int x) { require(x > 0); } + function b(int y) { require(y > 1); } + }`; + expect(compileString(multi, { rescheduleStacks: true }).bytecode) + .toEqual(compileString(multi).bytecode); + }); +}); + +// Dead computation: a value that never reaches its block's exit still executes for its +// failure behaviour — rejecting the spend is its only observable effect, so eliminating +// it would ACCEPT witnesses the plain compile rejects (see hasDeadComputation). +describe('dead computation is never eliminated', () => { + // a void guard function is a zero-output invoke node at the call site — dead by + // construction; disableInlining pins the OP_DEFINE/OP_INVOKE shape that exercises it + const VOID_GUARD = ` + function check(int x) { require(x > 500); } + contract Guard() { + function spend(int a, int b) { + check(a); + check(b); + require(a + b > 0); + } + }`; + + it.each([['opcost'], ['size']] as const)( + 'keeps void guard calls under the %s objective', + (optimizeFor) => { + const plain = compileString(VOID_GUARD, { optimizeFor, disableInlining: true }); + const rescheduled = compileString(VOID_GUARD, { optimizeFor, disableInlining: true, rescheduleStacks: true }); + + // both call sites survive rescheduling + const invokeCount = (asm: string): number => [...asm.matchAll(/OP_INVOKE/g)].length; + expect(invokeCount(rescheduled.bytecode)).toEqual(invokeCount(plain.bytecode)); + + expect(evaluate(plain.bytecode, [501n, 1000n])).toBe(true); + expect(evaluate(rescheduled.bytecode, [501n, 1000n])).toBe(true); + + // each guard must still reject independently + expect(evaluate(plain.bytecode, [1n, 1000n])).toBe(false); + expect(evaluate(rescheduled.bytecode, [1n, 1000n])).toBe(false); + expect(evaluate(plain.bytecode, [1000n, 1n])).toBe(false); + expect(evaluate(rescheduled.bytecode, [1000n, 1n])).toBe(false); + }, + ); + + it('keeps void guard calls with inlining enabled (default)', () => { + const plain = compileString(VOID_GUARD); + const rescheduled = compileString(VOID_GUARD, { rescheduleStacks: true }); + expect(evaluate(plain.bytecode, [501n, 1000n])).toBe(true); + expect(evaluate(rescheduled.bytecode, [501n, 1000n])).toBe(true); + expect(evaluate(rescheduled.bytecode, [1n, 1000n])).toBe(false); + expect(evaluate(rescheduled.bytecode, [1000n, 1n])).toBe(false); + }); + + it.each([['opcost'], ['size']] as const)( + "keeps an 'unused' variable's failure-capable initializer under the %s objective", + (optimizeFor) => { + const UNUSED_DIV = ` + contract DivGuard() { + function spend(int a) { + int unused x = 500 / a; + require(a < 100); + } + }`; + const plain = compileString(UNUSED_DIV, { optimizeFor }); + const rescheduled = compileString(UNUSED_DIV, { optimizeFor, rescheduleStacks: true }); + + expect(rescheduled.bytecode).toContain('OP_DIV'); + + expect(evaluate(plain.bytecode, [5n])).toBe(true); + expect(evaluate(rescheduled.bytecode, [5n])).toBe(true); + + // division by zero aborts the script in both compiles + expect(evaluate(plain.bytecode, [0n])).toBe(false); + expect(evaluate(rescheduled.bytecode, [0n])).toBe(false); + }, + ); +}); diff --git a/packages/utils/src/artifact.ts b/packages/utils/src/artifact.ts index c2a4709f..c6acb4b8 100644 --- a/packages/utils/src/artifact.ts +++ b/packages/utils/src/artifact.ts @@ -1,6 +1,15 @@ export interface CompilerOptions { enforceFunctionParameterTypes?: boolean; enforceLocktimeGuard?: boolean; + // Reschedule straight-line stack code from its dataflow DAG after bytecode optimisation, + // so operands are computed onto the top of the stack instead of fetched from variable + // slots with ` OP_PICK/OP_ROLL`, and choose each user function's argument-arrival + // order jointly with its schedule (see stack-rescheduling.ts). Candidates are ranked by + // the `optimizeFor` objective; per block the compiler keeps min(original, rescheduled), + // function bodies are differentially tested on a VM against the plain compile. Off by + // default: rescheduled regions keep only statement-level debug info (each emitted + // opcode maps to its block's merged source span). Single-function contracts only. + rescheduleStacks?: boolean; // The optimisation objective for decisions that trade bytecode size against op-cost. // 'size' minimises bytecode bytes (e.g. binds a literal repeated within one function body to a // local, so later uses are ~2-byte stack picks instead of repeated pushes: ~-30 bytes per From 9fe0dc955af5724112a3b2880286995dcc3f9bc8 Mon Sep 17 00:00:00 2001 From: Mathieu Geukens Date: Tue, 28 Jul 2026 09:30:30 +0200 Subject: [PATCH 11/12] test(utils): land a differential fuzz suite for the peephole optimiser MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The peephole rewrite's guarantee is that swapping string matching for opcode matching changed nothing about the output. This suite enforces that guarantee systematically: 2,000 seeded random scripts (plus directed edge cases and metadata goldens) are optimised by both the new engine and a string-based reference with the same rule table, and every byte must agree. The fuzz earned its keep before landing. It caught a real pass-semantics divergence in the rewrite, now fixed in that commit: the splice engine let a replacement cascade into later matches within the same pass, where regex /g computes matches against the sweep-start string and a removal leaves an unmatchable double space until the pass-end cleanup — both now emulated exactly. It also surfaced a latent corruption in the OTHER string engine still in the tree: the cashproof cross-check optimiser (optimiseBytecodeOld) builds unanchored regexes, so a rule can match a token PREFIX (after OP_NOT OP_IF -> OP_NOTIF, its rule `OP_GREATERTHAN OP_NOT` matches inside `OP_GREATERTHAN OP_NOTIF`, yielding the invalid token OP_LESSTHANOREQUALIF). The replaced production engine already anchored pattern ends with (\s|$) ("no partial matches"), so production was never affected; the reference here mirrors that guard with \b anchors, and element-wise matching is immune by construction. Note the in-compiler cross-check compares against optimiseBytecodeOld, whose cashproof-derived table composes rules in a different order on adversarial inputs (and lacks the anchor above); the two optimisers are only expected to agree on compiler-shaped output, which the cross-check verifies per compile. Co-Authored-By: Claude Fable 5 --- .../utils/test/optimiser-differential.test.ts | 208 ++++++++++++++++++ packages/utils/test/script.test.ts | 4 +- 2 files changed, 210 insertions(+), 2 deletions(-) create mode 100644 packages/utils/test/optimiser-differential.test.ts diff --git a/packages/utils/test/optimiser-differential.test.ts b/packages/utils/test/optimiser-differential.test.ts new file mode 100644 index 00000000..0c68d1de --- /dev/null +++ b/packages/utils/test/optimiser-differential.test.ts @@ -0,0 +1,208 @@ +import { + asmToScript, + FullLocationData, + Op, + optimiseBytecode, + PositionHint, + Script, + scriptToAsm, +} from '../src/index.js'; +import { optimisationReplacements } from '../src/optimisations.js'; + +// Differential oracle for the opcode-matching peephole optimiser: on any input, its bytecode must +// byte-for-byte match the string-based engine it replaced, running the SAME optimisation table. +// (The in-compiler cross-check against optimiseBytecodeOld is a different comparison: that +// optimiser applies the cashproof-derived table, whose rule order composes differently on +// adversarial inputs, so the two are only expected to agree on compiler-shaped output.) +// +// The reference below reproduces the replaced engine's string semantics: regex /g computes +// matches against the sweep-start string (a replacement never cascades within its own rule's +// sweep), and an empty replacement leaves a double space that no single-space pattern can match +// across until the pass-end whitespace cleanup. Patterns are anchored with \b, mirroring the +// replaced engine's `${pattern}(\s|$)` end anchor ("no partial matches") — equivalent for +// space-separated ASM — and the opcode matcher is immune to partial-token matches by +// construction. (The cashproof cross-check optimiser, optimiseBytecodeOld, has NO such anchor +// and genuinely can corrupt adversarial scripts: after `OP_NOT OP_IF` -> `OP_NOTIF`, its +// unanchored rule `OP_GREATERTHAN OP_NOT` matches inside `OP_GREATERTHAN OP_NOTIF`, yielding +// the invalid token `OP_LESSTHANOREQUALIF`. That, plus its differently-ordered rule table, is +// why this suite does not use it as the oracle.) +const referenceOptimise = (script: Script, runs: number = 1000): Script => { + for (let i = 0; i < runs; i += 1) { + const oldScript = script; + let asm = scriptToAsm(script); + optimisationReplacements.forEach(([pattern, replacement]) => { + asm = asm.replace(new RegExp(`\\b${pattern}\\b`, 'g'), replacement); + }); + asm = asm.replace(/\s+/g, ' ').trim(); + script = asmToScript(asm); // eslint-disable-line no-param-reassign + if (scriptToAsm(oldScript) === scriptToAsm(script)) break; + } + return script; +}; + +// Deterministic PRNG (mulberry32) so any failure is reproducible from the reported script index. +const mulberry32 = (initialSeed: number): (() => number) => { + let seed = initialSeed; + return (): number => { + seed = (seed + 0x6d2b79f5) | 0; + let t = Math.imul(seed ^ (seed >>> 15), 1 | seed); + t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t; + return ((t ^ (t >>> 14)) >>> 0) / 4294967296; + }; +}; + +const OPCODE_POOL: Op[] = [ + Op.OP_0, Op.OP_1, Op.OP_2, Op.OP_3, Op.OP_16, Op.OP_1NEGATE, + Op.OP_DUP, Op.OP_2DUP, Op.OP_3DUP, Op.OP_DROP, Op.OP_2DROP, Op.OP_NIP, Op.OP_TUCK, + Op.OP_SWAP, Op.OP_2SWAP, Op.OP_ROT, Op.OP_2ROT, Op.OP_OVER, Op.OP_2OVER, + Op.OP_PICK, Op.OP_ROLL, Op.OP_TOALTSTACK, Op.OP_FROMALTSTACK, Op.OP_DEPTH, Op.OP_SIZE, + Op.OP_NOT, Op.OP_0NOTEQUAL, Op.OP_ADD, Op.OP_SUB, Op.OP_1ADD, Op.OP_1SUB, Op.OP_NEGATE, Op.OP_ABS, + Op.OP_MIN, Op.OP_MAX, Op.OP_WITHIN, Op.OP_BOOLAND, Op.OP_BOOLOR, + Op.OP_NUMEQUAL, Op.OP_NUMEQUALVERIFY, Op.OP_NUMNOTEQUAL, Op.OP_EQUAL, Op.OP_EQUALVERIFY, + Op.OP_LESSTHAN, Op.OP_GREATERTHAN, Op.OP_LESSTHANOREQUAL, Op.OP_GREATERTHANOREQUAL, + Op.OP_VERIFY, Op.OP_IF, Op.OP_ELSE, Op.OP_ENDIF, + Op.OP_CAT, Op.OP_SPLIT, Op.OP_REVERSEBYTES, Op.OP_BIN2NUM, Op.OP_NUM2BIN, + Op.OP_SHA256, Op.OP_HASH160, Op.OP_HASH256, Op.OP_RIPEMD160, Op.OP_SHA1, + Op.OP_CHECKSIG, Op.OP_CHECKSIGVERIFY, Op.OP_CHECKDATASIG, Op.OP_CHECKDATASIGVERIFY, +]; + +// Pushes chosen to stress the disassembly-exact matching of small-integer representations: +// empty push (renders OP_0), non-minimal single bytes (render OP_1..OP_16 / OP_1NEGATE), and +// plain multi-byte data. +const PUSH_POOL: Uint8Array[] = [ + new Uint8Array([]), + new Uint8Array([0x00]), + new Uint8Array([0x01]), + new Uint8Array([0x07]), + new Uint8Array([0x10]), + new Uint8Array([0x81]), + new Uint8Array([0x11]), + new Uint8Array([0xff]), + new Uint8Array([0x01, 0x02]), + new Uint8Array([0xde, 0xad, 0xbe, 0xef]), + new Uint8Array(20).fill(0xab), + new Uint8Array(32).fill(0xcd), +]; + +// Injected multi-element fragments that overlap known rewrite rules, so matches (including +// cascading ones) stay dense enough to exercise the splice/fixed-point machinery. +const FRAGMENT_POOL: Script[] = [ + [Op.OP_SWAP, Op.OP_SWAP], + [Op.OP_DUP, Op.OP_DROP], + [Op.OP_0, Op.OP_ROLL], + [Op.OP_1, Op.OP_ROLL], + [Op.OP_1, Op.OP_PICK], + [Op.OP_TOALTSTACK, Op.OP_FROMALTSTACK], + [Op.OP_OVER, Op.OP_OVER], + [Op.OP_3, Op.OP_PICK, Op.OP_3, Op.OP_PICK], + [Op.OP_3, Op.OP_ROLL, Op.OP_3, Op.OP_ROLL], + [Op.OP_5, Op.OP_ROLL, Op.OP_5, Op.OP_ROLL], + [Op.OP_EQUAL, Op.OP_VERIFY], + [Op.OP_NUMEQUAL, Op.OP_VERIFY], + [Op.OP_CHECKSIG, Op.OP_VERIFY], + [Op.OP_SWAP, Op.OP_ADD], + [Op.OP_SWAP, Op.OP_MUL], + [Op.OP_DUP, Op.OP_SWAP], + [Op.OP_NOT, Op.OP_IF], +]; + +const randomScript = (rand: () => number, length: number): Script => { + const script: Script = []; + while (script.length < length) { + const roll = rand(); + if (roll < 0.5) { + script.push(OPCODE_POOL[Math.floor(rand() * OPCODE_POOL.length)]); + } else if (roll < 0.7) { + script.push(PUSH_POOL[Math.floor(rand() * PUSH_POOL.length)]); + } else { + script.push(...FRAGMENT_POOL[Math.floor(rand() * FRAGMENT_POOL.length)]); + } + } + return script; +}; + +const dummyLocationData = (length: number): FullLocationData => Array.from({ length }, () => ({ + location: { start: { line: 1, column: 0 }, end: { line: 1, column: 1 } }, + positionHint: PositionHint.START, +})); + +const optimiseNew = (script: Script, requires = [], logs = []): ReturnType => ( + optimiseBytecode(script, dummyLocationData(script.length), logs, requires, [], [], 0) +); + +describe('optimiser differential (opcode matcher vs same-table string reference)', () => { + // ~2s uninstrumented, but coverage instrumentation pushes it past vitest's 5s default timeout + it('produces byte-for-byte identical output on seeded random scripts', { timeout: 60_000 }, () => { + const rand = mulberry32(0xca5c); + for (let i = 0; i < 2000; i += 1) { + const length = 20 + Math.floor(rand() * 130); + const script = randomScript(rand, length); + + const expected = scriptToAsm(referenceOptimise(script)); + const result = optimiseNew(script); + const actual = scriptToAsm(result.script); + + if (actual !== expected) { + throw new Error([ + `optimiser divergence at seeded script #${i}`, + `input: ${scriptToAsm(script)}`, + `reference: ${expected}`, + `new: ${actual}`, + ].join('\n')); + } + // metadata must track the script 1:1 through every splice + expect(result.locationData.length).toBe(result.script.length); + } + }); + + const directedCases: Array<[string, Script]> = [ + ['pattern at the very start', [Op.OP_SWAP, Op.OP_SWAP, Op.OP_ADD]], + ['pattern at the very end', [Op.OP_ADD, Op.OP_SWAP, Op.OP_SWAP]], + ['entire script optimises away', [Op.OP_SWAP, Op.OP_SWAP]], + ['empty push renders as OP_0', [new Uint8Array([]), Op.OP_ROLL]], + ['non-minimal single-byte push renders as OP_1', [new Uint8Array([0x01]), Op.OP_ROLL]], + ['non-minimal single-byte push renders as OP_1NEGATE', [new Uint8Array([0x81]), Op.OP_DROP]], + ['OP_1NEGATE opcode form', [Op.OP_1NEGATE, Op.OP_SWAP, Op.OP_SWAP, Op.OP_ADD]], + ['cascading matches across a splice', [Op.OP_DUP, Op.OP_SWAP, Op.OP_SWAP, Op.OP_DROP, Op.OP_1]], + ['overlapping candidates', [Op.OP_SWAP, Op.OP_SWAP, Op.OP_SWAP, Op.OP_ADD]], + ['push data is opaque to patterns', [new Uint8Array([0xde, 0xad]), Op.OP_SWAP, Op.OP_SWAP]], + ]; + + it.each(directedCases)('matches the string reference on edge case: %s', (_, script) => { + const expected = scriptToAsm(referenceOptimise(script)); + expect(scriptToAsm(optimiseNew(script).script)).toBe(expected); + }); +}); + +describe('optimiser metadata adjustment goldens', () => { + it('shifts require ips and location data across a removed pair', () => { + const script = [Op.OP_2, Op.OP_SWAP, Op.OP_SWAP, Op.OP_3, Op.OP_ADD]; + const requires = [{ ip: 4, line: 1 }]; + + const result = optimiseBytecode(script, dummyLocationData(script.length), [], requires, [], [], 0); + + expect(scriptToAsm(result.script)).toBe('OP_2 OP_3 OP_ADD'); + expect(result.requires).toEqual([{ ip: 2, line: 1 }]); + expect(result.locationData.length).toBe(3); + }); + + it('keeps require ips before a removed pair untouched', () => { + const script = [Op.OP_2, Op.OP_3, Op.OP_ADD, Op.OP_SWAP, Op.OP_SWAP]; + const requires = [{ ip: 2, line: 1 }]; + + const result = optimiseBytecode(script, dummyLocationData(script.length), [], requires, [], [], 0); + + expect(scriptToAsm(result.script)).toBe('OP_2 OP_3 OP_ADD'); + expect(result.requires).toEqual([{ ip: 2, line: 1 }]); + }); + + it('shifts log ips across a removed pair', () => { + const script = [Op.OP_DUP, Op.OP_DROP, Op.OP_2, Op.OP_3, Op.OP_ADD]; + const logs = [{ ip: 4, line: 1, data: [] }]; + + const result = optimiseBytecode(script, dummyLocationData(script.length), logs, [], [], [], 0); + + expect(scriptToAsm(result.script)).toBe('OP_2 OP_3 OP_ADD'); + expect(result.logs).toEqual([{ ip: 2, line: 1, data: [] }]); + }); +}); diff --git a/packages/utils/test/script.test.ts b/packages/utils/test/script.test.ts index fa7ae8f4..f7989ce3 100644 --- a/packages/utils/test/script.test.ts +++ b/packages/utils/test/script.test.ts @@ -101,6 +101,6 @@ describe('script utils', () => { describe.skip('TODO: generateContractBytecodeScript()', () => { }); - describe.skip('TODO: optimiseBytecode()', () => { - }); + // optimiseBytecode() is covered by optimiser-differential.test.ts (seeded fuzz vs the legacy + // optimiser, directed edge cases, and metadata adjustment goldens). }); From ba4e309a150edf3e79d7984e35b3351382fde6d2 Mon Sep 17 00:00:00 2001 From: Mathieu Geukens Date: Tue, 28 Jul 2026 10:33:23 +0200 Subject: [PATCH 12/12] perf(cashc): make tiny-body inlining placement-aware, and the byte model exact MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A contract with several functions compiles into one script with a branch per function, and the VM charges 100 op-cost for every opcode it steps over in the branches a spend does NOT take. Inlining a small helper that is called once in each contract function therefore plants copies that every spend pays to walk over — measured ~686 op-cost AND +8 bytes worse than sharing on a 4-function contract. Two changes: - Density guard: a tiny body is only force-inlined under 'opcost' when no spend path can lose — for every entry function, the extra stepping of the other entries' inlined copies (100 x (elements - 2) each vs their 2-op invoke sites) must stay within what inlining saves (the one-time 301 + 2B define plus 201 per own call site). Single-function contracts pass trivially; bodies of <= 2 elements pass at any spread. Call sites inside still-defined helpers are attributed to every entry that reaches them — conservative in the safe direction (keeps OP_DEFINE, forgoing at most the 201/call invoke saving). - Exact byte model: the define site pushes the body as data, which carries a push-length prefix the model previously omitted. With the prefix counted, a 7-byte body used twice is recognised as a byte TIE (14 = 14) and inlines, saving ~700 op-cost for zero bytes; previously it stayed defined. The 6-byte force-inline cap is unchanged: it bounds collateral bytes at ~4 per extra call site (~50 op-cost per byte). Co-Authored-By: Claude Fable 5 --- .../src/generation/GenerateTargetTraversal.ts | 6 +- packages/cashc/src/generation/inlining.ts | 83 +++++++++++++++---- .../cashc/test/global-definitions.test.ts | 45 ++++++++++ 3 files changed, 116 insertions(+), 18 deletions(-) diff --git a/packages/cashc/src/generation/GenerateTargetTraversal.ts b/packages/cashc/src/generation/GenerateTargetTraversal.ts index 464f17a1..d18ae0f9 100644 --- a/packages/cashc/src/generation/GenerateTargetTraversal.ts +++ b/packages/cashc/src/generation/GenerateTargetTraversal.ts @@ -74,7 +74,7 @@ import { } from './utils.js'; import { isNumericType } from '../utils.js'; import { - collectFunctionCalls, collectLoopResidentFunctions, isRecursive, shouldInline, + collectEntryReachableCalls, collectFunctionCalls, collectLoopResidentFunctions, isRecursive, shouldInline, } from './inlining.js'; import type { InternalCompilerOptions } from '../compiler.js'; @@ -218,6 +218,7 @@ export default class GenerateTargetTraversal extends AstTraversal { }); const reachableCalls = [node.contract!, ...node.functions].flatMap((n) => collectFunctionCalls(n)); + const entryReachableCalls = collectEntryReachableCalls(node); const loopResidentFunctions = collectLoopResidentFunctions(node); const definedFunctions: Array<{ func: FunctionDefinitionNode, compiledResult: OptimiseBytecodeResult }> = []; let nextFunctionId = recursiveFunctions.length; @@ -228,7 +229,8 @@ export default class GenerateTargetTraversal extends AstTraversal { // If the function should be inlined, we ONLY update the symbol const inline = shouldInline( - symbol, compiledResult, reachableCalls, loopResidentFunctions, nextFunctionId, this.compilerOptions, + symbol, compiledResult, reachableCalls, entryReachableCalls, loopResidentFunctions, nextFunctionId, + this.compilerOptions, ); if (inline) { symbol.setInlinedBytecode(compiledResult.script, this.buildDebugFrame(func, compiledResult)); diff --git a/packages/cashc/src/generation/inlining.ts b/packages/cashc/src/generation/inlining.ts index 3c7a1d35..f90d79c8 100644 --- a/packages/cashc/src/generation/inlining.ts +++ b/packages/cashc/src/generation/inlining.ts @@ -25,6 +25,7 @@ export const shouldInline = ( symbol: Symbol, optimisedResult: OptimiseBytecodeResult, reachableCalls: FunctionCallNode[], + entryReachableCalls: FunctionCallNode[][], loopResidentFunctions: Set, nextFunctionId: number, compilerOptions: InternalCompilerOptions, @@ -47,45 +48,71 @@ export const shouldInline = ( } const callCount = reachableCalls.filter((call) => call.identifier.symbol === symbol).length; - return isWorthInlining(nextFunctionId, optimisedResult.script, callCount, compilerOptions.optimizeFor); + const entryCallCounts = entryReachableCalls + .map((calls) => calls.filter((call) => call.identifier.symbol === symbol).length); + return isWorthInlining(nextFunctionId, optimisedResult.script, callCount, entryCallCounts, compilerOptions.optimizeFor); }; // Op-cost accounting (CHIP-2021-05 VM limits): every evaluated instruction costs a base 100 and // stack pushes add 1 per pushed byte, so sharing a body of B bytes (1-byte funcid) pays // OP_DEFINE = 301 + 2B once per spend (OP_DEFINE re-prices the body's // stack-pushed bytes) plus OP_INVOKE = 201 per call, while an inlined body executes at -// identical cost to an invoked one. For EXECUTED call sites inlining therefore always wins op-cost. -// That is not a universal win: a SKIPPED call site (untaken branch — e.g. a helper called once per -// entry function of a multi-function contract) steps the whole inlined body at 100/opcode where an -// invoke site steps 2 ops (a 6-element body: 600 vs 200; a helper shared across 4 entry functions -// measured ~686 op-cost worse AND +8 bytes when force-inlined). Forcing tiny bodies inline is thus -// a bet on execution density — that call sites usually execute — with the downside bounded small: -// each skipped site risks ~100 x (elements - 2) op-cost, while each executed site saves the -// 201/call invoke overhead plus the one-time 301 + 2B define. On bytes: the model below omits the -// body push's length prefix, so the true two-site break-even is 7 bytes, not 6 — the cap -// deliberately stays at 6 so any body forced inline here is one the byte model would also inline -// at two uses, capping the byte regression at ~4 bytes per extra call site. Loop-resident bodies -// are still excluded above: stepping a skipped inlined body costs 100/opcode per ITERATION, which -// quickly dwarfs the 201/call invoke saving. +// identical cost to an invoked one. For EXECUTED call sites inlining therefore always wins +// op-cost, so under the 'opcost' objective tiny bodies inline regardless of use count. The cap +// bounds the collateral bytes: each inlined call site costs B bytes instead of the ~2-byte invoke +// site, so 6 tolerates ~4 extra bytes per additional call site (~50 op-cost bought per byte). +// Loop-resident bodies are excluded before this rule (stepping a skipped inlined body costs +// 100/opcode per ITERATION), and the density guard below excludes bodies whose call sites are +// spread across contract entry functions. const OPCOST_INLINE_MAX_BODY_BYTES = 6; function isWorthInlining( candidateFunctionId: number, bodyScript: Script, callCount: number, + entryCallCounts: number[], optimizeFor?: OptimizationTarget, ): boolean { const bodyBytes = scriptToBytecode(bodyScript).length; - if (optimizeFor !== 'size' && bodyBytes <= OPCOST_INLINE_MAX_BODY_BYTES) return true; + if ( + optimizeFor !== 'size' + && bodyBytes <= OPCOST_INLINE_MAX_BODY_BYTES + && passesDensityGuard(entryCallCounts, bodyScript.length, bodyBytes) + ) { + return true; + } const idBytes = scriptToBytecode([encodeInt(BigInt(candidateFunctionId))]).length; - const bytesWhenDefined = bodyBytes + idBytes + 1 + callCount * (idBytes + 1); + // The define site pushes the body as data, so it carries a push-length prefix; serializing the + // wrapped body computes prefix + body exactly at any size. + const bodyPushBytes = scriptToBytecode([scriptToBytecode(bodyScript)]).length; + const bytesWhenDefined = bodyPushBytes + idBytes + 1 + callCount * (idBytes + 1); const bytesWhenInlined = callCount * bodyBytes; return bytesWhenInlined <= bytesWhenDefined; } +// A multi-function contract compiles into one script with a selector branch per entry function, +// and the VM steps (and charges 100/opcode for) the branches a spend does NOT take. An inlined +// copy in an untaken branch therefore costs 100 x elements per spend where an invoke site costs +// 200 — so a tiny body is only forced inline when no spend path can lose op-cost: for every entry +// function, the extra stepping of the OTHER entries' copies must not exceed what inlining saves +// (the one-time define and the entry's own invoke overhead). Single-entry contracts pass +// trivially (no other branches); bodies of <= 2 elements pass at any spread (a copy steps no more +// than the invoke site it replaces). No spend-frequency assumptions: the bound must hold for +// every entry. Call sites inside still-defined helpers are attributed to every entry reaching the +// helper, an over-approximation that only makes the guard more conservative (keeps OP_DEFINE and +// forgoes at most the 201/call invoke saving — never a stepping regression). +function passesDensityGuard(entryCallCounts: number[], bodyElements: number, bodyBytes: number): boolean { + if (bodyElements <= 2) return true; + const totalCalls = entryCallCounts.reduce((total, count) => total + count, 0); + const defineCost = 301 + 2 * bodyBytes; + return entryCallCounts.every((count) => ( + 100 * (bodyElements - 2) * (totalCalls - count) <= defineCost + 201 * count + )); +} + class FunctionCallCollector extends AstTraversal { functionCalls: FunctionCallNode[] = []; @@ -102,6 +129,30 @@ export function collectFunctionCalls(node: Node): FunctionCallNode[] { return collector.functionCalls; } +// Call sites reachable from each contract entry function: the entry's own body plus the bodies +// of every global function it (transitively) calls. Feeds the inlining density guard, which +// needs to know how a callee's call sites distribute over the selector branches. +export function collectEntryReachableCalls(node: SourceFileNode): FunctionCallNode[][] { + return (node.contract?.functions ?? []).map((entry) => { + const calls = [...collectFunctionCalls(entry)]; + const seen = new Set(); + const queue = callDefinitions(calls); + while (queue.length > 0) { + const definition = queue.shift()!; + if (seen.has(definition)) continue; + seen.add(definition); + const inner = collectFunctionCalls(definition.body); + calls.push(...inner); + queue.push(...callDefinitions(inner)); + } + return calls; + }); +} + +const callDefinitions = (calls: FunctionCallNode[]): FunctionDefinitionNode[] => calls + .map((call) => call.identifier.symbol?.definition) + .filter((definition): definition is FunctionDefinitionNode => definition instanceof FunctionDefinitionNode); + export function isRecursive(func: FunctionDefinitionNode): boolean { return transitiveCalledFunctions(func).includes(func); } diff --git a/packages/cashc/test/global-definitions.test.ts b/packages/cashc/test/global-definitions.test.ts index e654b59c..923ba193 100644 --- a/packages/cashc/test/global-definitions.test.ts +++ b/packages/cashc/test/global-definitions.test.ts @@ -232,6 +232,51 @@ describe('Inlining and shared definitions', () => { expect(bytecode).toContain('OP_INVOKE'); }); + it('keeps a tiny helper shared when its call sites are spread across contract functions', () => { + // 6-byte, 6-element body called once per entry: spending any entry steps the other two + // inlined copies at 100/opcode (2 x 400 extra vs their invoke sites), which exceeds the + // saved define (313) + own invoke (201) — so the density guard keeps OP_DEFINE. + const code = ` + function calc(int x) returns (int) { return x * 3 + 2 - 5; } + contract C() { + function a(int n) { require(calc(n) == 0); } + function b(int n) { require(calc(n) == 1); } + function c(int n) { require(calc(n) == 2); } + }`; + + const { bytecode } = compileString(code); + expect(bytecode).toContain('OP_DEFINE'); + expect(countOp(bytecode, 'OP_INVOKE')).toEqual(3); + }); + + it('still force-inlines a spread helper when its body is small enough that no spend path loses', () => { + // 4-byte, 4-element body, same spread: 2 x 200 extra stepping stays under the saved + // define (309) + invoke (201), so inlining cannot lose op-cost on any path. + const code = ` + function calc(int x) returns (int) { return x * 3 + 2; } + contract C() { + function a(int n) { require(calc(n) == 0); } + function b(int n) { require(calc(n) == 1); } + function c(int n) { require(calc(n) == 2); } + }`; + + const { bytecode } = compileString(code); + expect(bytecode).not.toContain('OP_DEFINE'); + expect(bytecode).not.toContain('OP_INVOKE'); + }); + + it('inlines a 7-byte body used twice (byte-exact tie: the define prelude carries a push prefix)', () => { + // inlined: 2 x 7 = 14 bytes; defined: (1 + 7) body push + 1 id + 1 OP_DEFINE + 2 x 2 call + // sites = 14 bytes — a tie in bytes, and inlining skips the define and invoke op-cost. + const code = ` + function calc(int x) returns (int) { return x * 17 + 2 - 5; } + contract C() { function spend(int n) { require(calc(n) + calc(n + 1) > 0); } }`; + + const { bytecode } = compileString(code); + expect(bytecode).not.toContain('OP_DEFINE'); + expect(bytecode).not.toContain('OP_INVOKE'); + }); + it('inlines a function whose only call site is a for-loop initializer (runs before OP_BEGIN)', () => { const code = ` function calc(int x) returns (int) { return (x * 7 + 3) * (x + 11) - 5; }