From 46d3d3443688e3d24a1068cf3e85435c314022c1 Mon Sep 17 00:00:00 2001 From: sagie gur ari Date: Sat, 1 Feb 2020 11:23:19 +0000 Subject: [PATCH] New map_get and map_put commands --- CHANGELOG.md | 2 + docs/sdk.md | 73 ++++++++ .../src/sdk/std/collections/map_get/help.md | 28 +++ .../src/sdk/std/collections/map_get/mod.rs | 163 ++++++++++++++++++ .../sdk/std/collections/map_get/mod_test.rs | 37 ++++ .../src/sdk/std/collections/map_put/help.md | 29 ++++ .../src/sdk/std/collections/map_put/mod.rs | 122 +++++++++++++ .../sdk/std/collections/map_put/mod_test.rs | 46 +++++ duckscript_sdk/src/sdk/std/collections/mod.rs | 4 + test/std/collections/map_test.ds | 12 ++ 10 files changed, 516 insertions(+) create mode 100644 duckscript_sdk/src/sdk/std/collections/map_get/help.md create mode 100755 duckscript_sdk/src/sdk/std/collections/map_get/mod.rs create mode 100644 duckscript_sdk/src/sdk/std/collections/map_get/mod_test.rs create mode 100644 duckscript_sdk/src/sdk/std/collections/map_put/help.md create mode 100755 duckscript_sdk/src/sdk/std/collections/map_put/mod.rs create mode 100644 duckscript_sdk/src/sdk/std/collections/map_put/mod_test.rs create mode 100644 test/std/collections/map_test.ds diff --git a/CHANGELOG.md b/CHANGELOG.md index c1cacf8..42a84c6 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ### v0.1.9 +* New map_get command. +* New map_put command. * New map command. * The set command now supports 'or' condition. * New base64 command #79 diff --git a/docs/sdk.md b/docs/sdk.md index 225cdd9..0dff4ab 100644 --- a/docs/sdk.md +++ b/docs/sdk.md @@ -22,6 +22,8 @@ * [std::collections::ArrayPush (array_push)](#std__collections__ArrayPush) * [std::collections::IsArray (is_array)](#std__collections__IsArray) * [std::collections::Map (map)](#std__collections__Map) +* [std::collections::MapGet (map_get)](#std__collections__MapGet) +* [std::collections::MapPut (map_put)](#std__collections__MapPut) * [std::collections::Range (range)](#std__collections__Range) * [std::collections::ReadProperties (read_properties)](#std__collections__ReadProperties) * [std::collections::WriteProperties (write_properties)](#std__collections__WriteProperties) @@ -1068,6 +1070,77 @@ release ${handle} #### Aliases: map + +## std::collections::MapGet +```sh +value = map_get handle key +``` + +Returns a the value corresponding to the key from the map. + +#### Parameters + +* The map handle. +* The key. + +#### Return Value + +The value corresponding to the key from the map. + +#### Examples + +```sh +handle = map + +result = map_put ${handle} key value +assert_eq ${result} true + +value = map_get ${handle} key +assert_eq ${value} value + +release ${handle} +``` + + +#### Aliases: +map_get + + +## std::collections::MapPut +```sh +var = map_put handle key value +``` + +Inserts a key-value pair into the map. + +#### Parameters + +* The map handle. +* The key. +* The new value. + +#### Return Value + +True if a new value was inserted. + +#### Examples + +```sh +handle = map + +result = map_put ${handle} key value +assert_eq ${result} true + +value = map_get ${handle} key +assert_eq ${value} value + +release ${handle} +``` + + +#### Aliases: +map_put + ## std::collections::Range ```sh diff --git a/duckscript_sdk/src/sdk/std/collections/map_get/help.md b/duckscript_sdk/src/sdk/std/collections/map_get/help.md new file mode 100644 index 0000000..44403ad --- /dev/null +++ b/duckscript_sdk/src/sdk/std/collections/map_get/help.md @@ -0,0 +1,28 @@ +```sh +value = map_get handle key +``` + +Returns a the value corresponding to the key from the map. + +#### Parameters + +* The map handle. +* The key. + +#### Return Value + +The value corresponding to the key from the map. + +#### Examples + +```sh +handle = map + +result = map_put ${handle} key value +assert_eq ${result} true + +value = map_get ${handle} key +assert_eq ${value} value + +release ${handle} +``` diff --git a/duckscript_sdk/src/sdk/std/collections/map_get/mod.rs b/duckscript_sdk/src/sdk/std/collections/map_get/mod.rs new file mode 100755 index 0000000..0297122 --- /dev/null +++ b/duckscript_sdk/src/sdk/std/collections/map_get/mod.rs @@ -0,0 +1,163 @@ +use crate::utils::pckg; +use crate::utils::state::get_handles_sub_state; +use duckscript::types::command::{Command, CommandResult, Commands}; +use duckscript::types::instruction::Instruction; +use duckscript::types::runtime::StateValue; +use std::collections::HashMap; + +#[cfg(test)] +#[path = "./mod_test.rs"] +mod mod_test; + +#[derive(Clone)] +pub(crate) struct CommandImpl { + package: String, +} + +impl Command for CommandImpl { + fn name(&self) -> String { + pckg::concat(&self.package, "MapGet") + } + + fn aliases(&self) -> Vec { + vec!["map_get".to_string()] + } + + fn help(&self) -> String { + include_str!("help.md").to_string() + } + + fn clone_and_box(&self) -> Box { + Box::new((*self).clone()) + } + + fn requires_context(&self) -> bool { + true + } + + fn run_with_context( + &self, + arguments: Vec, + state: &mut HashMap, + _variables: &mut HashMap, + _output_variable: Option, + _instructions: &Vec, + _commands: &mut Commands, + _line: usize, + ) -> CommandResult { + if arguments.is_empty() { + CommandResult::Error("Map handle not provided.".to_string()) + } else if arguments.len() < 2 { + CommandResult::Error("Key not provided.".to_string()) + } else { + let state = get_handles_sub_state(state); + + let key = &arguments[0]; + + match state.remove(key) { + Some(state_value) => match state_value { + StateValue::SubState(mut map) => { + let item = match map.remove(&arguments[1]) { + Some(value) => { + let value_clone = value.clone(); + map.insert(arguments[1].clone(), value); + Some(value_clone) + } + None => None, + }; + + state.insert(key.to_string(), StateValue::SubState(map)); + + match item { + Some(map_item_value) => match map_item_value { + StateValue::Boolean(value) => { + CommandResult::Continue(Some(value.to_string())) + } + StateValue::Number(value) => { + CommandResult::Continue(Some(value.to_string())) + } + StateValue::UnsignedNumber(value) => { + CommandResult::Continue(Some(value.to_string())) + } + StateValue::Number32Bit(value) => { + CommandResult::Continue(Some(value.to_string())) + } + StateValue::UnsignedNumber32Bit(value) => { + CommandResult::Continue(Some(value.to_string())) + } + StateValue::Number64Bit(value) => { + CommandResult::Continue(Some(value.to_string())) + } + StateValue::UnsignedNumber64Bit(value) => { + CommandResult::Continue(Some(value.to_string())) + } + StateValue::String(value) => { + CommandResult::Continue(Some(value.to_string())) + } + StateValue::ByteArray(_) => { + CommandResult::Error("Unsupported map element.".to_string()) + } + StateValue::List(_) => { + CommandResult::Error("Unsupported map element.".to_string()) + } + StateValue::SubState(_) => { + CommandResult::Error("Unsupported map element.".to_string()) + } + }, + None => CommandResult::Continue(None), + } + } + StateValue::Boolean(value) => { + state.insert(key.to_string(), StateValue::Boolean(value)); + CommandResult::Error("Invalid handle provided.".to_string()) + } + StateValue::Number(value) => { + state.insert(key.to_string(), StateValue::Number(value)); + CommandResult::Error("Invalid handle provided.".to_string()) + } + StateValue::UnsignedNumber(value) => { + state.insert(key.to_string(), StateValue::UnsignedNumber(value)); + CommandResult::Error("Invalid handle provided.".to_string()) + } + StateValue::Number32Bit(value) => { + state.insert(key.to_string(), StateValue::Number32Bit(value)); + CommandResult::Error("Invalid handle provided.".to_string()) + } + StateValue::UnsignedNumber32Bit(value) => { + state.insert(key.to_string(), StateValue::UnsignedNumber32Bit(value)); + CommandResult::Error("Invalid handle provided.".to_string()) + } + StateValue::Number64Bit(value) => { + state.insert(key.to_string(), StateValue::Number64Bit(value)); + CommandResult::Error("Invalid handle provided.".to_string()) + } + StateValue::UnsignedNumber64Bit(value) => { + state.insert(key.to_string(), StateValue::UnsignedNumber64Bit(value)); + CommandResult::Error("Invalid handle provided.".to_string()) + } + StateValue::String(value) => { + state.insert(key.to_string(), StateValue::String(value)); + CommandResult::Error("Invalid handle provided.".to_string()) + } + StateValue::ByteArray(value) => { + state.insert(key.to_string(), StateValue::ByteArray(value)); + CommandResult::Error("Invalid handle provided.".to_string()) + } + StateValue::List(value) => { + state.insert(key.to_string(), StateValue::List(value)); + CommandResult::Error("Invalid handle provided.".to_string()) + } + }, + None => { + CommandResult::Error(format!("Map for handle: {} not found.", key).to_string()) + } + } + } + } +} + +pub(crate) fn create(package: &str) -> Box { + Box::new(CommandImpl { + package: package.to_string(), + }) +} diff --git a/duckscript_sdk/src/sdk/std/collections/map_get/mod_test.rs b/duckscript_sdk/src/sdk/std/collections/map_get/mod_test.rs new file mode 100644 index 0000000..c3ac8d8 --- /dev/null +++ b/duckscript_sdk/src/sdk/std/collections/map_get/mod_test.rs @@ -0,0 +1,37 @@ +use super::*; +use crate::sdk::std::collections::{map, map_put}; +use crate::test; +use crate::test::CommandValidation; + +#[test] +fn common_functions() { + test::test_common_command_functions(create("")); +} + +#[test] +fn run_no_args() { + test::run_script_and_error(vec![create("")], "out = map_get", "out"); +} + +#[test] +fn run_missing_key() { + test::run_script_and_error(vec![create("")], "out = map_get handle", "out"); +} + +#[test] +fn run_not_found() { + test::run_script_and_error(vec![create("")], "out = map_get bad_handle key", "out"); +} + +#[test] +fn run_found() { + test::run_script_and_validate( + vec![create(""), map::create(""), map_put::create("")], + r#" + handle = map + map_put ${handle} key value + out = map_get ${handle} key + "#, + CommandValidation::Match("out".to_string(), "value".to_string()), + ); +} diff --git a/duckscript_sdk/src/sdk/std/collections/map_put/help.md b/duckscript_sdk/src/sdk/std/collections/map_put/help.md new file mode 100644 index 0000000..82c5356 --- /dev/null +++ b/duckscript_sdk/src/sdk/std/collections/map_put/help.md @@ -0,0 +1,29 @@ +```sh +var = map_put handle key value +``` + +Inserts a key-value pair into the map. + +#### Parameters + +* The map handle. +* The key. +* The new value. + +#### Return Value + +True if a new value was inserted. + +#### Examples + +```sh +handle = map + +result = map_put ${handle} key value +assert_eq ${result} true + +value = map_get ${handle} key +assert_eq ${value} value + +release ${handle} +``` diff --git a/duckscript_sdk/src/sdk/std/collections/map_put/mod.rs b/duckscript_sdk/src/sdk/std/collections/map_put/mod.rs new file mode 100755 index 0000000..9bb7090 --- /dev/null +++ b/duckscript_sdk/src/sdk/std/collections/map_put/mod.rs @@ -0,0 +1,122 @@ +use crate::utils::pckg; +use crate::utils::state::get_handles_sub_state; +use duckscript::types::command::{Command, CommandResult, Commands}; +use duckscript::types::instruction::Instruction; +use duckscript::types::runtime::StateValue; +use std::collections::HashMap; + +#[cfg(test)] +#[path = "./mod_test.rs"] +mod mod_test; + +#[derive(Clone)] +pub(crate) struct CommandImpl { + package: String, +} + +impl Command for CommandImpl { + fn name(&self) -> String { + pckg::concat(&self.package, "MapPut") + } + + fn aliases(&self) -> Vec { + vec!["map_put".to_string()] + } + + fn help(&self) -> String { + include_str!("help.md").to_string() + } + + fn clone_and_box(&self) -> Box { + Box::new((*self).clone()) + } + + fn requires_context(&self) -> bool { + true + } + + fn run_with_context( + &self, + arguments: Vec, + state: &mut HashMap, + _variables: &mut HashMap, + _output_variable: Option, + _instructions: &Vec, + _commands: &mut Commands, + _line: usize, + ) -> CommandResult { + if arguments.is_empty() { + CommandResult::Error("Map handle not provided.".to_string()) + } else if arguments.len() < 3 { + CommandResult::Error("Key/Value not provided.".to_string()) + } else { + let state = get_handles_sub_state(state); + + let key = &arguments[0]; + + match state.remove(key) { + Some(state_value) => match state_value { + StateValue::SubState(mut map) => { + let item_key = arguments[1].clone(); + let value = arguments[2].clone(); + + map.insert(item_key, StateValue::String(value)); + + state.insert(key.to_string(), StateValue::SubState(map)); + + CommandResult::Continue(Some("true".to_string())) + } + StateValue::Boolean(value) => { + state.insert(key.to_string(), StateValue::Boolean(value)); + CommandResult::Error("Invalid handle provided.".to_string()) + } + StateValue::Number(value) => { + state.insert(key.to_string(), StateValue::Number(value)); + CommandResult::Error("Invalid handle provided.".to_string()) + } + StateValue::UnsignedNumber(value) => { + state.insert(key.to_string(), StateValue::UnsignedNumber(value)); + CommandResult::Error("Invalid handle provided.".to_string()) + } + StateValue::Number32Bit(value) => { + state.insert(key.to_string(), StateValue::Number32Bit(value)); + CommandResult::Error("Invalid handle provided.".to_string()) + } + StateValue::UnsignedNumber32Bit(value) => { + state.insert(key.to_string(), StateValue::UnsignedNumber32Bit(value)); + CommandResult::Error("Invalid handle provided.".to_string()) + } + StateValue::Number64Bit(value) => { + state.insert(key.to_string(), StateValue::Number64Bit(value)); + CommandResult::Error("Invalid handle provided.".to_string()) + } + StateValue::UnsignedNumber64Bit(value) => { + state.insert(key.to_string(), StateValue::UnsignedNumber64Bit(value)); + CommandResult::Error("Invalid handle provided.".to_string()) + } + StateValue::String(value) => { + state.insert(key.to_string(), StateValue::String(value)); + CommandResult::Error("Invalid handle provided.".to_string()) + } + StateValue::ByteArray(value) => { + state.insert(key.to_string(), StateValue::ByteArray(value)); + CommandResult::Error("Invalid handle provided.".to_string()) + } + StateValue::List(value) => { + state.insert(key.to_string(), StateValue::List(value)); + CommandResult::Error("Invalid handle provided.".to_string()) + } + }, + None => { + CommandResult::Error(format!("Map for handle: {} not found.", key).to_string()) + } + } + } + } +} + +pub(crate) fn create(package: &str) -> Box { + Box::new(CommandImpl { + package: package.to_string(), + }) +} diff --git a/duckscript_sdk/src/sdk/std/collections/map_put/mod_test.rs b/duckscript_sdk/src/sdk/std/collections/map_put/mod_test.rs new file mode 100644 index 0000000..c05bf2b --- /dev/null +++ b/duckscript_sdk/src/sdk/std/collections/map_put/mod_test.rs @@ -0,0 +1,46 @@ +use super::*; +use crate::sdk::std::collections::{map, map_get}; +use crate::test; +use crate::test::CommandValidation; + +#[test] +fn common_functions() { + test::test_common_command_functions(create("")); +} + +#[test] +fn run_no_args() { + test::run_script_and_error(vec![create("")], "out = map_put", "out"); +} + +#[test] +fn run_missing_key() { + test::run_script_and_error(vec![create("")], "out = map_put handle", "out"); +} + +#[test] +fn run_missing_value() { + test::run_script_and_error(vec![create("")], "out = map_put handle key", "out"); +} + +#[test] +fn run_not_found() { + test::run_script_and_error( + vec![create("")], + "out = map_put bad_handle key value", + "out", + ); +} + +#[test] +fn run_found() { + test::run_script_and_validate( + vec![create(""), map::create(""), map_get::create("")], + r#" + handle = map + map_put ${handle} key value + out = map_get ${handle} key + "#, + CommandValidation::Match("out".to_string(), "value".to_string()), + ); +} diff --git a/duckscript_sdk/src/sdk/std/collections/mod.rs b/duckscript_sdk/src/sdk/std/collections/mod.rs index 4cac3c0..995c2c1 100755 --- a/duckscript_sdk/src/sdk/std/collections/mod.rs +++ b/duckscript_sdk/src/sdk/std/collections/mod.rs @@ -7,6 +7,8 @@ pub(crate) mod array_pop; mod array_push; mod is_array; mod map; +mod map_get; +mod map_put; mod range; mod read_properties; mod write_properties; @@ -29,6 +31,8 @@ pub(crate) fn load(commands: &mut Commands, parent: &str) -> Result<(), ScriptEr commands.set(array_pop::create(&package))?; commands.set(is_array::create(&package))?; commands.set(map::create(&package))?; + commands.set(map_get::create(&package))?; + commands.set(map_put::create(&package))?; commands.set(range::create(&package))?; commands.set(read_properties::create(&package))?; commands.set(write_properties::create(&package))?; diff --git a/test/std/collections/map_test.ds b/test/std/collections/map_test.ds new file mode 100644 index 0000000..1e18152 --- /dev/null +++ b/test/std/collections/map_test.ds @@ -0,0 +1,12 @@ + +fn test_put_get + handle = map + + result = map_put ${handle} key value + assert_eq ${result} true + + value = map_get ${handle} key + assert_eq ${value} value + + release ${handle} +end