From ad3e83fb456492178d2cf0767d30f6bae1211f2c Mon Sep 17 00:00:00 2001 From: Will Smith Date: Mon, 26 Jun 2023 21:12:52 -0300 Subject: [PATCH 01/22] feat: expose everything --- crates/syn-solidity/src/attribute/mod.rs | 4 ++-- crates/syn-solidity/src/ident/mod.rs | 2 +- crates/syn-solidity/src/item/mod.rs | 22 +++++++++----------- crates/syn-solidity/src/lib.rs | 26 ++++++++---------------- crates/syn-solidity/src/type/mod.rs | 8 ++++---- 5 files changed, 26 insertions(+), 36 deletions(-) diff --git a/crates/syn-solidity/src/attribute/mod.rs b/crates/syn-solidity/src/attribute/mod.rs index 6e948d4ac2..4621305d04 100644 --- a/crates/syn-solidity/src/attribute/mod.rs +++ b/crates/syn-solidity/src/attribute/mod.rs @@ -13,10 +13,10 @@ use syn::{ }; mod function; -pub use function::{FunctionAttribute, FunctionAttributes}; +pub use function::*; mod variable; -pub use variable::{VariableAttribute, VariableAttributes}; +pub use variable::*; kw_enum! { /// A storage location. diff --git a/crates/syn-solidity/src/ident/mod.rs b/crates/syn-solidity/src/ident/mod.rs index c2f8b39fe2..167b8ccb78 100644 --- a/crates/syn-solidity/src/ident/mod.rs +++ b/crates/syn-solidity/src/ident/mod.rs @@ -8,7 +8,7 @@ use syn::{ }; mod path; -pub use path::SolPath; +pub use path::*; /// A Solidity identifier. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] diff --git a/crates/syn-solidity/src/item/mod.rs b/crates/syn-solidity/src/item/mod.rs index 874698daa0..2c2082374f 100644 --- a/crates/syn-solidity/src/item/mod.rs +++ b/crates/syn-solidity/src/item/mod.rs @@ -6,36 +6,34 @@ use syn::{ }; mod contract; -pub use contract::ItemContract; +pub use contract::*; mod r#enum; -pub use r#enum::ItemEnum; +pub use r#enum::*; mod error; -pub use error::ItemError; +pub use error::*; mod event; -pub use event::{EventParameter, ItemEvent}; +pub use event::*; mod function; -pub use function::{ItemFunction, Returns}; +pub use function::*; mod import; -pub use import::{ - ImportAlias, ImportAliases, ImportDirective, ImportGlob, ImportPath, ImportPlain, -}; +pub use import::*; mod pragma; -pub use pragma::{PragmaDirective, PragmaTokens}; +pub use pragma::*; mod r#struct; -pub use r#struct::ItemStruct; +pub use r#struct::*; mod udt; -pub use udt::ItemUdt; +pub use udt::*; mod using; -pub use using::{UserDefinableOperator, UsingDirective, UsingList, UsingListItem, UsingType}; +pub use using::*; /// An AST item. A more expanded version of a [Solidity source unit][ref]. /// diff --git a/crates/syn-solidity/src/lib.rs b/crates/syn-solidity/src/lib.rs index a4579b9b4c..d10c63ffee 100644 --- a/crates/syn-solidity/src/lib.rs +++ b/crates/syn-solidity/src/lib.rs @@ -21,40 +21,32 @@ use syn::Result; mod macros; mod attribute; -pub use attribute::{ - FunctionAttribute, FunctionAttributes, Modifier, Mutability, Override, Storage, - VariableAttribute, VariableAttributes, Visibility, -}; +pub use attribute::*; mod file; -pub use file::File; +pub use file::*; mod ident; -pub use ident::{SolIdent, SolPath}; +pub use ident::*; mod item; -pub use item::{ - EventParameter, ImportAlias, ImportAliases, ImportDirective, ImportGlob, ImportPath, - ImportPlain, Item, ItemContract, ItemEnum, ItemError, ItemEvent, ItemFunction, ItemStruct, - ItemUdt, PragmaDirective, PragmaTokens, Returns, UserDefinableOperator, UsingDirective, - UsingList, UsingListItem, UsingType, -}; - +pub use item::*; mod lit; -pub use lit::LitStr; +pub use lit::*; pub mod kw; +pub use kw::*; mod stmt; -pub use stmt::Block; +pub use stmt::*; mod r#type; -pub use r#type::{Type, TypeArray, TypeFunction, TypeMapping, TypeTuple}; +pub use r#type::*; pub(crate) mod utils; mod variable; -pub use variable::{FieldList, ParameterList, Parameters, VariableDeclaration, VariableDefinition}; +pub use variable::*; #[cfg(feature = "visit")] pub mod visit; diff --git a/crates/syn-solidity/src/type/mod.rs b/crates/syn-solidity/src/type/mod.rs index f58451626e..fd78226603 100644 --- a/crates/syn-solidity/src/type/mod.rs +++ b/crates/syn-solidity/src/type/mod.rs @@ -13,16 +13,16 @@ use syn::{ }; mod array; -pub use array::TypeArray; +pub use array::*; mod function; -pub use function::TypeFunction; +pub use function::*; mod mapping; -pub use mapping::TypeMapping; +pub use mapping::*; mod tuple; -pub use tuple::TypeTuple; +pub use tuple::*; /// A type name. /// From 854cfdf595ed0d7a9c23e066b19f07fc739e737c Mon Sep 17 00:00:00 2001 From: Will Smith Date: Mon, 26 Jun 2023 21:15:38 -0300 Subject: [PATCH 02/22] feat: expose everything --- crates/syn-solidity/src/lib.rs | 16 ++++++++-------- crates/syn-solidity/src/type/mod.rs | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/crates/syn-solidity/src/lib.rs b/crates/syn-solidity/src/lib.rs index d10c63ffee..e050d5394c 100644 --- a/crates/syn-solidity/src/lib.rs +++ b/crates/syn-solidity/src/lib.rs @@ -20,32 +20,32 @@ use syn::Result; #[macro_use] mod macros; -mod attribute; +pub mod attribute; pub use attribute::*; -mod file; +pub mod file; pub use file::*; -mod ident; +pub mod ident; pub use ident::*; -mod item; +pub mod item; pub use item::*; -mod lit; +pub mod lit; pub use lit::*; pub mod kw; pub use kw::*; -mod stmt; +pub mod stmt; pub use stmt::*; -mod r#type; +pub mod r#type; pub use r#type::*; pub(crate) mod utils; -mod variable; +pub mod variable; pub use variable::*; #[cfg(feature = "visit")] diff --git a/crates/syn-solidity/src/type/mod.rs b/crates/syn-solidity/src/type/mod.rs index fd78226603..2a826d7be5 100644 --- a/crates/syn-solidity/src/type/mod.rs +++ b/crates/syn-solidity/src/type/mod.rs @@ -12,16 +12,16 @@ use syn::{ Error, Ident, Result, Token, }; -mod array; +pub mod array; pub use array::*; -mod function; +pub mod function; pub use function::*; -mod mapping; +pub mod mapping; pub use mapping::*; -mod tuple; +pub mod tuple; pub use tuple::*; /// A type name. From a18219f7d1221d5814262b6ddfe3463299180ed6 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Sun, 2 Jul 2023 19:40:52 -0300 Subject: [PATCH 03/22] feat: add statments --- crates/syn-solidity/src/lib.rs | 5 +++-- crates/syn-solidity/src/statments/cast.rs | 0 crates/syn-solidity/src/statments/expr.rs | 11 +++++++++++ crates/syn-solidity/src/statments/for.rs | 0 crates/syn-solidity/src/statments/if.rs | 0 crates/syn-solidity/src/statments/mod.rs | 6 ++++++ crates/syn-solidity/src/statments/operators/mod.rs | 1 + crates/syn-solidity/src/statments/operators/not.rs | 6 ++++++ crates/syn-solidity/src/statments/while.rs | 0 9 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 crates/syn-solidity/src/statments/cast.rs create mode 100644 crates/syn-solidity/src/statments/expr.rs create mode 100644 crates/syn-solidity/src/statments/for.rs create mode 100644 crates/syn-solidity/src/statments/if.rs create mode 100644 crates/syn-solidity/src/statments/mod.rs create mode 100644 crates/syn-solidity/src/statments/operators/mod.rs create mode 100644 crates/syn-solidity/src/statments/operators/not.rs create mode 100644 crates/syn-solidity/src/statments/while.rs diff --git a/crates/syn-solidity/src/lib.rs b/crates/syn-solidity/src/lib.rs index e050d5394c..a41d8ce8ec 100644 --- a/crates/syn-solidity/src/lib.rs +++ b/crates/syn-solidity/src/lib.rs @@ -23,6 +23,9 @@ mod macros; pub mod attribute; pub use attribute::*; +pub mod statments; +pub use statments::*; + pub mod file; pub use file::*; @@ -35,13 +38,11 @@ pub mod lit; pub use lit::*; pub mod kw; -pub use kw::*; pub mod stmt; pub use stmt::*; pub mod r#type; -pub use r#type::*; pub(crate) mod utils; diff --git a/crates/syn-solidity/src/statments/cast.rs b/crates/syn-solidity/src/statments/cast.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/crates/syn-solidity/src/statments/expr.rs b/crates/syn-solidity/src/statments/expr.rs new file mode 100644 index 0000000000..6f0f19128b --- /dev/null +++ b/crates/syn-solidity/src/statments/expr.rs @@ -0,0 +1,11 @@ +use crate::Block; + +pub enum Expr { + Loop(), + If(), + ForLoop(), + Cast(), + Assign(), + Block(Block), + Index(), +} diff --git a/crates/syn-solidity/src/statments/for.rs b/crates/syn-solidity/src/statments/for.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/crates/syn-solidity/src/statments/if.rs b/crates/syn-solidity/src/statments/if.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/crates/syn-solidity/src/statments/mod.rs b/crates/syn-solidity/src/statments/mod.rs new file mode 100644 index 0000000000..9ae29270ef --- /dev/null +++ b/crates/syn-solidity/src/statments/mod.rs @@ -0,0 +1,6 @@ +pub mod expr; +pub mod r#for; +pub mod r#if; +pub mod operators; +pub mod r#while; +pub mod cast; diff --git a/crates/syn-solidity/src/statments/operators/mod.rs b/crates/syn-solidity/src/statments/operators/mod.rs new file mode 100644 index 0000000000..3654a7a242 --- /dev/null +++ b/crates/syn-solidity/src/statments/operators/mod.rs @@ -0,0 +1 @@ +pub mod not; diff --git a/crates/syn-solidity/src/statments/operators/not.rs b/crates/syn-solidity/src/statments/operators/not.rs new file mode 100644 index 0000000000..562a790d8f --- /dev/null +++ b/crates/syn-solidity/src/statments/operators/not.rs @@ -0,0 +1,6 @@ +use proc_macro2::Span; + +pub struct Not { + pub spans: Span, +} + diff --git a/crates/syn-solidity/src/statments/while.rs b/crates/syn-solidity/src/statments/while.rs new file mode 100644 index 0000000000..e69de29bb2 From b9e3d309aed34c8581bef53224fea274c20cfafb Mon Sep 17 00:00:00 2001 From: Will Smith Date: Wed, 19 Jul 2023 17:17:55 +0200 Subject: [PATCH 04/22] feat: add stmts --- crates/syn-solidity/src/kw.rs | 2 + .../syn-solidity/src/statments/assignment.rs | 19 ++++ crates/syn-solidity/src/statments/binop.rs | 21 +++++ .../syn-solidity/src/statments/binops/mod.rs | 70 +++++++++++++++ .../syn-solidity/src/statments/binops/pow.rs | 17 ++++ .../src/statments/binops/ternary.rs | 29 ++++++ crates/syn-solidity/src/statments/cast.rs | 0 crates/syn-solidity/src/statments/expr.rs | 90 +++++++++++++++++-- crates/syn-solidity/src/statments/field.rs | 20 +++++ crates/syn-solidity/src/statments/for.rs | 42 +++++++++ crates/syn-solidity/src/statments/if.rs | 48 ++++++++++ crates/syn-solidity/src/statments/index.rs | 21 +++++ .../syn-solidity/src/statments/method_call.rs | 27 ++++++ crates/syn-solidity/src/statments/mod.rs | 9 +- .../src/statments/operators/mod.rs | 1 - .../src/statments/operators/not.rs | 6 -- .../syn-solidity/src/statments/try_catch.rs | 72 +++++++++++++++ crates/syn-solidity/src/statments/while.rs | 61 +++++++++++++ crates/syn-solidity/src/stmt.rs | 8 +- 19 files changed, 544 insertions(+), 19 deletions(-) create mode 100644 crates/syn-solidity/src/statments/assignment.rs create mode 100644 crates/syn-solidity/src/statments/binop.rs create mode 100644 crates/syn-solidity/src/statments/binops/mod.rs create mode 100644 crates/syn-solidity/src/statments/binops/pow.rs create mode 100644 crates/syn-solidity/src/statments/binops/ternary.rs delete mode 100644 crates/syn-solidity/src/statments/cast.rs create mode 100644 crates/syn-solidity/src/statments/field.rs create mode 100644 crates/syn-solidity/src/statments/index.rs create mode 100644 crates/syn-solidity/src/statments/method_call.rs delete mode 100644 crates/syn-solidity/src/statments/operators/mod.rs delete mode 100644 crates/syn-solidity/src/statments/operators/not.rs create mode 100644 crates/syn-solidity/src/statments/try_catch.rs diff --git a/crates/syn-solidity/src/kw.rs b/crates/syn-solidity/src/kw.rs index f277640bcd..41777a88ba 100644 --- a/crates/syn-solidity/src/kw.rs +++ b/crates/syn-solidity/src/kw.rs @@ -35,6 +35,7 @@ custom_keywords!( // Error error, + panic, // Event event, @@ -70,4 +71,5 @@ custom_keywords!( // Other is, unicode, + catch, ); diff --git a/crates/syn-solidity/src/statments/assignment.rs b/crates/syn-solidity/src/statments/assignment.rs new file mode 100644 index 0000000000..13e1ca462f --- /dev/null +++ b/crates/syn-solidity/src/statments/assignment.rs @@ -0,0 +1,19 @@ +use crate::expr::Expr; +use syn::{parse::Parse, token::Eq, Ident}; + +#[derive(Debug, Clone)] +pub struct AssignmentExpr { + pub ident: Ident, + pub eq: Eq, + pub assign: Box, +} + +impl Parse for AssignmentExpr { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + let ident: Ident = input.parse()?; + let eq: Eq = input.parse()?; + let assign: Box = Box::new(input.parse()?); + + Ok(Self { assign, ident, eq }) + } +} diff --git a/crates/syn-solidity/src/statments/binop.rs b/crates/syn-solidity/src/statments/binop.rs new file mode 100644 index 0000000000..172743a00f --- /dev/null +++ b/crates/syn-solidity/src/statments/binop.rs @@ -0,0 +1,21 @@ +use crate::binops::Binop; +use syn::parse::Parse; + +use crate::expr::Expr; + +#[derive(Debug, Clone)] +pub struct BinopExpr { + pub left: Box, + pub op: Binop, + pub right: Box, +} + +impl Parse for BinopExpr { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + Ok(Self { + left: Box::new(input.parse()?), + op: input.parse()?, + right: Box::new(input.parse()?), + }) + } +} diff --git a/crates/syn-solidity/src/statments/binops/mod.rs b/crates/syn-solidity/src/statments/binops/mod.rs new file mode 100644 index 0000000000..0e42d014fd --- /dev/null +++ b/crates/syn-solidity/src/statments/binops/mod.rs @@ -0,0 +1,70 @@ +pub mod pow; +pub mod ternary; + +use self::pow::PowOps; + +use super::binops::ternary::Ternary; +use syn::{parse::Parse, Token}; + +#[derive(Debug, Clone)] +pub enum Binop { + Assign(Token![=]), + Add(Token![+]), + AddAssign(Token![+=]), + Minus(Token![-]), + MinusAssign(Token![-=]), + Mul(Token![*]), + MulAssign(Token![*=]), + Not(Token![!]), + BitNot(Token![~]), + Div(Token![/]), + DivAssign(Token![/=]), + Mod(Token![%]), + ModAssign(Token![%=]), + BitAnd(Token![&]), + AndAssign(Token![&=]), + BitXor(Token![^]), + XorAssign(Token![^=]), + BitOr(Token![|]), + Shl(Token![<<]), + ShlAssign(Token![<<=]), + Shr(Token![>>]), + ShrAssign(Token![>>=]), + Equality(Token![==]), + And(Token![&&]), + Or(Token![||]), + Ternary(Ternary), + // don't have in rust but swag + Exponent(PowOps), +} + +impl Parse for Binop { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + || { + input.peek(Token![~]) + || input.peek2(Token!(=)) + || input.peek2(Token!(+)) + || input.peek2(Token!(+=)) + || input.peek2(Token!(-)) + || input.peek2(Token!(-=)) + || input.peek2(Token!(*)) + || input.peek2(Token!(*=)) + || input.peek2(Token!(/)) + || input.peek2(Token!(/=)) + || input.peek2(Token!(%)) + || input.peek2(Token!(%=)) + || input.peek2(Token!(&)) + || input.peek2(Token!(&=)) + || input.peek2(Token!(^)) + || input.peek2(Token!(^=)) + || input.peek2(Token!(|)) + || input.peek2(Token!(<<)) + || input.peek2(Token!(<<=)) + || input.peek2(Token!(>>)) + || input.peek2(Token!(>>=)) + || input.peek2(Token!(==)) + || input.peek2(Token!(&&)) + || input.peek2(Token!(||)) + } + } +} diff --git a/crates/syn-solidity/src/statments/binops/pow.rs b/crates/syn-solidity/src/statments/binops/pow.rs new file mode 100644 index 0000000000..61b5a608c4 --- /dev/null +++ b/crates/syn-solidity/src/statments/binops/pow.rs @@ -0,0 +1,17 @@ +use syn::{parse::Parse, Token}; + +/// def not right way todo this but we ballin +#[derive(Debug, Clone)] +pub struct PowOps { + pub star0: Token!(*), + pub star1: Token!(*), +} + +impl Parse for PowOps { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + Ok(Self { + star0: input.parse()?, + star1: input.parse()?, + }) + } +} diff --git a/crates/syn-solidity/src/statments/binops/ternary.rs b/crates/syn-solidity/src/statments/binops/ternary.rs new file mode 100644 index 0000000000..529ff66c97 --- /dev/null +++ b/crates/syn-solidity/src/statments/binops/ternary.rs @@ -0,0 +1,29 @@ +use crate::expr::Expr; +use syn::{parse::Parse, Token}; + +#[derive(Debug, Clone)] +pub struct Ternary { + pub var1: Box, + pub q: Token![?], + pub res_0: Box, + pub semi: Token![;], + pub res_1: Box, +} + +impl Parse for Ternary { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + let var1 = Box::new(input.parse()?); + let q = input.parse()?; + let res_0 = Box::new(input.parse()?); + let semi = input.parse()?; + let res_1 = Box::new(input.parse()?); + + Ok(Self { + res_1, + semi, + res_0, + var1, + q, + }) + } +} diff --git a/crates/syn-solidity/src/statments/cast.rs b/crates/syn-solidity/src/statments/cast.rs deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/crates/syn-solidity/src/statments/expr.rs b/crates/syn-solidity/src/statments/expr.rs index 6f0f19128b..0438d2d254 100644 --- a/crates/syn-solidity/src/statments/expr.rs +++ b/crates/syn-solidity/src/statments/expr.rs @@ -1,11 +1,85 @@ -use crate::Block; +use crate::{ + assignment::AssignmentExpr, + binop::BinopExpr, + binops::{pow::PowOps, Binop}, + index::Index, + method_call::MethodCall, + r#for::ForStmt, + r#if::IfStmt, + r#while::{DoWhile, While}, +}; +use syn::{ + parse::Parse, + token::{Bracket, Paren}, + Ident, Token, +}; + +#[derive(Clone, Debug)] pub enum Expr { - Loop(), - If(), - ForLoop(), - Cast(), - Assign(), - Block(Block), - Index(), + While(While), + DoWhile(DoWhile), + If(IfStmt), + ForLoop(ForStmt), + Assign(AssignmentExpr), + Index(Index), + Binop(BinopExpr), + MethodCall(MethodCall), +} + +impl Parse for Vec { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + todo!() + } +} + +impl Parse for Expr { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + if input.peek(Token![while]) { + return Ok(Self::While(While::parse(input)?)) + } else if input.peek(Token![do]) { + return Ok(Self::DoWhile(DoWhile::parse(input)?)) + } else if input.peek(Token![if]) { + return Ok(Self::If(IfStmt::parse(input)?)) + } else if input.peek(Token![for]) { + return Ok(Self::ForLoop(ForStmt::parse(input)?)) + } else if input.peek2(Bracket) { + return Ok(Self::Index(Index::parse(input)?)) + } else if input.peek(Ident) && input.peek2(Paren) { + return Ok(Self::MethodCall(MethodCall::parse(input)?)) + // so jank feel like should be better way but just send it ig + } else if input.peek(Token![!]) + || input.peek(Token![~]) + || input.peek2(Token!(=)) + || input.peek2(Token!(+)) + || input.peek2(Token!(+=)) + || input.peek2(Token!(-)) + || input.peek2(Token!(-=)) + || input.peek2(Token!(*)) + || input.peek2(Token!(*=)) + || input.peek2(Token!(/)) + || input.peek2(Token!(/=)) + || input.peek2(Token!(%)) + || input.peek2(Token!(%=)) + || input.peek2(Token!(&)) + || input.peek2(Token!(&=)) + || input.peek2(Token!(^)) + || input.peek2(Token!(^=)) + || input.peek2(Token!(|)) + || input.peek2(Token!(<<)) + || input.peek2(Token!(<<=)) + || input.peek2(Token!(>>)) + || input.peek2(Token!(>>=)) + || input.peek2(Token!(==)) + || input.peek2(Token!(&&)) + || input.peek2(Token!(||)) + { + return Ok(Self::Binop(Binop::parse(input)?)) + } else { + Err(syn::Error::new( + input.span(), + format!("{:?} Path not implimented", input), + )) + } + } } diff --git a/crates/syn-solidity/src/statments/field.rs b/crates/syn-solidity/src/statments/field.rs new file mode 100644 index 0000000000..d643865a2e --- /dev/null +++ b/crates/syn-solidity/src/statments/field.rs @@ -0,0 +1,20 @@ +use crate::expr::Expr; +use proc_macro2::Ident; +use syn::{parse::Parse, Token}; + +#[derive(Debug, Clone)] +pub struct Field { + pub base: Box, + pub dot: Token![.], + pub name: Ident, +} + +impl Parse for Field { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + Ok(Self { + base: input.parse()?, + dot: input.parse()?, + name: input.parse()?, + }) + } +} diff --git a/crates/syn-solidity/src/statments/for.rs b/crates/syn-solidity/src/statments/for.rs index e69de29bb2..8e48269d67 100644 --- a/crates/syn-solidity/src/statments/for.rs +++ b/crates/syn-solidity/src/statments/for.rs @@ -0,0 +1,42 @@ +use crate::{assignment::AssignmentExpr, expr::Expr, Block}; +use syn::{parse::Parse, token::Paren, Token}; + +#[derive(Debug, Clone)] +pub struct ForStmt { + pub for_token: Token![for], + pub for_assign: ForAssignment, +} + +#[derive(Debug, Clone)] +pub struct ForAssignment { + pub brace: Paren, + pub iter_asign: AssignmentExpr, + pub semi: Token![;], + pub cond: Box, + pub semi2: Token![;], + pub up_cond: Option>, + pub block: Block, +} + +impl Parse for ForStmt { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + Ok(Self { + for_token: input.parse()?, + for_assign: input.parse()?, + }) + } +} + +impl Parse for ForAssignment { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + Ok(Self { + brace: input.parse()?, + iter_asign: input.parse()?, + semi: input.parse()?, + cond: Box::new(input.parse()?), + semi2: input.parse()?, + up_cond: input.parse().ok(), + block: input.parse()?, + }) + } +} diff --git a/crates/syn-solidity/src/statments/if.rs b/crates/syn-solidity/src/statments/if.rs index e69de29bb2..165842f5ed 100644 --- a/crates/syn-solidity/src/statments/if.rs +++ b/crates/syn-solidity/src/statments/if.rs @@ -0,0 +1,48 @@ +use syn::{parse::Parse, Token}; + +use crate::Block; + +#[derive(Debug, Clone)] +pub enum IfStmtType { + ElseIf, + Else, +} + +#[derive(Debug, Clone)] +pub struct IfStmt { + pub init: Token![if], + pub optional_stmts: Vec, + pub expr: Block, +} + +impl Parse for IfStmtType { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + if input.peek2(Token!(if)) { + Ok(Self::ElseIf) + } else if input.peek(Token![else]) { + Ok(Self::Else) + } else { + Err(syn::Error::new( + input.span(), + "secondary control flow parsing failed", + )) + } + } +} +impl Parse for IfStmt { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + let init = input.parse()?; + let mut optional = Vec::new(); + + let fork = input.fork(); + while let Ok(stmt) = fork.parse::() { + optional.push(stmt); + } + + Ok(Self { + init, + optional_stmts: optional, + expr: input.parse(), + }) + } +} diff --git a/crates/syn-solidity/src/statments/index.rs b/crates/syn-solidity/src/statments/index.rs new file mode 100644 index 0000000000..48b8054404 --- /dev/null +++ b/crates/syn-solidity/src/statments/index.rs @@ -0,0 +1,21 @@ +use proc_macro2::Ident; +use syn::{parse::Parse, token::Bracket}; + +use crate::expr::Expr; + +#[derive(Debug, Clone)] +pub struct Index { + pub name: Ident, + pub bracket: Bracket, + pub index_by: Box, +} + +impl Parse for Index { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + Ok(Self { + name: input.parse()?, + bracket: input.parse()?, + index_by: input.parse()?, + }) + } +} diff --git a/crates/syn-solidity/src/statments/method_call.rs b/crates/syn-solidity/src/statments/method_call.rs new file mode 100644 index 0000000000..6968f9a11a --- /dev/null +++ b/crates/syn-solidity/src/statments/method_call.rs @@ -0,0 +1,27 @@ +use proc_macro2::Ident; + +use crate::{Parameters, VariableDeclaration}; +use syn::{parse::Parse, token::Paren, Token}; + +pub struct MethodCall { + pub fn_name: Ident, + pub paren_token: Paren, + pub arguments: Parameters, +} + +impl Parse for MethodCall { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + let fn_name = input.parse()?; + let paren = input.parse()?; + let mut args = Parameters::new(); + while let Ok(arg) = input.parse::() { + args.push(arg); + } + + Ok(Self { + fn_name, + paren_token: paren, + arguments: args, + }) + } +} diff --git a/crates/syn-solidity/src/statments/mod.rs b/crates/syn-solidity/src/statments/mod.rs index 9ae29270ef..e3972841a6 100644 --- a/crates/syn-solidity/src/statments/mod.rs +++ b/crates/syn-solidity/src/statments/mod.rs @@ -1,6 +1,11 @@ +pub mod assignment; +pub mod binop; +pub mod binops; pub mod expr; +pub mod field; pub mod r#for; pub mod r#if; -pub mod operators; +pub mod index; +pub mod method_call; +pub mod try_catch; pub mod r#while; -pub mod cast; diff --git a/crates/syn-solidity/src/statments/operators/mod.rs b/crates/syn-solidity/src/statments/operators/mod.rs deleted file mode 100644 index 3654a7a242..0000000000 --- a/crates/syn-solidity/src/statments/operators/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod not; diff --git a/crates/syn-solidity/src/statments/operators/not.rs b/crates/syn-solidity/src/statments/operators/not.rs deleted file mode 100644 index 562a790d8f..0000000000 --- a/crates/syn-solidity/src/statments/operators/not.rs +++ /dev/null @@ -1,6 +0,0 @@ -use proc_macro2::Span; - -pub struct Not { - pub spans: Span, -} - diff --git a/crates/syn-solidity/src/statments/try_catch.rs b/crates/syn-solidity/src/statments/try_catch.rs new file mode 100644 index 0000000000..9d399a8217 --- /dev/null +++ b/crates/syn-solidity/src/statments/try_catch.rs @@ -0,0 +1,72 @@ +use crate::{kw, Block, Parameters, VariableDeclaration}; +use syn::{parse::Parse, token::Paren, Token}; + +// annoying since there is 4 differnt types of error catching methods +#[derive(Debug, Clone)] +pub struct TryCatch { + pub r#try: Token![try], + pub block: Block, + pub catch: Catch, +} + +pub struct Catch { + pub error: Option, + pub panic: Option, + // this is tech o + pub args: Option>, + pub block: Block, +} + +impl Parse for Catch { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + let (error, panic) = if input.peek(kw::error) { + (Some(kw::error(input.span())), None) + } else if input.peek(kw::panic) { + (None, Some(kw::panic(input.span()))) + } else { + (None, None) + }; + + let args = if error.is_none() && panic.is_none() { + if input.peek(Paren) { + // we have args + let f = input.fork(); + let mut args = Parameters::new(); + while let Ok(arg) = input.parse::() { + args.push(arg); + } + Some(args) + } else { + // they raw doggin + None + } + } else { + let mut args = Parameters::new(); + while let Ok(arg) = input.parse::() { + args.push(arg); + } + Some(args) + }; + + Ok(Self { + error, + panic, + args, + block: input.parse()?, + }) + } +} + +impl Parse for TryCatch { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + let a_try = input.parse()?; + let block = input.parse()?; + let catch = input.parse()?; + + Ok(Self { + r#try: a_try, + block, + catch, + }) + } +} diff --git a/crates/syn-solidity/src/statments/while.rs b/crates/syn-solidity/src/statments/while.rs index e69de29bb2..31031baadd 100644 --- a/crates/syn-solidity/src/statments/while.rs +++ b/crates/syn-solidity/src/statments/while.rs @@ -0,0 +1,61 @@ +use syn::{ + parse::Parse, + token::{Brace, Paren}, + Token, +}; + +use crate::{expr::Expr, Block}; + +#[derive(Debug, Clone)] +pub struct DoWhile { + pub do_token: Token![do], + pub brace: Brace, + pub block: Block, + pub while_token: Token![while], + pub paren: Paren, + pub expr: Box, +} + +impl Parse for DoWhile { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + let do_token = input.parse()?; + let brace = input.parse()?; + let block = input.parse()?; + let while_token = input.parse()?; + let paren = input.parse()?; + let expr = Box::new(input.parse()?); + + Ok(Self { + do_token, + brace, + block, + while_token, + paren, + expr, + }) + } +} + +#[derive(Debug, Clone)] +pub struct While { + pub while_token: Token![while], + pub paren: Paren, + pub expr: Box, + pub block: Block, +} + +impl Parse for While { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + let while_token = input.parse()?; + let paren = input.parse()?; + let expr = input.parse()?; + let block = input.parse()?; + + Ok(Self { + while_token, + paren, + expr, + block, + }) + } +} diff --git a/crates/syn-solidity/src/stmt.rs b/crates/syn-solidity/src/stmt.rs index 4f6cebf3a0..761935126c 100644 --- a/crates/syn-solidity/src/stmt.rs +++ b/crates/syn-solidity/src/stmt.rs @@ -1,4 +1,3 @@ -use proc_macro2::TokenStream; use std::fmt; use syn::{ parse::{Parse, ParseStream}, @@ -6,11 +5,13 @@ use syn::{ Result, }; +use crate::expr::Expr; + /// A curly-braced block of statements. #[derive(Clone)] pub struct Block { pub brace_token: Brace, - pub stmts: TokenStream, + pub stmts: Vec, } impl fmt::Debug for Block { @@ -22,6 +23,9 @@ impl fmt::Debug for Block { impl Parse for Block { fn parse(input: ParseStream<'_>) -> Result { let content; + + let fork = input.fork(); + Ok(Self { brace_token: syn::braced!(content in input), stmts: content.parse()?, From f3ac52da99f32f3baf74911152c17fc9d1b5754d Mon Sep 17 00:00:00 2001 From: Will Smith Date: Thu, 20 Jul 2023 13:44:30 +0200 Subject: [PATCH 05/22] just missing lits --- crates/syn-solidity/src/kw.rs | 6 ++ crates/syn-solidity/src/statments/assembly.rs | 12 ++++ .../syn-solidity/src/statments/assignment.rs | 8 +-- .../syn-solidity/src/statments/binops/mod.rs | 62 ++++++++++--------- .../syn-solidity/src/statments/call_args.rs | 34 ++++++++++ crates/syn-solidity/src/statments/emit.rs | 21 +++++++ crates/syn-solidity/src/statments/expr.rs | 25 +++++--- crates/syn-solidity/src/statments/for.rs | 5 +- crates/syn-solidity/src/statments/if.rs | 3 +- crates/syn-solidity/src/statments/index.rs | 5 +- .../src/statments/inline_array_expr.rs | 24 +++++++ crates/syn-solidity/src/statments/loop_ops.rs | 7 +++ .../syn-solidity/src/statments/method_call.rs | 6 +- crates/syn-solidity/src/statments/mod.rs | 10 +++ crates/syn-solidity/src/statments/new.rs | 17 +++++ crates/syn-solidity/src/statments/return.rs | 19 ++++++ crates/syn-solidity/src/statments/revert.rs | 21 +++++++ .../syn-solidity/src/statments/try_catch.rs | 1 + .../syn-solidity/src/statments/tuple_expr.rs | 25 ++++++++ .../syn-solidity/src/statments/unchecked.rs | 18 ++++++ crates/syn-solidity/src/statments/while.rs | 16 ++--- crates/syn-solidity/src/stmt.rs | 7 ++- 22 files changed, 291 insertions(+), 61 deletions(-) create mode 100644 crates/syn-solidity/src/statments/assembly.rs create mode 100644 crates/syn-solidity/src/statments/call_args.rs create mode 100644 crates/syn-solidity/src/statments/emit.rs create mode 100644 crates/syn-solidity/src/statments/inline_array_expr.rs create mode 100644 crates/syn-solidity/src/statments/loop_ops.rs create mode 100644 crates/syn-solidity/src/statments/new.rs create mode 100644 crates/syn-solidity/src/statments/return.rs create mode 100644 crates/syn-solidity/src/statments/revert.rs create mode 100644 crates/syn-solidity/src/statments/tuple_expr.rs create mode 100644 crates/syn-solidity/src/statments/unchecked.rs diff --git a/crates/syn-solidity/src/kw.rs b/crates/syn-solidity/src/kw.rs index 41777a88ba..c6649cca00 100644 --- a/crates/syn-solidity/src/kw.rs +++ b/crates/syn-solidity/src/kw.rs @@ -72,4 +72,10 @@ custom_keywords!( is, unicode, catch, + delete, + unchecked, + new, + emit, + revert, + assembly, ); diff --git a/crates/syn-solidity/src/statments/assembly.rs b/crates/syn-solidity/src/statments/assembly.rs new file mode 100644 index 0000000000..538c482de5 --- /dev/null +++ b/crates/syn-solidity/src/statments/assembly.rs @@ -0,0 +1,12 @@ +use proc_macro2::TokenStream; +use syn::token::Brace; + +use crate::kw; + +#[derive(Debug, Clone)] +pub struct Assembly { + kw: kw::assembly, + // stuff here + brace: Brace, + input: TokenStream, +} diff --git a/crates/syn-solidity/src/statments/assignment.rs b/crates/syn-solidity/src/statments/assignment.rs index 13e1ca462f..bf05b5c46e 100644 --- a/crates/syn-solidity/src/statments/assignment.rs +++ b/crates/syn-solidity/src/statments/assignment.rs @@ -1,19 +1,19 @@ use crate::expr::Expr; -use syn::{parse::Parse, token::Eq, Ident}; +use syn::{parse::Parse, token::Eq}; #[derive(Debug, Clone)] pub struct AssignmentExpr { - pub ident: Ident, + pub left: Box, pub eq: Eq, pub assign: Box, } impl Parse for AssignmentExpr { fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { - let ident: Ident = input.parse()?; + let left = input.parse()?; let eq: Eq = input.parse()?; let assign: Box = Box::new(input.parse()?); - Ok(Self { assign, ident, eq }) + Ok(Self { left, assign, eq }) } } diff --git a/crates/syn-solidity/src/statments/binops/mod.rs b/crates/syn-solidity/src/statments/binops/mod.rs index 0e42d014fd..2a2922f57e 100644 --- a/crates/syn-solidity/src/statments/binops/mod.rs +++ b/crates/syn-solidity/src/statments/binops/mod.rs @@ -1,6 +1,8 @@ pub mod pow; pub mod ternary; +use crate::kw; + use self::pow::PowOps; use super::binops::ternary::Ternary; @@ -36,35 +38,35 @@ pub enum Binop { Ternary(Ternary), // don't have in rust but swag Exponent(PowOps), + Delete(kw::delete), } -impl Parse for Binop { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { - || { - input.peek(Token![~]) - || input.peek2(Token!(=)) - || input.peek2(Token!(+)) - || input.peek2(Token!(+=)) - || input.peek2(Token!(-)) - || input.peek2(Token!(-=)) - || input.peek2(Token!(*)) - || input.peek2(Token!(*=)) - || input.peek2(Token!(/)) - || input.peek2(Token!(/=)) - || input.peek2(Token!(%)) - || input.peek2(Token!(%=)) - || input.peek2(Token!(&)) - || input.peek2(Token!(&=)) - || input.peek2(Token!(^)) - || input.peek2(Token!(^=)) - || input.peek2(Token!(|)) - || input.peek2(Token!(<<)) - || input.peek2(Token!(<<=)) - || input.peek2(Token!(>>)) - || input.peek2(Token!(>>=)) - || input.peek2(Token!(==)) - || input.peek2(Token!(&&)) - || input.peek2(Token!(||)) - } - } -} +// impl Parse for Binop { +// fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { +// input.peek(Token![~]) +// || input.peek2(Token!(=)) +// || input.peek2(Token!(+)) +// || input.peek2(Token!(+=)) +// || input.peek2(Token!(-)) +// || input.peek2(Token!(-=)) +// || input.peek2(Token!(*)) +// || input.peek2(Token!(*=)) +// || input.peek2(Token!(/)) +// || input.peek2(Token!(/=)) +// || input.peek2(Token!(%)) +// || input.peek2(Token!(%=)) +// || input.peek2(Token!(&)) +// || input.peek2(Token!(&=)) +// || input.peek2(Token!(^)) +// || input.peek2(Token!(^=)) +// || input.peek2(Token!(|)) +// || input.peek2(Token!(<<)) +// || input.peek2(Token!(<<=)) +// || input.peek2(Token!(>>)) +// || input.peek2(Token!(>>=)) +// || input.peek2(Token!(==)) +// || input.peek2(Token!(&&)) +// || input.peek2(Token!(||)) +// } +// } +// } diff --git a/crates/syn-solidity/src/statments/call_args.rs b/crates/syn-solidity/src/statments/call_args.rs new file mode 100644 index 0000000000..57f7129562 --- /dev/null +++ b/crates/syn-solidity/src/statments/call_args.rs @@ -0,0 +1,34 @@ +use syn::{parse::Parse, punctuated::Punctuated, Ident, Token}; + +use crate::expr::Expr; + +#[derive(Debug, Clone)] +pub enum CallArgs { + Map(MapArgs), + List(ListArgs), +} + +#[derive(Debug, Clone)] +pub struct MapArgs(Punctuated); + +#[derive(Debug, Clone)] +pub struct Map { + pub key: Ident, + pub value: Box, +} + +#[derive(Debug, Clone)] +pub struct ListArgs(Punctuated); + +impl Parse for CallArgs { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result {} +} +impl Parse for MapArgs { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result {} +} +impl Parse for Map { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result {} +} +impl Parse for ListArgs { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result {} +} diff --git a/crates/syn-solidity/src/statments/emit.rs b/crates/syn-solidity/src/statments/emit.rs new file mode 100644 index 0000000000..7b17f35bcf --- /dev/null +++ b/crates/syn-solidity/src/statments/emit.rs @@ -0,0 +1,21 @@ +use crate::{call_args::CallArgs, expr::Expr, kw}; +use syn::{parse::Parse, Token}; + +#[derive(Debug, Clone)] +pub struct Emit { + keyword: kw::emit, + expr: Box, + args: CallArgs, + semi: Token!(;), +} + +impl Parse for Emit { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + Ok(Self { + keyword: input.parse()?, + expr: Box::new(input.parse()?), + args: input.parse()?, + semi: input.parse()?, + }) + } +} diff --git a/crates/syn-solidity/src/statments/expr.rs b/crates/syn-solidity/src/statments/expr.rs index 0438d2d254..04b891e450 100644 --- a/crates/syn-solidity/src/statments/expr.rs +++ b/crates/syn-solidity/src/statments/expr.rs @@ -1,12 +1,19 @@ use crate::{ assignment::AssignmentExpr, binop::BinopExpr, - binops::{pow::PowOps, Binop}, + emit::Emit, index::Index, + inline_array_expr::InlineArrayExpr, + loop_ops::LoopOps, method_call::MethodCall, + new::New, r#for::ForStmt, r#if::IfStmt, + r#return::Return, r#while::{DoWhile, While}, + revert::Revert, + tuple_expr::TupleExpr, + unchecked::Unchecked, }; use syn::{ @@ -21,16 +28,18 @@ pub enum Expr { DoWhile(DoWhile), If(IfStmt), ForLoop(ForStmt), + LoopOps(LoopOps), Assign(AssignmentExpr), Index(Index), Binop(BinopExpr), MethodCall(MethodCall), -} - -impl Parse for Vec { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { - todo!() - } + Return(Return), + Emit(Emit), + Unchecked(Unchecked), + Revert(Revert), + Tuple(TupleExpr), + InlineArray(InlineArrayExpr), + New(New), } impl Parse for Expr { @@ -74,7 +83,7 @@ impl Parse for Expr { || input.peek2(Token!(&&)) || input.peek2(Token!(||)) { - return Ok(Self::Binop(Binop::parse(input)?)) + return Ok(Self::Binop(BinopExpr::parse(input)?)) } else { Err(syn::Error::new( input.span(), diff --git a/crates/syn-solidity/src/statments/for.rs b/crates/syn-solidity/src/statments/for.rs index 8e48269d67..cb91ef3336 100644 --- a/crates/syn-solidity/src/statments/for.rs +++ b/crates/syn-solidity/src/statments/for.rs @@ -1,5 +1,5 @@ use crate::{assignment::AssignmentExpr, expr::Expr, Block}; -use syn::{parse::Parse, token::Paren, Token}; +use syn::{parenthesized, parse::Parse, token::Paren, Token}; #[derive(Debug, Clone)] pub struct ForStmt { @@ -29,8 +29,9 @@ impl Parse for ForStmt { impl Parse for ForAssignment { fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + let content; Ok(Self { - brace: input.parse()?, + brace: parenthesized!(content in input), iter_asign: input.parse()?, semi: input.parse()?, cond: Box::new(input.parse()?), diff --git a/crates/syn-solidity/src/statments/if.rs b/crates/syn-solidity/src/statments/if.rs index 165842f5ed..627d50083b 100644 --- a/crates/syn-solidity/src/statments/if.rs +++ b/crates/syn-solidity/src/statments/if.rs @@ -34,6 +34,7 @@ impl Parse for IfStmt { let init = input.parse()?; let mut optional = Vec::new(); + // this wrong let fork = input.fork(); while let Ok(stmt) = fork.parse::() { optional.push(stmt); @@ -42,7 +43,7 @@ impl Parse for IfStmt { Ok(Self { init, optional_stmts: optional, - expr: input.parse(), + expr: input.parse()?, }) } } diff --git a/crates/syn-solidity/src/statments/index.rs b/crates/syn-solidity/src/statments/index.rs index 48b8054404..302ad98b64 100644 --- a/crates/syn-solidity/src/statments/index.rs +++ b/crates/syn-solidity/src/statments/index.rs @@ -1,5 +1,5 @@ use proc_macro2::Ident; -use syn::{parse::Parse, token::Bracket}; +use syn::{bracketed, parse::Parse, token::Bracket}; use crate::expr::Expr; @@ -12,9 +12,10 @@ pub struct Index { impl Parse for Index { fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + let content; Ok(Self { name: input.parse()?, - bracket: input.parse()?, + bracket: bracketed!(content in input), index_by: input.parse()?, }) } diff --git a/crates/syn-solidity/src/statments/inline_array_expr.rs b/crates/syn-solidity/src/statments/inline_array_expr.rs new file mode 100644 index 0000000000..54221bbff8 --- /dev/null +++ b/crates/syn-solidity/src/statments/inline_array_expr.rs @@ -0,0 +1,24 @@ +use crate::expr::Expr; +use syn::{bracketed, parse::Parse, punctuated::Punctuated, token::Bracket, Token}; + +#[derive(Debug, Clone)] +pub struct InlineArrayExpr { + bracket: Bracket, + exprs: Punctuated, +} + +impl Parse for InlineArrayExpr { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + let content; + let bracket = bracketed!(content in input); + + let mut exprs = Punctuated::new(); + exprs.push(input.parse()?); + while input.peek(Token![,]) { + exprs.push(input.parse()?); + } + exprs.push(input.parse()?); + + Ok(Self { exprs, bracket }) + } +} diff --git a/crates/syn-solidity/src/statments/loop_ops.rs b/crates/syn-solidity/src/statments/loop_ops.rs new file mode 100644 index 0000000000..6489836de2 --- /dev/null +++ b/crates/syn-solidity/src/statments/loop_ops.rs @@ -0,0 +1,7 @@ +use syn::Token; + +#[derive(Debug, Clone)] +pub enum LoopOps { + Continue(Token!(continue)), + Break(Token!(break)), +} diff --git a/crates/syn-solidity/src/statments/method_call.rs b/crates/syn-solidity/src/statments/method_call.rs index 6968f9a11a..84a7bd6394 100644 --- a/crates/syn-solidity/src/statments/method_call.rs +++ b/crates/syn-solidity/src/statments/method_call.rs @@ -1,8 +1,9 @@ use proc_macro2::Ident; use crate::{Parameters, VariableDeclaration}; -use syn::{parse::Parse, token::Paren, Token}; +use syn::{parenthesized, parse::Parse, token::Paren, Token}; +#[derive(Debug, Clone)] pub struct MethodCall { pub fn_name: Ident, pub paren_token: Paren, @@ -11,8 +12,9 @@ pub struct MethodCall { impl Parse for MethodCall { fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + let content; let fn_name = input.parse()?; - let paren = input.parse()?; + let paren = parenthesized!(content in input); let mut args = Parameters::new(); while let Ok(arg) = input.parse::() { args.push(arg); diff --git a/crates/syn-solidity/src/statments/mod.rs b/crates/syn-solidity/src/statments/mod.rs index e3972841a6..a2c1b50210 100644 --- a/crates/syn-solidity/src/statments/mod.rs +++ b/crates/syn-solidity/src/statments/mod.rs @@ -1,11 +1,21 @@ +pub mod assembly; pub mod assignment; pub mod binop; pub mod binops; +pub mod call_args; +pub mod emit; pub mod expr; pub mod field; pub mod r#for; pub mod r#if; pub mod index; +pub mod inline_array_expr; +pub mod loop_ops; pub mod method_call; +pub mod new; +pub mod r#return; +pub mod revert; pub mod try_catch; +pub mod tuple_expr; +pub mod unchecked; pub mod r#while; diff --git a/crates/syn-solidity/src/statments/new.rs b/crates/syn-solidity/src/statments/new.rs new file mode 100644 index 0000000000..563f9182b6 --- /dev/null +++ b/crates/syn-solidity/src/statments/new.rs @@ -0,0 +1,17 @@ +use crate::{kw, r#type::Type}; +use syn::parse::Parse; + +#[derive(Debug, Clone)] +pub struct New { + new_kw: kw::new, + type_name: Type, +} + +impl Parse for New { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + Ok(Self { + new_kw: input.parse()?, + type_name: input.parse()?, + }) + } +} diff --git a/crates/syn-solidity/src/statments/return.rs b/crates/syn-solidity/src/statments/return.rs new file mode 100644 index 0000000000..30a717b09a --- /dev/null +++ b/crates/syn-solidity/src/statments/return.rs @@ -0,0 +1,19 @@ +use crate::expr::Expr; +use syn::{parse::Parse, Token}; + +#[derive(Debug, Clone)] +pub struct Return { + token: Token![return], + expr: Box, + semi: Token![;], +} + +impl Parse for Return { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + Ok(Self { + token: input.parse()?, + expr: Box::new(input.parse()?), + semi: input.parse()?, + }) + } +} diff --git a/crates/syn-solidity/src/statments/revert.rs b/crates/syn-solidity/src/statments/revert.rs new file mode 100644 index 0000000000..2d7c843341 --- /dev/null +++ b/crates/syn-solidity/src/statments/revert.rs @@ -0,0 +1,21 @@ +use crate::{call_args::CallArgs, expr::Expr, kw}; +use syn::{parse::Parse, Token}; + +#[derive(Clone, Debug)] +pub struct Revert { + kw: kw::revert, + expr: Box, + args: CallArgs, + semi: Token![;], +} + +impl Parse for Revert { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + Ok(Self { + kw: input.parse()?, + expr: Box::new(input.parse()?), + args: input.parse()?, + semi: input.parse()?, + }) + } +} diff --git a/crates/syn-solidity/src/statments/try_catch.rs b/crates/syn-solidity/src/statments/try_catch.rs index 9d399a8217..ebe370b8e0 100644 --- a/crates/syn-solidity/src/statments/try_catch.rs +++ b/crates/syn-solidity/src/statments/try_catch.rs @@ -9,6 +9,7 @@ pub struct TryCatch { pub catch: Catch, } +#[derive(Debug, Clone)] pub struct Catch { pub error: Option, pub panic: Option, diff --git a/crates/syn-solidity/src/statments/tuple_expr.rs b/crates/syn-solidity/src/statments/tuple_expr.rs new file mode 100644 index 0000000000..4512f129cc --- /dev/null +++ b/crates/syn-solidity/src/statments/tuple_expr.rs @@ -0,0 +1,25 @@ +use syn::{parenthesized, parse::Parse, punctuated::Punctuated, token::Paren}; + +use crate::{expr::Expr, Parameters}; + +#[derive(Debug, Clone)] +pub struct TupleExpr { + paran: Paren, + exprs: Punctuated, +} + +impl Parse for TupleExpr { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + let content; + let paren = parenthesized!(content in input); + + let exprs = Punctuated::new(); + exprs.push(input.parse()?); + while input.peek(Token![,]) { + exprs.push(input.parse()?); + } + exprs.push(input.parse()?); + + Ok(Self { exprs, paran }) + } +} diff --git a/crates/syn-solidity/src/statments/unchecked.rs b/crates/syn-solidity/src/statments/unchecked.rs new file mode 100644 index 0000000000..41ef3ddeea --- /dev/null +++ b/crates/syn-solidity/src/statments/unchecked.rs @@ -0,0 +1,18 @@ +use syn::parse::Parse; + +use crate::{kw, Block}; + +#[derive(Debug, Clone)] +pub struct Unchecked { + unchecked: kw::unchecked, + block: Block, +} + +impl Parse for Unchecked { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + Ok(Self { + unchecked: input.parse()?, + block: input.parse()?, + }) + } +} diff --git a/crates/syn-solidity/src/statments/while.rs b/crates/syn-solidity/src/statments/while.rs index 31031baadd..dd841e8416 100644 --- a/crates/syn-solidity/src/statments/while.rs +++ b/crates/syn-solidity/src/statments/while.rs @@ -1,15 +1,10 @@ -use syn::{ - parse::Parse, - token::{Brace, Paren}, - Token, -}; +use syn::{parenthesized, parse::Parse, token::Paren, Token}; use crate::{expr::Expr, Block}; #[derive(Debug, Clone)] pub struct DoWhile { pub do_token: Token![do], - pub brace: Brace, pub block: Block, pub while_token: Token![while], pub paren: Paren, @@ -18,16 +13,16 @@ pub struct DoWhile { impl Parse for DoWhile { fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + let content; let do_token = input.parse()?; - let brace = input.parse()?; let block = input.parse()?; let while_token = input.parse()?; - let paren = input.parse()?; + + let paren = parenthesized!(content in input); let expr = Box::new(input.parse()?); Ok(Self { do_token, - brace, block, while_token, paren, @@ -46,8 +41,9 @@ pub struct While { impl Parse for While { fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + let content; let while_token = input.parse()?; - let paren = input.parse()?; + let paren = parenthesized!(content in input); let expr = input.parse()?; let block = input.parse()?; diff --git a/crates/syn-solidity/src/stmt.rs b/crates/syn-solidity/src/stmt.rs index 761935126c..5e7a309e0e 100644 --- a/crates/syn-solidity/src/stmt.rs +++ b/crates/syn-solidity/src/stmt.rs @@ -23,12 +23,15 @@ impl fmt::Debug for Block { impl Parse for Block { fn parse(input: ParseStream<'_>) -> Result { let content; + let mut exprs = Vec::new(); - let fork = input.fork(); + while !input.peek(Brace) { + exprs.push(input.parse()?); + } Ok(Self { brace_token: syn::braced!(content in input), - stmts: content.parse()?, + stmts: exprs, }) } } From f57c23cdc0d4ce196a41bb4b78d4e6bb678700a4 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Thu, 20 Jul 2023 14:08:43 +0200 Subject: [PATCH 06/22] wip --- crates/syn-solidity/src/lib.rs | 1 + .../syn-solidity/src/literals/hex_string.rs | 4 +++ crates/syn-solidity/src/literals/lits.rs | 10 +++++++ crates/syn-solidity/src/literals/mod.rs | 5 ++++ crates/syn-solidity/src/literals/numbers.rs | 0 crates/syn-solidity/src/literals/strings.rs | 3 ++ crates/syn-solidity/src/literals/unicode.rs | 0 .../syn-solidity/src/statments/call_args.rs | 28 ++++++++++++++--- crates/syn-solidity/src/statments/expr.rs | 3 +- crates/syn-solidity/src/statments/loop_ops.rs | 30 +++++++++++++++++-- .../syn-solidity/src/statments/tuple_expr.rs | 10 +++---- 11 files changed, 81 insertions(+), 13 deletions(-) create mode 100644 crates/syn-solidity/src/literals/hex_string.rs create mode 100644 crates/syn-solidity/src/literals/lits.rs create mode 100644 crates/syn-solidity/src/literals/mod.rs create mode 100644 crates/syn-solidity/src/literals/numbers.rs create mode 100644 crates/syn-solidity/src/literals/strings.rs create mode 100644 crates/syn-solidity/src/literals/unicode.rs diff --git a/crates/syn-solidity/src/lib.rs b/crates/syn-solidity/src/lib.rs index a41d8ce8ec..6c119244a6 100644 --- a/crates/syn-solidity/src/lib.rs +++ b/crates/syn-solidity/src/lib.rs @@ -20,6 +20,7 @@ use syn::Result; #[macro_use] mod macros; +pub mod literals; pub mod attribute; pub use attribute::*; diff --git a/crates/syn-solidity/src/literals/hex_string.rs b/crates/syn-solidity/src/literals/hex_string.rs new file mode 100644 index 0000000000..95ec5dd739 --- /dev/null +++ b/crates/syn-solidity/src/literals/hex_string.rs @@ -0,0 +1,4 @@ +use syn::Token; +pub struct HexString { + +} diff --git a/crates/syn-solidity/src/literals/lits.rs b/crates/syn-solidity/src/literals/lits.rs new file mode 100644 index 0000000000..300f019d10 --- /dev/null +++ b/crates/syn-solidity/src/literals/lits.rs @@ -0,0 +1,10 @@ +use syn::{LitStr, LitInt, LitBool}; + +#[derive(Debug, Clone)] +pub enum Literals { + String(LitStr), + Number(LitInt), + Bool(LitBool), + HexString(), + Unicode(), +} diff --git a/crates/syn-solidity/src/literals/mod.rs b/crates/syn-solidity/src/literals/mod.rs new file mode 100644 index 0000000000..1b924c30dc --- /dev/null +++ b/crates/syn-solidity/src/literals/mod.rs @@ -0,0 +1,5 @@ +pub mod lits; +pub mod hex_string; +pub mod strings; +pub mod numbers; +pub mod unicode; diff --git a/crates/syn-solidity/src/literals/numbers.rs b/crates/syn-solidity/src/literals/numbers.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/crates/syn-solidity/src/literals/strings.rs b/crates/syn-solidity/src/literals/strings.rs new file mode 100644 index 0000000000..18e6f94e18 --- /dev/null +++ b/crates/syn-solidity/src/literals/strings.rs @@ -0,0 +1,3 @@ +use syn::LitStr; + +pub struct StringLit(LitStr); diff --git a/crates/syn-solidity/src/literals/unicode.rs b/crates/syn-solidity/src/literals/unicode.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/crates/syn-solidity/src/statments/call_args.rs b/crates/syn-solidity/src/statments/call_args.rs index 57f7129562..2c564f144a 100644 --- a/crates/syn-solidity/src/statments/call_args.rs +++ b/crates/syn-solidity/src/statments/call_args.rs @@ -1,4 +1,9 @@ -use syn::{parse::Parse, punctuated::Punctuated, Ident, Token}; +use syn::{ + parse::Parse, + punctuated::Punctuated, + token::{Brace, Paren}, + Error, Ident, Token, +}; use crate::expr::Expr; @@ -9,11 +14,12 @@ pub enum CallArgs { } #[derive(Debug, Clone)] -pub struct MapArgs(Punctuated); +pub struct MapArgs(Punctuated); #[derive(Debug, Clone)] pub struct Map { pub key: Ident, + pub semi: Token![:], pub value: Box, } @@ -21,10 +27,24 @@ pub struct Map { pub struct ListArgs(Punctuated); impl Parse for CallArgs { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result {} + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + // map + if input.peek2(Brace) { + Ok(Self::Map(input.parse()?)) + } + // list + else if input.peek(Paren) { + Ok(Self::List(input.parse()?)) + } else { + Err(Error::new(input.span(), "invalid call args")) + } + } } impl Parse for MapArgs { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result {} + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + while input.peek(token) + + } } impl Parse for Map { fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result {} diff --git a/crates/syn-solidity/src/statments/expr.rs b/crates/syn-solidity/src/statments/expr.rs index 04b891e450..57eb6ee693 100644 --- a/crates/syn-solidity/src/statments/expr.rs +++ b/crates/syn-solidity/src/statments/expr.rs @@ -13,7 +13,7 @@ use crate::{ r#while::{DoWhile, While}, revert::Revert, tuple_expr::TupleExpr, - unchecked::Unchecked, + unchecked::Unchecked, literals::lits::Literals, }; use syn::{ @@ -40,6 +40,7 @@ pub enum Expr { Tuple(TupleExpr), InlineArray(InlineArrayExpr), New(New), + Lit(Literals), } impl Parse for Expr { diff --git a/crates/syn-solidity/src/statments/loop_ops.rs b/crates/syn-solidity/src/statments/loop_ops.rs index 6489836de2..f83fc40c4f 100644 --- a/crates/syn-solidity/src/statments/loop_ops.rs +++ b/crates/syn-solidity/src/statments/loop_ops.rs @@ -1,7 +1,31 @@ -use syn::Token; +use syn::{parse::Parse, Error, Token}; #[derive(Debug, Clone)] pub enum LoopOps { - Continue(Token!(continue)), - Break(Token!(break)), + Continue { + kw: Token!(continue), + semi: Token!(;), + }, + Break { + kw: Token!(break), + semi: Token!(;), + }, +} + +impl Parse for LoopOps { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + if input.peek(Token![continue]) { + Ok(Self::Continue { + kw: input.parse()?, + semi: input.parse()?, + }) + } else if input.peek(Token![break]) { + Ok(Self::Break { + kw: input.parse()?, + semi: input.parse()?, + }) + } else { + Err(Error::new(input.span(), "failed to match on loop op")) + } + } } diff --git a/crates/syn-solidity/src/statments/tuple_expr.rs b/crates/syn-solidity/src/statments/tuple_expr.rs index 4512f129cc..384343d175 100644 --- a/crates/syn-solidity/src/statments/tuple_expr.rs +++ b/crates/syn-solidity/src/statments/tuple_expr.rs @@ -1,10 +1,10 @@ -use syn::{parenthesized, parse::Parse, punctuated::Punctuated, token::Paren}; +use syn::{parenthesized, parse::Parse, punctuated::Punctuated, token::Paren, Token}; -use crate::{expr::Expr, Parameters}; +use crate::expr::Expr; #[derive(Debug, Clone)] pub struct TupleExpr { - paran: Paren, + paren: Paren, exprs: Punctuated, } @@ -13,13 +13,13 @@ impl Parse for TupleExpr { let content; let paren = parenthesized!(content in input); - let exprs = Punctuated::new(); + let mut exprs = Punctuated::new(); exprs.push(input.parse()?); while input.peek(Token![,]) { exprs.push(input.parse()?); } exprs.push(input.parse()?); - Ok(Self { exprs, paran }) + Ok(Self { exprs, paren }) } } From 00a2bd0175039d11b52bdf02123277bb2efa295e Mon Sep 17 00:00:00 2001 From: Will Smith Date: Thu, 20 Jul 2023 16:22:26 +0200 Subject: [PATCH 07/22] wip --- crates/syn-solidity/src/lib.rs | 2 +- .../syn-solidity/src/literals/hex_string.rs | 4 - crates/syn-solidity/src/literals/lits.rs | 18 +++- crates/syn-solidity/src/literals/mod.rs | 4 - crates/syn-solidity/src/literals/numbers.rs | 0 crates/syn-solidity/src/literals/strings.rs | 3 - crates/syn-solidity/src/literals/unicode.rs | 0 crates/syn-solidity/src/statments/assembly.rs | 13 ++- .../syn-solidity/src/statments/binops/mod.rs | 89 ++++++++++++------- .../syn-solidity/src/statments/call_args.rs | 39 +++++--- crates/syn-solidity/src/statments/expr.rs | 30 ++++++- 11 files changed, 142 insertions(+), 60 deletions(-) delete mode 100644 crates/syn-solidity/src/literals/hex_string.rs delete mode 100644 crates/syn-solidity/src/literals/numbers.rs delete mode 100644 crates/syn-solidity/src/literals/strings.rs delete mode 100644 crates/syn-solidity/src/literals/unicode.rs diff --git a/crates/syn-solidity/src/lib.rs b/crates/syn-solidity/src/lib.rs index 6c119244a6..f7a8e35956 100644 --- a/crates/syn-solidity/src/lib.rs +++ b/crates/syn-solidity/src/lib.rs @@ -20,8 +20,8 @@ use syn::Result; #[macro_use] mod macros; -pub mod literals; pub mod attribute; +pub mod literals; pub use attribute::*; pub mod statments; diff --git a/crates/syn-solidity/src/literals/hex_string.rs b/crates/syn-solidity/src/literals/hex_string.rs deleted file mode 100644 index 95ec5dd739..0000000000 --- a/crates/syn-solidity/src/literals/hex_string.rs +++ /dev/null @@ -1,4 +0,0 @@ -use syn::Token; -pub struct HexString { - -} diff --git a/crates/syn-solidity/src/literals/lits.rs b/crates/syn-solidity/src/literals/lits.rs index 300f019d10..e36dca6cc6 100644 --- a/crates/syn-solidity/src/literals/lits.rs +++ b/crates/syn-solidity/src/literals/lits.rs @@ -1,10 +1,22 @@ -use syn::{LitStr, LitInt, LitBool}; +use syn::{parse::Parse, Error, LitBool, LitInt, LitStr}; #[derive(Debug, Clone)] pub enum Literals { String(LitStr), Number(LitInt), Bool(LitBool), - HexString(), - Unicode(), +} + +impl Parse for Literals { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + if input.peek(LitStr) { + Ok(Self::String(input.parse()?)) + } else if input.peek(LitInt) { + Ok(Self::Number(input.parse()?)) + } else if input.peek(LitBool) { + Ok(Self::Bool(input.parse()?)) + } else { + Err(Error::new(input.span(), "failed to parse literal")) + } + } } diff --git a/crates/syn-solidity/src/literals/mod.rs b/crates/syn-solidity/src/literals/mod.rs index 1b924c30dc..73e0f9b188 100644 --- a/crates/syn-solidity/src/literals/mod.rs +++ b/crates/syn-solidity/src/literals/mod.rs @@ -1,5 +1 @@ pub mod lits; -pub mod hex_string; -pub mod strings; -pub mod numbers; -pub mod unicode; diff --git a/crates/syn-solidity/src/literals/numbers.rs b/crates/syn-solidity/src/literals/numbers.rs deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/crates/syn-solidity/src/literals/strings.rs b/crates/syn-solidity/src/literals/strings.rs deleted file mode 100644 index 18e6f94e18..0000000000 --- a/crates/syn-solidity/src/literals/strings.rs +++ /dev/null @@ -1,3 +0,0 @@ -use syn::LitStr; - -pub struct StringLit(LitStr); diff --git a/crates/syn-solidity/src/literals/unicode.rs b/crates/syn-solidity/src/literals/unicode.rs deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/crates/syn-solidity/src/statments/assembly.rs b/crates/syn-solidity/src/statments/assembly.rs index 538c482de5..537083f61e 100644 --- a/crates/syn-solidity/src/statments/assembly.rs +++ b/crates/syn-solidity/src/statments/assembly.rs @@ -1,5 +1,5 @@ use proc_macro2::TokenStream; -use syn::token::Brace; +use syn::{braced, parse::Parse, token::Brace}; use crate::kw; @@ -10,3 +10,14 @@ pub struct Assembly { brace: Brace, input: TokenStream, } + +impl Parse for Assembly { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + let content; + let kw = input.parse()?; + let brace = braced!(content in input); + let input = input.parse()?; + + Ok(Self { input, kw, brace }) + } +} diff --git a/crates/syn-solidity/src/statments/binops/mod.rs b/crates/syn-solidity/src/statments/binops/mod.rs index 2a2922f57e..2fc71d1b3f 100644 --- a/crates/syn-solidity/src/statments/binops/mod.rs +++ b/crates/syn-solidity/src/statments/binops/mod.rs @@ -6,7 +6,7 @@ use crate::kw; use self::pow::PowOps; use super::binops::ternary::Ternary; -use syn::{parse::Parse, Token}; +use syn::{parse::Parse, Error, Token}; #[derive(Debug, Clone)] pub enum Binop { @@ -28,6 +28,7 @@ pub enum Binop { BitXor(Token![^]), XorAssign(Token![^=]), BitOr(Token![|]), + BitOrAssign(Token![|=]), Shl(Token![<<]), ShlAssign(Token![<<=]), Shr(Token![>>]), @@ -41,32 +42,60 @@ pub enum Binop { Delete(kw::delete), } -// impl Parse for Binop { -// fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { -// input.peek(Token![~]) -// || input.peek2(Token!(=)) -// || input.peek2(Token!(+)) -// || input.peek2(Token!(+=)) -// || input.peek2(Token!(-)) -// || input.peek2(Token!(-=)) -// || input.peek2(Token!(*)) -// || input.peek2(Token!(*=)) -// || input.peek2(Token!(/)) -// || input.peek2(Token!(/=)) -// || input.peek2(Token!(%)) -// || input.peek2(Token!(%=)) -// || input.peek2(Token!(&)) -// || input.peek2(Token!(&=)) -// || input.peek2(Token!(^)) -// || input.peek2(Token!(^=)) -// || input.peek2(Token!(|)) -// || input.peek2(Token!(<<)) -// || input.peek2(Token!(<<=)) -// || input.peek2(Token!(>>)) -// || input.peek2(Token!(>>=)) -// || input.peek2(Token!(==)) -// || input.peek2(Token!(&&)) -// || input.peek2(Token!(||)) -// } -// } -// } +impl Parse for Binop { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + if input.peek(Token![=]) { + Ok(Self::Assign(input.parse()?)) + } else if input.peek(Token![~]) { + Ok(Self::BitNot(input.parse()?)) + } else if input.peek(Token![==]) { + Ok(Self::Equality(input.parse()?)) + } else if input.peek(Token![+]) { + Ok(Self::Add(input.parse()?)) + } else if input.peek(Token![+=]) { + Ok(Self::AddAssign(input.parse()?)) + } else if input.peek(Token![-]) { + Ok(Self::Minus(input.parse()?)) + } else if input.peek(Token![-=]) { + Ok(Self::MinusAssign(input.parse()?)) + } else if input.peek(Token![*]) { + Ok(Self::Mul(input.parse()?)) + } else if input.peek(Token![*=]) { + Ok(Self::MulAssign(input.parse()?)) + } else if input.peek(Token![/]) { + Ok(Self::Div(input.parse()?)) + } else if input.peek(Token![/=]) { + Ok(Self::DivAssign(input.parse()?)) + } else if input.peek(Token![%]) { + Ok(Self::Mod(input.parse()?)) + } else if input.peek(Token![%=]) { + Ok(Self::ModAssign(input.parse()?)) + } else if input.peek(Token![&]) { + Ok(Self::BitAnd(input.parse()?)) + } else if input.peek(Token![&=]) { + Ok(Self::AndAssign(input.parse()?)) + } else if input.peek(Token![^]) { + Ok(Self::BitXor(input.parse()?)) + } else if input.peek(Token![^=]) { + Ok(Self::XorAssign(input.parse()?)) + } else if input.peek(Token![|]) { + Ok(Self::BitOr(input.parse()?)) + } else if input.peek(Token![|=]) { + Ok(Self::BitOrAssign(input.parse()?)) + } else if input.peek(Token![<<]) { + Ok(Self::Shl(input.parse()?)) + } else if input.peek(Token![<<=]) { + Ok(Self::ShlAssign(input.parse()?)) + } else if input.peek(Token![>>]) { + Ok(Self::Shr(input.parse()?)) + } else if input.peek(Token![>>=]) { + Ok(Self::ShrAssign(input.parse()?)) + } else if input.peek(Token![&&]) { + Ok(Self::And(input.parse()?)) + } else if input.peek(Token![||]) { + Ok(Self::Or(input.parse()?)) + } else { + Err(Error::new(input.span(), "failed to parse binop")) + } + } +} diff --git a/crates/syn-solidity/src/statments/call_args.rs b/crates/syn-solidity/src/statments/call_args.rs index 2c564f144a..103542cc42 100644 --- a/crates/syn-solidity/src/statments/call_args.rs +++ b/crates/syn-solidity/src/statments/call_args.rs @@ -14,7 +14,10 @@ pub enum CallArgs { } #[derive(Debug, Clone)] -pub struct MapArgs(Punctuated); +pub struct ListArgs(pub Punctuated); + +#[derive(Debug, Clone)] +pub struct MapArgs(pub Punctuated); #[derive(Debug, Clone)] pub struct Map { @@ -23,17 +26,11 @@ pub struct Map { pub value: Box, } -#[derive(Debug, Clone)] -pub struct ListArgs(Punctuated); - impl Parse for CallArgs { fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { - // map if input.peek2(Brace) { Ok(Self::Map(input.parse()?)) - } - // list - else if input.peek(Paren) { + } else if input.peek(Paren) { Ok(Self::List(input.parse()?)) } else { Err(Error::new(input.span(), "invalid call args")) @@ -42,13 +39,33 @@ impl Parse for CallArgs { } impl Parse for MapArgs { fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { - while input.peek(token) + let mut map = Punctuated::new(); + while input.peek2(Token![:]) { + let entry = input.parse()?; + map.push(entry); + } + Ok(Self(map)) } } + impl Parse for Map { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result {} + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + Ok(Self { + key: input.parse()?, + semi: input.parse()?, + value: input.parse()?, + }) + } } + impl Parse for ListArgs { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result {} + fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { + let mut list = Punctuated::new(); + while input.peek(Token![,]) { + list.push(input.parse()?); + } + list.push(input.parse()?); + Ok(Self(list)) + } } diff --git a/crates/syn-solidity/src/statments/expr.rs b/crates/syn-solidity/src/statments/expr.rs index 57eb6ee693..31c347009c 100644 --- a/crates/syn-solidity/src/statments/expr.rs +++ b/crates/syn-solidity/src/statments/expr.rs @@ -1,9 +1,12 @@ use crate::{ + assembly::Assembly, assignment::AssignmentExpr, binop::BinopExpr, emit::Emit, index::Index, inline_array_expr::InlineArrayExpr, + kw, + literals::lits::Literals, loop_ops::LoopOps, method_call::MethodCall, new::New, @@ -13,13 +16,13 @@ use crate::{ r#while::{DoWhile, While}, revert::Revert, tuple_expr::TupleExpr, - unchecked::Unchecked, literals::lits::Literals, + unchecked::Unchecked, }; use syn::{ parse::Parse, token::{Bracket, Paren}, - Ident, Token, + Ident, LitBool, LitInt, LitStr, Token, }; #[derive(Clone, Debug)] @@ -41,6 +44,7 @@ pub enum Expr { InlineArray(InlineArrayExpr), New(New), Lit(Literals), + Assembly(Assembly), } impl Parse for Expr { @@ -53,7 +57,7 @@ impl Parse for Expr { return Ok(Self::If(IfStmt::parse(input)?)) } else if input.peek(Token![for]) { return Ok(Self::ForLoop(ForStmt::parse(input)?)) - } else if input.peek2(Bracket) { + } else if input.peek(Ident) && input.peek2(Bracket) { return Ok(Self::Index(Index::parse(input)?)) } else if input.peek(Ident) && input.peek2(Paren) { return Ok(Self::MethodCall(MethodCall::parse(input)?)) @@ -85,6 +89,26 @@ impl Parse for Expr { || input.peek2(Token!(||)) { return Ok(Self::Binop(BinopExpr::parse(input)?)) + } else if input.peek(kw::emit) { + Ok(Self::Emit(Emit::parse(input)?)) + } else if input.peek(kw::returns) { + Ok(Self::Return(Return::parse(input)?)) + } else if input.peek(kw::unchecked) { + Ok(Self::Unchecked(Unchecked::parse(input)?)) + } else if input.peek(kw::revert) { + Ok(Self::Revert(Revert::parse(input)?)) + } else if input.peek(Paren) && input.peek3(Token!(,)) { + Ok(Self::Tuple(TupleExpr::parse(input)?)) + } else if input.peek(Ident) && input.peek2(Paren) { + Ok(Self::MethodCall(MethodCall::parse(input)?)) + } else if input.peek(Bracket) { + Ok(Self::InlineArray(InlineArrayExpr::parse(input)?)) + } else if input.peek(kw::new) { + Ok(Self::New(New::parse(input)?)) + } else if input.peek(kw::assembly) { + Ok(Self::Assembly(Assembly::parse(input)?)) + } else if input.peek(LitBool) || input.peek(LitStr) || input.peek(LitInt) { + Ok(Self::Lit(Literals::parse(input)?)) } else { Err(syn::Error::new( input.span(), From d8b483a896dd1df3b2a53038cf4235a360ee6a60 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Fri, 21 Jul 2023 14:21:22 +0200 Subject: [PATCH 08/22] changes --- crates/sol-macro/src/expand/ty.rs | 5 ++++- crates/syn-solidity/src/item/error.rs | 2 +- crates/syn-solidity/src/item/event.rs | 4 +++- crates/syn-solidity/src/item/function.rs | 2 +- crates/syn-solidity/src/item/mod.rs | 2 +- crates/syn-solidity/src/item/struct.rs | 2 +- crates/syn-solidity/src/item/udt.rs | 2 +- crates/syn-solidity/src/item/using.rs | 2 +- crates/syn-solidity/src/lib.rs | 1 + crates/syn-solidity/src/statments/expr.rs | 7 ++++++- crates/syn-solidity/src/type/array.rs | 2 +- crates/syn-solidity/src/type/mapping.rs | 2 +- crates/syn-solidity/src/type/tuple.rs | 2 +- crates/syn-solidity/src/variable/list.rs | 2 +- crates/syn-solidity/src/variable/mod.rs | 2 +- crates/syn-solidity/src/visit.rs | 1 + crates/syn-solidity/src/visit_mut.rs | 1 + 17 files changed, 27 insertions(+), 14 deletions(-) diff --git a/crates/sol-macro/src/expand/ty.rs b/crates/sol-macro/src/expand/ty.rs index cb644f7ce3..bf1090d6a3 100644 --- a/crates/sol-macro/src/expand/ty.rs +++ b/crates/sol-macro/src/expand/ty.rs @@ -2,7 +2,10 @@ use super::ExpCtxt; use crate::expand::generate_name; -use ast::{EventParameter, Item, Parameters, Type, TypeArray, VariableDeclaration}; +use ast::{ + r#type::{Type, TypeArray}, + EventParameter, Item, Parameters, VariableDeclaration, +}; use proc_macro2::{Literal, TokenStream}; use quote::{quote, quote_spanned, ToTokens}; use std::{fmt, num::NonZeroU16}; diff --git a/crates/syn-solidity/src/item/error.rs b/crates/syn-solidity/src/item/error.rs index cbf768e1ad..dc0f4bffc5 100644 --- a/crates/syn-solidity/src/item/error.rs +++ b/crates/syn-solidity/src/item/error.rs @@ -1,4 +1,4 @@ -use crate::{kw, Parameters, SolIdent, Type}; +use crate::{kw, r#type::Type, Parameters, SolIdent}; use proc_macro2::Span; use std::fmt; use syn::{ diff --git a/crates/syn-solidity/src/item/event.rs b/crates/syn-solidity/src/item/event.rs index 42234fcc8f..1dc4288b98 100644 --- a/crates/syn-solidity/src/item/event.rs +++ b/crates/syn-solidity/src/item/event.rs @@ -1,4 +1,6 @@ -use crate::{kw, utils::DebugPunctuated, ParameterList, SolIdent, Type, VariableDeclaration}; +use crate::{ + kw, r#type::Type, utils::DebugPunctuated, ParameterList, SolIdent, VariableDeclaration, +}; use proc_macro2::Span; use std::fmt; use syn::{ diff --git a/crates/syn-solidity/src/item/function.rs b/crates/syn-solidity/src/item/function.rs index a8e6de42bd..1b2536a682 100644 --- a/crates/syn-solidity/src/item/function.rs +++ b/crates/syn-solidity/src/item/function.rs @@ -1,4 +1,4 @@ -use crate::{kw, Block, FunctionAttributes, Parameters, SolIdent, Type}; +use crate::{kw, r#type::Type, Block, FunctionAttributes, Parameters, SolIdent}; use proc_macro2::Span; use std::{ fmt, diff --git a/crates/syn-solidity/src/item/mod.rs b/crates/syn-solidity/src/item/mod.rs index 2c2082374f..0007086e59 100644 --- a/crates/syn-solidity/src/item/mod.rs +++ b/crates/syn-solidity/src/item/mod.rs @@ -102,7 +102,7 @@ impl Parse for Item { input.parse().map(Self::Import) } else if lookahead.peek(kw::using) { input.parse().map(Self::Using) - } else if crate::Type::peek(&lookahead) { + } else if crate::r#type::Type::peek(&lookahead) { input.parse().map(Self::Variable) } else { Err(lookahead.error()) diff --git a/crates/syn-solidity/src/item/struct.rs b/crates/syn-solidity/src/item/struct.rs index b981b559bc..f40454f15a 100644 --- a/crates/syn-solidity/src/item/struct.rs +++ b/crates/syn-solidity/src/item/struct.rs @@ -1,4 +1,4 @@ -use crate::{Parameters, SolIdent, Type}; +use crate::{r#type::Type, Parameters, SolIdent}; use proc_macro2::Span; use std::{ fmt, diff --git a/crates/syn-solidity/src/item/udt.rs b/crates/syn-solidity/src/item/udt.rs index 41e47a4e67..f7870924b0 100644 --- a/crates/syn-solidity/src/item/udt.rs +++ b/crates/syn-solidity/src/item/udt.rs @@ -1,4 +1,4 @@ -use crate::{kw, SolIdent, Type}; +use crate::{kw, r#type::Type, SolIdent}; use proc_macro2::Span; use std::{ fmt, diff --git a/crates/syn-solidity/src/item/using.rs b/crates/syn-solidity/src/item/using.rs index 9fa5e854e4..8b3580c180 100644 --- a/crates/syn-solidity/src/item/using.rs +++ b/crates/syn-solidity/src/item/using.rs @@ -1,4 +1,4 @@ -use crate::{kw, SolPath, Type}; +use crate::{kw, r#type::Type, SolPath}; use proc_macro2::Span; use syn::{ braced, diff --git a/crates/syn-solidity/src/lib.rs b/crates/syn-solidity/src/lib.rs index f7a8e35956..cbddf547bd 100644 --- a/crates/syn-solidity/src/lib.rs +++ b/crates/syn-solidity/src/lib.rs @@ -44,6 +44,7 @@ pub mod stmt; pub use stmt::*; pub mod r#type; +pub use r#type::Type; pub(crate) mod utils; diff --git a/crates/syn-solidity/src/statments/expr.rs b/crates/syn-solidity/src/statments/expr.rs index 31c347009c..c51dac5bea 100644 --- a/crates/syn-solidity/src/statments/expr.rs +++ b/crates/syn-solidity/src/statments/expr.rs @@ -17,16 +17,18 @@ use crate::{ revert::Revert, tuple_expr::TupleExpr, unchecked::Unchecked, + Block, }; use syn::{ parse::Parse, - token::{Bracket, Paren}, + token::{Brace, Bracket, Paren}, Ident, LitBool, LitInt, LitStr, Token, }; #[derive(Clone, Debug)] pub enum Expr { + Block(Block), While(While), DoWhile(DoWhile), If(IfStmt), @@ -51,6 +53,9 @@ impl Parse for Expr { fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { if input.peek(Token![while]) { return Ok(Self::While(While::parse(input)?)) + // this prob wrong lol + } else if input.peek(Brace) { + return Ok(Self::Block(Block::parse(input)?)) } else if input.peek(Token![do]) { return Ok(Self::DoWhile(DoWhile::parse(input)?)) } else if input.peek(Token![if]) { diff --git a/crates/syn-solidity/src/type/array.rs b/crates/syn-solidity/src/type/array.rs index 811d6e4b95..94637d244e 100644 --- a/crates/syn-solidity/src/type/array.rs +++ b/crates/syn-solidity/src/type/array.rs @@ -1,4 +1,4 @@ -use crate::Type; +use crate::r#type::Type; use proc_macro2::Span; use std::{ fmt, diff --git a/crates/syn-solidity/src/type/mapping.rs b/crates/syn-solidity/src/type/mapping.rs index 208b50f740..f9e1337ebb 100644 --- a/crates/syn-solidity/src/type/mapping.rs +++ b/crates/syn-solidity/src/type/mapping.rs @@ -1,4 +1,4 @@ -use crate::{kw, SolIdent, Type}; +use crate::{kw, r#type::Type, SolIdent}; use proc_macro2::Span; use std::{ fmt, diff --git a/crates/syn-solidity/src/type/tuple.rs b/crates/syn-solidity/src/type/tuple.rs index bc577ba983..69f6bf54b2 100644 --- a/crates/syn-solidity/src/type/tuple.rs +++ b/crates/syn-solidity/src/type/tuple.rs @@ -1,4 +1,4 @@ -use crate::{kw, utils::DebugPunctuated, Type}; +use crate::{kw, r#type::Type, utils::DebugPunctuated}; use proc_macro2::Span; use std::{ fmt, diff --git a/crates/syn-solidity/src/variable/list.rs b/crates/syn-solidity/src/variable/list.rs index f3f45a0f4d..f5aaf44859 100644 --- a/crates/syn-solidity/src/variable/list.rs +++ b/crates/syn-solidity/src/variable/list.rs @@ -1,5 +1,5 @@ use super::VariableDeclaration; -use crate::{SolIdent, Type}; +use crate::{r#type::Type, SolIdent}; use std::{ fmt, ops::{Deref, DerefMut}, diff --git a/crates/syn-solidity/src/variable/mod.rs b/crates/syn-solidity/src/variable/mod.rs index 41a0105c4e..1e68c0fe56 100644 --- a/crates/syn-solidity/src/variable/mod.rs +++ b/crates/syn-solidity/src/variable/mod.rs @@ -1,4 +1,4 @@ -use super::{SolIdent, Storage, Type}; +use super::{r#type::Type, SolIdent, Storage}; use crate::{utils::tts_until_semi, VariableAttributes}; use proc_macro2::{Span, TokenStream}; use std::fmt::{self, Write}; diff --git a/crates/syn-solidity/src/visit.rs b/crates/syn-solidity/src/visit.rs index aa83c1cd20..47e0783733 100644 --- a/crates/syn-solidity/src/visit.rs +++ b/crates/syn-solidity/src/visit.rs @@ -8,6 +8,7 @@ #![allow(unused_variables)] use super::*; +use crate::r#type::*; make_visitor! { /// Syntax tree traversal to walk a shared borrow of a syntax tree. diff --git a/crates/syn-solidity/src/visit_mut.rs b/crates/syn-solidity/src/visit_mut.rs index 7e7b52c7f1..53aa970c1e 100644 --- a/crates/syn-solidity/src/visit_mut.rs +++ b/crates/syn-solidity/src/visit_mut.rs @@ -9,6 +9,7 @@ #![allow(unused_variables)] use super::*; +use crate::r#type::*; make_visitor! { /// Syntax tree traversal to mutate an exclusive borrow of a syntax tree in From 72f7e9ee9f584b90d23e05932283d7dd910c5fc6 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Fri, 21 Jul 2023 15:41:42 +0200 Subject: [PATCH 09/22] remove dup --- .../syn-solidity/src/statments/assignment.rs | 19 ------------------- crates/syn-solidity/src/statments/expr.rs | 2 -- crates/syn-solidity/src/statments/for.rs | 4 ++-- crates/syn-solidity/src/statments/loop_ops.rs | 2 +- crates/syn-solidity/src/statments/mod.rs | 1 - 5 files changed, 3 insertions(+), 25 deletions(-) delete mode 100644 crates/syn-solidity/src/statments/assignment.rs diff --git a/crates/syn-solidity/src/statments/assignment.rs b/crates/syn-solidity/src/statments/assignment.rs deleted file mode 100644 index bf05b5c46e..0000000000 --- a/crates/syn-solidity/src/statments/assignment.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::expr::Expr; -use syn::{parse::Parse, token::Eq}; - -#[derive(Debug, Clone)] -pub struct AssignmentExpr { - pub left: Box, - pub eq: Eq, - pub assign: Box, -} - -impl Parse for AssignmentExpr { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { - let left = input.parse()?; - let eq: Eq = input.parse()?; - let assign: Box = Box::new(input.parse()?); - - Ok(Self { left, assign, eq }) - } -} diff --git a/crates/syn-solidity/src/statments/expr.rs b/crates/syn-solidity/src/statments/expr.rs index c51dac5bea..4f3fcc7de7 100644 --- a/crates/syn-solidity/src/statments/expr.rs +++ b/crates/syn-solidity/src/statments/expr.rs @@ -1,6 +1,5 @@ use crate::{ assembly::Assembly, - assignment::AssignmentExpr, binop::BinopExpr, emit::Emit, index::Index, @@ -34,7 +33,6 @@ pub enum Expr { If(IfStmt), ForLoop(ForStmt), LoopOps(LoopOps), - Assign(AssignmentExpr), Index(Index), Binop(BinopExpr), MethodCall(MethodCall), diff --git a/crates/syn-solidity/src/statments/for.rs b/crates/syn-solidity/src/statments/for.rs index cb91ef3336..3f6e57ac0c 100644 --- a/crates/syn-solidity/src/statments/for.rs +++ b/crates/syn-solidity/src/statments/for.rs @@ -1,4 +1,4 @@ -use crate::{assignment::AssignmentExpr, expr::Expr, Block}; +use crate::{binop::BinopExpr, expr::Expr, Block}; use syn::{parenthesized, parse::Parse, token::Paren, Token}; #[derive(Debug, Clone)] @@ -10,7 +10,7 @@ pub struct ForStmt { #[derive(Debug, Clone)] pub struct ForAssignment { pub brace: Paren, - pub iter_asign: AssignmentExpr, + pub iter_asign: BinopExpr, pub semi: Token![;], pub cond: Box, pub semi2: Token![;], diff --git a/crates/syn-solidity/src/statments/loop_ops.rs b/crates/syn-solidity/src/statments/loop_ops.rs index f83fc40c4f..4fe500e659 100644 --- a/crates/syn-solidity/src/statments/loop_ops.rs +++ b/crates/syn-solidity/src/statments/loop_ops.rs @@ -1,6 +1,6 @@ use syn::{parse::Parse, Error, Token}; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] pub enum LoopOps { Continue { kw: Token!(continue), diff --git a/crates/syn-solidity/src/statments/mod.rs b/crates/syn-solidity/src/statments/mod.rs index a2c1b50210..0bbc4c2cf9 100644 --- a/crates/syn-solidity/src/statments/mod.rs +++ b/crates/syn-solidity/src/statments/mod.rs @@ -1,5 +1,4 @@ pub mod assembly; -pub mod assignment; pub mod binop; pub mod binops; pub mod call_args; From 0809496e2801bd57c48ad17fd1bb525be8befccf Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Thu, 3 Aug 2023 22:58:46 +0200 Subject: [PATCH 10/22] wip --- crates/syn-solidity/src/attribute/mod.rs | 38 +++++++++---------- crates/syn-solidity/src/ident/mod.rs | 2 +- crates/syn-solidity/src/item/event.rs | 4 +- crates/syn-solidity/src/item/mod.rs | 22 ++++++----- crates/syn-solidity/src/item/udt.rs | 2 +- crates/syn-solidity/src/item/using.rs | 2 +- crates/syn-solidity/src/lib.rs | 32 ++++++++-------- crates/syn-solidity/src/literals/lits.rs | 22 ----------- crates/syn-solidity/src/literals/mod.rs | 1 - .../src/{statments => stmt}/assembly.rs | 0 .../src/{statments => stmt}/binop.rs | 6 +-- .../src/{statments => stmt}/binops/mod.rs | 0 .../src/{statments => stmt}/binops/pow.rs | 0 .../src/{statments => stmt}/binops/ternary.rs | 0 .../src/{stmt.rs => stmt/block.rs} | 19 +++++----- .../src/{statments => stmt}/call_args.rs | 6 +-- .../src/{statments => stmt}/emit.rs | 4 +- .../src/{statments => stmt}/expr.rs | 4 +- .../src/{statments => stmt}/field.rs | 4 +- .../src/{statments => stmt}/for.rs | 6 +-- .../src/{statments => stmt}/if.rs | 0 .../src/{statments => stmt}/index.rs | 4 +- .../{statments => stmt}/inline_array_expr.rs | 4 +- .../src/{statments => stmt}/loop_ops.rs | 0 .../src/{statments => stmt}/method_call.rs | 0 .../src/{statments => stmt}/mod.rs | 5 +++ .../src/{statments => stmt}/new.rs | 10 ++--- .../src/{statments => stmt}/return.rs | 4 +- .../src/{statments => stmt}/revert.rs | 4 +- .../src/{statments => stmt}/try_catch.rs | 0 .../src/{statments => stmt}/tuple_expr.rs | 4 +- .../src/{statments => stmt}/unchecked.rs | 0 .../src/{statments => stmt}/while.rs | 6 +-- crates/syn-solidity/src/type/array.rs | 2 +- crates/syn-solidity/src/type/mapping.rs | 2 +- crates/syn-solidity/src/type/mod.rs | 16 ++++---- crates/syn-solidity/src/type/tuple.rs | 2 +- crates/syn-solidity/src/variable/list.rs | 2 +- crates/syn-solidity/src/variable/mod.rs | 2 +- crates/syn-solidity/src/visit.rs | 1 - crates/syn-solidity/src/visit_mut.rs | 1 - 41 files changed, 111 insertions(+), 132 deletions(-) delete mode 100644 crates/syn-solidity/src/literals/lits.rs delete mode 100644 crates/syn-solidity/src/literals/mod.rs rename crates/syn-solidity/src/{statments => stmt}/assembly.rs (100%) rename crates/syn-solidity/src/{statments => stmt}/binop.rs (83%) rename crates/syn-solidity/src/{statments => stmt}/binops/mod.rs (100%) rename crates/syn-solidity/src/{statments => stmt}/binops/pow.rs (100%) rename crates/syn-solidity/src/{statments => stmt}/binops/ternary.rs (100%) rename crates/syn-solidity/src/{stmt.rs => stmt/block.rs} (68%) rename crates/syn-solidity/src/{statments => stmt}/call_args.rs (93%) rename crates/syn-solidity/src/{statments => stmt}/emit.rs (85%) rename crates/syn-solidity/src/{statments => stmt}/expr.rs (99%) rename crates/syn-solidity/src/{statments => stmt}/field.rs (88%) rename crates/syn-solidity/src/{statments => stmt}/for.rs (90%) rename crates/syn-solidity/src/{statments => stmt}/if.rs (100%) rename crates/syn-solidity/src/{statments => stmt}/index.rs (89%) rename crates/syn-solidity/src/{statments => stmt}/inline_array_expr.rs (90%) rename crates/syn-solidity/src/{statments => stmt}/loop_ops.rs (100%) rename crates/syn-solidity/src/{statments => stmt}/method_call.rs (100%) rename crates/syn-solidity/src/{statments => stmt}/mod.rs (86%) rename crates/syn-solidity/src/{statments => stmt}/new.rs (57%) rename crates/syn-solidity/src/{statments => stmt}/return.rs (89%) rename crates/syn-solidity/src/{statments => stmt}/revert.rs (85%) rename crates/syn-solidity/src/{statments => stmt}/try_catch.rs (100%) rename crates/syn-solidity/src/{statments => stmt}/tuple_expr.rs (90%) rename crates/syn-solidity/src/{statments => stmt}/unchecked.rs (100%) rename crates/syn-solidity/src/{statments => stmt}/while.rs (93%) diff --git a/crates/syn-solidity/src/attribute/mod.rs b/crates/syn-solidity/src/attribute/mod.rs index 4621305d04..6e18546e61 100644 --- a/crates/syn-solidity/src/attribute/mod.rs +++ b/crates/syn-solidity/src/attribute/mod.rs @@ -13,10 +13,10 @@ use syn::{ }; mod function; -pub use function::*; +pub use function::{FunctionAttribute, FunctionAttributes}; mod variable; -pub use variable::*; +pub use variable::{VariableAttribute, VariableAttributes}; kw_enum! { /// A storage location. @@ -137,23 +137,6 @@ pub struct Modifier { pub arguments: Punctuated, } -impl fmt::Display for Modifier { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.name.fmt(f)?; - if self.paren_token.is_some() { - f.write_str("(")?; - for (i, arg) in self.arguments.iter().enumerate() { - if i > 0 { - f.write_str(", ")?; - } - arg.fmt(f)?; - } - f.write_str(")")?; - } - Ok(()) - } -} - impl PartialEq for Modifier { fn eq(&self, other: &Self) -> bool { self.name == other.name @@ -177,6 +160,23 @@ impl fmt::Debug for Modifier { } } +impl fmt::Display for Modifier { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.name.fmt(f)?; + if self.paren_token.is_some() { + f.write_str("(")?; + for (i, arg) in self.arguments.iter().enumerate() { + if i > 0 { + f.write_str(", ")?; + } + arg.fmt(f)?; + } + f.write_str(")")?; + } + Ok(()) + } +} + impl Parse for Modifier { fn parse(input: ParseStream<'_>) -> Result { let name = input.parse()?; diff --git a/crates/syn-solidity/src/ident/mod.rs b/crates/syn-solidity/src/ident/mod.rs index 167b8ccb78..c2f8b39fe2 100644 --- a/crates/syn-solidity/src/ident/mod.rs +++ b/crates/syn-solidity/src/ident/mod.rs @@ -8,7 +8,7 @@ use syn::{ }; mod path; -pub use path::*; +pub use path::SolPath; /// A Solidity identifier. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] diff --git a/crates/syn-solidity/src/item/event.rs b/crates/syn-solidity/src/item/event.rs index 1dc4288b98..42234fcc8f 100644 --- a/crates/syn-solidity/src/item/event.rs +++ b/crates/syn-solidity/src/item/event.rs @@ -1,6 +1,4 @@ -use crate::{ - kw, r#type::Type, utils::DebugPunctuated, ParameterList, SolIdent, VariableDeclaration, -}; +use crate::{kw, utils::DebugPunctuated, ParameterList, SolIdent, Type, VariableDeclaration}; use proc_macro2::Span; use std::fmt; use syn::{ diff --git a/crates/syn-solidity/src/item/mod.rs b/crates/syn-solidity/src/item/mod.rs index 3425e42ae9..ca70d31cae 100644 --- a/crates/syn-solidity/src/item/mod.rs +++ b/crates/syn-solidity/src/item/mod.rs @@ -6,34 +6,36 @@ use syn::{ }; mod contract; -pub use contract::*; +pub use contract::ItemContract; mod r#enum; -pub use r#enum::*; +pub use r#enum::ItemEnum; mod error; -pub use error::*; +pub use error::ItemError; mod event; -pub use event::*; +pub use event::{EventParameter, ItemEvent}; mod function; pub use function::{FunctionKind, ItemFunction, Returns}; mod import; -pub use import::*; +pub use import::{ + ImportAlias, ImportAliases, ImportDirective, ImportGlob, ImportPath, ImportPlain, +}; mod pragma; -pub use pragma::*; +pub use pragma::{PragmaDirective, PragmaTokens}; mod r#struct; -pub use r#struct::*; +pub use r#struct::ItemStruct; mod udt; -pub use udt::*; +pub use udt::ItemUdt; mod using; -pub use using::*; +pub use using::{UserDefinableOperator, UsingDirective, UsingList, UsingListItem, UsingType}; /// An AST item. A more expanded version of a [Solidity source unit][ref]. /// @@ -102,7 +104,7 @@ impl Parse for Item { input.parse().map(Self::Import) } else if lookahead.peek(kw::using) { input.parse().map(Self::Using) - } else if crate::r#type::Type::peek(&lookahead) { + } else if crate::Type::peek(&lookahead) { input.parse().map(Self::Variable) } else { Err(lookahead.error()) diff --git a/crates/syn-solidity/src/item/udt.rs b/crates/syn-solidity/src/item/udt.rs index f7870924b0..41e47a4e67 100644 --- a/crates/syn-solidity/src/item/udt.rs +++ b/crates/syn-solidity/src/item/udt.rs @@ -1,4 +1,4 @@ -use crate::{kw, r#type::Type, SolIdent}; +use crate::{kw, SolIdent, Type}; use proc_macro2::Span; use std::{ fmt, diff --git a/crates/syn-solidity/src/item/using.rs b/crates/syn-solidity/src/item/using.rs index 8b3580c180..9fa5e854e4 100644 --- a/crates/syn-solidity/src/item/using.rs +++ b/crates/syn-solidity/src/item/using.rs @@ -1,4 +1,4 @@ -use crate::{kw, r#type::Type, SolPath}; +use crate::{kw, SolPath, Type}; use proc_macro2::Span; use syn::{ braced, diff --git a/crates/syn-solidity/src/lib.rs b/crates/syn-solidity/src/lib.rs index efdfd07553..46ec33f55f 100644 --- a/crates/syn-solidity/src/lib.rs +++ b/crates/syn-solidity/src/lib.rs @@ -20,15 +20,17 @@ use syn::Result; #[macro_use] mod macros; -pub mod attribute; -pub mod literals; -pub use attribute::*; +mod attribute; +pub use attribute::{ + FunctionAttribute, FunctionAttributes, Modifier, Mutability, Override, Storage, + VariableAttribute, VariableAttributes, Visibility, +}; -pub mod statments; -pub use statments::*; +mod file; +pub use file::File; -pub mod file; -pub use file::*; +mod ident; +pub use ident::{SolIdent, SolPath}; mod item; pub use item::{ @@ -38,23 +40,21 @@ pub use item::{ UsingDirective, UsingList, UsingListItem, UsingType, }; -pub mod item; -pub use item::*; -pub mod lit; -pub use lit::*; +mod lit; +pub use lit::LitStr; pub mod kw; -pub mod stmt; +mod stmt; pub use stmt::*; -pub mod r#type; -pub use r#type::Type; +mod r#type; +pub use r#type::{Type, TypeArray, TypeFunction, TypeMapping, TypeTuple}; pub(crate) mod utils; -pub mod variable; -pub use variable::*; +mod variable; +pub use variable::{FieldList, ParameterList, Parameters, VariableDeclaration, VariableDefinition}; #[cfg(feature = "visit")] pub mod visit; diff --git a/crates/syn-solidity/src/literals/lits.rs b/crates/syn-solidity/src/literals/lits.rs deleted file mode 100644 index e36dca6cc6..0000000000 --- a/crates/syn-solidity/src/literals/lits.rs +++ /dev/null @@ -1,22 +0,0 @@ -use syn::{parse::Parse, Error, LitBool, LitInt, LitStr}; - -#[derive(Debug, Clone)] -pub enum Literals { - String(LitStr), - Number(LitInt), - Bool(LitBool), -} - -impl Parse for Literals { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { - if input.peek(LitStr) { - Ok(Self::String(input.parse()?)) - } else if input.peek(LitInt) { - Ok(Self::Number(input.parse()?)) - } else if input.peek(LitBool) { - Ok(Self::Bool(input.parse()?)) - } else { - Err(Error::new(input.span(), "failed to parse literal")) - } - } -} diff --git a/crates/syn-solidity/src/literals/mod.rs b/crates/syn-solidity/src/literals/mod.rs deleted file mode 100644 index 73e0f9b188..0000000000 --- a/crates/syn-solidity/src/literals/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod lits; diff --git a/crates/syn-solidity/src/statments/assembly.rs b/crates/syn-solidity/src/stmt/assembly.rs similarity index 100% rename from crates/syn-solidity/src/statments/assembly.rs rename to crates/syn-solidity/src/stmt/assembly.rs diff --git a/crates/syn-solidity/src/statments/binop.rs b/crates/syn-solidity/src/stmt/binop.rs similarity index 83% rename from crates/syn-solidity/src/statments/binop.rs rename to crates/syn-solidity/src/stmt/binop.rs index 172743a00f..d084cd1bd0 100644 --- a/crates/syn-solidity/src/statments/binop.rs +++ b/crates/syn-solidity/src/stmt/binop.rs @@ -1,13 +1,13 @@ use crate::binops::Binop; use syn::parse::Parse; -use crate::expr::Expr; +use crate::expr::Stmt; #[derive(Debug, Clone)] pub struct BinopExpr { - pub left: Box, + pub left: Box, pub op: Binop, - pub right: Box, + pub right: Box, } impl Parse for BinopExpr { diff --git a/crates/syn-solidity/src/statments/binops/mod.rs b/crates/syn-solidity/src/stmt/binops/mod.rs similarity index 100% rename from crates/syn-solidity/src/statments/binops/mod.rs rename to crates/syn-solidity/src/stmt/binops/mod.rs diff --git a/crates/syn-solidity/src/statments/binops/pow.rs b/crates/syn-solidity/src/stmt/binops/pow.rs similarity index 100% rename from crates/syn-solidity/src/statments/binops/pow.rs rename to crates/syn-solidity/src/stmt/binops/pow.rs diff --git a/crates/syn-solidity/src/statments/binops/ternary.rs b/crates/syn-solidity/src/stmt/binops/ternary.rs similarity index 100% rename from crates/syn-solidity/src/statments/binops/ternary.rs rename to crates/syn-solidity/src/stmt/binops/ternary.rs diff --git a/crates/syn-solidity/src/stmt.rs b/crates/syn-solidity/src/stmt/block.rs similarity index 68% rename from crates/syn-solidity/src/stmt.rs rename to crates/syn-solidity/src/stmt/block.rs index 5e7a309e0e..f9a84cc17d 100644 --- a/crates/syn-solidity/src/stmt.rs +++ b/crates/syn-solidity/src/stmt/block.rs @@ -1,3 +1,4 @@ +use crate::Stmt; use std::fmt; use syn::{ parse::{Parse, ParseStream}, @@ -5,13 +6,11 @@ use syn::{ Result, }; -use crate::expr::Expr; - /// A curly-braced block of statements. #[derive(Clone)] pub struct Block { pub brace_token: Brace, - pub stmts: Vec, + pub stmts: Vec, } impl fmt::Debug for Block { @@ -23,15 +22,15 @@ impl fmt::Debug for Block { impl Parse for Block { fn parse(input: ParseStream<'_>) -> Result { let content; - let mut exprs = Vec::new(); - - while !input.peek(Brace) { - exprs.push(input.parse()?); - } - Ok(Self { brace_token: syn::braced!(content in input), - stmts: exprs, + stmts: { + let mut stmts = Vec::new(); + while !content.is_empty() { + stmts.push(content.parse()?); + } + stmts + }, }) } } diff --git a/crates/syn-solidity/src/statments/call_args.rs b/crates/syn-solidity/src/stmt/call_args.rs similarity index 93% rename from crates/syn-solidity/src/statments/call_args.rs rename to crates/syn-solidity/src/stmt/call_args.rs index 103542cc42..2ec471a67d 100644 --- a/crates/syn-solidity/src/statments/call_args.rs +++ b/crates/syn-solidity/src/stmt/call_args.rs @@ -5,7 +5,7 @@ use syn::{ Error, Ident, Token, }; -use crate::expr::Expr; +use crate::expr::Stmt; #[derive(Debug, Clone)] pub enum CallArgs { @@ -14,7 +14,7 @@ pub enum CallArgs { } #[derive(Debug, Clone)] -pub struct ListArgs(pub Punctuated); +pub struct ListArgs(pub Punctuated); #[derive(Debug, Clone)] pub struct MapArgs(pub Punctuated); @@ -23,7 +23,7 @@ pub struct MapArgs(pub Punctuated); pub struct Map { pub key: Ident, pub semi: Token![:], - pub value: Box, + pub value: Box, } impl Parse for CallArgs { diff --git a/crates/syn-solidity/src/statments/emit.rs b/crates/syn-solidity/src/stmt/emit.rs similarity index 85% rename from crates/syn-solidity/src/statments/emit.rs rename to crates/syn-solidity/src/stmt/emit.rs index 7b17f35bcf..ee06bf24b8 100644 --- a/crates/syn-solidity/src/statments/emit.rs +++ b/crates/syn-solidity/src/stmt/emit.rs @@ -1,10 +1,10 @@ -use crate::{call_args::CallArgs, expr::Expr, kw}; +use crate::{call_args::CallArgs, expr::Stmt, kw}; use syn::{parse::Parse, Token}; #[derive(Debug, Clone)] pub struct Emit { keyword: kw::emit, - expr: Box, + expr: Box, args: CallArgs, semi: Token!(;), } diff --git a/crates/syn-solidity/src/statments/expr.rs b/crates/syn-solidity/src/stmt/expr.rs similarity index 99% rename from crates/syn-solidity/src/statments/expr.rs rename to crates/syn-solidity/src/stmt/expr.rs index 4f3fcc7de7..a14ce98d59 100644 --- a/crates/syn-solidity/src/statments/expr.rs +++ b/crates/syn-solidity/src/stmt/expr.rs @@ -26,7 +26,7 @@ use syn::{ }; #[derive(Clone, Debug)] -pub enum Expr { +pub enum Stmt { Block(Block), While(While), DoWhile(DoWhile), @@ -47,7 +47,7 @@ pub enum Expr { Assembly(Assembly), } -impl Parse for Expr { +impl Parse for Stmt { fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { if input.peek(Token![while]) { return Ok(Self::While(While::parse(input)?)) diff --git a/crates/syn-solidity/src/statments/field.rs b/crates/syn-solidity/src/stmt/field.rs similarity index 88% rename from crates/syn-solidity/src/statments/field.rs rename to crates/syn-solidity/src/stmt/field.rs index d643865a2e..781c095e88 100644 --- a/crates/syn-solidity/src/statments/field.rs +++ b/crates/syn-solidity/src/stmt/field.rs @@ -1,10 +1,10 @@ -use crate::expr::Expr; +use crate::expr::Stmt; use proc_macro2::Ident; use syn::{parse::Parse, Token}; #[derive(Debug, Clone)] pub struct Field { - pub base: Box, + pub base: Box, pub dot: Token![.], pub name: Ident, } diff --git a/crates/syn-solidity/src/statments/for.rs b/crates/syn-solidity/src/stmt/for.rs similarity index 90% rename from crates/syn-solidity/src/statments/for.rs rename to crates/syn-solidity/src/stmt/for.rs index 3f6e57ac0c..e7634ff607 100644 --- a/crates/syn-solidity/src/statments/for.rs +++ b/crates/syn-solidity/src/stmt/for.rs @@ -1,4 +1,4 @@ -use crate::{binop::BinopExpr, expr::Expr, Block}; +use crate::{binop::BinopExpr, expr::Stmt, Block}; use syn::{parenthesized, parse::Parse, token::Paren, Token}; #[derive(Debug, Clone)] @@ -12,9 +12,9 @@ pub struct ForAssignment { pub brace: Paren, pub iter_asign: BinopExpr, pub semi: Token![;], - pub cond: Box, + pub cond: Box, pub semi2: Token![;], - pub up_cond: Option>, + pub up_cond: Option>, pub block: Block, } diff --git a/crates/syn-solidity/src/statments/if.rs b/crates/syn-solidity/src/stmt/if.rs similarity index 100% rename from crates/syn-solidity/src/statments/if.rs rename to crates/syn-solidity/src/stmt/if.rs diff --git a/crates/syn-solidity/src/statments/index.rs b/crates/syn-solidity/src/stmt/index.rs similarity index 89% rename from crates/syn-solidity/src/statments/index.rs rename to crates/syn-solidity/src/stmt/index.rs index 302ad98b64..a235927341 100644 --- a/crates/syn-solidity/src/statments/index.rs +++ b/crates/syn-solidity/src/stmt/index.rs @@ -1,13 +1,13 @@ use proc_macro2::Ident; use syn::{bracketed, parse::Parse, token::Bracket}; -use crate::expr::Expr; +use crate::expr::Stmt; #[derive(Debug, Clone)] pub struct Index { pub name: Ident, pub bracket: Bracket, - pub index_by: Box, + pub index_by: Box, } impl Parse for Index { diff --git a/crates/syn-solidity/src/statments/inline_array_expr.rs b/crates/syn-solidity/src/stmt/inline_array_expr.rs similarity index 90% rename from crates/syn-solidity/src/statments/inline_array_expr.rs rename to crates/syn-solidity/src/stmt/inline_array_expr.rs index 54221bbff8..5d5bbff1e4 100644 --- a/crates/syn-solidity/src/statments/inline_array_expr.rs +++ b/crates/syn-solidity/src/stmt/inline_array_expr.rs @@ -1,10 +1,10 @@ -use crate::expr::Expr; +use crate::expr::Stmt; use syn::{bracketed, parse::Parse, punctuated::Punctuated, token::Bracket, Token}; #[derive(Debug, Clone)] pub struct InlineArrayExpr { bracket: Bracket, - exprs: Punctuated, + exprs: Punctuated, } impl Parse for InlineArrayExpr { diff --git a/crates/syn-solidity/src/statments/loop_ops.rs b/crates/syn-solidity/src/stmt/loop_ops.rs similarity index 100% rename from crates/syn-solidity/src/statments/loop_ops.rs rename to crates/syn-solidity/src/stmt/loop_ops.rs diff --git a/crates/syn-solidity/src/statments/method_call.rs b/crates/syn-solidity/src/stmt/method_call.rs similarity index 100% rename from crates/syn-solidity/src/statments/method_call.rs rename to crates/syn-solidity/src/stmt/method_call.rs diff --git a/crates/syn-solidity/src/statments/mod.rs b/crates/syn-solidity/src/stmt/mod.rs similarity index 86% rename from crates/syn-solidity/src/statments/mod.rs rename to crates/syn-solidity/src/stmt/mod.rs index 0bbc4c2cf9..d7418f63fd 100644 --- a/crates/syn-solidity/src/statments/mod.rs +++ b/crates/syn-solidity/src/stmt/mod.rs @@ -18,3 +18,8 @@ pub mod try_catch; pub mod tuple_expr; pub mod unchecked; pub mod r#while; + +mod block; +pub use block::Block; + +pub use expr::Stmt; diff --git a/crates/syn-solidity/src/statments/new.rs b/crates/syn-solidity/src/stmt/new.rs similarity index 57% rename from crates/syn-solidity/src/statments/new.rs rename to crates/syn-solidity/src/stmt/new.rs index 563f9182b6..11cbc86fa7 100644 --- a/crates/syn-solidity/src/statments/new.rs +++ b/crates/syn-solidity/src/stmt/new.rs @@ -1,17 +1,17 @@ -use crate::{kw, r#type::Type}; +use crate::{kw, Type}; use syn::parse::Parse; #[derive(Debug, Clone)] pub struct New { - new_kw: kw::new, - type_name: Type, + new_token: kw::new, + ty: Type, } impl Parse for New { fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { Ok(Self { - new_kw: input.parse()?, - type_name: input.parse()?, + new_token: input.parse()?, + ty: input.parse()?, }) } } diff --git a/crates/syn-solidity/src/statments/return.rs b/crates/syn-solidity/src/stmt/return.rs similarity index 89% rename from crates/syn-solidity/src/statments/return.rs rename to crates/syn-solidity/src/stmt/return.rs index 30a717b09a..5d228b7367 100644 --- a/crates/syn-solidity/src/statments/return.rs +++ b/crates/syn-solidity/src/stmt/return.rs @@ -1,10 +1,10 @@ -use crate::expr::Expr; +use crate::expr::Stmt; use syn::{parse::Parse, Token}; #[derive(Debug, Clone)] pub struct Return { token: Token![return], - expr: Box, + expr: Box, semi: Token![;], } diff --git a/crates/syn-solidity/src/statments/revert.rs b/crates/syn-solidity/src/stmt/revert.rs similarity index 85% rename from crates/syn-solidity/src/statments/revert.rs rename to crates/syn-solidity/src/stmt/revert.rs index 2d7c843341..3d51629735 100644 --- a/crates/syn-solidity/src/statments/revert.rs +++ b/crates/syn-solidity/src/stmt/revert.rs @@ -1,10 +1,10 @@ -use crate::{call_args::CallArgs, expr::Expr, kw}; +use crate::{call_args::CallArgs, expr::Stmt, kw}; use syn::{parse::Parse, Token}; #[derive(Clone, Debug)] pub struct Revert { kw: kw::revert, - expr: Box, + expr: Box, args: CallArgs, semi: Token![;], } diff --git a/crates/syn-solidity/src/statments/try_catch.rs b/crates/syn-solidity/src/stmt/try_catch.rs similarity index 100% rename from crates/syn-solidity/src/statments/try_catch.rs rename to crates/syn-solidity/src/stmt/try_catch.rs diff --git a/crates/syn-solidity/src/statments/tuple_expr.rs b/crates/syn-solidity/src/stmt/tuple_expr.rs similarity index 90% rename from crates/syn-solidity/src/statments/tuple_expr.rs rename to crates/syn-solidity/src/stmt/tuple_expr.rs index 384343d175..3560c5d048 100644 --- a/crates/syn-solidity/src/statments/tuple_expr.rs +++ b/crates/syn-solidity/src/stmt/tuple_expr.rs @@ -1,11 +1,11 @@ use syn::{parenthesized, parse::Parse, punctuated::Punctuated, token::Paren, Token}; -use crate::expr::Expr; +use crate::expr::Stmt; #[derive(Debug, Clone)] pub struct TupleExpr { paren: Paren, - exprs: Punctuated, + exprs: Punctuated, } impl Parse for TupleExpr { diff --git a/crates/syn-solidity/src/statments/unchecked.rs b/crates/syn-solidity/src/stmt/unchecked.rs similarity index 100% rename from crates/syn-solidity/src/statments/unchecked.rs rename to crates/syn-solidity/src/stmt/unchecked.rs diff --git a/crates/syn-solidity/src/statments/while.rs b/crates/syn-solidity/src/stmt/while.rs similarity index 93% rename from crates/syn-solidity/src/statments/while.rs rename to crates/syn-solidity/src/stmt/while.rs index dd841e8416..7ba4751fa0 100644 --- a/crates/syn-solidity/src/statments/while.rs +++ b/crates/syn-solidity/src/stmt/while.rs @@ -1,6 +1,6 @@ use syn::{parenthesized, parse::Parse, token::Paren, Token}; -use crate::{expr::Expr, Block}; +use crate::{expr::Stmt, Block}; #[derive(Debug, Clone)] pub struct DoWhile { @@ -8,7 +8,7 @@ pub struct DoWhile { pub block: Block, pub while_token: Token![while], pub paren: Paren, - pub expr: Box, + pub expr: Box, } impl Parse for DoWhile { @@ -35,7 +35,7 @@ impl Parse for DoWhile { pub struct While { pub while_token: Token![while], pub paren: Paren, - pub expr: Box, + pub expr: Box, pub block: Block, } diff --git a/crates/syn-solidity/src/type/array.rs b/crates/syn-solidity/src/type/array.rs index 256cfcb39e..0f677d8144 100644 --- a/crates/syn-solidity/src/type/array.rs +++ b/crates/syn-solidity/src/type/array.rs @@ -1,4 +1,4 @@ -use crate::r#type::Type; +use crate::Type; use proc_macro2::Span; use std::{ fmt, diff --git a/crates/syn-solidity/src/type/mapping.rs b/crates/syn-solidity/src/type/mapping.rs index f9e1337ebb..208b50f740 100644 --- a/crates/syn-solidity/src/type/mapping.rs +++ b/crates/syn-solidity/src/type/mapping.rs @@ -1,4 +1,4 @@ -use crate::{kw, r#type::Type, SolIdent}; +use crate::{kw, SolIdent, Type}; use proc_macro2::Span; use std::{ fmt, diff --git a/crates/syn-solidity/src/type/mod.rs b/crates/syn-solidity/src/type/mod.rs index c530562ff1..f0927330f6 100644 --- a/crates/syn-solidity/src/type/mod.rs +++ b/crates/syn-solidity/src/type/mod.rs @@ -12,17 +12,17 @@ use syn::{ Error, Ident, Result, Token, }; -pub mod array; -pub use array::*; +mod array; +pub use array::TypeArray; -pub mod function; -pub use function::*; +mod function; +pub use function::TypeFunction; -pub mod mapping; -pub use mapping::*; +mod mapping; +pub use mapping::TypeMapping; -pub mod tuple; -pub use tuple::*; +mod tuple; +pub use tuple::TypeTuple; /// A type name. /// diff --git a/crates/syn-solidity/src/type/tuple.rs b/crates/syn-solidity/src/type/tuple.rs index 69f6bf54b2..bc577ba983 100644 --- a/crates/syn-solidity/src/type/tuple.rs +++ b/crates/syn-solidity/src/type/tuple.rs @@ -1,4 +1,4 @@ -use crate::{kw, r#type::Type, utils::DebugPunctuated}; +use crate::{kw, utils::DebugPunctuated, Type}; use proc_macro2::Span; use std::{ fmt, diff --git a/crates/syn-solidity/src/variable/list.rs b/crates/syn-solidity/src/variable/list.rs index 50effd1627..b195d54759 100644 --- a/crates/syn-solidity/src/variable/list.rs +++ b/crates/syn-solidity/src/variable/list.rs @@ -1,5 +1,5 @@ use super::VariableDeclaration; -use crate::{r#type::Type, SolIdent}; +use crate::{SolIdent, Type}; use std::{ fmt, ops::{Deref, DerefMut}, diff --git a/crates/syn-solidity/src/variable/mod.rs b/crates/syn-solidity/src/variable/mod.rs index 813f152c39..b922ddd3d4 100644 --- a/crates/syn-solidity/src/variable/mod.rs +++ b/crates/syn-solidity/src/variable/mod.rs @@ -1,4 +1,4 @@ -use super::{r#type::Type, SolIdent, Storage}; +use super::{SolIdent, Storage, Type}; use crate::{utils::tts_until_semi, VariableAttributes}; use proc_macro2::{Span, TokenStream}; use std::fmt::{self, Write}; diff --git a/crates/syn-solidity/src/visit.rs b/crates/syn-solidity/src/visit.rs index 47e0783733..aa83c1cd20 100644 --- a/crates/syn-solidity/src/visit.rs +++ b/crates/syn-solidity/src/visit.rs @@ -8,7 +8,6 @@ #![allow(unused_variables)] use super::*; -use crate::r#type::*; make_visitor! { /// Syntax tree traversal to walk a shared borrow of a syntax tree. diff --git a/crates/syn-solidity/src/visit_mut.rs b/crates/syn-solidity/src/visit_mut.rs index 53aa970c1e..7e7b52c7f1 100644 --- a/crates/syn-solidity/src/visit_mut.rs +++ b/crates/syn-solidity/src/visit_mut.rs @@ -9,7 +9,6 @@ #![allow(unused_variables)] use super::*; -use crate::r#type::*; make_visitor! { /// Syntax tree traversal to mutate an exclusive borrow of a syntax tree in From 75b651a76cee2ad3573051a5580427e8edcbd6f3 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Fri, 4 Aug 2023 02:39:41 +0200 Subject: [PATCH 11/22] feat: stmt --- a.sol | 5 + crates/sol-macro/src/expand/ty.rs | 5 +- crates/syn-solidity/src/attribute/function.rs | 6 +- crates/syn-solidity/src/attribute/mod.rs | 2 +- crates/syn-solidity/src/attribute/variable.rs | 4 +- crates/syn-solidity/src/expr/args.rs | 108 ++++++++++ crates/syn-solidity/src/expr/mod.rs | 33 +++ crates/syn-solidity/src/file.rs | 2 +- crates/syn-solidity/src/item/contract.rs | 6 +- crates/syn-solidity/src/kw.rs | 2 - crates/syn-solidity/src/lib.rs | 7 +- crates/syn-solidity/src/lit.rs | 8 + crates/syn-solidity/src/stmt/assembly.rs | 91 ++++++-- crates/syn-solidity/src/stmt/binop.rs | 21 -- crates/syn-solidity/src/stmt/binops/mod.rs | 101 --------- crates/syn-solidity/src/stmt/binops/pow.rs | 17 -- .../syn-solidity/src/stmt/binops/ternary.rs | 29 --- crates/syn-solidity/src/stmt/block.rs | 36 ---- crates/syn-solidity/src/stmt/blocks.rs | 76 +++++++ crates/syn-solidity/src/stmt/break.rs | 43 ++++ crates/syn-solidity/src/stmt/call_args.rs | 71 ------- crates/syn-solidity/src/stmt/continue.rs | 43 ++++ crates/syn-solidity/src/stmt/do_while.rs | 57 +++++ crates/syn-solidity/src/stmt/emit.rs | 58 ++++-- crates/syn-solidity/src/stmt/expr.rs | 150 ++++---------- crates/syn-solidity/src/stmt/field.rs | 20 -- crates/syn-solidity/src/stmt/for.rs | 86 +++++--- crates/syn-solidity/src/stmt/if.rs | 90 ++++---- crates/syn-solidity/src/stmt/index.rs | 22 -- .../src/stmt/inline_array_expr.rs | 24 --- crates/syn-solidity/src/stmt/loop_ops.rs | 31 --- crates/syn-solidity/src/stmt/method_call.rs | 29 --- crates/syn-solidity/src/stmt/mod.rs | 196 +++++++++++++++--- crates/syn-solidity/src/stmt/new.rs | 17 -- crates/syn-solidity/src/stmt/return.rs | 57 +++-- crates/syn-solidity/src/stmt/revert.rs | 58 ++++-- crates/syn-solidity/src/stmt/try.rs | 121 +++++++++++ crates/syn-solidity/src/stmt/try_catch.rs | 73 ------- crates/syn-solidity/src/stmt/tuple_expr.rs | 25 --- crates/syn-solidity/src/stmt/unchecked.rs | 18 -- crates/syn-solidity/src/stmt/var_decl.rs | 146 +++++++++++++ crates/syn-solidity/src/stmt/while.rs | 85 ++++---- crates/syn-solidity/src/utils.rs | 18 +- crates/syn-solidity/src/variable/mod.rs | 11 +- crates/syn-solidity/src/yul/block.rs | 43 ++++ crates/syn-solidity/src/yul/mod.rs | 2 + 46 files changed, 1285 insertions(+), 868 deletions(-) create mode 100644 a.sol create mode 100644 crates/syn-solidity/src/expr/args.rs create mode 100644 crates/syn-solidity/src/expr/mod.rs delete mode 100644 crates/syn-solidity/src/stmt/binop.rs delete mode 100644 crates/syn-solidity/src/stmt/binops/mod.rs delete mode 100644 crates/syn-solidity/src/stmt/binops/pow.rs delete mode 100644 crates/syn-solidity/src/stmt/binops/ternary.rs delete mode 100644 crates/syn-solidity/src/stmt/block.rs create mode 100644 crates/syn-solidity/src/stmt/blocks.rs create mode 100644 crates/syn-solidity/src/stmt/break.rs delete mode 100644 crates/syn-solidity/src/stmt/call_args.rs create mode 100644 crates/syn-solidity/src/stmt/continue.rs create mode 100644 crates/syn-solidity/src/stmt/do_while.rs delete mode 100644 crates/syn-solidity/src/stmt/field.rs delete mode 100644 crates/syn-solidity/src/stmt/index.rs delete mode 100644 crates/syn-solidity/src/stmt/inline_array_expr.rs delete mode 100644 crates/syn-solidity/src/stmt/loop_ops.rs delete mode 100644 crates/syn-solidity/src/stmt/method_call.rs delete mode 100644 crates/syn-solidity/src/stmt/new.rs create mode 100644 crates/syn-solidity/src/stmt/try.rs delete mode 100644 crates/syn-solidity/src/stmt/try_catch.rs delete mode 100644 crates/syn-solidity/src/stmt/tuple_expr.rs delete mode 100644 crates/syn-solidity/src/stmt/unchecked.rs create mode 100644 crates/syn-solidity/src/stmt/var_decl.rs create mode 100644 crates/syn-solidity/src/yul/block.rs create mode 100644 crates/syn-solidity/src/yul/mod.rs diff --git a/a.sol b/a.sol new file mode 100644 index 0000000000..3fc6fc2fe1 --- /dev/null +++ b/a.sol @@ -0,0 +1,5 @@ +function f() pure { + uint256 a; + (++a, ++a); + uint256; +} diff --git a/crates/sol-macro/src/expand/ty.rs b/crates/sol-macro/src/expand/ty.rs index 45b6631825..f37ea50570 100644 --- a/crates/sol-macro/src/expand/ty.rs +++ b/crates/sol-macro/src/expand/ty.rs @@ -2,10 +2,7 @@ use super::ExpCtxt; use crate::expand::generate_name; -use ast::{ - r#type::{Type, TypeArray}, - EventParameter, Item, Parameters, VariableDeclaration, -}; +use ast::{EventParameter, Item, Parameters, Type, TypeArray, VariableDeclaration}; use proc_macro2::{Literal, TokenStream}; use quote::{quote, quote_spanned, ToTokens}; use std::{fmt, num::NonZeroU16}; diff --git a/crates/syn-solidity/src/attribute/function.rs b/crates/syn-solidity/src/attribute/function.rs index f407146348..4bbfe9aa2b 100644 --- a/crates/syn-solidity/src/attribute/function.rs +++ b/crates/syn-solidity/src/attribute/function.rs @@ -116,7 +116,7 @@ pub enum FunctionAttribute { /// A [Mutability] attribute. Mutability(Mutability), /// `virtual` - Virtual(kw::Virtual), + Virtual(Token![virtual]), /// `immutable` Immutable(kw::immutable), /// An [Override] attribute. @@ -178,9 +178,9 @@ impl Parse for FunctionAttribute { input.parse().map(Self::Visibility) } else if Mutability::peek(&lookahead) { input.parse().map(Self::Mutability) - } else if lookahead.peek(kw::Virtual) { + } else if lookahead.peek(Token![virtual]) { input.parse().map(Self::Virtual) - } else if lookahead.peek(kw::Override) { + } else if lookahead.peek(Token![override]) { input.parse().map(Self::Override) } else if lookahead.peek(kw::immutable) { input.parse().map(Self::Immutable) diff --git a/crates/syn-solidity/src/attribute/mod.rs b/crates/syn-solidity/src/attribute/mod.rs index 6e18546e61..39789a9dbe 100644 --- a/crates/syn-solidity/src/attribute/mod.rs +++ b/crates/syn-solidity/src/attribute/mod.rs @@ -61,7 +61,7 @@ kw_enum! { /// The `override` attribute. #[derive(Clone, PartialEq, Eq, Hash)] pub struct Override { - pub override_token: kw::Override, + pub override_token: Token![override], pub paren_token: Option, pub paths: Punctuated, } diff --git a/crates/syn-solidity/src/attribute/variable.rs b/crates/syn-solidity/src/attribute/variable.rs index 6f7b878e63..0f04eda240 100644 --- a/crates/syn-solidity/src/attribute/variable.rs +++ b/crates/syn-solidity/src/attribute/variable.rs @@ -8,7 +8,7 @@ use std::{ }; use syn::{ parse::{Parse, ParseStream}, - Error, Result, + Error, Result, Token, }; /// A list of unique variable attributes. @@ -132,7 +132,7 @@ impl Parse for VariableAttribute { input.parse().map(Self::Visibility) } else if lookahead.peek(kw::constant) { input.parse().map(Self::Constant) - } else if lookahead.peek(kw::Override) { + } else if lookahead.peek(Token![override]) { input.parse().map(Self::Override) } else if lookahead.peek(kw::immutable) { input.parse().map(Self::Immutable) diff --git a/crates/syn-solidity/src/expr/args.rs b/crates/syn-solidity/src/expr/args.rs new file mode 100644 index 0000000000..28f07fbd75 --- /dev/null +++ b/crates/syn-solidity/src/expr/args.rs @@ -0,0 +1,108 @@ +use crate::{Expr, SolIdent}; +use proc_macro2::Span; +use std::fmt; +use syn::{ + braced, parenthesized, + parse::{Parse, ParseStream}, + punctuated::Punctuated, + token::{Brace, Paren}, + Result, Token, +}; + +#[derive(Clone)] +pub struct CallArgumentList { + pub paren_token: Paren, + /// The list of arguments. Can be named or unnamed. + /// + /// When empty, this is an empty unnamed list. + pub list: CallArgumentListImpl, +} + +impl fmt::Debug for CallArgumentList { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("CallArgumentList") + .field("list", &self.list) + .finish() + } +} + +impl Parse for CallArgumentList { + fn parse(input: ParseStream<'_>) -> Result { + let content; + Ok(Self { + paren_token: parenthesized!(content in input), + list: content.parse()?, + }) + } +} + +impl CallArgumentList { + pub fn span(&self) -> Span { + self.paren_token.span.join() + } + + pub fn set_span(&mut self, span: Span) { + self.paren_token = Paren(span); + } +} + +#[derive(Clone, Debug)] +pub enum CallArgumentListImpl { + Unnamed(Punctuated), + Named(Brace, Punctuated), +} + +impl Parse for CallArgumentListImpl { + fn parse(input: ParseStream<'_>) -> Result { + if input.peek(Brace) { + let content; + Ok(Self::Named( + braced!(content in input), + content.parse_terminated(NamedArg::parse, Token![,])?, + )) + } else { + input + .parse_terminated(Expr::parse, Token![,]) + .map(Self::Unnamed) + } + } +} + +/// A named argument in an argument list: `foo: uint256(42)` +#[derive(Clone)] +pub struct NamedArg { + pub name: SolIdent, + pub colon_token: Token![:], + pub arg: Expr, +} + +impl fmt::Debug for NamedArg { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("NamedArg") + .field("name", &self.name) + .field("arg", &self.arg) + .finish() + } +} + +impl Parse for NamedArg { + fn parse(input: ParseStream<'_>) -> Result { + Ok(Self { + name: input.parse()?, + colon_token: input.parse()?, + arg: input.parse()?, + }) + } +} + +impl NamedArg { + pub fn span(&self) -> Span { + let span = self.name.span(); + span.join(self.arg.span()).unwrap_or(span) + } + + pub fn set_span(&mut self, span: Span) { + self.name.set_span(span); + self.arg.set_span(span); + } +} diff --git a/crates/syn-solidity/src/expr/mod.rs b/crates/syn-solidity/src/expr/mod.rs new file mode 100644 index 0000000000..96101a86bf --- /dev/null +++ b/crates/syn-solidity/src/expr/mod.rs @@ -0,0 +1,33 @@ +use proc_macro2::Span; +use syn::{ + parse::{Parse, ParseStream}, + Result, +}; + +mod args; +pub use args::{CallArgumentList, CallArgumentListImpl, NamedArg}; + +/// An expression. +/// +/// Solidity reference: +/// +#[derive(Clone, Debug)] +pub enum Expr {} + +impl Parse for Expr { + fn parse(input: ParseStream<'_>) -> Result { + let _ = input; + todo!() + } +} + +impl Expr { + pub fn span(&self) -> Span { + match *self {} + } + + pub fn set_span(&mut self, span: Span) { + let _ = span; + match *self {} + } +} diff --git a/crates/syn-solidity/src/file.rs b/crates/syn-solidity/src/file.rs index c716fd5d2d..5597325e84 100644 --- a/crates/syn-solidity/src/file.rs +++ b/crates/syn-solidity/src/file.rs @@ -5,7 +5,7 @@ use syn::{ }; /// A Solidity file. The root of the AST. -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct File { /// The inner attributes of the file. pub attrs: Vec, diff --git a/crates/syn-solidity/src/item/contract.rs b/crates/syn-solidity/src/item/contract.rs index 706a68c5a9..42fc5d2d03 100644 --- a/crates/syn-solidity/src/item/contract.rs +++ b/crates/syn-solidity/src/item/contract.rs @@ -107,7 +107,7 @@ impl ItemContract { /// The kind of contract. #[derive(Clone, Copy, PartialEq, Eq, Hash)] pub enum ContractKind { - AbstractContract(kw::Abstract, kw::contract), + AbstractContract(Token![abstract], kw::contract), Contract(kw::contract), Interface(kw::interface), Library(kw::library), @@ -140,7 +140,7 @@ impl Ord for ContractKind { impl Parse for ContractKind { fn parse(input: ParseStream<'_>) -> Result { let lookahead = input.lookahead1(); - if lookahead.peek(kw::Abstract) { + if lookahead.peek(Token![abstract]) { Ok(Self::AbstractContract(input.parse()?, input.parse()?)) } else if lookahead.peek(kw::contract) { input.parse().map(Self::Contract) @@ -156,7 +156,7 @@ impl Parse for ContractKind { impl ContractKind { pub fn peek(lookahead: &Lookahead1<'_>) -> bool { - lookahead.peek(kw::Abstract) + lookahead.peek(Token![abstract]) || lookahead.peek(kw::contract) || lookahead.peek(kw::interface) || lookahead.peek(kw::library) diff --git a/crates/syn-solidity/src/kw.rs b/crates/syn-solidity/src/kw.rs index c6649cca00..fd0d2cd9f5 100644 --- a/crates/syn-solidity/src/kw.rs +++ b/crates/syn-solidity/src/kw.rs @@ -1,7 +1,5 @@ //! Solidity keywords. -pub use syn::token::{Abstract, Override, Virtual}; - macro_rules! custom_keywords { ($($name:ident),+ $(,)?) => { $(syn::custom_keyword!($name);)+ diff --git a/crates/syn-solidity/src/lib.rs b/crates/syn-solidity/src/lib.rs index 46ec33f55f..7381b8d817 100644 --- a/crates/syn-solidity/src/lib.rs +++ b/crates/syn-solidity/src/lib.rs @@ -4,7 +4,6 @@ html_favicon_url = "https://raw.githubusercontent.com/alloy-rs/core/main/assets/favicon.ico" )] #![warn( - missing_copy_implementations, missing_debug_implementations, unreachable_pub, unused_crate_dependencies, @@ -26,6 +25,9 @@ pub use attribute::{ VariableAttribute, VariableAttributes, Visibility, }; +mod expr; +pub use expr::*; + mod file; pub use file::File; @@ -66,6 +68,9 @@ pub mod visit_mut; #[cfg(feature = "visit-mut")] pub use visit_mut::VisitMut; +mod yul; +pub use yul::YulBlock; + /// Parse a Solidity [`proc_macro::TokenStream`] into a [`File`]. pub fn parse(input: proc_macro::TokenStream) -> Result { syn::parse(input) diff --git a/crates/syn-solidity/src/lit.rs b/crates/syn-solidity/src/lit.rs index 64d3d45acc..e0e39ee735 100644 --- a/crates/syn-solidity/src/lit.rs +++ b/crates/syn-solidity/src/lit.rs @@ -50,6 +50,14 @@ impl Parse for LitStr { } impl LitStr { + pub fn parse_opt(input: ParseStream<'_>) -> Result> { + if input.peek(kw::unicode) || input.peek(syn::LitStr) { + input.parse().map(Some) + } else { + Ok(None) + } + } + pub fn span(&self) -> Span { let mut span = if let Some(kw) = &self.unicode_token { kw.span diff --git a/crates/syn-solidity/src/stmt/assembly.rs b/crates/syn-solidity/src/stmt/assembly.rs index 537083f61e..8fcfcb3059 100644 --- a/crates/syn-solidity/src/stmt/assembly.rs +++ b/crates/syn-solidity/src/stmt/assembly.rs @@ -1,23 +1,84 @@ -use proc_macro2::TokenStream; -use syn::{braced, parse::Parse, token::Brace}; +use crate::{kw, LitStr, YulBlock}; +use proc_macro2::Span; +use std::fmt; +use syn::{ + parse::{Parse, ParseStream}, + punctuated::Punctuated, + token::Paren, + Result, Token, +}; -use crate::kw; +#[derive(Clone)] +pub struct StmtAssembly { + pub assembly_token: kw::assembly, + pub literal: Option, + pub flags: Option, + pub block: YulBlock, +} -#[derive(Debug, Clone)] -pub struct Assembly { - kw: kw::assembly, - // stuff here - brace: Brace, - input: TokenStream, +impl fmt::Debug for StmtAssembly { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("StmtAssembly") + .field("literal", &self.literal) + .field("flags", &self.flags) + .field("block", &self.block) + .finish() + } +} + +impl Parse for StmtAssembly { + fn parse(input: ParseStream<'_>) -> Result { + Ok(Self { + assembly_token: input.parse()?, + literal: input.call(LitStr::parse_opt)?, + flags: input.call(AssemblyFlags::parse_opt)?, + block: input.parse()?, + }) + } } -impl Parse for Assembly { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { +impl StmtAssembly { + pub fn span(&self) -> Span { + let span = self.assembly_token.span; + span.join(self.block.span()).unwrap_or(span) + } + + pub fn set_span(&mut self, span: Span) { + self.assembly_token.span = span; + self.block.set_span(span); + } +} + +#[derive(Clone)] +pub struct AssemblyFlags { + pub paren_token: Paren, + pub strings: Punctuated, +} + +impl fmt::Debug for AssemblyFlags { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("AssemblyFlags") + .field("strings", &self.strings) + .finish() + } +} + +impl Parse for AssemblyFlags { + fn parse(input: ParseStream<'_>) -> Result { let content; - let kw = input.parse()?; - let brace = braced!(content in input); - let input = input.parse()?; + Ok(Self { + paren_token: syn::parenthesized!(content in input), + strings: content.parse_terminated(LitStr::parse, Token![,])?, + }) + } +} - Ok(Self { input, kw, brace }) +impl AssemblyFlags { + pub fn parse_opt(input: ParseStream<'_>) -> Result> { + if input.peek(Paren) { + input.parse().map(Some) + } else { + Ok(None) + } } } diff --git a/crates/syn-solidity/src/stmt/binop.rs b/crates/syn-solidity/src/stmt/binop.rs deleted file mode 100644 index d084cd1bd0..0000000000 --- a/crates/syn-solidity/src/stmt/binop.rs +++ /dev/null @@ -1,21 +0,0 @@ -use crate::binops::Binop; -use syn::parse::Parse; - -use crate::expr::Stmt; - -#[derive(Debug, Clone)] -pub struct BinopExpr { - pub left: Box, - pub op: Binop, - pub right: Box, -} - -impl Parse for BinopExpr { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { - Ok(Self { - left: Box::new(input.parse()?), - op: input.parse()?, - right: Box::new(input.parse()?), - }) - } -} diff --git a/crates/syn-solidity/src/stmt/binops/mod.rs b/crates/syn-solidity/src/stmt/binops/mod.rs deleted file mode 100644 index 2fc71d1b3f..0000000000 --- a/crates/syn-solidity/src/stmt/binops/mod.rs +++ /dev/null @@ -1,101 +0,0 @@ -pub mod pow; -pub mod ternary; - -use crate::kw; - -use self::pow::PowOps; - -use super::binops::ternary::Ternary; -use syn::{parse::Parse, Error, Token}; - -#[derive(Debug, Clone)] -pub enum Binop { - Assign(Token![=]), - Add(Token![+]), - AddAssign(Token![+=]), - Minus(Token![-]), - MinusAssign(Token![-=]), - Mul(Token![*]), - MulAssign(Token![*=]), - Not(Token![!]), - BitNot(Token![~]), - Div(Token![/]), - DivAssign(Token![/=]), - Mod(Token![%]), - ModAssign(Token![%=]), - BitAnd(Token![&]), - AndAssign(Token![&=]), - BitXor(Token![^]), - XorAssign(Token![^=]), - BitOr(Token![|]), - BitOrAssign(Token![|=]), - Shl(Token![<<]), - ShlAssign(Token![<<=]), - Shr(Token![>>]), - ShrAssign(Token![>>=]), - Equality(Token![==]), - And(Token![&&]), - Or(Token![||]), - Ternary(Ternary), - // don't have in rust but swag - Exponent(PowOps), - Delete(kw::delete), -} - -impl Parse for Binop { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { - if input.peek(Token![=]) { - Ok(Self::Assign(input.parse()?)) - } else if input.peek(Token![~]) { - Ok(Self::BitNot(input.parse()?)) - } else if input.peek(Token![==]) { - Ok(Self::Equality(input.parse()?)) - } else if input.peek(Token![+]) { - Ok(Self::Add(input.parse()?)) - } else if input.peek(Token![+=]) { - Ok(Self::AddAssign(input.parse()?)) - } else if input.peek(Token![-]) { - Ok(Self::Minus(input.parse()?)) - } else if input.peek(Token![-=]) { - Ok(Self::MinusAssign(input.parse()?)) - } else if input.peek(Token![*]) { - Ok(Self::Mul(input.parse()?)) - } else if input.peek(Token![*=]) { - Ok(Self::MulAssign(input.parse()?)) - } else if input.peek(Token![/]) { - Ok(Self::Div(input.parse()?)) - } else if input.peek(Token![/=]) { - Ok(Self::DivAssign(input.parse()?)) - } else if input.peek(Token![%]) { - Ok(Self::Mod(input.parse()?)) - } else if input.peek(Token![%=]) { - Ok(Self::ModAssign(input.parse()?)) - } else if input.peek(Token![&]) { - Ok(Self::BitAnd(input.parse()?)) - } else if input.peek(Token![&=]) { - Ok(Self::AndAssign(input.parse()?)) - } else if input.peek(Token![^]) { - Ok(Self::BitXor(input.parse()?)) - } else if input.peek(Token![^=]) { - Ok(Self::XorAssign(input.parse()?)) - } else if input.peek(Token![|]) { - Ok(Self::BitOr(input.parse()?)) - } else if input.peek(Token![|=]) { - Ok(Self::BitOrAssign(input.parse()?)) - } else if input.peek(Token![<<]) { - Ok(Self::Shl(input.parse()?)) - } else if input.peek(Token![<<=]) { - Ok(Self::ShlAssign(input.parse()?)) - } else if input.peek(Token![>>]) { - Ok(Self::Shr(input.parse()?)) - } else if input.peek(Token![>>=]) { - Ok(Self::ShrAssign(input.parse()?)) - } else if input.peek(Token![&&]) { - Ok(Self::And(input.parse()?)) - } else if input.peek(Token![||]) { - Ok(Self::Or(input.parse()?)) - } else { - Err(Error::new(input.span(), "failed to parse binop")) - } - } -} diff --git a/crates/syn-solidity/src/stmt/binops/pow.rs b/crates/syn-solidity/src/stmt/binops/pow.rs deleted file mode 100644 index 61b5a608c4..0000000000 --- a/crates/syn-solidity/src/stmt/binops/pow.rs +++ /dev/null @@ -1,17 +0,0 @@ -use syn::{parse::Parse, Token}; - -/// def not right way todo this but we ballin -#[derive(Debug, Clone)] -pub struct PowOps { - pub star0: Token!(*), - pub star1: Token!(*), -} - -impl Parse for PowOps { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { - Ok(Self { - star0: input.parse()?, - star1: input.parse()?, - }) - } -} diff --git a/crates/syn-solidity/src/stmt/binops/ternary.rs b/crates/syn-solidity/src/stmt/binops/ternary.rs deleted file mode 100644 index 529ff66c97..0000000000 --- a/crates/syn-solidity/src/stmt/binops/ternary.rs +++ /dev/null @@ -1,29 +0,0 @@ -use crate::expr::Expr; -use syn::{parse::Parse, Token}; - -#[derive(Debug, Clone)] -pub struct Ternary { - pub var1: Box, - pub q: Token![?], - pub res_0: Box, - pub semi: Token![;], - pub res_1: Box, -} - -impl Parse for Ternary { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { - let var1 = Box::new(input.parse()?); - let q = input.parse()?; - let res_0 = Box::new(input.parse()?); - let semi = input.parse()?; - let res_1 = Box::new(input.parse()?); - - Ok(Self { - res_1, - semi, - res_0, - var1, - q, - }) - } -} diff --git a/crates/syn-solidity/src/stmt/block.rs b/crates/syn-solidity/src/stmt/block.rs deleted file mode 100644 index f9a84cc17d..0000000000 --- a/crates/syn-solidity/src/stmt/block.rs +++ /dev/null @@ -1,36 +0,0 @@ -use crate::Stmt; -use std::fmt; -use syn::{ - parse::{Parse, ParseStream}, - token::Brace, - Result, -}; - -/// A curly-braced block of statements. -#[derive(Clone)] -pub struct Block { - pub brace_token: Brace, - pub stmts: Vec, -} - -impl fmt::Debug for Block { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("Block").field(&self.stmts).finish() - } -} - -impl Parse for Block { - fn parse(input: ParseStream<'_>) -> Result { - let content; - Ok(Self { - brace_token: syn::braced!(content in input), - stmts: { - let mut stmts = Vec::new(); - while !content.is_empty() { - stmts.push(content.parse()?); - } - stmts - }, - }) - } -} diff --git a/crates/syn-solidity/src/stmt/blocks.rs b/crates/syn-solidity/src/stmt/blocks.rs new file mode 100644 index 0000000000..5585bcc2ee --- /dev/null +++ b/crates/syn-solidity/src/stmt/blocks.rs @@ -0,0 +1,76 @@ +use crate::{kw, Stmt}; +use proc_macro2::Span; +use std::fmt; +use syn::{ + parse::{Parse, ParseStream}, + token::Brace, + Result, +}; + +/// A curly-braced block of statements. +#[derive(Clone)] +pub struct Block { + pub brace_token: Brace, + pub stmts: Vec, +} + +impl fmt::Debug for Block { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("Block").field(&self.stmts).finish() + } +} + +impl Parse for Block { + fn parse(input: ParseStream<'_>) -> Result { + let content; + Ok(Self { + brace_token: syn::braced!(content in input), + stmts: crate::utils::parse_vec(&content, true)?, + }) + } +} + +impl Block { + pub fn span(&self) -> Span { + self.brace_token.span.join() + } + + pub fn set_span(&mut self, span: Span) { + self.brace_token = Brace(span); + } +} + +#[derive(Clone)] +pub struct UncheckedBlock { + pub unchecked_token: kw::unchecked, + pub block: Block, +} + +impl fmt::Debug for UncheckedBlock { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("UncheckedBlock") + .field("stmts", &self.block.stmts) + .finish() + } +} + +impl Parse for UncheckedBlock { + fn parse(input: ParseStream<'_>) -> Result { + Ok(Self { + unchecked_token: input.parse()?, + block: input.parse()?, + }) + } +} + +impl UncheckedBlock { + pub fn span(&self) -> Span { + let span = self.unchecked_token.span; + span.join(self.block.span()).unwrap_or(span) + } + + pub fn set_span(&mut self, span: Span) { + self.unchecked_token.span = span; + self.block.set_span(span); + } +} diff --git a/crates/syn-solidity/src/stmt/break.rs b/crates/syn-solidity/src/stmt/break.rs new file mode 100644 index 0000000000..649d50d055 --- /dev/null +++ b/crates/syn-solidity/src/stmt/break.rs @@ -0,0 +1,43 @@ +use proc_macro2::Span; +use std::fmt; +use syn::{ + parse::{Parse, ParseStream}, + Result, Token, +}; + +/// A break statement: `break;` +/// +/// Solidity Reference: +/// +#[derive(Clone)] +pub struct StmtBreak { + pub break_token: Token![break], + pub semi_token: Token![;], +} + +impl fmt::Debug for StmtBreak { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("StmtBreak").finish() + } +} + +impl Parse for StmtBreak { + fn parse(input: ParseStream<'_>) -> Result { + Ok(Self { + break_token: input.parse()?, + semi_token: input.parse()?, + }) + } +} + +impl StmtBreak { + pub fn span(&self) -> Span { + let span = self.break_token.span; + span.join(self.semi_token.span).unwrap_or(span) + } + + pub fn set_span(&mut self, span: Span) { + self.break_token.span = span; + self.semi_token.span = span; + } +} diff --git a/crates/syn-solidity/src/stmt/call_args.rs b/crates/syn-solidity/src/stmt/call_args.rs deleted file mode 100644 index 2ec471a67d..0000000000 --- a/crates/syn-solidity/src/stmt/call_args.rs +++ /dev/null @@ -1,71 +0,0 @@ -use syn::{ - parse::Parse, - punctuated::Punctuated, - token::{Brace, Paren}, - Error, Ident, Token, -}; - -use crate::expr::Stmt; - -#[derive(Debug, Clone)] -pub enum CallArgs { - Map(MapArgs), - List(ListArgs), -} - -#[derive(Debug, Clone)] -pub struct ListArgs(pub Punctuated); - -#[derive(Debug, Clone)] -pub struct MapArgs(pub Punctuated); - -#[derive(Debug, Clone)] -pub struct Map { - pub key: Ident, - pub semi: Token![:], - pub value: Box, -} - -impl Parse for CallArgs { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { - if input.peek2(Brace) { - Ok(Self::Map(input.parse()?)) - } else if input.peek(Paren) { - Ok(Self::List(input.parse()?)) - } else { - Err(Error::new(input.span(), "invalid call args")) - } - } -} -impl Parse for MapArgs { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { - let mut map = Punctuated::new(); - while input.peek2(Token![:]) { - let entry = input.parse()?; - map.push(entry); - } - - Ok(Self(map)) - } -} - -impl Parse for Map { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { - Ok(Self { - key: input.parse()?, - semi: input.parse()?, - value: input.parse()?, - }) - } -} - -impl Parse for ListArgs { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { - let mut list = Punctuated::new(); - while input.peek(Token![,]) { - list.push(input.parse()?); - } - list.push(input.parse()?); - Ok(Self(list)) - } -} diff --git a/crates/syn-solidity/src/stmt/continue.rs b/crates/syn-solidity/src/stmt/continue.rs new file mode 100644 index 0000000000..6fa4562bef --- /dev/null +++ b/crates/syn-solidity/src/stmt/continue.rs @@ -0,0 +1,43 @@ +use proc_macro2::Span; +use std::fmt; +use syn::{ + parse::{Parse, ParseStream}, + Result, Token, +}; + +/// A continue statement: `continue;` +/// +/// Solidity Reference: +/// +#[derive(Clone)] +pub struct StmtContinue { + pub continue_token: Token![continue], + pub semi_token: Token![;], +} + +impl fmt::Debug for StmtContinue { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("StmtContinue").finish() + } +} + +impl Parse for StmtContinue { + fn parse(input: ParseStream<'_>) -> Result { + Ok(Self { + continue_token: input.parse()?, + semi_token: input.parse()?, + }) + } +} + +impl StmtContinue { + pub fn span(&self) -> Span { + let span = self.continue_token.span; + span.join(self.semi_token.span).unwrap_or(span) + } + + pub fn set_span(&mut self, span: Span) { + self.continue_token.span = span; + self.semi_token.span = span; + } +} diff --git a/crates/syn-solidity/src/stmt/do_while.rs b/crates/syn-solidity/src/stmt/do_while.rs new file mode 100644 index 0000000000..707f4b70d2 --- /dev/null +++ b/crates/syn-solidity/src/stmt/do_while.rs @@ -0,0 +1,57 @@ +use crate::{Expr, Stmt}; +use proc_macro2::Span; +use std::fmt; +use syn::{ + parse::{Parse, ParseStream}, + token::Paren, + Result, Token, +}; + +/// A do-while statement: `do { ... } while (condition);` +/// +/// Solidity Reference: +/// +#[derive(Clone)] +pub struct StmtDoWhile { + pub do_token: Token![do], + pub body: Box, + pub while_token: Token![while], + pub paren_token: Paren, + pub cond: Expr, + pub semi_token: Token![;], +} + +impl fmt::Debug for StmtDoWhile { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("DoWhile") + .field("body", &self.body) + .field("condition", &self.cond) + .finish() + } +} + +impl Parse for StmtDoWhile { + fn parse(input: ParseStream<'_>) -> Result { + let content; + Ok(Self { + do_token: input.parse()?, + body: input.parse()?, + while_token: input.parse()?, + paren_token: syn::parenthesized!(content in input), + cond: content.parse()?, + semi_token: input.parse()?, + }) + } +} + +impl StmtDoWhile { + pub fn span(&self) -> Span { + let span = self.do_token.span; + span.join(self.semi_token.span).unwrap_or(span) + } + + pub fn set_span(&mut self, span: Span) { + self.do_token.span = span; + self.semi_token.span = span; + } +} diff --git a/crates/syn-solidity/src/stmt/emit.rs b/crates/syn-solidity/src/stmt/emit.rs index ee06bf24b8..08398447f3 100644 --- a/crates/syn-solidity/src/stmt/emit.rs +++ b/crates/syn-solidity/src/stmt/emit.rs @@ -1,21 +1,51 @@ -use crate::{call_args::CallArgs, expr::Stmt, kw}; -use syn::{parse::Parse, Token}; +use crate::{kw, CallArgumentList, Expr}; +use proc_macro2::Span; +use std::fmt; +use syn::{ + parse::{Parse, ParseStream}, + Result, Token, +}; -#[derive(Debug, Clone)] -pub struct Emit { - keyword: kw::emit, - expr: Box, - args: CallArgs, - semi: Token!(;), +/// An emit statement: `emit FooBar(42);` +/// +/// Solidity Reference: +/// +#[derive(Clone)] +pub struct StmtEmit { + pub emit_token: kw::emit, + pub expr: Expr, + pub list: CallArgumentList, + pub semi_token: Token![;], } -impl Parse for Emit { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { +impl fmt::Debug for StmtEmit { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("StmtEmit") + .field("expr", &self.expr) + .field("list", &self.list) + .finish() + } +} + +impl Parse for StmtEmit { + fn parse(input: ParseStream<'_>) -> Result { Ok(Self { - keyword: input.parse()?, - expr: Box::new(input.parse()?), - args: input.parse()?, - semi: input.parse()?, + emit_token: input.parse()?, + expr: input.parse()?, + list: input.parse()?, + semi_token: input.parse()?, }) } } + +impl StmtEmit { + pub fn span(&self) -> Span { + let span = self.emit_token.span; + span.join(self.semi_token.span).unwrap_or(span) + } + + pub fn set_span(&mut self, span: Span) { + self.emit_token.span = span; + self.semi_token.span = span; + } +} diff --git a/crates/syn-solidity/src/stmt/expr.rs b/crates/syn-solidity/src/stmt/expr.rs index a14ce98d59..67a92008c7 100644 --- a/crates/syn-solidity/src/stmt/expr.rs +++ b/crates/syn-solidity/src/stmt/expr.rs @@ -1,122 +1,42 @@ -use crate::{ - assembly::Assembly, - binop::BinopExpr, - emit::Emit, - index::Index, - inline_array_expr::InlineArrayExpr, - kw, - literals::lits::Literals, - loop_ops::LoopOps, - method_call::MethodCall, - new::New, - r#for::ForStmt, - r#if::IfStmt, - r#return::Return, - r#while::{DoWhile, While}, - revert::Revert, - tuple_expr::TupleExpr, - unchecked::Unchecked, - Block, -}; - +use crate::Expr; +use proc_macro2::Span; +use std::fmt; use syn::{ - parse::Parse, - token::{Brace, Bracket, Paren}, - Ident, LitBool, LitInt, LitStr, Token, + parse::{Parse, ParseStream}, + Result, Token, }; -#[derive(Clone, Debug)] -pub enum Stmt { - Block(Block), - While(While), - DoWhile(DoWhile), - If(IfStmt), - ForLoop(ForStmt), - LoopOps(LoopOps), - Index(Index), - Binop(BinopExpr), - MethodCall(MethodCall), - Return(Return), - Emit(Emit), - Unchecked(Unchecked), - Revert(Revert), - Tuple(TupleExpr), - InlineArray(InlineArrayExpr), - New(New), - Lit(Literals), - Assembly(Assembly), +#[derive(Clone)] +pub struct StmtExpr { + pub expr: Expr, + pub semi_token: Token![;], +} + +impl fmt::Debug for StmtExpr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("StmtExpr") + .field("expr", &self.expr) + .finish() + } +} + +impl Parse for StmtExpr { + fn parse(input: ParseStream<'_>) -> Result { + Ok(Self { + expr: input.parse()?, + semi_token: input.parse()?, + }) + } } -impl Parse for Stmt { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { - if input.peek(Token![while]) { - return Ok(Self::While(While::parse(input)?)) - // this prob wrong lol - } else if input.peek(Brace) { - return Ok(Self::Block(Block::parse(input)?)) - } else if input.peek(Token![do]) { - return Ok(Self::DoWhile(DoWhile::parse(input)?)) - } else if input.peek(Token![if]) { - return Ok(Self::If(IfStmt::parse(input)?)) - } else if input.peek(Token![for]) { - return Ok(Self::ForLoop(ForStmt::parse(input)?)) - } else if input.peek(Ident) && input.peek2(Bracket) { - return Ok(Self::Index(Index::parse(input)?)) - } else if input.peek(Ident) && input.peek2(Paren) { - return Ok(Self::MethodCall(MethodCall::parse(input)?)) - // so jank feel like should be better way but just send it ig - } else if input.peek(Token![!]) - || input.peek(Token![~]) - || input.peek2(Token!(=)) - || input.peek2(Token!(+)) - || input.peek2(Token!(+=)) - || input.peek2(Token!(-)) - || input.peek2(Token!(-=)) - || input.peek2(Token!(*)) - || input.peek2(Token!(*=)) - || input.peek2(Token!(/)) - || input.peek2(Token!(/=)) - || input.peek2(Token!(%)) - || input.peek2(Token!(%=)) - || input.peek2(Token!(&)) - || input.peek2(Token!(&=)) - || input.peek2(Token!(^)) - || input.peek2(Token!(^=)) - || input.peek2(Token!(|)) - || input.peek2(Token!(<<)) - || input.peek2(Token!(<<=)) - || input.peek2(Token!(>>)) - || input.peek2(Token!(>>=)) - || input.peek2(Token!(==)) - || input.peek2(Token!(&&)) - || input.peek2(Token!(||)) - { - return Ok(Self::Binop(BinopExpr::parse(input)?)) - } else if input.peek(kw::emit) { - Ok(Self::Emit(Emit::parse(input)?)) - } else if input.peek(kw::returns) { - Ok(Self::Return(Return::parse(input)?)) - } else if input.peek(kw::unchecked) { - Ok(Self::Unchecked(Unchecked::parse(input)?)) - } else if input.peek(kw::revert) { - Ok(Self::Revert(Revert::parse(input)?)) - } else if input.peek(Paren) && input.peek3(Token!(,)) { - Ok(Self::Tuple(TupleExpr::parse(input)?)) - } else if input.peek(Ident) && input.peek2(Paren) { - Ok(Self::MethodCall(MethodCall::parse(input)?)) - } else if input.peek(Bracket) { - Ok(Self::InlineArray(InlineArrayExpr::parse(input)?)) - } else if input.peek(kw::new) { - Ok(Self::New(New::parse(input)?)) - } else if input.peek(kw::assembly) { - Ok(Self::Assembly(Assembly::parse(input)?)) - } else if input.peek(LitBool) || input.peek(LitStr) || input.peek(LitInt) { - Ok(Self::Lit(Literals::parse(input)?)) - } else { - Err(syn::Error::new( - input.span(), - format!("{:?} Path not implimented", input), - )) - } +impl StmtExpr { + pub fn span(&self) -> Span { + let span = self.expr.span(); + span.join(self.semi_token.span).unwrap_or(span) + } + + pub fn set_span(&mut self, span: Span) { + self.expr.set_span(span); + self.semi_token.span = span; } } diff --git a/crates/syn-solidity/src/stmt/field.rs b/crates/syn-solidity/src/stmt/field.rs deleted file mode 100644 index 781c095e88..0000000000 --- a/crates/syn-solidity/src/stmt/field.rs +++ /dev/null @@ -1,20 +0,0 @@ -use crate::expr::Stmt; -use proc_macro2::Ident; -use syn::{parse::Parse, Token}; - -#[derive(Debug, Clone)] -pub struct Field { - pub base: Box, - pub dot: Token![.], - pub name: Ident, -} - -impl Parse for Field { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { - Ok(Self { - base: input.parse()?, - dot: input.parse()?, - name: input.parse()?, - }) - } -} diff --git a/crates/syn-solidity/src/stmt/for.rs b/crates/syn-solidity/src/stmt/for.rs index e7634ff607..12a2df91e8 100644 --- a/crates/syn-solidity/src/stmt/for.rs +++ b/crates/syn-solidity/src/stmt/for.rs @@ -1,43 +1,65 @@ -use crate::{binop::BinopExpr, expr::Stmt, Block}; -use syn::{parenthesized, parse::Parse, token::Paren, Token}; +use crate::{Expr, Stmt, StmtExpr, StmtVarDecl}; +use proc_macro2::Span; +use std::fmt; +use syn::{ + parse::{Parse, ParseStream}, + token::Paren, + Result, Token, +}; -#[derive(Debug, Clone)] -pub struct ForStmt { +/// A for statement: `for (uint256 i; i < 42; ++i) { ... }` +/// +/// Solidity Reference: +/// +#[derive(Clone)] +pub struct StmtFor { pub for_token: Token![for], - pub for_assign: ForAssignment, + pub paren_token: Paren, + pub init: Option, + pub semi_token1: Token![;], + pub cond: Option, + pub semi_token2: Token![;], + pub post: Option, + pub body: Box, } -#[derive(Debug, Clone)] -pub struct ForAssignment { - pub brace: Paren, - pub iter_asign: BinopExpr, - pub semi: Token![;], - pub cond: Box, - pub semi2: Token![;], - pub up_cond: Option>, - pub block: Block, +impl fmt::Debug for StmtFor { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("StmtFor") + .field("init", &self.init) + .field("cond", &self.cond) + .field("post", &self.post) + .field("body", &self.body) + .finish() + } +} + +impl Parse for StmtFor { + fn parse(_input: ParseStream<'_>) -> Result { + todo!() + } } -impl Parse for ForStmt { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { - Ok(Self { - for_token: input.parse()?, - for_assign: input.parse()?, - }) +impl StmtFor { + pub fn span(&self) -> Span { + let span = self.for_token.span; + span.join(self.body.span()).unwrap_or(span) } + + pub fn set_span(&mut self, span: Span) { + self.for_token.span = span; + self.body.set_span(span); + } +} + +#[derive(Clone, Debug)] +pub enum ForInitStmt { + VarDecl(StmtVarDecl), + Expression(StmtExpr), } -impl Parse for ForAssignment { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { - let content; - Ok(Self { - brace: parenthesized!(content in input), - iter_asign: input.parse()?, - semi: input.parse()?, - cond: Box::new(input.parse()?), - semi2: input.parse()?, - up_cond: input.parse().ok(), - block: input.parse()?, - }) +impl Parse for ForInitStmt { + fn parse(_input: ParseStream<'_>) -> Result { + todo!() } } diff --git a/crates/syn-solidity/src/stmt/if.rs b/crates/syn-solidity/src/stmt/if.rs index 627d50083b..b29bec9111 100644 --- a/crates/syn-solidity/src/stmt/if.rs +++ b/crates/syn-solidity/src/stmt/if.rs @@ -1,49 +1,63 @@ -use syn::{parse::Parse, Token}; +use crate::{Block, Expr, Stmt}; +use proc_macro2::Span; +use std::fmt; +use syn::{ + parse::{Parse, ParseStream}, + token::Paren, + Result, Token, +}; -use crate::Block; - -#[derive(Debug, Clone)] -pub enum IfStmtType { - ElseIf, - Else, +#[derive(Clone)] +pub struct StmtIf { + pub if_token: Token![if], + pub paren_token: Paren, + pub cond: Expr, + pub then_branch: Block, + pub else_branch: Option<(Token![else], Box)>, } -#[derive(Debug, Clone)] -pub struct IfStmt { - pub init: Token![if], - pub optional_stmts: Vec, - pub expr: Block, +impl fmt::Debug for StmtIf { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("StmtIf") + .field("cond", &self.cond) + .field("then_branch", &self.then_branch) + .field("else_branch", &self.else_branch) + .finish() + } } -impl Parse for IfStmtType { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { - if input.peek2(Token!(if)) { - Ok(Self::ElseIf) - } else if input.peek(Token![else]) { - Ok(Self::Else) - } else { - Err(syn::Error::new( - input.span(), - "secondary control flow parsing failed", - )) - } +impl Parse for StmtIf { + fn parse(input: ParseStream<'_>) -> Result { + let content; + Ok(Self { + if_token: input.parse()?, + paren_token: syn::parenthesized!(content in input), + cond: content.parse()?, + then_branch: input.parse()?, + else_branch: if input.peek(Token![else]) { + Some((input.parse()?, input.parse()?)) + } else { + None + }, + }) } } -impl Parse for IfStmt { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { - let init = input.parse()?; - let mut optional = Vec::new(); - // this wrong - let fork = input.fork(); - while let Ok(stmt) = fork.parse::() { - optional.push(stmt); - } +impl StmtIf { + pub fn span(&self) -> Span { + let span = self.if_token.span; + self.else_branch + .as_ref() + .and_then(|(_, stmt)| stmt.span().join(span)) + .or_else(|| span.join(self.then_branch.span())) + .unwrap_or(span) + } - Ok(Self { - init, - optional_stmts: optional, - expr: input.parse()?, - }) + pub fn set_span(&mut self, span: Span) { + self.if_token.span = span; + self.then_branch.set_span(span); + if let Some((_, stmt)) = &mut self.else_branch { + stmt.set_span(span); + } } } diff --git a/crates/syn-solidity/src/stmt/index.rs b/crates/syn-solidity/src/stmt/index.rs deleted file mode 100644 index a235927341..0000000000 --- a/crates/syn-solidity/src/stmt/index.rs +++ /dev/null @@ -1,22 +0,0 @@ -use proc_macro2::Ident; -use syn::{bracketed, parse::Parse, token::Bracket}; - -use crate::expr::Stmt; - -#[derive(Debug, Clone)] -pub struct Index { - pub name: Ident, - pub bracket: Bracket, - pub index_by: Box, -} - -impl Parse for Index { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { - let content; - Ok(Self { - name: input.parse()?, - bracket: bracketed!(content in input), - index_by: input.parse()?, - }) - } -} diff --git a/crates/syn-solidity/src/stmt/inline_array_expr.rs b/crates/syn-solidity/src/stmt/inline_array_expr.rs deleted file mode 100644 index 5d5bbff1e4..0000000000 --- a/crates/syn-solidity/src/stmt/inline_array_expr.rs +++ /dev/null @@ -1,24 +0,0 @@ -use crate::expr::Stmt; -use syn::{bracketed, parse::Parse, punctuated::Punctuated, token::Bracket, Token}; - -#[derive(Debug, Clone)] -pub struct InlineArrayExpr { - bracket: Bracket, - exprs: Punctuated, -} - -impl Parse for InlineArrayExpr { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { - let content; - let bracket = bracketed!(content in input); - - let mut exprs = Punctuated::new(); - exprs.push(input.parse()?); - while input.peek(Token![,]) { - exprs.push(input.parse()?); - } - exprs.push(input.parse()?); - - Ok(Self { exprs, bracket }) - } -} diff --git a/crates/syn-solidity/src/stmt/loop_ops.rs b/crates/syn-solidity/src/stmt/loop_ops.rs deleted file mode 100644 index 4fe500e659..0000000000 --- a/crates/syn-solidity/src/stmt/loop_ops.rs +++ /dev/null @@ -1,31 +0,0 @@ -use syn::{parse::Parse, Error, Token}; - -#[derive(Debug, Clone, Copy)] -pub enum LoopOps { - Continue { - kw: Token!(continue), - semi: Token!(;), - }, - Break { - kw: Token!(break), - semi: Token!(;), - }, -} - -impl Parse for LoopOps { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { - if input.peek(Token![continue]) { - Ok(Self::Continue { - kw: input.parse()?, - semi: input.parse()?, - }) - } else if input.peek(Token![break]) { - Ok(Self::Break { - kw: input.parse()?, - semi: input.parse()?, - }) - } else { - Err(Error::new(input.span(), "failed to match on loop op")) - } - } -} diff --git a/crates/syn-solidity/src/stmt/method_call.rs b/crates/syn-solidity/src/stmt/method_call.rs deleted file mode 100644 index 84a7bd6394..0000000000 --- a/crates/syn-solidity/src/stmt/method_call.rs +++ /dev/null @@ -1,29 +0,0 @@ -use proc_macro2::Ident; - -use crate::{Parameters, VariableDeclaration}; -use syn::{parenthesized, parse::Parse, token::Paren, Token}; - -#[derive(Debug, Clone)] -pub struct MethodCall { - pub fn_name: Ident, - pub paren_token: Paren, - pub arguments: Parameters, -} - -impl Parse for MethodCall { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { - let content; - let fn_name = input.parse()?; - let paren = parenthesized!(content in input); - let mut args = Parameters::new(); - while let Ok(arg) = input.parse::() { - args.push(arg); - } - - Ok(Self { - fn_name, - paren_token: paren, - arguments: args, - }) - } -} diff --git a/crates/syn-solidity/src/stmt/mod.rs b/crates/syn-solidity/src/stmt/mod.rs index d7418f63fd..17ee7a78c8 100644 --- a/crates/syn-solidity/src/stmt/mod.rs +++ b/crates/syn-solidity/src/stmt/mod.rs @@ -1,25 +1,171 @@ -pub mod assembly; -pub mod binop; -pub mod binops; -pub mod call_args; -pub mod emit; -pub mod expr; -pub mod field; -pub mod r#for; -pub mod r#if; -pub mod index; -pub mod inline_array_expr; -pub mod loop_ops; -pub mod method_call; -pub mod new; -pub mod r#return; -pub mod revert; -pub mod try_catch; -pub mod tuple_expr; -pub mod unchecked; -pub mod r#while; - -mod block; -pub use block::Block; - -pub use expr::Stmt; +mod assembly; +pub use assembly::StmtAssembly; + +mod blocks; +pub use blocks::{Block, UncheckedBlock}; + +mod r#break; +pub use r#break::StmtBreak; + +mod r#continue; +pub use r#continue::StmtContinue; + +mod do_while; +pub use do_while::StmtDoWhile; + +mod emit; +pub use emit::StmtEmit; + +mod expr; +pub use expr::StmtExpr; + +mod r#for; +pub use r#for::StmtFor; + +mod r#if; +pub use r#if::StmtIf; + +mod r#return; +pub use r#return::StmtReturn; + +mod revert; +pub use revert::StmtRevert; + +mod r#try; +pub use r#try::StmtTry; + +mod var_decl; +pub use var_decl::StmtVarDecl; + +mod r#while; +pub use r#while::StmtWhile; + +use crate::kw; +use proc_macro2::Span; +use syn::{ + parse::{discouraged::Speculative, Parse, ParseStream}, + token::{Brace, Paren}, + Result, Token, +}; + +/// A statement. +/// +/// Solidity reference: +/// +#[derive(Clone, Debug)] +pub enum Stmt { + Block(Block), + UncheckedBlock(UncheckedBlock), + VarDecl(StmtVarDecl), + Expr(StmtExpr), + If(StmtIf), + For(StmtFor), + While(StmtWhile), + DoWhile(StmtDoWhile), + Continue(StmtContinue), + Break(StmtBreak), + Try(StmtTry), + Return(StmtReturn), + Emit(StmtEmit), + Revert(StmtRevert), + Assembly(StmtAssembly), +} + +impl Parse for Stmt { + fn parse(input: ParseStream<'_>) -> Result { + let lookahead = input.lookahead1(); + if lookahead.peek(Brace) { + input.parse().map(Self::Block) + } else if lookahead.peek(Paren) { + if input.peek2(Token![=]) { + input.parse().map(Self::VarDecl) + } else { + input.parse().map(Self::Expr) + } + } else if lookahead.peek(kw::unchecked) { + input.parse().map(Self::UncheckedBlock) + } else if lookahead.peek(Token![if]) { + input.parse().map(Self::If) + } else if lookahead.peek(Token![for]) { + input.parse().map(Self::For) + } else if lookahead.peek(Token![while]) { + input.parse().map(Self::While) + } else if lookahead.peek(Token![do]) { + input.parse().map(Self::DoWhile) + } else if lookahead.peek(Token![continue]) { + input.parse().map(Self::Continue) + } else if lookahead.peek(Token![break]) { + input.parse().map(Self::Break) + } else if lookahead.peek(Token![try]) { + input.parse().map(Self::Try) + } else if lookahead.peek(Token![return]) { + input.parse().map(Self::Return) + } else if lookahead.peek(kw::emit) { + input.parse().map(Self::Emit) + } else if lookahead.peek(kw::revert) { + input.parse().map(Self::Revert) + } else if lookahead.peek(kw::assembly) { + input.parse().map(Self::Assembly) + } else if lookahead.peek(kw::tuple) + || lookahead.peek(kw::function) + || lookahead.peek(kw::mapping) + { + input.parse().map(Self::VarDecl) + } else { + // TODO: Handle this better + let start = input.fork(); + match input.parse() { + Ok(var) => Ok(Self::VarDecl(var)), + Err(_) => match start.parse() { + Ok(expr) => { + input.advance_to(&start); + Ok(Self::Expr(expr)) + } + Err(_) => Err(lookahead.error()), + }, + } + } + } +} + +impl Stmt { + pub fn span(&self) -> Span { + match self { + Stmt::Block(block) => block.span(), + Stmt::UncheckedBlock(block) => block.span(), + Stmt::VarDecl(stmt) => stmt.span(), + Stmt::Expr(stmt) => stmt.span(), + Stmt::If(stmt) => stmt.span(), + Stmt::For(stmt) => stmt.span(), + Stmt::While(stmt) => stmt.span(), + Stmt::DoWhile(stmt) => stmt.span(), + Stmt::Continue(stmt) => stmt.span(), + Stmt::Break(stmt) => stmt.span(), + Stmt::Try(stmt) => stmt.span(), + Stmt::Return(stmt) => stmt.span(), + Stmt::Emit(stmt) => stmt.span(), + Stmt::Revert(stmt) => stmt.span(), + Stmt::Assembly(stmt) => stmt.span(), + } + } + + pub fn set_span(&mut self, span: Span) { + match self { + Stmt::Block(block) => block.set_span(span), + Stmt::UncheckedBlock(block) => block.set_span(span), + Stmt::VarDecl(stmt) => stmt.set_span(span), + Stmt::Expr(stmt) => stmt.set_span(span), + Stmt::If(stmt) => stmt.set_span(span), + Stmt::For(stmt) => stmt.set_span(span), + Stmt::While(stmt) => stmt.set_span(span), + Stmt::DoWhile(stmt) => stmt.set_span(span), + Stmt::Continue(stmt) => stmt.set_span(span), + Stmt::Break(stmt) => stmt.set_span(span), + Stmt::Try(stmt) => stmt.set_span(span), + Stmt::Return(stmt) => stmt.set_span(span), + Stmt::Emit(stmt) => stmt.set_span(span), + Stmt::Revert(stmt) => stmt.set_span(span), + Stmt::Assembly(stmt) => stmt.set_span(span), + } + } +} diff --git a/crates/syn-solidity/src/stmt/new.rs b/crates/syn-solidity/src/stmt/new.rs deleted file mode 100644 index 11cbc86fa7..0000000000 --- a/crates/syn-solidity/src/stmt/new.rs +++ /dev/null @@ -1,17 +0,0 @@ -use crate::{kw, Type}; -use syn::parse::Parse; - -#[derive(Debug, Clone)] -pub struct New { - new_token: kw::new, - ty: Type, -} - -impl Parse for New { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { - Ok(Self { - new_token: input.parse()?, - ty: input.parse()?, - }) - } -} diff --git a/crates/syn-solidity/src/stmt/return.rs b/crates/syn-solidity/src/stmt/return.rs index 5d228b7367..a31c9b66f8 100644 --- a/crates/syn-solidity/src/stmt/return.rs +++ b/crates/syn-solidity/src/stmt/return.rs @@ -1,19 +1,52 @@ -use crate::expr::Stmt; -use syn::{parse::Parse, Token}; +use crate::Expr; +use proc_macro2::Span; +use std::fmt; +use syn::{ + parse::{Parse, ParseStream}, + Result, Token, +}; -#[derive(Debug, Clone)] -pub struct Return { - token: Token![return], - expr: Box, - semi: Token![;], +/// A return statement: `return 42;` +/// +/// Solidity Reference: +/// +#[derive(Clone)] +pub struct StmtReturn { + pub return_token: Token![return], + pub expr: Option, + pub semi_token: Token![;], } -impl Parse for Return { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { +impl fmt::Debug for StmtReturn { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("StmtReturn") + .field("expr", &self.expr) + .finish() + } +} + +impl Parse for StmtReturn { + fn parse(input: ParseStream<'_>) -> Result { Ok(Self { - token: input.parse()?, - expr: Box::new(input.parse()?), - semi: input.parse()?, + return_token: input.parse()?, + expr: if input.peek(Token![;]) { + None + } else { + Some(input.parse()?) + }, + semi_token: input.parse()?, }) } } + +impl StmtReturn { + pub fn span(&self) -> Span { + let span = self.return_token.span; + span.join(self.semi_token.span).unwrap_or(span) + } + + pub fn set_span(&mut self, span: Span) { + self.return_token.span = span; + self.semi_token.span = span; + } +} diff --git a/crates/syn-solidity/src/stmt/revert.rs b/crates/syn-solidity/src/stmt/revert.rs index 3d51629735..8195ad7934 100644 --- a/crates/syn-solidity/src/stmt/revert.rs +++ b/crates/syn-solidity/src/stmt/revert.rs @@ -1,21 +1,51 @@ -use crate::{call_args::CallArgs, expr::Stmt, kw}; -use syn::{parse::Parse, Token}; +use crate::{kw, CallArgumentList, Expr}; +use proc_macro2::Span; +use std::fmt; +use syn::{ + parse::{Parse, ParseStream}, + Result, Token, +}; -#[derive(Clone, Debug)] -pub struct Revert { - kw: kw::revert, - expr: Box, - args: CallArgs, - semi: Token![;], +/// A revert statement: `revert("error");` +/// +/// Solidity Reference: +/// +#[derive(Clone)] +pub struct StmtRevert { + pub revert_token: kw::revert, + pub expr: Expr, + pub list: CallArgumentList, + pub semi_token: Token![;], } -impl Parse for Revert { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { +impl fmt::Debug for StmtRevert { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("StmtRevert") + .field("expr", &self.expr) + .field("list", &self.list) + .finish() + } +} + +impl Parse for StmtRevert { + fn parse(input: ParseStream<'_>) -> Result { Ok(Self { - kw: input.parse()?, - expr: Box::new(input.parse()?), - args: input.parse()?, - semi: input.parse()?, + revert_token: input.parse()?, + expr: input.parse()?, + list: input.parse()?, + semi_token: input.parse()?, }) } } + +impl StmtRevert { + pub fn span(&self) -> Span { + let span = self.revert_token.span; + span.join(self.semi_token.span).unwrap_or(span) + } + + pub fn set_span(&mut self, span: Span) { + self.revert_token.span = span; + self.semi_token.span = span; + } +} diff --git a/crates/syn-solidity/src/stmt/try.rs b/crates/syn-solidity/src/stmt/try.rs new file mode 100644 index 0000000000..b5ce8388af --- /dev/null +++ b/crates/syn-solidity/src/stmt/try.rs @@ -0,0 +1,121 @@ +use crate::{kw, Block, Expr, ParameterList, Returns, SolIdent}; +use proc_macro2::Span; +use std::fmt; +use syn::{ + parenthesized, + parse::{Parse, ParseStream}, + token::Paren, + Result, Token, +}; + +/// A try statement: `try fooBar(42) catch { ... }` +/// +/// Solidity reference: +/// +#[derive(Clone)] +pub struct StmtTry { + pub try_token: Token![try], + pub expr: Expr, + pub returns: Option, + /// The try block. + pub block: Block, + /// The list of catch clauses. Cannot be parsed empty. + pub catch: Vec, +} + +impl fmt::Debug for StmtTry { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("StmtTry") + .field("expr", &self.expr) + .field("returns", &self.returns) + .field("block", &self.block) + .field("catch", &self.catch) + .finish() + } +} + +impl Parse for StmtTry { + fn parse(input: ParseStream<'_>) -> Result { + Ok(Self { + try_token: input.parse()?, + expr: input.parse()?, + returns: input.call(Returns::parse_opt)?, + block: input.parse()?, + catch: { + let mut catch = Vec::new(); + while input.peek(kw::catch) { + catch.push(input.parse()?); + } + catch + }, + }) + } +} + +impl StmtTry { + pub fn span(&self) -> Span { + let span = self.try_token.span; + span.join(self.block.span()).unwrap_or(span) + } + + pub fn set_span(&mut self, span: Span) { + self.try_token.span = span; + self.block.set_span(span); + } +} + +/// A catch clause of a [`StmtTry`]: `catch { ... }` +/// +/// Solidity reference: +/// +#[derive(Clone)] +pub struct CatchClause { + pub catch_token: kw::catch, + pub name: Option, + pub paren_token: Option, + pub list: ParameterList, + pub block: Block, +} + +impl fmt::Debug for CatchClause { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("CatchClause") + .field("name", &self.name) + .field("list", &self.list) + .field("block", &self.block) + .finish() + } +} + +impl Parse for CatchClause { + fn parse(input: ParseStream<'_>) -> Result { + let catch_token = input.parse()?; + let name = input.call(SolIdent::parse_opt)?; + let (paren_token, list) = if input.peek(Paren) { + let content; + (Some(parenthesized!(content in input)), content.parse()?) + } else { + (None, ParameterList::new()) + }; + let block = input.parse()?; + Ok(Self { + catch_token, + name, + paren_token, + list, + block, + }) + } +} + +impl CatchClause { + pub fn span(&self) -> Span { + let span = self.catch_token.span; + span.join(self.block.span()).unwrap_or(span) + } + + pub fn set_span(&mut self, span: Span) { + self.catch_token.span = span; + self.block.set_span(span); + } +} diff --git a/crates/syn-solidity/src/stmt/try_catch.rs b/crates/syn-solidity/src/stmt/try_catch.rs deleted file mode 100644 index ebe370b8e0..0000000000 --- a/crates/syn-solidity/src/stmt/try_catch.rs +++ /dev/null @@ -1,73 +0,0 @@ -use crate::{kw, Block, Parameters, VariableDeclaration}; -use syn::{parse::Parse, token::Paren, Token}; - -// annoying since there is 4 differnt types of error catching methods -#[derive(Debug, Clone)] -pub struct TryCatch { - pub r#try: Token![try], - pub block: Block, - pub catch: Catch, -} - -#[derive(Debug, Clone)] -pub struct Catch { - pub error: Option, - pub panic: Option, - // this is tech o - pub args: Option>, - pub block: Block, -} - -impl Parse for Catch { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { - let (error, panic) = if input.peek(kw::error) { - (Some(kw::error(input.span())), None) - } else if input.peek(kw::panic) { - (None, Some(kw::panic(input.span()))) - } else { - (None, None) - }; - - let args = if error.is_none() && panic.is_none() { - if input.peek(Paren) { - // we have args - let f = input.fork(); - let mut args = Parameters::new(); - while let Ok(arg) = input.parse::() { - args.push(arg); - } - Some(args) - } else { - // they raw doggin - None - } - } else { - let mut args = Parameters::new(); - while let Ok(arg) = input.parse::() { - args.push(arg); - } - Some(args) - }; - - Ok(Self { - error, - panic, - args, - block: input.parse()?, - }) - } -} - -impl Parse for TryCatch { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { - let a_try = input.parse()?; - let block = input.parse()?; - let catch = input.parse()?; - - Ok(Self { - r#try: a_try, - block, - catch, - }) - } -} diff --git a/crates/syn-solidity/src/stmt/tuple_expr.rs b/crates/syn-solidity/src/stmt/tuple_expr.rs deleted file mode 100644 index 3560c5d048..0000000000 --- a/crates/syn-solidity/src/stmt/tuple_expr.rs +++ /dev/null @@ -1,25 +0,0 @@ -use syn::{parenthesized, parse::Parse, punctuated::Punctuated, token::Paren, Token}; - -use crate::expr::Stmt; - -#[derive(Debug, Clone)] -pub struct TupleExpr { - paren: Paren, - exprs: Punctuated, -} - -impl Parse for TupleExpr { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { - let content; - let paren = parenthesized!(content in input); - - let mut exprs = Punctuated::new(); - exprs.push(input.parse()?); - while input.peek(Token![,]) { - exprs.push(input.parse()?); - } - exprs.push(input.parse()?); - - Ok(Self { exprs, paren }) - } -} diff --git a/crates/syn-solidity/src/stmt/unchecked.rs b/crates/syn-solidity/src/stmt/unchecked.rs deleted file mode 100644 index 41ef3ddeea..0000000000 --- a/crates/syn-solidity/src/stmt/unchecked.rs +++ /dev/null @@ -1,18 +0,0 @@ -use syn::parse::Parse; - -use crate::{kw, Block}; - -#[derive(Debug, Clone)] -pub struct Unchecked { - unchecked: kw::unchecked, - block: Block, -} - -impl Parse for Unchecked { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { - Ok(Self { - unchecked: input.parse()?, - block: input.parse()?, - }) - } -} diff --git a/crates/syn-solidity/src/stmt/var_decl.rs b/crates/syn-solidity/src/stmt/var_decl.rs new file mode 100644 index 0000000000..f9aa8252ac --- /dev/null +++ b/crates/syn-solidity/src/stmt/var_decl.rs @@ -0,0 +1,146 @@ +use crate::{Expr, VariableDeclaration}; +use proc_macro2::Span; +use std::fmt; +use syn::{ + parenthesized, + parse::{Parse, ParseStream}, + punctuated::Punctuated, + token::Paren, + Result, Token, +}; + +/// A variable declaration statement: `uint256 foo = 42;` +/// +/// Solidity Reference: +/// +#[derive(Clone)] +pub struct StmtVarDecl { + pub declaration: VarDeclDecl, + pub assignment: Option<(Token![=], Expr)>, + pub semi_token: Token![;], +} + +impl fmt::Debug for StmtVarDecl { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("StmtVarDecl") + .field("declaration", &self.declaration) + .field("assignment", &self.assignment) + .finish() + } +} + +impl Parse for StmtVarDecl { + fn parse(input: ParseStream<'_>) -> Result { + Ok(Self { + declaration: input.parse()?, + assignment: { + if input.peek(Token![=]) { + Some((input.parse()?, input.parse()?)) + } else { + None + } + }, + semi_token: input.parse()?, + }) + } +} + +impl StmtVarDecl { + pub fn span(&self) -> Span { + let span = self.declaration.span(); + self.assignment + .as_ref() + .and_then(|(_, expr)| expr.span().join(span)) + .unwrap_or(span) + } + + pub fn set_span(&mut self, span: Span) { + self.declaration.set_span(span); + if let Some((eq, expr)) = &mut self.assignment { + eq.span = span; + expr.set_span(span); + } + self.semi_token.span = span; + } +} + +/// The declaration of the variable(s) in a [`StmtVarDecl`]. +#[derive(Clone, Debug)] +pub enum VarDeclDecl { + VarDecl(VariableDeclaration), + Expression(VarDeclTuple), +} + +impl Parse for VarDeclDecl { + fn parse(input: ParseStream<'_>) -> Result { + if input.peek(Paren) { + input.parse().map(Self::Expression) + } else { + input.parse().map(Self::VarDecl) + } + } +} + +impl VarDeclDecl { + pub fn span(&self) -> Span { + match self { + Self::VarDecl(decl) => decl.span(), + Self::Expression(decl) => decl.span(), + } + } + + pub fn set_span(&mut self, span: Span) { + match self { + Self::VarDecl(decl) => decl.set_span(span), + Self::Expression(decl) => decl.set_span(span), + } + } +} + +/// A declaration of variables in a tuple: `(,,uint256 foo,string memory bar)` +/// +/// Solidity Reference: +/// +#[derive(Clone)] +pub struct VarDeclTuple { + pub paren_token: Paren, + /// The list of variables being declared. The list can't be empty, but it + /// can contain `None` elements, indicating the field is empty. + pub vars: Punctuated, Token![,]>, +} + +impl fmt::Debug for VarDeclTuple { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("TupleVarDecl") + .field("vars", &self.vars) + .finish() + } +} + +impl Parse for VarDeclTuple { + fn parse(input: ParseStream<'_>) -> Result { + let content; + Ok(Self { + paren_token: parenthesized!(content in input), + vars: content.parse_terminated(Self::parse_var_opt, Token![,])?, + }) + } +} + +impl VarDeclTuple { + pub fn span(&self) -> Span { + self.paren_token.span.join() + } + + pub fn set_span(&mut self, span: Span) { + self.paren_token = Paren(span); + } + + fn parse_var_opt(input: ParseStream<'_>) -> Result> { + if input.peek(Token![,]) { + Ok(None) + } else { + input.parse().map(Some) + } + } +} diff --git a/crates/syn-solidity/src/stmt/while.rs b/crates/syn-solidity/src/stmt/while.rs index 7ba4751fa0..4bb31e9039 100644 --- a/crates/syn-solidity/src/stmt/while.rs +++ b/crates/syn-solidity/src/stmt/while.rs @@ -1,57 +1,52 @@ -use syn::{parenthesized, parse::Parse, token::Paren, Token}; - -use crate::{expr::Stmt, Block}; - -#[derive(Debug, Clone)] -pub struct DoWhile { - pub do_token: Token![do], - pub block: Block, +use crate::{Expr, Stmt}; +use proc_macro2::Span; +use std::fmt; +use syn::{ + parse::{Parse, ParseStream}, + token::Paren, + Result, Token, +}; + +/// A while statement: `while (i < 42) { ... }` +/// +/// +#[derive(Clone)] +pub struct StmtWhile { pub while_token: Token![while], - pub paren: Paren, - pub expr: Box, + pub paren_token: Paren, + pub cond: Expr, + pub body: Box, } -impl Parse for DoWhile { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { - let content; - let do_token = input.parse()?; - let block = input.parse()?; - let while_token = input.parse()?; - - let paren = parenthesized!(content in input); - let expr = Box::new(input.parse()?); +impl fmt::Debug for StmtWhile { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("StmtWhile") + .field("cond", &self.cond) + .field("body", &self.body) + .finish() + } +} +impl Parse for StmtWhile { + fn parse(input: ParseStream<'_>) -> Result { + let content; Ok(Self { - do_token, - block, - while_token, - paren, - expr, + while_token: input.parse()?, + paren_token: syn::parenthesized!(content in input), + cond: content.parse()?, + body: input.parse()?, }) } } -#[derive(Debug, Clone)] -pub struct While { - pub while_token: Token![while], - pub paren: Paren, - pub expr: Box, - pub block: Block, -} - -impl Parse for While { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { - let content; - let while_token = input.parse()?; - let paren = parenthesized!(content in input); - let expr = input.parse()?; - let block = input.parse()?; +impl StmtWhile { + pub fn span(&self) -> Span { + let span = self.while_token.span; + span.join(self.body.span()).unwrap_or(span) + } - Ok(Self { - while_token, - paren, - expr, - block, - }) + pub fn set_span(&mut self, span: Span) { + self.while_token.span = span; + self.body.set_span(span); } } diff --git a/crates/syn-solidity/src/utils.rs b/crates/syn-solidity/src/utils.rs index 7c842875e3..72ad21095a 100644 --- a/crates/syn-solidity/src/utils.rs +++ b/crates/syn-solidity/src/utils.rs @@ -1,6 +1,10 @@ use proc_macro2::{TokenStream, TokenTree}; use std::fmt; -use syn::{parse::ParseStream, punctuated::Punctuated, Token}; +use syn::{ + parse::{Parse, ParseStream}, + punctuated::Punctuated, + Result, Token, +}; #[repr(transparent)] pub(crate) struct DebugPunctuated(Punctuated); @@ -26,3 +30,15 @@ pub(crate) fn tts_until_semi(input: ParseStream<'_>) -> TokenStream { } tts } + +pub(crate) fn parse_vec(input: ParseStream<'_>, allow_empty: bool) -> Result> { + let mut vec = Vec::::new(); + while !input.is_empty() { + vec.push(input.parse()?); + } + if !allow_empty && vec.is_empty() { + Err(input.parse::().err().expect("unreachable")) + } else { + Ok(vec) + } +} diff --git a/crates/syn-solidity/src/variable/mod.rs b/crates/syn-solidity/src/variable/mod.rs index b922ddd3d4..5d48d394b6 100644 --- a/crates/syn-solidity/src/variable/mod.rs +++ b/crates/syn-solidity/src/variable/mod.rs @@ -1,6 +1,6 @@ use super::{SolIdent, Storage, Type}; -use crate::{utils::tts_until_semi, VariableAttributes}; -use proc_macro2::{Span, TokenStream}; +use crate::{Expr, VariableAttributes}; +use proc_macro2::Span; use std::fmt::{self, Write}; use syn::{ ext::IdentExt, @@ -23,7 +23,7 @@ pub struct VariableDeclaration { /// The storage location of the variable, if any. pub storage: Option, /// The name of the variable. This is always Some if parsed as part of - /// [`Parameters`]. + /// [`Parameters`] or a [`Stmt`][crate::Stmt]. pub name: Option, } @@ -111,8 +111,7 @@ pub struct VariableDefinition { pub ty: Type, pub attributes: VariableAttributes, pub name: SolIdent, - // TODO: Expr - pub initializer: Option<(Token![=], TokenStream)>, + pub initializer: Option<(Token![=], Expr)>, pub semi_token: Token![;], } @@ -123,7 +122,7 @@ impl Parse for VariableDefinition { attributes: input.parse()?, name: input.parse()?, initializer: if input.peek(Token![=]) { - Some((input.parse()?, tts_until_semi(input))) + Some((input.parse()?, input.parse()?)) } else { None }, diff --git a/crates/syn-solidity/src/yul/block.rs b/crates/syn-solidity/src/yul/block.rs new file mode 100644 index 0000000000..570b7ebfb8 --- /dev/null +++ b/crates/syn-solidity/src/yul/block.rs @@ -0,0 +1,43 @@ +use proc_macro2::{Span, TokenStream}; +use std::fmt; +use syn::{ + braced, + parse::{Parse, ParseStream}, + token::Brace, + Result, +}; + +#[derive(Clone)] +pub struct YulBlock { + pub brace_token: Brace, + // TODO + pub stmts: TokenStream, +} + +impl fmt::Debug for YulBlock { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("YulBlock") + .field("stmts", &self.stmts) + .finish() + } +} + +impl Parse for YulBlock { + fn parse(input: ParseStream<'_>) -> Result { + let content; + Ok(Self { + brace_token: braced!(content in input), + stmts: content.parse()?, + }) + } +} + +impl YulBlock { + pub fn span(&self) -> Span { + self.brace_token.span.join() + } + + pub fn set_span(&mut self, span: Span) { + self.brace_token = Brace(span); + } +} diff --git a/crates/syn-solidity/src/yul/mod.rs b/crates/syn-solidity/src/yul/mod.rs new file mode 100644 index 0000000000..c1265f9677 --- /dev/null +++ b/crates/syn-solidity/src/yul/mod.rs @@ -0,0 +1,2 @@ +mod block; +pub use block::YulBlock; From a0ccd5ab5ca9227a24dee3e0bb40e81574106e0a Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Fri, 4 Aug 2023 17:01:24 +0200 Subject: [PATCH 12/22] feat: exprs --- a.sol | 1 + crates/syn-solidity/src/expr/args.rs | 170 +++++++++++++++-- crates/syn-solidity/src/expr/array.rs | 96 ++++++++++ crates/syn-solidity/src/expr/binary.rs | 75 ++++++++ crates/syn-solidity/src/expr/member.rs | 52 ++++++ crates/syn-solidity/src/expr/mod.rs | 185 ++++++++++++++++++- crates/syn-solidity/src/expr/ternary.rs | 51 +++++ crates/syn-solidity/src/expr/tuple.rs | 45 +++++ crates/syn-solidity/src/expr/type.rs | 84 +++++++++ crates/syn-solidity/src/expr/unary.rs | 118 ++++++++++++ crates/syn-solidity/src/item/contract.rs | 2 +- crates/syn-solidity/src/item/enum.rs | 2 +- crates/syn-solidity/src/item/error.rs | 2 +- crates/syn-solidity/src/item/function.rs | 4 +- crates/syn-solidity/src/item/import.rs | 2 +- crates/syn-solidity/src/item/struct.rs | 2 +- crates/syn-solidity/src/item/udt.rs | 2 +- crates/syn-solidity/src/item/using.rs | 2 +- crates/syn-solidity/src/kw.rs | 13 +- crates/syn-solidity/src/lib.rs | 5 +- crates/syn-solidity/src/lit.rs | 81 -------- crates/syn-solidity/src/lit/mod.rs | 69 +++++++ crates/syn-solidity/src/lit/str.rs | 158 ++++++++++++++++ crates/syn-solidity/src/macros.rs | 72 ++++++-- crates/syn-solidity/src/spanned.rs | 226 +++++++++++++++++++++++ crates/syn-solidity/src/stmt/assembly.rs | 1 + crates/syn-solidity/src/stmt/blocks.rs | 3 +- crates/syn-solidity/src/stmt/break.rs | 2 +- crates/syn-solidity/src/stmt/continue.rs | 2 +- crates/syn-solidity/src/stmt/do_while.rs | 2 +- crates/syn-solidity/src/stmt/emit.rs | 6 +- crates/syn-solidity/src/stmt/expr.rs | 1 + crates/syn-solidity/src/stmt/for.rs | 2 +- crates/syn-solidity/src/stmt/if.rs | 6 +- crates/syn-solidity/src/stmt/mod.rs | 112 +++++++---- crates/syn-solidity/src/stmt/return.rs | 2 +- crates/syn-solidity/src/stmt/revert.rs | 6 +- crates/syn-solidity/src/stmt/try.rs | 4 +- crates/syn-solidity/src/stmt/var_decl.rs | 4 +- crates/syn-solidity/src/stmt/while.rs | 2 +- crates/syn-solidity/src/type/function.rs | 2 +- crates/syn-solidity/src/type/mod.rs | 2 +- crates/syn-solidity/src/type/tuple.rs | 2 +- crates/syn-solidity/src/utils.rs | 32 +++- 44 files changed, 1509 insertions(+), 203 deletions(-) create mode 100644 crates/syn-solidity/src/expr/array.rs create mode 100644 crates/syn-solidity/src/expr/binary.rs create mode 100644 crates/syn-solidity/src/expr/member.rs create mode 100644 crates/syn-solidity/src/expr/ternary.rs create mode 100644 crates/syn-solidity/src/expr/tuple.rs create mode 100644 crates/syn-solidity/src/expr/type.rs create mode 100644 crates/syn-solidity/src/expr/unary.rs delete mode 100644 crates/syn-solidity/src/lit.rs create mode 100644 crates/syn-solidity/src/lit/mod.rs create mode 100644 crates/syn-solidity/src/lit/str.rs create mode 100644 crates/syn-solidity/src/spanned.rs diff --git a/a.sol b/a.sol index 3fc6fc2fe1..45d5199d84 100644 --- a/a.sol +++ b/a.sol @@ -2,4 +2,5 @@ function f() pure { uint256 a; (++a, ++a); uint256; + string memory s = unicode"" unicode""; } diff --git a/crates/syn-solidity/src/expr/args.rs b/crates/syn-solidity/src/expr/args.rs index 28f07fbd75..a2b07d58ac 100644 --- a/crates/syn-solidity/src/expr/args.rs +++ b/crates/syn-solidity/src/expr/args.rs @@ -1,4 +1,4 @@ -use crate::{Expr, SolIdent}; +use crate::{kw, Expr, SolIdent}; use proc_macro2::Span; use std::fmt; use syn::{ @@ -9,16 +9,96 @@ use syn::{ Result, Token, }; +/// A function call expression: `foo(42)` or `foo({ bar: 42 })`. +#[derive(Clone, Debug)] +pub struct ExprCall { + pub expr: Box, + pub args: ArgList, +} + +impl Parse for ExprCall { + fn parse(input: ParseStream<'_>) -> Result { + Ok(Self { + expr: input.parse()?, + args: input.parse()?, + }) + } +} + +impl ExprCall { + pub fn span(&self) -> Span { + let span = self.expr.span(); + span.join(self.args.span()).unwrap_or(span) + } + + pub fn set_span(&mut self, span: Span) { + self.expr.set_span(span); + self.args.set_span(span); + } +} + +/// A `payable` expression: `payable(address(0x...))`. +#[derive(Clone)] +pub struct ExprPayable { + pub payable_token: kw::payable, + pub args: ArgList, +} + +impl fmt::Debug for ExprPayable { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ExprPayable") + .field("args", &self.args) + .finish() + } +} + +impl From for ExprCall { + fn from(value: ExprPayable) -> Self { + Self { + expr: Box::new(Expr::Ident(SolIdent::new_spanned( + "payable", + value.payable_token.span, + ))), + args: value.args, + } + } +} + +impl Parse for ExprPayable { + fn parse(input: ParseStream<'_>) -> Result { + Ok(Self { + payable_token: input.parse()?, + args: input.parse()?, + }) + } +} + +impl ExprPayable { + pub fn span(&self) -> Span { + let span = self.payable_token.span; + span.join(self.args.span()).unwrap_or(span) + } + + pub fn set_span(&mut self, span: Span) { + self.payable_token.span = span; + self.args.set_span(span); + } +} + +/// A list of named or unnamed arguments: `{ foo: 42, bar: 64 }` or `(42, 64)`. +/// +/// Solidity reference: +/// #[derive(Clone)] -pub struct CallArgumentList { +pub struct ArgList { pub paren_token: Paren, /// The list of arguments. Can be named or unnamed. /// /// When empty, this is an empty unnamed list. - pub list: CallArgumentListImpl, + pub list: ArgListImpl, } -impl fmt::Debug for CallArgumentList { +impl fmt::Debug for ArgList { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("CallArgumentList") .field("list", &self.list) @@ -26,7 +106,7 @@ impl fmt::Debug for CallArgumentList { } } -impl Parse for CallArgumentList { +impl Parse for ArgList { fn parse(input: ParseStream<'_>) -> Result { let content; Ok(Self { @@ -36,7 +116,7 @@ impl Parse for CallArgumentList { } } -impl CallArgumentList { +impl ArgList { pub fn span(&self) -> Span { self.paren_token.span.join() } @@ -46,20 +126,17 @@ impl CallArgumentList { } } +/// A list of either unnamed or named arguments. #[derive(Clone, Debug)] -pub enum CallArgumentListImpl { +pub enum ArgListImpl { Unnamed(Punctuated), - Named(Brace, Punctuated), + Named(NamedArgList), } -impl Parse for CallArgumentListImpl { +impl Parse for ArgListImpl { fn parse(input: ParseStream<'_>) -> Result { if input.peek(Brace) { - let content; - Ok(Self::Named( - braced!(content in input), - content.parse_terminated(NamedArg::parse, Token![,])?, - )) + input.parse().map(Self::Named) } else { input .parse_terminated(Expr::parse, Token![,]) @@ -68,7 +145,70 @@ impl Parse for CallArgumentListImpl { } } -/// A named argument in an argument list: `foo: uint256(42)` +/// A struct expression: `Foo { bar: 1, baz: 2 }`. +#[derive(Clone, Debug)] +pub struct ExprStruct { + pub expr: Box, + pub args: NamedArgList, +} + +impl Parse for ExprStruct { + fn parse(input: ParseStream<'_>) -> Result { + Ok(Self { + expr: input.parse()?, + args: input.parse()?, + }) + } +} + +impl ExprStruct { + pub fn span(&self) -> Span { + let span = self.expr.span(); + span.join(self.args.span()).unwrap_or(span) + } + + pub fn set_span(&mut self, span: Span) { + self.expr.set_span(span); + self.args.set_span(span); + } +} + +/// A named argument list: `{ foo: uint256(42), bar: true }`. +#[derive(Clone)] +pub struct NamedArgList { + pub brace_token: Brace, + pub list: Punctuated, +} + +impl fmt::Debug for NamedArgList { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("NamedArgumentList") + .field("list", &self.list) + .finish() + } +} + +impl Parse for NamedArgList { + fn parse(input: ParseStream<'_>) -> Result { + let content; + Ok(Self { + brace_token: braced!(content in input), + list: content.parse_terminated(NamedArg::parse, Token![,])?, + }) + } +} + +impl NamedArgList { + pub fn span(&self) -> Span { + self.brace_token.span.join() + } + + pub fn set_span(&mut self, span: Span) { + self.brace_token = Brace(span); + } +} + +/// A named argument in an argument list: `foo: uint256(42)`. #[derive(Clone)] pub struct NamedArg { pub name: SolIdent, diff --git a/crates/syn-solidity/src/expr/array.rs b/crates/syn-solidity/src/expr/array.rs new file mode 100644 index 0000000000..66006fa12e --- /dev/null +++ b/crates/syn-solidity/src/expr/array.rs @@ -0,0 +1,96 @@ +use crate::Expr; +use proc_macro2::Span; +use std::fmt; +use syn::{ + bracketed, + parse::{Parse, ParseStream}, + punctuated::Punctuated, + token::Bracket, + Result, Token, +}; + +/// An array literal expression: `[a, b, c, d]`. +#[derive(Clone)] +pub struct ExprArray { + pub bracket_token: Bracket, + pub elems: Punctuated, +} + +impl fmt::Debug for ExprArray { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ExprArray") + .field("elems", &self.elems) + .finish() + } +} + +impl Parse for ExprArray { + fn parse(input: ParseStream<'_>) -> Result { + let content; + Ok(Self { + bracket_token: bracketed!(content in input), + elems: content.parse_terminated(Expr::parse, Token![,])?, + }) + } +} + +impl ExprArray { + pub fn span(&self) -> Span { + self.bracket_token.span.join() + } + + pub fn set_span(&mut self, span: Span) { + self.bracket_token = Bracket(span); + } +} + +/// A square bracketed indexing expression: `vector[2]`. +#[derive(Clone)] +pub struct ExprIndex { + pub expr: Box, + pub bracket_token: Bracket, + pub start: Option>, + pub end: Option<(Token![:], Box)>, +} + +impl fmt::Debug for ExprIndex { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ExprIndex") + .field("expr", &self.expr) + .field("start", &self.start) + .field("end", &self.end) + .finish() + } +} + +impl Parse for ExprIndex { + fn parse(input: ParseStream<'_>) -> Result { + let content; + Ok(Self { + expr: input.parse()?, + bracket_token: bracketed!(content in input), + start: if content.is_empty() || content.peek(Token![:]) { + None + } else { + Some(content.parse()?) + }, + end: if content.is_empty() { + None + } else { + Some((content.parse()?, content.parse()?)) + }, + }) + } +} + +impl ExprIndex { + pub fn span(&self) -> Span { + let span = self.expr.span(); + span.join(self.bracket_token.span.join()).unwrap_or(span) + } + + pub fn set_span(&mut self, span: Span) { + self.expr.set_span(span); + self.bracket_token = Bracket(span); + } +} diff --git a/crates/syn-solidity/src/expr/binary.rs b/crates/syn-solidity/src/expr/binary.rs new file mode 100644 index 0000000000..3d7d1226e2 --- /dev/null +++ b/crates/syn-solidity/src/expr/binary.rs @@ -0,0 +1,75 @@ +use crate::Expr; +use proc_macro2::Span; +use syn::{ + parse::{Parse, ParseStream}, + Result, +}; + +/// A binary operation: `a + b`, `a += b`. +#[derive(Clone, Debug)] +pub struct ExprBinary { + pub left: Box, + pub op: BinOp, + pub right: Box, +} + +impl Parse for ExprBinary { + fn parse(input: ParseStream<'_>) -> Result { + Ok(Self { + left: input.parse()?, + op: input.parse()?, + right: input.parse()?, + }) + } +} + +impl ExprBinary { + pub fn span(&self) -> Span { + let span = self.left.span(); + span.join(self.right.span()).unwrap_or(span) + } + + pub fn set_span(&mut self, span: Span) { + self.left.set_span(span); + self.right.set_span(span); + } +} + +op_enum! { + /// A binary operator: `+`, `+=`, `&`. + pub enum BinOp { + Add(+), + Sub(-), + Mul(*), + Div(/), + Rem(%), + Pow(**), + + Sar(>>>), + Shr(>>), + Shl(<<), + BitAnd(&), + BitOr(|), + BitXor(^), + + Lt(<), + Gt(>), + Le(<=), + Ge(>=), + Eq(==), + Neq(!=), + + Assign(=), + AddAssign(+=), + SubAssign(-=), + MulAssign(*=), + DivAssign(/=), + RemAssign(%=), + BitAndAssign(&=), + BitOrAssign(|=), + BitXorAssign(^=), + ShlAssign(<<=), + ShrAssign(>>=), + SarAssign(>>>=), + } +} diff --git a/crates/syn-solidity/src/expr/member.rs b/crates/syn-solidity/src/expr/member.rs new file mode 100644 index 0000000000..0f3d612be5 --- /dev/null +++ b/crates/syn-solidity/src/expr/member.rs @@ -0,0 +1,52 @@ +use crate::Expr; +use proc_macro2::Span; +use std::fmt; +use syn::{ + parse::{Parse, ParseStream}, + Result, Token, +}; + +/// Access of a named member: `obj.k`. +#[derive(Clone)] +pub struct ExprMember { + pub expr: Box, + pub dot_token: Token![.], + pub member: Box, +} + +impl fmt::Debug for ExprMember { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ExprMember") + .field("expr", &self.expr) + .field("member", &self.member) + .finish() + } +} + +impl Parse for ExprMember { + fn parse(input: ParseStream<'_>) -> Result { + Ok(Self { + expr: input.parse()?, + dot_token: input.parse()?, + member: input.parse()?, + }) + } +} + +impl ExprMember { + pub fn span(&self) -> Span { + self.expr + .span() + .join(self.member.span()) + .unwrap_or_else(|| { + self.dot_token + .span + .join(self.member.span()) + .unwrap_or_else(|| self.expr.span()) + }) + } + + pub fn set_span(&mut self, span: Span) { + self.expr.set_span(span); + } +} diff --git a/crates/syn-solidity/src/expr/mod.rs b/crates/syn-solidity/src/expr/mod.rs index 96101a86bf..6d22425a79 100644 --- a/crates/syn-solidity/src/expr/mod.rs +++ b/crates/syn-solidity/src/expr/mod.rs @@ -1,33 +1,198 @@ -use proc_macro2::Span; +use proc_macro2::{Ident, Span}; use syn::{ - parse::{Parse, ParseStream}, - Result, + ext::IdentExt, + parse::{discouraged::Speculative, Parse, ParseStream}, + token::{Brace, Bracket, Paren}, + Result, Token, }; +mod array; +pub use array::{ExprArray, ExprIndex}; + mod args; -pub use args::{CallArgumentList, CallArgumentListImpl, NamedArg}; +pub use args::{ArgList, ArgListImpl, ExprCall, ExprPayable, ExprStruct, NamedArg, NamedArgList}; + +mod binary; +pub use binary::{BinOp, ExprBinary}; + +mod member; +pub use member::ExprMember; + +mod ternary; +pub use ternary::ExprTernary; + +mod tuple; +pub use tuple::ExprTuple; + +mod r#type; +pub use r#type::{ExprNew, ExprTypeCall}; + +mod unary; +pub use unary::{ExprDelete, ExprPostfix, ExprUnary, PostUnOp, UnOp}; + +use crate::{kw, Lit, SolIdent, Type}; /// An expression. /// /// Solidity reference: /// #[derive(Clone, Debug)] -pub enum Expr {} +pub enum Expr { + /// An array literal expression: `[a, b, c, d]`. + Array(ExprArray), + + /// A binary operation: `a + b`, `a += b`. + Binary(ExprBinary), + + /// A function call expression: `foo(42)` or `foo({ bar: 42 })`. + Call(ExprCall), + + /// A unary `delete` expression: `delete vector`. + Delete(ExprDelete), + + /// An identifier: `foo`. + Ident(SolIdent), + + /// A square bracketed indexing expression: `vector[2]`. + Index(ExprIndex), + + /// A literal: `hex"1234"`. + Lit(Lit), + + /// Access of a named member: `obj.k`. + Member(ExprMember), + + /// A `new` expression: `new Contract`. + New(ExprNew), + + /// A `payable` expression: `payable(address(0x...))`. + Payable(ExprPayable), + + /// A postfix unary expression: `foo++`. + Postfix(ExprPostfix), + + /// A struct expression: `Foo { bar: 1, baz: 2 }`. + Struct(ExprStruct), + + /// A ternary (AKA conditional) expression: `foo ? bar : baz`. + Ternary(ExprTernary), + + /// A tuple expression: `(a, b, c, d)`. + Tuple(ExprTuple), + + /// A type name. + Type(Type), + + /// A `type()` expression: `type(uint256)` + TypeCall(ExprTypeCall), + + /// A unary operation: `!x`, `*x`. + Unary(ExprUnary), +} impl Parse for Expr { fn parse(input: ParseStream<'_>) -> Result { - let _ = input; - todo!() + let lookahead = input.lookahead1(); + if lookahead.peek(Paren) { + // TODO: tuple type? + input.parse().map(Self::Tuple) + } else if lookahead.peek(Bracket) { + input.parse().map(Self::Array) + } else if Lit::peek(&lookahead) { + input.parse().map(Self::Lit) + } else if lookahead.peek(kw::payable) { + input.parse().map(Self::Payable) + } else if lookahead.peek(Token![type]) { + input.parse().map(Self::TypeCall) + } else if lookahead.peek(kw::new) { + input.parse().map(Self::New) + } else if lookahead.peek(kw::delete) { + input.parse().map(Self::Delete) + } else if lookahead.peek(Ident::peek_any) { + let fork = input.fork(); + match fork.parse() { + Ok(ty) => { + input.advance_to(&fork); + Ok(Self::Type(ty)) + } + Err(_) => input.parse().map(Self::Ident), + } + } else if UnOp::peek(input, &lookahead) { + input.parse().map(Self::Unary) + } else { + let fork = input.fork(); + match input.parse::() { + Ok(_) => Self::parse2(input, &fork), + Err(_) => Err(lookahead.error()), + } + } } } impl Expr { + /// Parse an expression that starts with an expression. + fn parse2(input: ParseStream<'_>, start: ParseStream<'_>) -> Result { + let lookahead = input.lookahead1(); + if lookahead.peek(Bracket) { + start.parse().map(Self::Index) + } else if lookahead.peek(Brace) { + start.parse().map(Self::Struct) + } else if lookahead.peek(Paren) { + start.parse().map(Self::Call) + } else if lookahead.peek(Token![.]) { + start.parse().map(Self::Member) + } else if lookahead.peek(Token![?]) { + start.parse().map(Self::Ternary) + } else if PostUnOp::peek(input, &lookahead) { + start.parse().map(Self::Postfix) + } else if BinOp::peek(input, &lookahead) { + start.parse().map(Self::Binary) + } else { + Err(lookahead.error()) + } + } + pub fn span(&self) -> Span { - match *self {} + match self { + Self::Index(expr) => expr.span(), + Self::Member(expr) => expr.span(), + Self::Struct(expr) => expr.span(), + Self::Call(expr) => expr.span(), + Self::Payable(expr) => expr.span(), + Self::TypeCall(expr) => expr.span(), + Self::Unary(expr) => expr.span(), + Self::Binary(expr) => expr.span(), + Self::Ternary(expr) => expr.span(), + Self::Postfix(expr) => expr.span(), + Self::New(expr) => expr.span(), + Self::Delete(expr) => expr.span(), + Self::Tuple(expr) => expr.span(), + Self::Array(expr) => expr.span(), + Self::Ident(expr) => expr.span(), + Self::Lit(expr) => expr.span(), + Self::Type(expr) => expr.span(), + } } pub fn set_span(&mut self, span: Span) { - let _ = span; - match *self {} + match self { + Self::Index(expr) => expr.set_span(span), + Self::Member(expr) => expr.set_span(span), + Self::Struct(expr) => expr.set_span(span), + Self::Call(expr) => expr.set_span(span), + Self::Payable(expr) => expr.set_span(span), + Self::TypeCall(expr) => expr.set_span(span), + Self::Unary(expr) => expr.set_span(span), + Self::Binary(expr) => expr.set_span(span), + Self::Ternary(expr) => expr.set_span(span), + Self::Postfix(expr) => expr.set_span(span), + Self::New(expr) => expr.set_span(span), + Self::Delete(expr) => expr.set_span(span), + Self::Tuple(expr) => expr.set_span(span), + Self::Array(expr) => expr.set_span(span), + Self::Ident(expr) => expr.set_span(span), + Self::Lit(expr) => expr.set_span(span), + Self::Type(expr) => expr.set_span(span), + } } } diff --git a/crates/syn-solidity/src/expr/ternary.rs b/crates/syn-solidity/src/expr/ternary.rs new file mode 100644 index 0000000000..98c24d2b65 --- /dev/null +++ b/crates/syn-solidity/src/expr/ternary.rs @@ -0,0 +1,51 @@ +use crate::Expr; +use proc_macro2::Span; +use std::fmt; +use syn::{ + parse::{Parse, ParseStream}, + Result, Token, +}; + +/// A ternary (AKA conditional) expression: `foo ? bar : baz`. +#[derive(Clone)] +pub struct ExprTernary { + pub cond: Box, + pub question_token: Token![?], + pub if_true: Box, + pub colon_token: Token![:], + pub if_false: Box, +} + +impl fmt::Debug for ExprTernary { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ExprTernary") + .field("cond", &self.cond) + .field("if_true", &self.if_true) + .field("if_false", &self.if_false) + .finish() + } +} + +impl Parse for ExprTernary { + fn parse(input: ParseStream<'_>) -> Result { + Ok(Self { + cond: input.parse()?, + question_token: input.parse()?, + if_true: input.parse()?, + colon_token: input.parse()?, + if_false: input.parse()?, + }) + } +} + +impl ExprTernary { + pub fn span(&self) -> Span { + let span = self.cond.span(); + span.join(self.if_false.span()).unwrap_or(span) + } + + pub fn set_span(&mut self, span: Span) { + self.cond.set_span(span); + self.if_false.set_span(span); + } +} diff --git a/crates/syn-solidity/src/expr/tuple.rs b/crates/syn-solidity/src/expr/tuple.rs new file mode 100644 index 0000000000..46ffb0dbe3 --- /dev/null +++ b/crates/syn-solidity/src/expr/tuple.rs @@ -0,0 +1,45 @@ +use crate::Expr; +use proc_macro2::Span; +use std::fmt; +use syn::{ + parenthesized, + parse::{Parse, ParseStream}, + punctuated::Punctuated, + token::Paren, + Result, Token, +}; + +/// A tuple expression: `(a, b, c, d)`. +#[derive(Clone)] +pub struct ExprTuple { + pub paren_token: Paren, + pub elems: Punctuated, +} + +impl fmt::Debug for ExprTuple { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ExprTuple") + .field("elems", &self.elems) + .finish() + } +} + +impl Parse for ExprTuple { + fn parse(input: ParseStream<'_>) -> Result { + let content; + Ok(Self { + paren_token: parenthesized!(content in input), + elems: content.parse_terminated(Expr::parse, Token![,])?, + }) + } +} + +impl ExprTuple { + pub fn span(&self) -> Span { + self.paren_token.span.join() + } + + pub fn set_span(&mut self, span: Span) { + self.paren_token = Paren(span); + } +} diff --git a/crates/syn-solidity/src/expr/type.rs b/crates/syn-solidity/src/expr/type.rs new file mode 100644 index 0000000000..fda7f84d38 --- /dev/null +++ b/crates/syn-solidity/src/expr/type.rs @@ -0,0 +1,84 @@ +use crate::{kw, Type}; +use proc_macro2::Span; +use std::fmt; +use syn::{ + parenthesized, + parse::{Parse, ParseStream}, + token::Paren, + Result, Token, +}; + +/// A `type()` expression: `type(uint256)` +#[derive(Clone)] +pub struct ExprTypeCall { + pub type_token: Token![type], + pub paren_token: Paren, + pub ty: Type, +} + +impl fmt::Debug for ExprTypeCall { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ExprTypeCall") + .field("ty", &self.ty) + .finish() + } +} + +impl Parse for ExprTypeCall { + fn parse(input: ParseStream<'_>) -> Result { + let content; + Ok(Self { + type_token: input.parse()?, + paren_token: parenthesized!(content in input), + ty: content.parse()?, + }) + } +} + +impl ExprTypeCall { + pub fn span(&self) -> Span { + let span = self.type_token.span; + span.join(self.paren_token.span.join()).unwrap_or(span) + } + + pub fn set_span(&mut self, span: Span) { + self.type_token.span = span; + self.paren_token = Paren(span); + } +} + +/// A `new` expression: `new Contract`. +/// +/// i.e. a contract creation or the allocation of a dynamic memory array. +#[derive(Clone)] +pub struct ExprNew { + pub new_token: kw::new, + pub ty: Type, +} + +impl fmt::Debug for ExprNew { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ExprNew").field("ty", &self.ty).finish() + } +} + +impl Parse for ExprNew { + fn parse(input: ParseStream<'_>) -> Result { + Ok(Self { + new_token: input.parse()?, + ty: input.parse()?, + }) + } +} + +impl ExprNew { + pub fn span(&self) -> Span { + let span = self.new_token.span; + span.join(self.ty.span()).unwrap_or(span) + } + + pub fn set_span(&mut self, span: Span) { + self.new_token.span = span; + self.ty.set_span(span); + } +} diff --git a/crates/syn-solidity/src/expr/unary.rs b/crates/syn-solidity/src/expr/unary.rs new file mode 100644 index 0000000000..807a5ec07d --- /dev/null +++ b/crates/syn-solidity/src/expr/unary.rs @@ -0,0 +1,118 @@ +use crate::{kw, Expr}; +use proc_macro2::Span; +use std::fmt; +use syn::{ + parse::{Parse, ParseStream}, + Result, +}; + +/// A unary operation: `!x`, `*x`. +#[derive(Clone, Debug)] +pub struct ExprUnary { + pub op: UnOp, + pub expr: Box, +} + +impl Parse for ExprUnary { + fn parse(input: ParseStream<'_>) -> Result { + Ok(Self { + op: input.parse()?, + expr: input.parse()?, + }) + } +} + +impl ExprUnary { + pub fn span(&self) -> Span { + let span = self.op.span(); + span.join(self.expr.span()).unwrap_or(span) + } + + pub fn set_span(&mut self, span: Span) { + self.op.set_span(span); + self.expr.set_span(span); + } +} + +/// A unary `delete` expression: `delete vector`. +#[derive(Clone)] +pub struct ExprDelete { + pub delete_token: kw::delete, + pub expr: Box, +} + +impl fmt::Debug for ExprDelete { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ExprDelete") + .field("expr", &self.expr) + .finish() + } +} + +impl Parse for ExprDelete { + fn parse(input: ParseStream<'_>) -> Result { + Ok(Self { + delete_token: input.parse()?, + expr: input.parse()?, + }) + } +} + +impl ExprDelete { + pub fn span(&self) -> Span { + let span = self.delete_token.span; + span.join(self.expr.span()).unwrap_or(span) + } + + pub fn set_span(&mut self, span: Span) { + self.delete_token.span = span; + self.expr.set_span(span); + } +} + +/// A postfix unary expression: `foo++`. +#[derive(Clone, Debug)] +pub struct ExprPostfix { + pub expr: Box, + pub op: PostUnOp, +} + +impl Parse for ExprPostfix { + fn parse(input: ParseStream<'_>) -> Result { + Ok(Self { + expr: input.parse()?, + op: input.parse()?, + }) + } +} + +impl ExprPostfix { + pub fn span(&self) -> Span { + let span = self.op.span(); + span.join(self.expr.span()).unwrap_or(span) + } + + pub fn set_span(&mut self, span: Span) { + self.op.set_span(span); + self.expr.set_span(span); + } +} + +op_enum! { + /// Unary operators. + pub enum UnOp { + Increment(++), + Decrement(--), + Not(!), + BitNot(~), + Neg(-), + } +} + +op_enum! { + /// Postfix unary operators. + pub enum PostUnOp { + Increment(++), + Decrement(--), + } +} diff --git a/crates/syn-solidity/src/item/contract.rs b/crates/syn-solidity/src/item/contract.rs index 42fc5d2d03..a7592b83d9 100644 --- a/crates/syn-solidity/src/item/contract.rs +++ b/crates/syn-solidity/src/item/contract.rs @@ -11,7 +11,7 @@ use syn::{ }; /// A contract, abstract contract, interface, or library definition: -/// `contract Foo is Bar("foo"), Baz { ... }` +/// `contract Foo is Bar("foo"), Baz { ... }`. /// /// Solidity reference: /// diff --git a/crates/syn-solidity/src/item/enum.rs b/crates/syn-solidity/src/item/enum.rs index d9dc144784..5ebe4d504b 100644 --- a/crates/syn-solidity/src/item/enum.rs +++ b/crates/syn-solidity/src/item/enum.rs @@ -9,7 +9,7 @@ use syn::{ Attribute, Result, Token, }; -/// An enum definition: `enum Foo { A, B, C }` +/// An enum definition: `enum Foo { A, B, C }`. /// /// Solidity reference: /// diff --git a/crates/syn-solidity/src/item/error.rs b/crates/syn-solidity/src/item/error.rs index 4e804b5aef..db4b8820bf 100644 --- a/crates/syn-solidity/src/item/error.rs +++ b/crates/syn-solidity/src/item/error.rs @@ -8,7 +8,7 @@ use syn::{ Attribute, Result, Token, }; -/// An error definition: `error Foo(uint256 a, uint256 b);` +/// An error definition: `error Foo(uint256 a, uint256 b);`. /// /// Solidity reference: /// diff --git a/crates/syn-solidity/src/item/function.rs b/crates/syn-solidity/src/item/function.rs index 7a96475093..ce177ee549 100644 --- a/crates/syn-solidity/src/item/function.rs +++ b/crates/syn-solidity/src/item/function.rs @@ -14,7 +14,7 @@ use syn::{ }; /// A function, constructor, fallback, receive, or modifier definition: -/// `function helloWorld() external pure returns(string memory);` +/// `function helloWorld() external pure returns(string memory);`. /// /// Solidity reference: /// @@ -86,7 +86,7 @@ impl ItemFunction { let span = name.span(); let kind = FunctionKind::new_function(span); - let mut function = ItemFunction::new(kind, Some(name)); + let mut function = Self::new(kind, Some(name)); let mut returns = ParameterList::new(); returns.push(var.as_declaration()); diff --git a/crates/syn-solidity/src/item/import.rs b/crates/syn-solidity/src/item/import.rs index aa80321715..7f906f69a1 100644 --- a/crates/syn-solidity/src/item/import.rs +++ b/crates/syn-solidity/src/item/import.rs @@ -9,7 +9,7 @@ use syn::{ Result, Token, }; -/// An import directive: `import "foo.sol";` +/// An import directive: `import "foo.sol";`. /// /// Solidity reference: /// diff --git a/crates/syn-solidity/src/item/struct.rs b/crates/syn-solidity/src/item/struct.rs index 3d13dbe21c..964454ae73 100644 --- a/crates/syn-solidity/src/item/struct.rs +++ b/crates/syn-solidity/src/item/struct.rs @@ -11,7 +11,7 @@ use syn::{ Attribute, Result, Token, }; -/// A struct definition: `struct Foo { uint256 bar; }` +/// A struct definition: `struct Foo { uint256 bar; }`. /// /// Solidity reference: /// diff --git a/crates/syn-solidity/src/item/udt.rs b/crates/syn-solidity/src/item/udt.rs index 41e47a4e67..ff0fb812fe 100644 --- a/crates/syn-solidity/src/item/udt.rs +++ b/crates/syn-solidity/src/item/udt.rs @@ -9,7 +9,7 @@ use syn::{ Attribute, Result, Token, }; -/// A user-defined value type definition: `type Foo is uint256;` +/// A user-defined value type definition: `type Foo is uint256;`. /// /// Solidity reference: /// diff --git a/crates/syn-solidity/src/item/using.rs b/crates/syn-solidity/src/item/using.rs index 9fa5e854e4..bac0a6ba3d 100644 --- a/crates/syn-solidity/src/item/using.rs +++ b/crates/syn-solidity/src/item/using.rs @@ -8,7 +8,7 @@ use syn::{ Result, Token, }; -/// A `using` directive: `using { A, B.mul as * } for uint256 global;` +/// A `using` directive: `using { A, B.mul as * } for uint256 global;`. /// /// Solidity reference: /// diff --git a/crates/syn-solidity/src/kw.rs b/crates/syn-solidity/src/kw.rs index fd0d2cd9f5..7d20937a63 100644 --- a/crates/syn-solidity/src/kw.rs +++ b/crates/syn-solidity/src/kw.rs @@ -66,14 +66,17 @@ custom_keywords!( using, global, - // Other - is, + // Literals unicode, + hex, + + // Other + assembly, catch, delete, - unchecked, - new, emit, + is, + new, revert, - assembly, + unchecked, ); diff --git a/crates/syn-solidity/src/lib.rs b/crates/syn-solidity/src/lib.rs index 7381b8d817..8b5dcc06e0 100644 --- a/crates/syn-solidity/src/lib.rs +++ b/crates/syn-solidity/src/lib.rs @@ -43,10 +43,13 @@ pub use item::{ }; mod lit; -pub use lit::LitStr; +pub use lit::{HexStr, Lit, LitHex, LitStr, LitUnicode, UnicodeStr}; pub mod kw; +mod spanned; +pub use spanned::Spanned; + mod stmt; pub use stmt::*; diff --git a/crates/syn-solidity/src/lit.rs b/crates/syn-solidity/src/lit.rs deleted file mode 100644 index e0e39ee735..0000000000 --- a/crates/syn-solidity/src/lit.rs +++ /dev/null @@ -1,81 +0,0 @@ -use crate::kw; -use proc_macro2::Span; -use std::fmt; -use syn::{ - parse::{Parse, ParseStream}, - Result, -}; - -/// A string literal. -#[derive(Clone)] -pub struct LitStr { - pub unicode_token: Option, - pub values: Vec, -} - -impl fmt::Debug for LitStr { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("LitStr") - .field("unicode", &self.unicode_token.is_some()) - .field("values", &self.values) - .finish() - } -} - -impl fmt::Display for LitStr { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for value in &self.values { - f.write_str(&value.value())?; - } - Ok(()) - } -} - -impl Parse for LitStr { - fn parse(input: ParseStream<'_>) -> Result { - Ok(Self { - unicode_token: input.parse()?, - values: { - let mut values = Vec::new(); - while !input.peek(syn::LitStr) { - values.push(input.parse()?); - } - if values.is_empty() { - return Err(input.parse::().unwrap_err()) - } - values - }, - }) - } -} - -impl LitStr { - pub fn parse_opt(input: ParseStream<'_>) -> Result> { - if input.peek(kw::unicode) || input.peek(syn::LitStr) { - input.parse().map(Some) - } else { - Ok(None) - } - } - - pub fn span(&self) -> Span { - let mut span = if let Some(kw) = &self.unicode_token { - kw.span - } else { - self.values.first().unwrap().span() - }; - for value in &self.values { - span = span.join(value.span()).unwrap_or(span); - } - span - } - - pub fn set_span(&mut self, span: Span) { - if let Some(kw) = &mut self.unicode_token { - kw.span = span; - } - for value in &mut self.values { - value.set_span(span); - } - } -} diff --git a/crates/syn-solidity/src/lit/mod.rs b/crates/syn-solidity/src/lit/mod.rs new file mode 100644 index 0000000000..31f5324423 --- /dev/null +++ b/crates/syn-solidity/src/lit/mod.rs @@ -0,0 +1,69 @@ +use crate::kw; +use proc_macro2::Span; +use syn::{ + parse::{Lookahead1, Parse, ParseStream}, + LitBool, LitFloat, LitInt, Result, +}; + +mod str; +pub use str::{HexStr, LitHex, LitStr, LitUnicode, UnicodeStr}; + +/// A literal. +#[derive(Clone, Debug)] +pub enum Lit { + Str(LitStr), + Int(LitInt), + Float(LitFloat), + Bool(LitBool), + Hex(LitHex), + Unicode(LitUnicode), +} + +impl Parse for Lit { + fn parse(input: ParseStream<'_>) -> Result { + let lookahead = input.lookahead1(); + if lookahead.peek(syn::LitStr) { + input.parse().map(Self::Str) + } else if lookahead.peek(LitInt) { + input.parse().map(Self::Int) + } else if lookahead.peek(LitFloat) { + input.parse().map(Self::Float) + } else if lookahead.peek(LitBool) { + input.parse().map(Self::Bool) + } else if lookahead.peek(kw::unicode) { + input.parse().map(Self::Unicode) + } else if lookahead.peek(kw::hex) { + input.parse().map(Self::Hex) + } else { + Err(lookahead.error()) + } + } +} + +impl Lit { + pub fn peek(lookahead: &Lookahead1<'_>) -> bool { + lookahead.peek(syn::Lit) || lookahead.peek(kw::unicode) || lookahead.peek(kw::hex) + } + + pub fn span(&self) -> Span { + match self { + Self::Str(lit) => lit.span(), + Self::Int(lit) => lit.span(), + Self::Float(lit) => lit.span(), + Self::Bool(lit) => lit.span(), + Self::Hex(lit) => lit.span(), + Self::Unicode(lit) => lit.span(), + } + } + + pub fn set_span(&mut self, span: Span) { + match self { + Self::Str(lit) => lit.set_span(span), + Self::Int(lit) => lit.set_span(span), + Self::Float(lit) => lit.set_span(span), + Self::Bool(lit) => lit.set_span(span), + Self::Hex(lit) => lit.set_span(span), + Self::Unicode(lit) => lit.set_span(span), + } + } +} diff --git a/crates/syn-solidity/src/lit/str.rs b/crates/syn-solidity/src/lit/str.rs new file mode 100644 index 0000000000..24e9f26629 --- /dev/null +++ b/crates/syn-solidity/src/lit/str.rs @@ -0,0 +1,158 @@ +use crate::{kw, utils::parse_vec}; +use proc_macro2::Span; +use std::{ + fmt, + ops::{Deref, DerefMut}, +}; +use syn::{ + parse::{Parse, ParseStream}, + Result, +}; + +macro_rules! str_lit { + ($(#[$attr:meta])* $vis:vis struct $name:ident($t:ty) $(: $kw:ident)?) => { + #[derive(Clone, Debug)] + $vis struct $name { + $vis values: Vec<$t>, + } + + impl fmt::Display for $name { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for (i, value) in self.values.iter().enumerate() { + if i > 0 { + f.write_str(" ")?; + } + + $( + f.write_str(stringify!($kw))?; + )? + f.write_str(&value.value())?; + } + Ok(()) + } + } + + impl Parse for $name { + fn parse(input: ParseStream<'_>) -> Result { + Ok(Self { + values: parse_vec(input, false)?, + }) + } + } + + impl $name { + pub fn parse_opt(input: ParseStream<'_>) -> Result> { + if $(input.peek(kw::$kw) || )? input.peek(syn::LitStr) { + input.parse().map(Some) + } else { + Ok(None) + } + } + + pub fn span(&self) -> Span { + let mut span = self.values.first().unwrap().span(); + for value in &self.values[1..] { + span = span.join(value.span()).unwrap_or(span); + } + span + } + + pub fn set_span(&mut self, span: Span) { + for value in &mut self.values { + value.set_span(span); + } + } + + pub fn value(&self) -> String { + self.values.iter().map(|v| v.value()).collect() + } + } + }; +} + +macro_rules! wrap_str { + ($(#[$attr:meta])* $vis:vis struct $name:ident { $token:ident : kw::$kw:ident $(,)? }) => { + $(#[$attr])* + #[derive(Clone)] + $vis struct $name { + /// The prefix of the string. + $vis $token: kw::$kw, + /// The string literal. + $vis value: syn::LitStr, + } + + impl fmt::Debug for $name { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct(stringify!($name)) + .field("value", &self.value) + .finish() + } + } + + impl Deref for $name { + type Target = syn::LitStr; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.value + } + } + + impl DerefMut for $name { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.value + } + } + + impl Parse for $name { + fn parse(input: ParseStream<'_>) -> Result { + Ok(Self { + $token: input.parse()?, + value: input.parse()?, + }) + } + } + + impl $name { + pub fn span(&self) -> Span { + let span = self.$token.span; + span.join(self.value.span()).unwrap_or(span) + } + + pub fn set_span(&mut self, span: Span) { + self.$token.span = span; + self.value.set_span(span); + } + } + }; +} + +str_lit! { + /// A string literal. + pub struct LitStr(syn::LitStr) +} + +str_lit! { + /// A unicode string literal. + pub struct LitUnicode(UnicodeStr): unicode +} + +wrap_str! { + /// A unicode string. + pub struct UnicodeStr { + unicode_token: kw::unicode, + } +} + +str_lit! { + /// A hex string literal. + pub struct LitHex(HexStr): hex +} + +wrap_str! { + /// A hex string. + pub struct HexStr { + hex_token: kw::hex, + } +} diff --git a/crates/syn-solidity/src/macros.rs b/crates/syn-solidity/src/macros.rs index 7f51bc2924..249833be79 100644 --- a/crates/syn-solidity/src/macros.rs +++ b/crates/syn-solidity/src/macros.rs @@ -269,7 +269,7 @@ macro_rules! kw_enum { ::paste::paste! { $( #[inline] - pub fn [](span: ::proc_macro2::Span) -> Self { + pub fn [](span: ::proc_macro2::Span) -> Self { Self::$variant(kw::$kw(span)) } )+ @@ -317,7 +317,7 @@ macro_rules! kw_enum { ::paste::paste! { $( #[inline] - pub const fn [](self) -> bool { + pub const fn [](self) -> bool { matches!(self, Self::$variant(_)) } )+ @@ -327,18 +327,40 @@ macro_rules! kw_enum { } macro_rules! op_enum { + (@skip $($tt:tt)*) => {}; + (@first $first:tt $($rest:tt)*) => { ::syn::Token![$first] }; + + (@peek $input:ident, $lookahead:ident, $a:tt) => { + $lookahead.peek(::syn::Token![$a]) + }; + (@peek $input:ident, $lookahead:ident, $a:tt $b:tt) => { + $lookahead.peek(::syn::Token![$a]) + && $input.peek2(::syn::Token![$b]) + }; + (@peek $input:ident, $lookahead:ident, $a:tt $b:tt $c:tt) => { + $lookahead.peek(::syn::Token![$a]) + && $input.peek2(::syn::Token![$b]) + && $input.peek3(::syn::Token![$c]) + }; + (@peek $input:ident, $lookahead:ident, $($t:tt)*) => { + compile_error!( + "too many tokens in operator: ", + concat!($(stringify!($t)),*), + ) + }; + ( $(#[$attr:meta])* $vis:vis enum $name:ident {$( $(#[$variant_attr:meta])* - $variant:ident($op:tt) + $variant:ident($($op:tt)+) ),+ $(,)?} ) => { $(#[$attr])* #[derive(Clone, Copy)] $vis enum $name {$( - #[doc = concat!("`", stringify!($t), "`")] - $variant(::syn::Token![$op]), + #[doc = concat!("`", $(stringify!($op),)+ "`")] + $variant($(::syn::Token![$op]),+), )+} impl ::core::cmp::PartialEq for $name { @@ -375,8 +397,10 @@ macro_rules! op_enum { fn parse(input: ::syn::parse::ParseStream<'_>) -> ::syn::Result { let lookahead = input.lookahead1(); $( - if lookahead.peek(Token![$op]) { - input.parse().map(Self::$variant) + if op_enum!(@peek input, lookahead, $($op)+) { + Ok(Self::$variant( + $(input.parse::<::syn::Token![$op]>()?),+ + )) } else )+ { @@ -389,29 +413,51 @@ macro_rules! op_enum { ::paste::paste! { $( #[inline] - pub fn [](span: ::proc_macro2::Span) -> Self { - Self::$variant(::syn::Token![$op](span)) + pub fn [](span: ::proc_macro2::Span) -> Self { + Self::$variant($(::syn::Token![$op](span)),+) } )+ } + #[allow(unused_parens, unused_variables)] + pub fn peek(input: syn::parse::ParseStream<'_>, lookahead: &::syn::parse::Lookahead1<'_>) -> bool { + $(( + op_enum!(@peek input, lookahead, $($op)+) + ))||+ + } + pub const fn as_str(self) -> &'static str { match self {$( - Self::$variant(_) => stringify!($op), + Self::$variant(..) => concat!($(stringify!($op)),+), )+} } pub const fn as_debug_str(self) -> &'static str { match self {$( - Self::$variant(_) => stringify!($variant), + Self::$variant(..) => stringify!($variant), )+} } + pub const fn span(self) -> ::proc_macro2::Span { + todo!() + // match self {$( + // Self::$variant(kw, ..) => kw.span(), + // )+} + } + + pub fn set_span(&mut self, span: ::proc_macro2::Span) { + let _ = span; + todo!() + // match self {$( + // Self::$variant(kw, ..) => kw.set_span(span), + // )+} + } + ::paste::paste! { $( #[inline] - pub const fn [](self) -> bool { - matches!(self, Self::$variant(_)) + pub const fn [](self) -> bool { + matches!(self, Self::$variant(..)) } )+ } diff --git a/crates/syn-solidity/src/spanned.rs b/crates/syn-solidity/src/spanned.rs new file mode 100644 index 0000000000..b17aa47b5a --- /dev/null +++ b/crates/syn-solidity/src/spanned.rs @@ -0,0 +1,226 @@ +use proc_macro2::Span; +use syn::Token; + +fn join_spans>(spans: I) -> Span { + let mut iter = spans.into_iter(); + let Some(first) = iter.next() else { + return Span::call_site() + }; + iter.last() + .and_then(|last| first.join(last)) + .unwrap_or(first) +} + +fn set_spans<'a, I: IntoIterator>(spans: I, set_to: Span) { + for span in spans { + *span = set_to; + } +} + +/// A trait for getting and setting the span of a syntax tree node. +pub trait Spanned { + /// Returns the span of this syntax tree node. + fn span(&self) -> Span; + + /// Sets the span of this syntax tree node. + fn set_span(&mut self, span: Span); +} + +impl Spanned for Span { + #[inline] + fn span(&self) -> Span { + *self + } + + #[inline] + fn set_span(&mut self, span: Span) { + *self = span; + } +} + +impl Spanned for Option { + #[inline] + fn span(&self) -> Span { + match self { + Some(t) => t.span(), + None => Span::call_site(), + } + } + + #[inline] + fn set_span(&mut self, span: Span) { + if let Some(t) = self { + t.set_span(span); + } + } +} + +macro_rules! deref_impl { + ($($(#[$attr:meta])* [$($gen:tt)*] $t:ty),+ $(,)?) => {$( + $(#[$attr])* + impl<$($gen)*> Spanned for $t { + #[inline] + fn span(&self) -> Span { + (**self).span() + } + + #[inline] + fn set_span(&mut self, span: Span) { + (**self).set_span(span) + } + } + )+}; +} + +deref_impl! { + [T: ?Sized + Spanned] &mut T, + [T: ?Sized + Spanned] Box, + [T: Spanned] Vec, +} + +impl Spanned for [T] { + #[inline] + fn span(&self) -> Span { + join_spans(self.iter().map(Spanned::span)) + } + + #[inline] + fn set_span(&mut self, span: Span) { + self.iter_mut().for_each(|item| item.set_span(span)); + } +} + +// For `syn::Token!`s +macro_rules! kw_impl { + ($([$($t:tt)+])+) => { $(kw_impl!($($t)+);)+ }; + + (__more $t:tt) => { + impl Spanned for Token![$t] { + #[inline] + fn span(&self) -> Span { + join_spans(self.spans) + } + + #[inline] + fn set_span(&mut self, span: Span) { + set_spans(&mut self.spans, span); + } + } + }; + + ($t:tt) => { + impl Spanned for Token![$t] { + #[inline] + fn span(&self) -> Span { + self.span + } + + #[inline] + fn set_span(&mut self, span: Span) { + self.span = span; + } + } + }; +} + +kw_impl! { + [abstract] + [as] + [async] + [auto] + [await] + [become] + [box] + [break] + [const] + [continue] + [crate] + [default] + [do] + [dyn] + [else] + [enum] + [extern] + [final] + [fn] + [for] + [if] + [impl] + [in] + [let] + [loop] + [macro] + [match] + [mod] + [move] + [mut] + [override] + [priv] + [pub] + [ref] + [return] + [Self] + [self] + [static] + [struct] + [super] + [trait] + [try] + [type] + [typeof] + [union] + [unsafe] + [unsized] + [use] + [virtual] + [where] + [while] + [yield] + [&] + [__more &&] + [__more &=] + [@] + [^] + [__more ^=] + [:] + [,] + [$] + [.] + [__more ..] + [__more ...] + [__more ..=] + [=] + [__more ==] + [__more =>] + [__more >=] + [>] + [__more <-] + [__more <=] + [<] + [-] + [__more -=] + [__more !=] + [!] + [|] + [__more |=] + [__more ||] + [__more ::] + [%] + [__more %=] + [+] + [__more +=] + [#] + [?] + [__more ->] + [;] + [__more <<] + [__more <<=] + [__more >>] + [__more >>=] + [/] + [__more /=] + [*] + [__more *=] + [~] + [_] +} diff --git a/crates/syn-solidity/src/stmt/assembly.rs b/crates/syn-solidity/src/stmt/assembly.rs index 8fcfcb3059..cccb83a146 100644 --- a/crates/syn-solidity/src/stmt/assembly.rs +++ b/crates/syn-solidity/src/stmt/assembly.rs @@ -8,6 +8,7 @@ use syn::{ Result, Token, }; +/// An assembly block, with optional flags: `assembly "evmasm" { ... }`. #[derive(Clone)] pub struct StmtAssembly { pub assembly_token: kw::assembly, diff --git a/crates/syn-solidity/src/stmt/blocks.rs b/crates/syn-solidity/src/stmt/blocks.rs index 5585bcc2ee..d495b31dc6 100644 --- a/crates/syn-solidity/src/stmt/blocks.rs +++ b/crates/syn-solidity/src/stmt/blocks.rs @@ -7,7 +7,7 @@ use syn::{ Result, }; -/// A curly-braced block of statements. +/// A curly-braced block of statements: `{ ... }`. #[derive(Clone)] pub struct Block { pub brace_token: Brace, @@ -40,6 +40,7 @@ impl Block { } } +/// An unchecked block: `unchecked { ... }`. #[derive(Clone)] pub struct UncheckedBlock { pub unchecked_token: kw::unchecked, diff --git a/crates/syn-solidity/src/stmt/break.rs b/crates/syn-solidity/src/stmt/break.rs index 649d50d055..9a423a482b 100644 --- a/crates/syn-solidity/src/stmt/break.rs +++ b/crates/syn-solidity/src/stmt/break.rs @@ -5,7 +5,7 @@ use syn::{ Result, Token, }; -/// A break statement: `break;` +/// A break statement: `break;`. /// /// Solidity Reference: /// diff --git a/crates/syn-solidity/src/stmt/continue.rs b/crates/syn-solidity/src/stmt/continue.rs index 6fa4562bef..611f66425b 100644 --- a/crates/syn-solidity/src/stmt/continue.rs +++ b/crates/syn-solidity/src/stmt/continue.rs @@ -5,7 +5,7 @@ use syn::{ Result, Token, }; -/// A continue statement: `continue;` +/// A continue statement: `continue;`. /// /// Solidity Reference: /// diff --git a/crates/syn-solidity/src/stmt/do_while.rs b/crates/syn-solidity/src/stmt/do_while.rs index 707f4b70d2..3bae36e2e9 100644 --- a/crates/syn-solidity/src/stmt/do_while.rs +++ b/crates/syn-solidity/src/stmt/do_while.rs @@ -7,7 +7,7 @@ use syn::{ Result, Token, }; -/// A do-while statement: `do { ... } while (condition);` +/// A do-while statement: `do { ... } while (condition);`. /// /// Solidity Reference: /// diff --git a/crates/syn-solidity/src/stmt/emit.rs b/crates/syn-solidity/src/stmt/emit.rs index 08398447f3..93658a4726 100644 --- a/crates/syn-solidity/src/stmt/emit.rs +++ b/crates/syn-solidity/src/stmt/emit.rs @@ -1,4 +1,4 @@ -use crate::{kw, CallArgumentList, Expr}; +use crate::{kw, ArgList, Expr}; use proc_macro2::Span; use std::fmt; use syn::{ @@ -6,7 +6,7 @@ use syn::{ Result, Token, }; -/// An emit statement: `emit FooBar(42);` +/// An emit statement: `emit FooBar(42);`. /// /// Solidity Reference: /// @@ -14,7 +14,7 @@ use syn::{ pub struct StmtEmit { pub emit_token: kw::emit, pub expr: Expr, - pub list: CallArgumentList, + pub list: ArgList, pub semi_token: Token![;], } diff --git a/crates/syn-solidity/src/stmt/expr.rs b/crates/syn-solidity/src/stmt/expr.rs index 67a92008c7..d63fbdda8d 100644 --- a/crates/syn-solidity/src/stmt/expr.rs +++ b/crates/syn-solidity/src/stmt/expr.rs @@ -6,6 +6,7 @@ use syn::{ Result, Token, }; +/// An expression with a trailing semicolon. #[derive(Clone)] pub struct StmtExpr { pub expr: Expr, diff --git a/crates/syn-solidity/src/stmt/for.rs b/crates/syn-solidity/src/stmt/for.rs index 12a2df91e8..4c18a443c6 100644 --- a/crates/syn-solidity/src/stmt/for.rs +++ b/crates/syn-solidity/src/stmt/for.rs @@ -7,7 +7,7 @@ use syn::{ Result, Token, }; -/// A for statement: `for (uint256 i; i < 42; ++i) { ... }` +/// A for statement: `for (uint256 i; i < 42; ++i) { ... }`. /// /// Solidity Reference: /// diff --git a/crates/syn-solidity/src/stmt/if.rs b/crates/syn-solidity/src/stmt/if.rs index b29bec9111..343dafb5a5 100644 --- a/crates/syn-solidity/src/stmt/if.rs +++ b/crates/syn-solidity/src/stmt/if.rs @@ -1,4 +1,4 @@ -use crate::{Block, Expr, Stmt}; +use crate::{Expr, Stmt}; use proc_macro2::Span; use std::fmt; use syn::{ @@ -7,12 +7,14 @@ use syn::{ Result, Token, }; +/// An `if` statement with an optional `else` block: `if (expr) { ... } else { +/// ... }`. #[derive(Clone)] pub struct StmtIf { pub if_token: Token![if], pub paren_token: Paren, pub cond: Expr, - pub then_branch: Block, + pub then_branch: Box, pub else_branch: Option<(Token![else], Box)>, } diff --git a/crates/syn-solidity/src/stmt/mod.rs b/crates/syn-solidity/src/stmt/mod.rs index 17ee7a78c8..f5947a60b3 100644 --- a/crates/syn-solidity/src/stmt/mod.rs +++ b/crates/syn-solidity/src/stmt/mod.rs @@ -48,27 +48,57 @@ use syn::{ Result, Token, }; -/// A statement. +/// A statement, usually ending in a semicolon. /// /// Solidity reference: /// #[derive(Clone, Debug)] pub enum Stmt { + /// An assembly block, with optional flags: `assembly "evmasm" { ... }`. + Assembly(StmtAssembly), + + /// A blocked scope: `{ ... }`. Block(Block), - UncheckedBlock(UncheckedBlock), - VarDecl(StmtVarDecl), + + /// A break statement: `break;`. + Break(StmtBreak), + + /// A continue statement: `continue;`. + Continue(StmtContinue), + + /// A do-while statement: `do { ... } while (condition);`. + DoWhile(StmtDoWhile), + + /// An emit statement: `emit FooBar(42);`. + Emit(StmtEmit), + + /// An expression with a trailing semicolon. Expr(StmtExpr), - If(StmtIf), + + /// A for statement: `for (uint256 i; i < 42; ++i) { ... }`. For(StmtFor), - While(StmtWhile), - DoWhile(StmtDoWhile), - Continue(StmtContinue), - Break(StmtBreak), - Try(StmtTry), + + /// An `if` statement with an optional `else` block: `if (expr) { ... } else + /// { ... }`. + If(StmtIf), + + /// A return statement: `return 42;`. Return(StmtReturn), - Emit(StmtEmit), + + /// A revert statement: `revert("error");`. Revert(StmtRevert), - Assembly(StmtAssembly), + + /// A try statement: `try fooBar(42) catch { ... }`. + Try(StmtTry), + + /// An unchecked block: `unchecked { ... }`. + UncheckedBlock(UncheckedBlock), + + /// A variable declaration statement: `uint256 foo = 42;`. + VarDecl(StmtVarDecl), + + /// A while statement: `while (i < 42) { ... }`. + While(StmtWhile), } impl Parse for Stmt { @@ -131,41 +161,41 @@ impl Parse for Stmt { impl Stmt { pub fn span(&self) -> Span { match self { - Stmt::Block(block) => block.span(), - Stmt::UncheckedBlock(block) => block.span(), - Stmt::VarDecl(stmt) => stmt.span(), - Stmt::Expr(stmt) => stmt.span(), - Stmt::If(stmt) => stmt.span(), - Stmt::For(stmt) => stmt.span(), - Stmt::While(stmt) => stmt.span(), - Stmt::DoWhile(stmt) => stmt.span(), - Stmt::Continue(stmt) => stmt.span(), - Stmt::Break(stmt) => stmt.span(), - Stmt::Try(stmt) => stmt.span(), - Stmt::Return(stmt) => stmt.span(), - Stmt::Emit(stmt) => stmt.span(), - Stmt::Revert(stmt) => stmt.span(), - Stmt::Assembly(stmt) => stmt.span(), + Self::Assembly(stmt) => stmt.span(), + Self::Block(block) => block.span(), + Self::Break(stmt) => stmt.span(), + Self::Continue(stmt) => stmt.span(), + Self::DoWhile(stmt) => stmt.span(), + Self::Emit(stmt) => stmt.span(), + Self::Expr(stmt) => stmt.span(), + Self::For(stmt) => stmt.span(), + Self::If(stmt) => stmt.span(), + Self::Return(stmt) => stmt.span(), + Self::Revert(stmt) => stmt.span(), + Self::Try(stmt) => stmt.span(), + Self::UncheckedBlock(block) => block.span(), + Self::VarDecl(stmt) => stmt.span(), + Self::While(stmt) => stmt.span(), } } pub fn set_span(&mut self, span: Span) { match self { - Stmt::Block(block) => block.set_span(span), - Stmt::UncheckedBlock(block) => block.set_span(span), - Stmt::VarDecl(stmt) => stmt.set_span(span), - Stmt::Expr(stmt) => stmt.set_span(span), - Stmt::If(stmt) => stmt.set_span(span), - Stmt::For(stmt) => stmt.set_span(span), - Stmt::While(stmt) => stmt.set_span(span), - Stmt::DoWhile(stmt) => stmt.set_span(span), - Stmt::Continue(stmt) => stmt.set_span(span), - Stmt::Break(stmt) => stmt.set_span(span), - Stmt::Try(stmt) => stmt.set_span(span), - Stmt::Return(stmt) => stmt.set_span(span), - Stmt::Emit(stmt) => stmt.set_span(span), - Stmt::Revert(stmt) => stmt.set_span(span), - Stmt::Assembly(stmt) => stmt.set_span(span), + Self::Assembly(stmt) => stmt.set_span(span), + Self::Block(block) => block.set_span(span), + Self::Break(stmt) => stmt.set_span(span), + Self::Continue(stmt) => stmt.set_span(span), + Self::DoWhile(stmt) => stmt.set_span(span), + Self::Emit(stmt) => stmt.set_span(span), + Self::Expr(stmt) => stmt.set_span(span), + Self::For(stmt) => stmt.set_span(span), + Self::If(stmt) => stmt.set_span(span), + Self::Return(stmt) => stmt.set_span(span), + Self::Revert(stmt) => stmt.set_span(span), + Self::Try(stmt) => stmt.set_span(span), + Self::UncheckedBlock(block) => block.set_span(span), + Self::VarDecl(stmt) => stmt.set_span(span), + Self::While(stmt) => stmt.set_span(span), } } } diff --git a/crates/syn-solidity/src/stmt/return.rs b/crates/syn-solidity/src/stmt/return.rs index a31c9b66f8..e53dd47f72 100644 --- a/crates/syn-solidity/src/stmt/return.rs +++ b/crates/syn-solidity/src/stmt/return.rs @@ -6,7 +6,7 @@ use syn::{ Result, Token, }; -/// A return statement: `return 42;` +/// A return statement: `return 42;`. /// /// Solidity Reference: /// diff --git a/crates/syn-solidity/src/stmt/revert.rs b/crates/syn-solidity/src/stmt/revert.rs index 8195ad7934..63b894e894 100644 --- a/crates/syn-solidity/src/stmt/revert.rs +++ b/crates/syn-solidity/src/stmt/revert.rs @@ -1,4 +1,4 @@ -use crate::{kw, CallArgumentList, Expr}; +use crate::{kw, ArgList, Expr}; use proc_macro2::Span; use std::fmt; use syn::{ @@ -6,7 +6,7 @@ use syn::{ Result, Token, }; -/// A revert statement: `revert("error");` +/// A revert statement: `revert("error");`. /// /// Solidity Reference: /// @@ -14,7 +14,7 @@ use syn::{ pub struct StmtRevert { pub revert_token: kw::revert, pub expr: Expr, - pub list: CallArgumentList, + pub list: ArgList, pub semi_token: Token![;], } diff --git a/crates/syn-solidity/src/stmt/try.rs b/crates/syn-solidity/src/stmt/try.rs index b5ce8388af..7d88c10a9b 100644 --- a/crates/syn-solidity/src/stmt/try.rs +++ b/crates/syn-solidity/src/stmt/try.rs @@ -8,7 +8,7 @@ use syn::{ Result, Token, }; -/// A try statement: `try fooBar(42) catch { ... }` +/// A try statement: `try fooBar(42) catch { ... }`. /// /// Solidity reference: /// @@ -64,7 +64,7 @@ impl StmtTry { } } -/// A catch clause of a [`StmtTry`]: `catch { ... }` +/// A catch clause of a [`StmtTry`]: `catch { ... }`. /// /// Solidity reference: /// diff --git a/crates/syn-solidity/src/stmt/var_decl.rs b/crates/syn-solidity/src/stmt/var_decl.rs index f9aa8252ac..f9e5fc14fa 100644 --- a/crates/syn-solidity/src/stmt/var_decl.rs +++ b/crates/syn-solidity/src/stmt/var_decl.rs @@ -9,7 +9,7 @@ use syn::{ Result, Token, }; -/// A variable declaration statement: `uint256 foo = 42;` +/// A variable declaration statement: `uint256 foo = 42;`. /// /// Solidity Reference: /// @@ -97,7 +97,7 @@ impl VarDeclDecl { } } -/// A declaration of variables in a tuple: `(,,uint256 foo,string memory bar)` +/// A declaration of variables in a tuple: `(,,uint256 foo,string memory bar)`. /// /// Solidity Reference: /// diff --git a/crates/syn-solidity/src/stmt/while.rs b/crates/syn-solidity/src/stmt/while.rs index 4bb31e9039..01cf640911 100644 --- a/crates/syn-solidity/src/stmt/while.rs +++ b/crates/syn-solidity/src/stmt/while.rs @@ -7,7 +7,7 @@ use syn::{ Result, Token, }; -/// A while statement: `while (i < 42) { ... }` +/// A while statement: `while (i < 42) { ... }`. /// /// #[derive(Clone)] diff --git a/crates/syn-solidity/src/type/function.rs b/crates/syn-solidity/src/type/function.rs index 966121c123..644fbd0b39 100644 --- a/crates/syn-solidity/src/type/function.rs +++ b/crates/syn-solidity/src/type/function.rs @@ -11,7 +11,7 @@ use syn::{ Result, }; -/// A function type: `function() returns (string memory)` +/// A function type: `function() returns (string memory)`. /// /// Solidity reference: /// diff --git a/crates/syn-solidity/src/type/mod.rs b/crates/syn-solidity/src/type/mod.rs index f0927330f6..f94aede74e 100644 --- a/crates/syn-solidity/src/type/mod.rs +++ b/crates/syn-solidity/src/type/mod.rs @@ -268,7 +268,7 @@ impl Type { match self { Self::Custom(_) => true, Self::Array(a) => a.ty.has_custom(), - Self::Tuple(t) => t.types.iter().any(Type::has_custom), + Self::Tuple(t) => t.types.iter().any(Self::has_custom), Self::Function(f) => { f.arguments.iter().any(|arg| arg.ty.has_custom()) || f.returns.as_ref().map_or(false, |ret| { diff --git a/crates/syn-solidity/src/type/tuple.rs b/crates/syn-solidity/src/type/tuple.rs index bc577ba983..3236e33e9a 100644 --- a/crates/syn-solidity/src/type/tuple.rs +++ b/crates/syn-solidity/src/type/tuple.rs @@ -79,7 +79,7 @@ impl Parse for TypeTuple { impl FromIterator for TypeTuple { fn from_iter>(iter: T) -> Self { - TypeTuple { + Self { tuple_token: None, paren_token: Paren::default(), types: { diff --git a/crates/syn-solidity/src/utils.rs b/crates/syn-solidity/src/utils.rs index 72ad21095a..eea560c459 100644 --- a/crates/syn-solidity/src/utils.rs +++ b/crates/syn-solidity/src/utils.rs @@ -1,4 +1,5 @@ -use proc_macro2::{TokenStream, TokenTree}; +use crate::Spanned; +use proc_macro2::{Span, TokenStream, TokenTree}; use std::fmt; use syn::{ parse::{Parse, ParseStream}, @@ -32,13 +33,32 @@ pub(crate) fn tts_until_semi(input: ParseStream<'_>) -> TokenStream { } pub(crate) fn parse_vec(input: ParseStream<'_>, allow_empty: bool) -> Result> { - let mut vec = Vec::::new(); + let mut vec = Vec::new(); + if !allow_empty { + vec.push(input.parse()?); + } while !input.is_empty() { vec.push(input.parse()?); } - if !allow_empty && vec.is_empty() { - Err(input.parse::().err().expect("unreachable")) - } else { - Ok(vec) + Ok(vec) +} + +pub(crate) fn _join_spans>(items: I) -> Span { + let mut iter = items.into_iter(); + let Some(first) = iter.next() else { + return Span::call_site() + }; + let first = first.span(); + iter.last() + .and_then(|last| first.join(last.span())) + .unwrap_or(first) +} + +pub(crate) fn _set_spans<'a, T: Spanned + 'a, I: IntoIterator>( + items: I, + set_to: Span, +) { + for item in items { + item.set_span(set_to); } } From bf8425c257cb3b9c915fd60695792a0446423408 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Fri, 4 Aug 2023 19:59:50 +0200 Subject: [PATCH 13/22] feat: spanned --- crates/sol-macro/src/expand/enum.rs | 2 +- crates/sol-macro/src/expand/event.rs | 2 +- crates/sol-macro/src/expand/mod.rs | 11 ++- crates/sol-macro/src/expand/struct.rs | 2 +- crates/sol-macro/src/expand/ty.rs | 2 +- crates/sol-macro/src/input.rs | 1 + crates/syn-solidity/src/attribute/function.rs | 20 ++++- crates/syn-solidity/src/attribute/mod.rs | 14 +-- crates/syn-solidity/src/attribute/variable.rs | 20 ++++- crates/syn-solidity/src/expr/args.rs | 38 ++++----- crates/syn-solidity/src/expr/array.rs | 14 +-- crates/syn-solidity/src/expr/binary.rs | 8 +- crates/syn-solidity/src/expr/member.rs | 8 +- crates/syn-solidity/src/expr/mod.rs | 8 +- crates/syn-solidity/src/expr/ternary.rs | 8 +- crates/syn-solidity/src/expr/tuple.rs | 8 +- crates/syn-solidity/src/expr/type.rs | 14 +-- crates/syn-solidity/src/expr/unary.rs | 20 ++--- crates/syn-solidity/src/file.rs | 13 ++- crates/syn-solidity/src/ident/mod.rs | 36 ++++---- crates/syn-solidity/src/ident/path.rs | 29 +++---- crates/syn-solidity/src/item/contract.rs | 39 +++++---- crates/syn-solidity/src/item/enum.rs | 10 ++- crates/syn-solidity/src/item/error.rs | 10 ++- crates/syn-solidity/src/item/event.rs | 20 +++-- crates/syn-solidity/src/item/function.rs | 57 +++++++------ crates/syn-solidity/src/item/import.rs | 42 ++++----- crates/syn-solidity/src/item/mod.rs | 10 ++- crates/syn-solidity/src/item/pragma.rs | 15 ++-- crates/syn-solidity/src/item/struct.rs | 10 ++- crates/syn-solidity/src/item/udt.rs | 8 +- crates/syn-solidity/src/item/using.rs | 56 +++++++++++- crates/syn-solidity/src/kw.rs | 18 +++- crates/syn-solidity/src/lit/mod.rs | 18 ++-- crates/syn-solidity/src/lit/str.rs | 32 +++---- crates/syn-solidity/src/macros.rs | 62 ++++++++------ crates/syn-solidity/src/spanned.rs | 85 +++++++++++++++---- crates/syn-solidity/src/stmt/assembly.rs | 18 +++- crates/syn-solidity/src/stmt/blocks.rs | 14 +-- crates/syn-solidity/src/stmt/break.rs | 7 +- crates/syn-solidity/src/stmt/continue.rs | 7 +- crates/syn-solidity/src/stmt/do_while.rs | 8 +- crates/syn-solidity/src/stmt/emit.rs | 8 +- crates/syn-solidity/src/stmt/expr.rs | 8 +- crates/syn-solidity/src/stmt/for.rs | 8 +- crates/syn-solidity/src/stmt/if.rs | 8 +- crates/syn-solidity/src/stmt/mod.rs | 8 +- crates/syn-solidity/src/stmt/return.rs | 8 +- crates/syn-solidity/src/stmt/revert.rs | 8 +- crates/syn-solidity/src/stmt/try.rs | 14 +-- crates/syn-solidity/src/stmt/var_decl.rs | 22 ++--- crates/syn-solidity/src/stmt/while.rs | 8 +- crates/syn-solidity/src/type/array.rs | 10 ++- crates/syn-solidity/src/type/function.rs | 8 +- crates/syn-solidity/src/type/mapping.rs | 8 +- crates/syn-solidity/src/type/mod.rs | 34 ++++---- crates/syn-solidity/src/type/tuple.rs | 10 ++- crates/syn-solidity/src/utils.rs | 28 ++++-- crates/syn-solidity/src/variable/list.rs | 14 ++- crates/syn-solidity/src/variable/mod.rs | 51 +++++------ crates/syn-solidity/src/yul/block.rs | 7 +- 61 files changed, 664 insertions(+), 430 deletions(-) diff --git a/crates/sol-macro/src/expand/enum.rs b/crates/sol-macro/src/expand/enum.rs index 3627c2b594..d0be6f9e30 100644 --- a/crates/sol-macro/src/expand/enum.rs +++ b/crates/sol-macro/src/expand/enum.rs @@ -1,7 +1,7 @@ //! [`ItemEnum`] expansion. use super::ExpCtxt; -use ast::ItemEnum; +use ast::{ItemEnum, Spanned}; use proc_macro2::TokenStream; use quote::quote; use syn::Result; diff --git a/crates/sol-macro/src/expand/event.rs b/crates/sol-macro/src/expand/event.rs index c2dee10aa9..81b1965b0b 100644 --- a/crates/sol-macro/src/expand/event.rs +++ b/crates/sol-macro/src/expand/event.rs @@ -2,7 +2,7 @@ use super::{anon_name, expand_tuple_types, expand_type, ExpCtxt}; use crate::expand::ty::expand_event_tokenize_func; -use ast::{EventParameter, ItemEvent, SolIdent}; +use ast::{EventParameter, ItemEvent, SolIdent, Spanned}; use proc_macro2::TokenStream; use quote::{quote, quote_spanned}; use syn::Result; diff --git a/crates/sol-macro/src/expand/mod.rs b/crates/sol-macro/src/expand/mod.rs index 624404e73b..05ab6cfeb9 100644 --- a/crates/sol-macro/src/expand/mod.rs +++ b/crates/sol-macro/src/expand/mod.rs @@ -5,11 +5,11 @@ use crate::{ utils::ExprArray, }; use ast::{ - File, Item, ItemError, ItemEvent, ItemFunction, Parameters, SolIdent, SolPath, Type, + File, Item, ItemError, ItemEvent, ItemFunction, Parameters, SolIdent, SolPath, Spanned, Type, VariableDeclaration, Visit, }; use proc_macro2::{Ident, Span, TokenStream}; -use quote::{format_ident, quote, IdentFragment}; +use quote::{format_ident, quote}; use std::{borrow::Borrow, collections::HashMap, fmt::Write}; use syn::{parse_quote, Attribute, Error, Result}; @@ -329,7 +329,7 @@ impl ExpCtxt<'_> { } } - fn raw_call_name(&self, function_name: impl IdentFragment + std::fmt::Display) -> Ident { + fn raw_call_name(&self, function_name: impl quote::IdentFragment + std::fmt::Display) -> Ident { format_ident!("{function_name}Call") } @@ -338,7 +338,10 @@ impl ExpCtxt<'_> { self.raw_call_name(function_name) } - fn raw_return_name(&self, function_name: impl IdentFragment + std::fmt::Display) -> Ident { + fn raw_return_name( + &self, + function_name: impl quote::IdentFragment + std::fmt::Display, + ) -> Ident { format_ident!("{function_name}Return") } diff --git a/crates/sol-macro/src/expand/struct.rs b/crates/sol-macro/src/expand/struct.rs index ce32f42002..988e0d0e53 100644 --- a/crates/sol-macro/src/expand/struct.rs +++ b/crates/sol-macro/src/expand/struct.rs @@ -3,7 +3,7 @@ use super::{ expand_fields, expand_from_into_tuples, expand_type, ty::expand_tokenize_func, ExpCtxt, }; -use ast::{Item, ItemStruct, Type, VariableDeclaration}; +use ast::{Item, ItemStruct, Spanned, Type, VariableDeclaration}; use proc_macro2::TokenStream; use quote::quote; use std::num::NonZeroU16; diff --git a/crates/sol-macro/src/expand/ty.rs b/crates/sol-macro/src/expand/ty.rs index f37ea50570..60b887e626 100644 --- a/crates/sol-macro/src/expand/ty.rs +++ b/crates/sol-macro/src/expand/ty.rs @@ -2,7 +2,7 @@ use super::ExpCtxt; use crate::expand::generate_name; -use ast::{EventParameter, Item, Parameters, Type, TypeArray, VariableDeclaration}; +use ast::{EventParameter, Item, Parameters, Spanned, Type, TypeArray, VariableDeclaration}; use proc_macro2::{Literal, TokenStream}; use quote::{quote, quote_spanned, ToTokens}; use std::{fmt, num::NonZeroU16}; diff --git a/crates/sol-macro/src/input.rs b/crates/sol-macro/src/input.rs index bb6eb619b2..705d57d532 100644 --- a/crates/sol-macro/src/input.rs +++ b/crates/sol-macro/src/input.rs @@ -1,3 +1,4 @@ +use ast::Spanned; use proc_macro2::TokenStream; use quote::quote; use std::path::PathBuf; diff --git a/crates/syn-solidity/src/attribute/function.rs b/crates/syn-solidity/src/attribute/function.rs index 4bbfe9aa2b..4b5e40cd81 100644 --- a/crates/syn-solidity/src/attribute/function.rs +++ b/crates/syn-solidity/src/attribute/function.rs @@ -1,4 +1,4 @@ -use super::{kw, Modifier, Mutability, Override, SolPath, VariableAttribute, Visibility}; +use crate::{kw, Modifier, Mutability, Override, SolPath, Spanned, VariableAttribute, Visibility}; use proc_macro2::Span; use std::{ collections::HashSet, @@ -53,6 +53,16 @@ impl Parse for FunctionAttributes { } } +impl Spanned for FunctionAttributes { + fn span(&self) -> Span { + crate::utils::join_spans(&self.0) + } + + fn set_span(&mut self, span: Span) { + crate::utils::set_spans_clone(&mut self.0, span) + } +} + impl FunctionAttributes { #[inline] pub fn new() -> Self { @@ -206,8 +216,8 @@ impl From for FunctionAttribute { } } -impl FunctionAttribute { - pub fn span(&self) -> Span { +impl Spanned for FunctionAttribute { + fn span(&self) -> Span { match self { Self::Visibility(v) => v.span(), Self::Mutability(m) => m.span(), @@ -218,7 +228,7 @@ impl FunctionAttribute { } } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { match self { Self::Visibility(v) => v.set_span(span), Self::Mutability(m) => m.set_span(span), @@ -228,7 +238,9 @@ impl FunctionAttribute { Self::Modifier(m) => m.set_span(span), } } +} +impl FunctionAttribute { #[inline] pub const fn visibility(&self) -> Option { match self { diff --git a/crates/syn-solidity/src/attribute/mod.rs b/crates/syn-solidity/src/attribute/mod.rs index 39789a9dbe..c83c1d7be7 100644 --- a/crates/syn-solidity/src/attribute/mod.rs +++ b/crates/syn-solidity/src/attribute/mod.rs @@ -1,4 +1,4 @@ -use super::{kw, utils::DebugPunctuated, SolPath}; +use crate::{kw, utils::DebugPunctuated, SolPath, Spanned}; use proc_macro2::{Span, TokenStream}; use std::{ fmt, @@ -112,15 +112,15 @@ impl Parse for Override { } } -impl Override { - pub fn span(&self) -> Span { +impl Spanned for Override { + fn span(&self) -> Span { let span = self.override_token.span; self.paren_token .and_then(|paren_token| span.join(paren_token.span.join())) .unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.override_token.span = span; if let Some(paren_token) = &mut self.paren_token { *paren_token = Paren(span); @@ -200,15 +200,15 @@ impl Parse for Modifier { } } -impl Modifier { - pub fn span(&self) -> Span { +impl Spanned for Modifier { + fn span(&self) -> Span { let span = self.name.span(); self.paren_token .and_then(|paren_token| span.join(paren_token.span.join())) .unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.name.set_span(span); if let Some(paren_token) = &mut self.paren_token { *paren_token = Paren(span); diff --git a/crates/syn-solidity/src/attribute/variable.rs b/crates/syn-solidity/src/attribute/variable.rs index 0f04eda240..49b0b0c742 100644 --- a/crates/syn-solidity/src/attribute/variable.rs +++ b/crates/syn-solidity/src/attribute/variable.rs @@ -1,4 +1,4 @@ -use super::{kw, Override, SolPath, Visibility}; +use crate::{kw, Override, SolPath, Spanned, Visibility}; use proc_macro2::Span; use std::{ collections::HashSet, @@ -53,6 +53,16 @@ impl Parse for VariableAttributes { } } +impl Spanned for VariableAttributes { + fn span(&self) -> Span { + crate::utils::join_spans(&self.0) + } + + fn set_span(&mut self, span: Span) { + crate::utils::set_spans_clone(&mut self.0, span) + } +} + impl VariableAttributes { pub fn visibility(&self) -> Option { self.0.iter().find_map(VariableAttribute::visibility) @@ -142,8 +152,8 @@ impl Parse for VariableAttribute { } } -impl VariableAttribute { - pub fn span(&self) -> Span { +impl Spanned for VariableAttribute { + fn span(&self) -> Span { match self { Self::Visibility(v) => v.span(), Self::Constant(c) => c.span, @@ -152,7 +162,7 @@ impl VariableAttribute { } } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { match self { Self::Visibility(v) => v.set_span(span), Self::Constant(c) => c.span = span, @@ -160,7 +170,9 @@ impl VariableAttribute { Self::Immutable(i) => i.span = span, } } +} +impl VariableAttribute { #[inline] pub const fn visibility(&self) -> Option { match self { diff --git a/crates/syn-solidity/src/expr/args.rs b/crates/syn-solidity/src/expr/args.rs index a2b07d58ac..d2262b5707 100644 --- a/crates/syn-solidity/src/expr/args.rs +++ b/crates/syn-solidity/src/expr/args.rs @@ -1,4 +1,4 @@ -use crate::{kw, Expr, SolIdent}; +use crate::{kw, Expr, SolIdent, Spanned}; use proc_macro2::Span; use std::fmt; use syn::{ @@ -25,13 +25,13 @@ impl Parse for ExprCall { } } -impl ExprCall { - pub fn span(&self) -> Span { +impl Spanned for ExprCall { + fn span(&self) -> Span { let span = self.expr.span(); span.join(self.args.span()).unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.expr.set_span(span); self.args.set_span(span); } @@ -73,13 +73,13 @@ impl Parse for ExprPayable { } } -impl ExprPayable { - pub fn span(&self) -> Span { +impl Spanned for ExprPayable { + fn span(&self) -> Span { let span = self.payable_token.span; span.join(self.args.span()).unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.payable_token.span = span; self.args.set_span(span); } @@ -116,12 +116,12 @@ impl Parse for ArgList { } } -impl ArgList { - pub fn span(&self) -> Span { +impl Spanned for ArgList { + fn span(&self) -> Span { self.paren_token.span.join() } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.paren_token = Paren(span); } } @@ -161,13 +161,13 @@ impl Parse for ExprStruct { } } -impl ExprStruct { - pub fn span(&self) -> Span { +impl Spanned for ExprStruct { + fn span(&self) -> Span { let span = self.expr.span(); span.join(self.args.span()).unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.expr.set_span(span); self.args.set_span(span); } @@ -198,12 +198,12 @@ impl Parse for NamedArgList { } } -impl NamedArgList { - pub fn span(&self) -> Span { +impl Spanned for NamedArgList { + fn span(&self) -> Span { self.brace_token.span.join() } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.brace_token = Brace(span); } } @@ -235,13 +235,13 @@ impl Parse for NamedArg { } } -impl NamedArg { - pub fn span(&self) -> Span { +impl Spanned for NamedArg { + fn span(&self) -> Span { let span = self.name.span(); span.join(self.arg.span()).unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.name.set_span(span); self.arg.set_span(span); } diff --git a/crates/syn-solidity/src/expr/array.rs b/crates/syn-solidity/src/expr/array.rs index 66006fa12e..11fd9fe00a 100644 --- a/crates/syn-solidity/src/expr/array.rs +++ b/crates/syn-solidity/src/expr/array.rs @@ -1,4 +1,4 @@ -use crate::Expr; +use crate::{Expr, Spanned}; use proc_macro2::Span; use std::fmt; use syn::{ @@ -34,12 +34,12 @@ impl Parse for ExprArray { } } -impl ExprArray { - pub fn span(&self) -> Span { +impl Spanned for ExprArray { + fn span(&self) -> Span { self.bracket_token.span.join() } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.bracket_token = Bracket(span); } } @@ -83,13 +83,13 @@ impl Parse for ExprIndex { } } -impl ExprIndex { - pub fn span(&self) -> Span { +impl Spanned for ExprIndex { + fn span(&self) -> Span { let span = self.expr.span(); span.join(self.bracket_token.span.join()).unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.expr.set_span(span); self.bracket_token = Bracket(span); } diff --git a/crates/syn-solidity/src/expr/binary.rs b/crates/syn-solidity/src/expr/binary.rs index 3d7d1226e2..75e7fa45e8 100644 --- a/crates/syn-solidity/src/expr/binary.rs +++ b/crates/syn-solidity/src/expr/binary.rs @@ -1,4 +1,4 @@ -use crate::Expr; +use crate::{Expr, Spanned}; use proc_macro2::Span; use syn::{ parse::{Parse, ParseStream}, @@ -23,13 +23,13 @@ impl Parse for ExprBinary { } } -impl ExprBinary { - pub fn span(&self) -> Span { +impl Spanned for ExprBinary { + fn span(&self) -> Span { let span = self.left.span(); span.join(self.right.span()).unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.left.set_span(span); self.right.set_span(span); } diff --git a/crates/syn-solidity/src/expr/member.rs b/crates/syn-solidity/src/expr/member.rs index 0f3d612be5..2ba050dc2d 100644 --- a/crates/syn-solidity/src/expr/member.rs +++ b/crates/syn-solidity/src/expr/member.rs @@ -1,4 +1,4 @@ -use crate::Expr; +use crate::{Expr, Spanned}; use proc_macro2::Span; use std::fmt; use syn::{ @@ -33,8 +33,8 @@ impl Parse for ExprMember { } } -impl ExprMember { - pub fn span(&self) -> Span { +impl Spanned for ExprMember { + fn span(&self) -> Span { self.expr .span() .join(self.member.span()) @@ -46,7 +46,7 @@ impl ExprMember { }) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.expr.set_span(span); } } diff --git a/crates/syn-solidity/src/expr/mod.rs b/crates/syn-solidity/src/expr/mod.rs index 6d22425a79..8ed4e95f4b 100644 --- a/crates/syn-solidity/src/expr/mod.rs +++ b/crates/syn-solidity/src/expr/mod.rs @@ -30,7 +30,7 @@ pub use r#type::{ExprNew, ExprTypeCall}; mod unary; pub use unary::{ExprDelete, ExprPostfix, ExprUnary, PostUnOp, UnOp}; -use crate::{kw, Lit, SolIdent, Type}; +use crate::{kw, Lit, SolIdent, Spanned, Type}; /// An expression. /// @@ -151,8 +151,10 @@ impl Expr { Err(lookahead.error()) } } +} - pub fn span(&self) -> Span { +impl Spanned for Expr { + fn span(&self) -> Span { match self { Self::Index(expr) => expr.span(), Self::Member(expr) => expr.span(), @@ -174,7 +176,7 @@ impl Expr { } } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { match self { Self::Index(expr) => expr.set_span(span), Self::Member(expr) => expr.set_span(span), diff --git a/crates/syn-solidity/src/expr/ternary.rs b/crates/syn-solidity/src/expr/ternary.rs index 98c24d2b65..05aba9d246 100644 --- a/crates/syn-solidity/src/expr/ternary.rs +++ b/crates/syn-solidity/src/expr/ternary.rs @@ -1,4 +1,4 @@ -use crate::Expr; +use crate::{Expr, Spanned}; use proc_macro2::Span; use std::fmt; use syn::{ @@ -38,13 +38,13 @@ impl Parse for ExprTernary { } } -impl ExprTernary { - pub fn span(&self) -> Span { +impl Spanned for ExprTernary { + fn span(&self) -> Span { let span = self.cond.span(); span.join(self.if_false.span()).unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.cond.set_span(span); self.if_false.set_span(span); } diff --git a/crates/syn-solidity/src/expr/tuple.rs b/crates/syn-solidity/src/expr/tuple.rs index 46ffb0dbe3..b77a28bab2 100644 --- a/crates/syn-solidity/src/expr/tuple.rs +++ b/crates/syn-solidity/src/expr/tuple.rs @@ -1,4 +1,4 @@ -use crate::Expr; +use crate::{Expr, Spanned}; use proc_macro2::Span; use std::fmt; use syn::{ @@ -34,12 +34,12 @@ impl Parse for ExprTuple { } } -impl ExprTuple { - pub fn span(&self) -> Span { +impl Spanned for ExprTuple { + fn span(&self) -> Span { self.paren_token.span.join() } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.paren_token = Paren(span); } } diff --git a/crates/syn-solidity/src/expr/type.rs b/crates/syn-solidity/src/expr/type.rs index fda7f84d38..01e5f94f45 100644 --- a/crates/syn-solidity/src/expr/type.rs +++ b/crates/syn-solidity/src/expr/type.rs @@ -1,4 +1,4 @@ -use crate::{kw, Type}; +use crate::{kw, Spanned, Type}; use proc_macro2::Span; use std::fmt; use syn::{ @@ -35,13 +35,13 @@ impl Parse for ExprTypeCall { } } -impl ExprTypeCall { - pub fn span(&self) -> Span { +impl Spanned for ExprTypeCall { + fn span(&self) -> Span { let span = self.type_token.span; span.join(self.paren_token.span.join()).unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.type_token.span = span; self.paren_token = Paren(span); } @@ -71,13 +71,13 @@ impl Parse for ExprNew { } } -impl ExprNew { - pub fn span(&self) -> Span { +impl Spanned for ExprNew { + fn span(&self) -> Span { let span = self.new_token.span; span.join(self.ty.span()).unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.new_token.span = span; self.ty.set_span(span); } diff --git a/crates/syn-solidity/src/expr/unary.rs b/crates/syn-solidity/src/expr/unary.rs index 807a5ec07d..2b785179ea 100644 --- a/crates/syn-solidity/src/expr/unary.rs +++ b/crates/syn-solidity/src/expr/unary.rs @@ -1,4 +1,4 @@ -use crate::{kw, Expr}; +use crate::{kw, Expr, Spanned}; use proc_macro2::Span; use std::fmt; use syn::{ @@ -22,13 +22,13 @@ impl Parse for ExprUnary { } } -impl ExprUnary { - pub fn span(&self) -> Span { +impl Spanned for ExprUnary { + fn span(&self) -> Span { let span = self.op.span(); span.join(self.expr.span()).unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.op.set_span(span); self.expr.set_span(span); } @@ -58,13 +58,13 @@ impl Parse for ExprDelete { } } -impl ExprDelete { - pub fn span(&self) -> Span { +impl Spanned for ExprDelete { + fn span(&self) -> Span { let span = self.delete_token.span; span.join(self.expr.span()).unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.delete_token.span = span; self.expr.set_span(span); } @@ -86,13 +86,13 @@ impl Parse for ExprPostfix { } } -impl ExprPostfix { - pub fn span(&self) -> Span { +impl Spanned for ExprPostfix { + fn span(&self) -> Span { let span = self.op.span(); span.join(self.expr.span()).unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.op.set_span(span); self.expr.set_span(span); } diff --git a/crates/syn-solidity/src/file.rs b/crates/syn-solidity/src/file.rs index 5597325e84..eefb37399e 100644 --- a/crates/syn-solidity/src/file.rs +++ b/crates/syn-solidity/src/file.rs @@ -1,4 +1,5 @@ -use super::Item; +use crate::{Item, Spanned}; +use proc_macro2::Span; use syn::{ parse::{Parse, ParseStream}, Attribute, Result, @@ -27,3 +28,13 @@ impl Parse for File { } } } + +impl Spanned for File { + fn span(&self) -> Span { + crate::utils::join_spans(&self.items) + } + + fn set_span(&mut self, span: Span) { + crate::utils::set_spans(&mut self.items, span); + } +} diff --git a/crates/syn-solidity/src/ident/mod.rs b/crates/syn-solidity/src/ident/mod.rs index c2f8b39fe2..cbddd14d16 100644 --- a/crates/syn-solidity/src/ident/mod.rs +++ b/crates/syn-solidity/src/ident/mod.rs @@ -10,6 +10,8 @@ use syn::{ mod path; pub use path::SolPath; +use crate::Spanned; + /// A Solidity identifier. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(transparent)] @@ -21,7 +23,7 @@ impl quote::IdentFragment for SolIdent { } fn span(&self) -> Option { - Some(self.span()) + Some(self.0.span()) } } @@ -43,6 +45,18 @@ impl> PartialEq for SolIdent { } } +impl From for SolIdent { + fn from(value: Ident) -> Self { + Self(value) + } +} + +impl From for Ident { + fn from(value: SolIdent) -> Self { + value.0 + } +} + impl Parse for SolIdent { fn parse(input: ParseStream<'_>) -> Result { input.call(Ident::parse_any).map(Self) @@ -55,15 +69,13 @@ impl ToTokens for SolIdent { } } -impl From for SolIdent { - fn from(value: Ident) -> Self { - Self(value) +impl Spanned for SolIdent { + fn span(&self) -> Span { + self.0.span() } -} -impl From for Ident { - fn from(value: SolIdent) -> Self { - value.0 + fn set_span(&mut self, span: Span) { + self.0.set_span(span); } } @@ -76,14 +88,6 @@ impl SolIdent { Self(Ident::new(s, span)) } - pub fn span(&self) -> Span { - self.0.span() - } - - pub fn set_span(&mut self, span: Span) { - self.0.set_span(span); - } - /// Returns the identifier as a string, without the `r#` prefix if present. pub fn as_string(&self) -> String { let mut s = self.0.to_string(); diff --git a/crates/syn-solidity/src/ident/path.rs b/crates/syn-solidity/src/ident/path.rs index e957057867..db32097e8d 100644 --- a/crates/syn-solidity/src/ident/path.rs +++ b/crates/syn-solidity/src/ident/path.rs @@ -1,4 +1,4 @@ -use super::SolIdent; +use crate::{SolIdent, Spanned}; use proc_macro2::{Ident, Span}; use std::{ fmt, @@ -98,6 +98,16 @@ impl Parse for SolPath { } } +impl Spanned for SolPath { + fn span(&self) -> Span { + crate::utils::join_spans(&self.0) + } + + fn set_span(&mut self, span: Span) { + crate::utils::set_spans(&mut self.0, span); + } +} + impl SolPath { pub const fn new() -> Self { Self(Punctuated::new()) @@ -127,21 +137,4 @@ impl SolPath { pub fn last_mut(&mut self) -> &mut SolIdent { self.0.last_mut().unwrap() } - - pub fn span(&self) -> Span { - let Some(first) = self.0.first() else { - return Span::call_site() - }; - let span = first.span(); - self.0 - .last() - .and_then(|last| span.join(last.span())) - .unwrap_or(span) - } - - pub fn set_span(&mut self, span: Span) { - for ident in self.0.iter_mut() { - ident.set_span(span); - } - } } diff --git a/crates/syn-solidity/src/item/contract.rs b/crates/syn-solidity/src/item/contract.rs index a7592b83d9..cf5d0b7cb6 100644 --- a/crates/syn-solidity/src/item/contract.rs +++ b/crates/syn-solidity/src/item/contract.rs @@ -1,5 +1,4 @@ -use super::Item; -use crate::{kw, utils::DebugPunctuated, Modifier, SolIdent}; +use crate::{kw, utils::DebugPunctuated, Item, Modifier, SolIdent, Spanned}; use proc_macro2::Span; use std::{cmp::Ordering, fmt}; use syn::{ @@ -74,15 +73,17 @@ impl Parse for ItemContract { } } -impl ItemContract { - pub fn span(&self) -> Span { +impl Spanned for ItemContract { + fn span(&self) -> Span { self.name.span() } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.name.set_span(span); } +} +impl ItemContract { /// Returns true if `self` is an abstract contract. pub fn is_abstract_contract(&self) -> bool { self.kind.is_abstract_contract() @@ -154,15 +155,8 @@ impl Parse for ContractKind { } } -impl ContractKind { - pub fn peek(lookahead: &Lookahead1<'_>) -> bool { - lookahead.peek(Token![abstract]) - || lookahead.peek(kw::contract) - || lookahead.peek(kw::interface) - || lookahead.peek(kw::library) - } - - pub fn span(self) -> Span { +impl Spanned for ContractKind { + fn span(&self) -> Span { match self { Self::AbstractContract(kw_abstract, kw_contract) => { let span = kw_abstract.span; @@ -174,7 +168,7 @@ impl ContractKind { } } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { match self { Self::AbstractContract(kw_abstract, kw_contract) => { kw_abstract.span = span; @@ -185,6 +179,15 @@ impl ContractKind { Self::Library(kw) => kw.span = span, } } +} + +impl ContractKind { + pub fn peek(lookahead: &Lookahead1<'_>) -> bool { + lookahead.peek(Token![abstract]) + || lookahead.peek(kw::contract) + || lookahead.peek(kw::interface) + || lookahead.peek(kw::library) + } /// Returns true if `self` is an abstract contract. pub fn is_abstract_contract(self) -> bool { @@ -278,8 +281,8 @@ impl Parse for Inheritance { } } -impl Inheritance { - pub fn span(&self) -> Span { +impl Spanned for Inheritance { + fn span(&self) -> Span { let span = self.is_token.span; self.inheritance .last() @@ -287,7 +290,7 @@ impl Inheritance { .unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.is_token.span = span; } } diff --git a/crates/syn-solidity/src/item/enum.rs b/crates/syn-solidity/src/item/enum.rs index 5ebe4d504b..9bfa149694 100644 --- a/crates/syn-solidity/src/item/enum.rs +++ b/crates/syn-solidity/src/item/enum.rs @@ -1,4 +1,4 @@ -use crate::{utils::DebugPunctuated, SolIdent, Type}; +use crate::{utils::DebugPunctuated, SolIdent, Spanned, Type}; use proc_macro2::Span; use std::{fmt, num::NonZeroU16}; use syn::{ @@ -45,15 +45,17 @@ impl Parse for ItemEnum { } } -impl ItemEnum { - pub fn span(&self) -> Span { +impl Spanned for ItemEnum { + fn span(&self) -> Span { self.name.span() } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.name.set_span(span); } +} +impl ItemEnum { pub fn as_type(&self) -> Type { Type::Uint(self.span(), Some(NonZeroU16::new(8).unwrap())) } diff --git a/crates/syn-solidity/src/item/error.rs b/crates/syn-solidity/src/item/error.rs index db4b8820bf..0db696eabd 100644 --- a/crates/syn-solidity/src/item/error.rs +++ b/crates/syn-solidity/src/item/error.rs @@ -1,4 +1,4 @@ -use crate::{kw, ParameterList, SolIdent, Type}; +use crate::{kw, ParameterList, SolIdent, Spanned, Type}; use proc_macro2::Span; use std::fmt; use syn::{ @@ -46,15 +46,17 @@ impl Parse for ItemError { } } -impl ItemError { - pub fn span(&self) -> Span { +impl Spanned for ItemError { + fn span(&self) -> Span { self.name.span() } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.name.set_span(span); } +} +impl ItemError { pub fn as_type(&self) -> Type { let mut ty = Type::Tuple(self.parameters.types().cloned().collect()); ty.set_span(self.span()); diff --git a/crates/syn-solidity/src/item/event.rs b/crates/syn-solidity/src/item/event.rs index 42234fcc8f..584246e5c8 100644 --- a/crates/syn-solidity/src/item/event.rs +++ b/crates/syn-solidity/src/item/event.rs @@ -1,4 +1,6 @@ -use crate::{kw, utils::DebugPunctuated, ParameterList, SolIdent, Type, VariableDeclaration}; +use crate::{ + kw, utils::DebugPunctuated, ParameterList, SolIdent, Spanned, Type, VariableDeclaration, +}; use proc_macro2::Span; use std::fmt; use syn::{ @@ -46,15 +48,17 @@ impl Parse for ItemEvent { } } -impl ItemEvent { - pub fn span(&self) -> Span { +impl Spanned for ItemEvent { + fn span(&self) -> Span { self.name.span() } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.name.set_span(span); } +} +impl ItemEvent { /// Returns `true` if the event is anonymous. #[inline] pub const fn is_anonymous(&self) -> bool { @@ -159,9 +163,9 @@ impl Parse for EventParameter { } } -impl EventParameter { +impl Spanned for EventParameter { /// Get the span of the event parameter - pub fn span(&self) -> Span { + fn span(&self) -> Span { let span = self.ty.span(); self.name .as_ref() @@ -170,7 +174,7 @@ impl EventParameter { } /// Sets the span of the event parameter. - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.ty.set_span(span); if let Some(kw) = &mut self.indexed { kw.span = span; @@ -179,7 +183,9 @@ impl EventParameter { name.set_span(span); } } +} +impl EventParameter { /// Convert to a parameter declaration. pub fn as_param(&self) -> VariableDeclaration { VariableDeclaration { diff --git a/crates/syn-solidity/src/item/function.rs b/crates/syn-solidity/src/item/function.rs index ce177ee549..510d1c79f0 100644 --- a/crates/syn-solidity/src/item/function.rs +++ b/crates/syn-solidity/src/item/function.rs @@ -1,5 +1,6 @@ use crate::{ - kw, Block, FunctionAttributes, ParameterList, Parameters, SolIdent, Type, VariableDefinition, + kw, Block, FunctionAttributes, ParameterList, Parameters, SolIdent, Spanned, Type, + VariableDefinition, }; use proc_macro2::Span; use std::{ @@ -62,6 +63,23 @@ impl Parse for ItemFunction { } } +impl Spanned for ItemFunction { + fn span(&self) -> Span { + if let Some(name) = &self.name { + name.span() + } else { + self.kind.span() + } + } + + fn set_span(&mut self, span: Span) { + self.kind.set_span(span); + if let Some(name) = &mut self.name { + name.set_span(span); + } + } +} + impl ItemFunction { pub fn new(kind: FunctionKind, name: Option) -> Self { let span = name @@ -101,21 +119,6 @@ impl ItemFunction { function } - pub fn span(&self) -> Span { - if let Some(name) = &self.name { - name.span() - } else { - self.kind.span() - } - } - - pub fn set_span(&mut self, span: Span) { - self.kind.set_span(span); - if let Some(name) = &mut self.name { - name.set_span(span); - } - } - /// Returns the name of the function. /// /// # Panics @@ -238,6 +241,18 @@ impl Parse for Returns { } } +impl Spanned for Returns { + fn span(&self) -> Span { + let span = self.returns_token.span; + span.join(self.paren_token.span.join()).unwrap_or(span) + } + + fn set_span(&mut self, span: Span) { + self.returns_token.span = span; + self.paren_token = Paren(span); + } +} + impl Returns { pub fn new(span: Span, returns: ParameterList) -> Self { Self { @@ -247,16 +262,6 @@ impl Returns { } } - pub fn span(&self) -> Span { - let span = self.returns_token.span; - span.join(self.paren_token.span.join()).unwrap_or(span) - } - - pub fn set_span(&mut self, span: Span) { - self.returns_token.span = span; - self.paren_token = Paren(span); - } - pub fn parse_opt(input: ParseStream<'_>) -> Result> { if input.peek(kw::returns) { input.parse().map(Some) diff --git a/crates/syn-solidity/src/item/import.rs b/crates/syn-solidity/src/item/import.rs index 7f906f69a1..bfeb8c212b 100644 --- a/crates/syn-solidity/src/item/import.rs +++ b/crates/syn-solidity/src/item/import.rs @@ -1,4 +1,4 @@ -use crate::{kw, LitStr, SolIdent}; +use crate::{kw, LitStr, SolIdent, Spanned}; use proc_macro2::Span; use std::fmt; use syn::{ @@ -30,13 +30,13 @@ impl Parse for ImportDirective { } } -impl ImportDirective { - pub fn span(&self) -> Span { +impl Spanned for ImportDirective { + fn span(&self) -> Span { let span = self.import_token.span; span.join(self.semi_token.span).unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.import_token.span = span; self.path.set_span(span); self.semi_token.span = span; @@ -67,8 +67,8 @@ impl Parse for ImportPath { } } -impl ImportPath { - pub fn span(&self) -> Span { +impl Spanned for ImportPath { + fn span(&self) -> Span { match self { Self::Plain(p) => p.span(), Self::Aliases(p) => p.span(), @@ -76,14 +76,16 @@ impl ImportPath { } } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { match self { Self::Plain(p) => p.set_span(span), Self::Aliases(p) => p.set_span(span), Self::Glob(p) => p.set_span(span), } } +} +impl ImportPath { pub fn path(&self) -> &LitStr { match self { Self::Plain(ImportPlain { path, .. }) @@ -123,17 +125,19 @@ impl Parse for ImportAlias { } } -impl ImportAlias { - pub fn span(&self) -> Span { +impl Spanned for ImportAlias { + fn span(&self) -> Span { let span = self.as_token.span; span.join(self.alias.span()).unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.as_token.span = span; self.alias.set_span(span); } +} +impl ImportAlias { pub fn parse_opt(input: ParseStream<'_>) -> Result> { if input.peek(Token![as]) { input.parse().map(Some) @@ -168,8 +172,8 @@ impl Parse for ImportPlain { } } -impl ImportPlain { - pub fn span(&self) -> Span { +impl Spanned for ImportPlain { + fn span(&self) -> Span { let span = self.path.span(); if let Some(alias) = &self.alias { span.join(alias.span()).unwrap_or(span) @@ -178,7 +182,7 @@ impl ImportPlain { } } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.path.set_span(span); if let Some(alias) = &mut self.alias { alias.set_span(span); @@ -216,13 +220,13 @@ impl Parse for ImportAliases { } } -impl ImportAliases { - pub fn span(&self) -> Span { +impl Spanned for ImportAliases { + fn span(&self) -> Span { let span = self.brace_token.span.join(); span.join(self.path.span()).unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.brace_token = Brace(span); self.from_token.span = span; self.path.set_span(span); @@ -258,13 +262,13 @@ impl Parse for ImportGlob { } } -impl ImportGlob { - pub fn span(&self) -> Span { +impl Spanned for ImportGlob { + fn span(&self) -> Span { let span = self.star_token.span; span.join(self.path.span()).unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.star_token.span = span; self.alias.set_span(span); self.from_token.span = span; diff --git a/crates/syn-solidity/src/item/mod.rs b/crates/syn-solidity/src/item/mod.rs index ca70d31cae..f5171db120 100644 --- a/crates/syn-solidity/src/item/mod.rs +++ b/crates/syn-solidity/src/item/mod.rs @@ -1,4 +1,4 @@ -use crate::{kw, variable::VariableDefinition, SolIdent}; +use crate::{kw, variable::VariableDefinition, SolIdent, Spanned}; use proc_macro2::Span; use syn::{ parse::{Parse, ParseStream}, @@ -117,8 +117,8 @@ impl Parse for Item { } } -impl Item { - pub fn span(&self) -> Span { +impl Spanned for Item { + fn span(&self) -> Span { match self { Self::Contract(contract) => contract.span(), Self::Enum(enumm) => enumm.span(), @@ -134,7 +134,7 @@ impl Item { } } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { match self { Self::Contract(contract) => contract.set_span(span), Self::Enum(enumm) => enumm.set_span(span), @@ -149,7 +149,9 @@ impl Item { Self::Variable(variable) => variable.set_span(span), } } +} +impl Item { pub fn name(&self) -> Option<&SolIdent> { match self { Self::Contract(ItemContract { name, .. }) diff --git a/crates/syn-solidity/src/item/pragma.rs b/crates/syn-solidity/src/item/pragma.rs index c024efa73d..bfbe6fef53 100644 --- a/crates/syn-solidity/src/item/pragma.rs +++ b/crates/syn-solidity/src/item/pragma.rs @@ -1,9 +1,8 @@ -use crate::{kw, utils::tts_until_semi, SolIdent}; +use crate::{kw, utils::tts_until_semi, SolIdent, Spanned}; use proc_macro2::{Span, TokenStream}; use std::fmt; use syn::{ parse::{Parse, ParseStream}, - spanned::Spanned, Result, Token, }; @@ -31,13 +30,13 @@ impl Parse for PragmaDirective { } } -impl PragmaDirective { - pub fn span(&self) -> Span { +impl Spanned for PragmaDirective { + fn span(&self) -> Span { let span = self.pragma_token.span; span.join(self.semi_token.span).unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.pragma_token.span = span; self.tokens.set_span(span); self.semi_token.span = span; @@ -72,8 +71,8 @@ impl Parse for PragmaTokens { } } -impl PragmaTokens { - pub fn span(&self) -> Span { +impl Spanned for PragmaTokens { + fn span(&self) -> Span { match self { Self::Version(solidity, version) => { let span = solidity.span; @@ -91,7 +90,7 @@ impl PragmaTokens { } } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { match self { Self::Version(solidity, _version) => { solidity.span = span; diff --git a/crates/syn-solidity/src/item/struct.rs b/crates/syn-solidity/src/item/struct.rs index 964454ae73..00d2ce9360 100644 --- a/crates/syn-solidity/src/item/struct.rs +++ b/crates/syn-solidity/src/item/struct.rs @@ -1,4 +1,4 @@ -use crate::{FieldList, SolIdent, Type}; +use crate::{FieldList, SolIdent, Spanned, Type}; use proc_macro2::Span; use std::{ fmt, @@ -62,17 +62,19 @@ impl Parse for ItemStruct { } } -impl ItemStruct { - pub fn span(&self) -> Span { +impl Spanned for ItemStruct { + fn span(&self) -> Span { self.name.span() } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.struct_token = Token![struct](span); self.name.set_span(span); self.brace_token = Brace(span); } +} +impl ItemStruct { pub fn as_type(&self) -> Type { let mut ty = Type::Tuple(self.fields.types().cloned().collect()); ty.set_span(self.span()); diff --git a/crates/syn-solidity/src/item/udt.rs b/crates/syn-solidity/src/item/udt.rs index ff0fb812fe..1c00513d92 100644 --- a/crates/syn-solidity/src/item/udt.rs +++ b/crates/syn-solidity/src/item/udt.rs @@ -1,4 +1,4 @@ -use crate::{kw, SolIdent, Type}; +use crate::{kw, SolIdent, Spanned, Type}; use proc_macro2::Span; use std::{ fmt, @@ -71,12 +71,12 @@ impl Parse for ItemUdt { } } -impl ItemUdt { - pub fn span(&self) -> Span { +impl Spanned for ItemUdt { + fn span(&self) -> Span { self.name.span() } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.type_token.span = span; self.name.set_span(span); self.is_token.span = span; diff --git a/crates/syn-solidity/src/item/using.rs b/crates/syn-solidity/src/item/using.rs index bac0a6ba3d..fd43a0526a 100644 --- a/crates/syn-solidity/src/item/using.rs +++ b/crates/syn-solidity/src/item/using.rs @@ -1,4 +1,4 @@ -use crate::{kw, SolPath, Type}; +use crate::{kw, SolPath, Spanned, Type}; use proc_macro2::Span; use syn::{ braced, @@ -35,13 +35,13 @@ impl Parse for UsingDirective { } } -impl UsingDirective { - pub fn span(&self) -> Span { +impl Spanned for UsingDirective { + fn span(&self) -> Span { let span = self.using_token.span; span.join(self.semi_token.span).unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.using_token.span = span; self.semi_token.span = span; } @@ -67,6 +67,28 @@ impl Parse for UsingList { } } +impl Spanned for UsingList { + fn span(&self) -> Span { + match self { + Self::Single(path) => path.span(), + Self::Multiple(brace, list) => { + let span = brace.span.join(); + span.join(list.span()).unwrap_or(span) + } + } + } + + fn set_span(&mut self, span: Span) { + match self { + Self::Single(path) => path.set_span(span), + Self::Multiple(brace, list) => { + *brace = Brace(span); + list.set_span(span); + } + } + } +} + #[derive(Clone, Debug)] pub struct UsingListItem { pub path: SolPath, @@ -86,6 +108,16 @@ impl Parse for UsingListItem { } } +impl Spanned for UsingListItem { + fn span(&self) -> Span { + self.path.span() + } + + fn set_span(&mut self, span: Span) { + self.path.set_span(span); + } +} + #[derive(Clone, Debug)] pub enum UsingType { Star(Token![*]), @@ -102,6 +134,22 @@ impl Parse for UsingType { } } +impl Spanned for UsingType { + fn span(&self) -> Span { + match self { + Self::Star(star) => star.span, + Self::Type(ty) => ty.span(), + } + } + + fn set_span(&mut self, span: Span) { + match self { + Self::Star(star) => star.span = span, + Self::Type(ty) => ty.set_span(span), + } + } +} + op_enum! { /// A user-definable operator: `+`, `*`, `|`, etc. /// diff --git a/crates/syn-solidity/src/kw.rs b/crates/syn-solidity/src/kw.rs index 7d20937a63..e028cc7711 100644 --- a/crates/syn-solidity/src/kw.rs +++ b/crates/syn-solidity/src/kw.rs @@ -1,9 +1,21 @@ //! Solidity keywords. macro_rules! custom_keywords { - ($($name:ident),+ $(,)?) => { - $(syn::custom_keyword!($name);)+ - }; + ($($name:ident),+ $(,)?) => {$( + syn::custom_keyword!($name); + + impl $crate::Spanned for $name { + #[inline] + fn span(&self) -> ::proc_macro2::Span { + self.span + } + + #[inline] + fn set_span(&mut self, span: ::proc_macro2::Span) { + self.span = span; + } + } + )+}; } #[rustfmt::skip] diff --git a/crates/syn-solidity/src/lit/mod.rs b/crates/syn-solidity/src/lit/mod.rs index 31f5324423..fa4bc7236e 100644 --- a/crates/syn-solidity/src/lit/mod.rs +++ b/crates/syn-solidity/src/lit/mod.rs @@ -1,4 +1,4 @@ -use crate::kw; +use crate::{kw, Spanned}; use proc_macro2::Span; use syn::{ parse::{Lookahead1, Parse, ParseStream}, @@ -40,12 +40,8 @@ impl Parse for Lit { } } -impl Lit { - pub fn peek(lookahead: &Lookahead1<'_>) -> bool { - lookahead.peek(syn::Lit) || lookahead.peek(kw::unicode) || lookahead.peek(kw::hex) - } - - pub fn span(&self) -> Span { +impl Spanned for Lit { + fn span(&self) -> Span { match self { Self::Str(lit) => lit.span(), Self::Int(lit) => lit.span(), @@ -56,7 +52,7 @@ impl Lit { } } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { match self { Self::Str(lit) => lit.set_span(span), Self::Int(lit) => lit.set_span(span), @@ -67,3 +63,9 @@ impl Lit { } } } + +impl Lit { + pub fn peek(lookahead: &Lookahead1<'_>) -> bool { + lookahead.peek(syn::Lit) || lookahead.peek(kw::unicode) || lookahead.peek(kw::hex) + } +} diff --git a/crates/syn-solidity/src/lit/str.rs b/crates/syn-solidity/src/lit/str.rs index 24e9f26629..1f0b1861b8 100644 --- a/crates/syn-solidity/src/lit/str.rs +++ b/crates/syn-solidity/src/lit/str.rs @@ -1,4 +1,4 @@ -use crate::{kw, utils::parse_vec}; +use crate::{kw, utils::parse_vec, Spanned}; use proc_macro2::Span; use std::{ fmt, @@ -40,16 +40,8 @@ macro_rules! str_lit { } } - impl $name { - pub fn parse_opt(input: ParseStream<'_>) -> Result> { - if $(input.peek(kw::$kw) || )? input.peek(syn::LitStr) { - input.parse().map(Some) - } else { - Ok(None) - } - } - - pub fn span(&self) -> Span { + impl Spanned for $name { + fn span(&self) -> Span { let mut span = self.values.first().unwrap().span(); for value in &self.values[1..] { span = span.join(value.span()).unwrap_or(span); @@ -57,11 +49,21 @@ macro_rules! str_lit { span } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { for value in &mut self.values { value.set_span(span); } } + } + + impl $name { + pub fn parse_opt(input: ParseStream<'_>) -> Result> { + if $(input.peek(kw::$kw) || )? input.peek(syn::LitStr) { + input.parse().map(Some) + } else { + Ok(None) + } + } pub fn value(&self) -> String { self.values.iter().map(|v| v.value()).collect() @@ -114,13 +116,13 @@ macro_rules! wrap_str { } } - impl $name { - pub fn span(&self) -> Span { + impl Spanned for $name { + fn span(&self) -> Span { let span = self.$token.span; span.join(self.value.span()).unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.$token.span = span; self.value.set_span(span); } diff --git a/crates/syn-solidity/src/macros.rs b/crates/syn-solidity/src/macros.rs index 249833be79..627f2576b4 100644 --- a/crates/syn-solidity/src/macros.rs +++ b/crates/syn-solidity/src/macros.rs @@ -265,9 +265,24 @@ macro_rules! kw_enum { } } + impl $crate::Spanned for $name { + fn span(&self) -> ::proc_macro2::Span { + match self {$( + Self::$variant(kw) => kw.span, + )+} + } + + fn set_span(&mut self, span: ::proc_macro2::Span) { + match self {$( + Self::$variant(kw) => kw.span = span, + )+} + } + } + impl $name { ::paste::paste! { $( + #[doc = concat!("Creates a new `", stringify!($variant), "` keyword with the given `span`.")] #[inline] pub fn [](span: ::proc_macro2::Span) -> Self { Self::$variant(kw::$kw(span)) @@ -290,18 +305,6 @@ macro_rules! kw_enum { $( lookahead.peek($crate::kw::$kw) )||+ } - pub const fn span(self) -> ::proc_macro2::Span { - match self {$( - Self::$variant(kw) => kw.span, - )+} - } - - pub fn set_span(&mut self, span: ::proc_macro2::Span) { - match self {$( - Self::$variant(kw) => kw.span = span, - )+} - } - pub const fn as_str(self) -> &'static str { match self {$( Self::$variant(_) => stringify!($kw), @@ -316,6 +319,7 @@ macro_rules! kw_enum { ::paste::paste! { $( + #[doc = concat!("Returns true if `self` matches `Self::", stringify!($variant), "`.")] #[inline] pub const fn [](self) -> bool { matches!(self, Self::$variant(_)) @@ -409,9 +413,27 @@ macro_rules! op_enum { } } + impl $crate::Spanned for $name { + fn span(&self) -> ::proc_macro2::Span { + todo!() + // match self {$( + // Self::$variant(kw, ..) => kw.span(), + // )+} + } + + fn set_span(&mut self, span: ::proc_macro2::Span) { + let _ = span; + todo!() + // match self {$( + // Self::$variant(kw, ..) => kw.set_span(span), + // )+} + } + } + impl $name { ::paste::paste! { $( + #[doc = concat!("Creates a new `", stringify!($variant), "` operator with the given `span`.")] #[inline] pub fn [](span: ::proc_macro2::Span) -> Self { Self::$variant($(::syn::Token![$op](span)),+) @@ -438,23 +460,9 @@ macro_rules! op_enum { )+} } - pub const fn span(self) -> ::proc_macro2::Span { - todo!() - // match self {$( - // Self::$variant(kw, ..) => kw.span(), - // )+} - } - - pub fn set_span(&mut self, span: ::proc_macro2::Span) { - let _ = span; - todo!() - // match self {$( - // Self::$variant(kw, ..) => kw.set_span(span), - // )+} - } - ::paste::paste! { $( + #[doc = concat!("Returns true if `self` matches `Self::", stringify!($variant), "`.")] #[inline] pub const fn [](self) -> bool { matches!(self, Self::$variant(..)) diff --git a/crates/syn-solidity/src/spanned.rs b/crates/syn-solidity/src/spanned.rs index b17aa47b5a..cbcf70e9b5 100644 --- a/crates/syn-solidity/src/spanned.rs +++ b/crates/syn-solidity/src/spanned.rs @@ -1,21 +1,5 @@ -use proc_macro2::Span; -use syn::Token; - -fn join_spans>(spans: I) -> Span { - let mut iter = spans.into_iter(); - let Some(first) = iter.next() else { - return Span::call_site() - }; - iter.last() - .and_then(|last| first.join(last)) - .unwrap_or(first) -} - -fn set_spans<'a, I: IntoIterator>(spans: I, set_to: Span) { - for span in spans { - *span = set_to; - } -} +use proc_macro2::{Span, TokenStream, TokenTree}; +use syn::{punctuated::Punctuated, Token}; /// A trait for getting and setting the span of a syntax tree node. pub trait Spanned { @@ -38,6 +22,30 @@ impl Spanned for Span { } } +impl Spanned for TokenStream { + #[inline] + fn span(&self) -> Span { + syn::spanned::Spanned::span(self) + } + + #[inline] + fn set_span(&mut self, span: Span) { + crate::utils::set_spans_clone(self, span); + } +} + +impl Spanned for TokenTree { + #[inline] + fn span(&self) -> Span { + TokenTree::span(self) + } + + #[inline] + fn set_span(&mut self, span: Span) { + TokenTree::set_span(self, span) + } +} + impl Spanned for Option { #[inline] fn span(&self) -> Span { @@ -55,6 +63,31 @@ impl Spanned for Option { } } +impl Spanned for &T { + #[inline] + fn span(&self) -> Span { + (**self).span() + } + + #[inline] + fn set_span(&mut self, _span: Span) { + unimplemented!( + "cannot set span of borrowed Spanned: {:?}", + std::any::type_name::() + ) + } +} + +impl Spanned for Punctuated { + fn span(&self) -> Span { + crate::utils::join_spans(self) + } + + fn set_span(&mut self, span: Span) { + crate::utils::set_spans(self, span) + } +} + macro_rules! deref_impl { ($($(#[$attr:meta])* [$($gen:tt)*] $t:ty),+ $(,)?) => {$( $(#[$attr])* @@ -224,3 +257,19 @@ kw_impl! { [~] [_] } + +fn join_spans>(spans: I) -> Span { + let mut iter = spans.into_iter(); + let Some(first) = iter.next() else { + return Span::call_site() + }; + iter.last() + .and_then(|last| first.join(last)) + .unwrap_or(first) +} + +fn set_spans<'a, I: IntoIterator>(spans: I, set_to: Span) { + for span in spans { + *span = set_to; + } +} diff --git a/crates/syn-solidity/src/stmt/assembly.rs b/crates/syn-solidity/src/stmt/assembly.rs index cccb83a146..8d1a2941dd 100644 --- a/crates/syn-solidity/src/stmt/assembly.rs +++ b/crates/syn-solidity/src/stmt/assembly.rs @@ -1,4 +1,4 @@ -use crate::{kw, LitStr, YulBlock}; +use crate::{kw, LitStr, Spanned, YulBlock}; use proc_macro2::Span; use std::fmt; use syn::{ @@ -38,13 +38,13 @@ impl Parse for StmtAssembly { } } -impl StmtAssembly { - pub fn span(&self) -> Span { +impl Spanned for StmtAssembly { + fn span(&self) -> Span { let span = self.assembly_token.span; span.join(self.block.span()).unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.assembly_token.span = span; self.block.set_span(span); } @@ -74,6 +74,16 @@ impl Parse for AssemblyFlags { } } +impl Spanned for AssemblyFlags { + fn span(&self) -> Span { + self.paren_token.span.join() + } + + fn set_span(&mut self, span: Span) { + self.paren_token = Paren(span); + } +} + impl AssemblyFlags { pub fn parse_opt(input: ParseStream<'_>) -> Result> { if input.peek(Paren) { diff --git a/crates/syn-solidity/src/stmt/blocks.rs b/crates/syn-solidity/src/stmt/blocks.rs index d495b31dc6..b55ee0b1b6 100644 --- a/crates/syn-solidity/src/stmt/blocks.rs +++ b/crates/syn-solidity/src/stmt/blocks.rs @@ -1,4 +1,4 @@ -use crate::{kw, Stmt}; +use crate::{kw, Spanned, Stmt}; use proc_macro2::Span; use std::fmt; use syn::{ @@ -30,12 +30,12 @@ impl Parse for Block { } } -impl Block { - pub fn span(&self) -> Span { +impl Spanned for Block { + fn span(&self) -> Span { self.brace_token.span.join() } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.brace_token = Brace(span); } } @@ -64,13 +64,13 @@ impl Parse for UncheckedBlock { } } -impl UncheckedBlock { - pub fn span(&self) -> Span { +impl Spanned for UncheckedBlock { + fn span(&self) -> Span { let span = self.unchecked_token.span; span.join(self.block.span()).unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.unchecked_token.span = span; self.block.set_span(span); } diff --git a/crates/syn-solidity/src/stmt/break.rs b/crates/syn-solidity/src/stmt/break.rs index 9a423a482b..31612aeb62 100644 --- a/crates/syn-solidity/src/stmt/break.rs +++ b/crates/syn-solidity/src/stmt/break.rs @@ -1,3 +1,4 @@ +use crate::Spanned; use proc_macro2::Span; use std::fmt; use syn::{ @@ -30,13 +31,13 @@ impl Parse for StmtBreak { } } -impl StmtBreak { - pub fn span(&self) -> Span { +impl Spanned for StmtBreak { + fn span(&self) -> Span { let span = self.break_token.span; span.join(self.semi_token.span).unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.break_token.span = span; self.semi_token.span = span; } diff --git a/crates/syn-solidity/src/stmt/continue.rs b/crates/syn-solidity/src/stmt/continue.rs index 611f66425b..06e828b800 100644 --- a/crates/syn-solidity/src/stmt/continue.rs +++ b/crates/syn-solidity/src/stmt/continue.rs @@ -1,3 +1,4 @@ +use crate::Spanned; use proc_macro2::Span; use std::fmt; use syn::{ @@ -30,13 +31,13 @@ impl Parse for StmtContinue { } } -impl StmtContinue { - pub fn span(&self) -> Span { +impl Spanned for StmtContinue { + fn span(&self) -> Span { let span = self.continue_token.span; span.join(self.semi_token.span).unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.continue_token.span = span; self.semi_token.span = span; } diff --git a/crates/syn-solidity/src/stmt/do_while.rs b/crates/syn-solidity/src/stmt/do_while.rs index 3bae36e2e9..e35f9c7a2c 100644 --- a/crates/syn-solidity/src/stmt/do_while.rs +++ b/crates/syn-solidity/src/stmt/do_while.rs @@ -1,4 +1,4 @@ -use crate::{Expr, Stmt}; +use crate::{Expr, Spanned, Stmt}; use proc_macro2::Span; use std::fmt; use syn::{ @@ -44,13 +44,13 @@ impl Parse for StmtDoWhile { } } -impl StmtDoWhile { - pub fn span(&self) -> Span { +impl Spanned for StmtDoWhile { + fn span(&self) -> Span { let span = self.do_token.span; span.join(self.semi_token.span).unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.do_token.span = span; self.semi_token.span = span; } diff --git a/crates/syn-solidity/src/stmt/emit.rs b/crates/syn-solidity/src/stmt/emit.rs index 93658a4726..15f45c56cd 100644 --- a/crates/syn-solidity/src/stmt/emit.rs +++ b/crates/syn-solidity/src/stmt/emit.rs @@ -1,4 +1,4 @@ -use crate::{kw, ArgList, Expr}; +use crate::{kw, ArgList, Expr, Spanned}; use proc_macro2::Span; use std::fmt; use syn::{ @@ -38,13 +38,13 @@ impl Parse for StmtEmit { } } -impl StmtEmit { - pub fn span(&self) -> Span { +impl Spanned for StmtEmit { + fn span(&self) -> Span { let span = self.emit_token.span; span.join(self.semi_token.span).unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.emit_token.span = span; self.semi_token.span = span; } diff --git a/crates/syn-solidity/src/stmt/expr.rs b/crates/syn-solidity/src/stmt/expr.rs index d63fbdda8d..e835d485ba 100644 --- a/crates/syn-solidity/src/stmt/expr.rs +++ b/crates/syn-solidity/src/stmt/expr.rs @@ -1,4 +1,4 @@ -use crate::Expr; +use crate::{Expr, Spanned}; use proc_macro2::Span; use std::fmt; use syn::{ @@ -30,13 +30,13 @@ impl Parse for StmtExpr { } } -impl StmtExpr { - pub fn span(&self) -> Span { +impl Spanned for StmtExpr { + fn span(&self) -> Span { let span = self.expr.span(); span.join(self.semi_token.span).unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.expr.set_span(span); self.semi_token.span = span; } diff --git a/crates/syn-solidity/src/stmt/for.rs b/crates/syn-solidity/src/stmt/for.rs index 4c18a443c6..f9c8e0b900 100644 --- a/crates/syn-solidity/src/stmt/for.rs +++ b/crates/syn-solidity/src/stmt/for.rs @@ -1,4 +1,4 @@ -use crate::{Expr, Stmt, StmtExpr, StmtVarDecl}; +use crate::{Expr, Spanned, Stmt, StmtExpr, StmtVarDecl}; use proc_macro2::Span; use std::fmt; use syn::{ @@ -40,13 +40,13 @@ impl Parse for StmtFor { } } -impl StmtFor { - pub fn span(&self) -> Span { +impl Spanned for StmtFor { + fn span(&self) -> Span { let span = self.for_token.span; span.join(self.body.span()).unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.for_token.span = span; self.body.set_span(span); } diff --git a/crates/syn-solidity/src/stmt/if.rs b/crates/syn-solidity/src/stmt/if.rs index 343dafb5a5..fe157bc3f9 100644 --- a/crates/syn-solidity/src/stmt/if.rs +++ b/crates/syn-solidity/src/stmt/if.rs @@ -1,4 +1,4 @@ -use crate::{Expr, Stmt}; +use crate::{Expr, Spanned, Stmt}; use proc_macro2::Span; use std::fmt; use syn::{ @@ -45,8 +45,8 @@ impl Parse for StmtIf { } } -impl StmtIf { - pub fn span(&self) -> Span { +impl Spanned for StmtIf { + fn span(&self) -> Span { let span = self.if_token.span; self.else_branch .as_ref() @@ -55,7 +55,7 @@ impl StmtIf { .unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.if_token.span = span; self.then_branch.set_span(span); if let Some((_, stmt)) = &mut self.else_branch { diff --git a/crates/syn-solidity/src/stmt/mod.rs b/crates/syn-solidity/src/stmt/mod.rs index f5947a60b3..39729a789d 100644 --- a/crates/syn-solidity/src/stmt/mod.rs +++ b/crates/syn-solidity/src/stmt/mod.rs @@ -40,7 +40,7 @@ pub use var_decl::StmtVarDecl; mod r#while; pub use r#while::StmtWhile; -use crate::kw; +use crate::{kw, Spanned}; use proc_macro2::Span; use syn::{ parse::{discouraged::Speculative, Parse, ParseStream}, @@ -158,8 +158,8 @@ impl Parse for Stmt { } } -impl Stmt { - pub fn span(&self) -> Span { +impl Spanned for Stmt { + fn span(&self) -> Span { match self { Self::Assembly(stmt) => stmt.span(), Self::Block(block) => block.span(), @@ -179,7 +179,7 @@ impl Stmt { } } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { match self { Self::Assembly(stmt) => stmt.set_span(span), Self::Block(block) => block.set_span(span), diff --git a/crates/syn-solidity/src/stmt/return.rs b/crates/syn-solidity/src/stmt/return.rs index e53dd47f72..4e98ea00e1 100644 --- a/crates/syn-solidity/src/stmt/return.rs +++ b/crates/syn-solidity/src/stmt/return.rs @@ -1,4 +1,4 @@ -use crate::Expr; +use crate::{Expr, Spanned}; use proc_macro2::Span; use std::fmt; use syn::{ @@ -39,13 +39,13 @@ impl Parse for StmtReturn { } } -impl StmtReturn { - pub fn span(&self) -> Span { +impl Spanned for StmtReturn { + fn span(&self) -> Span { let span = self.return_token.span; span.join(self.semi_token.span).unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.return_token.span = span; self.semi_token.span = span; } diff --git a/crates/syn-solidity/src/stmt/revert.rs b/crates/syn-solidity/src/stmt/revert.rs index 63b894e894..e4506c2ab0 100644 --- a/crates/syn-solidity/src/stmt/revert.rs +++ b/crates/syn-solidity/src/stmt/revert.rs @@ -1,4 +1,4 @@ -use crate::{kw, ArgList, Expr}; +use crate::{kw, ArgList, Expr, Spanned}; use proc_macro2::Span; use std::fmt; use syn::{ @@ -38,13 +38,13 @@ impl Parse for StmtRevert { } } -impl StmtRevert { - pub fn span(&self) -> Span { +impl Spanned for StmtRevert { + fn span(&self) -> Span { let span = self.revert_token.span; span.join(self.semi_token.span).unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.revert_token.span = span; self.semi_token.span = span; } diff --git a/crates/syn-solidity/src/stmt/try.rs b/crates/syn-solidity/src/stmt/try.rs index 7d88c10a9b..a34ed89346 100644 --- a/crates/syn-solidity/src/stmt/try.rs +++ b/crates/syn-solidity/src/stmt/try.rs @@ -1,4 +1,4 @@ -use crate::{kw, Block, Expr, ParameterList, Returns, SolIdent}; +use crate::{kw, Block, Expr, ParameterList, Returns, SolIdent, Spanned}; use proc_macro2::Span; use std::fmt; use syn::{ @@ -52,13 +52,13 @@ impl Parse for StmtTry { } } -impl StmtTry { - pub fn span(&self) -> Span { +impl Spanned for StmtTry { + fn span(&self) -> Span { let span = self.try_token.span; span.join(self.block.span()).unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.try_token.span = span; self.block.set_span(span); } @@ -108,13 +108,13 @@ impl Parse for CatchClause { } } -impl CatchClause { - pub fn span(&self) -> Span { +impl Spanned for CatchClause { + fn span(&self) -> Span { let span = self.catch_token.span; span.join(self.block.span()).unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.catch_token.span = span; self.block.set_span(span); } diff --git a/crates/syn-solidity/src/stmt/var_decl.rs b/crates/syn-solidity/src/stmt/var_decl.rs index f9e5fc14fa..c900956599 100644 --- a/crates/syn-solidity/src/stmt/var_decl.rs +++ b/crates/syn-solidity/src/stmt/var_decl.rs @@ -1,4 +1,4 @@ -use crate::{Expr, VariableDeclaration}; +use crate::{Expr, Spanned, VariableDeclaration}; use proc_macro2::Span; use std::fmt; use syn::{ @@ -45,8 +45,8 @@ impl Parse for StmtVarDecl { } } -impl StmtVarDecl { - pub fn span(&self) -> Span { +impl Spanned for StmtVarDecl { + fn span(&self) -> Span { let span = self.declaration.span(); self.assignment .as_ref() @@ -54,7 +54,7 @@ impl StmtVarDecl { .unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.declaration.set_span(span); if let Some((eq, expr)) = &mut self.assignment { eq.span = span; @@ -81,15 +81,15 @@ impl Parse for VarDeclDecl { } } -impl VarDeclDecl { - pub fn span(&self) -> Span { +impl Spanned for VarDeclDecl { + fn span(&self) -> Span { match self { Self::VarDecl(decl) => decl.span(), Self::Expression(decl) => decl.span(), } } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { match self { Self::VarDecl(decl) => decl.set_span(span), Self::Expression(decl) => decl.set_span(span), @@ -127,15 +127,17 @@ impl Parse for VarDeclTuple { } } -impl VarDeclTuple { - pub fn span(&self) -> Span { +impl Spanned for VarDeclTuple { + fn span(&self) -> Span { self.paren_token.span.join() } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.paren_token = Paren(span); } +} +impl VarDeclTuple { fn parse_var_opt(input: ParseStream<'_>) -> Result> { if input.peek(Token![,]) { Ok(None) diff --git a/crates/syn-solidity/src/stmt/while.rs b/crates/syn-solidity/src/stmt/while.rs index 01cf640911..6d5398714d 100644 --- a/crates/syn-solidity/src/stmt/while.rs +++ b/crates/syn-solidity/src/stmt/while.rs @@ -1,4 +1,4 @@ -use crate::{Expr, Stmt}; +use crate::{Expr, Spanned, Stmt}; use proc_macro2::Span; use std::fmt; use syn::{ @@ -39,13 +39,13 @@ impl Parse for StmtWhile { } } -impl StmtWhile { - pub fn span(&self) -> Span { +impl Spanned for StmtWhile { + fn span(&self) -> Span { let span = self.while_token.span; span.join(self.body.span()).unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.while_token.span = span; self.body.set_span(span); } diff --git a/crates/syn-solidity/src/type/array.rs b/crates/syn-solidity/src/type/array.rs index 0f677d8144..96989fc709 100644 --- a/crates/syn-solidity/src/type/array.rs +++ b/crates/syn-solidity/src/type/array.rs @@ -1,4 +1,4 @@ -use crate::Type; +use crate::{Spanned, Type}; use proc_macro2::Span; use std::{ fmt, @@ -62,20 +62,22 @@ impl Parse for TypeArray { } } -impl TypeArray { - pub fn span(&self) -> Span { +impl Spanned for TypeArray { + fn span(&self) -> Span { let span = self.ty.span(); span.join(self.bracket_token.span.join()).unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.ty.set_span(span); self.bracket_token = Bracket(span); if let Some(size) = &mut self.size { size.set_span(span); } } +} +impl TypeArray { /// Returns the size of the array, or None if dynamic. pub fn size(&self) -> Option { self.size.as_ref().map(|s| s.base10_parse().unwrap()) diff --git a/crates/syn-solidity/src/type/function.rs b/crates/syn-solidity/src/type/function.rs index 644fbd0b39..ae6b829d13 100644 --- a/crates/syn-solidity/src/type/function.rs +++ b/crates/syn-solidity/src/type/function.rs @@ -1,4 +1,4 @@ -use crate::{kw, FunctionAttributes, ParameterList, Returns}; +use crate::{kw, FunctionAttributes, ParameterList, Returns, Spanned}; use proc_macro2::Span; use std::{ fmt, @@ -84,12 +84,12 @@ impl Parse for TypeFunction { } } -impl TypeFunction { - pub fn span(&self) -> Span { +impl Spanned for TypeFunction { + fn span(&self) -> Span { self.function_token.span } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.function_token.span = span; } } diff --git a/crates/syn-solidity/src/type/mapping.rs b/crates/syn-solidity/src/type/mapping.rs index 208b50f740..69daa85c36 100644 --- a/crates/syn-solidity/src/type/mapping.rs +++ b/crates/syn-solidity/src/type/mapping.rs @@ -1,4 +1,4 @@ -use crate::{kw, SolIdent, Type}; +use crate::{kw, SolIdent, Spanned, Type}; use proc_macro2::Span; use std::{ fmt, @@ -70,13 +70,13 @@ impl Parse for TypeMapping { } } -impl TypeMapping { - pub fn span(&self) -> Span { +impl Spanned for TypeMapping { + fn span(&self) -> Span { let span = self.mapping_token.span; span.join(self.paren_token.span.join()).unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.mapping_token.span = span; self.paren_token = Paren(span); self.key.set_span(span); diff --git a/crates/syn-solidity/src/type/mod.rs b/crates/syn-solidity/src/type/mod.rs index f94aede74e..4dd65dab6c 100644 --- a/crates/syn-solidity/src/type/mod.rs +++ b/crates/syn-solidity/src/type/mod.rs @@ -1,4 +1,4 @@ -use crate::{kw, sol_path, SolPath}; +use crate::{kw, sol_path, SolPath, Spanned}; use proc_macro2::Span; use std::{ fmt, @@ -162,20 +162,8 @@ impl Parse for Type { } } -impl Type { - pub fn peek(lookahead: &Lookahead1<'_>) -> bool { - lookahead.peek(syn::token::Paren) - || lookahead.peek(kw::tuple) - || lookahead.peek(kw::function) - || lookahead.peek(kw::mapping) - || lookahead.peek(Ident::peek_any) - } - - pub fn custom(ident: Ident) -> Self { - Self::Custom(sol_path![ident]) - } - - pub fn span(&self) -> Span { +impl Spanned for Type { + fn span(&self) -> Span { match self { &Self::Address(span, payable) => { payable.and_then(|kw| span.join(kw.span)).unwrap_or(span) @@ -194,7 +182,7 @@ impl Type { } } - pub fn set_span(&mut self, new_span: Span) { + fn set_span(&mut self, new_span: Span) { match self { Self::Address(span, payable) => { *span = new_span; @@ -216,6 +204,20 @@ impl Type { Self::Custom(custom) => custom.set_span(new_span), } } +} + +impl Type { + pub fn peek(lookahead: &Lookahead1<'_>) -> bool { + lookahead.peek(syn::token::Paren) + || lookahead.peek(kw::tuple) + || lookahead.peek(kw::function) + || lookahead.peek(kw::mapping) + || lookahead.peek(Ident::peek_any) + } + + pub fn custom(ident: Ident) -> Self { + Self::Custom(sol_path![ident]) + } /// Returns whether this type is ABI-encoded as a single EVM word (32 /// bytes). diff --git a/crates/syn-solidity/src/type/tuple.rs b/crates/syn-solidity/src/type/tuple.rs index 3236e33e9a..cf98315257 100644 --- a/crates/syn-solidity/src/type/tuple.rs +++ b/crates/syn-solidity/src/type/tuple.rs @@ -1,4 +1,4 @@ -use crate::{kw, utils::DebugPunctuated, Type}; +use crate::{kw, utils::DebugPunctuated, Spanned, Type}; use proc_macro2::Span; use std::{ fmt, @@ -94,21 +94,23 @@ impl FromIterator for TypeTuple { } } -impl TypeTuple { - pub fn span(&self) -> Span { +impl Spanned for TypeTuple { + fn span(&self) -> Span { let span = self.paren_token.span.join(); self.tuple_token .and_then(|tuple_token| tuple_token.span.join(span)) .unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { if let Some(tuple_token) = &mut self.tuple_token { tuple_token.span = span; } self.paren_token = Paren(span); } +} +impl TypeTuple { /// See [`Type::is_abi_dynamic`]. pub fn is_abi_dynamic(&self) -> bool { self.types.iter().any(Type::is_abi_dynamic) diff --git a/crates/syn-solidity/src/utils.rs b/crates/syn-solidity/src/utils.rs index eea560c459..56c3d2a5d2 100644 --- a/crates/syn-solidity/src/utils.rs +++ b/crates/syn-solidity/src/utils.rs @@ -43,7 +43,7 @@ pub(crate) fn parse_vec(input: ParseStream<'_>, allow_empty: bool) -> Ok(vec) } -pub(crate) fn _join_spans>(items: I) -> Span { +pub(crate) fn join_spans>(items: I) -> Span { let mut iter = items.into_iter(); let Some(first) = iter.next() else { return Span::call_site() @@ -54,11 +54,27 @@ pub(crate) fn _join_spans>(items: I) -> Sp .unwrap_or(first) } -pub(crate) fn _set_spans<'a, T: Spanned + 'a, I: IntoIterator>( - items: I, - set_to: Span, -) { +pub(crate) fn set_spans<'a, T, I>(items: I, span: Span) +where + T: Spanned + 'a, + I: IntoIterator, +{ for item in items { - item.set_span(set_to); + item.set_span(span); } } + +pub(crate) fn set_spans_clone<'a, T, I>(items: &mut I, span: Span) +where + T: Spanned + 'a, + I: Clone + IntoIterator + FromIterator, +{ + *items = items + .clone() + .into_iter() + .map(|mut item| { + item.set_span(span); + item + }) + .collect(); +} diff --git a/crates/syn-solidity/src/variable/list.rs b/crates/syn-solidity/src/variable/list.rs index b195d54759..0b11786c1f 100644 --- a/crates/syn-solidity/src/variable/list.rs +++ b/crates/syn-solidity/src/variable/list.rs @@ -1,5 +1,5 @@ -use super::VariableDeclaration; -use crate::{SolIdent, Type}; +use crate::{SolIdent, Spanned, Type, VariableDeclaration}; +use proc_macro2::Span; use std::{ fmt, ops::{Deref, DerefMut}, @@ -70,6 +70,16 @@ impl Parse for FieldList { } } +impl

Spanned for Parameters

{ + fn span(&self) -> Span { + crate::utils::join_spans(&self.0) + } + + fn set_span(&mut self, span: Span) { + crate::utils::set_spans(&mut self.0, span); + } +} + impl

IntoIterator for Parameters

{ type IntoIter = as IntoIterator>::IntoIter; type Item = ::Item; diff --git a/crates/syn-solidity/src/variable/mod.rs b/crates/syn-solidity/src/variable/mod.rs index 5d48d394b6..2f99c566ec 100644 --- a/crates/syn-solidity/src/variable/mod.rs +++ b/crates/syn-solidity/src/variable/mod.rs @@ -1,5 +1,4 @@ -use super::{SolIdent, Storage, Type}; -use crate::{Expr, VariableAttributes}; +use crate::{Expr, SolIdent, Spanned, Storage, Type, VariableAttributes}; use proc_macro2::Span; use std::fmt::{self, Write}; use syn::{ @@ -48,17 +47,8 @@ impl Parse for VariableDeclaration { } } -impl VariableDeclaration { - pub const fn new(ty: Type) -> Self { - Self { - attrs: Vec::new(), - ty, - storage: None, - name: None, - } - } - - pub fn span(&self) -> Span { +impl Spanned for VariableDeclaration { + fn span(&self) -> Span { let span = self.ty.span(); match (&self.storage, &self.name) { (Some(storage), None) => span.join(storage.span()), @@ -68,7 +58,7 @@ impl VariableDeclaration { .unwrap_or(span) } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.ty.set_span(span); if let Some(storage) = &mut self.storage { storage.set_span(span); @@ -77,6 +67,17 @@ impl VariableDeclaration { name.set_span(span); } } +} + +impl VariableDeclaration { + pub const fn new(ty: Type) -> Self { + Self { + attrs: Vec::new(), + ty, + storage: None, + name: None, + } + } /// Formats `self` as an EIP-712 field: ` ` pub fn fmt_eip712(&self, f: &mut impl Write) -> fmt::Result { @@ -131,6 +132,18 @@ impl Parse for VariableDefinition { } } +impl Spanned for VariableDefinition { + fn span(&self) -> Span { + let span = self.ty.span(); + span.join(self.semi_token.span).unwrap_or(span) + } + + fn set_span(&mut self, span: Span) { + self.ty.set_span(span); + self.semi_token.span = span; + } +} + impl VariableDefinition { pub fn as_declaration(&self) -> VariableDeclaration { VariableDeclaration { @@ -140,14 +153,4 @@ impl VariableDefinition { name: Some(self.name.clone()), } } - - pub fn span(&self) -> Span { - let span = self.ty.span(); - span.join(self.semi_token.span).unwrap_or(span) - } - - pub fn set_span(&mut self, span: Span) { - self.ty.set_span(span); - self.semi_token.span = span; - } } diff --git a/crates/syn-solidity/src/yul/block.rs b/crates/syn-solidity/src/yul/block.rs index 570b7ebfb8..078cf6a8a8 100644 --- a/crates/syn-solidity/src/yul/block.rs +++ b/crates/syn-solidity/src/yul/block.rs @@ -1,3 +1,4 @@ +use crate::Spanned; use proc_macro2::{Span, TokenStream}; use std::fmt; use syn::{ @@ -32,12 +33,12 @@ impl Parse for YulBlock { } } -impl YulBlock { - pub fn span(&self) -> Span { +impl Spanned for YulBlock { + fn span(&self) -> Span { self.brace_token.span.join() } - pub fn set_span(&mut self, span: Span) { + fn set_span(&mut self, span: Span) { self.brace_token = Brace(span); } } From 3d5be6ba73a6928621448c7516c38e789cf9086f Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Sat, 5 Aug 2023 04:28:54 +0200 Subject: [PATCH 14/22] fix bugs, part 1 --- crates/sol-macro/src/expand/contract.rs | 21 ++- crates/syn-solidity/src/attribute/mod.rs | 12 +- crates/syn-solidity/src/expr/args.rs | 44 +++-- crates/syn-solidity/src/expr/array.rs | 15 +- crates/syn-solidity/src/expr/binary.rs | 44 ++--- crates/syn-solidity/src/expr/member.rs | 10 +- crates/syn-solidity/src/expr/mod.rs | 195 ++++++++++++++--------- crates/syn-solidity/src/expr/ternary.rs | 10 +- crates/syn-solidity/src/expr/tuple.rs | 4 +- crates/syn-solidity/src/expr/unary.rs | 10 +- crates/syn-solidity/src/lib.rs | 2 + crates/syn-solidity/src/lit/str.rs | 28 ++-- crates/syn-solidity/src/macros.rs | 36 +++-- crates/syn-solidity/src/spanned.rs | 14 +- crates/syn-solidity/src/stmt/assembly.rs | 4 +- crates/syn-solidity/src/stmt/blocks.rs | 11 +- crates/syn-solidity/src/stmt/emit.rs | 8 +- crates/syn-solidity/src/stmt/for.rs | 39 ++++- crates/syn-solidity/src/stmt/mod.rs | 47 +++--- crates/syn-solidity/src/stmt/revert.rs | 8 +- crates/syn-solidity/src/stmt/var_decl.rs | 23 ++- crates/syn-solidity/src/type/mod.rs | 108 +++++++------ crates/syn-solidity/src/utils.rs | 38 ++--- crates/syn-solidity/tests/contracts.rs | 22 ++- 24 files changed, 484 insertions(+), 269 deletions(-) diff --git a/crates/sol-macro/src/expand/contract.rs b/crates/sol-macro/src/expand/contract.rs index 296730460c..8cf627aa54 100644 --- a/crates/sol-macro/src/expand/contract.rs +++ b/crates/sol-macro/src/expand/contract.rs @@ -386,7 +386,7 @@ fn generate_variant_conversions(name: &Ident, variant: &Ident, ty: &Ident) -> To fn generate_variant_methods((variant, ty): (&Ident, &Ident)) -> TokenStream { let name = variant.unraw(); - let name_snake = name.to_string().to_snake_case(); + let name_snake = snakify(&name.to_string()); let is_variant = format_ident!("is_{name_snake}"); let is_variant_doc = format!("Returns `true` if `self` matches [`{name}`](Self::{name})."); @@ -427,3 +427,22 @@ fn generate_variant_methods((variant, ty): (&Ident, &Ident)) -> TokenStream { } } } + +/// `heck` doesn't treat numbers as new words, and discards leading underscores. +fn snakify(s: &str) -> String { + let leading = s.chars().take_while(|c| *c == '_'); + let mut output: Vec = leading.chain(s.to_snake_case().chars()).collect(); + + let mut num_starts = vec![]; + for (pos, c) in output.iter().enumerate() { + if pos != 0 && c.is_digit(10) && !output[pos - 1].is_digit(10) { + num_starts.push(pos); + } + } + // need to do in reverse, because after inserting, all chars after the point of + // insertion are off + for i in num_starts.into_iter().rev() { + output.insert(i, '_') + } + output.into_iter().collect() +} diff --git a/crates/syn-solidity/src/attribute/mod.rs b/crates/syn-solidity/src/attribute/mod.rs index c83c1d7be7..3efd239dc1 100644 --- a/crates/syn-solidity/src/attribute/mod.rs +++ b/crates/syn-solidity/src/attribute/mod.rs @@ -1,5 +1,5 @@ -use crate::{kw, utils::DebugPunctuated, SolPath, Spanned}; -use proc_macro2::{Span, TokenStream}; +use crate::{kw, utils::DebugPunctuated, Expr, SolPath, Spanned}; +use proc_macro2::Span; use std::{ fmt, hash::{Hash, Hasher}, @@ -133,8 +133,7 @@ impl Spanned for Override { pub struct Modifier { pub name: SolPath, pub paren_token: Option, - // TODO: Expr - pub arguments: Punctuated, + pub arguments: Punctuated, } impl PartialEq for Modifier { @@ -169,7 +168,8 @@ impl fmt::Display for Modifier { if i > 0 { f.write_str(", ")?; } - arg.fmt(f)?; + // TODO: impl fmt::Display for Expr + write!(f, "{arg:?}")?; } f.write_str(")")?; } @@ -183,7 +183,7 @@ impl Parse for Modifier { let this = if input.peek(Paren) { let content; let paren_token = parenthesized!(content in input); - let arguments = content.parse_terminated(TokenStream::parse, Token![,])?; + let arguments = content.parse_terminated(Expr::parse, Token![,])?; Self { name, paren_token: Some(paren_token), diff --git a/crates/syn-solidity/src/expr/args.rs b/crates/syn-solidity/src/expr/args.rs index d2262b5707..629600182f 100644 --- a/crates/syn-solidity/src/expr/args.rs +++ b/crates/syn-solidity/src/expr/args.rs @@ -1,4 +1,8 @@ -use crate::{kw, Expr, SolIdent, Spanned}; +use crate::{ + kw, + utils::{DebugPunctuated, ParseNested}, + Expr, SolIdent, Spanned, +}; use proc_macro2::Span; use std::fmt; use syn::{ @@ -16,15 +20,17 @@ pub struct ExprCall { pub args: ArgList, } -impl Parse for ExprCall { - fn parse(input: ParseStream<'_>) -> Result { +impl ParseNested for ExprCall { + fn parse_nested(expr: Box, input: ParseStream<'_>) -> Result { Ok(Self { - expr: input.parse()?, + expr, args: input.parse()?, }) } } +derive_parse!(ExprCall); + impl Spanned for ExprCall { fn span(&self) -> Span { let span = self.expr.span(); @@ -100,9 +106,7 @@ pub struct ArgList { impl fmt::Debug for ArgList { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("CallArgumentList") - .field("list", &self.list) - .finish() + f.debug_struct("ArgList").field("list", &self.list).finish() } } @@ -127,12 +131,24 @@ impl Spanned for ArgList { } /// A list of either unnamed or named arguments. -#[derive(Clone, Debug)] +#[derive(Clone)] pub enum ArgListImpl { Unnamed(Punctuated), Named(NamedArgList), } +impl fmt::Debug for ArgListImpl { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Unnamed(list) => f + .debug_tuple("Unnamed") + .field(DebugPunctuated::new(list)) + .finish(), + Self::Named(list) => f.debug_tuple("Named").field(list).finish(), + } + } +} + impl Parse for ArgListImpl { fn parse(input: ParseStream<'_>) -> Result { if input.peek(Brace) { @@ -152,15 +168,17 @@ pub struct ExprStruct { pub args: NamedArgList, } -impl Parse for ExprStruct { - fn parse(input: ParseStream<'_>) -> Result { +impl ParseNested for ExprStruct { + fn parse_nested(expr: Box, input: ParseStream<'_>) -> Result { Ok(Self { - expr: input.parse()?, + expr, args: input.parse()?, }) } } +derive_parse!(ExprStruct); + impl Spanned for ExprStruct { fn span(&self) -> Span { let span = self.expr.span(); @@ -182,8 +200,8 @@ pub struct NamedArgList { impl fmt::Debug for NamedArgList { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("NamedArgumentList") - .field("list", &self.list) + f.debug_struct("NamedArgList") + .field("list", DebugPunctuated::new(&self.list)) .finish() } } diff --git a/crates/syn-solidity/src/expr/array.rs b/crates/syn-solidity/src/expr/array.rs index 11fd9fe00a..edeb51dc0c 100644 --- a/crates/syn-solidity/src/expr/array.rs +++ b/crates/syn-solidity/src/expr/array.rs @@ -1,4 +1,7 @@ -use crate::{Expr, Spanned}; +use crate::{ + utils::{DebugPunctuated, ParseNested}, + Expr, Spanned, +}; use proc_macro2::Span; use std::fmt; use syn::{ @@ -19,7 +22,7 @@ pub struct ExprArray { impl fmt::Debug for ExprArray { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ExprArray") - .field("elems", &self.elems) + .field("elems", DebugPunctuated::new(&self.elems)) .finish() } } @@ -63,11 +66,11 @@ impl fmt::Debug for ExprIndex { } } -impl Parse for ExprIndex { - fn parse(input: ParseStream<'_>) -> Result { +impl ParseNested for ExprIndex { + fn parse_nested(expr: Box, input: ParseStream<'_>) -> Result { let content; Ok(Self { - expr: input.parse()?, + expr, bracket_token: bracketed!(content in input), start: if content.is_empty() || content.peek(Token![:]) { None @@ -83,6 +86,8 @@ impl Parse for ExprIndex { } } +derive_parse!(ExprIndex); + impl Spanned for ExprIndex { fn span(&self) -> Span { let span = self.expr.span(); diff --git a/crates/syn-solidity/src/expr/binary.rs b/crates/syn-solidity/src/expr/binary.rs index 75e7fa45e8..212d855552 100644 --- a/crates/syn-solidity/src/expr/binary.rs +++ b/crates/syn-solidity/src/expr/binary.rs @@ -1,4 +1,4 @@ -use crate::{Expr, Spanned}; +use crate::{utils::ParseNested, Expr, Spanned}; use proc_macro2::Span; use syn::{ parse::{Parse, ParseStream}, @@ -13,16 +13,18 @@ pub struct ExprBinary { pub right: Box, } -impl Parse for ExprBinary { - fn parse(input: ParseStream<'_>) -> Result { +impl ParseNested for ExprBinary { + fn parse_nested(expr: Box, input: ParseStream<'_>) -> Result { Ok(Self { - left: input.parse()?, + left: expr, op: input.parse()?, right: input.parse()?, }) } } +derive_parse!(ExprBinary); + impl Spanned for ExprBinary { fn span(&self) -> Span { let span = self.left.span(); @@ -38,26 +40,14 @@ impl Spanned for ExprBinary { op_enum! { /// A binary operator: `+`, `+=`, `&`. pub enum BinOp { - Add(+), - Sub(-), - Mul(*), - Div(/), - Rem(%), - Pow(**), - - Sar(>>>), - Shr(>>), - Shl(<<), - BitAnd(&), - BitOr(|), - BitXor(^), - - Lt(<), - Gt(>), Le(<=), Ge(>=), + Lt(<), + Gt(>), Eq(==), Neq(!=), + Or(||), + And(&&), Assign(=), AddAssign(+=), @@ -71,5 +61,19 @@ op_enum! { ShlAssign(<<=), ShrAssign(>>=), SarAssign(>>>=), + + Add(+), + Sub(-), + Pow(**), + Mul(*), + Div(/), + Rem(%), + + Sar(>>>), + Shr(>>), + Shl(<<), + BitAnd(&), + BitOr(|), + BitXor(^), } } diff --git a/crates/syn-solidity/src/expr/member.rs b/crates/syn-solidity/src/expr/member.rs index 2ba050dc2d..a39412d3b1 100644 --- a/crates/syn-solidity/src/expr/member.rs +++ b/crates/syn-solidity/src/expr/member.rs @@ -1,4 +1,4 @@ -use crate::{Expr, Spanned}; +use crate::{utils::ParseNested, Expr, Spanned}; use proc_macro2::Span; use std::fmt; use syn::{ @@ -23,16 +23,18 @@ impl fmt::Debug for ExprMember { } } -impl Parse for ExprMember { - fn parse(input: ParseStream<'_>) -> Result { +impl ParseNested for ExprMember { + fn parse_nested(expr: Box, input: ParseStream<'_>) -> Result { Ok(Self { - expr: input.parse()?, + expr, dot_token: input.parse()?, member: input.parse()?, }) } } +derive_parse!(ExprMember); + impl Spanned for ExprMember { fn span(&self) -> Span { self.expr diff --git a/crates/syn-solidity/src/expr/mod.rs b/crates/syn-solidity/src/expr/mod.rs index 8ed4e95f4b..6c95376158 100644 --- a/crates/syn-solidity/src/expr/mod.rs +++ b/crates/syn-solidity/src/expr/mod.rs @@ -1,7 +1,9 @@ +use std::fmt; + use proc_macro2::{Ident, Span}; use syn::{ ext::IdentExt, - parse::{discouraged::Speculative, Parse, ParseStream}, + parse::{Parse, ParseStream}, token::{Brace, Bracket, Paren}, Result, Token, }; @@ -30,13 +32,13 @@ pub use r#type::{ExprNew, ExprTypeCall}; mod unary; pub use unary::{ExprDelete, ExprPostfix, ExprUnary, PostUnOp, UnOp}; -use crate::{kw, Lit, SolIdent, Spanned, Type}; +use crate::{kw, utils::ParseNested, Lit, SolIdent, Spanned, Type}; /// An expression. /// /// Solidity reference: /// -#[derive(Clone, Debug)] +#[derive(Clone)] pub enum Expr { /// An array literal expression: `[a, b, c, d]`. Array(ExprArray), @@ -81,6 +83,8 @@ pub enum Expr { Tuple(ExprTuple), /// A type name. + /// + /// Cannot be `Custom`, as custom identifiers are parsed as `Ident` instead. Type(Type), /// A `type()` expression: `type(uint256)` @@ -90,14 +94,106 @@ pub enum Expr { Unary(ExprUnary), } +impl fmt::Debug for Expr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Expr::")?; + match self { + Self::Array(expr) => expr.fmt(f), + Self::Binary(expr) => expr.fmt(f), + Self::Call(expr) => expr.fmt(f), + Self::Delete(expr) => expr.fmt(f), + Self::Ident(ident) => ident.fmt(f), + Self::Index(expr) => expr.fmt(f), + Self::Lit(lit) => lit.fmt(f), + Self::Member(expr) => expr.fmt(f), + Self::New(expr) => expr.fmt(f), + Self::Payable(expr) => expr.fmt(f), + Self::Postfix(expr) => expr.fmt(f), + Self::Struct(expr) => expr.fmt(f), + Self::Ternary(expr) => expr.fmt(f), + Self::Tuple(expr) => expr.fmt(f), + Self::Type(ty) => ty.fmt(f), + Self::TypeCall(expr) => expr.fmt(f), + Self::Unary(expr) => expr.fmt(f), + } + } +} + impl Parse for Expr { fn parse(input: ParseStream<'_>) -> Result { + // skip any attributes + let _ = input.call(syn::Attribute::parse_outer)?; + + debug!(" >> {:?}", input.to_string()); + let mut expr = Self::parse_simple(input)?; + debug!(" > {expr:?}"); + loop { + let (new, cont) = Self::parse_nested(expr, input)?; + if cont { + debug!(" > {new:?}"); + expr = new; + } else { + return Ok(new) + } + } + } +} + +impl Spanned for Expr { + fn span(&self) -> Span { + match self { + Self::Array(expr) => expr.span(), + Self::Binary(expr) => expr.span(), + Self::Call(expr) => expr.span(), + Self::Delete(expr) => expr.span(), + Self::Ident(ident) => ident.span(), + Self::Index(expr) => expr.span(), + Self::Lit(lit) => lit.span(), + Self::Member(expr) => expr.span(), + Self::New(expr) => expr.span(), + Self::Payable(expr) => expr.span(), + Self::Postfix(expr) => expr.span(), + Self::Struct(expr) => expr.span(), + Self::Ternary(expr) => expr.span(), + Self::Tuple(expr) => expr.span(), + Self::Type(ty) => ty.span(), + Self::TypeCall(expr) => expr.span(), + Self::Unary(expr) => expr.span(), + } + } + + fn set_span(&mut self, span: Span) { + match self { + Self::Array(expr) => expr.set_span(span), + Self::Binary(expr) => expr.set_span(span), + Self::Call(expr) => expr.set_span(span), + Self::Delete(expr) => expr.set_span(span), + Self::Ident(ident) => ident.set_span(span), + Self::Index(expr) => expr.set_span(span), + Self::Lit(lit) => lit.set_span(span), + Self::Member(expr) => expr.set_span(span), + Self::New(expr) => expr.set_span(span), + Self::Payable(expr) => expr.set_span(span), + Self::Postfix(expr) => expr.set_span(span), + Self::Struct(expr) => expr.set_span(span), + Self::Ternary(expr) => expr.set_span(span), + Self::Tuple(expr) => expr.set_span(span), + Self::Type(ty) => ty.set_span(span), + Self::TypeCall(expr) => expr.set_span(span), + Self::Unary(expr) => expr.set_span(span), + } + } +} + +impl Expr { + fn parse_simple(input: ParseStream<'_>) -> Result { let lookahead = input.lookahead1(); if lookahead.peek(Paren) { - // TODO: tuple type? input.parse().map(Self::Tuple) } else if lookahead.peek(Bracket) { input.parse().map(Self::Array) + } else if UnOp::peek(input, &lookahead) { + input.parse().map(Self::Unary) } else if Lit::peek(&lookahead) { input.parse().map(Self::Lit) } else if lookahead.peek(kw::payable) { @@ -108,93 +204,40 @@ impl Parse for Expr { input.parse().map(Self::New) } else if lookahead.peek(kw::delete) { input.parse().map(Self::Delete) - } else if lookahead.peek(Ident::peek_any) { - let fork = input.fork(); - match fork.parse() { - Ok(ty) => { - input.advance_to(&fork); - Ok(Self::Type(ty)) - } - Err(_) => input.parse().map(Self::Ident), + } else if let Ok(ident) = input.call(Ident::parse_any) { + match Type::parse_ident(ident.clone()) { + Ok(ty) if !ty.is_custom() => ty.parse_payable(input).map(Self::Type), + _ => Ok(Self::Ident(ident.into())), } - } else if UnOp::peek(input, &lookahead) { - input.parse().map(Self::Unary) } else { - let fork = input.fork(); - match input.parse::() { - Ok(_) => Self::parse2(input, &fork), - Err(_) => Err(lookahead.error()), - } + Err(lookahead.error()) } } -} -impl Expr { /// Parse an expression that starts with an expression. - fn parse2(input: ParseStream<'_>, start: ParseStream<'_>) -> Result { + /// + /// Returns `(ParseResult, continue_parsing)` + fn parse_nested(expr: Self, input: ParseStream<'_>) -> Result<(Self, bool)> { + let mut cont = true; let lookahead = input.lookahead1(); if lookahead.peek(Bracket) { - start.parse().map(Self::Index) + ParseNested::parse_nested(expr.into(), input).map(Self::Index) } else if lookahead.peek(Brace) { - start.parse().map(Self::Struct) + ParseNested::parse_nested(expr.into(), input).map(Self::Struct) } else if lookahead.peek(Paren) { - start.parse().map(Self::Call) + ParseNested::parse_nested(expr.into(), input).map(Self::Call) } else if lookahead.peek(Token![.]) { - start.parse().map(Self::Member) + ParseNested::parse_nested(expr.into(), input).map(Self::Member) } else if lookahead.peek(Token![?]) { - start.parse().map(Self::Ternary) + ParseNested::parse_nested(expr.into(), input).map(Self::Ternary) } else if PostUnOp::peek(input, &lookahead) { - start.parse().map(Self::Postfix) + ParseNested::parse_nested(expr.into(), input).map(Self::Postfix) } else if BinOp::peek(input, &lookahead) { - start.parse().map(Self::Binary) + ParseNested::parse_nested(expr.into(), input).map(Self::Binary) } else { - Err(lookahead.error()) - } - } -} - -impl Spanned for Expr { - fn span(&self) -> Span { - match self { - Self::Index(expr) => expr.span(), - Self::Member(expr) => expr.span(), - Self::Struct(expr) => expr.span(), - Self::Call(expr) => expr.span(), - Self::Payable(expr) => expr.span(), - Self::TypeCall(expr) => expr.span(), - Self::Unary(expr) => expr.span(), - Self::Binary(expr) => expr.span(), - Self::Ternary(expr) => expr.span(), - Self::Postfix(expr) => expr.span(), - Self::New(expr) => expr.span(), - Self::Delete(expr) => expr.span(), - Self::Tuple(expr) => expr.span(), - Self::Array(expr) => expr.span(), - Self::Ident(expr) => expr.span(), - Self::Lit(expr) => expr.span(), - Self::Type(expr) => expr.span(), - } - } - - fn set_span(&mut self, span: Span) { - match self { - Self::Index(expr) => expr.set_span(span), - Self::Member(expr) => expr.set_span(span), - Self::Struct(expr) => expr.set_span(span), - Self::Call(expr) => expr.set_span(span), - Self::Payable(expr) => expr.set_span(span), - Self::TypeCall(expr) => expr.set_span(span), - Self::Unary(expr) => expr.set_span(span), - Self::Binary(expr) => expr.set_span(span), - Self::Ternary(expr) => expr.set_span(span), - Self::Postfix(expr) => expr.set_span(span), - Self::New(expr) => expr.set_span(span), - Self::Delete(expr) => expr.set_span(span), - Self::Tuple(expr) => expr.set_span(span), - Self::Array(expr) => expr.set_span(span), - Self::Ident(expr) => expr.set_span(span), - Self::Lit(expr) => expr.set_span(span), - Self::Type(expr) => expr.set_span(span), + cont = false; + Ok(expr) } + .map(|expr| (expr, cont)) } } diff --git a/crates/syn-solidity/src/expr/ternary.rs b/crates/syn-solidity/src/expr/ternary.rs index 05aba9d246..8523590fa7 100644 --- a/crates/syn-solidity/src/expr/ternary.rs +++ b/crates/syn-solidity/src/expr/ternary.rs @@ -1,4 +1,4 @@ -use crate::{Expr, Spanned}; +use crate::{utils::ParseNested, Expr, Spanned}; use proc_macro2::Span; use std::fmt; use syn::{ @@ -26,10 +26,10 @@ impl fmt::Debug for ExprTernary { } } -impl Parse for ExprTernary { - fn parse(input: ParseStream<'_>) -> Result { +impl ParseNested for ExprTernary { + fn parse_nested(expr: Box, input: ParseStream<'_>) -> Result { Ok(Self { - cond: input.parse()?, + cond: expr, question_token: input.parse()?, if_true: input.parse()?, colon_token: input.parse()?, @@ -38,6 +38,8 @@ impl Parse for ExprTernary { } } +derive_parse!(ExprTernary); + impl Spanned for ExprTernary { fn span(&self) -> Span { let span = self.cond.span(); diff --git a/crates/syn-solidity/src/expr/tuple.rs b/crates/syn-solidity/src/expr/tuple.rs index b77a28bab2..e3637c4bf7 100644 --- a/crates/syn-solidity/src/expr/tuple.rs +++ b/crates/syn-solidity/src/expr/tuple.rs @@ -1,4 +1,4 @@ -use crate::{Expr, Spanned}; +use crate::{utils::DebugPunctuated, Expr, Spanned}; use proc_macro2::Span; use std::fmt; use syn::{ @@ -19,7 +19,7 @@ pub struct ExprTuple { impl fmt::Debug for ExprTuple { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ExprTuple") - .field("elems", &self.elems) + .field("elems", DebugPunctuated::new(&self.elems)) .finish() } } diff --git a/crates/syn-solidity/src/expr/unary.rs b/crates/syn-solidity/src/expr/unary.rs index 2b785179ea..c91c79befd 100644 --- a/crates/syn-solidity/src/expr/unary.rs +++ b/crates/syn-solidity/src/expr/unary.rs @@ -1,4 +1,4 @@ -use crate::{kw, Expr, Spanned}; +use crate::{kw, utils::ParseNested, Expr, Spanned}; use proc_macro2::Span; use std::fmt; use syn::{ @@ -77,15 +77,17 @@ pub struct ExprPostfix { pub op: PostUnOp, } -impl Parse for ExprPostfix { - fn parse(input: ParseStream<'_>) -> Result { +impl ParseNested for ExprPostfix { + fn parse_nested(expr: Box, input: ParseStream<'_>) -> Result { Ok(Self { - expr: input.parse()?, + expr, op: input.parse()?, }) } } +derive_parse!(ExprPostfix); + impl Spanned for ExprPostfix { fn span(&self) -> Span { let span = self.op.span(); diff --git a/crates/syn-solidity/src/lib.rs b/crates/syn-solidity/src/lib.rs index 8b5dcc06e0..b84c57a1a1 100644 --- a/crates/syn-solidity/src/lib.rs +++ b/crates/syn-solidity/src/lib.rs @@ -83,3 +83,5 @@ pub fn parse(input: proc_macro::TokenStream) -> Result { pub fn parse2(input: proc_macro2::TokenStream) -> Result { syn::parse2(input) } + +const DEBUG: bool = true; diff --git a/crates/syn-solidity/src/lit/str.rs b/crates/syn-solidity/src/lit/str.rs index 1f0b1861b8..d129f57bfb 100644 --- a/crates/syn-solidity/src/lit/str.rs +++ b/crates/syn-solidity/src/lit/str.rs @@ -1,11 +1,11 @@ -use crate::{kw, utils::parse_vec, Spanned}; +use crate::{kw, Spanned}; use proc_macro2::Span; use std::{ fmt, ops::{Deref, DerefMut}, }; use syn::{ - parse::{Parse, ParseStream}, + parse::{Lookahead1, Parse, ParseStream}, Result, }; @@ -34,31 +34,31 @@ macro_rules! str_lit { impl Parse for $name { fn parse(input: ParseStream<'_>) -> Result { - Ok(Self { - values: parse_vec(input, false)?, - }) + let mut values = Vec::new(); + while Self::peek(&input.lookahead1()) { + values.push(input.parse()?); + } + Ok(Self { values }) } } impl Spanned for $name { fn span(&self) -> Span { - let mut span = self.values.first().unwrap().span(); - for value in &self.values[1..] { - span = span.join(value.span()).unwrap_or(span); - } - span + crate::utils::join_spans(&self.values) } fn set_span(&mut self, span: Span) { - for value in &mut self.values { - value.set_span(span); - } + crate::utils::set_spans(&mut self.values, span) } } impl $name { + pub fn peek(lookahead: &Lookahead1<'_>) -> bool { + $(lookahead.peek(kw::$kw) || )? lookahead.peek(syn::LitStr) + } + pub fn parse_opt(input: ParseStream<'_>) -> Result> { - if $(input.peek(kw::$kw) || )? input.peek(syn::LitStr) { + if Self::peek(&input.lookahead1()) { input.parse().map(Some) } else { Ok(None) diff --git a/crates/syn-solidity/src/macros.rs b/crates/syn-solidity/src/macros.rs index 627f2576b4..e380c3b28d 100644 --- a/crates/syn-solidity/src/macros.rs +++ b/crates/syn-solidity/src/macros.rs @@ -415,18 +415,15 @@ macro_rules! op_enum { impl $crate::Spanned for $name { fn span(&self) -> ::proc_macro2::Span { - todo!() - // match self {$( - // Self::$variant(kw, ..) => kw.span(), - // )+} + match self {$( + Self::$variant(kw, ..) => kw.span(), + )+} } fn set_span(&mut self, span: ::proc_macro2::Span) { - let _ = span; - todo!() - // match self {$( - // Self::$variant(kw, ..) => kw.set_span(span), - // )+} + match self {$( + Self::$variant(kw, ..) => kw.set_span(span), + )+} } } @@ -472,3 +469,24 @@ macro_rules! op_enum { } }; } + +macro_rules! derive_parse { + ($($t:ty),+ $(,)?) => {$( + impl Parse for $t { + fn parse(input: ParseStream<'_>) -> Result { + ::parse_nested( + input.parse()?, + input, + ) + } + } + )+}; +} + +macro_rules! debug { + ($($t:tt)*) => { + if $crate::DEBUG { + eprintln!($($t)*) + } + }; +} diff --git a/crates/syn-solidity/src/spanned.rs b/crates/syn-solidity/src/spanned.rs index cbcf70e9b5..8e425eba7e 100644 --- a/crates/syn-solidity/src/spanned.rs +++ b/crates/syn-solidity/src/spanned.rs @@ -37,12 +37,22 @@ impl Spanned for TokenStream { impl Spanned for TokenTree { #[inline] fn span(&self) -> Span { - TokenTree::span(self) + self.span() } #[inline] fn set_span(&mut self, span: Span) { - TokenTree::set_span(self, span) + self.set_span(span); + } +} + +impl Spanned for syn::LitStr { + fn span(&self) -> Span { + self.span() + } + + fn set_span(&mut self, span: Span) { + self.set_span(span); } } diff --git a/crates/syn-solidity/src/stmt/assembly.rs b/crates/syn-solidity/src/stmt/assembly.rs index 8d1a2941dd..7596241103 100644 --- a/crates/syn-solidity/src/stmt/assembly.rs +++ b/crates/syn-solidity/src/stmt/assembly.rs @@ -1,4 +1,4 @@ -use crate::{kw, LitStr, Spanned, YulBlock}; +use crate::{kw, utils::DebugPunctuated, LitStr, Spanned, YulBlock}; use proc_macro2::Span; use std::fmt; use syn::{ @@ -59,7 +59,7 @@ pub struct AssemblyFlags { impl fmt::Debug for AssemblyFlags { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("AssemblyFlags") - .field("strings", &self.strings) + .field("strings", DebugPunctuated::new(&self.strings)) .finish() } } diff --git a/crates/syn-solidity/src/stmt/blocks.rs b/crates/syn-solidity/src/stmt/blocks.rs index b55ee0b1b6..59f8d4618d 100644 --- a/crates/syn-solidity/src/stmt/blocks.rs +++ b/crates/syn-solidity/src/stmt/blocks.rs @@ -25,7 +25,16 @@ impl Parse for Block { let content; Ok(Self { brace_token: syn::braced!(content in input), - stmts: crate::utils::parse_vec(&content, true)?, + stmts: { + let mut vec = Vec::new(); + while !content.is_empty() { + debug!(">>> {:?}", content.to_string()); + let r = content.parse(); + debug!("<<< {r:?}\n"); + vec.push(r?); + } + vec + }, }) } } diff --git a/crates/syn-solidity/src/stmt/emit.rs b/crates/syn-solidity/src/stmt/emit.rs index 15f45c56cd..9566345716 100644 --- a/crates/syn-solidity/src/stmt/emit.rs +++ b/crates/syn-solidity/src/stmt/emit.rs @@ -1,4 +1,4 @@ -use crate::{kw, ArgList, Expr, Spanned}; +use crate::{kw, Expr, Spanned}; use proc_macro2::Span; use std::fmt; use syn::{ @@ -14,7 +14,7 @@ use syn::{ pub struct StmtEmit { pub emit_token: kw::emit, pub expr: Expr, - pub list: ArgList, + // pub list: ArgList, // TODO pub semi_token: Token![;], } @@ -22,7 +22,7 @@ impl fmt::Debug for StmtEmit { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("StmtEmit") .field("expr", &self.expr) - .field("list", &self.list) + // .field("list", &self.list) .finish() } } @@ -32,7 +32,7 @@ impl Parse for StmtEmit { Ok(Self { emit_token: input.parse()?, expr: input.parse()?, - list: input.parse()?, + // list: input.parse()?, semi_token: input.parse()?, }) } diff --git a/crates/syn-solidity/src/stmt/for.rs b/crates/syn-solidity/src/stmt/for.rs index f9c8e0b900..b26d3ca290 100644 --- a/crates/syn-solidity/src/stmt/for.rs +++ b/crates/syn-solidity/src/stmt/for.rs @@ -2,6 +2,7 @@ use crate::{Expr, Spanned, Stmt, StmtExpr, StmtVarDecl}; use proc_macro2::Span; use std::fmt; use syn::{ + parenthesized, parse::{Parse, ParseStream}, token::Paren, Result, Token, @@ -15,10 +16,9 @@ use syn::{ pub struct StmtFor { pub for_token: Token![for], pub paren_token: Paren, - pub init: Option, - pub semi_token1: Token![;], + pub init: ForInitStmt, pub cond: Option, - pub semi_token2: Token![;], + pub semi_token: Token![;], pub post: Option, pub body: Box, } @@ -35,8 +35,25 @@ impl fmt::Debug for StmtFor { } impl Parse for StmtFor { - fn parse(_input: ParseStream<'_>) -> Result { - todo!() + fn parse(input: ParseStream<'_>) -> Result { + let content; + Ok(Self { + for_token: input.parse()?, + paren_token: parenthesized!(content in input), + init: content.parse()?, + cond: if content.peek(Token![;]) { + None + } else { + Some(content.parse()?) + }, + semi_token: content.parse()?, + post: if content.is_empty() { + None + } else { + Some(content.parse()?) + }, + body: input.parse()?, + }) } } @@ -56,10 +73,18 @@ impl Spanned for StmtFor { pub enum ForInitStmt { VarDecl(StmtVarDecl), Expression(StmtExpr), + Empty(Token![;]), } impl Parse for ForInitStmt { - fn parse(_input: ParseStream<'_>) -> Result { - todo!() + fn parse(input: ParseStream<'_>) -> Result { + let lookahead = input.lookahead1(); + if lookahead.peek(Token![;]) { + input.parse().map(Self::Empty) + } else if StmtVarDecl::peek(input, &lookahead) { + input.parse().map(Self::VarDecl) + } else { + input.parse().map(Self::Expression) + } } } diff --git a/crates/syn-solidity/src/stmt/mod.rs b/crates/syn-solidity/src/stmt/mod.rs index 39729a789d..e2fc278816 100644 --- a/crates/syn-solidity/src/stmt/mod.rs +++ b/crates/syn-solidity/src/stmt/mod.rs @@ -1,4 +1,6 @@ mod assembly; +use std::fmt; + pub use assembly::StmtAssembly; mod blocks; @@ -43,7 +45,7 @@ pub use r#while::StmtWhile; use crate::{kw, Spanned}; use proc_macro2::Span; use syn::{ - parse::{discouraged::Speculative, Parse, ParseStream}, + parse::{Parse, ParseStream}, token::{Brace, Paren}, Result, Token, }; @@ -52,7 +54,7 @@ use syn::{ /// /// Solidity reference: /// -#[derive(Clone, Debug)] +#[derive(Clone)] pub enum Stmt { /// An assembly block, with optional flags: `assembly "evmasm" { ... }`. Assembly(StmtAssembly), @@ -101,6 +103,29 @@ pub enum Stmt { While(StmtWhile), } +impl fmt::Debug for Stmt { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Stmt::")?; + match self { + Self::Assembly(stmt) => stmt.fmt(f), + Self::Block(block) => block.fmt(f), + Self::Break(stmt) => stmt.fmt(f), + Self::Continue(stmt) => stmt.fmt(f), + Self::DoWhile(stmt) => stmt.fmt(f), + Self::Emit(stmt) => stmt.fmt(f), + Self::Expr(stmt) => stmt.fmt(f), + Self::For(stmt) => stmt.fmt(f), + Self::If(stmt) => stmt.fmt(f), + Self::Return(stmt) => stmt.fmt(f), + Self::Revert(stmt) => stmt.fmt(f), + Self::Try(stmt) => stmt.fmt(f), + Self::UncheckedBlock(block) => block.fmt(f), + Self::VarDecl(stmt) => stmt.fmt(f), + Self::While(stmt) => stmt.fmt(f), + } + } +} + impl Parse for Stmt { fn parse(input: ParseStream<'_>) -> Result { let lookahead = input.lookahead1(); @@ -136,24 +161,10 @@ impl Parse for Stmt { input.parse().map(Self::Revert) } else if lookahead.peek(kw::assembly) { input.parse().map(Self::Assembly) - } else if lookahead.peek(kw::tuple) - || lookahead.peek(kw::function) - || lookahead.peek(kw::mapping) - { + } else if StmtVarDecl::peek(input, &lookahead) { input.parse().map(Self::VarDecl) } else { - // TODO: Handle this better - let start = input.fork(); - match input.parse() { - Ok(var) => Ok(Self::VarDecl(var)), - Err(_) => match start.parse() { - Ok(expr) => { - input.advance_to(&start); - Ok(Self::Expr(expr)) - } - Err(_) => Err(lookahead.error()), - }, - } + input.parse().map(Self::Expr) } } } diff --git a/crates/syn-solidity/src/stmt/revert.rs b/crates/syn-solidity/src/stmt/revert.rs index e4506c2ab0..0fd423ff4b 100644 --- a/crates/syn-solidity/src/stmt/revert.rs +++ b/crates/syn-solidity/src/stmt/revert.rs @@ -1,4 +1,4 @@ -use crate::{kw, ArgList, Expr, Spanned}; +use crate::{kw, Expr, Spanned}; use proc_macro2::Span; use std::fmt; use syn::{ @@ -14,7 +14,7 @@ use syn::{ pub struct StmtRevert { pub revert_token: kw::revert, pub expr: Expr, - pub list: ArgList, + // pub list: ArgList, // TODO pub semi_token: Token![;], } @@ -22,7 +22,7 @@ impl fmt::Debug for StmtRevert { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("StmtRevert") .field("expr", &self.expr) - .field("list", &self.list) + // .field("list", &self.list) .finish() } } @@ -32,7 +32,7 @@ impl Parse for StmtRevert { Ok(Self { revert_token: input.parse()?, expr: input.parse()?, - list: input.parse()?, + // list: input.parse()?, semi_token: input.parse()?, }) } diff --git a/crates/syn-solidity/src/stmt/var_decl.rs b/crates/syn-solidity/src/stmt/var_decl.rs index c900956599..11ac58fe6c 100644 --- a/crates/syn-solidity/src/stmt/var_decl.rs +++ b/crates/syn-solidity/src/stmt/var_decl.rs @@ -1,9 +1,10 @@ -use crate::{Expr, Spanned, VariableDeclaration}; -use proc_macro2::Span; +use crate::{kw, utils::DebugPunctuated, Expr, Spanned, VariableDeclaration}; +use proc_macro2::{Ident, Span}; use std::fmt; use syn::{ + ext::IdentExt, parenthesized, - parse::{Parse, ParseStream}, + parse::{Lookahead1, Parse, ParseStream}, punctuated::Punctuated, token::Paren, Result, Token, @@ -64,6 +65,18 @@ impl Spanned for StmtVarDecl { } } +impl StmtVarDecl { + pub fn peek(input: ParseStream<'_>, lookahead: &Lookahead1<'_>) -> bool { + lookahead.peek(kw::tuple) + || lookahead.peek(kw::function) + || lookahead.peek(kw::mapping) + || (lookahead.peek(Paren) && input.peek2(Token![=])) + || (input.peek(Ident::peek_any) + && input.peek2(Ident::peek_any) + && (input.peek3(Token![=]) || input.peek3(Token![;]))) + } +} + /// The declaration of the variable(s) in a [`StmtVarDecl`]. #[derive(Clone, Debug)] pub enum VarDeclDecl { @@ -111,8 +124,8 @@ pub struct VarDeclTuple { impl fmt::Debug for VarDeclTuple { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TupleVarDecl") - .field("vars", &self.vars) + f.debug_struct("VarDeclTuple") + .field("vars", DebugPunctuated::new(&self.vars)) .finish() } } diff --git a/crates/syn-solidity/src/type/mod.rs b/crates/syn-solidity/src/type/mod.rs index 4dd65dab6c..c38c038a6b 100644 --- a/crates/syn-solidity/src/type/mod.rs +++ b/crates/syn-solidity/src/type/mod.rs @@ -30,6 +30,7 @@ pub use tuple::TypeTuple; /// #[derive(Clone)] pub enum Type { + // TODO: `fixed` and `ufixed` /// `address $(payable)?` Address(Span, Option), /// `bool` @@ -106,6 +107,7 @@ impl Hash for Type { impl fmt::Debug for Type { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Type::")?; match self { Self::Address(_, None) => f.write_str("Address"), Self::Address(_, Some(_)) => f.write_str("AddressPayable"), @@ -207,6 +209,10 @@ impl Spanned for Type { } impl Type { + pub fn custom(ident: Ident) -> Self { + Self::Custom(sol_path![ident]) + } + pub fn peek(lookahead: &Lookahead1<'_>) -> bool { lookahead.peek(syn::token::Paren) || lookahead.peek(kw::tuple) @@ -215,8 +221,61 @@ impl Type { || lookahead.peek(Ident::peek_any) } - pub fn custom(ident: Ident) -> Self { - Self::Custom(sol_path![ident]) + /// Parses an identifier as an [elementary type name][ref]. + /// + /// Note that you will have to check for the existence of a `payable` + /// keyword separately. + /// + /// [ref]: https://docs.soliditylang.org/en/latest/grammar.html#a4.SolidityParser.elementaryTypeName + pub fn parse_ident(ident: Ident) -> Result { + let span = ident.span(); + let s = ident.to_string(); + let ret = match s.as_str() { + "address" => Self::Address(span, None), + "bool" => Self::Bool(span), + "string" => Self::String(span), + s => { + if let Some(s) = s.strip_prefix("bytes") { + match parse_size(s, span)? { + None => Self::custom(ident), + Some(Some(size)) if size.get() > 32 => { + return Err(Error::new(span, "fixed bytes range is 1-32")) + } + Some(Some(size)) => Self::FixedBytes(span, size), + Some(None) => Self::Bytes(span), + } + } else if let Some(s) = s.strip_prefix("int") { + match parse_size(s, span)? { + None => Self::custom(ident), + Some(Some(size)) if size.get() > 256 || size.get() % 8 != 0 => { + return Err(Error::new(span, "intX must be a multiple of 8 up to 256")) + } + Some(size) => Self::Int(span, size), + } + } else if let Some(s) = s.strip_prefix("uint") { + match parse_size(s, span)? { + None => Self::custom(ident), + Some(Some(size)) if size.get() > 256 || size.get() % 8 != 0 => { + return Err(Error::new(span, "uintX must be a multiple of 8 up to 256")) + } + Some(size) => Self::Uint(span, size), + } + } else { + Self::custom(ident) + } + } + }; + Ok(ret) + } + + /// Parses the `payable` keyword from the input stream if this type is an + /// address. + pub fn parse_payable(mut self, input: ParseStream<'_>) -> Result { + match &mut self { + Self::Address(_, opt @ None) => *opt = input.parse()?, + _ => {} + } + Ok(self) } /// Returns whether this type is ABI-encoded as a single EVM word (32 @@ -329,50 +388,7 @@ impl Type { input.parse().map(Self::Custom) } else if input.peek(Ident::peek_any) { let ident = input.call(Ident::parse_any)?; - let span = ident.span(); - let s = ident.to_string(); - let ret = match s.as_str() { - "address" => Self::Address(span, input.parse()?), - "bool" => Self::Bool(span), - "string" => Self::String(span), - s => { - if let Some(s) = s.strip_prefix("bytes") { - match parse_size(s, span)? { - None => Self::custom(ident), - Some(Some(size)) if size.get() > 32 => { - return Err(Error::new(span, "fixed bytes range is 1-32")) - } - Some(None) => Self::Bytes(span), - Some(Some(size)) => Self::FixedBytes(span, size), - } - } else if let Some(s) = s.strip_prefix("int") { - match parse_size(s, span)? { - None => Self::custom(ident), - Some(Some(size)) if size.get() > 256 || size.get() % 8 != 0 => { - return Err(Error::new( - span, - "intX must be a multiple of 8 up to 256", - )) - } - Some(size) => Self::Int(span, size), - } - } else if let Some(s) = s.strip_prefix("uint") { - match parse_size(s, span)? { - None => Self::custom(ident), - Some(Some(size)) if size.get() > 256 || size.get() % 8 != 0 => { - return Err(Error::new( - span, - "uintX must be a multiple of 8 up to 256", - )) - } - Some(size) => Self::Uint(span, size), - } - } else { - Self::custom(ident) - } - } - }; - Ok(ret) + Self::parse_ident(ident)?.parse_payable(input) } else { Err(input.error( "expected a Solidity type: \ diff --git a/crates/syn-solidity/src/utils.rs b/crates/syn-solidity/src/utils.rs index 56c3d2a5d2..aa3d5a5ff3 100644 --- a/crates/syn-solidity/src/utils.rs +++ b/crates/syn-solidity/src/utils.rs @@ -1,11 +1,13 @@ -use crate::Spanned; -use proc_macro2::{Span, TokenStream, TokenTree}; +use crate::{Expr, Spanned}; +use proc_macro2::{Delimiter, Span, TokenStream, TokenTree}; use std::fmt; -use syn::{ - parse::{Parse, ParseStream}, - punctuated::Punctuated, - Result, Token, -}; +use syn::{parse::ParseStream, punctuated::Punctuated, Result, Token}; + +/// Helper trait to parsing nested expressions. +pub(crate) trait ParseNested: Sized { + /// Parse `Self` as an expression that starts with `expr`. + fn parse_nested(expr: Box, input: ParseStream<'_>) -> Result; +} #[repr(transparent)] pub(crate) struct DebugPunctuated(Punctuated); @@ -23,6 +25,17 @@ impl fmt::Debug for DebugPunctuated { } } +#[allow(dead_code)] +pub(crate) fn peek_tt(input: ParseStream<'_>) -> Option { + let tt = input.cursor().token_tree(); + tt.and_then(|(tt, _)| match tt { + TokenTree::Group(g) if matches!(g.delimiter(), Delimiter::None) => { + g.stream().into_iter().next() + } + _ => Some(tt), + }) +} + pub(crate) fn tts_until_semi(input: ParseStream<'_>) -> TokenStream { let mut tts = TokenStream::new(); while !input.is_empty() && !input.peek(Token![;]) { @@ -32,17 +45,6 @@ pub(crate) fn tts_until_semi(input: ParseStream<'_>) -> TokenStream { tts } -pub(crate) fn parse_vec(input: ParseStream<'_>, allow_empty: bool) -> Result> { - let mut vec = Vec::new(); - if !allow_empty { - vec.push(input.parse()?); - } - while !input.is_empty() { - vec.push(input.parse()?); - } - Ok(vec) -} - pub(crate) fn join_spans>(items: I) -> Span { let mut iter = items.into_iter(); let Some(first) = iter.next() else { diff --git a/crates/syn-solidity/tests/contracts.rs b/crates/syn-solidity/tests/contracts.rs index c11c1d0ceb..fdbc6e383e 100644 --- a/crates/syn-solidity/tests/contracts.rs +++ b/crates/syn-solidity/tests/contracts.rs @@ -36,13 +36,27 @@ fn contracts() { let mut failed = false; for file in files { let path = file.path(); - match parse_file(&path) { - Ok(()) => {} - Err(e) => { - let name = path.file_name().unwrap().to_str().unwrap(); + let name = path.file_name().unwrap().to_str().unwrap(); + match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| parse_file(&path))) { + Ok(Ok(())) => {} + Ok(Err(e)) => { eprintln!("failed to parse {name}: {e} ({e:?})"); failed = true; } + Err(payload) => { + let msg = match payload.downcast_ref::<&'static str>() { + Some(s) => *s, + None => match payload.downcast_ref::() { + Some(s) => &s[..], + None => "Box", + }, + }; + eprintln!("panicked while parsing {name}: {msg}"); + failed = true; + } + } + if failed { + break } } From ea3bdd28694a88c1191d37ba3653e4c1a7e909f0 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Sat, 5 Aug 2023 04:42:07 +0200 Subject: [PATCH 15/22] fix(sol-macro): snake_case'd function names --- crates/sol-macro/src/expand/contract.rs | 21 ++++++++++++++++++++- crates/sol-types/tests/sol.rs | 17 +++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/crates/sol-macro/src/expand/contract.rs b/crates/sol-macro/src/expand/contract.rs index 296730460c..8cf627aa54 100644 --- a/crates/sol-macro/src/expand/contract.rs +++ b/crates/sol-macro/src/expand/contract.rs @@ -386,7 +386,7 @@ fn generate_variant_conversions(name: &Ident, variant: &Ident, ty: &Ident) -> To fn generate_variant_methods((variant, ty): (&Ident, &Ident)) -> TokenStream { let name = variant.unraw(); - let name_snake = name.to_string().to_snake_case(); + let name_snake = snakify(&name.to_string()); let is_variant = format_ident!("is_{name_snake}"); let is_variant_doc = format!("Returns `true` if `self` matches [`{name}`](Self::{name})."); @@ -427,3 +427,22 @@ fn generate_variant_methods((variant, ty): (&Ident, &Ident)) -> TokenStream { } } } + +/// `heck` doesn't treat numbers as new words, and discards leading underscores. +fn snakify(s: &str) -> String { + let leading = s.chars().take_while(|c| *c == '_'); + let mut output: Vec = leading.chain(s.to_snake_case().chars()).collect(); + + let mut num_starts = vec![]; + for (pos, c) in output.iter().enumerate() { + if pos != 0 && c.is_digit(10) && !output[pos - 1].is_digit(10) { + num_starts.push(pos); + } + } + // need to do in reverse, because after inserting, all chars after the point of + // insertion are off + for i in num_starts.into_iter().rev() { + output.insert(i, '_') + } + output.into_iter().collect() +} diff --git a/crates/sol-types/tests/sol.rs b/crates/sol-types/tests/sol.rs index b4764fd4e0..61efc23cab 100644 --- a/crates/sol-types/tests/sol.rs +++ b/crates/sol-types/tests/sol.rs @@ -162,6 +162,23 @@ fn empty_call() { let depositCall {} = depositCall::decode_raw(&[], true).unwrap(); } +#[test] +fn function_names() { + sol! { + contract LeadingUnderscores { + function f(); + function _f(); + function __f(); + } + } + use LeadingUnderscores::*; + + let call = LeadingUnderscoresCalls::f(fCall {}); + assert!(call.is_f()); + assert!(!call.is__f()); + assert!(!call.is___f()); +} + #[test] fn abigen_sol_multicall() { sol!("../syn-solidity/tests/contracts/Multicall.sol"); From b014827e0cfe3bf9bb1cc9e789678ee7fbd85ace Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Sat, 5 Aug 2023 18:26:40 +0200 Subject: [PATCH 16/22] fix bugs, part 2 --- crates/sol-macro/src/input.rs | 18 +- crates/sol-macro/src/json.rs | 1 - crates/syn-solidity/README.md | 20 ++- crates/syn-solidity/src/attribute/function.rs | 8 +- crates/syn-solidity/src/expr/args.rs | 10 +- crates/syn-solidity/src/expr/array.rs | 40 +++-- crates/syn-solidity/src/expr/binary.rs | 23 +-- crates/syn-solidity/src/expr/mod.rs | 65 ++++--- crates/syn-solidity/src/expr/unary.rs | 8 +- crates/syn-solidity/src/file.rs | 10 +- crates/syn-solidity/src/ident/mod.rs | 3 +- crates/syn-solidity/src/item/contract.rs | 2 +- crates/syn-solidity/src/item/enum.rs | 2 +- crates/syn-solidity/src/item/error.rs | 2 +- crates/syn-solidity/src/item/event.rs | 2 +- crates/syn-solidity/src/item/function.rs | 41 ++++- crates/syn-solidity/src/item/import.rs | 10 +- crates/syn-solidity/src/item/mod.rs | 28 ++- crates/syn-solidity/src/item/pragma.rs | 4 +- crates/syn-solidity/src/item/struct.rs | 2 +- crates/syn-solidity/src/item/udt.rs | 2 +- crates/syn-solidity/src/item/using.rs | 13 +- crates/syn-solidity/src/kw.rs | 11 ++ crates/syn-solidity/src/lib.rs | 28 ++- crates/syn-solidity/src/lit/mod.rs | 60 +++++-- crates/syn-solidity/src/lit/number.rs | 163 ++++++++++++++++++ crates/syn-solidity/src/lit/str.rs | 4 +- crates/syn-solidity/src/macros.rs | 31 ++-- crates/syn-solidity/src/stmt/assembly.rs | 1 + crates/syn-solidity/src/stmt/blocks.rs | 7 +- crates/syn-solidity/src/stmt/for.rs | 15 +- crates/syn-solidity/src/stmt/mod.rs | 109 ++++++------ crates/syn-solidity/src/stmt/try.rs | 4 +- crates/syn-solidity/src/stmt/var_decl.rs | 72 +++++--- crates/syn-solidity/src/type/array.rs | 12 +- crates/syn-solidity/src/type/mod.rs | 2 +- crates/syn-solidity/src/variable/list.rs | 2 +- crates/syn-solidity/src/variable/mod.rs | 11 +- crates/syn-solidity/src/yul/block.rs | 3 +- crates/syn-solidity/tests/contracts.rs | 14 +- 40 files changed, 609 insertions(+), 254 deletions(-) create mode 100644 crates/syn-solidity/src/lit/number.rs diff --git a/crates/sol-macro/src/input.rs b/crates/sol-macro/src/input.rs index 705d57d532..ee7077254a 100644 --- a/crates/sol-macro/src/input.rs +++ b/crates/sol-macro/src/input.rs @@ -3,10 +3,11 @@ use proc_macro2::TokenStream; use quote::quote; use std::path::PathBuf; use syn::{ - parse::{Parse, ParseStream}, + parse::{discouraged::Speculative, Parse, ParseStream}, Error, Ident, LitStr, Result, Token, }; +#[derive(Clone, Debug)] pub enum SolInputKind { Sol(ast::File), Type(ast::Type), @@ -17,15 +18,15 @@ pub enum SolInputKind { // doesn't parse Json impl Parse for SolInputKind { fn parse(input: ParseStream<'_>) -> Result { - let start = input.fork(); - match input.parse() { - Ok(file) => Ok(Self::Sol(file)), - Err(e) => match start.parse() { + let fork = input.fork(); + match fork.parse() { + Ok(file) => { + input.advance_to(&fork); + Ok(Self::Sol(file)) + } + Err(e) => match input.parse() { Ok(ast::Type::Custom(_)) | Err(_) => Err(e), - Ok(ast::Type::Function(f)) => { - Err(Error::new(f.span(), "function types are not yet supported")) - } Ok(ast::Type::Mapping(m)) => { Err(Error::new(m.span(), "mapping types are not yet supported")) } @@ -36,6 +37,7 @@ impl Parse for SolInputKind { } } +#[derive(Clone, Debug)] pub struct SolInput { pub path: Option, pub kind: SolInputKind, diff --git a/crates/sol-macro/src/json.rs b/crates/sol-macro/src/json.rs index adcc96515d..2589ae3554 100644 --- a/crates/sol-macro/src/json.rs +++ b/crates/sol-macro/src/json.rs @@ -62,7 +62,6 @@ fn expand_abi(name: &Ident, abi: JsonAbi) -> Result { // `Other` is a UDVT if it's not a basic Solidity type if let Some(it) = internal_type.other_specifier() { if it.try_basic_solidity().is_err() { - let _ = dbg!(it.try_basic_solidity()); udvts.insert(struct_ident(ty).to_owned(), real_ty.to_owned()); } } diff --git a/crates/syn-solidity/README.md b/crates/syn-solidity/README.md index c2e177486c..bbf330c80f 100644 --- a/crates/syn-solidity/README.md +++ b/crates/syn-solidity/README.md @@ -62,7 +62,7 @@ Basic usage: ```rust use quote::quote; -use syn_solidity::{File, Item}; +use syn_solidity::{Expr, File, Item, Lit, Stmt}; // Create a Solidity `TokenStream` let tokens = quote! { @@ -80,16 +80,28 @@ let tokens = quote! { let ast: File = syn_solidity::parse2(tokens)?; let items: &[Item] = &ast.items; -let Some(Item::Contract(contract)) = items.first() else { unreachable!() }; +let Some(Item::Contract(contract)) = items.first() else { + unreachable!() +}; assert_eq!(contract.name, "HelloWorld"); assert_eq!(contract.attrs.len(), 2); // doc comments let body: &[Item] = &contract.body; -let Some(Item::Function(function)) = body.first() else { unreachable!() }; +let Some(Item::Function(function)) = body.first() else { + unreachable!() +}; assert_eq!(function.attrs.len(), 1); // doc comment assert_eq!(function.name.as_ref().unwrap(), "helloWorld"); -assert!(function.arguments.is_empty()); // () +assert!(function.arguments.is_empty()); // () assert_eq!(function.attributes.len(), 2); // external pure assert!(function.returns.is_some()); + +let Some([Stmt::Return(ret)]) = function.body() else { + unreachable!() +}; +let Some(Expr::Lit(Lit::Str(s))) = &ret.expr else { + unreachable!() +}; +assert_eq!(s.value(), "Hello, World!"); # syn::Result::Ok(()) ``` diff --git a/crates/syn-solidity/src/attribute/function.rs b/crates/syn-solidity/src/attribute/function.rs index 4b5e40cd81..6861010605 100644 --- a/crates/syn-solidity/src/attribute/function.rs +++ b/crates/syn-solidity/src/attribute/function.rs @@ -16,9 +16,15 @@ use syn::{ /// A list of unique function attributes. Used in /// [ItemFunction][crate::ItemFunction]. -#[derive(Clone, Debug, Default, PartialEq, Eq)] +#[derive(Clone, Default, PartialEq, Eq)] pub struct FunctionAttributes(pub HashSet); +impl fmt::Debug for FunctionAttributes { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + impl Deref for FunctionAttributes { type Target = HashSet; diff --git a/crates/syn-solidity/src/expr/args.rs b/crates/syn-solidity/src/expr/args.rs index 629600182f..f8f6c85425 100644 --- a/crates/syn-solidity/src/expr/args.rs +++ b/crates/syn-solidity/src/expr/args.rs @@ -161,14 +161,14 @@ impl Parse for ArgListImpl { } } -/// A struct expression: `Foo { bar: 1, baz: 2 }`. +/// Function call options: `foo.bar{ value: 1, gas: 2 }`. #[derive(Clone, Debug)] -pub struct ExprStruct { +pub struct ExprCallOptions { pub expr: Box, pub args: NamedArgList, } -impl ParseNested for ExprStruct { +impl ParseNested for ExprCallOptions { fn parse_nested(expr: Box, input: ParseStream<'_>) -> Result { Ok(Self { expr, @@ -177,9 +177,9 @@ impl ParseNested for ExprStruct { } } -derive_parse!(ExprStruct); +derive_parse!(ExprCallOptions); -impl Spanned for ExprStruct { +impl Spanned for ExprCallOptions { fn span(&self) -> Span { let span = self.expr.span(); span.join(self.args.span()).unwrap_or(span) diff --git a/crates/syn-solidity/src/expr/array.rs b/crates/syn-solidity/src/expr/array.rs index edeb51dc0c..254ff7290f 100644 --- a/crates/syn-solidity/src/expr/array.rs +++ b/crates/syn-solidity/src/expr/array.rs @@ -53,7 +53,8 @@ pub struct ExprIndex { pub expr: Box, pub bracket_token: Bracket, pub start: Option>, - pub end: Option<(Token![:], Box)>, + pub colon_token: Option, + pub end: Option>, } impl fmt::Debug for ExprIndex { @@ -69,19 +70,28 @@ impl fmt::Debug for ExprIndex { impl ParseNested for ExprIndex { fn parse_nested(expr: Box, input: ParseStream<'_>) -> Result { let content; + let bracket_token = bracketed!(content in input); + let start = if content.is_empty() || content.peek(Token![:]) { + None + } else { + Some(content.parse()?) + }; + let colon_token = if content.is_empty() { + None + } else { + Some(content.parse()?) + }; + let end = if content.is_empty() || colon_token.is_none() { + None + } else { + Some(content.parse()?) + }; Ok(Self { expr, - bracket_token: bracketed!(content in input), - start: if content.is_empty() || content.peek(Token![:]) { - None - } else { - Some(content.parse()?) - }, - end: if content.is_empty() { - None - } else { - Some((content.parse()?, content.parse()?)) - }, + bracket_token, + start, + colon_token, + end, }) } } @@ -99,3 +109,9 @@ impl Spanned for ExprIndex { self.bracket_token = Bracket(span); } } + +impl ExprIndex { + pub fn is_range(&self) -> bool { + self.colon_token.is_some() + } +} diff --git a/crates/syn-solidity/src/expr/binary.rs b/crates/syn-solidity/src/expr/binary.rs index 212d855552..5fc0fcd3e9 100644 --- a/crates/syn-solidity/src/expr/binary.rs +++ b/crates/syn-solidity/src/expr/binary.rs @@ -42,8 +42,6 @@ op_enum! { pub enum BinOp { Le(<=), Ge(>=), - Lt(<), - Gt(>), Eq(==), Neq(!=), Or(||), @@ -58,22 +56,25 @@ op_enum! { BitAndAssign(&=), BitOrAssign(|=), BitXorAssign(^=), + SarAssign(>>>=) peek3, ShlAssign(<<=), ShrAssign(>>=), - SarAssign(>>>=), - Add(+), - Sub(-), - Pow(**), - Mul(*), - Div(/), - Rem(%), - - Sar(>>>), + Sar(>>>) peek3, Shr(>>), Shl(<<), BitAnd(&), BitOr(|), BitXor(^), + + Lt(<), + Gt(>), + + Add(+), + Sub(-), + Pow(**) peek2, + Mul(*), + Div(/), + Rem(%), } } diff --git a/crates/syn-solidity/src/expr/mod.rs b/crates/syn-solidity/src/expr/mod.rs index 6c95376158..ff05685d32 100644 --- a/crates/syn-solidity/src/expr/mod.rs +++ b/crates/syn-solidity/src/expr/mod.rs @@ -1,6 +1,6 @@ -use std::fmt; - +use crate::{kw, utils::ParseNested, Lit, SolIdent, Spanned, Type}; use proc_macro2::{Ident, Span}; +use std::fmt; use syn::{ ext::IdentExt, parse::{Parse, ParseStream}, @@ -12,7 +12,9 @@ mod array; pub use array::{ExprArray, ExprIndex}; mod args; -pub use args::{ArgList, ArgListImpl, ExprCall, ExprPayable, ExprStruct, NamedArg, NamedArgList}; +pub use args::{ + ArgList, ArgListImpl, ExprCall, ExprCallOptions, ExprPayable, NamedArg, NamedArgList, +}; mod binary; pub use binary::{BinOp, ExprBinary}; @@ -32,8 +34,6 @@ pub use r#type::{ExprNew, ExprTypeCall}; mod unary; pub use unary::{ExprDelete, ExprPostfix, ExprUnary, PostUnOp, UnOp}; -use crate::{kw, utils::ParseNested, Lit, SolIdent, Spanned, Type}; - /// An expression. /// /// Solidity reference: @@ -49,6 +49,9 @@ pub enum Expr { /// A function call expression: `foo(42)` or `foo({ bar: 42 })`. Call(ExprCall), + /// Function call options: `foo.bar{ value: 1, gas: 2 }`. + CallOptions(ExprCallOptions), + /// A unary `delete` expression: `delete vector`. Delete(ExprDelete), @@ -73,9 +76,6 @@ pub enum Expr { /// A postfix unary expression: `foo++`. Postfix(ExprPostfix), - /// A struct expression: `Foo { bar: 1, baz: 2 }`. - Struct(ExprStruct), - /// A ternary (AKA conditional) expression: `foo ? bar : baz`. Ternary(ExprTernary), @@ -101,6 +101,7 @@ impl fmt::Debug for Expr { Self::Array(expr) => expr.fmt(f), Self::Binary(expr) => expr.fmt(f), Self::Call(expr) => expr.fmt(f), + Self::CallOptions(expr) => expr.fmt(f), Self::Delete(expr) => expr.fmt(f), Self::Ident(ident) => ident.fmt(f), Self::Index(expr) => expr.fmt(f), @@ -109,7 +110,6 @@ impl fmt::Debug for Expr { Self::New(expr) => expr.fmt(f), Self::Payable(expr) => expr.fmt(f), Self::Postfix(expr) => expr.fmt(f), - Self::Struct(expr) => expr.fmt(f), Self::Ternary(expr) => expr.fmt(f), Self::Tuple(expr) => expr.fmt(f), Self::Type(ty) => ty.fmt(f), @@ -124,13 +124,13 @@ impl Parse for Expr { // skip any attributes let _ = input.call(syn::Attribute::parse_outer)?; - debug!(" >> {:?}", input.to_string()); + debug!(" > Expr: {:?}", input.to_string()); let mut expr = Self::parse_simple(input)?; - debug!(" > {expr:?}"); + debug!(" < Expr: {expr:?}"); loop { let (new, cont) = Self::parse_nested(expr, input)?; if cont { - debug!(" > {new:?}"); + debug!(" << Expr: {new:?}"); expr = new; } else { return Ok(new) @@ -145,6 +145,7 @@ impl Spanned for Expr { Self::Array(expr) => expr.span(), Self::Binary(expr) => expr.span(), Self::Call(expr) => expr.span(), + Self::CallOptions(expr) => expr.span(), Self::Delete(expr) => expr.span(), Self::Ident(ident) => ident.span(), Self::Index(expr) => expr.span(), @@ -153,7 +154,6 @@ impl Spanned for Expr { Self::New(expr) => expr.span(), Self::Payable(expr) => expr.span(), Self::Postfix(expr) => expr.span(), - Self::Struct(expr) => expr.span(), Self::Ternary(expr) => expr.span(), Self::Tuple(expr) => expr.span(), Self::Type(ty) => ty.span(), @@ -167,6 +167,7 @@ impl Spanned for Expr { Self::Array(expr) => expr.set_span(span), Self::Binary(expr) => expr.set_span(span), Self::Call(expr) => expr.set_span(span), + Self::CallOptions(expr) => expr.set_span(span), Self::Delete(expr) => expr.set_span(span), Self::Ident(ident) => ident.set_span(span), Self::Index(expr) => expr.set_span(span), @@ -175,7 +176,6 @@ impl Spanned for Expr { Self::New(expr) => expr.set_span(span), Self::Payable(expr) => expr.set_span(span), Self::Postfix(expr) => expr.set_span(span), - Self::Struct(expr) => expr.set_span(span), Self::Ternary(expr) => expr.set_span(span), Self::Tuple(expr) => expr.set_span(span), Self::Type(ty) => ty.set_span(span), @@ -204,7 +204,8 @@ impl Expr { input.parse().map(Self::New) } else if lookahead.peek(kw::delete) { input.parse().map(Self::Delete) - } else if let Ok(ident) = input.call(Ident::parse_any) { + } else if lookahead.peek(Ident::peek_any) { + let ident = input.call(Ident::parse_any)?; match Type::parse_ident(ident.clone()) { Ok(ty) if !ty.is_custom() => ty.parse_payable(input).map(Self::Type), _ => Ok(Self::Ident(ident.into())), @@ -218,26 +219,38 @@ impl Expr { /// /// Returns `(ParseResult, continue_parsing)` fn parse_nested(expr: Self, input: ParseStream<'_>) -> Result<(Self, bool)> { - let mut cont = true; + macro_rules! parse { + (break) => { + Ok((expr, false)) + }; + + ($map:expr) => { + ParseNested::parse_nested(expr.into(), input).map(|e| ($map(e), true)) + }; + } + let lookahead = input.lookahead1(); if lookahead.peek(Bracket) { - ParseNested::parse_nested(expr.into(), input).map(Self::Index) + parse!(Self::Index) } else if lookahead.peek(Brace) { - ParseNested::parse_nested(expr.into(), input).map(Self::Struct) + // Special case: `try` stmt block + if input.peek2(kw::catch) { + parse!(break) + } else { + parse!(Self::CallOptions) + } } else if lookahead.peek(Paren) { - ParseNested::parse_nested(expr.into(), input).map(Self::Call) + parse!(Self::Call) } else if lookahead.peek(Token![.]) { - ParseNested::parse_nested(expr.into(), input).map(Self::Member) + parse!(Self::Member) } else if lookahead.peek(Token![?]) { - ParseNested::parse_nested(expr.into(), input).map(Self::Ternary) + parse!(Self::Ternary) } else if PostUnOp::peek(input, &lookahead) { - ParseNested::parse_nested(expr.into(), input).map(Self::Postfix) + parse!(Self::Postfix) } else if BinOp::peek(input, &lookahead) { - ParseNested::parse_nested(expr.into(), input).map(Self::Binary) + parse!(Self::Binary) } else { - cont = false; - Ok(expr) + parse!(break) } - .map(|expr| (expr, cont)) } } diff --git a/crates/syn-solidity/src/expr/unary.rs b/crates/syn-solidity/src/expr/unary.rs index c91c79befd..685b894bb1 100644 --- a/crates/syn-solidity/src/expr/unary.rs +++ b/crates/syn-solidity/src/expr/unary.rs @@ -103,8 +103,8 @@ impl Spanned for ExprPostfix { op_enum! { /// Unary operators. pub enum UnOp { - Increment(++), - Decrement(--), + Increment(++) peek2, + Decrement(--) peek2, Not(!), BitNot(~), Neg(-), @@ -114,7 +114,7 @@ op_enum! { op_enum! { /// Postfix unary operators. pub enum PostUnOp { - Increment(++), - Decrement(--), + Increment(++) peek2, + Decrement(--) peek2, } } diff --git a/crates/syn-solidity/src/file.rs b/crates/syn-solidity/src/file.rs index eefb37399e..477f63d5b7 100644 --- a/crates/syn-solidity/src/file.rs +++ b/crates/syn-solidity/src/file.rs @@ -18,14 +18,12 @@ impl Parse for File { fn parse(input: ParseStream<'_>) -> Result { let attrs = input.call(Attribute::parse_inner)?; let mut items = Vec::new(); - while !input.is_empty() { + let mut first = true; + while first || !input.is_empty() { + first = false; items.push(input.parse()?); } - if items.is_empty() { - Err(input.parse::().unwrap_err()) - } else { - Ok(Self { attrs, items }) - } + Ok(Self { attrs, items }) } } diff --git a/crates/syn-solidity/src/ident/mod.rs b/crates/syn-solidity/src/ident/mod.rs index cbddd14d16..9797d58031 100644 --- a/crates/syn-solidity/src/ident/mod.rs +++ b/crates/syn-solidity/src/ident/mod.rs @@ -1,3 +1,4 @@ +use crate::Spanned; use proc_macro2::{Ident, Span}; use quote::ToTokens; use std::fmt; @@ -10,7 +11,7 @@ use syn::{ mod path; pub use path::SolPath; -use crate::Spanned; +// TODO: Deny Solidity keywords /// A Solidity identifier. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] diff --git a/crates/syn-solidity/src/item/contract.rs b/crates/syn-solidity/src/item/contract.rs index cf5d0b7cb6..dcd7e8b241 100644 --- a/crates/syn-solidity/src/item/contract.rs +++ b/crates/syn-solidity/src/item/contract.rs @@ -26,7 +26,7 @@ pub struct ItemContract { impl fmt::Debug for ItemContract { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Contract") + f.debug_struct("ItemContract") .field("attrs", &self.attrs) .field("kind", &self.kind) .field("name", &self.name) diff --git a/crates/syn-solidity/src/item/enum.rs b/crates/syn-solidity/src/item/enum.rs index 9bfa149694..79583a4bd2 100644 --- a/crates/syn-solidity/src/item/enum.rs +++ b/crates/syn-solidity/src/item/enum.rs @@ -24,7 +24,7 @@ pub struct ItemEnum { impl fmt::Debug for ItemEnum { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Enum") + f.debug_struct("ItemEnum") .field("attrs", &self.attrs) .field("name", &self.name) .field("variants", DebugPunctuated::new(&self.variants)) diff --git a/crates/syn-solidity/src/item/error.rs b/crates/syn-solidity/src/item/error.rs index 0db696eabd..3cb3576e36 100644 --- a/crates/syn-solidity/src/item/error.rs +++ b/crates/syn-solidity/src/item/error.rs @@ -24,7 +24,7 @@ pub struct ItemError { impl fmt::Debug for ItemError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Error") + f.debug_struct("ItemError") .field("attrs", &self.attrs) .field("name", &self.name) .field("fields", &self.parameters) diff --git a/crates/syn-solidity/src/item/event.rs b/crates/syn-solidity/src/item/event.rs index 584246e5c8..d9fa4090a5 100644 --- a/crates/syn-solidity/src/item/event.rs +++ b/crates/syn-solidity/src/item/event.rs @@ -28,7 +28,7 @@ impl fmt::Debug for ItemEvent { .field("attrs", &self.attrs) .field("name", &self.name) .field("arguments", DebugPunctuated::new(&self.parameters)) - .field("anonymous", &self.anonymous.is_some()) + .field("anonymous", &self.is_anonymous()) .finish() } } diff --git a/crates/syn-solidity/src/item/function.rs b/crates/syn-solidity/src/item/function.rs index 510d1c79f0..c25c1acf53 100644 --- a/crates/syn-solidity/src/item/function.rs +++ b/crates/syn-solidity/src/item/function.rs @@ -1,5 +1,5 @@ use crate::{ - kw, Block, FunctionAttributes, ParameterList, Parameters, SolIdent, Spanned, Type, + kw, Block, FunctionAttributes, ParameterList, Parameters, SolIdent, Spanned, Stmt, Type, VariableDefinition, }; use proc_macro2::Span; @@ -36,13 +36,14 @@ pub struct ItemFunction { impl fmt::Debug for ItemFunction { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Function") + f.debug_struct("ItemFunction") .field("attrs", &self.attrs) .field("kind", &self.kind) .field("name", &self.name) .field("arguments", &self.arguments) .field("attributes", &self.attributes) .field("returns", &self.returns) + .field("body", &self.body) .finish() } } @@ -162,6 +163,29 @@ impl ItemFunction { ) }) } + + /// Returns a reference to the function's body, if any. + pub fn body(&self) -> Option<&[Stmt]> { + match &self.body { + FunctionBody::Block(block) => Some(&block.stmts), + _ => None, + } + } + + /// Returns a mutable reference to the function's body, if any. + pub fn body_mut(&mut self) -> Option<&mut Vec> { + match &mut self.body { + FunctionBody::Block(block) => Some(&mut block.stmts), + _ => None, + } + } + + pub fn into_body(self) -> std::result::Result, Self> { + match self.body { + FunctionBody::Block(block) => Ok(block.stmts), + _ => Err(self), + } + } } kw_enum! { @@ -271,7 +295,8 @@ impl Returns { } } -#[derive(Clone, Debug)] +/// The body of a function. +#[derive(Clone)] pub enum FunctionBody { /// A function body delimited by curly braces. Block(Block), @@ -279,6 +304,16 @@ pub enum FunctionBody { Empty(Token![;]), } +impl fmt::Debug for FunctionBody { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("FunctionBody::")?; + match self { + Self::Block(block) => block.fmt(f), + Self::Empty(_) => f.write_str("Empty"), + } + } +} + impl Parse for FunctionBody { fn parse(input: ParseStream<'_>) -> Result { let lookahead = input.lookahead1(); diff --git a/crates/syn-solidity/src/item/import.rs b/crates/syn-solidity/src/item/import.rs index bfeb8c212b..627c2fbda9 100644 --- a/crates/syn-solidity/src/item/import.rs +++ b/crates/syn-solidity/src/item/import.rs @@ -13,13 +13,21 @@ use syn::{ /// /// Solidity reference: /// -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct ImportDirective { pub import_token: kw::import, pub path: ImportPath, pub semi_token: Token![;], } +impl fmt::Debug for ImportDirective { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ImportDirective") + .field("path", &self.path) + .finish() + } +} + impl Parse for ImportDirective { fn parse(input: ParseStream<'_>) -> Result { Ok(Self { diff --git a/crates/syn-solidity/src/item/mod.rs b/crates/syn-solidity/src/item/mod.rs index f5171db120..05e95fe343 100644 --- a/crates/syn-solidity/src/item/mod.rs +++ b/crates/syn-solidity/src/item/mod.rs @@ -1,12 +1,13 @@ use crate::{kw, variable::VariableDefinition, SolIdent, Spanned}; use proc_macro2::Span; +use std::fmt; use syn::{ parse::{Parse, ParseStream}, Attribute, Result, Token, }; mod contract; -pub use contract::ItemContract; +pub use contract::{ContractKind, Inheritance, ItemContract}; mod r#enum; pub use r#enum::ItemEnum; @@ -18,7 +19,7 @@ mod event; pub use event::{EventParameter, ItemEvent}; mod function; -pub use function::{FunctionKind, ItemFunction, Returns}; +pub use function::{FunctionBody, FunctionKind, ItemFunction, Returns}; mod import; pub use import::{ @@ -40,7 +41,7 @@ pub use using::{UserDefinableOperator, UsingDirective, UsingList, UsingListItem, /// An AST item. A more expanded version of a [Solidity source unit][ref]. /// /// [ref]: https://docs.soliditylang.org/en/latest/grammar.html#a4.SolidityParser.sourceUnit -#[derive(Clone, Debug)] +#[derive(Clone)] pub enum Item { /// A contract, abstract contract, interface, or library definition: /// `contract Foo is Bar, Baz { ... }` @@ -79,6 +80,25 @@ pub enum Item { Variable(VariableDefinition), } +impl fmt::Debug for Item { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Item::")?; + match self { + Self::Contract(item) => item.fmt(f), + Self::Enum(item) => item.fmt(f), + Self::Error(item) => item.fmt(f), + Self::Event(item) => item.fmt(f), + Self::Function(item) => item.fmt(f), + Self::Import(item) => item.fmt(f), + Self::Pragma(item) => item.fmt(f), + Self::Struct(item) => item.fmt(f), + Self::Udt(item) => item.fmt(f), + Self::Using(item) => item.fmt(f), + Self::Variable(item) => item.fmt(f), + } + } +} + impl Parse for Item { fn parse(input: ParseStream<'_>) -> Result { let mut attrs = input.call(Attribute::parse_outer)?; @@ -92,7 +112,7 @@ impl Parse for Item { input.parse().map(Self::Event) } else if lookahead.peek(kw::error) { input.parse().map(Self::Error) - } else if contract::ContractKind::peek(&lookahead) { + } else if ContractKind::peek(&lookahead) { input.parse().map(Self::Contract) } else if lookahead.peek(Token![enum]) { input.parse().map(Self::Enum) diff --git a/crates/syn-solidity/src/item/pragma.rs b/crates/syn-solidity/src/item/pragma.rs index bfbe6fef53..838bf2703b 100644 --- a/crates/syn-solidity/src/item/pragma.rs +++ b/crates/syn-solidity/src/item/pragma.rs @@ -16,7 +16,9 @@ pub struct PragmaDirective { impl fmt::Debug for PragmaDirective { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("Pragma").field(&self.tokens).finish() + f.debug_tuple("PragmaDirective") + .field(&self.tokens) + .finish() } } diff --git a/crates/syn-solidity/src/item/struct.rs b/crates/syn-solidity/src/item/struct.rs index 00d2ce9360..c9ac5ca61c 100644 --- a/crates/syn-solidity/src/item/struct.rs +++ b/crates/syn-solidity/src/item/struct.rs @@ -41,7 +41,7 @@ impl Hash for ItemStruct { impl fmt::Debug for ItemStruct { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Struct") + f.debug_struct("ItemStruct") .field("attrs", &self.attrs) .field("name", &self.name) .field("fields", &self.fields) diff --git a/crates/syn-solidity/src/item/udt.rs b/crates/syn-solidity/src/item/udt.rs index 1c00513d92..b85aaccc19 100644 --- a/crates/syn-solidity/src/item/udt.rs +++ b/crates/syn-solidity/src/item/udt.rs @@ -25,7 +25,7 @@ pub struct ItemUdt { impl fmt::Debug for ItemUdt { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Udt") + f.debug_struct("ItemUdt") .field("attrs", &self.attrs) .field("name", &self.name) .field("ty", &self.ty) diff --git a/crates/syn-solidity/src/item/using.rs b/crates/syn-solidity/src/item/using.rs index fd43a0526a..3214b56fa3 100644 --- a/crates/syn-solidity/src/item/using.rs +++ b/crates/syn-solidity/src/item/using.rs @@ -1,5 +1,6 @@ use crate::{kw, SolPath, Spanned, Type}; use proc_macro2::Span; +use std::fmt; use syn::{ braced, parse::{Parse, ParseStream}, @@ -12,7 +13,7 @@ use syn::{ /// /// Solidity reference: /// -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct UsingDirective { pub using_token: kw::using, pub list: UsingList, @@ -22,6 +23,16 @@ pub struct UsingDirective { pub semi_token: Token![;], } +impl fmt::Debug for UsingDirective { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("UsingDirective") + .field("list", &self.list) + .field("ty", &self.ty) + .field("global", &self.global_token.is_some()) + .finish() + } +} + impl Parse for UsingDirective { fn parse(input: ParseStream<'_>) -> Result { Ok(Self { diff --git a/crates/syn-solidity/src/kw.rs b/crates/syn-solidity/src/kw.rs index e028cc7711..818214fcbe 100644 --- a/crates/syn-solidity/src/kw.rs +++ b/crates/syn-solidity/src/kw.rs @@ -82,6 +82,17 @@ custom_keywords!( unicode, hex, + // Sub-denominations + wei, + gwei, + ether, + seconds, + minutes, + hours, + days, + weeks, + years, + // Other assembly, catch, diff --git a/crates/syn-solidity/src/lib.rs b/crates/syn-solidity/src/lib.rs index b84c57a1a1..0e5413c94b 100644 --- a/crates/syn-solidity/src/lib.rs +++ b/crates/syn-solidity/src/lib.rs @@ -26,7 +26,11 @@ pub use attribute::{ }; mod expr; -pub use expr::*; +pub use expr::{ + ArgList, ArgListImpl, BinOp, Expr, ExprArray, ExprBinary, ExprCall, ExprCallOptions, + ExprDelete, ExprIndex, ExprMember, ExprNew, ExprPayable, ExprPostfix, ExprTernary, ExprTuple, + ExprTypeCall, ExprUnary, NamedArg, NamedArgList, PostUnOp, UnOp, +}; mod file; pub use file::File; @@ -36,14 +40,18 @@ pub use ident::{SolIdent, SolPath}; mod item; pub use item::{ - EventParameter, FunctionKind, ImportAlias, ImportAliases, ImportDirective, ImportGlob, - ImportPath, ImportPlain, Item, ItemContract, ItemEnum, ItemError, ItemEvent, ItemFunction, - ItemStruct, ItemUdt, PragmaDirective, PragmaTokens, Returns, UserDefinableOperator, - UsingDirective, UsingList, UsingListItem, UsingType, + ContractKind, EventParameter, FunctionBody, FunctionKind, ImportAlias, ImportAliases, + ImportDirective, ImportGlob, ImportPath, ImportPlain, Inheritance, Item, ItemContract, + ItemEnum, ItemError, ItemEvent, ItemFunction, ItemStruct, ItemUdt, PragmaDirective, + PragmaTokens, Returns, UserDefinableOperator, UsingDirective, UsingList, UsingListItem, + UsingType, }; mod lit; -pub use lit::{HexStr, Lit, LitHex, LitStr, LitUnicode, UnicodeStr}; +pub use lit::{ + HexStr, Lit, LitHexStr, LitNumber, LitNumberKind, LitStr, LitUnicodeStr, SubDenomination, + UnicodeStr, +}; pub mod kw; @@ -51,7 +59,11 @@ mod spanned; pub use spanned::Spanned; mod stmt; -pub use stmt::*; +pub use stmt::{ + AssemblyFlags, Block, CatchClause, ForInitStmt, Stmt, StmtAssembly, StmtBreak, StmtContinue, + StmtDoWhile, StmtEmit, StmtExpr, StmtFor, StmtIf, StmtReturn, StmtRevert, StmtTry, StmtVarDecl, + StmtWhile, UncheckedBlock, VarDeclDecl, VarDeclTuple, +}; mod r#type; pub use r#type::{Type, TypeArray, TypeFunction, TypeMapping, TypeTuple}; @@ -84,4 +96,4 @@ pub fn parse2(input: proc_macro2::TokenStream) -> Result { syn::parse2(input) } -const DEBUG: bool = true; +const DEBUG: bool = option_env!("SYN_SOLIDITY_DEBUG").is_some(); diff --git a/crates/syn-solidity/src/lit/mod.rs b/crates/syn-solidity/src/lit/mod.rs index fa4bc7236e..39c0207422 100644 --- a/crates/syn-solidity/src/lit/mod.rs +++ b/crates/syn-solidity/src/lit/mod.rs @@ -1,22 +1,48 @@ +use std::fmt; + use crate::{kw, Spanned}; use proc_macro2::Span; use syn::{ parse::{Lookahead1, Parse, ParseStream}, - LitBool, LitFloat, LitInt, Result, + LitBool, Result, }; +mod number; +pub use number::{LitNumber, LitNumberKind, SubDenomination}; + mod str; -pub use str::{HexStr, LitHex, LitStr, LitUnicode, UnicodeStr}; +pub use str::{HexStr, LitHexStr, LitStr, LitUnicodeStr, UnicodeStr}; -/// A literal. -#[derive(Clone, Debug)] +/// A Solidity literal such as a string or integer or boolean. +#[derive(Clone)] pub enum Lit { - Str(LitStr), - Int(LitInt), - Float(LitFloat), + /// A boolean literal: `true` or `false`. Bool(LitBool), - Hex(LitHex), - Unicode(LitUnicode), + + /// A hex string literal: `hex"1234"`. + Hex(LitHexStr), + + /// An integer or fixed-point number literal: `1` or `1.0`. + Number(LitNumber), + + /// A string literal. + Str(LitStr), + + /// A unicode string literal. + Unicode(LitUnicodeStr), +} + +impl fmt::Debug for Lit { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Lit::")?; + match self { + Self::Bool(lit) => lit.fmt(f), + Self::Hex(lit) => lit.fmt(f), + Self::Number(lit) => lit.fmt(f), + Self::Str(lit) => lit.fmt(f), + Self::Unicode(lit) => lit.fmt(f), + } + } } impl Parse for Lit { @@ -24,10 +50,8 @@ impl Parse for Lit { let lookahead = input.lookahead1(); if lookahead.peek(syn::LitStr) { input.parse().map(Self::Str) - } else if lookahead.peek(LitInt) { - input.parse().map(Self::Int) - } else if lookahead.peek(LitFloat) { - input.parse().map(Self::Float) + } else if LitNumber::peek(&lookahead) { + input.parse().map(Self::Number) } else if lookahead.peek(LitBool) { input.parse().map(Self::Bool) } else if lookahead.peek(kw::unicode) { @@ -43,22 +67,20 @@ impl Parse for Lit { impl Spanned for Lit { fn span(&self) -> Span { match self { - Self::Str(lit) => lit.span(), - Self::Int(lit) => lit.span(), - Self::Float(lit) => lit.span(), Self::Bool(lit) => lit.span(), Self::Hex(lit) => lit.span(), + Self::Number(lit) => lit.span(), + Self::Str(lit) => lit.span(), Self::Unicode(lit) => lit.span(), } } fn set_span(&mut self, span: Span) { match self { - Self::Str(lit) => lit.set_span(span), - Self::Int(lit) => lit.set_span(span), - Self::Float(lit) => lit.set_span(span), Self::Bool(lit) => lit.set_span(span), Self::Hex(lit) => lit.set_span(span), + Self::Number(lit) => lit.set_span(span), + Self::Str(lit) => lit.set_span(span), Self::Unicode(lit) => lit.set_span(span), } } diff --git a/crates/syn-solidity/src/lit/number.rs b/crates/syn-solidity/src/lit/number.rs new file mode 100644 index 0000000000..963f5bf2e6 --- /dev/null +++ b/crates/syn-solidity/src/lit/number.rs @@ -0,0 +1,163 @@ +use crate::{kw, Spanned}; +use proc_macro2::{Literal, Span}; +use std::{fmt, str::FromStr}; +use syn::{ + parse::{Lookahead1, Parse, ParseStream}, + LitFloat, LitInt, Result, +}; + +// TODO: Fixed point numbers + +/// An integer or fixed-point number literal: `1` or `1.0`. +#[derive(Clone, Debug)] +pub struct LitNumber { + pub kind: LitNumberKind, + pub denom: Option, +} + +impl Parse for LitNumber { + fn parse(input: ParseStream<'_>) -> Result { + Ok(Self { + kind: input.parse()?, + denom: input.call(SubDenomination::parse_opt)?, + }) + } +} + +impl Spanned for LitNumber { + fn span(&self) -> Span { + let span = self.kind.span(); + self.denom + .as_ref() + .and_then(|d| d.span().join(span)) + .unwrap_or(span) + } + + fn set_span(&mut self, span: Span) { + self.kind.set_span(span); + if let Some(denom) = &mut self.denom { + denom.set_span(span); + } + } +} + +impl LitNumber { + pub fn new(kind: LitNumberKind) -> Self { + Self { kind, denom: None } + } + + pub fn peek(lookahead: &Lookahead1<'_>) -> bool { + LitNumberKind::peek(lookahead) + } +} + +#[derive(Clone)] +pub enum LitNumberKind { + Int(LitInt), + Float(LitFloat), +} + +impl fmt::Debug for LitNumberKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Int(lit) => lit.fmt(f), + Self::Float(lit) => lit.fmt(f), + } + } +} + +impl Parse for LitNumberKind { + fn parse(input: ParseStream<'_>) -> Result { + let lookahead = input.lookahead1(); + if lookahead.peek(LitInt) { + input.parse().map(Self::Int) + } else if lookahead.peek(LitFloat) { + input.parse().map(Self::Float) + } else { + Err(lookahead.error()) + } + } +} + +impl Spanned for LitNumberKind { + fn span(&self) -> Span { + match self { + Self::Int(lit) => lit.span(), + Self::Float(lit) => lit.span(), + } + } + + fn set_span(&mut self, span: Span) { + match self { + Self::Int(lit) => lit.set_span(span), + Self::Float(lit) => lit.set_span(span), + } + } +} + +impl LitNumberKind { + pub fn new_int(repr: &str, span: Span) -> Self { + Self::Int(LitInt::new(repr, span)) + } + + pub fn new_fixed(repr: &str, span: Span) -> Self { + Self::Float(LitFloat::new(repr, span)) + } + + pub fn peek(lookahead: &Lookahead1<'_>) -> bool { + lookahead.peek(LitInt) || lookahead.peek(LitFloat) + } + + /// Returns the base-10 digits of the literal. + pub fn base10_digits(&self) -> &str { + match self { + Self::Int(lit) => lit.base10_digits(), + Self::Float(lit) => lit.base10_digits(), + } + } + + /// Parses the literal into a selected number type. + /// + /// This is equivalent to `lit.base10_digits().parse()` except that the + /// resulting errors will be correctly spanned to point to the literal token + /// in the macro input. + pub fn base10_parse(&self) -> Result + where + N: FromStr, + N::Err: fmt::Display, + { + match self { + Self::Int(lit) => lit.base10_parse(), + Self::Float(lit) => lit.base10_parse(), + } + } + + pub fn suffix(&self) -> &str { + match self { + Self::Int(lit) => lit.suffix(), + Self::Float(lit) => lit.suffix(), + } + } + + pub fn token(&self) -> Literal { + match self { + Self::Int(lit) => lit.token(), + Self::Float(lit) => lit.token(), + } + } +} + +kw_enum! { + pub enum SubDenomination { + Wei(kw::wei), + Gwei(kw::gwei), + Ether(kw::ether), + + Seconds(kw::seconds), + Minutes(kw::minutes), + Hours(kw::hours), + Days(kw::days), + Weeks(kw::weeks), + Years(kw::years), + } +} diff --git a/crates/syn-solidity/src/lit/str.rs b/crates/syn-solidity/src/lit/str.rs index d129f57bfb..c982388a18 100644 --- a/crates/syn-solidity/src/lit/str.rs +++ b/crates/syn-solidity/src/lit/str.rs @@ -137,7 +137,7 @@ str_lit! { str_lit! { /// A unicode string literal. - pub struct LitUnicode(UnicodeStr): unicode + pub struct LitUnicodeStr(UnicodeStr): unicode } wrap_str! { @@ -149,7 +149,7 @@ wrap_str! { str_lit! { /// A hex string literal. - pub struct LitHex(HexStr): hex + pub struct LitHexStr(HexStr): hex } wrap_str! { diff --git a/crates/syn-solidity/src/macros.rs b/crates/syn-solidity/src/macros.rs index e380c3b28d..69f90ceb0a 100644 --- a/crates/syn-solidity/src/macros.rs +++ b/crates/syn-solidity/src/macros.rs @@ -217,6 +217,8 @@ macro_rules! kw_enum { $(#[$attr])* #[derive(Clone, Copy)] $vis enum $name {$( + #[doc = concat!("`", stringify!($kw), "`")] + /// $(#[$variant_attr])* $variant($crate::kw::$kw), )+} @@ -337,33 +339,26 @@ macro_rules! op_enum { (@peek $input:ident, $lookahead:ident, $a:tt) => { $lookahead.peek(::syn::Token![$a]) }; - (@peek $input:ident, $lookahead:ident, $a:tt $b:tt) => { + // can't use `peek2` for `BinOp::Sar` (`>>>`) since the first token is 2 characters, + // so take it in as input + (@peek $input:ident, $lookahead:ident, $a:tt $b:tt $peek:ident) => { $lookahead.peek(::syn::Token![$a]) - && $input.peek2(::syn::Token![$b]) - }; - (@peek $input:ident, $lookahead:ident, $a:tt $b:tt $c:tt) => { - $lookahead.peek(::syn::Token![$a]) - && $input.peek2(::syn::Token![$b]) - && $input.peek3(::syn::Token![$c]) - }; - (@peek $input:ident, $lookahead:ident, $($t:tt)*) => { - compile_error!( - "too many tokens in operator: ", - concat!($(stringify!($t)),*), - ) + && $input.$peek(::syn::Token![$b]) }; ( $(#[$attr:meta])* $vis:vis enum $name:ident {$( $(#[$variant_attr:meta])* - $variant:ident($($op:tt)+) + $variant:ident($($op:tt)+) $($peek:ident)? ),+ $(,)?} ) => { $(#[$attr])* #[derive(Clone, Copy)] $vis enum $name {$( #[doc = concat!("`", $(stringify!($op),)+ "`")] + /// + $(#[$variant_attr])* $variant($(::syn::Token![$op]),+), )+} @@ -401,7 +396,7 @@ macro_rules! op_enum { fn parse(input: ::syn::parse::ParseStream<'_>) -> ::syn::Result { let lookahead = input.lookahead1(); $( - if op_enum!(@peek input, lookahead, $($op)+) { + if op_enum!(@peek input, lookahead, $($op)+ $($peek)?) { Ok(Self::$variant( $(input.parse::<::syn::Token![$op]>()?),+ )) @@ -440,9 +435,9 @@ macro_rules! op_enum { #[allow(unused_parens, unused_variables)] pub fn peek(input: syn::parse::ParseStream<'_>, lookahead: &::syn::parse::Lookahead1<'_>) -> bool { - $(( - op_enum!(@peek input, lookahead, $($op)+) - ))||+ + $( + (op_enum!(@peek input, lookahead, $($op)+ $($peek)?)) + )||+ } pub const fn as_str(self) -> &'static str { diff --git a/crates/syn-solidity/src/stmt/assembly.rs b/crates/syn-solidity/src/stmt/assembly.rs index 7596241103..9f576c825f 100644 --- a/crates/syn-solidity/src/stmt/assembly.rs +++ b/crates/syn-solidity/src/stmt/assembly.rs @@ -50,6 +50,7 @@ impl Spanned for StmtAssembly { } } +/// A list of flags of an assembly statement. #[derive(Clone)] pub struct AssemblyFlags { pub paren_token: Paren, diff --git a/crates/syn-solidity/src/stmt/blocks.rs b/crates/syn-solidity/src/stmt/blocks.rs index 59f8d4618d..382d501ca4 100644 --- a/crates/syn-solidity/src/stmt/blocks.rs +++ b/crates/syn-solidity/src/stmt/blocks.rs @@ -27,12 +27,11 @@ impl Parse for Block { brace_token: syn::braced!(content in input), stmts: { let mut vec = Vec::new(); + debug!("> Block: {:?}", content.to_string()); while !content.is_empty() { - debug!(">>> {:?}", content.to_string()); - let r = content.parse(); - debug!("<<< {r:?}\n"); - vec.push(r?); + vec.push(content.parse()?); } + debug!("< Block: {} stmts\n", vec.len()); vec }, }) diff --git a/crates/syn-solidity/src/stmt/for.rs b/crates/syn-solidity/src/stmt/for.rs index b26d3ca290..835317a4a8 100644 --- a/crates/syn-solidity/src/stmt/for.rs +++ b/crates/syn-solidity/src/stmt/for.rs @@ -69,11 +69,14 @@ impl Spanned for StmtFor { } } +/// A for statement initializer. +/// +/// This can either be empty, a variable declaration, or an expression. #[derive(Clone, Debug)] pub enum ForInitStmt { - VarDecl(StmtVarDecl), - Expression(StmtExpr), Empty(Token![;]), + VarDecl(StmtVarDecl), + Expr(StmtExpr), } impl Parse for ForInitStmt { @@ -81,10 +84,12 @@ impl Parse for ForInitStmt { let lookahead = input.lookahead1(); if lookahead.peek(Token![;]) { input.parse().map(Self::Empty) - } else if StmtVarDecl::peek(input, &lookahead) { - input.parse().map(Self::VarDecl) } else { - input.parse().map(Self::Expression) + match StmtVarDecl::parse_or_expr(input)? { + Stmt::VarDecl(decl) => Ok(Self::VarDecl(decl)), + Stmt::Expr(expr) => Ok(Self::Expr(expr)), + s => unreachable!("StmtVarDecl::parse_or_expr: invalid output {s:?}"), + } } } } diff --git a/crates/syn-solidity/src/stmt/mod.rs b/crates/syn-solidity/src/stmt/mod.rs index e2fc278816..5e2b40212a 100644 --- a/crates/syn-solidity/src/stmt/mod.rs +++ b/crates/syn-solidity/src/stmt/mod.rs @@ -1,7 +1,14 @@ -mod assembly; +use crate::{kw, Spanned}; +use proc_macro2::Span; use std::fmt; +use syn::{ + parse::{Parse, ParseStream}, + token::{Brace, Bracket, Paren}, + Result, Token, +}; -pub use assembly::StmtAssembly; +mod assembly; +pub use assembly::{AssemblyFlags, StmtAssembly}; mod blocks; pub use blocks::{Block, UncheckedBlock}; @@ -22,7 +29,7 @@ mod expr; pub use expr::StmtExpr; mod r#for; -pub use r#for::StmtFor; +pub use r#for::{ForInitStmt, StmtFor}; mod r#if; pub use r#if::StmtIf; @@ -34,22 +41,14 @@ mod revert; pub use revert::StmtRevert; mod r#try; -pub use r#try::StmtTry; +pub use r#try::{CatchClause, StmtTry}; mod var_decl; -pub use var_decl::StmtVarDecl; +pub use var_decl::{StmtVarDecl, VarDeclDecl, VarDeclTuple}; mod r#while; pub use r#while::StmtWhile; -use crate::{kw, Spanned}; -use proc_macro2::Span; -use syn::{ - parse::{Parse, ParseStream}, - token::{Brace, Paren}, - Result, Token, -}; - /// A statement, usually ending in a semicolon. /// /// Solidity reference: @@ -128,44 +127,13 @@ impl fmt::Debug for Stmt { impl Parse for Stmt { fn parse(input: ParseStream<'_>) -> Result { - let lookahead = input.lookahead1(); - if lookahead.peek(Brace) { - input.parse().map(Self::Block) - } else if lookahead.peek(Paren) { - if input.peek2(Token![=]) { - input.parse().map(Self::VarDecl) - } else { - input.parse().map(Self::Expr) - } - } else if lookahead.peek(kw::unchecked) { - input.parse().map(Self::UncheckedBlock) - } else if lookahead.peek(Token![if]) { - input.parse().map(Self::If) - } else if lookahead.peek(Token![for]) { - input.parse().map(Self::For) - } else if lookahead.peek(Token![while]) { - input.parse().map(Self::While) - } else if lookahead.peek(Token![do]) { - input.parse().map(Self::DoWhile) - } else if lookahead.peek(Token![continue]) { - input.parse().map(Self::Continue) - } else if lookahead.peek(Token![break]) { - input.parse().map(Self::Break) - } else if lookahead.peek(Token![try]) { - input.parse().map(Self::Try) - } else if lookahead.peek(Token![return]) { - input.parse().map(Self::Return) - } else if lookahead.peek(kw::emit) { - input.parse().map(Self::Emit) - } else if lookahead.peek(kw::revert) { - input.parse().map(Self::Revert) - } else if lookahead.peek(kw::assembly) { - input.parse().map(Self::Assembly) - } else if StmtVarDecl::peek(input, &lookahead) { - input.parse().map(Self::VarDecl) - } else { - input.parse().map(Self::Expr) - } + // skip any attributes + let _ = input.call(syn::Attribute::parse_outer)?; + + debug!(" > Stmt: {:?}", input.to_string()); + let stmt = Self::parse_simple(input)?; + debug!(" < Stmt: {stmt:?}\n"); + Ok(stmt) } } @@ -210,3 +178,42 @@ impl Spanned for Stmt { } } } + +impl Stmt { + fn parse_simple(input: ParseStream<'_>) -> Result { + let lookahead = input.lookahead1(); + if lookahead.peek(Brace) { + input.parse().map(Self::Block) + } else if lookahead.peek(Paren) { + StmtVarDecl::parse_or_expr(input) + } else if lookahead.peek(Bracket) { + input.parse().map(Self::Expr) + } else if lookahead.peek(kw::unchecked) { + input.parse().map(Self::UncheckedBlock) + } else if lookahead.peek(Token![if]) { + input.parse().map(Self::If) + } else if lookahead.peek(Token![for]) { + input.parse().map(Self::For) + } else if lookahead.peek(Token![while]) { + input.parse().map(Self::While) + } else if lookahead.peek(Token![do]) { + input.parse().map(Self::DoWhile) + } else if lookahead.peek(Token![continue]) { + input.parse().map(Self::Continue) + } else if lookahead.peek(Token![break]) { + input.parse().map(Self::Break) + } else if lookahead.peek(Token![try]) { + input.parse().map(Self::Try) + } else if lookahead.peek(Token![return]) { + input.parse().map(Self::Return) + } else if lookahead.peek(kw::emit) { + input.parse().map(Self::Emit) + } else if lookahead.peek(kw::revert) { + input.parse().map(Self::Revert) + } else if lookahead.peek(kw::assembly) { + input.parse().map(Self::Assembly) + } else { + StmtVarDecl::parse_or_expr(input) + } + } +} diff --git a/crates/syn-solidity/src/stmt/try.rs b/crates/syn-solidity/src/stmt/try.rs index a34ed89346..46a475ef43 100644 --- a/crates/syn-solidity/src/stmt/try.rs +++ b/crates/syn-solidity/src/stmt/try.rs @@ -43,7 +43,9 @@ impl Parse for StmtTry { block: input.parse()?, catch: { let mut catch = Vec::new(); - while input.peek(kw::catch) { + let mut first = true; + while first || input.peek(kw::catch) { + first = false; catch.push(input.parse()?); } catch diff --git a/crates/syn-solidity/src/stmt/var_decl.rs b/crates/syn-solidity/src/stmt/var_decl.rs index 11ac58fe6c..9598cbe26a 100644 --- a/crates/syn-solidity/src/stmt/var_decl.rs +++ b/crates/syn-solidity/src/stmt/var_decl.rs @@ -1,10 +1,9 @@ -use crate::{kw, utils::DebugPunctuated, Expr, Spanned, VariableDeclaration}; -use proc_macro2::{Ident, Span}; +use crate::{utils::DebugPunctuated, Expr, Spanned, Stmt, VariableDeclaration}; +use proc_macro2::Span; use std::fmt; use syn::{ - ext::IdentExt, parenthesized, - parse::{Lookahead1, Parse, ParseStream}, + parse::{discouraged::Speculative, Parse, ParseStream}, punctuated::Punctuated, token::Paren, Result, Token, @@ -32,16 +31,21 @@ impl fmt::Debug for StmtVarDecl { impl Parse for StmtVarDecl { fn parse(input: ParseStream<'_>) -> Result { + let declaration: VarDeclDecl = input.parse()?; + + // tuple requires assignment + let assignment = if matches!(declaration, VarDeclDecl::Tuple(_)) || input.peek(Token![=]) { + Some((input.parse()?, input.parse()?)) + } else { + None + }; + + let semi_token = input.parse()?; + Ok(Self { - declaration: input.parse()?, - assignment: { - if input.peek(Token![=]) { - Some((input.parse()?, input.parse()?)) - } else { - None - } - }, - semi_token: input.parse()?, + declaration, + assignment, + semi_token, }) } } @@ -66,30 +70,44 @@ impl Spanned for StmtVarDecl { } impl StmtVarDecl { - pub fn peek(input: ParseStream<'_>, lookahead: &Lookahead1<'_>) -> bool { - lookahead.peek(kw::tuple) - || lookahead.peek(kw::function) - || lookahead.peek(kw::mapping) - || (lookahead.peek(Paren) && input.peek2(Token![=])) - || (input.peek(Ident::peek_any) - && input.peek2(Ident::peek_any) - && (input.peek3(Token![=]) || input.peek3(Token![;]))) + pub fn parse_or_expr(input: ParseStream<'_>) -> Result { + // TODO: Figure if we can do this without forking + let speculative_parse = || { + let fork = input.fork(); + match fork.parse() { + Ok(var) => { + input.advance_to(&fork); + Ok(Stmt::VarDecl(var)) + } + Err(_) => input.parse().map(Stmt::Expr), + } + }; + + if input.peek(Paren) { + if input.peek2(Token![=]) { + speculative_parse() + } else { + input.parse().map(Stmt::Expr) + } + } else { + speculative_parse() + } } } -/// The declaration of the variable(s) in a [`StmtVarDecl`]. +/// The declaration of the variable(s) in a variable declaration statement. #[derive(Clone, Debug)] pub enum VarDeclDecl { VarDecl(VariableDeclaration), - Expression(VarDeclTuple), + Tuple(VarDeclTuple), } impl Parse for VarDeclDecl { fn parse(input: ParseStream<'_>) -> Result { if input.peek(Paren) { - input.parse().map(Self::Expression) + input.parse().map(Self::Tuple) } else { - input.parse().map(Self::VarDecl) + VariableDeclaration::parse_with_name(input).map(Self::VarDecl) } } } @@ -98,14 +116,14 @@ impl Spanned for VarDeclDecl { fn span(&self) -> Span { match self { Self::VarDecl(decl) => decl.span(), - Self::Expression(decl) => decl.span(), + Self::Tuple(decl) => decl.span(), } } fn set_span(&mut self, span: Span) { match self { Self::VarDecl(decl) => decl.set_span(span), - Self::Expression(decl) => decl.set_span(span), + Self::Tuple(decl) => decl.set_span(span), } } } diff --git a/crates/syn-solidity/src/type/array.rs b/crates/syn-solidity/src/type/array.rs index 96989fc709..46de9457e3 100644 --- a/crates/syn-solidity/src/type/array.rs +++ b/crates/syn-solidity/src/type/array.rs @@ -58,7 +58,7 @@ impl fmt::Display for TypeArray { impl Parse for TypeArray { fn parse(input: ParseStream<'_>) -> Result { let ty = input.parse()?; - Self::wrap(input, ty) + Self::parse_nested(Box::new(ty), input) } } @@ -92,13 +92,17 @@ impl TypeArray { } /// Parses an array type from the given input stream, wrapping `ty` with it. - pub fn wrap(input: ParseStream<'_>, ty: Type) -> Result { + pub fn parse_nested(ty: Box, input: ParseStream<'_>) -> Result { let content; Ok(Self { - ty: Box::new(ty), + ty, bracket_token: bracketed!(content in input), size: { - let size = content.parse::>()?; + let size = if content.is_empty() { + None + } else { + Some(content.parse::()?) + }; // Validate the size if let Some(sz) = &size { sz.base10_parse::()?; diff --git a/crates/syn-solidity/src/type/mod.rs b/crates/syn-solidity/src/type/mod.rs index c38c038a6b..1b0b38d3de 100644 --- a/crates/syn-solidity/src/type/mod.rs +++ b/crates/syn-solidity/src/type/mod.rs @@ -157,7 +157,7 @@ impl Parse for Type { // while the next token is a bracket, parse an array size and nest the // candidate into an array while input.peek(Bracket) { - candidate = Self::Array(TypeArray::wrap(input, candidate)?); + candidate = Self::Array(TypeArray::parse_nested(Box::new(candidate), input)?); } Ok(candidate) diff --git a/crates/syn-solidity/src/variable/list.rs b/crates/syn-solidity/src/variable/list.rs index 0b11786c1f..6184344e7e 100644 --- a/crates/syn-solidity/src/variable/list.rs +++ b/crates/syn-solidity/src/variable/list.rs @@ -59,7 +59,7 @@ impl Parse for ParameterList { /// Struct: enforce semicolon after each field and field name. impl Parse for FieldList { fn parse(input: ParseStream<'_>) -> Result { - let this = input.parse_terminated(VariableDeclaration::parse_for_struct, Token![;])?; + let this = input.parse_terminated(VariableDeclaration::parse_with_name, Token![;])?; if this.is_empty() { Err(input.error("defining empty structs is disallowed")) } else if !this.trailing_punct() { diff --git a/crates/syn-solidity/src/variable/mod.rs b/crates/syn-solidity/src/variable/mod.rs index 2f99c566ec..a42612cec1 100644 --- a/crates/syn-solidity/src/variable/mod.rs +++ b/crates/syn-solidity/src/variable/mod.rs @@ -10,9 +10,7 @@ use syn::{ mod list; pub use list::{FieldList, ParameterList, Parameters}; -/// A variable declaration. -/// -/// ` [storage] ` +/// A variable declaration: `string memory hello`. #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct VariableDeclaration { /// The attributes of the variable. @@ -88,17 +86,16 @@ impl VariableDeclaration { Ok(()) } - pub fn parse_for_struct(input: ParseStream<'_>) -> Result { + pub fn parse_with_name(input: ParseStream<'_>) -> Result { Self::_parse(input, true) } - fn _parse(input: ParseStream<'_>, for_struct: bool) -> Result { + fn _parse(input: ParseStream<'_>, require_name: bool) -> Result { Ok(Self { attrs: input.call(Attribute::parse_outer)?, ty: input.parse()?, storage: input.call(Storage::parse_opt)?, - // structs must have field names - name: if for_struct || input.peek(Ident::peek_any) { + name: if require_name || input.peek(Ident::peek_any) { Some(input.parse()?) } else { None diff --git a/crates/syn-solidity/src/yul/block.rs b/crates/syn-solidity/src/yul/block.rs index 078cf6a8a8..75b933c319 100644 --- a/crates/syn-solidity/src/yul/block.rs +++ b/crates/syn-solidity/src/yul/block.rs @@ -18,7 +18,8 @@ pub struct YulBlock { impl fmt::Debug for YulBlock { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("YulBlock") - .field("stmts", &self.stmts) + // .field("stmts", &self.stmts) + .field("stmts", &self.stmts.to_string()) .finish() } } diff --git a/crates/syn-solidity/tests/contracts.rs b/crates/syn-solidity/tests/contracts.rs index fdbc6e383e..3a75d1ef59 100644 --- a/crates/syn-solidity/tests/contracts.rs +++ b/crates/syn-solidity/tests/contracts.rs @@ -10,10 +10,11 @@ fn contracts() { .parent() .unwrap(); - let files: Vec<_> = fs::read_dir(PATH) + let mut files: Vec<_> = fs::read_dir(PATH) .unwrap() .collect::>() .unwrap(); + files.sort_by_key(|e| e.path()); let patches = files .iter() .filter(|p| p.path().extension() == Some("patch".as_ref())); @@ -43,15 +44,8 @@ fn contracts() { eprintln!("failed to parse {name}: {e} ({e:?})"); failed = true; } - Err(payload) => { - let msg = match payload.downcast_ref::<&'static str>() { - Some(s) => *s, - None => match payload.downcast_ref::() { - Some(s) => &s[..], - None => "Box", - }, - }; - eprintln!("panicked while parsing {name}: {msg}"); + Err(_) => { + eprintln!("panicked while parsing {name}"); failed = true; } } From c72a924de6e16412bc6ed0bd34a35d311d24c43a Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Sat, 5 Aug 2023 18:28:33 +0200 Subject: [PATCH 17/22] chore: clippy --- crates/sol-macro/src/expand/contract.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/sol-macro/src/expand/contract.rs b/crates/sol-macro/src/expand/contract.rs index 8cf627aa54..540d234e16 100644 --- a/crates/sol-macro/src/expand/contract.rs +++ b/crates/sol-macro/src/expand/contract.rs @@ -435,7 +435,7 @@ fn snakify(s: &str) -> String { let mut num_starts = vec![]; for (pos, c) in output.iter().enumerate() { - if pos != 0 && c.is_digit(10) && !output[pos - 1].is_digit(10) { + if pos != 0 && c.is_ascii_digit() && !output[pos - 1].is_ascii_digit() { num_starts.push(pos); } } From 83e135f8b74277e0c2fc58f43909946a6156903f Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Sat, 5 Aug 2023 18:32:40 +0200 Subject: [PATCH 18/22] fix mod name --- a.sol | 6 ------ crates/syn-solidity/src/lit/mod.rs | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) delete mode 100644 a.sol diff --git a/a.sol b/a.sol deleted file mode 100644 index 45d5199d84..0000000000 --- a/a.sol +++ /dev/null @@ -1,6 +0,0 @@ -function f() pure { - uint256 a; - (++a, ++a); - uint256; - string memory s = unicode"" unicode""; -} diff --git a/crates/syn-solidity/src/lit/mod.rs b/crates/syn-solidity/src/lit/mod.rs index 39c0207422..bc77deb848 100644 --- a/crates/syn-solidity/src/lit/mod.rs +++ b/crates/syn-solidity/src/lit/mod.rs @@ -11,7 +11,7 @@ mod number; pub use number::{LitNumber, LitNumberKind, SubDenomination}; mod str; -pub use str::{HexStr, LitHexStr, LitStr, LitUnicodeStr, UnicodeStr}; +pub use self::str::{HexStr, LitHexStr, LitStr, LitUnicodeStr, UnicodeStr}; /// A Solidity literal such as a string or integer or boolean. #[derive(Clone)] From 1323d45e1779365dec9a2f64a4eea19332900f5d Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Sat, 5 Aug 2023 18:37:02 +0200 Subject: [PATCH 19/22] chore: clippy --- crates/syn-solidity/src/type/mod.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/crates/syn-solidity/src/type/mod.rs b/crates/syn-solidity/src/type/mod.rs index 1b0b38d3de..f40018cda8 100644 --- a/crates/syn-solidity/src/type/mod.rs +++ b/crates/syn-solidity/src/type/mod.rs @@ -271,9 +271,8 @@ impl Type { /// Parses the `payable` keyword from the input stream if this type is an /// address. pub fn parse_payable(mut self, input: ParseStream<'_>) -> Result { - match &mut self { - Self::Address(_, opt @ None) => *opt = input.parse()?, - _ => {} + if let Self::Address(_, opt @ None) = &mut self { + *opt = input.parse()? } Ok(self) } From fd0ef219c5f97034b0e18c528b4248da32ca3f43 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Sat, 5 Aug 2023 20:03:47 +0200 Subject: [PATCH 20/22] fixes --- crates/sol-macro/src/expand/ty.rs | 16 ++-- crates/syn-solidity/src/attribute/function.rs | 15 ++-- crates/syn-solidity/src/attribute/variable.rs | 19 ++--- crates/syn-solidity/src/expr/mod.rs | 21 ++++- crates/syn-solidity/src/ident/mod.rs | 18 ++++- crates/syn-solidity/src/ident/path.rs | 6 -- crates/syn-solidity/src/lib.rs | 2 +- crates/syn-solidity/src/lit/mod.rs | 5 +- crates/syn-solidity/src/lit/number.rs | 79 ++++++++----------- crates/syn-solidity/src/stmt/for.rs | 6 +- crates/syn-solidity/src/stmt/try.rs | 2 +- crates/syn-solidity/src/stmt/var_decl.rs | 4 +- crates/syn-solidity/src/type/array.rs | 49 ++++++++---- crates/syn-solidity/tests/ident.rs | 7 +- crates/syn-solidity/tests/macros.rs | 9 --- 15 files changed, 136 insertions(+), 122 deletions(-) delete mode 100644 crates/syn-solidity/tests/macros.rs diff --git a/crates/sol-macro/src/expand/ty.rs b/crates/sol-macro/src/expand/ty.rs index 60b887e626..77eaee85fd 100644 --- a/crates/sol-macro/src/expand/ty.rs +++ b/crates/sol-macro/src/expand/ty.rs @@ -102,7 +102,7 @@ fn rec_expand_type(ty: &Type, tokens: &mut TokenStream) { Type::Array(ref array) => { let ty = expand_type(&array.ty); let span = array.span(); - if let Some(size) = &array.size { + if let Some(size) = array.size() { quote_spanned! {span=> ::alloy_sol_types::sol_data::FixedArray<#ty, #size> } @@ -148,11 +148,13 @@ pub(super) fn type_base_data_size(cx: &ExpCtxt<'_>, ty: &Type) -> usize { Type::String(_) | Type::Bytes(_) | Type::Array(TypeArray { size: None, .. }) => 64, // fixed array: size * encoded size - Type::Array(TypeArray { - ty: inner, - size: Some(size), - .. - }) => type_base_data_size(cx, inner) * size.base10_parse::().unwrap(), + Type::Array( + a @ TypeArray { + ty: inner, + size: Some(_), + .. + }, + ) => type_base_data_size(cx, inner) * a.size().unwrap(), // tuple: sum of encoded sizes Type::Tuple(tuple) => tuple @@ -290,7 +292,7 @@ impl fmt::Display for TypePrinter<'_> { Type::Array(array) => { Self::new(self.cx, &array.ty).fmt(f)?; f.write_str("[")?; - if let Some(size) = &array.size { + if let Some(size) = array.size() { size.fmt(f)?; } f.write_str("]") diff --git a/crates/syn-solidity/src/attribute/function.rs b/crates/syn-solidity/src/attribute/function.rs index 6861010605..347f50c70a 100644 --- a/crates/syn-solidity/src/attribute/function.rs +++ b/crates/syn-solidity/src/attribute/function.rs @@ -1,7 +1,6 @@ use crate::{kw, Modifier, Mutability, Override, SolPath, Spanned, VariableAttribute, Visibility}; use proc_macro2::Span; use std::{ - collections::HashSet, fmt, hash::{Hash, Hasher}, mem, @@ -17,7 +16,7 @@ use syn::{ /// A list of unique function attributes. Used in /// [ItemFunction][crate::ItemFunction]. #[derive(Clone, Default, PartialEq, Eq)] -pub struct FunctionAttributes(pub HashSet); +pub struct FunctionAttributes(pub Vec); impl fmt::Debug for FunctionAttributes { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -26,7 +25,7 @@ impl fmt::Debug for FunctionAttributes { } impl Deref for FunctionAttributes { - type Target = HashSet; + type Target = Vec; fn deref(&self) -> &Self::Target { &self.0 @@ -41,19 +40,19 @@ impl DerefMut for FunctionAttributes { impl Parse for FunctionAttributes { fn parse(input: ParseStream<'_>) -> Result { - let mut attributes = HashSet::::new(); + let mut attributes = Vec::::new(); while !(input.is_empty() || input.peek(kw::returns) || input.peek(Token![;]) || input.peek(Brace)) { - let attr = input.parse()?; - if let Some(prev) = attributes.get(&attr) { + let attr: FunctionAttribute = input.parse()?; + if let Some(prev) = attributes.iter().find(|a| **a == attr) { let mut e = Error::new(attr.span(), "duplicate attribute"); e.combine(Error::new(prev.span(), "previous declaration is here")); return Err(e) } - attributes.insert(attr); + attributes.push(attr); } Ok(Self(attributes)) } @@ -72,7 +71,7 @@ impl Spanned for FunctionAttributes { impl FunctionAttributes { #[inline] pub fn new() -> Self { - Self(HashSet::new()) + Self(Vec::new()) } pub fn visibility(&self) -> Option { diff --git a/crates/syn-solidity/src/attribute/variable.rs b/crates/syn-solidity/src/attribute/variable.rs index 49b0b0c742..43514e9206 100644 --- a/crates/syn-solidity/src/attribute/variable.rs +++ b/crates/syn-solidity/src/attribute/variable.rs @@ -1,7 +1,6 @@ use crate::{kw, Override, SolPath, Spanned, Visibility}; use proc_macro2::Span; use std::{ - collections::HashSet, fmt, hash::{Hash, Hasher}, mem, @@ -13,11 +12,11 @@ use syn::{ /// A list of unique variable attributes. #[derive(Clone, Debug)] -pub struct VariableAttributes(pub HashSet); +pub struct VariableAttributes(pub Vec); impl Parse for VariableAttributes { fn parse(input: ParseStream<'_>) -> Result { - let mut attributes = HashSet::new(); + let mut attributes = Vec::new(); while let Ok(attribute) = input.parse::() { let error = |prev: &VariableAttribute| { let mut e = Error::new(attribute.span(), "duplicate attribute"); @@ -28,15 +27,17 @@ impl Parse for VariableAttributes { // Only one of: `constant`, `immutable` match attribute { VariableAttribute::Constant(_) => { - if let Some(prev) = - attributes.get(&VariableAttribute::Immutable(Default::default())) + if let Some(prev) = attributes + .iter() + .find(|a| matches!(a, VariableAttribute::Immutable(_))) { return Err(error(prev)) } } VariableAttribute::Immutable(_) => { - if let Some(prev) = - attributes.get(&VariableAttribute::Constant(Default::default())) + if let Some(prev) = attributes + .iter() + .find(|a| matches!(a, VariableAttribute::Constant(_))) { return Err(error(prev)) } @@ -44,10 +45,10 @@ impl Parse for VariableAttributes { _ => {} } - if let Some(prev) = attributes.get(&attribute) { + if let Some(prev) = attributes.iter().find(|a| **a == attribute) { return Err(error(prev)) } - attributes.insert(attribute); + attributes.push(attribute); } Ok(Self(attributes)) } diff --git a/crates/syn-solidity/src/expr/mod.rs b/crates/syn-solidity/src/expr/mod.rs index ff05685d32..14dbe4b403 100644 --- a/crates/syn-solidity/src/expr/mod.rs +++ b/crates/syn-solidity/src/expr/mod.rs @@ -1,4 +1,6 @@ -use crate::{kw, utils::ParseNested, Lit, SolIdent, Spanned, Type}; +use crate::{ + kw, utils::ParseNested, Lit, LitDenominated, SolIdent, Spanned, SubDenomination, Type, +}; use proc_macro2::{Ident, Span}; use std::fmt; use syn::{ @@ -64,6 +66,9 @@ pub enum Expr { /// A literal: `hex"1234"`. Lit(Lit), + /// A number literal with a sub-denomination: `1 ether`. + LitDenominated(LitDenominated), + /// Access of a named member: `obj.k`. Member(ExprMember), @@ -106,6 +111,7 @@ impl fmt::Debug for Expr { Self::Ident(ident) => ident.fmt(f), Self::Index(expr) => expr.fmt(f), Self::Lit(lit) => lit.fmt(f), + Self::LitDenominated(lit) => lit.fmt(f), Self::Member(expr) => expr.fmt(f), Self::New(expr) => expr.fmt(f), Self::Payable(expr) => expr.fmt(f), @@ -150,6 +156,7 @@ impl Spanned for Expr { Self::Ident(ident) => ident.span(), Self::Index(expr) => expr.span(), Self::Lit(lit) => lit.span(), + Self::LitDenominated(lit) => lit.span(), Self::Member(expr) => expr.span(), Self::New(expr) => expr.span(), Self::Payable(expr) => expr.span(), @@ -172,6 +179,7 @@ impl Spanned for Expr { Self::Ident(ident) => ident.set_span(span), Self::Index(expr) => expr.set_span(span), Self::Lit(lit) => lit.set_span(span), + Self::LitDenominated(lit) => lit.set_span(span), Self::Member(expr) => expr.set_span(span), Self::New(expr) => expr.set_span(span), Self::Payable(expr) => expr.set_span(span), @@ -195,7 +203,16 @@ impl Expr { } else if UnOp::peek(input, &lookahead) { input.parse().map(Self::Unary) } else if Lit::peek(&lookahead) { - input.parse().map(Self::Lit) + match (input.parse()?, input.call(SubDenomination::parse_opt)?) { + (Lit::Number(number), Some(denom)) => { + Ok(Self::LitDenominated(LitDenominated { number, denom })) + } + (lit, None) => Ok(Self::Lit(lit)), + (_, Some(denom)) => Err(syn::Error::new( + denom.span(), + "unexpected subdenomination for literal", + )), + } } else if lookahead.peek(kw::payable) { input.parse().map(Self::Payable) } else if lookahead.peek(Token![type]) { diff --git a/crates/syn-solidity/src/ident/mod.rs b/crates/syn-solidity/src/ident/mod.rs index 9797d58031..a598ad98d7 100644 --- a/crates/syn-solidity/src/ident/mod.rs +++ b/crates/syn-solidity/src/ident/mod.rs @@ -11,8 +11,6 @@ use syn::{ mod path; pub use path::SolPath; -// TODO: Deny Solidity keywords - /// A Solidity identifier. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(transparent)] @@ -58,9 +56,16 @@ impl From for Ident { } } +impl From<&str> for SolIdent { + fn from(value: &str) -> Self { + Self::new(value) + } +} + impl Parse for SolIdent { fn parse(input: ParseStream<'_>) -> Result { - input.call(Ident::parse_any).map(Self) + // TODO: Deny Solidity keywords + Self::parse_any(input) } } @@ -98,7 +103,12 @@ impl SolIdent { s } - /// See `[Ident::peek_any]`. + /// Parses any identifier including keywords. + pub fn parse_any(input: ParseStream<'_>) -> Result { + input.call(Ident::parse_any).map(Self) + } + + /// Peeks any identifier including keywords. pub fn peek_any(input: ParseStream<'_>) -> bool { input.peek(Ident::peek_any) } diff --git a/crates/syn-solidity/src/ident/path.rs b/crates/syn-solidity/src/ident/path.rs index db32097e8d..f09c967145 100644 --- a/crates/syn-solidity/src/ident/path.rs +++ b/crates/syn-solidity/src/ident/path.rs @@ -21,12 +21,6 @@ macro_rules! sol_path { $(path.push($crate::SolIdent::from($e));)+ path }}; - - ($($id:ident).+) => {{ - let mut path = $crate::SolPath::new(); - $(path.push($crate::SolIdent::new(stringify!($id))));+ - path - }}; } /// A list of identifiers, separated by dots. diff --git a/crates/syn-solidity/src/lib.rs b/crates/syn-solidity/src/lib.rs index 0e5413c94b..5c1c6badf8 100644 --- a/crates/syn-solidity/src/lib.rs +++ b/crates/syn-solidity/src/lib.rs @@ -49,7 +49,7 @@ pub use item::{ mod lit; pub use lit::{ - HexStr, Lit, LitHexStr, LitNumber, LitNumberKind, LitStr, LitUnicodeStr, SubDenomination, + HexStr, Lit, LitDenominated, LitHexStr, LitNumber, LitStr, LitUnicodeStr, SubDenomination, UnicodeStr, }; diff --git a/crates/syn-solidity/src/lit/mod.rs b/crates/syn-solidity/src/lit/mod.rs index bc77deb848..b080322607 100644 --- a/crates/syn-solidity/src/lit/mod.rs +++ b/crates/syn-solidity/src/lit/mod.rs @@ -1,14 +1,13 @@ -use std::fmt; - use crate::{kw, Spanned}; use proc_macro2::Span; +use std::fmt; use syn::{ parse::{Lookahead1, Parse, ParseStream}, LitBool, Result, }; mod number; -pub use number::{LitNumber, LitNumberKind, SubDenomination}; +pub use number::{LitDenominated, LitNumber, SubDenomination}; mod str; pub use self::str::{HexStr, LitHexStr, LitStr, LitUnicodeStr, UnicodeStr}; diff --git a/crates/syn-solidity/src/lit/number.rs b/crates/syn-solidity/src/lit/number.rs index 963f5bf2e6..452c0ab2b3 100644 --- a/crates/syn-solidity/src/lit/number.rs +++ b/crates/syn-solidity/src/lit/number.rs @@ -9,55 +9,13 @@ use syn::{ // TODO: Fixed point numbers /// An integer or fixed-point number literal: `1` or `1.0`. -#[derive(Clone, Debug)] -pub struct LitNumber { - pub kind: LitNumberKind, - pub denom: Option, -} - -impl Parse for LitNumber { - fn parse(input: ParseStream<'_>) -> Result { - Ok(Self { - kind: input.parse()?, - denom: input.call(SubDenomination::parse_opt)?, - }) - } -} - -impl Spanned for LitNumber { - fn span(&self) -> Span { - let span = self.kind.span(); - self.denom - .as_ref() - .and_then(|d| d.span().join(span)) - .unwrap_or(span) - } - - fn set_span(&mut self, span: Span) { - self.kind.set_span(span); - if let Some(denom) = &mut self.denom { - denom.set_span(span); - } - } -} - -impl LitNumber { - pub fn new(kind: LitNumberKind) -> Self { - Self { kind, denom: None } - } - - pub fn peek(lookahead: &Lookahead1<'_>) -> bool { - LitNumberKind::peek(lookahead) - } -} - #[derive(Clone)] -pub enum LitNumberKind { +pub enum LitNumber { Int(LitInt), Float(LitFloat), } -impl fmt::Debug for LitNumberKind { +impl fmt::Debug for LitNumber { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Int(lit) => lit.fmt(f), @@ -66,7 +24,7 @@ impl fmt::Debug for LitNumberKind { } } -impl Parse for LitNumberKind { +impl Parse for LitNumber { fn parse(input: ParseStream<'_>) -> Result { let lookahead = input.lookahead1(); if lookahead.peek(LitInt) { @@ -79,7 +37,7 @@ impl Parse for LitNumberKind { } } -impl Spanned for LitNumberKind { +impl Spanned for LitNumber { fn span(&self) -> Span { match self { Self::Int(lit) => lit.span(), @@ -95,7 +53,7 @@ impl Spanned for LitNumberKind { } } -impl LitNumberKind { +impl LitNumber { pub fn new_int(repr: &str, span: Span) -> Self { Self::Int(LitInt::new(repr, span)) } @@ -147,6 +105,33 @@ impl LitNumberKind { } } +#[derive(Clone, Debug)] +pub struct LitDenominated { + pub number: LitNumber, + pub denom: SubDenomination, +} + +impl Parse for LitDenominated { + fn parse(input: ParseStream<'_>) -> Result { + Ok(Self { + number: input.parse()?, + denom: input.parse()?, + }) + } +} + +impl Spanned for LitDenominated { + fn span(&self) -> Span { + let span = self.number.span(); + span.join(self.denom.span()).unwrap_or(span) + } + + fn set_span(&mut self, span: Span) { + self.number.set_span(span); + self.denom.set_span(span); + } +} + kw_enum! { pub enum SubDenomination { Wei(kw::wei), diff --git a/crates/syn-solidity/src/stmt/for.rs b/crates/syn-solidity/src/stmt/for.rs index 835317a4a8..c8d3d4305a 100644 --- a/crates/syn-solidity/src/stmt/for.rs +++ b/crates/syn-solidity/src/stmt/for.rs @@ -16,10 +16,10 @@ use syn::{ pub struct StmtFor { pub for_token: Token![for], pub paren_token: Paren, - pub init: ForInitStmt, - pub cond: Option, + pub init: Box, + pub cond: Option>, pub semi_token: Token![;], - pub post: Option, + pub post: Option>, pub body: Box, } diff --git a/crates/syn-solidity/src/stmt/try.rs b/crates/syn-solidity/src/stmt/try.rs index 46a475ef43..dd1abf9640 100644 --- a/crates/syn-solidity/src/stmt/try.rs +++ b/crates/syn-solidity/src/stmt/try.rs @@ -15,7 +15,7 @@ use syn::{ #[derive(Clone)] pub struct StmtTry { pub try_token: Token![try], - pub expr: Expr, + pub expr: Box, pub returns: Option, /// The try block. pub block: Block, diff --git a/crates/syn-solidity/src/stmt/var_decl.rs b/crates/syn-solidity/src/stmt/var_decl.rs index 9598cbe26a..db3d794ab5 100644 --- a/crates/syn-solidity/src/stmt/var_decl.rs +++ b/crates/syn-solidity/src/stmt/var_decl.rs @@ -15,7 +15,7 @@ use syn::{ /// #[derive(Clone)] pub struct StmtVarDecl { - pub declaration: VarDeclDecl, + pub declaration: Box, pub assignment: Option<(Token![=], Expr)>, pub semi_token: Token![;], } @@ -43,7 +43,7 @@ impl Parse for StmtVarDecl { let semi_token = input.parse()?; Ok(Self { - declaration, + declaration: Box::new(declaration), assignment, semi_token, }) diff --git a/crates/syn-solidity/src/type/array.rs b/crates/syn-solidity/src/type/array.rs index 46de9457e3..1d467104e7 100644 --- a/crates/syn-solidity/src/type/array.rs +++ b/crates/syn-solidity/src/type/array.rs @@ -1,4 +1,4 @@ -use crate::{Spanned, Type}; +use crate::{Expr, Lit, LitNumber, Spanned, Type}; use proc_macro2::Span; use std::{ fmt, @@ -7,9 +7,9 @@ use std::{ }; use syn::{ bracketed, - parse::{Parse, ParseStream}, + parse::{discouraged::Speculative, Parse, ParseStream}, token::Bracket, - LitInt, Result, + Result, }; /// An array type. @@ -17,12 +17,12 @@ use syn::{ pub struct TypeArray { pub ty: Box, pub bracket_token: Bracket, - pub size: Option, + pub size: Option>, } impl PartialEq for TypeArray { fn eq(&self, other: &Self) -> bool { - self.ty == other.ty && self.size == other.size + self.ty == other.ty && self.size() == other.size() } } @@ -31,7 +31,7 @@ impl Eq for TypeArray {} impl Hash for TypeArray { fn hash(&self, state: &mut H) { self.ty.hash(state); - self.size.hash(state); + self.size().hash(state); } } @@ -39,7 +39,7 @@ impl fmt::Debug for TypeArray { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("TypeArray") .field(&self.ty) - .field(&self.size.as_ref().map(|s| s.base10_digits())) + .field(&self.size()) .finish() } } @@ -48,7 +48,7 @@ impl fmt::Display for TypeArray { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.ty.fmt(f)?; f.write_str("[")?; - if let Some(s) = &self.size { + if let Some(s) = self.size_lit() { f.write_str(s.base10_digits())?; } f.write_str("]") @@ -80,7 +80,15 @@ impl Spanned for TypeArray { impl TypeArray { /// Returns the size of the array, or None if dynamic. pub fn size(&self) -> Option { - self.size.as_ref().map(|s| s.base10_parse().unwrap()) + self.size_lit().map(|s| s.base10_parse().unwrap()) + } + + /// Returns the size of the array, or None if dynamic. + pub fn size_lit(&self) -> Option<&LitNumber> { + self.size.as_ref().map(|s| match &**s { + Expr::Lit(Lit::Number(n)) => n, + _ => panic!("unevaluated literal in array size"), + }) } /// See [`Type::is_abi_dynamic`]. @@ -98,16 +106,27 @@ impl TypeArray { ty, bracket_token: bracketed!(content in input), size: { - let size = if content.is_empty() { + if content.is_empty() { None } else { - Some(content.parse::()?) - }; - // Validate the size - if let Some(sz) = &size { + let fork = content.fork(); + let sz = match fork.parse::() { + Ok(lit) => lit, + Err(e) => { + return Err(match fork.parse::() { + Ok(_) => syn::Error::new( + e.span(), + "generic expressions are not supported in array type sizes", + ), + Err(e) => e, + }) + } + }; + content.advance_to(&fork); + // Validate the size sz.base10_parse::()?; + Some(Box::new(Expr::Lit(Lit::Number(LitNumber::Int(sz))))) } - size }, }) } diff --git a/crates/syn-solidity/tests/ident.rs b/crates/syn-solidity/tests/ident.rs index 367f211db1..ef7594db38 100644 --- a/crates/syn-solidity/tests/ident.rs +++ b/crates/syn-solidity/tests/ident.rs @@ -1,7 +1,4 @@ -use syn_solidity::{SolIdent, SolPath}; - -#[macro_use] -mod macros; +use syn_solidity::{sol_path, SolIdent, SolPath}; #[test] fn ident() { @@ -12,7 +9,7 @@ fn ident() { #[test] fn ident_path() { let path: SolPath = syn::parse_str("a.b.c").unwrap(); - assert_eq!(path, path![a, b, c]); + assert_eq!(path, sol_path!["a", "b", "c"]); } #[test] diff --git a/crates/syn-solidity/tests/macros.rs b/crates/syn-solidity/tests/macros.rs deleted file mode 100644 index 4d6a287c58..0000000000 --- a/crates/syn-solidity/tests/macros.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![allow(unused_macros, unused_macro_rules)] - -macro_rules! path { - ($($e:ident),* $(,)?) => {{ - let mut path = syn_solidity::SolPath::new(); - $(path.push(syn_solidity::SolIdent::new(stringify!($e)));)+ - path - }} -} From 72ad57f5126285ede559a0039401ad89cf88c1a6 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Sat, 5 Aug 2023 20:47:50 +0200 Subject: [PATCH 21/22] docs --- crates/syn-solidity/src/attribute/mod.rs | 11 ----------- crates/syn-solidity/src/expr/mod.rs | 2 +- crates/syn-solidity/src/expr/unary.rs | 2 +- crates/syn-solidity/src/item/function.rs | 5 ----- crates/syn-solidity/src/lit/number.rs | 1 + 5 files changed, 3 insertions(+), 18 deletions(-) diff --git a/crates/syn-solidity/src/attribute/mod.rs b/crates/syn-solidity/src/attribute/mod.rs index 3efd239dc1..1502608c0e 100644 --- a/crates/syn-solidity/src/attribute/mod.rs +++ b/crates/syn-solidity/src/attribute/mod.rs @@ -21,11 +21,8 @@ pub use variable::{VariableAttribute, VariableAttributes}; kw_enum! { /// A storage location. pub enum Storage { - /// `memory` Memory(kw::memory), - /// `storage` Storage(kw::storage), - /// `calldata` Calldata(kw::calldata), } } @@ -33,13 +30,9 @@ kw_enum! { kw_enum! { /// A visibility attribute. pub enum Visibility { - /// `external` External(kw::external), - /// `public` Public(kw::public), - /// `internal` Internal(kw::internal), - /// `private` Private(kw::private), } } @@ -47,13 +40,9 @@ kw_enum! { kw_enum! { /// A mutability attribute. pub enum Mutability { - /// `pure` Pure(kw::pure), - /// `view` View(kw::view), - /// `constant` Constant(kw::constant), - /// `payable` Payable(kw::payable), } } diff --git a/crates/syn-solidity/src/expr/mod.rs b/crates/syn-solidity/src/expr/mod.rs index 14dbe4b403..4d326e2188 100644 --- a/crates/syn-solidity/src/expr/mod.rs +++ b/crates/syn-solidity/src/expr/mod.rs @@ -95,7 +95,7 @@ pub enum Expr { /// A `type()` expression: `type(uint256)` TypeCall(ExprTypeCall), - /// A unary operation: `!x`, `*x`. + /// A unary operation: `!x`, `-x`. Unary(ExprUnary), } diff --git a/crates/syn-solidity/src/expr/unary.rs b/crates/syn-solidity/src/expr/unary.rs index 685b894bb1..ca7fa339ac 100644 --- a/crates/syn-solidity/src/expr/unary.rs +++ b/crates/syn-solidity/src/expr/unary.rs @@ -6,7 +6,7 @@ use syn::{ Result, }; -/// A unary operation: `!x`, `*x`. +/// A unary operation: `!x`, `-x`. #[derive(Clone, Debug)] pub struct ExprUnary { pub op: UnOp, diff --git a/crates/syn-solidity/src/item/function.rs b/crates/syn-solidity/src/item/function.rs index c25c1acf53..7fdf8087c6 100644 --- a/crates/syn-solidity/src/item/function.rs +++ b/crates/syn-solidity/src/item/function.rs @@ -191,15 +191,10 @@ impl ItemFunction { kw_enum! { /// The kind of function. pub enum FunctionKind { - /// `constructor` Constructor(kw::constructor), - /// `function` Function(kw::function), - /// `fallback` Fallback(kw::fallback), - /// `receive` Receive(kw::receive), - /// `modifier` Modifier(kw::modifier), } } diff --git a/crates/syn-solidity/src/lit/number.rs b/crates/syn-solidity/src/lit/number.rs index 452c0ab2b3..85388c9802 100644 --- a/crates/syn-solidity/src/lit/number.rs +++ b/crates/syn-solidity/src/lit/number.rs @@ -133,6 +133,7 @@ impl Spanned for LitDenominated { } kw_enum! { + /// A sub-denomination suffix for a number literal. pub enum SubDenomination { Wei(kw::wei), Gwei(kw::gwei), From fb7a3a99ac5a738c6747899ac48137c2f57cc9d5 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Fri, 18 Aug 2023 12:03:29 +0200 Subject: [PATCH 22/22] update tests --- crates/sol-types/tests/ui/type.stderr | 4 ++-- crates/syn-solidity/src/attribute/function.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/sol-types/tests/ui/type.stderr b/crates/sol-types/tests/ui/type.stderr index eb68fd074e..f79ecce468 100644 --- a/crates/sol-types/tests/ui/type.stderr +++ b/crates/sol-types/tests/ui/type.stderr @@ -74,7 +74,7 @@ error: proc macro panicked 741 | | } | |_^ | - = help: message: mapping types are unsupported: TypeMapping { key: TypeMapping { key: Custom([SolIdent("a")]), key_name: Some(SolIdent("b")), value: Custom([SolIdent("c")]), value_name: Some(SolIdent("d")) }, key_name: Some(SolIdent("e")), value: TypeMapping { key: Custom([SolIdent("f")]), key_name: Some(SolIdent("g")), value: Custom([SolIdent("h")]), value_name: Some(SolIdent("i")) }, value_name: Some(SolIdent("j")) } + = help: message: mapping types are unsupported: TypeMapping { key: Type::TypeMapping { key: Type::Custom([SolIdent("a")]), key_name: Some(SolIdent("b")), value: Type::Custom([SolIdent("c")]), value_name: Some(SolIdent("d")) }, key_name: Some(SolIdent("e")), value: Type::TypeMapping { key: Type::Custom([SolIdent("f")]), key_name: Some(SolIdent("g")), value: Type::Custom([SolIdent("h")]), value_name: Some(SolIdent("i")) }, value_name: Some(SolIdent("j")) } error: proc macro panicked --> tests/ui/type.rs:743:1 @@ -84,7 +84,7 @@ error: proc macro panicked 745 | | } | |_^ | - = help: message: mapping types are unsupported: TypeMapping { key: Uint(Some(256)), key_name: Some(SolIdent("a")), value: Bool, value_name: Some(SolIdent("b")) } + = help: message: mapping types are unsupported: TypeMapping { key: Type::Uint(Some(256)), key_name: Some(SolIdent("a")), value: Type::Bool, value_name: Some(SolIdent("b")) } error[E0412]: cannot find type `bytes_` in this scope --> tests/ui/type.rs:205:9 diff --git a/crates/syn-solidity/src/attribute/function.rs b/crates/syn-solidity/src/attribute/function.rs index cb56c6f958..26c1d01303 100644 --- a/crates/syn-solidity/src/attribute/function.rs +++ b/crates/syn-solidity/src/attribute/function.rs @@ -41,7 +41,7 @@ impl DerefMut for FunctionAttributes { impl Parse for FunctionAttributes { fn parse(input: ParseStream<'_>) -> Result { let mut attributes = Vec::::new(); - while !(input.is_empty() || input.peek(kw::returns) || input.peek(Ident::peek_any)) { + while !input.is_empty() && !input.peek(kw::returns) && input.peek(Ident::peek_any) { let attr: FunctionAttribute = input.parse()?; if let Some(prev) = attributes.iter().find(|a| **a == attr) { let mut e = Error::new(attr.span(), "duplicate attribute");