From b4e9ae520d3e68579f1c6aa04f937a20262d61b0 Mon Sep 17 00:00:00 2001 From: Garrit Franke Date: Sat, 20 Feb 2021 21:09:54 +0100 Subject: [PATCH] feat: parser implementation of match --- src/generator/c.rs | 1 + src/generator/js.rs | 1 + src/parser/node_type.rs | 3 +++ src/parser/parser.rs | 6 ++++++ src/parser/rules.rs | 42 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 53 insertions(+) diff --git a/src/generator/c.rs b/src/generator/c.rs index 02da8ea..ad080e8 100644 --- a/src/generator/c.rs +++ b/src/generator/c.rs @@ -112,6 +112,7 @@ fn generate_statement(statement: Statement) -> String { Statement::For(_ident, _expr, _body) => todo!(), Statement::Continue => todo!(), Statement::Break => todo!(), + Statement::Match(_, _) => todo!(), }; format!("{}\n", state) diff --git a/src/generator/js.rs b/src/generator/js.rs index 6f174bf..d777344 100644 --- a/src/generator/js.rs +++ b/src/generator/js.rs @@ -103,6 +103,7 @@ fn generate_statement(statement: Statement) -> String { Statement::For(ident, expr, body) => generate_for_loop(ident, expr, *body), Statement::Continue => generate_continue(), Statement::Break => generate_break(), + Statement::Match(_, _) => todo!(), }; format!("{};\n", state) diff --git a/src/parser/node_type.rs b/src/parser/node_type.rs index bc0940f..e680e13 100644 --- a/src/parser/node_type.rs +++ b/src/parser/node_type.rs @@ -20,6 +20,8 @@ use std::collections::HashMap; /// Table that contains all symbol and its types pub type SymbolTable = HashMap>; +pub type MatchArm = (Expression, Statement); + #[derive(Debug)] pub struct Program { pub func: Vec, @@ -97,6 +99,7 @@ pub enum Statement { If(Expression, Box, Option>), While(Expression, Box), For(Variable, Expression, Box), + Match(Expression, Vec), Break, Continue, Exp(Expression), diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 58e5751..9184448 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +use crate::lexer::Position; use crate::lexer::Keyword; use crate::lexer::{Token, TokenKind}; use crate::parser::infer::infer; @@ -126,6 +127,11 @@ impl Parser { } } + pub(super) fn make_error_msg(&mut self, pos: Position, msg: String) -> String { + let pos_string = format!("{}:{}", pos.line, pos.offset); + format!("ERROR: {}\nAt {}", msg, pos_string) + } + pub(super) fn prev(&mut self) -> Option { self.prev.clone() } diff --git a/src/parser/rules.rs b/src/parser/rules.rs index 4334764..3086931 100644 --- a/src/parser/rules.rs +++ b/src/parser/rules.rs @@ -165,6 +165,7 @@ impl Parser { TokenKind::Keyword(Keyword::Break) => self.parse_break(), TokenKind::Keyword(Keyword::Continue) => self.parse_continue(), TokenKind::Keyword(Keyword::For) => self.parse_for_loop(), + TokenKind::Keyword(Keyword::Match) => self.parse_match_statement(), TokenKind::Identifier(_) => { let ident = self.match_identifier()?; let expr = if self.peek_token(TokenKind::Dot).is_ok() { @@ -457,6 +458,47 @@ impl Parser { )) } + fn parse_match_statement(&mut self) -> Result { + self.match_keyword(Keyword::Match)?; + let subject = self.parse_expression()?; + self.match_token(TokenKind::CurlyBracesOpen)?; + let mut arms: Vec = Vec::new(); + + // Used to mitigate multiple default cases were defined + let mut has_default = false; + loop { + let next = self.peek()?; + match next.kind { + TokenKind::Literal(_) | TokenKind::Identifier(_) => { + arms.push(self.parse_match_arm()?) + } + TokenKind::Keyword(Keyword::Default) => { + if has_default { + return Err(self.make_error_msg( + next.pos, + "Multiple defaults are not allowed".to_string(), + )); + } + has_default = true; + arms.push(self.parse_match_arm()?); + } + TokenKind::CurlyBracesClose => break, + _ => return Err(self.make_error_msg(next.pos, "Illegal token".to_string())) + } + } + self.match_token(TokenKind::CurlyBracesClose)?; + Ok(Statement::Match(subject, arms)) + } + + fn parse_match_arm(&mut self) -> Result { + let expr = self.parse_expression()?; + self.match_token(TokenKind::ArrowRight)?; + let statement = self.parse_statement()?; + + Ok((expr, statement)) + + } + fn parse_conditional_statement(&mut self) -> Result { self.match_keyword(Keyword::If)?; let condition = self.parse_expression()?;