From a62d08455b19290ffd6b742527ea3a89a5e94062 Mon Sep 17 00:00:00 2001 From: Araozu Date: Wed, 31 Jul 2024 09:58:51 -0500 Subject: [PATCH] refactor: remove old codegen, test new codegen nodes --- src/codegen/binding.rs | 41 ---------- src/codegen/block.rs | 17 ---- src/codegen/expression.rs | 76 ------------------ src/codegen/function_call.rs | 17 ---- src/codegen/function_declaration.rs | 43 ----------- src/codegen/mod.rs | 8 -- src/codegen/module_ast.rs | 50 ------------ src/codegen/php/expression/mod.rs | 1 + .../php/expression/primary_expression.rs | 61 +++++++++++++++ src/codegen/php/mod.rs | 45 ++--------- src/codegen/php/statement/echo_statement.rs | 0 src/codegen/php/statement/mod.rs | 77 +++++++++++++++++++ src/codegen/php/statement_list.rs | 27 +++++++ src/codegen/statement.rs | 14 ---- src/codegen/top_level_construct.rs | 13 ---- src/file/mod.rs | 3 +- src/php_ast/mod.rs | 28 ++++++- src/php_ast/transformers/expression.rs | 7 +- src/php_ast/transformers/module_ast.rs | 6 +- 19 files changed, 207 insertions(+), 327 deletions(-) delete mode 100644 src/codegen/binding.rs delete mode 100644 src/codegen/block.rs delete mode 100644 src/codegen/expression.rs delete mode 100644 src/codegen/function_call.rs delete mode 100644 src/codegen/function_declaration.rs delete mode 100644 src/codegen/module_ast.rs create mode 100644 src/codegen/php/expression/mod.rs create mode 100644 src/codegen/php/expression/primary_expression.rs create mode 100644 src/codegen/php/statement/echo_statement.rs create mode 100644 src/codegen/php/statement/mod.rs create mode 100644 src/codegen/php/statement_list.rs delete mode 100644 src/codegen/statement.rs delete mode 100644 src/codegen/top_level_construct.rs diff --git a/src/codegen/binding.rs b/src/codegen/binding.rs deleted file mode 100644 index 447cc26..0000000 --- a/src/codegen/binding.rs +++ /dev/null @@ -1,41 +0,0 @@ -use super::Transpilable; -use crate::syntax::ast::var_binding::VariableBinding; - -impl Transpilable for VariableBinding<'_> { - /// Transpiles val and var bindings into PHP. - fn transpile(&self) -> String { - let expression_str = self.expression.transpile(); - - format!("${} = {}", self.identifier.value, expression_str) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{ - lexic::token::{Token, TokenType}, - syntax::ast::{var_binding::VariableBinding, Expression}, - }; - - #[test] - fn binding_should_transpile() { - let id = String::from("identifier"); - let id_token = Token { - token_type: TokenType::Identifier, - value: id, - position: 0, - }; - let value = String::from("322"); - let binding = VariableBinding { - datatype: None, - identifier: &id_token, - expression: Expression::Int(&value), - is_mutable: false, - }; - - let result = binding.transpile(); - - assert_eq!("$identifier = 322", result); - } -} diff --git a/src/codegen/block.rs b/src/codegen/block.rs deleted file mode 100644 index 087c206..0000000 --- a/src/codegen/block.rs +++ /dev/null @@ -1,17 +0,0 @@ -use crate::syntax::ast::Block; - -use super::Transpilable; - -impl Transpilable for Block<'_> { - fn transpile(&self) -> String { - // TODO: Handle indentation - todo!("transpilation for block"); - /* - self.members - .iter() - .map(|x| x.transpile()) - .collect::>() - .join("\n") - */ - } -} diff --git a/src/codegen/expression.rs b/src/codegen/expression.rs deleted file mode 100644 index 5752adb..0000000 --- a/src/codegen/expression.rs +++ /dev/null @@ -1,76 +0,0 @@ -use super::Transpilable; -use crate::syntax::ast::Expression; - -impl Transpilable for Expression<'_> { - /// Transpiles an Expression to PHP - /// - /// Right now the expressions in the grammar are: - /// - Number - /// - String - /// - Boolean - /// - Identifier - fn transpile(&self) -> String { - match self { - Expression::Int(value) => format!("{}", value), - Expression::Float(value) => format!("{}", value), - Expression::String(value) => { - format!("{}", *value) - } - Expression::Boolean(value) => String::from(if *value { "true" } else { "false" }), - Expression::Identifier(value) => format!("{}", *value), - Expression::FunctionCall(f) => f.transpile(), - Expression::BinaryOperator(left_expr, right_expr, operator) => { - format!( - "{}{}{}", - left_expr.transpile(), - operator, - right_expr.transpile() - ) - } - Expression::UnaryOperator(operator, expression) => { - format!("{}{}", operator, expression.transpile()) - } - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::syntax::ast::Expression; - - #[test] - fn should_transpile_number() { - let str = String::from("42"); - let exp = Expression::Int(&str); - let result = exp.transpile(); - - assert_eq!("42", result); - } - - #[test] - fn should_transpile_string() { - let str = String::from("\"Hello world\""); - let exp = Expression::String(&str); - let result = exp.transpile(); - - assert_eq!("\"Hello world\"", result); - } - - #[test] - fn should_transpile_boolean() { - let exp = Expression::Boolean(true); - let result = exp.transpile(); - - assert_eq!("true", result); - } - - #[test] - fn should_transpile_identifier() { - let s = String::from("newValue"); - let exp = Expression::Identifier(&s); - let result = exp.transpile(); - - assert_eq!("newValue", result); - } -} diff --git a/src/codegen/function_call.rs b/src/codegen/function_call.rs deleted file mode 100644 index 3a8ab85..0000000 --- a/src/codegen/function_call.rs +++ /dev/null @@ -1,17 +0,0 @@ -use crate::syntax::ast::functions::FunctionCall; - -use super::Transpilable; - -impl Transpilable for FunctionCall<'_> { - fn transpile(&self) -> String { - let parameters = &self - .arguments - .arguments - .iter() - .map(|expr| expr.transpile()) - .collect::>() - .join(", "); - - format!("{}({})", self.function.transpile(), parameters) - } -} diff --git a/src/codegen/function_declaration.rs b/src/codegen/function_declaration.rs deleted file mode 100644 index e6850ff..0000000 --- a/src/codegen/function_declaration.rs +++ /dev/null @@ -1,43 +0,0 @@ -use crate::syntax::ast::FunctionDeclaration; - -use super::Transpilable; - -impl Transpilable for FunctionDeclaration<'_> { - fn transpile(&self) -> String { - format!( - "function {}() {{\n{}\n}}", - self.identifier.value, - self.block.transpile() - ) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{ - lexic::get_tokens, - syntax::{ - ast::{ModuleMembers, Statement}, - build_ast, - }, - }; - - /* TODO: reimplement - #[test] - fn should_transpile() { - let tokens = get_tokens(&String::from("fun id() {}")).unwrap(); - let result = build_ast(&tokens).unwrap(); - - let fun_dec = result.productions.get(0).unwrap(); - - match fun_dec { - ModuleMembers::Stmt(Statement::FnDecl(fun_decl)) => { - let transpiled = fun_decl.transpile(); - - assert_eq!("function id() {\n\n}", transpiled); - } - _ => panic!("Expected a function declaration"), - } - }*/ -} diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 6dc92a2..13a136f 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -1,13 +1,5 @@ // TODO: These are for the THP AST. Eventually replace this // with the PHP AST -mod binding; -mod block; -mod expression; -mod function_call; -mod function_declaration; -mod module_ast; -mod statement; -mod top_level_construct; mod php; diff --git a/src/codegen/module_ast.rs b/src/codegen/module_ast.rs deleted file mode 100644 index 3aafd9d..0000000 --- a/src/codegen/module_ast.rs +++ /dev/null @@ -1,50 +0,0 @@ -use super::Transpilable; -use crate::syntax::ast::ModuleAST; - -impl Transpilable for ModuleAST<'_> { - /// Transpiles the whole AST into PHP, using this same trait on the - /// nodes and leaves of the AST - fn transpile(&self) -> String { - let bindings_str: Vec = self - .productions - .iter() - .map(|binding| binding.transpile()) - .collect(); - - format!(" { + fn transpile(&self) -> String { + match self { + PhpPrimaryExpression::IntegerLiteral(value) => value.to_string(), + PhpPrimaryExpression::FloatingLiteral(value) => value.to_string(), + PhpPrimaryExpression::StringLiteral(value) => format!("\"{}\"", value), + } + } +} + +#[cfg(test)] +mod tests { + use crate::{codegen::Transpilable, php_ast::PhpPrimaryExpression}; + + #[test] + fn should_transpile_empty_string() { + let input = String::from(""); + let ast = PhpPrimaryExpression::StringLiteral(&input); + let output = ast.transpile(); + + assert_eq!("\"\"", output) + } + + #[test] + fn should_transpile_string() { + let input = String::from("abc"); + let ast = PhpPrimaryExpression::StringLiteral(&input); + let output = ast.transpile(); + + assert_eq!("\"abc\"", output) + } + + #[test] + fn should_transpile_string_with_quotes() { + let input = String::from("a\\\"b\\\"c"); + let ast = PhpPrimaryExpression::StringLiteral(&input); + let output = ast.transpile(); + + assert_eq!("\"a\\\"b\\\"c\"", output) + } + + #[test] + fn should_transpile_int() { + let input = String::from("322"); + let ast = PhpPrimaryExpression::IntegerLiteral(&input); + let output = ast.transpile(); + + assert_eq!("322", output) + } + + #[test] + fn should_transpile_floating() { + let input = String::from("322.644"); + let ast = PhpPrimaryExpression::FloatingLiteral(&input); + let output = ast.transpile(); + + assert_eq!("322.644", output) + } +} diff --git a/src/codegen/php/mod.rs b/src/codegen/php/mod.rs index 37d2846..8b42ed0 100644 --- a/src/codegen/php/mod.rs +++ b/src/codegen/php/mod.rs @@ -1,49 +1,14 @@ -use std::os::linux::raw::stat; - -use crate::php_ast::{PhpAst, PhpExpression, PhpStatement}; - use super::Transpilable; +use crate::php_ast::PhpExpression; -impl Transpilable for PhpAst<'_> { - fn transpile(&self) -> String { - let mut fragments = vec![String::from(" { - 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) - } - } - } -} +pub mod statement; +pub mod statement_list; +mod expression; impl Transpilable for PhpExpression<'_> { fn transpile(&self) -> String { match self { - PhpExpression::String(value) => { - format!("{}", value) - } + PhpExpression::PrimaryExpression(p) => p.transpile(), } } } diff --git a/src/codegen/php/statement/echo_statement.rs b/src/codegen/php/statement/echo_statement.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/codegen/php/statement/mod.rs b/src/codegen/php/statement/mod.rs new file mode 100644 index 0000000..84ec7ea --- /dev/null +++ b/src/codegen/php/statement/mod.rs @@ -0,0 +1,77 @@ +use crate::{codegen::Transpilable, php_ast::PhpStatement}; + +mod echo_statement; + +impl Transpilable for PhpStatement<'_> { + 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) + } + } + } +} + +#[cfg(test)] +mod tests { + use crate::{ + codegen::Transpilable, + php_ast::{PhpExpression, PhpExpressionList, PhpPrimaryExpression, PhpStatement}, + }; + + #[test] + fn should_gen_empty_echo_statement() { + let expressions = PhpExpressionList { + expressions: vec![], + }; + let ast = PhpStatement::PhpEchoStatement(expressions); + let output = ast.transpile(); + + assert_eq!("echo \"\";", output) + } + + #[test] + fn should_gen_echo_with_expr() { + let input = String::from("322"); + let exp_1 = PhpPrimaryExpression::FloatingLiteral(&input); + let expressions = PhpExpressionList { + expressions: vec![PhpExpression::PrimaryExpression(exp_1)], + }; + let ast = PhpStatement::PhpEchoStatement(expressions); + let output = ast.transpile(); + + assert_eq!("echo 322;", output) + } + + #[test] + fn should_gen_echo_with_multiple_expr() { + let input = String::from("322"); + let exp_1 = PhpPrimaryExpression::FloatingLiteral(&input); + + let input = String::from("Hai world"); + let exp_2 = PhpPrimaryExpression::StringLiteral(&input); + + let expressions = PhpExpressionList { + expressions: vec![ + PhpExpression::PrimaryExpression(exp_1), + PhpExpression::PrimaryExpression(exp_2), + ], + }; + let ast = PhpStatement::PhpEchoStatement(expressions); + let output = ast.transpile(); + + assert_eq!("echo 322, \"Hai world\";", output) + } +} diff --git a/src/codegen/php/statement_list.rs b/src/codegen/php/statement_list.rs new file mode 100644 index 0000000..922aca2 --- /dev/null +++ b/src/codegen/php/statement_list.rs @@ -0,0 +1,27 @@ +use crate::{codegen::Transpilable, php_ast::PhpAst}; + +impl Transpilable for PhpAst<'_> { + fn transpile(&self) -> String { + let mut fragments = vec![String::from(" { - fn transpile(&self) -> String { - let stmt = match self { - Statement::FnDecl(f) => f.transpile(), - Statement::Binding(b) => b.transpile(), - }; - - format!("{stmt};") - } -} diff --git a/src/codegen/top_level_construct.rs b/src/codegen/top_level_construct.rs deleted file mode 100644 index 6b44fbb..0000000 --- a/src/codegen/top_level_construct.rs +++ /dev/null @@ -1,13 +0,0 @@ -use crate::syntax::ast::{ModuleMembers, Statement}; - -use super::Transpilable; - -impl Transpilable for ModuleMembers<'_> { - fn transpile(&self) -> String { - match self { - ModuleMembers::Stmt(Statement::Binding(b)) => b.transpile(), - ModuleMembers::Stmt(Statement::FnDecl(f)) => f.transpile(), - _ => todo!("Not implemented: Transpilable for Expression"), - } - } -} diff --git a/src/file/mod.rs b/src/file/mod.rs index 8780a36..a4e349d 100644 --- a/src/file/mod.rs +++ b/src/file/mod.rs @@ -101,5 +101,6 @@ fn build_ast(input: &String, tokens: Vec) -> Result { } }; - Ok(codegen::codegen(&ast)) + Err("Code generation disabled: rewriting into PHP AST".into()) + // Ok(codegen::codegen(&ast)) } diff --git a/src/php_ast/mod.rs b/src/php_ast/mod.rs index 163c26e..ac2bdfb 100644 --- a/src/php_ast/mod.rs +++ b/src/php_ast/mod.rs @@ -1,12 +1,23 @@ -// Follows https://phplang.org/spec/19-grammar.html#syntactic-grammar +/// This AST implements a subset of the PHP AST as defined +/// by https://phplang.org/spec/19-grammar.html#syntactic-grammar +/// +/// This subset only includes nodes that can be generated by +/// THP pub mod transformers; -/// Represents `statement-list` on the grammar +/// Represents `statement-list` on the grammar, +/// and thus a whole PHP source file pub struct PhpAst<'a> { pub statements: Vec>, } +/// https://phplang.org/spec/19-grammar.html#grammar-statement +/// +/// Not fully implemented +/// +/// statement: +/// echo-statement pub enum PhpStatement<'a> { PhpEchoStatement(PhpExpressionList<'a>), } @@ -16,5 +27,16 @@ pub struct PhpExpressionList<'a> { } pub enum PhpExpression<'a> { - String(&'a String), + PrimaryExpression(PhpPrimaryExpression<'a>), } + +/// https://phplang.org/spec/19-grammar.html#grammar-primary-expression +/// +/// primary-expression: +/// literal +pub enum PhpPrimaryExpression<'a> { + IntegerLiteral(&'a String), + FloatingLiteral(&'a String), + StringLiteral(&'a String), +} + diff --git a/src/php_ast/transformers/expression.rs b/src/php_ast/transformers/expression.rs index e9ea6ed..0d3a891 100644 --- a/src/php_ast/transformers/expression.rs +++ b/src/php_ast/transformers/expression.rs @@ -1,5 +1,5 @@ use super::super::PhpExpression; -use crate::syntax::ast::Expression; +use crate::{php_ast::PhpPrimaryExpression, syntax::ast::Expression}; use super::PHPTransformable; @@ -9,7 +9,10 @@ impl<'a> PHPTransformable<'a> for Expression<'_> { fn into_php_ast(&'a self) -> Self::Item { match self { - Expression::String(value) => PhpExpression::String(value), + Expression::String(value) => { + let expr = PhpPrimaryExpression::StringLiteral(value); + PhpExpression::PrimaryExpression(expr) + }, _ => todo!("transformation for expression: {:?}", self), } } diff --git a/src/php_ast/transformers/module_ast.rs b/src/php_ast/transformers/module_ast.rs index 0d9ab6b..fa9fb38 100644 --- a/src/php_ast/transformers/module_ast.rs +++ b/src/php_ast/transformers/module_ast.rs @@ -1,5 +1,5 @@ use super::super::PhpAst; -use crate::php_ast::{PhpExpression, PhpExpressionList, PhpStatement}; +use crate::php_ast::{PhpExpression, PhpExpressionList, PhpPrimaryExpression, PhpStatement}; use crate::syntax::ast::{Expression, ModuleAST, ModuleMembers}; use super::PHPTransformable; @@ -33,7 +33,9 @@ impl<'a> PHPTransformable<'a> for ModuleAST<'_> { for e in fc.arguments.arguments.iter() { match e { Expression::String(v) => { - expressions.push(PhpExpression::String(v)) + expressions.push( + PhpExpression::PrimaryExpression(PhpPrimaryExpression::StringLiteral(v.clone())) + ) }, _ => panic!("Non string expressions not supported") }