diff --git a/crates/analyzer/src/db/queries/module.rs b/crates/analyzer/src/db/queries/module.rs index 8c46a60583..c3d51af2b5 100644 --- a/crates/analyzer/src/db/queries/module.rs +++ b/crates/analyzer/src/db/queries/module.rs @@ -97,6 +97,7 @@ pub fn module_all_items(db: &dyn AnalyzerDb, module: ModuleId) -> Rc<[Item]> { })))) } ast::ModuleStmt::Pragma(_) => None, + ast::ModuleStmt::Trait(_) => None, ast::ModuleStmt::Use(_) => None, ast::ModuleStmt::Event(node) => Some(Item::Event(db.intern_event(Rc::new(Event { ast: node.clone(), diff --git a/crates/lowering/src/mappers/functions.rs b/crates/lowering/src/mappers/functions.rs index 048d9745c5..b3303be097 100644 --- a/crates/lowering/src/mappers/functions.rs +++ b/crates/lowering/src/mappers/functions.rs @@ -22,6 +22,7 @@ pub fn func_def(context: &mut ModuleContext, function: FunctionId) -> Node Node ast::Function { unsafe_: None, name: names::list_expr_generator_fn_name(array).into_node(), args, + generic_params: Vec::new().into_node(), return_type, body: [vec![var_decl], assignments, vec![return_stmt]].concat(), } diff --git a/crates/parser/src/ast.rs b/crates/parser/src/ast.rs index cc3af76dce..ebaaa5b053 100644 --- a/crates/parser/src/ast.rs +++ b/crates/parser/src/ast.rs @@ -21,6 +21,7 @@ pub enum ModuleStmt { Contract(Node), Constant(Node), Struct(Node), + Trait(Node), Function(Node), Event(Node), ParseError(Span), @@ -87,6 +88,12 @@ pub struct Struct { pub pub_qual: Option, } +#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)] +pub struct Trait { + pub name: Node, + pub pub_qual: Option, +} + #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)] pub enum TypeDesc { Unit, @@ -123,6 +130,24 @@ impl Spanned for GenericArg { } } +#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)] +pub enum GenericParameter { + Unbounded(Node), + Bounded { + name: Node, + bound: Node, + }, +} + +impl Spanned for GenericParameter { + fn span(&self) -> Span { + match self { + GenericParameter::Unbounded(node) => node.span, + GenericParameter::Bounded { name, bound } => name.span + bound.span, + } + } +} + /// struct or contract field, with optional 'pub' and 'const' qualifiers #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)] pub struct Field { @@ -153,6 +178,7 @@ pub struct Function { pub pub_: Option, pub unsafe_: Option, pub name: Node, + pub generic_params: Node>, pub args: Vec>, pub return_type: Option>, pub body: Vec>, @@ -406,6 +432,7 @@ impl Spanned for ModuleStmt { match self { ModuleStmt::Pragma(inner) => inner.span, ModuleStmt::Use(inner) => inner.span, + ModuleStmt::Trait(inner) => inner.span, ModuleStmt::TypeAlias(inner) => inner.span, ModuleStmt::Contract(inner) => inner.span, ModuleStmt::Constant(inner) => inner.span, @@ -437,6 +464,7 @@ impl fmt::Display for ModuleStmt { match self { ModuleStmt::Pragma(node) => write!(f, "{}", node.kind), ModuleStmt::Use(node) => write!(f, "{}", node.kind), + ModuleStmt::Trait(node) => write!(f, "{}", node.kind), ModuleStmt::TypeAlias(node) => write!(f, "{}", node.kind), ModuleStmt::Contract(node) => write!(f, "{}", node.kind), ModuleStmt::Constant(node) => write!(f, "{}", node.kind), @@ -504,6 +532,14 @@ impl fmt::Display for ConstantDecl { } } +impl fmt::Display for Trait { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + writeln!(f, "trait {}:", self.name.kind)?; + + Ok(()) + } +} + impl fmt::Display for TypeAlias { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "type {} = {}", self.name.kind, self.typ.kind) diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs index 00bfb7447f..0b8c906573 100644 --- a/crates/parser/src/grammar.rs +++ b/crates/parser/src/grammar.rs @@ -2,4 +2,5 @@ pub mod contracts; pub mod expressions; pub mod functions; pub mod module; +pub mod traits; pub mod types; diff --git a/crates/parser/src/grammar/functions.rs b/crates/parser/src/grammar/functions.rs index 99ef6085b2..53b797f2bc 100644 --- a/crates/parser/src/grammar/functions.rs +++ b/crates/parser/src/grammar/functions.rs @@ -2,11 +2,11 @@ use super::expressions::{parse_call_args, parse_expr}; use super::types::parse_type_desc; use crate::ast::{ - BinOperator, Expr, FuncStmt, Function, FunctionArg, RegularFunctionArg, VarDeclTarget, + BinOperator, Expr, FuncStmt, Function, FunctionArg, GenericParameter, RegularFunctionArg, + VarDeclTarget, }; -use crate::lexer::TokenKind; use crate::node::{Node, Span}; -use crate::{Label, ParseFailed, ParseResult, Parser}; +use crate::{Label, ParseFailed, ParseResult, Parser, TokenKind}; /// Parse a function definition. The optional `pub` qualifier must be parsed by /// the caller, and passed in. Next token must be `unsafe` or `fn`. @@ -28,7 +28,14 @@ pub fn parse_fn_def(par: &mut Parser, mut pub_qual: Option) -> ParseResult } let fn_tok = par.expect(TokenKind::Fn, "failed to parse function definition")?; let name = par.expect(TokenKind::Name, "failed to parse function definition")?; - let mut span = fn_tok.span + unsafe_qual + pub_qual + name.span; + + let generic_params = if par.peek() == Some(TokenKind::Lt) { + parse_generic_params(par)? + } else { + Node::new(vec![], name.span) + }; + + let mut span = fn_tok.span + unsafe_qual + pub_qual + name.span + generic_params.span; let args = match par.peek_or_err()? { TokenKind::ParenOpen => { @@ -87,6 +94,7 @@ pub fn parse_fn_def(par: &mut Parser, mut pub_qual: Option) -> ParseResult unsafe_: unsafe_qual, name: name.into(), args, + generic_params, return_type, body, }, @@ -94,6 +102,85 @@ pub fn parse_fn_def(par: &mut Parser, mut pub_qual: Option) -> ParseResult )) } +/// Parse a single generic function parameter (eg. `T:SomeTrait` in `fn foo(some_arg: u256) -> bool`). +/// # Panics +/// Panics if the first token isn't `Name`. +pub fn parse_generic_param(par: &mut Parser) -> ParseResult { + use TokenKind::*; + + let name = par.assert(Name); + match par.optional(Colon) { + Some(_) => { + let bound = par.assert(Name); + Ok(GenericParameter::Bounded { + name: Node::new(name.text.into(), name.span), + bound: Node::new(bound.text.into(), bound.span), + }) + } + None => Ok(GenericParameter::Unbounded(Node::new( + name.text.into(), + name.span, + ))), + } +} + +/// Parse an angle-bracket-wrapped list of generic arguments (eg. `` in `fn foo(some_arg: u256) -> bool`). +/// # Panics +/// Panics if the first token isn't `<`. +pub fn parse_generic_params(par: &mut Parser) -> ParseResult>> { + use TokenKind::*; + let mut span = par.assert(Lt).span; + + let mut args = vec![]; + + let expect_end = |par: &mut Parser| { + // If there's no comma, the next token must be `>` + match par.peek_or_err()? { + Gt => Ok(par.next()?.span), + _ => { + let tok = par.next()?; + par.unexpected_token_error( + tok.span, + "Unexpected token while parsing generic arg list", + vec!["Expected a `>` here".to_string()], + ); + Err(ParseFailed) + } + } + }; + + loop { + match par.peek_or_err()? { + Gt => { + span += par.next()?.span; + break; + } + Name => { + let typ = parse_generic_param(par)?; + args.push(typ); + if par.peek() == Some(Comma) { + par.next()?; + } else { + span += expect_end(par)?; + break; + } + } + + // Invalid generic argument. + _ => { + let tok = par.next()?; + par.unexpected_token_error( + tok.span, + "failed to parse list of generic function parameters", + vec!["Expected a generic parameter name such as `T` here".to_string()], + ); + return Err(ParseFailed); + } + } + } + Ok(Node::new(args, span)) +} + fn parse_fn_param_list(par: &mut Parser) -> ParseResult>>> { let mut span = par.assert(TokenKind::ParenOpen).span; let mut params = vec![]; diff --git a/crates/parser/src/grammar/module.rs b/crates/parser/src/grammar/module.rs index d7e49cd126..f429e3d8de 100644 --- a/crates/parser/src/grammar/module.rs +++ b/crates/parser/src/grammar/module.rs @@ -1,6 +1,7 @@ use super::contracts::parse_contract_def; use super::expressions::parse_expr; use super::functions::parse_fn_def; +use super::traits::parse_trait_def; use super::types::{ parse_event_def, parse_path_tail, parse_struct_def, parse_type_alias, parse_type_desc, }; @@ -44,6 +45,7 @@ pub fn parse_module_stmt(par: &mut Parser) -> ParseResult { TokenKind::Use => ModuleStmt::Use(parse_use(par)?), TokenKind::Contract => ModuleStmt::Contract(parse_contract_def(par, None)?), TokenKind::Struct => ModuleStmt::Struct(parse_struct_def(par, None)?), + TokenKind::Trait => ModuleStmt::Trait(parse_trait_def(par, None)?), TokenKind::Type => ModuleStmt::TypeAlias(parse_type_alias(par, None)?), TokenKind::Const => ModuleStmt::Constant(parse_constant(par, None)?), diff --git a/crates/parser/src/grammar/traits.rs b/crates/parser/src/grammar/traits.rs new file mode 100644 index 0000000000..147367aceb --- /dev/null +++ b/crates/parser/src/grammar/traits.rs @@ -0,0 +1,55 @@ +use crate::ast::Trait; +use crate::grammar::functions::parse_single_word_stmt; +use crate::node::{Node, Span}; +use crate::{ParseFailed, ParseResult, Parser, TokenKind}; + +/// Parse a trait definition. +/// # Panics +/// Panics if the next token isn't `trait`. +pub fn parse_trait_def(par: &mut Parser, trait_pub_qual: Option) -> ParseResult> { + let trait_tok = par.assert(TokenKind::Trait); + + // trait Event: + // pass + // + + let trait_name = par.expect_with_notes( + TokenKind::Name, + "failed to parse trait definition", + |_| vec!["Note: `trait` must be followed by a name, which must start with a letter and contain only letters, numbers, or underscores".into()], + )?; + + let header_span = trait_tok.span + trait_name.span; + par.enter_block(header_span, "trait definition")?; + + loop { + match par.peek() { + Some(TokenKind::Pass) => { + parse_single_word_stmt(par)?; + } + Some(TokenKind::Dedent) => { + par.next()?; + break; + } + None => break, + Some(_) => { + let tok = par.next()?; + par.unexpected_token_error( + tok.span, + "failed to parse trait definition body", + vec![], + ); + return Err(ParseFailed); + } + }; + } + + let span = header_span + trait_pub_qual; + Ok(Node::new( + Trait { + name: Node::new(trait_name.text.into(), trait_name.span), + pub_qual: trait_pub_qual, + }, + span, + )) +} diff --git a/crates/parser/src/lexer/token.rs b/crates/parser/src/lexer/token.rs index 4a76fe6001..d148c202dd 100644 --- a/crates/parser/src/lexer/token.rs +++ b/crates/parser/src/lexer/token.rs @@ -101,6 +101,8 @@ pub enum TokenKind { SelfValue, #[token("struct")] Struct, + #[token("trait")] + Trait, #[token("type")] Type, #[token("unsafe")] @@ -249,6 +251,7 @@ impl TokenKind { Revert => "keyword `revert`", SelfValue => "keyword `self`", Struct => "keyword `struct`", + Trait => "keyword `trait`", Type => "keyword `type`", Unsafe => "keyword `unsafe`", While => "keyword `while`", diff --git a/crates/parser/tests/cases/parse_ast.rs b/crates/parser/tests/cases/parse_ast.rs index 443342719a..9b29a1ead3 100644 --- a/crates/parser/tests/cases/parse_ast.rs +++ b/crates/parser/tests/cases/parse_ast.rs @@ -141,6 +141,8 @@ test_parse! { type_tuple, types::parse_type_desc, "(u8, u16, address, Map bool:\n false"} + +test_parse! { fn_def_generic, try_parse_module, "fn foo(this: T, that: R, _ val: u64) -> bool:\n false"} test_parse! { fn_def_pub, try_parse_module, "pub fn foo21(x: bool, y: address,) -> bool:\n x"} test_parse! { fn_def_unsafe, try_parse_module, "unsafe fn foo21(x: bool, y: address,) -> bool:\n x"} test_parse! { fn_def_pub_unsafe, try_parse_module, "pub unsafe fn foo21(x: bool, y: address,) -> bool:\n x"} diff --git a/crates/parser/tests/cases/snapshots/cases__errors__module_bad_stmt.snap b/crates/parser/tests/cases/snapshots/cases__errors__module_bad_stmt.snap index ec1698efa4..d401976178 100644 --- a/crates/parser/tests/cases/snapshots/cases__errors__module_bad_stmt.snap +++ b/crates/parser/tests/cases/snapshots/cases__errors__module_bad_stmt.snap @@ -9,6 +9,6 @@ error: failed to parse module 1 │ if x: │ ^^ unexpected token │ - = Note: expected import, contract, struct, type, const or event + = Note: expected import, contract, struct, trait, type, const or event diff --git a/crates/parser/tests/cases/snapshots/cases__parse_ast__contract_def.snap b/crates/parser/tests/cases/snapshots/cases__parse_ast__contract_def.snap index 2b5ac85227..0d61f5867f 100644 --- a/crates/parser/tests/cases/snapshots/cases__parse_ast__contract_def.snap +++ b/crates/parser/tests/cases/snapshots/cases__parse_ast__contract_def.snap @@ -1,6 +1,6 @@ --- source: crates/parser/tests/cases/parse_ast.rs -expression: "ast_string(stringify!(contract_def), module::parse_module,\n r#\"contract Foo:\n x: address\n pub y: u8\n pub const z: Map\n pub fn foo() -> u8:\n return 10\n event Bar:\n idx from: address\n\"#)" +expression: "ast_string(stringify!(contract_def), try_parse_module,\n r#\"contract Foo:\n x: address\n pub y: u8\n pub const z: Map\n pub fn foo() -> u8:\n return 10\n event Bar:\n idx from: address\n\"#)" --- Node( @@ -145,6 +145,13 @@ Node( end: 83, ), ), + generic_params: Node( + kind: [], + span: Span( + start: 80, + end: 83, + ), + ), args: [], return_type: Some(Node( kind: Base( diff --git a/crates/parser/tests/cases/snapshots/cases__parse_ast__fn_def.snap b/crates/parser/tests/cases/snapshots/cases__parse_ast__fn_def.snap index ebed258f4b..24be74401c 100644 --- a/crates/parser/tests/cases/snapshots/cases__parse_ast__fn_def.snap +++ b/crates/parser/tests/cases/snapshots/cases__parse_ast__fn_def.snap @@ -1,6 +1,6 @@ --- source: crates/parser/tests/cases/parse_ast.rs -expression: "ast_string(stringify!(fn_def), try_parse_module,\n \"fn transfer(from sender: address, to recip: address, _ val: u64) -> bool:\\n false\")" +expression: "ast_string(stringify!(fn_def), try_parse_module,\n \"fn transfer(from sender: address, to recip: address, _ val: u64) -> bool:\\n false\")" --- Node( @@ -17,6 +17,13 @@ Node( end: 11, ), ), + generic_params: Node( + kind: [], + span: Span( + start: 3, + end: 11, + ), + ), args: [ Node( kind: Regular(RegularFunctionArg( diff --git a/crates/parser/tests/cases/snapshots/cases__parse_ast__fn_def_generic.snap b/crates/parser/tests/cases/snapshots/cases__parse_ast__fn_def_generic.snap new file mode 100644 index 0000000000..15e16ae572 --- /dev/null +++ b/crates/parser/tests/cases/snapshots/cases__parse_ast__fn_def_generic.snap @@ -0,0 +1,172 @@ +--- +source: crates/parser/tests/cases/parse_ast.rs +expression: "ast_string(stringify!(fn_def_generic), try_parse_module,\n \"fn foo(this: T, that: R, _ val: u64) -> bool:\\n false\")" + +--- +Node( + kind: Module( + body: [ + Function(Node( + kind: Function( + pub_: None, + unsafe_: None, + name: Node( + kind: "foo", + span: Span( + start: 3, + end: 6, + ), + ), + generic_params: Node( + kind: [ + Unbounded(Node( + kind: "T", + span: Span( + start: 7, + end: 8, + ), + )), + Bounded( + name: Node( + kind: "R", + span: Span( + start: 10, + end: 11, + ), + ), + bound: Node( + kind: "Event", + span: Span( + start: 13, + end: 18, + ), + ), + ), + ], + span: Span( + start: 6, + end: 19, + ), + ), + args: [ + Node( + kind: Regular(RegularFunctionArg( + label: None, + name: Node( + kind: "this", + span: Span( + start: 20, + end: 24, + ), + ), + typ: Node( + kind: Base( + base: "T", + ), + span: Span( + start: 26, + end: 27, + ), + ), + )), + span: Span( + start: 20, + end: 27, + ), + ), + Node( + kind: Regular(RegularFunctionArg( + label: None, + name: Node( + kind: "that", + span: Span( + start: 29, + end: 33, + ), + ), + typ: Node( + kind: Base( + base: "R", + ), + span: Span( + start: 35, + end: 36, + ), + ), + )), + span: Span( + start: 29, + end: 36, + ), + ), + Node( + kind: Regular(RegularFunctionArg( + label: Some(Node( + kind: "_", + span: Span( + start: 38, + end: 39, + ), + )), + name: Node( + kind: "val", + span: Span( + start: 40, + end: 43, + ), + ), + typ: Node( + kind: Base( + base: "u64", + ), + span: Span( + start: 45, + end: 48, + ), + ), + )), + span: Span( + start: 40, + end: 48, + ), + ), + ], + return_type: Some(Node( + kind: Base( + base: "bool", + ), + span: Span( + start: 53, + end: 57, + ), + )), + body: [ + Node( + kind: Expr( + value: Node( + kind: Bool(false), + span: Span( + start: 60, + end: 65, + ), + ), + ), + span: Span( + start: 60, + end: 65, + ), + ), + ], + ), + span: Span( + start: 0, + end: 65, + ), + )), + ], + ), + span: Span( + start: 0, + end: 65, + ), +) diff --git a/crates/parser/tests/cases/snapshots/cases__parse_ast__fn_def_pub.snap b/crates/parser/tests/cases/snapshots/cases__parse_ast__fn_def_pub.snap index 1110f57e14..aba7965c16 100644 --- a/crates/parser/tests/cases/snapshots/cases__parse_ast__fn_def_pub.snap +++ b/crates/parser/tests/cases/snapshots/cases__parse_ast__fn_def_pub.snap @@ -1,6 +1,6 @@ --- source: crates/parser/tests/cases/parse_ast.rs -expression: "ast_string(stringify!(fn_def_pub), try_parse_module,\n \"pub fn foo21(x: bool, y: address,) -> bool:\\n x\")" +expression: "ast_string(stringify!(fn_def_pub), try_parse_module,\n \"pub fn foo21(x: bool, y: address,) -> bool:\\n x\")" --- Node( @@ -20,6 +20,13 @@ Node( end: 12, ), ), + generic_params: Node( + kind: [], + span: Span( + start: 7, + end: 12, + ), + ), args: [ Node( kind: Regular(RegularFunctionArg( diff --git a/crates/parser/tests/cases/snapshots/cases__parse_ast__fn_def_pub_unsafe.snap b/crates/parser/tests/cases/snapshots/cases__parse_ast__fn_def_pub_unsafe.snap index 4d3486bddf..23de356ec9 100644 --- a/crates/parser/tests/cases/snapshots/cases__parse_ast__fn_def_pub_unsafe.snap +++ b/crates/parser/tests/cases/snapshots/cases__parse_ast__fn_def_pub_unsafe.snap @@ -1,6 +1,6 @@ --- source: crates/parser/tests/cases/parse_ast.rs -expression: "ast_string(stringify!(fn_def_pub_unsafe), try_parse_module,\n \"pub unsafe fn foo21(x: bool, y: address,) -> bool:\\n x\")" +expression: "ast_string(stringify!(fn_def_pub_unsafe), try_parse_module,\n \"pub unsafe fn foo21(x: bool, y: address,) -> bool:\\n x\")" --- Node( @@ -23,6 +23,13 @@ Node( end: 19, ), ), + generic_params: Node( + kind: [], + span: Span( + start: 14, + end: 19, + ), + ), args: [ Node( kind: Regular(RegularFunctionArg( diff --git a/crates/parser/tests/cases/snapshots/cases__parse_ast__fn_def_unsafe.snap b/crates/parser/tests/cases/snapshots/cases__parse_ast__fn_def_unsafe.snap index bad0eae436..c63c32db1e 100644 --- a/crates/parser/tests/cases/snapshots/cases__parse_ast__fn_def_unsafe.snap +++ b/crates/parser/tests/cases/snapshots/cases__parse_ast__fn_def_unsafe.snap @@ -1,6 +1,6 @@ --- source: crates/parser/tests/cases/parse_ast.rs -expression: "ast_string(stringify!(fn_def_unsafe), try_parse_module,\n \"unsafe fn foo21(x: bool, y: address,) -> bool:\\n x\")" +expression: "ast_string(stringify!(fn_def_unsafe), try_parse_module,\n \"unsafe fn foo21(x: bool, y: address,) -> bool:\\n x\")" --- Node( @@ -20,6 +20,13 @@ Node( end: 15, ), ), + generic_params: Node( + kind: [], + span: Span( + start: 10, + end: 15, + ), + ), args: [ Node( kind: Regular(RegularFunctionArg( diff --git a/crates/parser/tests/cases/snapshots/cases__parse_ast__guest_book.snap b/crates/parser/tests/cases/snapshots/cases__parse_ast__guest_book.snap index 1e04087566..34e8edca12 100644 --- a/crates/parser/tests/cases/snapshots/cases__parse_ast__guest_book.snap +++ b/crates/parser/tests/cases/snapshots/cases__parse_ast__guest_book.snap @@ -1,6 +1,6 @@ --- source: crates/parser/tests/cases/parse_ast.rs -expression: "ast_string(stringify!(guest_book), try_parse_module,\n r#\"\ntype BookMsg = Array\n\ncontract GuestBook:\n pub guest_book: Map\n\n event Signed:\n idx book_msg: BookMsg\n\n pub fn sign(self, book_msg: BookMsg):\n self.guest_book[msg.sender] = book_msg\n\n emit Signed(book_msg: book_msg)\n\n pub fn get_msg(self, addr: address) -> BookMsg:\n return self.guest_book[addr]\n\"#)" +expression: "ast_string(stringify!(guest_book), try_parse_module,\n r#\"\ntype BookMsg = Array\n\ncontract GuestBook:\n pub guest_book: Map\n\n event Signed:\n idx book_msg: BookMsg\n\n pub fn sign(self, book_msg: BookMsg):\n self.guest_book[msg.sender] = book_msg\n\n emit Signed(book_msg: book_msg)\n\n pub fn get_msg(self, addr: address) -> BookMsg:\n return self.guest_book[addr]\n\"#)" --- Node( @@ -189,6 +189,13 @@ Node( end: 162, ), ), + generic_params: Node( + kind: [], + span: Span( + start: 158, + end: 162, + ), + ), args: [ Node( kind: Self_, @@ -358,6 +365,13 @@ Node( end: 296, ), ), + generic_params: Node( + kind: [], + span: Span( + start: 289, + end: 296, + ), + ), args: [ Node( kind: Self_, diff --git a/crates/parser/tests/cases/snapshots/cases__parse_ast__module_level_events.snap b/crates/parser/tests/cases/snapshots/cases__parse_ast__module_level_events.snap index 09860e0522..cbad5e032e 100644 --- a/crates/parser/tests/cases/snapshots/cases__parse_ast__module_level_events.snap +++ b/crates/parser/tests/cases/snapshots/cases__parse_ast__module_level_events.snap @@ -1,6 +1,6 @@ --- source: crates/parser/tests/cases/parse_ast.rs -expression: "ast_string(stringify!(module_level_events), try_parse_module,\n r#\"\nuse std::context::Context\n\nevent Transfer:\n idx sender: address\n idx receiver: address\n value: u256\n\ncontract Foo:\n fn transfer(ctx: Context, to: address, value: u256):\n emit Transfer(ctx, sender: msg.sender, receiver: to, value)\n\"#)" +expression: "ast_string(stringify!(module_level_events), try_parse_module,\n r#\"\nuse std::context::Context\n\nevent Transfer:\n idx sender: address\n idx receiver: address\n value: u256\n\ncontract Foo:\n fn transfer(ctx: Context, to: address, value: u256):\n emit Transfer(ctx, sender: msg.sender, receiver: to, value)\n\"#)" --- Node( @@ -163,6 +163,13 @@ Node( end: 140, ), ), + generic_params: Node( + kind: [], + span: Span( + start: 132, + end: 140, + ), + ), args: [ Node( kind: Regular(RegularFunctionArg( diff --git a/crates/parser/tests/cases/snapshots/cases__parse_ast__module_stmts.snap b/crates/parser/tests/cases/snapshots/cases__parse_ast__module_stmts.snap index 9481406c48..a00a095876 100644 --- a/crates/parser/tests/cases/snapshots/cases__parse_ast__module_stmts.snap +++ b/crates/parser/tests/cases/snapshots/cases__parse_ast__module_stmts.snap @@ -1,6 +1,6 @@ --- source: crates/parser/tests/cases/parse_ast.rs -expression: "ast_string(stringify!(module_stmts), try_parse_module,\n r#\"\npragma 0.5.0\n\nuse foo::bar::{\n bing as bong,\n food::*\n}\n\ntype X = Map\n\npub fn double(x: u8) -> u8:\n return x * 2\n\nfn secret() -> u8:\n return 0xBEEF\n\ncontract A:\n pub const x: u256 = 10\n\ncontract B:\n pub x: X\n\"#)" +expression: "ast_string(stringify!(module_stmts), try_parse_module,\n r#\"\npragma 0.5.0\n\nuse foo::bar::{\n bing as bong,\n food::*\n}\n\ntype X = Map\n\npub fn double(x: u8) -> u8:\n return x * 2\n\nfn secret() -> u8:\n return 0xBEEF\n\ncontract A:\n pub const x: u256 = 10\n\ncontract B:\n pub x: X\n\"#)" --- Node( @@ -173,6 +173,13 @@ Node( end: 100, ), ), + generic_params: Node( + kind: [], + span: Span( + start: 94, + end: 100, + ), + ), args: [ Node( kind: Regular(RegularFunctionArg( @@ -265,6 +272,13 @@ Node( end: 142, ), ), + generic_params: Node( + kind: [], + span: Span( + start: 136, + end: 142, + ), + ), args: [], return_type: Some(Node( kind: Base( diff --git a/crates/parser/tests/cases/snapshots/cases__parse_ast__pub_contract_def.snap b/crates/parser/tests/cases/snapshots/cases__parse_ast__pub_contract_def.snap index 5c75d89c19..584a66f1a3 100644 --- a/crates/parser/tests/cases/snapshots/cases__parse_ast__pub_contract_def.snap +++ b/crates/parser/tests/cases/snapshots/cases__parse_ast__pub_contract_def.snap @@ -1,6 +1,6 @@ --- source: crates/parser/tests/cases/parse_ast.rs -expression: "ast_string(stringify!(pub_contract_def), module::parse_module,\n r#\"pub contract Foo:\n pub fn foo() -> u8:\n return 10\n\"#)" +expression: "ast_string(stringify!(pub_contract_def), try_parse_module,\n r#\"pub contract Foo:\n pub fn foo() -> u8:\n return 10\n\"#)" --- Node( @@ -31,6 +31,13 @@ Node( end: 32, ), ), + generic_params: Node( + kind: [], + span: Span( + start: 29, + end: 32, + ), + ), args: [], return_type: Some(Node( kind: Base( diff --git a/crates/parser/tests/cases/snapshots/cases__parse_ast__struct_def.snap b/crates/parser/tests/cases/snapshots/cases__parse_ast__struct_def.snap index 98495e85cd..f2f171ed32 100644 --- a/crates/parser/tests/cases/snapshots/cases__parse_ast__struct_def.snap +++ b/crates/parser/tests/cases/snapshots/cases__parse_ast__struct_def.snap @@ -1,6 +1,6 @@ --- source: crates/parser/tests/cases/parse_ast.rs -expression: "ast_string(stringify!(struct_def), module::parse_module,\n r#\"struct S:\n x: address\n pub y: u8\n z: u8\n pub a: Map\n\n pub fn foo(self) -> u8:\n return self.z + self.y\n unsafe fn bar():\n pass\n\"#)" +expression: "ast_string(stringify!(struct_def), try_parse_module,\n r#\"struct S:\n x: address\n pub y: u8\n z: u8\n pub a: Map\n\n pub fn foo(self) -> u8:\n return self.z + self.y\n unsafe fn bar():\n pass\n\"#)" --- Node( @@ -172,6 +172,13 @@ Node( end: 78, ), ), + generic_params: Node( + kind: [], + span: Span( + start: 75, + end: 78, + ), + ), args: [ Node( kind: Self_, @@ -279,6 +286,13 @@ Node( end: 134, ), ), + generic_params: Node( + kind: [], + span: Span( + start: 131, + end: 134, + ), + ), args: [], return_type: None, body: [ diff --git a/foo.fe b/foo.fe new file mode 100644 index 0000000000..59c3226881 --- /dev/null +++ b/foo.fe @@ -0,0 +1,7 @@ +trait Foo: + pass + +contract Meh: + + pub fn bar(x: T) -> bool: + return true \ No newline at end of file