Skip to content

Commit ed05b76

Browse files
committed
Add support for custom errors
1 parent bd0e636 commit ed05b76

File tree

4 files changed

+195
-5
lines changed

4 files changed

+195
-5
lines changed

src/ASTBuilder.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -705,6 +705,29 @@ export class ASTBuilder
705705
return this._addMeta(node, ctx)
706706
}
707707

708+
public visitCustomErrorDefinition(
709+
ctx: SP.CustomErrorDefinitionContext
710+
): AST.CustomErrorDefinition & WithMeta {
711+
const node: AST.CustomErrorDefinition = {
712+
type: 'CustomErrorDefinition',
713+
name: this._toText(ctx.identifier()),
714+
parameters: this.visitParameterList(ctx.parameterList()),
715+
}
716+
717+
return this._addMeta(node, ctx)
718+
}
719+
720+
public visitRevertStatement(
721+
ctx: SP.RevertStatementContext
722+
): AST.RevertStatement & WithMeta {
723+
const node: AST.RevertStatement = {
724+
type: 'RevertStatement',
725+
revertCall: this.visitFunctionCall(ctx.functionCall()),
726+
}
727+
728+
return this._addMeta(node, ctx)
729+
}
730+
708731
public visitFunctionCall(
709732
ctx: SP.FunctionCallContext
710733
): AST.FunctionCall & WithMeta {

src/ast-types.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ export const astNodeTypes = [
5757
'ModifierInvocation',
5858
'FunctionDefinition',
5959
'EventDefinition',
60+
'CustomErrorDefinition',
61+
'RevertStatement',
6062
'EnumValue',
6163
'EnumDefinition',
6264
'VariableDeclaration',
@@ -181,6 +183,15 @@ export interface FunctionDefinition extends BaseASTNode {
181183
isFallback: boolean
182184
isVirtual: boolean
183185
}
186+
export interface CustomErrorDefinition extends BaseASTNode {
187+
type: 'CustomErrorDefinition'
188+
name: string
189+
parameters: VariableDeclaration[]
190+
}
191+
export interface RevertStatement extends BaseASTNode {
192+
type: 'RevertStatement'
193+
revertCall: FunctionCall
194+
}
184195
export interface EventDefinition extends BaseASTNode {
185196
type: 'EventDefinition'
186197
name: string
@@ -558,6 +569,7 @@ export type ASTNode =
558569
| ModifierInvocation
559570
| FunctionDefinition
560571
| EventDefinition
572+
| CustomErrorDefinition
561573
| EnumValue
562574
| EnumDefinition
563575
| VariableDeclaration
@@ -659,6 +671,7 @@ export type Statement =
659671
| VariableDeclarationStatement
660672
| UncheckedStatement
661673
| TryStatement
674+
| RevertStatement
662675

663676
type ASTMap<U> = { [K in ASTNodeTypeString]: U extends { type: K } ? U : never };
664677
type ASTTypeMap = ASTMap<ASTNode>;

test/ast.ts

Lines changed: 143 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ describe('AST', () => {
347347
isDeclaredConst: false,
348348
isIndexed: false,
349349
isImmutable: false,
350-
storageLocation: null
350+
storageLocation: null,
351351
},
352352
],
353353
initialValue: null,
@@ -374,7 +374,7 @@ describe('AST', () => {
374374
isDeclaredConst: false,
375375
isIndexed: false,
376376
isImmutable: true,
377-
storageLocation: null
377+
storageLocation: null,
378378
},
379379
],
380380
initialValue: null,
@@ -433,7 +433,7 @@ describe('AST', () => {
433433
isDeclaredConst: false,
434434
isIndexed: false,
435435
isImmutable: false,
436-
storageLocation: null
436+
storageLocation: null,
437437
},
438438
],
439439
initialValue: null,
@@ -502,7 +502,7 @@ describe('AST', () => {
502502
isDeclaredConst: false,
503503
isIndexed: false,
504504
isImmutable: false,
505-
storageLocation: null
505+
storageLocation: null,
506506
},
507507
],
508508
initialValue: null,
@@ -2254,7 +2254,7 @@ describe('AST', () => {
22542254
type: 'DecimalNumber',
22552255
value: '0',
22562256
},
2257-
default: false
2257+
default: false,
22582258
},
22592259
{
22602260
type: 'AssemblyCase',
@@ -2895,4 +2895,142 @@ describe('AST', () => {
28952895
},
28962896
})
28972897
})
2898+
2899+
it('should support top-level custom errors', function () {
2900+
let ast: any = parser.parse('error MyCustomError();')
2901+
assert.deepEqual(ast.children[0], {
2902+
type: 'CustomErrorDefinition',
2903+
name: 'MyCustomError',
2904+
parameters: [],
2905+
})
2906+
2907+
ast = parser.parse('error MyCustomError(uint a);')
2908+
assert.deepEqual(ast.children[0], {
2909+
type: 'CustomErrorDefinition',
2910+
name: 'MyCustomError',
2911+
parameters: [
2912+
{
2913+
type: 'VariableDeclaration',
2914+
typeName: {
2915+
type: 'ElementaryTypeName',
2916+
name: 'uint',
2917+
stateMutability: null,
2918+
},
2919+
name: 'a',
2920+
isStateVar: false,
2921+
isIndexed: false,
2922+
expression: null,
2923+
storageLocation: null,
2924+
},
2925+
],
2926+
})
2927+
2928+
ast = parser.parse('error MyCustomError(string);')
2929+
assert.deepEqual(ast.children[0], {
2930+
type: 'CustomErrorDefinition',
2931+
name: 'MyCustomError',
2932+
parameters: [
2933+
{
2934+
type: 'VariableDeclaration',
2935+
typeName: {
2936+
type: 'ElementaryTypeName',
2937+
name: 'string',
2938+
stateMutability: null,
2939+
},
2940+
name: null,
2941+
isStateVar: false,
2942+
isIndexed: false,
2943+
expression: null,
2944+
storageLocation: null,
2945+
},
2946+
],
2947+
})
2948+
})
2949+
2950+
it('should support contract-level custom errors', function () {
2951+
let ast: any = parseNode('error MyCustomError();')
2952+
assert.deepEqual(ast, {
2953+
type: 'CustomErrorDefinition',
2954+
name: 'MyCustomError',
2955+
parameters: [],
2956+
})
2957+
2958+
ast = parseNode('error MyCustomError(uint a);')
2959+
assert.deepEqual(ast, {
2960+
type: 'CustomErrorDefinition',
2961+
name: 'MyCustomError',
2962+
parameters: [
2963+
{
2964+
type: 'VariableDeclaration',
2965+
typeName: {
2966+
type: 'ElementaryTypeName',
2967+
name: 'uint',
2968+
stateMutability: null,
2969+
},
2970+
name: 'a',
2971+
isStateVar: false,
2972+
isIndexed: false,
2973+
expression: null,
2974+
storageLocation: null,
2975+
},
2976+
],
2977+
})
2978+
2979+
ast = parseNode('error MyCustomError(string);')
2980+
assert.deepEqual(ast, {
2981+
type: 'CustomErrorDefinition',
2982+
name: 'MyCustomError',
2983+
parameters: [
2984+
{
2985+
type: 'VariableDeclaration',
2986+
typeName: {
2987+
type: 'ElementaryTypeName',
2988+
name: 'string',
2989+
stateMutability: null,
2990+
},
2991+
name: null,
2992+
isStateVar: false,
2993+
isIndexed: false,
2994+
expression: null,
2995+
storageLocation: null,
2996+
},
2997+
],
2998+
})
2999+
})
3000+
3001+
it('should support revert statements', function () {
3002+
let ast: any = parseStatement('revert MyCustomError();')
3003+
assert.deepEqual(ast, {
3004+
type: 'RevertStatement',
3005+
revertCall: {
3006+
arguments: [],
3007+
expression: {
3008+
name: 'MyCustomError',
3009+
type: 'Identifier',
3010+
},
3011+
names: [],
3012+
type: 'FunctionCall',
3013+
},
3014+
})
3015+
3016+
ast = parseStatement('revert MyCustomError(3);')
3017+
assert.deepEqual(ast, {
3018+
type: 'RevertStatement',
3019+
revertCall: {
3020+
arguments: [
3021+
{
3022+
number: '3',
3023+
subdenomination: null,
3024+
type: 'NumberLiteral',
3025+
},
3026+
],
3027+
expression: {
3028+
name: 'MyCustomError',
3029+
type: 'Identifier',
3030+
},
3031+
names: [],
3032+
type: 'FunctionCall',
3033+
},
3034+
})
3035+
})
28983036
})

test/test.sol

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -733,3 +733,19 @@ contract ArraySlices {
733733
address a3 = abi.decode(x[4:], (address));
734734
}
735735
}
736+
737+
// custom errors
738+
739+
error TopLevelCustomError();
740+
error TopLevelCustomErrorWithArg(uint x);
741+
error TopLevelCustomErrorArgWithoutName(string);
742+
743+
contract CustomErrors {
744+
error ContractCustomError();
745+
error ContractCustomErrorWithArg(uint x);
746+
error ContractCustomErrorArgWithoutName(string);
747+
748+
function throwCustomError() {
749+
revert ContractCustomError();
750+
}
751+
}

0 commit comments

Comments
 (0)