diff --git a/src/modules/block.rs b/src/modules/block.rs index 915f02c1..dd54ca9d 100644 --- a/src/modules/block.rs +++ b/src/modules/block.rs @@ -1,7 +1,6 @@ use std::collections::VecDeque; use std::ops::Index; -use crate::fragments; use crate::modules::prelude::*; use heraclitus_compiler::prelude::*; use itertools::Itertools; @@ -71,10 +70,13 @@ impl TranslateModule for Block { // Save the current statement queue and create a new one let mut new_queue = VecDeque::new(); std::mem::swap(&mut meta.stmt_queue, &mut new_queue); - let result = if self.is_empty() { - fragments!(":") - } else { - let statements = self.statements.iter().map(|statement| statement.translate(meta)).collect(); + let result = { + let mut statements = vec![]; + for statement in &self.statements { + let statement = statement.translate(meta); + statements.extend(meta.stmt_queue.drain(..)); + statements.push(statement); + } BlockFragment::new(statements, self.should_indent).to_frag() }; // Restore the old statement queue diff --git a/src/modules/builtin/len.rs b/src/modules/builtin/len.rs index 280654bb..5a19d6dd 100644 --- a/src/modules/builtin/len.rs +++ b/src/modules/builtin/len.rs @@ -53,7 +53,7 @@ impl TranslateModule for Len { fn translate(&self, meta: &mut TranslateMetadata) -> TranslationFragment { let value = self.value.translate(meta); let id = meta.gen_value_id(); - let var_fragment = meta.push_stmt_variable("__length", Some(id), Type::Num, value).set_get_length(); + let var_fragment = meta.push_stmt_variable_lazy("__length", Some(id), Type::Num, value).set_get_length(); var_fragment.to_frag() } } diff --git a/src/modules/builtin/lines.rs b/src/modules/builtin/lines.rs index b75de82b..eb43b62f 100644 --- a/src/modules/builtin/lines.rs +++ b/src/modules/builtin/lines.rs @@ -54,7 +54,7 @@ impl TranslateModule for LinesInvocation { .expect("Cannot read lines without provided path"); let indent = TranslateMetadata::single_indent(); let id = meta.gen_value_id(); - let value = meta.push_stmt_variable("__array", Some(id), Type::array_of(Type::Text), fragments!("()")); + let value = meta.push_stmt_variable_lazy("__array", Some(id), Type::array_of(Type::Text), TranslationFragment::Empty); meta.stmt_queue.extend([ fragments!(raw: "while IFS= read -r {temp}; do"), fragments!(raw: "{indent}{}+=(\"${}\")", value.get_name(), temp), diff --git a/src/modules/command/cmd.rs b/src/modules/command/cmd.rs index 3ab602c4..3c51cf40 100644 --- a/src/modules/command/cmd.rs +++ b/src/modules/command/cmd.rs @@ -56,7 +56,7 @@ impl Command { fn translate_command(&self, meta: &mut TranslateMetadata, is_statement: bool) -> TranslationFragment { // Translate all interpolations let interps = self.interps.iter() - .map(|item| item.translate(meta)) + .map(|item| item.translate(meta).unquote()) .collect::>(); let failed = self.failed.translate(meta); @@ -81,10 +81,10 @@ impl Command { } if let TranslationFragment::Empty = failed { - meta.gen_subprocess(translation) + SubprocessFragment::new(translation).to_frag() } else { let id = meta.gen_value_id(); - let value = fragments!("$(", translation, ")"); + let value = SubprocessFragment::new(translation).to_frag(); let variable = meta.push_stmt_variable("__command", Some(id), Type::Text, value); meta.stmt_queue.push_back(failed); variable.to_frag() diff --git a/src/modules/condition/failed.rs b/src/modules/condition/failed.rs index 534c834e..f02d4a58 100644 --- a/src/modules/condition/failed.rs +++ b/src/modules/condition/failed.rs @@ -97,11 +97,17 @@ impl TranslateModule for Failed { fragments!("fi"), ], false).to_frag() } - if let TranslationFragment::Empty = block { - return fragments!("__status=$?") + match &block { + TranslationFragment::Empty => { + return fragments!("__status=$?") + }, + TranslationFragment::Block(block) if block.is_empty() => { + return fragments!("__status=$?") + }, + _ => {} } BlockFragment::new(vec![ - fragments!("__status=$?;"), + fragments!("__status=$?"), fragments!("if [ $__status != 0 ]; then"), block, fragments!("fi"), diff --git a/src/modules/expression/binop/add.rs b/src/modules/expression/binop/add.rs index 8c5be040..b7022c47 100644 --- a/src/modules/expression/binop/add.rs +++ b/src/modules/expression/binop/add.rs @@ -63,8 +63,8 @@ impl TranslateModule for Add { match self.kind { Type::Array(_) => { let id = meta.gen_value_id(); - let value = fragments!("(", left, " ", right, ")"); - let var = meta.push_stmt_variable("__array_add", Some(id), self.kind.clone(), value); + let value = fragments!(left, " ", right); + let var = meta.push_stmt_variable_lazy("__array_add", Some(id), self.kind.clone(), value); var.to_frag() }, Type::Text => fragments!(left, right), diff --git a/src/modules/expression/binop/eq.rs b/src/modules/expression/binop/eq.rs index 16f336ed..aa8ed19a 100644 --- a/src/modules/expression/binop/eq.rs +++ b/src/modules/expression/binop/eq.rs @@ -56,7 +56,7 @@ impl TranslateModule for Eq { let right = self.right.translate(meta).unquote(); // Handle text comparison if self.left.get_type() == Type::Text && self.right.get_type() == Type::Text { - meta.gen_subprocess(fragments!("[ \"_", left, "\" != \"_", right, "\" ]; echo $?")) + SubprocessFragment::new(fragments!("[ \"_", left, "\" != \"_", right, "\" ]; echo $?")).to_frag() } else { translate_computation(meta, ArithOp::Eq, Some(left), Some(right)) } diff --git a/src/modules/expression/binop/neq.rs b/src/modules/expression/binop/neq.rs index 1f26e052..84aa7a77 100644 --- a/src/modules/expression/binop/neq.rs +++ b/src/modules/expression/binop/neq.rs @@ -54,7 +54,7 @@ impl TranslateModule for Neq { let left = self.left.translate(meta).unquote(); let right = self.right.translate(meta).unquote(); if self.left.get_type() == Type::Text && self.right.get_type() == Type::Text { - meta.gen_subprocess(fragments!("[ \"_", left, "\" == \"_", right, "\" ]; echo $?")) + SubprocessFragment::new(fragments!("[ \"_", left, "\" == \"_", right, "\" ]; echo $?")).to_frag() } else { translate_computation(meta, ArithOp::Neq, Some(left), Some(right)) } diff --git a/src/modules/expression/binop/range.rs b/src/modules/expression/binop/range.rs index c8ca2e69..d098aadf 100644 --- a/src/modules/expression/binop/range.rs +++ b/src/modules/expression/binop/range.rs @@ -72,7 +72,7 @@ impl TranslateModule for Range { } }; let expr = fragments!("seq ", from, " ", to); - meta.gen_subprocess(expr) + SubprocessFragment::new(expr).to_frag() } } @@ -108,10 +108,8 @@ impl Range { let offset = { let offset_id = Some(meta.gen_value_id()); let offset_val = self.from.translate(meta); - let offset_var = meta.push_stmt_variable("__slice_offset", offset_id, Type::Num, offset_val); - let offset_var_name = RawFragment::new(&offset_var.get_name()).to_frag(); - let offset_var = offset_var.to_frag(); - let offset_cap = fragments!(offset_var_name, "=$((", offset_var.clone(), " > 0 ? ", offset_var, " : 0))"); + let offset_var = meta.push_stmt_variable("__slice_offset", offset_id, Type::Num, offset_val).to_frag(); + let offset_cap = fragments!("$((", offset_var.clone(), " > 0 ? ", offset_var, " : 0))"); meta.push_stmt_variable("__slice_offset", offset_id, Type::Num, offset_cap).to_frag() }; @@ -119,10 +117,8 @@ impl Range { let length = { let length_id = Some(meta.gen_value_id()); let length_val = translate_computation(meta, ArithOp::Sub, Some(upper), Some(offset.clone())); - let length_var = meta.push_stmt_variable("__slice_length", length_id, Type::Num, length_val); - let length_var_name = RawFragment::new(&length_var.get_name()).to_frag(); - let length_var = length_var.to_frag(); - let length_cap = fragments!(length_var_name, "=$((", length_var.clone(), " > 0 ? ", length_var, " : 0))"); + let length_var = meta.push_stmt_variable("__slice_length", length_id, Type::Num, length_val).to_frag(); + let length_cap = fragments!("$((", length_var.clone(), " > 0 ? ", length_var, " : 0))"); meta.push_stmt_variable("__slice_length", length_id, Type::Num, length_cap).to_frag() }; diff --git a/src/modules/expression/literal/array.rs b/src/modules/expression/literal/array.rs index d2598209..4b8bd6b4 100644 --- a/src/modules/expression/literal/array.rs +++ b/src/modules/expression/literal/array.rs @@ -1,5 +1,4 @@ use heraclitus_compiler::prelude::*; -use crate::fragments; use crate::modules::expression::expr::Expr; use crate::modules::types::{try_parse_type, Type, Typed}; use crate::modules::prelude::*; @@ -88,7 +87,7 @@ impl TranslateModule for Array { let id = meta.gen_value_id(); let args = self.exprs.iter().map(|expr| expr.translate_eval(meta, false)).collect::>(); let args = ListFragment::new(args, " ").to_frag(); - let var = meta.push_stmt_variable("__array", Some(id), self.kind.clone(), fragments!("(", args, ")")); + let var = meta.push_stmt_variable_lazy("__array", Some(id), self.kind.clone(), args); var.to_frag() } } diff --git a/src/modules/expression/literal/text.rs b/src/modules/expression/literal/text.rs index 205c6498..58c54aaa 100644 --- a/src/modules/expression/literal/text.rs +++ b/src/modules/expression/literal/text.rs @@ -39,7 +39,7 @@ impl TranslateModule for Text { fn translate(&self, meta: &mut TranslateMetadata) -> TranslationFragment { // Translate all interpolations let interps = self.interps.iter() - .map(|item| item.translate(meta)) + .map(|item| item.translate(meta).unquote()) .collect::>(); InterpolableFragment::new(self.strings.clone(), interps, InterpolableRenderType::StringLiteral).to_frag() } diff --git a/src/modules/expression/ternop/ternary.rs b/src/modules/expression/ternop/ternary.rs index 1f81b147..fcf402dc 100644 --- a/src/modules/expression/ternop/ternary.rs +++ b/src/modules/expression/ternop/ternary.rs @@ -80,7 +80,7 @@ impl TranslateModule for Ternary { let true_expr = self.true_expr.translate(meta); let false_expr = self.false_expr.translate(meta); let expr = fragments!("if [ ", cond, " != 0 ]; then echo ", true_expr, "; else echo ", false_expr, "; fi"); - meta.gen_subprocess(expr) + SubprocessFragment::new(expr).to_frag() } } diff --git a/src/modules/function/declaration.rs b/src/modules/function/declaration.rs index 688c3f79..c6576739 100644 --- a/src/modules/function/declaration.rs +++ b/src/modules/function/declaration.rs @@ -254,7 +254,7 @@ impl TranslateModule for FunctionDeclaration { meta.fun_meta = Some(FunctionMetadata::new(&self.name, self.id, index, &self.returns)); // Parse the function body let name = fragments!(raw: "{}__{}_v{}", self.name, self.id, index); - result.push(fragments!(name, "() {{")); + result.push(fragments!(name, "() {")); if let Some(args) = self.set_args_as_variables(meta, function, &self.arg_refs) { result.push(args); } diff --git a/src/modules/function/invocation.rs b/src/modules/function/invocation.rs index 43c163c9..cc8ef3b2 100644 --- a/src/modules/function/invocation.rs +++ b/src/modules/function/invocation.rs @@ -146,23 +146,22 @@ impl TranslateModule for FunctionInvocation { let args = izip!(self.args.iter(), self.refs.iter()).map(| (arg, is_ref) | match arg.translate(meta) { TranslationFragment::Var(var) if *is_ref => var.set_render_type(VarRenderType::BashName).to_frag(), - TranslationFragment::Var(var) if var.kind.is_array() => var.set_render_type(VarRenderType::BashName).to_frag(), + TranslationFragment::Var(var) if var.kind.is_array() => fragments!(var.set_render_type(VarRenderType::BashName).to_frag().unquote(), "[@]"), _ if *is_ref => panic!("Reference value accepts only variables"), var @ _ => var }).collect::>(); let args = ListFragment::new(args, " ").to_frag(); meta.stmt_queue.push_back(fragments!(name, " ", args, silent)); - let invocation_return = &format!("__returned_{}{}_v{}", self.name, self.id, self.variant_id); - let invocation_instance = &format!("__returned_{}{}_v{}__{}_{}", self.name, self.id, self.variant_id, self.line, self.col); + let invocation_return = &format!("__ret_{}{}_v{}", self.name, self.id, self.variant_id); + let invocation_instance = &format!("__ret_{}{}_v{}__{}_{}", self.name, self.id, self.variant_id, self.line, self.col); let parsed_invocation_return = self.get_variable(meta, invocation_return); swap(&mut is_silent, &mut meta.silenced); if self.is_failable { let failed = self.failed.translate(meta); meta.stmt_queue.push_back(failed); } - let ret_value = if self.kind.is_array() { format!("({})", parsed_invocation_return) } else { parsed_invocation_return }; - let variable = meta.push_stmt_variable(invocation_instance, None, self.kind.clone(), fragments!(raw: "{}", ret_value)); + let variable = meta.push_stmt_variable_lazy(invocation_instance, None, self.kind.clone(), fragments!(raw: "{}", parsed_invocation_return)); variable.to_frag() } } diff --git a/src/modules/function/ret.rs b/src/modules/function/ret.rs index ba061932..82cf8737 100644 --- a/src/modules/function/ret.rs +++ b/src/modules/function/ret.rs @@ -60,11 +60,6 @@ impl TranslateModule for Return { .map(FunctionMetadata::mangled_name) .expect("Function name and return type not set"); let result = self.expr.translate(meta); - let result = if self.expr.get_type().is_array() { - fragments!("(", result, ")") - } else { - result - }; meta.push_stmt_variable(&fun_name, None, self.expr.get_type(), result); fragments!("return 0") } diff --git a/src/modules/prelude.rs b/src/modules/prelude.rs index 13a78e84..de4977be 100644 --- a/src/modules/prelude.rs +++ b/src/modules/prelude.rs @@ -4,7 +4,7 @@ pub use crate::translate::fragments::{ block::BlockFragment, compound::CompoundFragment, fragment::TranslationFragment, raw::RawFragment, var::VarFragment, var::VarRenderType, interpolable::InterpolableFragment, interpolable::InterpolableRenderType, - list::ListFragment, + list::ListFragment, subprocess::SubprocessFragment }; pub use crate::translate::module::TranslateModule; pub use crate::docs::module::DocumentationModule; diff --git a/src/modules/shorthand/add.rs b/src/modules/shorthand/add.rs index ef011833..565b08b8 100644 --- a/src/modules/shorthand/add.rs +++ b/src/modules/shorthand/add.rs @@ -1,6 +1,6 @@ use heraclitus_compiler::prelude::*; use crate::modules::prelude::*; -use crate::{error_type_match, fragments}; +use crate::error_type_match; use crate::modules::expression::expr::Expr; use crate::modules::variable::{handle_variable_reference, prevent_constant_mutation, variable_name_extensions}; use crate::translate::compute::translate_computation_eval; @@ -51,17 +51,16 @@ impl TranslateModule for ShorthandAdd { //noinspection DuplicatedCode fn translate(&self, meta: &mut TranslateMetadata) -> TranslationFragment { let var = VarFragment::new(&self.var, self.kind.clone(), self.is_ref, self.global_id); - let name = var.get_name(); match self.kind { Type::Text | Type::Array(_) => { let expr = self.expr.translate_eval(meta, self.is_ref); - let (stmt, _var) = meta.gen_stmt_variable(&name, self.global_id, self.kind.clone(), self.is_ref, None, "+=", expr); + let (stmt, _var) = meta.gen_stmt_variable(&self.var, self.global_id, self.kind.clone(), self.is_ref, None, "+=", expr); stmt } _ => { let expr = self.expr.translate_eval(meta, self.is_ref); - let expr = translate_computation_eval(meta, ArithOp::Add, Some(fragments!(raw: "{}", name)), Some(expr), self.is_ref); - let (stmt, _var) = meta.gen_stmt_variable(&name, self.global_id, self.kind.clone(), self.is_ref, None, "+=", expr); + let expr = translate_computation_eval(meta, ArithOp::Add, Some(var.to_frag()), Some(expr), self.is_ref); + let (stmt, _var) = meta.gen_stmt_variable(&self.var, self.global_id, self.kind.clone(), self.is_ref, None, "=", expr); stmt } } diff --git a/src/modules/shorthand/div.rs b/src/modules/shorthand/div.rs index 04116efb..32645e88 100644 --- a/src/modules/shorthand/div.rs +++ b/src/modules/shorthand/div.rs @@ -1,6 +1,6 @@ use heraclitus_compiler::prelude::*; use crate::modules::prelude::*; -use crate::{error_type_match, fragments}; +use crate::error_type_match; use crate::modules::expression::expr::Expr; use crate::modules::variable::{handle_variable_reference, prevent_constant_mutation, variable_name_extensions}; use crate::translate::compute::translate_computation_eval; @@ -51,11 +51,9 @@ impl TranslateModule for ShorthandDiv { //noinspection DuplicatedCode fn translate(&self, meta: &mut TranslateMetadata) -> TranslationFragment { let var = VarFragment::new(&self.var, self.kind.clone(), self.is_ref, self.global_id); - let name = var.get_name(); - let expr = self.expr.translate_eval(meta, self.is_ref); - let expr = translate_computation_eval(meta, ArithOp::Div, Some(fragments!(raw: "{}", name)), Some(expr), self.is_ref); - let (stmt, _var) = meta.gen_stmt_variable(&name, self.global_id, self.kind.clone(), self.is_ref, None, "=", expr); + let expr = translate_computation_eval(meta, ArithOp::Div, Some(var.to_frag()), Some(expr), self.is_ref); + let (stmt, _var) = meta.gen_stmt_variable(&self.var, self.global_id, self.kind.clone(), self.is_ref, None, "=", expr); stmt } } diff --git a/src/modules/shorthand/modulo.rs b/src/modules/shorthand/modulo.rs index 47f652b7..b4022e78 100644 --- a/src/modules/shorthand/modulo.rs +++ b/src/modules/shorthand/modulo.rs @@ -1,6 +1,6 @@ use heraclitus_compiler::prelude::*; use crate::modules::prelude::*; -use crate::{error_type_match, fragments}; +use crate::error_type_match; use crate::modules::expression::expr::Expr; use crate::modules::variable::{handle_variable_reference, prevent_constant_mutation, variable_name_extensions}; use crate::translate::compute::translate_computation_eval; @@ -51,11 +51,9 @@ impl TranslateModule for ShorthandModulo { //noinspection DuplicatedCode fn translate(&self, meta: &mut TranslateMetadata) -> TranslationFragment { let var = VarFragment::new(&self.var, self.kind.clone(), self.is_ref, self.global_id); - let name = var.get_name(); - let expr = self.expr.translate_eval(meta, self.is_ref); - let expr = translate_computation_eval(meta, ArithOp::Modulo, Some(fragments!(raw: "{}", name)), Some(expr), self.is_ref); - let (stmt, _var) = meta.gen_stmt_variable(&name, self.global_id, self.kind.clone(), self.is_ref, None, "=", expr); + let expr = translate_computation_eval(meta, ArithOp::Modulo, Some(var.to_frag()), Some(expr), self.is_ref); + let (stmt, _var) = meta.gen_stmt_variable(&self.var, self.global_id, self.kind.clone(), self.is_ref, None, "=", expr); stmt } } diff --git a/src/modules/shorthand/mul.rs b/src/modules/shorthand/mul.rs index 5399730c..c8376dce 100644 --- a/src/modules/shorthand/mul.rs +++ b/src/modules/shorthand/mul.rs @@ -1,6 +1,6 @@ use heraclitus_compiler::prelude::*; use crate::modules::prelude::*; -use crate::{error_type_match, fragments}; +use crate::error_type_match; use crate::modules::expression::expr::Expr; use crate::modules::variable::{handle_variable_reference, prevent_constant_mutation, variable_name_extensions}; use crate::translate::compute::translate_computation_eval; @@ -51,11 +51,9 @@ impl TranslateModule for ShorthandMul { //noinspection DuplicatedCode fn translate(&self, meta: &mut TranslateMetadata) -> TranslationFragment { let var = VarFragment::new(&self.var, self.kind.clone(), self.is_ref, self.global_id); - let name = var.get_name(); - let expr = self.expr.translate_eval(meta, self.is_ref); - let expr = translate_computation_eval(meta, ArithOp::Mul, Some(fragments!(raw: "{}", name)), Some(expr), self.is_ref); - let (stmt, _var) = meta.gen_stmt_variable(&name, self.global_id, self.kind.clone(), self.is_ref, None, "=", expr); + let expr = translate_computation_eval(meta, ArithOp::Mul, Some(var.to_frag()), Some(expr), self.is_ref); + let (stmt, _var) = meta.gen_stmt_variable(&self.var, self.global_id, self.kind.clone(), self.is_ref, None, "=", expr); stmt } } diff --git a/src/modules/shorthand/sub.rs b/src/modules/shorthand/sub.rs index 60fc971c..aedab4c0 100644 --- a/src/modules/shorthand/sub.rs +++ b/src/modules/shorthand/sub.rs @@ -1,6 +1,6 @@ use heraclitus_compiler::prelude::*; use crate::modules::prelude::*; -use crate::{error_type_match, fragments}; +use crate::error_type_match; use crate::modules::expression::expr::Expr; use crate::modules::variable::{handle_variable_reference, prevent_constant_mutation, variable_name_extensions}; use crate::translate::compute::translate_computation_eval; @@ -51,11 +51,9 @@ impl TranslateModule for ShorthandSub { //noinspection DuplicatedCode fn translate(&self, meta: &mut TranslateMetadata) -> TranslationFragment { let var = VarFragment::new(&self.var, self.kind.clone(), self.is_ref, self.global_id); - let name = var.get_name(); - let expr = self.expr.translate_eval(meta, self.is_ref); - let expr = translate_computation_eval(meta, ArithOp::Sub, Some(fragments!(raw: "{}", name)), Some(expr), self.is_ref); - let (stmt, _var) = meta.gen_stmt_variable(&name, self.global_id, self.kind.clone(), self.is_ref, None, "=", expr); + let expr = translate_computation_eval(meta, ArithOp::Sub, Some(var.to_frag()), Some(expr), self.is_ref); + let (stmt, _var) = meta.gen_stmt_variable(&self.var, self.global_id, self.kind.clone(), self.is_ref, None, "=", expr); stmt } } diff --git a/src/modules/statement/statement.rs b/src/modules/statement/statement.rs index 72e8022c..c1ad23a8 100644 --- a/src/modules/statement/statement.rs +++ b/src/modules/statement/statement.rs @@ -165,11 +165,7 @@ impl TranslateModule for Statement { }, _ => self.translate_match(meta, statement) }; - if meta.stmt_queue.is_empty() { - return translated; - } else { - return BlockFragment::new(meta.stmt_queue.drain(..).collect(), false).to_frag() - } + translated } } diff --git a/src/modules/variable/init.rs b/src/modules/variable/init.rs index 54c3c13e..237c88ff 100644 --- a/src/modules/variable/init.rs +++ b/src/modules/variable/init.rs @@ -1,5 +1,4 @@ use heraclitus_compiler::prelude::*; -use crate::fragments; use crate::modules::prelude::*; use crate::modules::types::Typed; use crate::modules::expression::expr::Expr; @@ -60,10 +59,7 @@ impl SyntaxModule for VariableInit { impl TranslateModule for VariableInit { fn translate(&self, meta: &mut TranslateMetadata) -> TranslationFragment { - let mut expr = self.expr.translate(meta); - if self.expr.get_type().is_array() { - expr = fragments!("(", expr, ")"); - } + let expr = self.expr.translate(meta); let (stmt, _var) = meta.gen_stmt_variable(&self.name, self.global_id, self.expr.get_type(), false, None, "=", expr); stmt } diff --git a/src/modules/variable/set.rs b/src/modules/variable/set.rs index 0948e583..d5415e42 100644 --- a/src/modules/variable/set.rs +++ b/src/modules/variable/set.rs @@ -1,5 +1,4 @@ use heraclitus_compiler::prelude::*; -use crate::fragments; use crate::modules::prelude::*; use crate::docs::module::DocumentationModule; use crate::{modules::expression::expr::Expr, translate::module::TranslateModule}; @@ -67,11 +66,8 @@ impl SyntaxModule for VariableSet { impl TranslateModule for VariableSet { fn translate(&self, meta: &mut TranslateMetadata) -> TranslationFragment { let name = self.name.clone(); - let index = self.index.as_ref().map(|v| v.translate_eval(meta, self.is_ref)); - let mut expr = self.expr.translate_eval(meta, self.is_ref); - if let Type::Array(_) = self.expr.get_type() { - expr = fragments!("(", expr, ")"); - } + let index = self.index.as_ref().map(|v| v.translate(meta)); + let expr = self.expr.translate(meta); let (stmt, _var) = meta.gen_stmt_variable(&name, self.global_id, self.expr.get_type(), self.is_ref, index, "=", expr); stmt } diff --git a/src/tests/validity/variable_ref_function_invocation.ab b/src/tests/validity/variable_ref_function_invocation.ab index dbab6ad6..ccfcb535 100644 --- a/src/tests/validity/variable_ref_function_invocation.ab +++ b/src/tests/validity/variable_ref_function_invocation.ab @@ -1,5 +1,5 @@ // Output -// "sram" +// sram fun reversed(input: Text): Text { return trust $ echo {input} | rev $ diff --git a/src/translate/compute.rs b/src/translate/compute.rs index 6d38c264..d905c651 100644 --- a/src/translate/compute.rs +++ b/src/translate/compute.rs @@ -3,6 +3,8 @@ use crate::{modules::prelude::{TranslationFragment, TranslationFragmentable}, ut use crate::modules::prelude::*; use crate::fragments; +use super::fragments::subprocess::SubprocessFragment; + pub enum ArithType { BcSed } @@ -62,8 +64,8 @@ pub fn translate_computation( }; let math_lib_flag = RawFragment::new(if math_lib_flag { "-l" } else { "" }).to_frag(); let operator = RawFragment::new(&format!(" '{op}' ")).to_frag(); - let value = fragments!("echo ", left, operator, right, " | bc ", math_lib_flag, " | sed", sed_regex); - meta.gen_subprocess(value) + let value = fragments!("echo ", left, operator, right, " | bc ", math_lib_flag, " | sed '", sed_regex, "'"); + SubprocessFragment::new(value).to_frag() } } } diff --git a/src/translate/fragments/block.rs b/src/translate/fragments/block.rs index 4b58e4df..61757eb7 100644 --- a/src/translate/fragments/block.rs +++ b/src/translate/fragments/block.rs @@ -1,3 +1,4 @@ +use std::mem; use super::fragment::{TranslationFragment, TranslationFragmentable}; use crate::utils::TranslateMetadata; @@ -18,25 +19,42 @@ impl BlockFragment { pub fn append(&mut self, statement: TranslationFragment) { self.statements.push(statement); } + + pub fn is_empty(&self) -> bool { + self.statements.is_empty() + } } impl TranslationFragmentable for BlockFragment { fn render(self, meta: &mut TranslateMetadata) -> String { + if self.is_empty() && self.increase_indent { + return ":".to_string() + } if self.increase_indent { meta.increase_indent(); } - let mut result = String::new(); + let mut result = vec![]; for statement in self.statements { - if let TranslationFragment::Empty = statement { - continue; + match statement { + TranslationFragment::Empty => { + continue + } + TranslationFragment::Block(block) => { + result.push(block.render(meta)); + } + _ => { + let statement = statement.render(meta); + for stmt in mem::take(&mut meta.stmt_queue) { + result.push(meta.gen_indent() + &stmt.render(meta)); + } + result.push(meta.gen_indent() + &statement); + } } - result.push_str(&meta.gen_indent()); - result.push_str(&statement.render(meta)); } if self.increase_indent { meta.decrease_indent(); } - result + result.join("\n") } fn to_frag(self) -> TranslationFragment { diff --git a/src/translate/fragments/eval.rs b/src/translate/fragments/eval.rs new file mode 100644 index 00000000..fd105344 --- /dev/null +++ b/src/translate/fragments/eval.rs @@ -0,0 +1,36 @@ +use super::fragment::{TranslationFragment, TranslationFragmentable}; +use crate::utils::TranslateMetadata; + +#[derive(Debug, Clone)] +pub struct EvalFragment { + pub fragment: Box, + pub toggle: bool, +} + +impl EvalFragment { + pub fn new(fragment: TranslationFragment, toggle: bool) -> Self { + EvalFragment { + fragment: Box::new(fragment), + toggle, + } + } +} + +impl TranslationFragmentable for EvalFragment { + fn render(self, meta: &mut TranslateMetadata) -> String { + let prev = meta.eval_ctx; + meta.eval_ctx = self.toggle; + let result = self.fragment.render(meta); + meta.eval_ctx = prev; + + if self.toggle { + format!("eval \"{result}\"") + } else { + result + } + } + + fn to_frag(self) -> TranslationFragment { + TranslationFragment::Eval(self) + } +} diff --git a/src/translate/fragments/fragment.rs b/src/translate/fragments/fragment.rs index af08b952..79b41fdf 100644 --- a/src/translate/fragments/fragment.rs +++ b/src/translate/fragments/fragment.rs @@ -1,10 +1,5 @@ use super::{ - block::BlockFragment, - compound::CompoundFragment, - interpolable::InterpolableFragment, - list::ListFragment, - raw::RawFragment, - var::VarFragment, + block::BlockFragment, compound::CompoundFragment, eval::EvalFragment, interpolable::InterpolableFragment, list::ListFragment, raw::RawFragment, subprocess::SubprocessFragment, var::VarFragment }; use crate::utils::TranslateMetadata; @@ -21,6 +16,8 @@ pub enum TranslationFragment { Compound(CompoundFragment), Interpolable(InterpolableFragment), List(ListFragment), + Eval(EvalFragment), + Subprocess(SubprocessFragment), Empty } @@ -42,6 +39,8 @@ impl TranslationFragmentable for TranslationFragment { TranslationFragment::Compound(statement) => statement.render(meta), TranslationFragment::Interpolable(interpolable) => interpolable.render(meta), TranslationFragment::List(list) => list.render(meta), + TranslationFragment::Eval(eval) => eval.render(meta), + TranslationFragment::Subprocess(subprocess) => subprocess.render(meta), TranslationFragment::Empty => String::new(), } } diff --git a/src/translate/fragments/interpolable.rs b/src/translate/fragments/interpolable.rs index 958d242a..223fd748 100644 --- a/src/translate/fragments/interpolable.rs +++ b/src/translate/fragments/interpolable.rs @@ -118,7 +118,7 @@ impl TranslationFragmentable for InterpolableFragment { let quote = meta.gen_quote(); match render_type { InterpolableRenderType::StringLiteral => format!("{quote}{result}{quote}"), - InterpolableRenderType::GlobalContext => result, + InterpolableRenderType::GlobalContext => result.trim().to_string(), } } diff --git a/src/translate/fragments/mod.rs b/src/translate/fragments/mod.rs index e3803a82..37f3c04e 100644 --- a/src/translate/fragments/mod.rs +++ b/src/translate/fragments/mod.rs @@ -5,6 +5,8 @@ pub mod raw; pub mod var; pub mod interpolable; pub mod list; +pub mod eval; +pub mod subprocess; #[macro_export] macro_rules! fragments { diff --git a/src/translate/fragments/subprocess.rs b/src/translate/fragments/subprocess.rs new file mode 100644 index 00000000..e3bf8dd2 --- /dev/null +++ b/src/translate/fragments/subprocess.rs @@ -0,0 +1,30 @@ +use super::fragment::{TranslationFragment, TranslationFragmentable}; +use crate::utils::TranslateMetadata; + +#[derive(Debug, Clone)] +pub struct SubprocessFragment { + pub fragment: Box, +} + +impl SubprocessFragment { + pub fn new(fragment: TranslationFragment) -> Self { + SubprocessFragment { + fragment: Box::new(fragment), + } + } +} + +impl TranslationFragmentable for SubprocessFragment { + fn render(self, meta: &mut TranslateMetadata) -> String { + let result = self.fragment.render(meta); + if meta.eval_ctx { + format!("$(eval \"{}\")", result) + } else { + format!("$({})", result) + } + } + + fn to_frag(self) -> TranslationFragment { + TranslationFragment::Subprocess(self) + } +} diff --git a/src/translate/fragments/var.rs b/src/translate/fragments/var.rs index 69763b0f..ba1de085 100644 --- a/src/translate/fragments/var.rs +++ b/src/translate/fragments/var.rs @@ -89,13 +89,14 @@ impl VarFragment { if !self.is_quoted { self.get_name() } else { - meta.gen_quote().to_string() + &self.name + meta.gen_quote() + meta.gen_quote().to_string() + &self.get_name() + meta.gen_quote() } } // Returns the variable value in the bash context Ex. "$varname" or "${varname[@]}" pub fn render_bash_value(mut self, meta: &mut TranslateMetadata) -> String { let quote = if self.is_quoted { meta.gen_quote() } else { "" }; + let dollar = meta.gen_dollar(); let name = self.get_name(); let index = self.index.take(); @@ -107,11 +108,11 @@ impl VarFragment { } match self.kind { - Type::Text => { - format!("{quote}${{{name}}}{quote}") + Type::Text | Type::Array(_) => { + format!("{quote}{dollar}{{{prefix}{name}{suffix}}}{quote}") } _ => { - format!("${{{name}}}") + format!("{dollar}{{{prefix}{name}{suffix}}}") } } } @@ -146,19 +147,32 @@ impl VarFragment { } } + fn result_is_array(&self) -> bool { + let is_index = matches!(*self.index, Some(VarIndexValue::Index(_))); + self.kind.is_array() && !self.is_length && !is_index + } + fn render_deref_variable(self, meta: &mut TranslateMetadata, prefix: &str, name: &str, suffix: &str) -> String { + let arr_open = if self.result_is_array() { "(" } else { "" }; + let arr_close = if self.result_is_array() { ")" } else { "" }; + let quote = if self.is_quoted { meta.gen_quote() } else { "" }; + let dollar = meta.gen_dollar(); if prefix.is_empty() && suffix.is_empty() { - let quote = if self.is_quoted { meta.gen_quote() } else { "" }; - return format!("{quote}${{!{name}}}{quote}"); + return format!("{quote}{dollar}{{!{name}}}{quote}"); } let id = meta.gen_value_id(); - let eval_value = format!("{prefix}${{{name}}}{suffix}"); + let eval_value = format!("{prefix}{dollar}{{{name}}}{suffix}"); // TODO: Check if we can just `{name}_deref` without `__` and/or id. let var_name = format!("__{name}_deref_{id}"); meta.stmt_queue.push_back(RawFragment::new( - &format!("eval \"local {var_name}=\\\"\\${{{eval_value}}}\\\"\"") + &format!("eval \"local {var_name}={arr_open}\\\"\\${{{eval_value}}}\\\"{arr_close}\"") ).to_frag()); - format!("${var_name}") + + if self.result_is_array() { + format!("{quote}{dollar}{{{var_name}[@]}}{quote}") + } else { + format!("{quote}{dollar}{{{var_name}}}{quote}") + } } } diff --git a/src/utils/function_metadata.rs b/src/utils/function_metadata.rs index 2093c604..382420cb 100644 --- a/src/utils/function_metadata.rs +++ b/src/utils/function_metadata.rs @@ -16,7 +16,7 @@ impl FunctionMetadata { } pub fn mangled_name(&self) -> String { - format!("__AF_{}{}_v{}", self.name, self.id, self.variant) + format!("__ret_{}{}_v{}", self.name, self.id, self.variant) } pub fn default_return(&self) -> &'static str { diff --git a/src/utils/metadata/translate.rs b/src/utils/metadata/translate.rs index 570c8e0a..1b94c88a 100644 --- a/src/utils/metadata/translate.rs +++ b/src/utils/metadata/translate.rs @@ -7,6 +7,7 @@ use crate::fragments; use crate::modules::prelude::*; use crate::modules::types::Type; use crate::translate::compute::ArithType; +use crate::translate::fragments::eval::EvalFragment; use crate::utils::function_cache::FunctionCache; use crate::utils::function_metadata::FunctionMetadata; @@ -64,6 +65,13 @@ impl TranslateMetadata { var } + #[inline] + pub fn push_stmt_variable_lazy(&mut self, name: &str, id: Option, kind: Type, value: TranslationFragment) -> VarFragment { + let (stmt, var) = self.gen_stmt_variable_lazy(name, id, kind, false, None, "=", value); + self.stmt_queue.push_back(stmt); + var + } + pub fn gen_stmt_variable( &mut self, name: &str, @@ -73,6 +81,41 @@ impl TranslateMetadata { index: Option, op: &str, value: TranslationFragment + ) -> (TranslationFragment, VarFragment) { + let is_array = kind.is_array(); + let variable = VarFragment::new(name, kind, is_ref, id); + let frags = { + let mut result = vec![]; + match is_ref { + true => result.push(fragments!(raw: "${{{}}}", variable.get_name())), + false => result.push(fragments!(raw: "{}", variable.get_name())), + } + if let Some(index) = index { + result.push(fragments!("[", index, "]")); + } + result.push(fragments!(raw: "{}", op)); + if is_array { + result.push(fragments!(raw: "(")); + } + result.push(value); + if is_array { + result.push(fragments!(raw: ")")); + } + result + }; + let stmt = CompoundFragment::new(frags).to_frag(); + (EvalFragment::new(stmt, is_ref).to_frag(), variable) + } + + pub fn gen_stmt_variable_lazy( + &mut self, + name: &str, + id: Option, + kind: Type, + is_ref: bool, + index: Option, + op: &str, + value: TranslationFragment ) -> (TranslationFragment, VarFragment) { match value { // If the value is already variable, then we don't need to assign it to a new variable. @@ -80,25 +123,7 @@ impl TranslateMetadata { (TranslationFragment::Empty, var) }, _ => { - let variable = VarFragment::new(name, kind, is_ref, id); - let frags = { - let mut result = vec![]; - if is_ref { - result.push(fragments!(raw: "eval \"")); - } - result.push(fragments!(raw: "{}", variable.get_name())); - if let Some(index) = index { - result.push(fragments!("[", index, "]")); - } - result.push(fragments!(raw: "{}", op)); - result.push(value); - if is_ref { - result.push(fragments!(raw: "\"")); - } - result - }; - let stmt = CompoundFragment::new(frags).to_frag(); - (stmt, variable) + self.gen_stmt_variable(name, id, kind, is_ref, index, op, value) } } } @@ -131,14 +156,6 @@ impl TranslateMetadata { } } - pub fn gen_subprocess(&self, stmt: TranslationFragment) -> TranslationFragment { - if self.eval_ctx { - fragments!("$(eval \"", stmt, "\")") - } else { - fragments!("$(", stmt, ")") - } - } - pub fn gen_dollar(&self) -> &'static str { if self.eval_ctx { "\\$"