diff --git a/CHANGELOG.md b/CHANGELOG.md index 72c62ca..0b3adbc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/src/codegen/php/expression/primary_expression.rs b/src/codegen/php/expression/primary_expression.rs index a071d14..b728fb1 100644 --- a/src/codegen/php/expression/primary_expression.rs +++ b/src/codegen/php/expression/primary_expression.rs @@ -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") + } + } } } } diff --git a/src/codegen/php/statement_list.rs b/src/codegen/php/statement_list.rs index 0af1b8c..7455654 100644 --- a/src/codegen/php/statement_list.rs +++ b/src/codegen/php/statement_list.rs @@ -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!(" { 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 diff --git a/src/php_ast/transformers/expression.rs b/src/php_ast/transformers/expression.rs index bf74207..cc2a792 100644 --- a/src/php_ast/transformers/expression.rs +++ b/src/php_ast/transformers/expression.rs @@ -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"), } } } diff --git a/src/semantic/checks/expression.rs b/src/semantic/checks/expression.rs index 240e492..085e090 100644 --- a/src/semantic/checks/expression.rs +++ b/src/semantic/checks/expression.rs @@ -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(()) diff --git a/src/syntax/parsers/module.rs b/src/syntax/parsers/module.rs index 623e90a..6647f7e 100644 --- a/src/syntax/parsers/module.rs +++ b/src/syntax/parsers/module.rs @@ -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];