Change grammar to incorporate binary operators

master
Araozu 2023-11-21 07:49:49 -05:00
parent c02e1c1f8e
commit c045721f46
7 changed files with 110 additions and 29 deletions

View File

@ -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

View File

@ -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")
}
}
}
}

View File

@ -35,4 +35,6 @@ pub enum Expression {
Boolean(bool),
Identifier(Box<String>),
FunctionCall(FunctionCall),
BinaryOperator(Box<Expression>, Box<Expression>, Box<String>),
}

View File

@ -0,0 +1,8 @@
use crate::{syntax::{ParseResult, ast::Expression}, lexic::token::Token};
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()> {
//
todo!()
}

View File

@ -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<Token>, pos: usize) -> ParseResult<Expression, ()> {
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,
}
}

View File

@ -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:
/// This grammar may not be up to date. Refer to the spec for the latest grammar.
///
/// - A number
/// - A string
/// - A boolean
/// - An identifier
/// - A function call
/// ```ebnf
/// primary = number | string | boolean | identifier | ("(", expression, ")");
/// ```
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()> {
/*
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<Token>, pos: usize) -> ParseResult<Expression, ()>
Expression::Identifier(Box::new(token.value.clone())),
pos + 1,
),
// TODO: Parse parenthesized expressions.
_ => ParseResult::Unmatched,
},
None => ParseResult::Unmatched,

View File

@ -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, ")");
```