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] Check for conflicting identifiers at the current scope
|
||||||
- [x] Semantic check for unary operator
|
- [x] Semantic check for unary operator
|
||||||
- [x] Semantic check for binary operator
|
- [x] Semantic check for binary operator
|
||||||
|
- [x] Enforce new lines after every statement
|
||||||
|
|
||||||
|
|
||||||
## v0.1.0
|
## 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) => {
|
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 {
|
let binding = VariableBinding {
|
||||||
datatype,
|
datatype,
|
||||||
identifier: &identifier,
|
identifier: &identifier,
|
||||||
@ -354,4 +374,22 @@ mod tests {
|
|||||||
_ => panic!("Error expected"),
|
_ => 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
|
// Attempt to parse an expression
|
||||||
match Expression::try_parse(tokens, current_pos) {
|
match Expression::try_parse(tokens, current_pos) {
|
||||||
Ok((prod, next_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));
|
productions.push(ModuleMembers::Expr(prod));
|
||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
continue;
|
continue;
|
||||||
@ -122,4 +148,19 @@ mod test {
|
|||||||
Err(_) => {}
|
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