@@ -376,33 +376,47 @@ let statement: P.Parser<Ast.Statement>;
376376 * Type Parsers
377377 */
378378
379- // Elementary types with location
379+ // Elementary types with location. Dynamic bytes may be followed by
380+ // `calldata`: bytes in calldata
380381const elementaryType = located (
381- Lang . elementaryType . map ( ( name : string ) => {
382- // Parse the type name to extract kind and bits
383- if ( name . startsWith ( "uint" ) ) {
384- const bits = parseInt ( name . substring ( 4 ) , 10 ) ;
385- return Ast . Type . Elementary . uint ( PENDING_ID , bits ) ;
386- } else if ( name . startsWith ( "int" ) ) {
387- const bits = parseInt ( name . substring ( 3 ) , 10 ) ;
388- return Ast . Type . Elementary . int ( PENDING_ID , bits ) ;
389- } else if ( name . startsWith ( "bytes" ) && name !== "bytes" ) {
390- const size = parseInt ( name . substring ( 5 ) , 10 ) ;
391- return Ast . Type . Elementary . bytes ( PENDING_ID , size ) ;
392- } else if ( name === "address" ) {
393- return Ast . Type . Elementary . address ( PENDING_ID ) ;
394- } else if ( name === "bool" ) {
395- return Ast . Type . Elementary . bool ( PENDING_ID ) ;
396- } else if ( name === "string" ) {
397- return Ast . Type . Elementary . string ( PENDING_ID ) ;
398- } else if ( name === "bytes" ) {
399- return Ast . Type . Elementary . bytes ( PENDING_ID ) ;
400- }
401- // This should never happen as elementaryTypeName parser ensures valid names
402- throw new Error ( `Unknown elementary type: ${ name } ` ) ;
403- } ) ,
382+ Lang . elementaryType . chain ( ( name : string ) =>
383+ name === "bytes"
384+ ? Lang . keyword ( "calldata" )
385+ . atMost ( 1 )
386+ . map ( ( calldata ) =>
387+ Ast . Type . Elementary . bytes (
388+ PENDING_ID ,
389+ undefined ,
390+ undefined ,
391+ calldata . length > 0 ? "calldata" : undefined ,
392+ ) ,
393+ )
394+ : P . succeed ( elementaryTypeOf ( name ) ) ,
395+ ) ,
404396) ;
405397
398+ function elementaryTypeOf ( name : string ) : Ast . Type . Elementary {
399+ // Parse the type name to extract kind and bits
400+ if ( name . startsWith ( "uint" ) ) {
401+ const bits = parseInt ( name . substring ( 4 ) , 10 ) ;
402+ return Ast . Type . Elementary . uint ( PENDING_ID , bits ) ;
403+ } else if ( name . startsWith ( "int" ) ) {
404+ const bits = parseInt ( name . substring ( 3 ) , 10 ) ;
405+ return Ast . Type . Elementary . int ( PENDING_ID , bits ) ;
406+ } else if ( name . startsWith ( "bytes" ) && name !== "bytes" ) {
407+ const size = parseInt ( name . substring ( 5 ) , 10 ) ;
408+ return Ast . Type . Elementary . bytes ( PENDING_ID , size ) ;
409+ } else if ( name === "address" ) {
410+ return Ast . Type . Elementary . address ( PENDING_ID ) ;
411+ } else if ( name === "bool" ) {
412+ return Ast . Type . Elementary . bool ( PENDING_ID ) ;
413+ } else if ( name === "string" ) {
414+ return Ast . Type . Elementary . string ( PENDING_ID ) ;
415+ }
416+ // This should never happen as elementaryTypeName parser ensures valid names
417+ throw new Error ( `Unknown elementary type: ${ name } ` ) ;
418+ }
419+
406420// Reference type (identifier in type position)
407421const referenceType = located (
408422 Lang . identifier . map ( ( name : string ) => Ast . Type . reference ( PENDING_ID , name ) ) ,
0 commit comments