Compare commits
10 Commits
f97b8e2e07
...
8a039ffc64
Author | SHA1 | Date | |
---|---|---|---|
8a039ffc64 | |||
61051ed11b | |||
ec09dbfc0d | |||
98f67bd097 | |||
e43eb9e137 | |||
1348020cd7 | |||
d822c64fd7 | |||
ac2ab8d2dc | |||
ed9ccab5e1 | |||
e074e2cd74 |
31
CHANGELOG.md
31
CHANGELOG.md
@ -8,7 +8,6 @@
|
|||||||
codegen section can focus only in codegen, not in
|
codegen section can focus only in codegen, not in
|
||||||
translation of thp->php.
|
translation of thp->php.
|
||||||
- Parse __more__ binary operators
|
- Parse __more__ binary operators
|
||||||
- Parse `Type name = value` bindings
|
|
||||||
- Parse more complex bindings
|
- Parse more complex bindings
|
||||||
- Watch mode
|
- Watch mode
|
||||||
- Improve error messages
|
- Improve error messages
|
||||||
@ -23,18 +22,40 @@
|
|||||||
- Simple language server
|
- Simple language server
|
||||||
- Decide how to handle comments in the syntax (?)(should comments mean something like in rust?)
|
- Decide how to handle comments in the syntax (?)(should comments mean something like in rust?)
|
||||||
|
|
||||||
|
## v0.0.12
|
||||||
|
|
||||||
|
- [ ] Infer datatype of a function call expression
|
||||||
|
- [ ] Infer datatype of binary operators
|
||||||
|
- [ ] Execute semantic analysis on the function's block
|
||||||
|
- [ ] Write tests
|
||||||
|
|
||||||
|
|
||||||
|
## v0.0.11
|
||||||
|
|
||||||
|
- [ ] Parse binding of form `val Type variable = value`
|
||||||
|
- [ ] Parse binding of form `Type variable = value`
|
||||||
|
- [ ] Infer datatype of `value` in the above for a simple expression
|
||||||
|
- [ ] Ensure that the anotated datatype matches the datatype of `value` in the above
|
||||||
|
- [ ] Infer datatype of a `val variable = value` in the AST: Use the infered datatype
|
||||||
|
- [ ] Formally define the top level constructs
|
||||||
|
- [ ] Parse bindings and function declarations as top level constructs
|
||||||
|
- [ ] Parse function declaration arguments (`Type id`)
|
||||||
|
- [ ] Parse function return datatype (`fun f() -> Type`)
|
||||||
|
- [ ] Return parsing to variables to var/val
|
||||||
|
- [ ] Write tests
|
||||||
|
|
||||||
|
|
||||||
## v0.0.10
|
## v0.0.10
|
||||||
|
|
||||||
- [x] Parse function call parameters
|
- [x] Parse function call parameters
|
||||||
- [x] Codegen function call parameters
|
- [x] Codegen function call parameters
|
||||||
- [x] Parse function declaration arguments (Type id)
|
|
||||||
- [x] Begin work on semantic analysis
|
- [x] Begin work on semantic analysis
|
||||||
- [x] Minimal symbol table
|
- [x] Minimal symbol table
|
||||||
- [x] Check duplicate function declarations
|
- [x] Check duplicate function declarations
|
||||||
- [x] Improve REPL/File compilation code
|
- [x] Improve REPL/File compilation code
|
||||||
- [ ] Typecheck bindings
|
- [x] Check binding duplication in it's scope
|
||||||
- [x] Typecheck functions
|
- [x] Check function duplication in it's scope
|
||||||
- [ ] Transform simple THP expression into PHP statements
|
- [x] Transform simple THP expression into PHP statements
|
||||||
|
|
||||||
## v0.0.9
|
## v0.0.9
|
||||||
|
|
||||||
|
@ -1,28 +1,36 @@
|
|||||||
use super::Transpilable;
|
use super::Transpilable;
|
||||||
use crate::syntax::ast::var_binding::Binding;
|
use crate::syntax::ast::var_binding::Binding;
|
||||||
|
|
||||||
impl Transpilable for Binding {
|
impl Transpilable for Binding<'_> {
|
||||||
/// Transpiles val and var bindings into PHP.
|
/// Transpiles val and var bindings into PHP.
|
||||||
fn transpile(&self) -> String {
|
fn transpile(&self) -> String {
|
||||||
let expression_str = self.expression.transpile();
|
let expression_str = self.expression.transpile();
|
||||||
|
|
||||||
format!("${} = {}", self.identifier, expression_str)
|
format!("${} = {}", self.identifier.value, expression_str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::syntax::ast::{var_binding::Binding, Expression};
|
use crate::{
|
||||||
|
lexic::token::{Token, TokenType},
|
||||||
|
syntax::ast::{var_binding::Binding, Expression},
|
||||||
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn binding_should_transpile() {
|
fn binding_should_transpile() {
|
||||||
let id = String::from("identifier");
|
let id = String::from("identifier");
|
||||||
|
let id_token = Token {
|
||||||
|
token_type: TokenType::Identifier,
|
||||||
|
value: id,
|
||||||
|
position: 0,
|
||||||
|
};
|
||||||
let value = String::from("322");
|
let value = String::from("322");
|
||||||
let binding = Binding {
|
let binding = Binding {
|
||||||
datatype: None,
|
datatype: None,
|
||||||
identifier: Box::new(id),
|
identifier: &id_token,
|
||||||
expression: Expression::Number(Box::new(value)),
|
expression: Expression::Number(&value),
|
||||||
is_mutable: false,
|
is_mutable: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ use crate::syntax::ast::Block;
|
|||||||
|
|
||||||
use super::Transpilable;
|
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
|
self.statements
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use super::Transpilable;
|
use super::Transpilable;
|
||||||
use crate::syntax::ast::Expression;
|
use crate::syntax::ast::Expression;
|
||||||
|
|
||||||
impl Transpilable for Expression {
|
impl Transpilable for Expression<'_> {
|
||||||
/// Transpiles an Expression to PHP
|
/// Transpiles an Expression to PHP
|
||||||
///
|
///
|
||||||
/// Right now the expressions in the grammar are:
|
/// Right now the expressions in the grammar are:
|
||||||
@ -41,7 +41,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_transpile_number() {
|
fn should_transpile_number() {
|
||||||
let str = String::from("42");
|
let str = String::from("42");
|
||||||
let exp = Expression::Number(Box::new(str));
|
let exp = Expression::Number(&str);
|
||||||
let result = exp.transpile();
|
let result = exp.transpile();
|
||||||
|
|
||||||
assert_eq!("42", result);
|
assert_eq!("42", result);
|
||||||
@ -50,7 +50,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_transpile_string() {
|
fn should_transpile_string() {
|
||||||
let str = String::from("\"Hello world\"");
|
let str = String::from("\"Hello world\"");
|
||||||
let exp = Expression::String(Box::new(str));
|
let exp = Expression::String(&str);
|
||||||
let result = exp.transpile();
|
let result = exp.transpile();
|
||||||
|
|
||||||
assert_eq!("\"Hello world\"", result);
|
assert_eq!("\"Hello world\"", result);
|
||||||
@ -67,7 +67,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_transpile_identifier() {
|
fn should_transpile_identifier() {
|
||||||
let s = String::from("newValue");
|
let s = String::from("newValue");
|
||||||
let exp = Expression::Identifier(Box::new(s));
|
let exp = Expression::Identifier(&s);
|
||||||
let result = exp.transpile();
|
let result = exp.transpile();
|
||||||
|
|
||||||
assert_eq!("newValue", result);
|
assert_eq!("newValue", result);
|
||||||
|
@ -2,7 +2,7 @@ use crate::syntax::ast::functions::FunctionCall;
|
|||||||
|
|
||||||
use super::Transpilable;
|
use super::Transpilable;
|
||||||
|
|
||||||
impl Transpilable for FunctionCall {
|
impl Transpilable for FunctionCall<'_> {
|
||||||
fn transpile(&self) -> String {
|
fn transpile(&self) -> String {
|
||||||
let parameters = &self
|
let parameters = &self
|
||||||
.arguments
|
.arguments
|
||||||
|
@ -2,11 +2,11 @@ use crate::syntax::ast::FunctionDeclaration;
|
|||||||
|
|
||||||
use super::Transpilable;
|
use super::Transpilable;
|
||||||
|
|
||||||
impl Transpilable for FunctionDeclaration {
|
impl Transpilable for FunctionDeclaration<'_> {
|
||||||
fn transpile(&self) -> String {
|
fn transpile(&self) -> String {
|
||||||
format!(
|
format!(
|
||||||
"function {}() {{\n{}\n}}",
|
"function {}() {{\n{}\n}}",
|
||||||
self.identifier,
|
self.identifier.value,
|
||||||
self.block.transpile()
|
self.block.transpile()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -34,6 +34,7 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!("function id() {\n\n}", transpiled);
|
assert_eq!("function id() {\n\n}", transpiled);
|
||||||
}
|
}
|
||||||
|
_ => panic!("Not implemented: Expression at top level"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use super::Transpilable;
|
use super::Transpilable;
|
||||||
use crate::syntax::ast::ModuleAST;
|
use crate::syntax::ast::ModuleAST;
|
||||||
|
|
||||||
impl Transpilable for ModuleAST {
|
impl Transpilable for ModuleAST<'_> {
|
||||||
/// Transpiles the whole AST into PHP, using this same trait on the
|
/// Transpiles the whole AST into PHP, using this same trait on the
|
||||||
/// nodes and leaves of the AST
|
/// nodes and leaves of the AST
|
||||||
fn transpile(&self) -> String {
|
fn transpile(&self) -> String {
|
||||||
@ -18,16 +18,24 @@ impl Transpilable for ModuleAST {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::syntax::ast::{var_binding::Binding, Expression, TopLevelDeclaration};
|
use crate::{
|
||||||
|
lexic::token::{Token, TokenType},
|
||||||
|
syntax::ast::{var_binding::Binding, Expression, TopLevelDeclaration},
|
||||||
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn module_ast_should_transpile() {
|
fn module_ast_should_transpile() {
|
||||||
let id = String::from("identifier");
|
let id = String::from("identifier");
|
||||||
|
let id_token = Token {
|
||||||
|
token_type: TokenType::Identifier,
|
||||||
|
value: id,
|
||||||
|
position: 0,
|
||||||
|
};
|
||||||
let value = String::from("322");
|
let value = String::from("322");
|
||||||
let binding = Binding {
|
let binding = Binding {
|
||||||
datatype: None,
|
datatype: None,
|
||||||
identifier: Box::new(id),
|
identifier: &id_token,
|
||||||
expression: Expression::Number(Box::new(value)),
|
expression: Expression::Number(&value),
|
||||||
is_mutable: false,
|
is_mutable: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ use crate::syntax::ast::statement::Statement;
|
|||||||
|
|
||||||
use super::Transpilable;
|
use super::Transpilable;
|
||||||
|
|
||||||
impl Transpilable for Statement {
|
impl Transpilable for Statement<'_> {
|
||||||
fn transpile(&self) -> String {
|
fn transpile(&self) -> String {
|
||||||
let stmt = match self {
|
let stmt = match self {
|
||||||
Statement::FunctionCall(f) => f.transpile(),
|
Statement::FunctionCall(f) => f.transpile(),
|
||||||
|
@ -2,11 +2,12 @@ use crate::syntax::ast::TopLevelDeclaration;
|
|||||||
|
|
||||||
use super::Transpilable;
|
use super::Transpilable;
|
||||||
|
|
||||||
impl Transpilable for TopLevelDeclaration {
|
impl Transpilable for TopLevelDeclaration<'_> {
|
||||||
fn transpile(&self) -> String {
|
fn transpile(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
TopLevelDeclaration::Binding(binding) => binding.transpile(),
|
TopLevelDeclaration::Binding(binding) => binding.transpile(),
|
||||||
TopLevelDeclaration::FunctionDeclaration(fun) => fun.transpile(),
|
TopLevelDeclaration::FunctionDeclaration(fun) => fun.transpile(),
|
||||||
|
_ => panic!("Not implemented: Expression at top level"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ pub enum TokenType {
|
|||||||
FUN,
|
FUN,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Token {
|
pub struct Token {
|
||||||
pub token_type: TokenType,
|
pub token_type: TokenType,
|
||||||
// The token as a raw string
|
// The token as a raw string
|
||||||
|
@ -13,7 +13,6 @@ mod lexic;
|
|||||||
mod semantic;
|
mod semantic;
|
||||||
// Transforms an AST to JS
|
// Transforms an AST to JS
|
||||||
mod codegen;
|
mod codegen;
|
||||||
mod utils;
|
|
||||||
|
|
||||||
mod error_handling;
|
mod error_handling;
|
||||||
|
|
||||||
|
@ -4,13 +4,13 @@ use crate::{
|
|||||||
syntax::ast::{ModuleAST, TopLevelDeclaration},
|
syntax::ast::{ModuleAST, TopLevelDeclaration},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::symbol_table::SymbolTable;
|
use super::symbol_table::{SymbolEntry, SymbolTable};
|
||||||
|
|
||||||
pub trait SemanticCheck {
|
pub trait SemanticCheck {
|
||||||
fn check_semantics(&self, scope: &SymbolTable) -> Result<(), MistiError>;
|
fn check_semantics(&self, scope: &SymbolTable) -> Result<(), MistiError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SemanticCheck for ModuleAST {
|
impl SemanticCheck for ModuleAST<'_> {
|
||||||
/// Checks that this AST is semantically correct, given a symbol table
|
/// Checks that this AST is semantically correct, given a symbol table
|
||||||
fn check_semantics(&self, scope: &SymbolTable) -> Result<(), MistiError> {
|
fn check_semantics(&self, scope: &SymbolTable) -> Result<(), MistiError> {
|
||||||
for declaration in &self.declarations {
|
for declaration in &self.declarations {
|
||||||
@ -21,28 +21,60 @@ impl SemanticCheck for ModuleAST {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SemanticCheck for TopLevelDeclaration {
|
impl SemanticCheck for TopLevelDeclaration<'_> {
|
||||||
fn check_semantics(&self, scope: &SymbolTable) -> Result<(), MistiError> {
|
fn check_semantics(&self, scope: &SymbolTable) -> Result<(), MistiError> {
|
||||||
match self {
|
match self {
|
||||||
TopLevelDeclaration::Binding(_) => {
|
TopLevelDeclaration::Binding(binding) => {
|
||||||
|
let binding_name = &binding.identifier.value;
|
||||||
|
|
||||||
|
if scope.test(binding_name) {
|
||||||
let error = SemanticError {
|
let error = SemanticError {
|
||||||
error_start: 0,
|
error_start: binding.identifier.position,
|
||||||
error_end: 0,
|
error_end: binding.identifier.get_end_position(),
|
||||||
reason: "Binding typechecking: Not implemented".into(),
|
reason: format!(
|
||||||
|
"Duplicated function: A function with name {} was already defined",
|
||||||
|
binding_name
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
Err(MistiError::Semantic(error))
|
return Err(MistiError::Semantic(error));
|
||||||
|
}
|
||||||
|
|
||||||
|
let datatype = match binding.datatype {
|
||||||
|
Some(t) => t,
|
||||||
|
None => {
|
||||||
|
let error = SemanticError {
|
||||||
|
error_start: binding.identifier.position,
|
||||||
|
error_end: binding.identifier.get_end_position(),
|
||||||
|
reason: format!(
|
||||||
|
"The variable `{}` didn't define a datatype. Datatype inference is not implemented.",
|
||||||
|
binding_name
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
return Err(MistiError::Semantic(error));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
scope.insert(
|
||||||
|
binding_name.clone(),
|
||||||
|
SymbolEntry::new_variable(datatype.value.clone()),
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
TopLevelDeclaration::FunctionDeclaration(function) => {
|
TopLevelDeclaration::FunctionDeclaration(function) => {
|
||||||
let function_name = function.identifier.as_ref().clone();
|
let function_name = function.identifier.value.clone();
|
||||||
|
|
||||||
|
// Check that the function is not already defined
|
||||||
if scope.test(&function_name) {
|
if scope.test(&function_name) {
|
||||||
let error = SemanticError {
|
let error = SemanticError {
|
||||||
// TODO: Get the position of the function name. For this, these structs
|
error_start: function.identifier.position,
|
||||||
// should store the token instead of just the string
|
error_end: function.identifier.get_end_position(),
|
||||||
error_start: 0,
|
reason: format!(
|
||||||
error_end: 0,
|
"Duplicated function: A function with name {} was already defined",
|
||||||
reason: format!("Function {} already defined", function_name),
|
function_name
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
return Err(MistiError::Semantic(error));
|
return Err(MistiError::Semantic(error));
|
||||||
@ -50,11 +82,12 @@ impl SemanticCheck for TopLevelDeclaration {
|
|||||||
|
|
||||||
scope.insert(
|
scope.insert(
|
||||||
function_name,
|
function_name,
|
||||||
super::symbol_table::SymbolEntry::Function(vec![], "Unit".into()),
|
SymbolEntry::new_function(vec![], "Unit".into()),
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
_ => panic!("Not implemented"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
use super::Expression;
|
use super::Expression;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FunctionCall {
|
pub struct FunctionCall<'a> {
|
||||||
pub function: Box<Expression>,
|
pub function: Box<Expression<'a>>,
|
||||||
pub arguments: Box<ArgumentsList>,
|
pub arguments: Box<ArgumentsList<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ArgumentsList {
|
pub struct ArgumentsList<'a> {
|
||||||
pub arguments: Vec<Expression>,
|
pub arguments: Vec<Expression<'a>>,
|
||||||
}
|
}
|
||||||
|
@ -1,46 +1,49 @@
|
|||||||
|
use crate::lexic::token::Token;
|
||||||
|
|
||||||
use self::functions::FunctionCall;
|
use self::functions::FunctionCall;
|
||||||
|
|
||||||
pub mod functions;
|
pub mod functions;
|
||||||
pub mod statement;
|
pub mod statement;
|
||||||
pub mod var_binding;
|
pub mod var_binding;
|
||||||
|
|
||||||
pub struct ModuleAST {
|
pub struct ModuleAST<'a> {
|
||||||
pub declarations: Vec<TopLevelDeclaration>,
|
pub declarations: Vec<TopLevelDeclaration<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum TopLevelDeclaration {
|
pub enum TopLevelDeclaration<'a> {
|
||||||
Binding(var_binding::Binding),
|
Binding(var_binding::Binding<'a>),
|
||||||
FunctionDeclaration(FunctionDeclaration),
|
FunctionDeclaration(FunctionDeclaration<'a>),
|
||||||
|
Expression(Expression<'a>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FunctionDeclaration {
|
pub struct FunctionDeclaration<'a> {
|
||||||
pub identifier: Box<String>,
|
pub identifier: &'a Token,
|
||||||
pub params_list: Box<ParamsList>,
|
pub params_list: Box<ParamsList>,
|
||||||
pub block: Box<Block>,
|
pub block: Box<Block<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Block {
|
pub struct Block<'a> {
|
||||||
pub statements: Vec<statement::Statement>,
|
pub statements: Vec<statement::Statement<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ParamsList {}
|
pub struct ParamsList {}
|
||||||
|
|
||||||
pub struct Parameter {
|
pub struct Parameter<'a> {
|
||||||
pub identifier: Box<String>,
|
pub identifier: &'a String,
|
||||||
pub datatype: Box<String>,
|
pub datatype: &'a String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Expression {
|
pub enum Expression<'a> {
|
||||||
Number(Box<String>),
|
Number(&'a String),
|
||||||
String(Box<String>),
|
String(&'a String),
|
||||||
Boolean(bool),
|
Boolean(bool),
|
||||||
Identifier(Box<String>),
|
Identifier(&'a String),
|
||||||
FunctionCall(FunctionCall),
|
FunctionCall(FunctionCall<'a>),
|
||||||
UnaryOperator(Box<String>, Box<Expression>),
|
UnaryOperator(&'a String, Box<Expression<'a>>),
|
||||||
BinaryOperator(Box<Expression>, Box<Expression>, Box<String>),
|
BinaryOperator(Box<Expression<'a>>, Box<Expression<'a>>, &'a String),
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use super::{functions::FunctionCall, var_binding::Binding};
|
use super::{functions::FunctionCall, var_binding::Binding};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Statement {
|
pub enum Statement<'a> {
|
||||||
FunctionCall(FunctionCall),
|
FunctionCall(FunctionCall<'a>),
|
||||||
Binding(Binding),
|
Binding(Binding<'a>),
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
|
use crate::lexic::token::Token;
|
||||||
|
|
||||||
use super::Expression;
|
use super::Expression;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Binding {
|
pub struct Binding<'a> {
|
||||||
pub datatype: Option<String>,
|
pub datatype: Option<&'a Token>,
|
||||||
pub identifier: Box<String>,
|
pub identifier: &'a Token,
|
||||||
pub expression: Expression,
|
pub expression: Expression<'a>,
|
||||||
pub is_mutable: bool,
|
pub is_mutable: bool,
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
use super::ast::var_binding::Binding;
|
use super::ast::var_binding::Binding;
|
||||||
use super::utils::{parse_token_type, try_operator};
|
use super::utils::{parse_token_type, try_operator};
|
||||||
use super::{expression, ParseResult};
|
use super::{expression, ParsingError, ParsingResult};
|
||||||
use crate::error_handling::SyntaxError;
|
use crate::error_handling::SyntaxError;
|
||||||
use crate::lexic::token::{Token, TokenType};
|
use crate::lexic::token::{Token, TokenType};
|
||||||
use crate::utils::Result3;
|
|
||||||
|
|
||||||
pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<Binding, ()> {
|
pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParsingResult<Binding> {
|
||||||
let mut current_pos = pos;
|
let mut current_pos = pos;
|
||||||
|
|
||||||
// TODO: Detect if the binding starts with a datatype
|
// TODO: Detect if the binding starts with a datatype
|
||||||
|
// TODO: Revert to val/var
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* let keyword
|
* let keyword
|
||||||
@ -16,14 +16,14 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<Binding,
|
|||||||
let (is_mutable, binding_token, next_pos) = {
|
let (is_mutable, binding_token, next_pos) = {
|
||||||
let let_token = parse_token_type(tokens, current_pos, TokenType::LET);
|
let let_token = parse_token_type(tokens, current_pos, TokenType::LET);
|
||||||
match let_token {
|
match let_token {
|
||||||
ParseResult::Ok(let_token, next_let) => {
|
Ok((let_token, next_let)) => {
|
||||||
let mut_token = parse_token_type(tokens, next_let, TokenType::MUT);
|
let mut_token = parse_token_type(tokens, next_let, TokenType::MUT);
|
||||||
match mut_token {
|
match mut_token {
|
||||||
ParseResult::Ok(_mut_token, next_mut) => (true, let_token, next_mut),
|
Ok((_mut_token, next_mut)) => (true, let_token, next_mut),
|
||||||
_ => (false, let_token, next_let),
|
_ => (false, let_token, next_let),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => return ParseResult::Unmatched,
|
_ => return Err(ParsingError::Unmatched),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
@ -33,28 +33,28 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<Binding,
|
|||||||
*/
|
*/
|
||||||
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)
|
||||||
{
|
{
|
||||||
ParseResult::Ok(t, n) => (t, n),
|
Ok((t, n)) => (t, n),
|
||||||
ParseResult::Mismatch(token) => {
|
Err(ParsingError::Mismatch(token)) => {
|
||||||
// The parser found a token, but it's not an identifier
|
// The parser found a token, but it's not an identifier
|
||||||
return ParseResult::Err(SyntaxError {
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
error_start: token.position,
|
error_start: token.position,
|
||||||
error_end: token.get_end_position(),
|
error_end: token.get_end_position(),
|
||||||
reason: "??".into(),
|
reason: "??".into(),
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
ParseResult::Err(error) => {
|
Err(ParsingError::Err(error)) => {
|
||||||
return ParseResult::Err(error);
|
return Err(ParsingError::Err(error));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// The parser didn't find an Identifier after VAL/VAR
|
// The parser didn't find an Identifier after VAL/VAR
|
||||||
return ParseResult::Err(SyntaxError {
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
reason: format!(
|
reason: format!(
|
||||||
"There should be an identifier after a `{}` token",
|
"There should be an identifier after a `{}` token",
|
||||||
if is_mutable { "val" } else { "var" }
|
if is_mutable { "val" } else { "var" }
|
||||||
),
|
),
|
||||||
error_start: binding_token.position,
|
error_start: binding_token.position,
|
||||||
error_end: binding_token.get_end_position(),
|
error_end: binding_token.get_end_position(),
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
@ -63,67 +63,67 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<Binding,
|
|||||||
* Equal (=) operator
|
* Equal (=) operator
|
||||||
*/
|
*/
|
||||||
let equal_operator = match try_operator(tokens, current_pos, String::from("=")) {
|
let equal_operator = match try_operator(tokens, current_pos, String::from("=")) {
|
||||||
Result3::Ok(t) => t,
|
Ok((t, _)) => t,
|
||||||
Result3::Err(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
|
||||||
return ParseResult::Err(SyntaxError {
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
reason: format!("There should be an equal sign `=` after the identifier"),
|
reason: format!("There should be an equal sign `=` after the identifier"),
|
||||||
error_start: t.position,
|
error_start: t.position,
|
||||||
error_end: t.get_end_position(),
|
error_end: t.get_end_position(),
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
Result3::None => {
|
_ => {
|
||||||
// The parser didn't find the `=` operator after the identifier
|
// The parser didn't find the `=` operator after the identifier
|
||||||
return ParseResult::Err(SyntaxError {
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
reason: format!("There should be an equal sign `=` after the identifier",),
|
reason: format!("There should be an equal sign `=` after the identifier",),
|
||||||
error_start: identifier.position,
|
error_start: identifier.position,
|
||||||
error_end: identifier.get_end_position(),
|
error_end: identifier.get_end_position(),
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
current_pos += 1;
|
current_pos += 1;
|
||||||
|
|
||||||
let (expression, next_pos) = match expression::try_parse(tokens, current_pos) {
|
let (expression, next_pos) = match expression::try_parse(tokens, current_pos) {
|
||||||
ParseResult::Ok(exp, next) => (exp, next),
|
Ok((exp, next)) => (exp, next),
|
||||||
_ => {
|
_ => {
|
||||||
return ParseResult::Err(SyntaxError {
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
reason: String::from("Expected an expression after the equal `=` operator"),
|
reason: String::from("Expected an expression after the equal `=` operator"),
|
||||||
error_start: equal_operator.position,
|
error_start: equal_operator.position,
|
||||||
error_end: equal_operator.get_end_position(),
|
error_end: equal_operator.get_end_position(),
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
|
|
||||||
let binding = Binding {
|
let binding = Binding {
|
||||||
datatype: None,
|
datatype: None,
|
||||||
identifier: Box::new(identifier.value.clone()),
|
identifier: &identifier,
|
||||||
expression,
|
expression,
|
||||||
is_mutable,
|
is_mutable,
|
||||||
};
|
};
|
||||||
|
|
||||||
ParseResult::Ok(binding, current_pos)
|
Ok((binding, current_pos))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{lexic::get_tokens, syntax::utils::try_token_type};
|
use crate::{lexic::get_tokens, syntax::utils::parse_token_type};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_parse_val_binding() {
|
fn should_parse_val_binding() {
|
||||||
let tokens = get_tokens(&String::from("let identifier = 20")).unwrap();
|
let tokens = get_tokens(&String::from("let identifier = 20")).unwrap();
|
||||||
let ParseResult::Ok(binding, _) = try_parse(&tokens, 0) else {
|
let Ok((binding, _)) = try_parse(&tokens, 0) else {
|
||||||
panic!()
|
panic!()
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!("identifier", format!("{}", binding.identifier));
|
assert_eq!("identifier", format!("{}", binding.identifier.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_parse_val() {
|
fn should_parse_val() {
|
||||||
let tokens = get_tokens(&String::from("let")).unwrap();
|
let tokens = get_tokens(&String::from("let")).unwrap();
|
||||||
let token = *try_token_type(&tokens, 0, TokenType::LET).unwrap();
|
let (token, _) = parse_token_type(&tokens, 0, TokenType::LET).unwrap();
|
||||||
|
|
||||||
assert_eq!(TokenType::LET, token.token_type);
|
assert_eq!(TokenType::LET, token.token_type);
|
||||||
assert_eq!("let", token.value);
|
assert_eq!("let", token.value);
|
||||||
@ -132,7 +132,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_parse_identifier() {
|
fn should_parse_identifier() {
|
||||||
let tokens = get_tokens(&String::from("identifier")).unwrap();
|
let tokens = get_tokens(&String::from("identifier")).unwrap();
|
||||||
let token = *try_token_type(&tokens, 0, TokenType::Identifier).unwrap();
|
let (token, _) = parse_token_type(&tokens, 0, TokenType::Identifier).unwrap();
|
||||||
|
|
||||||
assert_eq!("identifier", token.value);
|
assert_eq!("identifier", token.value);
|
||||||
}
|
}
|
||||||
@ -140,7 +140,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_parse_operator() {
|
fn should_parse_operator() {
|
||||||
let tokens = get_tokens(&String::from("=")).unwrap();
|
let tokens = get_tokens(&String::from("=")).unwrap();
|
||||||
let token = *try_operator(&tokens, 0, String::from("=")).unwrap();
|
let (token, _) = try_operator(&tokens, 0, String::from("=")).unwrap();
|
||||||
|
|
||||||
assert_eq!("=", token.value);
|
assert_eq!("=", token.value);
|
||||||
}
|
}
|
||||||
@ -174,7 +174,7 @@ mod tests {
|
|||||||
let binding = try_parse(&tokens, 0);
|
let binding = try_parse(&tokens, 0);
|
||||||
|
|
||||||
match binding {
|
match binding {
|
||||||
ParseResult::Err(error) => {
|
Err(ParsingError::Err(error)) => {
|
||||||
assert_eq!(0, error.error_start);
|
assert_eq!(0, error.error_start);
|
||||||
assert_eq!(3, error.error_end);
|
assert_eq!(3, error.error_end);
|
||||||
}
|
}
|
||||||
@ -190,7 +190,7 @@ mod tests {
|
|||||||
let binding = try_parse(&tokens, 0);
|
let binding = try_parse(&tokens, 0);
|
||||||
|
|
||||||
match binding {
|
match binding {
|
||||||
ParseResult::Err(error) => {
|
Err(ParsingError::Err(error)) => {
|
||||||
assert_eq!(4, error.error_start);
|
assert_eq!(4, error.error_start);
|
||||||
assert_eq!(7, error.error_end);
|
assert_eq!(7, error.error_end);
|
||||||
}
|
}
|
||||||
@ -201,7 +201,7 @@ mod tests {
|
|||||||
let binding = try_parse(&tokens, 0);
|
let binding = try_parse(&tokens, 0);
|
||||||
|
|
||||||
match binding {
|
match binding {
|
||||||
ParseResult::Err(error) => {
|
Err(ParsingError::Err(error)) => {
|
||||||
assert_eq!(4, error.error_start);
|
assert_eq!(4, error.error_start);
|
||||||
assert_eq!(11, error.error_end);
|
assert_eq!(11, error.error_end);
|
||||||
}
|
}
|
||||||
@ -215,7 +215,7 @@ mod tests {
|
|||||||
let binding = try_parse(&tokens, 0);
|
let binding = try_parse(&tokens, 0);
|
||||||
|
|
||||||
match binding {
|
match binding {
|
||||||
ParseResult::Err(error) => {
|
Err(ParsingError::Err(error)) => {
|
||||||
assert_eq!(7, error.error_start);
|
assert_eq!(7, error.error_start);
|
||||||
assert_eq!(14, error.error_end);
|
assert_eq!(14, error.error_end);
|
||||||
}
|
}
|
||||||
|
@ -3,19 +3,13 @@ use crate::{
|
|||||||
lexic::token::{Token, TokenType},
|
lexic::token::{Token, TokenType},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{ast::Block, utils::parse_token_type, ParseResult};
|
use super::{ast::Block, utils::parse_token_type, ParsingError, ParsingResult};
|
||||||
|
|
||||||
// Assumes that the token at `pos` is a {
|
// Assumes that the token at `pos` is a {
|
||||||
pub fn parse_block<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<Block, &Token> {
|
pub fn parse_block<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParsingResult<Block> {
|
||||||
let mut current_pos = pos;
|
let mut current_pos = pos;
|
||||||
|
|
||||||
let (opening_brace, next_pos) =
|
let (opening_brace, next_pos) = parse_token_type(tokens, current_pos, TokenType::LeftBrace)?;
|
||||||
match parse_token_type(tokens, current_pos, TokenType::LeftBrace) {
|
|
||||||
ParseResult::Ok(t, next) => (t, next),
|
|
||||||
ParseResult::Err(err) => return ParseResult::Err(err),
|
|
||||||
ParseResult::Mismatch(t) => return ParseResult::Mismatch(t),
|
|
||||||
ParseResult::Unmatched => return ParseResult::Unmatched,
|
|
||||||
};
|
|
||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
|
|
||||||
// Parse block statements
|
// Parse block statements
|
||||||
@ -23,13 +17,12 @@ pub fn parse_block<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<Block,
|
|||||||
|
|
||||||
// First statement
|
// First statement
|
||||||
match super::statement::try_parse(tokens, current_pos) {
|
match super::statement::try_parse(tokens, current_pos) {
|
||||||
ParseResult::Ok(statement, next_pos) => {
|
Ok((statement, next_pos)) => {
|
||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
statements.push(statement);
|
statements.push(statement);
|
||||||
}
|
}
|
||||||
ParseResult::Err(err) => return ParseResult::Err(err),
|
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
||||||
ParseResult::Unmatched => {}
|
_ => {}
|
||||||
ParseResult::Mismatch(_) => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// More statements separated by new lines
|
// More statements separated by new lines
|
||||||
@ -40,11 +33,11 @@ pub fn parse_block<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<Block,
|
|||||||
current_pos += 1;
|
current_pos += 1;
|
||||||
|
|
||||||
match super::statement::try_parse(tokens, current_pos) {
|
match super::statement::try_parse(tokens, current_pos) {
|
||||||
ParseResult::Ok(statement, next_pos) => {
|
Ok((statement, next_pos)) => {
|
||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
statements.push(statement);
|
statements.push(statement);
|
||||||
}
|
}
|
||||||
ParseResult::Err(err) => return ParseResult::Err(err),
|
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
||||||
_ => break,
|
_ => break,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -52,26 +45,26 @@ pub fn parse_block<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<Block,
|
|||||||
// Parse closing brace
|
// Parse closing brace
|
||||||
let (_closing_brace, next_pos) =
|
let (_closing_brace, next_pos) =
|
||||||
match parse_token_type(tokens, current_pos, TokenType::RightBrace) {
|
match parse_token_type(tokens, current_pos, TokenType::RightBrace) {
|
||||||
ParseResult::Ok(t, next) => (t, next),
|
Ok((t, next)) => (t, next),
|
||||||
ParseResult::Err(err) => return ParseResult::Err(err),
|
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
||||||
ParseResult::Mismatch(t) => {
|
Err(ParsingError::Mismatch(t)) => {
|
||||||
return ParseResult::Err(SyntaxError {
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
reason: String::from("Expected a closing brace after the block body."),
|
reason: String::from("Expected a closing brace after the block body."),
|
||||||
error_start: t.position,
|
error_start: t.position,
|
||||||
error_end: t.get_end_position(),
|
error_end: t.get_end_position(),
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
ParseResult::Unmatched => {
|
Err(ParsingError::Unmatched) => {
|
||||||
return ParseResult::Err(SyntaxError {
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
reason: String::from("Expected a closing brace after the block body."),
|
reason: String::from("Expected a closing brace after the block body."),
|
||||||
error_start: opening_brace.position,
|
error_start: opening_brace.position,
|
||||||
error_end: opening_brace.get_end_position(),
|
error_end: opening_brace.get_end_position(),
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
|
|
||||||
ParseResult::Ok(Block { statements }, current_pos)
|
Ok((Block { statements }, current_pos))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -85,7 +78,7 @@ mod tests {
|
|||||||
let block = parse_block(&tokens, 0);
|
let block = parse_block(&tokens, 0);
|
||||||
|
|
||||||
let block = match block {
|
let block = match block {
|
||||||
ParseResult::Ok(p, _) => p,
|
ParsingResult::Ok((p, _)) => p,
|
||||||
_ => panic!("Expected a block, got: {:?}", block),
|
_ => panic!("Expected a block, got: {:?}", block),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -98,7 +91,7 @@ mod tests {
|
|||||||
let block = parse_block(&tokens, 0);
|
let block = parse_block(&tokens, 0);
|
||||||
|
|
||||||
let block = match block {
|
let block = match block {
|
||||||
ParseResult::Ok(p, _) => p,
|
ParsingResult::Ok((p, _)) => p,
|
||||||
_ => panic!("Expected a block, got: {:?}", block),
|
_ => panic!("Expected a block, got: {:?}", block),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -111,7 +104,7 @@ mod tests {
|
|||||||
let block = parse_block(&tokens, 0);
|
let block = parse_block(&tokens, 0);
|
||||||
|
|
||||||
let block = match block {
|
let block = match block {
|
||||||
ParseResult::Ok(p, _) => p,
|
ParsingResult::Ok((p, _)) => p,
|
||||||
_ => {
|
_ => {
|
||||||
panic!("Expected a block, got: {:?}\n\n{:?}", block, tokens)
|
panic!("Expected a block, got: {:?}\n\n{:?}", block, tokens)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
lexic::token::Token,
|
lexic::token::Token,
|
||||||
syntax::{ast::Expression, ParseResult},
|
syntax::{ast::Expression, ParsingError, ParsingResult},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Parses a factor expression.
|
/// Parses a factor expression.
|
||||||
@ -8,20 +8,20 @@ use crate::{
|
|||||||
/// ```ebnf
|
/// ```ebnf
|
||||||
/// comparison = term, ((">" | ">=" | "<" | "<="), term)*;
|
/// comparison = term, ((">" | ">=" | "<" | "<="), term)*;
|
||||||
/// ```
|
/// ```
|
||||||
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()> {
|
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParsingResult<Expression> {
|
||||||
let (term, next_pos) = match super::term::try_parse(tokens, pos) {
|
let (term, next_pos) = match super::term::try_parse(tokens, pos) {
|
||||||
ParseResult::Ok(expr, next_pos) => (expr, next_pos),
|
Ok((expr, next_pos)) => (expr, next_pos),
|
||||||
_ => return ParseResult::Unmatched,
|
_ => return Err(ParsingError::Unmatched),
|
||||||
};
|
};
|
||||||
|
|
||||||
parse_many(tokens, next_pos, term)
|
parse_many(tokens, next_pos, term)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_many(
|
fn parse_many<'a>(
|
||||||
tokens: &Vec<Token>,
|
tokens: &'a Vec<Token>,
|
||||||
pos: usize,
|
pos: usize,
|
||||||
prev_expr: Expression,
|
prev_expr: Expression<'a>,
|
||||||
) -> ParseResult<Expression, ()> {
|
) -> ParsingResult<'a, Expression<'a>> {
|
||||||
// comparison = term, ((">" | ">=" | "<" | "<="), term)*;
|
// comparison = term, ((">" | ">=" | "<" | "<="), term)*;
|
||||||
|
|
||||||
match tokens.get(pos) {
|
match tokens.get(pos) {
|
||||||
@ -32,18 +32,18 @@ fn parse_many(
|
|||||||
|| token.value == ">=" =>
|
|| token.value == ">=" =>
|
||||||
{
|
{
|
||||||
match super::term::try_parse(tokens, pos + 1) {
|
match super::term::try_parse(tokens, pos + 1) {
|
||||||
ParseResult::Ok(expr, next_pos) => {
|
Ok((expr, next_pos)) => {
|
||||||
let expr = Expression::BinaryOperator(
|
let expr = Expression::BinaryOperator(
|
||||||
Box::new(prev_expr),
|
Box::new(prev_expr),
|
||||||
Box::new(expr),
|
Box::new(expr),
|
||||||
Box::new(token.value.clone()),
|
&token.value,
|
||||||
);
|
);
|
||||||
|
|
||||||
parse_many(tokens, next_pos, expr)
|
parse_many(tokens, next_pos, expr)
|
||||||
}
|
}
|
||||||
_ => ParseResult::Unmatched,
|
_ => Err(ParsingError::Unmatched),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => ParseResult::Ok(prev_expr, pos),
|
_ => Ok((prev_expr, pos)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
lexic::token::Token,
|
lexic::token::Token,
|
||||||
syntax::{ast::Expression, ParseResult},
|
syntax::{ast::Expression, ParsingError, ParsingResult},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Parses a factor expression.
|
/// Parses a factor expression.
|
||||||
@ -8,37 +8,37 @@ use crate::{
|
|||||||
/// ```ebnf
|
/// ```ebnf
|
||||||
/// equality = comparison, (("==" | "!="), comparison )*;
|
/// equality = comparison, (("==" | "!="), comparison )*;
|
||||||
/// ```
|
/// ```
|
||||||
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()> {
|
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParsingResult<Expression> {
|
||||||
let (comparison, next_pos) = match super::comparison::try_parse(tokens, pos) {
|
let (comparison, next_pos) = match super::comparison::try_parse(tokens, pos) {
|
||||||
ParseResult::Ok(expr, next_pos) => (expr, next_pos),
|
Ok((expr, next_pos)) => (expr, next_pos),
|
||||||
_ => return ParseResult::Unmatched,
|
_ => return Err(ParsingError::Unmatched),
|
||||||
};
|
};
|
||||||
|
|
||||||
parse_many(tokens, next_pos, comparison)
|
parse_many(tokens, next_pos, comparison)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_many(
|
fn parse_many<'a>(
|
||||||
tokens: &Vec<Token>,
|
tokens: &'a Vec<Token>,
|
||||||
pos: usize,
|
pos: usize,
|
||||||
prev_expr: Expression,
|
prev_expr: Expression<'a>,
|
||||||
) -> ParseResult<Expression, ()> {
|
) -> ParsingResult<'a, Expression<'a>> {
|
||||||
// equality = comparison, (("==" | "!="), comparison )*;
|
// equality = comparison, (("==" | "!="), comparison )*;
|
||||||
|
|
||||||
match tokens.get(pos) {
|
match tokens.get(pos) {
|
||||||
Some(token) if token.value == "==" || token.value == "!=" => {
|
Some(token) if token.value == "==" || token.value == "!=" => {
|
||||||
match super::comparison::try_parse(tokens, pos + 1) {
|
match super::comparison::try_parse(tokens, pos + 1) {
|
||||||
ParseResult::Ok(expr, next_pos) => {
|
Ok((expr, next_pos)) => {
|
||||||
let expr = Expression::BinaryOperator(
|
let expr = Expression::BinaryOperator(
|
||||||
Box::new(prev_expr),
|
Box::new(prev_expr),
|
||||||
Box::new(expr),
|
Box::new(expr),
|
||||||
Box::new(token.value.clone()),
|
&token.value,
|
||||||
);
|
);
|
||||||
|
|
||||||
parse_many(tokens, next_pos, expr)
|
parse_many(tokens, next_pos, expr)
|
||||||
}
|
}
|
||||||
_ => ParseResult::Unmatched,
|
_ => Err(ParsingError::Unmatched),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => ParseResult::Ok(prev_expr, pos),
|
_ => Ok((prev_expr, pos)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
lexic::token::Token,
|
lexic::token::Token,
|
||||||
syntax::{ast::Expression, ParseResult},
|
syntax::{ast::Expression, ParsingError, ParsingResult},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Parses a factor expression.
|
/// Parses a factor expression.
|
||||||
@ -8,37 +8,37 @@ use crate::{
|
|||||||
/// ```ebnf
|
/// ```ebnf
|
||||||
/// factor = unary, (("/" | "*"), unary)*;
|
/// factor = unary, (("/" | "*"), unary)*;
|
||||||
/// ```
|
/// ```
|
||||||
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()> {
|
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParsingResult<Expression> {
|
||||||
let (unary, next_pos) = match super::unary::try_parse(tokens, pos) {
|
let (unary, next_pos) = match super::unary::try_parse(tokens, pos) {
|
||||||
ParseResult::Ok(expr, next_pos) => (expr, next_pos),
|
Ok((expr, next_pos)) => (expr, next_pos),
|
||||||
_ => return ParseResult::Unmatched,
|
_ => return Err(ParsingError::Unmatched),
|
||||||
};
|
};
|
||||||
|
|
||||||
parse_many(tokens, next_pos, unary)
|
parse_many(tokens, next_pos, unary)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_many(
|
fn parse_many<'a>(
|
||||||
tokens: &Vec<Token>,
|
tokens: &'a Vec<Token>,
|
||||||
pos: usize,
|
pos: usize,
|
||||||
prev_expr: Expression,
|
prev_expr: Expression<'a>,
|
||||||
) -> ParseResult<Expression, ()> {
|
) -> ParsingResult<'a, Expression<'a>> {
|
||||||
// (("/" | "*"), unary)*
|
// (("/" | "*"), unary)*
|
||||||
|
|
||||||
match tokens.get(pos) {
|
match tokens.get(pos) {
|
||||||
Some(token) if token.value == "/" || token.value == "*" => {
|
Some(token) if token.value == "/" || token.value == "*" => {
|
||||||
match super::unary::try_parse(tokens, pos + 1) {
|
match super::unary::try_parse(tokens, pos + 1) {
|
||||||
ParseResult::Ok(expr, next_pos) => {
|
Ok((expr, next_pos)) => {
|
||||||
let expr = Expression::BinaryOperator(
|
let expr = Expression::BinaryOperator(
|
||||||
Box::new(prev_expr),
|
Box::new(prev_expr),
|
||||||
Box::new(expr),
|
Box::new(expr),
|
||||||
Box::new(token.value.clone()),
|
&token.value,
|
||||||
);
|
);
|
||||||
|
|
||||||
parse_many(tokens, next_pos, expr)
|
parse_many(tokens, next_pos, expr)
|
||||||
}
|
}
|
||||||
_ => ParseResult::Unmatched,
|
_ => Err(ParsingError::Unmatched),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => ParseResult::Ok(prev_expr, pos),
|
_ => Ok((prev_expr, pos)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ use crate::{
|
|||||||
syntax::{
|
syntax::{
|
||||||
ast::{functions::FunctionCall, Expression},
|
ast::{functions::FunctionCall, Expression},
|
||||||
functions::arguments_list,
|
functions::arguments_list,
|
||||||
ParseResult,
|
ParsingError, ParsingResult,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -13,18 +13,18 @@ use crate::{
|
|||||||
/// function call expr = primary, "(", (arguments list)?, ")"
|
/// function call expr = primary, "(", (arguments list)?, ")"
|
||||||
/// | primary;
|
/// | primary;
|
||||||
/// ```
|
/// ```
|
||||||
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()> {
|
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParsingResult<Expression> {
|
||||||
let (primary_expr, next_pos) = match super::primary::try_parse(tokens, pos) {
|
let (primary_expr, next_pos) = match super::primary::try_parse(tokens, pos) {
|
||||||
ParseResult::Ok(expr, next_pos) => (expr, next_pos),
|
Ok((expr, next_pos)) => (expr, next_pos),
|
||||||
_ => return ParseResult::Unmatched,
|
_ => return Err(ParsingError::Unmatched),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Parse arguments list
|
// Parse arguments list
|
||||||
let (arguments, next_pos) = match arguments_list::try_parse(tokens, next_pos) {
|
let (arguments, next_pos) = match arguments_list::try_parse(tokens, next_pos) {
|
||||||
ParseResult::Ok(args, next) => (args, next),
|
Ok((args, next)) => (args, next),
|
||||||
ParseResult::Err(err) => return ParseResult::Err(err),
|
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
||||||
_ => {
|
_ => {
|
||||||
return ParseResult::Ok(primary_expr, next_pos);
|
return Ok((primary_expr, next_pos));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()>
|
|||||||
arguments: Box::new(arguments),
|
arguments: Box::new(arguments),
|
||||||
};
|
};
|
||||||
|
|
||||||
ParseResult::Ok(Expression::FunctionCall(fun_call), next_pos)
|
Ok((Expression::FunctionCall(fun_call), next_pos))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use super::{ast::Expression, ParseResult};
|
use super::{ast::Expression, ParsingResult};
|
||||||
use crate::lexic::token::Token;
|
use crate::lexic::token::Token;
|
||||||
|
|
||||||
mod comparison;
|
mod comparison;
|
||||||
@ -10,8 +10,8 @@ mod term;
|
|||||||
mod unary;
|
mod unary;
|
||||||
|
|
||||||
/// Expression is defined in the grammar.
|
/// Expression is defined in the grammar.
|
||||||
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()> {
|
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParsingResult<Expression> {
|
||||||
return equality::try_parse(tokens, pos);
|
equality::try_parse(tokens, pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use super::super::utils::Tokenizer;
|
use super::super::utils::Tokenizer;
|
||||||
use crate::{
|
use crate::{
|
||||||
lexic::token::{Token, TokenType},
|
lexic::token::{Token, TokenType},
|
||||||
syntax::{ast::Expression, ParseResult},
|
syntax::{ast::Expression, ParsingError, ParsingResult},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// This grammar may not be up to date. Refer to the spec for the latest grammar.
|
/// This grammar may not be up to date. Refer to the spec for the latest grammar.
|
||||||
@ -9,42 +9,33 @@ use crate::{
|
|||||||
/// ```ebnf
|
/// ```ebnf
|
||||||
/// primary = number | string | boolean | identifier | ("(", expression, ")");
|
/// primary = number | string | boolean | identifier | ("(", expression, ")");
|
||||||
/// ```
|
/// ```
|
||||||
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()> {
|
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParsingResult<Expression> {
|
||||||
match tokens.get_significant(pos) {
|
match tokens.get_significant(pos) {
|
||||||
Some((token, token_pos)) => match token.token_type {
|
Some((token, token_pos)) => match token.token_type {
|
||||||
TokenType::Number => ParseResult::Ok(
|
TokenType::Number => Ok((Expression::Number(&token.value), token_pos + 1)),
|
||||||
Expression::Number(Box::new(token.value.clone())),
|
TokenType::String => Ok((Expression::String(&token.value), token_pos + 1)),
|
||||||
token_pos + 1,
|
|
||||||
),
|
|
||||||
TokenType::String => ParseResult::Ok(
|
|
||||||
Expression::String(Box::new(token.value.clone())),
|
|
||||||
token_pos + 1,
|
|
||||||
),
|
|
||||||
TokenType::Identifier if token.value == "true" || token.value == "false" => {
|
TokenType::Identifier if token.value == "true" || token.value == "false" => {
|
||||||
ParseResult::Ok(Expression::Boolean(token.value == "true"), token_pos + 1)
|
Ok((Expression::Boolean(token.value == "true"), token_pos + 1))
|
||||||
}
|
}
|
||||||
TokenType::Identifier => ParseResult::Ok(
|
TokenType::Identifier => Ok((Expression::Identifier(&token.value), token_pos + 1)),
|
||||||
Expression::Identifier(Box::new(token.value.clone())),
|
|
||||||
token_pos + 1,
|
|
||||||
),
|
|
||||||
TokenType::LeftParen => parse_parenthesized_expression(tokens, token_pos),
|
TokenType::LeftParen => parse_parenthesized_expression(tokens, token_pos),
|
||||||
_ => ParseResult::Unmatched,
|
_ => Err(ParsingError::Unmatched),
|
||||||
},
|
},
|
||||||
None => ParseResult::Unmatched,
|
None => Err(ParsingError::Unmatched),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_parenthesized_expression(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()> {
|
fn parse_parenthesized_expression(tokens: &Vec<Token>, pos: usize) -> ParsingResult<Expression> {
|
||||||
let expression = super::try_parse(tokens, pos + 1);
|
let expression = super::try_parse(tokens, pos + 1);
|
||||||
match expression {
|
match expression {
|
||||||
ParseResult::Ok(expression, next_pos) => match tokens.get(next_pos) {
|
Ok((expression, next_pos)) => match tokens.get(next_pos) {
|
||||||
Some(token) => match token.token_type {
|
Some(token) => match token.token_type {
|
||||||
TokenType::RightParen => ParseResult::Ok(expression, next_pos + 1),
|
TokenType::RightParen => Ok((expression, next_pos + 1)),
|
||||||
_ => ParseResult::Unmatched,
|
_ => Err(ParsingError::Unmatched),
|
||||||
},
|
},
|
||||||
None => ParseResult::Unmatched,
|
None => Err(ParsingError::Unmatched),
|
||||||
},
|
},
|
||||||
_ => ParseResult::Unmatched,
|
_ => Err(ParsingError::Unmatched),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,7 +50,9 @@ mod tests {
|
|||||||
let expression = try_parse(&tokens, 0);
|
let expression = try_parse(&tokens, 0);
|
||||||
|
|
||||||
match expression {
|
match expression {
|
||||||
ParseResult::Ok(Expression::Number(value), _) => assert_eq!("40", format!("{}", value)),
|
Ok((Expression::Number(value), _)) => {
|
||||||
|
assert_eq!("40", format!("{}", value))
|
||||||
|
}
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -70,7 +63,7 @@ mod tests {
|
|||||||
let expression = try_parse(&tokens, 0);
|
let expression = try_parse(&tokens, 0);
|
||||||
|
|
||||||
match expression {
|
match expression {
|
||||||
ParseResult::Ok(Expression::String(value), _) => {
|
Ok((Expression::String(value), _)) => {
|
||||||
assert_eq!("\"Hello\"", format!("{}", value))
|
assert_eq!("\"Hello\"", format!("{}", value))
|
||||||
}
|
}
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
@ -83,7 +76,7 @@ mod tests {
|
|||||||
let expression = try_parse(&tokens, 0);
|
let expression = try_parse(&tokens, 0);
|
||||||
|
|
||||||
match expression {
|
match expression {
|
||||||
ParseResult::Ok(Expression::Boolean(value), _) => assert!(value),
|
Ok((Expression::Boolean(value), _)) => assert!(value),
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -94,7 +87,7 @@ mod tests {
|
|||||||
let expression = try_parse(&tokens, 0);
|
let expression = try_parse(&tokens, 0);
|
||||||
|
|
||||||
match expression {
|
match expression {
|
||||||
ParseResult::Ok(Expression::Identifier(value), _) => {
|
Ok((Expression::Identifier(value), _)) => {
|
||||||
assert_eq!("someIdentifier", format!("{}", value))
|
assert_eq!("someIdentifier", format!("{}", value))
|
||||||
}
|
}
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
@ -107,7 +100,7 @@ mod tests {
|
|||||||
let expression = try_parse(&tokens, 0);
|
let expression = try_parse(&tokens, 0);
|
||||||
|
|
||||||
match expression {
|
match expression {
|
||||||
ParseResult::Ok(Expression::Identifier(value), _) => {
|
Ok((Expression::Identifier(value), _)) => {
|
||||||
assert_eq!("identifier", format!("{}", value))
|
assert_eq!("identifier", format!("{}", value))
|
||||||
}
|
}
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
lexic::token::Token,
|
lexic::token::Token,
|
||||||
syntax::{ast::Expression, ParseResult},
|
syntax::{ast::Expression, ParsingError, ParsingResult},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Parses a factor expression.
|
/// Parses a factor expression.
|
||||||
@ -8,37 +8,37 @@ use crate::{
|
|||||||
/// ```ebnf
|
/// ```ebnf
|
||||||
/// term = factor, (("-" | "+"), factor)*;
|
/// term = factor, (("-" | "+"), factor)*;
|
||||||
/// ```
|
/// ```
|
||||||
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()> {
|
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParsingResult<Expression> {
|
||||||
let (factor, next_pos) = match super::factor::try_parse(tokens, pos) {
|
let (factor, next_pos) = match super::factor::try_parse(tokens, pos) {
|
||||||
ParseResult::Ok(expr, next_pos) => (expr, next_pos),
|
Ok((expr, next_pos)) => (expr, next_pos),
|
||||||
_ => return ParseResult::Unmatched,
|
_ => return Err(ParsingError::Unmatched),
|
||||||
};
|
};
|
||||||
|
|
||||||
parse_many(tokens, next_pos, factor)
|
parse_many(tokens, next_pos, factor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_many(
|
fn parse_many<'a>(
|
||||||
tokens: &Vec<Token>,
|
tokens: &'a Vec<Token>,
|
||||||
pos: usize,
|
pos: usize,
|
||||||
prev_expr: Expression,
|
prev_expr: Expression<'a>,
|
||||||
) -> ParseResult<Expression, ()> {
|
) -> ParsingResult<'a, Expression<'a>> {
|
||||||
// term = factor, (("-" | "+"), factor)*;
|
// term = factor, (("-" | "+"), factor)*;
|
||||||
|
|
||||||
match tokens.get(pos) {
|
match tokens.get(pos) {
|
||||||
Some(token) if token.value == "+" || token.value == "-" => {
|
Some(token) if token.value == "+" || token.value == "-" => {
|
||||||
match super::factor::try_parse(tokens, pos + 1) {
|
match super::factor::try_parse(tokens, pos + 1) {
|
||||||
ParseResult::Ok(expr, next_pos) => {
|
Ok((expr, next_pos)) => {
|
||||||
let expr = Expression::BinaryOperator(
|
let expr = Expression::BinaryOperator(
|
||||||
Box::new(prev_expr),
|
Box::new(prev_expr),
|
||||||
Box::new(expr),
|
Box::new(expr),
|
||||||
Box::new(token.value.clone()),
|
&token.value,
|
||||||
);
|
);
|
||||||
|
|
||||||
parse_many(tokens, next_pos, expr)
|
parse_many(tokens, next_pos, expr)
|
||||||
}
|
}
|
||||||
_ => ParseResult::Unmatched,
|
_ => Err(ParsingError::Unmatched),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => ParseResult::Ok(prev_expr, pos),
|
_ => Ok((prev_expr, pos)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
lexic::token::Token,
|
lexic::token::Token,
|
||||||
syntax::{ast::Expression, ParseResult},
|
syntax::{ast::Expression, ParsingError, ParsingResult},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::function_call_expr;
|
use super::function_call_expr;
|
||||||
@ -11,15 +11,15 @@ use super::function_call_expr;
|
|||||||
/// unary = ("!" | "-"), expression
|
/// unary = ("!" | "-"), expression
|
||||||
/// | function call expr;
|
/// | function call expr;
|
||||||
/// ```
|
/// ```
|
||||||
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()> {
|
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParsingResult<Expression> {
|
||||||
match tokens.get(pos) {
|
match tokens.get(pos) {
|
||||||
Some(token) if token.value == "!" || token.value == "-" => {
|
Some(token) if token.value == "!" || token.value == "-" => {
|
||||||
match super::try_parse(tokens, pos + 1) {
|
match super::try_parse(tokens, pos + 1) {
|
||||||
ParseResult::Ok(expression, next_pos) => ParseResult::Ok(
|
Ok((expression, next_pos)) => Ok((
|
||||||
Expression::UnaryOperator(Box::new(token.value.clone()), Box::new(expression)),
|
Expression::UnaryOperator(&token.value, Box::new(expression)),
|
||||||
next_pos,
|
next_pos,
|
||||||
),
|
)),
|
||||||
_ => ParseResult::Unmatched,
|
_ => Err(ParsingError::Unmatched),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => function_call_expr::try_parse(tokens, pos),
|
_ => function_call_expr::try_parse(tokens, pos),
|
||||||
@ -37,7 +37,7 @@ mod tests {
|
|||||||
let expression = try_parse(&tokens, 0);
|
let expression = try_parse(&tokens, 0);
|
||||||
|
|
||||||
match expression {
|
match expression {
|
||||||
ParseResult::Ok(Expression::Identifier(value), _) => {
|
Ok((Expression::Identifier(value), _)) => {
|
||||||
assert_eq!("identifier", format!("{}", value))
|
assert_eq!("identifier", format!("{}", value))
|
||||||
}
|
}
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
@ -50,7 +50,7 @@ mod tests {
|
|||||||
let expression = try_parse(&tokens, 0);
|
let expression = try_parse(&tokens, 0);
|
||||||
|
|
||||||
match expression {
|
match expression {
|
||||||
ParseResult::Ok(Expression::UnaryOperator(operator, expression), _) => {
|
Ok((Expression::UnaryOperator(operator, expression), _)) => {
|
||||||
match (operator, *expression) {
|
match (operator, *expression) {
|
||||||
(op, Expression::Number(value)) => {
|
(op, Expression::Number(value)) => {
|
||||||
assert_eq!(*op, "-");
|
assert_eq!(*op, "-");
|
||||||
@ -69,7 +69,7 @@ mod tests {
|
|||||||
let expression = try_parse(&tokens, 0);
|
let expression = try_parse(&tokens, 0);
|
||||||
|
|
||||||
match expression {
|
match expression {
|
||||||
ParseResult::Ok(Expression::UnaryOperator(operator, expression), _) => {
|
Ok((Expression::UnaryOperator(operator, expression), _)) => {
|
||||||
assert_eq!(*operator, "-");
|
assert_eq!(*operator, "-");
|
||||||
match *expression {
|
match *expression {
|
||||||
Expression::BinaryOperator(_, _, _) => {
|
Expression::BinaryOperator(_, _, _) => {
|
||||||
|
@ -4,19 +4,19 @@ use crate::{
|
|||||||
syntax::{
|
syntax::{
|
||||||
ast::{functions::ArgumentsList, Expression},
|
ast::{functions::ArgumentsList, Expression},
|
||||||
utils::parse_token_type,
|
utils::parse_token_type,
|
||||||
ParseResult,
|
ParsingError, ParsingResult,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<ArgumentsList, &Token> {
|
pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParsingResult<ArgumentsList> {
|
||||||
let mut current_pos = pos;
|
let mut current_pos = pos;
|
||||||
|
|
||||||
let (opening_paren, next_pos) =
|
let (opening_paren, next_pos) =
|
||||||
match parse_token_type(tokens, current_pos, TokenType::LeftParen) {
|
match parse_token_type(tokens, current_pos, TokenType::LeftParen) {
|
||||||
ParseResult::Ok(t, next) => (t, next),
|
Ok((t, next)) => (t, next),
|
||||||
ParseResult::Err(err) => return ParseResult::Err(err),
|
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
||||||
ParseResult::Mismatch(t) => return ParseResult::Mismatch(t),
|
Err(ParsingError::Mismatch(t)) => return Err(ParsingError::Mismatch(t)),
|
||||||
ParseResult::Unmatched => return ParseResult::Unmatched,
|
Err(ParsingError::Unmatched) => return Err(ParsingError::Unmatched),
|
||||||
};
|
};
|
||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
|
|
||||||
@ -24,10 +24,10 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<Argument
|
|||||||
loop {
|
loop {
|
||||||
let (next_expression, next_pos) =
|
let (next_expression, next_pos) =
|
||||||
match super::super::expression::try_parse(tokens, current_pos) {
|
match super::super::expression::try_parse(tokens, current_pos) {
|
||||||
ParseResult::Ok(expression, next_pos) => (expression, next_pos),
|
Ok((expression, next_pos)) => (expression, next_pos),
|
||||||
ParseResult::Err(error) => {
|
Err(ParsingError::Err(error)) => {
|
||||||
// TODO: Write a more detailed error
|
// TODO: Write a more detailed error
|
||||||
return ParseResult::Err(error);
|
return Err(ParsingError::Err(error));
|
||||||
}
|
}
|
||||||
_ => break,
|
_ => break,
|
||||||
};
|
};
|
||||||
@ -37,44 +37,44 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<Argument
|
|||||||
|
|
||||||
// Parse comma. This also parses a trailing comma
|
// Parse comma. This also parses a trailing comma
|
||||||
match parse_token_type(tokens, current_pos, TokenType::Comma) {
|
match parse_token_type(tokens, current_pos, TokenType::Comma) {
|
||||||
ParseResult::Ok(_, next) => {
|
Ok((_, next)) => {
|
||||||
current_pos = next;
|
current_pos = next;
|
||||||
}
|
}
|
||||||
// This should never happen
|
// This should never happen
|
||||||
ParseResult::Err(err) => return ParseResult::Err(err),
|
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
||||||
ParseResult::Mismatch(_) => {
|
Err(ParsingError::Mismatch(_)) => {
|
||||||
// Something other than a comma was found. It must be a closing paren )
|
// Something other than a comma was found. It must be a closing paren )
|
||||||
// Still, break the loop, assume there are no more arguments
|
// Still, break the loop, assume there are no more arguments
|
||||||
// TODO: This could be a good place to write a detailed error?
|
// TODO: This could be a good place to write a detailed error?
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ParseResult::Unmatched => break,
|
Err(ParsingError::Unmatched) => break,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse closing paren
|
// Parse closing paren
|
||||||
let (_closing_paren, next_pos) =
|
let (_closing_paren, next_pos) =
|
||||||
match parse_token_type(tokens, current_pos, TokenType::RightParen) {
|
match parse_token_type(tokens, current_pos, TokenType::RightParen) {
|
||||||
ParseResult::Ok(t, next) => (t, next),
|
Ok((t, next)) => (t, next),
|
||||||
ParseResult::Err(err) => return ParseResult::Err(err),
|
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
||||||
ParseResult::Mismatch(t) => {
|
Err(ParsingError::Mismatch(t)) => {
|
||||||
return ParseResult::Err(SyntaxError {
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
reason: String::from("Expected a closing paren after the function identifier."),
|
reason: String::from("Expected a closing paren after the function identifier."),
|
||||||
error_start: t.position,
|
error_start: t.position,
|
||||||
error_end: t.get_end_position(),
|
error_end: t.get_end_position(),
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
ParseResult::Unmatched => {
|
Err(ParsingError::Unmatched) => {
|
||||||
return ParseResult::Err(SyntaxError {
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
reason: String::from("Expected a closing paren after the function identifier."),
|
reason: String::from("Expected a closing paren after the function identifier."),
|
||||||
error_start: opening_paren.position,
|
error_start: opening_paren.position,
|
||||||
error_end: opening_paren.get_end_position(),
|
error_end: opening_paren.get_end_position(),
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
|
|
||||||
ParseResult::Ok(ArgumentsList { arguments }, current_pos)
|
Ok((ArgumentsList { arguments }, current_pos))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -87,7 +87,7 @@ mod tests {
|
|||||||
let tokens = get_tokens(&String::from("()")).unwrap();
|
let tokens = get_tokens(&String::from("()")).unwrap();
|
||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = try_parse(&tokens, 0);
|
||||||
|
|
||||||
let ParseResult::Ok(list, next) = fun_decl else {
|
let Ok((list, next)) = fun_decl else {
|
||||||
panic!("Expected an unmatched result: {:?}", fun_decl);
|
panic!("Expected an unmatched result: {:?}", fun_decl);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -100,7 +100,7 @@ mod tests {
|
|||||||
let tokens = get_tokens(&String::from("( ) ")).unwrap();
|
let tokens = get_tokens(&String::from("( ) ")).unwrap();
|
||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = try_parse(&tokens, 0);
|
||||||
|
|
||||||
let ParseResult::Ok(list, next) = fun_decl else {
|
let Ok((list, next)) = fun_decl else {
|
||||||
panic!("Expected a result, got: {:?}", fun_decl);
|
panic!("Expected a result, got: {:?}", fun_decl);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -113,7 +113,7 @@ mod tests {
|
|||||||
let tokens = get_tokens(&String::from("(\n \n)")).unwrap();
|
let tokens = get_tokens(&String::from("(\n \n)")).unwrap();
|
||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = try_parse(&tokens, 0);
|
||||||
|
|
||||||
let ParseResult::Ok(list, next) = fun_decl else {
|
let Ok((list, next)) = fun_decl else {
|
||||||
panic!("Expected a result, got: {:?}", fun_decl);
|
panic!("Expected a result, got: {:?}", fun_decl);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -126,7 +126,7 @@ mod tests {
|
|||||||
let tokens = get_tokens(&String::from("(0)")).unwrap();
|
let tokens = get_tokens(&String::from("(0)")).unwrap();
|
||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = try_parse(&tokens, 0);
|
||||||
|
|
||||||
let ParseResult::Ok(arguments_list, next) = fun_decl else {
|
let Ok((arguments_list, next)) = fun_decl else {
|
||||||
panic!("Expected a result, got: {:?}", fun_decl);
|
panic!("Expected a result, got: {:?}", fun_decl);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -145,7 +145,7 @@ mod tests {
|
|||||||
let tokens = get_tokens(&String::from("(0, )")).unwrap();
|
let tokens = get_tokens(&String::from("(0, )")).unwrap();
|
||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = try_parse(&tokens, 0);
|
||||||
|
|
||||||
let ParseResult::Ok(arguments_list, next) = fun_decl else {
|
let Ok((arguments_list, next)) = fun_decl else {
|
||||||
panic!("Expected a result, got: {:?}", fun_decl);
|
panic!("Expected a result, got: {:?}", fun_decl);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -163,7 +163,7 @@ mod tests {
|
|||||||
let tokens = get_tokens(&String::from("(\"Hello new world\", 322, )")).unwrap();
|
let tokens = get_tokens(&String::from("(\"Hello new world\", 322, )")).unwrap();
|
||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = try_parse(&tokens, 0);
|
||||||
|
|
||||||
let ParseResult::Ok(arguments_list, _next) = fun_decl else {
|
let Ok((arguments_list, _next)) = fun_decl else {
|
||||||
panic!("Expected a result, got: {:?}", fun_decl);
|
panic!("Expected a result, got: {:?}", fun_decl);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -185,7 +185,7 @@ mod tests {
|
|||||||
let tokens = get_tokens(&String::from("(foo(), bar())")).unwrap();
|
let tokens = get_tokens(&String::from("(foo(), bar())")).unwrap();
|
||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = try_parse(&tokens, 0);
|
||||||
|
|
||||||
let ParseResult::Ok(arguments_list, _next) = fun_decl else {
|
let Ok((arguments_list, _next)) = fun_decl else {
|
||||||
panic!("Expected a result, got: {:?}", fun_decl);
|
panic!("Expected a result, got: {:?}", fun_decl);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,102 +1,96 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error_handling::SyntaxError,
|
error_handling::SyntaxError,
|
||||||
lexic::token::{Token, TokenType},
|
lexic::token::{Token, TokenType},
|
||||||
utils::Result3,
|
syntax::{ParsingError, ParsingResult},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
super::{
|
super::{ast::FunctionDeclaration, block::parse_block, utils::parse_token_type},
|
||||||
ast::FunctionDeclaration,
|
|
||||||
block::parse_block,
|
|
||||||
utils::{parse_token_type, try_token_type},
|
|
||||||
ParseResult,
|
|
||||||
},
|
|
||||||
params_list::parse_params_list,
|
params_list::parse_params_list,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<FunctionDeclaration, ()> {
|
pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParsingResult<FunctionDeclaration> {
|
||||||
let mut current_pos = pos;
|
let mut current_pos = pos;
|
||||||
|
|
||||||
// `fun` keyword
|
// `fun` keyword
|
||||||
let fun_keyword = match try_token_type(tokens, current_pos, TokenType::FUN) {
|
let (fun_keyword, next_pos) = match parse_token_type(tokens, current_pos, TokenType::FUN) {
|
||||||
Result3::Ok(t) => t,
|
Ok((t, next)) => (t, next),
|
||||||
Result3::Err(_token) => return ParseResult::Unmatched,
|
_ => return Err(ParsingError::Unmatched),
|
||||||
Result3::None => return ParseResult::Unmatched,
|
|
||||||
};
|
};
|
||||||
current_pos += 1;
|
current_pos = next_pos;
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
ParseResult::Ok(id, next) => (id, next),
|
Ok((id, next)) => (id, next),
|
||||||
ParseResult::Err(err) => return ParseResult::Err(err),
|
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
||||||
ParseResult::Mismatch(wrong_token) => {
|
Err(ParsingError::Mismatch(wrong_token)) => {
|
||||||
return ParseResult::Err(SyntaxError {
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
reason: String::from("Expected an identifier after the `fun` keyword."),
|
reason: String::from("Expected an identifier after the `fun` keyword."),
|
||||||
error_start: wrong_token.position,
|
error_start: wrong_token.position,
|
||||||
error_end: wrong_token.get_end_position(),
|
error_end: wrong_token.get_end_position(),
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
ParseResult::Unmatched => {
|
Err(ParsingError::Unmatched) => {
|
||||||
return ParseResult::Err(SyntaxError {
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
reason: String::from("Expected an identifier after the `fun` keyword."),
|
reason: String::from("Expected an identifier after the `fun` keyword."),
|
||||||
error_start: fun_keyword.position,
|
error_start: fun_keyword.position,
|
||||||
error_end: fun_keyword.get_end_position(),
|
error_end: fun_keyword.get_end_position(),
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
|
|
||||||
let (params_list, next_pos) = match parse_params_list(tokens, current_pos) {
|
let (params_list, next_pos) = match parse_params_list(tokens, current_pos) {
|
||||||
ParseResult::Ok(params, next_pos) => (params, next_pos),
|
Ok((params, next_pos)) => (params, next_pos),
|
||||||
ParseResult::Err(err) => return ParseResult::Err(err),
|
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
||||||
ParseResult::Mismatch(wrong_token) => {
|
Err(ParsingError::Mismatch(wrong_token)) => {
|
||||||
return ParseResult::Err(SyntaxError {
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
reason: String::from("Expected an opening paren afted the function identifier."),
|
reason: String::from("Expected an opening paren afted 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(),
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
ParseResult::Unmatched => {
|
Err(ParsingError::Unmatched) => {
|
||||||
return ParseResult::Err(SyntaxError {
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
reason: String::from("Expected an opening paren afted the function identifier."),
|
reason: String::from("Expected an opening paren afted the function identifier."),
|
||||||
error_start: identifier.position,
|
error_start: identifier.position,
|
||||||
error_end: identifier.get_end_position(),
|
error_end: identifier.get_end_position(),
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
|
|
||||||
let (block, next_pos) = match parse_block(tokens, current_pos) {
|
let (block, next_pos) = match parse_block(tokens, current_pos) {
|
||||||
ParseResult::Ok(block, next_pos) => (block, next_pos),
|
Ok((block, next_pos)) => (block, next_pos),
|
||||||
ParseResult::Err(error) => {
|
Err(ParsingError::Err(error)) => {
|
||||||
return ParseResult::Err(error);
|
return Err(ParsingError::Err(error));
|
||||||
}
|
}
|
||||||
ParseResult::Mismatch(wrong_token) => {
|
Err(ParsingError::Mismatch(wrong_token)) => {
|
||||||
return ParseResult::Err(SyntaxError {
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
reason: String::from("Expected a block after the function declaration."),
|
reason: String::from("Expected a block after the function declaration."),
|
||||||
error_start: wrong_token.position,
|
error_start: wrong_token.position,
|
||||||
error_end: wrong_token.get_end_position(),
|
error_end: wrong_token.get_end_position(),
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
ParseResult::Unmatched => {
|
Err(ParsingError::Unmatched) => {
|
||||||
return ParseResult::Err(SyntaxError {
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
reason: String::from("Expected a block after the function declaration."),
|
reason: String::from("Expected a block after the function declaration."),
|
||||||
error_start: identifier.position,
|
error_start: identifier.position,
|
||||||
error_end: identifier.get_end_position(),
|
error_end: identifier.get_end_position(),
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
|
|
||||||
// Construct and return the function declaration
|
// Construct and return the function declaration
|
||||||
ParseResult::Ok(
|
Ok((
|
||||||
FunctionDeclaration {
|
FunctionDeclaration {
|
||||||
identifier: Box::new(identifier.value.clone()),
|
identifier: &identifier,
|
||||||
params_list: Box::new(params_list),
|
params_list: Box::new(params_list),
|
||||||
block: Box::new(block),
|
block: Box::new(block),
|
||||||
},
|
},
|
||||||
current_pos,
|
current_pos,
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -110,7 +104,7 @@ mod tests {
|
|||||||
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 = try_parse(&tokens, 0);
|
||||||
|
|
||||||
let ParseResult::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);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -121,7 +115,7 @@ mod tests {
|
|||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = try_parse(&tokens, 0);
|
||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
ParseResult::Err(err) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
err.reason,
|
err.reason,
|
||||||
"Expected an identifier after the `fun` keyword."
|
"Expected an identifier after the `fun` keyword."
|
||||||
@ -135,7 +129,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 = try_parse(&tokens, 0);
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
ParseResult::Err(err) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
err.reason,
|
err.reason,
|
||||||
"Expected an identifier after the `fun` keyword."
|
"Expected an identifier after the `fun` keyword."
|
||||||
@ -153,7 +147,7 @@ mod tests {
|
|||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = try_parse(&tokens, 0);
|
||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
ParseResult::Err(err) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
err.reason,
|
err.reason,
|
||||||
"Expected an opening paren afted the function identifier."
|
"Expected an opening paren afted the function identifier."
|
||||||
@ -167,7 +161,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 = try_parse(&tokens, 0);
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
ParseResult::Err(err) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
err.reason,
|
err.reason,
|
||||||
"Expected an opening paren afted the function identifier."
|
"Expected an opening paren afted the function identifier."
|
||||||
@ -185,7 +179,7 @@ mod tests {
|
|||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = try_parse(&tokens, 0);
|
||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
ParseResult::Err(err) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
err.reason,
|
err.reason,
|
||||||
"Expected a closing paren after the function identifier."
|
"Expected a closing paren after the function identifier."
|
||||||
@ -199,7 +193,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 = try_parse(&tokens, 0);
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
ParseResult::Err(err) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
err.reason,
|
err.reason,
|
||||||
"Expected a closing paren after the function identifier."
|
"Expected a closing paren after the function identifier."
|
||||||
@ -217,7 +211,7 @@ mod tests {
|
|||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = try_parse(&tokens, 0);
|
||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
ParseResult::Err(err) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
err.reason,
|
err.reason,
|
||||||
"Expected an identifier after the `fun` keyword."
|
"Expected an identifier after the `fun` keyword."
|
||||||
@ -233,7 +227,7 @@ mod tests {
|
|||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = try_parse(&tokens, 0);
|
||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
ParseResult::Err(err) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
err.reason,
|
err.reason,
|
||||||
"Expected an identifier after the `fun` keyword."
|
"Expected an identifier after the `fun` keyword."
|
||||||
@ -251,7 +245,7 @@ mod tests {
|
|||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = try_parse(&tokens, 0);
|
||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
ParseResult::Err(err) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
err.reason,
|
err.reason,
|
||||||
"Expected a block after the function declaration."
|
"Expected a block after the function declaration."
|
||||||
@ -265,7 +259,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 = try_parse(&tokens, 0);
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
ParseResult::Err(err) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
err.reason,
|
err.reason,
|
||||||
"Expected a block after the function declaration."
|
"Expected a block after the function declaration."
|
||||||
@ -283,7 +277,7 @@ mod tests {
|
|||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = try_parse(&tokens, 0);
|
||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
ParseResult::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, 11);
|
||||||
assert_eq!(err.error_end, 13);
|
assert_eq!(err.error_end, 13);
|
||||||
@ -295,7 +289,7 @@ mod tests {
|
|||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = try_parse(&tokens, 0);
|
||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
ParseResult::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, 9);
|
assert_eq!(err.error_start, 9);
|
||||||
assert_eq!(err.error_end, 10);
|
assert_eq!(err.error_end, 10);
|
||||||
@ -307,14 +301,9 @@ 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 ParseResult::Ok(function_declaration, _) = try_parse(&tokens, 0) else {
|
let (function_declaration, _) = try_parse(&tokens, 0).unwrap();
|
||||||
panic!("Expected a function declaration.")
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(function_declaration.identifier.value, String::from("id"));
|
||||||
function_declaration.identifier,
|
|
||||||
Box::new(String::from("id"))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -327,48 +316,38 @@ 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 ParseResult::Ok(declaration, _) = try_parse(&tokens, 0) else {
|
let (declaration, _) = try_parse(&tokens, 0).unwrap();
|
||||||
panic!("Expected a function declaration.")
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(declaration.identifier, Box::new(String::from("id")));
|
assert_eq!(declaration.identifier.value, (String::from("id")));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[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 ParseResult::Ok(declaration, _) = try_parse(&tokens, 0) else {
|
let (declaration, _) = try_parse(&tokens, 0).unwrap();
|
||||||
panic!("Expected a function declaration.")
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(declaration.identifier, Box::new(String::from("id")));
|
assert_eq!(declaration.identifier.value, (String::from("id")));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[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 ParseResult::Ok(declaration, _) = try_parse(&tokens, 0) else {
|
let (declaration, _) = try_parse(&tokens, 0).unwrap();
|
||||||
panic!("Expected a function declaration.")
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(declaration.identifier, Box::new(String::from("id")));
|
assert_eq!(declaration.identifier.value, (String::from("id")));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[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 ParseResult::Ok(declaration, _) = try_parse(&tokens, 0) else {
|
let (declaration, _) = try_parse(&tokens, 0).unwrap();
|
||||||
panic!("Expected a function declaration.")
|
assert_eq!(declaration.identifier.value, (String::from("id")));
|
||||||
};
|
|
||||||
assert_eq!(declaration.identifier, Box::new(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 ParseResult::Ok(declaration, _) = try_parse(&tokens, 0) else {
|
let (declaration, _) = try_parse(&tokens, 0).unwrap();
|
||||||
panic!("Expected a function declaration.")
|
assert_eq!(declaration.identifier.value, (String::from("id")));
|
||||||
};
|
|
||||||
assert_eq!(declaration.identifier, Box::new(String::from("id")));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,36 +1,41 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error_handling::SyntaxError,
|
error_handling::SyntaxError,
|
||||||
lexic::token::{Token, TokenType},
|
lexic::token::{Token, TokenType},
|
||||||
syntax::utils::parse_token_type,
|
syntax::{utils::parse_token_type, ParsingError, ParsingResult},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::super::{
|
use super::super::{
|
||||||
ast::{Parameter, ParamsList},
|
ast::{Parameter, ParamsList},
|
||||||
utils, ParseResult,
|
utils,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn parse_params_list<'a>(
|
pub fn parse_params_list<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParsingResult<ParamsList> {
|
||||||
tokens: &'a Vec<Token>,
|
|
||||||
pos: usize,
|
|
||||||
) -> ParseResult<ParamsList, &Token> {
|
|
||||||
let mut current_pos = pos;
|
let mut current_pos = pos;
|
||||||
|
|
||||||
let (opening_paren, next_pos) =
|
let (opening_paren, next_pos) =
|
||||||
match parse_token_type(tokens, current_pos, TokenType::LeftParen) {
|
match parse_token_type(tokens, current_pos, TokenType::LeftParen) {
|
||||||
ParseResult::Ok(t, next) => (t, next),
|
Ok((t, next)) => (t, next),
|
||||||
ParseResult::Err(err) => return ParseResult::Err(err),
|
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
||||||
ParseResult::Mismatch(t) => return ParseResult::Mismatch(t),
|
Err(ParsingError::Mismatch(t)) => return Err(ParsingError::Mismatch(&t)),
|
||||||
ParseResult::Unmatched => return ParseResult::Unmatched,
|
Err(ParsingError::Unmatched) => return Err(ParsingError::Unmatched),
|
||||||
};
|
};
|
||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
|
|
||||||
|
/*
|
||||||
|
val (opening_paren, next_pos) = try parse_token_type(...)
|
||||||
|
|
||||||
|
val (next_parameter, next_pos) = try parse_param_definition(...) catch
|
||||||
|
case ::Err(e) { return ::Err(e) }
|
||||||
|
else { break }
|
||||||
|
*/
|
||||||
|
|
||||||
// Parse parameters definitions, separated by commas
|
// Parse parameters definitions, separated by commas
|
||||||
let mut parameters = Vec::<Parameter>::new();
|
let mut parameters = Vec::<Parameter>::new();
|
||||||
loop {
|
loop {
|
||||||
let (next_parameter, next_pos) = match parse_param_definition(tokens, current_pos) {
|
let (next_parameter, next_pos) = match parse_param_definition(tokens, current_pos) {
|
||||||
ParseResult::Ok(parameter, next_pos) => (parameter, next_pos),
|
Ok((parameter, next_pos)) => (parameter, next_pos),
|
||||||
ParseResult::Err(error) => {
|
Err(ParsingError::Err(error)) => {
|
||||||
return ParseResult::Err(error);
|
return Err(ParsingError::Err(error));
|
||||||
}
|
}
|
||||||
_ => break,
|
_ => break,
|
||||||
};
|
};
|
||||||
@ -39,50 +44,47 @@ pub fn parse_params_list<'a>(
|
|||||||
|
|
||||||
// Parse comma. This also parses a trailing comma
|
// Parse comma. This also parses a trailing comma
|
||||||
match parse_token_type(tokens, current_pos, TokenType::Comma) {
|
match parse_token_type(tokens, current_pos, TokenType::Comma) {
|
||||||
ParseResult::Ok(_, next) => {
|
Ok((_, next)) => {
|
||||||
current_pos = next;
|
current_pos = next;
|
||||||
}
|
}
|
||||||
// This should never happen
|
// This should never happen
|
||||||
ParseResult::Err(err) => return ParseResult::Err(err),
|
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
||||||
ParseResult::Mismatch(_) => {
|
Err(ParsingError::Mismatch(_)) => {
|
||||||
// Something other than a comma was found. It must be a closing paren )
|
// Something other than a comma was found. It must be a closing paren )
|
||||||
// Still, break the loop, assume there are no more arguments
|
// Still, break the loop, assume there are no more arguments
|
||||||
// TODO: This could be a good place to write a detailed error?
|
// TODO: This could be a good place to write a detailed error?
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ParseResult::Unmatched => break,
|
Err(ParsingError::Unmatched) => break,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse closing paren
|
// Parse closing paren
|
||||||
let (_closing_paren, next_pos) =
|
let (_closing_paren, next_pos) =
|
||||||
match parse_token_type(tokens, current_pos, TokenType::RightParen) {
|
match parse_token_type(tokens, current_pos, TokenType::RightParen) {
|
||||||
ParseResult::Ok(t, next) => (t, next),
|
Ok((t, next)) => (t, next),
|
||||||
ParseResult::Err(err) => return ParseResult::Err(err),
|
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
||||||
ParseResult::Mismatch(t) => {
|
Err(ParsingError::Mismatch(t)) => {
|
||||||
return ParseResult::Err(SyntaxError {
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
reason: String::from("Expected a closing paren after the function identifier."),
|
reason: String::from("Expected a closing paren after the function identifier."),
|
||||||
error_start: t.position,
|
error_start: t.position,
|
||||||
error_end: t.get_end_position(),
|
error_end: t.get_end_position(),
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
ParseResult::Unmatched => {
|
Err(ParsingError::Unmatched) => {
|
||||||
return ParseResult::Err(SyntaxError {
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
reason: String::from("Expected a closing paren after the function identifier."),
|
reason: String::from("Expected a closing paren after the function identifier."),
|
||||||
error_start: opening_paren.position,
|
error_start: opening_paren.position,
|
||||||
error_end: opening_paren.get_end_position(),
|
error_end: opening_paren.get_end_position(),
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
|
|
||||||
ParseResult::Ok(ParamsList {}, current_pos)
|
Ok((ParamsList {}, current_pos))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_param_definition<'a>(
|
fn parse_param_definition<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParsingResult<Parameter> {
|
||||||
tokens: &'a Vec<Token>,
|
|
||||||
pos: usize,
|
|
||||||
) -> ParseResult<Parameter, &Token> {
|
|
||||||
// Parse a single parameter definition of the form:
|
// Parse a single parameter definition of the form:
|
||||||
// - Type identifier
|
// - Type identifier
|
||||||
// There will be more constructs in the future, like:
|
// There will be more constructs in the future, like:
|
||||||
@ -93,45 +95,45 @@ fn parse_param_definition<'a>(
|
|||||||
let mut current_pos = pos;
|
let mut current_pos = pos;
|
||||||
let (datatype, next_pos) =
|
let (datatype, next_pos) =
|
||||||
match utils::parse_token_type(tokens, current_pos, TokenType::Datatype) {
|
match utils::parse_token_type(tokens, current_pos, TokenType::Datatype) {
|
||||||
ParseResult::Ok(token, next) => (token, next),
|
Ok((token, next)) => (token, next),
|
||||||
ParseResult::Err(err) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
return ParseResult::Err(err);
|
return Err(ParsingError::Err(err));
|
||||||
}
|
}
|
||||||
// If there is no datatype this construction doesn't apply.
|
// If there is no datatype this construction doesn't apply.
|
||||||
// Return a mismatch and let the caller handle it
|
// Return a mismatch and let the caller handle it
|
||||||
ParseResult::Mismatch(t) => return ParseResult::Mismatch(t),
|
Err(ParsingError::Mismatch(t)) => return Err(ParsingError::Mismatch(t)),
|
||||||
ParseResult::Unmatched => return ParseResult::Unmatched,
|
Err(ParsingError::Unmatched) => return Err(ParsingError::Unmatched),
|
||||||
};
|
};
|
||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
|
|
||||||
let (identifier, next_pos) =
|
let (identifier, next_pos) =
|
||||||
match utils::parse_token_type(tokens, current_pos, TokenType::Identifier) {
|
match utils::parse_token_type(tokens, current_pos, TokenType::Identifier) {
|
||||||
ParseResult::Ok(token, next) => (token, next),
|
Ok((token, next)) => (token, next),
|
||||||
ParseResult::Err(err) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
return ParseResult::Err(err);
|
return Err(ParsingError::Err(err));
|
||||||
}
|
}
|
||||||
// However, if we fail to parse an identifier, it's an error
|
// However, if we fail to parse an identifier, it's an error
|
||||||
ParseResult::Mismatch(_) => {
|
Err(ParsingError::Mismatch(_)) => {
|
||||||
return ParseResult::Err(SyntaxError {
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
reason: String::from("Expected an identifier for the parameter."),
|
reason: String::from("Expected an identifier for the parameter."),
|
||||||
error_start: tokens[pos].position,
|
error_start: tokens[pos].position,
|
||||||
error_end: tokens[pos].get_end_position(),
|
error_end: tokens[pos].get_end_position(),
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
ParseResult::Unmatched => {
|
Err(ParsingError::Unmatched) => {
|
||||||
return ParseResult::Err(SyntaxError {
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
reason: String::from("Expected an identifier for the parameter."),
|
reason: String::from("Expected an identifier for the parameter."),
|
||||||
error_start: tokens[pos].position,
|
error_start: tokens[pos].position,
|
||||||
error_end: tokens[pos].get_end_position(),
|
error_end: tokens[pos].get_end_position(),
|
||||||
})
|
}))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ParseResult::Ok(
|
Ok((
|
||||||
Parameter {
|
Parameter {
|
||||||
identifier: Box::new(identifier.value.clone()),
|
identifier: &identifier.value,
|
||||||
datatype: Box::new(datatype.value.clone()),
|
datatype: &datatype.value,
|
||||||
},
|
},
|
||||||
next_pos,
|
next_pos,
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,21 @@
|
|||||||
# Grammar
|
# Grammar
|
||||||
|
|
||||||
|
|
||||||
## Module
|
## Source file
|
||||||
|
|
||||||
A module is (commonly) a single source file.
|
|
||||||
|
|
||||||
```ebnf
|
```ebnf
|
||||||
module = top level declaration*
|
source file = top level statement*
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Top level declaration
|
## Top level statement
|
||||||
|
|
||||||
|
Current focus: Have a mvp compiler (w lexical/syntactic/semantic analysis + codegen) for
|
||||||
|
simple function calls, and then implement other features top down
|
||||||
|
|
||||||
```ebnf
|
```ebnf
|
||||||
top level declaration = function declaration
|
top level statement = expression
|
||||||
|
| function declaration
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,21 +14,19 @@ use ast::ModuleAST;
|
|||||||
|
|
||||||
use self::ast::TopLevelDeclaration;
|
use self::ast::TopLevelDeclaration;
|
||||||
|
|
||||||
|
pub type ParsingResult<'a, A> = Result<(A, usize), ParsingError<'a>>;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ParseResult<A, B> {
|
pub enum ParsingError<'a> {
|
||||||
/// The parsing was a success. The first element is the parsed construct,
|
/// Some other token was found than the expected one
|
||||||
/// the second element is the position of the next token to parse
|
Mismatch(&'a Token),
|
||||||
Ok(A, usize),
|
/// The parsing didn't succeed, but it's not a fatal error
|
||||||
|
Unmatched,
|
||||||
/// The parsing failed past a point of no return.
|
/// The parsing failed past a point of no return.
|
||||||
///
|
///
|
||||||
/// For example, when parsing a function declaration
|
/// For example, when parsing a function declaration
|
||||||
/// the `fun` token is found, but then no identifier
|
/// the `fun` token is found, but then no identifier
|
||||||
Err(SyntaxError),
|
Err(SyntaxError),
|
||||||
/// Some special value was expected, but something else was found.
|
|
||||||
/// The inside element is the something else found.
|
|
||||||
Mismatch(B),
|
|
||||||
/// This parsing didn't succeed, but it's not a fatal error.
|
|
||||||
Unmatched,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs the Misti AST from a vector of tokens
|
/// Constructs the Misti AST from a vector of tokens
|
||||||
@ -46,11 +44,11 @@ pub fn construct_ast<'a>(tokens: &'a Vec<Token>) -> Result<ModuleAST, MistiError
|
|||||||
}
|
}
|
||||||
|
|
||||||
match next_construct(tokens, current_pos) {
|
match next_construct(tokens, current_pos) {
|
||||||
ParseResult::Ok(module, next_pos) => {
|
Ok((module, next_pos)) => {
|
||||||
top_level_declarations.push(module);
|
top_level_declarations.push(module);
|
||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
}
|
}
|
||||||
ParseResult::Err(err) => return Err(MistiError::Syntax(err)),
|
Err(ParsingError::Err(err)) => return Err(MistiError::Syntax(err)),
|
||||||
_ => {
|
_ => {
|
||||||
return Err(MistiError::Syntax(SyntaxError {
|
return Err(MistiError::Syntax(SyntaxError {
|
||||||
reason: String::from("PARSER couldn't parse any construction"),
|
reason: String::from("PARSER couldn't parse any construction"),
|
||||||
@ -70,18 +68,21 @@ pub fn construct_ast<'a>(tokens: &'a Vec<Token>) -> Result<ModuleAST, MistiError
|
|||||||
fn next_construct<'a>(
|
fn next_construct<'a>(
|
||||||
tokens: &'a Vec<Token>,
|
tokens: &'a Vec<Token>,
|
||||||
current_pos: usize,
|
current_pos: usize,
|
||||||
) -> ParseResult<TopLevelDeclaration, ()> {
|
) -> ParsingResult<TopLevelDeclaration> {
|
||||||
None.or_else(
|
// Try to parse a function declaration
|
||||||
|| match functions::function_declaration::try_parse(tokens, current_pos) {
|
match functions::function_declaration::try_parse(tokens, current_pos) {
|
||||||
ParseResult::Ok(declaration, next_pos) => Some(ParseResult::Ok(
|
Ok((declaration, next_pos)) => {
|
||||||
|
return Ok((
|
||||||
TopLevelDeclaration::FunctionDeclaration(declaration),
|
TopLevelDeclaration::FunctionDeclaration(declaration),
|
||||||
next_pos,
|
next_pos,
|
||||||
)),
|
))
|
||||||
ParseResult::Err(err) => Some(ParseResult::Err(err)),
|
}
|
||||||
_ => None,
|
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
||||||
},
|
_ => {}
|
||||||
)
|
}
|
||||||
.unwrap_or_else(|| ParseResult::Unmatched)
|
|
||||||
|
// No top level construct was found, return unmatched
|
||||||
|
Err(ParsingError::Unmatched)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -90,7 +91,7 @@ mod tests {
|
|||||||
|
|
||||||
#[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");
|
||||||
let tokens = crate::lexic::get_tokens(&input).unwrap();
|
let tokens = crate::lexic::get_tokens(&input).unwrap();
|
||||||
let declarations = construct_ast(&tokens).unwrap().declarations;
|
let declarations = construct_ast(&tokens).unwrap().declarations;
|
||||||
|
|
||||||
@ -101,6 +102,7 @@ mod tests {
|
|||||||
TopLevelDeclaration::FunctionDeclaration(_f) => {
|
TopLevelDeclaration::FunctionDeclaration(_f) => {
|
||||||
assert!(true)
|
assert!(true)
|
||||||
}
|
}
|
||||||
|
_ => panic!("Not implemented: Expression at top level"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,6 +119,7 @@ mod tests {
|
|||||||
TopLevelDeclaration::FunctionDeclaration(_f) => {
|
TopLevelDeclaration::FunctionDeclaration(_f) => {
|
||||||
assert!(true)
|
assert!(true)
|
||||||
}
|
}
|
||||||
|
_ => panic!("Not implemented: Expression at top level"),
|
||||||
}
|
}
|
||||||
|
|
||||||
match declarations.get(1).unwrap() {
|
match declarations.get(1).unwrap() {
|
||||||
@ -124,6 +127,7 @@ mod tests {
|
|||||||
TopLevelDeclaration::FunctionDeclaration(_f) => {
|
TopLevelDeclaration::FunctionDeclaration(_f) => {
|
||||||
assert!(true)
|
assert!(true)
|
||||||
}
|
}
|
||||||
|
_ => panic!("Not implemented: Expression at top level"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,26 +4,26 @@ use super::{
|
|||||||
ast::{statement::Statement, Expression},
|
ast::{statement::Statement, Expression},
|
||||||
binding,
|
binding,
|
||||||
expression::function_call_expr,
|
expression::function_call_expr,
|
||||||
ParseResult,
|
ParsingError, ParsingResult,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<Statement, ()> {
|
pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParsingResult<Statement> {
|
||||||
None.or_else(|| match binding::try_parse(tokens, pos) {
|
// Try to parse a binding
|
||||||
ParseResult::Ok(b, next) => Some(ParseResult::Ok(Statement::Binding(b), next)),
|
match binding::try_parse(tokens, pos) {
|
||||||
ParseResult::Err(err) => Some(ParseResult::Err(err)),
|
Ok((b, next)) => return Ok((Statement::Binding(b), next)),
|
||||||
_ => None,
|
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
||||||
})
|
_ => {}
|
||||||
.or_else(|| match function_call_expr::try_parse(tokens, pos) {
|
|
||||||
ParseResult::Ok(f, next) => {
|
|
||||||
let Expression::FunctionCall(f) = f else {
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
Some(ParseResult::Ok(Statement::FunctionCall(f), next))
|
|
||||||
}
|
}
|
||||||
ParseResult::Err(err) => Some(ParseResult::Err(err)),
|
|
||||||
_ => None,
|
// Try to parse a function call
|
||||||
})
|
match function_call_expr::try_parse(tokens, pos) {
|
||||||
.unwrap_or_else(|| ParseResult::Unmatched)
|
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)]
|
#[cfg(test)]
|
||||||
@ -37,7 +37,7 @@ mod tests {
|
|||||||
let statement = try_parse(&tokens, 0);
|
let statement = try_parse(&tokens, 0);
|
||||||
|
|
||||||
let statement = match statement {
|
let statement = match statement {
|
||||||
ParseResult::Ok(s, _) => s,
|
Ok((s, _)) => s,
|
||||||
_ => panic!("Expected a statement"),
|
_ => panic!("Expected a statement"),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ mod tests {
|
|||||||
let statement = try_parse(&tokens, 0);
|
let statement = try_parse(&tokens, 0);
|
||||||
|
|
||||||
let statement = match statement {
|
let statement = match statement {
|
||||||
ParseResult::Ok(s, _) => s,
|
Ok((s, _)) => s,
|
||||||
_ => panic!("Expected a statement"),
|
_ => panic!("Expected a statement"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
use crate::{
|
use crate::lexic::token::{Token, TokenType};
|
||||||
lexic::token::{Token, TokenType},
|
|
||||||
utils::Result3,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::ParseResult;
|
use super::{ParsingError, ParsingResult};
|
||||||
|
|
||||||
pub trait Tokenizer {
|
pub trait Tokenizer {
|
||||||
fn get_significant<'a>(&'a self, index: usize) -> Option<(&'a Token, usize)>;
|
fn get_significant<'a>(&'a self, index: usize) -> Option<(&'a Token, usize)>;
|
||||||
@ -33,38 +30,31 @@ impl Tokenizer for Vec<Token> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Expects the token at `pos` to be of type `token_type`
|
/// Expects the token at `pos` to be an operator of value `operator`. Doesn't ignore whitespace or newlines
|
||||||
pub fn try_token_type(tokens: &Vec<Token>, pos: usize, token_type: TokenType) -> Result3<&Token> {
|
pub fn try_operator(tokens: &Vec<Token>, pos: usize, operator: String) -> ParsingResult<&Token> {
|
||||||
match tokens.get(pos) {
|
match tokens.get(pos) {
|
||||||
Some(t) if t.token_type == token_type => Result3::Ok(t),
|
Some(t) if t.token_type == TokenType::Operator && t.value == operator => Ok((t, pos + 1)),
|
||||||
Some(t) if t.token_type == TokenType::EOF || t.token_type == TokenType::NewLine => {
|
|
||||||
Result3::None
|
|
||||||
}
|
|
||||||
Some(t) => Result3::Err(t),
|
|
||||||
None => Result3::None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn try_operator(tokens: &Vec<Token>, pos: usize, operator: String) -> Result3<&Token> {
|
|
||||||
match tokens.get(pos) {
|
|
||||||
Some(t) if t.token_type == TokenType::Operator && t.value == operator => Result3::Ok(t),
|
|
||||||
Some(t) if t.token_type == TokenType::NewLine || t.token_type == TokenType::EOF => {
|
Some(t) if t.token_type == TokenType::NewLine || t.token_type == TokenType::EOF => {
|
||||||
Result3::None
|
Err(ParsingError::Unmatched)
|
||||||
}
|
}
|
||||||
Some(t) => Result3::Err(t),
|
Some(t) => Err(ParsingError::Mismatch(t)),
|
||||||
None => Result3::None,
|
None => Err(ParsingError::Unmatched),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Expects the token at `pos` to be of type `token_type`
|
/// Expects the token at `pos` to be of type `token_type`, and returns the token and the next position.
|
||||||
|
///
|
||||||
|
/// Ignores all whitespace and newlines.
|
||||||
|
///
|
||||||
|
/// Only returns: Ok, Unmatched, Mismatched
|
||||||
pub fn parse_token_type(
|
pub fn parse_token_type(
|
||||||
tokens: &Vec<Token>,
|
tokens: &Vec<Token>,
|
||||||
pos: usize,
|
pos: usize,
|
||||||
token_type: TokenType,
|
token_type: TokenType,
|
||||||
) -> ParseResult<&Token, &Token> {
|
) -> ParsingResult<&Token> {
|
||||||
let mut current_pos = pos;
|
let mut current_pos = pos;
|
||||||
|
|
||||||
// Ignore all whitespace and newlines
|
// Ignore all whitespace, newlines and semicolons
|
||||||
while let Some(t) = tokens.get(current_pos) {
|
while let Some(t) = tokens.get(current_pos) {
|
||||||
if t.token_type == TokenType::INDENT
|
if t.token_type == TokenType::INDENT
|
||||||
|| t.token_type == TokenType::DEDENT
|
|| t.token_type == TokenType::DEDENT
|
||||||
@ -77,11 +67,11 @@ pub fn parse_token_type(
|
|||||||
}
|
}
|
||||||
|
|
||||||
match tokens.get(current_pos) {
|
match tokens.get(current_pos) {
|
||||||
Some(t) if t.token_type == token_type => ParseResult::Ok(t, current_pos + 1),
|
Some(t) if t.token_type == token_type => Ok((t, current_pos + 1)),
|
||||||
Some(t) if t.token_type == TokenType::EOF || t.token_type == TokenType::NewLine => {
|
Some(t) if t.token_type == TokenType::EOF || t.token_type == TokenType::NewLine => {
|
||||||
ParseResult::Unmatched
|
Err(ParsingError::Unmatched)
|
||||||
}
|
}
|
||||||
Some(t) => ParseResult::Mismatch(t),
|
Some(t) => Err(ParsingError::Mismatch(t)),
|
||||||
None => ParseResult::Unmatched,
|
None => Err(ParsingError::Unmatched),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
pub enum Result3<T> {
|
|
||||||
Ok(T),
|
|
||||||
Err(T),
|
|
||||||
None,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
impl<T> Result3<T> {
|
|
||||||
pub fn unwrap(&self) -> &T {
|
|
||||||
match self {
|
|
||||||
Result3::Ok(t) => t,
|
|
||||||
_ => panic!(""),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user