feat: parse assignments
This commit is contained in:
parent
68d3e0dba4
commit
aede32a068
@ -16,6 +16,7 @@
|
||||
- Remove all panic! and todo!
|
||||
- Change REPL to execute code only after `;;` is found
|
||||
- Forward the code generated by the REPL to the PHP repl
|
||||
- Test assignment parsing
|
||||
|
||||
|
||||
## v0.1.3
|
||||
@ -23,6 +24,12 @@
|
||||
- [ ] Test semantic analysis
|
||||
- [ ] Generate php code from current AST
|
||||
- [x] Test correct operator precedence
|
||||
- [x] Parse assignments
|
||||
- [ ] Parse dot `.` operator
|
||||
- [ ] Parse logic operators `&& ||`
|
||||
- [ ] Parse Array access `arr[pos]`
|
||||
- [ ] Parse namespace operator `::`
|
||||
- [ ] Implement subtyping for numbers
|
||||
|
||||
|
||||
## v0.1.2
|
||||
|
@ -24,6 +24,7 @@ pub const COMPILER_TODO: u32 = 20;
|
||||
pub const SEMANTIC_MISMATCHED_TYPES: u32 = 21;
|
||||
pub const SEMANTIC_DUPLICATED_REFERENCE: u32 = 22;
|
||||
pub const SEMANTIC_MISMATCHED_ARGUMENT_COUNT: u32 = 23;
|
||||
pub const SYNTAX_INVALID_ASSIGNMENT: u32 = 24;
|
||||
|
||||
/// Reads the error codes from the error code list
|
||||
pub fn error_code_to_string() -> String {
|
||||
|
@ -25,6 +25,9 @@ impl SemanticCheck for Statement<'_> {
|
||||
Statement::Conditional(c) => c.check_semantics(scope),
|
||||
Statement::ForLoop(f) => f.check_semantics(scope),
|
||||
Statement::WhileLoop(w) => w.check_semantics(scope),
|
||||
Statement::Assignment(_assignment) => {
|
||||
unimplemented!("Semantic check for an assignment")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,6 +37,15 @@ pub enum Statement<'a> {
|
||||
Conditional(Conditional<'a>),
|
||||
ForLoop(ForLoop<'a>),
|
||||
WhileLoop(WhileLoop<'a>),
|
||||
Assignment(Assignment<'a>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Assignment<'a> {
|
||||
/// The left side of the assignment
|
||||
pub identifier: &'a Token,
|
||||
/// The right side of the assignment
|
||||
pub expression: Box<Expression<'a>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
91
src/syntax/parsers/assignment.rs
Normal file
91
src/syntax/parsers/assignment.rs
Normal file
@ -0,0 +1,91 @@
|
||||
use crate::{
|
||||
error_handling::{error_messages::SYNTAX_INVALID_ASSIGNMENT, ErrorContainer, ErrorLabel},
|
||||
lexic::token::{self, TokenType},
|
||||
syntax::{
|
||||
ast::{Assignment, Expression},
|
||||
parseable::{self, Parseable, ParsingError},
|
||||
utils::{parse_token_type, try_operator},
|
||||
},
|
||||
};
|
||||
|
||||
/// https://thp-lang.org/spec/ast/ast/#assignment
|
||||
impl<'a> Parseable<'a> for Assignment<'a> {
|
||||
type Item = Assignment<'a>;
|
||||
|
||||
fn try_parse(
|
||||
tokens: &'a Vec<token::Token>,
|
||||
current_pos: usize,
|
||||
) -> parseable::ParsingResult<'a, Self::Item> {
|
||||
// parse the target identifier
|
||||
let (identifier, next) = match parse_token_type(tokens, current_pos, TokenType::Identifier)
|
||||
{
|
||||
Ok(tuple) => tuple,
|
||||
_ => return Err(ParsingError::Unmatched),
|
||||
};
|
||||
|
||||
// parse the equal sign
|
||||
let (equal_operator, next) = match try_operator(tokens, next, String::from("=")) {
|
||||
Ok((t, next)) => (t, next),
|
||||
Err(ParsingError::Mismatch(t)) => {
|
||||
// The parser found a token, but it's not the `=` operator
|
||||
let label = ErrorLabel {
|
||||
message: String::from("Expected an equal sign `=` here, the identifier"),
|
||||
start: t.position,
|
||||
end: t.get_end_position(),
|
||||
};
|
||||
let econtainer = ErrorContainer {
|
||||
error_code: SYNTAX_INVALID_ASSIGNMENT,
|
||||
error_offset: t.position,
|
||||
labels: vec![label],
|
||||
note: None,
|
||||
help: None,
|
||||
};
|
||||
return Err(ParsingError::Err(econtainer));
|
||||
}
|
||||
_ => {
|
||||
// The parser didn't find the `=` operator after the identifier
|
||||
let label = ErrorLabel {
|
||||
message: String::from("Expected an equal sign `=` after this identifier"),
|
||||
start: identifier.position,
|
||||
end: identifier.get_end_position(),
|
||||
};
|
||||
let econtainer = ErrorContainer {
|
||||
error_code: SYNTAX_INVALID_ASSIGNMENT,
|
||||
error_offset: identifier.position,
|
||||
labels: vec![label],
|
||||
note: None,
|
||||
help: None,
|
||||
};
|
||||
return Err(ParsingError::Err(econtainer));
|
||||
}
|
||||
};
|
||||
|
||||
// parse the expression
|
||||
let (expression, next) = match Expression::try_parse(tokens, next) {
|
||||
Ok((exp, next)) => (exp, next),
|
||||
_ => {
|
||||
let label = ErrorLabel {
|
||||
message: String::from("Expected an expression after this equal `=` operator"),
|
||||
start: equal_operator.position,
|
||||
end: equal_operator.get_end_position(),
|
||||
};
|
||||
let econtainer = ErrorContainer {
|
||||
error_code: SYNTAX_INVALID_ASSIGNMENT,
|
||||
error_offset: equal_operator.position,
|
||||
labels: vec![label],
|
||||
note: None,
|
||||
help: None,
|
||||
};
|
||||
return Err(ParsingError::Err(econtainer));
|
||||
}
|
||||
};
|
||||
|
||||
// Build and return the assignment object
|
||||
let assignment = Assignment {
|
||||
identifier,
|
||||
expression: Box::new(expression),
|
||||
};
|
||||
|
||||
Ok((assignment, next))
|
||||
}
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
pub mod assignment;
|
||||
pub mod binding;
|
||||
pub mod block;
|
||||
pub mod conditional;
|
||||
|
@ -4,7 +4,7 @@ use crate::{
|
||||
ast::{
|
||||
loops::{ForLoop, WhileLoop},
|
||||
var_binding::VariableBinding,
|
||||
Conditional, FunctionDeclaration, Statement,
|
||||
Assignment, Conditional, FunctionDeclaration, Statement,
|
||||
},
|
||||
parseable::{Parseable, ParsingError, ParsingResult},
|
||||
},
|
||||
@ -59,6 +59,13 @@ impl<'a> Parseable<'a> for Statement<'a> {
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Try to parse an assignment
|
||||
match Assignment::try_parse(tokens, current_pos) {
|
||||
Ok((prod, next)) => return Ok((Statement::Assignment(prod), next)),
|
||||
Err(ParsingError::Err(e)) => return Err(ParsingError::Err(e)),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Here nothing was parsed.
|
||||
Err(ParsingError::Unmatched)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user