diff --git a/setup/install.ab b/setup/install.ab index 5f1ad551..c6dd0bf2 100644 --- a/setup/install.ab +++ b/setup/install.ab @@ -36,7 +36,11 @@ unsafe { not hasFailed("ruby -v") { let code = "require \"open-uri\"; open(\"{target}\", \"wb\") do |file|; file << open(\"{url}\").read; end" echo "Using ruby as a download method..." - $sudo ruby -e "{code}"$ + $sudo ruby -e "{code}"$ failed { + echo "Ruby failed to download amber." + echo "Please try again or use another download method." + $exit 1$ + } } not hasFailed("curl -v") { echo "Using curl as a download method..." diff --git a/setup/install.sh b/setup/install.sh index 3e4d82dd..add69b80 100755 --- a/setup/install.sh +++ b/setup/install.sh @@ -3,7 +3,6 @@ function hasFailed__18_v0 { ${command} > /dev/null 2>&1 __AMBER_STATUS=$?; if [ $__AMBER_STATUS != 0 ]; then -$(exit $__AMBER_STATUS) : fi; __AMBER_FUN_hasFailed18_v0=$(echo $__AMBER_STATUS '!=' 0 | bc -l | sed '/\./ s/\.\{0,1\}0\{1,\}$//'); @@ -16,14 +15,12 @@ __3_place="/opt/amber"; __AMBER_VAL_0=$(uname -s); __AMBER_STATUS=$?; if [ $__AMBER_STATUS != 0 ]; then -$(exit $__AMBER_STATUS) : fi; os=$(if [ $([ "_${__AMBER_VAL_0}" != "_Darwin" ]; echo $?) != 0 ]; then echo "macos"; else echo "linux"; fi); __AMBER_VAL_1=$(uname -m); __AMBER_STATUS=$?; if [ $__AMBER_STATUS != 0 ]; then -$(exit $__AMBER_STATUS) : fi; arch=$(if [ $([ "_${__AMBER_VAL_1}" != "_arm64" ]; echo $?) != 0 ]; then echo "aarch64"; else echo "x86_64"; fi); @@ -31,7 +28,6 @@ fi; test -d "${__3_place}" __AMBER_STATUS=$?; if [ $__AMBER_STATUS != 0 ]; then -$(exit $__AMBER_STATUS) : fi; if [ $(echo $__AMBER_STATUS '==' 0 | bc -l | sed '/\./ s/\.\{0,1\}0\{1,\}$//') != 0 ]; then @@ -42,37 +38,42 @@ fi; exit 0 __AMBER_STATUS=$?; if [ $__AMBER_STATUS != 0 ]; then -$(exit $__AMBER_STATUS) : fi fi; echo "Installing Amber"; hasFailed__18_v0 "ruby -v"; + __AMBER_FUN_hasFailed18_v0__36=${__AMBER_FUN_hasFailed18_v0}; hasFailed__18_v0 "curl -v"; + __AMBER_FUN_hasFailed18_v0__45=${__AMBER_FUN_hasFailed18_v0}; hasFailed__18_v0 "wget -V"; - if [ $(echo '!' ${__AMBER_FUN_hasFailed18_v0} | bc -l | sed '/\./ s/\.\{0,1\}0\{1,\}$//') != 0 ]; then + __AMBER_FUN_hasFailed18_v0__49=${__AMBER_FUN_hasFailed18_v0}; + if [ $(echo '!' ${__AMBER_FUN_hasFailed18_v0__36} | bc -l | sed '/\./ s/\.\{0,1\}0\{1,\}$//') != 0 ]; then code="require \"open-uri\"; open(\"${__1_target}\", \"wb\") do |file|; file << open(\"${url}\").read; end"; echo "Using ruby as a download method..."; sudo ruby -e "${code}" __AMBER_STATUS=$?; if [ $__AMBER_STATUS != 0 ]; then -$(exit $__AMBER_STATUS) + echo "Ruby failed to download amber."; + echo "Please try again or use another download method."; + exit 1 +__AMBER_STATUS=$?; +if [ $__AMBER_STATUS != 0 ]; then : fi -elif [ $(echo '!' ${__AMBER_FUN_hasFailed18_v0} | bc -l | sed '/\./ s/\.\{0,1\}0\{1,\}$//') != 0 ]; then +fi +elif [ $(echo '!' ${__AMBER_FUN_hasFailed18_v0__45} | bc -l | sed '/\./ s/\.\{0,1\}0\{1,\}$//') != 0 ]; then echo "Using curl as a download method..."; curl -o "${__1_target}" "${url}" __AMBER_STATUS=$?; if [ $__AMBER_STATUS != 0 ]; then -$(exit $__AMBER_STATUS) : fi -elif [ $(echo '!' ${__AMBER_FUN_hasFailed18_v0} | bc -l | sed '/\./ s/\.\{0,1\}0\{1,\}$//') != 0 ]; then +elif [ $(echo '!' ${__AMBER_FUN_hasFailed18_v0__49} | bc -l | sed '/\./ s/\.\{0,1\}0\{1,\}$//') != 0 ]; then echo "Using wget as a download method..."; wget -O "${__1_target}" "${url}" __AMBER_STATUS=$?; if [ $__AMBER_STATUS != 0 ]; then -$(exit $__AMBER_STATUS) : fi else @@ -81,32 +82,27 @@ else exit 1 __AMBER_STATUS=$?; if [ $__AMBER_STATUS != 0 ]; then -$(exit $__AMBER_STATUS) : fi fi; sudo mkdir "${__3_place}" > /dev/null __AMBER_STATUS=$?; if [ $__AMBER_STATUS != 0 ]; then -$(exit $__AMBER_STATUS) : fi; sudo mv "${__1_target}" "${__3_place}/${__1_target}" __AMBER_STATUS=$?; if [ $__AMBER_STATUS != 0 ]; then -$(exit $__AMBER_STATUS) : fi; sudo chmod +x "${__3_place}/${__1_target}" __AMBER_STATUS=$?; if [ $__AMBER_STATUS != 0 ]; then -$(exit $__AMBER_STATUS) : fi; sudo ln -s "${__3_place}/${__1_target}" "/usr/local/bin/${__1_target}" __AMBER_STATUS=$?; if [ $__AMBER_STATUS != 0 ]; then -$(exit $__AMBER_STATUS) : fi; echo "Amber has been installed successfully. 🎉" \ No newline at end of file diff --git a/setup/uninstall.sh b/setup/uninstall.sh index 3374e2f8..479838f2 100755 --- a/setup/uninstall.sh +++ b/setup/uninstall.sh @@ -2,26 +2,22 @@ test -d "${place}" > /dev/null __AMBER_STATUS=$?; if [ $__AMBER_STATUS != 0 ]; then -$(exit $__AMBER_STATUS) : fi; __AMBER_VAL_0=$(echo $?); __AMBER_STATUS=$?; if [ $__AMBER_STATUS != 0 ]; then -$(exit $__AMBER_STATUS) : fi; if [ $([ "_${__AMBER_VAL_0}" != "_0" ]; echo $?) != 0 ]; then sudo rm -rf "${place}" __AMBER_STATUS=$?; if [ $__AMBER_STATUS != 0 ]; then -$(exit $__AMBER_STATUS) : fi; sudo rm "/usr/local/bin/amber" __AMBER_STATUS=$?; if [ $__AMBER_STATUS != 0 ]; then -$(exit $__AMBER_STATUS) : fi; echo "Uninstalled Amber successfully 🎉" diff --git a/src/modules/condition/failed.rs b/src/modules/condition/failed.rs index d5a74893..252a728e 100644 --- a/src/modules/condition/failed.rs +++ b/src/modules/condition/failed.rs @@ -26,39 +26,42 @@ impl SyntaxModule for Failed { fn parse(&mut self, meta: &mut ParserMetadata) -> SyntaxResult { let tok = meta.get_current_token(); - if meta.context.is_unsafe_ctx { - self.is_main = meta.context.is_main_ctx; - self.is_parsed = true; - return Ok(()); - } if let Ok(_) = token(meta, "?") { - if !meta.context.is_fun_ctx && !meta.context.is_main_ctx { + 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") } self.is_question_mark = true; } else { - token(meta, "failed")?; - match token(meta, "{") { - Ok(_) => { - let tok = meta.get_current_token(); - syntax(meta, &mut *self.block)?; - if self.block.is_empty() { - let message = Message::new_warn_at_token(meta, tok) - .message("Empty failed block") - .comment("You should use 'unsafe' modifier to run commands without handling errors"); - meta.messages.push(message); + match token(meta, "failed") { + Ok(_) => match token(meta, "{") { + Ok(_) => { + let tok = meta.get_current_token(); + syntax(meta, &mut *self.block)?; + if self.block.is_empty() { + let message = Message::new_warn_at_token(meta, tok) + .message("Empty failed block") + .comment("You should use 'unsafe' modifier to run commands without handling errors"); + meta.messages.push(message); + } + token(meta, "}")?; + }, + Err(_) => { + match token(meta, ":") { + Ok(_) => { + let mut statement = Statement::new(); + syntax(meta, &mut statement)?; + self.block.push_statement(statement); + }, + Err(_) => return error!(meta, tok, "Failed expression must be followed by a block or statement") + } } - token(meta, "}")?; }, - Err(_) => { - match token(meta, ":") { - Ok(_) => { - let mut statement = Statement::new(); - syntax(meta, &mut statement)?; - self.block.push_statement(statement); - }, - Err(_) => return error!(meta, tok, "Failed expression must be followed by a block or statement") - } + Err(_) => if meta.context.is_unsafe_ctx { + self.is_main = meta.context.is_main_ctx; + self.is_parsed = true; + return Ok(()); + } else { + return error!(meta, tok, "Failed expression must be followed by a block or statement") } } } @@ -73,8 +76,8 @@ impl TranslateModule for Failed { if self.is_parsed { let block = self.block.translate(meta); let ret = self.is_main - .then(|| "exit $?") - .unwrap_or("return $?"); + .then(|| "exit $__AMBER_STATUS") + .unwrap_or("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 @@ -88,7 +91,6 @@ impl TranslateModule for Failed { "__AMBER_STATUS=$?;", "if [ $__AMBER_STATUS != 0 ]; then", &clear_return, - &format!("$(exit $__AMBER_STATUS)"), ret, "fi" ].join("\n") @@ -96,7 +98,6 @@ impl TranslateModule for Failed { vec![ "__AMBER_STATUS=$?;", "if [ $__AMBER_STATUS != 0 ]; then", - &format!("$(exit $__AMBER_STATUS)"), &block, "fi" ].join("\n") diff --git a/src/modules/function/invocation.rs b/src/modules/function/invocation.rs index dbd06812..c275b403 100644 --- a/src/modules/function/invocation.rs +++ b/src/modules/function/invocation.rs @@ -16,6 +16,7 @@ pub struct FunctionInvocation { kind: Type, variant_id: usize, id: usize, + line: usize, failed: Failed, is_failable: bool } @@ -37,6 +38,7 @@ impl SyntaxModule for FunctionInvocation { kind: Type::Null, variant_id: 0, id: 0, + line: 0, failed: Failed::new(), is_failable: false } @@ -45,6 +47,9 @@ impl SyntaxModule for FunctionInvocation { fn parse(&mut self, meta: &mut ParserMetadata) -> SyntaxResult { // Get the function name let tok = meta.get_current_token(); + if let Some(ref tok) = tok { + self.line = tok.pos.0; + } self.name = variable(meta, variable_name_extensions())?; // Get the arguments token(meta, "(")?; @@ -89,6 +94,17 @@ impl SyntaxModule for FunctionInvocation { } } +impl FunctionInvocation { + fn get_variable(&self, meta: &mut TranslateMetadata, name: &str) -> String { + if matches!(self.kind, Type::Array(_)) { + let quote = meta.gen_quote(); + format!("{quote}${{{name}[@]}}{quote}") + } else { + format!("${{{name}}}") + } + } +} + impl TranslateModule for FunctionInvocation { fn translate(&self, meta: &mut TranslateMetadata) -> String { let name = format!("{}__{}_v{}", self.name, self.id, self.variant_id); @@ -105,15 +121,20 @@ impl TranslateModule for FunctionInvocation { } }).collect::>().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)); if self.is_failable { let failed = self.failed.translate(meta); meta.stmt_queue.push_back(failed); } - if matches!(self.kind, Type::Array(_)) { - let quote = meta.gen_quote(); - format!("{quote}${{__AMBER_FUN_{}{}_v{}[@]}}{quote}", self.name, self.id, self.variant_id) - } else { - format!("${{__AMBER_FUN_{}{}_v{}}}", self.name, self.id, self.variant_id) - } + 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) + } else { + invocation_return + }) + ); + invocation_instance } } \ No newline at end of file