diff --git a/easy.reid b/easy.reid index 9f32e47..f38801e 100644 --- a/easy.reid +++ b/easy.reid @@ -3,8 +3,9 @@ import std::print; let test = 5; +let simpleAdd = 2 + 2; let arithmetic = 3 + 2 * 5 + 1 * 2; let multiplier = 5 * 2; -let result = arithmetic * multiplier + arithmetic; +let result = arithmetic + multiplier * arithmetic; print(result); \ No newline at end of file diff --git a/src/lexer.rs b/src/lexer.rs index 39e7d05..d9b2a0c 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -93,22 +93,6 @@ pub fn tokenize>(to_tokenize: T) -> Result, Strin Ok(tokens) } -pub struct FullToken { - pub token: Token, - position: Position, -} - -impl Debug for FullToken { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_fmt(format_args!( - "{:?} (Ln {}, Col {})", - self.token, self.position.1, self.position.0 - )) - } -} - -pub type Position = (u32, u32); - #[derive(Debug, Eq, PartialEq, Clone)] pub enum Token { // Values @@ -132,6 +116,32 @@ pub enum Token { Eof, } +impl Token { + pub fn get_token_prec(&self) -> i8 { + match &self { + Token::Plus => 10, + Token::Times => 20, + _ => -1, + } + } +} + +pub struct FullToken { + pub token: Token, + position: Position, +} + +impl Debug for FullToken { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_fmt(format_args!( + "{:?} (Ln {}, Col {})", + self.token, self.position.1, self.position.0 + )) + } +} + +pub type Position = (u32, u32); + pub struct Cursor<'a> { pub position: Position, char_stream: Peekable>, diff --git a/src/parser.rs b/src/parser.rs index 6195296..a4940c1 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -7,24 +7,71 @@ where fn parse(stream: TokenStream) -> Result; } -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum Expression { VariableName(String), ContantI32(i32), + BinopAdd(Box, Box), + BinopMult(Box, Box), } impl Parseable for Expression { fn parse(mut stream: TokenStream) -> Result { - if let Some(token) = stream.next() { - Ok(match &token { - Token::Identifier(v) => Expression::VariableName(v.clone()), - Token::DecimalValue(v) => Expression::ContantI32(v.parse().unwrap()), - _ => Err(())?, - }) + let lhs = parse_primary_expression(&mut stream)?; + parse_binop_rhs(&mut stream, lhs, 0) + } +} + +fn parse_primary_expression(stream: &mut TokenStream) -> Result { + if let Some(token) = stream.next() { + Ok(match &token { + Token::Identifier(v) => Expression::VariableName(v.clone()), + Token::DecimalValue(v) => Expression::ContantI32(v.parse().unwrap()), + _ => Err(())?, + }) + } else { + Err(()) + } +} + +/// This algorithm seems somewhat like magic to me. I understand it if I read +/// carefully, but it is difficult to read every single time. +/// +/// Reference for how the algorithm is formed: +/// https://llvm.org/docs/tutorial/MyFirstLanguageFrontend/LangImpl02.html#binary-expression-parsing +fn parse_binop_rhs( + stream: &mut TokenStream, + mut lhs: Expression, + expr_prec: i8, +) -> Result { + while let Some(token) = stream.peek() { + let curr_token_prec = token.get_token_prec(); + + if curr_token_prec < expr_prec { + break; // Just return lhs } else { - Err(()) + // token has to be an operator + stream.next(); // Eat token + + let mut rhs = parse_primary_expression(stream)?; + if let Some(next_op) = stream.peek() { + let next_prec = next_op.get_token_prec(); + if curr_token_prec < next_prec { + // Operator on the right of rhs has more precedence, turn + // rhs into lhs for new binop + rhs = parse_binop_rhs(stream, rhs, curr_token_prec + 1)?; + } + } + + lhs = match &token { + Token::Plus => Expression::BinopAdd(Box::new(lhs), Box::new(rhs)), + Token::Times => Expression::BinopMult(Box::new(lhs), Box::new(rhs)), + _ => Err(())?, + }; } } + + Ok(lhs) } #[derive(Debug)] diff --git a/src/token_stream.rs b/src/token_stream.rs index dab5a91..ebb84af 100644 --- a/src/token_stream.rs +++ b/src/token_stream.rs @@ -20,7 +20,7 @@ impl<'a, 'b> TokenStream<'a, 'b> { pub fn expect(&mut self, token: Token) -> Result<(), ()> { if let Some(peeked) = self.peek() { - if token == *peeked { + if token == peeked { self.position += 1; Ok(()) } else { @@ -41,11 +41,11 @@ impl<'a, 'b> TokenStream<'a, 'b> { value } - pub fn peek(&mut self) -> Option<&Token> { + pub fn peek(&mut self) -> Option { if self.tokens.len() < self.position { None } else { - Some(&self.tokens[self.position].token) + Some(self.tokens[self.position].token.clone()) } }