import { DeclarationStatement , ClassDeclaration , DecoratorNode , ClassPrototype , Element , ElementKind , FunctionPrototype , Expression , IdentifierExpression , NodeKind , BinaryExpression , SourceKind , FieldPrototype , NamedTypeNode , Range , CommonFlags } from "assemblyscript" ; import { getCustomDecoratorKind } from "../contract/decorator" ; import { DocDecoratorNodeDef } from "../contract/elementdef" ; import { ContractDecoratorKind } from "../enums/decorator" ; import { Strings } from "./primitiveutil" ; export class ElementUtil { static isEventClassPrototype ( element ) { if ( element . kind == ElementKind . CLASS_PROTOTYPE ) { let clzPrototype = < ClassPrototype > element ; return AstUtil . hasSpecifyDecorator ( clzPrototype . declaration , ContractDecoratorKind . EVENT ) ; } return false ; } static isTopContractClass ( element ) { if ( element . kind == ElementKind . CLASS_PROTOTYPE ) { let clzPrototype = < ClassPrototype > element ; return clzPrototype . declaration . range . source . sourceKind == SourceKind . USER_ENTRY && AstUtil . hasSpecifyDecorator ( clzPrototype . declaration , ContractDecoratorKind . CONTRACT ) ; } return false ; } static isStoreClassPrototype ( element ) { return ( element . kind == ElementKind . CLASS_PROTOTYPE ) ? AstUtil . hasSpecifyDecorator ( ( < ClassPrototype > element ) . declaration , ContractDecoratorKind . STORAGE ) : false ; } static isDynamicClassPrototype ( element ) { return ( element . kind == ElementKind . CLASS_PROTOTYPE ) ? AstUtil . hasSpecifyDecorator ( ( < ClassPrototype > element ) . declaration , ContractDecoratorKind . DYNAMIC ) : false ; } param element static isCntrFuncPrototype ( element ) { if ( element . kind == ElementKind . FUNCTION_PROTOTYPE ) { return AstUtil . hasSpecifyDecorator ( ( < FunctionPrototype > element ) . declaration , ContractDecoratorKind . CONSTRUCTOR ) ; } return false ; } static isTopicField ( element ) { if ( element . kind == ElementKind . FIELD_PROTOTYPE ) { return AstUtil . hasSpecifyDecorator ( ( < FieldPrototype > element ) . declaration , ContractDecoratorKind . TOPIC ) ; } return false ; } static isExtendCodec ( element ) { if ( element . kind == ElementKind . CLASS_PROTOTYPE ) { return ElementUtil . impledInterfaces ( < ClassPrototype > element ) . includes ( "Codec" ) ; } return false ; } param classPrototype static impledInterfaces ( classPrototype ) { var tempClz = classPrototype ; var interfaces = new Array < string > ( ) ; while ( tempClz != null ) { let implTypes = ( < ClassDeclaration > tempClz . declaration ) . implementsTypes ; if ( implTypes ) { for ( let type of implTypes ) { interfaces . push ( type . name . range . toString ( ) ) ; } } tempClz = tempClz . basePrototype ; } return interfaces ; } param element static isMessageFuncPrototype ( element ) { if ( element . kind == ElementKind . FUNCTION_PROTOTYPE ) { let funcType = < FunctionPrototype > element ; return AstUtil . hasSpecifyDecorator ( funcType . declaration , ContractDecoratorKind . MESSAGE ) ; } return false ; } } export class AstUtil { static isVoid ( type ) { return type . name . range . toString ( ) == "void" ; } static getIdentifier ( expression ) { if ( expression . kind == NodeKind . IDENTIFIER ) { return ( < IdentifierExpression > expression ) . text ; } else if ( expression . kind == NodeKind . BINARY ) { return ( < BinaryExpression > expression ) . left . range . toString ( ) ; } return "" ; } static getBinaryExprRight ( expression ) { if ( expression . kind == NodeKind . BINARY ) { return ( < BinaryExpression > expression ) . right . range . toString ( ) ; } return Strings . EMPTY ; } public static getDocDecorator ( statement ) { return AstUtil . getSpecifyDecorator ( statement , ContractDecoratorKind . DOC ) ; } param statement param kind static hasSpecifyDecorator ( statement , kind ) { if ( statement . decorators ) { return DecoratorUtil . containDecorator ( statement . decorators , kind ) ; } return false ; } static getSpecifyDecorator ( statement , kind ) { if ( statement . decorators ) { for ( let decorator of statement . decorators ) { if ( DecoratorUtil . isDecoratorKind ( decorator , kind ) ) { return decorator ; } } } return null ; } param declareType static getArrayTypeArgument ( declareType ) { var bracketIndex = declareType . indexOf ( "[" ) ; if ( bracketIndex != - 1 ) { let index = declareType . indexOf ( " " ) == - 1 ? bracketIndex : declareType . indexOf ( " " ) ; return declareType . substring ( 0 , index ) ; } bracketIndex = declareType . indexOf ( "<" ) ; if ( bracketIndex != - 1 ) { let endIndex = declareType . indexOf ( ">" ) ; return declareType . substring ( bracketIndex + 1 , endIndex ) ; } return declareType ; } param declareType static isArrayType ( declareType ) { return declareType == "[]" || declareType == "Array" || declareType == "StorableArray" || declareType == "SpreadStorableArray" || declareType == "PackedStorableArray" ; } param declareType static isMapType ( declareType ) { return declareType == "Map" || declareType == "StorableMap" || declareType == "SpreadStorableMap" || declareType == "PackedStorableMap" ; } static checkPublic ( declaration ) { if ( declaration . isAny ( CommonFlags . PRIVATE ) ) { throw new Error ( `Method: ${ declaration . name . range . toString ( ) } should be public. Trace: ${ RangeUtil . location ( declaration . range ) }.` ) ; } } } export class RangeUtil { public static location ( range ) { return `source text: ${ range . toString ( ) }. Path:${ range . source . normalizedPath } lineAt: ${ range . source . lineAt ( range . start ) } columnAt: ${ range . source . columnAt ( ) } range: (${ range . start . toString ( 10 ) } ${ range . end . toString ( 10 ) }).` ; } } export class DecoratorUtil { static isDecoratorKind ( decorator , kind ) { return kind == getCustomDecoratorKind ( decorator ) ; } static containDecorator ( decorators , kind ) { for ( let decorator of decorators ) { if ( getCustomDecoratorKind ( decorator ) == kind ) { return true ; } } return false ; } public static getDoc ( statement ) { let decortor = AstUtil . getDocDecorator ( statement ) ; return decortor == null ? [ Strings . EMPTY ] : [ new DocDecoratorNodeDef ( decortor ) . doc ] ; } public static checkSelecrot ( decorator , selector ) { let isLegal = false ; if ( selector ) { var re = /0x[0-9A-Fa-f]{8}/g ; if ( re . test ( selector ) ) { isLegal = true ; } } if ( ! isLegal ) { throw new Error ( `Decorator: ${ decorator . name . range . toString ( ) } argument selector value should be start with 0x hex string(4 Bytes). Trace: ${ RangeUtil . location ( decorator . range ) } ` ) ; } } public static checkMutates ( decorator , val ) { let isLegal = ( val == 'false' ) ; if ( ! isLegal ) { throw new Error ( `Decorator: ${ decorator . name . range . toString ( ) } argument mutates value should be false. Trace: ${ RangeUtil . location ( decorator . range ) } ` ) ; } } public static throwNoArguException ( decorator , identifier ) { throw new Error ( `Decorator: ${ decorator . name . range . toString ( ) } should not contain argument ${ identifier }. Trace: ${ RangeUtil . location ( decorator . range ) } ` ) ; } }