diff --git a/src/codegen/php/expression/assignment.rs b/src/codegen/php/expression/assignment.rs new file mode 100644 index 0000000..a80293c --- /dev/null +++ b/src/codegen/php/expression/assignment.rs @@ -0,0 +1,38 @@ +use crate::{codegen::Transpilable, php_ast::PhpAssignmentExpression}; + +impl Transpilable for PhpAssignmentExpression<'_> { + 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(); + + format!("${} = {}", variable_name, expression_str) + } + } + } +} + +#[cfg(test)] +mod tests { + use crate::{ + codegen::Transpilable, + php_ast::{PhpAssignmentExpression, PhpPrimaryExpression, PhpSimpleAssignment}, + }; + + #[test] + fn should_gen_assignment() { + let variable = String::from("name"); + let value = String::from("John"); + let assignment = PhpPrimaryExpression::StringLiteral(&value); + + let ast = PhpAssignmentExpression::SimpleAssignment(PhpSimpleAssignment { + variable, + assignment, + }); + let output = ast.transpile(); + + assert_eq!("$name = \"John\"", output) + } +} diff --git a/src/codegen/php/expression/mod.rs b/src/codegen/php/expression/mod.rs index 3b5a873..dccd81f 100644 --- a/src/codegen/php/expression/mod.rs +++ b/src/codegen/php/expression/mod.rs @@ -1 +1,2 @@ mod primary_expression; +mod assignment; diff --git a/src/codegen/php/expression/primary_expression.rs b/src/codegen/php/expression/primary_expression.rs index 423ea95..d4a4657 100644 --- a/src/codegen/php/expression/primary_expression.rs +++ b/src/codegen/php/expression/primary_expression.rs @@ -6,6 +6,7 @@ impl Transpilable for PhpPrimaryExpression<'_> { PhpPrimaryExpression::IntegerLiteral(value) => value.to_string(), PhpPrimaryExpression::FloatingLiteral(value) => value.to_string(), PhpPrimaryExpression::StringLiteral(value) => format!("\"{}\"", value), + PhpPrimaryExpression::Variable(name) => format!("${}", name), } } } @@ -58,4 +59,13 @@ mod tests { assert_eq!("322.644", output) } + + #[test] + fn should_transpile_variable() { + let input = String::from("name"); + let ast = PhpPrimaryExpression::Variable(&input); + let output = ast.transpile(); + + assert_eq!("$name", output) + } } diff --git a/src/codegen/php/mod.rs b/src/codegen/php/mod.rs index 41ef974..9730bf2 100644 --- a/src/codegen/php/mod.rs +++ b/src/codegen/php/mod.rs @@ -8,7 +8,7 @@ pub mod statement_list; impl Transpilable for PhpExpression<'_> { fn transpile(&self) -> String { match self { - PhpExpression::PrimaryExpression(p) => p.transpile(), + PhpExpression::Assignment(p) => p.transpile(), } } } diff --git a/src/codegen/php/statement/mod.rs b/src/codegen/php/statement/mod.rs index 84ec7ea..a3c444d 100644 --- a/src/codegen/php/statement/mod.rs +++ b/src/codegen/php/statement/mod.rs @@ -20,6 +20,10 @@ impl Transpilable for PhpStatement<'_> { format!("echo {};", expressions_str) } + PhpStatement::PhpExpressionStatement(expr) => { + let expr_str = expr.transpile(); + format!("{};", expr_str) + } } } } @@ -28,7 +32,10 @@ impl Transpilable for PhpStatement<'_> { mod tests { use crate::{ codegen::Transpilable, - php_ast::{PhpExpression, PhpExpressionList, PhpPrimaryExpression, PhpStatement}, + php_ast::{ + PhpAssignmentExpression, PhpExpression, PhpExpressionList, PhpPrimaryExpression, + PhpStatement, + }, }; #[test] @@ -47,7 +54,9 @@ mod tests { let input = String::from("322"); let exp_1 = PhpPrimaryExpression::FloatingLiteral(&input); let expressions = PhpExpressionList { - expressions: vec![PhpExpression::PrimaryExpression(exp_1)], + expressions: vec![PhpExpression::Assignment(PhpAssignmentExpression::Primary( + exp_1, + ))], }; let ast = PhpStatement::PhpEchoStatement(expressions); let output = ast.transpile(); @@ -65,8 +74,8 @@ mod tests { let expressions = PhpExpressionList { expressions: vec![ - PhpExpression::PrimaryExpression(exp_1), - PhpExpression::PrimaryExpression(exp_2), + PhpExpression::Assignment(PhpAssignmentExpression::Primary(exp_1)), + PhpExpression::Assignment(PhpAssignmentExpression::Primary(exp_2)), ], }; let ast = PhpStatement::PhpEchoStatement(expressions); @@ -74,4 +83,16 @@ mod tests { assert_eq!("echo 322, \"Hai world\";", output) } + + #[test] + fn should_gen_expression_stmt() { + let input = String::from("Hi!"); + let exp_1 = PhpPrimaryExpression::StringLiteral(&input); + let ast = PhpStatement::PhpExpressionStatement(PhpExpression::Assignment( + PhpAssignmentExpression::Primary(exp_1), + )); + let output = ast.transpile(); + + assert_eq!("\"Hi!\";", output) + } } diff --git a/src/php_ast/mod.rs b/src/php_ast/mod.rs index 68c6a47..98343cc 100644 --- a/src/php_ast/mod.rs +++ b/src/php_ast/mod.rs @@ -19,6 +19,7 @@ pub struct PhpAst<'a> { /// echo-statement pub enum PhpStatement<'a> { PhpEchoStatement(PhpExpressionList<'a>), + PhpExpressionStatement(PhpExpression<'a>), } pub struct PhpExpressionList<'a> { @@ -26,15 +27,30 @@ pub struct PhpExpressionList<'a> { } pub enum PhpExpression<'a> { - PrimaryExpression(PhpPrimaryExpression<'a>), + Assignment(PhpAssignmentExpression<'a>), +} + +pub enum PhpAssignmentExpression<'a> { + Primary(PhpPrimaryExpression<'a>), + SimpleAssignment(PhpSimpleAssignment<'a>), +} + +pub struct PhpSimpleAssignment<'a> { + pub variable: String, + pub assignment: PhpPrimaryExpression<'a>, } /// https://phplang.org/spec/19-grammar.html#grammar-primary-expression /// /// primary-expression: /// literal +/// variable pub enum PhpPrimaryExpression<'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 + Variable(&'a String), } diff --git a/src/php_ast/transformers/expression.rs b/src/php_ast/transformers/expression.rs index 14fdc3d..0415ba6 100644 --- a/src/php_ast/transformers/expression.rs +++ b/src/php_ast/transformers/expression.rs @@ -1,5 +1,8 @@ use super::super::PhpExpression; -use crate::{php_ast::PhpPrimaryExpression, syntax::ast::Expression}; +use crate::{ + php_ast::{PhpAssignmentExpression, PhpPrimaryExpression}, + syntax::ast::Expression, +}; use super::PHPTransformable; @@ -11,7 +14,7 @@ impl<'a> PHPTransformable<'a> for Expression<'_> { match self { Expression::String(value) => { let expr = PhpPrimaryExpression::StringLiteral(value); - PhpExpression::PrimaryExpression(expr) + PhpExpression::Assignment(PhpAssignmentExpression::Primary(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 cb33258..d8c6bde 100644 --- a/src/php_ast/transformers/module_ast.rs +++ b/src/php_ast/transformers/module_ast.rs @@ -1,5 +1,7 @@ use super::super::PhpAst; -use crate::php_ast::{PhpExpression, PhpExpressionList, PhpPrimaryExpression, PhpStatement}; +use crate::php_ast::{ + PhpAssignmentExpression, PhpExpression, PhpExpressionList, PhpPrimaryExpression, PhpStatement, +}; use crate::syntax::ast::{Expression, ModuleAST, ModuleMembers}; use super::PHPTransformable; @@ -34,7 +36,7 @@ impl<'a> PHPTransformable<'a> for ModuleAST<'_> { match e { Expression::String(v) => { expressions.push( - PhpExpression::PrimaryExpression(PhpPrimaryExpression::StringLiteral(v)) + PhpExpression::Assignment(PhpAssignmentExpression::Primary(PhpPrimaryExpression::StringLiteral(v))) ) }, _ => todo!("Non string expressions not supported")