From c045721f4657ac8a5def32057a5aa22a1af0be58 Mon Sep 17 00:00:00 2001 From: Araozu Date: Tue, 21 Nov 2023 07:49:49 -0500 Subject: [PATCH] Change grammar to incorporate binary operators --- CHANGELOG.md | 4 +- src/codegen/expression.rs | 3 + src/syntax/ast/mod.rs | 2 + src/syntax/expression/equality.rs | 8 +++ src/syntax/expression/mod.rs | 36 +++++++++++ .../{expression.rs => expression/primary.rs} | 22 ++++--- src/syntax/grammar.md | 64 +++++++++++++------ 7 files changed, 110 insertions(+), 29 deletions(-) create mode 100644 src/syntax/expression/equality.rs create mode 100644 src/syntax/expression/mod.rs rename src/syntax/{expression.rs => expression/primary.rs} (85%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 875a963..569a39d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,10 +2,8 @@ ## TODO -- Parse multiple statements - Parse binary operators - Parse more complex bindings -- Parse block of code - Watch mode - Improve error messages - Parse other language constructions @@ -17,6 +15,8 @@ ## v0.0.8 + +- Parse block of code - Parse multiple statements inside a block diff --git a/src/codegen/expression.rs b/src/codegen/expression.rs index 05b7242..3ebe936 100644 --- a/src/codegen/expression.rs +++ b/src/codegen/expression.rs @@ -18,6 +18,9 @@ impl Transpilable for Expression { Expression::Boolean(value) => String::from(if *value { "true" } else { "false" }), Expression::Identifier(value) => format!("{}", *value), Expression::FunctionCall(_) => todo!("FunctionCall codegen is not implemented yet"), + Expression::BinaryOperator(_, _, _) => { + todo!("BinaryOperator codegen is not implemented yet") + } } } } diff --git a/src/syntax/ast/mod.rs b/src/syntax/ast/mod.rs index cee691b..0d08819 100644 --- a/src/syntax/ast/mod.rs +++ b/src/syntax/ast/mod.rs @@ -35,4 +35,6 @@ pub enum Expression { Boolean(bool), Identifier(Box), FunctionCall(FunctionCall), + BinaryOperator(Box, Box, Box), } + diff --git a/src/syntax/expression/equality.rs b/src/syntax/expression/equality.rs new file mode 100644 index 0000000..d7ace6c --- /dev/null +++ b/src/syntax/expression/equality.rs @@ -0,0 +1,8 @@ +use crate::{syntax::{ParseResult, ast::Expression}, lexic::token::Token}; + + +pub fn try_parse(tokens: &Vec, pos: usize) -> ParseResult { + // + + todo!() +} diff --git a/src/syntax/expression/mod.rs b/src/syntax/expression/mod.rs new file mode 100644 index 0000000..eb0da6f --- /dev/null +++ b/src/syntax/expression/mod.rs @@ -0,0 +1,36 @@ +use super::{ast::Expression, functions::function_call, ParseResult}; +use crate::lexic::token::{Token, TokenType}; + +mod equality; +mod primary; + +/// Expression is defined in the grammar. +pub fn try_parse(tokens: &Vec, pos: usize) -> ParseResult { + match function_call::try_parse(tokens, pos) { + super::ParseResult::Ok(function_call, next_pos) => { + return ParseResult::Ok::<_, ()>(Expression::FunctionCall(function_call), next_pos) + } + _ => {} + }; + + match tokens.get(pos) { + Some(token) => match token.token_type { + TokenType::Number => { + ParseResult::Ok(Expression::Number(Box::new(token.value.clone())), pos + 1) + } + TokenType::String => { + ParseResult::Ok(Expression::String(Box::new(token.value.clone())), pos + 1) + } + TokenType::Identifier if token.value == "true" || token.value == "false" => { + ParseResult::Ok(Expression::Boolean(token.value == "true"), pos + 1) + } + TokenType::Identifier => ParseResult::Ok( + Expression::Identifier(Box::new(token.value.clone())), + pos + 1, + ), + _ => ParseResult::Unmatched, + }, + None => ParseResult::Unmatched, + } +} + diff --git a/src/syntax/expression.rs b/src/syntax/expression/primary.rs similarity index 85% rename from src/syntax/expression.rs rename to src/syntax/expression/primary.rs index a3a968c..870598b 100644 --- a/src/syntax/expression.rs +++ b/src/syntax/expression/primary.rs @@ -1,20 +1,23 @@ -use super::{ast::Expression, functions::function_call, ParseResult}; -use crate::lexic::token::{Token, TokenType}; +use crate::{ + lexic::token::{Token, TokenType}, + syntax::{ast::Expression, ParseResult}, +}; -/// An expression can be: -/// -/// - A number -/// - A string -/// - A boolean -/// - An identifier -/// - A function call +/// This grammar may not be up to date. Refer to the spec for the latest grammar. +/// +/// ```ebnf +/// primary = number | string | boolean | identifier | ("(", expression, ")"); +/// ``` pub fn try_parse(tokens: &Vec, pos: usize) -> ParseResult { + /* + TODO: Incorporate function_call into the grammar, figure out its precedence. match function_call::try_parse(tokens, pos) { super::ParseResult::Ok(function_call, next_pos) => { return ParseResult::Ok::<_, ()>(Expression::FunctionCall(function_call), next_pos) } _ => {} }; + */ match tokens.get(pos) { Some(token) => match token.token_type { @@ -31,6 +34,7 @@ pub fn try_parse(tokens: &Vec, pos: usize) -> ParseResult Expression::Identifier(Box::new(token.value.clone())), pos + 1, ), + // TODO: Parse parenthesized expressions. _ => ParseResult::Unmatched, }, None => ParseResult::Unmatched, diff --git a/src/syntax/grammar.md b/src/syntax/grammar.md index e48435b..0e15a27 100644 --- a/src/syntax/grammar.md +++ b/src/syntax/grammar.md @@ -9,6 +9,7 @@ A module is (commonly) a single source file. module = top level declaration* ``` + ## Top level declaration ```ebnf @@ -19,18 +20,10 @@ top level declaration = function declaration ## Function declaration ```ebnf -function declaration = "fun", identifier, params list, return type?, block -``` +function declaration = "fun", identifier, params list, return type?, block; -### Params list +params list = "(", ")"; -```ebnf -params list = "(", ")" -``` - -### Return type - -```ebnf return type = ; ``` @@ -38,28 +31,63 @@ return type = ; ### Block ```ebnf -block = "{", (statement, (new line, statement)*)?, "}" +block = "{", (statement, (new line, statement)*)?, "}" ``` ### Statement ```ebnf -statement = function call | binding +statement = binding + | function call ``` ## Function call ```ebnf -function call = identifier, arguments list -``` +function call = identifier, arguments list; - -### Arguments list - -```ebnf arguments list = "(", ")" ``` +## Binding + +```ebnf +binding = ("val" | "var"), identifier, "=", expression +``` + + +## Operator precedence + +From highest to lowest: + +- `== !=`, left associative +- `> >= < <=`, left associative +- `- +`, left associative +- `/ *`, left associative +- `! -`, left associative + +## Expression + +```ebnf +expression = equality; + +equality = comparison, (("==" | "!="), comparison )*; + +comparison = term, ((">" | ">=" | "<" | "<="), term)*; + +term = factor, (("-" | "+"), factor)*; + +factor = unary, (("/" | "*"), unary)*; + +unary = ("!" | "-"), expression + | primary; + +primary = number | string | boolean | identifier | ("(", expression, ")"); +``` + + + +