Skip to content

Commit

Permalink
feat: exit as builtin function (#402)
Browse files Browse the repository at this point in the history
* feat: `exit` as builtin function

* feat: optional exit code

* fix: clippy issue
  • Loading branch information
MuhamedMagdi authored Sep 23, 2024
1 parent 2290bf3 commit eb16c99
Show file tree
Hide file tree
Showing 9 changed files with 95 additions and 15 deletions.
58 changes: 58 additions & 0 deletions src/modules/builtin/exit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
use heraclitus_compiler::prelude::*;
use crate::modules::expression::expr::Expr;
use crate::docs::module::DocumentationModule;
use crate::modules::types::{Type, Typed};
use crate::translate::module::TranslateModule;
use crate::utils::{ParserMetadata, TranslateMetadata};

#[derive(Debug, Clone)]
pub struct Exit {
code: Option<Expr>
}

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

fn new() -> Self {
Exit {
code: None
}
}

fn parse(&mut self, meta: &mut ParserMetadata) -> SyntaxResult {
token(meta, "exit")?;

let mut code_expr = Expr::new();
if syntax(meta, &mut code_expr).is_ok() {
self.code = Some(code_expr);
}

if let Some(ref code_expr) = self.code {
let code_type = code_expr.get_type();
if code_type != Type::Num {
let position = code_expr.get_position(meta);
return error_pos!(meta, position => {
message: "Builtin function `exit` can only be used with values of type Num",
comment: format!("Given type: {}, expected type: {}", code_type, Type::Num)
});
}
}

Ok(())
}
}

impl TranslateModule for Exit {
fn translate(&self, meta: &mut TranslateMetadata) -> String {
let code = self.code.as_ref()
.map(|expr| expr.translate(meta))
.unwrap_or_else(|| "0".to_string());
format!("exit {}", code)
}
}

impl DocumentationModule for Exit {
fn document(&self, _meta: &ParserMetadata) -> String {
"".to_string()
}
}
1 change: 1 addition & 0 deletions src/modules/builtin/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ pub mod cd;
pub mod echo;
pub mod mv;
pub mod nameof;
pub mod exit;
6 changes: 4 additions & 2 deletions src/modules/statement/stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ use crate::modules::main::Main;
use crate::modules::builtin::{
echo::Echo,
mv::Mv,
cd::Cd
cd::Cd,
exit::Exit
};
use super::comment_doc::CommentDoc;
use super::comment::Comment;
Expand Down Expand Up @@ -66,6 +67,7 @@ pub enum StatementType {
Cd(Cd),
Echo(Echo),
Mv(Mv),
Exit(Exit),
CommandModifier(CommandModifier),
Comment(Comment),
CommentDoc(CommentDoc)
Expand Down Expand Up @@ -93,7 +95,7 @@ impl Statement {
ShorthandMul, ShorthandDiv,
ShorthandModulo,
// Command
CommandModifier, Echo, Mv, Cd,
CommandModifier, Echo, Mv, Cd, Exit,
// Comment doc
CommentDoc, Comment,
// Expression
Expand Down
2 changes: 1 addition & 1 deletion src/modules/variable/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pub fn variable_name_keywords() -> Vec<&'static str> {
// Command Modifiers
"silent", "unsafe",
// Misc
"echo", "status", "nameof", "mv", "cd"
"echo", "status", "nameof", "mv", "cd", "exit"
]
}

Expand Down
5 changes: 0 additions & 5 deletions src/std/env.ab
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,6 @@ pub fun has_failed(command: Text): Bool {
return status != 0
}

/// Closes the script.
pub fun exit(code: Num): Null {
unsafe $exit "{code}"$
}

/// Checks if the script is running with a user with root permission.
pub fun is_root(): Bool {
if unsafe $id -u$ == "0" {
Expand Down
28 changes: 25 additions & 3 deletions src/tests/extra.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ fn http_server() {
}

#[test]
fn exit() {
let code = fs::read_to_string("src/tests/stdlib/no_output/exit.ab")
.expect("Failed to open stdlib/no_output/exit.ab test file");
fn exit_with_code() {
let code = fs::read_to_string("src/tests/validity/no_output/exit_with_code.ab")
.expect("Failed to open validity/no_output/exit_with_code.ab test file");

let code = compile_code(code);
let mut cmd = Command::new("bash")
Expand All @@ -38,6 +38,28 @@ fn exit() {
);
}

#[test]
fn exit_with_no_code() {
let code = fs::read_to_string("src/tests/validity/no_output/exit_with_no_code.ab")
.expect("Failed to open validity/no_output/exit_with_no_code.ab test file");

let code = compile_code(code);
let mut cmd = Command::new("bash")
.arg("-c")
.arg(code)
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn()
.expect("Couldn't spawn bash");

assert_eq!(
cmd.wait()
.expect("Couldn't wait for bash to execute")
.code(),
Some(0)
);
}

#[test]
fn download() {
let server = std::thread::spawn(http_server);
Expand Down
4 changes: 0 additions & 4 deletions src/tests/stdlib/no_output/exit.ab

This file was deleted.

3 changes: 3 additions & 0 deletions src/tests/validity/no_output/exit_with_code.ab
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
main {
exit 37
}
3 changes: 3 additions & 0 deletions src/tests/validity/no_output/exit_with_no_code.ab
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
main {
exit
}

0 comments on commit eb16c99

Please sign in to comment.