From 3f037a50b1f162aa9affb331cf704527265f8b22 Mon Sep 17 00:00:00 2001 From: peefy Date: Tue, 5 Sep 2023 13:23:40 +0800 Subject: [PATCH] feat: enhance system package sematic definitions and sync spec. --- VERSION | 2 +- kclvm/runtime/src/_kclvm.h | 4 - kclvm/runtime/src/_kclvm.rs | 2 - kclvm/runtime/src/_kclvm_addr.rs | 2 - kclvm/runtime/src/_kclvm_api_spec.rs | 8 - kclvm/runtime/src/datetime/datetime.rs | 8 +- kclvm/runtime/src/json/json.rs | 44 +- kclvm/runtime/src/lib.rs | 3 - kclvm/runtime/src/math/math.rs | 41 +- kclvm/runtime/src/net/net.rs | 2 +- kclvm/runtime/src/regex/regex.rs | 12 +- kclvm/runtime/src/testing/mod.rs | 4 - kclvm/runtime/src/testing/testing.rs | 28 - kclvm/runtime/src/value/val_args.rs | 12 + kclvm/runtime/src/yaml/yaml.rs | 37 +- kclvm/sema/src/builtin/system_module.rs | 1483 +++++++++++++++++++++-- kclvm/sema/src/ty/constructor.rs | 10 +- 17 files changed, 1488 insertions(+), 214 deletions(-) delete mode 100644 kclvm/runtime/src/testing/mod.rs delete mode 100644 kclvm/runtime/src/testing/testing.rs diff --git a/VERSION b/VERSION index ad83b1b09..ec3e3be37 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.5.6 \ No newline at end of file +0.6.0-alpha.1 \ No newline at end of file diff --git a/kclvm/runtime/src/_kclvm.h b/kclvm/runtime/src/_kclvm.h index 3d4a3056b..25cdfd566 100644 --- a/kclvm/runtime/src/_kclvm.h +++ b/kclvm/runtime/src/_kclvm.h @@ -482,10 +482,6 @@ kclvm_value_ref_t* kclvm_schema_value_new(kclvm_context_t* ctx, kclvm_value_ref_ kclvm_size_t kclvm_strlen(uint8_t* ptr); -void kclvm_testing_arguments(kclvm_context_t* _ctx, kclvm_value_ref_t* _args, kclvm_value_ref_t* _kwargs); - -void kclvm_testing_setting_file(kclvm_context_t* _ctx, kclvm_value_ref_t* _args, kclvm_value_ref_t* _kwargs); - kclvm_value_ref_t* kclvm_units_to_G(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); kclvm_value_ref_t* kclvm_units_to_Gi(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); diff --git a/kclvm/runtime/src/_kclvm.rs b/kclvm/runtime/src/_kclvm.rs index 3b0ed7e48..348230c95 100644 --- a/kclvm/runtime/src/_kclvm.rs +++ b/kclvm/runtime/src/_kclvm.rs @@ -227,8 +227,6 @@ pub enum ApiFunc { kclvm_schema_value_check, kclvm_schema_value_new, kclvm_strlen, - kclvm_testing_arguments, - kclvm_testing_setting_file, kclvm_units_to_G, kclvm_units_to_Gi, kclvm_units_to_K, diff --git a/kclvm/runtime/src/_kclvm_addr.rs b/kclvm/runtime/src/_kclvm_addr.rs index 1ec97af69..07cd60818 100644 --- a/kclvm/runtime/src/_kclvm_addr.rs +++ b/kclvm/runtime/src/_kclvm_addr.rs @@ -244,8 +244,6 @@ pub fn _kclvm_get_fn_ptr_by_name(name: &str) -> u64 { "kclvm_schema_value_check" => crate::kclvm_schema_value_check as *const () as u64, "kclvm_schema_value_new" => crate::kclvm_schema_value_new as *const () as u64, "kclvm_strlen" => crate::kclvm_strlen as *const () as u64, - "kclvm_testing_arguments" => crate::kclvm_testing_arguments as *const () as u64, - "kclvm_testing_setting_file" => crate::kclvm_testing_setting_file as *const () as u64, "kclvm_units_to_G" => crate::kclvm_units_to_G as *const () as u64, "kclvm_units_to_Gi" => crate::kclvm_units_to_Gi as *const () as u64, "kclvm_units_to_K" => crate::kclvm_units_to_K as *const () as u64, diff --git a/kclvm/runtime/src/_kclvm_api_spec.rs b/kclvm/runtime/src/_kclvm_api_spec.rs index b608c2ad6..7cbfc4f4b 100644 --- a/kclvm/runtime/src/_kclvm_api_spec.rs +++ b/kclvm/runtime/src/_kclvm_api_spec.rs @@ -1190,14 +1190,6 @@ // api-spec(c): char* kclvm_plugin_invoke_json(int8_t* method, char* args, char* kwargs); // api-spec(llvm): declare i8* @kclvm_plugin_invoke_json(i8* %method, i8* %args, i8* %kwargs); -// api-spec: kclvm_testing_arguments -// api-spec(c): void kclvm_testing_arguments(kclvm_context_t* _ctx, kclvm_value_ref_t* _args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare void @kclvm_testing_arguments(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %_args, %kclvm_value_ref_t* %_kwargs); - -// api-spec: kclvm_testing_setting_file -// api-spec(c): void kclvm_testing_setting_file(kclvm_context_t* _ctx, kclvm_value_ref_t* _args, kclvm_value_ref_t* _kwargs); -// api-spec(llvm): declare void @kclvm_testing_setting_file(%kclvm_context_t* %_ctx, %kclvm_value_ref_t* %_args, %kclvm_value_ref_t* %_kwargs); - // api-spec: kclvm_units_to_n // api-spec(c): kclvm_value_ref_t* kclvm_units_to_n(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* kwargs); // api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_units_to_n(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %kwargs); diff --git a/kclvm/runtime/src/datetime/datetime.rs b/kclvm/runtime/src/datetime/datetime.rs index ee9378c1a..a94aeaa96 100644 --- a/kclvm/runtime/src/datetime/datetime.rs +++ b/kclvm/runtime/src/datetime/datetime.rs @@ -12,7 +12,7 @@ use crate::*; #[allow(non_camel_case_types)] type kclvm_value_ref_t = ValueRef; -// def KMANGLED_today() -> str: +// today() -> str: #[no_mangle] #[runtime_fn] @@ -25,7 +25,7 @@ pub unsafe extern "C" fn kclvm_datetime_today( return ValueRef::str(s.as_ref()).into_raw(); } -// def KMANGLED_now() -> str: +// now() -> str: #[no_mangle] #[runtime_fn] @@ -38,7 +38,7 @@ pub unsafe extern "C" fn kclvm_datetime_now( return ValueRef::str(s.as_ref()).into_raw(); } -// def KMANGLED_ticks() -> float: +// ticks() -> float: #[no_mangle] #[runtime_fn] @@ -51,7 +51,7 @@ pub unsafe extern "C" fn kclvm_datetime_ticks( ValueRef::float(x as f64).into_raw() } -// def KMANGLED_date() -> str: +// date() -> str: #[no_mangle] #[runtime_fn] diff --git a/kclvm/runtime/src/json/json.rs b/kclvm/runtime/src/json/json.rs index 3063ff28e..9e113addd 100644 --- a/kclvm/runtime/src/json/json.rs +++ b/kclvm/runtime/src/json/json.rs @@ -20,22 +20,11 @@ pub unsafe extern "C" fn kclvm_json_encode( let args = ptr_as_ref(args); let kwargs = ptr_as_ref(kwargs); - let mut opt = JsonEncodeOptions::default(); - if let Some(sort_keys) = kwargs.kwarg_bool("sort_keys", None) { - opt.sort_keys = sort_keys; - } - if let Some(indent) = kwargs.kwarg_int("indent", None) { - opt.indent = indent; - } - if let Some(ignore_private) = kwargs.kwarg_bool("ignore_private", None) { - opt.ignore_private = ignore_private; - } - if let Some(ignore_none) = kwargs.kwarg_bool("ignore_none", None) { - opt.ignore_none = ignore_none; - } - if let Some(arg0) = args.arg_i(0) { - let s = ValueRef::str(arg0.to_json_string_with_option(&opt).as_ref()); + let s = ValueRef::str( + arg0.to_json_string_with_option(&kwargs_to_opts(kwargs)) + .as_ref(), + ); return s.into_raw(); } panic!("encode() missing 1 required positional argument: 'value'") @@ -64,17 +53,34 @@ pub unsafe extern "C" fn kclvm_json_decode( pub unsafe extern "C" fn kclvm_json_dump_to_file( _ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, - _kwargs: *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 yaml = data.to_json_string(); let filename = filename.as_str(); - - std::fs::write(filename, yaml).expect("Unable to write file"); + let json = data.to_json_string_with_option(&kwargs_to_opts(kwargs)); + std::fs::write(filename, json).expect("Unable to write file"); } } panic!("dump_to_file() missing 2 required positional arguments: 'data' and 'filename'") } + +fn kwargs_to_opts(kwargs: &ValueRef) -> JsonEncodeOptions { + let mut opts = JsonEncodeOptions::default(); + if let Some(sort_keys) = kwargs.kwarg_bool("sort_keys", None) { + opts.sort_keys = sort_keys; + } + if let Some(indent) = kwargs.kwarg_int("indent", None) { + opts.indent = indent; + } + if let Some(ignore_private) = kwargs.kwarg_bool("ignore_private", None) { + opts.ignore_private = ignore_private; + } + if let Some(ignore_none) = kwargs.kwarg_bool("ignore_none", None) { + opts.ignore_none = ignore_none; + } + opts +} diff --git a/kclvm/runtime/src/lib.rs b/kclvm/runtime/src/lib.rs index 56191b709..1a2f398f3 100644 --- a/kclvm/runtime/src/lib.rs +++ b/kclvm/runtime/src/lib.rs @@ -98,9 +98,6 @@ pub use self::regex::*; pub mod stdlib; pub use self::stdlib::*; -pub mod testing; -pub use self::testing::*; - pub mod units; pub use self::units::*; diff --git a/kclvm/runtime/src/math/math.rs b/kclvm/runtime/src/math/math.rs index 149900a5e..f8a43a960 100644 --- a/kclvm/runtime/src/math/math.rs +++ b/kclvm/runtime/src/math/math.rs @@ -23,7 +23,7 @@ pub unsafe extern "C" fn kclvm_math_ceil( ) -> *const kclvm_value_ref_t { let args = ptr_as_ref(args); - if let Some(x) = args.arg_i_int(0, None) { + if let Some(x) = args.arg_i_int_or_bool(0, None) { return kclvm_value_Int(x); } if let Some(x) = args.arg_i_float(0, None) { @@ -55,7 +55,7 @@ pub unsafe extern "C" fn kclvm_math_factorial( let args = ptr_as_ref(args); - if let Some(x) = args.arg_i_int(0, None) { + if let Some(x) = args.arg_i_int_or_bool(0, None) { if x >= 0 { return kclvm_value_Int(factorial(x)); } @@ -65,6 +65,7 @@ pub unsafe extern "C" fn kclvm_math_factorial( return kclvm_value_Float(factorial(x as i64) as f64); } } + if args.args_len() > 0 { panic!("factorial() only accepts integral values") } @@ -80,7 +81,7 @@ pub unsafe extern "C" fn kclvm_math_floor( ) -> *const kclvm_value_ref_t { let args = ptr_as_ref(args); - if let Some(x) = args.arg_i_int(0, None) { + if let Some(x) = args.arg_i_int_or_bool(0, None) { return kclvm_value_Int(x); } if let Some(x) = args.arg_i_float(0, None) { @@ -120,12 +121,15 @@ pub unsafe extern "C" fn kclvm_math_isfinite( ) -> *const kclvm_value_ref_t { let args = ptr_as_ref(args); - if let Some(_x) = args.arg_i_int(0, None) { + if let Some(_) = args.arg_i_int_or_bool(0, None) { return kclvm_value_Bool(true as i8); } if let Some(x) = args.arg_i_float(0, None) { return kclvm_value_Bool(x.is_finite() as i8); } + if let Some(_) = args.arg_i_bool(0, None) { + return kclvm_value_Bool(true as i8); + } panic!("isfinite() takes exactly one argument (0 given)"); } @@ -139,12 +143,15 @@ pub unsafe extern "C" fn kclvm_math_isinf( ) -> *const kclvm_value_ref_t { let args = ptr_as_ref(args); - if let Some(_x) = args.arg_i_int(0, None) { + if let Some(_x) = args.arg_i_int_or_bool(0, None) { return kclvm_value_Bool(false as i8); } if let Some(x) = args.arg_i_float(0, None) { return kclvm_value_Bool(x.is_infinite() as i8); } + if let Some(_) = args.arg_i_bool(0, None) { + return kclvm_value_Bool(false as i8); + } panic!("isinf() takes exactly one argument (0 given)"); } @@ -158,7 +165,7 @@ pub unsafe extern "C" fn kclvm_math_isnan( ) -> *const kclvm_value_ref_t { let args = ptr_as_ref(args); - if let Some(_x) = args.arg_i_int(0, None) { + if let Some(_x) = args.arg_i_int_or_bool(0, None) { return kclvm_value_Bool(false as i8); } if let Some(x) = args.arg_i_float(0, None) { @@ -177,7 +184,7 @@ pub unsafe extern "C" fn kclvm_math_modf( ) -> *const kclvm_value_ref_t { let args = ptr_as_ref(args); - if let Some(x) = args.arg_i_int(0, None) { + if let Some(x) = args.arg_i_int_or_bool(0, None) { let list = ValueRef::list_float(&[0.0, x as f64]); return list.into_raw(); } @@ -207,7 +214,7 @@ pub unsafe extern "C" fn kclvm_math_exp( ) -> *const kclvm_value_ref_t { let args = ptr_as_ref(args); - if let Some(x) = args.arg_i_int(0, None) { + if let Some(x) = args.arg_i_int_or_bool(0, None) { return kclvm_value_Float((x as f64).exp()); } if let Some(x) = args.arg_i_float(0, None) { @@ -225,7 +232,7 @@ pub unsafe extern "C" fn kclvm_math_expm1( ) -> *const kclvm_value_ref_t { let args = ptr_as_ref(args); - if let Some(x) = args.arg_i_int(0, None) { + if let Some(x) = args.arg_i_int_or_bool(0, None) { return kclvm_value_Float((x as f64).exp_m1()); } if let Some(x) = args.arg_i_float(0, None) { @@ -243,7 +250,7 @@ pub unsafe extern "C" fn kclvm_math_log( ) -> *const kclvm_value_ref_t { let args = ptr_as_ref(args); - if let Some(x) = args.arg_i_int(0, None) { + if let Some(x) = args.arg_i_int_or_bool(0, None) { if let Some(base) = args.arg_i_float(1, Some(std::f64::consts::E)) { return kclvm_value_Int((x as f64).log(base) as i64); } @@ -265,7 +272,7 @@ pub unsafe extern "C" fn kclvm_math_log1p( ) -> *const kclvm_value_ref_t { let args = ptr_as_ref(args); - if let Some(x) = args.arg_i_int(0, None) { + if let Some(x) = args.arg_i_int_or_bool(0, None) { return kclvm_value_Float(((x + 1) as f64).ln_1p()); } if let Some(x) = args.arg_i_float(0, None) { @@ -283,7 +290,7 @@ pub unsafe extern "C" fn kclvm_math_log2( ) -> *const kclvm_value_ref_t { let args = ptr_as_ref(args); - if let Some(x) = args.arg_i_int(0, None) { + if let Some(x) = args.arg_i_int_or_bool(0, None) { return kclvm_value_Int((x as f64).log2() as i64); } if let Some(x) = args.arg_i_float(0, None) { @@ -301,7 +308,7 @@ pub unsafe extern "C" fn kclvm_math_log10( ) -> *const kclvm_value_ref_t { let args = ptr_as_ref(args); - if let Some(x) = args.arg_i_int(0, None) { + if let Some(x) = args.arg_i_int_or_bool(0, None) { return kclvm_value_Float((x as f64).log10()); } if let Some(x) = args.arg_i_float(0, None) { @@ -319,8 +326,8 @@ pub unsafe extern "C" fn kclvm_math_pow( ) -> *const kclvm_value_ref_t { let args = ptr_as_ref(args); - if let Some(x) = args.arg_i_int(0, None) { - if let Some(n) = args.arg_i_int(1, None) { + if let Some(x) = args.arg_i_int_or_bool(0, None) { + if let Some(n) = args.arg_i_int_or_bool(1, None) { if n < 0 { return kclvm_value_Float((x as f64).powf(n as f64)); } else { @@ -332,7 +339,7 @@ pub unsafe extern "C" fn kclvm_math_pow( } } if let Some(x) = args.arg_i_float(0, None) { - if let Some(n) = args.arg_i_int(1, None) { + if let Some(n) = args.arg_i_int_or_bool(1, None) { return kclvm_value_Float(x.powi(n as i32)); } if let Some(n) = args.arg_i_float(1, None) { @@ -351,7 +358,7 @@ pub unsafe extern "C" fn kclvm_math_sqrt( ) -> *const kclvm_value_ref_t { let args = ptr_as_ref(args); - if let Some(x) = args.arg_i_int(0, None) { + if let Some(x) = args.arg_i_int_or_bool(0, None) { return kclvm_value_Float((x as f64).sqrt()); } if let Some(x) = args.arg_i_float(0, None) { diff --git a/kclvm/runtime/src/net/net.rs b/kclvm/runtime/src/net/net.rs index e5fafc248..bc7d6614b 100644 --- a/kclvm/runtime/src/net/net.rs +++ b/kclvm/runtime/src/net/net.rs @@ -132,7 +132,7 @@ pub unsafe extern "C" fn kclvm_net_IP_string( return ValueRef::str(s.as_ref()).into_raw(); } - return kclvm_value_False(); + return ValueRef::str("").into_raw(); } panic!("IP_string() missing 1 required positional argument: 'ip'"); diff --git a/kclvm/runtime/src/regex/regex.rs b/kclvm/runtime/src/regex/regex.rs index 01ff95903..573b1800c 100644 --- a/kclvm/runtime/src/regex/regex.rs +++ b/kclvm/runtime/src/regex/regex.rs @@ -16,7 +16,7 @@ use crate::*; #[allow(non_camel_case_types)] type kclvm_value_ref_t = ValueRef; -// def KMANGLED_match(string: str, pattern: str) -> bool: +// match(string: str, pattern: str) -> bool: #[no_mangle] #[runtime_fn] @@ -46,7 +46,7 @@ pub unsafe extern "C" fn kclvm_regex_match( panic!("match() missing 2 required positional arguments: 'string' and 'pattern'") } -// def KMANGLED_replace(string: str, pattern: str, replace: str, count: int = 0): +// replace(string: str, pattern: str, replace: str, count: int = 0): #[no_mangle] #[runtime_fn] @@ -71,7 +71,7 @@ pub unsafe extern "C" fn kclvm_regex_replace( panic!("replace() missing 3 required positional arguments: 'string', 'pattern', and 'replace"); } -// def KMANGLED_compile(pattern: str) -> bool: +// compile(pattern: str) -> bool: #[no_mangle] #[runtime_fn] @@ -91,7 +91,7 @@ pub unsafe extern "C" fn kclvm_regex_compile( panic!("compile() missing 2 required positional arguments: 'string' and 'pattern'") } -// def KMANGLED_findall(string: str, pattern: str) -> [str]: +// findall(string: str, pattern: str) -> [str]: #[no_mangle] #[runtime_fn] @@ -130,7 +130,7 @@ pub unsafe extern "C" fn kclvm_regex_findall( panic!("findall() missing 2 required positional arguments: 'string' and 'pattern'") } -// def KMANGLED_search(string: str, pattern: str): +// search(string: str, pattern: str): #[no_mangle] #[runtime_fn] @@ -154,7 +154,7 @@ pub unsafe extern "C" fn kclvm_regex_search( panic!("search() missing 2 required positional arguments: 'string' and 'pattern'"); } -// def KMANGLED_split(string: str, pattern: str, maxsplit: int = 0): +// split(string: str, pattern: str, maxsplit: int = 0): #[no_mangle] #[runtime_fn] diff --git a/kclvm/runtime/src/testing/mod.rs b/kclvm/runtime/src/testing/mod.rs deleted file mode 100644 index c4034afa8..000000000 --- a/kclvm/runtime/src/testing/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright 2021 The KCL Authors. All rights reserved. - -pub mod testing; -pub use self::testing::*; diff --git a/kclvm/runtime/src/testing/testing.rs b/kclvm/runtime/src/testing/testing.rs deleted file mode 100644 index 3a16ad538..000000000 --- a/kclvm/runtime/src/testing/testing.rs +++ /dev/null @@ -1,28 +0,0 @@ -//! KCL testing system module -//! -//! Copyright 2021 The KCL Authors. All rights reserved. - -use crate::*; - -#[allow(non_camel_case_types)] -type kclvm_value_ref_t = ValueRef; - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_testing_arguments( - _ctx: *mut kclvm_context_t, - _args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) { - // Nothing to do -} - -#[no_mangle] -#[runtime_fn] -pub extern "C" fn kclvm_testing_setting_file( - _ctx: *mut kclvm_context_t, - _args: *const kclvm_value_ref_t, - _kwargs: *const kclvm_value_ref_t, -) { - // Nothing to do -} diff --git a/kclvm/runtime/src/value/val_args.rs b/kclvm/runtime/src/value/val_args.rs index b70bf4253..3702a0658 100644 --- a/kclvm/runtime/src/value/val_args.rs +++ b/kclvm/runtime/src/value/val_args.rs @@ -89,6 +89,18 @@ impl ValueRef { default } + pub fn arg_i_int_or_bool(&self, i: usize, default: Option) -> Option { + if let Some(x) = self.arg_i(i) { + match *x.rc.borrow() { + Value::bool_value(v) => return Some(v as i64), + Value::int_value(v) => return Some(v), + Value::none => return default, + _ => return None, + } + } + default + } + pub fn arg_i_float(&self, i: usize, default: Option) -> Option { if let Some(x) = self.arg_i(i) { match *x.rc.borrow() { diff --git a/kclvm/runtime/src/yaml/yaml.rs b/kclvm/runtime/src/yaml/yaml.rs index 4dbb54165..b2ceb4215 100644 --- a/kclvm/runtime/src/yaml/yaml.rs +++ b/kclvm/runtime/src/yaml/yaml.rs @@ -8,7 +8,7 @@ use crate::*; #[allow(non_camel_case_types)] type kclvm_value_ref_t = ValueRef; -// def KMANGLED_encode(data, sort_keys=False, ignore_private=False, ignore_none=False): +// encode(data, sort_keys=False, ignore_private=False, ignore_none=False): #[no_mangle] #[runtime_fn] @@ -20,19 +20,11 @@ pub unsafe extern "C" fn kclvm_yaml_encode( let args = ptr_as_ref(args); let kwargs = ptr_as_ref(kwargs); - let mut opt = YamlEncodeOptions::default(); - if let Some(sort_keys) = kwargs.kwarg_bool("sort_keys", None) { - opt.sort_keys = sort_keys; - } - if let Some(ignore_private) = kwargs.kwarg_bool("ignore_private", None) { - opt.ignore_private = ignore_private; - } - if let Some(ignore_none) = kwargs.kwarg_bool("ignore_none", None) { - opt.ignore_none = ignore_none; - } - if let Some(arg0) = args.arg_i(0) { - let s = ValueRef::str(arg0.to_yaml_string_with_options(&opt).as_ref()); + let s = ValueRef::str( + arg0.to_yaml_string_with_options(&kwargs_to_opts(kwargs)) + .as_ref(), + ); return s.into_raw(); } panic!("encode() missing 1 required positional argument: 'value'") @@ -61,17 +53,32 @@ pub unsafe extern "C" fn kclvm_yaml_decode( pub unsafe extern "C" fn kclvm_yaml_dump_to_file( _ctx: *mut kclvm_context_t, args: *const kclvm_value_ref_t, - _kwargs: *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 yaml = data.to_yaml_string(); let filename = filename.as_str(); + let yaml = data.to_yaml_string_with_options(&kwargs_to_opts(kwargs)); std::fs::write(filename, yaml).expect("Unable to write file"); } } panic!("dump_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) { + opts.sort_keys = sort_keys; + } + if let Some(ignore_private) = kwargs.kwarg_bool("ignore_private", None) { + opts.ignore_private = ignore_private; + } + if let Some(ignore_none) = kwargs.kwarg_bool("ignore_none", None) { + opts.ignore_none = ignore_none; + } + opts +} diff --git a/kclvm/sema/src/builtin/system_module.rs b/kclvm/sema/src/builtin/system_module.rs index accb49dc2..6218d1f40 100644 --- a/kclvm/sema/src/builtin/system_module.rs +++ b/kclvm/sema/src/builtin/system_module.rs @@ -6,8 +6,12 @@ use crate::ty::{Parameter, Type, TypeRef}; use indexmap::IndexMap; use once_cell::sync::Lazy; +// ------------------------------ +// base64 system package +// ------------------------------ + pub const BASE64: &str = "base64"; -pub const BASE64_FUNCTION_NAMES: [&str; 2] = ["encode", "decode"]; +pub const BASE64_FUNCTION_NAMES: &[&str] = &["encode", "decode"]; macro_rules! register_base64_member { ($($name:ident => $ty:expr)*) => ( pub const BASE64_FUNCTION_TYPES: Lazy> = Lazy::new(|| { @@ -16,9 +20,1097 @@ macro_rules! register_base64_member { builtin_mapping }); ) -} -register_base64_member! { - encode => Type::function( +} +register_base64_member! { + encode => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "value".to_string(), + ty: Type::str_ref(), + has_default: false, + }, + Parameter { + name: "encoding".to_string(), + ty: Type::str_ref(), + has_default: true, + }, + ], + r#"Encode the string `value` using the codec registered for encoding."#, + false, + None, + ) + decode => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "value".to_string(), + ty: Type::str_ref(), + has_default: false, + }, + Parameter { + name: "encoding".to_string(), + ty: Type::str_ref(), + has_default: true, + }, + ], + r#"Decode the string `value` using the codec registered for encoding."#, + false, + None, + ) +} + +// ------------------------------ +// net system package +// ------------------------------ + +pub const NET: &str = "net"; +pub const NET_FUNCTION_NAMES: &[&str] = &[ + "split_host_port", + "join_host_port", + "fqdn", + "parse_IP", + "to_IP4", + "to_IP16", + "IP_string", + "is_IPv4", + "is_IP", + "is_loopback_IP", + "is_multicast_IP", + "is_interface_local_multicast_IP", + "is_link_local_multicast_IP", + "is_link_local_unicast_IP", + "is_global_unicast_IP", + "is_unspecified_IP", +]; +macro_rules! register_net_member { + ($($name:ident => $ty:expr)*) => ( + pub const NET_FUNCTION_TYPES: Lazy> = Lazy::new(|| { + let mut builtin_mapping = IndexMap::default(); + $( builtin_mapping.insert(stringify!($name).to_string(), $ty); )* + builtin_mapping + }); + ) +} +register_net_member! { + split_host_port => Type::function( + None, + Type::list_ref(Type::str_ref()), + &[ + Parameter { + name: "ip_end_point".to_string(), + ty: Type::str_ref(), + has_default: false, + }, + ], + r#"Split the `host` and `port` from the `ip_end_point`."#, + false, + None, + ) + join_host_port => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "host".to_string(), + ty: Type::str_ref(), + has_default: false, + }, + Parameter { + name: "port".to_string(), + ty: Type::union_ref(&[Type::int_ref(), Type::str_ref()]), + has_default: false, + }, + ], + r#"Merge the `host` and `port`."#, + false, + None, + ) + fqdn => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "name".to_string(), + ty: Type::str_ref(), + has_default: true, + }, + ], + r#"Return Fully Qualified Domain Name (FQDN)."#, + false, + None, + ) + parse_IP => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "ip".to_string(), + ty: Type::str_ref(), + has_default: false, + }, + ], + r#"Parse ip to a real IP address."#, + false, + None, + ) + IP_string => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "ip".to_string(), + ty: Type::str_ref(), + has_default: false, + }, + ], + r#"Get the IP string."#, + false, + None, + ) + to_IP4 => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "ip".to_string(), + ty: Type::str_ref(), + has_default: false, + }, + ], + r#"Get the IP4 form of ip."#, + false, + None, + ) + to_IP16 => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "ip".to_string(), + ty: Type::str_ref(), + has_default: false, + }, + ], + r#"Get the IP16 form of ip."#, + false, + None, + ) + is_IPv4 => Type::function( + None, + Type::bool_ref(), + &[ + Parameter { + name: "ip".to_string(), + ty: Type::str_ref(), + has_default: false, + }, + ], + r#"Whether ip is a IPv4 one."#, + false, + None, + ) + is_IP =>Type::function( + None, + Type::bool_ref(), + &[ + Parameter { + name: "ip".to_string(), + ty: Type::str_ref(), + has_default: false, + }, + ], + r#"Whether ip is a valid ip address."#, + false, + None, + ) + is_loopback_IP =>Type::function( + None, + Type::bool_ref(), + &[ + Parameter { + name: "ip".to_string(), + ty: Type::str_ref(), + has_default: false, + }, + ], + r#"Whether ip is a loopback one."#, + false, + None, + ) + is_multicast_IP =>Type::function( + None, + Type::bool_ref(), + &[ + Parameter { + name: "ip".to_string(), + ty: Type::str_ref(), + has_default: false, + }, + ], + r#"Whether ip is a multicast one."#, + false, + None, + ) + is_interface_local_multicast_IP => Type::function( + None, + Type::bool_ref(), + &[ + Parameter { + name: "ip".to_string(), + ty: Type::str_ref(), + has_default: false, + }, + ], + r#"Whether ip is a interface, local and multicast one."#, + false, + None, + ) + is_link_local_multicast_IP =>Type::function( + None, + Type::bool_ref(), + &[ + Parameter { + name: "ip".to_string(), + ty: Type::str_ref(), + has_default: false, + }, + ], + r#"Whether ip is a link local and multicast one."#, + false, + None, + ) + is_link_local_unicast_IP =>Type::function( + None, + Type::bool_ref(), + &[ + Parameter { + name: "ip".to_string(), + ty: Type::str_ref(), + has_default: false, + }, + ], + r#"Whether ip is a link local and unicast one."#, + false, + None, + ) + is_global_unicast_IP =>Type::function( + None, + Type::bool_ref(), + &[ + Parameter { + name: "ip".to_string(), + ty: Type::str_ref(), + has_default: false, + }, + ], + r#"Whether ip is a global and unicast one."#, + false, + None, + ) + is_unspecified_IP => Type::function( + None, + Type::bool_ref(), + &[ + Parameter { + name: "ip".to_string(), + ty: Type::str_ref(), + has_default: false, + }, + ], + r#"Whether ip is a unspecified one."#, + false, + None, + ) +} + +// ------------------------------ +// manifests system package +// ------------------------------ + +pub const MANIFESTS: &str = "manifests"; +pub const MANIFESTS_FUNCTION_NAMES: &[&str] = &["yaml_stream"]; +macro_rules! register_manifests_member { + ($($name:ident => $ty:expr)*) => ( + pub const MANIFESTS_FUNCTION_TYPES: Lazy> = Lazy::new(|| { + let mut builtin_mapping = IndexMap::default(); + $( builtin_mapping.insert(stringify!($name).to_string(), $ty); )* + builtin_mapping + }); + ) +} +register_manifests_member! { + yaml_stream => Type::function( + None, + Type::any_ref(), + &[ + Parameter { + name: "values".to_string(), + ty: Type::str_ref(), + has_default: false, + }, + Parameter { + name: "values".to_string(), + ty: Type::dict_ref(Type::str_ref(), Type::any_ref()), + has_default: true, + }, + ], + r#"""This function is used to serialize the KCL object list into YAML output with the --- separator. It has two parameters: ++ values - A list of KCL objects ++ opts - The YAML serialization options + + sort_keys: Whether to sort the serialized results in the dictionary order of attribute names (the default is False). + + ignore_private: Whether to ignore the attribute output whose name starts with the character _ (the default value is True). + + ignore_none: Whether to ignore the attribute with the value of' None '(the default value is False). + + sep: Set the separator between multiple YAML documents (the default value is "---"). +"""#, + false, + None, + ) +} + +// ------------------------------ +// math system package +// ------------------------------ + +pub const MATH: &str = "math"; +pub const MATH_FUNCTION_NAMES: &[&str] = &[ + "ceil", + "factorial", + "floor", + "gcd", + "isfinite", + "isinf", + "isnan", + "modf", + "exp", + "expm1", + "log", + "log1p", + "log2", + "log10", + "pow", + "sqrt", +]; +macro_rules! register_math_member { + ($($name:ident => $ty:expr)*) => ( + pub const MATH_FUNCTION_TYPES: Lazy> = Lazy::new(|| { + let mut builtin_mapping = IndexMap::default(); + $( builtin_mapping.insert(stringify!($name).to_string(), $ty); )* + builtin_mapping + }); + ) +} +register_math_member! { + ceil => Type::function( + None, + Type::int_ref(), + &[ + Parameter { + name: "x".to_string(), + ty: Type::number(), + has_default: false, + }, + ], + r#"Return the ceiling of `x` as an Integral. This is the smallest integer >= `x`."#, + false, + None, + ) + factorial => Type::function( + None, + Type::int_ref(), + &[ + Parameter { + name: "x".to_string(), + ty: Type::number(), + has_default: false, + }, + ], + r#"Return `x`!. Raise a error if `x` is negative or non-integral."#, + false, + None, + ) + floor => Type::function( + None, + Type::int_ref(), + &[ + Parameter { + name: "x".to_string(), + ty: Type::number(), + has_default: false, + }, + ], + r#"Return the floor of `x` as an Integral. This is the largest integer <= `x`."#, + false, + None, + ) + gcd => Type::function( + None, + Type::int_ref(), + &[ + Parameter { + name: "a".to_string(), + ty: Type::int_ref(), + has_default: false, + }, + Parameter { + name: "b".to_string(), + ty: Type::int_ref(), + has_default: false, + }, + ], + r#"Return the greatest common divisor of `x` and `y`."#, + false, + None, + ) + isfinite => Type::function( + None, + Type::bool_ref(), + &[ + Parameter { + name: "x".to_string(), + ty: Type::number(), + has_default: false, + }, + ], + r#"Return `True` if `x` is neither an infinity nor a NaN, and `False` otherwise."#, + false, + None, + ) + isinf => Type::function( + None, + Type::bool_ref(), + &[ + Parameter { + name: "x".to_string(), + ty: Type::number(), + has_default: false, + }, + ], + r#"Return `True` if `x` is a positive or negative infinity, and `False` otherwise."#, + false, + None, + ) + isnan => Type::function( + None, + Type::bool_ref(), + &[ + Parameter { + name: "x".to_string(), + ty: Type::number(), + has_default: false, + }, + ], + r#"Return `True` if `x` is a NaN (not a number), and `False` otherwise."#, + false, + None, + ) + modf => Type::function( + None, + Type::list_ref(Type::float_ref()), + &[ + Parameter { + name: "x".to_string(), + ty: Type::number(), + has_default: false, + }, + ], + r#"Return the fractional and integer parts of `x`. Both results carry the sign of `x` and are floats."#, + false, + None, + ) + exp => Type::function( + None, + Type::float_ref(), + &[ + Parameter { + name: "x".to_string(), + ty: Type::number(), + has_default: false, + }, + ], + r#"Return `e` raised to the power of `x`."#, + false, + None, + ) + expm1 => Type::function( + None, + Type::float_ref(), + &[ + Parameter { + name: "x".to_string(), + ty: Type::number(), + has_default: false, + }, + ], + r#"Return `exp(x) - 1`. This function avoids the loss of precision involved in the direct evaluation of `exp(x) - 1` for small `x`."#, + false, + None, + ) + log => Type::function( + None, + Type::float_ref(), + &[ + Parameter { + name: "x".to_string(), + ty: Type::number(), + has_default: false, + }, + Parameter { + name: "e".to_string(), + ty: Type::float_ref(), + has_default: true, + }, + ], + r#"Return the logarithm of `x` to the base `e`."#, + false, + None, + ) + log1p => Type::function( + None, + Type::float_ref(), + &[ + Parameter { + name: "x".to_string(), + ty: Type::number(), + has_default: false, + }, + ], + r#"Return the natural logarithm of `1+x` (base `e`). The result is computed in a way which is accurate for `x` near zero."#, + false, + None, + ) + log2 => Type::function( + None, + Type::float_ref(), + &[ + Parameter { + name: "x".to_string(), + ty: Type::number(), + has_default: false, + }, + ], + r#"Return the base 2 logarithm of x."#, + false, + None, + ) + log10 => Type::function( + None, + Type::float_ref(), + &[ + Parameter { + name: "x".to_string(), + ty: Type::number(), + has_default: false, + }, + ], + r#"Return the base 10 logarithm of `x`."#, + false, + None, + ) + pow => Type::function( + None, + Type::float_ref(), + &[ + Parameter { + name: "x".to_string(), + ty: Type::number(), + has_default: false, + }, + Parameter { + name: "y".to_string(), + ty: Type::number(), + has_default: false, + }, + ], + r#"Return `x**y` (`x` to the power of `y`)."#, + false, + None, + ) + sqrt => Type::function( + None, + Type::float_ref(), + &[ + Parameter { + name: "x".to_string(), + ty: Type::number(), + has_default: false, + }, + ], + r#"Return the square root of `x`."#, + false, + None, + ) +} + +// ------------------------------ +// datetime system package +// ------------------------------ + +pub const DATETIME: &str = "datetime"; +pub const DATETIME_FUNCTION_NAMES: [&str; 4] = ["today", "now", "ticks", "date"]; +macro_rules! register_datetime_member { + ($($name:ident => $ty:expr)*) => ( + pub const DATETIME_FUNCTION_TYPES: Lazy> = Lazy::new(|| { + let mut builtin_mapping = IndexMap::default(); + $( builtin_mapping.insert(stringify!($name).to_string(), $ty); )* + builtin_mapping + }); + ) +} +register_datetime_member! { + ticks => Type::function( + None, + Type::float_ref(), + &[], + r#"Return the current time in seconds since the Epoch. Fractions of a second may be present if the system clock provides them."#, + false, + None, + ) + date => Type::function( + None, + Type::str_ref(), + &[], + r#"Return the `%Y-%m-%d %H:%M:%S` format date."#, + false, + None, + ) + now => Type::function( + None, + Type::str_ref(), + &[], + r#"Return the local time. e.g. 'Sat Jun 06 16:26:11 1998'."#, + false, + None, + ) + today => Type::function( + None, + Type::str_ref(), + &[], + r#"Return the `%Y-%m-%d %H:%M:%S.%{ticks}` format date."#, + false, + None, + ) +} + +// ------------------------------ +// regex system package +// ------------------------------ + +pub const REGEX: &str = "regex"; +pub const REGEX_FUNCTION_NAMES: &[&str] = + &["replace", "match", "compile", "findall", "search", "split"]; +macro_rules! register_regex_member { + ($($name:ident => $ty:expr)*) => ( + pub const REGEX_FUNCTION_TYPES: Lazy> = Lazy::new(|| { + let mut builtin_mapping = IndexMap::default(); + $( builtin_mapping.insert(stringify!($name).to_string(), $ty); )* + builtin_mapping + }); + ) +} +register_regex_member! { + replace => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "string".to_string(), + ty: Type::str_ref(), + has_default: false, + }, + Parameter { + name: "pattern".to_string(), + ty: Type::str_ref(), + has_default: false, + }, + Parameter { + name: "replace".to_string(), + ty: Type::str_ref(), + has_default: false, + }, + Parameter { + name: "count".to_string(), + ty: Type::int_ref(), + has_default: true, + }, + ], + r#"Return the string obtained by replacing the leftmost non-overlapping occurrences of the pattern in string by the replacement."#, + false, + None, + ) + match => Type::function( + None, + Type::bool_ref(), + &[ + Parameter { + name: "string".to_string(), + ty: Type::str_ref(), + has_default: false, + }, + Parameter { + name: "pattern".to_string(), + ty: Type::str_ref(), + has_default: false, + }, + ], + r#"Try to apply the pattern at the start of the string, returning a bool value `True` if any match was found, or `False` if no match was found."#, + false, + None, + ) + compile => Type::function( + None, + Type::bool_ref(), + &[ + Parameter { + name: "pattern".to_string(), + ty: Type::str_ref(), + has_default: false, + }, + ], + r#"Compile a regular expression pattern, returning a bool value denoting whether the pattern is valid."#, + false, + None, + ) + findall => Type::function( + None, + Type::list_ref(Type::str_ref()), + &[ + Parameter { + name: "string".to_string(), + ty: Type::str_ref(), + has_default: false, + }, + Parameter { + name: "pattern".to_string(), + ty: Type::str_ref(), + has_default: false, + }, + ], + r#"Return a list of all non-overlapping matches in the string."#, + false, + None, + ) + search => Type::function( + None, + Type::bool_ref(), + &[ + Parameter { + name: "string".to_string(), + ty: Type::str_ref(), + has_default: false, + }, + Parameter { + name: "pattern".to_string(), + ty: Type::str_ref(), + has_default: false, + }, + ], + r#"Scan through string looking for a match to the pattern, returning a bool value `True` if any match was found, or `False` if no match was found."#, + false, + None, + ) + split => Type::function( + None, + Type::list_ref(Type::str_ref()), + &[ + Parameter { + name: "string".to_string(), + ty: Type::str_ref(), + has_default: false, + }, + Parameter { + name: "pattern".to_string(), + ty: Type::str_ref(), + has_default: false, + }, + Parameter { + name: "maxsplit".to_string(), + ty: Type::int_ref(), + has_default: true, + }, + ], + r#"Return a list composed of words from the string, splitting up to a maximum of `maxsplit` times using `pattern` as the separator."#, + false, + None, + ) +} + +// ------------------------------ +// yaml system package +// ------------------------------ + +pub const YAML: &str = "yaml"; +pub const YAML_FUNCTION_NAMES: &[&str] = &["encode", "decode", "dump_to_file"]; +macro_rules! register_yaml_member { + ($($name:ident => $ty:expr)*) => ( + pub const YAML_FUNCTION_TYPES: Lazy> = Lazy::new(|| { + let mut builtin_mapping = IndexMap::default(); + $( builtin_mapping.insert(stringify!($name).to_string(), $ty); )* + builtin_mapping + }); + ) +} +register_yaml_member! { + encode => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "data".to_string(), + ty: 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 KCL object `data` to a YAML formatted str."#, + false, + Some(1), + ) + decode => Type::function( + None, + Type::any_ref(), + &[ + Parameter { + name: "value".to_string(), + ty: Type::str_ref(), + has_default: false, + }, + ], + r#"Deserialize `value` (a string instance containing a YAML document) to a KCL object."#, + false, + None, + ) + dump_to_file => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "data".to_string(), + ty: 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 KCL object `data` to a YAML formatted str and write it into the file `filename`."#, + false, + Some(2), + ) +} + +// ------------------------------ +// json system package +// ------------------------------ + +pub const JSON: &str = "json"; +pub const JSON_FUNCTION_NAMES: &[&str] = &["encode", "decode", "dump_to_file"]; +macro_rules! register_json_member { + ($($name:ident => $ty:expr)*) => ( + pub const JSON_FUNCTION_TYPES: Lazy> = Lazy::new(|| { + let mut builtin_mapping = IndexMap::default(); + $( builtin_mapping.insert(stringify!($name).to_string(), $ty); )* + builtin_mapping + }); + ) +} +register_json_member! { + encode => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "data".to_string(), + ty: Type::any_ref(), + has_default: false, + }, + Parameter { + name: "sort_keys".to_string(), + ty: Type::bool_ref(), + has_default: true, + }, + Parameter { + name: "indent".to_string(), + ty: Type::int_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 KCL object `data` to a JSON formatted str."#, + false, + Some(1), + ) + decode => Type::function( + None, + Type::any_ref(), + &[ + Parameter { + name: "value".to_string(), + ty: Type::str_ref(), + has_default: false, + }, + ], + r#"Deserialize `value` (a string instance containing a JSON document) to a KCL object."#, + false, + None, + ) + dump_to_file => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "data".to_string(), + ty: 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: "indent".to_string(), + ty: Type::int_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 KCL object `data` to a YAML formatted str and write it into the file `filename`."#, + false, + Some(2), + ) +} + +// ------------------------------ +// crypto system package +// ------------------------------ + +pub const CRYPTO: &str = "crypto"; +pub const CRYPTO_FUNCTION_NAMES: &[&str] = &["md5", "sha1", "sha224", "sha256", "sha384", "sha512"]; +macro_rules! register_crypto_member { + ($($name:ident => $ty:expr)*) => ( + pub const CRYPTO_FUNCTION_TYPES: Lazy> = Lazy::new(|| { + let mut builtin_mapping = IndexMap::default(); + $( builtin_mapping.insert(stringify!($name).to_string(), $ty); )* + builtin_mapping + }); + ) +} +register_crypto_member! { + md5 => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "value".to_string(), + ty: Type::str_ref(), + has_default: false, + }, + Parameter { + name: "encoding".to_string(), + ty: Type::str_ref(), + has_default: true, + }, + ], + r#"Encrypt the string `value` using `MD5` and the codec registered for encoding."#, + false, + None, + ) + sha1 => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "value".to_string(), + ty: Type::str_ref(), + has_default: false, + }, + Parameter { + name: "encoding".to_string(), + ty: Type::str_ref(), + has_default: true, + }, + ], + r#"Encrypt the string `value` using `SHA1` and the codec registered for encoding."#, + false, + None, + ) + sha224 => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "value".to_string(), + ty: Type::str_ref(), + has_default: false, + }, + Parameter { + name: "encoding".to_string(), + ty: Type::str_ref(), + has_default: true, + }, + ], + r#"Encrypt the string `value` using `SHA224` and the codec registered for encoding."#, + false, + None, + ) + sha256 => Type::function( None, Type::str_ref(), &[ @@ -33,11 +1125,11 @@ register_base64_member! { has_default: true, }, ], - r#"Encode the string `value` using the codec registered for encoding."#, + r#"Encrypt the string `value` using `SHA256` and the codec registered for encoding."#, false, None, ) - decode => Type::function( + sha384 => Type::function( None, Type::str_ref(), &[ @@ -52,108 +1144,42 @@ register_base64_member! { has_default: true, }, ], - r#"Decode the string `value` using the codec registered for encoding."#, + r#"Encrypt the string `value` using `SHA384` and the codec registered for encoding."#, false, None, ) -} - -pub const NET: &str = "net"; -pub const NET_FUNCTION_NAMES: [&str; 16] = [ - "split_host_port", - "join_host_port", - "fqdn", - "parse_IP", - "to_IP4", - "to_IP16", - "IP_string", - "is_IPv4", - "is_IP", - "is_loopback_IP", - "is_multicast_IP", - "is_interface_local_multicast_IP", - "is_link_local_multicast_IP", - "is_link_local_unicast_IP", - "is_global_unicast_IP", - "is_unspecified_IP", -]; -macro_rules! register_net_member { - ($($name:ident => $ty:expr)*) => ( - pub const NET_FUNCTION_TYPES: Lazy> = Lazy::new(|| { - let mut builtin_mapping = IndexMap::default(); - $( builtin_mapping.insert(stringify!($name).to_string(), $ty); )* - builtin_mapping - }); - ) -} -// TODO: add more system package types. -register_net_member! { - split_host_port => Type::function( + sha512 => Type::function( None, - Type::list_ref(Type::str_ref()), + Type::str_ref(), &[ Parameter { - name: "ip_end_point".to_string(), + name: "value".to_string(), ty: Type::str_ref(), has_default: false, }, + Parameter { + name: "encoding".to_string(), + ty: Type::str_ref(), + has_default: true, + }, ], - r#"Split the `host` and `port` from the `ip_end_point`."#, + r#"Encrypt the string `value` using `SHA512` and the codec registered for encoding."#, false, None, ) } -pub const MANIFESTS: &str = "manifests"; -pub const MANIFESTS_FUNCTION_NAMES: [&str; 1] = ["yaml_stream"]; - -pub const MATH: &str = "math"; -pub const MATH_FUNCTION_NAMES: [&str; 16] = [ - "ceil", - "factorial", - "floor", - "gcd", - "isfinite", - "isinf", - "isnan", - "modf", - "exp", - "expm1", - "log", - "log1p", - "log2", - "log10", - "pow", - "sqrt", -]; - -pub const DATETIME: &str = "datetime"; -pub const DATETIME_FUNCTION_NAMES: [&str; 4] = ["today", "now", "ticks", "date"]; - -pub const REGEX: &str = "regex"; -pub const REGEX_FUNCTION_NAMES: [&str; 6] = - ["replace", "match", "compile", "findall", "search", "split"]; - -pub const YAML: &str = "yaml"; -pub const YAML_FUNCTION_NAMES: [&str; 3] = ["encode", "decode", "dump_to_file"]; - -pub const JSON: &str = "json"; -pub const JSON_FUNCTION_NAMES: [&str; 3] = ["encode", "decode", "dump_to_file"]; - -pub const CRYPTO: &str = "crypto"; -pub const CRYPTO_FUNCTION_NAMES: [&str; 6] = - ["md5", "sha1", "sha224", "sha256", "sha384", "sha512"]; - -pub const TESTING: &str = "testing"; -pub const TESTING_FUNCTION_NAMES: [&str; 2] = ["arguments", "setting_file"]; +// ------------------------------ +// units system package +// ------------------------------ pub const UNITS: &str = "units"; -pub const UNITS_FUNCTION_NAMES: [&str; 13] = [ +pub const UNITS_FUNCTION_NAMES: &[&str] = &[ "to_n", "to_u", "to_m", "to_K", "to_M", "to_G", "to_T", "to_P", "to_Ki", "to_Mi", "to_Gi", "to_Ti", "to_Pi", ]; pub const UNITS_NUMBER_MULTIPLIER: &str = "NumberMultiplier"; -pub const UNITS_FIELD_NAMES: [&str; 15] = [ +pub const UNITS_FIELD_NAMES: &[&str] = &[ "n", "u", "m", @@ -170,15 +1196,251 @@ pub const UNITS_FIELD_NAMES: [&str; 15] = [ "Pi", UNITS_NUMBER_MULTIPLIER, ]; +macro_rules! register_units_member { + ($($name:ident => $ty:expr)*) => ( + pub const UNITS_FUNCTION_TYPES: Lazy> = Lazy::new(|| { + let mut builtin_mapping = IndexMap::default(); + $( builtin_mapping.insert(stringify!($name).to_string(), $ty); )* + builtin_mapping + }); + ) +} +register_units_member! { + n => Type::INT + u => Type::INT + m => Type::INT + k => Type::INT + K => Type::INT + M => Type::INT + G => Type::INT + T => Type::INT + P => Type::INT + Ki => Type::INT + Mi => Type::INT + Gi => Type::INT + Ti => Type::INT + Pi => Type::INT + to_n => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "num".to_string(), + ty: Type::number(), + has_default: false, + }, + ], + r#"Int literal to string with `n` suffix."#, + false, + None, + ) + to_u => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "num".to_string(), + ty: Type::number(), + has_default: false, + }, + ], + r#"Int literal to string with `u` suffix."#, + false, + None, + ) + to_m => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "num".to_string(), + ty: Type::number(), + has_default: false, + }, + ], + r#"Int literal to string with `m` suffix."#, + false, + None, + ) + to_K => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "num".to_string(), + ty: Type::number(), + has_default: false, + }, + ], + r#"Int literal to string with `K` suffix."#, + false, + None, + ) + to_M => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "num".to_string(), + ty: Type::number(), + has_default: false, + }, + ], + r#"Int literal to string with `M` suffix."#, + false, + None, + ) + to_G => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "num".to_string(), + ty: Type::number(), + has_default: false, + }, + ], + r#"Int literal to string with `G` suffix."#, + false, + None, + ) + to_T => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "num".to_string(), + ty: Type::number(), + has_default: false, + }, + ], + r#"Int literal to string with `T` suffix."#, + false, + None, + ) + to_P => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "num".to_string(), + ty: Type::number(), + has_default: false, + }, + ], + r#"Int literal to string with `P` suffix."#, + false, + None, + ) + to_Ki => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "num".to_string(), + ty: Type::number(), + has_default: false, + }, + ], + r#"Int literal to string with `Ki` suffix."#, + false, + None, + ) + to_Mi => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "num".to_string(), + ty: Type::number(), + has_default: false, + }, + ], + r#"Int literal to string with `Mi` suffix."#, + false, + None, + ) + to_Gi => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "num".to_string(), + ty: Type::number(), + has_default: false, + }, + ], + r#"Int literal to string with `Gi` suffix."#, + false, + None, + ) + to_Ti => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "num".to_string(), + ty: Type::number(), + has_default: false, + }, + ], + r#"Int literal to string with `Ti` suffix."#, + false, + None, + ) + to_Pi => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "num".to_string(), + ty: Type::number(), + has_default: false, + }, + ], + r#"Int literal to string with `Pi` suffix."#, + false, + None, + ) +} + +// ------------------------------ +// collection system package +// ------------------------------ pub const COLLECTION: &str = "collection"; -pub const COLLECTION_FUNCTION_NAMES: [&str; 1] = ["union_all"]; +pub const COLLECTION_FUNCTION_NAMES: &[&str] = &["union_all"]; +macro_rules! register_collection_member { + ($($name:ident => $ty:expr)*) => ( + pub const COLLECTION_FUNCTION_TYPES: Lazy> = Lazy::new(|| { + let mut builtin_mapping = IndexMap::default(); + $( builtin_mapping.insert(stringify!($name).to_string(), $ty); )* + builtin_mapping + }); + ) +} +register_collection_member! { + union_all => Type::function( + None, + Type::any_ref(), + &[ + Parameter { + name: "num".to_string(), + ty: Type::list_ref(Type::any_ref()), + has_default: false, + }, + ], + r#"Union all object to one object."#, + false, + None, + ) +} -pub const STANDARD_SYSTEM_MODULES: [&str; 12] = [ - COLLECTION, NET, MANIFESTS, MATH, DATETIME, REGEX, YAML, JSON, CRYPTO, BASE64, TESTING, UNITS, +pub const STANDARD_SYSTEM_MODULES: &[&str] = &[ + COLLECTION, NET, MANIFESTS, MATH, DATETIME, REGEX, YAML, JSON, CRYPTO, BASE64, UNITS, ]; -pub const STANDARD_SYSTEM_MODULE_NAMES_WITH_AT: [&str; 12] = [ +pub const STANDARD_SYSTEM_MODULE_NAMES_WITH_AT: &[&str] = &[ "@collection", "@net", "@manifests", @@ -189,7 +1451,6 @@ pub const STANDARD_SYSTEM_MODULE_NAMES_WITH_AT: [&str; 12] = [ "@json", "@crypto", "@base64", - "@testing", "@units", ]; @@ -205,7 +1466,6 @@ pub fn get_system_module_members(name: &str) -> Vec<&str> { YAML => YAML_FUNCTION_NAMES.to_vec(), JSON => JSON_FUNCTION_NAMES.to_vec(), CRYPTO => CRYPTO_FUNCTION_NAMES.to_vec(), - TESTING => TESTING_FUNCTION_NAMES.to_vec(), UNITS => { let mut members = UNITS_FUNCTION_NAMES.to_vec(); members.append(&mut UNITS_FIELD_NAMES.to_vec()); @@ -218,7 +1478,6 @@ pub fn get_system_module_members(name: &str) -> Vec<&str> { /// Get the system package member function type, if not found, return the any type. pub fn get_system_member_function_ty(name: &str, func: &str) -> TypeRef { - // TODO: add more system package types. let optional_ty = match name { BASE64 => { let types = BASE64_FUNCTION_TYPES; @@ -228,6 +1487,42 @@ pub fn get_system_member_function_ty(name: &str, func: &str) -> TypeRef { let types = NET_FUNCTION_TYPES; types.get(func).cloned() } + MANIFESTS => { + let types = MANIFESTS_FUNCTION_TYPES; + types.get(func).cloned() + } + MATH => { + let types = MATH_FUNCTION_TYPES; + types.get(func).cloned() + } + DATETIME => { + let types = DATETIME_FUNCTION_TYPES; + types.get(func).cloned() + } + REGEX => { + let types = REGEX_FUNCTION_TYPES; + types.get(func).cloned() + } + YAML => { + let types = YAML_FUNCTION_TYPES; + types.get(func).cloned() + } + JSON => { + let types = JSON_FUNCTION_TYPES; + types.get(func).cloned() + } + CRYPTO => { + let types = CRYPTO_FUNCTION_TYPES; + types.get(func).cloned() + } + UNITS => { + let types = UNITS_FUNCTION_TYPES; + types.get(func).cloned() + } + COLLECTION => { + let types = COLLECTION_FUNCTION_TYPES; + types.get(func).cloned() + } _ => None, }; optional_ty.map(|ty| Rc::new(ty)).unwrap_or(Type::any_ref()) diff --git a/kclvm/sema/src/ty/constructor.rs b/kclvm/sema/src/ty/constructor.rs index 40cf65ca7..b6c37e97b 100644 --- a/kclvm/sema/src/ty/constructor.rs +++ b/kclvm/sema/src/ty/constructor.rs @@ -214,6 +214,7 @@ impl Type { } } /// Construct a iterable type + #[inline] pub fn iterable() -> Rc { Rc::new(Type::union(&[ Rc::new(Type::STR), @@ -222,12 +223,9 @@ impl Type { ])) } /// Construct a number type - pub fn number() -> Rc { - Rc::new(Type::union(&[ - Rc::new(Type::INT), - Rc::new(Type::FLOAT), - Rc::new(Type::STR), - ])) + #[inline] + pub fn number() -> TypeRef { + Type::union_ref(&[Type::int_ref(), Type::float_ref(), Type::bool_ref()]) } /// Whether is a any type. #[inline]