feat: semantic check for unary op
This commit is contained in:
parent
28d48c8b2f
commit
ee9b12253d
@ -28,6 +28,7 @@
|
|||||||
- [x] Scan octal and binary numbers
|
- [x] Scan octal and binary numbers
|
||||||
- [x] Simple type checking
|
- [x] Simple type checking
|
||||||
- [x] Check for conflicting identifiers at the current scope
|
- [x] Check for conflicting identifiers at the current scope
|
||||||
|
- [x] Semantic check for unary operator
|
||||||
|
|
||||||
|
|
||||||
## v0.1.0
|
## v0.1.0
|
||||||
|
@ -8,6 +8,13 @@ impl Transpilable for PPrimary<'_> {
|
|||||||
PPrimary::StringLiteral(value) => format!("\"{}\"", value),
|
PPrimary::StringLiteral(value) => format!("\"{}\"", value),
|
||||||
PPrimary::Variable(name) => format!("${}", name),
|
PPrimary::Variable(name) => format!("${}", name),
|
||||||
PPrimary::Symbol(name) => format!("{}", name),
|
PPrimary::Symbol(name) => format!("{}", name),
|
||||||
|
PPrimary::BoolLiteral(bool) => {
|
||||||
|
if *bool {
|
||||||
|
String::from("true")
|
||||||
|
} else {
|
||||||
|
String::from("false")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ impl Transpilable for PFile<'_> {
|
|||||||
fragments.push(statement.transpile());
|
fragments.push(statement.transpile());
|
||||||
}
|
}
|
||||||
|
|
||||||
fragments.join("")
|
fragments.join("\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,6 +37,6 @@ mod tests {
|
|||||||
};
|
};
|
||||||
let output = ast.transpile();
|
let output = ast.transpile();
|
||||||
|
|
||||||
assert_eq!("<?php\n\"Hello world!\";", output);
|
assert_eq!("<?php\n\n\"Hello world!\";", output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,7 @@ pub enum PPrimary<'a> {
|
|||||||
IntegerLiteral(&'a String),
|
IntegerLiteral(&'a String),
|
||||||
FloatingLiteral(&'a String),
|
FloatingLiteral(&'a String),
|
||||||
StringLiteral(&'a String),
|
StringLiteral(&'a String),
|
||||||
|
BoolLiteral(bool),
|
||||||
/// https://phplang.org/spec/19-grammar.html#grammar-variable
|
/// https://phplang.org/spec/19-grammar.html#grammar-variable
|
||||||
///
|
///
|
||||||
/// Supports only variable -> callable-variable -> simple-variable -> variable-name
|
/// Supports only variable -> callable-variable -> simple-variable -> variable-name
|
||||||
|
@ -32,7 +32,11 @@ impl<'a> PHPTransformable<'a> for Expression<'_> {
|
|||||||
PExpresssion::FunctionCall(fn_call_expr)
|
PExpresssion::FunctionCall(fn_call_expr)
|
||||||
}
|
}
|
||||||
Expression::Identifier(i) => PExpresssion::Primary(PPrimary::Variable(&i.value)),
|
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"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,6 @@ impl SemanticCheck for Expression<'_> {
|
|||||||
// The argument and the parameter have diferent types
|
// The argument and the parameter have diferent types
|
||||||
let (error_start, error_end) = argument.get_position();
|
let (error_start, error_end) = argument.get_position();
|
||||||
return Err(MistiError::Semantic(SemanticError {
|
return Err(MistiError::Semantic(SemanticError {
|
||||||
// TODO: fix
|
|
||||||
error_start,
|
error_start,
|
||||||
error_end,
|
error_end,
|
||||||
reason: format!(
|
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::Int(_) => {}
|
||||||
Expression::Float(_) => {}
|
Expression::Float(_) => {}
|
||||||
Expression::String(_) => {}
|
Expression::String(_) => {}
|
||||||
Expression::Boolean(_) => {}
|
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(())
|
Ok(())
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error_handling::SyntaxError,
|
error_handling::SyntaxError,
|
||||||
lexic::token::Token,
|
lexic::token::{Token, TokenType},
|
||||||
syntax::{
|
syntax::{
|
||||||
ast::{Expression, ModuleAST, ModuleMembers, Statement},
|
ast::{Expression, ModuleAST, ModuleMembers, Statement},
|
||||||
parseable::{Parseable, ParsingError, ParsingResult},
|
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
|
// If we reached this point we didn't match any productions and fail
|
||||||
let t = &tokens[current_pos];
|
let t = &tokens[current_pos];
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user