Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@solidity-parser/parser

Package Overview
Dependencies
Maintainers
1
Versions
50
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@solidity-parser/parser - npm Package Compare versions

Comparing version 0.12.1 to 0.13.0-rc.0

dist/antlr/Solidity.tokens

63

package.json
{
"name": "@solidity-parser/parser",
"version": "0.12.1",
"version": "0.13.0-rc.0",
"description": "A Solidity parser built from a robust ANTLR 4 grammar",
"main": "dist/index.cjs.js",
"browser": "dist/index.iife.js",
"browser": {
"fs": false,
"path": false
},
"files": [

@@ -11,12 +14,17 @@ "dist/**/*",

],
"types": "dist/index.d.ts",
"types": "dist/src/index.d.ts",
"scripts": {
"antlr": "sh scripts/antlr.sh",
"build": "rollup -c rollup.config.js",
"antlr": "antlr4ts -visitor antlr/Solidity.g4 -o src",
"build:browser": "esbuild src/index.ts --outfile=dist/index.iife.js --bundle --loader:.tokens=file --sourcemap --format=iife --global-name=SolidityParser --define:__dirname=true --define:BROWSER=true --inject:./process-shim.js",
"build:node": "esbuild src/index.ts --outfile=dist/index.cjs.js --bundle --loader:.tokens=file --sourcemap --format=cjs --platform=node",
"build": "npm run build:node && npm run build:browser && npm run generate-types && npm run copy-files",
"generate-types": "tsc",
"copy-files": "shx mkdir -p dist/antlr && shx cp './src/antlr/*tokens' dist/antlr",
"prettier": "prettier --write 'src/**/*' 'test/**/*'",
"prepack": "npm run build && npm run generate-types",
"eslint": "eslint src",
"lint": "eslint src",
"test": "npm run build && nyc mocha"
"prepack": "npm run build",
"lint": "eslint src test",
"test": "npm run test:node && npm run test:browser",
"test:node": "mocha",
"test:browser": "karma start karma.conf.js",
"test:coverage": "nyc mocha"
},

@@ -36,18 +44,14 @@ "authors": [

"devDependencies": {
"@babel/cli": "^7.12.1",
"@babel/core": "^7.9.0",
"@babel/plugin-proposal-class-properties": "^7.12.1",
"@babel/plugin-transform-typescript": "^7.12.1",
"@babel/preset-env": "^7.12.1",
"@babel/preset-typescript": "^7.12.7",
"@babel/register": "^7.12.1",
"@rollup/plugin-babel": "^5.2.2",
"@rollup/plugin-commonjs": "^17.0.0",
"@rollup/plugin-node-resolve": "^11.0.0",
"@types/chai": "^4.2.16",
"@types/mocha": "^8.2.2",
"@types/node": "^14.14.41",
"@typescript-eslint/eslint-plugin": "^4.9.0",
"@typescript-eslint/parser": "^4.9.0",
"antlr4": "^4.9.0",
"babel-loader": "^8.1.0",
"babel-plugin-inline-import": "^3.0.0",
"antlr4ts": "^0.5.0-alpha.4",
"antlr4ts-cli": "^0.5.0-alpha.4",
"assert": "^2.0.0",
"chai": "^4.2.0",
"esbuild": "^0.11.13",
"esbuild-register": "^2.5.0",
"eslint": "^7.15.0",

@@ -58,16 +62,23 @@ "eslint-plugin-import": "^2.18.2",

"eslint-plugin-standard": "^4.0.1",
"karma": "^6.3.2",
"karma-chrome-launcher": "^3.1.0",
"karma-mocha": "^2.0.1",
"mocha": "^6.2.0",
"nyc": "^14.1.1",
"prettier": "^2.2.1",
"raw-loader": "^4.0.0",
"rollup": "^2.34.2",
"rollup-plugin-node-polyfills": "^0.2.1",
"puppeteer": "^9.0.0",
"shx": "^0.3.3",
"ts-node": "^9.1.1",
"typescript": "^4.1.2",
"util": "^0.12.3",
"yarn": "^1.17.3"
},
"nyc": {
"include": [
"src/*.js"
"extension": [
".ts"
]
},
"volta": {
"node": "14.16.1"
}
}

@@ -6,9 +6,13 @@ // Base on the original type definitions for solidity-parser-antlr 0.2

import { Token } from './types'
interface Location {
start: {
line: number
column: number
}
end: {
line: number
column: number
}
}
export type AST = {
errors?: any[]
tokens?: Token[]
} & ASTNode
export interface BaseASTNode {

@@ -20,98 +24,7 @@ type: ASTNodeTypeString

export type ASTNodeTypeString =
| 'SourceUnit'
| 'PragmaDirective'
| 'PragmaName'
| 'PragmaValue'
| 'ImportDirective'
| 'ContractDefinition'
| 'InheritanceSpecifier'
| 'StateVariableDeclaration'
| 'UsingForDeclaration'
| 'StructDefinition'
| 'ModifierDefinition'
| 'ModifierInvocation'
| 'FunctionDefinition'
| 'EventDefinition'
| 'EnumValue'
| 'EnumDefinition'
| 'VariableDeclaration'
| 'UserDefinedTypeName'
| 'Mapping'
| 'ArrayTypeName'
| 'FunctionTypeName'
| 'StorageLocation'
| 'StateMutability'
| 'Block'
| 'ExpressionStatement'
| 'IfStatement'
| 'WhileStatement'
| 'ForStatement'
| 'InlineAssemblyStatement'
| 'DoWhileStatement'
| 'ContinueStatement'
| 'Break'
| 'Continue'
| 'BreakStatement'
| 'ReturnStatement'
| 'EmitStatement'
| 'ThrowStatement'
| 'VariableDeclarationStatement'
| 'IdentifierList'
| 'ElementaryTypeName'
| 'FunctionCall'
| 'AssemblyBlock'
| 'AssemblyItem'
| 'AssemblyCall'
| 'AssemblyLocalDefinition'
| 'AssemblyAssignment'
| 'AssemblyStackAssignment'
| 'LabelDefinition'
| 'AssemblySwitch'
| 'AssemblyCase'
| 'AssemblyFunctionDefinition'
| 'AssemblyFunctionReturns'
| 'AssemblyFor'
| 'AssemblyIf'
| 'AssemblyLiteral'
| 'SubAssembly'
| 'TupleExpression'
| 'TypeNameExpression'
| 'NameValueExpression'
| 'BooleanLiteral'
| 'NumberLiteral'
| 'Identifier'
| 'BinaryOperation'
| 'UnaryOperation'
| 'NewExpression'
| 'Conditional'
| 'StringLiteral'
| 'HexLiteral'
| 'HexNumber'
| 'DecimalNumber'
| 'MemberAccess'
| 'IndexAccess'
| 'IndexRangeAccess'
| 'NameValueList'
| 'UncheckedStatement'
export interface BaseASTNode {
type: ASTNodeTypeString
range?: [number, number]
loc?: Location
}
export interface SourceUnit extends BaseASTNode {
type: 'SourceUnit'
children: ASTNode[] // TODO: Can be more precise
} // tslint:disable-line:no-empty-interface
export interface PragmaDirective extends BaseASTNode {
type: 'PragmaDirective'
name: string
value: string
children: ASTNode[]
}
export interface ImportDirective extends BaseASTNode {
type: 'ImportDirective'
path: string
unitAlias: string
symbolAliases: Array<[string, string]>
}
export interface ContractDefinition extends BaseASTNode {

@@ -122,4 +35,5 @@ type: 'ContractDefinition'

kind: string
subNodes: ASTNode[] // TODO: Can be more precise
subNodes: BaseASTNode[]
}
export interface InheritanceSpecifier extends BaseASTNode {

@@ -130,10 +44,110 @@ type: 'InheritanceSpecifier'

}
export interface UserDefinedTypeName extends BaseASTNode {
type: 'UserDefinedTypeName'
namePath: string
}
export const astNodeTypes = [
'SourceUnit',
'PragmaDirective',
'ImportDirective',
'ContractDefinition',
'InheritanceSpecifier',
'StateVariableDeclaration',
'UsingForDeclaration',
'StructDefinition',
'ModifierDefinition',
'ModifierInvocation',
'FunctionDefinition',
'EventDefinition',
'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',
'AssemblyFunctionReturns',
'AssemblyFor',
'AssemblyIf',
'SubAssembly',
'TupleExpression',
'TypeNameExpression',
'NameValueExpression',
'BooleanLiteral',
'NumberLiteral',
'Identifier',
'BinaryOperation',
'UnaryOperation',
'NewExpression',
'Conditional',
'StringLiteral',
'HexLiteral',
'HexNumber',
'DecimalNumber',
'MemberAccess',
'IndexAccess',
'IndexRangeAccess',
'NameValueList',
'UncheckedStatement',
'TryStatement',
'CatchClause',
'FileLevelConstant',
'AssemblyMemberAccess',
] 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
unitAlias: string | null
symbolAliases: Array<[string, string | null]> | null
}
export interface StateVariableDeclaration extends BaseASTNode {
type: 'StateVariableDeclaration'
variables: StateVariableDeclarationVariable[]
initialValue?: Expression
initialValue: Expression | null
}
export interface FileLevelConstant extends BaseASTNode {
type: 'FileLevelConstant'
typeName: TypeName
name: string
initialValue: Expression
}
export interface UsingForDeclaration extends BaseASTNode {
type: 'UsingForDeclaration'
typeName: TypeName
typeName: TypeName | null
libraryName: string

@@ -161,10 +175,10 @@ }

type: 'FunctionDefinition'
name?: string
name: string | null
parameters: VariableDeclaration[]
modifiers: ModifierInvocation[]
stateMutability?: 'pure' | 'constant' | 'payable' | 'view'
stateMutability: 'pure' | 'constant' | 'payable' | 'view' | null
visibility: 'default' | 'external' | 'internal' | 'public' | 'private'
returnParameters?: VariableDeclaration[]
body?: Block
override: null | UserDefinedTypeName[]
returnParameters: VariableDeclaration[] | null
body: Block | null
override: UserDefinedTypeName[] | null
isConstructor: boolean

@@ -179,2 +193,3 @@ isReceiveEther: boolean

parameters: VariableDeclaration[]
isAnonymous: boolean
}

@@ -194,7 +209,7 @@ export interface EnumValue extends BaseASTNode {

isStateVar: boolean
typeName: TypeName
name: string
typeName: TypeName | null
name: string | null
isDeclaredConst?: boolean
storageLocation?: string
expression?: Expression
storageLocation: string | null
expression: Expression | null
visibility?: 'public' | 'private' | 'internal' | 'default'

@@ -206,6 +221,2 @@ }

}
export interface UserDefinedTypeName extends BaseASTNode {
type: 'UserDefinedTypeName'
namePath: string
}
export interface ArrayTypeName extends BaseASTNode {

@@ -218,3 +229,3 @@ type: 'ArrayTypeName'

type: 'Mapping'
keyType: ElementaryTypeName
keyType: ElementaryTypeName | UserDefinedTypeName
valueType: TypeName

@@ -224,14 +235,15 @@ }

type: 'FunctionTypeName'
parameterTypes: TypeName[]
returnTypes: TypeName[]
parameterTypes: VariableDeclaration[]
returnTypes: VariableDeclaration[]
visibility: string
stateMutability: string
stateMutability: string | null
}
export interface Block extends BaseASTNode {
type: 'Block'
statements: Statement[]
statements: BaseASTNode[]
}
export interface ExpressionStatement extends BaseASTNode {
type: 'ExpressionStatement'
expression: Expression
expression: Expression | null
}

@@ -242,3 +254,3 @@ export interface IfStatement extends BaseASTNode {

trueBody: Statement
falseBody?: Statement
falseBody: Statement | null
}

@@ -249,4 +261,19 @@ export interface UncheckedStatement extends BaseASTNode {

}
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

@@ -256,5 +283,5 @@ }

type: 'ForStatement'
initExpression?: SimpleStatement
initExpression: SimpleStatement | null
conditionExpression?: Expression
loopExpression?: ExpressionStatement
loopExpression: ExpressionStatement
body: Statement

@@ -264,3 +291,3 @@ }

type: 'InlineAssemblyStatement'
language: string
language: string | null
body: AssemblyBlock

@@ -298,4 +325,4 @@ }

type: 'VariableDeclarationStatement'
variables: ASTNode[]
initialValue?: Expression
variables: Array<BaseASTNode | null>
initialValue: Expression | null
}

@@ -305,2 +332,3 @@ export interface ElementaryTypeName extends BaseASTNode {

name: string
stateMutability: string | null
}

@@ -324,22 +352,35 @@ export interface FunctionCall extends BaseASTNode {

type: 'AssemblyLocalDefinition'
names: Identifier[] | AssemblyMemberAccess[]
expression: AssemblyExpression
}
export interface AssemblyAssignment extends BaseASTNode {
type: 'AssemblyAssignment'
names: Identifier[] | AssemblyMemberAccess[]
expression: AssemblyExpression
names: Identifier[]
}
export interface AssemblyStackAssignment extends BaseASTNode {
type: 'AssemblyStackAssignment'
name: string
}
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
}

@@ -351,12 +392,25 @@ export interface AssemblyFunctionReturns 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 interface AssemblyLiteral extends BaseASTNode {
type: 'AssemblyLiteral'
}
export type AssemblyLiteral =
| StringLiteral
| DecimalNumber
| HexNumber
| HexLiteral
export interface SubAssembly extends BaseASTNode {
type: 'SubAssembly'
}
export interface AssemblyMemberAccess extends BaseASTNode {
type: 'AssemblyMemberAccess'
expression: Identifier
memberName: Identifier
}
export interface NewExpression extends BaseASTNode {

@@ -368,3 +422,3 @@ type: 'NewExpression'

type: 'TupleExpression'
components: Expression[]
components: Array<BaseASTNode | null>
isArray: boolean

@@ -379,3 +433,3 @@ }

expression: Expression
arguments: { [name: string]: Expression }
arguments: NameValueList
}

@@ -417,34 +471,49 @@ export interface NumberLiteral extends BaseASTNode {

}
export type BinOp =
| '+'
| '-'
| '*'
| '/'
| '**'
| '%'
| '<<'
| '>>'
| '&&'
| '||'
| '&'
| '|'
| '^'
| '<'
| '>'
| '<='
| '>='
| '=='
| '!='
| '='
| '|='
| '^='
| '&='
| '<<='
| '>>='
| '+='
| '-='
| '*='
| '/='
| '%='
export type UnaryOp = '-' | '+' | '++' | '~' | 'after' | 'delete' | '!'
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 {

@@ -465,4 +534,4 @@ type: 'BinaryOperation'

condition: Expression
trueExpression: ASTNode
falseExpression: ASTNode
trueExpression: Expression
falseExpression: Expression
}

@@ -496,3 +565,3 @@ export interface IndexAccess extends BaseASTNode {

names: string[]
args: Expression[]
arguments: Expression[]
}

@@ -544,2 +613,7 @@ export type ASTNode =

| Expression
| NameValueList
| AssemblyMemberAccess
| CatchClause
| FileLevelConstant
export type AssemblyItem =

@@ -580,2 +654,4 @@ | Identifier

| BooleanLiteral
| HexLiteral
| StringLiteral
| NumberLiteral

@@ -607,1 +683,204 @@ | Identifier

| UncheckedStatement
| TryStatement
interface ASTVisitorEnter {
SourceUnit?: (node: SourceUnit) => any
PragmaDirective?: (node: PragmaDirective) => any
ImportDirective?: (node: ImportDirective) => any
ContractDefinition?: (node: ContractDefinition) => any
InheritanceSpecifier?: (node: InheritanceSpecifier) => any
StateVariableDeclaration?: (node: StateVariableDeclaration) => any
UsingForDeclaration?: (node: UsingForDeclaration) => any
StructDefinition?: (node: StructDefinition) => any
ModifierDefinition?: (node: ModifierDefinition) => any
ModifierInvocation?: (node: ModifierInvocation) => any
FunctionDefinition?: (node: FunctionDefinition) => any
EventDefinition?: (node: EventDefinition) => any
EnumValue?: (node: EnumValue) => any
EnumDefinition?: (node: EnumDefinition) => any
VariableDeclaration?: (node: VariableDeclaration) => any
UserDefinedTypeName?: (node: UserDefinedTypeName) => any
Mapping?: (node: Mapping) => any
ArrayTypeName?: (node: ArrayTypeName) => any
FunctionTypeName?: (node: FunctionTypeName) => any
Block?: (node: Block) => any
ExpressionStatement?: (node: ExpressionStatement) => any
IfStatement?: (node: IfStatement) => any
WhileStatement?: (node: WhileStatement) => any
ForStatement?: (node: ForStatement) => any
InlineAssemblyStatement?: (node: InlineAssemblyStatement) => any
DoWhileStatement?: (node: DoWhileStatement) => any
ContinueStatement?: (node: ContinueStatement) => any
Break?: (node: Break) => any
Continue?: (node: Continue) => any
BreakStatement?: (node: BreakStatement) => any
ReturnStatement?: (node: ReturnStatement) => any
EmitStatement?: (node: EmitStatement) => any
ThrowStatement?: (node: ThrowStatement) => any
VariableDeclarationStatement?: (node: VariableDeclarationStatement) => any
ElementaryTypeName?: (node: ElementaryTypeName) => any
FunctionCall?: (node: FunctionCall) => any
AssemblyBlock?: (node: AssemblyBlock) => any
AssemblyCall?: (node: AssemblyCall) => any
AssemblyLocalDefinition?: (node: AssemblyLocalDefinition) => any
AssemblyAssignment?: (node: AssemblyAssignment) => any
AssemblyStackAssignment?: (node: AssemblyStackAssignment) => any
LabelDefinition?: (node: LabelDefinition) => any
AssemblySwitch?: (node: AssemblySwitch) => any
AssemblyCase?: (node: AssemblyCase) => any
AssemblyFunctionDefinition?: (node: AssemblyFunctionDefinition) => any
AssemblyFunctionReturns?: (node: AssemblyFunctionReturns) => any
AssemblyFor?: (node: AssemblyFor) => any
AssemblyIf?: (node: AssemblyIf) => any
SubAssembly?: (node: SubAssembly) => any
TupleExpression?: (node: TupleExpression) => any
TypeNameExpression?: (node: TypeNameExpression) => any
NameValueExpression?: (node: NameValueExpression) => any
BooleanLiteral?: (node: BooleanLiteral) => any
NumberLiteral?: (node: NumberLiteral) => any
Identifier?: (node: Identifier) => any
BinaryOperation?: (node: BinaryOperation) => any
UnaryOperation?: (node: UnaryOperation) => any
NewExpression?: (node: NewExpression) => any
Conditional?: (node: Conditional) => any
StringLiteral?: (node: StringLiteral) => any
HexLiteral?: (node: HexLiteral) => any
HexNumber?: (node: HexNumber) => any
DecimalNumber?: (node: DecimalNumber) => any
MemberAccess?: (node: MemberAccess) => any
IndexAccess?: (node: IndexAccess) => any
IndexRangeAccess?: (node: IndexRangeAccess) => any
NameValueList?: (node: NameValueList) => any
UncheckedStatement?: (node: UncheckedStatement) => any
TryStatement?: (node: TryStatement) => any
CatchClause?: (node: CatchClause) => any
FileLevelConstant?: (node: FileLevelConstant) => any
AssemblyMemberAccess?: (node: AssemblyMemberAccess) => any
}
interface ASTVisitorExit {
'SourceUnit:exit'?: (node: SourceUnit) => any
'PragmaDirective:exit'?: (node: PragmaDirective) => any
'ImportDirective:exit'?: (node: ImportDirective) => any
'ContractDefinition:exit'?: (node: ContractDefinition) => any
'InheritanceSpecifier:exit'?: (node: InheritanceSpecifier) => any
'StateVariableDeclaration:exit'?: (node: StateVariableDeclaration) => any
'UsingForDeclaration:exit'?: (node: UsingForDeclaration) => any
'StructDefinition:exit'?: (node: StructDefinition) => any
'ModifierDefinition:exit'?: (node: ModifierDefinition) => any
'ModifierInvocation:exit'?: (node: ModifierInvocation) => any
'FunctionDefinition:exit'?: (node: FunctionDefinition) => any
'EventDefinition:exit'?: (node: EventDefinition) => any
'EnumValue:exit'?: (node: EnumValue) => any
'EnumDefinition:exit'?: (node: EnumDefinition) => any
'VariableDeclaration:exit'?: (node: VariableDeclaration) => any
'UserDefinedTypeName:exit'?: (node: UserDefinedTypeName) => any
'Mapping:exit'?: (node: Mapping) => any
'ArrayTypeName:exit'?: (node: ArrayTypeName) => any
'FunctionTypeName:exit'?: (node: FunctionTypeName) => any
'Block:exit'?: (node: Block) => any
'ExpressionStatement:exit'?: (node: ExpressionStatement) => any
'IfStatement:exit'?: (node: IfStatement) => any
'WhileStatement:exit'?: (node: WhileStatement) => any
'ForStatement:exit'?: (node: ForStatement) => any
'InlineAssemblyStatement:exit'?: (node: InlineAssemblyStatement) => any
'DoWhileStatement:exit'?: (node: DoWhileStatement) => any
'ContinueStatement:exit'?: (node: ContinueStatement) => any
'Break:exit'?: (node: Break) => any
'Continue:exit'?: (node: Continue) => any
'BreakStatement:exit'?: (node: BreakStatement) => any
'ReturnStatement:exit'?: (node: ReturnStatement) => any
'EmitStatement:exit'?: (node: EmitStatement) => any
'ThrowStatement:exit'?: (node: ThrowStatement) => any
'VariableDeclarationStatement:exit'?: (
node: VariableDeclarationStatement
) => any
'ElementaryTypeName:exit'?: (node: ElementaryTypeName) => any
'FunctionCall:exit'?: (node: FunctionCall) => any
'AssemblyBlock:exit'?: (node: AssemblyBlock) => any
'AssemblyCall:exit'?: (node: AssemblyCall) => any
'AssemblyLocalDefinition:exit'?: (node: AssemblyLocalDefinition) => any
'AssemblyAssignment:exit'?: (node: AssemblyAssignment) => any
'AssemblyStackAssignment:exit'?: (node: AssemblyStackAssignment) => any
'LabelDefinition:exit'?: (node: LabelDefinition) => any
'AssemblySwitch:exit'?: (node: AssemblySwitch) => any
'AssemblyCase:exit'?: (node: AssemblyCase) => any
'AssemblyFunctionDefinition:exit'?: (node: AssemblyFunctionDefinition) => any
'AssemblyFunctionReturns:exit'?: (node: AssemblyFunctionReturns) => any
'AssemblyFor:exit'?: (node: AssemblyFor) => any
'AssemblyIf:exit'?: (node: AssemblyIf) => any
'SubAssembly:exit'?: (node: SubAssembly) => any
'TupleExpression:exit'?: (node: TupleExpression) => any
'TypeNameExpression:exit'?: (node: TypeNameExpression) => any
'NameValueExpression:exit'?: (node: NameValueExpression) => any
'BooleanLiteral:exit'?: (node: BooleanLiteral) => any
'NumberLiteral:exit'?: (node: NumberLiteral) => any
'Identifier:exit'?: (node: Identifier) => any
'BinaryOperation:exit'?: (node: BinaryOperation) => any
'UnaryOperation:exit'?: (node: UnaryOperation) => any
'NewExpression:exit'?: (node: NewExpression) => any
'Conditional:exit'?: (node: Conditional) => any
'StringLiteral:exit'?: (node: StringLiteral) => any
'HexLiteral:exit'?: (node: HexLiteral) => any
'HexNumber:exit'?: (node: HexNumber) => any
'DecimalNumber:exit'?: (node: DecimalNumber) => any
'MemberAccess:exit'?: (node: MemberAccess) => any
'IndexAccess:exit'?: (node: IndexAccess) => any
'IndexRangeAccess:exit'?: (node: IndexRangeAccess) => any
'NameValueList:exit'?: (node: NameValueList) => any
'UncheckedStatement:exit'?: (node: UncheckedStatement) => any
'TryStatement:exit'?: (node: TryStatement) => any
'CatchClause:exit'?: (node: CatchClause) => any
'FileLevelConstant:exit'?: (node: FileLevelConstant) => any
'AssemblyMemberAccess:exit'?: (node: AssemblyMemberAccess) => 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 */

@@ -1,161 +0,273 @@

import antlr4 from 'antlr4'
import { ParserRuleContext } from 'antlr4ts'
import { AbstractParseTreeVisitor } from 'antlr4ts/tree/AbstractParseTreeVisitor'
import { ParseTree } from 'antlr4ts/tree/ParseTree'
import * as SP from './antlr/SolidityParser'
import { SolidityVisitor } from './antlr/SolidityVisitor'
import { ParseOptions } from './types'
import * as ASTTypes from './ast-types'
import { BaseASTNode } from './ast-types'
import * as AST from './ast-types'
type Ctx = any
function toText(ctx: Ctx | null) {
if (ctx !== null) {
return ctx.getText()
interface SourceLocation {
start: {
line: number
column: number
}
return null
end: {
line: number
column: number
}
}
function mapCommasToNulls(children: Ctx[]) {
if (children.length === 0) {
return []
export class ASTBuilder
extends AbstractParseTreeVisitor<AST.ASTNode>
implements SolidityVisitor<AST.ASTNode | AST.ASTNode[]> {
public result: AST.SourceUnit | null = null
private _currentContract?: string
constructor(public options: ParseOptions) {
super()
}
const values = []
let comma = true
defaultResult() {
return ({ type: '' } as unknown) as AST.ASTNode
}
for (const el of children) {
if (comma) {
if (toText(el) === ',') {
values.push(null)
} else {
values.push(el)
comma = false
}
} else {
if (toText(el) !== ',') {
throw new Error('expected comma')
}
comma = true
aggregateResult() {
return ({ type: '' } as unknown) as AST.ASTNode
}
public visitSourceUnit(ctx: SP.SourceUnitContext): AST.SourceUnit {
const children = ctx.children ?? []
const node: AST.SourceUnit = {
type: 'SourceUnit',
children: children.slice(0, -1).map((child) => this.visit(child)),
}
this.result = this._addMeta(node, ctx)
return this.result
}
if (comma) {
values.push(null)
public visitContractPart(ctx: SP.ContractPartContext) {
return this.visit(ctx.getChild(0))
}
return values
}
public visitContractDefinition(
ctx: SP.ContractDefinitionContext
): AST.ContractDefinition {
const name = this._toText(ctx.identifier())
const kind = this._toText(ctx.getChild(0))
function isBinOp(op: string): boolean {
const binOps = [
'+',
'-',
'*',
'/',
'**',
'%',
'<<',
'>>',
'&&',
'||',
'&',
'|',
'^',
'<',
'>',
'<=',
'>=',
'==',
'!=',
'=',
'|=',
'^=',
'&=',
'<<=',
'>>=',
'+=',
'-=',
'*=',
'/=',
'%=',
]
return binOps.includes(op)
}
this._currentContract = name
const transformAST = {
SourceUnit(ctx: Ctx): ASTTypes.SourceUnit {
// last element is EOF terminal node
return {
type: 'SourceUnit',
children: (this as any).visit(ctx.children.slice(0, -1)),
const node: AST.ContractDefinition = {
type: 'ContractDefinition',
name,
baseContracts: ctx
.inheritanceSpecifier()
.map((x) => this.visitInheritanceSpecifier(x)),
subNodes: ctx.contractPart().map((x) => this.visit(x)),
kind,
}
},
EnumDefinition(ctx: Ctx): ASTTypes.EnumDefinition {
return {
type: 'EnumDefinition',
name: toText(ctx.identifier()),
members: (this as any).visit(ctx.enumValue()),
return this._addMeta(node, ctx)
}
public visitStateVariableDeclaration(
ctx: SP.StateVariableDeclarationContext
) {
const type = this.visitTypeName(ctx.typeName())
const iden = ctx.identifier()
const name = this._toText(iden)
let expression: AST.Expression | null = null
const ctxExpression = ctx.expression()
if (ctxExpression) {
expression = this.visitExpression(ctxExpression)
}
},
EnumValue(ctx: Ctx) {
return {
name: toText(ctx.identifier()),
let visibility: AST.VariableDeclaration['visibility'] = 'default'
if (ctx.InternalKeyword().length > 0) {
visibility = 'internal'
} else if (ctx.PublicKeyword().length > 0) {
visibility = 'public'
} else if (ctx.PrivateKeyword().length > 0) {
visibility = 'private'
}
},
UsingForDeclaration(ctx: Ctx) {
let typeName = null
if (toText(ctx.getChild(3)) !== '*') {
typeName = (this as any).visit(ctx.getChild(3))
let isDeclaredConst = false
if (ctx.ConstantKeyword().length > 0) {
isDeclaredConst = true
}
return {
typeName,
libraryName: toText(ctx.identifier()),
let override
const overrideSpecifier = ctx.overrideSpecifier()
if (overrideSpecifier.length === 0) {
override = null
} else {
override = overrideSpecifier[0]
.userDefinedTypeName()
.map((x) => this.visitUserDefinedTypeName(x))
}
},
PragmaDirective(ctx: Ctx) {
// this converts something like >= 0.5.0 <0.7.0
// in >=0.5.0 <0.7.0
const value = ctx
.pragmaValue()
.children[0].children.map((x: any) => toText(x))
.join(' ')
let isImmutable = false
if (ctx.ImmutableKeyword().length > 0) {
isImmutable = true
}
return {
name: toText(ctx.pragmaName()),
value,
const decl: AST.StateVariableDeclarationVariable = {
type: 'VariableDeclaration',
typeName: type,
name,
expression,
visibility,
isStateVar: true,
isDeclaredConst,
isIndexed: false,
isImmutable,
override,
storageLocation: null,
}
},
ContractDefinition(ctx: Ctx) {
const name = toText(ctx.identifier())
const kind = toText(ctx.getChild(0))
const node: AST.StateVariableDeclaration = {
type: 'StateVariableDeclaration',
variables: [this._addMeta(decl, ctx)],
initialValue: expression,
}
;(this as any)._currentContract = name
return this._addMeta(node, ctx)
}
return {
name,
baseContracts: (this as any).visit(ctx.inheritanceSpecifier()),
subNodes: (this as any).visit(ctx.contractPart()),
kind,
public visitVariableDeclaration(
ctx: SP.VariableDeclarationContext
): AST.VariableDeclaration {
let storageLocation: string | null = null
const ctxStorageLocation = ctx.storageLocation()
if (ctxStorageLocation) {
storageLocation = this._toText(ctxStorageLocation)
}
},
InheritanceSpecifier(ctx: Ctx) {
const exprList = ctx.expressionList()
const args =
exprList != null ? (this as any).visit(exprList.expression()) : []
const node: AST.VariableDeclaration = {
type: 'VariableDeclaration',
typeName: this.visitTypeName(ctx.typeName()),
name: this._toText(ctx.identifier()),
storageLocation,
isStateVar: false,
isIndexed: false,
expression: null,
}
return {
baseName: (this as any).visit(ctx.userDefinedTypeName()),
arguments: args,
return this._addMeta(node, ctx)
}
public visitVariableDeclarationStatement(
ctx: SP.VariableDeclarationStatementContext
): AST.VariableDeclarationStatement {
let variables: Array<AST.BaseASTNode | null> = []
const ctxVariableDeclaration = ctx.variableDeclaration()
const ctxIdentifierList = ctx.identifierList()
const ctxVariableDeclarationList = ctx.variableDeclarationList()
if (ctxVariableDeclaration !== undefined) {
variables = [this.visitVariableDeclaration(ctxVariableDeclaration)]
} else if (ctxIdentifierList !== undefined) {
variables = this.buildIdentifierList(ctxIdentifierList)
} else if (ctxVariableDeclarationList) {
variables = this.buildVariableDeclarationList(ctxVariableDeclarationList)
}
},
ContractPart(ctx: Ctx) {
return (this as any).visit(ctx.children[0])
},
let initialValue: AST.Expression | null = null
const ctxExpression = ctx.expression()
if (ctxExpression) {
initialValue = this.visitExpression(ctxExpression)
}
FunctionDefinition(ctx: Ctx) {
const node: AST.VariableDeclarationStatement = {
type: 'VariableDeclarationStatement',
variables,
initialValue,
}
return this._addMeta(node, ctx)
}
public visitStatement(ctx: SP.StatementContext) {
return this.visit(ctx.getChild(0)) as AST.Statement
}
public visitSimpleStatement(ctx: SP.SimpleStatementContext) {
return this.visit(ctx.getChild(0)) as AST.SimpleStatement
}
public visitEventDefinition(ctx: SP.EventDefinitionContext) {
const parameters = ctx
.eventParameterList()
.eventParameter()
.map((paramCtx) => {
const type = this.visitTypeName(paramCtx.typeName())
let name: string | null = null
const paramCtxIdentifier = paramCtx.identifier()
if (paramCtxIdentifier) {
name = this._toText(paramCtxIdentifier)
}
const node: AST.VariableDeclaration = {
type: 'VariableDeclaration',
typeName: type,
name,
isStateVar: false,
isIndexed: paramCtx.IndexedKeyword() !== undefined,
storageLocation: null,
expression: null,
}
return this._addMeta(node, paramCtx)
})
const node: AST.EventDefinition = {
type: 'EventDefinition',
name: this._toText(ctx.identifier()),
parameters,
isAnonymous: ctx.AnonymousKeyword() !== undefined,
}
return this._addMeta(node, ctx)
}
public visitBlock(ctx: SP.BlockContext): AST.Block {
const node: AST.Block = {
type: 'Block',
statements: ctx.statement().map((x) => this.visitStatement(x)),
}
return this._addMeta(node, ctx)
}
public visitParameter(ctx: SP.ParameterContext) {
let storageLocation: string | null = null
const ctxStorageLocation = ctx.storageLocation()
if (ctxStorageLocation !== undefined) {
storageLocation = this._toText(ctxStorageLocation)
}
let name: string | null = null
const ctxIdentifier = ctx.identifier()
if (ctxIdentifier !== undefined) {
name = this._toText(ctxIdentifier)
}
const node: AST.VariableDeclaration = {
type: 'VariableDeclaration',
typeName: this.visitTypeName(ctx.typeName()),
name,
storageLocation,
isStateVar: false,
isIndexed: false,
expression: null,
}
return this._addMeta(node, ctx)
}
public visitFunctionDefinition(
ctx: SP.FunctionDefinitionContext
): AST.FunctionDefinition {
let isConstructor = false

@@ -165,10 +277,11 @@ let isFallback = false

let isVirtual = false
let name = null
let parameters = []
let returnParameters = null
let visibility = 'default'
let name: string | null = null
let parameters: any = []
let returnParameters: AST.VariableDeclaration[] | null = null
let visibility: AST.FunctionDefinition['visibility'] = 'default'
let block = null
if (ctx.block()) {
block = (this as any).visit(ctx.block())
let block: AST.Block | null = null
const ctxBlock = ctx.block()
if (ctxBlock !== undefined) {
block = this.visitBlock(ctxBlock)
}

@@ -179,25 +292,24 @@

.modifierInvocation()
.map((mod: any) => (this as any).visit(mod))
.map((mod) => this.visitModifierInvocation(mod))
let stateMutability = null
if (ctx.modifierList().stateMutability(0)) {
stateMutability = toText(ctx.modifierList().stateMutability(0))
if (ctx.modifierList().stateMutability().length > 0) {
stateMutability = this._stateMutabilityToText(
ctx.modifierList().stateMutability(0)
)
}
// see what type of function we're dealing with
switch (toText(ctx.functionDescriptor().getChild(0))) {
const ctxReturnParameters = ctx.returnParameters()
switch (this._toText(ctx.functionDescriptor().getChild(0))) {
case 'constructor':
parameters = (this as any).visit(ctx.parameterList())
parameters = ctx
.parameterList()
.parameter()
.map((x) => this.visit(x))
if (
ctx.returnParameters() &&
ctx.returnParameters().parameterList().parameter().length > 0
) {
throw new Error('Constructors cannot have return parameters')
}
// error out on incorrect function visibility
if (ctx.modifierList().InternalKeyword(0)) {
if (ctx.modifierList().InternalKeyword().length > 0) {
visibility = 'internal'
} else if (ctx.modifierList().PublicKeyword(0)) {
} else if (ctx.modifierList().PublicKeyword().length > 0) {
visibility = 'public'

@@ -211,71 +323,30 @@ } else {

case 'fallback':
if (ctx.parameterList().parameter().length > 0) {
throw new Error('Fallback functions cannot have parameters')
}
if (
ctx.returnParameters() &&
ctx.returnParameters().parameterList().parameter().length > 0
) {
throw new Error('Fallback functions cannot have return parameters')
}
// error out on incorrect function visibility
if (!ctx.modifierList().ExternalKeyword(0)) {
throw new Error('Fallback functions have to be declared "external"')
}
visibility = 'external'
isFallback = true
break
case 'receive':
if (ctx.parameterList().parameter().length > 0) {
throw new Error('Receive Ether functions cannot have parameters')
}
if (
ctx.returnParameters() &&
ctx.returnParameters().parameterList().parameter().length > 0
) {
throw new Error(
'Receive Ether functions cannot have return parameters'
)
}
// error out on incorrect function visibility
if (!ctx.modifierList().ExternalKeyword(0)) {
throw new Error(
'Receive Ether functions have to be declared "external"'
)
}
visibility = 'external'
// error out on incorrect function payability
if (
!ctx.modifierList().stateMutability(0) ||
!ctx.modifierList().stateMutability(0).PayableKeyword(0)
) {
throw new Error(
'Receive Ether functions have to be declared "payable"'
)
}
isReceiveEther = true
break
case 'function':
name = ctx.functionDescriptor().identifier(0)
? toText(ctx.functionDescriptor().identifier(0))
: ''
case 'function': {
const identifier = ctx.functionDescriptor().identifier()
name = identifier !== undefined ? this._toText(identifier) : ''
parameters = (this as any).visit(ctx.parameterList())
returnParameters = (this as any).visit(ctx.returnParameters())
parameters = ctx
.parameterList()
.parameter()
.map((x) => this.visit(x))
returnParameters =
ctxReturnParameters !== undefined
? this.visitReturnParameters(ctxReturnParameters)
: null
// parse function visibility
if (ctx.modifierList().ExternalKeyword(0)) {
if (ctx.modifierList().ExternalKeyword().length > 0) {
visibility = 'external'
} else if (ctx.modifierList().InternalKeyword(0)) {
} else if (ctx.modifierList().InternalKeyword().length > 0) {
visibility = 'internal'
} else if (ctx.modifierList().PublicKeyword(0)) {
} else if (ctx.modifierList().PublicKeyword().length > 0) {
visibility = 'public'
} else if (ctx.modifierList().PrivateKeyword(0)) {
} else if (ctx.modifierList().PrivateKeyword().length > 0) {
visibility = 'private'

@@ -285,12 +356,13 @@ }

// check if function is virtual
if (ctx.modifierList().VirtualKeyword(0)) {
if (ctx.modifierList().VirtualKeyword().length > 0) {
isVirtual = true
}
isConstructor = name === (this as any)._currentContract
isConstructor = name === this._currentContract
isFallback = name === ''
break
}
}
let override
let override: AST.UserDefinedTypeName[] | null
const overrideSpecifier = ctx.modifierList().overrideSpecifier()

@@ -300,6 +372,9 @@ if (overrideSpecifier.length === 0) {

} else {
override = (this as any).visit(overrideSpecifier[0].userDefinedTypeName())
override = overrideSpecifier[0]
.userDefinedTypeName()
.map((x) => this.visitUserDefinedTypeName(x))
}
return {
const node: AST.FunctionDefinition = {
type: 'FunctionDefinition',
name,

@@ -318,62 +393,223 @@ parameters,

}
},
ModifierInvocation(ctx: Ctx) {
const exprList = ctx.expressionList()
return this._addMeta(node, ctx)
}
let args
if (exprList != null) {
args = (this as any).visit(exprList.expression())
} else if (ctx.children.length > 1) {
args = []
} else {
args = null
public visitEnumDefinition(
ctx: SP.EnumDefinitionContext
): AST.EnumDefinition {
const node: AST.EnumDefinition = {
type: 'EnumDefinition',
name: this._toText(ctx.identifier()),
members: ctx.enumValue().map((x) => this.visitEnumValue(x)),
}
return {
name: toText(ctx.identifier()),
arguments: args,
return this._addMeta(node, ctx)
}
public visitEnumValue(ctx: SP.EnumValueContext): AST.EnumValue {
const node: AST.EnumValue = {
type: 'EnumValue',
name: this._toText(ctx.identifier()),
}
},
return this._addMeta(node, ctx)
}
TypeNameExpression(ctx: Ctx) {
let typeName = ctx.elementaryTypeName()
if (!typeName) {
typeName = ctx.userDefinedTypeName()
public visitElementaryTypeName(
ctx: SP.ElementaryTypeNameContext
): AST.ElementaryTypeName {
const node: AST.ElementaryTypeName = {
type: 'ElementaryTypeName',
name: this._toText(ctx),
stateMutability: null,
}
return {
typeName: (this as any).visit(typeName),
return this._addMeta(node, ctx)
}
public visitIdentifier(ctx: SP.IdentifierContext): AST.Identifier {
const node: AST.Identifier = {
type: 'Identifier',
name: this._toText(ctx),
}
},
return this._addMeta(node, ctx)
}
TypeName(ctx: Ctx) {
if (ctx.children.length > 2) {
public visitTypeName(ctx: SP.TypeNameContext): AST.TypeName {
if (ctx.children !== undefined && ctx.children.length > 2) {
let length = null
if (ctx.children.length === 4) {
length = (this as any).visit(ctx.getChild(2))
const expression = ctx.expression()
if (expression === undefined) {
throw new Error(
'Assertion error: a typeName with 4 children should have an expression'
)
}
length = this.visitExpression(expression)
}
return {
const ctxTypeName = ctx.typeName()
const node: AST.ArrayTypeName = {
type: 'ArrayTypeName',
baseTypeName: (this as any).visit(ctx.typeName()),
baseTypeName: this.visitTypeName(ctxTypeName!),
length,
}
return this._addMeta(node, ctx)
}
if (ctx.children.length === 2) {
return {
if (ctx.children?.length === 2) {
const node: AST.ElementaryTypeName = {
type: 'ElementaryTypeName',
name: toText(ctx.getChild(0)),
stateMutability: toText(ctx.getChild(1)),
name: this._toText(ctx.getChild(0)),
stateMutability: this._toText(ctx.getChild(1)),
}
return this._addMeta(node, ctx)
}
return (this as any).visit(ctx.getChild(0))
},
FunctionTypeName(ctx: Ctx) {
if (ctx.elementaryTypeName() !== undefined) {
return this.visitElementaryTypeName(ctx.elementaryTypeName()!)
}
if (ctx.userDefinedTypeName() !== undefined) {
return this.visitUserDefinedTypeName(ctx.userDefinedTypeName()!)
}
if (ctx.mapping() !== undefined) {
return this.visitMapping(ctx.mapping()!)
}
if (ctx.functionTypeName() !== undefined) {
return this.visitFunctionTypeName(ctx.functionTypeName()!)
}
throw new Error('Assertion error: unhandled type name case')
}
public visitUserDefinedTypeName(
ctx: SP.UserDefinedTypeNameContext
): AST.UserDefinedTypeName {
const node: AST.UserDefinedTypeName = {
type: 'UserDefinedTypeName',
namePath: this._toText(ctx),
}
return this._addMeta(node, ctx)
}
public visitUsingForDeclaration(
ctx: SP.UsingForDeclarationContext
): AST.UsingForDeclaration {
let typeName = null
const ctxTypeName = ctx.typeName()
if (ctxTypeName !== undefined) {
typeName = this.visitTypeName(ctxTypeName)
}
const node: AST.UsingForDeclaration = {
type: 'UsingForDeclaration',
typeName,
libraryName: this._toText(ctx.identifier()),
}
return this._addMeta(node, ctx)
}
public visitPragmaDirective(
ctx: SP.PragmaDirectiveContext
): AST.PragmaDirective {
// this converts something like >= 0.5.0 <0.7.0
// in >=0.5.0 <0.7.0
const versionContext = ctx.pragmaValue().version()
let value = ''
if (versionContext?.children !== undefined) {
value = versionContext.children.map((x) => this._toText(x)).join(' ')
}
const node: AST.PragmaDirective = {
type: 'PragmaDirective',
name: this._toText(ctx.pragmaName()),
value,
}
return this._addMeta(node, ctx)
}
public visitInheritanceSpecifier(
ctx: SP.InheritanceSpecifierContext
): AST.InheritanceSpecifier {
const exprList = ctx.expressionList()
const args =
exprList !== undefined
? exprList.expression().map((x) => this.visitExpression(x))
: []
const node: AST.InheritanceSpecifier = {
type: 'InheritanceSpecifier',
baseName: this.visitUserDefinedTypeName(ctx.userDefinedTypeName()),
arguments: args,
}
return this._addMeta(node, ctx)
}
public visitModifierInvocation(
ctx: SP.ModifierInvocationContext
): AST.ModifierInvocation {
const exprList = ctx.expressionList()
let args
if (exprList != null) {
args = exprList.expression().map((x) => this.visit(x))
} else if (ctx.children !== undefined && ctx.children.length > 1) {
args = []
} else {
args = null
}
const node: AST.ModifierInvocation = {
type: 'ModifierInvocation',
name: this._toText(ctx.identifier()),
arguments: args,
}
return this._addMeta(node, ctx)
}
public visitTypeNameExpression(
ctx: SP.TypeNameExpressionContext
): AST.TypeNameExpression {
const ctxElementaryTypeName = ctx.elementaryTypeName()
const ctxUserDefinedTypeName = ctx.userDefinedTypeName()
let typeName
if (ctxElementaryTypeName !== undefined) {
typeName = this.visitElementaryTypeName(ctxElementaryTypeName)
} else if (ctxUserDefinedTypeName !== undefined) {
typeName = this.visitUserDefinedTypeName(ctxUserDefinedTypeName)
} else {
throw new Error(
'Assertion error: either elementaryTypeName or userDefinedTypeName should be defined'
)
}
const node: AST.TypeNameExpression = {
type: 'TypeNameExpression',
typeName,
}
return this._addMeta(node, ctx)
}
public visitFunctionTypeName(
ctx: SP.FunctionTypeNameContext
): AST.FunctionTypeName {
const parameterTypes = ctx
.functionTypeParameterList(0)
.functionTypeParameter()
.map((typeCtx: any) => (this as any).visit(typeCtx))
.map((typeCtx) => this.visitFunctionTypeParameter(typeCtx))
let returnTypes = []
let returnTypes: AST.VariableDeclaration[] = []
if (ctx.functionTypeParameterList(1)) {

@@ -383,9 +619,9 @@ returnTypes = ctx

.functionTypeParameter()
.map((typeCtx: any) => (this as any).visit(typeCtx))
.map((typeCtx) => this.visitFunctionTypeParameter(typeCtx))
}
let visibility = 'default'
if (ctx.InternalKeyword(0)) {
if (ctx.InternalKeyword().length > 0) {
visibility = 'internal'
} else if (ctx.ExternalKeyword(0)) {
} else if (ctx.ExternalKeyword().length > 0) {
visibility = 'external'

@@ -395,7 +631,8 @@ }

let stateMutability = null
if (ctx.stateMutability(0)) {
stateMutability = toText(ctx.stateMutability(0))
if (ctx.stateMutability().length > 0) {
stateMutability = this._toText(ctx.stateMutability(0))
}
return {
const node: AST.FunctionTypeName = {
type: 'FunctionTypeName',
parameterTypes,

@@ -406,130 +643,152 @@ returnTypes,

}
},
ReturnStatement(ctx: Ctx) {
return this._addMeta(node, ctx)
}
public visitFunctionTypeParameter(
ctx: SP.FunctionTypeParameterContext
): AST.VariableDeclaration {
let storageLocation = null
if (ctx.storageLocation()) {
storageLocation = this._toText(ctx.storageLocation()!)
}
const node: AST.VariableDeclaration = {
type: 'VariableDeclaration',
typeName: this.visitTypeName(ctx.typeName()),
name: null,
storageLocation,
isStateVar: false,
isIndexed: false,
expression: null,
}
return this._addMeta(node, ctx)
}
public visitThrowStatement(
ctx: SP.ThrowStatementContext
): AST.ThrowStatement {
const node: AST.ThrowStatement = {
type: 'ThrowStatement',
}
return this._addMeta(node, ctx)
}
public visitReturnStatement(
ctx: SP.ReturnStatementContext
): AST.ReturnStatement {
let expression = null
if (ctx.expression()) {
expression = (this as any).visit(ctx.expression())
const ctxExpression = ctx.expression()
if (ctxExpression) {
expression = this.visitExpression(ctxExpression)
}
return { expression }
},
const node: AST.ReturnStatement = {
type: 'ReturnStatement',
expression,
}
EmitStatement(ctx: Ctx) {
return {
eventCall: (this as any).visit(ctx.functionCall()),
return this._addMeta(node, ctx)
}
public visitEmitStatement(ctx: SP.EmitStatementContext): AST.EmitStatement {
const node: AST.EmitStatement = {
type: 'EmitStatement',
eventCall: this.visitFunctionCall(ctx.functionCall()),
}
},
FunctionCall(ctx: Ctx) {
let args = []
return this._addMeta(node, ctx)
}
public visitFunctionCall(ctx: SP.FunctionCallContext): AST.FunctionCall {
let args: AST.Expression[] = []
const names = []
const ctxArgs = ctx.functionCallArguments()
if (ctxArgs.expressionList()) {
args = ctxArgs
.expressionList()
const ctxArgsExpressionList = ctxArgs.expressionList()
const ctxArgsNameValueList = ctxArgs.nameValueList()
if (ctxArgsExpressionList) {
args = ctxArgsExpressionList
.expression()
.map((exprCtx: any) => (this as any).visit(exprCtx))
} else if (ctxArgs.nameValueList()) {
for (const nameValue of ctxArgs.nameValueList().nameValue()) {
args.push((this as any).visit(nameValue.expression()))
names.push(toText(nameValue.identifier()))
.map((exprCtx) => this.visitExpression(exprCtx))
} else if (ctxArgsNameValueList) {
for (const nameValue of ctxArgsNameValueList.nameValue()) {
args.push(this.visitExpression(nameValue.expression()))
names.push(this._toText(nameValue.identifier()))
}
}
return {
expression: (this as any).visit(ctx.expression()),
const node: AST.FunctionCall = {
type: 'FunctionCall',
expression: this.visitExpression(ctx.expression()),
arguments: args,
names,
}
},
StructDefinition(ctx: Ctx) {
return {
name: toText(ctx.identifier()),
members: (this as any).visit(ctx.variableDeclaration()),
}
},
return this._addMeta(node, ctx)
}
VariableDeclaration(ctx: Ctx) {
let storageLocation = null
if (ctx.storageLocation()) {
storageLocation = toText(ctx.storageLocation())
public visitStructDefinition(
ctx: SP.StructDefinitionContext
): AST.StructDefinition {
const node: AST.StructDefinition = {
type: 'StructDefinition',
name: this._toText(ctx.identifier()),
members: ctx
.variableDeclaration()
.map((x) => this.visitVariableDeclaration(x)),
}
return {
typeName: (this as any).visit(ctx.typeName()),
name: toText(ctx.identifier()),
storageLocation,
isStateVar: false,
isIndexed: false,
}
},
return this._addMeta(node, ctx)
}
EventParameter(ctx: Ctx) {
let storageLocation = null
if (ctx.storageLocation(0)) {
storageLocation = toText(ctx.storageLocation(0))
public visitWhileStatement(
ctx: SP.WhileStatementContext
): AST.WhileStatement {
const node: AST.WhileStatement = {
type: 'WhileStatement',
condition: this.visitExpression(ctx.expression()),
body: this.visitStatement(ctx.statement()),
}
return {
type: 'VariableDeclaration',
typeName: (this as any).visit(ctx.typeName()),
name: toText(ctx.identifier()),
storageLocation,
isStateVar: false,
isIndexed: !!ctx.IndexedKeyword(0),
}
},
return this._addMeta(node, ctx)
}
FunctionTypeParameter(ctx: Ctx) {
let storageLocation = null
if (ctx.storageLocation()) {
storageLocation = toText(ctx.storageLocation())
public visitDoWhileStatement(
ctx: SP.DoWhileStatementContext
): AST.DoWhileStatement {
const node: AST.DoWhileStatement = {
type: 'DoWhileStatement',
condition: this.visitExpression(ctx.expression()),
body: this.visitStatement(ctx.statement()),
}
return {
type: 'VariableDeclaration',
typeName: (this as any).visit(ctx.typeName()),
name: null,
storageLocation,
isStateVar: false,
isIndexed: false,
}
},
return this._addMeta(node, ctx)
}
WhileStatement(ctx: Ctx) {
return {
condition: (this as any).visit(ctx.expression()),
body: (this as any).visit(ctx.statement()),
}
},
public visitIfStatement(ctx: SP.IfStatementContext): AST.IfStatement {
const trueBody = this.visitStatement(ctx.statement(0))
DoWhileStatement(ctx: Ctx) {
return {
condition: (this as any).visit(ctx.expression()),
body: (this as any).visit(ctx.statement()),
}
},
IfStatement(ctx: Ctx) {
const trueBody = (this as any).visit(ctx.statement(0))
let falseBody = null
if (ctx.statement().length > 1) {
falseBody = (this as any).visit(ctx.statement(1))
falseBody = this.visitStatement(ctx.statement(1))
}
return {
condition: (this as any).visit(ctx.expression()),
const node: AST.IfStatement = {
type: 'IfStatement',
condition: this.visitExpression(ctx.expression()),
trueBody,
falseBody,
}
},
TryStatement(ctx: Ctx) {
return this._addMeta(node, ctx)
}
public visitTryStatement(ctx: SP.TryStatementContext): AST.TryStatement {
let returnParameters = null
if (ctx.returnParameters()) {
returnParameters = (this as any).visit(ctx.returnParameters())
const ctxReturnParameters = ctx.returnParameters()
if (ctxReturnParameters !== undefined) {
returnParameters = this.visitReturnParameters(ctxReturnParameters)
}

@@ -539,16 +798,19 @@

.catchClause()
.map((exprCtx: any) => (this as any).visit(exprCtx))
.map((exprCtx) => this.visitCatchClause(exprCtx))
return {
expression: (this as any).visit(ctx.expression()),
const node: AST.TryStatement = {
type: 'TryStatement',
expression: this.visitExpression(ctx.expression()),
returnParameters,
body: (this as any).visit(ctx.block()),
body: this.visitBlock(ctx.block()),
catchClauses,
}
},
CatchClause(ctx: Ctx) {
return this._addMeta(node, ctx)
}
public visitCatchClause(ctx: SP.CatchClauseContext): AST.CatchClause {
let parameters = null
if (ctx.parameterList()) {
parameters = (this as any).visit(ctx.parameterList())
parameters = this.visitParameterList(ctx.parameterList()!)
}

@@ -558,4 +820,4 @@

ctx.identifier() &&
toText(ctx.identifier()) !== 'Error' &&
toText(ctx.identifier()) !== 'Panic'
this._toText(ctx.identifier()!) !== 'Error' &&
this._toText(ctx.identifier()!) !== 'Panic'
) {

@@ -566,59 +828,57 @@ throw new Error('Expected "Error" or "Panic" identifier in catch clause')

let kind = null
if (ctx.identifier()) {
kind = toText(ctx.identifier())
const ctxIdentifier = ctx.identifier()
if (ctxIdentifier !== undefined) {
kind = this._toText(ctxIdentifier)
}
return {
const node: AST.CatchClause = {
type: 'CatchClause',
// deprecated, use the `kind` property instead,
isReasonStringType:
!!ctx.identifier() && toText(ctx.identifier()) === 'Error',
isReasonStringType: kind === 'Error',
kind,
parameters,
body: (this as any).visit(ctx.block()),
body: this.visitBlock(ctx.block()),
}
},
UserDefinedTypeName(ctx: Ctx) {
return {
namePath: toText(ctx),
}
},
return this._addMeta(node, ctx)
}
ElementaryTypeName(ctx: Ctx) {
return {
name: toText(ctx),
public visitExpressionStatement(
ctx: SP.ExpressionStatementContext
): AST.ExpressionStatement {
if (!ctx) {
return null as any
}
},
Block(ctx: Ctx) {
return {
statements: (this as any).visit(ctx.statement()),
const node: AST.ExpressionStatement = {
type: 'ExpressionStatement',
expression: this.visitExpression(ctx.expression()),
}
},
ExpressionStatement(ctx: Ctx) {
return {
expression: (this as any).visit(ctx.expression()),
}
},
return this._addMeta(node, ctx)
}
NumberLiteral(ctx: Ctx) {
const number = toText(ctx.getChild(0))
public visitNumberLiteral(ctx: SP.NumberLiteralContext): AST.NumberLiteral {
const number = this._toText(ctx.getChild(0))
let subdenomination = null
if (ctx.children.length === 2) {
subdenomination = toText(ctx.getChild(1))
if (ctx.children?.length === 2) {
subdenomination = this._toText(ctx.getChild(1))
}
return {
const node: AST.NumberLiteral = {
type: 'NumberLiteral',
number,
subdenomination,
subdenomination: subdenomination as AST.NumberLiteral['subdenomination'],
}
},
MappingKey(ctx: Ctx) {
return this._addMeta(node, ctx)
}
public visitMappingKey(
ctx: SP.MappingKeyContext
): AST.ElementaryTypeName | AST.UserDefinedTypeName {
if (ctx.elementaryTypeName()) {
return (this as any).visit(ctx.elementaryTypeName())
return this.visitElementaryTypeName(ctx.elementaryTypeName()!)
} else if (ctx.userDefinedTypeName()) {
return (this as any).visit(ctx.userDefinedTypeName())
return this.visitUserDefinedTypeName(ctx.userDefinedTypeName()!)
} else {

@@ -630,19 +890,24 @@ throw new Error(

}
},
}
Mapping(ctx: Ctx) {
return {
keyType: (this as any).visit(ctx.mappingKey()),
valueType: (this as any).visit(ctx.typeName()),
public visitMapping(ctx: SP.MappingContext): AST.Mapping {
const node: AST.Mapping = {
type: 'Mapping',
keyType: this.visitMappingKey(ctx.mappingKey()),
valueType: this.visitTypeName(ctx.typeName()),
}
},
ModifierDefinition(ctx: Ctx) {
return this._addMeta(node, ctx)
}
public visitModifierDefinition(
ctx: SP.ModifierDefinitionContext
): AST.ModifierDefinition {
let parameters = null
if (ctx.parameterList()) {
parameters = (this as any).visit(ctx.parameterList())
parameters = this.visitParameterList(ctx.parameterList()!)
}
let isVirtual = false
if (ctx.VirtualKeyword(0)) {
if (ctx.VirtualKeyword().length > 0) {
isVirtual = true

@@ -656,67 +921,85 @@ }

} else {
override = (this as any).visit(overrideSpecifier[0].userDefinedTypeName())
override = overrideSpecifier[0]
.userDefinedTypeName()
.map((x) => this.visitUserDefinedTypeName(x))
}
return {
name: toText(ctx.identifier()),
const node: AST.ModifierDefinition = {
type: 'ModifierDefinition',
name: this._toText(ctx.identifier()),
parameters,
body: (this as any).visit(ctx.block()),
body: this.visitBlock(ctx.block()),
isVirtual,
override,
}
},
Statement(ctx: Ctx) {
return (this as any).visit(ctx.getChild(0))
},
return this._addMeta(node, ctx)
}
SimpleStatement(ctx: Ctx) {
return (this as any).visit(ctx.getChild(0))
},
UncheckedStatement(ctx: Ctx) {
return {
block: (this as any).visit(ctx.block()),
public visitUncheckedStatement(
ctx: SP.UncheckedStatementContext
): AST.UncheckedStatement {
const node: AST.UncheckedStatement = {
type: 'UncheckedStatement',
block: this.visitBlock(ctx.block()),
}
},
Expression(ctx: Ctx): ASTTypes.Expression {
let op
return this._addMeta(node, ctx)
}
switch (ctx.children.length) {
case 1:
public visitExpression(ctx: SP.ExpressionContext): AST.Expression {
let op: string
switch (ctx.children!.length) {
case 1: {
// primary expression
return (this as any).visit(ctx.getChild(0))
const primaryExpressionCtx = ctx.tryGetRuleContext(
0,
SP.PrimaryExpressionContext
)
if (primaryExpressionCtx === undefined) {
throw new Error(
'Assertion error: primary expression should exist when children length is 1'
)
}
return this.visitPrimaryExpression(primaryExpressionCtx)
}
case 2:
op = toText(ctx.getChild(0))
op = this._toText(ctx.getChild(0))
// new expression
if (op === 'new') {
return {
const node: AST.NewExpression = {
type: 'NewExpression',
typeName: (this as any).visit(ctx.typeName()),
typeName: this.visitTypeName(ctx.typeName()!),
}
return this._addMeta(node, ctx)
}
// prefix operators
if (['+', '-', '++', '--', '!', '~', 'after', 'delete'].includes(op)) {
return {
if (AST.unaryOpValues.includes(op as AST.UnaryOp)) {
const node: AST.UnaryOperation = {
type: 'UnaryOperation',
operator: op,
subExpression: (this as any).visit(ctx.getChild(1)),
operator: op as AST.UnaryOp,
subExpression: this.visitExpression(
ctx.getRuleContext(0, SP.ExpressionContext)
),
isPrefix: true,
}
return this._addMeta(node, ctx)
}
op = toText(ctx.getChild(1))
op = this._toText(ctx.getChild(1))!
// postfix operators
if (['++', '--'].includes(op)) {
return {
const node: AST.UnaryOperation = {
type: 'UnaryOperation',
operator: op,
subExpression: (this as any).visit(ctx.getChild(0)),
operator: op as AST.UnaryOp,
subExpression: this.visitExpression(
ctx.getRuleContext(0, SP.ExpressionContext)
),
isPrefix: false,
}
return this._addMeta(node, ctx)
}

@@ -728,58 +1011,35 @@ break

if (
toText(ctx.getChild(0)) === '(' &&
toText(ctx.getChild(2)) === ')'
this._toText(ctx.getChild(0)) === '(' &&
this._toText(ctx.getChild(2)) === ')'
) {
return {
const node: AST.TupleExpression = {
type: 'TupleExpression',
components: [(this as any).visit(ctx.getChild(1))],
isArray: false,
}
}
// if square parenthesis are present it can only be
// a typename expression
if (
toText(ctx.getChild(1)) === '[' &&
toText(ctx.getChild(2)) === ']'
) {
return {
type: 'TypeNameExpression',
typeName: {
type: 'ArrayTypeName',
baseTypeName: (this as any).visit(ctx.getChild(0)),
length: null,
},
}
}
op = toText(ctx.getChild(1))
// tuple separator
if (op === ',') {
return {
type: 'TupleExpression',
components: [
(this as any).visit(ctx.getChild(0)),
(this as any).visit(ctx.getChild(2)),
this.visitExpression(ctx.getRuleContext(0, SP.ExpressionContext)),
],
isArray: false,
}
return this._addMeta(node, ctx)
}
op = this._toText(ctx.getChild(1))!
// member access
if (op === '.') {
return {
const node: AST.MemberAccess = {
type: 'MemberAccess',
expression: (this as any).visit(ctx.getChild(0)),
memberName: toText(ctx.getChild(2)),
expression: this.visitExpression(ctx.expression(0)),
memberName: this._toText(ctx.identifier()!),
}
return this._addMeta(node, ctx)
}
if (isBinOp(op)) {
return {
const node: AST.BinaryOperation = {
type: 'BinaryOperation',
operator: op,
left: (this as any).visit(ctx.getChild(0)),
right: (this as any).visit(ctx.getChild(2)),
left: this.visitExpression(ctx.expression(0)),
right: this.visitExpression(ctx.expression(1)),
}
return this._addMeta(node, ctx)
}

@@ -791,27 +1051,29 @@ break

if (
toText(ctx.getChild(1)) === '(' &&
toText(ctx.getChild(3)) === ')'
this._toText(ctx.getChild(1)) === '(' &&
this._toText(ctx.getChild(3)) === ')'
) {
let args = []
let args: AST.Expression[] = []
const names = []
const ctxArgs = ctx.functionCallArguments()
const ctxArgs = ctx.functionCallArguments()!
if (ctxArgs.expressionList()) {
args = ctxArgs
.expressionList()
.expressionList()!
.expression()
.map((exprCtx: any) => (this as any).visit(exprCtx))
.map((exprCtx) => this.visitExpression(exprCtx))
} else if (ctxArgs.nameValueList()) {
for (const nameValue of ctxArgs.nameValueList().nameValue()) {
args.push((this as any).visit(nameValue.expression()))
names.push(toText(nameValue.identifier()))
for (const nameValue of ctxArgs.nameValueList()!.nameValue()) {
args.push(this.visitExpression(nameValue.expression()))
names.push(this._toText(nameValue.identifier()))
}
}
return {
const node: AST.FunctionCall = {
type: 'FunctionCall',
expression: (this as any).visit(ctx.getChild(0)),
expression: this.visitExpression(ctx.expression(0)),
arguments: args,
names,
}
return this._addMeta(node, ctx)
}

@@ -821,17 +1083,21 @@

if (
toText(ctx.getChild(1)) === '[' &&
toText(ctx.getChild(3)) === ']'
this._toText(ctx.getChild(1)) === '[' &&
this._toText(ctx.getChild(3)) === ']'
) {
if (ctx.getChild(2).getText() === ':') {
return {
if (ctx.getChild(2).text === ':') {
const node: AST.IndexRangeAccess = {
type: 'IndexRangeAccess',
base: (this as any).visit(ctx.getChild(0)),
base: this.visitExpression(ctx.expression(0)),
}
return this._addMeta(node, ctx)
}
return {
const node: AST.IndexAccess = {
type: 'IndexAccess',
base: (this as any).visit(ctx.getChild(0)),
index: (this as any).visit(ctx.getChild(2)),
base: this.visitExpression(ctx.expression(0)),
index: this.visitExpression(ctx.expression(1)),
}
return this._addMeta(node, ctx)
}

@@ -841,10 +1107,12 @@

if (
toText(ctx.getChild(1)) === '{' &&
toText(ctx.getChild(3)) === '}'
this._toText(ctx.getChild(1)) === '{' &&
this._toText(ctx.getChild(3)) === '}'
) {
return {
const node: AST.NameValueExpression = {
type: 'NameValueExpression',
expression: (this as any).visit(ctx.getChild(0)),
arguments: (this as any).visit(ctx.getChild(2)),
expression: this.visitExpression(ctx.expression(0)),
arguments: this.visitNameValueList(ctx.nameValueList()!),
}
return this._addMeta(node, ctx)
}

@@ -857,11 +1125,13 @@

if (
toText(ctx.getChild(1)) === '?' &&
toText(ctx.getChild(3)) === ':'
this._toText(ctx.getChild(1)) === '?' &&
this._toText(ctx.getChild(3)) === ':'
) {
return {
const node: AST.Conditional = {
type: 'Conditional',
condition: (this as any).visit(ctx.getChild(0)),
trueExpression: (this as any).visit(ctx.getChild(2)),
falseExpression: (this as any).visit(ctx.getChild(4)),
condition: this.visitExpression(ctx.expression(0)),
trueExpression: this.visitExpression(ctx.expression(1)),
falseExpression: this.visitExpression(ctx.expression(2)),
}
return this._addMeta(node, ctx)
}

@@ -871,21 +1141,25 @@

if (
toText(ctx.getChild(1)) === '[' &&
toText(ctx.getChild(2)) === ':' &&
toText(ctx.getChild(4)) === ']'
this._toText(ctx.getChild(1)) === '[' &&
this._toText(ctx.getChild(2)) === ':' &&
this._toText(ctx.getChild(4)) === ']'
) {
return {
const node: AST.IndexRangeAccess = {
type: 'IndexRangeAccess',
base: (this as any).visit(ctx.getChild(0)),
indexEnd: (this as any).visit(ctx.getChild(3)),
base: this.visitExpression(ctx.expression(0)),
indexEnd: this.visitExpression(ctx.expression(1)),
}
return this._addMeta(node, ctx)
} else if (
toText(ctx.getChild(1)) === '[' &&
toText(ctx.getChild(3)) === ':' &&
toText(ctx.getChild(4)) === ']'
this._toText(ctx.getChild(1)) === '[' &&
this._toText(ctx.getChild(3)) === ':' &&
this._toText(ctx.getChild(4)) === ']'
) {
return {
const node: AST.IndexRangeAccess = {
type: 'IndexRangeAccess',
base: (this as any).visit(ctx.getChild(0)),
indexStart: (this as any).visit(ctx.getChild(2)),
base: this.visitExpression(ctx.expression(0)),
indexStart: this.visitExpression(ctx.expression(1)),
}
return this._addMeta(node, ctx)
}

@@ -897,12 +1171,14 @@ break

if (
toText(ctx.getChild(1)) === '[' &&
toText(ctx.getChild(3)) === ':' &&
toText(ctx.getChild(5)) === ']'
this._toText(ctx.getChild(1)) === '[' &&
this._toText(ctx.getChild(3)) === ':' &&
this._toText(ctx.getChild(5)) === ']'
) {
return {
const node: AST.IndexRangeAccess = {
type: 'IndexRangeAccess',
base: (this as any).visit(ctx.getChild(0)),
indexStart: (this as any).visit(ctx.getChild(2)),
indexEnd: (this as any).visit(ctx.getChild(4)),
base: this.visitExpression(ctx.expression(0)),
indexStart: this.visitExpression(ctx.expression(1)),
indexEnd: this.visitExpression(ctx.expression(2)),
}
return this._addMeta(node, ctx)
}

@@ -913,14 +1189,14 @@ break

throw new Error('Unrecognized expression')
},
}
NameValueList(ctx: Ctx) {
const names = []
const args = []
public visitNameValueList(ctx: SP.NameValueListContext): AST.NameValueList {
const names: string[] = []
const args: AST.Expression[] = []
for (const nameValue of ctx.nameValue()) {
names.push(toText(nameValue.identifier()))
args.push((this as any).visit(nameValue.expression()))
names.push(this._toText(nameValue.identifier()))
args.push(this.visitExpression(nameValue.expression()))
}
return {
const node: AST.NameValueList = {
type: 'NameValueList',

@@ -930,74 +1206,15 @@ names,

}
},
StateVariableDeclaration(ctx: Ctx) {
const type = (this as any).visit(ctx.typeName())
const iden = ctx.identifier()
const name = toText(iden)
return this._addMeta(node, ctx)
}
let expression = null
if (ctx.expression()) {
expression = (this as any).visit(ctx.expression())
}
let visibility = 'default'
if (ctx.InternalKeyword(0)) {
visibility = 'internal'
} else if (ctx.PublicKeyword(0)) {
visibility = 'public'
} else if (ctx.PrivateKeyword(0)) {
visibility = 'private'
}
let isDeclaredConst = false
if (ctx.ConstantKeyword(0)) {
isDeclaredConst = true
}
let override
const overrideSpecifier = ctx.overrideSpecifier()
if (overrideSpecifier.length === 0) {
override = null
} else {
override = (this as any).visit(overrideSpecifier[0].userDefinedTypeName())
}
let isImmutable = false
if (ctx.ImmutableKeyword(0)) {
isImmutable = true
}
const decl = (this as any).createNode(
{
type: 'VariableDeclaration',
typeName: type,
name,
expression,
visibility,
isStateVar: true,
isDeclaredConst,
isIndexed: false,
isImmutable,
override,
},
iden
)
return {
variables: [decl],
initialValue: expression,
}
},
FileLevelConstant(ctx: Ctx) {
const type = (this as any).visit(ctx.typeName())
public visitFileLevelConstant(ctx: SP.FileLevelConstantContext) {
const type = this.visitTypeName(ctx.typeName())
const iden = ctx.identifier()
const name = toText(iden)
const name = this._toText(iden)
let expression = null
if (ctx.expression()) {
expression = (this as any).visit(ctx.expression())
}
const expression = this.visitExpression(ctx.expression())
return {
const node: AST.FileLevelConstant = {
type: 'FileLevelConstant',
typeName: type,

@@ -1007,27 +1224,37 @@ name,

}
},
ForStatement(ctx: Ctx) {
let conditionExpression = (this as any).visit(ctx.expressionStatement())
return this._addMeta(node, ctx)
}
public visitForStatement(ctx: SP.ForStatementContext) {
let conditionExpression: any = this.visitExpressionStatement(
ctx.expressionStatement()!
)
if (conditionExpression) {
conditionExpression = conditionExpression.expression
}
return {
initExpression: (this as any).visit(ctx.simpleStatement()),
const node: AST.ForStatement = {
type: 'ForStatement',
initExpression: ctx.simpleStatement()
? this.visitSimpleStatement(ctx.simpleStatement()!)
: null,
conditionExpression,
loopExpression: {
type: 'ExpressionStatement',
expression: (this as any).visit(ctx.expression()),
expression:
ctx.expression() !== undefined ? this.visitExpression(ctx.expression()!) : null,
},
body: (this as any).visit(ctx.statement()),
body: this.visitStatement(ctx.statement()),
}
},
HexLiteral(ctx: Ctx) {
return this._addMeta(node, ctx)
}
public visitHexLiteral(ctx: SP.HexLiteralContext) {
const parts = ctx
.HexLiteralFragment()
.map(toText)
.map((x: any) => x.substring(4, x.length - 1))
.map((x) => this._toText(x))
.map((x) => x.substring(4, x.length - 1))
return {
const node: AST.HexLiteral = {
type: 'HexLiteral',

@@ -1037,14 +1264,20 @@ value: parts.join(''),

}
},
PrimaryExpression(ctx: Ctx) {
return this._addMeta(node, ctx)
}
public visitPrimaryExpression(
ctx: SP.PrimaryExpressionContext
): AST.PrimaryExpression {
if (ctx.BooleanLiteral()) {
return {
const node: AST.BooleanLiteral = {
type: 'BooleanLiteral',
value: toText(ctx.BooleanLiteral()) === 'true',
value: this._toText(ctx.BooleanLiteral()!) === 'true',
}
return this._addMeta(node, ctx)
}
if (ctx.hexLiteral()) {
return (this as any).visit(ctx.hexLiteral())
return this.visitHexLiteral(ctx.hexLiteral()!)
}

@@ -1054,6 +1287,6 @@

const fragments = ctx
.stringLiteral()
.stringLiteral()!
.StringLiteralFragment()
.map((stringLiteralFragmentCtx: any) => {
let text = toText(stringLiteralFragmentCtx)
let text = this._toText(stringLiteralFragmentCtx)!

@@ -1075,3 +1308,3 @@ const isUnicode = text.slice(0, 7) === 'unicode'

return {
const node: AST.StringLiteral = {
type: 'StringLiteral',

@@ -1082,17 +1315,25 @@ value: parts.join(''),

}
return this._addMeta(node, ctx)
}
if (ctx.numberLiteral()) {
return this.visitNumberLiteral(ctx.numberLiteral()!)
}
if (ctx.TypeKeyword()) {
return {
const node: AST.Identifier = {
type: 'Identifier',
name: 'type',
}
return this._addMeta(node, ctx)
}
if (
ctx.children.length == 3 &&
toText(ctx.getChild(1)) === '[' &&
toText(ctx.getChild(2)) === ']'
ctx.children!.length == 3 &&
this._toText(ctx.getChild(1)) === '[' &&
this._toText(ctx.getChild(2)) === ']'
) {
let node = (this as any).visit(ctx.getChild(0))
let node: any = this.visit(ctx.getChild(0))
if (node.type === 'Identifier') {

@@ -1108,48 +1349,49 @@ node = {

type: 'ElementaryTypeName',
name: toText(ctx.getChild(0)),
name: this._toText(ctx.getChild(0)),
}
}
const typeName = {
const typeName: AST.ArrayTypeName = {
type: 'ArrayTypeName',
baseTypeName: node,
baseTypeName: this._addMeta(node, ctx),
length: null,
}
return {
const result: AST.TypeNameExpression = {
type: 'TypeNameExpression',
typeName,
typeName: this._addMeta(typeName, ctx),
}
return this._addMeta(result, ctx)
}
return (this as any).visit(ctx.getChild(0))
},
return this.visitTupleExpression(ctx.tupleExpression()!)
Identifier(ctx: Ctx) {
return {
name: toText(ctx),
}
},
throw new Error("Assertion error: unhandled primary expression")
}
TupleExpression(ctx: Ctx) {
public visitTupleExpression(ctx: SP.TupleExpressionContext): AST.TupleExpression {
// remove parentheses
const children = ctx.children.slice(1, -1)
const components = mapCommasToNulls(children).map((expr) => {
const children = ctx.children!.slice(1, -1)
const components = this._mapCommasToNulls(children).map((expr) => {
// add a null for each empty value
if (!expr) {
if (expr === null) {
return null
}
return (this as any).visit(expr)
return this.visit(expr)
})
return {
const node: AST.TupleExpression = {
type: 'TupleExpression',
components,
isArray: toText(ctx.getChild(0)) === '[',
isArray: this._toText(ctx.getChild(0)) === '[',
}
},
IdentifierList(ctx: Ctx) {
return this._addMeta(node, ctx)
}
public buildIdentifierList(ctx: SP.IdentifierListContext) {
// remove parentheses
const children = ctx.children.slice(1, -1)
return mapCommasToNulls(children).map((iden) => {
const children = ctx.children!.slice(1, -1)
return this._mapCommasToNulls(children).map((iden) => {
// add a null for each empty value

@@ -1160,19 +1402,21 @@ if (!iden) {

return (this as any).createNode(
{
type: 'VariableDeclaration',
name: toText(iden),
storageLocation: null,
typeName: null,
isStateVar: false,
isIndexed: false,
},
iden
)
const node: AST.VariableDeclaration = {
type: 'VariableDeclaration',
name: this._toText(iden),
isStateVar: false,
isIndexed: false,
typeName: null,
storageLocation: null,
expression: null,
}
return node
})
},
}
VariableDeclarationList(ctx: Ctx) {
public buildVariableDeclarationList(
ctx: SP.VariableDeclarationListContext
): Array<AST.VariableDeclaration | null> {
// remove parentheses
return mapCommasToNulls(ctx.children).map((decl) => {
return this._mapCommasToNulls(ctx.children!).map((decl: any) => {
// add a null for each empty value

@@ -1183,44 +1427,23 @@ if (!decl) {

let storageLocation = null
let storageLocation: string | null = null
if (decl.storageLocation()) {
storageLocation = toText(decl.storageLocation())
storageLocation = this._toText(decl.storageLocation()!)
}
return (this as any).createNode(
{
type: 'VariableDeclaration',
name: toText(decl.identifier()),
typeName: (this as any).visit(decl.typeName()),
storageLocation,
isStateVar: false,
isIndexed: false,
},
decl
)
const result: AST.VariableDeclaration = {
type: 'VariableDeclaration',
name: this._toText(decl.identifier()),
typeName: this.visitTypeName(decl.typeName()),
storageLocation,
isStateVar: false,
isIndexed: false,
expression: null,
}
return result
})
},
}
VariableDeclarationStatement(ctx: Ctx) {
let variables
if (ctx.variableDeclaration()) {
variables = [(this as any).visit(ctx.variableDeclaration())]
} else if (ctx.identifierList()) {
variables = (this as any).visit(ctx.identifierList())
} else if (ctx.variableDeclarationList()) {
variables = (this as any).visit(ctx.variableDeclarationList())
}
let initialValue = null
if (ctx.expression()) {
initialValue = (this as any).visit(ctx.expression())
}
return {
variables,
initialValue,
}
},
ImportDirective(ctx: Ctx) {
const pathString = toText(ctx.StringLiteralFragment())
public visitImportDirective(ctx: SP.ImportDirectiveContext) {
const pathString = this._toText(ctx.StringLiteralFragment())!
let unitAlias = null

@@ -1230,17 +1453,18 @@ let symbolAliases = null

if (ctx.importDeclaration().length > 0) {
symbolAliases = ctx.importDeclaration().map((decl: any) => {
const symbol = toText(decl.identifier(0))
symbolAliases = ctx.importDeclaration().map((decl) => {
const symbol = this._toText(decl.identifier(0))
let alias = null
if (decl.identifier(1)) {
alias = toText(decl.identifier(1))
if (decl.identifier().length > 1) {
alias = this._toText(decl.identifier(1))
}
return [symbol, alias]
return [symbol, alias] as [string, string | null]
})
} else if (ctx.children.length === 7) {
unitAlias = toText(ctx.getChild(3))
} else if (ctx.children.length === 5) {
unitAlias = toText(ctx.getChild(3))
} else if (ctx.children!.length === 7) {
unitAlias = this._toText(ctx.getChild(3))
} else if (ctx.children!.length === 5) {
unitAlias = this._toText(ctx.getChild(3))
}
return {
const node: AST.ImportDirective = {
type: 'ImportDirective',
path: pathString.substring(1, pathString.length - 1),

@@ -1250,94 +1474,74 @@ unitAlias,

}
},
EventDefinition(ctx: Ctx) {
return {
name: toText(ctx.identifier()),
parameters: (this as any).visit(ctx.eventParameterList()),
isAnonymous: !!ctx.AnonymousKeyword(),
}
},
return this._addMeta(node, ctx)
}
EventParameterList(ctx: Ctx) {
public buildEventParameterList(ctx: SP.EventParameterListContext) {
return ctx.eventParameter().map((paramCtx: any) => {
const type = (this as any).visit(paramCtx.typeName())
const type = this.visit(paramCtx.typeName())
let name = null
if (paramCtx.identifier()) {
name = toText(paramCtx.identifier())
name = this._toText(paramCtx.identifier())
}
return (this as any).createNode(
{
type: 'VariableDeclaration',
typeName: type,
name,
isStateVar: false,
isIndexed: !!paramCtx.IndexedKeyword(0),
},
paramCtx
)
}, this)
},
return {
type: 'VariableDeclaration',
typeName: type,
name,
isStateVar: false,
isIndexed: !!paramCtx.IndexedKeyword(0),
}
})
}
ReturnParameters(ctx: Ctx) {
return (this as any).visit(ctx.parameterList())
},
public visitReturnParameters(
ctx: SP.ReturnParametersContext
): AST.VariableDeclaration[] {
return this.visitParameterList(ctx.parameterList())
}
ParameterList(ctx: Ctx) {
return ctx.parameter().map((paramCtx: any) => (this as any).visit(paramCtx))
},
public visitParameterList(
ctx: SP.ParameterListContext
): AST.VariableDeclaration[] {
return ctx.parameter().map((paramCtx: any) => this.visitParameter(paramCtx))
}
Parameter(ctx: Ctx) {
let storageLocation = null
if (ctx.storageLocation()) {
storageLocation = toText(ctx.storageLocation())
public visitInlineAssemblyStatement(ctx: SP.InlineAssemblyStatementContext) {
let language: string | null = null
if (ctx.StringLiteralFragment()) {
language = this._toText(ctx.StringLiteralFragment()!)!
language = language.substring(1, language.length - 1)
}
let name = null
if (ctx.identifier()) {
name = toText(ctx.identifier())
const node: AST.InlineAssemblyStatement = {
type: 'InlineAssemblyStatement',
language,
body: this.visitAssemblyBlock(ctx.assemblyBlock()),
}
return {
type: 'VariableDeclaration',
typeName: (this as any).visit(ctx.typeName()),
name,
storageLocation,
isStateVar: false,
isIndexed: false,
}
},
return this._addMeta(node, ctx)
}
InlineAssemblyStatement(ctx: Ctx) {
let language = null
if (ctx.StringLiteralFragment()) {
language = toText(ctx.StringLiteralFragment())
language = language.substring(1, language.length - 1)
}
public visitAssemblyBlock(ctx: SP.AssemblyBlockContext): AST.AssemblyBlock {
const operations = ctx.assemblyItem().map((item) => this.visitAssemblyItem(item))
return {
language,
body: (this as any).visit(ctx.assemblyBlock()),
const node: AST.AssemblyBlock = {
type: 'AssemblyBlock',
operations,
}
},
AssemblyBlock(ctx: Ctx) {
const operations = ctx
.assemblyItem()
.map((it: any) => (this as any).visit(it))
return this._addMeta(node, ctx)
}
return { operations }
},
AssemblyItem(ctx: Ctx) {
public visitAssemblyItem(ctx: SP.AssemblyItemContext): AST.AssemblyItem {
let text
if (ctx.hexLiteral()) {
return (this as any).visit(ctx.hexLiteral())
return this.visitHexLiteral(ctx.hexLiteral()!)
}
if (ctx.stringLiteral()) {
text = toText(ctx.stringLiteral())
text = this._toText(ctx.stringLiteral()!)!
const value = text.substring(1, text.length - 1)
return {
const node: AST.StringLiteral = {
type: 'StringLiteral',

@@ -1348,42 +1552,49 @@ value,

}
return this._addMeta(node, ctx)
}
if (ctx.BreakKeyword()) {
return {
const node: AST.Break = {
type: 'Break',
}
return this._addMeta(node, ctx)
}
if (ctx.ContinueKeyword()) {
return {
const node: AST.Continue = {
type: 'Continue',
}
return this._addMeta(node, ctx)
}
return (this as any).visit(ctx.getChild(0))
},
return this.visit(ctx.getChild(0)) as AST.AssemblyItem
}
AssemblyExpression(ctx: Ctx) {
return (this as any).visit(ctx.getChild(0))
},
public visitAssemblyExpression(ctx: SP.AssemblyExpressionContext) {
return this.visit(ctx.getChild(0)) as AST.AssemblyExpression
}
AssemblyCall(ctx: Ctx) {
const functionName = toText(ctx.getChild(0))
const args = ctx
.assemblyExpression()
.map((arg: any) => (this as any).visit(arg))
public visitAssemblyCall(ctx: SP.AssemblyCallContext) {
const functionName = this._toText(ctx.getChild(0))
const args = ctx.assemblyExpression().map((assemblyExpr) => this.visitAssemblyExpression(assemblyExpr))
return {
const node: AST.AssemblyCall = {
type: 'AssemblyCall',
functionName,
arguments: args,
}
},
AssemblyLiteral(ctx: Ctx) {
return this._addMeta(node, ctx)
}
public visitAssemblyLiteral(ctx: SP.AssemblyLiteralContext): AST.AssemblyLiteral {
let text
if (ctx.stringLiteral()) {
text = toText(ctx)
text = this._toText(ctx)!
const value = text.substring(1, text.length - 1)
return {
const node: AST.StringLiteral = {
type: 'StringLiteral',

@@ -1394,205 +1605,286 @@ value,

}
return this._addMeta(node, ctx)
}
if (ctx.DecimalNumber()) {
return {
const node: AST.DecimalNumber = {
type: 'DecimalNumber',
value: toText(ctx),
value: this._toText(ctx),
}
return this._addMeta(node, ctx)
}
if (ctx.HexNumber()) {
return {
const node: AST.HexNumber = {
type: 'HexNumber',
value: toText(ctx),
value: this._toText(ctx),
}
return this._addMeta(node, ctx)
}
if (ctx.hexLiteral()) {
return (this as any).visit(ctx.hexLiteral())
return this.visitHexLiteral(ctx.hexLiteral()!)
}
},
AssemblySwitch(ctx: Ctx) {
return {
expression: (this as any).visit(ctx.assemblyExpression()),
cases: ctx.assemblyCase().map((c: any) => (this as any).visit(c)),
throw new Error('Should never reach here')
}
public visitAssemblySwitch(ctx: SP.AssemblySwitchContext) {
const node: AST.AssemblySwitch = {
type: 'AssemblySwitch',
expression: this.visitAssemblyExpression(ctx.assemblyExpression()),
cases: ctx.assemblyCase().map((c) => this.visitAssemblyCase(c)),
}
},
AssemblyCase(ctx: Ctx) {
return this._addMeta(node, ctx)
}
public visitAssemblyCase(ctx: SP.AssemblyCaseContext): AST.AssemblyCase {
let value = null
if (toText(ctx.getChild(0)) === 'case') {
value = (this as any).visit(ctx.assemblyLiteral())
if (this._toText(ctx.getChild(0)) === 'case') {
value = this.visitAssemblyLiteral(ctx.assemblyLiteral()!)
}
const node: any = { block: (this as any).visit(ctx.assemblyBlock()) }
if (value) {
node.value = value
} else {
node.default = true
const node: AST.AssemblyCase = {
type: 'AssemblyCase',
block: this.visitAssemblyBlock(ctx.assemblyBlock()),
value,
default: value === null
}
return node
},
return this._addMeta(node, ctx)
}
AssemblyLocalDefinition(ctx: Ctx) {
let names = ctx.assemblyIdentifierOrList()
if (names.identifier()) {
names = [(this as any).visit(names.identifier())]
} else if (names.assemblyMember()) {
names = [(this as any).visit(names.assemblyMember())]
public visitAssemblyLocalDefinition(ctx: SP.AssemblyLocalDefinitionContext): AST.AssemblyLocalDefinition {
const ctxAssemblyIdentifierOrList = ctx.assemblyIdentifierOrList()
let names
if (ctxAssemblyIdentifierOrList.identifier()) {
names = [this.visitIdentifier(ctxAssemblyIdentifierOrList.identifier()!)]
} else if (ctxAssemblyIdentifierOrList.assemblyMember()) {
names = [this.visitAssemblyMember(ctxAssemblyIdentifierOrList.assemblyMember()!)]
} else {
names = (this as any).visit(names.assemblyIdentifierList().identifier())
names = ctxAssemblyIdentifierOrList
.assemblyIdentifierList()!
.identifier()!
.map((x) => this.visitIdentifier(x))
}
return {
const node: AST.AssemblyLocalDefinition = {
type: 'AssemblyLocalDefinition',
names,
expression: (this as any).visit(ctx.assemblyExpression()),
expression: this.visitAssemblyExpression(ctx.assemblyExpression()!),
}
},
AssemblyFunctionDefinition(ctx: Ctx) {
let args = ctx.assemblyIdentifierList()
args = args ? (this as any).visit(args.identifier()) : []
return this._addMeta(node, ctx)
}
let returnArgs = ctx.assemblyFunctionReturns()
returnArgs = returnArgs
? (this as any).visit(returnArgs.assemblyIdentifierList().identifier())
public visitAssemblyFunctionDefinition(
ctx: SP.AssemblyFunctionDefinitionContext
) {
const ctxAssemblyIdentifierList = ctx.assemblyIdentifierList()
const args =
ctxAssemblyIdentifierList !== undefined
? ctxAssemblyIdentifierList.identifier().map((x) => this.visitIdentifier(x))
: []
const ctxAssemblyFunctionReturns = ctx.assemblyFunctionReturns()
const returnArgs = ctxAssemblyFunctionReturns
? ctxAssemblyFunctionReturns
.assemblyIdentifierList()!
.identifier()
.map((x) => this.visitIdentifier(x))
: []
return {
name: toText(ctx.identifier()),
const node: AST.AssemblyFunctionDefinition = {
type: 'AssemblyFunctionDefinition',
name: this._toText(ctx.identifier()),
arguments: args,
returnArguments: returnArgs,
body: (this as any).visit(ctx.assemblyBlock()),
body: this.visitAssemblyBlock(ctx.assemblyBlock()),
}
},
AssemblyAssignment(ctx: Ctx) {
let names = ctx.assemblyIdentifierOrList()
if (names.identifier()) {
names = [(this as any).visit(names.identifier())]
} else if (names.assemblyMember()) {
names = [(this as any).visit(names.assemblyMember())]
return this._addMeta(node, ctx)
}
public visitAssemblyAssignment(ctx: SP.AssemblyAssignmentContext) {
const ctxAssemblyIdentifierOrList = ctx.assemblyIdentifierOrList()
let names
if (ctxAssemblyIdentifierOrList.identifier()) {
names = [this.visitIdentifier(ctxAssemblyIdentifierOrList.identifier()!)]
} else if (ctxAssemblyIdentifierOrList.assemblyMember()) {
names = [this.visitAssemblyMember(ctxAssemblyIdentifierOrList.assemblyMember()!)]
} else {
names = (this as any).visit(names.assemblyIdentifierList().identifier())
names = ctxAssemblyIdentifierOrList
.assemblyIdentifierList()!
.identifier()
.map((x) => this.visitIdentifier(x))
}
return {
const node: AST.AssemblyAssignment = {
type: 'AssemblyAssignment',
names,
expression: (this as any).visit(ctx.assemblyExpression()),
expression: this.visitAssemblyExpression(ctx.assemblyExpression()),
}
},
AssemblyMember(ctx: Ctx) {
return this._addMeta(node, ctx)
}
public visitAssemblyMember(ctx: SP.AssemblyMemberContext): AST.AssemblyMemberAccess {
const [accessed, member] = ctx.identifier()
return {
const node: AST.AssemblyMemberAccess = {
type: 'AssemblyMemberAccess',
expression: (this as any).visit(accessed),
memberName: (this as any).visit(member),
expression: this.visitIdentifier(accessed),
memberName: this.visitIdentifier(member),
}
},
LabelDefinition(ctx: Ctx) {
return {
name: toText(ctx.identifier()),
return this._addMeta(node, ctx)
}
public visitLabelDefinition(ctx: SP.LabelDefinitionContext) {
const node: AST.LabelDefinition = {
type: 'LabelDefinition',
name: this._toText(ctx.identifier()),
}
},
AssemblyStackAssignment(ctx: Ctx) {
return {
name: toText(ctx.identifier()),
return this._addMeta(node, ctx)
}
public visitAssemblyStackAssignment(ctx: SP.AssemblyStackAssignmentContext) {
const node: AST.AssemblyStackAssignment = {
type: 'AssemblyStackAssignment',
name: this._toText(ctx.identifier()),
}
},
AssemblyFor(ctx: Ctx) {
return {
pre: (this as any).visit(ctx.getChild(1)),
condition: (this as any).visit(ctx.getChild(2)),
post: (this as any).visit(ctx.getChild(3)),
body: (this as any).visit(ctx.getChild(4)),
return this._addMeta(node, ctx)
}
public visitAssemblyFor(ctx: SP.AssemblyForContext) {
// TODO remove these type assertions
const node: AST.AssemblyFor = {
type: 'AssemblyFor',
pre: this.visit(ctx.getChild(1)) as AST.AssemblyBlock | AST.AssemblyExpression,
condition: this.visit(ctx.getChild(2)) as AST.AssemblyExpression,
post: this.visit(ctx.getChild(3)) as AST.AssemblyBlock | AST.AssemblyExpression,
body: this.visit(ctx.getChild(4)) as AST.AssemblyBlock,
}
},
AssemblyIf(ctx: Ctx) {
return {
condition: (this as any).visit(ctx.assemblyExpression()),
body: (this as any).visit(ctx.assemblyBlock()),
return this._addMeta(node, ctx)
}
public visitAssemblyIf(ctx: SP.AssemblyIfContext) {
const node: AST.AssemblyIf = {
type: 'AssemblyIf',
condition: this.visitAssemblyExpression(ctx.assemblyExpression()),
body: this.visitAssemblyBlock(ctx.assemblyBlock()),
}
},
}
class ASTBuilder extends antlr4.tree.ParseTreeVisitor {
public options: ParseOptions
return this._addMeta(node, ctx)
}
constructor(options: ParseOptions) {
super(options)
private _toText(ctx: ParserRuleContext | ParseTree): string {
const text = ctx.text
if (text === undefined) {
throw new Error('Assertion error: text should never be undefiend')
}
this.options = options
return text
}
_loc(ctx: Ctx) {
const sourceLocation = {
private _stateMutabilityToText(
ctx: SP.StateMutabilityContext
): AST.FunctionDefinition['stateMutability'] {
if (ctx.PureKeyword() !== undefined) {
return 'pure'
}
if (ctx.ConstantKeyword() !== undefined) {
return 'constant'
}
if (ctx.PayableKeyword() !== undefined) {
return 'payable'
}
if (ctx.ViewKeyword() !== undefined) {
return 'view'
}
throw new Error('Assertion error: non-exhaustive stateMutability check')
}
private _loc(ctx: ParserRuleContext): SourceLocation {
const sourceLocation: SourceLocation = {
start: {
line: ctx.start.line,
column: ctx.start.column,
column: ctx.start.charPositionInLine,
},
end: {
line: ctx.stop ? ctx.stop.line : ctx.start.line,
column: ctx.stop ? ctx.stop.column : ctx.start.column,
column: ctx.stop
? ctx.stop.charPositionInLine
: ctx.start.charPositionInLine,
},
}
return { loc: sourceLocation }
return sourceLocation
}
_range(ctx: Ctx) {
return { range: [ctx.start.start, ctx.stop.stop] }
_range(ctx: ParserRuleContext): [number, number] {
return [ctx.start.startIndex, ctx.stop?.stopIndex ?? ctx.start.startIndex]
}
meta(ctx: Ctx) {
const ret: any = {}
private _addMeta<T extends AST.BaseASTNode>(
node: T,
ctx: ParserRuleContext
): T {
const nodeWithMeta: AST.BaseASTNode = {
type: node.type,
}
if (this.options.loc === true) {
Object.assign(ret, this._loc(ctx))
node.loc = this._loc(ctx)
}
if (this.options.range === true) {
Object.assign(ret, this._range(ctx))
node.range = this._range(ctx)
}
return ret
}
createNode(obj: any, ctx: any) {
return Object.assign(obj, this.meta(ctx))
return {
...nodeWithMeta,
...node,
}
}
visit(ctx: Ctx): BaseASTNode | BaseASTNode[] | null {
if (!ctx) {
return null
private _mapCommasToNulls(children: ParseTree[]) {
if (children.length === 0) {
return []
}
if (Array.isArray(ctx)) {
return ctx.map((child) => {
return (this as any).visit(child)
}, this)
}
const values: Array<ParseTree | null> = []
let comma = true
let name: string = ctx.constructor.name
if (name.endsWith('Context')) {
name = name.substring(0, name.length - 'Context'.length)
for (const el of children) {
if (comma) {
if (this._toText(el) === ',') {
values.push(null)
} else {
values.push(el)
comma = false
}
} else {
if (this._toText(el) !== ',') {
throw new Error('expected comma')
}
comma = true
}
}
const node = { type: name }
if (name in transformAST) {
const visited = (transformAST as any)[name].call(this, ctx)
if (Array.isArray(visited)) {
return visited
}
Object.assign(node, visited)
if (comma) {
values.push(null)
}
return (this as any).createNode(node, ctx)
return values
}
}
export default ASTBuilder
function isBinOp(op: string): op is AST.BinOp {
return AST.binaryOpValues.includes(op as AST.BinOp)
}

@@ -1,121 +0,3 @@

import SolidityLexer from './lib/SolidityLexer'
import SolidityParser from './lib/SolidityParser'
import { Token, ParseOptions, TokenizeOptions } from './types'
import { AST, BaseASTNode } from './ast-types'
export * from "./parser";
import antlr4 from 'antlr4'
import { buildTokenList } from './tokens'
import ASTBuilder from './ASTBuilder'
import ErrorListener from './ErrorListener'
interface ParserErrorItem {
message: string
line: number
column: number
}
export class ParserError extends Error {
public errors: ParserErrorItem[]
constructor(args: { errors: ParserErrorItem[] }) {
super()
const { message, line, column } = args.errors[0]
this.message = `${message} (${line}:${column})`
this.errors = args.errors
if (Error.captureStackTrace !== undefined) {
Error.captureStackTrace(this, this.constructor)
} else {
this.stack = new Error().stack
}
}
}
export function tokenize(
input: string,
options: TokenizeOptions = {}
): Token[] {
const chars = new antlr4.InputStream(input)
const lexer = new SolidityLexer(chars)
const tokens = new antlr4.CommonTokenStream(lexer)
return buildTokenList(tokens.tokenSource.getAllTokens(), options)
}
export function parse(input: string, options: ParseOptions = {}): AST {
const chars = new antlr4.InputStream(input)
const listener = new ErrorListener()
const lexer: any = new SolidityLexer(chars)
lexer.removeErrorListeners()
lexer.addErrorListener(listener)
const tokens = new antlr4.CommonTokenStream(lexer)
const parser: any = new SolidityParser(tokens)
parser.removeErrorListeners()
parser.addErrorListener(listener)
parser.buildParseTrees = true
const tree = parser.sourceUnit()
let tokenList: Token[] = []
if (options.tokens === true) {
const tokenSource = tokens.tokenSource
tokenSource.reset()
tokenList = buildTokenList(tokenSource.getAllTokens(), options)
}
if (options.tolerant !== true && listener.hasErrors()) {
throw new ParserError({ errors: listener.getErrors() })
}
const visitor = new ASTBuilder(options)
const ast = visitor.visit(tree) as AST
if (options.tolerant === true && listener.hasErrors()) {
ast.errors = listener.getErrors()
}
if (options.tokens === true) {
ast.tokens = tokenList
}
return ast
}
function _isASTNode(node: any): node is BaseASTNode {
return (
node !== null &&
typeof node === 'object' &&
Object.prototype.hasOwnProperty.call(node, 'type')
)
}
export function visit(node: any, visitor: any): void {
if (Array.isArray(node)) {
node.forEach((child) => visit(child, visitor))
}
if (!_isASTNode(node)) return
let cont = true
if (visitor[node.type] !== undefined) {
cont = visitor[node.type](node)
}
if (cont === false) return
for (const prop in node) {
if (Object.prototype.hasOwnProperty.call(node, prop)) {
visit((node as any)[prop], visitor)
}
}
const selector = node.type + ':exit'
if (visitor[selector] !== undefined) {
visitor[selector](node)
}
}
export type { ParseOptions } from "./types";
// This is an indirect file to import the tokens string
// It needs to be a js file so that tsc doesn't complain
import tokens from './lib/Solidity.tokens'
export default tokens
if (typeof BROWSER !== "undefined") {
module.exports = require('./antlr/Solidity.tokens')
} else {
module.exports = require('fs')
.readFileSync(require('path').join(__dirname, './antlr/Solidity.tokens'))
.toString()
}

@@ -79,8 +79,8 @@ import { Token, AntlrToken, TokenizeOptions } from './types'

if (options.range === true) {
node.range = [token.start, token.stop + 1]
node.range = [token.startIndex, token.stopIndex + 1]
}
if (options.loc === true) {
node.loc = {
start: { line: token.line, column: token.column },
end: { line: token.line, column: token.column + token.text.length },
start: { line: token.line, column: token.charPositionInLine },
end: { line: token.line, column: token.charPositionInLine + (token.text?.length ?? 0) },
}

@@ -87,0 +87,0 @@ }

@@ -0,1 +1,2 @@

import { Token as Antlr4TsToken } from "antlr4ts";
export interface Node {

@@ -5,10 +6,3 @@ type: string

export interface AntlrToken {
type: string
text: string
start: number
stop: number
line: number
column: number
}
export type AntlrToken = Antlr4TsToken;

@@ -27,3 +21,3 @@ export interface TokenizeOptions {

type: string
value: string
value: string | undefined
range?: [number, number]

@@ -30,0 +24,0 @@ loc?: {

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc