// Base on the original type definitions for solidity-parser-antlr 0.2 // by Leonid Logvinov // Alex Browne // Xiao Liang interface Position { line: number column: number } export interface Location { start: Position end: Position } export interface Comment { type: 'BlockComment' | 'LineComment' value: string range?: [number, number] loc?: Location } export interface BaseASTNode { type: ASTNodeTypeString comments?: Comment[] range?: [number, number] loc?: Location } export interface SourceUnit extends BaseASTNode { type: 'SourceUnit' children: ASTNode[] } export interface ContractDefinition extends BaseASTNode { type: 'ContractDefinition' name: string baseContracts: InheritanceSpecifier[] kind: string subNodes: BaseASTNode[] storageLayout?: Expression } export interface InheritanceSpecifier extends BaseASTNode { type: 'InheritanceSpecifier' baseName: UserDefinedTypeName arguments: Expression[] } export interface UserDefinedTypeName extends BaseASTNode { type: 'UserDefinedTypeName' namePath: string } export const astNodeTypes = [ 'SourceUnit', 'PragmaDirective', 'ImportDirective', 'ContractDefinition', 'InheritanceSpecifier', 'StateVariableDeclaration', 'UsingForDeclaration', 'StructDefinition', 'ModifierDefinition', 'ModifierInvocation', 'FunctionDefinition', 'EventDefinition', 'CustomErrorDefinition', 'RevertStatement', 'EnumValue', 'EnumDefinition', 'VariableDeclaration', 'UserDefinedTypeName', 'Mapping', 'ArrayTypeName', 'FunctionTypeName', 'Block', 'ExpressionStatement', 'IfStatement', 'WhileStatement', 'ForStatement', 'InlineAssemblyStatement', 'DoWhileStatement', 'ContinueStatement', 'Break', 'Continue', 'BreakStatement', 'ReturnStatement', 'EmitStatement', 'ThrowStatement', 'VariableDeclarationStatement', 'ElementaryTypeName', 'FunctionCall', 'AssemblyBlock', 'AssemblyCall', 'AssemblyLocalDefinition', 'AssemblyAssignment', 'AssemblyStackAssignment', 'LabelDefinition', 'AssemblySwitch', 'AssemblyCase', 'AssemblyFunctionDefinition', 'AssemblyFor', 'AssemblyIf', 'TupleExpression', 'NameValueExpression', 'BooleanLiteral', 'NumberLiteral', 'Identifier', 'BinaryOperation', 'UnaryOperation', 'NewExpression', 'Conditional', 'StringLiteral', 'HexLiteral', 'HexNumber', 'DecimalNumber', 'MemberAccess', 'IndexAccess', 'IndexRangeAccess', 'NameValueList', 'UncheckedStatement', 'TryStatement', 'CatchClause', 'FileLevelConstant', 'AssemblyMemberAccess', 'TypeDefinition', ] as const export type ASTNodeTypeString = (typeof astNodeTypes)[number] export interface PragmaDirective extends BaseASTNode { type: 'PragmaDirective' name: string value: string } export interface ImportDirective extends BaseASTNode { type: 'ImportDirective' path: string pathLiteral: StringLiteral unitAlias: string | null unitAliasIdentifier: Identifier | null symbolAliases: Array<[string, string | null]> | null symbolAliasesIdentifiers: Array<[Identifier, Identifier | null]> | null } export interface StateVariableDeclaration extends BaseASTNode { type: 'StateVariableDeclaration' variables: StateVariableDeclarationVariable[] initialValue: Expression | null } export interface FileLevelConstant extends BaseASTNode { type: 'FileLevelConstant' typeName: TypeName name: string initialValue: Expression isDeclaredConst: boolean isImmutable: boolean } export interface UsingForDeclaration extends BaseASTNode { type: 'UsingForDeclaration' typeName: TypeName | null functions: string[] // for each item in `functions`, the item with the same index in `operators` // will be the defined operator, or null if it's just an attached function operators: Array libraryName: string | null isGlobal: boolean } export interface StructDefinition extends BaseASTNode { type: 'StructDefinition' name: string members: VariableDeclaration[] } export interface ModifierDefinition extends BaseASTNode { type: 'ModifierDefinition' name: string parameters: null | VariableDeclaration[] isVirtual: boolean override: null | UserDefinedTypeName[] body: Block | null } export interface ModifierInvocation extends BaseASTNode { type: 'ModifierInvocation' name: string arguments: Expression[] | null } export interface FunctionDefinition extends BaseASTNode { type: 'FunctionDefinition' name: string | null parameters: VariableDeclaration[] modifiers: ModifierInvocation[] stateMutability: 'pure' | 'constant' | 'payable' | 'view' | null visibility: 'default' | 'external' | 'internal' | 'public' | 'private' returnParameters: VariableDeclaration[] | null body: Block | null override: UserDefinedTypeName[] | null isConstructor: boolean isReceiveEther: boolean isFallback: boolean isVirtual: boolean } export interface CustomErrorDefinition extends BaseASTNode { type: 'CustomErrorDefinition' name: string parameters: VariableDeclaration[] } export interface TypeDefinition extends BaseASTNode { type: 'TypeDefinition' name: string definition: ElementaryTypeName } export interface RevertStatement extends BaseASTNode { type: 'RevertStatement' revertCall: FunctionCall } export interface EventDefinition extends BaseASTNode { type: 'EventDefinition' name: string parameters: VariableDeclaration[] isAnonymous: boolean } export interface EnumValue extends BaseASTNode { type: 'EnumValue' name: string } export interface EnumDefinition extends BaseASTNode { type: 'EnumDefinition' name: string members: EnumValue[] } export interface VariableDeclaration extends BaseASTNode { type: 'VariableDeclaration' isIndexed: boolean isStateVar: boolean typeName: TypeName | null name: string | null identifier: Identifier | null isDeclaredConst?: boolean storageLocation: string | null expression: Expression | null visibility?: 'public' | 'private' | 'internal' | 'default' } export interface StateVariableDeclarationVariable extends VariableDeclaration { override: null | UserDefinedTypeName[] isImmutable: boolean isTransient: boolean } export interface ArrayTypeName extends BaseASTNode { type: 'ArrayTypeName' baseTypeName: TypeName length: Expression | null } export interface Mapping extends BaseASTNode { type: 'Mapping' keyType: ElementaryTypeName | UserDefinedTypeName keyName: Identifier | null valueType: TypeName valueName: Identifier | null } export interface FunctionTypeName extends BaseASTNode { type: 'FunctionTypeName' parameterTypes: VariableDeclaration[] returnTypes: VariableDeclaration[] visibility: string stateMutability: string | null } export interface Block extends BaseASTNode { type: 'Block' statements: BaseASTNode[] } export interface ExpressionStatement extends BaseASTNode { type: 'ExpressionStatement' expression: Expression | null } export interface IfStatement extends BaseASTNode { type: 'IfStatement' condition: Expression trueBody: Statement falseBody: Statement | null } export interface UncheckedStatement extends BaseASTNode { type: 'UncheckedStatement' block: Block } export interface TryStatement extends BaseASTNode { type: 'TryStatement' expression: Expression returnParameters: VariableDeclaration[] | null body: Block catchClauses: CatchClause[] } export interface CatchClause extends BaseASTNode { type: 'CatchClause' isReasonStringType: boolean kind: string | null parameters: VariableDeclaration[] | null body: Block } export interface WhileStatement extends BaseASTNode { type: 'WhileStatement' condition: Expression body: Statement } export interface ForStatement extends BaseASTNode { type: 'ForStatement' initExpression: SimpleStatement | null conditionExpression?: Expression loopExpression: ExpressionStatement body: Statement } export interface InlineAssemblyStatement extends BaseASTNode { type: 'InlineAssemblyStatement' language: string | null flags: string[] body: AssemblyBlock } export interface DoWhileStatement extends BaseASTNode { type: 'DoWhileStatement' condition: Expression body: Statement } export interface ContinueStatement extends BaseASTNode { type: 'ContinueStatement' } export interface Break extends BaseASTNode { type: 'Break' } export interface Continue extends BaseASTNode { type: 'Continue' } export interface BreakStatement extends BaseASTNode { type: 'BreakStatement' } export interface ReturnStatement extends BaseASTNode { type: 'ReturnStatement' expression: Expression | null } export interface EmitStatement extends BaseASTNode { type: 'EmitStatement' eventCall: FunctionCall } export interface ThrowStatement extends BaseASTNode { type: 'ThrowStatement' } export interface VariableDeclarationStatement extends BaseASTNode { type: 'VariableDeclarationStatement' variables: Array initialValue: Expression | null } export interface ElementaryTypeName extends BaseASTNode { type: 'ElementaryTypeName' name: string stateMutability: string | null } export interface FunctionCall extends BaseASTNode { type: 'FunctionCall' expression: Expression arguments: Expression[] names: string[] identifiers: Identifier[] } export interface AssemblyBlock extends BaseASTNode { type: 'AssemblyBlock' operations: AssemblyItem[] } export interface AssemblyCall extends BaseASTNode { type: 'AssemblyCall' functionName: string arguments: AssemblyExpression[] } export interface AssemblyLocalDefinition extends BaseASTNode { type: 'AssemblyLocalDefinition' names: Identifier[] | AssemblyMemberAccess[] expression: AssemblyExpression | null } export interface AssemblyAssignment extends BaseASTNode { type: 'AssemblyAssignment' names: Identifier[] | AssemblyMemberAccess[] expression: AssemblyExpression } export interface AssemblyStackAssignment extends BaseASTNode { type: 'AssemblyStackAssignment' name: string expression: AssemblyExpression } export interface LabelDefinition extends BaseASTNode { type: 'LabelDefinition' name: string } export interface AssemblySwitch extends BaseASTNode { type: 'AssemblySwitch' expression: AssemblyExpression cases: AssemblyCase[] } export interface AssemblyCase extends BaseASTNode { type: 'AssemblyCase' value: AssemblyLiteral | null block: AssemblyBlock default: boolean } export interface AssemblyFunctionDefinition extends BaseASTNode { type: 'AssemblyFunctionDefinition' name: string arguments: Identifier[] returnArguments: Identifier[] body: AssemblyBlock } export interface AssemblyFor extends BaseASTNode { type: 'AssemblyFor' pre: AssemblyBlock | AssemblyExpression condition: AssemblyExpression post: AssemblyBlock | AssemblyExpression body: AssemblyBlock } export interface AssemblyIf extends BaseASTNode { type: 'AssemblyIf' condition: AssemblyExpression body: AssemblyBlock } export type AssemblyLiteral = | StringLiteral | BooleanLiteral | DecimalNumber | HexNumber | HexLiteral export interface AssemblyMemberAccess extends BaseASTNode { type: 'AssemblyMemberAccess' expression: Identifier memberName: Identifier } export interface NewExpression extends BaseASTNode { type: 'NewExpression' typeName: TypeName } export interface TupleExpression extends BaseASTNode { type: 'TupleExpression' components: Array isArray: boolean } export interface NameValueExpression extends BaseASTNode { type: 'NameValueExpression' expression: Expression arguments: NameValueList } export interface NumberLiteral extends BaseASTNode { type: 'NumberLiteral' number: string subdenomination: | null | 'wei' | 'szabo' | 'finney' | 'ether' | 'seconds' | 'minutes' | 'hours' | 'days' | 'weeks' | 'years' } export interface BooleanLiteral extends BaseASTNode { type: 'BooleanLiteral' value: boolean } export interface HexLiteral extends BaseASTNode { type: 'HexLiteral' value: string parts: string[] } export interface StringLiteral extends BaseASTNode { type: 'StringLiteral' value: string parts: string[] isUnicode: boolean[] } export interface Identifier extends BaseASTNode { type: 'Identifier' name: string } export const binaryOpValues = [ '+', '-', '*', '/', '**', '%', '<<', '>>', '&&', '||', '&', '^', '<', '>', '<=', '>=', '==', '!=', '=', '^=', '&=', '<<=', '>>=', '+=', '-=', '*=', '/=', '%=', '|', '|=', ] as const export type BinOp = (typeof binaryOpValues)[number] export const unaryOpValues = [ '-', '+', '++', '--', '~', 'after', 'delete', '!', ] as const export type UnaryOp = (typeof unaryOpValues)[number] export interface BinaryOperation extends BaseASTNode { type: 'BinaryOperation' left: Expression right: Expression operator: BinOp } export interface UnaryOperation extends BaseASTNode { type: 'UnaryOperation' operator: UnaryOp subExpression: Expression isPrefix: boolean } export interface Conditional extends BaseASTNode { type: 'Conditional' condition: Expression trueExpression: Expression falseExpression: Expression } export interface IndexAccess extends BaseASTNode { type: 'IndexAccess' base: Expression index: Expression } export interface IndexRangeAccess extends BaseASTNode { type: 'IndexRangeAccess' base: Expression indexStart?: Expression indexEnd?: Expression } export interface MemberAccess extends BaseASTNode { type: 'MemberAccess' expression: Expression memberName: string } export interface HexNumber extends BaseASTNode { type: 'HexNumber' value: string } export interface DecimalNumber extends BaseASTNode { type: 'DecimalNumber' value: string } export interface NameValueList extends BaseASTNode { type: 'NameValueList' names: string[] identifiers: Identifier[] arguments: Expression[] } export type ASTNode = | SourceUnit | PragmaDirective | ImportDirective | ContractDefinition | InheritanceSpecifier | StateVariableDeclaration | UsingForDeclaration | StructDefinition | ModifierDefinition | ModifierInvocation | FunctionDefinition | EventDefinition | CustomErrorDefinition | EnumValue | EnumDefinition | VariableDeclaration | TypeName | UserDefinedTypeName | Mapping | FunctionTypeName | Block | Statement | ElementaryTypeName | AssemblyBlock | AssemblyCall | AssemblyLocalDefinition | AssemblyAssignment | AssemblyStackAssignment | LabelDefinition | AssemblySwitch | AssemblyCase | AssemblyFunctionDefinition | AssemblyFor | AssemblyIf | AssemblyLiteral | TupleExpression | BinaryOperation | Conditional | IndexAccess | IndexRangeAccess | AssemblyItem | Expression | NameValueList | AssemblyMemberAccess | CatchClause | FileLevelConstant | TypeDefinition export type AssemblyItem = | Identifier | AssemblyBlock | AssemblyExpression | AssemblyLocalDefinition | AssemblyAssignment | AssemblyStackAssignment | LabelDefinition | AssemblySwitch | AssemblyFunctionDefinition | AssemblyFor | AssemblyIf | Break | Continue | NumberLiteral | StringLiteral | HexNumber | HexLiteral | DecimalNumber export type AssemblyExpression = AssemblyCall | AssemblyLiteral export type Expression = | IndexAccess | IndexRangeAccess | TupleExpression | BinaryOperation | Conditional | MemberAccess | FunctionCall | UnaryOperation | NewExpression | PrimaryExpression | NameValueExpression export type PrimaryExpression = | BooleanLiteral | HexLiteral | StringLiteral | NumberLiteral | Identifier | TupleExpression | TypeName export type SimpleStatement = VariableDeclarationStatement | ExpressionStatement export type TypeName = | ElementaryTypeName | UserDefinedTypeName | Mapping | ArrayTypeName | FunctionTypeName export type Statement = | IfStatement | WhileStatement | ForStatement | Block | InlineAssemblyStatement | DoWhileStatement | ContinueStatement | BreakStatement | ReturnStatement | EmitStatement | ThrowStatement | SimpleStatement | VariableDeclarationStatement | UncheckedStatement | TryStatement | RevertStatement type ASTMap = { [K in ASTNodeTypeString]: U extends { type: K } ? U : never } type ASTTypeMap = ASTMap type ASTVisitorEnter = { [K in keyof ASTTypeMap]?: (ast: ASTTypeMap[K], parent?: ASTNode) => any } type ASTVisitorExit = { [K in keyof ASTTypeMap as `${K}:exit`]?: ( ast: ASTTypeMap[K], parent?: ASTNode ) => any } export type ASTVisitor = ASTVisitorEnter & ASTVisitorExit /* eslint-disable @typescript-eslint/no-unused-vars */ /** * This monstrosity is here to check that there are no ASTNodeTypeString without * a corresponding ASTNode, no ASTNode without a corresponding ASTNodeTypeString, * no ASTVisitorEnter callback without a corresponding ASTNode, * no ASTVisitorExit callback without a corresponding ASTVisitorEnter callback, * and so on, and so on. * * There are probably some ways to simplify this by deriving some types * from others. */ function checkTypes() { const astNodeType: ASTNode['type'] = '' as any const astNodeTypeString: ASTNodeTypeString = '' as any const astVisitorEnterKey: keyof ASTVisitorEnter = '' as any let assignAstNodeType: ASTNode['type'] = astNodeTypeString assignAstNodeType = astVisitorEnterKey let assignAstNodeTyeString: ASTNodeTypeString = astNodeType assignAstNodeTyeString = astVisitorEnterKey let assignAstVisitorEnterKey: keyof ASTVisitorEnter = astNodeType assignAstVisitorEnterKey = astNodeTypeString const astNodeTypeExit: `${ASTNode['type']}:exit` = '' as any const astNodeTypeStringExit: `${ASTNodeTypeString}:exit` = '' as any const astVisitorEnterKeyExit: `${keyof ASTVisitorEnter}:exit` = '' as any const astVisitorExitKey: keyof ASTVisitorExit = '' as any let letAstNodeTypeExit: `${ASTNode['type']}:exit` = astNodeTypeStringExit letAstNodeTypeExit = astVisitorEnterKeyExit letAstNodeTypeExit = astVisitorExitKey let assignAstNodeTypeStringExit: `${ASTNodeTypeString}:exit` = astNodeTypeExit assignAstNodeTypeStringExit = astVisitorEnterKeyExit assignAstNodeTypeStringExit = astVisitorExitKey let assignAstVisitorEnterKeyExit: `${keyof ASTVisitorEnter}:exit` = astNodeTypeExit assignAstVisitorEnterKeyExit = astNodeTypeStringExit assignAstVisitorEnterKeyExit = astVisitorExitKey let assignAstVisitorExitKey: keyof ASTVisitorExit = astNodeTypeExit assignAstVisitorExitKey = astNodeTypeStringExit assignAstVisitorExitKey = astVisitorEnterKeyExit } /* eslint-enable @typescript-eslint/no-unused-vars */