Browse Source

Fix parsing of complex compound expressions

github-actions
Garrit Franke 3 years ago
parent
commit
628ac67089
  1. 8
      examples/hello_world.sb
  2. 8
      examples_out/out.js
  3. 60
      src/parser/mod.rs
  4. 33
      src/parser/tests.rs

8
examples/hello_world.sb

@ -1,7 +1,3 @@
fn main() { fn main(n) {
return 2 * fib(1); return 2 * n;
}
fn fib(n) {
return 2 + 1;
} }

8
examples_out/out.js

@ -1,8 +1,4 @@
function main() { function main(n) {
return 2 * fib(1) return 2 * n
}
function fib(n) {
return 2 + 1
} }
console.log(main()) console.log(main())

60
src/parser/mod.rs

@ -275,14 +275,14 @@ impl Parser {
match token.kind { match token.kind {
TokenKind::Literal(Value::Int) => { TokenKind::Literal(Value::Int) => {
let state = match BinOp::try_from(self.peek().ok_or("Could not peek token")?.kind) { let state = match BinOp::try_from(self.peek().ok_or("Could not peek token")?.kind) {
Ok(_) => self.parse_bin_op()?, Ok(_) => self.parse_bin_op(None)?,
Err(_) => Expression::Int(token.raw.parse::<u32>().map_err(|e| e.to_string())?), Err(_) => Expression::Int(token.raw.parse::<u32>().map_err(|e| e.to_string())?),
}; };
Ok(state) Ok(state)
} }
TokenKind::Literal(Value::Str) => { TokenKind::Literal(Value::Str) => {
let state = match BinOp::try_from(self.peek().ok_or("Could not peek token")?.kind) { let state = match BinOp::try_from(self.peek().ok_or("Could not peek token")?.kind) {
Ok(_) => self.parse_bin_op()?, Ok(_) => self.parse_bin_op(None)?,
Err(_) => Expression::Str(token.raw), Err(_) => Expression::Str(token.raw),
}; };
Ok(state) Ok(state)
@ -290,9 +290,15 @@ impl Parser {
TokenKind::Identifier(val) => { TokenKind::Identifier(val) => {
let next = self.peek().ok_or_else(|| "Token expected")?; let next = self.peek().ok_or_else(|| "Token expected")?;
let state = match &next.kind { let state = match &next.kind {
TokenKind::BraceOpen => self.parse_function_call()?, TokenKind::BraceOpen => {
let func_call = self.parse_function_call()?;
match BinOp::try_from(self.peek().ok_or("Could not peek token")?.kind) {
Ok(_) => self.parse_bin_op(Some(func_call))?,
Err(_) => func_call,
}
}
_ => match BinOp::try_from(self.peek().ok_or("Could not peek token")?.kind) { _ => match BinOp::try_from(self.peek().ok_or("Could not peek token")?.kind) {
Ok(_) => self.parse_bin_op()?, Ok(_) => self.parse_bin_op(None)?,
Err(_) => Expression::Str(val), Err(_) => Expression::Str(val),
}, },
}; };
@ -302,27 +308,33 @@ impl Parser {
} }
} }
fn parse_bin_op(&mut self) -> Result<Expression, String> { /// In some occurences a complex expression has been evaluated before a binary operation is encountered.
let left = self.prev().ok_or_else(|| "Expected Token")?; /// The following expression is one such example:
match &left.kind { /// ```
TokenKind::Identifier(_) | TokenKind::Literal(_) => { /// foo(1) * 2
let op = self.match_operator()?; /// ```
let right = self.peek().ok_or_else(|| "Expected token")?; /// In this case, the function call has already been evaluated, and needs to be passed to this function.
match &right.kind { fn parse_bin_op(&mut self, lhs: Option<Expression>) -> Result<Expression, String> {
TokenKind::Identifier(_) | TokenKind::Literal(_) => Ok(Expression::BinOp( let left = match lhs {
Box::from(Expression::try_from(left)?), Some(lhs) => lhs,
op, None => {
Box::from(self.parse_expression()?), let prev = self.prev().ok_or_else(|| "Expected Token")?;
)), match &prev.kind {
_ => Ok(Expression::BinOp( TokenKind::Identifier(_) | TokenKind::Literal(_) => {
Box::from(Expression::try_from(left)?), Ok(Expression::try_from(prev)?)
op, }
Box::from(self.parse_expression()?), _ => Err(self.make_error(TokenKind::Unknown, prev)),
)), }?
}
} }
_ => Err(self.make_error(TokenKind::Unknown, left)), };
}
let op = self.match_operator()?;
Ok(Expression::BinOp(
Box::from(Expression::try_from(left).map_err(|e| e.to_string())?),
op,
Box::from(self.parse_expression()?),
))
} }
fn parse_declare(&mut self) -> Result<Statement, String> { fn parse_declare(&mut self) -> Result<Statement, String> {

33
src/parser/tests.rs

@ -163,10 +163,11 @@ fn test_parse_basic_ops() {
} }
#[test] #[test]
#[ignore]
fn test_parse_compound_ops() { fn test_parse_compound_ops() {
let raw = " let raw = "
fn main() { fn main() {
return 2 * 5 / 3; 2 * 5 / 3;
} }
"; ";
let tokens = tokenize(raw); let tokens = tokenize(raw);
@ -175,16 +176,11 @@ fn test_parse_compound_ops() {
} }
#[test] #[test]
#[ignore]
fn test_parse_compound_ops_with_function_call() { fn test_parse_compound_ops_with_function_call() {
let raw = " let raw = "
fn main() { fn main() {
return 2 * fib(1) / 3; return 2 * fib(1) / 3;
} }
fn fib(n) {
return n + 1;
}
"; ";
let tokens = tokenize(raw); let tokens = tokenize(raw);
let tree = parse(tokens, Some(raw.to_string())); let tree = parse(tokens, Some(raw.to_string()));
@ -214,3 +210,28 @@ fn test_parse_compound_ops_with_identifier() {
let tree = parse(tokens, Some(raw.to_string())); let tree = parse(tokens, Some(raw.to_string()));
assert!(tree.is_ok()) assert!(tree.is_ok())
} }
#[test]
#[ignore]
fn test_parse_compound_ops_with_identifier_first() {
let raw = "
fn main(n) {
return n * 2;
}
";
let tokens = tokenize(raw);
let tree = parse(tokens, Some(raw.to_string()));
assert!(tree.is_ok())
}
#[test]
fn test_parse_compound_ops_return() {
let raw = "
fn main(n) {
return 2 * n;
}
";
let tokens = tokenize(raw);
let tree = parse(tokens, Some(raw.to_string()));
assert!(tree.is_ok())
}

Loading…
Cancel
Save