feat: semantic check for unary op

master
Araozu 2024-08-27 07:50:57 -05:00
parent 28d48c8b2f
commit ee9b12253d
7 changed files with 65 additions and 6 deletions

View File

@ -28,6 +28,7 @@
- [x] Scan octal and binary numbers
- [x] Simple type checking
- [x] Check for conflicting identifiers at the current scope
- [x] Semantic check for unary operator
## v0.1.0

View File

@ -8,6 +8,13 @@ impl Transpilable for PPrimary<'_> {
PPrimary::StringLiteral(value) => format!("\"{}\"", value),
PPrimary::Variable(name) => format!("${}", name),
PPrimary::Symbol(name) => format!("{}", name),
PPrimary::BoolLiteral(bool) => {
if *bool {
String::from("true")
} else {
String::from("false")
}
}
}
}
}

View File

@ -8,7 +8,7 @@ impl Transpilable for PFile<'_> {
fragments.push(statement.transpile());
}
fragments.join("")
fragments.join("\n")
}
}
@ -37,6 +37,6 @@ mod tests {
};
let output = ast.transpile();
assert_eq!("<?php\n\"Hello world!\";", output);
assert_eq!("<?php\n\n\"Hello world!\";", output);
}
}

View File

@ -52,6 +52,7 @@ pub enum PPrimary<'a> {
IntegerLiteral(&'a String),
FloatingLiteral(&'a String),
StringLiteral(&'a String),
BoolLiteral(bool),
/// https://phplang.org/spec/19-grammar.html#grammar-variable
///
/// Supports only variable -> callable-variable -> simple-variable -> variable-name

View File

@ -32,7 +32,11 @@ impl<'a> PHPTransformable<'a> for Expression<'_> {
PExpresssion::FunctionCall(fn_call_expr)
}
Expression::Identifier(i) => PExpresssion::Primary(PPrimary::Variable(&i.value)),
_ => todo!("transformation for expression: {:?}", self),
Expression::Boolean(b) => {
PExpresssion::Primary(PPrimary::BoolLiteral(b.value == "true"))
}
Expression::UnaryOperator(_, _) => unimplemented!("transform unary op into php"),
Expression::BinaryOperator(_, _, _) => unimplemented!("transform binary op into php"),
}
}
}

View File

@ -43,7 +43,6 @@ impl SemanticCheck for Expression<'_> {
// The argument and the parameter have diferent types
let (error_start, error_end) = argument.get_position();
return Err(MistiError::Semantic(SemanticError {
// TODO: fix
error_start,
error_end,
reason: format!(
@ -67,11 +66,48 @@ impl SemanticCheck for Expression<'_> {
}
}
}
// These are empty because they have nothing to check,
// their existance alone is correct
Expression::Int(_) => {}
Expression::Float(_) => {}
Expression::String(_) => {}
Expression::Boolean(_) => {}
_ => todo!("Check semantics for expression other than function call and primitive"),
Expression::Identifier(_) => {}
Expression::UnaryOperator(operator, expression) => {
// There are a limited amount of unary operators,
// so their checking is not generalized
let expr_type = expression.get_type(scope)?;
match (operator.value.as_str(), expr_type) {
("!", Type::Value(t)) => {
if t == "Bool" {
// Ok, empty
} else {
// Error: unary negation can only be applied to a Bool
let (error_start, error_end) = expression.get_position();
return Err(MistiError::Semantic(SemanticError {
error_start,
error_end,
reason: format!("Expected a Bool, got a {}", t),
}));
}
}
("!", Type::Function(_, _)) => {
// Error: unary negation can only be applied to a Bool
let (error_start, error_end) = expression.get_position();
return Err(MistiError::Semantic(SemanticError {
error_start,
error_end,
reason: format!("Expected a Bool, got a function",),
}));
}
(op, _) => {
// Compiler error: something that shouldn't be
// parsed as a unary operator was found.
unreachable!("Found a unary operator that shouldn't be: {}", op)
}
}
}
Expression::BinaryOperator(_, _, _) => unimplemented!(),
}
Ok(())

View File

@ -1,6 +1,6 @@
use crate::{
error_handling::SyntaxError,
lexic::token::Token,
lexic::token::{Token, TokenType},
syntax::{
ast::{Expression, ModuleAST, ModuleMembers, Statement},
parseable::{Parseable, ParsingError, ParsingResult},
@ -51,6 +51,16 @@ impl<'a> Parseable<'a> for ModuleAST<'a> {
_ => {}
}
// Ignore comments, if any
if let Some(s) = tokens.get(current_pos) {
if s.token_type == TokenType::Comment
|| s.token_type == TokenType::MultilineComment
{
current_pos += 1;
continue;
}
}
// If we reached this point we didn't match any productions and fail
let t = &tokens[current_pos];