Skip to content

Commit

Permalink
Implement parsing of structs
Browse files Browse the repository at this point in the history
  • Loading branch information
cburgdorf committed Jan 25, 2021
1 parent e2807d1 commit babd211
Show file tree
Hide file tree
Showing 9 changed files with 185 additions and 0 deletions.
1 change: 1 addition & 0 deletions compiler/src/yul/mappers/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub fn module(context: &Context, module: &fe::Module) -> Result<YulContracts, Co
return Err(CompileError::static_str("duplicate contract def"));
}
}
fe::ModuleStmt::StructDef { .. } => unimplemented!(),
fe::ModuleStmt::FromImport { .. } => unimplemented!(),
fe::ModuleStmt::SimpleImport { .. } => unimplemented!(),
}
Expand Down
7 changes: 7 additions & 0 deletions compiler/tests/evm_contracts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -909,6 +909,13 @@ fn sized_vals_in_sto() {
});
}

#[test]
fn structs() {
with_executor(&|mut executor| {
let harness = deploy_contract(&mut executor, "structs.fe", "Foo", vec![]);
});
}

#[test]
fn erc20_token() {
with_executor(&|mut executor| {
Expand Down
19 changes: 19 additions & 0 deletions compiler/tests/fixtures/structs.fe
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
struct House:
price: u256
size: u256

type BookMsg = bytes[100]

contract GuestBook:
pub guest_book: map<address, BookMsg>

event Signed:
book_msg: BookMsg

pub def sign(book_msg: BookMsg):
self.guest_book[msg.sender] = book_msg

emit Signed(book_msg=book_msg)

pub def get_msg(addr: address) -> BookMsg:
return self.guest_book[addr].to_mem()
21 changes: 21 additions & 0 deletions parser/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ pub enum ModuleStmt<'a> {
#[serde(borrow)]
body: Vec<Spanned<ContractStmt<'a>>>,
},
StructDef {
name: Spanned<&'a str>,
#[serde(borrow)]
body: Vec<Spanned<StructStmt<'a>>>,
},
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
Expand Down Expand Up @@ -108,12 +113,28 @@ pub enum ContractStmt<'a> {
},
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub enum StructStmt<'a> {
StructField {
//qual: Option<Spanned<ContractFieldQual>>,
#[serde(borrow)]
name: Spanned<&'a str>,
typ: Spanned<TypeDesc<'a>>,
},
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub enum ContractFieldQual {
Const,
Pub,
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub enum StructFieldQual {
Const,
Pub,
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub struct EventField<'a> {
pub qual: Option<Spanned<EventFieldQual>>,
Expand Down
17 changes: 17 additions & 0 deletions parser/src/ast_traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,23 @@ impl TryFrom<&Token<'_>> for Spanned<ContractFieldQual> {
}
}

impl TryFrom<&Token<'_>> for Spanned<StructFieldQual> {
type Error = &'static str;

#[cfg_attr(tarpaulin, rustfmt::skip)]
fn try_from(tok: &Token) -> Result<Self, Self::Error> {
use StructFieldQual::*;

let span = tok.span;

Ok(match tok.string {
"const" => Spanned { node: Const, span },
"pub" => Spanned { node: Pub, span },
_ => return Err("unrecognized string"),
})
}
}

impl TryFrom<&Token<'_>> for Spanned<EventFieldQual> {
type Error = &'static str;

Expand Down
67 changes: 67 additions & 0 deletions parser/src/parsers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,68 @@ pub fn contract_field(input: Cursor) -> ParseResult<Spanned<ContractStmt>> {
))
}

/// Parse a struct definition statement.
pub fn struct_def(input: Cursor) -> ParseResult<Spanned<ModuleStmt>> {
// "struct" name ":" NEWLINE
let (input, contract_kw) = name("struct")(input)?;
let (input, name_tok) = name_token(input)?;
let (input, _) = op(":")(input)?;
let (input, _) = newline_token(input)?;

// INDENT struct_field+ DEDENT
let (input, _) = indent_token(input)?;
let (input, body) = many1(struct_field)(input)?;
let (input, _) = dedent_token(input)?;

let last_stmt = body.last().unwrap();
let span = Span::from_pair(contract_kw, last_stmt);

Ok((
input,
Spanned {
node: StructDef {
name: name_tok.into(),
body,
},
span,
},
))
}

/// Parse a struct field definition.
pub fn struct_field(input: Cursor) -> ParseResult<Spanned<StructStmt>> {
let (input, (qual, name_tok)) = alt((
// Look for a qualifier and field name first...
map(pair(struct_field_qual, name_token), |res| {
let (qual, tok) = res;
(Some(qual), tok)
}),
// ...then fall back to just a field name
map(name_token, |tok| (None, tok)),
))(input)?;

let (input, _) = op(":")(input)?;
let (input, typ) = type_desc(input)?;
let (input, _) = newline_token(input)?;

let span = match &qual {
Some(spanned) => Span::from_pair(spanned, &typ),
None => Span::from_pair(name_tok, &typ),
};

Ok((
input,
Spanned {
node: StructStmt::StructField {
//qual,
name: name_tok.into(),
typ,
},
span,
},
))
}

/// Parse an event definition statement.
pub fn event_def(input: Cursor) -> ParseResult<Spanned<ContractStmt>> {
// "event" name ":" NEWLINE
Expand Down Expand Up @@ -759,6 +821,11 @@ pub fn contract_field_qual(input: Cursor) -> ParseResult<Spanned<ContractFieldQu
try_from_tok(alt((name("const"), name("pub"))))(input)
}

/// Parse a struct field qualifier keyword e.g. "const".
pub fn struct_field_qual(input: Cursor) -> ParseResult<Spanned<StructFieldQual>> {
try_from_tok(name("pub"))(input)
}

/// Parse an event field qualifier keyword i.e. "idx".
pub fn event_field_qual(input: Cursor) -> ParseResult<Spanned<EventFieldQual>> {
try_from_tok(name("idx"))(input)
Expand Down
46 changes: 46 additions & 0 deletions parser/tests/fixtures/parsers/struct_def.ron
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
struct Foo:
x: address
---
[
Spanned(
node: StructDef(
name: Spanned(
node: "Foo",
span: Span(
start: 7,
end: 10,
),
),
body: [
Spanned(
node: StructField(
name: Spanned(
node: "x",
span: Span(
start: 16,
end: 17,
),
),
typ: Spanned(
node: Base(
base: "address",
),
span: Span(
start: 19,
end: 26,
),
),
),
span: Span(
start: 16,
end: 26,
),
),
],
),
span: Span(
start: 0,
end: 26,
),
),
]
6 changes: 6 additions & 0 deletions parser/tests/test_parsers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,12 @@ parser_fixture_tests! {
write_contract_def,
"fixtures/parsers/contract_def.ron",
),
(
repeat(struct_def),
test_struct_def,
write_struct_def,
"fixtures/parsers/struct_def.ron",
),
(
repeat(contract_stmt),
test_contract_stmt,
Expand Down
1 change: 1 addition & 0 deletions semantics/src/traversal/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub fn module(context: Shared<Context>, module: &fe::Module) -> Result<(), Seman
fe::ModuleStmt::ContractDef { .. } => {
contracts::contract_def(Rc::clone(&scope), Rc::clone(&context), stmt)?
}
fe::ModuleStmt::StructDef { .. } => unimplemented!(),
fe::ModuleStmt::FromImport { .. } => unimplemented!(),
fe::ModuleStmt::SimpleImport { .. } => unimplemented!(),
}
Expand Down

0 comments on commit babd211

Please sign in to comment.