Ability to write standard SDK commands with duckscript #50

This commit is contained in:
sagie gur ari 2020-01-10 15:02:38 +00:00
parent fc3018b325
commit b057b8ba76
25 changed files with 255 additions and 19 deletions

View file

@ -2,6 +2,8 @@
### v0.1.6
* Ability to write standard SDK commands with duckscript #50
* New array_is_empty command.
* assert commands should return 'crash' and stop execution #52
### v0.1.5 (2020-01-09)

View file

@ -164,7 +164,7 @@
<span class="ident">_output_variable</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">String</span><span class="op">&gt;</span>,
<span class="ident">_instructions</span>: <span class="kw-2">&amp;</span><span class="ident">Vec</span><span class="op">&lt;</span><span class="ident">Instruction</span><span class="op">&gt;</span>,
<span class="ident">commands</span>: <span class="kw-2">&amp;</span><span class="kw-2">mut</span> <span class="ident">Commands</span>,
<span class="ident">_test_setline</span>: <span class="ident">usize</span>,
<span class="ident">_line</span>: <span class="ident">usize</span>,
) <span class="op">-&gt;</span> <span class="ident">CommandResult</span> {
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">all_arguments</span> <span class="op">=</span> <span class="macro">vec</span><span class="macro">!</span>[];
<span class="ident">all_arguments</span>.<span class="ident">append</span>(<span class="kw-2">&amp;</span><span class="kw-2">mut</span> <span class="self">self</span>.<span class="ident">arguments</span>.<span class="ident">clone</span>());
@ -217,7 +217,7 @@
<span class="ident">_output_variable</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">String</span><span class="op">&gt;</span>,
<span class="ident">_instructions</span>: <span class="kw-2">&amp;</span><span class="ident">Vec</span><span class="op">&lt;</span><span class="ident">Instruction</span><span class="op">&gt;</span>,
<span class="ident">commands</span>: <span class="kw-2">&amp;</span><span class="kw-2">mut</span> <span class="ident">Commands</span>,
<span class="ident">_test_setline</span>: <span class="ident">usize</span>,
<span class="ident">_line</span>: <span class="ident">usize</span>,
) <span class="op">-&gt;</span> <span class="ident">CommandResult</span> {
<span class="kw">if</span> <span class="ident">arguments</span>.<span class="ident">len</span>() <span class="op">&lt;</span> <span class="number">2</span> {
<span class="ident">CommandResult</span>::<span class="ident">Error</span>(<span class="string">&quot;Invalid alias provided.&quot;</span>.<span class="ident">to_string</span>())

View file

@ -88,7 +88,7 @@
<span class="ident">_output_variable</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">String</span><span class="op">&gt;</span>,
<span class="ident">_instructions</span>: <span class="kw-2">&amp;</span><span class="ident">Vec</span><span class="op">&lt;</span><span class="ident">Instruction</span><span class="op">&gt;</span>,
<span class="ident">commands</span>: <span class="kw-2">&amp;</span><span class="kw-2">mut</span> <span class="ident">Commands</span>,
<span class="ident">_test_setline</span>: <span class="ident">usize</span>,
<span class="ident">_line</span>: <span class="ident">usize</span>,
) <span class="op">-&gt;</span> <span class="ident">CommandResult</span> {
<span class="ident">eval</span>::<span class="ident">eval</span>(<span class="kw-2">&amp;</span><span class="ident">arguments</span>, <span class="ident">state</span>, <span class="ident">variables</span>, <span class="ident">commands</span>)
}

View file

@ -94,7 +94,7 @@
<span class="ident">_output_variable</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">String</span><span class="op">&gt;</span>,
<span class="ident">_instructions</span>: <span class="kw-2">&amp;</span><span class="ident">Vec</span><span class="op">&lt;</span><span class="ident">Instruction</span><span class="op">&gt;</span>,
<span class="ident">_commands</span>: <span class="kw-2">&amp;</span><span class="kw-2">mut</span> <span class="ident">Commands</span>,
<span class="ident">_test_setline</span>: <span class="ident">usize</span>,
<span class="ident">_line</span>: <span class="ident">usize</span>,
) <span class="op">-&gt;</span> <span class="ident">CommandResult</span> {
<span class="kw">if</span> <span class="ident">arguments</span>.<span class="ident">is_empty</span>() {
<span class="ident">CommandResult</span>::<span class="ident">Error</span>(<span class="string">&quot;Variable name not provided.&quot;</span>.<span class="ident">to_string</span>())

View file

@ -127,7 +127,7 @@
<span class="ident">_output_variable</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">String</span><span class="op">&gt;</span>,
<span class="ident">_instructions</span>: <span class="kw-2">&amp;</span><span class="ident">Vec</span><span class="op">&lt;</span><span class="ident">Instruction</span><span class="op">&gt;</span>,
<span class="ident">commands</span>: <span class="kw-2">&amp;</span><span class="kw-2">mut</span> <span class="ident">Commands</span>,
<span class="ident">_test_setline</span>: <span class="ident">usize</span>,
<span class="ident">_line</span>: <span class="ident">usize</span>,
) <span class="op">-&gt;</span> <span class="ident">CommandResult</span> {
<span class="kw">if</span> <span class="ident">arguments</span>.<span class="ident">is_empty</span>() {
<span class="ident">print_help</span>(<span class="self">self</span>.<span class="ident">help</span>(), <span class="kw-2">&amp;</span><span class="self">self</span>.<span class="ident">name</span>())

View file

@ -107,7 +107,7 @@
<span class="ident">_output_variable</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">String</span><span class="op">&gt;</span>,
<span class="ident">_instructions</span>: <span class="kw-2">&amp;</span><span class="ident">Vec</span><span class="op">&lt;</span><span class="ident">Instruction</span><span class="op">&gt;</span>,
<span class="ident">commands</span>: <span class="kw-2">&amp;</span><span class="kw-2">mut</span> <span class="ident">Commands</span>,
<span class="ident">_test_setline</span>: <span class="ident">usize</span>,
<span class="ident">_line</span>: <span class="ident">usize</span>,
) <span class="op">-&gt;</span> <span class="ident">CommandResult</span> {
<span class="kw">if</span> <span class="ident">arguments</span>.<span class="ident">len</span>() <span class="op">!=</span> <span class="number">1</span> {
<span class="ident">CommandResult</span>::<span class="ident">Error</span>(<span class="string">&quot;Invalid alias name provided.&quot;</span>.<span class="ident">to_string</span>())

View file

@ -15,6 +15,7 @@
* [std::ShowCommandDocumentation (man)](#std__ShowCommandDocumentation)
* [std::Unalias (unalias)](#std__Unalias)
* [std::collections::Array (array)](#std__collections__Array)
* [std::collections::ArrayIsEmpty (array_is_empty)](#std__collections__ArrayIsEmpty)
* [std::collections::ArrayLength (array_length, arrlen)](#std__collections__ArrayLength)
* [std::collections::Range (range)](#std__collections__Range)
* [std::env::GetVar (get_env)](#std__env__GetVar)
@ -713,6 +714,20 @@ release ${handle}
#### Aliases:
array
<a name="std__collections__ArrayIsEmpty"></a>
## std::collections::ArrayIsEmpty
Alias for:
```sh
__length = array_length ${argument1}
equals 0 ${__length}
```
#### Aliases:
array_is_empty
<a name="std__collections__ArrayLength"></a>
## std::collections::ArrayLength
```sh
@ -1955,7 +1970,7 @@ assert yes
value = set "some text"
assert ${value}
# error conditions
# error conditions (each one will break the execution)
assert
assert false
assert 0
@ -1994,7 +2009,7 @@ assert_eq false false
value = set "some text"
assert_eq ${value} "some text"
# error conditions
# error conditions (each one will break the execution)
assert_eq 1 2
assert_eq 1 2 "This is my error message"
```

View file

@ -7,7 +7,8 @@
#[path = "./instruction_test.rs"]
mod instruction_test;
trait InstructionOperations {
/// Defines common instruction capabilities
pub trait InstructionOperations {
/// Returns true if this instruction has some actionable command to run
fn is_actionable(&self) -> bool;
}

View file

@ -121,6 +121,7 @@
//!
pub(crate) mod sdk;
mod types;
mod utils;
#[cfg(test)]

View file

@ -43,7 +43,7 @@ fn create_alias_command(
_output_variable: Option<String>,
_instructions: &Vec<Instruction>,
commands: &mut Commands,
_test_setline: usize,
_line: usize,
) -> CommandResult {
let mut all_arguments = vec![];
all_arguments.append(&mut self.arguments.clone());
@ -96,7 +96,7 @@ impl Command for CommandImpl {
_output_variable: Option<String>,
_instructions: &Vec<Instruction>,
commands: &mut Commands,
_test_setline: usize,
_line: usize,
) -> CommandResult {
if arguments.len() < 2 {
CommandResult::Error("Invalid alias provided.".to_string())

View file

@ -0,0 +1,17 @@
use crate::types::command::create_alias_command;
use crate::utils::pckg;
use duckscript::types::command::Command;
#[cfg(test)]
#[path = "./mod_test.rs"]
mod mod_test;
pub(crate) fn create(package: &str) -> Box<dyn Command> {
let name = pckg::concat(package, "ArrayIsEmpty");
Box::new(create_alias_command(
name,
vec!["array_is_empty".to_string()],
include_str!("script.ds").to_string(),
1,
))
}

View file

@ -0,0 +1,44 @@
use super::*;
use crate::sdk::std::collections::{array, array_length};
use crate::sdk::std::string::equals;
use crate::test;
use crate::test::CommandValidation;
#[test]
fn common_functions() {
test::test_common_command_functions(create(""));
}
#[test]
fn run_not_empty() {
test::run_script_and_validate(
vec![
create(""),
array::create(""),
array_length::create(""),
equals::create(""),
],
r#"
values = array a b c
out = array_is_empty ${values}
"#,
CommandValidation::Match("out".to_string(), "false".to_string()),
);
}
#[test]
fn run_empty() {
test::run_script_and_validate(
vec![
create(""),
array::create(""),
array_length::create(""),
equals::create(""),
],
r#"
values = array
out = array_is_empty ${values}
"#,
CommandValidation::Match("out".to_string(), "true".to_string()),
);
}

View file

@ -0,0 +1,2 @@
__length = array_length ${argument1}
equals 0 ${__length}

View file

@ -52,7 +52,9 @@ impl Command for CommandImpl {
StateValue::List(list) => CommandResult::Continue(Some(list.len().to_string())),
_ => CommandResult::Error("Invalid handle provided.".to_string()),
},
None => CommandResult::Error("Array not found.".to_string()),
None => CommandResult::Error(
format!("Array for handle: {} not found.", key).to_string(),
),
}
}
}

View file

@ -1,5 +1,6 @@
pub(crate) mod array;
mod array_length;
mod array_is_empty;
pub(crate) mod array_length;
mod range;
use crate::utils::pckg;
@ -12,6 +13,7 @@ pub(crate) fn load(commands: &mut Commands, parent: &str) -> Result<(), ScriptEr
let package = pckg::concat(parent, PACKAGE);
commands.set(array::create(&package))?;
commands.set(array_is_empty::create(&package))?;
commands.set(array_length::create(&package))?;
commands.set(range::create(&package))?;

View file

@ -37,7 +37,7 @@ impl Command for CommandImpl {
_output_variable: Option<String>,
_instructions: &Vec<Instruction>,
commands: &mut Commands,
_test_setline: usize,
_line: usize,
) -> CommandResult {
eval::eval(&arguments, state, variables, commands)
}

View file

@ -37,7 +37,7 @@ impl Command for CommandImpl {
_output_variable: Option<String>,
_instructions: &Vec<Instruction>,
_commands: &mut Commands,
_test_setline: usize,
_line: usize,
) -> CommandResult {
if arguments.is_empty() {
CommandResult::Error("Variable name not provided.".to_string())

View file

@ -47,7 +47,7 @@ impl Command for CommandImpl {
_output_variable: Option<String>,
_instructions: &Vec<Instruction>,
commands: &mut Commands,
_test_setline: usize,
_line: usize,
) -> CommandResult {
if arguments.is_empty() {
print_help(self.help(), &self.name())

View file

@ -19,7 +19,7 @@ mod process;
mod read;
mod release;
mod set;
mod string;
pub(crate) mod string;
mod test;
mod thread;
mod unalias;

View file

@ -1,6 +1,6 @@
mod contains;
mod ends_with;
mod equals;
pub(crate) mod equals;
mod indexof;
mod is_empty;
mod last_indexof;

View file

@ -39,7 +39,7 @@ impl Command for CommandImpl {
_output_variable: Option<String>,
_instructions: &Vec<Instruction>,
commands: &mut Commands,
_test_setline: usize,
_line: usize,
) -> CommandResult {
if arguments.len() != 1 {
CommandResult::Error("Invalid alias name provided.".to_string())

View file

@ -123,6 +123,8 @@ impl Command for OnErrorCommand {
_commands: &mut Commands,
_line: usize,
) -> CommandResult {
println!("on error: {:#?}", &arguments);
let mut index = 0;
for argument in arguments {
index = index + 1;

View file

@ -0,0 +1,146 @@
use duckscript::types::command::{Command, CommandResult, Commands};
use duckscript::types::instruction::{Instruction, InstructionType};
use duckscript::types::runtime::StateValue;
use duckscript::{parser, runner};
use std::collections::HashMap;
#[cfg(test)]
#[path = "./command_test.rs"]
mod command_test;
pub(crate) struct AliasCommand {
name: String,
aliases: Vec<String>,
raw_command: String,
arguments_amount: usize,
}
impl Command for AliasCommand {
fn name(&self) -> String {
self.name.clone()
}
fn aliases(&self) -> Vec<String> {
self.aliases.clone()
}
fn help(&self) -> String {
format!(
r#"
Alias for:
```sh
{}
```
"#,
&self.raw_command
)
.to_string()
}
fn requires_context(&self) -> bool {
true
}
fn run_with_context(
&self,
arguments: Vec<String>,
state: &mut HashMap<String, StateValue>,
variables: &mut HashMap<String, String>,
_output_variable: Option<String>,
_instructions: &Vec<Instruction>,
commands: &mut Commands,
_line: usize,
) -> CommandResult {
if arguments.len() != self.arguments_amount {
CommandResult::Error("Invalid arguments provided.".to_string())
} else {
// define function arguments
if !arguments.is_empty() {
let mut index = 0;
for argument in arguments {
index = index + 1;
let mut key = "argument".to_string();
key.push_str(&index.to_string());
variables.insert(key, argument);
}
}
match parser::parse_text(&self.raw_command) {
Ok(instructions) => {
let mut line = 0;
let mut flow_output = None;
for instruction in instructions {
match instruction.instruction_type {
InstructionType::Script(ref script_instruction) => {
let (command_result, _) = runner::run_instruction(
commands,
variables,
state,
&vec![],
instruction.clone(),
line,
);
match command_result {
CommandResult::Exit(output) => {
return CommandResult::Exit(output);
}
CommandResult::Error(error) => {
return CommandResult::Error(error);
}
CommandResult::Crash(error) => {
return CommandResult::Crash(error);
}
CommandResult::GoTo(_, _) => {
return CommandResult::Error(
"goto result not supported in alias command flow."
.to_string(),
);
}
CommandResult::Continue(output) => {
flow_output = output.clone();
match script_instruction.output {
Some(ref output_variable) => {
match output {
Some(value) => variables
.insert(output_variable.to_string(), value),
None => variables.remove(output_variable),
};
}
None => (),
};
line = line + 1;
}
};
}
_ => (),
};
}
CommandResult::Continue(flow_output)
}
Err(error) => CommandResult::Error(error.to_string()),
}
}
}
}
pub(crate) fn create_alias_command(
name: String,
aliases: Vec<String>,
script: String,
arguments_amount: usize,
) -> AliasCommand {
let raw_command = script.trim().to_string();
AliasCommand {
name,
aliases,
raw_command,
arguments_amount,
}
}

View file

@ -0,0 +1 @@

View file

@ -0,0 +1 @@
pub(crate) mod command;