Parse val/var binding & implicit val binding
This commit is contained in:
parent
f60992c303
commit
2d32f1a0bc
@ -32,13 +32,13 @@
|
|||||||
|
|
||||||
## v0.0.11
|
## v0.0.11
|
||||||
|
|
||||||
- [ ] Parse binding of form `val Type variable = value`
|
- [x] Parse binding of form `val Type variable = value`
|
||||||
- [ ] Parse binding of form `Type variable = value`
|
- [x] Parse binding of form `Type variable = value`
|
||||||
- [ ] Infer datatype of `value` in the above for a simple expression
|
- [ ] Infer datatype of `value` in the above for a simple expression
|
||||||
- [ ] Ensure that the anotated datatype matches the datatype of `value` in the above
|
- [ ] 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
|
- [ ] Infer datatype of a `val variable = value` in the AST: Use the infered datatype
|
||||||
- [ ] Formally define the top level constructs
|
- [x] Formally define the top level constructs
|
||||||
- [ ] Parse bindings and function declarations as top level constructs
|
- [x] Parse bindings and function declarations as top level constructs
|
||||||
- [ ] Parse function declaration arguments (`Type id`)
|
- [ ] Parse function declaration arguments (`Type id`)
|
||||||
- [x] Parse function return datatype (`fun f() -> Type`)
|
- [x] Parse function return datatype (`fun f() -> Type`)
|
||||||
- [x] Return parsing to variables to var/val
|
- [x] Return parsing to variables to var/val
|
||||||
|
@ -4,29 +4,51 @@ 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};
|
||||||
|
|
||||||
|
/*
|
||||||
|
binding = val binding | var binding
|
||||||
|
val binding = "val", datatype?, binding remainder
|
||||||
|
| datatype, binding remainder
|
||||||
|
|
||||||
|
var binding = "var", datatype?, binding remainder
|
||||||
|
|
||||||
|
binding remainder = identifier, "=", expression
|
||||||
|
*/
|
||||||
pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParsingResult<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: Revert to val/var
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* let keyword
|
* val/var keyword
|
||||||
*/
|
*/
|
||||||
let (is_mutable, binding_token, next_pos) = {
|
let (is_var, binding_token, next_pos) = 'token: {
|
||||||
match parse_token_type(tokens, current_pos, TokenType::VAL) {
|
// check for VAL
|
||||||
Ok((val_token, next_pos)) => (false, val_token, next_pos),
|
if let Ok((val_token, next_pos)) = parse_token_type(tokens, current_pos, TokenType::VAL) {
|
||||||
_ => {
|
break 'token (false, Some(val_token), next_pos);
|
||||||
// If VAL is not found, search for VAR
|
};
|
||||||
match parse_token_type(tokens, current_pos, TokenType::VAR) {
|
|
||||||
Ok((var_token, next_pos)) => (true, var_token, next_pos),
|
// check for VAR
|
||||||
_ => return Err(ParsingError::Unmatched),
|
match parse_token_type(tokens, current_pos, TokenType::VAR) {
|
||||||
}
|
Ok((var_token, next_pos)) => (true, Some(var_token), next_pos),
|
||||||
}
|
// If a VAR is not found it is still possible that the binding is an implicit VAL
|
||||||
|
_ => (false, None, current_pos),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* datatype
|
||||||
|
*/
|
||||||
|
let (datatype, next_pos) = match parse_token_type(tokens, current_pos, TokenType::Datatype) {
|
||||||
|
Ok((t, next)) => (Some(t), next),
|
||||||
|
_ => (None, current_pos),
|
||||||
|
};
|
||||||
|
current_pos = next_pos;
|
||||||
|
|
||||||
|
// Here:
|
||||||
|
// If the binding is None and the datatype is None, then we didn't match a binding
|
||||||
|
if binding_token.is_none() && datatype.is_none() {
|
||||||
|
return Err(ParsingError::Unmatched);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* identifier
|
* identifier
|
||||||
*/
|
*/
|
||||||
@ -45,15 +67,29 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParsingResult<Bindin
|
|||||||
return Err(ParsingError::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 or the Datatype
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
match (binding_token, datatype) {
|
||||||
reason: format!(
|
(Some(binding_token), _) => {
|
||||||
"There should be an identifier after a `{}` token",
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
if is_mutable { "val" } else { "var" }
|
reason: format!(
|
||||||
),
|
"There should be an identifier after a `{}` token",
|
||||||
error_start: binding_token.position,
|
if is_var { "val" } else { "var" }
|
||||||
error_end: binding_token.get_end_position(),
|
),
|
||||||
}));
|
error_start: binding_token.position,
|
||||||
|
error_end: binding_token.get_end_position(),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
(None, Some(datatype_token)) => {
|
||||||
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
|
reason: "There should be an identifier after the datatype".into(),
|
||||||
|
error_start: datatype_token.position,
|
||||||
|
error_end: datatype_token.get_end_position(),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
panic!("Illegal parser state: binding_token and datatype are both None")
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
@ -82,6 +118,9 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParsingResult<Bindin
|
|||||||
};
|
};
|
||||||
current_pos += 1;
|
current_pos += 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Expression of the binding
|
||||||
|
*/
|
||||||
let (expression, next_pos) = match expression::try_parse(tokens, current_pos) {
|
let (expression, next_pos) = match expression::try_parse(tokens, current_pos) {
|
||||||
Ok((exp, next)) => (exp, next),
|
Ok((exp, next)) => (exp, next),
|
||||||
_ => {
|
_ => {
|
||||||
@ -95,10 +134,10 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParsingResult<Bindin
|
|||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
|
|
||||||
let binding = Binding {
|
let binding = Binding {
|
||||||
datatype: None,
|
datatype,
|
||||||
identifier: &identifier,
|
identifier: &identifier,
|
||||||
expression,
|
expression,
|
||||||
is_mutable,
|
is_mutable: is_var,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok((binding, current_pos))
|
Ok((binding, current_pos))
|
||||||
@ -144,26 +183,51 @@ mod tests {
|
|||||||
assert_eq!("=", token.value);
|
assert_eq!("=", token.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_parse_binding_with_datatype() {
|
fn should_parse_val_binding_with_datatype() {
|
||||||
let tokens = get_tokens(&String::from("Num val identifier = 20")).unwrap();
|
let tokens = get_tokens(&String::from("val Int identifier = 20")).unwrap();
|
||||||
let ParseResult::Ok(Binding::Val(binding), _) = try_parse(&tokens, 0) else {
|
let (binding, _) = try_parse(&tokens, 0).unwrap();
|
||||||
panic!()
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(Some(String::from("Num")), binding.datatype);
|
assert!(!binding.is_mutable);
|
||||||
assert_eq!("identifier", format!("{}", binding.identifier));
|
assert_eq!("Int", binding.datatype.unwrap().value);
|
||||||
|
assert_eq!("identifier", binding.identifier.value);
|
||||||
let tokens = get_tokens(&String::from("Bool var identifier = 20")).unwrap();
|
}
|
||||||
let ParseResult::Ok(Binding::Var(binding), _) = try_parse(&tokens, 0) else {
|
|
||||||
panic!()
|
#[test]
|
||||||
};
|
fn should_parse_var_binding_with_datatype() {
|
||||||
|
let tokens = get_tokens(&String::from("var Int identifier = 20")).unwrap();
|
||||||
assert_eq!(Some(String::from("Bool")), binding.datatype);
|
let (binding, _) = try_parse(&tokens, 0).unwrap();
|
||||||
assert_eq!("identifier", format!("{}", binding.identifier));
|
|
||||||
|
assert!(binding.is_mutable);
|
||||||
|
assert!(binding.datatype.is_some());
|
||||||
|
assert_eq!("Int", binding.datatype.unwrap().value);
|
||||||
|
assert_eq!("identifier", binding.identifier.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_parse_implicit_val_binding() {
|
||||||
|
let tokens = get_tokens(&String::from("Int identifier = 20")).unwrap();
|
||||||
|
let (binding, _) = try_parse(&tokens, 0).unwrap();
|
||||||
|
|
||||||
|
assert!(!binding.is_mutable);
|
||||||
|
assert!(binding.datatype.is_some());
|
||||||
|
assert_eq!("Int", binding.datatype.unwrap().value);
|
||||||
|
assert_eq!("identifier", binding.identifier.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_return_error_on_implicit_val_binding() {
|
||||||
|
let tokens = get_tokens(&String::from("Int => 20")).unwrap();
|
||||||
|
let binding = try_parse(&tokens, 0);
|
||||||
|
|
||||||
|
match binding {
|
||||||
|
Err(ParsingError::Err(error)) => {
|
||||||
|
assert_eq!(4, error.error_start);
|
||||||
|
assert_eq!(6, error.error_end);
|
||||||
|
}
|
||||||
|
_ => panic!("Error expected"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_return_correct_error() {
|
fn should_return_correct_error() {
|
||||||
|
@ -69,7 +69,6 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParsingResult<Functi
|
|||||||
};
|
};
|
||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
|
|
||||||
|
|
||||||
// Try to parse a return type
|
// Try to parse a return type
|
||||||
let (return_type, next_pos) = 'return_label: {
|
let (return_type, next_pos) = 'return_label: {
|
||||||
let (arrow_op, next_pos) = match try_operator(tokens, current_pos, "->".into()) {
|
let (arrow_op, next_pos) = match try_operator(tokens, current_pos, "->".into()) {
|
||||||
@ -134,7 +133,6 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParsingResult<Functi
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::lexic::get_tokens;
|
use crate::lexic::get_tokens;
|
||||||
@ -355,7 +353,10 @@ mod tests {
|
|||||||
let (function_declaration, _) = try_parse(&tokens, 0).unwrap();
|
let (function_declaration, _) = try_parse(&tokens, 0).unwrap();
|
||||||
|
|
||||||
assert_eq!(function_declaration.identifier.value, String::from("id"));
|
assert_eq!(function_declaration.identifier.value, String::from("id"));
|
||||||
assert_eq!(function_declaration.return_type.unwrap().value, String::from("String"));
|
assert_eq!(
|
||||||
|
function_declaration.return_type.unwrap().value,
|
||||||
|
String::from("String")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -58,7 +58,13 @@ arguments list = "(", ")"
|
|||||||
## Binding
|
## Binding
|
||||||
|
|
||||||
```ebnf
|
```ebnf
|
||||||
binding = ("val" | "var"), identifier, "=", expression
|
binding = val binding | var binding
|
||||||
|
val binding = "val", datatype?, binding remainder
|
||||||
|
| datatype, binding remainder
|
||||||
|
|
||||||
|
var binding = "var", datatype?, binding remainder
|
||||||
|
|
||||||
|
binding remainder = identifier, "=", expression
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
@ -75,5 +75,3 @@ pub fn parse_token_type(
|
|||||||
None => Err(ParsingError::Unmatched),
|
None => Err(ParsingError::Unmatched),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user