From bc3a1ad88feadc8114be086c27cfddc3bfa993cb Mon Sep 17 00:00:00 2001 From: Ross Andrews Date: Sat, 8 Jul 2023 20:54:23 -0500 Subject: [PATCH] Completed the parser --- forge_core/src/ast.rs | 39 +++++--- forge_core/src/forge.pest | 2 +- forge_core/src/forge_parser.rs | 176 ++++++++++++++++++++++++++++----- 3 files changed, 177 insertions(+), 40 deletions(-) diff --git a/forge_core/src/ast.rs b/forge_core/src/ast.rs index ba71fc3..011e1cf 100644 --- a/forge_core/src/ast.rs +++ b/forge_core/src/ast.rs @@ -1,4 +1,7 @@ -#[derive(Eq, PartialEq, Clone, Debug)] +#[derive(PartialEq, Clone, Debug)] +pub struct Program(pub Vec); + +#[derive(PartialEq, Clone, Debug)] pub enum Declaration { Function(Function), Global(Global), @@ -39,13 +42,17 @@ pub struct Const { pub string: Option, } -#[derive(Eq, PartialEq, Clone, Debug)] +#[derive(PartialEq, Clone, Debug)] +pub struct Block(pub Vec); + +#[derive(PartialEq, Clone, Debug)] pub struct Function { pub name: String, pub org: Option, pub typename: Option, pub inline: bool, pub args: Vec, + pub body: Block, } #[derive(Eq, PartialEq, Clone, Debug)] @@ -54,11 +61,6 @@ pub struct Argname { pub typename: Option, } -#[derive(PartialEq, Clone, Debug)] -pub struct Block { - pub statements: Vec, -} - #[derive(PartialEq, Clone, Debug)] pub enum Statement { Return(Return), @@ -105,14 +107,25 @@ pub struct VarDecl { pub initial: Option, } -#[derive(Eq, PartialEq, Clone, Debug)] -pub struct Conditional {} +#[derive(PartialEq, Clone, Debug)] +pub struct Conditional { + pub condition: Node, + pub body: Block, + pub alternative: Option, +} -#[derive(Eq, PartialEq, Clone, Debug)] -pub struct WhileLoop {} +#[derive(PartialEq, Clone, Debug)] +pub struct WhileLoop { + pub condition: Node, + pub body: Block, +} -#[derive(Eq, PartialEq, Clone, Debug)] -pub struct RepeatLoop {} +#[derive(PartialEq, Clone, Debug)] +pub struct RepeatLoop { + pub count: Node, + pub name: Option, + pub body: Block, +} /// One of the five arithmetical operators #[derive(Debug, PartialEq, Copy, Clone)] diff --git a/forge_core/src/forge.pest b/forge_core/src/forge.pest index ffe132e..0ab1eb4 100644 --- a/forge_core/src/forge.pest +++ b/forge_core/src/forge.pest @@ -59,7 +59,7 @@ program = { (COMMENT | WHITESPACE)? ~ declaration* ~ EOI } return_stmt = { "return" ~ expr? } conditional = { "if" ~ "(" ~ expr ~ ")" ~ block ~ ("else" ~ block)? } while_loop = { "while" ~ "(" ~ expr ~ ")" ~ block } -repeat_loop = { "repeat" ~ "(" ~ expr ~ ")" ~ name ~ block } +repeat_loop = { "repeat" ~ "(" ~ expr ~ ")" ~ name? ~ block } var_decl = { "var" ~ name ~ varinfo ~ ("=" ~ expr)? } global = { "global" ~ name ~ varinfo ~ ";" } typename = { ":" ~ name } diff --git a/forge_core/src/forge_parser.rs b/forge_core/src/forge_parser.rs index f25a177..5f5f76f 100644 --- a/forge_core/src/forge_parser.rs +++ b/forge_core/src/forge_parser.rs @@ -128,6 +128,7 @@ impl Parseable for T { impl AstNode for Declaration { const RULE: Rule = Rule::declaration; fn from_pair(pair: Pair) -> Self { + let pair = pair.first(); match pair.as_rule() { Rule::function => Self::Function(Function::from_pair(pair)), Rule::global => Self::Global(Global::from_pair(pair)), @@ -259,12 +260,15 @@ impl AstNode for Function { .map(Argname::from_pair) .collect(); + let body = Block::from_pair(inner.next().unwrap()); + Self { name, org, typename, inline, args, + body, } } } @@ -374,10 +378,28 @@ impl AstNode for VarDecl { /////////////////////////////////////////////////////////////////////////////////////////// +impl AstNode for Block { + const RULE: Rule = Rule::block; + + fn from_pair(pair: Pair) -> Self { + Self(pair.into_inner().map(Statement::from_pair).collect()) + } +} + +/////////////////////////////////////////////////////////////////////////////////////////// + impl AstNode for Conditional { const RULE: Rule = Rule::conditional; fn from_pair(pair: Pair) -> Self { - todo!() + let mut inner = pair.into_inner(); + let condition = Node::from_pair(inner.next().unwrap()); + let body = Block::from_pair(inner.next().unwrap()); + let alternative = inner.next().map(Block::from_pair); + Self { + condition, + body, + alternative, + } } } @@ -386,7 +408,11 @@ impl AstNode for Conditional { impl AstNode for WhileLoop { const RULE: Rule = Rule::while_loop; fn from_pair(pair: Pair) -> Self { - todo!() + let mut inner = pair.into_inner(); + Self { + condition: Node::from_pair(inner.next().unwrap()), + body: Block::from_pair(inner.next().unwrap()), + } } } @@ -395,7 +421,13 @@ impl AstNode for WhileLoop { impl AstNode for RepeatLoop { const RULE: Rule = Rule::repeat_loop; fn from_pair(pair: Pair) -> Self { - todo!() + let mut inner = pair.into_inner().peekable(); + let count = Node::from_pair(inner.next().unwrap()); + let name = inner + .next_if_rule(Rule::name) + .map(|p| String::from(p.as_str())); + let body = Block::from_pair(inner.next().unwrap()); + Self { count, name, body } } } @@ -482,6 +514,22 @@ impl AstNode for ArrayRef { /////////////////////////////////////////////////////////////////////////////////////////// +impl AstNode for Program { + const RULE: Rule = Rule::program; + fn from_pair(pair: Pair) -> Self { + // Program captures EOI, to make sure that it's parsing the entire stream. We need to + // ignore that though: + Self( + pair.into_inner() + .filter(|p| p.as_rule() != Rule::EOI) + .map(Declaration::from_pair) + .collect(), + ) + } +} + +/////////////////////////////////////////////////////////////////////////////////////////// + #[cfg(test)] mod test { use super::*; @@ -614,6 +662,7 @@ mod test { org: None, typename: None, args: vec![], + body: Block(vec![]), }) ); assert_eq!( @@ -633,6 +682,7 @@ mod test { typename: None } ], + body: Block(vec![]), }) ); assert_eq!( @@ -652,34 +702,27 @@ mod test { typename: None } ], + body: Block(vec![]), }) ); + + let func = Function { + name: "foo".into(), + inline: true, + org: Some(0x400), + typename: None, + args: vec![Argname { + name: "a".into(), + typename: None, + }], + body: Block(vec![]), + }; + assert_eq!( Function::parse("fn foo(a) {}"), - Ok(Function { - name: "foo".into(), - inline: true, - org: Some(0x400), - typename: None, - args: vec![Argname { - name: "a".into(), - typename: None - },], - }) - ); - assert_eq!( - Function::parse("fn foo(a) {}"), - Ok(Function { - name: "foo".into(), - inline: true, - org: Some(0x400), - typename: None, - args: vec![Argname { - name: "a".into(), - typename: None - },], - }) + Ok(func.clone()) ); + assert_eq!(Function::parse("fn foo(a) {}"), Ok(func)); } #[test] @@ -861,4 +904,85 @@ mod test { }) ); } + + #[test] + fn parse_block() { + assert_eq!( + Block::parse("{ foo(); bar(); }"), + Ok(Block(vec![ + Statement::Call(Call { + name: "foo".into(), + args: vec![] + }), + Statement::Call(Call { + name: "bar".into(), + args: vec![] + }), + ])) + ); + } + + #[test] + fn parse_conditional() { + assert_eq!( + Statement::parse("if(cond) { foo(); }"), + Ok(Statement::Conditional(Conditional { + condition: Node::parse("cond").unwrap(), + body: Block::parse("{ foo(); }").unwrap(), + alternative: None + })) + ); + + assert_eq!( + Statement::parse("if(cond) { foo(); } else { bar(); }"), + Ok(Statement::Conditional(Conditional { + condition: Node::parse("cond").unwrap(), + body: Block::parse("{ foo(); }").unwrap(), + alternative: Some(Block::parse("{ bar(); }").unwrap()), + })) + ); + } + + #[test] + fn parse_while_loops() { + assert_eq!( + Statement::parse("while(cond) { foo(); }"), + Ok(Statement::WhileLoop(WhileLoop { + condition: Node::parse("cond").unwrap(), + body: Block::parse("{ foo(); }").unwrap(), + })) + ); + } + + #[test] + fn parse_repeat_loops() { + assert_eq!( + Statement::parse("repeat(10) x { foo(x); }"), + Ok(Statement::RepeatLoop(RepeatLoop { + count: Node::Number(10), + name: Some("x".into()), + body: Block::parse("{ foo(x); }").unwrap(), + })) + ); + + assert_eq!( + Statement::parse("repeat(10) { foo(); }"), + Ok(Statement::RepeatLoop(RepeatLoop { + count: Node::Number(10), + name: None, + body: Block::parse("{ foo(); }").unwrap(), + })) + ); + } + + #[test] + fn parse_program() { + assert_eq!( + Program::parse("global foo; struct Point { x, y }"), + Ok(Program(vec![ + Declaration::parse("global foo;").unwrap(), + Declaration::parse("struct Point { x, y }").unwrap(), + ])) + ) + } }