From 974c380eafbebfa58deb1c6ae81aec572751e4fb Mon Sep 17 00:00:00 2001 From: Araozu Date: Mon, 26 Aug 2024 16:13:54 -0500 Subject: [PATCH] refactor: revert to old ast transformation strategy --- src/codegen/php/expression/assignment.rs | 18 +++--- src/codegen/php/expression/mod.rs | 13 +++++ .../php/expression/primary_expression.rs | 18 ++++-- src/codegen/php/function/mod.rs | 9 +++ src/codegen/php/mod.rs | 9 +-- src/codegen/php/statement/echo_statement.rs | 1 - src/codegen/php/statement/mod.rs | 28 +++------- src/codegen/php/statement_list.rs | 12 ++-- src/php_ast/mod.rs | 2 + src/php_ast/php_ast_2.rs | 56 +++++++++++++++++++ src/php_ast/transformers/expression.rs | 32 ++++++++--- src/php_ast/transformers/functions.rs | 29 ++++++++++ src/php_ast/transformers/mod.rs | 5 +- src/php_ast/transformers/module_ast.rs | 21 +++++-- src/php_ast/transformers/statement.rs | 36 +++++------- 15 files changed, 203 insertions(+), 86 deletions(-) create mode 100644 src/codegen/php/function/mod.rs delete mode 100644 src/codegen/php/statement/echo_statement.rs create mode 100644 src/php_ast/php_ast_2.rs create mode 100644 src/php_ast/transformers/functions.rs diff --git a/src/codegen/php/expression/assignment.rs b/src/codegen/php/expression/assignment.rs index ec83a0b..f83a98e 100644 --- a/src/codegen/php/expression/assignment.rs +++ b/src/codegen/php/expression/assignment.rs @@ -1,16 +1,14 @@ -use crate::{codegen::Transpilable, php_ast::PhpAssignmentExpression}; +use crate::{ + codegen::Transpilable, + php_ast::{php_ast_2::PSimpleAssignment, PhpAssignmentExpression}, +}; -impl Transpilable for PhpAssignmentExpression<'_> { +impl Transpilable for PSimpleAssignment<'_> { fn transpile(&self) -> String { - match self { - PhpAssignmentExpression::Primary(p) => p.transpile(), - PhpAssignmentExpression::SimpleAssignment(assignment) => { - let variable_name = &assignment.variable; - let expression_str = assignment.assignment.transpile(); + let variable_name = self.variable; + let expression_str = self.assignment.transpile(); - format!("${} = {}", variable_name, expression_str) - } - } + format!("${} = {}", variable_name, expression_str) } } diff --git a/src/codegen/php/expression/mod.rs b/src/codegen/php/expression/mod.rs index e653e89..275707a 100644 --- a/src/codegen/php/expression/mod.rs +++ b/src/codegen/php/expression/mod.rs @@ -1,2 +1,15 @@ +use crate::{codegen::Transpilable, php_ast::php_ast_2::PExpresssion}; +use PExpresssion::*; + mod assignment; mod primary_expression; + +impl Transpilable for PExpresssion<'_> { + fn transpile(&self) -> String { + match self { + Primary(p) => p.transpile(), + Assignment(a) => a.transpile(), + FunctionCall(f) => f.transpile(), + } + } +} diff --git a/src/codegen/php/expression/primary_expression.rs b/src/codegen/php/expression/primary_expression.rs index d4a4657..d075cc3 100644 --- a/src/codegen/php/expression/primary_expression.rs +++ b/src/codegen/php/expression/primary_expression.rs @@ -1,12 +1,16 @@ -use crate::{codegen::Transpilable, php_ast::PhpPrimaryExpression}; +use crate::{ + codegen::Transpilable, + php_ast::{php_ast_2::PPrimary, PhpPrimaryExpression}, +}; -impl Transpilable for PhpPrimaryExpression<'_> { +impl Transpilable for PPrimary<'_> { fn transpile(&self) -> String { match self { - PhpPrimaryExpression::IntegerLiteral(value) => value.to_string(), - PhpPrimaryExpression::FloatingLiteral(value) => value.to_string(), - PhpPrimaryExpression::StringLiteral(value) => format!("\"{}\"", value), - PhpPrimaryExpression::Variable(name) => format!("${}", name), + PPrimary::IntegerLiteral(value) => value.to_string(), + PPrimary::FloatingLiteral(value) => value.to_string(), + PPrimary::StringLiteral(value) => format!("\"{}\"", value), + PPrimary::Variable(name) => format!("${}", name), + PPrimary::Symbol(name) => format!("{}", name), } } } @@ -15,6 +19,7 @@ impl Transpilable for PhpPrimaryExpression<'_> { mod tests { use crate::{codegen::Transpilable, php_ast::PhpPrimaryExpression}; + /* #[test] fn should_transpile_empty_string() { let input = String::from(""); @@ -68,4 +73,5 @@ mod tests { assert_eq!("$name", output) } + */ } diff --git a/src/codegen/php/function/mod.rs b/src/codegen/php/function/mod.rs new file mode 100644 index 0000000..dddb260 --- /dev/null +++ b/src/codegen/php/function/mod.rs @@ -0,0 +1,9 @@ +use crate::{codegen::Transpilable, php_ast::php_ast_2::PFunctionCall}; + +impl Transpilable for PFunctionCall<'_> { + fn transpile(&self) -> String { + let args: Vec<_> = self.arguments.iter().map(|a| a.transpile()).collect(); + + format!("{}({})", self.function_name, args.join(", ")) + } +} diff --git a/src/codegen/php/mod.rs b/src/codegen/php/mod.rs index 9730bf2..5a5ef5e 100644 --- a/src/codegen/php/mod.rs +++ b/src/codegen/php/mod.rs @@ -4,11 +4,4 @@ use crate::php_ast::PhpExpression; mod expression; pub mod statement; pub mod statement_list; - -impl Transpilable for PhpExpression<'_> { - fn transpile(&self) -> String { - match self { - PhpExpression::Assignment(p) => p.transpile(), - } - } -} +mod function; diff --git a/src/codegen/php/statement/echo_statement.rs b/src/codegen/php/statement/echo_statement.rs deleted file mode 100644 index 8b13789..0000000 --- a/src/codegen/php/statement/echo_statement.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/codegen/php/statement/mod.rs b/src/codegen/php/statement/mod.rs index a3c444d..aa24515 100644 --- a/src/codegen/php/statement/mod.rs +++ b/src/codegen/php/statement/mod.rs @@ -1,26 +1,12 @@ -use crate::{codegen::Transpilable, php_ast::PhpStatement}; +use crate::{ + codegen::Transpilable, + php_ast::{php_ast_2::PStatement, PhpStatement}, +}; -mod echo_statement; - -impl Transpilable for PhpStatement<'_> { +impl Transpilable for PStatement<'_> { fn transpile(&self) -> String { match self { - PhpStatement::PhpEchoStatement(expr_list) => { - let expressions_vec = expr_list - .expressions - .iter() - .map(|e| e.transpile()) - .collect::>(); - - let expressions_str = if expressions_vec.is_empty() { - "\"\"".into() - } else { - expressions_vec.join(", ") - }; - - format!("echo {};", expressions_str) - } - PhpStatement::PhpExpressionStatement(expr) => { + PStatement::ExpressionStatement(expr) => { let expr_str = expr.transpile(); format!("{};", expr_str) } @@ -38,6 +24,7 @@ mod tests { }, }; + /* #[test] fn should_gen_empty_echo_statement() { let expressions = PhpExpressionList { @@ -95,4 +82,5 @@ mod tests { assert_eq!("\"Hi!\";", output) } + */ } diff --git a/src/codegen/php/statement_list.rs b/src/codegen/php/statement_list.rs index f7f2555..7b5f1be 100644 --- a/src/codegen/php/statement_list.rs +++ b/src/codegen/php/statement_list.rs @@ -1,6 +1,9 @@ -use crate::{codegen::Transpilable, php_ast::PhpAst}; +use crate::{ + codegen::Transpilable, + php_ast::{php_ast_2::PFile, PhpAst}, +}; -impl Transpilable for PhpAst<'_> { +impl Transpilable for PFile<'_> { fn transpile(&self) -> String { let mut fragments = vec![String::from(" = Box<(dyn Transpilable + 'a)>; /// Represents `statement-list` on the grammar, diff --git a/src/php_ast/php_ast_2.rs b/src/php_ast/php_ast_2.rs new file mode 100644 index 0000000..48fb0b2 --- /dev/null +++ b/src/php_ast/php_ast_2.rs @@ -0,0 +1,56 @@ +/// A single PHP source code file +pub struct PFile<'a> { + pub statements: Vec>, +} + +/// A PHP statement +pub enum PStatement<'a> { + ExpressionStatement(PExpressionStatement<'a>), +} + +/// A statement composed of a single expression, +/// whose value is discarded +/// +/// ## Examples +/// +/// ```php +/// 10; +/// "hello"; +/// ``` +pub type PExpressionStatement<'a> = PExpresssion<'a>; + +/// A generic PHP expression +pub enum PExpresssion<'a> { + FunctionCall(PFunctionCall<'a>), + Primary(PPrimary<'a>), + /// This comes from a THP binding + Assignment(PSimpleAssignment<'a>), +} + +pub struct PSimpleAssignment<'a> { + pub variable: &'a String, + pub assignment: Box>, +} + +/// A function call as an expression +pub struct PFunctionCall<'a> { + /// Arbitrary expressions that compute into + /// a function not supported + pub function_name: &'a String, + pub arguments: Vec>, +} + +/// A Primary expression: literals and variables +pub enum PPrimary<'a> { + IntegerLiteral(&'a String), + FloatingLiteral(&'a String), + StringLiteral(&'a String), + /// https://phplang.org/spec/19-grammar.html#grammar-variable + /// + /// Supports only variable -> callable-variable -> simple-variable -> variable-name + /// + /// This is a $variable + Variable(&'a String), + /// This is a symbol, e.g. a function name + Symbol(&'a String), +} diff --git a/src/php_ast/transformers/expression.rs b/src/php_ast/transformers/expression.rs index c262ce5..e39fbeb 100644 --- a/src/php_ast/transformers/expression.rs +++ b/src/php_ast/transformers/expression.rs @@ -1,6 +1,11 @@ use super::super::PhpExpression; use crate::{ - codegen::Transpilable, php_ast::{PhpAssignmentExpression, PhpPrimaryExpression}, syntax::ast::Expression + codegen::Transpilable, + php_ast::{ + php_ast_2::{PExpresssion, PFunctionCall, PPrimary}, + PhpAssignmentExpression, PhpPrimaryExpression, + }, + syntax::ast::Expression, }; // TODO: next rewrite the test to use the output of Transpilable? @@ -9,19 +14,30 @@ use super::PHPTransformable; /// Transforms a THP expression into a PHP expression impl<'a> PHPTransformable<'a> for Expression<'_> { - fn into_php_ast(&'a self) -> Box<(dyn Transpilable + 'a)> { + type Item = PExpresssion<'a>; + + fn into_php_ast(&'a self) -> PExpresssion<'a> { match self { Expression::String(value) => { - let expr = PhpPrimaryExpression::StringLiteral(&value.value); - Box::new(PhpExpression::Assignment(PhpAssignmentExpression::Primary(expr))) + let expr = PPrimary::StringLiteral(&value.value); + + PExpresssion::Primary(expr) } Expression::Int(value) => { - let expr = PhpPrimaryExpression::IntegerLiteral(&value.value); - Box::new(PhpExpression::Assignment(PhpAssignmentExpression::Primary(expr))) + let expr = PPrimary::IntegerLiteral(&value.value); + PExpresssion::Primary(expr) } Expression::Float(value) => { - let expr = PhpPrimaryExpression::FloatingLiteral(&value.value); - Box::new(PhpExpression::Assignment(PhpAssignmentExpression::Primary(expr))) + let expr = PPrimary::FloatingLiteral(&value.value); + PExpresssion::Primary(expr) + } + Expression::FunctionCall(f) => { + let fn_call_expr = f.into_php_ast(); + + PExpresssion::FunctionCall(fn_call_expr) + } + Expression::Identifier(i) => { + PExpresssion::Primary(PPrimary::Variable(&i.value)) } _ => todo!("transformation for expression: {:?}", self), } diff --git a/src/php_ast/transformers/functions.rs b/src/php_ast/transformers/functions.rs new file mode 100644 index 0000000..827c97f --- /dev/null +++ b/src/php_ast/transformers/functions.rs @@ -0,0 +1,29 @@ +use crate::{ + php_ast::php_ast_2::PFunctionCall, + syntax::ast::{functions::FunctionCall, Expression}, +}; + +use super::PHPTransformable; + +impl<'a> PHPTransformable<'a> for FunctionCall<'a> { + type Item = PFunctionCall<'a>; + + fn into_php_ast(&'a self) -> Self::Item { + let function_expr = match *self.function { + Expression::Identifier(i) => &i.value, + _ => panic!("Cannot use an arbitrary expression as a function, only identifiers (for now)"), + }; + + let expressions: Vec<_> = self + .arguments + .arguments + .iter() + .map(|a| a.into_php_ast()) + .collect(); + + PFunctionCall { + function_name: function_expr, + arguments: expressions, + } + } +} diff --git a/src/php_ast/transformers/mod.rs b/src/php_ast/transformers/mod.rs index baa0171..71f1b4d 100644 --- a/src/php_ast/transformers/mod.rs +++ b/src/php_ast/transformers/mod.rs @@ -3,8 +3,11 @@ use crate::codegen::Transpilable; pub mod expression; pub mod module_ast; pub mod statement; +pub mod functions; /// Implemented by AST nodes that can be transformed to PHP pub trait PHPTransformable<'a> { - fn into_php_ast(&'a self) -> Box<(dyn Transpilable + 'a)>; + type Item; + + fn into_php_ast(&'a self) -> Self::Item; } diff --git a/src/php_ast/transformers/module_ast.rs b/src/php_ast/transformers/module_ast.rs index f947bc8..6895695 100644 --- a/src/php_ast/transformers/module_ast.rs +++ b/src/php_ast/transformers/module_ast.rs @@ -1,5 +1,6 @@ use super::super::PhpAst; use crate::codegen::Transpilable; +use crate::php_ast::php_ast_2::{PFile, PStatement}; use crate::php_ast::{ PhpAssignmentExpression, PhpExpression, PhpExpressionList, PhpPrimaryExpression, PhpStatement, }; @@ -9,8 +10,10 @@ use super::PHPTransformable; /// Transforms a THP AST into a PHP AST impl<'a> PHPTransformable<'a> for ModuleAST<'_> { - fn into_php_ast(&'a self) -> Box<(dyn Transpilable + 'a)>{ - let mut php_statements = Vec::<_>::new(); + type Item = PFile<'a>; + + fn into_php_ast(&'a self) -> PFile<'a> { + let mut php_statements = Vec::::new(); for production in self.productions.iter() { match production { @@ -18,9 +21,16 @@ impl<'a> PHPTransformable<'a> for ModuleAST<'_> { php_statements.push(stmt.into_php_ast()); } ModuleMembers::Expr(expr) => { - // TODO: This should be done by the Expression transformer + let p_expression = expr.into_php_ast(); + + php_statements.push(PStatement::ExpressionStatement(p_expression)); + + /* match expr { Expression::FunctionCall(fc) => { + + + // TODO: This definitely needs refactoring let function_expr: &Expression = &*fc.function; match function_expr { @@ -75,13 +85,14 @@ impl<'a> PHPTransformable<'a> for ModuleAST<'_> { todo!("not implemented: AST transform for expression {:?}", expr) } } + */ } } } - Box::new(PhpAst { + PFile { statements: php_statements, - }) + } } } diff --git a/src/php_ast/transformers/statement.rs b/src/php_ast/transformers/statement.rs index 91dd2ce..0b89429 100644 --- a/src/php_ast/transformers/statement.rs +++ b/src/php_ast/transformers/statement.rs @@ -1,38 +1,28 @@ use super::super::PhpStatement; use crate::{ - codegen::Transpilable, php_ast::{PhpAssignmentExpression, PhpExpression, PhpSimpleAssignment}, syntax::ast::Statement + codegen::Transpilable, + php_ast::{ + php_ast_2::{PExpresssion, PSimpleAssignment, PStatement}, + PhpAssignmentExpression, PhpExpression, PhpSimpleAssignment, + }, + syntax::ast::Statement, }; use super::PHPTransformable; /// Transforms a THP expression into a PHP expression impl<'a> PHPTransformable<'a> for Statement<'_> { - fn into_php_ast(&'a self) -> Box<(dyn Transpilable + 'a)>{ + type Item = PStatement<'a>; + + fn into_php_ast(&'a self) -> PStatement<'a> { 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"), - }; - */ - - Box::new(PhpStatement::PhpExpressionStatement(PhpExpression::Assignment( - PhpAssignmentExpression::SimpleAssignment(PhpSimpleAssignment { - variable: b.identifier.value.clone(), - assignment: binding_expr, - }), - ))) + PStatement::ExpressionStatement(PExpresssion::Assignment(PSimpleAssignment { + variable: &b.identifier.value, + assignment: Box::new(binding_expr), + })) } _ => todo!("transformation for statement: {:?}", self), }