Compare commits
3 Commits
b650447e06
...
6a951434f3
Author | SHA1 | Date | |
---|---|---|---|
6a951434f3 | |||
8d5fcd1ce3 | |||
778a1390a0 |
@ -29,12 +29,12 @@
|
|||||||
## v0.0.13
|
## v0.0.13
|
||||||
|
|
||||||
- [ ] Begin work on a formal grammar
|
- [ ] Begin work on a formal grammar
|
||||||
- [ ] Simplify AST
|
- [ ] Simplify/rewrite AST
|
||||||
- [ ] Define the top level constructs
|
- [ ] Define the top level constructs
|
||||||
- [ ] Include the original tokens in the AST
|
- [ ] Include the original tokens in the AST
|
||||||
- [ ] Implement a hello world until semantic analysis
|
- [ ] Finish the workflow for a hello world
|
||||||
- [ ] Refactor code
|
- [ ] Refactor code
|
||||||
- [ ] Remove `PARSER couldn't parse any construction` error & replace with an actual error message
|
- [x] Remove `PARSER couldn't parse any construction` error & replace with an actual error message
|
||||||
|
|
||||||
|
|
||||||
## v0.0.12
|
## v0.0.12
|
||||||
|
@ -5,10 +5,13 @@ use super::Transpilable;
|
|||||||
impl Transpilable for Block<'_> {
|
impl Transpilable for Block<'_> {
|
||||||
fn transpile(&self) -> String {
|
fn transpile(&self) -> String {
|
||||||
// TODO: Handle indentation
|
// TODO: Handle indentation
|
||||||
self.statements
|
todo!("transpilation for block");
|
||||||
|
/*
|
||||||
|
self.members
|
||||||
.iter()
|
.iter()
|
||||||
.map(|x| x.transpile())
|
.map(|x| x.transpile())
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join("\n")
|
.join("\n")
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ mod tests {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* TODO: reimplement
|
||||||
#[test]
|
#[test]
|
||||||
fn should_transpile() {
|
fn should_transpile() {
|
||||||
let tokens = get_tokens(&String::from("fun id() {}")).unwrap();
|
let tokens = get_tokens(&String::from("fun id() {}")).unwrap();
|
||||||
@ -38,5 +39,5 @@ mod tests {
|
|||||||
}
|
}
|
||||||
_ => panic!("Expected a function declaration"),
|
_ => panic!("Expected a function declaration"),
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ use crate::{
|
|||||||
impls::SemanticCheck,
|
impls::SemanticCheck,
|
||||||
symbol_table::{SymbolEntry, SymbolTable},
|
symbol_table::{SymbolEntry, SymbolTable},
|
||||||
},
|
},
|
||||||
syntax::ast::{FunctionDeclaration, Statement},
|
syntax::ast::{BlockMember, FunctionDeclaration, Statement},
|
||||||
};
|
};
|
||||||
|
|
||||||
impl SemanticCheck for FunctionDeclaration<'_> {
|
impl SemanticCheck for FunctionDeclaration<'_> {
|
||||||
@ -33,16 +33,17 @@ impl SemanticCheck for FunctionDeclaration<'_> {
|
|||||||
|
|
||||||
// TODO: Check the return type of the function body
|
// TODO: Check the return type of the function body
|
||||||
// This should be the last expression in the block
|
// This should be the last expression in the block
|
||||||
for stmt in self.block.statements.iter() {
|
for stmt in self.block.members.iter() {
|
||||||
match stmt {
|
match stmt {
|
||||||
Statement::Binding(b) => {
|
BlockMember::Stmt(Statement::Binding(b)) => {
|
||||||
if let Err(err) = b.check_semantics(&function_scope) {
|
if let Err(err) = b.check_semantics(&function_scope) {
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Statement::FnDecl(_) => {
|
BlockMember::Stmt(Statement::FnDecl(_)) => {
|
||||||
todo!("Function declaration: semantic check not implemented")
|
todo!("Function declaration: semantic check not implemented")
|
||||||
}
|
}
|
||||||
|
_ => todo!("Expression: semantic check not implemented"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,8 +37,14 @@ pub struct FunctionDeclaration<'a> {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Block<'a> {
|
pub struct Block<'a> {
|
||||||
// TODO: this should be a Vec of Statement|Expression
|
pub members: Vec<BlockMember<'a>>,
|
||||||
pub statements: Vec<Statement<'a>>,
|
}
|
||||||
|
|
||||||
|
/// Enum for productions available at the block level
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum BlockMember<'a> {
|
||||||
|
Stmt(Statement<'a>),
|
||||||
|
Expr(Expression<'a>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -1,118 +0,0 @@
|
|||||||
use crate::{
|
|
||||||
error_handling::SyntaxError,
|
|
||||||
lexic::token::{Token, TokenType},
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{ast::Block, utils::parse_token_type, ParsingError, ParsingResult};
|
|
||||||
|
|
||||||
// Assumes that the token at `pos` is a {
|
|
||||||
pub fn parse_block<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParsingResult<Block> {
|
|
||||||
let mut current_pos = pos;
|
|
||||||
|
|
||||||
let (opening_brace, next_pos) = parse_token_type(tokens, current_pos, TokenType::LeftBrace)?;
|
|
||||||
current_pos = next_pos;
|
|
||||||
|
|
||||||
// Parse block statements
|
|
||||||
let mut statements = Vec::new();
|
|
||||||
|
|
||||||
// First statement
|
|
||||||
match super::statement::try_parse(tokens, current_pos) {
|
|
||||||
Ok((statement, next_pos)) => {
|
|
||||||
current_pos = next_pos;
|
|
||||||
statements.push(statement);
|
|
||||||
}
|
|
||||||
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// More statements separated by new lines
|
|
||||||
while let Some(t) = tokens.get(current_pos) {
|
|
||||||
if t.token_type != TokenType::NewLine {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
current_pos += 1;
|
|
||||||
|
|
||||||
match super::statement::try_parse(tokens, current_pos) {
|
|
||||||
Ok((statement, next_pos)) => {
|
|
||||||
current_pos = next_pos;
|
|
||||||
statements.push(statement);
|
|
||||||
}
|
|
||||||
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
|
||||||
_ => break,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse closing brace
|
|
||||||
let (_closing_brace, next_pos) =
|
|
||||||
match parse_token_type(tokens, current_pos, TokenType::RightBrace) {
|
|
||||||
Ok((t, next)) => (t, next),
|
|
||||||
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
|
||||||
Err(ParsingError::Mismatch(t)) => {
|
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
|
||||||
reason: String::from("Expected a closing brace after the block body."),
|
|
||||||
error_start: t.position,
|
|
||||||
error_end: t.get_end_position(),
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
Err(ParsingError::Unmatched) => {
|
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
|
||||||
reason: String::from("Expected a closing brace after the block body."),
|
|
||||||
error_start: opening_brace.position,
|
|
||||||
error_end: opening_brace.get_end_position(),
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
current_pos = next_pos;
|
|
||||||
|
|
||||||
Ok((Block { statements }, current_pos))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
use crate::lexic::get_tokens;
|
|
||||||
|
|
||||||
// TODO: rewrite, refactor
|
|
||||||
/*
|
|
||||||
#[test]
|
|
||||||
fn test_parse_block() {
|
|
||||||
let tokens = get_tokens(&String::from("{f()}")).unwrap();
|
|
||||||
let block = parse_block(&tokens, 0);
|
|
||||||
|
|
||||||
let block = match block {
|
|
||||||
ParsingResult::Ok((p, _)) => p,
|
|
||||||
_ => panic!("Expected a block, got: {:?}", block),
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(block.statements.len(), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_parse_block_2() {
|
|
||||||
let tokens = get_tokens(&String::from("{f()\ng()}")).unwrap();
|
|
||||||
let block = parse_block(&tokens, 0);
|
|
||||||
|
|
||||||
let block = match block {
|
|
||||||
ParsingResult::Ok((p, _)) => p,
|
|
||||||
_ => panic!("Expected a block, got: {:?}", block),
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(block.statements.len(), 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_parse_block_3() {
|
|
||||||
let tokens = get_tokens(&String::from("{\n f()\n}")).unwrap();
|
|
||||||
let block = parse_block(&tokens, 0);
|
|
||||||
|
|
||||||
let block = match block {
|
|
||||||
ParsingResult::Ok((p, _)) => p,
|
|
||||||
_ => {
|
|
||||||
panic!("Expected a block, got: {:?}\n\n{:?}", block, tokens)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(block.statements.len(), 1);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
@ -11,6 +11,7 @@ mod unary;
|
|||||||
|
|
||||||
/// Expression is defined in the grammar.
|
/// Expression is defined in the grammar.
|
||||||
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParsingResult<Expression> {
|
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParsingResult<Expression> {
|
||||||
|
// TODO: This must be newline/indentation aware
|
||||||
equality::try_parse(tokens, pos)
|
equality::try_parse(tokens, pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,2 @@
|
|||||||
pub mod arguments_list;
|
pub mod arguments_list;
|
||||||
|
|
||||||
pub mod function_declaration;
|
|
||||||
pub mod params_list;
|
pub mod params_list;
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
use crate::error_handling::MistiError;
|
use crate::error_handling::MistiError;
|
||||||
|
|
||||||
mod binding;
|
|
||||||
mod block;
|
|
||||||
mod expression;
|
mod expression;
|
||||||
mod functions;
|
mod functions;
|
||||||
mod parseable;
|
mod parseable;
|
||||||
mod parsers;
|
mod parsers;
|
||||||
mod statement;
|
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
pub mod ast;
|
pub mod ast;
|
||||||
@ -36,7 +33,6 @@ mod tests {
|
|||||||
use tests::ast::Statement;
|
use tests::ast::Statement;
|
||||||
|
|
||||||
// TODO: Reenable when statement parsing is rewritten
|
// TODO: Reenable when statement parsing is rewritten
|
||||||
/*
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_parse_top_level_construct_with_trailing_newline() {
|
fn should_parse_top_level_construct_with_trailing_newline() {
|
||||||
let input = String::from(" fun f1(){}\n");
|
let input = String::from(" fun f1(){}\n");
|
||||||
@ -52,7 +48,6 @@ mod tests {
|
|||||||
_ => panic!("Expected a function declaration"),
|
_ => panic!("Expected a function declaration"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_parse_2_top_level_construct() {
|
fn should_parse_2_top_level_construct() {
|
||||||
|
@ -1,27 +1,26 @@
|
|||||||
use super::ast::var_binding::VariableBinding;
|
use crate::{
|
||||||
use super::utils::{parse_token_type, try_operator};
|
error_handling::SyntaxError,
|
||||||
use super::{expression, ParsingError, ParsingResult};
|
lexic::token::{Token, TokenType},
|
||||||
use crate::error_handling::SyntaxError;
|
syntax::{
|
||||||
use crate::lexic::token::{Token, TokenType};
|
ast::{var_binding::VariableBinding, Expression},
|
||||||
|
parseable::{Parseable, ParsingError, ParsingResult},
|
||||||
|
utils::{parse_token_type, try_operator},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
impl<'a> Parseable<'a> for VariableBinding<'a> {
|
||||||
binding = val binding | var binding
|
type Item = VariableBinding<'a>;
|
||||||
val binding = "val", datatype?, binding remainder
|
|
||||||
| datatype, binding remainder
|
|
||||||
|
|
||||||
var binding = "var", datatype?, binding remainder
|
fn try_parse(tokens: &'a Vec<Token>, current_pos: usize) -> ParsingResult<'a, Self::Item> {
|
||||||
|
let current_pos = current_pos;
|
||||||
binding remainder = identifier, "=", expression
|
|
||||||
*/
|
|
||||||
pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParsingResult<VariableBinding> {
|
|
||||||
let mut current_pos = pos;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* val/var keyword
|
* val/var keyword
|
||||||
*/
|
*/
|
||||||
let (is_var, binding_token, next_pos) = 'token: {
|
let (is_var, binding_token, next_pos) = 'token: {
|
||||||
// check for VAL
|
// check for VAL
|
||||||
if let Ok((val_token, next_pos)) = parse_token_type(tokens, current_pos, TokenType::VAL) {
|
if let Ok((val_token, next_pos)) = parse_token_type(tokens, current_pos, TokenType::VAL)
|
||||||
|
{
|
||||||
break 'token (false, Some(val_token), next_pos);
|
break 'token (false, Some(val_token), next_pos);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -32,16 +31,14 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParsingResult<Variab
|
|||||||
_ => (false, None, current_pos),
|
_ => (false, None, current_pos),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
current_pos = next_pos;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* datatype
|
* datatype
|
||||||
*/
|
*/
|
||||||
let (datatype, next_pos) = match parse_token_type(tokens, current_pos, TokenType::Datatype) {
|
let (datatype, next_pos) = match parse_token_type(tokens, next_pos, TokenType::Datatype) {
|
||||||
Ok((t, next)) => (Some(t), next),
|
Ok((t, next)) => (Some(t), next),
|
||||||
_ => (None, current_pos),
|
_ => (None, next_pos),
|
||||||
};
|
};
|
||||||
current_pos = next_pos;
|
|
||||||
|
|
||||||
// Here:
|
// Here:
|
||||||
// If the binding is None and the datatype is None, then we didn't match a binding
|
// If the binding is None and the datatype is None, then we didn't match a binding
|
||||||
@ -52,7 +49,7 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParsingResult<Variab
|
|||||||
/*
|
/*
|
||||||
* identifier
|
* identifier
|
||||||
*/
|
*/
|
||||||
let (identifier, next_pos) = match parse_token_type(tokens, current_pos, TokenType::Identifier)
|
let (identifier, next_pos) = match parse_token_type(tokens, next_pos, TokenType::Identifier)
|
||||||
{
|
{
|
||||||
Ok((t, n)) => (t, n),
|
Ok((t, n)) => (t, n),
|
||||||
Err(ParsingError::Mismatch(token)) => {
|
Err(ParsingError::Mismatch(token)) => {
|
||||||
@ -84,17 +81,18 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParsingResult<Variab
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!("Illegal parser state: binding_token and datatype are both None")
|
unreachable!(
|
||||||
|
"Illegal parser state: binding_token and datatype are both None"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
current_pos = next_pos;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Equal (=) operator
|
* Equal (=) operator
|
||||||
*/
|
*/
|
||||||
let equal_operator = match try_operator(tokens, current_pos, String::from("=")) {
|
let equal_operator = match try_operator(tokens, next_pos, String::from("=")) {
|
||||||
Ok((t, _)) => t,
|
Ok((t, _)) => t,
|
||||||
Err(ParsingError::Mismatch(t)) => {
|
Err(ParsingError::Mismatch(t)) => {
|
||||||
// The parser found a token, but it's not the `=` operator
|
// The parser found a token, but it's not the `=` operator
|
||||||
@ -113,12 +111,12 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParsingResult<Variab
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
current_pos += 1;
|
let next_pos = next_pos + 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Expression of the binding
|
* Expression of the binding
|
||||||
*/
|
*/
|
||||||
let (expression, next_pos) = match expression::try_parse(tokens, current_pos) {
|
let (expression, next_pos) = match Expression::try_parse(tokens, next_pos) {
|
||||||
Ok((exp, next)) => (exp, next),
|
Ok((exp, next)) => (exp, next),
|
||||||
_ => {
|
_ => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
@ -128,7 +126,6 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParsingResult<Variab
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
current_pos = next_pos;
|
|
||||||
|
|
||||||
let binding = VariableBinding {
|
let binding = VariableBinding {
|
||||||
datatype,
|
datatype,
|
||||||
@ -137,7 +134,8 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParsingResult<Variab
|
|||||||
is_mutable: is_var,
|
is_mutable: is_var,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok((binding, current_pos))
|
Ok((binding, next_pos))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -148,7 +146,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_parse_val_binding() {
|
fn should_parse_val_binding() {
|
||||||
let tokens = get_tokens(&String::from("val identifier = 20")).unwrap();
|
let tokens = get_tokens(&String::from("val identifier = 20")).unwrap();
|
||||||
let Ok((binding, _)) = try_parse(&tokens, 0) else {
|
let Ok((binding, _)) = VariableBinding::try_parse(&tokens, 0) else {
|
||||||
panic!()
|
panic!()
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -183,7 +181,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_parse_val_binding_with_datatype() {
|
fn should_parse_val_binding_with_datatype() {
|
||||||
let tokens = get_tokens(&String::from("val Int identifier = 20")).unwrap();
|
let tokens = get_tokens(&String::from("val Int identifier = 20")).unwrap();
|
||||||
let (binding, _) = try_parse(&tokens, 0).unwrap();
|
let (binding, _) = VariableBinding::try_parse(&tokens, 0).unwrap();
|
||||||
|
|
||||||
assert!(!binding.is_mutable);
|
assert!(!binding.is_mutable);
|
||||||
assert_eq!("Int", binding.datatype.unwrap().value);
|
assert_eq!("Int", binding.datatype.unwrap().value);
|
||||||
@ -193,7 +191,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_parse_var_binding_with_datatype() {
|
fn should_parse_var_binding_with_datatype() {
|
||||||
let tokens = get_tokens(&String::from("var Int identifier = 20")).unwrap();
|
let tokens = get_tokens(&String::from("var Int identifier = 20")).unwrap();
|
||||||
let (binding, _) = try_parse(&tokens, 0).unwrap();
|
let (binding, _) = VariableBinding::try_parse(&tokens, 0).unwrap();
|
||||||
|
|
||||||
assert!(binding.is_mutable);
|
assert!(binding.is_mutable);
|
||||||
assert!(binding.datatype.is_some());
|
assert!(binding.datatype.is_some());
|
||||||
@ -204,7 +202,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_parse_implicit_val_binding() {
|
fn should_parse_implicit_val_binding() {
|
||||||
let tokens = get_tokens(&String::from("Int identifier = 20")).unwrap();
|
let tokens = get_tokens(&String::from("Int identifier = 20")).unwrap();
|
||||||
let (binding, _) = try_parse(&tokens, 0).unwrap();
|
let (binding, _) = VariableBinding::try_parse(&tokens, 0).unwrap();
|
||||||
|
|
||||||
assert!(!binding.is_mutable);
|
assert!(!binding.is_mutable);
|
||||||
assert!(binding.datatype.is_some());
|
assert!(binding.datatype.is_some());
|
||||||
@ -215,7 +213,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_return_error_on_implicit_val_binding() {
|
fn should_return_error_on_implicit_val_binding() {
|
||||||
let tokens = get_tokens(&String::from("Int => 20")).unwrap();
|
let tokens = get_tokens(&String::from("Int => 20")).unwrap();
|
||||||
let binding = try_parse(&tokens, 0);
|
let binding = VariableBinding::try_parse(&tokens, 0);
|
||||||
|
|
||||||
match binding {
|
match binding {
|
||||||
Err(ParsingError::Err(error)) => {
|
Err(ParsingError::Err(error)) => {
|
||||||
@ -231,7 +229,7 @@ mod tests {
|
|||||||
let tokens = get_tokens(&String::from("val")).unwrap();
|
let tokens = get_tokens(&String::from("val")).unwrap();
|
||||||
assert_eq!(TokenType::VAL, tokens[0].token_type);
|
assert_eq!(TokenType::VAL, tokens[0].token_type);
|
||||||
assert_eq!(0, tokens[0].position);
|
assert_eq!(0, tokens[0].position);
|
||||||
let binding = try_parse(&tokens, 0);
|
let binding = VariableBinding::try_parse(&tokens, 0);
|
||||||
|
|
||||||
match binding {
|
match binding {
|
||||||
Err(ParsingError::Err(error)) => {
|
Err(ParsingError::Err(error)) => {
|
||||||
@ -247,7 +245,7 @@ mod tests {
|
|||||||
let tokens = get_tokens(&String::from("val 322")).unwrap();
|
let tokens = get_tokens(&String::from("val 322")).unwrap();
|
||||||
assert_eq!(TokenType::VAL, tokens[0].token_type);
|
assert_eq!(TokenType::VAL, tokens[0].token_type);
|
||||||
assert_eq!(0, tokens[0].position);
|
assert_eq!(0, tokens[0].position);
|
||||||
let binding = try_parse(&tokens, 0);
|
let binding = VariableBinding::try_parse(&tokens, 0);
|
||||||
|
|
||||||
match binding {
|
match binding {
|
||||||
Err(ParsingError::Err(error)) => {
|
Err(ParsingError::Err(error)) => {
|
||||||
@ -258,7 +256,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let tokens = get_tokens(&String::from("val \"hello\"")).unwrap();
|
let tokens = get_tokens(&String::from("val \"hello\"")).unwrap();
|
||||||
let binding = try_parse(&tokens, 0);
|
let binding = VariableBinding::try_parse(&tokens, 0);
|
||||||
|
|
||||||
match binding {
|
match binding {
|
||||||
Err(ParsingError::Err(error)) => {
|
Err(ParsingError::Err(error)) => {
|
||||||
@ -276,7 +274,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_return_error_when_equal_op_is_wrong() {
|
fn should_return_error_when_equal_op_is_wrong() {
|
||||||
let tokens = get_tokens(&String::from("val id \"error\"")).unwrap();
|
let tokens = get_tokens(&String::from("val id \"error\"")).unwrap();
|
||||||
let binding = try_parse(&tokens, 0);
|
let binding = VariableBinding::try_parse(&tokens, 0);
|
||||||
|
|
||||||
match binding {
|
match binding {
|
||||||
Err(ParsingError::Err(error)) => {
|
Err(ParsingError::Err(error)) => {
|
||||||
@ -290,7 +288,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_return_error_when_identifier_is_empty() {
|
fn should_return_error_when_identifier_is_empty() {
|
||||||
let tokens = get_tokens(&String::from("val String ")).unwrap();
|
let tokens = get_tokens(&String::from("val String ")).unwrap();
|
||||||
let binding = try_parse(&tokens, 0);
|
let binding = VariableBinding::try_parse(&tokens, 0);
|
||||||
|
|
||||||
match binding {
|
match binding {
|
||||||
Err(ParsingError::Err(error)) => {
|
Err(ParsingError::Err(error)) => {
|
||||||
@ -308,7 +306,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_return_error_when_identifier_is_empty_2() {
|
fn should_return_error_when_identifier_is_empty_2() {
|
||||||
let tokens = get_tokens(&String::from("val ")).unwrap();
|
let tokens = get_tokens(&String::from("val ")).unwrap();
|
||||||
let binding = try_parse(&tokens, 0);
|
let binding = VariableBinding::try_parse(&tokens, 0);
|
||||||
|
|
||||||
match binding {
|
match binding {
|
||||||
Err(ParsingError::Err(error)) => {
|
Err(ParsingError::Err(error)) => {
|
||||||
@ -326,7 +324,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_error_when_equal_op_is_missing() {
|
fn should_error_when_equal_op_is_missing() {
|
||||||
let tokens = get_tokens(&String::from("val identifier ")).unwrap();
|
let tokens = get_tokens(&String::from("val identifier ")).unwrap();
|
||||||
let binding = try_parse(&tokens, 0);
|
let binding = VariableBinding::try_parse(&tokens, 0);
|
||||||
|
|
||||||
match binding {
|
match binding {
|
||||||
Err(ParsingError::Err(error)) => {
|
Err(ParsingError::Err(error)) => {
|
||||||
@ -344,7 +342,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_error_when_exp_is_empty() {
|
fn should_error_when_exp_is_empty() {
|
||||||
let tokens = get_tokens(&String::from("val identifier = ")).unwrap();
|
let tokens = get_tokens(&String::from("val identifier = ")).unwrap();
|
||||||
let binding = try_parse(&tokens, 0);
|
let binding = VariableBinding::try_parse(&tokens, 0);
|
||||||
|
|
||||||
match binding {
|
match binding {
|
||||||
Err(ParsingError::Err(error)) => {
|
Err(ParsingError::Err(error)) => {
|
147
src/syntax/parsers/block.rs
Normal file
147
src/syntax/parsers/block.rs
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
use crate::{
|
||||||
|
error_handling::SyntaxError,
|
||||||
|
lexic::token::{Token, TokenType},
|
||||||
|
syntax::{
|
||||||
|
ast::{Block, BlockMember, Expression, Statement},
|
||||||
|
parseable::{Parseable, ParsingError, ParsingResult},
|
||||||
|
utils::parse_token_type,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
impl<'a> Parseable<'a> for Block<'a> {
|
||||||
|
type Item = Block<'a>;
|
||||||
|
|
||||||
|
fn try_parse(tokens: &'a Vec<Token>, current_pos: usize) -> ParsingResult<'a, Self::Item> {
|
||||||
|
let mut current_pos = current_pos;
|
||||||
|
|
||||||
|
let (opening_brace, next_pos) =
|
||||||
|
parse_token_type(tokens, current_pos, TokenType::LeftBrace)?;
|
||||||
|
current_pos = next_pos;
|
||||||
|
|
||||||
|
// Parse BlockMember = Statement | Expression
|
||||||
|
let mut members = Vec::<BlockMember>::new();
|
||||||
|
|
||||||
|
let tokens_len = tokens.len();
|
||||||
|
|
||||||
|
// Minus one because last token is EOF
|
||||||
|
while current_pos < tokens_len - 1 {
|
||||||
|
// Attempt to parse an statement
|
||||||
|
match Statement::try_parse(tokens, current_pos) {
|
||||||
|
Ok((prod, next_pos)) => {
|
||||||
|
members.push(BlockMember::Stmt(prod));
|
||||||
|
current_pos = next_pos;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Err(ParsingError::Err(error)) => {
|
||||||
|
// TODO: Better error handling, write a better error message
|
||||||
|
return Err(ParsingError::Err(error));
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Attempt to parse an expression
|
||||||
|
match Expression::try_parse(tokens, current_pos) {
|
||||||
|
Ok((prod, next_pos)) => {
|
||||||
|
members.push(BlockMember::Expr(prod));
|
||||||
|
current_pos = next_pos;
|
||||||
|
}
|
||||||
|
Err(ParsingError::Err(error)) => {
|
||||||
|
// TODO: Better error handling, write a better error message
|
||||||
|
return Err(ParsingError::Err(error));
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we reached this point we didn't match any productions
|
||||||
|
// we get out of the block, the parsing of "}" will deal
|
||||||
|
// with any incorrect tokens
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse closing brace
|
||||||
|
let (_closing_brace, next_pos) =
|
||||||
|
match parse_token_type(tokens, current_pos, TokenType::RightBrace) {
|
||||||
|
Ok((t, next)) => (t, next),
|
||||||
|
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
||||||
|
Err(ParsingError::Mismatch(t)) => {
|
||||||
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
|
reason: String::from("Expected a closing brace after the block body."),
|
||||||
|
error_start: t.position,
|
||||||
|
error_end: t.get_end_position(),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
Err(ParsingError::Unmatched) => {
|
||||||
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
|
reason: String::from("Expected a closing brace after the block body."),
|
||||||
|
// TODO: use the last token (at pos current_pos) as guide for the error
|
||||||
|
// msg position
|
||||||
|
error_start: opening_brace.position,
|
||||||
|
error_end: opening_brace.get_end_position(),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
current_pos = next_pos;
|
||||||
|
|
||||||
|
let block = Block { members };
|
||||||
|
Ok((block, current_pos))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::lexic::get_tokens;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_parse_empty_block() {
|
||||||
|
let tokens = get_tokens(&String::from("{}")).unwrap();
|
||||||
|
let (block, next_pos) = Block::try_parse(&tokens, 0).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(2, next_pos);
|
||||||
|
assert_eq!(0, block.members.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: rewrite, refactor
|
||||||
|
/*
|
||||||
|
#[test]
|
||||||
|
fn test_parse_block() {
|
||||||
|
let tokens = get_tokens(&String::from("{f()}")).unwrap();
|
||||||
|
let block = parse_block(&tokens, 0);
|
||||||
|
|
||||||
|
let block = match block {
|
||||||
|
ParsingResult::Ok((p, _)) => p,
|
||||||
|
_ => panic!("Expected a block, got: {:?}", block),
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(block.statements.len(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_block_2() {
|
||||||
|
let tokens = get_tokens(&String::from("{f()\ng()}")).unwrap();
|
||||||
|
let block = parse_block(&tokens, 0);
|
||||||
|
|
||||||
|
let block = match block {
|
||||||
|
ParsingResult::Ok((p, _)) => p,
|
||||||
|
_ => panic!("Expected a block, got: {:?}", block),
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(block.statements.len(), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_block_3() {
|
||||||
|
let tokens = get_tokens(&String::from("{\n f()\n}")).unwrap();
|
||||||
|
let block = parse_block(&tokens, 0);
|
||||||
|
|
||||||
|
let block = match block {
|
||||||
|
ParsingResult::Ok((p, _)) => p,
|
||||||
|
_ => {
|
||||||
|
panic!("Expected a block, got: {:?}\n\n{:?}", block, tokens)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(block.statements.len(), 1);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
@ -2,6 +2,7 @@ use crate::{
|
|||||||
lexic::token::Token,
|
lexic::token::Token,
|
||||||
syntax::{
|
syntax::{
|
||||||
ast::Expression,
|
ast::Expression,
|
||||||
|
expression,
|
||||||
parseable::{Parseable, ParsingResult},
|
parseable::{Parseable, ParsingResult},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -10,6 +11,6 @@ impl<'a> Parseable<'a> for Expression<'a> {
|
|||||||
type Item = Expression<'a>;
|
type Item = Expression<'a>;
|
||||||
|
|
||||||
fn try_parse(tokens: &'a Vec<Token>, current_pos: usize) -> ParsingResult<'a, Self::Item> {
|
fn try_parse(tokens: &'a Vec<Token>, current_pos: usize) -> ParsingResult<'a, Self::Item> {
|
||||||
todo!()
|
expression::try_parse(tokens, current_pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,19 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error_handling::SyntaxError,
|
error_handling::SyntaxError,
|
||||||
lexic::token::{Token, TokenType},
|
lexic::token::{Token, TokenType},
|
||||||
syntax::{utils::try_operator, ParsingError, ParsingResult},
|
syntax::{
|
||||||
|
ast::{Block, FunctionDeclaration},
|
||||||
|
functions::params_list::parse_params_list,
|
||||||
|
parseable::{Parseable, ParsingError, ParsingResult},
|
||||||
|
utils::{parse_token_type, try_operator},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
impl<'a> Parseable<'a> for FunctionDeclaration<'a> {
|
||||||
super::{ast::FunctionDeclaration, block::parse_block, utils::parse_token_type},
|
type Item = FunctionDeclaration<'a>;
|
||||||
params_list::parse_params_list,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
fn try_parse(tokens: &'a Vec<Token>, current_pos: usize) -> ParsingResult<'a, Self::Item> {
|
||||||
function declaration = "fun", identifier, params list, return type?, block;
|
let mut current_pos = current_pos;
|
||||||
|
|
||||||
return type = "->", datatype;
|
|
||||||
*/
|
|
||||||
pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParsingResult<FunctionDeclaration> {
|
|
||||||
let mut current_pos = pos;
|
|
||||||
|
|
||||||
// `fun` keyword
|
// `fun` keyword
|
||||||
let (fun_keyword, next_pos) = match parse_token_type(tokens, current_pos, TokenType::FUN) {
|
let (fun_keyword, next_pos) = match parse_token_type(tokens, current_pos, TokenType::FUN) {
|
||||||
@ -25,8 +23,8 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParsingResult<Functi
|
|||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
|
|
||||||
// identifier
|
// identifier
|
||||||
let (identifier, next_pos) = match parse_token_type(tokens, current_pos, TokenType::Identifier)
|
let (identifier, next_pos) =
|
||||||
{
|
match parse_token_type(tokens, current_pos, TokenType::Identifier) {
|
||||||
Ok((id, next)) => (id, next),
|
Ok((id, next)) => (id, next),
|
||||||
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
||||||
Err(ParsingError::Mismatch(wrong_token)) => {
|
Err(ParsingError::Mismatch(wrong_token)) => {
|
||||||
@ -47,19 +45,24 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParsingResult<Functi
|
|||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
|
|
||||||
// Params list
|
// Params list
|
||||||
|
// TODO: impl Parseable
|
||||||
let (params_list, next_pos) = match parse_params_list(tokens, current_pos) {
|
let (params_list, next_pos) = match parse_params_list(tokens, current_pos) {
|
||||||
Ok((params, next_pos)) => (params, next_pos),
|
Ok((params, next_pos)) => (params, next_pos),
|
||||||
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
||||||
Err(ParsingError::Mismatch(wrong_token)) => {
|
Err(ParsingError::Mismatch(wrong_token)) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
reason: String::from("Expected an opening paren after the function identifier."),
|
reason: String::from(
|
||||||
|
"Expected an opening paren after the function identifier.",
|
||||||
|
),
|
||||||
error_start: wrong_token.position,
|
error_start: wrong_token.position,
|
||||||
error_end: wrong_token.get_end_position(),
|
error_end: wrong_token.get_end_position(),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
Err(ParsingError::Unmatched) => {
|
Err(ParsingError::Unmatched) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
reason: String::from("Expected an opening paren after the function identifier."),
|
reason: String::from(
|
||||||
|
"Expected an opening paren after the function identifier.",
|
||||||
|
),
|
||||||
error_start: identifier.position,
|
error_start: identifier.position,
|
||||||
error_end: identifier.get_end_position(),
|
error_end: identifier.get_end_position(),
|
||||||
}));
|
}));
|
||||||
@ -68,6 +71,7 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParsingResult<Functi
|
|||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
|
|
||||||
// Try to parse a return type
|
// Try to parse a return type
|
||||||
|
// TODO: abstract parsing of Datatype to parse generics
|
||||||
let (return_type, next_pos) = 'return_label: {
|
let (return_type, next_pos) = 'return_label: {
|
||||||
let (arrow_op, next_pos) = match try_operator(tokens, current_pos, "->".into()) {
|
let (arrow_op, next_pos) = match try_operator(tokens, current_pos, "->".into()) {
|
||||||
Ok((op, next)) => (op, next),
|
Ok((op, next)) => (op, next),
|
||||||
@ -97,7 +101,8 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParsingResult<Functi
|
|||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
|
|
||||||
// Function body (block)
|
// Function body (block)
|
||||||
let (block, next_pos) = match parse_block(tokens, current_pos) {
|
// TODO: impl Parseable
|
||||||
|
let (block, next_pos) = match Block::try_parse(tokens, current_pos) {
|
||||||
Ok((block, next_pos)) => (block, next_pos),
|
Ok((block, next_pos)) => (block, next_pos),
|
||||||
Err(ParsingError::Err(error)) => {
|
Err(ParsingError::Err(error)) => {
|
||||||
return Err(ParsingError::Err(error));
|
return Err(ParsingError::Err(error));
|
||||||
@ -130,6 +135,7 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParsingResult<Functi
|
|||||||
current_pos,
|
current_pos,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
@ -140,7 +146,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_return_none_on_wrong_initial_token() {
|
fn should_return_none_on_wrong_initial_token() {
|
||||||
let tokens = get_tokens(&String::from("val identifier = 20")).unwrap();
|
let tokens = get_tokens(&String::from("val identifier = 20")).unwrap();
|
||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
||||||
|
|
||||||
let Err(ParsingError::Unmatched) = fun_decl else {
|
let Err(ParsingError::Unmatched) = fun_decl else {
|
||||||
panic!("Expected an unmatched result: {:?}", fun_decl);
|
panic!("Expected an unmatched result: {:?}", fun_decl);
|
||||||
@ -150,7 +156,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_not_parse_fun_without_identifier() {
|
fn should_not_parse_fun_without_identifier() {
|
||||||
let tokens = get_tokens(&String::from("fun = 20")).unwrap();
|
let tokens = get_tokens(&String::from("fun = 20")).unwrap();
|
||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
@ -165,7 +171,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let tokens = get_tokens(&String::from("fun")).unwrap();
|
let tokens = get_tokens(&String::from("fun")).unwrap();
|
||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -182,7 +188,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_not_parse_fun_without_parens() {
|
fn should_not_parse_fun_without_parens() {
|
||||||
let tokens = get_tokens(&String::from("fun id =")).unwrap();
|
let tokens = get_tokens(&String::from("fun id =")).unwrap();
|
||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
@ -197,7 +203,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let tokens = get_tokens(&String::from("fun id")).unwrap();
|
let tokens = get_tokens(&String::from("fun id")).unwrap();
|
||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -214,7 +220,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_not_parse_fun_without_closing_paren() {
|
fn should_not_parse_fun_without_closing_paren() {
|
||||||
let tokens = get_tokens(&String::from("fun id(=")).unwrap();
|
let tokens = get_tokens(&String::from("fun id(=")).unwrap();
|
||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
@ -229,7 +235,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let tokens = get_tokens(&String::from("fun id(")).unwrap();
|
let tokens = get_tokens(&String::from("fun id(")).unwrap();
|
||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -246,7 +252,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_not_parse_fun_when_missing_id() {
|
fn should_not_parse_fun_when_missing_id() {
|
||||||
let tokens = get_tokens(&String::from("fun")).unwrap();
|
let tokens = get_tokens(&String::from("fun")).unwrap();
|
||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
@ -262,7 +268,7 @@ mod tests {
|
|||||||
|
|
||||||
let tokens = get_tokens(&String::from("fun\n")).unwrap();
|
let tokens = get_tokens(&String::from("fun\n")).unwrap();
|
||||||
println!("{:?}", tokens);
|
println!("{:?}", tokens);
|
||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
@ -280,7 +286,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_not_parse_fun_without_opening_brace() {
|
fn should_not_parse_fun_without_opening_brace() {
|
||||||
let tokens = get_tokens(&String::from("fun id() =")).unwrap();
|
let tokens = get_tokens(&String::from("fun id() =")).unwrap();
|
||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
@ -295,7 +301,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let tokens = get_tokens(&String::from("fun id()")).unwrap();
|
let tokens = get_tokens(&String::from("fun id()")).unwrap();
|
||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -311,20 +317,20 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_not_parse_fun_without_closing_brace() {
|
fn should_not_parse_fun_without_closing_brace() {
|
||||||
let tokens = get_tokens(&String::from("fun id() { 20")).unwrap();
|
let tokens = get_tokens(&String::from("fun id() { ")).unwrap();
|
||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!(err.reason, "Expected a closing brace after the block body.");
|
assert_eq!(err.reason, "Expected a closing brace after the block body.");
|
||||||
assert_eq!(err.error_start, 11);
|
assert_eq!(err.error_start, 9);
|
||||||
assert_eq!(err.error_end, 13);
|
assert_eq!(err.error_end, 10);
|
||||||
}
|
}
|
||||||
_ => panic!("Expected an error: {:?}", fun_decl),
|
_ => panic!("Expected an error: {:?}", fun_decl),
|
||||||
}
|
}
|
||||||
|
|
||||||
let tokens = get_tokens(&String::from("fun id() {")).unwrap();
|
let tokens = get_tokens(&String::from("fun id() {")).unwrap();
|
||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
@ -339,7 +345,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_parse_simple_function_declaration() {
|
fn should_parse_simple_function_declaration() {
|
||||||
let tokens = get_tokens(&String::from("fun id() {}")).unwrap();
|
let tokens = get_tokens(&String::from("fun id() {}")).unwrap();
|
||||||
let (function_declaration, _) = try_parse(&tokens, 0).unwrap();
|
let (function_declaration, _) = FunctionDeclaration::try_parse(&tokens, 0).unwrap();
|
||||||
|
|
||||||
assert_eq!(function_declaration.identifier.value, String::from("id"));
|
assert_eq!(function_declaration.identifier.value, String::from("id"));
|
||||||
assert_eq!(function_declaration.return_type, None);
|
assert_eq!(function_declaration.return_type, None);
|
||||||
@ -348,7 +354,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_parse_return_type() {
|
fn should_parse_return_type() {
|
||||||
let tokens = get_tokens(&String::from("fun id() -> String {}")).unwrap();
|
let tokens = get_tokens(&String::from("fun id() -> String {}")).unwrap();
|
||||||
let (function_declaration, _) = try_parse(&tokens, 0).unwrap();
|
let (function_declaration, _) = FunctionDeclaration::try_parse(&tokens, 0).unwrap();
|
||||||
|
|
||||||
assert_eq!(function_declaration.identifier.value, String::from("id"));
|
assert_eq!(function_declaration.identifier.value, String::from("id"));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -360,7 +366,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_throw_error_on_return_type_1() {
|
fn should_throw_error_on_return_type_1() {
|
||||||
let tokens = get_tokens(&String::from("fun id() -> {}")).unwrap();
|
let tokens = get_tokens(&String::from("fun id() -> {}")).unwrap();
|
||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
@ -375,7 +381,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_throw_error_on_return_type_2() {
|
fn should_throw_error_on_return_type_2() {
|
||||||
let tokens = get_tokens(&String::from("fun id() -> ")).unwrap();
|
let tokens = get_tokens(&String::from("fun id() -> ")).unwrap();
|
||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
@ -397,7 +403,7 @@ mod whitespace_test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_ignore_whitespace_1() {
|
fn should_ignore_whitespace_1() {
|
||||||
let tokens = get_tokens(&String::from("fun\nid() {}")).unwrap();
|
let tokens = get_tokens(&String::from("fun\nid() {}")).unwrap();
|
||||||
let (declaration, _) = try_parse(&tokens, 0).unwrap();
|
let (declaration, _) = FunctionDeclaration::try_parse(&tokens, 0).unwrap();
|
||||||
|
|
||||||
assert_eq!(declaration.identifier.value, (String::from("id")));
|
assert_eq!(declaration.identifier.value, (String::from("id")));
|
||||||
}
|
}
|
||||||
@ -405,7 +411,7 @@ mod whitespace_test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_ignore_whitespace_2() {
|
fn should_ignore_whitespace_2() {
|
||||||
let tokens = get_tokens(&String::from("fun\nid\n() {}")).unwrap();
|
let tokens = get_tokens(&String::from("fun\nid\n() {}")).unwrap();
|
||||||
let (declaration, _) = try_parse(&tokens, 0).unwrap();
|
let (declaration, _) = FunctionDeclaration::try_parse(&tokens, 0).unwrap();
|
||||||
|
|
||||||
assert_eq!(declaration.identifier.value, (String::from("id")));
|
assert_eq!(declaration.identifier.value, (String::from("id")));
|
||||||
}
|
}
|
||||||
@ -413,7 +419,7 @@ mod whitespace_test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_ignore_whitespace_3() {
|
fn should_ignore_whitespace_3() {
|
||||||
let tokens = get_tokens(&String::from("fun\nid\n(\n) {}")).unwrap();
|
let tokens = get_tokens(&String::from("fun\nid\n(\n) {}")).unwrap();
|
||||||
let (declaration, _) = try_parse(&tokens, 0).unwrap();
|
let (declaration, _) = FunctionDeclaration::try_parse(&tokens, 0).unwrap();
|
||||||
|
|
||||||
assert_eq!(declaration.identifier.value, (String::from("id")));
|
assert_eq!(declaration.identifier.value, (String::from("id")));
|
||||||
}
|
}
|
||||||
@ -421,14 +427,14 @@ mod whitespace_test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_ignore_whitespace_4() {
|
fn should_ignore_whitespace_4() {
|
||||||
let tokens = get_tokens(&String::from("fun id\n(\n)\n{}")).unwrap();
|
let tokens = get_tokens(&String::from("fun id\n(\n)\n{}")).unwrap();
|
||||||
let (declaration, _) = try_parse(&tokens, 0).unwrap();
|
let (declaration, _) = FunctionDeclaration::try_parse(&tokens, 0).unwrap();
|
||||||
assert_eq!(declaration.identifier.value, (String::from("id")));
|
assert_eq!(declaration.identifier.value, (String::from("id")));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_ignore_whitespace_5() {
|
fn should_ignore_whitespace_5() {
|
||||||
let tokens = get_tokens(&String::from("fun\nid() \n{\n}")).unwrap();
|
let tokens = get_tokens(&String::from("fun\nid() \n{\n}")).unwrap();
|
||||||
let (declaration, _) = try_parse(&tokens, 0).unwrap();
|
let (declaration, _) = FunctionDeclaration::try_parse(&tokens, 0).unwrap();
|
||||||
assert_eq!(declaration.identifier.value, (String::from("id")));
|
assert_eq!(declaration.identifier.value, (String::from("id")));
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,3 +1,6 @@
|
|||||||
|
pub mod binding;
|
||||||
|
pub mod block;
|
||||||
pub mod expression;
|
pub mod expression;
|
||||||
|
pub mod function_declaration;
|
||||||
pub mod module;
|
pub mod module;
|
||||||
pub mod statement;
|
pub mod statement;
|
||||||
|
@ -22,12 +22,7 @@ impl<'a> Parseable<'a> for ModuleAST<'a> {
|
|||||||
let mut current_pos = 0;
|
let mut current_pos = 0;
|
||||||
|
|
||||||
// Minus one because last token is EOF
|
// Minus one because last token is EOF
|
||||||
// TODO: Does that EOF do anything?
|
|
||||||
while current_pos < tokens_len - 1 {
|
while current_pos < tokens_len - 1 {
|
||||||
println!(
|
|
||||||
"len: {} pos: {}, value: `{}`, type: {:?}",
|
|
||||||
tokens_len, current_pos, tokens[current_pos].value, tokens[current_pos].token_type
|
|
||||||
);
|
|
||||||
// Attempt to parse an statement
|
// Attempt to parse an statement
|
||||||
match Statement::try_parse(tokens, current_pos) {
|
match Statement::try_parse(tokens, current_pos) {
|
||||||
Ok((prod, next_pos)) => {
|
Ok((prod, next_pos)) => {
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
use crate::syntax::{
|
use crate::syntax::{
|
||||||
ast::Statement,
|
ast::{var_binding::VariableBinding, FunctionDeclaration, Statement},
|
||||||
binding,
|
|
||||||
functions::function_declaration,
|
|
||||||
parseable::{Parseable, ParsingError},
|
parseable::{Parseable, ParsingError},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -13,8 +11,7 @@ impl<'a> Parseable<'a> for Statement<'a> {
|
|||||||
current_pos: usize,
|
current_pos: usize,
|
||||||
) -> crate::syntax::parseable::ParsingResult<'a, Self::Item> {
|
) -> crate::syntax::parseable::ParsingResult<'a, Self::Item> {
|
||||||
// Try to parse a variable binding
|
// Try to parse a variable binding
|
||||||
// TODO: Rewrite function_declaration to use Parseable
|
match VariableBinding::try_parse(tokens, current_pos) {
|
||||||
match binding::try_parse(tokens, current_pos) {
|
|
||||||
Ok((prod, next)) => {
|
Ok((prod, next)) => {
|
||||||
return Ok((Statement::Binding(prod), next));
|
return Ok((Statement::Binding(prod), next));
|
||||||
}
|
}
|
||||||
@ -26,8 +23,7 @@ impl<'a> Parseable<'a> for Statement<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Try to parse a function declaration
|
// Try to parse a function declaration
|
||||||
// TODO: Rewrite function_declaration to use Parseable
|
match FunctionDeclaration::try_parse(tokens, current_pos) {
|
||||||
match function_declaration::try_parse(tokens, current_pos) {
|
|
||||||
Ok((prod, next)) => {
|
Ok((prod, next)) => {
|
||||||
return Ok((Statement::FnDecl(prod), next));
|
return Ok((Statement::FnDecl(prod), next));
|
||||||
}
|
}
|
||||||
|
@ -1,47 +0,0 @@
|
|||||||
use crate::lexic::token::Token;
|
|
||||||
|
|
||||||
use super::{ast::Statement, binding, ParsingError, ParsingResult};
|
|
||||||
|
|
||||||
pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParsingResult<Statement> {
|
|
||||||
// Try to parse a binding
|
|
||||||
match binding::try_parse(tokens, pos) {
|
|
||||||
Ok((b, next)) => return Ok((Statement::Binding(b), next)),
|
|
||||||
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// A function call is an expression, not a statement. Remove
|
|
||||||
// Try to parse a function call
|
|
||||||
/*
|
|
||||||
match function_call_expr::try_parse(tokens, pos) {
|
|
||||||
Ok((Expression::FunctionCall(f), next)) => return Ok((Statement::FunctionCall(f), next)),
|
|
||||||
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Return unmatched
|
|
||||||
Err(ParsingError::Unmatched)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn should_parse_binding() {
|
|
||||||
let input = String::from("val identifier = 20");
|
|
||||||
let tokens = crate::lexic::get_tokens(&input).unwrap();
|
|
||||||
let statement = try_parse(&tokens, 0);
|
|
||||||
|
|
||||||
let statement = match statement {
|
|
||||||
Ok((s, _)) => s,
|
|
||||||
_ => panic!("Expected a statement"),
|
|
||||||
};
|
|
||||||
|
|
||||||
match statement {
|
|
||||||
Statement::Binding(_) => assert!(true),
|
|
||||||
_ => panic!("Expected a binding"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user