Skip to content

Commit 4b15d01

Browse files
Ph0enixKMb1ekhdwalters
authored
New translation modules architecture (#678)
* feat: initial commit * fix: validity tests * fix: some of the stdlib errors * fix: some tests * fix: stdlib tests * fix: additional error * fix: cargo clippy * fix: wrong quoting * fix: wrong init value * fix: block rendering * feat: improve block formatting * fix: shellcheck issues * feat: add more tests * fix: shellcheck issues * fix: clippy error * feat: add ternary tests * fix: escaping of slices * impl From<String> for CommentFragment * simplify path for use * refactor match for readability Co-authored-by: Huw Walters <huw.walters@gmail.com> * refactor &*self.index -> self.index.as_ref() * add trailing comma to match block * rigidly match all requirements to be 1 1 0 * remove a redundant blank line * simplify echoing the array * reword unreachable code * refactor constructor to give every function its own line * refactor: render -> to_string * fix: trailing commas * refactor: rename fragment structures * refactor: symbols and block fn name * refactor: add context to text escaped regular character test * refactor: remove padding in doc comments * fix: comment and compound * refactor: remove unnecessary files * refactor: compount -> list * refactor: set_quoted -> with_quotes * refactor: iter loop * refactor: fragments(raw:) -> raw_fragment() * refactor: formatting * refactor: improve readability * refactor: variable * refactor: finalize addressing concerns * fix: clippy errors --------- Co-authored-by: b1ek <me@blek.codes> Co-authored-by: Huw Walters <huw.walters@gmail.com>
1 parent d5f8fe8 commit 4b15d01

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

102 files changed

+1565
-1023
lines changed

src/compiler.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
extern crate chrono;
22
use crate::docs::module::DocumentationModule;
33
use crate::modules::block::Block;
4+
use crate::modules::prelude::{BlockFragment, FragmentRenderable};
45
use crate::translate::check_all_blocks;
56
use crate::translate::module::TranslateModule;
67
use crate::utils::{ParserMetadata, TranslateMetadata};
@@ -165,9 +166,9 @@ impl AmberCompiler {
165166
let ast_forest = self.get_sorted_ast_forest(block, &meta);
166167
let mut meta_translate = TranslateMetadata::new(meta, &self.options);
167168
let time = Instant::now();
168-
let mut result = vec![];
169+
let mut result = BlockFragment::new(Vec::new(), false);
169170
for (_path, block) in ast_forest {
170-
result.push(block.translate(&mut meta_translate));
171+
result.append(block.translate(&mut meta_translate));
171172
}
172173
if Self::env_flag_set(AMBER_DEBUG_TIME) {
173174
let pathname = self.path.clone().unwrap_or(String::from("unknown"));
@@ -178,7 +179,7 @@ impl AmberCompiler {
178179
);
179180
}
180181

181-
let mut result = result.join("\n") + "\n";
182+
let mut result = result.to_string(&mut meta_translate);
182183

183184
let filters = self.options.no_proc.iter()
184185
.map(|x| WildMatchPattern::new(x))

src/modules/block.rs

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
use std::collections::VecDeque;
22
use std::ops::Index;
33

4+
use crate::modules::prelude::*;
45
use heraclitus_compiler::prelude::*;
56
use itertools::Itertools;
6-
use crate::docs::module::DocumentationModule;
7-
use crate::utils::{metadata::ParserMetadata, TranslateMetadata};
8-
use crate::translate::module::TranslateModule;
97
use super::statement::stmt::Statement;
108

119
#[derive(Debug, Clone)]
1210
pub struct Block {
13-
pub statements: Vec<Statement>
11+
pub statements: Vec<Statement>,
12+
pub should_indent: bool,
13+
pub needs_noop: bool,
1414
}
1515

1616
impl Block {
@@ -23,14 +23,26 @@ impl Block {
2323
pub fn push_statement(&mut self, statement: Statement) {
2424
self.statements.push(statement);
2525
}
26+
27+
pub fn with_needs_noop(mut self) -> Self {
28+
self.needs_noop = true;
29+
self
30+
}
31+
32+
pub fn with_no_indent(mut self) -> Self {
33+
self.should_indent = false;
34+
self
35+
}
2636
}
2737

2838
impl SyntaxModule<ParserMetadata> for Block {
2939
syntax_name!("Block");
3040

3141
fn new() -> Self {
3242
Block {
33-
statements: vec![]
43+
statements: vec![],
44+
should_indent: true,
45+
needs_noop: false,
3446
}
3547
}
3648

@@ -61,20 +73,21 @@ impl SyntaxModule<ParserMetadata> for Block {
6173
}
6274

6375
impl TranslateModule for Block {
64-
fn translate(&self, meta: &mut TranslateMetadata) -> String {
76+
fn translate(&self, meta: &mut TranslateMetadata) -> FragmentKind {
6577
// Save the current statement queue and create a new one
6678
let mut new_queue = VecDeque::new();
6779
std::mem::swap(&mut meta.stmt_queue, &mut new_queue);
68-
meta.increase_indent();
69-
let result = if self.is_empty() {
70-
":".to_string()
71-
} else {
72-
self.statements.iter()
73-
.map(|statement| statement.translate(meta))
74-
.filter(|translation| !translation.trim().is_empty())
75-
.collect::<Vec<_>>().join("\n")
80+
let result = {
81+
let mut statements = vec![];
82+
for statement in &self.statements {
83+
let statement = statement.translate(meta);
84+
statements.extend(meta.stmt_queue.drain(..));
85+
statements.push(statement);
86+
}
87+
BlockFragment::new(statements, self.should_indent)
88+
.with_needs_noop(self.needs_noop)
89+
.to_frag()
7690
};
77-
meta.decrease_indent();
7891
// Restore the old statement queue
7992
std::mem::swap(&mut meta.stmt_queue, &mut new_queue);
8093
result

src/modules/builtin/cd.rs

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,19 @@
1-
use heraclitus_compiler::prelude::*;
1+
use crate::fragments;
22
use crate::modules::expression::expr::Expr;
3-
use crate::docs::module::DocumentationModule;
3+
use heraclitus_compiler::prelude::*;
4+
use crate::modules::prelude::*;
45
use crate::modules::types::{Type, Typed};
5-
use crate::translate::module::TranslateModule;
6-
use crate::utils::{ParserMetadata, TranslateMetadata};
76

87
#[derive(Debug, Clone)]
98
pub struct Cd {
10-
value: Expr
9+
value: Expr,
1110
}
1211

1312
impl SyntaxModule<ParserMetadata> for Cd {
1413
syntax_name!("ChangeDirectory");
1514

1615
fn new() -> Self {
17-
Cd {
18-
value: Expr::new()
19-
}
16+
Cd { value: Expr::new() }
2017
}
2118

2219
fn parse(&mut self, meta: &mut ParserMetadata) -> SyntaxResult {
@@ -35,9 +32,8 @@ impl SyntaxModule<ParserMetadata> for Cd {
3532
}
3633

3734
impl TranslateModule for Cd {
38-
fn translate(&self, meta: &mut TranslateMetadata) -> String {
39-
let value = self.value.translate(meta);
40-
format!("cd {} || exit", value)
35+
fn translate(&self, meta: &mut TranslateMetadata) -> FragmentKind {
36+
fragments!("cd ", self.value.translate(meta), " || exit")
4137
}
4238
}
4339

src/modules/builtin/echo.rs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,19 @@
1-
use heraclitus_compiler::prelude::*;
2-
use crate::docs::module::DocumentationModule;
1+
use crate::fragments;
32
use crate::modules::expression::expr::Expr;
4-
use crate::translate::module::TranslateModule;
5-
use crate::utils::{ParserMetadata, TranslateMetadata};
3+
use crate::modules::prelude::*;
4+
use heraclitus_compiler::prelude::*;
65

76
#[derive(Debug, Clone)]
87
pub struct Echo {
9-
value: Box<Expr>
8+
value: Box<Expr>,
109
}
1110

1211
impl SyntaxModule<ParserMetadata> for Echo {
1312
syntax_name!("Log");
1413

1514
fn new() -> Self {
1615
Echo {
17-
value: Box::new(Expr::new())
16+
value: Box::new(Expr::new()),
1817
}
1918
}
2019

@@ -26,9 +25,8 @@ impl SyntaxModule<ParserMetadata> for Echo {
2625
}
2726

2827
impl TranslateModule for Echo {
29-
fn translate(&self, meta: &mut TranslateMetadata) -> String {
30-
let value = self.value.translate(meta);
31-
format!("echo {}", value)
28+
fn translate(&self, meta: &mut TranslateMetadata) -> FragmentKind {
29+
fragments!("echo ", self.value.translate(meta))
3230
}
3331
}
3432

src/modules/builtin/exit.rs

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,19 @@
1-
use heraclitus_compiler::prelude::*;
1+
use crate::fragments;
22
use crate::modules::expression::expr::Expr;
3-
use crate::docs::module::DocumentationModule;
3+
use crate::modules::prelude::*;
44
use crate::modules::types::{Type, Typed};
5-
use crate::translate::module::TranslateModule;
6-
use crate::utils::{ParserMetadata, TranslateMetadata};
5+
use heraclitus_compiler::prelude::*;
76

87
#[derive(Debug, Clone)]
98
pub struct Exit {
10-
code: Option<Expr>
9+
code: Option<Expr>,
1110
}
1211

1312
impl SyntaxModule<ParserMetadata> for Exit {
1413
syntax_name!("Exit");
1514

1615
fn new() -> Self {
17-
Exit {
18-
code: None
19-
}
16+
Exit { code: None }
2017
}
2118

2219
fn parse(&mut self, meta: &mut ParserMetadata) -> SyntaxResult {
@@ -43,11 +40,11 @@ impl SyntaxModule<ParserMetadata> for Exit {
4340
}
4441

4542
impl TranslateModule for Exit {
46-
fn translate(&self, meta: &mut TranslateMetadata) -> String {
47-
let code = self.code.as_ref()
43+
fn translate(&self, meta: &mut TranslateMetadata) -> FragmentKind {
44+
let exit_code = self.code.as_ref()
4845
.map(|expr| expr.translate(meta))
49-
.unwrap_or_else(|| "0".to_string());
50-
format!("exit {}", code)
46+
.unwrap_or(fragments!("0"));
47+
fragments!("exit ", exit_code)
5148
}
5249
}
5350

src/modules/builtin/len.rs

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
use crate::docs::module::DocumentationModule;
21
use crate::modules::expression::expr::Expr;
32
use crate::modules::expression::unop::UnOp;
3+
use crate::modules::prelude::*;
44
use crate::modules::types::{Type, Typed};
55
use crate::translate::module::TranslateModule;
66
use crate::utils::{ParserMetadata, TranslateMetadata};
@@ -50,21 +50,12 @@ impl SyntaxModule<ParserMetadata> for Len {
5050
}
5151

5252
impl TranslateModule for Len {
53-
fn translate(&self, meta: &mut TranslateMetadata) -> String {
53+
fn translate(&self, meta: &mut TranslateMetadata) -> FragmentKind {
5454
let value = self.value.translate(meta);
55-
if self.value.get_type() == Type::Text {
56-
meta.stmt_queue.push_back(format!("__AMBER_LEN={value}"));
57-
return String::from("\"${#__AMBER_LEN}\"")
58-
}
59-
// Case for Array passed as a reference
60-
if value.starts_with("\"${!") {
61-
meta.stmt_queue.push_back(format!("__AMBER_LEN=({value})"));
62-
String::from("\"${#__AMBER_LEN[@]}\"")
63-
} else {
64-
format!("\"${{#{}", value.trim_start_matches("\"${"))
65-
.trim_end()
66-
.to_string()
67-
}
55+
let id = meta.gen_value_id();
56+
meta.push_intermediate_variable_lazy("__length", Some(id), Type::Num, value)
57+
.with_length_getter(true)
58+
.to_frag()
6859
}
6960
}
7061

src/modules/builtin/lines.rs

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
use heraclitus_compiler::prelude::*;
2-
use crate::docs::module::DocumentationModule;
1+
use crate::fragments;
2+
use crate::raw_fragment;
33
use crate::modules::expression::expr::Expr;
44
use crate::modules::types::{Type, Typed};
55
use crate::translate::module::TranslateModule;
66
use crate::utils::metadata::{ParserMetadata, TranslateMetadata};
7+
use crate::modules::prelude::*;
8+
use heraclitus_compiler::prelude::*;
79

810
#[derive(Debug, Clone)]
911
pub struct LinesInvocation {
@@ -12,7 +14,7 @@ pub struct LinesInvocation {
1214

1315
impl Typed for LinesInvocation {
1416
fn get_type(&self) -> Type {
15-
Type::Array(Box::new(Type::Text))
17+
Type::array_of(Type::Text)
1618
}
1719
}
1820

@@ -21,7 +23,7 @@ impl SyntaxModule<ParserMetadata> for LinesInvocation {
2123

2224
fn new() -> Self {
2325
LinesInvocation {
24-
path: Box::new(None)
26+
path: Box::new(None),
2527
}
2628
}
2729

@@ -33,7 +35,10 @@ impl SyntaxModule<ParserMetadata> for LinesInvocation {
3335
syntax(meta, &mut path)?;
3436
token(meta, ")")?;
3537
if path.get_type() != Type::Text {
36-
let msg = format!("Expected value of type 'Text' but got '{}'", path.get_type());
38+
let msg = format!(
39+
"Expected value of type 'Text' but got '{}'",
40+
path.get_type()
41+
);
3742
return error!(meta, tok, msg);
3843
}
3944
self.path = Box::new(Some(path));
@@ -42,34 +47,30 @@ impl SyntaxModule<ParserMetadata> for LinesInvocation {
4247
}
4348

4449
impl TranslateModule for LinesInvocation {
45-
fn translate(&self, meta: &mut TranslateMetadata) -> String {
46-
let name = format!("__AMBER_ARRAY_{}", meta.gen_value_id());
50+
fn translate(&self, meta: &mut TranslateMetadata) -> FragmentKind {
4751
let temp = format!("__AMBER_LINE_{}", meta.gen_value_id());
48-
let path = (*self.path).as_ref()
49-
.map(|p| p.translate_eval(meta, false))
50-
.unwrap_or_default();
51-
let quote = meta.gen_quote();
52-
let dollar = meta.gen_dollar();
52+
let path = (*self.path)
53+
.as_ref()
54+
.map(|p| p.translate(meta))
55+
.expect("Cannot read lines without provided path");
5356
let indent = TranslateMetadata::single_indent();
54-
let block = [
55-
format!("{name}=()"),
56-
format!("while IFS= read -r {temp}; do"),
57-
format!("{indent}{name}+=(\"${temp}\")"),
58-
format!("done <{path}"),
59-
].join("\n");
60-
meta.stmt_queue.push_back(block);
61-
format!("{quote}{dollar}{{{name}[@]}}{quote}")
57+
let id = meta.gen_value_id();
58+
let value = meta.push_intermediate_variable_lazy("__array", Some(id), Type::array_of(Type::Text), FragmentKind::Empty);
59+
meta.stmt_queue.extend([
60+
raw_fragment!("while IFS= read -r {temp}; do"),
61+
raw_fragment!("{indent}{}+=(\"${}\")", value.get_name(), temp),
62+
fragments!("done <", path),
63+
]);
64+
value.to_frag()
6265
}
6366
}
6467

6568
impl LinesInvocation {
66-
pub fn surround_iter(&self, meta: &mut TranslateMetadata, name: &str) -> (String, String) {
67-
let path = (*self.path).as_ref()
69+
pub fn translate_path(&self, meta: &mut TranslateMetadata) -> FragmentKind {
70+
(*self.path)
71+
.as_ref()
6872
.map(|p| p.translate(meta))
69-
.unwrap_or_default();
70-
let prefix = format!("while IFS= read -r {name}; do");
71-
let suffix = format!("done <{path}");
72-
(prefix, suffix)
73+
.expect("Cannot read lines without provided path in iterator loop")
7374
}
7475
}
7576

0 commit comments

Comments
 (0)