Skip to content

msg syntax #1066

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions crates/hir/src/lower/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ impl<'db> ItemKind<'db> {
ast::ItemKind::Enum(enum_) => {
Enum::lower_ast(ctxt, enum_);
}
ast::ItemKind::Msg(_) => {
todo!() // xxx
}
ast::ItemKind::TypeAlias(alias) => {
TypeAlias::lower_ast(ctxt, alias);
}
Expand Down
98 changes: 98 additions & 0 deletions crates/parser/src/ast/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ impl Item {
.or_else(|| support::child(self.syntax()).map(ItemKind::Func))
.or_else(|| support::child(self.syntax()).map(ItemKind::Struct))
.or_else(|| support::child(self.syntax()).map(ItemKind::Contract))
.or_else(|| support::child(self.syntax()).map(ItemKind::Msg))
.or_else(|| support::child(self.syntax()).map(ItemKind::Enum))
.or_else(|| support::child(self.syntax()).map(ItemKind::TypeAlias))
.or_else(|| support::child(self.syntax()).map(ItemKind::Impl))
Expand Down Expand Up @@ -334,6 +335,7 @@ ast_node! {
pub struct RecordFieldDef,
SK::RecordFieldDef,
}

impl super::AttrListOwner for RecordFieldDef {}
impl RecordFieldDef {
/// Returns the pub keyword if exists.
Expand Down Expand Up @@ -442,12 +444,69 @@ pub trait ItemModifierOwner: AstNode<Language = FeLang> {
}
}

ast_node! {
/// `msg Erc20Msg { ... }`
pub struct Msg,
SK::Msg,
}

impl super::AttrListOwner for Msg {}
impl super::ItemModifierOwner for Msg {}
impl Msg {
/// Returns the name of the message interface.
pub fn name(&self) -> Option<SyntaxToken> {
support::token(self.syntax(), SK::Ident)
}

/// Returns the message variants.
pub fn variants(&self) -> Option<MsgVariantList> {
support::child(self.syntax())
}
}

ast_node! {
/// A list of message variants.
pub struct MsgVariantList,
SK::MsgVariantList,
IntoIterator<Item=MsgVariant>
}

ast_node! {
/// A single message variant.
/// `Transfer { to: Address, amount: u256 } -> bool`
pub struct MsgVariant,
SK::MsgVariant,
}
impl super::AttrListOwner for MsgVariant {}
impl MsgVariant {
pub fn name(&self) -> Option<SyntaxToken> {
support::token(self.syntax(), SK::Ident)
}

pub fn params(&self) -> Option<MsgVariantParams> {
support::child(self.syntax())
}

pub fn ret_ty(&self) -> Option<super::Type> {
support::child(self.syntax())
}
}

ast_node! {
/// Message variant parameters.
/// `{ to: Address, amount: u256 }`
pub struct MsgVariantParams,
SK::MsgVariantParams,
IntoIterator<Item=RecordFieldDef>
}

#[derive(Debug, Clone, PartialEq, Eq, Hash, derive_more::From, derive_more::TryInto)]
pub enum ItemKind {
Mod(Mod),
Func(Func),
Struct(Struct),
Contract(Contract),
Msg(Msg),
Enum(Enum),
TypeAlias(TypeAlias),
Impl(Impl),
Expand Down Expand Up @@ -804,4 +863,43 @@ mod tests {
}
assert_eq!(e.extern_block().unwrap().iter().count(), 2);
}
#[test]
#[wasm_bindgen_test]
fn msg_() {
let source = r#"
msg Erc20Msg {
Transfer { to: Address, amount: u256 } -> bool,
Balance { addr: Address } -> u256,
TotalSupply -> u256,
}
"#;
let m: Msg = parse_item(source);
assert_eq!(m.name().unwrap().text(), "Erc20Msg");

let mut count = 0;
for variant in m.variants().unwrap() {
match count {
0 => {
assert_eq!(variant.name().unwrap().text(), "Transfer");
assert!(variant.params().is_some());
assert!(variant.ret_ty().is_some());
assert_eq!(variant.params().unwrap().into_iter().count(), 2);
}
1 => {
assert_eq!(variant.name().unwrap().text(), "Balance");
assert!(variant.params().is_some());
assert!(variant.ret_ty().is_some());
assert_eq!(variant.params().unwrap().into_iter().count(), 1);
}
2 => {
assert_eq!(variant.name().unwrap().text(), "TotalSupply");
assert!(variant.params().is_none());
assert!(variant.ret_ty().is_some());
}
_ => panic!("unexpected variant"),
}
count += 1;
}
assert_eq!(count, 3);
}
}
80 changes: 78 additions & 2 deletions crates/parser/src/parser/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use super::{
func::FuncDefScope,
param::{parse_generic_params_opt, parse_where_clause_opt, TraitRefScope},
parse_list,
struct_::RecordFieldDefListScope,
struct_::{RecordFieldDefListScope, RecordFieldDefScope},
token_stream::{LexicalToken, TokenStream},
type_::{parse_type, TupleTypeScope},
use_tree::UseTreeScope,
Expand Down Expand Up @@ -124,7 +124,7 @@ impl super::Parse for ItemScope {

parser.expect(
&[
ModKw, FnKw, StructKw, ContractKw, EnumKw, TraitKw, ImplKw, UseKw, ConstKw,
ModKw, FnKw, StructKw, ContractKw, MsgKw, EnumKw, TraitKw, ImplKw, UseKw, ConstKw,
ExternKw, TypeKw,
],
Some(ExpectedKind::Syntax(SyntaxKind::Item)),
Expand All @@ -135,6 +135,7 @@ impl super::Parse for ItemScope {
Some(FnKw) => parser.parse_cp(FuncScope::default(), checkpoint),
Some(StructKw) => parser.parse_cp(super::struct_::StructScope::default(), checkpoint),
Some(ContractKw) => parser.parse_cp(ContractScope::default(), checkpoint),
Some(MsgKw) => parser.parse_cp(MsgScope::default(), checkpoint),
Some(EnumKw) => parser.parse_cp(EnumScope::default(), checkpoint),
Some(TraitKw) => parser.parse_cp(TraitScope::default(), checkpoint),
Some(ImplKw) => parser.parse_cp(ImplScope::default(), checkpoint),
Expand Down Expand Up @@ -267,6 +268,81 @@ impl super::Parse for ContractScope {
Ok(())
}
}
define_scope! { MsgScope, Msg }
impl super::Parse for MsgScope {
type Error = Recovery<ErrProof>;

fn parse<S: TokenStream>(&mut self, parser: &mut Parser<S>) -> Result<(), Self::Error> {
parser.bump_expected(SyntaxKind::MsgKw);

parser.set_scope_recovery_stack(&[SyntaxKind::Ident, SyntaxKind::LBrace]);

if parser.find_and_pop(SyntaxKind::Ident, ExpectedKind::Name(SyntaxKind::Msg))? {
parser.bump();
}
if parser.find_and_pop(SyntaxKind::LBrace, ExpectedKind::Body(SyntaxKind::Msg))? {
parser.parse(MsgVariantListScope::default())?;
}
Ok(())
}
}

define_scope! { MsgVariantListScope, MsgVariantList, (Comma, RBrace) }
impl super::Parse for MsgVariantListScope {
type Error = Recovery<ErrProof>;

fn parse<S: TokenStream>(&mut self, parser: &mut Parser<S>) -> Result<(), Self::Error> {
parse_list(
parser,
true,
SyntaxKind::MsgVariantList,
(SyntaxKind::LBrace, SyntaxKind::RBrace),
|parser| parser.parse(MsgVariantScope::default()),
)
}
}

define_scope! { MsgVariantScope, MsgVariant }
impl super::Parse for MsgVariantScope {
type Error = Recovery<ErrProof>;

fn parse<S: TokenStream>(&mut self, parser: &mut Parser<S>) -> Result<(), Self::Error> {
parser.set_newline_as_trivia(false);

// Parse attribute list
parse_attr_list(parser)?;

// Parse variant name
parser.bump_or_recover(SyntaxKind::Ident, "expected identifier for message variant")?;

// Parse optional parameters
if parser.current_kind() == Some(SyntaxKind::LBrace) {
parser.parse(MsgVariantParamsScope::default())?;
}

// Parse optional return type
if parser.bump_if(SyntaxKind::Arrow) {
parse_type(parser, None)?;
}

Ok(())
}
}

define_scope! { MsgVariantParamsScope, MsgVariantParams, (Comma, RBrace) }
impl super::Parse for MsgVariantParamsScope {
type Error = Recovery<ErrProof>;

fn parse<S: TokenStream>(&mut self, parser: &mut Parser<S>) -> Result<(), Self::Error> {
parse_list(
parser,
true,
SyntaxKind::MsgVariantParams,
(SyntaxKind::LBrace, SyntaxKind::RBrace),
|parser| parser.parse(RecordFieldDefScope::default()),
)
}
}

define_scope! { EnumScope, Enum }
impl super::Parse for EnumScope {
Expand Down
2 changes: 1 addition & 1 deletion crates/parser/src/parser/struct_.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ impl super::Parse for RecordFieldDefListScope {
}
}

define_scope! { RecordFieldDefScope, RecordFieldDef }
define_scope! { pub(crate) RecordFieldDefScope, RecordFieldDef }
impl super::Parse for RecordFieldDefScope {
type Error = Recovery<ErrProof>;

Expand Down
17 changes: 17 additions & 0 deletions crates/parser/src/syntax_kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,9 @@ pub enum SyntaxKind {
/// `contract`
#[token("contract")]
ContractKw,
/// `msg`
#[token("msg")]
MsgKw,
/// `fn`
#[token("fn")]
FnKw,
Expand Down Expand Up @@ -369,6 +372,8 @@ pub enum SyntaxKind {
Const,
/// `use foo::{Foo as Foo1, bar::Baz}`
Use,
/// `msg Erc20Msg { ... }`
Msg,
/// `foo::{Foo as Foo1, bar::Baz}`
UseTree,
/// `{Foo as Foo1, bar::Baz}`
Expand Down Expand Up @@ -459,6 +464,12 @@ pub enum SyntaxKind {
WhereClause,
/// `Option<T>: Trait1 + Trait2`
WherePredicate,
/// `Transfer { to: Address, amount: u256 } -> bool`
MsgVariant,
/// `{ to: Address, amount: u256 }`
MsgVariantParams,
/// `TotalSupply, Balance { addr: Address }`
MsgVariantList,

/// Root node of the input source.
Root,
Expand Down Expand Up @@ -512,6 +523,7 @@ impl SyntaxKind {
| SyntaxKind::FnKw
| SyntaxKind::StructKw
| SyntaxKind::ContractKw
| SyntaxKind::MsgKw
| SyntaxKind::EnumKw
| SyntaxKind::TypeKw
| SyntaxKind::ImplKw
Expand Down Expand Up @@ -568,6 +580,7 @@ impl SyntaxKind {
SyntaxKind::BreakKw => "`break`",
SyntaxKind::ContinueKw => "`continue`",
SyntaxKind::ContractKw => "`contract`",
SyntaxKind::MsgKw => "`msg`",
SyntaxKind::FnKw => "`fn`",
SyntaxKind::ModKw => "`mod`",
SyntaxKind::ConstKw => "`const`",
Expand Down Expand Up @@ -662,6 +675,10 @@ impl SyntaxKind {
SyntaxKind::Func => "function definition",
SyntaxKind::Struct => "struct definition",
SyntaxKind::Contract => "contract definition",
SyntaxKind::Msg => "message definition",
SyntaxKind::MsgVariant => "message variant",
SyntaxKind::MsgVariantParams => "message variant parameters",
SyntaxKind::MsgVariantList => "message variants",
SyntaxKind::Enum => "enum definition",
SyntaxKind::TypeAlias => "type alias",
SyntaxKind::Impl => "`impl` block",
Expand Down
20 changes: 20 additions & 0 deletions crates/parser/test_files/syntax_node/items/msg.fe
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
msg Erc20Msg {
// Transfers `amount` tokens to `to`, returns success
Transfer { to: Address, amount: u256 } -> bool,
// Returns the balance of `addr`
Balance { addr: Address } -> u256,
// Returns the total token supply
TotalSupply -> u256,
// Returns the remaining allowance that `spender` can spend from `owner`
Allowance { owner: Address, spender: Address } -> u256,
// Approves `spender` to spend `amount` tokens, returns success
Approve { spender: Address, amount: u256 } -> bool,
// Transfers `amount` tokens from `from` to `to` using allowance, returns success
TransferFrom { from: Address, to: Address, amount: u256 } -> bool,
// Optional: Returns the token's name
Name -> string,
// Optional: Returns the token's symbol
Symbol -> string,
// Optional: Returns the number of decimals
Decimals -> u8
}
Loading