refactor: revert to old ast transformation strategy
This commit is contained in:
parent
912384c856
commit
974c380eaf
@ -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 {
|
fn transpile(&self) -> String {
|
||||||
match self {
|
let variable_name = self.variable;
|
||||||
PhpAssignmentExpression::Primary(p) => p.transpile(),
|
let expression_str = self.assignment.transpile();
|
||||||
PhpAssignmentExpression::SimpleAssignment(assignment) => {
|
|
||||||
let variable_name = &assignment.variable;
|
|
||||||
let expression_str = assignment.assignment.transpile();
|
|
||||||
|
|
||||||
format!("${} = {}", variable_name, expression_str)
|
format!("${} = {}", variable_name, expression_str)
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,2 +1,15 @@
|
|||||||
|
use crate::{codegen::Transpilable, php_ast::php_ast_2::PExpresssion};
|
||||||
|
use PExpresssion::*;
|
||||||
|
|
||||||
mod assignment;
|
mod assignment;
|
||||||
mod primary_expression;
|
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(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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 {
|
fn transpile(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
PhpPrimaryExpression::IntegerLiteral(value) => value.to_string(),
|
PPrimary::IntegerLiteral(value) => value.to_string(),
|
||||||
PhpPrimaryExpression::FloatingLiteral(value) => value.to_string(),
|
PPrimary::FloatingLiteral(value) => value.to_string(),
|
||||||
PhpPrimaryExpression::StringLiteral(value) => format!("\"{}\"", value),
|
PPrimary::StringLiteral(value) => format!("\"{}\"", value),
|
||||||
PhpPrimaryExpression::Variable(name) => format!("${}", name),
|
PPrimary::Variable(name) => format!("${}", name),
|
||||||
|
PPrimary::Symbol(name) => format!("{}", name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -15,6 +19,7 @@ impl Transpilable for PhpPrimaryExpression<'_> {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use crate::{codegen::Transpilable, php_ast::PhpPrimaryExpression};
|
use crate::{codegen::Transpilable, php_ast::PhpPrimaryExpression};
|
||||||
|
|
||||||
|
/*
|
||||||
#[test]
|
#[test]
|
||||||
fn should_transpile_empty_string() {
|
fn should_transpile_empty_string() {
|
||||||
let input = String::from("");
|
let input = String::from("");
|
||||||
@ -68,4 +73,5 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!("$name", output)
|
assert_eq!("$name", output)
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
9
src/codegen/php/function/mod.rs
Normal file
9
src/codegen/php/function/mod.rs
Normal file
@ -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(", "))
|
||||||
|
}
|
||||||
|
}
|
@ -4,11 +4,4 @@ use crate::php_ast::PhpExpression;
|
|||||||
mod expression;
|
mod expression;
|
||||||
pub mod statement;
|
pub mod statement;
|
||||||
pub mod statement_list;
|
pub mod statement_list;
|
||||||
|
mod function;
|
||||||
impl Transpilable for PhpExpression<'_> {
|
|
||||||
fn transpile(&self) -> String {
|
|
||||||
match self {
|
|
||||||
PhpExpression::Assignment(p) => p.transpile(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1 +0,0 @@
|
|||||||
|
|
@ -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 PStatement<'_> {
|
||||||
|
|
||||||
impl Transpilable for PhpStatement<'_> {
|
|
||||||
fn transpile(&self) -> String {
|
fn transpile(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
PhpStatement::PhpEchoStatement(expr_list) => {
|
PStatement::ExpressionStatement(expr) => {
|
||||||
let expressions_vec = expr_list
|
|
||||||
.expressions
|
|
||||||
.iter()
|
|
||||||
.map(|e| e.transpile())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let expressions_str = if expressions_vec.is_empty() {
|
|
||||||
"\"\"".into()
|
|
||||||
} else {
|
|
||||||
expressions_vec.join(", ")
|
|
||||||
};
|
|
||||||
|
|
||||||
format!("echo {};", expressions_str)
|
|
||||||
}
|
|
||||||
PhpStatement::PhpExpressionStatement(expr) => {
|
|
||||||
let expr_str = expr.transpile();
|
let expr_str = expr.transpile();
|
||||||
format!("{};", expr_str)
|
format!("{};", expr_str)
|
||||||
}
|
}
|
||||||
@ -38,6 +24,7 @@ mod tests {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
#[test]
|
#[test]
|
||||||
fn should_gen_empty_echo_statement() {
|
fn should_gen_empty_echo_statement() {
|
||||||
let expressions = PhpExpressionList {
|
let expressions = PhpExpressionList {
|
||||||
@ -95,4 +82,5 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!("\"Hi!\";", output)
|
assert_eq!("\"Hi!\";", output)
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
fn transpile(&self) -> String {
|
||||||
let mut fragments = vec![String::from("<?php\n")];
|
let mut fragments = vec![String::from("<?php\n")];
|
||||||
|
|
||||||
@ -17,13 +20,14 @@ mod tests {
|
|||||||
use crate::{
|
use crate::{
|
||||||
codegen::Transpilable,
|
codegen::Transpilable,
|
||||||
php_ast::{
|
php_ast::{
|
||||||
PhpAssignmentExpression, PhpAst, PhpExpression, PhpPrimaryExpression, PhpStatement,
|
php_ast_2::PFile, PhpAssignmentExpression, PhpAst, PhpExpression, PhpPrimaryExpression,
|
||||||
|
PhpStatement,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_transpile_empty_file() {
|
fn should_transpile_empty_file() {
|
||||||
let ast = PhpAst { statements: vec![] };
|
let ast = PFile { statements: vec![] };
|
||||||
let output = ast.transpile();
|
let output = ast.transpile();
|
||||||
|
|
||||||
assert_eq!("<?php\n", output);
|
assert_eq!("<?php\n", output);
|
||||||
|
@ -7,6 +7,8 @@ use crate::codegen::Transpilable;
|
|||||||
/// THP
|
/// THP
|
||||||
pub mod transformers;
|
pub mod transformers;
|
||||||
|
|
||||||
|
pub mod php_ast_2;
|
||||||
|
|
||||||
type TranspilableBox<'a> = Box<(dyn Transpilable + 'a)>;
|
type TranspilableBox<'a> = Box<(dyn Transpilable + 'a)>;
|
||||||
|
|
||||||
/// Represents `statement-list` on the grammar,
|
/// Represents `statement-list` on the grammar,
|
||||||
|
56
src/php_ast/php_ast_2.rs
Normal file
56
src/php_ast/php_ast_2.rs
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/// A single PHP source code file
|
||||||
|
pub struct PFile<'a> {
|
||||||
|
pub statements: Vec<PStatement<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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<PExpresssion<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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<PExpresssion<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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),
|
||||||
|
}
|
@ -1,6 +1,11 @@
|
|||||||
use super::super::PhpExpression;
|
use super::super::PhpExpression;
|
||||||
use crate::{
|
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?
|
// 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
|
/// Transforms a THP expression into a PHP expression
|
||||||
impl<'a> PHPTransformable<'a> for 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 {
|
match self {
|
||||||
Expression::String(value) => {
|
Expression::String(value) => {
|
||||||
let expr = PhpPrimaryExpression::StringLiteral(&value.value);
|
let expr = PPrimary::StringLiteral(&value.value);
|
||||||
Box::new(PhpExpression::Assignment(PhpAssignmentExpression::Primary(expr)))
|
|
||||||
|
PExpresssion::Primary(expr)
|
||||||
}
|
}
|
||||||
Expression::Int(value) => {
|
Expression::Int(value) => {
|
||||||
let expr = PhpPrimaryExpression::IntegerLiteral(&value.value);
|
let expr = PPrimary::IntegerLiteral(&value.value);
|
||||||
Box::new(PhpExpression::Assignment(PhpAssignmentExpression::Primary(expr)))
|
PExpresssion::Primary(expr)
|
||||||
}
|
}
|
||||||
Expression::Float(value) => {
|
Expression::Float(value) => {
|
||||||
let expr = PhpPrimaryExpression::FloatingLiteral(&value.value);
|
let expr = PPrimary::FloatingLiteral(&value.value);
|
||||||
Box::new(PhpExpression::Assignment(PhpAssignmentExpression::Primary(expr)))
|
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),
|
_ => todo!("transformation for expression: {:?}", self),
|
||||||
}
|
}
|
||||||
|
29
src/php_ast/transformers/functions.rs
Normal file
29
src/php_ast/transformers/functions.rs
Normal file
@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,8 +3,11 @@ use crate::codegen::Transpilable;
|
|||||||
pub mod expression;
|
pub mod expression;
|
||||||
pub mod module_ast;
|
pub mod module_ast;
|
||||||
pub mod statement;
|
pub mod statement;
|
||||||
|
pub mod functions;
|
||||||
|
|
||||||
/// Implemented by AST nodes that can be transformed to PHP
|
/// Implemented by AST nodes that can be transformed to PHP
|
||||||
pub trait PHPTransformable<'a> {
|
pub trait PHPTransformable<'a> {
|
||||||
fn into_php_ast(&'a self) -> Box<(dyn Transpilable + 'a)>;
|
type Item;
|
||||||
|
|
||||||
|
fn into_php_ast(&'a self) -> Self::Item;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use super::super::PhpAst;
|
use super::super::PhpAst;
|
||||||
use crate::codegen::Transpilable;
|
use crate::codegen::Transpilable;
|
||||||
|
use crate::php_ast::php_ast_2::{PFile, PStatement};
|
||||||
use crate::php_ast::{
|
use crate::php_ast::{
|
||||||
PhpAssignmentExpression, PhpExpression, PhpExpressionList, PhpPrimaryExpression, PhpStatement,
|
PhpAssignmentExpression, PhpExpression, PhpExpressionList, PhpPrimaryExpression, PhpStatement,
|
||||||
};
|
};
|
||||||
@ -9,8 +10,10 @@ use super::PHPTransformable;
|
|||||||
|
|
||||||
/// Transforms a THP AST into a PHP AST
|
/// Transforms a THP AST into a PHP AST
|
||||||
impl<'a> PHPTransformable<'a> for ModuleAST<'_> {
|
impl<'a> PHPTransformable<'a> for ModuleAST<'_> {
|
||||||
fn into_php_ast(&'a self) -> Box<(dyn Transpilable + 'a)>{
|
type Item = PFile<'a>;
|
||||||
let mut php_statements = Vec::<_>::new();
|
|
||||||
|
fn into_php_ast(&'a self) -> PFile<'a> {
|
||||||
|
let mut php_statements = Vec::<PStatement>::new();
|
||||||
|
|
||||||
for production in self.productions.iter() {
|
for production in self.productions.iter() {
|
||||||
match production {
|
match production {
|
||||||
@ -18,9 +21,16 @@ impl<'a> PHPTransformable<'a> for ModuleAST<'_> {
|
|||||||
php_statements.push(stmt.into_php_ast());
|
php_statements.push(stmt.into_php_ast());
|
||||||
}
|
}
|
||||||
ModuleMembers::Expr(expr) => {
|
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 {
|
match expr {
|
||||||
Expression::FunctionCall(fc) => {
|
Expression::FunctionCall(fc) => {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: This definitely needs refactoring
|
// TODO: This definitely needs refactoring
|
||||||
let function_expr: &Expression = &*fc.function;
|
let function_expr: &Expression = &*fc.function;
|
||||||
match function_expr {
|
match function_expr {
|
||||||
@ -75,13 +85,14 @@ impl<'a> PHPTransformable<'a> for ModuleAST<'_> {
|
|||||||
todo!("not implemented: AST transform for expression {:?}", expr)
|
todo!("not implemented: AST transform for expression {:?}", expr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Box::new(PhpAst {
|
PFile {
|
||||||
statements: php_statements,
|
statements: php_statements,
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,38 +1,28 @@
|
|||||||
use super::super::PhpStatement;
|
use super::super::PhpStatement;
|
||||||
use crate::{
|
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;
|
use super::PHPTransformable;
|
||||||
|
|
||||||
/// Transforms a THP expression into a PHP expression
|
/// Transforms a THP expression into a PHP expression
|
||||||
impl<'a> PHPTransformable<'a> for Statement<'_> {
|
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 {
|
match self {
|
||||||
Statement::Binding(b) => {
|
Statement::Binding(b) => {
|
||||||
// This is a PhpExpression, but a PhpPrimaryExpression is needed
|
|
||||||
let binding_expr = b.expression.into_php_ast();
|
let binding_expr = b.expression.into_php_ast();
|
||||||
|
|
||||||
/*
|
PStatement::ExpressionStatement(PExpresssion::Assignment(PSimpleAssignment {
|
||||||
// TODO: Somehow fix this...
|
variable: &b.identifier.value,
|
||||||
// the function above `into_php_ast` should somehow
|
assignment: Box::new(binding_expr),
|
||||||
// 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,
|
|
||||||
}),
|
|
||||||
)))
|
|
||||||
}
|
}
|
||||||
_ => todo!("transformation for statement: {:?}", self),
|
_ => todo!("transformation for statement: {:?}", self),
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user