Skip to content

Commit

Permalink
builtin updates
Browse files Browse the repository at this point in the history
  • Loading branch information
mikkeldamsgaard committed May 26, 2021
1 parent 2d621b5 commit 360e9f3
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 33 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ Prints to standard out
```javascript
print(1,2,"abc") # prints 1 2 abc
```
prints arguments seperated with a space
prints arguments separated with a space
### println
Identical to print, but add a newline
### len
Expand All @@ -317,7 +317,7 @@ Converts a string to a float
is_float, is_string, is_list, is_table, is_process_result
Returns 1 if the argument is the corresponding type
### process result extracts
```javascript
```bash
stdout(proc_res) # stdout of the process as a string, throws error if the output is not a valid utf8 string
stderr(proc_res) # stderr of the process as a string, throws error if the output is not a valid utf8 string
exit_code(proc_res) # exit code of the process
Expand Down
5 changes: 4 additions & 1 deletion docs/_config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,7 @@ compress_html:
envs: development

encoding: "utf-8"
markdown_ext: "markdown,mkdown,mkdn,mkd,md"
markdown_ext: "markdown,mkdown,mkdn,mkd,md"

kramdown:
auto_ids: true
80 changes: 80 additions & 0 deletions docs/book/builtins.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,83 @@ title: Built-in functions
permalink: /book/builtins
toc: true
---
There are some builtin functions in addition to the type specific functions described in the
[Types chapter](/book/types)

## Output
These functions control output from the script

### print
The function takes an arbitrary number of arguments and outputs the result of to_str of each
argument separated by a space to standard out.
```javascript
print(1,2,[1]) # prints "1 2 [1]" to stdout
```

### println
Identical to print, except it adds a newline character to the output

### eprint
Identical to print, except it outputs to standard error

### eprintln
Identical to eprint, except it adds a newline character to the output

## Type functions
These functions help convert between and identify value types

### to_str
The to_str converts its one argument into a string representation. For strings,
it is the identity function. For Numbers, Lists, Tables and Process Results it is a JSON representation of the
structure. For functions, it will return "<<function>>"

### is_
The is_ functions are used to query the type of a value.
- is_number
- is_string
- is_list
- is_table
- is_process_result
- is_function

### parse_number
Parses a number from a string
```bash
parse_number("1.42") # Returns the number value 1.42
```

## Shell functions
These functions interacts with the execution environment

### include
This function evaluates the provided script in the current scope. The argument is a string that will
be resolved to a file name and that file will be loaded and interpreted in the current scope.

### args
Zero argument function that returns the arguments to the script as a list. This function returns a copy of the formal
arguments to the script. The first element is the script itself.

When being run with stdin as source, the list will be empty.

### cwd
Zero argument function that return the current working directory

### path_of_script
Zero argument function that returns the path of the current executing script.
It returns the current working directory when
input is received on stdin.

### exit
Exits with the given exit code
```javascript
exit(0)
```

### lookup_env_var
Looks up an environment variable.
```javascript
lookup_env_var("PATH") # returns the value of the environment variable PATH (corresponds to $PATH)
```

The function is similar to the `$VAR` notation but allows for dynamic variable lookup, as in
`lookup_env_var("VA"+"R")`
69 changes: 40 additions & 29 deletions src/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,21 @@ pub fn add_builtin_to_closure(closure: &mut Closure) {
Ok(NoValue(String::from("println")))
}),
},
Builtin {
name: "eprint".to_owned(),
function: Rc::new(|args, _spans, _closure, slash| {
eprint(args, slash);
Ok(NoValue(String::from("eprint")))
}),
},
Builtin {
name: "eprintln".to_owned(),
function: Rc::new(|args, _spans, _closure, slash| {
eprint(args, slash);
slash.write_stderr("\n");
Ok(NoValue(String::from("eprintln")))
}),
},
Builtin {
name: "len".to_owned(),
function: Rc::new(|args, spans, _closure, _slash| {
Expand All @@ -78,7 +93,7 @@ pub fn add_builtin_to_closure(closure: &mut Closure) {
}),
},
Builtin {
name: "parse_float".to_owned(),
name: "parse_number".to_owned(),
function: Rc::new(|args, spans, _closure, _slash| {
verify_formal_args(&args, &spans, 1)?;
if let Value::String(s) = &args[0] {
Expand All @@ -92,58 +107,45 @@ pub fn add_builtin_to_closure(closure: &mut Closure) {
}),
},
Builtin {
name: "is_float".to_owned(),
name: "is_number".to_owned(),
function: Rc::new(|args, spans, _closure, _slash| {
verify_formal_args(&args, &spans, 1)?;
if let Value::Number(_) = &args[0] {
Ok(FunctionCallResult::Value(Value::Number(1.0)))
} else {
Ok(FunctionCallResult::Value(Value::Number(0.0)))
}
Ok(FunctionCallResult::Value(Value::Number(if let Value::Number(_) = &args[0] { 1.0 } else { 0.0 })))
}),
},
Builtin {
name: "is_list".to_owned(),
function: Rc::new(|args, spans, _closure, _slash| {
verify_formal_args(&args, &spans, 1)?;
if let Value::List(_) = &args[0] {
Ok(FunctionCallResult::Value(Value::Number(1.0)))
} else {
Ok(FunctionCallResult::Value(Value::Number(0.0)))
}
Ok(FunctionCallResult::Value(Value::Number(if let Value::List(_) = &args[0] { 1.0 } else { 0.0 })))
}),
},
Builtin {
name: "is_table".to_owned(),
function: Rc::new(|args, spans, _closure, _slash| {
verify_formal_args(&args, &spans, 1)?;
if let Value::Table(_) = &args[0] {
Ok(FunctionCallResult::Value(Value::Number(1.0)))
} else {
Ok(FunctionCallResult::Value(Value::Number(0.0)))
}
Ok(FunctionCallResult::Value(Value::Number(if let Value::Table(_) = &args[0] { 1.0 } else { 0.0 })))
}),
},
Builtin {
name: "is_string".to_owned(),
function: Rc::new(|args, spans, _closure, _slash| {
verify_formal_args(&args, &spans, 1)?;
if let Value::String(_) = &args[0] {
Ok(FunctionCallResult::Value(Value::Number(1.0)))
} else {
Ok(FunctionCallResult::Value(Value::Number(0.0)))
}
Ok(FunctionCallResult::Value(Value::Number(if let Value::String(_) = &args[0] { 1.0 } else { 0.0 })))
}),
},
Builtin {
name: "is_process_result".to_owned(),
function: Rc::new(|args, spans, _closure, _slash| {
verify_formal_args(&args, &spans, 1)?;
if let Value::ProcessResult(_, _, _) = &args[0] {
Ok(FunctionCallResult::Value(Value::Number(1.0)))
} else {
Ok(FunctionCallResult::Value(Value::Number(0.0)))
}
Ok(FunctionCallResult::Value(Value::Number(if let Value::ProcessResult(_, _, _) = &args[0] { 1.0 } else { 0.0 })))
}),
},
Builtin {
name: "is_function".to_owned(),
function: Rc::new(|args, spans, _closure, _slash| {
verify_formal_args(&args, &spans, 1)?;
Ok(FunctionCallResult::Value(Value::Number(if let Value::Function(_) = &args[0] { 1.0 } else { 0.0 })))
}),
},
Builtin {
Expand Down Expand Up @@ -335,10 +337,19 @@ pub fn function_call(pair: Pair<Rule>, closure: &mut Closure, slash: &Slash) ->
function.invoke(args,func_spans,closure, slash)
}

fn print(args: Vec<Value>, slash: &Slash) {
fn format_args(args: Vec<Value>) -> String {
if args.is_empty() { return "".to_owned()}
let mut s = String::new();
args.iter().for_each(|a| s.push_str(&format!(" {}", &a.to_string())));
slash.write_stdout(&s[1..]);
return s[1..].to_owned();
}

fn print(args: Vec<Value>, slash: &Slash) {
slash.write_stdout(&format_args(args));
}

fn eprint(args: Vec<Value>, slash: &Slash) {
slash.write_stderr(&format_args(args));
}

fn verify_formal_args(args: &Vec<Value>, spans: &Vec<Span>, num: usize) -> Result<(), SlashError> {
Expand Down
4 changes: 4 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,10 @@ impl Slash<'_> {
self.stdout.borrow_mut().write_fmt(format_args!("{}", msg)).expect("Failed to write to stdout");
}

pub fn write_stderr(&self, msg: &str) {
self.stderr.borrow_mut().write_fmt(format_args!("{}", msg)).expect("Failed to write to stdout");
}

fn create_cmd(&self, ast: Pair<Rule>, closure: &mut Closure) -> Result<duct::Expression, SlashError> {
//println!("to_cmd ast={:?}", ast);
let mut pairs = ast.into_inner();
Expand Down
42 changes: 42 additions & 0 deletions tests/function_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,45 @@ fn test_fun() {
print(add(1,2)) # 3
"##,"3");
}

#[test]
fn test_builtin() {
common::run(r##"
print()
"##,"");

common::run(r##"
print(1,2,[1]) # prints "1 2 [1]" to stdout
"##,"1 2 [1]");

common::run(r##"
if is_number(2) { print("pass") }
if is_number("1") { print("fail") }
"##,"pass");

common::run(r##"
if is_string("2") { print("pass") }
if is_string(1) { print("fail") }
"##,"pass");

common::run(r##"
if is_list([]) { print("pass") }
if is_list("1") { print("fail") }
"##,"pass");

common::run(r##"
if is_table({}) { print("pass") }
if is_table("1") { print("fail") }
"##,"pass");

common::run(r##"
if is_function(|| {}) { print("pass") }
if is_function("1") { print("fail") }
"##,"pass");

common::run(r##"
echo $> pr
if is_process_result(pr) { print("pass") }
if is_process_result("1") { print("fail") }
"##,"pass");
}
2 changes: 1 addition & 1 deletion tests/testfiles/sub/print_arg.sl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!target/debug/slash
let args = args()

print(args[parse_float(args[1])])
print(args[parse_number(args[1])])

0 comments on commit 360e9f3

Please sign in to comment.