feat: enforce new line after a statement

master
Araozu 2024-08-27 09:43:08 -05:00
parent f0cde4a28e
commit b481351597
4 changed files with 83 additions and 1 deletions

View File

@ -30,6 +30,7 @@
- [x] Check for conflicting identifiers at the current scope
- [x] Semantic check for unary operator
- [x] Semantic check for binary operator
- [x] Enforce new lines after every statement
## v0.1.0

View File

@ -58,7 +58,9 @@ impl Typed for Expression<'_> {
})),
}
}
_ => unimplemented!("Get datatype of an expression that resolves into a function call"),
_ => unimplemented!(
"Get datatype of an expression that resolves into a function call"
),
}
}
Expression::UnaryOperator(op, exp) => {

View File

@ -125,6 +125,26 @@ impl<'a> Parseable<'a> for VariableBinding<'a> {
}
};
// After the expression there should be a new line
// to terminate the statement
match tokens.get(next_pos) {
Some(t) if t.token_type == TokenType::NewLine || t.token_type == TokenType::EOF => {
// continue
}
Some(t) => {
return Err(ParsingError::Err(SyntaxError {
error_start: t.position,
error_end: t.get_end_position(),
reason: format!("Unexpected token `{}`, expected a new line", t.value),
}))
}
_ => {
// this should never happen, the lexer always appends
// an EOF
unreachable!("got to the final of a token stream without finding EOF")
}
}
let binding = VariableBinding {
datatype,
identifier: &identifier,
@ -354,4 +374,22 @@ mod tests {
_ => panic!("Error expected"),
}
}
#[test]
fn should_error_when_there_is_no_delimiter() {
let tokens = get_tokens(&String::from("val identifier = 322 print(identifier)")).unwrap();
let binding = VariableBinding::try_parse(&tokens, 0);
match binding {
Err(ParsingError::Err(error)) => {
assert_eq!(21, error.error_start);
assert_eq!(26, error.error_end);
assert_eq!(
"Unexpected token `print`, expected a new line",
error.reason
);
}
_ => panic!("Error expected"),
}
}
}

View File

@ -40,6 +40,32 @@ impl<'a> Parseable<'a> for ModuleAST<'a> {
// Attempt to parse an expression
match Expression::try_parse(tokens, current_pos) {
Ok((prod, next_pos)) => {
// After a expression is parsed as an statement
// there should be a delimiter (new line or EOF)
match tokens.get(next_pos) {
Some(t)
if t.token_type == TokenType::NewLine
|| t.token_type == TokenType::EOF =>
{
// continue
}
Some(t) => {
return Err(ParsingError::Err(SyntaxError {
error_start: t.position,
error_end: t.get_end_position(),
reason: format!(
"Unexpected token `{}`, expected a new line",
t.value
),
}))
}
_ => {
// this should never happen, the lexer always appends
// an EOF
unreachable!("got to the final of a token stream without finding EOF")
}
}
productions.push(ModuleMembers::Expr(prod));
current_pos = next_pos;
continue;
@ -122,4 +148,19 @@ mod test {
Err(_) => {}
}
}
#[test]
fn should_fail_on_two_expressions_together() {
// TODO: enforce newlines after every statement
let tokens = get_tokens(&String::from("print print")).unwrap();
let result = ModuleAST::try_parse(&tokens, 0);
match result {
Ok(_) => panic!("Expected an error"),
Err(ParsingError::Err(err)) => {
assert_eq!("Unexpected token `print`, expected a new line", err.reason);
}
_ => panic!("Expected a parsing error"),
}
}
}