Skip to content

Commit

Permalink
feat(syn-solidity): add statements and expressions (#199)
Browse files Browse the repository at this point in the history
* feat: expose everything

* feat: expose everything

* feat: add statments

* feat: add stmts

* just missing lits

* wip

* wip

* changes

* remove dup

* wip

* feat: stmt

* feat: exprs

* feat: spanned

* fix bugs, part 1

* fix(sol-macro): snake_case'd function names

* fix bugs, part 2

* chore: clippy

* fix mod name

* chore: clippy

* fixes

* docs

* update tests

---------

Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com>
  • Loading branch information
Will-Smith11 and DaniPopes authored Aug 23, 2023
1 parent 691ddf1 commit 4298501
Show file tree
Hide file tree
Showing 72 changed files with 3,977 additions and 582 deletions.
2 changes: 1 addition & 1 deletion crates/sol-macro/src/expand/enum.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
2 changes: 1 addition & 1 deletion crates/sol-macro/src/expand/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
11 changes: 7 additions & 4 deletions crates/sol-macro/src/expand/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -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")
}

Expand All @@ -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")
}

Expand Down
2 changes: 1 addition & 1 deletion crates/sol-macro/src/expand/struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
18 changes: 10 additions & 8 deletions crates/sol-macro/src/expand/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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>
}
Expand Down Expand Up @@ -153,11 +153,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::<usize>().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
Expand Down Expand Up @@ -295,7 +297,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("]")
Expand Down
19 changes: 11 additions & 8 deletions crates/sol-macro/src/input.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use ast::Spanned;
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),
Expand All @@ -16,15 +18,15 @@ pub enum SolInputKind {
// doesn't parse Json
impl Parse for SolInputKind {
fn parse(input: ParseStream<'_>) -> Result<Self> {
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"))
}
Expand All @@ -35,6 +37,7 @@ impl Parse for SolInputKind {
}
}

#[derive(Clone, Debug)]
pub struct SolInput {
pub path: Option<PathBuf>,
pub kind: SolInputKind,
Expand Down
1 change: 0 additions & 1 deletion crates/sol-macro/src/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ fn expand_abi(name: &Ident, abi: JsonAbi) -> Result<TokenStream> {
// `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());
}
}
Expand Down
4 changes: 2 additions & 2 deletions crates/sol-types/tests/ui/type.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
20 changes: 16 additions & 4 deletions crates/syn-solidity/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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! {
Expand All @@ -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(())
```
53 changes: 35 additions & 18 deletions crates/syn-solidity/src/attribute/function.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
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,
fmt,
hash::{Hash, Hasher},
mem,
Expand All @@ -11,16 +10,22 @@ use syn::{
ext::IdentExt,
parse::{Parse, ParseStream},
token::Brace,
Error, Ident, Result,
Error, Ident, Result, Token,
};

/// A list of unique function attributes. Used in
/// [ItemFunction][crate::ItemFunction].
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct FunctionAttributes(pub HashSet<FunctionAttribute>);
#[derive(Clone, Default, PartialEq, Eq)]
pub struct FunctionAttributes(pub Vec<FunctionAttribute>);

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<FunctionAttribute>;
type Target = Vec<FunctionAttribute>;

fn deref(&self) -> &Self::Target {
&self.0
Expand All @@ -35,24 +40,34 @@ impl DerefMut for FunctionAttributes {

impl Parse for FunctionAttributes {
fn parse(input: ParseStream<'_>) -> Result<Self> {
let mut attributes = HashSet::<FunctionAttribute>::new();
while !(input.is_empty() || input.peek(kw::returns) || !input.peek(Ident::peek_any)) {
let attr = input.parse()?;
if let Some(prev) = attributes.get(&attr) {
let mut attributes = Vec::<FunctionAttribute>::new();
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");
e.combine(Error::new(prev.span(), "previous declaration is here"));
return Err(e)
}
attributes.insert(attr);
attributes.push(attr);
}
Ok(Self(attributes))
}
}

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 {
Self(HashSet::new())
Self(Vec::new())
}

pub fn visibility(&self) -> Option<Visibility> {
Expand Down Expand Up @@ -112,7 +127,7 @@ pub enum FunctionAttribute {
/// A [Mutability] attribute.
Mutability(Mutability),
/// `virtual`
Virtual(kw::Virtual),
Virtual(Token![virtual]),
/// `immutable`
Immutable(kw::immutable),
/// An [Override] attribute.
Expand Down Expand Up @@ -174,9 +189,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)
Expand All @@ -202,8 +217,8 @@ impl From<VariableAttribute> 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(),
Expand All @@ -214,7 +229,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),
Expand All @@ -224,7 +239,9 @@ impl FunctionAttribute {
Self::Modifier(m) => m.set_span(span),
}
}
}

impl FunctionAttribute {
#[inline]
pub const fn visibility(&self) -> Option<Visibility> {
match self {
Expand Down
Loading

0 comments on commit 4298501

Please sign in to comment.