From 5943e7d4675f244eb3e4a89bb77f2515889b9164 Mon Sep 17 00:00:00 2001 From: Petr Makhnev <51853996+i582@users.noreply.github.com> Date: Tue, 21 Jan 2025 16:08:43 +0400 Subject: [PATCH] refactor: follow-up change long imports for AST to `* as A` imports (#1461) --- src/ast/compare.ts | 290 ++++++++++------------- src/ast/hash.ts | 130 +++++----- src/ast/rename.ts | 93 ++++---- src/ast/sort.ts | 22 +- src/ast/util.ts | 106 ++++----- src/generator/writers/writeExpression.ts | 71 +++--- src/generator/writers/writeFunction.ts | 41 ++-- src/grammar/prev/grammar.ts | 88 +++---- src/optimizer/interpreter.ts | 276 +++++++++------------ src/optimizer/test/partial-eval.spec.ts | 33 ++- src/types/resolveABITypeRef.ts | 81 +++---- src/types/resolveStatements.ts | 65 +++-- 12 files changed, 546 insertions(+), 750 deletions(-) diff --git a/src/ast/compare.ts b/src/ast/compare.ts index dded77751..475b998b0 100644 --- a/src/ast/compare.ts +++ b/src/ast/compare.ts @@ -1,60 +1,4 @@ -import { - AstConstantDef, - AstReceiverKind, - AstStructFieldInitializer, - AstFunctionAttribute, - AstOpBinary, - AstOpUnary, - AstFieldAccess, - AstConditional, - AstMethodCall, - AstStaticCall, - AstNumber, - AstBoolean, - AstString, - AstStructInstance, - AstInitOf, - AstConstantAttribute, - AstContractAttribute, - AstTypedParameter, - AstImport, - AstNativeFunctionDecl, - AstReceiver, - AstStatementRepeat, - AstStatementUntil, - AstStatementWhile, - AstStatementForEach, - AstStatementTry, - AstCondition, - AstStatementAugmentedAssign, - AstStatementAssign, - AstStatementExpression, - AstStatementReturn, - AstStatementLet, - AstFunctionDef, - AstContract, - AstTrait, - AstId, - AstModule, - AstStructDecl, - AstMessageDecl, - AstFunctionDecl, - AstConstantDecl, - AstContractInit, - AstPrimitiveTypeDecl, - AstTypeId, - AstMapType, - AstBouncedMessageType, - AstFieldDecl, - AstOptionalType, - AstNode, - AstFuncId, - AstAsmFunctionDef, - AstAsmInstruction, - AstDestructMapping, - AstStatementDestruct, - AstStatementBlock, -} from "./ast"; +import * as A from "./ast"; import { AstRenamer } from "./rename"; import { throwInternalCompilerError } from "../error/errors"; import JSONbig from "json-bigint"; @@ -82,7 +26,7 @@ export class AstComparator { return new AstComparator(sort, canonicalize); } - public compare(node1: AstNode, node2: AstNode): boolean { + public compare(node1: A.AstNode, node2: A.AstNode): boolean { if (node1.kind !== node2.kind) { return false; } @@ -91,11 +35,13 @@ export class AstComparator { case "module": { if (this.canonicalize) { const renamer = AstRenamer.make({ sort: this.sort }); - node1 = renamer.renameModule(node1 as AstModule); - node2 = renamer.renameModule(node2 as AstModule); + node1 = renamer.renameModule(node1 as A.AstModule); + node2 = renamer.renameModule(node2 as A.AstModule); } - const { imports: imports1, items: items1 } = node1 as AstModule; - const { imports: imports2, items: items2 } = node2 as AstModule; + const { imports: imports1, items: items1 } = + node1 as A.AstModule; + const { imports: imports2, items: items2 } = + node2 as A.AstModule; return ( this.compareArray(imports1, imports2) && this.compareArray(items1, items2) @@ -103,14 +49,14 @@ export class AstComparator { } case "import": { - const { path: path1 } = node1 as AstImport; - const { path: path2 } = node2 as AstImport; + const { path: path1 } = node1 as A.AstImport; + const { path: path2 } = node2 as A.AstImport; return this.compare(path1, path2); } case "primitive_type_decl": { - const { name: name1 } = node1 as AstPrimitiveTypeDecl; - const { name: name2 } = node2 as AstPrimitiveTypeDecl; + const { name: name1 } = node1 as A.AstPrimitiveTypeDecl; + const { name: name2 } = node2 as A.AstPrimitiveTypeDecl; return this.compare(name1, name2); } @@ -121,14 +67,14 @@ export class AstComparator { return: returnType1, params: params1, statements: statements1, - } = node1 as AstFunctionDef; + } = node1 as A.AstFunctionDef; const { attributes: attributes2, name: funcName2, return: returnType2, params: params2, statements: statements2, - } = node2 as AstFunctionDef; + } = node2 as A.AstFunctionDef; return ( this.compareAttributes(attributes1, attributes2) && this.compare(funcName1, funcName2) && @@ -146,7 +92,7 @@ export class AstComparator { return: returnType1, params: params1, instructions: instructions1, - } = node1 as AstAsmFunctionDef; + } = node1 as A.AstAsmFunctionDef; const { shuffle: shuffle2, attributes: attributes2, @@ -154,7 +100,7 @@ export class AstComparator { return: returnType2, params: params2, instructions: instructions2, - } = node2 as AstAsmFunctionDef; + } = node2 as A.AstAsmFunctionDef; return ( this.compareArray(shuffle1.args, shuffle2.args) && this.compareArray(shuffle1.ret, shuffle2.ret) && @@ -171,13 +117,13 @@ export class AstComparator { name: declName1, return: declReturnType1, params: declParams1, - } = node1 as AstFunctionDecl; + } = node1 as A.AstFunctionDecl; const { attributes: declAttributes2, name: declName2, return: declReturnType2, params: declParams2, - } = node2 as AstFunctionDecl; + } = node2 as A.AstFunctionDecl; return ( this.compareAttributes(declAttributes1, declAttributes2) && this.compare(declName1, declName2) && @@ -196,14 +142,14 @@ export class AstComparator { nativeName: nativeFuncName1, params: nativeParams1, return: returnTy1, - } = node1 as AstNativeFunctionDecl; + } = node1 as A.AstNativeFunctionDecl; const { attributes: nativeAttributes2, name: nativeName2, nativeName: nativeFuncName2, params: nativeParams2, return: returnTy2, - } = node2 as AstNativeFunctionDecl; + } = node2 as A.AstNativeFunctionDecl; return ( this.compareAttributes( nativeAttributes1, @@ -222,13 +168,13 @@ export class AstComparator { name: constName1, type: constType1, initializer: constInitializer1, - } = node1 as AstConstantDef; + } = node1 as A.AstConstantDef; const { attributes: constAttributes2, name: constName2, type: constType2, initializer: constInitializer2, - } = node2 as AstConstantDef; + } = node2 as A.AstConstantDef; return ( this.compareAttributes( constAttributes1, @@ -245,12 +191,12 @@ export class AstComparator { attributes: constDeclAttributes1, name: constDeclName1, type: constDeclType1, - } = node1 as AstConstantDecl; + } = node1 as A.AstConstantDecl; const { attributes: constDeclAttributes2, name: constDeclName2, type: constDeclType2, - } = node2 as AstConstantDecl; + } = node2 as A.AstConstantDecl; return ( this.compareAttributes( constDeclAttributes1, @@ -263,9 +209,9 @@ export class AstComparator { case "struct_decl": { const { name: structName1, fields: structFields1 } = - node1 as AstStructDecl; + node1 as A.AstStructDecl; const { name: structName2, fields: structFields2 } = - node2 as AstStructDecl; + node2 as A.AstStructDecl; return ( this.compare(structName1, structName2) && this.compareArray(structFields1, structFields2) @@ -274,9 +220,9 @@ export class AstComparator { case "message_decl": { const { name: msgName1, fields: msgFields1 } = - node1 as AstMessageDecl; + node1 as A.AstMessageDecl; const { name: msgName2, fields: msgFields2 } = - node2 as AstMessageDecl; + node2 as A.AstMessageDecl; return ( this.compare(msgName1, msgName2) && this.compareArray(msgFields1, msgFields2) @@ -289,13 +235,13 @@ export class AstComparator { traits: contractTraits1, attributes: contractAttributes1, declarations: contractDeclarations1, - } = node1 as AstContract; + } = node1 as A.AstContract; const { name: contractName2, traits: contractTraits2, attributes: contractAttributes2, declarations: contractDeclarations2, - } = node2 as AstContract; + } = node2 as A.AstContract; return ( this.compare(contractName1, contractName2) && this.compareArray(contractTraits1, contractTraits2) && @@ -316,13 +262,13 @@ export class AstComparator { traits: traits1, attributes: attributes1, declarations: declarations1, - } = node1 as AstTrait; + } = node1 as A.AstTrait; const { name: traitName2, traits: traits2, attributes: attributes2, declarations: declarations2, - } = node2 as AstTrait; + } = node2 as A.AstTrait; return ( this.compare(traitName1, traitName2) && this.compareArray(traits1, traits2) && @@ -337,13 +283,13 @@ export class AstComparator { type: fieldType1, initializer: fieldInitializer1, as: as1, - } = node1 as AstFieldDecl; + } = node1 as A.AstFieldDecl; const { name: fieldName2, type: fieldType2, initializer: fieldInitializer2, as: as2, - } = node2 as AstFieldDecl; + } = node2 as A.AstFieldDecl; return ( this.compare(fieldName1, fieldName2) && this.compare(fieldType1, fieldType2) && @@ -359,11 +305,11 @@ export class AstComparator { const { selector: receiverSelector1, statements: receiverStatements1, - } = node1 as AstReceiver; + } = node1 as A.AstReceiver; const { selector: receiverSelector2, statements: receiverStatements2, - } = node2 as AstReceiver; + } = node2 as A.AstReceiver; return ( this.compareReceiverKinds( receiverSelector1, @@ -375,9 +321,9 @@ export class AstComparator { case "contract_init": { const { params: initParams1, statements: initStatements1 } = - node1 as AstContractInit; + node1 as A.AstContractInit; const { params: initParams2, statements: initStatements2 } = - node2 as AstContractInit; + node2 as A.AstContractInit; return ( this.compareArray(initParams1, initParams2) && this.compareArray(initStatements1, initStatements2) @@ -389,12 +335,12 @@ export class AstComparator { name: name1, type: ty1, expression: expr1, - } = node1 as AstStatementLet; + } = node1 as A.AstStatementLet; const { name: name2, type: ty2, expression: expr2, - } = node2 as AstStatementLet; + } = node2 as A.AstStatementLet; return ( this.compare(name1, name2) && this.compareNullableNodes(ty1, ty2) && @@ -403,22 +349,22 @@ export class AstComparator { } case "statement_return": { - const { expression: expr1 } = node1 as AstStatementReturn; - const { expression: expr2 } = node2 as AstStatementReturn; + const { expression: expr1 } = node1 as A.AstStatementReturn; + const { expression: expr2 } = node2 as A.AstStatementReturn; return this.compareNullableNodes(expr1, expr2); } case "statement_expression": { - const { expression: expr1 } = node1 as AstStatementExpression; - const { expression: expr2 } = node2 as AstStatementExpression; + const { expression: expr1 } = node1 as A.AstStatementExpression; + const { expression: expr2 } = node2 as A.AstStatementExpression; return this.compareNullableNodes(expr1, expr2); } case "statement_assign": { const { path: assignPath1, expression: assignExpression1 } = - node1 as AstStatementAssign; + node1 as A.AstStatementAssign; const { path: assignPath2, expression: assignExpression2 } = - node2 as AstStatementAssign; + node2 as A.AstStatementAssign; return ( this.compare(assignPath1, assignPath2) && this.compare(assignExpression1, assignExpression2) @@ -430,12 +376,12 @@ export class AstComparator { op: augOp1, path: augPath1, expression: augExpression1, - } = node1 as AstStatementAugmentedAssign; + } = node1 as A.AstStatementAugmentedAssign; const { op: augOp2, path: augPath2, expression: augExpression2, - } = node2 as AstStatementAugmentedAssign; + } = node2 as A.AstStatementAugmentedAssign; return ( augOp1 === augOp2 && this.compare(augPath1, augPath2) && @@ -449,13 +395,13 @@ export class AstComparator { trueStatements: true1, falseStatements: false1, elseif: condElseIf1, - } = node1 as AstCondition; + } = node1 as A.AstCondition; const { condition: cond2, trueStatements: true2, falseStatements: false2, elseif: condElseIf2, - } = node2 as AstCondition; + } = node2 as A.AstCondition; return ( this.compare(cond1, cond2) && this.compareArray(true1, true2) && @@ -468,11 +414,11 @@ export class AstComparator { const { condition: loopCondition1, statements: loopStatements1, - } = node1 as AstStatementWhile; + } = node1 as A.AstStatementWhile; const { condition: loopCondition2, statements: loopStatements2, - } = node2 as AstStatementWhile; + } = node2 as A.AstStatementWhile; return ( this.compare(loopCondition1, loopCondition2) && this.compareArray(loopStatements1, loopStatements2) @@ -483,11 +429,11 @@ export class AstComparator { const { condition: loopCondition1, statements: loopStatements1, - } = node1 as AstStatementUntil; + } = node1 as A.AstStatementUntil; const { condition: loopCondition2, statements: loopStatements2, - } = node2 as AstStatementUntil; + } = node2 as A.AstStatementUntil; return ( this.compare(loopCondition1, loopCondition2) && this.compareArray(loopStatements1, loopStatements2) @@ -496,9 +442,9 @@ export class AstComparator { case "statement_repeat": { const { iterations: iter1, statements: stmts1 } = - node1 as AstStatementRepeat; + node1 as A.AstStatementRepeat; const { iterations: iter2, statements: stmts2 } = - node2 as AstStatementRepeat; + node2 as A.AstStatementRepeat; return ( this.compare(iter1, iter2) && this.compareArray(stmts1, stmts2) @@ -509,11 +455,11 @@ export class AstComparator { const { statements: tryCatchStatements1, catchBlock: catchBlock1, - } = node1 as AstStatementTry; + } = node1 as A.AstStatementTry; const { statements: tryCatchStatements2, catchBlock: catchBlock2, - } = node2 as AstStatementTry; + } = node2 as A.AstStatementTry; if ( !this.compareArray(tryCatchStatements1, tryCatchStatements2) @@ -551,13 +497,13 @@ export class AstComparator { valueName: forEachValueName1, map: forEachMap1, statements: forEachStatements1, - } = node1 as AstStatementForEach; + } = node1 as A.AstStatementForEach; const { keyName: forEachKeyName2, valueName: forEachValueName2, map: forEachMap2, statements: forEachStatements2, - } = node2 as AstStatementForEach; + } = node2 as A.AstStatementForEach; return ( this.compare(forEachKeyName1, forEachKeyName2) && this.compare(forEachValueName1, forEachValueName2) && @@ -570,11 +516,11 @@ export class AstComparator { const { field: destructMappingField1, name: destructMappingName1, - } = node1 as AstDestructMapping; + } = node1 as A.AstDestructMapping; const { field: destructMappingField2, name: destructMappingName2, - } = node2 as AstDestructMapping; + } = node2 as A.AstDestructMapping; return ( this.compare( destructMappingField1, @@ -589,12 +535,12 @@ export class AstComparator { type: destructType1, identifiers: destructIdentifiers1, expression: destructExpression1, - } = node1 as AstStatementDestruct; + } = node1 as A.AstStatementDestruct; const { type: destructType2, identifiers: destructIdentifiers2, expression: destructExpression2, - } = node2 as AstStatementDestruct; + } = node2 as A.AstStatementDestruct; const sortedIdentifiers1 = Array.from( destructIdentifiers1.values(), ).sort(); @@ -625,20 +571,24 @@ export class AstComparator { } case "statement_block": { - const { statements: statements1 } = node1 as AstStatementBlock; - const { statements: statements2 } = node2 as AstStatementBlock; + const { statements: statements1 } = + node1 as A.AstStatementBlock; + const { statements: statements2 } = + node2 as A.AstStatementBlock; return this.compareArray(statements1, statements2); } case "type_id": { - const { text: typeIdText1 } = node1 as AstTypeId; - const { text: typeIdText2 } = node2 as AstTypeId; + const { text: typeIdText1 } = node1 as A.AstTypeId; + const { text: typeIdText2 } = node2 as A.AstTypeId; return typeIdText1 === typeIdText2; } case "optional_type": { - const { typeArg: optionalTypeArg1 } = node1 as AstOptionalType; - const { typeArg: optionalTypeArg2 } = node2 as AstOptionalType; + const { typeArg: optionalTypeArg1 } = + node1 as A.AstOptionalType; + const { typeArg: optionalTypeArg2 } = + node2 as A.AstOptionalType; return this.compare(optionalTypeArg1, optionalTypeArg2); } @@ -648,13 +598,13 @@ export class AstComparator { keyStorageType: mapKeyStorageType1, valueType: mapValueType1, valueStorageType: mapValueStorageType1, - } = node1 as AstMapType; + } = node1 as A.AstMapType; const { keyType: mapKeyType2, keyStorageType: mapKeyStorageType2, valueType: mapValueType2, valueStorageType: mapValueStorageType2, - } = node2 as AstMapType; + } = node2 as A.AstMapType; return ( this.compare(mapKeyType1, mapKeyType2) && this.compareNullableNodes( @@ -671,9 +621,9 @@ export class AstComparator { case "bounced_message_type": { const { messageType: messageTy1 } = - node1 as AstBouncedMessageType; + node1 as A.AstBouncedMessageType; const { messageType: messageTy2 } = - node2 as AstBouncedMessageType; + node2 as A.AstBouncedMessageType; return this.compare(messageTy1, messageTy2); } @@ -682,12 +632,12 @@ export class AstComparator { op: binaryOp1, left: lhs1, right: rhs1, - } = node1 as AstOpBinary; + } = node1 as A.AstOpBinary; const { op: binaryOp2, left: lhs2, right: rhs2, - } = node2 as AstOpBinary; + } = node2 as A.AstOpBinary; return ( binaryOp1 === binaryOp2 && this.compare(lhs1, lhs2) && @@ -696,16 +646,16 @@ export class AstComparator { } case "op_unary": { - const { op: op1, operand: operand1 } = node1 as AstOpUnary; - const { op: op2, operand: operand2 } = node2 as AstOpUnary; + const { op: op1, operand: operand1 } = node1 as A.AstOpUnary; + const { op: op2, operand: operand2 } = node2 as A.AstOpUnary; return op1 === op2 && this.compare(operand1, operand2); } case "field_access": { const { aggregate: aggregate1, field: field1 } = - node1 as AstFieldAccess; + node1 as A.AstFieldAccess; const { aggregate: aggregate2, field: field2 } = - node2 as AstFieldAccess; + node2 as A.AstFieldAccess; return ( this.compare(aggregate1, aggregate2) && this.compare(field1, field2) @@ -717,12 +667,12 @@ export class AstComparator { self: self1, method: method1, args: args1, - } = node1 as AstMethodCall; + } = node1 as A.AstMethodCall; const { self: self2, method: method2, args: args2, - } = node2 as AstMethodCall; + } = node2 as A.AstMethodCall; return ( this.compare(self1, self2) && this.compare(method1, method2) && @@ -732,9 +682,9 @@ export class AstComparator { case "static_call": { const { function: staticFunction1, args: staticArgs1 } = - node1 as AstStaticCall; + node1 as A.AstStaticCall; const { function: staticFunction2, args: staticArgs2 } = - node2 as AstStaticCall; + node2 as A.AstStaticCall; return ( this.compare(staticFunction1, staticFunction2) && this.compareArray(staticArgs1, staticArgs2) @@ -742,8 +692,8 @@ export class AstComparator { } case "struct_instance": { - const { type: ty1, args: args1 } = node1 as AstStructInstance; - const { type: ty2, args: args2 } = node2 as AstStructInstance; + const { type: ty1, args: args1 } = node1 as A.AstStructInstance; + const { type: ty2, args: args2 } = node2 as A.AstStructInstance; return ( this.compare(ty1, ty2) && this.compareArray(args1, args2) ); @@ -751,9 +701,9 @@ export class AstComparator { case "init_of": { const { contract: initOfContract1, args: initOfArgs1 } = - node1 as AstInitOf; + node1 as A.AstInitOf; const { contract: initOfContract2, args: initOfArgs2 } = - node2 as AstInitOf; + node2 as A.AstInitOf; return ( this.compare(initOfContract1, initOfContract2) && this.compareArray(initOfArgs1, initOfArgs2) @@ -765,12 +715,12 @@ export class AstComparator { condition: cond1, thenBranch: then1, elseBranch: else1, - } = node1 as AstConditional; + } = node1 as A.AstConditional; const { condition: cond2, thenBranch: then2, elseBranch: else2, - } = node2 as AstConditional; + } = node2 as A.AstConditional; return ( this.compare(cond1, cond2) && this.compare(then1, then2) && @@ -779,32 +729,32 @@ export class AstComparator { } case "id": { - const { text: text1 } = node1 as AstId; - const { text: text2 } = node2 as AstId; + const { text: text1 } = node1 as A.AstId; + const { text: text2 } = node2 as A.AstId; return text1 === text2; } case "func_id": { - const { text: text1 } = node1 as AstFuncId; - const { text: text2 } = node2 as AstFuncId; + const { text: text1 } = node1 as A.AstFuncId; + const { text: text2 } = node2 as A.AstFuncId; return text1 === text2; } case "number": { - const { value: val1 } = node1 as AstNumber; - const { value: val2 } = node2 as AstNumber; + const { value: val1 } = node1 as A.AstNumber; + const { value: val2 } = node2 as A.AstNumber; return val1 === val2; } case "boolean": { - const { value: val1 } = node1 as AstBoolean; - const { value: val2 } = node2 as AstBoolean; + const { value: val1 } = node1 as A.AstBoolean; + const { value: val2 } = node2 as A.AstBoolean; return val1 === val2; } case "string": { - const { value: val1 } = node1 as AstString; - const { value: val2 } = node2 as AstString; + const { value: val1 } = node1 as A.AstString; + const { value: val2 } = node2 as A.AstString; return val1 === val2; } @@ -813,16 +763,16 @@ export class AstComparator { } case "typed_parameter": { - const { name: name1, type: ty1 } = node1 as AstTypedParameter; - const { name: name2, type: ty2 } = node1 as AstTypedParameter; + const { name: name1, type: ty1 } = node1 as A.AstTypedParameter; + const { name: name2, type: ty2 } = node1 as A.AstTypedParameter; return this.compare(name1, name2) && this.compare(ty1, ty2); } case "struct_field_initializer": { const { field: field1, initializer: initializer1 } = - node1 as AstStructFieldInitializer; + node1 as A.AstStructFieldInitializer; const { field: field2, initializer: initializer2 } = - node2 as AstStructFieldInitializer; + node2 as A.AstStructFieldInitializer; return ( this.compare(field1, field2) && this.compare(initializer1, initializer2) @@ -837,8 +787,8 @@ export class AstComparator { } private compareNullableNodes( - node1: AstNode | null, - node2: AstNode | null, + node1: A.AstNode | null, + node2: A.AstNode | null, ): boolean { if (node1 === null || node2 === null) { return node1 === node2; @@ -846,7 +796,7 @@ export class AstComparator { return this.compare(node1, node2); } - private compareArray(nodes1: AstNode[], nodes2: AstNode[]): boolean { + private compareArray(nodes1: A.AstNode[], nodes2: A.AstNode[]): boolean { if (nodes1.length !== nodes2.length) { return false; } @@ -859,8 +809,8 @@ export class AstComparator { } private compareNullableArray( - nodes1: AstNode[] | null, - nodes2: AstNode[] | null, + nodes1: A.AstNode[] | null, + nodes2: A.AstNode[] | null, ): boolean { if (nodes1 === null || nodes2 === null) { return nodes1 === nodes2; @@ -869,8 +819,8 @@ export class AstComparator { } private compareAsmInstructions( - instructions1: AstAsmInstruction[], - instructions2: AstAsmInstruction[], + instructions1: A.AstAsmInstruction[], + instructions2: A.AstAsmInstruction[], ): boolean { if (instructions1.length !== instructions2.length) { return false; @@ -880,9 +830,9 @@ export class AstComparator { private compareAttributes< T extends - | AstFunctionAttribute - | AstConstantAttribute - | AstContractAttribute, + | A.AstFunctionAttribute + | A.AstConstantAttribute + | A.AstContractAttribute, >(attrs1: T[], attrs2: T[]): boolean { if (attrs1.length !== attrs2.length) { return false; @@ -896,8 +846,8 @@ export class AstComparator { } private compareReceiverKinds( - kind1: AstReceiverKind, - kind2: AstReceiverKind, + kind1: A.AstReceiverKind, + kind2: A.AstReceiverKind, ): boolean { if (kind1.kind !== kind2.kind) { return false; diff --git a/src/ast/hash.ts b/src/ast/hash.ts index c447b771c..3e9351a58 100644 --- a/src/ast/hash.ts +++ b/src/ast/hash.ts @@ -1,30 +1,4 @@ -import { - AstConstantDef, - AstModuleItem, - AstStatement, - AstStructFieldInitializer, - AstFunctionAttribute, - AstConstantAttribute, - AstContractAttribute, - AstTypedParameter, - AstImport, - AstNativeFunctionDecl, - AstReceiver, - AstFunctionDef, - AstContract, - AstTrait, - AstId, - AstModule, - AstStructDecl, - AstMessageDecl, - AstFunctionDecl, - AstConstantDecl, - AstContractInit, - AstFieldDecl, - AstNode, - AstAsmFunctionDef, - AstAsmInstruction, -} from "./ast"; +import * as A from "./ast"; import { createHash } from "crypto"; import { throwInternalCompilerError } from "../error/errors"; import JSONbig from "json-bigint"; @@ -41,7 +15,7 @@ export class AstHasher { return new AstHasher(sort); } - public hash(node: AstNode): AstHash { + public hash(node: A.AstNode): AstHash { const data = node.kind === "id" || node.kind === "func_id" ? `${node.kind}_${node.text}` @@ -52,48 +26,52 @@ export class AstHasher { /** * Generates a string that is used to create a hash. */ - private getHashData(node: AstNode): string { + private getHashData(node: A.AstNode): string { switch (node.kind) { case "module": - return this.hashModule(node); + return this.hashModule(node as A.AstModule); case "struct_decl": - return this.hashStructDecl(node); + return this.hashStructDecl(node as A.AstStructDecl); case "message_decl": - return this.hashMessageDecl(node); + return this.hashMessageDecl(node as A.AstMessageDecl); case "function_def": - return this.hashFunctionDef(node); + return this.hashFunctionDef(node as A.AstFunctionDef); case "asm_function_def": - return this.hashAsmFunctionDef(node); + return this.hashAsmFunctionDef(node as A.AstAsmFunctionDef); case "constant_def": - return this.hashConstantDef(node); + return this.hashConstantDef(node as A.AstConstantDef); case "trait": - return this.hashTrait(node); + return this.hashTrait(node as A.AstTrait); case "contract": - return this.hashContract(node); + return this.hashContract(node as A.AstContract); case "field_decl": - return this.hashFieldDecl(node); + return this.hashFieldDecl(node as A.AstFieldDecl); case "primitive_type_decl": - return `${node.kind}|${node.name.kind}`; + return node.kind; case "contract_init": - return this.hashContractInit(node); + return this.hashContractInit(node as A.AstContractInit); case "native_function_decl": - return this.hashNativeFunctionDecl(node); + return this.hashNativeFunctionDecl( + node as A.AstNativeFunctionDecl, + ); case "receiver": - return this.hashReceiver(node); + return this.hashReceiver(node as A.AstReceiver); case "id": return "id"; case "func_id": return "func_id"; case "typed_parameter": - return this.hashTypedParameter(node); + return this.hashTypedParameter(node as A.AstTypedParameter); case "function_decl": - return this.hashFunctionDecl(node); + return this.hashFunctionDecl(node as A.AstFunctionDecl); case "struct_field_initializer": - return this.hashStructFieldInitializer(node); + return this.hashStructFieldInitializer( + node as A.AstStructFieldInitializer, + ); case "import": - return this.hashImport(node); + return this.hashImport(node as A.AstImport); case "constant_decl": - return this.hashConstantDecl(node); + return this.hashConstantDecl(node as A.AstConstantDecl); // Statements case "statement_let": return `${node.kind}|${node.type ? this.hash(node.type) : "null"}|${this.hash(node.expression)}`; @@ -201,24 +179,24 @@ export class AstHasher { } } - private hashDestructIdentifiers(identifiers: [AstId, AstId][]): string { + private hashDestructIdentifiers(identifiers: [A.AstId, A.AstId][]): string { const identifiersHash = identifiers .map(([key, value]) => `${this.hash(key)}|${this.hash(value)}`) .join("|"); return identifiersHash; } - private hashStructDecl(node: AstStructDecl): string { + private hashStructDecl(node: A.AstStructDecl): string { const fieldsHash = this.hashFields(node.fields); return `struct|${fieldsHash}`; } - private hashMessageDecl(node: AstMessageDecl): string { + private hashMessageDecl(node: A.AstMessageDecl): string { const fieldsHash = this.hashFields(node.fields); return `message|${fieldsHash}|${node.opcode ? this.hash(node.opcode) : "null"}`; } - private hashFunctionDef(node: AstFunctionDef): string { + private hashFunctionDef(node: A.AstFunctionDef): string { const attributesHash = this.hashAttributes(node.attributes); const returnHash = node.return ? this.hash(node.return) : "void"; const paramsHash = this.hashParams(node.params); @@ -226,7 +204,7 @@ export class AstHasher { return `function|${attributesHash}|${returnHash}|${paramsHash}|${statementsHash}`; } - private hashAsmFunctionDef(node: AstAsmFunctionDef): string { + private hashAsmFunctionDef(node: A.AstAsmFunctionDef): string { const asmAttributeHash = `asm|${this.hashIds(node.shuffle.args)}|->|${node.shuffle.ret.map((num) => num.value.toString()).join("|")}`; const attributesHash = this.hashAttributes(node.attributes); const returnHash = node.return ? this.hash(node.return) : "void"; @@ -235,28 +213,28 @@ export class AstHasher { return `function|${asmAttributeHash}|${attributesHash}|${returnHash}|${paramsHash}|${instructionsHash}`; } - private hashConstantDef(node: AstConstantDef): string { + private hashConstantDef(node: A.AstConstantDef): string { const attributesHash = this.hashAttributes(node.attributes); const typeHash = this.hash(node.type); const initializerHash = this.hash(node.initializer); return `constant|${attributesHash}|${typeHash}|${initializerHash}`; } - private hashTrait(node: AstTrait): string { + private hashTrait(node: A.AstTrait): string { const traitsHash = this.hashIds(node.traits); const attributesHash = this.hashContractAttributes(node.attributes); const declarationsHash = this.hashDeclarations(node.declarations); return `trait|${traitsHash}|${attributesHash}|${declarationsHash}`; } - private hashContract(node: AstContract): string { + private hashContract(node: A.AstContract): string { const traitsHash = this.hashIds(node.traits); const attributesHash = this.hashContractAttributes(node.attributes); const declarationsHash = this.hashDeclarations(node.declarations); return `contract|${traitsHash}|${attributesHash}|${declarationsHash}`; } - private hashFields(fields: AstFieldDecl[]): string { + private hashFields(fields: A.AstFieldDecl[]): string { let hashedFields = fields.map((field) => this.hashFieldDecl(field)); if (this.sort) { hashedFields = hashedFields.sort(); @@ -264,7 +242,7 @@ export class AstHasher { return hashedFields.join("|"); } - private hashParams(params: AstTypedParameter[]): string { + private hashParams(params: A.AstTypedParameter[]): string { let hashedParams = params.map((param) => this.hashTypedParameter(param), ); @@ -274,13 +252,13 @@ export class AstHasher { return hashedParams.join("|"); } - private hashTypedParameter(param: AstTypedParameter): string { + private hashTypedParameter(param: A.AstTypedParameter): string { const typeHash = this.hash(param.type); return `param|${typeHash}`; } private hashAttributes( - attributes: (AstFunctionAttribute | AstConstantAttribute)[], + attributes: (A.AstFunctionAttribute | A.AstConstantAttribute)[], ): string { return attributes .map((attr) => attr.type) @@ -288,21 +266,23 @@ export class AstHasher { .join("|"); } - private hashContractAttributes(attributes: AstContractAttribute[]): string { + private hashContractAttributes( + attributes: A.AstContractAttribute[], + ): string { return attributes .map((attr) => `${attr.type}|${attr.name.value}`) .sort() .join("|"); } - private hashIds(ids: AstId[]): string { + private hashIds(ids: A.AstId[]): string { return ids .map((id) => id.kind) .sort() .join("|"); // Ignore actual id.text, just hash based on kind } - private hashDeclarations(declarations: AstNode[]): string { + private hashDeclarations(declarations: A.AstNode[]): string { let hashedDeclarations = declarations.map((decl) => this.hash(decl)); if (this.sort) { hashedDeclarations = hashedDeclarations.sort(); @@ -310,7 +290,7 @@ export class AstHasher { return hashedDeclarations.join("|"); } - private hashStatements(statements: AstStatement[]): string { + private hashStatements(statements: A.AstStatement[]): string { let hashedStatements = statements.map((stmt) => this.hash(stmt)); if (this.sort) { hashedStatements = hashedStatements.sort(); @@ -318,64 +298,64 @@ export class AstHasher { return hashedStatements.join("|"); } - private hashInstructions(instructions: AstAsmInstruction[]): string { + private hashInstructions(instructions: A.AstAsmInstruction[]): string { return instructions.join("|"); } private hashStructFieldInitializer( - initializer: AstStructFieldInitializer, + initializer: A.AstStructFieldInitializer, ): string { return `field_initializer|${this.hash(initializer.initializer)}`; } - private hashFieldDecl(field: AstFieldDecl): string { + private hashFieldDecl(field: A.AstFieldDecl): string { const typeHash = this.hash(field.type); return `field|${typeHash}`; } - private hashContractInit(node: AstContractInit): string { + private hashContractInit(node: A.AstContractInit): string { const paramsHash = this.hashParams(node.params); const statementsHash = this.hashStatements(node.statements); return `${node.kind}|${paramsHash}|${statementsHash}`; } - private hashNativeFunctionDecl(node: AstNativeFunctionDecl): string { + private hashNativeFunctionDecl(node: A.AstNativeFunctionDecl): string { const attributesHash = this.hashAttributes(node.attributes); const paramsHash = this.hashParams(node.params); const returnHash = node.return ? this.hash(node.return) : "void"; return `${node.kind}|${attributesHash}|${paramsHash}|${returnHash}`; } - private hashReceiver(node: AstReceiver): string { + private hashReceiver(node: A.AstReceiver): string { const selectorHash = node.selector.kind; const statementsHash = this.hashStatements(node.statements); return `${node.kind}|${selectorHash}|${statementsHash}`; } - private hashFunctionDecl(node: AstFunctionDecl): string { + private hashFunctionDecl(node: A.AstFunctionDecl): string { const attributesHash = this.hashAttributes(node.attributes); const returnHash = node.return ? this.hash(node.return) : "void"; const paramsHash = this.hashParams(node.params); return `${node.kind}|${attributesHash}|${returnHash}|${paramsHash}`; } - private hashImport(node: AstImport): string { + private hashImport(node: A.AstImport): string { return `${node.kind}|${this.hash(node.path)}`; } - private hashConstantDecl(node: AstConstantDecl): string { + private hashConstantDecl(node: A.AstConstantDecl): string { const attributesHash = this.hashAttributes(node.attributes); const typeHash = this.hash(node.type); return `${node.kind}|${attributesHash}|${typeHash}`; } - private hashModule(node: AstModule): string { + private hashModule(node: A.AstModule): string { const importsHash = this.hashImports(node.imports); const itemsHash = this.hashModuleItems(node.items); return `${node.kind}|${importsHash}|${itemsHash}`; } - private hashImports(imports: AstImport[]): string { + private hashImports(imports: A.AstImport[]): string { let hashedImports = imports.map((imp) => this.hash(imp)); if (this.sort) { hashedImports = hashedImports.sort(); @@ -383,7 +363,7 @@ export class AstHasher { return hashedImports.join("|"); } - private hashModuleItems(items: AstModuleItem[]): string { + private hashModuleItems(items: A.AstModuleItem[]): string { let hashedItems = items.map((item) => this.hash(item)); if (this.sort) { hashedItems = hashedItems.sort(); diff --git a/src/ast/rename.ts b/src/ast/rename.ts index 174c777b0..9f686c363 100644 --- a/src/ast/rename.ts +++ b/src/ast/rename.ts @@ -1,29 +1,11 @@ -import { - AstConstantDef, - AstModuleItem, - AstStatement, - AstModule, - AstTraitDeclaration, - AstContractDeclaration, - AstExpression, - AstStructFieldInitializer, - AstCondition, - AstFunctionDef, - AstContract, - AstTrait, - AstId, - AstFunctionDecl, - AstConstantDecl, - AstNode, - AstFunctionAttribute, -} from "./ast"; +import * as A from "./ast"; import { AstSorter } from "./sort"; import { AstHasher, AstHash } from "./hash"; import { dummySrcInfo } from "../grammar/src-info"; type GivenName = string; -function id(text: string): AstId { +function id(text: string): A.AstId { return { kind: "id", text, id: 0, loc: dummySrcInfo }; } @@ -46,7 +28,7 @@ export class AstRenamer { /** * Renames the given node based on its AST. */ - public renameModule(module: AstModule): AstNode { + public renameModule(module: A.AstModule): A.AstNode { return { ...module, items: this.renameModuleItems(module.items), @@ -62,14 +44,14 @@ export class AstRenamer { /** * Generates a new unique node name. */ - private generateName(node: AstNode): GivenName { + private generateName(node: A.AstNode): GivenName { return `${node.kind}_${this.nextIdx()}`; } /** * Tries to get an identifier based on the node definition. */ - private getName(node: AstNode): string | undefined { + private getName(node: A.AstNode): string | undefined { switch (node.kind) { case "id": case "func_id": @@ -93,7 +75,7 @@ export class AstRenamer { /** * Sets new or an existent name based on node's hash. */ - private setName(node: AstNode, forceName?: string): GivenName { + private setName(node: A.AstNode, forceName?: string): GivenName { const hash = AstHasher.make({ sort: this.sort }).hash(node); const giveNewName = (newName: string) => { const name = this.getName(node); @@ -112,7 +94,7 @@ export class AstRenamer { return name; } - public renameModuleItems(items: AstModuleItem[]): AstModuleItem[] { + public renameModuleItems(items: A.AstModuleItem[]): A.AstModuleItem[] { // Give new names to module-level elements. const renamedItems = items.map((item) => this.renameModuleItemContents( @@ -127,7 +109,7 @@ export class AstRenamer { /** * Lexicographically sort items based on their kinds and then by their names. */ - private sortModuleItems(items: AstModuleItem[]): AstModuleItem[] { + private sortModuleItems(items: A.AstModuleItem[]): A.AstModuleItem[] { const kindOrder = { primitive_type_decl: 1, native_function_decl: 2, @@ -152,7 +134,7 @@ export class AstRenamer { * Changes the name of a top-level/contract/trait element without inspecting its body. */ private changeItemName< - T extends AstModuleItem | AstConstantDecl | AstFunctionDecl, + T extends A.AstModuleItem | A.AstConstantDecl | A.AstFunctionDecl, >(item: T): T { switch (item.kind) { case "primitive_type_decl": @@ -173,7 +155,7 @@ export class AstRenamer { ) { return this.changeItemName( decl, - ) as AstContractDeclaration; + ) as A.AstContractDeclaration; } else { return decl; } @@ -189,7 +171,9 @@ export class AstRenamer { decl.kind === "function_decl" || decl.kind === "constant_decl" ) { - return this.changeItemName(decl) as AstTraitDeclaration; + return this.changeItemName( + decl, + ) as A.AstTraitDeclaration; } else { return decl; } @@ -206,7 +190,7 @@ export class AstRenamer { /** * Renames the contents of an AstModuleItem based on its kind. */ - private renameModuleItemContents(item: AstModuleItem): AstModuleItem { + private renameModuleItemContents(item: A.AstModuleItem): A.AstModuleItem { switch (item.kind) { case "struct_decl": return item; @@ -219,13 +203,13 @@ export class AstRenamer { } return item; case "function_def": - return this.renameFunctionContents(item as AstFunctionDef); + return this.renameFunctionContents(item as A.AstFunctionDef); case "constant_def": - return this.renameConstantContents(item as AstConstantDef); + return this.renameConstantContents(item as A.AstConstantDef); case "trait": - return this.renameTraitContents(item as AstTrait); + return this.renameTraitContents(item as A.AstTrait); case "contract": - return this.renameContractContents(item as AstContract); + return this.renameContractContents(item as A.AstContract); default: return item; // No further renaming needed for other kinds } @@ -235,7 +219,10 @@ export class AstRenamer { * Sorts attributes within an item if available. */ private sortAttributes< - T extends AstModuleItem | AstContractDeclaration | AstTraitDeclaration, + T extends + | A.AstModuleItem + | A.AstContractDeclaration + | A.AstTraitDeclaration, >(item: T): T { switch (item.kind) { case "trait": @@ -268,8 +255,8 @@ export class AstRenamer { * Renames the contents of a function. */ private renameFunctionContents( - functionDef: AstFunctionDef, - ): AstFunctionDef { + functionDef: A.AstFunctionDef, + ): A.AstFunctionDef { const attributes = this.renameFunctionAttributes( functionDef.attributes, ); @@ -281,8 +268,8 @@ export class AstRenamer { * Renames getter's methodId expression. */ private renameFunctionAttributes( - functionAttrs: AstFunctionAttribute[], - ): AstFunctionAttribute[] { + functionAttrs: A.AstFunctionAttribute[], + ): A.AstFunctionAttribute[] { return functionAttrs.map((attr) => { if (attr.type === "get" && attr.methodId !== null) { return { @@ -299,8 +286,8 @@ export class AstRenamer { * Renames the contents of a constant, focusing on the initializer. */ private renameConstantContents( - constantDef: AstConstantDef, - ): AstConstantDef { + constantDef: A.AstConstantDef, + ): A.AstConstantDef { const initializer = this.renameExpression(constantDef.initializer); return { ...constantDef, initializer }; } @@ -308,12 +295,12 @@ export class AstRenamer { /** * Renames the contents of a trait, including its declarations. */ - private renameTraitContents(trait: AstTrait): AstTrait { + private renameTraitContents(trait: A.AstTrait): A.AstTrait { const declarations = trait.declarations.map((decl) => { if (decl.kind === "function_def") { - return this.renameFunctionContents(decl as AstFunctionDef); + return this.renameFunctionContents(decl as A.AstFunctionDef); } else if (decl.kind === "constant_def") { - return this.renameConstantContents(decl as AstConstantDef); + return this.renameConstantContents(decl as A.AstConstantDef); } else { return decl; } @@ -324,12 +311,12 @@ export class AstRenamer { /** * Renames the contents of a contract, including its declarations and parameters. */ - private renameContractContents(contract: AstContract): AstContract { + private renameContractContents(contract: A.AstContract): A.AstContract { const declarations = contract.declarations.map((decl) => { if (decl.kind === "function_def") { - return this.renameFunctionContents(decl as AstFunctionDef); + return this.renameFunctionContents(decl as A.AstFunctionDef); } else if (decl.kind === "constant_def") { - return this.renameConstantContents(decl as AstConstantDef); + return this.renameConstantContents(decl as A.AstConstantDef); } else { return decl; } @@ -337,13 +324,13 @@ export class AstRenamer { return { ...contract, declarations }; } - private renameStatements(statements: AstStatement[]): AstStatement[] { + private renameStatements(statements: A.AstStatement[]): A.AstStatement[] { return statements.map((stmt) => { return this.renameStatement(stmt); }); } - private renameStatement(stmt: AstStatement): AstStatement { + private renameStatement(stmt: A.AstStatement): A.AstStatement { switch (stmt.kind) { case "statement_let": return { @@ -383,7 +370,7 @@ export class AstRenamer { ? this.renameStatements(stmt.falseStatements) : null, elseif: stmt.elseif - ? (this.renameStatement(stmt.elseif) as AstCondition) + ? (this.renameStatement(stmt.elseif) as A.AstCondition) : null, }; case "statement_while": @@ -428,7 +415,7 @@ export class AstRenamer { } } - private renameExpression(expr: AstExpression): AstExpression { + private renameExpression(expr: A.AstExpression): A.AstExpression { switch (expr.kind) { case "id": return { @@ -487,8 +474,8 @@ export class AstRenamer { } private renameStructFieldInitializer( - initializer: AstStructFieldInitializer, - ): AstStructFieldInitializer { + initializer: A.AstStructFieldInitializer, + ): A.AstStructFieldInitializer { return { ...initializer, initializer: this.renameExpression(initializer.initializer), diff --git a/src/ast/sort.ts b/src/ast/sort.ts index a924702c6..f055a6384 100644 --- a/src/ast/sort.ts +++ b/src/ast/sort.ts @@ -1,10 +1,4 @@ -import { - AstPrimitiveTypeDecl, - AstFunctionAttribute, - AstConstantAttribute, - AstContractAttribute, - AstNode, -} from "./ast"; +import * as A from "./ast"; import { throwInternalCompilerError } from "../error/errors"; /** @@ -12,7 +6,7 @@ import { throwInternalCompilerError } from "../error/errors"; */ // eslint-disable-next-line @typescript-eslint/no-extraneous-class export class AstSorter { - public static sort(items: T[]): T[] { + public static sort(items: T[]): T[] { if (items.length === 0) { return items; } @@ -20,7 +14,7 @@ export class AstSorter { switch (kind) { case "primitive_type_decl": return this.sortPrimitiveTypeDecls( - items as AstPrimitiveTypeDecl[], + items as A.AstPrimitiveTypeDecl[], ) as T[]; default: throwInternalCompilerError(`Unsupported node kind: ${kind}`); @@ -28,8 +22,8 @@ export class AstSorter { } private static sortPrimitiveTypeDecls( - decls: AstPrimitiveTypeDecl[], - ): AstPrimitiveTypeDecl[] { + decls: A.AstPrimitiveTypeDecl[], + ): A.AstPrimitiveTypeDecl[] { return decls.sort((a, b) => { // Case-insensitive sorting const nameA = a.name.text.toLowerCase(); @@ -46,9 +40,9 @@ export class AstSorter { public static sortAttributes< T extends - | AstConstantAttribute - | AstContractAttribute - | AstFunctionAttribute, + | A.AstConstantAttribute + | A.AstContractAttribute + | A.AstFunctionAttribute, >(attributes: T[]): T[] { return attributes.sort((a, b) => a.type.localeCompare(b.type)); } diff --git a/src/ast/util.ts b/src/ast/util.ts index 0a2f7af34..962938d41 100644 --- a/src/ast/util.ts +++ b/src/ast/util.ts @@ -1,44 +1,26 @@ +import * as A from "./ast"; import { Address, Cell, Slice } from "@ton/core"; -import { - AstExpression, - AstUnaryOperation, - AstBinaryOperation, - isLiteral, - AstNumber, - AstBoolean, - AstSimplifiedString, - AstNull, - AstCell, - AstSlice, - AstAddress, - AstLiteral, - AstStructValue, - AstStructFieldValue, - AstId, - AstCommentValue, - FactoryAst, -} from "./ast"; import { dummySrcInfo, SrcInfo } from "../grammar"; -export const getAstUtil = ({ createNode }: FactoryAst) => { +export const getAstUtil = ({ createNode }: A.FactoryAst) => { function makeUnaryExpression( - op: AstUnaryOperation, - operand: AstExpression, - ): AstExpression { + op: A.AstUnaryOperation, + operand: A.AstExpression, + ): A.AstExpression { const result = createNode({ kind: "op_unary", op: op, operand: operand, loc: dummySrcInfo, }); - return result as AstExpression; + return result as A.AstExpression; } function makeBinaryExpression( - op: AstBinaryOperation, - left: AstExpression, - right: AstExpression, - ): AstExpression { + op: A.AstBinaryOperation, + left: A.AstExpression, + right: A.AstExpression, + ): A.AstExpression { const result = createNode({ kind: "op_binary", op: op, @@ -46,114 +28,114 @@ export const getAstUtil = ({ createNode }: FactoryAst) => { right: right, loc: dummySrcInfo, }); - return result as AstExpression; + return result as A.AstExpression; } - function makeNumberLiteral(n: bigint, loc: SrcInfo): AstNumber { + function makeNumberLiteral(n: bigint, loc: SrcInfo): A.AstNumber { const result = createNode({ kind: "number", base: 10, value: n, loc: loc, }); - return result as AstNumber; + return result as A.AstNumber; } - function makeBooleanLiteral(b: boolean, loc: SrcInfo): AstBoolean { + function makeBooleanLiteral(b: boolean, loc: SrcInfo): A.AstBoolean { const result = createNode({ kind: "boolean", value: b, loc: loc, }); - return result as AstBoolean; + return result as A.AstBoolean; } function makeSimplifiedStringLiteral( s: string, loc: SrcInfo, - ): AstSimplifiedString { + ): A.AstSimplifiedString { const result = createNode({ kind: "simplified_string", value: s, loc: loc, }); - return result as AstSimplifiedString; + return result as A.AstSimplifiedString; } - function makeCommentLiteral(s: string, loc: SrcInfo): AstCommentValue { + function makeCommentLiteral(s: string, loc: SrcInfo): A.AstCommentValue { const result = createNode({ kind: "comment_value", value: s, loc: loc, }); - return result as AstCommentValue; + return result as A.AstCommentValue; } - function makeNullLiteral(loc: SrcInfo): AstNull { + function makeNullLiteral(loc: SrcInfo): A.AstNull { const result = createNode({ kind: "null", loc: loc, }); - return result as AstNull; + return result as A.AstNull; } - function makeCellLiteral(c: Cell, loc: SrcInfo): AstCell { + function makeCellLiteral(c: Cell, loc: SrcInfo): A.AstCell { const result = createNode({ kind: "cell", value: c, loc: loc, }); - return result as AstCell; + return result as A.AstCell; } - function makeSliceLiteral(s: Slice, loc: SrcInfo): AstSlice { + function makeSliceLiteral(s: Slice, loc: SrcInfo): A.AstSlice { const result = createNode({ kind: "slice", value: s, loc: loc, }); - return result as AstSlice; + return result as A.AstSlice; } - function makeAddressLiteral(a: Address, loc: SrcInfo): AstAddress { + function makeAddressLiteral(a: Address, loc: SrcInfo): A.AstAddress { const result = createNode({ kind: "address", value: a, loc: loc, }); - return result as AstAddress; + return result as A.AstAddress; } function makeStructFieldValue( fieldName: string, - val: AstLiteral, + val: A.AstLiteral, loc: SrcInfo, - ): AstStructFieldValue { + ): A.AstStructFieldValue { const result = createNode({ kind: "struct_field_value", field: createNode({ kind: "id", text: fieldName, loc: loc, - }) as AstId, + }) as A.AstId, initializer: val, loc: loc, }); - return result as AstStructFieldValue; + return result as A.AstStructFieldValue; } function makeStructValue( - fields: AstStructFieldValue[], - type: AstId, + fields: A.AstStructFieldValue[], + type: A.AstId, loc: SrcInfo, - ): AstStructValue { + ): A.AstStructValue { const result = createNode({ kind: "struct_value", args: fields, loc: loc, type: type, }); - return result as AstStructValue; + return result as A.AstStructValue; } return { @@ -175,38 +157,38 @@ export const getAstUtil = ({ createNode }: FactoryAst) => { export type AstUtil = ReturnType; // Checks if the top level node is an unary op node -export function checkIsUnaryOpNode(ast: AstExpression): boolean { +export function checkIsUnaryOpNode(ast: A.AstExpression): boolean { return ast.kind === "op_unary"; } // Checks if the top level node is a binary op node -export function checkIsBinaryOpNode(ast: AstExpression): boolean { +export function checkIsBinaryOpNode(ast: A.AstExpression): boolean { return ast.kind === "op_binary"; } // Checks if top level node is a binary op node // with a value node on the right -export function checkIsBinaryOp_With_RightValue(ast: AstExpression): boolean { - return ast.kind === "op_binary" ? isLiteral(ast.right) : false; +export function checkIsBinaryOp_With_RightValue(ast: A.AstExpression): boolean { + return ast.kind === "op_binary" ? A.isLiteral(ast.right) : false; } // Checks if top level node is a binary op node // with a value node on the left -export function checkIsBinaryOp_With_LeftValue(ast: AstExpression): boolean { - return ast.kind === "op_binary" ? isLiteral(ast.left) : false; +export function checkIsBinaryOp_With_LeftValue(ast: A.AstExpression): boolean { + return ast.kind === "op_binary" ? A.isLiteral(ast.left) : false; } // Checks if the top level node is the specified number -export function checkIsNumber(ast: AstExpression, n: bigint): boolean { +export function checkIsNumber(ast: A.AstExpression, n: bigint): boolean { return ast.kind === "number" ? ast.value == n : false; } -export function checkIsName(ast: AstExpression): boolean { +export function checkIsName(ast: A.AstExpression): boolean { return ast.kind === "id"; } // Checks if the top level node is the specified boolean -export function checkIsBoolean(ast: AstExpression, b: boolean): boolean { +export function checkIsBoolean(ast: A.AstExpression, b: boolean): boolean { return ast.kind === "boolean" ? ast.value == b : false; } diff --git a/src/generator/writers/writeExpression.ts b/src/generator/writers/writeExpression.ts index fea2743c0..9665b89bc 100644 --- a/src/generator/writers/writeExpression.ts +++ b/src/generator/writers/writeExpression.ts @@ -1,12 +1,4 @@ -import { - AstExpression, - AstId, - AstLiteral, - eqNames, - getAstFactory, - idText, - tryExtractPath, -} from "../../ast/ast"; +import * as A from "../../ast/ast"; import { idTextErr, TactConstEvalError, @@ -45,7 +37,7 @@ import { isLvalue } from "../../types/resolveStatements"; import { evalConstantExpression } from "../../optimizer/constEval"; import { getAstUtil } from "../../ast/util"; -function isNull(wCtx: WriterContext, expr: AstExpression): boolean { +function isNull(wCtx: WriterContext, expr: A.AstExpression): boolean { return getExpType(wCtx.ctx, expr).kind === "null"; } @@ -99,7 +91,7 @@ function writeStructConstructor( return name; } -export function writeValue(val: AstLiteral, wCtx: WriterContext): string { +export function writeValue(val: A.AstLiteral, wCtx: WriterContext): string { switch (val.kind) { case "number": return val.value.toString(10); @@ -134,9 +126,9 @@ export function writeValue(val: AstLiteral, wCtx: WriterContext): string { } case "struct_value": { // Transform the struct fields into a map for lookup - const valMap: Map = new Map(); + const valMap: Map = new Map(); for (const f of val.args) { - valMap.set(idText(f.field), f.initializer); + valMap.set(A.idText(f.field), f.initializer); } const structDescription = getType(wCtx.ctx, val.type); @@ -167,11 +159,16 @@ export function writeValue(val: AstLiteral, wCtx: WriterContext): string { } } -export function writePathExpression(path: AstId[]): string { - return [funcIdOf(idText(path[0]!)), ...path.slice(1).map(idText)].join(`'`); +export function writePathExpression(path: A.AstId[]): string { + return [funcIdOf(A.idText(path[0]!)), ...path.slice(1).map(A.idText)].join( + `'`, + ); } -export function writeExpression(f: AstExpression, wCtx: WriterContext): string { +export function writeExpression( + f: A.AstExpression, + wCtx: WriterContext, +): string { // literals and constant expressions are covered here // FIXME: Once optimization step is added, remove this try and replace it with this @@ -180,7 +177,7 @@ export function writeExpression(f: AstExpression, wCtx: WriterContext): string { // return writeValue(f, wCtx); // } try { - const util = getAstUtil(getAstFactory()); + const util = getAstUtil(A.getAstFactory()); // Let us put a limit of 2 ^ 12 = 4096 iterations on loops to increase compiler responsiveness. // If a loop takes more than such number of iterations, the interpreter will fail evaluation. // I think maxLoopIterations should be a command line option in case a user wants to wait more @@ -466,8 +463,8 @@ export function writeExpression(f: AstExpression, wCtx: WriterContext): string { fields = fields.slice(0, srcT.partialFieldCount); } - const field = fields.find((v) => eqNames(v.name, f.field)); - const cst = srcT.constants.find((v) => eqNames(v.name, f.field)); + const field = fields.find((v) => A.eqNames(v.name, f.field)); + const cst = srcT.constants.find((v) => A.eqNames(v.name, f.field)); if (!field && !cst) { throwCompilationError( `Cannot find field ${idTextErr(f.field)} in struct ${idTextErr(srcT.name)}`, @@ -477,7 +474,7 @@ export function writeExpression(f: AstExpression, wCtx: WriterContext): string { if (field) { // Trying to resolve field as a path - const path = tryExtractPath(f); + const path = A.tryExtractPath(f); if (path) { // Prepare path const idd = writePathExpression(path); @@ -506,8 +503,8 @@ export function writeExpression(f: AstExpression, wCtx: WriterContext): string { if (f.kind === "static_call") { // Check global functions - if (GlobalFunctions.has(idText(f.function))) { - return GlobalFunctions.get(idText(f.function))!.generate( + if (GlobalFunctions.has(A.idText(f.function))) { + return GlobalFunctions.get(A.idText(f.function))!.generate( wCtx, f.args.map((v) => getExpType(wCtx.ctx, v)), f.args, @@ -515,10 +512,10 @@ export function writeExpression(f: AstExpression, wCtx: WriterContext): string { ); } - const sf = getStaticFunction(wCtx.ctx, idText(f.function)); - let n = ops.global(idText(f.function)); + const sf = getStaticFunction(wCtx.ctx, A.idText(f.function)); + let n = ops.global(A.idText(f.function)); if (sf.ast.kind === "native_function_decl") { - n = idText(sf.ast.nativeName); + n = A.idText(sf.ast.nativeName); if (n.startsWith("__tact")) { wCtx.used(n); } @@ -547,7 +544,7 @@ export function writeExpression(f: AstExpression, wCtx: WriterContext): string { // Write a constructor const id = writeStructConstructor( src, - f.args.map((v) => idText(v.field)), + f.args.map((v) => A.idText(v.field)), wCtx, ); wCtx.used(id); @@ -557,7 +554,7 @@ export function writeExpression(f: AstExpression, wCtx: WriterContext): string { (v) => writeCastedExpression( v.initializer, - src.fields.find((v2) => eqNames(v2.name, v.field))!.type, + src.fields.find((v2) => A.eqNames(v2.name, v.field))!.type, wCtx, ), wCtx, @@ -580,8 +577,8 @@ export function writeExpression(f: AstExpression, wCtx: WriterContext): string { // Check struct ABI if (selfTy.kind === "struct") { - if (StructFunctions.has(idText(f.method))) { - const abi = StructFunctions.get(idText(f.method))!; + if (StructFunctions.has(A.idText(f.method))) { + const abi = StructFunctions.get(A.idText(f.method))!; return abi.generate( wCtx, [ @@ -595,8 +592,8 @@ export function writeExpression(f: AstExpression, wCtx: WriterContext): string { } // Resolve function - const methodDescr = selfTy.functions.get(idText(f.method))!; - let name = ops.extension(selfTyRef.name, idText(f.method)); + const methodDescr = selfTy.functions.get(A.idText(f.method))!; + let name = ops.extension(selfTyRef.name, A.idText(f.method)); if ( methodDescr.ast.kind === "function_def" || methodDescr.ast.kind === "function_decl" || @@ -604,7 +601,7 @@ export function writeExpression(f: AstExpression, wCtx: WriterContext): string { ) { wCtx.used(name); } else { - name = idText(methodDescr.ast.nativeName); + name = A.idText(methodDescr.ast.nativeName); if (name.startsWith("__tact")) { wCtx.used(name); } @@ -638,7 +635,7 @@ export function writeExpression(f: AstExpression, wCtx: WriterContext): string { const s = writeCastedExpression(f.self, methodDescr.self!, wCtx); if (methodDescr.isMutating) { // check if it's an l-value - const path = tryExtractPath(f.self); + const path = A.tryExtractPath(f.self); if (path !== null && isLvalue(path, wCtx.ctx)) { return `${s}~${name}(${renderedArguments.join(", ")})`; } else { @@ -651,13 +648,13 @@ export function writeExpression(f: AstExpression, wCtx: WriterContext): string { // Map types if (selfTyRef.kind === "map") { - if (!MapFunctions.has(idText(f.method))) { + if (!MapFunctions.has(A.idText(f.method))) { throwCompilationError( - `Map function "${idText(f.method)}" not found`, + `Map function "${A.idText(f.method)}" not found`, f.loc, ); } - const abf = MapFunctions.get(idText(f.method))!; + const abf = MapFunctions.get(A.idText(f.method))!; return abf.generate( wCtx, [selfTyRef, ...f.args.map((v) => getExpType(wCtx.ctx, v))], @@ -685,7 +682,7 @@ export function writeExpression(f: AstExpression, wCtx: WriterContext): string { const initArgs = f.args.map((a, i) => writeCastedExpression(a, type.init!.params[i]!.type, wCtx), ); - return `${ops.contractInitChild(idText(f.contract), wCtx)}(${initArgs.join(", ")})`; + return `${ops.contractInitChild(A.idText(f.contract), wCtx)}(${initArgs.join(", ")})`; } // diff --git a/src/generator/writers/writeFunction.ts b/src/generator/writers/writeFunction.ts index 9c931d7f4..934ca3fbc 100644 --- a/src/generator/writers/writeFunction.ts +++ b/src/generator/writers/writeFunction.ts @@ -1,14 +1,5 @@ import { enabledInline } from "../../config/features"; -import { - AstAsmShuffle, - AstCondition, - AstExpression, - AstStatement, - idOfText, - idText, - isWildcard, - tryExtractPath, -} from "../../ast/ast"; +import * as A from "../../ast/ast"; import { getType, resolveTypeRef } from "../../types/resolveDescriptors"; import { getExpType } from "../../types/resolveExpression"; import { FunctionDescription, TypeRef } from "../../types/types"; @@ -26,7 +17,7 @@ import { idTextErr, throwInternalCompilerError } from "../../error/errors"; import { ppAsmShuffle } from "../../ast/ast-printer"; export function writeCastedExpression( - expression: AstExpression, + expression: A.AstExpression, to: TypeRef, ctx: WriterContext, ) { @@ -64,7 +55,7 @@ function unwrapExternal( } export function writeStatement( - f: AstStatement, + f: A.AstStatement, self: string | null, returns: TypeRef | null, ctx: WriterContext, @@ -103,7 +94,7 @@ export function writeStatement( } case "statement_let": { // Underscore name case - if (isWildcard(f.name)) { + if (A.isWildcard(f.name)) { ctx.append(`${writeExpression(f.expression, ctx)};`); return; } @@ -137,7 +128,7 @@ export function writeStatement( } case "statement_assign": { // Prepare lvalue - const lvaluePath = tryExtractPath(f.path); + const lvaluePath = A.tryExtractPath(f.path); if (lvaluePath === null) { // typechecker is supposed to catch this throwInternalCompilerError( @@ -165,7 +156,7 @@ export function writeStatement( return; } case "statement_augmentedassign": { - const lvaluePath = tryExtractPath(f.path); + const lvaluePath = A.tryExtractPath(f.path); if (lvaluePath === null) { // typechecker is supposed to catch this throwInternalCompilerError( @@ -230,7 +221,7 @@ export function writeStatement( const catchBlock = f.catchBlock; if (catchBlock !== undefined) { - if (isWildcard(catchBlock.catchName)) { + if (A.isWildcard(catchBlock.catchName)) { ctx.append(`} catch (_) {`); } else { ctx.append( @@ -250,7 +241,7 @@ export function writeStatement( return; } case "statement_foreach": { - const mapPath = tryExtractPath(f.map); + const mapPath = A.tryExtractPath(f.map); if (mapPath === null) { // typechecker is supposed to catch this throwInternalCompilerError( @@ -266,10 +257,10 @@ export function writeStatement( } const flag = freshIdentifier("flag"); - const key = isWildcard(f.keyName) + const key = A.isWildcard(f.keyName) ? freshIdentifier("underscore") : funcIdOf(f.keyName); - const value = isWildcard(f.valueName) + const value = A.isWildcard(f.valueName) ? freshIdentifier("underscore") : funcIdOf(f.valueName); @@ -481,7 +472,7 @@ export function writeStatement( const ty = getType(ctx.ctx, t.name); const ids = ty.fields.map((field) => { const id = f.identifiers.get(field.name); - return id === undefined || isWildcard(id[1]) + return id === undefined || A.isWildcard(id[1]) ? "_" : funcIdOf(id[1]); }); @@ -502,7 +493,7 @@ export function writeStatement( } function writeCondition( - f: AstCondition, + f: A.AstCondition, self: string | null, elseif: boolean, returns: TypeRef | null, @@ -564,7 +555,7 @@ export function writeFunction(f: FunctionDescription, ctx: WriterContext) { const fAst = f.ast; switch (fAst.kind) { case "native_function_decl": { - const name = idText(fAst.nativeName); + const name = A.idText(fAst.nativeName); if (f.isMutating && !ctx.isRendered(name)) { writeNonMutatingFunction( f, @@ -590,9 +581,11 @@ export function writeFunction(f: FunctionDescription, ctx: WriterContext) { ctx.context("stdlib"); } // we need to do some renames (prepending $ to identifiers) - const asmShuffleEscaped: AstAsmShuffle = { + const asmShuffleEscaped: A.AstAsmShuffle = { ...fAst.shuffle, - args: fAst.shuffle.args.map((id) => idOfText(funcIdOf(id))), + args: fAst.shuffle.args.map((id) => + A.idOfText(funcIdOf(id)), + ), }; ctx.asm( ppAsmShuffle(asmShuffleEscaped), diff --git a/src/grammar/prev/grammar.ts b/src/grammar/prev/grammar.ts index ad6dec8e6..4a9d2af26 100644 --- a/src/grammar/prev/grammar.ts +++ b/src/grammar/prev/grammar.ts @@ -1,23 +1,7 @@ import { Node, IterationNode, NonterminalNode } from "ohm-js"; import tactGrammar from "./grammar.ohm-bundle"; import { throwInternalCompilerError } from "../../error/errors"; -import { - AstAugmentedAssignOperation, - AstConstantAttribute, - AstContractAttribute, - AstExpression, - AstFunctionAttribute, - AstNode, - AstModule, - AstReceiverKind, - AstString, - AstType, - AstImport, - AstConstantDef, - AstNumberBase, - AstId, - FactoryAst, -} from "../../ast/ast"; +import * as A from "../../ast/ast"; import { ItemOrigin, SrcInfo } from "../src-info"; import { displayToString } from "../../error/display-to-string"; import { ParserErrors, parserErrorSchema } from "./parser-error"; @@ -26,7 +10,7 @@ import { getSrcInfoFromOhm } from "./src-info"; type Context = { origin: ItemOrigin | null; currentFile: string | null; - createNode: FactoryAst["createNode"] | null; + createNode: A.FactoryAst["createNode"] | null; errorTypes: ParserErrors | null; }; @@ -56,7 +40,7 @@ function createRef(s: Node): SrcInfo { return getSrcInfoFromOhm(s.source, context.currentFile, context.origin); } -const createNode: FactoryAst["createNode"] = (...args) => { +const createNode: A.FactoryAst["createNode"] = (...args) => { if (context.createNode === null) { throwInternalCompilerError("Parser context was not initialized"); } @@ -95,7 +79,7 @@ const checkAttributes = (kind: "constant" | "function") => ( isAbstract: boolean, - attributes: (AstConstantAttribute | AstFunctionAttribute)[], + attributes: (A.AstConstantAttribute | A.AstFunctionAttribute)[], loc: SrcInfo, ) => { const { duplicate, tooAbstract, notAbstract } = err()[kind]; @@ -120,7 +104,7 @@ const checkFunctionAttributes = checkAttributes("function"); const semantics = tactGrammar.createSemantics(); -semantics.addOperation("astOfModule", { +semantics.addOperation("astOfModule", { Module(imports, items) { return createNode({ kind: "module", @@ -130,9 +114,9 @@ semantics.addOperation("astOfModule", { }, }); -semantics.addOperation("astOfImport", { +semantics.addOperation("astOfImport", { Import(_importKwd, path, _semicolon) { - const pathAST = path.astOfExpression() as AstString; + const pathAST = path.astOfExpression() as A.AstString; if (pathAST.value.includes("\\")) { err().importWithBackslash()(createRef(path)); } @@ -144,13 +128,13 @@ semantics.addOperation("astOfImport", { }, }); -semantics.addOperation("astOfJustImports", { +semantics.addOperation("astOfJustImports", { JustImports(imports, _restOfInput) { return imports.children.map((item) => item.astOfImport()); }, }); -semantics.addOperation("astOfModuleItem", { +semantics.addOperation("astOfModuleItem", { PrimitiveTypeDecl(_primitive_kwd, typeId, _semicolon) { checkVariableName(typeId.sourceString, createRef(typeId)); return createNode({ @@ -265,7 +249,7 @@ semantics.addOperation("astOfModuleItem", { return fun.astOfItem(); }, ModuleConstant(constant) { - const astConstDef: AstConstantDef = constant.astOfItem(); + const astConstDef: A.AstConstantDef = constant.astOfItem(); if (astConstDef.attributes.length !== 0) { err().topLevelConstantWithAttribute()( astConstDef.attributes[0]!.loc, @@ -278,7 +262,7 @@ semantics.addOperation("astOfModuleItem", { // top-level (module-level), contract or trait items: // constant declarations/definitions, functions, receivers, // getters, etc. -semantics.addOperation("astOfItem", { +semantics.addOperation("astOfItem", { ConstantDefinition( constAttributes, _constKwd, @@ -291,7 +275,7 @@ semantics.addOperation("astOfItem", { ) { const attributes = constAttributes.children.map((a) => a.astOfConstAttribute(), - ) as AstConstantAttribute[]; + ) as A.AstConstantAttribute[]; checkConstAttributes(false, attributes, createRef(this)); return createNode({ kind: "constant_def", @@ -312,7 +296,7 @@ semantics.addOperation("astOfItem", { ) { const attributes = constAttributes.children.map((a) => a.astOfConstAttribute(), - ) as AstConstantAttribute[]; + ) as A.AstConstantAttribute[]; checkConstAttributes(true, attributes, createRef(this)); return createNode({ kind: "constant_decl", @@ -338,7 +322,7 @@ semantics.addOperation("astOfItem", { ) { const attributes = funAttributes.children.map((a) => a.astOfFunctionAttributes(), - ) as AstFunctionAttribute[]; + ) as A.AstFunctionAttribute[]; checkVariableName(funId.sourceString, createRef(funId)); checkFunctionAttributes(false, attributes, createRef(this)); return createNode({ @@ -370,7 +354,7 @@ semantics.addOperation("astOfItem", { }; const attributes = funAttributes.children.map((a) => a.astOfFunctionAttributes(), - ) as AstFunctionAttribute[]; + ) as A.AstFunctionAttribute[]; checkVariableName(funId.sourceString, createRef(funId)); checkFunctionAttributes(false, attributes, createRef(this)); return createNode({ @@ -397,7 +381,7 @@ semantics.addOperation("astOfItem", { ) { const attributes = funAttributes.children.map((a) => a.astOfFunctionAttributes(), - ) as AstFunctionAttribute[]; + ) as A.AstFunctionAttribute[]; checkVariableName(funId.sourceString, createRef(funId)); checkFunctionAttributes(true, attributes, createRef(this)); return createNode({ @@ -427,7 +411,7 @@ semantics.addOperation("astOfItem", { _rbrace, ) { const optParam = optParameter.children[0] as Node | undefined; - const selector: AstReceiverKind = optParam + const selector: A.AstReceiverKind = optParam ? { kind: "internal-simple", param: optParam.astOfDeclaration(), @@ -485,7 +469,7 @@ semantics.addOperation("astOfItem", { _rbrace, ) { const optParam = optParameter.children[0] as Node | undefined; - const selector: AstReceiverKind = optParam + const selector: A.AstReceiverKind = optParam ? { kind: "external-simple", param: optParam.astOfDeclaration(), @@ -594,7 +578,7 @@ semantics.addOperation("astOfAsmInstruction", { }, }); -semantics.addOperation("astOfFunctionAttributes", { +semantics.addOperation("astOfFunctionAttributes", { FunctionAttribute_getter(_getKwd, _optLparen, optMethodId, _optRparen) { return { kind: "function_attribute", @@ -647,7 +631,7 @@ semantics.addOperation("astOfFunctionAttributes", { }, }); -semantics.addOperation<{ args: AstNode[]; ret: AstNode[] }>( +semantics.addOperation<{ args: A.AstNode[]; ret: A.AstNode[] }>( "astsOfAsmShuffle", { AsmShuffle(_lparen, argsShuffle, _optArrow, optRetShuffle, _rparen) { @@ -662,7 +646,7 @@ semantics.addOperation<{ args: AstNode[]; ret: AstNode[] }>( }, ); -semantics.addOperation("astOfConstAttribute", { +semantics.addOperation("astOfConstAttribute", { ConstantAttribute_override(_) { return { type: "override", loc: createRef(this) }; }, @@ -674,7 +658,7 @@ semantics.addOperation("astOfConstAttribute", { }, }); -semantics.addOperation("astsOfList", { +semantics.addOperation("astsOfList", { InheritedTraits(traits, _optTrailingComma) { return traits .asIteration() @@ -705,7 +689,7 @@ semantics.addOperation("astsOfList", { }, }); -semantics.addOperation("astOfContractAttributes", { +semantics.addOperation("astOfContractAttributes", { ContractAttribute_interface(_interface, _lparen, interfaceName, _rparen) { return { type: "interface", @@ -715,7 +699,7 @@ semantics.addOperation("astOfContractAttributes", { }, }); -semantics.addOperation("astOfDeclaration", { +semantics.addOperation("astOfDeclaration", { FieldDecl( id, _colon, @@ -728,7 +712,7 @@ semantics.addOperation("astOfDeclaration", { return createNode({ kind: "field_decl", name: id.astOfExpression(), - type: type.astOfType() as AstType, + type: type.astOfType() as A.AstType, as: unwrapOptNode(optStorageType, (t) => t.astOfExpression()), initializer: unwrapOptNode(optInitializer, (e) => e.astOfExpression(), @@ -764,7 +748,7 @@ semantics.addOperation("astOfDeclaration", { }); // Statements -semantics.addOperation("astOfStatement", { +semantics.addOperation("astOfStatement", { // TODO: process StatementBlock StatementLet( @@ -816,7 +800,7 @@ semantics.addOperation("astOfStatement", { loc: createRef(this), }); } else { - let op: AstAugmentedAssignOperation; + let op: A.AstAugmentedAssignOperation; switch (operator.sourceString) { case "+=": op = "+"; @@ -1050,7 +1034,7 @@ semantics.addOperation("astOfStatement", { destructItem.name, ]); return map; - }, new Map()), + }, new Map()), ignoreUnspecifiedFields: endOfIdentifiers.astOfExpression().ignoreUnspecifiedFields, expression: expression.astOfExpression(), @@ -1066,7 +1050,7 @@ semantics.addOperation("astOfStatement", { }, }); -semantics.addOperation("astOfType", { +semantics.addOperation("astOfType", { typeId(firstTactTypeIdCharacter, restOfTactTypeId) { return createNode({ kind: "type_id", @@ -1125,7 +1109,7 @@ function bigintOfIntLiteral(litString: NonterminalNode): bigint { return BigInt(litString.sourceString.replaceAll("_", "")); } -function baseOfIntLiteral(node: NonterminalNode): AstNumberBase { +function baseOfIntLiteral(node: NonterminalNode): A.AstNumberBase { const basePrefix = node.sourceString.slice(0, 2).toLowerCase(); switch (basePrefix) { case "0x": @@ -1139,7 +1123,7 @@ function baseOfIntLiteral(node: NonterminalNode): AstNumberBase { } } -function astOfNumber(node: Node): AstNode { +function astOfNumber(node: Node): A.AstNode { return createNode({ kind: "number", base: baseOfIntLiteral(node), @@ -1149,7 +1133,7 @@ function astOfNumber(node: Node): AstNode { } // Expressions -semantics.addOperation("astOfExpression", { +semantics.addOperation("astOfExpression", { // Literals integerLiteral(_) { // Parses dec, hex, and bin numbers @@ -1508,10 +1492,10 @@ semantics.addOperation("astOfExpression", { /** * @deprecated */ -export const getParser = (ast: FactoryAst) => { +export const getParser = (ast: A.FactoryAst) => { const errorTypes = parserErrorSchema(displayToString); - function parse(src: string, path: string, origin: ItemOrigin): AstModule { + function parse(src: string, path: string, origin: ItemOrigin): A.AstModule { return withContext( { currentFile: path, @@ -1529,7 +1513,7 @@ export const getParser = (ast: FactoryAst) => { ); } - function parseExpression(sourceCode: string): AstExpression { + function parseExpression(sourceCode: string): A.AstExpression { return withContext( { currentFile: null, @@ -1551,7 +1535,7 @@ export const getParser = (ast: FactoryAst) => { src: string, path: string, origin: ItemOrigin, - ): AstImport[] { + ): A.AstImport[] { return withContext( { currentFile: path, diff --git a/src/optimizer/interpreter.ts b/src/optimizer/interpreter.ts index 12dcbf42d..c0ab3bb1d 100644 --- a/src/optimizer/interpreter.ts +++ b/src/optimizer/interpreter.ts @@ -1,6 +1,7 @@ import { Address, beginCell, BitString, Cell, toNano } from "@ton/core"; import { paddedBufferToBits } from "@ton/core/dist/boc/utils/paddedBits"; import * as crc32 from "crc-32"; +import * as A from "../ast/ast"; import { evalConstantExpression } from "./constEval"; import { CompilerContext } from "../context/context"; import { @@ -10,61 +11,6 @@ import { throwConstEvalError, throwInternalCompilerError, } from "../error/errors"; -import { - AstAddress, - AstBinaryOperation, - AstBoolean, - AstCell, - AstCommentValue, - AstCondition, - AstConditional, - AstConstantDef, - AstContract, - AstExpression, - AstFieldAccess, - AstFunctionDef, - AstId, - AstInitOf, - AstLiteral, - AstMessageDecl, - AstMethodCall, - AstModuleItem, - AstNativeFunctionDecl, - AstNull, - AstNumber, - AstOpBinary, - AstOpUnary, - AstPrimitiveTypeDecl, - AstSimplifiedString, - AstSlice, - FactoryAst, - AstStatement, - AstStatementAssign, - AstStatementAugmentedAssign, - AstStatementDestruct, - AstStatementExpression, - AstStatementForEach, - AstStatementLet, - AstStatementRepeat, - AstStatementReturn, - AstStatementTry, - AstStatementUntil, - AstStatementWhile, - AstStaticCall, - AstString, - AstStructDecl, - AstStructFieldValue, - AstStructInstance, - AstStructValue, - AstTrait, - AstUnaryOperation, - eqExpressions, - eqNames, - getAstFactory, - idText, - isSelfId, - AstStatementBlock, -} from "../ast/ast"; import { AstUtil, divFloor, getAstUtil, modFloor } from "../ast/util"; import { getStaticConstant, @@ -115,10 +61,10 @@ function throwErrorConstEval(msg: string, source: SrcInfo): never { ); } type EvalResult = - | { kind: "ok"; value: AstLiteral } + | { kind: "ok"; value: A.AstLiteral } | { kind: "error"; message: string }; -export function ensureInt(val: AstExpression): AstNumber { +export function ensureInt(val: A.AstExpression): A.AstNumber { if (val.kind !== "number") { throwErrorConstEval( `integer expected, but got expression of kind '${val.kind}'`, @@ -135,7 +81,7 @@ export function ensureInt(val: AstExpression): AstNumber { } } -function ensureArgumentForEquality(val: AstLiteral): AstLiteral { +function ensureArgumentForEquality(val: A.AstLiteral): A.AstLiteral { switch (val.kind) { case "address": case "boolean": @@ -157,7 +103,7 @@ function ensureArgumentForEquality(val: AstLiteral): AstLiteral { } } -function ensureRepeatInt(val: AstExpression): AstNumber { +function ensureRepeatInt(val: A.AstExpression): A.AstNumber { if (val.kind !== "number") { throwErrorConstEval( `integer expected, but got expression of kind '${val.kind}'`, @@ -174,7 +120,7 @@ function ensureRepeatInt(val: AstExpression): AstNumber { } } -export function ensureBoolean(val: AstExpression): AstBoolean { +export function ensureBoolean(val: A.AstExpression): A.AstBoolean { if (val.kind !== "boolean") { throwErrorConstEval( `boolean expected, but got expression of kind '${val.kind}'`, @@ -184,7 +130,7 @@ export function ensureBoolean(val: AstExpression): AstBoolean { return val; } -export function ensureString(val: AstExpression): AstString { +export function ensureString(val: A.AstExpression): A.AstString { if (val.kind !== "string") { throwErrorConstEval( `string expected, but got expression of kind '${val.kind}'`, @@ -195,8 +141,8 @@ export function ensureString(val: AstExpression): AstString { } export function ensureSimplifiedString( - val: AstExpression, -): AstSimplifiedString { + val: A.AstExpression, +): A.AstSimplifiedString { if (val.kind !== "simplified_string") { throwErrorConstEval( `simplified string expected, but got expression of kind '${val.kind}'`, @@ -206,7 +152,11 @@ export function ensureSimplifiedString( return val; } -function ensureFunArity(arity: number, args: AstExpression[], source: SrcInfo) { +function ensureFunArity( + arity: number, + args: A.AstExpression[], + source: SrcInfo, +) { if (args.length !== arity) { throwErrorConstEval( `function expects ${arity} argument(s), but got ${args.length}`, @@ -217,7 +167,7 @@ function ensureFunArity(arity: number, args: AstExpression[], source: SrcInfo) { function ensureMethodArity( arity: number, - args: AstExpression[], + args: A.AstExpression[], source: SrcInfo, ) { if (args.length !== arity) { @@ -229,11 +179,11 @@ function ensureMethodArity( } export function evalUnaryOp( - op: AstUnaryOperation, - valOperand: AstLiteral, + op: A.AstUnaryOperation, + valOperand: A.AstLiteral, source: SrcInfo, util: AstUtil, -): AstLiteral { +): A.AstLiteral { switch (op) { case "+": return ensureInt(valOperand); @@ -266,12 +216,12 @@ export function evalUnaryOp( } export function evalBinaryOp( - op: AstBinaryOperation, - valLeft: AstLiteral, - valRightContinuation: () => AstLiteral, // It needs to be a continuation, because some binary operators short-circuit + op: A.AstBinaryOperation, + valLeft: A.AstLiteral, + valRightContinuation: () => A.AstLiteral, // It needs to be a continuation, because some binary operators short-circuit source: SrcInfo, util: AstUtil, -): AstLiteral { +): A.AstLiteral { switch (op) { case "+": { const astLeft = ensureInt(valLeft); @@ -425,7 +375,7 @@ export function evalBinaryOp( const valR_ = ensureArgumentForEquality(valR); // Changed to equality testing (instead of ===) because cells, slices, address are equal by hashing - const result = eqExpressions(valLeft_, valR_); + const result = A.eqExpressions(valLeft_, valR_); return util.makeBooleanLiteral(result, source); } case "!=": { @@ -447,7 +397,7 @@ export function evalBinaryOp( const valR_ = ensureArgumentForEquality(valR); // Changed to equality testing (instead of ===) because cells, slices are equal by hashing - const result = !eqExpressions(valLeft_, valR_); + const result = !A.eqExpressions(valLeft_, valR_); return util.makeBooleanLiteral(result, source); } case "&&": { @@ -518,14 +468,14 @@ export function interpretEscapeSequences( } class ReturnSignal extends Error { - private value?: AstLiteral; + private value?: A.AstLiteral; - constructor(value?: AstLiteral) { + constructor(value?: A.AstLiteral) { super(); this.value = value; } - public getValue(): AstLiteral | undefined { + public getValue(): A.AstLiteral | undefined { return this.value; } } @@ -540,7 +490,7 @@ export type InterpreterConfig = { const WILDCARD_NAME: string = "_"; -type Environment = { values: Map; parent?: Environment }; +type Environment = { values: Map; parent?: Environment }; class EnvironmentStack { private currentEnv: Environment; @@ -549,7 +499,9 @@ class EnvironmentStack { this.currentEnv = { values: new Map() }; } - private findBindingMap(name: string): Map | undefined { + private findBindingMap( + name: string, + ): Map | undefined { let env: Environment | undefined = this.currentEnv; while (env !== undefined) { if (env.values.has(name)) { @@ -607,7 +559,7 @@ class EnvironmentStack { so that the return at line 5 (now in the environment a = 3) will produce 3 * 2 = 6, and so on. */ - public setNewBinding(name: string, val: AstLiteral) { + public setNewBinding(name: string, val: A.AstLiteral) { if (name !== WILDCARD_NAME) { this.currentEnv.values.set(name, val); } @@ -620,7 +572,7 @@ class EnvironmentStack { to "val". If it does not find "name", the stack is unchanged. As a special case, name "_" is always ignored. */ - public updateBinding(name: string, val: AstLiteral) { + public updateBinding(name: string, val: A.AstLiteral) { if (name !== WILDCARD_NAME) { const bindings = this.findBindingMap(name); if (bindings !== undefined) { @@ -636,7 +588,7 @@ class EnvironmentStack { If it does not find "name", it returns undefined. As a special case, name "_" always returns undefined. */ - public getBinding(name: string): AstLiteral | undefined { + public getBinding(name: string): A.AstLiteral | undefined { if (name === WILDCARD_NAME) { return undefined; } @@ -664,7 +616,7 @@ class EnvironmentStack { */ public executeInNewEnvironment( code: () => T, - initialBindings: { names: string[]; values: AstLiteral[] } = { + initialBindings: { names: string[]; values: A.AstLiteral[] } = { names: [], values: [], }, @@ -689,7 +641,7 @@ class EnvironmentStack { export function parseAndEvalExpression( sourceCode: string, - ast: FactoryAst = getAstFactory(), + ast: A.FactoryAst = A.getAstFactory(), parser: Parser = getParser(ast, defaultParser), util: AstUtil = getAstUtil(ast), ): EvalResult { @@ -772,7 +724,7 @@ export class Interpreter { this.util = util; } - public interpretModuleItem(ast: AstModuleItem): void { + public interpretModuleItem(ast: A.AstModuleItem): void { switch (ast.kind) { case "constant_def": this.interpretConstantDef(ast); @@ -807,63 +759,63 @@ export class Interpreter { } } - public interpretConstantDef(ast: AstConstantDef) { + public interpretConstantDef(ast: A.AstConstantDef) { throwNonFatalErrorConstEval( "Constant definitions are currently not supported.", ast.loc, ); } - public interpretFunctionDef(ast: AstFunctionDef) { + public interpretFunctionDef(ast: A.AstFunctionDef) { throwNonFatalErrorConstEval( "Function definitions are currently not supported.", ast.loc, ); } - public interpretStructDecl(ast: AstStructDecl) { + public interpretStructDecl(ast: A.AstStructDecl) { throwNonFatalErrorConstEval( "Struct declarations are currently not supported.", ast.loc, ); } - public interpretMessageDecl(ast: AstMessageDecl) { + public interpretMessageDecl(ast: A.AstMessageDecl) { throwNonFatalErrorConstEval( "Message declarations are currently not supported.", ast.loc, ); } - public interpretPrimitiveTypeDecl(ast: AstPrimitiveTypeDecl) { + public interpretPrimitiveTypeDecl(ast: A.AstPrimitiveTypeDecl) { throwNonFatalErrorConstEval( "Primitive type declarations are currently not supported.", ast.loc, ); } - public interpretFunctionDecl(ast: AstNativeFunctionDecl) { + public interpretFunctionDecl(ast: A.AstNativeFunctionDecl) { throwNonFatalErrorConstEval( "Native function declarations are currently not supported.", ast.loc, ); } - public interpretContract(ast: AstContract) { + public interpretContract(ast: A.AstContract) { throwNonFatalErrorConstEval( "Contract declarations are currently not supported.", ast.loc, ); } - public interpretTrait(ast: AstTrait) { + public interpretTrait(ast: A.AstTrait) { throwNonFatalErrorConstEval( "Trait declarations are currently not supported.", ast.loc, ); } - public interpretExpression(ast: AstExpression): AstLiteral { + public interpretExpression(ast: A.AstExpression): A.AstLiteral { switch (ast.kind) { case "id": return this.interpretName(ast); @@ -908,9 +860,9 @@ export class Interpreter { } } - public interpretName(ast: AstId): AstLiteral { - if (hasStaticConstant(this.context, idText(ast))) { - const constant = getStaticConstant(this.context, idText(ast)); + public interpretName(ast: A.AstId): A.AstLiteral { + if (hasStaticConstant(this.context, A.idText(ast))) { + const constant = getStaticConstant(this.context, A.idText(ast)); if (constant.value !== undefined) { return constant.value; } else { @@ -920,15 +872,15 @@ export class Interpreter { ); } } - const variableBinding = this.envStack.getBinding(idText(ast)); + const variableBinding = this.envStack.getBinding(A.idText(ast)); if (variableBinding !== undefined) { return variableBinding; } throwNonFatalErrorConstEval("cannot evaluate a variable", ast.loc); } - public interpretMethodCall(ast: AstMethodCall): AstLiteral { - switch (idText(ast.method)) { + public interpretMethodCall(ast: A.AstMethodCall): A.AstLiteral { + switch (A.idText(ast.method)) { case "asComment": { ensureMethodArity(0, ast.args, ast.loc); const comment = ensureSimplifiedString( @@ -944,55 +896,55 @@ export class Interpreter { } } - public interpretInitOf(ast: AstInitOf): AstLiteral { + public interpretInitOf(ast: A.AstInitOf): A.AstLiteral { throwNonFatalErrorConstEval( "initOf is not supported at this moment", ast.loc, ); } - public interpretNull(ast: AstNull): AstNull { + public interpretNull(ast: A.AstNull): A.AstNull { return ast; } - public interpretBoolean(ast: AstBoolean): AstBoolean { + public interpretBoolean(ast: A.AstBoolean): A.AstBoolean { return ast; } - public interpretNumber(ast: AstNumber): AstNumber { + public interpretNumber(ast: A.AstNumber): A.AstNumber { return ensureInt(ast); } - public interpretString(ast: AstString): AstSimplifiedString { + public interpretString(ast: A.AstString): A.AstSimplifiedString { return this.util.makeSimplifiedStringLiteral( interpretEscapeSequences(ast.value, ast.loc), ast.loc, ); } - public interpretCommentValue(ast: AstCommentValue): AstCommentValue { + public interpretCommentValue(ast: A.AstCommentValue): A.AstCommentValue { return ast; } public interpretSimplifiedString( - ast: AstSimplifiedString, - ): AstSimplifiedString { + ast: A.AstSimplifiedString, + ): A.AstSimplifiedString { return ast; } - public interpretAddress(ast: AstAddress): AstAddress { + public interpretAddress(ast: A.AstAddress): A.AstAddress { return ast; } - public interpretCell(ast: AstCell): AstCell { + public interpretCell(ast: A.AstCell): A.AstCell { return ast; } - public interpretSlice(ast: AstSlice): AstSlice { + public interpretSlice(ast: A.AstSlice): A.AstSlice { return ast; } - public interpretUnaryOp(ast: AstOpUnary): AstLiteral { + public interpretUnaryOp(ast: A.AstOpUnary): A.AstLiteral { // Tact grammar does not have negative integer literals, // so in order to avoid errors for `-115792089237316195423570985008687907853269984665640564039457584007913129639936` // which is `-(2**256)` we need to have a special case for it @@ -1009,7 +961,7 @@ export class Interpreter { return evalUnaryOp(ast.op, valOperand, ast.loc, this.util); } - public interpretBinaryOp(ast: AstOpBinary): AstLiteral { + public interpretBinaryOp(ast: A.AstOpBinary): A.AstLiteral { const valLeft = this.interpretExpression(ast.left); const valRightContinuation = () => this.interpretExpression(ast.right); @@ -1022,7 +974,7 @@ export class Interpreter { ); } - public interpretConditional(ast: AstConditional): AstLiteral { + public interpretConditional(ast: A.AstConditional): A.AstLiteral { // here we rely on the typechecker that both branches have the same type const valCond = ensureBoolean(this.interpretExpression(ast.condition)); if (valCond.value) { @@ -1032,13 +984,13 @@ export class Interpreter { } } - public interpretStructInstance(ast: AstStructInstance): AstStructValue { + public interpretStructInstance(ast: A.AstStructInstance): A.AstStructValue { const structTy = getType(this.context, ast.type); // initialize the resulting struct value with // the default values for fields with initializers // or null for uninitialized optional fields - const resultMap: Map = new Map(); + const resultMap: Map = new Map(); for (const field of structTy.fields) { if (typeof field.default !== "undefined") { @@ -1056,17 +1008,17 @@ export class Interpreter { // this will override default fields set above for (const fieldWithInit of ast.args) { const v = this.interpretExpression(fieldWithInit.initializer); - resultMap.set(idText(fieldWithInit.field), v); + resultMap.set(A.idText(fieldWithInit.field), v); } // Create the field entries for the StructValue // The previous loop ensures that the map resultMap cannot return // undefined for each of the fields in ast.args - const structValueFields: AstStructFieldValue[] = []; + const structValueFields: A.AstStructFieldValue[] = []; for (const [fieldName, fieldValue] of resultMap) { // Find the source code declaration, if existent const sourceField = ast.args.find( - (f) => idText(f.field) === fieldName, + (f) => A.idText(f.field) === fieldName, ); if (typeof sourceField !== "undefined") { structValueFields.push( @@ -1091,19 +1043,19 @@ export class Interpreter { return this.util.makeStructValue(structValueFields, ast.type, ast.loc); } - public interpretStructValue(ast: AstStructValue): AstStructValue { + public interpretStructValue(ast: A.AstStructValue): A.AstStructValue { // Struct values are already simplified to their simplest form return ast; } - public interpretFieldAccess(ast: AstFieldAccess): AstLiteral { + public interpretFieldAccess(ast: A.AstFieldAccess): A.AstLiteral { // special case for contract/trait constant accesses via `self.constant` // interpret "self" as a contract/trait access only if "self" // is not already assigned in the environment (this would mean // we are executing inside an extends function) if ( ast.aggregate.kind === "id" && - isSelfId(ast.aggregate) && + A.isSelfId(ast.aggregate) && !this.envStack.selfInEnvironment() ) { const selfTypeRef = getExpType(this.context, ast.aggregate); @@ -1114,7 +1066,7 @@ export class Interpreter { ); const foundContractConst = contractTypeDescription.constants.find((constId) => - eqNames(ast.field, constId.name), + A.eqNames(ast.field, constId.name), ); if (foundContractConst === undefined) { // not a constant, e.g. `self.storageVariable` @@ -1141,7 +1093,7 @@ export class Interpreter { ); } const field = valStruct.args.find( - (f) => idText(ast.field) === idText(f.field), + (f) => A.idText(ast.field) === A.idText(f.field), ); if (typeof field !== "undefined") { return field.initializer; @@ -1154,8 +1106,8 @@ export class Interpreter { } } - public interpretStaticCall(ast: AstStaticCall): AstLiteral { - switch (idText(ast.function)) { + public interpretStaticCall(ast: A.AstStaticCall): A.AstLiteral { + switch (A.idText(ast.function)) { case "ton": { ensureFunArity(1, ast.args, ast.loc); const tons = ensureSimplifiedString( @@ -1435,10 +1387,10 @@ export class Interpreter { ); } default: - if (hasStaticFunction(this.context, idText(ast.function))) { + if (hasStaticFunction(this.context, A.idText(ast.function))) { const functionDescription = getStaticFunction( this.context, - idText(ast.function), + A.idText(ast.function), ); switch (functionDescription.ast.kind) { case "function_def": @@ -1484,15 +1436,15 @@ export class Interpreter { } private evalStaticFunction( - functionCode: AstFunctionDef, - args: AstExpression[], + functionCode: A.AstFunctionDef, + args: A.AstExpression[], returns: TypeRef, - ): AstLiteral { + ): A.AstLiteral { // Evaluate the arguments in the current environment const argValues = args.map(this.interpretExpression, this); // Extract the parameter names const paramNames = functionCode.params.map((param) => - idText(param.name), + A.idText(param.name), ); // Check parameter names do not shadow constants if ( @@ -1501,7 +1453,7 @@ export class Interpreter { ) ) { throwInternalCompilerError( - `some parameter of function ${idText(functionCode.name)} shadows a constant with the same name`, + `some parameter of function ${A.idText(functionCode.name)} shadows a constant with the same name`, functionCode.loc, ); } @@ -1534,7 +1486,7 @@ export class Interpreter { // function is not void if (returns.kind !== "void") { throwInternalCompilerError( - `function ${idText(functionCode.name)} must return a value`, + `function ${A.idText(functionCode.name)} must return a value`, functionCode.loc, ); } else { @@ -1548,7 +1500,7 @@ export class Interpreter { ); } - public interpretStatement(ast: AstStatement): void { + public interpretStatement(ast: A.AstStatement): void { switch (ast.kind) { case "statement_let": this.interpretLetStatement(ast); @@ -1592,24 +1544,24 @@ export class Interpreter { } } - public interpretLetStatement(ast: AstStatementLet) { - if (hasStaticConstant(this.context, idText(ast.name))) { + public interpretLetStatement(ast: A.AstStatementLet) { + if (hasStaticConstant(this.context, A.idText(ast.name))) { // Attempt of shadowing a constant in a let declaration throwInternalCompilerError( - `declaration of ${idText(ast.name)} shadows a constant with the same name`, + `declaration of ${A.idText(ast.name)} shadows a constant with the same name`, ast.loc, ); } const val = this.interpretExpression(ast.expression); - this.envStack.setNewBinding(idText(ast.name), val); + this.envStack.setNewBinding(A.idText(ast.name), val); } - public interpretDestructStatement(ast: AstStatementDestruct) { + public interpretDestructStatement(ast: A.AstStatementDestruct) { for (const [_, name] of ast.identifiers.values()) { - if (hasStaticConstant(this.context, idText(name))) { + if (hasStaticConstant(this.context, A.idText(name))) { // Attempt of shadowing a constant in a destructuring declaration throwInternalCompilerError( - `declaration of ${idText(name)} shadows a constant with the same name`, + `declaration of ${A.idText(name)} shadows a constant with the same name`, ast.loc, ); } @@ -1625,14 +1577,14 @@ export class Interpreter { } // Keep a map of the fields in val for lookup - const valAsMap: Map = new Map(); - val.args.forEach((f) => valAsMap.set(idText(f.field), f.initializer)); + const valAsMap: Map = new Map(); + val.args.forEach((f) => valAsMap.set(A.idText(f.field), f.initializer)); for (const [field, name] of ast.identifiers.values()) { if (name.text === "_") { continue; } - const v = valAsMap.get(idText(field)); + const v = valAsMap.get(A.idText(field)); if (typeof v === "undefined") { throwErrorConstEval( `destructuring assignment expected field ${idTextErr( @@ -1641,14 +1593,14 @@ export class Interpreter { ast.loc, ); } - this.envStack.setNewBinding(idText(name), v); + this.envStack.setNewBinding(A.idText(name), v); } } - public interpretAssignStatement(ast: AstStatementAssign) { + public interpretAssignStatement(ast: A.AstStatementAssign) { if (ast.path.kind === "id") { const val = this.interpretExpression(ast.expression); - this.envStack.updateBinding(idText(ast.path), val); + this.envStack.updateBinding(A.idText(ast.path), val); } else { throwNonFatalErrorConstEval( "only identifiers are currently supported as path expressions", @@ -1657,10 +1609,14 @@ export class Interpreter { } } - public interpretAugmentedAssignStatement(ast: AstStatementAugmentedAssign) { + public interpretAugmentedAssignStatement( + ast: A.AstStatementAugmentedAssign, + ) { if (ast.path.kind === "id") { const updateVal = () => this.interpretExpression(ast.expression); - const currentPathValue = this.envStack.getBinding(idText(ast.path)); + const currentPathValue = this.envStack.getBinding( + A.idText(ast.path), + ); if (currentPathValue === undefined) { throwNonFatalErrorConstEval( "undeclared identifier", @@ -1674,7 +1630,7 @@ export class Interpreter { ast.loc, this.util, ); - this.envStack.updateBinding(idText(ast.path), newVal); + this.envStack.updateBinding(A.idText(ast.path), newVal); } else { throwNonFatalErrorConstEval( "only identifiers are currently supported as path expressions", @@ -1683,7 +1639,7 @@ export class Interpreter { } } - public interpretConditionStatement(ast: AstCondition) { + public interpretConditionStatement(ast: A.AstCondition) { const condition = ensureBoolean( this.interpretExpression(ast.condition), ); @@ -1698,15 +1654,15 @@ export class Interpreter { } } - public interpretExpressionStatement(ast: AstStatementExpression) { + public interpretExpressionStatement(ast: A.AstStatementExpression) { this.interpretExpression(ast.expression); } - public interpretForEachStatement(ast: AstStatementForEach) { + public interpretForEachStatement(ast: A.AstStatementForEach) { throwNonFatalErrorConstEval("foreach currently not supported", ast.loc); } - public interpretRepeatStatement(ast: AstStatementRepeat) { + public interpretRepeatStatement(ast: A.AstStatementRepeat) { const iterations = ensureRepeatInt( this.interpretExpression(ast.iterations), ); @@ -1725,7 +1681,7 @@ export class Interpreter { } } - public interpretReturnStatement(ast: AstStatementReturn) { + public interpretReturnStatement(ast: A.AstStatementReturn) { if (ast.expression !== null) { const val = this.interpretExpression(ast.expression); throw new ReturnSignal(val); @@ -1734,14 +1690,14 @@ export class Interpreter { } } - public interpretTryStatement(ast: AstStatementTry) { + public interpretTryStatement(ast: A.AstStatementTry) { throwNonFatalErrorConstEval( "try statements currently not supported", ast.loc, ); } - public interpretUntilStatement(ast: AstStatementUntil) { + public interpretUntilStatement(ast: A.AstStatementUntil) { let condition; let iterCount = 0; // We can create a single environment for all the iterations in the loop @@ -1770,7 +1726,7 @@ export class Interpreter { }); } - public interpretWhileStatement(ast: AstStatementWhile) { + public interpretWhileStatement(ast: A.AstStatementWhile) { let condition; let iterCount = 0; // We can create a single environment for all the iterations in the loop @@ -1801,7 +1757,7 @@ export class Interpreter { }); } - public interpretBlockStatement(ast: AstStatementBlock) { + public interpretBlockStatement(ast: A.AstStatementBlock) { this.envStack.executeInNewEnvironment(() => { ast.statements.forEach(this.interpretStatement, this); }); diff --git a/src/optimizer/test/partial-eval.spec.ts b/src/optimizer/test/partial-eval.spec.ts index 81c4004d9..2601a249b 100644 --- a/src/optimizer/test/partial-eval.spec.ts +++ b/src/optimizer/test/partial-eval.spec.ts @@ -1,10 +1,4 @@ -import { - AstExpression, - FactoryAst, - eqExpressions, - getAstFactory, - isLiteral, -} from "../../ast/ast"; +import * as A from "../../ast/ast"; import { AstUtil, getAstUtil } from "../../ast/util"; import { getOptimizer } from "../constEval"; import { CompilerContext } from "../../context/context"; @@ -316,7 +310,7 @@ const booleanExpressions = [ function testExpression(original: string, simplified: string) { it(`should simplify ${original} to ${simplified}`, () => { - const ast = getAstFactory(); + const ast = A.getAstFactory(); const { parseExpression } = getParser(ast, defaultParser); const util = getAstUtil(ast); const { partiallyEvalExpression } = getOptimizer(util); @@ -325,7 +319,7 @@ function testExpression(original: string, simplified: string) { new CompilerContext(), ); const simplifiedValue = dummyEval(parseExpression(simplified), ast); - const areMatching = eqExpressions(originalValue, simplifiedValue); + const areMatching = A.eqExpressions(originalValue, simplifiedValue); expect(areMatching).toBe(true); }); } @@ -336,13 +330,13 @@ function testExpressionWithOptimizer( optimizer: ExpressionTransformer, ) { it(`should simplify ${original} to ${simplified}`, () => { - const ast = getAstFactory(); + const ast = A.getAstFactory(); const { parseExpression } = getParser(ast, defaultParser); const originalValue = optimizer.applyRules( dummyEval(parseExpression(original), ast), ); const simplifiedValue = dummyEval(parseExpression(simplified), ast); - const areMatching = eqExpressions(originalValue, simplifiedValue); + const areMatching = A.eqExpressions(originalValue, simplifiedValue); expect(areMatching).toBe(true); }); } @@ -352,10 +346,13 @@ function testExpressionWithOptimizer( // The reason for doing this is that the partial evaluator will actually simplify constant // expressions. So, when comparing for equality of expressions, we also need to simplify // constant expressions. -function dummyEval(ast: AstExpression, astFactory: FactoryAst): AstExpression { +function dummyEval( + ast: A.AstExpression, + astFactory: A.FactoryAst, +): A.AstExpression { const cloneNode = astFactory.cloneNode; const util = getAstUtil(astFactory); - const recurse = (ast: AstExpression): AstExpression => { + const recurse = (ast: A.AstExpression): A.AstExpression => { switch (ast.kind) { case "null": return ast; @@ -393,7 +390,7 @@ function dummyEval(ast: AstExpression, astFactory: FactoryAst): AstExpression { case "op_unary": { const newNode = cloneNode(ast); newNode.operand = recurse(ast.operand); - if (isLiteral(newNode.operand)) { + if (A.isLiteral(newNode.operand)) { return evalUnaryOp(ast.op, newNode.operand, ast.loc, util); } return newNode; @@ -402,7 +399,7 @@ function dummyEval(ast: AstExpression, astFactory: FactoryAst): AstExpression { const newNode = cloneNode(ast); newNode.left = recurse(ast.left); newNode.right = recurse(ast.right); - if (isLiteral(newNode.left) && isLiteral(newNode.right)) { + if (A.isLiteral(newNode.left) && A.isLiteral(newNode.right)) { const valR = newNode.right; return evalBinaryOp( ast.op, @@ -452,13 +449,13 @@ class ParameterizableDummyOptimizer implements ExpressionTransformer { public util: AstUtil; - constructor(rules: Rule[], Ast: FactoryAst) { + constructor(rules: Rule[], Ast: A.FactoryAst) { this.util = getAstUtil(Ast); this.rules = rules; } - public applyRules = (ast: AstExpression): AstExpression => { + public applyRules = (ast: A.AstExpression): A.AstExpression => { return this.rules.reduce( (prev, rule) => rule.applyRule(prev, this), ast, @@ -482,7 +479,7 @@ describe("partial-evaluator", () => { // uses the associative rule 3. const optimizer = new ParameterizableDummyOptimizer( [new AssociativeRule3()], - getAstFactory(), + A.getAstFactory(), ); testExpressionWithOptimizer(test.original, test.simplified, optimizer); diff --git a/src/types/resolveABITypeRef.ts b/src/types/resolveABITypeRef.ts index c0773821b..193b143eb 100644 --- a/src/types/resolveABITypeRef.ts +++ b/src/types/resolveABITypeRef.ts @@ -1,18 +1,5 @@ import { ABITypeRef } from "@ton/core"; -import { - AstFieldDecl, - AstTypeId, - eqNames, - idText, - isAddress, - isBool, - isBuilder, - isCell, - isInt, - isSlice, - isString, - isStringBuilder, -} from "../ast/ast"; +import * as A from "../ast/ast"; import { idTextErr, throwCompilationError, @@ -76,7 +63,7 @@ const builderFormats: FormatDef = { remaining: { type: "builder", format: "remainder" }, }; -export function resolveABIType(src: AstFieldDecl): ABITypeRef { +export function resolveABIType(src: A.AstFieldDecl): ABITypeRef { if ( src.type.kind === "type_id" || (src.type.kind === "optional_type" && @@ -86,7 +73,7 @@ export function resolveABIType(src: AstFieldDecl): ABITypeRef { // Primitive types // - const typeId: AstTypeId = + const typeId: A.AstTypeId = src.type.kind === "type_id" ? src.type : src.type.typeArg.kind === "type_id" @@ -96,9 +83,9 @@ export function resolveABIType(src: AstFieldDecl): ABITypeRef { src.type.typeArg.loc, ); - if (isInt(typeId)) { + if (A.isInt(typeId)) { if (src.as) { - const fmt = intFormats[idText(src.as)]; + const fmt = intFormats[A.idText(src.as)]; if (!fmt) { throwCompilationError( `Unsupported format ${idTextErr(src.as)}`, @@ -119,7 +106,7 @@ export function resolveABIType(src: AstFieldDecl): ABITypeRef { format: 257, }; // Default is maximum size int } - if (isBool(typeId)) { + if (A.isBool(typeId)) { if (src.as) { throwCompilationError( `Unsupported format ${idTextErr(src.as)}`, @@ -132,9 +119,9 @@ export function resolveABIType(src: AstFieldDecl): ABITypeRef { optional: src.type.kind === "optional_type", }; } - if (isCell(typeId)) { + if (A.isCell(typeId)) { if (src.as) { - const fmt = cellFormats[idText(src.as)]; + const fmt = cellFormats[A.idText(src.as)]; if (!fmt) { throwCompilationError( `Unsupported format ${idTextErr(src.as)}`, @@ -154,9 +141,9 @@ export function resolveABIType(src: AstFieldDecl): ABITypeRef { optional: src.type.kind === "optional_type", }; } - if (isSlice(typeId)) { + if (A.isSlice(typeId)) { if (src.as) { - const fmt = sliceFormats[idText(src.as)]; + const fmt = sliceFormats[A.idText(src.as)]; if (!fmt) { throwCompilationError( `Unsupported format ${idTextErr(src.as)}`, @@ -176,9 +163,9 @@ export function resolveABIType(src: AstFieldDecl): ABITypeRef { optional: src.type.kind === "optional_type", }; } - if (isBuilder(typeId)) { + if (A.isBuilder(typeId)) { if (src.as) { - const fmt = builderFormats[idText(src.as)]; + const fmt = builderFormats[A.idText(src.as)]; if (!fmt) { throwCompilationError( `Unsupported format ${idTextErr(src.as)}`, @@ -198,7 +185,7 @@ export function resolveABIType(src: AstFieldDecl): ABITypeRef { optional: src.type.kind === "optional_type", }; } - if (isAddress(typeId)) { + if (A.isAddress(typeId)) { if (src.as) { throwCompilationError( `Unsupported format ${idTextErr(src.as)}`, @@ -211,7 +198,7 @@ export function resolveABIType(src: AstFieldDecl): ABITypeRef { optional: src.type.kind === "optional_type", }; } - if (isString(typeId)) { + if (A.isString(typeId)) { if (src.as) { throwCompilationError( `Unsupported format ${idTextErr(src.as)}`, @@ -224,7 +211,7 @@ export function resolveABIType(src: AstFieldDecl): ABITypeRef { optional: src.type.kind === "optional_type", }; } - if (isStringBuilder(typeId)) { + if (A.isStringBuilder(typeId)) { throwCompilationError(`Unsupported type StringBuilder`, src.loc); } @@ -233,10 +220,10 @@ export function resolveABIType(src: AstFieldDecl): ABITypeRef { // if (src.as) { - if (eqNames(src.as, "reference")) { + if (A.eqNames(src.as, "reference")) { return { kind: "simple", - type: idText(typeId), + type: A.idText(typeId), optional: src.type.kind === "optional_type", format: "ref", }; @@ -249,7 +236,7 @@ export function resolveABIType(src: AstFieldDecl): ABITypeRef { } return { kind: "simple", - type: idText(typeId), + type: A.idText(typeId), optional: src.type.kind === "optional_type", }; } @@ -265,11 +252,11 @@ export function resolveABIType(src: AstFieldDecl): ABITypeRef { let valueFormat: string | number | undefined = undefined; // Resolve key type - if (isInt(src.type.keyType)) { + if (A.isInt(src.type.keyType)) { key = "int"; if (src.type.keyStorageType) { const format = - intMapKeyFormats[idText(src.type.keyStorageType)]; + intMapKeyFormats[A.idText(src.type.keyStorageType)]; if (!format) { throwCompilationError( `Unsupported format ${idTextErr(src.type.keyStorageType)} for map key`, @@ -279,7 +266,7 @@ export function resolveABIType(src: AstFieldDecl): ABITypeRef { key = format.type; keyFormat = format.format; } - } else if (isAddress(src.type.keyType)) { + } else if (A.isAddress(src.type.keyType)) { key = "address"; if (src.type.keyStorageType) { throwCompilationError( @@ -295,21 +282,21 @@ export function resolveABIType(src: AstFieldDecl): ABITypeRef { } // Resolve value type - if (isInt(src.type.valueType)) { + if (A.isInt(src.type.valueType)) { value = "int"; if (src.type.valueStorageType) { const format = - intMapValFormats[idText(src.type.valueStorageType)]; + intMapValFormats[A.idText(src.type.valueStorageType)]; if (!format) { throwCompilationError( - `Unsupported format ${idText(src.type.valueStorageType)} for map value`, + `Unsupported format ${A.idText(src.type.valueStorageType)} for map value`, src.loc, ); } value = format.type; valueFormat = format.format; } - } else if (isBool(src.type.valueType)) { + } else if (A.isBool(src.type.valueType)) { value = "bool"; if (src.type.valueStorageType) { throwCompilationError( @@ -317,24 +304,24 @@ export function resolveABIType(src: AstFieldDecl): ABITypeRef { src.loc, ); } - } else if (isCell(src.type.valueType)) { + } else if (A.isCell(src.type.valueType)) { value = "cell"; valueFormat = "ref"; if ( src.type.valueStorageType && - eqNames(src.type.valueStorageType, "reference") + A.eqNames(src.type.valueStorageType, "reference") ) { throwCompilationError( `Unsupported format ${idTextErr(src.type.valueStorageType)} for map value`, src.loc, ); } - } else if (isSlice(src.type.valueType)) { + } else if (A.isSlice(src.type.valueType)) { throwCompilationError( `Unsupported map value type ${idTextErr(src.type.valueType)}`, src.loc, ); - } else if (isAddress(src.type.valueType)) { + } else if (A.isAddress(src.type.valueType)) { value = "address"; if (src.type.valueStorageType) { throwCompilationError( @@ -342,25 +329,25 @@ export function resolveABIType(src: AstFieldDecl): ABITypeRef { src.loc, ); } - } else if (isString(src.type.valueType)) { + } else if (A.isString(src.type.valueType)) { throwCompilationError( `Unsupported map value type ${idTextErr(src.type.valueType)}`, src.loc, ); } else if ( - isStringBuilder(src.type.valueType) || - isBuilder(src.type.valueType) + A.isStringBuilder(src.type.valueType) || + A.isBuilder(src.type.valueType) ) { throwCompilationError( `Unsupported map value type ${idTextErr(src.type.valueType)}`, src.loc, ); } else { - value = idText(src.type.valueType); + value = A.idText(src.type.valueType); valueFormat = "ref"; if ( src.type.valueStorageType && - eqNames(src.type.valueStorageType, "reference") + A.eqNames(src.type.valueStorageType, "reference") ) { throwCompilationError( `Unsupported format ${idTextErr(src.type.valueStorageType)} for map value`, diff --git a/src/types/resolveStatements.ts b/src/types/resolveStatements.ts index b6be0529d..e1b057b9e 100644 --- a/src/types/resolveStatements.ts +++ b/src/types/resolveStatements.ts @@ -1,16 +1,5 @@ +import * as A from "../ast/ast"; import { CompilerContext } from "../context/context"; -import { - AstCondition, - AstStatement, - tryExtractPath, - AstId, - idText, - isWildcard, - selfId, - isSelfId, - eqNames, - FactoryAst, -} from "../ast/ast"; import { isAssignable } from "./subtyping"; import { idTextErr, @@ -59,24 +48,24 @@ export function emptyContext( function checkVariableExists( ctx: CompilerContext, sctx: StatementContext, - name: AstId, + name: A.AstId, ): void { - if (sctx.vars.has(idText(name))) { + if (sctx.vars.has(A.idText(name))) { throwCompilationError( `Variable already exists: ${idTextErr(name)}`, name.loc, ); } // Check if the user tries to shadow the current function name - if (sctx.funName === idText(name)) { + if (sctx.funName === A.idText(name)) { throwCompilationError( `Variable cannot have the same name as its enclosing function: ${idTextErr(name)}`, name.loc, ); } - if (hasStaticConstant(ctx, idText(name))) { + if (hasStaticConstant(ctx, A.idText(name))) { if (name.loc.origin === "stdlib") { - const constLoc = getStaticConstant(ctx, idText(name)).loc; + const constLoc = getStaticConstant(ctx, A.idText(name)).loc; throwCompilationError( `Constant ${idTextErr(name)} is shadowing an identifier defined in the Tact standard library: pick a different constant name`, constLoc, @@ -118,23 +107,23 @@ function removeRequiredVariable( } function addVariable( - name: AstId, + name: A.AstId, ref: TypeRef, ctx: CompilerContext, sctx: StatementContext, ): StatementContext { checkVariableExists(ctx, sctx, name); // Should happen earlier - if (isWildcard(name)) { + if (A.isWildcard(name)) { return sctx; } return { ...sctx, - vars: new Map(sctx.vars).set(idText(name), ref), + vars: new Map(sctx.vars).set(A.idText(name), ref), }; } function processCondition( - condition: AstCondition, + condition: A.AstCondition, sctx: StatementContext, ctx: CompilerContext, ): { @@ -213,16 +202,16 @@ function processCondition( // Precondition: `self` here means a contract or a trait, // and not a `self` parameter of a mutating method -export function isLvalue(path: AstId[], ctx: CompilerContext): boolean { +export function isLvalue(path: A.AstId[], ctx: CompilerContext): boolean { const headId = path[0]!; - if (isSelfId(headId) && path.length > 1) { + if (A.isSelfId(headId) && path.length > 1) { // we can be dealing with a contract/trait constant `self.constFoo` const selfTypeRef = getExpType(ctx, headId); if (selfTypeRef.kind == "ref") { const contractTypeDescription = getType(ctx, selfTypeRef.name); return ( contractTypeDescription.constants.findIndex((constDescr) => - eqNames(path[1]!, constDescr.name), + A.eqNames(path[1]!, constDescr.name), ) === -1 ); } else { @@ -230,12 +219,12 @@ export function isLvalue(path: AstId[], ctx: CompilerContext): boolean { } } else { // if the head path symbol is a global constant, then the whole path expression is a constant - return !hasStaticConstant(ctx, idText(headId)); + return !hasStaticConstant(ctx, A.idText(headId)); } } function processStatements( - statements: AstStatement[], + statements: A.AstStatement[], sctx: StatementContext, ctx: CompilerContext, ): { @@ -295,7 +284,7 @@ function processStatements( const tempSctx = { ...sctx, requiredFields: [] }; // Process lvalue ctx = resolveExpression(s.path, tempSctx, ctx); - const path = tryExtractPath(s.path); + const path = A.tryExtractPath(s.path); if (path === null) { throwCompilationError( `Assignments are allowed only into path expressions, i.e. identifiers, or sequences of direct contract/struct/message accesses, like "self.foo" or "self.structure.field"`, @@ -339,7 +328,7 @@ function processStatements( // Process lvalue const tempSctx = { ...sctx, requiredFields: [] }; ctx = resolveExpression(s.path, tempSctx, ctx); - const path = tryExtractPath(s.path); + const path = A.tryExtractPath(s.path); if (path === null) { throwCompilationError( `Assignments are allowed only into path expressions, i.e. identifiers, or sequences of direct contract/struct/message accesses, like "self.foo" or "self.structure.field"`, @@ -415,7 +404,7 @@ function processStatements( if ( s.expression.kind === "static_call" && ["throw", "nativeThrow"].includes( - idText(s.expression.function), + A.idText(s.expression.function), ) ) { returnAlwaysReachable = true; @@ -629,7 +618,7 @@ function processStatements( // Resolve map expression ctx = resolveExpression(s.map, sctx, ctx); - const mapPath = tryExtractPath(s.map); + const mapPath = A.tryExtractPath(s.map); if (mapPath === null) { throwCompilationError( `foreach is only allowed over maps that are path expressions, i.e. identifiers, or sequences of direct contract/struct/message accesses, like "self.foo" or "self.structure.field"`, @@ -649,7 +638,7 @@ function processStatements( let foreachSctx = sctx; // Add key and value to statement context - if (!isWildcard(s.keyName)) { + if (!A.isWildcard(s.keyName)) { checkVariableExists(ctx, initialSctx, s.keyName); foreachSctx = addVariable( s.keyName, @@ -658,7 +647,7 @@ function processStatements( initialSctx, ); } - if (!isWildcard(s.valueName)) { + if (!A.isWildcard(s.valueName)) { checkVariableExists(ctx, foreachSctx, s.valueName); foreachSctx = addVariable( s.valueName, @@ -746,7 +735,7 @@ function processStatements( // Add variables s.identifiers.forEach(([field, name], _) => { - const f = ty.fields.find((f) => eqNames(f.name, field)); + const f = ty.fields.find((f) => A.eqNames(f.name, field)); if (!f) { throwCompilationError( `Field '${idTextErr(field)}' not found in type '${expressionType.name}'`, @@ -773,7 +762,7 @@ function processStatements( } function processFunctionBody( - statements: AstStatement[], + statements: A.AstStatement[], sctx: StatementContext, ctx: CompilerContext, ): CompilerContext { @@ -805,7 +794,7 @@ function processFunctionBody( return res.ctx; } -export function resolveStatements(ctx: CompilerContext, Ast: FactoryAst) { +export function resolveStatements(ctx: CompilerContext, Ast: A.FactoryAst) { const util = getAstUtil(Ast); // Process all static functions @@ -830,7 +819,7 @@ export function resolveStatements(ctx: CompilerContext, Ast: FactoryAst) { // Self sctx = addVariable( - selfId, + A.selfId, { kind: "ref", name: t.name, optional: false }, ctx, sctx, @@ -862,7 +851,7 @@ export function resolveStatements(ctx: CompilerContext, Ast: FactoryAst) { // Build statement context let sctx = emptyContext(f.ast.loc, null, { kind: "void" }); sctx = addVariable( - selfId, + A.selfId, { kind: "ref", name: t.name, optional: false }, ctx, sctx, @@ -958,7 +947,7 @@ export function resolveStatements(ctx: CompilerContext, Ast: FactoryAst) { "Self is null where it should not be", ); } - sctx = addVariable(selfId, f.self, ctx, sctx); + sctx = addVariable(A.selfId, f.self, ctx, sctx); // Check for collisions in getter method IDs if (f.isGetter) {