diff --git a/CHANGELOG.md b/CHANGELOG.md index b89a145..cf1b5f5 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ ## CHANGELOG -### v0.6.2 +### v0.6.2 (2020-07-24) * New function <scope> annotation #121 * New scope_pop_stack command #121 diff --git a/docs/api/duckscript_sdk/source-files.js b/docs/api/duckscript_sdk/source-files.js index c504a0f..3e505b0 100644 --- a/docs/api/duckscript_sdk/source-files.js +++ b/docs/api/duckscript_sdk/source-files.js @@ -1,3 +1,3 @@ var N = null;var sourcesIndex = {}; -sourcesIndex["duckscriptsdk"] = {"name":"","dirs":[{"name":"sdk","dirs":[{"name":"internal","dirs":[{"name":"sdkdocs","files":["mod.rs"]}],"files":["mod.rs"]},{"name":"std","dirs":[{"name":"collections","dirs":[{"name":"array","files":["mod.rs"]},{"name":"array_clear","files":["mod.rs"]},{"name":"array_concat","files":["mod.rs"]},{"name":"array_contains","files":["mod.rs"]},{"name":"array_get","files":["mod.rs"]},{"name":"array_is_empty","files":["mod.rs"]},{"name":"array_join","files":["mod.rs"]},{"name":"array_length","files":["mod.rs"]},{"name":"array_pop","files":["mod.rs"]},{"name":"array_push","files":["mod.rs"]},{"name":"array_remove","files":["mod.rs"]},{"name":"array_set","files":["mod.rs"]},{"name":"is_array","files":["mod.rs"]},{"name":"is_map","files":["mod.rs"]},{"name":"is_set","files":["mod.rs"]},{"name":"map","files":["mod.rs"]},{"name":"map_clear","files":["mod.rs"]},{"name":"map_contains_key","files":["mod.rs"]},{"name":"map_contains_value","files":["mod.rs"]},{"name":"map_get","files":["mod.rs"]},{"name":"map_is_empty","files":["mod.rs"]},{"name":"map_keys","files":["mod.rs"]},{"name":"map_load_properties","files":["mod.rs"]},{"name":"map_put","files":["mod.rs"]},{"name":"map_remove","files":["mod.rs"]},{"name":"map_size","files":["mod.rs"]},{"name":"map_to_properties","files":["mod.rs"]},{"name":"range","files":["mod.rs"]},{"name":"read_properties","files":["mod.rs"]},{"name":"set","files":["mod.rs"]},{"name":"set_clear","files":["mod.rs"]},{"name":"set_contains","files":["mod.rs"]},{"name":"set_from_array","files":["mod.rs"]},{"name":"set_is_empty","files":["mod.rs"]},{"name":"set_put","files":["mod.rs"]},{"name":"set_remove","files":["mod.rs"]},{"name":"set_size","files":["mod.rs"]},{"name":"set_to_array","files":["mod.rs"]},{"name":"write_properties","files":["mod.rs"]}],"files":["mod.rs"]},{"name":"debug","dirs":[{"name":"duckscript_sdk_version","files":["mod.rs"]},{"name":"duckscript_version","files":["mod.rs"]},{"name":"dump_instructions","files":["mod.rs"]},{"name":"dump_state","files":["mod.rs"]},{"name":"dump_variables","files":["mod.rs"]}],"files":["mod.rs"]},{"name":"echo","files":["mod.rs"]},{"name":"env","dirs":[{"name":"cpu_count","files":["mod.rs"]},{"name":"env_to_map","files":["mod.rs"]},{"name":"get_env","files":["mod.rs"]},{"name":"get_home_dir","files":["mod.rs"]},{"name":"get_user_name","files":["mod.rs"]},{"name":"is_windows","files":["mod.rs"]},{"name":"os_family","files":["mod.rs"]},{"name":"os_name","files":["mod.rs"]},{"name":"os_release","files":["mod.rs"]},{"name":"os_version","files":["mod.rs"]},{"name":"print_current_directory","files":["mod.rs"]},{"name":"print_env","files":["mod.rs"]},{"name":"set_current_directory","files":["mod.rs"]},{"name":"set_env","files":["mod.rs"]},{"name":"uname","files":["mod.rs"]},{"name":"unset","files":["mod.rs"]},{"name":"which","files":["mod.rs"]}],"files":["mod.rs"]},{"name":"eval","files":["mod.rs"]},{"name":"flowcontrol","dirs":[{"name":"end","files":["mod.rs"]},{"name":"forin","files":["mod.rs"]},{"name":"function","files":["mod.rs"]},{"name":"goto","files":["mod.rs"]},{"name":"ifelse","files":["mod.rs"]}],"files":["mod.rs"]},{"name":"fs","dirs":[{"name":"append","files":["mod.rs"]},{"name":"basename","files":["mod.rs"]},{"name":"canonical","files":["mod.rs"]},{"name":"cp","files":["mod.rs"]},{"name":"dirname","files":["mod.rs"]},{"name":"exists","files":["mod.rs"]},{"name":"get_last_modified_time","files":["mod.rs"]},{"name":"glob_array","files":["mod.rs"]},{"name":"is_directory","files":["mod.rs"]},{"name":"is_file","files":["mod.rs"]},{"name":"is_path_newer","files":["mod.rs"]},{"name":"is_readonly","files":["mod.rs"]},{"name":"list","files":["mod.rs"]},{"name":"mkdir","files":["mod.rs"]},{"name":"mv","files":["mod.rs"]},{"name":"print","files":["mod.rs"]},{"name":"read_bytes","files":["mod.rs"]},{"name":"read_text","files":["mod.rs"]},{"name":"rm","files":["mod.rs"]},{"name":"rmdir","files":["mod.rs"]},{"name":"set_mode","files":["mod.rs"]},{"name":"set_mode_glob","files":["mod.rs"]},{"name":"temp_dir","files":["mod.rs"]},{"name":"temp_file","files":["mod.rs"]},{"name":"touch","files":["mod.rs"]},{"name":"write_bytes","files":["mod.rs"]},{"name":"write_text","files":["mod.rs"]}],"files":["mod.rs"]},{"name":"is_defined","files":["mod.rs"]},{"name":"lib","dirs":[{"name":"alias","dirs":[{"name":"set","files":["mod.rs"]},{"name":"unset","files":["mod.rs"]}],"files":["mod.rs"]},{"name":"command","dirs":[{"name":"remove","files":["mod.rs"]}],"files":["mod.rs"]}],"files":["mod.rs"]},{"name":"man","files":["mod.rs"]},{"name":"math","dirs":[{"name":"calc","files":["mod.rs"]},{"name":"greater_than","files":["mod.rs"]},{"name":"less_than","files":["mod.rs"]}],"files":["mod.rs"]},{"name":"net","dirs":[{"name":"ftp","dirs":[{"name":"get","files":["mod.rs"]},{"name":"get_in_memory","files":["mod.rs"]},{"name":"list","files":["mod.rs"]},{"name":"nlst","files":["mod.rs"]},{"name":"put","files":["mod.rs"]},{"name":"put_in_memory","files":["mod.rs"]}],"files":["mod.rs"]},{"name":"hostname","files":["mod.rs"]},{"name":"http_client","files":["mod.rs"]},{"name":"wget","files":["mod.rs"]}],"files":["mod.rs"]},{"name":"noop","files":["mod.rs"]},{"name":"not","files":["mod.rs"]},{"name":"on_error","dirs":[{"name":"exit_on_error","files":["mod.rs"]},{"name":"get_last_error","files":["mod.rs"]},{"name":"get_last_error_line","files":["mod.rs"]},{"name":"get_last_error_source","files":["mod.rs"]},{"name":"on_error","files":["mod.rs"]},{"name":"set_error","files":["mod.rs"]},{"name":"trigger_error","files":["mod.rs"]}],"files":["mod.rs"]},{"name":"process","dirs":[{"name":"exec","files":["mod.rs"]},{"name":"exit","files":["mod.rs"]},{"name":"process_id","files":["mod.rs"]},{"name":"spawn","files":["mod.rs"]},{"name":"watchdog","files":["mod.rs"]}],"files":["mod.rs"]},{"name":"read","files":["mod.rs"]},{"name":"release","files":["mod.rs"]},{"name":"scope","dirs":[{"name":"clear","files":["mod.rs"]}],"files":["mod.rs"]},{"name":"string","dirs":[{"name":"base64","files":["mod.rs"]},{"name":"base64_decode","files":["mod.rs"]},{"name":"base64_encode","files":["mod.rs"]},{"name":"bytes_to_string","files":["mod.rs"]},{"name":"concat","files":["mod.rs"]},{"name":"contains","files":["mod.rs"]},{"name":"ends_with","files":["mod.rs"]},{"name":"equals","files":["mod.rs"]},{"name":"indexof","files":["mod.rs"]},{"name":"is_empty","files":["mod.rs"]},{"name":"last_indexof","files":["mod.rs"]},{"name":"length","files":["mod.rs"]},{"name":"replace","files":["mod.rs"]},{"name":"split","files":["mod.rs"]},{"name":"starts_with","files":["mod.rs"]},{"name":"string_to_bytes","files":["mod.rs"]},{"name":"substring","files":["mod.rs"]},{"name":"trim","files":["mod.rs"]},{"name":"trim_end","files":["mod.rs"]},{"name":"trim_start","files":["mod.rs"]}],"files":["mod.rs"]},{"name":"test","dirs":[{"name":"assert","files":["mod.rs"]},{"name":"assert_eq","files":["mod.rs"]},{"name":"assert_error","files":["mod.rs"]},{"name":"assert_fail","files":["mod.rs"]},{"name":"assert_false","files":["mod.rs"]},{"name":"test_directory","files":["mod.rs"]},{"name":"test_file","files":["mod.rs"]}],"files":["mod.rs"]},{"name":"thread","dirs":[{"name":"sleep","files":["mod.rs"]}],"files":["mod.rs"]},{"name":"time","dirs":[{"name":"current_time","files":["mod.rs"]}],"files":["mod.rs"]},{"name":"var","dirs":[{"name":"get_all_var_names","files":["mod.rs"]},{"name":"get_by_name","files":["mod.rs"]},{"name":"set","files":["mod.rs"]},{"name":"set_by_name","files":["mod.rs"]},{"name":"unset","files":["mod.rs"]}],"files":["mod.rs"]}],"files":["mod.rs"]}],"files":["mod.rs"]},{"name":"types","files":["command.rs","mod.rs","scope.rs"]},{"name":"utils","files":["condition.rs","eval.rs","exec.rs","flags.rs","instruction_query.rs","io.rs","mod.rs","pckg.rs","state.rs"]}],"files":["lib.rs"]}; +sourcesIndex["duckscriptsdk"] = {"name":"","dirs":[{"name":"sdk","dirs":[{"name":"internal","dirs":[{"name":"sdkdocs","files":["mod.rs"]}],"files":["mod.rs"]},{"name":"std","dirs":[{"name":"collections","dirs":[{"name":"array","files":["mod.rs"]},{"name":"array_clear","files":["mod.rs"]},{"name":"array_concat","files":["mod.rs"]},{"name":"array_contains","files":["mod.rs"]},{"name":"array_get","files":["mod.rs"]},{"name":"array_is_empty","files":["mod.rs"]},{"name":"array_join","files":["mod.rs"]},{"name":"array_length","files":["mod.rs"]},{"name":"array_pop","files":["mod.rs"]},{"name":"array_push","files":["mod.rs"]},{"name":"array_remove","files":["mod.rs"]},{"name":"array_set","files":["mod.rs"]},{"name":"is_array","files":["mod.rs"]},{"name":"is_map","files":["mod.rs"]},{"name":"is_set","files":["mod.rs"]},{"name":"map","files":["mod.rs"]},{"name":"map_clear","files":["mod.rs"]},{"name":"map_contains_key","files":["mod.rs"]},{"name":"map_contains_value","files":["mod.rs"]},{"name":"map_get","files":["mod.rs"]},{"name":"map_is_empty","files":["mod.rs"]},{"name":"map_keys","files":["mod.rs"]},{"name":"map_load_properties","files":["mod.rs"]},{"name":"map_put","files":["mod.rs"]},{"name":"map_remove","files":["mod.rs"]},{"name":"map_size","files":["mod.rs"]},{"name":"map_to_properties","files":["mod.rs"]},{"name":"range","files":["mod.rs"]},{"name":"read_properties","files":["mod.rs"]},{"name":"set","files":["mod.rs"]},{"name":"set_clear","files":["mod.rs"]},{"name":"set_contains","files":["mod.rs"]},{"name":"set_from_array","files":["mod.rs"]},{"name":"set_is_empty","files":["mod.rs"]},{"name":"set_put","files":["mod.rs"]},{"name":"set_remove","files":["mod.rs"]},{"name":"set_size","files":["mod.rs"]},{"name":"set_to_array","files":["mod.rs"]},{"name":"write_properties","files":["mod.rs"]}],"files":["mod.rs"]},{"name":"debug","dirs":[{"name":"duckscript_sdk_version","files":["mod.rs"]},{"name":"duckscript_version","files":["mod.rs"]},{"name":"dump_instructions","files":["mod.rs"]},{"name":"dump_state","files":["mod.rs"]},{"name":"dump_variables","files":["mod.rs"]}],"files":["mod.rs"]},{"name":"echo","files":["mod.rs"]},{"name":"env","dirs":[{"name":"cpu_count","files":["mod.rs"]},{"name":"env_to_map","files":["mod.rs"]},{"name":"get_env","files":["mod.rs"]},{"name":"get_home_dir","files":["mod.rs"]},{"name":"get_user_name","files":["mod.rs"]},{"name":"is_windows","files":["mod.rs"]},{"name":"os_family","files":["mod.rs"]},{"name":"os_name","files":["mod.rs"]},{"name":"os_release","files":["mod.rs"]},{"name":"os_version","files":["mod.rs"]},{"name":"print_current_directory","files":["mod.rs"]},{"name":"print_env","files":["mod.rs"]},{"name":"set_current_directory","files":["mod.rs"]},{"name":"set_env","files":["mod.rs"]},{"name":"uname","files":["mod.rs"]},{"name":"unset","files":["mod.rs"]},{"name":"which","files":["mod.rs"]}],"files":["mod.rs"]},{"name":"eval","files":["mod.rs"]},{"name":"flowcontrol","dirs":[{"name":"end","files":["mod.rs"]},{"name":"forin","files":["mod.rs"]},{"name":"function","files":["mod.rs"]},{"name":"goto","files":["mod.rs"]},{"name":"ifelse","files":["mod.rs"]}],"files":["mod.rs"]},{"name":"fs","dirs":[{"name":"append","files":["mod.rs"]},{"name":"basename","files":["mod.rs"]},{"name":"canonical","files":["mod.rs"]},{"name":"cp","files":["mod.rs"]},{"name":"dirname","files":["mod.rs"]},{"name":"exists","files":["mod.rs"]},{"name":"get_last_modified_time","files":["mod.rs"]},{"name":"glob_array","files":["mod.rs"]},{"name":"is_directory","files":["mod.rs"]},{"name":"is_file","files":["mod.rs"]},{"name":"is_path_newer","files":["mod.rs"]},{"name":"is_readonly","files":["mod.rs"]},{"name":"list","files":["mod.rs"]},{"name":"mkdir","files":["mod.rs"]},{"name":"mv","files":["mod.rs"]},{"name":"print","files":["mod.rs"]},{"name":"read_bytes","files":["mod.rs"]},{"name":"read_text","files":["mod.rs"]},{"name":"rm","files":["mod.rs"]},{"name":"rmdir","files":["mod.rs"]},{"name":"set_mode","files":["mod.rs"]},{"name":"set_mode_glob","files":["mod.rs"]},{"name":"temp_dir","files":["mod.rs"]},{"name":"temp_file","files":["mod.rs"]},{"name":"touch","files":["mod.rs"]},{"name":"write_bytes","files":["mod.rs"]},{"name":"write_text","files":["mod.rs"]}],"files":["mod.rs"]},{"name":"is_defined","files":["mod.rs"]},{"name":"lib","dirs":[{"name":"alias","dirs":[{"name":"set","files":["mod.rs"]},{"name":"unset","files":["mod.rs"]}],"files":["mod.rs"]},{"name":"command","dirs":[{"name":"remove","files":["mod.rs"]}],"files":["mod.rs"]}],"files":["mod.rs"]},{"name":"man","files":["mod.rs"]},{"name":"math","dirs":[{"name":"calc","files":["mod.rs"]},{"name":"greater_than","files":["mod.rs"]},{"name":"less_than","files":["mod.rs"]}],"files":["mod.rs"]},{"name":"net","dirs":[{"name":"ftp","dirs":[{"name":"get","files":["mod.rs"]},{"name":"get_in_memory","files":["mod.rs"]},{"name":"list","files":["mod.rs"]},{"name":"nlst","files":["mod.rs"]},{"name":"put","files":["mod.rs"]},{"name":"put_in_memory","files":["mod.rs"]}],"files":["mod.rs"]},{"name":"hostname","files":["mod.rs"]},{"name":"http_client","files":["mod.rs"]},{"name":"wget","files":["mod.rs"]}],"files":["mod.rs"]},{"name":"noop","files":["mod.rs"]},{"name":"not","files":["mod.rs"]},{"name":"on_error","dirs":[{"name":"exit_on_error","files":["mod.rs"]},{"name":"get_last_error","files":["mod.rs"]},{"name":"get_last_error_line","files":["mod.rs"]},{"name":"get_last_error_source","files":["mod.rs"]},{"name":"on_error","files":["mod.rs"]},{"name":"set_error","files":["mod.rs"]},{"name":"trigger_error","files":["mod.rs"]}],"files":["mod.rs"]},{"name":"process","dirs":[{"name":"exec","files":["mod.rs"]},{"name":"exit","files":["mod.rs"]},{"name":"process_id","files":["mod.rs"]},{"name":"spawn","files":["mod.rs"]},{"name":"watchdog","files":["mod.rs"]}],"files":["mod.rs"]},{"name":"read","files":["mod.rs"]},{"name":"release","files":["mod.rs"]},{"name":"scope","dirs":[{"name":"clear","files":["mod.rs"]},{"name":"pop_stack","files":["mod.rs"]},{"name":"push_stack","files":["mod.rs"]}],"files":["mod.rs"]},{"name":"string","dirs":[{"name":"base64","files":["mod.rs"]},{"name":"base64_decode","files":["mod.rs"]},{"name":"base64_encode","files":["mod.rs"]},{"name":"bytes_to_string","files":["mod.rs"]},{"name":"concat","files":["mod.rs"]},{"name":"contains","files":["mod.rs"]},{"name":"ends_with","files":["mod.rs"]},{"name":"equals","files":["mod.rs"]},{"name":"indexof","files":["mod.rs"]},{"name":"is_empty","files":["mod.rs"]},{"name":"last_indexof","files":["mod.rs"]},{"name":"length","files":["mod.rs"]},{"name":"replace","files":["mod.rs"]},{"name":"split","files":["mod.rs"]},{"name":"starts_with","files":["mod.rs"]},{"name":"string_to_bytes","files":["mod.rs"]},{"name":"substring","files":["mod.rs"]},{"name":"trim","files":["mod.rs"]},{"name":"trim_end","files":["mod.rs"]},{"name":"trim_start","files":["mod.rs"]}],"files":["mod.rs"]},{"name":"test","dirs":[{"name":"assert","files":["mod.rs"]},{"name":"assert_eq","files":["mod.rs"]},{"name":"assert_error","files":["mod.rs"]},{"name":"assert_fail","files":["mod.rs"]},{"name":"assert_false","files":["mod.rs"]},{"name":"test_directory","files":["mod.rs"]},{"name":"test_file","files":["mod.rs"]}],"files":["mod.rs"]},{"name":"thread","dirs":[{"name":"sleep","files":["mod.rs"]}],"files":["mod.rs"]},{"name":"time","dirs":[{"name":"current_time","files":["mod.rs"]}],"files":["mod.rs"]},{"name":"var","dirs":[{"name":"get_all_var_names","files":["mod.rs"]},{"name":"get_by_name","files":["mod.rs"]},{"name":"set","files":["mod.rs"]},{"name":"set_by_name","files":["mod.rs"]},{"name":"unset","files":["mod.rs"]}],"files":["mod.rs"]}],"files":["mod.rs"]}],"files":["mod.rs"]},{"name":"types","files":["command.rs","mod.rs","scope.rs"]},{"name":"utils","files":["annotation.rs","condition.rs","eval.rs","exec.rs","flags.rs","instruction_query.rs","io.rs","mod.rs","pckg.rs","scope.rs","state.rs"]}],"files":["lib.rs"]}; createSourceSidebar(); diff --git a/docs/api/duckscript_sdk/src/duckscriptsdk/sdk/std/flowcontrol/function/mod.rs.html b/docs/api/duckscript_sdk/src/duckscriptsdk/sdk/std/flowcontrol/function/mod.rs.html index d2b91a8..3933393 100644 --- a/docs/api/duckscript_sdk/src/duckscriptsdk/sdk/std/flowcontrol/function/mod.rs.html +++ b/docs/api/duckscript_sdk/src/duckscriptsdk/sdk/std/flowcontrol/function/mod.rs.html @@ -565,11 +565,73 @@ 565 566 567 +568 +569 +570 +571 +572 +573 +574 +575 +576 +577 +578 +579 +580 +581 +582 +583 +584 +585 +586 +587 +588 +589 +590 +591 +592 +593 +594 +595 +596 +597 +598 +599 +600 +601 +602 +603 +604 +605 +606 +607 +608 +609 +610 +611 +612 +613 +614 +615 +616 +617 +618 +619 +620 +621 +622 +623 +624 +625 +626 +627 +628 +629
 use crate::sdk::std::flowcontrol::{end, forin, ifelse};
 use crate::types::scope::get_line_context_name;
 use crate::utils::state::{get_core_sub_state_for_command, get_list, get_sub_state};
-use crate::utils::{instruction_query, pckg};
+use crate::utils::{annotation, instruction_query, pckg, scope};
 use duckscript::types::command::{Command, CommandResult, Commands, GoToValue};
 use duckscript::types::error::ScriptError;
 use duckscript::types::instruction::Instruction;
@@ -589,6 +651,7 @@
     pub(crate) name: String,
     pub(crate) start: usize,
     pub(crate) end: usize,
+    pub(crate) scoped: bool,
 }
 
 #[derive(Debug)]
@@ -598,6 +661,7 @@
     pub(crate) end_line: usize,
     pub(crate) line_context_name: String,
     pub(crate) output_variable: Option<String>,
+    pub(crate) scoped: bool,
 }
 
 fn store_fn_info_in_state(
@@ -625,6 +689,7 @@
         StateValue::UnsignedNumber(meta_info.start),
     );
     fn_info_state.insert("end".to_string(), StateValue::UnsignedNumber(meta_info.end));
+    fn_info_state.insert("scoped".to_string(), StateValue::Boolean(meta_info.scoped));
 
     Ok(())
 }
@@ -653,10 +718,19 @@
             _ => return None,
         };
 
+        let scoped = match fn_info_state.get("scoped") {
+            Some(state_value) => match state_value {
+                StateValue::Boolean(value) => *value,
+                _ => false,
+            },
+            _ => false,
+        };
+
         Some(FunctionMetaInfo {
             name: name.to_string(),
             start,
             end,
+            scoped,
         })
     } else {
         None
@@ -690,6 +764,7 @@
             StateValue::String(output_variable.to_string()),
         );
     }
+    sub_state.insert("scoped".to_string(), StateValue::Boolean(call_info.scoped));
 
     call_stack.push(StateValue::SubState(sub_state));
 }
@@ -741,12 +816,21 @@
                     None => None,
                 };
 
+                let scoped = match sub_state.get("scoped") {
+                    Some(value) => match value {
+                        StateValue::Boolean(scoped) => *scoped,
+                        _ => false,
+                    },
+                    None => false,
+                };
+
                 Some(CallInfo {
                     call_line,
                     start_line,
                     end_line,
                     line_context_name,
                     output_variable,
+                    scoped,
                 })
             }
             _ => return pop_from_call_stack(state),
@@ -765,6 +849,13 @@
 ) -> CommandResult {
     match get_fn_info_from_state(state, &function_name) {
         Some(fn_info) => {
+            if fn_info.scoped {
+                match scope::push(variables, state, &vec![]) {
+                    Err(error) => return CommandResult::Error(error),
+                    _ => (),
+                }
+            }
+
             // define function arguments
             let mut index = 0;
             for argument in arguments {
@@ -782,6 +873,7 @@
                 end_line: fn_info.end,
                 line_context_name,
                 output_variable,
+                scoped: fn_info.scoped,
             };
             push_to_call_stack(state, &call_info);
 
@@ -841,7 +933,18 @@
         if arguments.is_empty() {
             CommandResult::Error("Missing function name.".to_string())
         } else {
-            let function_name = arguments[0].clone();
+            let (function_name, scoped) = if arguments.len() == 1 {
+                (arguments[0].clone(), false)
+            } else {
+                match annotation::parse(&arguments[0]) {
+                    Some(annotations) => (
+                        arguments[1].clone(),
+                        annotations.contains(&"scope".to_string()),
+                    ),
+                    None => (arguments[0].clone(), false),
+                }
+            };
+
             match get_fn_info_from_state(state, &function_name) {
                 Some(fn_info) => {
                     if fn_info.start != line {
@@ -900,6 +1003,7 @@
                                     name: function_name.clone(),
                                     start: line,
                                     end: fn_end_line,
+                                    scoped,
                                 };
 
                                 end::set_command(fn_end_line, state, end_command.name());
@@ -1014,7 +1118,7 @@
         &self,
         _arguments: Vec<String>,
         state: &mut HashMap<String, StateValue>,
-        _variables: &mut HashMap<String, String>,
+        variables: &mut HashMap<String, String>,
         _output_variable: Option<String>,
         _instructions: &Vec<Instruction>,
         _commands: &mut Commands,
@@ -1026,6 +1130,14 @@
             Some(call_info) => {
                 if call_info.end_line == line && call_info.line_context_name == line_context_name {
                     let next_line = call_info.call_line + 1;
+
+                    if call_info.scoped {
+                        match scope::pop(variables, state, &vec![]) {
+                            Err(error) => return CommandResult::Error(error),
+                            _ => (),
+                        }
+                    }
+
                     CommandResult::GoTo(None, GoToValue::Line(next_line))
                 } else {
                     push_to_call_stack(state, &call_info);
@@ -1082,11 +1194,11 @@
                     && call_info.line_context_name == line_context_name
                 {
                     match call_info.output_variable {
-                        Some(name) => {
+                        Some(ref name) => {
                             if arguments.is_empty() {
-                                variables.remove(&name);
+                                variables.remove(name);
                             } else {
-                                variables.insert(name, arguments[0].clone());
+                                variables.insert(name.to_string(), arguments[0].clone());
                             }
                         }
                         None => (),
@@ -1098,6 +1210,18 @@
                         Some(arguments[0].clone())
                     };
 
+                    if call_info.scoped {
+                        let copy = match call_info.output_variable {
+                            Some(ref name) => vec![name.to_string()],
+                            None => vec![],
+                        };
+
+                        match scope::pop(variables, state, &copy) {
+                            Err(error) => return CommandResult::Error(error),
+                            _ => (),
+                        }
+                    }
+
                     let next_line = call_info.call_line + 1;
                     CommandResult::GoTo(output, GoToValue::Line(next_line))
                 } else {
diff --git a/docs/api/duckscript_sdk/src/duckscriptsdk/sdk/std/scope/mod.rs.html b/docs/api/duckscript_sdk/src/duckscriptsdk/sdk/std/scope/mod.rs.html
index 86e2243..fa953c7 100644
--- a/docs/api/duckscript_sdk/src/duckscriptsdk/sdk/std/scope/mod.rs.html
+++ b/docs/api/duckscript_sdk/src/duckscriptsdk/sdk/std/scope/mod.rs.html
@@ -13,8 +13,14 @@
 13
 14
 15
+16
+17
+18
+19
 
 pub(crate) mod clear;
+mod pop_stack;
+mod push_stack;
 
 use crate::utils::pckg;
 use duckscript::types::command::Commands;
@@ -26,6 +32,8 @@
     let package = pckg::concat(parent, PACKAGE);
 
     commands.set(clear::create(&package))?;
+    commands.set(pop_stack::create(&package))?;
+    commands.set(push_stack::create(&package))?;
 
     Ok(())
 }
diff --git a/docs/api/duckscript_sdk/src/duckscriptsdk/sdk/std/scope/pop_stack/mod.rs.html b/docs/api/duckscript_sdk/src/duckscriptsdk/sdk/std/scope/pop_stack/mod.rs.html
new file mode 100644
index 0000000..9cf4e28
--- /dev/null
+++ b/docs/api/duckscript_sdk/src/duckscriptsdk/sdk/std/scope/pop_stack/mod.rs.html
@@ -0,0 +1,135 @@
+mod.rs.html -- source
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+
+use crate::utils::{pckg, scope};
+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, "PopStack")
+    }
+
+    fn aliases(&self) -> Vec<String> {
+        vec!["scope_pop_stack".to_string()]
+    }
+
+    fn help(&self) -> String {
+        include_str!("help.md").to_string()
+    }
+
+    fn clone_and_box(&self) -> Box<dyn Command> {
+        Box::new((*self).clone())
+    }
+
+    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 {
+        let copy = if arguments.is_empty() {
+            &[]
+        } else if arguments[0] == "--copy" {
+            &arguments[1..]
+        } else {
+            &[]
+        };
+
+        match scope::pop(variables, state, &copy) {
+            Ok(_) => CommandResult::Continue(Some("true".to_string())),
+            Err(error) => CommandResult::Error(error),
+        }
+    }
+}
+
+pub(crate) fn create(package: &str) -> Box<dyn Command> {
+    Box::new(CommandImpl {
+        package: package.to_string(),
+    })
+}
+
+
\ No newline at end of file diff --git a/docs/api/duckscript_sdk/src/duckscriptsdk/sdk/std/scope/push_stack/mod.rs.html b/docs/api/duckscript_sdk/src/duckscriptsdk/sdk/std/scope/push_stack/mod.rs.html new file mode 100644 index 0000000..b383dc8 --- /dev/null +++ b/docs/api/duckscript_sdk/src/duckscriptsdk/sdk/std/scope/push_stack/mod.rs.html @@ -0,0 +1,135 @@ +mod.rs.html -- source
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+
+use crate::utils::{pckg, scope};
+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, "PushStack")
+    }
+
+    fn aliases(&self) -> Vec<String> {
+        vec!["scope_push_stack".to_string()]
+    }
+
+    fn help(&self) -> String {
+        include_str!("help.md").to_string()
+    }
+
+    fn clone_and_box(&self) -> Box<dyn Command> {
+        Box::new((*self).clone())
+    }
+
+    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 {
+        let copy = if arguments.is_empty() {
+            &[]
+        } else if arguments[0] == "--copy" {
+            &arguments[1..]
+        } else {
+            &[]
+        };
+
+        match scope::push(variables, state, &copy) {
+            Ok(_) => CommandResult::Continue(Some("true".to_string())),
+            Err(error) => CommandResult::Error(error),
+        }
+    }
+}
+
+pub(crate) fn create(package: &str) -> Box<dyn Command> {
+    Box::new(CommandImpl {
+        package: package.to_string(),
+    })
+}
+
+
\ No newline at end of file diff --git a/docs/api/duckscript_sdk/src/duckscriptsdk/utils/annotation.rs.html b/docs/api/duckscript_sdk/src/duckscriptsdk/utils/annotation.rs.html new file mode 100644 index 0000000..b8d79e1 --- /dev/null +++ b/docs/api/duckscript_sdk/src/duckscriptsdk/utils/annotation.rs.html @@ -0,0 +1,41 @@ +annotation.rs.html -- source
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+
+pub(crate) fn parse(string: &str) -> Option<Vec<String>> {
+    let mut modified_string = string.trim();
+    if modified_string.starts_with("<") && modified_string.ends_with(">") {
+        modified_string = modified_string
+            .strip_prefix("<")
+            .unwrap()
+            .strip_suffix(">")
+            .unwrap();
+
+        let values: Vec<String> = modified_string
+            .split(',')
+            .map(|item| item.to_string())
+            .collect();
+
+        Some(values)
+    } else {
+        None
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/api/duckscript_sdk/src/duckscriptsdk/utils/mod.rs.html b/docs/api/duckscript_sdk/src/duckscriptsdk/utils/mod.rs.html index 3c555ef..45eeb15 100644 --- a/docs/api/duckscript_sdk/src/duckscriptsdk/utils/mod.rs.html +++ b/docs/api/duckscript_sdk/src/duckscriptsdk/utils/mod.rs.html @@ -1,12 +1,15 @@ -mod.rs.html -- source
1
-2
-3
-4
-5
-6
-7
-8
+mod.rs.html -- source
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
 
+pub(crate) mod annotation;
 pub(crate) mod condition;
 pub(crate) mod eval;
 pub(crate) mod exec;
@@ -14,6 +17,7 @@
 pub(crate) mod instruction_query;
 pub(crate) mod io;
 pub(crate) mod pckg;
+pub(crate) mod scope;
 pub(crate) mod state;
 
\ No newline at end of file diff --git a/docs/api/duckscript_sdk/src/duckscriptsdk/utils/scope.rs.html b/docs/api/duckscript_sdk/src/duckscriptsdk/utils/scope.rs.html new file mode 100644 index 0000000..f5bad8f --- /dev/null +++ b/docs/api/duckscript_sdk/src/duckscriptsdk/utils/scope.rs.html @@ -0,0 +1,173 @@ +scope.rs.html -- source
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+
+use crate::utils::state::{ensure_list, mutate_list};
+use duckscript::types::runtime::StateValue;
+use std::cell::RefCell;
+use std::collections::HashMap;
+use std::rc::Rc;
+
+static SCOPE_STACK_STATE_KEY: &str = "scope_stack";
+
+pub(crate) fn push(
+    variables: &mut HashMap<String, String>,
+    state: &mut HashMap<String, StateValue>,
+    copy: &[String],
+) -> Result<(), String> {
+    ensure_list(SCOPE_STACK_STATE_KEY, state);
+
+    match mutate_list(SCOPE_STACK_STATE_KEY.to_string(), state, |list| {
+        list.push(StateValue::Any(Rc::new(RefCell::new(variables.clone()))));
+        Ok(None)
+    }) {
+        Ok(_) => {
+            let mut new_variables = HashMap::new();
+            for key in copy {
+                let value = variables.remove(key);
+                new_variables.insert(key, value);
+            }
+
+            variables.clear();
+
+            for (key, value) in new_variables {
+                variables.insert(key.to_string(), value.unwrap());
+            }
+
+            Ok(())
+        }
+        Err(error) => Err(error),
+    }
+}
+
+pub(crate) fn pop(
+    variables: &mut HashMap<String, String>,
+    state: &mut HashMap<String, StateValue>,
+    copy: &[String],
+) -> Result<(), String> {
+    ensure_list(SCOPE_STACK_STATE_KEY, state);
+
+    match mutate_list(
+        SCOPE_STACK_STATE_KEY.to_string(),
+        state,
+        |list| match list.pop() {
+            Some(state_value) => match state_value {
+                StateValue::Any(rc_value) => {
+                    let value_any = rc_value.borrow();
+
+                    match value_any.downcast_ref::<HashMap<String, String>>() {
+                        Some(old_variables) => {
+                            let mut new_variables = HashMap::new();
+                            for key in copy {
+                                let value = variables.remove(key);
+                                new_variables.insert(key, value);
+                            }
+
+                            variables.clear();
+
+                            for (key, value) in old_variables {
+                                variables.insert(key.to_string(), value.clone());
+                            }
+
+                            for (key, value) in new_variables {
+                                variables.insert(key.to_string(), value.unwrap());
+                            }
+
+                            Ok(None)
+                        }
+                        None => Err("Scope stack not available, invalid type.".to_string()),
+                    }
+                }
+                _ => Err("Scope stack not available, invalid state value type.".to_string()),
+            },
+            None => Err("Reached end of scope stack.".to_string()),
+        },
+    ) {
+        Ok(_) => Ok(()),
+        Err(error) => Err(error),
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/api/duckscript_sdk/src/duckscriptsdk/utils/state.rs.html b/docs/api/duckscript_sdk/src/duckscriptsdk/utils/state.rs.html index b0d4dd6..f766bf3 100644 --- a/docs/api/duckscript_sdk/src/duckscriptsdk/utils/state.rs.html +++ b/docs/api/duckscript_sdk/src/duckscriptsdk/utils/state.rs.html @@ -498,7 +498,7 @@ } } -fn ensure_list(key: &str, state: &mut HashMap<String, StateValue>) { +pub(crate) fn ensure_list(key: &str, state: &mut HashMap<String, StateValue>) { match state.get(key) { Some(value) => match value { StateValue::List(_) => (), diff --git a/duckscript_cli/Cargo.toml b/duckscript_cli/Cargo.toml index e400b93..9dae0ad 100644 --- a/duckscript_cli/Cargo.toml +++ b/duckscript_cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "duckscript_cli" -version = "0.6.1" +version = "0.6.2" authors = ["Sagie Gur-Ari "] description = "The duckscript command line executable." license = "Apache-2.0" @@ -28,7 +28,7 @@ path = "src/main.rs" [dependencies] duckscript = { version = "^0.5.0", path = "../duckscript" } -duckscriptsdk = { version = "^0.6.1", path = "../duckscript_sdk" } +duckscriptsdk = { version = "^0.6.2", path = "../duckscript_sdk" } [badges.codecov] branch = "master" diff --git a/duckscript_sdk/Cargo.toml b/duckscript_sdk/Cargo.toml index a0e1c08..ef106d7 100644 --- a/duckscript_sdk/Cargo.toml +++ b/duckscript_sdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "duckscriptsdk" -version = "0.6.1" +version = "0.6.2" authors = ["Sagie Gur-Ari "] description = "The duckscript SDK." license = "Apache-2.0"