diff --git a/kclvm/runtime/src/_kclvm.bc b/kclvm/runtime/src/_kclvm.bc index 9c21603c5..d1495da08 100644 Binary files a/kclvm/runtime/src/_kclvm.bc and b/kclvm/runtime/src/_kclvm.bc differ diff --git a/kclvm/runtime/src/_kclvm.h b/kclvm/runtime/src/_kclvm.h index cef33eeab..4966ffa09 100644 --- a/kclvm/runtime/src/_kclvm.h +++ b/kclvm/runtime/src/_kclvm.h @@ -652,10 +652,16 @@ kclvm_value_ref_t* kclvm_value_union_all(kclvm_context_t* ctx, kclvm_value_ref_t kclvm_value_ref_t* kclvm_yaml_decode(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_yaml_decode_all(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); + +kclvm_value_ref_t* kclvm_yaml_dump_all_to_file(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); + kclvm_value_ref_t* kclvm_yaml_dump_to_file(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); kclvm_value_ref_t* kclvm_yaml_encode(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +kclvm_value_ref_t* kclvm_yaml_encode_all(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); + #ifdef __cplusplus } // extern "C" #endif diff --git a/kclvm/runtime/src/_kclvm.ll b/kclvm/runtime/src/_kclvm.ll index da786c0bb..7f5cff0ff 100644 --- a/kclvm/runtime/src/_kclvm.ll +++ b/kclvm/runtime/src/_kclvm.ll @@ -600,10 +600,16 @@ declare %kclvm_value_ref_t* @kclvm_value_union_all(%kclvm_context_t* %ctx, %kclv declare %kclvm_value_ref_t* @kclvm_yaml_decode(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +declare %kclvm_value_ref_t* @kclvm_yaml_decode_all(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); + +declare %kclvm_value_ref_t* @kclvm_yaml_dump_all_to_file(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + declare %kclvm_value_ref_t* @kclvm_yaml_dump_to_file(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); declare %kclvm_value_ref_t* @kclvm_yaml_encode(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); +declare %kclvm_value_ref_t* @kclvm_yaml_encode_all(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + define void @__kcl_keep_link_runtime(%kclvm_value_ref_t* %_a, %kclvm_context_t* %_b) { call %kclvm_value_ref_t* @kclvm_value_None(%kclvm_context_t* %_b) ret void diff --git a/kclvm/runtime/src/_kclvm.rs b/kclvm/runtime/src/_kclvm.rs index 20e5c0814..64d13cec4 100644 --- a/kclvm/runtime/src/_kclvm.rs +++ b/kclvm/runtime/src/_kclvm.rs @@ -312,8 +312,11 @@ pub enum ApiFunc { kclvm_value_union, kclvm_value_union_all, kclvm_yaml_decode, + kclvm_yaml_decode_all, + kclvm_yaml_dump_all_to_file, kclvm_yaml_dump_to_file, kclvm_yaml_encode, + kclvm_yaml_encode_all, } impl std::fmt::Display for ApiFunc { diff --git a/kclvm/runtime/src/_kclvm_addr.rs b/kclvm/runtime/src/_kclvm_addr.rs index c94b1e462..873b2518a 100644 --- a/kclvm/runtime/src/_kclvm_addr.rs +++ b/kclvm/runtime/src/_kclvm_addr.rs @@ -341,8 +341,11 @@ pub fn _kclvm_get_fn_ptr_by_name(name: &str) -> u64 { "kclvm_value_union" => crate::kclvm_value_union as *const () as u64, "kclvm_value_union_all" => crate::kclvm_value_union_all as *const () as u64, "kclvm_yaml_decode" => crate::kclvm_yaml_decode as *const () as u64, + "kclvm_yaml_decode_all" => crate::kclvm_yaml_decode_all as *const () as u64, + "kclvm_yaml_dump_all_to_file" => crate::kclvm_yaml_dump_all_to_file as *const () as u64, "kclvm_yaml_dump_to_file" => crate::kclvm_yaml_dump_to_file as *const () as u64, "kclvm_yaml_encode" => crate::kclvm_yaml_encode as *const () as u64, + "kclvm_yaml_encode_all" => crate::kclvm_yaml_encode_all as *const () as u64, _ => panic!("unknown {name}"), } } diff --git a/kclvm/runtime/src/_kclvm_api_spec.rs b/kclvm/runtime/src/_kclvm_api_spec.rs index 37b979c2b..3f96732dc 100644 --- a/kclvm/runtime/src/_kclvm_api_spec.rs +++ b/kclvm/runtime/src/_kclvm_api_spec.rs @@ -1146,11 +1146,23 @@ // api-spec(c): kclvm_value_ref_t* kclvm_yaml_encode(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); // api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_yaml_encode(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); +// api-spec: kclvm_yaml_encode_all +// api-spec(c): kclvm_value_ref_t* kclvm_yaml_encode_all(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_yaml_encode_all(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + // api-spec: kclvm_yaml_decode // api-spec(c): kclvm_value_ref_t* kclvm_yaml_decode(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); // api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_yaml_decode(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +// api-spec: kclvm_yaml_decode_all +// api-spec(c): kclvm_value_ref_t* kclvm_yaml_decode_all(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_yaml_decode_all(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); + // api-spec: kclvm_yaml_dump_to_file // api-spec(c): kclvm_value_ref_t* kclvm_yaml_dump_to_file(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); // api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_yaml_dump_to_file(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); +// api-spec: kclvm_yaml_dump_all_to_file +// api-spec(c): kclvm_value_ref_t* kclvm_yaml_dump_all_to_file(kclvm_context_t* _ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); +// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_yaml_dump_all_to_file(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); + diff --git a/kclvm/runtime/src/value/val_plan.rs b/kclvm/runtime/src/value/val_plan.rs index 94bdae207..5fa4eda64 100644 --- a/kclvm/runtime/src/value/val_plan.rs +++ b/kclvm/runtime/src/value/val_plan.rs @@ -7,7 +7,6 @@ use std::rc::Rc; pub const KCL_PRIVATE_VAR_PREFIX: &str = "_"; const LIST_DICT_TEMP_KEY: &str = "$"; -const YAML_STREAM_SEP: &str = "\n---\n"; const SCHEMA_TYPE_META_ATTR: &str = "_type"; /// PlanOptions denotes the configuration required to execute the KCL diff --git a/kclvm/runtime/src/yaml/mod.rs b/kclvm/runtime/src/yaml/mod.rs index 90e2e7ec7..1653ad4bf 100644 --- a/kclvm/runtime/src/yaml/mod.rs +++ b/kclvm/runtime/src/yaml/mod.rs @@ -1,8 +1,9 @@ // Copyright 2021 The KCL Authors. All rights reserved. use crate::*; -// encode(data, sort_keys=False, ignore_private=False, ignore_none=False): +pub const YAML_STREAM_SEP: &str = "\n---\n"; +/// encode(data, sort_keys=False, ignore_private=False, ignore_none=False) #[no_mangle] #[runtime_fn] pub extern "C" fn kclvm_yaml_encode( @@ -20,9 +21,35 @@ pub extern "C" fn kclvm_yaml_encode( ); return s.into_raw(mut_ptr_as_ref(ctx)); } - panic!("encode() missing 1 required positional argument: 'value'") + panic!("encode_all() missing 1 required positional argument: 'data'") } +/// encode_all(data, sort_keys=False, ignore_private=False, ignore_none=False) +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_yaml_encode_all( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(arg0) = args.arg_i(0) { + let opts = kwargs_to_opts(kwargs); + let results = arg0 + .as_list_ref() + .values + .iter() + .map(|r| r.to_yaml_string_with_options(&opts)) + .collect::>(); + let s = ValueRef::str(&results.join(YAML_STREAM_SEP)); + return s.into_raw(mut_ptr_as_ref(ctx)); + } + panic!("encode() missing 1 required positional argument: 'data'") +} + +/// decode(value) #[no_mangle] #[runtime_fn] pub extern "C" fn kclvm_yaml_decode( @@ -42,6 +69,27 @@ pub extern "C" fn kclvm_yaml_decode( panic!("decode() missing 1 required positional argument: 'value'") } +/// decode_all(value) +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_yaml_decode_all( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + _kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + + let ctx = mut_ptr_as_ref(ctx); + if let Some(arg0) = args.arg_i(0) { + match ValueRef::from_yaml_stream(ctx, arg0.as_str().as_ref()) { + Ok(x) => return x.into_raw(ctx), + Err(err) => panic!("{}", err), + } + } + panic!("decode_all() missing 1 required positional argument: 'value'") +} + +/// dump_to_file(data, sort_keys=False, ignore_private=False, ignore_none=False) #[no_mangle] #[runtime_fn] pub extern "C" fn kclvm_yaml_dump_to_file( @@ -63,6 +111,34 @@ pub extern "C" fn kclvm_yaml_dump_to_file( panic!("dump_to_file() missing 2 required positional arguments: 'data' and 'filename'") } +/// dump_all_to_file(data, sort_keys=False, ignore_private=False, ignore_none=False) +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_yaml_dump_all_to_file( + _ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let kwargs = ptr_as_ref(kwargs); + + if let Some(data) = args.arg_i(0) { + if let Some(filename) = args.arg_i(0) { + let filename = filename.as_str(); + let opts = kwargs_to_opts(kwargs); + let results = data + .as_list_ref() + .values + .iter() + .map(|r| r.to_yaml_string_with_options(&opts)) + .collect::>(); + + std::fs::write(filename, results.join(YAML_STREAM_SEP)).expect("Unable to write file"); + } + } + panic!("dump_all_to_file() missing 2 required positional arguments: 'data' and 'filename'") +} + fn kwargs_to_opts(kwargs: &ValueRef) -> YamlEncodeOptions { let mut opts = YamlEncodeOptions::default(); if let Some(sort_keys) = kwargs.kwarg_bool("sort_keys", None) { diff --git a/kclvm/sema/src/builtin/system_module.rs b/kclvm/sema/src/builtin/system_module.rs index feee83dba..5760ec266 100644 --- a/kclvm/sema/src/builtin/system_module.rs +++ b/kclvm/sema/src/builtin/system_module.rs @@ -842,7 +842,14 @@ register_regex_member! { // ------------------------------ pub const YAML: &str = "yaml"; -pub const YAML_FUNCTION_NAMES: &[&str] = &["encode", "decode", "dump_to_file"]; +pub const YAML_FUNCTION_NAMES: &[&str] = &[ + "encode", + "encode_all", + "decode", + "decode_all", + "dump_to_file", + "dump_all_to_file", +]; macro_rules! register_yaml_member { ($($name:ident => $ty:expr)*) => ( pub const YAML_FUNCTION_TYPES: Lazy> = Lazy::new(|| { @@ -882,6 +889,35 @@ register_yaml_member! { false, Some(1), ) + encode_all => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "data".to_string(), + ty: Type::list_ref(Type::any_ref()), + has_default: false, + }, + Parameter { + name: "sort_keys".to_string(), + ty: Type::bool_ref(), + has_default: true, + }, + Parameter { + name: "ignore_private".to_string(), + ty: Type::bool_ref(), + has_default: true, + }, + Parameter { + name: "ignore_none".to_string(), + ty: Type::bool_ref(), + has_default: true, + }, + ], + r#"Serialize a sequence of KCL objects into a YAML stream str."#, + false, + Some(1), + ) decode => Type::function( None, Type::any_ref(), @@ -896,6 +932,20 @@ register_yaml_member! { false, None, ) + decode_all => Type::function( + None, + Type::list_ref(Type::any_ref()), + &[ + Parameter { + name: "value".to_string(), + ty: Type::str_ref(), + has_default: false, + }, + ], + r#"Parse all YAML documents in a stream and produce corresponding KCL objects."#, + false, + None, + ) dump_to_file => Type::function( None, Type::str_ref(), @@ -930,6 +980,40 @@ register_yaml_member! { false, Some(2), ) + dump_all_to_file => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "data".to_string(), + ty: Type::list_ref(Type::any_ref()), + has_default: false, + }, + Parameter { + name: "filename".to_string(), + ty: Type::str_ref(), + has_default: false, + }, + Parameter { + name: "sort_keys".to_string(), + ty: Type::bool_ref(), + has_default: true, + }, + Parameter { + name: "ignore_private".to_string(), + ty: Type::bool_ref(), + has_default: true, + }, + Parameter { + name: "ignore_none".to_string(), + ty: Type::bool_ref(), + has_default: true, + }, + ], + r#"Serialize a sequence of KCL objects into a YAML stream str and write it into the file `filename`."#, + false, + Some(2), + ) } // ------------------------------ diff --git a/kclvm/tools/src/LSP/src/notification.rs b/kclvm/tools/src/LSP/src/notification.rs index e82d7fb61..338c84f4e 100644 --- a/kclvm/tools/src/LSP/src/notification.rs +++ b/kclvm/tools/src/LSP/src/notification.rs @@ -94,7 +94,7 @@ impl LanguageServerState { let new_word_index = build_word_index_for_file_content(text.clone(), &text_document.uri); let binding = text_document.uri.path(); let file_path = Path::new(binding); //todo rename - let mut word_index_map = &mut *self.word_index_map.write(); + let word_index_map = &mut *self.word_index_map.write(); for (key, value) in word_index_map { let workspace_folder_path = Path::new(key.path()); if file_path.starts_with(workspace_folder_path) { diff --git a/test/grammar/builtins/yaml/decode_all_0/main.k b/test/grammar/builtins/yaml/decode_all_0/main.k new file mode 100644 index 000000000..af7f4da6d --- /dev/null +++ b/test/grammar/builtins/yaml/decode_all_0/main.k @@ -0,0 +1,11 @@ +import yaml + +yamlStrList = [ + 'key: value', + '- 1\n- 2\n- 3', + '1', + '1.1', + 'null', + 'true', +] +data = [yaml.decode_all(s) for s in yamlStrList] diff --git a/test/grammar/builtins/yaml/decode_all_0/stdout.golden b/test/grammar/builtins/yaml/decode_all_0/stdout.golden new file mode 100644 index 000000000..e5b0ffa4d --- /dev/null +++ b/test/grammar/builtins/yaml/decode_all_0/stdout.golden @@ -0,0 +1,19 @@ +yamlStrList: +- 'key: value' +- |- + - 1 + - 2 + - 3 +- '1' +- '1.1' +- 'null' +- 'true' +data: +- key: value +- - 1 + - 2 + - 3 +- 1 +- 1.1 +- null +- true diff --git a/test/grammar/builtins/yaml/decode_all_1/main.k b/test/grammar/builtins/yaml/decode_all_1/main.k new file mode 100644 index 000000000..e67562cfa --- /dev/null +++ b/test/grammar/builtins/yaml/decode_all_1/main.k @@ -0,0 +1,9 @@ +import yaml + +yamlStrList = [ + 'key1: value2\n---\nkey2: [1, 2, 3]', + '- 1\n- 2\n- 3\n---\nkey: value', + '1\n---\n2', + '1.1\n---\nnull\n---\ntrue\n---\nfalse', +] +data = [yaml.decode_all(s) for s in yamlStrList] diff --git a/test/grammar/builtins/yaml/decode_all_1/stdout.golden b/test/grammar/builtins/yaml/decode_all_1/stdout.golden new file mode 100644 index 000000000..2c4dac91d --- /dev/null +++ b/test/grammar/builtins/yaml/decode_all_1/stdout.golden @@ -0,0 +1,39 @@ +yamlStrList: +- |- + key1: value2 + --- + key2: [1, 2, 3] +- |- + - 1 + - 2 + - 3 + --- + key: value +- |- + 1 + --- + 2 +- |- + 1.1 + --- + null + --- + true + --- + false +data: +- - key1: value2 + - key2: + - 1 + - 2 + - 3 +- - - 1 + - 2 + - 3 + - key: value +- - 1 + - 2 +- - 1.1 + - null + - true + - false diff --git a/test/grammar/builtins/yaml/encode_0/_main.k b/test/grammar/builtins/yaml/encode_0/_main.k deleted file mode 100644 index da9c24ede..000000000 --- a/test/grammar/builtins/yaml/encode_0/_main.k +++ /dev/null @@ -1,11 +0,0 @@ -import yaml - -dataDict = {"key": "value"} -dataList = [1, 2, 3] -#dataInt = 1 -#dataFloat = 1.1 -#dataNone = None -#dataBool = True - -#yamlStr = [yaml.encode(data) for data in [dataDict, dataList, dataInt, dataFloat, dataNone, dataBool]] -yamlStr = [yaml.encode(data) for data in [dataDict, dataList]] diff --git a/test/grammar/builtins/yaml/encode_0/main.k b/test/grammar/builtins/yaml/encode_0/main.k new file mode 100644 index 000000000..51e77fba3 --- /dev/null +++ b/test/grammar/builtins/yaml/encode_0/main.k @@ -0,0 +1,6 @@ +import yaml + +dataDict = {"key": "value"} +dataList = [1, 2, 3] + +yamlStr = [yaml.encode(data) for data in [dataDict, dataList]] diff --git a/test/grammar/builtins/yaml/encode_1/_main.k b/test/grammar/builtins/yaml/encode_1/main.k similarity index 100% rename from test/grammar/builtins/yaml/encode_1/_main.k rename to test/grammar/builtins/yaml/encode_1/main.k diff --git a/test/grammar/builtins/yaml/encode_all_0/main.k b/test/grammar/builtins/yaml/encode_all_0/main.k new file mode 100644 index 000000000..f99c6b70a --- /dev/null +++ b/test/grammar/builtins/yaml/encode_all_0/main.k @@ -0,0 +1,6 @@ +import yaml + +dataDict = {"key": "value"} +dataList = [1, 2, 3] + +yamlStr = yaml.encode_all([dataDict, dataList]) diff --git a/test/grammar/builtins/yaml/encode_all_0/stdout.golden b/test/grammar/builtins/yaml/encode_all_0/stdout.golden new file mode 100644 index 000000000..7f546203d --- /dev/null +++ b/test/grammar/builtins/yaml/encode_all_0/stdout.golden @@ -0,0 +1,13 @@ +dataDict: + key: value +dataList: +- 1 +- 2 +- 3 +yamlStr: | + key: value + + --- + - 1 + - 2 + - 3 diff --git a/test/grammar/builtins/yaml/encode_all_1/main.k b/test/grammar/builtins/yaml/encode_all_1/main.k new file mode 100644 index 000000000..be26367f6 --- /dev/null +++ b/test/grammar/builtins/yaml/encode_all_1/main.k @@ -0,0 +1,3 @@ +import yaml + +yamlStr = yaml.encode_all([{"key": [1, 2, 3]}, [1, 2, 3]]) diff --git a/test/grammar/builtins/yaml/encode_all_1/stdout.golden b/test/grammar/builtins/yaml/encode_all_1/stdout.golden new file mode 100644 index 000000000..7484e6014 --- /dev/null +++ b/test/grammar/builtins/yaml/encode_all_1/stdout.golden @@ -0,0 +1,10 @@ +yamlStr: | + key: + - 1 + - 2 + - 3 + + --- + - 1 + - 2 + - 3 diff --git a/test/grammar/builtins/yaml/encode_all_2/main.k b/test/grammar/builtins/yaml/encode_all_2/main.k new file mode 100644 index 000000000..39c7e53db --- /dev/null +++ b/test/grammar/builtins/yaml/encode_all_2/main.k @@ -0,0 +1,3 @@ +import yaml + +yamlStr = yaml.encode_all([1, 2, 3]) diff --git a/test/grammar/builtins/yaml/encode_all_2/stdout.golden b/test/grammar/builtins/yaml/encode_all_2/stdout.golden new file mode 100644 index 000000000..f5df77f8d --- /dev/null +++ b/test/grammar/builtins/yaml/encode_all_2/stdout.golden @@ -0,0 +1,8 @@ +yamlStr: | + 1 + + --- + 2 + + --- + 3 diff --git a/test/grammar/builtins/yaml/output_0/_main.k b/test/grammar/builtins/yaml/output_0/main.k similarity index 54% rename from test/grammar/builtins/yaml/output_0/_main.k rename to test/grammar/builtins/yaml/output_0/main.k index d0c0fd63f..b48bae06c 100644 --- a/test/grammar/builtins/yaml/output_0/_main.k +++ b/test/grammar/builtins/yaml/output_0/main.k @@ -12,13 +12,5 @@ _person = Person { name: "Alice" age: 18 } -# print(yaml.encode(_person), end="") -# print("---") -# print(yaml.encode(_person, ignore_private=True), end="") -# print("---") -# print(yaml.encode(_person, ignore_none=True), end="") -# print("---") -# print(yaml.encode(_person, ignore_private=True, ignore_none=True), end="") - a1 = yaml.encode(_person, ignore_private=True) a2 = yaml.encode(_person, ignore_private=True, ignore_none=True)