From 6eef841e84cb4a4447497ae5d3ed59c4caa55fb8 Mon Sep 17 00:00:00 2001 From: Araozu Date: Thu, 1 Aug 2024 17:49:25 -0500 Subject: [PATCH] feat: Naive transpiling of variable bindings --- CHANGELOG.md | 1 + Cargo.lock | 2 +- Cargo.toml | 2 +- src/codegen/php/expression/mod.rs | 2 +- src/codegen/php/statement_list.rs | 22 +++++- src/php_ast/transformers/expression.rs | 67 ++++++++++++++++++ src/php_ast/transformers/module_ast.rs | 15 ++++ src/php_ast/transformers/statement.rs | 74 +++++++++++++++++++- src/semantic/checks/top_level_declaration.rs | 8 +-- 9 files changed, 184 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 87e3fc5..c822c9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ ## v0.1.1 - [x] Top level expressions as statements +- [ ] Naively transpile variable bindings ## v0.1.0 diff --git a/Cargo.lock b/Cargo.lock index 2ffbd66..58ab771 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -92,7 +92,7 @@ dependencies = [ [[package]] name = "thp" -version = "0.0.14" +version = "0.1.0" dependencies = [ "colored", "serde", diff --git a/Cargo.toml b/Cargo.toml index 28d918b..31aec6d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "thp" -version = "0.0.14" +version = "0.1.0" edition = "2021" diff --git a/src/codegen/php/expression/mod.rs b/src/codegen/php/expression/mod.rs index dccd81f..e653e89 100644 --- a/src/codegen/php/expression/mod.rs +++ b/src/codegen/php/expression/mod.rs @@ -1,2 +1,2 @@ -mod primary_expression; mod assignment; +mod primary_expression; diff --git a/src/codegen/php/statement_list.rs b/src/codegen/php/statement_list.rs index 95491df..54a16f4 100644 --- a/src/codegen/php/statement_list.rs +++ b/src/codegen/php/statement_list.rs @@ -14,7 +14,12 @@ impl Transpilable for PhpAst<'_> { #[cfg(test)] mod tests { - use crate::{codegen::Transpilable, php_ast::PhpAst}; + use crate::{ + codegen::Transpilable, + php_ast::{ + PhpAssignmentExpression, PhpAst, PhpExpression, PhpPrimaryExpression, PhpStatement, + }, + }; #[test] fn should_transpile_empty_file() { @@ -23,4 +28,19 @@ mod tests { assert_eq!(" PHPTransformable<'a> for Expression<'_> { let expr = PhpPrimaryExpression::StringLiteral(value); PhpExpression::Assignment(PhpAssignmentExpression::Primary(expr)) } + Expression::Int(value) => { + let expr = PhpPrimaryExpression::IntegerLiteral(value); + PhpExpression::Assignment(PhpAssignmentExpression::Primary(expr)) + } + Expression::Float(value) => { + let expr = PhpPrimaryExpression::FloatingLiteral(value); + PhpExpression::Assignment(PhpAssignmentExpression::Primary(expr)) + } _ => todo!("transformation for expression: {:?}", self), } } } + +#[cfg(test)] +mod tests { + use crate::{ + php_ast::{ + transformers::PHPTransformable, PhpAssignmentExpression, PhpExpression, + PhpPrimaryExpression, + }, + syntax::ast::Expression, + }; + + #[test] + fn should_transform_string() { + let value = String::from("Hello"); + let input = Expression::String(&value); + let output = input.into_php_ast(); + + match output { + PhpExpression::Assignment(PhpAssignmentExpression::Primary( + PhpPrimaryExpression::StringLiteral(value), + )) => { + assert_eq!("Hello", value) + } + _ => panic!("Expected a String literal"), + } + } + + #[test] + fn should_transform_int() { + let value = String::from("322"); + let input = Expression::Int(&value); + let output = input.into_php_ast(); + + match output { + PhpExpression::Assignment(PhpAssignmentExpression::Primary( + PhpPrimaryExpression::IntegerLiteral(value), + )) => { + assert_eq!("322", value) + } + _ => panic!("Expected a Int literal"), + } + } + + #[test] + fn should_transform_float() { + let value = String::from("322.644"); + let input = Expression::Float(&value); + let output = input.into_php_ast(); + + match output { + PhpExpression::Assignment(PhpAssignmentExpression::Primary( + PhpPrimaryExpression::FloatingLiteral(value), + )) => { + assert_eq!("322.644", value) + } + _ => panic!("Expected a Float literal"), + } + } +} diff --git a/src/php_ast/transformers/module_ast.rs b/src/php_ast/transformers/module_ast.rs index f85b4ca..7fcfed7 100644 --- a/src/php_ast/transformers/module_ast.rs +++ b/src/php_ast/transformers/module_ast.rs @@ -85,3 +85,18 @@ impl<'a> PHPTransformable<'a> for ModuleAST<'_> { } } } + +#[cfg(test)] +mod tests { + use crate::{php_ast::transformers::PHPTransformable, syntax::ast::ModuleAST}; + + #[test] + fn should_transform_empty_ast() { + let input = ModuleAST { + productions: vec![], + }; + let output = input.into_php_ast(); + + assert!(output.statements.is_empty()) + } +} diff --git a/src/php_ast/transformers/statement.rs b/src/php_ast/transformers/statement.rs index f6d1da8..329b38d 100644 --- a/src/php_ast/transformers/statement.rs +++ b/src/php_ast/transformers/statement.rs @@ -1,5 +1,8 @@ use super::super::PhpStatement; -use crate::syntax::ast::Statement; +use crate::{ + php_ast::{PhpAssignmentExpression, PhpExpression, PhpSimpleAssignment}, + syntax::ast::Statement, +}; use super::PHPTransformable; @@ -9,7 +12,76 @@ impl<'a> PHPTransformable<'a> for Statement<'_> { fn into_php_ast(&'a self) -> Self::Item { match self { + Statement::Binding(b) => { + // This is a PhpExpression, but a PhpPrimaryExpression is needed + let binding_expr = b.expression.into_php_ast(); + + // TODO: Somehow fix this... + // the function above `into_php_ast` should somehow + // return what I need? Or should return something general and + // then i decide how to transform it here? + // if it reaches this point in the pipeline, is it + // safe to assume that any AST is correct, since + // semantic analysis (supposedly) did its job? + let binding_primary_expr = match binding_expr { + PhpExpression::Assignment(PhpAssignmentExpression::Primary(p)) => p, + _ => unreachable!("Expected a PrimaryExpression during AST transformation"), + }; + + PhpStatement::PhpExpressionStatement(PhpExpression::Assignment( + PhpAssignmentExpression::SimpleAssignment(PhpSimpleAssignment { + variable: b.identifier.value.clone(), + assignment: binding_primary_expr, + }), + )) + } _ => todo!("transformation for statement: {:?}", self), } } } + +#[cfg(test)] +mod tests { + use crate::{ + lexic::token::{Token, TokenType}, + php_ast::{ + transformers::PHPTransformable, PhpAssignmentExpression, PhpExpression, + PhpPrimaryExpression, PhpStatement, + }, + syntax::ast::{var_binding::VariableBinding, Expression, Statement}, + }; + + #[test] + fn should_transform_binding() { + let identifier_token = Token { + token_type: TokenType::Identifier, + value: "name".into(), + position: 0, + }; + let expr_value = String::from("Hello"); + let expression = Expression::String(&expr_value); + let binding = Statement::Binding(VariableBinding { + datatype: None, + identifier: &identifier_token, + expression, + is_mutable: false, + }); + let output = binding.into_php_ast(); + + match output { + PhpStatement::PhpExpressionStatement(PhpExpression::Assignment( + PhpAssignmentExpression::SimpleAssignment(assignment), + )) => { + assert_eq!("name", assignment.variable); + + match assignment.assignment { + PhpPrimaryExpression::StringLiteral(value) => { + assert_eq!("Hello", value); + } + _ => panic!("Expected a String literal as the value of the assignment"), + } + } + _ => panic!("Expected an ExpressionStatement"), + } + } +} diff --git a/src/semantic/checks/top_level_declaration.rs b/src/semantic/checks/top_level_declaration.rs index d7e5509..e649ac5 100644 --- a/src/semantic/checks/top_level_declaration.rs +++ b/src/semantic/checks/top_level_declaration.rs @@ -88,10 +88,10 @@ impl SemanticCheck for Expression<'_> { } } } - Expression::Int(_) => {}, - Expression::Float(_) => {}, - Expression::String(_) => {}, - Expression::Boolean(_) => {}, + Expression::Int(_) => {} + Expression::Float(_) => {} + Expression::String(_) => {} + Expression::Boolean(_) => {} _ => todo!("Check semantics for expression other than function call and primitive"), }