feat: enforce new line after a statement
This commit is contained in:
parent
f0cde4a28e
commit
b481351597
@ -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
|
||||
|
@ -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) => {
|
||||
|
@ -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"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user