Skip to content

Commit

Permalink
Merge pull request #58 from Ph0enixKM/A88
Browse files Browse the repository at this point in the history
A88 Add ref for accessing variables passed by reference
  • Loading branch information
Ph0enixKM authored Sep 28, 2023
2 parents 6c26276 + f44481d commit 5bd596c
Show file tree
Hide file tree
Showing 42 changed files with 417 additions and 118 deletions.
2 changes: 1 addition & 1 deletion src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ impl AmberCompiler {
pub fn parse(&self, tokens: Vec<Token>) -> Result<(Block, ParserMetadata), Message> {
let code = self.cc.code.as_ref().expect(NO_CODE_PROVIDED).clone();
let mut meta = ParserMetadata::new(tokens, self.path.clone(), Some(code));
if let Err(Failure::Loud(err)) = check_all_blocks(&mut meta) {
if let Err(Failure::Loud(err)) = check_all_blocks(&meta) {
return Err(err);
}
let mut block = Block::new();
Expand Down
10 changes: 6 additions & 4 deletions src/modules/command/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ impl SyntaxModule<ParserMetadata> for CommandExpr {
}
Ok(())
},
Err(Failure::Loud(err)) => return Err(Failure::Loud(err)),
Err(Failure::Loud(err)) => Err(Failure::Loud(err)),
Err(Failure::Quiet(_)) => {
let tok = meta.get_current_token();
(self.strings, self.interps) = parse_interpolated_region(meta, '$')?;
Expand All @@ -71,16 +71,18 @@ impl TranslateModule for CommandExpr {
.map(|item| item.translate(meta))
.collect::<Vec<String>>();
let failed = self.failed.translate(meta);
let silent = self.is_silent_expr.then(|| " 2>/dev/null").unwrap_or("");
let silent = if self.is_silent_expr { " 2>/dev/null" } else { "" };
if failed.is_empty() {
format!("$({}{silent})", translate_interpolated_region(self.strings.clone(), interps, false))
let translation = translate_interpolated_region(self.strings.clone(), interps, false);
meta.gen_subprocess(&(translation + silent))
} else {
let id = meta.gen_value_id();
let quote = meta.gen_quote();
let dollar = meta.gen_dollar();
let translation = translate_interpolated_region(self.strings.clone(), interps, false);
meta.stmt_queue.push_back(format!("__AMBER_VAL_{id}=$({translation}{silent})"));
meta.stmt_queue.push_back(failed);
format!("{quote}${{__AMBER_VAL_{id}}}{quote}")
format!("{quote}{dollar}{{__AMBER_VAL_{id}}}{quote}")
}
}
}
2 changes: 1 addition & 1 deletion src/modules/command/modifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ impl SyntaxModule<ParserMetadata> for CommandModifier {
match meta.get_current_token() {
Some(tok) => {
sequence.push_str(tok.word.as_str());
sequence.push_str(" ");
sequence.push(' ');
match tok.word.as_str() {
"unsafe" => {
self.is_unsafe = true;
Expand Down
18 changes: 6 additions & 12 deletions src/modules/condition/failed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ impl SyntaxModule<ParserMetadata> for Failed {

fn parse(&mut self, meta: &mut ParserMetadata) -> SyntaxResult {
let tok = meta.get_current_token();
if let Ok(_) = token(meta, "?") {
if token(meta, "?").is_ok() {
if !meta.context.is_fun_ctx && !meta.context.is_main_ctx && !meta.context.is_unsafe_ctx {
return error!(meta, tok, "The '?' operator can only be used in the main block or function body")
}
Expand Down Expand Up @@ -76,9 +76,7 @@ impl TranslateModule for Failed {
fn translate(&self, meta: &mut TranslateMetadata) -> String {
if self.is_parsed {
let block = self.block.translate(meta);
let ret = self.is_main
.then(|| "exit $__AMBER_STATUS")
.unwrap_or("return $__AMBER_STATUS");
let ret = if self.is_main { "exit $__AMBER_STATUS" } else { "return $__AMBER_STATUS" };
// the condition of '$?' clears the status code thus we need to store it in a variable
if self.is_question_mark {
// if the failed expression is in the main block we need to clear the return value
Expand All @@ -88,20 +86,16 @@ impl TranslateModule for Failed {
} else {
String::new()
};
vec![
"__AMBER_STATUS=$?;",
["__AMBER_STATUS=$?;",
"if [ $__AMBER_STATUS != 0 ]; then",
&clear_return,
ret,
"fi"
].join("\n")
"fi"].join("\n")
} else {
vec![
"__AMBER_STATUS=$?;",
["__AMBER_STATUS=$?;",
"if [ $__AMBER_STATUS != 0 ]; then",
&block,
"fi"
].join("\n")
"fi"].join("\n")
}
} else {
String::new()
Expand Down
4 changes: 1 addition & 3 deletions src/modules/condition/ifchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,7 @@ impl SyntaxModule<ParserMetadata> for IfChain {
return Ok(())
}
// Handle end of the if chain
if let Err(err) = syntax(meta, &mut cond) {
return Err(err)
}
syntax(meta, &mut cond)?;
match token(meta, "{") {
Ok(_) => {
syntax(meta, &mut block)?;
Expand Down
2 changes: 1 addition & 1 deletion src/modules/condition/ternary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,6 @@ impl TranslateModule for Ternary {
let cond = self.cond.translate(meta);
let true_expr = self.true_expr.translate(meta);
let false_expr = self.false_expr.translate(meta);
format!("$(if [ {} != 0 ]; then echo {}; else echo {}; fi)", cond, true_expr, false_expr)
meta.gen_subprocess(&format!("if [ {} != 0 ]; then echo {}; else echo {}; fi", cond, true_expr, false_expr))
}
}
2 changes: 1 addition & 1 deletion src/modules/expression/binop/eq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ impl TranslateModule for Eq {
if self.left.get_type() == Type::Text && self.right.get_type() == Type::Text {
strip_text_quotes(&mut left);
strip_text_quotes(&mut right);
format!("$([ \"_{left}\" != \"_{right}\" ]; echo $?)")
meta.gen_subprocess(&format!("[ \"_{left}\" != \"_{right}\" ]; echo $?"))
} else {
translate_computation(meta, ArithOp::Eq, Some(left), Some(right))
}
Expand Down
4 changes: 2 additions & 2 deletions src/modules/expression/binop/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ pub mod le;
pub mod eq;
pub mod neq;

pub fn expression_arms_of_type(meta: &mut ParserMetadata, left: &Type, right: &Type, predicate: impl Fn(Type) -> bool, tok_pos: Option<Token>, message: &str) -> Result<Type, Failure> {
pub fn expression_arms_of_type(meta: &ParserMetadata, left: &Type, right: &Type, predicate: impl Fn(Type) -> bool, tok_pos: Option<Token>, message: &str) -> Result<Type, Failure> {
if left == right && [left, right].iter().all(|kind| predicate((*kind).clone())) {
Ok(left.clone())
} else {
error!(meta, tok_pos, message)
}
}

pub fn expression_arms_of_same_type(meta: &mut ParserMetadata, left: &Expr, right: &Expr, tok_pos: Option<Token>, message: &str) -> SyntaxResult {
pub fn expression_arms_of_same_type(meta: &ParserMetadata, left: &Expr, right: &Expr, tok_pos: Option<Token>, message: &str) -> SyntaxResult {
if left.get_type() != right.get_type() {
error!(meta, tok_pos, message)
} else {
Expand Down
2 changes: 1 addition & 1 deletion src/modules/expression/binop/neq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ impl TranslateModule for Neq {
if self.left.get_type() == Type::Text && self.right.get_type() == Type::Text {
strip_text_quotes(&mut left);
strip_text_quotes(&mut right);
format!("$([ \"_{left}\" == \"_{right}\" ]; echo $?)")
meta.gen_subprocess(&format!("[ \"_{left}\" == \"_{right}\" ]; echo $?"))
} else {
translate_computation(meta, ArithOp::Neq, Some(left), Some(right))
}
Expand Down
5 changes: 3 additions & 2 deletions src/modules/expression/literal/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ impl SyntaxModule<ParserMetadata> for Array {
Err(Failure::Quiet(_)) => {
loop {
let tok = meta.get_current_token();
if let Ok(_) = token(meta, "[") {
if token(meta, "[").is_ok() {
return error!(meta, tok, "Arrays cannot be nested due to the Bash limitations")
}
// Parse array value
Expand Down Expand Up @@ -84,7 +84,8 @@ impl TranslateModule for Array {
let name = format!("__AMBER_ARRAY_{}", meta.gen_array_id());
let args = self.exprs.iter().map(|expr| expr.translate_eval(meta, false)).collect::<Vec<String>>().join(" ");
let quote = meta.gen_quote();
let dollar = meta.gen_dollar();
meta.stmt_queue.push_back(format!("{name}=({args})"));
format!("{quote}${{{name}[@]}}{quote}")
format!("{quote}{dollar}{{{name}[@]}}{quote}")
}
}
2 changes: 1 addition & 1 deletion src/modules/expression/literal/bool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ impl SyntaxModule<ParserMetadata> for Bool {
}

fn parse(&mut self, meta: &mut ParserMetadata) -> SyntaxResult {
let value = token_by(meta, |value| vec!["true", "false"].contains(&value.as_str()))?;
let value = token_by(meta, |value| ["true", "false"].contains(&value.as_str()))?;
self.value = value == "true";
Ok(())
}
Expand Down
2 changes: 1 addition & 1 deletion src/modules/expression/literal/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ pub fn translate_interpolated_region(strings: Vec<String>, interps: Vec<String>,
match value {
Some(translated) => {
if is_even {
if translated.starts_with("\"") && translated.ends_with("\"") {
if translated.starts_with('\"') && translated.ends_with('\"') {
result.push(translated.get(1..translated.len() - 1).unwrap().to_string());
} else {
result.push(translated);
Expand Down
4 changes: 2 additions & 2 deletions src/modules/expression/literal/range.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ impl TranslateModule for Range {
let to = self.to.translate(meta);
if self.neq {
let to_neq = translate_computation(meta, ArithOp::Sub, Some(to), Some("1".to_string()));
format!("$(seq {} {})", from, to_neq)
meta.gen_subprocess(&format!("seq {} {}", from, to_neq))
} else {
format!("$(seq {} {})", from, to)
meta.gen_subprocess(&format!("seq {} {}", from, to))
}
}
}
2 changes: 1 addition & 1 deletion src/modules/expression/literal/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ impl SyntaxModule<ParserMetadata> for Status {

impl TranslateModule for Status {
fn translate(&self, _meta: &mut TranslateMetadata) -> String {
format!("$__AMBER_STATUS")
"$__AMBER_STATUS".to_string()
}
}
2 changes: 1 addition & 1 deletion src/modules/expression/unop/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ impl SyntaxModule<ParserMetadata> for Cast {
}

fn parse(&mut self, meta: &mut ParserMetadata) -> SyntaxResult {
parse_left_expr(meta, &mut *self.expr, "as")?;
parse_left_expr(meta, &mut self.expr, "as")?;
let tok = meta.get_current_token();
token(meta, "as")?;
self.kind = parse_type(meta)?;
Expand Down
6 changes: 3 additions & 3 deletions src/modules/function/declaration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ impl SyntaxModule<ParserMetadata> for FunctionDeclaration {
self.is_public = true;
}
if let Err(err) = token(meta, "fun") {
if flags.len() > 0 {
if !flags.is_empty() {
return error!(meta, tok, "Compiler flags can only be used in function declarations")
}
return Err(err)
Expand Down Expand Up @@ -145,7 +145,7 @@ impl SyntaxModule<ParserMetadata> for FunctionDeclaration {
arg_refs: self.arg_refs.clone(),
returns: self.returns.clone(),
is_public: self.is_public,
is_failable: is_failable
is_failable
}, ctx)?;
// Restore the compiler flags
swap(&mut meta.context.cc_flags, &mut flags);
Expand All @@ -167,7 +167,7 @@ impl TranslateModule for FunctionDeclaration {
meta.fun_name = Some((self.name.clone(), self.id, index));
// Parse the function body
result.push(format!("function {name} {{"));
if let Some(args) = self.set_args_as_variables(meta, &function, &self.arg_refs) {
if let Some(args) = self.set_args_as_variables(meta, function, &self.arg_refs) {
result.push(args);
}
result.push(function.block.translate(meta));
Expand Down
2 changes: 1 addition & 1 deletion src/modules/function/declaration_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub fn skip_function_body(meta: &mut ParserMetadata) -> (usize, usize, bool) {
(index_begin, index_end, is_failable)
}

pub fn handle_existing_function(meta: &mut ParserMetadata, tok: Option<Token>) -> Result<(), Failure> {
pub fn handle_existing_function(meta: &ParserMetadata, tok: Option<Token>) -> Result<(), Failure> {
let name = tok.as_ref().unwrap().word.clone();
handle_identifier_name(meta, &name, tok.clone())?;
if meta.get_fun_declaration(&name).is_some() {
Expand Down
20 changes: 11 additions & 9 deletions src/modules/function/invocation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,13 @@ impl SyntaxModule<ParserMetadata> for FunctionInvocation {
}

impl FunctionInvocation {
fn get_variable(&self, meta: &mut TranslateMetadata, name: &str) -> String {
fn get_variable(&self, meta: &TranslateMetadata, name: &str, dollar_override: bool) -> String {
let dollar = dollar_override.then_some("$").unwrap_or_else(|| meta.gen_dollar());
if matches!(self.kind, Type::Array(_)) {
let quote = meta.gen_quote();
format!("{quote}${{{name}[@]}}{quote}")
format!("{quote}{dollar}{{{name}[@]}}{quote}")
} else {
format!("${{{name}}}")
format!("{dollar}{{{name}}}")
}
}
}
Expand All @@ -117,24 +118,25 @@ impl TranslateModule for FunctionInvocation {
// If the argument is an array, we have to get just the "name[@]" part
(translation.starts_with("\"${") && translation.ends_with("[@]}\""))
.then(|| translation.get(3..translation.len() - 2).unwrap().to_string())
.unwrap_or_else(|| translation)
.unwrap_or(translation)
}
}).collect::<Vec<String>>().join(" ");
meta.stmt_queue.push_back(format!("{name} {args}{silent}"));
let invocation_return = self.get_variable(meta, &format!("__AMBER_FUN_{}{}_v{}", self.name, self.id, self.variant_id));
let invocation_instance = self.get_variable(meta, &format!("__AMBER_FUN_{}{}_v{}__{}", self.name, self.id, self.variant_id, self.line));
let invocation_return = &format!("__AMBER_FUN_{}{}_v{}", self.name, self.id, self.variant_id);
let invocation_instance = &format!("__AMBER_FUN_{}{}_v{}__{}", self.name, self.id, self.variant_id, self.line);
let parsed_invocation_return = self.get_variable(meta, invocation_return, true);
if self.is_failable {
let failed = self.failed.translate(meta);
meta.stmt_queue.push_back(failed);
}
meta.stmt_queue.push_back(
format!("__AMBER_FUN_{}{}_v{}__{}={}", self.name, self.id, self.variant_id, self.line, if matches!(self.kind, Type::Array(_)) {
// If the function returns an array we have to store the intermediate result in a variable that is of type array
format!("({})", invocation_return)
format!("({})", parsed_invocation_return)
} else {
invocation_return
parsed_invocation_return
})
);
invocation_instance
self.get_variable(meta, invocation_instance, false)
}
}
13 changes: 6 additions & 7 deletions src/modules/function/invocation_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ fn run_function_with_args(meta: &mut ParserMetadata, mut fun: FunctionDecl, args
// Create a sub context for new variables
meta.push_scope();
for (kind, name, is_ref) in izip!(args, &fun.arg_names, &fun.arg_refs) {
meta.add_param(name, kind.clone(), is_ref.clone());
meta.add_param(name, kind.clone(), *is_ref);
}
// Set the expected return type if specified
if fun.returns != Type::Generic {
Expand All @@ -73,12 +73,12 @@ fn run_function_with_args(meta: &mut ParserMetadata, mut fun: FunctionDecl, args
fun.returns = ctx.fun_ret_type.clone().unwrap_or_else(|| Type::Null);
};
// Set the new argument types
fun.arg_types = args.iter().cloned().collect();
fun.arg_types = args.to_vec();
// Persist the new function instance
Ok((fun.returns.clone(), meta.add_fun_instance(fun.to_interface(), block)))
Ok((fun.returns.clone(), meta.add_fun_instance(fun.into_interface(), block)))
}

pub fn handle_function_reference(meta: &mut ParserMetadata, tok: Option<Token>, name: &str) -> Result<usize, Failure> {
pub fn handle_function_reference(meta: &ParserMetadata, tok: Option<Token>, name: &str) -> Result<usize, Failure> {
match meta.get_fun_declaration(name) {
Some(fun_decl) => Ok(fun_decl.id),
None => {
Expand Down Expand Up @@ -109,9 +109,8 @@ pub fn handle_function_parameters(meta: &mut ParserMetadata, id: usize, fun: Fun
}
}

fn handle_similar_function(meta: &mut ParserMetadata, name: &str) -> Option<String> {
fn handle_similar_function(meta: &ParserMetadata, name: &str) -> Option<String> {
let vars = Vec::from_iter(meta.get_fun_names());
find_best_similarity(name, &vars)
.map(|(match_name, score)| (score >= 0.75).then(|| format!("Did you mean '{match_name}'?")))
.flatten()
.and_then(|(match_name, score)| (score >= 0.75).then(|| format!("Did you mean '{match_name}'?")))
}
4 changes: 2 additions & 2 deletions src/modules/function/ret.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ impl TranslateModule for Return {
let result = self.expr.translate_eval(meta, false);
let result = matches!(self.expr.get_type(), Type::Array(_))
.then(|| format!("({result})"))
.unwrap_or_else(|| result);
.unwrap_or(result);
meta.stmt_queue.push_back(format!("__AMBER_FUN_{name}{id}_v{variant}={result}"));
format!("return 0")
"return 0".to_string()
}
}
2 changes: 1 addition & 1 deletion src/modules/imports/import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ impl Import {
Ok(())
}

fn resolve_import(&mut self, meta: &mut ParserMetadata) -> Result<String, Failure> {
fn resolve_import(&mut self, meta: &ParserMetadata) -> Result<String, Failure> {
match fs::read_to_string(self.path.value.clone()) {
Ok(content) => Ok(content),
Err(err) => error!(meta, self.token_path.clone() => {
Expand Down
2 changes: 1 addition & 1 deletion src/modules/imports/import_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub struct ImportString {
}

impl ImportString {
fn resolve_path(&mut self, meta: &mut ParserMetadata, tok: Option<Token>) -> SyntaxResult {
fn resolve_path(&mut self, meta: &ParserMetadata, tok: Option<Token>) -> SyntaxResult {
if self.value == "std" {
self.value = "[standard library]".to_string();
return Ok(())
Expand Down
6 changes: 2 additions & 4 deletions src/modules/loops/infinite_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,9 @@ impl SyntaxModule<ParserMetadata> for InfiniteLoop {

impl TranslateModule for InfiniteLoop {
fn translate(&self, meta: &mut TranslateMetadata) -> String {
vec![
"while :".to_string(),
["while :".to_string(),
"do".to_string(),
self.block.translate(meta),
"done".to_string()
].join("\n")
"done".to_string()].join("\n")
}
}
Loading

0 comments on commit 5bd596c

Please sign in to comment.