diff --git a/interpreter/builtin.mbt b/interpreter/builtin.mbt index bb2c2a3..9d36c5c 100644 --- a/interpreter/builtin.mbt +++ b/interpreter/builtin.mbt @@ -336,7 +336,7 @@ let abort_fn : RuntimeFunction = ctx => { /// 布尔 NOT 运算 let bool_not_fn : RuntimeFunction = ctx => { if ctx.args is [{ val: Bool(b), .. }] { - Bool(not(b)) + Bool(!b) } else { Unit } diff --git a/interpreter/control_flow.mbt b/interpreter/control_flow.mbt index cebed60..cba2833 100644 --- a/interpreter/control_flow.mbt +++ b/interpreter/control_flow.mbt @@ -46,7 +46,7 @@ fn ClosureInterpreter::visit_for( } None => true } - if not(should_continue) { + if !should_continue { break } @@ -107,7 +107,7 @@ fn ClosureInterpreter::visit_while( |> ignore } // 如果没有break,执行else分支 - if not(broke) { + if !broke { match while_else { Some(else_expr) => result = self.visit_scoped( diff --git a/interpreter/core_modules.mbt b/interpreter/core_modules.mbt index 05cce09..896643b 100644 --- a/interpreter/core_modules.mbt +++ b/interpreter/core_modules.mbt @@ -2,135 +2,9 @@ /// Auto-generated core modules for moonbit-eval interpreter /// This file contains embedded RuntimePackage definitions for all moonbitlang/core modules + ///| -let core_modules : Map[String, RuntimePackage] = { - "abort": moonbitlang_core_abort_module, - "moonbitlang/core/abort": moonbitlang_core_abort_module, - "array": moonbitlang_core_array_module, - "moonbitlang/core/array": moonbitlang_core_array_module, - "bench": moonbitlang_core_bench_module, - "moonbitlang/core/bench": moonbitlang_core_bench_module, - "bigint": moonbitlang_core_bigint_module, - "moonbitlang/core/bigint": moonbitlang_core_bigint_module, - "bool": moonbitlang_core_bool_module, - "moonbitlang/core/bool": moonbitlang_core_bool_module, - "buffer": moonbitlang_core_buffer_module, - "moonbitlang/core/buffer": moonbitlang_core_buffer_module, - "builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "byte": moonbitlang_core_byte_module, - "moonbitlang/core/byte": moonbitlang_core_byte_module, - "bytes": moonbitlang_core_bytes_module, - "moonbitlang/core/bytes": moonbitlang_core_bytes_module, - "char": moonbitlang_core_char_module, - "moonbitlang/core/char": moonbitlang_core_char_module, - "cmp": moonbitlang_core_cmp_module, - "moonbitlang/core/cmp": moonbitlang_core_cmp_module, - "deque": moonbitlang_core_deque_module, - "moonbitlang/core/deque": moonbitlang_core_deque_module, - "double": moonbitlang_core_double_module, - "moonbitlang/core/double": moonbitlang_core_double_module, - "double/internal/ryu": moonbitlang_core_double_internal_ryu_module, - "moonbitlang/core/double/internal/ryu": moonbitlang_core_double_internal_ryu_module, - "encoding/utf16": moonbitlang_core_encoding_utf16_module, - "moonbitlang/core/encoding/utf16": moonbitlang_core_encoding_utf16_module, - "encoding/utf8": moonbitlang_core_encoding_utf8_module, - "moonbitlang/core/encoding/utf8": moonbitlang_core_encoding_utf8_module, - "env": moonbitlang_core_env_module, - "moonbitlang/core/env": moonbitlang_core_env_module, - "error": moonbitlang_core_error_module, - "moonbitlang/core/error": moonbitlang_core_error_module, - "float": moonbitlang_core_float_module, - "moonbitlang/core/float": moonbitlang_core_float_module, - "hashmap": moonbitlang_core_hashmap_module, - "moonbitlang/core/hashmap": moonbitlang_core_hashmap_module, - "hashset": moonbitlang_core_hashset_module, - "moonbitlang/core/hashset": moonbitlang_core_hashset_module, - "immut/array": moonbitlang_core_immut_array_module, - "moonbitlang/core/immut/array": moonbitlang_core_immut_array_module, - "immut/hashmap": moonbitlang_core_immut_hashmap_module, - "moonbitlang/core/immut/hashmap": moonbitlang_core_immut_hashmap_module, - "immut/hashset": moonbitlang_core_immut_hashset_module, - "moonbitlang/core/immut/hashset": moonbitlang_core_immut_hashset_module, - "immut/internal/path": moonbitlang_core_immut_internal_path_module, - "moonbitlang/core/immut/internal/path": moonbitlang_core_immut_internal_path_module, - "immut/internal/sparse_array": moonbitlang_core_immut_internal_sparse_array_module, - "moonbitlang/core/immut/internal/sparse_array": moonbitlang_core_immut_internal_sparse_array_module, - "immut/list": moonbitlang_core_immut_list_module, - "moonbitlang/core/immut/list": moonbitlang_core_immut_list_module, - "immut/priority_queue": moonbitlang_core_immut_priority_queue_module, - "moonbitlang/core/immut/priority_queue": moonbitlang_core_immut_priority_queue_module, - "immut/sorted_map": moonbitlang_core_immut_sorted_map_module, - "moonbitlang/core/immut/sorted_map": moonbitlang_core_immut_sorted_map_module, - "immut/sorted_set": moonbitlang_core_immut_sorted_set_module, - "moonbitlang/core/immut/sorted_set": moonbitlang_core_immut_sorted_set_module, - "int": moonbitlang_core_int_module, - "moonbitlang/core/int": moonbitlang_core_int_module, - "int16": moonbitlang_core_int16_module, - "moonbitlang/core/int16": moonbitlang_core_int16_module, - "int64": moonbitlang_core_int64_module, - "moonbitlang/core/int64": moonbitlang_core_int64_module, - "json": moonbitlang_core_json_module, - "moonbitlang/core/json": moonbitlang_core_json_module, - "list": moonbitlang_core_list_module, - "moonbitlang/core/list": moonbitlang_core_list_module, - "math": moonbitlang_core_math_module, - "moonbitlang/core/math": moonbitlang_core_math_module, - "option": moonbitlang_core_option_module, - "moonbitlang/core/option": moonbitlang_core_option_module, - "prelude": moonbitlang_core_prelude_module, - "moonbitlang/core/prelude": moonbitlang_core_prelude_module, - "priority_queue": moonbitlang_core_priority_queue_module, - "moonbitlang/core/priority_queue": moonbitlang_core_priority_queue_module, - "queue": moonbitlang_core_queue_module, - "moonbitlang/core/queue": moonbitlang_core_queue_module, - "quickcheck": moonbitlang_core_quickcheck_module, - "moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module, - "quickcheck/splitmix": moonbitlang_core_quickcheck_splitmix_module, - "moonbitlang/core/quickcheck/splitmix": moonbitlang_core_quickcheck_splitmix_module, - "random": moonbitlang_core_random_module, - "moonbitlang/core/random": moonbitlang_core_random_module, - "random/internal/random_source": moonbitlang_core_random_internal_random_source_module, - "moonbitlang/core/random/internal/random_source": moonbitlang_core_random_internal_random_source_module, - "ref": moonbitlang_core_ref_module, - "moonbitlang/core/ref": moonbitlang_core_ref_module, - "result": moonbitlang_core_result_module, - "moonbitlang/core/result": moonbitlang_core_result_module, - "set": moonbitlang_core_set_module, - "moonbitlang/core/set": moonbitlang_core_set_module, - "sorted_map": moonbitlang_core_sorted_map_module, - "moonbitlang/core/sorted_map": moonbitlang_core_sorted_map_module, - "sorted_set": moonbitlang_core_sorted_set_module, - "moonbitlang/core/sorted_set": moonbitlang_core_sorted_set_module, - "strconv": moonbitlang_core_strconv_module, - "moonbitlang/core/strconv": moonbitlang_core_strconv_module, - "string": moonbitlang_core_string_module, - "moonbitlang/core/string": moonbitlang_core_string_module, - "string/regex": moonbitlang_core_string_regex_module, - "moonbitlang/core/string/regex": moonbitlang_core_string_regex_module, - "string/regex/internal/regexp": moonbitlang_core_string_regex_internal_regexp_module, - "moonbitlang/core/string/regex/internal/regexp": moonbitlang_core_string_regex_internal_regexp_module, - "string/regex/internal/regexp/internal/ast": moonbitlang_core_string_regex_internal_regexp_internal_ast_module, - "moonbitlang/core/string/regex/internal/regexp/internal/ast": moonbitlang_core_string_regex_internal_regexp_internal_ast_module, - "string/regex/internal/regexp/internal/parse": moonbitlang_core_string_regex_internal_regexp_internal_parse_module, - "moonbitlang/core/string/regex/internal/regexp/internal/parse": moonbitlang_core_string_regex_internal_regexp_internal_parse_module, - "string/regex/internal/regexp/internal/unicode": moonbitlang_core_string_regex_internal_regexp_internal_unicode_module, - "moonbitlang/core/string/regex/internal/regexp/internal/unicode": moonbitlang_core_string_regex_internal_regexp_internal_unicode_module, - "string/regex/internal/regexp/internal/vm": moonbitlang_core_string_regex_internal_regexp_internal_vm_module, - "moonbitlang/core/string/regex/internal/regexp/internal/vm": moonbitlang_core_string_regex_internal_regexp_internal_vm_module, - "test": moonbitlang_core_test_module, - "moonbitlang/core/test": moonbitlang_core_test_module, - "tuple": moonbitlang_core_tuple_module, - "moonbitlang/core/tuple": moonbitlang_core_tuple_module, - "uint": moonbitlang_core_uint_module, - "moonbitlang/core/uint": moonbitlang_core_uint_module, - "uint16": moonbitlang_core_uint16_module, - "moonbitlang/core/uint16": moonbitlang_core_uint16_module, - "uint64": moonbitlang_core_uint64_module, - "moonbitlang/core/uint64": moonbitlang_core_uint64_module, - "unit": moonbitlang_core_unit_module, - "moonbitlang/core/unit": moonbitlang_core_unit_module, -} +let core_modules : Map[String, RuntimePackage] = { "abort": moonbitlang_core_abort_module, "moonbitlang/core/abort": moonbitlang_core_abort_module, "argparse": moonbitlang_core_argparse_module, "moonbitlang/core/argparse": moonbitlang_core_argparse_module, "array": moonbitlang_core_array_module, "moonbitlang/core/array": moonbitlang_core_array_module, "bench": moonbitlang_core_bench_module, "moonbitlang/core/bench": moonbitlang_core_bench_module, "bigint": moonbitlang_core_bigint_module, "moonbitlang/core/bigint": moonbitlang_core_bigint_module, "buffer": moonbitlang_core_buffer_module, "moonbitlang/core/buffer": moonbitlang_core_buffer_module, "builtin": moonbitlang_core_builtin_module, "moonbitlang/core/builtin": moonbitlang_core_builtin_module, "byte": moonbitlang_core_byte_module, "moonbitlang/core/byte": moonbitlang_core_byte_module, "bytes": moonbitlang_core_bytes_module, "moonbitlang/core/bytes": moonbitlang_core_bytes_module, "bytes/internal/regex_engine": moonbitlang_core_bytes_internal_regex_engine_module, "moonbitlang/core/bytes/internal/regex_engine": moonbitlang_core_bytes_internal_regex_engine_module, "bytes/internal/regex_engine/ast": moonbitlang_core_bytes_internal_regex_engine_ast_module, "moonbitlang/core/bytes/internal/regex_engine/ast": moonbitlang_core_bytes_internal_regex_engine_ast_module, "bytes/internal/regex_engine/symbol_map": moonbitlang_core_bytes_internal_regex_engine_symbol_map_module, "moonbitlang/core/bytes/internal/regex_engine/symbol_map": moonbitlang_core_bytes_internal_regex_engine_symbol_map_module, "char": moonbitlang_core_char_module, "moonbitlang/core/char": moonbitlang_core_char_module, "cmp": moonbitlang_core_cmp_module, "moonbitlang/core/cmp": moonbitlang_core_cmp_module, "debug": moonbitlang_core_debug_module, "moonbitlang/core/debug": moonbitlang_core_debug_module, "deque": moonbitlang_core_deque_module, "moonbitlang/core/deque": moonbitlang_core_deque_module, "double": moonbitlang_core_double_module, "moonbitlang/core/double": moonbitlang_core_double_module, "encoding/ascii": moonbitlang_core_encoding_ascii_module, "moonbitlang/core/encoding/ascii": moonbitlang_core_encoding_ascii_module, "encoding/base64": moonbitlang_core_encoding_base64_module, "moonbitlang/core/encoding/base64": moonbitlang_core_encoding_base64_module, "encoding/utf16": moonbitlang_core_encoding_utf16_module, "moonbitlang/core/encoding/utf16": moonbitlang_core_encoding_utf16_module, "encoding/utf8": moonbitlang_core_encoding_utf8_module, "moonbitlang/core/encoding/utf8": moonbitlang_core_encoding_utf8_module, "env": moonbitlang_core_env_module, "moonbitlang/core/env": moonbitlang_core_env_module, "error": moonbitlang_core_error_module, "moonbitlang/core/error": moonbitlang_core_error_module, "float": moonbitlang_core_float_module, "moonbitlang/core/float": moonbitlang_core_float_module, "hashmap": moonbitlang_core_hashmap_module, "moonbitlang/core/hashmap": moonbitlang_core_hashmap_module, "hashset": moonbitlang_core_hashset_module, "moonbitlang/core/hashset": moonbitlang_core_hashset_module, "immut/array": moonbitlang_core_immut_array_module, "moonbitlang/core/immut/array": moonbitlang_core_immut_array_module, "immut/hashmap": moonbitlang_core_immut_hashmap_module, "moonbitlang/core/immut/hashmap": moonbitlang_core_immut_hashmap_module, "immut/hashset": moonbitlang_core_immut_hashset_module, "moonbitlang/core/immut/hashset": moonbitlang_core_immut_hashset_module, "immut/internal/path": moonbitlang_core_immut_internal_path_module, "moonbitlang/core/immut/internal/path": moonbitlang_core_immut_internal_path_module, "immut/internal/sparse_array": moonbitlang_core_immut_internal_sparse_array_module, "moonbitlang/core/immut/internal/sparse_array": moonbitlang_core_immut_internal_sparse_array_module, "immut/priority_queue": moonbitlang_core_immut_priority_queue_module, "moonbitlang/core/immut/priority_queue": moonbitlang_core_immut_priority_queue_module, "immut/sorted_map": moonbitlang_core_immut_sorted_map_module, "moonbitlang/core/immut/sorted_map": moonbitlang_core_immut_sorted_map_module, "immut/sorted_set": moonbitlang_core_immut_sorted_set_module, "moonbitlang/core/immut/sorted_set": moonbitlang_core_immut_sorted_set_module, "int": moonbitlang_core_int_module, "moonbitlang/core/int": moonbitlang_core_int_module, "int16": moonbitlang_core_int16_module, "moonbitlang/core/int16": moonbitlang_core_int16_module, "int64": moonbitlang_core_int64_module, "moonbitlang/core/int64": moonbitlang_core_int64_module, "internal/regex_engine/automata": moonbitlang_core_internal_regex_engine_automata_module, "moonbitlang/core/internal/regex_engine/automata": moonbitlang_core_internal_regex_engine_automata_module, "internal/regex_engine/shared_types": moonbitlang_core_internal_regex_engine_shared_types_module, "moonbitlang/core/internal/regex_engine/shared_types": moonbitlang_core_internal_regex_engine_shared_types_module, "internal/regex_engine/shared_types/rechar_set": moonbitlang_core_internal_regex_engine_shared_types_rechar_set_module, "moonbitlang/core/internal/regex_engine/shared_types/rechar_set": moonbitlang_core_internal_regex_engine_shared_types_rechar_set_module, "json": moonbitlang_core_json_module, "moonbitlang/core/json": moonbitlang_core_json_module, "list": moonbitlang_core_list_module, "moonbitlang/core/list": moonbitlang_core_list_module, "math": moonbitlang_core_math_module, "moonbitlang/core/math": moonbitlang_core_math_module, "option": moonbitlang_core_option_module, "moonbitlang/core/option": moonbitlang_core_option_module, "prelude": moonbitlang_core_prelude_module, "moonbitlang/core/prelude": moonbitlang_core_prelude_module, "priority_queue": moonbitlang_core_priority_queue_module, "moonbitlang/core/priority_queue": moonbitlang_core_priority_queue_module, "queue": moonbitlang_core_queue_module, "moonbitlang/core/queue": moonbitlang_core_queue_module, "quickcheck": moonbitlang_core_quickcheck_module, "moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module, "quickcheck/splitmix": moonbitlang_core_quickcheck_splitmix_module, "moonbitlang/core/quickcheck/splitmix": moonbitlang_core_quickcheck_splitmix_module, "random": moonbitlang_core_random_module, "moonbitlang/core/random": moonbitlang_core_random_module, "random/internal/random_source": moonbitlang_core_random_internal_random_source_module, "moonbitlang/core/random/internal/random_source": moonbitlang_core_random_internal_random_source_module, "ref": moonbitlang_core_ref_module, "moonbitlang/core/ref": moonbitlang_core_ref_module, "result": moonbitlang_core_result_module, "moonbitlang/core/result": moonbitlang_core_result_module, "set": moonbitlang_core_set_module, "moonbitlang/core/set": moonbitlang_core_set_module, "sorted_map": moonbitlang_core_sorted_map_module, "moonbitlang/core/sorted_map": moonbitlang_core_sorted_map_module, "sorted_set": moonbitlang_core_sorted_set_module, "moonbitlang/core/sorted_set": moonbitlang_core_sorted_set_module, "strconv": moonbitlang_core_strconv_module, "moonbitlang/core/strconv": moonbitlang_core_strconv_module, "string": moonbitlang_core_string_module, "moonbitlang/core/string": moonbitlang_core_string_module, "string/internal/regex_engine": moonbitlang_core_string_internal_regex_engine_module, "moonbitlang/core/string/internal/regex_engine": moonbitlang_core_string_internal_regex_engine_module, "string/internal/regex_engine/ast": moonbitlang_core_string_internal_regex_engine_ast_module, "moonbitlang/core/string/internal/regex_engine/ast": moonbitlang_core_string_internal_regex_engine_ast_module, "string/internal/regex_engine/symbol_map": moonbitlang_core_string_internal_regex_engine_symbol_map_module, "moonbitlang/core/string/internal/regex_engine/symbol_map": moonbitlang_core_string_internal_regex_engine_symbol_map_module, "string/internal/regex_parser": moonbitlang_core_string_internal_regex_parser_module, "moonbitlang/core/string/internal/regex_parser": moonbitlang_core_string_internal_regex_parser_module, "test": moonbitlang_core_test_module, "moonbitlang/core/test": moonbitlang_core_test_module, "tuple": moonbitlang_core_tuple_module, "moonbitlang/core/tuple": moonbitlang_core_tuple_module, "uint": moonbitlang_core_uint_module, "moonbitlang/core/uint": moonbitlang_core_uint_module, "uint16": moonbitlang_core_uint16_module, "moonbitlang/core/uint16": moonbitlang_core_uint16_module, "uint64": moonbitlang_core_uint64_module, "moonbitlang/core/uint64": moonbitlang_core_uint64_module, "unit": moonbitlang_core_unit_module, "moonbitlang/core/unit": moonbitlang_core_unit_module } ///| fn dummy_loc() -> @basic.Location { @@ -143,40410 +17,46535 @@ fn dummy_loc() -> @basic.Location { ///| let moonbitlang_core_abort_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/abort", - deps={}, + deps={ }, + files={ + "abort.mbt": ( + #|#cfg(not(target="native")) + #|pub fn[T] abort(msg : String) -> T { + #| let _ = msg + #| panic_impl() + #|} + #|#cfg(target="native") + #|fn println(s : String) -> Unit = "%println" + #|#cfg(target="native") + #|pub fn[T] abort(msg : String) -> T { + #| println(msg) + #| panic_impl() + #|} + #|fn[T] panic_impl() -> T = "%panic" + ) + } +) + +///| +let moonbitlang_core_argparse_module : RuntimePackage = RuntimePackage::new( + "moonbitlang/core/argparse", + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "virtual": { - #| "has-default": true - #| } - #|} - ), - "abort.mbt": ( - #|#cfg(not(target="native")) - #|pub fn[T] abort(msg : String) -> T { - #| let _ = msg - #| panic_impl() - #|} - #|#cfg(target="native") - #|fn println(s : String) -> Unit = "%println" - #|#cfg(target="native") - #|pub fn[T] abort(msg : String) -> T { - #| println(msg) - #| panic_impl() - #|} - #|fn[T] panic_impl() -> T = "%panic" - ), - }, + "arg_action.mbt": ( + #|fn arg_min_max_for_validate(arg : Arg) -> (Int, Int?) raise ArgBuildError { + #| if arg.info is PositionalInfo(num_args=Some(range), ..) { + #| if range.lower < 0 { + #| raise Unsupported("min values must be >= 0") + #| } + #| if range.upper is Some(max_value) { + #| if max_value < 0 { + #| raise Unsupported("max values must be >= 0") + #| } + #| if max_value < range.lower { + #| raise Unsupported("max values must be >= min values") + #| } + #| if range.lower == 0 && max_value == 0 { + #| raise Unsupported("empty value range (0..0) is unsupported") + #| } + #| } + #| (range.lower, range.upper) + #| } else { + #| (0, None) + #| } + #|} + #|fn arg_min_max(arg : Arg) -> (Int, Int?) { + #| match arg.info { + #| PositionalInfo(num_args=Some(range), ..) => (range.lower, range.upper) + #| _ => (0, None) + #| } + #|} + ), + "arg_group.mbt": ( + #|pub struct ArgGroup { + #| priv name : String + #| priv required : Bool + #| priv multiple : Bool + #| priv args : Array[String] + #| priv requires : Array[String] + #| priv conflicts_with : Array[String] + #| fn new( + #| name : StringView, + #| required? : Bool, + #| multiple? : Bool, + #| args? : ArrayView[String], + #| requires? : ArrayView[String], + #| conflicts_with? : ArrayView[String], + #| ) -> ArgGroup + #|} + #|pub fn ArgGroup::new( + #| name : StringView, + #| required? : Bool = false, + #| multiple? : Bool = true, + #| args? : ArrayView[String] = [], + #| requires? : ArrayView[String] = [], + #| conflicts_with? : ArrayView[String] = [], + #|) -> ArgGroup { + #| { + #| name: name.to_string(), + #| required, + #| multiple, + #| args: args.to_array(), + #| requires: requires.to_array(), + #| conflicts_with: conflicts_with.to_array(), + #| } + #|} + ), + "arg_spec.mbt": ( + #|pub(all) enum FlagAction { + #| SetTrue + #| SetFalse + #| Count + #| Help + #| Version + #|} derive(Eq, Show) + #|pub(all) enum OptionAction { + #| Set + #| Append + #|} derive(Eq, Show) + #|priv struct Arg { + #| name : String + #| about : String? + #| env : String? + #| requires : Array[String] + #| conflicts_with : Array[String] + #| required : Bool + #| global : Bool + #| hidden : Bool + #| info : ArgInfo + #| multiple : Bool + #|} + #|priv enum ArgInfo { + #| FlagInfo( + #| short~ : Char?, + #| long~ : String?, + #| action~ : FlagAction, + #| negatable~ : Bool + #| ) + #| OptionInfo( + #| short~ : Char?, + #| long~ : String?, + #| action~ : OptionAction, + #| default_values~ : Array[String]?, + #| allow_hyphen_values~ : Bool + #| ) + #| PositionalInfo( + #| num_args~ : ValueRange?, + #| default_values~ : Array[String]?, + #| allow_hyphen_values~ : Bool + #| ) + #|} + #|pub struct FlagArg { + #| priv arg : Arg + #| fn new( + #| name : StringView, + #| short? : Char, + #| long? : StringView, + #| about? : StringView, + #| action? : FlagAction, + #| env? : StringView, + #| requires? : ArrayView[String], + #| conflicts_with? : ArrayView[String], + #| required? : Bool, + #| global? : Bool, + #| negatable? : Bool, + #| hidden? : Bool, + #| ) -> FlagArg + #|} + #|pub fn FlagArg::new( + #| name : StringView, + #| short? : Char, + #| long? : StringView = name, + #| about? : StringView, + #| action? : FlagAction = SetTrue, + #| env? : StringView, + #| requires? : ArrayView[String] = [], + #| conflicts_with? : ArrayView[String] = [], + #| required? : Bool = false, + #| global? : Bool = false, + #| negatable? : Bool = false, + #| hidden? : Bool = false, + #|) -> FlagArg { + #| let name = name.to_string() + #| let long = if long == "" { None } else { Some(long.to_string()) } + #| let about = about.map(v => v.to_string()) + #| let env = env.map(v => v.to_string()) + #| { + #| arg: { + #| name, + #| about, + #| env, + #| global, + #| hidden, + #| requires: requires.to_array(), + #| conflicts_with: conflicts_with.to_array(), + #| required, + #| info: FlagInfo(short~, long~, action~, negatable~), + #| multiple: false, + #| }, + #| } + #|} + #|pub struct OptionArg { + #| priv arg : Arg + #| fn new( + #| name : StringView, + #| short? : Char, + #| long? : StringView, + #| about? : StringView, + #| action? : OptionAction, + #| env? : StringView, + #| default_values? : ArrayView[String], + #| allow_hyphen_values? : Bool, + #| requires? : ArrayView[String], + #| conflicts_with? : ArrayView[String], + #| required? : Bool, + #| global? : Bool, + #| hidden? : Bool, + #| ) -> OptionArg + #|} + #|pub fn OptionArg::new( + #| name : StringView, + #| short? : Char, + #| long? : StringView = name, + #| about? : StringView, + #| action? : OptionAction = Set, + #| env? : StringView, + #| default_values? : ArrayView[String], + #| allow_hyphen_values? : Bool = false, + #| requires? : ArrayView[String] = [], + #| conflicts_with? : ArrayView[String] = [], + #| required? : Bool = false, + #| global? : Bool = false, + #| hidden? : Bool = false, + #|) -> OptionArg { + #| let name = name.to_string() + #| let long = if long == "" { None } else { Some(long.to_string()) } + #| let about = about.map(v => v.to_string()) + #| let env = env.map(v => v.to_string()) + #| { + #| arg: { + #| name, + #| about, + #| env, + #| requires: requires.to_array(), + #| conflicts_with: conflicts_with.to_array(), + #| required, + #| global, + #| hidden, + #| info: OptionInfo( + #| short~, + #| long~, + #| action~, + #| default_values=default_values.map(values => values.to_array()), + #| allow_hyphen_values~, + #| ), + #| multiple: action is Append, + #| }, + #| } + #|} + #|pub struct PositionArg { + #| priv arg : Arg + #| fn new( + #| name : StringView, + #| about? : StringView, + #| env? : StringView, + #| default_values? : ArrayView[String], + #| num_args? : ValueRange, + #| allow_hyphen_values? : Bool, + #| requires? : ArrayView[String], + #| conflicts_with? : ArrayView[String], + #| global? : Bool, + #| hidden? : Bool, + #| ) -> PositionArg + #|} + #|pub fn PositionArg::new( + #| name : StringView, + #| about? : StringView, + #| env? : StringView, + #| default_values? : ArrayView[String], + #| num_args? : ValueRange, + #| allow_hyphen_values? : Bool = false, + #| requires? : ArrayView[String] = [], + #| conflicts_with? : ArrayView[String] = [], + #| global? : Bool = false, + #| hidden? : Bool = false, + #|) -> PositionArg { + #| let name = name.to_string() + #| let about = about.map(v => v.to_string()) + #| let env = env.map(v => v.to_string()) + #| { + #| arg: { + #| name, + #| about, + #| env, + #| requires: requires.to_array(), + #| conflicts_with: conflicts_with.to_array(), + #| required: false, + #| global, + #| hidden, + #| info: PositionalInfo( + #| num_args~, + #| default_values=default_values.map(values => values.to_array()), + #| allow_hyphen_values~, + #| ), + #| multiple: range_allows_multiple(num_args), + #| }, + #| } + #|} + #|fn arg_name(arg : Arg) -> String { + #| arg.name + #|} + #|fn range_allows_multiple(range : ValueRange?) -> Bool { + #| range is Some(r) && + #| (match r.upper { + #| Some(upper) => upper > 1 + #| None => true + #| }) + #|} + ), + "command.mbt": ( + #|pub struct Command { + #| priv name : String + #| priv args : Array[Arg] + #| priv groups : Array[ArgGroup] + #| priv subcommands : Array[Command] + #| priv about : String? + #| priv version : String? + #| priv disable_help_flag : Bool + #| priv disable_version_flag : Bool + #| priv disable_help_subcommand : Bool + #| priv arg_required_else_help : Bool + #| priv subcommand_required : Bool + #| priv hidden : Bool + #| priv mut build_error : ArgBuildError? + #| fn new( + #| name : StringView, + #| flags? : ArrayView[FlagArg], + #| options? : ArrayView[OptionArg], + #| positionals? : ArrayView[PositionArg], + #| subcommands? : ArrayView[Command], + #| about? : StringView, + #| version? : StringView, + #| disable_help_flag? : Bool, + #| disable_version_flag? : Bool, + #| disable_help_subcommand? : Bool, + #| arg_required_else_help? : Bool, + #| subcommand_required? : Bool, + #| hidden? : Bool, + #| groups? : ArrayView[ArgGroup], + #| ) -> Command + #|} + #|pub fn Command::new( + #| name : StringView, + #| flags? : ArrayView[FlagArg] = [], + #| options? : ArrayView[OptionArg] = [], + #| positionals? : ArrayView[PositionArg] = [], + #| subcommands? : ArrayView[Command] = [], + #| about? : StringView, + #| version? : StringView, + #| disable_help_flag? : Bool = false, + #| disable_version_flag? : Bool = false, + #| disable_help_subcommand? : Bool = false, + #| arg_required_else_help? : Bool = false, + #| subcommand_required? : Bool = false, + #| hidden? : Bool = false, + #| groups? : ArrayView[ArgGroup] = [], + #|) -> Command { + #| let (parsed_args, arg_error) = collect_args(flags, options, positionals) + #| let groups = groups.to_array() + #| let cmd = Command::{ + #| name: name.to_string(), + #| args: parsed_args, + #| groups, + #| subcommands: subcommands.to_array(), + #| about: about.map(v => v.to_string()), + #| version: version.map(v => v.to_string()), + #| disable_help_flag, + #| disable_version_flag, + #| disable_help_subcommand, + #| arg_required_else_help, + #| subcommand_required, + #| hidden, + #| build_error: arg_error, + #| } + #| if cmd.build_error is None { + #| validate_command(cmd, parsed_args, groups, []) catch { + #| err => cmd.build_error = Some(err) + #| } + #| } + #| cmd + #|} + #|pub fn Command::render_help(self : Command) -> String { + #| render_help(self) + #|} + #|#as_free_fn + #|pub fn Command::parse( + #| self : Command, + #| argv? : ArrayView[String] = default_argv(), + #| env? : Map[String, String] = {}, + #|) -> Matches raise { + #| try { + #| let raw = parse_command(self, argv, env, [], {}, {}, self.name) + #| build_matches(self, raw, []) + #| } catch { + #| DisplayHelp::Message(text) => print_and_exit_success(text) + #| DisplayVersion::Message(text) => print_and_exit_success(text) + #| ArgError::Message(_) as err => raise err + #| err => { + #| println(err.to_string()) + #| panic() + #| } + #| } + #|} + #|fn build_matches( + #| cmd : Command, + #| raw : Matches, + #| inherited_globals : Array[Arg], + #|) -> Matches { + #| let flags : Map[String, Bool] = {} + #| let values : Map[String, Array[String]] = {} + #| let flag_counts : Map[String, Int] = {} + #| let sources : Map[String, ValueSource] = {} + #| let specs = inherited_globals + cmd.args + #| for spec in specs { + #| let name = arg_name(spec) + #| if raw.values.get(name) is Some(vs) { + #| values[name] = vs.copy() + #| } + #| let count = raw.counts.get_or_default(name, 0) + #| if count > 0 { + #| flag_counts[name] = count + #| } + #| let source = match raw.flag_sources.get(name) { + #| Some(v) => Some(v) + #| None => raw.value_sources.get(name) + #| } + #| if source is Some(source) { + #| sources[name] = source + #| if spec.info is FlagInfo(action~, ..) { + #| if action is Count { + #| flags[name] = count > 0 + #| } else { + #| flags[name] = raw.flags.get(name).unwrap_or(false) + #| } + #| } + #| } + #| } + #| let child_globals = merge_global_defs( + #| inherited_globals, + #| collect_globals(cmd.args), + #| ) + #| let subcommand = match raw.parsed_subcommand { + #| Some((name, sub_raw)) => + #| if find_decl_subcommand(cmd.subcommands, name) is Some(sub_spec) { + #| Some((name, build_matches(sub_spec, sub_raw, child_globals))) + #| } else { + #| Some( + #| ( + #| name, + #| { + #| flags: {}, + #| values: {}, + #| flag_counts: {}, + #| sources: {}, + #| subcommand: None, + #| counts: {}, + #| flag_sources: {}, + #| value_sources: {}, + #| parsed_subcommand: None, + #| }, + #| ), + #| ) + #| } + #| None => None + #| } + #| { + #| flags, + #| values, + #| flag_counts, + #| sources, + #| subcommand, + #| counts: {}, + #| flag_sources: {}, + #| value_sources: {}, + #| parsed_subcommand: None, + #| } + #|} + #|fn find_decl_subcommand(subs : Array[Command], name : String) -> Command? { + #| for sub in subs { + #| if sub.name == name { + #| return Some(sub) + #| } + #| } + #| None + #|} + #|fn collect_args( + #| flags : ArrayView[FlagArg], + #| options : ArrayView[OptionArg], + #| positionals : ArrayView[PositionArg], + #|) -> (Array[Arg], ArgBuildError?) { + #| let args : Array[Arg] = [] + #| for flag in flags { + #| args.push(flag.arg) + #| } + #| for option in options { + #| args.push(option.arg) + #| } + #| for positional in positionals { + #| args.push(positional.arg) + #| } + #| let ctx = ValidationCtx::new() + #| let first_error : ArgBuildError? = for + #| flag in flags + #| first_error = (None : ArgBuildError?) { + #| validate_flag_arg(flag.arg, ctx) catch { + #| err => if first_error is None { continue Some(err) } + #| } + #| continue first_error + #| } nobreak { + #| first_error + #| } + #| let first_error : ArgBuildError? = for + #| option in options + #| first_error = first_error { + #| validate_option_arg(option.arg, ctx) catch { + #| err => if first_error is None { continue Some(err) } + #| } + #| continue first_error + #| } nobreak { + #| first_error + #| } + #| let first_error : ArgBuildError? = for + #| positional in positionals + #| first_error = first_error { + #| validate_positional_arg(positional.arg, ctx) catch { + #| err => if first_error is None { continue Some(err) } + #| } + #| continue first_error + #| } nobreak { + #| first_error + #| } + #| let first_error = if first_error is None { + #| try { + #| ctx.finalize() + #| None + #| } catch { + #| err => Some(err) + #| } + #| } else { + #| first_error + #| } + #| (args, first_error) + #|} + ), + "error.mbt": ( + #|priv suberror ArgError { + #| Message(String) + #|} + #|impl Show for ArgError with output(self : ArgError, logger) { + #| match self { + #| Message(msg) => logger.write_string(msg) + #| } + #|} + #|priv suberror ArgParseError { + #| UnknownArgument(String, String?) + #| InvalidArgument(String) + #| MissingValue(String) + #| MissingRequired(String, String?) + #| TooFewValues(String, Int, Int) + #| TooManyValues(String, Int, Int) + #| TooManyPositionals(String, String?) + #| InvalidValue(String) + #| MissingGroup(String) + #| GroupConflict(String) + #|} + #|fn ArgParseError::arg_parse_error_message(self : ArgParseError) -> String { + #| match self { + #| UnknownArgument(arg, Some(hint)) => + #| ( + #| $|error: unexpected argument '\{arg}' found + #| $| + #| $| tip: a similar argument exists: '\{hint}' + #| ) + #| UnknownArgument(arg, None) => "error: unexpected argument '\{arg}' found" + #| InvalidArgument(arg) => + #| if arg.has_prefix("-") { + #| "error: unexpected argument '\{arg}' found" + #| } else { + #| "error: \{arg}" + #| } + #| MissingValue(arg) => + #| "error: a value is required for '\{arg}' but none was supplied" + #| MissingRequired(name, by) => + #| if by is Some(source) { + #| "error: the following required argument was not provided: '\{name}' (required by '\{source}')" + #| } else { + #| "error: the following required argument was not provided: '\{name}'" + #| } + #| TooFewValues(name, got, min) => + #| "error: '\{name}' requires at least \{min} values but only \{got} were provided" + #| TooManyValues(name, got, max) => + #| "error: '\{name}' allows at most \{max} values but \{got} were provided" + #| TooManyPositionals(value, Some(arg)) => + #| "error: unexpected value '\{value}' for '\{arg}' found; no more were expected" + #| TooManyPositionals(value, None) => + #| "error: unexpected value '\{value}' found; no more were expected" + #| InvalidValue(msg) => "error: \{msg}" + #| MissingGroup(name) => + #| "error: the following required argument group was not provided: '\{name}'" + #| GroupConflict(name) => "error: group conflict \{name}" + #| } + #|} + #|priv suberror ArgBuildError { + #| Unsupported(String) + #|} + #|priv suberror DisplayHelp { + #| Message(String) + #|} + #|priv suberror DisplayVersion { + #| Message(String) + #|} + ), + "help_render.mbt": ( + #|fn render_help(cmd : Command) -> String { + #| render_help_with_usage_override(cmd, None) + #|} + #|fn render_help_with_usage_override( + #| cmd : Command, + #| usage_line : String?, + #|) -> String { + #| let usage_line = usage_line.unwrap_or("Usage: \{cmd.name}\{usage_tail(cmd)}") + #| let about = cmd.about.unwrap_or("") + #| let about_section = if about == "" { + #| "" + #| } else { + #| ( + #| $| + #| $| + #| $|\{about} + #| ) + #| } + #| let commands_section = render_section("Commands:", subcommand_entries(cmd)) + #| let arguments_section = render_section("Arguments:", positional_entries(cmd)) + #| let options_section = render_section( + #| "Options:", + #| option_entries(cmd), + #| keep_empty=true, + #| ) + #| let groups_section = render_section("Groups:", group_entries(cmd)) + #| ( + #| $|\{usage_line}\{about_section}\{commands_section}\{arguments_section}\{options_section}\{groups_section} + #| $| + #| ) + #|} + #|fn usage_tail(cmd : Command) -> String { + #| let mut tail = "" + #| let required_options = required_option_usage(cmd) + #| if required_options != "" { + #| tail = "\{tail} \{required_options}" + #| } + #| if has_options(cmd) { + #| tail = "\{tail} [options]" + #| } + #| let pos = positional_usage(cmd) + #| if pos != "" { + #| tail = "\{tail} \{pos}" + #| } + #| let sub = subcommand_usage(cmd) + #| if sub != "" { + #| tail = "\{tail} \{sub}" + #| } + #| tail + #|} + #|fn subcommand_usage(cmd : Command) -> String { + #| if !has_subcommands_for_help(cmd) { + #| return "" + #| } + #| if cmd.subcommand_required { + #| "" + #| } else { + #| "[command]" + #| } + #|} + #|fn has_options(cmd : Command) -> Bool { + #| for arg in cmd.args { + #| if arg.hidden { + #| continue + #| } + #| if arg.info is (OptionInfo(long~, short~, ..) | FlagInfo(long~, short~, ..)) && + #| (long is Some(_) || short is Some(_)) && + #| !is_required_arg(arg) { + #| return true + #| } + #| } + #| false + #|} + #|fn required_option_usage(cmd : Command) -> String { + #| let parts = Array::new(capacity=cmd.args.length()) + #| for arg in cmd.args { + #| if arg.hidden || !is_required_arg(arg) { + #| continue + #| } + #| if arg.info is PositionalInfo(_) { + #| continue + #| } + #| if required_option_token(arg) is Some(token) { + #| parts.push(token) + #| } + #| } + #| parts.join(" ") + #|} + #|fn required_option_token(arg : Arg) -> String? { + #| let prefix = match arg.info { + #| OptionInfo(long~, short~, ..) | FlagInfo(long~, short~, ..) => + #| if long is Some(long) { + #| Some("--\{long}") + #| } else if short is Some(short) { + #| Some("-\{short}") + #| } else { + #| None + #| } + #| PositionalInfo(_) => None + #| } + #| match prefix { + #| Some(prefix) => + #| if arg.info is OptionInfo(_) { + #| Some("\{prefix} <\{arg.name}>") + #| } else { + #| Some(prefix) + #| } + #| None => None + #| } + #|} + #|fn positional_usage(cmd : Command) -> String { + #| let parts = Array::new(capacity=cmd.args.length()) + #| for arg in positional_args(cmd.args) { + #| if arg.hidden { + #| continue + #| } + #| let required = is_required_arg(arg) + #| if arg.multiple { + #| if required { + #| parts.push("<\{arg.name}...>") + #| } else { + #| parts.push("[\{arg.name}...]") + #| } + #| } else if required { + #| parts.push("<\{arg.name}>") + #| } else { + #| parts.push("[\{arg.name}]") + #| } + #| } + #| parts.join(" ") + #|} + #|fn option_entries(cmd : Command) -> Array[String] { + #| let args = cmd.args + #| let display = Array::new(capacity=args.length() + 2) + #| let builtin_help_short = help_flag_enabled(cmd) && + #| !has_short_option(args, 'h') + #| let builtin_help_long = help_flag_enabled(cmd) && + #| !has_long_option(args, "help") + #| let builtin_version_short = version_flag_enabled(cmd) && + #| !has_short_option(args, 'V') + #| let builtin_version_long = version_flag_enabled(cmd) && + #| !has_long_option(args, "version") + #| let builtin_help_label = builtin_option_label( + #| builtin_help_short, builtin_help_long, "-h", "--help", + #| ) + #| if builtin_help_label is Some(label) { + #| display.push((label, "Show help information.")) + #| } + #| let builtin_version_label = builtin_option_label( + #| builtin_version_short, builtin_version_long, "-V", "--version", + #| ) + #| if builtin_version_label is Some(label) { + #| display.push((label, "Show version information.")) + #| } + #| for arg in args { + #| guard arg.info + #| is (OptionInfo(long~, short~, ..) | FlagInfo(long~, short~, ..)) && + #| (long is Some(_) || short is Some(_)) else { + #| continue + #| } + #| if arg.hidden { + #| continue + #| } + #| let name = if arg.info is OptionInfo(_) { + #| "\{arg_display(arg)} <\{arg.name}>" + #| } else { + #| arg_display(arg) + #| } + #| display.push((name, arg_doc(arg))) + #| } + #| format_entries(display) + #|} + #|fn has_long_option(args : Array[Arg], name : String) -> Bool { + #| for arg in args { + #| if arg.info is (OptionInfo(long~, ..) | FlagInfo(long~, ..)) && + #| long is Some(long) && + #| long == name { + #| return true + #| } + #| } + #| false + #|} + #|fn has_short_option(args : Array[Arg], value : Char) -> Bool { + #| for arg in args { + #| if arg.info is (OptionInfo(short~, ..) | FlagInfo(short~, ..)) && + #| short is Some(short) && + #| short == value { + #| return true + #| } + #| } + #| false + #|} + #|fn builtin_option_label( + #| has_short : Bool, + #| has_long : Bool, + #| short_label : String, + #| long_label : String, + #|) -> String? { + #| if has_short && has_long { + #| Some("\{short_label}, \{long_label}") + #| } else if has_short { + #| Some(short_label) + #| } else if has_long { + #| Some(long_label) + #| } else { + #| None + #| } + #|} + #|fn positional_entries(cmd : Command) -> Array[String] { + #| let display = Array::new(capacity=cmd.args.length()) + #| for arg in positional_args(cmd.args) { + #| if arg.hidden { + #| continue + #| } + #| display.push((positional_display(arg), arg_doc(arg))) + #| } + #| format_entries(display) + #|} + #|fn subcommand_entries(cmd : Command) -> Array[String] { + #| let display = Array::new(capacity=cmd.subcommands.length() + 1) + #| for sub in cmd.subcommands { + #| if sub.hidden { + #| continue + #| } + #| display.push((sub.name, sub.about.unwrap_or(""))) + #| } + #| if help_subcommand_enabled(cmd) { + #| display.push(("help", "Print help for the subcommand(s).")) + #| } + #| format_entries(display) + #|} + #|fn group_entries(cmd : Command) -> Array[String] { + #| let display = Array::new(capacity=cmd.groups.length()) + #| for group in cmd.groups { + #| let members = group_members(cmd, group) + #| if members == "" { + #| continue + #| } + #| display.push((group_label(group), members)) + #| } + #| format_entries(display) + #|} + #|fn render_section( + #| header : String, + #| lines : Array[String], + #| keep_empty? : Bool = false, + #|) -> String { + #| if lines.length() == 0 { + #| if keep_empty { + #| ( + #| $| + #| $| + #| $|\{header} + #| ) + #| } else { + #| "" + #| } + #| } else { + #| let body = lines.join("\n") + #| ( + #| $| + #| $| + #| $|\{header} + #| $|\{body} + #| ) + #| } + #|} + #|fn format_entries(display : Array[(String, String)]) -> Array[String] { + #| let entries = Array::new(capacity=display.length()) + #| let max_len = for item in display; max_len = 0 { + #| let (name, _) = item + #| if name.length() > max_len { + #| continue name.length() + #| } else { + #| continue max_len + #| } + #| } nobreak { + #| max_len + #| } + #| for item in display { + #| let (name, doc) = item + #| let padding = " ".repeat(max_len - name.length() + 2) + #| entries.push(" \{name}\{padding}\{doc}") + #| } + #| entries + #|} + #|fn arg_display(arg : Arg) -> String { + #| let parts = Array::new(capacity=2) + #| let (short, long) = match arg.info { + #| OptionInfo(short~, long~, ..) => (short, long) + #| FlagInfo(short~, long~, ..) => (short, long) + #| PositionalInfo(_) => (None, None) + #| } + #| if short is Some(short) { + #| parts.push("-\{short}") + #| } + #| if long is Some(long) { + #| if arg.info is FlagInfo(negatable=true, ..) { + #| parts.push("--[no-]\{long}") + #| } else { + #| parts.push("--\{long}") + #| } + #| } + #| if parts.length() == 0 { + #| arg.name + #| } else { + #| parts.join(", ") + #| } + #|} + #|fn positional_display(arg : Arg) -> String { + #| if arg.multiple { + #| "\{arg.name}..." + #| } else { + #| arg.name + #| } + #|} + #|fn arg_doc(arg : Arg) -> String { + #| let notes = [] + #| match arg.env { + #| Some(env_name) => notes.push("[env: \{env_name}]") + #| None => () + #| } + #| if arg.info + #| is (OptionInfo(default_values~, ..) | PositionalInfo(default_values~, ..)) && + #| default_values is Some(values) { + #| if values.length() > 0 { + #| let defaults = values.join(", ") + #| notes.push("[default: \{defaults}]") + #| } + #| } + #| let help = arg.about.unwrap_or("") + #| if help == "" { + #| notes.join(" ") + #| } else if notes.length() > 0 { + #| let notes_text = notes.join(" ") + #| "\{help} \{notes_text}" + #| } else { + #| help + #| } + #|} + #|fn has_subcommands_for_help(cmd : Command) -> Bool { + #| if help_subcommand_enabled(cmd) { + #| return true + #| } + #| for sub in cmd.subcommands { + #| if !sub.hidden { + #| return true + #| } + #| } + #| false + #|} + #|fn is_required_arg(arg : Arg) -> Bool { + #| if arg.required { + #| true + #| } else { + #| let (min, _) = arg_min_max(arg) + #| min > 0 + #| } + #|} + #|fn group_label(group : ArgGroup) -> String { + #| let tags = [] + #| if group.required { + #| tags.push("[required]") + #| } + #| if !group.multiple { + #| tags.push("[exclusive]") + #| } + #| if tags.length() == 0 { + #| group.name + #| } else { + #| let tags_text = tags.join(" ") + #| "\{group.name} \{tags_text}" + #| } + #|} + #|fn group_members(cmd : Command, group : ArgGroup) -> String { + #| let members = [] + #| for arg in cmd.args { + #| if arg.hidden { + #| continue + #| } + #| if arg_in_group(arg, group) { + #| members.push(group_member_display(arg)) + #| } + #| } + #| members.join(", ") + #|} + #|fn group_member_display(arg : Arg) -> String { + #| let base = arg_display(arg) + #| match arg.info { + #| FlagInfo(_) => base + #| OptionInfo(_) => "\{base} <\{arg.name}>" + #| PositionalInfo(_) => base + #| } + #|} + ), + "matches.mbt": ( + #|using @debug {trait Debug, type Repr} + #|pub enum ValueSource { + #| Argv + #| Env + #| Default + #|} derive(Eq, Show, Debug) + #|pub struct Matches { + #| flags : Map[String, Bool] + #| values : Map[String, Array[String]] + #| flag_counts : Map[String, Int] + #| sources : Map[String, ValueSource] + #| subcommand : (String, Matches)? + #| priv counts : Map[String, Int] + #| priv flag_sources : Map[String, ValueSource] + #| priv value_sources : Map[String, ValueSource] + #| priv mut parsed_subcommand : (String, Matches)? + #|} derive(Debug) + #|fn new_matches_parse_state() -> Matches { + #| { + #| flags: {}, + #| values: {}, + #| flag_counts: {}, + #| sources: {}, + #| subcommand: None, + #| counts: {}, + #| flag_sources: {}, + #| value_sources: {}, + #| parsed_subcommand: None, + #| } + #|} + ), + "parser.mbt": ( + #|fn raise_help(text : String) -> Unit raise DisplayHelp { + #| raise Message(text) + #|} + #|fn raise_version(text : String) -> Unit raise DisplayVersion { + #| raise Message(text) + #|} + #|fn[T] raise_unknown_long( + #| name : String, + #| long_index : Map[String, Arg], + #|) -> T raise ArgParseError { + #| let hint = suggest_long(name, long_index) + #| raise UnknownArgument("--\{name}", hint) + #|} + #|fn[T] raise_unknown_short( + #| short : Char, + #| short_index : Map[Char, Arg], + #|) -> T raise ArgParseError { + #| let hint = suggest_short(short, short_index) + #| raise UnknownArgument("-\{short}", hint) + #|} + #|fn[T] raise_subcommand_conflict(name : String) -> T raise ArgParseError { + #| raise InvalidArgument( + #| "subcommand '\{name}' cannot be used with positional arguments", + #| ) + #|} + #|fn help_context_command( + #| cmd : Command, + #| inherited_globals : Array[Arg], + #| command_path : String, + #|) -> Command { + #| let help_name = if command_path == "" { cmd.name } else { command_path } + #| { ..cmd, args: inherited_globals + cmd.args, name: help_name } + #|} + #|fn render_help_for_context( + #| cmd : Command, + #| inherited_globals : Array[Arg], + #| command_path : String, + #|) -> String { + #| let help_cmd = help_context_command(cmd, inherited_globals, command_path) + #| render_help(help_cmd) + #|} + #|fn raise_context_help( + #| cmd : Command, + #| inherited_globals : Array[Arg], + #| command_path : String, + #|) -> Unit raise DisplayHelp { + #| raise_help(render_help_for_context(cmd, inherited_globals, command_path)) + #|} + #|fn default_argv() -> Array[String] { + #| let args = @env.args() + #| if args.length() > 1 { + #| args[1:].to_array() + #| } else { + #| [] + #| } + #|} + #|fn merge_global_defs( + #| inherited_globals : Array[Arg], + #| globals_here : Array[Arg], + #|) -> Array[Arg] { + #| let merged = inherited_globals.copy() + #| for global in globals_here { + #| match merged.search_by(arg => arg.name == global.name) { + #| Some(idx) => merged[idx] = global + #| None => merged.push(global) + #| } + #| } + #| merged + #|} + #|fn env_resolution_args( + #| inherited_globals : Array[Arg], + #| args : Array[Arg], + #|) -> Array[Arg] { + #| let merged_globals = merge_global_defs( + #| inherited_globals, + #| collect_globals(args), + #| ) + #| let local_only = args.filter(arg => { + #| !(arg.global && arg.info is (FlagInfo(_) | OptionInfo(_))) + #| }) + #| merged_globals + local_only + #|} + #|fn format_error_with_help( + #| msg : String, + #| cmd : Command, + #| inherited_globals : Array[Arg], + #| command_path : String, + #|) -> String { + #| "\{msg}\n\n\{render_help_for_context(cmd, inherited_globals, command_path)}" + #|} + #|fn arg_usage_token_for_group(arg : Arg) -> String { + #| let base = match arg.info { + #| OptionInfo(long~, short~, ..) | FlagInfo(long~, short~, ..) => + #| if long is Some(long) { + #| "--\{long}" + #| } else if short is Some(short) { + #| "-\{short}" + #| } else { + #| arg.name + #| } + #| PositionalInfo(_) => + #| if arg.multiple { + #| "<\{arg.name}...>" + #| } else { + #| "<\{arg.name}>" + #| } + #| } + #| if arg.info is OptionInfo(_) { + #| "\{base} <\{arg.name}>" + #| } else { + #| base + #| } + #|} + #|fn group_usage_expr( + #| groups : Array[ArgGroup], + #| args : Array[Arg], + #| name : String, + #|) -> String? { + #| for group in groups { + #| if group.name != name { + #| continue + #| } + #| let members = [] + #| for member_name in group.args { + #| if args.search_by(arg => arg.name == member_name) is Some(idx) { + #| let item = args[idx] + #| if item.hidden { + #| continue + #| } + #| members.push(arg_usage_token_for_group(item)) + #| } + #| } + #| if members.length() == 0 { + #| return None + #| } + #| let joined = members.join("|") + #| return Some("<\{joined}>") + #| } + #| None + #|} + #|fn missing_group_error_message( + #| cmd : Command, + #| inherited_globals : Array[Arg], + #| command_path : String, + #| group_name : String, + #|) -> String { + #| let help_cmd = help_context_command(cmd, inherited_globals, command_path) + #| if group_usage_expr(help_cmd.groups, help_cmd.args, group_name) is Some(expr) { + #| ( + #| $|error: the following required arguments were not provided: + #| $| \{expr} + #| ) + #| } else { + #| MissingGroup(group_name).arg_parse_error_message() + #| } + #|} + #|fn arg_error_for_parse_failure( + #| err : ArgParseError, + #| cmd : Command, + #| inherited_globals : Array[Arg], + #| command_path : String, + #|) -> ArgError { + #| match err { + #| MissingGroup(name) => + #| Message( + #| format_error_with_help( + #| missing_group_error_message( + #| cmd, inherited_globals, command_path, name, + #| ), + #| cmd, + #| inherited_globals, + #| command_path, + #| ), + #| ) + #| GroupConflict(_) => + #| Message( + #| format_error_with_help( + #| err.arg_parse_error_message(), + #| cmd, + #| inherited_globals, + #| command_path, + #| ), + #| ) + #| _ => + #| Message( + #| format_error_with_help( + #| err.arg_parse_error_message(), + #| cmd, + #| inherited_globals, + #| command_path, + #| ), + #| ) + #| } + #|} + #|fn parse_command( + #| cmd : Command, + #| argv : ArrayView[String], + #| env : Map[String, String], + #| inherited_globals : Array[Arg], + #| inherited_version_long : Map[String, String], + #| inherited_version_short : Map[Char, String], + #| command_path : String, + #| seed_matches? : Matches = new_matches_parse_state(), + #|) -> Matches raise { + #| parse_command_impl( + #| cmd, argv, env, inherited_globals, inherited_version_long, inherited_version_short, + #| command_path, seed_matches, + #| ) catch { + #| UnknownArgument(arg, hint) => + #| raise arg_error_for_parse_failure( + #| UnknownArgument(arg, hint), + #| cmd, + #| inherited_globals, + #| command_path, + #| ) + #| InvalidArgument(msg) => + #| raise arg_error_for_parse_failure( + #| InvalidArgument(msg), + #| cmd, + #| inherited_globals, + #| command_path, + #| ) + #| MissingValue(name) => + #| raise arg_error_for_parse_failure( + #| MissingValue(name), + #| cmd, + #| inherited_globals, + #| command_path, + #| ) + #| MissingRequired(name, by) => + #| raise arg_error_for_parse_failure( + #| MissingRequired(name, by), + #| cmd, + #| inherited_globals, + #| command_path, + #| ) + #| TooFewValues(name, got, min) => + #| raise arg_error_for_parse_failure( + #| TooFewValues(name, got, min), + #| cmd, + #| inherited_globals, + #| command_path, + #| ) + #| TooManyValues(name, got, max) => + #| raise arg_error_for_parse_failure( + #| TooManyValues(name, got, max), + #| cmd, + #| inherited_globals, + #| command_path, + #| ) + #| TooManyPositionals(value, arg) => + #| raise arg_error_for_parse_failure( + #| TooManyPositionals(value, arg), + #| cmd, + #| inherited_globals, + #| command_path, + #| ) + #| InvalidValue(msg) => + #| raise arg_error_for_parse_failure( + #| InvalidValue(msg), + #| cmd, + #| inherited_globals, + #| command_path, + #| ) + #| MissingGroup(name) => + #| raise arg_error_for_parse_failure( + #| MissingGroup(name), + #| cmd, + #| inherited_globals, + #| command_path, + #| ) + #| GroupConflict(name) => + #| raise arg_error_for_parse_failure( + #| GroupConflict(name), + #| cmd, + #| inherited_globals, + #| command_path, + #| ) + #| Unsupported(msg) => + #| raise ArgError::Message( + #| "error: command definition validation failed: \{msg}", + #| ) + #| err => raise err + #| } + #|} + #|fn parse_command_impl( + #| cmd : Command, + #| argv : ArrayView[String], + #| env : Map[String, String], + #| inherited_globals : Array[Arg], + #| inherited_version_long : Map[String, String], + #| inherited_version_short : Map[Char, String], + #| command_path : String, + #| seed_matches : Matches, + #|) -> Matches raise { + #| match cmd.build_error { + #| Some(err) => raise err + #| None => () + #| } + #| let args = cmd.args + #| let groups = cmd.groups + #| let subcommands = cmd.subcommands + #| if cmd.arg_required_else_help && argv.length() == 0 { + #| raise_context_help(cmd, inherited_globals, command_path) + #| } + #| let matches = seed_matches + #| let globals_here = collect_globals(args) + #| let child_globals = merge_global_defs(inherited_globals, globals_here) + #| let child_version_long = inherited_version_long.copy() + #| let child_version_short = inherited_version_short.copy() + #| for global in globals_here { + #| if global.info is FlagInfo(long~, short~, action=Version, ..) { + #| if long is Some(name) { + #| child_version_long[name] = command_version(cmd) + #| } + #| if short is Some(short) { + #| child_version_short[short] = command_version(cmd) + #| } + #| } + #| } + #| let long_index = build_long_index(inherited_globals, args) + #| let short_index = build_short_index(inherited_globals, args) + #| let builtin_help_short = help_flag_enabled(cmd) && + #| short_index.get('h') is None + #| let builtin_help_long = help_flag_enabled(cmd) && + #| long_index.get("help") is None + #| let builtin_version_short = version_flag_enabled(cmd) && + #| short_index.get('V') is None + #| let builtin_version_long = version_flag_enabled(cmd) && + #| long_index.get("version") is None + #| let positionals = positional_args(args) + #| let positional_values = [] + #| let mut i = 0 + #| let mut positional_arg_found = false + #| while i < argv.length() { + #| let arg = argv[i] + #| if arg == "--" { + #| if i + 1 < argv.length() { + #| positional_arg_found = true + #| } + #| for rest in argv[i + 1:] { + #| positional_values.push(rest) + #| } + #| break + #| } + #| if builtin_help_short && arg == "-h" { + #| raise_context_help(cmd, inherited_globals, command_path) + #| } + #| if builtin_help_long && arg == "--help" { + #| raise_context_help(cmd, inherited_globals, command_path) + #| } + #| if builtin_version_short && arg == "-V" { + #| raise_version(command_version(cmd)) + #| } + #| if builtin_version_long && arg == "--version" { + #| raise_version(command_version(cmd)) + #| } + #| if should_parse_as_positional( + #| arg, positionals, positional_values, long_index, short_index, + #| ) { + #| positional_values.push(arg) + #| positional_arg_found = true + #| i = i + 1 + #| continue + #| } + #| if arg.has_prefix("--") { + #| let (name, inline) = split_long(arg) + #| if builtin_help_long && name == "help" { + #| if inline is Some(_) { + #| raise ArgParseError::InvalidArgument(arg) + #| } + #| raise_context_help(cmd, inherited_globals, command_path) + #| } + #| if builtin_version_long && name == "version" { + #| if inline is Some(_) { + #| raise ArgParseError::InvalidArgument(arg) + #| } + #| raise_version(command_version(cmd)) + #| } + #| match long_index.get(name) { + #| None => + #| if name is [.. "no-", .. target] && + #| long_index.get(target.to_string()) + #| is Some({ info: FlagInfo(negatable=true, action~, ..), .. } as spec) { + #| if inline is Some(_) { + #| raise ArgParseError::InvalidArgument(arg) + #| } + #| let value = match action { + #| SetFalse => true + #| _ => false + #| } + #| if action is Count { + #| matches.counts[spec.name] = 0 + #| } + #| matches.flags[spec.name] = value + #| matches.flag_sources[spec.name] = Argv + #| } else { + #| raise_unknown_long(name, long_index) + #| } + #| Some(spec) => + #| if spec.info is (OptionInfo(_) | PositionalInfo(_)) { + #| check_duplicate_set_occurrence(matches, spec) + #| if inline is Some(v) { + #| assign_value(matches, spec, v, Argv) + #| } else { + #| let can_take_next = i + 1 < argv.length() && + #| !should_stop_option_value( + #| argv[i + 1], + #| spec, + #| long_index, + #| short_index, + #| ) + #| if can_take_next { + #| i = i + 1 + #| assign_value(matches, spec, argv[i], Argv) + #| } else { + #| raise ArgParseError::MissingValue("--\{name}") + #| } + #| } + #| } else { + #| if inline is Some(_) { + #| raise ArgParseError::InvalidArgument(arg) + #| } + #| match spec.info { + #| FlagInfo(action=Help, ..) => + #| raise_context_help(cmd, inherited_globals, command_path) + #| FlagInfo(action=Version, ..) => + #| raise_version( + #| version_text_for_long_action( + #| cmd, name, inherited_version_long, + #| ), + #| ) + #| _ => apply_flag(matches, spec, Argv) + #| } + #| } + #| } + #| i = i + 1 + #| continue + #| } + #| if arg.has_prefix("-") && arg != "-" { + #| let chars = arg.iter() + #| ignore(chars.next()) + #| let mut consumed_next = false + #| while chars.next() is Some(short) { + #| if short == 'h' && builtin_help_short { + #| raise_context_help(cmd, inherited_globals, command_path) + #| } + #| if short == 'V' && builtin_version_short { + #| raise_version(command_version(cmd)) + #| } + #| let spec = match short_index.get(short) { + #| Some(v) => v + #| None => raise_unknown_short(short, short_index) + #| } + #| if spec.info is (OptionInfo(_) | PositionalInfo(_)) { + #| check_duplicate_set_occurrence(matches, spec) + #| let rest = String::from_iter(chars) + #| if rest != "" { + #| let inline = match rest.strip_prefix("=") { + #| Some(view) => view.to_string() + #| None => rest + #| } + #| assign_value(matches, spec, inline, Argv) + #| } else { + #| let can_take_next = i + 1 < argv.length() && + #| !should_stop_option_value( + #| argv[i + 1], + #| spec, + #| long_index, + #| short_index, + #| ) + #| if can_take_next { + #| consumed_next = true + #| assign_value(matches, spec, argv[i + 1], Argv) + #| } else { + #| raise ArgParseError::MissingValue("-\{short}") + #| } + #| } + #| break + #| } else { + #| match spec.info { + #| FlagInfo(action=Help, ..) => + #| raise_context_help(cmd, inherited_globals, command_path) + #| FlagInfo(action=Version, ..) => + #| raise_version( + #| version_text_for_short_action( + #| cmd, short, inherited_version_short, + #| ), + #| ) + #| _ => apply_flag(matches, spec, Argv) + #| } + #| } + #| } + #| i = i + 1 + (if consumed_next { 1 } else { 0 }) + #| continue + #| } + #| if help_subcommand_enabled(cmd) && arg == "help" { + #| if positional_arg_found { + #| raise_subcommand_conflict("help") + #| } + #| let rest = argv[i + 1:].to_array() + #| let (target, target_globals, target_path) = resolve_help_target( + #| cmd, rest, builtin_help_short, builtin_help_long, inherited_globals, command_path, + #| ) + #| let text = render_help_for_context(target, target_globals, target_path) + #| raise_help(text) + #| } + #| if subcommands.iter().find_first(sub => sub.name == arg) is Some(sub) { + #| if positional_arg_found { + #| raise_subcommand_conflict(sub.name) + #| } + #| let rest = argv[i + 1:].to_array() + #| let sub_path = if command_path == "" { + #| sub.name + #| } else { + #| "\{command_path} \{sub.name}" + #| } + #| let child_local_non_globals = collect_non_global_names(sub.args) + #| let child_seed = seed_child_globals_from_parent( + #| matches, child_globals, child_local_non_globals, + #| ) + #| let sub_matches = parse_command( + #| sub, + #| rest, + #| env, + #| child_globals, + #| child_version_long, + #| child_version_short, + #| sub_path, + #| seed_matches=child_seed, + #| ) + #| matches.parsed_subcommand = Some((sub.name, sub_matches)) + #| merge_globals_from_child( + #| matches, sub_matches, child_globals, child_local_non_globals, + #| ) + #| let env_args = env_resolution_args(inherited_globals, args) + #| let parent_matches = finalize_matches( + #| cmd, args, groups, matches, positionals, positional_values, env_args, env, + #| ) + #| validate_relationships(parent_matches, args) + #| match parent_matches.parsed_subcommand { + #| Some((sub_name, sub_m)) => { + #| propagate_globals_to_child( + #| parent_matches, sub_m, child_globals, child_local_non_globals, + #| ) + #| parent_matches.parsed_subcommand = Some((sub_name, sub_m)) + #| } + #| None => () + #| } + #| return parent_matches + #| } + #| positional_values.push(arg) + #| positional_arg_found = true + #| i = i + 1 + #| } + #| let env_args = env_resolution_args(inherited_globals, args) + #| let final_matches = finalize_matches( + #| cmd, args, groups, matches, positionals, positional_values, env_args, env, + #| ) + #| validate_relationships(final_matches, args) + #| final_matches + #|} + #|fn finalize_matches( + #| cmd : Command, + #| args : Array[Arg], + #| groups : Array[ArgGroup], + #| matches : Matches, + #| positionals : Array[Arg], + #| positional_values : Array[String], + #| env_args : Array[Arg], + #| env : Map[String, String], + #|) -> Matches raise ArgParseError { + #| assign_positionals(matches, positionals, positional_values) + #| apply_env(matches, env_args, env) + #| apply_defaults(matches, env_args) + #| validate_values(args, matches) + #| validate_groups(args, groups, matches) + #| validate_command_policies(cmd, matches) + #| matches + #|} + #|fn help_subcommand_enabled(cmd : Command) -> Bool { + #| !cmd.disable_help_subcommand && cmd.subcommands.length() > 0 + #|} + #|fn help_flag_enabled(cmd : Command) -> Bool { + #| !cmd.disable_help_flag + #|} + #|fn version_flag_enabled(cmd : Command) -> Bool { + #| !cmd.disable_version_flag && cmd.version is Some(_) + #|} + #|fn command_version(cmd : Command) -> String { + #| cmd.version.unwrap_or("") + #|} + #|fn version_text_for_long_action( + #| cmd : Command, + #| long : String, + #| inherited_version_long : Map[String, String], + #|) -> String { + #| for arg in cmd.args { + #| if arg.info is FlagInfo(long=Some(name), action=Version, ..) && name == long { + #| return command_version(cmd) + #| } + #| } + #| inherited_version_long.get(long).unwrap_or(command_version(cmd)) + #|} + #|fn version_text_for_short_action( + #| cmd : Command, + #| short : Char, + #| inherited_version_short : Map[Char, String], + #|) -> String { + #| for arg in cmd.args { + #| if arg.info is FlagInfo(short=Some(value), action=Version, ..) && + #| value == short { + #| return command_version(cmd) + #| } + #| } + #| inherited_version_short.get(short).unwrap_or(command_version(cmd)) + #|} + ), + "parser_globals_merge.mbt": ( + #|fn source_priority(source : ValueSource?) -> Int { + #| match source { + #| Some(Argv) => 3 + #| Some(Env) => 2 + #| Some(Default) => 1 + #| None => 0 + #| } + #|} + #|fn prefer_child_source( + #| parent_source : ValueSource?, + #| child_source : ValueSource?, + #|) -> Bool { + #| let parent_priority = source_priority(parent_source) + #| let child_priority = source_priority(child_source) + #| if child_priority > parent_priority { + #| true + #| } else if child_priority < parent_priority { + #| false + #| } else { + #| child_source is Some(Argv) + #| } + #|} + #|fn strongest_source( + #| parent_source : ValueSource?, + #| child_source : ValueSource?, + #|) -> ValueSource? { + #| if prefer_child_source(parent_source, child_source) { + #| child_source + #| } else { + #| match parent_source { + #| Some(source) => Some(source) + #| None => child_source + #| } + #| } + #|} + #|fn merge_global_value_from_child( + #| parent : Matches, + #| child : Matches, + #| arg : Arg, + #| name : String, + #|) -> Unit raise ArgParseError { + #| let parent_vals = parent.values.get(name) + #| let child_vals = child.values.get(name) + #| let parent_source = parent.value_sources.get(name) + #| let child_source = child.value_sources.get(name) + #| let has_parent = parent_vals is Some(pv) && pv.length() > 0 + #| let has_child = child_vals is Some(cv) && cv.length() > 0 + #| if !has_parent && !has_child { + #| return + #| } + #| if arg.multiple || arg.info is OptionInfo(action=Append, ..) { + #| let both_argv = parent_source is Some(Argv) && child_source is Some(Argv) + #| if both_argv { + #| let merged = [] + #| if parent_vals is Some(pv) { + #| for v in pv { + #| merged.push(v) + #| } + #| } + #| if child_vals is Some(cv) { + #| for v in cv { + #| merged.push(v) + #| } + #| } + #| if merged.length() > 0 { + #| parent.values[name] = merged + #| parent.value_sources[name] = Argv + #| } + #| } else { + #| let choose_child = has_child && + #| (!has_parent || prefer_child_source(parent_source, child_source)) + #| if choose_child { + #| if child_vals is Some(cv) && cv.length() > 0 { + #| parent.values[name] = cv.copy() + #| } + #| match child_source { + #| Some(src) => parent.value_sources[name] = src + #| None => () + #| } + #| } else if parent_vals is Some(pv) && pv.length() > 0 { + #| parent.values[name] = pv.copy() + #| match parent_source { + #| Some(src) => parent.value_sources[name] = src + #| None => () + #| } + #| } + #| } + #| } else { + #| if has_parent && + #| has_child && + #| parent_source is Some(Argv) && + #| child_source is Some(Argv) && + #| arg.info is OptionInfo(action=Set, ..) { + #| raise InvalidArgument( + #| "argument '\{global_option_conflict_label(arg)}' cannot be used multiple times", + #| ) + #| } + #| let choose_child = has_child && + #| (!has_parent || prefer_child_source(parent_source, child_source)) + #| if choose_child { + #| if child_vals is Some(cv) && cv.length() > 0 { + #| parent.values[name] = cv.copy() + #| } + #| match child_source { + #| Some(src) => parent.value_sources[name] = src + #| None => () + #| } + #| } else if parent_vals is Some(pv) && pv.length() > 0 { + #| parent.values[name] = pv.copy() + #| match parent_source { + #| Some(src) => parent.value_sources[name] = src + #| None => () + #| } + #| } + #| } + #|} + #|fn merge_global_flag_from_child( + #| parent : Matches, + #| child : Matches, + #| arg : Arg, + #| name : String, + #|) -> Unit { + #| match child.flags.get(name) { + #| Some(v) => + #| if arg.info is FlagInfo(action=Count, ..) { + #| let has_parent = parent.flags.get(name) is Some(_) + #| let parent_source = parent.flag_sources.get(name) + #| let child_source = child.flag_sources.get(name) + #| let both_argv = parent_source is Some(Argv) && + #| child_source is Some(Argv) + #| if both_argv { + #| let parent_count = parent.counts.get(name).unwrap_or(0) + #| let child_count = child.counts.get(name).unwrap_or(0) + #| if child_count == 0 && !v { + #| parent.counts[name] = 0 + #| parent.flags[name] = false + #| } else { + #| let total = parent_count + child_count + #| parent.counts[name] = total + #| parent.flags[name] = total > 0 + #| } + #| match strongest_source(parent_source, child_source) { + #| Some(src) => parent.flag_sources[name] = src + #| None => () + #| } + #| } else { + #| let choose_child = !has_parent || + #| prefer_child_source(parent_source, child_source) + #| if choose_child { + #| let child_count = child.counts.get(name).unwrap_or(0) + #| parent.counts[name] = child_count + #| parent.flags[name] = child_count > 0 + #| match child_source { + #| Some(src) => parent.flag_sources[name] = src + #| None => () + #| } + #| } + #| } + #| } else { + #| let has_parent = parent.flags.get(name) is Some(_) + #| let parent_source = parent.flag_sources.get(name) + #| let child_source = child.flag_sources.get(name) + #| let choose_child = !has_parent || + #| prefer_child_source(parent_source, child_source) + #| if choose_child { + #| parent.flags[name] = v + #| match child_source { + #| Some(src) => parent.flag_sources[name] = src + #| None => () + #| } + #| } + #| } + #| None => () + #| } + #|} + #|fn seed_child_globals_from_parent( + #| parent : Matches, + #| globals : Array[Arg], + #| child_local_non_globals : @set.Set[String], + #|) -> Matches { + #| let seed = new_matches_parse_state() + #| let seen : @set.Set[String] = @set.new() + #| for arg in globals { + #| let name = arg.name + #| if child_local_non_globals.contains(name) || !seen.add_and_check(name) { + #| continue + #| } + #| if arg.info is (OptionInfo(_) | PositionalInfo(_)) { + #| if parent.values.get(name) is Some(_) && + #| parent.value_sources.get(name) is Some(Argv) { + #| seed.values[name] = [] + #| seed.value_sources[name] = Argv + #| } + #| continue + #| } + #| if parent.flags.get(name) is Some(v) && + #| parent.flag_sources.get(name) is Some(Argv) { + #| seed.flags[name] = v + #| seed.flag_sources[name] = Argv + #| if arg.info is FlagInfo(action=Count, ..) { + #| seed.counts[name] = 0 + #| } + #| } + #| } + #| seed + #|} + #|fn merge_globals_from_child( + #| parent : Matches, + #| child : Matches, + #| globals : Array[Arg], + #| child_local_non_globals : @set.Set[String], + #|) -> Unit raise ArgParseError { + #| for arg in globals { + #| let name = arg.name + #| if child_local_non_globals.contains(name) { + #| continue + #| } + #| match arg.info { + #| OptionInfo(_) | PositionalInfo(_) => + #| merge_global_value_from_child(parent, child, arg, name) + #| FlagInfo(_) => merge_global_flag_from_child(parent, child, arg, name) + #| } + #| } + #|} + #|fn global_option_conflict_label(arg : Arg) -> String { + #| match arg.info { + #| FlagInfo(long~, short~, ..) | OptionInfo(long~, short~, ..) => + #| match long { + #| Some(name) => "--\{name}" + #| None => + #| match short { + #| Some(short) => "-\{short}" + #| None => arg.name + #| } + #| } + #| PositionalInfo(_) => arg.name + #| } + #|} + #|fn propagate_globals_to_child( + #| parent : Matches, + #| child : Matches, + #| globals : Array[Arg], + #| child_local_non_globals : @set.Set[String], + #|) -> Unit { + #| for arg in globals { + #| let name = arg.name + #| if child_local_non_globals.contains(name) { + #| continue + #| } + #| if arg.info is (OptionInfo(_) | PositionalInfo(_)) { + #| match parent.values.get(name) { + #| Some(values) => { + #| child.values[name] = values.copy() + #| match parent.value_sources.get(name) { + #| Some(src) => child.value_sources[name] = src + #| None => () + #| } + #| } + #| None => () + #| } + #| } else { + #| match parent.flags.get(name) { + #| Some(v) => { + #| child.flags[name] = v + #| match parent.flag_sources.get(name) { + #| Some(src) => child.flag_sources[name] = src + #| None => () + #| } + #| if arg.info is FlagInfo(action=Count, ..) { + #| match parent.counts.get(name) { + #| Some(c) => child.counts[name] = c + #| None => () + #| } + #| } + #| } + #| None => () + #| } + #| } + #| } + #| match child.parsed_subcommand { + #| Some((sub_name, sub_m)) => { + #| propagate_globals_to_child(parent, sub_m, globals, @set.new()) + #| child.parsed_subcommand = Some((sub_name, sub_m)) + #| } + #| None => () + #| } + #|} + ), + "parser_lookup.mbt": ( + #|fn build_long_index( + #| globals : Array[Arg], + #| args : Array[Arg], + #|) -> Map[String, Arg] { + #| let index : Map[String, Arg] = {} + #| for arg in globals.iter() + args.iter() { + #| if arg.info is (FlagInfo(long~, ..) | OptionInfo(long~, ..)) && + #| long is Some(name) { + #| index[name] = arg + #| } + #| } + #| index + #|} + #|fn build_short_index(globals : Array[Arg], args : Array[Arg]) -> Map[Char, Arg] { + #| let index : Map[Char, Arg] = {} + #| for arg in globals { + #| if arg.info is (FlagInfo(short~, ..) | OptionInfo(short~, ..)) && + #| short is Some(value) { + #| index[value] = arg + #| } + #| } + #| for arg in args { + #| if arg.info is (FlagInfo(short~, ..) | OptionInfo(short~, ..)) && + #| short is Some(value) { + #| index[value] = arg + #| } + #| } + #| index + #|} + #|fn collect_globals(args : Array[Arg]) -> Array[Arg] { + #| args.filter(arg => arg.global && arg.info is (FlagInfo(_) | OptionInfo(_))) + #|} + #|fn collect_non_global_names(args : Array[Arg]) -> @set.Set[String] { + #| @set.from_iter(args.iter().filter(arg => !arg.global).map(arg => arg.name)) + #|} + #|fn resolve_help_target( + #| cmd : Command, + #| argv : Array[String], + #| builtin_help_short : Bool, + #| builtin_help_long : Bool, + #| inherited_globals : Array[Arg], + #| command_path : String, + #|) -> (Command, Array[Arg], String) raise ArgParseError { + #| let targets = match argv { + #| [.. pre, "-h"] if builtin_help_short => pre + #| [.. pre, "--help"] if builtin_help_long => pre + #| _ => argv + #| } + #| for + #| name in targets + #| current = cmd, + #| current_path = command_path, + #| current_globals = inherited_globals, + #| subs = cmd.subcommands { + #| if name.has_prefix("-") { + #| raise InvalidArgument("unexpected help argument: \{name}") + #| } + #| guard subs.iter().find_first(sub => sub.name == name) is Some(sub) else { + #| raise InvalidArgument("unknown subcommand: \{name}") + #| } + #| let current_globals = merge_global_defs( + #| current_globals, + #| collect_globals(current.args), + #| ) + #| let current_path = if current_path == "" { + #| sub.name + #| } else { + #| "\{current_path} \{sub.name}" + #| } + #| continue sub, current_path, current_globals, sub.subcommands + #| } nobreak { + #| (current, current_globals, current_path) + #| } + #|} + #|fn split_long(arg : String) -> (String, String?) { + #| let parts = [] + #| for part in arg.split("=") { + #| parts.push(part.to_string()) + #| } + #| if parts.length() <= 1 { + #| let name = match parts[0].strip_prefix("--") { + #| Some(view) => view.to_string() + #| None => parts[0] + #| } + #| (name, None) + #| } else { + #| let name = match parts[0].strip_prefix("--") { + #| Some(view) => view.to_string() + #| None => parts[0] + #| } + #| let value = parts[1:].to_array().join("=") + #| (name, Some(value)) + #| } + #|} + ), + "parser_positionals.mbt": ( + #|fn positional_args(args : Array[Arg]) -> Array[Arg] { + #| let ordered = [] + #| for arg in args { + #| if arg.info is PositionalInfo(_) { + #| ordered.push(arg) + #| } + #| } + #| ordered + #|} + #|fn next_positional(positionals : Array[Arg], collected : Array[String]) -> Arg? { + #| let target = collected.length() + #| let total = target + 1 + #| for idx in 0..= total { + #| break None + #| } + #| let arg = positionals[idx] + #| let remaining = total - cursor + #| let take = if arg.multiple { + #| let (min, max) = arg_min_max(arg) + #| let reserve = remaining_positional_min(positionals, idx + 1) + #| let mut take = remaining - reserve + #| if take < 0 { + #| take = 0 + #| } + #| match max { + #| Some(max_count) if take > max_count => take = max_count + #| _ => () + #| } + #| if take < min { + #| take = min + #| } + #| if take > remaining { + #| take = remaining + #| } + #| take + #| } else if remaining > 0 { + #| 1 + #| } else { + #| 0 + #| } + #| if take > 0 && target < cursor + take { + #| break Some(arg) + #| } + #| continue cursor + take + #| } nobreak { + #| None + #| } + #|} + #|fn should_parse_as_positional( + #| arg : String, + #| positionals : Array[Arg], + #| collected : Array[String], + #| long_index : Map[String, Arg], + #| short_index : Map[Char, Arg], + #|) -> Bool { + #| if !arg.has_prefix("-") || arg == "-" { + #| return false + #| } + #| let next = match next_positional(positionals, collected) { + #| Some(v) => v + #| None => return false + #| } + #| let next_allow = match next.info { + #| FlagInfo(_) => false + #| OptionInfo(allow_hyphen_values~, ..) + #| | PositionalInfo(allow_hyphen_values~, ..) => allow_hyphen_values + #| } + #| let allow = next_allow || is_negative_number(arg) + #| if !allow { + #| return false + #| } + #| if arg.has_prefix("--") { + #| let (name, _) = split_long(arg) + #| return long_index.get(name) is None + #| } + #| let short = arg.get_char(1) + #| match short { + #| Some(ch) => short_index.get(ch) is None + #| None => true + #| } + #|} + #|fn is_negative_number(arg : String) -> Bool { + #| if arg.length() < 2 { + #| return false + #| } + #| guard arg.get_char(0) is Some('-') else { return false } + #| for i = 1; i < arg.length(); { + #| let ch = arg.get_char(i).unwrap() + #| if ch < '0' || ch > '9' { + #| return false + #| } + #| continue i + ch.utf16_len() + #| } + #| true + #|} + ), + "parser_suggest.mbt": ( + #|fn suggest_long(name : String, long_index : Map[String, Arg]) -> String? { + #| let candidates = long_index.keys().collect() + #| if suggest_name(name, candidates) is Some(best) { + #| Some("--\{best}") + #| } else { + #| None + #| } + #|} + #|fn suggest_short(short : Char, short_index : Map[Char, Arg]) -> String? { + #| let candidates = short_index.keys().map(c => c.to_string()).collect() + #| let input = short.to_string() + #| if suggest_name(input, candidates) is Some(best) { + #| Some("-\{best}") + #| } else { + #| None + #| } + #|} + #|fn suggest_name(input : String, candidates : Array[String]) -> String? { + #| let max_dist = suggestion_threshold(input.length()) + #| for cand in candidates; best = (None : String?), best_dist = 0 { + #| let dist = levenshtein(input, cand) + #| if best is None || dist < best_dist { + #| continue Some(cand), dist + #| } else { + #| continue best, best_dist + #| } + #| } nobreak { + #| match best { + #| Some(name) if best_dist <= max_dist => Some(name) + #| _ => None + #| } + #| } + #|} + #|fn suggestion_threshold(len : Int) -> Int { + #| if len <= 4 { + #| 1 + #| } else if len <= 8 { + #| 2 + #| } else { + #| 3 + #| } + #|} + #|fn levenshtein(a : String, b : String) -> Int { + #| let aa = a.to_array() + #| let bb = b.to_array() + #| let m = aa.length() + #| let n = bb.length() + #| if m == 0 { + #| return n + #| } + #| if n == 0 { + #| return m + #| } + #| let mut prev = Array::new(capacity=n + 1) + #| let mut curr = Array::new(capacity=n + 1) + #| for j = 0; j <= n; { + #| prev.push(j) + #| curr.push(0) + #| continue j + 1 + #| } + #| for i = 1; i <= m; { + #| curr[0] = i + #| for j2 = 1; j2 <= n; { + #| let cost = if aa[i - 1] == bb[j2 - 1] { 0 } else { 1 } + #| let del = prev[j2] + 1 + #| let ins = curr[j2 - 1] + 1 + #| let sub = prev[j2 - 1] + cost + #| curr[j2] = if del < ins { + #| if del < sub { + #| del + #| } else { + #| sub + #| } + #| } else if ins < sub { + #| ins + #| } else { + #| sub + #| } + #| continue j2 + 1 + #| } + #| let temp = prev + #| prev = curr + #| curr = temp + #| continue i + 1 + #| } + #| prev[n] + #|} + ), + "parser_validate.mbt": ( + #|priv struct ValidationCtx { + #| inherited_global_names : @set.Set[String] + #| seen_names : @set.Set[String] + #| seen_long : @set.Set[String] + #| seen_short : @set.Set[Char] + #| args : Array[Arg] + #|} + #|fn ValidationCtx::new( + #| inherited_global_names? : @set.Set[String] = @set.new(), + #|) -> ValidationCtx { + #| { + #| inherited_global_names: inherited_global_names.copy(), + #| seen_names: @set.new(), + #| seen_long: @set.new(), + #| seen_short: @set.new(), + #| args: [], + #| } + #|} + #|fn ValidationCtx::record_arg( + #| self : ValidationCtx, + #| arg : Arg, + #|) -> Unit raise ArgBuildError { + #| if !self.seen_names.add_and_check(arg.name) { + #| raise Unsupported("duplicate arg name: \{arg.name}") + #| } + #| if !arg.global && self.inherited_global_names.contains(arg.name) { + #| raise Unsupported( + #| "arg '\{arg.name}' shadows an inherited global; rename the arg or mark it global", + #| ) + #| } + #| fn check_long(name) raise _ { + #| if !self.seen_long.add_and_check(name) { + #| raise ArgBuildError::Unsupported("duplicate long option: --\{name}") + #| } + #| } + #| fn check_short(short) raise _ { + #| if !self.seen_short.add_and_check(short) { + #| raise ArgBuildError::Unsupported("duplicate short option: -\{short}") + #| } + #| } + #| match arg.info { + #| FlagInfo(long~, short~, negatable~, ..) => { + #| if long is Some(name) { + #| check_long(name) + #| if negatable { + #| check_long("no-\{name}") + #| } + #| } + #| if short is Some(short) { + #| check_short(short) + #| } + #| } + #| OptionInfo(long~, short~, ..) => { + #| if long is Some(name) { + #| check_long(name) + #| } + #| if short is Some(short) { + #| check_short(short) + #| } + #| } + #| PositionalInfo(_) => () + #| } + #| self.args.push(arg) + #|} + #|fn ValidationCtx::finalize(self : ValidationCtx) -> Unit raise ArgBuildError { + #| validate_requires_conflicts_targets(self.args, self.seen_names) + #|} + #|fn validate_command( + #| cmd : Command, + #| args : Array[Arg], + #| groups : Array[ArgGroup], + #| inherited_globals : Array[Arg], + #|) -> Unit raise ArgBuildError { + #| match cmd.build_error { + #| Some(err) => raise err + #| None => () + #| } + #| validate_inherited_global_shadowing(args, inherited_globals) + #| validate_group_defs(args, groups) + #| validate_group_refs(args, groups) + #| validate_subcommand_defs(cmd.subcommands) + #| validate_subcommand_required_policy(cmd) + #| validate_help_subcommand(cmd) + #| validate_version_actions(cmd) + #| let child_inherited_globals = merge_inherited_globals( + #| inherited_globals, + #| collect_globals(args), + #| ) + #| for sub in cmd.subcommands { + #| validate_command(sub, sub.args, sub.groups, child_inherited_globals) + #| } + #|} + #|fn validate_inherited_global_shadowing( + #| args : Array[Arg], + #| inherited_globals : Array[Arg], + #|) -> Unit raise ArgBuildError { + #| for arg in args { + #| if inherited_globals.iter().find_first(g => g.name == arg.name) + #| is Some(inherited_arg) { + #| if !arg.global { + #| raise Unsupported( + #| "arg '\{arg.name}' shadows an inherited global; rename the arg or mark it global", + #| ) + #| } + #| if !global_override_compatible(inherited_arg, arg) { + #| raise Unsupported( + #| "global arg '\{arg.name}' is incompatible with inherited global definition", + #| ) + #| } + #| } + #| match arg.info { + #| FlagInfo(long~, short~, negatable~, ..) => { + #| if long is Some(name) { + #| validate_inherited_global_long_collision(arg, name, inherited_globals) + #| if negatable { + #| validate_inherited_global_long_collision( + #| arg, + #| "no-\{name}", + #| inherited_globals, + #| ) + #| } + #| } + #| if short is Some(value) { + #| validate_inherited_global_short_collision( + #| arg, value, inherited_globals, + #| ) + #| } + #| } + #| OptionInfo(long~, short~, ..) => { + #| if long is Some(name) { + #| validate_inherited_global_long_collision(arg, name, inherited_globals) + #| } + #| if short is Some(value) { + #| validate_inherited_global_short_collision( + #| arg, value, inherited_globals, + #| ) + #| } + #| } + #| PositionalInfo(_) => () + #| } + #| } + #|} + #|fn merge_inherited_globals( + #| inherited_globals : Array[Arg], + #| globals_here : Array[Arg], + #|) -> Array[Arg] { + #| let merged = inherited_globals.copy() + #| for global in globals_here { + #| match merged.search_by(arg => arg.name == global.name) { + #| Some(idx) => merged[idx] = global + #| None => merged.push(global) + #| } + #| } + #| merged + #|} + #|fn global_override_compatible(inherited_arg : Arg, arg : Arg) -> Bool { + #| match inherited_arg.info { + #| FlagInfo(action=inherited_action, negatable=inherited_negatable, ..) => + #| match arg.info { + #| FlagInfo(action~, negatable~, ..) => + #| inherited_action == action && inherited_negatable == negatable + #| _ => false + #| } + #| OptionInfo(action=inherited_action, ..) => + #| match arg.info { + #| OptionInfo(action~, ..) => inherited_action == action + #| _ => false + #| } + #| PositionalInfo(_) => false + #| } + #|} + #|fn validate_inherited_global_long_collision( + #| arg : Arg, + #| long : String, + #| inherited_globals : Array[Arg], + #|) -> Unit raise ArgBuildError { + #| if inherited_global_long_owner(arg.name, long, inherited_globals) + #| is Some(owner) { + #| raise Unsupported( + #| "arg '\{arg.name}' long option --\{long} conflicts with inherited global '\{owner}'", + #| ) + #| } + #|} + #|fn validate_inherited_global_short_collision( + #| arg : Arg, + #| short : Char, + #| inherited_globals : Array[Arg], + #|) -> Unit raise ArgBuildError { + #| if inherited_global_short_owner(arg.name, short, inherited_globals) + #| is Some(owner) { + #| raise Unsupported( + #| "arg '\{arg.name}' short option -\{short} conflicts with inherited global '\{owner}'", + #| ) + #| } + #|} + #|fn inherited_global_long_owner( + #| current_name : String, + #| long : String, + #| inherited_globals : Array[Arg], + #|) -> String? { + #| for inherited in inherited_globals { + #| if inherited.name == current_name { + #| continue + #| } + #| match inherited.info { + #| FlagInfo(long=inherited_long, negatable~, ..) => + #| if inherited_long is Some(name) && + #| (name == long || (negatable && "no-\{name}" == long)) { + #| return Some(inherited.name) + #| } + #| OptionInfo(long=inherited_long, ..) => + #| if inherited_long is Some(name) && name == long { + #| return Some(inherited.name) + #| } + #| PositionalInfo(_) => () + #| } + #| } + #| None + #|} + #|fn inherited_global_short_owner( + #| current_name : String, + #| short : Char, + #| inherited_globals : Array[Arg], + #|) -> String? { + #| for inherited in inherited_globals { + #| if inherited.name == current_name { + #| continue + #| } + #| match inherited.info { + #| FlagInfo(short=inherited_short, ..) + #| | OptionInfo(short=inherited_short, ..) => + #| if inherited_short is Some(value) && value == short { + #| return Some(inherited.name) + #| } + #| PositionalInfo(_) => () + #| } + #| } + #| None + #|} + #|fn validate_flag_arg( + #| arg : Arg, + #| ctx : ValidationCtx, + #|) -> Unit raise ArgBuildError { + #| validate_named_option_arg(arg) + #| guard arg.info is FlagInfo(action~, negatable~, ..) + #| if action is (Help | Version) { + #| guard !negatable else { + #| raise Unsupported("help/version actions do not support negatable") + #| } + #| guard arg.env is None else { + #| raise Unsupported("help/version actions do not support env/defaults") + #| } + #| guard !arg.multiple else { + #| raise Unsupported("help/version actions do not support multiple values") + #| } + #| } + #| ctx.record_arg(arg) + #|} + #|fn validate_option_arg( + #| arg : Arg, + #| ctx : ValidationCtx, + #|) -> Unit raise ArgBuildError { + #| validate_named_option_arg(arg) + #| validate_default_values(arg) + #| ctx.record_arg(arg) + #|} + #|fn validate_positional_arg( + #| arg : Arg, + #| ctx : ValidationCtx, + #|) -> Unit raise ArgBuildError { + #| let (min, max) = arg_min_max_for_validate(arg) + #| if (min > 1 || (max is Some(m) && m > 1)) && !arg.multiple { + #| raise Unsupported( + #| "multiple values require action=Append or num_args allowing >1", + #| ) + #| } + #| validate_default_values(arg) + #| ctx.record_arg(arg) + #|} + #|fn validate_named_option_arg(arg : Arg) -> Unit raise ArgBuildError { + #| guard arg.info + #| is (FlagInfo(long~, short~, ..) | OptionInfo(long~, short~, ..)) + #| guard long is Some(_) || short is Some(_) || arg.env is Some(_) else { + #| raise Unsupported("flag/option args require short/long/env") + #| } + #|} + #|fn validate_default_values(arg : Arg) -> Unit raise ArgBuildError { + #| if arg.info + #| is (OptionInfo(default_values~, ..) | PositionalInfo(default_values~, ..)) && + #| default_values is Some(values) && + #| values.length() > 1 && + #| !arg.multiple && + #| !(arg.info is OptionInfo(action=Append, ..)) { + #| raise Unsupported( + #| "default_values with multiple entries require action=Append", + #| ) + #| } + #|} + #|fn validate_group_defs( + #| args : Array[Arg], + #| groups : Array[ArgGroup], + #|) -> Unit raise ArgBuildError { + #| let seen : @set.Set[String] = @set.new() + #| let arg_seen : @set.Set[String] = @set.new() + #| for arg in args { + #| arg_seen.add(arg.name) + #| } + #| for group in groups { + #| if !seen.add_and_check(group.name) { + #| raise Unsupported("duplicate group: \{group.name}") + #| } + #| } + #| for group in groups { + #| for required in group.requires { + #| if required == group.name { + #| raise Unsupported("group cannot require itself: \{group.name}") + #| } + #| if !seen.contains(required) && !arg_seen.contains(required) { + #| raise Unsupported( + #| "unknown group requires target: \{group.name} -> \{required}", + #| ) + #| } + #| } + #| for conflict in group.conflicts_with { + #| if conflict == group.name { + #| raise Unsupported("group cannot conflict with itself: \{group.name}") + #| } + #| if !seen.contains(conflict) && !arg_seen.contains(conflict) { + #| raise Unsupported( + #| "unknown group conflicts_with target: \{group.name} -> \{conflict}", + #| ) + #| } + #| } + #| } + #|} + #|fn validate_group_refs( + #| args : Array[Arg], + #| groups : Array[ArgGroup], + #|) -> Unit raise ArgBuildError { + #| if groups.length() == 0 { + #| return + #| } + #| let arg_index : @set.Set[String] = @set.new() + #| for arg in args { + #| arg_index.add(arg.name) + #| } + #| for group in groups { + #| for name in group.args { + #| if !arg_index.contains(name) { + #| raise Unsupported("unknown group arg: \{group.name} -> \{name}") + #| } + #| } + #| } + #|} + #|fn validate_requires_conflicts_targets( + #| args : Array[Arg], + #| seen_names : @set.Set[String], + #|) -> Unit raise ArgBuildError { + #| for arg in args { + #| for required in arg.requires { + #| if required == arg.name { + #| raise Unsupported("arg cannot require itself: \{arg.name}") + #| } + #| if !seen_names.contains(required) { + #| raise Unsupported("unknown requires target: \{arg.name} -> \{required}") + #| } + #| } + #| for conflict in arg.conflicts_with { + #| if conflict == arg.name { + #| raise Unsupported("arg cannot conflict with itself: \{arg.name}") + #| } + #| if !seen_names.contains(conflict) { + #| raise Unsupported( + #| "unknown conflicts_with target: \{arg.name} -> \{conflict}", + #| ) + #| } + #| } + #| } + #|} + #|fn validate_subcommand_defs(subs : Array[Command]) -> Unit raise ArgBuildError { + #| if subs.length() == 0 { + #| return + #| } + #| let seen : @set.Set[String] = @set.new() + #| for sub in subs { + #| if !seen.add_and_check(sub.name) { + #| raise Unsupported("duplicate subcommand: \{sub.name}") + #| } + #| } + #|} + #|fn validate_subcommand_required_policy( + #| cmd : Command, + #|) -> Unit raise ArgBuildError { + #| if cmd.subcommand_required && cmd.subcommands.length() == 0 { + #| raise Unsupported("subcommand_required requires at least one subcommand") + #| } + #|} + #|fn validate_help_subcommand(cmd : Command) -> Unit raise ArgBuildError { + #| if help_subcommand_enabled(cmd) && + #| cmd.subcommands.any(cmd => cmd.name == "help") { + #| raise Unsupported( + #| "subcommand name reserved for built-in help: help (disable with disable_help_subcommand)", + #| ) + #| } + #|} + #|fn validate_version_actions(cmd : Command) -> Unit raise ArgBuildError { + #| if cmd.version is None && + #| cmd.args.any(arg => arg.info is FlagInfo(action=Version, ..)) { + #| raise Unsupported("version action requires command version text") + #| } + #|} + #|fn validate_command_policies( + #| cmd : Command, + #| matches : Matches, + #|) -> Unit raise ArgParseError { + #| if cmd.subcommand_required && + #| cmd.subcommands.length() > 0 && + #| matches.parsed_subcommand is None { + #| raise MissingRequired("subcommand", None) + #| } + #|} + #|fn validate_groups( + #| args : Array[Arg], + #| groups : Array[ArgGroup], + #| matches : Matches, + #|) -> Unit raise ArgParseError { + #| if groups.length() == 0 { + #| return + #| } + #| let group_presence : Map[String, Int] = {} + #| let group_seen : @set.Set[String] = @set.new() + #| let arg_seen : @set.Set[String] = @set.new() + #| for group in groups { + #| group_seen.add(group.name) + #| } + #| for arg in args { + #| arg_seen.add(arg.name) + #| } + #| for group in groups { + #| let count = for arg in args; count = 0 { + #| if !arg_in_group(arg, group) { + #| continue count + #| } + #| if matches_has_value_or_flag(matches, arg.name) { + #| continue count + 1 + #| } else { + #| continue count + #| } + #| } nobreak { + #| count + #| } + #| group_presence[group.name] = count + #| if group.required && count == 0 { + #| raise MissingGroup(group.name) + #| } + #| if !group.multiple && count > 1 { + #| raise GroupConflict(group.name) + #| } + #| } + #| for group in groups { + #| let count = group_presence[group.name] + #| if count == 0 { + #| continue + #| } + #| for required in group.requires { + #| if group_seen.contains(required) { + #| if group_presence.get(required).unwrap_or(0) == 0 { + #| raise MissingGroup(required) + #| } + #| } else if arg_seen.contains(required) { + #| if !matches_has_value_or_flag(matches, required) { + #| raise MissingRequired(required, None) + #| } + #| } + #| } + #| for conflict in group.conflicts_with { + #| if group_seen.contains(conflict) { + #| if group_presence.get(conflict).unwrap_or(0) > 0 { + #| raise GroupConflict("\{group.name} conflicts with \{conflict}") + #| } + #| } else if arg_seen.contains(conflict) { + #| if matches_has_value_or_flag(matches, conflict) { + #| raise GroupConflict("\{group.name} conflicts with \{conflict}") + #| } + #| } + #| } + #| } + #|} + #|fn arg_in_group(arg : Arg, group : ArgGroup) -> Bool { + #| group.args.contains(arg.name) + #|} + #|fn validate_values( + #| args : Array[Arg], + #| matches : Matches, + #|) -> Unit raise ArgParseError { + #| for arg in args { + #| let present = matches_has_value_or_flag(matches, arg.name) + #| if arg.required && !present { + #| raise MissingRequired(arg.name, None) + #| } + #| guard arg.info is (OptionInfo(_) | PositionalInfo(_)) else { continue } + #| if !present { + #| if arg.info is PositionalInfo(_) { + #| let (min, _) = arg_min_max(arg) + #| if min > 0 { + #| raise TooFewValues(arg.name, 0, min) + #| } + #| } + #| continue + #| } + #| let values = matches.values.get(arg.name).unwrap_or([]) + #| let count = values.length() + #| let (min, max) = arg_min_max(arg) + #| if count < min { + #| raise TooFewValues(arg.name, count, min) + #| } + #| if !(arg.info is OptionInfo(action=Append, ..)) { + #| match max { + #| Some(max) if count > max => raise TooManyValues(arg.name, count, max) + #| _ => () + #| } + #| } + #| } + #|} + #|fn validate_relationships( + #| matches : Matches, + #| args : Array[Arg], + #|) -> Unit raise ArgParseError { + #| for arg in args { + #| if !matches_has_value_or_flag(matches, arg.name) { + #| continue + #| } + #| for required in arg.requires { + #| if !matches_has_value_or_flag(matches, required) { + #| raise MissingRequired(required, Some(arg.name)) + #| } + #| } + #| for conflict in arg.conflicts_with { + #| if matches_has_value_or_flag(matches, conflict) { + #| raise InvalidArgument( + #| "conflicting arguments: \{arg.name} and \{conflict}", + #| ) + #| } + #| } + #| } + #|} + ), + "parser_values.mbt": ( + #|fn assign_positionals( + #| matches : Matches, + #| positionals : Array[Arg], + #| values : Array[String], + #|) -> Unit raise ArgParseError { + #| let cursor = for idx, arg in positionals; cursor = 0 { + #| let remaining = values.length() - cursor + #| if arg.multiple { + #| let (min, max) = arg_min_max(arg) + #| let reserve = remaining_positional_min(positionals, idx + 1) + #| let mut take = remaining - reserve + #| if take < 0 { + #| take = 0 + #| } + #| match max { + #| Some(max_count) if take > max_count => take = max_count + #| _ => () + #| } + #| if take < min { + #| take = min + #| } + #| if take > remaining { + #| take = remaining + #| } + #| let mut taken = 0 + #| while taken < take { + #| add_value(matches, arg.name, values[cursor + taken], arg, Argv) + #| taken = taken + 1 + #| } + #| continue cursor + taken + #| } + #| if remaining > 0 { + #| add_value(matches, arg.name, values[cursor], arg, Argv) + #| continue cursor + 1 + #| } else { + #| continue cursor + #| } + #| } nobreak { + #| cursor + #| } + #| if cursor < values.length() { + #| let overflow_label = if positionals.length() > 0 { + #| let last = positionals[positionals.length() - 1] + #| if last.multiple { + #| Some("<\{last.name}...>") + #| } else { + #| Some("<\{last.name}>") + #| } + #| } else { + #| None + #| } + #| raise TooManyPositionals(values[cursor], overflow_label) + #| } + #|} + #|fn positional_min_required(arg : Arg) -> Int { + #| let (min, _) = arg_min_max(arg) + #| if min > 0 { + #| min + #| } else { + #| 0 + #| } + #|} + #|fn remaining_positional_min(positionals : Array[Arg], start : Int) -> Int { + #| for idx = start, total = 0; idx < positionals.length(); { + #| continue idx + 1, total + positional_min_required(positionals[idx]) + #| } nobreak { + #| total + #| } + #|} + #|fn add_value( + #| matches : Matches, + #| name : String, + #| value : String, + #| arg : Arg, + #| source : ValueSource, + #|) -> Unit { + #| if arg.multiple || arg.info is OptionInfo(action=Append, ..) { + #| let arr = matches.values.get(name).unwrap_or([]) + #| arr.push(value) + #| matches.values[name] = arr + #| matches.value_sources[name] = source + #| } else { + #| matches.values[name] = [value] + #| matches.value_sources[name] = source + #| } + #|} + #|fn assign_value( + #| matches : Matches, + #| arg : Arg, + #| value : String, + #| source : ValueSource, + #|) -> Unit raise ArgParseError { + #| match arg.info { + #| OptionInfo(action=Append, ..) => + #| add_value(matches, arg.name, value, arg, source) + #| OptionInfo(action=Set, ..) | PositionalInfo(_) => + #| add_value(matches, arg.name, value, arg, source) + #| FlagInfo(action=SetTrue, ..) => { + #| let flag = parse_bool(value) + #| matches.flags[arg.name] = flag + #| matches.flag_sources[arg.name] = source + #| } + #| FlagInfo(action=SetFalse, ..) => { + #| let flag = parse_bool(value) + #| matches.flags[arg.name] = !flag + #| matches.flag_sources[arg.name] = source + #| } + #| FlagInfo(action=Count, ..) => { + #| let count = parse_count(value) + #| matches.counts[arg.name] = count + #| matches.flags[arg.name] = count > 0 + #| matches.flag_sources[arg.name] = source + #| } + #| FlagInfo(action=Help, ..) => + #| raise InvalidArgument("help action does not take values") + #| FlagInfo(action=Version, ..) => + #| raise InvalidArgument("version action does not take values") + #| } + #|} + #|fn option_conflict_label(arg : Arg) -> String { + #| match arg.info { + #| FlagInfo(long~, short~, ..) | OptionInfo(long~, short~, ..) => + #| match long { + #| Some(name) => "--\{name}" + #| None => + #| match short { + #| Some(short) => "-\{short}" + #| None => arg.name + #| } + #| } + #| PositionalInfo(_) => arg.name + #| } + #|} + #|fn check_duplicate_set_occurrence( + #| matches : Matches, + #| arg : Arg, + #|) -> Unit raise ArgParseError { + #| guard arg.info is (OptionInfo(action=Set, ..) | PositionalInfo(_)) else { + #| return + #| } + #| if matches.values.get(arg.name) is Some(values) && values.length() > 0 { + #| raise InvalidArgument( + #| "argument '\{option_conflict_label(arg)}' cannot be used multiple times", + #| ) + #| } + #|} + #|fn should_stop_option_value( + #| value : String, + #| arg : Arg, + #| _long_index : Map[String, Arg], + #| _short_index : Map[Char, Arg], + #|) -> Bool { + #| if !value.has_prefix("-") || value == "-" { + #| return false + #| } + #| if arg.info + #| is (OptionInfo(allow_hyphen_values~, ..) + #| | PositionalInfo(allow_hyphen_values~, ..)) && + #| allow_hyphen_values { + #| return false + #| } + #| true + #|} + #|fn apply_env( + #| matches : Matches, + #| args : Array[Arg], + #| env : Map[String, String], + #|) -> Unit raise ArgParseError { + #| for arg in args { + #| let name = arg.name + #| if matches_has_value_or_flag(matches, name) { + #| continue + #| } + #| let env_name = match arg.env { + #| Some(value) => value + #| None => continue + #| } + #| let value = match env.get(env_name) { + #| Some(v) => v + #| None => continue + #| } + #| if arg.info is (OptionInfo(_) | PositionalInfo(_)) { + #| assign_value(matches, arg, value, Env) + #| continue + #| } + #| match arg.info { + #| FlagInfo(action=Count, ..) => { + #| let count = parse_count(value) + #| matches.counts[name] = count + #| matches.flags[name] = count > 0 + #| matches.flag_sources[name] = Env + #| } + #| FlagInfo(action=SetFalse, ..) => { + #| let flag = parse_bool(value) + #| matches.flags[name] = !flag + #| matches.flag_sources[name] = Env + #| } + #| FlagInfo(action=SetTrue, ..) => { + #| let flag = parse_bool(value) + #| matches.flags[name] = flag + #| matches.flag_sources[name] = Env + #| } + #| OptionInfo(_) | PositionalInfo(_) => () + #| FlagInfo(action=Help | Version, ..) => () + #| } + #| } + #|} + #|fn apply_defaults(matches : Matches, args : Array[Arg]) -> Unit { + #| for arg in args { + #| let default_values = match arg.info { + #| FlagInfo(_) => continue + #| OptionInfo(default_values~, ..) | PositionalInfo(default_values~, ..) => + #| default_values + #| } + #| if matches_has_value_or_flag(matches, arg.name) { + #| continue + #| } + #| match default_values { + #| Some(values) if values.length() > 0 => + #| for value in values { + #| let _ = add_value(matches, arg.name, value, arg, Default) + #| } + #| _ => () + #| } + #| } + #|} + #|fn matches_has_value_or_flag(matches : Matches, name : String) -> Bool { + #| matches.flags.contains(name) || matches.values.contains(name) + #|} + #|fn apply_flag(matches : Matches, arg : Arg, source : ValueSource) -> Unit { + #| match arg.info { + #| FlagInfo(action=SetTrue, ..) => matches.flags[arg.name] = true + #| FlagInfo(action=SetFalse, ..) => matches.flags[arg.name] = false + #| FlagInfo(action=Count, ..) => { + #| let current = matches.counts.get(arg.name).unwrap_or(0) + #| matches.counts[arg.name] = current + 1 + #| matches.flags[arg.name] = true + #| } + #| FlagInfo(action=Help, ..) => () + #| FlagInfo(action=Version, ..) => () + #| _ => matches.flags[arg.name] = true + #| } + #| matches.flag_sources[arg.name] = source + #|} + #|fn parse_bool(value : String) -> Bool raise ArgParseError { + #| match value { + #| "1" | "true" | "yes" | "on" => true + #| "0" | "false" | "no" | "off" => false + #| _ => + #| raise InvalidValue( + #| "invalid value '\{value}' for boolean flag; expected one of: 1, 0, true, false, yes, no, on, off", + #| ) + #| } + #|} + #|fn parse_count(value : String) -> Int raise ArgParseError { + #| try @strconv.parse_int(value) catch { + #| _ => + #| raise InvalidValue( + #| "invalid value '\{value}' for count; expected a non-negative integer", + #| ) + #| } noraise { + #| _..<0 => + #| raise InvalidValue( + #| "invalid value '\{value}' for count; expected a non-negative integer", + #| ) + #| v => v + #| } + #|} + ), + "runtime_exit.mbt": ( + #|fn trim_single_trailing_newline(text : String) -> String { + #| match text.strip_suffix("\n") { + #| Some(view) => view.to_string() + #| None => text + #| } + #|} + #|fn[T] print_and_exit_success(text : String) -> T { + #| println(trim_single_trailing_newline(text)) + #| runtime_exit_success() + #| panic() + #|} + ), + "runtime_exit_js.mbt": ( + #|#cfg(target="js") + #|extern "js" fn runtime_js_try_exit(code : Int) -> Bool = + #| #| function(code) { + #| #| if (typeof process !== "undefined" && typeof process.exit === "function") { + #| #| process.exit(code); + #| #| return true; + #| #| } + #| #| return false; + #| #| } + #|#cfg(target="js") + #|fn runtime_exit_success() -> Unit { + #| if !runtime_js_try_exit(0) { + #| panic() + #| } + #|} + ), + "runtime_exit_native.mbt": ( + #|#cfg(any(target="native", target="llvm")) + #|extern "c" fn runtime_native_exit(code : Int) = "exit" + #|#cfg(any(target="native", target="llvm")) + #|fn runtime_exit_success() -> Unit { + #| runtime_native_exit(0) + #|} + ), + "runtime_exit_wasm.mbt": ( + #|#cfg(any(target="wasm", target="wasm-gc")) + #|fn runtime_wasm_exit(code : Int) -> Unit = "__moonbit_sys_unstable" "exit" + #|#cfg(any(target="wasm", target="wasm-gc")) + #|fn runtime_exit_success() -> Unit { + #| runtime_wasm_exit(0) + #|} + ), + "value_range.mbt": ( + #|pub struct ValueRange { + #| priv lower : Int + #| priv upper : Int? + #| fn new(lower? : Int, upper? : Int) -> ValueRange + #|} derive(Eq, Show) + #|pub fn ValueRange::single() -> ValueRange { + #| ValueRange(lower=1, upper=1) + #|} + #|pub fn ValueRange::new(lower? : Int = 0, upper? : Int) -> ValueRange { + #| { lower, upper } + #|} + ) + } ) ///| let moonbitlang_core_array_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/array", - deps={ "moonbitlang/core/builtin": moonbitlang_core_builtin_module }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| "moonbitlang/core/builtin" - #| ], - #| "test-import": [ - #| "moonbitlang/core/char" - #| ], - #| "targets": { - #| "array_js.mbt": ["js"], - #| "array_nonjs.mbt": ["not", "js"], - #| "blit_js.mbt": ["js"], - #| "blit_nonjs.mbt": ["not", "js"], - #| "panic_test.mbt": ["not", "native", "llvm"] - #| } - #|} - ), - "array.mbt": ( - #|pub fn[A, B, C] zip_with( - #| l : Array[A], - #| r : Array[B], - #| merge : (A, B) -> C raise?, - #|) -> Array[C] raise? { - #| let length = if l.length() < r.length() { l.length() } else { r.length() } - #| Array::makei(length, i => merge(l[i], r[i])) - #|} - ), - "view.mbt": ( - #|#deprecated - #|pub type View[T] = ArrayView[T] - ), - }, + "array.mbt": ( + #|pub fn[A, B, C] zip_with( + #| l : Array[A], + #| r : Array[B], + #| merge : (A, B) -> C raise?, + #|) -> Array[C] raise? { + #| let length = if l.length() < r.length() { l.length() } else { r.length() } + #| Array::makei(length, i => merge(l[i], r[i])) + #|} + ), + "view.mbt": ( + #|#deprecated + #|pub type View[T] = ArrayView[T] + ) + } ) ///| let moonbitlang_core_bench_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/bench", - deps={ - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/double": moonbitlang_core_double_module, - "moonbitlang/core/array": moonbitlang_core_array_module, - "moonbitlang/core/json": moonbitlang_core_json_module, - }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "targets": { - #| "monotonic_clock_js.mbt": ["js"], - #| "monotonic_clock_wasm.mbt": ["wasm", "wasm-gc"], - #| "monotonic_clock_native.mbt": ["native", "llvm"] - #| }, - #| "import": [ - #| "moonbitlang/core/builtin", - #| "moonbitlang/core/double", - #| "moonbitlang/core/array", - #| "moonbitlang/core/json" - #| ] - #|} - ), - "bench.mbt": ( - #|fn iter_n_microseconds(inner : () -> Unit, k : Int) -> Double { - #| let ts = monotonic_clock_start() - #| for i in 0.. Unit, count : UInt) -> Summary { - #| let count = count.land(0x7FFFFFFF).reinterpret_as_int() - #| let threshold = 100000.0 // 100 ms - #| let target_batch_size = loop 1 { - #| trial => { - #| let single_us = iter_n_microseconds(inner, trial) / trial.to_double() - #| let target_batch_size = threshold / - #| (if single_us < 1.0 { 1.0 } else { single_us }) - #| if trial.to_double() * single_us > threshold { - #| break target_batch_size - #| } - #| continue trial * 2 - #| } - #| } - #| let batch_size = if target_batch_size < 1.0 { - #| 1 - #| } else { - #| target_batch_size.ceil().to_int() - #| } - #| let samples = Array::makei(count, _ => iter_n_microseconds(inner, batch_size) / - #| batch_size.to_double()) - #| samples.sort() - #| winsorize(sorted_data=samples, 5.0) - #| Summary::new(name?, sorted_data=samples, batch_size) - #|} - #|pub fn Bench::bench( - #| self : Bench, - #| name? : String, - #| f : () -> Unit, - #| count? : UInt = 10, - #|) -> Unit { - #| let summary = iter_count(name?, f, count) - #| if !self.buffer.is_empty() { - #| self.buffer.write_char(',') - #| } - #| self.buffer.write_string(summary.to_json().stringify(escape_slash=true)) - #| self.summaries.push(summary) - #|} - #|pub fn single_bench( - #| name? : String, - #| f : () -> Unit, - #| count? : UInt = 10, - #|) -> Summary { - #| iter_count(name?, f, count) - #|} - #|pub fn[Any] Bench::keep(self : Bench, value : Any) -> Unit { - #| let trait_object : &OpaqueValue = value - #| self._storage = trait_object - #|} - #|#coverage.skip - #|pub fn Bench::dump_summaries(self : Bench) -> String { - #| "[\{self.buffer.to_string()}]" - #|} - #|#skip("slow benchmarking test") - #|test "bench - single_bench basic functionality" { - #| let bench_result = single_bench( - #| () => { - #| let x = 1 + 1 - #| ignore(x) - #| }, - #| count=2, - #| ) - #| inspect(bench_result.runs, content="2") - #| inspect(bench_result.batch_size > 0, content="true") - #| inspect(bench_result.sum > 0.0, content="true") - #| inspect(bench_result.min <= bench_result.max, content="true") - #|} - #|#skip("slow benchmarking test") - #|test "bench - Summary struct properties" { - #| let bench_result = single_bench( - #| () => { - #| let x = 1 - #| ignore(x) - #| }, - #| count=5, - #| ) - #| inspect(bench_result.mean >= 0, content="true") - #| inspect(bench_result.median >= 0, content="true") - #| inspect(bench_result.std_dev >= 0, content="true") - #| inspect(bench_result.std_dev_pct >= 0, content="true") - #| inspect(bench_result.median_abs_dev >= 0, content="true") - #| inspect(bench_result.median_abs_dev_pct >= 0, content="true") - #| let (q1, q2, q3) = bench_result.quartiles - #| inspect(q1 <= q2, content="true") - #| inspect(q2 <= q3, content="true") - #| inspect((q3 - q1 - bench_result.iqr).abs() < 0.001, content="true") - #|} - #|#skip("slow benchmarking test") - #|test "bench - T struct and bench method" { - #| let bench_obj = new() - #| inspect(bench_obj.buffer.is_empty(), content="true") - #| inspect(bench_obj.summaries.is_empty(), content="true") - #| bench_obj.bench( - #| () => { - #| let x = 20 * 20 - #| ignore(x) - #| }, - #| count=2, - #| ) - #| inspect(bench_obj.buffer.is_empty(), content="false") - #| inspect(bench_obj.summaries.length(), content="1") - #| bench_obj.bench( - #| () => { - #| let y = 30 * 30 - #| ignore(y) - #| }, - #| count=2, - #| ) - #| inspect(bench_obj.summaries.length(), content="2") - #|} - #|#skip("slow benchmarking test") - #|test "bench - monotonic clock functionality" { - #| let start = monotonic_clock_start() - #| let mut result = 0 - #| for _ in 0..<1000 { - #| result += 1 - #| } - #| ignore(result) - #| let elapsed = monotonic_clock_end(start) - #| inspect(elapsed >= 0.0, content="true") - #|} - #|test "bench - keep stores value" { - #| let b = new() - #| assert_eq(b.summaries.length(), 0) - #| b.keep(123) - #| assert_eq(b.summaries.length(), 0) - #| b.keep(456) - #| assert_eq(b.summaries.length(), 0) - #|} - ), - "monotonic_clock_js.mbt": ( - #|type Timestamp - #|pub extern "js" fn monotonic_clock_start() -> Timestamp = - #| #| () => performance.now() - #|pub extern "js" fn monotonic_clock_end(ts : Timestamp) -> Double = - #| #| (ts) => (performance.now() - ts) * 1000.0 - ), - "monotonic_clock_native.mbt": ( - #|#external - #|type Timestamp - #|pub extern "C" fn monotonic_clock_start() -> Timestamp = "moonbit_monotonic_clock_start" - #|pub extern "C" fn monotonic_clock_end(ts : Timestamp) -> Double = "moonbit_monotonic_clock_stop" - ), - "monotonic_clock_wasm.mbt": ( - #|#external - #|type Timestamp - #|fn instant_elapsed_as_secs_f64(x : Timestamp) -> Double = "__moonbit_time_unstable" "instant_elapsed_as_secs_f64" - #|pub fn monotonic_clock_start() -> Timestamp = "__moonbit_time_unstable" "instant_now" - #|pub fn monotonic_clock_end(ts : Timestamp) -> Double { - #| let elapsed_secs : Double = instant_elapsed_as_secs_f64(ts) - #| elapsed_secs * 1000000.0 - #|} - ), - "stats.mbt": ( - #|struct Summary { - #| name : String? - #| sum : Double - #| min : Double - #| max : Double - #| mean : Double - #| median : Double - #| variance : Double - #| std_dev : Double - #| std_dev_pct : Double - #| median_abs_dev : Double - #| median_abs_dev_pct : Double - #| quartiles : (Double, Double, Double) - #| iqr : Double - #| batch_size : Int - #| runs : Int - #|} derive(ToJson) - #|fn Summary::new( - #| name? : String, - #| sorted_data~ : Array[Double], - #| batch_size : Int, - #|) -> Summary { - #| let sum = sum(sorted_data) - #| let min = min(sorted_data~) - #| let max = max(sorted_data~) - #| let mean = mean(sorted_data, sum~) - #| let median = median(sorted_data~) - #| let variance = variance(sorted_data, mean~) - #| let std_dev = std_dev(variance~) - #| let std_dev_pct = std_dev_pct(mean~, std_dev~) - #| let median_abs_dev = median_abs_dev(sorted_data, median_=median) - #| let median_abs_dev_pct = median_abs_dev_pct(median~, median_abs_dev~) - #| let quartiles = quartiles(sorted_data~) - #| let iqr = iqr(quartiles~) - #| { - #| name, - #| sum, - #| min, - #| max, - #| mean, - #| median, - #| variance, - #| std_dev, - #| std_dev_pct, - #| median_abs_dev, - #| median_abs_dev_pct, - #| quartiles, - #| iqr, - #| batch_size, - #| runs: sorted_data.length(), - #| } - #|} - #|fn sum(data : Array[Double]) -> Double { - #| let mut sum = 0.0 - #| for i in data { - #| sum += i - #| } - #| sum - #|} - #|fn min(sorted_data~ : Array[Double]) -> Double { - #| sorted_data[0] - #|} - #|fn max(sorted_data~ : Array[Double]) -> Double { - #| sorted_data[sorted_data.length() - 1] - #|} - #|fn mean(data : Array[Double], sum~ : Double) -> Double { - #| let count = data.length() - #| sum / count.to_double() - #|} - #|fn median(sorted_data~ : Array[Double]) -> Double { - #| percentile(sorted_data~, pct=50.0) - #|} - #|fn variance(data : Array[Double], mean~ : Double) -> Double { - #| if data.length() < 2 { - #| return 0.0 - #| } - #| let mut v = 0.0 - #| for i in data { - #| let d = i - mean - #| v += d * d - #| } - #| v / (data.length() - 1).to_double() - #|} - #|fn std_dev(variance~ : Double) -> Double { - #| variance.sqrt() - #|} - #|fn std_dev_pct(mean~ : Double, std_dev~ : Double) -> Double { - #| if mean == 0.0 { - #| return 0.0 - #| } - #| std_dev / mean * 100.0 - #|} - #|fn median_abs_dev(data : Array[Double], median_~ : Double) -> Double { - #| let abs_devs = data.map(x => (median_ - x).abs()) - #| abs_devs.sort() - #| median(sorted_data=abs_devs) * 1.4826 - #|} - #|fn median_abs_dev_pct(median~ : Double, median_abs_dev~ : Double) -> Double { - #| if median == 0.0 { - #| return 0.0 - #| } - #| median_abs_dev / median * 100.0 - #|} - #|fn quartiles(sorted_data~ : Array[Double]) -> (Double, Double, Double) { - #| let q1 = percentile(sorted_data~, pct=25.0) - #| let q2 = percentile(sorted_data~, pct=50.0) - #| let q3 = percentile(sorted_data~, pct=75.0) - #| (q1, q2, q3) - #|} - #|fn iqr(quartiles~ : (Double, Double, Double)) -> Double { - #| let (q1, _, q3) = quartiles - #| q3 - q1 - #|} - #|fn percentile(sorted_data~ : Array[Double], pct~ : Double) -> Double { - #| guard sorted_data.length() > 0 - #| guard pct >= 0.0 && pct <= 100.0 - #| if sorted_data.length() == 1 { - #| return sorted_data[0] - #| } - #| if pct == 100.0 { - #| return sorted_data[sorted_data.length() - 1] - #| } - #| let length = (sorted_data.length() - 1).to_double() - #| let rank = pct / 100 * length - #| let lrank = rank.floor() - #| let d = rank - lrank - #| let n = lrank.to_int() - #| let lo = sorted_data[n] - #| let hi = sorted_data[n + 1] - #| lo + (hi - lo) * d - #|} - #|fn winsorize(sorted_data~ : Array[Double], pct : Double) -> Unit { - #| let lo = percentile(sorted_data~, pct~) - #| let hi = percentile(sorted_data~, pct=100.0 - pct) - #| for i, samp in sorted_data { - #| if samp > hi { - #| sorted_data[i] = hi - #| } else if samp < lo { - #| sorted_data[i] = lo - #| } - #| } - #|} - #|test { - #| let data = [1.1, 21.4, 2.2, 3.3, 4.5, 12.5, 33.3, 14.4] - #| data.sort() - #| let summary = Summary::new(sorted_data=data, 3) - #| assert_true(summary.sum.is_close(92.7)) - #| assert_true(summary.min.is_close(1.1)) - #| assert_true(summary.max.is_close(33.3)) - #| assert_true(summary.mean.is_close(11.5875)) - #| assert_true(summary.median.is_close(8.5)) - #| assert_true(summary.variance.is_close(127.64125)) - #| assert_true(summary.std_dev.is_close(11.297842714430043)) - #| assert_true(summary.std_dev_pct.is_close(97.50026075020534)) - #| assert_true(summary.median_abs_dev.is_close(9.04386)) - #| assert_true(summary.median_abs_dev_pct.is_close(106.39835294117646)) - #| let (q1, q2, q3) = summary.quartiles - #| assert_true(q1.is_close(3.025)) - #| assert_true(q2.is_close(8.5)) - #| assert_true(q3.is_close(16.15)) - #| assert_true(summary.iqr.is_close(13.125)) - #| assert_true(summary.batch_size == 3) - #| assert_true(summary.runs == 8) - #| @json.inspect(summary, content={ - #| "sum": 92.69999999999999, - #| "min": 1.1, - #| "max": 33.3, - #| "mean": 11.587499999999999, - #| "median": 8.5, - #| "variance": 127.64124999999999, - #| "std_dev": 11.297842714430042, - #| "std_dev_pct": 97.50026075020534, - #| "median_abs_dev": 9.043859999999999, - #| "median_abs_dev_pct": 106.39835294117646, - #| "quartiles": [3.025, 8.5, 16.15], - #| "iqr": 13.124999999999998, - #| "batch_size": 3, - #| "runs": 8, - #| }) - #|} - #|test "std_dev_pct zero mean" { - #| assert_eq(std_dev_pct(mean=0.0, std_dev=5.0), 0.0) - #|} - #|test "median_abs_dev_pct zero median" { - #| assert_eq(median_abs_dev_pct(median=0.0, median_abs_dev=3.0), 0.0) - #|} - #|test "percentile edge cases" { - #| assert_eq(percentile(sorted_data=[42.0], pct=50.0), 42.0) - #| assert_eq(percentile(sorted_data=[1.0, 2.0, 3.0], pct=100.0), 3.0) - #|} - ), - "types.mbt": ( - #|priv trait OpaqueValue {} - #|#alias(T) - #|struct Bench { - #| buffer : StringBuilder - #| summaries : Array[Summary] - #| mut _storage : &OpaqueValue - #|} - #|#as_free_fn - #|pub fn Bench::new() -> Bench { - #| let buffer = StringBuilder::new() - #| let summaries = Array::new() - #| { buffer, summaries, _storage: () } - #|} - ), - }, + "bench.mbt": ( + #|fn iter_n_microseconds(inner : () -> Unit, k : Int) -> Double { + #| let ts = monotonic_clock_start() + #| for _ in 0.. Unit, count : UInt) -> Summary { + #| let count = count.land(0x7FFFFFFF).reinterpret_as_int() + #| let threshold = 100000.0 // 100 ms + #| let target_batch_size = loop 1 { + #| trial => { + #| let single_us = iter_n_microseconds(inner, trial) / trial.to_double() + #| let target_batch_size = threshold / + #| (if single_us < 1.0 { 1.0 } else { single_us }) + #| if trial.to_double() * single_us > threshold { + #| break target_batch_size + #| } + #| continue trial * 2 + #| } + #| } + #| let batch_size = if target_batch_size < 1.0 { + #| 1 + #| } else { + #| target_batch_size.ceil().to_int() + #| } + #| let samples = Array::makei(count, _ => { + #| iter_n_microseconds(inner, batch_size) / batch_size.to_double() + #| }) + #| samples.sort() + #| winsorize(sorted_data=samples, 5.0) + #| Summary::new(name?, sorted_data=samples, batch_size) + #|} + #|pub fn Bench::bench( + #| self : Bench, + #| name? : String, + #| f : () -> Unit, + #| count? : UInt = 10, + #|) -> Unit { + #| let summary = iter_count(name?, f, count) + #| if !self.buffer.is_empty() { + #| self.buffer.write_char(',') + #| } + #| self.buffer.write_string(summary.to_json().stringify(escape_slash=true)) + #| self.summaries.push(summary) + #|} + #|pub fn single_bench( + #| name? : String, + #| f : () -> Unit, + #| count? : UInt = 10, + #|) -> Summary { + #| iter_count(name?, f, count) + #|} + #|pub fn[Any] Bench::keep(self : Bench, value : Any) -> Unit { + #| let trait_object : &OpaqueValue = @ref.new(value) + #| self._storage = trait_object + #|} + #|#coverage.skip + #|pub fn Bench::dump_summaries(self : Bench) -> String { + #| "[\{self.buffer.to_string()}]" + #|} + #|#skip("slow benchmarking test") + #|test "bench - single_bench basic functionality" { + #| let bench_result = single_bench( + #| () => { + #| let x = 1 + 1 + #| ignore(x) + #| }, + #| count=2, + #| ) + #| inspect(bench_result.runs, content="2") + #| inspect(bench_result.batch_size > 0, content="true") + #| inspect(bench_result.sum > 0.0, content="true") + #| inspect(bench_result.min <= bench_result.max, content="true") + #|} + #|#skip("slow benchmarking test") + #|test "bench - Summary struct properties" { + #| let bench_result = single_bench( + #| () => { + #| let x = 1 + #| ignore(x) + #| }, + #| count=5, + #| ) + #| inspect(bench_result.mean >= 0, content="true") + #| inspect(bench_result.median >= 0, content="true") + #| inspect(bench_result.std_dev >= 0, content="true") + #| inspect(bench_result.std_dev_pct >= 0, content="true") + #| inspect(bench_result.median_abs_dev >= 0, content="true") + #| inspect(bench_result.median_abs_dev_pct >= 0, content="true") + #| let (q1, q2, q3) = bench_result.quartiles + #| inspect(q1 <= q2, content="true") + #| inspect(q2 <= q3, content="true") + #| inspect((q3 - q1 - bench_result.iqr).abs() < 0.001, content="true") + #|} + #|#skip("slow benchmarking test") + #|test "bench - T struct and bench method" { + #| let bench_obj = new() + #| inspect(bench_obj.buffer.is_empty(), content="true") + #| inspect(bench_obj.summaries.is_empty(), content="true") + #| bench_obj.bench( + #| () => { + #| let x = 20 * 20 + #| ignore(x) + #| }, + #| count=2, + #| ) + #| inspect(bench_obj.buffer.is_empty(), content="false") + #| inspect(bench_obj.summaries.length(), content="1") + #| bench_obj.bench( + #| () => { + #| let y = 30 * 30 + #| ignore(y) + #| }, + #| count=2, + #| ) + #| inspect(bench_obj.summaries.length(), content="2") + #|} + #|#skip("slow benchmarking test") + #|test "bench - monotonic clock functionality" { + #| let start = monotonic_clock_start() + #| let result = for _ in 0..<1000; result = 0 { + #| continue result + 1 + #| } nobreak { + #| result + #| } + #| ignore(result) + #| let elapsed = monotonic_clock_end(start) + #| inspect(elapsed >= 0.0, content="true") + #|} + #|test "bench - keep stores value" { + #| let b = new() + #| assert_eq(b.summaries.length(), 0) + #| b.keep(123) + #| assert_eq(b.summaries.length(), 0) + #| b.keep(456) + #| assert_eq(b.summaries.length(), 0) + #|} + ), + "monotonic_clock_js.mbt": ( + #|type Timestamp + #|pub extern "js" fn monotonic_clock_start() -> Timestamp = + #| #| () => performance.now() + #|pub extern "js" fn monotonic_clock_end(ts : Timestamp) -> Double = + #| #| (ts) => (performance.now() - ts) * 1000.0 + ), + "monotonic_clock_native.mbt": ( + #|#external + #|type Timestamp + #|pub extern "C" fn monotonic_clock_start() -> Timestamp = "moonbit_monotonic_clock_start" + #|pub extern "C" fn monotonic_clock_end(ts : Timestamp) -> Double = "moonbit_monotonic_clock_stop" + ), + "monotonic_clock_wasm.mbt": ( + #|#external + #|type Timestamp + #|fn instant_elapsed_as_secs_f64(x : Timestamp) -> Double = "__moonbit_time_unstable" "instant_elapsed_as_secs_f64" + #|pub fn monotonic_clock_start() -> Timestamp = "__moonbit_time_unstable" "instant_now" + #|pub fn monotonic_clock_end(ts : Timestamp) -> Double { + #| let elapsed_secs : Double = instant_elapsed_as_secs_f64(ts) + #| elapsed_secs * 1000000.0 + #|} + ), + "stats.mbt": ( + #|struct Summary { + #| name : String? + #| sum : Double + #| min : Double + #| max : Double + #| mean : Double + #| median : Double + #| variance : Double + #| std_dev : Double + #| std_dev_pct : Double + #| median_abs_dev : Double + #| median_abs_dev_pct : Double + #| quartiles : (Double, Double, Double) + #| iqr : Double + #| batch_size : Int + #| runs : Int + #|} derive(ToJson) + #|fn Summary::new( + #| name? : String, + #| sorted_data~ : Array[Double], + #| batch_size : Int, + #|) -> Summary { + #| let sum = sum(sorted_data) + #| let min = min(sorted_data~) + #| let max = max(sorted_data~) + #| let mean = mean(sorted_data, sum~) + #| let median = median(sorted_data~) + #| let variance = variance(sorted_data, mean~) + #| let std_dev = std_dev(variance~) + #| let std_dev_pct = std_dev_pct(mean~, std_dev~) + #| let median_abs_dev = median_abs_dev(sorted_data, median_=median) + #| let median_abs_dev_pct = median_abs_dev_pct(median~, median_abs_dev~) + #| let quartiles = quartiles(sorted_data~) + #| let iqr = iqr(quartiles~) + #| { + #| name, + #| sum, + #| min, + #| max, + #| mean, + #| median, + #| variance, + #| std_dev, + #| std_dev_pct, + #| median_abs_dev, + #| median_abs_dev_pct, + #| quartiles, + #| iqr, + #| batch_size, + #| runs: sorted_data.length(), + #| } + #|} + #|fn sum(data : Array[Double]) -> Double { + #| for i in data; sum = 0.0 { + #| continue sum + i + #| } nobreak { + #| sum + #| } + #|} + #|fn min(sorted_data~ : Array[Double]) -> Double { + #| sorted_data[0] + #|} + #|fn max(sorted_data~ : Array[Double]) -> Double { + #| sorted_data[sorted_data.length() - 1] + #|} + #|fn mean(data : Array[Double], sum~ : Double) -> Double { + #| let count = data.length() + #| sum / count.to_double() + #|} + #|fn median(sorted_data~ : Array[Double]) -> Double { + #| percentile(sorted_data~, pct=50.0) + #|} + #|fn variance(data : Array[Double], mean~ : Double) -> Double { + #| if data.length() < 2 { + #| return 0.0 + #| } + #| for i in data; v = 0.0 { + #| let d = i - mean + #| continue v + d * d + #| } nobreak { + #| v / (data.length() - 1).to_double() + #| } + #|} + #|fn std_dev(variance~ : Double) -> Double { + #| variance.sqrt() + #|} + #|fn std_dev_pct(mean~ : Double, std_dev~ : Double) -> Double { + #| if mean == 0.0 { + #| return 0.0 + #| } + #| std_dev / mean * 100.0 + #|} + #|fn median_abs_dev(data : Array[Double], median_~ : Double) -> Double { + #| let abs_devs = data.map(x => (median_ - x).abs()) + #| abs_devs.sort() + #| median(sorted_data=abs_devs) * 1.4826 + #|} + #|fn median_abs_dev_pct(median~ : Double, median_abs_dev~ : Double) -> Double { + #| if median == 0.0 { + #| return 0.0 + #| } + #| median_abs_dev / median * 100.0 + #|} + #|fn quartiles(sorted_data~ : Array[Double]) -> (Double, Double, Double) { + #| let q1 = percentile(sorted_data~, pct=25.0) + #| let q2 = percentile(sorted_data~, pct=50.0) + #| let q3 = percentile(sorted_data~, pct=75.0) + #| (q1, q2, q3) + #|} + #|fn iqr(quartiles~ : (Double, Double, Double)) -> Double { + #| let (q1, _, q3) = quartiles + #| q3 - q1 + #|} + #|fn percentile(sorted_data~ : Array[Double], pct~ : Double) -> Double { + #| guard sorted_data.length() > 0 + #| guard pct >= 0.0 && pct <= 100.0 + #| if sorted_data.length() == 1 { + #| return sorted_data[0] + #| } + #| if pct == 100.0 { + #| return sorted_data[sorted_data.length() - 1] + #| } + #| let length = (sorted_data.length() - 1).to_double() + #| let rank = pct / 100 * length + #| let lrank = rank.floor() + #| let d = rank - lrank + #| let n = lrank.to_int() + #| let lo = sorted_data[n] + #| let hi = sorted_data[n + 1] + #| lo + (hi - lo) * d + #|} + #|fn winsorize(sorted_data~ : Array[Double], pct : Double) -> Unit { + #| let lo = percentile(sorted_data~, pct~) + #| let hi = percentile(sorted_data~, pct=100.0 - pct) + #| for i, samp in sorted_data { + #| if samp > hi { + #| sorted_data[i] = hi + #| } else if samp < lo { + #| sorted_data[i] = lo + #| } + #| } + #|} + #|test { + #| let data = [1.1, 21.4, 2.2, 3.3, 4.5, 12.5, 33.3, 14.4] + #| data.sort() + #| let summary = Summary::new(sorted_data=data, 3) + #| assert_true(summary.sum.is_close(92.7)) + #| assert_true(summary.min.is_close(1.1)) + #| assert_true(summary.max.is_close(33.3)) + #| assert_true(summary.mean.is_close(11.5875)) + #| assert_true(summary.median.is_close(8.5)) + #| assert_true(summary.variance.is_close(127.64125)) + #| assert_true(summary.std_dev.is_close(11.297842714430043)) + #| assert_true(summary.std_dev_pct.is_close(97.50026075020534)) + #| assert_true(summary.median_abs_dev.is_close(9.04386)) + #| assert_true(summary.median_abs_dev_pct.is_close(106.39835294117646)) + #| let (q1, q2, q3) = summary.quartiles + #| assert_true(q1.is_close(3.025)) + #| assert_true(q2.is_close(8.5)) + #| assert_true(q3.is_close(16.15)) + #| assert_true(summary.iqr.is_close(13.125)) + #| assert_true(summary.batch_size == 3) + #| assert_true(summary.runs == 8) + #| @json.json_inspect(summary, content={ + #| "sum": 92.69999999999999, + #| "min": 1.1, + #| "max": 33.3, + #| "mean": 11.587499999999999, + #| "median": 8.5, + #| "variance": 127.64124999999999, + #| "std_dev": 11.297842714430042, + #| "std_dev_pct": 97.50026075020534, + #| "median_abs_dev": 9.043859999999999, + #| "median_abs_dev_pct": 106.39835294117646, + #| "quartiles": [3.025, 8.5, 16.15], + #| "iqr": 13.124999999999998, + #| "batch_size": 3, + #| "runs": 8, + #| }) + #|} + #|test "std_dev_pct zero mean" { + #| assert_eq(std_dev_pct(mean=0.0, std_dev=5.0), 0.0) + #|} + #|test "median_abs_dev_pct zero median" { + #| assert_eq(median_abs_dev_pct(median=0.0, median_abs_dev=3.0), 0.0) + #|} + #|test "percentile edge cases" { + #| assert_eq(percentile(sorted_data=[42.0], pct=50.0), 42.0) + #| assert_eq(percentile(sorted_data=[1.0, 2.0, 3.0], pct=100.0), 3.0) + #|} + ), + "types.mbt": ( + #|priv trait OpaqueValue {} + #|impl[X] OpaqueValue for @ref.Ref[X] + #|#alias(T) + #|struct Bench { + #| buffer : StringBuilder + #| summaries : Array[Summary] + #| mut _storage : &OpaqueValue + #|} + #|#as_free_fn + #|pub fn Bench::new() -> Bench { + #| let buffer = StringBuilder::new() + #| let summaries = Array::new() + #| { buffer, summaries, _storage: @ref.new(()) } + #|} + ) + } ) ///| let moonbitlang_core_bigint_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/bigint", - deps={ - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/char": moonbitlang_core_char_module, - "moonbitlang/core/uint": moonbitlang_core_uint_module, - "moonbitlang/core/json": moonbitlang_core_json_module, - "moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module, - "moonbitlang/core/quickcheck/splitmix": moonbitlang_core_quickcheck_splitmix_module, - "moonbitlang/core/string": moonbitlang_core_string_module, - "moonbitlang/core/bytes": moonbitlang_core_bytes_module, - "moonbitlang/core/int16": moonbitlang_core_int16_module, - "moonbitlang/core/uint16": moonbitlang_core_uint16_module, - }, - files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| "moonbitlang/core/builtin", - #| "moonbitlang/core/char", - #| "moonbitlang/core/uint", - #| "moonbitlang/core/json", - #| "moonbitlang/core/quickcheck", - #| "moonbitlang/core/quickcheck/splitmix", - #| "moonbitlang/core/string", - #| "moonbitlang/core/bytes", - #| "moonbitlang/core/int16", - #| "moonbitlang/core/uint16" - #| ], - #| "targets": { - #| "bigint_js.mbt": ["js"], - #| "bigint_nonjs.mbt": ["not", "js"], - #| "bigint_js_wbtest.mbt": ["js"], - #| "bigint_nonjs_wbtest.mbt": ["not", "js"] - #| }, - #| "warn-list": "-29" - #|} - ), - "bigint.mbt": ( - #|pub impl ToJson for BigInt with to_json(self : BigInt) -> Json { - #| Json::string(self.to_string()) - #|} - #|pub impl @json.FromJson for BigInt with from_json(json, path) { - #| guard json is String(s) else { - #| raise @json.JsonDecodeError( - #| (path, "BigInt::from_json: expected number in string representation"), - #| ) - #| } - #| BigInt::from_string(s) - #|} - #|pub impl @quickcheck.Arbitrary for BigInt with arbitrary(size, rs) { - #| if size == 0 { - #| 0 - #| } else { - #| rs.next_int64() |> BigInt::from_int64 - #| } - #|} - #|pub impl Default for BigInt with default() { - #| zero - #|} - #|pub fn BigInt::equal_int(self : BigInt, other : Int) -> Bool { - #| can_convert_to_int(self) && self.to_int() == other - #|} - #|pub fn BigInt::equal_int64(self : BigInt, other : Int64) -> Bool { - #| can_convert_to_int64(self) && self.to_int64() == other - #|} - #|pub fn BigInt::compare_int(self : BigInt, other : Int) -> Int { - #| guard can_convert_to_int(self) else { - #| return if is_neg(self) { -1 } else { 1 } - #| } - #| let self = self.to_int() - #| Int::compare(self, other) - #|} - #|pub fn BigInt::compare_int64(self : BigInt, other : Int64) -> Int { - #| guard can_convert_to_int64(self) else { - #| return if is_neg(self) { -1 } else { 1 } - #| } - #| let self = self.to_int64() - #| Int64::compare(self, other) - #|} - #|test "can_convert_to_int" { - #| assert_true(can_convert_to_int(0N)) - #| assert_true(can_convert_to_int(1N)) - #| assert_true(can_convert_to_int(-1N)) - #| assert_true(can_convert_to_int(2147483647N)) // Int.max_value - #| assert_true(can_convert_to_int(-2147483648N)) // Int.min_value - #| assert_false(can_convert_to_int(2147483648N)) // Int.max_value + 1 - #| assert_false(can_convert_to_int(-2147483649N)) // Int.min_value - 1 - #| assert_false(can_convert_to_int(4294967295N)) // 2^32 - 1 - #| assert_false(can_convert_to_int(-4294967295N)) // -(2^32 - 1) - #| assert_false(can_convert_to_int(4294967296N)) // 2^32 - #| assert_false(can_convert_to_int(-4294967296N)) // -2^32 - #|} - #|test "can_convert_to_int64" { - #| assert_true(can_convert_to_int64(0N)) - #| assert_true(can_convert_to_int64(1N)) - #| assert_true(can_convert_to_int64(-1N)) - #| assert_true(can_convert_to_int64(2147483647N)) // Int.max_value - #| assert_true(can_convert_to_int64(-2147483648N)) // Int.min_value - #| assert_true(can_convert_to_int64(2147483648N)) // Int.max_value + 1 - #| assert_true(can_convert_to_int64(-2147483649N)) // Int.min_value - 1 - #| assert_true(can_convert_to_int64(4294967295N)) // 2^32 - 1 - #| assert_true(can_convert_to_int64(-4294967295N)) // -(2^32 - 1) - #| assert_true(can_convert_to_int64(4294967296N)) // 2^32 - #| assert_true(can_convert_to_int64(-4294967296N)) // -2^32 - #| assert_true(can_convert_to_int64(9223372036854775807N)) // Int64.max_value - #| assert_true(can_convert_to_int64(-9223372036854775808N)) // Int64.min_value - #| assert_false(can_convert_to_int64(9223372036854775808N)) // Int64.max_value + 1 - #| assert_false(can_convert_to_int64(-9223372036854775809N)) // Int64.min_value - 1 - #| assert_false(can_convert_to_int64(18446744073709551615N)) // 2^64 - 1 - #| assert_false(can_convert_to_int64(-18446744073709551615N)) // -(2^64 - 1) - #| assert_false(can_convert_to_int64(18446744073709551616N)) // 2^64 - #| assert_false(can_convert_to_int64(-18446744073709551616N)) // -2^64 - #|} - #|pub impl Hash for BigInt with hash_combine(self, hasher) { - #| hasher.combine(self.signum()) - #| for limb in self.limbs() { - #| hasher.combine(limb) - #| } - #|} - #|fn BigInt::signum(self : Self) -> Int { - #| if self.is_zero() { - #| 0 - #| } else if is_neg(self) { - #| -1 - #| } else { - #| 1 - #| } - #|} - #|pub fn BigInt::to_uint16(self : BigInt) -> UInt16 { - #| self.to_int().to_uint16() - #|} - #|pub fn BigInt::to_int16(self : BigInt) -> Int16 { - #| Int16::from_int(self.to_int()) - #|} - ), - "bigint_js.mbt": ( - #|type BigInt - #|let zero = 0N - #|pub fn BigInt::from_string(str : String) -> BigInt { - #| if str.length() == 0 { - #| abort("empty string") - #| } - #| BigInt::js_from_string(str) - #|} - #|extern "js" fn BigInt::js_from_string(str : String) -> BigInt = - #| #|(x) => BigInt(x) - #|pub impl Show for BigInt with output(self, logger) { - #| logger.write_string(self.to_string()) - #|} - #|pub extern "js" fn BigInt::to_string(self : BigInt) -> String = - #| #|(x) => String(x) - #|pub extern "js" fn BigInt::from_hex(str : String) -> BigInt = - #| #|(x) => x.startsWith('-') ? -BigInt(`0x${x.slice(1)}`) : BigInt(`0x${x}`) - #|pub extern "js" fn BigInt::to_hex( - #| self : BigInt, - #| uppercase? : Bool = true, - #|) -> String = - #| #|(x, uppercase) => { - #| #| const r = x.toString(16); - #| #| return uppercase ? r.toUpperCase() : r; - #| #|} - #|extern "js" fn hex2(b : Byte) -> String = - #| #|(x) => x.toString(16).padStart(2, '0') - #|pub fn BigInt::from_octets(octets : Bytes, signum? : Int = 1) -> BigInt { - #| if signum < 0 { - #| return -1N * BigInt::from_octets(octets, signum=1) - #| } - #| if signum == 0 { - #| return 0N - #| } - #| let str = StringBuilder::new() - #| str.write_string("0x") - #| for octet in octets { - #| str.write_string(hex2(octet)) - #| } - #| BigInt::from_string(str.to_string()) - #|} - #|pub fn BigInt::to_octets(self : BigInt, length? : Int) -> Bytes { - #| if self < 0 { - #| abort("negative BigInt") - #| } - #| if self == 0 { - #| return match length { - #| Some(len) => Bytes::make(len, 0) - #| None => [0] - #| } - #| } - #| let buf = [] - #| loop self { - #| v => - #| if v > 0 { - #| buf.push(v.to_byte()) - #| continue v >> 8 - #| } - #| } - #| let buf_len = buf.length() - #| match length { - #| Some(len) => { - #| if len <= 0 { - #| abort("negative length") - #| } - #| if len > buf_len { - #| Bytes::makei(len, i => { - #| let padding = len - buf_len - #| if i < padding { - #| 0 - #| } else { - #| buf[buf_len - (i - padding) - 1] - #| } - #| }) - #| } else { - #| Bytes::makei(buf_len, i => buf[buf_len - i - 1]) - #| } - #| } - #| None => Bytes::makei(buf_len, i => buf[buf_len - i - 1]) - #| } - #|} - #|extern "js" fn BigInt::compare(self : BigInt, other : BigInt) -> Int = - #| #|(x, y) => x < y ? -1 : x > y ? 1 : 0 - #|pub impl Compare for BigInt with compare(self, other) { - #| self.compare(other) - #|} - #|extern "js" fn BigInt::equal(self : BigInt, other : BigInt) -> Bool = - #| #|(x, y) => x === y - #|pub impl Eq for BigInt with equal(self, other) { - #| self.equal(other) - #|} - #|pub extern "js" fn BigInt::from_int(x : Int) -> BigInt = - #| #|(x) => BigInt(x) - #|pub extern "js" fn BigInt::from_uint(x : UInt) -> BigInt = - #| #|(x) => BigInt(x >>> 0) - #|pub extern "js" fn BigInt::from_int64(x : Int64) -> BigInt = - #| #|(x) => BigInt(x.hi) * 0x100000000n + BigInt(x.lo >>> 0) - #|pub extern "js" fn BigInt::from_uint64(x : UInt64) -> BigInt = - #| #|(x) => BigInt(x.hi >>> 0) * 0x100000000n + BigInt(x.lo >>> 0) - #|pub extern "js" fn BigInt::is_zero(self : BigInt) -> Bool = - #| #|(x) => x === 0n - #|extern "js" fn BigInt::op_neg_ffi(self : BigInt) -> BigInt = - #| #|(x) => -x - #|pub impl Neg for BigInt with neg(self) { - #| self.op_neg_ffi() - #|} - #|extern "js" fn BigInt::op_add_ffi(self : BigInt, other : BigInt) -> BigInt = - #| #|(x, y) => x + y - #|pub impl Add for BigInt with add(self, other) { - #| self.op_add_ffi(other) - #|} - #|extern "js" fn BigInt::op_sub_ffi(self : BigInt, other : BigInt) -> BigInt = - #| #|(x, y) => x - y - #|pub impl Sub for BigInt with sub(self, other) { - #| self.op_sub_ffi(other) - #|} - #|extern "js" fn BigInt::op_mul_ffi(self : BigInt, other : BigInt) -> BigInt = - #| #|(x, y) => x * y - #|pub impl Mul for BigInt with mul(self, other) { - #| self.op_mul_ffi(other) - #|} - #|extern "js" fn BigInt::op_div_ffi(self : BigInt, other : BigInt) -> BigInt = - #| #|(x, y) => x / y - #|pub impl Div for BigInt with div(self, other) { - #| self.op_div_ffi(other) - #|} - #|extern "js" fn BigInt::op_mod_ffi(self : BigInt, other : BigInt) -> BigInt = - #| #|(x, y) => x % y - #|pub impl Mod for BigInt with mod(self, other) { - #| self.op_mod_ffi(other) - #|} - #|extern "js" fn BigInt::modpow_ffi( - #| self : BigInt, - #| exponent : BigInt, - #| modulus : BigInt, - #|) -> BigInt = - #| #|(x, y, z) => { - #| #| if (z === 1n) return 0n; - #| #| let result = 1n; - #| #| x = x % z; - #| #| while (y > 0n) { - #| #| if (y & 1n) { - #| #| result = (result * x) % z; - #| #| } - #| #| y >>= 1n; - #| #| x = (x * x) % z; - #| #| } - #| #| return result; - #| #|} - #|extern "js" fn BigInt::pow_ffi(self : BigInt, exponent : BigInt) -> BigInt = - #| #|(x, y) => x ** y - #|pub fn BigInt::pow( - #| self : BigInt, - #| exponent : BigInt, - #| modulus? : BigInt, - #|) -> BigInt { - #| if exponent < 0 { - #| abort("negative exponent") - #| } - #| match modulus { - #| Some(modulus) => - #| if modulus <= 0 { - #| abort("non-positive modulus") - #| } else { - #| self.modpow_ffi(exponent, modulus) - #| } - #| None => self.pow_ffi(exponent) - #| } - #|} - #|extern "js" fn BigInt::to_byte(self : BigInt) -> Byte = - #| #|(x) => Number(BigInt.asUintN(8, x)) | 0 - #|pub impl Shl for BigInt with shl(self : BigInt, n : Int) -> BigInt { - #| if n < 0 { - #| abort("negative shift count") - #| } - #| self.js_shl(n) - #|} - #|pub impl Shr for BigInt with shr(self : BigInt, n : Int) -> BigInt { - #| if n < 0 { - #| abort("negative shift count") - #| } - #| self.js_shr(n) - #|} - #|extern "js" fn BigInt::js_shl(self : BigInt, other : Int) -> BigInt = - #| #|(x, y) => x << BigInt(y) - #|extern "js" fn BigInt::js_shr(self : BigInt, other : Int) -> BigInt = - #| #|(x, y) => x >> BigInt(y) - #|extern "js" fn BigInt::js_land(self : BigInt, other : BigInt) -> BigInt = - #| #|(x, y) => x & y - #|pub impl BitAnd for BigInt with land(self, other) { - #| self.js_land(other) - #|} - #|extern "js" fn BigInt::js_lor(self : BigInt, other : BigInt) -> BigInt = - #| #|(x, y) => x | y - #|pub impl BitOr for BigInt with lor(self, other) { - #| self.js_lor(other) - #|} - #|extern "js" fn BigInt::js_lxor(self : BigInt, other : BigInt) -> BigInt = - #| #|(x, y) => x ^ y - #|pub impl BitXOr for BigInt with lxor(self, other) { - #| self.js_lxor(other) - #|} - #|pub extern "js" fn BigInt::to_uint(self : BigInt) -> UInt = - #| #|(x) => Number(BigInt.asUintN(32, x)) | 0 - #|pub extern "js" fn BigInt::to_int(self : BigInt) -> Int = - #| #|(x) => Number(BigInt.asIntN(32, x)) - #|pub fn BigInt::to_uint64(self : BigInt) -> UInt64 { - #| let hi = (self >> 32).to_uint() - #| let lo = self.to_uint() - #| (hi.to_uint64() << 32) | lo.to_uint64() - #|} - #|pub fn BigInt::to_int64(self : BigInt) -> Int64 { - #| let hi = (self >> 32).to_uint() - #| let lo = self.to_uint() - #| (hi.to_int64() << 32) | lo.to_int64() - #|} - #|pub extern "js" fn BigInt::bit_length(self : BigInt) -> Int = - #| #|(n) => { - #| #| if (n >= 0) { - #| #| return n === 0n ? 0 : n.toString(2).length; - #| #| } else { - #| #| const absN = -n; - #| #| const absMinus1 = absN - 1n; - #| #| return absMinus1 === 0n ? 0 : absMinus1.toString(2).length; - #| #| } - #| #|} - #|pub extern "js" fn BigInt::ctz(self : BigInt) -> Int = - #| #|(n) => { - #| #| if (n === 0n) return 0; - #| #| let absN = n < 0n ? -n : n; - #| #| let count = 0; - #| #| while ((absN & 1n) === 0n) { - #| #| absN >>= 1n; - #| #| count++; - #| #| } - #| #| return count; - #| #|} - #|extern "js" fn can_convert_to_int(x : BigInt) -> Bool = - #| #|(x) => x >= -(2n ** 31n) && x < 2n ** 31n - #|extern "js" fn can_convert_to_int64(x : BigInt) -> Bool = - #| #|(x) => x >= -(2n ** 63n) && x < 2n ** 63n - #|extern "js" fn is_neg(x : BigInt) -> Bool = - #| #|(x) => x < 0n - #|fn BigInt::limbs(self : Self) -> Array[UInt] { - #| guard !self.is_zero() else { [0] } - #| let result = [] - #| for n = self * BigInt::from_int(self.signum()); n > 0; n = n >> 32 { - #| let limb = n.to_uint() - #| result.push(limb) - #| } - #| result - #|} - ), - "bigint_nonjs.mbt": ( - #|struct BigInt { - #| limbs : FixedArray[UInt] // Note: do not use limbs.length(), use len instead because of leading zeros - #| sign : Sign - #| len : Int - #|} - #|priv enum Sign { - #| Positive - #| Negative - #|} derive(Eq) - #|let radix_bit_len = 32 - #|let radix : UInt64 = 1UL << radix_bit_len // TODO: This can be generalized once we have const generics - #|let radix_mask : UInt64 = radix - 1 - #|let decimal_ratio = 0.302 // log10(2) - #|let karatsuba_threshold = 50 - #|let zero : BigInt = 0N - #|let one : BigInt = 1N - #|pub fn BigInt::from_int(n : Int) -> BigInt { - #| BigInt::from_int64(n.to_int64()) - #|} - #|pub fn BigInt::from_uint(n : UInt) -> BigInt { - #| BigInt::from_uint64(n.to_uint64()) - #|} - #|pub fn BigInt::from_int64(n : Int64) -> BigInt { - #| if n < 0L { - #| -BigInt::from_uint64((-n).reinterpret_as_uint64()) - #| } else { - #| BigInt::from_uint64(n.reinterpret_as_uint64()) - #| } - #|} - #|pub fn BigInt::from_uint64(n : UInt64) -> BigInt { - #| if n == 0UL { - #| return { limbs: FixedArray::make(1, 0), sign: Positive, len: 1 } - #| } - #| let limbs = FixedArray::make(64 / radix_bit_len, 0U) - #| let mut m = n - #| let mut i = 0 - #| while m > 0 { - #| limbs[i] = (m % radix).to_uint() - #| m /= radix - #| i += 1 - #| } - #| { limbs, sign: Positive, len: i } - #|} - #|pub impl Neg for BigInt with neg(self : BigInt) -> BigInt { - #| if self.is_zero() { - #| return zero - #| } - #| { ..self, sign: if self.sign == Positive { Negative } else { Positive } } - #|} - #|pub impl Add for BigInt with add(self : BigInt, other : BigInt) -> BigInt { - #| if self.sign == Negative { - #| if other.sign == Negative { - #| return -(-other + -self) - #| } else { - #| return other - -self - #| } - #| } else if other.sign == Negative { - #| return self - -other - #| } - #| let self_len = self.len - #| let other_len = other.len - #| let limbs = FixedArray::make(1 + max(self_len, other_len), 0U) - #| let mut carry = 0UL - #| let mut i = 0 - #| while i < self_len || i < other_len || carry != 0 { - #| let a = if i < self_len { self.limbs[i].to_uint64() } else { 0 } - #| let b = if i < other_len { other.limbs[i].to_uint64() } else { 0 } - #| let sum = a + b + carry - #| limbs[i] = (sum % radix).to_uint() - #| carry = sum / radix - #| i += 1 - #| } - #| { limbs, sign: Positive, len: i } - #|} - #|pub impl Sub for BigInt with sub(self : BigInt, other : BigInt) -> BigInt { - #| if self.sign == Negative { - #| if other.sign == Negative { - #| return -other - -self - #| } else { - #| return -(other + -self) - #| } - #| } else if other.sign == Negative { - #| return self + -other - #| } - #| if self < other { - #| return -(other - self) - #| } - #| let self_len = self.len - #| let other_len = other.len - #| let limbs = FixedArray::make(max(self_len, other_len), 0U) - #| let mut borrow = 0L - #| let mut i = 0 - #| while i < self_len || i < other_len || borrow != 0L { - #| let a = if i < self_len { self.limbs[i].to_int64() } else { 0 } - #| let b = if i < other_len { other.limbs[i].to_int64() } else { 0 } - #| let diff = a - b - borrow // 0 <= a < radix, 0 <= b < radix, 0 <= borrow <= 1 => -radix <= diff < radix - #| if diff < 0L { - #| limbs[i] = (diff + radix.reinterpret_as_int64()) - #| .reinterpret_as_uint64() - #| .to_uint() // -radix <= diff < 0, so we don't need to mod by radix - #| borrow = 1L - #| } else { - #| limbs[i] = diff.reinterpret_as_uint64().to_uint() // 0 <= diff < radix, so we don't need to mod by radix - #| borrow = 0L - #| } - #| i += 1 - #| } - #| while i > 1 && limbs[i - 1] == 0 { - #| i -= 1 - #| } - #| { limbs, sign: Positive, len: i } - #|} - #|pub impl Mul for BigInt with mul(self : BigInt, other : BigInt) -> BigInt { - #| if self.is_zero() || other.is_zero() { - #| return zero - #| } - #| let ret = if self.len < karatsuba_threshold || other.len < karatsuba_threshold { - #| self.grade_school_mul(other) - #| } else { - #| self.karatsuba_mul(other) - #| } - #| { ..ret, sign: if self.sign == other.sign { Positive } else { Negative } } - #|} - #|fn BigInt::grade_school_mul(self : BigInt, other : BigInt) -> BigInt { - #| let self_len = self.len - #| let other_len = other.len - #| let mut len = self_len + other_len - #| let limbs = FixedArray::make(len, 0U) - #| for i in 0.. BigInt { - #| let half = (max(self.len, other.len) + 1) / 2 - #| let (xl, xh) = self.split(half) - #| let (yl, yh) = other.split(half) - #| let p1 = xh * yh - #| let p2 = xl * yl - #| let p3 = (xh + xl) * (yh + yl) - #| (p1 << (radix_bit_len * 2 * half)) + - #| ((p3 - p1 - p2) << (radix_bit_len * half)) + - #| p2 - #|} - #|fn BigInt::split(self : BigInt, half : Int) -> (BigInt, BigInt) { - #| if self.len <= half { - #| return ({ ..self, sign: Positive }, zero) - #| } - #| let lower_len = for i = half - 1; i > 0; i = i - 1 { - #| if self.limbs[i] > 0 { - #| break i + 1 - #| } - #| } else { - #| 1 - #| } - #| let lower = FixedArray::make(lower_len, 0U) - #| lower.unsafe_blit(0, self.limbs, 0, lower_len) - #| let upper = FixedArray::make(self.len - half, 0U) - #| upper.unsafe_blit(0, self.limbs, half, self.len - half) - #| ( - #| { limbs: lower, sign: Positive, len: lower_len }, - #| { limbs: upper, sign: Positive, len: self.len - half }, - #| ) - #|} - #|pub impl Div for BigInt with div(self : BigInt, other : BigInt) -> BigInt { - #| if other is 0 { - #| abort("division by zero") - #| } - #| if self.sign == Negative { - #| if other.sign == Negative { - #| BigInt::grade_school_div(-self, -other).0 - #| } else { - #| -BigInt::grade_school_div(-self, other).0 - #| } - #| } else if other.sign == Negative { - #| -BigInt::grade_school_div(self, -other).0 - #| } else { - #| return BigInt::grade_school_div(self, other).0 - #| } - #|} - #|pub impl Mod for BigInt with mod(self : BigInt, other : BigInt) -> BigInt { - #| if other == zero { - #| abort("division by zero") - #| } - #| if self.sign == Negative { - #| if other.sign == Negative { - #| -BigInt::grade_school_div(-self, -other).1 - #| } else { - #| -BigInt::grade_school_div(-self, other).1 - #| } - #| } else if other.sign == Negative { - #| BigInt::grade_school_div(self, -other).1 - #| } else { - #| BigInt::grade_school_div(self, other).1 - #| } - #|} - #|fn BigInt::grade_school_div(self : BigInt, other : BigInt) -> (BigInt, BigInt) { - #| if self < other { - #| return (zero, self) - #| } else if self == other { - #| return (one, zero) - #| } - #| if other.len == 1 { - #| let number = other.limbs[0] - #| let ret = self.copy() - #| if number == 1 { - #| return (ret, zero) - #| } - #| let a = ret.limbs - #| let x = number.to_uint64() - #| let mut y = 0UL - #| for i = self.len - 1; i >= 0; i = i - 1 { - #| y = y << radix_bit_len - #| y += a[i].to_uint64() - #| a[i] = ((y / x) & radix_mask).to_uint() - #| y %= x - #| } - #| if ret.limbs[ret.len - 1] == 0 { - #| return ( - #| { ..ret, len: ret.len - 1 }, - #| { limbs: FixedArray::make(1, y.to_uint()), sign: Positive, len: 1 }, - #| ) - #| } - #| return ( - #| ret, - #| { limbs: FixedArray::make(1, y.to_uint()), sign: Positive, len: 1 }, - #| ) - #| } - #| let dividend = self - #| let divisor = other - #| let lshift = max( - #| 0, - #| radix_bit_len - (64 - divisor.limbs[divisor.len - 1].to_int64().clz()), - #| ) - #| let a_len = dividend.len - #| let dividend = dividend << lshift - #| let divisor = divisor << lshift - #| let b_len = divisor.len - #| let b = FixedArray::make(b_len, 0UL) - #| for i in 0.. i { - #| a[i] = dividend.limbs[i].to_uint64() - #| } - #| } - #| let a_len = a_len + 1 - #| let v1 = b[b_len - 1] - #| let v2 = b[b_len - 2] - #| let q = FixedArray::make(a_len - b_len, 0U) - #| for i = q.length() - 1; i >= 0; i = i - 1 { - #| let u0 = a[i + b_len] - #| let u1 = a[i + b_len - 1] - #| let u2 = a[i + b_len - 2] - #| let mut qh = (u0 * radix + u1) / v1 - #| if qh * v2 > radix * (u0 * radix + u1 - qh * v1) + u2 { - #| qh -= 1 - #| } - #| let mut borrow = 0L - #| let mut carry = 0UL - #| for j in 0..> radix_bit_len - #| carry = carry >> radix_bit_len - #| } - #| borrow = borrow + a[i + b_len].reinterpret_as_int64() - #| borrow -= carry.reinterpret_as_int64() - #| a[i + b_len] = (borrow & radix_mask.reinterpret_as_int64()).reinterpret_as_uint64() - #| borrow = borrow >> radix_bit_len - #| if borrow < 0L { - #| carry = 0UL - #| for j in 0..> radix_bit_len - #| } - #| carry += a[i + b_len] - #| a[i + b_len] = carry & radix_mask - #| carry = carry >> radix_bit_len - #| borrow += carry.reinterpret_as_int64() - #| qh -= 1 - #| } - #| q[i] = qh.to_uint() - #| } - #| let len = if q[q.length() - 1] == 0 { q.length() - 1 } else { q.length() } - #| let mut i = a.length() - 1 - #| while i >= 0 && a[i] == 0 { - #| i -= 1 - #| } - #| if i < 0 { - #| i = 1 - #| } else { - #| i += 1 - #| } - #| let modulo = FixedArray::make(i, 0U) - #| for j in 0..> lshift) - #|} - #|pub impl Shl for BigInt with shl(self : BigInt, n : Int) -> BigInt { - #| if n < 0 { - #| abort("negative shift count") - #| } - #| if !self.is_zero() { - #| let new_limbs = FixedArray::make( - #| self.len + (n + radix_bit_len - 1) / radix_bit_len, // ceiling(n / radix_bit_len) - #| 0U, - #| ) - #| let a = self.limbs - #| let r = n % radix_bit_len - #| let lz = n / radix_bit_len // number of leading zeros - #| let mut len = self.len + lz - #| if r != 0 { - #| let mut carry = 0UL - #| for i in 0..> radix_bit_len - #| } - #| if carry != 0 { - #| new_limbs[self.len + lz] = carry.to_uint() - #| len += 1 - #| } - #| } else { - #| new_limbs.unsafe_blit(lz, self.limbs, 0, self.len) - #| } - #| { limbs: new_limbs, sign: self.sign, len } - #| } else { - #| zero - #| } - #|} - #|pub impl Shr for BigInt with shr(self : BigInt, n : Int) -> BigInt { - #| if n < 0 { - #| abort("negative shift count") - #| } - #| let r = n % radix_bit_len - #| let lz = n / radix_bit_len - #| if lz >= self.len { - #| match self.sign { - #| Positive => return zero - #| Negative => - #| return { limbs: FixedArray::make(1, 1), sign: Negative, len: 1 } - #| } - #| } - #| let mut new_len = self.len - lz - #| if r == 0 { - #| let new_limbs = FixedArray::make(new_len, 0U) - #| new_limbs.unsafe_blit(0, self.limbs, lz, new_len) - #| { limbs: new_limbs, sign: self.sign, len: new_len } - #| } else { - #| let new_limbs = FixedArray::make(new_len, 0U) - #| let a = self.limbs - #| let mut carry = 0UL - #| for i = self.len - 1; i >= lz; i = i - 1 { - #| let x = a[i].to_uint64() - #| new_limbs[i - lz] = ((x >> r) | carry).to_uint() - #| carry = (x << (radix_bit_len - r)) % radix - #| } - #| if new_len > 1 && new_limbs[new_len - 1] == 0 { - #| new_len -= 1 - #| } - #| if self.sign == Negative && (carry & (1UL << r)) != carry { - #| { limbs: new_limbs, sign: self.sign, len: new_len } - 1 - #| } else { - #| { limbs: new_limbs, sign: self.sign, len: new_len } - #| } - #| } - #|} - #|pub fn BigInt::is_zero(self : BigInt) -> Bool { - #| self.len == 1 && self.limbs[0] == 0 - #|} - #|pub impl Compare for BigInt with compare(self, other) { - #| if self.sign != other.sign { - #| return if self.sign == Positive { 1 } else { -1 } - #| } - #| let self_len = self.len - #| let other_len = other.len - #| if self_len != other_len { - #| return if self.sign == Positive { - #| self_len - other_len - #| } else { - #| other_len - self_len - #| } - #| } - #| for i = self_len - 1; i >= 0; i = i - 1 { - #| if self.limbs[i] != other.limbs[i] { - #| return if self.sign == Positive { - #| self.limbs[i].compare(other.limbs[i]) - #| } else { - #| other.limbs[i].compare(self.limbs[i]) - #| } - #| } - #| } - #| 0 - #|} - #|pub impl Eq for BigInt with equal(self, other) { - #| if self.sign != other.sign || self.len != other.len { - #| return false - #| } - #| for i in 0.. String { - #| if self.is_zero() { - #| return "0" - #| } - #| let decimal_radix_bit_len = 19 - 1 - (1 + radix_bit_len) / 3 // < len(9,223,372,036,854,775,807) - len(2^radix_bit_len). len means the number of digits in decimal. - #| let decimal_mask = 10_000_000L // 10^(decimal_radix_bit_len). TODO: compute it when we have power function. - #| let decimal_len = unchecked_double_to_int( - #| (self.len * radix_bit_len).to_double() * - #| decimal_ratio / - #| decimal_radix_bit_len.to_double() + - #| 1, - #| ) - #| let s = if self.sign == Negative { "-" } else { "" } - #| let v = Array::make(decimal_len, 0L) - #| let mut v_idx = 0 - #| for i = self.len - 1; i >= 0; i = i - 1 { - #| let mut x = self.limbs[i].to_int64() - #| for j in 0.. 0L { - #| v[v_idx] = x % decimal_mask - #| v_idx += 1 - #| x /= decimal_mask - #| } - #| } - #| let mut ret = "" - #| for i in 0..<(v_idx - 1) { - #| for j in 0.. 0L { - #| let y = x % 10L - #| x /= 10L - #| ret = y.to_string() + ret - #| } - #| s + ret - #|} - #|pub impl Show for BigInt with output(self, logger) { - #| logger.write_string(self.to_string()) - #|} - #|pub fn BigInt::from_string(input : String) -> BigInt { - #| let len = input.length() - #| if len == 0 { - #| abort("empty string") - #| } - #| let sign : Sign = if input.unsafe_charcode_at(0) == '-' { - #| Negative - #| } else { - #| Positive - #| } - #| let mut b_len = ( - #| unchecked_double_to_int(len.to_double() / decimal_ratio) + - #| 1 + - #| radix_bit_len - #| ) / - #| radix_bit_len + - #| 1 - #| let b = FixedArray::make(b_len, 0U) - #| for - #| i in (match sign { - #| Negative => 1 - #| Positive => 0 - #| }).. 9 { - #| abort("invalid character") - #| } - #| let mut carry = x.reinterpret_as_uint().to_uint64() - #| for j in 0.. 1 { - #| b_len -= 1 - #| } - #| { limbs: b, sign, len: b_len } - #|} - #|pub fn BigInt::from_hex(input : String) -> BigInt { - #| fn char_from_hex(x : Int) -> UInt { - #| (match x { - #| '0'..='9' => x - '0' - #| 'A'..='F' => x + (10 - 'A') - #| 'a'..='f' => x + (10 - 'a') - #| _ => abort("invalid character") - #| }).reinterpret_as_uint() - #| } - #| let len = input.length() - #| if len == 0 { - #| abort("empty string") - #| } - #| let (sign, number_len) = if input.unsafe_charcode_at(0) == '-' { - #| (Negative, len - 1) - #| } else { - #| (Positive, len) - #| } - #| let nb_char = radix_bit_len / 4 // number of char per limb - #| let quotient = number_len / nb_char - #| let mod = number_len % nb_char - #| let mut b_len = if mod == 0 { quotient } else { quotient + 1 } - #| let b = FixedArray::make(b_len, 0U) - #| if mod != 0 { - #| let start = len - quotient * nb_char - mod - #| for i in 0.. 1 { - #| b_len -= 1 - #| } - #| { limbs: b, sign, len: b_len } - #|} - #|pub fn BigInt::to_hex(self : BigInt, uppercase? : Bool = true) -> String { - #| if self.is_zero() { - #| return "0" - #| } - #| let digits_per_limb = radix_bit_len / 4 - #| let buf = if self.sign is Negative { - #| let builder = StringBuilder::new(size_hint=self.len * digits_per_limb + 2) - #| builder.write_char('-') - #| builder - #| } else { - #| StringBuilder::new(size_hint=self.len * digits_per_limb) - #| } - #| for i = self.len - 1; i >= 0; i = i - 1 { // TODO: reverse iteration would be a bit faster. - #| let mut x = self.limbs[i] - #| let digits = FixedArray::make(digits_per_limb, '0') - #| let mut idx = 0 - #| while x > 0 { - #| let y = x % 16 - #| x /= 16 - #| digits[idx] = if y < 10 { - #| (y.reinterpret_as_int() + '0'.to_int()).unsafe_to_char() - #| } else if uppercase { - #| (y.reinterpret_as_int() - 10 + 'A'.to_int()).unsafe_to_char() - #| } else { - #| (y.reinterpret_as_int() - 10 + 'a'.to_int()).unsafe_to_char() - #| } - #| idx += 1 - #| } - #| if i != self.len - 1 { - #| idx = digits_per_limb - #| } - #| for j in 0.. BigInt { - #| let new_limbs = FixedArray::make(self.len, 0U) - #| new_limbs.unsafe_blit(0, self.limbs, 0, self.len) - #| { limbs: new_limbs, sign: self.sign, len: self.len } - #|} - #|fn[T : Compare] max(a : T, b : T) -> T { - #| if a > b { - #| a - #| } else { - #| b - #| } - #|} - #|pub fn BigInt::pow(self : BigInt, exp : BigInt, modulus? : BigInt) -> BigInt { - #| if exp.sign == Negative { - #| abort("negative exponent") - #| } - #| match modulus { - #| None => { - #| let mut result = 1N - #| let mut base = self - #| let mut exp = exp - #| while exp > 0 { - #| if exp % 2 == 1 { - #| result = result * base - #| } - #| base = base * base - #| exp = exp / 2 - #| } - #| result - #| } - #| Some(modulus) => { - #| guard !(modulus.is_zero() || modulus.sign == Negative) - #| let mut result = 1N - #| let mut base = self - #| let mut exp = exp - #| while exp > 0 { - #| if exp % 2 == 1 { - #| result = result * base % modulus - #| } - #| base = base * base % modulus - #| exp = exp / 2 - #| } - #| result - #| } - #| } - #|} - #|pub fn BigInt::from_octets(input : Bytes, signum? : Int = 1) -> BigInt { - #| let len = input.length() // number of bytes - #| if signum == 0 { - #| return zero - #| } else if signum < 0 { - #| return -BigInt::from_octets(input) - #| } - #| if len == 0 { - #| abort("empty octet string") - #| } - #| let div = len * 8 / radix_bit_len - #| let mod = len * 8 % radix_bit_len // number of bits in the first limb - #| let limbs_len = if mod == 0 { div } else { div + 1 } - #| let limbs = FixedArray::make(limbs_len, 0U) - #| for i in 0..<(mod / 8) { - #| limbs[limbs_len - 1] = (limbs[limbs_len - 1] << 8) | input[i].to_uint() - #| } - #| let byte_per_limb = radix_bit_len / 8 - #| for i in 0..
Bytes { - #| let length = match length { - #| None => 1 - #| Some(l) => if l <= 0 { abort("negative length") } else { l } - #| } - #| if self.is_zero() { - #| return Bytes::new(max(1, length)) - #| } - #| if self.sign == Negative { - #| abort("negative BigInt") - #| } - #| let head_bits = 32 - self.limbs[self.len - 1].reinterpret_as_int().clz() - #| let tail_len = self.len - 1 - #| let len = (head_bits + 7) / 8 + tail_len * (radix_bit_len / 8) - #| let len = max(length, len) - #| let result = FixedArray::make(len, Byte::default()) - #| for i = 0; i < len && i / 4 < self.len; i = i + 1 { - #| result[len - 1 - i] = ((self.limbs[i / 4] >> (i % 4 * 8)) & 0xffU) - #| .reinterpret_as_int() - #| .to_byte() - #| } - #| unsafe_fixedarray_to_bytes(result) - #|} - #|pub impl BitAnd for BigInt with land(self : BigInt, other : BigInt) -> BigInt { - #| let max_length = if self.limbs.length() < other.limbs.length() { - #| other.limbs.length() + 1 - #| } else { - #| self.limbs.length() + 1 - #| } - #| let x_limbs = FixedArray::make(max_length, 0U) - #| x_limbs..unsafe_blit(0, self.limbs, 0, self.limbs.length()) - #| let y_limbs = FixedArray::make(max_length, 0U) - #| y_limbs..unsafe_blit(0, other.limbs, 0, other.limbs.length()) - #| if self.sign == Negative { - #| for i in 0.. other.len { - #| self.len - #| } else { - #| other.len - #| }, - #| } - #|} - #|pub impl BitOr for BigInt with lor(self : BigInt, other : BigInt) -> BigInt { - #| let max_length = if self.limbs.length() < other.limbs.length() { - #| other.limbs.length() + 1 - #| } else { - #| self.limbs.length() + 1 - #| } - #| let x_limbs = FixedArray::make(max_length, 0U) - #| x_limbs.unsafe_blit(0, self.limbs, 0, self.limbs.length()) - #| let y_limbs = FixedArray::make(max_length, 0U) - #| y_limbs.unsafe_blit(0, other.limbs, 0, other.limbs.length()) - #| if self.sign == Negative { - #| for i in 0.. other.len { - #| self.len - #| } else { - #| other.len - #| }, - #| } - #|} - #|pub impl BitXOr for BigInt with lxor(self : BigInt, other : BigInt) -> BigInt { - #| let max_length = if self.limbs.length() < other.limbs.length() { - #| other.limbs.length() + 1 - #| } else { - #| self.limbs.length() + 1 - #| } - #| let x_limbs = FixedArray::make(max_length, 0U) - #| x_limbs..unsafe_blit(0, self.limbs, 0, self.limbs.length()) - #| let y_limbs = FixedArray::make(max_length, 0U) - #| y_limbs..unsafe_blit(0, other.limbs, 0, other.limbs.length()) - #| if self.sign == Negative { - #| for i in 0.. other.len { - #| self.len - #| } else { - #| other.len - #| }, - #| } - #|} - #|pub fn BigInt::to_int(self : BigInt) -> Int { - #| self.to_uint().reinterpret_as_int() - #|} - #|pub fn BigInt::to_uint(self : BigInt) -> UInt { - #| let value = if self.sign == Negative { (1N << 32) + self } else { self } - #| value.limbs[0] - #|} - #|pub fn BigInt::to_int64(self : BigInt) -> Int64 { - #| self.to_uint64().reinterpret_as_int64() - #|} - #|pub fn BigInt::to_uint64(self : BigInt) -> UInt64 { - #| let value = if self.sign == Negative { (1N << 64) + self } else { self } - #| let len = 64 / radix_bit_len - #| let len = if value.len < len { value.len } else { len } - #| let mut result = 0UL - #| for i = len - 1; i >= 0; i = i - 1 { - #| result = result << radix_bit_len - #| result = result | (value.limbs[i].to_uint64() & radix_mask) - #| } - #| result - #|} - #|pub fn BigInt::bit_length(self : BigInt) -> Int { - #| if self.len == 0 { - #| return 0 - #| } - #| let mut bit_length = (self.len - 1) * radix_bit_len + - #| (radix_bit_len - self.limbs[self.len - 1].clz()) - #| if self.sign == Negative { - #| let mut pow2 = self.limbs[0].popcnt() == 1 - #| for i = 1; i < self.len && pow2; i = i + 1 { - #| pow2 = self.limbs[i] == 0 - #| } - #| if pow2 { - #| bit_length -= 1 - #| } - #| } - #| bit_length - #|} - #|pub fn BigInt::ctz(self : BigInt) -> Int { - #| if self.is_zero() { - #| return 0 - #| } - #| let mut i = 0 - #| while i < self.len && self.limbs[i] == 0 { - #| i = i + 1 - #| } - #| radix_bit_len * i + self.limbs[i].ctz() - #|} - #|fn unchecked_double_to_int(d : Double) -> Int = "%f64_to_i32" - #|fn unsafe_fixedarray_to_bytes(arr : FixedArray[Byte]) -> Bytes = "%identity" - #|fn can_convert_to_int(x : BigInt) -> Bool { - #| x.len == 1 && - #| (if x.sign == Negative { - #| x.limbs[0] <= 0x80000000 - #| } else { - #| x.limbs[0] < 0x80000000 - #| }) - #|} - #|fn can_convert_to_int64(x : BigInt) -> Bool { - #| x.len <= 2 && - #| (if x.sign == Negative { - #| x.limbs[1] < 0x80000000 || (x.limbs[1] == 0x80000000 && x.limbs[0] == 0) - #| } else { - #| x.limbs[1] < 0x80000000 - #| }) - #|} - #|fn is_neg(x : BigInt) -> Bool { - #| x.sign == Negative - #|} - #|test "limb length" { - #| inspect(0N.len, content="1") - #| inspect(1N.len, content="1") - #| inspect((-1N).len, content="1") - #| inspect(2147483647N.len, content="1") // Int.max_value - #| inspect((-2147483648N).len, content="1") // Int.min_value - #| inspect(2147483648N.len, content="1") // Int.max_value + 1 - #| inspect((-2147483649N).len, content="1") // Int.min_value - 1 - #| inspect(4294967295N.len, content="1") // 2^32 - 1 - #| inspect((-4294967295N).len, content="1") // -(2^32 - 1) - #| inspect(4294967296N.len, content="2") // 2^32 - #| inspect((-4294967296N).len, content="2") // -2^32 - #|} - #|fn BigInt::limbs(self : Self) -> Array[UInt] { - #| self.limbs[:self.len].to_array() - #|} - ), - "deprecated.mbt": ( - #|#deprecated("Use infix bitwise operator `>>` instead") - #|#coverage.skip - #|pub fn BigInt::asr(self : BigInt, n : Int) -> BigInt { - #| self >> n - #|} - #|#deprecated("Use infix bitwise operator `<<` instead") - #|#coverage.skip - #|pub fn BigInt::shl(self : BigInt, n : Int) -> BigInt { - #| self << n - #|} - #|#deprecated("Use infix bitwise operator `<<` instead") - #|#coverage.skip - #|pub fn BigInt::lsl(self : BigInt, n : Int) -> BigInt { - #| self << n - #|} - #|#deprecated("Use infix bitwise operator `>>` instead") - #|#coverage.skip - #|pub fn BigInt::shr(self : BigInt, n : Int) -> BigInt { - #| self >> n - #|} - ), - }, -) - -///| -let moonbitlang_core_bool_module : RuntimePackage = RuntimePackage::new( - "moonbitlang/core/bool", - deps={ "moonbitlang/core/builtin": moonbitlang_core_builtin_module }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": ["moonbitlang/core/builtin"], - #| "test-import": [ "moonbitlang/core/char", "moonbitlang/core/int16" ] - #|} - ), - }, + "bigint.mbt": ( + #|pub impl ToJson for BigInt with to_json(self : BigInt) -> Json { + #| Json::string(self.to_string()) + #|} + #|pub impl @json.FromJson for BigInt with from_json(json, path) { + #| guard json is String(s) else { + #| raise @json.JsonDecodeError( + #| (path, "BigInt::from_json: expected number in string representation"), + #| ) + #| } + #| BigInt::from_string(s) + #|} + #|pub impl @quickcheck.Arbitrary for BigInt with arbitrary(size, rs) { + #| if size == 0 { + #| 0 + #| } else { + #| rs.next_int64() |> BigInt::from_int64 + #| } + #|} + #|pub impl Default for BigInt with default() { + #| zero + #|} + #|pub fn BigInt::equal_int(self : BigInt, other : Int) -> Bool { + #| can_convert_to_int(self) && self.to_int() == other + #|} + #|pub fn BigInt::equal_int64(self : BigInt, other : Int64) -> Bool { + #| can_convert_to_int64(self) && self.to_int64() == other + #|} + #|pub fn BigInt::equal_uint(self : BigInt, other : UInt) -> Bool { + #| if is_neg(self) || self.bit_length() > 32 { + #| false + #| } else { + #| self.to_uint() == other + #| } + #|} + #|pub fn BigInt::equal_uint64(self : BigInt, other : UInt64) -> Bool { + #| if is_neg(self) || self.bit_length() > 64 { + #| false + #| } else { + #| self.to_uint64() == other + #| } + #|} + #|pub fn BigInt::compare_int(self : BigInt, other : Int) -> Int { + #| guard can_convert_to_int(self) else { + #| return if is_neg(self) { -1 } else { 1 } + #| } + #| let self = self.to_int() + #| Int::compare(self, other) + #|} + #|pub fn BigInt::compare_int64(self : BigInt, other : Int64) -> Int { + #| guard can_convert_to_int64(self) else { + #| return if is_neg(self) { -1 } else { 1 } + #| } + #| let self = self.to_int64() + #| Int64::compare(self, other) + #|} + #|pub fn BigInt::compare_uint(self : BigInt, other : UInt) -> Int { + #| if is_neg(self) { + #| -1 + #| } else if self.bit_length() > 32 { + #| 1 + #| } else { + #| UInt::compare(self.to_uint(), other) + #| } + #|} + #|pub fn BigInt::compare_uint64(self : BigInt, other : UInt64) -> Int { + #| if is_neg(self) { + #| -1 + #| } else if self.bit_length() > 64 { + #| 1 + #| } else { + #| UInt64::compare(self.to_uint64(), other) + #| } + #|} + #|test "can_convert_to_int" { + #| assert_true(can_convert_to_int(0N)) + #| assert_true(can_convert_to_int(1N)) + #| assert_true(can_convert_to_int(-1N)) + #| assert_true(can_convert_to_int(2147483647N)) // Int.max_value + #| assert_true(can_convert_to_int(-2147483648N)) // Int.min_value + #| assert_false(can_convert_to_int(2147483648N)) // Int.max_value + 1 + #| assert_false(can_convert_to_int(-2147483649N)) // Int.min_value - 1 + #| assert_false(can_convert_to_int(4294967295N)) // 2^32 - 1 + #| assert_false(can_convert_to_int(-4294967295N)) // -(2^32 - 1) + #| assert_false(can_convert_to_int(4294967296N)) // 2^32 + #| assert_false(can_convert_to_int(-4294967296N)) // -2^32 + #|} + #|test "can_convert_to_int64" { + #| assert_true(can_convert_to_int64(0N)) + #| assert_true(can_convert_to_int64(1N)) + #| assert_true(can_convert_to_int64(-1N)) + #| assert_true(can_convert_to_int64(2147483647N)) // Int.max_value + #| assert_true(can_convert_to_int64(-2147483648N)) // Int.min_value + #| assert_true(can_convert_to_int64(2147483648N)) // Int.max_value + 1 + #| assert_true(can_convert_to_int64(-2147483649N)) // Int.min_value - 1 + #| assert_true(can_convert_to_int64(4294967295N)) // 2^32 - 1 + #| assert_true(can_convert_to_int64(-4294967295N)) // -(2^32 - 1) + #| assert_true(can_convert_to_int64(4294967296N)) // 2^32 + #| assert_true(can_convert_to_int64(-4294967296N)) // -2^32 + #| assert_true(can_convert_to_int64(9223372036854775807N)) // Int64.max_value + #| assert_true(can_convert_to_int64(-9223372036854775808N)) // Int64.min_value + #| assert_false(can_convert_to_int64(9223372036854775808N)) // Int64.max_value + 1 + #| assert_false(can_convert_to_int64(-9223372036854775809N)) // Int64.min_value - 1 + #| assert_false(can_convert_to_int64(18446744073709551615N)) // 2^64 - 1 + #| assert_false(can_convert_to_int64(-18446744073709551615N)) // -(2^64 - 1) + #| assert_false(can_convert_to_int64(18446744073709551616N)) // 2^64 + #| assert_false(can_convert_to_int64(-18446744073709551616N)) // -2^64 + #|} + #|pub impl Hash for BigInt with hash_combine(self, hasher) { + #| hasher.combine(self.signum()) + #| for limb in self.limbs() { + #| hasher.combine(limb) + #| } + #|} + #|fn BigInt::signum(self : Self) -> Int { + #| if self.is_zero() { + #| 0 + #| } else if is_neg(self) { + #| -1 + #| } else { + #| 1 + #| } + #|} + #|pub fn BigInt::to_uint16(self : BigInt) -> UInt16 { + #| self.to_int().to_uint16() + #|} + #|pub fn BigInt::to_int16(self : BigInt) -> Int16 { + #| Int16::from_int(self.to_int()) + #|} + ), + "bigint_js.mbt": ( + #|type BigInt + #|let zero = 0N + #|pub fn BigInt::from_string(str : String, radix? : Int = 10) -> BigInt { + #| if str.length() == 0 { + #| abort("empty string") + #| } + #| if radix < 2 || radix > 36 { + #| abort("radix must be between 2 and 36") + #| } + #| if radix != 10 { + #| return BigInt::from_string_radix(str, radix) + #| } + #| if str == "-" { + #| abort("invalid character") + #| } + #| BigInt::js_from_string(str) + #|} + #|extern "js" fn BigInt::js_from_string(str : String) -> BigInt = + #| #|(x) => BigInt(x) + #|fn digit_from_char(x : Int) -> Int { + #| match x { + #| '0'..='9' => x - '0' + #| 'A'..='Z' => x + (10 - 'A') + #| 'a'..='z' => x + (10 - 'a') + #| _ => -1 + #| } + #|} + #|fn pow2_shift(radix : Int) -> Int? { + #| if radix >= 2 && (radix & (radix - 1)) == 0 { + #| Some(radix.ctz()) + #| } else { + #| None + #| } + #|} + #|fn BigInt::from_string_radix(str : String, radix : Int) -> BigInt { + #| let len = str.length() + #| let sign = if str.unsafe_get(0) == '-' { -1 } else { 1 } + #| let start = if sign == -1 { 1 } else { 0 } + #| if start == len { + #| abort("invalid character") + #| } + #| let mut acc = 0N + #| match pow2_shift(radix) { + #| Some(shift) => + #| for i in start..= radix { + #| abort("invalid character") + #| } + #| acc = (acc << shift) | BigInt::from_int(digit) + #| } + #| None => { + #| let base = BigInt::from_int(radix) + #| for i in start..= radix { + #| abort("invalid character") + #| } + #| acc = acc * base + BigInt::from_int(digit) + #| } + #| } + #| } + #| if sign == -1 { + #| -acc + #| } else { + #| acc + #| } + #|} + #|pub impl Show for BigInt with output(self, logger) { + #| logger.write_string(self.to_string()) + #|} + #|pub fn BigInt::to_string(self : BigInt, radix? : Int = 10) -> String { + #| if radix < 2 || radix > 36 { + #| abort("radix must be between 2 and 36") + #| } + #| BigInt::js_to_string_radix(self, radix) + #|} + #|extern "js" fn BigInt::js_to_string_radix(self : BigInt, radix : Int) -> String = + #| #|(x, radix) => x.toString(radix) + #|extern "js" fn hex2(b : Byte) -> String = + #| #|(x) => x.toString(16).padStart(2, '0') + #|pub fn BigInt::from_octets(octets : Bytes, signum? : Int = 1) -> BigInt { + #| if signum < 0 { + #| return -1N * BigInt::from_octets(octets, signum=1) + #| } + #| if signum == 0 { + #| return 0N + #| } + #| let str = StringBuilder::new() + #| str.write_string("0x") + #| for octet in octets { + #| str.write_string(hex2(octet)) + #| } + #| BigInt::from_string(str.to_string()) + #|} + #|pub fn BigInt::to_octets(self : BigInt, length? : Int) -> Bytes { + #| if self < 0 { + #| abort("negative BigInt") + #| } + #| if self == 0 { + #| return match length { + #| Some(len) => Bytes::make(len, 0) + #| None => [0] + #| } + #| } + #| let buf = [] + #| loop self { + #| v => + #| if v > 0 { + #| buf.push(v.to_byte()) + #| continue v >> 8 + #| } + #| } + #| let buf_len = buf.length() + #| match length { + #| Some(len) => { + #| if len <= 0 { + #| abort("negative length") + #| } + #| if len > buf_len { + #| Bytes::makei(len, i => { + #| let padding = len - buf_len + #| if i < padding { + #| 0 + #| } else { + #| buf[buf_len - (i - padding) - 1] + #| } + #| }) + #| } else { + #| Bytes::makei(buf_len, i => buf[buf_len - i - 1]) + #| } + #| } + #| None => Bytes::makei(buf_len, i => buf[buf_len - i - 1]) + #| } + #|} + #|extern "js" fn BigInt::compare(self : BigInt, other : BigInt) -> Int = + #| #|(x, y) => x < y ? -1 : x > y ? 1 : 0 + #|pub impl Compare for BigInt with compare(self, other) { + #| self.compare(other) + #|} + #|extern "js" fn BigInt::equal(self : BigInt, other : BigInt) -> Bool = + #| #|(x, y) => x === y + #|pub impl Eq for BigInt with equal(self, other) { + #| self.equal(other) + #|} + #|pub extern "js" fn BigInt::from_int(x : Int) -> BigInt = + #| #|(x) => BigInt(x) + #|pub extern "js" fn BigInt::from_uint(x : UInt) -> BigInt = + #| #|(x) => BigInt(x >>> 0) + #|pub extern "js" fn BigInt::from_int64(x : Int64) -> BigInt = + #| #|(x) => BigInt(x.hi) * 0x100000000n + BigInt(x.lo >>> 0) + #|pub extern "js" fn BigInt::from_uint64(x : UInt64) -> BigInt = + #| #|(x) => BigInt(x.hi >>> 0) * 0x100000000n + BigInt(x.lo >>> 0) + #|pub extern "js" fn BigInt::is_zero(self : BigInt) -> Bool = + #| #|(x) => x === 0n + #|extern "js" fn BigInt::op_neg_ffi(self : BigInt) -> BigInt = + #| #|(x) => -x + #|pub impl Neg for BigInt with neg(self) { + #| self.op_neg_ffi() + #|} + #|extern "js" fn BigInt::op_add_ffi(self : BigInt, other : BigInt) -> BigInt = + #| #|(x, y) => x + y + #|pub impl Add for BigInt with add(self, other) { + #| self.op_add_ffi(other) + #|} + #|extern "js" fn BigInt::op_sub_ffi(self : BigInt, other : BigInt) -> BigInt = + #| #|(x, y) => x - y + #|pub impl Sub for BigInt with sub(self, other) { + #| self.op_sub_ffi(other) + #|} + #|extern "js" fn BigInt::op_mul_ffi(self : BigInt, other : BigInt) -> BigInt = + #| #|(x, y) => x * y + #|pub impl Mul for BigInt with mul(self, other) { + #| self.op_mul_ffi(other) + #|} + #|extern "js" fn BigInt::op_div_ffi(self : BigInt, other : BigInt) -> BigInt = + #| #|(x, y) => x / y + #|pub impl Div for BigInt with div(self, other) { + #| self.op_div_ffi(other) + #|} + #|extern "js" fn BigInt::op_mod_ffi(self : BigInt, other : BigInt) -> BigInt = + #| #|(x, y) => x % y + #|pub impl Mod for BigInt with mod(self, other) { + #| self.op_mod_ffi(other) + #|} + #|extern "js" fn BigInt::modpow_ffi( + #| self : BigInt, + #| exponent : BigInt, + #| modulus : BigInt, + #|) -> BigInt = + #| #|(x, y, z) => { + #| #| if (z === 1n) return 0n; + #| #| let result = 1n; + #| #| x = x % z; + #| #| while (y > 0n) { + #| #| if (y & 1n) { + #| #| result = (result * x) % z; + #| #| } + #| #| y >>= 1n; + #| #| x = (x * x) % z; + #| #| } + #| #| return result; + #| #|} + #|extern "js" fn BigInt::pow_ffi(self : BigInt, exponent : BigInt) -> BigInt = + #| #|(x, y) => x ** y + #|pub fn BigInt::pow( + #| self : BigInt, + #| exponent : BigInt, + #| modulus? : BigInt, + #|) -> BigInt { + #| if exponent < 0 { + #| abort("negative exponent") + #| } + #| match modulus { + #| Some(modulus) => + #| if modulus <= 0 { + #| abort("non-positive modulus") + #| } else { + #| self.modpow_ffi(exponent, modulus) + #| } + #| None => self.pow_ffi(exponent) + #| } + #|} + #|extern "js" fn BigInt::to_byte(self : BigInt) -> Byte = + #| #|(x) => Number(BigInt.asUintN(8, x)) | 0 + #|pub impl Shl for BigInt with shl(self : BigInt, n : Int) -> BigInt { + #| if n < 0 { + #| abort("negative shift count") + #| } + #| self.js_shl(n) + #|} + #|pub impl Shr for BigInt with shr(self : BigInt, n : Int) -> BigInt { + #| if n < 0 { + #| abort("negative shift count") + #| } + #| self.js_shr(n) + #|} + #|extern "js" fn BigInt::js_shl(self : BigInt, other : Int) -> BigInt = + #| #|(x, y) => x << BigInt(y) + #|extern "js" fn BigInt::js_shr(self : BigInt, other : Int) -> BigInt = + #| #|(x, y) => x >> BigInt(y) + #|extern "js" fn BigInt::js_land(self : BigInt, other : BigInt) -> BigInt = + #| #|(x, y) => x & y + #|pub impl BitAnd for BigInt with land(self, other) { + #| self.js_land(other) + #|} + #|extern "js" fn BigInt::js_lor(self : BigInt, other : BigInt) -> BigInt = + #| #|(x, y) => x | y + #|pub impl BitOr for BigInt with lor(self, other) { + #| self.js_lor(other) + #|} + #|extern "js" fn BigInt::js_lxor(self : BigInt, other : BigInt) -> BigInt = + #| #|(x, y) => x ^ y + #|pub impl BitXOr for BigInt with lxor(self, other) { + #| self.js_lxor(other) + #|} + #|pub extern "js" fn BigInt::to_uint(self : BigInt) -> UInt = + #| #|(x) => Number(BigInt.asUintN(32, x)) | 0 + #|pub extern "js" fn BigInt::to_int(self : BigInt) -> Int = + #| #|(x) => Number(BigInt.asIntN(32, x)) + #|pub fn BigInt::to_uint64(self : BigInt) -> UInt64 { + #| let hi = (self >> 32).to_uint() + #| let lo = self.to_uint() + #| (hi.to_uint64() << 32) | lo.to_uint64() + #|} + #|pub fn BigInt::to_int64(self : BigInt) -> Int64 { + #| let hi = (self >> 32).to_uint() + #| let lo = self.to_uint() + #| (hi.to_int64() << 32) | lo.to_int64() + #|} + #|pub extern "js" fn BigInt::bit_length(self : BigInt) -> Int = + #| #|(n) => { + #| #| if (n >= 0) { + #| #| return n === 0n ? 0 : n.toString(2).length; + #| #| } else { + #| #| const absN = -n; + #| #| const absMinus1 = absN - 1n; + #| #| return absMinus1 === 0n ? 0 : absMinus1.toString(2).length; + #| #| } + #| #|} + #|pub extern "js" fn BigInt::ctz(self : BigInt) -> Int = + #| #|(n) => { + #| #| if (n === 0n) return 0; + #| #| let absN = n < 0n ? -n : n; + #| #| let count = 0; + #| #| while ((absN & 1n) === 0n) { + #| #| absN >>= 1n; + #| #| count++; + #| #| } + #| #| return count; + #| #|} + #|extern "js" fn can_convert_to_int(x : BigInt) -> Bool = + #| #|(x) => x >= -(2n ** 31n) && x < 2n ** 31n + #|extern "js" fn can_convert_to_int64(x : BigInt) -> Bool = + #| #|(x) => x >= -(2n ** 63n) && x < 2n ** 63n + #|extern "js" fn is_neg(x : BigInt) -> Bool = + #| #|(x) => x < 0n + #|fn BigInt::limbs(self : Self) -> Array[UInt] { + #| guard !self.is_zero() else { [0] } + #| let result = [] + #| for n = self * BigInt::from_int(self.signum()); n > 0; n = n >> 32 { + #| let limb = n.to_uint() + #| result.push(limb) + #| } + #| result + #|} + ), + "bigint_nonjs.mbt": ( + #|#valtype + #|struct BigInt { + #| limbs : FixedArray[UInt] // Note: do not use limbs.length(), use len instead because of leading zeros + #| sign : Sign + #| len : Int + #|} + #|priv enum Sign { + #| Positive + #| Negative + #|} derive(Eq) + #|let radix_bit_len = 32 + #|let radix : UInt64 = 1UL << radix_bit_len // TODO: This can be generalized once we have const generics + #|let radix_mask : UInt64 = radix - 1 + #|let decimal_ratio = 0.302 // log10(2) + #|let karatsuba_threshold = 50 + #|let zero : BigInt = 0N + #|let one : BigInt = 1N + #|pub fn BigInt::from_int(n : Int) -> BigInt { + #| BigInt::from_int64(n.to_int64()) + #|} + #|pub fn BigInt::from_uint(n : UInt) -> BigInt { + #| BigInt::from_uint64(n.to_uint64()) + #|} + #|pub fn BigInt::from_int64(n : Int64) -> BigInt { + #| if n < 0L { + #| -BigInt::from_uint64((-n).reinterpret_as_uint64()) + #| } else { + #| BigInt::from_uint64(n.reinterpret_as_uint64()) + #| } + #|} + #|pub fn BigInt::from_uint64(n : UInt64) -> BigInt { + #| if n == 0UL { + #| return { limbs: FixedArray::make(1, 0), sign: Positive, len: 1 } + #| } + #| let limbs = FixedArray::make(64 / radix_bit_len, 0U) + #| let i = for m = n, i = 0; m > 0; { + #| limbs[i] = (m % radix).to_uint() + #| continue m / radix, i + 1 + #| } nobreak { + #| i + #| } + #| { limbs, sign: Positive, len: i } + #|} + #|pub impl Neg for BigInt with neg(self : BigInt) -> BigInt { + #| if self.is_zero() { + #| return zero + #| } + #| { ..self, sign: if self.sign == Positive { Negative } else { Positive } } + #|} + #|pub impl Add for BigInt with add(self : BigInt, other : BigInt) -> BigInt { + #| if self.sign == Negative { + #| if other.sign == Negative { + #| return -(-other + -self) + #| } else { + #| return other - -self + #| } + #| } else if other.sign == Negative { + #| return self - -other + #| } + #| let self_len = self.len + #| let other_len = other.len + #| let limbs = FixedArray::make(1 + max(self_len, other_len), 0U) + #| let i = for carry = 0UL, i = 0; i < self_len || i < other_len || carry != 0; { + #| let a = if i < self_len { self.limbs[i].to_uint64() } else { 0 } + #| let b = if i < other_len { other.limbs[i].to_uint64() } else { 0 } + #| let sum = a + b + carry + #| limbs[i] = (sum % radix).to_uint() + #| continue sum / radix, i + 1 + #| } nobreak { + #| i + #| } + #| { limbs, sign: Positive, len: i } + #|} + #|pub impl Sub for BigInt with sub(self : BigInt, other : BigInt) -> BigInt { + #| if self.sign == Negative { + #| if other.sign == Negative { + #| return -other - -self + #| } else { + #| return -(other + -self) + #| } + #| } else if other.sign == Negative { + #| return self + -other + #| } + #| if self < other { + #| return -(other - self) + #| } + #| let self_len = self.len + #| let other_len = other.len + #| let limbs = FixedArray::make(max(self_len, other_len), 0U) + #| let i = for borrow = 0L, i = 0; i < self_len || i < other_len || borrow != 0L; { + #| let a = if i < self_len { self.limbs[i].to_int64() } else { 0 } + #| let b = if i < other_len { other.limbs[i].to_int64() } else { 0 } + #| let diff = a - b - borrow // 0 <= a < radix, 0 <= b < radix, 0 <= borrow <= 1 => -radix <= diff < radix + #| if diff < 0L { + #| limbs[i] = (diff + radix.reinterpret_as_int64()) + #| .reinterpret_as_uint64() + #| .to_uint() // -radix <= diff < 0, so we don't need to mod by radix + #| continue 1L, i + 1 + #| } else { + #| limbs[i] = diff.reinterpret_as_uint64().to_uint() // 0 <= diff < radix, so we don't need to mod by radix + #| continue 0L, i + 1 + #| } + #| } nobreak { + #| i + #| } + #| let i = for i = i; i > 1 && limbs[i - 1] == 0; { + #| continue i - 1 + #| } nobreak { + #| i + #| } + #| { limbs, sign: Positive, len: i } + #|} + #|pub impl Mul for BigInt with mul(self : BigInt, other : BigInt) -> BigInt { + #| if self.is_zero() || other.is_zero() { + #| return zero + #| } + #| let ret = if self.len < karatsuba_threshold || other.len < karatsuba_threshold { + #| self.grade_school_mul(other) + #| } else { + #| self.karatsuba_mul(other) + #| } + #| { ..ret, sign: if self.sign == other.sign { Positive } else { Negative } } + #|} + #|fn BigInt::grade_school_mul(self : BigInt, other : BigInt) -> BigInt { + #| let self_len = self.len + #| let other_len = other.len + #| let mut len = self_len + other_len + #| let limbs = FixedArray::make(len, 0U) + #| for i in 0.. BigInt { + #| let half = (max(self.len, other.len) + 1) / 2 + #| let (xl, xh) = self.split(half) + #| let (yl, yh) = other.split(half) + #| let p1 = xh * yh + #| let p2 = xl * yl + #| let p3 = (xh + xl) * (yh + yl) + #| (p1 << (radix_bit_len * 2 * half)) + + #| ((p3 - p1 - p2) << (radix_bit_len * half)) + + #| p2 + #|} + #|fn BigInt::split(self : BigInt, half : Int) -> (BigInt, BigInt) { + #| if self.len <= half { + #| return ({ ..self, sign: Positive }, zero) + #| } + #| let lower_len = for i in half>..1 { + #| if self.limbs[i] > 0 { + #| break i + 1 + #| } + #| } nobreak { + #| 1 + #| } + #| let lower = FixedArray::make(lower_len, 0U) + #| lower.unsafe_blit(0, self.limbs, 0, lower_len) + #| let upper = FixedArray::make(self.len - half, 0U) + #| upper.unsafe_blit(0, self.limbs, half, self.len - half) + #| ( + #| { limbs: lower, sign: Positive, len: lower_len }, + #| { limbs: upper, sign: Positive, len: self.len - half }, + #| ) + #|} + #|pub impl Div for BigInt with div(self : BigInt, other : BigInt) -> BigInt { + #| if other is 0 { + #| abort("division by zero") + #| } + #| if self.sign == Negative { + #| if other.sign == Negative { + #| BigInt::grade_school_div(-self, -other).0 + #| } else { + #| -BigInt::grade_school_div(-self, other).0 + #| } + #| } else if other.sign == Negative { + #| -BigInt::grade_school_div(self, -other).0 + #| } else { + #| return BigInt::grade_school_div(self, other).0 + #| } + #|} + #|pub impl Mod for BigInt with mod(self : BigInt, other : BigInt) -> BigInt { + #| if other == zero { + #| abort("division by zero") + #| } + #| if self.sign == Negative { + #| if other.sign == Negative { + #| -BigInt::grade_school_div(-self, -other).1 + #| } else { + #| -BigInt::grade_school_div(-self, other).1 + #| } + #| } else if other.sign == Negative { + #| BigInt::grade_school_div(self, -other).1 + #| } else { + #| BigInt::grade_school_div(self, other).1 + #| } + #|} + #|fn BigInt::grade_school_div(self : BigInt, other : BigInt) -> (BigInt, BigInt) { + #| if self < other { + #| return (zero, self) + #| } else if self == other { + #| return (one, zero) + #| } + #| if other.len == 1 { + #| let number = other.limbs[0] + #| let ret = self.copy() + #| if number == 1 { + #| return (ret, zero) + #| } + #| let a = ret.limbs + #| let x = number.to_uint64() + #| let y = for i in self.len>..0; y = 0UL { + #| let y = y << radix_bit_len + #| let y = y + a[i].to_uint64() + #| a[i] = ((y / x) & radix_mask).to_uint() + #| continue y % x + #| } nobreak { + #| y + #| } + #| if ret.limbs[ret.len - 1] == 0 { + #| return ( + #| { ..ret, len: ret.len - 1 }, + #| { limbs: FixedArray::make(1, y.to_uint()), sign: Positive, len: 1 }, + #| ) + #| } + #| return ( + #| ret, + #| { limbs: FixedArray::make(1, y.to_uint()), sign: Positive, len: 1 }, + #| ) + #| } + #| let dividend = self + #| let divisor = other + #| let lshift = max( + #| 0, + #| radix_bit_len - (64 - divisor.limbs[divisor.len - 1].to_int64().clz()), + #| ) + #| let a_len = dividend.len + #| let dividend = dividend << lshift + #| let divisor = divisor << lshift + #| let b_len = divisor.len + #| let b = FixedArray::make(b_len, 0UL) + #| for i in 0.. a_len { + #| a[a_len] = dividend.limbs[a_len].to_uint64() + #| } + #| let a_len = a_len + 1 + #| let v1 = b[b_len - 1] + #| let v2 = b[b_len - 2] + #| let q = FixedArray::make(a_len - b_len, 0U) + #| for i in q.length()>..0 { + #| let u0 = a[i + b_len] + #| let u1 = a[i + b_len - 1] + #| let u2 = a[i + b_len - 2] + #| let mut qh = (u0 * radix + u1) / v1 + #| if qh * v2 > radix * (u0 * radix + u1 - qh * v1) + u2 { + #| qh -= 1 + #| } + #| let mut borrow = 0L + #| let mut carry = 0UL + #| for j in 0..> radix_bit_len + #| carry = carry >> radix_bit_len + #| } + #| borrow = borrow + a[i + b_len].reinterpret_as_int64() + #| borrow -= carry.reinterpret_as_int64() + #| a[i + b_len] = (borrow & radix_mask.reinterpret_as_int64()).reinterpret_as_uint64() + #| borrow = borrow >> radix_bit_len + #| if borrow < 0L { + #| carry = 0UL + #| for j in 0..> radix_bit_len + #| } + #| carry += a[i + b_len] + #| a[i + b_len] = carry & radix_mask + #| carry = carry >> radix_bit_len + #| borrow += carry.reinterpret_as_int64() + #| qh -= 1 + #| } + #| q[i] = qh.to_uint() + #| } + #| let len = if q[q.length() - 1] == 0 { q.length() - 1 } else { q.length() } + #| let mut i = a.length() - 1 + #| while i >= 0 && a[i] == 0 { + #| i -= 1 + #| } + #| if i < 0 { + #| i = 1 + #| } else { + #| i += 1 + #| } + #| let modulo = FixedArray::make(i, 0U) + #| for j in 0..> lshift) + #|} + #|pub impl Shl for BigInt with shl(self : BigInt, n : Int) -> BigInt { + #| if n < 0 { + #| abort("negative shift count") + #| } + #| if !self.is_zero() { + #| let new_limbs = FixedArray::make( + #| self.len + (n + radix_bit_len - 1) / radix_bit_len, // ceiling(n / radix_bit_len) + #| 0U, + #| ) + #| let a = self.limbs + #| let r = n % radix_bit_len + #| let lz = n / radix_bit_len // number of leading zeros + #| let mut len = self.len + lz + #| if r != 0 { + #| let carry = for i in 0..> radix_bit_len + #| } nobreak { + #| carry + #| } + #| if carry != 0 { + #| new_limbs[self.len + lz] = carry.to_uint() + #| len += 1 + #| } + #| } else { + #| new_limbs.unsafe_blit(lz, self.limbs, 0, self.len) + #| } + #| { limbs: new_limbs, sign: self.sign, len } + #| } else { + #| zero + #| } + #|} + #|pub impl Shr for BigInt with shr(self : BigInt, n : Int) -> BigInt { + #| if n < 0 { + #| abort("negative shift count") + #| } + #| let r = n % radix_bit_len + #| let lz = n / radix_bit_len + #| if lz >= self.len { + #| match self.sign { + #| Positive => return zero + #| Negative => + #| return { limbs: FixedArray::make(1, 1), sign: Negative, len: 1 } + #| } + #| } + #| let mut new_len = self.len - lz + #| if r == 0 { + #| let new_limbs = FixedArray::make(new_len, 0U) + #| new_limbs.unsafe_blit(0, self.limbs, lz, new_len) + #| { limbs: new_limbs, sign: self.sign, len: new_len } + #| } else { + #| let new_limbs = FixedArray::make(new_len, 0U) + #| let a = self.limbs + #| let carry = for i in self.len>..lz; carry = 0UL { + #| let x = a[i].to_uint64() + #| new_limbs[i - lz] = ((x >> r) | carry).to_uint() + #| continue (x << (radix_bit_len - r)) % radix + #| } nobreak { + #| carry + #| } + #| if new_len > 1 && new_limbs[new_len - 1] == 0 { + #| new_len -= 1 + #| } + #| if self.sign == Negative && (carry & (1UL << r)) != carry { + #| { limbs: new_limbs, sign: self.sign, len: new_len } - 1 + #| } else { + #| { limbs: new_limbs, sign: self.sign, len: new_len } + #| } + #| } + #|} + #|pub fn BigInt::is_zero(self : BigInt) -> Bool { + #| self.len == 1 && self.limbs[0] == 0 + #|} + #|pub impl Compare for BigInt with compare(self, other) { + #| if self.sign != other.sign { + #| return if self.sign == Positive { 1 } else { -1 } + #| } + #| let self_len = self.len + #| let other_len = other.len + #| if self_len != other_len { + #| return if self.sign == Positive { + #| self_len - other_len + #| } else { + #| other_len - self_len + #| } + #| } + #| for i in self_len>..0 { + #| if self.limbs[i] != other.limbs[i] { + #| return if self.sign == Positive { + #| self.limbs[i].compare(other.limbs[i]) + #| } else { + #| other.limbs[i].compare(self.limbs[i]) + #| } + #| } + #| } + #| 0 + #|} + #|pub impl Eq for BigInt with equal(self, other) { + #| if self.sign != other.sign || self.len != other.len { + #| return false + #| } + #| for i in 0.. String { + #| if radix < 2 || radix > 36 { + #| abort("radix must be between 2 and 36") + #| } + #| if radix != 10 { + #| return self.to_string_radix(radix) + #| } + #| if self.is_zero() { + #| return "0" + #| } + #| let decimal_radix_bit_len = 19 - 1 - (1 + radix_bit_len) / 3 // < len(9,223,372,036,854,775,807) - len(2^radix_bit_len). len means the number of digits in decimal. + #| let decimal_mask = 10_000_000L // 10^(decimal_radix_bit_len). TODO: compute it when we have power function. + #| let decimal_len = unchecked_double_to_int( + #| (self.len * radix_bit_len).to_double() * + #| decimal_ratio / + #| decimal_radix_bit_len.to_double() + + #| 1, + #| ) + #| let s = if self.sign == Negative { "-" } else { "" } + #| let v = Array::make(decimal_len, 0L) + #| let mut v_idx = 0 + #| for i in self.len>..0 { + #| let mut x = self.limbs[i].to_int64() + #| for j in 0.. 0L { + #| v[v_idx] = x % decimal_mask + #| v_idx += 1 + #| x /= decimal_mask + #| } + #| } + #| let mut ret = "" + #| for i in 0..<(v_idx - 1) { + #| for _ in 0.. 0L; { // v_idx is at least 1, we check is_zero() at the beginning. + #| let y = x % 10L + #| continue x / 10L, y.to_string() + ret + #| } nobreak { + #| ret + #| } + #| s + ret + #|} + #|pub impl Show for BigInt with output(self, logger) { + #| logger.write_string(self.to_string()) + #|} + #|fn digit_from_char(x : Int) -> Int { + #| match x { + #| '0'..='9' => x - '0' + #| 'A'..='Z' => x + (10 - 'A') + #| 'a'..='z' => x + (10 - 'a') + #| _ => -1 + #| } + #|} + #|fn char_from_digit(d : Int) -> Char { + #| if d < 10 { + #| (d + '0'.to_int()).unsafe_to_char() + #| } else { + #| (d - 10 + 'a'.to_int()).unsafe_to_char() + #| } + #|} + #|fn pow2_shift(radix : Int) -> Int? { + #| if radix >= 2 && (radix & (radix - 1)) == 0 { + #| Some(radix.ctz()) + #| } else { + #| None + #| } + #|} + #|fn BigInt::to_string_radix(self : BigInt, radix : Int) -> String { + #| if self.is_zero() { + #| return "0" + #| } + #| match pow2_shift(radix) { + #| Some(shift) => self.to_string_radix_pow2(shift) + #| None => { + #| let is_negative = self.sign == Negative + #| let base = BigInt::from_int(radix) + #| let value = if is_negative { -self } else { self } + #| let digits = [] + #| loop value { + #| v => + #| if v > zero { + #| let (q, r) = BigInt::grade_school_div(v, base) + #| digits.push(char_from_digit(r.to_int())) + #| continue q + #| } + #| } + #| let builder = StringBuilder::new( + #| size_hint=digits.length() + (if is_negative { 1 } else { 0 }), + #| ) + #| if is_negative { + #| builder.write_char('-') + #| } + #| for i in digits.length()>..0 { + #| builder.write_char(digits[i]) + #| } + #| builder.to_string() + #| } + #| } + #|} + #|fn BigInt::to_string_radix_pow2(self : BigInt, shift : Int) -> String { + #| let is_negative = self.sign == Negative + #| let value = if is_negative { -self } else { self } + #| let bit_len = value.bit_length() + #| let digit_len = (bit_len + shift - 1) / shift + #| let builder = StringBuilder::new( + #| size_hint=digit_len + (if is_negative { 1 } else { 0 }), + #| ) + #| if is_negative { + #| builder.write_char('-') + #| } + #| let mask = (1UL << shift) - 1UL + #| for pos in digit_len>..0 { + #| let bit_index = pos * shift + #| let limb_index = bit_index / radix_bit_len + #| let offset = bit_index % radix_bit_len + #| let mut chunk = value.limbs[limb_index].to_uint64() >> offset + #| if offset + shift > radix_bit_len && limb_index + 1 < value.len { + #| chunk = chunk | + #| (value.limbs[limb_index + 1].to_uint64() << (radix_bit_len - offset)) + #| } + #| let digit = (chunk & mask).to_int() + #| builder.write_char(char_from_digit(digit)) + #| } + #| builder.to_string() + #|} + #|fn BigInt::from_string_radix(input : String, radix : Int) -> BigInt { + #| match pow2_shift(radix) { + #| Some(shift) => BigInt::from_string_radix_pow2(input, radix, shift) + #| None => { + #| let len = input.length() + #| if len == 0 { + #| abort("empty string") + #| } + #| let sign : Sign = if input.unsafe_get(0) == '-' { + #| Negative + #| } else { + #| Positive + #| } + #| let start = if sign == Negative { 1 } else { 0 } + #| if start == len { + #| abort("invalid character") + #| } + #| let base = BigInt::from_int(radix) + #| let acc = for i in start..= radix { + #| abort("invalid character") + #| } + #| continue acc * base + BigInt::from_int(digit) + #| } nobreak { + #| acc + #| } + #| if sign == Negative { + #| -acc + #| } else { + #| acc + #| } + #| } + #| } + #|} + #|fn BigInt::from_string_radix_pow2( + #| input : String, + #| radix : Int, + #| shift : Int, + #|) -> BigInt { + #| let len = input.length() + #| if len == 0 { + #| abort("empty string") + #| } + #| let sign : Sign = if input.unsafe_get(0) == '-' { Negative } else { Positive } + #| let start = if sign == Negative { 1 } else { 0 } + #| if start == len { + #| abort("invalid character") + #| } + #| let mut first = start + #| while first < len { + #| let digit = digit_from_char(input.unsafe_get(first).to_int()) + #| if digit < 0 || digit >= radix { + #| abort("invalid character") + #| } + #| if digit != 0 { + #| break + #| } + #| first += 1 + #| } + #| if first == len { + #| return zero + #| } + #| let digits_count = len - first + #| let total_bits = digits_count * shift + #| let b_len = (total_bits + radix_bit_len - 1) / radix_bit_len + #| let limbs = FixedArray::make(b_len, 0U) + #| for i in len>..first; bit_pos = 0 { + #| let digit = digit_from_char(input.unsafe_get(i).to_int()) + #| if digit < 0 || digit >= radix { + #| abort("invalid character") + #| } + #| let limb_index = bit_pos / radix_bit_len + #| let offset = bit_pos % radix_bit_len + #| let val = digit.reinterpret_as_uint().to_uint64() + #| limbs[limb_index] = (limbs[limb_index].to_uint64() | (val << offset)).to_uint() + #| if offset + shift > radix_bit_len { + #| let hi = val >> (radix_bit_len - offset) + #| limbs[limb_index + 1] = (limbs[limb_index + 1].to_uint64() | hi).to_uint() + #| } + #| continue bit_pos + shift + #| } + #| let b_len = normalize_len(limbs, b_len) + #| let sign = if b_len == 1 && limbs[0] == 0 { Positive } else { sign } + #| { limbs, sign, len: b_len } + #|} + #|pub fn BigInt::from_string(input : String, radix? : Int = 10) -> BigInt { + #| if radix < 2 || radix > 36 { + #| abort("radix must be between 2 and 36") + #| } + #| if radix != 10 { + #| return BigInt::from_string_radix(input, radix) + #| } + #| BigInt::from_string_dec(input) + #|} + #|fn BigInt::from_string_dec(input : String) -> BigInt { + #| let len = input.length() + #| if len == 0 { + #| abort("empty string") + #| } + #| let sign : Sign = if input.unsafe_get(0) == '-' { Negative } else { Positive } + #| if sign == Negative && len == 1 { + #| abort("invalid character") + #| } + #| let mut b_len = ( + #| unchecked_double_to_int(len.to_double() / decimal_ratio) + + #| 1 + + #| radix_bit_len + #| ) / + #| radix_bit_len + + #| 1 + #| let b = FixedArray::make(b_len, 0U) + #| for + #| i in (match sign { + #| Negative => 1 + #| Positive => 0 + #| }).. 9 { + #| abort("invalid character") + #| } + #| let mut carry = x.reinterpret_as_uint().to_uint64() + #| for j in 0.. 1 { + #| b_len -= 1 + #| } + #| let sign = if b_len == 1 && b[0] == 0 { Positive } else { sign } + #| { limbs: b, sign, len: b_len } + #|} + #|fn BigInt::copy(self : BigInt) -> BigInt { + #| let new_limbs = FixedArray::make(self.len, 0U) + #| new_limbs.unsafe_blit(0, self.limbs, 0, self.len) + #| { limbs: new_limbs, sign: self.sign, len: self.len } + #|} + #|fn normalize_len(limbs : FixedArray[UInt], max_len : Int) -> Int { + #| let mut actual_len = max_len + #| while actual_len > 1 && limbs[actual_len - 1] == 0U { + #| actual_len -= 1 + #| } + #| actual_len + #|} + #|fn[T : Compare] max(a : T, b : T) -> T { + #| if a > b { + #| a + #| } else { + #| b + #| } + #|} + #|pub fn BigInt::pow(self : BigInt, exp : BigInt, modulus? : BigInt) -> BigInt { + #| if exp.sign == Negative { + #| abort("negative exponent") + #| } + #| match modulus { + #| None => { + #| let mut result = 1N + #| let mut base = self + #| let mut exp = exp + #| while exp > 0 { + #| if exp % 2 == 1 { + #| result = result * base + #| } + #| base = base * base + #| exp = exp / 2 + #| } + #| result + #| } + #| Some(modulus) => { + #| guard !(modulus.is_zero() || modulus.sign == Negative) + #| let mut result = 1N + #| let mut base = self + #| let mut exp = exp + #| while exp > 0 { + #| if exp % 2 == 1 { + #| result = result * base % modulus + #| } + #| base = base * base % modulus + #| exp = exp / 2 + #| } + #| result + #| } + #| } + #|} + #|pub fn BigInt::from_octets(input : Bytes, signum? : Int = 1) -> BigInt { + #| let len = input.length() // number of bytes + #| if signum == 0 { + #| return zero + #| } else if signum < 0 { + #| return -BigInt::from_octets(input) + #| } + #| if len == 0 { + #| abort("empty octet string") + #| } + #| let div = len * 8 / radix_bit_len + #| let mod = len * 8 % radix_bit_len // number of bits in the first limb + #| let limbs_len = if mod == 0 { div } else { div + 1 } + #| let limbs = FixedArray::make(limbs_len, 0U) + #| for i in 0..<(mod / 8) { + #| limbs[limbs_len - 1] = (limbs[limbs_len - 1] << 8) | input[i].to_uint() + #| } + #| let byte_per_limb = radix_bit_len / 8 + #| for i in 0..
Bytes { + #| let length = match length { + #| None => 1 + #| Some(l) => if l <= 0 { abort("negative length") } else { l } + #| } + #| if self.is_zero() { + #| return Bytes::new(max(1, length)) + #| } + #| if self.sign == Negative { + #| abort("negative BigInt") + #| } + #| let head_bits = 32 - self.limbs[self.len - 1].reinterpret_as_int().clz() + #| let tail_len = self.len - 1 + #| let len = (head_bits + 7) / 8 + tail_len * (radix_bit_len / 8) + #| let len = max(length, len) + #| let result = FixedArray::make(len, Byte::default()) + #| for i in 0..= self.len { + #| break + #| } + #| result[len - 1 - i] = ((self.limbs[i / 4] >> (i % 4 * 8)) & 0xffU) + #| .reinterpret_as_int() + #| .to_byte() + #| } + #| unsafe_fixedarray_to_bytes(result) + #|} + #|pub impl BitAnd for BigInt with land(self : BigInt, other : BigInt) -> BigInt { + #| let max_length = if self.limbs.length() < other.limbs.length() { + #| other.limbs.length() + 1 + #| } else { + #| self.limbs.length() + 1 + #| } + #| let x_limbs = FixedArray::make(max_length, 0U) + #| x_limbs.unsafe_blit(0, self.limbs, 0, self.limbs.length()) + #| let y_limbs = FixedArray::make(max_length, 0U) + #| y_limbs.unsafe_blit(0, other.limbs, 0, other.limbs.length()) + #| if self.sign == Negative { + #| for i in 0.. BigInt { + #| let max_length = if self.limbs.length() < other.limbs.length() { + #| other.limbs.length() + 1 + #| } else { + #| self.limbs.length() + 1 + #| } + #| let x_limbs = FixedArray::make(max_length, 0U) + #| x_limbs.unsafe_blit(0, self.limbs, 0, self.limbs.length()) + #| let y_limbs = FixedArray::make(max_length, 0U) + #| y_limbs.unsafe_blit(0, other.limbs, 0, other.limbs.length()) + #| if self.sign == Negative { + #| for i in 0.. BigInt { + #| let max_length = if self.limbs.length() < other.limbs.length() { + #| other.limbs.length() + 1 + #| } else { + #| self.limbs.length() + 1 + #| } + #| let x_limbs = FixedArray::make(max_length, 0U) + #| x_limbs.unsafe_blit(0, self.limbs, 0, self.limbs.length()) + #| let y_limbs = FixedArray::make(max_length, 0U) + #| y_limbs.unsafe_blit(0, other.limbs, 0, other.limbs.length()) + #| if self.sign == Negative { + #| for i in 0.. Int { + #| self.to_uint().reinterpret_as_int() + #|} + #|pub fn BigInt::to_uint(self : BigInt) -> UInt { + #| let value = if self.sign == Negative { (1N << 32) + self } else { self } + #| value.limbs[0] + #|} + #|pub fn BigInt::to_int64(self : BigInt) -> Int64 { + #| self.to_uint64().reinterpret_as_int64() + #|} + #|pub fn BigInt::to_uint64(self : BigInt) -> UInt64 { + #| let value = if self.sign == Negative { (1N << 64) + self } else { self } + #| let len = 64 / radix_bit_len + #| let len = if value.len < len { value.len } else { len } + #| let mut result = 0UL + #| for i in len>..0 { + #| result = result << radix_bit_len + #| result = result | (value.limbs[i].to_uint64() & radix_mask) + #| } + #| result + #|} + #|pub fn BigInt::bit_length(self : BigInt) -> Int { + #| if self.len == 0 { + #| return 0 + #| } + #| let mut bit_length = (self.len - 1) * radix_bit_len + + #| (radix_bit_len - self.limbs[self.len - 1].clz()) + #| if self.sign == Negative { + #| let mut pow2 = self.limbs[0].popcnt() == 1 + #| for i in 1.. Int { + #| if self.is_zero() { + #| return 0 + #| } + #| let i = for i = 0; i < self.len && self.limbs[i] == 0; { + #| continue i + 1 + #| } nobreak { + #| i + #| } + #| radix_bit_len * i + self.limbs[i].ctz() + #|} + #|fn unchecked_double_to_int(d : Double) -> Int = "%f64_to_i32" + #|fn unsafe_fixedarray_to_bytes(arr : FixedArray[Byte]) -> Bytes = "%identity" + #|fn can_convert_to_int(x : BigInt) -> Bool { + #| x.len == 1 && + #| (if x.sign == Negative { + #| x.limbs[0] <= 0x80000000 + #| } else { + #| x.limbs[0] < 0x80000000 + #| }) + #|} + #|fn can_convert_to_int64(x : BigInt) -> Bool { + #| if x.len == 1 { + #| true + #| } else if x.len == 2 { + #| if x.sign == Negative { + #| x.limbs[1] < 0x80000000 || (x.limbs[1] == 0x80000000 && x.limbs[0] == 0) + #| } else { + #| x.limbs[1] < 0x80000000 + #| } + #| } else { + #| false + #| } + #|} + #|fn is_neg(x : BigInt) -> Bool { + #| x.sign == Negative + #|} + #|test "limb length" { + #| inspect(0N.len, content="1") + #| inspect(1N.len, content="1") + #| inspect((-1N).len, content="1") + #| inspect(2147483647N.len, content="1") // Int.max_value + #| inspect((-2147483648N).len, content="1") // Int.min_value + #| inspect(2147483648N.len, content="1") // Int.max_value + 1 + #| inspect((-2147483649N).len, content="1") // Int.min_value - 1 + #| inspect(4294967295N.len, content="1") // 2^32 - 1 + #| inspect((-4294967295N).len, content="1") // -(2^32 - 1) + #| inspect(4294967296N.len, content="2") // 2^32 + #| inspect((-4294967296N).len, content="2") // -2^32 + #|} + #|fn BigInt::limbs(self : Self) -> Array[UInt] { + #| self.limbs[:self.len].to_array() + #|} + ), + "deprecated.mbt": ( + #|#deprecated("Use infix bitwise operator `>>` instead") + #|#coverage.skip + #|pub fn BigInt::asr(self : BigInt, n : Int) -> BigInt { + #| self >> n + #|} + #|#deprecated("Use infix bitwise operator `<<` instead") + #|#coverage.skip + #|pub fn BigInt::shl(self : BigInt, n : Int) -> BigInt { + #| self << n + #|} + #|#deprecated("Use infix bitwise operator `<<` instead") + #|#coverage.skip + #|pub fn BigInt::lsl(self : BigInt, n : Int) -> BigInt { + #| self << n + #|} + #|#deprecated("Use infix bitwise operator `>>` instead") + #|#coverage.skip + #|pub fn BigInt::shr(self : BigInt, n : Int) -> BigInt { + #| self >> n + #|} + #|#deprecated("Use `to_string(radix=16)` instead") + #|#coverage.skip + #|#cfg(not(target="js")) + #|pub fn BigInt::to_hex(self : BigInt, uppercase? : Bool = true) -> String { + #| if self.is_zero() { + #| return "0" + #| } + #| let digits_per_limb = radix_bit_len / 4 + #| let buf = if self.sign is Negative { + #| let builder = StringBuilder::new(size_hint=self.len * digits_per_limb + 2) + #| builder.write_char('-') + #| builder + #| } else { + #| StringBuilder::new(size_hint=self.len * digits_per_limb) + #| } + #| for i in self.len>..0 { + #| let digits = FixedArray::make(digits_per_limb, '0') + #| let idx = for x = self.limbs[i], idx = 0; x > 0; { + #| let y = x % 16 + #| digits[idx] = if y < 10 { + #| (y.reinterpret_as_int() + '0'.to_int()).unsafe_to_char() + #| } else if uppercase { + #| (y.reinterpret_as_int() - 10 + 'A'.to_int()).unsafe_to_char() + #| } else { + #| (y.reinterpret_as_int() - 10 + 'a'.to_int()).unsafe_to_char() + #| } + #| continue x / 16, idx + 1 + #| } nobreak { + #| idx + #| } + #| let idx = if i != self.len - 1 { digits_per_limb } else { idx } + #| for j in 0.. String = + #| #|(x, uppercase) => { + #| #| const r = x.toString(16); + #| #| return uppercase ? r.toUpperCase() : r; + #| #|} + #|#deprecated("Use `from_string(radix=16)` instead") + #|#coverage.skip + #|#cfg(not(target="js")) + #|pub fn BigInt::from_hex(input : String) -> BigInt { + #| fn char_from_hex(x : Int) -> UInt { + #| (match x { + #| '0'..='9' => x - '0' + #| 'A'..='F' => x + (10 - 'A') + #| 'a'..='f' => x + (10 - 'a') + #| _ => abort("invalid character") + #| }).reinterpret_as_uint() + #| } + #| let len = input.length() + #| if len == 0 { + #| abort("empty string") + #| } + #| let (sign, number_len) = if input.unsafe_get(0) == '-' { + #| (Negative, len - 1) + #| } else { + #| (Positive, len) + #| } + #| let nb_char = radix_bit_len / 4 // number of char per limb + #| let quotient = number_len / nb_char + #| let mod = number_len % nb_char + #| let b_len = if mod == 0 { quotient } else { quotient + 1 } + #| let b = FixedArray::make(b_len, 0U) + #| if mod != 0 { + #| let start = len - quotient * nb_char - mod + #| for i in 0.. 1; { + #| continue b_len - 1 + #| } nobreak { + #| b_len + #| } + #| let sign = if b_len == 1 && b[0] == 0 { Positive } else { sign } + #| { limbs: b, sign, len: b_len } + #|} + #|#deprecated("Use `from_string(radix=16)` instead") + #|#coverage.skip + #|#cfg(target="js") + #|pub extern "js" fn BigInt::from_hex(str : String) -> BigInt = + #| #|(x) => x.startsWith('-') ? -BigInt(`0x${x.slice(1)}`) : BigInt(`0x${x}`) + ) + } ) ///| let moonbitlang_core_buffer_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/buffer", - deps={ - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/bytes": moonbitlang_core_bytes_module, - "moonbitlang/core/array": moonbitlang_core_array_module, - "moonbitlang/core/string": moonbitlang_core_string_module, - "moonbitlang/core/float": moonbitlang_core_float_module, - "moonbitlang/core/int16": moonbitlang_core_int16_module, - "moonbitlang/core/uint16": moonbitlang_core_uint16_module, - }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| "moonbitlang/core/builtin", - #| "moonbitlang/core/bytes", - #| "moonbitlang/core/array", - #| "moonbitlang/core/string", - #| "moonbitlang/core/float", - #| "moonbitlang/core/int16", - #| "moonbitlang/core/uint16" - #| ], - #| "test-import": ["moonbitlang/core/int"] - #|} - ), - "buffer.mbt": ( - #|#alias(T, deprecated) - #|struct Buffer { - #| mut data : FixedArray[Byte] - #| mut len : Int - #|} - #|fn Buffer::grow_if_necessary(self : Buffer, required : Int) -> Unit { - #| let start = if self.data.length() <= 0 { 1 } else { self.data.length() } - #| let enough_space = for space = start { - #| if space >= required { - #| break space - #| } - #| continue space * 2 - #| } - #| if enough_space != self.data.length() { - #| let new_data = FixedArray::make(enough_space, Byte::default()) - #| new_data.unsafe_blit(0, self.data, 0, self.len) - #| self.data = new_data - #| } - #|} - #|pub fn Buffer::length(self : Buffer) -> Int { - #| self.len - #|} - #|pub fn Buffer::is_empty(self : Buffer) -> Bool { - #| self.len == 0 - #|} - #|pub fn new(size_hint? : Int = 0) -> Buffer { - #| let initial = if size_hint < 1 { 1 } else { size_hint } - #| let data = FixedArray::make(initial, Byte::default()) - #| { data, len: 0 } - #|} - #|pub fn from_bytes(bytes : Bytes) -> Buffer { - #| let val_len = bytes.length() - #| let buf = new(size_hint=val_len) - #| buf.data.blit_from_bytes(0, bytes, 0, val_len) - #| buf.len = val_len - #| buf - #|} - #|pub fn from_array(arr : ArrayView[Byte]) -> Buffer { - #| let buf = new(size_hint=arr.length()) - #| for byte in arr { - #| buf.data[buf.len] = byte - #| buf.len += 1 - #| } - #| buf - #|} - #|pub fn from_iter(iter : Iter[Byte]) -> Buffer { - #| let buf = new() - #| let mut capacity = buf.data.length() - #| for byte in iter { - #| if buf.len == capacity { - #| buf.grow_if_necessary(capacity + 1) - #| capacity = buf.data.length() - #| } - #| buf.data[buf.len] = byte - #| buf.len += 1 - #| } - #| buf - #|} - #|pub impl Logger for Buffer with write_string(self, value) { - #| self.grow_if_necessary(self.len + value.length() * 2) - #| self.data.blit_from_string(self.len, value, 0, value.length()) - #| self.len += value.length() * 2 - #|} - #|pub fn Buffer::write_uint64_be(self : Buffer, value : UInt64) -> Unit { - #| self.grow_if_necessary(self.len + 8) - #| let offset = self.len - #| self.data[offset] = (value >> 56).to_byte() - #| self.data[offset + 1] = (value >> 48).to_byte() - #| self.data[offset + 2] = (value >> 40).to_byte() - #| self.data[offset + 3] = (value >> 32).to_byte() - #| self.data[offset + 4] = (value >> 24).to_byte() - #| self.data[offset + 5] = (value >> 16).to_byte() - #| self.data[offset + 6] = (value >> 8).to_byte() - #| self.data[offset + 7] = value.to_byte() - #| self.len += 8 - #|} - #|pub fn Buffer::write_uint64_le(self : Buffer, value : UInt64) -> Unit { - #| self.grow_if_necessary(self.len + 8) - #| let offset = self.len - #| self.data[offset] = value.to_byte() - #| self.data[offset + 1] = (value >> 8).to_byte() - #| self.data[offset + 2] = (value >> 16).to_byte() - #| self.data[offset + 3] = (value >> 24).to_byte() - #| self.data[offset + 4] = (value >> 32).to_byte() - #| self.data[offset + 5] = (value >> 40).to_byte() - #| self.data[offset + 6] = (value >> 48).to_byte() - #| self.data[offset + 7] = (value >> 56).to_byte() - #| self.len += 8 - #|} - #|pub fn Buffer::write_int64_be(self : Buffer, value : Int64) -> Unit { - #| self.write_uint64_be(value.reinterpret_as_uint64()) - #|} - #|pub fn Buffer::write_int64_le(self : Buffer, value : Int64) -> Unit { - #| self.write_uint64_le(value.reinterpret_as_uint64()) - #|} - #|pub fn Buffer::write_uint_be(self : Buffer, value : UInt) -> Unit { - #| self.grow_if_necessary(self.len + 4) - #| let offset = self.len - #| self.data[offset] = (value >> 24).to_byte() - #| self.data[offset + 1] = (value >> 16).to_byte() - #| self.data[offset + 2] = (value >> 8).to_byte() - #| self.data[offset + 3] = value.to_byte() - #| self.len += 4 - #|} - #|pub fn Buffer::write_uint_le(self : Buffer, value : UInt) -> Unit { - #| self.grow_if_necessary(self.len + 4) - #| let offset = self.len - #| self.data[offset] = value.to_byte() - #| self.data[offset + 1] = (value >> 8).to_byte() - #| self.data[offset + 2] = (value >> 16).to_byte() - #| self.data[offset + 3] = (value >> 24).to_byte() - #| self.len += 4 - #|} - #|pub fn Buffer::write_int_be(self : Buffer, value : Int) -> Unit { - #| self.write_uint_be(value.reinterpret_as_uint()) - #|} - #|pub fn Buffer::write_int_le(self : Buffer, value : Int) -> Unit { - #| self.write_uint_le(value.reinterpret_as_uint()) - #|} - #|pub fn Buffer::write_uint16_be(self : Buffer, value : UInt16) -> Unit { - #| self.grow_if_necessary(self.len + 2) - #| let offset = self.len - #| self.data[offset] = (value.to_int() >> 8).to_byte() - #| self.data[offset + 1] = value.to_byte() - #| self.len += 2 - #|} - #|pub fn Buffer::write_uint16_le(self : Buffer, value : UInt16) -> Unit { - #| self.grow_if_necessary(self.len + 2) - #| let offset = self.len - #| self.data[offset] = value.to_byte() - #| self.data[offset + 1] = (value.to_int() >> 8).to_byte() - #| self.len += 2 - #|} - #|pub fn Buffer::write_int16_be(self : Buffer, value : Int16) -> Unit { - #| self.grow_if_necessary(self.len + 2) - #| let offset = self.len - #| self.data[offset] = (value.to_int() >> 8).to_byte() - #| self.data[offset + 1] = value.to_byte() - #| self.len += 2 - #|} - #|pub fn Buffer::write_int16_le(self : Buffer, value : Int16) -> Unit { - #| self.grow_if_necessary(self.len + 2) - #| let offset = self.len - #| self.data[offset] = value.to_byte() - #| self.data[offset + 1] = (value.to_int() >> 8).to_byte() - #| self.len += 2 - #|} - #|pub fn Buffer::write_double_be(self : Buffer, value : Double) -> Unit { - #| self.write_uint64_be(value.reinterpret_as_uint64()) - #|} - #|pub fn Buffer::write_double_le(self : Buffer, value : Double) -> Unit { - #| self.write_uint64_le(value.reinterpret_as_uint64()) - #|} - #|pub fn Buffer::write_float_be(self : Buffer, value : Float) -> Unit { - #| self.write_uint_be(value.reinterpret_as_uint()) - #|} - #|pub fn Buffer::write_float_le(self : Buffer, value : Float) -> Unit { - #| self.write_uint_le(value.reinterpret_as_uint()) - #|} - #|pub fn Buffer::write_object(self : Buffer, value : &Show) -> Unit { - #| self.write_string(value.to_string()) - #|} - #|pub fn Buffer::write_bytes(self : Buffer, value : Bytes) -> Unit { - #| let val_len = value.length() - #| self.grow_if_necessary(self.len + val_len) - #| self.data.blit_from_bytes(self.len, value, 0, val_len) - #| self.len += val_len - #|} - #|pub fn Buffer::write_bytesview(self : Buffer, value : BytesView) -> Unit { - #| let val_len = value.length() - #| self.grow_if_necessary(self.len + val_len) - #| self.data.blit_from_bytes( - #| self.len, - #| value.data(), - #| value.start_offset(), - #| value.length(), - #| ) - #| self.len += val_len - #|} - #|pub fn Buffer::write_char_utf8(buf : Self, value : Char) -> Unit { - #| let code = value.to_uint() - #| match code { - #| _..<0x80 => { - #| buf.grow_if_necessary(buf.len + 1) - #| buf.data[buf.len] = ((code & 0x7F) | 0x00).to_byte() - #| buf.len += 1 - #| } - #| _..<0x0800 => { - #| buf.grow_if_necessary(buf.len + 2) - #| buf.data[buf.len] = (((code >> 6) & 0x1F) | 0xC0).to_byte() - #| buf.data[buf.len + 1] = ((code & 0x3F) | 0x80).to_byte() - #| buf.len += 2 - #| } - #| _..<0x010000 => { - #| buf.grow_if_necessary(buf.len + 3) - #| buf.data[buf.len] = (((code >> 12) & 0x0F) | 0xE0).to_byte() - #| buf.data[buf.len + 1] = (((code >> 6) & 0x3F) | 0x80).to_byte() - #| buf.data[buf.len + 2] = ((code & 0x3F) | 0x80).to_byte() - #| buf.len += 3 - #| } - #| _..<0x110000 => { - #| buf.grow_if_necessary(buf.len + 4) - #| buf.data[buf.len] = (((code >> 18) & 0x07) | 0xF0).to_byte() - #| buf.data[buf.len + 1] = (((code >> 12) & 0x3F) | 0x80).to_byte() - #| buf.data[buf.len + 2] = (((code >> 6) & 0x3F) | 0x80).to_byte() - #| buf.data[buf.len + 3] = ((code & 0x3F) | 0x80).to_byte() - #| buf.len += 4 - #| } - #| _ => abort("Char out of range") - #| } - #|} - #|pub fn Buffer::write_char_utf16le(buf : Self, value : Char) -> Unit { - #| let code = value.to_uint() - #| if code < 0x10000 { - #| buf.grow_if_necessary(buf.len + 2) - #| buf.data[buf.len + 0] = (code & 0xFF).to_byte() - #| buf.data[buf.len + 1] = (code >> 8).to_byte() - #| buf.len += 2 - #| } else if code < 0x110000 { - #| let cp = code - 0x10000 - #| let high = (cp >> 10) | 0xD800 - #| let low = (cp & 0x3FF) | 0xDC00 - #| buf.grow_if_necessary(buf.len + 4) - #| buf.data[buf.len + 0] = (high & 0xFF).to_byte() - #| buf.data[buf.len + 1] = (high >> 8).to_byte() - #| buf.data[buf.len + 2] = (low & 0xFF).to_byte() - #| buf.data[buf.len + 3] = (low >> 8).to_byte() - #| buf.len += 4 - #| } else { - #| abort("Char out of range") - #| } - #|} - #|pub fn Buffer::write_char_utf16be(buf : Self, value : Char) -> Unit { - #| let code = value.to_uint() - #| if code < 0x10000 { - #| buf.grow_if_necessary(buf.len + 2) - #| buf.data[buf.len + 0] = (code >> 8).to_byte() - #| buf.data[buf.len + 1] = (code & 0xFF).to_byte() - #| buf.len += 2 - #| } else if code < 0x110000 { - #| buf.grow_if_necessary(buf.len + 4) - #| let cp = code - 0x10000 - #| let high = (cp >> 10) | 0xD800 - #| let low = (cp & 0x3FF) | 0xDC00 - #| buf.data[buf.len + 0] = (high >> 8).to_byte() - #| buf.data[buf.len + 1] = (high & 0xFF).to_byte() - #| buf.data[buf.len + 2] = (low >> 8).to_byte() - #| buf.data[buf.len + 3] = (low & 0xFF).to_byte() - #| buf.len += 4 - #| } else { - #| abort("Char out of range") - #| } - #|} - #|pub fn Buffer::write_string_utf8(buf : Self, string : StringView) -> Unit { - #| for ch in string { - #| buf.write_char_utf8(ch) - #| } - #|} - #|#alias(write_stringview, deprecated="use write_string_utf16le instead") - #|pub fn Buffer::write_string_utf16le(buf : Self, string : StringView) -> Unit { - #| let len = string.length() - #| buf.grow_if_necessary(buf.len + len * 2) - #| for i = 0, j = buf.len; i < len; i = i + 1, j = j + 2 { - #| let c = string.unsafe_charcode_at(i).reinterpret_as_uint() - #| buf.data[j] = (c & 0xff).to_byte() - #| buf.data[j + 1] = (c >> 8).to_byte() - #| } - #| buf.len += len * 2 - #|} - #|pub fn Buffer::write_string_utf16be(buf : Self, string : StringView) -> Unit { - #| let len = string.length() - #| buf.grow_if_necessary(buf.len + len * 2) - #| for i = 0, j = buf.len; i < len; i = i + 1, j = j + 2 { - #| let c = string.unsafe_charcode_at(i).reinterpret_as_uint() - #| buf.data[j + 1] = (c & 0xff).to_byte() - #| buf.data[j] = (c >> 8).to_byte() - #| } - #| buf.len += len * 2 - #|} - #|pub impl Logger for Buffer with write_view(self : Buffer, value : StringView) -> Unit { - #| self.grow_if_necessary(self.len + value.length() * 2) - #| self.data.blit_from_string( - #| self.len, - #| value.data(), - #| value.start_offset(), - #| value.length(), - #| ) - #| self.len += value.length() * 2 - #|} - #|pub impl Logger for Buffer with write_char(self : Buffer, value : Char) -> Unit { - #| self.grow_if_necessary(self.len + 4) - #| let inc = self.data.set_utf16le_char(self.len, value) - #| self.len += inc - #|} - #|pub fn Buffer::write_byte(self : Buffer, value : Byte) -> Unit { - #| self.grow_if_necessary(self.len + 1) - #| self.data[self.len] = value - #| self.len += 1 - #|} - #|pub fn Buffer::write_iter(self : Buffer, iter : Iter[Byte]) -> Unit { - #| for byte in iter { - #| self.write_byte(byte) - #| } - #|} - #|pub fn Buffer::reset(self : Buffer) -> Unit { - #| self.len = 0 - #|} - #|#alias(contents) - #|pub fn Buffer::to_bytes(self : Buffer) -> Bytes { - #| Bytes::from_array(self.data[0:self.len]) - #|} - #|pub fn Buffer::view(self : Buffer) -> ArrayView[Byte] { - #| self.data[0:self.len] - #|} - #|pub impl Show for Buffer with output(self, logger) { - #| logger.write_string(self.contents().to_unchecked_string()) - #|} - ), - "deprecated.mbt": "", - "sleb128.mbt": ( - #|trait Leb128 { - #| output(Self, Buffer) -> Unit - #|} - #|pub impl Leb128 for Int with output(self, buffer) { - #| for value = self { - #| let byte = value & 0x7f // Get the low 7 bits - #| let next_value = value >> 7 // Arithmetic right shift - #| let sign_bit_set = (byte & 0x40) != 0 - #| let need_more = if value >= 0 { - #| next_value != 0 || sign_bit_set - #| } else { - #| next_value != -1 || !sign_bit_set - #| } - #| if need_more { - #| buffer.write_byte((byte | 0x80).to_byte()) - #| continue next_value - #| } else { - #| buffer.write_byte(byte.to_byte()) - #| break - #| } - #| } - #|} - #|pub impl Leb128 for Int64 with output(self, buffer) { - #| for value = self { - #| let byte = value & 0x7f // Get the low 7 bits - #| let next_value = value >> 7 // Arithmetic right shift - #| let sign_bit_set = (byte & 0x40) != 0 - #| let need_more = if value >= 0 { - #| next_value != 0 || sign_bit_set - #| } else { - #| next_value != -1 || !sign_bit_set - #| } - #| if need_more { - #| buffer.write_byte((byte | 0x80).to_byte()) - #| continue next_value - #| } else { - #| buffer.write_byte(byte.to_byte()) - #| break - #| } - #| } - #|} - #|pub fn[A : Leb128] Buffer::write_leb128(buffer : Buffer, value : A) -> Unit { - #| value.output(buffer) - #|} - ), - "uleb128.mbt": ( - #|pub impl Leb128 for UInt with output(self, buffer) { - #| for value = self { - #| if value < 128 { - #| buffer.write_byte(value.to_byte()) - #| break - #| } else { - #| buffer.write_byte(((value % 128) | 128).to_byte()) - #| continue value / 128 - #| } - #| } - #|} - #|pub impl Leb128 for UInt64 with output(self, buffer) { - #| for value = self { - #| if value < 128 { - #| buffer.write_byte(value.to_byte()) - #| break - #| } else { - #| buffer.write_byte(((value % 128) | 128).to_byte()) - #| continue value / 128 - #| } - #| } - #|} - ), - }, + "buffer.mbt": ( + #|#alias(T, deprecated) + #|struct Buffer { + #| mut data : FixedArray[Byte] + #| mut len : Int + #|} + #|fn Buffer::grow_if_necessary(self : Buffer, required : Int) -> Unit { + #| let start = if self.data.length() <= 0 { 1 } else { self.data.length() } + #| let enough_space = for space = start { + #| if space >= required { + #| break space + #| } + #| continue space * 2 + #| } + #| if enough_space != self.data.length() { + #| let new_data = FixedArray::make(enough_space, Byte::default()) + #| new_data.unsafe_blit(0, self.data, 0, self.len) + #| self.data = new_data + #| } + #|} + #|pub fn Buffer::length(self : Buffer) -> Int { + #| self.len + #|} + #|pub fn Buffer::is_empty(self : Buffer) -> Bool { + #| self.len == 0 + #|} + #|pub fn new(size_hint? : Int = 0) -> Buffer { + #| let initial = if size_hint < 1 { 1 } else { size_hint } + #| let data = FixedArray::make(initial, Byte::default()) + #| { data, len: 0 } + #|} + #|pub fn from_bytes(bytes : Bytes) -> Buffer { + #| let val_len = bytes.length() + #| let buf = new(size_hint=val_len) + #| buf.data.blit_from_bytes(0, bytes, 0, val_len) + #| buf.len = val_len + #| buf + #|} + #|pub fn from_array(arr : ArrayView[Byte]) -> Buffer { + #| let buf = new(size_hint=arr.length()) + #| for byte in arr { + #| buf.data[buf.len] = byte + #| buf.len += 1 + #| } + #| buf + #|} + #|pub fn from_iter(iter : Iter[Byte]) -> Buffer { + #| let buf = new() + #| for byte in iter; capacity = buf.data.length() { + #| let capacity = if buf.len == capacity { + #| buf.grow_if_necessary(capacity + 1) + #| buf.data.length() + #| } else { + #| capacity + #| } + #| buf.data[buf.len] = byte + #| buf.len += 1 + #| continue capacity + #| } + #| buf + #|} + #|pub impl Logger for Buffer with write_string(self, value) { + #| self.grow_if_necessary(self.len + value.length() * 2) + #| self.data.blit_from_string(self.len, value, 0, value.length()) + #| self.len += value.length() * 2 + #|} + #|pub fn Buffer::write_uint64_be(self : Buffer, value : UInt64) -> Unit { + #| self.grow_if_necessary(self.len + 8) + #| let offset = self.len + #| self.data[offset] = (value >> 56).to_byte() + #| self.data[offset + 1] = (value >> 48).to_byte() + #| self.data[offset + 2] = (value >> 40).to_byte() + #| self.data[offset + 3] = (value >> 32).to_byte() + #| self.data[offset + 4] = (value >> 24).to_byte() + #| self.data[offset + 5] = (value >> 16).to_byte() + #| self.data[offset + 6] = (value >> 8).to_byte() + #| self.data[offset + 7] = value.to_byte() + #| self.len += 8 + #|} + #|pub fn Buffer::write_uint64_le(self : Buffer, value : UInt64) -> Unit { + #| self.grow_if_necessary(self.len + 8) + #| let offset = self.len + #| self.data[offset] = value.to_byte() + #| self.data[offset + 1] = (value >> 8).to_byte() + #| self.data[offset + 2] = (value >> 16).to_byte() + #| self.data[offset + 3] = (value >> 24).to_byte() + #| self.data[offset + 4] = (value >> 32).to_byte() + #| self.data[offset + 5] = (value >> 40).to_byte() + #| self.data[offset + 6] = (value >> 48).to_byte() + #| self.data[offset + 7] = (value >> 56).to_byte() + #| self.len += 8 + #|} + #|pub fn Buffer::write_int64_be(self : Buffer, value : Int64) -> Unit { + #| self.write_uint64_be(value.reinterpret_as_uint64()) + #|} + #|pub fn Buffer::write_int64_le(self : Buffer, value : Int64) -> Unit { + #| self.write_uint64_le(value.reinterpret_as_uint64()) + #|} + #|pub fn Buffer::write_uint_be(self : Buffer, value : UInt) -> Unit { + #| self.grow_if_necessary(self.len + 4) + #| let offset = self.len + #| self.data[offset] = (value >> 24).to_byte() + #| self.data[offset + 1] = (value >> 16).to_byte() + #| self.data[offset + 2] = (value >> 8).to_byte() + #| self.data[offset + 3] = value.to_byte() + #| self.len += 4 + #|} + #|pub fn Buffer::write_uint_le(self : Buffer, value : UInt) -> Unit { + #| self.grow_if_necessary(self.len + 4) + #| let offset = self.len + #| self.data[offset] = value.to_byte() + #| self.data[offset + 1] = (value >> 8).to_byte() + #| self.data[offset + 2] = (value >> 16).to_byte() + #| self.data[offset + 3] = (value >> 24).to_byte() + #| self.len += 4 + #|} + #|pub fn Buffer::write_int_be(self : Buffer, value : Int) -> Unit { + #| self.write_uint_be(value.reinterpret_as_uint()) + #|} + #|pub fn Buffer::write_int_le(self : Buffer, value : Int) -> Unit { + #| self.write_uint_le(value.reinterpret_as_uint()) + #|} + #|pub fn Buffer::write_uint16_be(self : Buffer, value : UInt16) -> Unit { + #| self.grow_if_necessary(self.len + 2) + #| let offset = self.len + #| self.data[offset] = (value.to_int() >> 8).to_byte() + #| self.data[offset + 1] = value.to_byte() + #| self.len += 2 + #|} + #|pub fn Buffer::write_uint16_le(self : Buffer, value : UInt16) -> Unit { + #| self.grow_if_necessary(self.len + 2) + #| let offset = self.len + #| self.data[offset] = value.to_byte() + #| self.data[offset + 1] = (value.to_int() >> 8).to_byte() + #| self.len += 2 + #|} + #|pub fn Buffer::write_int16_be(self : Buffer, value : Int16) -> Unit { + #| self.grow_if_necessary(self.len + 2) + #| let offset = self.len + #| self.data[offset] = (value.to_int() >> 8).to_byte() + #| self.data[offset + 1] = value.to_byte() + #| self.len += 2 + #|} + #|pub fn Buffer::write_int16_le(self : Buffer, value : Int16) -> Unit { + #| self.grow_if_necessary(self.len + 2) + #| let offset = self.len + #| self.data[offset] = value.to_byte() + #| self.data[offset + 1] = (value.to_int() >> 8).to_byte() + #| self.len += 2 + #|} + #|pub fn Buffer::write_double_be(self : Buffer, value : Double) -> Unit { + #| self.write_uint64_be(value.reinterpret_as_uint64()) + #|} + #|pub fn Buffer::write_double_le(self : Buffer, value : Double) -> Unit { + #| self.write_uint64_le(value.reinterpret_as_uint64()) + #|} + #|pub fn Buffer::write_float_be(self : Buffer, value : Float) -> Unit { + #| self.write_uint_be(value.reinterpret_as_uint()) + #|} + #|pub fn Buffer::write_float_le(self : Buffer, value : Float) -> Unit { + #| self.write_uint_le(value.reinterpret_as_uint()) + #|} + #|pub fn Buffer::write_object(self : Buffer, value : &Show) -> Unit { + #| self.write_string(value.to_string()) + #|} + #|pub fn Buffer::write_bytes(self : Buffer, value : Bytes) -> Unit { + #| let val_len = value.length() + #| self.grow_if_necessary(self.len + val_len) + #| self.data.blit_from_bytes(self.len, value, 0, val_len) + #| self.len += val_len + #|} + #|pub fn Buffer::write_bytesview(self : Buffer, value : BytesView) -> Unit { + #| let val_len = value.length() + #| self.grow_if_necessary(self.len + val_len) + #| self.data.blit_from_bytes( + #| self.len, + #| value.data(), + #| value.start_offset(), + #| value.length(), + #| ) + #| self.len += val_len + #|} + #|pub fn Buffer::write_char_utf8(buf : Self, value : Char) -> Unit { + #| let code = value.to_uint() + #| match code { + #| _..<0x80 => { + #| buf.grow_if_necessary(buf.len + 1) + #| buf.data[buf.len] = ((code & 0x7F) | 0x00).to_byte() + #| buf.len += 1 + #| } + #| _..<0x0800 => { + #| buf.grow_if_necessary(buf.len + 2) + #| buf.data[buf.len] = (((code >> 6) & 0x1F) | 0xC0).to_byte() + #| buf.data[buf.len + 1] = ((code & 0x3F) | 0x80).to_byte() + #| buf.len += 2 + #| } + #| _..<0x010000 => { + #| buf.grow_if_necessary(buf.len + 3) + #| buf.data[buf.len] = (((code >> 12) & 0x0F) | 0xE0).to_byte() + #| buf.data[buf.len + 1] = (((code >> 6) & 0x3F) | 0x80).to_byte() + #| buf.data[buf.len + 2] = ((code & 0x3F) | 0x80).to_byte() + #| buf.len += 3 + #| } + #| _..<0x110000 => { + #| buf.grow_if_necessary(buf.len + 4) + #| buf.data[buf.len] = (((code >> 18) & 0x07) | 0xF0).to_byte() + #| buf.data[buf.len + 1] = (((code >> 12) & 0x3F) | 0x80).to_byte() + #| buf.data[buf.len + 2] = (((code >> 6) & 0x3F) | 0x80).to_byte() + #| buf.data[buf.len + 3] = ((code & 0x3F) | 0x80).to_byte() + #| buf.len += 4 + #| } + #| _ => abort("Char out of range") + #| } + #|} + #|pub fn Buffer::write_char_utf16le(buf : Self, value : Char) -> Unit { + #| let code = value.to_uint() + #| if code < 0x10000 { + #| buf.grow_if_necessary(buf.len + 2) + #| buf.data[buf.len + 0] = (code & 0xFF).to_byte() + #| buf.data[buf.len + 1] = (code >> 8).to_byte() + #| buf.len += 2 + #| } else if code < 0x110000 { + #| let cp = code - 0x10000 + #| let high = (cp >> 10) | 0xD800 + #| let low = (cp & 0x3FF) | 0xDC00 + #| buf.grow_if_necessary(buf.len + 4) + #| buf.data[buf.len + 0] = (high & 0xFF).to_byte() + #| buf.data[buf.len + 1] = (high >> 8).to_byte() + #| buf.data[buf.len + 2] = (low & 0xFF).to_byte() + #| buf.data[buf.len + 3] = (low >> 8).to_byte() + #| buf.len += 4 + #| } else { + #| abort("Char out of range") + #| } + #|} + #|pub fn Buffer::write_char_utf16be(buf : Self, value : Char) -> Unit { + #| let code = value.to_uint() + #| if code < 0x10000 { + #| buf.grow_if_necessary(buf.len + 2) + #| buf.data[buf.len + 0] = (code >> 8).to_byte() + #| buf.data[buf.len + 1] = (code & 0xFF).to_byte() + #| buf.len += 2 + #| } else if code < 0x110000 { + #| buf.grow_if_necessary(buf.len + 4) + #| let cp = code - 0x10000 + #| let high = (cp >> 10) | 0xD800 + #| let low = (cp & 0x3FF) | 0xDC00 + #| buf.data[buf.len + 0] = (high >> 8).to_byte() + #| buf.data[buf.len + 1] = (high & 0xFF).to_byte() + #| buf.data[buf.len + 2] = (low >> 8).to_byte() + #| buf.data[buf.len + 3] = (low & 0xFF).to_byte() + #| buf.len += 4 + #| } else { + #| abort("Char out of range") + #| } + #|} + #|pub fn Buffer::write_string_utf8(buf : Self, string : StringView) -> Unit { + #| for ch in string { + #| buf.write_char_utf8(ch) + #| } + #|} + #|#alias(write_stringview, deprecated="use write_string_utf16le instead") + #|pub fn Buffer::write_string_utf16le(buf : Self, string : StringView) -> Unit { + #| let len = string.length() + #| buf.grow_if_necessary(buf.len + len * 2) + #| for i in 0..> 8).to_byte() + #| } + #| buf.len += len * 2 + #|} + #|pub fn Buffer::write_string_utf16be(buf : Self, string : StringView) -> Unit { + #| let len = string.length() + #| buf.grow_if_necessary(buf.len + len * 2) + #| for i in 0..> 8).to_byte() + #| } + #| buf.len += len * 2 + #|} + #|pub impl Logger for Buffer with write_view(self : Buffer, value : StringView) -> Unit { + #| self.grow_if_necessary(self.len + value.length() * 2) + #| self.data.blit_from_string( + #| self.len, + #| value.data(), + #| value.start_offset(), + #| value.length(), + #| ) + #| self.len += value.length() * 2 + #|} + #|pub impl Logger for Buffer with write_char(self : Buffer, value : Char) -> Unit { + #| self.grow_if_necessary(self.len + 4) + #| let inc = self.data.set_utf16le_char(self.len, value) + #| self.len += inc + #|} + #|pub fn Buffer::write_byte(self : Buffer, value : Byte) -> Unit { + #| self.grow_if_necessary(self.len + 1) + #| self.data[self.len] = value + #| self.len += 1 + #|} + #|pub fn Buffer::write_iter(self : Buffer, iter : Iter[Byte]) -> Unit { + #| for byte in iter { + #| self.write_byte(byte) + #| } + #|} + #|pub fn Buffer::reset(self : Buffer) -> Unit { + #| self.len = 0 + #|} + #|#alias(contents) + #|pub fn Buffer::to_bytes(self : Buffer) -> Bytes { + #| Bytes::from_array(self.data[0:self.len]) + #|} + #|pub fn Buffer::view(self : Buffer) -> ArrayView[Byte] { + #| self.data[0:self.len] + #|} + #|pub impl Show for Buffer with output(self, logger) { + #| logger.write_string(self.contents().to_unchecked_string()) + #|} + ), + "deprecated.mbt": "", + "sleb128.mbt": ( + #|trait Leb128 { + #| output(Self, Buffer) -> Unit + #|} + #|pub impl Leb128 for Int with output(self, buffer) { + #| for value = self { + #| let byte = value & 0x7f // Get the low 7 bits + #| let next_value = value >> 7 // Arithmetic right shift + #| let sign_bit_set = (byte & 0x40) != 0 + #| let need_more = if value >= 0 { + #| next_value != 0 || sign_bit_set + #| } else { + #| next_value != -1 || !sign_bit_set + #| } + #| if need_more { + #| buffer.write_byte((byte | 0x80).to_byte()) + #| continue next_value + #| } else { + #| buffer.write_byte(byte.to_byte()) + #| break + #| } + #| } + #|} + #|pub impl Leb128 for Int64 with output(self, buffer) { + #| for value = self { + #| let byte = value & 0x7f // Get the low 7 bits + #| let next_value = value >> 7 // Arithmetic right shift + #| let sign_bit_set = (byte & 0x40) != 0 + #| let need_more = if value >= 0 { + #| next_value != 0 || sign_bit_set + #| } else { + #| next_value != -1 || !sign_bit_set + #| } + #| if need_more { + #| buffer.write_byte((byte | 0x80).to_byte()) + #| continue next_value + #| } else { + #| buffer.write_byte(byte.to_byte()) + #| break + #| } + #| } + #|} + #|pub fn[A : Leb128] Buffer::write_leb128(buffer : Buffer, value : A) -> Unit { + #| value.output(buffer) + #|} + ), + "uleb128.mbt": ( + #|pub impl Leb128 for UInt with output(self, buffer) { + #| for value = self { + #| if value < 128 { + #| buffer.write_byte(value.to_byte()) + #| break + #| } else { + #| buffer.write_byte(((value % 128) | 128).to_byte()) + #| continue value / 128 + #| } + #| } + #|} + #|pub impl Leb128 for UInt64 with output(self, buffer) { + #| for value = self { + #| if value < 128 { + #| buffer.write_byte(value.to_byte()) + #| break + #| } else { + #| buffer.write_byte(((value % 128) | 128).to_byte()) + #| continue value / 128 + #| } + #| } + #|} + ) + } ) ///| let moonbitlang_core_builtin_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/builtin", - deps={ "moonbitlang/core/abort": moonbitlang_core_abort_module }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| "moonbitlang/core/abort" - #| ], - #| "test-import": [ - #| "moonbitlang/core/char", - #| "moonbitlang/core/string", - #| "moonbitlang/core/bytes", - #| "moonbitlang/core/int", - #| "moonbitlang/core/double", - #| "moonbitlang/core/uint64", - #| "moonbitlang/core/array", - #| "moonbitlang/core/int64", - #| "moonbitlang/core/uint", - #| "moonbitlang/core/json", - #| "moonbitlang/core/bigint", - #| "moonbitlang/core/ref", - #| "moonbitlang/core/float", - #| "moonbitlang/core/quickcheck", - #| "moonbitlang/core/test", - #| "moonbitlang/core/random", - #| "moonbitlang/core/int16" - #| ], - #| "warn-list": "-test_unqualified_package", - #| "targets": { - #| "int64_js.mbt": ["js"], - #| "int64_nonjs.mbt": ["not", "js"], - #| "arraycore_js.mbt": ["js"], - #| "arraycore_nonjs.mbt": ["not", "js"], - #| "panic_test.mbt": ["not", "native", "llvm"], - #| "panic_wbtest.mbt": ["not", "native", "llvm"], - #| "panic_nonjs_test.mbt": ["wasm", "wasm-gc"], - #| "array_nonjs_test.mbt": ["not", "js"], - #| "stringbuilder_buffer.mbt": ["not", "js"], - #| "stringbuilder_concat.mbt": ["js"], - #| "double_to_int64_js.mbt": ["js"], - #| "double_to_int64_native.mbt": ["native", "llvm"], - #| "double_to_int64_wasm.mbt": ["wasm", "wasm-gc"], - #| "double_to_int.mbt": ["not", "wasm", "wasm-gc"], - #| "double_to_int_wasm.mbt": ["wasm", "wasm-gc"] - #| } - #|} - ), - "array.mbt": ( - #|pub fn[T] Array::from_fixed_array(arr : FixedArray[T]) -> Array[T] { - #| let len = arr.length() - #| let arr2 = Array::make_uninit(len) - #| UninitializedArray::unsafe_blit_fixed(arr2.buffer(), 0, arr, 0, len) - #| arr2 - #|} - #|pub fn[T] Array::make(len : Int, elem : T) -> Array[T] { - #| let arr = Array::make_uninit(len) - #| for i in 0.. T raise?) -> Array[T] raise? { - #| if length <= 0 { - #| [] - #| } else { - #| let array = Array::make_uninit(length) - #| for i in 0.. Int { - #| self.buffer().0.length() - #|} - #|#intrinsic("%array.unsafe_get") - #|pub fn[T] Array::unsafe_get(self : Array[T], idx : Int) -> T { - #| self.buffer()[idx] - #|} - #|#intrinsic("%array.get") - #|#alias("_[_]") - #|pub fn[T] Array::at(self : Array[T], index : Int) -> T { - #| let len = self.length() - #| guard index >= 0 && index < len - #| self.buffer()[index] - #|} - #|pub fn[T] Array::get(self : Array[T], index : Int) -> T? { - #| let len = self.length() - #| guard index >= 0 && index < len else { None } - #| Some(self.unsafe_get(index)) - #|} - #|#intrinsic("%array.unsafe_set") - #|pub fn[T] Array::unsafe_set(self : Array[T], idx : Int, val : T) -> Unit { - #| self.buffer()[idx] = val - #|} - #|#intrinsic("%array.set") - #|#alias("_[_]=_") - #|pub fn[T] Array::set(self : Array[T], index : Int, value : T) -> Unit { - #| let len = self.length() - #| guard index >= 0 && index < len - #| self.buffer()[index] = value - #|} - #|pub impl[T : Eq] Eq for Array[T] with equal(self, other) { - #| let self_len = self.length() - #| let other_len = other.length() - #| guard self_len == other_len else { return false } - #| for i in 0.. Unit { - #| other.blit_to(self, dst_offset=self.length()) - #|} - #|#locals(f) - #|pub fn[T] Array::each(self : Array[T], f : (T) -> Unit raise?) -> Unit raise? { - #| for v in self { - #| f(v) - #| } - #|} - #|#locals(f) - #|pub fn[T] Array::rev_each(self : Array[T], f : (T) -> Unit) -> Unit { - #| let len = self.length() - #| for i in 0.. Unit raise?, - #|) -> Unit raise? { - #| let len = self.length() - #| for i in 0.. Unit raise?, - #|) -> Unit raise? { - #| for i, v in self { - #| f(i, v) - #| } - #|} - #|pub fn[T] Array::clear(self : Array[T]) -> Unit { - #| self.unsafe_truncate_to_length(0) - #|} - #|#locals(f) - #|pub fn[T, U] Array::map( - #| self : Array[T], - #| f : (T) -> U raise?, - #|) -> Array[U] raise? { - #| let arr = Array::make_uninit(self.length()) - #| for i, v in self { - #| arr.unsafe_set(i, f(v)) - #| } - #| arr - #|} - #|#locals(f) - #|#alias(map_inplace, deprecated) - #|pub fn[T] Array::map_in_place( - #| self : Array[T], - #| f : (T) -> T raise?, - #|) -> Unit raise? { - #| for i, v in self { - #| self[i] = f(v) - #| } - #|} - #|#locals(f) - #|pub fn[T, U] Array::mapi( - #| self : Array[T], - #| f : (Int, T) -> U raise?, - #|) -> Array[U] raise? { - #| if self.length() == 0 { - #| return [] - #| } - #| let arr = Array::make_uninit(self.length()) - #| for i, v in self { - #| arr.unsafe_set(i, f(i, v)) - #| } - #| arr - #|} - #|#locals(f) - #|#alias(mapi_inplace, deprecated) - #|pub fn[T] Array::mapi_in_place( - #| self : Array[T], - #| f : (Int, T) -> T raise?, - #|) -> Unit raise? { - #| for i, v in self { - #| self[i] = f(i, v) - #| } - #|} - #|#locals(f) - #|pub fn[T] Array::filter( - #| self : Array[T], - #| f : (T) -> Bool raise?, - #|) -> Array[T] raise? { - #| let arr = [] - #| for v in self { - #| if f(v) { - #| arr.push(v) - #| } - #| } - #| arr - #|} - #|pub fn[T] Array::is_empty(self : Array[T]) -> Bool { - #| self.length() == 0 - #|} - #|#alias(rev_inplace, deprecated) - #|pub fn[T] Array::rev_in_place(self : Array[T]) -> Unit { - #| let len = self.length() - #| for i in 0..<(len / 2) { - #| let temp = self.unsafe_get(i) - #| self.unsafe_set(i, self.unsafe_get(len - i - 1)) - #| self.unsafe_set(len - i - 1, temp) - #| } - #|} - #|pub fn[T] Array::rev(self : Array[T]) -> Array[T] { - #| let len = self.length() - #| let arr = Array::make_uninit(len) - #| for i in 0.. (Array[T], Array[T]) { - #| if index < 0 || index > self.length() { - #| let len = self.length() - #| abort( - #| "index out of bounds: the len is from 0 to \{len} but the index is \{index}", - #| ) - #| } - #| let v1 = Array::make_uninit(index) - #| let v2 = Array::make_uninit(self.length() - index) - #| UninitializedArray::unsafe_blit(v1.buffer(), 0, self.buffer(), 0, index) - #| if index != self.length() { - #| UninitializedArray::unsafe_blit( - #| v2.buffer(), - #| 0, - #| self.buffer(), - #| index, - #| self.length() - index, - #| ) - #| } - #| (v1, v2) - #|} - #|pub fn[T : Eq] Array::contains(self : Array[T], value : T) -> Bool { - #| for v in self { - #| if v == value { - #| break true - #| } - #| } else { - #| false - #| } - #|} - #|pub fn[T : Eq] Array::starts_with(self : Array[T], prefix : Array[T]) -> Bool { - #| if prefix.length() > self.length() { - #| return false - #| } - #| for i in 0.. Bool { - #| if suffix.length() > self.length() { - #| return false - #| } - #| for i in 0.. Array[T]? { - #| if self.starts_with(prefix) { - #| let v = Array::make_uninit(self.length() - prefix.length()) - #| UninitializedArray::unsafe_blit( - #| v.buffer(), - #| 0, - #| self.buffer(), - #| prefix.length(), - #| self.length() - prefix.length(), - #| ) - #| Some(v) - #| } else { - #| None - #| } - #|} - #|pub fn[T : Eq] Array::strip_suffix( - #| self : Array[T], - #| suffix : Array[T], - #|) -> Array[T]? { - #| if self.ends_with(suffix) { - #| let v = Array::make_uninit(self.length() - suffix.length()) - #| let len = self.length() - suffix.length() - #| UninitializedArray::unsafe_blit(v.buffer(), 0, self.buffer(), 0, len) - #| Some(v) - #| } else { - #| None - #| } - #|} - #|pub fn[T : Eq] Array::search(self : Array[T], value : T) -> Int? { - #| for i, v in self { - #| if v == value { - #| break Some(i) - #| } - #| } else { - #| None - #| } - #|} - #|#locals(f) - #|#alias(find_index, deprecated) - #|pub fn[T] Array::search_by(self : Array[T], f : (T) -> Bool) -> Int? { - #| for i, v in self { - #| if f(v) { - #| break Some(i) - #| } - #| } else { - #| None - #| } - #|} - #|pub fn[T : Compare] Array::binary_search( - #| self : Array[T], - #| value : T, - #|) -> Result[Int, Int] { - #| let len = self.length() - #| for i = 0, j = len; i < j; { - #| let h = i + (j - i) / 2 - #| if self.unsafe_get(h) < value { - #| continue h + 1, j - #| } else { - #| continue i, h - #| } - #| } else { - #| if i < len && self.unsafe_get(i) == value { - #| Ok(i) - #| } else { - #| Err(i) - #| } - #| } - #|} - #|#locals(cmp) - #|pub fn[T] Array::binary_search_by( - #| self : Array[T], - #| cmp : (T) -> Int, - #|) -> Result[Int, Int] { - #| let len = self.length() - #| for i = 0, j = len; i < j; { - #| let h = i + (j - i) / 2 - #| if cmp(self.unsafe_get(h)) < 0 { - #| continue h + 1, j - #| } else { - #| continue i, h - #| } - #| } else { - #| if i < len && cmp(self.unsafe_get(i)) == 0 { - #| Ok(i) - #| } else { - #| Err(i) - #| } - #| } - #|} - #|pub fn[T] Array::swap(self : Array[T], i : Int, j : Int) -> Unit { - #| if i >= self.length() || j >= self.length() || i < 0 || j < 0 { - #| let len = self.length() - #| abort( - #| "index out of bounds: the len is from 0 to \{len} but the index is (\{i}, \{j})", - #| ) - #| } - #| let temp = self.unsafe_get(i) - #| self.unsafe_set(i, self.unsafe_get(j)) - #| self.unsafe_set(j, temp) - #|} - #|#locals(f) - #|pub fn[T] Array::retain(self : Array[T], f : (T) -> Bool raise?) -> Unit raise? { - #| let len = self.length() - #| for i = 0, j = 0; i < len; { - #| let item = self.unsafe_get(i) - #| if f(item) { - #| self.unsafe_set(j, item) - #| continue i + 1, j + 1 - #| } - #| continue i + 1, j - #| } else { - #| self.unsafe_truncate_to_length(j) - #| } - #|} - #|pub fn[T] Array::resize(self : Array[T], new_len : Int, f : T) -> Unit { - #| if new_len < 0 { - #| abort("negative new length") - #| } - #| if new_len < self.length() { - #| self.unsafe_truncate_to_length(new_len) - #| } else { - #| let len = self.length() - #| for _ in len.. Array[T] { - #| let mut len = 0 - #| for x in self { - #| len += x.length() - #| } - #| let res = Array::make_uninit(len) - #| let mut i = 0 - #| for xs in self { - #| res.unsafe_blit(i, xs, 0, xs.length()) - #| i += xs.length() - #| } - #| res - #|} - #|pub fn[T] Array::repeat(self : Array[T], times : Int) -> Array[T] { - #| let v = Array::new(capacity=self.length() * times) - #| for i in 0.. B raise?, - #|) -> B raise? { - #| for i = 0, acc = init; i < self.length(); { - #| continue i + 1, f(acc, self[i]) - #| } else { - #| acc - #| } - #|} - #|#locals(f) - #|#alias(fold_right, deprecated) - #|pub fn[A, B] Array::rev_fold( - #| self : Array[A], - #| init~ : B, - #| f : (B, A) -> B raise?, - #|) -> B raise? { - #| for i = self.length() - 1, acc = init; i >= 0; { - #| continue i - 1, f(acc, self[i]) - #| } else { - #| acc - #| } - #|} - #|#locals(f) - #|#alias(fold_lefti, deprecated) - #|pub fn[A, B] Array::foldi( - #| self : Array[A], - #| init~ : B, - #| f : (Int, B, A) -> B raise?, - #|) -> B raise? { - #| for i = 0, acc = init; i < self.length(); { - #| continue i + 1, f(i, acc, self[i]) - #| } else { - #| acc - #| } - #|} - #|#locals(f) - #|#alias(fold_righti, deprecated) - #|pub fn[A, B] Array::rev_foldi( - #| self : Array[A], - #| init~ : B, - #| f : (Int, B, A) -> B raise?, - #|) -> B raise? { - #| let len = self.length() - #| for i = len - 1, acc = init; i >= 0; { - #| continue i - 1, f(len - i - 1, acc, self[i]) - #| } else { - #| acc - #| } - #|} - #|pub fn[T : Eq] Array::dedup(self : Array[T]) -> Unit { - #| if self.is_empty() { - #| return - #| } - #| let mut w = 1 - #| for i in 1.. Bool) -> Array[T] { - #| let removed = [] - #| let mut write = 0 - #| for read in 0.. Array[ArrayView[T]] { - #| guard size > 0 - #| let len = self.length() - #| if len == 0 { - #| return [] - #| } - #| let num_chunks = (len + size - 1) / size - #| Array::makei(num_chunks, i => { - #| let start = i * size - #| let end = Int::min(start + size, len) - #| self[start:end] - #| }) - #|} - #|#locals(pred) - #|pub fn[T] Array::chunk_by( - #| self : Array[T], - #| pred : (T, T) -> Bool raise?, - #|) -> Array[ArrayView[T]] raise? { - #| let chunks = [] - #| if self.is_empty() { - #| return chunks - #| } - #| let mut start = 0 - #| for i in 1.. Array[ArrayView[T]] { - #| guard size > 0 - #| let len = self.length() - size + 1 - #| if len < 1 { - #| return [] - #| } - #| Array::makei(len, i => self[i:i + size]) - #|} - #|pub fn[T] Array::suffixes( - #| self : Array[T], - #| include_empty? : Bool = false, - #|) -> Iterator[ArrayView[T]] { - #| self[:].suffixes(include_empty~) - #|} - #|#locals(pred) - #|pub fn[T] Array::split( - #| self : Array[T], - #| pred : (T) -> Bool raise?, - #|) -> Array[Array[T]] raise? { - #| let chunks = [] - #| let mut i = 0 - #| while i < self.length() { - #| let chunk = [] - #| while i < self.length() && !pred(self[i]) { - #| chunk.push(self[i]) - #| i = i + 1 - #| } - #| chunks.push(chunk) - #| i = i + 1 - #| } - #| chunks - #|} - #|pub fn[T] Array::iter(self : Array[T]) -> Iter[T] { - #| self.iterator().iter() - #|} - #|pub fn[T] Array::rev_iter(self : Array[T]) -> Iter[T] { - #| self.rev_iterator().iter() - #|} - #|pub fn[A] Array::iter2(self : Array[A]) -> Iter2[Int, A] { - #| self.Iter2().iter2() - #|} - #|pub impl[T] Default for Array[T] with default() { - #| [] - #|} - #|#internal(unsafe, "Panic if the array is empty on non-JS backend.") - #|#doc(hidden) - #|pub fn[A] Array::unsafe_pop_back(self : Array[A]) -> Unit { - #| self.unsafe_pop() |> ignore - #|} - #|pub fn[A] Array::truncate(self : Array[A], len : Int) -> Unit { - #| guard len >= 0 && len < self.length() else { return } - #| self.unsafe_truncate_to_length(len) - #|} - #|pub fn[A] Array::retain_map(self : Array[A], f : (A) -> A?) -> Unit { - #| if self.is_empty() { - #| return - #| } - #| let buf = self.buffer() - #| let len = self.length() - #| let mut write_idx = 0 - #| for read_idx in 0.. { - #| buf[write_idx] = new_val - #| write_idx += 1 - #| } - #| None => () - #| } - #| } - #| self.unsafe_truncate_to_length(write_idx) - #|} - #|pub fn[T] Array::from_iter(iter : Iter[T]) -> Array[T] { - #| iter.collect() - #|} - #|pub fn[T] Array::from_iterator(iter : Iterator[T]) -> Array[T] { - #| iter.collect() - #|} - #|pub fn[T] Array::push_iter(self : Self[T], iter : Iter[T]) -> Unit { - #| for x in iter { - #| self.push(x) - #| } - #|} - #|pub fn[T] Array::shuffle_in_place( - #| self : Array[T], - #| rand~ : (Int) -> Int, - #|) -> Unit { - #| let n = self.length() - #| for i = n - 1; i > 0; i = i - 1 { - #| let j = rand(i + 1) % (i + 1) - #| self.swap(i, j) - #| } - #|} - #|pub fn[T] Array::shuffle(self : Array[T], rand~ : (Int) -> Int) -> Array[T] { - #| let new_arr = self.copy() - #| Array::shuffle_in_place(new_arr, rand~) - #| new_arr - #|} - #|pub fn[A, B] Array::filter_map( - #| self : Array[A], - #| f : (A) -> B? raise?, - #|) -> Array[B] raise? { - #| let result = [] - #| for x in self { - #| if f(x) is Some(x) { - #| result.push(x) - #| } - #| } - #| result - #|} - #|pub fn[A] Array::last(self : Array[A]) -> A? { - #| match self { - #| [] => None - #| [.., last] => Some(last) - #| } - #|} - #|pub fn[A, B] Array::zip(self : Array[A], other : Array[B]) -> Array[(A, B)] { - #| let length = if self.length() < other.length() { - #| self.length() - #| } else { - #| other.length() - #| } - #| Array::makei(length, i => (self[i], other[i])) - #|} - #|pub fn[T1, T2] Array::unzip(self : Array[(T1, T2)]) -> (Array[T1], Array[T2]) { - #| let arr1 : Array[T1] = Array::new(capacity=self.length()) - #| let arr2 : Array[T2] = Array::new(capacity=self.length()) - #| for pair in self { - #| let (x, y) = pair - #| arr1.push(x) - #| arr2.push(y) - #| } - #| (arr1, arr2) - #|} - #|pub fn[A, B] Array::zip_to_iter2( - #| self : Array[A], - #| other : Array[B], - #|) -> Iter2[A, B] { - #| let length = if self.length() < other.length() { - #| self.length() - #| } else { - #| other.length() - #| } - #| let mut i = 0 - #| Iter2::new(() => { - #| guard i < length else { None } - #| let elem = (self[i], other[i]) - #| i += 1 - #| Some(elem) - #| }).iter2() - #|} - #|pub fn[A : ToStringView] Array::join( - #| self : Array[A], - #| separator : StringView, - #|) -> String { - #| self[:].join(separator) - #|} - #|pub fn[X] Array::iterator(self : Array[X]) -> Iterator[X] { - #| self[:].iterator() - #|} - #|pub fn[X] Array::rev_iterator(self : Array[X]) -> Iterator[X] { - #| self[:].rev_iterator() - #|} - #|pub fn[X] Array::Iter2(self : Array[X]) -> Iter2[Int, X] { - #| self[:].Iter2() - #|} - ), - "array_block.mbt": ( - #|#internal(unsafe, "Panic if the indices or length are out of bounds") - #|#doc(hidden) - #|pub fn[A] Array::unsafe_blit( - #| dst : Array[A], - #| dst_offset : Int, - #| src : Array[A], - #| src_offset : Int, - #| len : Int, - #|) -> Unit { - #| FixedArray::unsafe_blit( - #| dst.buffer().0, - #| dst_offset, - #| src.buffer().0, - #| src_offset, - #| len, - #| ) - #|} - #|pub fn[A] Array::unsafe_blit_fixed( - #| dst : Array[A], - #| dst_offset : Int, - #| src : FixedArray[A], - #| src_offset : Int, - #| len : Int, - #|) -> Unit { - #| UninitializedArray::unsafe_blit_fixed( - #| dst.buffer(), - #| dst_offset, - #| src, - #| src_offset, - #| len, - #| ) - #|} - #|#label_migration(src_offset, fill=false, msg="Use ArrayView::blit_to instead") - #|#label_migration(len, fill=false, msg="Use ArrayView::blit_to instead") - #|pub fn[A] Array::blit_to( - #| self : Array[A], - #| dst : Array[A], - #| len? : Int = self.length(), - #| src_offset? : Int = 0, - #| dst_offset? : Int = 0, - #|) -> Unit { - #| guard len >= 0 && - #| dst_offset >= 0 && - #| src_offset >= 0 && - #| dst_offset <= dst.length() && - #| src_offset + len <= self.length() - #| if dst_offset + len > dst.length() { - #| dst.unsafe_grow_to_length(dst_offset + len) - #| } - #| Array::unsafe_blit(dst, dst_offset, self, src_offset, len) - #|} - #|pub fn[A] ArrayView::blit_to( - #| self : ArrayView[A], - #| dst : Array[A], - #| dst_offset? : Int = 0, - #|) -> Unit { - #| let len = self.len() - #| guard dst_offset >= 0 && dst_offset <= dst.length() - #| if dst_offset + len > dst.length() { - #| dst.unsafe_grow_to_length(dst_offset + len) - #| } - #| UninitializedArray::unsafe_blit( - #| dst.buffer(), - #| dst_offset, - #| self.buf(), - #| self.start(), - #| len, - #| ) - #|} - #|test "Array::blit_to/basic" { - #| let src = [1, 2, 3, 4, 5] - #| let dst = [0, 0, 0, 0, 0] - #| src[1:4].blit_to(dst, dst_offset=2) - #| inspect(dst, content="[0, 0, 2, 3, 4]") - #| let src = [1, 2, 3, 4, 5] - #| let dst = [0, 0, 0, 0, 0] - #| src[0:3].blit_to(dst) - #| inspect(dst, content="[1, 2, 3, 0, 0]") - #|} - #|test "Array::blit_to/zero_length" { - #| let src = [1, 2, 3] - #| let dst = [4, 5, 6] - #| src[0:0].blit_to(dst) - #| inspect(dst, content="[4, 5, 6]") - #|} - #|test "Array::blit_to/grow_destination" { - #| let src = [1, 2, 3, 4, 5] - #| let dst = [0, 0] - #| src[0:3].blit_to(dst, dst_offset=1) - #| inspect(dst, content="[0, 1, 2, 3]") - #|} - #|test "Array::blit_to/edge_cases" { - #| let src = [1, 2, 3, 4, 5] - #| let dst = [0, 0, 0, 0, 0] - #| src[1:3].blit_to(dst, dst_offset=2) - #| inspect(dst, content="[0, 0, 2, 3, 0]") - #| src[0:2].blit_to(src, dst_offset=3) - #| inspect(src, content="[1, 2, 3, 1, 2]") - #| src[0:0].blit_to(dst, dst_offset=0) - #| inspect(dst, content="[0, 0, 2, 3, 0]") - #| src[0:5].blit_to(dst) - #| inspect(dst, content="[1, 2, 3, 1, 2]") - #|} - #|test "panic Array::blit_to/boundary_cases1" { - #| let src = [1, 2, 3, 4, 5] - #| let dst = [0, 0, 0, 0, 0] - #| ignore(src[3:1].blit_to(dst)) - #|} - #|test "panic Array::blit_to/boundary_cases2" { - #| let src = [1, 2, 3, 4, 5] - #| let dst = [0, 0, 0, 0, 0] - #| ignore(src[-1:1].blit_to(dst)) - #|} - #|test "panic Array::blit_to/boundary_cases3" { - #| let src = [1, 2, 3, 4, 5] - #| let dst = [0, 0, 0, 0, 0] - #| ignore(src[0:6].blit_to(dst)) - #|} - #|test "panic Array::blit_to/boundary_cases4" { - #| let src = [1, 2, 3, 4, 5] - #| let dst = [0, 0, 0, 0, 0] - #| ignore(src[0:5].blit_to(dst, dst_offset=6)) - #|} - #|test "Array::blit_to - random cases" { - #| let src = [10, 20, 30, 40, 50] - #| let dst = [0, 0, 0, 0, 0] - #| src[2:4].blit_to(dst, dst_offset=1) - #| inspect(dst, content="[0, 30, 40, 0, 0]") - #| src[1:4].blit_to(dst, dst_offset=2) - #| inspect(dst, content="[0, 30, 20, 30, 40]") - #| src[4:5].blit_to(dst, dst_offset=4) - #| inspect(dst, content="[0, 30, 20, 30, 50]") - #|} - #|test "Array::blit_to - boundary cases" { - #| let src = [1, 2, 3, 4, 5] - #| let dst = [0, 0, 0, 0, 0] - #| src[4:5].blit_to(dst, dst_offset=0) - #| inspect(dst, content="[5, 0, 0, 0, 0]") - #| src[0:1].blit_to(dst, dst_offset=4) - #| inspect(dst, content="[5, 0, 0, 0, 1]") - #| src[3:5].blit_to(dst, dst_offset=3) - #| inspect(dst, content="[5, 0, 0, 4, 5]") - #|} - #|test "Array::unsafe_blit_fixed" { - #| let src = FixedArray::make(3, 1) // Create a FixedArray with 3 elements of value 1 - #| let dst = Array::make(5, 0) // Create an Array with 5 elements of value 0 - #| Array::unsafe_blit_fixed(dst, 1, src, 0, 2) // Copy 2 elements from src[0] to dst[1] - #| inspect(dst, content="[0, 1, 1, 0, 0]") - #|} - #|test "ArrayView::blit_to/basic" { - #| let src = [1, 2, 3, 4, 5] - #| let view = src[1:4] // view = [2, 3, 4] - #| let dst = [0, 0, 0, 0, 0] - #| view.blit_to(dst) - #| inspect(dst, content="[2, 3, 4, 0, 0]") - #|} - #|test "ArrayView::blit_to/with_offset" { - #| let src = [1, 2, 3, 4, 5] - #| let view = src[1:4] // view = [2, 3, 4] - #| let dst = [0, 0, 0, 0, 0] - #| view.blit_to(dst, dst_offset=2) - #| inspect(dst, content="[0, 0, 2, 3, 4]") - #|} - #|test "ArrayView::blit_to/grow_destination" { - #| let src = [1, 2, 3, 4, 5] - #| let view = src[1:4] // view = [2, 3, 4] - #| let dst = [0, 0] - #| view.blit_to(dst, dst_offset=1) - #| inspect(dst, content="[0, 2, 3, 4]") - #|} - #|test "ArrayView::blit_to/empty_view" { - #| let src = [1, 2, 3, 4, 5] - #| let view = src[2:2] // empty view - #| let dst = [0, 0, 0] - #| view.blit_to(dst) - #| inspect(dst, content="[0, 0, 0]") - #|} - #|test "ArrayView::blit_to/nested_view" { - #| let src = [1, 2, 3, 4, 5, 6, 7] - #| let view1 = src[1:6] // [2, 3, 4, 5, 6] - #| let view2 = view1[1:4] // [3, 4, 5] - #| let dst = [0, 0, 0, 0, 0] - #| view2.blit_to(dst, dst_offset=1) - #| inspect(dst, content="[0, 3, 4, 5, 0]") - #|} - #|test "panic ArrayView::blit_to/invalid_offset" { - #| let src = [1, 2, 3, 4, 5] - #| let view = src[1:4] - #| let dst = [0, 0, 0] - #| ignore(view.blit_to(dst, dst_offset=-1)) - #|} - #|test "panic ArrayView::blit_to/offset_exceeds_length" { - #| let src = [1, 2, 3, 4, 5] - #| let view = src[1:4] - #| let dst = [0, 0, 0] - #| ignore(view.blit_to(dst, dst_offset=4)) - #|} - ), - "array_sort.mbt": ( - #|pub fn[T] MutArrayView::sort_by(self : Self[T], cmp : (T, T) -> Int) -> Unit { - #| fixed_quick_sort_by(self, cmp, None, fixed_get_limit(self.length())) - #|} - #|pub fn[T : Compare] MutArrayView::sort(self : MutArrayView[T]) -> Unit { - #| fixed_quick_sort(self, None, fixed_get_limit(self.length())) - #|} - #|pub fn[T : Compare] MutArrayView::stable_sort(self : MutArrayView[T]) -> Unit { - #| timsort(self) - #|} - #|pub fn[T, K : Compare] MutArrayView::sort_by_key( - #| self : Self[T], - #| map : (T) -> K, - #|) -> Unit { - #| fixed_quick_sort_by( - #| self, - #| (a, b) => map(a).compare(map(b)), - #| None, - #| fixed_get_limit(self.length()), - #| ) - #|} - #|pub fn[T : Compare] ArrayView::is_sorted(self : ArrayView[T]) -> Bool { - #| for i in 1.. self[i] { - #| break false - #| } - #| } else { - #| true - #| } - #|} - #|pub fn[T : Compare] Array::is_sorted(self : Array[T]) -> Bool { - #| self[:].is_sorted() - #|} - #|pub fn[T : Compare] Array::sort(self : Array[T]) -> Unit { - #| self.mut_view().sort() - #|} - #|pub fn[T, K : Compare] Array::sort_by_key( - #| self : Array[T], - #| map : (T) -> K, - #|) -> Unit { - #| self.mut_view().sort_by_key(map) - #|} - #|pub fn[T] Array::sort_by(self : Array[T], cmp : (T, T) -> Int) -> Unit { - #| self.mut_view().sort_by(cmp) - #|} - #|pub fn[T : Compare] FixedArray::is_sorted(arr : FixedArray[T]) -> Bool { - #| arr[:].is_sorted() - #|} - #|pub fn[T : Compare] FixedArray::stable_sort(self : FixedArray[T]) -> Unit { - #| self.mut_view().stable_sort() - #|} - #|pub fn[T, K : Compare] FixedArray::sort_by_key( - #| self : FixedArray[T], - #| map : (T) -> K, - #|) -> Unit { - #| self.mut_view().sort_by_key(map) - #|} - #|test "FixedArray::sort_by_key/basic" { - #| let arr : FixedArray[_] = [3, 1, 4, 1, 5] - #| arr.sort_by_key(x => x) - #| inspect(arr, content="[1, 1, 3, 4, 5]") - #| let arr2 : FixedArray[_] = [3, 1, 4, 1, 5] - #| arr2.sort_by_key(x => -x) - #| inspect(arr2, content="[5, 4, 3, 1, 1]") - #|} - #|pub fn[T] FixedArray::sort_by( - #| self : FixedArray[T], - #| cmp : (T, T) -> Int, - #|) -> Unit { - #| self.mut_view().sort_by(cmp) - #|} - #|test "FixedArray::sort_by: basic functionality" { - #| let arr : FixedArray[_] = [5, 3, 2, 4, 1] - #| arr.sort_by((a, b) => a - b) - #| inspect(arr, content="[1, 2, 3, 4, 5]") - #|} - #|test "FixedArray::sort_by: edge cases" { - #| let empty_arr : FixedArray[Int] = [] - #| empty_arr.sort_by((a, b) => a - b) - #| inspect(empty_arr, content="[]") - #| let single_element_arr : FixedArray[_] = [1] - #| single_element_arr.sort_by((a, b) => a - b) - #| inspect(single_element_arr, content="[1]") - #|} - #|test "FixedArray::sort_by: random cases" { - #| let random_arr1 : FixedArray[_] = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5] - #| random_arr1.sort_by((a, b) => a - b) - #| inspect(random_arr1, content="[1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9]") - #| let random_arr2 : FixedArray[_] = [7, 1, 8, 2, 8, 1, 8, 2, 8, 4, 5, 9] - #| random_arr2.sort_by((a, b) => a - b) - #| inspect(random_arr2, content="[1, 1, 2, 2, 4, 5, 7, 8, 8, 8, 8, 9]") - #| let random_arr3 : FixedArray[_] = [10, -1, 0, 10, -1, 0, 10, -1, 0] - #| random_arr3.sort_by((a, b) => a - b) - #| inspect(random_arr3, content="[-1, -1, -1, 0, 0, 0, 10, 10, 10]") - #|} - #|test "FixedArray::sort_by: large array" { - #| let large_arr = FixedArray::makei(1000, i => 1000 - i) - #| large_arr.sort_by((a, b) => a - b) - #| let expected = FixedArray::makei(1000, i => i + 1) - #| inspect(large_arr, content=expected.to_string()) - #|} - #|test "FixedArray::sort_by: negative numbers" { - #| let negative_arr : FixedArray[_] = [-5, -3, -2, -4, -1] - #| negative_arr.sort_by((a, b) => a - b) - #| inspect(negative_arr, content="[-5, -4, -3, -2, -1]") - #|} - #|test "FixedArray::sort_by: mixed positive and negative numbers" { - #| let mixed_arr : FixedArray[_] = [-5, 3, -2, 4, -1] - #| mixed_arr.sort_by((a, b) => a - b) - #| inspect(mixed_arr, content="[-5, -2, -1, 3, 4]") - #|} - ), - "array_sort_by_impl.mbt": ( - #|fn[T] fixed_quick_sort_by( - #| arr : MutArrayView[T], - #| cmp : (T, T) -> Int, - #| pred : T?, - #| limit : Int, - #|) -> Unit { - #| let mut limit = limit - #| let mut arr = arr - #| let mut pred = pred - #| let mut was_partitioned = true - #| let mut balanced = true - #| let bubble_sort_len = 16 - #| while true { - #| let len = arr.length() - #| if len <= bubble_sort_len { - #| if len >= 2 { - #| fixed_bubble_sort_by(arr, cmp) - #| } - #| return - #| } - #| if limit == 0 { - #| fixed_heap_sort_by(arr, cmp) - #| return - #| } - #| let (pivot_index, likely_sorted) = fixed_choose_pivot_by(arr, cmp) - #| if was_partitioned && balanced && likely_sorted { - #| if fixed_try_bubble_sort_by(arr, cmp) { - #| return - #| } - #| } - #| let (pivot, partitioned) = fixed_partition_by(arr, cmp, pivot_index) - #| was_partitioned = partitioned - #| balanced = minimum(pivot, len - pivot) >= len / 8 - #| if !balanced { - #| limit -= 1 - #| } - #| if pred is Some(pred) { - #| if cmp(pred, arr[pivot]) == 0 { - #| let mut i = pivot - #| while i < len && cmp(pred, arr[i]) == 0 { - #| i = i + 1 - #| } - #| arr = arr.slice(i, len) - #| continue - #| } - #| } - #| let left = arr.slice(0, pivot) - #| let right = arr.slice(pivot + 1, len) - #| if left.length() < right.length() { - #| fixed_quick_sort_by(left, cmp, pred, limit) - #| pred = Some(arr[pivot]) - #| arr = right - #| } else { - #| fixed_quick_sort_by(right, cmp, Some(arr[pivot]), limit) - #| arr = left - #| } - #| } - #|} - #|fn[T] fixed_try_bubble_sort_by( - #| arr : MutArrayView[T], - #| cmp : (T, T) -> Int, - #|) -> Bool { - #| let max_tries = 8 - #| let mut tries = 0 - #| for i in 1.. 0 && cmp(arr[j - 1], arr[j]) > 0; j = j - 1 { - #| sorted = false - #| arr.swap(j, j - 1) - #| } - #| if !sorted { - #| tries += 1 - #| if tries > max_tries { - #| return false - #| } - #| } - #| } - #| true - #|} - #|fn[T] fixed_bubble_sort_by(arr : MutArrayView[T], cmp : (T, T) -> Int) -> Unit { - #| for i in 1.. 0 && cmp(arr[j - 1], arr[j]) > 0; j = j - 1 { - #| arr.swap(j, j - 1) - #| } - #| } - #|} - #|test "try_bubble_sort" { - #| let arr : FixedArray[_] = [8, 7, 6, 5, 4, 3, 2, 1] - #| let sorted = fixed_try_bubble_sort_by(arr.mut_view(), (a, b) => a - b) - #| inspect(sorted, content="true") - #| assert_eq(arr, [1, 2, 3, 4, 5, 6, 7, 8]) - #|} - #|fn[T] fixed_partition_by( - #| arr : MutArrayView[T], - #| cmp : (T, T) -> Int, - #| pivot_index : Int, - #|) -> (Int, Bool) { - #| arr.swap(pivot_index, arr.length() - 1) - #| let pivot = arr[arr.length() - 1] - #| let mut i = 0 - #| let mut partitioned = true - #| for j in 0..<(arr.length() - 1) { - #| if cmp(arr[j], pivot) < 0 { - #| if i != j { - #| arr.swap(i, j) - #| partitioned = false - #| } - #| i = i + 1 - #| } - #| } - #| arr.swap(i, arr.length() - 1) - #| (i, partitioned) - #|} - #|fn[T] fixed_choose_pivot_by( - #| arr : MutArrayView[T], - #| cmp : (T, T) -> Int, - #|) -> (Int, Bool) { - #| let len = arr.length() - #| let use_median_of_medians = 50 - #| let max_swaps = 4 * 3 - #| let mut swaps = 0 - #| let b = len / 4 * 2 - #| if len >= 8 { - #| let a = len / 4 * 1 - #| let c = len / 4 * 3 - #| let sort_2 = (a : Int, b : Int) => if cmp(arr[a], arr[b]) > 0 { - #| arr.swap(a, b) - #| swaps += 1 - #| } - #| let sort_3 = (a : Int, b : Int, c : Int) => { - #| sort_2(a, b) - #| sort_2(b, c) - #| sort_2(a, b) - #| } - #| if len > use_median_of_medians { - #| sort_3(a - 1, a, a + 1) - #| sort_3(b - 1, b, b + 1) - #| sort_3(c - 1, c, c + 1) - #| } - #| sort_3(a, b, c) - #| } - #| if swaps == max_swaps { - #| arr.rev_in_place() - #| (len - b - 1, true) - #| } else { - #| (b, swaps == 0) - #| } - #|} - #|fn[T] fixed_heap_sort_by(arr : MutArrayView[T], cmp : (T, T) -> Int) -> Unit { - #| let len = arr.length() - #| for i = len / 2 - 1; i >= 0; i = i - 1 { - #| fixed_sift_down_by(arr, i, cmp) - #| } - #| for i = len - 1; i > 0; i = i - 1 { - #| arr.swap(0, i) - #| fixed_sift_down_by(arr.slice(0, i), 0, cmp) - #| } - #|} - #|fn[T] fixed_sift_down_by( - #| arr : MutArrayView[T], - #| index : Int, - #| cmp : (T, T) -> Int, - #|) -> Unit { - #| let mut index = index - #| let len = arr.length() - #| let mut child = index * 2 + 1 - #| while child < len { - #| if child + 1 < len && cmp(arr[child], arr[child + 1]) < 0 { - #| child = child + 1 - #| } - #| if cmp(arr[index], arr[child]) >= 0 { - #| return - #| } - #| arr.swap(index, child) - #| index = child - #| child = index * 2 + 1 - #| } - #|} - #|test "heap_sort" { - #| fixed_test_sort(arr => fixed_heap_sort_by(arr.mut_view(), (a, b) => a - b)) - #|} - #|test "bubble_sort" { - #| fixed_test_sort(arr => fixed_bubble_sort_by(arr.mut_view(), (a, b) => a - b)) - #|} - #|test "sort" { - #| fixed_test_sort(arr => arr.sort()) - #|} - #|test "sort_by" { - #| let arr = [5, 1, 3, 4, 2] - #| arr.mut_view().sort_by_key(x => -x) - #| assert_eq(arr, [5, 4, 3, 2, 1]) - #|} - #|test "sort_by_fallback" { - #| let arr = FixedArray::makei(100, i => if i % 2 == 0 { 1 } else { 0 }) - #| arr - #| .mut_view() - #| .sort_by( - #| (a, b) => if a < b { -1 } else { 1 }, - #| ) - #| assert_true(arr.is_sorted()) - #|} - ), - "array_sort_impl.mbt": ( - #|priv struct TimSortRun { - #| len : Int - #| start : Int - #|} - #|fn[T : Compare] timsort(arr : MutArrayView[T]) -> Unit { - #| let max_insertion = 20 - #| let len = arr.length() - #| if len <= max_insertion { - #| MutArrayView::insertion_sort(arr) - #| } - #| let mut end = 0 - #| let mut start = 0 - #| let runs : Array[TimSortRun] = [] - #| while end < len { - #| let (streak_end, was_reversed) = find_streak(arr.mut_view(start~)) - #| end += streak_end - #| if was_reversed { - #| arr.mut_view(start~, end~).rev_in_place() - #| } - #| end = provide_sorted_batch(arr, start, end) - #| runs.push({ start, len: end - start }) - #| start = end - #| while true { - #| guard collapse(runs, len) is Some(r) else { break } - #| let left = runs[r] - #| let right = runs[r + 1] - #| merge(arr.slice(left.start, right.start + right.len), left.len) - #| runs[r + 1] = { start: left.start, len: left.len + right.len } - #| runs.remove(r) |> ignore - #| } - #| } - #|} - #|fn[T : Compare] MutArrayView::insertion_sort(arr : MutArrayView[T]) -> Unit { - #| for i in 1.. 0 && arr[j] < arr[j - 1]; j = j - 1 { - #| arr.swap(j, j - 1) - #| } - #| } - #|} - #|fn[T : Compare] merge(arr : MutArrayView[T], mid : Int) -> Unit { - #| let buf_len = arr.length() - mid - #| let buf : FixedArray[T] = FixedArray::make(buf_len, arr[mid]) - #| for i in 0..= - #| 0 && - #| p2 >= 0; { - #| if arr[p1] > buf[p2] { - #| arr[p] = arr[p1] - #| continue p1 - 1, p2, p - 1 - #| } else { - #| arr[p] = buf[p2] - #| continue p1, p2 - 1, p - 1 - #| } - #| } else { - #| p2 - #| } - #| for i = buf_remaining; i >= 0; i = i - 1 { - #| arr[i] = buf[i] - #| } - #|} - #|fn[T : Compare] find_streak(arr : MutArrayView[T]) -> (Int, Bool) { - #| let len = arr.length() - #| if len < 2 { - #| return (len, false) - #| } - #| let assume_reverse = arr[1] < arr[0] - #| if assume_reverse { - #| for end = 2 { - #| if end < len && arr[end] < arr[end - 1] { - #| continue end + 1 - #| } else { - #| break (end, true) - #| } - #| } - #| } else { - #| for end = 2 { - #| if end < len && arr[end] >= arr[end - 1] { - #| continue end + 1 - #| } else { - #| break (end, false) - #| } - #| } - #| } - #|} - #|fn[T : Compare] provide_sorted_batch( - #| arr : MutArrayView[T], - #| start : Int, - #| end : Int, - #|) -> Int { - #| let len = arr.length() - #| let min_insertion_run = 10 - #| let start_end_diff = end - start - #| if start_end_diff < min_insertion_run && end < len { - #| let sort_end = minimum(len, start + min_insertion_run) - #| MutArrayView::insertion_sort(arr.slice(start, sort_end)) - #| sort_end - #| } else { - #| end - #| } - #|} - #|fn collapse(runs : Array[TimSortRun], stop : Int) -> Int? { - #| let n : Int = runs.length() - #| if n >= 2 && - #| ( - #| runs[n - 1].start + runs[n - 1].len == stop || - #| runs[n - 2].len <= runs[n - 1].len || - #| (n >= 3 && runs[n - 3].len <= runs[n - 2].len + runs[n - 1].len) || - #| (n >= 4 && runs[n - 4].len <= runs[n - 3].len + runs[n - 2].len) - #| ) { - #| if n >= 3 && runs[n - 3].len < runs[n - 1].len { - #| Some(n - 3) - #| } else { - #| Some(n - 2) - #| } - #| } else { - #| None - #| } - #|} - #|pub fn[T : Compare] FixedArray::sort(self : FixedArray[T]) -> Unit { - #| self.mut_view().sort() - #|} - #|fn[T] MutArrayView::slice( - #| arr : MutArrayView[T], - #| start : Int, - #| end : Int, - #|) -> MutArrayView[T] { - #| arr.mut_view(start~, end~) - #|} - #|fn[T] MutArrayView::swap(arr : MutArrayView[T], i : Int, j : Int) -> Unit { - #| let temp = arr[i] - #| arr[i] = arr[j] - #| arr[j] = temp - #|} - #|fn[T] MutArrayView::rev_in_place(arr : MutArrayView[T]) -> Unit { - #| let len = arr.length() - #| let mid_len = len / 2 - #| for i in 0.. Unit { - #| let mut limit = limit - #| let mut arr = arr - #| let mut pred = pred - #| let mut was_partitioned = true - #| let mut balanced = true - #| let bubble_sort_len = 16 - #| while true { - #| let len = arr.length() - #| if len <= bubble_sort_len { - #| if len >= 2 { - #| fixed_bubble_sort(arr) - #| } - #| return - #| } - #| if limit == 0 { - #| fixed_heap_sort(arr) - #| return - #| } - #| let (pivot_index, likely_sorted) = fixed_choose_pivot(arr) - #| if was_partitioned && balanced && likely_sorted { - #| if fixed_try_bubble_sort(arr) { - #| return - #| } - #| } - #| let (pivot, partitioned) = fixed_partition(arr, pivot_index) - #| was_partitioned = partitioned - #| balanced = minimum(pivot, len - pivot) >= len / 8 - #| if !balanced { - #| limit -= 1 - #| } - #| if pred is Some(pred) { - #| if pred == arr[pivot] { - #| let mut i = pivot - #| while i < len && pred == arr[i] { - #| i = i + 1 - #| } - #| arr = arr.slice(i, len) - #| continue - #| } - #| } - #| let left = arr.slice(0, pivot) - #| let right = arr.slice(pivot + 1, len) - #| if left.length() < right.length() { - #| fixed_quick_sort(left, pred, limit) - #| pred = Some(arr[pivot]) - #| arr = right - #| } else { - #| fixed_quick_sort(right, Some(arr[pivot]), limit) - #| arr = left - #| } - #| } - #|} - #|fn fixed_get_limit(len : Int) -> Int { - #| let mut len = len - #| let mut limit = 0 - #| while len > 0 { - #| len = len / 2 - #| limit += 1 - #| } - #| limit - #|} - #|fn[T : Compare] fixed_try_bubble_sort(arr : MutArrayView[T]) -> Bool { - #| let max_tries = 8 - #| let mut tries = 0 - #| for i in 1.. 0 && arr[j - 1] > arr[j]; j = j - 1 { - #| sorted = false - #| arr.swap(j, j - 1) - #| } - #| if !sorted { - #| tries += 1 - #| if tries > max_tries { - #| return false - #| } - #| } - #| } - #| true - #|} - #|fn[T : Compare] fixed_bubble_sort(arr : MutArrayView[T]) -> Unit { - #| for i in 1.. 0 && arr[j - 1] > arr[j]; j = j - 1 { - #| arr.swap(j, j - 1) - #| } - #| } - #|} - #|test "fixed_try_bubble_sort" { - #| let arr : FixedArray[_] = [8, 7, 6, 5, 4, 3, 2, 1] - #| let sorted = fixed_try_bubble_sort(arr.mut_view()) - #| inspect(sorted, content="true") - #| assert_eq(arr, [1, 2, 3, 4, 5, 6, 7, 8]) - #|} - #|fn[T : Compare] fixed_partition( - #| arr : MutArrayView[T], - #| pivot_index : Int, - #|) -> (Int, Bool) { - #| arr.swap(pivot_index, arr.length() - 1) - #| let pivot = arr[arr.length() - 1] - #| let mut i = 0 - #| let mut partitioned = true - #| for j in 0..<(arr.length() - 1) { - #| if arr[j] < pivot { - #| if i != j { - #| arr.swap(i, j) - #| partitioned = false - #| } - #| i = i + 1 - #| } - #| } - #| arr.swap(i, arr.length() - 1) - #| (i, partitioned) - #|} - #|fn[T : Compare] fixed_choose_pivot(arr : MutArrayView[T]) -> (Int, Bool) { - #| let len = arr.length() - #| let use_median_of_medians = 50 - #| let max_swaps = 4 * 3 - #| let mut swaps = 0 - #| let b = len / 4 * 2 - #| if len >= 8 { - #| let a = len / 4 * 1 - #| let c = len / 4 * 3 - #| let sort_2 = (a : Int, b : Int) => if arr[a] > arr[b] { - #| arr.swap(a, b) - #| swaps += 1 - #| } - #| let sort_3 = (a : Int, b : Int, c : Int) => { - #| sort_2(a, b) - #| sort_2(b, c) - #| sort_2(a, b) - #| } - #| if len > use_median_of_medians { - #| sort_3(a - 1, a, a + 1) - #| sort_3(b - 1, b, b + 1) - #| sort_3(c - 1, c, c + 1) - #| } - #| sort_3(a, b, c) - #| } - #| if swaps == max_swaps { - #| arr.rev_in_place() - #| (len - b - 1, true) - #| } else { - #| (b, swaps == 0) - #| } - #|} - #|fn[T : Compare] fixed_heap_sort(arr : MutArrayView[T]) -> Unit { - #| let len = arr.length() - #| for i = len / 2 - 1; i >= 0; i = i - 1 { - #| fixed_sift_down(arr, i) - #| } - #| for i = len - 1; i > 0; i = i - 1 { - #| arr.swap(0, i) - #| fixed_sift_down(arr.slice(0, i), 0) - #| } - #|} - #|fn[T : Compare] fixed_sift_down(arr : MutArrayView[T], index : Int) -> Unit { - #| let mut index = index - #| let len = arr.length() - #| let mut child = index * 2 + 1 - #| while child < len { - #| if child + 1 < len && arr[child] < arr[child + 1] { - #| child = child + 1 - #| } - #| if arr[index] >= arr[child] { - #| return - #| } - #| arr.swap(index, child) - #| index = child - #| child = index * 2 + 1 - #| } - #|} - #|fn fixed_test_sort(f : (MutArrayView[Int]) -> Unit) -> Unit raise { - #| let arr : FixedArray[_] = [5, 4, 3, 2, 1] - #| f(arr.mut_view()) - #| assert_eq(arr, [1, 2, 3, 4, 5]) - #| let arr : FixedArray[_] = [5, 5, 5, 5, 1] - #| f(arr.mut_view()) - #| assert_eq(arr, [1, 5, 5, 5, 5]) - #| let arr : FixedArray[_] = [1, 2, 3, 4, 5] - #| f(arr.mut_view()) - #| assert_eq(arr, [1, 2, 3, 4, 5]) - #| let arr = FixedArray::make(1000, 0) - #| for i in 0..<1000 { - #| arr[i] = 1000 - i - 1 - #| } - #| for i = 10; i < 1000; i = i + 10 { - #| arr.swap(i, i - 1) - #| } - #| f(arr.mut_view()) - #| let expected = FixedArray::make(1000, 0) - #| for i in 0..<1000 { - #| expected[i] = i - #| } - #| assert_eq(arr, expected) - #|} - #|test "fixed_heap_sort" { - #| fixed_test_sort(arr => fixed_heap_sort(arr.mut_view())) - #|} - #|test "fixed_bubble_sort" { - #| fixed_test_sort(arr => fixed_bubble_sort(arr.mut_view())) - #|} - #|test "sort" { - #| fixed_test_sort(arr => arr.sort()) - #|} - #|test "stable_sort" { - #| let arr : FixedArray[_] = [5, 1, 3, 4, 2] - #| arr.mut_view().stable_sort() - #| assert_eq(arr, [1, 2, 3, 4, 5]) - #| let arr = FixedArray::make(1000, 0) - #| for i in 0..<1000 { - #| arr[i] = 1000 - i - 1 - #| } - #| for i = 10; i < 1000; i = i + 10 { - #| arr.swap(i, i - 1) - #| } - #| arr.mut_view().stable_sort() - #| let expected = FixedArray::make(1000, 0) - #| for i in 0..<1000 { - #| expected[i] = i - #| } - #| assert_eq(arr, expected) - #|} - #|test "stable_sort_complex" { - #| let run_lens = [86, 64, 21, 20, 22] - #| let total_len = run_lens.fold(init=0, (acc, x) => acc + x) - #| let arr = FixedArray::make(total_len, 0) - #| let mut index = 0 - #| for i in 0.. Int { - #| if x > y { - #| y - #| } else { - #| x - #| } - #|} - ), - "arraycore_js.mbt": ( - #|#external - #|priv type JSValue - #|fn[T] JSValue::ofAny(array : T) -> JSValue = "%identity" - #|fn[T] JSValue::toAny(self : JSValue) -> T = "%identity" - #|#external - #|priv type JSArray - #|fn[T] JSArray::ofAnyArray(array : Array[T]) -> JSArray = "%identity" - #|fn[T] JSArray::toAnyArray(self : JSArray) -> Array[T] = "%identity" - #|fn[T] JSArray::ofAnyFixedArray(array : FixedArray[T]) -> JSArray = "%identity" - #|fn[T] JSArray::toAnyFixedArray(self : JSArray) -> FixedArray[T] = "%identity" - #|extern "js" fn JSArray::set_length(self : JSArray, new_len : Int) -> Unit = - #| #| (arr, len) => { arr.length = len; } - #|extern "js" fn JSArray::push(self : JSArray, value : JSValue) -> Unit = - #| #| (arr, val) => { arr.push(val); } - #|extern "js" fn JSArray::pop(self : JSArray) -> JSValue = - #| #| (arr) => arr.pop() - #|extern "js" fn JSArray::splice( - #| self : JSArray, - #| index : Int, - #| count : Int, - #|) -> JSArray = - #| #| (arr, idx, cnt) => arr.splice(idx, cnt) - #|extern "js" fn JSArray::splice1( - #| self : JSArray, - #| index : Int, - #| count : Int, - #| value : JSValue, - #|) -> JSArray = - #| #| (arr, idx, cnt, val) => arr.splice(idx, cnt, val) - #|extern "js" fn JSArray::fill( - #| self : JSArray, - #| value : JSValue, - #| start : Int, - #| end : Int, - #|) -> Unit = - #| #| (arr, val, start, end) => arr.fill(val, start, end) - #|extern "js" fn JSArray::copy(self : JSArray) -> JSArray = - #| #|(arr) => arr.slice(0) - #|#external - #|type Array[T] - #|fn[T] Array::make_uninit(len : Int) -> Array[T] = "%fixedarray.make_uninit" - #|pub fn[T] Array::new(capacity? : Int = 0) -> Array[T] { - #| ignore(capacity) - #| [] - #|} - #|pub fn[T] Array::length(self : Array[T]) -> Int = "%fixedarray.length" - #|fn[T] Array::unsafe_truncate_to_length(self : Array[T], new_len : Int) -> Unit { - #| JSArray::ofAnyArray(self).set_length(new_len) - #|} - #|fn[T] Array::buffer(self : Array[T]) -> UninitializedArray[T] = "%identity" - #|test "array_unsafe_blit_fixed" { - #| let src = FixedArray::make(5, 0) - #| let dst = UninitializedArray::make(5) - #| for i in 0..<5 { - #| src[i] = i + 1 - #| } - #| UninitializedArray::unsafe_blit_fixed(dst, 0, src, 0, 5) - #| for i in 0..<5 { - #| assert_eq(dst[i], src[i]) - #| } - #|} - #|test "UninitializedArray::unsafe_blit_fixed" { - #| let src = FixedArray::make(5, 0) - #| let dst = UninitializedArray::make(5) - #| for i in 0..<5 { - #| src[i] = i + 1 - #| } - #| UninitializedArray::unsafe_blit_fixed(dst, 0, src, 0, 5) - #| for i in 0..<5 { - #| assert_eq(dst[i], src[i]) - #| } - #|} - #|pub fn[T] Array::reserve_capacity(self : Array[T], capacity : Int) -> Unit { - #| ignore(self) - #| ignore(capacity) - #|} - #|pub fn[T] Array::shrink_to_fit(self : Array[T]) -> Unit { - #| ignore(self) - #|} - #|pub fn[T] Array::push(self : Array[T], value : T) -> Unit { - #| JSArray::ofAnyArray(self).push(JSValue::ofAny(value)) - #|} - #|pub fn[T] Array::pop(self : Array[T]) -> T? { - #| if self.length() == 0 { - #| None - #| } else { - #| let v = self.unsafe_pop() - #| Some(v) - #| } - #|} - #|#internal(unsafe, "Panic if the array is empty.") - #|#doc(hidden) - #|#alias(pop_exn, deprecated) - #|pub fn[T] Array::unsafe_pop(self : Array[T]) -> T { - #| JSArray::ofAnyArray(self).pop().toAny() - #|} - #|pub fn[T] Array::remove(self : Array[T], index : Int) -> T { - #| guard index >= 0 && index < self.length() else { - #| abort( - #| "index out of bounds: the len is from 0 to \{self.length()} but the index is \{index}", - #| ) - #| } - #| let value = self.buffer()[index] - #| let _ = JSArray::ofAnyArray(self).splice(index, 1) - #| value - #|} - #|pub fn[T] Array::drain(self : Array[T], begin : Int, end : Int) -> Array[T] { - #| guard begin >= 0 && end <= self.length() && begin <= end else { - #| abort( - #| "index out of bounds: the len is \{self.length()} but the index is (\{begin}, \{end})", - #| ) - #| } - #| JSArray::ofAnyArray(self).splice(begin, end - begin).toAnyArray() - #|} - #|pub fn[T] Array::insert(self : Array[T], index : Int, value : T) -> Unit { - #| guard index >= 0 && index <= self.length() else { - #| abort( - #| "index out of bounds: the len is from 0 to \{self.length()} but the index is \{index}", - #| ) - #| } - #| let _ = JSArray::ofAnyArray(self).splice1(index, 0, JSValue::ofAny(value)) - #|} - #|fn[T] Array::unsafe_grow_to_length(self : Array[T], new_len : Int) -> Unit { - #| guard new_len >= self.length() - #| JSArray::ofAnyArray(self).set_length(new_len) - #|} - #|pub fn[A] Array::fill( - #| self : Array[A], - #| value : A, - #| start? : Int = 0, - #| end? : Int, - #|) -> Unit { - #| let array_length = self.length() - #| guard array_length > 0 else { return } - #| guard start >= 0 && start < array_length - #| let end = match end { - #| None => array_length - #| Some(e) => { - #| guard e >= 0 && e <= array_length - #| e - #| } - #| } - #| JSArray::ofAnyArray(self).fill(JSValue::ofAny(value), start, end) - #|} - #|pub fn[T] Array::copy(self : Array[T]) -> Array[T] { - #| JSArray::ofAnyArray(self).copy().toAnyArray() - #|} - ), - "arraycore_nonjs.mbt": ( - #|fn[T] UninitializedArray::set_null(self : UninitializedArray[T], index : Int) = "%fixedarray.set_null" - #|struct Array[T] { - #| mut buf : UninitializedArray[T] - #| mut len : Int - #|} - #|fn[T] Array::make_uninit(len : Int) -> Array[T] { - #| { buf: UninitializedArray::make(len), len } - #|} - #|pub fn[T] Array::new(capacity? : Int = 0) -> Array[T] { - #| if capacity == 0 { - #| [] - #| } else { - #| { buf: UninitializedArray::make(capacity), len: 0 } - #| } - #|} - #|#intrinsic("%array.length") - #|pub fn[T] Array::length(self : Array[T]) -> Int { - #| self.len - #|} - #|fn[T] Array::unsafe_truncate_to_length(self : Array[T], new_len : Int) -> Unit { - #| let len = self.length() - #| guard new_len <= len - #| for i in new_len.. UninitializedArray[T] { - #| self.buf - #|} - #|fn[T] Array::resize_buffer(self : Array[T], new_capacity : Int) -> Unit { - #| let new_buf = UninitializedArray::make(new_capacity) - #| let old_buf = self.buf - #| let old_cap = old_buf.0.length() - #| let copy_len = if old_cap < new_capacity { old_cap } else { new_capacity } - #| UninitializedArray::unsafe_blit(new_buf, 0, old_buf, 0, copy_len) - #| self.buf = new_buf - #|} - #|test "array_unsafe_blit_fixed" { - #| let src = FixedArray::make(5, 0) - #| let dst = UninitializedArray::make(5) - #| for i in 0..<5 { - #| src[i] = i + 1 - #| } - #| UninitializedArray::unsafe_blit_fixed(dst, 0, src, 0, 5) - #| for i in 0..<5 { - #| assert_eq(dst[i], src[i]) - #| } - #|} - #|test "UninitializedArray::unsafe_blit_fixed" { - #| let src = FixedArray::make(5, 0) - #| let dst = UninitializedArray::make(5) - #| for i in 0..<5 { - #| src[i] = i + 1 - #| } - #| UninitializedArray::unsafe_blit_fixed(dst, 0, src, 0, 5) - #| for i in 0..<5 { - #| assert_eq(dst[i], src[i]) - #| } - #|} - #|test "Array::resize_buffer" { - #| let arr = Array::new(capacity=2) - #| arr.push(1) - #| arr.push(2) - #| arr.resize_buffer(4) - #| assert_eq(arr.buffer().0.length() >= 4, true) - #| arr.push(3) - #| arr.push(4) - #| assert_eq(arr.length(), 4) - #| assert_eq(arr[0], 1) - #| assert_eq(arr[1], 2) - #| assert_eq(arr[2], 3) - #| assert_eq(arr[3], 4) - #|} - #|fn[T] Array::realloc(self : Array[T]) -> Unit { - #| let old_cap = self.length() - #| let new_cap = if old_cap == 0 { 8 } else { old_cap * 2 } - #| self.resize_buffer(new_cap) - #|} - #|pub fn[T] Array::reserve_capacity(self : Array[T], capacity : Int) -> Unit { - #| if self.capacity() >= capacity { - #| return - #| } - #| self.resize_buffer(capacity) - #|} - #|pub fn[T] Array::shrink_to_fit(self : Array[T]) -> Unit { - #| if self.capacity() <= self.length() { - #| return - #| } - #| self.resize_buffer(self.length()) - #|} - #|pub fn[T] Array::push(self : Array[T], value : T) -> Unit { - #| if self.length() == self.buffer().0.length() { - #| self.realloc() - #| } - #| let length = self.length() - #| self.unsafe_set(length, value) - #| self.len = length + 1 - #|} - #|pub fn[T] Array::pop(self : Array[T]) -> T? { - #| let len = self.length() - #| if len == 0 { - #| None - #| } else { - #| let index = len - 1 - #| let v = self.unsafe_get(index) - #| self.buf.set_null(index) - #| self.len = index - #| Some(v) - #| } - #|} - #|#internal(unsafe, "Panic if the array is empty.") - #|#doc(hidden) - #|#alias(pop_exn, deprecated) - #|pub fn[T] Array::unsafe_pop(self : Array[T]) -> T { - #| let len = self.length() - #| guard len != 0 - #| let index = len - 1 - #| let v = self.unsafe_get(index) - #| self.buf.set_null(index) - #| self.len = index - #| v - #|} - #|pub fn[T] Array::remove(self : Array[T], index : Int) -> T { - #| guard index >= 0 && index < self.length() else { - #| abort( - #| "index out of bounds: the len is from 0 to \{self.length()} but the index is \{index}", - #| ) - #| } - #| let value = self.unsafe_get(index) - #| UninitializedArray::unsafe_blit( - #| self.buffer(), - #| index, - #| self.buffer(), - #| index + 1, - #| self.length() - index - 1, - #| ) - #| self.unsafe_truncate_to_length(self.length() - 1) - #| value - #|} - #|pub fn[T] Array::drain(self : Array[T], begin : Int, end : Int) -> Array[T] { - #| guard begin >= 0 && end <= self.length() && begin <= end - #| let num = end - begin - #| let v = Array::make_uninit(num) - #| UninitializedArray::unsafe_blit(v.buffer(), 0, self.buffer(), begin, num) - #| UninitializedArray::unsafe_blit( - #| self.buffer(), - #| begin, - #| self.buffer(), - #| end, - #| self.length() - end, - #| ) - #| self.unsafe_truncate_to_length(self.length() - num) - #| v - #|} - #|pub fn[T] Array::insert(self : Array[T], index : Int, value : T) -> Unit { - #| guard index >= 0 && index <= self.length() else { - #| abort( - #| "index out of bounds: the len is from 0 to \{self.length()} but the index is \{index}", - #| ) - #| } - #| if self.length() == self.buffer().0.length() { - #| self.realloc() - #| } - #| UninitializedArray::unsafe_blit( - #| self.buffer(), - #| index + 1, - #| self.buffer(), - #| index, - #| self.length() - index, - #| ) - #| let length = self.length() - #| self.unsafe_set(index, value) - #| self.len = length + 1 - #|} - #|fn[T] Array::unsafe_grow_to_length(self : Array[T], new_len : Int) -> Unit { - #| guard new_len >= self.length() - #| let new_buf = UninitializedArray::make(new_len) - #| UninitializedArray::unsafe_blit(new_buf, 0, self.buf, 0, self.len) - #| self.len = new_len - #| self.buf = new_buf - #|} - #|pub fn[A] Array::fill( - #| self : Array[A], - #| value : A, - #| start? : Int = 0, - #| end? : Int, - #|) -> Unit { - #| let array_length = self.length() - #| guard array_length > 0 else { return } - #| guard start >= 0 && start < array_length - #| let length = match end { - #| None => array_length - #| Some(e) => { - #| guard e >= start && e <= array_length - #| e - #| } - #| } - #| self.buf.unchecked_fill(start, value, length - start) - #|} - #|pub fn[T] Array::copy(self : Array[T]) -> Array[T] { - #| let len = self.length() - #| if len == 0 { - #| [] - #| } else { - #| let arr = Array::make(len, self[0]) - #| Array::unsafe_blit(arr, 0, self, 0, len) - #| arr - #| } - #|} - ), - "arrayview.mbt": ( - #|#builtin.valtype - #|type ArrayView[T] - #|fn[T] ArrayView::buf(self : ArrayView[T]) -> UninitializedArray[T] = "%arrayview.buf" - #|fn[T] ArrayView::start(self : ArrayView[T]) -> Int = "%arrayview.start" - #|fn[T] ArrayView::len(self : ArrayView[T]) -> Int = "%arrayview.len" - #|fn[T] ArrayView::make( - #| buf : UninitializedArray[T], - #| start : Int, - #| len : Int, - #|) -> ArrayView[T] = "%arrayview.make" - #|pub fn[T] ArrayView::length(self : ArrayView[T]) -> Int { - #| self.len() - #|} - #|pub fn[T] ArrayView::start_offset(self : Self[T]) -> Int { - #| self.start() - #|} - #|#alias("_[_]") - #|pub fn[T] ArrayView::at(self : ArrayView[T], index : Int) -> T { - #| guard index >= 0 && index < self.len() else { - #| abort( - #| "index out of bounds: the len is from 0 to \{self.len()} but the index is \{index}", - #| ) - #| } - #| self.buf()[self.start() + index] - #|} - #|pub fn[T] ArrayView::get(self : ArrayView[T], index : Int) -> T? { - #| let len = self.length() - #| guard index >= 0 && index < len else { None } - #| Some(self.buf()[self.start() + index]) - #|} - #|#intrinsic("%arrayview.unsafe_get") - #|#internal(unsafe, "Panic if index is out of bounds") - #|#doc(hidden) - #|pub fn[T] ArrayView::unsafe_get(self : ArrayView[T], index : Int) -> T { - #| self.buf()[self.start() + index] - #|} - #|#alias("_[_:_]") - #|pub fn[T] Array::sub( - #| self : Array[T], - #| start? : Int = 0, - #| end? : Int, - #|) -> ArrayView[T] { - #| let len = self.length() - #| let end = match end { - #| None => len - #| Some(end) => if end < 0 { len + end } else { end } - #| } - #| let start = if start < 0 { len + start } else { start } - #| guard start >= 0 && start <= end && end <= len else { - #| abort("View index out of bounds") - #| } - #| ArrayView::make(self.buffer(), start, end - start) - #|} - #|#alias("_[_:_]") - #|pub fn[T] ArrayView::sub( - #| self : ArrayView[T], - #| start? : Int = 0, - #| end? : Int, - #|) -> ArrayView[T] { - #| let len = self.length() - #| let end = match end { - #| None => len - #| Some(end) => if end < 0 { len + end } else { end } - #| } - #| let start = if start < 0 { len + start } else { start } - #| guard start >= 0 && start <= end && end <= len else { - #| abort("View index out of bounds") - #| } - #| ArrayView::make(self.buf(), self.start() + start, end - start) - #|} - #|fn[T] unsafe_cast_fixedarray_to_uninitializedarray( - #| arr : FixedArray[T], - #|) -> UninitializedArray[T] = "%identity" - #|#alias("_[_:_]") - #|pub fn[T] FixedArray::sub( - #| self : FixedArray[T], - #| start? : Int = 0, - #| end? : Int, - #|) -> ArrayView[T] { - #| let len = self.length() - #| let end = match end { - #| None => len - #| Some(end) => if end < 0 { len + end } else { end } - #| } - #| let start = if start < 0 { len + start } else { start } - #| guard start >= 0 && start <= end && end <= len else { - #| abort("View index out of bounds") - #| } - #| ArrayView::make( - #| unsafe_cast_fixedarray_to_uninitializedarray(self), - #| start, - #| end - start, - #| ) - #|} - #|pub fn[T] ArrayView::suffixes( - #| self : Self[T], - #| include_empty? : Bool = false, - #|) -> Iterator[ArrayView[T]] { - #| let len = self.length() - #| let mut i = 0 - #| Iterator::new(fn() -> ArrayView[T]? { - #| if i < len { - #| let suffix = self[i:] - #| i += 1 - #| Some(suffix) - #| } else if i == len { - #| i += 1 - #| if include_empty { - #| Some(self[len:]) - #| } else { - #| None - #| } - #| } else { - #| None - #| } - #| }) - #|} - #|pub fn[X] ArrayView::iterator(self : ArrayView[X]) -> Iterator[X] { - #| let mut i = 0 - #| Iterator::new(fn() { - #| guard i < self.length() else { None } - #| let elem = self.unsafe_get(i) - #| i += 1 - #| Some(elem) - #| }) - #|} - #|pub fn[A] ArrayView::iter(self : ArrayView[A]) -> Iter[A] { - #| self.iterator().iter() - #|} - #|pub fn[X] ArrayView::rev_iterator(self : ArrayView[X]) -> Iterator[X] { - #| let mut i = self.length() - #| Iterator::new(fn() { - #| guard i > 0 else { None } - #| i -= 1 - #| Some(self.unsafe_get(i)) - #| }) - #|} - #|pub fn[X] ArrayView::Iter2(self : ArrayView[X]) -> Iter2[Int, X] { - #| let mut i = 0 - #| Iter2::new(fn() { - #| guard i < self.length() else { None } - #| let result = Some((i, self.unsafe_get(i))) - #| i += 1 - #| result - #| }) - #|} - #|pub fn[A] ArrayView::iter2(self : ArrayView[A]) -> Iter2[Int, A] { - #| self.Iter2().iter2() - #|} - #|pub fn[T] ArrayView::each( - #| self : ArrayView[T], - #| f : (T) -> Unit raise?, - #|) -> Unit raise? { - #| for v in self { - #| f(v) - #| } - #|} - #|pub fn[T] ArrayView::eachi( - #| self : ArrayView[T], - #| f : (Int, T) -> Unit raise?, - #|) -> Unit raise? { - #| for i, v in self { - #| f(i, v) - #| } - #|} - #|pub fn[T] ArrayView::all( - #| self : ArrayView[T], - #| f : (T) -> Bool raise?, - #|) -> Bool raise? { - #| for v in self { - #| if !f(v) { - #| return false - #| } - #| } - #| true - #|} - #|pub fn[T] ArrayView::any( - #| self : ArrayView[T], - #| f : (T) -> Bool raise?, - #|) -> Bool raise? { - #| for v in self { - #| if f(v) { - #| return true - #| } - #| } - #| false - #|} - #|pub fn[T : Eq] ArrayView::contains(self : ArrayView[T], value : T) -> Bool { - #| for v in self { - #| if v == value { - #| break true - #| } - #| } else { - #| false - #| } - #|} - #|pub fn[A, B] ArrayView::fold( - #| self : ArrayView[A], - #| init~ : B, - #| f : (B, A) -> B raise?, - #|) -> B raise? { - #| for i = 0, acc = init; i < self.length(); { - #| continue i + 1, f(acc, self[i]) - #| } else { - #| acc - #| } - #|} - #|pub fn[A, B] ArrayView::rev_fold( - #| self : ArrayView[A], - #| init~ : B, - #| f : (B, A) -> B raise?, - #|) -> B raise? { - #| for i = self.length() - 1, acc = init; i >= 0; { - #| continue i - 1, f(acc, self[i]) - #| } else { - #| acc - #| } - #|} - #|pub fn[A, B] ArrayView::foldi( - #| self : ArrayView[A], - #| init~ : B, - #| f : (Int, B, A) -> B raise?, - #|) -> B raise? { - #| for i = 0, acc = init; i < self.length(); { - #| continue i + 1, f(i, acc, self[i]) - #| } else { - #| acc - #| } - #|} - #|pub fn[A, B] ArrayView::rev_foldi( - #| self : ArrayView[A], - #| init~ : B, - #| f : (Int, B, A) -> B raise?, - #|) -> B raise? { - #| let len = self.length() - #| for i = len - 1, acc = init; i >= 0; { - #| continue i - 1, f(len - i - 1, acc, self[i]) - #| } else { - #| acc - #| } - #|} - #|pub fn[T, U] ArrayView::map( - #| self : ArrayView[T], - #| f : (T) -> U raise?, - #|) -> Array[U] raise? { - #| if self.length() == 0 { - #| return [] - #| } - #| Array::makei(self.length(), i => f(self[i])) - #|} - #|pub fn[T, U] ArrayView::mapi( - #| self : ArrayView[T], - #| f : (Int, T) -> U raise?, - #|) -> Array[U] raise? { - #| if self.length() == 0 { - #| return [] - #| } - #| Array::makei(self.length(), i => f(i, self[i])) - #|} - #|pub fn[T] ArrayView::filter( - #| self : ArrayView[T], - #| f : (T) -> Bool raise?, - #|) -> Array[T] raise? { - #| let arr = [] - #| for v in self { - #| if f(v) { - #| arr.push(v) - #| } - #| } - #| arr - #|} - #|pub fn[T] ArrayView::to_array(self : ArrayView[T]) -> Array[T] { - #| let len = self.length() - #| if len == 0 { - #| [] - #| } else { - #| let arr = Array::make(len, self[0]) - #| for i, v in self { - #| arr[i] = v - #| } - #| arr - #| } - #|} - #|pub fn[A : ToStringView] ArrayView::join( - #| self : ArrayView[A], - #| separator : StringView, - #|) -> String { - #| match self { - #| [] => "" - #| [hd, .. tl] => { - #| let hd = hd.to_string_view() - #| let mut size_hint = hd.length() - #| for s in tl { - #| size_hint += s.to_string_view().length() + separator.length() - #| } - #| size_hint = size_hint << 1 - #| let buf = StringBuilder::new(size_hint~) - #| buf.write_view(hd) - #| if separator is "" { - #| for s in tl { - #| let s = s.to_string_view() - #| buf.write_view(s) - #| } - #| } else { - #| for s in tl { - #| let s = s.to_string_view() - #| buf.write_view(separator) - #| buf.write_view(s) - #| } - #| } - #| buf.to_string() - #| } - #| } - #|} - #|pub impl[X : Show] Show for ArrayView[X] with output(self, logger) { - #| logger.write_iter(self.iter()) - #|} - #|pub impl[T : Eq] Eq for ArrayView[T] with equal(self, other) -> Bool { - #| if self.length() != other.length() { - #| return false - #| } - #| for i in 0.. Int { - #| let len_self = self.length() - #| let len_other = other.length() - #| let cmp = len_self.compare(len_other) - #| guard cmp == 0 else { return cmp } - #| for i in 0.. String { - #| let buf = StringBuilder::new(size_hint=50) - #| t.output(buf) - #| buf.to_string() - #|} - #|#callsite(autofill(loc)) - #|#coverage.skip - #|pub fn[T : Eq + Show] assert_eq( - #| a : T, - #| b : T, - #| msg? : String, - #| loc~ : SourceLoc, - #|) -> Unit raise { - #| if a != b { - #| let fail_msg = match msg { - #| Some(msg) => msg - #| None => "`\{debug_string(a)} != \{debug_string(b)}`" - #| } - #| fail(fail_msg, loc~) - #| } - #|} - #|#callsite(autofill(loc)) - #|#coverage.skip - #|pub fn[T : Eq + Show] assert_not_eq( - #| a : T, - #| b : T, - #| msg? : String, - #| loc~ : SourceLoc, - #|) -> Unit raise { - #| if !(a != b) { - #| let fail_msg = match msg { - #| Some(msg) => msg - #| None => "`\{debug_string(a)} == \{debug_string(b)}`" - #| } - #| fail(fail_msg, loc~) - #| } - #|} - #|#callsite(autofill(loc)) - #|#coverage.skip - #|pub fn assert_true(x : Bool, msg? : String, loc~ : SourceLoc) -> Unit raise { - #| if !x { - #| let fail_msg = match msg { - #| Some(msg) => msg - #| None => "`\{x}` is not true" - #| } - #| fail(fail_msg, loc~) - #| } - #|} - #|#callsite(autofill(loc)) - #|#coverage.skip - #|pub fn assert_false(x : Bool, msg? : String, loc~ : SourceLoc) -> Unit raise { - #| if x { - #| let fail_msg = match msg { - #| Some(msg) => msg - #| None => "`\{x}` is not false" - #| } - #| fail(fail_msg, loc~) - #| } - #|} - ), - "autoloc.mbt": ( - #|pub(all) type SourceLoc - #|fn SourceLoc::repr(self : Self) -> String = "%loc_to_string" - #|pub impl Show for SourceLoc with output(self, logger) { - #| SourceLocRepr::parse(self.repr()).output(logger) - #|} - #|priv struct SourceLocRepr { - #| pkg : StringView - #| filename : StringView - #| start_line : StringView - #| start_column : StringView - #| end_line : StringView - #| end_column : StringView - #|} - #|impl Show for SourceLocRepr with output(self, logger) { - #| let pkg = self.pkg - #| let (module_name, package_name) = { - #| guard pkg.find("/") is Some(first_slash) else { (pkg, None) } - #| guard pkg.view(start_offset=first_slash + 1).find("/") is Some(second_slash) else { - #| (pkg, None) - #| } - #| let module_name_end = first_slash + 1 + second_slash - #| ( - #| pkg.view(end_offset=module_name_end), - #| Some(pkg.view(start_offset=module_name_end + 1)), - #| ) - #| } - #| if package_name is Some(pkg_name) { - #| logger..write_view(pkg_name)..write_char('/') - #| } - #| logger - #| ..write_view(self.filename) - #| ..write_char(':') - #| ..write_view(self.start_line) - #| ..write_char(':') - #| ..write_view(self.start_column) - #| ..write_char('-') - #| ..write_view(self.end_line) - #| ..write_char(':') - #| ..write_view(self.end_column) - #| ..write_char('@') - #| ..write_view(module_name) - #|} - #|fn SourceLocRepr::parse(repr : String) -> SourceLocRepr { - #| fn parse_loc(view : StringView) -> (StringView, StringView)? { - #| guard view.find(":") is Some(i) else { None } - #| guard i > 0 && i + 1 < view.length() else { None } - #| Some((view.view(end_offset=i), view.view(start_offset=i + 1))) - #| } - #| guard repr is ['@', .. rest] - #| guard rest.find(":") is Some(pkg_end) - #| let pkg = rest.view(start_offset=0, end_offset=pkg_end) - #| guard rest.rev_find("-") is Some(start_loc_end) - #| guard start_loc_end + 1 < rest.length() - #| let end_loc = rest.view(start_offset=start_loc_end + 1) - #| guard parse_loc(end_loc) is Some((end_line, end_column)) - #| let rest = rest.view(end_offset=start_loc_end) - #| guard rest.rev_find(":") is Some(start_line_end) && - #| rest.view(end_offset=start_line_end).rev_find(":") is Some(filename_end) - #| guard filename_end + 1 < rest.length() - #| let start_loc = rest.view(start_offset=filename_end + 1) - #| guard parse_loc(start_loc) is Some((start_line, start_column)) - #| guard filename_end > pkg_end + 1 - #| let filename = rest.view(start_offset=pkg_end + 1, end_offset=filename_end) - #| { pkg, filename, start_line, start_column, end_line, end_column } - #|} - #|fn SourceLocRepr::to_json_string(self : SourceLocRepr) -> String { - #| StringBuilder::new() - #| ..write_string("{\"pkg\":\"\{self.pkg}\"") - #| ..write_string(",\"filename\":") - #| ..write_object(self.filename) - #| ..write_string(",\"start_line\":\{self.start_line}") - #| ..write_string(",\"start_column\":\{self.start_column}") - #| ..write_string(",\"end_line\":\{self.end_line}") - #| ..write_string(",\"end_column\":\{self.end_column}}") - #| .to_string() - #|} - #|pub fn SourceLoc::to_json_string(self : SourceLoc) -> String { - #| SourceLocRepr::parse(self.repr()).to_json_string() - #|} - #|pub(all) struct ArgsLoc(Array[SourceLoc?]) derive(Show) - #|pub fn ArgsLoc::to_json(self : ArgsLoc) -> String { - #| let buf = StringBuilder::new(size_hint=10) - #| let ArgsLoc(self) = self - #| buf.write_char('[') - #| for i in 0.. buf.write_string("null") - #| Some(loc) => buf.write_string(loc.to_json_string()) - #| } - #| } - #| buf.write_char(']') - #| buf.to_string() - #|} - ), - "bitstring.mbt": ( - #|fn UInt::extend_sign(self : UInt, len : Int) -> Int { - #| let b = 32 - len - #| self.reinterpret_as_int() << b >> b - #|} - #|fn UInt64::extend_sign(self : UInt64, len : Int) -> Int64 { - #| let b = 64 - len - #| self.reinterpret_as_int64() << b >> b - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn ArrayView::unsafe_extract_bit( - #| bs : ArrayView[Byte], - #| offset : Int, - #| _len : Int, - #|) -> UInt { - #| let byte_index = offset >> 3 - #| let bit_shift = 7 - (offset & 7) - #| let byte_val = bs.unsafe_get(byte_index).to_uint() - #| (byte_val >> bit_shift) & 1U - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn ArrayView::unsafe_extract_bit_signed( - #| bs : ArrayView[Byte], - #| offset : Int, - #| _len : Int, - #|) -> Int { - #| let byte_index = offset >> 3 - #| let bit_shift = 7 - (offset & 7) - #| let byte_val = bs.unsafe_get(byte_index).to_int() - #| ((byte_val >> bit_shift) & 1) * -1 - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn ArrayView::unsafe_extract_byte( - #| bs : ArrayView[Byte], - #| offset : Int, - #| len : Int, - #|) -> UInt { - #| let byte_index = offset >> 3 - #| if (offset & 7) == 0 { - #| let byte = bs.unsafe_get(byte_index) - #| (byte >> (8 - len)).to_uint() - #| } else if (offset & 7) + len <= 8 { - #| let byte = bs.unsafe_get(byte_index).to_uint() - #| let shift = 8 - ((offset & 7) + len) - #| let mask = (1U << len) - 1 - #| (byte >> shift) & mask - #| } else { - #| let b0 = bs.unsafe_get(byte_index).to_uint() - #| let b1 = bs.unsafe_get(byte_index + 1).to_uint() - #| let data = (b0 << 8) | b1 - #| let bit_mask = (1U << (16 - (offset & 7))) - 1 - #| let data = data & bit_mask - #| let shift = 16 - ((offset & 7) + len) - #| data >> shift - #| } - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn ArrayView::unsafe_extract_uint_le( - #| bs : ArrayView[Byte], - #| offset : Int, - #| len : Int, - #|) -> UInt { - #| let bytes_needed = (len + 7) / 8 - #| let b0 = bs.unsafe_extract_byte(offset, 8) - #| match bytes_needed { - #| 2 => { - #| let b1 = bs.unsafe_extract_byte(offset + 8, len - 8) - #| (b1 << 8) | b0 - #| } - #| 3 => { - #| let b1 = bs.unsafe_extract_byte(offset + 8, 8) - #| let b2 = bs.unsafe_extract_byte(offset + 16, len - 16) - #| (b2 << 16) | (b1 << 8) | b0 - #| } - #| 4 => { - #| let b1 = bs.unsafe_extract_byte(offset + 8, 8) - #| let b2 = bs.unsafe_extract_byte(offset + 16, 8) - #| let b3 = bs.unsafe_extract_byte(offset + 24, len - 24) - #| (b3 << 24) | (b2 << 16) | (b1 << 8) | b0 - #| } - #| _ => abort("Invalid byte count for int32 extraction") - #| } - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn ArrayView::unsafe_extract_uint_be( - #| bs : ArrayView[Byte], - #| offset : Int, - #| len : Int, - #|) -> UInt { - #| let bytes_needed = (len + 7) / 8 - #| let b0 = bs.unsafe_extract_byte(offset, 8) - #| match bytes_needed { - #| 2 => { - #| let b1 = bs.unsafe_extract_byte(offset + 8, len - 8) - #| let shift = 16 - len - #| let data = (b0 << 8) | (b1 << shift) - #| data >> shift - #| } - #| 3 => { - #| let b1 = bs.unsafe_extract_byte(offset + 8, 8) - #| let b2 = bs.unsafe_extract_byte(offset + 16, len - 16) - #| let shift = 24 - len - #| let data = (b0 << 16) | (b1 << 8) | (b2 << shift) - #| data >> shift - #| } - #| 4 => { - #| let b1 = bs.unsafe_extract_byte(offset + 8, 8) - #| let b2 = bs.unsafe_extract_byte(offset + 16, 8) - #| let b3 = bs.unsafe_extract_byte(offset + 24, len - 24) - #| let shift = 32 - len - #| let data = (b0 << 24) | (b1 << 16) | (b2 << 8) | (b3 << shift) - #| data >> shift - #| } - #| _ => abort("Invalid byte count for int32 extraction") - #| } - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn ArrayView::unsafe_extract_uint64_le( - #| bs : ArrayView[Byte], - #| offset : Int, - #| len : Int, - #|) -> UInt64 { - #| let bytes_needed = (len + 7) / 8 - #| let b0 = bs.unsafe_extract_byte(offset, 8).to_uint64() - #| let b1 = bs.unsafe_extract_byte(offset + 8, 8).to_uint64() - #| let b2 = bs.unsafe_extract_byte(offset + 16, 8).to_uint64() - #| let b3 = bs.unsafe_extract_byte(offset + 24, 8).to_uint64() - #| match bytes_needed { - #| 5 => { - #| let b4 = bs.unsafe_extract_byte(offset + 32, len - 32).to_uint64() - #| (b4 << 32) | (b3 << 24) | (b2 << 16) | (b1 << 8) | b0 - #| } - #| 6 => { - #| let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64() - #| let b5 = bs.unsafe_extract_byte(offset + 40, len - 40).to_uint64() - #| (b5 << 40) | (b4 << 32) | (b3 << 24) | (b2 << 16) | (b1 << 8) | b0 - #| } - #| 7 => { - #| let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64() - #| let b5 = bs.unsafe_extract_byte(offset + 40, 8).to_uint64() - #| let b6 = bs.unsafe_extract_byte(offset + 48, len - 48).to_uint64() - #| (b6 << 48) | - #| (b5 << 40) | - #| (b4 << 32) | - #| (b3 << 24) | - #| (b2 << 16) | - #| (b1 << 8) | - #| b0 - #| } - #| 8 => { - #| let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64() - #| let b5 = bs.unsafe_extract_byte(offset + 40, 8).to_uint64() - #| let b6 = bs.unsafe_extract_byte(offset + 48, 8).to_uint64() - #| let b7 = bs.unsafe_extract_byte(offset + 56, len - 56).to_uint64() - #| (b7 << 56) | - #| (b6 << 48) | - #| (b5 << 40) | - #| (b4 << 32) | - #| (b3 << 24) | - #| (b2 << 16) | - #| (b1 << 8) | - #| b0 - #| } - #| _ => abort("Invalid byte count for int64 extraction") - #| } - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn ArrayView::unsafe_extract_uint64_be( - #| bs : ArrayView[Byte], - #| offset : Int, - #| len : Int, - #|) -> UInt64 { - #| let bytes_needed = (len + 7) / 8 - #| let b0 = bs.unsafe_extract_byte(offset, 8).to_uint64() - #| let b1 = bs.unsafe_extract_byte(offset + 8, 8).to_uint64() - #| let b2 = bs.unsafe_extract_byte(offset + 16, 8).to_uint64() - #| let b3 = bs.unsafe_extract_byte(offset + 24, 8).to_uint64() - #| match bytes_needed { - #| 5 => { - #| let b4 = bs.unsafe_extract_byte(offset + 32, len - 32).to_uint64() - #| let shift = 40 - len - #| let data = (b0 << 32) | - #| (b1 << 24) | - #| (b2 << 16) | - #| (b3 << 8) | - #| (b4 << shift) - #| data >> shift - #| } - #| 6 => { - #| let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64() - #| let b5 = bs.unsafe_extract_byte(offset + 40, len - 40).to_uint64() - #| let shift = 48 - len - #| let data = (b0 << 40) | - #| (b1 << 32) | - #| (b2 << 24) | - #| (b3 << 16) | - #| (b4 << 8) | - #| (b5 << shift) - #| data >> shift - #| } - #| 7 => { - #| let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64() - #| let b5 = bs.unsafe_extract_byte(offset + 40, 8).to_uint64() - #| let b6 = bs.unsafe_extract_byte(offset + 48, len - 48).to_uint64() - #| let shift = 56 - len - #| let data = (b0 << 48) | - #| (b1 << 40) | - #| (b2 << 32) | - #| (b3 << 24) | - #| (b4 << 16) | - #| (b5 << 8) | - #| (b6 << shift) - #| data >> shift - #| } - #| 8 => { - #| let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64() - #| let b5 = bs.unsafe_extract_byte(offset + 40, 8).to_uint64() - #| let b6 = bs.unsafe_extract_byte(offset + 48, 8).to_uint64() - #| let b7 = bs.unsafe_extract_byte(offset + 56, len - 56).to_uint64() - #| let shift = 64 - len - #| let data = (b0 << 56) | - #| (b1 << 48) | - #| (b2 << 40) | - #| (b3 << 32) | - #| (b4 << 24) | - #| (b5 << 16) | - #| (b6 << 8) | - #| (b7 << shift) - #| data >> shift - #| } - #| _ => abort("Invalid byte count for int64 extraction") - #| } - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn ArrayView::unsafe_extract_bytesview( - #| bs : ArrayView[Byte], - #| offset : Int, - #| len : Int, - #|) -> ArrayView[Byte] { - #| let start = offset >> 3 - #| let end = start + (len >> 3) - #| bs[start:end] - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn ArrayView::unsafe_extract_byte_signed( - #| bs : ArrayView[Byte], - #| offset : Int, - #| len : Int, - #|) -> Int { - #| let unsigned = bs.unsafe_extract_byte(offset, len) - #| unsigned.extend_sign(len) - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn ArrayView::unsafe_extract_int_le( - #| bs : ArrayView[Byte], - #| offset : Int, - #| len : Int, - #|) -> Int { - #| let unsigned = bs.unsafe_extract_uint_le(offset, len) - #| unsigned.extend_sign(len) - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn ArrayView::unsafe_extract_int_be( - #| bs : ArrayView[Byte], - #| offset : Int, - #| len : Int, - #|) -> Int { - #| let unsigned = bs.unsafe_extract_uint_be(offset, len) - #| unsigned.extend_sign(len) - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn ArrayView::unsafe_extract_int64_le( - #| bs : ArrayView[Byte], - #| offset : Int, - #| len : Int, - #|) -> Int64 { - #| let unsigned = bs.unsafe_extract_uint64_le(offset, len) - #| unsigned.extend_sign(len) - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn ArrayView::unsafe_extract_int64_be( - #| bs : ArrayView[Byte], - #| offset : Int, - #| len : Int, - #|) -> Int64 { - #| let unsigned = bs.unsafe_extract_uint64_be(offset, len) - #| unsigned.extend_sign(len) - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn Array::unsafe_extract_bit( - #| bs : Array[Byte], - #| offset : Int, - #| len : Int, - #|) -> UInt { - #| bs[:].unsafe_extract_bit(offset, len) - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn Array::unsafe_extract_byte( - #| bs : Array[Byte], - #| offset : Int, - #| len : Int, - #|) -> UInt { - #| bs[:].unsafe_extract_byte(offset, len) - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn Array::unsafe_extract_uint_le( - #| bs : Array[Byte], - #| offset : Int, - #| len : Int, - #|) -> UInt { - #| bs[:].unsafe_extract_uint_le(offset, len) - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn Array::unsafe_extract_uint_be( - #| bs : Array[Byte], - #| offset : Int, - #| len : Int, - #|) -> UInt { - #| bs[:].unsafe_extract_uint_be(offset, len) - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn Array::unsafe_extract_uint64_le( - #| bs : Array[Byte], - #| offset : Int, - #| len : Int, - #|) -> UInt64 { - #| bs[:].unsafe_extract_uint64_le(offset, len) - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn Array::unsafe_extract_uint64_be( - #| bs : Array[Byte], - #| offset : Int, - #| len : Int, - #|) -> UInt64 { - #| bs[:].unsafe_extract_uint64_be(offset, len) - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn Array::unsafe_extract_bytesview( - #| bs : Array[Byte], - #| offset : Int, - #| len : Int, - #|) -> ArrayView[Byte] { - #| bs[:].unsafe_extract_bytesview(offset, len) - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn FixedArray::unsafe_extract_bit( - #| bs : FixedArray[Byte], - #| offset : Int, - #| len : Int, - #|) -> UInt { - #| bs[:].unsafe_extract_bit(offset, len) - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn FixedArray::unsafe_extract_byte( - #| bs : FixedArray[Byte], - #| offset : Int, - #| len : Int, - #|) -> UInt { - #| bs[:].unsafe_extract_byte(offset, len) - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn FixedArray::unsafe_extract_uint_le( - #| bs : FixedArray[Byte], - #| offset : Int, - #| len : Int, - #|) -> UInt { - #| bs[:].unsafe_extract_uint_le(offset, len) - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn FixedArray::unsafe_extract_uint_be( - #| bs : FixedArray[Byte], - #| offset : Int, - #| len : Int, - #|) -> UInt { - #| bs[:].unsafe_extract_uint_be(offset, len) - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn FixedArray::unsafe_extract_uint64_le( - #| bs : FixedArray[Byte], - #| offset : Int, - #| len : Int, - #|) -> UInt64 { - #| bs[:].unsafe_extract_uint64_le(offset, len) - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn FixedArray::unsafe_extract_uint64_be( - #| bs : FixedArray[Byte], - #| offset : Int, - #| len : Int, - #|) -> UInt64 { - #| bs[:].unsafe_extract_uint64_be(offset, len) - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn FixedArray::unsafe_extract_bytesview( - #| bs : FixedArray[Byte], - #| offset : Int, - #| len : Int, - #|) -> ArrayView[Byte] { - #| bs[:].unsafe_extract_bytesview(offset, len) - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn BytesView::unsafe_extract_bit( - #| bs : BytesView, - #| offset : Int, - #| _len : Int, - #|) -> UInt { - #| let byte_index = offset >> 3 - #| let bit_shift = 7 - (offset & 7) - #| let byte_val = bs.unsafe_get(byte_index).to_uint() - #| (byte_val >> bit_shift) & 1U - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn BytesView::unsafe_extract_bit_signed( - #| bs : BytesView, - #| offset : Int, - #| _len : Int, - #|) -> Int { - #| let byte_index = offset >> 3 - #| let bit_shift = 7 - (offset & 7) - #| let byte_val = bs.unsafe_get(byte_index).to_int() - #| ((byte_val >> bit_shift) & 1) * -1 - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn BytesView::unsafe_extract_byte( - #| bs : BytesView, - #| offset : Int, - #| len : Int, - #|) -> UInt { - #| let byte_index = offset >> 3 - #| if (offset & 7) == 0 { - #| let byte = bs.unsafe_get(byte_index) - #| (byte >> (8 - len)).to_uint() - #| } else if (offset & 7) + len <= 8 { - #| let byte = bs.unsafe_get(byte_index).to_uint() - #| let shift = 8 - ((offset & 7) + len) - #| let mask = (1U << len) - 1 - #| (byte >> shift) & mask - #| } else { - #| let b0 = bs.unsafe_get(byte_index).to_uint() - #| let b1 = bs.unsafe_get(byte_index + 1).to_uint() - #| let data = (b0 << 8) | b1 - #| let bit_mask = (1U << (16 - (offset & 7))) - 1 - #| let data = data & bit_mask - #| let shift = 16 - ((offset & 7) + len) - #| data >> shift - #| } - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn BytesView::unsafe_extract_uint_le( - #| bs : BytesView, - #| offset : Int, - #| len : Int, - #|) -> UInt { - #| let bytes_needed = (len + 7) / 8 - #| let b0 = bs.unsafe_extract_byte(offset, 8) - #| match bytes_needed { - #| 2 => { - #| let b1 = bs.unsafe_extract_byte(offset + 8, len - 8) - #| (b1 << 8) | b0 - #| } - #| 3 => { - #| let b1 = bs.unsafe_extract_byte(offset + 8, 8) - #| let b2 = bs.unsafe_extract_byte(offset + 16, len - 16) - #| (b2 << 16) | (b1 << 8) | b0 - #| } - #| 4 => { - #| let b1 = bs.unsafe_extract_byte(offset + 8, 8) - #| let b2 = bs.unsafe_extract_byte(offset + 16, 8) - #| let b3 = bs.unsafe_extract_byte(offset + 24, len - 24) - #| (b3 << 24) | (b2 << 16) | (b1 << 8) | b0 - #| } - #| _ => abort("Invalid byte count for int32 extraction") - #| } - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn BytesView::unsafe_extract_uint_be( - #| bs : BytesView, - #| offset : Int, - #| len : Int, - #|) -> UInt { - #| let bytes_needed = (len + 7) / 8 - #| let b0 = bs.unsafe_extract_byte(offset, 8) - #| match bytes_needed { - #| 2 => { - #| let b1 = bs.unsafe_extract_byte(offset + 8, len - 8) - #| let shift = 16 - len - #| let data = (b0 << 8) | (b1 << shift) - #| data >> shift - #| } - #| 3 => { - #| let b1 = bs.unsafe_extract_byte(offset + 8, 8) - #| let b2 = bs.unsafe_extract_byte(offset + 16, len - 16) - #| let shift = 24 - len - #| let data = (b0 << 16) | (b1 << 8) | (b2 << shift) - #| data >> shift - #| } - #| 4 => { - #| let b1 = bs.unsafe_extract_byte(offset + 8, 8) - #| let b2 = bs.unsafe_extract_byte(offset + 16, 8) - #| let b3 = bs.unsafe_extract_byte(offset + 24, len - 24) - #| let shift = 32 - len - #| let data = (b0 << 24) | (b1 << 16) | (b2 << 8) | (b3 << shift) - #| data >> shift - #| } - #| _ => abort("Invalid byte count for int32 extraction") - #| } - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn BytesView::unsafe_extract_uint64_le( - #| bs : BytesView, - #| offset : Int, - #| len : Int, - #|) -> UInt64 { - #| let bytes_needed = (len + 7) / 8 - #| let b0 = bs.unsafe_extract_byte(offset, 8).to_uint64() - #| let b1 = bs.unsafe_extract_byte(offset + 8, 8).to_uint64() - #| let b2 = bs.unsafe_extract_byte(offset + 16, 8).to_uint64() - #| let b3 = bs.unsafe_extract_byte(offset + 24, 8).to_uint64() - #| match bytes_needed { - #| 5 => { - #| let b4 = bs.unsafe_extract_byte(offset + 32, len - 32).to_uint64() - #| (b4 << 32) | (b3 << 24) | (b2 << 16) | (b1 << 8) | b0 - #| } - #| 6 => { - #| let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64() - #| let b5 = bs.unsafe_extract_byte(offset + 40, len - 40).to_uint64() - #| (b5 << 40) | (b4 << 32) | (b3 << 24) | (b2 << 16) | (b1 << 8) | b0 - #| } - #| 7 => { - #| let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64() - #| let b5 = bs.unsafe_extract_byte(offset + 40, 8).to_uint64() - #| let b6 = bs.unsafe_extract_byte(offset + 48, len - 48).to_uint64() - #| (b6 << 48) | - #| (b5 << 40) | - #| (b4 << 32) | - #| (b3 << 24) | - #| (b2 << 16) | - #| (b1 << 8) | - #| b0 - #| } - #| 8 => { - #| let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64() - #| let b5 = bs.unsafe_extract_byte(offset + 40, 8).to_uint64() - #| let b6 = bs.unsafe_extract_byte(offset + 48, 8).to_uint64() - #| let b7 = bs.unsafe_extract_byte(offset + 56, len - 56).to_uint64() - #| (b7 << 56) | - #| (b6 << 48) | - #| (b5 << 40) | - #| (b4 << 32) | - #| (b3 << 24) | - #| (b2 << 16) | - #| (b1 << 8) | - #| b0 - #| } - #| _ => abort("Invalid byte count for int64 extraction") - #| } - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn BytesView::unsafe_extract_uint64_be( - #| bs : BytesView, - #| offset : Int, - #| len : Int, - #|) -> UInt64 { - #| let bytes_needed = (len + 7) / 8 - #| let b0 = bs.unsafe_extract_byte(offset, 8).to_uint64() - #| let b1 = bs.unsafe_extract_byte(offset + 8, 8).to_uint64() - #| let b2 = bs.unsafe_extract_byte(offset + 16, 8).to_uint64() - #| let b3 = bs.unsafe_extract_byte(offset + 24, 8).to_uint64() - #| match bytes_needed { - #| 5 => { - #| let b4 = bs.unsafe_extract_byte(offset + 32, len - 32).to_uint64() - #| let shift = 40 - len - #| let data = (b0 << 32) | - #| (b1 << 24) | - #| (b2 << 16) | - #| (b3 << 8) | - #| (b4 << shift) - #| data >> shift - #| } - #| 6 => { - #| let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64() - #| let b5 = bs.unsafe_extract_byte(offset + 40, len - 40).to_uint64() - #| let shift = 48 - len - #| let data = (b0 << 40) | - #| (b1 << 32) | - #| (b2 << 24) | - #| (b3 << 16) | - #| (b4 << 8) | - #| (b5 << shift) - #| data >> shift - #| } - #| 7 => { - #| let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64() - #| let b5 = bs.unsafe_extract_byte(offset + 40, 8).to_uint64() - #| let b6 = bs.unsafe_extract_byte(offset + 48, len - 48).to_uint64() - #| let shift = 56 - len - #| let data = (b0 << 48) | - #| (b1 << 40) | - #| (b2 << 32) | - #| (b3 << 24) | - #| (b4 << 16) | - #| (b5 << 8) | - #| (b6 << shift) - #| data >> shift - #| } - #| 8 => { - #| let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64() - #| let b5 = bs.unsafe_extract_byte(offset + 40, 8).to_uint64() - #| let b6 = bs.unsafe_extract_byte(offset + 48, 8).to_uint64() - #| let b7 = bs.unsafe_extract_byte(offset + 56, len - 56).to_uint64() - #| let shift = 64 - len - #| let data = (b0 << 56) | - #| (b1 << 48) | - #| (b2 << 40) | - #| (b3 << 32) | - #| (b4 << 24) | - #| (b5 << 16) | - #| (b6 << 8) | - #| (b7 << shift) - #| data >> shift - #| } - #| _ => abort("Invalid byte count for int64 extraction") - #| } - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn BytesView::unsafe_extract_bytesview( - #| bs : BytesView, - #| offset : Int, - #| len : Int, - #|) -> BytesView { - #| BytesView::make(bs.bytes(), bs.start() + (offset >> 3), len >> 3) - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn BytesView::unsafe_extract_byte_signed( - #| bs : BytesView, - #| offset : Int, - #| len : Int, - #|) -> Int { - #| let unsigned = bs.unsafe_extract_byte(offset, len) - #| unsigned.extend_sign(len) - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn BytesView::unsafe_extract_int_le( - #| bs : BytesView, - #| offset : Int, - #| len : Int, - #|) -> Int { - #| let unsigned = bs.unsafe_extract_uint_le(offset, len) - #| unsigned.extend_sign(len) - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn BytesView::unsafe_extract_int_be( - #| bs : BytesView, - #| offset : Int, - #| len : Int, - #|) -> Int { - #| let unsigned = bs.unsafe_extract_uint_be(offset, len) - #| unsigned.extend_sign(len) - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn BytesView::unsafe_extract_int64_le( - #| bs : BytesView, - #| offset : Int, - #| len : Int, - #|) -> Int64 { - #| let unsigned = bs.unsafe_extract_uint64_le(offset, len) - #| unsigned.extend_sign(len) - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn BytesView::unsafe_extract_int64_be( - #| bs : BytesView, - #| offset : Int, - #| len : Int, - #|) -> Int64 { - #| let unsigned = bs.unsafe_extract_uint64_be(offset, len) - #| unsigned.extend_sign(len) - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn Bytes::unsafe_extract_bit(bs : Bytes, offset : Int, len : Int) -> UInt { - #| bs[:].unsafe_extract_bit(offset, len) - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn Bytes::unsafe_extract_byte(bs : Bytes, offset : Int, len : Int) -> UInt { - #| bs[:].unsafe_extract_byte(offset, len) - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn Bytes::unsafe_extract_uint_le( - #| bs : Bytes, - #| offset : Int, - #| len : Int, - #|) -> UInt { - #| bs[:].unsafe_extract_uint_le(offset, len) - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn Bytes::unsafe_extract_uint_be( - #| bs : Bytes, - #| offset : Int, - #| len : Int, - #|) -> UInt { - #| bs[:].unsafe_extract_uint_be(offset, len) - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn Bytes::unsafe_extract_uint64_le( - #| bs : Bytes, - #| offset : Int, - #| len : Int, - #|) -> UInt64 { - #| bs[:].unsafe_extract_uint64_le(offset, len) - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn Bytes::unsafe_extract_uint64_be( - #| bs : Bytes, - #| offset : Int, - #| len : Int, - #|) -> UInt64 { - #| bs[:].unsafe_extract_uint64_be(offset, len) - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn Bytes::unsafe_extract_bytesview( - #| bs : Bytes, - #| offset : Int, - #| len : Int, - #|) -> BytesView { - #| bs[:].unsafe_extract_bytesview(offset, len) - #|} - ), - "bool.mbt": ( - #|pub fn Bool::to_int(self : Bool) -> Int { - #| if self { - #| 1 - #| } else { - #| 0 - #| } - #|} - #|pub fn Bool::to_int64(self : Bool) -> Int64 { - #| if self { - #| 1 - #| } else { - #| 0 - #| } - #|} - #|pub fn Bool::to_uint(self : Bool) -> UInt { - #| if self { - #| 1 - #| } else { - #| 0 - #| } - #|} - #|pub fn Bool::to_uint64(self : Bool) -> UInt64 { - #| if self { - #| 1 - #| } else { - #| 0 - #| } - #|} - #|pub impl Hash for Bool with hash_combine(self, hasher) { - #| hasher.combine_bool(self) - #|} - #|pub fn Bool::to_uint16(self : Bool) -> UInt16 { - #| if self { - #| 1 - #| } else { - #| 0 - #| } - #|} - #|pub fn Bool::to_int16(self : Bool) -> Int16 { - #| if self { - #| 1 - #| } else { - #| 0 - #| } - #|} - ), - "byte.mbt": ( - #|pub impl Mul for Byte with mul(self : Byte, that : Byte) -> Byte { - #| (self.to_int() * that.to_int()).to_byte() - #|} - #|pub impl Div for Byte with div(self : Byte, that : Byte) -> Byte { - #| (self.to_int() / that.to_int()).to_byte() - #|} - #|pub impl Mod for Byte with mod(self : Byte, that : Byte) -> Byte { - #| (self.to_int() % that.to_int()).to_byte() - #|} - #|pub impl Eq for Byte with equal(self : Byte, that : Byte) -> Bool { - #| self.to_int() == that.to_int() - #|} - #|pub impl Add for Byte with add(self : Byte, that : Byte) -> Byte { - #| (self.to_int() + that.to_int()).to_byte() - #|} - #|pub impl Sub for Byte with sub(self : Byte, that : Byte) -> Byte { - #| (self.to_int() - that.to_int()).to_byte() - #|} - #|pub impl Compare for Byte with compare(self : Byte, that : Byte) -> Int { - #| self.to_int().compare(that.to_int()) - #|} - #|pub impl Compare for Byte with op_lt(x, y) { - #| x.to_int() < y.to_int() - #|} - #|pub impl Compare for Byte with op_le(x, y) { - #| x.to_int() <= y.to_int() - #|} - #|pub impl Compare for Byte with op_gt(x, y) { - #| x.to_int() > y.to_int() - #|} - #|pub impl Compare for Byte with op_ge(x, y) { - #| x.to_int() >= y.to_int() - #|} - #|fn alphabet(x : Int) -> String { - #| match x { - #| 0 => "0" - #| 1 => "1" - #| 2 => "2" - #| 3 => "3" - #| 4 => "4" - #| 5 => "5" - #| 6 => "6" - #| 7 => "7" - #| 8 => "8" - #| 9 => "9" - #| 10 => "A" - #| 11 => "B" - #| 12 => "C" - #| 13 => "D" - #| 14 => "E" - #| 15 => "F" - #| _ => abort("impossible") - #| } - #|} - #|pub fn Byte::to_string(self : Byte) -> String { - #| let i = self.to_int() - #| let hi = alphabet(i / 16) - #| let lo = alphabet(i % 16) - #| "b'\\x\{hi}\{lo}'" - #|} - #|pub impl Hash for Byte with hash_combine(self, hasher) { - #| hasher.combine_byte(self) - #|} - #|pub impl Default for Byte with default() { - #| b'\x00' - #|} - #|pub fn Byte::lnot(self : Byte) -> Byte { - #| self.to_int().lnot().to_byte() - #|} - #|pub impl BitAnd for Byte with land(self : Byte, that : Byte) -> Byte { - #| (self.to_int() & that.to_int()).to_byte() - #|} - #|pub impl BitOr for Byte with lor(self : Byte, that : Byte) -> Byte { - #| (self.to_int() | that.to_int()).to_byte() - #|} - #|pub impl BitXOr for Byte with lxor(self : Byte, that : Byte) -> Byte { - #| (self.to_int() ^ that.to_int()).to_byte() - #|} - #|pub fn Byte::to_uint(self : Byte) -> UInt { - #| self.to_int().reinterpret_as_uint() - #|} - #|pub fn Byte::to_uint64(self : Byte) -> UInt64 { - #| self.to_uint().to_uint64() - #|} - #|pub fn Byte::popcnt(self : Byte) -> Int { - #| let mut n = self - #| n = (n & 0x55) + ((n >> 1) & 0x55) - #| n = (n & 0x33) + ((n >> 2) & 0x33) - #| n = (n & 0x0F) + ((n >> 4) & 0x0F) - #| n.to_int() - #|} - #|pub impl Shl for Byte with shl(self : Byte, count : Int) -> Byte { - #| (self.to_int() << count).to_byte() - #|} - #|pub impl Shr for Byte with shr(self : Byte, count : Int) -> Byte { - #| (self.to_uint() >> count).reinterpret_as_int().to_byte() - #|} - ), - "bytes.mbt": ( - #|#internal(unsafe, "Creating mutable Bytes") - #|#doc(hidden) - #|pub fn FixedArray::unsafe_reinterpret_as_bytes( - #| self : FixedArray[Byte], - #|) -> Bytes = "%identity" - #|pub fn Bytes::makei(length : Int, value : (Int) -> Byte raise?) -> Bytes raise? { - #| if length <= 0 { - #| return [] - #| } - #| let arr = FixedArray::make(length, value(0)) - #| for i in 1.. String = "$moonbit.unsafe_bytes_sub_string" - #|pub fn Bytes::to_unchecked_string( - #| self : Bytes, - #| offset? : Int = 0, - #| length? : Int, - #|) -> String { - #| let len = self.length() - #| let length = if length is Some(l) { l } else { len - offset } - #| guard offset >= 0 && length >= 0 && offset + length <= len - #| unsafe_sub_string(self, offset, length) - #|} - #|pub fn FixedArray::blit_from_string( - #| self : FixedArray[Byte], - #| bytes_offset : Int, - #| str : String, - #| str_offset : Int, - #| length : Int, - #|) -> Unit { - #| let s1 = bytes_offset - #| let s2 = str_offset - #| let e1 = bytes_offset + length * 2 - 1 - #| let e2 = str_offset + length - 1 - #| let len1 = self.length() - #| let len2 = str.length() - #| guard length >= 0 && s1 >= 0 && e1 < len1 && s2 >= 0 && e2 < len2 - #| let end_str_offset = str_offset + length - #| for i = str_offset, j = bytes_offset; i < end_str_offset; i = i + 1, j = j + 2 { - #| let c = str.unsafe_charcode_at(i).reinterpret_as_uint() - #| self[j] = (c & 0xff).to_byte() - #| self[j + 1] = (c >> 8).to_byte() - #| } - #|} - #|fn unsafe_from_bytes(bytes : Bytes) -> FixedArray[Byte] = "%identity" - #|pub fn FixedArray::blit_from_bytes( - #| self : FixedArray[Byte], - #| bytes_offset : Int, - #| src : Bytes, - #| src_offset : Int, - #| length : Int, - #|) -> Unit { - #| let s1 = bytes_offset - #| let s2 = src_offset - #| let e1 = bytes_offset + length - 1 - #| let e2 = src_offset + length - 1 - #| let len1 = self.length() - #| let len2 = src.length() - #| guard length >= 0 && s1 >= 0 && e1 < len1 && s2 >= 0 && e2 < len2 - #| FixedArray::unsafe_blit( - #| self, - #| bytes_offset, - #| unsafe_from_bytes(src), - #| src_offset, - #| length, - #| ) - #|} - #|pub fn FixedArray::blit_from_bytesview( - #| self : FixedArray[Byte], - #| bytes_offset : Int, - #| src : BytesView, - #|) -> Unit { - #| FixedArray::blit_from_bytes( - #| self, - #| bytes_offset, - #| src.bytes(), - #| src.start(), - #| src.len(), - #| ) - #|} - #|pub fn FixedArray::set_utf8_char( - #| self : FixedArray[Byte], - #| offset : Int, - #| value : Char, - #|) -> Int { - #| let code = value.to_uint() - #| match code { - #| _..<0x80 => { - #| self[offset] = ((code & 0x7F) | 0x00).to_byte() - #| 1 - #| } - #| _..<0x0800 => { - #| self[offset] = (((code >> 6) & 0x1F) | 0xC0).to_byte() - #| self[offset + 1] = ((code & 0x3F) | 0x80).to_byte() - #| 2 - #| } - #| _..<0x010000 => { - #| self[offset] = (((code >> 12) & 0x0F) | 0xE0).to_byte() - #| self[offset + 1] = (((code >> 6) & 0x3F) | 0x80).to_byte() - #| self[offset + 2] = ((code & 0x3F) | 0x80).to_byte() - #| 3 - #| } - #| _..<0x110000 => { - #| self[offset] = (((code >> 18) & 0x07) | 0xF0).to_byte() - #| self[offset + 1] = (((code >> 12) & 0x3F) | 0x80).to_byte() - #| self[offset + 2] = (((code >> 6) & 0x3F) | 0x80).to_byte() - #| self[offset + 3] = ((code & 0x3F) | 0x80).to_byte() - #| 4 - #| } - #| _ => abort("Char out of range") - #| } - #|} - #|pub fn FixedArray::set_utf16le_char( - #| self : FixedArray[Byte], - #| offset : Int, - #| value : Char, - #|) -> Int { - #| let code = value.to_uint() - #| if code < 0x10000 { - #| self[offset] = (code & 0xFF).to_byte() - #| self[offset + 1] = (code >> 8).to_byte() - #| 2 - #| } else if code < 0x110000 { - #| let hi = code - 0x10000 - #| let lo = (hi >> 10) | 0xD800 - #| let hi = (hi & 0x3FF) | 0xDC00 - #| self[offset] = (lo & 0xFF).to_byte() - #| self[offset + 1] = (lo >> 8).to_byte() - #| self[offset + 2] = (hi & 0xFF).to_byte() - #| self[offset + 3] = (hi >> 8).to_byte() - #| 4 - #| } else { - #| abort("Char out of range") - #| } - #|} - #|pub fn FixedArray::set_utf16be_char( - #| self : FixedArray[Byte], - #| offset : Int, - #| value : Char, - #|) -> Int { - #| let code = value.to_uint() - #| if code < 0x10000 { - #| self[offset] = (code >> 8).to_byte() - #| self[offset + 1] = (code & 0xFF).to_byte() - #| 2 - #| } else if code < 0x110000 { - #| let hi = code - 0x10000 - #| let lo = (hi >> 10) | 0xD800 - #| let hi = (hi & 0x3FF) | 0xDC00 - #| self[offset] = (lo >> 8).to_byte() - #| self[offset + 1] = (lo & 0xFF).to_byte() - #| self[offset + 2] = (hi >> 8).to_byte() - #| self[offset + 3] = (hi & 0xFF).to_byte() - #| 4 - #| } else { - #| abort("Char out of range") - #| } - #|} - #|pub impl Eq for Bytes with equal(self : Bytes, other : Bytes) -> Bool { - #| if self.length() != other.length() { - #| false - #| } else { - #| let len = self.length() - #| for i in 0.. Bytes { - #| Bytes::makei(arr.length(), i => arr[i]) - #|} - #|#deprecated("Use Bytes::from_array instead") - #|pub fn Bytes::from_fixedarray(arr : FixedArray[Byte], len? : Int) -> Bytes { - #| let len = match len { - #| None => arr.length() - #| Some(x) => { - #| guard 0 <= x && x <= arr.length() - #| x - #| } - #| } - #| let result = unsafe_to_fixedarray(UninitializedArray::make(len)) - #| arr.blit_to(result, len~) - #| result.unsafe_reinterpret_as_bytes() - #|} - #|#label_migration(len, fill=false) - #|pub fn Bytes::to_fixedarray(self : Bytes, len? : Int) -> FixedArray[Byte] { - #| let len = match len { - #| None => self.length() - #| Some(x) => { - #| guard 0 <= x && x <= self.length() - #| x - #| } - #| } - #| let arr = unsafe_to_fixedarray(UninitializedArray::make(len)) - #| arr.blit_from_bytes(0, self, 0, len) - #| arr - #|} - #|pub fn BytesView::to_fixedarray(self : BytesView) -> FixedArray[Byte] { - #| let len = self.length() - #| let arr = unsafe_to_fixedarray(UninitializedArray::make(len)) - #| arr.blit_from_bytes(0, self.data(), self.start_offset(), len) - #| arr - #|} - #|pub fn Bytes::from_iter(iter : Iter[Byte]) -> Bytes { - #| Bytes::from_array(iter.collect()) - #|} - #|pub fn Bytes::from_iterator(iter : Iterator[Byte]) -> Bytes { - #| Bytes::from_array(iter.collect()) - #|} - #|pub fn Bytes::to_array(self : Bytes) -> Array[Byte] { - #| let len = self.length() - #| let rv = Array::make(len, b'0') - #| for i in 0.. Array[Byte] { - #| let len = self.length() - #| let rv = Array::make(len, b'0') - #| for i in 0.. Iter[Byte] { - #| self.iterator().iter() - #|} - #|pub fn Bytes::iterator(self : Bytes) -> Iterator[Byte] { - #| let mut i = 0 - #| let len = self.length() - #| Iterator::new(fn() { - #| guard i < len else { None } - #| let c = self.unsafe_get(i) - #| i += 1 - #| Some(c) - #| }) - #|} - #|pub fn Bytes::iter2(self : Bytes) -> Iter2[Int, Byte] { - #| self.Iter2().iter2() - #|} - #|pub fn Bytes::Iter2(self : Bytes) -> Iter2[Int, Byte] { - #| let mut i = 0 - #| let len = self.length() - #| Iterator::new(fn() { - #| guard i < len else { None } - #| let result = (i, self.unsafe_get(i)) - #| i += 1 - #| Some(result) - #| }) - #|} - #|pub impl Default for Bytes with default() { - #| b"" - #|} - #|pub fn Bytes::get(self : Bytes, index : Int) -> Byte? { - #| guard index >= 0 && index < self.length() else { None } - #| Some(self[index]) - #|} - #|fn unsafe_to_fixedarray(array : UninitializedArray[Byte]) -> FixedArray[Byte] = "%identity" - #|pub impl Add for Bytes with add(self : Bytes, other : Bytes) -> Bytes { - #| let len_self = self.length() - #| let len_other = other.length() - #| let rv : FixedArray[Byte] = FixedArray::make(len_self + len_other, 0) - #| for i in 0.. Bytes { - #| if count <= 0 || self.length() == 0 { - #| return [] - #| } - #| if count == 1 { - #| return self - #| } - #| let len = self.length() - #| let total = len * count - #| guard total / count == len - #| let arr = FixedArray::make(total, (0 : Byte)) - #| arr.blit_from_bytes(0, self, 0, len) - #| let mut filled = len - #| while filled < total { - #| let remaining = total - filled - #| let copy_len = if filled < remaining { filled } else { remaining } - #| let src = unsafe_to_bytes(arr) - #| arr.blit_from_bytes(filled, src, 0, copy_len) - #| filled = filled + copy_len - #| } - #| unsafe_to_bytes(arr) - #|} - ), - "bytes_find.mbt": ( - #|pub fn BytesView::find(target : BytesView, pattern : BytesView) -> Int? { - #| let target_len = target.length() - #| let pattern_len = pattern.length() - #| for i in 0..=(target_len - pattern_len) { - #| for j in 0.. Int? { - #| target[:].find(pattern) - #|} - #|pub fn BytesView::rev_find(target : BytesView, pattern : BytesView) -> Int? { - #| let target_len = target.length() - #| let pattern_len = pattern.length() - #| for i = target_len - pattern_len; i >= 0; i = i - 1 { - #| for j in 0.. Int? { - #| target[:].rev_find(pattern) - #|} - ), - "bytes_unsafe.mbt": ( - #|#intrinsic("%bytes.unsafe_write_uint64_le") - #|pub fn FixedArray::unsafe_write_uint64_le( - #| bytes : FixedArray[Byte], - #| index : Int, - #| value : UInt64, - #|) -> Unit { - #| for i in 0..=7 { - #| bytes.unsafe_set(i + index, (value >> (8 * i)).to_byte()) - #| } - #|} - #|#intrinsic("%bytes.unsafe_write_uint64_be") - #|pub fn FixedArray::unsafe_write_uint64_be( - #| bytes : FixedArray[Byte], - #| index : Int, - #| value : UInt64, - #|) -> Unit { - #| for i in 0..=7 { - #| bytes.unsafe_set(i + index, (value >> (8 * (7 - i))).to_byte()) - #| } - #|} - #|#intrinsic("%bytes.unsafe_write_uint32_le") - #|pub fn FixedArray::unsafe_write_uint32_le( - #| bytes : FixedArray[Byte], - #| index : Int, - #| value : UInt, - #|) -> Unit { - #| for i in 0..=3 { - #| bytes.unsafe_set(i + index, (value >> (8 * i)).to_byte()) - #| } - #|} - #|#intrinsic("%bytes.unsafe_write_uint32_be") - #|pub fn FixedArray::unsafe_write_uint32_be( - #| bytes : FixedArray[Byte], - #| index : Int, - #| value : UInt, - #|) -> Unit { - #| for i in 0..=3 { - #| bytes.unsafe_set(i + index, (value >> (8 * (3 - i))).to_byte()) - #| } - #|} - #|#intrinsic("%bytes.unsafe_write_uint16_le") - #|pub fn FixedArray::unsafe_write_uint16_le( - #| bytes : FixedArray[Byte], - #| index : Int, - #| value : UInt16, - #|) -> Unit { - #| for i in 0..=1 { - #| bytes.unsafe_set(i + index, (value >> (8 * i)).to_byte()) - #| } - #|} - #|#intrinsic("%bytes.unsafe_write_uint16_be") - #|pub fn FixedArray::unsafe_write_uint16_be( - #| bytes : FixedArray[Byte], - #| index : Int, - #| value : UInt16, - #|) -> Unit { - #| for i in 0..=1 { - #| bytes.unsafe_set(i + index, (value >> (8 * (1 - i))).to_byte()) - #| } - #|} - #|#intrinsic("%bytes.unsafe_read_uint64_le") - #|#doc(hidden) - #|pub fn Bytes::unsafe_read_uint64_le(bytes : Bytes, index : Int) -> UInt64 { - #| let mut result : UInt64 = 0 - #| for i in 0..=7 { - #| result = result | (bytes.unsafe_get(i + index).to_uint64() << (8 * i)) - #| } - #| result - #|} - #|#intrinsic("%bytes.unsafe_read_uint64_be") - #|#doc(hidden) - #|pub fn Bytes::unsafe_read_uint64_be(bytes : Bytes, index : Int) -> UInt64 { - #| let mut result : UInt64 = 0 - #| for i in 0..=7 { - #| result = result | (bytes.unsafe_get(i + index).to_uint64() << (8 * (7 - i))) - #| } - #| result - #|} - #|#intrinsic("%bytes.unsafe_read_uint32_le") - #|#doc(hidden) - #|pub fn Bytes::unsafe_read_uint32_le(bytes : Bytes, index : Int) -> UInt { - #| let mut result : UInt = 0 - #| for i in 0..=3 { - #| result = result | (bytes.unsafe_get(i + index).to_uint() << (8 * i)) - #| } - #| result - #|} - #|#intrinsic("%bytes.unsafe_read_uint32_be") - #|#doc(hidden) - #|pub fn Bytes::unsafe_read_uint32_be(bytes : Bytes, index : Int) -> UInt { - #| let mut result : UInt = 0 - #| for i in 0..=3 { - #| result = result | (bytes.unsafe_get(i + index).to_uint() << (8 * (3 - i))) - #| } - #| result - #|} - #|#intrinsic("%bytes.unsafe_read_uint16_le") - #|#doc(hidden) - #|pub fn Bytes::unsafe_read_uint16_le(bytes : Bytes, index : Int) -> UInt16 { - #| let mut result : UInt16 = 0 - #| for i in 0..=1 { - #| result = result | (bytes.unsafe_get(i + index).to_uint16() << (8 * i)) - #| } - #| result - #|} - #|#intrinsic("%bytes.unsafe_read_uint16_be") - #|#doc(hidden) - #|pub fn Bytes::unsafe_read_uint16_be(bytes : Bytes, index : Int) -> UInt16 { - #| let mut result : UInt16 = 0 - #| for i in 0..=1 { - #| result = result | (bytes.unsafe_get(i + index).to_uint16() << (8 * (1 - i))) - #| } - #| result - #|} - #|#doc(hidden) - #|pub fn BytesView::unsafe_read_uint64_le( - #| bytes : BytesView, - #| index : Int, - #|) -> UInt64 { - #| bytes.bytes().unsafe_read_uint64_le(bytes.start() + index) - #|} - #|#doc(hidden) - #|pub fn BytesView::unsafe_read_uint64_be( - #| bytes : BytesView, - #| index : Int, - #|) -> UInt64 { - #| bytes.bytes().unsafe_read_uint64_be(bytes.start() + index) - #|} - #|#doc(hidden) - #|pub fn BytesView::unsafe_read_uint32_le(bytes : BytesView, index : Int) -> UInt { - #| bytes.bytes().unsafe_read_uint32_le(bytes.start() + index) - #|} - #|#doc(hidden) - #|pub fn BytesView::unsafe_read_uint32_be(bytes : BytesView, index : Int) -> UInt { - #| bytes.bytes().unsafe_read_uint32_be(bytes.start() + index) - #|} - #|#doc(hidden) - #|pub fn BytesView::unsafe_read_uint16_le( - #| bytes : BytesView, - #| index : Int, - #|) -> UInt16 { - #| bytes.bytes().unsafe_read_uint16_le(bytes.start() + index) - #|} - #|#doc(hidden) - #|pub fn BytesView::unsafe_read_uint16_be( - #| bytes : BytesView, - #| index : Int, - #|) -> UInt16 { - #| bytes.bytes().unsafe_read_uint16_be(bytes.start() + index) - #|} - ), - "bytesview.mbt": ( - #|fn BytesView::bytes(self : BytesView) -> Bytes = "%bytesview.bytes" - #|fn BytesView::start(self : BytesView) -> Int = "%bytesview.start" - #|fn BytesView::len(self : BytesView) -> Int = "%bytesview.len" - #|fn BytesView::make(b : Bytes, start : Int, len : Int) -> BytesView = "%bytesview.make" - #|pub fn BytesView::length(self : BytesView) -> Int { - #| self.len() - #|} - #|#alias("_[_]") - #|pub fn BytesView::at(self : BytesView, index : Int) -> Byte { - #| guard index >= 0 && index < self.length() else { - #| abort( - #| "index out of bounds: the len is from 0 to \{self.length()} but the index is \{index}", - #| ) - #| } - #| self.bytes()[self.start() + index] - #|} - #|pub fn BytesView::get(self : BytesView, index : Int) -> Byte? { - #| guard index >= 0 && index < self.length() else { None } - #| Some(self.bytes().unsafe_get(self.start() + index)) - #|} - #|#internal(unsafe, "Panic if index is out of bounds") - #|#doc(hidden) - #|pub fn BytesView::unsafe_get(self : BytesView, index : Int) -> Byte { - #| self.bytes()[self.start() + index] - #|} - #|#alias("_[_:_]") - #|pub fn Bytes::sub(self : Bytes, start? : Int = 0, end? : Int) -> BytesView { - #| let len = self.length() - #| let end = match end { - #| None => len - #| Some(end) => if end < 0 { len + end } else { end } - #| } - #| let start = if start < 0 { len + start } else { start } - #| guard start >= 0 && start <= end && end <= len else { - #| abort("Invalid index for View") - #| } - #| BytesView::make(self, start, end - start) - #|} - #|#alias("_[_:_]") - #|pub fn BytesView::sub( - #| self : BytesView, - #| start? : Int = 0, - #| end? : Int, - #|) -> BytesView { - #| let len = self.length() - #| let end = match end { - #| None => len - #| Some(end) => if end < 0 { len + end } else { end } - #| } - #| let start = if start < 0 { len + start } else { start } - #| guard start >= 0 && start <= end && end <= len else { - #| abort("Invalid index for View") - #| } - #| BytesView::make(self.bytes(), self.start() + start, end - start) - #|} - #|pub fn BytesView::iter(self : BytesView) -> Iter[Byte] { - #| self.iterator().iter() - #|} - #|pub fn BytesView::iter2(self : BytesView) -> Iter2[Int, Byte] { - #| self.Iter2().iter2() - #|} - #|pub fn BytesView::iterator(self : BytesView) -> Iterator[Byte] { - #| let mut i = 0 - #| let len = self.length() - #| Iterator::new(fn() { - #| guard i < len else { None } - #| let result = self.unsafe_get(i) - #| i += 1 - #| Some(result) - #| }) - #|} - #|pub fn BytesView::Iter2(self : BytesView) -> Iter2[Int, Byte] { - #| let mut i = 0 - #| let len = self.length() - #| Iter2::new(fn() { - #| guard i < len else { None } - #| let result = (i, self.unsafe_get(i)) - #| i += 1 - #| Some(result) - #| }) - #|} - #|#deprecated("Use bits pattern directly") - #|#doc(hidden) - #|pub fn BytesView::to_uint_be(self : BytesView) -> UInt { - #| (self[0].to_uint() << 24) + - #| (self[1].to_uint() << 16) + - #| (self[2].to_uint() << 8) + - #| self[3].to_uint() - #|} - #|#deprecated("Use bits pattern directly") - #|#doc(hidden) - #|pub fn BytesView::to_uint_le(self : BytesView) -> UInt { - #| self[0].to_uint() + - #| (self[1].to_uint() << 8) + - #| (self[2].to_uint() << 16) + - #| (self[3].to_uint() << 24) - #|} - #|#deprecated("Use bits pattern directly") - #|#doc(hidden) - #|pub fn BytesView::to_uint64_be(self : BytesView) -> UInt64 { - #| (self[0].to_uint().to_uint64() << 56) + - #| (self[1].to_uint().to_uint64() << 48) + - #| (self[2].to_uint().to_uint64() << 40) + - #| (self[3].to_uint().to_uint64() << 32) + - #| (self[4].to_uint().to_uint64() << 24) + - #| (self[5].to_uint().to_uint64() << 16) + - #| (self[6].to_uint().to_uint64() << 8) + - #| self[7].to_uint().to_uint64() - #|} - #|#deprecated("Use bits pattern directly") - #|#doc(hidden) - #|pub fn BytesView::to_uint64_le(self : BytesView) -> UInt64 { - #| self[0].to_uint().to_uint64() + - #| (self[1].to_uint().to_uint64() << 8) + - #| (self[2].to_uint().to_uint64() << 16) + - #| (self[3].to_uint().to_uint64() << 24) + - #| (self[4].to_uint().to_uint64() << 32) + - #| (self[5].to_uint().to_uint64() << 40) + - #| (self[6].to_uint().to_uint64() << 48) + - #| (self[7].to_uint().to_uint64() << 56) - #|} - #|#deprecated - #|#doc(hidden) - #|pub fn BytesView::to_int_be(self : BytesView) -> Int { - #| guard self is [u32be(u32), ..] - #| u32.reinterpret_as_int() - #|} - #|#deprecated - #|#doc(hidden) - #|pub fn BytesView::to_int_le(self : BytesView) -> Int { - #| guard self is [u32le(u32), ..] - #| u32.reinterpret_as_int() - #|} - #|#deprecated - #|#doc(hidden) - #|pub fn BytesView::to_int64_be(self : BytesView) -> Int64 { - #| guard self is [u64be(u64), ..] - #| u64.reinterpret_as_int64() - #|} - #|#deprecated - #|#doc(hidden) - #|pub fn BytesView::to_int64_le(self : BytesView) -> Int64 { - #| guard self is [u64le(u64), ..] - #| u64.reinterpret_as_int64() - #|} - #|#deprecated("Use bits pattern directly") - #|#doc(hidden) - #|pub fn BytesView::to_double_be(self : BytesView) -> Double { - #| guard self is [u64be(u64), ..] - #| u64.reinterpret_as_double() - #|} - #|#deprecated("Use bits pattern directly") - #|#doc(hidden) - #|pub fn BytesView::to_double_le(self : BytesView) -> Double { - #| guard self is [u64le(u64), ..] - #| u64.reinterpret_as_double() - #|} - #|pub impl Show for BytesView with output(self, logger) { - #| logger.write_string("b\"") - #| for byte in self { - #| if byte is (' '..='~') && byte != '"' && byte != '\\' { - #| logger.write_char(byte.to_char()) - #| } else { - #| logger..write_string("\\x")..write_string(byte.to_hex()) - #| } - #| } - #| logger.write_string("\"") - #|} - #|pub impl Show for Bytes with output(self, logger) { - #| BytesView::output(self[:], logger) - #|} - #|pub impl Eq for BytesView with equal(self, other) -> Bool { - #| guard self.length() == other.length() else { return false } - #| for i in 0.. Int { - #| let self_len = self.length() - #| let other_len = other.length() - #| let cmp = self_len.compare(other_len) - #| guard cmp == 0 else { return cmp } - #| for i in 0.. Bytes { - #| self.bytes() - #|} - #|pub fn BytesView::start_offset(self : BytesView) -> Int { - #| self.start() - #|} - #|pub fn BytesView::to_bytes(self : BytesView) -> Bytes { - #| if self.length() == self.bytes().length() { - #| return self.bytes() - #| } - #| let bytes = FixedArray::make(self.length(), (0 : Byte)) - #| bytes.blit_from_bytes(0, self.bytes(), self.start_offset(), self.length()) - #| unsafe_to_bytes(bytes) - #|} - #|pub impl ToJson for BytesView with to_json(self) -> Json { - #| let sb = StringBuilder::new() - #| for byte in self { - #| if byte is (' '..='~') && byte != '"' && byte != '\\' { - #| sb.write_char(byte.to_char()) - #| } else { - #| sb..write_string("\\x")..write_string(byte.to_hex()) - #| } - #| } - #| Json::string(sb.to_string()) - #|} - #|pub impl ToJson for Bytes with to_json(self : Bytes) -> Json { - #| BytesView::to_json(self[:]) - #|} - ), - "char.mbt": ( - #|fn Char::to_hex(char : Char) -> String { - #| let code = char.to_int() - #| match code { - #| 0..=0xFF => code.to_byte().to_hex() - #| _..=0xFFFF => (code >> 8).to_byte().to_hex() + code.to_byte().to_hex() - #| _ => - #| (code >> 16).to_byte().to_hex() + - #| (code >> 8).to_byte().to_hex() + - #| code.to_byte().to_hex() - #| } - #|} - #|test "Char::to_hex" { - #| inspect(Char::to_hex('A'), content="41") - #| inspect(Char::to_hex('a'), content="61") - #| inspect(Char::to_hex('0'), content="30") - #| inspect(Char::to_hex('\n'), content="0a") - #| inspect(Char::to_hex('\u{0}'), content="00") - #| inspect(Char::to_hex('\u{FF}'), content="ff") - #| inspect(Char::to_hex('\u{100}'), content="0100") - #| inspect(Char::to_hex('\u{1000}'), content="1000") - #| inspect(Char::to_hex('😀'), content="01f600") - #|} - #|pub impl Hash for Char with hash_combine(self, hasher) -> Unit { - #| hasher.combine_char(self) - #|} - #|pub fn Char::is_ascii(self : Self) -> Bool { - #| self is ('\u{00}'..='\u{7F}') - #|} - #|pub fn Char::is_ascii_alphabetic(self : Self) -> Bool { - #| self is ('A'..='Z' | 'a'..='z') - #|} - #|pub fn Char::is_ascii_control(self : Self) -> Bool { - #| self is ('\u{00}'..='\u{1F}' | '\u{7F}') - #|} - #|pub fn Char::is_ascii_digit(self : Self) -> Bool { - #| self is ('0'..='9') - #|} - #|pub fn Char::is_ascii_graphic(self : Self) -> Bool { - #| self is ('\u{21}'..='\u{7E}') - #|} - #|pub fn Char::is_ascii_hexdigit(self : Self) -> Bool { - #| self is ('0'..='9' | 'A'..='F' | 'a'..='f') - #|} - #|pub fn Char::is_ascii_lowercase(self : Self) -> Bool { - #| self is ('a'..='z') - #|} - #|pub fn Char::is_ascii_octdigit(self : Self) -> Bool { - #| self is ('0'..='7') - #|} - #|pub fn Char::is_ascii_punctuation(self : Self) -> Bool { - #| self - #| is ('\u{21}'..='\u{2F}' - #| | '\u{3A}'..='\u{40}' - #| | '\u{5B}'..='\u{60}' - #| | '\u{7B}'..='\u{7E}') - #|} - #|pub fn Char::is_ascii_uppercase(self : Self) -> Bool { - #| self is ('A'..='Z') - #|} - #|pub fn Char::is_ascii_whitespace(self : Self) -> Bool { - #| self is ('\u{20}' | '\u{09}' | '\u{0A}' | '\u{0B}' | '\u{0C}' | '\u{0D}') - #|} - #|pub fn Char::is_control(self : Self) -> Bool { - #| self is ('\u0000'..='\u001F' | '\u007F'..='\u009F') - #|} - #|pub fn Char::is_digit(self : Self, radix : UInt) -> Bool { - #| let v = self.to_uint() - #| match radix { - #| 2..=10 => v >= 48 && v <= radix + 47 - #| 11..=36 => - #| (v >= 48 && v <= 57) || - #| (v >= 65 && v <= radix + 54) || - #| (v >= 97 && v <= radix + 86) - #| _ => panic() - #| } - #|} - #|pub fn Char::is_whitespace(self : Self) -> Bool { - #| self - #| is ('\u0009'..='\u000D' - #| | '\u0020' - #| | '\u0085' - #| | '\u00A0' - #| | '\u1680' - #| | '\u2000'..='\u200A' - #| | '\u2028' - #| | '\u2029' - #| | '\u202F' - #| | '\u205F' - #| | '\u3000') - #|} - #|pub fn Char::is_numeric(self : Self) -> Bool { - #| self - #| is ('\u0030'..='\u0039' - #| | '\u00B2' - #| | '\u00B3' - #| | '\u00B9' - #| | '\u00BC' - #| | '\u00BD' - #| | '\u00BE' - #| | '\u0660'..='\u0669' - #| | '\u06F0'..='\u06F9' - #| | '\u07C0'..='\u07F9' - #| | '\u0966'..='\u096F' - #| | '\u09E6'..='\u09EF' - #| | '\u09F4'..='\u09F9' - #| | '\u0A66'..='\u0A6F' - #| | '\u0AE6'..='\u0AEF' - #| | '\u0B66'..='\u0B6F' - #| | '\u0B72'..='\u0B77' - #| | '\u0BE6'..='\u0BEF' - #| | '\u0BF0'..='\u0BF2' - #| | '\u0C66'..='\u0C6F' - #| | '\u0C78'..='\u0C7E' - #| | '\u0CE6'..='\u0CEF' - #| | '\u0D58'..='\u0D5E' - #| | '\u0D66'..='\u0D6F' - #| | '\u0D70'..='\u0D78' - #| | '\u0DE6'..='\u0DEF' - #| | '\u0E50'..='\u0E59' - #| | '\u0ED0'..='\u0ED9' - #| | '\u0F20'..='\u0F33' - #| | '\u1040'..='\u1049' - #| | '\u1090'..='\u1099' - #| | '\u1369'..='\u137C' - #| | '\u16EE'..='\u16F0' - #| | '\u17E0'..='\u17E9' - #| | '\u17F0'..='\u17F9' - #| | '\u1810'..='\u1819' - #| | '\u1946'..='\u194F' - #| | '\u19D0'..='\u19DA' - #| | '\u1A80'..='\u1A89' - #| | '\u1A90'..='\u1A99' - #| | '\u1B50'..='\u1B59' - #| | '\u1BB0'..='\u1BB9' - #| | '\u1C40'..='\u1C49' - #| | '\u1C50'..='\u1C59' - #| | '\u2070' - #| | '\u2074'..='\u2079' - #| | '\u2080'..='\u2089' - #| | '\u2150'..='\u2189' - #| | '\u2460'..='\u249B' - #| | '\u24EA'..='\u24FF' - #| | '\u2776'..='\u2793' - #| | '\u2CFD' - #| | '\u3007' - #| | '\u3021'..='\u3029' - #| | '\u3038'..='\u303A' - #| | '\u3192'..='\u3195' - #| | '\u3220'..='\u3229' - #| | '\u3248'..='\u324F' - #| | '\u3251'..='\u325F' - #| | '\u3280'..='\u3289' - #| | '\u32B1'..='\u32BF' - #| | '\uA620'..='\uA629' - #| | '\uA6E6'..='\uA6EF' - #| | '\uA830'..='\uA835' - #| | '\uA8D0'..='\uA8D9' - #| | '\uA900'..='\uA909' - #| | '\uA9D0'..='\uA9D9' - #| | '\uA9F0'..='\uA9F9' - #| | '\uAA50'..='\uAA59' - #| | '\uABF0'..='\uABF9' - #| | '\uFF10'..='\uFF19' - #| | '\u{10107}'..='\u{10133}' - #| | '\u{10140}'..='\u{10178}' - #| | '\u{1018A}'..='\u{1018B}' - #| | '\u{102E1}'..='\u{102FB}' - #| | '\u{10320}'..='\u{10323}' - #| | '\u{10341}' - #| | '\u{1034A}' - #| | '\u{103D1}'..='\u{103D5}' - #| | '\u{104A0}'..='\u{104A9}' - #| | '\u{10858}'..='\u{1085F}' - #| | '\u{10879}'..='\u{1087F}' - #| | '\u{108A7}'..='\u{108AF}' - #| | '\u{108FB}'..='\u{108FF}' - #| | '\u{10916}'..='\u{1091B}' - #| | '\u{109BC}'..='\u{109BD}' - #| | '\u{109C0}'..='\u{109CF}' - #| | '\u{10A40}'..='\u{10A48}' - #| | '\u{10A7D}'..='\u{10A7E}' - #| | '\u{10A9D}'..='\u{10A9F}' - #| | '\u{10AEB}'..='\u{10AEF}' - #| | '\u{10B58}'..='\u{10B5F}' - #| | '\u{10B78}'..='\u{10B7F}' - #| | '\u{10BA9}'..='\u{10BAF}' - #| | '\u{10CFA}'..='\u{10CFF}' - #| | '\u{10D30}'..='\u{10D39}' - #| | '\u{10D40}'..='\u{10D49}' - #| | '\u{10E60}'..='\u{10E7E}' - #| | '\u{10F1D}'..='\u{10F26}' - #| | '\u{10F51}'..='\u{10F54}' - #| | '\u{10FC5}'..='\u{10FCB}' - #| | '\u{11052}'..='\u{1106F}' - #| | '\u{110F0}'..='\u{110F9}' - #| | '\u{11136}'..='\u{1113F}' - #| | '\u{111D0}'..='\u{111D9}' - #| | '\u{111E1}'..='\u{111F4}' - #| | '\u{112F0}'..='\u{112F9}' - #| | '\u{11450}'..='\u{11459}' - #| | '\u{114D0}'..='\u{114D9}' - #| | '\u{11650}'..='\u{11659}' - #| | '\u{116C0}'..='\u{116C9}' - #| | '\u{116D0}'..='\u{116E3}' - #| | '\u{11730}'..='\u{1173B}' - #| | '\u{118E0}'..='\u{118F2}' - #| | '\u{11950}'..='\u{11959}' - #| | '\u{11BF0}'..='\u{11BF9}' - #| | '\u{11C50}'..='\u{11C6C}' - #| | '\u{11D50}'..='\u{11D59}' - #| | '\u{11DA0}'..='\u{11DA9}' - #| | '\u{11F50}'..='\u{11F59}' - #| | '\u{11FC0}'..='\u{11FD4}' - #| | '\u{12400}'..='\u{1246E}' - #| | '\u{16130}'..='\u{16139}' - #| | '\u{16A60}'..='\u{16A69}' - #| | '\u{16AC0}'..='\u{16AC9}' - #| | '\u{16B50}'..='\u{16B59}' - #| | '\u{16B5B}'..='\u{16B61}' - #| | '\u{16D70}'..='\u{16D79}' - #| | '\u{16D80}'..='\u{16E96}' - #| | '\u{1CCF0}'..='\u{1CCF9}' - #| | '\u{1D2C0}'..='\u{1D2F3}' - #| | '\u{1D360}'..='\u{1D378}' - #| | '\u{1D7CE}'..='\u{1D7FF}' - #| | '\u{1E140}'..='\u{1E149}' - #| | '\u{1E2F0}'..='\u{1E2F9}' - #| | '\u{1E4F0}'..='\u{1E4F9}' - #| | '\u{1E5F1}'..='\u{1E5FA}' - #| | '\u{1E8C7}'..='\u{1E8CF}' - #| | '\u{1E950}'..='\u{1E959}' - #| | '\u{1EC71}'..='\u{1ECB4}' - #| | '\u{1ED01}'..='\u{1ED3D}' - #| | '\u{1F100}'..='\u{1F10C}' - #| | '\u{1FBF0}'..='\u{1FBF9}') - #|} - #|pub fn Char::is_printable(self : Self) -> Bool { - #| if self.is_control() { - #| return false - #| } - #| let self = self.to_int() - #| if self is (0xE000..=0xF8FF | 0xF0000..=0xFFFFD | 0x100000..=0x10FFFD) { - #| return false - #| } - #| if self - #| is ('\u{00AD}' - #| | '\u{0600}'..='\u{0605}' - #| | '\u{061C}' - #| | '\u{06DD}' - #| | '\u{070F}' - #| | '\u{0890}'..='\u{0891}' - #| | '\u{08E2}' - #| | '\u{180E}' - #| | '\u{200B}'..='\u{200F}' - #| | '\u{202A}'..='\u{202E}' - #| | '\u{2060}'..='\u{2064}' - #| | '\u{2066}'..='\u{206F}' - #| | '\u{feff}' - #| | '\u{FFF9}'..='\u{FFFB}' - #| | '\u{110BD}' - #| | '\u{110CD}' - #| | '\u{13430}'..='\u{1343F}' - #| | '\u{1BCA0}'..='\u{1BCA3}' - #| | '\u{1D173}'..='\u{1D17A}' - #| | '\u{E0001}' - #| | '\u{E0020}'..='\u{E007F}') { - #| return false - #| } - #| if self.is_surrogate() { - #| return false - #| } - #| if self == '\u{2028}' || self == '\u{2029}' { - #| return false - #| } - #| if self - #| is (0xFDD0..=0xFDEF - #| | 0xFFFE..=0xFFFF - #| | 0x1FFFE..=0x1FFFF - #| | 0x2FFFE..=0x2FFFF - #| | 0x3FFFE..=0x3FFFF - #| | 0x4FFFE..=0x4FFFF - #| | 0x5FFFE..=0x5FFFF - #| | 0x6FFFE..=0x6FFFF - #| | 0x7FFFE..=0x7FFFF - #| | 0x8FFFE..=0x8FFFF - #| | 0x9FFFE..=0x9FFFF - #| | 0xAFFFE..=0xAFFFF - #| | 0xBFFFE..=0xBFFFF - #| | 0xCFFFE..=0xCFFFF - #| | 0xDFFFE..=0xDFFFF - #| | 0xEFFFE..=0xEFFFF - #| | 0xFFFFE..=0xFFFFF - #| | 0x10FFFE..=0x10FFFF) { - #| return false - #| } - #| true - #|} - #|pub fn Char::to_ascii_lowercase(self : Self) -> Char { - #| if self.is_ascii_uppercase() { - #| return (self.to_int() + 32).unsafe_to_char() - #| } - #| self - #|} - #|pub fn Char::to_ascii_uppercase(self : Self) -> Char { - #| if self.is_ascii_lowercase() { - #| return (self.to_int() - 32).unsafe_to_char() - #| } - #| self - #|} - #|pub impl Show for Char with to_string(self : Char) -> String { - #| char_to_string(self) - #|} - #|#intrinsic("%char.to_string") - #|fn char_to_string(char : Char) -> String { - #| [char] - #|} - #|pub impl Show for Char with output(self, logger) { - #| logger.write_char('\'') - #| match self { - #| '\'' | '\\' => logger..write_char('\\')..write_char(self) - #| '\n' => logger.write_string("\\n") - #| '\r' => logger.write_string("\\r") - #| '\b' => logger.write_string("\\b") - #| '\t' => logger.write_string("\\t") - #| ' '..='~' => logger.write_char(self) - #| _ => - #| if !self.is_printable() { - #| logger.write_string("\\u{") - #| logger.write_string(self.to_hex()) - #| logger.write_char('}') - #| } else { - #| logger.write_char(self) - #| } - #| } - #| logger.write_char('\'') - #|} - #|pub impl ToJson for Char with to_json(self : Char) -> Json { - #| Json::string(self.to_string()) - #|} - #|pub fn Char::utf16_len(self : Self) -> Int { - #| let code = self.to_int() - #| if code <= 0xFFFF { - #| 1 - #| } else { - #| 2 - #| } - #|} - #|pub fn Char::is_bmp(self : Self) -> Bool { - #| self.to_int() <= 0xFFFF - #|} - ), - "console.mbt": ( - #|fn println_mono(s : String) -> Unit = "%println" - #|fn[T] any_to_string(any : T) -> String = "%any.to_string" - #|pub fn[T : Show] println(input : T) -> Unit { - #| println_mono(input.to_string()) - #|} - #|pub(all) suberror InspectError String - #|fn base64_encode(data : FixedArray[Byte]) -> String { - #| let base64 = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" - #| let buf = StringBuilder::new() - #| let len = data.length() - #| let rem = len % 3 - #| for i = 0; i < len - rem; i = i + 3 { - #| let b0 = data[i].to_int() - #| let b1 = data[i + 1].to_int() - #| let b2 = data[i + 2].to_int() - #| let x0 = base64[(b0 & 0xFC) >> 2] - #| let x1 = base64[((b0 & 0x03) << 4) | ((b1 & 0xF0) >> 4)] - #| let x2 = base64[((b1 & 0x0F) << 2) | ((b2 & 0xC0) >> 6)] - #| let x3 = base64[b2 & 0x3F] - #| buf.write_char(x0.to_char()) - #| buf.write_char(x1.to_char()) - #| buf.write_char(x2.to_char()) - #| buf.write_char(x3.to_char()) - #| } - #| if rem == 1 { - #| let b0 = data[len - 1].to_int() - #| let x0 = base64[(b0 & 0xFC) >> 2] - #| let x1 = base64[(b0 & 0x03) << 4] - #| buf.write_char(x0.to_char()) - #| buf.write_char(x1.to_char()) - #| buf.write_char('=') - #| buf.write_char('=') - #| } else if rem == 2 { - #| let b0 = data[len - 2].to_int() - #| let b1 = data[len - 1].to_int() - #| let x0 = base64[(b0 & 0xFC) >> 2] - #| let x1 = base64[((b0 & 0x03) << 4) | ((b1 & 0xF0) >> 4)] - #| let x2 = base64[(b1 & 0x0F) << 2] - #| buf.write_char(x0.to_char()) - #| buf.write_char(x1.to_char()) - #| buf.write_char(x2.to_char()) - #| buf.write_char('=') - #| } - #| buf.to_string() - #|} - #|fn base64_encode_string_codepoint(s : String) -> String { - #| let codepoint_length = s.char_length() - #| let data : FixedArray[Byte] = FixedArray::make(codepoint_length * 4, 0) - #| for i = 0, utf16_index = 0 - #| i < codepoint_length - #| i = i + 1, utf16_index = utf16_index + 1 { - #| let c = s.unsafe_char_at(utf16_index).to_int() - #| if c > 0xFFFF { - #| data[i * 4] = (c & 0xFF).to_byte() - #| data[i * 4 + 1] = ((c >> 8) & 0xFF).to_byte() - #| data[i * 4 + 2] = ((c >> 16) & 0xFF).to_byte() - #| data[i * 4 + 3] = ((c >> 24) & 0xFF).to_byte() - #| continue i + 1, utf16_index + 2 - #| } else { - #| data[i * 4] = (c & 0xFF).to_byte() - #| data[i * 4 + 1] = ((c >> 8) & 0xFF).to_byte() - #| data[i * 4 + 2] = 0 - #| data[i * 4 + 3] = 0 - #| } - #| } - #| base64_encode(data) - #|} - #|test { - #| inspect(base64_encode_string_codepoint("")) - #| inspect(base64_encode_string_codepoint("a"), content="YQAAAA==") - #| inspect(base64_encode_string_codepoint("ab"), content="YQAAAGIAAAA=") - #| inspect(base64_encode_string_codepoint("abc"), content="YQAAAGIAAABjAAAA") - #| inspect( - #| base64_encode_string_codepoint("abcd"), - #| content="YQAAAGIAAABjAAAAZAAAAA==", - #| ) - #| inspect( - #| base64_encode_string_codepoint("abcde"), - #| content="YQAAAGIAAABjAAAAZAAAAGUAAAA=", - #| ) - #| inspect(base64_encode_string_codepoint("a中"), content="YQAAAC1OAAA=") - #| inspect( - #| base64_encode_string_codepoint("a中🤣"), - #| content="YQAAAC1OAAAj+QEA", - #| ) - #| inspect( - #| base64_encode_string_codepoint("a中🤣a"), - #| content="YQAAAC1OAAAj+QEAYQAAAA==", - #| ) - #| inspect( - #| base64_encode_string_codepoint("a中🤣中"), - #| content="YQAAAC1OAAAj+QEALU4AAA==", - #| ) - #|} - #|#callsite(autofill(args_loc, loc)) - #|pub fn inspect( - #| obj : &Show, - #| content? : String = "", - #| loc~ : SourceLoc, - #| args_loc~ : ArgsLoc, - #|) -> Unit raise InspectError { - #| let actual = obj.to_string() - #| if actual != content { - #| let loc = loc.to_json_string() - #| let args_loc = args_loc.to_json() - #| let expect_escaped = content.escape() - #| let actual_escaped = actual.escape() - #| let expect_base64 = "\"\{base64_encode_string_codepoint(content)}\"" - #| let actual_base64 = "\"\{base64_encode_string_codepoint(actual)}\"" - #| raise InspectError( - #| "@EXPECT_FAILED {\"loc\": \{loc}, \"args_loc\": \{args_loc}, \"expect\": \{expect_escaped}, \"actual\": \{actual_escaped}, \"expect_base64\": \{expect_base64}, \"actual_base64\": \{actual_base64}}", - #| ) - #| } - #|} - #|pub(all) suberror SnapshotError String - #|pub(all) suberror BenchError String - #|test "panic error case of inspect" { - #| let x : Int = 42 - #| inspect(x, content="100") - #|} - ), - "deprecated.mbt": ( - #|#deprecated("Use `..<` in for loop or `until` method instead") - #|#coverage.skip - #|pub fn Int::upto(self : Int, end : Int, inclusive? : Bool = false) -> Iter[Int] { - #| yield_ => { - #| let mut i = self - #| while i < end || (inclusive && i == end) { - #| if yield_(i) is IterEnd { - #| break IterEnd - #| } - #| if i == end { - #| break IterContinue - #| } - #| i += 1 - #| } else { - #| IterContinue - #| } - #| } - #|} - #|#deprecated("Use `..<` in for loop or `until` method instead") - #|#coverage.skip - #|pub fn UInt::upto( - #| self : UInt, - #| end : UInt, - #| inclusive? : Bool = false, - #|) -> Iter[UInt] { - #| yield_ => { - #| let mut i = self - #| while i < end || (inclusive && i == end) { - #| if yield_(i) is IterEnd { - #| break IterEnd - #| } - #| if i == end { - #| break IterContinue - #| } - #| i += 1 - #| } else { - #| IterContinue - #| } - #| } - #|} - #|#deprecated("Use `..<` in for loop or `until` method instead") - #|#coverage.skip - #|pub fn UInt64::upto( - #| self : UInt64, - #| end : UInt64, - #| inclusive? : Bool = false, - #|) -> Iter[UInt64] { - #| yield_ => { - #| let mut i = self - #| while i < end || (inclusive && i == end) { - #| if yield_(i) is IterEnd { - #| break IterEnd - #| } - #| if i == end { - #| break IterContinue - #| } - #| i += 1 - #| } else { - #| IterContinue - #| } - #| } - #|} - #|#deprecated("Use `..<` in for loop or `until` method instead") - #|#coverage.skip - #|pub fn Int64::upto( - #| self : Int64, - #| end : Int64, - #| inclusive? : Bool = false, - #|) -> Iter[Int64] { - #| yield_ => { - #| let mut i = self - #| while i < end || (inclusive && i == end) { - #| if yield_(i) is IterEnd { - #| break IterEnd - #| } - #| if i == end { - #| break IterContinue - #| } - #| i += 1 - #| } else { - #| IterContinue - #| } - #| } - #|} - #|#deprecated("Use `..<` in for loop or `until` method instead") - #|#coverage.skip - #|pub fn Double::upto( - #| self : Double, - #| end : Double, - #| inclusive? : Bool = false, - #|) -> Iter[Double] { - #| yield_ => { - #| let mut i = self - #| while i < end || (inclusive && i == end) { - #| if yield_(i) is IterEnd { - #| break IterEnd - #| } - #| if i == end { - #| break IterContinue - #| } - #| i += 1 - #| } else { - #| IterContinue - #| } - #| } - #|} - #|#deprecated("check `@encoding/utf8.encode`") - #|#coverage.skip - #|pub fn Bytes::of_string(str : String) -> Bytes { - #| FixedArray::make(str.length() * 2, Byte::default()) - #| ..blit_from_string(0, str, 0, str.length()) - #| .unsafe_reinterpret_as_bytes() - #|} - #|#deprecated("Bytes are immutable. Use `FixedArray::blit_from_bytes` if it's really necessary.") - #|pub fn Bytes::copy(self : Bytes) -> Bytes { - #| Bytes::makei(self.length(), i => self[i]) - #|} - #|#deprecated("Use infix operator `<<` instead") - #|#coverage.skip - #|pub fn Byte::lsl(self : Byte, count : Int) -> Byte { - #| (self.to_int() << count).to_byte() - #|} - #|#deprecated("Use infix operator `>>` instead") - #|#coverage.skip - #|pub fn Byte::lsr(self : Byte, count : Int) -> Byte { - #| (self.to_uint() >> count).reinterpret_as_int().to_byte() - #|} - #|#callsite(autofill(loc)) - #|#deprecated("This function is for debugging only and should not be used in production", skip_current_package=true) - #|pub fn[T] dump(t : T, name? : String, loc~ : SourceLoc) -> T { - #| let name = match name { - #| Some(name) => name - #| None => "" - #| } - #| println("dump(\{name}@\{loc}) = \{any_to_string(t)}") - #| t - #|} - #|test "dump" { - #| let x = 42 - #| if false { - #| dump(()) // never reached here - #| assert_eq(dump(x) + x, 84) - #| } - #|} - #|#deprecated("The index will be changed to utf16 index. If you want to access n-th character, use `str.iter().nth(n).unwrap()` instead.") - #|pub fn String::codepoint_at(self : String, index : Int) -> Char { - #| let charcode_len = self.length() - #| guard index >= 0 && index < charcode_len else { abort("index out of bounds") } - #| for char_count = 0, utf16_offset = 0 - #| char_count < charcode_len && utf16_offset < index - #| char_count = char_count + 1, utf16_offset = utf16_offset + 1 { - #| let c1 = self.unsafe_charcode_at(char_count) - #| if c1.is_leading_surrogate() && char_count + 1 < charcode_len { - #| let c2 = self.unsafe_charcode_at(char_count + 1) - #| if c2.is_trailing_surrogate() { - #| continue char_count + 2, utf16_offset + 1 - #| } else { - #| abort("invalid surrogate pair") - #| } - #| } - #| } else { - #| guard utf16_offset == index && char_count < charcode_len else { - #| abort("index out of bounds") - #| } - #| let c1 = self.unsafe_charcode_at(char_count) - #| if c1.is_leading_surrogate() && char_count + 1 < charcode_len { - #| let c2 = self.unsafe_charcode_at(char_count + 1) - #| if c2.is_trailing_surrogate() { - #| code_point_of_surrogate_pair(c1, c2) - #| } else { - #| abort("invalid surrogate pair") - #| } - #| } else { - #| c1.unsafe_to_char() - #| } - #| } - #|} - #|#deprecated("Use `s.get_char(i).unwrap()` instead", skip_current_package=true) - #|pub fn String::unsafe_char_at(self : String, index : Int) -> Char { - #| let c1 = self.unsafe_charcode_at(index) - #| if c1.is_leading_surrogate() { - #| let c2 = self.unsafe_charcode_at(index + 1) - #| code_point_of_surrogate_pair(c1, c2) - #| } else { - #| c1.unsafe_to_char() - #| } - #|} - ), - "double_to_int.mbt": ( - #|pub fn Double::to_int(self : Double) -> Int { - #| if self != self { - #| 0 - #| } else if self >= 2147483647 { - #| 2147483647 - #| } else if self <= -2147483648 { - #| -2147483648 - #| } else { - #| self.to_unchecked_int() - #| } - #|} - #|fn Double::to_unchecked_int(self : Double) -> Int = "%f64_to_i32" - ), - "double_to_int64_js.mbt": ( - #|extern "js" fn MyInt64::from_double(value : Double) -> MyInt64 = - #| #|(a) => { - #| #| if (isNaN(a)) { - #| #| return { hi: 0, lo: 0 }; - #| #| } - #| #| if (a >= 9223372036854775807) { - #| #| return { hi: 0x7fffffff, lo: 0xffffffff }; - #| #| } - #| #| if (a <= -9223372036854775808) { - #| #| return { hi: -2147483648, lo: 0 }; - #| #| } - #| #| let neg = false; - #| #| if (a < 0) { - #| #| neg = true; - #| #| a = -a; - #| #| } - #| #| let hi = (a * (1 / 0x100000000)) | 0; - #| #| let lo = a >>> 0; - #| #| if (neg) { - #| #| if (lo === 0) { - #| #| hi = ~hi + 1; - #| #| } else { - #| #| hi = ~hi; - #| #| lo = ~lo + 1; - #| #| } - #| #| } - #| #| return { hi, lo }; - #| #|} - #|pub fn Double::to_int64(self : Double) -> Int64 { - #| MyInt64::from_double(self).to_int64() - #|} - #|extern "js" fn MyInt64::from_double_unsigned(value : Double) -> MyInt64 = - #| #|(a) => { - #| #| if (isNaN(a)) { - #| #| return { hi: 0, lo: 0 }; - #| #| } - #| #| if (a >= 18446744073709551615) { - #| #| return { hi: 0xffffffff, lo: 0xffffffff }; - #| #| } - #| #| if (a <= 0) { - #| #| return { hi: 0, lo: 0 }; - #| #| } - #| #| let hi = (a * (1 / 0x100000000)) | 0; - #| #| let lo = a | 0; - #| #| return { hi, lo }; - #| #|} - #|pub fn Double::to_uint64(self : Double) -> UInt64 { - #| MyInt64::from_double_unsigned(self).to_uint64() - #|} - ), - "double_to_int64_native.mbt": ( - #|fn Double::to_unchecked_int64(self : Double) -> Int64 = "%f64_to_i64" - #|pub fn Double::to_int64(self : Double) -> Int64 { - #| if self != self { - #| 0 - #| } else if self >= 9223372036854775807 { - #| 9223372036854775807L - #| } else if self <= -9223372036854775808 { - #| -9223372036854775808L - #| } else { - #| self.to_unchecked_int64() - #| } - #|} - #|fn Double::to_unchecked_uint64(self : Double) -> UInt64 = "%f64_to_i64" - #|pub fn Double::to_uint64(self : Double) -> UInt64 { - #| if self != self { - #| 0 - #| } else if self >= 9223372036854775807 { - #| 18446744073709551615UL - #| } else if self <= 0 { - #| 0UL - #| } else { - #| self.to_unchecked_uint64() - #| } - #|} - ), - "double_to_int64_wasm.mbt": ( - #|pub fn Double::to_int64(self : Double) -> Int64 = "%f64_to_i64_saturate" - #|pub fn Double::to_uint64(self : Double) -> UInt64 = "%f64.to_u64_saturate" - ), - "double_to_int_wasm.mbt": ( - #|pub fn Double::to_int(self : Double) -> Int = "%f64_to_i32_saturate" - ), - "failure.mbt": ( - #|pub(all) suberror Failure String derive(ToJson, Show) - #|#callsite(autofill(loc)) - #|pub fn[T] fail(msg : String, loc~ : SourceLoc) -> T raise Failure { - #| raise Failure("\{loc} FAILED: \{msg}") - #|} - ), - "fixedarray.mbt": ( - #|pub fn[T] FixedArray::get(self : FixedArray[T], idx : Int) -> T? { - #| let len = self.length() - #| guard idx >= 0 && idx < len else { None } - #| Some(self.unsafe_get(idx)) - #|} - #|#intrinsic("%iter.from_array") - #|pub fn[T] FixedArray::iter(self : FixedArray[T]) -> Iter[T] { - #| self.iterator().iter() - #|} - #|pub fn[T] FixedArray::iter2(self : FixedArray[T]) -> Iter2[Int, T] { - #| self.Iter2().iter2() - #|} - #|pub impl[X] Default for FixedArray[X] with default() { - #| [] - #|} - #|pub fn[T] FixedArray::fill( - #| self : FixedArray[T], - #| value : T, - #| start? : Int = 0, - #| end? : Int, - #|) -> Unit { - #| let array_length = self.length() - #| guard array_length > 0 else { return } - #| guard start >= 0 && start < array_length - #| let length = match end { - #| None => array_length - start - #| Some(e) => { - #| guard e >= start && e <= array_length - #| e - start - #| } - #| } - #| self.unchecked_fill(start, value, length) - #|} - #|#intrinsic("%fixedarray.fill") - #|fn[T] FixedArray::unchecked_fill( - #| self : FixedArray[T], - #| start : Int, - #| value : T, - #| len : Int, - #|) -> Unit { - #| for i in start..<(start + len) { - #| self[i] = value - #| } - #|} - #|pub fn[T] FixedArray::is_empty(self : FixedArray[T]) -> Bool { - #| self.length() == 0 - #|} - #|pub fn[T : Compare] FixedArray::binary_search( - #| self : FixedArray[T], - #| value : T, - #|) -> Result[Int, Int] { - #| let len = self.length() - #| for i = 0, j = len; i < j; { - #| let h = i + (j - i) / 2 - #| if self.unsafe_get(h) < value { - #| continue h + 1, j - #| } else { - #| continue i, h - #| } - #| } else { - #| if i < len && self.unsafe_get(i) == value { - #| Ok(i) - #| } else { - #| Err(i) - #| } - #| } - #|} - #|#locals(cmp) - #|pub fn[T] FixedArray::binary_search_by( - #| self : FixedArray[T], - #| cmp : (T) -> Int raise?, - #|) -> Result[Int, Int] raise? { - #| let len = self.length() - #| for i = 0, j = len; i < j; { - #| let h = i + (j - i) / 2 - #| if cmp(self.unsafe_get(h)) < 0 { - #| continue h + 1, j - #| } else { - #| continue i, h - #| } - #| } else { - #| if i < len && cmp(self.unsafe_get(i)) == 0 { - #| Ok(i) - #| } else { - #| Err(i) - #| } - #| } - #|} - #|pub fn[T] FixedArray::each( - #| self : FixedArray[T], - #| f : (T) -> Unit raise?, - #|) -> Unit raise? { - #| for v in self { - #| f(v) - #| } - #|} - #|test "each" { - #| let mut i = 0 - #| let mut failed = false - #| let f = elem => { - #| if elem != i + 1 { - #| failed = true - #| } - #| i = i + 1 - #| } - #| { - #| i = 0 - #| ([] : FixedArray[_]).each(f) - #| assert_false(failed) - #| inspect(i, content="0") - #| } - #| { - #| i = 0 - #| ([1] : FixedArray[_]).each(f) - #| assert_false(failed) - #| inspect(i, content="1") - #| } - #| i = 0 - #| ([1, 2, 3, 4, 5] : FixedArray[_]).each(f) - #| assert_false(failed) - #| inspect(i, content="5") - #|} - #|pub fn[T] FixedArray::eachi( - #| self : FixedArray[T], - #| f : (Int, T) -> Unit raise?, - #|) -> Unit raise? { - #| for i, v in self { - #| f(i, v) - #| } - #|} - #|test "eachi" { - #| let mut i = 0 - #| let mut failed = false - #| let f = (index, elem) => { - #| if index != i || elem != i + 1 { - #| failed = true - #| } - #| i = i + 1 - #| } - #| { - #| i = 0 - #| ([] : FixedArray[_]).eachi(f) - #| assert_false(failed) - #| inspect(i, content="0") - #| } - #| { - #| i = 0 - #| ([1] : FixedArray[_]).eachi(f) - #| assert_false(failed) - #| inspect(i, content="1") - #| } - #| i = 0 - #| ([1, 2, 3, 4, 5] : FixedArray[_]).eachi(f) - #| assert_false(failed) - #| inspect(i, content="5") - #|} - #|pub fn[T] FixedArray::rev_each( - #| self : FixedArray[T], - #| f : (T) -> Unit raise?, - #|) -> Unit raise? { - #| for i = self.length() - 1; i >= 0; i = i - 1 { - #| f(self[i]) - #| } - #|} - #|test "rev_each" { - #| let mut i = 6 - #| let mut failed = false - #| let f = elem => { - #| if elem != i - 1 { - #| failed = true - #| } - #| i = i - 1 - #| } - #| { - #| i = 1 - #| ([] : FixedArray[_]).rev_each(f) - #| assert_false(failed) - #| inspect(i, content="1") - #| } - #| { - #| i = 2 - #| ([1] : FixedArray[_]).rev_each(f) - #| assert_false(failed) - #| inspect(i, content="1") - #| } - #| i = 6 - #| ([1, 2, 3, 4, 5] : FixedArray[_]).rev_each(f) - #| assert_false(failed) - #| inspect(i, content="1") - #|} - #|pub fn[T] FixedArray::rev_eachi( - #| self : FixedArray[T], - #| f : (Int, T) -> Unit raise?, - #|) -> Unit raise? { - #| let len = self.length() - #| for i in 0.. { - #| if index != j || elem != i - 1 { - #| failed = true - #| } - #| i = i - 1 - #| j = j + 1 - #| } - #| { - #| i = 1 - #| j = 0 - #| ([] : FixedArray[_]).rev_eachi(f) - #| assert_false(failed) - #| inspect(i, content="1") - #| inspect(j, content="0") - #| } - #| { - #| i = 2 - #| j = 0 - #| ([1] : FixedArray[_]).rev_eachi(f) - #| assert_false(failed) - #| inspect(i, content="1") - #| inspect(j, content="1") - #| } - #| i = 6 - #| j = 0 - #| ([1, 2, 3, 4, 5] : FixedArray[_]).rev_eachi(f) - #| assert_false(failed) - #| inspect(i, content="1") - #| inspect(j, content="5") - #|} - #|pub fn[T, U] FixedArray::map( - #| self : FixedArray[T], - #| f : (T) -> U raise?, - #|) -> FixedArray[U] raise? { - #| if self.length() == 0 { - #| return [] - #| } - #| let res = FixedArray::make(self.length(), f(self[0])) - #| for i in 1.. x) - #| assert_eq(empty, []) - #| let simple_arr : FixedArray[_] = [6] - #| let simple_doubled = simple_arr.map(x => x * 2) - #| assert_eq(simple_doubled, [12]) - #| let arr : FixedArray[_] = [1, 2, 3, 4, 5] - #| let doubled = arr.map(x => x * 2) - #| assert_eq(doubled, [2, 4, 6, 8, 10]) - #|} - #|pub fn[T, U] FixedArray::mapi( - #| self : FixedArray[T], - #| f : (Int, T) -> U raise?, - #|) -> FixedArray[U] raise? { - #| if self.length() == 0 { - #| return [] - #| } - #| let res = FixedArray::make(self.length(), f(0, self[0])) - #| for i in 1.. x + i) - #| assert_eq(empty, []) - #| let simple_arr : FixedArray[_] = [6] - #| let simple_doubled = simple_arr.mapi((i, x) => x * 2 + i) - #| assert_eq(simple_doubled, [12]) - #| let arr : FixedArray[_] = [1, 2, 3, 4, 5] - #| let doubled = arr.mapi((i, x) => x * 2 + i) - #| assert_eq(doubled, [2, 5, 8, 11, 14]) - #|} - #|#locals(value) - #|pub fn[T] FixedArray::makei( - #| length : Int, - #| value : (Int) -> T raise?, - #|) -> FixedArray[T] raise? { - #| if length <= 0 { - #| [] - #| } else { - #| let array = FixedArray::make(length, value(0)) - #| for i in 1.. i) - #| inspect(empty.length(), content="0") - #| let simple_arr = FixedArray::makei(1, i => i) - #| inspect(simple_arr.length(), content="1") - #| inspect(simple_arr[0], content="0") - #| let arr = FixedArray::makei(2, i => i) - #| inspect(arr.length(), content="2") - #| inspect(arr[0], content="0") - #| inspect(arr[1], content="1") - #|} - #|pub fn[T] FixedArray::from_array(array : ArrayView[T]) -> FixedArray[T] { - #| FixedArray::makei(array.length(), i => array.unsafe_get(i)) - #|} - #|test "from_array" { - #| let array = FixedArray::from_array([1, 2, 3, 4, 5]) - #| assert_eq(array, [1, 2, 3, 4, 5]) - #|} - #|pub fn[A, B] FixedArray::fold( - #| self : FixedArray[A], - #| init~ : B, - #| f : (B, A) -> B raise?, - #|) -> B raise? { - #| for i = 0, acc = init; i < self.length(); { - #| continue i + 1, f(acc, self[i]) - #| } else { - #| acc - #| } - #|} - #|test "fold" { - #| let sum = ([] : FixedArray[_]).fold(init=1, (sum, elem) => sum + elem) - #| inspect(sum, content="1") - #| let sum = ([1] : FixedArray[_]).fold(init=2, (sum, elem) => sum + elem) - #| inspect(sum, content="3") - #| let sum = ([1, 2, 3, 4, 5] : FixedArray[_]).fold(init=0, (sum, elem) => sum + - #| elem) - #| inspect(sum, content="15") - #|} - #|pub fn[A, B] FixedArray::rev_fold( - #| self : FixedArray[A], - #| init~ : B, - #| f : (B, A) -> B raise?, - #|) -> B raise? { - #| for i = self.length() - 1, acc = init; i >= 0; { - #| continue i - 1, f(acc, self[i]) - #| } else { - #| acc - #| } - #|} - #|test "rev_fold" { - #| let sum = ([] : FixedArray[_]).rev_fold(init=1, (sum, elem) => sum + elem) - #| inspect(sum, content="1") - #| let sum = ([1] : FixedArray[_]).rev_fold(init=2, (sum, elem) => sum + elem) - #| inspect(sum, content="3") - #| let sum = ([1, 2, 3, 4, 5] : FixedArray[_]).rev_fold(init=0, (sum, elem) => sum + - #| elem) - #| inspect(sum, content="15") - #|} - #|pub fn[A, B] FixedArray::foldi( - #| self : FixedArray[A], - #| init~ : B, - #| f : (Int, B, A) -> B raise?, - #|) -> B raise? { - #| for i = 0, acc = init; i < self.length(); { - #| continue i + 1, f(i, acc, self[i]) - #| } else { - #| acc - #| } - #|} - #|test "fold_lefti" { - #| let f = (index, sum, elem) => index + sum + elem - #| { - #| let sum = ([] : FixedArray[_]).foldi(init=1, f) - #| inspect(sum, content="1") - #| } - #| { - #| let sum = ([1] : FixedArray[_]).foldi(init=2, f) - #| inspect(sum, content="3") - #| } - #| let sum = ([1, 2, 3, 4, 5] : FixedArray[_]).foldi(init=0, f) - #| inspect(sum, content="25") - #|} - #|pub fn[A, B] FixedArray::rev_foldi( - #| self : FixedArray[A], - #| init~ : B, - #| f : (Int, B, A) -> B raise?, - #|) -> B raise? { - #| let len = self.length() - #| for i = len - 1, acc = init; i >= 0; { - #| continue i - 1, f(len - i - 1, acc, self[i]) - #| } else { - #| acc - #| } - #|} - #|test "rev_foldi" { - #| let f = (index, sum, elem) => index + sum + elem - #| { - #| let sum = ([] : FixedArray[_]).rev_foldi(init=1, f) - #| inspect(sum, content="1") - #| } - #| { - #| let sum = ([1] : FixedArray[_]).rev_foldi(init=2, f) - #| inspect(sum, content="3") - #| } - #| let sum = ([1, 2, 3, 4, 5] : FixedArray[_]).rev_foldi(init=0, f) - #| inspect(sum, content="25") - #|} - #|#alias(rev_inplace, deprecated) - #|pub fn[T] FixedArray::rev_in_place(self : FixedArray[T]) -> Unit { - #| let mid_len = self.length() / 2 - #| for i in 0.. FixedArray[T] { - #| match self { - #| [] => [] - #| [.., first] => { - #| let res = FixedArray::make(self.length(), first) - #| let len = self.length() - #| for i in 1.. Unit { - #| let temp = self[i] - #| self[i] = self[j] - #| self[j] = temp - #|} - #|test "swap" { - #| { - #| let arr : FixedArray[Int] = [1] - #| arr.swap(0, 0) - #| assert_eq(arr, [1]) - #| } - #| { - #| let arr : FixedArray[_] = [1, 2] - #| arr.swap(0, 0) - #| assert_eq(arr, [1, 2]) - #| arr.swap(0, 1) - #| assert_eq(arr, [2, 1]) - #| } - #| let arr : FixedArray[_] = [1, 2, 3, 4, 5] - #| arr.swap(3, 3) - #| assert_eq(arr, [1, 2, 3, 4, 5]) - #| arr.swap(1, 3) - #| assert_eq(arr, [1, 4, 3, 2, 5]) - #|} - #|pub fn[T] FixedArray::all( - #| self : FixedArray[T], - #| f : (T) -> Bool raise?, - #|) -> Bool raise? { - #| for i in 0.. ele < 6)) - #| assert_true(arr.all(ele => ele < 5)) - #| } - #| { - #| let arr : FixedArray[_] = [5] - #| assert_true(arr.all(ele => ele < 6)) - #| assert_false(arr.all(ele => ele < 5)) - #| } - #| let arr : FixedArray[_] = [1, 2, 3, 4, 5] - #| assert_true(arr.all(ele => ele < 6)) - #| assert_false(arr.all(ele => ele < 5)) - #|} - #|pub fn[T] FixedArray::any( - #| self : FixedArray[T], - #| f : (T) -> Bool raise?, - #|) -> Bool raise? { - #| for i in 0.. ele < 6)) - #| assert_false(arr.any(ele => ele < 5)) - #| } - #| { - #| let arr : FixedArray[_] = [5] - #| assert_true(arr.any(ele => ele < 6)) - #| assert_false(arr.any(ele => ele < 5)) - #| } - #| let arr : FixedArray[_] = [1, 2, 3, 4, 5] - #| assert_true(arr.any(ele => ele < 6)) - #| assert_true(arr.any(ele => ele < 5)) - #|} - #|test "fill" { - #| { - #| let arr : FixedArray[Int] = [] - #| arr.fill(3) - #| assert_eq(arr, []) - #| } - #| { - #| let arr : FixedArray[_] = [6] - #| arr.fill(5) - #| assert_eq(arr, [5]) - #| } - #| let arr : FixedArray[_] = [0, 0, 0, 0, 0] - #| arr.fill(3) - #| assert_eq(arr, [3, 3, 3, 3, 3]) - #|} - #|pub fn[T : Eq] FixedArray::search(self : FixedArray[T], value : T) -> Int? { - #| for i in 0.. Bool { - #| for i in 0.. Bool { - #| if prefix.length() > self.length() { - #| return false - #| } - #| for i in 0.. Bool { - #| let self_len = self.length() - #| let suf_len = suffix.length() - #| if suf_len > self_len { - #| return false - #| } - #| for i in 0.. Bool { - #| if self.length() != that.length() { - #| return false - #| } - #| for i in 0.. if i < slen { - #| self[i] - #| } else { - #| other[i - slen] - #| }) - #|} - #|test "add" { - #| { - #| inspect(([] : FixedArray[Int]) + [], content="[]") - #| inspect(([] : FixedArray[_]) + [1, 2, 3, 4, 5], content="[1, 2, 3, 4, 5]") - #| inspect(([1, 2, 3, 4, 5] : FixedArray[_]) + [], content="[1, 2, 3, 4, 5]") - #| } - #| { - #| inspect(([1] : FixedArray[_]) + [2], content="[1, 2]") - #| inspect( - #| ([1] : FixedArray[_]) + [1, 2, 3, 4, 5], - #| content="[1, 1, 2, 3, 4, 5]", - #| ) - #| inspect( - #| ([1, 2, 3, 4, 5] : FixedArray[_]) + [1], - #| content="[1, 2, 3, 4, 5, 1]", - #| ) - #| } - #| inspect( - #| ([1, 2, 3, 4, 5] : FixedArray[_]) + [6, 7, 8, 9, 10], - #| content="[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]", - #| ) - #|} - #|test "iter" { - #| let arr : FixedArray[_] = [1, 2, 3, 4, 5] - #| let iter = arr.iter() - #| let exb = StringBuilder::new() - #| let mut i = 0 - #| iter.each(x => { - #| exb.write_string(x.to_string()) - #| exb.write_char('\n') - #| i = i + 1 - #| }) - #| assert_eq(i, arr.length()) - #| inspect( - #| exb, - #| content=( - #| #|1 - #| #|2 - #| #|3 - #| #|4 - #| #|5 - #| #| - #| ), - #| ) - #|} - #|pub fn[T] FixedArray::from_iter(iter : Iter[T]) -> FixedArray[T] { - #| FixedArray::from_array(iter.collect()) - #|} - #|pub fn[T] FixedArray::from_iterator(iter : Iterator[T]) -> FixedArray[T] { - #| FixedArray::from_array(iter.collect()) - #|} - #|pub fn[A] FixedArray::last(self : FixedArray[A]) -> A? { - #| match self { - #| [] => None - #| [.., last] => Some(last) - #| } - #|} - #|pub fn FixedArray::join( - #| self : FixedArray[String], - #| separator : StringView, - #|) -> String { - #| let len = self.length() - #| if len == 0 { - #| return "" - #| } - #| let first = self[0] - #| let mut size_hint = first.length() - #| for i in 1.. Iterator[X] { - #| self[:].iterator() - #|} - #|pub fn[X] FixedArray::Iter2(self : FixedArray[X]) -> Iter2[Int, X] { - #| self[:].Iter2() - #|} - #|#cfg(not(target="js")) - #|pub fn[T] FixedArray::copy(self : FixedArray[T]) -> FixedArray[T] { - #| let len = self.length() - #| if len == 0 { - #| [] - #| } else { - #| let arr = FixedArray::make(len, self[0]) - #| FixedArray::unsafe_blit(arr, 0, self, 0, len) - #| arr - #| } - #|} - #|#cfg(target="js") - #|pub fn[T] FixedArray::copy(self : FixedArray[T]) -> FixedArray[T] { - #| JSArray::ofAnyFixedArray(self).copy().toAnyFixedArray() - #|} - ), - "fixedarray_block.mbt": ( - #|#intrinsic("%fixedarray.copy") - #|#coverage.skip - #|pub fn[A] FixedArray::unsafe_blit( - #| dst : FixedArray[A], - #| dst_offset : Int, - #| src : FixedArray[A], - #| src_offset : Int, - #| len : Int, - #|) -> Unit { - #| if physical_equal(dst, src) && dst_offset < src_offset { - #| for i in 0..= 0; i = i - 1 { - #| dst[dst_offset + i] = src[src_offset + i] - #| } - #| } - #|} - #|#intrinsic("%fixedarray.copy") - #|#coverage.skip - #|fn[T] UninitializedArray::unsafe_blit_fixed( - #| dst : UninitializedArray[T], - #| dst_offset : Int, - #| src : FixedArray[T], - #| src_offset : Int, - #| len : Int, - #|) -> Unit { - #| for i = len - 1; i >= 0; i = i - 1 { - #| dst[dst_offset + i] = src[src_offset + i] - #| } - #|} - #|pub fn[A] FixedArray::blit_to( - #| self : FixedArray[A], - #| dst : FixedArray[A], - #| len~ : Int, - #| src_offset? : Int = 0, - #| dst_offset? : Int = 0, - #|) -> Unit { - #| guard dst_offset >= 0 && - #| src_offset >= 0 && - #| dst_offset + len <= dst.length() && - #| src_offset + len <= self.length() else { - #| abort( - #| "bounds check failed: dst_offset = \{dst_offset}, src_offset = \{src_offset}, len = \{len}, dst.length = \{dst.length()}, self.length = \{self.length()}", - #| ) - #| } - #| FixedArray::unsafe_blit(dst, dst_offset, self, src_offset, len) - #|} - ), - "hasher.mbt": ( - #|const GPRIME1 : UInt = 0x9E3779B1 - #|const GPRIMES2 : UInt = 0x85EBCA77 - #|const GPRIME3 : UInt = 0xC2B2AE3D - #|const GPRIME4 : UInt = 0x27D4EB2F - #|const GPRIME5 : UInt = 0x165667B1 - #|struct Hasher { - #| mut acc : UInt - #|} - #|pub fn Hasher::new(seed? : Int = seed) -> Hasher { - #| { acc: seed.reinterpret_as_uint() + GPRIME5 } - #|} - #|#cfg(not(target="js")) - #|let seed : Int = 0 - #|#cfg(target="js") - #|let seed : Int = random_seed() - #|#cfg(target="js") - #|extern "js" fn random_seed() -> Int = - #| #|() => { - #| #| if (globalThis.crypto?.getRandomValues) { - #| #| const array = new Uint32Array(1); - #| #| globalThis.crypto.getRandomValues(array); - #| #| return array[0] | 0; // Convert to signed 32 - #| #| } else { - #| #| return Math.floor(Math.random() * 0x100000000) | 0; // Fallback to Math.random - #| #| } - #| #|} - #|pub fn[T : Hash] Hasher::combine(self : Hasher, value : T) -> Unit { - #| value.hash_combine(self) - #|} - #|pub fn Hasher::combine_unit(self : Hasher) -> Unit { - #| self.combine_uint(0) - #|} - #|pub fn Hasher::combine_bool(self : Hasher, value : Bool) -> Unit { - #| self.combine_uint(if value { 1 } else { 0 }) - #|} - #|pub fn Hasher::combine_int(self : Hasher, value : Int) -> Unit { - #| self.combine_uint(value.reinterpret_as_uint()) - #|} - #|pub fn Hasher::combine_int64(self : Hasher, value : Int64) -> Unit { - #| self.acc += 8 - #| self.consume4(value.reinterpret_as_uint64().to_uint()) - #| self.consume4((value.reinterpret_as_uint64() >> 32).to_uint()) - #|} - #|pub fn Hasher::combine_uint(self : Hasher, value : UInt) -> Unit { - #| self.acc += 4 - #| self.consume4(value) - #|} - #|pub fn Hasher::combine_uint64(self : Hasher, value : UInt64) -> Unit { - #| self.combine_int64(value.reinterpret_as_int64()) - #|} - #|pub fn Hasher::combine_double(self : Hasher, value : Double) -> Unit { - #| self.combine_int64(value.reinterpret_as_int64()) - #|} - #|#deprecated - #|pub fn Hasher::combine_float(self : Hasher, value : Float) -> Unit { - #| self.combine_uint(value.reinterpret_as_uint()) - #|} - #|fn Float::reinterpret_as_uint(self : Float) -> UInt = "%f32.to_i32_reinterpret" - #|pub fn Hasher::combine_byte(self : Hasher, value : Byte) -> Unit { - #| self.consume1(value) - #|} - #|pub fn Hasher::combine_bytes(self : Hasher, value : Bytes) -> Unit { - #| let mut remain = value.length() - #| let mut cur = 0 - #| while remain >= 4 { - #| self.consume4(endian32(value, cur)) - #| cur += 4 - #| remain -= 4 - #| } - #| while remain >= 1 { - #| self.consume1(value[cur]) - #| cur += 1 - #| remain -= 1 - #| } - #|} - #|pub fn Hasher::combine_string(self : Hasher, value : String) -> Unit { - #| for i in 0.. Unit { - #| self.combine_uint(value.to_uint()) - #|} - #|pub fn Hasher::finalize(self : Hasher) -> Int { - #| self.avalanche().reinterpret_as_int() - #|} - #|fn Hasher::avalanche(self : Hasher) -> UInt { - #| let mut acc = self.acc - #| acc = acc ^ (acc >> 15) - #| acc *= GPRIMES2 - #| acc = acc ^ (acc >> 13) - #| acc *= GPRIME3 - #| acc = acc ^ (acc >> 16) - #| acc - #|} - #|fn Hasher::consume4(self : Hasher, input : UInt) -> Unit { - #| self.acc = rotl(self.acc + input * GPRIME3, 17) * GPRIME4 - #|} - #|fn Hasher::consume1(self : Hasher, input : Byte) -> Unit { - #| self.acc = rotl(self.acc + input.to_uint() * GPRIME5, 11) * GPRIME1 - #|} - #|fn rotl(x : UInt, r : Int) -> UInt { - #| (x << r) | (x >> (32 - r)) - #|} - #|fn endian32(input : Bytes, cur : Int) -> UInt { - #| input[cur + 0].to_uint() | - #| ( - #| (input[cur + 1].to_uint() << 8) | - #| (input[cur + 2].to_uint() << 16) | - #| (input[cur + 3].to_uint() << 24) - #| ) - #|} - #|pub impl Hash for String with hash_combine(self, hasher) { - #| hasher.combine_string(self) - #|} - #|pub impl Hash for StringView with hash_combine( - #| self : StringView, - #| hasher : Hasher, - #|) -> Unit { - #| let str = self.str() - #| for i in self.start().. hasher.combine_int(0) - #| Some(x) => hasher..combine_int(1)..combine(x) - #| } - #|} - #|pub impl[T : Hash, E : Hash] Hash for Result[T, E] with hash_combine( - #| self, - #| hasher, - #|) { - #| match self { - #| Ok(x) => hasher..combine_int(0)..combine(x) - #| Err(x) => hasher..combine_int(1)..combine(x) - #| } - #|} - #|pub impl Hash for BytesView with hash_combine(self : BytesView, hasher : Hasher) { - #| let mut start = self.start() - #| let data = self.bytes() - #| let mut rest = self.len() - #| while rest >= 4 { - #| let mut result : UInt = 0 - #| for i in 0..=3 { - #| result = result | (data.unsafe_get(i + start).to_uint() << (8 * i)) - #| } - #| hasher.combine_uint(result) - #| rest -= 4 - #| start += 4 - #| } - #| while rest >= 1 { - #| hasher.combine_byte(data.unsafe_get(start)) - #| rest -= 1 - #| start += 1 - #| } - #|} - ), - "int.mbt": ( - #|pub fn Int::next_power_of_two(self : Int) -> Int { - #| guard self >= 0 - #| if self <= 1 { - #| return 1 - #| } - #| let max_power_of_two = 1073741824 // 2^30 - #| if self > max_power_of_two { - #| return max_power_of_two - #| } - #| (2147483647 >> ((self - 1).clz() - 1)) + 1 - #|} - #|pub fn Int::min(self : Int, other : Int) -> Int { - #| if self < other { - #| self - #| } else { - #| other - #| } - #|} - #|pub fn Int::max(self : Int, other : Int) -> Int { - #| if self > other { - #| self - #| } else { - #| other - #| } - #|} - #|pub fn Int::clamp(self : Int, min~ : Int, max~ : Int) -> Int { - #| guard min <= max - #| if self < min { - #| min - #| } else if self > max { - #| max - #| } else { - #| self - #| } - #|} - #|pub fn Int::is_leading_surrogate(self : Int) -> Bool { - #| 0xD800 <= self && self <= 0xDBFF - #|} - #|pub fn Int::is_trailing_surrogate(self : Int) -> Bool { - #| 0xDC00 <= self && self <= 0xDFFF - #|} - #|pub fn Int::is_surrogate(self : Int) -> Bool { - #| 0xD800 <= self && self <= 0xDFFF - #|} - #|pub fn Int::abs(self : Int) -> Int { - #| if self < 0 { - #| -self - #| } else { - #| self - #| } - #|} - ), - "int64.mbt": ( - #|pub fn Int64::from_int(i : Int) -> Int64 { - #| i.to_int64() - #|} - #|pub fn Int64::abs(self : Int64) -> Int64 { - #| if self < 0L { - #| -self - #| } else { - #| self - #| } - #|} - #|pub impl Hash for Int64 with hash_combine(self, hasher) { - #| hasher.combine_int64(self) - #|} - ), - "int64_js.mbt": ( - #|priv struct MyInt64 { - #| hi : Int - #| lo : Int - #|} - #|fn MyInt64::to_int64(self : MyInt64) -> Int64 = "%identity" - #|fn MyInt64::from_int64(value : Int64) -> MyInt64 = "%identity" - #|impl Neg for MyInt64 with neg(self : MyInt64) -> MyInt64 { - #| if self.lo == 0 { - #| { hi: self.hi.lnot() + 1, lo: 0 } - #| } else { - #| { hi: self.hi.lnot(), lo: self.lo.lnot() + 1 } - #| } - #|} - #|fn MyInt64::add_hi_lo(self : MyInt64, bhi : Int, blo : Int) -> MyInt64 { - #| let { hi: ahi, lo: alo } = self - #| let lo = alo + blo - #| let s = lo >> 31 - #| let as_ = alo >> 31 - #| let bs = blo >> 31 - #| let c = ((as_ & bs) | (s.lnot() & (as_ ^ bs))) & 1 - #| let hi = ahi + bhi + c - #| { hi, lo } - #|} - #|impl Add for MyInt64 with add(self : MyInt64, other : MyInt64) -> MyInt64 { - #| self.add_hi_lo(other.hi, other.lo) - #|} - #|impl Sub for MyInt64 with sub(self : MyInt64, other : MyInt64) -> MyInt64 { - #| if other.lo == 0 { - #| { hi: self.hi - other.hi, lo: self.lo } - #| } else { - #| self.add_hi_lo(other.hi.lnot(), other.lo.lnot() + 1) - #| } - #|} - #|impl Mul for MyInt64 with mul(self : MyInt64, other : MyInt64) -> MyInt64 { - #| let { hi: ahi, lo: alo } = self - #| let { hi: bhi, lo: blo } = other - #| let ahi = ahi.reinterpret_as_uint() - #| let alo = alo.reinterpret_as_uint() - #| let bhi = bhi.reinterpret_as_uint() - #| let blo = blo.reinterpret_as_uint() - #| let a48 = ahi >> 16 - #| let a32 = ahi & 0xffff - #| let a16 = alo >> 16 - #| let a00 = alo & 0xffff - #| let b48 = bhi >> 16 - #| let b32 = bhi & 0xffff - #| let b16 = blo >> 16 - #| let b00 = blo & 0xffff - #| let c00 = a00 * b00 - #| let c16 = c00 >> 16 - #| let c00 = c00 & 0xffff - #| let c16 = c16 + a16 * b00 - #| let c32 = c16 >> 16 - #| let c16 = c16 & 0xffff - #| let c16 = c16 + a00 * b16 - #| let c32 = c32 + (c16 >> 16) - #| let c16 = c16 & 0xffff - #| let c32 = c32 + a32 * b00 - #| let c48 = c32 >> 16 - #| let c32 = c32 & 0xffff - #| let c32 = c32 + a16 * b16 - #| let c48 = c48 + (c32 >> 16) - #| let c32 = c32 & 0xffff - #| let c32 = c32 + a00 * b32 - #| let c48 = c48 + (c32 >> 16) - #| let c32 = c32 & 0xffff - #| let c48 = c48 + a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48 - #| let c48 = c48 & 0xffff - #| { - #| hi: ((c48 << 16) | c32).reinterpret_as_int(), - #| lo: ((c16 << 16) | c00).reinterpret_as_int(), - #| } - #|} - #|priv struct Int64WasmHelper { - #| div_s : (Int, Int, Int, Int) -> Int - #| div_u : (Int, Int, Int, Int) -> Int - #| rem_s : (Int, Int, Int, Int) -> Int - #| rem_u : (Int, Int, Int, Int) -> Int - #| get_high : () -> Int - #|} - #|priv struct WasmHelperCache { - #| mut tried : Bool - #| mut exports : Int64WasmHelper? - #|} - #|let wasm_helper_cache : WasmHelperCache = { tried: false, exports: None } - #|fn try_get_int64_wasm_helper() -> Bool { - #| if wasm_helper_cache.tried { - #| return match wasm_helper_cache.exports { - #| Some(_) => true - #| None => false - #| } - #| } - #| wasm_helper_cache.tried = true - #| wasm_helper_cache.exports = try_init_wasm_helper() - #| match wasm_helper_cache.exports { - #| Some(_) => true - #| None => false - #| } - #|} - #|extern "js" fn try_init_wasm_helper() -> Int64WasmHelper? = - #| #|function() { - #| #| try { - #| #| return new WebAssembly.Instance(new WebAssembly.Module(new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0, 1, 13, 2, 96, 0, 1, 127, 96, 4, 127, 127, 127, 127, 1, 127, 3, 7, 6, 0, 1, 1, 1, 1, 1, 6, 6, 1, 127, 1, 65, 0, 11, 7, 50, 6, 3, 109, 117, 108, 0, 1, 5, 100, 105, 118, 95, 115, 0, 2, 5, 100, 105, 118, 95, 117, 0, 3, 5, 114, 101, 109, 95, 115, 0, 4, 5, 114, 101, 109, 95, 117, 0, 5, 8, 103, 101, 116, 95, 104, 105, 103, 104, 0, 0, 10, 191, 1, 6, 4, 0, 35, 0, 11, 36, 1, 1, 126, 32, 0, 173, 32, 1, 173, 66, 32, 134, 132, 32, 2, 173, 32, 3, 173, 66, 32, 134, 132, 126, 34, 4, 66, 32, 135, 167, 36, 0, 32, 4, 167, 11, 36, 1, 1, 126, 32, 0, 173, 32, 1, 173, 66, 32, 134, 132, 32, 2, 173, 32, 3, 173, 66, 32, 134, 132, 127, 34, 4, 66, 32, 135, 167, 36, 0, 32, 4, 167, 11, 36, 1, 1, 126, 32, 0, 173, 32, 1, 173, 66, 32, 134, 132, 32, 2, 173, 32, 3, 173, 66, 32, 134, 132, 128, 34, 4, 66, 32, 135, 167, 36, 0, 32, 4, 167, 11, 36, 1, 1, 126, 32, 0, 173, 32, 1, 173, 66, 32, 134, 132, 32, 2, 173, 32, 3, 173, 66, 32, 134, 132, 129, 34, 4, 66, 32, 135, 167, 36, 0, 32, 4, 167, 11, 36, 1, 1, 126, 32, 0, 173, 32, 1, 173, 66, 32, 134, 132, 32, 2, 173, 32, 3, 173, 66, 32, 134, 132, 130, 34, 4, 66, 32, 135, 167, 36, 0, 32, 4, 167, 11])), {}).exports; - #| #| } catch (e) { - #| #| return undefined; - #| #| } - #| #|} - #|extern "js" fn MyInt64::div_bigint(self : MyInt64, other : MyInt64) -> MyInt64 = - #| #|(a, b) => { - #| #| const aVal = (BigInt(a.hi) << 32n) | BigInt(a.lo >>> 0); - #| #| const bVal = (BigInt(b.hi) << 32n) | BigInt(b.lo >>> 0); - #| #| const result = aVal / bVal; - #| #| const lo = Number(result & 0xFFFFFFFFn); - #| #| const hi = Number((result >> 32n) & 0xFFFFFFFFn); - #| #| return { hi: hi | 0, lo: lo | 0 }; - #| #|} - #|extern "js" fn MyInt64::div_u_bigint( - #| self : MyInt64, - #| other : MyInt64, - #|) -> MyInt64 = - #| #|(a, b) => { - #| #| const aVal = (BigInt(a.hi >>> 0) << 32n) | BigInt(a.lo >>> 0); - #| #| const bVal = (BigInt(b.hi >>> 0) << 32n) | BigInt(b.lo >>> 0); - #| #| const result = aVal / bVal; - #| #| const lo = Number(result & 0xFFFFFFFFn); - #| #| const hi = Number((result >> 32n) & 0xFFFFFFFFn); - #| #| return { hi: hi | 0, lo: lo | 0 }; - #| #|} - #|extern "js" fn MyInt64::mod_bigint(self : MyInt64, other : MyInt64) -> MyInt64 = - #| #|(a, b) => { - #| #| const aVal = (BigInt(a.hi) << 32n) | BigInt(a.lo >>> 0); - #| #| const bVal = (BigInt(b.hi) << 32n) | BigInt(b.lo >>> 0); - #| #| const result = aVal % bVal; - #| #| const lo = Number(result & 0xFFFFFFFFn); - #| #| const hi = Number((result >> 32n) & 0xFFFFFFFFn); - #| #| return { hi: hi | 0, lo: lo | 0 }; - #| #|} - #|extern "js" fn MyInt64::mod_u_bigint( - #| self : MyInt64, - #| other : MyInt64, - #|) -> MyInt64 = - #| #|(a, b) => { - #| #| const aVal = (BigInt(a.hi >>> 0) << 32n) | BigInt(a.lo >>> 0); - #| #| const bVal = (BigInt(b.hi >>> 0) << 32n) | BigInt(b.lo >>> 0); - #| #| const result = aVal % bVal; - #| #| const lo = Number(result & 0xFFFFFFFFn); - #| #| const hi = Number((result >> 32n) & 0xFFFFFFFFn); - #| #| return { hi: hi | 0, lo: lo | 0 }; - #| #|} - #|impl Div for MyInt64 with div(self : MyInt64, other : MyInt64) -> MyInt64 { - #| guard not(other.hi == 0 && other.lo == 0) else { panic() } - #| if not(try_get_int64_wasm_helper()) { - #| return self.div_bigint(other) - #| } - #| match wasm_helper_cache.exports { - #| Some(exports) => { - #| let { hi: ahi, lo: alo } = self - #| let { hi: bhi, lo: blo } = other - #| let lo = (exports.div_s)(alo, ahi, blo, bhi) - #| let hi = (exports.get_high)() - #| { hi, lo } - #| } - #| None => panic() - #| } - #|} - #|fn MyInt64::div_u(self : MyInt64, other : MyInt64) -> MyInt64 { - #| guard not(other.hi == 0 && other.lo == 0) else { panic() } - #| if not(try_get_int64_wasm_helper()) { - #| return self.div_u_bigint(other) - #| } - #| match wasm_helper_cache.exports { - #| Some(exports) => { - #| let { hi: ahi, lo: alo } = self - #| let { hi: bhi, lo: blo } = other - #| let lo = (exports.div_u)(alo, ahi, blo, bhi) - #| let hi = (exports.get_high)() - #| { hi, lo } - #| } - #| None => panic() - #| } - #|} - #|impl Mod for MyInt64 with mod(self : MyInt64, other : MyInt64) -> MyInt64 { - #| guard not(other.hi == 0 && other.lo == 0) else { panic() } - #| if not(try_get_int64_wasm_helper()) { - #| return self.mod_bigint(other) - #| } - #| match wasm_helper_cache.exports { - #| Some(exports) => { - #| let { hi: ahi, lo: alo } = self - #| let { hi: bhi, lo: blo } = other - #| let lo = (exports.rem_s)(alo, ahi, blo, bhi) - #| let hi = (exports.get_high)() - #| { hi, lo } - #| } - #| None => panic() - #| } - #|} - #|fn MyInt64::mod_u(self : MyInt64, other : MyInt64) -> MyInt64 { - #| guard not(other.hi == 0 && other.lo == 0) else { panic() } - #| if not(try_get_int64_wasm_helper()) { - #| return self.mod_u_bigint(other) - #| } - #| match wasm_helper_cache.exports { - #| Some(exports) => { - #| let { hi: ahi, lo: alo } = self - #| let { hi: bhi, lo: blo } = other - #| let lo = (exports.rem_u)(alo, ahi, blo, bhi) - #| let hi = (exports.get_high)() - #| { hi, lo } - #| } - #| None => panic() - #| } - #|} - #|fn MyInt64::lnot(self : MyInt64) -> MyInt64 { - #| { hi: self.hi.lnot(), lo: self.lo.lnot() } - #|} - #|fn MyInt64::land(self : MyInt64, other : MyInt64) -> MyInt64 { - #| { hi: self.hi & other.hi, lo: self.lo & other.lo } - #|} - #|fn MyInt64::lor(self : MyInt64, other : MyInt64) -> MyInt64 { - #| { hi: self.hi | other.hi, lo: self.lo | other.lo } - #|} - #|fn MyInt64::lxor(self : MyInt64, other : MyInt64) -> MyInt64 { - #| { hi: self.hi ^ other.hi, lo: self.lo ^ other.lo } - #|} - #|fn MyInt64::lsl(self : MyInt64, shift : Int) -> MyInt64 { - #| let shift = shift & 63 - #| if shift == 0 { - #| self - #| } else if shift < 32 { - #| let { hi, lo } = self - #| let hi = hi.reinterpret_as_uint() - #| let lo = lo.reinterpret_as_uint() - #| let hi = (hi << shift) | (lo >> (32 - shift)) - #| let lo = lo << shift - #| { hi: hi.reinterpret_as_int(), lo: lo.reinterpret_as_int() } - #| } else { - #| { hi: self.lo << (shift - 32), lo: 0 } - #| } - #|} - #|fn MyInt64::lsr(self : MyInt64, shift : Int) -> MyInt64 { - #| let shift = shift & 63 - #| if shift == 0 { - #| self - #| } else if shift < 32 { - #| { - #| hi: (self.hi.reinterpret_as_uint() >> shift).reinterpret_as_int(), - #| lo: (self.lo.reinterpret_as_uint() >> shift).reinterpret_as_int() | - #| (self.hi << (32 - shift)), - #| } - #| } else { - #| { - #| hi: 0, - #| lo: (self.hi.reinterpret_as_uint() >> (shift - 32)).reinterpret_as_int(), - #| } - #| } - #|} - #|fn MyInt64::asr(self : MyInt64, shift : Int) -> MyInt64 { - #| let shift = shift & 63 - #| if shift == 0 { - #| self - #| } else if shift < 32 { - #| { - #| hi: self.hi >> shift, - #| lo: (self.lo.reinterpret_as_uint() >> shift).reinterpret_as_int() | - #| (self.hi << (32 - shift)), - #| } - #| } else { - #| { hi: self.hi >> 31, lo: self.hi >> (shift - 32) } - #| } - #|} - #|fn MyInt64::clz(self : MyInt64) -> Int { - #| if self.hi != 0 { - #| self.hi.clz() - #| } else { - #| 32 + self.lo.clz() - #| } - #|} - #|fn MyInt64::ctz(self : MyInt64) -> Int { - #| if self.lo != 0 { - #| self.lo.ctz() - #| } else { - #| 32 + self.hi.ctz() - #| } - #|} - #|fn MyInt64::popcnt(self : MyInt64) -> Int { - #| self.hi.popcnt() + self.lo.popcnt() - #|} - #|impl Eq for MyInt64 with equal(self : MyInt64, other : MyInt64) -> Bool { - #| self.hi == other.hi && self.lo == other.lo - #|} - #|extern "js" fn MyInt64::compare(self : MyInt64, other : MyInt64) -> Int = - #| #|(a, b) => { - #| #| const ahi = a.hi; - #| #| const bhi = b.hi; - #| #| if (ahi < bhi) { - #| #| return -1; - #| #| } - #| #| if (ahi > bhi) { - #| #| return 1; - #| #| } - #| #| const alo = a.lo >>> 0; - #| #| const blo = b.lo >>> 0; - #| #| if (alo < blo) { - #| #| return -1; - #| #| } - #| #| if (alo > blo) { - #| #| return 1; - #| #| } - #| #| return 0; - #| #|} - #|extern "js" fn MyInt64::compare_u(self : MyInt64, other : MyInt64) -> Int = - #| #|(a, b) => { - #| #| const ahi = a.hi >>> 0; - #| #| const bhi = b.hi >>> 0; - #| #| if (ahi < bhi) { - #| #| return -1; - #| #| } - #| #| if (ahi > bhi) { - #| #| return 1; - #| #| } - #| #| const alo = a.lo >>> 0; - #| #| const blo = b.lo >>> 0; - #| #| if (alo < blo) { - #| #| return -1; - #| #| } - #| #| if (alo > blo) { - #| #| return 1; - #| #| } - #| #| return 0; - #| #|} - #|fn MyInt64::from_int(value : Int) -> MyInt64 { - #| { hi: (value >> 31) & -1, lo: value | 0 } - #|} - #|fn MyInt64::to_int(self : MyInt64) -> Int { - #| self.lo - #|} - #|fn MyInt64::to_uint(self : MyInt64) -> UInt { - #| self.lo.reinterpret_as_uint() - #|} - #|fn MyInt64::extend_i32_u(value : Int) -> MyInt64 { - #| { hi: 0, lo: value } - #|} - #|extern "js" fn MyInt64::reinterpret_as_double(self : MyInt64) -> Double = - #| #|function f(a) { - #| #| let view = f._view; - #| #| if (view === undefined) { - #| #| view = f._view = new DataView(new ArrayBuffer(8)); - #| #| } - #| #| view.setUint32(0, a.hi); - #| #| view.setUint32(4, a.lo); - #| #| return view.getFloat64(0); - #| #|} - #|extern "js" fn MyInt64::reinterpret_double(value : Double) -> MyInt64 = - #| #|function f(a) { - #| #| let view = f._view; - #| #| if (view === undefined) { - #| #| view = f._view = new DataView(new ArrayBuffer(8)); - #| #| } - #| #| view.setFloat64(0, a); - #| #| const hi = view.getInt32(0); - #| #| const lo = view.getInt32(4); - #| #| return { hi, lo }; - #| #|} - #|extern "js" fn MyInt64::trunc_double_u(value : Double) -> MyInt64 = - #| #|(a) => { - #| #| let hi = (a * (1 / 0x100000000)) | 0; - #| #| let lo = a | 0; - #| #| return { hi, lo }; - #| #|} - #|extern "js" fn MyInt64::convert_to_double_u(self : MyInt64) -> Double = - #| #|(a) => (a.hi >>> 0) * 4294967296.0 + (a.lo >>> 0) - #|extern "js" fn MyInt64::convert_to_double(self : MyInt64) -> Double = - #| #|(a) => a.hi * 4294967296.0 + (a.lo >>> 0) - #|pub impl Neg for Int64 with neg(self : Int64) -> Int64 { - #| (-MyInt64::from_int64(self)).to_int64() - #|} - #|pub impl Add for Int64 with add(self : Int64, other : Int64) -> Int64 { - #| MyInt64::from_int64(self).add(MyInt64::from_int64(other)).to_int64() - #|} - #|pub impl Sub for Int64 with sub(self : Int64, other : Int64) -> Int64 { - #| MyInt64::from_int64(self).sub(MyInt64::from_int64(other)).to_int64() - #|} - #|pub impl Mul for Int64 with mul(self : Int64, other : Int64) -> Int64 { - #| MyInt64::from_int64(self).mul(MyInt64::from_int64(other)).to_int64() - #|} - #|pub impl Div for Int64 with div(self : Int64, other : Int64) -> Int64 { - #| MyInt64::from_int64(self).div(MyInt64::from_int64(other)).to_int64() - #|} - #|pub impl Mod for Int64 with mod(self : Int64, other : Int64) -> Int64 { - #| MyInt64::from_int64(self).mod(MyInt64::from_int64(other)).to_int64() - #|} - #|pub fn Int64::lnot(self : Int64) -> Int64 { - #| MyInt64::from_int64(self).lnot().to_int64() - #|} - #|pub impl BitAnd for Int64 with land(self : Int64, other : Int64) -> Int64 { - #| MyInt64::from_int64(self).land(MyInt64::from_int64(other)).to_int64() - #|} - #|pub impl BitOr for Int64 with lor(self : Int64, other : Int64) -> Int64 { - #| MyInt64::from_int64(self).lor(MyInt64::from_int64(other)).to_int64() - #|} - #|pub impl BitXOr for Int64 with lxor(self : Int64, other : Int64) -> Int64 { - #| MyInt64::from_int64(self).lxor(MyInt64::from_int64(other)).to_int64() - #|} - #|#deprecated("Use infix operator `<<` instead") - #|#coverage.skip - #|pub fn Int64::lsl(self : Int64, other : Int) -> Int64 { - #| MyInt64::from_int64(self).lsl(other).to_int64() - #|} - #|#deprecated("Use infix operator `<<` instead") - #|#coverage.skip - #|pub fn Int64::shl(self : Int64, other : Int) -> Int64 { - #| MyInt64::from_int64(self).lsl(other).to_int64() - #|} - #|#deprecated("Use UInt64 type and infix operator `>>` instead") - #|#coverage.skip - #|pub fn Int64::lsr(self : Int64, other : Int) -> Int64 { - #| MyInt64::from_int64(self).lsr(other).to_int64() - #|} - #|#deprecated("Use infix operator `>>` instead") - #|#coverage.skip - #|pub fn Int64::shr(self : Int64, other : Int) -> Int64 { - #| MyInt64::from_int64(self).asr(other).to_int64() - #|} - #|#deprecated("Use infix operator `>>` instead") - #|#coverage.skip - #|pub fn Int64::asr(self : Int64, other : Int) -> Int64 { - #| MyInt64::from_int64(self).asr(other).to_int64() - #|} - #|pub impl Shr for Int64 with shr(self : Int64, other : Int) -> Int64 { - #| MyInt64::from_int64(self).asr(other).to_int64() - #|} - #|pub impl Shl for Int64 with shl(self : Int64, other : Int) -> Int64 { - #| MyInt64::from_int64(self).lsl(other).to_int64() - #|} - #|pub fn Int64::ctz(self : Int64) -> Int { - #| MyInt64::from_int64(self).ctz() - #|} - #|pub fn Int64::clz(self : Int64) -> Int { - #| MyInt64::from_int64(self).clz() - #|} - #|pub fn Int64::popcnt(self : Int64) -> Int { - #| MyInt64::from_int64(self).popcnt() - #|} - #|pub impl Eq for Int64 with equal(self : Int64, other : Int64) -> Bool { - #| MyInt64::from_int64(self) == MyInt64::from_int64(other) - #|} - #|pub impl Compare for Int64 with compare(self : Int64, other : Int64) -> Int { - #| MyInt64::compare(MyInt64::from_int64(self), MyInt64::from_int64(other)) - #|} - #|pub impl Default for Int64 with default() { - #| 0L - #|} - #|pub fn Int64::to_int(self : Int64) -> Int { - #| MyInt64::from_int64(self).to_int() - #|} - #|pub fn Int64::to_double(self : Int64) -> Double { - #| Double::convert_int64(self) - #|} - #|pub fn Int64::to_byte(self : Int64) -> Byte { - #| MyInt64::from_int64(self).to_int().to_byte() - #|} - #|pub fn Int64::to_uint16(self : Int64) -> UInt16 { - #| MyInt64::from_int64(self).to_int().to_uint16() - #|} - #|pub fn UInt64::extend_uint(value : UInt) -> UInt64 { - #| MyInt64::extend_i32_u(value.reinterpret_as_int()).to_uint64() - #|} - #|pub fn Int64::reinterpret_as_double(self : Int64) -> Double { - #| MyInt64::reinterpret_as_double(MyInt64::from_int64(self)) - #|} - #|pub fn UInt64::reinterpret_as_double(self : UInt64) -> Double { - #| MyInt64::reinterpret_as_double(MyInt64::from_uint64(self)) - #|} - #|pub fn Int::to_int64(self : Int) -> Int64 { - #| MyInt64::from_int(self).to_int64() - #|} - #|pub fn UInt16::to_int64(self : UInt16) -> Int64 { - #| MyInt64::from_int(self.to_int()).to_int64() - #|} - #|#deprecated("Use `reinterpret_as_int64` instead") - #|#coverage.skip - #|pub fn Double::reinterpret_as_i64(self : Double) -> Int64 { - #| MyInt64::reinterpret_double(self).to_int64() - #|} - #|pub fn Double::reinterpret_as_int64(self : Double) -> Int64 { - #| MyInt64::reinterpret_double(self).to_int64() - #|} - #|#deprecated("Use `reinterpret_as_uint64` instead") - #|#coverage.skip - #|pub fn Double::reinterpret_as_u64(self : Double) -> UInt64 { - #| MyInt64::reinterpret_double(self).to_uint64() - #|} - #|pub fn Double::reinterpret_as_uint64(self : Double) -> UInt64 { - #| MyInt64::reinterpret_double(self).to_uint64() - #|} - #|pub fn Double::convert_uint64(value : UInt64) -> Double { - #| MyInt64::convert_to_double_u(MyInt64::from_uint64(value)) - #|} - #|fn Double::convert_int64(value : Int64) -> Double { - #| MyInt64::convert_to_double(MyInt64::from_int64(value)) - #|} - #|fn MyInt64::to_uint64(self : MyInt64) -> UInt64 = "%identity" - #|fn MyInt64::from_uint64(value : UInt64) -> MyInt64 = "%identity" - #|#deprecated("Use `reinterpret_as_uint64` instead") - #|#coverage.skip - #|pub fn Int64::to_uint64(self : Int64) -> UInt64 = "%identity" - #|pub fn Int64::reinterpret_as_uint64(self : Int64) -> UInt64 = "%identity" - #|pub impl Add for UInt64 with add(self : UInt64, other : UInt64) -> UInt64 { - #| MyInt64::from_uint64(self).add(MyInt64::from_uint64(other)).to_uint64() - #|} - #|pub impl Sub for UInt64 with sub(self : UInt64, other : UInt64) -> UInt64 { - #| MyInt64::from_uint64(self).sub(MyInt64::from_uint64(other)).to_uint64() - #|} - #|pub impl Mul for UInt64 with mul(self : UInt64, other : UInt64) -> UInt64 { - #| MyInt64::from_uint64(self).mul(MyInt64::from_uint64(other)).to_uint64() - #|} - #|pub impl Div for UInt64 with div(self : UInt64, other : UInt64) -> UInt64 { - #| MyInt64::from_uint64(self).div_u(MyInt64::from_uint64(other)).to_uint64() - #|} - #|pub impl Mod for UInt64 with mod(self : UInt64, other : UInt64) -> UInt64 { - #| MyInt64::from_uint64(self).mod_u(MyInt64::from_uint64(other)).to_uint64() - #|} - #|#deprecated("Use reinterpret_as_int64 instead") - #|#coverage.skip - #|pub fn UInt64::to_int64(self : UInt64) -> Int64 = "%identity" - #|pub fn UInt64::reinterpret_as_int64(self : UInt64) -> Int64 = "%identity" - #|pub fn UInt64::to_uint(self : UInt64) -> UInt { - #| MyInt64::from_uint64(self).to_uint() - #|} - #|pub fn UInt64::to_uint16(self : UInt64) -> UInt16 { - #| self.reinterpret_as_int64().to_uint16() - #|} - #|pub fn UInt64::to_int(self : UInt64) -> Int { - #| MyInt64::from_uint64(self).to_int() - #|} - #|pub fn UInt64::to_double(self : UInt64) -> Double { - #| Double::convert_uint64(self) - #|} - #|pub impl Compare for UInt64 with compare(self : UInt64, other : UInt64) -> Int { - #| MyInt64::from_uint64(self).compare_u(MyInt64::from_uint64(other)) - #|} - #|pub impl Eq for UInt64 with equal(self : UInt64, other : UInt64) -> Bool { - #| MyInt64::from_uint64(self).equal(MyInt64::from_uint64(other)) - #|} - #|pub fn UInt64::trunc_double(value : Double) -> UInt64 { - #| MyInt64::trunc_double_u(value).to_uint64() - #|} - #|pub impl BitAnd for UInt64 with land(self : UInt64, other : UInt64) -> UInt64 { - #| MyInt64::land(MyInt64::from_uint64(self), MyInt64::from_uint64(other)).to_uint64() - #|} - #|pub impl BitOr for UInt64 with lor(self : UInt64, other : UInt64) -> UInt64 { - #| MyInt64::lor(MyInt64::from_uint64(self), MyInt64::from_uint64(other)).to_uint64() - #|} - #|pub impl BitXOr for UInt64 with lxor(self : UInt64, other : UInt64) -> UInt64 { - #| MyInt64::lxor(MyInt64::from_uint64(self), MyInt64::from_uint64(other)).to_uint64() - #|} - #|pub fn UInt64::lnot(self : UInt64) -> UInt64 { - #| MyInt64::lnot(MyInt64::from_uint64(self)).to_uint64() - #|} - #|#deprecated("Use infix operator `<<` instead") - #|#coverage.skip - #|pub fn UInt64::lsl(self : UInt64, shift : Int) -> UInt64 { - #| MyInt64::lsl(MyInt64::from_uint64(self), shift).to_uint64() - #|} - #|#deprecated("Use infix operator `<<` instead") - #|#coverage.skip - #|pub fn UInt64::lsr(self : UInt64, shift : Int) -> UInt64 { - #| MyInt64::lsr(MyInt64::from_uint64(self), shift).to_uint64() - #|} - #|#deprecated("Use infix operator `>>` instead") - #|#coverage.skip - #|pub fn UInt64::shl(self : UInt64, shift : Int) -> UInt64 { - #| MyInt64::lsl(MyInt64::from_uint64(self), shift).to_uint64() - #|} - #|#deprecated("Use infix operator `>>` instead") - #|#coverage.skip - #|pub fn UInt64::shr(self : UInt64, shift : Int) -> UInt64 { - #| MyInt64::lsr(MyInt64::from_uint64(self), shift).to_uint64() - #|} - #|pub impl Shl for UInt64 with shl(self : UInt64, shift : Int) -> UInt64 { - #| MyInt64::lsl(MyInt64::from_uint64(self), shift).to_uint64() - #|} - #|pub impl Shr for UInt64 with shr(self : UInt64, shift : Int) -> UInt64 { - #| MyInt64::lsr(MyInt64::from_uint64(self), shift).to_uint64() - #|} - #|pub fn UInt64::clz(self : UInt64) -> Int { - #| MyInt64::from_uint64(self).clz() - #|} - #|pub fn UInt64::ctz(self : UInt64) -> Int { - #| MyInt64::from_uint64(self).ctz() - #|} - #|pub fn UInt64::popcnt(self : UInt64) -> Int { - #| MyInt64::from_uint64(self).popcnt() - #|} - #|#deprecated("Use `Float::from_int64` instead") - #|pub fn Int64::to_float(self : Int64) -> Float { - #| self.to_double().to_float() - #|} - #|#deprecated("Use `Float::from_uint64` instead") - #|pub fn UInt64::to_float(self : UInt64) -> Float { - #| Double::convert_uint64(self).to_float() - #|} - ), - "int64_nonjs.mbt": ( - #|pub impl Neg for Int64 with neg(self : Int64) -> Int64 = "%i64_neg" - #|pub impl Add for Int64 with add(self, other) = "%i64_add" - #|pub impl Sub for Int64 with sub(self, other) = "%i64_sub" - #|pub impl Mul for Int64 with mul(self, other) = "%i64_mul" - #|pub impl Div for Int64 with div(self, other) = "%i64_div" - #|pub impl Mod for Int64 with mod(self, other) = "%i64_mod" - #|pub fn Int64::lnot(self : Int64) -> Int64 = "%i64_lnot" - #|pub impl BitAnd for Int64 with land(self, other) = "%i64_land" - #|pub impl BitOr for Int64 with lor(self, other) = "%i64_lor" - #|pub impl BitXOr for Int64 with lxor(self, other) = "%i64_lxor" - #|#deprecated("Use infix operator `<<` instead") - #|#coverage.skip - #|pub fn Int64::lsl(self : Int64, other : Int) -> Int64 = "%i64_shl" - #|#deprecated("Use infix operator `<<` instead") - #|#coverage.skip - #|pub fn Int64::shl(self : Int64, other : Int) -> Int64 = "%i64_shl" - #|#deprecated("Use UInt64 type and infix operator `>>` instead") - #|#coverage.skip - #|pub fn Int64::lsr(self : Int64, other : Int) -> Int64 = "%u64.shr" - #|#deprecated("Use infix operator `>>` instead") - #|#coverage.skip - #|pub fn Int64::asr(self : Int64, other : Int) -> Int64 = "%i64_shr" - #|#deprecated("Use infix operator `>>` instead") - #|#coverage.skip - #|pub fn Int64::shr(self : Int64, other : Int) -> Int64 = "%i64_shr" - #|pub impl Shl for Int64 with shl(self, other) = "%i64_shl" - #|pub impl Shr for Int64 with shr(self, other) = "%i64_shr" - #|pub fn Int64::ctz(self : Int64) -> Int = "%i64_ctz" - #|pub fn Int64::clz(self : Int64) -> Int = "%i64_clz" - #|pub fn Int64::popcnt(self : Int64) -> Int = "%i64_popcnt" - #|pub impl Eq for Int64 with equal(self : Int64, other : Int64) -> Bool = "%i64_eq" - #|pub impl Compare for Int64 with compare(self, other) = "%i64_compare" - #|pub impl Compare for Int64 with op_lt(x, y) = "%i64.lt" - #|pub impl Compare for Int64 with op_le(x, y) = "%i64.le" - #|pub impl Compare for Int64 with op_gt(x, y) = "%i64.gt" - #|pub impl Compare for Int64 with op_ge(x, y) = "%i64.ge" - #|pub impl Default for Int64 with default() = "%i64_default" - #|pub fn Int64::to_int(self : Int64) -> Int = "%i64_to_i32" - #|pub fn Int64::to_double(self : Int64) -> Double = "%i64_to_f64" - #|pub fn Int64::reinterpret_as_double(self : Int64) -> Double = "%i64_to_f64_reinterpret" - #|pub fn UInt64::reinterpret_as_double(self : UInt64) -> Double = "%i64_to_f64_reinterpret" - #|pub fn Int64::to_byte(self : Int64) -> Byte = "%i64_to_byte" - #|pub fn Int64::to_uint16(self : Int64) -> UInt16 = "%i64_to_u16" - #|pub fn UInt64::trunc_double(val : Double) -> UInt64 = "%f64.to_u64" - #|#deprecated("Use `Float::from_int64` instead") - #|pub fn Int64::to_float(self : Int64) -> Float = "%i64.to_f32" - #|pub fn UInt64::extend_uint(val : UInt) -> UInt64 = "%u32.to_u64" - #|pub fn Int::to_int64(self : Int) -> Int64 = "%i32_to_i64" - #|pub fn UInt16::to_int64(self : UInt16) -> Int64 = "%u16_to_i64" - #|#deprecated("Use `reinterpret_as_int64` instead") - #|#coverage.skip - #|pub fn Double::reinterpret_as_i64(self : Double) -> Int64 = "%f64_to_i64_reinterpret" - #|pub fn Double::reinterpret_as_int64(self : Double) -> Int64 = "%f64_to_i64_reinterpret" - #|#deprecated("Use `reinterpret_as_uint64` instead") - #|#coverage.skip - #|pub fn Double::reinterpret_as_u64(self : Double) -> UInt64 = "%f64_to_i64_reinterpret" - #|pub fn Double::reinterpret_as_uint64(self : Double) -> UInt64 = "%f64_to_i64_reinterpret" - #|pub fn Double::convert_uint64(val : UInt64) -> Double = "%u64.to_f64" - #|#deprecated("Use `reinterpret_as_uint64` instead") - #|#coverage.skip - #|pub fn Int64::to_uint64(self : Int64) -> UInt64 = "%i64.to_u64_reinterpret" - #|pub fn Int64::reinterpret_as_uint64(self : Int64) -> UInt64 = "%i64.to_u64_reinterpret" - #|#deprecated("Use `reinterpret_as_int64` instead") - #|#coverage.skip - #|pub fn UInt64::to_int64(self : UInt64) -> Int64 = "%u64.to_i64_reinterpret" - #|pub fn UInt64::reinterpret_as_int64(self : UInt64) -> Int64 = "%u64.to_i64_reinterpret" - #|pub fn UInt64::to_uint16(self : UInt64) -> UInt16 { - #| self.reinterpret_as_int64().to_uint16() - #|} - #|pub fn UInt64::to_uint(self : UInt64) -> UInt = "%u64.to_u32" - #|pub fn UInt64::to_int(self : UInt64) -> Int = "%u64.to_i32" - #|pub fn UInt64::to_double(self : UInt64) -> Double = "%u64.to_f64" - #|pub impl Add for UInt64 with add(self, other) = "%u64.add" - #|pub impl Sub for UInt64 with sub(self, other) = "%u64.sub" - #|pub impl Mul for UInt64 with mul(self, other) = "%u64.mul" - #|pub impl Div for UInt64 with div(self, other) = "%u64.div" - #|pub impl Mod for UInt64 with mod(self, other) = "%u64.mod" - #|pub impl Compare for UInt64 with compare(self, other) = "%u64.compare" - #|pub impl Compare for UInt64 with op_lt(x, y) = "%u64.lt" - #|pub impl Compare for UInt64 with op_le(x, y) = "%u64.le" - #|pub impl Compare for UInt64 with op_gt(x, y) = "%u64.gt" - #|pub impl Compare for UInt64 with op_ge(x, y) = "%u64.ge" - #|pub impl Eq for UInt64 with equal(self : UInt64, other : UInt64) -> Bool = "%u64.eq" - #|pub impl BitAnd for UInt64 with land(self, other) = "%u64.bitand" - #|pub impl BitOr for UInt64 with lor(self, other) = "%u64.bitor" - #|pub impl BitXOr for UInt64 with lxor(self, other) = "%u64.bitxor" - #|pub fn UInt64::lnot(self : UInt64) -> UInt64 = "%u64.bitnot" - #|#deprecated("Use infix operator `<<` instead") - #|#coverage.skip - #|pub fn UInt64::lsl(self : UInt64, shift : Int) -> UInt64 = "%u64.shl" - #|#deprecated("Use infix operator `<<` instead") - #|#coverage.skip - #|pub fn UInt64::shl(self : UInt64, shift : Int) -> UInt64 = "%u64.shl" - #|#deprecated("Use infix operator `>>` instead") - #|#coverage.skip - #|pub fn UInt64::shr(self : UInt64, shift : Int) -> UInt64 = "%u64.shr" - #|#deprecated("Use infix operator `>>` instead") - #|#coverage.skip - #|pub fn UInt64::lsr(self : UInt64, shift : Int) -> UInt64 = "%u64.shr" - #|pub impl Shl for UInt64 with shl(self, shift) = "%u64.shl" - #|pub impl Shr for UInt64 with shr(self, shift) = "%u64.shr" - #|pub fn UInt64::clz(self : UInt64) -> Int = "%u64.clz" - #|pub fn UInt64::ctz(self : UInt64) -> Int = "%u64.ctz" - #|pub fn UInt64::popcnt(self : UInt64) -> Int = "%u64.popcnt" - #|#deprecated("Use `Float::from_uint64` instead") - #|pub fn UInt64::to_float(self : UInt64) -> Float = "%u64.to_f32" - ), - "intrinsics.mbt": ( - #|pub fn[T] ignore(t : T) -> Unit = "%ignore" - #|pub fn[T] physical_equal(a : T, b : T) -> Bool = "%refeq" - #|#callsite(autofill(loc)) - #|pub fn[T] abort(string : String, loc~ : SourceLoc) -> T { - #| @abort.abort( - #| ( - #| $|\{string} - #| $| at \{loc} - #| $| - #| ), - #| ) - #|} - #|pub fn[T] panic() -> T = "%panic" - #|pub fn not(x : Bool) -> Bool = "%bool_not" - #|pub impl Eq for Bool with equal(self : Bool, other : Bool) -> Bool = "%bool_eq" - #|#deprecated("Use `compare` instead") - #|#coverage.skip - #|pub fn Bool::op_compare(self : Bool, other : Bool) -> Int = "%bool_compare" - #|pub impl Compare for Bool with compare(self, other) = "%bool_compare" - #|pub impl Default for Bool with default() = "%bool_default" - #|pub impl Neg for Int with neg(self) = "%i32_neg" - #|pub impl Add for Int with add(self, other) = "%i32_add" - #|pub impl Sub for Int with sub(self, other) = "%i32_sub" - #|pub impl Mul for Int with mul(self, other) = "%i32_mul" - #|pub impl Div for Int with div(self, other) = "%i32_div" - #|pub impl Mod for Int with mod(self, other) = "%i32_mod" - #|pub fn Int::lnot(self : Int) -> Int = "%i32_lnot" - #|pub impl BitAnd for Int with land(self : Int, other : Int) -> Int = "%i32_land" - #|pub impl BitOr for Int with lor(self : Int, other : Int) -> Int = "%i32_lor" - #|pub impl BitXOr for Int with lxor(self : Int, other : Int) -> Int = "%i32_lxor" - #|pub impl Shl for Int with shl(self, other) = "%i32_shl" - #|pub impl Shr for Int with shr(self, other) = "%i32_shr" - #|#deprecated("Use infix operator `<<` instead") - #|#coverage.skip - #|pub fn Int::lsl(self : Int, other : Int) -> Int = "%i32_shl" - #|#deprecated("Use infix operator `<<` instead") - #|#coverage.skip - #|pub fn Int::shl(self : Int, other : Int) -> Int = "%i32_shl" - #|#deprecated("Use UInt type and infix operator `>>` instead") - #|#coverage.skip - #|pub fn Int::lsr(self : Int, other : Int) -> Int { - #| (self.reinterpret_as_uint() >> other).reinterpret_as_int() - #|} - #|#deprecated("Use infix operator `>>` instead") - #|#coverage.skip - #|pub fn Int::asr(self : Int, other : Int) -> Int = "%i32_shr" - #|#deprecated("Use infix operator `>>` instead") - #|#coverage.skip - #|pub fn Int::shr(self : Int, other : Int) -> Int = "%i32_shr" - #|pub fn Int::ctz(self : Int) -> Int = "%i32_ctz" - #|pub fn Int::clz(self : Int) -> Int = "%i32_clz" - #|pub fn Int::popcnt(self : Int) -> Int = "%i32_popcnt" - #|pub impl Eq for Int with equal(self : Int, other : Int) -> Bool = "%i32_eq" - #|pub impl Compare for Int with compare(self, other) = "%i32_compare" - #|pub impl Compare for Int with op_lt(x, y) = "%i32.lt" - #|pub impl Compare for Int with op_le(x, y) = "%i32.le" - #|pub impl Compare for Int with op_gt(x, y) = "%i32.gt" - #|pub impl Compare for Int with op_ge(x, y) = "%i32.ge" - #|pub fn Int::is_pos(self : Int) -> Bool = "%i32_is_pos" - #|pub fn Int::is_neg(self : Int) -> Bool = "%i32_is_neg" - #|pub fn Int::is_non_pos(self : Int) -> Bool = "%i32_is_non_pos" - #|pub fn Int::is_non_neg(self : Int) -> Bool = "%i32_is_non_neg" - #|pub impl Default for Int with default() = "%i32_default" - #|pub fn Int::to_double(self : Int) -> Double = "%i32_to_f64" - #|pub fn UInt::trunc_double(val : Double) -> UInt = "%f64.to_u32" - #|pub fn Int::reinterpret_as_uint(self : Int) -> UInt = "%i32.to_u32_reinterpret" - #|#deprecated("Use `reinterpret_as_uint` instead") - #|#coverage.skip - #|pub fn Int::to_uint(self : Int) -> UInt = "%i32.to_u32_reinterpret" - #|pub fn Int::to_uint64(self : Int) -> UInt64 { - #| self.to_int64().reinterpret_as_uint64() - #|} - #|pub impl Neg for Double with neg(self) = "%f64_neg" - #|pub impl Add for Double with add(self, other) = "%f64_add" - #|pub impl Sub for Double with sub(self, other) = "%f64_sub" - #|pub impl Mul for Double with mul(self, other) = "%f64_mul" - #|pub impl Div for Double with div(self, other) = "%f64_div" - #|pub fn Double::sqrt(self : Double) -> Double = "%f64_sqrt" - #|pub impl Eq for Double with equal(self : Double, other : Double) -> Bool = "%f64_eq" - #|#deprecated("Use `a != b` instead") - #|#doc(hidden) - #|pub fn Double::op_neq(self : Double, other : Double) -> Bool = "%f64_ne" - #|pub impl Compare for Double with compare(self, other) = "%f64_compare" - #|pub impl Compare for Double with op_lt(x, y) = "%f64.lt" - #|pub impl Compare for Double with op_le(x, y) = "%f64.le" - #|pub impl Compare for Double with op_gt(x, y) = "%f64.gt" - #|pub impl Compare for Double with op_ge(x, y) = "%f64.ge" - #|pub impl Default for Double with default() = "%f64_default" - #|pub fn Double::convert_uint(val : UInt) -> Double = "%u32.to_f64" - #|pub fn Char::to_int(self : Char) -> Int = "%char_to_int" - #|pub fn Char::to_uint(self : Char) -> UInt { - #| self.to_int().reinterpret_as_uint() - #|} - #|#deprecated("Use `Int::unsafe_to_char` instead, and use `Int::to_char` for safe conversion") - #|pub fn Char::from_int(val : Int) -> Char = "%char_from_int" - #|pub impl Eq for Char with equal(self : Char, other : Char) -> Bool = "%char_eq" - #|pub impl Compare for Char with compare(self, other) = "%char_compare" - #|pub impl Compare for Char with op_lt(x, y) = "%i32.lt" - #|pub impl Compare for Char with op_le(x, y) = "%i32.le" - #|pub impl Compare for Char with op_gt(x, y) = "%i32.gt" - #|pub impl Compare for Char with op_ge(x, y) = "%i32.ge" - #|pub impl Default for Char with default() = "%char_default" - #|#alias("_[_]") - #|pub fn Bytes::at(self : Bytes, idx : Int) -> Byte = "%bytes_get" - #|#internal(unsafe, "Panic if index is out of bounds") - #|#doc(hidden) - #|pub fn Bytes::unsafe_get(self : Bytes, idx : Int) -> Byte = "%bytes.unsafe_get" - #|pub fn Bytes::length(self : Bytes) -> Int = "%bytes_length" - #|pub fn Bytes::make(len : Int, init : Byte) -> Bytes { - #| if len < 0 { - #| return [] - #| } - #| Bytes::unsafe_make(len, init) - #|} - #|fn Bytes::unsafe_make(len : Int, init : Byte) -> Bytes = "%bytes_make" - #|pub fn Bytes::new(len : Int) -> Bytes { - #| Bytes::make(len, b'\x00') - #|} - #|pub fn Int::to_byte(self : Int) -> Byte = "%i32_to_byte" - #|pub fn Int::unsafe_to_char(self : Int) -> Char = "%char_from_int" - #|pub fn Int::to_char(self : Int) -> Char? { - #| if self is (0..=0xD7FF) || self is (0xE000..=0x10FFFF) { - #| Some(self.unsafe_to_char()) - #| } else { - #| None - #| } - #|} - #|pub fn UInt64::to_byte(self : UInt64) -> Byte { - #| self.to_int().to_byte() - #|} - #|#alias("_[_]") - #|pub fn[T] FixedArray::at(self : FixedArray[T], idx : Int) -> T = "%fixedarray.get" - #|#internal(unsafe, "Panic if index is out of bounds") - #|#doc(hidden) - #|pub fn[T] FixedArray::unsafe_get(self : FixedArray[T], idx : Int) -> T = "%fixedarray.unsafe_get" - #|#internal(unsafe, "Panic if index is out of bounds") - #|#doc(hidden) - #|pub fn[T] FixedArray::unsafe_set( - #| self : FixedArray[T], - #| idx : Int, - #| val : T, - #|) -> Unit = "%fixedarray.unsafe_set" - #|#alias("_[_]=_") - #|pub fn[T] FixedArray::set(self : FixedArray[T], idx : Int, val : T) -> Unit = "%fixedarray.set" - #|pub fn[T] FixedArray::length(self : FixedArray[T]) -> Int = "%fixedarray.length" - #|pub fn[T] FixedArray::make(len : Int, init : T) -> FixedArray[T] = "%fixedarray.make" - #|#alias(charcode_length, deprecated) - #|pub fn String::length(self : String) -> Int = "%string_length" - #|#deprecated("Use `_[_]` instead which returns UInt16") - #|pub fn String::charcode_at(self : String, idx : Int) -> Int = "%string_get" - #|#alias("_[_]") - #|#alias(code_unit_at) - #|pub fn String::at(self : String, idx : Int) -> UInt16 = "%string_get" - #|#internal(unsafe, "Panic if index is out of bounds.") - #|#doc(hidden) - #|pub fn String::unsafe_charcode_at(self : String, idx : Int) -> Int = "%string.unsafe_get" - #|pub impl Add for String with add(self, other) = "%string_add" - #|pub impl Eq for String with equal(self : String, other : String) -> Bool = "%string_eq" - #|pub fn String::to_string(self : String) -> String = "%string_to_string" - #|priv type UnsafeMaybeUninit[_] - #|pub fn Byte::to_int(self : Byte) -> Int = "%byte_to_int" - #|pub fn Byte::to_char(self : Byte) -> Char { - #| self.to_int().unsafe_to_char() - #|} - #|pub fn Byte::to_int64(self : Byte) -> Int64 { - #| self.to_int().to_int64() - #|} - #|pub fn UInt::reinterpret_as_int(self : UInt) -> Int = "%u32.to_i32_reinterpret" - #|#deprecated("Use `reinterpret_as_int` instead") - #|#coverage.skip - #|pub fn UInt::to_int(self : UInt) -> Int = "%u32.to_i32_reinterpret" - #|pub impl Add for UInt with add(self, other) = "%u32.add" - #|pub impl Sub for UInt with sub(self, other) = "%u32.sub" - #|pub impl Mul for UInt with mul(self, other) = "%u32.mul" - #|pub impl Div for UInt with div(self, other) = "%u32.div" - #|pub impl Mod for UInt with mod(self, other) = "%u32.mod" - #|pub impl Eq for UInt with equal(self : UInt, other : UInt) -> Bool = "%u32.eq" - #|#deprecated("Use `a != b` instead") - #|#doc(hidden) - #|pub fn UInt::op_neq(self : UInt, other : UInt) -> Bool = "%u32.ne" - #|pub impl Compare for UInt with compare(self, other) = "%u32.compare" - #|pub impl Compare for UInt with op_lt(x, y) = "%u32.lt" - #|pub impl Compare for UInt with op_le(x, y) = "%u32.le" - #|pub impl Compare for UInt with op_gt(x, y) = "%u32.gt" - #|pub impl Compare for UInt with op_ge(x, y) = "%u32.ge" - #|pub impl BitAnd for UInt with land(self : UInt, other : UInt) -> UInt = "%u32.bitand" - #|pub impl BitOr for UInt with lor(self : UInt, other : UInt) -> UInt = "%u32.bitor" - #|pub impl BitXOr for UInt with lxor(self : UInt, other : UInt) -> UInt = "%u32.bitxor" - #|pub fn UInt::lnot(self : UInt) -> UInt = "%u32.bitnot" - #|#deprecated("Use infix operator `<<` instead") - #|#coverage.skip - #|pub fn UInt::lsl(self : UInt, shift : Int) -> UInt = "%u32.shl" - #|#deprecated("Use infix operator `<<` instead") - #|#coverage.skip - #|pub fn UInt::shl(self : UInt, shift : Int) -> UInt = "%u32.shl" - #|#deprecated("Use infix operator `>>` instead") - #|#coverage.skip - #|pub fn UInt::lsr(self : UInt, shift : Int) -> UInt = "%u32.shr" - #|#deprecated("Use infix operator `>>` instead") - #|#coverage.skip - #|pub fn UInt::shr(self : UInt, shift : Int) -> UInt = "%u32.shr" - #|pub impl Shl for UInt with shl(self, shift) = "%u32.shl" - #|pub impl Shr for UInt with shr(self, shift) = "%u32.shr" - #|pub fn UInt::clz(self : UInt) -> Int = "%u32.clz" - #|pub fn UInt::ctz(self : UInt) -> Int = "%u32.ctz" - #|pub fn UInt::popcnt(self : UInt) -> Int = "%u32.popcnt" - #|pub fn UInt::to_uint64(self : UInt) -> UInt64 { - #| UInt64::extend_uint(self) - #|} - #|pub fn UInt::to_byte(self : UInt) -> Byte { - #| self.reinterpret_as_int().to_byte() - #|} - #|pub fn UInt::to_double(self : UInt) -> Double = "%u32.to_f64" - #|#deprecated("Use `Float::from_int` instead") - #|pub fn Int::to_float(self : Int) -> Float = "%i32.to_f32" - #|#deprecated("Use `Float::reinterpret_from_int` instead") - #|pub fn Int::reinterpret_as_float(self : Int) -> Float = "%i32.to_f32_reinterpret" - #|#deprecated("Use `Float::reinterpret_from_uint` instead") - #|pub fn UInt::reinterpret_as_float(self : UInt) -> Float = "%i32.to_f32_reinterpret" - #|#deprecated("Use `Float::from_byte` instead") - #|pub fn Byte::to_float(self : Byte) -> Float = "%byte.to_f32" - #|pub fn Byte::to_double(self : Byte) -> Double { - #| self.to_int().to_double() - #|} - #|#deprecated("Use `Float::from_double` instead", skip_current_package=true) - #|pub fn Double::to_float(self : Double) -> Float = "%f64.to_f32" - #|#deprecated("Use `Float::from_uint` instead") - #|pub fn UInt::to_float(self : UInt) -> Float = "%u32.to_f32" - #|#deprecated("Use `Int16::from_int` instead") - #|pub fn Int::to_int16(self : Int) -> Int16 = "%i32_to_i16" - #|#deprecated("Use `Int16::from_byte` instead") - #|pub fn Byte::to_int16(self : Byte) -> Int16 = "%byte_to_i16" - #|pub fn UInt16::to_int(self : UInt16) -> Int = "%u16_to_i32" - #|pub fn UInt16::to_byte(self : UInt16) -> Byte = "%u16_to_byte" - #|pub fn UInt::to_uint16(self : UInt) -> UInt16 { - #| self.reinterpret_as_int().to_uint16() - #|} - #|pub fn Int::to_uint16(self : Int) -> UInt16 = "%i32_to_u16" - #|pub fn Byte::to_uint16(self : Byte) -> UInt16 = "%byte_to_u16" - ), - "iter.mbt": ( - #|struct Iter[T](((T) -> IterResult) -> IterResult) - #|pub fn[T] Iter::run(self : Iter[T], f : (T) -> IterResult) -> IterResult { - #| self(f) - #|} - #|pub fn[T] Iter::just_run(self : Iter[T], f : (T) -> IterResult) -> Unit { - #| self(f) |> ignore - #|} - #|pub(all) enum IterResult { - #| IterEnd // false - #| IterContinue // true - #|} derive(Eq) - #|pub impl[T : Show] Show for Iter[T] with output(self, logger) { - #| logger.write_iter(self) - #|} - #|pub fn[T] Iter::each(self : Iter[T], f : (T) -> Unit raise?) -> Unit raise? { - #| for a in self { - #| f(a) - #| } - #|} - #|pub fn[T] Iter::any(self : Iter[T], f : (T) -> Bool) -> Bool { - #| self.run(k => if f(k) { IterEnd } else { IterContinue }) != IterContinue - #|} - #|pub fn[T] Iter::all(self : Iter[T], f : (T) -> Bool) -> Bool { - #| self.run(k => if !f(k) { IterEnd } else { IterContinue }) is IterContinue - #|} - #|pub fn[T] Iter::eachi( - #| self : Iter[T], - #| f : (Int, T) -> Unit raise?, - #|) -> Unit raise? { - #| let mut i = 0 - #| for a in self { - #| f(i, a) - #| i += 1 - #| } - #|} - #|#locals(f) - #|pub fn[T, B] Iter::fold( - #| self : Iter[T], - #| init~ : B, - #| f : (B, T) -> B raise?, - #|) -> B raise? { - #| let mut acc = init - #| for a in self { - #| acc = f(acc, a) - #| } - #| acc - #|} - #|pub fn[T] Iter::count(self : Iter[T]) -> Int { - #| self.fold((acc, _) => acc + 1, init=0) - #|} - #|#deprecated("`Iter::new`, and the internal iterator type `Iter`, is deprecated. Create an external iterator `Iterator`, and use `Iterator::iter` to migrate usage of `Iter::new`. `Iter` will become an alias of `Iterator` in the future. See https://github.com/moonbitlang/core/pull/3050 for more details.") - #|pub fn[T] Iter::new(f : ((T) -> IterResult) -> IterResult) -> Iter[T] { - #| Iter(f) - #|} - #|pub fn[T] Iter::empty() -> Iter[T] { - #| _ => IterContinue - #|} - #|pub fn[T] Iter::singleton(a : T) -> Iter[T] { - #| yield_ => yield_(a) - #|} - #|#intrinsic("%iter.repeat") - #|pub fn[T] Iter::repeat(a : T) -> Iter[T] { - #| yield_ => loop yield_(a) { - #| IterContinue => continue yield_(a) - #| IterEnd => IterEnd - #| } - #|} - #|pub fn Int::until( - #| self : Int, - #| end : Int, - #| step? : Int = 1, - #| inclusive? : Bool = false, - #|) -> Iter[Int] { - #| if step == 0 { - #| return Iter::empty() - #| } - #| yield_ => { - #| let mut i = self - #| while (step > 0 && i < end) || - #| (step < 0 && i > end) || - #| (inclusive && i == end) { - #| if yield_(i) is IterEnd { - #| break IterEnd - #| } - #| let next = i + step - #| if (step > 0 && next >= i) || (step < 0 && next <= i) { - #| i = next - #| } else { - #| break IterContinue - #| } - #| } else { - #| IterContinue - #| } - #| } - #|} - #|pub fn Int64::until( - #| self : Int64, - #| end : Int64, - #| step? : Int64 = 1L, - #| inclusive? : Bool = false, - #|) -> Iter[Int64] { - #| if step == 0 { - #| return Iter::empty() - #| } - #| yield_ => { - #| let mut i = self - #| while (step > 0 && i < end) || - #| (step < 0 && i > end) || - #| (inclusive && i == end) { - #| if yield_(i) is IterEnd { - #| break IterEnd - #| } - #| let next = i + step - #| if (step > 0 && next >= i) || (step < 0 && next <= i) { - #| i = next - #| } else { - #| break IterContinue - #| } - #| } else { - #| IterContinue - #| } - #| } - #|} - #|pub fn Double::until( - #| self : Double, - #| end : Double, - #| step? : Double = 1.0, - #| inclusive? : Bool = false, - #|) -> Iter[Double] { - #| if step == 0.0 { - #| return Iter::empty() - #| } - #| yield_ => { - #| let mut i = self - #| while (step > 0.0 && i < end) || - #| (step < 0.0 && i > end) || - #| (inclusive && i == end) { - #| if yield_(i) is IterEnd { - #| break IterEnd - #| } - #| let next = i + step - #| if (step > 0.0 && next >= i) || (step < 0.0 && next <= i) { - #| i = next - #| } else { - #| break IterContinue - #| } - #| } else { - #| IterContinue - #| } - #| } - #|} - #|#intrinsic("%iter.filter") - #|pub fn[T] Iter::filter(self : Iter[T], f : (T) -> Bool) -> Iter[T] { - #| yield_ => self.run(a => if f(a) { yield_(a) } else { IterContinue }) - #|} - #|#intrinsic("%iter.map") - #|pub fn[T, R] Iter::map(self : Iter[T], f : (T) -> R) -> Iter[R] { - #| yield_ => self.run(a => yield_(f(a))) - #|} - #|pub fn[T, R] Iter::mapi(self : Iter[T], f : (Int, T) -> R) -> Iter[R] { - #| yield_ => { - #| let mut i = -1 - #| self.run(a => { - #| i = i + 1 - #| yield_(f(i, a)) - #| }) - #| } - #|} - #|#alias(map_option, deprecated) - #|pub fn[A, B] Iter::filter_map(self : Iter[A], f : (A) -> B?) -> Iter[B] { - #| yield_ => self.run(a => match f(a) { - #| Some(b) => yield_(b) - #| None => IterContinue - #| }) - #|} - #|#intrinsic("%iter.flat_map") - #|pub fn[T, R] Iter::flat_map(self : Iter[T], f : (T) -> Iter[R]) -> Iter[R] { - #| yield_ => self.run(x => f(x).run(yield_)) - #|} - #|pub fn[T] Iter::flatten(self : Iter[Iter[T]]) -> Iter[T] { - #| yield_ => self.run(x => x.run(yield_)) - #|} - #|pub fn[T] Iter::tap(self : Iter[T], f : (T) -> Unit) -> Iter[T] { - #| self.map(a => { - #| f(a) - #| a - #| }) - #|} - #|pub fn[T] Iter::take(self : Iter[T], n : Int) -> Iter[T] { - #| yield_ => { - #| guard n > 0 else { return IterContinue } - #| let mut i = 0 - #| let mut r = IterContinue - #| self.just_run(a => { - #| i = i + 1 - #| guard yield_(a) is IterContinue else { - #| r = IterEnd - #| return IterEnd - #| } - #| guard i < n else { return IterEnd } - #| IterContinue - #| }) - #| r - #| } - #|} - #|pub fn[T] Iter::take_while(self : Iter[T], f : (T) -> Bool) -> Iter[T] { - #| yield_ => { - #| let mut r : IterResult = IterContinue - #| self.just_run(a => if f(a) { - #| if yield_(a) is IterContinue { - #| IterContinue - #| } else { - #| r = IterEnd - #| IterEnd - #| } - #| } else { - #| IterEnd - #| }) - #| r - #| } - #|} - #|pub fn[A, B] Iter::map_while(self : Iter[A], f : (A) -> B?) -> Iter[B] { - #| yield_ => { - #| let mut r : IterResult = IterContinue - #| self.just_run(a => match f(a) { - #| Some(b) => - #| if yield_(b) is IterContinue { - #| IterContinue - #| } else { - #| r = IterEnd - #| IterEnd - #| } - #| None => IterEnd - #| }) - #| r - #| } - #|} - #|pub fn[T] Iter::drop(self : Iter[T], n : Int) -> Iter[T] { - #| yield_ => { - #| let mut i = 0 - #| self.run(a => if i < n { - #| i = i + 1 - #| IterContinue - #| } else { - #| yield_(a) - #| }) - #| } - #|} - #|pub fn[T] Iter::drop_while(self : Iter[T], f : (T) -> Bool) -> Iter[T] { - #| yield_ => { - #| let mut dropping = true - #| self.run(a => if dropping && f(a) { - #| IterContinue - #| } else { - #| dropping = false - #| yield_(a) - #| }) - #| } - #|} - #|pub fn[T] Iter::find_first(self : Iter[T], f : (T) -> Bool) -> T? { - #| for a in self { - #| if f(a) { - #| break Some(a) - #| } - #| } else { - #| None - #| } - #|} - #|pub fn[T] Iter::peek(self : Iter[T]) -> T? { - #| let mut first = None - #| self.just_run(a => { - #| first = Some(a) - #| IterEnd - #| }) - #| first - #|} - #|#deprecated("Use `Iter::singleton(a) + self` instead") - #|pub fn[T] Iter::prepend(self : Iter[T], a : T) -> Iter[T] { - #| yield_ => if yield_(a) is IterContinue { self.run(yield_) } else { IterEnd } - #|} - #|#deprecated("Use `self + Iter::singleton(a)` instead") - #|pub fn[T] Iter::append(self : Iter[T], a : T) -> Iter[T] { - #| yield_ => if self.run(yield_) is IterContinue { yield_(a) } else { IterEnd } - #|} - #|#intrinsic("%iter.concat") - #|pub fn[T] Iter::concat(self : Iter[T], other : Iter[T]) -> Iter[T] { - #| yield_ => if self.run(yield_) is IterContinue { - #| other.run(yield_) - #| } else { - #| IterEnd - #| } - #|} - #|pub impl[T] Add for Iter[T] with add(self, other) { - #| Iter::concat(self, other) - #|} - #|pub fn[T] Iter::to_array(self : Iter[T]) -> Array[T] { - #| let result = [] - #| for e in self { - #| result.push(e) - #| } - #| result - #|} - #|pub fn[T] Iter::collect(self : Iter[T]) -> Array[T] { - #| let result = [] - #| self.each(e => result.push(e)) - #| result - #|} - #|pub fn Iter::join(self : Iter[String], sep : String) -> String { - #| let buf = StringBuilder::new() - #| let mut first = true - #| for str in self { - #| if first { - #| first = false - #| } else { - #| buf.write_string(sep) - #| } - #| buf.write_string(str) - #| } - #| buf.to_string() - #|} - #|pub fn[T] Iter::iter(self : Iter[T]) -> Iter[T] { - #| self - #|} - #|pub fn[A] Iter::last(self : Iter[A]) -> A? { - #| let mut last = None - #| for a in self { - #| last = Some(a) - #| } - #| last - #|} - #|pub fn[A] Iter::head(self : Iter[A]) -> A? { - #| for i in self { - #| break Some(i) - #| } else { - #| None - #| } - #|} - #|pub fn[A] Iter::intersperse(self : Iter[A], sep : A) -> Iter[A] { - #| yield_ => { - #| let mut first = true - #| self.run(x => if first { - #| first = false - #| yield_(x) - #| } else if yield_(sep) is IterEnd { - #| IterEnd - #| } else { - #| yield_(x) - #| }) - #| } - #|} - #|#alias("_[_:_]") - #|pub fn[A] Iter::sub(self : Iter[A], start? : Int = 0, end? : Int) -> Iter[A] { - #| match end { - #| Some(end) => self.drop(start).take(end - start) - #| None => self.drop(start) - #| } - #|} - #|pub fn[A : Eq] Iter::contains(self : Iter[A], value : A) -> Bool { - #| for v in self { - #| if v == value { - #| break true - #| } - #| } else { - #| false - #| } - #|} - #|pub fn[T] Iter::nth(self : Iter[T], n : Int) -> T? { - #| self.drop(n).head() - #|} - #|pub fn[T : Compare] Iter::maximum(self : Iter[T]) -> T? { - #| let mut res = None - #| for x in self { - #| match res { - #| None => res = Some(x) - #| Some(max) => if x > max { res = Some(x) } - #| } - #| } - #| res - #|} - #|pub fn[T : Compare] Iter::minimum(self : Iter[T]) -> T? { - #| let mut res = None - #| for x in self { - #| match res { - #| None => res = Some(x) - #| Some(min) => if x < min { res = Some(x) } - #| } - #| } - #| res - #|} - #|#deprecated - #|pub fn[T, K : Eq + Hash] Iter::group_by( - #| self : Iter[T], - #| f : (T) -> K, - #|) -> Map[K, Array[T]] { - #| let result = Map::new() - #| for element in self { - #| let key = f(element) - #| match result.get(key) { - #| Some(arr) => result.set(key, arr + [element]) - #| None => result.set(key, [element]) - #| } - #| } - #| result - #|} - #|pub fn[T] Iter::iter2(self : Iter[T]) -> Iter2[Int, T] { - #| yield_ => { - #| let mut index = -1 - #| self.run(i => { - #| index += 1 - #| yield_(index, i) - #| }) - #| } - #|} - ), - "iter2.mbt": ( - #|struct Iter2[A, B](((A, B) -> IterResult) -> IterResult) - #|pub fn[A, B] Iter2::run( - #| self : Iter2[A, B], - #| f : (A, B) -> IterResult, - #|) -> IterResult { - #| self(f) - #|} - #|pub impl[A : Show, B : Show] Show for Iter2[A, B] with output(self, logger) { - #| logger.write_string("[") - #| let mut first = true - #| for k, v in self { - #| if !first { - #| logger.write_string(", ") - #| } else { - #| first = false - #| } - #| logger - #| ..write_string("(") - #| ..write_object(k) - #| ..write_string(", ") - #| ..write_object(v) - #| ..write_string(")") - #| } - #| logger.write_string("]") - #|} - #|#deprecated("`Iter2::new`, and the internal iterator type `Iter2`, is deprecated. Create an external iterator `Iter2`, and use `Iter2::iter2` to migrate usage of `Iter2::new`. `Iter2` will become an alias of `Iter2` in the future. See https://github.com/moonbitlang/core/pull/3050 for more details.") - #|pub fn[A, B] Iter2::new( - #| f : ((A, B) -> IterResult) -> IterResult, - #|) -> Iter2[A, B] { - #| Iter2(f) - #|} - #|pub fn[A, B] Iter2::each(self : Iter2[A, B], f : (A, B) -> Unit) -> Unit { - #| self.run((a, b) => { - #| f(a, b) - #| IterContinue - #| }) - #| |> ignore - #|} - #|pub fn[A, B] Iter2::iter(self : Iter2[A, B]) -> Iter[(A, B)] { - #| Iter(yield_ => self.run((a, b) => yield_((a, b)))) - #|} - #|pub fn[A, B] Iter2::iter2(self : Iter2[A, B]) -> Iter2[A, B] { - #| self - #|} - #|pub fn[A, B] Iter2::to_array(self : Iter2[A, B]) -> Array[(A, B)] { - #| let arr = [] - #| for k, v in self { - #| arr.push((k, v)) - #| } - #| arr - #|} - #|pub fn[A, B] Iter2::concat( - #| self : Iter2[A, B], - #| other : Iter2[A, B], - #|) -> Iter2[A, B] { - #| yield_ => { - #| guard self.run(yield_) is IterContinue else { IterEnd } - #| other.run(yield_) - #| } - #|} - ), - "iterator.mbt": ( - #|struct Iterator[X](() -> X?) - #|#alias(peek, deprecated) - #|#alias(head) - #|pub fn[X] Iterator::next(self : Iterator[X]) -> X? { - #| (self.0)() - #|} - #|#locals(f) - #|#deprecated("write a loop instead.") - #|pub fn[X] Iterator::run( - #| self : Iterator[X], - #| f : (X) -> IterResult, - #|) -> IterResult { - #| while self.next() is Some(x) { - #| guard f(x) is IterContinue else { break IterEnd } - #| } else { - #| IterContinue - #| } - #|} - #|#deprecated("write a loop instead.") - #|pub fn[X] Iterator::just_run(self : Iterator[X], f : (X) -> IterResult) -> Unit { - #| while self.next() is Some(x) { - #| if f(x) is IterEnd { - #| break - #| } - #| } - #|} - #|pub impl[X : Show] Show for Iterator[X] with output(self, logger) { - #| logger.write_string("[") - #| if self.next() is Some(x) { - #| logger.write_object(x) - #| while self.next() is Some(x) { - #| logger.write_string(", ") - #| logger.write_object(x) - #| } - #| } - #| logger.write_string("]") - #|} - #|pub impl[X : ToJson] ToJson for Iterator[X] with to_json(self) { - #| Json::array(self.map(_.to_json()).collect()) - #|} - #|#locals(f) - #|pub fn[X] Iterator::each( - #| self : Iterator[X], - #| f : (X) -> Unit raise?, - #|) -> Unit raise? { - #| while self.next() is Some(x) { - #| f(x) - #| } - #|} - #|#locals(f) - #|pub fn[X] Iterator::any(self : Iterator[X], f : (X) -> Bool) -> Bool { - #| while self.next() is Some(x) { - #| if f(x) { - #| break true - #| } - #| } else { - #| false - #| } - #|} - #|#locals(f) - #|pub fn[X] Iterator::all(self : Iterator[X], f : (X) -> Bool) -> Bool { - #| while self.next() is Some(x) { - #| guard f(x) else { break false } - #| } else { - #| true - #| } - #|} - #|#locals(f) - #|pub fn[X] Iterator::eachi( - #| self : Iterator[X], - #| f : (Int, X) -> Unit raise?, - #|) -> Unit raise? { - #| let mut i = 0 - #| while self.next() is Some(x) { - #| f(i, x) - #| i += 1 - #| } - #|} - #|#locals(f) - #|pub fn[X, R] Iterator::fold( - #| self : Iterator[X], - #| init~ : R, - #| f : (R, X) -> R raise?, - #|) -> R raise? { - #| let mut acc = init - #| while self.next() is Some(x) { - #| acc = f(acc, x) - #| } - #| acc - #|} - #|pub fn[X] Iterator::count(self : Iterator[X]) -> Int { - #| self.fold((acc, _) => acc + 1, init=0) - #|} - #|pub fn[X] Iterator::new(f : () -> X?) -> Iterator[X] { - #| Iterator(f) - #|} - #|pub fn[X] Iterator::empty() -> Iterator[X] { - #| () => None - #|} - #|pub fn[X] Iterator::singleton(elem : X) -> Iterator[X] { - #| let mut consumed = false - #| fn() { - #| if consumed { - #| None - #| } else { - #| consumed = true - #| Some(elem) - #| } - #| } - #|} - #|pub fn[X] Iterator::repeat(x : X) -> Iterator[X] { - #| () => Some(x) - #|} - #|pub fn[X] Iterator::filter(self : Iterator[X], f : (X) -> Bool) -> Iterator[X] { - #| fn() { - #| while self.next() is Some(x) { - #| if f(x) { - #| break Some(x) - #| } - #| } else { - #| None - #| } - #| } - #|} - #|pub fn[X, Y] Iterator::map(self : Iterator[X], f : (X) -> Y) -> Iterator[Y] { - #| fn() { - #| match self.next() { - #| Some(x) => Some(f(x)) - #| None => None - #| } - #| } - #|} - #|pub fn[X, Y] Iterator::mapi( - #| self : Iterator[X], - #| f : (Int, X) -> Y, - #|) -> Iterator[Y] { - #| let mut i = 0 - #| fn() { - #| match self.next() { - #| Some(x) => { - #| let result = f(i, x) - #| i += 1 - #| Some(result) - #| } - #| None => None - #| } - #| } - #|} - #|pub fn[X, Y] Iterator::filter_map( - #| self : Iterator[X], - #| f : (X) -> Y?, - #|) -> Iterator[Y] { - #| fn() { - #| while self.next() is Some(x) { - #| match f(x) { - #| Some(_) as y => break y - #| None => () - #| } - #| } else { - #| None - #| } - #| } - #|} - #|pub fn[X, Y] Iterator::flat_map( - #| self : Iterator[X], - #| f : (X) -> Iterator[Y], - #|) -> Iterator[Y] { - #| let mut current_iter = Some(Iterator::empty()) - #| fn() { - #| guard current_iter is Some(iter) else { None } - #| loop iter.next() { - #| Some(_) as elem => elem - #| None => { - #| guard self.next() is Some(x) else { None } - #| let iter = f(x) - #| current_iter = Some(iter) - #| continue iter.next() - #| } - #| } - #| } - #|} - #|pub fn[X] Iterator::flatten(self : Iterator[Iterator[X]]) -> Iterator[X] { - #| self.flat_map(it => it) - #|} - #|pub fn Iterator::join(self : Iterator[String], sep : String) -> String { - #| let result = StringBuilder::new() - #| if self.next() is Some(x) { - #| result.write_string(x) - #| while self.next() is Some(x) { - #| result.write_string(sep) - #| result.write_string(x) - #| } - #| } - #| result.to_string() - #|} - #|pub fn[X] Iterator::tap(self : Iterator[X], f : (X) -> Unit) -> Iterator[X] { - #| fn() { - #| let result = self.next() - #| if result is Some(x) { - #| f(x) - #| } - #| result - #| } - #|} - #|pub fn[X] Iterator::take(self : Iterator[X], n : Int) -> Iterator[X] { - #| let mut remaining = n - #| fn() { - #| guard remaining > 0 else { None } - #| let result = self.next() - #| if result is Some(_) { - #| remaining -= 1 - #| } - #| result - #| } - #|} - #|pub fn[X] Iterator::take_while( - #| self : Iterator[X], - #| f : (X) -> Bool, - #|) -> Iterator[X] { - #| let mut still_running = true - #| fn() { - #| guard still_running else { None } - #| let result = self.next() - #| if result is Some(x) && !f(x) { - #| still_running = false - #| None - #| } else { - #| result - #| } - #| } - #|} - #|pub fn[X, Y] Iterator::map_while( - #| self : Iterator[X], - #| f : (X) -> Y?, - #|) -> Iterator[Y] { - #| let mut still_running = true - #| fn() { - #| guard still_running else { None } - #| let src = self.next() - #| guard src is Some(x) else { None } - #| let result = f(x) - #| if result is None { - #| still_running = false - #| } - #| result - #| } - #|} - #|pub fn[X] Iterator::drop(self : Iterator[X], n : Int) -> Iterator[X] { - #| let mut remaining = n - #| fn() { - #| while remaining > 0 { - #| guard self.next() is Some(_) else { break None } - #| remaining -= 1 - #| } else { - #| self.next() - #| } - #| } - #|} - #|pub fn[X] Iterator::drop_while( - #| self : Iterator[X], - #| f : (X) -> Bool, - #|) -> Iterator[X] { - #| let mut dropped = false - #| fn() { - #| if !dropped { - #| dropped = true - #| loop self.next() { - #| Some(x) if f(x) => continue self.next() - #| result => result - #| } - #| } else { - #| self.next() - #| } - #| } - #|} - #|pub fn[X] Iterator::find_first(self : Iterator[X], f : (X) -> Bool) -> X? { - #| while self.next() is Some(x) { - #| if f(x) { - #| break Some(x) - #| } - #| } else { - #| None - #| } - #|} - #|pub fn[X] Iterator::concat( - #| self : Iterator[X], - #| other : Iterator[X], - #|) -> Iterator[X] { - #| let mut in_first = true - #| fn() { - #| if in_first { - #| let result = self.next() - #| if result is None { - #| in_first = false - #| other.next() - #| } else { - #| result - #| } - #| } else { - #| other.next() - #| } - #| } - #|} - #|pub impl[T] Add for Iterator[T] with add(self, other) { - #| self.concat(other) - #|} - #|#alias(collect) - #|pub fn[X] Iterator::to_array(self : Iterator[X]) -> Array[X] { - #| let result = [] - #| while self.next() is Some(x) { - #| result.push(x) - #| } - #| result - #|} - #|pub fn[X] Iterator::iter(self : Iterator[X]) -> Iter[X] { - #| Iter(yield_ => while self.next() is Some(x) { - #| guard yield_(x) is IterContinue else { break IterEnd } - #| } else { - #| IterContinue - #| }) - #|} - #|pub fn[X] Iterator::iterator(self : Iterator[X]) -> Iterator[X] { - #| self - #|} - #|pub fn[X] Iterator::iter2(self : Iterator[X]) -> Iter2[Int, X] { - #| Iter2(fn(yield_) { - #| let mut i = 0 - #| while self.next() is Some(x) { - #| guard yield_(i, x) is IterContinue else { break IterEnd } - #| i += 1 - #| } else { - #| IterContinue - #| } - #| }) - #|} - #|pub fn[X] Iterator::Iter2(self : Iterator[X]) -> Iter2[Int, X] { - #| let mut i = 0 - #| Iter2::new(fn() { - #| match self.next() { - #| None => None - #| Some(x) => { - #| let result = Some((i, x)) - #| i += 1 - #| result - #| } - #| } - #| }) - #|} - #|pub fn[X] Iterator::last(self : Iterator[X]) -> X? { - #| loop (None, self.next()) { - #| (last, None) => last - #| (_, Some(_) as x) => continue (x, self.next()) - #| } - #|} - #|pub fn[X] Iterator::intersperse(self : Iterator[X], sep : X) -> Iterator[X] { - #| enum State { - #| Init - #| Output_Elem(X) - #| Output_Sep - #| } - #| let mut state = Init - #| fn() { - #| match state { - #| Init => { - #| let result = self.next() - #| state = Output_Sep - #| result - #| } - #| Output_Elem(x) => { - #| state = Output_Sep - #| Some(x) - #| } - #| Output_Sep => - #| match self.next() { - #| Some(x) => { - #| state = Output_Elem(x) - #| Some(sep) - #| } - #| None => None - #| } - #| } - #| } - #|} - #|#alias("_[_:_]") - #|pub fn[X] Iterator::sub( - #| self : Iterator[X], - #| start? : Int = 0, - #| end? : Int, - #|) -> Iterator[X] { - #| match (start, end) { - #| (_..=0, None) => self - #| (_..=0, Some(end)) => self.take(end) - #| (start, None) => self.drop(start) - #| (start, Some(end)) => { - #| let mut index = 0 - #| fn() { - #| if index >= end { - #| return None - #| } - #| while index < start { - #| guard self.next() is Some(_) else { return None } - #| } - #| let result = self.next() - #| if result is Some(_) { - #| index += 1 - #| } - #| result - #| } - #| } - #| } - #|} - #|pub fn[X : Eq] Iterator::contains(self : Iterator[X], value : X) -> Bool { - #| while self.next() is Some(x) { - #| if x == value { - #| break true - #| } - #| } else { - #| false - #| } - #|} - #|pub fn[X] Iterator::nth(self : Iterator[X], n : Int) -> X? { - #| for i = 0; i < n; i = i + 1 { - #| guard self.next() is Some(_) else { break None } - #| } else { - #| self.next() - #| } - #|} - #|pub fn[X : Compare] Iterator::maximum(self : Iterator[X]) -> X? { - #| guard self.next() is Some(x) else { return None } - #| let mut res = x - #| while self.next() is Some(x) { - #| if x > res { - #| res = x - #| } - #| } - #| Some(res) - #|} - #|pub fn[X : Compare] Iterator::minimum(self : Iterator[X]) -> X? { - #| guard self.next() is Some(x) else { return None } - #| let mut res = x - #| while self.next() is Some(x) { - #| if x < res { - #| res = x - #| } - #| } - #| Some(res) - #|} - #|pub(all) struct Iter2[X, Y](Iterator[(X, Y)]) - #|pub fn[X, Y] Iter2::new(f : () -> (X, Y)?) -> Iter2[X, Y] { - #| Iter2(Iterator::new(f)) - #|} - #|pub fn[X, Y] Iter2::iterator(self : Iter2[X, Y]) -> Iterator[(X, Y)] { - #| self.0 - #|} - #|pub fn[X, Y] Iter2::Iter2(self : Iter2[X, Y]) -> Iter2[X, Y] { - #| self - #|} - #|pub fn[X, Y] Iter2::next(self : Iter2[X, Y]) -> (X, Y)? { - #| self.0.next() - #|} - #|pub fn[X, Y] Iter2::iter2(self : Iter2[X, Y]) -> Iter2[X, Y] { - #| Iter2(yield_ => while self.next() is Some((x, y)) { - #| guard yield_(x, y) is IterContinue else { break IterEnd } - #| } else { - #| IterContinue - #| }) - #|} - #|pub impl[X : Show, Y : Show] Show for Iter2[X, Y] with output(self, logger) { - #| self.0.output(logger) - #|} - ), - "json.mbt": ( - #|pub enum Json { - #| Null - #| True - #| False - #| Number(Double, repr~ : String?) // 1.0000000000000000000e100 - #| String(String) - #| Array(Array[Json]) - #| Object(Map[String, Json]) - #|} - #|pub impl Eq for Json with equal(a, b) { - #| match (a, b) { - #| (Null, Null) => true - #| (True, True) => true - #| (False, False) => true - #| (Number(a_num, ..), Number(b_num, ..)) => a_num == b_num - #| (String(a_str), String(b_str)) => a_str == b_str - #| (Array(a_arr), Array(b_arr)) => a_arr == b_arr - #| (Object(a_obj), Object(b_obj)) => a_obj == b_obj - #| _ => false - #| } - #|} - #|pub fn Json::null() -> Json { - #| return Null - #|} - #|pub let null : Json = Null - #|pub fn Json::number(number : Double, repr? : String) -> Json { - #| return Number(number, repr~) - #|} - #|pub fn Json::string(string : String) -> Json { - #| return String(string) - #|} - #|pub fn Json::boolean(boolean : Bool) -> Json { - #| if boolean { - #| True - #| } else { - #| False - #| } - #|} - #|pub fn Json::array(array : Array[Json]) -> Json { - #| return Array(array) - #|} - #|pub fn Json::object(object : Map[String, Json]) -> Json { - #| return Object(object) - #|} - #|pub(open) trait ToJson { - #| to_json(Self) -> Json - #|} - #|pub impl ToJson for Bool with to_json(self : Bool) -> Json { - #| if self { - #| true - #| } else { - #| false - #| } - #|} - #|pub impl ToJson for Byte with to_json(self : Byte) -> Json { - #| Json::number(self.to_double()) - #|} - #|pub impl ToJson for Int with to_json(self : Int) -> Json { - #| Json::number(self.to_double()) - #|} - #|pub impl ToJson for Int64 with to_json(self : Int64) -> Json { - #| String::to_json(self.to_string()) - #|} - #|pub impl ToJson for UInt with to_json(self : UInt) -> Json { - #| Json::number(self.to_uint64().to_double()) - #|} - #|pub impl ToJson for UInt64 with to_json(self : UInt64) -> Json { - #| String::to_json(self.to_string()) - #|} - #|pub impl ToJson for Double with to_json(self : Double) -> Json { - #| if self != self { - #| Json::string("NaN") - #| } else if self > 0x7FEFFFFFFFFFFFFFL.reinterpret_as_double() { - #| Json::string("Infinity") - #| } else if self < 0xFFEFFFFFFFFFFFFFL.reinterpret_as_double() { - #| Json::string("-Infinity") - #| } else { - #| Json::number(self) - #| } - #|} - #|pub impl ToJson for String with to_json(self : String) -> Json { - #| String(self) - #|} - #|pub impl[X : ToJson] ToJson for Array[X] with to_json(self) { - #| Array(self.map(ToJson::to_json)) - #|} - #|pub impl[X : ToJson] ToJson for FixedArray[X] with to_json(self) { - #| let len = self.length() - #| if len == 0 { - #| return [] - #| } - #| let res = Array::make_uninit(self.length()) - #| for i, x in self { - #| res.unsafe_set(i, ToJson::to_json(x)) - #| } - #| Array(res) - #|} - #|pub impl[X : ToJson] ToJson for ArrayView[X] with to_json(self) { - #| let len = self.length() - #| if len == 0 { - #| return [] - #| } - #| let res = Array::make_uninit(self.length()) - #| for i, x in self { - #| res.unsafe_set(i, ToJson::to_json(x)) - #| } - #| Array(res) - #|} - #|pub impl[K : Show, V : ToJson] ToJson for Map[K, V] with to_json(self) { - #| let object = Map::new(capacity=self.capacity) - #| for k, v in self { - #| object[k.to_string()] = v.to_json() - #| } - #| Object(object) - #|} - #|pub impl[T : ToJson] ToJson for T? with to_json(self) { - #| match self { - #| None => Null - #| Some(value) => [value] - #| } - #|} - #|pub impl[Ok : ToJson, Err : ToJson] ToJson for Result[Ok, Err] with to_json( - #| self : Result[Ok, Err], - #|) -> Json { - #| match self { - #| Ok(ok) => { "Ok": ok } - #| Err(err) => { "Err": err } - #| } - #|} - #|pub impl ToJson for Unit with to_json(_self) { - #| Null - #|} - #|pub impl Default for Json with default() { - #| false - #|} - #|pub impl[X : ToJson] ToJson for Iter[X] with to_json(self) { - #| let arr = [] - #| for x in self { - #| arr.push(ToJson::to_json(x)) - #| } - #| Array(arr) - #|} - ), - "linked_hash_map.mbt": ( - #|priv struct Entry[K, V] { - #| mut prev : Int - #| mut next : Entry[K, V]? - #| mut psl : Int - #| hash : Int - #| key : K - #| mut value : V - #|} derive(Show) - #|struct Map[K, V] { - #| mut entries : FixedArray[Entry[K, V]?] - #| mut size : Int // active key-value pairs count - #| mut capacity : Int // current capacity - #| mut capacity_mask : Int // capacity_mask = capacity - 1, used to find idx - #| mut grow_at : Int // threshold that triggers grow - #| mut head : Entry[K, V]? // head of linked list - #| mut tail : Int // tail of linked list - #|} - #|pub fn[K, V] Map::new(capacity? : Int = 8) -> Map[K, V] { - #| let capacity = capacity.next_power_of_two() - #| { - #| size: 0, - #| capacity, - #| capacity_mask: capacity - 1, - #| grow_at: calc_grow_threshold(capacity), - #| entries: FixedArray::make(capacity, None), - #| head: None, - #| tail: -1, - #| } - #|} - #|pub fn[K : Hash + Eq, V] Map::from_array(arr : ArrayView[(K, V)]) -> Map[K, V] { - #| let length = arr.length() - #| let mut capacity = length.next_power_of_two() - #| if length > calc_grow_threshold(capacity) { - #| capacity *= 2 - #| } - #| let m = Map::new(capacity~) - #| for e in arr { - #| m.set(e.0, e.1) - #| } - #| m - #|} - #|#alias("_[_]=_") - #|pub fn[K : Hash + Eq, V] Map::set(self : Map[K, V], key : K, value : V) -> Unit { - #| self.set_with_hash(key, value, key.hash()) - #|} - #|fn[K : Eq, V] Map::set_with_hash( - #| self : Map[K, V], - #| key : K, - #| value : V, - #| hash : Int, - #|) -> Unit { - #| if self.size >= self.grow_at { - #| self.grow() - #| } - #| let (idx, psl) = for psl = 0, idx = hash & self.capacity_mask { - #| match self.entries[idx] { - #| None => break (idx, psl) - #| Some(curr_entry) => { - #| if curr_entry.hash == hash && curr_entry.key == key { - #| curr_entry.value = value - #| return - #| } - #| if psl > curr_entry.psl { - #| self.push_away(idx, curr_entry) - #| break (idx, psl) - #| } - #| continue psl + 1, (idx + 1) & self.capacity_mask - #| } - #| } - #| } - #| let entry = { prev: self.tail, next: None, psl, key, value, hash } - #| self.add_entry_to_tail(idx, entry) - #|} - #|fn[K, V] Map::push_away( - #| self : Map[K, V], - #| idx : Int, - #| entry : Entry[K, V], - #|) -> Unit { - #| for psl = entry.psl + 1, idx = (idx + 1) & self.capacity_mask, entry = entry { - #| match self.entries[idx] { - #| None => { - #| entry.psl = psl - #| self.set_entry(entry, idx) - #| break - #| } - #| Some(curr_entry) => - #| if psl > curr_entry.psl { - #| entry.psl = psl - #| self.set_entry(entry, idx) - #| continue curr_entry.psl + 1, - #| (idx + 1) & self.capacity_mask, - #| curr_entry - #| } else { - #| continue psl + 1, (idx + 1) & self.capacity_mask, entry - #| } - #| } - #| } - #|} - #|fn[K, V] Map::set_entry( - #| self : Map[K, V], - #| entry : Entry[K, V], - #| new_idx : Int, - #|) -> Unit { - #| self.entries[new_idx] = Some(entry) - #| match entry.next { - #| None => self.tail = new_idx - #| Some(next) => next.prev = new_idx - #| } - #|} - #|pub fn[K : Hash + Eq, V] Map::get(self : Map[K, V], key : K) -> V? { - #| let hash = key.hash() - #| for i = 0, idx = hash & self.capacity_mask { - #| guard self.entries[idx] is Some(entry) else { break None } - #| if entry.hash == hash && entry.key == key { - #| break Some(entry.value) - #| } - #| if i > entry.psl { - #| break None - #| } - #| continue i + 1, (idx + 1) & self.capacity_mask - #| } - #|} - #|#alias("_[_]") - #|pub fn[K : Hash + Eq, V] Map::at(self : Map[K, V], key : K) -> V { - #| let hash = key.hash() - #| for i = 0, idx = hash & self.capacity_mask { - #| guard self.entries[idx] is Some(entry) - #| if entry.hash == hash && entry.key == key { - #| return entry.value - #| } - #| guard i <= entry.psl - #| continue i + 1, (idx + 1) & self.capacity_mask - #| } - #|} - #|pub fn[K : Hash + Eq, V] Map::get_or_default( - #| self : Map[K, V], - #| key : K, - #| default : V, - #|) -> V { - #| let hash = key.hash() - #| for i = 0, idx = hash & self.capacity_mask { - #| match self.entries[idx] { - #| Some(entry) => { - #| if entry.hash == hash && entry.key == key { - #| break entry.value - #| } - #| if i > entry.psl { - #| break default - #| } - #| continue i + 1, (idx + 1) & self.capacity_mask - #| } - #| None => break default - #| } - #| } - #|} - #|pub fn[K : Hash + Eq, V] Map::get_or_init( - #| self : Map[K, V], - #| key : K, - #| default : () -> V, - #|) -> V { - #| let hash = key.hash() - #| let (idx, psl, new_value, push_away) = for psl = 0, idx = hash & - #| self.capacity_mask { - #| match self.entries[idx] { - #| Some(entry) => { - #| if entry.hash == hash && entry.key == key { - #| return entry.value - #| } - #| if psl > entry.psl { - #| let new_value = default() - #| break (idx, psl, new_value, Some(entry)) - #| } - #| continue psl + 1, (idx + 1) & self.capacity_mask - #| } - #| None => { - #| let new_value = default() - #| break (idx, psl, new_value, None) - #| } - #| } - #| } - #| if self.size >= self.grow_at { - #| self.grow() - #| self.set_with_hash(key, new_value, hash) - #| } else { - #| if push_away is Some(entry) { - #| self.push_away(idx, entry) - #| } - #| let entry = { - #| prev: self.tail, - #| next: None, - #| psl, - #| hash, - #| key, - #| value: new_value, - #| } - #| self.add_entry_to_tail(idx, entry) - #| } - #| new_value - #|} - #|pub fn[K : Hash + Eq, V] Map::contains(self : Map[K, V], key : K) -> Bool { - #| let hash = key.hash() - #| for i = 0, idx = hash & self.capacity_mask { - #| guard self.entries[idx] is Some(entry) else { break false } - #| if entry.hash == hash && entry.key == key { - #| break true - #| } - #| if i > entry.psl { - #| break false - #| } - #| continue i + 1, (idx + 1) & self.capacity_mask - #| } - #|} - #|pub fn[K : Hash + Eq, V : Eq] Map::contains_kv( - #| self : Map[K, V], - #| key : K, - #| value : V, - #|) -> Bool { - #| let hash = key.hash() - #| for i = 0, idx = hash & self.capacity_mask { - #| guard self.entries[idx] is Some(entry) else { break false } - #| if entry.hash == hash && entry.key == key && entry.value == value { - #| break true - #| } - #| if i > entry.psl { - #| break false - #| } - #| continue i + 1, (idx + 1) & self.capacity_mask - #| } - #|} - #|pub fn[K : Hash + Eq, V] Map::remove(self : Map[K, V], key : K) -> Unit { - #| self.remove_with_hash(key, key.hash()) - #|} - #|fn[K : Eq, V] Map::remove_with_hash( - #| self : Map[K, V], - #| key : K, - #| hash : Int, - #|) -> Unit { - #| for i = 0, idx = hash & self.capacity_mask { - #| guard self.entries[idx] is Some(entry) else { break } - #| if entry.hash == hash && entry.key == key { - #| self.remove_entry(entry) - #| self.shift_back(idx) - #| self.size -= 1 - #| break - #| } - #| if i > entry.psl { - #| break - #| } - #| continue i + 1, (idx + 1) & self.capacity_mask - #| } - #|} - #|fn[K, V] Map::add_entry_to_tail( - #| self : Map[K, V], - #| idx : Int, - #| entry : Entry[K, V], - #|) -> Unit { - #| match self.tail { - #| -1 => self.head = Some(entry) - #| tail => self.entries[tail].unwrap().next = Some(entry) - #| } - #| self.tail = idx - #| self.entries[idx] = Some(entry) - #| self.size += 1 - #|} - #|fn[K, V] Map::remove_entry(self : Map[K, V], entry : Entry[K, V]) -> Unit { - #| match entry.prev { - #| -1 => self.head = entry.next - #| idx => self.entries[idx].unwrap().next = entry.next - #| } - #| match entry.next { - #| None => self.tail = entry.prev - #| Some(next) => next.prev = entry.prev - #| } - #|} - #|fn[K, V] Map::shift_back(self : Map[K, V], idx : Int) -> Unit { - #| let next = (idx + 1) & self.capacity_mask - #| match self.entries[next] { - #| None | Some({ psl: 0, .. }) => self.entries[idx] = None - #| Some(entry) => { - #| entry.psl -= 1 - #| self.set_entry(entry, idx) - #| self.shift_back(next) - #| } - #| } - #|} - #|fn[K : Eq, V] Map::grow(self : Map[K, V]) -> Unit { - #| let old_head = self.head - #| let new_capacity = self.capacity << 1 - #| self.entries = FixedArray::make(new_capacity, None) - #| self.capacity = new_capacity - #| self.capacity_mask = new_capacity - 1 - #| self.grow_at = calc_grow_threshold(self.capacity) - #| self.size = 0 - #| self.head = None - #| self.tail = -1 - #| loop old_head { - #| Some({ next, key, value, hash, .. }) => { - #| self.set_with_hash(key, value, hash) - #| continue next - #| } - #| None => break - #| } - #|} - #|fn calc_grow_threshold(capacity : Int) -> Int { - #| capacity * 13 / 16 - #|} - #|pub impl[K : Show, V : Show] Show for Map[K, V] with output(self, logger) { - #| logger.write_string("{") - #| loop (0, self.head) { - #| (_, None) => logger.write_string("}") - #| (i, Some({ key, value, next, .. })) => { - #| if i > 0 { - #| logger.write_string(", ") - #| } - #| logger..write_object(key)..write_string(": ")..write_object(value) - #| continue (i + 1, next) - #| } - #| } - #|} - #|#alias(size, deprecated) - #|pub fn[K, V] Map::length(self : Map[K, V]) -> Int { - #| self.size - #|} - #|pub fn[K, V] Map::capacity(self : Map[K, V]) -> Int { - #| self.capacity - #|} - #|pub fn[K, V] Map::is_empty(self : Map[K, V]) -> Bool { - #| self.size == 0 - #|} - #|#locals(f) - #|pub fn[K, V] Map::each( - #| self : Map[K, V], - #| f : (K, V) -> Unit raise?, - #|) -> Unit raise? { - #| loop self.head { - #| Some({ key, value, next, .. }) => { - #| f(key, value) - #| continue next - #| } - #| None => break - #| } - #|} - #|#locals(f) - #|pub fn[K, V] Map::eachi( - #| self : Map[K, V], - #| f : (Int, K, V) -> Unit raise?, - #|) -> Unit raise? { - #| loop (0, self.head) { - #| (i, Some({ key, value, next, .. })) => { - #| f(i, key, value) - #| continue (i + 1, next) - #| } - #| (_, None) => break - #| } - #|} - #|pub fn[K, V] Map::clear(self : Map[K, V]) -> Unit { - #| self.entries.fill(None) - #| self.size = 0 - #| self.head = None - #| self.tail = -1 - #|} - #|pub fn[K, V] Map::iter(self : Map[K, V]) -> Iter[(K, V)] { - #| self.iterator().iter() - #|} - #|pub fn[K, V] Map::iterator(self : Map[K, V]) -> Iterator[(K, V)] { - #| let mut curr_entry = self.head - #| Iterator::new(fn() { - #| match curr_entry { - #| Some({ key, value, next, .. }) => { - #| curr_entry = next - #| Some((key, value)) - #| } - #| None => None - #| } - #| }) - #|} - #|pub fn[K, V] Map::Iter2(self : Map[K, V]) -> Iter2[K, V] { - #| self.iterator() - #|} - #|pub fn[K, V] Map::iter2(self : Map[K, V]) -> Iter2[K, V] { - #| self.Iter2().iter2() - #|} - #|pub fn[K, V] Map::keys(self : Map[K, V]) -> Iter[K] { - #| let mut curr_entry = self.head - #| Iterator::new(fn() { - #| match curr_entry { - #| Some({ key, next, .. }) => { - #| curr_entry = next - #| Some(key) - #| } - #| None => None - #| } - #| }).iter() - #|} - #|pub fn[K, V] Map::values(self : Map[K, V]) -> Iter[V] { - #| let mut curr_entry = self.head - #| Iterator::new(fn() { - #| match curr_entry { - #| Some({ value, next, .. }) => { - #| curr_entry = next - #| Some(value) - #| } - #| None => None - #| } - #| }).iter() - #|} - #|pub fn[K, V] Map::to_array(self : Map[K, V]) -> Array[(K, V)] { - #| let arr = Array::make_uninit(self.size) - #| let mut i = 0 - #| loop self.head { - #| Some({ key, value, next, .. }) => { - #| arr.unsafe_set(i, (key, value)) - #| i += 1 - #| continue next - #| } - #| None => break - #| } - #| arr - #|} - #|pub impl[K : Hash + Eq, V : Eq] Eq for Map[K, V] with equal( - #| self : Map[K, V], - #| that : Map[K, V], - #|) -> Bool { - #| guard self.size == that.size else { return false } - #| for k, v in self { - #| guard that.contains_kv(k, v) else { return false } - #| } else { - #| true - #| } - #|} - #|pub fn[K : Hash + Eq, V] Map::of(arr : FixedArray[(K, V)]) -> Map[K, V] { - #| let length = arr.length() - #| let mut capacity = length.next_power_of_two() - #| if length > calc_grow_threshold(capacity) { - #| capacity *= 2 - #| } - #| let m = Map::new(capacity~) - #| for i in 0.. Map[K, V] { - #| let m = {} - #| for e in iter { - #| m.set(e.0, e.1) - #| } - #| m - #|} - #|pub fn[K : Hash + Eq, V] Map::from_iterator( - #| iter : Iterator[(K, V)], - #|) -> Map[K, V] { - #| let m = {} - #| while iter.next() is Some((k, v)) { - #| m.set(k, v) - #| } - #| m - #|} - #|pub impl[K, V] Default for Map[K, V] with default() { - #| Map::new() - #|} - #|pub fn[K, V, V2] Map::map(self : Map[K, V], f : (K, V) -> V2) -> Map[K, V2] { - #| let other = { - #| capacity: self.capacity, - #| entries: FixedArray::make(self.capacity, None), - #| size: self.size, - #| capacity_mask: self.capacity_mask, - #| grow_at: self.grow_at, - #| head: None, - #| tail: self.tail, - #| } - #| if self.size == 0 { - #| return other - #| } - #| guard self.entries[self.tail] is Some(last) - #| loop (last, self.tail, None) { - #| ({ prev, psl, hash, key, value, .. }, idx, next) => { - #| let new_value = f(key, value) - #| let new_entry = { prev, next, psl, hash, key, value: new_value } - #| other.entries[idx] = Some(new_entry) - #| if prev != -1 { - #| continue (self.entries[prev].unwrap(), prev, Some(new_entry)) - #| } else { - #| other.head = Some(new_entry) - #| } - #| } - #| } - #| other - #|} - #|pub fn[K, V] Map::copy(self : Map[K, V]) -> Map[K, V] { - #| let other = { - #| capacity: self.capacity, - #| entries: FixedArray::make(self.capacity, None), - #| size: self.size, - #| capacity_mask: self.capacity_mask, - #| grow_at: self.grow_at, - #| head: None, - #| tail: self.tail, - #| } - #| if self.size == 0 { - #| return other - #| } - #| guard self.entries[self.tail] is Some(last) - #| loop (last, self.tail, None) { - #| ({ prev, psl, hash, key, value, .. }, idx, next) => { - #| let new_entry = { prev, next, psl, hash, key, value } - #| other.entries[idx] = Some(new_entry) - #| if prev != -1 { - #| continue (self.entries[prev].unwrap(), prev, Some(new_entry)) - #| } else { - #| other.head = Some(new_entry) - #| } - #| } - #| } - #| other - #|} - #|pub fn[K : Eq, V] Map::merge(self : Map[K, V], other : Map[K, V]) -> Map[K, V] { - #| let result = self.copy() - #| result.merge_in_place(other) - #| result - #|} - #|pub fn[K : Eq, V] Map::merge_in_place( - #| self : Map[K, V], - #| other : Map[K, V], - #|) -> Unit { - #| loop other.head { - #| Some({ key, value, next, hash, .. }) => { - #| self.set_with_hash(key, value, hash) - #| continue next - #| } - #| None => break - #| } - #|} - #|#locals(f) - #|pub fn[K, V] Map::retain(self : Map[K, V], f : (K, V) -> Bool) -> Unit { - #| loop (self.head, false) { - #| (Some({ key, value, next, prev: idx, .. }), remove_prev) => { - #| if remove_prev { - #| guard self.entries[idx] is Some(entry) - #| self.remove_entry(entry) - #| self.shift_back(idx) - #| self.size -= 1 - #| } - #| continue (next, !f(key, value)) - #| } - #| (None, remove_prev) => - #| if remove_prev { - #| let idx = self.tail - #| guard self.entries[idx] is Some(entry) - #| self.remove_entry(entry) - #| self.shift_back(idx) - #| self.size -= 1 - #| } - #| } - #|} - #|pub fn[K : Hash + Eq, V] Map::update( - #| self : Map[K, V], - #| key : K, - #| f : (V?) -> V?, - #|) -> Unit { - #| let hash = key.hash() - #| let (idx, psl, new_value, push_away) = for psl = 0, idx = hash & - #| self.capacity_mask { - #| match self.entries[idx] { - #| Some(entry) => { - #| if entry.hash == hash && entry.key == key { - #| if f(Some(entry.value)) is Some(new_value) { - #| entry.value = new_value - #| } else { - #| self.remove_entry(entry) - #| self.shift_back(idx) - #| self.size -= 1 - #| } - #| return - #| } - #| if psl > entry.psl { - #| guard f(None) is Some(new_value) else { return } - #| break (idx, psl, new_value, Some(entry)) - #| } - #| continue psl + 1, (idx + 1) & self.capacity_mask - #| } - #| None => { - #| guard f(None) is Some(new_value) else { return } - #| break (idx, psl, new_value, None) - #| } - #| } - #| } - #| if self.size >= self.grow_at { - #| self.grow() - #| self.set(key, new_value) - #| } else { - #| if push_away is Some(entry) { - #| self.push_away(idx, entry) - #| } - #| let entry = { - #| prev: self.tail, - #| next: None, - #| psl, - #| hash, - #| key, - #| value: new_value, - #| } - #| self.add_entry_to_tail(idx, entry) - #| } - #|} - #|fn StringView::equal_to_string(self : Self, other : String) -> Bool { - #| let str = self.str() - #| let start = self.start() - #| let end = self.end() - #| let len = end - start - #| guard len == other.length() else { return false } - #| if physical_equal(str, other) && self.start() == 0 { - #| return true - #| } - #| for i in 0.. Bool { - #| let self_len = self.len() - #| let start = self.start() - #| guard self_len == other.length() else { return false } - #| for i in 0.. V? { - #| let hash = key.hash() - #| for i = 0, idx = hash & map.capacity_mask { - #| guard map.entries[idx] is Some(entry) else { break None } - #| if entry.hash == hash && key.equal_to_bytes(entry.key) { - #| break Some(entry.value) - #| } - #| if i > entry.psl { - #| break None - #| } - #| continue i + 1, (idx + 1) & map.capacity_mask - #| } - #|} - #|pub fn[V] Map::get_from_string(map : Self[String, V], key : StringView) -> V? { - #| let hash = key.hash() - #| for i = 0, idx = hash & map.capacity_mask { - #| guard map.entries[idx] is Some(entry) else { break None } - #| if entry.hash == hash && key.equal_to_string(entry.key) { - #| break Some(entry.value) - #| } - #| if i > entry.psl { - #| break None - #| } - #| continue i + 1, (idx + 1) & map.capacity_mask - #| } - #|} - ), - "mutarrayview.mbt": ( - #|#builtin.valtype - #|type MutArrayView[T] - #|fn[T] MutArrayView::buf(self : MutArrayView[T]) -> UninitializedArray[T] = "%arrayview.buf" - #|fn[T] MutArrayView::start(self : MutArrayView[T]) -> Int = "%arrayview.start" - #|fn[T] MutArrayView::len(self : MutArrayView[T]) -> Int = "%arrayview.len" - #|fn[T] MutArrayView::make( - #| buf : UninitializedArray[T], - #| start : Int, - #| len : Int, - #|) -> MutArrayView[T] = "%arrayview.make" - #|pub fn[T] MutArrayView::length(self : MutArrayView[T]) -> Int { - #| self.len() - #|} - #|#alias("_[_]") - #|pub fn[T] MutArrayView::at(self : MutArrayView[T], index : Int) -> T { - #| guard index >= 0 && index < self.len() else { - #| abort( - #| "index out of bounds: the len is from 0 to \{self.len()} but the index is \{index}", - #| ) - #| } - #| self.buf()[self.start() + index] - #|} - #|#intrinsic("%arrayview.unsafe_get") - #|#internal(unsafe, "Panic if index is out of bounds") - #|pub fn[T] MutArrayView::unsafe_get(self : MutArrayView[T], index : Int) -> T { - #| self.buf()[self.start() + index] - #|} - #|#alias("_[_]=_") - #|pub fn[T] MutArrayView::set( - #| self : MutArrayView[T], - #| index : Int, - #| value : T, - #|) -> Unit { - #| guard index >= 0 && index < self.len() else { - #| abort( - #| "index out of bounds: the len is from 0 to \{self.len()} but the index is \{index}", - #| ) - #| } - #| self.buf()[self.start() + index] = value - #|} - #|#intrinsic("%arrayview.unsafe_set") - #|#internal(unsafe, "Panic if index is out of bounds") - #|pub fn[T] MutArrayView::unsafe_set( - #| self : MutArrayView[T], - #| index : Int, - #| value : T, - #|) -> Unit { - #| self.buf()[self.start() + index] = value - #|} - #|pub fn[T] Array::mut_view( - #| self : Array[T], - #| start? : Int = 0, - #| end? : Int, - #|) -> MutArrayView[T] { - #| let len = self.length() - #| let end = match end { - #| None => len - #| Some(end) => if end < 0 { len + end } else { end } - #| } - #| let start = if start < 0 { len + start } else { start } - #| guard start >= 0 && start <= end && end <= len else { - #| abort("View index out of bounds") - #| } - #| MutArrayView::make(self.buffer(), start, end - start) - #|} - #|pub fn[T] MutArrayView::mut_view( - #| self : MutArrayView[T], - #| start? : Int = 0, - #| end? : Int, - #|) -> MutArrayView[T] { - #| let len = self.length() - #| let end = match end { - #| None => len - #| Some(end) => if end < 0 { len + end } else { end } - #| } - #| let start = if start < 0 { len + start } else { start } - #| guard start >= 0 && start <= end && end <= len else { - #| abort("View index out of bounds") - #| } - #| MutArrayView::make(self.buf(), self.start() + start, end - start) - #|} - #|pub fn[T] FixedArray::mut_view( - #| self : FixedArray[T], - #| start? : Int = 0, - #| end? : Int, - #|) -> MutArrayView[T] { - #| let len = self.length() - #| let end = match end { - #| None => len - #| Some(end) => if end < 0 { len + end } else { end } - #| } - #| let start = if start < 0 { len + start } else { start } - #| guard start >= 0 && start <= end && end <= len else { - #| abort("View index out of bounds") - #| } - #| MutArrayView::make( - #| unsafe_cast_fixedarray_to_uninitializedarray(self), - #| start, - #| end - start, - #| ) - #|} - #|#alias("_[_:_]") - #|pub fn[T] MutArrayView::sub( - #| self : MutArrayView[T], - #| start? : Int = 0, - #| end? : Int, - #|) -> ArrayView[T] { - #| let len = self.length() - #| let end = match end { - #| None => len - #| Some(end) => if end < 0 { len + end } else { end } - #| } - #| let start = if start < 0 { len + start } else { start } - #| guard start >= 0 && start <= end && end <= len else { - #| abort("View index out of bounds") - #| } - #| ArrayView::make(self.buf(), self.start() + start, end - start) - #|} - #|pub fn[X] MutArrayView::iterator(self : MutArrayView[X]) -> Iterator[X] { - #| let mut i = 0 - #| Iterator::new(fn() { - #| guard i < self.length() else { None } - #| let elem = self.unsafe_get(i) - #| i += 1 - #| Some(elem) - #| }) - #|} - #|pub fn[X] MutArrayView::rev_iterator(self : MutArrayView[X]) -> Iterator[X] { - #| let mut i = self.length() - #| Iterator::new(fn() { - #| guard i > 0 else { None } - #| i -= 1 - #| Some(self.unsafe_get(i)) - #| }) - #|} - #|pub fn[X] MutArrayView::Iter2(self : MutArrayView[X]) -> Iter2[Int, X] { - #| let mut i = 0 - #| Iter2::new(fn() { - #| guard i < self.length() else { None } - #| let result = Some((i, self.unsafe_get(i))) - #| i += 1 - #| result - #| }) - #|} - #|pub impl[X : Show] Show for MutArrayView[X] with output(self, logger) { - #| self[:].output(logger) - #|} - #|pub impl[T : Eq] Eq for MutArrayView[T] with equal(self, other) -> Bool { - #| self[:] == other[:] - #|} - #|pub impl[T : Compare] Compare for MutArrayView[T] with compare(self, other) -> Int { - #| self[:].compare(other[:]) - #|} - #|pub impl[A : Hash] Hash for MutArrayView[A] with hash_combine(self, hasher) { - #| self[:].hash_combine(hasher) - #|} - ), - "op.mbt": ( - #|#coverage.skip - #|#deprecated - #|#doc(hidden) - #|pub fn[T : Compare] op_lt(self_ : T, other : T) -> Bool { - #| Compare::op_lt(self_, other) - #|} - #|#coverage.skip - #|#deprecated - #|#doc(hidden) - #|pub fn[T : Compare] op_gt(self_ : T, other : T) -> Bool { - #| Compare::op_gt(self_, other) - #|} - #|#coverage.skip - #|#deprecated - #|#doc(hidden) - #|pub fn[T : Compare] op_le(self_ : T, other : T) -> Bool { - #| Compare::op_le(self_, other) - #|} - #|#coverage.skip - #|#deprecated - #|#doc(hidden) - #|pub fn[T : Compare] op_ge(self_ : T, other : T) -> Bool { - #| Compare::op_ge(self_, other) - #|} - #|#coverage.skip - #|pub fn[T : Eq] op_notequal(x : T, y : T) -> Bool { - #| !(x == y) - #|} - ), - "operators.mbt": ( - #|pub(open) trait Add { - #| add(Self, Self) -> Self = _ - #| #deprecated("use `add` instead", skip_current_package=true) - #| op_add(Self, Self) -> Self = _ - #|} - #|pub(open) trait Sub { - #| sub(Self, Self) -> Self = _ - #| #deprecated("use `sub` instead", skip_current_package=true) - #| op_sub(Self, Self) -> Self = _ - #|} - #|pub(open) trait Mul { - #| mul(Self, Self) -> Self = _ - #| #deprecated("use `mul` instead", skip_current_package=true) - #| op_mul(Self, Self) -> Self = _ - #|} - #|pub(open) trait Div { - #| div(Self, Self) -> Self = _ - #| #deprecated("use `div` instead", skip_current_package=true) - #| op_div(Self, Self) -> Self = _ - #|} - #|pub(open) trait Neg { - #| neg(Self) -> Self = _ - #| #deprecated("use `neg` instead", skip_current_package=true) - #| op_neg(Self) -> Self = _ - #|} - #|pub(open) trait Mod { - #| mod(Self, Self) -> Self = _ - #| #deprecated("use `mod` instead", skip_current_package=true) - #| op_mod(Self, Self) -> Self = _ - #|} - #|pub(open) trait BitAnd { - #| land(Self, Self) -> Self - #|} - #|pub(open) trait BitOr { - #| lor(Self, Self) -> Self - #|} - #|pub(open) trait BitXOr { - #| lxor(Self, Self) -> Self - #|} - #|pub(open) trait Shl { - #| shl(Self, Int) -> Self = _ - #| #deprecated("use `shl` instead", skip_current_package=true) - #| op_shl(Self, Int) -> Self = _ - #|} - #|pub(open) trait Shr { - #| shr(Self, Int) -> Self = _ - #| #deprecated("use `shr` instead", skip_current_package=true) - #| op_shr(Self, Int) -> Self = _ - #|} - #|#deprecated("replace `impl op_add` with `impl add`") - #|impl Add with add(self, other) { - #| Add::op_add(self, other) - #|} - #|impl Add with op_add(self, other) { - #| Add::add(self, other) - #|} - #|#deprecated("replace `impl op_sub` with `impl sub`") - #|impl Sub with sub(self, other) { - #| Sub::op_sub(self, other) - #|} - #|impl Sub with op_sub(self, other) { - #| Sub::sub(self, other) - #|} - #|#deprecated("replace `impl op_mul` with `impl mul`") - #|impl Mul with mul(self, other) { - #| Mul::op_mul(self, other) - #|} - #|impl Mul with op_mul(self, other) { - #| Mul::mul(self, other) - #|} - #|#deprecated("replace `impl op_div` with `impl div`") - #|impl Div with div(self, other) { - #| Div::op_div(self, other) - #|} - #|impl Div with op_div(self, other) { - #| Div::div(self, other) - #|} - #|#deprecated("replace `impl op_neg` with `impl neg`") - #|impl Neg with neg(self) { - #| Neg::op_neg(self) - #|} - #|impl Neg with op_neg(self) { - #| Neg::neg(self) - #|} - #|#deprecated("replace `impl op_mod` with `impl mod`") - #|impl Mod with mod(self, other) { - #| Mod::op_mod(self, other) - #|} - #|impl Mod with op_mod(self, other) { - #| Mod::mod(self, other) - #|} - #|#deprecated("replace `impl op_shl` with `impl shl`") - #|impl Shl with shl(self, i) { - #| Shl::op_shl(self, i) - #|} - #|impl Shl with op_shl(self, i) { - #| Shl::shl(self, i) - #|} - #|#deprecated("replace `impl op_shr` with `impl shr`") - #|impl Shr with shr(self, i) { - #| Shr::op_shr(self, i) - #|} - #|impl Shr with op_shr(self, i) { - #| Shr::shr(self, i) - #|} - ), - "option.mbt": ( - #|pub impl[X : Eq] Eq for X? with equal(self, other) { - #| match (self, other) { - #| (None, None) => true - #| (Some(x), Some(y)) => x == y - #| _ => false - #| } - #|} - #|pub fn[X : Show] Option::to_string(self : X?) -> String { - #| match self { - #| None => "None" - #| Some(x) => "Some(" + x.to_string() + ")" - #| } - #|} - #|pub fn[X] Option::unwrap(self : X?) -> X { - #| match self { - #| None => panic() - #| Some(x) => x - #| } - #|} - #|#alias(or, deprecated) - #|pub fn[T] Option::unwrap_or(self : T?, default : T) -> T { - #| match self { - #| None => default - #| Some(t) => t - #| } - #|} - #|#alias(or_else, deprecated) - #|pub fn[T] Option::unwrap_or_else( - #| self : T?, - #| default : () -> T raise?, - #|) -> T raise? { - #| match self { - #| None => default() - #| Some(t) => t - #| } - #|} - #|#alias(or_default, deprecated) - #|pub fn[T : Default] Option::unwrap_or_default(self : T?) -> T { - #| match self { - #| None => T::default() - #| Some(t) => t - #| } - #|} - #|pub impl[X : Compare] Compare for X? with compare(self, other) { - #| match (self, other) { - #| (Some(x), Some(y)) => x.compare(y) - #| (Some(_), None) => 1 - #| (None, Some(_)) => -1 - #| (None, None) => 0 - #| } - #|} - #|#alias(or_error, deprecated) - #|pub fn[T, Err : Error] Option::unwrap_or_error( - #| self : T?, - #| err : Err, - #|) -> T raise Err { - #| match self { - #| Some(v) => v - #| None => raise err - #| } - #|} - #|pub impl[X] Default for X? with default() { - #| None - #|} - #|pub fn[T] Option::iter(self : T?) -> Iter[T] { - #| match self { - #| Some(v) => Iter::singleton(v) - #| None => Iter::empty() - #| } - #|} - #|pub fn[T] Option::iterator(self : T?) -> Iterator[T] { - #| match self { - #| Some(v) => Iterator::singleton(v) - #| None => Iterator::empty() - #| } - #|} - #|pub fn[T, U] Option::map(self : T?, f : (T) -> U raise?) -> U? raise? { - #| match self { - #| Some(t) => Some(f(t)) - #| None => None - #| } - #|} - #|pub fn[T, U] Option::map_or( - #| self : T?, - #| default : U, - #| f : (T) -> U raise?, - #|) -> U raise? { - #| match self { - #| None => default - #| Some(x) => f(x) - #| } - #|} - #|pub fn[T, U] Option::map_or_else( - #| self : T?, - #| default : () -> U raise?, - #| f : (T) -> U raise?, - #|) -> U raise? { - #| match self { - #| None => default() - #| Some(x) => f(x) - #| } - #|} - #|pub fn[T, U] Option::bind(self : T?, f : (T) -> U? raise?) -> U? raise? { - #| match self { - #| Some(t) => f(t) - #| None => None - #| } - #|} - #|#deprecated("use `option.bind(x => x)` instead") - #|pub fn[T] Option::flatten(self : T??) -> T? { - #| match self { - #| Some(inner) => inner - #| None => None - #| } - #|} - #|#deprecated("use `x is None` instead") - #|pub fn[T] Option::is_empty(self : T?) -> Bool { - #| self is None - #|} - #|pub fn[T] Option::filter(self : T?, f : (T) -> Bool raise?) -> T? raise? { - #| match self { - #| Some(t) => if f(t) { self } else { None } - #| None => None - #| } - #|} - #|#deprecated("use `x is Some(_)` instead") - #|pub fn[T] Option::is_some(self : T?) -> Bool { - #| self is Some(_) - #|} - #|#deprecated("use `x is None` instead") - #|pub fn[T] Option::is_none(self : T?) -> Bool { - #| self is None - #|} - ), - "readonlyarray.mbt": ( - #|fn[T] ReadOnlyArray::unsafe_reinterpret_to_fixed_array( - #| self : ReadOnlyArray[T], - #|) -> FixedArray[T] = "%identity" - #|fn[T] unsafe_reinterpret_from_fixed_array( - #| arr : FixedArray[T], - #|) -> ReadOnlyArray[T] = "%identity" - #|#alias("_[_]") - #|pub fn[T] ReadOnlyArray::at(self : ReadOnlyArray[T], index : Int) -> T { - #| self.unsafe_reinterpret_to_fixed_array()[index] - #|} - #|pub fn[T] ReadOnlyArray::from_array(array : ArrayView[T]) -> ReadOnlyArray[T] { - #| unsafe_reinterpret_from_fixed_array(FixedArray::from_array(array)) - #|} - #|pub fn[T] ReadOnlyArray::from_iter(iter : Iter[T]) -> ReadOnlyArray[T] { - #| unsafe_reinterpret_from_fixed_array(FixedArray::from_iter(iter)) - #|} - #|pub fn[T] ReadOnlyArray::from_iterator(iter : Iterator[T]) -> ReadOnlyArray[T] { - #| unsafe_reinterpret_from_fixed_array(FixedArray::from_iterator(iter)) - #|} - #|pub fn[T] ReadOnlyArray::makei( - #| length : Int, - #| value : (Int) -> T raise?, - #|) -> ReadOnlyArray[T] raise? { - #| unsafe_reinterpret_from_fixed_array(FixedArray::makei(length, value)) - #|} - #|pub fn[T] ReadOnlyArray::get(self : ReadOnlyArray[T], index : Int) -> T? { - #| self.unsafe_reinterpret_to_fixed_array().get(index) - #|} - #|pub fn[T] ReadOnlyArray::length(self : ReadOnlyArray[T]) -> Int { - #| self.unsafe_reinterpret_to_fixed_array().length() - #|} - #|pub fn[T] ReadOnlyArray::is_empty(self : ReadOnlyArray[T]) -> Bool { - #| self.unsafe_reinterpret_to_fixed_array().is_empty() - #|} - #|pub fn[T] ReadOnlyArray::last(self : ReadOnlyArray[T]) -> T? { - #| self.unsafe_reinterpret_to_fixed_array().last() - #|} - #|pub fn[T] ReadOnlyArray::iter(self : ReadOnlyArray[T]) -> Iter[T] { - #| self.unsafe_reinterpret_to_fixed_array().iter() - #|} - #|pub fn[T] ReadOnlyArray::iterator(self : ReadOnlyArray[T]) -> Iterator[T] { - #| self.unsafe_reinterpret_to_fixed_array().iterator() - #|} - #|pub fn[T] ReadOnlyArray::iter2(self : ReadOnlyArray[T]) -> Iter2[Int, T] { - #| self.unsafe_reinterpret_to_fixed_array().iter2() - #|} - #|pub fn[T] ReadOnlyArray::each( - #| self : ReadOnlyArray[T], - #| f : (T) -> Unit raise?, - #|) -> Unit raise? { - #| self.unsafe_reinterpret_to_fixed_array().each(f) - #|} - #|pub fn[T] ReadOnlyArray::eachi( - #| self : ReadOnlyArray[T], - #| f : (Int, T) -> Unit raise?, - #|) -> Unit raise? { - #| self.unsafe_reinterpret_to_fixed_array().eachi(f) - #|} - #|pub fn[T] ReadOnlyArray::rev_each( - #| self : ReadOnlyArray[T], - #| f : (T) -> Unit raise?, - #|) -> Unit raise? { - #| self.unsafe_reinterpret_to_fixed_array().rev_each(f) - #|} - #|pub fn[T] ReadOnlyArray::rev_eachi( - #| self : ReadOnlyArray[T], - #| f : (Int, T) -> Unit raise?, - #|) -> Unit raise? { - #| self.unsafe_reinterpret_to_fixed_array().rev_eachi(f) - #|} - #|pub fn[T, U] ReadOnlyArray::map( - #| self : ReadOnlyArray[T], - #| f : (T) -> U raise?, - #|) -> ReadOnlyArray[U] raise? { - #| unsafe_reinterpret_from_fixed_array( - #| self.unsafe_reinterpret_to_fixed_array().map(f), - #| ) - #|} - #|pub fn[T, U] ReadOnlyArray::mapi( - #| self : ReadOnlyArray[T], - #| f : (Int, T) -> U raise?, - #|) -> ReadOnlyArray[U] raise? { - #| unsafe_reinterpret_from_fixed_array( - #| self.unsafe_reinterpret_to_fixed_array().mapi(f), - #| ) - #|} - #|pub fn[A, B] ReadOnlyArray::fold( - #| self : ReadOnlyArray[A], - #| init~ : B, - #| f : (B, A) -> B raise?, - #|) -> B raise? { - #| self.unsafe_reinterpret_to_fixed_array().fold(init~, f) - #|} - #|pub fn[A, B] ReadOnlyArray::rev_fold( - #| self : ReadOnlyArray[A], - #| init~ : B, - #| f : (B, A) -> B raise?, - #|) -> B raise? { - #| self.unsafe_reinterpret_to_fixed_array().rev_fold(init~, f) - #|} - #|pub fn[A, B] ReadOnlyArray::foldi( - #| self : ReadOnlyArray[A], - #| init~ : B, - #| f : (Int, B, A) -> B raise?, - #|) -> B raise? { - #| self.unsafe_reinterpret_to_fixed_array().foldi(init~, f) - #|} - #|pub fn[A, B] ReadOnlyArray::rev_foldi( - #| self : ReadOnlyArray[A], - #| init~ : B, - #| f : (Int, B, A) -> B raise?, - #|) -> B raise? { - #| self.unsafe_reinterpret_to_fixed_array().rev_foldi(init~, f) - #|} - #|pub fn[T] ReadOnlyArray::rev(self : ReadOnlyArray[T]) -> ReadOnlyArray[T] { - #| unsafe_reinterpret_from_fixed_array( - #| self.unsafe_reinterpret_to_fixed_array().rev(), - #| ) - #|} - #|pub fn[T : Eq] ReadOnlyArray::search( - #| self : ReadOnlyArray[T], - #| value : T, - #|) -> Int? { - #| self.unsafe_reinterpret_to_fixed_array().search(value) - #|} - #|pub fn[T : Eq] ReadOnlyArray::contains( - #| self : ReadOnlyArray[T], - #| value : T, - #|) -> Bool { - #| self.unsafe_reinterpret_to_fixed_array().contains(value) - #|} - #|pub fn[T : Eq] ReadOnlyArray::starts_with( - #| self : ReadOnlyArray[T], - #| prefix : ReadOnlyArray[T], - #|) -> Bool { - #| self - #| .unsafe_reinterpret_to_fixed_array() - #| .starts_with(prefix.unsafe_reinterpret_to_fixed_array()) - #|} - #|pub fn[T : Eq] ReadOnlyArray::ends_with( - #| self : ReadOnlyArray[T], - #| suffix : ReadOnlyArray[T], - #|) -> Bool { - #| self - #| .unsafe_reinterpret_to_fixed_array() - #| .ends_with(suffix.unsafe_reinterpret_to_fixed_array()) - #|} - #|pub fn[T] ReadOnlyArray::all( - #| self : ReadOnlyArray[T], - #| f : (T) -> Bool raise?, - #|) -> Bool raise? { - #| self.unsafe_reinterpret_to_fixed_array().all(f) - #|} - #|pub fn[T] ReadOnlyArray::any( - #| self : ReadOnlyArray[T], - #| f : (T) -> Bool raise?, - #|) -> Bool raise? { - #| self.unsafe_reinterpret_to_fixed_array().any(f) - #|} - #|pub fn[T : Compare] ReadOnlyArray::binary_search( - #| self : ReadOnlyArray[T], - #| value : T, - #|) -> Result[Int, Int] { - #| self.unsafe_reinterpret_to_fixed_array().binary_search(value) - #|} - #|pub fn[T] ReadOnlyArray::binary_search_by( - #| self : ReadOnlyArray[T], - #| cmp : (T) -> Int raise?, - #|) -> Result[Int, Int] raise? { - #| self.unsafe_reinterpret_to_fixed_array().binary_search_by(cmp) - #|} - #|#alias("_[_:_]") - #|pub fn[T] ReadOnlyArray::sub( - #| self : ReadOnlyArray[T], - #| start? : Int = 0, - #| end? : Int, - #|) -> ArrayView[T] { - #| match end { - #| None => self.unsafe_reinterpret_to_fixed_array().sub(start~) - #| Some(e) => self.unsafe_reinterpret_to_fixed_array().sub(start~, end=e) - #| } - #|} - #|pub fn ReadOnlyArray::join( - #| self : ReadOnlyArray[String], - #| separator : StringView, - #|) -> String { - #| self.unsafe_reinterpret_to_fixed_array().join(separator) - #|} - #|pub impl[T] Default for ReadOnlyArray[T] with default() { - #| unsafe_reinterpret_from_fixed_array(FixedArray::default()) - #|} - #|pub impl[T : Show] Show for ReadOnlyArray[T] with output(self, logger) { - #| self.unsafe_reinterpret_to_fixed_array().output(logger) - #|} - #|pub impl[T : ToJson] ToJson for ReadOnlyArray[T] with to_json(self) { - #| self.unsafe_reinterpret_to_fixed_array().to_json() - #|} - #|pub impl[T : Eq] Eq for ReadOnlyArray[T] with equal(self, other) { - #| self - #| .unsafe_reinterpret_to_fixed_array() - #| .equal(other.unsafe_reinterpret_to_fixed_array()) - #|} - #|pub impl[T : Compare] Compare for ReadOnlyArray[T] with compare(self, other) { - #| self - #| .unsafe_reinterpret_to_fixed_array() - #| .compare(other.unsafe_reinterpret_to_fixed_array()) - #|} - ), - "result.mbt": ( - #|pub fn[T, E, U] Result::map(self : Result[T, E], f : (T) -> U) -> Result[U, E] { - #| match self { - #| Ok(value) => Ok(f(value)) - #| Err(err) => Err(err) - #| } - #|} - #|test "map" { - #| let x : Result[Int, Unit] = Ok(6) - #| let y = x.map((v : Int) => v * 7) - #| let z : Result[Int, Int] = Err(3) - #| let w = z.map((v : Int) => v * 7) - #| assert_eq(y, Ok(42)) - #| assert_eq(w, Err(3)) - #|} - #|pub fn[T, E, F] Result::map_err( - #| self : Result[T, E], - #| f : (E) -> F, - #|) -> Result[T, F] { - #| match self { - #| Ok(value) => Ok(value) - #| Err(err) => Err(f(err)) - #| } - #|} - #|test "map_err" { - #| let x : Result[Int, String] = Err("error") - #| let y = x.map_err((v : String) => v + "!") - #| let z : Result[Int, Int] = Ok(6) - #| let w = z.map_err((v : Int) => v + 6) - #| assert_eq(y, Err("error!")) - #| assert_eq(w, Ok(6)) - #|} - #|#alias(or) - #|pub fn[T, E] Result::unwrap_or(self : Result[T, E], default : T) -> T { - #| match self { - #| Ok(value) => value - #| Err(_) => default - #| } - #|} - #|test "unwrap_or" { - #| let x : Result[Int, String] = Ok(3) - #| let y : Result[Int, String] = Err("error") - #| assert_eq(x.unwrap_or(5), 3) - #| assert_eq(y.unwrap_or(5), 5) - #|} - #|#alias(or_else) - #|pub fn[T, E] Result::unwrap_or_else( - #| self : Result[T, E], - #| default : () -> T raise?, - #|) -> T raise? { - #| match self { - #| Ok(value) => value - #| Err(_) => default() - #| } - #|} - #|test "unwrap_or_else" { - #| let x : Result[Int, String] = Ok(3) - #| let y : Result[Int, String] = Err("error") - #| assert_eq(x.unwrap_or_else(() => 5), 3) - #| assert_eq(y.unwrap_or_else(() => 5), 5) - #|} - #|pub fn[T, E] Result::flatten(self : Result[Result[T, E], E]) -> Result[T, E] { - #| match self { - #| Ok(value) => value - #| Err(err) => Err(err) - #| } - #|} - #|test "flatten" { - #| let x : Result[Result[Int, String], String] = Ok(Ok(6)) - #| let y = x.flatten() - #| let z : Result[Result[Int, String], String] = Err("error") - #| let w = z.flatten() - #| assert_eq(y, Ok(6)) - #| assert_eq(w, Err("error")) - #|} - #|pub fn[T, E, U] Result::bind( - #| self : Result[T, E], - #| g : (T) -> Result[U, E], - #|) -> Result[U, E] { - #| match self { - #| Ok(value) => g(value) - #| Err(err) => Err(err) - #| } - #|} - #|test "bind" { - #| let x : Result[Int, String] = Ok(6) - #| let y = x.bind((v : Int) => Ok(v * 7)) - #| assert_eq(y, Ok(42)) - #|} - #|pub fn[T, E] Result::to_option(self : Result[T, E]) -> T? { - #| match self { - #| Ok(value) => Some(value) - #| Err(_) => None - #| } - #|} - #|test "to_option" { - #| let x : Result[Int, String] = Ok(6) - #| let y : Result[Int, String] = Err("error") - #| let z = x.to_option() - #| let w = y.to_option() - #| assert_eq(z, Some(6)) - #| assert_eq(w, None) - #|} - #|pub impl[T : Compare, E : Compare] Compare for Result[T, E] with compare( - #| self : Result[T, E], - #| other : Result[T, E], - #|) -> Int { - #| match (self, other) { - #| (Ok(x), Ok(y)) => x.compare(y) - #| (Ok(_), Err(_)) => -1 - #| (Err(_), Ok(_)) => 1 - #| (Err(x), Err(y)) => x.compare(y) - #| } - #|} - #|test "compare" { - #| let ok1 = Result::Ok(1) - #| let ok2 = Result::Ok(2) - #| let err1 = Result::Err(1) - #| let err2 = Result::Err(2) - #| assert_eq(0, ok1.compare(ok1)) - #| assert_eq(0, err2.compare(Result::Err(2))) - #| assert_eq(-1, ok1.compare(ok2)) - #| assert_eq(1, ok2.compare(ok1)) - #| assert_eq(-1, err1.compare(err2)) - #| assert_eq(1, err2.compare(err1)) - #| assert_eq(-1, ok2.compare(err1)) - #| assert_eq(1, err1.compare(ok2)) - #|} - #|pub fn[T, E] Result::unwrap(self : Result[T, E]) -> T { - #| match self { - #| Ok(x) => x - #| Err(_) => abort("called `Result::unwrap()` on an `Err` value") - #| } - #|} - #|pub fn[T, E] Result::unwrap_err(self : Result[T, E]) -> E { - #| match self { - #| Ok(_) => abort("called `Result::unwrap_err()` on an `Ok` value") - #| Err(e) => e - #| } - #|} - #|test "show" { - #| let ok : Result[_, String] = Ok("hello") - #| inspect( - #| ok, - #| content=( - #| #|Ok("hello") - #| ), - #| ) - #| let err : Result[String, _] = Err("world") - #| inspect( - #| err, - #| content=( - #| #|Err("world") - #| ), - #| ) - #|} - #|pub fn[T : Default, E] Result::unwrap_or_default(self : Result[T, E]) -> T { - #| match self { - #| Ok(value) => value - #| Err(_) => T::default() - #| } - #|} - #|test "unwrap_or_default" { - #| let x : Result[Int, String] = Ok(3) - #| let y : Result[Int, String] = Err("error") - #| assert_eq(x.unwrap_or_default(), 3) - #| assert_eq(y.unwrap_or_default(), 0) - #|} - #|pub fn[T, E : Error] Result::unwrap_or_error(self : Result[T, E]) -> T raise E { - #| match self { - #| Ok(x) => x - #| Err(e) => raise e - #| } - #|} - #|test "unwrap exn" { - #| (try - #| (Err(Failure("This is serious")) : Result[Unit, Failure]).unwrap_or_error() - #| |> Ok - #| catch { - #| Failure(msg) => Err(msg) - #| }) - #| |> inspect( - #| content=( - #| #|Err("This is serious") - #| ), - #| ) - #|} - #|pub impl[T : Eq, E : Eq] Eq for Result[T, E] with equal(self, other) { - #| match (self, other) { - #| (Ok(x), Ok(y)) => x == y - #| (Err(x), Err(y)) => x == y - #| _ => false - #| } - #|} - ), - "show.mbt": ( - #|pub impl Show for Unit with output(_self, logger) { - #| logger.write_string("()") - #|} - #|pub impl Show for Bool with output(self, logger) { - #| if self { - #| logger.write_string("true") - #| } else { - #| logger.write_string("false") - #| } - #|} - #|pub impl Show for Int with output(self, logger) { - #| logger.write_string(self.to_string()) - #|} - #|pub impl Show for Int64 with output(self, logger) { - #| logger.write_string(self.to_string()) - #|} - #|pub impl Show for UInt with output(self, logger) { - #| logger.write_string(self.to_string()) - #|} - #|pub impl Show for UInt64 with output(self, logger) { - #| logger.write_string(self.to_string()) - #|} - #|pub impl Show for Byte with output(self, logger) { - #| logger.write_string(self.to_string()) - #|} - #|pub impl Show for UInt16 with output(self, logger) { - #| logger.write_string(self.to_string()) - #|} - #|pub fn Byte::to_hex(b : Byte) -> String { - #| fn to_hex_digit(i : Byte) -> Char { - #| if i < 10 { - #| (i + '0').to_char() - #| } else { - #| (i + 'a' - 10).to_char() - #| } - #| } - #| [to_hex_digit(b / 16), to_hex_digit(b % 16)] - #|} - #|test "to_hex_digit" { - #| inspect(Byte::to_hex(b'\xee'), content="ee") - #| inspect(Byte::to_hex(b'\xf3'), content="f3") - #|} - #|pub impl Show for String with output(self, logger) { - #| logger.write_char('"') - #| fn flush_segment(seg : Int, i : Int) { - #| if i > seg { - #| logger.write_substring(self, seg, i - seg) - #| } - #| } - #| let len = self.length() - #| for i = 0, seg = 0 { - #| if i >= len { - #| flush_segment(seg, i) - #| break - #| } - #| let code = self.unsafe_charcode_at(i) - #| match code { - #| '"' | '\\' as c => { - #| flush_segment(seg, i) - #| logger..write_char('\\')..write_char(c.unsafe_to_char()) - #| continue i + 1, i + 1 - #| } - #| '\n' => { - #| flush_segment(seg, i) - #| logger.write_string("\\n") - #| continue i + 1, i + 1 - #| } - #| '\r' => { - #| flush_segment(seg, i) - #| logger.write_string("\\r") - #| continue i + 1, i + 1 - #| } - #| '\b' => { - #| flush_segment(seg, i) - #| logger.write_string("\\b") - #| continue i + 1, i + 1 - #| } - #| '\t' => { - #| flush_segment(seg, i) - #| logger.write_string("\\t") - #| continue i + 1, i + 1 - #| } - #| code => - #| if code < ' ' { - #| flush_segment(seg, i) - #| logger - #| ..write_string("\\u{") - #| ..write_string(code.to_byte().to_hex()) - #| ..write_char('}') - #| continue i + 1, i + 1 - #| } else { - #| continue i + 1, seg - #| } - #| } - #| } - #| logger.write_char('"') - #|} - #|pub impl Show for String with to_string(self) { - #| self - #|} - #|pub fn String::escape(self : String) -> String { - #| let buf = StringBuilder::new() - #| Show::output(self, buf) - #| buf.to_string() - #|} - #|pub impl[X : Show] Show for X? with output(self, logger) { - #| match self { - #| None => logger.write_string("None") - #| Some(arg) => - #| logger..write_string("Some(")..write_object(arg)..write_string(")") - #| } - #|} - #|pub impl[T : Show, E : Show] Show for Result[T, E] with output(self, logger) { - #| match self { - #| Ok(x) => logger..write_string("Ok(")..write_object(x)..write_string(")") - #| Err(e) => logger..write_string("Err(")..write_object(e)..write_string(")") - #| } - #|} - #|pub impl[X : Show] Show for FixedArray[X] with output(self, logger) { - #| logger.write_iter(self.iter()) - #|} - #|pub impl[X : Show] Show for Array[X] with output(self, logger) { - #| logger.write_iter(self.iter()) - #|} - ), - "string.mbt": ( - #|fn unsafe_make_string(length : Int, value : Char) -> String = "$moonbit.unsafe_make_string" - #|pub fn String::make(length : Int, value : Char) -> String { - #| guard length >= 0 else { abort("invalid length") } - #| if value.to_int() <= 0xFFFF { - #| unsafe_make_string(length, value) - #| } else { - #| let buf = StringBuilder::new(size_hint=2 * length) - #| for _ in 0.. Char { - #| ((leading - 0xD800) * 0x400 + trailing - 0xDC00 + 0x10000).unsafe_to_char() - #|} - #|#alias(codepoint_length, deprecated) - #|pub fn String::char_length( - #| self : String, - #| start_offset? : Int = 0, - #| end_offset? : Int, - #|) -> Int { - #| let end_offset = if end_offset is Some(o) { o } else { self.length() } - #| guard start_offset >= 0 && - #| start_offset <= end_offset && - #| end_offset <= self.length() else { - #| abort("invalid start or end index for String::codepoint_length") - #| } - #| for utf16_index = start_offset, char_count = 0 - #| utf16_index < end_offset - #| utf16_index = utf16_index + 1, char_count = char_count + 1 { - #| let c1 = self.unsafe_charcode_at(utf16_index) - #| if c1.is_leading_surrogate() && utf16_index + 1 < end_offset { - #| let c2 = self.unsafe_charcode_at(utf16_index + 1) - #| if c2.is_trailing_surrogate() { - #| continue utf16_index + 2, char_count + 1 - #| } else { - #| abort("invalid surrogate pair") - #| } - #| } - #| } else { - #| char_count - #| } - #|} - #|#intrinsic("%string.substring") - #|pub fn String::unsafe_substring( - #| str : String, - #| start~ : Int, - #| end~ : Int, - #|) -> String { - #| if start == 0 && end == str.length() { - #| return str - #| } - #| let len = end - start - #| let bytes = FixedArray::make(len * 2, Byte::default()) - #| bytes.blit_from_string(0, str, start, len) - #| bytes.unsafe_reinterpret_as_bytes().to_unchecked_string() - #|} - #|#deprecated("Use `str[:]` or `str[:].to_string()` instead", skip_current_package=true) - #|pub fn String::substring(self : String, start? : Int = 0, end? : Int) -> String { - #| let len = self.length() - #| let end = match end { - #| Some(end) => end - #| None => len - #| } - #| guard start >= 0 && start <= end && end <= len - #| self.unsafe_substring(start~, end~) - #|} - #|pub fn String::suffixes( - #| self : String, - #| include_empty? : Bool = false, - #|) -> Iterator[StringView] { - #| self[:].suffixes(include_empty~) - #|} - #|test "substring/empty" { - #| let s = "test" - #| inspect(s.substring(start=2, end=2), content="") - #| inspect(s.substring(start=4, end=4), content="") - #| inspect("".substring(), content="") - #|} - #|test "panic substring/invalid_range" { - #| let s = "test" - #| ignore(s.substring(start=-1)) - #| ignore(s.substring(end=5)) - #| ignore(s.substring(start=3, end=2)) - #|} - #|test "substring/basic" { - #| inspect("Hello world".substring(start=0, end=5), content="Hello") - #| inspect("Hello world".substring(start=6, end=11), content="world") - #| inspect("Hello world".substring(start=0), content="Hello world") - #| inspect("Hello world".substring(start=6), content="world") - #|} - #|test "substring/boundary" { - #| inspect("".substring(start=0, end=0), content="") - #| inspect("a".substring(start=0, end=1), content="a") - #| inspect("abc".substring(start=0), content="abc") - #| inspect("abc".substring(start=1), content="bc") - #| inspect("abc".substring(start=0, end=3), content="abc") - #|} - #|test "panic substring/out_of_bounds" { - #| ignore("hello".substring(start=-1, end=4)) - #| ignore("hello".substring(start=6, end=4)) - #| ignore("hello".substring(start=0, end=6)) - #|} - #|pub impl Compare for String with compare(self, other) { - #| let len = self.length() - #| match len.compare(other.length()) { - #| 0 => { - #| for i in 0.. order - #| } - #|} - #|pub impl Default for String with default() { - #| "" - #|} - #|#deprecated("Check `@encoding/utf8.encode`") - #|pub fn String::to_bytes(self : String) -> Bytes { - #| let array = FixedArray::make(self.length() * 2, Byte::default()) - #| array.blit_from_string(0, self, 0, self.length()) - #| array |> unsafe_to_bytes - #|} - #|fn unsafe_to_bytes(array : FixedArray[Byte]) -> Bytes = "%identity" - #|pub fn String::to_array(self : String) -> Array[Char] { - #| self - #| .iter() - #| .fold(init=Array::new(capacity=self.length()), (rv, c) => { - #| rv.push(c) - #| rv - #| }) - #|} - #|pub fn String::iter(self : String) -> Iter[Char] { - #| self.iterator().iter() - #|} - #|pub fn String::iterator(self : String) -> Iterator[Char] { - #| let len = self.length() - #| let mut index = 0 - #| Iterator::new(fn() { - #| guard index < len else { None } - #| let c1 = self.unsafe_charcode_at(index) - #| if c1.is_leading_surrogate() && index + 1 < len { - #| let c2 = self.unsafe_charcode_at(index + 1) - #| if c2.is_trailing_surrogate() { - #| let c = code_point_of_surrogate_pair(c1, c2) - #| index += 2 - #| return Some(c) - #| } - #| } - #| index += 1 - #| Some(c1.unsafe_to_char()) - #| }) - #|} - #|pub fn String::iter2(self : String) -> Iter2[Int, Char] { - #| self.Iter2().iter2() - #|} - #|pub fn String::Iter2(self : String) -> Iter2[Int, Char] { - #| self.iterator().Iter2() - #|} - #|pub fn String::rev_iter(self : String) -> Iter[Char] { - #| self.rev_iterator().iter() - #|} - #|pub fn String::rev_iterator(self : String) -> Iterator[Char] { - #| let len = self.length() - #| let mut index = len - #| Iterator::new(fn() { - #| guard index > 0 else { None } - #| index -= 1 - #| let c1 = self.unsafe_charcode_at(index) - #| if c1.is_trailing_surrogate() && index - 1 >= 0 { - #| let c2 = self.unsafe_charcode_at(index - 1) - #| if c2.is_leading_surrogate() { - #| index -= 1 - #| return Some(code_point_of_surrogate_pair(c2, c1)) - #| } - #| } - #| Some(c1.unsafe_to_char()) - #| }) - #|} - #|fn String::offset_of_nth_char_forward( - #| self : String, - #| n : Int, - #| start_offset~ : Int, - #| end_offset~ : Int, - #|) -> Int? { - #| guard start_offset >= 0 && start_offset <= end_offset else { - #| abort("Invalid start index") - #| } - #| let mut utf16_offset = start_offset - #| let mut char_count = 0 - #| while utf16_offset < end_offset && char_count < n { - #| let c = self.unsafe_charcode_at(utf16_offset) - #| if c.is_leading_surrogate() { - #| utf16_offset = utf16_offset + 2 - #| } else { - #| utf16_offset = utf16_offset + 1 - #| } - #| char_count = char_count + 1 - #| } - #| if char_count < n || utf16_offset >= end_offset { - #| None - #| } else { - #| Some(utf16_offset) - #| } - #|} - #|fn String::offset_of_nth_char_backward( - #| self : String, - #| n : Int, - #| start_offset~ : Int, - #| end_offset~ : Int, - #|) -> Int? { - #| let mut char_count = 0 - #| let mut utf16_offset = end_offset - #| while utf16_offset - 1 >= start_offset && char_count < n { - #| let c = self.unsafe_charcode_at(utf16_offset - 1) - #| if c.is_trailing_surrogate() { - #| utf16_offset = utf16_offset - 2 - #| } else { - #| utf16_offset = utf16_offset - 1 - #| } - #| char_count = char_count + 1 - #| } - #| if char_count < n || utf16_offset < start_offset { - #| None - #| } else { - #| Some(utf16_offset) - #| } - #|} - #|pub fn String::offset_of_nth_char( - #| self : String, - #| i : Int, - #| start_offset? : Int = 0, - #| end_offset? : Int, - #|) -> Int? { - #| let end_offset = if end_offset is Some(o) { o } else { self.length() } - #| if i >= 0 { - #| self.offset_of_nth_char_forward(i, start_offset~, end_offset~) - #| } else { - #| self.offset_of_nth_char_backward(-i, start_offset~, end_offset~) - #| } - #|} - #|pub fn String::char_length_eq( - #| self : String, - #| len : Int, - #| start_offset? : Int = 0, - #| end_offset? : Int, - #|) -> Bool { - #| let end_offset = if end_offset is Some(o) { o } else { self.length() } - #| for index = start_offset, count = 0 - #| index < end_offset && count < len - #| index = index + 1, count = count + 1 { - #| let c1 = self.unsafe_charcode_at(index) - #| if c1.is_leading_surrogate() && index + 1 < end_offset { - #| let c2 = self.unsafe_charcode_at(index + 1) - #| if c2.is_trailing_surrogate() { - #| continue index + 2, count + 1 - #| } else { - #| abort("invalid surrogate pair") - #| } - #| } - #| } else { - #| count == len && index == end_offset - #| } - #|} - #|pub fn String::char_length_ge( - #| self : String, - #| len : Int, - #| start_offset? : Int = 0, - #| end_offset? : Int, - #|) -> Bool { - #| let end_offset = if end_offset is Some(o) { o } else { self.length() } - #| for index = start_offset, count = 0 - #| index < end_offset && count < len - #| index = index + 1, count = count + 1 { - #| let c1 = self.unsafe_charcode_at(index) - #| if c1.is_leading_surrogate() && index + 1 < end_offset { - #| let c2 = self.unsafe_charcode_at(index + 1) - #| if c2.is_trailing_surrogate() { - #| continue index + 2, count + 1 - #| } else { - #| abort("invalid surrogate pair") - #| } - #| } - #| } else { - #| count >= len - #| } - #|} - #|pub fn String::lexical_compare(self : String, other : String) -> Int { - #| self[:].lexical_compare(other[:]) - #|} - #|pub fn String::from_array(chars : ArrayView[Char]) -> String { - #| let buf = StringBuilder::new(size_hint=chars.length() * 4) - #| for c in chars { - #| buf.write_char(c) - #| } - #| buf.to_string() - #|} - #|pub fn String::from_iter(iter : Iter[Char]) -> String { - #| let buf = StringBuilder::new() - #| for c in iter { - #| buf.write_char(c) - #| } - #| buf.to_string() - #|} - #|pub fn String::from_iterator(iter : Iterator[Char]) -> String { - #| let buf = StringBuilder::new() - #| for c in iter { - #| buf.write_char(c) - #| } - #| buf.to_string() - #|} - ), - "string_like.mbt": ( - #|pub trait ToStringView { - #| to_string_view(Self) -> StringView - #|} - #|pub impl ToStringView for String with to_string_view(self) -> StringView { - #| self[:] - #|} - #|pub impl ToStringView for StringView with to_string_view(self) -> StringView { - #| self - #|} - ), - "string_methods.mbt": ( - #|pub fn StringView::find(self : StringView, str : StringView) -> Int? { - #| if str.length() <= 4 { - #| brute_force_find(self, str) - #| } else { - #| boyer_moore_horspool_find(self, str) - #| } - #|} - #|fn brute_force_find(haystack : StringView, needle : StringView) -> Int? { - #| let haystack_len = haystack.length() - #| let needle_len = needle.length() - #| guard needle_len > 0 else { return Some(0) } - #| guard haystack_len >= needle_len else { return None } - #| let needle_first = needle.unsafe_charcode_at(0) - #| let forward_len = haystack_len - needle_len - #| let mut i = 0 - #| while i <= forward_len { - #| while i <= forward_len && haystack.unsafe_charcode_at(i) != needle_first { - #| i += 1 - #| } - #| if i <= forward_len { - #| for j in 1.. Int? { - #| let haystack_len = haystack.length() - #| let needle_len = needle.length() - #| guard needle_len > 0 else { return Some(0) } - #| guard haystack_len >= needle_len else { return None } - #| let skip_table = FixedArray::make(1 << 8, needle_len) - #| for i in 0..<(needle_len - 1) { - #| skip_table[needle.unsafe_charcode_at(i) & 0xFF] = needle_len - 1 - i - #| } - #| for i = 0 - #| i <= haystack_len - needle_len - #| i = i + skip_table[haystack.unsafe_charcode_at(i + needle_len - 1) & 0xFF] { - #| for j in 0..=(needle_len - 1) { - #| if haystack.unsafe_charcode_at(i + j) != needle.unsafe_charcode_at(j) { - #| break - #| } - #| } else { - #| return Some(i) - #| } - #| } - #| None - #|} - #|test "boyer_moore_horspool_find edge cases" { - #| inspect(boyer_moore_horspool_find("abc"[:], ""[:]), content="Some(0)") - #| inspect(boyer_moore_horspool_find("ab"[:], "abcd"[:]), content="None") - #|} - #|test "boyer_moore_horspool_rev_find edge cases" { - #| inspect(boyer_moore_horspool_rev_find("abc"[:], ""[:]), content="Some(3)") - #| inspect(boyer_moore_horspool_rev_find("ab"[:], "abcd"[:]), content="None") - #|} - #|pub fn String::find(self : String, str : StringView) -> Int? { - #| self[:].find(str) - #|} - #|test "find" { - #| inspect("hello".find("o"), content="Some(4)") - #| inspect("hello".find("l"), content="Some(2)") - #| inspect("hello".find("hello"), content="Some(0)") - #| inspect("hello".find("h"), content="Some(0)") - #| inspect("hello".find(""), content="Some(0)") - #| inspect("hello".find("world"), content="None") - #| inspect("".find(""), content="Some(0)") - #| inspect("".find("a"), content="None") - #| inspect("hello hello".find("hello"), content="Some(0)") - #| inspect("aaa".find("aa"), content="Some(0)") - #| inspect("😀😀".find("😀"), content="Some(0)") - #| inspect( - #| ("😀😀aa".repeat(20) + "😀😀😀😀").find("😀😀😀😀"), - #| content="Some(120)", - #| ) - #| inspect( - #| ("😀😀😀😀" + "😀😀aa".repeat(20)).find("😀😀😀😀"), - #| content="Some(0)", - #| ) - #|} - #|pub fn StringView::find_by(self : StringView, pred : (Char) -> Bool) -> Int? { - #| for i, c in self { - #| if pred(c) { - #| return Some(i) - #| } - #| } - #| None - #|} - #|pub fn String::find_by(self : String, pred : (Char) -> Bool) -> Int? { - #| self[:].find_by(pred) - #|} - #|test "find_by" { - #| inspect("hello".find_by(c => c == 'o'), content="Some(4)") - #| inspect("hello".find_by(c => c == 'l'), content="Some(2)") - #| inspect("hello".find_by(c => c == 'z'), content="None") - #| inspect("".find_by(c => c == 'a'), content="None") - #| inspect("hello".find_by(c => c is ('0'..='9')), content="None") - #| inspect("hello123".find_by(c => c is ('0'..='9')), content="Some(5)") - #| inspect("hello".find_by(c => c is ('A'..='Z')), content="None") - #| inspect("Hello".find_by(c => c is ('A'..='Z')), content="Some(0)") - #| inspect("αβγ".find_by(c => c == 'β'), content="Some(1)") - #| inspect("😀😁😂".find_by(c => c == '😂'), content="Some(2)") - #|} - #|pub fn StringView::rev_find(self : StringView, str : StringView) -> Int? { - #| if str.length() <= 4 { - #| brute_force_rev_find(self, str) - #| } else { - #| boyer_moore_horspool_rev_find(self, str) - #| } - #|} - #|fn brute_force_rev_find(haystack : StringView, needle : StringView) -> Int? { - #| let haystack_len = haystack.length() - #| let needle_len = needle.length() - #| guard needle_len > 0 else { return Some(haystack_len) } - #| guard haystack_len >= needle_len else { return None } - #| let needle_first = needle.unsafe_charcode_at(0) - #| let mut i = haystack_len - needle_len - #| while i >= 0 { - #| while i >= 0 && haystack.unsafe_charcode_at(i) != needle_first { - #| i -= 1 - #| } - #| if i >= 0 { - #| for j in 1.. Int? { - #| let haystack_len = haystack.length() - #| let needle_len = needle.length() - #| guard needle_len > 0 else { return Some(haystack_len) } - #| guard haystack_len >= needle_len else { return None } - #| let skip_table = FixedArray::make(1 << 8, needle_len) - #| for i = needle_len - 1; i > 0; i = i - 1 { - #| skip_table[needle.unsafe_charcode_at(i) & 0xFF] = i - #| } - #| for i = haystack_len - needle_len - #| i >= 0 - #| i = i - skip_table[haystack.unsafe_charcode_at(i) & 0xFF] { - #| for j in 0.. Int? { - #| self[:].rev_find(str) - #|} - #|test "rev_find" { - #| inspect("hello".rev_find("o"), content="Some(4)") - #| inspect("hello".rev_find("l"), content="Some(3)") - #| inspect("hello".rev_find("hello"), content="Some(0)") - #| inspect("hello".rev_find("h"), content="Some(0)") - #| inspect("hello".rev_find(""), content="Some(5)") - #| inspect("hello".rev_find("world"), content="None") - #| inspect("".rev_find(""), content="Some(0)") - #| inspect("".rev_find("a"), content="None") - #| inspect("hello hello".rev_find("hello"), content="Some(6)") - #| inspect("aaa".rev_find("aa"), content="Some(1)") - #| inspect("😀😀".rev_find("😀"), content="Some(2)") - #| inspect( - #| ("😀😀aa".repeat(20) + "😀😀😀😀").rev_find("😀😀😀😀"), - #| content="Some(120)", - #| ) - #| inspect( - #| ("😀😀😀😀" + "😀😀aa".repeat(20)).rev_find("😀😀😀😀"), - #| content="Some(4)", - #| ) - #|} - #|#alias(ends_with, deprecated) - #|pub fn StringView::has_suffix(self : StringView, str : StringView) -> Bool { - #| self.rev_find(str) is Some(i) && i == self.length() - str.length() - #|} - #|#alias(ends_with, deprecated) - #|pub fn String::has_suffix(self : String, str : StringView) -> Bool { - #| self[:].has_suffix(str) - #|} - #|test "has_suffix" { - #| inspect("hello".has_suffix("lo"), content="true") - #| inspect("hello".has_suffix("hello"), content="true") - #| inspect("hello".has_suffix(""), content="true") - #| inspect("hello".has_suffix("world"), content="false") - #| inspect("hello".has_suffix("hel"), content="false") - #| inspect("".has_suffix(""), content="true") - #| inspect("".has_suffix("a"), content="false") - #| inspect("hello world".has_suffix("world"), content="true") - #| inspect("😀😀".has_suffix("😀"), content="true") - #| inspect("😀😀".has_suffix("😀😀"), content="true") - #|} - #|#alias(starts_with, deprecated) - #|pub fn StringView::has_prefix(self : StringView, str : StringView) -> Bool { - #| self.find(str) is Some(i) && i == 0 - #|} - #|#alias(starts_with, deprecated) - #|pub fn String::has_prefix(self : String, str : StringView) -> Bool { - #| self[:].has_prefix(str) - #|} - #|test "has_prefix" { - #| inspect("hello".has_prefix("h"), content="true") - #| inspect("hello".has_prefix("he"), content="true") - #| inspect("hello".has_prefix(""), content="true") - #| inspect("hello".has_prefix("world"), content="false") - #| inspect("hello".has_prefix("lo"), content="false") - #| inspect("".has_prefix(""), content="true") - #| inspect("".has_prefix("a"), content="false") - #| inspect("😀hello".has_prefix("😀"), content="true") - #| inspect("😀😃hello".has_prefix("😀😃"), content="true") - #| inspect("😀hello".has_prefix("😃"), content="false") - #| inspect("hello😀".has_prefix("😀"), content="false") - #|} - #|pub fn String::strip_suffix(self : String, suffix : StringView) -> StringView? { - #| if self.has_suffix(suffix) { - #| Some(self.view(end_offset=self.length() - suffix.length())) - #| } else { - #| None - #| } - #|} - #|test "strip_prefix" { - #| inspect("hello world".strip_prefix("hello "), content="Some(\"world\")") - #| inspect("hello world".strip_prefix("hi "), content="None") - #| inspect("hello".strip_prefix("hello"), content="Some(\"\")") - #| inspect("".strip_prefix(""), content="Some(\"\")") - #| inspect("".strip_prefix("a"), content="None") - #| inspect("abc".strip_prefix(""), content="Some(\"abc\")") - #| inspect("😀hello".strip_prefix("😀"), content="Some(\"hello\")") - #| inspect("😀😃hello".strip_prefix("😀😃"), content="Some(\"hello\")") - #|} - #|test "strip_suffix" { - #| inspect("hello world".strip_suffix(" world"), content="Some(\"hello\")") - #| inspect("hello world".strip_suffix(" moon"), content="None") - #| inspect("hello".strip_suffix("hello"), content="Some(\"\")") - #| inspect("".strip_suffix(""), content="Some(\"\")") - #| inspect("".strip_suffix("a"), content="None") - #| inspect("abc".strip_suffix(""), content="Some(\"abc\")") - #| inspect("hello😀".strip_suffix("😀"), content="Some(\"hello\")") - #| inspect("hello😀😃".strip_suffix("😀😃"), content="Some(\"hello\")") - #|} - #|pub fn String::strip_prefix(self : String, prefix : StringView) -> StringView? { - #| if self.has_prefix(prefix) { - #| Some(self.view(start_offset=prefix.length())) - #| } else { - #| None - #| } - #|} - #|pub fn StringView::strip_prefix( - #| self : StringView, - #| prefix : StringView, - #|) -> StringView? { - #| if self.has_prefix(prefix) { - #| Some(self.view(start_offset=prefix.length())) - #| } else { - #| None - #| } - #|} - #|pub fn StringView::strip_suffix( - #| self : StringView, - #| suffix : StringView, - #|) -> StringView? { - #| if self.has_suffix(suffix) { - #| Some(self.view(end_offset=self.length() - suffix.length())) - #| } else { - #| None - #| } - #|} - #|pub fn StringView::to_array(self : StringView) -> Array[Char] { - #| self - #| .iter() - #| .fold(init=Array::new(capacity=self.length()), (rv, c) => { - #| rv.push(c) - #| rv - #| }) - #|} - #|#deprecated("Check `@encoding/utf8.encode`") - #|#coverage.skip - #|pub fn StringView::to_bytes(self : StringView) -> Bytes { - #| let array = FixedArray::make(self.length() * 2, Byte::default()) - #| array.blit_from_string(0, self.data(), self.start_offset(), self.length()) - #| array |> unsafe_to_bytes - #|} - #|test "View::strip_prefix" { - #| let view = "hello world"[:] - #| inspect(view.strip_prefix("hello "), content="Some(\"world\")") - #| inspect(view.strip_prefix("hi "), content="None") - #| inspect(view.strip_prefix("hello world"), content="Some(\"\")") - #| inspect(view.strip_prefix(""), content="Some(\"hello world\")") - #| let empty_view = ""[:] - #| inspect(empty_view.strip_prefix(""), content="Some(\"\")") - #| inspect(empty_view.strip_prefix("a"), content="None") - #| let unicode_view = "😀hello😃"[:] - #| inspect(unicode_view.strip_prefix("😀"), content="Some(\"hello😃\")") - #| inspect(unicode_view.strip_prefix("😃"), content="None") - #|} - #|test "View::strip_suffix" { - #| let view = "hello world"[:] - #| inspect(view.strip_suffix(" world"), content="Some(\"hello\")") - #| inspect(view.strip_suffix(" moon"), content="None") - #| inspect(view.strip_suffix("hello world"), content="Some(\"\")") - #| inspect(view.strip_suffix(""), content="Some(\"hello world\")") - #| let empty_view = ""[:] - #| inspect(empty_view.strip_suffix(""), content="Some(\"\")") - #| inspect(empty_view.strip_suffix("a"), content="None") - #| let unicode_view = "😀hello😃"[:] - #| inspect(unicode_view.strip_suffix("😃"), content="Some(\"😀hello\")") - #| inspect(unicode_view.strip_suffix("😀"), content="None") - #|} - #|test "View::to_array" { - #| let view = "Hello🤣"[:] - #| let chars = view.to_array() - #| assert_eq(chars, ['H', 'e', 'l', 'l', 'o', '🤣']) - #| let empty_view = ""[:] - #| let empty_chars = empty_view.to_array() - #| assert_eq(empty_chars, []) - #| let sub_view = "Hello World"[6:11] // "World" - #| let sub_chars = sub_view.to_array() - #| assert_eq(sub_chars, ['W', 'o', 'r', 'l', 'd']) - #|} - #|pub fn StringView::contains(self : StringView, str : StringView) -> Bool { - #| self.find(str) is Some(_) - #|} - #|pub fn String::contains(self : String, str : StringView) -> Bool { - #| self[:].contains(str) - #|} - #|pub fn StringView::contains_any(self : StringView, chars~ : StringView) -> Bool { - #| match chars { - #| [] => false - #| [c] => self.contains_char(c) // specialize for single character - #| _ => - #| for c in self { - #| if chars.contains_char(c) { - #| break true - #| } - #| } else { - #| false - #| } - #| } - #|} - #|pub fn String::contains_any(self : String, chars~ : StringView) -> Bool { - #| self[:].contains_any(chars~) - #|} - #|test "contains" { - #| inspect("hello".contains("o"), content="true") - #| inspect("hello".contains("l"), content="true") - #| inspect("hello".contains("hello"), content="true") - #| inspect("hello".contains("h"), content="true") - #| inspect("hello".contains(""), content="true") - #| inspect("hello".contains("world"), content="false") - #| inspect("".contains(""), content="true") - #| inspect("".contains("a"), content="false") - #| inspect("hello hello".contains("hello"), content="true") - #| inspect("aaa".contains("aa"), content="true") - #| inspect("😀😀".contains("😀"), content="true") - #|} - #|test "contains_any" { - #| inspect("hello".contains_any(chars="h"), content="true") - #| inspect("hello".contains_any(chars="xyz"), content="false") - #| inspect("hello".contains_any(chars=""), content="false") - #| inspect("".contains_any(chars="abc"), content="false") - #| inspect("😀😃".contains_any(chars="😄😀"), content="true") - #| inspect("hello"[:].contains_any(chars="eo"), content="true") - #|} - #|pub fn StringView::contains_char(self : StringView, c : Char) -> Bool { - #| let len = self.length() - #| guard len > 0 else { return false } - #| let c = c.to_int() - #| if c <= 0xFFFF { - #| for i in 0..= 2 else { return false } - #| let adj = c - 0x10000 - #| let high = 0xD800 + (adj >> 10) - #| let low = 0xDC00 + (adj & 0x3FF) - #| let mut i = 0 - #| while i < len - 1 { - #| if self.unsafe_charcode_at(i) == high { - #| i += 1 - #| if self.unsafe_charcode_at(i) == low { - #| return true - #| } - #| } - #| i += 1 - #| } - #| } - #| false - #|} - #|pub fn String::contains_char(self : String, c : Char) -> Bool { - #| self[:].contains_char(c) - #|} - #|test "contains_char" { - #| inspect("hello".contains_char('h'), content="true") - #| inspect("hello".contains_char('e'), content="true") - #| inspect("hello".contains_char('l'), content="true") - #| inspect("hello".contains_char('o'), content="true") - #| inspect("hello".contains_char('x'), content="false") - #| inspect("".contains_char('a'), content="false") - #| inspect("hello world".contains_char(' '), content="true") - #| inspect("hello world".contains_char('w'), content="true") - #| inspect("😀😀".contains_char('😀'), content="true") - #| inspect("😀😀".contains_char('😃'), content="false") - #| inspect("hello".contains_char((104).unsafe_to_char()), content="true") // 'h' is 104 in ASCII - #|} - #|#label_migration(chars, allow_positional=true) - #|#label_migration(chars, alias=char_set) - #|pub fn StringView::trim_start( - #| self : StringView, - #| chars~ : StringView, - #|) -> StringView { - #| loop self { - #| [] as v => v - #| [c, .. rest] as v => if chars.contains_char(c) { continue rest } else { v } - #| } - #|} - #|#label_migration(chars, alias=char_set) - #|pub fn String::trim_start( - #| self : String, - #| chars? : StringView = "\t\n\r ", - #|) -> StringView { - #| self[:].trim_start(chars~) - #|} - #|test "trim_start" { - #| inspect("hello".trim_start(chars="h"), content="ello") - #| inspect("hello".trim_start(chars="he"), content="llo") - #| inspect("hello".trim_start(chars="eh"), content="llo") - #| inspect("hello".trim_start(chars="x"), content="hello") - #| inspect("hello".trim_start(chars=""), content="hello") - #| inspect("".trim_start(chars="a"), content="") - #| inspect(" hello".trim_start(chars=" "), content="hello") - #| inspect("hello world".trim_start(chars="helo"), content=" world") - #| inspect("😀😀hello".trim_start(chars="😀"), content="hello") - #| inspect("😀😃hello".trim_start(chars="😀😃"), content="hello") - #| inspect("aaaabc".trim_start(chars="a"), content="bc") - #| inspect("aaaa".trim_start(chars="a"), content="") - #|} - #|#label_migration(chars, alias=char_set) - #|pub fn StringView::trim_end( - #| self : StringView, - #| chars? : StringView = "\t\n\r ", - #|) -> StringView { - #| loop self { - #| [] as v => v - #| [.. rest, c] as v => if chars.contains_char(c) { continue rest } else { v } - #| } - #|} - #|#label_migration(chars, alias=char_set) - #|pub fn String::trim_end( - #| self : String, - #| chars? : StringView = "\t\n\r ", - #|) -> StringView { - #| self[:].trim_end(chars~) - #|} - #|test "trim_end" { - #| inspect("hello".trim_end(chars="o"), content="hell") - #| inspect("hello".trim_end(chars="lo"), content="he") - #| inspect("hello".trim_end(chars="x"), content="hello") - #| inspect("hello".trim_end(chars=""), content="hello") - #| inspect("".trim_end(chars="a"), content="") - #| inspect("hello ".trim_end(chars=" "), content="hello") - #| inspect("hello world".trim_end(chars="dlrow "), content="he") - #| inspect("hello😀😀".trim_end(chars="😀"), content="hello") - #| inspect("hello😀😃".trim_end(chars="😀😃"), content="hello") - #| inspect("abcccc".trim_end(chars="c"), content="ab") - #| inspect("cccc".trim_end(chars="c"), content="") - #|} - #|#label_migration(chars, alias=char_set) - #|pub fn StringView::trim( - #| self : StringView, - #| chars? : StringView = "\t\n\r ", - #|) -> StringView { - #| self.trim_start(chars~).trim_end(chars~) - #|} - #|#label_migration(chars, alias=char_set) - #|pub fn String::trim( - #| self : String, - #| chars? : StringView = "\t\n\r ", - #|) -> StringView { - #| self[:].trim(chars~) - #|} - #|test "trim" { - #| inspect("hello".trim(chars="h"), content="ello") - #| inspect("hello".trim(chars="o"), content="hell") - #| inspect("hello".trim(chars="ho"), content="ell") - #| inspect("hello".trim(chars="oh"), content="ell") - #| inspect("hello".trim(chars="x"), content="hello") - #| inspect("hello".trim(chars=""), content="hello") - #| inspect("".trim(chars="a"), content="") - #| inspect(" hello ".trim(chars=" "), content="hello") - #| inspect("hello world".trim(chars="hd"), content="ello worl") - #| inspect("😀hello😀".trim(chars="😀"), content="hello") - #| inspect("😀😃hello😀😃".trim(chars="😀😃"), content="hello") - #| inspect("aaaabcaaa".trim(chars="a"), content="bc") - #| inspect("aaaa".trim(chars="a"), content="") - #| inspect(" hello world ".trim(chars=" "), content="hello world") - #| inspect("abcabc".trim(chars="abc"), content="") - #|} - #|#deprecated("Use `trim` with default whitespace characters instead") - #|pub fn StringView::trim_space(self : StringView) -> StringView { - #| self.trim() - #|} - #|#deprecated("Use `trim` with default whitespace characters instead") - #|pub fn String::trim_space(self : String) -> StringView { - #| self.trim() - #|} - #|test "trim whitespace for string" { - #| inspect("hello".trim(), content="hello") - #| inspect(" hello ".trim(), content="hello") - #| inspect("hello ".trim(), content="hello") - #| inspect(" hello".trim(), content="hello") - #| inspect("\t\nhello\r\n".trim(), content="hello") - #| inspect(" hello world ".trim(), content="hello world") - #| inspect(" ".trim(), content="") - #| inspect("\n\r\t".trim(), content="") - #| inspect("".trim(), content="") - #| inspect(" hello\nworld\t".trim(), content="hello\nworld") - #|} - #|pub fn StringView::is_empty(self : StringView) -> Bool { - #| self.length() == 0 - #|} - #|pub fn String::is_empty(self : String) -> Bool { - #| self == "" - #|} - #|test "is_empty" { - #| inspect("".is_empty(), content="true") - #| inspect("hello".is_empty(), content="false") - #| inspect(" ".is_empty(), content="false") - #| inspect("\n".is_empty(), content="false") - #| inspect("\t".is_empty(), content="false") - #| inspect(" ".is_empty(), content="false") - #| let s = "hello" - #| let empty_view = s[0:0] - #| let non_empty_view = s[0:3] - #| inspect(empty_view.is_empty(), content="true") - #| inspect(non_empty_view.is_empty(), content="false") - #|} - #|pub fn StringView::is_blank(self : StringView) -> Bool { - #| self.trim().is_empty() - #|} - #|pub fn String::is_blank(self : String) -> Bool { - #| self[:].is_blank() - #|} - #|test "is_blank" { - #| inspect("".is_blank(), content="true") - #| inspect("hello".is_blank(), content="false") - #| inspect(" ".is_blank(), content="true") - #| inspect("\n".is_blank(), content="true") - #| inspect("\t".is_blank(), content="true") - #| inspect(" ".is_blank(), content="true") - #| inspect(" \n\t\r ".is_blank(), content="true") - #| inspect("hello world".is_blank(), content="false") - #| inspect(" hello ".is_blank(), content="false") - #| let s = " hello " - #| let blank_view = s[0:3] // " " - #| let non_blank_view = s[3:8] // "hello" - #| inspect(blank_view.is_blank(), content="true") - #| inspect(non_blank_view.is_blank(), content="false") - #|} - #|pub fn StringView::pad_start( - #| self : StringView, - #| total_width : Int, - #| padding_char : Char, - #|) -> String { - #| let len = self.length() - #| guard len < total_width else { return self.to_string() } - #| let padding = String::make(total_width - len, padding_char) - #| [..padding, ..self] - #|} - #|pub fn String::pad_start( - #| self : String, - #| total_width : Int, - #| padding_char : Char, - #|) -> String { - #| let len = self.length() - #| guard len < total_width else { return self } - #| let padding = String::make(total_width - len, padding_char) - #| [..padding, ..self] - #|} - #|test "pad_start" { - #| inspect("2".pad_start(3, '0'), content="002") - #| inspect("abc".pad_start(5, 'x'), content="xxabc") - #| inspect("hello".pad_start(4, ' '), content="hello") // No padding needed - #| inspect("".pad_start(3, '-'), content="---") - #| inspect("test".pad_start(8, '*'), content="****test") - #| inspect("123".pad_start(6, '0'), content="000123") - #| let s = "hello" - #| let view = s[2:5] // "llo" - #| inspect(view.pad_start(5, 'x'), content="xxllo") - #| inspect("🌟".pad_start(3, '✨'), content="✨🌟") - #| inspect("abc".pad_start(0, 'x'), content="abc") // width less than string length - #| inspect("abc".pad_start(3, 'x'), content="abc") // width equal to string length - #|} - #|pub fn StringView::pad_end( - #| self : StringView, - #| total_width : Int, - #| padding_char : Char, - #|) -> String { - #| let len = self.length() - #| guard len < total_width else { return self.to_string() } - #| let padding = String::make(total_width - len, padding_char) - #| [..self, ..padding] - #|} - #|pub fn String::pad_end( - #| self : String, - #| total_width : Int, - #| padding_char : Char, - #|) -> String { - #| let len = self.length() - #| guard len < total_width else { return self } - #| let padding = String::make(total_width - len, padding_char) - #| [..self, ..padding] - #|} - #|test "pad_end" { - #| inspect("2".pad_end(3, '0'), content="200") - #| inspect("abc".pad_end(5, 'x'), content="abcxx") - #| inspect("hello".pad_end(4, ' '), content="hello") // No padding needed - #| inspect("".pad_end(3, '-'), content="---") - #| inspect("test".pad_end(8, '*'), content="test****") - #| inspect("123".pad_end(6, '0'), content="123000") - #| let s = "hello" - #| let view = s[2:5] // "llo" - #| inspect(view.pad_end(5, 'x'), content="lloxx") - #| inspect("🌟".pad_end(3, '✨'), content="🌟✨") - #| inspect("abc".pad_end(0, 'x'), content="abc") // width less than string length - #| inspect("abc".pad_end(3, 'x'), content="abc") // width equal to string length - #|} - #|pub fn StringView::repeat(self : StringView, n : Int) -> StringView { - #| match n { - #| _..=0 => "" - #| 1 => self - #| _ => { - #| let len = self.length() - #| let buf = StringBuilder::new(size_hint=len * n) - #| let str = self.to_string() - #| for _ in 0.. String { - #| match n { - #| _..=0 => "" - #| 1 => self - #| _ => { - #| let len = self.length() - #| let buf = StringBuilder::new(size_hint=len * n) - #| let str = self.to_string() - #| for _ in 0.. String { - #| let buf = StringBuilder::new(size_hint=self.length()) - #| for c in self.rev_iter() { - #| buf.write_char(c) - #| } - #| buf.to_string() - #|} - #|pub fn String::rev(self : String) -> String { - #| self[:].rev() - #|} - #|test "rev" { - #| inspect("hello".rev(), content="olleh") - #| inspect("".rev(), content="") - #| inspect("abc".rev(), content="cba") - #| inspect("😀😃".rev(), content="😃😀") - #|} - #|pub fn StringView::split( - #| self : StringView, - #| sep : StringView, - #|) -> Iter[StringView] { - #| let sep_len = sep.length() - #| if sep_len == 0 { - #| return self.iter().map(c => c.to_string().view()) - #| } - #| let mut remaining = Some(self) - #| Iterator::new(() => { - #| guard remaining is Some(view) else { None } - #| guard view.find(sep) is Some(end) else { - #| remaining = None - #| Some(view) - #| } - #| remaining = Some(view.view(start_offset=end + sep_len)) - #| Some(view.view(end_offset=end)) - #| }).iter() - #|} - #|pub fn String::split(self : String, sep : StringView) -> Iter[StringView] { - #| self[:].split(sep) - #|} - #|test "split" { - #| assert_eq("a,b,c".split(",").map(StringView::to_string).collect(), [ - #| "a", "b", "c", - #| ]) - #| assert_eq("a,b,c".split("").map(StringView::to_string).collect(), [ - #| "a", ",", "b", ",", "c", - #| ]) - #| assert_eq( - #| "apple::orange::banana".split("::").map(StringView::to_string).collect(), - #| ["apple", "orange", "banana"], - #| ) - #| assert_eq("abc".split("").map(StringView::to_string).collect(), [ - #| "a", "b", "c", - #| ]) - #| assert_eq("hello".split(",").map(StringView::to_string).collect(), ["hello"]) - #| assert_eq(",a,b,c".split(",").map(StringView::to_string).collect(), [ - #| "", "a", "b", "c", - #| ]) - #| assert_eq("a,b,c,".split(",").map(StringView::to_string).collect(), [ - #| "a", "b", "c", "", - #| ]) - #| assert_eq("a,b,c".split("").map(StringView::to_string).collect(), [ - #| "a", ",", "b", ",", "c", - #| ]) - #| assert_eq("".split("").map(StringView::to_string).collect(), []) - #| assert_eq("".split(",").map(StringView::to_string).collect(), [""]) - #| assert_eq("😀,😃,😄".split(",").map(StringView::to_string).collect(), [ - #| "😀", "😃", "😄", - #| ]) - #| assert_eq("a😀b😀c".split("😀").map(StringView::to_string).collect(), [ - #| "a", "b", "c", - #| ]) - #|} - #|pub fn StringView::replace( - #| self : StringView, - #| old~ : StringView, - #| new~ : StringView, - #|) -> StringView { - #| match self.find(old) { - #| Some(end) => - #| [ - #| ..self.view(end_offset=end), - #| ..new, - #| ..self.view(start_offset=end + old.length()), - #| ] - #| None => self - #| } - #|} - #|pub fn String::replace( - #| self : String, - #| old~ : StringView, - #| new~ : StringView, - #|) -> String { - #| match self.find(old) { - #| Some(end) => - #| [ - #| ..self.view(end_offset=end), - #| ..new, - #| ..self.view(start_offset=end + old.length()), - #| ] - #| None => self - #| } - #|} - #|test "replace" { - #| inspect("hello".replace(old="o", new="a"), content="hella") - #| inspect("hello".replace(old="l", new="a"), content="healo") - #| inspect("hello".replace(old="hello", new="a"), content="a") - #| inspect("hello".replace(old="h", new="a"), content="aello") - #| inspect("hello".replace(old="", new="a"), content="ahello") - #| inspect("hello".replace(old="world", new="a"), content="hello") - #| inspect("".replace(old="", new="a"), content="a") - #|} - #|pub fn StringView::replace_all( - #| self : StringView, - #| old~ : StringView, - #| new~ : StringView, - #|) -> StringView { - #| let len = self.length() - #| let buf = StringBuilder::new(size_hint=len) - #| let old_len = old.length() - #| let new = new.to_string() - #| if old_len == 0 { - #| buf.write_string(new) - #| for c in self { - #| buf.write_char(c) - #| buf.write_string(new) - #| } - #| buf.to_string() - #| } else { - #| let first_end = self.find(old) - #| if first_end is Some(end) { - #| for view = self, end = end { - #| let seg = view.view(end_offset=end) - #| buf.write_substring(seg.data(), seg.start_offset(), seg.length()) - #| buf.write_string(new) - #| guard end + old_len <= len else { break } - #| let next_view = view.view(start_offset=end + old_len) - #| guard next_view.find(old) is Some(next_end) else { - #| buf.write_substring( - #| next_view.data(), - #| next_view.start_offset(), - #| next_view.length(), - #| ) - #| break - #| } - #| continue next_view, next_end - #| } - #| buf.to_string() - #| } else { - #| self - #| } - #| } - #|} - #|pub fn String::replace_all( - #| self : String, - #| old~ : StringView, - #| new~ : StringView, - #|) -> String { - #| let len = self.length() - #| let buf = StringBuilder::new(size_hint=len) - #| let old_len = old.length() - #| let new = new.to_string() - #| if old_len == 0 { - #| buf.write_string(new) - #| for c in self { - #| buf.write_char(c) - #| buf.write_string(new) - #| } - #| buf.to_string() - #| } else { - #| let first_end = self.find(old) - #| if first_end is Some(end) { - #| for view = self[:], end = end { - #| let seg = view.view(end_offset=end) - #| buf.write_substring(seg.data(), seg.start_offset(), seg.length()) - #| buf.write_string(new) - #| guard end + old_len <= len else { break } - #| let next_view = view.view(start_offset=end + old_len) - #| guard next_view.find(old) is Some(next_end) else { - #| buf.write_substring( - #| next_view.data(), - #| next_view.start_offset(), - #| next_view.length(), - #| ) - #| break - #| } - #| continue next_view, next_end - #| } - #| buf.to_string() - #| } else { - #| self - #| } - #| } - #|} - #|test "replace_all" { - #| assert_eq("hello".replace_all(old="o", new="a"), "hella") - #| assert_eq("hello".replace_all(old="l", new="a"), "heaao") - #| assert_eq("hello".replace_all(old="ll", new="rr"), "herro") - #| assert_eq("hello".replace_all(old="hello", new="world"), "world") - #| assert_eq("hello hello hello".replace_all(old="hello", new="hi"), "hi hi hi") - #| assert_eq( - #| "hello hello helloi".replace_all(old="hello", new="hi"), - #| "hi hi hii", - #| ) - #| assert_eq( - #| "hi hi hii".replace_all(old="hi", new="hello"), - #| "hello hello helloi", - #| ) - #| assert_eq("hello".replace_all(old="", new="a"), "ahaealalaoa") - #| assert_eq("hello".replace_all(old="world", new="a"), "hello") - #| assert_eq("".replace_all(old="", new="a"), "a") - #| assert_eq("aaa".replace_all(old="a", new="b"), "bbb") - #| assert_eq("aaa".replace_all(old="a", new="bb"), "bbbbbb") - #| assert_eq("aaa".replace_all(old="aa", new="b"), "ba") - #| assert_eq("🤣🤣🤣".replace_all(old="🤣", new="😊"), "😊😊😊") - #| assert_eq("abc123abc".replace_all(old="abc", new="xyz"), "xyz123xyz") - #| assert_eq("abcabcabc".replace_all(old="abc", new=""), "") - #| assert_eq("abc".replace_all(old="abc", new=""), "") - #| assert_eq("abc".replace_all(old="", new="x"), "xaxbxcx") - #|} - #|test "String::replace_all boundary cases" { - #| assert_eq("helloworld".replace_all(old="world", new="X"), "helloX") - #| assert_eq("abcdef".replace_all(old="def", new="XYZ"), "abcXYZ") - #| assert_eq("abcabc".replace_all(old="abc", new="X"), "XX") - #| assert_eq("test".replace_all(old="test", new="done"), "done") - #| assert_eq("remove_me".replace_all(old="_me", new=""), "remove") - #|} - #|test "View::replace_all" { - #| assert_eq("hello"[:].replace_all(old="o", new="a"), "hella") - #| assert_eq("hello"[:].replace_all(old="l", new="a"), "heaao") - #| assert_eq("hello"[:].replace_all(old="ll", new="rr"), "herro") - #| assert_eq("hello"[:].replace_all(old="hello", new="world"), "world") - #| assert_eq( - #| "hello hello hello"[:].replace_all(old="hello", new="hi"), - #| "hi hi hi", - #| ) - #| assert_eq( - #| "hello hello helloi"[:].replace_all(old="hello", new="hi"), - #| "hi hi hii", - #| ) - #| assert_eq( - #| "hi hi hii"[:].replace_all(old="hi", new="hello"), - #| "hello hello helloi", - #| ) - #| assert_eq("hello"[:].replace_all(old="", new="a"), "ahaealalaoa") - #| assert_eq("hello"[:].replace_all(old="world", new="a"), "hello") - #| assert_eq(""[:].replace_all(old="", new="a"), "a") - #| assert_eq("aaa"[:].replace_all(old="a", new="b"), "bbb") - #| assert_eq("aaa"[:].replace_all(old="a", new="bb"), "bbbbbb") - #| assert_eq("aaa"[:].replace_all(old="aa", new="b"), "ba") - #| assert_eq( - #| "🤣🤣🤣"[:].replace_all(old="🤣", new="😊"), - #| "😊😊😊", - #| ) - #| assert_eq("abc123abc"[:].replace_all(old="abc", new="xyz"), "xyz123xyz") - #| assert_eq("abcabcabc"[:].replace_all(old="abc", new=""), "") - #| assert_eq("abc"[:].replace_all(old="abc", new=""), "") - #| assert_eq("abc"[:].replace_all(old="", new="x"), "xaxbxcx") - #|} - #|test "View::replace_all boundary cases" { - #| assert_eq("abcabc"[:].replace_all(old="abc", new="X"), "XX") - #| assert_eq("aaaa"[:].replace_all(old="aa", new="b"), "bb") - #| assert_eq("hello"[:].replace_all(old="lo", new="X"), "helX") - #| assert_eq("a"[:].replace_all(old="a", new=""), "") - #| inspect("Testing boundary condition", content="Testing boundary condition") - #|} - #|pub fn StringView::to_lower(self : StringView) -> StringView { - #| guard self.find_by(x => x.is_ascii_uppercase()) is Some(idx) else { - #| return self - #| } - #| let buf = StringBuilder::new(size_hint=self.length()) - #| let head = self.view(end_offset=idx) - #| buf.write_substring(head.data(), head.start_offset(), head.length()) - #| for c in self.view(start_offset=idx) { - #| if c.is_ascii_uppercase() { - #| buf.write_char((c.to_int() + 32).unsafe_to_char()) - #| } else { - #| buf.write_char(c) - #| } - #| } - #| buf.to_string() - #|} - #|pub fn String::to_lower(self : String) -> String { - #| guard self.find_by(x => x.is_ascii_uppercase()) is Some(idx) else { - #| return self - #| } - #| let buf = StringBuilder::new(size_hint=self.length()) - #| let head = self.view(end_offset=idx) - #| buf.write_substring(head.data(), head.start_offset(), head.length()) - #| for c in self.view(start_offset=idx) { - #| if c.is_ascii_uppercase() { - #| buf.write_char((c.to_int() + 32).unsafe_to_char()) - #| } else { - #| buf.write_char(c) - #| } - #| } - #| buf.to_string() - #|} - #|test "to_lower" { - #| assert_eq("Hello".to_lower(), "hello") - #| assert_eq("HELLO".to_lower(), "hello") - #| assert_eq("Hello, World!".to_lower(), "hello, world!") - #|} - #|test "View::to_lower" { - #| assert_eq("Hello"[:].to_lower(), "hello") - #| assert_eq("HELLO"[:].to_lower(), "hello") - #| assert_eq("Hello, World!"[:].to_lower(), "hello, world!") - #|} - #|pub fn StringView::to_upper(self : StringView) -> StringView { - #| guard self.find_by(_.is_ascii_lowercase()) is Some(idx) else { return self } - #| let buf = StringBuilder::new(size_hint=self.length()) - #| let head = self.view(end_offset=idx) - #| buf.write_substring(head.data(), head.start_offset(), head.length()) - #| for c in self.view(start_offset=idx) { - #| if c.is_ascii_lowercase() { - #| buf.write_char((c.to_int() - 32).unsafe_to_char()) - #| } else { - #| buf.write_char(c) - #| } - #| } - #| buf.to_string() - #|} - #|pub fn String::to_upper(self : String) -> String { - #| guard self.find_by(_.is_ascii_lowercase()) is Some(idx) else { return self } - #| let buf = StringBuilder::new(size_hint=self.length()) - #| let head = self.view(end_offset=idx) - #| buf.write_substring(head.data(), head.start_offset(), head.length()) - #| for c in self.view(start_offset=idx) { - #| if c.is_ascii_lowercase() { - #| buf.write_char((c.to_int() - 32).unsafe_to_char()) - #| } else { - #| buf.write_char(c) - #| } - #| } - #| buf.to_string() - #|} - #|test "to_upper" { - #| assert_eq("hello".to_upper(), "HELLO") - #| assert_eq("HELLO".to_upper(), "HELLO") - #| assert_eq("Hello, World!".to_upper(), "HELLO, WORLD!") - #|} - #|test "View::to_upper" { - #| assert_eq("hello"[:].to_upper(), "HELLO") - #| assert_eq("HELLO"[:].to_upper(), "HELLO") - #| assert_eq("Hello, World!"[:].to_upper(), "HELLO, WORLD!") - #|} - #|pub fn[A] StringView::fold( - #| self : StringView, - #| init~ : A, - #| f : (A, Char) -> A raise?, - #|) -> A raise? { - #| let mut rv = init - #| for c in self { - #| rv = f(rv, c) - #| } - #| rv - #|} - #|pub fn[A] String::fold( - #| self : String, - #| init~ : A, - #| f : (A, Char) -> A raise?, - #|) -> A raise? { - #| self[:].fold(init~, f) - #|} - #|test "fold" { - #| assert_eq( - #| "hello".fold(init=[], (acc, c) => { - #| acc.push(c) - #| acc - #| }), - #| ['h', 'e', 'l', 'l', 'o'], - #| ) - #| assert_eq( - #| "hello".fold(init=0, (acc, c) => acc + c.to_int()), - #| 104 + 101 + 108 + 108 + 111, - #| ) - #|} - #|test "fold with raise" { - #| let result = try? "hello".fold(init=0, (acc, c) => { - #| if c == 'l' { - #| raise Failure("found l") - #| } - #| acc + 1 - #| }) - #| inspect(result, content="Err(Failure(\"found l\"))") - #|} - #|pub fn[A] StringView::rev_fold( - #| self : StringView, - #| init~ : A, - #| f : (A, Char) -> A raise?, - #|) -> A raise? { - #| let mut rv = init - #| for c in self.rev_iter() { - #| rv = f(rv, c) - #| } - #| rv - #|} - #|pub fn[A] String::rev_fold( - #| self : String, - #| init~ : A, - #| f : (A, Char) -> A raise?, - #|) -> A raise? { - #| self[:].rev_fold(init~, f) - #|} - #|test "rev_fold" { - #| assert_eq( - #| "hello".rev_fold(init=[], (acc, c) => { - #| acc.push(c) - #| acc - #| }), - #| ['o', 'l', 'l', 'e', 'h'], - #| ) - #| assert_eq( - #| "hello".rev_fold(init=0, (acc, c) => acc + c.to_int()), - #| 111 + 108 + 108 + 101 + 104, - #| ) - #|} - #|test "rev_fold with raise" { - #| let result = try? "hello".rev_fold(init=0, (acc, c) => { - #| if c == 'l' { - #| raise Failure("found l") - #| } - #| acc + 1 - #| }) - #| inspect(result, content="Err(Failure(\"found l\"))") - #|} - #|#deprecated("The return type is about to change to `UInt16?` in a future release. Please check boundaries manually and use `String::code_unit_at` instead.", skip_current_package=true) - #|pub fn String::get(self : String, idx : Int) -> Int? { - #| guard idx >= 0 && idx < self.length() else { return None } - #| Some(self.unsafe_charcode_at(idx)) - #|} - #|#deprecated("The return type is about to change to `UInt16?` in a future release. Please check boundaries manually and use `StringView::code_unit_at` instead.", skip_current_package=true) - #|pub fn StringView::get(self : StringView, idx : Int) -> Int? { - #| guard idx >= 0 && idx < self.length() else { return None } - #| Some(self.unsafe_charcode_at(idx)) - #|} - #|test "String::get supports emoji (surrogate pair)" { - #| let s = "hello" - #| inspect(s.get(0), content="Some(104)") - #| inspect(s.get(4), content="Some(111)") - #| inspect(s.get(5), content="None") - #| inspect(s.get(-1), content="None") - #| let s = "a🤣b" - #| inspect(s.get(0), content="Some(97)") - #| inspect(s.get(1), content="Some(55358)") - #| inspect(s.get(2), content="Some(56611)") - #| inspect(s.get(3), content="Some(98)") - #| inspect(s.get(4), content="None") - #|} - #|test "View::get basic cases" { - #| let v = "hello"[1:-1] - #| inspect(v.get(0), content="Some(101)") - #| inspect(v.get(2), content="Some(108)") - #| inspect(v.get(3), content="None") - #| inspect(v.get(-1), content="None") - #| let v = "ab🤣cd"[1:-1] - #| inspect(v.get(0), content="Some(98)") - #| inspect(v.get(1), content="Some(55358)") - #| inspect(v.get(2), content="Some(56611)") - #|} - #|pub fn String::get_char(self : String, idx : Int) -> Char? { - #| guard idx >= 0 && idx < self.length() else { return None } - #| let c = self.unsafe_charcode_at(idx) - #| if c.is_leading_surrogate() { - #| guard idx + 1 < self.length() else { return None } - #| let next = self.unsafe_charcode_at(idx + 1) - #| if next.is_trailing_surrogate() { - #| Some(code_point_of_surrogate_pair(c, next)) - #| } else { - #| None - #| } - #| } else if c.is_trailing_surrogate() { - #| None - #| } else { - #| Some(c.unsafe_to_char()) - #| } - #|} - #|pub fn StringView::get_char(self : StringView, idx : Int) -> Char? { - #| guard idx >= 0 && idx < self.length() else { return None } - #| let c = self.unsafe_charcode_at(idx) - #| if c.is_leading_surrogate() { - #| guard idx + 1 < self.length() else { return None } - #| let next = self.unsafe_charcode_at(idx + 1) - #| if next.is_trailing_surrogate() { - #| Some(code_point_of_surrogate_pair(c, next)) - #| } else { - #| None - #| } - #| } else if c.is_trailing_surrogate() { - #| None - #| } else { - #| Some(c.unsafe_to_char()) - #| } - #|} - #|test "String::get_char basic cases" { - #| let s = "hello" - #| inspect(s.get_char(0), content="Some('h')") - #| inspect(s.get_char(1), content="Some('e')") - #| inspect(s.get_char(4), content="Some('o')") - #| inspect(s.get_char(5), content="None") - #| inspect(s.get_char(-1), content="None") - #| let s = "a🤣b" - #| inspect(s.get_char(0), content="Some('a')") - #| inspect(s.get_char(1), content="Some('🤣')") - #| inspect(s.get_char(2), content="None") // Second half of surrogate pair is not a valid char - #| inspect(s.get_char(3), content="Some('b')") - #| inspect(s.get_char(4), content="None") - #|} - #|test "View::get_char basic cases" { - #| let s = "a🤣b" - #| let v = s[0:-1] - #| inspect(v.get_char(0), content="Some('a')") - #| inspect(v.get_char(1), content="Some('🤣')") - #| inspect(v.get_char(2), content="None") - #| inspect(v.get_char(3), content="None") - #| inspect(v.get_char(4), content="None") - #| let v2 = s[1:3] // Only contains the emoji surrogate pair - #| inspect(v2.get_char(0), content="Some('🤣')") - #| inspect(v2.get_char(1), content="None") - #| inspect(v2.get_char(2), content="None") - #|} - ), - "stringbuilder.mbt": ( - #|pub fn[T : Show] StringBuilder::write_object( - #| self : StringBuilder, - #| obj : T, - #|) -> Unit { - #| obj.output(self) - #|} - #|pub fn StringBuilder::write_iter( - #| self : StringBuilder, - #| iter : Iter[Char], - #|) -> Unit { - #| for ch in iter { - #| self.write_char(ch) - #| } - #|} - #|pub fn StringBuilder::write_stringview( - #| self : StringBuilder, - #| view : StringView, - #|) -> Unit { - #| let start = view.start() - #| let end = view.end() - #| self.write_substring(view.str(), start, end - start) - #|} - ), - "stringbuilder_buffer.mbt": ( - #|struct StringBuilder { - #| mut data : FixedArray[Byte] - #| mut len : Int - #|} - #|pub fn StringBuilder::new(size_hint? : Int = 0) -> StringBuilder { - #| let initial = if size_hint < 1 { 1 } else { size_hint } - #| let data : FixedArray[Byte] = FixedArray::make(initial, 0) - #| { data, len: 0 } - #|} - #|pub fn StringBuilder::is_empty(self : StringBuilder) -> Bool { - #| self.len == 0 - #|} - #|fn StringBuilder::grow_if_necessary( - #| self : StringBuilder, - #| required : Int, - #|) -> Unit { - #| let current_len = self.data.length() - #| if required <= current_len { - #| return - #| } - #| let mut enough_space = current_len - #| while enough_space < required { - #| enough_space = enough_space * 2 - #| } - #| let new_data = FixedArray::make(enough_space, Byte::default()) - #| new_data.unsafe_blit(0, self.data, 0, self.len) - #| self.data = new_data - #|} - #|pub impl Logger for StringBuilder with write_string(self, str) { - #| self.grow_if_necessary(self.len + str.length() * 2) - #| self.data.blit_from_string(self.len, str, 0, str.length()) - #| self.len += str.length() * 2 - #|} - #|pub impl Logger for StringBuilder with write_char(self, ch) { - #| self.grow_if_necessary(self.len + 4) - #| let inc = self.data.set_utf16le_char(self.len, ch) - #| self.len += inc - #|} - #|pub impl Logger for StringBuilder with write_view( - #| self : StringBuilder, - #| str : StringView, - #|) -> Unit { - #| self.grow_if_necessary(self.len + str.length() * 2) - #| self.data.blit_from_string( - #| self.len, - #| str.data(), - #| str.start_offset(), - #| str.length(), - #| ) - #| self.len += str.length() * 2 - #|} - #|pub fn StringBuilder::to_string(self : StringBuilder) -> String { - #| self.data - #| .unsafe_reinterpret_as_bytes() - #| .to_unchecked_string(offset=0, length=self.len) - #|} - #|pub impl Show for StringBuilder with output(self, logger) { - #| logger.write_string( - #| self.data - #| .unsafe_reinterpret_as_bytes() - #| .to_unchecked_string(offset=0, length=self.len), - #| ) - #|} - #|pub fn StringBuilder::reset(self : StringBuilder) -> Unit { - #| self.len = 0 - #|} - ), - "stringbuilder_concat.mbt": ( - #|struct StringBuilder(Ref[String]) - #|pub fn StringBuilder::new(size_hint? : Int = 0) -> StringBuilder { - #| ignore(size_hint) - #| { val: "" } - #|} - #|pub fn StringBuilder::is_empty(self : StringBuilder) -> Bool { - #| self.val == "" - #|} - #|pub impl Logger for StringBuilder with write_string(self, str) { - #| self.val += str - #|} - #|pub impl Logger for StringBuilder with write_char(self, ch) { - #| self.val += char_to_string(ch) - #|} - #|pub impl Logger for StringBuilder with write_view( - #| self : StringBuilder, - #| str : StringView, - #|) -> Unit { - #| self.val += str.to_string() - #|} - #|pub impl Show for StringBuilder with output(self, logger) { - #| logger.write_string(self.val) - #|} - #|pub fn StringBuilder::to_string(self : StringBuilder) -> String { - #| self.val - #|} - #|pub fn StringBuilder::reset(self : StringBuilder) -> Unit { - #| self.val = "" - #|} - ), - "stringview.mbt": ( - #|fn StringView::str(self : StringView) -> String = "%stringview.str" - #|fn StringView::start(self : StringView) -> Int = "%stringview.start" - #|fn StringView::end(self : StringView) -> Int = "%stringview.end" - #|fn StringView::make_view(str : String, start : Int, end : Int) -> StringView = "%stringview.make" - #|#alias("_[_]") - #|#alias(code_unit_at) - #|pub fn StringView::at(self : StringView, index : Int) -> UInt16 { - #| guard index >= 0 && index < self.length() else { - #| abort("Index out of bounds") - #| } - #| self.str().code_unit_at(self.start() + index) - #|} - #|pub fn StringView::length(self : StringView) -> Int { - #| self.end() - self.start() - #|} - #|pub fn StringView::suffixes( - #| self : StringView, - #| include_empty? : Bool = false, - #|) -> Iterator[StringView] { - #| let str = self.str() - #| let end = self.end() - #| let mut next_start = self.start() - #| let mut finished = false - #| Iterator::new(fn() -> StringView? { - #| if finished { - #| None - #| } else if next_start == end { - #| finished = true - #| if include_empty { - #| Some(StringView::make_view(str, next_start, end)) - #| } else { - #| None - #| } - #| } else { - #| let suffix = StringView::make_view(str, next_start, end) - #| let code = str.unsafe_charcode_at(next_start) - #| if code.is_leading_surrogate() && - #| next_start + 1 < end && - #| str.unsafe_charcode_at(next_start + 1).is_trailing_surrogate() { - #| next_start += 2 - #| } else { - #| next_start += 1 - #| } - #| Some(suffix) - #| } - #| }) - #|} - #|pub fn StringView::data(self : StringView) -> String { - #| self.str() - #|} - #|pub fn StringView::start_offset(self : StringView) -> Int { - #| self.start() - #|} - #|pub fn StringView::view( - #| self : StringView, - #| start_offset? : Int = 0, - #| end_offset? : Int, - #|) -> StringView { - #| let end_offset = if end_offset is Some(o) { o } else { self.length() } - #| guard start_offset >= 0 && - #| start_offset <= end_offset && - #| end_offset <= self.length() else { - #| abort("Invalid index for View") - #| } - #| StringView::make_view( - #| self.str(), - #| self.start() + start_offset, - #| self.start() + end_offset, - #| ) - #|} - #|pub fn StringView::unsafe_charcode_at(self : StringView, index : Int) -> Int { - #| self.str().unsafe_charcode_at(self.start() + index) - #|} - #|pub fn StringView::char_length(self : StringView) -> Int { - #| self.str().char_length(start_offset=self.start(), end_offset=self.end()) - #|} - #|pub impl Show for StringView with output(self, logger) { - #| let substr = self.str().unsafe_substring(start=self.start(), end=self.end()) - #| String::output(substr, logger) - #|} - #|pub impl Show for StringView with to_string(self) { - #| self.str().unsafe_substring(start=self.start(), end=self.end()) - #|} - #|pub fn StringView::iter(self : StringView) -> Iter[Char] { - #| self.iterator().iter() - #|} - #|pub fn StringView::iterator(self : StringView) -> Iterator[Char] { - #| let start = self.start() - #| let end = self.end() - #| let mut index = start - #| Iterator::new(fn() { - #| guard index < end else { None } - #| let c1 = self.str().unsafe_charcode_at(index) - #| if c1.is_leading_surrogate() && index + 1 < self.end() { - #| let c2 = self.str().unsafe_charcode_at(index + 1) - #| if c2.is_trailing_surrogate() { - #| index += 2 - #| return Some(code_point_of_surrogate_pair(c1, c2)) - #| } - #| } - #| index += 1 - #| Some(c1.unsafe_to_char()) - #| }) - #|} - #|pub fn StringView::iter2(self : StringView) -> Iter2[Int, Char] { - #| self.Iter2().iter2() - #|} - #|pub fn StringView::Iter2(self : StringView) -> Iter2[Int, Char] { - #| let start = self.start() - #| let end = self.end() - #| let mut index = start - #| let mut char_index = 0 - #| Iter2::new(fn() { - #| guard index < end else { None } - #| let c1 = self.str().unsafe_charcode_at(index) - #| if c1.is_leading_surrogate() && index + 1 < self.end() { - #| let c2 = self.str().unsafe_charcode_at(index + 1) - #| if c2.is_trailing_surrogate() { - #| let result = (char_index, code_point_of_surrogate_pair(c1, c2)) - #| index += 2 - #| char_index += 1 - #| return Some(result) - #| } - #| } - #| let result = (char_index, c1.unsafe_to_char()) - #| index += 1 - #| char_index += 1 - #| Some(result) - #| }) - #|} - #|pub fn StringView::rev_iter(self : StringView) -> Iter[Char] { - #| self.rev_iterator().iter() - #|} - #|pub fn StringView::rev_iterator(self : StringView) -> Iterator[Char] { - #| let start = self.start() - #| let end = self.end() - #| let mut index = end - #| Iterator::new(fn() { - #| guard index > start else { None } - #| index -= 1 - #| let c1 = self.str().unsafe_charcode_at(index) - #| if c1.is_trailing_surrogate() && index - 1 >= 0 { - #| let c2 = self.str().unsafe_charcode_at(index - 1) - #| if c2.is_leading_surrogate() { - #| index -= 1 - #| return Some(code_point_of_surrogate_pair(c2, c1)) - #| } - #| } - #| Some(c1.unsafe_to_char()) - #| }) - #|} - #|pub impl Eq for StringView with equal(self, other) { - #| let len = self.length() - #| guard len == other.length() else { return false } - #| if physical_equal(self.str(), other.str()) && self.start() == other.start() { - #| return true - #| } - #| for i in 0.. Int { - #| let self_len = self.length() - #| let other_len = other.length() - #| let min_len = if self_len < other_len { self_len } else { other_len } - #| for i in 0.. StringView { - #| let end_offset = if end_offset is Some(o) { o } else { self.length() } - #| guard start_offset >= 0 && - #| start_offset <= end_offset && - #| end_offset <= self.length() else { - #| abort("Invalid index for View") - #| } - #| StringView::make_view(self, start_offset, end_offset) - #|} - #|pub fn StringView::from_array(chars : ArrayView[Char]) -> StringView { - #| String::from_array(chars) - #|} - #|pub fn StringView::from_iter(iter : Iter[Char]) -> StringView { - #| String::from_iter(iter) - #|} - #|pub fn StringView::from_iterator(iter : Iterator[Char]) -> StringView { - #| String::from_iterator(iter) - #|} - #|pub suberror CreatingViewError { - #| IndexOutOfBounds - #| InvalidIndex - #|} derive(Show) - #|#alias("_[_:_]") - #|pub fn String::sub( - #| self : String, - #| start? : Int = 0, - #| end? : Int, - #|) -> StringView raise CreatingViewError { - #| let len = self.length() - #| let end = match end { - #| None => len - #| Some(end) => if end < 0 { len + end } else { end } - #| } - #| let start = if start < 0 { len + start } else { start } - #| guard start >= 0 && start <= end && end <= len else { raise IndexOutOfBounds } - #| if start < len && self.unsafe_charcode_at(start).is_trailing_surrogate() { - #| raise InvalidIndex - #| } - #| if end < len && self.unsafe_charcode_at(end).is_trailing_surrogate() { - #| raise InvalidIndex - #| } - #| StringView::make_view(self, start, end) - #|} - #|#alias("_[_:_]") - #|pub fn StringView::sub( - #| self : StringView, - #| start? : Int = 0, - #| end? : Int, - #|) -> StringView raise CreatingViewError { - #| let str_len = self.str().length() - #| let abs_end = match end { - #| None => self.end() - #| Some(end) => if end < 0 { self.end() + end } else { self.start() + end } - #| } - #| let abs_start = if start < 0 { - #| self.end() + start - #| } else { - #| self.start() + start - #| } - #| guard abs_start >= self.start() && - #| abs_start <= abs_end && - #| abs_end <= self.end() else { - #| raise IndexOutOfBounds - #| } - #| if abs_start < str_len && - #| self.str().unsafe_charcode_at(abs_start).is_trailing_surrogate() { - #| raise InvalidIndex - #| } - #| if abs_end < str_len && - #| self.str().unsafe_charcode_at(abs_end).is_trailing_surrogate() { - #| raise InvalidIndex - #| } - #| StringView::make_view(self.str(), abs_start, abs_end) - #|} - #|pub fn StringView::char_length_eq(self : StringView, len : Int) -> Bool { - #| self - #| .str() - #| .char_length_eq(len, start_offset=self.start(), end_offset=self.end()) - #|} - #|pub fn StringView::char_length_ge(self : StringView, len : Int) -> Bool { - #| self - #| .str() - #| .char_length_ge(len, start_offset=self.start(), end_offset=self.end()) - #|} - #|pub fn StringView::offset_of_nth_char(self : StringView, i : Int) -> Int? { - #| if self - #| .str() - #| .offset_of_nth_char(i, start_offset=self.start(), end_offset=self.end()) - #| is Some(index) { - #| Some(index - self.start()) - #| } else { - #| None - #| } - #|} - #|pub impl Default for StringView with default() { - #| "" - #|} - #|pub fn StringView::make(length : Int, value : Char) -> StringView { - #| String::make(length, value) - #|} - #|pub impl ToJson for StringView with to_json(self) { - #| String::to_json(self.to_string()) - #|} - #|pub impl Add for StringView with add(self, other) { - #| [..self, ..other] - #|} - ), - "to_string.mbt": ( - #|#cfg(not(target="js")) - #|const ALPHABET : String = "0123456789abcdefghijklmnopqrstuvwxyz" - #|#cfg(not(target="js")) - #|fn unsafe_fixedarray_uint16_to_string(buffer : FixedArray[UInt16]) -> String = "%string.unsafe_from_uint16_fixedarray" - #|#cfg(not(target="js")) - #|fn int_to_string_hex( - #| buffer : FixedArray[UInt16], - #| num : UInt, - #| digit_start : Int, - #| total_len : Int, - #|) -> Unit { - #| let mut offset = total_len - digit_start - #| let mut n = num - #| while offset >= 2 { - #| offset = offset - 2 - #| let byte_val = n.land(0xFFU).reinterpret_as_int() - #| let hi = byte_val / 16 - #| let lo = byte_val % 16 - #| buffer.unsafe_set( - #| digit_start + offset, - #| ALPHABET.unsafe_charcode_at(hi).to_uint16(), - #| ) - #| buffer.unsafe_set( - #| digit_start + offset + 1, - #| ALPHABET.unsafe_charcode_at(lo).to_uint16(), - #| ) - #| n = n >> 8 - #| } - #| if offset == 1 { - #| let nibble = n.land(0xFU).reinterpret_as_int() - #| buffer.unsafe_set( - #| digit_start, - #| ALPHABET.unsafe_charcode_at(nibble).to_uint16(), - #| ) - #| } - #|} - #|#cfg(not(target="js")) - #|fn int_to_string_generic( - #| buffer : FixedArray[UInt16], - #| num : UInt, - #| digit_start : Int, - #| total_len : Int, - #| radix : Int, - #|) -> Unit { - #| let mut offset = total_len - digit_start - #| let mut n = num - #| let base = radix.reinterpret_as_uint() - #| if (radix & (radix - 1)) == 0 { - #| let shift = radix.ctz() - #| let mask = base - 1U - #| while n > 0U { - #| offset = offset - 1 - #| let digit = n.land(mask).reinterpret_as_int() - #| buffer.unsafe_set( - #| digit_start + offset, - #| ALPHABET.unsafe_charcode_at(digit).to_uint16(), - #| ) - #| n = n >> shift - #| } - #| } else { - #| while n > 0U { - #| offset = offset - 1 - #| let q = n / base - #| let digit = (n - q * base).reinterpret_as_int() - #| buffer.unsafe_set( - #| digit_start + offset, - #| ALPHABET.unsafe_charcode_at(digit).to_uint16(), - #| ) - #| n = q - #| } - #| } - #|} - #|#cfg(not(target="js")) - #|fn int_to_string_dec( - #| buffer : FixedArray[UInt16], - #| num : UInt, - #| digit_start : Int, - #| total_len : Int, - #|) -> Unit { - #| let mut num = num - #| let mut offset = total_len - digit_start - #| while num >= 10000U { - #| let t = num / 10000U - #| let r = (num % 10000U).reinterpret_as_int() - #| num = t - #| let d1 = r / 100 - #| let d2 = r % 100 - #| offset = offset - 4 - #| let d1_hi = (0x30 + d1 / 10).to_uint16() - #| let d1_lo = (0x30 + d1 % 10).to_uint16() - #| let d2_hi = (0x30 + d2 / 10).to_uint16() - #| let d2_lo = (0x30 + d2 % 10).to_uint16() - #| buffer.unsafe_set(digit_start + offset, d1_hi) - #| buffer.unsafe_set(digit_start + offset + 1, d1_lo) - #| buffer.unsafe_set(digit_start + offset + 2, d2_hi) - #| buffer.unsafe_set(digit_start + offset + 3, d2_lo) - #| } - #| let mut remaining = num.reinterpret_as_int() - #| while remaining >= 100 { - #| let t = remaining / 100 - #| let d = remaining % 100 - #| remaining = t - #| offset = offset - 2 - #| let d_hi = (0x30 + d / 10).to_uint16() - #| let d_lo = (0x30 + d % 10).to_uint16() - #| buffer.unsafe_set(digit_start + offset, d_hi) - #| buffer.unsafe_set(digit_start + offset + 1, d_lo) - #| } - #| if remaining >= 10 { - #| offset = offset - 2 - #| let d_hi = (0x30 + remaining / 10).to_uint16() - #| let d_lo = (0x30 + remaining % 10).to_uint16() - #| buffer.unsafe_set(digit_start + offset, d_hi) - #| buffer.unsafe_set(digit_start + offset + 1, d_lo) - #| } else { - #| offset = offset - 1 - #| buffer.unsafe_set(digit_start + offset, (0x30 + remaining).to_uint16()) - #| } - #|} - #|#cfg(not(target="js")) - #|fn dec_count32(value : UInt) -> Int { - #| if value >= 100000U { // >= 10^5 means 6+ digits - #| if value >= 10000000U { // >= 10^7 means 8+ digits - #| if value >= 1000000000U { // >= 10^9 means 10 digits - #| 10 - #| } else if value >= 100000000U { // >= 10^8 means 9 digits - #| 9 - #| } else { - #| 8 - #| } - #| } else if value >= 1000000U { // >= 10^6 means 7 digits - #| 7 - #| } else { - #| 6 - #| } - #| } else if value >= 1000U { // >= 10^3 means 4+ digits - #| if value >= 10000U { // >= 10^4 means 5 digits - #| 5 - #| } else { - #| 4 - #| } - #| } else if value >= 100U { // >= 10^2 means 3 digits - #| 3 - #| } else if value >= 10U { // >= 10^1 means 2 digits - #| 2 - #| } else { - #| 1 - #| } - #|} - #|#cfg(not(target="js")) - #|fn hex_count32(value : UInt) -> Int { - #| if value == 0U { - #| 1 - #| } else { - #| let leading_zeros = value.clz() - #| (31 - leading_zeros) / 4 + 1 - #| } - #|} - #|#cfg(not(target="js")) - #|fn radix_count32(value : UInt, radix : Int) -> Int { - #| if value == 0U { - #| return 1 - #| } - #| let mut num = value - #| let base = radix.reinterpret_as_uint() - #| let mut count = 0 - #| while num > 0U { - #| count = count + 1 - #| num = num / base - #| } - #| count - #|} - #|#cfg(not(target="js")) - #|pub fn Int::to_string(self : Int, radix? : Int = 10) -> String { - #| if radix < 2 || radix > 36 { - #| abort("radix must be between 2 and 36") - #| } - #| if self == 0 { - #| return "0" - #| } - #| let is_negative = self < 0 - #| let num : UInt = if is_negative { - #| (-self).reinterpret_as_uint() - #| } else { - #| self.reinterpret_as_uint() - #| } - #| let buffer = match radix { - #| 10 => { - #| let digit_len = dec_count32(num) - #| let total_len = digit_len + (if is_negative { 1 } else { 0 }) - #| let buffer : FixedArray[UInt16] = FixedArray::make(total_len, 0) - #| let digit_start = if is_negative { 1 } else { 0 } - #| int_to_string_dec(buffer, num, digit_start, total_len) - #| buffer - #| } - #| 16 => { - #| let digit_len = hex_count32(num) - #| let total_len = digit_len + (if is_negative { 1 } else { 0 }) - #| let buffer : FixedArray[UInt16] = FixedArray::make(total_len, 0) - #| let digit_start = if is_negative { 1 } else { 0 } - #| int_to_string_hex(buffer, num, digit_start, total_len) - #| buffer - #| } - #| _ => { - #| let digit_len = radix_count32(num, radix) - #| let total_len = digit_len + (if is_negative { 1 } else { 0 }) - #| let buffer : FixedArray[UInt16] = FixedArray::make(total_len, 0) - #| let digit_start = if is_negative { 1 } else { 0 } - #| int_to_string_generic(buffer, num, digit_start, total_len, radix) - #| buffer - #| } - #| } - #| if is_negative { - #| buffer.unsafe_set(0, 0x002D) - #| } - #| unsafe_fixedarray_uint16_to_string(buffer) - #|} - #|#cfg(not(target="js")) - #|pub fn UInt::to_string(self : UInt, radix? : Int = 10) -> String { - #| if radix < 2 || radix > 36 { - #| abort("radix must be between 2 and 36") - #| } - #| if self == 0U { - #| return "0" - #| } - #| let buffer = match radix { - #| 10 => { - #| let len = dec_count32(self) - #| let buffer : FixedArray[UInt16] = FixedArray::make(len, 0) - #| int_to_string_dec(buffer, self, 0, len) - #| buffer - #| } - #| 16 => { - #| let len = hex_count32(self) - #| let buffer : FixedArray[UInt16] = FixedArray::make(len, 0) - #| int_to_string_hex(buffer, self, 0, len) - #| buffer - #| } - #| _ => { - #| let len = radix_count32(self, radix) - #| let buffer : FixedArray[UInt16] = FixedArray::make(len, 0) - #| int_to_string_generic(buffer, self, 0, len, radix) - #| buffer - #| } - #| } - #| unsafe_fixedarray_uint16_to_string(buffer) - #|} - #|#cfg(target="js") - #|pub fn Int::to_string(self : Int, radix? : Int = 10) -> String { - #| int_to_string_js(self, radix) - #|} - #|#cfg(target="js") - #|extern "js" fn int_to_string_js(i : Int, radix : Int) -> String = - #| #|(x, radix) => { - #| #| return x.toString(radix); - #| #|} - #|#cfg(target="js") - #|pub fn UInt::to_string(self : UInt, radix? : Int = 10) -> String { - #| uint_to_string_js(self, radix) - #|} - #|#cfg(target="js") - #|extern "js" fn uint_to_string_js(i : UInt, radix : Int) -> String = - #| #|(x, radix) => { - #| #| return (x >>> 0).toString(radix); - #| #|} - #|#cfg(not(target="js")) - #|fn dec_count64(value : UInt64) -> Int { - #| if value >= 10000000000UL { // >= 10^10 means 11+ digits - #| if value >= 100000000000000UL { // >= 10^14 means 15+ digits - #| if value >= 10000000000000000UL { // >= 10^16 means 17+ digits - #| if value >= 1000000000000000000UL { // >= 10^18 means 19+ digits - #| if value >= 10000000000000000000UL { // >= 10^19 means 20 digits - #| 20 - #| } else { - #| 19 - #| } - #| } else if value >= 100000000000000000UL { // >= 10^17 means 18 digits - #| 18 - #| } else { - #| 17 - #| } - #| } else if value >= 1000000000000000UL { // >= 10^15 means 16 digits - #| 16 - #| } else { - #| 15 - #| } - #| } else if value >= 1000000000000UL { // >= 10^12 means 13+ digits - #| if value >= 10000000000000UL { // >= 10^13 means 14 digits - #| 14 - #| } else { - #| 13 - #| } - #| } else if value >= 100000000000UL { // >= 10^11 means 12 digits - #| 12 - #| } else { - #| 11 - #| } - #| } else if value >= 100000UL { // >= 10^5 means 6+ digits - #| if value >= 10000000UL { // >= 10^7 means 8+ digits - #| if value >= 1000000000UL { // >= 10^9 means 10 digits - #| 10 - #| } else if value >= 100000000UL { // >= 10^8 means 9 digits - #| 9 - #| } else { - #| 8 - #| } - #| } else if value >= 1000000UL { // >= 10^6 means 7 digits - #| 7 - #| } else { - #| 6 - #| } - #| } else if value >= 1000UL { // >= 10^3 means 4+ digits - #| if value >= 10000UL { // >= 10^4 means 5 digits - #| 5 - #| } else { - #| 4 - #| } - #| } else if value >= 100UL { // >= 10^2 means 3 digits - #| 3 - #| } else if value >= 10UL { // >= 10^1 means 2 digits - #| 2 - #| } else { - #| 1 - #| } - #|} - #|#cfg(not(target="js")) - #|fn hex_count64(value : UInt64) -> Int { - #| if value == 0UL { - #| 1 - #| } else { - #| let leading_zeros = value.clz() - #| (63 - leading_zeros) / 4 + 1 - #| } - #|} - #|#cfg(not(target="js")) - #|fn radix_count64(value : UInt64, radix : Int) -> Int { - #| if value == 0UL { - #| return 1 - #| } - #| let mut num = value - #| let base = radix.to_uint64() - #| let mut count = 0 - #| while num > 0UL { - #| count = count + 1 - #| num = num / base - #| } - #| count - #|} - #|#cfg(not(target="js")) - #|fn int64_to_string_hex( - #| buffer : FixedArray[UInt16], - #| num : UInt64, - #| digit_start : Int, - #| total_len : Int, - #|) -> Unit { - #| let mut offset = total_len - digit_start - #| let mut n = num - #| while offset >= 2 { - #| offset = offset - 2 - #| let byte_val = n.land(0xFFUL).to_int() - #| let hi = byte_val / 16 - #| let lo = byte_val % 16 - #| buffer.unsafe_set( - #| digit_start + offset, - #| ALPHABET.unsafe_charcode_at(hi).to_uint16(), - #| ) - #| buffer.unsafe_set( - #| digit_start + offset + 1, - #| ALPHABET.unsafe_charcode_at(lo).to_uint16(), - #| ) - #| n = n >> 8 - #| } - #| if offset == 1 { - #| let nibble = n.land(0xFUL).to_int() - #| buffer.unsafe_set( - #| digit_start, - #| ALPHABET.unsafe_charcode_at(nibble).to_uint16(), - #| ) - #| } - #|} - #|#cfg(not(target="js")) - #|fn int64_to_string_generic( - #| buffer : FixedArray[UInt16], - #| num : UInt64, - #| digit_start : Int, - #| total_len : Int, - #| radix : Int, - #|) -> Unit { - #| let mut offset = total_len - digit_start - #| let mut n = num - #| let base = radix.to_uint64() - #| if (radix & (radix - 1)) == 0 { - #| let shift = radix.ctz() - #| let mask = base - 1UL - #| while n > 0UL { - #| offset = offset - 1 - #| let digit = n.land(mask).to_int() - #| buffer.unsafe_set( - #| digit_start + offset, - #| ALPHABET.unsafe_charcode_at(digit).to_uint16(), - #| ) - #| n = n >> shift - #| } - #| } else { - #| while n > 0UL { - #| offset = offset - 1 - #| let q = n / base - #| let digit = (n - q * base).to_int() - #| buffer.unsafe_set( - #| digit_start + offset, - #| ALPHABET.unsafe_charcode_at(digit).to_uint16(), - #| ) - #| n = q - #| } - #| } - #|} - #|#cfg(not(target="js")) - #|fn int64_to_string_dec( - #| buffer : FixedArray[UInt16], - #| num : UInt64, - #| digit_start : Int, - #| total_len : Int, - #|) -> Unit { - #| let mut num = num - #| let mut offset = total_len - digit_start - #| while num >= 10000UL { - #| let t = num / 10000UL - #| let r = (num % 10000UL).to_int() - #| num = t - #| let d1 = r / 100 - #| let d2 = r % 100 - #| offset = offset - 4 - #| let d1_hi = (0x30 + d1 / 10).to_uint16() - #| let d1_lo = (0x30 + d1 % 10).to_uint16() - #| let d2_hi = (0x30 + d2 / 10).to_uint16() - #| let d2_lo = (0x30 + d2 % 10).to_uint16() - #| buffer.unsafe_set(digit_start + offset, d1_hi) - #| buffer.unsafe_set(digit_start + offset + 1, d1_lo) - #| buffer.unsafe_set(digit_start + offset + 2, d2_hi) - #| buffer.unsafe_set(digit_start + offset + 3, d2_lo) - #| } - #| let mut remaining = num.to_int() - #| while remaining >= 100 { - #| let t = remaining / 100 - #| let d = remaining % 100 - #| remaining = t - #| offset = offset - 2 - #| let d_hi = (0x30 + d / 10).to_uint16() - #| let d_lo = (0x30 + d % 10).to_uint16() - #| buffer.unsafe_set(digit_start + offset, d_hi) - #| buffer.unsafe_set(digit_start + offset + 1, d_lo) - #| } - #| if remaining >= 10 { - #| offset = offset - 2 - #| let d_hi = (0x30 + remaining / 10).to_uint16() - #| let d_lo = (0x30 + remaining % 10).to_uint16() - #| buffer.unsafe_set(digit_start + offset, d_hi) - #| buffer.unsafe_set(digit_start + offset + 1, d_lo) - #| } else { - #| offset = offset - 1 - #| buffer.unsafe_set(digit_start + offset, (0x30 + remaining).to_uint16()) - #| } - #|} - #|#cfg(not(target="js")) - #|pub fn Int64::to_string(self : Int64, radix? : Int = 10) -> String { - #| if radix < 2 || radix > 36 { - #| abort("radix must be between 2 and 36") - #| } - #| if self == 0L { - #| return "0" - #| } - #| let is_negative = self < 0L - #| let num : UInt64 = if is_negative { - #| (-self).reinterpret_as_uint64() - #| } else { - #| self.reinterpret_as_uint64() - #| } - #| let buffer = match radix { - #| 10 => { - #| let digit_len = dec_count64(num) - #| let total_len = digit_len + (if is_negative { 1 } else { 0 }) - #| let buffer : FixedArray[UInt16] = FixedArray::make(total_len, 0) - #| let digit_start = if is_negative { 1 } else { 0 } - #| int64_to_string_dec(buffer, num, digit_start, total_len) - #| buffer - #| } - #| 16 => { - #| let digit_len = hex_count64(num) - #| let total_len = digit_len + (if is_negative { 1 } else { 0 }) - #| let buffer : FixedArray[UInt16] = FixedArray::make(total_len, 0) - #| let digit_start = if is_negative { 1 } else { 0 } - #| int64_to_string_hex(buffer, num, digit_start, total_len) - #| buffer - #| } - #| _ => { - #| let digit_len = radix_count64(num, radix) - #| let total_len = digit_len + (if is_negative { 1 } else { 0 }) - #| let buffer : FixedArray[UInt16] = FixedArray::make(total_len, 0) - #| let digit_start = if is_negative { 1 } else { 0 } - #| int64_to_string_generic(buffer, num, digit_start, total_len, radix) - #| buffer - #| } - #| } - #| if is_negative { - #| buffer.unsafe_set(0, 0x002D) - #| } - #| unsafe_fixedarray_uint16_to_string(buffer) - #|} - #|#cfg(not(target="js")) - #|pub fn UInt64::to_string(self : UInt64, radix? : Int = 10) -> String { - #| if radix < 2 || radix > 36 { - #| abort("radix must be between 2 and 36") - #| } - #| if self == 0UL { - #| return "0" - #| } - #| let buffer = match radix { - #| 10 => { - #| let len = dec_count64(self) - #| let buffer : FixedArray[UInt16] = FixedArray::make(len, 0) - #| int64_to_string_dec(buffer, self, 0, len) - #| buffer - #| } - #| 16 => { - #| let len = hex_count64(self) - #| let buffer : FixedArray[UInt16] = FixedArray::make(len, 0) - #| int64_to_string_hex(buffer, self, 0, len) - #| buffer - #| } - #| _ => { - #| let len = radix_count64(self, radix) - #| let buffer : FixedArray[UInt16] = FixedArray::make(len, 0) - #| int64_to_string_generic(buffer, self, 0, len, radix) - #| buffer - #| } - #| } - #| unsafe_fixedarray_uint16_to_string(buffer) - #|} - #|#cfg(target="js") - #|pub fn Int64::to_string(self : Int64, radix? : Int = 10) -> String { - #| int64_to_string_js(self, radix) - #|} - #|#cfg(target="js") - #|extern "js" fn int64_to_string_js(num : Int64, radix : Int) -> String = - #| #|(num, radix) => { - #| #| let val = (BigInt(num.hi >>> 0) << 32n) | BigInt(num.lo >>> 0); - #| #| if (val & (1n << 63n)) { - #| #| val = val - (1n << 64n); - #| #| } - #| #| return val.toString(radix); - #| #|} - #|#cfg(target="js") - #|pub fn UInt64::to_string(self : UInt64, radix? : Int = 10) -> String { - #| uint64_to_string_js(self, radix) - #|} - #|#cfg(target="js") - #|extern "js" fn uint64_to_string_js(num : UInt64, radix : Int) -> String = - #| #|(num, radix) => { - #| #| return (BigInt(num.hi >>> 0) << 32n | BigInt(num.lo >>> 0)).toString(radix); - #| #|} - #|pub fn UInt16::to_string(self : UInt16, radix? : Int = 10) -> String { - #| self.to_int().to_string(radix~) - #|} - #|test "UInt::to_string" { - #| inspect(0U, content="0") - #| inspect(17U, content="17") - #| inspect(4294967295U, content="4294967295") - #|} - #|test "to_string" { - #| assert_eq((0x100).to_string(), "256") - #| assert_eq("\{0x100}", "256") - #| assert_eq(0x200U.to_string(), "512") - #| assert_eq("\{0x200U}", "512") - #| assert_eq(0x300L.to_string(), "768") - #| assert_eq("\{0x300L}", "768") - #| assert_eq(0x400UL.to_string(), "1024") - #| assert_eq("\{0x400UL}", "1024") - #|} - #|test "panic to_string_by_radix/illegal_radix" { - #| ignore((1).to_string(radix=1)) - #| ignore((1).to_string(radix=37)) - #| ignore(1L.to_string(radix=0)) - #| ignore(1L.to_string(radix=42)) - #| ignore(1U.to_string(radix=-1)) - #| ignore(1U.to_string(radix=73)) - #| ignore(1UL.to_string(radix=-100)) - #| ignore(1UL.to_string(radix=100)) - #|} - ), - "traits.mbt": ( - #|pub(open) trait Eq { - #| equal(Self, Self) -> Bool = _ - #| #deprecated("use `equal` instead", skip_current_package=true) - #| op_equal(Self, Self) -> Bool = _ - #|} - #|pub(open) trait Compare: Eq { - #| compare(Self, Self) -> Int - #| op_lt(Self, Self) -> Bool = _ - #| op_gt(Self, Self) -> Bool = _ - #| op_le(Self, Self) -> Bool = _ - #| op_ge(Self, Self) -> Bool = _ - #|} - #|impl Compare with op_lt(x, y) { - #| x.compare(y).is_neg() - #|} - #|impl Compare with op_gt(x, y) { - #| x.compare(y).is_pos() - #|} - #|impl Compare with op_le(x, y) { - #| x.compare(y).is_non_pos() - #|} - #|impl Compare with op_ge(x, y) { - #| x.compare(y).is_non_neg() - #|} - #|pub(open) trait Hash { - #| hash_combine(Self, Hasher) -> Unit - #| hash(Self) -> Int = _ - #|} - #|impl Hash with hash(self) { - #| Hasher::new()..combine(self).finalize() - #|} - #|pub(open) trait Default { - #| default() -> Self - #|} - #|pub(open) trait Logger { - #| write_string(Self, String) -> Unit = _ - #| #deprecated("use `write_view` instead", skip_current_package=true) - #| write_substring(Self, String, Int, Int) -> Unit = _ - #| write_view(Self, StringView) -> Unit = _ - #| write_char(Self, Char) -> Unit = _ - #|} - #|impl Logger with write_substring(self, value, start, len) { - #| self.write_view(try! value[start:start + len]) - #|} - #|impl Logger with write_string(self, value) { - #| self.write_view(value[:]) - #|} - #|#deprecated("replace `impl write_substring` with `impl write_view`") - #|impl Logger with write_view(self, value) { - #| self.write_substring(value.data(), value.start_offset(), value.length()) - #|} - #|impl Logger with write_char(self, value) { - #| self.write_string([value]) - #|} - #|pub(open) trait Show { - #| output(Self, &Logger) -> Unit - #| to_string(Self) -> String = _ - #|} - #|impl Show with to_string(self) { - #| let logger = StringBuilder::new() - #| self.output(logger) - #| logger.to_string() - #|} - #|pub fn[Obj : Show] &Logger::write_object(self : &Logger, obj : Obj) -> Unit { - #| obj.output(self) - #|} - #|pub fn[T : Show] &Logger::write_iter( - #| self : &Logger, - #| iter : Iter[T], - #| prefix? : String = "[", - #| suffix? : String = "]", - #| sep? : String = ", ", - #| trailing? : Bool = false, - #|) -> Unit { - #| self.write_string(prefix) - #| if trailing { - #| for x in iter { - #| self.write_object(x) - #| self.write_string(sep) - #| } - #| } else { - #| let mut first = true - #| for x in iter { - #| if first { - #| first = false - #| } else { - #| self.write_string(sep) - #| } - #| self.write_object(x) - #| } - #| } - #| self.write_string(suffix) - #|} - #|pub fn[T : Show] repr(t : T) -> String { - #| let logger = StringBuilder::new() - #| t.output(logger) - #| logger.to_string() - #|} - #|#deprecated("replace `impl op_equal` with `impl equal`") - #|impl Eq with equal(self, other) { - #| Eq::op_equal(self, other) - #|} - #|impl Eq with op_equal(self, other) { - #| Eq::equal(self, other) - #|} - ), - "tuple_compare.mbt": ( - #|pub impl[T0 : Compare, T1 : Compare] Compare for (T0, T1) with compare( - #| self : (T0, T1), - #| other : (T0, T1), - #|) -> Int { - #| let t0 = self.0.compare(other.0) - #| guard t0 == 0 else { return t0 } - #| self.1.compare(other.1) - #|} - #|pub impl[T0 : Compare, T1 : Compare, T2 : Compare] Compare for (T0, T1, T2) with compare( - #| self : (T0, T1, T2), - #| other : (T0, T1, T2), - #|) -> Int { - #| let t0 = self.0.compare(other.0) - #| guard t0 == 0 else { return t0 } - #| let t1 = self.1.compare(other.1) - #| guard t1 == 0 else { return t1 } - #| self.2.compare(other.2) - #|} - #|pub impl[T0 : Compare, T1 : Compare, T2 : Compare, T3 : Compare] Compare for ( - #| T0, - #| T1, - #| T2, - #| T3, - #|) with compare(self : (T0, T1, T2, T3), other : (T0, T1, T2, T3)) -> Int { - #| let t0 = self.0.compare(other.0) - #| guard t0 == 0 else { return t0 } - #| let t1 = self.1.compare(other.1) - #| guard t1 == 0 else { return t1 } - #| let t2 = self.2.compare(other.2) - #| guard t2 == 0 else { return t2 } - #| self.3.compare(other.3) - #|} - #|pub impl[T0 : Compare, T1 : Compare, T2 : Compare, T3 : Compare, T4 : Compare] Compare for ( - #| T0, - #| T1, - #| T2, - #| T3, - #| T4, - #|) with compare(self : (T0, T1, T2, T3, T4), other : (T0, T1, T2, T3, T4)) -> Int { - #| let t0 = self.0.compare(other.0) - #| guard t0 == 0 else { return t0 } - #| let t1 = self.1.compare(other.1) - #| guard t1 == 0 else { return t1 } - #| let t2 = self.2.compare(other.2) - #| guard t2 == 0 else { return t2 } - #| let t3 = self.3.compare(other.3) - #| guard t3 == 0 else { return t3 } - #| self.4.compare(other.4) - #|} - #|pub impl[ - #| T0 : Compare, - #| T1 : Compare, - #| T2 : Compare, - #| T3 : Compare, - #| T4 : Compare, - #| T5 : Compare, - #|] Compare for (T0, T1, T2, T3, T4, T5) with compare( - #| self : (T0, T1, T2, T3, T4, T5), - #| other : (T0, T1, T2, T3, T4, T5), - #|) -> Int { - #| let t0 = self.0.compare(other.0) - #| guard t0 == 0 else { return t0 } - #| let t1 = self.1.compare(other.1) - #| guard t1 == 0 else { return t1 } - #| let t2 = self.2.compare(other.2) - #| guard t2 == 0 else { return t2 } - #| let t3 = self.3.compare(other.3) - #| guard t3 == 0 else { return t3 } - #| let t4 = self.4.compare(other.4) - #| guard t4 == 0 else { return t4 } - #| self.5.compare(other.5) - #|} - #|pub impl[ - #| T0 : Compare, - #| T1 : Compare, - #| T2 : Compare, - #| T3 : Compare, - #| T4 : Compare, - #| T5 : Compare, - #| T6 : Compare, - #|] Compare for (T0, T1, T2, T3, T4, T5, T6) with compare( - #| self : (T0, T1, T2, T3, T4, T5, T6), - #| other : (T0, T1, T2, T3, T4, T5, T6), - #|) -> Int { - #| let t0 = self.0.compare(other.0) - #| guard t0 == 0 else { return t0 } - #| let t1 = self.1.compare(other.1) - #| guard t1 == 0 else { return t1 } - #| let t2 = self.2.compare(other.2) - #| guard t2 == 0 else { return t2 } - #| let t3 = self.3.compare(other.3) - #| guard t3 == 0 else { return t3 } - #| let t4 = self.4.compare(other.4) - #| guard t4 == 0 else { return t4 } - #| let t5 = self.5.compare(other.5) - #| guard t5 == 0 else { return t5 } - #| self.6.compare(other.6) - #|} - #|pub impl[ - #| T0 : Compare, - #| T1 : Compare, - #| T2 : Compare, - #| T3 : Compare, - #| T4 : Compare, - #| T5 : Compare, - #| T6 : Compare, - #| T7 : Compare, - #|] Compare for (T0, T1, T2, T3, T4, T5, T6, T7) with compare( - #| self : (T0, T1, T2, T3, T4, T5, T6, T7), - #| other : (T0, T1, T2, T3, T4, T5, T6, T7), - #|) -> Int { - #| let t0 = self.0.compare(other.0) - #| guard t0 == 0 else { return t0 } - #| let t1 = self.1.compare(other.1) - #| guard t1 == 0 else { return t1 } - #| let t2 = self.2.compare(other.2) - #| guard t2 == 0 else { return t2 } - #| let t3 = self.3.compare(other.3) - #| guard t3 == 0 else { return t3 } - #| let t4 = self.4.compare(other.4) - #| guard t4 == 0 else { return t4 } - #| let t5 = self.5.compare(other.5) - #| guard t5 == 0 else { return t5 } - #| let t6 = self.6.compare(other.6) - #| guard t6 == 0 else { return t6 } - #| self.7.compare(other.7) - #|} - #|pub impl[ - #| T0 : Compare, - #| T1 : Compare, - #| T2 : Compare, - #| T3 : Compare, - #| T4 : Compare, - #| T5 : Compare, - #| T6 : Compare, - #| T7 : Compare, - #| T8 : Compare, - #|] Compare for (T0, T1, T2, T3, T4, T5, T6, T7, T8) with compare( - #| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8), - #| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8), - #|) -> Int { - #| let t0 = self.0.compare(other.0) - #| guard t0 == 0 else { return t0 } - #| let t1 = self.1.compare(other.1) - #| guard t1 == 0 else { return t1 } - #| let t2 = self.2.compare(other.2) - #| guard t2 == 0 else { return t2 } - #| let t3 = self.3.compare(other.3) - #| guard t3 == 0 else { return t3 } - #| let t4 = self.4.compare(other.4) - #| guard t4 == 0 else { return t4 } - #| let t5 = self.5.compare(other.5) - #| guard t5 == 0 else { return t5 } - #| let t6 = self.6.compare(other.6) - #| guard t6 == 0 else { return t6 } - #| let t7 = self.7.compare(other.7) - #| guard t7 == 0 else { return t7 } - #| self.8.compare(other.8) - #|} - #|pub impl[ - #| T0 : Compare, - #| T1 : Compare, - #| T2 : Compare, - #| T3 : Compare, - #| T4 : Compare, - #| T5 : Compare, - #| T6 : Compare, - #| T7 : Compare, - #| T8 : Compare, - #| T9 : Compare, - #|] Compare for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) with compare( - #| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9), - #| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9), - #|) -> Int { - #| let t0 = self.0.compare(other.0) - #| guard t0 == 0 else { return t0 } - #| let t1 = self.1.compare(other.1) - #| guard t1 == 0 else { return t1 } - #| let t2 = self.2.compare(other.2) - #| guard t2 == 0 else { return t2 } - #| let t3 = self.3.compare(other.3) - #| guard t3 == 0 else { return t3 } - #| let t4 = self.4.compare(other.4) - #| guard t4 == 0 else { return t4 } - #| let t5 = self.5.compare(other.5) - #| guard t5 == 0 else { return t5 } - #| let t6 = self.6.compare(other.6) - #| guard t6 == 0 else { return t6 } - #| let t7 = self.7.compare(other.7) - #| guard t7 == 0 else { return t7 } - #| let t8 = self.8.compare(other.8) - #| guard t8 == 0 else { return t8 } - #| self.9.compare(other.9) - #|} - #|pub impl[ - #| T0 : Compare, - #| T1 : Compare, - #| T2 : Compare, - #| T3 : Compare, - #| T4 : Compare, - #| T5 : Compare, - #| T6 : Compare, - #| T7 : Compare, - #| T8 : Compare, - #| T9 : Compare, - #| T10 : Compare, - #|] Compare for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) with compare( - #| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10), - #| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10), - #|) -> Int { - #| let t0 = self.0.compare(other.0) - #| guard t0 == 0 else { return t0 } - #| let t1 = self.1.compare(other.1) - #| guard t1 == 0 else { return t1 } - #| let t2 = self.2.compare(other.2) - #| guard t2 == 0 else { return t2 } - #| let t3 = self.3.compare(other.3) - #| guard t3 == 0 else { return t3 } - #| let t4 = self.4.compare(other.4) - #| guard t4 == 0 else { return t4 } - #| let t5 = self.5.compare(other.5) - #| guard t5 == 0 else { return t5 } - #| let t6 = self.6.compare(other.6) - #| guard t6 == 0 else { return t6 } - #| let t7 = self.7.compare(other.7) - #| guard t7 == 0 else { return t7 } - #| let t8 = self.8.compare(other.8) - #| guard t8 == 0 else { return t8 } - #| let t9 = self.9.compare(other.9) - #| guard t9 == 0 else { return t9 } - #| self.10.compare(other.10) - #|} - #|pub impl[ - #| T0 : Compare, - #| T1 : Compare, - #| T2 : Compare, - #| T3 : Compare, - #| T4 : Compare, - #| T5 : Compare, - #| T6 : Compare, - #| T7 : Compare, - #| T8 : Compare, - #| T9 : Compare, - #| T10 : Compare, - #| T11 : Compare, - #|] Compare for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) with compare( - #| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11), - #| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11), - #|) -> Int { - #| let t0 = self.0.compare(other.0) - #| guard t0 == 0 else { return t0 } - #| let t1 = self.1.compare(other.1) - #| guard t1 == 0 else { return t1 } - #| let t2 = self.2.compare(other.2) - #| guard t2 == 0 else { return t2 } - #| let t3 = self.3.compare(other.3) - #| guard t3 == 0 else { return t3 } - #| let t4 = self.4.compare(other.4) - #| guard t4 == 0 else { return t4 } - #| let t5 = self.5.compare(other.5) - #| guard t5 == 0 else { return t5 } - #| let t6 = self.6.compare(other.6) - #| guard t6 == 0 else { return t6 } - #| let t7 = self.7.compare(other.7) - #| guard t7 == 0 else { return t7 } - #| let t8 = self.8.compare(other.8) - #| guard t8 == 0 else { return t8 } - #| let t9 = self.9.compare(other.9) - #| guard t9 == 0 else { return t9 } - #| let t10 = self.10.compare(other.10) - #| guard t10 == 0 else { return t10 } - #| self.11.compare(other.11) - #|} - #|pub impl[ - #| T0 : Compare, - #| T1 : Compare, - #| T2 : Compare, - #| T3 : Compare, - #| T4 : Compare, - #| T5 : Compare, - #| T6 : Compare, - #| T7 : Compare, - #| T8 : Compare, - #| T9 : Compare, - #| T10 : Compare, - #| T11 : Compare, - #| T12 : Compare, - #|] Compare for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) with compare( - #| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12), - #| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12), - #|) -> Int { - #| let t0 = self.0.compare(other.0) - #| guard t0 == 0 else { return t0 } - #| let t1 = self.1.compare(other.1) - #| guard t1 == 0 else { return t1 } - #| let t2 = self.2.compare(other.2) - #| guard t2 == 0 else { return t2 } - #| let t3 = self.3.compare(other.3) - #| guard t3 == 0 else { return t3 } - #| let t4 = self.4.compare(other.4) - #| guard t4 == 0 else { return t4 } - #| let t5 = self.5.compare(other.5) - #| guard t5 == 0 else { return t5 } - #| let t6 = self.6.compare(other.6) - #| guard t6 == 0 else { return t6 } - #| let t7 = self.7.compare(other.7) - #| guard t7 == 0 else { return t7 } - #| let t8 = self.8.compare(other.8) - #| guard t8 == 0 else { return t8 } - #| let t9 = self.9.compare(other.9) - #| guard t9 == 0 else { return t9 } - #| let t10 = self.10.compare(other.10) - #| guard t10 == 0 else { return t10 } - #| let t11 = self.11.compare(other.11) - #| guard t11 == 0 else { return t11 } - #| self.12.compare(other.12) - #|} - #|pub impl[ - #| T0 : Compare, - #| T1 : Compare, - #| T2 : Compare, - #| T3 : Compare, - #| T4 : Compare, - #| T5 : Compare, - #| T6 : Compare, - #| T7 : Compare, - #| T8 : Compare, - #| T9 : Compare, - #| T10 : Compare, - #| T11 : Compare, - #| T12 : Compare, - #| T13 : Compare, - #|] Compare for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) with compare( - #| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13), - #| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13), - #|) -> Int { - #| let t0 = self.0.compare(other.0) - #| guard t0 == 0 else { return t0 } - #| let t1 = self.1.compare(other.1) - #| guard t1 == 0 else { return t1 } - #| let t2 = self.2.compare(other.2) - #| guard t2 == 0 else { return t2 } - #| let t3 = self.3.compare(other.3) - #| guard t3 == 0 else { return t3 } - #| let t4 = self.4.compare(other.4) - #| guard t4 == 0 else { return t4 } - #| let t5 = self.5.compare(other.5) - #| guard t5 == 0 else { return t5 } - #| let t6 = self.6.compare(other.6) - #| guard t6 == 0 else { return t6 } - #| let t7 = self.7.compare(other.7) - #| guard t7 == 0 else { return t7 } - #| let t8 = self.8.compare(other.8) - #| guard t8 == 0 else { return t8 } - #| let t9 = self.9.compare(other.9) - #| guard t9 == 0 else { return t9 } - #| let t10 = self.10.compare(other.10) - #| guard t10 == 0 else { return t10 } - #| let t11 = self.11.compare(other.11) - #| guard t11 == 0 else { return t11 } - #| let t12 = self.12.compare(other.12) - #| guard t12 == 0 else { return t12 } - #| self.13.compare(other.13) - #|} - #|pub impl[ - #| T0 : Compare, - #| T1 : Compare, - #| T2 : Compare, - #| T3 : Compare, - #| T4 : Compare, - #| T5 : Compare, - #| T6 : Compare, - #| T7 : Compare, - #| T8 : Compare, - #| T9 : Compare, - #| T10 : Compare, - #| T11 : Compare, - #| T12 : Compare, - #| T13 : Compare, - #| T14 : Compare, - #|] Compare for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14) with compare( - #| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14), - #| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14), - #|) -> Int { - #| let t0 = self.0.compare(other.0) - #| guard t0 == 0 else { return t0 } - #| let t1 = self.1.compare(other.1) - #| guard t1 == 0 else { return t1 } - #| let t2 = self.2.compare(other.2) - #| guard t2 == 0 else { return t2 } - #| let t3 = self.3.compare(other.3) - #| guard t3 == 0 else { return t3 } - #| let t4 = self.4.compare(other.4) - #| guard t4 == 0 else { return t4 } - #| let t5 = self.5.compare(other.5) - #| guard t5 == 0 else { return t5 } - #| let t6 = self.6.compare(other.6) - #| guard t6 == 0 else { return t6 } - #| let t7 = self.7.compare(other.7) - #| guard t7 == 0 else { return t7 } - #| let t8 = self.8.compare(other.8) - #| guard t8 == 0 else { return t8 } - #| let t9 = self.9.compare(other.9) - #| guard t9 == 0 else { return t9 } - #| let t10 = self.10.compare(other.10) - #| guard t10 == 0 else { return t10 } - #| let t11 = self.11.compare(other.11) - #| guard t11 == 0 else { return t11 } - #| let t12 = self.12.compare(other.12) - #| guard t12 == 0 else { return t12 } - #| let t13 = self.13.compare(other.13) - #| guard t13 == 0 else { return t13 } - #| self.14.compare(other.14) - #|} - #|pub impl[ - #| T0 : Compare, - #| T1 : Compare, - #| T2 : Compare, - #| T3 : Compare, - #| T4 : Compare, - #| T5 : Compare, - #| T6 : Compare, - #| T7 : Compare, - #| T8 : Compare, - #| T9 : Compare, - #| T10 : Compare, - #| T11 : Compare, - #| T12 : Compare, - #| T13 : Compare, - #| T14 : Compare, - #| T15 : Compare, - #|] Compare for ( - #| T0, - #| T1, - #| T2, - #| T3, - #| T4, - #| T5, - #| T6, - #| T7, - #| T8, - #| T9, - #| T10, - #| T11, - #| T12, - #| T13, - #| T14, - #| T15, - #|) with compare( - #| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15), - #| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15), - #|) -> Int { - #| let t0 = self.0.compare(other.0) - #| guard t0 == 0 else { return t0 } - #| let t1 = self.1.compare(other.1) - #| guard t1 == 0 else { return t1 } - #| let t2 = self.2.compare(other.2) - #| guard t2 == 0 else { return t2 } - #| let t3 = self.3.compare(other.3) - #| guard t3 == 0 else { return t3 } - #| let t4 = self.4.compare(other.4) - #| guard t4 == 0 else { return t4 } - #| let t5 = self.5.compare(other.5) - #| guard t5 == 0 else { return t5 } - #| let t6 = self.6.compare(other.6) - #| guard t6 == 0 else { return t6 } - #| let t7 = self.7.compare(other.7) - #| guard t7 == 0 else { return t7 } - #| let t8 = self.8.compare(other.8) - #| guard t8 == 0 else { return t8 } - #| let t9 = self.9.compare(other.9) - #| guard t9 == 0 else { return t9 } - #| let t10 = self.10.compare(other.10) - #| guard t10 == 0 else { return t10 } - #| let t11 = self.11.compare(other.11) - #| guard t11 == 0 else { return t11 } - #| let t12 = self.12.compare(other.12) - #| guard t12 == 0 else { return t12 } - #| let t13 = self.13.compare(other.13) - #| guard t13 == 0 else { return t13 } - #| let t14 = self.14.compare(other.14) - #| guard t14 == 0 else { return t14 } - #| self.15.compare(other.15) - #|} - ), - "tuple_eq.mbt": ( - #|pub impl[T0 : Eq, T1 : Eq] Eq for (T0, T1) with equal( - #| self : (T0, T1), - #| other : (T0, T1), - #|) -> Bool { - #| self.0 == other.0 && self.1 == other.1 - #|} - #|pub impl[T0 : Eq, T1 : Eq, T2 : Eq] Eq for (T0, T1, T2) with equal( - #| self : (T0, T1, T2), - #| other : (T0, T1, T2), - #|) -> Bool { - #| self.0 == other.0 && self.1 == other.1 && self.2 == other.2 - #|} - #|pub impl[T0 : Eq, T1 : Eq, T2 : Eq, T3 : Eq] Eq for (T0, T1, T2, T3) with equal( - #| self : (T0, T1, T2, T3), - #| other : (T0, T1, T2, T3), - #|) -> Bool { - #| self.0 == other.0 && - #| self.1 == other.1 && - #| self.2 == other.2 && - #| self.3 == other.3 - #|} - #|pub impl[T0 : Eq, T1 : Eq, T2 : Eq, T3 : Eq, T4 : Eq] Eq for ( - #| T0, - #| T1, - #| T2, - #| T3, - #| T4, - #|) with equal(self : (T0, T1, T2, T3, T4), other : (T0, T1, T2, T3, T4)) -> Bool { - #| self.0 == other.0 && - #| self.1 == other.1 && - #| self.2 == other.2 && - #| self.3 == other.3 && - #| self.4 == other.4 - #|} - #|pub impl[T0 : Eq, T1 : Eq, T2 : Eq, T3 : Eq, T4 : Eq, T5 : Eq] Eq for ( - #| T0, - #| T1, - #| T2, - #| T3, - #| T4, - #| T5, - #|) with equal(self : (T0, T1, T2, T3, T4, T5), other : (T0, T1, T2, T3, T4, T5)) -> Bool { - #| self.0 == other.0 && - #| self.1 == other.1 && - #| self.2 == other.2 && - #| self.3 == other.3 && - #| self.4 == other.4 && - #| self.5 == other.5 - #|} - #|pub impl[T0 : Eq, T1 : Eq, T2 : Eq, T3 : Eq, T4 : Eq, T5 : Eq, T6 : Eq] Eq for ( - #| T0, - #| T1, - #| T2, - #| T3, - #| T4, - #| T5, - #| T6, - #|) with equal( - #| self : (T0, T1, T2, T3, T4, T5, T6), - #| other : (T0, T1, T2, T3, T4, T5, T6), - #|) -> Bool { - #| self.0 == other.0 && - #| self.1 == other.1 && - #| self.2 == other.2 && - #| self.3 == other.3 && - #| self.4 == other.4 && - #| self.5 == other.5 && - #| self.6 == other.6 - #|} - #|pub impl[T0 : Eq, T1 : Eq, T2 : Eq, T3 : Eq, T4 : Eq, T5 : Eq, T6 : Eq, T7 : Eq] Eq for ( - #| T0, - #| T1, - #| T2, - #| T3, - #| T4, - #| T5, - #| T6, - #| T7, - #|) with equal( - #| self : (T0, T1, T2, T3, T4, T5, T6, T7), - #| other : (T0, T1, T2, T3, T4, T5, T6, T7), - #|) -> Bool { - #| self.0 == other.0 && - #| self.1 == other.1 && - #| self.2 == other.2 && - #| self.3 == other.3 && - #| self.4 == other.4 && - #| self.5 == other.5 && - #| self.6 == other.6 && - #| self.7 == other.7 - #|} - #|pub impl[ - #| T0 : Eq, - #| T1 : Eq, - #| T2 : Eq, - #| T3 : Eq, - #| T4 : Eq, - #| T5 : Eq, - #| T6 : Eq, - #| T7 : Eq, - #| T8 : Eq, - #|] Eq for (T0, T1, T2, T3, T4, T5, T6, T7, T8) with equal( - #| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8), - #| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8), - #|) -> Bool { - #| self.0 == other.0 && - #| self.1 == other.1 && - #| self.2 == other.2 && - #| self.3 == other.3 && - #| self.4 == other.4 && - #| self.5 == other.5 && - #| self.6 == other.6 && - #| self.7 == other.7 && - #| self.8 == other.8 - #|} - #|pub impl[ - #| T0 : Eq, - #| T1 : Eq, - #| T2 : Eq, - #| T3 : Eq, - #| T4 : Eq, - #| T5 : Eq, - #| T6 : Eq, - #| T7 : Eq, - #| T8 : Eq, - #| T9 : Eq, - #|] Eq for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) with equal( - #| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9), - #| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9), - #|) -> Bool { - #| self.0 == other.0 && - #| self.1 == other.1 && - #| self.2 == other.2 && - #| self.3 == other.3 && - #| self.4 == other.4 && - #| self.5 == other.5 && - #| self.6 == other.6 && - #| self.7 == other.7 && - #| self.8 == other.8 && - #| self.9 == other.9 - #|} - #|pub impl[ - #| T0 : Eq, - #| T1 : Eq, - #| T2 : Eq, - #| T3 : Eq, - #| T4 : Eq, - #| T5 : Eq, - #| T6 : Eq, - #| T7 : Eq, - #| T8 : Eq, - #| T9 : Eq, - #| T10 : Eq, - #|] Eq for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) with equal( - #| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10), - #| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10), - #|) -> Bool { - #| self.0 == other.0 && - #| self.1 == other.1 && - #| self.2 == other.2 && - #| self.3 == other.3 && - #| self.4 == other.4 && - #| self.5 == other.5 && - #| self.6 == other.6 && - #| self.7 == other.7 && - #| self.8 == other.8 && - #| self.9 == other.9 && - #| self.10 == other.10 - #|} - #|pub impl[ - #| T0 : Eq, - #| T1 : Eq, - #| T2 : Eq, - #| T3 : Eq, - #| T4 : Eq, - #| T5 : Eq, - #| T6 : Eq, - #| T7 : Eq, - #| T8 : Eq, - #| T9 : Eq, - #| T10 : Eq, - #| T11 : Eq, - #|] Eq for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) with equal( - #| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11), - #| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11), - #|) -> Bool { - #| self.0 == other.0 && - #| self.1 == other.1 && - #| self.2 == other.2 && - #| self.3 == other.3 && - #| self.4 == other.4 && - #| self.5 == other.5 && - #| self.6 == other.6 && - #| self.7 == other.7 && - #| self.8 == other.8 && - #| self.9 == other.9 && - #| self.10 == other.10 && - #| self.11 == other.11 - #|} - #|pub impl[ - #| T0 : Eq, - #| T1 : Eq, - #| T2 : Eq, - #| T3 : Eq, - #| T4 : Eq, - #| T5 : Eq, - #| T6 : Eq, - #| T7 : Eq, - #| T8 : Eq, - #| T9 : Eq, - #| T10 : Eq, - #| T11 : Eq, - #| T12 : Eq, - #|] Eq for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) with equal( - #| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12), - #| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12), - #|) -> Bool { - #| self.0 == other.0 && - #| self.1 == other.1 && - #| self.2 == other.2 && - #| self.3 == other.3 && - #| self.4 == other.4 && - #| self.5 == other.5 && - #| self.6 == other.6 && - #| self.7 == other.7 && - #| self.8 == other.8 && - #| self.9 == other.9 && - #| self.10 == other.10 && - #| self.11 == other.11 && - #| self.12 == other.12 - #|} - #|pub impl[ - #| T0 : Eq, - #| T1 : Eq, - #| T2 : Eq, - #| T3 : Eq, - #| T4 : Eq, - #| T5 : Eq, - #| T6 : Eq, - #| T7 : Eq, - #| T8 : Eq, - #| T9 : Eq, - #| T10 : Eq, - #| T11 : Eq, - #| T12 : Eq, - #| T13 : Eq, - #|] Eq for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) with equal( - #| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13), - #| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13), - #|) -> Bool { - #| self.0 == other.0 && - #| self.1 == other.1 && - #| self.2 == other.2 && - #| self.3 == other.3 && - #| self.4 == other.4 && - #| self.5 == other.5 && - #| self.6 == other.6 && - #| self.7 == other.7 && - #| self.8 == other.8 && - #| self.9 == other.9 && - #| self.10 == other.10 && - #| self.11 == other.11 && - #| self.12 == other.12 && - #| self.13 == other.13 - #|} - #|pub impl[ - #| T0 : Eq, - #| T1 : Eq, - #| T2 : Eq, - #| T3 : Eq, - #| T4 : Eq, - #| T5 : Eq, - #| T6 : Eq, - #| T7 : Eq, - #| T8 : Eq, - #| T9 : Eq, - #| T10 : Eq, - #| T11 : Eq, - #| T12 : Eq, - #| T13 : Eq, - #| T14 : Eq, - #|] Eq for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14) with equal( - #| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14), - #| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14), - #|) -> Bool { - #| self.0 == other.0 && - #| self.1 == other.1 && - #| self.2 == other.2 && - #| self.3 == other.3 && - #| self.4 == other.4 && - #| self.5 == other.5 && - #| self.6 == other.6 && - #| self.7 == other.7 && - #| self.8 == other.8 && - #| self.9 == other.9 && - #| self.10 == other.10 && - #| self.11 == other.11 && - #| self.12 == other.12 && - #| self.13 == other.13 && - #| self.14 == other.14 - #|} - #|pub impl[ - #| T0 : Eq, - #| T1 : Eq, - #| T2 : Eq, - #| T3 : Eq, - #| T4 : Eq, - #| T5 : Eq, - #| T6 : Eq, - #| T7 : Eq, - #| T8 : Eq, - #| T9 : Eq, - #| T10 : Eq, - #| T11 : Eq, - #| T12 : Eq, - #| T13 : Eq, - #| T14 : Eq, - #| T15 : Eq, - #|] Eq for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15) with equal( - #| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15), - #| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15), - #|) -> Bool { - #| self.0 == other.0 && - #| self.1 == other.1 && - #| self.2 == other.2 && - #| self.3 == other.3 && - #| self.4 == other.4 && - #| self.5 == other.5 && - #| self.6 == other.6 && - #| self.7 == other.7 && - #| self.8 == other.8 && - #| self.9 == other.9 && - #| self.10 == other.10 && - #| self.11 == other.11 && - #| self.12 == other.12 && - #| self.13 == other.13 && - #| self.14 == other.14 && - #| self.15 == other.15 - #|} - ), - "tuple_hash.mbt": ( - #|pub impl[A : Hash, B : Hash] Hash for (A, B) with hash_combine(self, hasher) { - #| let (a, b) = self - #| hasher..combine(a)..combine(b) - #|} - #|pub impl[A : Hash, B : Hash, C : Hash] Hash for (A, B, C) with hash_combine( - #| self, - #| hasher, - #|) { - #| let (a, b, c) = self - #| hasher..combine(a)..combine(b)..combine(c) - #|} - #|pub impl[A : Hash, B : Hash, C : Hash, D : Hash] Hash for (A, B, C, D) with hash_combine( - #| self, - #| hasher, - #|) { - #| let (a, b, c, d) = self - #| hasher..combine(a)..combine(b)..combine(c)..combine(d) - #|} - #|pub impl[A : Hash, B : Hash, C : Hash, D : Hash, E : Hash] Hash for ( - #| A, - #| B, - #| C, - #| D, - #| E, - #|) with hash_combine(self, hasher) { - #| let (a, b, c, d, e) = self - #| hasher..combine(a)..combine(b)..combine(c)..combine(d)..combine(e) - #|} - #|pub impl[A : Hash, B : Hash, C : Hash, D : Hash, E : Hash, F : Hash] Hash for ( - #| A, - #| B, - #| C, - #| D, - #| E, - #| F, - #|) with hash_combine(self, hasher) { - #| let (a, b, c, d, e, f) = self - #| hasher..combine(a)..combine(b)..combine(c)..combine(d)..combine(e)..combine(f) - #|} - #|pub impl[A : Hash, B : Hash, C : Hash, D : Hash, E : Hash, F : Hash, G : Hash] Hash for ( - #| A, - #| B, - #| C, - #| D, - #| E, - #| F, - #| G, - #|) with hash_combine(self, hasher) { - #| let (a, b, c, d, e, f, g) = self - #| hasher - #| ..combine(a) - #| ..combine(b) - #| ..combine(c) - #| ..combine(d) - #| ..combine(e) - #| ..combine(f) - #| ..combine(g) - #|} - ), - "tuple_show.mbt": ( - #|pub impl[A : Show, B : Show] Show for (A, B) with output(self, logger) { - #| let (a, b) = self - #| logger - #| ..write_string("(") - #| ..write_object(a) - #| ..write_string(", ") - #| ..write_object(b) - #| ..write_string(")") - #|} - #|pub impl[A : Show, B : Show, C : Show] Show for (A, B, C) with output( - #| self, - #| logger, - #|) { - #| let (a, b, c) = self - #| logger - #| ..write_string("(") - #| ..write_object(a) - #| ..write_string(", ") - #| ..write_object(b) - #| ..write_string(", ") - #| ..write_object(c) - #| ..write_string(")") - #|} - #|pub impl[A : Show, B : Show, C : Show, D : Show] Show for (A, B, C, D) with output( - #| self, - #| logger, - #|) { - #| let (a, b, c, d) = self - #| logger - #| ..write_string("(") - #| ..write_object(a) - #| ..write_string(", ") - #| ..write_object(b) - #| ..write_string(", ") - #| ..write_object(c) - #| ..write_string(", ") - #| ..write_object(d) - #| ..write_string(")") - #|} - #|pub impl[A : Show, B : Show, C : Show, D : Show, E : Show] Show for ( - #| A, - #| B, - #| C, - #| D, - #| E, - #|) with output(self, logger) { - #| let (a, b, c, d, e) = self - #| logger - #| ..write_string("(") - #| ..write_object(a) - #| ..write_string(", ") - #| ..write_object(b) - #| ..write_string(", ") - #| ..write_object(c) - #| ..write_string(", ") - #| ..write_object(d) - #| ..write_string(", ") - #| ..write_object(e) - #| ..write_string(")") - #|} - #|pub impl[A : Show, B : Show, C : Show, D : Show, E : Show, F : Show] Show for ( - #| A, - #| B, - #| C, - #| D, - #| E, - #| F, - #|) with output(self, logger) { - #| let (a, b, c, d, e, f) = self - #| logger - #| ..write_string("(") - #| ..write_object(a) - #| ..write_string(", ") - #| ..write_object(b) - #| ..write_string(", ") - #| ..write_object(c) - #| ..write_string(", ") - #| ..write_object(d) - #| ..write_string(", ") - #| ..write_object(e) - #| ..write_string(", ") - #| ..write_object(f) - #| ..write_string(")") - #|} - #|pub impl[A : Show, B : Show, C : Show, D : Show, E : Show, F : Show, G : Show] Show for ( - #| A, - #| B, - #| C, - #| D, - #| E, - #| F, - #| G, - #|) with output(self, logger) { - #| let (a, b, c, d, e, f, g) = self - #| logger - #| ..write_string("(") - #| ..write_object(a) - #| ..write_string(", ") - #| ..write_object(b) - #| ..write_string(", ") - #| ..write_object(c) - #| ..write_string(", ") - #| ..write_object(d) - #| ..write_string(", ") - #| ..write_object(e) - #| ..write_string(", ") - #| ..write_object(f) - #| ..write_string(", ") - #| ..write_object(g) - #| ..write_string(")") - #|} - #|pub impl[ - #| T0 : Show, - #| T1 : Show, - #| T2 : Show, - #| T3 : Show, - #| T4 : Show, - #| T5 : Show, - #| T6 : Show, - #| T7 : Show, - #|] Show for (T0, T1, T2, T3, T4, T5, T6, T7) with output(self, logger) { - #| let (x0, x1, x2, x3, x4, x5, x6, x7) = self - #| logger - #| ..write_string("(") - #| ..write_object(x0) - #| ..write_string(", ") - #| ..write_object(x1) - #| ..write_string(", ") - #| ..write_object(x2) - #| ..write_string(", ") - #| ..write_object(x3) - #| ..write_string(", ") - #| ..write_object(x4) - #| ..write_string(", ") - #| ..write_object(x5) - #| ..write_string(", ") - #| ..write_object(x6) - #| ..write_string(", ") - #| ..write_object(x7) - #| ..write_string(")") - #|} - #|pub impl[ - #| T0 : Show, - #| T1 : Show, - #| T2 : Show, - #| T3 : Show, - #| T4 : Show, - #| T5 : Show, - #| T6 : Show, - #| T7 : Show, - #| T8 : Show, - #|] Show for (T0, T1, T2, T3, T4, T5, T6, T7, T8) with output(self, logger) { - #| let (x0, x1, x2, x3, x4, x5, x6, x7, x8) = self - #| logger - #| ..write_string("(") - #| ..write_object(x0) - #| ..write_string(", ") - #| ..write_object(x1) - #| ..write_string(", ") - #| ..write_object(x2) - #| ..write_string(", ") - #| ..write_object(x3) - #| ..write_string(", ") - #| ..write_object(x4) - #| ..write_string(", ") - #| ..write_object(x5) - #| ..write_string(", ") - #| ..write_object(x6) - #| ..write_string(", ") - #| ..write_object(x7) - #| ..write_string(", ") - #| ..write_object(x8) - #| ..write_string(")") - #|} - #|pub impl[ - #| T0 : Show, - #| T1 : Show, - #| T2 : Show, - #| T3 : Show, - #| T4 : Show, - #| T5 : Show, - #| T6 : Show, - #| T7 : Show, - #| T8 : Show, - #| T9 : Show, - #|] Show for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) with output(self, logger) { - #| let (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) = self - #| logger - #| ..write_string("(") - #| ..write_object(x0) - #| ..write_string(", ") - #| ..write_object(x1) - #| ..write_string(", ") - #| ..write_object(x2) - #| ..write_string(", ") - #| ..write_object(x3) - #| ..write_string(", ") - #| ..write_object(x4) - #| ..write_string(", ") - #| ..write_object(x5) - #| ..write_string(", ") - #| ..write_object(x6) - #| ..write_string(", ") - #| ..write_object(x7) - #| ..write_string(", ") - #| ..write_object(x8) - #| ..write_string(", ") - #| ..write_object(x9) - #| ..write_string(")") - #|} - #|pub impl[ - #| T0 : Show, - #| T1 : Show, - #| T2 : Show, - #| T3 : Show, - #| T4 : Show, - #| T5 : Show, - #| T6 : Show, - #| T7 : Show, - #| T8 : Show, - #| T9 : Show, - #| T10 : Show, - #|] Show for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) with output( - #| self, - #| logger, - #|) { - #| let (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10) = self - #| logger - #| ..write_string("(") - #| ..write_object(x0) - #| ..write_string(", ") - #| ..write_object(x1) - #| ..write_string(", ") - #| ..write_object(x2) - #| ..write_string(", ") - #| ..write_object(x3) - #| ..write_string(", ") - #| ..write_object(x4) - #| ..write_string(", ") - #| ..write_object(x5) - #| ..write_string(", ") - #| ..write_object(x6) - #| ..write_string(", ") - #| ..write_object(x7) - #| ..write_string(", ") - #| ..write_object(x8) - #| ..write_string(", ") - #| ..write_object(x9) - #| ..write_string(", ") - #| ..write_object(x10) - #| ..write_string(")") - #|} - #|pub impl[ - #| T0 : Show, - #| T1 : Show, - #| T2 : Show, - #| T3 : Show, - #| T4 : Show, - #| T5 : Show, - #| T6 : Show, - #| T7 : Show, - #| T8 : Show, - #| T9 : Show, - #| T10 : Show, - #| T11 : Show, - #|] Show for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) with output( - #| self, - #| logger, - #|) { - #| let (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11) = self - #| logger - #| ..write_string("(") - #| ..write_object(x0) - #| ..write_string(", ") - #| ..write_object(x1) - #| ..write_string(", ") - #| ..write_object(x2) - #| ..write_string(", ") - #| ..write_object(x3) - #| ..write_string(", ") - #| ..write_object(x4) - #| ..write_string(", ") - #| ..write_object(x5) - #| ..write_string(", ") - #| ..write_object(x6) - #| ..write_string(", ") - #| ..write_object(x7) - #| ..write_string(", ") - #| ..write_object(x8) - #| ..write_string(", ") - #| ..write_object(x9) - #| ..write_string(", ") - #| ..write_object(x10) - #| ..write_string(", ") - #| ..write_object(x11) - #| ..write_string(")") - #|} - #|pub impl[ - #| T0 : Show, - #| T1 : Show, - #| T2 : Show, - #| T3 : Show, - #| T4 : Show, - #| T5 : Show, - #| T6 : Show, - #| T7 : Show, - #| T8 : Show, - #| T9 : Show, - #| T10 : Show, - #| T11 : Show, - #| T12 : Show, - #|] Show for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) with output( - #| self, - #| logger, - #|) { - #| let (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12) = self - #| logger - #| ..write_string("(") - #| ..write_object(x0) - #| ..write_string(", ") - #| ..write_object(x1) - #| ..write_string(", ") - #| ..write_object(x2) - #| ..write_string(", ") - #| ..write_object(x3) - #| ..write_string(", ") - #| ..write_object(x4) - #| ..write_string(", ") - #| ..write_object(x5) - #| ..write_string(", ") - #| ..write_object(x6) - #| ..write_string(", ") - #| ..write_object(x7) - #| ..write_string(", ") - #| ..write_object(x8) - #| ..write_string(", ") - #| ..write_object(x9) - #| ..write_string(", ") - #| ..write_object(x10) - #| ..write_string(", ") - #| ..write_object(x11) - #| ..write_string(", ") - #| ..write_object(x12) - #| ..write_string(")") - #|} - #|pub impl[ - #| T0 : Show, - #| T1 : Show, - #| T2 : Show, - #| T3 : Show, - #| T4 : Show, - #| T5 : Show, - #| T6 : Show, - #| T7 : Show, - #| T8 : Show, - #| T9 : Show, - #| T10 : Show, - #| T11 : Show, - #| T12 : Show, - #| T13 : Show, - #|] Show for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) with output( - #| self, - #| logger, - #|) { - #| let (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13) = self - #| logger - #| ..write_string("(") - #| ..write_object(x0) - #| ..write_string(", ") - #| ..write_object(x1) - #| ..write_string(", ") - #| ..write_object(x2) - #| ..write_string(", ") - #| ..write_object(x3) - #| ..write_string(", ") - #| ..write_object(x4) - #| ..write_string(", ") - #| ..write_object(x5) - #| ..write_string(", ") - #| ..write_object(x6) - #| ..write_string(", ") - #| ..write_object(x7) - #| ..write_string(", ") - #| ..write_object(x8) - #| ..write_string(", ") - #| ..write_object(x9) - #| ..write_string(", ") - #| ..write_object(x10) - #| ..write_string(", ") - #| ..write_object(x11) - #| ..write_string(", ") - #| ..write_object(x12) - #| ..write_string(", ") - #| ..write_object(x13) - #| ..write_string(")") - #|} - #|pub impl[ - #| T0 : Show, - #| T1 : Show, - #| T2 : Show, - #| T3 : Show, - #| T4 : Show, - #| T5 : Show, - #| T6 : Show, - #| T7 : Show, - #| T8 : Show, - #| T9 : Show, - #| T10 : Show, - #| T11 : Show, - #| T12 : Show, - #| T13 : Show, - #| T14 : Show, - #|] Show for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14) with output( - #| self, - #| logger, - #|) { - #| let (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14) = self - #| logger - #| ..write_string("(") - #| ..write_object(x0) - #| ..write_string(", ") - #| ..write_object(x1) - #| ..write_string(", ") - #| ..write_object(x2) - #| ..write_string(", ") - #| ..write_object(x3) - #| ..write_string(", ") - #| ..write_object(x4) - #| ..write_string(", ") - #| ..write_object(x5) - #| ..write_string(", ") - #| ..write_object(x6) - #| ..write_string(", ") - #| ..write_object(x7) - #| ..write_string(", ") - #| ..write_object(x8) - #| ..write_string(", ") - #| ..write_object(x9) - #| ..write_string(", ") - #| ..write_object(x10) - #| ..write_string(", ") - #| ..write_object(x11) - #| ..write_string(", ") - #| ..write_object(x12) - #| ..write_string(", ") - #| ..write_object(x13) - #| ..write_string(", ") - #| ..write_object(x14) - #| ..write_string(")") - #|} - #|pub impl[ - #| T0 : Show, - #| T1 : Show, - #| T2 : Show, - #| T3 : Show, - #| T4 : Show, - #| T5 : Show, - #| T6 : Show, - #| T7 : Show, - #| T8 : Show, - #| T9 : Show, - #| T10 : Show, - #| T11 : Show, - #| T12 : Show, - #| T13 : Show, - #| T14 : Show, - #| T15 : Show, - #|] Show for ( - #| T0, - #| T1, - #| T2, - #| T3, - #| T4, - #| T5, - #| T6, - #| T7, - #| T8, - #| T9, - #| T10, - #| T11, - #| T12, - #| T13, - #| T14, - #| T15, - #|) with output(self, logger) { - #| let (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15) = self - #| logger - #| ..write_string("(") - #| ..write_object(x0) - #| ..write_string(", ") - #| ..write_object(x1) - #| ..write_string(", ") - #| ..write_object(x2) - #| ..write_string(", ") - #| ..write_object(x3) - #| ..write_string(", ") - #| ..write_object(x4) - #| ..write_string(", ") - #| ..write_object(x5) - #| ..write_string(", ") - #| ..write_object(x6) - #| ..write_string(", ") - #| ..write_object(x7) - #| ..write_string(", ") - #| ..write_object(x8) - #| ..write_string(", ") - #| ..write_object(x9) - #| ..write_string(", ") - #| ..write_object(x10) - #| ..write_string(", ") - #| ..write_object(x11) - #| ..write_string(", ") - #| ..write_object(x12) - #| ..write_string(", ") - #| ..write_object(x13) - #| ..write_string(", ") - #| ..write_object(x14) - #| ..write_string(", ") - #| ..write_object(x15) - #| ..write_string(")") - #|} - ), - "tuple_to_json.mbt": ( - #|pub impl[A : ToJson, B : ToJson] ToJson for (A, B) with to_json(self) { - #| let (a0, a1) = self - #| [a0, a1] - #|} - #|pub impl[A : ToJson, B : ToJson, C : ToJson] ToJson for (A, B, C) with to_json( - #| self, - #|) { - #| let (a0, a1, a2) = self - #| [a0, a1, a2] - #|} - #|pub impl[A : ToJson, B : ToJson, C : ToJson, D : ToJson] ToJson for (A, B, C, D) with to_json( - #| self, - #|) { - #| let (a0, a1, a2, a3) = self - #| [a0, a1, a2, a3] - #|} - #|pub impl[A : ToJson, B : ToJson, C : ToJson, D : ToJson, E : ToJson] ToJson for ( - #| A, - #| B, - #| C, - #| D, - #| E, - #|) with to_json(self) { - #| let (a0, a1, a2, a3, a4) = self - #| [a0, a1, a2, a3, a4] - #|} - #|pub impl[A : ToJson, B : ToJson, C : ToJson, D : ToJson, E : ToJson, F : ToJson] ToJson for ( - #| A, - #| B, - #| C, - #| D, - #| E, - #| F, - #|) with to_json(self) { - #| let (a0, a1, a2, a3, a4, a5) = self - #| [a0, a1, a2, a3, a4, a5] - #|} - #|pub impl[ - #| A : ToJson, - #| B : ToJson, - #| C : ToJson, - #| D : ToJson, - #| E : ToJson, - #| F : ToJson, - #| G : ToJson, - #|] ToJson for (A, B, C, D, E, F, G) with to_json(self) { - #| let (a0, a1, a2, a3, a4, a5, a6) = self - #| [a0, a1, a2, a3, a4, a5, a6] - #|} - #|pub impl[ - #| A : ToJson, - #| B : ToJson, - #| C : ToJson, - #| D : ToJson, - #| E : ToJson, - #| F : ToJson, - #| G : ToJson, - #| H : ToJson, - #|] ToJson for (A, B, C, D, E, F, G, H) with to_json(self) { - #| let (a0, a1, a2, a3, a4, a5, a6, a7) = self - #| [a0, a1, a2, a3, a4, a5, a6, a7] - #|} - #|pub impl[ - #| A : ToJson, - #| B : ToJson, - #| C : ToJson, - #| D : ToJson, - #| E : ToJson, - #| F : ToJson, - #| G : ToJson, - #| H : ToJson, - #| I : ToJson, - #|] ToJson for (A, B, C, D, E, F, G, H, I) with to_json(self) { - #| let (a0, a1, a2, a3, a4, a5, a6, a7, a8) = self - #| [a0, a1, a2, a3, a4, a5, a6, a7, a8] - #|} - #|pub impl[ - #| A : ToJson, - #| B : ToJson, - #| C : ToJson, - #| D : ToJson, - #| E : ToJson, - #| F : ToJson, - #| G : ToJson, - #| H : ToJson, - #| I : ToJson, - #| J : ToJson, - #|] ToJson for (A, B, C, D, E, F, G, H, I, J) with to_json(self) { - #| let (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) = self - #| [a0, a1, a2, a3, a4, a5, a6, a7, a8, a9] - #|} - #|pub impl[ - #| A : ToJson, - #| B : ToJson, - #| C : ToJson, - #| D : ToJson, - #| E : ToJson, - #| F : ToJson, - #| G : ToJson, - #| H : ToJson, - #| I : ToJson, - #| J : ToJson, - #| K : ToJson, - #|] ToJson for (A, B, C, D, E, F, G, H, I, J, K) with to_json(self) { - #| let (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) = self - #| [a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10] - #|} - #|pub impl[ - #| A : ToJson, - #| B : ToJson, - #| C : ToJson, - #| D : ToJson, - #| E : ToJson, - #| F : ToJson, - #| G : ToJson, - #| H : ToJson, - #| I : ToJson, - #| J : ToJson, - #| K : ToJson, - #| L : ToJson, - #|] ToJson for (A, B, C, D, E, F, G, H, I, J, K, L) with to_json(self) { - #| let (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11) = self - #| [a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11] - #|} - #|pub impl[ - #| A : ToJson, - #| B : ToJson, - #| C : ToJson, - #| D : ToJson, - #| E : ToJson, - #| F : ToJson, - #| G : ToJson, - #| H : ToJson, - #| I : ToJson, - #| J : ToJson, - #| K : ToJson, - #| L : ToJson, - #| M : ToJson, - #|] ToJson for (A, B, C, D, E, F, G, H, I, J, K, L, M) with to_json(self) { - #| let (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12) = self - #| [a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12] - #|} - #|pub impl[ - #| A : ToJson, - #| B : ToJson, - #| C : ToJson, - #| D : ToJson, - #| E : ToJson, - #| F : ToJson, - #| G : ToJson, - #| H : ToJson, - #| I : ToJson, - #| J : ToJson, - #| K : ToJson, - #| L : ToJson, - #| M : ToJson, - #| N : ToJson, - #|] ToJson for (A, B, C, D, E, F, G, H, I, J, K, L, M, N) with to_json(self) { - #| let (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13) = self - #| [a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13] - #|} - #|pub impl[ - #| A : ToJson, - #| B : ToJson, - #| C : ToJson, - #| D : ToJson, - #| E : ToJson, - #| F : ToJson, - #| G : ToJson, - #| H : ToJson, - #| I : ToJson, - #| J : ToJson, - #| K : ToJson, - #| L : ToJson, - #| M : ToJson, - #| N : ToJson, - #| O : ToJson, - #|] ToJson for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O) with to_json(self) { - #| let (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14) = self - #| [a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14] - #|} - #|pub impl[ - #| A : ToJson, - #| B : ToJson, - #| C : ToJson, - #| D : ToJson, - #| E : ToJson, - #| F : ToJson, - #| G : ToJson, - #| H : ToJson, - #| I : ToJson, - #| J : ToJson, - #| K : ToJson, - #| L : ToJson, - #| M : ToJson, - #| N : ToJson, - #| O : ToJson, - #| P : ToJson, - #|] ToJson for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P) with to_json(self) { - #| let (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15) = self - #| [a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15] - #|} - ), - "uint16_char.mbt": ( - #|pub fn UInt16::is_leading_surrogate(self : Self) -> Bool { - #| self >= 0xD800 && self <= 0xDBFF - #|} - #|pub fn UInt16::is_trailing_surrogate(self : Self) -> Bool { - #| self >= 0xDC00 && self <= 0xDFFF - #|} - #|pub fn UInt16::is_surrogate(self : Self) -> Bool { - #| self >= 0xD800 && self <= 0xDFFF - #|} - #|pub fn UInt16::unsafe_to_char(self : UInt16) -> Char { - #| self.to_int().unsafe_to_char() - #|} - #|pub fn UInt16::to_char(self : UInt16) -> Char? { - #| if self is (0..=0xD7FF) || self is (0xE000..<_) { - #| Some(self.unsafe_to_char()) - #| } else { - #| None - #| } - #|} - #|pub impl Add for UInt16 with add(self : UInt16, that : UInt16) -> UInt16 { - #| (self.to_int() + that.to_int()).to_uint16() - #|} - #|pub impl Sub for UInt16 with sub(self : UInt16, that : UInt16) -> UInt16 { - #| (self.to_int() - that.to_int()).to_uint16() - #|} - #|pub impl Mul for UInt16 with mul(self : UInt16, that : UInt16) -> UInt16 { - #| (self.to_int() * that.to_int()).to_uint16() - #|} - #|pub impl Div for UInt16 with div(self : UInt16, that : UInt16) -> UInt16 { - #| (self.to_int() / that.to_int()).to_uint16() - #|} - #|pub impl Mod for UInt16 with mod(self : UInt16, that : UInt16) -> UInt16 { - #| (self.to_int() % that.to_int()).to_uint16() - #|} - #|pub impl Eq for UInt16 with equal(self, that) { - #| self.to_int() == that.to_int() - #|} - #|pub impl Compare for UInt16 with compare(self, that) { - #| self.to_int().compare(that.to_int()) - #|} - #|pub impl Hash for UInt16 with hash_combine(self, hasher) { - #| hasher.combine_int(self.to_int()) - #|} - #|pub impl Shl for UInt16 with shl(self : UInt16, that : Int) -> UInt16 { - #| (self.to_int() << that).to_uint16() - #|} - #|pub impl Shr for UInt16 with shr(self : UInt16, that : Int) -> UInt16 { - #| (self.to_int() >> that).to_uint16() - #|} - #|pub impl BitOr for UInt16 with lor(self : UInt16, that : UInt16) -> UInt16 { - #| (self.to_int() | that.to_int()).to_uint16() - #|} - #|pub impl BitAnd for UInt16 with land(self : UInt16, that : UInt16) -> UInt16 { - #| (self.to_int() & that.to_int()).to_uint16() - #|} - #|pub impl BitXOr for UInt16 with lxor(self : UInt16, that : UInt16) -> UInt16 { - #| (self.to_int() ^ that.to_int()).to_uint16() - #|} - #|pub impl Default for UInt16 with default() { - #| 0 - #|} - #|pub impl ToJson for UInt16 with to_json(self : UInt16) -> Json { - #| Json::number(self.to_int().to_double()) - #|} - #|pub fn UInt16::to_uint(self : UInt16) -> UInt { - #| self.to_int().reinterpret_as_uint() - #|} - #|pub fn UInt16::to_uint64(self : UInt16) -> UInt64 { - #| self.to_int().to_uint64() - #|} - ), - "uint64.mbt": ( - #|pub impl Default for UInt64 with default() { - #| 0 - #|} - #|test { - #| inspect(0x7000_0001_1F00_100FUL.popcnt(), content="14") - #|} - ), - "uninitialized_array.mbt": ( - #|struct UninitializedArray[T](FixedArray[UnsafeMaybeUninit[T]]) - #|pub fn[T] UninitializedArray::make(size : Int) -> UninitializedArray[T] = "%fixedarray.make_uninit" - #|#alias("_[_]") - #|pub fn[T] UninitializedArray::at( - #| self : UninitializedArray[T], - #| index : Int, - #|) -> T = "%fixedarray.get" - #|#alias("_[_]=_") - #|pub fn[T] UninitializedArray::set( - #| self : UninitializedArray[T], - #| index : Int, - #| value : T, - #|) = "%fixedarray.set" - #|#alias("_[_:_]") - #|pub fn[T] UninitializedArray::sub( - #| self : UninitializedArray[T], - #| start? : Int = 0, - #| end? : Int, - #|) -> ArrayView[T] { - #| let len = self.length() - #| let end = match end { - #| None => len - #| Some(end) => end - #| } - #| guard start >= 0 && start <= end && end <= len else { - #| abort("View start index out of bounds") - #| } - #| ArrayView::make(self, start, end - start) - #|} - #|pub fn[A] UninitializedArray::length(self : UninitializedArray[A]) -> Int { - #| self.0.length() - #|} - #|#internal(unsafe, "For internal use only.") - #|#doc(hidden) - #|pub fn[T] UninitializedArray::unsafe_blit( - #| dst : UninitializedArray[T], - #| dst_offset : Int, - #| src : UninitializedArray[T], - #| src_offset : Int, - #| len : Int, - #|) -> Unit { - #| FixedArray::unsafe_blit(dst.0, dst_offset, src.0, src_offset, len) - #|} - #|test "as_view with valid_range" { - #| let arr : UninitializedArray[Int] = UninitializedArray::make(5) - #| let view = arr[1:4] - #| inspect(view.start(), content="1") - #| inspect(view.len(), content="3") - #|} - #|test "panic as_view with invalid_start" { - #| let arr : UninitializedArray[Int] = UninitializedArray::make(5) - #| ignore(arr[-1:]) - #|} - #|test "panic as_view with invalid_end" { - #| let arr : UninitializedArray[Int] = UninitializedArray::make(5) - #| ignore(arr[2:10]) - #|} - #|#intrinsic("%fixedarray.fill") - #|#cfg(not(target="js")) - #|fn[T] UninitializedArray::unchecked_fill( - #| self : UninitializedArray[T], - #| start : Int, - #| value : T, - #| len : Int, - #|) -> Unit { - #| for i in start..<(start + len) { - #| self[i] = value - #| } - #|} - ), - "unit.mbt": ( - #|pub impl Eq for Unit with equal(_ : Unit, _ : Unit) -> Bool { - #| true - #|} - ), - }, + "array.mbt": ( + #|pub fn[T] Array::from_fixed_array(arr : FixedArray[T]) -> Array[T] { + #| let len = arr.length() + #| let arr2 = Array::make_uninit(len) + #| UninitializedArray::unsafe_blit_fixed(arr2.buffer(), 0, arr, 0, len) + #| arr2 + #|} + #|pub fn[T] Array::make(len : Int, elem : T) -> Array[T] { + #| let arr = Array::make_uninit(len) + #| for i in 0.. T raise?) -> Array[T] raise? { + #| if length <= 0 { + #| [] + #| } else { + #| let array = Array::make_uninit(length) + #| for i in 0.. Int { + #| self.buffer().0.length() + #|} + #|#intrinsic("%array.unsafe_get") + #|pub fn[T] Array::unsafe_get(self : Array[T], idx : Int) -> T { + #| self.buffer()[idx] + #|} + #|#intrinsic("%array.get") + #|#alias("_[_]") + #|pub fn[T] Array::at(self : Array[T], index : Int) -> T { + #| let len = self.length() + #| guard index >= 0 && index < len + #| self.buffer()[index] + #|} + #|pub fn[T] Array::get(self : Array[T], index : Int) -> T? { + #| let len = self.length() + #| guard index >= 0 && index < len else { None } + #| Some(self.unsafe_get(index)) + #|} + #|#intrinsic("%array.unsafe_set") + #|pub fn[T] Array::unsafe_set(self : Array[T], idx : Int, val : T) -> Unit { + #| self.buffer()[idx] = val + #|} + #|#intrinsic("%array.set") + #|#alias("_[_]=_") + #|pub fn[T] Array::set(self : Array[T], index : Int, value : T) -> Unit { + #| let len = self.length() + #| guard index >= 0 && index < len + #| self.buffer()[index] = value + #|} + #|pub impl[T : Eq] Eq for Array[T] with equal(self, other) { + #| let self_len = self.length() + #| let other_len = other.length() + #| guard self_len == other_len else { return false } + #| for i in 0.. Unit { + #| other.blit_to(self, dst_offset=self.length()) + #|} + #|#locals(f) + #|pub fn[T] Array::each(self : Array[T], f : (T) -> Unit raise?) -> Unit raise? { + #| for v in self { + #| f(v) + #| } + #|} + #|#locals(f) + #|pub fn[T] Array::rev_each(self : Array[T], f : (T) -> Unit) -> Unit { + #| let len = self.length() + #| for i in 0.. Unit raise?, + #|) -> Unit raise? { + #| let len = self.length() + #| for i in 0.. Unit raise?, + #|) -> Unit raise? { + #| for i, v in self { + #| f(i, v) + #| } + #|} + #|#alias(every) + #|pub fn[T] Array::all(self : Array[T], f : (T) -> Bool raise?) -> Bool raise? { + #| self[:].all(f) + #|} + #|#alias(exists) + #|pub fn[T] Array::any(self : Array[T], f : (T) -> Bool raise?) -> Bool raise? { + #| self[:].any(f) + #|} + #|pub fn[T] Array::clear(self : Array[T]) -> Unit { + #| self.unsafe_truncate_to_length(0) + #|} + #|#locals(f) + #|pub fn[T, U] Array::map( + #| self : Array[T], + #| f : (T) -> U raise?, + #|) -> Array[U] raise? { + #| let arr = Array::make_uninit(self.length()) + #| for i, v in self { + #| arr.unsafe_set(i, f(v)) + #| } + #| arr + #|} + #|#locals(f) + #|#alias(map_inplace, deprecated) + #|pub fn[T] Array::map_in_place( + #| self : Array[T], + #| f : (T) -> T raise?, + #|) -> Unit raise? { + #| for i, v in self { + #| self[i] = f(v) + #| } + #|} + #|#locals(f) + #|pub fn[T, U] Array::mapi( + #| self : Array[T], + #| f : (Int, T) -> U raise?, + #|) -> Array[U] raise? { + #| if self.length() == 0 { + #| return [] + #| } + #| let arr = Array::make_uninit(self.length()) + #| for i, v in self { + #| arr.unsafe_set(i, f(i, v)) + #| } + #| arr + #|} + #|#locals(f) + #|#alias(mapi_inplace, deprecated) + #|pub fn[T] Array::mapi_in_place( + #| self : Array[T], + #| f : (Int, T) -> T raise?, + #|) -> Unit raise? { + #| for i, v in self { + #| self[i] = f(i, v) + #| } + #|} + #|#locals(f) + #|pub fn[T] Array::filter( + #| self : Array[T], + #| f : (T) -> Bool raise?, + #|) -> Array[T] raise? { + #| let arr = [] + #| for v in self { + #| if f(v) { + #| arr.push(v) + #| } + #| } + #| arr + #|} + #|pub fn[T] Array::is_empty(self : Array[T]) -> Bool { + #| self.length() == 0 + #|} + #|#alias(rev_inplace, deprecated) + #|pub fn[T] Array::rev_in_place(self : Array[T]) -> Unit { + #| let len = self.length() + #| for i in 0..<(len / 2) { + #| let temp = self.unsafe_get(i) + #| self.unsafe_set(i, self.unsafe_get(len - i - 1)) + #| self.unsafe_set(len - i - 1, temp) + #| } + #|} + #|pub fn[T] Array::rev(self : Array[T]) -> Array[T] { + #| let len = self.length() + #| let arr = Array::make_uninit(len) + #| for i in 0.. (Array[T], Array[T]) { + #| if index < 0 || index > self.length() { + #| let len = self.length() + #| abort( + #| "index out of bounds: the len is from 0 to \{len} but the index is \{index}", + #| ) + #| } + #| let v1 = Array::make_uninit(index) + #| let v2 = Array::make_uninit(self.length() - index) + #| UninitializedArray::unsafe_blit(v1.buffer(), 0, self.buffer(), 0, index) + #| if index != self.length() { + #| UninitializedArray::unsafe_blit( + #| v2.buffer(), + #| 0, + #| self.buffer(), + #| index, + #| self.length() - index, + #| ) + #| } + #| (v1, v2) + #|} + #|pub fn[T : Eq] Array::contains(self : Array[T], value : T) -> Bool { + #| for v in self { + #| if v == value { + #| break true + #| } + #| } nobreak { + #| false + #| } + #|} + #|pub fn[T : Eq] Array::starts_with(self : Array[T], prefix : Array[T]) -> Bool { + #| self[:].starts_with(prefix[:]) + #|} + #|pub fn[T : Eq] Array::ends_with(self : Array[T], suffix : Array[T]) -> Bool { + #| self[:].ends_with(suffix[:]) + #|} + #|pub fn[T : Eq] Array::strip_prefix( + #| self : Array[T], + #| prefix : Array[T], + #|) -> Array[T]? { + #| if self.starts_with(prefix) { + #| let v = Array::make_uninit(self.length() - prefix.length()) + #| UninitializedArray::unsafe_blit( + #| v.buffer(), + #| 0, + #| self.buffer(), + #| prefix.length(), + #| self.length() - prefix.length(), + #| ) + #| Some(v) + #| } else { + #| None + #| } + #|} + #|pub fn[T : Eq] Array::strip_suffix( + #| self : Array[T], + #| suffix : Array[T], + #|) -> Array[T]? { + #| if self.ends_with(suffix) { + #| let v = Array::make_uninit(self.length() - suffix.length()) + #| let len = self.length() - suffix.length() + #| UninitializedArray::unsafe_blit(v.buffer(), 0, self.buffer(), 0, len) + #| Some(v) + #| } else { + #| None + #| } + #|} + #|pub fn[T : Eq] Array::search(self : Array[T], value : T) -> Int? { + #| self[:].search(value) + #|} + #|#locals(f) + #|#alias(find_index, deprecated) + #|pub fn[T] Array::search_by(self : Array[T], f : (T) -> Bool) -> Int? { + #| for i, v in self { + #| if f(v) { + #| break Some(i) + #| } + #| } nobreak { + #| None + #| } + #|} + #|pub fn[T : Compare] Array::binary_search( + #| self : Array[T], + #| value : T, + #|) -> Result[Int, Int] { + #| self[:].binary_search(value) + #|} + #|pub fn[T] Array::binary_search_by( + #| self : Array[T], + #| cmp : (T) -> Int raise?, + #|) -> Result[Int, Int] raise? { + #| self[:].binary_search_by(cmp) + #|} + #|pub fn[T] Array::swap(self : Array[T], i : Int, j : Int) -> Unit { + #| if i >= self.length() || j >= self.length() || i < 0 || j < 0 { + #| let len = self.length() + #| abort( + #| "index out of bounds: the len is from 0 to \{len} but the index is (\{i}, \{j})", + #| ) + #| } + #| let temp = self.unsafe_get(i) + #| self.unsafe_set(i, self.unsafe_get(j)) + #| self.unsafe_set(j, temp) + #|} + #|#locals(f) + #|pub fn[T] Array::retain(self : Array[T], f : (T) -> Bool raise?) -> Unit raise? { + #| let len = self.length() + #| for i = 0, j = 0; i < len; { + #| let item = self.unsafe_get(i) + #| if f(item) { + #| self.unsafe_set(j, item) + #| continue i + 1, j + 1 + #| } + #| continue i + 1, j + #| } nobreak { + #| self.unsafe_truncate_to_length(j) + #| } + #|} + #|pub fn[T] Array::resize(self : Array[T], new_len : Int, f : T) -> Unit { + #| if new_len < 0 { + #| abort("negative new length") + #| } + #| if new_len < self.length() { + #| self.unsafe_truncate_to_length(new_len) + #| } else { + #| let len = self.length() + #| for _ in len.. Array[T] { + #| let len = for x in self; len = 0 { + #| continue len + x.length() + #| } nobreak { + #| len + #| } + #| let res = Array::make_uninit(len) + #| for xs in self; i = 0 { + #| res.unsafe_blit(i, xs, 0, xs.length()) + #| continue i + xs.length() + #| } + #| res + #|} + #|pub fn[T] Array::repeat(self : Array[T], times : Int) -> Array[T] { + #| let v = Array::new(capacity=self.length() * times) + #| for _ in 0.. B raise?, + #|) -> B raise? { + #| for item in self; acc = init { + #| continue f(acc, item) + #| } nobreak { + #| acc + #| } + #|} + #|#locals(f) + #|#alias(fold_right, deprecated) + #|pub fn[A, B] Array::rev_fold( + #| self : Array[A], + #| init~ : B, + #| f : (B, A) -> B raise?, + #|) -> B raise? { + #| for i = self.length() - 1, acc = init; i >= 0; { + #| continue i - 1, f(acc, self[i]) + #| } nobreak { + #| acc + #| } + #|} + #|#locals(f) + #|#alias(fold_lefti, deprecated) + #|pub fn[A, B] Array::foldi( + #| self : Array[A], + #| init~ : B, + #| f : (Int, B, A) -> B raise?, + #|) -> B raise? { + #| for i = 0, acc = init; i < self.length(); { + #| continue i + 1, f(i, acc, self[i]) + #| } nobreak { + #| acc + #| } + #|} + #|#locals(f) + #|#alias(fold_righti, deprecated) + #|pub fn[A, B] Array::rev_foldi( + #| self : Array[A], + #| init~ : B, + #| f : (Int, B, A) -> B raise?, + #|) -> B raise? { + #| let len = self.length() + #| for i = len - 1, acc = init; i >= 0; { + #| continue i - 1, f(len - i - 1, acc, self[i]) + #| } nobreak { + #| acc + #| } + #|} + #|pub fn[T : Eq] Array::dedup(self : Array[T]) -> Unit { + #| if self.is_empty() { + #| return + #| } + #| let w = for i in 1.. Bool) -> Array[T] { + #| let removed = [] + #| for read in 0.. Array[ArrayView[T]] { + #| guard size > 0 + #| let len = self.length() + #| if len == 0 { + #| return [] + #| } + #| let num_chunks = (len + size - 1) / size + #| Array::makei(num_chunks, i => { + #| let start = i * size + #| let end = Int::min(start + size, len) + #| self[start:end] + #| }) + #|} + #|#locals(pred) + #|pub fn[T] Array::chunk_by( + #| self : Array[T], + #| pred : (T, T) -> Bool raise?, + #|) -> Array[ArrayView[T]] raise? { + #| let chunks = [] + #| if self.is_empty() { + #| return chunks + #| } + #| let start = for i in 1.. Array[ArrayView[T]] { + #| guard size > 0 + #| let len = self.length() - size + 1 + #| if len < 1 { + #| return [] + #| } + #| Array::makei(len, i => self[i:i + size]) + #|} + #|pub fn[T] Array::suffixes( + #| self : Array[T], + #| include_empty? : Bool = false, + #|) -> Iter[ArrayView[T]] { + #| self[:].suffixes(include_empty~) + #|} + #|#locals(pred) + #|pub fn[T] Array::split( + #| self : Array[T], + #| pred : (T) -> Bool raise?, + #|) -> Array[Array[T]] raise? { + #| let chunks = [] + #| for i = 0; i < self.length(); { + #| let chunk = [] + #| let i = for i = i; i < self.length() && !pred(self[i]); { + #| chunk.push(self[i]) + #| continue i + 1 + #| } nobreak { + #| i + #| } + #| chunks.push(chunk) + #| continue i + 1 + #| } + #| chunks + #|} + #|#alias(iterator, deprecated) + #|pub fn[T] Array::iter(self : Array[T]) -> Iter[T] { + #| self[:].iter() + #|} + #|#alias(rev_iterator, deprecated) + #|pub fn[T] Array::rev_iter(self : Array[T]) -> Iter[T] { + #| self[:].rev_iter() + #|} + #|#alias(iterator2, deprecated) + #|pub fn[A] Array::iter2(self : Array[A]) -> Iter2[Int, A] { + #| self[:].iter2() + #|} + #|pub impl[T] Default for Array[T] with default() { + #| [] + #|} + #|#internal(unsafe, "Panic if the array is empty on non-JS backend.") + #|#doc(hidden) + #|pub fn[A] Array::unsafe_pop_back(self : Array[A]) -> Unit { + #| self.unsafe_pop() |> ignore + #|} + #|pub fn[A] Array::truncate(self : Array[A], len : Int) -> Unit { + #| guard len >= 0 && len < self.length() else { return } + #| self.unsafe_truncate_to_length(len) + #|} + #|pub fn[A] Array::retain_map(self : Array[A], f : (A) -> A?) -> Unit { + #| if self.is_empty() { + #| return + #| } + #| let buf = self.buffer() + #| let len = self.length() + #| for read_idx in 0.. { + #| buf[write_idx] = new_val + #| continue write_idx + 1 + #| } + #| None => continue write_idx + #| } + #| } nobreak { + #| self.unsafe_truncate_to_length(write_idx) + #| } + #|} + #|#alias(from_iterator, deprecated) + #|pub fn[T] Array::from_iter(iter : Iter[T]) -> Array[T] { + #| iter.collect() + #|} + #|pub fn[T] Array::push_iter(self : Self[T], iter : Iter[T]) -> Unit { + #| for x in iter { + #| self.push(x) + #| } + #|} + #|pub fn[T] Array::shuffle_in_place( + #| self : Array[T], + #| rand~ : (Int) -> Int, + #|) -> Unit { + #| let n = self.length() + #| for i in n>..1 { + #| let j = rand(i + 1) % (i + 1) + #| self.swap(i, j) + #| } + #|} + #|pub fn[T] Array::shuffle(self : Array[T], rand~ : (Int) -> Int) -> Array[T] { + #| let new_arr = self.copy() + #| Array::shuffle_in_place(new_arr, rand~) + #| new_arr + #|} + #|pub fn[A, B] Array::filter_map( + #| self : Array[A], + #| f : (A) -> B? raise?, + #|) -> Array[B] raise? { + #| let result = [] + #| for x in self { + #| if f(x) is Some(x) { + #| result.push(x) + #| } + #| } + #| result + #|} + #|pub fn[A] Array::last(self : Array[A]) -> A? { + #| match self { + #| [] => None + #| [.., last] => Some(last) + #| } + #|} + #|pub fn[A, B] Array::zip(self : Array[A], other : Array[B]) -> Array[(A, B)] { + #| let length = if self.length() < other.length() { + #| self.length() + #| } else { + #| other.length() + #| } + #| Array::makei(length, i => (self[i], other[i])) + #|} + #|pub fn[T1, T2] Array::unzip(self : Array[(T1, T2)]) -> (Array[T1], Array[T2]) { + #| let arr1 : Array[T1] = Array::new(capacity=self.length()) + #| let arr2 : Array[T2] = Array::new(capacity=self.length()) + #| for pair in self { + #| let (x, y) = pair + #| arr1.push(x) + #| arr2.push(y) + #| } + #| (arr1, arr2) + #|} + #|pub fn[A, B] Array::zip_to_iter2( + #| self : Array[A], + #| other : Array[B], + #|) -> Iter2[A, B] { + #| let length = if self.length() < other.length() { + #| self.length() + #| } else { + #| other.length() + #| } + #| let mut i = 0 + #| Iter2::new(() => { + #| guard i < length else { None } + #| let elem = (self[i], other[i]) + #| i += 1 + #| Some(elem) + #| }).iter2() + #|} + #|pub fn[A : ToStringView] Array::join( + #| self : Array[A], + #| separator : StringView, + #|) -> String { + #| self[:].join(separator) + #|} + #|pub fn[T : Compare] Array::lexical_compare( + #| self : Array[T], + #| other : Array[T], + #|) -> Int { + #| self[:].lexical_compare(other[:]) + #|} + ), + "array_block.mbt": ( + #|#internal(unsafe, "Panic if the indices or length are out of bounds") + #|#doc(hidden) + #|pub fn[A] Array::unsafe_blit( + #| dst : Array[A], + #| dst_offset : Int, + #| src : Array[A], + #| src_offset : Int, + #| len : Int, + #|) -> Unit { + #| FixedArray::unsafe_blit( + #| dst.buffer().0, + #| dst_offset, + #| src.buffer().0, + #| src_offset, + #| len, + #| ) + #|} + #|pub fn[A] Array::unsafe_blit_fixed( + #| dst : Array[A], + #| dst_offset : Int, + #| src : FixedArray[A], + #| src_offset : Int, + #| len : Int, + #|) -> Unit { + #| UninitializedArray::unsafe_blit_fixed( + #| dst.buffer(), + #| dst_offset, + #| src, + #| src_offset, + #| len, + #| ) + #|} + #|#label_migration(src_offset, fill=false, msg="Use ArrayView::blit_to instead") + #|#label_migration(len, fill=false, msg="Use ArrayView::blit_to instead") + #|pub fn[A] Array::blit_to( + #| self : Array[A], + #| dst : Array[A], + #| len? : Int = self.length(), + #| src_offset? : Int = 0, + #| dst_offset? : Int = 0, + #|) -> Unit { + #| guard len >= 0 && + #| dst_offset >= 0 && + #| src_offset >= 0 && + #| dst_offset <= dst.length() && + #| src_offset + len <= self.length() + #| if dst_offset + len > dst.length() { + #| dst.unsafe_grow_to_length(dst_offset + len) + #| } + #| Array::unsafe_blit(dst, dst_offset, self, src_offset, len) + #|} + #|pub fn[A] ArrayView::blit_to( + #| self : ArrayView[A], + #| dst : Array[A], + #| dst_offset? : Int = 0, + #|) -> Unit { + #| let len = self.len() + #| guard dst_offset >= 0 && dst_offset <= dst.length() + #| if dst_offset + len > dst.length() { + #| dst.unsafe_grow_to_length(dst_offset + len) + #| } + #| UninitializedArray::unsafe_blit( + #| dst.buffer(), + #| dst_offset, + #| self.buf(), + #| self.start(), + #| len, + #| ) + #|} + #|test "Array::blit_to/basic" { + #| let src = [1, 2, 3, 4, 5] + #| let dst = [0, 0, 0, 0, 0] + #| src[1:4].blit_to(dst, dst_offset=2) + #| inspect(dst, content="[0, 0, 2, 3, 4]") + #| let src = [1, 2, 3, 4, 5] + #| let dst = [0, 0, 0, 0, 0] + #| src[0:3].blit_to(dst) + #| inspect(dst, content="[1, 2, 3, 0, 0]") + #|} + #|test "Array::blit_to/zero_length" { + #| let src = [1, 2, 3] + #| let dst = [4, 5, 6] + #| src[0:0].blit_to(dst) + #| inspect(dst, content="[4, 5, 6]") + #|} + #|test "Array::blit_to/grow_destination" { + #| let src = [1, 2, 3, 4, 5] + #| let dst = [0, 0] + #| src[0:3].blit_to(dst, dst_offset=1) + #| inspect(dst, content="[0, 1, 2, 3]") + #|} + #|test "Array::blit_to/edge_cases" { + #| let src = [1, 2, 3, 4, 5] + #| let dst = [0, 0, 0, 0, 0] + #| src[1:3].blit_to(dst, dst_offset=2) + #| inspect(dst, content="[0, 0, 2, 3, 0]") + #| src[0:2].blit_to(src, dst_offset=3) + #| inspect(src, content="[1, 2, 3, 1, 2]") + #| src[0:0].blit_to(dst, dst_offset=0) + #| inspect(dst, content="[0, 0, 2, 3, 0]") + #| src[0:5].blit_to(dst) + #| inspect(dst, content="[1, 2, 3, 1, 2]") + #|} + #|test "panic Array::blit_to/boundary_cases1" { + #| let src = [1, 2, 3, 4, 5] + #| let dst = [0, 0, 0, 0, 0] + #| ignore(src[3:1].blit_to(dst)) + #|} + #|test "panic Array::blit_to/boundary_cases2" { + #| let src = [1, 2, 3, 4, 5] + #| let dst = [0, 0, 0, 0, 0] + #| ignore(src[-1:1].blit_to(dst)) + #|} + #|test "panic Array::blit_to/boundary_cases3" { + #| let src = [1, 2, 3, 4, 5] + #| let dst = [0, 0, 0, 0, 0] + #| ignore(src[0:6].blit_to(dst)) + #|} + #|test "panic Array::blit_to/boundary_cases4" { + #| let src = [1, 2, 3, 4, 5] + #| let dst = [0, 0, 0, 0, 0] + #| ignore(src[0:5].blit_to(dst, dst_offset=6)) + #|} + #|test "Array::blit_to - random cases" { + #| let src = [10, 20, 30, 40, 50] + #| let dst = [0, 0, 0, 0, 0] + #| src[2:4].blit_to(dst, dst_offset=1) + #| inspect(dst, content="[0, 30, 40, 0, 0]") + #| src[1:4].blit_to(dst, dst_offset=2) + #| inspect(dst, content="[0, 30, 20, 30, 40]") + #| src[4:5].blit_to(dst, dst_offset=4) + #| inspect(dst, content="[0, 30, 20, 30, 50]") + #|} + #|test "Array::blit_to - boundary cases" { + #| let src = [1, 2, 3, 4, 5] + #| let dst = [0, 0, 0, 0, 0] + #| src[4:5].blit_to(dst, dst_offset=0) + #| inspect(dst, content="[5, 0, 0, 0, 0]") + #| src[0:1].blit_to(dst, dst_offset=4) + #| inspect(dst, content="[5, 0, 0, 0, 1]") + #| src[3:5].blit_to(dst, dst_offset=3) + #| inspect(dst, content="[5, 0, 0, 4, 5]") + #|} + #|test "Array::unsafe_blit_fixed" { + #| let src = FixedArray::make(3, 1) // Create a FixedArray with 3 elements of value 1 + #| let dst = Array::make(5, 0) // Create an Array with 5 elements of value 0 + #| Array::unsafe_blit_fixed(dst, 1, src, 0, 2) // Copy 2 elements from src[0] to dst[1] + #| inspect(dst, content="[0, 1, 1, 0, 0]") + #|} + #|test "ArrayView::blit_to/basic" { + #| let src = [1, 2, 3, 4, 5] + #| let view = src[1:4] // view = [2, 3, 4] + #| let dst = [0, 0, 0, 0, 0] + #| view.blit_to(dst) + #| inspect(dst, content="[2, 3, 4, 0, 0]") + #|} + #|test "ArrayView::blit_to/with_offset" { + #| let src = [1, 2, 3, 4, 5] + #| let view = src[1:4] // view = [2, 3, 4] + #| let dst = [0, 0, 0, 0, 0] + #| view.blit_to(dst, dst_offset=2) + #| inspect(dst, content="[0, 0, 2, 3, 4]") + #|} + #|test "ArrayView::blit_to/grow_destination" { + #| let src = [1, 2, 3, 4, 5] + #| let view = src[1:4] // view = [2, 3, 4] + #| let dst = [0, 0] + #| view.blit_to(dst, dst_offset=1) + #| inspect(dst, content="[0, 2, 3, 4]") + #|} + #|test "ArrayView::blit_to/empty_view" { + #| let src = [1, 2, 3, 4, 5] + #| let view = src[2:2] // empty view + #| let dst = [0, 0, 0] + #| view.blit_to(dst) + #| inspect(dst, content="[0, 0, 0]") + #|} + #|test "ArrayView::blit_to/nested_view" { + #| let src = [1, 2, 3, 4, 5, 6, 7] + #| let view1 = src[1:6] // [2, 3, 4, 5, 6] + #| let view2 = view1[1:4] // [3, 4, 5] + #| let dst = [0, 0, 0, 0, 0] + #| view2.blit_to(dst, dst_offset=1) + #| inspect(dst, content="[0, 3, 4, 5, 0]") + #|} + #|test "panic ArrayView::blit_to/invalid_offset" { + #| let src = [1, 2, 3, 4, 5] + #| let view = src[1:4] + #| let dst = [0, 0, 0] + #| ignore(view.blit_to(dst, dst_offset=-1)) + #|} + #|test "panic ArrayView::blit_to/offset_exceeds_length" { + #| let src = [1, 2, 3, 4, 5] + #| let view = src[1:4] + #| let dst = [0, 0, 0] + #| ignore(view.blit_to(dst, dst_offset=4)) + #|} + ), + "array_sort.mbt": ( + #|pub fn[T] MutArrayView::sort_by(self : Self[T], cmp : (T, T) -> Int) -> Unit { + #| fixed_quick_sort_by(self, cmp, None, fixed_get_limit(self.length())) + #|} + #|pub fn[T : Compare] MutArrayView::sort(self : MutArrayView[T]) -> Unit { + #| fixed_quick_sort(self, None, fixed_get_limit(self.length())) + #|} + #|pub fn[T : Compare] MutArrayView::stable_sort(self : MutArrayView[T]) -> Unit { + #| timsort(self) + #|} + #|pub fn[T, K : Compare] MutArrayView::sort_by_key( + #| self : Self[T], + #| map : (T) -> K, + #|) -> Unit { + #| fixed_quick_sort_by( + #| self, + #| (a, b) => map(a).compare(map(b)), + #| None, + #| fixed_get_limit(self.length()), + #| ) + #|} + #|pub fn[T : Compare] ArrayView::is_sorted(self : ArrayView[T]) -> Bool { + #| for i in 1.. self[i] { + #| break false + #| } + #| } nobreak { + #| true + #| } + #|} + #|pub fn[T : Compare] Array::is_sorted(self : Array[T]) -> Bool { + #| self[:].is_sorted() + #|} + #|pub fn[T : Compare] Array::sort(self : Array[T]) -> Unit { + #| self.mut_view().sort() + #|} + #|pub fn[T, K : Compare] Array::sort_by_key( + #| self : Array[T], + #| map : (T) -> K, + #|) -> Unit { + #| self.mut_view().sort_by_key(map) + #|} + #|pub fn[T] Array::sort_by(self : Array[T], cmp : (T, T) -> Int) -> Unit { + #| self.mut_view().sort_by(cmp) + #|} + #|pub fn[T : Compare] FixedArray::is_sorted(arr : FixedArray[T]) -> Bool { + #| arr[:].is_sorted() + #|} + #|pub fn[T : Compare] FixedArray::stable_sort(self : FixedArray[T]) -> Unit { + #| self.mut_view().stable_sort() + #|} + #|pub fn[T, K : Compare] FixedArray::sort_by_key( + #| self : FixedArray[T], + #| map : (T) -> K, + #|) -> Unit { + #| self.mut_view().sort_by_key(map) + #|} + #|test "FixedArray::sort_by_key/basic" { + #| let arr : FixedArray[_] = [3, 1, 4, 1, 5] + #| arr.sort_by_key(x => x) + #| inspect(arr, content="[1, 1, 3, 4, 5]") + #| let arr2 : FixedArray[_] = [3, 1, 4, 1, 5] + #| arr2.sort_by_key(x => -x) + #| inspect(arr2, content="[5, 4, 3, 1, 1]") + #|} + #|pub fn[T] FixedArray::sort_by( + #| self : FixedArray[T], + #| cmp : (T, T) -> Int, + #|) -> Unit { + #| self.mut_view().sort_by(cmp) + #|} + #|test "FixedArray::sort_by: basic functionality" { + #| let arr : FixedArray[_] = [5, 3, 2, 4, 1] + #| arr.sort_by((a, b) => a - b) + #| inspect(arr, content="[1, 2, 3, 4, 5]") + #|} + #|test "FixedArray::sort_by: edge cases" { + #| let empty_arr : FixedArray[Int] = [] + #| empty_arr.sort_by((a, b) => a - b) + #| inspect(empty_arr, content="[]") + #| let single_element_arr : FixedArray[_] = [1] + #| single_element_arr.sort_by((a, b) => a - b) + #| inspect(single_element_arr, content="[1]") + #|} + #|test "FixedArray::sort_by: random cases" { + #| let random_arr1 : FixedArray[_] = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5] + #| random_arr1.sort_by((a, b) => a - b) + #| inspect(random_arr1, content="[1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9]") + #| let random_arr2 : FixedArray[_] = [7, 1, 8, 2, 8, 1, 8, 2, 8, 4, 5, 9] + #| random_arr2.sort_by((a, b) => a - b) + #| inspect(random_arr2, content="[1, 1, 2, 2, 4, 5, 7, 8, 8, 8, 8, 9]") + #| let random_arr3 : FixedArray[_] = [10, -1, 0, 10, -1, 0, 10, -1, 0] + #| random_arr3.sort_by((a, b) => a - b) + #| inspect(random_arr3, content="[-1, -1, -1, 0, 0, 0, 10, 10, 10]") + #|} + #|test "FixedArray::sort_by: large array" { + #| let large_arr = FixedArray::makei(1000, i => 1000 - i) + #| large_arr.sort_by((a, b) => a - b) + #| let expected = FixedArray::makei(1000, i => i + 1) + #| inspect(large_arr, content=expected.to_string()) + #|} + #|test "FixedArray::sort_by: negative numbers" { + #| let negative_arr : FixedArray[_] = [-5, -3, -2, -4, -1] + #| negative_arr.sort_by((a, b) => a - b) + #| inspect(negative_arr, content="[-5, -4, -3, -2, -1]") + #|} + #|test "FixedArray::sort_by: mixed positive and negative numbers" { + #| let mixed_arr : FixedArray[_] = [-5, 3, -2, 4, -1] + #| mixed_arr.sort_by((a, b) => a - b) + #| inspect(mixed_arr, content="[-5, -2, -1, 3, 4]") + #|} + ), + "array_sort_by_impl.mbt": ( + #|fn[T] fixed_quick_sort_by( + #| arr : MutArrayView[T], + #| cmp : (T, T) -> Int, + #| pred : T?, + #| limit : Int, + #|) -> Unit { + #| let bubble_sort_len = 16 + #| for limit = limit, arr = arr, pred = pred, was_partitioned = true, balanced = true { + #| let len = arr.length() + #| if len <= bubble_sort_len { + #| if len >= 2 { + #| fixed_bubble_sort_by(arr, cmp) + #| } + #| return + #| } + #| if limit == 0 { + #| fixed_heap_sort_by(arr, cmp) + #| return + #| } + #| let (pivot_index, likely_sorted) = fixed_choose_pivot_by(arr, cmp) + #| if was_partitioned && balanced && likely_sorted { + #| if fixed_try_bubble_sort_by(arr, cmp) { + #| return + #| } + #| } + #| let (pivot, partitioned) = fixed_partition_by(arr, cmp, pivot_index) + #| let was_partitioned = partitioned + #| let balanced = minimum(pivot, len - pivot) >= len / 8 + #| let limit = if !balanced { limit - 1 } else { limit } + #| if pred is Some(p) { + #| if cmp(p, arr[pivot]) == 0 { + #| let i = for i = pivot; i < len && cmp(p, arr[i]) == 0; { + #| continue i + 1 + #| } nobreak { + #| i + #| } + #| continue limit, arr.slice(i, len), pred, was_partitioned, balanced + #| } + #| } + #| let left = arr.slice(0, pivot) + #| let right = arr.slice(pivot + 1, len) + #| if left.length() < right.length() { + #| fixed_quick_sort_by(left, cmp, pred, limit) + #| continue limit, right, Some(arr[pivot]), was_partitioned, balanced + #| } else { + #| fixed_quick_sort_by(right, cmp, Some(arr[pivot]), limit) + #| continue limit, left, pred, was_partitioned, balanced + #| } + #| } + #|} + #|fn[T] fixed_try_bubble_sort_by( + #| arr : MutArrayView[T], + #| cmp : (T, T) -> Int, + #|) -> Bool { + #| let max_tries = 8 + #| for i in 1.. 0 && cmp(arr[j - 1], arr[j]) > 0; { + #| arr.swap(j, j - 1) + #| continue j - 1, false + #| } nobreak { + #| sorted + #| } + #| if !sorted { + #| let tries = tries + 1 + #| if tries > max_tries { + #| break false + #| } + #| continue tries + #| } else { + #| continue tries + #| } + #| } nobreak { + #| true + #| } + #|} + #|fn[T] fixed_bubble_sort_by(arr : MutArrayView[T], cmp : (T, T) -> Int) -> Unit { + #| for i in 1.. 0 && cmp(arr[j - 1], arr[j]) > 0; j = j - 1 { + #| arr.swap(j, j - 1) + #| } + #| } + #|} + #|test "try_bubble_sort" { + #| let arr : FixedArray[_] = [8, 7, 6, 5, 4, 3, 2, 1] + #| let sorted = fixed_try_bubble_sort_by(arr.mut_view(), (a, b) => a - b) + #| inspect(sorted, content="true") + #| assert_eq(arr, [1, 2, 3, 4, 5, 6, 7, 8]) + #|} + #|fn[T] fixed_partition_by( + #| arr : MutArrayView[T], + #| cmp : (T, T) -> Int, + #| pivot_index : Int, + #|) -> (Int, Bool) { + #| arr.swap(pivot_index, arr.length() - 1) + #| let pivot = arr[arr.length() - 1] + #| let (i, partitioned) = for + #| j in 0..<(arr.length() - 1) + #| i = 0, partitioned = true { + #| if cmp(arr[j], pivot) < 0 { + #| if i != j { + #| arr.swap(i, j) + #| continue i + 1, false + #| } else { + #| continue i + 1, partitioned + #| } + #| } else { + #| continue i, partitioned + #| } + #| } nobreak { + #| (i, partitioned) + #| } + #| arr.swap(i, arr.length() - 1) + #| (i, partitioned) + #|} + #|fn[T] fixed_choose_pivot_by( + #| arr : MutArrayView[T], + #| cmp : (T, T) -> Int, + #|) -> (Int, Bool) { + #| let len = arr.length() + #| let use_median_of_medians = 50 + #| let max_swaps = 4 * 3 + #| let mut swaps = 0 + #| let b = len / 4 * 2 + #| if len >= 8 { + #| let a = len / 4 * 1 + #| let c = len / 4 * 3 + #| let sort_2 = (a : Int, b : Int) => { + #| if cmp(arr[a], arr[b]) > 0 { + #| arr.swap(a, b) + #| swaps += 1 + #| } + #| } + #| let sort_3 = (a : Int, b : Int, c : Int) => { + #| sort_2(a, b) + #| sort_2(b, c) + #| sort_2(a, b) + #| } + #| if len > use_median_of_medians { + #| sort_3(a - 1, a, a + 1) + #| sort_3(b - 1, b, b + 1) + #| sort_3(c - 1, c, c + 1) + #| } + #| sort_3(a, b, c) + #| } + #| if swaps == max_swaps { + #| arr.rev_in_place() + #| (len - b - 1, true) + #| } else { + #| (b, swaps == 0) + #| } + #|} + #|fn[T] fixed_heap_sort_by(arr : MutArrayView[T], cmp : (T, T) -> Int) -> Unit { + #| let len = arr.length() + #| for i in (len / 2)>..0 { + #| fixed_sift_down_by(arr, i, cmp) + #| } + #| for i in len>..1 { + #| arr.swap(0, i) + #| fixed_sift_down_by(arr.slice(0, i), 0, cmp) + #| } + #|} + #|fn[T] fixed_sift_down_by( + #| arr : MutArrayView[T], + #| index : Int, + #| cmp : (T, T) -> Int, + #|) -> Unit { + #| let len = arr.length() + #| for index = index, child = index * 2 + 1; child < len; { + #| let child = if child + 1 < len && cmp(arr[child], arr[child + 1]) < 0 { + #| child + 1 + #| } else { + #| child + #| } + #| if cmp(arr[index], arr[child]) >= 0 { + #| return + #| } + #| arr.swap(index, child) + #| continue child, child * 2 + 1 + #| } + #|} + #|test "heap_sort" { + #| fixed_test_sort(arr => fixed_heap_sort_by(arr.mut_view(), (a, b) => a - b)) + #|} + #|test "bubble_sort" { + #| fixed_test_sort(arr => fixed_bubble_sort_by(arr.mut_view(), (a, b) => a - b)) + #|} + #|test "sort" { + #| fixed_test_sort(arr => arr.sort()) + #|} + #|test "sort_by" { + #| let arr = [5, 1, 3, 4, 2] + #| arr.mut_view().sort_by_key(x => -x) + #| assert_eq(arr, [5, 4, 3, 2, 1]) + #|} + #|test "sort_by_fallback" { + #| let arr = FixedArray::makei(100, i => if i % 2 == 0 { 1 } else { 0 }) + #| arr + #| .mut_view() + #| .sort_by( + #| (a, b) => if a < b { -1 } else { 1 }, + #| ) + #| assert_true(arr.is_sorted()) + #|} + ), + "array_sort_impl.mbt": ( + #|priv struct TimSortRun { + #| len : Int + #| start : Int + #|} + #|fn[T : Compare] timsort(arr : MutArrayView[T]) -> Unit { + #| let max_insertion = 20 + #| let len = arr.length() + #| if len <= max_insertion { + #| MutArrayView::insertion_sort(arr) + #| return + #| } + #| let runs : Array[TimSortRun] = [] + #| for start = 0, end = 0; end < len; { + #| let (streak_end, was_reversed) = find_streak(arr.mut_view(start~)) + #| let end = end + streak_end + #| if was_reversed { + #| arr.mut_view(start~, end~).rev_in_place() + #| } + #| let end = provide_sorted_batch(arr, start, end) + #| runs.push({ start, len: end - start }) + #| while true { + #| guard collapse(runs, len) is Some(r) else { break } + #| let left = runs[r] + #| let right = runs[r + 1] + #| merge(arr.slice(left.start, right.start + right.len), left.len) + #| runs[r + 1] = { start: left.start, len: left.len + right.len } + #| runs.remove(r) |> ignore + #| } + #| continue end, end + #| } + #|} + #|fn[T : Compare] MutArrayView::insertion_sort(arr : MutArrayView[T]) -> Unit { + #| for i in 1.. 0 && arr[j] < arr[j - 1]; j = j - 1 { + #| arr.swap(j, j - 1) + #| } + #| } + #|} + #|fn[T : Compare] merge(arr : MutArrayView[T], mid : Int) -> Unit { + #| let buf_len = arr.length() - mid + #| let buf : FixedArray[T] = FixedArray::make(buf_len, arr[mid]) + #| for i in 0..= + #| 0 && + #| p2 >= 0; { + #| if arr[p1] > buf[p2] { + #| arr[p] = arr[p1] + #| continue p1 - 1, p2, p - 1 + #| } else { + #| arr[p] = buf[p2] + #| continue p1, p2 - 1, p - 1 + #| } + #| } nobreak { + #| p2 + #| } + #| for i = buf_remaining; i >= 0; i = i - 1 { + #| arr[i] = buf[i] + #| } + #|} + #|fn[T : Compare] find_streak(arr : MutArrayView[T]) -> (Int, Bool) { + #| let len = arr.length() + #| if len < 2 { + #| return (len, false) + #| } + #| let assume_reverse = arr[1] < arr[0] + #| if assume_reverse { + #| let end = for idx in 2..= arr[idx - 1] { + #| continue + #| } + #| break idx + #| } nobreak { + #| len + #| } + #| (end, false) + #| } + #|} + #|fn[T : Compare] provide_sorted_batch( + #| arr : MutArrayView[T], + #| start : Int, + #| end : Int, + #|) -> Int { + #| let len = arr.length() + #| let min_insertion_run = 10 + #| let start_end_diff = end - start + #| if start_end_diff < min_insertion_run && end < len { + #| let sort_end = minimum(len, start + min_insertion_run) + #| MutArrayView::insertion_sort(arr.slice(start, sort_end)) + #| sort_end + #| } else { + #| end + #| } + #|} + #|fn collapse(runs : Array[TimSortRun], stop : Int) -> Int? { + #| let n : Int = runs.length() + #| if n >= 2 && + #| ( + #| runs[n - 1].start + runs[n - 1].len == stop || + #| runs[n - 2].len <= runs[n - 1].len || + #| (n >= 3 && runs[n - 3].len <= runs[n - 2].len + runs[n - 1].len) || + #| (n >= 4 && runs[n - 4].len <= runs[n - 3].len + runs[n - 2].len) + #| ) { + #| if n >= 3 && runs[n - 3].len < runs[n - 1].len { + #| Some(n - 3) + #| } else { + #| Some(n - 2) + #| } + #| } else { + #| None + #| } + #|} + #|pub fn[T : Compare] FixedArray::sort(self : FixedArray[T]) -> Unit { + #| self.mut_view().sort() + #|} + #|fn[T] MutArrayView::slice( + #| arr : MutArrayView[T], + #| start : Int, + #| end : Int, + #|) -> MutArrayView[T] { + #| arr.mut_view(start~, end~) + #|} + #|fn[T] MutArrayView::swap(arr : MutArrayView[T], i : Int, j : Int) -> Unit { + #| let temp = arr[i] + #| arr[i] = arr[j] + #| arr[j] = temp + #|} + #|fn[T] MutArrayView::rev_in_place(arr : MutArrayView[T]) -> Unit { + #| let len = arr.length() + #| let mid_len = len / 2 + #| for i in 0.. Unit { + #| let bubble_sort_len = 16 + #| for limit = limit, arr = arr, pred = pred, was_partitioned = true, balanced = true { + #| let len = arr.length() + #| if len <= bubble_sort_len { + #| if len >= 2 { + #| fixed_bubble_sort(arr) + #| } + #| return + #| } + #| if limit == 0 { + #| fixed_heap_sort(arr) + #| return + #| } + #| let (pivot_index, likely_sorted) = fixed_choose_pivot(arr) + #| if was_partitioned && balanced && likely_sorted { + #| if fixed_try_bubble_sort(arr) { + #| return + #| } + #| } + #| let (pivot, partitioned) = fixed_partition(arr, pivot_index) + #| let was_partitioned = partitioned + #| let balanced = minimum(pivot, len - pivot) >= len / 8 + #| let limit = if !balanced { limit - 1 } else { limit } + #| if pred is Some(p) { + #| if p == arr[pivot] { + #| let i = for i = pivot; i < len && p == arr[i]; { + #| continue i + 1 + #| } nobreak { + #| i + #| } + #| continue limit, arr.slice(i, len), pred, was_partitioned, balanced + #| } + #| } + #| let left = arr.slice(0, pivot) + #| let right = arr.slice(pivot + 1, len) + #| if left.length() < right.length() { + #| fixed_quick_sort(left, pred, limit) + #| continue limit, right, Some(arr[pivot]), was_partitioned, balanced + #| } else { + #| fixed_quick_sort(right, Some(arr[pivot]), limit) + #| continue limit, left, pred, was_partitioned, balanced + #| } + #| } + #|} + #|fn fixed_get_limit(len : Int) -> Int { + #| for len = len, limit = 0; len > 0; { + #| continue len / 2, limit + 1 + #| } nobreak { + #| limit + #| } + #|} + #|fn[T : Compare] fixed_try_bubble_sort(arr : MutArrayView[T]) -> Bool { + #| let max_tries = 8 + #| for i in 1.. 0 && arr[j - 1] > arr[j]; { + #| arr.swap(j, j - 1) + #| continue j - 1, false + #| } nobreak { + #| sorted + #| } + #| if !sorted { + #| let tries = tries + 1 + #| if tries > max_tries { + #| break false + #| } + #| continue tries + #| } else { + #| continue tries + #| } + #| } nobreak { + #| true + #| } + #|} + #|fn[T : Compare] fixed_bubble_sort(arr : MutArrayView[T]) -> Unit { + #| for i in 1.. 0 && arr[j - 1] > arr[j]; j = j - 1 { + #| arr.swap(j, j - 1) + #| } + #| } + #|} + #|test "fixed_try_bubble_sort" { + #| let arr : FixedArray[_] = [8, 7, 6, 5, 4, 3, 2, 1] + #| let sorted = fixed_try_bubble_sort(arr.mut_view()) + #| inspect(sorted, content="true") + #| assert_eq(arr, [1, 2, 3, 4, 5, 6, 7, 8]) + #|} + #|fn[T : Compare] fixed_partition( + #| arr : MutArrayView[T], + #| pivot_index : Int, + #|) -> (Int, Bool) { + #| arr.swap(pivot_index, arr.length() - 1) + #| let pivot = arr[arr.length() - 1] + #| let (i, partitioned) = for + #| j in 0..<(arr.length() - 1) + #| i = 0, partitioned = true { + #| if arr[j] < pivot { + #| if i != j { + #| arr.swap(i, j) + #| continue i + 1, false + #| } else { + #| continue i + 1, partitioned + #| } + #| } else { + #| continue i, partitioned + #| } + #| } nobreak { + #| (i, partitioned) + #| } + #| arr.swap(i, arr.length() - 1) + #| (i, partitioned) + #|} + #|fn[T : Compare] fixed_choose_pivot(arr : MutArrayView[T]) -> (Int, Bool) { + #| let len = arr.length() + #| let use_median_of_medians = 50 + #| let max_swaps = 4 * 3 + #| let mut swaps = 0 + #| let b = len / 4 * 2 + #| if len >= 8 { + #| let a = len / 4 * 1 + #| let c = len / 4 * 3 + #| let sort_2 = (a : Int, b : Int) => { + #| if arr[a] > arr[b] { + #| arr.swap(a, b) + #| swaps += 1 + #| } + #| } + #| let sort_3 = (a : Int, b : Int, c : Int) => { + #| sort_2(a, b) + #| sort_2(b, c) + #| sort_2(a, b) + #| } + #| if len > use_median_of_medians { + #| sort_3(a - 1, a, a + 1) + #| sort_3(b - 1, b, b + 1) + #| sort_3(c - 1, c, c + 1) + #| } + #| sort_3(a, b, c) + #| } + #| if swaps == max_swaps { + #| arr.rev_in_place() + #| (len - b - 1, true) + #| } else { + #| (b, swaps == 0) + #| } + #|} + #|fn[T : Compare] fixed_heap_sort(arr : MutArrayView[T]) -> Unit { + #| let len = arr.length() + #| for i in (len / 2)>..0 { + #| fixed_sift_down(arr, i) + #| } + #| for i in len>..1 { + #| arr.swap(0, i) + #| fixed_sift_down(arr.slice(0, i), 0) + #| } + #|} + #|fn[T : Compare] fixed_sift_down(arr : MutArrayView[T], index : Int) -> Unit { + #| let len = arr.length() + #| for index = index, child = index * 2 + 1; child < len; { + #| let child = if child + 1 < len && arr[child] < arr[child + 1] { + #| child + 1 + #| } else { + #| child + #| } + #| if arr[index] >= arr[child] { + #| return + #| } + #| arr.swap(index, child) + #| continue child, child * 2 + 1 + #| } + #|} + #|fn fixed_test_sort(f : (MutArrayView[Int]) -> Unit) -> Unit raise { + #| let arr : FixedArray[_] = [5, 4, 3, 2, 1] + #| f(arr.mut_view()) + #| assert_eq(arr, [1, 2, 3, 4, 5]) + #| let arr : FixedArray[_] = [5, 5, 5, 5, 1] + #| f(arr.mut_view()) + #| assert_eq(arr, [1, 5, 5, 5, 5]) + #| let arr : FixedArray[_] = [1, 2, 3, 4, 5] + #| f(arr.mut_view()) + #| assert_eq(arr, [1, 2, 3, 4, 5]) + #| let arr = FixedArray::make(1000, 0) + #| for i in 0..<1000 { + #| arr[i] = 1000 - i - 1 + #| } + #| for step in 1..<100 { + #| let i = step * 10 + #| arr.swap(i, i - 1) + #| } + #| f(arr.mut_view()) + #| let expected = FixedArray::make(1000, 0) + #| for i in 0..<1000 { + #| expected[i] = i + #| } + #| assert_eq(arr, expected) + #|} + #|test "fixed_heap_sort" { + #| fixed_test_sort(arr => fixed_heap_sort(arr.mut_view())) + #|} + #|test "fixed_bubble_sort" { + #| fixed_test_sort(arr => fixed_bubble_sort(arr.mut_view())) + #|} + #|test "sort" { + #| fixed_test_sort(arr => arr.sort()) + #|} + #|test "stable_sort" { + #| let arr : FixedArray[_] = [5, 1, 3, 4, 2] + #| arr.mut_view().stable_sort() + #| assert_eq(arr, [1, 2, 3, 4, 5]) + #| let arr = FixedArray::make(1000, 0) + #| for i in 0..<1000 { + #| arr[i] = 1000 - i - 1 + #| } + #| for step in 1..<100 { + #| let i = step * 10 + #| arr.swap(i, i - 1) + #| } + #| arr.mut_view().stable_sort() + #| let expected = FixedArray::make(1000, 0) + #| for i in 0..<1000 { + #| expected[i] = i + #| } + #| assert_eq(arr, expected) + #|} + #|test "stable_sort_complex" { + #| let run_lens = [86, 64, 21, 20, 22] + #| let total_len = run_lens.fold(init=0, (acc, x) => acc + x) + #| let arr = FixedArray::make(total_len, 0) + #| for i in 0.. Int { + #| if x > y { + #| y + #| } else { + #| x + #| } + #|} + ), + "arraycore_js.mbt": ( + #|#external + #|priv type JSValue + #|fn[T] JSValue::ofAny(array : T) -> JSValue = "%identity" + #|fn[T] JSValue::toAny(self : JSValue) -> T = "%identity" + #|#external + #|priv type JSArray + #|fn[T] JSArray::ofAnyArray(array : Array[T]) -> JSArray = "%identity" + #|fn[T] JSArray::toAnyArray(self : JSArray) -> Array[T] = "%identity" + #|fn[T] JSArray::ofAnyFixedArray(array : FixedArray[T]) -> JSArray = "%identity" + #|fn[T] JSArray::toAnyFixedArray(self : JSArray) -> FixedArray[T] = "%identity" + #|extern "js" fn JSArray::set_length(self : JSArray, new_len : Int) -> Unit = + #| #| (arr, len) => { arr.length = len; } + #|extern "js" fn JSArray::push(self : JSArray, value : JSValue) -> Unit = + #| #| (arr, val) => { arr.push(val); } + #|extern "js" fn JSArray::pop(self : JSArray) -> JSValue = + #| #| (arr) => arr.pop() + #|extern "js" fn JSArray::splice( + #| self : JSArray, + #| index : Int, + #| count : Int, + #|) -> JSArray = + #| #| (arr, idx, cnt) => arr.splice(idx, cnt) + #|extern "js" fn JSArray::splice1( + #| self : JSArray, + #| index : Int, + #| count : Int, + #| value : JSValue, + #|) -> JSArray = + #| #| (arr, idx, cnt, val) => arr.splice(idx, cnt, val) + #|extern "js" fn JSArray::fill( + #| self : JSArray, + #| value : JSValue, + #| start : Int, + #| end : Int, + #|) -> Unit = + #| #| (arr, val, start, end) => arr.fill(val, start, end) + #|extern "js" fn JSArray::copy(self : JSArray) -> JSArray = + #| #|(arr) => arr.slice(0) + #|#external + #|type Array[T] + #|fn[T] Array::make_uninit(len : Int) -> Array[T] = "%fixedarray.make_uninit" + #|pub fn[T] Array::new(capacity? : Int = 0) -> Array[T] { + #| ignore(capacity) + #| [] + #|} + #|pub fn[T] Array::length(self : Array[T]) -> Int = "%fixedarray.length" + #|fn[T] Array::unsafe_truncate_to_length(self : Array[T], new_len : Int) -> Unit { + #| JSArray::ofAnyArray(self).set_length(new_len) + #|} + #|fn[T] Array::buffer(self : Array[T]) -> UninitializedArray[T] = "%identity" + #|test "array_unsafe_blit_fixed" { + #| let src = FixedArray::make(5, 0) + #| let dst = UninitializedArray::make(5) + #| for i in 0..<5 { + #| src[i] = i + 1 + #| } + #| UninitializedArray::unsafe_blit_fixed(dst, 0, src, 0, 5) + #| for i in 0..<5 { + #| assert_eq(dst[i], src[i]) + #| } + #|} + #|test "UninitializedArray::unsafe_blit_fixed" { + #| let src = FixedArray::make(5, 0) + #| let dst = UninitializedArray::make(5) + #| for i in 0..<5 { + #| src[i] = i + 1 + #| } + #| UninitializedArray::unsafe_blit_fixed(dst, 0, src, 0, 5) + #| for i in 0..<5 { + #| assert_eq(dst[i], src[i]) + #| } + #|} + #|pub fn[T] Array::reserve_capacity(self : Array[T], capacity : Int) -> Unit { + #| ignore(self) + #| ignore(capacity) + #|} + #|pub fn[T] Array::shrink_to_fit(self : Array[T]) -> Unit { + #| ignore(self) + #|} + #|pub fn[T] Array::push(self : Array[T], value : T) -> Unit { + #| JSArray::ofAnyArray(self).push(JSValue::ofAny(value)) + #|} + #|pub fn[T] Array::pop(self : Array[T]) -> T? { + #| if self.length() == 0 { + #| None + #| } else { + #| let v = self.unsafe_pop() + #| Some(v) + #| } + #|} + #|#internal(unsafe, "Panic if the array is empty.") + #|#doc(hidden) + #|#alias(pop_exn, deprecated) + #|pub fn[T] Array::unsafe_pop(self : Array[T]) -> T { + #| JSArray::ofAnyArray(self).pop().toAny() + #|} + #|pub fn[T] Array::remove(self : Array[T], index : Int) -> T { + #| guard index >= 0 && index < self.length() else { + #| abort( + #| "index out of bounds: the len is from 0 to \{self.length()} but the index is \{index}", + #| ) + #| } + #| let value = self.buffer()[index] + #| let _ = JSArray::ofAnyArray(self).splice(index, 1) + #| value + #|} + #|pub fn[T] Array::drain(self : Array[T], begin : Int, end : Int) -> Array[T] { + #| guard begin >= 0 && end <= self.length() && begin <= end else { + #| abort( + #| "index out of bounds: the len is \{self.length()} but the index is (\{begin}, \{end})", + #| ) + #| } + #| JSArray::ofAnyArray(self).splice(begin, end - begin).toAnyArray() + #|} + #|pub fn[T] Array::insert(self : Array[T], index : Int, value : T) -> Unit { + #| guard index >= 0 && index <= self.length() else { + #| abort( + #| "index out of bounds: the len is from 0 to \{self.length()} but the index is \{index}", + #| ) + #| } + #| let _ = JSArray::ofAnyArray(self).splice1(index, 0, JSValue::ofAny(value)) + #|} + #|fn[T] Array::unsafe_grow_to_length(self : Array[T], new_len : Int) -> Unit { + #| guard new_len >= self.length() + #| JSArray::ofAnyArray(self).set_length(new_len) + #|} + #|pub fn[A] Array::fill( + #| self : Array[A], + #| value : A, + #| start? : Int = 0, + #| end? : Int, + #|) -> Unit { + #| let array_length = self.length() + #| guard array_length > 0 else { return } + #| guard start >= 0 && start < array_length + #| let end = match end { + #| None => array_length + #| Some(e) => { + #| guard e >= 0 && e <= array_length + #| e + #| } + #| } + #| JSArray::ofAnyArray(self).fill(JSValue::ofAny(value), start, end) + #|} + #|#alias(clone, deprecated) + #|pub fn[T] Array::copy(self : Array[T]) -> Array[T] { + #| JSArray::ofAnyArray(self).copy().toAnyArray() + #|} + ), + "arraycore_nonjs.mbt": ( + #|fn[T] UninitializedArray::set_null(self : UninitializedArray[T], index : Int) = "%fixedarray.set_null" + #|struct Array[T] { + #| mut buf : UninitializedArray[T] + #| mut len : Int + #|} + #|fn[T] Array::make_uninit(len : Int) -> Array[T] { + #| { buf: UninitializedArray::make(len), len } + #|} + #|pub fn[T] Array::new(capacity? : Int = 0) -> Array[T] { + #| if capacity == 0 { + #| [] + #| } else { + #| { buf: UninitializedArray::make(capacity), len: 0 } + #| } + #|} + #|#intrinsic("%array.length") + #|pub fn[T] Array::length(self : Array[T]) -> Int { + #| self.len + #|} + #|fn[T] Array::unsafe_truncate_to_length(self : Array[T], new_len : Int) -> Unit { + #| let len = self.length() + #| guard new_len <= len + #| for i in new_len.. UninitializedArray[T] { + #| self.buf + #|} + #|fn[T] Array::resize_buffer(self : Array[T], new_capacity : Int) -> Unit { + #| let new_buf = UninitializedArray::make(new_capacity) + #| let old_buf = self.buf + #| let old_cap = old_buf.0.length() + #| let copy_len = if old_cap < new_capacity { old_cap } else { new_capacity } + #| UninitializedArray::unsafe_blit(new_buf, 0, old_buf, 0, copy_len) + #| self.buf = new_buf + #|} + #|test "array_unsafe_blit_fixed" { + #| let src = FixedArray::make(5, 0) + #| let dst = UninitializedArray::make(5) + #| for i in 0..<5 { + #| src[i] = i + 1 + #| } + #| UninitializedArray::unsafe_blit_fixed(dst, 0, src, 0, 5) + #| for i in 0..<5 { + #| assert_eq(dst[i], src[i]) + #| } + #|} + #|test "UninitializedArray::unsafe_blit_fixed" { + #| let src = FixedArray::make(5, 0) + #| let dst = UninitializedArray::make(5) + #| for i in 0..<5 { + #| src[i] = i + 1 + #| } + #| UninitializedArray::unsafe_blit_fixed(dst, 0, src, 0, 5) + #| for i in 0..<5 { + #| assert_eq(dst[i], src[i]) + #| } + #|} + #|test "Array::resize_buffer" { + #| let arr = Array::new(capacity=2) + #| arr.push(1) + #| arr.push(2) + #| arr.resize_buffer(4) + #| assert_eq(arr.buffer().0.length() >= 4, true) + #| arr.push(3) + #| arr.push(4) + #| assert_eq(arr.length(), 4) + #| assert_eq(arr[0], 1) + #| assert_eq(arr[1], 2) + #| assert_eq(arr[2], 3) + #| assert_eq(arr[3], 4) + #|} + #|fn[T] Array::realloc(self : Array[T]) -> Unit { + #| let old_cap = self.length() + #| let new_cap = if old_cap == 0 { 8 } else { old_cap * 2 } + #| self.resize_buffer(new_cap) + #|} + #|pub fn[T] Array::reserve_capacity(self : Array[T], capacity : Int) -> Unit { + #| if self.capacity() >= capacity { + #| return + #| } + #| self.resize_buffer(capacity) + #|} + #|pub fn[T] Array::shrink_to_fit(self : Array[T]) -> Unit { + #| if self.capacity() <= self.length() { + #| return + #| } + #| self.resize_buffer(self.length()) + #|} + #|pub fn[T] Array::push(self : Array[T], value : T) -> Unit { + #| if self.length() == self.buffer().0.length() { + #| self.realloc() + #| } + #| let length = self.length() + #| self.unsafe_set(length, value) + #| self.len = length + 1 + #|} + #|pub fn[T] Array::pop(self : Array[T]) -> T? { + #| let len = self.length() + #| if len == 0 { + #| None + #| } else { + #| let index = len - 1 + #| let v = self.unsafe_get(index) + #| self.buf.set_null(index) + #| self.len = index + #| Some(v) + #| } + #|} + #|#internal(unsafe, "Panic if the array is empty.") + #|#doc(hidden) + #|#alias(pop_exn, deprecated) + #|pub fn[T] Array::unsafe_pop(self : Array[T]) -> T { + #| let len = self.length() + #| guard len != 0 + #| let index = len - 1 + #| let v = self.unsafe_get(index) + #| self.buf.set_null(index) + #| self.len = index + #| v + #|} + #|pub fn[T] Array::remove(self : Array[T], index : Int) -> T { + #| guard index >= 0 && index < self.length() else { + #| abort( + #| "index out of bounds: the len is from 0 to \{self.length()} but the index is \{index}", + #| ) + #| } + #| let value = self.unsafe_get(index) + #| UninitializedArray::unsafe_blit( + #| self.buffer(), + #| index, + #| self.buffer(), + #| index + 1, + #| self.length() - index - 1, + #| ) + #| self.unsafe_truncate_to_length(self.length() - 1) + #| value + #|} + #|pub fn[T] Array::drain(self : Array[T], begin : Int, end : Int) -> Array[T] { + #| guard begin >= 0 && end <= self.length() && begin <= end + #| let num = end - begin + #| let v = Array::make_uninit(num) + #| UninitializedArray::unsafe_blit(v.buffer(), 0, self.buffer(), begin, num) + #| UninitializedArray::unsafe_blit( + #| self.buffer(), + #| begin, + #| self.buffer(), + #| end, + #| self.length() - end, + #| ) + #| self.unsafe_truncate_to_length(self.length() - num) + #| v + #|} + #|pub fn[T] Array::insert(self : Array[T], index : Int, value : T) -> Unit { + #| guard index >= 0 && index <= self.length() else { + #| abort( + #| "index out of bounds: the len is from 0 to \{self.length()} but the index is \{index}", + #| ) + #| } + #| if self.length() == self.buffer().0.length() { + #| self.realloc() + #| } + #| UninitializedArray::unsafe_blit( + #| self.buffer(), + #| index + 1, + #| self.buffer(), + #| index, + #| self.length() - index, + #| ) + #| let length = self.length() + #| self.unsafe_set(index, value) + #| self.len = length + 1 + #|} + #|fn[T] Array::unsafe_grow_to_length(self : Array[T], new_len : Int) -> Unit { + #| guard new_len >= self.length() + #| let new_buf = UninitializedArray::make(new_len) + #| UninitializedArray::unsafe_blit(new_buf, 0, self.buf, 0, self.len) + #| self.len = new_len + #| self.buf = new_buf + #|} + #|pub fn[A] Array::fill( + #| self : Array[A], + #| value : A, + #| start? : Int = 0, + #| end? : Int, + #|) -> Unit { + #| let array_length = self.length() + #| guard array_length > 0 else { return } + #| guard start >= 0 && start < array_length + #| let length = match end { + #| None => array_length + #| Some(e) => { + #| guard e >= start && e <= array_length + #| e + #| } + #| } + #| self.buf.unchecked_fill(start, value, length - start) + #|} + #|#alias(clone, deprecated) + #|pub fn[T] Array::copy(self : Array[T]) -> Array[T] { + #| let len = self.length() + #| if len == 0 { + #| [] + #| } else { + #| let arr = Array::make(len, self[0]) + #| Array::unsafe_blit(arr, 0, self, 0, len) + #| arr + #| } + #|} + ), + "arrayview.mbt": ( + #|#builtin.valtype + #|type ArrayView[T] + #|fn[T] ArrayView::buf(self : ArrayView[T]) -> UninitializedArray[T] = "%arrayview.buf" + #|fn[T] ArrayView::start(self : ArrayView[T]) -> Int = "%arrayview.start" + #|fn[T] ArrayView::len(self : ArrayView[T]) -> Int = "%arrayview.len" + #|fn[T] ArrayView::make( + #| buf : UninitializedArray[T], + #| start : Int, + #| len : Int, + #|) -> ArrayView[T] = "%arrayview.make" + #|pub fn[T] ArrayView::length(self : ArrayView[T]) -> Int { + #| self.len() + #|} + #|pub fn[T] ArrayView::is_empty(self : ArrayView[T]) -> Bool { + #| self.length() == 0 + #|} + #|pub fn[T] ArrayView::start_offset(self : Self[T]) -> Int { + #| self.start() + #|} + #|#alias("_[_]") + #|pub fn[T] ArrayView::at(self : ArrayView[T], index : Int) -> T { + #| guard index >= 0 && index < self.len() else { + #| abort( + #| "index out of bounds: the len is from 0 to \{self.len()} but the index is \{index}", + #| ) + #| } + #| self.buf()[self.start() + index] + #|} + #|pub fn[T] ArrayView::get(self : ArrayView[T], index : Int) -> T? { + #| let len = self.length() + #| guard index >= 0 && index < len else { None } + #| Some(self.buf()[self.start() + index]) + #|} + #|pub fn[T] ArrayView::last(self : ArrayView[T]) -> T? { + #| let len = self.length() + #| if len == 0 { + #| None + #| } else { + #| Some(self.unsafe_get(len - 1)) + #| } + #|} + #|#intrinsic("%arrayview.unsafe_get") + #|#internal(unsafe, "Panic if index is out of bounds") + #|#doc(hidden) + #|pub fn[T] ArrayView::unsafe_get(self : ArrayView[T], index : Int) -> T { + #| self.buf()[self.start() + index] + #|} + #|#alias("_[_:_]") + #|#alias(sub, deprecated="Use _[_:_] instead") + #|pub fn[T] Array::view( + #| self : Array[T], + #| start? : Int = 0, + #| end? : Int, + #|) -> ArrayView[T] { + #| let len = self.length() + #| let end = match end { + #| None => len + #| Some(end) => if end < 0 { len + end } else { end } + #| } + #| let start = if start < 0 { len + start } else { start } + #| guard start >= 0 && start <= end && end <= len else { + #| abort("View index out of bounds") + #| } + #| ArrayView::make(self.buffer(), start, end - start) + #|} + #|pub fn[T] Array::get_view( + #| self : Array[T], + #| start? : Int = 0, + #| end? : Int, + #|) -> ArrayView[T]? { + #| let len = self.length() + #| let end = match end { + #| None => len + #| Some(end) => if end < 0 { len + end } else { end } + #| } + #| let start = if start < 0 { len + start } else { start } + #| guard start >= 0 && start <= end && end <= len else { None } + #| Some(ArrayView::make(self.buffer(), start, end - start)) + #|} + #|#alias("_[_:_]") + #|#alias(sub, deprecated="Use _[_:_] instead") + #|pub fn[T] ArrayView::view( + #| self : ArrayView[T], + #| start? : Int = 0, + #| end? : Int, + #|) -> ArrayView[T] { + #| let len = self.length() + #| let end = match end { + #| None => len + #| Some(end) => if end < 0 { len + end } else { end } + #| } + #| let start = if start < 0 { len + start } else { start } + #| guard start >= 0 && start <= end && end <= len else { + #| abort("View index out of bounds") + #| } + #| ArrayView::make(self.buf(), self.start() + start, end - start) + #|} + #|pub fn[T] ArrayView::get_view( + #| self : ArrayView[T], + #| start? : Int = 0, + #| end? : Int, + #|) -> ArrayView[T]? { + #| let len = self.length() + #| let end = match end { + #| None => len + #| Some(end) => if end < 0 { len + end } else { end } + #| } + #| let start = if start < 0 { len + start } else { start } + #| guard start >= 0 && start <= end && end <= len else { None } + #| Some(ArrayView::make(self.buf(), self.start() + start, end - start)) + #|} + #|fn[T] unsafe_cast_fixedarray_to_uninitializedarray( + #| arr : FixedArray[T], + #|) -> UninitializedArray[T] = "%identity" + #|#alias("_[_:_]") + #|#alias(sub, deprecated="Use _[_:_] instead") + #|pub fn[T] FixedArray::view( + #| self : FixedArray[T], + #| start? : Int = 0, + #| end? : Int, + #|) -> ArrayView[T] { + #| let len = self.length() + #| let end = match end { + #| None => len + #| Some(end) => if end < 0 { len + end } else { end } + #| } + #| let start = if start < 0 { len + start } else { start } + #| guard start >= 0 && start <= end && end <= len else { + #| abort("View index out of bounds") + #| } + #| ArrayView::make( + #| unsafe_cast_fixedarray_to_uninitializedarray(self), + #| start, + #| end - start, + #| ) + #|} + #|pub fn[T] FixedArray::get_view( + #| self : FixedArray[T], + #| start? : Int = 0, + #| end? : Int, + #|) -> ArrayView[T]? { + #| let len = self.length() + #| let end = match end { + #| None => len + #| Some(end) => if end < 0 { len + end } else { end } + #| } + #| let start = if start < 0 { len + start } else { start } + #| guard start >= 0 && start <= end && end <= len else { None } + #| Some( + #| ArrayView::make( + #| unsafe_cast_fixedarray_to_uninitializedarray(self), + #| start, + #| end - start, + #| ), + #| ) + #|} + #|pub fn[T] ArrayView::suffixes( + #| self : Self[T], + #| include_empty? : Bool = false, + #|) -> Iter[ArrayView[T]] { + #| let len = self.length() + #| let mut i = 0 + #| Iter::new(fn() -> ArrayView[T]? { + #| if i < len { + #| let suffix = self[i:] + #| i += 1 + #| Some(suffix) + #| } else if i == len { + #| i += 1 + #| if include_empty { + #| Some(self[len:]) + #| } else { + #| None + #| } + #| } else { + #| None + #| } + #| }) + #|} + #|#alias(iterator, deprecated) + #|pub fn[X] ArrayView::iter(self : ArrayView[X]) -> Iter[X] { + #| let mut i = 0 + #| Iter::new(fn() { + #| guard i < self.length() else { None } + #| let elem = self.unsafe_get(i) + #| i += 1 + #| Some(elem) + #| }) + #|} + #|#alias(rev_iterator, deprecated) + #|pub fn[X] ArrayView::rev_iter(self : ArrayView[X]) -> Iter[X] { + #| let mut i = self.length() + #| Iter::new(fn() { + #| guard i > 0 else { None } + #| i -= 1 + #| Some(self.unsafe_get(i)) + #| }) + #|} + #|#alias(iterator2, deprecated) + #|pub fn[X] ArrayView::iter2(self : ArrayView[X]) -> Iter2[Int, X] { + #| let mut i = 0 + #| Iter2::new(fn() { + #| guard i < self.length() else { None } + #| let result = Some((i, self.unsafe_get(i))) + #| i += 1 + #| result + #| }) + #|} + #|pub fn[T] ArrayView::each( + #| self : ArrayView[T], + #| f : (T) -> Unit raise?, + #|) -> Unit raise? { + #| for v in self { + #| f(v) + #| } + #|} + #|pub fn[T] ArrayView::eachi( + #| self : ArrayView[T], + #| f : (Int, T) -> Unit raise?, + #|) -> Unit raise? { + #| for i, v in self { + #| f(i, v) + #| } + #|} + #|#alias(every) + #|pub fn[T] ArrayView::all( + #| self : ArrayView[T], + #| f : (T) -> Bool raise?, + #|) -> Bool raise? { + #| for v in self { + #| if !f(v) { + #| return false + #| } + #| } + #| true + #|} + #|#alias(exists) + #|pub fn[T] ArrayView::any( + #| self : ArrayView[T], + #| f : (T) -> Bool raise?, + #|) -> Bool raise? { + #| for v in self { + #| if f(v) { + #| return true + #| } + #| } + #| false + #|} + #|pub fn[T : Eq] ArrayView::contains(self : ArrayView[T], value : T) -> Bool { + #| for v in self { + #| if v == value { + #| break true + #| } + #| } nobreak { + #| false + #| } + #|} + #|pub fn[T : Eq] ArrayView::search(self : ArrayView[T], value : T) -> Int? { + #| for i in 0.. Bool { + #| if prefix.length() > self.length() { + #| return false + #| } + #| for i in 0.. Bool { + #| let suffix_len = suffix.length() + #| let self_len = self.length() + #| if suffix_len > self_len { + #| return false + #| } + #| for i in 0.. Result[Int, Int] { + #| let len = self.length() + #| for i = 0, j = len; i < j; { + #| let h = i + (j - i) / 2 + #| if self.unsafe_get(h) < value { + #| continue h + 1, j + #| } else { + #| continue i, h + #| } + #| } nobreak { + #| if i < len && self.unsafe_get(i) == value { + #| Ok(i) + #| } else { + #| Err(i) + #| } + #| } + #|} + #|#locals(cmp) + #|pub fn[T] ArrayView::binary_search_by( + #| self : ArrayView[T], + #| cmp : (T) -> Int raise?, + #|) -> Result[Int, Int] raise? { + #| let len = self.length() + #| for i = 0, j = len; i < j; { + #| let h = i + (j - i) / 2 + #| if cmp(self.unsafe_get(h)) < 0 { + #| continue h + 1, j + #| } else { + #| continue i, h + #| } + #| } nobreak { + #| if i < len && cmp(self.unsafe_get(i)) == 0 { + #| Ok(i) + #| } else { + #| Err(i) + #| } + #| } + #|} + #|pub fn[A, B] ArrayView::fold( + #| self : ArrayView[A], + #| init~ : B, + #| f : (B, A) -> B raise?, + #|) -> B raise? { + #| for i = 0, acc = init; i < self.length(); { + #| continue i + 1, f(acc, self[i]) + #| } nobreak { + #| acc + #| } + #|} + #|pub fn[A, B] ArrayView::rev_fold( + #| self : ArrayView[A], + #| init~ : B, + #| f : (B, A) -> B raise?, + #|) -> B raise? { + #| for i = self.length() - 1, acc = init; i >= 0; { + #| continue i - 1, f(acc, self[i]) + #| } nobreak { + #| acc + #| } + #|} + #|pub fn[A, B] ArrayView::foldi( + #| self : ArrayView[A], + #| init~ : B, + #| f : (Int, B, A) -> B raise?, + #|) -> B raise? { + #| for i = 0, acc = init; i < self.length(); { + #| continue i + 1, f(i, acc, self[i]) + #| } nobreak { + #| acc + #| } + #|} + #|pub fn[A, B] ArrayView::rev_foldi( + #| self : ArrayView[A], + #| init~ : B, + #| f : (Int, B, A) -> B raise?, + #|) -> B raise? { + #| let len = self.length() + #| for i = len - 1, acc = init; i >= 0; { + #| continue i - 1, f(len - i - 1, acc, self[i]) + #| } nobreak { + #| acc + #| } + #|} + #|pub fn[T, U] ArrayView::map( + #| self : ArrayView[T], + #| f : (T) -> U raise?, + #|) -> Array[U] raise? { + #| if self.length() == 0 { + #| return [] + #| } + #| Array::makei(self.length(), i => f(self[i])) + #|} + #|pub fn[T, U] ArrayView::mapi( + #| self : ArrayView[T], + #| f : (Int, T) -> U raise?, + #|) -> Array[U] raise? { + #| if self.length() == 0 { + #| return [] + #| } + #| Array::makei(self.length(), i => f(i, self[i])) + #|} + #|pub fn[T] ArrayView::filter( + #| self : ArrayView[T], + #| f : (T) -> Bool raise?, + #|) -> Array[T] raise? { + #| let arr = [] + #| for v in self { + #| if f(v) { + #| arr.push(v) + #| } + #| } + #| arr + #|} + #|pub fn[T] ArrayView::to_array(self : ArrayView[T]) -> Array[T] { + #| let len = self.length() + #| if len == 0 { + #| [] + #| } else { + #| let arr = Array::make(len, self[0]) + #| for i, v in self { + #| arr[i] = v + #| } + #| arr + #| } + #|} + #|pub fn[A : ToStringView] ArrayView::join( + #| self : ArrayView[A], + #| separator : StringView, + #|) -> String { + #| match self { + #| [] => "" + #| [hd, .. tl] => { + #| let hd = hd.to_string_view() + #| let size_hint = for s in tl; size_hint = hd.length() { + #| continue size_hint + s.to_string_view().length() + separator.length() + #| } nobreak { + #| size_hint + #| } + #| let size_hint = size_hint << 1 + #| let buf = StringBuilder::new(size_hint~) + #| buf.write_view(hd) + #| if separator is "" { + #| for s in tl { + #| let s = s.to_string_view() + #| buf.write_view(s) + #| } + #| } else { + #| for s in tl { + #| let s = s.to_string_view() + #| buf.write_view(separator) + #| buf.write_view(s) + #| } + #| } + #| buf.to_string() + #| } + #| } + #|} + #|pub fn[T : Compare] ArrayView::lexical_compare( + #| self : ArrayView[T], + #| other : ArrayView[T], + #|) -> Int { + #| let self_len = self.length() + #| let other_len = other.length() + #| let min_len = if self_len < other_len { self_len } else { other_len } + #| for i in 0.. Bool { + #| if self.length() != other.length() { + #| return false + #| } + #| for i in 0.. Int { + #| let len_self = self.length() + #| let len_other = other.length() + #| let cmp = len_self.compare(len_other) + #| guard cmp == 0 else { return cmp } + #| for i in 0.. String { + #| let buf = StringBuilder::new(size_hint=50) + #| t.output(buf) + #| buf.to_string() + #|} + #|#callsite(autofill(loc)) + #|#coverage.skip + #|pub fn[T : Eq + Show] assert_eq( + #| a : T, + #| b : T, + #| msg? : String, + #| loc~ : SourceLoc, + #|) -> Unit raise { + #| if a != b { + #| let fail_msg = match msg { + #| Some(msg) => msg + #| None => "`\{debug_string(a)} != \{debug_string(b)}`" + #| } + #| fail(fail_msg, loc~) + #| } + #|} + #|#callsite(autofill(loc)) + #|#coverage.skip + #|pub fn[T : Eq + Show] assert_not_eq( + #| a : T, + #| b : T, + #| msg? : String, + #| loc~ : SourceLoc, + #|) -> Unit raise { + #| if !(a != b) { + #| let fail_msg = match msg { + #| Some(msg) => msg + #| None => "`\{debug_string(a)} == \{debug_string(b)}`" + #| } + #| fail(fail_msg, loc~) + #| } + #|} + #|#callsite(autofill(loc)) + #|#coverage.skip + #|pub fn assert_true(x : Bool, msg? : String, loc~ : SourceLoc) -> Unit raise { + #| if !x { + #| let fail_msg = match msg { + #| Some(msg) => msg + #| None => "`\{x}` is not true" + #| } + #| fail(fail_msg, loc~) + #| } + #|} + #|#callsite(autofill(loc)) + #|#coverage.skip + #|pub fn assert_false(x : Bool, msg? : String, loc~ : SourceLoc) -> Unit raise { + #| if x { + #| let fail_msg = match msg { + #| Some(msg) => msg + #| None => "`\{x}` is not false" + #| } + #| fail(fail_msg, loc~) + #| } + #|} + ), + "assert_debug.mbt": ( + #|pub fn debug_assert(x : () -> Bool) -> Unit { + #| guard x() + #|} + ), + "assert_release.mbt": ( + #|pub fn debug_assert(x : () -> Bool) -> Unit = "%ignore" + ), + "autoloc.mbt": ( + #|pub(all) type SourceLoc + #|fn SourceLoc::repr(self : Self) -> String = "%loc_to_string" + #|pub impl Show for SourceLoc with output(self, logger) { + #| SourceLocRepr::parse(self.repr()).output(logger) + #|} + #|priv struct SourceLocRepr { + #| pkg : StringView + #| filename : StringView + #| start_line : StringView + #| start_column : StringView + #| end_line : StringView + #| end_column : StringView + #|} + #|impl Show for SourceLocRepr with output(self, logger) { + #| let pkg = self.pkg + #| let (module_name, package_name) = lexmatch pkg { + #| (("[^/]*/[^/]*" as module_name) "/" (".*" as package_name)) => + #| (module_name, Some(package_name)) + #| _ => (pkg, None) + #| } + #| if package_name is Some(pkg_name) { + #| logger.write_view(pkg_name) + #| logger.write_char('/') + #| } + #| logger.write_view(self.filename) + #| logger.write_char(':') + #| logger.write_view(self.start_line) + #| logger.write_char(':') + #| logger.write_view(self.start_column) + #| logger.write_char('-') + #| logger.write_view(self.end_line) + #| logger.write_char(':') + #| logger.write_view(self.end_column) + #| logger.write_char('@') + #| logger.write_view(module_name) + #|} + #|fn SourceLocRepr::parse(repr : String) -> SourceLocRepr { + #| lexmatch repr[:] { + #| ( + #| "@" + #| ("[^:]*" as pkg) + #| ":" + #| (".+?" as filename) + #| ":" + #| ("[[:digit:]]+" as start_line) + #| ":" + #| ("[[:digit:]]+" as start_column) + #| "-" + #| ("[[:digit:]]+" as end_line) + #| ":" + #| ("[[:digit:]]+" as end_column) + #| ) => { pkg, filename, start_line, start_column, end_line, end_column } + #| _ => panic() + #| } + #|} + #|fn SourceLocRepr::to_json_string(self : SourceLocRepr) -> String { + #| let sb = StringBuilder::new() + #| sb.write_string("{\"pkg\":\"\{self.pkg}\"") + #| sb.write_string(",\"filename\":") + #| sb.write_object(self.filename) + #| sb.write_string(",\"start_line\":\{self.start_line}") + #| sb.write_string(",\"start_column\":\{self.start_column}") + #| sb.write_string(",\"end_line\":\{self.end_line}") + #| sb.write_string(",\"end_column\":\{self.end_column}}") + #| sb.to_string() + #|} + #|pub fn SourceLoc::to_json_string(self : SourceLoc) -> String { + #| SourceLocRepr::parse(self.repr()).to_json_string() + #|} + #|pub(all) struct ArgsLoc(Array[SourceLoc?]) derive(Show) + #|pub fn ArgsLoc::to_json(self : ArgsLoc) -> String { + #| let buf = StringBuilder::new(size_hint=10) + #| let ArgsLoc(self) = self + #| buf.write_char('[') + #| for i, item in self { + #| if i != 0 { + #| buf.write_string(", ") + #| } + #| match item { + #| None => buf.write_string("null") + #| Some(loc) => buf.write_string(loc.to_json_string()) + #| } + #| } + #| buf.write_char(']') + #| buf.to_string() + #|} + ), + "bitstring.mbt": ( + #|fn UInt::extend_sign(self : UInt, len : Int) -> Int { + #| let b = 32 - len + #| self.reinterpret_as_int() << b >> b + #|} + #|fn UInt64::extend_sign(self : UInt64, len : Int) -> Int64 { + #| let b = 64 - len + #| self.reinterpret_as_int64() << b >> b + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn ArrayView::unsafe_extract_bit( + #| bs : ArrayView[Byte], + #| offset : Int, + #| _len : Int, + #|) -> UInt { + #| let byte_index = offset >> 3 + #| let bit_shift = 7 - (offset & 7) + #| let byte_val = bs.unsafe_get(byte_index).to_uint() + #| (byte_val >> bit_shift) & 1U + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn ArrayView::unsafe_extract_bit_signed( + #| bs : ArrayView[Byte], + #| offset : Int, + #| _len : Int, + #|) -> Int { + #| let byte_index = offset >> 3 + #| let bit_shift = 7 - (offset & 7) + #| let byte_val = bs.unsafe_get(byte_index).to_int() + #| ((byte_val >> bit_shift) & 1) * -1 + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn ArrayView::unsafe_extract_byte( + #| bs : ArrayView[Byte], + #| offset : Int, + #| len : Int, + #|) -> UInt { + #| let byte_index = offset >> 3 + #| if (offset & 7) == 0 { + #| let byte = bs.unsafe_get(byte_index) + #| (byte >> (8 - len)).to_uint() + #| } else if (offset & 7) + len <= 8 { + #| let byte = bs.unsafe_get(byte_index).to_uint() + #| let shift = 8 - ((offset & 7) + len) + #| let mask = (1U << len) - 1 + #| (byte >> shift) & mask + #| } else { + #| let b0 = bs.unsafe_get(byte_index).to_uint() + #| let b1 = bs.unsafe_get(byte_index + 1).to_uint() + #| let data = (b0 << 8) | b1 + #| let bit_mask = (1U << (16 - (offset & 7))) - 1 + #| let data = data & bit_mask + #| let shift = 16 - ((offset & 7) + len) + #| data >> shift + #| } + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn ArrayView::unsafe_extract_uint_le( + #| bs : ArrayView[Byte], + #| offset : Int, + #| len : Int, + #|) -> UInt { + #| let bytes_needed = (len + 7) / 8 + #| let b0 = bs.unsafe_extract_byte(offset, 8) + #| match bytes_needed { + #| 2 => { + #| let b1 = bs.unsafe_extract_byte(offset + 8, len - 8) + #| (b1 << 8) | b0 + #| } + #| 3 => { + #| let b1 = bs.unsafe_extract_byte(offset + 8, 8) + #| let b2 = bs.unsafe_extract_byte(offset + 16, len - 16) + #| (b2 << 16) | (b1 << 8) | b0 + #| } + #| 4 => { + #| let b1 = bs.unsafe_extract_byte(offset + 8, 8) + #| let b2 = bs.unsafe_extract_byte(offset + 16, 8) + #| let b3 = bs.unsafe_extract_byte(offset + 24, len - 24) + #| (b3 << 24) | (b2 << 16) | (b1 << 8) | b0 + #| } + #| _ => abort("Invalid byte count for int32 extraction") + #| } + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn ArrayView::unsafe_extract_uint_be( + #| bs : ArrayView[Byte], + #| offset : Int, + #| len : Int, + #|) -> UInt { + #| let bytes_needed = (len + 7) / 8 + #| let b0 = bs.unsafe_extract_byte(offset, 8) + #| match bytes_needed { + #| 2 => { + #| let b1 = bs.unsafe_extract_byte(offset + 8, len - 8) + #| let shift = 16 - len + #| let data = (b0 << 8) | (b1 << shift) + #| data >> shift + #| } + #| 3 => { + #| let b1 = bs.unsafe_extract_byte(offset + 8, 8) + #| let b2 = bs.unsafe_extract_byte(offset + 16, len - 16) + #| let shift = 24 - len + #| let data = (b0 << 16) | (b1 << 8) | (b2 << shift) + #| data >> shift + #| } + #| 4 => { + #| let b1 = bs.unsafe_extract_byte(offset + 8, 8) + #| let b2 = bs.unsafe_extract_byte(offset + 16, 8) + #| let b3 = bs.unsafe_extract_byte(offset + 24, len - 24) + #| let shift = 32 - len + #| let data = (b0 << 24) | (b1 << 16) | (b2 << 8) | (b3 << shift) + #| data >> shift + #| } + #| _ => abort("Invalid byte count for int32 extraction") + #| } + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn ArrayView::unsafe_extract_uint64_le( + #| bs : ArrayView[Byte], + #| offset : Int, + #| len : Int, + #|) -> UInt64 { + #| let bytes_needed = (len + 7) / 8 + #| let b0 = bs.unsafe_extract_byte(offset, 8).to_uint64() + #| let b1 = bs.unsafe_extract_byte(offset + 8, 8).to_uint64() + #| let b2 = bs.unsafe_extract_byte(offset + 16, 8).to_uint64() + #| let b3 = bs.unsafe_extract_byte(offset + 24, 8).to_uint64() + #| match bytes_needed { + #| 5 => { + #| let b4 = bs.unsafe_extract_byte(offset + 32, len - 32).to_uint64() + #| (b4 << 32) | (b3 << 24) | (b2 << 16) | (b1 << 8) | b0 + #| } + #| 6 => { + #| let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64() + #| let b5 = bs.unsafe_extract_byte(offset + 40, len - 40).to_uint64() + #| (b5 << 40) | (b4 << 32) | (b3 << 24) | (b2 << 16) | (b1 << 8) | b0 + #| } + #| 7 => { + #| let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64() + #| let b5 = bs.unsafe_extract_byte(offset + 40, 8).to_uint64() + #| let b6 = bs.unsafe_extract_byte(offset + 48, len - 48).to_uint64() + #| (b6 << 48) | + #| (b5 << 40) | + #| (b4 << 32) | + #| (b3 << 24) | + #| (b2 << 16) | + #| (b1 << 8) | + #| b0 + #| } + #| 8 => { + #| let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64() + #| let b5 = bs.unsafe_extract_byte(offset + 40, 8).to_uint64() + #| let b6 = bs.unsafe_extract_byte(offset + 48, 8).to_uint64() + #| let b7 = bs.unsafe_extract_byte(offset + 56, len - 56).to_uint64() + #| (b7 << 56) | + #| (b6 << 48) | + #| (b5 << 40) | + #| (b4 << 32) | + #| (b3 << 24) | + #| (b2 << 16) | + #| (b1 << 8) | + #| b0 + #| } + #| _ => abort("Invalid byte count for int64 extraction") + #| } + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn ArrayView::unsafe_extract_uint64_be( + #| bs : ArrayView[Byte], + #| offset : Int, + #| len : Int, + #|) -> UInt64 { + #| let bytes_needed = (len + 7) / 8 + #| let b0 = bs.unsafe_extract_byte(offset, 8).to_uint64() + #| let b1 = bs.unsafe_extract_byte(offset + 8, 8).to_uint64() + #| let b2 = bs.unsafe_extract_byte(offset + 16, 8).to_uint64() + #| let b3 = bs.unsafe_extract_byte(offset + 24, 8).to_uint64() + #| match bytes_needed { + #| 5 => { + #| let b4 = bs.unsafe_extract_byte(offset + 32, len - 32).to_uint64() + #| let shift = 40 - len + #| let data = (b0 << 32) | + #| (b1 << 24) | + #| (b2 << 16) | + #| (b3 << 8) | + #| (b4 << shift) + #| data >> shift + #| } + #| 6 => { + #| let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64() + #| let b5 = bs.unsafe_extract_byte(offset + 40, len - 40).to_uint64() + #| let shift = 48 - len + #| let data = (b0 << 40) | + #| (b1 << 32) | + #| (b2 << 24) | + #| (b3 << 16) | + #| (b4 << 8) | + #| (b5 << shift) + #| data >> shift + #| } + #| 7 => { + #| let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64() + #| let b5 = bs.unsafe_extract_byte(offset + 40, 8).to_uint64() + #| let b6 = bs.unsafe_extract_byte(offset + 48, len - 48).to_uint64() + #| let shift = 56 - len + #| let data = (b0 << 48) | + #| (b1 << 40) | + #| (b2 << 32) | + #| (b3 << 24) | + #| (b4 << 16) | + #| (b5 << 8) | + #| (b6 << shift) + #| data >> shift + #| } + #| 8 => { + #| let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64() + #| let b5 = bs.unsafe_extract_byte(offset + 40, 8).to_uint64() + #| let b6 = bs.unsafe_extract_byte(offset + 48, 8).to_uint64() + #| let b7 = bs.unsafe_extract_byte(offset + 56, len - 56).to_uint64() + #| let shift = 64 - len + #| let data = (b0 << 56) | + #| (b1 << 48) | + #| (b2 << 40) | + #| (b3 << 32) | + #| (b4 << 24) | + #| (b5 << 16) | + #| (b6 << 8) | + #| (b7 << shift) + #| data >> shift + #| } + #| _ => abort("Invalid byte count for int64 extraction") + #| } + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn ArrayView::unsafe_extract_bytesview( + #| bs : ArrayView[Byte], + #| offset : Int, + #| len : Int, + #|) -> ArrayView[Byte] { + #| let start = offset >> 3 + #| let end = start + (len >> 3) + #| bs[start:end] + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn ArrayView::unsafe_extract_byte_signed( + #| bs : ArrayView[Byte], + #| offset : Int, + #| len : Int, + #|) -> Int { + #| let unsigned = bs.unsafe_extract_byte(offset, len) + #| unsigned.extend_sign(len) + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn ArrayView::unsafe_extract_int_le( + #| bs : ArrayView[Byte], + #| offset : Int, + #| len : Int, + #|) -> Int { + #| let unsigned = bs.unsafe_extract_uint_le(offset, len) + #| unsigned.extend_sign(len) + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn ArrayView::unsafe_extract_int_be( + #| bs : ArrayView[Byte], + #| offset : Int, + #| len : Int, + #|) -> Int { + #| let unsigned = bs.unsafe_extract_uint_be(offset, len) + #| unsigned.extend_sign(len) + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn ArrayView::unsafe_extract_int64_le( + #| bs : ArrayView[Byte], + #| offset : Int, + #| len : Int, + #|) -> Int64 { + #| let unsigned = bs.unsafe_extract_uint64_le(offset, len) + #| unsigned.extend_sign(len) + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn ArrayView::unsafe_extract_int64_be( + #| bs : ArrayView[Byte], + #| offset : Int, + #| len : Int, + #|) -> Int64 { + #| let unsigned = bs.unsafe_extract_uint64_be(offset, len) + #| unsigned.extend_sign(len) + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn Array::unsafe_extract_bit( + #| bs : Array[Byte], + #| offset : Int, + #| len : Int, + #|) -> UInt { + #| bs[:].unsafe_extract_bit(offset, len) + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn Array::unsafe_extract_byte( + #| bs : Array[Byte], + #| offset : Int, + #| len : Int, + #|) -> UInt { + #| bs[:].unsafe_extract_byte(offset, len) + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn Array::unsafe_extract_uint_le( + #| bs : Array[Byte], + #| offset : Int, + #| len : Int, + #|) -> UInt { + #| bs[:].unsafe_extract_uint_le(offset, len) + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn Array::unsafe_extract_uint_be( + #| bs : Array[Byte], + #| offset : Int, + #| len : Int, + #|) -> UInt { + #| bs[:].unsafe_extract_uint_be(offset, len) + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn Array::unsafe_extract_uint64_le( + #| bs : Array[Byte], + #| offset : Int, + #| len : Int, + #|) -> UInt64 { + #| bs[:].unsafe_extract_uint64_le(offset, len) + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn Array::unsafe_extract_uint64_be( + #| bs : Array[Byte], + #| offset : Int, + #| len : Int, + #|) -> UInt64 { + #| bs[:].unsafe_extract_uint64_be(offset, len) + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn Array::unsafe_extract_bytesview( + #| bs : Array[Byte], + #| offset : Int, + #| len : Int, + #|) -> ArrayView[Byte] { + #| bs[:].unsafe_extract_bytesview(offset, len) + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn FixedArray::unsafe_extract_bit( + #| bs : FixedArray[Byte], + #| offset : Int, + #| len : Int, + #|) -> UInt { + #| bs[:].unsafe_extract_bit(offset, len) + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn FixedArray::unsafe_extract_byte( + #| bs : FixedArray[Byte], + #| offset : Int, + #| len : Int, + #|) -> UInt { + #| bs[:].unsafe_extract_byte(offset, len) + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn FixedArray::unsafe_extract_uint_le( + #| bs : FixedArray[Byte], + #| offset : Int, + #| len : Int, + #|) -> UInt { + #| bs[:].unsafe_extract_uint_le(offset, len) + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn FixedArray::unsafe_extract_uint_be( + #| bs : FixedArray[Byte], + #| offset : Int, + #| len : Int, + #|) -> UInt { + #| bs[:].unsafe_extract_uint_be(offset, len) + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn FixedArray::unsafe_extract_uint64_le( + #| bs : FixedArray[Byte], + #| offset : Int, + #| len : Int, + #|) -> UInt64 { + #| bs[:].unsafe_extract_uint64_le(offset, len) + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn FixedArray::unsafe_extract_uint64_be( + #| bs : FixedArray[Byte], + #| offset : Int, + #| len : Int, + #|) -> UInt64 { + #| bs[:].unsafe_extract_uint64_be(offset, len) + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn FixedArray::unsafe_extract_bytesview( + #| bs : FixedArray[Byte], + #| offset : Int, + #| len : Int, + #|) -> ArrayView[Byte] { + #| bs[:].unsafe_extract_bytesview(offset, len) + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn BytesView::unsafe_extract_bit( + #| bs : BytesView, + #| offset : Int, + #| _len : Int, + #|) -> UInt { + #| let byte_index = offset >> 3 + #| let bit_shift = 7 - (offset & 7) + #| let byte_val = bs.unsafe_get(byte_index).to_uint() + #| (byte_val >> bit_shift) & 1U + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn BytesView::unsafe_extract_bit_signed( + #| bs : BytesView, + #| offset : Int, + #| _len : Int, + #|) -> Int { + #| let byte_index = offset >> 3 + #| let bit_shift = 7 - (offset & 7) + #| let byte_val = bs.unsafe_get(byte_index).to_int() + #| ((byte_val >> bit_shift) & 1) * -1 + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn BytesView::unsafe_extract_byte( + #| bs : BytesView, + #| offset : Int, + #| len : Int, + #|) -> UInt { + #| let byte_index = offset >> 3 + #| if (offset & 7) == 0 { + #| let byte = bs.unsafe_get(byte_index) + #| (byte >> (8 - len)).to_uint() + #| } else if (offset & 7) + len <= 8 { + #| let byte = bs.unsafe_get(byte_index).to_uint() + #| let shift = 8 - ((offset & 7) + len) + #| let mask = (1U << len) - 1 + #| (byte >> shift) & mask + #| } else { + #| let b0 = bs.unsafe_get(byte_index).to_uint() + #| let b1 = bs.unsafe_get(byte_index + 1).to_uint() + #| let data = (b0 << 8) | b1 + #| let bit_mask = (1U << (16 - (offset & 7))) - 1 + #| let data = data & bit_mask + #| let shift = 16 - ((offset & 7) + len) + #| data >> shift + #| } + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn BytesView::unsafe_extract_uint_le( + #| bs : BytesView, + #| offset : Int, + #| len : Int, + #|) -> UInt { + #| let bytes_needed = (len + 7) / 8 + #| let b0 = bs.unsafe_extract_byte(offset, 8) + #| match bytes_needed { + #| 2 => { + #| let b1 = bs.unsafe_extract_byte(offset + 8, len - 8) + #| (b1 << 8) | b0 + #| } + #| 3 => { + #| let b1 = bs.unsafe_extract_byte(offset + 8, 8) + #| let b2 = bs.unsafe_extract_byte(offset + 16, len - 16) + #| (b2 << 16) | (b1 << 8) | b0 + #| } + #| 4 => { + #| let b1 = bs.unsafe_extract_byte(offset + 8, 8) + #| let b2 = bs.unsafe_extract_byte(offset + 16, 8) + #| let b3 = bs.unsafe_extract_byte(offset + 24, len - 24) + #| (b3 << 24) | (b2 << 16) | (b1 << 8) | b0 + #| } + #| _ => abort("Invalid byte count for int32 extraction") + #| } + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn BytesView::unsafe_extract_uint_be( + #| bs : BytesView, + #| offset : Int, + #| len : Int, + #|) -> UInt { + #| let bytes_needed = (len + 7) / 8 + #| let b0 = bs.unsafe_extract_byte(offset, 8) + #| match bytes_needed { + #| 2 => { + #| let b1 = bs.unsafe_extract_byte(offset + 8, len - 8) + #| let shift = 16 - len + #| let data = (b0 << 8) | (b1 << shift) + #| data >> shift + #| } + #| 3 => { + #| let b1 = bs.unsafe_extract_byte(offset + 8, 8) + #| let b2 = bs.unsafe_extract_byte(offset + 16, len - 16) + #| let shift = 24 - len + #| let data = (b0 << 16) | (b1 << 8) | (b2 << shift) + #| data >> shift + #| } + #| 4 => { + #| let b1 = bs.unsafe_extract_byte(offset + 8, 8) + #| let b2 = bs.unsafe_extract_byte(offset + 16, 8) + #| let b3 = bs.unsafe_extract_byte(offset + 24, len - 24) + #| let shift = 32 - len + #| let data = (b0 << 24) | (b1 << 16) | (b2 << 8) | (b3 << shift) + #| data >> shift + #| } + #| _ => abort("Invalid byte count for int32 extraction") + #| } + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn BytesView::unsafe_extract_uint64_le( + #| bs : BytesView, + #| offset : Int, + #| len : Int, + #|) -> UInt64 { + #| let bytes_needed = (len + 7) / 8 + #| let b0 = bs.unsafe_extract_byte(offset, 8).to_uint64() + #| let b1 = bs.unsafe_extract_byte(offset + 8, 8).to_uint64() + #| let b2 = bs.unsafe_extract_byte(offset + 16, 8).to_uint64() + #| let b3 = bs.unsafe_extract_byte(offset + 24, 8).to_uint64() + #| match bytes_needed { + #| 5 => { + #| let b4 = bs.unsafe_extract_byte(offset + 32, len - 32).to_uint64() + #| (b4 << 32) | (b3 << 24) | (b2 << 16) | (b1 << 8) | b0 + #| } + #| 6 => { + #| let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64() + #| let b5 = bs.unsafe_extract_byte(offset + 40, len - 40).to_uint64() + #| (b5 << 40) | (b4 << 32) | (b3 << 24) | (b2 << 16) | (b1 << 8) | b0 + #| } + #| 7 => { + #| let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64() + #| let b5 = bs.unsafe_extract_byte(offset + 40, 8).to_uint64() + #| let b6 = bs.unsafe_extract_byte(offset + 48, len - 48).to_uint64() + #| (b6 << 48) | + #| (b5 << 40) | + #| (b4 << 32) | + #| (b3 << 24) | + #| (b2 << 16) | + #| (b1 << 8) | + #| b0 + #| } + #| 8 => { + #| let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64() + #| let b5 = bs.unsafe_extract_byte(offset + 40, 8).to_uint64() + #| let b6 = bs.unsafe_extract_byte(offset + 48, 8).to_uint64() + #| let b7 = bs.unsafe_extract_byte(offset + 56, len - 56).to_uint64() + #| (b7 << 56) | + #| (b6 << 48) | + #| (b5 << 40) | + #| (b4 << 32) | + #| (b3 << 24) | + #| (b2 << 16) | + #| (b1 << 8) | + #| b0 + #| } + #| _ => abort("Invalid byte count for int64 extraction") + #| } + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn BytesView::unsafe_extract_uint64_be( + #| bs : BytesView, + #| offset : Int, + #| len : Int, + #|) -> UInt64 { + #| let bytes_needed = (len + 7) / 8 + #| let b0 = bs.unsafe_extract_byte(offset, 8).to_uint64() + #| let b1 = bs.unsafe_extract_byte(offset + 8, 8).to_uint64() + #| let b2 = bs.unsafe_extract_byte(offset + 16, 8).to_uint64() + #| let b3 = bs.unsafe_extract_byte(offset + 24, 8).to_uint64() + #| match bytes_needed { + #| 5 => { + #| let b4 = bs.unsafe_extract_byte(offset + 32, len - 32).to_uint64() + #| let shift = 40 - len + #| let data = (b0 << 32) | + #| (b1 << 24) | + #| (b2 << 16) | + #| (b3 << 8) | + #| (b4 << shift) + #| data >> shift + #| } + #| 6 => { + #| let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64() + #| let b5 = bs.unsafe_extract_byte(offset + 40, len - 40).to_uint64() + #| let shift = 48 - len + #| let data = (b0 << 40) | + #| (b1 << 32) | + #| (b2 << 24) | + #| (b3 << 16) | + #| (b4 << 8) | + #| (b5 << shift) + #| data >> shift + #| } + #| 7 => { + #| let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64() + #| let b5 = bs.unsafe_extract_byte(offset + 40, 8).to_uint64() + #| let b6 = bs.unsafe_extract_byte(offset + 48, len - 48).to_uint64() + #| let shift = 56 - len + #| let data = (b0 << 48) | + #| (b1 << 40) | + #| (b2 << 32) | + #| (b3 << 24) | + #| (b4 << 16) | + #| (b5 << 8) | + #| (b6 << shift) + #| data >> shift + #| } + #| 8 => { + #| let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64() + #| let b5 = bs.unsafe_extract_byte(offset + 40, 8).to_uint64() + #| let b6 = bs.unsafe_extract_byte(offset + 48, 8).to_uint64() + #| let b7 = bs.unsafe_extract_byte(offset + 56, len - 56).to_uint64() + #| let shift = 64 - len + #| let data = (b0 << 56) | + #| (b1 << 48) | + #| (b2 << 40) | + #| (b3 << 32) | + #| (b4 << 24) | + #| (b5 << 16) | + #| (b6 << 8) | + #| (b7 << shift) + #| data >> shift + #| } + #| _ => abort("Invalid byte count for int64 extraction") + #| } + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn BytesView::unsafe_extract_bytesview( + #| bs : BytesView, + #| offset : Int, + #| len : Int, + #|) -> BytesView { + #| BytesView::make(bs.bytes(), bs.start() + (offset >> 3), len >> 3) + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn BytesView::unsafe_extract_byte_signed( + #| bs : BytesView, + #| offset : Int, + #| len : Int, + #|) -> Int { + #| let unsigned = bs.unsafe_extract_byte(offset, len) + #| unsigned.extend_sign(len) + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn BytesView::unsafe_extract_int_le( + #| bs : BytesView, + #| offset : Int, + #| len : Int, + #|) -> Int { + #| let unsigned = bs.unsafe_extract_uint_le(offset, len) + #| unsigned.extend_sign(len) + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn BytesView::unsafe_extract_int_be( + #| bs : BytesView, + #| offset : Int, + #| len : Int, + #|) -> Int { + #| let unsigned = bs.unsafe_extract_uint_be(offset, len) + #| unsigned.extend_sign(len) + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn BytesView::unsafe_extract_int64_le( + #| bs : BytesView, + #| offset : Int, + #| len : Int, + #|) -> Int64 { + #| let unsigned = bs.unsafe_extract_uint64_le(offset, len) + #| unsigned.extend_sign(len) + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn BytesView::unsafe_extract_int64_be( + #| bs : BytesView, + #| offset : Int, + #| len : Int, + #|) -> Int64 { + #| let unsigned = bs.unsafe_extract_uint64_be(offset, len) + #| unsigned.extend_sign(len) + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn Bytes::unsafe_extract_bit(bs : Bytes, offset : Int, len : Int) -> UInt { + #| bs[:].unsafe_extract_bit(offset, len) + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn Bytes::unsafe_extract_byte(bs : Bytes, offset : Int, len : Int) -> UInt { + #| bs[:].unsafe_extract_byte(offset, len) + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn Bytes::unsafe_extract_uint_le( + #| bs : Bytes, + #| offset : Int, + #| len : Int, + #|) -> UInt { + #| bs[:].unsafe_extract_uint_le(offset, len) + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn Bytes::unsafe_extract_uint_be( + #| bs : Bytes, + #| offset : Int, + #| len : Int, + #|) -> UInt { + #| bs[:].unsafe_extract_uint_be(offset, len) + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn Bytes::unsafe_extract_uint64_le( + #| bs : Bytes, + #| offset : Int, + #| len : Int, + #|) -> UInt64 { + #| bs[:].unsafe_extract_uint64_le(offset, len) + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn Bytes::unsafe_extract_uint64_be( + #| bs : Bytes, + #| offset : Int, + #| len : Int, + #|) -> UInt64 { + #| bs[:].unsafe_extract_uint64_be(offset, len) + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn Bytes::unsafe_extract_bytesview( + #| bs : Bytes, + #| offset : Int, + #| len : Int, + #|) -> BytesView { + #| bs[:].unsafe_extract_bytesview(offset, len) + #|} + ), + "bool.mbt": ( + #|pub fn Bool::to_int(self : Bool) -> Int { + #| if self { + #| 1 + #| } else { + #| 0 + #| } + #|} + #|pub fn Bool::to_int64(self : Bool) -> Int64 { + #| if self { + #| 1 + #| } else { + #| 0 + #| } + #|} + #|pub fn Bool::to_uint(self : Bool) -> UInt { + #| if self { + #| 1 + #| } else { + #| 0 + #| } + #|} + #|pub fn Bool::to_uint64(self : Bool) -> UInt64 { + #| if self { + #| 1 + #| } else { + #| 0 + #| } + #|} + #|pub impl Hash for Bool with hash_combine(self, hasher) { + #| hasher.combine_bool(self) + #|} + #|pub fn Bool::to_uint16(self : Bool) -> UInt16 { + #| if self { + #| 1 + #| } else { + #| 0 + #| } + #|} + #|pub fn Bool::to_int16(self : Bool) -> Int16 { + #| if self { + #| 1 + #| } else { + #| 0 + #| } + #|} + ), + "byte.mbt": ( + #|pub impl Mul for Byte with mul(self : Byte, that : Byte) -> Byte { + #| (self.to_int() * that.to_int()).to_byte() + #|} + #|pub impl Div for Byte with div(self : Byte, that : Byte) -> Byte { + #| (self.to_int() / that.to_int()).to_byte() + #|} + #|pub impl Mod for Byte with mod(self : Byte, that : Byte) -> Byte { + #| (self.to_int() % that.to_int()).to_byte() + #|} + #|pub impl Eq for Byte with equal(self : Byte, that : Byte) -> Bool { + #| self.to_int() == that.to_int() + #|} + #|pub impl Eq for Byte with not_equal(self : Byte, that : Byte) -> Bool { + #| self.to_int() != that.to_int() + #|} + #|pub impl Add for Byte with add(self : Byte, that : Byte) -> Byte { + #| (self.to_int() + that.to_int()).to_byte() + #|} + #|pub impl Sub for Byte with sub(self : Byte, that : Byte) -> Byte { + #| (self.to_int() - that.to_int()).to_byte() + #|} + #|pub impl Compare for Byte with compare(self : Byte, that : Byte) -> Int { + #| self.to_int().compare(that.to_int()) + #|} + #|pub impl Compare for Byte with op_lt(x, y) { + #| x.to_int() < y.to_int() + #|} + #|pub impl Compare for Byte with op_le(x, y) { + #| x.to_int() <= y.to_int() + #|} + #|pub impl Compare for Byte with op_gt(x, y) { + #| x.to_int() > y.to_int() + #|} + #|pub impl Compare for Byte with op_ge(x, y) { + #| x.to_int() >= y.to_int() + #|} + #|fn alphabet(x : Int) -> String { + #| match x { + #| 0 => "0" + #| 1 => "1" + #| 2 => "2" + #| 3 => "3" + #| 4 => "4" + #| 5 => "5" + #| 6 => "6" + #| 7 => "7" + #| 8 => "8" + #| 9 => "9" + #| 10 => "A" + #| 11 => "B" + #| 12 => "C" + #| 13 => "D" + #| 14 => "E" + #| 15 => "F" + #| _ => abort("impossible") + #| } + #|} + #|pub fn Byte::to_string(self : Byte) -> String { + #| let i = self.to_int() + #| let hi = alphabet(i / 16) + #| let lo = alphabet(i % 16) + #| "b'\\x\{hi}\{lo}'" + #|} + #|pub impl Hash for Byte with hash_combine(self, hasher) { + #| hasher.combine_byte(self) + #|} + #|pub impl Default for Byte with default() { + #| b'\x00' + #|} + #|pub fn Byte::lnot(self : Byte) -> Byte { + #| self.to_int().lnot().to_byte() + #|} + #|pub impl BitAnd for Byte with land(self : Byte, that : Byte) -> Byte { + #| (self.to_int() & that.to_int()).to_byte() + #|} + #|pub impl BitOr for Byte with lor(self : Byte, that : Byte) -> Byte { + #| (self.to_int() | that.to_int()).to_byte() + #|} + #|pub impl BitXOr for Byte with lxor(self : Byte, that : Byte) -> Byte { + #| (self.to_int() ^ that.to_int()).to_byte() + #|} + #|pub fn Byte::to_uint(self : Byte) -> UInt { + #| self.to_int().reinterpret_as_uint() + #|} + #|pub fn Byte::to_uint64(self : Byte) -> UInt64 { + #| self.to_uint().to_uint64() + #|} + #|pub fn Byte::popcnt(self : Byte) -> Int { + #| let mut n = self + #| n = (n & 0x55) + ((n >> 1) & 0x55) + #| n = (n & 0x33) + ((n >> 2) & 0x33) + #| n = (n & 0x0F) + ((n >> 4) & 0x0F) + #| n.to_int() + #|} + #|pub impl Shl for Byte with shl(self : Byte, count : Int) -> Byte { + #| (self.to_int() << count).to_byte() + #|} + #|pub impl Shr for Byte with shr(self : Byte, count : Int) -> Byte { + #| (self.to_uint() >> count).reinterpret_as_int().to_byte() + #|} + ), + "bytes.mbt": ( + #|#internal(unsafe, "Creating mutable Bytes") + #|#doc(hidden) + #|pub fn FixedArray::unsafe_reinterpret_as_bytes( + #| self : FixedArray[Byte], + #|) -> Bytes = "%identity" + #|pub fn Bytes::makei(length : Int, value : (Int) -> Byte raise?) -> Bytes raise? { + #| if length <= 0 { + #| return [] + #| } + #| let arr = FixedArray::make(length, value(0)) + #| for i in 1.. String = "$moonbit.unsafe_bytes_sub_string" + #|pub fn Bytes::to_unchecked_string( + #| self : Bytes, + #| offset? : Int = 0, + #| length? : Int, + #|) -> String { + #| let len = self.length() + #| let length = if length is Some(l) { l } else { len - offset } + #| guard offset >= 0 && length >= 0 && offset + length <= len + #| unsafe_sub_string(self, offset, length) + #|} + #|pub fn FixedArray::blit_from_string( + #| self : FixedArray[Byte], + #| bytes_offset : Int, + #| str : String, + #| str_offset : Int, + #| length : Int, + #|) -> Unit { + #| let s1 = bytes_offset + #| let s2 = str_offset + #| let e1 = bytes_offset + length * 2 - 1 + #| let e2 = str_offset + length - 1 + #| let len1 = self.length() + #| let len2 = str.length() + #| guard length >= 0 && s1 >= 0 && e1 < len1 && s2 >= 0 && e2 < len2 + #| let end_str_offset = str_offset + length + #| for i = str_offset, j = bytes_offset; i < end_str_offset; i = i + 1, j = j + 2 { + #| let c = str.unsafe_get(i).to_int().reinterpret_as_uint() + #| self[j] = (c & 0xff).to_byte() + #| self[j + 1] = (c >> 8).to_byte() + #| } + #|} + #|fn unsafe_from_bytes(bytes : Bytes) -> FixedArray[Byte] = "%identity" + #|pub fn FixedArray::blit_from_bytes( + #| self : FixedArray[Byte], + #| bytes_offset : Int, + #| src : Bytes, + #| src_offset : Int, + #| length : Int, + #|) -> Unit { + #| let s1 = bytes_offset + #| let s2 = src_offset + #| let e1 = bytes_offset + length - 1 + #| let e2 = src_offset + length - 1 + #| let len1 = self.length() + #| let len2 = src.length() + #| guard length >= 0 && s1 >= 0 && e1 < len1 && s2 >= 0 && e2 < len2 + #| FixedArray::unsafe_blit( + #| self, + #| bytes_offset, + #| unsafe_from_bytes(src), + #| src_offset, + #| length, + #| ) + #|} + #|pub fn FixedArray::blit_from_bytesview( + #| self : FixedArray[Byte], + #| bytes_offset : Int, + #| src : BytesView, + #|) -> Unit { + #| FixedArray::blit_from_bytes( + #| self, + #| bytes_offset, + #| src.bytes(), + #| src.start(), + #| src.len(), + #| ) + #|} + #|pub fn FixedArray::set_utf8_char( + #| self : FixedArray[Byte], + #| offset : Int, + #| value : Char, + #|) -> Int { + #| let code = value.to_uint() + #| match code { + #| _..<0x80 => { + #| self[offset] = ((code & 0x7F) | 0x00).to_byte() + #| 1 + #| } + #| _..<0x0800 => { + #| self[offset] = (((code >> 6) & 0x1F) | 0xC0).to_byte() + #| self[offset + 1] = ((code & 0x3F) | 0x80).to_byte() + #| 2 + #| } + #| _..<0x010000 => { + #| self[offset] = (((code >> 12) & 0x0F) | 0xE0).to_byte() + #| self[offset + 1] = (((code >> 6) & 0x3F) | 0x80).to_byte() + #| self[offset + 2] = ((code & 0x3F) | 0x80).to_byte() + #| 3 + #| } + #| _..<0x110000 => { + #| self[offset] = (((code >> 18) & 0x07) | 0xF0).to_byte() + #| self[offset + 1] = (((code >> 12) & 0x3F) | 0x80).to_byte() + #| self[offset + 2] = (((code >> 6) & 0x3F) | 0x80).to_byte() + #| self[offset + 3] = ((code & 0x3F) | 0x80).to_byte() + #| 4 + #| } + #| _ => abort("Char out of range") + #| } + #|} + #|pub fn FixedArray::set_utf16le_char( + #| self : FixedArray[Byte], + #| offset : Int, + #| value : Char, + #|) -> Int { + #| let code = value.to_uint() + #| if code < 0x10000 { + #| self[offset] = (code & 0xFF).to_byte() + #| self[offset + 1] = (code >> 8).to_byte() + #| 2 + #| } else if code < 0x110000 { + #| let hi = code - 0x10000 + #| let lo = (hi >> 10) | 0xD800 + #| let hi = (hi & 0x3FF) | 0xDC00 + #| self[offset] = (lo & 0xFF).to_byte() + #| self[offset + 1] = (lo >> 8).to_byte() + #| self[offset + 2] = (hi & 0xFF).to_byte() + #| self[offset + 3] = (hi >> 8).to_byte() + #| 4 + #| } else { + #| abort("Char out of range") + #| } + #|} + #|pub fn FixedArray::set_utf16be_char( + #| self : FixedArray[Byte], + #| offset : Int, + #| value : Char, + #|) -> Int { + #| let code = value.to_uint() + #| if code < 0x10000 { + #| self[offset] = (code >> 8).to_byte() + #| self[offset + 1] = (code & 0xFF).to_byte() + #| 2 + #| } else if code < 0x110000 { + #| let hi = code - 0x10000 + #| let lo = (hi >> 10) | 0xD800 + #| let hi = (hi & 0x3FF) | 0xDC00 + #| self[offset] = (lo >> 8).to_byte() + #| self[offset + 1] = (lo & 0xFF).to_byte() + #| self[offset + 2] = (hi >> 8).to_byte() + #| self[offset + 3] = (hi & 0xFF).to_byte() + #| 4 + #| } else { + #| abort("Char out of range") + #| } + #|} + #|pub impl Eq for Bytes with equal(self : Bytes, other : Bytes) -> Bool { + #| if self.length() != other.length() { + #| false + #| } else { + #| let len = self.length() + #| for i in 0.. Bytes { + #| Bytes::makei(arr.length(), i => arr[i]) + #|} + #|#deprecated("Use Bytes::from_array instead") + #|pub fn Bytes::from_fixedarray(arr : FixedArray[Byte], len? : Int) -> Bytes { + #| let len = match len { + #| None => arr.length() + #| Some(x) => { + #| guard 0 <= x && x <= arr.length() + #| x + #| } + #| } + #| let result = unsafe_to_fixedarray(UninitializedArray::make(len)) + #| arr.blit_to(result, len~) + #| result.unsafe_reinterpret_as_bytes() + #|} + #|#label_migration(len, fill=false) + #|pub fn Bytes::to_fixedarray(self : Bytes, len? : Int) -> FixedArray[Byte] { + #| let len = match len { + #| None => self.length() + #| Some(x) => { + #| guard 0 <= x && x <= self.length() + #| x + #| } + #| } + #| let arr = unsafe_to_fixedarray(UninitializedArray::make(len)) + #| arr.blit_from_bytes(0, self, 0, len) + #| arr + #|} + #|pub fn BytesView::to_fixedarray(self : BytesView) -> FixedArray[Byte] { + #| let len = self.length() + #| let arr = unsafe_to_fixedarray(UninitializedArray::make(len)) + #| arr.blit_from_bytes(0, self.data(), self.start_offset(), len) + #| arr + #|} + #|#alias(from_iterator, deprecated) + #|pub fn Bytes::from_iter(iter : Iter[Byte]) -> Bytes { + #| Bytes::from_array(iter.collect()) + #|} + #|pub fn Bytes::to_array(self : Bytes) -> Array[Byte] { + #| let len = self.length() + #| let rv = Array::make(len, b'0') + #| for i in 0.. Array[Byte] { + #| let len = self.length() + #| let rv = Array::make(len, b'0') + #| for i in 0.. Iter[Byte] { + #| let mut i = 0 + #| let len = self.length() + #| Iter::new(fn() { + #| guard i < len else { None } + #| let c = self.unsafe_get(i) + #| i += 1 + #| Some(c) + #| }) + #|} + #|#alias(iterator2, deprecated) + #|pub fn Bytes::iter2(self : Bytes) -> Iter2[Int, Byte] { + #| let mut i = 0 + #| let len = self.length() + #| Iter::new(fn() { + #| guard i < len else { None } + #| let result = (i, self.unsafe_get(i)) + #| i += 1 + #| Some(result) + #| }) + #|} + #|pub impl Default for Bytes with default() { + #| b"" + #|} + #|pub fn Bytes::is_empty(self : Bytes) -> Bool { + #| self.length() == 0 + #|} + #|pub fn Bytes::get(self : Bytes, index : Int) -> Byte? { + #| guard index >= 0 && index < self.length() else { None } + #| Some(self[index]) + #|} + #|fn unsafe_to_fixedarray(array : UninitializedArray[Byte]) -> FixedArray[Byte] = "%identity" + #|pub impl Add for Bytes with add(self : Bytes, other : Bytes) -> Bytes { + #| let len_self = self.length() + #| let len_other = other.length() + #| let rv : FixedArray[Byte] = FixedArray::make(len_self + len_other, 0) + #| for i in 0.. Bytes { + #| if count <= 0 || self.length() == 0 { + #| return [] + #| } + #| if count == 1 { + #| return self + #| } + #| let len = self.length() + #| let total = len * count + #| guard total / count == len + #| let arr = FixedArray::make(total, (0 : Byte)) + #| arr.blit_from_bytes(0, self, 0, len) + #| for filled = len; filled < total; { + #| let remaining = total - filled + #| let copy_len = if filled < remaining { filled } else { remaining } + #| let src = unsafe_to_bytes(arr) + #| arr.blit_from_bytes(filled, src, 0, copy_len) + #| continue filled + copy_len + #| } + #| unsafe_to_bytes(arr) + #|} + #|pub fn Bytes::lexical_compare(self : Bytes, other : Bytes) -> Int { + #| self[:].lexical_compare(other[:]) + #|} + ), + "bytes_find.mbt": ( + #|pub fn BytesView::find(target : BytesView, pattern : BytesView) -> Int? { + #| let target_len = target.length() + #| let pattern_len = pattern.length() + #| for i in 0..<=(target_len - pattern_len) { + #| for j in 0.. Int? { + #| target[:].find(pattern) + #|} + #|pub fn BytesView::rev_find(target : BytesView, pattern : BytesView) -> Int? { + #| let target_len = target.length() + #| let pattern_len = pattern.length() + #| for i = target_len - pattern_len; i >= 0; i = i - 1 { + #| for j in 0.. Int? { + #| target[:].rev_find(pattern) + #|} + #|pub fn BytesView::has_prefix(self : BytesView, prefix : BytesView) -> Bool { + #| let prefix_len = prefix.length() + #| self.length() >= prefix_len && self[:prefix_len] == prefix + #|} + #|pub fn Bytes::has_prefix(self : Bytes, prefix : BytesView) -> Bool { + #| self[:].has_prefix(prefix) + #|} + #|pub fn BytesView::has_suffix(self : BytesView, suffix : BytesView) -> Bool { + #| let self_len = self.length() + #| let suffix_len = suffix.length() + #| self_len >= suffix_len && self[self_len - suffix_len:] == suffix + #|} + #|pub fn Bytes::has_suffix(self : Bytes, suffix : BytesView) -> Bool { + #| self[:].has_suffix(suffix) + #|} + #|pub fn BytesView::chop_prefix( + #| self : BytesView, + #| prefix : BytesView, + #|) -> BytesView? { + #| let prefix_len = prefix.length() + #| if self.length() >= prefix_len && self[:prefix_len] == prefix { + #| Some(self[prefix_len:]) + #| } else { + #| None + #| } + #|} + #|pub fn Bytes::chop_prefix(self : Bytes, prefix : BytesView) -> BytesView? { + #| self[:].chop_prefix(prefix) + #|} + #|pub fn BytesView::chop_suffix( + #| self : BytesView, + #| suffix : BytesView, + #|) -> BytesView? { + #| let self_len = self.length() + #| let suffix_len = suffix.length() + #| if self_len >= suffix_len && self[self_len - suffix_len:] == suffix { + #| Some(self[:self_len - suffix_len]) + #| } else { + #| None + #| } + #|} + #|pub fn Bytes::chop_suffix(self : Bytes, suffix : BytesView) -> BytesView? { + #| self[:].chop_suffix(suffix) + #|} + ), + "bytes_unsafe.mbt": ( + #|#intrinsic("%bytes.unsafe_write_uint64_le") + #|pub fn FixedArray::unsafe_write_uint64_le( + #| bytes : FixedArray[Byte], + #| index : Int, + #| value : UInt64, + #|) -> Unit { + #| for i in 0..<=7 { + #| bytes.unsafe_set(i + index, (value >> (8 * i)).to_byte()) + #| } + #|} + #|#intrinsic("%bytes.unsafe_write_uint64_be") + #|pub fn FixedArray::unsafe_write_uint64_be( + #| bytes : FixedArray[Byte], + #| index : Int, + #| value : UInt64, + #|) -> Unit { + #| for i in 0..<=7 { + #| bytes.unsafe_set(i + index, (value >> (8 * (7 - i))).to_byte()) + #| } + #|} + #|#intrinsic("%bytes.unsafe_write_uint32_le") + #|pub fn FixedArray::unsafe_write_uint32_le( + #| bytes : FixedArray[Byte], + #| index : Int, + #| value : UInt, + #|) -> Unit { + #| for i in 0..<=3 { + #| bytes.unsafe_set(i + index, (value >> (8 * i)).to_byte()) + #| } + #|} + #|#intrinsic("%bytes.unsafe_write_uint32_be") + #|pub fn FixedArray::unsafe_write_uint32_be( + #| bytes : FixedArray[Byte], + #| index : Int, + #| value : UInt, + #|) -> Unit { + #| for i in 0..<=3 { + #| bytes.unsafe_set(i + index, (value >> (8 * (3 - i))).to_byte()) + #| } + #|} + #|#intrinsic("%bytes.unsafe_write_uint16_le") + #|pub fn FixedArray::unsafe_write_uint16_le( + #| bytes : FixedArray[Byte], + #| index : Int, + #| value : UInt16, + #|) -> Unit { + #| for i in 0..<=1 { + #| bytes.unsafe_set(i + index, (value >> (8 * i)).to_byte()) + #| } + #|} + #|#intrinsic("%bytes.unsafe_write_uint16_be") + #|pub fn FixedArray::unsafe_write_uint16_be( + #| bytes : FixedArray[Byte], + #| index : Int, + #| value : UInt16, + #|) -> Unit { + #| for i in 0..<=1 { + #| bytes.unsafe_set(i + index, (value >> (8 * (1 - i))).to_byte()) + #| } + #|} + #|#intrinsic("%bytes.unsafe_read_uint64_le") + #|#doc(hidden) + #|pub fn Bytes::unsafe_read_uint64_le(bytes : Bytes, index : Int) -> UInt64 { + #| for i in 0..<=7; result = (0 : UInt64) { + #| continue result | (bytes.unsafe_get(i + index).to_uint64() << (8 * i)) + #| } nobreak { + #| result + #| } + #|} + #|#intrinsic("%bytes.unsafe_read_uint64_be") + #|#doc(hidden) + #|pub fn Bytes::unsafe_read_uint64_be(bytes : Bytes, index : Int) -> UInt64 { + #| for i in 0..<=7; result = (0 : UInt64) { + #| continue result | (bytes.unsafe_get(i + index).to_uint64() << (8 * (7 - i))) + #| } nobreak { + #| result + #| } + #|} + #|#intrinsic("%bytes.unsafe_read_uint32_le") + #|#doc(hidden) + #|pub fn Bytes::unsafe_read_uint32_le(bytes : Bytes, index : Int) -> UInt { + #| for i in 0..<=3; result = (0 : UInt) { + #| continue result | (bytes.unsafe_get(i + index).to_uint() << (8 * i)) + #| } nobreak { + #| result + #| } + #|} + #|#intrinsic("%bytes.unsafe_read_uint32_be") + #|#doc(hidden) + #|pub fn Bytes::unsafe_read_uint32_be(bytes : Bytes, index : Int) -> UInt { + #| for i in 0..<=3; result = (0 : UInt) { + #| continue result | (bytes.unsafe_get(i + index).to_uint() << (8 * (3 - i))) + #| } nobreak { + #| result + #| } + #|} + #|#intrinsic("%bytes.unsafe_read_uint16_le") + #|#doc(hidden) + #|pub fn Bytes::unsafe_read_uint16_le(bytes : Bytes, index : Int) -> UInt16 { + #| for i in 0..<=1; result = (0 : UInt16) { + #| continue result | (bytes.unsafe_get(i + index).to_uint16() << (8 * i)) + #| } nobreak { + #| result + #| } + #|} + #|#intrinsic("%bytes.unsafe_read_uint16_be") + #|#doc(hidden) + #|pub fn Bytes::unsafe_read_uint16_be(bytes : Bytes, index : Int) -> UInt16 { + #| for i in 0..<=1; result = (0 : UInt16) { + #| continue result | (bytes.unsafe_get(i + index).to_uint16() << (8 * (1 - i))) + #| } nobreak { + #| result + #| } + #|} + #|#doc(hidden) + #|pub fn BytesView::unsafe_read_uint64_le( + #| bytes : BytesView, + #| index : Int, + #|) -> UInt64 { + #| bytes.bytes().unsafe_read_uint64_le(bytes.start() + index) + #|} + #|#doc(hidden) + #|pub fn BytesView::unsafe_read_uint64_be( + #| bytes : BytesView, + #| index : Int, + #|) -> UInt64 { + #| bytes.bytes().unsafe_read_uint64_be(bytes.start() + index) + #|} + #|#doc(hidden) + #|pub fn BytesView::unsafe_read_uint32_le(bytes : BytesView, index : Int) -> UInt { + #| bytes.bytes().unsafe_read_uint32_le(bytes.start() + index) + #|} + #|#doc(hidden) + #|pub fn BytesView::unsafe_read_uint32_be(bytes : BytesView, index : Int) -> UInt { + #| bytes.bytes().unsafe_read_uint32_be(bytes.start() + index) + #|} + #|#doc(hidden) + #|pub fn BytesView::unsafe_read_uint16_le( + #| bytes : BytesView, + #| index : Int, + #|) -> UInt16 { + #| bytes.bytes().unsafe_read_uint16_le(bytes.start() + index) + #|} + #|#doc(hidden) + #|pub fn BytesView::unsafe_read_uint16_be( + #| bytes : BytesView, + #| index : Int, + #|) -> UInt16 { + #| bytes.bytes().unsafe_read_uint16_be(bytes.start() + index) + #|} + ), + "bytesview.mbt": ( + #|fn BytesView::bytes(self : BytesView) -> Bytes = "%bytesview.bytes" + #|fn BytesView::start(self : BytesView) -> Int = "%bytesview.start" + #|fn BytesView::len(self : BytesView) -> Int = "%bytesview.len" + #|fn BytesView::make(b : Bytes, start : Int, len : Int) -> BytesView = "%bytesview.make" + #|pub fn BytesView::length(self : BytesView) -> Int { + #| self.len() + #|} + #|pub fn BytesView::is_empty(self : BytesView) -> Bool { + #| self.length() == 0 + #|} + #|#alias("_[_]") + #|pub fn BytesView::at(self : BytesView, index : Int) -> Byte { + #| guard index >= 0 && index < self.length() else { + #| abort( + #| "index out of bounds: the len is from 0 to \{self.length()} but the index is \{index}", + #| ) + #| } + #| self.bytes()[self.start() + index] + #|} + #|pub fn BytesView::get(self : BytesView, index : Int) -> Byte? { + #| guard index >= 0 && index < self.length() else { None } + #| Some(self.bytes().unsafe_get(self.start() + index)) + #|} + #|#internal(unsafe, "Panic if index is out of bounds") + #|#doc(hidden) + #|pub fn BytesView::unsafe_get(self : BytesView, index : Int) -> Byte { + #| self.bytes().unsafe_get(self.start() + index) + #|} + #|#alias("_[_:_]") + #|#alias(sub, deprecated="Use _[_:_ instead") + #|pub fn Bytes::view(self : Bytes, start? : Int = 0, end? : Int) -> BytesView { + #| let len = self.length() + #| let end = match end { + #| None => len + #| Some(end) => if end < 0 { len + end } else { end } + #| } + #| let start = if start < 0 { len + start } else { start } + #| guard start >= 0 && start <= end && end <= len else { + #| abort("Invalid index for View") + #| } + #| BytesView::make(self, start, end - start) + #|} + #|#alias("_[_:_]") + #|#alias(sub, deprecated="Use _[_:_] instead") + #|pub fn BytesView::view( + #| self : BytesView, + #| start? : Int = 0, + #| end? : Int, + #|) -> BytesView { + #| let len = self.length() + #| let end = match end { + #| None => len + #| Some(end) => if end < 0 { len + end } else { end } + #| } + #| let start = if start < 0 { len + start } else { start } + #| guard start >= 0 && start <= end && end <= len else { + #| abort("Invalid index for View") + #| } + #| BytesView::make(self.bytes(), self.start() + start, end - start) + #|} + #|#alias(iterator, deprecated) + #|pub fn BytesView::iter(self : BytesView) -> Iter[Byte] { + #| let mut i = 0 + #| let len = self.length() + #| Iter::new(fn() { + #| guard i < len else { None } + #| let result = self.unsafe_get(i) + #| i += 1 + #| Some(result) + #| }) + #|} + #|#alias(iterator2, deprecated) + #|pub fn BytesView::iter2(self : BytesView) -> Iter2[Int, Byte] { + #| let mut i = 0 + #| let len = self.length() + #| Iter2::new(fn() { + #| guard i < len else { None } + #| let result = (i, self.unsafe_get(i)) + #| i += 1 + #| Some(result) + #| }) + #|} + #|#deprecated("Use bits pattern directly") + #|#doc(hidden) + #|pub fn BytesView::to_uint_be(self : BytesView) -> UInt { + #| (self[0].to_uint() << 24) + + #| (self[1].to_uint() << 16) + + #| (self[2].to_uint() << 8) + + #| self[3].to_uint() + #|} + #|#deprecated("Use bits pattern directly") + #|#doc(hidden) + #|pub fn BytesView::to_uint_le(self : BytesView) -> UInt { + #| self[0].to_uint() + + #| (self[1].to_uint() << 8) + + #| (self[2].to_uint() << 16) + + #| (self[3].to_uint() << 24) + #|} + #|#deprecated("Use bits pattern directly") + #|#doc(hidden) + #|pub fn BytesView::to_uint64_be(self : BytesView) -> UInt64 { + #| (self[0].to_uint().to_uint64() << 56) + + #| (self[1].to_uint().to_uint64() << 48) + + #| (self[2].to_uint().to_uint64() << 40) + + #| (self[3].to_uint().to_uint64() << 32) + + #| (self[4].to_uint().to_uint64() << 24) + + #| (self[5].to_uint().to_uint64() << 16) + + #| (self[6].to_uint().to_uint64() << 8) + + #| self[7].to_uint().to_uint64() + #|} + #|#deprecated("Use bits pattern directly") + #|#doc(hidden) + #|pub fn BytesView::to_uint64_le(self : BytesView) -> UInt64 { + #| self[0].to_uint().to_uint64() + + #| (self[1].to_uint().to_uint64() << 8) + + #| (self[2].to_uint().to_uint64() << 16) + + #| (self[3].to_uint().to_uint64() << 24) + + #| (self[4].to_uint().to_uint64() << 32) + + #| (self[5].to_uint().to_uint64() << 40) + + #| (self[6].to_uint().to_uint64() << 48) + + #| (self[7].to_uint().to_uint64() << 56) + #|} + #|#deprecated + #|#doc(hidden) + #|pub fn BytesView::to_int_be(self : BytesView) -> Int { + #| guard self is [u32be(u32), ..] + #| u32.reinterpret_as_int() + #|} + #|#deprecated + #|#doc(hidden) + #|pub fn BytesView::to_int_le(self : BytesView) -> Int { + #| guard self is [u32le(u32), ..] + #| u32.reinterpret_as_int() + #|} + #|#deprecated + #|#doc(hidden) + #|pub fn BytesView::to_int64_be(self : BytesView) -> Int64 { + #| guard self is [u64be(u64), ..] + #| u64.reinterpret_as_int64() + #|} + #|#deprecated + #|#doc(hidden) + #|pub fn BytesView::to_int64_le(self : BytesView) -> Int64 { + #| guard self is [u64le(u64), ..] + #| u64.reinterpret_as_int64() + #|} + #|#deprecated("Use bits pattern directly") + #|#doc(hidden) + #|pub fn BytesView::to_double_be(self : BytesView) -> Double { + #| guard self is [u64be(u64), ..] + #| u64.reinterpret_as_double() + #|} + #|#deprecated("Use bits pattern directly") + #|#doc(hidden) + #|pub fn BytesView::to_double_le(self : BytesView) -> Double { + #| guard self is [u64le(u64), ..] + #| u64.reinterpret_as_double() + #|} + #|pub impl Show for BytesView with output(self, logger) { + #| logger.write_string("b\"") + #| for byte in self { + #| if byte is (' '..='~') && byte != '"' && byte != '\\' { + #| logger.write_char(byte.to_char()) + #| } else { + #| logger.write_string("\\x") + #| logger.write_string(byte.to_hex()) + #| } + #| } + #| logger.write_string("\"") + #|} + #|pub impl Show for Bytes with output(self, logger) { + #| BytesView::output(self[:], logger) + #|} + #|pub impl Eq for BytesView with equal(self, other) -> Bool { + #| guard self.length() == other.length() else { return false } + #| for i in 0.. Int { + #| let self_len = self.length() + #| let other_len = other.length() + #| let cmp = self_len.compare(other_len) + #| guard cmp == 0 else { return cmp } + #| for i in 0.. Int { + #| let self_len = self.length() + #| let other_len = other.length() + #| let min_len = if self_len < other_len { self_len } else { other_len } + #| for i in 0.. Bytes { + #| self.bytes() + #|} + #|pub fn BytesView::start_offset(self : BytesView) -> Int { + #| self.start() + #|} + #|pub fn BytesView::to_bytes(self : BytesView) -> Bytes { + #| if self.length() == self.bytes().length() { + #| return self.bytes() + #| } + #| let bytes = FixedArray::make(self.length(), (0 : Byte)) + #| bytes.blit_from_bytes(0, self.bytes(), self.start_offset(), self.length()) + #| unsafe_to_bytes(bytes) + #|} + #|pub impl ToJson for BytesView with to_json(self) -> Json { + #| let sb = StringBuilder::new() + #| for byte in self { + #| if byte is (' '..='~') && byte != '"' && byte != '\\' { + #| sb.write_char(byte.to_char()) + #| } else { + #| sb.write_string("\\x") + #| sb.write_string(byte.to_hex()) + #| } + #| } + #| Json::string(sb.to_string()) + #|} + #|pub impl ToJson for Bytes with to_json(self : Bytes) -> Json { + #| BytesView::to_json(self[:]) + #|} + ), + "char.mbt": ( + #|fn Char::to_hex(char : Char) -> String { + #| let code = char.to_int() + #| match code { + #| 0..=0xFF => code.to_byte().to_hex() + #| _..=0xFFFF => (code >> 8).to_byte().to_hex() + code.to_byte().to_hex() + #| _ => + #| (code >> 16).to_byte().to_hex() + + #| (code >> 8).to_byte().to_hex() + + #| code.to_byte().to_hex() + #| } + #|} + #|test "Char::to_hex" { + #| inspect(Char::to_hex('A'), content="41") + #| inspect(Char::to_hex('a'), content="61") + #| inspect(Char::to_hex('0'), content="30") + #| inspect(Char::to_hex('\n'), content="0a") + #| inspect(Char::to_hex('\u{0}'), content="00") + #| inspect(Char::to_hex('\u{FF}'), content="ff") + #| inspect(Char::to_hex('\u{100}'), content="0100") + #| inspect(Char::to_hex('\u{1000}'), content="1000") + #| inspect(Char::to_hex('😀'), content="01f600") + #|} + #|pub impl Hash for Char with hash_combine(self, hasher) -> Unit { + #| hasher.combine_char(self) + #|} + #|pub fn Char::is_ascii(self : Self) -> Bool { + #| self is ('\u{00}'..='\u{7F}') + #|} + #|pub fn Char::is_ascii_alphabetic(self : Self) -> Bool { + #| self is ('A'..='Z' | 'a'..='z') + #|} + #|pub fn Char::is_ascii_control(self : Self) -> Bool { + #| self is ('\u{00}'..='\u{1F}' | '\u{7F}') + #|} + #|pub fn Char::is_ascii_digit(self : Self) -> Bool { + #| self is ('0'..='9') + #|} + #|pub fn Char::is_ascii_graphic(self : Self) -> Bool { + #| self is ('\u{21}'..='\u{7E}') + #|} + #|pub fn Char::is_ascii_hexdigit(self : Self) -> Bool { + #| self is ('0'..='9' | 'A'..='F' | 'a'..='f') + #|} + #|pub fn Char::is_ascii_lowercase(self : Self) -> Bool { + #| self is ('a'..='z') + #|} + #|pub fn Char::is_ascii_octdigit(self : Self) -> Bool { + #| self is ('0'..='7') + #|} + #|pub fn Char::is_ascii_punctuation(self : Self) -> Bool { + #| self + #| is ('\u{21}'..='\u{2F}' + #| | '\u{3A}'..='\u{40}' + #| | '\u{5B}'..='\u{60}' + #| | '\u{7B}'..='\u{7E}') + #|} + #|pub fn Char::is_ascii_uppercase(self : Self) -> Bool { + #| self is ('A'..='Z') + #|} + #|pub fn Char::is_ascii_whitespace(self : Self) -> Bool { + #| self is ('\u{20}' | '\u{09}' | '\u{0A}' | '\u{0B}' | '\u{0C}' | '\u{0D}') + #|} + #|pub fn Char::is_control(self : Self) -> Bool { + #| self is ('\u0000'..='\u001F' | '\u007F'..='\u009F') + #|} + #|pub fn Char::is_digit(self : Self, radix : UInt) -> Bool { + #| let v = self.to_uint() + #| match radix { + #| 2..=10 => v >= 48 && v <= radix + 47 + #| 11..=36 => + #| (v >= 48 && v <= 57) || + #| (v >= 65 && v <= radix + 54) || + #| (v >= 97 && v <= radix + 86) + #| _ => panic() + #| } + #|} + #|pub fn Char::is_whitespace(self : Self) -> Bool { + #| self + #| is ('\u0009'..='\u000D' + #| | '\u0020' + #| | '\u0085' + #| | '\u00A0' + #| | '\u1680' + #| | '\u2000'..='\u200A' + #| | '\u2028' + #| | '\u2029' + #| | '\u202F' + #| | '\u205F' + #| | '\u3000') + #|} + #|pub fn Char::is_numeric(self : Self) -> Bool { + #| self + #| is ('\u0030'..='\u0039' + #| | '\u00B2' + #| | '\u00B3' + #| | '\u00B9' + #| | '\u00BC' + #| | '\u00BD' + #| | '\u00BE' + #| | '\u0660'..='\u0669' + #| | '\u06F0'..='\u06F9' + #| | '\u07C0'..='\u07F9' + #| | '\u0966'..='\u096F' + #| | '\u09E6'..='\u09EF' + #| | '\u09F4'..='\u09F9' + #| | '\u0A66'..='\u0A6F' + #| | '\u0AE6'..='\u0AEF' + #| | '\u0B66'..='\u0B6F' + #| | '\u0B72'..='\u0B77' + #| | '\u0BE6'..='\u0BEF' + #| | '\u0BF0'..='\u0BF2' + #| | '\u0C66'..='\u0C6F' + #| | '\u0C78'..='\u0C7E' + #| | '\u0CE6'..='\u0CEF' + #| | '\u0D58'..='\u0D5E' + #| | '\u0D66'..='\u0D6F' + #| | '\u0D70'..='\u0D78' + #| | '\u0DE6'..='\u0DEF' + #| | '\u0E50'..='\u0E59' + #| | '\u0ED0'..='\u0ED9' + #| | '\u0F20'..='\u0F33' + #| | '\u1040'..='\u1049' + #| | '\u1090'..='\u1099' + #| | '\u1369'..='\u137C' + #| | '\u16EE'..='\u16F0' + #| | '\u17E0'..='\u17E9' + #| | '\u17F0'..='\u17F9' + #| | '\u1810'..='\u1819' + #| | '\u1946'..='\u194F' + #| | '\u19D0'..='\u19DA' + #| | '\u1A80'..='\u1A89' + #| | '\u1A90'..='\u1A99' + #| | '\u1B50'..='\u1B59' + #| | '\u1BB0'..='\u1BB9' + #| | '\u1C40'..='\u1C49' + #| | '\u1C50'..='\u1C59' + #| | '\u2070' + #| | '\u2074'..='\u2079' + #| | '\u2080'..='\u2089' + #| | '\u2150'..='\u2189' + #| | '\u2460'..='\u249B' + #| | '\u24EA'..='\u24FF' + #| | '\u2776'..='\u2793' + #| | '\u2CFD' + #| | '\u3007' + #| | '\u3021'..='\u3029' + #| | '\u3038'..='\u303A' + #| | '\u3192'..='\u3195' + #| | '\u3220'..='\u3229' + #| | '\u3248'..='\u324F' + #| | '\u3251'..='\u325F' + #| | '\u3280'..='\u3289' + #| | '\u32B1'..='\u32BF' + #| | '\uA620'..='\uA629' + #| | '\uA6E6'..='\uA6EF' + #| | '\uA830'..='\uA835' + #| | '\uA8D0'..='\uA8D9' + #| | '\uA900'..='\uA909' + #| | '\uA9D0'..='\uA9D9' + #| | '\uA9F0'..='\uA9F9' + #| | '\uAA50'..='\uAA59' + #| | '\uABF0'..='\uABF9' + #| | '\uFF10'..='\uFF19' + #| | '\u{10107}'..='\u{10133}' + #| | '\u{10140}'..='\u{10178}' + #| | '\u{1018A}'..='\u{1018B}' + #| | '\u{102E1}'..='\u{102FB}' + #| | '\u{10320}'..='\u{10323}' + #| | '\u{10341}' + #| | '\u{1034A}' + #| | '\u{103D1}'..='\u{103D5}' + #| | '\u{104A0}'..='\u{104A9}' + #| | '\u{10858}'..='\u{1085F}' + #| | '\u{10879}'..='\u{1087F}' + #| | '\u{108A7}'..='\u{108AF}' + #| | '\u{108FB}'..='\u{108FF}' + #| | '\u{10916}'..='\u{1091B}' + #| | '\u{109BC}'..='\u{109BD}' + #| | '\u{109C0}'..='\u{109CF}' + #| | '\u{10A40}'..='\u{10A48}' + #| | '\u{10A7D}'..='\u{10A7E}' + #| | '\u{10A9D}'..='\u{10A9F}' + #| | '\u{10AEB}'..='\u{10AEF}' + #| | '\u{10B58}'..='\u{10B5F}' + #| | '\u{10B78}'..='\u{10B7F}' + #| | '\u{10BA9}'..='\u{10BAF}' + #| | '\u{10CFA}'..='\u{10CFF}' + #| | '\u{10D30}'..='\u{10D39}' + #| | '\u{10D40}'..='\u{10D49}' + #| | '\u{10E60}'..='\u{10E7E}' + #| | '\u{10F1D}'..='\u{10F26}' + #| | '\u{10F51}'..='\u{10F54}' + #| | '\u{10FC5}'..='\u{10FCB}' + #| | '\u{11052}'..='\u{1106F}' + #| | '\u{110F0}'..='\u{110F9}' + #| | '\u{11136}'..='\u{1113F}' + #| | '\u{111D0}'..='\u{111D9}' + #| | '\u{111E1}'..='\u{111F4}' + #| | '\u{112F0}'..='\u{112F9}' + #| | '\u{11450}'..='\u{11459}' + #| | '\u{114D0}'..='\u{114D9}' + #| | '\u{11650}'..='\u{11659}' + #| | '\u{116C0}'..='\u{116C9}' + #| | '\u{116D0}'..='\u{116E3}' + #| | '\u{11730}'..='\u{1173B}' + #| | '\u{118E0}'..='\u{118F2}' + #| | '\u{11950}'..='\u{11959}' + #| | '\u{11BF0}'..='\u{11BF9}' + #| | '\u{11C50}'..='\u{11C6C}' + #| | '\u{11D50}'..='\u{11D59}' + #| | '\u{11DA0}'..='\u{11DA9}' + #| | '\u{11F50}'..='\u{11F59}' + #| | '\u{11FC0}'..='\u{11FD4}' + #| | '\u{12400}'..='\u{1246E}' + #| | '\u{16130}'..='\u{16139}' + #| | '\u{16A60}'..='\u{16A69}' + #| | '\u{16AC0}'..='\u{16AC9}' + #| | '\u{16B50}'..='\u{16B59}' + #| | '\u{16B5B}'..='\u{16B61}' + #| | '\u{16D70}'..='\u{16D79}' + #| | '\u{16D80}'..='\u{16E96}' + #| | '\u{1CCF0}'..='\u{1CCF9}' + #| | '\u{1D2C0}'..='\u{1D2F3}' + #| | '\u{1D360}'..='\u{1D378}' + #| | '\u{1D7CE}'..='\u{1D7FF}' + #| | '\u{1E140}'..='\u{1E149}' + #| | '\u{1E2F0}'..='\u{1E2F9}' + #| | '\u{1E4F0}'..='\u{1E4F9}' + #| | '\u{1E5F1}'..='\u{1E5FA}' + #| | '\u{1E8C7}'..='\u{1E8CF}' + #| | '\u{1E950}'..='\u{1E959}' + #| | '\u{1EC71}'..='\u{1ECB4}' + #| | '\u{1ED01}'..='\u{1ED3D}' + #| | '\u{1F100}'..='\u{1F10C}' + #| | '\u{1FBF0}'..='\u{1FBF9}') + #|} + #|pub fn Char::is_printable(self : Self) -> Bool { + #| if self.is_control() { + #| return false + #| } + #| let self = self.to_int() + #| if self is (0xE000..=0xF8FF | 0xF0000..=0xFFFFD | 0x100000..=0x10FFFD) { + #| return false + #| } + #| if self + #| is ('\u{00AD}' + #| | '\u{0600}'..='\u{0605}' + #| | '\u{061C}' + #| | '\u{06DD}' + #| | '\u{070F}' + #| | '\u{0890}'..='\u{0891}' + #| | '\u{08E2}' + #| | '\u{180E}' + #| | '\u{200B}'..='\u{200F}' + #| | '\u{202A}'..='\u{202E}' + #| | '\u{2060}'..='\u{2064}' + #| | '\u{2066}'..='\u{206F}' + #| | '\u{feff}' + #| | '\u{FFF9}'..='\u{FFFB}' + #| | '\u{110BD}' + #| | '\u{110CD}' + #| | '\u{13430}'..='\u{1343F}' + #| | '\u{1BCA0}'..='\u{1BCA3}' + #| | '\u{1D173}'..='\u{1D17A}' + #| | '\u{E0001}' + #| | '\u{E0020}'..='\u{E007F}') { + #| return false + #| } + #| if self.is_surrogate() { + #| return false + #| } + #| if self == '\u{2028}' || self == '\u{2029}' { + #| return false + #| } + #| if self + #| is (0xFDD0..=0xFDEF + #| | 0xFFFE..=0xFFFF + #| | 0x1FFFE..=0x1FFFF + #| | 0x2FFFE..=0x2FFFF + #| | 0x3FFFE..=0x3FFFF + #| | 0x4FFFE..=0x4FFFF + #| | 0x5FFFE..=0x5FFFF + #| | 0x6FFFE..=0x6FFFF + #| | 0x7FFFE..=0x7FFFF + #| | 0x8FFFE..=0x8FFFF + #| | 0x9FFFE..=0x9FFFF + #| | 0xAFFFE..=0xAFFFF + #| | 0xBFFFE..=0xBFFFF + #| | 0xCFFFE..=0xCFFFF + #| | 0xDFFFE..=0xDFFFF + #| | 0xEFFFE..=0xEFFFF + #| | 0xFFFFE..=0xFFFFF + #| | 0x10FFFE..=0x10FFFF) { + #| return false + #| } + #| true + #|} + #|pub fn Char::to_ascii_lowercase(self : Self) -> Char { + #| if self.is_ascii_uppercase() { + #| return (self.to_int() + 32).unsafe_to_char() + #| } + #| self + #|} + #|pub fn Char::to_ascii_uppercase(self : Self) -> Char { + #| if self.is_ascii_lowercase() { + #| return (self.to_int() - 32).unsafe_to_char() + #| } + #| self + #|} + #|pub impl Show for Char with to_string(self : Char) -> String { + #| char_to_string(self) + #|} + #|#intrinsic("%char.to_string") + #|fn char_to_string(char : Char) -> String { + #| [char] + #|} + #|pub fn Char::escape(self : Char, quote? : Bool = true) -> String { + #| let buf = StringBuilder::new() + #| self.escape_to(buf, quote~) + #| buf.to_string() + #|} + #|fn Char::escape_to(self : Char, logger : &Logger, quote? : Bool = true) -> Unit { + #| if quote { + #| logger.write_char('\'') + #| } + #| match self { + #| '\'' | '\\' => { + #| logger.write_char('\\') + #| logger.write_char(self) + #| } + #| '\n' => logger.write_string("\\n") + #| '\r' => logger.write_string("\\r") + #| '\b' => logger.write_string("\\b") + #| '\t' => logger.write_string("\\t") + #| ' '..='~' => logger.write_char(self) + #| _ => + #| if !self.is_printable() { + #| logger.write_string("\\u{") + #| logger.write_string(self.to_hex()) + #| logger.write_char('}') + #| } else { + #| logger.write_char(self) + #| } + #| } + #| if quote { + #| logger.write_char('\'') + #| } + #|} + #|pub impl Show for Char with output(self, logger) { + #| self.escape_to(logger) + #|} + #|pub impl ToJson for Char with to_json(self : Char) -> Json { + #| Json::string(self.to_string()) + #|} + #|pub fn Char::utf16_len(self : Self) -> Int { + #| let code = self.to_int() + #| if code <= 0xFFFF { + #| 1 + #| } else { + #| 2 + #| } + #|} + #|pub fn Char::is_bmp(self : Self) -> Bool { + #| self.to_int() <= 0xFFFF + #|} + ), + "console.mbt": ( + #|fn println_mono(s : String) -> Unit = "%println" + #|pub fn[T : Show] println(input : T) -> Unit { + #| println_mono(input.to_string()) + #|} + #|pub(all) suberror InspectError { + #| InspectError(String) + #|} + #|fn base64_encode(data : FixedArray[Byte]) -> String { + #| let base64 = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + #| let buf = StringBuilder::new() + #| let len = data.length() + #| let rem = len % 3 + #| for i = 0; i < len - rem; i = i + 3 { + #| let b0 = data[i].to_int() + #| let b1 = data[i + 1].to_int() + #| let b2 = data[i + 2].to_int() + #| let x0 = base64[(b0 & 0xFC) >> 2] + #| let x1 = base64[((b0 & 0x03) << 4) | ((b1 & 0xF0) >> 4)] + #| let x2 = base64[((b1 & 0x0F) << 2) | ((b2 & 0xC0) >> 6)] + #| let x3 = base64[b2 & 0x3F] + #| buf.write_char(x0.to_char()) + #| buf.write_char(x1.to_char()) + #| buf.write_char(x2.to_char()) + #| buf.write_char(x3.to_char()) + #| } + #| if rem == 1 { + #| let b0 = data[len - 1].to_int() + #| let x0 = base64[(b0 & 0xFC) >> 2] + #| let x1 = base64[(b0 & 0x03) << 4] + #| buf.write_char(x0.to_char()) + #| buf.write_char(x1.to_char()) + #| buf.write_char('=') + #| buf.write_char('=') + #| } else if rem == 2 { + #| let b0 = data[len - 2].to_int() + #| let b1 = data[len - 1].to_int() + #| let x0 = base64[(b0 & 0xFC) >> 2] + #| let x1 = base64[((b0 & 0x03) << 4) | ((b1 & 0xF0) >> 4)] + #| let x2 = base64[(b1 & 0x0F) << 2] + #| buf.write_char(x0.to_char()) + #| buf.write_char(x1.to_char()) + #| buf.write_char(x2.to_char()) + #| buf.write_char('=') + #| } + #| buf.to_string() + #|} + #|fn base64_encode_string_codepoint(s : String) -> String { + #| let codepoint_length = s.char_length() + #| let data : FixedArray[Byte] = FixedArray::make(codepoint_length * 4, 0) + #| for i = 0, utf16_index = 0 + #| i < codepoint_length + #| i = i + 1, utf16_index = utf16_index + 1 { + #| let c = s.unsafe_char_at(utf16_index).to_int() + #| if c > 0xFFFF { + #| data[i * 4] = (c & 0xFF).to_byte() + #| data[i * 4 + 1] = ((c >> 8) & 0xFF).to_byte() + #| data[i * 4 + 2] = ((c >> 16) & 0xFF).to_byte() + #| data[i * 4 + 3] = ((c >> 24) & 0xFF).to_byte() + #| continue i + 1, utf16_index + 2 + #| } else { + #| data[i * 4] = (c & 0xFF).to_byte() + #| data[i * 4 + 1] = ((c >> 8) & 0xFF).to_byte() + #| data[i * 4 + 2] = 0 + #| data[i * 4 + 3] = 0 + #| } + #| } + #| base64_encode(data) + #|} + #|test { + #| inspect(base64_encode_string_codepoint("")) + #| inspect(base64_encode_string_codepoint("a"), content="YQAAAA==") + #| inspect(base64_encode_string_codepoint("ab"), content="YQAAAGIAAAA=") + #| inspect(base64_encode_string_codepoint("abc"), content="YQAAAGIAAABjAAAA") + #| inspect( + #| base64_encode_string_codepoint("abcd"), + #| content="YQAAAGIAAABjAAAAZAAAAA==", + #| ) + #| inspect( + #| base64_encode_string_codepoint("abcde"), + #| content="YQAAAGIAAABjAAAAZAAAAGUAAAA=", + #| ) + #| inspect(base64_encode_string_codepoint("a中"), content="YQAAAC1OAAA=") + #| inspect( + #| base64_encode_string_codepoint("a中🤣"), + #| content="YQAAAC1OAAAj+QEA", + #| ) + #| inspect( + #| base64_encode_string_codepoint("a中🤣a"), + #| content="YQAAAC1OAAAj+QEAYQAAAA==", + #| ) + #| inspect( + #| base64_encode_string_codepoint("a中🤣中"), + #| content="YQAAAC1OAAAj+QEALU4AAA==", + #| ) + #|} + #|#callsite(autofill(args_loc, loc)) + #|pub fn inspect( + #| obj : &Show, + #| content? : String = "", + #| loc~ : SourceLoc, + #| args_loc~ : ArgsLoc, + #|) -> Unit raise InspectError { + #| let actual = obj.to_string() + #| if actual != content { + #| let loc = loc.to_json_string() + #| let args_loc = args_loc.to_json() + #| let expect_escaped = content.escape() + #| let actual_escaped = actual.escape() + #| let expect_base64 = "\"\{base64_encode_string_codepoint(content)}\"" + #| let actual_base64 = "\"\{base64_encode_string_codepoint(actual)}\"" + #| raise InspectError( + #| "@EXPECT_FAILED {\"loc\": \{loc}, \"args_loc\": \{args_loc}, \"expect\": \{expect_escaped}, \"actual\": \{actual_escaped}, \"expect_base64\": \{expect_base64}, \"actual_base64\": \{actual_base64}}", + #| ) + #| } + #|} + #|pub(all) suberror SnapshotError { + #| SnapshotError(String) + #|} + #|#deprecated + #|pub(all) suberror BenchError { + #| BenchError(String) + #|} + #|test "panic error case of inspect" { + #| let x : Int = 42 + #| inspect(x, content="100") + #|} + ), + "deprecated.mbt": ( + #|#deprecated("check `@encoding/utf8.encode`") + #|#coverage.skip + #|pub fn Bytes::of_string(str : String) -> Bytes { + #| let arr = FixedArray::make(str.length() * 2, Byte::default()) + #| arr.blit_from_string(0, str, 0, str.length()) + #| arr.unsafe_reinterpret_as_bytes() + #|} + #|#deprecated("Bytes are immutable. Use `FixedArray::blit_from_bytes` if it's really necessary.") + #|#alias(clone, deprecated) + #|pub fn Bytes::copy(self : Bytes) -> Bytes { + #| Bytes::makei(self.length(), i => self[i]) + #|} + #|#deprecated("Use infix operator `<<` instead") + #|#coverage.skip + #|pub fn Byte::lsl(self : Byte, count : Int) -> Byte { + #| (self.to_int() << count).to_byte() + #|} + #|#deprecated("Use infix operator `>>` instead") + #|#coverage.skip + #|pub fn Byte::lsr(self : Byte, count : Int) -> Byte { + #| (self.to_uint() >> count).reinterpret_as_int().to_byte() + #|} + #|#deprecated("Use `s.get_char(i).unwrap()` instead", skip_current_package=true) + #|pub fn String::unsafe_char_at(self : String, index : Int) -> Char { + #| let c1 = self.unsafe_get(index) + #| if c1.is_leading_surrogate() { + #| let c2 = self.unsafe_get(index + 1) + #| code_point_of_surrogate_pair(c1.to_int(), c2.to_int()) + #| } else { + #| c1.unsafe_to_char() + #| } + #|} + ), + "double.mbt": ( + #|pub fn Double::from_int(i : Int) -> Double { + #| i.to_double() + #|} + #|pub fn Double::abs(self : Double) -> Double = "%f64.abs" + #|pub fn Double::min(self : Double, other : Double) -> Double { + #| if self.is_nan() { + #| other + #| } else if other.is_nan() { + #| self + #| } else if self < other { + #| self + #| } else { + #| other + #| } + #|} + #|pub fn Double::max(self : Double, other : Double) -> Double { + #| if self.is_nan() { + #| other + #| } else if other.is_nan() { + #| self + #| } else if self > other { + #| self + #| } else { + #| other + #| } + #|} + #|pub fn Double::clamp(self : Double, min~ : Double, max~ : Double) -> Double { + #| guard min <= max + #| if self < min { + #| min + #| } else if self > max { + #| max + #| } else { + #| self + #| } + #|} + #|pub fn Double::lerp(self : Double, target~ : Double, t~ : Double) -> Double { + #| self + (target - self) * t + #|} + #|pub fn Double::signum(self : Double) -> Double { + #| if self < 0.0 { + #| -1.0 + #| } else if self > 0.0 { + #| 1.0 + #| } else { + #| self // handles 0.0, -0.0, NaN + #| } + #|} + #|pub fn Double::is_nan(self : Double) -> Bool { + #| self != self + #|} + #|pub fn Double::is_inf(self : Double) -> Bool { + #| self > double_max_value || self < double_min_value + #|} + #|pub fn Double::is_pos_inf(self : Double) -> Bool { + #| self > double_max_value + #|} + #|pub fn Double::is_neg_inf(self : Double) -> Bool { + #| self < double_min_value + #|} + #|pub impl Hash for Double with hash_combine(self, hasher) { + #| hasher.combine_double(self) + #|} + #|pub fn Double::to_string(self : Double) -> String { + #| ryu_to_string(self) + #|} + #|pub impl Show for Double with output(self, logger) { + #| logger.write_string(self.to_string()) + #|} + #|pub fn Double::is_close( + #| self : Self, + #| other : Self, + #| relative_tolerance? : Self = 1.0e-09, + #| absolute_tolerance? : Self = 0.0, + #|) -> Bool { + #| if relative_tolerance < 0.0 || absolute_tolerance < 0.0 { + #| abort("Tolerances must be non-negative") + #| } + #| if self == other { + #| return true + #| } + #| if self.is_inf() || other.is_inf() { + #| return false + #| } + #| let diff = (other - self).abs() + #| return ( + #| diff <= (relative_tolerance * other).abs() || + #| diff <= (relative_tolerance * self).abs() + #| ) || + #| diff <= absolute_tolerance + #|} + #|#deprecated + #|#doc(hidden) + #|pub fn Double::to_be_bytes(self : Double) -> Bytes { + #| self.reinterpret_as_uint64().to_be_bytes() + #|} + #|#deprecated + #|#doc(hidden) + #|pub fn Double::to_le_bytes(self : Double) -> Bytes { + #| self.reinterpret_as_uint64().to_le_bytes() + #|} + ), + "double_limits.mbt": ( + #|#cfg(not(target="js")) + #|let not_a_number : Double = 0x7FF8000000000001L.reinterpret_as_double() + #|let double_max_value : Double = 0x7FEFFFFFFFFFFFFFL.reinterpret_as_double() + #|let double_min_value : Double = 0xFFEFFFFFFFFFFFFFL.reinterpret_as_double() + ), + "double_mod_js.mbt": ( + #|extern "js" fn Double::mod_ffi(self : Double, other : Double) -> Double = + #| #| (a, b) => (a % b) + #|pub impl Mod for Double with mod(self, other) { + #| self.mod_ffi(other) + #|} + ), + "double_mod_nonjs.mbt": ( + #|pub impl Mod for Double with mod(self : Double, other : Double) -> Double { + #| let x = self + #| let y = other + #| let mut uint64_x = x.reinterpret_as_uint64() + #| let mut uint64_y = y.reinterpret_as_uint64() + #| let mut ex = ((uint64_x >> 52) & 0x7FF).to_int() + #| let mut ey = ((uint64_y >> 52) & 0x7FF).to_int() + #| let sign_x = uint64_x >> 63 + #| let mut i : UInt64 = 0 + #| if uint64_y << 1 == 0 || y.is_nan() || ex == 0x7ff { + #| return x * y / (x * y) + #| } + #| if uint64_x << 1 <= uint64_y << 1 { + #| if uint64_x << 1 == uint64_y << 1 { + #| return 0.0 * x + #| } + #| return x + #| } + #| if ex == 0 { + #| i = uint64_x << 12 + #| while i >> 63 == 0 { + #| ex -= 1 + #| i = i << 1 + #| } + #| uint64_x = uint64_x << (-ex + 1) + #| } else { + #| uint64_x = uint64_x & (18446744073709551615UL >> 12) + #| uint64_x = uint64_x | (1UL << 52) + #| } + #| if ey == 0 { + #| i = uint64_y << 12 + #| while i >> 63 == 0 { + #| ey -= 1 + #| i = i << 1 + #| } + #| uint64_y = uint64_y << (-ey + 1) + #| } else { + #| uint64_y = uint64_y & (18446744073709551615UL >> 12) + #| uint64_y = uint64_y | (1UL << 52) + #| } + #| while ex > ey { + #| i = uint64_x - uint64_y + #| if i >> 63 == 0 { + #| if i == 0 { + #| return 0.0 * x + #| } + #| uint64_x = i + #| } + #| uint64_x = uint64_x << 1 + #| ex -= 1 + #| } + #| i = uint64_x - uint64_y + #| if i >> 63 == 0 { + #| if i == 0 { + #| return 0.0 * x + #| } + #| uint64_x = i + #| } + #| while uint64_x >> 52 == 0 { + #| uint64_x = uint64_x << 1 + #| ex -= 1 + #| } + #| if ex > 0 { + #| uint64_x = uint64_x - (1UL << 52) + #| uint64_x = uint64_x | (ex.to_uint64() << 52) + #| } else { + #| uint64_x = uint64_x >> (-ex + 1) + #| } + #| uint64_x = uint64_x | (sign_x << 63) + #| uint64_x.reinterpret_as_double() + #|} + ), + "double_pow_js.mbt": ( + #|#deprecated("Use `@math.pow` instead") + #|pub fn Double::pow(self : Double, other : Double) -> Double = "Math" "pow" + #|let _j : (FixedArray[String], StringView) -> String = FixedArray::join + ), + "double_pow_nonjs.mbt": ( + #|let pow_bp : ReadOnlyArray[Double] = [1.0, 1.5] + #|let pow_dp_h : ReadOnlyArray[Double] = [0.0, 5.84962487220764160156e-01] + #|let pow_dp_l : ReadOnlyArray[Double] = [0.0, 1.35003920212974897128e-08] + #|const ZERO = 0.0 + #|const ONE = 1.0 + #|const TWO = 2.0 + #|const POW_two53 = 9007199254740992.0 + #|const POW_huge = 1.0e300 + #|const POW_tiny = 1.0e-300 + #|const POW_L1 = 5.99999999999994648725e-01 + #|const POW_L2 = 4.28571428578550184252e-01 + #|const POW_L3 = 3.33333329818377432918e-01 + #|const POW_L4 = 2.72728123808534006489e-01 + #|const POW_L5 = 2.30660745775561754067e-01 + #|const POW_L6 = 2.06975017800338417784e-01 + #|const POW_P1 = 1.66666666666666019037e-01 + #|const POW_P2 = -2.77777777770155933842e-03 + #|const POW_P3 = 6.61375632143793436117e-05 + #|const POW_P4 = -1.65339022054652515390e-06 + #|const POW_P5 = 4.13813679705723846039e-08 + #|const POW_lg2 = 6.93147180559945286227e-01 + #|const POW_lg2_h = 6.93147182464599609375e-01 + #|const POW_lg2_l = -1.90465429995776804525e-09 + #|const POW_ovt = 8.0085662595372944372e-0017 + #|const POW_cp = 9.61796693925975554329e-01 + #|const POW_cp_h = 9.61796700954437255859e-01 + #|const POW_cp_l = -7.02846165095275826516e-09 + #|const POW_ivln2 = 1.44269504088896338700e+00 + #|const POW_ivln2_h = 1.44269502162933349609e+00 + #|const POW_ivln2_l = 1.92596299112661746887e-08 + #|#deprecated("Use `@math.pow` instead") + #|pub fn Double::pow(self : Double, other : Double) -> Double { + #| fn set_low_word(d : Double, v : UInt) -> Double { + #| let bits : UInt64 = d.reinterpret_as_uint64() + #| let bits = bits & 0xFFFF_FFFF_0000_0000 + #| let bits = bits | v.to_uint64() + #| bits.reinterpret_as_double() + #| } + #| fn set_high_word(d : Double, v : UInt) -> Double { + #| let bits : UInt64 = d.reinterpret_as_uint64() + #| let bits = bits & 0x0000_0000_FFFF_FFFF + #| let bits = bits | (v.to_uint64() << 32) + #| bits.reinterpret_as_double() + #| } + #| fn get_high_word(x : Double) -> UInt { + #| (x.reinterpret_as_uint64() >> 32).to_uint() + #| } + #| fn get_low_word(x : Double) -> UInt { + #| x.reinterpret_as_uint64().to_uint() + #| } + #| let x = self + #| let y = other + #| let mut z : Double = 0.0 + #| let mut ax : Double = 0.0 + #| let mut z_h : Double = 0.0 + #| let mut z_l : Double = 0.0 + #| let mut p_h : Double = 0.0 + #| let mut p_l : Double = 0.0 + #| let mut y1 : Double = 0.0 + #| let mut t1 : Double = 0.0 + #| let mut t2 : Double = 0.0 + #| let mut r : Double = 0.0 + #| let mut s : Double = 0.0 + #| let mut t : Double = 0.0 + #| let mut u : Double = 0.0 + #| let mut v : Double = 0.0 + #| let mut w : Double = 0.0 + #| let mut i : Int = 0 + #| let mut j : Int = 0 + #| let mut k : Int = 0 + #| let mut yisint : Int = 0 + #| let mut n : Int = 0 + #| let hx : Int = (x.reinterpret_as_uint64() >> 32).to_int() + #| let lx : UInt = (x.reinterpret_as_uint64() & 0xFFFFFFFF).to_uint() + #| let hy : Int = (y.reinterpret_as_uint64() >> 32).to_int() + #| let ly : UInt = (y.reinterpret_as_uint64() & 0xFFFFFFFF).to_uint() + #| let mut ix : Int = hx & 0x7FFFFFFF + #| let iy : Int = hy & 0x7FFFFFFF + #| if (iy.reinterpret_as_uint() | ly) == 0 { + #| return ONE + #| } + #| if ix > 0x7FF00000 || + #| (ix == 0x7FF00000 && lx != 0) || + #| iy > 0x7FF00000 || + #| (iy == 0x7FF00000 && ly != 0) { + #| return x + y + #| } + #| if hx < 0 { + #| if iy >= 0x43400000 { + #| yisint = 2 // even integer y + #| } else if iy >= 0x3ff00000 { + #| k = (iy >> 20) - 0x3ff // exponent + #| if k > 20 { + #| j = (ly >> (52 - k)).reinterpret_as_int() + #| if j << (52 - k) == ly.reinterpret_as_int() { + #| yisint = 2 - (j & 1) + #| } + #| } else if ly == 0 { + #| j = iy >> (20 - k) + #| if j << (20 - k) == iy { + #| yisint = 2 - (j & 1) + #| } + #| } + #| } + #| } + #| if ly == 0 { + #| if iy == 0x7ff00000 { // y is +-inf + #| if ((ix.reinterpret_as_uint() - 0x3ff00000) | lx) == 0 { + #| return y - y // inf**+-1 is NaN + #| } else if ix >= 0x3ff00000 { // (|x|>1)**+-inf = inf,0 + #| return if hy >= 0 { y } else { ZERO } + #| } else { // (|x|<1)**-,+inf = inf,0 + #| return if hy < 0 { -y } else { ZERO } + #| } + #| } + #| if iy == 0x3ff00000 { // y is +-1 + #| if hy < 0 { + #| return ONE / x + #| } else { + #| return x + #| } + #| } + #| if hy == 0x40000000 { // y is 2 + #| return x * x + #| } + #| if hy == 0x3fe00000 { // y is 0.5 + #| if hx >= 0 { // x >= +0 + #| return x.sqrt() + #| } + #| } + #| } + #| ax = x.abs() + #| if lx == 0 { + #| if ix == 0x7ff00000 || ix == 0 || ix == 0x3ff00000 { + #| z = ax // x is +-0,+-inf,+-1 */ + #| if hy < 0 { + #| z = ONE / z // z = (1/|x|) + #| } + #| if hx < 0 { + #| if ((ix - 0x3ff00000) | yisint) == 0 { + #| z = not_a_number + #| } else if yisint == 1 { + #| z = -z // (x<0)**odd = -(|x|**odd) + #| } + #| } + #| return z + #| } + #| } + #| n = (hx >> 31) + 1 + #| if (n | yisint) == 0 { + #| return not_a_number + #| } + #| s = ONE // s (sign of result -ve**odd) = -1 else = 1 + #| if (n | (yisint - 1)) == 0 { + #| s = -ONE // (-ve)**(odd int) + #| } + #| if iy > 0x41e00000 { // if |y| > 2**31 */ + #| if iy > 0x43f00000 { // if |y| > 2**64, must o/uflow */ + #| if ix <= 0x3fefffff { + #| return if hy < 0 { POW_huge * POW_huge } else { POW_tiny * POW_tiny } + #| } + #| if ix >= 0x3ff00000 { + #| return if hy > 0 { POW_huge * POW_huge } else { POW_tiny * POW_tiny } + #| } + #| } + #| if ix < 0x3fefffff { + #| return if hy < 0 { + #| s * POW_huge * POW_huge + #| } else { + #| s * POW_tiny * POW_tiny + #| } + #| } + #| if ix > 0x3ff00000 { + #| return if hy > 0 { + #| s * POW_huge * POW_huge + #| } else { + #| s * POW_tiny * POW_tiny + #| } + #| } + #| t = ax - ONE // t has 20 trailing zeros */ + #| w = t * t * (0.5 - t * (0.3333333333333333333333 - t * 0.25)) + #| u = POW_ivln2_h * t // POW_ivln2_h has 21 sig. bits */ + #| v = t * POW_ivln2_l - w * POW_ivln2 + #| t1 = u + v + #| t1 = set_low_word(t1, 0) + #| t2 = v - (t1 - u) + #| } else { + #| n = 0 + #| if ix < 0x00100000 { + #| ax *= POW_two53 + #| n -= 53 + #| ix = get_high_word(ax).reinterpret_as_int() + #| } + #| n += (ix >> 20) - 0x3ff + #| j = ix & 0x000fffff + #| ix = j | 0x3ff00000 // normalize ix + #| if j <= 0x3988E { + #| k = 0 // |x|> 1) | 0x20000000) + + #| 0x00080000 + + #| (k.reinterpret_as_uint() << 18), + #| ) + #| let mut t_l : Double = ax - (t_h - pow_bp[k]) + #| let s_l : Double = v * (u - s_h * t_h - s_h * t_l) + #| let mut s2 : Double = ss * ss + #| r = s2 * + #| s2 * + #| ( + #| POW_L1 + + #| s2 * + #| (POW_L2 + s2 * (POW_L3 + s2 * (POW_L4 + s2 * (POW_L5 + s2 * POW_L6)))) + #| ) + #| r += s_l * (s_h + ss) + #| s2 = s_h * s_h + #| t_h = 3.0 + s2 + r + #| t_h = set_low_word(t_h, 0) + #| t_l = r - (t_h - 3.0 - s2) + #| u = s_h * t_h + #| v = s_l * t_h + t_l * ss + #| p_h = u + v + #| p_h = set_low_word(p_h, 0) + #| p_l = v - (p_h - u) + #| z_h = POW_cp_h * p_h // cp_h+cp_l = 2/(3*log2) + #| z_l = POW_cp_l * p_h + p_l * POW_cp + pow_dp_l[k] + #| t = n.to_double() + #| t1 = z_h + z_l + pow_dp_h[k] + t + #| t1 = set_low_word(t1, 0) + #| t2 = z_l - (t1 - t - pow_dp_h[k] - z_h) + #| } + #| y1 = y + #| y1 = set_low_word(y1, 0) + #| p_l = (y - y1) * t1 + y * t2 + #| p_h = y1 * t1 + #| z = p_l + p_h + #| j = get_high_word(z).reinterpret_as_int() + #| i = get_low_word(z).reinterpret_as_int() + #| if j >= 0x40900000 { // z >= 1024 + #| if ((j - 0x40900000) | i) != 0 { // if z > 1024 + #| return s * POW_huge * POW_huge // overflow + #| } else if p_l + POW_ovt > z - p_h { + #| return s * POW_huge * POW_huge // overflow + #| } + #| } else if (j & 0x7fffffff) >= 0x4090cc00 { // z <= -1075 + #| if ((j - 0xc090cc00) | i) != 0 { // z < -1075 + #| return s * POW_tiny * POW_tiny // underflow + #| } else if p_l <= z - p_h { + #| return s * POW_tiny * POW_tiny // underflow + #| } + #| } + #| i = j & 0x7fffffff + #| k = (i >> 20) - 0x3ff + #| n = 0 + #| if i > 0x3fe00000 { // if |z| > 0.5, set n = [z+0.5] + #| n = j + (0x00100000 >> (k + 1)) + #| k = ((n & 0x7fffffff) >> 20) - 0x3ff // new k for n + #| t = ZERO + #| t = set_high_word(t, (n & (0x000fffff >> k).lnot()).reinterpret_as_uint()) + #| n = ((n & 0x000fffff) | 0x00100000) >> (20 - k) + #| if j < 0 { + #| n = -n + #| } + #| p_h -= t + #| } + #| t = p_l + p_h + #| t = set_low_word(t, 0) + #| u = t * POW_lg2_h + #| v = (p_l - (t - p_h)) * POW_lg2 + t * POW_lg2_l + #| z = u + v + #| w = v - (z - u) + #| t = z * z + #| t1 = z - + #| t * (POW_P1 + t * (POW_P2 + t * (POW_P3 + t * (POW_P4 + t * POW_P5)))) + #| r = z * t1 / (t1 - TWO - (w + z * w)) + #| z = ONE - (r - z) + #| j = get_high_word(z).reinterpret_as_int() + #| j += (n.reinterpret_as_uint() << 20).reinterpret_as_int() + #| if j >> 20 <= 0 { + #| z = scalbn(z, n) + #| } else { // subnormal output */ + #| let tmp = get_high_word(z).reinterpret_as_int() + #| z = set_high_word( + #| z, + #| (tmp + (n.reinterpret_as_uint() << 20).reinterpret_as_int()).reinterpret_as_uint(), + #| ) + #| } + #| return s * z + #|} + ), + "double_round.mbt": ( + #|let sign_mask : UInt64 = 0x8000_0000_0000_0000 + #|let exp_bias = 1023 + #|let exp_bits = 11 + #|let frac_bits = 52 + #|pub fn Double::trunc(self : Double) -> Double { + #| let u64 = self.reinterpret_as_uint64() + #| let biased_exp = ((u64 >> frac_bits) & ((0x1UL << exp_bits) - 1)).to_int() + #| if biased_exp < exp_bias { + #| return (u64 & sign_mask).reinterpret_as_double() + #| } else if biased_exp >= exp_bias + frac_bits { + #| return self + #| } + #| let mask_shift = biased_exp - exp_bias + exp_bits + #| let trunc_mask = (sign_mask.reinterpret_as_int64() >> mask_shift).reinterpret_as_uint64() + #| return (u64 & trunc_mask).reinterpret_as_double() + #|} + #|pub fn Double::ceil(self : Double) -> Double { + #| let trunced = self.trunc() + #| if self > trunced { + #| return trunced + 1.0 + #| } else { + #| return trunced + #| } + #|} + #|pub fn Double::floor(self : Double) -> Double { + #| let trunced = self.trunc() + #| if self < trunced { + #| return trunced - 1.0 + #| } else { + #| return trunced + #| } + #|} + #|pub fn Double::round(self : Double) -> Double { + #| (self + 0.5).floor() + #|} + ), + "double_round_js.mbt": ( + #|pub fn Double::trunc(self : Double) -> Double = "Math" "trunc" + #|pub fn Double::ceil(self : Double) -> Double = "Math" "ceil" + #|pub fn Double::floor(self : Double) -> Double = "Math" "floor" + #|pub fn Double::round(self : Double) -> Double = "Math" "round" + ), + "double_round_wasm.mbt": ( + #|pub fn Double::trunc(self : Double) -> Double = "(func (param $d f64) (result f64) (f64.trunc (local.get $d)))" + #|pub fn Double::ceil(self : Double) -> Double = "(func (param $d f64) (result f64) (f64.ceil (local.get $d)))" + #|pub fn Double::floor(self : Double) -> Double = "(func (param $d f64) (result f64) (f64.floor (local.get $d)))" + #|pub fn Double::round(self : Double) -> Double { + #| (self + 0.5).floor() + #|} + ), + "double_ryu_js.mbt": ( + #|extern "js" fn ryu_to_string(val : Double) -> String = + #| #|(number) => number.toString() + ), + "double_ryu_nonjs.mbt": ( + #|fn pow5bits(e : Int) -> Int { + #| ((e * 1217359).reinterpret_as_uint() >> 19).reinterpret_as_int() + 1 + #|} + #|fn copy_special_str(sign : Bool, exponent : Bool, mantissa : Bool) -> String { + #| if mantissa { + #| return "NaN" + #| } + #| let s = if sign { "-" } else { "" } + #| if exponent { + #| return s + "Infinity" + #| } + #| return s + "0.0" + #|} + #|fn log10Pow5(e : Int) -> Int { + #| ((e * 732923).reinterpret_as_uint() >> 20).reinterpret_as_int() + #|} + #|fn log10Pow2(e : Int) -> Int { + #| ((e * 78913).reinterpret_as_uint() >> 18).reinterpret_as_int() + #|} + #|fn string_from_bytes(bytes : FixedArray[Byte], from : Int, to : Int) -> String { + #| let buf = StringBuilder::new(size_hint=bytes.length()) + #| for i in from.. Umul128 { + #| let aLo = a & 0xffffffff + #| let aHi = a >> 32 + #| let bLo = b & 0xffffffff + #| let bHi = b >> 32 + #| let x = aLo * bLo + #| let y = aHi * bLo + (x >> 32) + #| let z = aLo * bHi + (y & 0xffffffff) + #| let w = aHi * bHi + (y >> 32) + (z >> 32) + #| let lo = a * b + #| let hi = w + #| Umul128(lo, hi) + #|} + #|fn shiftright128(lo : UInt64, hi : UInt64, dist : Int) -> UInt64 { + #| (hi << (64 - dist)) | (lo >> dist) + #|} + #|fn pow5Factor(value : UInt64) -> Int { + #| if value % 5UL != 0UL { + #| return 0 + #| } + #| if value % 25UL != 0UL { + #| return 1 + #| } + #| if value % 125UL != 0UL { + #| return 2 + #| } + #| if value % 625UL != 0UL { + #| return 3 + #| } + #| for count = 4, v = value / 625UL; v > 0UL; { + #| if v % 5UL != 0UL { + #| break count + #| } + #| continue count + 1, v / 5UL + #| } nobreak { + #| abort("IllegalArgumentException \{value}") + #| } + #|} + #|fn multipleOfPowerOf5(value : UInt64, p : Int) -> Bool { + #| pow5Factor(value) >= p + #|} + #|fn multipleOfPowerOf2(value : UInt64, p : Int) -> Bool { + #| (value & ((1UL << p) - 1UL)) == 0UL + #|} + #|fn mulShiftAll64( + #| m : UInt64, + #| mul : Pow5Pair, + #| j : Int, + #| mmShift : Bool, + #|) -> MulShiftAll64Result { + #| let Pow5Pair(mul0, mul1) = mul + #| let m = m << 1 + #| let Umul128(lo, tmp) = umul128(m, mul0) + #| let Umul128(lo2, hi2) = umul128(m, mul1) + #| let mid = tmp + lo2 + #| let hi = hi2 + (if mid < tmp { 1UL } else { 0UL }) + #| let lo2 = lo + mul0 + #| let mid2 = mid + mul1 + (if lo2 < lo { 1UL } else { 0UL }) + #| let hi2 = hi + (if mid2 < mid { 1UL } else { 0UL }) + #| let vp : UInt64 = shiftright128(mid2, hi2, j - 64 - 1) + #| let mut vm : UInt64 = 0UL + #| if mmShift { + #| let lo3 = lo - mul0 + #| let mid3 = mid - mul1 - (if lo < lo3 { 1UL } else { 0UL }) + #| let hi3 = hi - (if mid < mid3 { 1UL } else { 0UL }) + #| vm = shiftright128(mid3, hi3, j - 64 - 1) + #| } else { + #| let lo3 : UInt64 = lo + lo + #| let mid3 : UInt64 = mid + mid + (if lo3 < lo { 1UL } else { 0UL }) + #| let hi3 : UInt64 = hi + hi + (if mid3 < mid { 1UL } else { 0UL }) + #| let lo4 : UInt64 = lo3 - mul0 + #| let mid4 : UInt64 = mid3 - mul1 - (if lo3 < lo4 { 1UL } else { 0UL }) + #| let hi4 : UInt64 = hi3 - (if mid3 < mid4 { 1UL } else { 0UL }) + #| vm = shiftright128(mid4, hi4, j - 64) + #| } + #| let vr : UInt64 = shiftright128(mid, hi, j - 64 - 1) + #| MulShiftAll64Result(vr, vp, vm) + #|} + #|let gPOW5_TABLE_SIZE = 26 + #|let gDOUBLE_POW5_INV_SPLIT2 : ReadOnlyArray[UInt64] = [ + #| 1, 2305843009213693952, 5955668970331000884, 1784059615882449851, 8982663654677661702, + #| 1380349269358112757, 7286864317269821294, 2135987035920910082, 7005857020398200553, + #| 1652639921975621497, 17965325103354776697, 1278668206209430417, 8928596168509315048, + #| 1978643211784836272, 10075671573058298858, 1530901034580419511, 597001226353042382, + #| 1184477304306571148, 1527430471115325346, 1832889850782397517, 12533209867169019542, + #| 1418129833677084982, 5577825024675947042, 2194449627517475473, 11006974540203867551, + #| 1697873161311732311, 10313493231639821582, 1313665730009899186, 12701016819766672773, + #| 2032799256770390445, + #|] + #|let gPOW5_INV_OFFSETS : ReadOnlyArray[UInt] = [ + #| 0x54544554, 0x04055545, 0x10041000, 0x00400414, 0x40010000, 0x41155555, 0x00000454, + #| 0x00010044, 0x40000000, 0x44000041, 0x50454450, 0x55550054, 0x51655554, 0x40004000, + #| 0x01000001, 0x00010500, 0x51515411, 0x05555554, 0x00000000, + #|] + #|let gDOUBLE_POW5_SPLIT2 : ReadOnlyArray[UInt64] = [ + #| 0, 1152921504606846976, 0, 1490116119384765625, 1032610780636961552, 1925929944387235853, + #| 7910200175544436838, 1244603055572228341, 16941905809032713930, 1608611746708759036, + #| 13024893955298202172, 2079081953128979843, 6607496772837067824, 1343575221513417750, + #| 17332926989895652603, 1736530273035216783, 13037379183483547984, 2244412773384604712, + #| 1605989338741628675, 1450417759929778918, 9630225068416591280, 1874621017369538693, + #| 665883850346957067, 1211445438634777304, 14931890668723713708, 1565756531257009982, + #|] + #|let gPOW5_OFFSETS : ReadOnlyArray[UInt] = [ + #| 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x40000000, 0x59695995, 0x55545555, + #| 0x56555515, 0x41150504, 0x40555410, 0x44555145, 0x44504540, 0x45555550, 0x40004000, + #| 0x96440440, 0x55565565, 0x54454045, 0x40154151, 0x55559155, 0x51405555, 0x00000105, + #|] + #|let gDOUBLE_POW5_TABLE : ReadOnlyArray[UInt64] = [ + #| 1, 5, 25, 125, 625, 3125, 15625, 78125, 390625, 1953125, 9765625, 48828125, 244140625, + #| 1220703125, 6103515625, 30517578125, 152587890625, 762939453125, 3814697265625, + #| 19073486328125, 95367431640625, 476837158203125, 2384185791015625, 11920928955078125, + #| 59604644775390625, 298023223876953125, + #|] + #|fn double_computePow5(i : Int) -> Pow5Pair { + #| let base = i / gPOW5_TABLE_SIZE + #| let base2 = base * gPOW5_TABLE_SIZE + #| let offset = i - base2 + #| let mul0 = gDOUBLE_POW5_SPLIT2[base * 2] + #| let mul1 = gDOUBLE_POW5_SPLIT2[base * 2 + 1] + #| if offset == 0 { + #| return Pow5Pair(mul0, mul1) + #| } + #| let m : UInt64 = gDOUBLE_POW5_TABLE[offset] + #| let Umul128(low1, high1) = umul128(m, mul1) + #| let Umul128(low0, high0) = umul128(m, mul0) + #| let sum : UInt64 = high0 + low1 + #| let mut high1 = high1 + #| if sum < high0 { + #| high1 = high1 + 1UL + #| } + #| let delta : Int = pow5bits(i) - pow5bits(base2) + #| let a : UInt64 = shiftright128(low0, sum, delta) + + #| ((gPOW5_OFFSETS[i / 16] >> ((i % 16) << 1)) & 3).to_uint64() + #| let b : UInt64 = shiftright128(sum, high1, delta) + #| Pow5Pair(a, b) + #|} + #|fn double_computeInvPow5(i : Int) -> Pow5Pair { + #| let base = (i + gPOW5_TABLE_SIZE - 1) / gPOW5_TABLE_SIZE + #| let base2 = base * gPOW5_TABLE_SIZE + #| let offset = base2 - i + #| let mul0 = gDOUBLE_POW5_INV_SPLIT2[base * 2] + #| let mul1 = gDOUBLE_POW5_INV_SPLIT2[base * 2 + 1] + #| if offset == 0 { + #| return Pow5Pair(mul0, mul1) + #| } + #| let m = gDOUBLE_POW5_TABLE[offset] + #| let Umul128(low1, high1) = umul128(m, mul1) + #| let Umul128(low0, high0) = umul128(m, mul0) + #| let sum = high0 + low1 + #| let mut high1 = high1 + #| if sum < high0 { + #| high1 = high1 + 1UL + #| } + #| let delta : Int = pow5bits(base2) - pow5bits(i) + #| let a : UInt64 = shiftright128(low0, sum, delta) + + #| 1UL + + #| ((gPOW5_INV_OFFSETS[i / 16] >> ((i % 16) << 1)) & 3).to_uint64() + #| let b : UInt64 = shiftright128(sum, high1, delta) + #| Pow5Pair(a, b) + #|} + #|let gDOUBLE_MANTISSA_BITS : Int = 52 + #|let gDOUBLE_EXPONENT_BITS : Int = 11 + #|let gDOUBLE_BIAS : Int = 1023 + #|let gDOUBLE_POW5_INV_BITCOUNT : Int = 125 + #|let gDOUBLE_POW5_BITCOUNT : Int = 125 + #|fn decimal_length17(v : UInt64) -> Int { + #| if v >= 10000000000000000 { + #| return 17 + #| } + #| if v >= 1000000000000000 { + #| return 16 + #| } + #| if v >= 100000000000000 { + #| return 15 + #| } + #| if v >= 10000000000000 { + #| return 14 + #| } + #| if v >= 1000000000000 { + #| return 13 + #| } + #| if v >= 100000000000 { + #| return 12 + #| } + #| if v >= 10000000000 { + #| return 11 + #| } + #| if v >= 1000000000 { + #| return 10 + #| } + #| if v >= 100000000 { + #| return 9 + #| } + #| if v >= 10000000 { + #| return 8 + #| } + #| if v >= 1000000 { + #| return 7 + #| } + #| if v >= 100000 { + #| return 6 + #| } + #| if v >= 10000 { + #| return 5 + #| } + #| if v >= 1000 { + #| return 4 + #| } + #| if v >= 100 { + #| return 3 + #| } + #| if v >= 10 { + #| return 2 + #| } + #| return 1 + #|} + #|priv struct FloatingDecimal64 { + #| mantissa : UInt64 + #| exponent : Int + #|} + #|fn d2d(ieeeMantissa : UInt64, ieeeExponent : UInt) -> FloatingDecimal64 { + #| let mut e2 : Int = 0 + #| let mut m2 : UInt64 = 0 + #| if ieeeExponent == 0 { + #| e2 = 1 - gDOUBLE_BIAS - gDOUBLE_MANTISSA_BITS - 2 + #| m2 = ieeeMantissa + #| } else { + #| e2 = ieeeExponent.reinterpret_as_int() - + #| gDOUBLE_BIAS - + #| gDOUBLE_MANTISSA_BITS - + #| 2 + #| m2 = (1UL << gDOUBLE_MANTISSA_BITS) | ieeeMantissa + #| } + #| let even = (m2 & 1UL) == 0UL + #| let mv = 4UL * + #| m2 + #| let mmShift = ieeeMantissa != 0UL || ieeeExponent <= 1 + #| let mut vr = 0UL + #| let mut vp = 0UL + #| let mut vm = 0UL + #| let mut e10 : Int = 0 + #| let mut vmIsTrailingZeros = false + #| let mut vrIsTrailingZeros = false + #| if e2 >= 0 { + #| let q : Int = log10Pow2(e2) - (e2 > 3).to_int() + #| e10 = q + #| let k = gDOUBLE_POW5_INV_BITCOUNT + pow5bits(q) - 1 + #| let i = -e2 + q + k + #| let pow5 : Pow5Pair = double_computeInvPow5(q) + #| let MulShiftAll64Result(vrOut, vpOut, vmOut) = mulShiftAll64( + #| m2, pow5, i, mmShift, + #| ) + #| vr = vrOut + #| vp = vpOut + #| vm = vmOut + #| if q <= 21 { + #| let mvMod5 : Int = mv.to_int() - 5 * (mv / 5UL).to_int() + #| if mvMod5 == 0 { + #| vrIsTrailingZeros = multipleOfPowerOf5(mv, q) + #| } else if even { + #| vmIsTrailingZeros = multipleOfPowerOf5( + #| mv - 1UL - mmShift.to_uint64(), + #| q, + #| ) + #| } else { + #| vp = vp - multipleOfPowerOf5(mv + 2UL, q).to_uint64() + #| } + #| } + #| } else { + #| let q : Int = log10Pow5(-e2) - (-e2 > 1).to_int() + #| e10 = q + e2 + #| let i : Int = -e2 - q + #| let k = pow5bits(i) - gDOUBLE_POW5_BITCOUNT + #| let j = q - k + #| let pow5 : Pow5Pair = double_computePow5(i) + #| let MulShiftAll64Result(vrOut, vpOut, vmOut) = mulShiftAll64( + #| m2, pow5, j, mmShift, + #| ) + #| vr = vrOut + #| vp = vpOut + #| vm = vmOut + #| if q <= 1 { + #| vrIsTrailingZeros = true + #| if even { + #| vmIsTrailingZeros = mmShift.to_int() == 1 + #| } else { + #| vp = vp - 1 + #| } + #| } else if q < 63 { + #| vrIsTrailingZeros = multipleOfPowerOf2(mv, q) + #| } + #| } + #| let mut removed : Int = 0 + #| let mut lastRemovedDigit : Int = 0 + #| let mut output : UInt64 = 0UL + #| if vmIsTrailingZeros || vrIsTrailingZeros { + #| while true { + #| let vpDiv10 = vp / 10 + #| let vmDiv10 = vm / 10 + #| if vpDiv10 <= vmDiv10 { + #| break + #| } + #| let vmMod10 : Int = vm.to_int() - 10 * vmDiv10.to_int() + #| let vrDiv10 = vr / 10 + #| let vrMod10 : Int = vr.to_int() - 10 * vrDiv10.to_int() + #| vmIsTrailingZeros = vmIsTrailingZeros && vmMod10 == 0 + #| vrIsTrailingZeros = vrIsTrailingZeros && lastRemovedDigit == 0 + #| lastRemovedDigit = vrMod10 + #| vr = vrDiv10 + #| vp = vpDiv10 + #| vm = vmDiv10 + #| removed = removed + 1 + #| } + #| if vmIsTrailingZeros { + #| while true { + #| let vmDiv10 = vm / 10 + #| let vmMod10 : Int = vm.to_int() - 10 * vmDiv10.to_int() + #| if vmMod10 != 0 { + #| break + #| } + #| let vpDiv10 = vp / 10 + #| let vrDiv10 = vr / 10 + #| let vrMod10 : Int = vr.to_int() - 10 * vrDiv10.to_int() + #| vrIsTrailingZeros = vrIsTrailingZeros && lastRemovedDigit == 0 + #| lastRemovedDigit = vrMod10 + #| vr = vrDiv10 + #| vp = vpDiv10 + #| vm = vmDiv10 + #| removed = removed + 1 + #| } + #| } + #| if vrIsTrailingZeros && lastRemovedDigit == 5 && vr % 2 == 0 { + #| lastRemovedDigit = 4 + #| } + #| output = vr + + #| ((vr == vm && (!even || !vmIsTrailingZeros)) || lastRemovedDigit >= 5) + #| .to_int64() + #| .reinterpret_as_uint64() + #| } else { + #| let mut roundUp = false + #| let vpDiv100 = vp / 100 + #| let vmDiv100 = vm / 100 + #| if vpDiv100 > vmDiv100 { + #| let vrDiv100 = vr / 100 + #| let vrMod100 : Int = vr.to_int() - 100 * vrDiv100.to_int() + #| roundUp = vrMod100 >= 50 + #| vr = vrDiv100 + #| vp = vpDiv100 + #| vm = vmDiv100 + #| removed = removed + 2 + #| } + #| while true { + #| let vpDiv10 = vp / 10 + #| let vmDiv10 = vm / 10 + #| if vpDiv10 <= vmDiv10 { + #| break + #| } + #| let vrDiv10 = vr / 10 + #| let vrMod10 : Int = vr.to_int() - 10 * vrDiv10.to_int() + #| roundUp = vrMod10 >= 5 + #| vr = vrDiv10 + #| vp = vpDiv10 + #| vm = vmDiv10 + #| removed = removed + 1 + #| } + #| output = vr + (vr == vm || roundUp).to_uint64() + #| } + #| let exp : Int = e10 + removed + #| let fd : FloatingDecimal64 = { mantissa: output, exponent: exp } + #| fd + #|} + #|fn to_chars(v : FloatingDecimal64, sign : Bool) -> String { + #| let result = FixedArray::make(25, Byte::default()) + #| let mut index : Int = 0 + #| if sign { + #| result[index] = b'-' + #| index += 1 + #| } + #| let output = v.mantissa + #| let olength = decimal_length17(output) + #| let mut exp : Int = v.exponent + olength - 1 + #| let scientificNotation = !(exp >= -6 && exp < 21) + #| if scientificNotation { + #| let output = for i in 0..<(olength - 1); output = output { + #| let c = output % 10 + #| result[index + olength - i] = (48 + c.to_int()).to_byte() + #| continue output / 10 + #| } nobreak { + #| output + #| } + #| result[index] = (48 + output.to_int() % 10).to_byte() + #| if olength > 1 { + #| result[index + 1] = b'.' + #| } else { + #| index -= 1 + #| } + #| index += olength + 1 + #| result[index] = b'e' + #| index += 1 + #| if exp < 0 { + #| result[index] = b'-' + #| index += 1 + #| exp = -exp + #| } else { + #| result[index] = b'+' + #| index += 1 + #| } + #| if exp >= 100 { + #| let a = exp / 100 + #| let b = exp / 10 % 10 + #| let c = exp % 10 + #| result[index + 0] = (48 + a).to_byte() + #| result[index + 1] = (48 + b).to_byte() + #| result[index + 2] = (48 + c).to_byte() + #| index += 3 + #| } else if exp >= 10 { + #| let a = exp / 10 + #| let b = exp % 10 + #| result[index + 0] = (48 + a).to_byte() + #| result[index + 1] = (48 + b).to_byte() + #| index += 2 + #| } else { + #| result[index] = (48 + exp).to_byte() + #| index += 1 + #| } + #| string_from_bytes(result, 0, index) + #| } else { + #| if exp < 0 { + #| result[index] = b'0' + #| result[index + 1] = b'.' + #| index += 2 + #| for i = -1; i > exp; i = i - 1 { + #| result[index - i - 1] = b'0' + #| } + #| let current = index + (-1 - exp) + #| for i in 0..= olength { + #| for i in 0.. FloatingDecimal64? { + #| let m2 : UInt64 = (1UL << gDOUBLE_MANTISSA_BITS) | ieeeMantissa + #| let e2 : Int = ieeeExponent - gDOUBLE_BIAS - gDOUBLE_MANTISSA_BITS + #| if e2 > 0 { + #| return None + #| } + #| if e2 < -52 { + #| return None + #| } + #| let mask : UInt64 = (1UL << -e2) - 1UL + #| let fraction : UInt64 = m2 & mask + #| if fraction != 0UL { + #| return None + #| } + #| Some({ mantissa: m2 >> -e2, exponent: 0 }) + #|} + #|fn ryu_to_string(val : Double) -> String { + #| if val == 0.0 { + #| return "0" + #| } + #| let bits : UInt64 = val.reinterpret_as_uint64() + #| let ieeeSign = ( + #| (bits >> (gDOUBLE_MANTISSA_BITS + gDOUBLE_EXPONENT_BITS)) & 1UL + #| ) != + #| 0UL + #| let ieeeMantissa : UInt64 = bits & ((1UL << gDOUBLE_MANTISSA_BITS) - 1UL) + #| let ieeeExponent : Int = ((bits >> gDOUBLE_MANTISSA_BITS) & + #| ((1UL << gDOUBLE_EXPONENT_BITS) - 1UL)).to_int() + #| if ieeeExponent == (1 << gDOUBLE_EXPONENT_BITS) - 1 || + #| (ieeeExponent == 0 && ieeeMantissa == 0UL) { + #| return copy_special_str(ieeeSign, ieeeExponent != 0, ieeeMantissa != 0UL) + #| } + #| let v = match d2d_small_int(ieeeMantissa, ieeeExponent) { + #| Some(f) => + #| for x = f { + #| let q : UInt64 = x.mantissa / 10 + #| let r = x.mantissa - 10UL * q + #| if r != 0 { + #| break x + #| } + #| continue { mantissa: q, exponent: x.exponent + 1 } + #| } + #| None => d2d(ieeeMantissa, ieeeExponent.reinterpret_as_uint()) + #| } + #| to_chars(v, ieeeSign) + #|} + #|test "double/ryu.mbt:205" { + #| let m = 123456789UL + #| let mul0 = 987654321UL + #| let Umul128(_, high0) = umul128(m, mul0) + #| let low1 = 111111111UL + #| let high1 = 222222222UL + #| let sum = high0 + low1 + #| let mut high1 = high1 + #| if sum < high0 { + #| high1 = high1 + 1 + #| } + #| inspect(high1, content="222222222") + #|} + #|test "double/ryu.mbt:230" { + #| let m = 123456789UL + #| let mul0 = 987654321UL + #| let Umul128(_, high0) = umul128(m, mul0) + #| let low1 = 111111111UL + #| let high1 = 222222222UL + #| let sum = high0 + low1 + #| let mut high1 = high1 + #| if sum < high0 { + #| high1 = high1 + 1UL + #| } + #| assert_eq(high1, 222222222UL) + #|} + #|test "double/ryu.mbt:252" { + #| inspect(gDOUBLE_POW5_BITCOUNT, content="125") + #|} + ), + "double_scalbn.mbt": ( + #|fn scalbn(x : Double, exp : Int) -> Double { + #| let mut n = exp + #| let mut y : Double = x + #| if n > 1023 { + #| y *= 0x1.0p1023 + #| n -= 1023 + #| if n > 1023 { + #| y *= 0x1.0p1023 + #| n -= 1023 + #| if n > 1023 { + #| n = 1023 + #| } + #| } + #| } else if n < -1022 { + #| y *= 0x1.0p-1022 * 0x1.0p53 + #| n += 1022 - 53 + #| if n < -1022 { + #| y *= 0x1.0p-1022 * 0x1.0p53 + #| n += 1022 - 53 + #| if n < -1022 { + #| n = -1022 + #| } + #| } + #| } + #| let ui = (0x3ff + n).to_uint64() << 52 + #| return y * ui.reinterpret_as_double() + #|} + ), + "double_to_int.mbt": ( + #|pub fn Double::to_int(self : Double) -> Int { + #| if self != self { + #| 0 + #| } else if self >= 2147483647 { + #| 2147483647 + #| } else if self <= -2147483648 { + #| -2147483648 + #| } else { + #| self.to_unchecked_int() + #| } + #|} + #|fn Double::to_unchecked_int(self : Double) -> Int = "%f64_to_i32" + ), + "double_to_int64_js.mbt": ( + #|extern "js" fn MyInt64::from_double(value : Double) -> MyInt64 = + #| #|(a) => { + #| #| if (isNaN(a)) { + #| #| return { hi: 0, lo: 0 }; + #| #| } + #| #| if (a >= 9223372036854775807) { + #| #| return { hi: 0x7fffffff, lo: 0xffffffff }; + #| #| } + #| #| if (a <= -9223372036854775808) { + #| #| return { hi: -2147483648, lo: 0 }; + #| #| } + #| #| let neg = false; + #| #| if (a < 0) { + #| #| neg = true; + #| #| a = -a; + #| #| } + #| #| let hi = (a * (1 / 0x100000000)) | 0; + #| #| let lo = a >>> 0; + #| #| if (neg) { + #| #| if (lo === 0) { + #| #| hi = ~hi + 1; + #| #| } else { + #| #| hi = ~hi; + #| #| lo = ~lo + 1; + #| #| } + #| #| } + #| #| return { hi, lo }; + #| #|} + #|pub fn Double::to_int64(self : Double) -> Int64 { + #| MyInt64::from_double(self).to_int64() + #|} + #|extern "js" fn MyInt64::from_double_unsigned(value : Double) -> MyInt64 = + #| #|(a) => { + #| #| if (isNaN(a)) { + #| #| return { hi: 0, lo: 0 }; + #| #| } + #| #| if (a >= 18446744073709551615) { + #| #| return { hi: 0xffffffff, lo: 0xffffffff }; + #| #| } + #| #| if (a <= 0) { + #| #| return { hi: 0, lo: 0 }; + #| #| } + #| #| let hi = (a * (1 / 0x100000000)) | 0; + #| #| let lo = a | 0; + #| #| return { hi, lo }; + #| #|} + #|pub fn Double::to_uint64(self : Double) -> UInt64 { + #| MyInt64::from_double_unsigned(self).to_uint64() + #|} + ), + "double_to_int64_native.mbt": ( + #|fn Double::to_unchecked_int64(self : Double) -> Int64 = "%f64_to_i64" + #|pub fn Double::to_int64(self : Double) -> Int64 { + #| if self != self { + #| 0 + #| } else if self >= 9223372036854775807 { + #| 9223372036854775807L + #| } else if self <= -9223372036854775808 { + #| -9223372036854775808L + #| } else { + #| self.to_unchecked_int64() + #| } + #|} + #|fn Double::to_unchecked_uint64(self : Double) -> UInt64 = "%f64_to_i64" + #|pub fn Double::to_uint64(self : Double) -> UInt64 { + #| if self != self { + #| 0 + #| } else if self >= 9223372036854775807 { + #| 18446744073709551615UL + #| } else if self <= 0 { + #| 0UL + #| } else { + #| self.to_unchecked_uint64() + #| } + #|} + ), + "double_to_int64_wasm.mbt": ( + #|pub fn Double::to_int64(self : Double) -> Int64 = "%f64_to_i64_saturate" + #|pub fn Double::to_uint64(self : Double) -> UInt64 = "%f64.to_u64_saturate" + ), + "double_to_int_wasm.mbt": ( + #|pub fn Double::to_int(self : Double) -> Int = "%f64_to_i32_saturate" + ), + "double_to_uint.mbt": ( + #|pub fn Double::to_uint(self : Double) -> UInt { + #| if self != self { + #| 0 + #| } else if self >= 4294967295.0 { + #| 4294967295U + #| } else if self <= 0 { + #| 0 + #| } else { + #| UInt::trunc_double(self) + #| } + #|} + ), + "double_to_uint_wasm.mbt": ( + #|pub fn Double::to_uint(self : Double) -> UInt = "%f64.to_u32_saturate" + ), + "failure.mbt": ( + #|pub(all) suberror Failure { + #| Failure(String) + #|} derive(ToJson, Show) + #|#callsite(autofill(loc)) + #|pub fn[T] fail(msg : String, loc~ : SourceLoc) -> T raise Failure { + #| raise Failure("\{loc} FAILED: \{msg}") + #|} + ), + "fixedarray.mbt": ( + #|pub fn[T] FixedArray::get(self : FixedArray[T], idx : Int) -> T? { + #| let len = self.length() + #| guard idx >= 0 && idx < len else { None } + #| Some(self.unsafe_get(idx)) + #|} + #|pub impl[X] Default for FixedArray[X] with default() { + #| [] + #|} + #|pub fn[T] FixedArray::fill( + #| self : FixedArray[T], + #| value : T, + #| start? : Int = 0, + #| end? : Int, + #|) -> Unit { + #| let array_length = self.length() + #| guard array_length > 0 else { return } + #| guard start >= 0 && start < array_length + #| let length = match end { + #| None => array_length - start + #| Some(e) => { + #| guard e >= start && e <= array_length + #| e - start + #| } + #| } + #| self.unchecked_fill(start, value, length) + #|} + #|#coverage.skip + #|#intrinsic("%fixedarray.fill") + #|fn[T] FixedArray::unchecked_fill( + #| self : FixedArray[T], + #| start : Int, + #| value : T, + #| len : Int, + #|) -> Unit { + #| for i in start..<(start + len) { + #| self[i] = value + #| } + #|} + #|pub fn[T] FixedArray::is_empty(self : FixedArray[T]) -> Bool { + #| self.length() == 0 + #|} + #|pub fn[T : Compare] FixedArray::binary_search( + #| self : FixedArray[T], + #| value : T, + #|) -> Result[Int, Int] { + #| self[:].binary_search(value) + #|} + #|pub fn[T] FixedArray::binary_search_by( + #| self : FixedArray[T], + #| cmp : (T) -> Int raise?, + #|) -> Result[Int, Int] raise? { + #| self[:].binary_search_by(cmp) + #|} + #|pub fn[T] FixedArray::each( + #| self : FixedArray[T], + #| f : (T) -> Unit raise?, + #|) -> Unit raise? { + #| for v in self { + #| f(v) + #| } + #|} + #|test "each" { + #| let mut i = 0 + #| let mut failed = false + #| let f = elem => { + #| if elem != i + 1 { + #| failed = true + #| } + #| i = i + 1 + #| } + #| { + #| i = 0 + #| ([] : FixedArray[_]).each(f) + #| assert_false(failed) + #| inspect(i, content="0") + #| } + #| { + #| i = 0 + #| ([1] : FixedArray[_]).each(f) + #| assert_false(failed) + #| inspect(i, content="1") + #| } + #| i = 0 + #| ([1, 2, 3, 4, 5] : FixedArray[_]).each(f) + #| assert_false(failed) + #| inspect(i, content="5") + #|} + #|pub fn[T] FixedArray::eachi( + #| self : FixedArray[T], + #| f : (Int, T) -> Unit raise?, + #|) -> Unit raise? { + #| for i, v in self { + #| f(i, v) + #| } + #|} + #|test "eachi" { + #| let mut i = 0 + #| let mut failed = false + #| let f = (index, elem) => { + #| if index != i || elem != i + 1 { + #| failed = true + #| } + #| i = i + 1 + #| } + #| { + #| i = 0 + #| ([] : FixedArray[_]).eachi(f) + #| assert_false(failed) + #| inspect(i, content="0") + #| } + #| { + #| i = 0 + #| ([1] : FixedArray[_]).eachi(f) + #| assert_false(failed) + #| inspect(i, content="1") + #| } + #| i = 0 + #| ([1, 2, 3, 4, 5] : FixedArray[_]).eachi(f) + #| assert_false(failed) + #| inspect(i, content="5") + #|} + #|pub fn[T] FixedArray::rev_each( + #| self : FixedArray[T], + #| f : (T) -> Unit raise?, + #|) -> Unit raise? { + #| for i in self.length()>..0 { + #| f(self[i]) + #| } + #|} + #|test "rev_each" { + #| let mut i = 6 + #| let mut failed = false + #| let f = elem => { + #| if elem != i - 1 { + #| failed = true + #| } + #| i = i - 1 + #| } + #| { + #| i = 1 + #| ([] : FixedArray[_]).rev_each(f) + #| assert_false(failed) + #| inspect(i, content="1") + #| } + #| { + #| i = 2 + #| ([1] : FixedArray[_]).rev_each(f) + #| assert_false(failed) + #| inspect(i, content="1") + #| } + #| i = 6 + #| ([1, 2, 3, 4, 5] : FixedArray[_]).rev_each(f) + #| assert_false(failed) + #| inspect(i, content="1") + #|} + #|pub fn[T] FixedArray::rev_eachi( + #| self : FixedArray[T], + #| f : (Int, T) -> Unit raise?, + #|) -> Unit raise? { + #| let len = self.length() + #| for i in 0.. { + #| if index != j || elem != i - 1 { + #| failed = true + #| } + #| i = i - 1 + #| j = j + 1 + #| } + #| { + #| i = 1 + #| j = 0 + #| ([] : FixedArray[_]).rev_eachi(f) + #| assert_false(failed) + #| inspect(i, content="1") + #| inspect(j, content="0") + #| } + #| { + #| i = 2 + #| j = 0 + #| ([1] : FixedArray[_]).rev_eachi(f) + #| assert_false(failed) + #| inspect(i, content="1") + #| inspect(j, content="1") + #| } + #| i = 6 + #| j = 0 + #| ([1, 2, 3, 4, 5] : FixedArray[_]).rev_eachi(f) + #| assert_false(failed) + #| inspect(i, content="1") + #| inspect(j, content="5") + #|} + #|pub fn[T, U] FixedArray::map( + #| self : FixedArray[T], + #| f : (T) -> U raise?, + #|) -> FixedArray[U] raise? { + #| if self.length() == 0 { + #| return [] + #| } + #| let res = FixedArray::make(self.length(), f(self[0])) + #| for i in 1.. x) + #| assert_eq(empty, []) + #| let simple_arr : FixedArray[_] = [6] + #| let simple_doubled = simple_arr.map(x => x * 2) + #| assert_eq(simple_doubled, [12]) + #| let arr : FixedArray[_] = [1, 2, 3, 4, 5] + #| let doubled = arr.map(x => x * 2) + #| assert_eq(doubled, [2, 4, 6, 8, 10]) + #|} + #|pub fn[T, U] FixedArray::mapi( + #| self : FixedArray[T], + #| f : (Int, T) -> U raise?, + #|) -> FixedArray[U] raise? { + #| if self.length() == 0 { + #| return [] + #| } + #| let res = FixedArray::make(self.length(), f(0, self[0])) + #| for i in 1.. x + i) + #| assert_eq(empty, []) + #| let simple_arr : FixedArray[_] = [6] + #| let simple_doubled = simple_arr.mapi((i, x) => x * 2 + i) + #| assert_eq(simple_doubled, [12]) + #| let arr : FixedArray[_] = [1, 2, 3, 4, 5] + #| let doubled = arr.mapi((i, x) => x * 2 + i) + #| assert_eq(doubled, [2, 5, 8, 11, 14]) + #|} + #|#locals(value) + #|pub fn[T] FixedArray::makei( + #| length : Int, + #| value : (Int) -> T raise?, + #|) -> FixedArray[T] raise? { + #| if length <= 0 { + #| [] + #| } else { + #| let array = FixedArray::make(length, value(0)) + #| for i in 1.. i) + #| inspect(empty.length(), content="0") + #| let simple_arr = FixedArray::makei(1, i => i) + #| inspect(simple_arr.length(), content="1") + #| inspect(simple_arr[0], content="0") + #| let arr = FixedArray::makei(2, i => i) + #| inspect(arr.length(), content="2") + #| inspect(arr[0], content="0") + #| inspect(arr[1], content="1") + #|} + #|pub fn[T] FixedArray::from_array(array : ArrayView[T]) -> FixedArray[T] { + #| FixedArray::makei(array.length(), i => array.unsafe_get(i)) + #|} + #|test "from_array" { + #| let array = FixedArray::from_array([1, 2, 3, 4, 5]) + #| assert_eq(array, [1, 2, 3, 4, 5]) + #|} + #|pub fn[A, B] FixedArray::fold( + #| self : FixedArray[A], + #| init~ : B, + #| f : (B, A) -> B raise?, + #|) -> B raise? { + #| for i = 0, acc = init; i < self.length(); { + #| continue i + 1, f(acc, self[i]) + #| } nobreak { + #| acc + #| } + #|} + #|test "fold" { + #| let sum = ([] : FixedArray[_]).fold(init=1, (sum, elem) => sum + elem) + #| inspect(sum, content="1") + #| let sum = ([1] : FixedArray[_]).fold(init=2, (sum, elem) => sum + elem) + #| inspect(sum, content="3") + #| let sum = ([1, 2, 3, 4, 5] : FixedArray[_]).fold(init=0, (sum, elem) => { + #| sum + elem + #| }) + #| inspect(sum, content="15") + #|} + #|pub fn[A, B] FixedArray::rev_fold( + #| self : FixedArray[A], + #| init~ : B, + #| f : (B, A) -> B raise?, + #|) -> B raise? { + #| for i = self.length() - 1, acc = init; i >= 0; { + #| continue i - 1, f(acc, self[i]) + #| } nobreak { + #| acc + #| } + #|} + #|test "rev_fold" { + #| let sum = ([] : FixedArray[_]).rev_fold(init=1, (sum, elem) => sum + elem) + #| inspect(sum, content="1") + #| let sum = ([1] : FixedArray[_]).rev_fold(init=2, (sum, elem) => sum + elem) + #| inspect(sum, content="3") + #| let sum = ([1, 2, 3, 4, 5] : FixedArray[_]).rev_fold(init=0, (sum, elem) => { + #| sum + elem + #| }) + #| inspect(sum, content="15") + #|} + #|pub fn[A, B] FixedArray::foldi( + #| self : FixedArray[A], + #| init~ : B, + #| f : (Int, B, A) -> B raise?, + #|) -> B raise? { + #| for i = 0, acc = init; i < self.length(); { + #| continue i + 1, f(i, acc, self[i]) + #| } nobreak { + #| acc + #| } + #|} + #|test "fold_lefti" { + #| let f = (index, sum, elem) => index + sum + elem + #| { + #| let sum = ([] : FixedArray[_]).foldi(init=1, f) + #| inspect(sum, content="1") + #| } + #| { + #| let sum = ([1] : FixedArray[_]).foldi(init=2, f) + #| inspect(sum, content="3") + #| } + #| let sum = ([1, 2, 3, 4, 5] : FixedArray[_]).foldi(init=0, f) + #| inspect(sum, content="25") + #|} + #|pub fn[A, B] FixedArray::rev_foldi( + #| self : FixedArray[A], + #| init~ : B, + #| f : (Int, B, A) -> B raise?, + #|) -> B raise? { + #| let len = self.length() + #| for i = len - 1, acc = init; i >= 0; { + #| continue i - 1, f(len - i - 1, acc, self[i]) + #| } nobreak { + #| acc + #| } + #|} + #|test "rev_foldi" { + #| let f = (index, sum, elem) => index + sum + elem + #| { + #| let sum = ([] : FixedArray[_]).rev_foldi(init=1, f) + #| inspect(sum, content="1") + #| } + #| { + #| let sum = ([1] : FixedArray[_]).rev_foldi(init=2, f) + #| inspect(sum, content="3") + #| } + #| let sum = ([1, 2, 3, 4, 5] : FixedArray[_]).rev_foldi(init=0, f) + #| inspect(sum, content="25") + #|} + #|#alias(rev_inplace, deprecated) + #|pub fn[T] FixedArray::rev_in_place(self : FixedArray[T]) -> Unit { + #| let mid_len = self.length() / 2 + #| for i in 0.. FixedArray[T] { + #| match self { + #| [] => [] + #| [.., first] => { + #| let res = FixedArray::make(self.length(), first) + #| let len = self.length() + #| for i in 1.. Unit { + #| let temp = self[i] + #| self[i] = self[j] + #| self[j] = temp + #|} + #|test "swap" { + #| { + #| let arr : FixedArray[Int] = [1] + #| arr.swap(0, 0) + #| assert_eq(arr, [1]) + #| } + #| { + #| let arr : FixedArray[_] = [1, 2] + #| arr.swap(0, 0) + #| assert_eq(arr, [1, 2]) + #| arr.swap(0, 1) + #| assert_eq(arr, [2, 1]) + #| } + #| let arr : FixedArray[_] = [1, 2, 3, 4, 5] + #| arr.swap(3, 3) + #| assert_eq(arr, [1, 2, 3, 4, 5]) + #| arr.swap(1, 3) + #| assert_eq(arr, [1, 4, 3, 2, 5]) + #|} + #|#alias(every) + #|pub fn[T] FixedArray::all( + #| self : FixedArray[T], + #| f : (T) -> Bool raise?, + #|) -> Bool raise? { + #| self[:].all(f) + #|} + #|test "all" { + #| { + #| let arr : FixedArray[Int] = [] + #| assert_true(arr.all(ele => ele < 6)) + #| assert_true(arr.all(ele => ele < 5)) + #| } + #| { + #| let arr : FixedArray[_] = [5] + #| assert_true(arr.all(ele => ele < 6)) + #| assert_false(arr.all(ele => ele < 5)) + #| } + #| let arr : FixedArray[_] = [1, 2, 3, 4, 5] + #| assert_true(arr.all(ele => ele < 6)) + #| assert_false(arr.all(ele => ele < 5)) + #|} + #|#alias(exists) + #|pub fn[T] FixedArray::any( + #| self : FixedArray[T], + #| f : (T) -> Bool raise?, + #|) -> Bool raise? { + #| self[:].any(f) + #|} + #|test "any" { + #| { + #| let arr : FixedArray[Int] = [] + #| assert_false(arr.any(ele => ele < 6)) + #| assert_false(arr.any(ele => ele < 5)) + #| } + #| { + #| let arr : FixedArray[_] = [5] + #| assert_true(arr.any(ele => ele < 6)) + #| assert_false(arr.any(ele => ele < 5)) + #| } + #| let arr : FixedArray[_] = [1, 2, 3, 4, 5] + #| assert_true(arr.any(ele => ele < 6)) + #| assert_true(arr.any(ele => ele < 5)) + #|} + #|test "fill" { + #| { + #| let arr : FixedArray[Int] = [] + #| arr.fill(3) + #| assert_eq(arr, []) + #| } + #| { + #| let arr : FixedArray[_] = [6] + #| arr.fill(5) + #| assert_eq(arr, [5]) + #| } + #| let arr : FixedArray[_] = [0, 0, 0, 0, 0] + #| arr.fill(3) + #| assert_eq(arr, [3, 3, 3, 3, 3]) + #|} + #|pub fn[T : Eq] FixedArray::search(self : FixedArray[T], value : T) -> Int? { + #| self[:].search(value) + #|} + #|test "search" { + #| { + #| let arr : FixedArray[Int] = [] + #| assert_eq(arr.search(3), None) + #| assert_eq(arr.search(-1), None) + #| } + #| { + #| let arr : FixedArray[_] = [3] + #| assert_eq(arr.search(3), Some(0)) + #| assert_eq(arr.search(-1), None) + #| } + #| let arr : FixedArray[_] = [1, 2, 3, 4, 5] + #| assert_eq(arr.search(1), Some(0)) + #| assert_eq(arr.search(5), Some(4)) + #| assert_eq(arr.search(3), Some(2)) + #| assert_eq(arr.search(-1), None) + #|} + #|pub fn[T : Eq] FixedArray::contains(self : FixedArray[T], value : T) -> Bool { + #| for i in 0.. Bool { + #| self[:].starts_with(prefix[:]) + #|} + #|test "starts_with" { + #| { + #| let arr : FixedArray[Int] = [] + #| assert_true(arr.starts_with([])) + #| assert_false(arr.starts_with([1])) + #| } + #| { + #| let arr : FixedArray[_] = [3] + #| assert_true(arr.starts_with([])) + #| assert_true(arr.starts_with([3])) + #| assert_false(arr.starts_with([2])) + #| assert_false(arr.starts_with([3, 1])) + #| } + #| let arr : FixedArray[_] = [3, 4, 5] + #| assert_true(arr.starts_with([])) + #| assert_true(arr.starts_with([3])) + #| assert_false(arr.starts_with([2])) + #| assert_true(arr.starts_with([3, 4])) + #| assert_false(arr.starts_with([3, 2])) + #| assert_true(arr.starts_with([3, 4, 5])) + #| assert_false(arr.starts_with([3, 4, 2])) + #| assert_false(arr.starts_with([3, 4, 5, 6])) + #|} + #|pub fn[T : Eq] FixedArray::ends_with( + #| self : FixedArray[T], + #| suffix : FixedArray[T], + #|) -> Bool { + #| self[:].ends_with(suffix[:]) + #|} + #|test "ends_with" { + #| { + #| let arr : FixedArray[Int] = [] + #| assert_true(arr.ends_with([])) + #| assert_false(arr.ends_with([1])) + #| } + #| { + #| let arr : FixedArray[_] = [3] + #| assert_true(arr.ends_with([])) + #| assert_true(arr.ends_with([3])) + #| assert_false(arr.ends_with([2])) + #| assert_false(arr.ends_with([3, 1])) + #| } + #| let arr : FixedArray[_] = [3, 4, 5] + #| assert_true(arr.ends_with([])) + #| assert_true(arr.ends_with([5])) + #| assert_false(arr.ends_with([2])) + #| assert_true(arr.ends_with([4, 5])) + #| assert_false(arr.ends_with([4, 2])) + #| assert_false(arr.ends_with([2, 5])) + #| assert_true(arr.ends_with([3, 4, 5])) + #| assert_false(arr.ends_with([3, 4, 2])) + #| assert_false(arr.ends_with([3, 2, 5])) + #| assert_false(arr.ends_with([2, 4, 5])) + #| assert_false(arr.ends_with([3, 4, 5, 6])) + #| assert_false(arr.ends_with([2, 3, 4, 5])) + #|} + #|pub impl[T : Eq] Eq for FixedArray[T] with equal( + #| self : FixedArray[T], + #| that : FixedArray[T], + #|) -> Bool { + #| if self.length() != that.length() { + #| return false + #| } + #| for i in 0.. { + #| if i < slen { + #| self[i] + #| } else { + #| other[i - slen] + #| } + #| }) + #|} + #|test "add" { + #| { + #| inspect(([] : FixedArray[Int]) + [], content="[]") + #| inspect(([] : FixedArray[_]) + [1, 2, 3, 4, 5], content="[1, 2, 3, 4, 5]") + #| inspect(([1, 2, 3, 4, 5] : FixedArray[_]) + [], content="[1, 2, 3, 4, 5]") + #| } + #| { + #| inspect(([1] : FixedArray[_]) + [2], content="[1, 2]") + #| inspect( + #| ([1] : FixedArray[_]) + [1, 2, 3, 4, 5], + #| content="[1, 1, 2, 3, 4, 5]", + #| ) + #| inspect( + #| ([1, 2, 3, 4, 5] : FixedArray[_]) + [1], + #| content="[1, 2, 3, 4, 5, 1]", + #| ) + #| } + #| inspect( + #| ([1, 2, 3, 4, 5] : FixedArray[_]) + [6, 7, 8, 9, 10], + #| content="[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]", + #| ) + #|} + #|test "iter" { + #| let arr : FixedArray[_] = [1, 2, 3, 4, 5] + #| let iter = arr.iter() + #| let exb = StringBuilder::new() + #| let mut i = 0 + #| iter.each(x => { + #| exb.write_string(x.to_string()) + #| exb.write_char('\n') + #| i = i + 1 + #| }) + #| assert_eq(i, arr.length()) + #| inspect( + #| exb, + #| content=( + #| #|1 + #| #|2 + #| #|3 + #| #|4 + #| #|5 + #| #| + #| ), + #| ) + #|} + #|#alias(from_iterator, deprecated) + #|pub fn[T] FixedArray::from_iter(iter : Iter[T]) -> FixedArray[T] { + #| FixedArray::from_array(iter.collect()) + #|} + #|pub fn[A] FixedArray::last(self : FixedArray[A]) -> A? { + #| match self { + #| [] => None + #| [.., last] => Some(last) + #| } + #|} + #|pub fn FixedArray::join( + #| self : FixedArray[String], + #| separator : StringView, + #|) -> String { + #| let len = self.length() + #| if len == 0 { + #| return "" + #| } + #| let first = self[0] + #| let size_hint = for i in 1.. Iter[X] { + #| self[:].iter() + #|} + #|#alias(iterator2, deprecated) + #|pub fn[X] FixedArray::iter2(self : FixedArray[X]) -> Iter2[Int, X] { + #| self[:].iter2() + #|} + #|#cfg(not(target="js")) + #|#alias(clone, deprecated) + #|pub fn[T] FixedArray::copy(self : FixedArray[T]) -> FixedArray[T] { + #| let len = self.length() + #| if len == 0 { + #| [] + #| } else { + #| let arr = FixedArray::make(len, self[0]) + #| FixedArray::unsafe_blit(arr, 0, self, 0, len) + #| arr + #| } + #|} + #|#cfg(target="js") + #|#alias(clone, deprecated) + #|pub fn[T] FixedArray::copy(self : FixedArray[T]) -> FixedArray[T] { + #| JSArray::ofAnyFixedArray(self).copy().toAnyFixedArray() + #|} + #|pub fn[T : Compare] FixedArray::lexical_compare( + #| self : FixedArray[T], + #| other : FixedArray[T], + #|) -> Int { + #| self[:].lexical_compare(other[:]) + #|} + ), + "fixedarray_block.mbt": ( + #|#intrinsic("%fixedarray.copy") + #|#coverage.skip + #|pub fn[A] FixedArray::unsafe_blit( + #| dst : FixedArray[A], + #| dst_offset : Int, + #| src : FixedArray[A], + #| src_offset : Int, + #| len : Int, + #|) -> Unit { + #| if physical_equal(dst, src) && dst_offset < src_offset { + #| for i in 0....0 { + #| dst[dst_offset + i] = src[src_offset + i] + #| } + #| } + #|} + #|#intrinsic("%fixedarray.copy") + #|#coverage.skip + #|fn[T] UninitializedArray::unsafe_blit_fixed( + #| dst : UninitializedArray[T], + #| dst_offset : Int, + #| src : FixedArray[T], + #| src_offset : Int, + #| len : Int, + #|) -> Unit { + #| for i in len>..0 { + #| dst[dst_offset + i] = src[src_offset + i] + #| } + #|} + #|pub fn[A] FixedArray::blit_to( + #| self : FixedArray[A], + #| dst : FixedArray[A], + #| len~ : Int, + #| src_offset? : Int = 0, + #| dst_offset? : Int = 0, + #|) -> Unit { + #| guard dst_offset >= 0 && + #| src_offset >= 0 && + #| dst_offset + len <= dst.length() && + #| src_offset + len <= self.length() else { + #| abort( + #| "bounds check failed: dst_offset = \{dst_offset}, src_offset = \{src_offset}, len = \{len}, dst.length = \{dst.length()}, self.length = \{self.length()}", + #| ) + #| } + #| FixedArray::unsafe_blit(dst, dst_offset, self, src_offset, len) + #|} + ), + "hasher.mbt": ( + #|const GPRIME1 : UInt = 0x9E3779B1 + #|const GPRIMES2 : UInt = 0x85EBCA77 + #|const GPRIME3 : UInt = 0xC2B2AE3D + #|const GPRIME4 : UInt = 0x27D4EB2F + #|const GPRIME5 : UInt = 0x165667B1 + #|struct Hasher { + #| mut acc : UInt + #|} + #|pub fn Hasher::new(seed? : Int = seed) -> Hasher { + #| { acc: seed.reinterpret_as_uint() + GPRIME5 } + #|} + #|#cfg(not(target="js")) + #|let seed : Int = 0 + #|#cfg(target="js") + #|let seed : Int = random_seed() + #|#cfg(target="js") + #|extern "js" fn random_seed() -> Int = + #| #|() => { + #| #| if (globalThis.crypto?.getRandomValues) { + #| #| const array = new Uint32Array(1); + #| #| globalThis.crypto.getRandomValues(array); + #| #| return array[0] | 0; // Convert to signed 32 + #| #| } else { + #| #| return Math.floor(Math.random() * 0x100000000) | 0; // Fallback to Math.random + #| #| } + #| #|} + #|pub fn[T : Hash] Hasher::combine(self : Hasher, value : T) -> Unit { + #| value.hash_combine(self) + #|} + #|pub fn Hasher::combine_unit(self : Hasher) -> Unit { + #| self.combine_uint(0) + #|} + #|pub fn Hasher::combine_bool(self : Hasher, value : Bool) -> Unit { + #| self.combine_uint(if value { 1 } else { 0 }) + #|} + #|pub fn Hasher::combine_int(self : Hasher, value : Int) -> Unit { + #| self.combine_uint(value.reinterpret_as_uint()) + #|} + #|pub fn Hasher::combine_int64(self : Hasher, value : Int64) -> Unit { + #| self.acc += 8 + #| self.consume4(value.reinterpret_as_uint64().to_uint()) + #| self.consume4((value.reinterpret_as_uint64() >> 32).to_uint()) + #|} + #|pub fn Hasher::combine_uint(self : Hasher, value : UInt) -> Unit { + #| self.acc += 4 + #| self.consume4(value) + #|} + #|pub fn Hasher::combine_uint64(self : Hasher, value : UInt64) -> Unit { + #| self.combine_int64(value.reinterpret_as_int64()) + #|} + #|pub fn Hasher::combine_double(self : Hasher, value : Double) -> Unit { + #| self.combine_int64(value.reinterpret_as_int64()) + #|} + #|#deprecated + #|pub fn Hasher::combine_float(self : Hasher, value : Float) -> Unit { + #| self.combine_uint(value.reinterpret_as_uint()) + #|} + #|fn Float::reinterpret_as_uint(self : Float) -> UInt = "%f32.to_i32_reinterpret" + #|pub fn Hasher::combine_byte(self : Hasher, value : Byte) -> Unit { + #| self.consume1(value) + #|} + #|pub fn Hasher::combine_bytes(self : Hasher, value : Bytes) -> Unit { + #| let (cur, remain) = for cur = 0, remain = value.length(); remain >= 4; { + #| self.consume4(endian32(value, cur)) + #| continue cur + 4, remain - 4 + #| } nobreak { + #| (cur, remain) + #| } + #| for cur = cur, remain = remain; remain >= 1; { + #| self.consume1(value[cur]) + #| continue cur + 1, remain - 1 + #| } + #|} + #|pub fn Hasher::combine_string(self : Hasher, value : String) -> Unit { + #| for i in 0.. Unit { + #| self.combine_uint(value.to_uint()) + #|} + #|pub fn Hasher::finalize(self : Hasher) -> Int { + #| self.avalanche().reinterpret_as_int() + #|} + #|fn Hasher::avalanche(self : Hasher) -> UInt { + #| let mut acc = self.acc + #| acc = acc ^ (acc >> 15) + #| acc *= GPRIMES2 + #| acc = acc ^ (acc >> 13) + #| acc *= GPRIME3 + #| acc = acc ^ (acc >> 16) + #| acc + #|} + #|fn Hasher::consume4(self : Hasher, input : UInt) -> Unit { + #| self.acc = rotl(self.acc + input * GPRIME3, 17) * GPRIME4 + #|} + #|fn Hasher::consume1(self : Hasher, input : Byte) -> Unit { + #| self.acc = rotl(self.acc + input.to_uint() * GPRIME5, 11) * GPRIME1 + #|} + #|fn rotl(x : UInt, r : Int) -> UInt { + #| (x << r) | (x >> (32 - r)) + #|} + #|fn endian32(input : Bytes, cur : Int) -> UInt { + #| input[cur + 0].to_uint() | + #| ( + #| (input[cur + 1].to_uint() << 8) | + #| (input[cur + 2].to_uint() << 16) | + #| (input[cur + 3].to_uint() << 24) + #| ) + #|} + #|pub impl Hash for String with hash_combine(self, hasher) { + #| hasher.combine_string(self) + #|} + #|pub impl Hash for StringView with hash_combine( + #| self : StringView, + #| hasher : Hasher, + #|) -> Unit { + #| let str = self.str() + #| for i in self.start().. hasher.combine_int(0) + #| Some(x) => { + #| hasher.combine_int(1) + #| hasher.combine(x) + #| } + #| } + #|} + #|pub impl[T : Hash, E : Hash] Hash for Result[T, E] with hash_combine( + #| self, + #| hasher, + #|) { + #| match self { + #| Ok(x) => { + #| hasher.combine_int(0) + #| hasher.combine(x) + #| } + #| Err(x) => { + #| hasher.combine_int(1) + #| hasher.combine(x) + #| } + #| } + #|} + #|pub impl Hash for BytesView with hash_combine(self : BytesView, hasher : Hasher) { + #| let data = self.bytes() + #| let (start, rest) = for start = self.start(), rest = self.len(); rest >= 4; { + #| let result = for i in 0..<=3; result = (0 : UInt) { + #| continue result | (data.unsafe_get(i + start).to_uint() << (8 * i)) + #| } nobreak { + #| result + #| } + #| hasher.combine_uint(result) + #| continue start + 4, rest - 4 + #| } nobreak { + #| (start, rest) + #| } + #| for start = start, rest = rest; rest >= 1; { + #| hasher.combine_byte(data.unsafe_get(start)) + #| continue start + 1, rest - 1 + #| } + #|} + ), + "int.mbt": ( + #|pub fn Int::next_power_of_two(self : Int) -> Int { + #| guard self >= 0 + #| if self <= 1 { + #| return 1 + #| } + #| let max_power_of_two = 1073741824 // 2^30 + #| if self > max_power_of_two { + #| return max_power_of_two + #| } + #| (2147483647 >> ((self - 1).clz() - 1)) + 1 + #|} + #|pub fn Int::min(self : Int, other : Int) -> Int { + #| if self < other { + #| self + #| } else { + #| other + #| } + #|} + #|pub fn Int::max(self : Int, other : Int) -> Int { + #| if self > other { + #| self + #| } else { + #| other + #| } + #|} + #|pub fn Int::clamp(self : Int, min~ : Int, max~ : Int) -> Int { + #| guard min <= max + #| if self < min { + #| min + #| } else if self > max { + #| max + #| } else { + #| self + #| } + #|} + #|pub fn Int::is_leading_surrogate(self : Int) -> Bool { + #| 0xD800 <= self && self <= 0xDBFF + #|} + #|pub fn Int::is_trailing_surrogate(self : Int) -> Bool { + #| 0xDC00 <= self && self <= 0xDFFF + #|} + #|pub fn Int::is_surrogate(self : Int) -> Bool { + #| 0xD800 <= self && self <= 0xDFFF + #|} + #|pub fn Int::abs(self : Int) -> Int { + #| if self < 0 { + #| -self + #| } else { + #| self + #| } + #|} + ), + "int64.mbt": ( + #|pub fn Int64::from_int(i : Int) -> Int64 { + #| i.to_int64() + #|} + #|pub fn Int64::abs(self : Int64) -> Int64 { + #| if self < 0L { + #| -self + #| } else { + #| self + #| } + #|} + #|pub fn Int64::min(self : Int64, other : Int64) -> Int64 { + #| if self < other { + #| self + #| } else { + #| other + #| } + #|} + #|pub fn Int64::max(self : Int64, other : Int64) -> Int64 { + #| if self > other { + #| self + #| } else { + #| other + #| } + #|} + #|pub fn Int64::clamp(self : Int64, min~ : Int64, max~ : Int64) -> Int64 { + #| guard min <= max + #| if self < min { + #| min + #| } else if self > max { + #| max + #| } else { + #| self + #| } + #|} + #|pub impl Hash for Int64 with hash_combine(self, hasher) { + #| hasher.combine_int64(self) + #|} + ), + "int64_js.mbt": ( + #|priv struct MyInt64 { + #| hi : Int + #| lo : Int + #|} + #|fn MyInt64::to_int64(self : MyInt64) -> Int64 = "%identity" + #|fn MyInt64::from_int64(value : Int64) -> MyInt64 = "%identity" + #|impl Neg for MyInt64 with neg(self : MyInt64) -> MyInt64 { + #| if self.lo == 0 { + #| { hi: self.hi.lnot() + 1, lo: 0 } + #| } else { + #| { hi: self.hi.lnot(), lo: self.lo.lnot() + 1 } + #| } + #|} + #|fn MyInt64::add_hi_lo(self : MyInt64, bhi : Int, blo : Int) -> MyInt64 { + #| let { hi: ahi, lo: alo } = self + #| let lo = alo + blo + #| let s = lo >> 31 + #| let as_ = alo >> 31 + #| let bs = blo >> 31 + #| let c = ((as_ & bs) | (s.lnot() & (as_ ^ bs))) & 1 + #| let hi = ahi + bhi + c + #| { hi, lo } + #|} + #|impl Add for MyInt64 with add(self : MyInt64, other : MyInt64) -> MyInt64 { + #| self.add_hi_lo(other.hi, other.lo) + #|} + #|impl Sub for MyInt64 with sub(self : MyInt64, other : MyInt64) -> MyInt64 { + #| if other.lo == 0 { + #| { hi: self.hi - other.hi, lo: self.lo } + #| } else { + #| self.add_hi_lo(other.hi.lnot(), other.lo.lnot() + 1) + #| } + #|} + #|impl Mul for MyInt64 with mul(self : MyInt64, other : MyInt64) -> MyInt64 { + #| let { hi: ahi, lo: alo } = self + #| let { hi: bhi, lo: blo } = other + #| let ahi = ahi.reinterpret_as_uint() + #| let alo = alo.reinterpret_as_uint() + #| let bhi = bhi.reinterpret_as_uint() + #| let blo = blo.reinterpret_as_uint() + #| let a48 = ahi >> 16 + #| let a32 = ahi & 0xffff + #| let a16 = alo >> 16 + #| let a00 = alo & 0xffff + #| let b48 = bhi >> 16 + #| let b32 = bhi & 0xffff + #| let b16 = blo >> 16 + #| let b00 = blo & 0xffff + #| let c00 = a00 * b00 + #| let c16 = c00 >> 16 + #| let c00 = c00 & 0xffff + #| let c16 = c16 + a16 * b00 + #| let c32 = c16 >> 16 + #| let c16 = c16 & 0xffff + #| let c16 = c16 + a00 * b16 + #| let c32 = c32 + (c16 >> 16) + #| let c16 = c16 & 0xffff + #| let c32 = c32 + a32 * b00 + #| let c48 = c32 >> 16 + #| let c32 = c32 & 0xffff + #| let c32 = c32 + a16 * b16 + #| let c48 = c48 + (c32 >> 16) + #| let c32 = c32 & 0xffff + #| let c32 = c32 + a00 * b32 + #| let c48 = c48 + (c32 >> 16) + #| let c32 = c32 & 0xffff + #| let c48 = c48 + a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48 + #| let c48 = c48 & 0xffff + #| { + #| hi: ((c48 << 16) | c32).reinterpret_as_int(), + #| lo: ((c16 << 16) | c00).reinterpret_as_int(), + #| } + #|} + #|priv struct Int64WasmHelper { + #| div_s : (Int, Int, Int, Int) -> Int + #| div_u : (Int, Int, Int, Int) -> Int + #| rem_s : (Int, Int, Int, Int) -> Int + #| rem_u : (Int, Int, Int, Int) -> Int + #| get_high : () -> Int + #|} + #|priv struct WasmHelperCache { + #| mut tried : Bool + #| mut exports : Int64WasmHelper? + #|} + #|let wasm_helper_cache : WasmHelperCache = { tried: false, exports: None } + #|fn try_get_int64_wasm_helper() -> Bool { + #| if wasm_helper_cache.tried { + #| return match wasm_helper_cache.exports { + #| Some(_) => true + #| None => false + #| } + #| } + #| wasm_helper_cache.tried = true + #| wasm_helper_cache.exports = try_init_wasm_helper() + #| match wasm_helper_cache.exports { + #| Some(_) => true + #| None => false + #| } + #|} + #|extern "js" fn try_init_wasm_helper() -> Int64WasmHelper? = + #| #|function() { + #| #| try { + #| #| return new WebAssembly.Instance(new WebAssembly.Module(new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0, 1, 13, 2, 96, 0, 1, 127, 96, 4, 127, 127, 127, 127, 1, 127, 3, 7, 6, 0, 1, 1, 1, 1, 1, 6, 6, 1, 127, 1, 65, 0, 11, 7, 50, 6, 3, 109, 117, 108, 0, 1, 5, 100, 105, 118, 95, 115, 0, 2, 5, 100, 105, 118, 95, 117, 0, 3, 5, 114, 101, 109, 95, 115, 0, 4, 5, 114, 101, 109, 95, 117, 0, 5, 8, 103, 101, 116, 95, 104, 105, 103, 104, 0, 0, 10, 191, 1, 6, 4, 0, 35, 0, 11, 36, 1, 1, 126, 32, 0, 173, 32, 1, 173, 66, 32, 134, 132, 32, 2, 173, 32, 3, 173, 66, 32, 134, 132, 126, 34, 4, 66, 32, 135, 167, 36, 0, 32, 4, 167, 11, 36, 1, 1, 126, 32, 0, 173, 32, 1, 173, 66, 32, 134, 132, 32, 2, 173, 32, 3, 173, 66, 32, 134, 132, 127, 34, 4, 66, 32, 135, 167, 36, 0, 32, 4, 167, 11, 36, 1, 1, 126, 32, 0, 173, 32, 1, 173, 66, 32, 134, 132, 32, 2, 173, 32, 3, 173, 66, 32, 134, 132, 128, 34, 4, 66, 32, 135, 167, 36, 0, 32, 4, 167, 11, 36, 1, 1, 126, 32, 0, 173, 32, 1, 173, 66, 32, 134, 132, 32, 2, 173, 32, 3, 173, 66, 32, 134, 132, 129, 34, 4, 66, 32, 135, 167, 36, 0, 32, 4, 167, 11, 36, 1, 1, 126, 32, 0, 173, 32, 1, 173, 66, 32, 134, 132, 32, 2, 173, 32, 3, 173, 66, 32, 134, 132, 130, 34, 4, 66, 32, 135, 167, 36, 0, 32, 4, 167, 11])), {}).exports; + #| #| } catch (e) { + #| #| return undefined; + #| #| } + #| #|} + #|extern "js" fn MyInt64::div_bigint(self : MyInt64, other : MyInt64) -> MyInt64 = + #| #|(a, b) => { + #| #| const aVal = (BigInt(a.hi) << 32n) | BigInt(a.lo >>> 0); + #| #| const bVal = (BigInt(b.hi) << 32n) | BigInt(b.lo >>> 0); + #| #| const result = aVal / bVal; + #| #| const lo = Number(result & 0xFFFFFFFFn); + #| #| const hi = Number((result >> 32n) & 0xFFFFFFFFn); + #| #| return { hi: hi | 0, lo: lo | 0 }; + #| #|} + #|extern "js" fn MyInt64::div_u_bigint( + #| self : MyInt64, + #| other : MyInt64, + #|) -> MyInt64 = + #| #|(a, b) => { + #| #| const aVal = (BigInt(a.hi >>> 0) << 32n) | BigInt(a.lo >>> 0); + #| #| const bVal = (BigInt(b.hi >>> 0) << 32n) | BigInt(b.lo >>> 0); + #| #| const result = aVal / bVal; + #| #| const lo = Number(result & 0xFFFFFFFFn); + #| #| const hi = Number((result >> 32n) & 0xFFFFFFFFn); + #| #| return { hi: hi | 0, lo: lo | 0 }; + #| #|} + #|extern "js" fn MyInt64::mod_bigint(self : MyInt64, other : MyInt64) -> MyInt64 = + #| #|(a, b) => { + #| #| const aVal = (BigInt(a.hi) << 32n) | BigInt(a.lo >>> 0); + #| #| const bVal = (BigInt(b.hi) << 32n) | BigInt(b.lo >>> 0); + #| #| const result = aVal % bVal; + #| #| const lo = Number(result & 0xFFFFFFFFn); + #| #| const hi = Number((result >> 32n) & 0xFFFFFFFFn); + #| #| return { hi: hi | 0, lo: lo | 0 }; + #| #|} + #|extern "js" fn MyInt64::mod_u_bigint( + #| self : MyInt64, + #| other : MyInt64, + #|) -> MyInt64 = + #| #|(a, b) => { + #| #| const aVal = (BigInt(a.hi >>> 0) << 32n) | BigInt(a.lo >>> 0); + #| #| const bVal = (BigInt(b.hi >>> 0) << 32n) | BigInt(b.lo >>> 0); + #| #| const result = aVal % bVal; + #| #| const lo = Number(result & 0xFFFFFFFFn); + #| #| const hi = Number((result >> 32n) & 0xFFFFFFFFn); + #| #| return { hi: hi | 0, lo: lo | 0 }; + #| #|} + #|impl Div for MyInt64 with div(self : MyInt64, other : MyInt64) -> MyInt64 { + #| guard !(other.hi == 0 && other.lo == 0) else { panic() } + #| if !try_get_int64_wasm_helper() { + #| return self.div_bigint(other) + #| } + #| match wasm_helper_cache.exports { + #| Some(exports) => { + #| let { hi: ahi, lo: alo } = self + #| let { hi: bhi, lo: blo } = other + #| let lo = (exports.div_s)(alo, ahi, blo, bhi) + #| let hi = (exports.get_high)() + #| { hi, lo } + #| } + #| None => panic() + #| } + #|} + #|fn MyInt64::div_u(self : MyInt64, other : MyInt64) -> MyInt64 { + #| guard !(other.hi == 0 && other.lo == 0) else { panic() } + #| if !try_get_int64_wasm_helper() { + #| return self.div_u_bigint(other) + #| } + #| match wasm_helper_cache.exports { + #| Some(exports) => { + #| let { hi: ahi, lo: alo } = self + #| let { hi: bhi, lo: blo } = other + #| let lo = (exports.div_u)(alo, ahi, blo, bhi) + #| let hi = (exports.get_high)() + #| { hi, lo } + #| } + #| None => panic() + #| } + #|} + #|impl Mod for MyInt64 with mod(self : MyInt64, other : MyInt64) -> MyInt64 { + #| guard !(other.hi == 0 && other.lo == 0) else { panic() } + #| if !try_get_int64_wasm_helper() { + #| return self.mod_bigint(other) + #| } + #| match wasm_helper_cache.exports { + #| Some(exports) => { + #| let { hi: ahi, lo: alo } = self + #| let { hi: bhi, lo: blo } = other + #| let lo = (exports.rem_s)(alo, ahi, blo, bhi) + #| let hi = (exports.get_high)() + #| { hi, lo } + #| } + #| None => panic() + #| } + #|} + #|fn MyInt64::mod_u(self : MyInt64, other : MyInt64) -> MyInt64 { + #| guard !(other.hi == 0 && other.lo == 0) else { panic() } + #| if !try_get_int64_wasm_helper() { + #| return self.mod_u_bigint(other) + #| } + #| match wasm_helper_cache.exports { + #| Some(exports) => { + #| let { hi: ahi, lo: alo } = self + #| let { hi: bhi, lo: blo } = other + #| let lo = (exports.rem_u)(alo, ahi, blo, bhi) + #| let hi = (exports.get_high)() + #| { hi, lo } + #| } + #| None => panic() + #| } + #|} + #|fn MyInt64::lnot(self : MyInt64) -> MyInt64 { + #| { hi: self.hi.lnot(), lo: self.lo.lnot() } + #|} + #|fn MyInt64::land(self : MyInt64, other : MyInt64) -> MyInt64 { + #| { hi: self.hi & other.hi, lo: self.lo & other.lo } + #|} + #|fn MyInt64::lor(self : MyInt64, other : MyInt64) -> MyInt64 { + #| { hi: self.hi | other.hi, lo: self.lo | other.lo } + #|} + #|fn MyInt64::lxor(self : MyInt64, other : MyInt64) -> MyInt64 { + #| { hi: self.hi ^ other.hi, lo: self.lo ^ other.lo } + #|} + #|fn MyInt64::lsl(self : MyInt64, shift : Int) -> MyInt64 { + #| let shift = shift & 63 + #| if shift == 0 { + #| self + #| } else if shift < 32 { + #| let { hi, lo } = self + #| let hi = hi.reinterpret_as_uint() + #| let lo = lo.reinterpret_as_uint() + #| let hi = (hi << shift) | (lo >> (32 - shift)) + #| let lo = lo << shift + #| { hi: hi.reinterpret_as_int(), lo: lo.reinterpret_as_int() } + #| } else { + #| { hi: self.lo << (shift - 32), lo: 0 } + #| } + #|} + #|fn MyInt64::lsr(self : MyInt64, shift : Int) -> MyInt64 { + #| let shift = shift & 63 + #| if shift == 0 { + #| self + #| } else if shift < 32 { + #| { + #| hi: (self.hi.reinterpret_as_uint() >> shift).reinterpret_as_int(), + #| lo: (self.lo.reinterpret_as_uint() >> shift).reinterpret_as_int() | + #| (self.hi << (32 - shift)), + #| } + #| } else { + #| { + #| hi: 0, + #| lo: (self.hi.reinterpret_as_uint() >> (shift - 32)).reinterpret_as_int(), + #| } + #| } + #|} + #|fn MyInt64::asr(self : MyInt64, shift : Int) -> MyInt64 { + #| let shift = shift & 63 + #| if shift == 0 { + #| self + #| } else if shift < 32 { + #| { + #| hi: self.hi >> shift, + #| lo: (self.lo.reinterpret_as_uint() >> shift).reinterpret_as_int() | + #| (self.hi << (32 - shift)), + #| } + #| } else { + #| { hi: self.hi >> 31, lo: self.hi >> (shift - 32) } + #| } + #|} + #|fn MyInt64::clz(self : MyInt64) -> Int { + #| if self.hi != 0 { + #| self.hi.clz() + #| } else { + #| 32 + self.lo.clz() + #| } + #|} + #|fn MyInt64::ctz(self : MyInt64) -> Int { + #| if self.lo != 0 { + #| self.lo.ctz() + #| } else { + #| 32 + self.hi.ctz() + #| } + #|} + #|fn MyInt64::popcnt(self : MyInt64) -> Int { + #| self.hi.popcnt() + self.lo.popcnt() + #|} + #|impl Eq for MyInt64 with equal(self : MyInt64, other : MyInt64) -> Bool { + #| self.hi == other.hi && self.lo == other.lo + #|} + #|extern "js" fn MyInt64::compare(self : MyInt64, other : MyInt64) -> Int = + #| #|(a, b) => { + #| #| const ahi = a.hi; + #| #| const bhi = b.hi; + #| #| if (ahi < bhi) { + #| #| return -1; + #| #| } + #| #| if (ahi > bhi) { + #| #| return 1; + #| #| } + #| #| const alo = a.lo >>> 0; + #| #| const blo = b.lo >>> 0; + #| #| if (alo < blo) { + #| #| return -1; + #| #| } + #| #| if (alo > blo) { + #| #| return 1; + #| #| } + #| #| return 0; + #| #|} + #|extern "js" fn MyInt64::compare_u(self : MyInt64, other : MyInt64) -> Int = + #| #|(a, b) => { + #| #| const ahi = a.hi >>> 0; + #| #| const bhi = b.hi >>> 0; + #| #| if (ahi < bhi) { + #| #| return -1; + #| #| } + #| #| if (ahi > bhi) { + #| #| return 1; + #| #| } + #| #| const alo = a.lo >>> 0; + #| #| const blo = b.lo >>> 0; + #| #| if (alo < blo) { + #| #| return -1; + #| #| } + #| #| if (alo > blo) { + #| #| return 1; + #| #| } + #| #| return 0; + #| #|} + #|fn MyInt64::from_int(value : Int) -> MyInt64 { + #| { hi: (value >> 31) & -1, lo: value | 0 } + #|} + #|fn MyInt64::to_int(self : MyInt64) -> Int { + #| self.lo + #|} + #|fn MyInt64::to_uint(self : MyInt64) -> UInt { + #| self.lo.reinterpret_as_uint() + #|} + #|fn MyInt64::extend_i32_u(value : Int) -> MyInt64 { + #| { hi: 0, lo: value } + #|} + #|extern "js" fn MyInt64::reinterpret_as_double(self : MyInt64) -> Double = + #| #|function f(a) { + #| #| let view = f._view; + #| #| if (view === undefined) { + #| #| view = f._view = new DataView(new ArrayBuffer(8)); + #| #| } + #| #| view.setUint32(0, a.hi); + #| #| view.setUint32(4, a.lo); + #| #| return view.getFloat64(0); + #| #|} + #|extern "js" fn MyInt64::reinterpret_double(value : Double) -> MyInt64 = + #| #|function f(a) { + #| #| let view = f._view; + #| #| if (view === undefined) { + #| #| view = f._view = new DataView(new ArrayBuffer(8)); + #| #| } + #| #| view.setFloat64(0, a); + #| #| const hi = view.getInt32(0); + #| #| const lo = view.getInt32(4); + #| #| return { hi, lo }; + #| #|} + #|extern "js" fn MyInt64::trunc_double_u(value : Double) -> MyInt64 = + #| #|(a) => { + #| #| let hi = (a * (1 / 0x100000000)) | 0; + #| #| let lo = a | 0; + #| #| return { hi, lo }; + #| #|} + #|extern "js" fn MyInt64::convert_to_double_u(self : MyInt64) -> Double = + #| #|(a) => (a.hi >>> 0) * 4294967296.0 + (a.lo >>> 0) + #|extern "js" fn MyInt64::convert_to_double(self : MyInt64) -> Double = + #| #|(a) => a.hi * 4294967296.0 + (a.lo >>> 0) + #|pub impl Neg for Int64 with neg(self : Int64) -> Int64 { + #| (-MyInt64::from_int64(self)).to_int64() + #|} + #|pub impl Add for Int64 with add(self : Int64, other : Int64) -> Int64 { + #| MyInt64::from_int64(self).add(MyInt64::from_int64(other)).to_int64() + #|} + #|pub impl Sub for Int64 with sub(self : Int64, other : Int64) -> Int64 { + #| MyInt64::from_int64(self).sub(MyInt64::from_int64(other)).to_int64() + #|} + #|pub impl Mul for Int64 with mul(self : Int64, other : Int64) -> Int64 { + #| MyInt64::from_int64(self).mul(MyInt64::from_int64(other)).to_int64() + #|} + #|pub impl Div for Int64 with div(self : Int64, other : Int64) -> Int64 { + #| MyInt64::from_int64(self).div(MyInt64::from_int64(other)).to_int64() + #|} + #|pub impl Mod for Int64 with mod(self : Int64, other : Int64) -> Int64 { + #| MyInt64::from_int64(self).mod(MyInt64::from_int64(other)).to_int64() + #|} + #|pub fn Int64::lnot(self : Int64) -> Int64 { + #| MyInt64::from_int64(self).lnot().to_int64() + #|} + #|pub impl BitAnd for Int64 with land(self : Int64, other : Int64) -> Int64 { + #| MyInt64::from_int64(self).land(MyInt64::from_int64(other)).to_int64() + #|} + #|pub impl BitOr for Int64 with lor(self : Int64, other : Int64) -> Int64 { + #| MyInt64::from_int64(self).lor(MyInt64::from_int64(other)).to_int64() + #|} + #|pub impl BitXOr for Int64 with lxor(self : Int64, other : Int64) -> Int64 { + #| MyInt64::from_int64(self).lxor(MyInt64::from_int64(other)).to_int64() + #|} + #|#deprecated("Use infix operator `<<` instead") + #|#coverage.skip + #|pub fn Int64::lsl(self : Int64, other : Int) -> Int64 { + #| MyInt64::from_int64(self).lsl(other).to_int64() + #|} + #|#deprecated("Use infix operator `<<` instead") + #|#coverage.skip + #|pub fn Int64::shl(self : Int64, other : Int) -> Int64 { + #| MyInt64::from_int64(self).lsl(other).to_int64() + #|} + #|#deprecated("Use UInt64 type and infix operator `>>` instead") + #|#coverage.skip + #|pub fn Int64::lsr(self : Int64, other : Int) -> Int64 { + #| MyInt64::from_int64(self).lsr(other).to_int64() + #|} + #|#deprecated("Use infix operator `>>` instead") + #|#coverage.skip + #|pub fn Int64::shr(self : Int64, other : Int) -> Int64 { + #| MyInt64::from_int64(self).asr(other).to_int64() + #|} + #|#deprecated("Use infix operator `>>` instead") + #|#coverage.skip + #|pub fn Int64::asr(self : Int64, other : Int) -> Int64 { + #| MyInt64::from_int64(self).asr(other).to_int64() + #|} + #|pub impl Shr for Int64 with shr(self : Int64, other : Int) -> Int64 { + #| MyInt64::from_int64(self).asr(other).to_int64() + #|} + #|pub impl Shl for Int64 with shl(self : Int64, other : Int) -> Int64 { + #| MyInt64::from_int64(self).lsl(other).to_int64() + #|} + #|pub fn Int64::ctz(self : Int64) -> Int { + #| MyInt64::from_int64(self).ctz() + #|} + #|pub fn Int64::clz(self : Int64) -> Int { + #| MyInt64::from_int64(self).clz() + #|} + #|pub fn Int64::popcnt(self : Int64) -> Int { + #| MyInt64::from_int64(self).popcnt() + #|} + #|pub impl Eq for Int64 with equal(self : Int64, other : Int64) -> Bool { + #| MyInt64::from_int64(self) == MyInt64::from_int64(other) + #|} + #|pub impl Compare for Int64 with compare(self : Int64, other : Int64) -> Int { + #| MyInt64::compare(MyInt64::from_int64(self), MyInt64::from_int64(other)) + #|} + #|pub impl Default for Int64 with default() { + #| 0L + #|} + #|pub fn Int64::to_int(self : Int64) -> Int { + #| MyInt64::from_int64(self).to_int() + #|} + #|pub fn Int64::to_double(self : Int64) -> Double { + #| Double::convert_int64(self) + #|} + #|pub fn Int64::to_byte(self : Int64) -> Byte { + #| MyInt64::from_int64(self).to_int().to_byte() + #|} + #|pub fn Int64::to_uint16(self : Int64) -> UInt16 { + #| MyInt64::from_int64(self).to_int().to_uint16() + #|} + #|pub fn UInt64::extend_uint(value : UInt) -> UInt64 { + #| MyInt64::extend_i32_u(value.reinterpret_as_int()).to_uint64() + #|} + #|pub fn Int64::reinterpret_as_double(self : Int64) -> Double { + #| MyInt64::reinterpret_as_double(MyInt64::from_int64(self)) + #|} + #|pub fn UInt64::reinterpret_as_double(self : UInt64) -> Double { + #| MyInt64::reinterpret_as_double(MyInt64::from_uint64(self)) + #|} + #|pub fn Int::to_int64(self : Int) -> Int64 { + #| MyInt64::from_int(self).to_int64() + #|} + #|pub fn UInt16::to_int64(self : UInt16) -> Int64 { + #| MyInt64::from_int(self.to_int()).to_int64() + #|} + #|#deprecated("Use `reinterpret_as_int64` instead") + #|#coverage.skip + #|pub fn Double::reinterpret_as_i64(self : Double) -> Int64 { + #| MyInt64::reinterpret_double(self).to_int64() + #|} + #|pub fn Double::reinterpret_as_int64(self : Double) -> Int64 { + #| MyInt64::reinterpret_double(self).to_int64() + #|} + #|#deprecated("Use `reinterpret_as_uint64` instead") + #|#coverage.skip + #|pub fn Double::reinterpret_as_u64(self : Double) -> UInt64 { + #| MyInt64::reinterpret_double(self).to_uint64() + #|} + #|pub fn Double::reinterpret_as_uint64(self : Double) -> UInt64 { + #| MyInt64::reinterpret_double(self).to_uint64() + #|} + #|pub fn Double::convert_uint64(value : UInt64) -> Double { + #| MyInt64::convert_to_double_u(MyInt64::from_uint64(value)) + #|} + #|fn Double::convert_int64(value : Int64) -> Double { + #| MyInt64::convert_to_double(MyInt64::from_int64(value)) + #|} + #|fn MyInt64::to_uint64(self : MyInt64) -> UInt64 = "%identity" + #|fn MyInt64::from_uint64(value : UInt64) -> MyInt64 = "%identity" + #|#deprecated("Use `reinterpret_as_uint64` instead") + #|#coverage.skip + #|pub fn Int64::to_uint64(self : Int64) -> UInt64 = "%identity" + #|pub fn Int64::reinterpret_as_uint64(self : Int64) -> UInt64 = "%identity" + #|pub impl Add for UInt64 with add(self : UInt64, other : UInt64) -> UInt64 { + #| MyInt64::from_uint64(self).add(MyInt64::from_uint64(other)).to_uint64() + #|} + #|pub impl Sub for UInt64 with sub(self : UInt64, other : UInt64) -> UInt64 { + #| MyInt64::from_uint64(self).sub(MyInt64::from_uint64(other)).to_uint64() + #|} + #|pub impl Mul for UInt64 with mul(self : UInt64, other : UInt64) -> UInt64 { + #| MyInt64::from_uint64(self).mul(MyInt64::from_uint64(other)).to_uint64() + #|} + #|pub impl Div for UInt64 with div(self : UInt64, other : UInt64) -> UInt64 { + #| MyInt64::from_uint64(self).div_u(MyInt64::from_uint64(other)).to_uint64() + #|} + #|pub impl Mod for UInt64 with mod(self : UInt64, other : UInt64) -> UInt64 { + #| MyInt64::from_uint64(self).mod_u(MyInt64::from_uint64(other)).to_uint64() + #|} + #|#deprecated("Use reinterpret_as_int64 instead") + #|#coverage.skip + #|pub fn UInt64::to_int64(self : UInt64) -> Int64 = "%identity" + #|pub fn UInt64::reinterpret_as_int64(self : UInt64) -> Int64 = "%identity" + #|pub fn UInt64::to_uint(self : UInt64) -> UInt { + #| MyInt64::from_uint64(self).to_uint() + #|} + #|pub fn UInt64::to_uint16(self : UInt64) -> UInt16 { + #| self.reinterpret_as_int64().to_uint16() + #|} + #|pub fn UInt64::to_int(self : UInt64) -> Int { + #| MyInt64::from_uint64(self).to_int() + #|} + #|pub fn UInt64::to_double(self : UInt64) -> Double { + #| Double::convert_uint64(self) + #|} + #|pub impl Compare for UInt64 with compare(self : UInt64, other : UInt64) -> Int { + #| MyInt64::from_uint64(self).compare_u(MyInt64::from_uint64(other)) + #|} + #|pub impl Eq for UInt64 with equal(self : UInt64, other : UInt64) -> Bool { + #| MyInt64::from_uint64(self).equal(MyInt64::from_uint64(other)) + #|} + #|pub fn UInt64::trunc_double(value : Double) -> UInt64 { + #| MyInt64::trunc_double_u(value).to_uint64() + #|} + #|pub impl BitAnd for UInt64 with land(self : UInt64, other : UInt64) -> UInt64 { + #| MyInt64::land(MyInt64::from_uint64(self), MyInt64::from_uint64(other)).to_uint64() + #|} + #|pub impl BitOr for UInt64 with lor(self : UInt64, other : UInt64) -> UInt64 { + #| MyInt64::lor(MyInt64::from_uint64(self), MyInt64::from_uint64(other)).to_uint64() + #|} + #|pub impl BitXOr for UInt64 with lxor(self : UInt64, other : UInt64) -> UInt64 { + #| MyInt64::lxor(MyInt64::from_uint64(self), MyInt64::from_uint64(other)).to_uint64() + #|} + #|pub fn UInt64::lnot(self : UInt64) -> UInt64 { + #| MyInt64::lnot(MyInt64::from_uint64(self)).to_uint64() + #|} + #|#deprecated("Use infix operator `<<` instead") + #|#coverage.skip + #|pub fn UInt64::lsl(self : UInt64, shift : Int) -> UInt64 { + #| MyInt64::lsl(MyInt64::from_uint64(self), shift).to_uint64() + #|} + #|#deprecated("Use infix operator `<<` instead") + #|#coverage.skip + #|pub fn UInt64::lsr(self : UInt64, shift : Int) -> UInt64 { + #| MyInt64::lsr(MyInt64::from_uint64(self), shift).to_uint64() + #|} + #|#deprecated("Use infix operator `>>` instead") + #|#coverage.skip + #|pub fn UInt64::shl(self : UInt64, shift : Int) -> UInt64 { + #| MyInt64::lsl(MyInt64::from_uint64(self), shift).to_uint64() + #|} + #|#deprecated("Use infix operator `>>` instead") + #|#coverage.skip + #|pub fn UInt64::shr(self : UInt64, shift : Int) -> UInt64 { + #| MyInt64::lsr(MyInt64::from_uint64(self), shift).to_uint64() + #|} + #|pub impl Shl for UInt64 with shl(self : UInt64, shift : Int) -> UInt64 { + #| MyInt64::lsl(MyInt64::from_uint64(self), shift).to_uint64() + #|} + #|pub impl Shr for UInt64 with shr(self : UInt64, shift : Int) -> UInt64 { + #| MyInt64::lsr(MyInt64::from_uint64(self), shift).to_uint64() + #|} + #|pub fn UInt64::clz(self : UInt64) -> Int { + #| MyInt64::from_uint64(self).clz() + #|} + #|pub fn UInt64::ctz(self : UInt64) -> Int { + #| MyInt64::from_uint64(self).ctz() + #|} + #|pub fn UInt64::popcnt(self : UInt64) -> Int { + #| MyInt64::from_uint64(self).popcnt() + #|} + #|#deprecated("Use `Float::from_int64` instead") + #|pub fn Int64::to_float(self : Int64) -> Float { + #| self.to_double().to_float() + #|} + #|#deprecated("Use `Float::from_uint64` instead") + #|pub fn UInt64::to_float(self : UInt64) -> Float { + #| Double::convert_uint64(self).to_float() + #|} + ), + "int64_nonjs.mbt": ( + #|pub impl Neg for Int64 with neg(self : Int64) -> Int64 = "%i64_neg" + #|pub impl Add for Int64 with add(self, other) = "%i64_add" + #|pub impl Sub for Int64 with sub(self, other) = "%i64_sub" + #|pub impl Mul for Int64 with mul(self, other) = "%i64_mul" + #|pub impl Div for Int64 with div(self, other) = "%i64_div" + #|pub impl Mod for Int64 with mod(self, other) = "%i64_mod" + #|pub fn Int64::lnot(self : Int64) -> Int64 = "%i64_lnot" + #|pub impl BitAnd for Int64 with land(self, other) = "%i64_land" + #|pub impl BitOr for Int64 with lor(self, other) = "%i64_lor" + #|pub impl BitXOr for Int64 with lxor(self, other) = "%i64_lxor" + #|#deprecated("Use infix operator `<<` instead") + #|#coverage.skip + #|pub fn Int64::lsl(self : Int64, other : Int) -> Int64 = "%i64_shl" + #|#deprecated("Use infix operator `<<` instead") + #|#coverage.skip + #|pub fn Int64::shl(self : Int64, other : Int) -> Int64 = "%i64_shl" + #|#deprecated("Use UInt64 type and infix operator `>>` instead") + #|#coverage.skip + #|pub fn Int64::lsr(self : Int64, other : Int) -> Int64 = "%u64.shr" + #|#deprecated("Use infix operator `>>` instead") + #|#coverage.skip + #|pub fn Int64::asr(self : Int64, other : Int) -> Int64 = "%i64_shr" + #|#deprecated("Use infix operator `>>` instead") + #|#coverage.skip + #|pub fn Int64::shr(self : Int64, other : Int) -> Int64 = "%i64_shr" + #|pub impl Shl for Int64 with shl(self, other) = "%i64_shl" + #|pub impl Shr for Int64 with shr(self, other) = "%i64_shr" + #|pub fn Int64::ctz(self : Int64) -> Int = "%i64_ctz" + #|pub fn Int64::clz(self : Int64) -> Int = "%i64_clz" + #|pub fn Int64::popcnt(self : Int64) -> Int = "%i64_popcnt" + #|pub impl Eq for Int64 with equal(self : Int64, other : Int64) -> Bool = "%i64_eq" + #|pub impl Eq for Int64 with not_equal(self : Int64, other : Int64) -> Bool = "%i64_ne" + #|pub impl Compare for Int64 with compare(self, other) = "%i64_compare" + #|pub impl Compare for Int64 with op_lt(x, y) = "%i64.lt" + #|pub impl Compare for Int64 with op_le(x, y) = "%i64.le" + #|pub impl Compare for Int64 with op_gt(x, y) = "%i64.gt" + #|pub impl Compare for Int64 with op_ge(x, y) = "%i64.ge" + #|pub impl Default for Int64 with default() = "%i64_default" + #|pub fn Int64::to_int(self : Int64) -> Int = "%i64_to_i32" + #|pub fn Int64::to_double(self : Int64) -> Double = "%i64_to_f64" + #|pub fn Int64::reinterpret_as_double(self : Int64) -> Double = "%i64_to_f64_reinterpret" + #|pub fn UInt64::reinterpret_as_double(self : UInt64) -> Double = "%i64_to_f64_reinterpret" + #|pub fn Int64::to_byte(self : Int64) -> Byte = "%i64_to_byte" + #|pub fn Int64::to_uint16(self : Int64) -> UInt16 = "%i64_to_u16" + #|pub fn UInt64::trunc_double(val : Double) -> UInt64 = "%f64.to_u64" + #|#deprecated("Use `Float::from_int64` instead") + #|pub fn Int64::to_float(self : Int64) -> Float = "%i64.to_f32" + #|pub fn UInt64::extend_uint(val : UInt) -> UInt64 = "%u32.to_u64" + #|pub fn Int::to_int64(self : Int) -> Int64 = "%i32_to_i64" + #|pub fn UInt16::to_int64(self : UInt16) -> Int64 = "%u16_to_i64" + #|#deprecated("Use `reinterpret_as_int64` instead") + #|#coverage.skip + #|pub fn Double::reinterpret_as_i64(self : Double) -> Int64 = "%f64_to_i64_reinterpret" + #|pub fn Double::reinterpret_as_int64(self : Double) -> Int64 = "%f64_to_i64_reinterpret" + #|#deprecated("Use `reinterpret_as_uint64` instead") + #|#coverage.skip + #|pub fn Double::reinterpret_as_u64(self : Double) -> UInt64 = "%f64_to_i64_reinterpret" + #|pub fn Double::reinterpret_as_uint64(self : Double) -> UInt64 = "%f64_to_i64_reinterpret" + #|pub fn Double::convert_uint64(val : UInt64) -> Double = "%u64.to_f64" + #|#deprecated("Use `reinterpret_as_uint64` instead") + #|#coverage.skip + #|pub fn Int64::to_uint64(self : Int64) -> UInt64 = "%i64.to_u64_reinterpret" + #|pub fn Int64::reinterpret_as_uint64(self : Int64) -> UInt64 = "%i64.to_u64_reinterpret" + #|#deprecated("Use `reinterpret_as_int64` instead") + #|#coverage.skip + #|pub fn UInt64::to_int64(self : UInt64) -> Int64 = "%u64.to_i64_reinterpret" + #|pub fn UInt64::reinterpret_as_int64(self : UInt64) -> Int64 = "%u64.to_i64_reinterpret" + #|pub fn UInt64::to_uint16(self : UInt64) -> UInt16 { + #| self.reinterpret_as_int64().to_uint16() + #|} + #|pub fn UInt64::to_uint(self : UInt64) -> UInt = "%u64.to_u32" + #|pub fn UInt64::to_int(self : UInt64) -> Int = "%u64.to_i32" + #|pub fn UInt64::to_double(self : UInt64) -> Double = "%u64.to_f64" + #|pub impl Add for UInt64 with add(self, other) = "%u64.add" + #|pub impl Sub for UInt64 with sub(self, other) = "%u64.sub" + #|pub impl Mul for UInt64 with mul(self, other) = "%u64.mul" + #|pub impl Div for UInt64 with div(self, other) = "%u64.div" + #|pub impl Mod for UInt64 with mod(self, other) = "%u64.mod" + #|pub impl Compare for UInt64 with compare(self, other) = "%u64.compare" + #|pub impl Compare for UInt64 with op_lt(x, y) = "%u64.lt" + #|pub impl Compare for UInt64 with op_le(x, y) = "%u64.le" + #|pub impl Compare for UInt64 with op_gt(x, y) = "%u64.gt" + #|pub impl Compare for UInt64 with op_ge(x, y) = "%u64.ge" + #|pub impl Eq for UInt64 with equal(self : UInt64, other : UInt64) -> Bool = "%u64.eq" + #|pub impl Eq for UInt64 with not_equal(self : UInt64, other : UInt64) -> Bool = "%u64.ne" + #|pub impl BitAnd for UInt64 with land(self, other) = "%u64.bitand" + #|pub impl BitOr for UInt64 with lor(self, other) = "%u64.bitor" + #|pub impl BitXOr for UInt64 with lxor(self, other) = "%u64.bitxor" + #|pub fn UInt64::lnot(self : UInt64) -> UInt64 = "%u64.bitnot" + #|#deprecated("Use infix operator `<<` instead") + #|#coverage.skip + #|pub fn UInt64::lsl(self : UInt64, shift : Int) -> UInt64 = "%u64.shl" + #|#deprecated("Use infix operator `<<` instead") + #|#coverage.skip + #|pub fn UInt64::shl(self : UInt64, shift : Int) -> UInt64 = "%u64.shl" + #|#deprecated("Use infix operator `>>` instead") + #|#coverage.skip + #|pub fn UInt64::shr(self : UInt64, shift : Int) -> UInt64 = "%u64.shr" + #|#deprecated("Use infix operator `>>` instead") + #|#coverage.skip + #|pub fn UInt64::lsr(self : UInt64, shift : Int) -> UInt64 = "%u64.shr" + #|pub impl Shl for UInt64 with shl(self, shift) = "%u64.shl" + #|pub impl Shr for UInt64 with shr(self, shift) = "%u64.shr" + #|pub fn UInt64::clz(self : UInt64) -> Int = "%u64.clz" + #|pub fn UInt64::ctz(self : UInt64) -> Int = "%u64.ctz" + #|pub fn UInt64::popcnt(self : UInt64) -> Int = "%u64.popcnt" + #|#deprecated("Use `Float::from_uint64` instead") + #|pub fn UInt64::to_float(self : UInt64) -> Float = "%u64.to_f32" + ), + "intrinsics.mbt": ( + #|pub fn[T] ignore(t : T) -> Unit = "%ignore" + #|pub fn[T] physical_equal(a : T, b : T) -> Bool = "%refeq" + #|#callsite(autofill(loc)) + #|pub fn[T] abort(string : String, loc~ : SourceLoc) -> T { + #| @abort.abort( + #| ( + #| $|\{string} + #| $| at \{loc} + #| $| + #| ), + #| ) + #|} + #|pub fn[T] panic() -> T = "%panic" + #|#deprecated + #|pub fn not(x : Bool) -> Bool = "%bool_not" + #|pub impl Eq for Bool with equal(self : Bool, other : Bool) -> Bool = "%bool_eq" + #|#deprecated("Use `compare` instead") + #|#coverage.skip + #|pub fn Bool::op_compare(self : Bool, other : Bool) -> Int = "%bool_compare" + #|pub impl Compare for Bool with compare(self, other) = "%bool_compare" + #|pub impl Default for Bool with default() = "%bool_default" + #|pub impl Neg for Int with neg(self) = "%i32_neg" + #|pub impl Add for Int with add(self, other) = "%i32_add" + #|pub impl Sub for Int with sub(self, other) = "%i32_sub" + #|pub impl Mul for Int with mul(self, other) = "%i32_mul" + #|pub impl Div for Int with div(self, other) = "%i32_div" + #|pub impl Mod for Int with mod(self, other) = "%i32_mod" + #|pub fn Int::lnot(self : Int) -> Int = "%i32_lnot" + #|pub impl BitAnd for Int with land(self : Int, other : Int) -> Int = "%i32_land" + #|pub impl BitOr for Int with lor(self : Int, other : Int) -> Int = "%i32_lor" + #|pub impl BitXOr for Int with lxor(self : Int, other : Int) -> Int = "%i32_lxor" + #|pub impl Shl for Int with shl(self, other) = "%i32_shl" + #|pub impl Shr for Int with shr(self, other) = "%i32_shr" + #|#deprecated("Use infix operator `<<` instead") + #|#coverage.skip + #|pub fn Int::lsl(self : Int, other : Int) -> Int = "%i32_shl" + #|#deprecated("Use infix operator `<<` instead") + #|#coverage.skip + #|pub fn Int::shl(self : Int, other : Int) -> Int = "%i32_shl" + #|#deprecated("Use UInt type and infix operator `>>` instead") + #|#coverage.skip + #|pub fn Int::lsr(self : Int, other : Int) -> Int { + #| (self.reinterpret_as_uint() >> other).reinterpret_as_int() + #|} + #|#deprecated("Use infix operator `>>` instead") + #|#coverage.skip + #|pub fn Int::asr(self : Int, other : Int) -> Int = "%i32_shr" + #|#deprecated("Use infix operator `>>` instead") + #|#coverage.skip + #|pub fn Int::shr(self : Int, other : Int) -> Int = "%i32_shr" + #|pub fn Int::ctz(self : Int) -> Int = "%i32_ctz" + #|pub fn Int::clz(self : Int) -> Int = "%i32_clz" + #|pub fn Int::popcnt(self : Int) -> Int = "%i32_popcnt" + #|pub impl Eq for Int with equal(self : Int, other : Int) -> Bool = "%i32_eq" + #|pub impl Eq for Int with not_equal(self : Int, other : Int) -> Bool = "%i32_ne" + #|pub impl Compare for Int with compare(self, other) = "%i32_compare" + #|pub impl Compare for Int with op_lt(x, y) = "%i32.lt" + #|pub impl Compare for Int with op_le(x, y) = "%i32.le" + #|pub impl Compare for Int with op_gt(x, y) = "%i32.gt" + #|pub impl Compare for Int with op_ge(x, y) = "%i32.ge" + #|pub fn Int::is_pos(self : Int) -> Bool = "%i32_is_pos" + #|pub fn Int::is_neg(self : Int) -> Bool = "%i32_is_neg" + #|pub fn Int::is_non_pos(self : Int) -> Bool = "%i32_is_non_pos" + #|pub fn Int::is_non_neg(self : Int) -> Bool = "%i32_is_non_neg" + #|pub impl Default for Int with default() = "%i32_default" + #|pub fn Int::to_double(self : Int) -> Double = "%i32_to_f64" + #|pub fn UInt::trunc_double(val : Double) -> UInt = "%f64.to_u32" + #|pub fn Int::reinterpret_as_uint(self : Int) -> UInt = "%i32.to_u32_reinterpret" + #|#deprecated("Use `reinterpret_as_uint` instead") + #|#coverage.skip + #|pub fn Int::to_uint(self : Int) -> UInt = "%i32.to_u32_reinterpret" + #|pub fn Int::to_uint64(self : Int) -> UInt64 { + #| self.to_int64().reinterpret_as_uint64() + #|} + #|pub impl Neg for Double with neg(self) = "%f64_neg" + #|pub impl Add for Double with add(self, other) = "%f64_add" + #|pub impl Sub for Double with sub(self, other) = "%f64_sub" + #|pub impl Mul for Double with mul(self, other) = "%f64_mul" + #|pub impl Div for Double with div(self, other) = "%f64_div" + #|pub fn Double::sqrt(self : Double) -> Double = "%f64_sqrt" + #|pub impl Eq for Double with equal(self : Double, other : Double) -> Bool = "%f64_eq" + #|pub impl Eq for Double with not_equal(self : Double, other : Double) -> Bool = "%f64_ne" + #|#deprecated("Use `a != b` instead") + #|#doc(hidden) + #|pub fn Double::op_neq(self : Double, other : Double) -> Bool = "%f64_ne" + #|pub impl Compare for Double with compare(self, other) = "%f64_compare" + #|pub impl Compare for Double with op_lt(x, y) = "%f64.lt" + #|pub impl Compare for Double with op_le(x, y) = "%f64.le" + #|pub impl Compare for Double with op_gt(x, y) = "%f64.gt" + #|pub impl Compare for Double with op_ge(x, y) = "%f64.ge" + #|pub impl Default for Double with default() = "%f64_default" + #|pub fn Double::convert_uint(val : UInt) -> Double = "%u32.to_f64" + #|pub fn Char::to_int(self : Char) -> Int = "%char_to_int" + #|pub fn Char::to_uint(self : Char) -> UInt { + #| self.to_int().reinterpret_as_uint() + #|} + #|#deprecated("Use `Int::unsafe_to_char` instead, and use `Int::to_char` for safe conversion") + #|pub fn Char::from_int(val : Int) -> Char = "%char_from_int" + #|pub impl Eq for Char with equal(self : Char, other : Char) -> Bool = "%char_eq" + #|pub impl Eq for Char with not_equal(self : Char, other : Char) -> Bool = "%i32_ne" + #|pub impl Compare for Char with compare(self, other) = "%char_compare" + #|pub impl Compare for Char with op_lt(x, y) = "%i32.lt" + #|pub impl Compare for Char with op_le(x, y) = "%i32.le" + #|pub impl Compare for Char with op_gt(x, y) = "%i32.gt" + #|pub impl Compare for Char with op_ge(x, y) = "%i32.ge" + #|pub impl Default for Char with default() = "%char_default" + #|#alias("_[_]") + #|pub fn Bytes::at(self : Bytes, idx : Int) -> Byte = "%bytes_get" + #|#internal(unsafe, "Panic if index is out of bounds") + #|#doc(hidden) + #|pub fn Bytes::unsafe_get(self : Bytes, idx : Int) -> Byte = "%bytes.unsafe_get" + #|pub fn Bytes::length(self : Bytes) -> Int = "%bytes_length" + #|pub fn Bytes::make(len : Int, init : Byte) -> Bytes { + #| if len < 0 { + #| return [] + #| } + #| Bytes::unsafe_make(len, init) + #|} + #|fn Bytes::unsafe_make(len : Int, init : Byte) -> Bytes = "%bytes_make" + #|pub fn Bytes::new(len : Int) -> Bytes { + #| Bytes::make(len, b'\x00') + #|} + #|pub fn Int::to_byte(self : Int) -> Byte = "%i32_to_byte" + #|pub fn Int::unsafe_to_char(self : Int) -> Char = "%char_from_int" + #|pub fn Int::to_char(self : Int) -> Char? { + #| if self is (0..=0xD7FF) || self is (0xE000..=0x10FFFF) { + #| Some(self.unsafe_to_char()) + #| } else { + #| None + #| } + #|} + #|pub fn UInt64::to_byte(self : UInt64) -> Byte { + #| self.to_int().to_byte() + #|} + #|#alias("_[_]") + #|pub fn[T] FixedArray::at(self : FixedArray[T], idx : Int) -> T = "%fixedarray.get" + #|#internal(unsafe, "Panic if index is out of bounds") + #|#doc(hidden) + #|pub fn[T] FixedArray::unsafe_get(self : FixedArray[T], idx : Int) -> T = "%fixedarray.unsafe_get" + #|#internal(unsafe, "Panic if index is out of bounds") + #|#doc(hidden) + #|pub fn[T] FixedArray::unsafe_set( + #| self : FixedArray[T], + #| idx : Int, + #| val : T, + #|) -> Unit = "%fixedarray.unsafe_set" + #|#alias("_[_]=_") + #|pub fn[T] FixedArray::set(self : FixedArray[T], idx : Int, val : T) -> Unit = "%fixedarray.set" + #|pub fn[T] FixedArray::length(self : FixedArray[T]) -> Int = "%fixedarray.length" + #|pub fn[T] FixedArray::make(len : Int, init : T) -> FixedArray[T] = "%fixedarray.make" + #|#alias(charcode_length, deprecated) + #|pub fn String::length(self : String) -> Int = "%string_length" + #|#alias("_[_]") + #|#alias(code_unit_at) + #|pub fn String::at(self : String, idx : Int) -> UInt16 = "%string_get" + #|#internal(unsafe, "Undefined behavior if index is out of bounds.") + #|#doc(hidden) + #|pub fn String::unsafe_get(self : String, idx : Int) -> UInt16 = "%string.unsafe_get" + #|#internal(unsafe, "Panic if index is out of bounds.") + #|#doc(hidden) + #|#deprecated("Use `String::unsafe_get` instead") + #|pub fn String::unsafe_charcode_at(self : String, idx : Int) -> Int = "%string.unsafe_get" + #|pub impl Add for String with add(self, other) = "%string_add" + #|pub impl Eq for String with equal(self : String, other : String) -> Bool = "%string_eq" + #|pub fn String::to_string(self : String) -> String = "%string_to_string" + #|priv type UnsafeMaybeUninit[_] + #|pub fn Byte::to_int(self : Byte) -> Int = "%byte_to_int" + #|pub fn Byte::to_char(self : Byte) -> Char { + #| self.to_int().unsafe_to_char() + #|} + #|pub fn Byte::to_int64(self : Byte) -> Int64 { + #| self.to_int().to_int64() + #|} + #|pub fn UInt::reinterpret_as_int(self : UInt) -> Int = "%u32.to_i32_reinterpret" + #|#deprecated("Use `reinterpret_as_int` instead") + #|#coverage.skip + #|pub fn UInt::to_int(self : UInt) -> Int = "%u32.to_i32_reinterpret" + #|pub impl Add for UInt with add(self, other) = "%u32.add" + #|pub impl Sub for UInt with sub(self, other) = "%u32.sub" + #|pub impl Mul for UInt with mul(self, other) = "%u32.mul" + #|pub impl Div for UInt with div(self, other) = "%u32.div" + #|pub impl Mod for UInt with mod(self, other) = "%u32.mod" + #|pub impl Eq for UInt with equal(self : UInt, other : UInt) -> Bool = "%u32.eq" + #|pub impl Eq for UInt with not_equal(self : UInt, other : UInt) -> Bool = "%u32.ne" + #|#deprecated("Use `a != b` instead") + #|#doc(hidden) + #|pub fn UInt::op_neq(self : UInt, other : UInt) -> Bool = "%u32.ne" + #|pub impl Compare for UInt with compare(self, other) = "%u32.compare" + #|pub impl Compare for UInt with op_lt(x, y) = "%u32.lt" + #|pub impl Compare for UInt with op_le(x, y) = "%u32.le" + #|pub impl Compare for UInt with op_gt(x, y) = "%u32.gt" + #|pub impl Compare for UInt with op_ge(x, y) = "%u32.ge" + #|pub impl BitAnd for UInt with land(self : UInt, other : UInt) -> UInt = "%u32.bitand" + #|pub impl BitOr for UInt with lor(self : UInt, other : UInt) -> UInt = "%u32.bitor" + #|pub impl BitXOr for UInt with lxor(self : UInt, other : UInt) -> UInt = "%u32.bitxor" + #|pub fn UInt::lnot(self : UInt) -> UInt = "%u32.bitnot" + #|#deprecated("Use infix operator `<<` instead") + #|#coverage.skip + #|pub fn UInt::lsl(self : UInt, shift : Int) -> UInt = "%u32.shl" + #|#deprecated("Use infix operator `<<` instead") + #|#coverage.skip + #|pub fn UInt::shl(self : UInt, shift : Int) -> UInt = "%u32.shl" + #|#deprecated("Use infix operator `>>` instead") + #|#coverage.skip + #|pub fn UInt::lsr(self : UInt, shift : Int) -> UInt = "%u32.shr" + #|#deprecated("Use infix operator `>>` instead") + #|#coverage.skip + #|pub fn UInt::shr(self : UInt, shift : Int) -> UInt = "%u32.shr" + #|pub impl Shl for UInt with shl(self, shift) = "%u32.shl" + #|pub impl Shr for UInt with shr(self, shift) = "%u32.shr" + #|pub fn UInt::clz(self : UInt) -> Int = "%u32.clz" + #|pub fn UInt::ctz(self : UInt) -> Int = "%u32.ctz" + #|pub fn UInt::popcnt(self : UInt) -> Int = "%u32.popcnt" + #|pub fn UInt::to_uint64(self : UInt) -> UInt64 { + #| UInt64::extend_uint(self) + #|} + #|pub fn UInt::to_byte(self : UInt) -> Byte { + #| self.reinterpret_as_int().to_byte() + #|} + #|pub fn UInt::to_double(self : UInt) -> Double = "%u32.to_f64" + #|#deprecated("Use `Float::from_int` instead") + #|pub fn Int::to_float(self : Int) -> Float = "%i32.to_f32" + #|#deprecated("Use `Float::reinterpret_from_int` instead") + #|pub fn Int::reinterpret_as_float(self : Int) -> Float = "%i32.to_f32_reinterpret" + #|#deprecated("Use `Float::reinterpret_from_uint` instead") + #|pub fn UInt::reinterpret_as_float(self : UInt) -> Float = "%i32.to_f32_reinterpret" + #|#deprecated("Use `Float::from_byte` instead") + #|pub fn Byte::to_float(self : Byte) -> Float = "%byte.to_f32" + #|pub fn Byte::to_double(self : Byte) -> Double { + #| self.to_int().to_double() + #|} + #|#deprecated("Use `Float::from_double` instead", skip_current_package=true) + #|pub fn Double::to_float(self : Double) -> Float = "%f64.to_f32" + #|#deprecated("Use `Float::from_uint` instead") + #|pub fn UInt::to_float(self : UInt) -> Float = "%u32.to_f32" + #|#deprecated("Use `Int16::from_int` instead") + #|pub fn Int::to_int16(self : Int) -> Int16 = "%i32_to_i16" + #|#deprecated("Use `Int16::from_byte` instead") + #|pub fn Byte::to_int16(self : Byte) -> Int16 = "%byte_to_i16" + #|pub fn UInt16::to_int(self : UInt16) -> Int = "%u16_to_i32" + #|pub fn UInt16::to_byte(self : UInt16) -> Byte = "%u16_to_byte" + #|pub fn UInt::to_uint16(self : UInt) -> UInt16 { + #| self.reinterpret_as_int().to_uint16() + #|} + #|pub fn Int::to_uint16(self : Int) -> UInt16 = "%i32_to_u16" + #|pub fn Byte::to_uint16(self : Byte) -> UInt16 = "%byte_to_u16" + ), + "iter.mbt": ( + #|#deprecated(skip_current_package=true) + #|pub(all) enum IterResult { + #| IterEnd // false + #| IterContinue // true + #|} derive(Eq) + #|pub fn Int::until( + #| self : Int, + #| end : Int, + #| step? : Int = 1, + #| inclusive? : Bool = false, + #|) -> Iter[Int] { + #| if step == 0 { + #| return Iter::empty() + #| } + #| let mut i = self + #| let mut done = false + #| () => { + #| guard !done else { None } + #| guard (step > 0 && i < end) || + #| (step < 0 && i > end) || + #| (inclusive && i == end) else { + #| None + #| } + #| let value = i + #| let next = i + step + #| if (step > 0 && next >= i) || (step < 0 && next <= i) { + #| i = next + #| } else { + #| done = true + #| } + #| Some(value) + #| } + #|} + #|pub fn Int64::until( + #| self : Int64, + #| end : Int64, + #| step? : Int64 = 1L, + #| inclusive? : Bool = false, + #|) -> Iter[Int64] { + #| if step == 0 { + #| return Iter::empty() + #| } + #| let mut i = self + #| let mut done = false + #| () => { + #| guard !done else { None } + #| guard (step > 0 && i < end) || + #| (step < 0 && i > end) || + #| (inclusive && i == end) else { + #| None + #| } + #| let value = i + #| let next = i + step + #| if (step > 0 && next >= i) || (step < 0 && next <= i) { + #| i = next + #| } else { + #| done = true + #| } + #| Some(value) + #| } + #|} + #|pub fn Double::until( + #| self : Double, + #| end : Double, + #| step? : Double = 1.0, + #| inclusive? : Bool = false, + #|) -> Iter[Double] { + #| if step == 0.0 { + #| return Iter::empty() + #| } + #| let mut i = self + #| let mut done = false + #| () => { + #| guard !done else { None } + #| guard (step > 0.0 && i < end) || + #| (step < 0.0 && i > end) || + #| (inclusive && i == end) else { + #| None + #| } + #| let value = i + #| let next = i + step + #| if (step > 0.0 && next >= i) || (step < 0.0 && next <= i) { + #| i = next + #| } else { + #| done = true + #| } + #| Some(value) + #| } + #|} + ), + "iterator.mbt": ( + #|#alias(Iterator, deprecated="The name `Iterator` is deprecated, use `Iter` instead. Note that if you have defined `iterator()` method to support `for .. in` loop, you should also rename `iterator()` to `iter()`. See https://github.com/moonbitlang/core/pull/3127 for more details.") + #|struct Iter[X](() -> X?) + #|#alias(peek, deprecated) + #|#alias(head) + #|pub fn[X] Iter::next(self : Iter[X]) -> X? { + #| (self.0)() + #|} + #|#locals(f) + #|#deprecated("write a loop instead.") + #|pub fn[X] Iter::run(self : Iter[X], f : (X) -> IterResult) -> IterResult { + #| while self.next() is Some(x) { + #| guard f(x) is IterContinue else { break IterEnd } + #| } nobreak { + #| IterContinue + #| } + #|} + #|#deprecated("write a loop instead.") + #|pub fn[X] Iter::just_run(self : Iter[X], f : (X) -> IterResult) -> Unit { + #| while self.next() is Some(x) { + #| if f(x) is IterEnd { + #| break + #| } + #| } + #|} + #|pub impl[X : Show] Show for Iter[X] with output(self, logger) { + #| logger.write_string("[") + #| if self.next() is Some(x) { + #| logger.write_object(x) + #| while self.next() is Some(x) { + #| logger.write_string(", ") + #| logger.write_object(x) + #| } + #| } + #| logger.write_string("]") + #|} + #|pub impl[X : ToJson] ToJson for Iter[X] with to_json(self) { + #| Json::array(self.map(x => x.to_json()).collect()) + #|} + #|#locals(f) + #|pub fn[X] Iter::each(self : Iter[X], f : (X) -> Unit raise?) -> Unit raise? { + #| while self.next() is Some(x) { + #| f(x) + #| } + #|} + #|#locals(f) + #|pub fn[X] Iter::any(self : Iter[X], f : (X) -> Bool) -> Bool { + #| while self.next() is Some(x) { + #| if f(x) { + #| break true + #| } + #| } nobreak { + #| false + #| } + #|} + #|#locals(f) + #|pub fn[X] Iter::all(self : Iter[X], f : (X) -> Bool) -> Bool { + #| while self.next() is Some(x) { + #| guard f(x) else { break false } + #| } nobreak { + #| true + #| } + #|} + #|#locals(f) + #|pub fn[X] Iter::eachi( + #| self : Iter[X], + #| f : (Int, X) -> Unit raise?, + #|) -> Unit raise? { + #| let mut i = 0 + #| while self.next() is Some(x) { + #| f(i, x) + #| i += 1 + #| } + #|} + #|#locals(f) + #|pub fn[X, R] Iter::fold( + #| self : Iter[X], + #| init~ : R, + #| f : (R, X) -> R raise?, + #|) -> R raise? { + #| let mut acc = init + #| while self.next() is Some(x) { + #| acc = f(acc, x) + #| } + #| acc + #|} + #|pub fn[X] Iter::count(self : Iter[X]) -> Int { + #| self.fold((acc, _) => acc + 1, init=0) + #|} + #|pub fn[X] Iter::new(f : () -> X?) -> Iter[X] { + #| Iter(f) + #|} + #|pub fn[X] Iter::empty() -> Iter[X] { + #| () => None + #|} + #|pub fn[X] Iter::singleton(elem : X) -> Iter[X] { + #| let mut consumed = false + #| fn() { + #| if consumed { + #| None + #| } else { + #| consumed = true + #| Some(elem) + #| } + #| } + #|} + #|pub fn[X] Iter::repeat(x : X) -> Iter[X] { + #| () => Some(x) + #|} + #|pub fn[X] Iter::filter(self : Iter[X], f : (X) -> Bool) -> Iter[X] { + #| fn() { + #| while self.next() is Some(x) { + #| if f(x) { + #| break Some(x) + #| } + #| } nobreak { + #| None + #| } + #| } + #|} + #|pub fn[X, Y] Iter::map(self : Iter[X], f : (X) -> Y) -> Iter[Y] { + #| fn() { + #| match self.next() { + #| Some(x) => Some(f(x)) + #| None => None + #| } + #| } + #|} + #|pub fn[X, Y] Iter::mapi(self : Iter[X], f : (Int, X) -> Y) -> Iter[Y] { + #| let mut i = 0 + #| fn() { + #| match self.next() { + #| Some(x) => { + #| let result = f(i, x) + #| i += 1 + #| Some(result) + #| } + #| None => None + #| } + #| } + #|} + #|pub fn[X, Y] Iter::filter_map(self : Iter[X], f : (X) -> Y?) -> Iter[Y] { + #| fn() { + #| while self.next() is Some(x) { + #| match f(x) { + #| Some(_) as y => break y + #| None => () + #| } + #| } nobreak { + #| None + #| } + #| } + #|} + #|pub fn[X, Y] Iter::flat_map(self : Iter[X], f : (X) -> Iter[Y]) -> Iter[Y] { + #| let mut current_iter = Some(Iter::empty()) + #| fn() { + #| guard current_iter is Some(iter) else { None } + #| loop iter.next() { + #| Some(_) as elem => elem + #| None => { + #| guard self.next() is Some(x) else { None } + #| let iter = f(x) + #| current_iter = Some(iter) + #| continue iter.next() + #| } + #| } + #| } + #|} + #|pub fn[X] Iter::flatten(self : Iter[Iter[X]]) -> Iter[X] { + #| self.flat_map(it => it) + #|} + #|pub fn Iter::join(self : Iter[String], sep : String) -> String { + #| let result = StringBuilder::new() + #| if self.next() is Some(x) { + #| result.write_string(x) + #| while self.next() is Some(x) { + #| result.write_string(sep) + #| result.write_string(x) + #| } + #| } + #| result.to_string() + #|} + #|pub fn[X] Iter::tap(self : Iter[X], f : (X) -> Unit) -> Iter[X] { + #| fn() { + #| let result = self.next() + #| if result is Some(x) { + #| f(x) + #| } + #| result + #| } + #|} + #|pub fn[X] Iter::take(self : Iter[X], n : Int) -> Iter[X] { + #| let mut remaining = n + #| fn() { + #| guard remaining > 0 else { None } + #| let result = self.next() + #| if result is Some(_) { + #| remaining -= 1 + #| } + #| result + #| } + #|} + #|pub fn[X] Iter::take_while(self : Iter[X], f : (X) -> Bool) -> Iter[X] { + #| let mut still_running = true + #| fn() { + #| guard still_running else { None } + #| let result = self.next() + #| if result is Some(x) && !f(x) { + #| still_running = false + #| None + #| } else { + #| result + #| } + #| } + #|} + #|pub fn[X, Y] Iter::map_while(self : Iter[X], f : (X) -> Y?) -> Iter[Y] { + #| let mut still_running = true + #| fn() { + #| guard still_running else { None } + #| let src = self.next() + #| guard src is Some(x) else { None } + #| let result = f(x) + #| if result is None { + #| still_running = false + #| } + #| result + #| } + #|} + #|pub fn[X] Iter::drop(self : Iter[X], n : Int) -> Iter[X] { + #| let mut remaining = n + #| fn() { + #| while remaining > 0 { + #| guard self.next() is Some(_) else { break None } + #| remaining -= 1 + #| } nobreak { + #| self.next() + #| } + #| } + #|} + #|pub fn[X] Iter::drop_while(self : Iter[X], f : (X) -> Bool) -> Iter[X] { + #| let mut dropped = false + #| fn() { + #| if !dropped { + #| dropped = true + #| loop self.next() { + #| Some(x) if f(x) => continue self.next() + #| result => result + #| } + #| } else { + #| self.next() + #| } + #| } + #|} + #|pub fn[X] Iter::find_first(self : Iter[X], f : (X) -> Bool) -> X? { + #| while self.next() is Some(x) { + #| if f(x) { + #| break Some(x) + #| } + #| } nobreak { + #| None + #| } + #|} + #|pub fn[X] Iter::concat(self : Iter[X], other : Iter[X]) -> Iter[X] { + #| let mut in_first = true + #| fn() { + #| if in_first { + #| let result = self.next() + #| if result is None { + #| in_first = false + #| other.next() + #| } else { + #| result + #| } + #| } else { + #| other.next() + #| } + #| } + #|} + #|#alias(combine) + #|pub fn[X, Y] Iter::zip(self : Iter[X], other : Iter[Y]) -> Iter[(X, Y)] { + #| fn() { + #| guard self.next() is Some(x) else { None } + #| guard other.next() is Some(y) else { None } + #| Some((x, y)) + #| } + #|} + #|pub impl[T] Add for Iter[T] with add(self, other) { + #| self.concat(other) + #|} + #|#alias(collect) + #|pub fn[X] Iter::to_array(self : Iter[X]) -> Array[X] { + #| let result = [] + #| while self.next() is Some(x) { + #| result.push(x) + #| } + #| result + #|} + #|#alias(iterator) + #|pub fn[X] Iter::iter(self : Iter[X]) -> Iter[X] { + #| self + #|} + #|#alias(iterator2) + #|pub fn[X] Iter::iter2(self : Iter[X]) -> Iter2[Int, X] { + #| let mut i = 0 + #| Iter(() => { + #| guard self.next() is Some(elem) else { None } + #| let result = Some((i, elem)) + #| i += 1 + #| result + #| }) + #|} + #|pub fn[X] Iter::last(self : Iter[X]) -> X? { + #| loop (None, self.next()) { + #| (last, None) => last + #| (_, Some(_) as x) => continue (x, self.next()) + #| } + #|} + #|pub fn[X] Iter::intersperse(self : Iter[X], sep : X) -> Iter[X] { + #| enum State { + #| Init + #| Output_Elem(X) + #| Output_Sep + #| } + #| let mut state = Init + #| fn() { + #| match state { + #| Init => { + #| let result = self.next() + #| state = Output_Sep + #| result + #| } + #| Output_Elem(x) => { + #| state = Output_Sep + #| Some(x) + #| } + #| Output_Sep => + #| match self.next() { + #| Some(x) => { + #| state = Output_Elem(x) + #| Some(sep) + #| } + #| None => None + #| } + #| } + #| } + #|} + #|#alias("_[_:_]") + #|#alias(sub, deprecated="Use _[_:_] instead") + #|pub fn[X] Iter::view(self : Iter[X], start? : Int = 0, end? : Int) -> Iter[X] { + #| match (start, end) { + #| (_..=0, None) => self + #| (_..=0, Some(end)) => self.take(end) + #| (start, None) => self.drop(start) + #| (start, Some(end)) => { + #| let mut index = 0 + #| fn() { + #| if index >= end { + #| return None + #| } + #| while index < start { + #| guard self.next() is Some(_) else { return None } + #| index += 1 + #| } + #| if index >= end { + #| return None + #| } + #| let result = self.next() + #| if result is Some(_) { + #| index += 1 + #| } + #| result + #| } + #| } + #| } + #|} + #|pub fn[X : Eq] Iter::contains(self : Iter[X], value : X) -> Bool { + #| while self.next() is Some(x) { + #| if x == value { + #| break true + #| } + #| } nobreak { + #| false + #| } + #|} + #|pub fn[X] Iter::nth(self : Iter[X], n : Int) -> X? { + #| guard n >= 0 else { None } + #| for _ in 0.. X? { + #| guard self.next() is Some(x) else { return None } + #| let mut res = x + #| while self.next() is Some(x) { + #| if x > res { + #| res = x + #| } + #| } + #| Some(res) + #|} + #|pub fn[X : Compare] Iter::minimum(self : Iter[X]) -> X? { + #| guard self.next() is Some(x) else { return None } + #| let mut res = x + #| while self.next() is Some(x) { + #| if x < res { + #| res = x + #| } + #| } + #| Some(res) + #|} + #|#alias(Iterator2, deprecated="The name `Iterator2` is deprecated, use `Iter2` instead. Note that if you have defined `iterator2()` method to support `for .. in` loop, you should also rename `iterator2()` to `iter2()`. See https://github.com/moonbitlang/core/pull/3127 for more details.") + #|pub(all) struct Iter2[X, Y](Iter[(X, Y)]) + #|pub fn[X, Y] Iter2::new(f : () -> (X, Y)?) -> Iter2[X, Y] { + #| Iter2(Iter::new(f)) + #|} + #|#alias(iterator) + #|pub fn[X, Y] Iter2::iter(self : Iter2[X, Y]) -> Iter[(X, Y)] { + #| self.0 + #|} + #|#alias(iterator2) + #|pub fn[X, Y] Iter2::iter2(self : Iter2[X, Y]) -> Iter2[X, Y] { + #| self + #|} + #|pub fn[X, Y] Iter2::next(self : Iter2[X, Y]) -> (X, Y)? { + #| self.0.next() + #|} + #|pub impl[X : Show, Y : Show] Show for Iter2[X, Y] with output(self, logger) { + #| self.0.output(logger) + #|} + #|#deprecated("write a loop instead.") + #|pub fn[X, Y] Iter2::run( + #| self : Iter2[X, Y], + #| f : (X, Y) -> IterResult, + #|) -> IterResult { + #| while self.0.next() is Some((x, y)) { + #| guard f(x, y) is IterContinue else { break IterEnd } + #| } nobreak { + #| IterContinue + #| } + #|} + #|pub fn[X, Y] Iter2::each(self : Iter2[X, Y], f : (X, Y) -> Unit) -> Unit { + #| self.0.each(pair => f(pair.0, pair.1)) + #|} + #|pub fn[X, Y] Iter2::concat( + #| self : Iter2[X, Y], + #| other : Iter2[X, Y], + #|) -> Iter2[X, Y] { + #| Iter2(self.0.concat(other.0)) + #|} + #|pub fn[X, Y] Iter2::to_array(self : Iter2[X, Y]) -> Array[(X, Y)] { + #| self.0.to_array() + #|} + ), + "json.mbt": ( + #|pub enum Json { + #| Null + #| True + #| False + #| Number(Double, repr~ : String?) // 1.0000000000000000000e100 + #| String(String) + #| Array(Array[Json]) + #| Object(Map[String, Json]) + #|} + #|pub impl Eq for Json with equal(a, b) { + #| match (a, b) { + #| (Null, Null) => true + #| (True, True) => true + #| (False, False) => true + #| (Number(a_num, ..), Number(b_num, ..)) => a_num == b_num + #| (String(a_str), String(b_str)) => a_str == b_str + #| (Array(a_arr), Array(b_arr)) => a_arr == b_arr + #| (Object(a_obj), Object(b_obj)) => a_obj == b_obj + #| _ => false + #| } + #|} + #|pub fn Json::null() -> Json { + #| return Null + #|} + #|pub let null : Json = Null + #|pub fn Json::number(number : Double, repr? : String) -> Json { + #| return Number(number, repr~) + #|} + #|pub fn Json::string(string : String) -> Json { + #| return String(string) + #|} + #|pub fn Json::boolean(boolean : Bool) -> Json { + #| if boolean { + #| True + #| } else { + #| False + #| } + #|} + #|pub fn Json::array(array : Array[Json]) -> Json { + #| return Array(array) + #|} + #|pub fn Json::object(object : Map[String, Json]) -> Json { + #| return Object(object) + #|} + #|pub(open) trait ToJson { + #| to_json(Self) -> Json + #|} + #|pub impl ToJson for Bool with to_json(self : Bool) -> Json { + #| if self { + #| true + #| } else { + #| false + #| } + #|} + #|pub impl ToJson for Byte with to_json(self : Byte) -> Json { + #| Json::number(self.to_double()) + #|} + #|pub impl ToJson for Int with to_json(self : Int) -> Json { + #| Json::number(self.to_double()) + #|} + #|pub impl ToJson for Int64 with to_json(self : Int64) -> Json { + #| String::to_json(self.to_string()) + #|} + #|pub impl ToJson for UInt with to_json(self : UInt) -> Json { + #| Json::number(self.to_uint64().to_double()) + #|} + #|pub impl ToJson for UInt64 with to_json(self : UInt64) -> Json { + #| String::to_json(self.to_string()) + #|} + #|pub impl ToJson for Double with to_json(self : Double) -> Json { + #| if self != self { + #| Json::string("NaN") + #| } else if self > 0x7FEFFFFFFFFFFFFFL.reinterpret_as_double() { + #| Json::string("Infinity") + #| } else if self < 0xFFEFFFFFFFFFFFFFL.reinterpret_as_double() { + #| Json::string("-Infinity") + #| } else { + #| Json::number(self) + #| } + #|} + #|pub impl ToJson for String with to_json(self : String) -> Json { + #| String(self) + #|} + #|pub impl[X : ToJson] ToJson for Array[X] with to_json(self) { + #| Array(self.map(x => x.to_json())) + #|} + #|pub impl[X : ToJson] ToJson for FixedArray[X] with to_json(self) { + #| let len = self.length() + #| if len == 0 { + #| return [] + #| } + #| let res = Array::make_uninit(self.length()) + #| for i, x in self { + #| res.unsafe_set(i, ToJson::to_json(x)) + #| } + #| Array(res) + #|} + #|pub impl[X : ToJson] ToJson for ArrayView[X] with to_json(self) { + #| let len = self.length() + #| if len == 0 { + #| return [] + #| } + #| let res = Array::make_uninit(self.length()) + #| for i, x in self { + #| res.unsafe_set(i, ToJson::to_json(x)) + #| } + #| Array(res) + #|} + #|pub impl[K : Show, V : ToJson] ToJson for Map[K, V] with to_json(self) { + #| let object = Map::new(capacity=self.capacity) + #| for k, v in self { + #| object[k.to_string()] = v.to_json() + #| } + #| Object(object) + #|} + #|pub impl[T : ToJson] ToJson for T? with to_json(self) { + #| match self { + #| None => Null + #| Some(value) => [value] + #| } + #|} + #|pub impl[Ok : ToJson, Err : ToJson] ToJson for Result[Ok, Err] with to_json( + #| self : Result[Ok, Err], + #|) -> Json { + #| match self { + #| Ok(ok) => { "Ok": ok } + #| Err(err) => { "Err": err } + #| } + #|} + #|pub impl ToJson for Unit with to_json(_self) { + #| Null + #|} + #|pub impl Default for Json with default() { + #| false + #|} + ), + "linked_hash_map.mbt": ( + #|priv struct Entry[K, V] { + #| mut prev : Int + #| mut next : Entry[K, V]? + #| mut psl : Int + #| hash : Int + #| key : K + #| mut value : V + #|} derive(Show) + #|struct Map[K, V] { + #| mut entries : FixedArray[Entry[K, V]?] + #| mut size : Int // active key-value pairs count + #| mut capacity : Int // current capacity + #| mut capacity_mask : Int // capacity_mask = capacity - 1, used to find idx + #| mut grow_at : Int // threshold that triggers grow + #| mut head : Entry[K, V]? // head of linked list + #| mut tail : Int // tail of linked list + #|} + #|pub fn[K, V] Map::new(capacity? : Int = 8) -> Map[K, V] { + #| let capacity = capacity.next_power_of_two() + #| { + #| size: 0, + #| capacity, + #| capacity_mask: capacity - 1, + #| grow_at: calc_grow_threshold(capacity), + #| entries: FixedArray::make(capacity, None), + #| head: None, + #| tail: -1, + #| } + #|} + #|pub fn[K : Hash + Eq, V] Map::from_array(arr : ArrayView[(K, V)]) -> Map[K, V] { + #| let length = arr.length() + #| let mut capacity = length.next_power_of_two() + #| if length > calc_grow_threshold(capacity) { + #| capacity *= 2 + #| } + #| let m = Map::new(capacity~) + #| for e in arr { + #| m.set(e.0, e.1) + #| } + #| m + #|} + #|#alias("_[_]=_") + #|pub fn[K : Hash + Eq, V] Map::set(self : Map[K, V], key : K, value : V) -> Unit { + #| self.set_with_hash(key, value, key.hash()) + #|} + #|fn[K : Eq, V] Map::set_with_hash( + #| self : Map[K, V], + #| key : K, + #| value : V, + #| hash : Int, + #|) -> Unit { + #| for psl = 0, idx = hash & self.capacity_mask { + #| match self.entries[idx] { + #| None => { + #| if self.size >= self.grow_at { + #| self.grow() + #| continue 0, hash & self.capacity_mask + #| } + #| let entry = { prev: self.tail, next: None, psl, key, value, hash } + #| self.add_entry_to_tail(idx, entry) + #| return + #| } + #| Some(curr_entry) => { + #| if curr_entry.hash == hash && curr_entry.key == key { + #| curr_entry.value = value + #| return + #| } + #| if psl > curr_entry.psl { + #| if self.size >= self.grow_at { + #| self.grow() + #| continue 0, hash & self.capacity_mask + #| } + #| self.push_away(idx, curr_entry) + #| let entry = { prev: self.tail, next: None, psl, key, value, hash } + #| self.add_entry_to_tail(idx, entry) + #| return + #| } + #| continue psl + 1, (idx + 1) & self.capacity_mask + #| } + #| } + #| } + #|} + #|fn[K, V] Map::push_away( + #| self : Map[K, V], + #| idx : Int, + #| entry : Entry[K, V], + #|) -> Unit { + #| for psl = entry.psl + 1, idx = (idx + 1) & self.capacity_mask, entry = entry { + #| match self.entries[idx] { + #| None => { + #| entry.psl = psl + #| self.set_entry(entry, idx) + #| break + #| } + #| Some(curr_entry) => + #| if psl > curr_entry.psl { + #| entry.psl = psl + #| self.set_entry(entry, idx) + #| continue curr_entry.psl + 1, + #| (idx + 1) & self.capacity_mask, + #| curr_entry + #| } else { + #| continue psl + 1, (idx + 1) & self.capacity_mask, entry + #| } + #| } + #| } + #|} + #|fn[K, V] Map::set_entry( + #| self : Map[K, V], + #| entry : Entry[K, V], + #| new_idx : Int, + #|) -> Unit { + #| self.entries[new_idx] = Some(entry) + #| match entry.next { + #| None => self.tail = new_idx + #| Some(next) => next.prev = new_idx + #| } + #|} + #|pub fn[K : Hash + Eq, V] Map::get(self : Map[K, V], key : K) -> V? { + #| let hash = key.hash() + #| for i = 0, idx = hash & self.capacity_mask { + #| guard self.entries[idx] is Some(entry) else { break None } + #| if entry.hash == hash && entry.key == key { + #| break Some(entry.value) + #| } + #| if i > entry.psl { + #| break None + #| } + #| continue i + 1, (idx + 1) & self.capacity_mask + #| } + #|} + #|#alias("_[_]") + #|pub fn[K : Hash + Eq, V] Map::at(self : Map[K, V], key : K) -> V { + #| let hash = key.hash() + #| for i = 0, idx = hash & self.capacity_mask { + #| guard self.entries[idx] is Some(entry) + #| if entry.hash == hash && entry.key == key { + #| return entry.value + #| } + #| guard i <= entry.psl + #| continue i + 1, (idx + 1) & self.capacity_mask + #| } + #|} + #|pub fn[K : Hash + Eq, V] Map::get_or_default( + #| self : Map[K, V], + #| key : K, + #| default : V, + #|) -> V { + #| let hash = key.hash() + #| for i = 0, idx = hash & self.capacity_mask { + #| match self.entries[idx] { + #| Some(entry) => { + #| if entry.hash == hash && entry.key == key { + #| break entry.value + #| } + #| if i > entry.psl { + #| break default + #| } + #| continue i + 1, (idx + 1) & self.capacity_mask + #| } + #| None => break default + #| } + #| } + #|} + #|pub fn[K : Hash + Eq, V] Map::get_or_init( + #| self : Map[K, V], + #| key : K, + #| default : () -> V, + #|) -> V { + #| let hash = key.hash() + #| let (idx, psl, new_value, push_away) = for psl = 0, idx = hash & + #| self.capacity_mask { + #| match self.entries[idx] { + #| Some(entry) => { + #| if entry.hash == hash && entry.key == key { + #| return entry.value + #| } + #| if psl > entry.psl { + #| let new_value = default() + #| break (idx, psl, new_value, Some(entry)) + #| } + #| continue psl + 1, (idx + 1) & self.capacity_mask + #| } + #| None => { + #| let new_value = default() + #| break (idx, psl, new_value, None) + #| } + #| } + #| } + #| if self.size >= self.grow_at { + #| self.grow() + #| self.set_with_hash(key, new_value, hash) + #| } else { + #| if push_away is Some(entry) { + #| self.push_away(idx, entry) + #| } + #| let entry = { + #| prev: self.tail, + #| next: None, + #| psl, + #| hash, + #| key, + #| value: new_value, + #| } + #| self.add_entry_to_tail(idx, entry) + #| } + #| new_value + #|} + #|pub fn[K : Hash + Eq, V] Map::contains(self : Map[K, V], key : K) -> Bool { + #| let hash = key.hash() + #| for i = 0, idx = hash & self.capacity_mask { + #| guard self.entries[idx] is Some(entry) else { break false } + #| if entry.hash == hash && entry.key == key { + #| break true + #| } + #| if i > entry.psl { + #| break false + #| } + #| continue i + 1, (idx + 1) & self.capacity_mask + #| } + #|} + #|pub fn[K : Hash + Eq, V : Eq] Map::contains_kv( + #| self : Map[K, V], + #| key : K, + #| value : V, + #|) -> Bool { + #| let hash = key.hash() + #| for i = 0, idx = hash & self.capacity_mask { + #| guard self.entries[idx] is Some(entry) else { break false } + #| if entry.hash == hash && entry.key == key && entry.value == value { + #| break true + #| } + #| if i > entry.psl { + #| break false + #| } + #| continue i + 1, (idx + 1) & self.capacity_mask + #| } + #|} + #|pub fn[K : Hash + Eq, V] Map::remove(self : Map[K, V], key : K) -> Unit { + #| self.remove_with_hash(key, key.hash()) + #|} + #|fn[K : Eq, V] Map::remove_with_hash( + #| self : Map[K, V], + #| key : K, + #| hash : Int, + #|) -> Unit { + #| for i = 0, idx = hash & self.capacity_mask { + #| guard self.entries[idx] is Some(entry) else { break } + #| if entry.hash == hash && entry.key == key { + #| self.remove_entry(entry) + #| self.shift_back(idx) + #| self.size -= 1 + #| break + #| } + #| if i > entry.psl { + #| break + #| } + #| continue i + 1, (idx + 1) & self.capacity_mask + #| } + #|} + #|fn[K, V] Map::add_entry_to_tail( + #| self : Map[K, V], + #| idx : Int, + #| entry : Entry[K, V], + #|) -> Unit { + #| match self.tail { + #| -1 => self.head = Some(entry) + #| tail => self.entries[tail].unwrap().next = Some(entry) + #| } + #| self.tail = idx + #| self.entries[idx] = Some(entry) + #| self.size += 1 + #|} + #|fn[K, V] Map::remove_entry(self : Map[K, V], entry : Entry[K, V]) -> Unit { + #| match entry.prev { + #| -1 => self.head = entry.next + #| idx => self.entries[idx].unwrap().next = entry.next + #| } + #| match entry.next { + #| None => self.tail = entry.prev + #| Some(next) => next.prev = entry.prev + #| } + #|} + #|fn[K, V] Map::shift_back(self : Map[K, V], idx : Int) -> Unit { + #| let next = (idx + 1) & self.capacity_mask + #| match self.entries[next] { + #| None | Some({ psl: 0, .. }) => self.entries[idx] = None + #| Some(entry) => { + #| entry.psl -= 1 + #| self.set_entry(entry, idx) + #| self.shift_back(next) + #| } + #| } + #|} + #|fn[K : Eq, V] Map::grow(self : Map[K, V]) -> Unit { + #| let old_head = self.head + #| let new_capacity = self.capacity << 1 + #| self.entries = FixedArray::make(new_capacity, None) + #| self.capacity = new_capacity + #| self.capacity_mask = new_capacity - 1 + #| self.grow_at = calc_grow_threshold(self.capacity) + #| self.size = 0 + #| self.head = None + #| self.tail = -1 + #| loop old_head { + #| Some({ next, key, value, hash, .. }) => { + #| self.set_with_hash(key, value, hash) + #| continue next + #| } + #| None => break + #| } + #|} + #|fn calc_grow_threshold(capacity : Int) -> Int { + #| capacity * 13 / 16 + #|} + #|pub impl[K : Show, V : Show] Show for Map[K, V] with output(self, logger) { + #| logger.write_string("{") + #| loop (0, self.head) { + #| (_, None) => logger.write_string("}") + #| (i, Some({ key, value, next, .. })) => { + #| if i > 0 { + #| logger.write_string(", ") + #| } + #| logger.write_object(key) + #| logger.write_string(": ") + #| logger.write_object(value) + #| continue (i + 1, next) + #| } + #| } + #|} + #|#alias(size, deprecated) + #|pub fn[K, V] Map::length(self : Map[K, V]) -> Int { + #| self.size + #|} + #|pub fn[K, V] Map::capacity(self : Map[K, V]) -> Int { + #| self.capacity + #|} + #|pub fn[K, V] Map::is_empty(self : Map[K, V]) -> Bool { + #| self.size == 0 + #|} + #|#locals(f) + #|pub fn[K, V] Map::each( + #| self : Map[K, V], + #| f : (K, V) -> Unit raise?, + #|) -> Unit raise? { + #| loop self.head { + #| Some({ key, value, next, .. }) => { + #| f(key, value) + #| continue next + #| } + #| None => break + #| } + #|} + #|#locals(f) + #|pub fn[K, V] Map::eachi( + #| self : Map[K, V], + #| f : (Int, K, V) -> Unit raise?, + #|) -> Unit raise? { + #| loop (0, self.head) { + #| (i, Some({ key, value, next, .. })) => { + #| f(i, key, value) + #| continue (i + 1, next) + #| } + #| (_, None) => break + #| } + #|} + #|pub fn[K, V] Map::clear(self : Map[K, V]) -> Unit { + #| self.entries.fill(None) + #| self.size = 0 + #| self.head = None + #| self.tail = -1 + #|} + #|#alias(iterator, deprecated) + #|pub fn[K, V] Map::iter(self : Map[K, V]) -> Iter[(K, V)] { + #| let mut curr_entry = self.head + #| Iter::new(fn() { + #| match curr_entry { + #| Some({ key, value, next, .. }) => { + #| curr_entry = next + #| Some((key, value)) + #| } + #| None => None + #| } + #| }) + #|} + #|#alias(iterator2, deprecated) + #|pub fn[K, V] Map::iter2(self : Map[K, V]) -> Iter2[K, V] { + #| self.iter() + #|} + #|pub fn[K, V] Map::keys(self : Map[K, V]) -> Iter[K] { + #| let mut curr_entry = self.head + #| Iter::new(fn() { + #| match curr_entry { + #| Some({ key, next, .. }) => { + #| curr_entry = next + #| Some(key) + #| } + #| None => None + #| } + #| }) + #|} + #|pub fn[K, V] Map::values(self : Map[K, V]) -> Iter[V] { + #| let mut curr_entry = self.head + #| Iter::new(fn() { + #| match curr_entry { + #| Some({ value, next, .. }) => { + #| curr_entry = next + #| Some(value) + #| } + #| None => None + #| } + #| }) + #|} + #|pub fn[K, V] Map::to_array(self : Map[K, V]) -> Array[(K, V)] { + #| let arr = Array::make_uninit(self.size) + #| let mut i = 0 + #| loop self.head { + #| Some({ key, value, next, .. }) => { + #| arr.unsafe_set(i, (key, value)) + #| i += 1 + #| continue next + #| } + #| None => break + #| } + #| arr + #|} + #|pub impl[K : Hash + Eq, V : Eq] Eq for Map[K, V] with equal( + #| self : Map[K, V], + #| that : Map[K, V], + #|) -> Bool { + #| guard self.size == that.size else { return false } + #| for k, v in self { + #| guard that.contains_kv(k, v) else { return false } + #| } nobreak { + #| true + #| } + #|} + #|pub fn[K : Hash + Eq, V] Map::of(arr : FixedArray[(K, V)]) -> Map[K, V] { + #| let length = arr.length() + #| let mut capacity = length.next_power_of_two() + #| if length > calc_grow_threshold(capacity) { + #| capacity *= 2 + #| } + #| let m = Map::new(capacity~) + #| for i in 0.. Map[K, V] { + #| let m = {} + #| while iter.next() is Some((k, v)) { + #| m.set(k, v) + #| } + #| m + #|} + #|pub impl[K, V] Default for Map[K, V] with default() { + #| Map::new() + #|} + #|pub fn[K, V, V2] Map::map(self : Map[K, V], f : (K, V) -> V2) -> Map[K, V2] { + #| let other = { + #| capacity: self.capacity, + #| entries: FixedArray::make(self.capacity, None), + #| size: self.size, + #| capacity_mask: self.capacity_mask, + #| grow_at: self.grow_at, + #| head: None, + #| tail: self.tail, + #| } + #| if self.size == 0 { + #| return other + #| } + #| guard self.entries[self.tail] is Some(last) + #| loop (last, self.tail, None) { + #| ({ prev, psl, hash, key, value, .. }, idx, next) => { + #| let new_value = f(key, value) + #| let new_entry = { prev, next, psl, hash, key, value: new_value } + #| other.entries[idx] = Some(new_entry) + #| if prev != -1 { + #| continue (self.entries[prev].unwrap(), prev, Some(new_entry)) + #| } else { + #| other.head = Some(new_entry) + #| } + #| } + #| } + #| other + #|} + #|#alias(clone, deprecated) + #|pub fn[K, V] Map::copy(self : Map[K, V]) -> Map[K, V] { + #| let other = { + #| capacity: self.capacity, + #| entries: FixedArray::make(self.capacity, None), + #| size: self.size, + #| capacity_mask: self.capacity_mask, + #| grow_at: self.grow_at, + #| head: None, + #| tail: self.tail, + #| } + #| if self.size == 0 { + #| return other + #| } + #| guard self.entries[self.tail] is Some(last) + #| loop (last, self.tail, None) { + #| ({ prev, psl, hash, key, value, .. }, idx, next) => { + #| let new_entry = { prev, next, psl, hash, key, value } + #| other.entries[idx] = Some(new_entry) + #| if prev != -1 { + #| continue (self.entries[prev].unwrap(), prev, Some(new_entry)) + #| } else { + #| other.head = Some(new_entry) + #| } + #| } + #| } + #| other + #|} + #|pub fn[K : Eq, V] Map::merge(self : Map[K, V], other : Map[K, V]) -> Map[K, V] { + #| let result = self.copy() + #| result.merge_in_place(other) + #| result + #|} + #|pub fn[K : Eq, V] Map::merge_in_place( + #| self : Map[K, V], + #| other : Map[K, V], + #|) -> Unit { + #| if physical_equal(self, other) { + #| return + #| } + #| loop other.head { + #| Some({ key, value, next, hash, .. }) => { + #| self.set_with_hash(key, value, hash) + #| continue next + #| } + #| None => break + #| } + #|} + #|#locals(f) + #|pub fn[K, V] Map::retain(self : Map[K, V], f : (K, V) -> Bool) -> Unit { + #| loop (self.head, false) { + #| (Some({ key, value, next, prev: idx, .. }), remove_prev) => { + #| if remove_prev { + #| guard self.entries[idx] is Some(entry) + #| self.remove_entry(entry) + #| self.shift_back(idx) + #| self.size -= 1 + #| } + #| continue (next, !f(key, value)) + #| } + #| (None, remove_prev) => + #| if remove_prev { + #| let idx = self.tail + #| guard self.entries[idx] is Some(entry) + #| self.remove_entry(entry) + #| self.shift_back(idx) + #| self.size -= 1 + #| } + #| } + #|} + #|pub fn[K : Hash + Eq, V] Map::update( + #| self : Map[K, V], + #| key : K, + #| f : (V?) -> V?, + #|) -> Unit { + #| let hash = key.hash() + #| let (idx, psl, new_value, push_away) = for psl = 0, idx = hash & + #| self.capacity_mask { + #| match self.entries[idx] { + #| Some(entry) => { + #| if entry.hash == hash && entry.key == key { + #| if f(Some(entry.value)) is Some(new_value) { + #| entry.value = new_value + #| } else { + #| self.remove_entry(entry) + #| self.shift_back(idx) + #| self.size -= 1 + #| } + #| return + #| } + #| if psl > entry.psl { + #| guard f(None) is Some(new_value) else { return } + #| break (idx, psl, new_value, Some(entry)) + #| } + #| continue psl + 1, (idx + 1) & self.capacity_mask + #| } + #| None => { + #| guard f(None) is Some(new_value) else { return } + #| break (idx, psl, new_value, None) + #| } + #| } + #| } + #| if self.size >= self.grow_at { + #| self.grow() + #| self.set(key, new_value) + #| } else { + #| if push_away is Some(entry) { + #| self.push_away(idx, entry) + #| } + #| let entry = { + #| prev: self.tail, + #| next: None, + #| psl, + #| hash, + #| key, + #| value: new_value, + #| } + #| self.add_entry_to_tail(idx, entry) + #| } + #|} + #|fn StringView::equal_to_string(self : Self, other : String) -> Bool { + #| let str = self.str() + #| let start = self.start() + #| let end = self.end() + #| let len = end - start + #| guard len == other.length() else { return false } + #| if physical_equal(str, other) && self.start() == 0 { + #| return true + #| } + #| for i in 0.. Bool { + #| let self_len = self.len() + #| let start = self.start() + #| guard self_len == other.length() else { return false } + #| for i in 0.. V? { + #| let hash = key.hash() + #| for i = 0, idx = hash & map.capacity_mask { + #| guard map.entries[idx] is Some(entry) else { break None } + #| if entry.hash == hash && key.equal_to_bytes(entry.key) { + #| break Some(entry.value) + #| } + #| if i > entry.psl { + #| break None + #| } + #| continue i + 1, (idx + 1) & map.capacity_mask + #| } + #|} + #|pub fn[V] Map::get_from_string(map : Self[String, V], key : StringView) -> V? { + #| let hash = key.hash() + #| for i = 0, idx = hash & map.capacity_mask { + #| guard map.entries[idx] is Some(entry) else { break None } + #| if entry.hash == hash && key.equal_to_string(entry.key) { + #| break Some(entry.value) + #| } + #| if i > entry.psl { + #| break None + #| } + #| continue i + 1, (idx + 1) & map.capacity_mask + #| } + #|} + ), + "mutarrayview.mbt": ( + #|#builtin.valtype + #|type MutArrayView[T] + #|fn[T] MutArrayView::buf(self : MutArrayView[T]) -> UninitializedArray[T] = "%arrayview.buf" + #|fn[T] MutArrayView::start(self : MutArrayView[T]) -> Int = "%arrayview.start" + #|fn[T] MutArrayView::len(self : MutArrayView[T]) -> Int = "%arrayview.len" + #|fn[T] MutArrayView::make( + #| buf : UninitializedArray[T], + #| start : Int, + #| len : Int, + #|) -> MutArrayView[T] = "%arrayview.make" + #|pub fn[T] MutArrayView::length(self : MutArrayView[T]) -> Int { + #| self.len() + #|} + #|pub fn[T] MutArrayView::is_empty(self : MutArrayView[T]) -> Bool { + #| self.length() == 0 + #|} + #|pub fn[T] MutArrayView::start_offset(self : MutArrayView[T]) -> Int { + #| self.start() + #|} + #|#alias("_[_]") + #|pub fn[T] MutArrayView::at(self : MutArrayView[T], index : Int) -> T { + #| guard index >= 0 && index < self.len() else { + #| abort( + #| "index out of bounds: the len is from 0 to \{self.len()} but the index is \{index}", + #| ) + #| } + #| self.buf()[self.start() + index] + #|} + #|#intrinsic("%arrayview.unsafe_get") + #|#internal(unsafe, "Panic if index is out of bounds") + #|pub fn[T] MutArrayView::unsafe_get(self : MutArrayView[T], index : Int) -> T { + #| self.buf()[self.start() + index] + #|} + #|#alias("_[_]=_") + #|pub fn[T] MutArrayView::set( + #| self : MutArrayView[T], + #| index : Int, + #| value : T, + #|) -> Unit { + #| guard index >= 0 && index < self.len() else { + #| abort( + #| "index out of bounds: the len is from 0 to \{self.len()} but the index is \{index}", + #| ) + #| } + #| self.buf()[self.start() + index] = value + #|} + #|#intrinsic("%arrayview.unsafe_set") + #|#internal(unsafe, "Panic if index is out of bounds") + #|pub fn[T] MutArrayView::unsafe_set( + #| self : MutArrayView[T], + #| index : Int, + #| value : T, + #|) -> Unit { + #| self.buf()[self.start() + index] = value + #|} + #|pub fn[T] Array::mut_view( + #| self : Array[T], + #| start? : Int = 0, + #| end? : Int, + #|) -> MutArrayView[T] { + #| let len = self.length() + #| let end = match end { + #| None => len + #| Some(end) => if end < 0 { len + end } else { end } + #| } + #| let start = if start < 0 { len + start } else { start } + #| guard start >= 0 && start <= end && end <= len else { + #| abort("View index out of bounds") + #| } + #| MutArrayView::make(self.buffer(), start, end - start) + #|} + #|pub fn[T] MutArrayView::mut_view( + #| self : MutArrayView[T], + #| start? : Int = 0, + #| end? : Int, + #|) -> MutArrayView[T] { + #| let len = self.length() + #| let end = match end { + #| None => len + #| Some(end) => if end < 0 { len + end } else { end } + #| } + #| let start = if start < 0 { len + start } else { start } + #| guard start >= 0 && start <= end && end <= len else { + #| abort("View index out of bounds") + #| } + #| MutArrayView::make(self.buf(), self.start() + start, end - start) + #|} + #|pub fn[T] FixedArray::mut_view( + #| self : FixedArray[T], + #| start? : Int = 0, + #| end? : Int, + #|) -> MutArrayView[T] { + #| let len = self.length() + #| let end = match end { + #| None => len + #| Some(end) => if end < 0 { len + end } else { end } + #| } + #| let start = if start < 0 { len + start } else { start } + #| guard start >= 0 && start <= end && end <= len else { + #| abort("View index out of bounds") + #| } + #| MutArrayView::make( + #| unsafe_cast_fixedarray_to_uninitializedarray(self), + #| start, + #| end - start, + #| ) + #|} + #|#alias("_[_:_]") + #|#alias(sub, deprecated="Use _[_:_] instead") + #|pub fn[T] MutArrayView::view( + #| self : MutArrayView[T], + #| start? : Int = 0, + #| end? : Int, + #|) -> ArrayView[T] { + #| let len = self.length() + #| let end = match end { + #| None => len + #| Some(end) => if end < 0 { len + end } else { end } + #| } + #| let start = if start < 0 { len + start } else { start } + #| guard start >= 0 && start <= end && end <= len else { + #| abort("View index out of bounds") + #| } + #| ArrayView::make(self.buf(), self.start() + start, end - start) + #|} + #|pub fn[T] MutArrayView::to_array(self : MutArrayView[T]) -> Array[T] { + #| self[:].to_array() + #|} + #|#alias(iterator, deprecated) + #|pub fn[X] MutArrayView::iter(self : MutArrayView[X]) -> Iter[X] { + #| let mut i = 0 + #| Iter::new(fn() { + #| guard i < self.length() else { None } + #| let elem = self.unsafe_get(i) + #| i += 1 + #| Some(elem) + #| }) + #|} + #|#alias(rev_iterator, deprecated) + #|pub fn[X] MutArrayView::rev_iter(self : MutArrayView[X]) -> Iter[X] { + #| let mut i = self.length() + #| Iter::new(fn() { + #| guard i > 0 else { None } + #| i -= 1 + #| Some(self.unsafe_get(i)) + #| }) + #|} + #|#alias(iterator2, deprecated) + #|pub fn[X] MutArrayView::iter2(self : MutArrayView[X]) -> Iter2[Int, X] { + #| let mut i = 0 + #| Iter2::new(fn() { + #| guard i < self.length() else { None } + #| let result = Some((i, self.unsafe_get(i))) + #| i += 1 + #| result + #| }) + #|} + #|pub impl[X : Show] Show for MutArrayView[X] with output(self, logger) { + #| self[:].output(logger) + #|} + #|pub impl[T : Eq] Eq for MutArrayView[T] with equal(self, other) -> Bool { + #| self[:] == other[:] + #|} + #|pub impl[T : Compare] Compare for MutArrayView[T] with compare(self, other) -> Int { + #| self[:].compare(other[:]) + #|} + #|pub impl[A : Hash] Hash for MutArrayView[A] with hash_combine(self, hasher) { + #| self[:].hash_combine(hasher) + #|} + ), + "op.mbt": ( + #|#coverage.skip + #|#deprecated + #|#doc(hidden) + #|pub fn[T : Compare] op_lt(self_ : T, other : T) -> Bool { + #| Compare::op_lt(self_, other) + #|} + #|#coverage.skip + #|#deprecated + #|#doc(hidden) + #|pub fn[T : Compare] op_gt(self_ : T, other : T) -> Bool { + #| Compare::op_gt(self_, other) + #|} + #|#coverage.skip + #|#deprecated + #|#doc(hidden) + #|pub fn[T : Compare] op_le(self_ : T, other : T) -> Bool { + #| Compare::op_le(self_, other) + #|} + #|#coverage.skip + #|#deprecated + #|#doc(hidden) + #|pub fn[T : Compare] op_ge(self_ : T, other : T) -> Bool { + #| Compare::op_ge(self_, other) + #|} + #|#coverage.skip + #|pub fn[T : Eq] op_notequal(x : T, y : T) -> Bool { + #| !(x == y) + #|} + ), + "operators.mbt": ( + #|pub(open) trait Add { + #| add(Self, Self) -> Self = _ + #| #deprecated("use `add` instead", skip_current_package=true) + #| op_add(Self, Self) -> Self = _ + #|} + #|pub(open) trait Sub { + #| sub(Self, Self) -> Self = _ + #| #deprecated("use `sub` instead", skip_current_package=true) + #| op_sub(Self, Self) -> Self = _ + #|} + #|pub(open) trait Mul { + #| mul(Self, Self) -> Self = _ + #| #deprecated("use `mul` instead", skip_current_package=true) + #| op_mul(Self, Self) -> Self = _ + #|} + #|pub(open) trait Div { + #| div(Self, Self) -> Self = _ + #| #deprecated("use `div` instead", skip_current_package=true) + #| op_div(Self, Self) -> Self = _ + #|} + #|pub(open) trait Neg { + #| neg(Self) -> Self = _ + #| #deprecated("use `neg` instead", skip_current_package=true) + #| op_neg(Self) -> Self = _ + #|} + #|pub(open) trait Mod { + #| mod(Self, Self) -> Self = _ + #| #deprecated("use `mod` instead", skip_current_package=true) + #| op_mod(Self, Self) -> Self = _ + #|} + #|pub(open) trait BitAnd { + #| land(Self, Self) -> Self + #|} + #|pub(open) trait BitOr { + #| lor(Self, Self) -> Self + #|} + #|pub(open) trait BitXOr { + #| lxor(Self, Self) -> Self + #|} + #|pub(open) trait Shl { + #| shl(Self, Int) -> Self = _ + #| #deprecated("use `shl` instead", skip_current_package=true) + #| op_shl(Self, Int) -> Self = _ + #|} + #|pub(open) trait Shr { + #| shr(Self, Int) -> Self = _ + #| #deprecated("use `shr` instead", skip_current_package=true) + #| op_shr(Self, Int) -> Self = _ + #|} + #|#deprecated("replace `impl op_add` with `impl add`") + #|impl Add with add(self, other) { + #| Add::op_add(self, other) + #|} + #|impl Add with op_add(self, other) { + #| Add::add(self, other) + #|} + #|#deprecated("replace `impl op_sub` with `impl sub`") + #|impl Sub with sub(self, other) { + #| Sub::op_sub(self, other) + #|} + #|impl Sub with op_sub(self, other) { + #| Sub::sub(self, other) + #|} + #|#deprecated("replace `impl op_mul` with `impl mul`") + #|impl Mul with mul(self, other) { + #| Mul::op_mul(self, other) + #|} + #|impl Mul with op_mul(self, other) { + #| Mul::mul(self, other) + #|} + #|#deprecated("replace `impl op_div` with `impl div`") + #|impl Div with div(self, other) { + #| Div::op_div(self, other) + #|} + #|impl Div with op_div(self, other) { + #| Div::div(self, other) + #|} + #|#deprecated("replace `impl op_neg` with `impl neg`") + #|impl Neg with neg(self) { + #| Neg::op_neg(self) + #|} + #|impl Neg with op_neg(self) { + #| Neg::neg(self) + #|} + #|#deprecated("replace `impl op_mod` with `impl mod`") + #|impl Mod with mod(self, other) { + #| Mod::op_mod(self, other) + #|} + #|impl Mod with op_mod(self, other) { + #| Mod::mod(self, other) + #|} + #|#deprecated("replace `impl op_shl` with `impl shl`") + #|impl Shl with shl(self, i) { + #| Shl::op_shl(self, i) + #|} + #|impl Shl with op_shl(self, i) { + #| Shl::shl(self, i) + #|} + #|#deprecated("replace `impl op_shr` with `impl shr`") + #|impl Shr with shr(self, i) { + #| Shr::op_shr(self, i) + #|} + #|impl Shr with op_shr(self, i) { + #| Shr::shr(self, i) + #|} + ), + "option.mbt": ( + #|pub impl[X : Eq] Eq for X? with equal(self, other) { + #| match (self, other) { + #| (None, None) => true + #| (Some(x), Some(y)) => x == y + #| _ => false + #| } + #|} + #|pub fn[X : Show] Option::to_string(self : X?) -> String { + #| match self { + #| None => "None" + #| Some(x) => "Some(" + x.to_string() + ")" + #| } + #|} + #|pub fn[X] Option::unwrap(self : X?) -> X { + #| match self { + #| None => panic() + #| Some(x) => x + #| } + #|} + #|#alias(or, deprecated) + #|pub fn[T] Option::unwrap_or(self : T?, default : T) -> T { + #| match self { + #| None => default + #| Some(t) => t + #| } + #|} + #|#alias(or_else, deprecated) + #|pub fn[T] Option::unwrap_or_else( + #| self : T?, + #| default : () -> T raise?, + #|) -> T raise? { + #| match self { + #| None => default() + #| Some(t) => t + #| } + #|} + #|#alias(or_default, deprecated) + #|pub fn[T : Default] Option::unwrap_or_default(self : T?) -> T { + #| match self { + #| None => T::default() + #| Some(t) => t + #| } + #|} + #|pub impl[X : Compare] Compare for X? with compare(self, other) { + #| match (self, other) { + #| (Some(x), Some(y)) => x.compare(y) + #| (Some(_), None) => 1 + #| (None, Some(_)) => -1 + #| (None, None) => 0 + #| } + #|} + #|#alias(or_error, deprecated) + #|pub fn[T, Err : Error] Option::unwrap_or_error( + #| self : T?, + #| err : Err, + #|) -> T raise Err { + #| match self { + #| Some(v) => v + #| None => raise err + #| } + #|} + #|pub impl[X] Default for X? with default() { + #| None + #|} + #|#alias(iterator, deprecated) + #|pub fn[T] Option::iter(self : T?) -> Iter[T] { + #| match self { + #| Some(v) => Iter::singleton(v) + #| None => Iter::empty() + #| } + #|} + #|pub fn[T, U] Option::map(self : T?, f : (T) -> U raise?) -> U? raise? { + #| match self { + #| Some(t) => Some(f(t)) + #| None => None + #| } + #|} + #|pub fn[T, U] Option::map_or( + #| self : T?, + #| default : U, + #| f : (T) -> U raise?, + #|) -> U raise? { + #| match self { + #| None => default + #| Some(x) => f(x) + #| } + #|} + #|pub fn[T, U] Option::map_or_else( + #| self : T?, + #| default : () -> U raise?, + #| f : (T) -> U raise?, + #|) -> U raise? { + #| match self { + #| None => default() + #| Some(x) => f(x) + #| } + #|} + #|pub fn[T, U] Option::bind(self : T?, f : (T) -> U? raise?) -> U? raise? { + #| match self { + #| Some(t) => f(t) + #| None => None + #| } + #|} + #|#deprecated("use `option.bind(x => x)` instead") + #|pub fn[T] Option::flatten(self : T??) -> T? { + #| match self { + #| Some(inner) => inner + #| None => None + #| } + #|} + #|#deprecated("use `x is None` instead") + #|pub fn[T] Option::is_empty(self : T?) -> Bool { + #| self is None + #|} + #|pub fn[T] Option::filter(self : T?, f : (T) -> Bool raise?) -> T? raise? { + #| match self { + #| Some(t) => if f(t) { self } else { None } + #| None => None + #| } + #|} + #|#deprecated("use `x is Some(_)` instead") + #|pub fn[T] Option::is_some(self : T?) -> Bool { + #| self is Some(_) + #|} + #|#deprecated("use `x is None` instead") + #|pub fn[T] Option::is_none(self : T?) -> Bool { + #| self is None + #|} + ), + "readonlyarray.mbt": ( + #|fn[T] ReadOnlyArray::unsafe_reinterpret_to_fixed_array( + #| self : ReadOnlyArray[T], + #|) -> FixedArray[T] = "%identity" + #|fn[T] unsafe_reinterpret_from_fixed_array( + #| arr : FixedArray[T], + #|) -> ReadOnlyArray[T] = "%identity" + #|#alias("_[_]") + #|pub fn[T] ReadOnlyArray::at(self : ReadOnlyArray[T], index : Int) -> T { + #| self.unsafe_reinterpret_to_fixed_array()[index] + #|} + #|pub fn[T] ReadOnlyArray::from_array(array : ArrayView[T]) -> ReadOnlyArray[T] { + #| unsafe_reinterpret_from_fixed_array(FixedArray::from_array(array)) + #|} + #|#alias(from_iterator, deprecated) + #|pub fn[T] ReadOnlyArray::from_iter(iter : Iter[T]) -> ReadOnlyArray[T] { + #| unsafe_reinterpret_from_fixed_array(FixedArray::from_iter(iter)) + #|} + #|pub fn[T] ReadOnlyArray::makei( + #| length : Int, + #| value : (Int) -> T raise?, + #|) -> ReadOnlyArray[T] raise? { + #| unsafe_reinterpret_from_fixed_array(FixedArray::makei(length, value)) + #|} + #|pub fn[T] ReadOnlyArray::get(self : ReadOnlyArray[T], index : Int) -> T? { + #| self.unsafe_reinterpret_to_fixed_array().get(index) + #|} + #|pub fn[T] ReadOnlyArray::length(self : ReadOnlyArray[T]) -> Int { + #| self.unsafe_reinterpret_to_fixed_array().length() + #|} + #|pub fn[T] ReadOnlyArray::is_empty(self : ReadOnlyArray[T]) -> Bool { + #| self.unsafe_reinterpret_to_fixed_array().is_empty() + #|} + #|pub fn[T] ReadOnlyArray::last(self : ReadOnlyArray[T]) -> T? { + #| self.unsafe_reinterpret_to_fixed_array().last() + #|} + #|#alias(iterator, deprecated) + #|pub fn[T] ReadOnlyArray::iter(self : ReadOnlyArray[T]) -> Iter[T] { + #| self.unsafe_reinterpret_to_fixed_array().iter() + #|} + #|pub fn[T] ReadOnlyArray::iter2(self : ReadOnlyArray[T]) -> Iter2[Int, T] { + #| self.unsafe_reinterpret_to_fixed_array().iter2() + #|} + #|pub fn[T] ReadOnlyArray::each( + #| self : ReadOnlyArray[T], + #| f : (T) -> Unit raise?, + #|) -> Unit raise? { + #| self.unsafe_reinterpret_to_fixed_array().each(f) + #|} + #|pub fn[T] ReadOnlyArray::eachi( + #| self : ReadOnlyArray[T], + #| f : (Int, T) -> Unit raise?, + #|) -> Unit raise? { + #| self.unsafe_reinterpret_to_fixed_array().eachi(f) + #|} + #|pub fn[T] ReadOnlyArray::rev_each( + #| self : ReadOnlyArray[T], + #| f : (T) -> Unit raise?, + #|) -> Unit raise? { + #| self.unsafe_reinterpret_to_fixed_array().rev_each(f) + #|} + #|pub fn[T] ReadOnlyArray::rev_eachi( + #| self : ReadOnlyArray[T], + #| f : (Int, T) -> Unit raise?, + #|) -> Unit raise? { + #| self.unsafe_reinterpret_to_fixed_array().rev_eachi(f) + #|} + #|pub fn[T, U] ReadOnlyArray::map( + #| self : ReadOnlyArray[T], + #| f : (T) -> U raise?, + #|) -> ReadOnlyArray[U] raise? { + #| unsafe_reinterpret_from_fixed_array( + #| self.unsafe_reinterpret_to_fixed_array().map(f), + #| ) + #|} + #|pub fn[T, U] ReadOnlyArray::mapi( + #| self : ReadOnlyArray[T], + #| f : (Int, T) -> U raise?, + #|) -> ReadOnlyArray[U] raise? { + #| unsafe_reinterpret_from_fixed_array( + #| self.unsafe_reinterpret_to_fixed_array().mapi(f), + #| ) + #|} + #|pub fn[A, B] ReadOnlyArray::fold( + #| self : ReadOnlyArray[A], + #| init~ : B, + #| f : (B, A) -> B raise?, + #|) -> B raise? { + #| self.unsafe_reinterpret_to_fixed_array().fold(init~, f) + #|} + #|pub fn[A, B] ReadOnlyArray::rev_fold( + #| self : ReadOnlyArray[A], + #| init~ : B, + #| f : (B, A) -> B raise?, + #|) -> B raise? { + #| self.unsafe_reinterpret_to_fixed_array().rev_fold(init~, f) + #|} + #|pub fn[A, B] ReadOnlyArray::foldi( + #| self : ReadOnlyArray[A], + #| init~ : B, + #| f : (Int, B, A) -> B raise?, + #|) -> B raise? { + #| self.unsafe_reinterpret_to_fixed_array().foldi(init~, f) + #|} + #|pub fn[A, B] ReadOnlyArray::rev_foldi( + #| self : ReadOnlyArray[A], + #| init~ : B, + #| f : (Int, B, A) -> B raise?, + #|) -> B raise? { + #| self.unsafe_reinterpret_to_fixed_array().rev_foldi(init~, f) + #|} + #|pub fn[T] ReadOnlyArray::rev(self : ReadOnlyArray[T]) -> ReadOnlyArray[T] { + #| unsafe_reinterpret_from_fixed_array( + #| self.unsafe_reinterpret_to_fixed_array().rev(), + #| ) + #|} + #|pub fn[T : Eq] ReadOnlyArray::search( + #| self : ReadOnlyArray[T], + #| value : T, + #|) -> Int? { + #| self.unsafe_reinterpret_to_fixed_array().search(value) + #|} + #|pub fn[T : Eq] ReadOnlyArray::contains( + #| self : ReadOnlyArray[T], + #| value : T, + #|) -> Bool { + #| self.unsafe_reinterpret_to_fixed_array().contains(value) + #|} + #|pub fn[T : Compare] ReadOnlyArray::is_sorted(self : ReadOnlyArray[T]) -> Bool { + #| self.unsafe_reinterpret_to_fixed_array().is_sorted() + #|} + #|pub fn[T : Eq] ReadOnlyArray::starts_with( + #| self : ReadOnlyArray[T], + #| prefix : ReadOnlyArray[T], + #|) -> Bool { + #| self + #| .unsafe_reinterpret_to_fixed_array() + #| .starts_with(prefix.unsafe_reinterpret_to_fixed_array()) + #|} + #|pub fn[T : Eq] ReadOnlyArray::ends_with( + #| self : ReadOnlyArray[T], + #| suffix : ReadOnlyArray[T], + #|) -> Bool { + #| self + #| .unsafe_reinterpret_to_fixed_array() + #| .ends_with(suffix.unsafe_reinterpret_to_fixed_array()) + #|} + #|#alias(every) + #|pub fn[T] ReadOnlyArray::all( + #| self : ReadOnlyArray[T], + #| f : (T) -> Bool raise?, + #|) -> Bool raise? { + #| self.unsafe_reinterpret_to_fixed_array().all(f) + #|} + #|#alias(exists) + #|pub fn[T] ReadOnlyArray::any( + #| self : ReadOnlyArray[T], + #| f : (T) -> Bool raise?, + #|) -> Bool raise? { + #| self.unsafe_reinterpret_to_fixed_array().any(f) + #|} + #|pub fn[T : Compare] ReadOnlyArray::binary_search( + #| self : ReadOnlyArray[T], + #| value : T, + #|) -> Result[Int, Int] { + #| self.unsafe_reinterpret_to_fixed_array().binary_search(value) + #|} + #|pub fn[T] ReadOnlyArray::binary_search_by( + #| self : ReadOnlyArray[T], + #| cmp : (T) -> Int raise?, + #|) -> Result[Int, Int] raise? { + #| self.unsafe_reinterpret_to_fixed_array().binary_search_by(cmp) + #|} + #|#alias("_[_:_]") + #|#alias(sub, deprecated="Use _[_:_] instead") + #|pub fn[T] ReadOnlyArray::view( + #| self : ReadOnlyArray[T], + #| start? : Int = 0, + #| end? : Int, + #|) -> ArrayView[T] { + #| match end { + #| None => self.unsafe_reinterpret_to_fixed_array()[start:] + #| Some(e) => self.unsafe_reinterpret_to_fixed_array()[start:e] + #| } + #|} + #|pub fn[T] ReadOnlyArray::get_view( + #| self : ReadOnlyArray[T], + #| start? : Int = 0, + #| end? : Int, + #|) -> ArrayView[T]? { + #| let fixed = self.unsafe_reinterpret_to_fixed_array() + #| match end { + #| None => fixed.get_view(start~) + #| Some(end) => fixed.get_view(start~, end~) + #| } + #|} + #|pub fn ReadOnlyArray::join( + #| self : ReadOnlyArray[String], + #| separator : StringView, + #|) -> String { + #| self.unsafe_reinterpret_to_fixed_array().join(separator) + #|} + #|pub impl[T] Default for ReadOnlyArray[T] with default() { + #| unsafe_reinterpret_from_fixed_array(FixedArray::default()) + #|} + #|pub impl[T : Show] Show for ReadOnlyArray[T] with output(self, logger) { + #| self.unsafe_reinterpret_to_fixed_array().output(logger) + #|} + #|pub impl[T : ToJson] ToJson for ReadOnlyArray[T] with to_json(self) { + #| self.unsafe_reinterpret_to_fixed_array().to_json() + #|} + #|pub impl[T : Eq] Eq for ReadOnlyArray[T] with equal(self, other) { + #| self + #| .unsafe_reinterpret_to_fixed_array() + #| .equal(other.unsafe_reinterpret_to_fixed_array()) + #|} + #|pub impl[T : Hash] Hash for ReadOnlyArray[T] with hash_combine(self, hasher) { + #| self.unsafe_reinterpret_to_fixed_array().hash_combine(hasher) + #|} + #|pub impl[T : Compare] Compare for ReadOnlyArray[T] with compare(self, other) { + #| self + #| .unsafe_reinterpret_to_fixed_array() + #| .compare(other.unsafe_reinterpret_to_fixed_array()) + #|} + ), + "result.mbt": ( + #|pub fn[T, E, U] Result::map(self : Result[T, E], f : (T) -> U) -> Result[U, E] { + #| match self { + #| Ok(value) => Ok(f(value)) + #| Err(err) => Err(err) + #| } + #|} + #|test "map" { + #| let x : Result[Int, Unit] = Ok(6) + #| let y = x.map((v : Int) => v * 7) + #| let z : Result[Int, Int] = Err(3) + #| let w = z.map((v : Int) => v * 7) + #| assert_eq(y, Ok(42)) + #| assert_eq(w, Err(3)) + #|} + #|pub fn[T, E, F] Result::map_err( + #| self : Result[T, E], + #| f : (E) -> F, + #|) -> Result[T, F] { + #| match self { + #| Ok(value) => Ok(value) + #| Err(err) => Err(f(err)) + #| } + #|} + #|test "map_err" { + #| let x : Result[Int, String] = Err("error") + #| let y = x.map_err((v : String) => v + "!") + #| let z : Result[Int, Int] = Ok(6) + #| let w = z.map_err((v : Int) => v + 6) + #| assert_eq(y, Err("error!")) + #| assert_eq(w, Ok(6)) + #|} + #|#alias(or) + #|pub fn[T, E] Result::unwrap_or(self : Result[T, E], default : T) -> T { + #| match self { + #| Ok(value) => value + #| Err(_) => default + #| } + #|} + #|test "unwrap_or" { + #| let x : Result[Int, String] = Ok(3) + #| let y : Result[Int, String] = Err("error") + #| assert_eq(x.unwrap_or(5), 3) + #| assert_eq(y.unwrap_or(5), 5) + #|} + #|#alias(or_else) + #|pub fn[T, E] Result::unwrap_or_else( + #| self : Result[T, E], + #| default : () -> T raise?, + #|) -> T raise? { + #| match self { + #| Ok(value) => value + #| Err(_) => default() + #| } + #|} + #|test "unwrap_or_else" { + #| let x : Result[Int, String] = Ok(3) + #| let y : Result[Int, String] = Err("error") + #| assert_eq(x.unwrap_or_else(() => 5), 3) + #| assert_eq(y.unwrap_or_else(() => 5), 5) + #|} + #|pub fn[T, E] Result::flatten(self : Result[Result[T, E], E]) -> Result[T, E] { + #| match self { + #| Ok(value) => value + #| Err(err) => Err(err) + #| } + #|} + #|test "flatten" { + #| let x : Result[Result[Int, String], String] = Ok(Ok(6)) + #| let y = x.flatten() + #| let z : Result[Result[Int, String], String] = Err("error") + #| let w = z.flatten() + #| assert_eq(y, Ok(6)) + #| assert_eq(w, Err("error")) + #|} + #|pub fn[T, E, U] Result::bind( + #| self : Result[T, E], + #| g : (T) -> Result[U, E], + #|) -> Result[U, E] { + #| match self { + #| Ok(value) => g(value) + #| Err(err) => Err(err) + #| } + #|} + #|test "bind" { + #| let x : Result[Int, String] = Ok(6) + #| let y = x.bind((v : Int) => Ok(v * 7)) + #| assert_eq(y, Ok(42)) + #|} + #|pub fn[T, E] Result::to_option(self : Result[T, E]) -> T? { + #| match self { + #| Ok(value) => Some(value) + #| Err(_) => None + #| } + #|} + #|test "to_option" { + #| let x : Result[Int, String] = Ok(6) + #| let y : Result[Int, String] = Err("error") + #| let z = x.to_option() + #| let w = y.to_option() + #| assert_eq(z, Some(6)) + #| assert_eq(w, None) + #|} + #|pub impl[T : Compare, E : Compare] Compare for Result[T, E] with compare( + #| self : Result[T, E], + #| other : Result[T, E], + #|) -> Int { + #| match (self, other) { + #| (Ok(x), Ok(y)) => x.compare(y) + #| (Ok(_), Err(_)) => -1 + #| (Err(_), Ok(_)) => 1 + #| (Err(x), Err(y)) => x.compare(y) + #| } + #|} + #|test "compare" { + #| let ok1 = Result::Ok(1) + #| let ok2 = Result::Ok(2) + #| let err1 = Result::Err(1) + #| let err2 = Result::Err(2) + #| assert_eq(0, ok1.compare(ok1)) + #| assert_eq(0, err2.compare(Result::Err(2))) + #| assert_eq(-1, ok1.compare(ok2)) + #| assert_eq(1, ok2.compare(ok1)) + #| assert_eq(-1, err1.compare(err2)) + #| assert_eq(1, err2.compare(err1)) + #| assert_eq(-1, ok2.compare(err1)) + #| assert_eq(1, err1.compare(ok2)) + #|} + #|pub fn[T, E] Result::unwrap(self : Result[T, E]) -> T { + #| match self { + #| Ok(x) => x + #| Err(_) => abort("called `Result::unwrap()` on an `Err` value") + #| } + #|} + #|pub fn[T, E] Result::unwrap_err(self : Result[T, E]) -> E { + #| match self { + #| Ok(_) => abort("called `Result::unwrap_err()` on an `Ok` value") + #| Err(e) => e + #| } + #|} + #|test "show" { + #| let ok : Result[_, String] = Ok("hello") + #| inspect( + #| ok, + #| content=( + #| #|Ok("hello") + #| ), + #| ) + #| let err : Result[String, _] = Err("world") + #| inspect( + #| err, + #| content=( + #| #|Err("world") + #| ), + #| ) + #|} + #|pub fn[T : Default, E] Result::unwrap_or_default(self : Result[T, E]) -> T { + #| match self { + #| Ok(value) => value + #| Err(_) => T::default() + #| } + #|} + #|test "unwrap_or_default" { + #| let x : Result[Int, String] = Ok(3) + #| let y : Result[Int, String] = Err("error") + #| assert_eq(x.unwrap_or_default(), 3) + #| assert_eq(y.unwrap_or_default(), 0) + #|} + #|pub fn[T, E : Error] Result::unwrap_or_error(self : Result[T, E]) -> T raise E { + #| match self { + #| Ok(x) => x + #| Err(e) => raise e + #| } + #|} + #|test "unwrap exn" { + #| (try + #| (Err(Failure("This is serious")) : Result[Unit, Failure]).unwrap_or_error() + #| |> Ok + #| catch { + #| Failure(msg) => Err(msg) + #| }) + #| |> inspect( + #| content=( + #| #|Err("This is serious") + #| ), + #| ) + #|} + #|pub impl[T : Eq, E : Eq] Eq for Result[T, E] with equal(self, other) { + #| match (self, other) { + #| (Ok(x), Ok(y)) => x == y + #| (Err(x), Err(y)) => x == y + #| _ => false + #| } + #|} + ), + "show.mbt": ( + #|pub impl Show for Unit with output(_self, logger) { + #| logger.write_string("()") + #|} + #|pub impl Show for Bool with output(self, logger) { + #| if self { + #| logger.write_string("true") + #| } else { + #| logger.write_string("false") + #| } + #|} + #|pub impl Show for Int with output(self, logger) { + #| logger.write_string(self.to_string()) + #|} + #|pub impl Show for Int64 with output(self, logger) { + #| logger.write_string(self.to_string()) + #|} + #|pub impl Show for UInt with output(self, logger) { + #| logger.write_string(self.to_string()) + #|} + #|pub impl Show for UInt64 with output(self, logger) { + #| logger.write_string(self.to_string()) + #|} + #|pub impl Show for Byte with output(self, logger) { + #| logger.write_string(self.to_string()) + #|} + #|pub impl Show for UInt16 with output(self, logger) { + #| logger.write_string(self.to_string()) + #|} + #|pub fn Byte::to_hex(b : Byte) -> String { + #| fn to_hex_digit(i : Byte) -> Char { + #| if i < 10 { + #| (i + '0').to_char() + #| } else { + #| (i + 'a' - 10).to_char() + #| } + #| } + #| [to_hex_digit(b / 16), to_hex_digit(b % 16)] + #|} + #|test "to_hex_digit" { + #| inspect(Byte::to_hex(b'\xee'), content="ee") + #| inspect(Byte::to_hex(b'\xf3'), content="f3") + #|} + #|pub fn String::escape(self : String, quote? : Bool = true) -> String { + #| let buf = StringBuilder::new() + #| self[:].escape_to(buf, quote~) + #| buf.to_string() + #|} + #|pub fn StringView::escape( + #| self : StringView, + #| quote? : Bool = true, + #|) -> StringView { + #| let buf = StringBuilder::new() + #| self.escape_to(buf, quote~) + #| buf.to_string() + #|} + #|fn StringView::escape_to( + #| self : StringView, + #| logger : &Logger, + #| quote? : Bool = true, + #|) -> Unit { + #| if quote { + #| logger.write_char('"') + #| } + #| let len = self.length() + #| fn flush_segment(seg : Int, i : Int) { + #| if i > seg { + #| logger.write_view(self[seg:i]) + #| } + #| } + #| for i = 0, seg = 0 { + #| if i >= len { + #| flush_segment(seg, i) + #| break + #| } + #| let code = self.unsafe_get(i) + #| match code { + #| '"' | '\\' as c => { + #| flush_segment(seg, i) + #| logger.write_char('\\') + #| logger.write_char(c.unsafe_to_char()) + #| continue i + 1, i + 1 + #| } + #| '\n' => { + #| flush_segment(seg, i) + #| logger.write_string("\\n") + #| continue i + 1, i + 1 + #| } + #| '\r' => { + #| flush_segment(seg, i) + #| logger.write_string("\\r") + #| continue i + 1, i + 1 + #| } + #| '\b' => { + #| flush_segment(seg, i) + #| logger.write_string("\\b") + #| continue i + 1, i + 1 + #| } + #| '\t' => { + #| flush_segment(seg, i) + #| logger.write_string("\\t") + #| continue i + 1, i + 1 + #| } + #| code => + #| if code < ' ' { + #| flush_segment(seg, i) + #| logger.write_string("\\u{") + #| logger.write_string(code.to_byte().to_hex()) + #| logger.write_char('}') + #| continue i + 1, i + 1 + #| } else { + #| continue i + 1, seg + #| } + #| } + #| } + #| if quote { + #| logger.write_char('"') + #| } + #|} + #|pub impl Show for String with output(self, logger) { + #| self[:].escape_to(logger) + #|} + #|pub impl Show for String with to_string(self) { + #| self + #|} + #|pub impl[X : Show] Show for X? with output(self, logger) { + #| match self { + #| None => logger.write_string("None") + #| Some(arg) => { + #| logger.write_string("Some(") + #| logger.write_object(arg) + #| logger.write_string(")") + #| } + #| } + #|} + #|pub impl[T : Show, E : Show] Show for Result[T, E] with output(self, logger) { + #| match self { + #| Ok(x) => { + #| logger.write_string("Ok(") + #| logger.write_object(x) + #| logger.write_string(")") + #| } + #| Err(e) => { + #| logger.write_string("Err(") + #| logger.write_object(e) + #| logger.write_string(")") + #| } + #| } + #|} + #|pub impl[X : Show] Show for FixedArray[X] with output(self, logger) { + #| logger.write_iter(self.iter()) + #|} + #|pub impl[X : Show] Show for Array[X] with output(self, logger) { + #| logger.write_iter(self.iter()) + #|} + ), + "string.mbt": ( + #|fn unsafe_make_string(length : Int, value : Char) -> String = "$moonbit.unsafe_make_string" + #|pub fn String::make(length : Int, value : Char) -> String { + #| guard length >= 0 else { abort("invalid length") } + #| if value.to_int() <= 0xFFFF { + #| unsafe_make_string(length, value) + #| } else { + #| let buf = StringBuilder::new(size_hint=2 * length) + #| for _ in 0.. Char { + #| ((leading - 0xD800) * 0x400 + trailing - 0xDC00 + 0x10000).unsafe_to_char() + #|} + #|#alias(codepoint_length, deprecated) + #|pub fn String::char_length( + #| self : String, + #| start_offset? : Int = 0, + #| end_offset? : Int, + #|) -> Int { + #| let end_offset = if end_offset is Some(o) { o } else { self.length() } + #| guard start_offset >= 0 && + #| start_offset <= end_offset && + #| end_offset <= self.length() else { + #| abort("invalid start or end index for String::codepoint_length") + #| } + #| for utf16_index = start_offset, char_count = 0 + #| utf16_index < end_offset + #| utf16_index = utf16_index + 1, char_count = char_count + 1 { + #| let c1 = self.unsafe_get(utf16_index) + #| if c1.is_leading_surrogate() && utf16_index + 1 < end_offset { + #| let c2 = self.unsafe_get(utf16_index + 1) + #| if c2.is_trailing_surrogate() { + #| continue utf16_index + 2, char_count + 1 + #| } else { + #| abort("invalid surrogate pair") + #| } + #| } + #| } nobreak { + #| char_count + #| } + #|} + #|#intrinsic("%string.substring") + #|pub fn String::unsafe_substring( + #| str : String, + #| start~ : Int, + #| end~ : Int, + #|) -> String { + #| if start == 0 && end == str.length() { + #| return str + #| } + #| let len = end - start + #| let bytes = FixedArray::make(len * 2, Byte::default()) + #| bytes.blit_from_string(0, str, start, len) + #| bytes.unsafe_reinterpret_as_bytes().to_unchecked_string() + #|} + #|#deprecated("Use `str[:]` or `str[:].to_string()` instead", skip_current_package=true) + #|pub fn String::substring(self : String, start? : Int = 0, end? : Int) -> String { + #| let len = self.length() + #| let end = match end { + #| Some(end) => end + #| None => len + #| } + #| guard start >= 0 && start <= end && end <= len + #| self.unsafe_substring(start~, end~) + #|} + #|pub fn String::suffixes( + #| self : String, + #| include_empty? : Bool = false, + #|) -> Iter[StringView] { + #| self[:].suffixes(include_empty~) + #|} + #|test "substring/empty" { + #| let s = "test" + #| inspect(s.substring(start=2, end=2), content="") + #| inspect(s.substring(start=4, end=4), content="") + #| inspect("".substring(), content="") + #|} + #|test "panic substring/invalid_range" { + #| let s = "test" + #| ignore(s.substring(start=-1)) + #| ignore(s.substring(end=5)) + #| ignore(s.substring(start=3, end=2)) + #|} + #|test "substring/basic" { + #| inspect("Hello world".substring(start=0, end=5), content="Hello") + #| inspect("Hello world".substring(start=6, end=11), content="world") + #| inspect("Hello world".substring(start=0), content="Hello world") + #| inspect("Hello world".substring(start=6), content="world") + #|} + #|test "substring/boundary" { + #| inspect("".substring(start=0, end=0), content="") + #| inspect("a".substring(start=0, end=1), content="a") + #| inspect("abc".substring(start=0), content="abc") + #| inspect("abc".substring(start=1), content="bc") + #| inspect("abc".substring(start=0, end=3), content="abc") + #|} + #|test "panic substring/out_of_bounds" { + #| ignore("hello".substring(start=-1, end=4)) + #| ignore("hello".substring(start=6, end=4)) + #| ignore("hello".substring(start=0, end=6)) + #|} + #|pub impl Compare for String with compare(self, other) { + #| let len = self.length() + #| match len.compare(other.length()) { + #| 0 => { + #| for i in 0.. order + #| } + #|} + #|pub impl Default for String with default() { + #| "" + #|} + #|#deprecated("Check `@encoding/utf8.encode`") + #|pub fn String::to_bytes(self : String) -> Bytes { + #| let array = FixedArray::make(self.length() * 2, Byte::default()) + #| array.blit_from_string(0, self, 0, self.length()) + #| array |> unsafe_to_bytes + #|} + #|fn unsafe_to_bytes(array : FixedArray[Byte]) -> Bytes = "%identity" + #|pub fn String::to_array(self : String) -> Array[Char] { + #| self + #| .iter() + #| .fold(init=Array::new(capacity=self.length()), (rv, c) => { + #| rv.push(c) + #| rv + #| }) + #|} + #|#alias(iterator, deprecated) + #|pub fn String::iter(self : String) -> Iter[Char] { + #| let len = self.length() + #| let mut index = 0 + #| Iter::new(fn() { + #| guard index < len else { None } + #| let c1 = self.unsafe_get(index) + #| if c1.is_leading_surrogate() && index + 1 < len { + #| let c2 = self.unsafe_get(index + 1) + #| if c2.is_trailing_surrogate() { + #| let c = code_point_of_surrogate_pair(c1.to_int(), c2.to_int()) + #| index += 2 + #| return Some(c) + #| } + #| } + #| index += 1 + #| Some(c1.unsafe_to_char()) + #| }) + #|} + #|#alias(iterator2, deprecated) + #|pub fn String::iter2(self : String) -> Iter2[Int, Char] { + #| self.iter().iter2() + #|} + #|#alias(rev_iterator, deprecated) + #|pub fn String::rev_iter(self : String) -> Iter[Char] { + #| let len = self.length() + #| let mut index = len + #| Iter::new(fn() { + #| guard index > 0 else { None } + #| index -= 1 + #| let c1 = self.unsafe_get(index) + #| if c1.is_trailing_surrogate() && index - 1 >= 0 { + #| let c2 = self.unsafe_get(index - 1) + #| if c2.is_leading_surrogate() { + #| index -= 1 + #| return Some(code_point_of_surrogate_pair(c2.to_int(), c1.to_int())) + #| } + #| } + #| Some(c1.unsafe_to_char()) + #| }) + #|} + #|fn String::offset_of_nth_char_forward( + #| self : String, + #| n : Int, + #| start_offset~ : Int, + #| end_offset~ : Int, + #|) -> Int? { + #| guard start_offset >= 0 && start_offset <= end_offset else { + #| abort("Invalid start index") + #| } + #| let (utf16_offset, char_count) = for utf16_offset = start_offset, char_count = 0; utf16_offset < + #| end_offset && + #| char_count < n; { + #| let c = self.unsafe_get(utf16_offset) + #| if c.is_leading_surrogate() { + #| continue utf16_offset + 2, char_count + 1 + #| } else { + #| continue utf16_offset + 1, char_count + 1 + #| } + #| } nobreak { + #| (utf16_offset, char_count) + #| } + #| if char_count < n || utf16_offset >= end_offset { + #| None + #| } else { + #| Some(utf16_offset) + #| } + #|} + #|fn String::offset_of_nth_char_backward( + #| self : String, + #| n : Int, + #| start_offset~ : Int, + #| end_offset~ : Int, + #|) -> Int? { + #| let (utf16_offset, char_count) = for utf16_offset = end_offset, char_count = 0; utf16_offset - + #| 1 >= + #| start_offset && + #| char_count < n; { + #| let c = self.unsafe_get(utf16_offset - 1) + #| if c.is_trailing_surrogate() { + #| continue utf16_offset - 2, char_count + 1 + #| } else { + #| continue utf16_offset - 1, char_count + 1 + #| } + #| } nobreak { + #| (utf16_offset, char_count) + #| } + #| if char_count < n || utf16_offset < start_offset { + #| None + #| } else { + #| Some(utf16_offset) + #| } + #|} + #|pub fn String::offset_of_nth_char( + #| self : String, + #| i : Int, + #| start_offset? : Int = 0, + #| end_offset? : Int, + #|) -> Int? { + #| let end_offset = if end_offset is Some(o) { o } else { self.length() } + #| if i >= 0 { + #| self.offset_of_nth_char_forward(i, start_offset~, end_offset~) + #| } else { + #| self.offset_of_nth_char_backward(-i, start_offset~, end_offset~) + #| } + #|} + #|pub fn String::char_length_eq( + #| self : String, + #| len : Int, + #| start_offset? : Int = 0, + #| end_offset? : Int, + #|) -> Bool { + #| let end_offset = if end_offset is Some(o) { o } else { self.length() } + #| for index = start_offset, count = 0 + #| index < end_offset && count < len + #| index = index + 1, count = count + 1 { + #| let c1 = self.unsafe_get(index) + #| if c1.is_leading_surrogate() && index + 1 < end_offset { + #| let c2 = self.unsafe_get(index + 1) + #| if c2.is_trailing_surrogate() { + #| continue index + 2, count + 1 + #| } else { + #| abort("invalid surrogate pair") + #| } + #| } + #| } nobreak { + #| count == len && index == end_offset + #| } + #|} + #|pub fn String::char_length_ge( + #| self : String, + #| len : Int, + #| start_offset? : Int = 0, + #| end_offset? : Int, + #|) -> Bool { + #| let end_offset = if end_offset is Some(o) { o } else { self.length() } + #| for index = start_offset, count = 0 + #| index < end_offset && count < len + #| index = index + 1, count = count + 1 { + #| let c1 = self.unsafe_get(index) + #| if c1.is_leading_surrogate() && index + 1 < end_offset { + #| let c2 = self.unsafe_get(index + 1) + #| if c2.is_trailing_surrogate() { + #| continue index + 2, count + 1 + #| } else { + #| abort("invalid surrogate pair") + #| } + #| } + #| } nobreak { + #| count >= len + #| } + #|} + #|pub fn String::lexical_compare(self : String, other : String) -> Int { + #| self[:].lexical_compare(other[:]) + #|} + #|pub fn String::from_array(chars : ArrayView[Char]) -> String { + #| let buf = StringBuilder::new(size_hint=chars.length() * 4) + #| for c in chars { + #| buf.write_char(c) + #| } + #| buf.to_string() + #|} + #|#alias(from_iterator, deprecated) + #|pub fn String::from_iter(iter : Iter[Char]) -> String { + #| let buf = StringBuilder::new() + #| for c in iter { + #| buf.write_char(c) + #| } + #| buf.to_string() + #|} + ), + "string_like.mbt": ( + #|pub trait ToStringView { + #| to_string_view(Self) -> StringView + #|} + #|pub impl ToStringView for String with to_string_view(self) -> StringView { + #| self[:] + #|} + #|pub impl ToStringView for StringView with to_string_view(self) -> StringView { + #| self + #|} + ), + "string_methods.mbt": ( + #|pub fn StringView::find(self : StringView, str : StringView) -> Int? { + #| if str.length() <= 4 { + #| brute_force_find(self, str) + #| } else { + #| boyer_moore_horspool_find(self, str) + #| } + #|} + #|fn brute_force_find(haystack : StringView, needle : StringView) -> Int? { + #| let haystack_len = haystack.length() + #| let needle_len = needle.length() + #| guard needle_len > 0 else { return Some(0) } + #| guard haystack_len >= needle_len else { return None } + #| let needle_first = needle.unsafe_get(0) + #| let forward_len = haystack_len - needle_len + #| for i = 0; i <= forward_len; { + #| if haystack.unsafe_get(i) != needle_first { + #| continue i + 1 + #| } + #| for j in 1.. Int? { + #| let haystack_len = haystack.length() + #| let needle_len = needle.length() + #| guard needle_len > 0 else { return Some(0) } + #| guard haystack_len >= needle_len else { return None } + #| let skip_table = FixedArray::make(1 << 8, needle_len) + #| for i in 0..<(needle_len - 1) { + #| skip_table[needle.unsafe_get(i).to_int() & 0xFF] = needle_len - 1 - i + #| } + #| for i = 0 + #| i <= haystack_len - needle_len + #| i = i + + #| skip_table[haystack.unsafe_get(i + needle_len - 1).to_int() & 0xFF] { + #| for j in 0..<=(needle_len - 1) { + #| if haystack.unsafe_get(i + j) != needle.unsafe_get(j) { + #| break + #| } + #| } nobreak { + #| return Some(i) + #| } + #| } + #| None + #|} + #|test "boyer_moore_horspool_find edge cases" { + #| inspect(boyer_moore_horspool_find("abc"[:], ""[:]), content="Some(0)") + #| inspect(boyer_moore_horspool_find("ab"[:], "abcd"[:]), content="None") + #|} + #|test "boyer_moore_horspool_rev_find edge cases" { + #| inspect(boyer_moore_horspool_rev_find("abc"[:], ""[:]), content="Some(3)") + #| inspect(boyer_moore_horspool_rev_find("ab"[:], "abcd"[:]), content="None") + #|} + #|pub fn String::find(self : String, str : StringView) -> Int? { + #| self[:].find(str) + #|} + #|test "find" { + #| inspect("hello".find("o"), content="Some(4)") + #| inspect("hello".find("l"), content="Some(2)") + #| inspect("hello".find("hello"), content="Some(0)") + #| inspect("hello".find("h"), content="Some(0)") + #| inspect("hello".find(""), content="Some(0)") + #| inspect("hello".find("world"), content="None") + #| inspect("".find(""), content="Some(0)") + #| inspect("".find("a"), content="None") + #| inspect("hello hello".find("hello"), content="Some(0)") + #| inspect("aaa".find("aa"), content="Some(0)") + #| inspect("😀😀".find("😀"), content="Some(0)") + #| inspect( + #| ("😀😀aa".repeat(20) + "😀😀😀😀").find("😀😀😀😀"), + #| content="Some(120)", + #| ) + #| inspect( + #| ("😀😀😀😀" + "😀😀aa".repeat(20)).find("😀😀😀😀"), + #| content="Some(0)", + #| ) + #|} + #|pub fn StringView::find_by(self : StringView, pred : (Char) -> Bool) -> Int? { + #| for i, c in self { + #| if pred(c) { + #| return Some(i) + #| } + #| } + #| None + #|} + #|pub fn String::find_by(self : String, pred : (Char) -> Bool) -> Int? { + #| self[:].find_by(pred) + #|} + #|test "find_by" { + #| inspect("hello".find_by(c => c == 'o'), content="Some(4)") + #| inspect("hello".find_by(c => c == 'l'), content="Some(2)") + #| inspect("hello".find_by(c => c == 'z'), content="None") + #| inspect("".find_by(c => c == 'a'), content="None") + #| inspect("hello".find_by(c => c is ('0'..='9')), content="None") + #| inspect("hello123".find_by(c => c is ('0'..='9')), content="Some(5)") + #| inspect("hello".find_by(c => c is ('A'..='Z')), content="None") + #| inspect("Hello".find_by(c => c is ('A'..='Z')), content="Some(0)") + #| inspect("αβγ".find_by(c => c == 'β'), content="Some(1)") + #| inspect("😀😁😂".find_by(c => c == '😂'), content="Some(2)") + #|} + #|pub fn StringView::rev_find(self : StringView, str : StringView) -> Int? { + #| if str.length() <= 4 { + #| brute_force_rev_find(self, str) + #| } else { + #| boyer_moore_horspool_rev_find(self, str) + #| } + #|} + #|fn brute_force_rev_find(haystack : StringView, needle : StringView) -> Int? { + #| let haystack_len = haystack.length() + #| let needle_len = needle.length() + #| guard needle_len > 0 else { return Some(haystack_len) } + #| guard haystack_len >= needle_len else { return None } + #| let needle_first = needle.unsafe_get(0) + #| for i = haystack_len - needle_len; i >= 0; { + #| if haystack.unsafe_get(i) != needle_first { + #| continue i - 1 + #| } + #| for j in 1.. Int? { + #| let haystack_len = haystack.length() + #| let needle_len = needle.length() + #| guard needle_len > 0 else { return Some(haystack_len) } + #| guard haystack_len >= needle_len else { return None } + #| let skip_table = FixedArray::make(1 << 8, needle_len) + #| for i in needle_len>..1 { + #| skip_table[needle.unsafe_get(i).to_int() & 0xFF] = i + #| } + #| for i = haystack_len - needle_len + #| i >= 0 + #| i = i - skip_table[haystack.unsafe_get(i).to_int() & 0xFF] { + #| for j in 0.. Int? { + #| self[:].rev_find(str) + #|} + #|test "rev_find" { + #| inspect("hello".rev_find("o"), content="Some(4)") + #| inspect("hello".rev_find("l"), content="Some(3)") + #| inspect("hello".rev_find("hello"), content="Some(0)") + #| inspect("hello".rev_find("h"), content="Some(0)") + #| inspect("hello".rev_find(""), content="Some(5)") + #| inspect("hello".rev_find("world"), content="None") + #| inspect("".rev_find(""), content="Some(0)") + #| inspect("".rev_find("a"), content="None") + #| inspect("hello hello".rev_find("hello"), content="Some(6)") + #| inspect("aaa".rev_find("aa"), content="Some(1)") + #| inspect("😀😀".rev_find("😀"), content="Some(2)") + #| inspect( + #| ("😀😀aa".repeat(20) + "😀😀😀😀").rev_find("😀😀😀😀"), + #| content="Some(120)", + #| ) + #| inspect( + #| ("😀😀😀😀" + "😀😀aa".repeat(20)).rev_find("😀😀😀😀"), + #| content="Some(4)", + #| ) + #|} + #|#alias(ends_with, deprecated) + #|pub fn StringView::has_suffix(self : StringView, str : StringView) -> Bool { + #| self.rev_find(str) is Some(i) && i == self.length() - str.length() + #|} + #|#alias(ends_with, deprecated) + #|pub fn String::has_suffix(self : String, str : StringView) -> Bool { + #| self[:].has_suffix(str) + #|} + #|test "has_suffix" { + #| inspect("hello".has_suffix("lo"), content="true") + #| inspect("hello".has_suffix("hello"), content="true") + #| inspect("hello".has_suffix(""), content="true") + #| inspect("hello".has_suffix("world"), content="false") + #| inspect("hello".has_suffix("hel"), content="false") + #| inspect("".has_suffix(""), content="true") + #| inspect("".has_suffix("a"), content="false") + #| inspect("hello world".has_suffix("world"), content="true") + #| inspect("😀😀".has_suffix("😀"), content="true") + #| inspect("😀😀".has_suffix("😀😀"), content="true") + #|} + #|#alias(starts_with, deprecated) + #|pub fn StringView::has_prefix(self : StringView, str : StringView) -> Bool { + #| self.find(str) is Some(i) && i == 0 + #|} + #|#alias(starts_with, deprecated) + #|pub fn String::has_prefix(self : String, str : StringView) -> Bool { + #| self[:].has_prefix(str) + #|} + #|test "has_prefix" { + #| inspect("hello".has_prefix("h"), content="true") + #| inspect("hello".has_prefix("he"), content="true") + #| inspect("hello".has_prefix(""), content="true") + #| inspect("hello".has_prefix("world"), content="false") + #| inspect("hello".has_prefix("lo"), content="false") + #| inspect("".has_prefix(""), content="true") + #| inspect("".has_prefix("a"), content="false") + #| inspect("😀hello".has_prefix("😀"), content="true") + #| inspect("😀😃hello".has_prefix("😀😃"), content="true") + #| inspect("😀hello".has_prefix("😃"), content="false") + #| inspect("hello😀".has_prefix("😀"), content="false") + #|} + #|#alias(chop_suffix) + #|pub fn String::strip_suffix(self : String, suffix : StringView) -> StringView? { + #| self[:].strip_suffix(suffix) + #|} + #|test "strip_prefix" { + #| inspect("hello world".strip_prefix("hello "), content="Some(\"world\")") + #| inspect("hello world".strip_prefix("hi "), content="None") + #| inspect("hello".strip_prefix("hello"), content="Some(\"\")") + #| inspect("".strip_prefix(""), content="Some(\"\")") + #| inspect("".strip_prefix("a"), content="None") + #| inspect("abc".strip_prefix(""), content="Some(\"abc\")") + #| inspect("😀hello".strip_prefix("😀"), content="Some(\"hello\")") + #| inspect("😀😃hello".strip_prefix("😀😃"), content="Some(\"hello\")") + #|} + #|test "strip_suffix" { + #| inspect("hello world".strip_suffix(" world"), content="Some(\"hello\")") + #| inspect("hello world".strip_suffix(" moon"), content="None") + #| inspect("hello".strip_suffix("hello"), content="Some(\"\")") + #| inspect("".strip_suffix(""), content="Some(\"\")") + #| inspect("".strip_suffix("a"), content="None") + #| inspect("abc".strip_suffix(""), content="Some(\"abc\")") + #| inspect("hello😀".strip_suffix("😀"), content="Some(\"hello\")") + #| inspect("hello😀😃".strip_suffix("😀😃"), content="Some(\"hello\")") + #|} + #|#alias(chop_prefix) + #|pub fn String::strip_prefix(self : String, prefix : StringView) -> StringView? { + #| self[:].strip_prefix(prefix) + #|} + #|#alias(chop_prefix) + #|pub fn StringView::strip_prefix( + #| self : StringView, + #| prefix : StringView, + #|) -> StringView? { + #| let prefix_len = prefix.length() + #| if self.length() >= prefix_len && self.view(end_offset=prefix_len) == prefix { + #| Some(self.view(start_offset=prefix_len)) + #| } else { + #| None + #| } + #|} + #|#alias(chop_suffix) + #|pub fn StringView::strip_suffix( + #| self : StringView, + #| suffix : StringView, + #|) -> StringView? { + #| let self_len = self.length() + #| let suffix_len = suffix.length() + #| if self_len >= suffix_len && + #| self.view(start_offset=self_len - suffix_len) == suffix { + #| Some(self.view(end_offset=self_len - suffix_len)) + #| } else { + #| None + #| } + #|} + #|pub fn StringView::to_array(self : StringView) -> Array[Char] { + #| self + #| .iter() + #| .fold(init=Array::new(capacity=self.length()), (rv, c) => { + #| rv.push(c) + #| rv + #| }) + #|} + #|#deprecated("Check `@encoding/utf8.encode`") + #|#coverage.skip + #|pub fn StringView::to_bytes(self : StringView) -> Bytes { + #| let array = FixedArray::make(self.length() * 2, Byte::default()) + #| array.blit_from_string(0, self.data(), self.start_offset(), self.length()) + #| array |> unsafe_to_bytes + #|} + #|test "View::strip_prefix" { + #| let view = "hello world"[:] + #| inspect(view.strip_prefix("hello "), content="Some(\"world\")") + #| inspect(view.strip_prefix("hi "), content="None") + #| inspect(view.strip_prefix("hello world"), content="Some(\"\")") + #| inspect(view.strip_prefix(""), content="Some(\"hello world\")") + #| let empty_view = ""[:] + #| inspect(empty_view.strip_prefix(""), content="Some(\"\")") + #| inspect(empty_view.strip_prefix("a"), content="None") + #| let unicode_view = "😀hello😃"[:] + #| inspect(unicode_view.strip_prefix("😀"), content="Some(\"hello😃\")") + #| inspect(unicode_view.strip_prefix("😃"), content="None") + #|} + #|test "View::strip_suffix" { + #| let view = "hello world"[:] + #| inspect(view.strip_suffix(" world"), content="Some(\"hello\")") + #| inspect(view.strip_suffix(" moon"), content="None") + #| inspect(view.strip_suffix("hello world"), content="Some(\"\")") + #| inspect(view.strip_suffix(""), content="Some(\"hello world\")") + #| let empty_view = ""[:] + #| inspect(empty_view.strip_suffix(""), content="Some(\"\")") + #| inspect(empty_view.strip_suffix("a"), content="None") + #| let unicode_view = "😀hello😃"[:] + #| inspect(unicode_view.strip_suffix("😃"), content="Some(\"😀hello\")") + #| inspect(unicode_view.strip_suffix("😀"), content="None") + #|} + #|test "View::to_array" { + #| let view = "Hello🤣"[:] + #| let chars = view.to_array() + #| assert_eq(chars, ['H', 'e', 'l', 'l', 'o', '🤣']) + #| let empty_view = ""[:] + #| let empty_chars = empty_view.to_array() + #| assert_eq(empty_chars, []) + #| let sub_view = "Hello World"[6:11] // "World" + #| let sub_chars = sub_view.to_array() + #| assert_eq(sub_chars, ['W', 'o', 'r', 'l', 'd']) + #|} + #|pub fn StringView::contains(self : StringView, str : StringView) -> Bool { + #| self.find(str) is Some(_) + #|} + #|pub fn String::contains(self : String, str : StringView) -> Bool { + #| self[:].contains(str) + #|} + #|pub fn StringView::contains_any(self : StringView, chars~ : StringView) -> Bool { + #| match chars { + #| [] => false + #| [c] => self.contains_char(c) // specialize for single character + #| _ => + #| for c in self { + #| if chars.contains_char(c) { + #| break true + #| } + #| } nobreak { + #| false + #| } + #| } + #|} + #|pub fn String::contains_any(self : String, chars~ : StringView) -> Bool { + #| self[:].contains_any(chars~) + #|} + #|test "contains" { + #| inspect("hello".contains("o"), content="true") + #| inspect("hello".contains("l"), content="true") + #| inspect("hello".contains("hello"), content="true") + #| inspect("hello".contains("h"), content="true") + #| inspect("hello".contains(""), content="true") + #| inspect("hello".contains("world"), content="false") + #| inspect("".contains(""), content="true") + #| inspect("".contains("a"), content="false") + #| inspect("hello hello".contains("hello"), content="true") + #| inspect("aaa".contains("aa"), content="true") + #| inspect("😀😀".contains("😀"), content="true") + #|} + #|test "contains_any" { + #| inspect("hello".contains_any(chars="h"), content="true") + #| inspect("hello".contains_any(chars="xyz"), content="false") + #| inspect("hello".contains_any(chars=""), content="false") + #| inspect("".contains_any(chars="abc"), content="false") + #| inspect("😀😃".contains_any(chars="😄😀"), content="true") + #| inspect("hello"[:].contains_any(chars="eo"), content="true") + #|} + #|pub fn StringView::contains_char(self : StringView, c : Char) -> Bool { + #| let len = self.length() + #| guard len > 0 else { return false } + #| let c = c.to_int() + #| if c <= 0xFFFF { + #| for i in 0..= 2 else { return false } + #| let adj = c - 0x10000 + #| let high = 0xD800 + (adj >> 10) + #| let low = 0xDC00 + (adj & 0x3FF) + #| for i = 0; i < len - 1; { + #| if self.unsafe_get(i).to_int() == high { + #| if self.unsafe_get(i + 1).to_int() == low { + #| return true + #| } + #| continue i + 2 + #| } + #| continue i + 1 + #| } + #| } + #| false + #|} + #|pub fn String::contains_char(self : String, c : Char) -> Bool { + #| self[:].contains_char(c) + #|} + #|test "contains_char" { + #| inspect("hello".contains_char('h'), content="true") + #| inspect("hello".contains_char('e'), content="true") + #| inspect("hello".contains_char('l'), content="true") + #| inspect("hello".contains_char('o'), content="true") + #| inspect("hello".contains_char('x'), content="false") + #| inspect("".contains_char('a'), content="false") + #| inspect("hello world".contains_char(' '), content="true") + #| inspect("hello world".contains_char('w'), content="true") + #| inspect("😀😀".contains_char('😀'), content="true") + #| inspect("😀😀".contains_char('😃'), content="false") + #| inspect("hello".contains_char((104).unsafe_to_char()), content="true") // 'h' is 104 in ASCII + #|} + #|#label_migration(chars, alias=char_set) + #|pub fn StringView::trim_start( + #| self : StringView, + #| chars? : StringView = "\t\n\r ", + #|) -> StringView { + #| loop self { + #| [] as v => v + #| [c, .. rest] as v => if chars.contains_char(c) { continue rest } else { v } + #| } + #|} + #|#label_migration(chars, alias=char_set) + #|pub fn String::trim_start( + #| self : String, + #| chars? : StringView = "\t\n\r ", + #|) -> StringView { + #| self[:].trim_start(chars~) + #|} + #|test "trim_start" { + #| inspect("hello".trim_start(chars="h"), content="ello") + #| inspect("hello".trim_start(chars="he"), content="llo") + #| inspect("hello".trim_start(chars="eh"), content="llo") + #| inspect("hello".trim_start(chars="x"), content="hello") + #| inspect("hello".trim_start(chars=""), content="hello") + #| inspect("".trim_start(chars="a"), content="") + #| inspect(" hello".trim_start(chars=" "), content="hello") + #| inspect("hello world".trim_start(chars="helo"), content=" world") + #| inspect("😀😀hello".trim_start(chars="😀"), content="hello") + #| inspect("😀😃hello".trim_start(chars="😀😃"), content="hello") + #| inspect("aaaabc".trim_start(chars="a"), content="bc") + #| inspect("aaaa".trim_start(chars="a"), content="") + #|} + #|#label_migration(chars, alias=char_set) + #|pub fn StringView::trim_end( + #| self : StringView, + #| chars? : StringView = "\t\n\r ", + #|) -> StringView { + #| loop self { + #| [] as v => v + #| [.. rest, c] as v => if chars.contains_char(c) { continue rest } else { v } + #| } + #|} + #|#label_migration(chars, alias=char_set) + #|pub fn String::trim_end( + #| self : String, + #| chars? : StringView = "\t\n\r ", + #|) -> StringView { + #| self[:].trim_end(chars~) + #|} + #|test "trim_end" { + #| inspect("hello".trim_end(chars="o"), content="hell") + #| inspect("hello".trim_end(chars="lo"), content="he") + #| inspect("hello".trim_end(chars="x"), content="hello") + #| inspect("hello".trim_end(chars=""), content="hello") + #| inspect("".trim_end(chars="a"), content="") + #| inspect("hello ".trim_end(chars=" "), content="hello") + #| inspect("hello world".trim_end(chars="dlrow "), content="he") + #| inspect("hello😀😀".trim_end(chars="😀"), content="hello") + #| inspect("hello😀😃".trim_end(chars="😀😃"), content="hello") + #| inspect("abcccc".trim_end(chars="c"), content="ab") + #| inspect("cccc".trim_end(chars="c"), content="") + #|} + #|#label_migration(chars, alias=char_set) + #|pub fn StringView::trim( + #| self : StringView, + #| chars? : StringView = "\t\n\r ", + #|) -> StringView { + #| self.trim_start(chars~).trim_end(chars~) + #|} + #|#label_migration(chars, alias=char_set) + #|pub fn String::trim( + #| self : String, + #| chars? : StringView = "\t\n\r ", + #|) -> StringView { + #| self[:].trim(chars~) + #|} + #|test "trim" { + #| inspect("hello".trim(chars="h"), content="ello") + #| inspect("hello".trim(chars="o"), content="hell") + #| inspect("hello".trim(chars="ho"), content="ell") + #| inspect("hello".trim(chars="oh"), content="ell") + #| inspect("hello".trim(chars="x"), content="hello") + #| inspect("hello".trim(chars=""), content="hello") + #| inspect("".trim(chars="a"), content="") + #| inspect(" hello ".trim(chars=" "), content="hello") + #| inspect("hello world".trim(chars="hd"), content="ello worl") + #| inspect("😀hello😀".trim(chars="😀"), content="hello") + #| inspect("😀😃hello😀😃".trim(chars="😀😃"), content="hello") + #| inspect("aaaabcaaa".trim(chars="a"), content="bc") + #| inspect("aaaa".trim(chars="a"), content="") + #| inspect(" hello world ".trim(chars=" "), content="hello world") + #| inspect("abcabc".trim(chars="abc"), content="") + #|} + #|#deprecated("Use `trim` with default whitespace characters instead") + #|pub fn StringView::trim_space(self : StringView) -> StringView { + #| self.trim() + #|} + #|#deprecated("Use `trim` with default whitespace characters instead") + #|pub fn String::trim_space(self : String) -> StringView { + #| self.trim() + #|} + #|test "trim whitespace for string" { + #| inspect("hello".trim(), content="hello") + #| inspect(" hello ".trim(), content="hello") + #| inspect("hello ".trim(), content="hello") + #| inspect(" hello".trim(), content="hello") + #| inspect("\t\nhello\r\n".trim(), content="hello") + #| inspect(" hello world ".trim(), content="hello world") + #| inspect(" ".trim(), content="") + #| inspect("\n\r\t".trim(), content="") + #| inspect("".trim(), content="") + #| inspect(" hello\nworld\t".trim(), content="hello\nworld") + #|} + #|pub fn StringView::is_empty(self : StringView) -> Bool { + #| self.length() == 0 + #|} + #|pub fn String::is_empty(self : String) -> Bool { + #| self == "" + #|} + #|test "is_empty" { + #| inspect("".is_empty(), content="true") + #| inspect("hello".is_empty(), content="false") + #| inspect(" ".is_empty(), content="false") + #| inspect("\n".is_empty(), content="false") + #| inspect("\t".is_empty(), content="false") + #| inspect(" ".is_empty(), content="false") + #| let s = "hello" + #| let empty_view = s[0:0] + #| let non_empty_view = s[0:3] + #| inspect(empty_view.is_empty(), content="true") + #| inspect(non_empty_view.is_empty(), content="false") + #|} + #|pub fn StringView::is_blank(self : StringView) -> Bool { + #| self.trim().is_empty() + #|} + #|pub fn String::is_blank(self : String) -> Bool { + #| self[:].is_blank() + #|} + #|test "is_blank" { + #| inspect("".is_blank(), content="true") + #| inspect("hello".is_blank(), content="false") + #| inspect(" ".is_blank(), content="true") + #| inspect("\n".is_blank(), content="true") + #| inspect("\t".is_blank(), content="true") + #| inspect(" ".is_blank(), content="true") + #| inspect(" \n\t\r ".is_blank(), content="true") + #| inspect("hello world".is_blank(), content="false") + #| inspect(" hello ".is_blank(), content="false") + #| let s = " hello " + #| let blank_view = s[0:3] // " " + #| let non_blank_view = s[3:8] // "hello" + #| inspect(blank_view.is_blank(), content="true") + #| inspect(non_blank_view.is_blank(), content="false") + #|} + #|pub fn StringView::pad_start( + #| self : StringView, + #| total_width : Int, + #| padding_char : Char, + #|) -> String { + #| let len = self.length() + #| guard len < total_width else { return self.to_string() } + #| let padding = String::make(total_width - len, padding_char) + #| [..padding, ..self] + #|} + #|pub fn String::pad_start( + #| self : String, + #| total_width : Int, + #| padding_char : Char, + #|) -> String { + #| let len = self.length() + #| guard len < total_width else { return self } + #| let padding = String::make(total_width - len, padding_char) + #| [..padding, ..self] + #|} + #|test "pad_start" { + #| inspect("2".pad_start(3, '0'), content="002") + #| inspect("abc".pad_start(5, 'x'), content="xxabc") + #| inspect("hello".pad_start(4, ' '), content="hello") // No padding needed + #| inspect("".pad_start(3, '-'), content="---") + #| inspect("test".pad_start(8, '*'), content="****test") + #| inspect("123".pad_start(6, '0'), content="000123") + #| let s = "hello" + #| let view = s[2:5] // "llo" + #| inspect(view.pad_start(5, 'x'), content="xxllo") + #| inspect("🌟".pad_start(3, '✨'), content="✨🌟") + #| inspect("abc".pad_start(0, 'x'), content="abc") // width less than string length + #| inspect("abc".pad_start(3, 'x'), content="abc") // width equal to string length + #|} + #|pub fn StringView::pad_end( + #| self : StringView, + #| total_width : Int, + #| padding_char : Char, + #|) -> String { + #| let len = self.length() + #| guard len < total_width else { return self.to_string() } + #| let padding = String::make(total_width - len, padding_char) + #| [..self, ..padding] + #|} + #|pub fn String::pad_end( + #| self : String, + #| total_width : Int, + #| padding_char : Char, + #|) -> String { + #| let len = self.length() + #| guard len < total_width else { return self } + #| let padding = String::make(total_width - len, padding_char) + #| [..self, ..padding] + #|} + #|test "pad_end" { + #| inspect("2".pad_end(3, '0'), content="200") + #| inspect("abc".pad_end(5, 'x'), content="abcxx") + #| inspect("hello".pad_end(4, ' '), content="hello") // No padding needed + #| inspect("".pad_end(3, '-'), content="---") + #| inspect("test".pad_end(8, '*'), content="test****") + #| inspect("123".pad_end(6, '0'), content="123000") + #| let s = "hello" + #| let view = s[2:5] // "llo" + #| inspect(view.pad_end(5, 'x'), content="lloxx") + #| inspect("🌟".pad_end(3, '✨'), content="🌟✨") + #| inspect("abc".pad_end(0, 'x'), content="abc") // width less than string length + #| inspect("abc".pad_end(3, 'x'), content="abc") // width equal to string length + #|} + #|pub fn StringView::repeat(self : StringView, n : Int) -> StringView { + #| match n { + #| _..=0 => "" + #| 1 => self + #| _ => { + #| let len = self.length() + #| let buf = StringBuilder::new(size_hint=len * n) + #| let str = self.to_string() + #| for _ in 0.. String { + #| match n { + #| _..=0 => "" + #| 1 => self + #| _ => { + #| let len = self.length() + #| let buf = StringBuilder::new(size_hint=len * n) + #| let str = self.to_string() + #| for _ in 0.. String { + #| let buf = StringBuilder::new(size_hint=self.length()) + #| for c in self.rev_iter() { + #| buf.write_char(c) + #| } + #| buf.to_string() + #|} + #|pub fn String::rev(self : String) -> String { + #| self[:].rev() + #|} + #|test "rev" { + #| inspect("hello".rev(), content="olleh") + #| inspect("".rev(), content="") + #| inspect("abc".rev(), content="cba") + #| inspect("😀😃".rev(), content="😃😀") + #|} + #|pub fn StringView::split( + #| self : StringView, + #| sep : StringView, + #|) -> Iter[StringView] { + #| let sep_len = sep.length() + #| if sep_len == 0 { + #| return self.iter().map(c => c.to_string().view()) + #| } + #| let mut remaining = Some(self) + #| Iter::new(() => { + #| guard remaining is Some(view) else { None } + #| guard view.find(sep) is Some(end) else { + #| remaining = None + #| Some(view) + #| } + #| remaining = Some(view.view(start_offset=end + sep_len)) + #| Some(view.view(end_offset=end)) + #| }) + #|} + #|pub fn String::split(self : String, sep : StringView) -> Iter[StringView] { + #| self[:].split(sep) + #|} + #|pub fn StringView::split_once( + #| self : StringView, + #| needle : StringView, + #|) -> (StringView, StringView)? { + #| match self.find(needle) { + #| Some(index) => + #| Some( + #| ( + #| self.view(end_offset=index), + #| self.view(start_offset=index + needle.length()), + #| ), + #| ) + #| None => None + #| } + #|} + #|pub fn String::split_once( + #| self : String, + #| needle : StringView, + #|) -> (StringView, StringView)? { + #| self[:].split_once(needle) + #|} + #|pub fn StringView::before( + #| self : StringView, + #| needle : StringView, + #|) -> StringView? { + #| match self.find(needle) { + #| Some(index) => Some(self.view(end_offset=index)) + #| None => None + #| } + #|} + #|pub fn String::before(self : String, needle : StringView) -> StringView? { + #| self[:].before(needle) + #|} + #|pub fn StringView::after(self : StringView, needle : StringView) -> StringView? { + #| match self.find(needle) { + #| Some(index) => Some(self.view(start_offset=index + needle.length())) + #| None => None + #| } + #|} + #|pub fn String::after(self : String, needle : StringView) -> StringView? { + #| self[:].after(needle) + #|} + #|pub fn StringView::rev_split_once( + #| self : StringView, + #| needle : StringView, + #|) -> (StringView, StringView)? { + #| match self.rev_find(needle) { + #| Some(index) => + #| Some( + #| ( + #| self.view(end_offset=index), + #| self.view(start_offset=index + needle.length()), + #| ), + #| ) + #| None => None + #| } + #|} + #|pub fn String::rev_split_once( + #| self : String, + #| needle : StringView, + #|) -> (StringView, StringView)? { + #| self[:].rev_split_once(needle) + #|} + #|pub fn StringView::rev_before( + #| self : StringView, + #| needle : StringView, + #|) -> StringView? { + #| match self.rev_find(needle) { + #| Some(index) => Some(self.view(end_offset=index)) + #| None => None + #| } + #|} + #|pub fn String::rev_before(self : String, needle : StringView) -> StringView? { + #| self[:].rev_before(needle) + #|} + #|pub fn StringView::rev_after( + #| self : StringView, + #| needle : StringView, + #|) -> StringView? { + #| match self.rev_find(needle) { + #| Some(index) => Some(self.view(start_offset=index + needle.length())) + #| None => None + #| } + #|} + #|pub fn String::rev_after(self : String, needle : StringView) -> StringView? { + #| self[:].rev_after(needle) + #|} + #|test "split" { + #| assert_eq("a,b,c".split(",").map(x => x.to_string()).collect(), [ + #| "a", "b", "c", + #| ]) + #| assert_eq("a,b,c".split("").map(x => x.to_string()).collect(), [ + #| "a", ",", "b", ",", "c", + #| ]) + #| assert_eq( + #| "apple::orange::banana".split("::").map(x => x.to_string()).collect(), + #| ["apple", "orange", "banana"], + #| ) + #| assert_eq("abc".split("").map(x => x.to_string()).collect(), ["a", "b", "c"]) + #| assert_eq("hello".split(",").map(x => x.to_string()).collect(), ["hello"]) + #| assert_eq(",a,b,c".split(",").map(x => x.to_string()).collect(), [ + #| "", "a", "b", "c", + #| ]) + #| assert_eq("a,b,c,".split(",").map(x => x.to_string()).collect(), [ + #| "a", "b", "c", "", + #| ]) + #| assert_eq("a,b,c".split("").map(x => x.to_string()).collect(), [ + #| "a", ",", "b", ",", "c", + #| ]) + #| assert_eq("".split("").map(x => x.to_string()).collect(), []) + #| assert_eq("".split(",").map(x => x.to_string()).collect(), [""]) + #| assert_eq("😀,😃,😄".split(",").map(x => x.to_string()).collect(), [ + #| "😀", "😃", "😄", + #| ]) + #| assert_eq("a😀b😀c".split("😀").map(x => x.to_string()).collect(), [ + #| "a", "b", "c", + #| ]) + #|} + #|test "split_once before after" { + #| inspect("a=b=c".split_once("="), content="Some((\"a\", \"b=c\"))") + #| inspect("a=b=c".before("="), content="Some(\"a\")") + #| inspect("a=b=c".after("="), content="Some(\"b=c\")") + #| inspect("nope".split_once("="), content="None") + #| inspect("nope".before("="), content="None") + #| inspect("nope".after("="), content="None") + #| inspect("".split_once(""), content="Some((\"\", \"\"))") + #| inspect("".before(""), content="Some(\"\")") + #| inspect("".after(""), content="Some(\"\")") + #| inspect("hello".split_once(""), content="Some((\"\", \"hello\"))") + #| inspect("hello".before(""), content="Some(\"\")") + #| inspect("hello".after(""), content="Some(\"hello\")") + #| inspect("😊::🚀".split_once("::"), content="Some((\"😊\", \"🚀\"))") + #|} + #|test "rev_split_once rev_before rev_after" { + #| inspect("a=b=c".rev_split_once("="), content="Some((\"a=b\", \"c\"))") + #| inspect("a=b=c".rev_before("="), content="Some(\"a=b\")") + #| inspect("a=b=c".rev_after("="), content="Some(\"c\")") + #| inspect("nope".rev_split_once("="), content="None") + #| inspect("nope".rev_before("="), content="None") + #| inspect("nope".rev_after("="), content="None") + #| inspect("a/b/c.txt".rev_before("/"), content="Some(\"a/b\")") + #| inspect("a/b/c.txt".rev_after("/"), content="Some(\"c.txt\")") + #| inspect("one=two".rev_split_once("="), content="Some((\"one\", \"two\"))") + #| inspect( + #| "😊::🚀::⭐".rev_split_once("::"), + #| content="Some((\"😊::🚀\", \"⭐\"))", + #| ) + #|} + #|pub fn StringView::replace( + #| self : StringView, + #| old~ : StringView, + #| new~ : StringView, + #|) -> StringView { + #| match self.find(old) { + #| Some(end) => + #| [ + #| ..self.view(end_offset=end), + #| ..new, + #| ..self.view(start_offset=end + old.length()), + #| ] + #| None => self + #| } + #|} + #|pub fn String::replace( + #| self : String, + #| old~ : StringView, + #| new~ : StringView, + #|) -> String { + #| match self.find(old) { + #| Some(end) => + #| [ + #| ..self.view(end_offset=end), + #| ..new, + #| ..self.view(start_offset=end + old.length()), + #| ] + #| None => self + #| } + #|} + #|test "replace" { + #| inspect("hello".replace(old="o", new="a"), content="hella") + #| inspect("hello".replace(old="l", new="a"), content="healo") + #| inspect("hello".replace(old="hello", new="a"), content="a") + #| inspect("hello".replace(old="h", new="a"), content="aello") + #| inspect("hello".replace(old="", new="a"), content="ahello") + #| inspect("hello".replace(old="world", new="a"), content="hello") + #| inspect("".replace(old="", new="a"), content="a") + #|} + #|pub fn StringView::replace_all( + #| self : StringView, + #| old~ : StringView, + #| new~ : StringView, + #|) -> StringView { + #| let len = self.length() + #| let buf = StringBuilder::new(size_hint=len) + #| let old_len = old.length() + #| let new = new.to_string() + #| if old_len == 0 { + #| buf.write_string(new) + #| for c in self { + #| buf.write_char(c) + #| buf.write_string(new) + #| } + #| buf.to_string() + #| } else { + #| let first_end = self.find(old) + #| if first_end is Some(end) { + #| for view = self, end = end { + #| let seg = view.view(end_offset=end) + #| buf.write_substring(seg.data(), seg.start_offset(), seg.length()) + #| buf.write_string(new) + #| guard end + old_len <= len else { break } + #| let next_view = view.view(start_offset=end + old_len) + #| guard next_view.find(old) is Some(next_end) else { + #| buf.write_substring( + #| next_view.data(), + #| next_view.start_offset(), + #| next_view.length(), + #| ) + #| break + #| } + #| continue next_view, next_end + #| } + #| buf.to_string() + #| } else { + #| self + #| } + #| } + #|} + #|pub fn String::replace_all( + #| self : String, + #| old~ : StringView, + #| new~ : StringView, + #|) -> String { + #| let len = self.length() + #| let buf = StringBuilder::new(size_hint=len) + #| let old_len = old.length() + #| let new = new.to_string() + #| if old_len == 0 { + #| buf.write_string(new) + #| for c in self { + #| buf.write_char(c) + #| buf.write_string(new) + #| } + #| buf.to_string() + #| } else { + #| let first_end = self.find(old) + #| if first_end is Some(end) { + #| for view = self[:], end = end { + #| let seg = view.view(end_offset=end) + #| buf.write_substring(seg.data(), seg.start_offset(), seg.length()) + #| buf.write_string(new) + #| guard end + old_len <= len else { break } + #| let next_view = view.view(start_offset=end + old_len) + #| guard next_view.find(old) is Some(next_end) else { + #| buf.write_substring( + #| next_view.data(), + #| next_view.start_offset(), + #| next_view.length(), + #| ) + #| break + #| } + #| continue next_view, next_end + #| } + #| buf.to_string() + #| } else { + #| self + #| } + #| } + #|} + #|test "replace_all" { + #| assert_eq("hello".replace_all(old="o", new="a"), "hella") + #| assert_eq("hello".replace_all(old="l", new="a"), "heaao") + #| assert_eq("hello".replace_all(old="ll", new="rr"), "herro") + #| assert_eq("hello".replace_all(old="hello", new="world"), "world") + #| assert_eq("hello hello hello".replace_all(old="hello", new="hi"), "hi hi hi") + #| assert_eq( + #| "hello hello helloi".replace_all(old="hello", new="hi"), + #| "hi hi hii", + #| ) + #| assert_eq( + #| "hi hi hii".replace_all(old="hi", new="hello"), + #| "hello hello helloi", + #| ) + #| assert_eq("hello".replace_all(old="", new="a"), "ahaealalaoa") + #| assert_eq("hello".replace_all(old="world", new="a"), "hello") + #| assert_eq("".replace_all(old="", new="a"), "a") + #| assert_eq("aaa".replace_all(old="a", new="b"), "bbb") + #| assert_eq("aaa".replace_all(old="a", new="bb"), "bbbbbb") + #| assert_eq("aaa".replace_all(old="aa", new="b"), "ba") + #| assert_eq("🤣🤣🤣".replace_all(old="🤣", new="😊"), "😊😊😊") + #| assert_eq("abc123abc".replace_all(old="abc", new="xyz"), "xyz123xyz") + #| assert_eq("abcabcabc".replace_all(old="abc", new=""), "") + #| assert_eq("abc".replace_all(old="abc", new=""), "") + #| assert_eq("abc".replace_all(old="", new="x"), "xaxbxcx") + #|} + #|test "String::replace_all boundary cases" { + #| assert_eq("helloworld".replace_all(old="world", new="X"), "helloX") + #| assert_eq("abcdef".replace_all(old="def", new="XYZ"), "abcXYZ") + #| assert_eq("abcabc".replace_all(old="abc", new="X"), "XX") + #| assert_eq("test".replace_all(old="test", new="done"), "done") + #| assert_eq("remove_me".replace_all(old="_me", new=""), "remove") + #|} + #|test "View::replace_all" { + #| assert_eq("hello"[:].replace_all(old="o", new="a"), "hella") + #| assert_eq("hello"[:].replace_all(old="l", new="a"), "heaao") + #| assert_eq("hello"[:].replace_all(old="ll", new="rr"), "herro") + #| assert_eq("hello"[:].replace_all(old="hello", new="world"), "world") + #| assert_eq( + #| "hello hello hello"[:].replace_all(old="hello", new="hi"), + #| "hi hi hi", + #| ) + #| assert_eq( + #| "hello hello helloi"[:].replace_all(old="hello", new="hi"), + #| "hi hi hii", + #| ) + #| assert_eq( + #| "hi hi hii"[:].replace_all(old="hi", new="hello"), + #| "hello hello helloi", + #| ) + #| assert_eq("hello"[:].replace_all(old="", new="a"), "ahaealalaoa") + #| assert_eq("hello"[:].replace_all(old="world", new="a"), "hello") + #| assert_eq(""[:].replace_all(old="", new="a"), "a") + #| assert_eq("aaa"[:].replace_all(old="a", new="b"), "bbb") + #| assert_eq("aaa"[:].replace_all(old="a", new="bb"), "bbbbbb") + #| assert_eq("aaa"[:].replace_all(old="aa", new="b"), "ba") + #| assert_eq( + #| "🤣🤣🤣"[:].replace_all(old="🤣", new="😊"), + #| "😊😊😊", + #| ) + #| assert_eq("abc123abc"[:].replace_all(old="abc", new="xyz"), "xyz123xyz") + #| assert_eq("abcabcabc"[:].replace_all(old="abc", new=""), "") + #| assert_eq("abc"[:].replace_all(old="abc", new=""), "") + #| assert_eq("abc"[:].replace_all(old="", new="x"), "xaxbxcx") + #|} + #|test "View::replace_all boundary cases" { + #| assert_eq("abcabc"[:].replace_all(old="abc", new="X"), "XX") + #| assert_eq("aaaa"[:].replace_all(old="aa", new="b"), "bb") + #| assert_eq("hello"[:].replace_all(old="lo", new="X"), "helX") + #| assert_eq("a"[:].replace_all(old="a", new=""), "") + #| inspect("Testing boundary condition", content="Testing boundary condition") + #|} + #|pub fn StringView::to_lower(self : StringView) -> StringView { + #| guard self.find_by(x => x.is_ascii_uppercase()) is Some(idx) else { + #| return self + #| } + #| let buf = StringBuilder::new(size_hint=self.length()) + #| let head = self.view(end_offset=idx) + #| buf.write_substring(head.data(), head.start_offset(), head.length()) + #| for c in self.view(start_offset=idx) { + #| if c.is_ascii_uppercase() { + #| buf.write_char((c.to_int() + 32).unsafe_to_char()) + #| } else { + #| buf.write_char(c) + #| } + #| } + #| buf.to_string() + #|} + #|pub fn String::to_lower(self : String) -> String { + #| guard self.find_by(x => x.is_ascii_uppercase()) is Some(idx) else { + #| return self + #| } + #| let buf = StringBuilder::new(size_hint=self.length()) + #| let head = self.view(end_offset=idx) + #| buf.write_substring(head.data(), head.start_offset(), head.length()) + #| for c in self.view(start_offset=idx) { + #| if c.is_ascii_uppercase() { + #| buf.write_char((c.to_int() + 32).unsafe_to_char()) + #| } else { + #| buf.write_char(c) + #| } + #| } + #| buf.to_string() + #|} + #|test "to_lower" { + #| assert_eq("Hello".to_lower(), "hello") + #| assert_eq("HELLO".to_lower(), "hello") + #| assert_eq("Hello, World!".to_lower(), "hello, world!") + #|} + #|test "View::to_lower" { + #| assert_eq("Hello"[:].to_lower(), "hello") + #| assert_eq("HELLO"[:].to_lower(), "hello") + #| assert_eq("Hello, World!"[:].to_lower(), "hello, world!") + #|} + #|pub fn StringView::to_upper(self : StringView) -> StringView { + #| guard self.find_by(c => c.is_ascii_lowercase()) is Some(idx) else { + #| return self + #| } + #| let buf = StringBuilder::new(size_hint=self.length()) + #| let head = self.view(end_offset=idx) + #| buf.write_substring(head.data(), head.start_offset(), head.length()) + #| for c in self.view(start_offset=idx) { + #| if c.is_ascii_lowercase() { + #| buf.write_char((c.to_int() - 32).unsafe_to_char()) + #| } else { + #| buf.write_char(c) + #| } + #| } + #| buf.to_string() + #|} + #|pub fn String::to_upper(self : String) -> String { + #| guard self.find_by(c => c.is_ascii_lowercase()) is Some(idx) else { + #| return self + #| } + #| let buf = StringBuilder::new(size_hint=self.length()) + #| let head = self.view(end_offset=idx) + #| buf.write_substring(head.data(), head.start_offset(), head.length()) + #| for c in self.view(start_offset=idx) { + #| if c.is_ascii_lowercase() { + #| buf.write_char((c.to_int() - 32).unsafe_to_char()) + #| } else { + #| buf.write_char(c) + #| } + #| } + #| buf.to_string() + #|} + #|test "to_upper" { + #| assert_eq("hello".to_upper(), "HELLO") + #| assert_eq("HELLO".to_upper(), "HELLO") + #| assert_eq("Hello, World!".to_upper(), "HELLO, WORLD!") + #|} + #|test "View::to_upper" { + #| assert_eq("hello"[:].to_upper(), "HELLO") + #| assert_eq("HELLO"[:].to_upper(), "HELLO") + #| assert_eq("Hello, World!"[:].to_upper(), "HELLO, WORLD!") + #|} + #|pub fn[A] StringView::fold( + #| self : StringView, + #| init~ : A, + #| f : (A, Char) -> A raise?, + #|) -> A raise? { + #| for c in self; rv = (init : A) { + #| continue f(rv, c) + #| } nobreak { + #| rv + #| } + #|} + #|pub fn[A] String::fold( + #| self : String, + #| init~ : A, + #| f : (A, Char) -> A raise?, + #|) -> A raise? { + #| self[:].fold(init~, f) + #|} + #|test "fold" { + #| assert_eq( + #| "hello".fold(init=[], (acc, c) => { + #| acc.push(c) + #| acc + #| }), + #| ['h', 'e', 'l', 'l', 'o'], + #| ) + #| assert_eq( + #| "hello".fold(init=0, (acc, c) => acc + c.to_int()), + #| 104 + 101 + 108 + 108 + 111, + #| ) + #|} + #|test "fold with raise" { + #| let result = try? "hello".fold(init=0, (acc, c) => { + #| if c == 'l' { + #| raise Failure("found l") + #| } + #| acc + 1 + #| }) + #| inspect(result, content="Err(Failure(\"found l\"))") + #|} + #|pub fn[A] StringView::rev_fold( + #| self : StringView, + #| init~ : A, + #| f : (A, Char) -> A raise?, + #|) -> A raise? { + #| for c in self.rev_iter(); rv = (init : A) { + #| continue f(rv, c) + #| } nobreak { + #| rv + #| } + #|} + #|pub fn[A] String::rev_fold( + #| self : String, + #| init~ : A, + #| f : (A, Char) -> A raise?, + #|) -> A raise? { + #| self[:].rev_fold(init~, f) + #|} + #|test "rev_fold" { + #| assert_eq( + #| "hello".rev_fold(init=[], (acc, c) => { + #| acc.push(c) + #| acc + #| }), + #| ['o', 'l', 'l', 'e', 'h'], + #| ) + #| assert_eq( + #| "hello".rev_fold(init=0, (acc, c) => acc + c.to_int()), + #| 111 + 108 + 108 + 101 + 104, + #| ) + #|} + #|test "rev_fold with raise" { + #| let result = try? "hello".rev_fold(init=0, (acc, c) => { + #| if c == 'l' { + #| raise Failure("found l") + #| } + #| acc + 1 + #| }) + #| inspect(result, content="Err(Failure(\"found l\"))") + #|} + #|#deprecated("The return type is about to change to `UInt16?` in a future release. Please check boundaries manually and use `String::code_unit_at` instead.", skip_current_package=true) + #|pub fn String::get(self : String, idx : Int) -> Int? { + #| guard idx >= 0 && idx < self.length() else { return None } + #| Some(self.unsafe_get(idx).to_int()) + #|} + #|#deprecated("The return type is about to change to `UInt16?` in a future release. Please check boundaries manually and use `StringView::code_unit_at` instead.", skip_current_package=true) + #|pub fn StringView::get(self : StringView, idx : Int) -> Int? { + #| guard idx >= 0 && idx < self.length() else { return None } + #| Some(self.unsafe_get(idx).to_int()) + #|} + #|test "String::get supports emoji (surrogate pair)" { + #| let s = "hello" + #| inspect(s.get(0), content="Some(104)") + #| inspect(s.get(4), content="Some(111)") + #| inspect(s.get(5), content="None") + #| inspect(s.get(-1), content="None") + #| let s = "a🤣b" + #| inspect(s.get(0), content="Some(97)") + #| inspect(s.get(1), content="Some(55358)") + #| inspect(s.get(2), content="Some(56611)") + #| inspect(s.get(3), content="Some(98)") + #| inspect(s.get(4), content="None") + #|} + #|test "View::get basic cases" { + #| let v = "hello"[1:-1] + #| inspect(v.get(0), content="Some(101)") + #| inspect(v.get(2), content="Some(108)") + #| inspect(v.get(3), content="None") + #| inspect(v.get(-1), content="None") + #| let v = "ab🤣cd"[1:-1] + #| inspect(v.get(0), content="Some(98)") + #| inspect(v.get(1), content="Some(55358)") + #| inspect(v.get(2), content="Some(56611)") + #|} + #|pub fn String::get_char(self : String, idx : Int) -> Char? { + #| guard idx >= 0 && idx < self.length() else { return None } + #| let c = self.unsafe_get(idx) + #| if c.is_leading_surrogate() { + #| guard idx + 1 < self.length() else { return None } + #| let next = self.unsafe_get(idx + 1) + #| if next.is_trailing_surrogate() { + #| Some(code_point_of_surrogate_pair(c.to_int(), next.to_int())) + #| } else { + #| None + #| } + #| } else if c.is_trailing_surrogate() { + #| None + #| } else { + #| Some(c.unsafe_to_char()) + #| } + #|} + #|pub fn StringView::get_char(self : StringView, idx : Int) -> Char? { + #| guard idx >= 0 && idx < self.length() else { return None } + #| let c = self.unsafe_get(idx) + #| if c.is_leading_surrogate() { + #| guard idx + 1 < self.length() else { return None } + #| let next = self.unsafe_get(idx + 1) + #| if next.is_trailing_surrogate() { + #| Some(code_point_of_surrogate_pair(c.to_int(), next.to_int())) + #| } else { + #| None + #| } + #| } else if c.is_trailing_surrogate() { + #| None + #| } else { + #| Some(c.unsafe_to_char()) + #| } + #|} + #|test "String::get_char basic cases" { + #| let s = "hello" + #| inspect(s.get_char(0), content="Some('h')") + #| inspect(s.get_char(1), content="Some('e')") + #| inspect(s.get_char(4), content="Some('o')") + #| inspect(s.get_char(5), content="None") + #| inspect(s.get_char(-1), content="None") + #| let s = "a🤣b" + #| inspect(s.get_char(0), content="Some('a')") + #| inspect(s.get_char(1), content="Some('🤣')") + #| inspect(s.get_char(2), content="None") // Second half of surrogate pair is not a valid char + #| inspect(s.get_char(3), content="Some('b')") + #| inspect(s.get_char(4), content="None") + #|} + #|test "View::get_char basic cases" { + #| let s = "a🤣b" + #| let v = s[0:-1] + #| inspect(v.get_char(0), content="Some('a')") + #| inspect(v.get_char(1), content="Some('🤣')") + #| inspect(v.get_char(2), content="None") + #| inspect(v.get_char(3), content="None") + #| inspect(v.get_char(4), content="None") + #| let v2 = s[1:3] // Only contains the emoji surrogate pair + #| inspect(v2.get_char(0), content="Some('🤣')") + #| inspect(v2.get_char(1), content="None") + #| inspect(v2.get_char(2), content="None") + #|} + ), + "stringbuilder.mbt": ( + #|pub fn[T : Show] StringBuilder::write_object( + #| self : StringBuilder, + #| obj : T, + #|) -> Unit { + #| obj.output(self) + #|} + #|pub fn StringBuilder::write_iter( + #| self : StringBuilder, + #| iter : Iter[Char], + #|) -> Unit { + #| for ch in iter { + #| self.write_char(ch) + #| } + #|} + #|pub fn StringBuilder::write_stringview( + #| self : StringBuilder, + #| view : StringView, + #|) -> Unit { + #| let start = view.start() + #| let end = view.end() + #| self.write_substring(view.str(), start, end - start) + #|} + ), + "stringbuilder_buffer.mbt": ( + #|struct StringBuilder { + #| mut data : FixedArray[Byte] + #| mut len : Int + #|} + #|pub fn StringBuilder::new(size_hint? : Int = 0) -> StringBuilder { + #| let initial = if size_hint < 1 { 1 } else { size_hint } + #| let data : FixedArray[Byte] = FixedArray::make(initial, 0) + #| { data, len: 0 } + #|} + #|pub fn StringBuilder::is_empty(self : StringBuilder) -> Bool { + #| self.len == 0 + #|} + #|fn StringBuilder::grow_if_necessary( + #| self : StringBuilder, + #| required : Int, + #|) -> Unit { + #| let current_len = self.data.length() + #| if required <= current_len { + #| return + #| } + #| let enough_space = for enough_space = current_len; enough_space < required; { + #| continue enough_space * 2 + #| } nobreak { + #| enough_space + #| } + #| let new_data = FixedArray::make(enough_space, Byte::default()) + #| new_data.unsafe_blit(0, self.data, 0, self.len) + #| self.data = new_data + #|} + #|pub impl Logger for StringBuilder with write_string(self, str) { + #| self.grow_if_necessary(self.len + str.length() * 2) + #| self.data.blit_from_string(self.len, str, 0, str.length()) + #| self.len += str.length() * 2 + #|} + #|pub impl Logger for StringBuilder with write_char(self, ch) { + #| self.grow_if_necessary(self.len + 4) + #| let inc = self.data.set_utf16le_char(self.len, ch) + #| self.len += inc + #|} + #|pub impl Logger for StringBuilder with write_view( + #| self : StringBuilder, + #| str : StringView, + #|) -> Unit { + #| self.grow_if_necessary(self.len + str.length() * 2) + #| self.data.blit_from_string( + #| self.len, + #| str.data(), + #| str.start_offset(), + #| str.length(), + #| ) + #| self.len += str.length() * 2 + #|} + #|pub fn StringBuilder::to_string(self : StringBuilder) -> String { + #| self.data + #| .unsafe_reinterpret_as_bytes() + #| .to_unchecked_string(offset=0, length=self.len) + #|} + #|pub impl Show for StringBuilder with output(self, logger) { + #| logger.write_string( + #| self.data + #| .unsafe_reinterpret_as_bytes() + #| .to_unchecked_string(offset=0, length=self.len), + #| ) + #|} + #|pub fn StringBuilder::reset(self : StringBuilder) -> Unit { + #| self.len = 0 + #|} + ), + "stringbuilder_concat.mbt": ( + #|struct StringBuilder { + #| mut val : String + #|} + #|pub fn StringBuilder::new(size_hint? : Int = 0) -> StringBuilder { + #| ignore(size_hint) + #| { val: "" } + #|} + #|pub fn StringBuilder::is_empty(self : StringBuilder) -> Bool { + #| self.val == "" + #|} + #|pub impl Logger for StringBuilder with write_string(self, str) { + #| self.val += str + #|} + #|pub impl Logger for StringBuilder with write_char(self, ch) { + #| self.val += char_to_string(ch) + #|} + #|pub impl Logger for StringBuilder with write_view( + #| self : StringBuilder, + #| str : StringView, + #|) -> Unit { + #| self.val += str.to_string() + #|} + #|pub impl Show for StringBuilder with output(self, logger) { + #| logger.write_string(self.val) + #|} + #|pub fn StringBuilder::to_string(self : StringBuilder) -> String { + #| self.val + #|} + #|pub fn StringBuilder::reset(self : StringBuilder) -> Unit { + #| self.val = "" + #|} + ), + "stringview.mbt": ( + #|fn StringView::str(self : StringView) -> String = "%stringview.str" + #|fn StringView::start(self : StringView) -> Int = "%stringview.start" + #|fn StringView::end(self : StringView) -> Int = "%stringview.end" + #|fn StringView::make_view(str : String, start : Int, end : Int) -> StringView = "%stringview.make" + #|#alias("_[_]") + #|#alias(code_unit_at) + #|pub fn StringView::at(self : StringView, index : Int) -> UInt16 { + #| guard index >= 0 && index < self.length() else { + #| abort("Index out of bounds") + #| } + #| self.unsafe_get(index) + #|} + #|pub fn StringView::length(self : StringView) -> Int { + #| self.end() - self.start() + #|} + #|pub fn StringView::suffixes( + #| self : StringView, + #| include_empty? : Bool = false, + #|) -> Iter[StringView] { + #| let str = self.str() + #| let end = self.end() + #| let mut next_start = self.start() + #| let mut finished = false + #| Iter::new(fn() -> StringView? { + #| if finished { + #| None + #| } else if next_start == end { + #| finished = true + #| if include_empty { + #| Some(StringView::make_view(str, next_start, end)) + #| } else { + #| None + #| } + #| } else { + #| let suffix = StringView::make_view(str, next_start, end) + #| let code = str.unsafe_get(next_start) + #| if code.is_leading_surrogate() && + #| next_start + 1 < end && + #| str.unsafe_get(next_start + 1).is_trailing_surrogate() { + #| next_start += 2 + #| } else { + #| next_start += 1 + #| } + #| Some(suffix) + #| } + #| }) + #|} + #|pub fn StringView::data(self : StringView) -> String { + #| self.str() + #|} + #|pub fn StringView::start_offset(self : StringView) -> Int { + #| self.start() + #|} + #|pub fn StringView::view( + #| self : StringView, + #| start_offset? : Int = 0, + #| end_offset? : Int, + #|) -> StringView { + #| let end_offset = if end_offset is Some(o) { o } else { self.length() } + #| guard start_offset >= 0 && + #| start_offset <= end_offset && + #| end_offset <= self.length() else { + #| abort("Invalid index for View") + #| } + #| StringView::make_view( + #| self.str(), + #| self.start() + start_offset, + #| self.start() + end_offset, + #| ) + #|} + #|#internal(unsafe, "Undefined behavior if index is out of bounds.") + #|pub fn StringView::unsafe_get(self : StringView, index : Int) -> UInt16 { + #| self.str().unsafe_get(self.start() + index) + #|} + #|#deprecated("Use `StringView::unsafe_get` instead") + #|pub fn StringView::unsafe_charcode_at(self : StringView, index : Int) -> Int { + #| self.str().unsafe_get(self.start() + index).to_int() + #|} + #|pub fn StringView::char_length(self : StringView) -> Int { + #| self.str().char_length(start_offset=self.start(), end_offset=self.end()) + #|} + #|pub impl Show for StringView with output(self, logger) { + #| self.escape_to(logger) + #|} + #|pub impl Show for StringView with to_string(self) { + #| self.str().unsafe_substring(start=self.start(), end=self.end()) + #|} + #|#alias(iterator, deprecated) + #|pub fn StringView::iter(self : StringView) -> Iter[Char] { + #| let start = self.start() + #| let end = self.end() + #| let mut index = start + #| Iter::new(fn() { + #| guard index < end else { None } + #| let c1 = self.str().unsafe_get(index) + #| if c1.is_leading_surrogate() && index + 1 < self.end() { + #| let c2 = self.str().unsafe_get(index + 1) + #| if c2.is_trailing_surrogate() { + #| index += 2 + #| return Some(code_point_of_surrogate_pair(c1.to_int(), c2.to_int())) + #| } + #| } + #| index += 1 + #| Some(c1.unsafe_to_char()) + #| }) + #|} + #|#alias(iterator2, deprecated) + #|pub fn StringView::iter2(self : StringView) -> Iter2[Int, Char] { + #| let start = self.start() + #| let end = self.end() + #| let mut index = start + #| let mut char_index = 0 + #| Iter2::new(fn() { + #| guard index < end else { None } + #| let c1 = self.str().unsafe_get(index) + #| if c1.is_leading_surrogate() && index + 1 < self.end() { + #| let c2 = self.str().unsafe_get(index + 1) + #| if c2.is_trailing_surrogate() { + #| let result = ( + #| char_index, + #| code_point_of_surrogate_pair(c1.to_int(), c2.to_int()), + #| ) + #| index += 2 + #| char_index += 1 + #| return Some(result) + #| } + #| } + #| let result = (char_index, c1.unsafe_to_char()) + #| index += 1 + #| char_index += 1 + #| Some(result) + #| }) + #|} + #|#alias(rev_iterator, deprecated) + #|pub fn StringView::rev_iter(self : StringView) -> Iter[Char] { + #| let start = self.start() + #| let end = self.end() + #| let mut index = end + #| Iter::new(fn() { + #| guard index > start else { None } + #| index -= 1 + #| let c1 = self.str().unsafe_get(index) + #| if c1.is_trailing_surrogate() && index - 1 >= 0 { + #| let c2 = self.str().unsafe_get(index - 1) + #| if c2.is_leading_surrogate() { + #| index -= 1 + #| return Some(code_point_of_surrogate_pair(c2.to_int(), c1.to_int())) + #| } + #| } + #| Some(c1.unsafe_to_char()) + #| }) + #|} + #|pub impl Eq for StringView with equal(self, other) { + #| let len = self.length() + #| guard len == other.length() else { return false } + #| if physical_equal(self.str(), other.str()) && self.start() == other.start() { + #| return true + #| } + #| for i in 0.. Int { + #| let self_len = self.length() + #| let other_len = other.length() + #| let min_len = if self_len < other_len { self_len } else { other_len } + #| for i in 0.. StringView { + #| let end_offset = if end_offset is Some(o) { o } else { self.length() } + #| guard start_offset >= 0 && + #| start_offset <= end_offset && + #| end_offset <= self.length() else { + #| abort("Invalid index for View") + #| } + #| StringView::make_view(self, start_offset, end_offset) + #|} + #|pub fn StringView::from_array(chars : ArrayView[Char]) -> StringView { + #| String::from_array(chars) + #|} + #|#alias(from_iterator, deprecated) + #|pub fn StringView::from_iter(iter : Iter[Char]) -> StringView { + #| String::from_iter(iter) + #|} + #|#alias("_[_:_]") + #|pub fn String::sub(self : String, start? : Int = 0, end? : Int) -> StringView { + #| let len = self.length() + #| let end = match end { + #| None => len + #| Some(end) => if end < 0 { len + end } else { end } + #| } + #| let start = if start < 0 { len + start } else { start } + #| guard start >= 0 && start <= end && end <= len + #| if start < len { + #| guard !self.unsafe_get(start).is_trailing_surrogate() + #| } + #| if end < len { + #| guard !self.unsafe_get(end).is_trailing_surrogate() + #| } + #| StringView::make_view(self, start, end) + #|} + #|#alias("_[_:_]") + #|pub fn StringView::sub( + #| self : StringView, + #| start? : Int = 0, + #| end? : Int, + #|) -> StringView { + #| let str_len = self.str().length() + #| let abs_end = match end { + #| None => self.end() + #| Some(end) => if end < 0 { self.end() + end } else { self.start() + end } + #| } + #| let abs_start = if start < 0 { + #| self.end() + start + #| } else { + #| self.start() + start + #| } + #| guard abs_start >= self.start() && + #| abs_start <= abs_end && + #| abs_end <= self.end() + #| if abs_start < str_len { + #| guard !self.str().unsafe_get(abs_start).is_trailing_surrogate() + #| } + #| if abs_end < str_len { + #| guard !self.str().unsafe_get(abs_end).is_trailing_surrogate() + #| } + #| StringView::make_view(self.str(), abs_start, abs_end) + #|} + #|pub fn StringView::char_length_eq(self : StringView, len : Int) -> Bool { + #| self + #| .str() + #| .char_length_eq(len, start_offset=self.start(), end_offset=self.end()) + #|} + #|pub fn StringView::char_length_ge(self : StringView, len : Int) -> Bool { + #| self + #| .str() + #| .char_length_ge(len, start_offset=self.start(), end_offset=self.end()) + #|} + #|pub fn StringView::offset_of_nth_char(self : StringView, i : Int) -> Int? { + #| if self + #| .str() + #| .offset_of_nth_char(i, start_offset=self.start(), end_offset=self.end()) + #| is Some(index) { + #| Some(index - self.start()) + #| } else { + #| None + #| } + #|} + #|pub impl Default for StringView with default() { + #| "" + #|} + #|pub fn StringView::make(length : Int, value : Char) -> StringView { + #| String::make(length, value) + #|} + #|pub impl ToJson for StringView with to_json(self) { + #| String::to_json(self.to_string()) + #|} + #|pub impl Add for StringView with add(self, other) { + #| [..self, ..other] + #|} + ), + "to_string.mbt": ( + #|#cfg(not(target="js")) + #|const ALPHABET : String = "0123456789abcdefghijklmnopqrstuvwxyz" + #|#cfg(not(target="js")) + #|fn unsafe_fixedarray_uint16_to_string(buffer : FixedArray[UInt16]) -> String = "%string.unsafe_from_uint16_fixedarray" + #|#cfg(not(target="js")) + #|fn int_to_string_hex( + #| buffer : FixedArray[UInt16], + #| num : UInt, + #| digit_start : Int, + #| total_len : Int, + #|) -> Unit { + #| let (offset, n) = for offset = total_len - digit_start, n = num; offset >= 2; { + #| let byte_val = n.land(0xFFU).reinterpret_as_int() + #| let hi = byte_val / 16 + #| let lo = byte_val % 16 + #| buffer.unsafe_set(digit_start + offset - 2, ALPHABET.unsafe_get(hi)) + #| buffer.unsafe_set(digit_start + offset - 1, ALPHABET.unsafe_get(lo)) + #| continue offset - 2, n >> 8 + #| } nobreak { + #| (offset, n) + #| } + #| if offset == 1 { + #| let nibble = n.land(0xFU).reinterpret_as_int() + #| buffer.unsafe_set(digit_start, ALPHABET.unsafe_get(nibble)) + #| } + #|} + #|#cfg(not(target="js")) + #|fn int_to_string_generic( + #| buffer : FixedArray[UInt16], + #| num : UInt, + #| digit_start : Int, + #| total_len : Int, + #| radix : Int, + #|) -> Unit { + #| let base = radix.reinterpret_as_uint() + #| if (radix & (radix - 1)) == 0 { + #| let shift = radix.ctz() + #| let mask = base - 1U + #| for offset = total_len - digit_start, n = num; n > 0U; { + #| let digit = n.land(mask).reinterpret_as_int() + #| buffer.unsafe_set(digit_start + offset - 1, ALPHABET.unsafe_get(digit)) + #| continue offset - 1, n >> shift + #| } + #| } else { + #| for offset = total_len - digit_start, n = num; n > 0U; { + #| let q = n / base + #| let digit = (n - q * base).reinterpret_as_int() + #| buffer.unsafe_set(digit_start + offset - 1, ALPHABET.unsafe_get(digit)) + #| continue offset - 1, q + #| } + #| } + #|} + #|#cfg(not(target="js")) + #|fn int_to_string_dec( + #| buffer : FixedArray[UInt16], + #| num : UInt, + #| digit_start : Int, + #| total_len : Int, + #|) -> Unit { + #| let (num, offset) = for num = num, offset = total_len - digit_start; num >= + #| 10000U; { + #| let t = num / 10000U + #| let r = (num % 10000U).reinterpret_as_int() + #| let d1 = r / 100 + #| let d2 = r % 100 + #| let d1_hi = (0x30 + d1 / 10).to_uint16() + #| let d1_lo = (0x30 + d1 % 10).to_uint16() + #| let d2_hi = (0x30 + d2 / 10).to_uint16() + #| let d2_lo = (0x30 + d2 % 10).to_uint16() + #| buffer.unsafe_set(digit_start + offset - 4, d1_hi) + #| buffer.unsafe_set(digit_start + offset - 3, d1_lo) + #| buffer.unsafe_set(digit_start + offset - 2, d2_hi) + #| buffer.unsafe_set(digit_start + offset - 1, d2_lo) + #| continue t, offset - 4 + #| } nobreak { + #| (num, offset) + #| } + #| let (remaining, offset) = for remaining = num.reinterpret_as_int(), offset = offset; remaining >= + #| 100; { + #| let t = remaining / 100 + #| let d = remaining % 100 + #| let d_hi = (0x30 + d / 10).to_uint16() + #| let d_lo = (0x30 + d % 10).to_uint16() + #| buffer.unsafe_set(digit_start + offset - 2, d_hi) + #| buffer.unsafe_set(digit_start + offset - 1, d_lo) + #| continue t, offset - 2 + #| } nobreak { + #| (remaining, offset) + #| } + #| if remaining >= 10 { + #| let d_hi = (0x30 + remaining / 10).to_uint16() + #| let d_lo = (0x30 + remaining % 10).to_uint16() + #| buffer.unsafe_set(digit_start + offset - 2, d_hi) + #| buffer.unsafe_set(digit_start + offset - 1, d_lo) + #| } else { + #| buffer.unsafe_set(digit_start + offset - 1, (0x30 + remaining).to_uint16()) + #| } + #|} + #|#cfg(not(target="js")) + #|fn dec_count32(value : UInt) -> Int { + #| if value >= 100000U { // >= 10^5 means 6+ digits + #| if value >= 10000000U { // >= 10^7 means 8+ digits + #| if value >= 1000000000U { // >= 10^9 means 10 digits + #| 10 + #| } else if value >= 100000000U { // >= 10^8 means 9 digits + #| 9 + #| } else { + #| 8 + #| } + #| } else if value >= 1000000U { // >= 10^6 means 7 digits + #| 7 + #| } else { + #| 6 + #| } + #| } else if value >= 1000U { // >= 10^3 means 4+ digits + #| if value >= 10000U { // >= 10^4 means 5 digits + #| 5 + #| } else { + #| 4 + #| } + #| } else if value >= 100U { // >= 10^2 means 3 digits + #| 3 + #| } else if value >= 10U { // >= 10^1 means 2 digits + #| 2 + #| } else { + #| 1 + #| } + #|} + #|#cfg(not(target="js")) + #|fn hex_count32(value : UInt) -> Int { + #| if value == 0U { + #| 1 + #| } else { + #| let leading_zeros = value.clz() + #| (31 - leading_zeros) / 4 + 1 + #| } + #|} + #|#cfg(not(target="js")) + #|fn radix_count32(value : UInt, radix : Int) -> Int { + #| if value == 0U { + #| return 1 + #| } + #| let base = radix.reinterpret_as_uint() + #| for num = value, count = 0; num > 0U; { + #| continue num / base, count + 1 + #| } nobreak { + #| count + #| } + #|} + #|#cfg(not(target="js")) + #|pub fn Int::to_string(self : Int, radix? : Int = 10) -> String { + #| if radix < 2 || radix > 36 { + #| abort("radix must be between 2 and 36") + #| } + #| if self == 0 { + #| return "0" + #| } + #| let is_negative = self < 0 + #| let num : UInt = if is_negative { + #| (-self).reinterpret_as_uint() + #| } else { + #| self.reinterpret_as_uint() + #| } + #| let buffer = match radix { + #| 10 => { + #| let digit_len = dec_count32(num) + #| let total_len = digit_len + (if is_negative { 1 } else { 0 }) + #| let buffer : FixedArray[UInt16] = FixedArray::make(total_len, 0) + #| let digit_start = if is_negative { 1 } else { 0 } + #| int_to_string_dec(buffer, num, digit_start, total_len) + #| buffer + #| } + #| 16 => { + #| let digit_len = hex_count32(num) + #| let total_len = digit_len + (if is_negative { 1 } else { 0 }) + #| let buffer : FixedArray[UInt16] = FixedArray::make(total_len, 0) + #| let digit_start = if is_negative { 1 } else { 0 } + #| int_to_string_hex(buffer, num, digit_start, total_len) + #| buffer + #| } + #| _ => { + #| let digit_len = radix_count32(num, radix) + #| let total_len = digit_len + (if is_negative { 1 } else { 0 }) + #| let buffer : FixedArray[UInt16] = FixedArray::make(total_len, 0) + #| let digit_start = if is_negative { 1 } else { 0 } + #| int_to_string_generic(buffer, num, digit_start, total_len, radix) + #| buffer + #| } + #| } + #| if is_negative { + #| buffer.unsafe_set(0, 0x002D) + #| } + #| unsafe_fixedarray_uint16_to_string(buffer) + #|} + #|#cfg(not(target="js")) + #|pub fn UInt::to_string(self : UInt, radix? : Int = 10) -> String { + #| if radix < 2 || radix > 36 { + #| abort("radix must be between 2 and 36") + #| } + #| if self == 0U { + #| return "0" + #| } + #| let buffer = match radix { + #| 10 => { + #| let len = dec_count32(self) + #| let buffer : FixedArray[UInt16] = FixedArray::make(len, 0) + #| int_to_string_dec(buffer, self, 0, len) + #| buffer + #| } + #| 16 => { + #| let len = hex_count32(self) + #| let buffer : FixedArray[UInt16] = FixedArray::make(len, 0) + #| int_to_string_hex(buffer, self, 0, len) + #| buffer + #| } + #| _ => { + #| let len = radix_count32(self, radix) + #| let buffer : FixedArray[UInt16] = FixedArray::make(len, 0) + #| int_to_string_generic(buffer, self, 0, len, radix) + #| buffer + #| } + #| } + #| unsafe_fixedarray_uint16_to_string(buffer) + #|} + #|#cfg(target="js") + #|pub fn Int::to_string(self : Int, radix? : Int = 10) -> String { + #| int_to_string_js(self, radix) + #|} + #|#cfg(target="js") + #|extern "js" fn int_to_string_js(i : Int, radix : Int) -> String = + #| #|(x, radix) => { + #| #| return x.toString(radix); + #| #|} + #|#cfg(target="js") + #|pub fn UInt::to_string(self : UInt, radix? : Int = 10) -> String { + #| uint_to_string_js(self, radix) + #|} + #|#cfg(target="js") + #|extern "js" fn uint_to_string_js(i : UInt, radix : Int) -> String = + #| #|(x, radix) => { + #| #| return (x >>> 0).toString(radix); + #| #|} + #|#cfg(not(target="js")) + #|fn dec_count64(value : UInt64) -> Int { + #| if value >= 10000000000UL { // >= 10^10 means 11+ digits + #| if value >= 100000000000000UL { // >= 10^14 means 15+ digits + #| if value >= 10000000000000000UL { // >= 10^16 means 17+ digits + #| if value >= 1000000000000000000UL { // >= 10^18 means 19+ digits + #| if value >= 10000000000000000000UL { // >= 10^19 means 20 digits + #| 20 + #| } else { + #| 19 + #| } + #| } else if value >= 100000000000000000UL { // >= 10^17 means 18 digits + #| 18 + #| } else { + #| 17 + #| } + #| } else if value >= 1000000000000000UL { // >= 10^15 means 16 digits + #| 16 + #| } else { + #| 15 + #| } + #| } else if value >= 1000000000000UL { // >= 10^12 means 13+ digits + #| if value >= 10000000000000UL { // >= 10^13 means 14 digits + #| 14 + #| } else { + #| 13 + #| } + #| } else if value >= 100000000000UL { // >= 10^11 means 12 digits + #| 12 + #| } else { + #| 11 + #| } + #| } else if value >= 100000UL { // >= 10^5 means 6+ digits + #| if value >= 10000000UL { // >= 10^7 means 8+ digits + #| if value >= 1000000000UL { // >= 10^9 means 10 digits + #| 10 + #| } else if value >= 100000000UL { // >= 10^8 means 9 digits + #| 9 + #| } else { + #| 8 + #| } + #| } else if value >= 1000000UL { // >= 10^6 means 7 digits + #| 7 + #| } else { + #| 6 + #| } + #| } else if value >= 1000UL { // >= 10^3 means 4+ digits + #| if value >= 10000UL { // >= 10^4 means 5 digits + #| 5 + #| } else { + #| 4 + #| } + #| } else if value >= 100UL { // >= 10^2 means 3 digits + #| 3 + #| } else if value >= 10UL { // >= 10^1 means 2 digits + #| 2 + #| } else { + #| 1 + #| } + #|} + #|#cfg(not(target="js")) + #|fn hex_count64(value : UInt64) -> Int { + #| if value == 0UL { + #| 1 + #| } else { + #| let leading_zeros = value.clz() + #| (63 - leading_zeros) / 4 + 1 + #| } + #|} + #|#cfg(not(target="js")) + #|fn radix_count64(value : UInt64, radix : Int) -> Int { + #| if value == 0UL { + #| return 1 + #| } + #| let base = radix.to_uint64() + #| for num = value, count = 0; num > 0UL; { + #| continue num / base, count + 1 + #| } nobreak { + #| count + #| } + #|} + #|#cfg(not(target="js")) + #|fn int64_to_string_hex( + #| buffer : FixedArray[UInt16], + #| num : UInt64, + #| digit_start : Int, + #| total_len : Int, + #|) -> Unit { + #| let (offset, n) = for offset = total_len - digit_start, n = num; offset >= 2; { + #| let byte_val = n.land(0xFFUL).to_int() + #| let hi = byte_val / 16 + #| let lo = byte_val % 16 + #| buffer.unsafe_set(digit_start + offset - 2, ALPHABET.unsafe_get(hi)) + #| buffer.unsafe_set(digit_start + offset - 1, ALPHABET.unsafe_get(lo)) + #| continue offset - 2, n >> 8 + #| } nobreak { + #| (offset, n) + #| } + #| if offset == 1 { + #| let nibble = n.land(0xFUL).to_int() + #| buffer.unsafe_set(digit_start, ALPHABET.unsafe_get(nibble)) + #| } + #|} + #|#cfg(not(target="js")) + #|fn int64_to_string_generic( + #| buffer : FixedArray[UInt16], + #| num : UInt64, + #| digit_start : Int, + #| total_len : Int, + #| radix : Int, + #|) -> Unit { + #| let base = radix.to_uint64() + #| if (radix & (radix - 1)) == 0 { + #| let shift = radix.ctz() + #| let mask = base - 1UL + #| for offset = total_len - digit_start, n = num; n > 0UL; { + #| let digit = n.land(mask).to_int() + #| buffer.unsafe_set(digit_start + offset - 1, ALPHABET.unsafe_get(digit)) + #| continue offset - 1, n >> shift + #| } + #| } else { + #| for offset = total_len - digit_start, n = num; n > 0UL; { + #| let q = n / base + #| let digit = (n - q * base).to_int() + #| buffer.unsafe_set(digit_start + offset - 1, ALPHABET.unsafe_get(digit)) + #| continue offset - 1, q + #| } + #| } + #|} + #|#cfg(not(target="js")) + #|fn int64_to_string_dec( + #| buffer : FixedArray[UInt16], + #| num : UInt64, + #| digit_start : Int, + #| total_len : Int, + #|) -> Unit { + #| let (num, offset) = for num = num, offset = total_len - digit_start; num >= + #| 10000UL; { + #| let t = num / 10000UL + #| let r = (num % 10000UL).to_int() + #| let d1 = r / 100 + #| let d2 = r % 100 + #| let d1_hi = (0x30 + d1 / 10).to_uint16() + #| let d1_lo = (0x30 + d1 % 10).to_uint16() + #| let d2_hi = (0x30 + d2 / 10).to_uint16() + #| let d2_lo = (0x30 + d2 % 10).to_uint16() + #| buffer.unsafe_set(digit_start + offset - 4, d1_hi) + #| buffer.unsafe_set(digit_start + offset - 3, d1_lo) + #| buffer.unsafe_set(digit_start + offset - 2, d2_hi) + #| buffer.unsafe_set(digit_start + offset - 1, d2_lo) + #| continue t, offset - 4 + #| } nobreak { + #| (num, offset) + #| } + #| let (remaining, offset) = for remaining = num.to_int(), offset = offset; remaining >= + #| 100; { + #| let t = remaining / 100 + #| let d = remaining % 100 + #| let d_hi = (0x30 + d / 10).to_uint16() + #| let d_lo = (0x30 + d % 10).to_uint16() + #| buffer.unsafe_set(digit_start + offset - 2, d_hi) + #| buffer.unsafe_set(digit_start + offset - 1, d_lo) + #| continue t, offset - 2 + #| } nobreak { + #| (remaining, offset) + #| } + #| if remaining >= 10 { + #| let d_hi = (0x30 + remaining / 10).to_uint16() + #| let d_lo = (0x30 + remaining % 10).to_uint16() + #| buffer.unsafe_set(digit_start + offset - 2, d_hi) + #| buffer.unsafe_set(digit_start + offset - 1, d_lo) + #| } else { + #| buffer.unsafe_set(digit_start + offset - 1, (0x30 + remaining).to_uint16()) + #| } + #|} + #|#cfg(not(target="js")) + #|pub fn Int64::to_string(self : Int64, radix? : Int = 10) -> String { + #| if radix < 2 || radix > 36 { + #| abort("radix must be between 2 and 36") + #| } + #| if self == 0L { + #| return "0" + #| } + #| let is_negative = self < 0L + #| let num : UInt64 = if is_negative { + #| (-self).reinterpret_as_uint64() + #| } else { + #| self.reinterpret_as_uint64() + #| } + #| let buffer = match radix { + #| 10 => { + #| let digit_len = dec_count64(num) + #| let total_len = digit_len + (if is_negative { 1 } else { 0 }) + #| let buffer : FixedArray[UInt16] = FixedArray::make(total_len, 0) + #| let digit_start = if is_negative { 1 } else { 0 } + #| int64_to_string_dec(buffer, num, digit_start, total_len) + #| buffer + #| } + #| 16 => { + #| let digit_len = hex_count64(num) + #| let total_len = digit_len + (if is_negative { 1 } else { 0 }) + #| let buffer : FixedArray[UInt16] = FixedArray::make(total_len, 0) + #| let digit_start = if is_negative { 1 } else { 0 } + #| int64_to_string_hex(buffer, num, digit_start, total_len) + #| buffer + #| } + #| _ => { + #| let digit_len = radix_count64(num, radix) + #| let total_len = digit_len + (if is_negative { 1 } else { 0 }) + #| let buffer : FixedArray[UInt16] = FixedArray::make(total_len, 0) + #| let digit_start = if is_negative { 1 } else { 0 } + #| int64_to_string_generic(buffer, num, digit_start, total_len, radix) + #| buffer + #| } + #| } + #| if is_negative { + #| buffer.unsafe_set(0, 0x002D) + #| } + #| unsafe_fixedarray_uint16_to_string(buffer) + #|} + #|#cfg(not(target="js")) + #|pub fn UInt64::to_string(self : UInt64, radix? : Int = 10) -> String { + #| if radix < 2 || radix > 36 { + #| abort("radix must be between 2 and 36") + #| } + #| if self == 0UL { + #| return "0" + #| } + #| let buffer = match radix { + #| 10 => { + #| let len = dec_count64(self) + #| let buffer : FixedArray[UInt16] = FixedArray::make(len, 0) + #| int64_to_string_dec(buffer, self, 0, len) + #| buffer + #| } + #| 16 => { + #| let len = hex_count64(self) + #| let buffer : FixedArray[UInt16] = FixedArray::make(len, 0) + #| int64_to_string_hex(buffer, self, 0, len) + #| buffer + #| } + #| _ => { + #| let len = radix_count64(self, radix) + #| let buffer : FixedArray[UInt16] = FixedArray::make(len, 0) + #| int64_to_string_generic(buffer, self, 0, len, radix) + #| buffer + #| } + #| } + #| unsafe_fixedarray_uint16_to_string(buffer) + #|} + #|#cfg(target="js") + #|pub fn Int64::to_string(self : Int64, radix? : Int = 10) -> String { + #| int64_to_string_js(self, radix) + #|} + #|#cfg(target="js") + #|extern "js" fn int64_to_string_js(num : Int64, radix : Int) -> String = + #| #|(num, radix) => { + #| #| let val = (BigInt(num.hi >>> 0) << 32n) | BigInt(num.lo >>> 0); + #| #| if (val & (1n << 63n)) { + #| #| val = val - (1n << 64n); + #| #| } + #| #| return val.toString(radix); + #| #|} + #|#cfg(target="js") + #|pub fn UInt64::to_string(self : UInt64, radix? : Int = 10) -> String { + #| uint64_to_string_js(self, radix) + #|} + #|#cfg(target="js") + #|extern "js" fn uint64_to_string_js(num : UInt64, radix : Int) -> String = + #| #|(num, radix) => { + #| #| return (BigInt(num.hi >>> 0) << 32n | BigInt(num.lo >>> 0)).toString(radix); + #| #|} + #|pub fn UInt16::to_string(self : UInt16, radix? : Int = 10) -> String { + #| self.to_int().to_string(radix~) + #|} + #|test "UInt::to_string" { + #| inspect(0U, content="0") + #| inspect(17U, content="17") + #| inspect(4294967295U, content="4294967295") + #|} + #|test "to_string" { + #| assert_eq((0x100).to_string(), "256") + #| assert_eq("\{0x100}", "256") + #| assert_eq(0x200U.to_string(), "512") + #| assert_eq("\{0x200U}", "512") + #| assert_eq(0x300L.to_string(), "768") + #| assert_eq("\{0x300L}", "768") + #| assert_eq(0x400UL.to_string(), "1024") + #| assert_eq("\{0x400UL}", "1024") + #|} + #|test "panic to_string_by_radix/illegal_radix" { + #| ignore((1).to_string(radix=1)) + #| ignore((1).to_string(radix=37)) + #| ignore(1L.to_string(radix=0)) + #| ignore(1L.to_string(radix=42)) + #| ignore(1U.to_string(radix=-1)) + #| ignore(1U.to_string(radix=73)) + #| ignore(1UL.to_string(radix=-100)) + #| ignore(1UL.to_string(radix=100)) + #|} + ), + "traits.mbt": ( + #|pub(open) trait Eq { + #| equal(Self, Self) -> Bool = _ + #| #deprecated("use `equal` instead", skip_current_package=true) + #| op_equal(Self, Self) -> Bool = _ + #| not_equal(Self, Self) -> Bool = _ + #|} + #|impl Eq with not_equal(x, y) { + #| !(x == y) + #|} + #|pub(open) trait Compare: Eq { + #| compare(Self, Self) -> Int + #| op_lt(Self, Self) -> Bool = _ + #| op_gt(Self, Self) -> Bool = _ + #| op_le(Self, Self) -> Bool = _ + #| op_ge(Self, Self) -> Bool = _ + #|} + #|impl Compare with op_lt(x, y) { + #| x.compare(y).is_neg() + #|} + #|impl Compare with op_gt(x, y) { + #| x.compare(y).is_pos() + #|} + #|impl Compare with op_le(x, y) { + #| x.compare(y).is_non_pos() + #|} + #|impl Compare with op_ge(x, y) { + #| x.compare(y).is_non_neg() + #|} + #|pub(open) trait Hash { + #| hash_combine(Self, Hasher) -> Unit + #| hash(Self) -> Int = _ + #|} + #|impl Hash with hash(self) { + #| let h = Hasher::new() + #| h.combine(self) + #| h.finalize() + #|} + #|pub(open) trait Default { + #| default() -> Self + #|} + #|pub(open) trait Logger { + #| write_string(Self, String) -> Unit = _ + #| #deprecated("use `write_view` instead", skip_current_package=true) + #| write_substring(Self, String, Int, Int) -> Unit = _ + #| write_view(Self, StringView) -> Unit = _ + #| write_char(Self, Char) -> Unit = _ + #|} + #|impl Logger with write_substring(self, value, start, len) { + #| self.write_view(value[start:start + len]) + #|} + #|impl Logger with write_string(self, value) { + #| self.write_view(value[:]) + #|} + #|#deprecated("replace `impl write_substring` with `impl write_view`") + #|impl Logger with write_view(self, value) { + #| self.write_substring(value.data(), value.start_offset(), value.length()) + #|} + #|impl Logger with write_char(self, value) { + #| self.write_string([value]) + #|} + #|pub(open) trait Show { + #| output(Self, &Logger) -> Unit + #| to_string(Self) -> String = _ + #|} + #|impl Show with to_string(self) { + #| let logger = StringBuilder::new() + #| self.output(logger) + #| logger.to_string() + #|} + #|pub fn[Obj : Show] &Logger::write_object(self : &Logger, obj : Obj) -> Unit { + #| obj.output(self) + #|} + #|pub fn[T : Show] &Logger::write_iter( + #| self : &Logger, + #| iter : Iter[T], + #| prefix? : String = "[", + #| suffix? : String = "]", + #| sep? : String = ", ", + #| trailing? : Bool = false, + #|) -> Unit { + #| self.write_string(prefix) + #| if trailing { + #| for x in iter { + #| self.write_object(x) + #| self.write_string(sep) + #| } + #| } else if iter.next() is Some(x) { + #| self.write_object(x) + #| for x in iter { + #| self.write_string(sep) + #| self.write_object(x) + #| } + #| } + #| self.write_string(suffix) + #|} + #|#deprecated("use `to_repr` for debugging representation") + #|pub fn[T : Show] repr(t : T) -> String { + #| let logger = StringBuilder::new() + #| t.output(logger) + #| logger.to_string() + #|} + #|#deprecated("replace `impl op_equal` with `impl equal`") + #|impl Eq with equal(self, other) { + #| Eq::op_equal(self, other) + #|} + #|impl Eq with op_equal(self, other) { + #| Eq::equal(self, other) + #|} + ), + "tuple_compare.mbt": ( + #|pub impl[T0 : Compare, T1 : Compare] Compare for (T0, T1) with compare( + #| self : (T0, T1), + #| other : (T0, T1), + #|) -> Int { + #| let t0 = self.0.compare(other.0) + #| guard t0 == 0 else { return t0 } + #| self.1.compare(other.1) + #|} + #|pub impl[T0 : Compare, T1 : Compare, T2 : Compare] Compare for (T0, T1, T2) with compare( + #| self : (T0, T1, T2), + #| other : (T0, T1, T2), + #|) -> Int { + #| let t0 = self.0.compare(other.0) + #| guard t0 == 0 else { return t0 } + #| let t1 = self.1.compare(other.1) + #| guard t1 == 0 else { return t1 } + #| self.2.compare(other.2) + #|} + #|pub impl[T0 : Compare, T1 : Compare, T2 : Compare, T3 : Compare] Compare for ( + #| T0, + #| T1, + #| T2, + #| T3, + #|) with compare(self : (T0, T1, T2, T3), other : (T0, T1, T2, T3)) -> Int { + #| let t0 = self.0.compare(other.0) + #| guard t0 == 0 else { return t0 } + #| let t1 = self.1.compare(other.1) + #| guard t1 == 0 else { return t1 } + #| let t2 = self.2.compare(other.2) + #| guard t2 == 0 else { return t2 } + #| self.3.compare(other.3) + #|} + #|pub impl[T0 : Compare, T1 : Compare, T2 : Compare, T3 : Compare, T4 : Compare] Compare for ( + #| T0, + #| T1, + #| T2, + #| T3, + #| T4, + #|) with compare(self : (T0, T1, T2, T3, T4), other : (T0, T1, T2, T3, T4)) -> Int { + #| let t0 = self.0.compare(other.0) + #| guard t0 == 0 else { return t0 } + #| let t1 = self.1.compare(other.1) + #| guard t1 == 0 else { return t1 } + #| let t2 = self.2.compare(other.2) + #| guard t2 == 0 else { return t2 } + #| let t3 = self.3.compare(other.3) + #| guard t3 == 0 else { return t3 } + #| self.4.compare(other.4) + #|} + #|pub impl[ + #| T0 : Compare, + #| T1 : Compare, + #| T2 : Compare, + #| T3 : Compare, + #| T4 : Compare, + #| T5 : Compare, + #|] Compare for (T0, T1, T2, T3, T4, T5) with compare( + #| self : (T0, T1, T2, T3, T4, T5), + #| other : (T0, T1, T2, T3, T4, T5), + #|) -> Int { + #| let t0 = self.0.compare(other.0) + #| guard t0 == 0 else { return t0 } + #| let t1 = self.1.compare(other.1) + #| guard t1 == 0 else { return t1 } + #| let t2 = self.2.compare(other.2) + #| guard t2 == 0 else { return t2 } + #| let t3 = self.3.compare(other.3) + #| guard t3 == 0 else { return t3 } + #| let t4 = self.4.compare(other.4) + #| guard t4 == 0 else { return t4 } + #| self.5.compare(other.5) + #|} + #|pub impl[ + #| T0 : Compare, + #| T1 : Compare, + #| T2 : Compare, + #| T3 : Compare, + #| T4 : Compare, + #| T5 : Compare, + #| T6 : Compare, + #|] Compare for (T0, T1, T2, T3, T4, T5, T6) with compare( + #| self : (T0, T1, T2, T3, T4, T5, T6), + #| other : (T0, T1, T2, T3, T4, T5, T6), + #|) -> Int { + #| let t0 = self.0.compare(other.0) + #| guard t0 == 0 else { return t0 } + #| let t1 = self.1.compare(other.1) + #| guard t1 == 0 else { return t1 } + #| let t2 = self.2.compare(other.2) + #| guard t2 == 0 else { return t2 } + #| let t3 = self.3.compare(other.3) + #| guard t3 == 0 else { return t3 } + #| let t4 = self.4.compare(other.4) + #| guard t4 == 0 else { return t4 } + #| let t5 = self.5.compare(other.5) + #| guard t5 == 0 else { return t5 } + #| self.6.compare(other.6) + #|} + #|pub impl[ + #| T0 : Compare, + #| T1 : Compare, + #| T2 : Compare, + #| T3 : Compare, + #| T4 : Compare, + #| T5 : Compare, + #| T6 : Compare, + #| T7 : Compare, + #|] Compare for (T0, T1, T2, T3, T4, T5, T6, T7) with compare( + #| self : (T0, T1, T2, T3, T4, T5, T6, T7), + #| other : (T0, T1, T2, T3, T4, T5, T6, T7), + #|) -> Int { + #| let t0 = self.0.compare(other.0) + #| guard t0 == 0 else { return t0 } + #| let t1 = self.1.compare(other.1) + #| guard t1 == 0 else { return t1 } + #| let t2 = self.2.compare(other.2) + #| guard t2 == 0 else { return t2 } + #| let t3 = self.3.compare(other.3) + #| guard t3 == 0 else { return t3 } + #| let t4 = self.4.compare(other.4) + #| guard t4 == 0 else { return t4 } + #| let t5 = self.5.compare(other.5) + #| guard t5 == 0 else { return t5 } + #| let t6 = self.6.compare(other.6) + #| guard t6 == 0 else { return t6 } + #| self.7.compare(other.7) + #|} + #|pub impl[ + #| T0 : Compare, + #| T1 : Compare, + #| T2 : Compare, + #| T3 : Compare, + #| T4 : Compare, + #| T5 : Compare, + #| T6 : Compare, + #| T7 : Compare, + #| T8 : Compare, + #|] Compare for (T0, T1, T2, T3, T4, T5, T6, T7, T8) with compare( + #| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8), + #| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8), + #|) -> Int { + #| let t0 = self.0.compare(other.0) + #| guard t0 == 0 else { return t0 } + #| let t1 = self.1.compare(other.1) + #| guard t1 == 0 else { return t1 } + #| let t2 = self.2.compare(other.2) + #| guard t2 == 0 else { return t2 } + #| let t3 = self.3.compare(other.3) + #| guard t3 == 0 else { return t3 } + #| let t4 = self.4.compare(other.4) + #| guard t4 == 0 else { return t4 } + #| let t5 = self.5.compare(other.5) + #| guard t5 == 0 else { return t5 } + #| let t6 = self.6.compare(other.6) + #| guard t6 == 0 else { return t6 } + #| let t7 = self.7.compare(other.7) + #| guard t7 == 0 else { return t7 } + #| self.8.compare(other.8) + #|} + #|pub impl[ + #| T0 : Compare, + #| T1 : Compare, + #| T2 : Compare, + #| T3 : Compare, + #| T4 : Compare, + #| T5 : Compare, + #| T6 : Compare, + #| T7 : Compare, + #| T8 : Compare, + #| T9 : Compare, + #|] Compare for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) with compare( + #| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9), + #| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9), + #|) -> Int { + #| let t0 = self.0.compare(other.0) + #| guard t0 == 0 else { return t0 } + #| let t1 = self.1.compare(other.1) + #| guard t1 == 0 else { return t1 } + #| let t2 = self.2.compare(other.2) + #| guard t2 == 0 else { return t2 } + #| let t3 = self.3.compare(other.3) + #| guard t3 == 0 else { return t3 } + #| let t4 = self.4.compare(other.4) + #| guard t4 == 0 else { return t4 } + #| let t5 = self.5.compare(other.5) + #| guard t5 == 0 else { return t5 } + #| let t6 = self.6.compare(other.6) + #| guard t6 == 0 else { return t6 } + #| let t7 = self.7.compare(other.7) + #| guard t7 == 0 else { return t7 } + #| let t8 = self.8.compare(other.8) + #| guard t8 == 0 else { return t8 } + #| self.9.compare(other.9) + #|} + #|pub impl[ + #| T0 : Compare, + #| T1 : Compare, + #| T2 : Compare, + #| T3 : Compare, + #| T4 : Compare, + #| T5 : Compare, + #| T6 : Compare, + #| T7 : Compare, + #| T8 : Compare, + #| T9 : Compare, + #| T10 : Compare, + #|] Compare for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) with compare( + #| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10), + #| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10), + #|) -> Int { + #| let t0 = self.0.compare(other.0) + #| guard t0 == 0 else { return t0 } + #| let t1 = self.1.compare(other.1) + #| guard t1 == 0 else { return t1 } + #| let t2 = self.2.compare(other.2) + #| guard t2 == 0 else { return t2 } + #| let t3 = self.3.compare(other.3) + #| guard t3 == 0 else { return t3 } + #| let t4 = self.4.compare(other.4) + #| guard t4 == 0 else { return t4 } + #| let t5 = self.5.compare(other.5) + #| guard t5 == 0 else { return t5 } + #| let t6 = self.6.compare(other.6) + #| guard t6 == 0 else { return t6 } + #| let t7 = self.7.compare(other.7) + #| guard t7 == 0 else { return t7 } + #| let t8 = self.8.compare(other.8) + #| guard t8 == 0 else { return t8 } + #| let t9 = self.9.compare(other.9) + #| guard t9 == 0 else { return t9 } + #| self.10.compare(other.10) + #|} + #|pub impl[ + #| T0 : Compare, + #| T1 : Compare, + #| T2 : Compare, + #| T3 : Compare, + #| T4 : Compare, + #| T5 : Compare, + #| T6 : Compare, + #| T7 : Compare, + #| T8 : Compare, + #| T9 : Compare, + #| T10 : Compare, + #| T11 : Compare, + #|] Compare for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) with compare( + #| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11), + #| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11), + #|) -> Int { + #| let t0 = self.0.compare(other.0) + #| guard t0 == 0 else { return t0 } + #| let t1 = self.1.compare(other.1) + #| guard t1 == 0 else { return t1 } + #| let t2 = self.2.compare(other.2) + #| guard t2 == 0 else { return t2 } + #| let t3 = self.3.compare(other.3) + #| guard t3 == 0 else { return t3 } + #| let t4 = self.4.compare(other.4) + #| guard t4 == 0 else { return t4 } + #| let t5 = self.5.compare(other.5) + #| guard t5 == 0 else { return t5 } + #| let t6 = self.6.compare(other.6) + #| guard t6 == 0 else { return t6 } + #| let t7 = self.7.compare(other.7) + #| guard t7 == 0 else { return t7 } + #| let t8 = self.8.compare(other.8) + #| guard t8 == 0 else { return t8 } + #| let t9 = self.9.compare(other.9) + #| guard t9 == 0 else { return t9 } + #| let t10 = self.10.compare(other.10) + #| guard t10 == 0 else { return t10 } + #| self.11.compare(other.11) + #|} + #|pub impl[ + #| T0 : Compare, + #| T1 : Compare, + #| T2 : Compare, + #| T3 : Compare, + #| T4 : Compare, + #| T5 : Compare, + #| T6 : Compare, + #| T7 : Compare, + #| T8 : Compare, + #| T9 : Compare, + #| T10 : Compare, + #| T11 : Compare, + #| T12 : Compare, + #|] Compare for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) with compare( + #| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12), + #| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12), + #|) -> Int { + #| let t0 = self.0.compare(other.0) + #| guard t0 == 0 else { return t0 } + #| let t1 = self.1.compare(other.1) + #| guard t1 == 0 else { return t1 } + #| let t2 = self.2.compare(other.2) + #| guard t2 == 0 else { return t2 } + #| let t3 = self.3.compare(other.3) + #| guard t3 == 0 else { return t3 } + #| let t4 = self.4.compare(other.4) + #| guard t4 == 0 else { return t4 } + #| let t5 = self.5.compare(other.5) + #| guard t5 == 0 else { return t5 } + #| let t6 = self.6.compare(other.6) + #| guard t6 == 0 else { return t6 } + #| let t7 = self.7.compare(other.7) + #| guard t7 == 0 else { return t7 } + #| let t8 = self.8.compare(other.8) + #| guard t8 == 0 else { return t8 } + #| let t9 = self.9.compare(other.9) + #| guard t9 == 0 else { return t9 } + #| let t10 = self.10.compare(other.10) + #| guard t10 == 0 else { return t10 } + #| let t11 = self.11.compare(other.11) + #| guard t11 == 0 else { return t11 } + #| self.12.compare(other.12) + #|} + #|pub impl[ + #| T0 : Compare, + #| T1 : Compare, + #| T2 : Compare, + #| T3 : Compare, + #| T4 : Compare, + #| T5 : Compare, + #| T6 : Compare, + #| T7 : Compare, + #| T8 : Compare, + #| T9 : Compare, + #| T10 : Compare, + #| T11 : Compare, + #| T12 : Compare, + #| T13 : Compare, + #|] Compare for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) with compare( + #| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13), + #| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13), + #|) -> Int { + #| let t0 = self.0.compare(other.0) + #| guard t0 == 0 else { return t0 } + #| let t1 = self.1.compare(other.1) + #| guard t1 == 0 else { return t1 } + #| let t2 = self.2.compare(other.2) + #| guard t2 == 0 else { return t2 } + #| let t3 = self.3.compare(other.3) + #| guard t3 == 0 else { return t3 } + #| let t4 = self.4.compare(other.4) + #| guard t4 == 0 else { return t4 } + #| let t5 = self.5.compare(other.5) + #| guard t5 == 0 else { return t5 } + #| let t6 = self.6.compare(other.6) + #| guard t6 == 0 else { return t6 } + #| let t7 = self.7.compare(other.7) + #| guard t7 == 0 else { return t7 } + #| let t8 = self.8.compare(other.8) + #| guard t8 == 0 else { return t8 } + #| let t9 = self.9.compare(other.9) + #| guard t9 == 0 else { return t9 } + #| let t10 = self.10.compare(other.10) + #| guard t10 == 0 else { return t10 } + #| let t11 = self.11.compare(other.11) + #| guard t11 == 0 else { return t11 } + #| let t12 = self.12.compare(other.12) + #| guard t12 == 0 else { return t12 } + #| self.13.compare(other.13) + #|} + #|pub impl[ + #| T0 : Compare, + #| T1 : Compare, + #| T2 : Compare, + #| T3 : Compare, + #| T4 : Compare, + #| T5 : Compare, + #| T6 : Compare, + #| T7 : Compare, + #| T8 : Compare, + #| T9 : Compare, + #| T10 : Compare, + #| T11 : Compare, + #| T12 : Compare, + #| T13 : Compare, + #| T14 : Compare, + #|] Compare for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14) with compare( + #| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14), + #| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14), + #|) -> Int { + #| let t0 = self.0.compare(other.0) + #| guard t0 == 0 else { return t0 } + #| let t1 = self.1.compare(other.1) + #| guard t1 == 0 else { return t1 } + #| let t2 = self.2.compare(other.2) + #| guard t2 == 0 else { return t2 } + #| let t3 = self.3.compare(other.3) + #| guard t3 == 0 else { return t3 } + #| let t4 = self.4.compare(other.4) + #| guard t4 == 0 else { return t4 } + #| let t5 = self.5.compare(other.5) + #| guard t5 == 0 else { return t5 } + #| let t6 = self.6.compare(other.6) + #| guard t6 == 0 else { return t6 } + #| let t7 = self.7.compare(other.7) + #| guard t7 == 0 else { return t7 } + #| let t8 = self.8.compare(other.8) + #| guard t8 == 0 else { return t8 } + #| let t9 = self.9.compare(other.9) + #| guard t9 == 0 else { return t9 } + #| let t10 = self.10.compare(other.10) + #| guard t10 == 0 else { return t10 } + #| let t11 = self.11.compare(other.11) + #| guard t11 == 0 else { return t11 } + #| let t12 = self.12.compare(other.12) + #| guard t12 == 0 else { return t12 } + #| let t13 = self.13.compare(other.13) + #| guard t13 == 0 else { return t13 } + #| self.14.compare(other.14) + #|} + #|pub impl[ + #| T0 : Compare, + #| T1 : Compare, + #| T2 : Compare, + #| T3 : Compare, + #| T4 : Compare, + #| T5 : Compare, + #| T6 : Compare, + #| T7 : Compare, + #| T8 : Compare, + #| T9 : Compare, + #| T10 : Compare, + #| T11 : Compare, + #| T12 : Compare, + #| T13 : Compare, + #| T14 : Compare, + #| T15 : Compare, + #|] Compare for ( + #| T0, + #| T1, + #| T2, + #| T3, + #| T4, + #| T5, + #| T6, + #| T7, + #| T8, + #| T9, + #| T10, + #| T11, + #| T12, + #| T13, + #| T14, + #| T15, + #|) with compare( + #| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15), + #| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15), + #|) -> Int { + #| let t0 = self.0.compare(other.0) + #| guard t0 == 0 else { return t0 } + #| let t1 = self.1.compare(other.1) + #| guard t1 == 0 else { return t1 } + #| let t2 = self.2.compare(other.2) + #| guard t2 == 0 else { return t2 } + #| let t3 = self.3.compare(other.3) + #| guard t3 == 0 else { return t3 } + #| let t4 = self.4.compare(other.4) + #| guard t4 == 0 else { return t4 } + #| let t5 = self.5.compare(other.5) + #| guard t5 == 0 else { return t5 } + #| let t6 = self.6.compare(other.6) + #| guard t6 == 0 else { return t6 } + #| let t7 = self.7.compare(other.7) + #| guard t7 == 0 else { return t7 } + #| let t8 = self.8.compare(other.8) + #| guard t8 == 0 else { return t8 } + #| let t9 = self.9.compare(other.9) + #| guard t9 == 0 else { return t9 } + #| let t10 = self.10.compare(other.10) + #| guard t10 == 0 else { return t10 } + #| let t11 = self.11.compare(other.11) + #| guard t11 == 0 else { return t11 } + #| let t12 = self.12.compare(other.12) + #| guard t12 == 0 else { return t12 } + #| let t13 = self.13.compare(other.13) + #| guard t13 == 0 else { return t13 } + #| let t14 = self.14.compare(other.14) + #| guard t14 == 0 else { return t14 } + #| self.15.compare(other.15) + #|} + ), + "tuple_eq.mbt": ( + #|pub impl[T0 : Eq, T1 : Eq] Eq for (T0, T1) with equal( + #| self : (T0, T1), + #| other : (T0, T1), + #|) -> Bool { + #| self.0 == other.0 && self.1 == other.1 + #|} + #|pub impl[T0 : Eq, T1 : Eq, T2 : Eq] Eq for (T0, T1, T2) with equal( + #| self : (T0, T1, T2), + #| other : (T0, T1, T2), + #|) -> Bool { + #| self.0 == other.0 && self.1 == other.1 && self.2 == other.2 + #|} + #|pub impl[T0 : Eq, T1 : Eq, T2 : Eq, T3 : Eq] Eq for (T0, T1, T2, T3) with equal( + #| self : (T0, T1, T2, T3), + #| other : (T0, T1, T2, T3), + #|) -> Bool { + #| self.0 == other.0 && + #| self.1 == other.1 && + #| self.2 == other.2 && + #| self.3 == other.3 + #|} + #|pub impl[T0 : Eq, T1 : Eq, T2 : Eq, T3 : Eq, T4 : Eq] Eq for ( + #| T0, + #| T1, + #| T2, + #| T3, + #| T4, + #|) with equal(self : (T0, T1, T2, T3, T4), other : (T0, T1, T2, T3, T4)) -> Bool { + #| self.0 == other.0 && + #| self.1 == other.1 && + #| self.2 == other.2 && + #| self.3 == other.3 && + #| self.4 == other.4 + #|} + #|pub impl[T0 : Eq, T1 : Eq, T2 : Eq, T3 : Eq, T4 : Eq, T5 : Eq] Eq for ( + #| T0, + #| T1, + #| T2, + #| T3, + #| T4, + #| T5, + #|) with equal(self : (T0, T1, T2, T3, T4, T5), other : (T0, T1, T2, T3, T4, T5)) -> Bool { + #| self.0 == other.0 && + #| self.1 == other.1 && + #| self.2 == other.2 && + #| self.3 == other.3 && + #| self.4 == other.4 && + #| self.5 == other.5 + #|} + #|pub impl[T0 : Eq, T1 : Eq, T2 : Eq, T3 : Eq, T4 : Eq, T5 : Eq, T6 : Eq] Eq for ( + #| T0, + #| T1, + #| T2, + #| T3, + #| T4, + #| T5, + #| T6, + #|) with equal( + #| self : (T0, T1, T2, T3, T4, T5, T6), + #| other : (T0, T1, T2, T3, T4, T5, T6), + #|) -> Bool { + #| self.0 == other.0 && + #| self.1 == other.1 && + #| self.2 == other.2 && + #| self.3 == other.3 && + #| self.4 == other.4 && + #| self.5 == other.5 && + #| self.6 == other.6 + #|} + #|pub impl[T0 : Eq, T1 : Eq, T2 : Eq, T3 : Eq, T4 : Eq, T5 : Eq, T6 : Eq, T7 : Eq] Eq for ( + #| T0, + #| T1, + #| T2, + #| T3, + #| T4, + #| T5, + #| T6, + #| T7, + #|) with equal( + #| self : (T0, T1, T2, T3, T4, T5, T6, T7), + #| other : (T0, T1, T2, T3, T4, T5, T6, T7), + #|) -> Bool { + #| self.0 == other.0 && + #| self.1 == other.1 && + #| self.2 == other.2 && + #| self.3 == other.3 && + #| self.4 == other.4 && + #| self.5 == other.5 && + #| self.6 == other.6 && + #| self.7 == other.7 + #|} + #|pub impl[ + #| T0 : Eq, + #| T1 : Eq, + #| T2 : Eq, + #| T3 : Eq, + #| T4 : Eq, + #| T5 : Eq, + #| T6 : Eq, + #| T7 : Eq, + #| T8 : Eq, + #|] Eq for (T0, T1, T2, T3, T4, T5, T6, T7, T8) with equal( + #| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8), + #| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8), + #|) -> Bool { + #| self.0 == other.0 && + #| self.1 == other.1 && + #| self.2 == other.2 && + #| self.3 == other.3 && + #| self.4 == other.4 && + #| self.5 == other.5 && + #| self.6 == other.6 && + #| self.7 == other.7 && + #| self.8 == other.8 + #|} + #|pub impl[ + #| T0 : Eq, + #| T1 : Eq, + #| T2 : Eq, + #| T3 : Eq, + #| T4 : Eq, + #| T5 : Eq, + #| T6 : Eq, + #| T7 : Eq, + #| T8 : Eq, + #| T9 : Eq, + #|] Eq for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) with equal( + #| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9), + #| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9), + #|) -> Bool { + #| self.0 == other.0 && + #| self.1 == other.1 && + #| self.2 == other.2 && + #| self.3 == other.3 && + #| self.4 == other.4 && + #| self.5 == other.5 && + #| self.6 == other.6 && + #| self.7 == other.7 && + #| self.8 == other.8 && + #| self.9 == other.9 + #|} + #|pub impl[ + #| T0 : Eq, + #| T1 : Eq, + #| T2 : Eq, + #| T3 : Eq, + #| T4 : Eq, + #| T5 : Eq, + #| T6 : Eq, + #| T7 : Eq, + #| T8 : Eq, + #| T9 : Eq, + #| T10 : Eq, + #|] Eq for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) with equal( + #| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10), + #| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10), + #|) -> Bool { + #| self.0 == other.0 && + #| self.1 == other.1 && + #| self.2 == other.2 && + #| self.3 == other.3 && + #| self.4 == other.4 && + #| self.5 == other.5 && + #| self.6 == other.6 && + #| self.7 == other.7 && + #| self.8 == other.8 && + #| self.9 == other.9 && + #| self.10 == other.10 + #|} + #|pub impl[ + #| T0 : Eq, + #| T1 : Eq, + #| T2 : Eq, + #| T3 : Eq, + #| T4 : Eq, + #| T5 : Eq, + #| T6 : Eq, + #| T7 : Eq, + #| T8 : Eq, + #| T9 : Eq, + #| T10 : Eq, + #| T11 : Eq, + #|] Eq for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) with equal( + #| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11), + #| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11), + #|) -> Bool { + #| self.0 == other.0 && + #| self.1 == other.1 && + #| self.2 == other.2 && + #| self.3 == other.3 && + #| self.4 == other.4 && + #| self.5 == other.5 && + #| self.6 == other.6 && + #| self.7 == other.7 && + #| self.8 == other.8 && + #| self.9 == other.9 && + #| self.10 == other.10 && + #| self.11 == other.11 + #|} + #|pub impl[ + #| T0 : Eq, + #| T1 : Eq, + #| T2 : Eq, + #| T3 : Eq, + #| T4 : Eq, + #| T5 : Eq, + #| T6 : Eq, + #| T7 : Eq, + #| T8 : Eq, + #| T9 : Eq, + #| T10 : Eq, + #| T11 : Eq, + #| T12 : Eq, + #|] Eq for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) with equal( + #| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12), + #| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12), + #|) -> Bool { + #| self.0 == other.0 && + #| self.1 == other.1 && + #| self.2 == other.2 && + #| self.3 == other.3 && + #| self.4 == other.4 && + #| self.5 == other.5 && + #| self.6 == other.6 && + #| self.7 == other.7 && + #| self.8 == other.8 && + #| self.9 == other.9 && + #| self.10 == other.10 && + #| self.11 == other.11 && + #| self.12 == other.12 + #|} + #|pub impl[ + #| T0 : Eq, + #| T1 : Eq, + #| T2 : Eq, + #| T3 : Eq, + #| T4 : Eq, + #| T5 : Eq, + #| T6 : Eq, + #| T7 : Eq, + #| T8 : Eq, + #| T9 : Eq, + #| T10 : Eq, + #| T11 : Eq, + #| T12 : Eq, + #| T13 : Eq, + #|] Eq for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) with equal( + #| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13), + #| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13), + #|) -> Bool { + #| self.0 == other.0 && + #| self.1 == other.1 && + #| self.2 == other.2 && + #| self.3 == other.3 && + #| self.4 == other.4 && + #| self.5 == other.5 && + #| self.6 == other.6 && + #| self.7 == other.7 && + #| self.8 == other.8 && + #| self.9 == other.9 && + #| self.10 == other.10 && + #| self.11 == other.11 && + #| self.12 == other.12 && + #| self.13 == other.13 + #|} + #|pub impl[ + #| T0 : Eq, + #| T1 : Eq, + #| T2 : Eq, + #| T3 : Eq, + #| T4 : Eq, + #| T5 : Eq, + #| T6 : Eq, + #| T7 : Eq, + #| T8 : Eq, + #| T9 : Eq, + #| T10 : Eq, + #| T11 : Eq, + #| T12 : Eq, + #| T13 : Eq, + #| T14 : Eq, + #|] Eq for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14) with equal( + #| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14), + #| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14), + #|) -> Bool { + #| self.0 == other.0 && + #| self.1 == other.1 && + #| self.2 == other.2 && + #| self.3 == other.3 && + #| self.4 == other.4 && + #| self.5 == other.5 && + #| self.6 == other.6 && + #| self.7 == other.7 && + #| self.8 == other.8 && + #| self.9 == other.9 && + #| self.10 == other.10 && + #| self.11 == other.11 && + #| self.12 == other.12 && + #| self.13 == other.13 && + #| self.14 == other.14 + #|} + #|pub impl[ + #| T0 : Eq, + #| T1 : Eq, + #| T2 : Eq, + #| T3 : Eq, + #| T4 : Eq, + #| T5 : Eq, + #| T6 : Eq, + #| T7 : Eq, + #| T8 : Eq, + #| T9 : Eq, + #| T10 : Eq, + #| T11 : Eq, + #| T12 : Eq, + #| T13 : Eq, + #| T14 : Eq, + #| T15 : Eq, + #|] Eq for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15) with equal( + #| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15), + #| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15), + #|) -> Bool { + #| self.0 == other.0 && + #| self.1 == other.1 && + #| self.2 == other.2 && + #| self.3 == other.3 && + #| self.4 == other.4 && + #| self.5 == other.5 && + #| self.6 == other.6 && + #| self.7 == other.7 && + #| self.8 == other.8 && + #| self.9 == other.9 && + #| self.10 == other.10 && + #| self.11 == other.11 && + #| self.12 == other.12 && + #| self.13 == other.13 && + #| self.14 == other.14 && + #| self.15 == other.15 + #|} + ), + "tuple_hash.mbt": ( + #|pub impl[A : Hash, B : Hash] Hash for (A, B) with hash_combine(self, hasher) { + #| let (a, b) = self + #| hasher.combine(a) + #| hasher.combine(b) + #|} + #|pub impl[A : Hash, B : Hash, C : Hash] Hash for (A, B, C) with hash_combine( + #| self, + #| hasher, + #|) { + #| let (a, b, c) = self + #| hasher.combine(a) + #| hasher.combine(b) + #| hasher.combine(c) + #|} + #|pub impl[A : Hash, B : Hash, C : Hash, D : Hash] Hash for (A, B, C, D) with hash_combine( + #| self, + #| hasher, + #|) { + #| let (a, b, c, d) = self + #| hasher.combine(a) + #| hasher.combine(b) + #| hasher.combine(c) + #| hasher.combine(d) + #|} + #|pub impl[A : Hash, B : Hash, C : Hash, D : Hash, E : Hash] Hash for ( + #| A, + #| B, + #| C, + #| D, + #| E, + #|) with hash_combine(self, hasher) { + #| let (a, b, c, d, e) = self + #| hasher.combine(a) + #| hasher.combine(b) + #| hasher.combine(c) + #| hasher.combine(d) + #| hasher.combine(e) + #|} + #|pub impl[A : Hash, B : Hash, C : Hash, D : Hash, E : Hash, F : Hash] Hash for ( + #| A, + #| B, + #| C, + #| D, + #| E, + #| F, + #|) with hash_combine(self, hasher) { + #| let (a, b, c, d, e, f) = self + #| hasher.combine(a) + #| hasher.combine(b) + #| hasher.combine(c) + #| hasher.combine(d) + #| hasher.combine(e) + #| hasher.combine(f) + #|} + #|pub impl[A : Hash, B : Hash, C : Hash, D : Hash, E : Hash, F : Hash, G : Hash] Hash for ( + #| A, + #| B, + #| C, + #| D, + #| E, + #| F, + #| G, + #|) with hash_combine(self, hasher) { + #| let (a, b, c, d, e, f, g) = self + #| hasher.combine(a) + #| hasher.combine(b) + #| hasher.combine(c) + #| hasher.combine(d) + #| hasher.combine(e) + #| hasher.combine(f) + #| hasher.combine(g) + #|} + ), + "tuple_show.mbt": ( + #|pub impl[A : Show, B : Show] Show for (A, B) with output(self, logger) { + #| let (a, b) = self + #| logger.write_string("(") + #| logger.write_object(a) + #| logger.write_string(", ") + #| logger.write_object(b) + #| logger.write_string(")") + #|} + #|pub impl[A : Show, B : Show, C : Show] Show for (A, B, C) with output( + #| self, + #| logger, + #|) { + #| let (a, b, c) = self + #| logger.write_string("(") + #| logger.write_object(a) + #| logger.write_string(", ") + #| logger.write_object(b) + #| logger.write_string(", ") + #| logger.write_object(c) + #| logger.write_string(")") + #|} + #|pub impl[A : Show, B : Show, C : Show, D : Show] Show for (A, B, C, D) with output( + #| self, + #| logger, + #|) { + #| let (a, b, c, d) = self + #| logger.write_string("(") + #| logger.write_object(a) + #| logger.write_string(", ") + #| logger.write_object(b) + #| logger.write_string(", ") + #| logger.write_object(c) + #| logger.write_string(", ") + #| logger.write_object(d) + #| logger.write_string(")") + #|} + #|pub impl[A : Show, B : Show, C : Show, D : Show, E : Show] Show for ( + #| A, + #| B, + #| C, + #| D, + #| E, + #|) with output(self, logger) { + #| let (a, b, c, d, e) = self + #| logger.write_string("(") + #| logger.write_object(a) + #| logger.write_string(", ") + #| logger.write_object(b) + #| logger.write_string(", ") + #| logger.write_object(c) + #| logger.write_string(", ") + #| logger.write_object(d) + #| logger.write_string(", ") + #| logger.write_object(e) + #| logger.write_string(")") + #|} + #|pub impl[A : Show, B : Show, C : Show, D : Show, E : Show, F : Show] Show for ( + #| A, + #| B, + #| C, + #| D, + #| E, + #| F, + #|) with output(self, logger) { + #| let (a, b, c, d, e, f) = self + #| logger.write_string("(") + #| logger.write_object(a) + #| logger.write_string(", ") + #| logger.write_object(b) + #| logger.write_string(", ") + #| logger.write_object(c) + #| logger.write_string(", ") + #| logger.write_object(d) + #| logger.write_string(", ") + #| logger.write_object(e) + #| logger.write_string(", ") + #| logger.write_object(f) + #| logger.write_string(")") + #|} + #|pub impl[A : Show, B : Show, C : Show, D : Show, E : Show, F : Show, G : Show] Show for ( + #| A, + #| B, + #| C, + #| D, + #| E, + #| F, + #| G, + #|) with output(self, logger) { + #| let (a, b, c, d, e, f, g) = self + #| logger.write_string("(") + #| logger.write_object(a) + #| logger.write_string(", ") + #| logger.write_object(b) + #| logger.write_string(", ") + #| logger.write_object(c) + #| logger.write_string(", ") + #| logger.write_object(d) + #| logger.write_string(", ") + #| logger.write_object(e) + #| logger.write_string(", ") + #| logger.write_object(f) + #| logger.write_string(", ") + #| logger.write_object(g) + #| logger.write_string(")") + #|} + #|pub impl[ + #| T0 : Show, + #| T1 : Show, + #| T2 : Show, + #| T3 : Show, + #| T4 : Show, + #| T5 : Show, + #| T6 : Show, + #| T7 : Show, + #|] Show for (T0, T1, T2, T3, T4, T5, T6, T7) with output(self, logger) { + #| let (x0, x1, x2, x3, x4, x5, x6, x7) = self + #| logger.write_string("(") + #| logger.write_object(x0) + #| logger.write_string(", ") + #| logger.write_object(x1) + #| logger.write_string(", ") + #| logger.write_object(x2) + #| logger.write_string(", ") + #| logger.write_object(x3) + #| logger.write_string(", ") + #| logger.write_object(x4) + #| logger.write_string(", ") + #| logger.write_object(x5) + #| logger.write_string(", ") + #| logger.write_object(x6) + #| logger.write_string(", ") + #| logger.write_object(x7) + #| logger.write_string(")") + #|} + #|pub impl[ + #| T0 : Show, + #| T1 : Show, + #| T2 : Show, + #| T3 : Show, + #| T4 : Show, + #| T5 : Show, + #| T6 : Show, + #| T7 : Show, + #| T8 : Show, + #|] Show for (T0, T1, T2, T3, T4, T5, T6, T7, T8) with output(self, logger) { + #| let (x0, x1, x2, x3, x4, x5, x6, x7, x8) = self + #| logger.write_string("(") + #| logger.write_object(x0) + #| logger.write_string(", ") + #| logger.write_object(x1) + #| logger.write_string(", ") + #| logger.write_object(x2) + #| logger.write_string(", ") + #| logger.write_object(x3) + #| logger.write_string(", ") + #| logger.write_object(x4) + #| logger.write_string(", ") + #| logger.write_object(x5) + #| logger.write_string(", ") + #| logger.write_object(x6) + #| logger.write_string(", ") + #| logger.write_object(x7) + #| logger.write_string(", ") + #| logger.write_object(x8) + #| logger.write_string(")") + #|} + #|pub impl[ + #| T0 : Show, + #| T1 : Show, + #| T2 : Show, + #| T3 : Show, + #| T4 : Show, + #| T5 : Show, + #| T6 : Show, + #| T7 : Show, + #| T8 : Show, + #| T9 : Show, + #|] Show for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) with output(self, logger) { + #| let (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) = self + #| logger.write_string("(") + #| logger.write_object(x0) + #| logger.write_string(", ") + #| logger.write_object(x1) + #| logger.write_string(", ") + #| logger.write_object(x2) + #| logger.write_string(", ") + #| logger.write_object(x3) + #| logger.write_string(", ") + #| logger.write_object(x4) + #| logger.write_string(", ") + #| logger.write_object(x5) + #| logger.write_string(", ") + #| logger.write_object(x6) + #| logger.write_string(", ") + #| logger.write_object(x7) + #| logger.write_string(", ") + #| logger.write_object(x8) + #| logger.write_string(", ") + #| logger.write_object(x9) + #| logger.write_string(")") + #|} + #|pub impl[ + #| T0 : Show, + #| T1 : Show, + #| T2 : Show, + #| T3 : Show, + #| T4 : Show, + #| T5 : Show, + #| T6 : Show, + #| T7 : Show, + #| T8 : Show, + #| T9 : Show, + #| T10 : Show, + #|] Show for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) with output( + #| self, + #| logger, + #|) { + #| let (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10) = self + #| logger.write_string("(") + #| logger.write_object(x0) + #| logger.write_string(", ") + #| logger.write_object(x1) + #| logger.write_string(", ") + #| logger.write_object(x2) + #| logger.write_string(", ") + #| logger.write_object(x3) + #| logger.write_string(", ") + #| logger.write_object(x4) + #| logger.write_string(", ") + #| logger.write_object(x5) + #| logger.write_string(", ") + #| logger.write_object(x6) + #| logger.write_string(", ") + #| logger.write_object(x7) + #| logger.write_string(", ") + #| logger.write_object(x8) + #| logger.write_string(", ") + #| logger.write_object(x9) + #| logger.write_string(", ") + #| logger.write_object(x10) + #| logger.write_string(")") + #|} + #|pub impl[ + #| T0 : Show, + #| T1 : Show, + #| T2 : Show, + #| T3 : Show, + #| T4 : Show, + #| T5 : Show, + #| T6 : Show, + #| T7 : Show, + #| T8 : Show, + #| T9 : Show, + #| T10 : Show, + #| T11 : Show, + #|] Show for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) with output( + #| self, + #| logger, + #|) { + #| let (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11) = self + #| logger.write_string("(") + #| logger.write_object(x0) + #| logger.write_string(", ") + #| logger.write_object(x1) + #| logger.write_string(", ") + #| logger.write_object(x2) + #| logger.write_string(", ") + #| logger.write_object(x3) + #| logger.write_string(", ") + #| logger.write_object(x4) + #| logger.write_string(", ") + #| logger.write_object(x5) + #| logger.write_string(", ") + #| logger.write_object(x6) + #| logger.write_string(", ") + #| logger.write_object(x7) + #| logger.write_string(", ") + #| logger.write_object(x8) + #| logger.write_string(", ") + #| logger.write_object(x9) + #| logger.write_string(", ") + #| logger.write_object(x10) + #| logger.write_string(", ") + #| logger.write_object(x11) + #| logger.write_string(")") + #|} + #|pub impl[ + #| T0 : Show, + #| T1 : Show, + #| T2 : Show, + #| T3 : Show, + #| T4 : Show, + #| T5 : Show, + #| T6 : Show, + #| T7 : Show, + #| T8 : Show, + #| T9 : Show, + #| T10 : Show, + #| T11 : Show, + #| T12 : Show, + #|] Show for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) with output( + #| self, + #| logger, + #|) { + #| let (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12) = self + #| logger.write_string("(") + #| logger.write_object(x0) + #| logger.write_string(", ") + #| logger.write_object(x1) + #| logger.write_string(", ") + #| logger.write_object(x2) + #| logger.write_string(", ") + #| logger.write_object(x3) + #| logger.write_string(", ") + #| logger.write_object(x4) + #| logger.write_string(", ") + #| logger.write_object(x5) + #| logger.write_string(", ") + #| logger.write_object(x6) + #| logger.write_string(", ") + #| logger.write_object(x7) + #| logger.write_string(", ") + #| logger.write_object(x8) + #| logger.write_string(", ") + #| logger.write_object(x9) + #| logger.write_string(", ") + #| logger.write_object(x10) + #| logger.write_string(", ") + #| logger.write_object(x11) + #| logger.write_string(", ") + #| logger.write_object(x12) + #| logger.write_string(")") + #|} + #|pub impl[ + #| T0 : Show, + #| T1 : Show, + #| T2 : Show, + #| T3 : Show, + #| T4 : Show, + #| T5 : Show, + #| T6 : Show, + #| T7 : Show, + #| T8 : Show, + #| T9 : Show, + #| T10 : Show, + #| T11 : Show, + #| T12 : Show, + #| T13 : Show, + #|] Show for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) with output( + #| self, + #| logger, + #|) { + #| let (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13) = self + #| logger.write_string("(") + #| logger.write_object(x0) + #| logger.write_string(", ") + #| logger.write_object(x1) + #| logger.write_string(", ") + #| logger.write_object(x2) + #| logger.write_string(", ") + #| logger.write_object(x3) + #| logger.write_string(", ") + #| logger.write_object(x4) + #| logger.write_string(", ") + #| logger.write_object(x5) + #| logger.write_string(", ") + #| logger.write_object(x6) + #| logger.write_string(", ") + #| logger.write_object(x7) + #| logger.write_string(", ") + #| logger.write_object(x8) + #| logger.write_string(", ") + #| logger.write_object(x9) + #| logger.write_string(", ") + #| logger.write_object(x10) + #| logger.write_string(", ") + #| logger.write_object(x11) + #| logger.write_string(", ") + #| logger.write_object(x12) + #| logger.write_string(", ") + #| logger.write_object(x13) + #| logger.write_string(")") + #|} + #|pub impl[ + #| T0 : Show, + #| T1 : Show, + #| T2 : Show, + #| T3 : Show, + #| T4 : Show, + #| T5 : Show, + #| T6 : Show, + #| T7 : Show, + #| T8 : Show, + #| T9 : Show, + #| T10 : Show, + #| T11 : Show, + #| T12 : Show, + #| T13 : Show, + #| T14 : Show, + #|] Show for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14) with output( + #| self, + #| logger, + #|) { + #| let (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14) = self + #| logger.write_string("(") + #| logger.write_object(x0) + #| logger.write_string(", ") + #| logger.write_object(x1) + #| logger.write_string(", ") + #| logger.write_object(x2) + #| logger.write_string(", ") + #| logger.write_object(x3) + #| logger.write_string(", ") + #| logger.write_object(x4) + #| logger.write_string(", ") + #| logger.write_object(x5) + #| logger.write_string(", ") + #| logger.write_object(x6) + #| logger.write_string(", ") + #| logger.write_object(x7) + #| logger.write_string(", ") + #| logger.write_object(x8) + #| logger.write_string(", ") + #| logger.write_object(x9) + #| logger.write_string(", ") + #| logger.write_object(x10) + #| logger.write_string(", ") + #| logger.write_object(x11) + #| logger.write_string(", ") + #| logger.write_object(x12) + #| logger.write_string(", ") + #| logger.write_object(x13) + #| logger.write_string(", ") + #| logger.write_object(x14) + #| logger.write_string(")") + #|} + #|pub impl[ + #| T0 : Show, + #| T1 : Show, + #| T2 : Show, + #| T3 : Show, + #| T4 : Show, + #| T5 : Show, + #| T6 : Show, + #| T7 : Show, + #| T8 : Show, + #| T9 : Show, + #| T10 : Show, + #| T11 : Show, + #| T12 : Show, + #| T13 : Show, + #| T14 : Show, + #| T15 : Show, + #|] Show for ( + #| T0, + #| T1, + #| T2, + #| T3, + #| T4, + #| T5, + #| T6, + #| T7, + #| T8, + #| T9, + #| T10, + #| T11, + #| T12, + #| T13, + #| T14, + #| T15, + #|) with output(self, logger) { + #| let (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15) = self + #| logger.write_string("(") + #| logger.write_object(x0) + #| logger.write_string(", ") + #| logger.write_object(x1) + #| logger.write_string(", ") + #| logger.write_object(x2) + #| logger.write_string(", ") + #| logger.write_object(x3) + #| logger.write_string(", ") + #| logger.write_object(x4) + #| logger.write_string(", ") + #| logger.write_object(x5) + #| logger.write_string(", ") + #| logger.write_object(x6) + #| logger.write_string(", ") + #| logger.write_object(x7) + #| logger.write_string(", ") + #| logger.write_object(x8) + #| logger.write_string(", ") + #| logger.write_object(x9) + #| logger.write_string(", ") + #| logger.write_object(x10) + #| logger.write_string(", ") + #| logger.write_object(x11) + #| logger.write_string(", ") + #| logger.write_object(x12) + #| logger.write_string(", ") + #| logger.write_object(x13) + #| logger.write_string(", ") + #| logger.write_object(x14) + #| logger.write_string(", ") + #| logger.write_object(x15) + #| logger.write_string(")") + #|} + ), + "tuple_to_json.mbt": ( + #|pub impl[A : ToJson, B : ToJson] ToJson for (A, B) with to_json(self) { + #| let (a0, a1) = self + #| [a0, a1] + #|} + #|pub impl[A : ToJson, B : ToJson, C : ToJson] ToJson for (A, B, C) with to_json( + #| self, + #|) { + #| let (a0, a1, a2) = self + #| [a0, a1, a2] + #|} + #|pub impl[A : ToJson, B : ToJson, C : ToJson, D : ToJson] ToJson for (A, B, C, D) with to_json( + #| self, + #|) { + #| let (a0, a1, a2, a3) = self + #| [a0, a1, a2, a3] + #|} + #|pub impl[A : ToJson, B : ToJson, C : ToJson, D : ToJson, E : ToJson] ToJson for ( + #| A, + #| B, + #| C, + #| D, + #| E, + #|) with to_json(self) { + #| let (a0, a1, a2, a3, a4) = self + #| [a0, a1, a2, a3, a4] + #|} + #|pub impl[A : ToJson, B : ToJson, C : ToJson, D : ToJson, E : ToJson, F : ToJson] ToJson for ( + #| A, + #| B, + #| C, + #| D, + #| E, + #| F, + #|) with to_json(self) { + #| let (a0, a1, a2, a3, a4, a5) = self + #| [a0, a1, a2, a3, a4, a5] + #|} + #|pub impl[ + #| A : ToJson, + #| B : ToJson, + #| C : ToJson, + #| D : ToJson, + #| E : ToJson, + #| F : ToJson, + #| G : ToJson, + #|] ToJson for (A, B, C, D, E, F, G) with to_json(self) { + #| let (a0, a1, a2, a3, a4, a5, a6) = self + #| [a0, a1, a2, a3, a4, a5, a6] + #|} + #|pub impl[ + #| A : ToJson, + #| B : ToJson, + #| C : ToJson, + #| D : ToJson, + #| E : ToJson, + #| F : ToJson, + #| G : ToJson, + #| H : ToJson, + #|] ToJson for (A, B, C, D, E, F, G, H) with to_json(self) { + #| let (a0, a1, a2, a3, a4, a5, a6, a7) = self + #| [a0, a1, a2, a3, a4, a5, a6, a7] + #|} + #|pub impl[ + #| A : ToJson, + #| B : ToJson, + #| C : ToJson, + #| D : ToJson, + #| E : ToJson, + #| F : ToJson, + #| G : ToJson, + #| H : ToJson, + #| I : ToJson, + #|] ToJson for (A, B, C, D, E, F, G, H, I) with to_json(self) { + #| let (a0, a1, a2, a3, a4, a5, a6, a7, a8) = self + #| [a0, a1, a2, a3, a4, a5, a6, a7, a8] + #|} + #|pub impl[ + #| A : ToJson, + #| B : ToJson, + #| C : ToJson, + #| D : ToJson, + #| E : ToJson, + #| F : ToJson, + #| G : ToJson, + #| H : ToJson, + #| I : ToJson, + #| J : ToJson, + #|] ToJson for (A, B, C, D, E, F, G, H, I, J) with to_json(self) { + #| let (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) = self + #| [a0, a1, a2, a3, a4, a5, a6, a7, a8, a9] + #|} + #|pub impl[ + #| A : ToJson, + #| B : ToJson, + #| C : ToJson, + #| D : ToJson, + #| E : ToJson, + #| F : ToJson, + #| G : ToJson, + #| H : ToJson, + #| I : ToJson, + #| J : ToJson, + #| K : ToJson, + #|] ToJson for (A, B, C, D, E, F, G, H, I, J, K) with to_json(self) { + #| let (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) = self + #| [a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10] + #|} + #|pub impl[ + #| A : ToJson, + #| B : ToJson, + #| C : ToJson, + #| D : ToJson, + #| E : ToJson, + #| F : ToJson, + #| G : ToJson, + #| H : ToJson, + #| I : ToJson, + #| J : ToJson, + #| K : ToJson, + #| L : ToJson, + #|] ToJson for (A, B, C, D, E, F, G, H, I, J, K, L) with to_json(self) { + #| let (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11) = self + #| [a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11] + #|} + #|pub impl[ + #| A : ToJson, + #| B : ToJson, + #| C : ToJson, + #| D : ToJson, + #| E : ToJson, + #| F : ToJson, + #| G : ToJson, + #| H : ToJson, + #| I : ToJson, + #| J : ToJson, + #| K : ToJson, + #| L : ToJson, + #| M : ToJson, + #|] ToJson for (A, B, C, D, E, F, G, H, I, J, K, L, M) with to_json(self) { + #| let (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12) = self + #| [a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12] + #|} + #|pub impl[ + #| A : ToJson, + #| B : ToJson, + #| C : ToJson, + #| D : ToJson, + #| E : ToJson, + #| F : ToJson, + #| G : ToJson, + #| H : ToJson, + #| I : ToJson, + #| J : ToJson, + #| K : ToJson, + #| L : ToJson, + #| M : ToJson, + #| N : ToJson, + #|] ToJson for (A, B, C, D, E, F, G, H, I, J, K, L, M, N) with to_json(self) { + #| let (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13) = self + #| [a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13] + #|} + #|pub impl[ + #| A : ToJson, + #| B : ToJson, + #| C : ToJson, + #| D : ToJson, + #| E : ToJson, + #| F : ToJson, + #| G : ToJson, + #| H : ToJson, + #| I : ToJson, + #| J : ToJson, + #| K : ToJson, + #| L : ToJson, + #| M : ToJson, + #| N : ToJson, + #| O : ToJson, + #|] ToJson for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O) with to_json(self) { + #| let (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14) = self + #| [a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14] + #|} + #|pub impl[ + #| A : ToJson, + #| B : ToJson, + #| C : ToJson, + #| D : ToJson, + #| E : ToJson, + #| F : ToJson, + #| G : ToJson, + #| H : ToJson, + #| I : ToJson, + #| J : ToJson, + #| K : ToJson, + #| L : ToJson, + #| M : ToJson, + #| N : ToJson, + #| O : ToJson, + #| P : ToJson, + #|] ToJson for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P) with to_json(self) { + #| let (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15) = self + #| [a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15] + #|} + ), + "uint.mbt": ( + #|pub fn UInt::min(self : UInt, other : UInt) -> UInt { + #| if self < other { + #| self + #| } else { + #| other + #| } + #|} + #|pub fn UInt::max(self : UInt, other : UInt) -> UInt { + #| if self > other { + #| self + #| } else { + #| other + #| } + #|} + #|pub fn UInt::clamp(self : UInt, min~ : UInt, max~ : UInt) -> UInt { + #| guard min <= max + #| if self < min { + #| min + #| } else if self > max { + #| max + #| } else { + #| self + #| } + #|} + ), + "uint16_char.mbt": ( + #|pub fn UInt16::is_leading_surrogate(self : Self) -> Bool { + #| self >= 0xD800 && self <= 0xDBFF + #|} + #|pub fn UInt16::is_trailing_surrogate(self : Self) -> Bool { + #| self >= 0xDC00 && self <= 0xDFFF + #|} + #|pub fn UInt16::is_surrogate(self : Self) -> Bool { + #| self >= 0xD800 && self <= 0xDFFF + #|} + #|pub fn UInt16::unsafe_to_char(self : UInt16) -> Char { + #| self.to_int().unsafe_to_char() + #|} + #|pub fn UInt16::to_char(self : UInt16) -> Char? { + #| if self is (0..=0xD7FF) || self is (0xE000..<_) { + #| Some(self.unsafe_to_char()) + #| } else { + #| None + #| } + #|} + #|pub impl Add for UInt16 with add(self : UInt16, that : UInt16) -> UInt16 { + #| (self.to_int() + that.to_int()).to_uint16() + #|} + #|pub impl Sub for UInt16 with sub(self : UInt16, that : UInt16) -> UInt16 { + #| (self.to_int() - that.to_int()).to_uint16() + #|} + #|pub impl Mul for UInt16 with mul(self : UInt16, that : UInt16) -> UInt16 { + #| (self.to_int() * that.to_int()).to_uint16() + #|} + #|pub impl Div for UInt16 with div(self : UInt16, that : UInt16) -> UInt16 { + #| (self.to_int() / that.to_int()).to_uint16() + #|} + #|pub impl Mod for UInt16 with mod(self : UInt16, that : UInt16) -> UInt16 { + #| (self.to_int() % that.to_int()).to_uint16() + #|} + #|pub impl Eq for UInt16 with equal(self, that) { + #| self.to_int() == that.to_int() + #|} + #|pub impl Eq for UInt16 with not_equal(self, that) { + #| self.to_int() != that.to_int() + #|} + #|pub impl Compare for UInt16 with compare(self, that) { + #| self.to_int().compare(that.to_int()) + #|} + #|pub impl Hash for UInt16 with hash_combine(self, hasher) { + #| hasher.combine_int(self.to_int()) + #|} + #|pub impl Shl for UInt16 with shl(self : UInt16, that : Int) -> UInt16 { + #| (self.to_int() << that).to_uint16() + #|} + #|pub impl Shr for UInt16 with shr(self : UInt16, that : Int) -> UInt16 { + #| (self.to_int() >> that).to_uint16() + #|} + #|pub impl BitOr for UInt16 with lor(self : UInt16, that : UInt16) -> UInt16 { + #| (self.to_int() | that.to_int()).to_uint16() + #|} + #|pub impl BitAnd for UInt16 with land(self : UInt16, that : UInt16) -> UInt16 { + #| (self.to_int() & that.to_int()).to_uint16() + #|} + #|pub impl BitXOr for UInt16 with lxor(self : UInt16, that : UInt16) -> UInt16 { + #| (self.to_int() ^ that.to_int()).to_uint16() + #|} + #|pub impl Default for UInt16 with default() { + #| 0 + #|} + #|pub impl ToJson for UInt16 with to_json(self : UInt16) -> Json { + #| Json::number(self.to_int().to_double()) + #|} + #|pub fn UInt16::to_uint(self : UInt16) -> UInt { + #| self.to_int().reinterpret_as_uint() + #|} + #|pub fn UInt16::to_uint64(self : UInt16) -> UInt64 { + #| self.to_int().to_uint64() + #|} + ), + "uint64.mbt": ( + #|pub impl Default for UInt64 with default() { + #| 0 + #|} + #|test { + #| inspect(0x7000_0001_1F00_100FUL.popcnt(), content="14") + #|} + #|pub fn UInt64::to_be_bytes(self : UInt64) -> Bytes { + #| [ + #| (self >> 56).to_byte(), + #| (self >> 48).to_byte(), + #| (self >> 40).to_byte(), + #| (self >> 32).to_byte(), + #| (self >> 24).to_byte(), + #| (self >> 16).to_byte(), + #| (self >> 8).to_byte(), + #| self.to_byte(), + #| ] + #|} + #|pub fn UInt64::to_le_bytes(self : UInt64) -> Bytes { + #| [ + #| self.to_byte(), + #| (self >> 8).to_byte(), + #| (self >> 16).to_byte(), + #| (self >> 24).to_byte(), + #| (self >> 32).to_byte(), + #| (self >> 40).to_byte(), + #| (self >> 48).to_byte(), + #| (self >> 56).to_byte(), + #| ] + #|} + ), + "uninitialized_array.mbt": ( + #|struct UninitializedArray[T](FixedArray[UnsafeMaybeUninit[T]]) + #|pub fn[T] UninitializedArray::make(size : Int) -> UninitializedArray[T] = "%fixedarray.make_uninit" + #|#alias("_[_]") + #|pub fn[T] UninitializedArray::at( + #| self : UninitializedArray[T], + #| index : Int, + #|) -> T = "%fixedarray.get" + #|#alias("_[_]=_") + #|pub fn[T] UninitializedArray::set( + #| self : UninitializedArray[T], + #| index : Int, + #| value : T, + #|) = "%fixedarray.set" + #|#alias("_[_:_]") + #|pub fn[T] UninitializedArray::sub( + #| self : UninitializedArray[T], + #| start? : Int = 0, + #| end? : Int, + #|) -> ArrayView[T] { + #| let len = self.length() + #| let end = match end { + #| None => len + #| Some(end) => end + #| } + #| guard start >= 0 && start <= end && end <= len else { + #| abort("View start index out of bounds") + #| } + #| ArrayView::make(self, start, end - start) + #|} + #|pub fn[A] UninitializedArray::length(self : UninitializedArray[A]) -> Int { + #| self.0.length() + #|} + #|#internal(unsafe, "For internal use only.") + #|#doc(hidden) + #|pub fn[T] UninitializedArray::unsafe_blit( + #| dst : UninitializedArray[T], + #| dst_offset : Int, + #| src : UninitializedArray[T], + #| src_offset : Int, + #| len : Int, + #|) -> Unit { + #| FixedArray::unsafe_blit(dst.0, dst_offset, src.0, src_offset, len) + #|} + #|test "as_view with valid_range" { + #| let arr : UninitializedArray[Int] = UninitializedArray::make(5) + #| let view = arr[1:4] + #| inspect(view.start(), content="1") + #| inspect(view.len(), content="3") + #|} + #|test "panic as_view with invalid_start" { + #| let arr : UninitializedArray[Int] = UninitializedArray::make(5) + #| ignore(arr[-1:]) + #|} + #|test "panic as_view with invalid_end" { + #| let arr : UninitializedArray[Int] = UninitializedArray::make(5) + #| ignore(arr[2:10]) + #|} + #|#coverage.skip + #|#intrinsic("%fixedarray.fill") + #|#cfg(not(target="js")) + #|fn[T] UninitializedArray::unchecked_fill( + #| self : UninitializedArray[T], + #| start : Int, + #| value : T, + #| len : Int, + #|) -> Unit { + #| for i in start..<(start + len) { + #| self[i] = value + #| } + #|} + ), + "unit.mbt": ( + #|pub impl Eq for Unit with equal(_ : Unit, _ : Unit) -> Bool { + #| true + #|} + #|pub impl Compare for Unit with compare(_, _) { + #| 0 + #|} + #|pub impl Default for Unit with default() -> Unit { + #| () + #|} + #|pub impl Hash for Unit with hash_combine(_, hasher) -> Unit { + #| hasher.combine_unit() + #|} + ) + } ) ///| let moonbitlang_core_byte_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/byte", - deps={ "moonbitlang/core/builtin": moonbitlang_core_builtin_module }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": ["moonbitlang/core/builtin"] - #|} - ), - "byte.mbt": ( - #|pub let max_value : Byte = b'\xFF' - #|pub let min_value : Byte = b'\x00' - ), - }, + "byte.mbt": ( + #|pub const MAX_VALUE : Byte = b'\xFF' + #|#deprecated("Use `MAX_VALUE` instead") + #|pub let max_value : Byte = b'\xFF' + #|pub const MIN_VALUE : Byte = b'\x00' + #|#deprecated("Use `MIN_VALUE` instead") + #|pub let min_value : Byte = b'\x00' + ) + } ) ///| let moonbitlang_core_bytes_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/bytes", - deps={ "moonbitlang/core/builtin": moonbitlang_core_builtin_module }, + deps={ }, + files={ + "alias.mbt": ( + #|#deprecated("Use `Bytes::default` instead") + #|#doc(hidden) + #|pub fn default() -> Bytes { + #| b"" + #|} + #|#deprecated("Use `Bytes::from_array` instead") + #|#doc(hidden) + #|pub fn from_fixedarray(arr : FixedArray[Byte], len? : Int) -> Bytes { + #| Bytes::from_array(arr[:len.unwrap_or(arr.length())]) + #|} + #|#deprecated("Use `Bytes::from_iter` instead") + #|#alias(from_iterator, deprecated="Use `Bytes::from_iter` instead") + #|#doc(hidden) + #|pub fn from_iter(iter : Iter[Byte]) -> Bytes { + #| Bytes::from_iter(iter) + #|} + #|#deprecated("Use `Bytes::from_array` instead") + #|#doc(hidden) + #|pub fn of(arr : ArrayView[Byte]) -> Bytes { + #| Bytes::from_array(arr) + #|} + #|#deprecated("Use `Bytes::from_array` instead") + #|#doc(hidden) + #|pub fn from_array(arr : ArrayView[Byte]) -> Bytes { + #| Bytes::from_array(arr) + #|} + #|#deprecated("@bytes.View is deprecated, use BytesView instead.") + #|pub type View = BytesView + ), + "regex.mbt": ( + #|#internal(experimental, "subject to breaking change without notice") + #|struct BytesRegex(@re.Regex) + #|#internal(experimental, "subject to breaking change without notice") + #|struct MatchResult { + #| input : BytesView + #| group_names : ReadOnlyArray[String?] + #| result : @re.MatchResult + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|pub fn MatchResult::before(self : MatchResult) -> BytesView { + #| guard self.result.group(0) is Some((start, _end)) else { panic() } + #| self.input[0:start] + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|pub fn MatchResult::after(self : MatchResult) -> BytesView { + #| guard self.result.group(0) is Some((_start, end)) else { panic() } + #| self.input[end:self.input.length()] + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|pub fn MatchResult::content(self : MatchResult) -> BytesView { + #| guard self.result.group(0) is Some((start, end)) else { panic() } + #| self.input[start:end] + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|pub fn MatchResult::group(self : MatchResult, group_index : Int) -> BytesView? { + #| match self.result.group(group_index) { + #| None => None + #| Some((start, end)) => Some(self.input[start:end]) + #| } + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|pub fn MatchResult::named_group( + #| self : MatchResult, + #| name : String, + #|) -> BytesView? { + #| match self.group_names.search(Some(name)) { + #| None => None + #| Some(index) => self.group(index) + #| } + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|#doc(hidden) + #|pub fn BytesRegex::internal_compile_pattern(pat : @re.Pattern) -> BytesRegex { + #| @re.compile(profile=re_profile, pat) + #|} + #|#internal(experimental, "subject to breaking change without notice") + #|pub fn BytesRegex::execute( + #| self : BytesRegex, + #| input : BytesView, + #| last_index? : Int = 0, + #|) -> MatchResult? { + #| match self.0.execute(input, last_index) { + #| None => None + #| Some(result) => + #| Some(MatchResult::{ input, group_names: self.0.group_names(), result }) + #| } + #|} + ), + "regex_pattern.mbt": ( + #|#internal(internal, "not intended for public use") + #|#doc(hidden) + #|struct Pattern(@re.Pattern) + #|#internal(internal, "not intended for public use") + #|#doc(hidden) + #|pub fn Pattern::epsilon() -> Pattern { + #| Pattern(@re.epsilon) + #|} + #|#internal(internal, "not intended for public use") + #|#doc(hidden) + #|pub fn Pattern::empty() -> Pattern { + #| Pattern(@re.empty) + #|} + #|#internal(internal, "not intended for public use") + #|#doc(hidden) + #|pub fn Pattern::char_range(lo : Int, hi : Int) -> Pattern { + #| Pattern(@re.char(@re.RecharSet::char_range(lo, hi))) + #|} + #|#internal(internal, "not intended for public use") + #|#doc(hidden) + #|pub fn Pattern::char_set(cs : ReadOnlyArray[(Int, Int)]) -> Pattern { + #| Pattern(@re.char(@re.RecharSet::from_sorted_array(cs))) + #|} + #|#internal(internal, "not intended for public use") + #|#doc(hidden) + #|pub fn Pattern::seq(pats : ReadOnlyArray[Pattern]) -> Pattern { + #| Pattern(@re.seq(pats.map(p => p.0))) + #|} + #|#internal(internal, "not intended for public use") + #|#doc(hidden) + #|pub fn Pattern::alt(pats : ReadOnlyArray[Pattern]) -> Pattern { + #| Pattern(@re.alt(pats.map(p => p.0))) + #|} + #|#internal(internal, "not intended for public use") + #|#doc(hidden) + #|pub fn Pattern::quantifier( + #| pat : Pattern, + #| min~ : Int, + #| max~ : Int?, + #| greedy~ : Bool, + #|) -> Pattern { + #| Pattern( + #| @re.quantifier(pat.0, { + #| min, + #| max, + #| mode: if greedy { + #| Greedy + #| } else { + #| NonGreedy + #| }, + #| }), + #| ) + #|} + #|#internal(internal, "not intended for public use") + #|#doc(hidden) + #|pub fn Pattern::capture(pat : Pattern, name? : String) -> Pattern { + #| Pattern(@re.capture(pat.0, name?)) + #|} + #|#internal(internal, "not intended for public use") + #|#doc(hidden) + #|pub fn Pattern::start_of_input() -> Pattern { + #| Pattern(@re.start_of_input) + #|} + #|#internal(internal, "not intended for public use") + #|#doc(hidden) + #|pub fn Pattern::end_of_input() -> Pattern { + #| Pattern(@re.end_of_input) + #|} + ), + "regex_profile.mbt": ( + #|let re_profile : @re.Profile = Profile( + #| valid=@re.RecharSet::char_range(0, 255), + #| word=@re.RecharSet::char_range('a', 'z') + + #| @re.RecharSet::char_range('A', 'Z') + + #| @re.RecharSet::char_range('0', '9') + + #| @re.RecharSet::char('_'), + #| category=c => { + #| match c { + #| 'a'..='z' | 'A'..='Z' | '0'..='9' | '_' => @re.Category::word() + #| '\n' => @re.Category::newline() + #| _ => @re.Category::not_word() + #| } + #| }, + #|) + ) + } +) + +///| +let moonbitlang_core_bytes_internal_regex_engine_module : RuntimePackage = RuntimePackage::new( + "moonbitlang/core/bytes/internal/regex_engine", + deps={ }, + files={ + "compile.mbt": ( + #|pub fn compile(profile~ : Profile, ast : Pattern) -> Regex { + #| let ast = if ast.is_anchored() { + #| capture(ast) + #| } else { + #| seq([ + #| shortest( + #| quantifier(char(profile.valid), { min: 0, max: None, mode: Greedy }), + #| ), + #| capture(ast), + #| ]) + #| } + #| let symbol_map = @symbol_map.new() + #| symbolize(profile~, symbol_map~, ast) + #| let (symbol_table, symbol_repr) = symbol_map.finalize(profile.lb, profile.ub) + #| let ctx = @automata.Context::new() + #| let tc = TranslateContext::new(ctx, symbol_table) + #| let (expr, pref) = translate(tc, ast) + #| let expr = enforce_pref(tc.ctx, First, pref, expr) + #| Regex::new( + #| profile, + #| ctx, + #| expr, + #| ReadOnlyArray::from_array(tc.groups), + #| symbol_table, + #| symbol_repr, + #| ) + #|} + ), + "execute.mbt": ( + #|using @debug {trait Debug, type Repr} + #|struct MatchResult(Array[Int]) derive(Debug) + #|const NULL_SYMBOL : Rechar = -1 + #|fn category_from_symbol( + #| profile~ : Profile, + #| symbol_repr~ : ReadOnlyArray[Rechar], + #| symbol : Rechar, + #|) -> Category { + #| if symbol is NULL_SYMBOL { + #| Category::inexistant() + #| } else { + #| (profile.category)(symbol_repr[symbol]) + #| } + #|} + #|pub fn MatchResult::group(self : MatchResult, index : Int) -> (Int, Int)? { + #| let start_pos = self.0.get(index * 2) + #| guard start_pos is Some(start_pos) && start_pos >= 0 else { None } + #| let end_pos = self.0[index * 2 + 1] + #| guard end_pos >= 0 else { panic() } + #| Some((start_pos, end_pos)) + #|} + #|fn Regex::find_start_state(self : Regex, cat : Category) -> StateId { + #| for i in 0.. MatchResult? { + #| guard lastIndex >= 0 && lastIndex <= input.length() else { panic() } + #| let { states, symbol_table, .. } = self + #| let mut pos = lastIndex + #| let end = input.length() + #| let start_cat = if pos == 0 { + #| Category::inexistant() + #| } else { + #| let prev = input.get(pos - 1) + #| let prev_symbol = symbol_table.map(prev) + #| category_from_symbol( + #| profile=self.profile, + #| symbol_repr=self.symbol_repr, + #| prev_symbol, + #| ) + #| } + #| let start_state_id = self.find_start_state(start_cat) + #| let positions = Positions::new() + #| let mut state_id = start_state_id + #| while pos < end { + #| let state = states.unsafe_get(state_id) + #| let ch = input.get(pos) + #| let symbol = symbol_table.map(ch) + #| let next_state_id = state.transitions.unsafe_get(symbol) + #| state_id = if next_state_id == PENDING_STATE_ID { + #| let cat = category_from_symbol( + #| profile=self.profile, + #| symbol_repr=self.symbol_repr, + #| symbol, + #| ) + #| let next_desc = @automata.delta( + #| ctx=self.ctx, + #| state.desc, + #| symbol, + #| next_cat=cat, + #| ) + #| let next_state_id = find_state( + #| self.state_table, + #| states, + #| self.symbol_repr.length(), + #| next_desc, + #| ) + #| state.transitions[symbol] = next_state_id + #| next_state_id + #| } else { + #| next_state_id + #| } + #| let state = states.unsafe_get(state_id) + #| let slot = state.desc.slot() + #| if slot.index >= positions.0.length() { + #| positions.0.resize(slot.index + 8, -1) + #| } + #| positions.0[slot.index] = pos + #| if state.kind is Break { + #| break + #| } + #| pos += 1 + #| } + #| let state = states.unsafe_get(state_id) + #| let matched = match state.desc.status() { + #| Failed => None + #| Running => { + #| let final_cat = if pos == end { + #| Category::inexistant() + #| } else { + #| let ch = input.get(pos) + #| let symbol = symbol_table.map(ch) + #| category_from_symbol( + #| profile=self.profile, + #| symbol_repr=self.symbol_repr, + #| symbol, + #| ) + #| } + #| let (slot, status) = loop state.final_ { + #| Empty => { + #| let next_desc = @automata.delta( + #| ctx=self.ctx, + #| state.desc, + #| NULL_SYMBOL, + #| next_cat=final_cat, + #| ) + #| let slot = next_desc.slot() + #| let status = next_desc.status() + #| state.final_ = @list.cons((final_cat, slot, status), state.final_) + #| (slot, status) + #| } + #| More(head, tail~) => + #| if head.0 == final_cat { + #| (head.1, head.2) + #| } else { + #| continue tail + #| } + #| } + #| match status { + #| Failed | Running => None + #| Match(marks) => { + #| positions.set(slot, pos) + #| Some(marks) + #| } + #| } + #| } + #| Match(marks) => Some(marks) + #| } + #| match matched { + #| None => None + #| Some(marks) => { + #| let mark_pos = Array::make(self.groups.length() * 2, -1) + #| for mark, slot in marks { + #| mark_pos[mark.0] = positions.get(slot) + #| } + #| Some(MatchResult(mark_pos)) + #| } + #| } + #|} + ), + "input.mbt": ( + #|pub trait Input { + #| length(Self) -> Int + #| get(Self, Int) -> Rechar + #|} + #|pub impl Input for BytesView with length(self) { + #| self.length() + #|} + #|pub impl Input for BytesView with get(self, index) { + #| self.unsafe_get(index).to_int() + #|} + #|pub impl Input for StringView with length(self) { + #| self.length() + #|} + #|pub impl Input for StringView with get(self, index) { + #| self.unsafe_get(index).to_int() + #|} + ), + "positions.mbt": ( + #|priv struct Positions(Array[Int]) + #|fn Positions::new() -> Positions { + #| Positions(Array::make(8, -1)) + #|} + #|#alias("_[_]=_") + #|fn Positions::set(self : Positions, slot : @automata.Slot, pos : Int) -> Unit { + #| if slot.index >= self.0.length() { + #| self.0.resize(slot.index + 8, -1) + #| } + #| self.0[slot.index] = pos + #|} + #|#alias("_[_]") + #|fn Positions::get(self : Positions, slot : @automata.Slot) -> Int { + #| debug_assert(() => slot.is_assigned()) + #| if slot.index >= self.0.length() { + #| -1 + #| } else { + #| self.0[slot.index] + #| } + #|} + ), + "regex.mbt": ( + #|struct Regex { + #| profile : Profile + #| ctx : @automata.Context + #| expr : @automata.Expr + #| groups : ReadOnlyArray[String?] + #| symbol_table : &@symbol_map.Table + #| symbol_repr : ReadOnlyArray[Rechar] + #| start_states : Array[(Category, StateId)] + #| state_table : @hashmap.HashMap[@automata.State, StateId] + #| states : Array[State] + #|} + #|pub fn Regex::group_names(self : Regex) -> ReadOnlyArray[String?] { + #| self.groups + #|} + #|fn Regex::new( + #| profile : Profile, + #| ctx : @automata.Context, + #| expr : @automata.Expr, + #| groups : ReadOnlyArray[String?], + #| symbol_table : &@symbol_map.Table, + #| symbol_repr : ReadOnlyArray[Rechar], + #|) -> Regex { + #| Regex::{ + #| profile, + #| ctx, + #| expr, + #| groups, + #| symbol_table, + #| symbol_repr, + #| start_states: [], + #| state_table: @hashmap.HashMap::new(), + #| states: [], + #| } + #|} + ), + "state.mbt": ( + #|type StateId = Int + #|const PENDING_STATE_ID : StateId = -1 + #|priv struct State { + #| kind : StateKind + #| desc : @automata.State + #| transitions : FixedArray[StateId] // indexed by symbol + #| mut final_ : @list.List[(Category, @automata.Slot, @automata.Status)] + #|} + #|priv enum StateKind { + #| Break + #| Normal + #|} + #|fn State::new(desc : @automata.State, num_symbols : Int) -> State { + #| let is_break = match desc.status() { + #| Match(_) | Failed => true + #| Running => false + #| } + #| State::{ + #| kind: if is_break { + #| Break + #| } else { + #| Normal + #| }, + #| desc, + #| transitions: if is_break { + #| [] + #| } else { + #| FixedArray::make(num_symbols, PENDING_STATE_ID) + #| }, + #| final_: @list.empty(), + #| } + #|} + #|fn find_state( + #| table : @hashmap.HashMap[@automata.State, StateId], + #| states : Array[State], + #| num_symbols : Int, + #| desc : @automata.State, + #|) -> StateId { + #| table.get_or_init(desc, () => { + #| let state_id = states.length() + #| states.push(State::new(desc, num_symbols)) + #| state_id + #| }) + #|} + ), + "symbolize.mbt": ( + #|fn symbolize( + #| profile~ : Profile, + #| symbol_map~ : @symbol_map.SymbolMap, + #| expr : Pattern, + #|) -> Unit { + #| fn aux(expr : Pattern) { + #| match expr.desc { + #| Char(s) => symbol_map.split(s) + #| Sequence(l) => l.each(aux) + #| Alternation(l) => l.each(aux) + #| Quantifier(_, r) => aux(r) + #| Assertion(StartOfLine) | Assertion(EndOfLine) => + #| symbol_map.split(RecharSet::char('\n')) + #| Assertion(StartOfWord) + #| | Assertion(EndOfWord) + #| | Assertion(NotWordBoundary) => + #| for split in profile.word_symbolize_splits { + #| symbol_map.split(split) + #| } + #| Assertion(StartOfInput) | Assertion(EndOfInput) => () + #| Preference(_, r) => aux(r) + #| Capture(r, ..) => aux(r) + #| } + #| } + #| aux(expr) + #|} + ), + "translate.mbt": ( + #|priv struct TranslateContext { + #| ctx : @automata.Context + #| pref : Preference + #| groups : Array[String?] + #| symbol_table : &@symbol_map.Table + #|} + #|fn TranslateContext::new( + #| ctx : @automata.Context, + #| symbol_table : &@symbol_map.Table, + #|) -> TranslateContext { + #| TranslateContext::{ ctx, pref: First, groups: [], symbol_table } + #|} + #|fn translate( + #| tc : TranslateContext, + #| ast : Pattern, + #|) -> (@automata.Expr, Preference) { + #| let { ctx, pref, groups, symbol_table } = tc + #| match ast.desc { + #| Char(c) => (@automata.e_cset(ctx~, symbol_table.map_set(c)), pref) + #| Sequence(exprs) => (transl_seq(tc, exprs), pref) + #| Alternation(exprs) => { + #| let alts = [] + #| for expr in exprs { + #| let (cr, pref2) = translate(tc, expr) + #| alts.push(enforce_pref(ctx, pref, pref2, cr)) + #| } + #| (@automata.e_alt(ctx~, alts), pref) + #| } + #| Quantifier(q, expr) => { + #| let (cr, pref2) = translate(tc, expr) + #| let rem = match q.max { + #| None => @automata.e_rep(ctx~, q.mode, pref2, cr) + #| Some(max) => { + #| let repeater = match q.mode { + #| Greedy => + #| rem => { + #| @automata.e_alt(ctx~, [ + #| @automata.e_seq(ctx~, pref2, @automata.e_copy(ctx~, cr), rem), + #| @automata.e_eps, + #| ]) + #| } + #| NonGreedy => + #| rem => { + #| @automata.e_alt(ctx~, [ + #| @automata.e_eps, + #| @automata.e_seq(ctx~, pref2, @automata.e_copy(ctx~, cr), rem), + #| ]) + #| } + #| } + #| iter(max - q.min, repeater, @automata.e_eps) + #| } + #| } + #| let result = iter( + #| q.min, + #| rem => @automata.e_seq(ctx~, pref2, @automata.e_copy(ctx~, cr), rem), + #| rem, + #| ) + #| (result, pref) + #| } + #| Preference(pref2, expr) => { + #| let (cr, pref3) = translate({ ..tc, pref: pref2 }, expr) + #| (enforce_pref(ctx, pref2, pref3, cr), pref2) + #| } + #| Capture(name~, expr) => { + #| let group_index = groups.length() + #| groups.push(name) + #| let (cr, pref2) = translate(tc, expr) + #| ( + #| @automata.e_seq( + #| ctx~, + #| First, + #| @automata.e_mark(ctx~, @automata.Mark(group_index * 2)), + #| @automata.e_seq( + #| ctx~, + #| First, + #| cr, + #| @automata.e_mark(ctx~, @automata.Mark(group_index * 2 + 1)), + #| ), + #| ), + #| pref2, + #| ) + #| } + #| Assertion(asrt) => (transl_asrt(ctx, asrt), pref) + #| } + #|} + #|fn transl_asrt(ctx : @automata.Context, asrt : Assertion) -> @automata.Expr { + #| match asrt { + #| StartOfLine => @automata.e_after(ctx~, Category::inexistant_or_newline()) + #| EndOfLine => @automata.e_before(ctx~, Category::inexistant_or_newline()) + #| StartOfWord => + #| @automata.e_seq( + #| ctx~, + #| First, + #| @automata.e_after(ctx~, Category::inexistant_or_non_word_end()), + #| @automata.e_before(ctx~, Category::word()), + #| ) + #| EndOfWord => + #| @automata.e_seq( + #| ctx~, + #| First, + #| @automata.e_after(ctx~, Category::word()), + #| @automata.e_before(ctx~, Category::inexistant_or_non_word_start()), + #| ) + #| NotWordBoundary => + #| @automata.e_alt(ctx~, [ + #| @automata.e_seq( + #| ctx~, + #| First, + #| @automata.e_after(ctx~, Category::word()), + #| @automata.e_before(ctx~, Category::word()), + #| ), + #| @automata.e_seq( + #| ctx~, + #| First, + #| @automata.e_after(ctx~, Category::inexistant_or_non_word_end()), + #| @automata.e_before(ctx~, Category::inexistant_or_non_word_start()), + #| ), + #| ]) + #| StartOfInput => @automata.e_after(ctx~, Category::inexistant()) + #| EndOfInput => @automata.e_before(ctx~, Category::inexistant()) + #| } + #|} + #|fn transl_seq( + #| tc : TranslateContext, + #| exprs : ReadOnlyArray[Pattern], + #|) -> @automata.Expr { + #| fn compose( + #| pref2 : Preference, + #| cr : @automata.Expr, + #| cr2 : @automata.Expr, + #| ) -> @automata.Expr { + #| if @automata.is_eps(cr2) { + #| enforce_pref(tc.ctx, tc.pref, pref2, cr) + #| } else if @automata.is_eps(cr) { + #| cr2 + #| } else { + #| @automata.e_seq(ctx=tc.ctx, pref2, cr, cr2) + #| } + #| } + #| fn go(i : Int) -> @automata.Expr { + #| if i >= exprs.length() { + #| @automata.e_eps + #| } else { + #| let (cr, pref2) = translate(tc, exprs[i]) + #| let cr2 = go(i + 1) + #| compose(pref2, cr, cr2) + #| } + #| } + #| go(0) + #|} + #|fn enforce_pref( + #| ctx : @automata.Context, + #| pref : Preference, + #| pref2 : Preference, + #| cr : @automata.Expr, + #|) -> @automata.Expr { + #| match (pref, pref2) { + #| (First, First) => cr + #| (First, k) => @automata.e_seq(ctx~, k, cr, @automata.e_eps) + #| _ => cr + #| } + #|} + #|fn[T] iter(n : Int, f : (T) -> T, init : T) -> T { + #| if n == 0 { + #| init + #| } else { + #| iter(n - 1, f, f(init)) + #| } + #|} + ), + "using.mbt": ( + #|pub using @shared_types { + #| type Profile, + #| type Rechar, + #| type RecharSet, + #| type Preference, + #| type Category, + #| type QuantifierMode, + #|} + #|pub using @ast { + #| type Pattern, + #| type Assertion, + #| type Quantifier, + #| char, + #| epsilon, + #| seq, + #| empty, + #| alt, + #| quantifier, + #| preference, + #| shortest, + #| longest, + #| first, + #| capture, + #| assertion, + #| start_of_input, + #| end_of_input, + #| start_of_line, + #| end_of_line, + #| start_of_word, + #| end_of_word, + #| not_word_boundary, + #|} + ) + } +) + +///| +let moonbitlang_core_bytes_internal_regex_engine_ast_module : RuntimePackage = RuntimePackage::new( + "moonbitlang/core/bytes/internal/regex_engine/ast", + deps={ }, + files={ + "pattern.mbt": ( + #|pub(all) struct Quantifier { + #| min : Int + #| max : Int? + #| mode : @shared_types.QuantifierMode + #|} derive(Debug) + #|pub enum Assertion { + #| StartOfInput + #| EndOfInput + #| StartOfLine + #| EndOfLine + #| StartOfWord + #| EndOfWord + #| NotWordBoundary + #|} derive(Debug) + #|pub struct Pattern { + #| desc : PatternDesc + #| nullable : Bool + #|} + #|pub impl Debug for Pattern with to_repr(self) { + #| self.desc.to_repr() + #|} + #|pub enum PatternDesc { + #| Char(@shared_types.RecharSet) + #| Sequence(ReadOnlyArray[Pattern]) + #| Alternation(ReadOnlyArray[Pattern]) + #| Quantifier(Quantifier, Pattern) + #| Preference(@shared_types.Preference, Pattern) + #| Capture(name~ : String?, Pattern) + #| Assertion(Assertion) + #|} derive(Debug) + #|pub fn Pattern::is_anchored(self : Pattern) -> Bool { + #| match self.desc { + #| Char(_) => false + #| Sequence(exprs) => exprs.any(e => e.is_anchored()) + #| Alternation(exprs) => exprs.all(e => e.is_anchored()) + #| Quantifier(q, expr) => q.min > 0 && expr.is_anchored() + #| Preference(_, expr) => expr.is_anchored() + #| Capture(expr, ..) => expr.is_anchored() + #| Assertion(StartOfInput) => true + #| Assertion(_) => false + #| } + #|} + #|pub fn char(cs : @shared_types.RecharSet) -> Pattern { + #| if cs.is_empty() { + #| empty + #| } else { + #| Pattern::{ desc: Char(cs), nullable: false } + #| } + #|} + #|pub let epsilon : Pattern = Pattern::{ desc: Sequence([]), nullable: true } + #|pub fn seq(exprs : ReadOnlyArray[Pattern]) -> Pattern { + #| let flatten = [] + #| for expr in exprs { + #| if expr.desc is Sequence(nested) { + #| for e in nested { + #| flatten.push(e) + #| } + #| } else { + #| flatten.push(expr) + #| } + #| } + #| match flatten { + #| [] => epsilon + #| [expr] => expr + #| exprs => + #| Pattern::{ + #| desc: Sequence(ReadOnlyArray::from_array(exprs)), + #| nullable: exprs.all(e => e.nullable), + #| } + #| } + #|} + #|pub let empty : Pattern = Pattern::{ desc: Alternation([]), nullable: false } + #|pub fn alt(exprs : ReadOnlyArray[Pattern]) -> Pattern { + #| match exprs { + #| [] => empty + #| [expr] => expr + #| exprs => + #| Pattern::{ + #| desc: Alternation(exprs), + #| nullable: exprs.any(e => e.nullable), + #| } + #| } + #|} + #|pub fn quantifier(expr : Pattern, q : Quantifier) -> Pattern { + #| guard q.min >= 0 else { panic() } + #| guard q.max is None || (q.max is Some(max) && max >= q.min) else { panic() } + #| Pattern::{ desc: Quantifier(q, expr), nullable: expr.nullable || q.min == 0 } + #|} + #|pub fn preference(pref : @shared_types.Preference, expr : Pattern) -> Pattern { + #| if expr.desc is Char(_) { + #| expr + #| } else { + #| Pattern::{ desc: Preference(pref, expr), nullable: expr.nullable } + #| } + #|} + #|pub fn longest(expr : Pattern) -> Pattern { + #| preference(Longest, expr) + #|} + #|pub fn shortest(expr : Pattern) -> Pattern { + #| preference(Shortest, expr) + #|} + #|pub fn first(expr : Pattern) -> Pattern { + #| preference(First, expr) + #|} + #|pub fn capture(name? : String, expr : Pattern) -> Pattern { + #| Pattern::{ desc: Capture(name~, expr), nullable: expr.nullable } + #|} + #|pub fn assertion(a : Assertion) -> Pattern { + #| Pattern::{ desc: Assertion(a), nullable: true } + #|} + #|pub let start_of_input : Pattern = assertion(StartOfInput) + #|pub let end_of_input : Pattern = assertion(EndOfInput) + #|pub let start_of_line : Pattern = assertion(StartOfLine) + #|pub let end_of_line : Pattern = assertion(EndOfLine) + #|pub let start_of_word : Pattern = assertion(StartOfWord) + #|pub let end_of_word : Pattern = assertion(EndOfWord) + #|pub let not_word_boundary : Pattern = assertion(NotWordBoundary) + ), + "using.mbt": ( + #|using @debug {trait Debug, type Repr} + #|fn[T : Debug] _suppress_unused_warning_of_debug_trait(x : T) -> Unit { + #| ignore(x.to_repr()) + #|} + ) + } +) + +///| +let moonbitlang_core_bytes_internal_regex_engine_symbol_map_module : RuntimePackage = RuntimePackage::new( + "moonbitlang/core/bytes/internal/regex_engine/symbol_map", + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| "moonbitlang/core/builtin" - #| ], - #| "test-import": [ - #| "moonbitlang/core/array", - #| "moonbitlang/core/double", - #| "moonbitlang/core/uint", - #| "moonbitlang/core/uint64", - #| "moonbitlang/core/test", - #| "moonbitlang/core/quickcheck", - #| "moonbitlang/core/error", - #| "moonbitlang/core/json", - #| "moonbitlang/core/float" - #| ] - #|} - ), - "alias.mbt": ( - #|#builtin.valtype - #|#deprecated("Use `BytesView` instead") - #|pub type View = BytesView - #|pub fn default() -> Bytes { - #| b"" - #|} - #|#deprecated("Use `Bytes::from_array` instead") - #|pub fn from_fixedarray(arr : FixedArray[Byte], len? : Int) -> Bytes { - #| Bytes::from_array(arr[:len.unwrap_or(arr.length())]) - #|} - #|#deprecated("Use `Bytes::from_iter` instead") - #|pub fn from_iter(iter : Iter[Byte]) -> Bytes { - #| Bytes::from_iter(iter) - #|} - #|#deprecated("Use `Bytes::from_iterator` instead") - #|pub fn from_iterator(iter : Iterator[Byte]) -> Bytes { - #| Bytes::from_array(iter.collect()) - #|} - #|#deprecated("Use `Bytes::from_array` instead") - #|pub fn of(arr : ArrayView[Byte]) -> Bytes { - #| Bytes::from_array(arr) - #|} - #|#deprecated("Use `Bytes::from_array` instead") - #|pub fn from_array(arr : ArrayView[Byte]) -> Bytes { - #| Bytes::from_array(arr) - #|} - ), - }, + "dense_table.mbt": ( + #|priv struct DenseTable(FixedArray[@shared_types.Rechar]) + #|impl Table for DenseTable with map(self, c) { + #| self.0.unsafe_get(c) + #|} + ), + "sparse_table.mbt": ( + #|#valtype + #|priv struct SparseTableEntry { + #| lo : @shared_types.Rechar + #| hi : @shared_types.Rechar + #| symbol : @shared_types.Rechar + #|} + #|priv struct SparseTable(ReadOnlyArray[SparseTableEntry]) + #|impl Table for SparseTable with map(self, c) { + #| let arr = self.0 + #| for left = 0, right = arr.length() - 1; left <= right; { + #| let mid = left + (right - left) / 2 + #| let entry = arr[mid] + #| if c < entry.lo { + #| continue left, mid - 1 + #| } else if c > entry.hi { + #| continue mid + 1, right + #| } else { + #| break entry.symbol + #| } + #| } nobreak { + #| panic() + #| } + #|} + ), + "symbol_map.mbt": ( + #|struct SymbolMap(@sorted_set.SortedSet[@shared_types.Rechar]) + #|pub fn new() -> SymbolMap { + #| SymbolMap(@sorted_set.new()) + #|} + #|pub fn SymbolMap::split( + #| self : SymbolMap, + #| set : @shared_types.RecharSet, + #|) -> Unit { + #| for interval in set.intervals() { + #| let (start, stop) = interval + #| self.0.add(start) + #| if stop + 1 > stop { + #| self.0.add(stop + 1) + #| } + #| } + #|} + #|pub fn SymbolMap::finalize( + #| self : SymbolMap, + #| lb : @shared_types.Rechar, + #| ub : @shared_types.Rechar, + #|) -> (&Table, ReadOnlyArray[@shared_types.Rechar]) { + #| if ub - lb < 1024 { + #| let (table, repr) = self.finalize_dense(lb, ub) + #| (table as &Table, repr) + #| } else { + #| let (table, repr) = self.finalize_sparse(lb, ub) + #| (table as &Table, repr) + #| } + #|} + #|fn SymbolMap::finalize_dense( + #| self : SymbolMap, + #| lb : @shared_types.Rechar, + #| ub : @shared_types.Rechar, + #|) -> (DenseTable, ReadOnlyArray[@shared_types.Rechar]) { + #| let repr = [] + #| let table = FixedArray::make(ub - lb + 1, 0) + #| self.each_intervals(lb, ub, (lo, hi) => { + #| let symbol = repr.length() + #| repr.push(lo) + #| for c in lo..<=hi { + #| table[c] = symbol + #| } + #| }) + #| (DenseTable(table), ReadOnlyArray::from_array(repr)) + #|} + #|fn SymbolMap::finalize_sparse( + #| self : SymbolMap, + #| lb : @shared_types.Rechar, + #| ub : @shared_types.Rechar, + #|) -> (SparseTable, ReadOnlyArray[@shared_types.Rechar]) { + #| let repr = [] + #| let entries = [] + #| self.each_intervals(lb, ub, (lo, hi) => { + #| let symbol = repr.length() + #| repr.push(lo) + #| entries.push({ lo, hi, symbol }) + #| }) + #| ( + #| SparseTable(ReadOnlyArray::from_array(entries)), + #| ReadOnlyArray::from_array(repr), + #| ) + #|} + #|#locals(f) + #|fn SymbolMap::each_intervals( + #| self : SymbolMap, + #| lb : @shared_types.Rechar, + #| ub : @shared_types.Rechar, + #| f : (@shared_types.Rechar, @shared_types.Rechar) -> Unit, + #|) -> Unit { + #| if self.0.is_empty() { + #| f(lb, ub) + #| } else { + #| let last_stop = for stop in self.0; last_stop = lb { + #| if stop - 1 >= last_stop { + #| f(last_stop, stop - 1) + #| continue stop + #| } else { + #| continue last_stop + #| } + #| } nobreak { + #| last_stop + #| } + #| if ub >= last_stop { + #| f(last_stop, ub) + #| } + #| } + #|} + ), + "table.mbt": ( + #|pub trait Table { + #| map(self : Self, c : @shared_types.Rechar) -> @shared_types.Rechar + #| map_set(self : Self, set : @shared_types.RecharSet) -> @shared_types.RecharSet = _ + #|} + #|impl Table with map_set(self, set) { + #| set.offset_by(c => self.map(c)) + #|} + ), + "using.mbt": "" + } ) ///| let moonbitlang_core_char_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/char", - deps={ "moonbitlang/core/builtin": moonbitlang_core_builtin_module }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": ["moonbitlang/core/builtin"] - #|} - ), - "char_util.mbt": "", - }, + "char_util.mbt": "" + } ) ///| let moonbitlang_core_cmp_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/cmp", - deps={ "moonbitlang/core/builtin": moonbitlang_core_builtin_module }, + deps={ }, + files={ + "cmp.mbt": ( + #|pub(all) struct Reverse[T](T) derive(Eq, Show, Hash) + #|pub impl[T : Compare] Compare for Reverse[T] with compare(a, b) { + #| -a.0.compare(b.0) + #|} + #|pub fn[T, K : Compare] maximum_by_key(x : T, y : T, f : (T) -> K) -> T { + #| if f(x) > f(y) { + #| x + #| } else { + #| y + #| } + #|} + #|pub fn[T, K : Compare] minimum_by_key(x : T, y : T, f : (T) -> K) -> T { + #| if f(x) > f(y) { + #| y + #| } else { + #| x + #| } + #|} + #|pub fn[T : Compare] maximum(x : T, y : T) -> T { + #| if x > y { + #| x + #| } else { + #| y + #| } + #|} + #|pub fn[T : Compare] minimum(x : T, y : T) -> T { + #| if x > y { + #| y + #| } else { + #| x + #| } + #|} + #|pub fn[T : Compare] minmax(x : T, y : T) -> (T, T) { + #| if x > y { + #| (y, x) + #| } else { + #| (x, y) + #| } + #|} + #|pub fn[T, K : Compare] minmax_by_key(x : T, y : T, f : (T) -> K) -> (T, T) { + #| if f(x) > f(y) { + #| (y, x) + #| } else { + #| (x, y) + #| } + #|} + ) + } +) + +///| +let moonbitlang_core_debug_module : RuntimePackage = RuntimePackage::new( + "moonbitlang/core/debug", + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| "moonbitlang/core/builtin" - #| ], - #| "test-import": [ - #| "moonbitlang/core/int" - #| ] - #|} - ), - "cmp.mbt": ( - #|pub(all) struct Reverse[T](T) derive(Eq, Show, Hash) - #|pub impl[T : Compare] Compare for Reverse[T] with compare(a, b) { - #| -a.0.compare(b.0) - #|} - #|pub fn[T, K : Compare] maximum_by_key(x : T, y : T, f : (T) -> K) -> T { - #| if f(x) > f(y) { - #| x - #| } else { - #| y - #| } - #|} - #|pub fn[T, K : Compare] minimum_by_key(x : T, y : T, f : (T) -> K) -> T { - #| if f(x) > f(y) { - #| y - #| } else { - #| x - #| } - #|} - #|pub fn[T : Compare] maximum(x : T, y : T) -> T { - #| if x > y { - #| x - #| } else { - #| y - #| } - #|} - #|pub fn[T : Compare] minimum(x : T, y : T) -> T { - #| if x > y { - #| y - #| } else { - #| x - #| } - #|} - #|pub fn[T : Compare] minmax(x : T, y : T) -> (T, T) { - #| if x > y { - #| (y, x) - #| } else { - #| (x, y) - #| } - #|} - #|pub fn[T, K : Compare] minmax_by_key(x : T, y : T, f : (T) -> K) -> (T, T) { - #| if f(x) > f(y) { - #| (y, x) - #| } else { - #| (x, y) - #| } - #|} - ), - }, + "debug.mbt": ( + #|pub(open) trait Debug { + #| #as_free_fn + #| to_repr(Self) -> Repr + #|} + #|pub impl Debug for Int with to_repr(self) { + #| Repr::integer(self.to_string()) + #|} + #|pub impl Debug for Int16 with to_repr(self) { + #| Repr::integer(self.to_string()) + #|} + #|pub impl Debug for Int64 with to_repr(self) { + #| Repr::integer(self.to_string()) + #|} + #|pub impl Debug for UInt16 with to_repr(self) { + #| Repr::integer(self.to_string()) + #|} + #|pub impl Debug for UInt with to_repr(self) { + #| Repr::integer(self.to_string()) + #|} + #|pub impl Debug for UInt64 with to_repr(self) { + #| Repr::integer(self.to_string()) + #|} + #|pub impl Debug for Double with to_repr(self) { + #| Repr::double(self) + #|} + #|pub impl Debug for Float with to_repr(self) { + #| Repr::float(self) + #|} + #|pub impl Debug for Bool with to_repr(self) { + #| Repr::bool(self) + #|} + #|pub impl Debug for Byte with to_repr(self) { + #| Repr::literal("0x" + self.to_hex()) + #|} + #|pub impl Debug for Char with to_repr(self) { + #| Repr::char(self) + #|} + #|pub impl Debug for String with to_repr(self) { + #| Repr::string(self) + #|} + #|pub impl Debug for StringView with to_repr(self) { + #| Repr::opaque_("StringView", Repr::string(self.to_string())) + #|} + #|pub impl Debug for Bytes with to_repr(self) { + #| Repr::opaque_( + #| "Bytes", + #| Repr::array(self.to_array().map(x => Debug::to_repr(x))), + #| ) + #|} + #|pub impl Debug for BytesView with to_repr(self) { + #| Repr::opaque_( + #| "BytesView", + #| Repr::array(self.to_array().map(x => Debug::to_repr(x))), + #| ) + #|} + #|pub impl Debug for Unit with to_repr(_) { + #| Repr::unit() + #|} + #|pub impl[T : Debug] Debug for Array[T] with to_repr(self) { + #| Repr::array(self.map(x => x.to_repr())) + #|} + #|pub impl[T : Debug] Debug for ArrayView[T] with to_repr(self) { + #| Repr::opaque_("ArrayView", Repr::array(self.map(x => x.to_repr()))) + #|} + #|pub impl[T : Debug] Debug for FixedArray[T] with to_repr(self) { + #| let view : ArrayView[T] = self[:] + #| Repr::opaque_("FixedArray", Repr::array(view.map(x => x.to_repr()))) + #|} + #|pub impl[T : Debug] Debug for ReadOnlyArray[T] with to_repr(self) { + #| let view : ArrayView[T] = self[:] + #| Repr::opaque_("ReadOnlyArray", Repr::array(view.map(x => x.to_repr()))) + #|} + #|pub impl[T : Debug] Debug for T? with to_repr(self) { + #| match self { + #| None => Repr::ctor("None", []) + #| Some(x) => Repr::ctor("Some", [(None, x.to_repr())]) + #| } + #|} + #|pub impl[T : Debug, E : Debug] Debug for Result[T, E] with to_repr(self) { + #| match self { + #| Ok(x) => Repr::ctor("Ok", [(None, x.to_repr())]) + #| Err(e) => Repr::ctor("Err", [(None, e.to_repr())]) + #| } + #|} + #|pub impl[A : Debug] Debug for @list.List[A] with to_repr(self) { + #| Repr::opaque_("List", Repr::array(self.to_array().map(x => x.to_repr()))) + #|} + #|pub impl[K : Debug, V : Debug] Debug for @hashmap.HashMap[K, V] with to_repr( + #| self, + #|) { + #| let entries : Array[(Repr, Repr)] = self + #| .to_array() + #| .map(kv => (kv.0.to_repr(), kv.1.to_repr())) + #| Repr::opaque_("HashMap", Repr::map(entries)) + #|} + #|pub impl[K : Debug] Debug for @hashset.HashSet[K] with to_repr(self) { + #| let xs : Array[Repr] = self.to_array().map(x => x.to_repr()) + #| Repr::opaque_("HashSet", Repr::array(xs)) + #|} + #|pub impl[A : Debug] Debug for @deque.Deque[A] with to_repr(self) { + #| Repr::opaque_("Deque", Repr::array(self.to_array().map(x => x.to_repr()))) + #|} + #|pub impl[A : Debug] Debug for @queue.Queue[A] with to_repr(self) { + #| Repr::opaque_( + #| "Queue", + #| Repr::array(self.iter().to_array().map(x => x.to_repr())), + #| ) + #|} + #|pub impl[A] Debug for Iter[A] with to_repr(_) { + #| Repr::opaque_("Iter", Omitted) + #|} + #|pub impl[A, B] Debug for Iter2[A, B] with to_repr(_) { + #| Repr::opaque_("Iter2", Omitted) + #|} + #|pub impl[T : Debug] Debug for MutArrayView[T] with to_repr(self) { + #| Repr::opaque_("MutArrayView", Repr::array(self[:].map(x => x.to_repr()))) + #|} + #|pub impl[T : Debug] Debug for @ref.Ref[T] with to_repr(self) { + #| Repr::opaque_("Ref", self.val.to_repr()) + #|} + #|pub impl[A : Debug + Compare] Debug for @priority_queue.PriorityQueue[A] with to_repr( + #| self, + #|) { + #| let xs : Array[Repr] = self.to_array().map(x => x.to_repr()) + #| Repr::opaque_("PriorityQueue", Repr::array(xs)) + #|} + #|pub impl Debug for @buffer.Buffer with to_repr(self) { + #| Repr::opaque_("Buffer", Debug::to_repr(self.to_bytes().to_array())) + #|} + #|pub impl Debug for StringBuilder with to_repr(self) { + #| Repr::string(self.to_string()) + #|} + #|pub impl[K : Debug, V : Debug] Debug for @immut_sorted_map.SortedMap[K, V] with to_repr( + #| self, + #|) { + #| Repr::opaque_( + #| "SortedMap", + #| Repr::map(self.to_array().map(kv => (kv.0.to_repr(), kv.1.to_repr()))), + #| ) + #|} + #|pub impl[K : Debug] Debug for @immut_sorted_set.SortedSet[K] with to_repr(self) { + #| Repr::opaque_("SortedSet", Repr::array(self.to_array().map(x => x.to_repr()))) + #|} + #|pub impl[K : Debug, V : Debug] Debug for @immut_hashmap.HashMap[K, V] with to_repr( + #| self, + #|) { + #| let entries : Array[(Repr, Repr)] = self + #| .to_array() + #| .map(kv => (kv.0.to_repr(), kv.1.to_repr())) + #| Repr::opaque_("HashMap", Repr::map(entries)) + #|} + #|pub impl[K : Debug] Debug for @immut_hashset.HashSet[K] with to_repr(self) { + #| let xs : Array[Repr] = self.iter().to_array().map(x => x.to_repr()) + #| Repr::opaque_("HashSet", Repr::array(xs)) + #|} + #|pub impl[A : Debug] Debug for @immut_array.T[A] with to_repr(self) { + #| Repr::opaque_("Array", Repr::array(self.to_array().map(x => x.to_repr()))) + #|} + #|pub impl[A : Debug + Compare] Debug for @immut_priority_queue.PriorityQueue[A] with to_repr( + #| self, + #|) { + #| let xs : Array[Repr] = self.to_array().map(x => x.to_repr()) + #| Repr::opaque_("PriorityQueue", Repr::array(xs)) + #|} + #|pub impl[K : Debug, V : Debug] Debug for Map[K, V] with to_repr(self) { + #| Repr::map( + #| self + #| .to_array() + #| .map(kv => { + #| let (k, v) = kv + #| (k.to_repr(), v.to_repr()) + #| }), + #| ) + #|} + #|pub impl Debug for SourceLoc with to_repr(self) { + #| Repr::opaque_("SourceLoc", Repr::string(self.to_string())) + #|} + #|pub impl[A : Debug, B : Debug] Debug for (A, B) with to_repr(self) { + #| let (a, b) = self + #| Repr::tuple([a.to_repr(), b.to_repr()]) + #|} + #|pub impl[A : Debug, B : Debug, C : Debug] Debug for (A, B, C) with to_repr(self) { + #| let (a, b, c) = self + #| Repr::tuple([a.to_repr(), b.to_repr(), c.to_repr()]) + #|} + #|pub impl[A : Debug, B : Debug, C : Debug, D : Debug] Debug for (A, B, C, D) with to_repr( + #| self, + #|) { + #| let (a, b, c, d) = self + #| Repr::tuple([a.to_repr(), b.to_repr(), c.to_repr(), d.to_repr()]) + #|} + #|pub impl[A : Debug, B : Debug, C : Debug, D : Debug, E : Debug] Debug for ( + #| A, + #| B, + #| C, + #| D, + #| E, + #|) with to_repr(self) { + #| let (a, b, c, d, e) = self + #| Repr::tuple([a.to_repr(), b.to_repr(), c.to_repr(), d.to_repr(), e.to_repr()]) + #|} + #|pub impl[A : Debug, B : Debug, C : Debug, D : Debug, E : Debug, F : Debug] Debug for ( + #| A, + #| B, + #| C, + #| D, + #| E, + #| F, + #|) with to_repr(self) { + #| let (a, b, c, d, e, f) = self + #| Repr::tuple([ + #| a.to_repr(), + #| b.to_repr(), + #| c.to_repr(), + #| d.to_repr(), + #| e.to_repr(), + #| f.to_repr(), + #| ]) + #|} + #|pub impl[ + #| A : Debug, + #| B : Debug, + #| C : Debug, + #| D : Debug, + #| E : Debug, + #| F : Debug, + #| G : Debug, + #|] Debug for (A, B, C, D, E, F, G) with to_repr(self) { + #| let (a, b, c, d, e, f, g) = self + #| Repr::tuple([ + #| a.to_repr(), + #| b.to_repr(), + #| c.to_repr(), + #| d.to_repr(), + #| e.to_repr(), + #| f.to_repr(), + #| g.to_repr(), + #| ]) + #|} + #|pub impl[ + #| A : Debug, + #| B : Debug, + #| C : Debug, + #| D : Debug, + #| E : Debug, + #| F : Debug, + #| G : Debug, + #| H : Debug, + #|] Debug for (A, B, C, D, E, F, G, H) with to_repr(self) { + #| let (a, b, c, d, e, f, g, h) = self + #| Repr::tuple([ + #| a.to_repr(), + #| b.to_repr(), + #| c.to_repr(), + #| d.to_repr(), + #| e.to_repr(), + #| f.to_repr(), + #| g.to_repr(), + #| h.to_repr(), + #| ]) + #|} + #|pub impl[ + #| A : Debug, + #| B : Debug, + #| C : Debug, + #| D : Debug, + #| E : Debug, + #| F : Debug, + #| G : Debug, + #| H : Debug, + #| I : Debug, + #|] Debug for (A, B, C, D, E, F, G, H, I) with to_repr(self) { + #| let (a, b, c, d, e, f, g, h, i) = self + #| Repr::tuple([ + #| a.to_repr(), + #| b.to_repr(), + #| c.to_repr(), + #| d.to_repr(), + #| e.to_repr(), + #| f.to_repr(), + #| g.to_repr(), + #| h.to_repr(), + #| i.to_repr(), + #| ]) + #|} + #|pub impl[ + #| A : Debug, + #| B : Debug, + #| C : Debug, + #| D : Debug, + #| E : Debug, + #| F : Debug, + #| G : Debug, + #| H : Debug, + #| I : Debug, + #| J : Debug, + #|] Debug for (A, B, C, D, E, F, G, H, I, J) with to_repr(self) { + #| let (a, b, c, d, e, f, g, h, i, j) = self + #| Repr::tuple([ + #| a.to_repr(), + #| b.to_repr(), + #| c.to_repr(), + #| d.to_repr(), + #| e.to_repr(), + #| f.to_repr(), + #| g.to_repr(), + #| h.to_repr(), + #| i.to_repr(), + #| j.to_repr(), + #| ]) + #|} + #|pub impl[ + #| A : Debug, + #| B : Debug, + #| C : Debug, + #| D : Debug, + #| E : Debug, + #| F : Debug, + #| G : Debug, + #| H : Debug, + #| I : Debug, + #| J : Debug, + #| K : Debug, + #|] Debug for (A, B, C, D, E, F, G, H, I, J, K) with to_repr(self) { + #| let (a, b, c, d, e, f, g, h, i, j, k) = self + #| Repr::tuple([ + #| a.to_repr(), + #| b.to_repr(), + #| c.to_repr(), + #| d.to_repr(), + #| e.to_repr(), + #| f.to_repr(), + #| g.to_repr(), + #| h.to_repr(), + #| i.to_repr(), + #| j.to_repr(), + #| k.to_repr(), + #| ]) + #|} + #|pub impl[ + #| A : Debug, + #| B : Debug, + #| C : Debug, + #| D : Debug, + #| E : Debug, + #| F : Debug, + #| G : Debug, + #| H : Debug, + #| I : Debug, + #| J : Debug, + #| K : Debug, + #| L : Debug, + #|] Debug for (A, B, C, D, E, F, G, H, I, J, K, L) with to_repr(self) { + #| let (a, b, c, d, e, f, g, h, i, j, k, l) = self + #| Repr::tuple([ + #| a.to_repr(), + #| b.to_repr(), + #| c.to_repr(), + #| d.to_repr(), + #| e.to_repr(), + #| f.to_repr(), + #| g.to_repr(), + #| h.to_repr(), + #| i.to_repr(), + #| j.to_repr(), + #| k.to_repr(), + #| l.to_repr(), + #| ]) + #|} + #|pub impl[ + #| A : Debug, + #| B : Debug, + #| C : Debug, + #| D : Debug, + #| E : Debug, + #| F : Debug, + #| G : Debug, + #| H : Debug, + #| I : Debug, + #| J : Debug, + #| K : Debug, + #| L : Debug, + #| M : Debug, + #|] Debug for (A, B, C, D, E, F, G, H, I, J, K, L, M) with to_repr(self) { + #| let (a, b, c, d, e, f, g, h, i, j, k, l, m) = self + #| Repr::tuple([ + #| a.to_repr(), + #| b.to_repr(), + #| c.to_repr(), + #| d.to_repr(), + #| e.to_repr(), + #| f.to_repr(), + #| g.to_repr(), + #| h.to_repr(), + #| i.to_repr(), + #| j.to_repr(), + #| k.to_repr(), + #| l.to_repr(), + #| m.to_repr(), + #| ]) + #|} + #|pub impl[ + #| A : Debug, + #| B : Debug, + #| C : Debug, + #| D : Debug, + #| E : Debug, + #| F : Debug, + #| G : Debug, + #| H : Debug, + #| I : Debug, + #| J : Debug, + #| K : Debug, + #| L : Debug, + #| M : Debug, + #| N : Debug, + #|] Debug for (A, B, C, D, E, F, G, H, I, J, K, L, M, N) with to_repr(self) { + #| let (a, b, c, d, e, f, g, h, i, j, k, l, m, n) = self + #| Repr::tuple([ + #| a.to_repr(), + #| b.to_repr(), + #| c.to_repr(), + #| d.to_repr(), + #| e.to_repr(), + #| f.to_repr(), + #| g.to_repr(), + #| h.to_repr(), + #| i.to_repr(), + #| j.to_repr(), + #| k.to_repr(), + #| l.to_repr(), + #| m.to_repr(), + #| n.to_repr(), + #| ]) + #|} + #|pub impl[ + #| A : Debug, + #| B : Debug, + #| C : Debug, + #| D : Debug, + #| E : Debug, + #| F : Debug, + #| G : Debug, + #| H : Debug, + #| I : Debug, + #| J : Debug, + #| K : Debug, + #| L : Debug, + #| M : Debug, + #| N : Debug, + #| O : Debug, + #|] Debug for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O) with to_repr(self) { + #| let (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) = self + #| Repr::tuple([ + #| a.to_repr(), + #| b.to_repr(), + #| c.to_repr(), + #| d.to_repr(), + #| e.to_repr(), + #| f.to_repr(), + #| g.to_repr(), + #| h.to_repr(), + #| i.to_repr(), + #| j.to_repr(), + #| k.to_repr(), + #| l.to_repr(), + #| m.to_repr(), + #| n.to_repr(), + #| o.to_repr(), + #| ]) + #|} + #|pub impl[ + #| A : Debug, + #| B : Debug, + #| C : Debug, + #| D : Debug, + #| E : Debug, + #| F : Debug, + #| G : Debug, + #| H : Debug, + #| I : Debug, + #| J : Debug, + #| K : Debug, + #| L : Debug, + #| M : Debug, + #| N : Debug, + #| O : Debug, + #| P : Debug, + #|] Debug for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P) with to_repr(self) { + #| let (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) = self + #| Repr::tuple([ + #| a.to_repr(), + #| b.to_repr(), + #| c.to_repr(), + #| d.to_repr(), + #| e.to_repr(), + #| f.to_repr(), + #| g.to_repr(), + #| h.to_repr(), + #| i.to_repr(), + #| j.to_repr(), + #| k.to_repr(), + #| l.to_repr(), + #| m.to_repr(), + #| n.to_repr(), + #| o.to_repr(), + #| p.to_repr(), + #| ]) + #|} + #|pub impl[ + #| A : Debug, + #| B : Debug, + #| C : Debug, + #| D : Debug, + #| E : Debug, + #| F : Debug, + #| G : Debug, + #| H : Debug, + #| I : Debug, + #| J : Debug, + #| K : Debug, + #| L : Debug, + #| M : Debug, + #| N : Debug, + #| O : Debug, + #| P : Debug, + #| Q : Debug, + #|] Debug for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q) with to_repr( + #| self, + #|) { + #| let (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q) = self + #| Repr::tuple([ + #| a.to_repr(), + #| b.to_repr(), + #| c.to_repr(), + #| d.to_repr(), + #| e.to_repr(), + #| f.to_repr(), + #| g.to_repr(), + #| h.to_repr(), + #| i.to_repr(), + #| j.to_repr(), + #| k.to_repr(), + #| l.to_repr(), + #| m.to_repr(), + #| n.to_repr(), + #| o.to_repr(), + #| p.to_repr(), + #| q.to_repr(), + #| ]) + #|} + #|pub impl[ + #| A : Debug, + #| B : Debug, + #| C : Debug, + #| D : Debug, + #| E : Debug, + #| F : Debug, + #| G : Debug, + #| H : Debug, + #| I : Debug, + #| J : Debug, + #| K : Debug, + #| L : Debug, + #| M : Debug, + #| N : Debug, + #| O : Debug, + #| P : Debug, + #| Q : Debug, + #| R : Debug, + #|] Debug for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R) with to_repr( + #| self, + #|) { + #| let (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r) = self + #| Repr::tuple([ + #| a.to_repr(), + #| b.to_repr(), + #| c.to_repr(), + #| d.to_repr(), + #| e.to_repr(), + #| f.to_repr(), + #| g.to_repr(), + #| h.to_repr(), + #| i.to_repr(), + #| j.to_repr(), + #| k.to_repr(), + #| l.to_repr(), + #| m.to_repr(), + #| n.to_repr(), + #| o.to_repr(), + #| p.to_repr(), + #| q.to_repr(), + #| r.to_repr(), + #| ]) + #|} + #|pub impl[ + #| A : Debug, + #| B : Debug, + #| C : Debug, + #| D : Debug, + #| E : Debug, + #| F : Debug, + #| G : Debug, + #| H : Debug, + #| I : Debug, + #| J : Debug, + #| K : Debug, + #| L : Debug, + #| M : Debug, + #| N : Debug, + #| O : Debug, + #| P : Debug, + #| Q : Debug, + #| R : Debug, + #| S : Debug, + #|] Debug for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S) with to_repr( + #| self, + #|) { + #| let (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s) = self + #| Repr::tuple([ + #| a.to_repr(), + #| b.to_repr(), + #| c.to_repr(), + #| d.to_repr(), + #| e.to_repr(), + #| f.to_repr(), + #| g.to_repr(), + #| h.to_repr(), + #| i.to_repr(), + #| j.to_repr(), + #| k.to_repr(), + #| l.to_repr(), + #| m.to_repr(), + #| n.to_repr(), + #| o.to_repr(), + #| p.to_repr(), + #| q.to_repr(), + #| r.to_repr(), + #| s.to_repr(), + #| ]) + #|} + #|pub impl[ + #| A : Debug, + #| B : Debug, + #| C : Debug, + #| D : Debug, + #| E : Debug, + #| F : Debug, + #| G : Debug, + #| H : Debug, + #| I : Debug, + #| J : Debug, + #| K : Debug, + #| L : Debug, + #| M : Debug, + #| N : Debug, + #| O : Debug, + #| P : Debug, + #| Q : Debug, + #| R : Debug, + #| S : Debug, + #| T : Debug, + #|] Debug for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T) with to_repr( + #| self, + #|) { + #| let (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t) = self + #| Repr::tuple([ + #| a.to_repr(), + #| b.to_repr(), + #| c.to_repr(), + #| d.to_repr(), + #| e.to_repr(), + #| f.to_repr(), + #| g.to_repr(), + #| h.to_repr(), + #| i.to_repr(), + #| j.to_repr(), + #| k.to_repr(), + #| l.to_repr(), + #| m.to_repr(), + #| n.to_repr(), + #| o.to_repr(), + #| p.to_repr(), + #| q.to_repr(), + #| r.to_repr(), + #| s.to_repr(), + #| t.to_repr(), + #| ]) + #|} + #|pub impl[ + #| A : Debug, + #| B : Debug, + #| C : Debug, + #| D : Debug, + #| E : Debug, + #| F : Debug, + #| G : Debug, + #| H : Debug, + #| I : Debug, + #| J : Debug, + #| K : Debug, + #| L : Debug, + #| M : Debug, + #| N : Debug, + #| O : Debug, + #| P : Debug, + #| Q : Debug, + #| R : Debug, + #| S : Debug, + #| T : Debug, + #| U : Debug, + #|] Debug for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U) with to_repr( + #| self, + #|) { + #| let (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u) = self + #| Repr::tuple([ + #| a.to_repr(), + #| b.to_repr(), + #| c.to_repr(), + #| d.to_repr(), + #| e.to_repr(), + #| f.to_repr(), + #| g.to_repr(), + #| h.to_repr(), + #| i.to_repr(), + #| j.to_repr(), + #| k.to_repr(), + #| l.to_repr(), + #| m.to_repr(), + #| n.to_repr(), + #| o.to_repr(), + #| p.to_repr(), + #| q.to_repr(), + #| r.to_repr(), + #| s.to_repr(), + #| t.to_repr(), + #| u.to_repr(), + #| ]) + #|} + #|pub impl[ + #| A : Debug, + #| B : Debug, + #| C : Debug, + #| D : Debug, + #| E : Debug, + #| F : Debug, + #| G : Debug, + #| H : Debug, + #| I : Debug, + #| J : Debug, + #| K : Debug, + #| L : Debug, + #| M : Debug, + #| N : Debug, + #| O : Debug, + #| P : Debug, + #| Q : Debug, + #| R : Debug, + #| S : Debug, + #| T : Debug, + #| U : Debug, + #| V : Debug, + #|] Debug for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V) with to_repr( + #| self, + #|) { + #| let (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v) = self + #| Repr::tuple([ + #| a.to_repr(), + #| b.to_repr(), + #| c.to_repr(), + #| d.to_repr(), + #| e.to_repr(), + #| f.to_repr(), + #| g.to_repr(), + #| h.to_repr(), + #| i.to_repr(), + #| j.to_repr(), + #| k.to_repr(), + #| l.to_repr(), + #| m.to_repr(), + #| n.to_repr(), + #| o.to_repr(), + #| p.to_repr(), + #| q.to_repr(), + #| r.to_repr(), + #| s.to_repr(), + #| t.to_repr(), + #| u.to_repr(), + #| v.to_repr(), + #| ]) + #|} + #|#callsite(autofill(args_loc, loc)) + #|#alias(inspect, deprecated="use `debug_inspect` without package name instead") + #|pub fn debug_inspect( + #| obj : &Debug, + #| content? : String, + #| loc~ : SourceLoc, + #| args_loc~ : ArgsLoc, + #|) -> Unit raise InspectError { + #| let loc = loc.to_json_string() + #| let args_loc = args_loc.to_json() + #| let actual = render(obj.to_repr()) + #| let want = match content { + #| None => "" + #| Some(x) => x + #| } + #| if actual != want { + #| raise InspectError( + #| "@EXPECT_FAILED {\"loc\": \{loc}, \"args_loc\": \{args_loc}, \"expect\": \{want.escape()}, \"actual\": \{actual.escape()} }", + #| ) + #| } + #|} + #|#callsite(autofill(loc)) + #|pub fn[T : Eq + Debug] assert_eq( + #| a : T, + #| b : T, + #| msg? : String, + #| loc~ : SourceLoc, + #|) -> Unit raise { + #| if a != b { + #| let fail_msg = match msg { + #| Some(msg) => msg + #| None => { + #| let repr_a = Debug::to_repr(a) + #| let repr_b = Debug::to_repr(b) + #| let diff = pretty_print_delta(diff_repr(repr_a, repr_b), use_ansi=false) + #| "`\{render(repr_a)} != \{render(repr_b)}`\ndiff:\n\{diff}" + #| } + #| } + #| fail(fail_msg, loc~) + #| } + #|} + #|test "tuple Debug implementations" { + #| debug_inspect((1, "a"), content="(1, \"a\")") + #| debug_inspect((1, "a", true), content="(1, \"a\", true)") + #| debug_inspect( + #| (1, "a", true, 2.0), + #| content=( + #| #|(1, "a", true, 2) + #| ), + #| ) + #| debug_inspect( + #| (1, "a", true, 2.0, 'c'), + #| content=( + #| #|(1, "a", true, 2, 'c') + #| ), + #| ) + #| debug_inspect( + #| (1, "a", true, 2.0, 'c', 6), + #| content=( + #| #|(1, "a", true, 2, 'c', 6) + #| ), + #| ) + #| debug_inspect( + #| (1, "a", true, 2.0, 'c', 6, "g"), + #| content=( + #| #|(1, "a", true, 2, 'c', 6, "g") + #| ), + #| ) + #| debug_inspect( + #| (1, "a", true, 2.0, 'c', 6, "g", false), + #| content=( + #| #|(1, "a", true, 2, 'c', 6, "g", false) + #| ), + #| ) + #| debug_inspect( + #| (1, "a", true, 2.0, 'c', 6, "g", false, 9), + #| content=( + #| #|(1, "a", true, 2, 'c', 6, "g", false, 9) + #| ), + #| ) + #| debug_inspect( + #| (1, "a", true, 2.0, 'c', 6, "g", false, 9, "j"), + #| content=( + #| #|(1, "a", true, 2, 'c', 6, "g", false, 9, "j") + #| ), + #| ) + #| debug_inspect( + #| (1, "a", true, 2.0, 'c', 6, "g", false, 9, "j", 11), + #| content=( + #| #|(1, "a", true, 2, 'c', 6, "g", false, 9, "j", 11) + #| ), + #| ) + #| debug_inspect( + #| (1, "a", true, 2.0, 'c', 6, "g", false, 9, "j", 11, "l"), + #| content=( + #| #|(1, "a", true, 2, 'c', 6, "g", false, 9, "j", 11, "l") + #| ), + #| ) + #| debug_inspect( + #| (1, "a", true, 2.0, 'c', 6, "g", false, 9, "j", 11, "l", 13), + #| content=( + #| #|(1, "a", true, 2, 'c', 6, "g", false, 9, "j", 11, "l", 13) + #| ), + #| ) + #| debug_inspect( + #| (1, "a", true, 2.0, 'c', 6, "g", false, 9, "j", 11, "l", 13, "n"), + #| content=( + #| #|(1, "a", true, 2, 'c', 6, "g", false, 9, "j", 11, "l", 13, "n") + #| ), + #| ) + #| debug_inspect( + #| (1, "a", true, 2.0, 'c', 6, "g", false, 9, "j", 11, "l", 13, "n", 15), + #| content=( + #| #|(1, "a", true, 2, 'c', 6, "g", false, 9, "j", 11, "l", 13, "n", 15) + #| ), + #| ) + #| debug_inspect( + #| (1, "a", true, 2.0, 'c', 6, "g", false, 9, "j", 11, "l", 13, "n", 15, "p"), + #| content=( + #| #|( + #| #| 1, + #| #| "a", + #| #| true, + #| #| 2, + #| #| 'c', + #| #| 6, + #| #| "g", + #| #| false, + #| #| 9, + #| #| "j", + #| #| 11, + #| #| "l", + #| #| 13, + #| #| "n", + #| #| 15, + #| #| "p", + #| #|) + #| ), + #| ) + #| debug_inspect( + #| ( + #| 1, "a", true, 2.0, 'c', 6, "g", false, 9, "j", 11, "l", 13, "n", 15, "p", 17, + #| ), + #| content=( + #| #|( + #| #| 1, + #| #| "a", + #| #| true, + #| #| 2, + #| #| 'c', + #| #| 6, + #| #| "g", + #| #| false, + #| #| 9, + #| #| "j", + #| #| 11, + #| #| "l", + #| #| 13, + #| #| "n", + #| #| 15, + #| #| "p", + #| #| 17, + #| #|) + #| ), + #| ) + #| debug_inspect( + #| ( + #| 1, "a", true, 2.0, 'c', 6, "g", false, 9, "j", 11, "l", 13, "n", 15, "p", 17, + #| "r", + #| ), + #| content=( + #| #|( + #| #| 1, + #| #| "a", + #| #| true, + #| #| 2, + #| #| 'c', + #| #| 6, + #| #| "g", + #| #| false, + #| #| 9, + #| #| "j", + #| #| 11, + #| #| "l", + #| #| 13, + #| #| "n", + #| #| 15, + #| #| "p", + #| #| 17, + #| #| "r", + #| #|) + #| ), + #| ) + #| debug_inspect( + #| ( + #| 1, "a", true, 2.0, 'c', 6, "g", false, 9, "j", 11, "l", 13, "n", 15, "p", 17, + #| "r", 19, + #| ), + #| content=( + #| #|( + #| #| 1, + #| #| "a", + #| #| true, + #| #| 2, + #| #| 'c', + #| #| 6, + #| #| "g", + #| #| false, + #| #| 9, + #| #| "j", + #| #| 11, + #| #| "l", + #| #| 13, + #| #| "n", + #| #| 15, + #| #| "p", + #| #| 17, + #| #| "r", + #| #| 19, + #| #|) + #| ), + #| ) + #| debug_inspect( + #| ( + #| 1, "a", true, 2.0, 'c', 6, "g", false, 9, "j", 11, "l", 13, "n", 15, "p", 17, + #| "r", 19, "t", + #| ), + #| content=( + #| #|( + #| #| 1, + #| #| "a", + #| #| true, + #| #| 2, + #| #| 'c', + #| #| 6, + #| #| "g", + #| #| false, + #| #| 9, + #| #| "j", + #| #| 11, + #| #| "l", + #| #| 13, + #| #| "n", + #| #| 15, + #| #| "p", + #| #| 17, + #| #| "r", + #| #| 19, + #| #| "t", + #| #|) + #| ), + #| ) + #| debug_inspect( + #| ( + #| 1, "a", true, 2.0, 'c', 6, "g", false, 9, "j", 11, "l", 13, "n", 15, "p", 17, + #| "r", 19, "t", 21, + #| ), + #| content=( + #| #|( + #| #| 1, + #| #| "a", + #| #| true, + #| #| 2, + #| #| 'c', + #| #| 6, + #| #| "g", + #| #| false, + #| #| 9, + #| #| "j", + #| #| 11, + #| #| "l", + #| #| 13, + #| #| "n", + #| #| 15, + #| #| "p", + #| #| 17, + #| #| "r", + #| #| 19, + #| #| "t", + #| #| 21, + #| #|) + #| ), + #| ) + #| debug_inspect( + #| ( + #| 1, "a", true, 2.0, 'c', 6, "g", false, 9, "j", 11, "l", 13, "n", 15, "p", 17, + #| "r", 19, "t", 21, "v", + #| ), + #| content=( + #| #|( + #| #| 1, + #| #| "a", + #| #| true, + #| #| 2, + #| #| 'c', + #| #| 6, + #| #| "g", + #| #| false, + #| #| 9, + #| #| "j", + #| #| 11, + #| #| "l", + #| #| 13, + #| #| "n", + #| #| 15, + #| #| "p", + #| #| 17, + #| #| "r", + #| #| 19, + #| #| "t", + #| #| 21, + #| #| "v", + #| #|) + #| ), + #| ) + #|} + #|test "core data structures Debug implementations" { + #| debug_inspect((1 : Int16), content="1") + #| debug_inspect((1 : UInt16), content="1") + #| debug_inspect((1 : UInt64), content="1") + #| debug_inspect((1.0 : Float), content="1") + #| let b : Bytes = b"ab" + #| debug_inspect(b, content="") + #| let bv : BytesView = b[:] + #| debug_inspect(bv, content="") + #| let sv : StringView = "abc"[:] + #| debug_inspect( + #| sv, + #| content=( + #| #| + #| ), + #| ) + #| let av : ArrayView[Int] = [1, 2, 3][1:3] + #| debug_inspect(av, content="") + #| let fa : FixedArray[Int] = [1, 2, 3] + #| debug_inspect(fa, content="") + #| let ro : ReadOnlyArray[Int] = [1, 2, 3] + #| debug_inspect(ro, content="") + #| let lst : @list.List[Int] = @list.from_array([1, 2, 3]) + #| debug_inspect(lst, content="") + #| let dq : @deque.Deque[Int] = @deque.from_array([1, 2, 3]) + #| debug_inspect(dq, content="") + #| let q : @queue.Queue[Int] = @queue.from_array([1, 2, 3]) + #| debug_inspect(q, content="") + #| let pq : @priority_queue.PriorityQueue[Int] = @priority_queue.from_array([ + #| 3, 1, 2, + #| ]) + #| debug_inspect(pq, content="") + #| let buf = @buffer.new() + #| buf.write_bytes(b"ab") + #| debug_inspect(buf, content="") + #| let r : @ref.Ref[Int] = @ref.new(1) + #| debug_inspect(r, content="") + #| let mv : MutArrayView[Int] = [1, 2, 3].mut_view(start=1, end=3) + #| debug_inspect(mv, content="") + #| debug_inspect((Ok(1) : Result[Int, String]), content="Ok(1)") + #| debug_inspect((Err("e") : Result[Int, String]), content="Err(\"e\")") + #| let immut_arr = @immut_array.from_array([1, 2, 3]) + #| debug_inspect(immut_arr, content="") + #| let immut_pq = @immut_priority_queue.from_array([3, 1, 2]) + #| debug_inspect(immut_pq, content="") + #| let immut_sm = @immut_sorted_map.from_array([(1, "a"), (2, "b")]) + #| debug_inspect( + #| immut_sm, + #| content=( + #| #| + #| ), + #| ) + #| let immut_ss = @immut_sorted_set.from_array([3, 1, 2]) + #| debug_inspect(immut_ss, content="") + #|} + #|test "Debug for hash-based collections" { + #| let hm : @hashmap.HashMap[Int, String] = @hashmap.from_array([(2, "b")]) + #| debug_inspect( + #| hm, + #| content=( + #| #| + #| ), + #| ) + #| let hs : @hashset.HashSet[Int] = @hashset.from_array([1]) + #| debug_inspect(hs, content="") + #| let immut_hm = @immut_hashmap.from_array([(2, "b")]) + #| debug_inspect(immut_hm, content="") + #| let immut_hs = @immut_hashset.from_array([3]) + #| debug_inspect(immut_hs, content="") + #|} + #|#callsite(autofill(loc)) + #|#deprecated("This function is for debugging only and should not be used in production", skip_current_package=true) + #|pub fn[T : Debug] dump(t : T, name? : String, loc~ : SourceLoc) -> T { + #| let name = match name { + #| Some(name) => name + #| None => "" + #| } + #| println("dump(\{name}@\{loc}) = \{to_string(t)}") + #| t + #|} + #|test "dump" { + #| let x = 42 + #| if false { + #| dump(()) // never reached here + #| assert_eq(dump(x) + x, 84) + #| } + #|} + #|fn error_to_repr(e : Error) -> Repr = "%error.to_repr" + #|pub impl Debug for Error with to_repr(self) { + #| error_to_repr(self) + #|} + #|pub impl Debug for InspectError with to_repr(self) { + #| match self { + #| InspectError(msg) => Repr::ctor("InspectError", [(None, Repr::string(msg))]) + #| } + #|} + #|pub impl Debug for Failure with to_repr(self) { + #| match self { + #| Failure(msg) => Repr::ctor("Failure", [(None, Repr::string(msg))]) + #| } + #|} + #|pub impl Debug for SnapshotError with to_repr(self) { + #| match self { + #| SnapshotError(msg) => + #| Repr::ctor("SnapshotError", [(None, Repr::string(msg))]) + #| } + #|} + #|test "Debug for Error" { + #| fn fail_with_error() -> Unit raise { + #| raise InspectError::InspectError("test error") + #| } + #| let result : Result[Unit, Error] = try? fail_with_error() + #| match result { + #| Err(e) => debug_inspect(e, content="InspectError(\"test error\")") + #| Ok(_) => fail("expected error") + #| } + #|} + #|test "Debug for builtin errors" { + #| debug_inspect( + #| InspectError::InspectError("inspect msg"), + #| content="InspectError(\"inspect msg\")", + #| ) + #| debug_inspect( + #| Failure::Failure("failure msg"), + #| content="Failure(\"failure msg\")", + #| ) + #| debug_inspect( + #| SnapshotError::SnapshotError("snapshot msg"), + #| content="SnapshotError(\"snapshot msg\")", + #| ) + #|} + ), + "delta.mbt": ( + #|priv enum ReprDelta { + #| Same(Repr, Array[ReprDelta]) + #| Different(Repr, Repr) + #| Extra1(Repr) + #| Extra2(Repr) + #|} + #|const DEFAULT_MAX_RELATIVE_ERROR : Double = 0.000000000001 + #|fn double_abs(x : Double) -> Double { + #| if x < 0.0 { + #| -x + #| } else { + #| x + #| } + #|} + #|fn double_max(x : Double, y : Double) -> Double { + #| if x > y { + #| x + #| } else { + #| y + #| } + #|} + #|fn relative_error(x : Double, y : Double) -> Double { + #| if x == y { + #| 0.0 + #| } else { + #| let denom = double_max(double_abs(x), double_abs(y)) + #| if denom == 0.0 { + #| double_abs(x - y) + #| } else { + #| double_abs(x - y) / denom + #| } + #| } + #|} + #|fn info_approx_eq(max_relative_error : Double, x : Repr, y : Repr) -> Bool { + #| match (x, y) { + #| (UnitLit, UnitLit) => true + #| (Integer(x1), Integer(y1)) => x1 == y1 + #| (DoubleLit(x1), DoubleLit(y1)) => + #| relative_error(x1, y1) <= max_relative_error + #| (FloatLit(x1), FloatLit(y1)) => x1 == y1 + #| (BoolLit(x1), BoolLit(y1)) => x1 == y1 + #| (CharLit(x1), CharLit(y1)) => x1 == y1 + #| (StringLit(x1), StringLit(y1)) => x1 == y1 + #| (Tuple(_), Tuple(_)) => true + #| (Array(_), Array(_)) => true + #| (Record(_), Record(_)) => true + #| (Enum(n1, _), Enum(n2, _)) => n1 == n2 + #| (Map(_), Map(_)) => true + #| (RecordField(n1, _), RecordField(n2, _)) => n1 == n2 + #| (EnumLabeledArg(n1, _), EnumLabeledArg(n2, _)) => n1 == n2 + #| (Opaque(n1, _), Opaque(n2, _)) => n1 == n2 + #| (Literal(x1), Literal(y1)) => x1 == y1 + #| (MapEntry(_, _), MapEntry(_, _)) => true + #| (Omitted, Omitted) => true + #| _ => false + #| } + #|} + #|fn info_is_unimportant(info : Repr) -> Bool { + #| info is (MapEntry(_, _) | Tuple(_) | Array(_) | Record(_)) + #|} + #|fn diff_info_with( + #| left : Repr, + #| right : Repr, + #| max_relative_error~ : Double, + #|) -> ReprDelta { + #| fn go(left_node : Repr, right_node : Repr) -> ReprDelta { + #| if info_approx_eq(max_relative_error, left_node, right_node) { + #| let xs = left_node.children() + #| let ys = right_node.children() + #| let xlen = xs.length() + #| let ylen = ys.length() + #| let min_len = if xlen < ylen { xlen } else { ylen } + #| let children : Array[ReprDelta] = [] + #| for i in 0.. !(d is Same(_, _))) { + #| Different(left_node, right_node) + #| } else { + #| Same(left_node.shallow(), children) + #| } + #| } else { + #| Different(left_node, right_node) + #| } + #| } + #| go(left, right) + #|} + #|fn diff_repr( + #| x : Repr, + #| y : Repr, + #| max_relative_error? : Double = DEFAULT_MAX_RELATIVE_ERROR, + #|) -> ReprDelta { + #| diff_info_with(x, y, max_relative_error~) + #|} + #|fn pretty_print_delta( + #| d : ReprDelta, + #| max_depth? : Int, + #| compact_threshold? : Int = default_threshold, + #| use_ansi? : Bool = true, + #|) -> String { + #| let max_depth : Int? = match max_depth { + #| Some(_) => max_depth + #| None => Some(default_max_depth) + #| } + #| let delta = prune_delta(max_depth, d) + #| print_content(render_delta(compact_threshold, use_ansi, delta).no_wrap()) + #|} + #|fn prune_delta(max_depth : Int?, delta : ReprDelta) -> ReprDelta { + #| fn go(d : Int, node : ReprDelta) -> ReprDelta { + #| if d <= 0 { + #| match node { + #| Same(label, children) => + #| if children.is_empty() { + #| node + #| } else if !label.info_adds_depth() { + #| Same(label, children.map(child => go(d, child))) + #| } else { + #| Same(Repr::omitted(), []) + #| } + #| Different(_, _) | Extra1(_) | Extra2(_) => Same(Repr::omitted(), []) + #| } + #| } else { + #| match node { + #| Same(label, children) => { + #| let next_depth = if label.info_adds_depth() { d - 1 } else { d } + #| Same(label, children.map(child => go(next_depth, child))) + #| } + #| Different(left, right) => + #| Different(prune_info(left, depth=d), prune_info(right, depth=d)) + #| Extra1(x) => Extra1(prune_info(x, depth=d)) + #| Extra2(x) => Extra2(prune_info(x, depth=d)) + #| } + #| } + #| } + #| match max_depth { + #| None => delta + #| Some(depth) => go(Int::max(1, depth), delta) + #| } + #|} + #|fn delta_root_size(delta : ReprDelta) -> Int { + #| match delta { + #| Same(label, _) => info_size(label) + #| _ => 0 + #| } + #|} + #|const ANSI_RESET : String = "\u001b[0m" + #|const ANSI_RED : String = "\u001b[31m" + #|const ANSI_GREEN : String = "\u001b[32m" + #|fn mark_removed(use_ansi : Bool, x : ContentParens) -> ContentParens { + #| if use_ansi { + #| surround(ANSI_RED + "-", ANSI_RESET, x) + #| } else { + #| surround("-", "", x) + #| } + #|} + #|fn mark_added(use_ansi : Bool, x : ContentParens) -> ContentParens { + #| if use_ansi { + #| surround(ANSI_GREEN + "+", ANSI_RESET, x) + #| } else { + #| surround("+", "", x) + #| } + #|} + #|fn render_delta(threshold : Int, use_ansi : Bool, delta : ReprDelta) -> Content { + #| match delta { + #| Same(label, children_delta) => { + #| let children = children_delta.map(child => { + #| render_delta(threshold, use_ansi, child) + #| }) + #| with_resizing( + #| delta_root_size(delta), + #| threshold, + #| pretty_print_repr_go(label, children), + #| ) + #| } + #| Different(left, right) => { + #| let children : Array[Content] = [ + #| render_repr(threshold, left), + #| render_repr(threshold, right), + #| ] + #| with_resizing( + #| 0, + #| threshold, + #| match children { + #| [left, right] => + #| no_parens( + #| mark_removed(use_ansi, left.no_wrap()) + + #| mark_added(use_ansi, right.no_wrap()), + #| ) + #| _ => empty_content() + #| }, + #| ) + #| } + #| Extra1(x) => { + #| let children : Array[Content] = [render_repr(threshold, x)] + #| with_resizing( + #| 0, + #| threshold, + #| match children { + #| [x] => no_parens(mark_removed(use_ansi, x.no_wrap())) + #| _ => empty_content() + #| }, + #| ) + #| } + #| Extra2(x) => { + #| let children : Array[Content] = [render_repr(threshold, x)] + #| with_resizing( + #| 0, + #| threshold, + #| match children { + #| [x] => no_parens(mark_added(use_ansi, x.no_wrap())) + #| _ => empty_content() + #| }, + #| ) + #| } + #| } + #|} + ), + "pretty_print.mbt": ( + #|let default_max_depth : Int = 16 + #|let default_threshold : Int = 70 + #|fn prune_repr_info(max_depth : Int?, info : Repr) -> Repr { + #| match max_depth { + #| None => info + #| Some(depth) => prune_info(info, depth~) + #| } + #|} + #|fn prune_info( + #| info : Repr, + #| replacement? : Repr = Repr::omitted(), + #| depth~ : Int, + #|) -> Repr { + #| fn go(d : Int, node : Repr) -> Repr { + #| let children = node.children() + #| if d <= 0 { + #| if children.is_empty() { + #| node + #| } else if !node.info_adds_depth() { + #| node.with_children(children.map(child => go(d, child))) + #| } else { + #| replacement + #| } + #| } else if children.is_empty() { + #| node + #| } else { + #| let next_depth = if node.info_adds_depth() { d - 1 } else { d } + #| node.with_children(children.map(child => go(next_depth, child))) + #| } + #| } + #| go(Int::max(1, depth), info) + #|} + #|fn Repr::info_adds_depth(info : Repr) -> Bool { + #| !(info is (RecordField(_, _) | EnumLabeledArg(_, _) | MapEntry(_, _))) + #|} + #|fn info_size(info : Repr) -> Int { + #| match info { + #| UnitLit => 1 + #| Integer(_) => 1 + #| DoubleLit(_) => 1 + #| FloatLit(_) => 1 + #| BoolLit(_) => 1 + #| CharLit(_) => 1 + #| StringLit(s) => if s.length() <= 15 { 1 } else { 2 } + #| Tuple(_) => 1 + #| Array(_) => 1 + #| Record(_) => 2 + #| RecordField(name, _) => if name.length() <= 15 { 0 } else { 1 } + #| EnumLabeledArg(name, _) => if name.length() <= 15 { 0 } else { 1 } + #| Enum(name, _) => if name.length() <= 15 { 1 } else { 2 } + #| Opaque(name, _) => if name.length() <= 15 { 1 } else { 2 } + #| Literal(s) => if s.length() <= 15 { 1 } else { 2 } + #| Map(_) => 2 + #| MapEntry(_, _) => 0 + #| Omitted => 0 + #| } + #|} + #|fn is_unquoted_key(key : String) -> Bool { + #| key is ['a'..='z' | '_', .. rest] && + #| (loop rest { + #| ['a'..='z' | 'A'..='Z' | '0'..='9' | '_', .. rest] => continue rest + #| [_, ..] => false + #| [] => true + #| }) + #|} + #|fn quote_string_literal(s : String) -> String { + #| s.escape() + #|} + #|fn pretty_print_label(name : String) -> String { + #| if is_unquoted_key(name) { + #| name + #| } else { + #| quote_string_literal(name) + #| } + #|} + #|fn pretty_print_repr_go(label : Repr, children : Array[Content]) -> Content { + #| match label { + #| UnitLit => comma_seq("(", ")", []) + #| Integer(s) => { + #| let needs_parens = s.length() > 0 && s.code_unit_at(0) == '-' + #| no_parens(content_parens(if needs_parens { 1 } else { 0 }, [s])) + #| } + #| DoubleLit(x) => { + #| let needs_parens = 1.0 / x < 0.0 + #| leaf(x.to_string(), needs_parens~) + #| } + #| FloatLit(x) => { + #| let needs_parens : Bool = (1.0 : Float) / x < (0.0 : Float) + #| leaf(x.to_string(), needs_parens~) + #| } + #| BoolLit(x) => leaf(x.to_string()) + #| CharLit(x) => leaf(x.escape()) + #| StringLit(x) => no_parens(verbatim(quote_string_literal(x))) + #| Tuple(_) => comma_seq("(", ")", children.map(x => x.no_wrap())) + #| Enum(name, _) => + #| match children { + #| [] => no_parens(verbatim(name)) + #| _ => + #| if name == "Tuple" { + #| comma_seq("(", ")", children.map(x => x.no_wrap())) + #| } else { + #| comma_seq(name + "(", ")", children.map(x => x.no_wrap())) + #| } + #| } + #| Array(_) => comma_seq("[", "]", children.map(x => x.no_wrap())) + #| Record(_) => comma_seq("{", "}", children.map(x => x.no_wrap())) + #| Opaque(name, _) => + #| if children.is_empty() { + #| no_parens(surround("<", ">", verbatim(name))) + #| } else { + #| let body = verbatim(name + ":") + + #| indent( + #| " ", + #| comma_seq("", "", children.map(x => x.no_wrap())).no_wrap(), + #| ) + #| no_parens(surround("<", ">", body)) + #| } + #| Literal(str) => no_parens(verbatim(str)) + #| Map(_) => comma_seq("{", "}", children.map(x => x.no_wrap())) + #| MapEntry(_, _) => + #| match children { + #| [key, val] => { + #| let k = key.no_wrap() + #| let v = val.no_wrap() + #| match v.lines { + #| [] => empty_content() + #| [one] => + #| no_parens( + #| content_parens(1 + k.size + v.size, [ + #| print_content(surround("", ": ", k)) + one, + #| ]), + #| ) + #| [first, ..] => { + #| let n = v.lines.length() + #| let rest = if n <= 1 { [] } else { v.lines[1:n].to_array() } + #| let head = print_content(surround("", ": ", k)) + first + #| no_parens(content_parens(1 + k.size + v.size, [head] + rest)) + #| } + #| } + #| } + #| _ => empty_content() + #| } + #| EnumLabeledArg(name, _) => + #| match children { + #| [val] => + #| match val.lines { + #| [] => empty_content() + #| [first] => + #| no_parens(content_parens(1 + val.size, [name + "=" + first])) + #| [first, ..] => { + #| let n = val.lines.length() + #| let rest = if n <= 1 { [] } else { val.lines[1:n].to_array() } + #| no_parens( + #| content_parens(1 + val.size, [name + "=" + first] + rest), + #| ) + #| } + #| } + #| _ => empty_content() + #| } + #| RecordField(name, _) => + #| match children { + #| [val] => { + #| let label = pretty_print_label(name) + #| let v = val.no_wrap() + #| match v.lines { + #| [] => empty_content() + #| [one] => no_parens(content_parens(1 + v.size, [label + ": " + one])) + #| [first, ..] => { + #| let n = v.lines.length() + #| let rest = if n <= 1 { [] } else { v.lines[1:n].to_array() } + #| no_parens( + #| content_parens(1 + v.size, [label + ": " + first] + rest), + #| ) + #| } + #| } + #| } + #| _ => empty_content() + #| } + #| Omitted => parens(verbatim("...")) + #| } + #|} + #|fn render_repr(threshold : Int, info : Repr) -> Content { + #| let label = info.shallow() + #| let children = info.children().map(child => render_repr(threshold, child)) + #| with_resizing( + #| info_size(label), + #| threshold, + #| pretty_print_repr_go(label, children), + #| ) + #|} + #|pub fn render(r : Repr, max_depth? : Int) -> String { + #| let max_depth : Int? = match max_depth { + #| Some(_) => max_depth + #| None => Some(default_max_depth) + #| } + #| let threshold = default_threshold + #| let info = prune_repr_info(max_depth, r) + #| print_content(render_repr(threshold, info).no_wrap()) + #|} + #|pub impl Show for Repr with output(self, logger) { + #| logger.write_string(render(self)) + #|} + #|pub fn[T : Debug] debug(x : T) -> Unit { + #| println(render(x.to_repr())) + #|} + #|pub fn[T : Debug] to_string(x : T) -> String { + #| render(x.to_repr()) + #|} + ), + "printer.mbt": ( + #|priv struct Content { + #| size : Int + #| lines : Array[String] + #| needs_parens : Bool + #|} + #|priv struct ContentParens { + #| size : Int + #| lines : Array[String] + #|} + #|impl Add for ContentParens with add(self, other) { + #| { size: self.size + other.size, lines: self.lines + other.lines } + #|} + #|fn empty_content() -> Content { + #| { size: 0, lines: [], needs_parens: false } + #|} + #|fn verbatim(x : String) -> ContentParens { + #| { size: 1, lines: [x] } + #|} + #|fn content_parens(size : Int, lines : Array[String]) -> ContentParens { + #| { size, lines } + #|} + #|fn leaf(x : String, needs_parens? : Bool = false) -> Content { + #| { size: 1, lines: [x], needs_parens } + #|} + #|fn with_lines( + #| r : ContentParens, + #| f : (Array[String]) -> Array[String], + #|) -> ContentParens { + #| { size: r.size, lines: f(r.lines) } + #|} + #|fn Content::with_lines_content( + #| r : Content, + #| f : (Array[String]) -> Array[String], + #|) -> Content { + #| { size: r.size, lines: f(r.lines), needs_parens: r.needs_parens } + #|} + #|fn surround_lines( + #| start : String, + #| finish : String, + #| lines : Array[String], + #|) -> Array[String] { + #| match lines { + #| [] => [start + finish] + #| [item] => [start + item + finish] + #| [first, .. middle, last] => [start + first, ..middle, last + finish] + #| } + #|} + #|fn surround( + #| start : String, + #| finish : String, + #| r : ContentParens, + #|) -> ContentParens { + #| with_lines(r, fn(lines) { surround_lines(start, finish, lines) }) + #|} + #|fn Content::no_wrap(c : Content) -> ContentParens { + #| { size: c.size, lines: c.lines } + #|} + #|fn parens(r : ContentParens) -> Content { + #| { size: r.size, lines: r.lines, needs_parens: true } + #|} + #|fn no_parens(r : ContentParens) -> Content { + #| { size: r.size, lines: r.lines, needs_parens: false } + #|} + #|fn compact_lines(lines : Array[String]) -> Array[String] { + #| match lines { + #| [] => [] + #| [x] => [x] + #| [first, .. middle, last] => + #| if (first == "[" && last == "]") || (first == "{" && last == "}") { + #| let parts : Array[String] = [] + #| for m in middle { + #| let t = m.trim().to_string() + #| if t != "" { + #| parts.push(t) + #| } + #| } + #| let joined0 = parts.join(" ") + #| let joined = match joined0.strip_suffix(",") { + #| Some(sv) => sv.to_string() + #| None => joined0 + #| } + #| if first == "{" { + #| let inner0 = joined + #| let inner1 = match inner0.strip_prefix(" ") { + #| Some(sv) => sv.to_string() + #| None => inner0 + #| } + #| let inner = match inner1.strip_suffix(" ") { + #| Some(sv) => sv.to_string() + #| None => inner1 + #| } + #| if inner == "" { + #| ["{}"] + #| } else { + #| ["{ " + inner + " }"] + #| } + #| } else { + #| ["[" + joined + "]"] + #| } + #| } else if first.has_suffix("(") && last == ")" { + #| let parts : Array[String] = [] + #| for m in middle { + #| let t = m.trim() + #| if t != "" { + #| parts.push(t.to_string()) + #| } + #| } + #| let joined0 = parts.join(" ") + #| let joined = match joined0.strip_suffix(",") { + #| Some(sv) => sv.to_string() + #| None => joined0 + #| } + #| [first + joined + last] + #| } else { + #| let parts : Array[StringView] = [first] + #| for m in middle { + #| parts.push(m.trim()) + #| } + #| parts.push(last.trim()) + #| [parts.join(" ")] + #| } + #| } + #|} + #|fn Content::compact(r : Content) -> Content { + #| r.with_lines_content(compact_lines) + #|} + #|fn indent(prefix : String, r : ContentParens) -> ContentParens { + #| with_lines(r, lines => lines.map(line => prefix + line)) + #|} + #|fn indent_spaces(n : Int, r : ContentParens) -> ContentParens { + #| indent(" ".repeat(n), r) + #|} + #|fn bracket_seq_lines( + #| open : String, + #| close : String, + #| indent_by : Int, + #| contents : Array[Array[String]], + #|) -> Array[String] { + #| match contents { + #| [] => [open + close] + #| [item] => + #| if item.length() > 1 { + #| let lines = indent_spaces(indent_by, { size: 0, lines: item }).lines + #| if lines.length() > 0 { + #| let last_i = lines.length() - 1 + #| lines[last_i] = lines[last_i] + "," + #| } + #| [open, ..lines, close] + #| } else { + #| let inner = compact_lines(item) + #| match inner { + #| [] => [open + close] + #| [x] => + #| if open == "{" && close == "}" { + #| let inner = x.trim().to_string() + #| if inner == "" { + #| ["{}"] + #| } else { + #| ["{ " + inner + " }"] + #| } + #| } else { + #| [open + x + close] + #| } + #| _ => + #| [ + #| open, + #| ..indent_spaces(indent_by, { size: 0, lines: item }).lines, + #| close, + #| ] + #| } + #| } + #| _ => { + #| let out : Array[String] = [open] + #| for item in contents { + #| let item_lines = item.filter(line => line != "") + #| match item_lines { + #| [] => () + #| [x] => out.push(" ".repeat(indent_by) + x + ",") + #| [first, .. middle, last] => { + #| out.push(" ".repeat(indent_by) + first) + #| for mid in middle { + #| out.push(" ".repeat(indent_by) + mid) + #| } + #| out.push(" ".repeat(indent_by) + last + ",") + #| } + #| } + #| } + #| out.push(close) + #| out + #| } + #| } + #|} + #|fn comma_seq_lines( + #| begin : String, + #| end : String, + #| contents : Array[Array[String]], + #|) -> Array[String] { + #| if begin == "[" && end == "]" { + #| bracket_seq_lines("[", "]", 2, contents) + #| } else if begin == "{" && end == "}" { + #| bracket_seq_lines("{", "}", 2, contents) + #| } else if begin == "" && end == "" { + #| fn spacer(begin : String) -> String { + #| " ".repeat(begin.length()) + #| } + #| let lines = match contents { + #| [] => [begin + end] + #| [item] => surround_lines(begin, end, item) + #| [first, .. middle, last] => { + #| let space = spacer(begin) + #| let middle_lines = [] + #| for item in middle { + #| middle_lines.append(surround_lines(space, ",", item)) + #| } + #| [ + #| ..surround_lines(begin, ",", first), + #| ..middle_lines, + #| ..surround_lines(space, end, last), + #| ] + #| } + #| } + #| lines.filter(line => line != "") + #| } else { + #| let indent_by = 2 + #| match contents { + #| [] => [begin + end] + #| [item] => { + #| let item_lines = item.filter(line => line != "") + #| match item_lines { + #| [] => [begin + end] + #| [x] => [begin + x + end] + #| [.. pre_lines, last_line] => + #| [ + #| begin, + #| ..pre_lines.iter().map(line => " ".repeat(indent_by) + line), + #| " ".repeat(indent_by) + last_line + ",", + #| end, + #| ] + #| } + #| } + #| _ => { + #| let out : Array[String] = [begin] + #| for item in contents { + #| let item_lines = item.filter(line => line != "") + #| match item_lines { + #| [] => () + #| [x] => out.push(" ".repeat(indent_by) + x + ",") + #| [first, .. middle, last] => { + #| out.push(" ".repeat(indent_by) + first) + #| for mid in middle { + #| out.push(" ".repeat(indent_by) + mid) + #| } + #| out.push(" ".repeat(indent_by) + last + ",") + #| } + #| } + #| } + #| out.push(end) + #| out + #| } + #| } + #| } + #|} + #|fn comma_seq( + #| begin : String, + #| end : String, + #| contents : Array[ContentParens], + #|) -> Content { + #| for c in contents; size = 0 { + #| continue size + c.size + #| } nobreak { + #| { + #| size, + #| lines: comma_seq_lines(begin, end, contents.map(c => c.lines)), + #| needs_parens: false, + #| } + #| } + #|} + #|fn print_content(r : ContentParens) -> String { + #| r.lines.join("\n") + #|} + #|fn with_resizing( + #| _root_size : Int, + #| threshold : Int, + #| rendered_children : Content, + #|) -> Content { + #| if threshold <= 0 { + #| rendered_children + #| } else { + #| let compacted = rendered_children.compact() + #| if compacted.lines.all(line => line.length() <= threshold) { + #| compacted + #| } else { + #| rendered_children + #| } + #| } + #|} + ), + "repr.mbt": ( + #|enum Repr { + #| UnitLit + #| Integer(String) + #| DoubleLit(Double) + #| FloatLit(Float) + #| BoolLit(Bool) + #| CharLit(Char) + #| StringLit(String) + #| Tuple(Array[Repr]) + #| Array(Array[Repr]) + #| Record(Array[Repr]) + #| Enum(String, Array[Repr]) + #| Map(Array[Repr]) + #| RecordField(String, Repr) + #| EnumLabeledArg(String, Repr) + #| Opaque(String, Repr) + #| Literal(String) + #| MapEntry(Repr, Repr) + #| Omitted + #|} + #|fn Repr::children(self : Repr) -> Array[Repr] { + #| match self { + #| UnitLit + #| | Integer(_) + #| | DoubleLit(_) + #| | FloatLit(_) + #| | BoolLit(_) + #| | CharLit(_) + #| | StringLit(_) + #| | Literal(_) + #| | Omitted => [] + #| Tuple(xs) | Array(xs) | Record(xs) | Enum(_, xs) | Map(xs) => xs + #| Opaque(_, value) | RecordField(_, value) | EnumLabeledArg(_, value) => + #| [value] + #| MapEntry(key, value) => [key, value] + #| } + #|} + #|fn Repr::with_children(self : Repr, children : Array[Repr]) -> Repr { + #| match self { + #| UnitLit + #| | Integer(_) + #| | DoubleLit(_) + #| | FloatLit(_) + #| | BoolLit(_) + #| | CharLit(_) + #| | StringLit(_) + #| | Literal(_) + #| | Omitted => self + #| Tuple(_) => Tuple(children) + #| Array(_) => Array(children) + #| Record(_) => Record(children) + #| Enum(name, _) => Enum(name, children) + #| Map(_) => Map(children) + #| RecordField(name, _) => + #| match children { + #| [value] => RecordField(name, value) + #| _ => RecordField(name, Omitted) + #| } + #| EnumLabeledArg(label, _) => + #| match children { + #| [value] => EnumLabeledArg(label, value) + #| _ => EnumLabeledArg(label, Omitted) + #| } + #| MapEntry(_, _) => + #| match children { + #| [key, value] => MapEntry(key, value) + #| _ => MapEntry(Omitted, Omitted) + #| } + #| Opaque(name, _) => + #| match children { + #| [value] => Opaque(name, value) + #| _ => Opaque(name, Omitted) + #| } + #| } + #|} + #|#doc(hidden) + #|pub fn Repr::traverse(self : Repr, f : (Repr) -> Repr) -> Repr { + #| fn go(node : Repr) -> Repr { + #| let children = node.children() + #| let next_children = children.map(child => go(child)) + #| f(node.with_children(next_children)) + #| } + #| go(self) + #|} + #|#doc(hidden) + #|pub fn Repr::integer(x : String) -> Repr { + #| Integer(x) + #|} + #|#doc(hidden) + #|pub fn Repr::double(x : Double) -> Repr { + #| DoubleLit(x) + #|} + #|#doc(hidden) + #|pub fn Repr::float(x : Float) -> Repr { + #| FloatLit(x) + #|} + #|#doc(hidden) + #|pub fn Repr::bool(x : Bool) -> Repr { + #| BoolLit(x) + #|} + #|#doc(hidden) + #|pub fn Repr::char(x : Char) -> Repr { + #| CharLit(x) + #|} + #|#doc(hidden) + #|pub fn Repr::string(x : String) -> Repr { + #| StringLit(x) + #|} + #|#doc(hidden) + #|pub fn Repr::tuple(children : Array[Repr]) -> Repr { + #| Tuple(children) + #|} + #|#doc(hidden) + #|pub fn Repr::array(children : Array[Repr]) -> Repr { + #| Array(children) + #|} + #|#doc(hidden) + #|pub fn Repr::record(fields : Map[String, Repr]) -> Repr { + #| Record(fields.to_array().map(p => RecordField(p.0, p.1))) + #|} + #|#doc(hidden) + #|pub fn Repr::opaque_(name : String, children : Repr) -> Repr { + #| Opaque(name, children) + #|} + #|#doc(hidden) + #|pub fn Repr::literal(value : String) -> Repr { + #| Literal(value) + #|} + #|#doc(hidden) + #|pub fn Repr::map(contents : Array[(Repr, Repr)]) -> Repr { + #| Map( + #| contents.map(pair => { + #| let (k, v) = pair + #| MapEntry(k, v) + #| }), + #| ) + #|} + #|#doc(hidden) + #|pub fn Repr::omitted() -> Repr { + #| Omitted + #|} + #|#doc(hidden) + #|pub fn Repr::unit() -> Repr { + #| UnitLit + #|} + #|#doc(hidden) + #|pub fn Repr::ctor(name : String, args : Array[(String?, Repr)]) -> Repr { + #| Enum( + #| name, + #| args.map(arg => { + #| let (label, value) = arg + #| match label { + #| None => value + #| Some(label) => EnumLabeledArg(label, value) + #| } + #| }), + #| ) + #|} + #|fn Repr::shallow(self : Repr) -> Repr { + #| match self { + #| UnitLit + #| | Integer(_) + #| | DoubleLit(_) + #| | FloatLit(_) + #| | BoolLit(_) + #| | CharLit(_) + #| | StringLit(_) + #| | Literal(_) + #| | Omitted => self + #| Tuple(_) => Tuple([]) + #| Array(_) => Array([]) + #| Record(_) => Record([]) + #| Enum(name, _) => Enum(name, []) + #| Opaque(name, _) => Opaque(name, Omitted) + #| Map(_) => Map([]) + #| RecordField(name, _) => RecordField(name, Omitted) + #| EnumLabeledArg(label, _) => EnumLabeledArg(label, Omitted) + #| MapEntry(_, _) => MapEntry(Omitted, Omitted) + #| } + #|} + ) + } ) ///| let moonbitlang_core_deque_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/deque", - deps={ - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/json": moonbitlang_core_json_module, - "moonbitlang/core/array": moonbitlang_core_array_module, - "moonbitlang/core/string": moonbitlang_core_string_module, - }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| "moonbitlang/core/builtin", - #| "moonbitlang/core/json", - #| "moonbitlang/core/array", - #| "moonbitlang/core/string" - #| ], - #| "targets": { - #| "panic_test.mbt": ["not", "native", "llvm"] - #| } - #|} - ), - "deprecated.mbt": "", - "deque.mbt": ( - #|fn[T] set_null(buffer : UninitializedArray[T], index : Int) = "%fixedarray.set_null" - #|#as_free_fn - #|pub fn[A] Deque::new(capacity? : Int = 0) -> Deque[A] { - #| Deque::{ buf: UninitializedArray::make(capacity), len: 0, head: 0, tail: 0 } - #|} - #|pub impl[A : Show] Show for Deque[A] with output(self, logger) { - #| logger.write_iter(self.iter(), prefix="@deque.from_array([", suffix="])") - #|} - #|pub impl[A : Hash] Hash for Deque[A] with hash_combine(self, hasher) { - #| for v in self { - #| v.hash_combine(hasher) - #| } - #|} - #|pub impl[A] Add for Deque[A] with add(self, other) { - #| let len = self.len + other.len - #| let buf = UninitializedArray::make(len) - #| for i, x in self { - #| buf[i] = x - #| } - #| for i, x in other { - #| buf[i + self.len] = x - #| } - #| Deque::{ buf, len, head: 0, tail: len - 1 } - #|} - #|#as_free_fn - #|#alias(of, deprecated="Use from_array instead") - #|#as_free_fn(of, deprecated="Use from_array instead") - #|pub fn[A] Deque::from_array(arr : ArrayView[A]) -> Deque[A] { - #| let len = arr.length() - #| let buf = UninitializedArray::make(len) - #| for i, x in arr { - #| buf[i] = x - #| } - #| Deque::{ buf, len, head: 0, tail: len - 1 } - #|} - #|pub fn[A] Deque::copy(self : Deque[A]) -> Deque[A] { - #| let len = self.len - #| let buf = UninitializedArray::make(len) - #| for i, x in self { - #| buf[i] = x - #| } - #| Deque::{ buf, len, head: 0, tail: len - 1 } - #|} - #|pub fn[A] Deque::blit_to( - #| self : Deque[A], - #| dst : Deque[A], - #| len~ : Int, - #| src_offset? : Int = 0, - #| dst_offset? : Int = 0, - #|) -> Unit { - #| guard len >= 0 && - #| dst_offset >= 0 && - #| src_offset >= 0 && - #| dst_offset <= dst.length() && - #| src_offset + len <= self.length() - #| if dst_offset + len > dst.buf.length() { - #| dst.reserve_capacity(dst_offset + len) - #| dst.head = 0 - #| dst.tail = dst.len - 1 - #| } - #| let dst_len = dst.len - #| for i = 0; i < len; i = i + 1 { - #| let dst_idx = (dst.head + dst_offset + i) % dst.buf.length() - #| let src_idx = (self.head + src_offset + i) % self.buf.length() - #| dst.buf[dst_idx] = self.buf[src_idx] - #| if dst_offset + i >= dst_len { - #| dst.tail = (dst.tail + 1) % dst.buf.length() - #| dst.len += 1 - #| } - #| } - #|} - #|pub fn[A] Deque::append(self : Deque[A], other : Deque[A]) -> Unit { - #| guard other.len != 0 else { return } - #| let space = if self.buf.length() != 0 { - #| (self.head - self.tail - 1 + self.buf.length()) % self.buf.length() - #| } else { - #| 0 - #| } - #| if space < other.len { - #| let new_cap = if self.len + other.len > self.buf.length() * 2 { - #| self.len + other.len - #| } else { - #| self.buf.length() * 2 - #| } - #| let new_buf = UninitializedArray::make(new_cap) - #| for i, x in self { - #| new_buf[i] = x - #| } - #| self.buf = new_buf - #| self.head = 0 - #| self.tail = self.len - 1 - #| } - #| for _, y in other { - #| self.tail = (self.tail + 1) % self.buf.length() - #| self.buf[self.tail] = y - #| self.len += 1 - #| } - #|} - #|pub fn[A] Deque::insert(self : Deque[A], index : Int, value : A) -> Unit { - #| guard index >= 0 && index <= self.length() else { - #| abort( - #| "index out of bounds: the len is from 0 to \{self.length()} but the index is \{index}", - #| ) - #| } - #| if self.buf.length() - self.len == 0 { - #| self.realloc() - #| } - #| let cap = self.buf.length() - #| if index < self.len / 2 { - #| let new_head = (self.head - 1 + cap) % cap - #| for i = 0; i < index; i = i + 1 { - #| let to = (new_head + i) % cap - #| let from = (self.head + i) % cap - #| self.buf[to] = self.buf[from] - #| } - #| self.head = new_head - #| } else { - #| let new_tail = (self.tail + 1) % cap - #| for i = self.len; i > index; i = i - 1 { - #| let from = (self.head + i - 1) % cap - #| let to = (self.head + i) % cap - #| self.buf[to] = self.buf[from] - #| } - #| self.tail = new_tail - #| } - #| self.buf[(self.head + index) % cap] = value - #| self.len += 1 - #|} - #|pub fn[A] Deque::remove(self : Deque[A], index : Int) -> A { - #| guard index >= 0 && index < self.length() else { - #| abort( - #| "index out of bounds: the len is from 0 to \{self.length()} but the index is \{index}", - #| ) - #| } - #| let res = self[index] - #| let cap = self.buf.length() - #| if index < self.len / 2 { - #| let new_head = (self.head + 1) % cap - #| for i = index - 1; i >= 0; i = i - 1 { - #| let to = (self.head + i + 1) % cap - #| let from = (self.head + i) % cap - #| self.buf[to] = self.buf[from] - #| } - #| set_null(self.buf, self.head) - #| self.head = new_head - #| } else { - #| let new_tail = (self.tail - 1 + cap) % cap - #| for i = index + 1; i < self.len; i = i + 1 { - #| let to = (self.head + i - 1) % cap - #| let from = (self.head + i) % cap - #| self.buf[to] = self.buf[from] - #| } - #| set_null(self.buf, self.tail) - #| self.tail = new_tail - #| } - #| self.len -= 1 - #| res - #|} - #|pub fn[A] Deque::length(self : Deque[A]) -> Int { - #| self.len - #|} - #|pub fn[A] Deque::capacity(self : Deque[A]) -> Int { - #| self.buf.length() - #|} - #|fn[A] Deque::realloc(self : Deque[A]) -> Unit { - #| let old_cap = self.len - #| let new_cap = if old_cap == 0 { 8 } else { old_cap * 2 } - #| let new_buf = UninitializedArray::make(new_cap) - #| if old_cap > 0 { - #| if self.tail >= self.head { - #| for i = self.head, j = 0; i <= self.tail; i = i + 1, j = j + 1 { - #| new_buf[j] = self.buf[i] - #| } - #| } else { - #| let mut j = 0 - #| for i in self.head.. A? { - #| if self.len == 0 { - #| None - #| } else { - #| Some(self.buf[self.head]) - #| } - #|} - #|pub fn[A] Deque::back(self : Deque[A]) -> A? { - #| if self.len == 0 { - #| None - #| } else { - #| Some(self.buf[self.tail]) - #| } - #|} - #|pub fn[A] Deque::push_front(self : Deque[A], value : A) -> Unit { - #| if self.len == self.buf.length() { - #| self.realloc() - #| } - #| if self.len != 0 { - #| self.head = (self.head + self.buf.length() - 1) % self.buf.length() - #| } - #| self.buf[self.head] = value - #| self.len += 1 - #|} - #|pub fn[A] Deque::push_back(self : Deque[A], value : A) -> Unit { - #| if self.len == self.buf.length() { - #| self.realloc() - #| } - #| if self.len != 0 { - #| self.tail = (self.tail + self.buf.length() + 1) % self.buf.length() - #| } - #| self.buf[self.tail] = value - #| self.len += 1 - #|} - #|#internal(unsafe, "Panic if the deque is empty.") - #|#doc(hidden) - #|#alias(pop_front_exn, deprecated) - #|pub fn[A] Deque::unsafe_pop_front(self : Deque[A]) -> Unit { - #| match self.len { - #| 0 => abort("The deque is empty!") - #| 1 => { - #| set_null(self.buf, self.head) - #| self.len -= 1 - #| } - #| _ => { - #| set_null(self.buf, self.head) - #| self.head = if self.head < self.buf.length() - 1 { - #| self.head + 1 - #| } else { - #| 0 - #| } - #| self.len -= 1 - #| } - #| } - #|} - #|#internal(unsafe, "Panic if the deque is empty.") - #|#doc(hidden) - #|#alias(pop_back_exn, deprecated) - #|pub fn[A] Deque::unsafe_pop_back(self : Deque[A]) -> Unit { - #| match self.len { - #| 0 => abort("The deque is empty!") - #| 1 => { - #| set_null(self.buf, self.tail) - #| self.len -= 1 - #| } - #| _ => { - #| set_null(self.buf, self.tail) - #| self.tail = if self.tail > 0 { - #| self.tail - 1 - #| } else { - #| self.buf.length() - 1 - #| } - #| self.len -= 1 - #| } - #| } - #|} - #|pub fn[A] Deque::pop_front(self : Deque[A]) -> A? { - #| match self.len { - #| 0 => None - #| 1 => { - #| let origin_head = self.buf[self.head] - #| set_null(self.buf, self.head) - #| self.len -= 1 - #| Some(origin_head) - #| } - #| _ => { - #| let origin_head = self.buf[self.head] - #| set_null(self.buf, self.head) - #| self.head = if self.head < self.buf.length() - 1 { - #| self.head + 1 - #| } else { - #| 0 - #| } - #| self.len -= 1 - #| Some(origin_head) - #| } - #| } - #|} - #|pub fn[A] Deque::pop_back(self : Deque[A]) -> A? { - #| match self.len { - #| 0 => None - #| 1 => { - #| let origin_back = self.buf[self.tail] - #| set_null(self.buf, self.tail) - #| self.len -= 1 - #| Some(origin_back) - #| } - #| _ => { - #| let origin_back = self.buf[self.tail] - #| set_null(self.buf, self.tail) - #| self.tail = if self.tail > 0 { - #| self.tail - 1 - #| } else { - #| self.buf.length() - 1 - #| } - #| self.len -= 1 - #| Some(origin_back) - #| } - #| } - #|} - #|#alias("_[_]") - #|pub fn[A] Deque::at(self : Deque[A], index : Int) -> A { - #| if index < 0 || index >= self.len { - #| let len = self.len - #| abort( - #| "index out of bounds: the len is from 0 to \{len} but the index is \{index}", - #| ) - #| } - #| if self.head + index < self.buf.length() { - #| self.buf[self.head + index] - #| } else { - #| self.buf[self.head + index - self.buf.length()] - #| } - #|} - #|#alias("_[_]=_") - #|pub fn[A] Deque::set(self : Deque[A], index : Int, value : A) -> Unit { - #| if index < 0 || index >= self.len { - #| let len = self.len - #| abort( - #| "index out of bounds: the len is from 0 to \{len} but the index is \{index}", - #| ) - #| } - #| if self.head + index < self.buf.length() { - #| self.buf[self.head + index] = value - #| } else { - #| self.buf[self.head + index - self.buf.length()] = value - #| } - #|} - #|pub fn[A] Deque::as_views(self : Deque[A]) -> (ArrayView[A], ArrayView[A]) { - #| guard self.len != 0 else { ([][:], [][:]) } - #| let { buf, head, len, .. } = self - #| let cap = buf.length() - #| let head_len = cap - head - #| if head_len >= len { - #| (buf[head:head + len], [][:]) - #| } else { - #| (buf[head:cap], buf[:len - head_len]) - #| } - #|} - #|pub impl[A : Eq] Eq for Deque[A] with equal(self, other) { - #| if self.len != other.len { - #| return false - #| } - #| for i in 0.. Unit) -> Unit { - #| for v in self { - #| f(v) - #| } - #|} - #|pub fn[A] Deque::eachi(self : Deque[A], f : (Int, A) -> Unit) -> Unit { - #| for i, v in self { - #| f(i, v) - #| } - #|} - #|pub fn[A] Deque::rev_each(self : Deque[A], f : (A) -> Unit) -> Unit { - #| for v in self.rev_iter() { - #| f(v) - #| } - #|} - #|pub fn[A] Deque::rev_eachi(self : Deque[A], f : (Int, A) -> Unit) -> Unit { - #| for i, v in self.rev_iter2() { - #| f(i, v) - #| } - #|} - #|pub fn[A] Deque::clear(self : Deque[A]) -> Unit { - #| let { head, buf, len, .. } = self - #| let cap = buf.length() - #| let head_len = cap - head - #| if head_len >= len { - #| for i in head..<(head + len) { - #| set_null(buf, i) - #| } - #| } else { - #| for i in head.. U) -> Deque[U] { - #| let cap = self.buf.length() - #| if self.len == 0 { - #| new() - #| } else { - #| let buf : UninitializedArray[U] = UninitializedArray::make(self.len) - #| for i in 0.. U) -> Deque[U] { - #| let cap = self.buf.length() - #| if self.len == 0 { - #| new() - #| } else { - #| let buf : UninitializedArray[U] = UninitializedArray::make(self.len) - #| for i in 0.. Bool { - #| self.len == 0 - #|} - #|pub fn[A : Eq] Deque::search(self : Deque[A], value : A) -> Int? { - #| let cap = self.buf.length() - #| for i in 0.. Bool { - #| self.iter().contains(value) - #|} - #|#locals(f) - #|pub fn[A] Deque::extract_if(self : Deque[A], f : (A) -> Bool) -> Deque[A] { - #| guard self.length() != 0 else { from_array([]) } - #| let removed = from_array([]) - #| let mut write = 0 - #| for read in 0.. Bool raise?, - #|) -> Deque[A] raise? { - #| let dq = from_array([]) - #| for v in self { - #| if f(v) { - #| dq.push_back(v) - #| } - #| } - #| dq - #|} - #|pub fn[A] Deque::reserve_capacity(self : Deque[A], capacity : Int) -> Unit { - #| if self.capacity() >= capacity { - #| return - #| } - #| let new_buf : UninitializedArray[A] = UninitializedArray::make(capacity) - #| let { buf, len, head, .. } = self - #| self.buf = new_buf - #| self.head = 0 - #| self.tail = if len == 0 { 0 } else { len - 1 } - #| for i in 0.. Unit { - #| if self.capacity() <= self.length() { - #| return - #| } - #| let { buf, len, head, .. } = self - #| self.buf = UninitializedArray::make(len) - #| self.head = 0 - #| self.tail = if len == 0 { 0 } else { len - 1 } - #| for i in 0.. Unit { - #| guard len >= 0 && len < self.len else { return } - #| if len == 0 { - #| self.clear() - #| return - #| } - #| let { head, buf, .. } = self - #| let (front, back) = self.as_views() - #| if front.length() < len { - #| self.len = len - #| let start = len - front.length() - #| self.tail = start - 1 - #| for i in start.. A?) -> Unit { - #| guard !self.is_empty() else { return } - #| let { head, buf, .. } = self - #| let cap = buf.length() - #| let head_len = cap - head - #| let mut idx = head - #| let (front, back) = self.as_views() - #| for cur in front { - #| if f(cur) is Some(v) { - #| buf[idx] = v - #| idx += 1 - #| } - #| } - #| if back.length() == 0 { - #| self.truncate(idx - head) - #| return - #| } - #| for cur in back { - #| if idx == cap { - #| idx = 0 - #| } - #| if f(cur) is Some(v) { - #| buf[idx] = v - #| idx += 1 - #| } - #| } - #| if idx <= self.len - head_len { - #| self.truncate(idx + head_len) - #| } else { - #| self.truncate(idx - head) - #| } - #|} - #|pub fn[A] Deque::retain(self : Deque[A], f : (A) -> Bool) -> Unit { - #| guard !self.is_empty() else { return } - #| let { head, buf, .. } = self - #| let cap = buf.length() - #| let head_len = cap - head - #| let mut idx = head - #| let (front, back) = self.as_views() - #| for cur in front { - #| if f(cur) { - #| buf[idx] = cur - #| idx += 1 - #| } - #| } - #| if back.length() == 0 { - #| self.truncate(idx - head) - #| return - #| } - #| for cur in back { - #| if idx == cap { - #| idx = 0 - #| } - #| if f(cur) { - #| buf[idx] = cur - #| idx += 1 - #| } - #| } - #| if idx <= self.len - head_len { - #| self.truncate(idx + head_len) - #| } else { - #| self.truncate(idx - head) - #| } - #|} - #|pub fn[A] Deque::iter(self : Deque[A]) -> Iter[A] { - #| self.iterator().iter() - #|} - #|pub fn[A] Deque::iterator(self : Deque[A]) -> Iterator[A] { - #| let mut index = 0 - #| Iterator::new(fn() { - #| guard index < self.len else { None } - #| let elem = self.buf[(self.head + index) % self.buf.length()] - #| index += 1 - #| Some(elem) - #| }) - #|} - #|pub fn[A] Deque::iter2(self : Deque[A]) -> Iter2[Int, A] { - #| self.Iter2().iter2() - #|} - #|pub fn[A] Deque::Iter2(self : Deque[A]) -> Iter2[Int, A] { - #| let mut index = 0 - #| Iter2::new(fn() { - #| guard index < self.len else { None } - #| let result = (index, self.buf[(self.head + index) % self.buf.length()]) - #| index += 1 - #| Some(result) - #| }) - #|} - #|pub fn[A] Deque::rev_iter(self : Deque[A]) -> Iter[A] { - #| self.rev_iterator().iter() - #|} - #|pub fn[A] Deque::rev_iterator(self : Deque[A]) -> Iterator[A] { - #| let mut index = self.len - #| Iterator::new(fn() { - #| guard index > 0 else { None } - #| index -= 1 - #| Some(self.buf[(self.head + index) % self.buf.length()]) - #| }) - #|} - #|pub fn[A] Deque::rev_iter2(self : Deque[A]) -> Iter2[Int, A] { - #| self.rev_Iter2().iter2() - #|} - #|pub fn[A] Deque::rev_Iter2(self : Deque[A]) -> Iter2[Int, A] { - #| let mut rev_index = self.len - #| Iter2::new(fn() { - #| guard rev_index > 0 else { None } - #| let index = self.len - rev_index - #| rev_index -= 1 - #| Some((index, self.buf[(self.head + rev_index) % self.buf.length()])) - #| }) - #|} - #|#as_free_fn - #|pub fn[A] Deque::from_iter(iter : Iter[A]) -> Deque[A] { - #| let dq = new() - #| iter.each(e => dq.push_back(e)) - #| dq - #|} - #|#as_free_fn - #|pub fn[A] Deque::from_iterator(iter : Iterator[A]) -> Deque[A] { - #| let dq = new() - #| while iter.next() is Some(e) { - #| dq.push_back(e) - #| } - #| dq - #|} - #|pub fn[A] Deque::to_array(self : Deque[A]) -> Array[A] { - #| let len = self.length() - #| if len == 0 { - #| [] - #| } else { - #| let xs = Array::make(len, self[0]) - #| for i in 0.. String { - #| let str = separator.to_string() - #| self.iter().join(str) - #|} - #|pub impl[A : ToJson] ToJson for Deque[A] with to_json(self : Deque[A]) -> Json { - #| let res = Array::make(self.length(), null) - #| for i, x in self { - #| res[i] = x.to_json() - #| } - #| Json::array(res) - #|} - #|pub impl[A : @json.FromJson] @json.FromJson for Deque[A] with from_json( - #| json, - #| path, - #|) { - #| guard json is Array(arr) else { - #| raise @json.JsonDecodeError((path, "Deque::from_json: expected array")) - #| } - #| let len = arr.length() - #| let buf = UninitializedArray::make(len) - #| let head = 0 - #| let tail = if len == 0 { 0 } else { len - 1 } - #| for i, x in arr { - #| buf[i] = @json.FromJson::from_json(x, path.add_index(i)) - #| } - #| { len, buf, head, tail } - #|} - #|pub fn[A] Deque::chunks(self : Deque[A], size : Int) -> Deque[Deque[A]] { - #| guard size > 0 - #| let chunks = from_array([]) - #| let mut i = 0 - #| while i < self.length() { - #| let chunk = Deque::new(capacity=size) - #| for j = 0; j < size && i < self.length(); j = j + 1 { - #| chunk.push_back(self[i]) - #| i = i + 1 - #| } - #| chunks.push_back(chunk) - #| } - #| chunks - #|} - #|#locals(pred) - #|pub fn[A] Deque::chunk_by( - #| self : Deque[A], - #| pred : (A, A) -> Bool raise?, - #|) -> Deque[Deque[A]] raise? { - #| let chunks = from_array([]) - #| let mut i = 0 - #| while i < self.length() { - #| let chunk = from_array([]) - #| chunk.push_back(self[i]) - #| i = i + 1 - #| while i < self.length() && pred(self[i - 1], self[i]) { - #| chunk.push_back(self[i]) - #| i = i + 1 - #| } - #| chunks.push_back(chunk) - #| } - #| chunks - #|} - #|pub fn[A] Deque::flatten(self : Deque[Deque[A]]) -> Deque[A] { - #| let mut len = 0 - #| for deque in self { - #| len += deque.length() - #| } - #| let target = Deque::{ - #| buf: UninitializedArray::make(len), - #| len, - #| head: 0, - #| tail: len - 1, - #| } - #| let mut i = 0 - #| for deque in self { - #| let (front, back) = deque.as_views() - #| target.buf.unsafe_blit(i, deque.buf, front.start_offset(), front.length()) - #| i += front.length() - #| target.buf.unsafe_blit(i, deque.buf, back.start_offset(), back.length()) - #| i += back.length() - #| } - #| target - #|} - #|pub fn[A] Deque::drain(self : Deque[A], start~ : Int, len? : Int) -> Deque[A] { - #| if start >= self.len { - #| return new() - #| } - #| let max_len = self.len - start - #| let len = if len is Some(l) && l <= max_len { l } else { max_len } - #| if len == 0 { - #| return new() - #| } - #| let deque = Deque::{ - #| buf: UninitializedArray::make(len), - #| len, - #| head: 0, - #| tail: len - 1, - #| } - #| let (front, back) = self.as_views() - #| if start < front.length() { - #| let front_max_drain = front.length() - start - #| if len <= front_max_drain { - #| deque.buf.unsafe_blit(0, self.buf, front.start_offset() + start, len) - #| if start == 0 && len == front_max_drain { - #| for i in front.start_offset().. 0 { - #| let back_remaining = len - front_max_drain - #| let back_len = back.length() - back_remaining - #| if back_len == 0 { - #| for i in 0.. Int, - #|) -> Result[Int, Int] { - #| let len = self.len - #| for i = 0, j = len; i < j; { - #| let h = i + (j - i) / 2 - #| let ord = cmp(self[h]) - #| if ord < 0 { - #| continue h + 1, j - #| } else { - #| continue i, h - #| } - #| } else { - #| if i < len && cmp(self[i]) == 0 { - #| Ok(i) - #| } else { - #| Err(i) - #| } - #| } - #|} - #|pub fn[A] Deque::get(self : Deque[A], index : Int) -> A? { - #| if index >= 0 && index < self.len { - #| let physical_index = (self.head + index) % self.buf.length() - #| Some(self.buf[physical_index]) - #| } else { - #| None - #| } - #|} - #|pub fn[A : Compare] Deque::binary_search( - #| self : Deque[A], - #| value : A, - #|) -> Result[Int, Int] { - #| self.binary_search_by(x => x.compare(value)) - #|} - #|pub impl[A : Compare] Compare for Deque[A] with compare(self, other) { - #| let len_self = self.length() - #| let len_other = other.length() - #| let cmp = len_self.compare(len_other) - #| guard cmp is 0 else { return cmp } - #| for i in 0.. Unit { - #| guard self.len > 0 else { return } - #| let cap = self.buf.length() - #| let mut left = self.head - #| let mut right = self.tail - #| for _ in 0..<(self.len / 2) { - #| let temp = self.buf[left] - #| self.buf[left] = self.buf[right] - #| self.buf[right] = temp - #| left = (left + 1) % cap - #| right = (right - 1 + cap) % cap - #| } - #|} - #|pub fn[A] Deque::rev(self : Deque[A]) -> Deque[A] { - #| let len = self.len - #| let new_buf = UninitializedArray::make(len) - #| for i in 0.. Int, - #|) -> Unit { - #| let n = self.len - #| let buf_length = self.buf.length() - #| for i = n - 1; i > 0; i = i - 1 { - #| let j = rand(i + 1) - #| let i_pos = (self.head + i) % buf_length - #| let j_pos = (self.head + j) % buf_length - #| let tmp = self.buf[i_pos] - #| self.buf[i_pos] = self.buf[j_pos] - #| self.buf[j_pos] = tmp - #| } - #|} - #|pub fn[A] Deque::shuffle(self : Deque[A], rand~ : (Int) -> Int) -> Deque[A] { - #| let new_deque = self.copy() - #| new_deque.shuffle_in_place(rand~) - #| new_deque - #|} - ), - "types.mbt": ( - #|#alias(T, deprecated) - #|struct Deque[A] { - #| mut buf : UninitializedArray[A] - #| mut len : Int - #| mut head : Int - #| mut tail : Int - #|} - ), - }, + "deprecated.mbt": "", + "deque.mbt": ( + #|fn[T] set_null(buffer : UninitializedArray[T], index : Int) = "%fixedarray.set_null" + #|#as_free_fn + #|pub fn[A] Deque::new(capacity? : Int = 0) -> Deque[A] { + #| Deque::{ buf: UninitializedArray::make(capacity), len: 0, head: 0 } + #|} + #|fn[A] Deque::tail_index(self : Deque[A]) -> Int { + #| (self.head + self.len - 1) % self.buf.length() + #|} + #|pub impl[A : Show] Show for Deque[A] with output(self, logger) { + #| logger.write_iter(self.iter(), prefix="@deque.from_array([", suffix="])") + #|} + #|pub impl[A : Hash] Hash for Deque[A] with hash_combine(self, hasher) { + #| for v in self { + #| v.hash_combine(hasher) + #| } + #|} + #|pub impl[A] Add for Deque[A] with add(self, other) { + #| let len = self.len + other.len + #| let buf = UninitializedArray::make(len) + #| for i, x in self { + #| buf[i] = x + #| } + #| for i, x in other { + #| buf[i + self.len] = x + #| } + #| Deque::{ buf, len, head: 0 } + #|} + #|test "add_empty" { + #| let empty1 : Deque[Int] = new() + #| let empty2 : Deque[Int] = new() + #| let result = empty1 + empty2 + #| inspect(result.len, content="0") + #| inspect(result.is_empty(), content="true") + #|} + #|#as_free_fn + #|#alias(of, deprecated="Use from_array instead") + #|#as_free_fn(of, deprecated="Use from_array instead") + #|pub fn[A] Deque::from_array(arr : ArrayView[A]) -> Deque[A] { + #| let len = arr.length() + #| let buf = UninitializedArray::make(len) + #| for i, x in arr { + #| buf[i] = x + #| } + #| Deque::{ buf, len, head: 0 } + #|} + #|test "from_array_empty" { + #| let dq : Deque[Int] = from_array([]) + #| inspect(dq.len, content="0") + #| inspect(dq.is_empty(), content="true") + #|} + #|#alias(clone, deprecated) + #|pub fn[A] Deque::copy(self : Deque[A]) -> Deque[A] { + #| let len = self.len + #| let buf = UninitializedArray::make(len) + #| for i, x in self { + #| buf[i] = x + #| } + #| Deque::{ buf, len, head: 0 } + #|} + #|pub fn[A] Deque::blit_to( + #| self : Deque[A], + #| dst : Deque[A], + #| len~ : Int, + #| src_offset? : Int = 0, + #| dst_offset? : Int = 0, + #|) -> Unit { + #| guard len >= 0 && + #| dst_offset >= 0 && + #| src_offset >= 0 && + #| dst_offset <= dst.length() && + #| src_offset + len <= self.length() + #| if dst_offset + len > dst.buf.length() { + #| dst.reserve_capacity(dst_offset + len) + #| dst.head = 0 + #| } + #| let dst_len = dst.len + #| let needs_reverse = physical_equal(self, dst) && + #| src_offset < dst_offset && + #| src_offset + len > dst_offset + #| if needs_reverse { + #| let new_len = if dst_offset + len > dst_len { + #| dst_offset + len + #| } else { + #| dst_len + #| } + #| if new_len > dst_len { + #| dst.len = new_len + #| } + #| for i in len>..0 { + #| let dst_idx = (dst.head + dst_offset + i) % dst.buf.length() + #| let src_idx = (self.head + src_offset + i) % self.buf.length() + #| dst.buf[dst_idx] = self.buf[src_idx] + #| } + #| } else { + #| for i in 0..= dst_len { + #| dst.len += 1 + #| } + #| } + #| } + #|} + #|pub fn[A] Deque::append(self : Deque[A], other : Deque[A]) -> Unit { + #| let other_len = other.len + #| let other_head = other.head + #| let other_buf = other.buf + #| let other_buf_len = other_buf.length() + #| guard other_len != 0 else { return } + #| let space = self.buf.length() - self.len + #| if space < other_len { + #| let new_cap = if self.len + other_len > self.buf.length() * 2 { + #| self.len + other_len + #| } else { + #| self.buf.length() * 2 + #| } + #| let new_buf = UninitializedArray::make(new_cap) + #| for i, x in self { + #| new_buf[i] = x + #| } + #| self.buf = new_buf + #| self.head = 0 + #| } + #| let cap = self.buf.length() + #| for i in 0.. Unit { + #| guard index >= 0 && index <= self.length() else { + #| abort( + #| "index out of bounds: the len is from 0 to \{self.length()} but the index is \{index}", + #| ) + #| } + #| if self.buf.length() - self.len == 0 { + #| self.realloc() + #| } + #| let cap = self.buf.length() + #| if index < self.len / 2 { + #| let new_head = (self.head - 1 + cap) % cap + #| for i in 0.. index; i = i - 1 { + #| let from = (self.head + i - 1) % cap + #| let to = (self.head + i) % cap + #| self.buf[to] = self.buf[from] + #| } + #| } + #| self.buf[(self.head + index) % cap] = value + #| self.len += 1 + #|} + #|pub fn[A] Deque::remove(self : Deque[A], index : Int) -> A { + #| guard index >= 0 && index < self.length() else { + #| abort( + #| "index out of bounds: the len is from 0 to \{self.length()} but the index is \{index}", + #| ) + #| } + #| let res = self[index] + #| let cap = self.buf.length() + #| if index < self.len / 2 { + #| let new_head = (self.head + 1) % cap + #| for i in index>..0 { + #| let to = (self.head + i + 1) % cap + #| let from = (self.head + i) % cap + #| self.buf[to] = self.buf[from] + #| } + #| set_null(self.buf, self.head) + #| self.head = new_head + #| } else { + #| let tail_idx = (self.head + self.len - 1) % cap + #| for i in (index + 1).. Int { + #| self.len + #|} + #|pub fn[A] Deque::capacity(self : Deque[A]) -> Int { + #| self.buf.length() + #|} + #|fn[A] Deque::realloc(self : Deque[A]) -> Unit { + #| let old_cap = self.buf.length() + #| let new_cap = if old_cap == 0 { 8 } else { old_cap * 2 } + #| let new_buf = UninitializedArray::make(new_cap) + #| for i in 0.. A? { + #| if self.len == 0 { + #| None + #| } else { + #| Some(self.buf[self.head]) + #| } + #|} + #|pub fn[A] Deque::back(self : Deque[A]) -> A? { + #| if self.len == 0 { + #| None + #| } else { + #| Some(self.buf[self.tail_index()]) + #| } + #|} + #|pub fn[A] Deque::push_front(self : Deque[A], value : A) -> Unit { + #| if self.len == self.buf.length() { + #| self.realloc() + #| } + #| let cap = self.buf.length() + #| self.head = (self.head - 1 + cap) % cap + #| self.buf[self.head] = value + #| self.len += 1 + #|} + #|pub fn[A] Deque::push_back(self : Deque[A], value : A) -> Unit { + #| if self.len == self.buf.length() { + #| self.realloc() + #| } + #| let cap = self.buf.length() + #| let write_idx = (self.head + self.len) % cap + #| self.buf[write_idx] = value + #| self.len += 1 + #|} + #|#internal(unsafe, "Panic if the deque is empty.") + #|#doc(hidden) + #|#alias(pop_front_exn, deprecated) + #|pub fn[A] Deque::unsafe_pop_front(self : Deque[A]) -> Unit { + #| guard self.len > 0 else { abort("The deque is empty!") } + #| set_null(self.buf, self.head) + #| let cap = self.buf.length() + #| self.head = (self.head + 1) % cap + #| self.len -= 1 + #|} + #|test "unsafe_pop_front after many push_front" { + #| let dq = new() + #| for i in 0..<10 { + #| dq.push_front(i) + #| } + #| for _ in 0..<10 { + #| dq.unsafe_pop_front() + #| } + #| assert_eq(dq.len, 0) + #|} + #|#internal(unsafe, "Panic if the deque is empty.") + #|#doc(hidden) + #|#alias(pop_back_exn, deprecated) + #|pub fn[A] Deque::unsafe_pop_back(self : Deque[A]) -> Unit { + #| guard self.len > 0 else { abort("The deque is empty!") } + #| let tail_idx = self.tail_index() + #| set_null(self.buf, tail_idx) + #| self.len -= 1 + #|} + #|pub fn[A] Deque::pop_front(self : Deque[A]) -> A? { + #| guard self.len > 0 else { return None } + #| let value = self.buf[self.head] + #| set_null(self.buf, self.head) + #| let cap = self.buf.length() + #| self.head = (self.head + 1) % cap + #| self.len -= 1 + #| Some(value) + #|} + #|pub fn[A] Deque::pop_back(self : Deque[A]) -> A? { + #| guard self.len > 0 else { return None } + #| let tail_idx = self.tail_index() + #| let value = self.buf[tail_idx] + #| set_null(self.buf, tail_idx) + #| self.len -= 1 + #| Some(value) + #|} + #|#alias("_[_]") + #|pub fn[A] Deque::at(self : Deque[A], index : Int) -> A { + #| if index < 0 || index >= self.len { + #| let len = self.len + #| abort( + #| "index out of bounds: the len is from 0 to \{len} but the index is \{index}", + #| ) + #| } + #| if self.head + index < self.buf.length() { + #| self.buf[self.head + index] + #| } else { + #| self.buf[self.head + index - self.buf.length()] + #| } + #|} + #|#alias("_[_]=_") + #|pub fn[A] Deque::set(self : Deque[A], index : Int, value : A) -> Unit { + #| if index < 0 || index >= self.len { + #| let len = self.len + #| abort( + #| "index out of bounds: the len is from 0 to \{len} but the index is \{index}", + #| ) + #| } + #| if self.head + index < self.buf.length() { + #| self.buf[self.head + index] = value + #| } else { + #| self.buf[self.head + index - self.buf.length()] = value + #| } + #|} + #|pub fn[A] Deque::as_views(self : Deque[A]) -> (ArrayView[A], ArrayView[A]) { + #| guard self.len != 0 else { ([][:], [][:]) } + #| let { buf, head, len } = self + #| let cap = buf.length() + #| let head_len = cap - head + #| if head_len >= len { + #| (buf[head:head + len], [][:]) + #| } else { + #| (buf[head:cap], buf[:len - head_len]) + #| } + #|} + #|pub impl[A : Eq] Eq for Deque[A] with equal(self, other) { + #| if self.len != other.len { + #| return false + #| } + #| for i in 0.. Unit) -> Unit { + #| for v in self { + #| f(v) + #| } + #|} + #|pub fn[A] Deque::eachi(self : Deque[A], f : (Int, A) -> Unit) -> Unit { + #| for i, v in self { + #| f(i, v) + #| } + #|} + #|pub fn[A] Deque::rev_each(self : Deque[A], f : (A) -> Unit) -> Unit { + #| for v in self.rev_iter() { + #| f(v) + #| } + #|} + #|pub fn[A] Deque::rev_eachi(self : Deque[A], f : (Int, A) -> Unit) -> Unit { + #| for i, v in self.rev_iter2() { + #| f(i, v) + #| } + #|} + #|pub fn[A] Deque::clear(self : Deque[A]) -> Unit { + #| let { head, buf, len } = self + #| let cap = buf.length() + #| let head_len = cap - head + #| if head_len >= len { + #| for i in head..<(head + len) { + #| set_null(buf, i) + #| } + #| } else { + #| for i in head.. U) -> Deque[U] { + #| let cap = self.buf.length() + #| if self.len == 0 { + #| new() + #| } else { + #| let buf : UninitializedArray[U] = UninitializedArray::make(self.len) + #| for i in 0.. U) -> Deque[U] { + #| let cap = self.buf.length() + #| if self.len == 0 { + #| new() + #| } else { + #| let buf : UninitializedArray[U] = UninitializedArray::make(self.len) + #| for i in 0.. Bool { + #| self.len == 0 + #|} + #|pub fn[A : Eq] Deque::search(self : Deque[A], value : A) -> Int? { + #| let cap = self.buf.length() + #| for i in 0.. Bool { + #| self.iter().contains(value) + #|} + #|#locals(f) + #|pub fn[A] Deque::extract_if(self : Deque[A], f : (A) -> Bool) -> Deque[A] { + #| guard self.length() != 0 else { from_array([]) } + #| let removed = from_array([]) + #| let write = for read in 0.. Bool raise?, + #|) -> Deque[A] raise? { + #| let dq = from_array([]) + #| for v in self { + #| if f(v) { + #| dq.push_back(v) + #| } + #| } + #| dq + #|} + #|pub fn[A] Deque::reserve_capacity(self : Deque[A], capacity : Int) -> Unit { + #| if self.capacity() >= capacity { + #| return + #| } + #| let new_buf : UninitializedArray[A] = UninitializedArray::make(capacity) + #| let { buf, len, head } = self + #| self.buf = new_buf + #| self.head = 0 + #| for i in 0.. Unit { + #| if self.capacity() <= self.length() { + #| return + #| } + #| let { buf, len, head } = self + #| self.buf = UninitializedArray::make(len) + #| self.head = 0 + #| for i in 0.. Unit { + #| guard len >= 0 && len < self.len else { return } + #| if len == 0 { + #| self.clear() + #| return + #| } + #| let { head, buf, .. } = self + #| let (front, back) = self.as_views() + #| if front.length() < len { + #| self.len = len + #| let start = len - front.length() + #| for i in start.. A?) -> Unit { + #| guard !self.is_empty() else { return } + #| let { head, buf, .. } = self + #| let cap = buf.length() + #| let (front, back) = self.as_views() + #| let (idx, kept_len) = for cur in front; idx = head, kept_len = 0 { + #| if f(cur) is Some(v) { + #| buf[idx] = v + #| continue idx + 1, kept_len + 1 + #| } + #| continue idx, kept_len + #| } nobreak { + #| (idx, kept_len) + #| } + #| if back.length() == 0 { + #| self.truncate(kept_len) + #| return + #| } + #| let kept_len = for cur in back; idx = idx, kept_len = kept_len { + #| let idx = if idx == cap { 0 } else { idx } + #| if f(cur) is Some(v) { + #| buf[idx] = v + #| continue idx + 1, kept_len + 1 + #| } + #| continue idx, kept_len + #| } nobreak { + #| kept_len + #| } + #| self.truncate(kept_len) + #|} + #|pub fn[A] Deque::retain(self : Deque[A], f : (A) -> Bool) -> Unit { + #| guard !self.is_empty() else { return } + #| let { head, buf, .. } = self + #| let cap = buf.length() + #| let (front, back) = self.as_views() + #| let (idx, kept_len) = for cur in front; idx = head, kept_len = 0 { + #| if f(cur) { + #| buf[idx] = cur + #| continue idx + 1, kept_len + 1 + #| } + #| continue idx, kept_len + #| } nobreak { + #| (idx, kept_len) + #| } + #| if back.length() == 0 { + #| self.truncate(kept_len) + #| return + #| } + #| let kept_len = for cur in back; idx = idx, kept_len = kept_len { + #| let idx = if idx == cap { 0 } else { idx } + #| if f(cur) { + #| buf[idx] = cur + #| continue idx + 1, kept_len + 1 + #| } + #| continue idx, kept_len + #| } nobreak { + #| kept_len + #| } + #| self.truncate(kept_len) + #|} + #|#alias(iterator, deprecated) + #|pub fn[A] Deque::iter(self : Deque[A]) -> Iter[A] { + #| let mut index = 0 + #| Iter::new(fn() { + #| guard index < self.len else { None } + #| let elem = self.buf[(self.head + index) % self.buf.length()] + #| index += 1 + #| Some(elem) + #| }) + #|} + #|#alias(iterator2, deprecated) + #|pub fn[A] Deque::iter2(self : Deque[A]) -> Iter2[Int, A] { + #| let mut index = 0 + #| Iter2::new(fn() { + #| guard index < self.len else { None } + #| let result = (index, self.buf[(self.head + index) % self.buf.length()]) + #| index += 1 + #| Some(result) + #| }) + #|} + #|#alias(rev_iterator, deprecated) + #|pub fn[A] Deque::rev_iter(self : Deque[A]) -> Iter[A] { + #| let mut index = self.len + #| Iter::new(fn() { + #| guard index > 0 else { None } + #| index -= 1 + #| Some(self.buf[(self.head + index) % self.buf.length()]) + #| }) + #|} + #|#alias(rev_iterator2, deprecated) + #|pub fn[A] Deque::rev_iter2(self : Deque[A]) -> Iter2[Int, A] { + #| let mut rev_index = self.len + #| Iter2::new(fn() { + #| guard rev_index > 0 else { None } + #| let index = self.len - rev_index + #| rev_index -= 1 + #| Some((index, self.buf[(self.head + rev_index) % self.buf.length()])) + #| }) + #|} + #|#as_free_fn + #|#alias(from_iterator, deprecated) + #|#as_free_fn(from_iterator, deprecated) + #|pub fn[A] Deque::from_iter(iter : Iter[A]) -> Deque[A] { + #| let dq = new() + #| while iter.next() is Some(e) { + #| dq.push_back(e) + #| } + #| dq + #|} + #|pub fn[A] Deque::to_array(self : Deque[A]) -> Array[A] { + #| let len = self.length() + #| if len == 0 { + #| [] + #| } else { + #| let xs = Array::make(len, self[0]) + #| for i in 0.. String { + #| let str = separator.to_string() + #| self.iter().join(str) + #|} + #|pub impl[A : ToJson] ToJson for Deque[A] with to_json(self : Deque[A]) -> Json { + #| let res = Array::make(self.length(), null) + #| for i, x in self { + #| res[i] = x.to_json() + #| } + #| Json::array(res) + #|} + #|pub impl[A : @json.FromJson] @json.FromJson for Deque[A] with from_json( + #| json, + #| path, + #|) { + #| guard json is Array(arr) else { + #| raise @json.JsonDecodeError((path, "Deque::from_json: expected array")) + #| } + #| let len = arr.length() + #| let buf = UninitializedArray::make(len) + #| for i, x in arr { + #| buf[i] = @json.FromJson::from_json(x, path.add_index(i)) + #| } + #| { len, buf, head: 0 } + #|} + #|pub fn[A] Deque::chunks(self : Deque[A], size : Int) -> Deque[Deque[A]] { + #| guard size > 0 + #| let chunks = from_array([]) + #| for i = 0; i < self.length(); { + #| let chunk = Deque::new(capacity=size) + #| let i = for _ in 0..= self.length() { + #| break i + #| } + #| chunk.push_back(self[i]) + #| continue i + 1 + #| } nobreak { + #| i + #| } + #| chunks.push_back(chunk) + #| continue i + #| } + #| chunks + #|} + #|#locals(pred) + #|pub fn[A] Deque::chunk_by( + #| self : Deque[A], + #| pred : (A, A) -> Bool raise?, + #|) -> Deque[Deque[A]] raise? { + #| let chunks = from_array([]) + #| for i = 0; i < self.length(); { + #| let chunk = from_array([]) + #| chunk.push_back(self[i]) + #| let i = for i = i + 1; i < self.length() && pred(self[i - 1], self[i]); { + #| chunk.push_back(self[i]) + #| continue i + 1 + #| } nobreak { + #| i + #| } + #| chunks.push_back(chunk) + #| continue i + #| } + #| chunks + #|} + #|pub fn[A] Deque::flatten(self : Deque[Deque[A]]) -> Deque[A] { + #| let len = for deque in self; len = 0 { + #| continue len + deque.length() + #| } nobreak { + #| len + #| } + #| let target = Deque::{ buf: UninitializedArray::make(len), len, head: 0 } + #| for deque in self; i = 0 { + #| let (front, back) = deque.as_views() + #| target.buf.unsafe_blit(i, deque.buf, front.start_offset(), front.length()) + #| let i = i + front.length() + #| target.buf.unsafe_blit(i, deque.buf, back.start_offset(), back.length()) + #| continue i + back.length() + #| } + #| target + #|} + #|pub fn[A] Deque::drain(self : Deque[A], start~ : Int, len? : Int) -> Deque[A] { + #| guard start >= 0 && start <= self.len else { + #| abort( + #| "Deque::drain: start index out of bounds (start=\{start}, deque.length()=\{self.len})", + #| ) + #| } + #| let len = match len { + #| Some(l) => { + #| guard l >= 0 && start + l <= self.len else { + #| abort( + #| "Deque::drain: len out of bounds (start=\{start}, len=\{l}, deque.length()=\{self.len})", + #| ) + #| } + #| l + #| } + #| None => self.len - start + #| } + #| if len == 0 { + #| return new() + #| } + #| let deque = Deque::{ buf: UninitializedArray::make(len), len, head: 0 } + #| let (front, back) = self.as_views() + #| if start < front.length() { + #| let front_max_drain = front.length() - start + #| if len <= front_max_drain { + #| deque.buf.unsafe_blit(0, self.buf, front.start_offset() + start, len) + #| if start == 0 && len == front_max_drain { + #| for i in front.start_offset().. 0 { + #| let back_remaining = len - front_max_drain + #| let back_len = back.length() - back_remaining + #| if back_len == 0 { + #| for i in 0.. Int, + #|) -> Result[Int, Int] { + #| let len = self.len + #| for i = 0, j = len; i < j; { + #| let h = i + (j - i) / 2 + #| let ord = cmp(self[h]) + #| if ord < 0 { + #| continue h + 1, j + #| } else { + #| continue i, h + #| } + #| } nobreak { + #| if i < len && cmp(self[i]) == 0 { + #| Ok(i) + #| } else { + #| Err(i) + #| } + #| } + #|} + #|pub fn[A] Deque::get(self : Deque[A], index : Int) -> A? { + #| if index >= 0 && index < self.len { + #| let physical_index = (self.head + index) % self.buf.length() + #| Some(self.buf[physical_index]) + #| } else { + #| None + #| } + #|} + #|pub fn[A : Compare] Deque::binary_search( + #| self : Deque[A], + #| value : A, + #|) -> Result[Int, Int] { + #| self.binary_search_by(x => x.compare(value)) + #|} + #|pub impl[A : Compare] Compare for Deque[A] with compare(self, other) { + #| let len_self = self.length() + #| let len_other = other.length() + #| let cmp = len_self.compare(len_other) + #| guard cmp is 0 else { return cmp } + #| for i in 0.. Unit { + #| guard self.len > 0 else { return } + #| let cap = self.buf.length() + #| for _ in 0..<(self.len / 2); left = self.head, right = self.tail_index() { + #| let temp = self.buf[left] + #| self.buf[left] = self.buf[right] + #| self.buf[right] = temp + #| continue (left + 1) % cap, (right - 1 + cap) % cap + #| } + #|} + #|pub fn[A] Deque::rev(self : Deque[A]) -> Deque[A] { + #| let len = self.len + #| let new_buf = UninitializedArray::make(len) + #| for i in 0.. Int, + #|) -> Unit { + #| let n = self.len + #| let buf_length = self.buf.length() + #| for i in n>..1 { + #| let j = rand(i + 1) + #| let i_pos = (self.head + i) % buf_length + #| let j_pos = (self.head + j) % buf_length + #| let tmp = self.buf[i_pos] + #| self.buf[i_pos] = self.buf[j_pos] + #| self.buf[j_pos] = tmp + #| } + #|} + #|pub fn[A] Deque::shuffle(self : Deque[A], rand~ : (Int) -> Int) -> Deque[A] { + #| let new_deque = self.copy() + #| new_deque.shuffle_in_place(rand~) + #| new_deque + #|} + ), + "types.mbt": ( + #|#alias(T, deprecated) + #|struct Deque[A] { + #| mut buf : UninitializedArray[A] + #| mut len : Int + #| mut head : Int + #|} + ) + } ) ///| let moonbitlang_core_double_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/double", - deps={ - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/uint64": moonbitlang_core_uint64_module, - "moonbitlang/core/double/internal/ryu": moonbitlang_core_double_internal_ryu_module, - }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| "moonbitlang/core/builtin", - #| "moonbitlang/core/uint64", - #| "moonbitlang/core/double/internal/ryu" - #| ], - #| "test-import": [ - #| "moonbitlang/core/bytes", - #| "moonbitlang/core/buffer" - #| ], - #| "targets": { - #| "exp_js.mbt": ["js"], - #| "exp_nonjs.mbt": ["not", "js"], - #| "log_js.mbt": ["js"], - #| "log_nonjs.mbt": ["not", "js"], - #| "mod_js.mbt": ["js"], - #| "mod_nonjs.mbt": ["not", "js"], - #| "pow_js.mbt": ["js"], - #| "pow_nonjs.mbt": ["not", "js"], - #| "trig_js.mbt" : ["js"], - #| "trig_nonjs.mbt" : ["not", "js"], - #| "round_js.mbt": ["js"], - #| "round_wasm.mbt": ["wasm", "wasm-gc"], - #| "round.mbt": ["not", "js", "wasm", "wasm-gc"], - #| "to_uint_wasm.mbt": ["wasm", "wasm-gc"], - #| "to_uint.mbt": ["not", "wasm", "wasm-gc"], - #| "hyperbolic_js.mbt": ["js"], - #| "hyperbolic_nonjs.mbt": ["not", "js"], - #| "cbrt_js.mbt" : ["js"], - #| "cbrt_nonjs.mbt" : ["not", "js"], - #| "hypot_js.mbt" : ["js"], - #| "hypot_nonjs.mbt" : ["not", "js"], - #| "scalbn.mbt" : ["not", "js"] - #| } - #|} - ), - "deprecated.mbt": ( - #|#deprecated("Use `@double.not_a_number` instead") - #|#coverage.skip - #|pub fn Double::nan() -> Double { - #| not_a_number - #|} - #|#deprecated("Use `@double.infinity` and `@double.neg_infinity` instead") - #|#coverage.skip - #|pub fn Double::inf(sign : Int) -> Double { - #| if sign >= 0 { - #| infinity - #| } else { - #| neg_infinity - #| } - #|} - #|#deprecated("Use `@double.min_positive` instead") - #|#coverage.skip - #|pub fn Double::min_normal() -> Double { - #| min_positive - #|} - ), - "double.mbt": ( - #|#as_free_fn(deprecated) - #|pub fn Double::from_int(i : Int) -> Double { - #| i.to_double() - #|} - #|#as_free_fn(deprecated) - #|pub fn Double::abs(self : Double) -> Double = "%f64.abs" - #|pub fn Double::signum(self : Double) -> Double { - #| if self < 0.0 { - #| -1.0 - #| } else if self > 0.0 { - #| 1.0 - #| } else { - #| self // handles 0.0, -0.0, NaN - #| } - #|} - #|pub fn Double::is_nan(self : Double) -> Bool { - #| self != self - #|} - #|pub fn Double::is_inf(self : Double) -> Bool { - #| self > max_value || self < min_value - #|} - #|pub fn Double::is_pos_inf(self : Double) -> Bool { - #| self > max_value - #|} - #|pub fn Double::is_neg_inf(self : Double) -> Bool { - #| self < min_value - #|} - #|pub impl Hash for Double with hash_combine(self, hasher) { - #| hasher.combine_double(self) - #|} - #|pub fn Double::to_string(self : Double) -> String { - #| @ryu.ryu_to_string(self) - #|} - #|pub impl Show for Double with output(self, logger) { - #| logger.write_string(self.to_string()) - #|} - #|#as_free_fn(deprecated) - #|pub fn Double::is_close( - #| self : Self, - #| other : Self, - #| relative_tolerance? : Self = 1.0e-09, - #| absolute_tolerance? : Self = 0.0, - #|) -> Bool { - #| if relative_tolerance < 0.0 || absolute_tolerance < 0.0 { - #| abort("Tolerances must be non-negative") - #| } - #| if self == other { - #| return true - #| } - #| if self.is_inf() || other.is_inf() { - #| return false - #| } - #| let diff = (other - self).abs() - #| return ( - #| diff <= (relative_tolerance * other).abs() || - #| diff <= (relative_tolerance * self).abs() - #| ) || - #| diff <= absolute_tolerance - #|} - #|#deprecated - #|#doc(hidden) - #|pub fn Double::to_be_bytes(self : Double) -> Bytes { - #| self.reinterpret_as_uint64().to_be_bytes() - #|} - #|#deprecated - #|#doc(hidden) - #|pub fn Double::to_le_bytes(self : Double) -> Bytes { - #| self.reinterpret_as_uint64().to_le_bytes() - #|} - ), - "limits.mbt": ( - #|pub let not_a_number : Double = 0x7FF8000000000001L.reinterpret_as_double() - #|pub let infinity : Double = 0x7FF0000000000000L.reinterpret_as_double() - #|pub let neg_infinity : Double = 0xFFF0000000000000L.reinterpret_as_double() - #|pub let max_value : Double = 0x7FEFFFFFFFFFFFFFL.reinterpret_as_double() - #|pub let min_value : Double = 0xFFEFFFFFFFFFFFFFL.reinterpret_as_double() - #|pub let min_positive : Double = 0x0010000000000000L.reinterpret_as_double() - ), - "mod_js.mbt": ( - #|extern "js" fn Double::mod_ffi(self : Double, other : Double) -> Double = - #| #| (a, b) => (a % b) - #|pub impl Mod for Double with mod(self, other) { - #| self.mod_ffi(other) - #|} - ), - "mod_nonjs.mbt": ( - #|pub impl Mod for Double with mod(self : Double, other : Double) -> Double { - #| let x = self - #| let y = other - #| let mut uint64_x = x.reinterpret_as_uint64() - #| let mut uint64_y = y.reinterpret_as_uint64() - #| let mut ex = ((uint64_x >> 52) & 0x7FF).to_int() - #| let mut ey = ((uint64_y >> 52) & 0x7FF).to_int() - #| let sign_x = uint64_x >> 63 - #| let mut i : UInt64 = 0 - #| if uint64_y << 1 == 0 || y.is_nan() || ex == 0x7ff { - #| return x * y / (x * y) - #| } - #| if uint64_x << 1 <= uint64_y << 1 { - #| if uint64_x << 1 == uint64_y << 1 { - #| return 0.0 * x - #| } - #| return x - #| } - #| if ex == 0 { - #| i = uint64_x << 12 - #| while i >> 63 == 0 { - #| ex -= 1 - #| i = i << 1 - #| } - #| uint64_x = uint64_x << (-ex + 1) - #| } else { - #| uint64_x = uint64_x & (18446744073709551615UL >> 12) - #| uint64_x = uint64_x | (1UL << 52) - #| } - #| if ey == 0 { - #| i = uint64_y << 12 - #| while i >> 63 == 0 { - #| ey -= 1 - #| i = i << 1 - #| } - #| uint64_y = uint64_y << (-ey + 1) - #| } else { - #| uint64_y = uint64_y & (18446744073709551615UL >> 12) - #| uint64_y = uint64_y | (1UL << 52) - #| } - #| while ex > ey { - #| i = uint64_x - uint64_y - #| if i >> 63 == 0 { - #| if i == 0 { - #| return 0.0 * x - #| } - #| uint64_x = i - #| } - #| uint64_x = uint64_x << 1 - #| ex -= 1 - #| } - #| i = uint64_x - uint64_y - #| if i >> 63 == 0 { - #| if i == 0 { - #| return 0.0 * x - #| } - #| uint64_x = i - #| } - #| while uint64_x >> 52 == 0 { - #| uint64_x = uint64_x << 1 - #| ex -= 1 - #| } - #| if ex > 0 { - #| uint64_x = uint64_x - (1UL << 52) - #| uint64_x = uint64_x | (ex.to_uint64() << 52) - #| } else { - #| uint64_x = uint64_x >> (-ex + 1) - #| } - #| uint64_x = uint64_x | (sign_x << 63) - #| uint64_x.reinterpret_as_double() - #|} - ), - "pow_js.mbt": ( - #|#as_free_fn - #|pub fn Double::pow(self : Double, other : Double) -> Double = "Math" "pow" - #|let _j : (FixedArray[String], StringView) -> String = FixedArray::join - ), - "pow_nonjs.mbt": ( - #|let pow_bp : ReadOnlyArray[Double] = [1.0, 1.5] - #|let pow_dp_h : ReadOnlyArray[Double] = [0.0, 5.84962487220764160156e-01] - #|let pow_dp_l : ReadOnlyArray[Double] = [0.0, 1.35003920212974897128e-08] - #|const ZERO = 0.0 - #|const ONE = 1.0 - #|const TWO = 2.0 - #|const POW_two53 = 9007199254740992.0 - #|const POW_huge = 1.0e300 - #|const POW_tiny = 1.0e-300 - #|const POW_L1 = 5.99999999999994648725e-01 - #|const POW_L2 = 4.28571428578550184252e-01 - #|const POW_L3 = 3.33333329818377432918e-01 - #|const POW_L4 = 2.72728123808534006489e-01 - #|const POW_L5 = 2.30660745775561754067e-01 - #|const POW_L6 = 2.06975017800338417784e-01 - #|const POW_P1 = 1.66666666666666019037e-01 - #|const POW_P2 = -2.77777777770155933842e-03 - #|const POW_P3 = 6.61375632143793436117e-05 - #|const POW_P4 = -1.65339022054652515390e-06 - #|const POW_P5 = 4.13813679705723846039e-08 - #|const POW_lg2 = 6.93147180559945286227e-01 - #|const POW_lg2_h = 6.93147182464599609375e-01 - #|const POW_lg2_l = -1.90465429995776804525e-09 - #|const POW_ovt = 8.0085662595372944372e-0017 - #|const POW_cp = 9.61796693925975554329e-01 - #|const POW_cp_h = 9.61796700954437255859e-01 - #|const POW_cp_l = -7.02846165095275826516e-09 - #|const POW_ivln2 = 1.44269504088896338700e+00 - #|const POW_ivln2_h = 1.44269502162933349609e+00 - #|const POW_ivln2_l = 1.92596299112661746887e-08 - #|#as_free_fn - #|pub fn Double::pow(self : Double, other : Double) -> Double { - #| fn set_low_word(d : Double, v : UInt) -> Double { - #| let bits : UInt64 = d.reinterpret_as_uint64() - #| let bits = bits & 0xFFFF_FFFF_0000_0000 - #| let bits = bits | v.to_uint64() - #| bits.reinterpret_as_double() - #| } - #| fn set_high_word(d : Double, v : UInt) -> Double { - #| let bits : UInt64 = d.reinterpret_as_uint64() - #| let bits = bits & 0x0000_0000_FFFF_FFFF - #| let bits = bits | (v.to_uint64() << 32) - #| bits.reinterpret_as_double() - #| } - #| fn get_high_word(x : Double) -> UInt { - #| (x.reinterpret_as_uint64() >> 32).to_uint() - #| } - #| fn get_low_word(x : Double) -> UInt { - #| x.reinterpret_as_uint64().to_uint() - #| } - #| let x = self - #| let y = other - #| let mut z : Double = 0.0 - #| let mut ax : Double = 0.0 - #| let mut z_h : Double = 0.0 - #| let mut z_l : Double = 0.0 - #| let mut p_h : Double = 0.0 - #| let mut p_l : Double = 0.0 - #| let mut y1 : Double = 0.0 - #| let mut t1 : Double = 0.0 - #| let mut t2 : Double = 0.0 - #| let mut r : Double = 0.0 - #| let mut s : Double = 0.0 - #| let mut t : Double = 0.0 - #| let mut u : Double = 0.0 - #| let mut v : Double = 0.0 - #| let mut w : Double = 0.0 - #| let mut i : Int = 0 - #| let mut j : Int = 0 - #| let mut k : Int = 0 - #| let mut yisint : Int = 0 - #| let mut n : Int = 0 - #| let hx : Int = (x.reinterpret_as_uint64() >> 32).to_int() - #| let lx : UInt = (x.reinterpret_as_uint64() & 0xFFFFFFFF).to_uint() - #| let hy : Int = (y.reinterpret_as_uint64() >> 32).to_int() - #| let ly : UInt = (y.reinterpret_as_uint64() & 0xFFFFFFFF).to_uint() - #| let mut ix : Int = hx & 0x7FFFFFFF - #| let iy : Int = hy & 0x7FFFFFFF - #| if (iy.reinterpret_as_uint() | ly) == 0 { - #| return ONE - #| } - #| if ix > 0x7FF00000 || - #| (ix == 0x7FF00000 && lx != 0) || - #| iy > 0x7FF00000 || - #| (iy == 0x7FF00000 && ly != 0) { - #| return x + y - #| } - #| if hx < 0 { - #| if iy >= 0x43400000 { - #| yisint = 2 // even integer y - #| } else if iy >= 0x3ff00000 { - #| k = (iy >> 20) - 0x3ff // exponent - #| if k > 20 { - #| j = (ly >> (52 - k)).reinterpret_as_int() - #| if j << (52 - k) == ly.reinterpret_as_int() { - #| yisint = 2 - (j & 1) - #| } - #| } else if ly == 0 { - #| j = iy >> (20 - k) - #| if j << (20 - k) == iy { - #| yisint = 2 - (j & 1) - #| } - #| } - #| } - #| } - #| if ly == 0 { - #| if iy == 0x7ff00000 { // y is +-inf - #| if ((ix.reinterpret_as_uint() - 0x3ff00000) | lx) == 0 { - #| return y - y // inf**+-1 is NaN - #| } else if ix >= 0x3ff00000 { // (|x|>1)**+-inf = inf,0 - #| return if hy >= 0 { y } else { ZERO } - #| } else { // (|x|<1)**-,+inf = inf,0 - #| return if hy < 0 { -y } else { ZERO } - #| } - #| } - #| if iy == 0x3ff00000 { // y is +-1 - #| if hy < 0 { - #| return ONE / x - #| } else { - #| return x - #| } - #| } - #| if hy == 0x40000000 { // y is 2 - #| return x * x - #| } - #| if hy == 0x3fe00000 { // y is 0.5 - #| if hx >= 0 { // x >= +0 - #| return x.sqrt() - #| } - #| } - #| } - #| ax = x.abs() - #| if lx == 0 { - #| if ix == 0x7ff00000 || ix == 0 || ix == 0x3ff00000 { - #| z = ax // x is +-0,+-inf,+-1 */ - #| if hy < 0 { - #| z = ONE / z // z = (1/|x|) - #| } - #| if hx < 0 { - #| if ((ix - 0x3ff00000) | yisint) == 0 { - #| z = not_a_number - #| } else if yisint == 1 { - #| z = -z // (x<0)**odd = -(|x|**odd) - #| } - #| } - #| return z - #| } - #| } - #| n = (hx >> 31) + 1 - #| if (n | yisint) == 0 { - #| return not_a_number - #| } - #| s = ONE // s (sign of result -ve**odd) = -1 else = 1 - #| if (n | (yisint - 1)) == 0 { - #| s = -ONE // (-ve)**(odd int) - #| } - #| if iy > 0x41e00000 { // if |y| > 2**31 */ - #| if iy > 0x43f00000 { // if |y| > 2**64, must o/uflow */ - #| if ix <= 0x3fefffff { - #| return if hy < 0 { POW_huge * POW_huge } else { POW_tiny * POW_tiny } - #| } - #| if ix >= 0x3ff00000 { - #| return if hy > 0 { POW_huge * POW_huge } else { POW_tiny * POW_tiny } - #| } - #| } - #| if ix < 0x3fefffff { - #| return if hy < 0 { - #| s * POW_huge * POW_huge - #| } else { - #| s * POW_tiny * POW_tiny - #| } - #| } - #| if ix > 0x3ff00000 { - #| return if hy > 0 { - #| s * POW_huge * POW_huge - #| } else { - #| s * POW_tiny * POW_tiny - #| } - #| } - #| t = ax - ONE // t has 20 trailing zeros */ - #| w = t * t * (0.5 - t * (0.3333333333333333333333 - t * 0.25)) - #| u = POW_ivln2_h * t // POW_ivln2_h has 21 sig. bits */ - #| v = t * POW_ivln2_l - w * POW_ivln2 - #| t1 = u + v - #| t1 = set_low_word(t1, 0) - #| t2 = v - (t1 - u) - #| } else { - #| n = 0 - #| if ix < 0x00100000 { - #| ax *= POW_two53 - #| n -= 53 - #| ix = get_high_word(ax).reinterpret_as_int() - #| } - #| n += (ix >> 20) - 0x3ff - #| j = ix & 0x000fffff - #| ix = j | 0x3ff00000 // normalize ix - #| if j <= 0x3988E { - #| k = 0 // |x|> 1) | 0x20000000) + - #| 0x00080000 + - #| (k.reinterpret_as_uint() << 18), - #| ) - #| let mut t_l : Double = ax - (t_h - pow_bp[k]) - #| let s_l : Double = v * (u - s_h * t_h - s_h * t_l) - #| let mut s2 : Double = ss * ss - #| r = s2 * - #| s2 * - #| ( - #| POW_L1 + - #| s2 * - #| (POW_L2 + s2 * (POW_L3 + s2 * (POW_L4 + s2 * (POW_L5 + s2 * POW_L6)))) - #| ) - #| r += s_l * (s_h + ss) - #| s2 = s_h * s_h - #| t_h = 3.0 + s2 + r - #| t_h = set_low_word(t_h, 0) - #| t_l = r - (t_h - 3.0 - s2) - #| u = s_h * t_h - #| v = s_l * t_h + t_l * ss - #| p_h = u + v - #| p_h = set_low_word(p_h, 0) - #| p_l = v - (p_h - u) - #| z_h = POW_cp_h * p_h // cp_h+cp_l = 2/(3*log2) - #| z_l = POW_cp_l * p_h + p_l * POW_cp + pow_dp_l[k] - #| t = n.to_double() - #| t1 = z_h + z_l + pow_dp_h[k] + t - #| t1 = set_low_word(t1, 0) - #| t2 = z_l - (t1 - t - pow_dp_h[k] - z_h) - #| } - #| y1 = y - #| y1 = set_low_word(y1, 0) - #| p_l = (y - y1) * t1 + y * t2 - #| p_h = y1 * t1 - #| z = p_l + p_h - #| j = get_high_word(z).reinterpret_as_int() - #| i = get_low_word(z).reinterpret_as_int() - #| if j >= 0x40900000 { // z >= 1024 - #| if ((j - 0x40900000) | i) != 0 { // if z > 1024 - #| return s * POW_huge * POW_huge // overflow - #| } else if p_l + POW_ovt > z - p_h { - #| return s * POW_huge * POW_huge // overflow - #| } - #| } else if (j & 0x7fffffff) >= 0x4090cc00 { // z <= -1075 - #| if ((j - 0xc090cc00) | i) != 0 { // z < -1075 - #| return s * POW_tiny * POW_tiny // underflow - #| } else if p_l <= z - p_h { - #| return s * POW_tiny * POW_tiny // underflow - #| } - #| } - #| i = j & 0x7fffffff - #| k = (i >> 20) - 0x3ff - #| n = 0 - #| if i > 0x3fe00000 { // if |z| > 0.5, set n = [z+0.5] - #| n = j + (0x00100000 >> (k + 1)) - #| k = ((n & 0x7fffffff) >> 20) - 0x3ff // new k for n - #| t = ZERO - #| t = set_high_word(t, (n & (0x000fffff >> k).lnot()).reinterpret_as_uint()) - #| n = ((n & 0x000fffff) | 0x00100000) >> (20 - k) - #| if j < 0 { - #| n = -n - #| } - #| p_h -= t - #| } - #| t = p_l + p_h - #| t = set_low_word(t, 0) - #| u = t * POW_lg2_h - #| v = (p_l - (t - p_h)) * POW_lg2 + t * POW_lg2_l - #| z = u + v - #| w = v - (z - u) - #| t = z * z - #| t1 = z - - #| t * (POW_P1 + t * (POW_P2 + t * (POW_P3 + t * (POW_P4 + t * POW_P5)))) - #| r = z * t1 / (t1 - TWO - (w + z * w)) - #| z = ONE - (r - z) - #| j = get_high_word(z).reinterpret_as_int() - #| j += (n.reinterpret_as_uint() << 20).reinterpret_as_int() - #| if j >> 20 <= 0 { - #| z = scalbn(z, n) - #| } else { // subnormal output */ - #| let tmp = get_high_word(z).reinterpret_as_int() - #| z = set_high_word( - #| z, - #| (tmp + (n.reinterpret_as_uint() << 20).reinterpret_as_int()).reinterpret_as_uint(), - #| ) - #| } - #| return s * z - #|} - ), - "round.mbt": ( - #|let sign_mask : UInt64 = 0x8000_0000_0000_0000 - #|let exp_bias = 1023 - #|let exp_bits = 11 - #|let frac_bits = 52 - #|#as_free_fn - #|pub fn Double::trunc(self : Double) -> Double { - #| let u64 = self.reinterpret_as_uint64() - #| let biased_exp = ((u64 >> frac_bits) & ((0x1UL << exp_bits) - 1)).to_int() - #| if biased_exp < exp_bias { - #| return (u64 & sign_mask).reinterpret_as_double() - #| } else if biased_exp >= exp_bias + frac_bits { - #| return self - #| } - #| let mask_shift = biased_exp - exp_bias + exp_bits - #| let trunc_mask = (sign_mask.reinterpret_as_int64() >> mask_shift).reinterpret_as_uint64() - #| return (u64 & trunc_mask).reinterpret_as_double() - #|} - #|#as_free_fn - #|pub fn Double::ceil(self : Double) -> Double { - #| let trunced = self.trunc() - #| if self > trunced { - #| return trunced + 1.0 - #| } else { - #| return trunced - #| } - #|} - #|#as_free_fn - #|pub fn Double::floor(self : Double) -> Double { - #| let trunced = self.trunc() - #| if self < trunced { - #| return trunced - 1.0 - #| } else { - #| return trunced - #| } - #|} - #|#as_free_fn - #|pub fn Double::round(self : Double) -> Double { - #| floor(self + 0.5) - #|} - ), - "round_js.mbt": ( - #|#as_free_fn - #|pub fn Double::trunc(self : Double) -> Double = "Math" "trunc" - #|#as_free_fn - #|pub fn Double::ceil(self : Double) -> Double = "Math" "ceil" - #|#as_free_fn - #|pub fn Double::floor(self : Double) -> Double = "Math" "floor" - #|#as_free_fn - #|pub fn Double::round(self : Double) -> Double = "Math" "round" - ), - "round_wasm.mbt": ( - #|#as_free_fn - #|pub fn Double::trunc(self : Double) -> Double = "(func (param $d f64) (result f64) (f64.trunc (local.get $d)))" - #|#as_free_fn - #|pub fn Double::ceil(self : Double) -> Double = "(func (param $d f64) (result f64) (f64.ceil (local.get $d)))" - #|#as_free_fn - #|pub fn Double::floor(self : Double) -> Double = "(func (param $d f64) (result f64) (f64.floor (local.get $d)))" - #|#as_free_fn - #|pub fn Double::round(self : Double) -> Double { - #| floor(self + 0.5) - #|} - ), - "scalbn.mbt": ( - #|fn scalbn(x : Double, exp : Int) -> Double { - #| let mut n = exp - #| let mut y : Double = x - #| if n > 1023 { - #| y *= 0x1.0p1023 - #| n -= 1023 - #| if n > 1023 { - #| y *= 0x1.0p1023 - #| n -= 1023 - #| if n > 1023 { - #| n = 1023 - #| } - #| } - #| } else if n < -1022 { - #| y *= 0x1.0p-1022 * 0x1.0p53 - #| n += 1022 - 53 - #| if n < -1022 { - #| y *= 0x1.0p-1022 * 0x1.0p53 - #| n += 1022 - 53 - #| if n < -1022 { - #| n = -1022 - #| } - #| } - #| } - #| let ui = (0x3ff + n).to_uint64() << 52 - #| return y * ui.reinterpret_as_double() - #|} - ), - "to_uint.mbt": ( - #|pub fn Double::to_uint(self : Double) -> UInt { - #| if self != self { - #| 0 - #| } else if self >= 4294967295.0 { - #| 4294967295U - #| } else if self <= 0 { - #| 0 - #| } else { - #| UInt::trunc_double(self) - #| } - #|} - ), - "to_uint_wasm.mbt": ( - #|pub fn Double::to_uint(self : Double) -> UInt = "%f64.to_u32_saturate" - ), - }, + "alias.mbt": ( + #|pub fn round(d : Double) -> Double { + #| d.round() + #|} + #|pub fn ceil(d : Double) -> Double { + #| d.ceil() + #|} + #|pub fn floor(d : Double) -> Double { + #| d.floor() + #|} + #|pub fn trunc(d : Double) -> Double { + #| d.trunc() + #|} + ), + "deprecated.mbt": ( + #|#deprecated("Use `@double.not_a_number` instead") + #|#coverage.skip + #|pub fn Double::nan() -> Double { + #| not_a_number + #|} + #|#deprecated("Use `@double.infinity` and `@double.neg_infinity` instead") + #|#coverage.skip + #|pub fn Double::inf(sign : Int) -> Double { + #| if sign >= 0 { + #| infinity + #| } else { + #| neg_infinity + #| } + #|} + #|#deprecated("Use `@double.min_positive` instead") + #|#coverage.skip + #|pub fn Double::min_normal() -> Double { + #| min_positive + #|} + #|#deprecated("Use `@math.pow` instead") + #|#warnings("-deprecated") + #|pub fn pow(m : Double, n : Double) -> Double { + #| m.pow(n) + #|} + #|#deprecated("Use `Double::is_close` instead") + #|pub fn is_close( + #| d : Double, + #| other : Double, + #| relative_tolerance? : Double = 1.0e-09, + #| absolute_tolerance? : Double = 0.0, + #|) -> Bool { + #| d.is_close(other, relative_tolerance~, absolute_tolerance~) + #|} + #|#deprecated("Use `Double::from_int` instead") + #|pub fn from_int(i : Int) -> Double { + #| Double::from_int(i) + #|} + #|#deprecated("Use `x.abs()` instead") + #|pub fn abs(x : Double) -> Double { + #| x.abs() + #|} + ), + "limits.mbt": ( + #|pub let not_a_number : Double = 0x7FF8000000000001L.reinterpret_as_double() + #|pub let infinity : Double = 0x7FF0000000000000L.reinterpret_as_double() + #|pub let neg_infinity : Double = 0xFFF0000000000000L.reinterpret_as_double() + #|pub let max_value : Double = 0x7FEFFFFFFFFFFFFFL.reinterpret_as_double() + #|pub let min_value : Double = 0xFFEFFFFFFFFFFFFFL.reinterpret_as_double() + #|pub let min_positive : Double = 0x0010000000000000L.reinterpret_as_double() + ) + } ) ///| -let moonbitlang_core_double_internal_ryu_module : RuntimePackage = RuntimePackage::new( - "moonbitlang/core/double/internal/ryu", - deps={ - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/bool": moonbitlang_core_bool_module, - "moonbitlang/core/array": moonbitlang_core_array_module, - }, +let moonbitlang_core_encoding_ascii_module : RuntimePackage = RuntimePackage::new( + "moonbitlang/core/encoding/ascii", + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| "moonbitlang/core/builtin", - #| "moonbitlang/core/bool", - #| "moonbitlang/core/array" - #| ] - #|} - ), - "ryu.mbt": ( - #|fn pow5bits(e : Int) -> Int { - #| ((e * 1217359).reinterpret_as_uint() >> 19).reinterpret_as_int() + 1 - #|} - #|fn copy_special_str(sign : Bool, exponent : Bool, mantissa : Bool) -> String { - #| if mantissa { - #| return "NaN" - #| } - #| let s = if sign { "-" } else { "" } - #| if exponent { - #| return s + "Infinity" - #| } - #| return s + "0.0" - #|} - #|fn log10Pow5(e : Int) -> Int { - #| ((e * 732923).reinterpret_as_uint() >> 20).reinterpret_as_int() - #|} - #|fn log10Pow2(e : Int) -> Int { - #| ((e * 78913).reinterpret_as_uint() >> 18).reinterpret_as_int() - #|} - #|fn string_from_bytes(bytes : FixedArray[Byte], from : Int, to : Int) -> String { - #| let buf = StringBuilder::new(size_hint=bytes.length()) - #| for i in from.. Umul128 { - #| let aLo = a & 0xffffffff - #| let aHi = a >> 32 - #| let bLo = b & 0xffffffff - #| let bHi = b >> 32 - #| let x = aLo * bLo - #| let y = aHi * bLo + (x >> 32) - #| let z = aLo * bHi + (y & 0xffffffff) - #| let w = aHi * bHi + (y >> 32) + (z >> 32) - #| let lo = a * b - #| let hi = w - #| Umul128(lo, hi) - #|} - #|fn shiftright128(lo : UInt64, hi : UInt64, dist : Int) -> UInt64 { - #| (hi << (64 - dist)) | (lo >> dist) - #|} - #|fn pow5Factor(value : UInt64) -> Int { - #| if value % 5UL != 0UL { - #| return 0 - #| } - #| if value % 25UL != 0UL { - #| return 1 - #| } - #| if value % 125UL != 0UL { - #| return 2 - #| } - #| if value % 625UL != 0UL { - #| return 3 - #| } - #| let mut count = 4 - #| let mut value = value / 625UL - #| while value > 0UL { - #| if value % 5UL != 0UL { - #| return count - #| } - #| value = value / 5UL - #| count = count + 1 - #| } - #| abort("IllegalArgumentException \{value}") - #|} - #|fn multipleOfPowerOf5(value : UInt64, p : Int) -> Bool { - #| pow5Factor(value) >= p - #|} - #|fn multipleOfPowerOf2(value : UInt64, p : Int) -> Bool { - #| (value & ((1UL << p) - 1UL)) == 0UL - #|} - #|fn mulShiftAll64( - #| m : UInt64, - #| mul : Pow5Pair, - #| j : Int, - #| mmShift : Bool, - #|) -> MulShiftAll64Result { - #| let Pow5Pair(mul0, mul1) = mul - #| let m = m << 1 - #| let Umul128(lo, tmp) = umul128(m, mul0) - #| let Umul128(lo2, hi2) = umul128(m, mul1) - #| let mid = tmp + lo2 - #| let hi = hi2 + (if mid < tmp { 1UL } else { 0UL }) - #| let lo2 = lo + mul0 - #| let mid2 = mid + mul1 + (if lo2 < lo { 1UL } else { 0UL }) - #| let hi2 = hi + (if mid2 < mid { 1UL } else { 0UL }) - #| let vp : UInt64 = shiftright128(mid2, hi2, j - 64 - 1) - #| let mut vm : UInt64 = 0UL - #| if mmShift { - #| let lo3 = lo - mul0 - #| let mid3 = mid - mul1 - (if lo < lo3 { 1UL } else { 0UL }) - #| let hi3 = hi - (if mid < mid3 { 1UL } else { 0UL }) - #| vm = shiftright128(mid3, hi3, j - 64 - 1) - #| } else { - #| let lo3 : UInt64 = lo + lo - #| let mid3 : UInt64 = mid + mid + (if lo3 < lo { 1UL } else { 0UL }) - #| let hi3 : UInt64 = hi + hi + (if mid3 < mid { 1UL } else { 0UL }) - #| let lo4 : UInt64 = lo3 - mul0 - #| let mid4 : UInt64 = mid3 - mul1 - (if lo3 < lo4 { 1UL } else { 0UL }) - #| let hi4 : UInt64 = hi3 - (if mid3 < mid4 { 1UL } else { 0UL }) - #| vm = shiftright128(mid4, hi4, j - 64) - #| } - #| let vr : UInt64 = shiftright128(mid, hi, j - 64 - 1) - #| MulShiftAll64Result(vr, vp, vm) - #|} - #|let gPOW5_TABLE_SIZE = 26 - #|let gDOUBLE_POW5_INV_SPLIT2 : ReadOnlyArray[UInt64] = [ - #| 1, 2305843009213693952, 5955668970331000884, 1784059615882449851, 8982663654677661702, - #| 1380349269358112757, 7286864317269821294, 2135987035920910082, 7005857020398200553, - #| 1652639921975621497, 17965325103354776697, 1278668206209430417, 8928596168509315048, - #| 1978643211784836272, 10075671573058298858, 1530901034580419511, 597001226353042382, - #| 1184477304306571148, 1527430471115325346, 1832889850782397517, 12533209867169019542, - #| 1418129833677084982, 5577825024675947042, 2194449627517475473, 11006974540203867551, - #| 1697873161311732311, 10313493231639821582, 1313665730009899186, 12701016819766672773, - #| 2032799256770390445, - #|] - #|let gPOW5_INV_OFFSETS : ReadOnlyArray[UInt] = [ - #| 0x54544554, 0x04055545, 0x10041000, 0x00400414, 0x40010000, 0x41155555, 0x00000454, - #| 0x00010044, 0x40000000, 0x44000041, 0x50454450, 0x55550054, 0x51655554, 0x40004000, - #| 0x01000001, 0x00010500, 0x51515411, 0x05555554, 0x00000000, - #|] - #|let gDOUBLE_POW5_SPLIT2 : ReadOnlyArray[UInt64] = [ - #| 0, 1152921504606846976, 0, 1490116119384765625, 1032610780636961552, 1925929944387235853, - #| 7910200175544436838, 1244603055572228341, 16941905809032713930, 1608611746708759036, - #| 13024893955298202172, 2079081953128979843, 6607496772837067824, 1343575221513417750, - #| 17332926989895652603, 1736530273035216783, 13037379183483547984, 2244412773384604712, - #| 1605989338741628675, 1450417759929778918, 9630225068416591280, 1874621017369538693, - #| 665883850346957067, 1211445438634777304, 14931890668723713708, 1565756531257009982, - #|] - #|let gPOW5_OFFSETS : ReadOnlyArray[UInt] = [ - #| 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x40000000, 0x59695995, 0x55545555, - #| 0x56555515, 0x41150504, 0x40555410, 0x44555145, 0x44504540, 0x45555550, 0x40004000, - #| 0x96440440, 0x55565565, 0x54454045, 0x40154151, 0x55559155, 0x51405555, 0x00000105, - #|] - #|let gDOUBLE_POW5_TABLE : ReadOnlyArray[UInt64] = [ - #| 1, 5, 25, 125, 625, 3125, 15625, 78125, 390625, 1953125, 9765625, 48828125, 244140625, - #| 1220703125, 6103515625, 30517578125, 152587890625, 762939453125, 3814697265625, - #| 19073486328125, 95367431640625, 476837158203125, 2384185791015625, 11920928955078125, - #| 59604644775390625, 298023223876953125, - #|] - #|fn double_computePow5(i : Int) -> Pow5Pair { - #| let base = i / gPOW5_TABLE_SIZE - #| let base2 = base * gPOW5_TABLE_SIZE - #| let offset = i - base2 - #| let mul0 = gDOUBLE_POW5_SPLIT2[base * 2] - #| let mul1 = gDOUBLE_POW5_SPLIT2[base * 2 + 1] - #| if offset == 0 { - #| return Pow5Pair(mul0, mul1) - #| } - #| let m : UInt64 = gDOUBLE_POW5_TABLE[offset] - #| let Umul128(low1, high1) = umul128(m, mul1) - #| let Umul128(low0, high0) = umul128(m, mul0) - #| let sum : UInt64 = high0 + low1 - #| let mut high1 = high1 - #| if sum < high0 { - #| high1 = high1 + 1UL - #| } - #| let delta : Int = pow5bits(i) - pow5bits(base2) - #| let a : UInt64 = shiftright128(low0, sum, delta) + - #| ((gPOW5_OFFSETS[i / 16] >> ((i % 16) << 1)) & 3).to_uint64() - #| let b : UInt64 = shiftright128(sum, high1, delta) - #| Pow5Pair(a, b) - #|} - #|fn double_computeInvPow5(i : Int) -> Pow5Pair { - #| let base = (i + gPOW5_TABLE_SIZE - 1) / gPOW5_TABLE_SIZE - #| let base2 = base * gPOW5_TABLE_SIZE - #| let offset = base2 - i - #| let mul0 = gDOUBLE_POW5_INV_SPLIT2[base * 2] - #| let mul1 = gDOUBLE_POW5_INV_SPLIT2[base * 2 + 1] - #| if offset == 0 { - #| return Pow5Pair(mul0, mul1) - #| } - #| let m = gDOUBLE_POW5_TABLE[offset] - #| let Umul128(low1, high1) = umul128(m, mul1) - #| let Umul128(low0, high0) = umul128(m, mul0) - #| let sum = high0 + low1 - #| let mut high1 = high1 - #| if sum < high0 { - #| high1 = high1 + 1UL - #| } - #| let delta : Int = pow5bits(base2) - pow5bits(i) - #| let a : UInt64 = shiftright128(low0, sum, delta) + - #| 1UL + - #| ((gPOW5_INV_OFFSETS[i / 16] >> ((i % 16) << 1)) & 3).to_uint64() - #| let b : UInt64 = shiftright128(sum, high1, delta) - #| Pow5Pair(a, b) - #|} - #|let gDOUBLE_MANTISSA_BITS : Int = 52 - #|let gDOUBLE_EXPONENT_BITS : Int = 11 - #|let gDOUBLE_BIAS : Int = 1023 - #|let gDOUBLE_POW5_INV_BITCOUNT : Int = 125 - #|let gDOUBLE_POW5_BITCOUNT : Int = 125 - #|fn decimal_length17(v : UInt64) -> Int { - #| if v >= 10000000000000000 { - #| return 17 - #| } - #| if v >= 1000000000000000 { - #| return 16 - #| } - #| if v >= 100000000000000 { - #| return 15 - #| } - #| if v >= 10000000000000 { - #| return 14 - #| } - #| if v >= 1000000000000 { - #| return 13 - #| } - #| if v >= 100000000000 { - #| return 12 - #| } - #| if v >= 10000000000 { - #| return 11 - #| } - #| if v >= 1000000000 { - #| return 10 - #| } - #| if v >= 100000000 { - #| return 9 - #| } - #| if v >= 10000000 { - #| return 8 - #| } - #| if v >= 1000000 { - #| return 7 - #| } - #| if v >= 100000 { - #| return 6 - #| } - #| if v >= 10000 { - #| return 5 - #| } - #| if v >= 1000 { - #| return 4 - #| } - #| if v >= 100 { - #| return 3 - #| } - #| if v >= 10 { - #| return 2 - #| } - #| return 1 - #|} - #|priv struct FloatingDecimal64 { - #| mantissa : UInt64 - #| exponent : Int - #|} - #|fn d2d(ieeeMantissa : UInt64, ieeeExponent : UInt) -> FloatingDecimal64 { - #| let mut e2 : Int = 0 - #| let mut m2 : UInt64 = 0 - #| if ieeeExponent == 0 { - #| e2 = 1 - gDOUBLE_BIAS - gDOUBLE_MANTISSA_BITS - 2 - #| m2 = ieeeMantissa - #| } else { - #| e2 = ieeeExponent.reinterpret_as_int() - - #| gDOUBLE_BIAS - - #| gDOUBLE_MANTISSA_BITS - - #| 2 - #| m2 = (1UL << gDOUBLE_MANTISSA_BITS) | ieeeMantissa - #| } - #| let even = (m2 & 1UL) == 0UL - #| let mv = 4UL * - #| m2 - #| let mmShift = ieeeMantissa != 0UL || ieeeExponent <= 1 - #| let mut vr = 0UL - #| let mut vp = 0UL - #| let mut vm = 0UL - #| let mut e10 : Int = 0 - #| let mut vmIsTrailingZeros = false - #| let mut vrIsTrailingZeros = false - #| if e2 >= 0 { - #| let q : Int = log10Pow2(e2) - (e2 > 3).to_int() - #| e10 = q - #| let k = gDOUBLE_POW5_INV_BITCOUNT + pow5bits(q) - 1 - #| let i = -e2 + q + k - #| let pow5 : Pow5Pair = double_computeInvPow5(q) - #| let MulShiftAll64Result(vrOut, vpOut, vmOut) = mulShiftAll64( - #| m2, pow5, i, mmShift, - #| ) - #| vr = vrOut - #| vp = vpOut - #| vm = vmOut - #| if q <= 21 { - #| let mvMod5 : Int = mv.to_int() - 5 * (mv / 5UL).to_int() - #| if mvMod5 == 0 { - #| vrIsTrailingZeros = multipleOfPowerOf5(mv, q) - #| } else if even { - #| vmIsTrailingZeros = multipleOfPowerOf5( - #| mv - 1UL - mmShift.to_uint64(), - #| q, - #| ) - #| } else { - #| vp = vp - multipleOfPowerOf5(mv + 2UL, q).to_uint64() - #| } - #| } - #| } else { - #| let q : Int = log10Pow5(-e2) - (-e2 > 1).to_int() - #| e10 = q + e2 - #| let i : Int = -e2 - q - #| let k = pow5bits(i) - gDOUBLE_POW5_BITCOUNT - #| let j = q - k - #| let pow5 : Pow5Pair = double_computePow5(i) - #| let MulShiftAll64Result(vrOut, vpOut, vmOut) = mulShiftAll64( - #| m2, pow5, j, mmShift, - #| ) - #| vr = vrOut - #| vp = vpOut - #| vm = vmOut - #| if q <= 1 { - #| vrIsTrailingZeros = true - #| if even { - #| vmIsTrailingZeros = mmShift.to_int() == 1 - #| } else { - #| vp = vp - 1 - #| } - #| } else if q < 63 { - #| vrIsTrailingZeros = multipleOfPowerOf2(mv, q) - #| } - #| } - #| let mut removed : Int = 0 - #| let mut lastRemovedDigit : Int = 0 - #| let mut output : UInt64 = 0UL - #| if vmIsTrailingZeros || vrIsTrailingZeros { - #| while true { - #| let vpDiv10 = vp / 10 - #| let vmDiv10 = vm / 10 - #| if vpDiv10 <= vmDiv10 { - #| break - #| } - #| let vmMod10 : Int = vm.to_int() - 10 * vmDiv10.to_int() - #| let vrDiv10 = vr / 10 - #| let vrMod10 : Int = vr.to_int() - 10 * vrDiv10.to_int() - #| vmIsTrailingZeros = vmIsTrailingZeros && vmMod10 == 0 - #| vrIsTrailingZeros = vrIsTrailingZeros && lastRemovedDigit == 0 - #| lastRemovedDigit = vrMod10 - #| vr = vrDiv10 - #| vp = vpDiv10 - #| vm = vmDiv10 - #| removed = removed + 1 - #| } - #| if vmIsTrailingZeros { - #| while true { - #| let vmDiv10 = vm / 10 - #| let vmMod10 : Int = vm.to_int() - 10 * vmDiv10.to_int() - #| if vmMod10 != 0 { - #| break - #| } - #| let vpDiv10 = vp / 10 - #| let vrDiv10 = vr / 10 - #| let vrMod10 : Int = vr.to_int() - 10 * vrDiv10.to_int() - #| vrIsTrailingZeros = vrIsTrailingZeros && lastRemovedDigit == 0 - #| lastRemovedDigit = vrMod10 - #| vr = vrDiv10 - #| vp = vpDiv10 - #| vm = vmDiv10 - #| removed = removed + 1 - #| } - #| } - #| if vrIsTrailingZeros && lastRemovedDigit == 5 && vr % 2 == 0 { - #| lastRemovedDigit = 4 - #| } - #| output = vr + - #| ((vr == vm && (!even || !vmIsTrailingZeros)) || lastRemovedDigit >= 5) - #| .to_int64() - #| .reinterpret_as_uint64() - #| } else { - #| let mut roundUp = false - #| let vpDiv100 = vp / 100 - #| let vmDiv100 = vm / 100 - #| if vpDiv100 > vmDiv100 { - #| let vrDiv100 = vr / 100 - #| let vrMod100 : Int = vr.to_int() - 100 * vrDiv100.to_int() - #| roundUp = vrMod100 >= 50 - #| vr = vrDiv100 - #| vp = vpDiv100 - #| vm = vmDiv100 - #| removed = removed + 2 - #| } - #| while true { - #| let vpDiv10 = vp / 10 - #| let vmDiv10 = vm / 10 - #| if vpDiv10 <= vmDiv10 { - #| break - #| } - #| let vrDiv10 = vr / 10 - #| let vrMod10 : Int = vr.to_int() - 10 * vrDiv10.to_int() - #| roundUp = vrMod10 >= 5 - #| vr = vrDiv10 - #| vp = vpDiv10 - #| vm = vmDiv10 - #| removed = removed + 1 - #| } - #| output = vr + (vr == vm || roundUp).to_uint64() - #| } - #| let exp : Int = e10 + removed - #| let fd : FloatingDecimal64 = { mantissa: output, exponent: exp } - #| fd - #|} - #|fn to_chars(v : FloatingDecimal64, sign : Bool) -> String { - #| let result = FixedArray::make(25, Byte::default()) - #| let mut index : Int = 0 - #| if sign { - #| result[index] = b'-' - #| index += 1 - #| } - #| let mut output = v.mantissa - #| let olength = decimal_length17(output) - #| let mut exp : Int = v.exponent + olength - 1 - #| let scientificNotation = !(exp >= -6 && exp < 21) - #| if scientificNotation { - #| for i in 0..<(olength - 1) { - #| let c = output % 10 - #| output /= 10 - #| result[index + olength - i] = (48 + c.to_int()).to_byte() - #| } - #| result[index] = (48 + output.to_int() % 10).to_byte() - #| if olength > 1 { - #| result[index + 1] = b'.' - #| } else { - #| index -= 1 - #| } - #| index += olength + 1 - #| result[index] = b'e' - #| index += 1 - #| if exp < 0 { - #| result[index] = b'-' - #| index += 1 - #| exp = -exp - #| } else { - #| result[index] = b'+' - #| index += 1 - #| } - #| if exp >= 100 { - #| let a = exp / 100 - #| let b = exp / 10 % 10 - #| let c = exp % 10 - #| result[index + 0] = (48 + a).to_byte() - #| result[index + 1] = (48 + b).to_byte() - #| result[index + 2] = (48 + c).to_byte() - #| index += 3 - #| } else if exp >= 10 { - #| let a = exp / 10 - #| let b = exp % 10 - #| result[index + 0] = (48 + a).to_byte() - #| result[index + 1] = (48 + b).to_byte() - #| index += 2 - #| } else { - #| result[index] = (48 + exp).to_byte() - #| index += 1 - #| } - #| string_from_bytes(result, 0, index) - #| } else { - #| if exp < 0 { - #| result[index] = b'0' - #| index += 1 - #| result[index] = b'.' - #| index += 1 - #| for i = -1; i > exp; i = i - 1 { - #| result[index] = b'0' - #| index += 1 - #| } - #| let current = index - #| for i in 0..= olength { - #| for i in 0.. FloatingDecimal64? { - #| let m2 : UInt64 = (1UL << gDOUBLE_MANTISSA_BITS) | ieeeMantissa - #| let e2 : Int = ieeeExponent - gDOUBLE_BIAS - gDOUBLE_MANTISSA_BITS - #| if e2 > 0 { - #| return None - #| } - #| if e2 < -52 { - #| return None - #| } - #| let mask : UInt64 = (1UL << -e2) - 1UL - #| let fraction : UInt64 = m2 & mask - #| if fraction != 0UL { - #| return None - #| } - #| Some({ mantissa: m2 >> -e2, exponent: 0 }) - #|} - #|pub fn ryu_to_string(val : Double) -> String { - #| if val == 0.0 { - #| return "0" - #| } - #| let bits : UInt64 = val.reinterpret_as_uint64() - #| let ieeeSign = ( - #| (bits >> (gDOUBLE_MANTISSA_BITS + gDOUBLE_EXPONENT_BITS)) & 1UL - #| ) != - #| 0UL - #| let ieeeMantissa : UInt64 = bits & ((1UL << gDOUBLE_MANTISSA_BITS) - 1UL) - #| let ieeeExponent : Int = ((bits >> gDOUBLE_MANTISSA_BITS) & - #| ((1UL << gDOUBLE_EXPONENT_BITS) - 1UL)).to_int() - #| if ieeeExponent == (1 << gDOUBLE_EXPONENT_BITS) - 1 || - #| (ieeeExponent == 0 && ieeeMantissa == 0UL) { - #| return copy_special_str(ieeeSign, ieeeExponent != 0, ieeeMantissa != 0UL) - #| } - #| let mut v : FloatingDecimal64 = { mantissa: 0UL, exponent: 0 } - #| let small = d2d_small_int(ieeeMantissa, ieeeExponent) - #| match small { - #| Some(f) => { - #| let mut x = f - #| while true { - #| let q : UInt64 = x.mantissa / 10 - #| let r = x.mantissa - 10UL * q - #| if r != 0 { - #| break - #| } - #| x = { mantissa: q, exponent: x.exponent + 1 } - #| } - #| v = x - #| } - #| None => v = d2d(ieeeMantissa, ieeeExponent.reinterpret_as_uint()) - #| } - #| to_chars(v, ieeeSign) - #|} - #|test "double/ryu.mbt:205" { - #| let m = 123456789UL - #| let mul0 = 987654321UL - #| let Umul128(_, high0) = umul128(m, mul0) - #| let low1 = 111111111UL - #| let high1 = 222222222UL - #| let sum = high0 + low1 - #| let mut high1 = high1 - #| if sum < high0 { - #| high1 = high1 + 1 - #| } - #| inspect(high1, content="222222222") - #|} - #|test "double/ryu.mbt:230" { - #| let m = 123456789UL - #| let mul0 = 987654321UL - #| let Umul128(_, high0) = umul128(m, mul0) - #| let low1 = 111111111UL - #| let high1 = 222222222UL - #| let sum = high0 + low1 - #| let mut high1 = high1 - #| if sum < high0 { - #| high1 = high1 + 1UL - #| } - #| assert_eq(high1, 222222222UL) - #|} - #|test "double/ryu.mbt:252" { - #| inspect(gDOUBLE_POW5_BITCOUNT, content="125") - #|} - ), - }, + "decode.mbt": ( + #|pub suberror Malformed { + #| Malformed(BytesView) + #|} + #|pub fn decode(bytes : BytesView) -> String raise Malformed { + #| let t : FixedArray[Byte] = FixedArray::make(bytes.length() * 2, 0) + #| let tlen = loop (0, bytes) { + #| (tlen, []) => tlen + #| (tlen, [0..=0x7F as b, .. rest]) => { + #| t.unsafe_set(tlen, b) + #| continue (tlen + 2, rest) + #| } + #| (_, _ as bytes) => raise Malformed(bytes) + #| } + #| t.unsafe_reinterpret_as_bytes().to_unchecked_string(offset=0, length=tlen) + #|} + #|pub fn decode_lossy(bytes : BytesView) -> String { + #| let t : FixedArray[Byte] = FixedArray::make(bytes.length() * 2, 0) + #| let tlen = loop (0, bytes) { + #| (tlen, []) => tlen + #| (tlen, [0..=0x7F as b, .. rest]) => { + #| t.unsafe_set(tlen, b) + #| continue (tlen + 2, rest) + #| } + #| (tlen, [_, .. rest]) => { + #| t.unsafe_set(tlen, 0xFD) + #| t.unsafe_set(tlen + 1, 0xFF) + #| continue (tlen + 2, rest) + #| } + #| } + #| t.unsafe_reinterpret_as_bytes().to_unchecked_string(offset=0, length=tlen) + #|} + ), + "encode.mbt": ( + #|pub fn encode(str : StringView) -> Bytes { + #| let length = str.length() + #| let arr = FixedArray::make(length, b'\x00') + #| for i in 0.. 0x7F { + #| panic() + #| } + #| arr[i] = code_unit.to_byte() + #| } + #| arr.unsafe_reinterpret_as_bytes() + #|} + ) + } +) + +///| +let moonbitlang_core_encoding_base64_module : RuntimePackage = RuntimePackage::new( + "moonbitlang/core/encoding/base64", + deps={ }, + files={ + "decode.mbt": ( + #|pub suberror Malformed { + #| Malformed(StringView) + #|} + #|const WRITESPACE = -3 + #|const PADDING = -2 + #|const INVALID_CHAR = -1 + #|fn base64_value(code_unit : Int) -> Int { + #| match code_unit { + #| 'A'..='Z' => code_unit - 'A' + #| 'a'..='z' => code_unit - 'a' + 26 + #| '0'..='9' => code_unit - '0' + 52 + #| '+' => 62 + #| '/' => 63 + #| ' ' | '\n' | '\r' | '\t' => WRITESPACE + #| '=' => PADDING + #| _ => INVALID_CHAR + #| } + #|} + #|pub fn decode( + #| text : StringView, + #| ignore_whitespace? : Bool = false, + #|) -> Bytes raise Malformed { + #| let buffer = @buffer.new(size_hint=text.length() / 4 * 3) + #| let quartet = FixedArray::make(4, 0) + #| let mut count = 0 + #| for i in 0.. + #| if ignore_whitespace { + #| continue + #| } else { + #| raise Malformed(text) + #| } + #| PADDING => + #| if count < 2 { + #| raise Malformed(text) + #| } else { + #| quartet[count] = PADDING + #| count += 1 + #| if count == 4 { + #| count = 0 + #| if quartet[2] == PADDING { + #| let b0 = ((quartet[0] << 2) | (quartet[1] >> 4)).to_byte() + #| buffer.write_byte(b0) + #| guard (quartet[1] & 0x0F) == 0 else { raise Malformed(text) } + #| } else { + #| let b0 = ((quartet[0] << 2) | (quartet[1] >> 4)).to_byte() + #| let b1 = (((quartet[1] & 0x0F) << 4) | (quartet[2] >> 2)).to_byte() + #| guard (quartet[2] & 0x03) == 0 else { raise Malformed(text) } + #| buffer.write_byte(b0) + #| buffer.write_byte(b1) + #| } + #| if ignore_whitespace { + #| for j in (i + 1).. raise Malformed(text) + #| value => { + #| quartet[count] = value + #| count += 1 + #| if count == 4 { + #| count = 0 + #| guard quartet[2] != PADDING else { raise Malformed(text) } + #| let b0 = ((quartet[0] << 2) | (quartet[1] >> 4)).to_byte() + #| let b1 = (((quartet[1] & 0x0F) << 4) | (quartet[2] >> 2)).to_byte() + #| let b2 = (((quartet[2] & 0x03) << 6) | quartet[3]).to_byte() + #| buffer.write_byte(b0) + #| buffer.write_byte(b1) + #| buffer.write_byte(b2) + #| } + #| } + #| } + #| } + #| match count { + #| 1 => raise Malformed(text) + #| 2 => { + #| let b0 = ((quartet[0] << 2) | (quartet[1] >> 4)).to_byte() + #| guard (quartet[1] & 0x0F) == 0 else { raise Malformed(text) } + #| buffer.write_byte(b0) + #| } + #| 3 => { + #| guard quartet[2] != PADDING else { raise Malformed(text) } + #| let b0 = ((quartet[0] << 2) | (quartet[1] >> 4)).to_byte() + #| let b1 = (((quartet[1] & 0x0F) << 4) | (quartet[2] >> 2)).to_byte() + #| guard (quartet[2] & 0x03) == 0 else { raise Malformed(text) } + #| buffer.write_byte(b0) + #| buffer.write_byte(b1) + #| } + #| _ => () + #| } + #| buffer.to_bytes() + #|} + #|pub fn decode_lossy( + #| text : StringView, + #| ignore_whitespace? : Bool = false, + #|) -> Bytes { + #| let buffer = @buffer.new(size_hint=text.length() / 4 * 3) + #| let quartet = FixedArray::make(4, 0) + #| let mut count = 0 + #| for i in 0.. if !ignore_whitespace { break } + #| PADDING => break + #| INVALID_CHAR => () + #| value => { + #| quartet[count] = value + #| count += 1 + #| if count == 4 { + #| count = 0 + #| let b0 = ((quartet[0] << 2) | (quartet[1] >> 4)).to_byte() + #| let b1 = (((quartet[1] & 0x0F) << 4) | (quartet[2] >> 2)).to_byte() + #| let b2 = (((quartet[2] & 0x03) << 6) | quartet[3]).to_byte() + #| buffer.write_byte(b0) + #| buffer.write_byte(b1) + #| buffer.write_byte(b2) + #| } + #| } + #| } + #| } + #| if count == 2 { + #| let b0 = ((quartet[0] << 2) | (quartet[1] >> 4)).to_byte() + #| buffer.write_byte(b0) + #| } else if count == 3 { + #| let b0 = ((quartet[0] << 2) | (quartet[1] >> 4)).to_byte() + #| let b1 = (((quartet[1] & 0x0F) << 4) | (quartet[2] >> 2)).to_byte() + #| buffer.write_byte(b0) + #| buffer.write_byte(b1) + #| } + #| buffer.to_bytes() + #|} + ), + "encode.mbt": ( + #|const BASE64_STD : Bytes = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + #|pub fn encode(bytes : BytesView, padding? : Bool = true) -> String { + #| let full_groups = bytes.length() / 3 + #| let remainder = bytes.length() % 3 + #| let mut size_hint = full_groups * 4 + #| if remainder != 0 { + #| size_hint += if padding is true { 4 } else { remainder + 1 } + #| } + #| let builder = StringBuilder::new(size_hint~) + #| loop bytes { + #| [b0, b1, b2, .. rest] => { + #| let n = (b0.to_int() << 16) | (b1.to_int() << 8) | b2.to_int() + #| builder.write_char(BASE64_STD[(n >> 18) & 0x3F].to_char()) + #| builder.write_char(BASE64_STD[(n >> 12) & 0x3F].to_char()) + #| builder.write_char(BASE64_STD[(n >> 6) & 0x3F].to_char()) + #| builder.write_char(BASE64_STD[n & 0x3F].to_char()) + #| continue rest + #| } + #| [b0, b1] => { + #| let n = (b0.to_int() << 16) | (b1.to_int() << 8) + #| builder.write_char(BASE64_STD[(n >> 18) & 0x3F].to_char()) + #| builder.write_char(BASE64_STD[(n >> 12) & 0x3F].to_char()) + #| builder.write_char(BASE64_STD[(n >> 6) & 0x3F].to_char()) + #| if padding is true { + #| builder.write_char('=') + #| } + #| } + #| [b0] => { + #| let n = b0.to_int() << 16 + #| builder.write_char(BASE64_STD[(n >> 18) & 0x3F].to_char()) + #| builder.write_char(BASE64_STD[(n >> 12) & 0x3F].to_char()) + #| if padding is true { + #| builder.write_string("==") + #| } + #| } + #| [] => () + #| } + #| builder.to_string() + #|} + ) + } ) ///| let moonbitlang_core_encoding_utf16_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/encoding/utf16", - deps={ - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/string": moonbitlang_core_string_module, - "moonbitlang/core/bytes": moonbitlang_core_bytes_module, - }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| "moonbitlang/core/builtin", - #| "moonbitlang/core/string", - #| "moonbitlang/core/bytes" - #| ] - #|} - ), - "decode.mbt": ( - #|pub suberror Malformed BytesView - #|const U_REP = '\u{FFFD}' - #|pub fn decode( - #| bytes : BytesView, - #| ignore_bom? : Bool = false, - #| endianness? : Endian = Little, - #|) -> String raise Malformed { - #| let bytes = if ignore_bom { - #| if endianness is Little && bytes is [.. "\xff\xfe", .. rest] { - #| rest - #| } else if endianness is Big && bytes is [.. "\xfe\xff", .. rest] { - #| rest - #| } else { - #| bytes - #| } - #| } else { - #| bytes - #| } - #| if endianness is Little { - #| loop bytes { - #| [] => () - #| [ - #| u16le(0xD800..=0xDBFF as higher), - #| u16le(0xDC00..=0xDFFF as lower), - #| .. rest, - #| ] as bytes => { - #| if ((higher.reinterpret_as_int() - 0xD800) << 10) + - #| (lower.reinterpret_as_int() - 0xDC00) + - #| 0x10000 > - #| 0x10FFFF { - #| raise Malformed(bytes) - #| } - #| continue rest - #| } - #| [u16le(0xD800..=0xDFFF), ..] as bytes => raise Malformed(bytes) - #| [u16le(_), .. rest] => continue rest - #| _ as bytes => raise Malformed(bytes) - #| } - #| bytes - #| .data() - #| .to_unchecked_string(offset=bytes.start_offset(), length=bytes.length()) - #| } else { - #| let string_bytes = FixedArray::make(bytes.length(), b'\x00') - #| let mut i = 0 - #| loop bytes { - #| [] => () - #| [ - #| u16be(0xD800..=0xDBFF as higher), - #| u16be(0xDC00..=0xDFFF as lower), - #| .. rest, - #| ] as bytes => { - #| if ((higher.reinterpret_as_int() - 0xD800) << 10) + - #| (lower.reinterpret_as_int() - 0xDC00) + - #| 0x10000 > - #| 0x10FFFF { - #| raise Malformed(bytes) - #| } - #| string_bytes[i] = (higher & 0xFF).to_byte() - #| string_bytes[i + 1] = (higher >> 8).to_byte() - #| string_bytes[i + 2] = (lower & 0xFF).to_byte() - #| string_bytes[i + 3] = (lower >> 8).to_byte() - #| i += 4 - #| continue rest - #| } - #| [u16be(0xD800..=0xDFFF), ..] as bytes => raise Malformed(bytes) - #| [u16be(code_unit), .. rest] => { - #| string_bytes[i] = (code_unit & 0xFF).to_byte() - #| string_bytes[i + 1] = (code_unit >> 8).to_byte() - #| i += 2 - #| continue rest - #| } - #| _ as bytes => raise Malformed(bytes) - #| } - #| string_bytes.unsafe_reinterpret_as_bytes().to_unchecked_string() - #| } - #|} - #|pub fn decode_lossy( - #| bytes : BytesView, - #| ignore_bom? : Bool = false, - #| endianness? : Endian = Little, - #|) -> String { - #| let bytes = if ignore_bom { - #| if endianness is Little && bytes is [.. "\xff\xfe", .. rest] { - #| rest - #| } else if endianness is Big && bytes is [.. "\xfe\xff", .. rest] { - #| rest - #| } else { - #| bytes - #| } - #| } else { - #| bytes - #| } - #| let builder = StringBuilder::new(size_hint=bytes.length()) - #| if endianness is Little { - #| loop bytes { - #| [] => () - #| [ - #| u16le(0xD800..=0xDBFF as higher), - #| u16le(0xDC00..=0xDFFF as lower), - #| .. rest, - #| ] => { - #| let ch = ((higher.reinterpret_as_int() - 0xD800) << 10) + - #| (lower.reinterpret_as_int() - 0xDC00) + - #| 0x10000 - #| if ch > 0x10FFFF { - #| builder.write_char(U_REP) - #| } else { - #| builder.write_char(ch.unsafe_to_char()) - #| } - #| continue rest - #| } - #| [u16le(0xD800..=0xDFFF), .. rest] => { - #| builder.write_char(U_REP) - #| continue rest - #| } - #| [u16le(ch), .. rest] => { - #| builder.write_char(ch.reinterpret_as_int().unsafe_to_char()) - #| continue rest - #| } - #| _ => builder.write_char(U_REP) - #| } - #| } else { - #| loop bytes { - #| [] => () - #| [ - #| u16be(0xD800..=0xDBFF as higher), - #| u16be(0xDC00..=0xDFFF as lower), - #| .. rest, - #| ] => { - #| let ch = ((higher.reinterpret_as_int() - 0xD800) << 10) + - #| (lower.reinterpret_as_int() - 0xDC00) + - #| 0x10000 - #| if ch > 0x10FFFF { - #| builder.write_char(U_REP) - #| } else { - #| builder.write_char(ch.unsafe_to_char()) - #| } - #| continue rest - #| } - #| [u16be(0xD800..=0xDFFF), .. rest] => { - #| builder.write_char(U_REP) - #| continue rest - #| } - #| [u16be(ch), .. rest] => { - #| builder.write_char(ch.reinterpret_as_int().unsafe_to_char()) - #| continue rest - #| } - #| _ => builder.write_char(U_REP) - #| } - #| } - #| builder.to_string() - #|} - ), - "encode.mbt": ( - #|pub fn encode( - #| str : StringView, - #| bom? : Bool = false, - #| endianness? : Endian = Little, - #|) -> Bytes { - #| if endianness is Little { - #| if bom is true { - #| let arr = FixedArray::make(str.length() * 2 + 2, b'\x00') - #| arr[0] = 0xFF - #| arr[1] = 0xFE - #| arr.blit_from_string(2, str.data(), str.start_offset(), str.length()) - #| arr.unsafe_reinterpret_as_bytes() - #| } else { - #| let arr = FixedArray::make(str.length() * 2, b'\x00') - #| arr.blit_from_string(0, str.data(), str.start_offset(), str.length()) - #| arr.unsafe_reinterpret_as_bytes() - #| } - #| } else if bom is true { - #| let arr = FixedArray::make(str.length() * 2 + 2, b'\x00') - #| arr[0] = 0xFE - #| arr[1] = 0xFF - #| for i in 0..> 8).to_byte() - #| arr[2 + i * 2 + 1] = (code_unit & 0xFF).to_byte() - #| } - #| arr.unsafe_reinterpret_as_bytes() - #| } else { - #| let arr = FixedArray::make(str.length() * 2, b'\x00') - #| for i in 0..> 8).to_byte() - #| arr[i * 2 + 1] = (code_unit & 0xFF).to_byte() - #| } - #| arr.unsafe_reinterpret_as_bytes() - #| } - #|} - ), - "types.mbt": ( - #|pub(all) enum Endian { - #| Little - #| Big - #|} - ), - }, + "decode.mbt": ( + #|pub suberror Malformed { + #| Malformed(BytesView) + #|} + #|const U_REP = '\u{FFFD}' + #|pub fn decode( + #| bytes : BytesView, + #| ignore_bom? : Bool = false, + #| endianness? : Endian = Little, + #|) -> String raise Malformed { + #| let bytes = if ignore_bom { + #| if endianness is Little && bytes is [.. "\xff\xfe", .. rest] { + #| rest + #| } else if endianness is Big && bytes is [.. "\xfe\xff", .. rest] { + #| rest + #| } else { + #| bytes + #| } + #| } else { + #| bytes + #| } + #| if endianness is Little { + #| loop bytes { + #| [] => () + #| [ + #| u16le(0xD800..=0xDBFF as higher), + #| u16le(0xDC00..=0xDFFF as lower), + #| .. rest, + #| ] as bytes => { + #| if ((higher.reinterpret_as_int() - 0xD800) << 10) + + #| (lower.reinterpret_as_int() - 0xDC00) + + #| 0x10000 > + #| 0x10FFFF { + #| raise Malformed(bytes) + #| } + #| continue rest + #| } + #| [u16le(0xD800..=0xDFFF), ..] as bytes => raise Malformed(bytes) + #| [u16le(_), .. rest] => continue rest + #| _ as bytes => raise Malformed(bytes) + #| } + #| bytes + #| .data() + #| .to_unchecked_string(offset=bytes.start_offset(), length=bytes.length()) + #| } else { + #| let string_bytes = FixedArray::make(bytes.length(), b'\x00') + #| let mut i = 0 + #| loop bytes { + #| [] => () + #| [ + #| u16be(0xD800..=0xDBFF as higher), + #| u16be(0xDC00..=0xDFFF as lower), + #| .. rest, + #| ] as bytes => { + #| if ((higher.reinterpret_as_int() - 0xD800) << 10) + + #| (lower.reinterpret_as_int() - 0xDC00) + + #| 0x10000 > + #| 0x10FFFF { + #| raise Malformed(bytes) + #| } + #| string_bytes[i] = (higher & 0xFF).to_byte() + #| string_bytes[i + 1] = (higher >> 8).to_byte() + #| string_bytes[i + 2] = (lower & 0xFF).to_byte() + #| string_bytes[i + 3] = (lower >> 8).to_byte() + #| i += 4 + #| continue rest + #| } + #| [u16be(0xD800..=0xDFFF), ..] as bytes => raise Malformed(bytes) + #| [u16be(code_unit), .. rest] => { + #| string_bytes[i] = (code_unit & 0xFF).to_byte() + #| string_bytes[i + 1] = (code_unit >> 8).to_byte() + #| i += 2 + #| continue rest + #| } + #| _ as bytes => raise Malformed(bytes) + #| } + #| string_bytes.unsafe_reinterpret_as_bytes().to_unchecked_string() + #| } + #|} + #|pub fn decode_lossy( + #| bytes : BytesView, + #| ignore_bom? : Bool = false, + #| endianness? : Endian = Little, + #|) -> String { + #| let bytes = if ignore_bom { + #| if endianness is Little && bytes is [.. "\xff\xfe", .. rest] { + #| rest + #| } else if endianness is Big && bytes is [.. "\xfe\xff", .. rest] { + #| rest + #| } else { + #| bytes + #| } + #| } else { + #| bytes + #| } + #| let builder = StringBuilder::new(size_hint=bytes.length()) + #| if endianness is Little { + #| loop bytes { + #| [] => () + #| [ + #| u16le(0xD800..=0xDBFF as higher), + #| u16le(0xDC00..=0xDFFF as lower), + #| .. rest, + #| ] => { + #| let ch = ((higher.reinterpret_as_int() - 0xD800) << 10) + + #| (lower.reinterpret_as_int() - 0xDC00) + + #| 0x10000 + #| if ch > 0x10FFFF { + #| builder.write_char(U_REP) + #| } else { + #| builder.write_char(ch.unsafe_to_char()) + #| } + #| continue rest + #| } + #| [u16le(0xD800..=0xDFFF), .. rest] => { + #| builder.write_char(U_REP) + #| continue rest + #| } + #| [u16le(ch), .. rest] => { + #| builder.write_char(ch.reinterpret_as_int().unsafe_to_char()) + #| continue rest + #| } + #| _ => builder.write_char(U_REP) + #| } + #| } else { + #| loop bytes { + #| [] => () + #| [ + #| u16be(0xD800..=0xDBFF as higher), + #| u16be(0xDC00..=0xDFFF as lower), + #| .. rest, + #| ] => { + #| let ch = ((higher.reinterpret_as_int() - 0xD800) << 10) + + #| (lower.reinterpret_as_int() - 0xDC00) + + #| 0x10000 + #| if ch > 0x10FFFF { + #| builder.write_char(U_REP) + #| } else { + #| builder.write_char(ch.unsafe_to_char()) + #| } + #| continue rest + #| } + #| [u16be(0xD800..=0xDFFF), .. rest] => { + #| builder.write_char(U_REP) + #| continue rest + #| } + #| [u16be(ch), .. rest] => { + #| builder.write_char(ch.reinterpret_as_int().unsafe_to_char()) + #| continue rest + #| } + #| _ => builder.write_char(U_REP) + #| } + #| } + #| builder.to_string() + #|} + ), + "encode.mbt": ( + #|pub fn encode( + #| str : StringView, + #| bom? : Bool = false, + #| endianness? : Endian = Little, + #|) -> Bytes { + #| if endianness is Little { + #| if bom is true { + #| let arr = FixedArray::make(str.length() * 2 + 2, b'\x00') + #| arr[0] = 0xFF + #| arr[1] = 0xFE + #| arr.blit_from_string(2, str.data(), str.start_offset(), str.length()) + #| arr.unsafe_reinterpret_as_bytes() + #| } else { + #| let arr = FixedArray::make(str.length() * 2, b'\x00') + #| arr.blit_from_string(0, str.data(), str.start_offset(), str.length()) + #| arr.unsafe_reinterpret_as_bytes() + #| } + #| } else if bom is true { + #| let arr = FixedArray::make(str.length() * 2 + 2, b'\x00') + #| arr[0] = 0xFE + #| arr[1] = 0xFF + #| for i in 0..> 8).to_byte() + #| arr[2 + i * 2 + 1] = (code_unit & 0xFF).to_byte() + #| } + #| arr.unsafe_reinterpret_as_bytes() + #| } else { + #| let arr = FixedArray::make(str.length() * 2, b'\x00') + #| for i in 0..> 8).to_byte() + #| arr[i * 2 + 1] = (code_unit & 0xFF).to_byte() + #| } + #| arr.unsafe_reinterpret_as_bytes() + #| } + #|} + ), + "types.mbt": ( + #|pub(all) enum Endian { + #| Little + #| Big + #|} + ) + } ) ///| let moonbitlang_core_encoding_utf8_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/encoding/utf8", - deps={ - "moonbitlang/core/buffer": moonbitlang_core_buffer_module, - "moonbitlang/core/string": moonbitlang_core_string_module, - "moonbitlang/core/bytes": moonbitlang_core_bytes_module, - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| "moonbitlang/core/buffer", - #| "moonbitlang/core/string", - #| "moonbitlang/core/bytes", - #| "moonbitlang/core/builtin" - #| ] - #|} - ), - "decode.mbt": ( - #|pub suberror Malformed BytesView - #|pub fn decode( - #| bytes : BytesView, - #| ignore_bom? : Bool = false, - #|) -> String raise Malformed { - #| let bytes = if ignore_bom && bytes is [.. "\xef\xbb\xbf", .. rest] { - #| rest - #| } else { - #| bytes - #| } - #| let t : FixedArray[Byte] = FixedArray::make(bytes.length() * 2, 0) - #| let tlen = loop (0, bytes) { - #| (tlen, []) => tlen - #| ( - #| tlen, - #| [ - #| _..=0x7F as b0, - #| _..=0x7F as b1, - #| _..=0x7F as b2, - #| _..=0x7F as b3, - #| _..=0x7F as b4, - #| _..=0x7F as b5, - #| _..=0x7F as b6, - #| _..=0x7F as b7, - #| .. rest, - #| ], - #| ) => { - #| t.unsafe_set(tlen, b0) - #| t.unsafe_set(tlen + 2, b1) - #| t.unsafe_set(tlen + 4, b2) - #| t.unsafe_set(tlen + 6, b3) - #| t.unsafe_set(tlen + 8, b4) - #| t.unsafe_set(tlen + 10, b5) - #| t.unsafe_set(tlen + 12, b6) - #| t.unsafe_set(tlen + 14, b7) - #| continue (tlen + 16, rest) - #| } - #| (tlen, [0..=0x7F as b, .. rest]) => { - #| t.unsafe_set(tlen, b) - #| continue (tlen + 2, rest) - #| } - #| (tlen, [0xC2..=0xDF as b0, 0x80..=0xBF as b1, .. rest]) => { - #| let ch = ((b0.to_int() & 0x1F) << 6) | (b1.to_int() & 0x3F) - #| t.unsafe_set(tlen, ch.to_byte()) - #| t.unsafe_set(tlen + 1, (ch >> 8).to_byte()) - #| continue (tlen + 2, rest) - #| } - #| ( - #| tlen, - #| [0xE0 as b0, 0xA0..=0xBF as b1, 0x80..=0xBF as b2, .. rest] - #| | [0xE1..=0xEC as b0, 0x80..=0xBF as b1, 0x80..=0xBF as b2, .. rest] - #| | [0xED as b0, 0x80..=0x9F as b1, 0x80..=0xBF as b2, .. rest] - #| | [0xEE..=0xEF as b0, 0x80..=0xBF as b1, 0x80..=0xBF as b2, .. rest], - #| ) => { - #| let ch = ((b0.to_int() & 0x0F) << 12) | - #| ((b1.to_int() & 0x3F) << 6) | - #| (b2.to_int() & 0x3F) - #| t.unsafe_set(tlen, ch.to_byte()) - #| t.unsafe_set(tlen + 1, (ch >> 8).to_byte()) - #| continue (tlen + 2, rest) - #| } - #| ( - #| tlen, - #| [ - #| 0xF0 as b0, - #| 0x90..=0xBF as b1, - #| 0x80..=0xBF as b2, - #| 0x80..=0xBF as b3, - #| .. rest, - #| ] - #| | [ - #| 0xF1..=0xF3 as b0, - #| 0x80..=0xBF as b1, - #| 0x80..=0xBF as b2, - #| 0x80..=0xBF as b3, - #| .. rest, - #| ] - #| | [ - #| 0xF4 as b0, - #| 0x80..=0x8F as b1, - #| 0x80..=0xBF as b2, - #| 0x80..=0xBF as b3, - #| .. rest, - #| ], - #| ) => { - #| let ch = ((b0.to_int() & 0x07) << 18) | - #| ((b1.to_int() & 0x3F) << 12) | - #| ((b2.to_int() & 0x3F) << 6) | - #| (b3.to_int() & 0x3F) - #| let chm = ch - 0x10000 - #| let ch1 = (chm >> 10) + 0xD800 - #| let ch2 = (chm & 0x3FF) + 0xDC00 - #| t.unsafe_set(tlen, ch1.to_byte()) - #| t.unsafe_set(tlen + 1, (ch1 >> 8).to_byte()) - #| t.unsafe_set(tlen + 2, ch2.to_byte()) - #| t.unsafe_set(tlen + 3, (ch2 >> 8).to_byte()) - #| continue (tlen + 4, rest) - #| } - #| (_, _ as bytes) => raise Malformed(bytes) - #| } - #| t.unsafe_reinterpret_as_bytes().to_unchecked_string(offset=0, length=tlen) - #|} - #|pub fn decode_lossy(bytes : BytesView, ignore_bom? : Bool = false) -> String { - #| let bytes = if ignore_bom && bytes is [.. "\xef\xbb\xbf", .. rest] { - #| rest - #| } else { - #| bytes - #| } - #| let t : FixedArray[Byte] = FixedArray::make(bytes.length() * 2, 0) - #| let tlen = loop (0, bytes) { - #| (tlen, []) => tlen - #| ( - #| tlen, - #| [ - #| _..=0x7F as b0, - #| _..=0x7F as b1, - #| _..=0x7F as b2, - #| _..=0x7F as b3, - #| _..=0x7F as b4, - #| _..=0x7F as b5, - #| _..=0x7F as b6, - #| _..=0x7F as b7, - #| .. rest, - #| ], - #| ) => { - #| t.unsafe_set(tlen, b0) - #| t.unsafe_set(tlen + 2, b1) - #| t.unsafe_set(tlen + 4, b2) - #| t.unsafe_set(tlen + 6, b3) - #| t.unsafe_set(tlen + 8, b4) - #| t.unsafe_set(tlen + 10, b5) - #| t.unsafe_set(tlen + 12, b6) - #| t.unsafe_set(tlen + 14, b7) - #| continue (tlen + 16, rest) - #| } - #| (tlen, [0..=0x7F as b, .. rest]) => { - #| t.unsafe_set(tlen, b) - #| continue (tlen + 2, rest) - #| } - #| (tlen, [0xC2..=0xDF as b0, 0x80..=0xBF as b1, .. rest]) => { - #| let ch = ((b0.to_int() & 0x1F) << 6) | (b1.to_int() & 0x3F) - #| t.unsafe_set(tlen, ch.to_byte()) - #| t.unsafe_set(tlen + 1, (ch >> 8).to_byte()) - #| continue (tlen + 2, rest) - #| } - #| ( - #| tlen, - #| [0xE0 as b0, 0xA0..=0xBF as b1, 0x80..=0xBF as b2, .. rest] - #| | [0xE1..=0xEC as b0, 0x80..=0xBF as b1, 0x80..=0xBF as b2, .. rest] - #| | [0xED as b0, 0x80..=0x9F as b1, 0x80..=0xBF as b2, .. rest] - #| | [0xEE..=0xEF as b0, 0x80..=0xBF as b1, 0x80..=0xBF as b2, .. rest], - #| ) => { - #| let ch = ((b0.to_int() & 0x0F) << 12) | - #| ((b1.to_int() & 0x3F) << 6) | - #| (b2.to_int() & 0x3F) - #| t.unsafe_set(tlen, ch.to_byte()) - #| t.unsafe_set(tlen + 1, (ch >> 8).to_byte()) - #| continue (tlen + 2, rest) - #| } - #| ( - #| tlen, - #| [ - #| 0xF0 as b0, - #| 0x90..=0xBF as b1, - #| 0x80..=0xBF as b2, - #| 0x80..=0xBF as b3, - #| .. rest, - #| ] - #| | [ - #| 0xF1..=0xF3 as b0, - #| 0x80..=0xBF as b1, - #| 0x80..=0xBF as b2, - #| 0x80..=0xBF as b3, - #| .. rest, - #| ] - #| | [ - #| 0xF4 as b0, - #| 0x80..=0x8F as b1, - #| 0x80..=0xBF as b2, - #| 0x80..=0xBF as b3, - #| .. rest, - #| ], - #| ) => { - #| let ch = ((b0.to_int() & 0x07) << 18) | - #| ((b1.to_int() & 0x3F) << 12) | - #| ((b2.to_int() & 0x3F) << 6) | - #| (b3.to_int() & 0x3F) - #| let chm = ch - 0x10000 - #| let ch1 = (chm >> 10) + 0xD800 - #| let ch2 = (chm & 0x3FF) + 0xDC00 - #| t.unsafe_set(tlen, ch1.to_byte()) - #| t.unsafe_set(tlen + 1, (ch1 >> 8).to_byte()) - #| t.unsafe_set(tlen + 2, ch2.to_byte()) - #| t.unsafe_set(tlen + 3, (ch2 >> 8).to_byte()) - #| continue (tlen + 4, rest) - #| } - #| (tlen, [0xE0, 0xA0..=0xBF, .. rest]) - #| | (tlen, [0xE1..=0xEC, 0x80..=0xBF, .. rest]) - #| | (tlen, [0xED, 0x80..=0x9F, .. rest]) - #| | (tlen, [0xEE..=0xEF, 0x80..=0xBF, .. rest]) => { - #| t.unsafe_set(tlen, 0xFD) - #| t.unsafe_set(tlen + 1, 0xFF) - #| continue (tlen + 2, rest) - #| } - #| (tlen, [0xF0, 0x90..=0xBF, 0x80..=0xBF, .. rest]) - #| | (tlen, [0xF1..=0xF3, 0x80..=0xBF, 0x80..=0xBF, .. rest]) - #| | (tlen, [0xF4, 0x80..=0x8F, 0x80..=0xBF, .. rest]) => { - #| t.unsafe_set(tlen, 0xFD) - #| t.unsafe_set(tlen + 1, 0xFF) - #| continue (tlen + 2, rest) - #| } - #| (tlen, [0xF0, 0x90..=0xBF, .. rest]) - #| | (tlen, [0xF1..=0xF3, 0x80..=0xBF, .. rest]) - #| | (tlen, [0xF4, 0x80..=0x8F, .. rest]) => { - #| t.unsafe_set(tlen, 0xFD) - #| t.unsafe_set(tlen + 1, 0xFF) - #| continue (tlen + 2, rest) - #| } - #| (tlen, [_, .. rest]) => { - #| t.unsafe_set(tlen, 0xFD) - #| t.unsafe_set(tlen + 1, 0xFF) - #| continue (tlen + 2, rest) - #| } - #| } - #| t.unsafe_reinterpret_as_bytes().to_unchecked_string(offset=0, length=tlen) - #|} - ), - "encode.mbt": ( - #|const U_BOM : Char = '\u{FEFF}' - #|pub fn encode(str : StringView, bom? : Bool = false) -> Bytes { - #| let buffer = @buffer.new(size_hint=str.length() * 4) - #| if bom is true { - #| buffer.write_char_utf8(U_BOM) - #| } - #| buffer.write_string_utf8(str) - #| buffer.to_bytes() - #|} - ), - }, + "decode.mbt": ( + #|pub suberror Malformed { + #| Malformed(BytesView) + #|} + #|pub fn decode( + #| bytes : BytesView, + #| ignore_bom? : Bool = false, + #|) -> String raise Malformed { + #| let bytes = if ignore_bom && bytes is [.. "\xef\xbb\xbf", .. rest] { + #| rest + #| } else { + #| bytes + #| } + #| let t : FixedArray[Byte] = FixedArray::make(bytes.length() * 2, 0) + #| let tlen = loop (0, bytes) { + #| (tlen, []) => tlen + #| ( + #| tlen, + #| [ + #| _..=0x7F as b0, + #| _..=0x7F as b1, + #| _..=0x7F as b2, + #| _..=0x7F as b3, + #| _..=0x7F as b4, + #| _..=0x7F as b5, + #| _..=0x7F as b6, + #| _..=0x7F as b7, + #| .. rest, + #| ], + #| ) => { + #| t.unsafe_set(tlen, b0) + #| t.unsafe_set(tlen + 2, b1) + #| t.unsafe_set(tlen + 4, b2) + #| t.unsafe_set(tlen + 6, b3) + #| t.unsafe_set(tlen + 8, b4) + #| t.unsafe_set(tlen + 10, b5) + #| t.unsafe_set(tlen + 12, b6) + #| t.unsafe_set(tlen + 14, b7) + #| continue (tlen + 16, rest) + #| } + #| (tlen, [0..=0x7F as b, .. rest]) => { + #| t.unsafe_set(tlen, b) + #| continue (tlen + 2, rest) + #| } + #| (tlen, [0xC2..=0xDF as b0, 0x80..=0xBF as b1, .. rest]) => { + #| let ch = ((b0.to_int() & 0x1F) << 6) | (b1.to_int() & 0x3F) + #| t.unsafe_set(tlen, ch.to_byte()) + #| t.unsafe_set(tlen + 1, (ch >> 8).to_byte()) + #| continue (tlen + 2, rest) + #| } + #| ( + #| tlen, + #| [0xE0 as b0, 0xA0..=0xBF as b1, 0x80..=0xBF as b2, .. rest] + #| | [0xE1..=0xEC as b0, 0x80..=0xBF as b1, 0x80..=0xBF as b2, .. rest] + #| | [0xED as b0, 0x80..=0x9F as b1, 0x80..=0xBF as b2, .. rest] + #| | [0xEE..=0xEF as b0, 0x80..=0xBF as b1, 0x80..=0xBF as b2, .. rest], + #| ) => { + #| let ch = ((b0.to_int() & 0x0F) << 12) | + #| ((b1.to_int() & 0x3F) << 6) | + #| (b2.to_int() & 0x3F) + #| t.unsafe_set(tlen, ch.to_byte()) + #| t.unsafe_set(tlen + 1, (ch >> 8).to_byte()) + #| continue (tlen + 2, rest) + #| } + #| ( + #| tlen, + #| [ + #| 0xF0 as b0, + #| 0x90..=0xBF as b1, + #| 0x80..=0xBF as b2, + #| 0x80..=0xBF as b3, + #| .. rest, + #| ] + #| | [ + #| 0xF1..=0xF3 as b0, + #| 0x80..=0xBF as b1, + #| 0x80..=0xBF as b2, + #| 0x80..=0xBF as b3, + #| .. rest, + #| ] + #| | [ + #| 0xF4 as b0, + #| 0x80..=0x8F as b1, + #| 0x80..=0xBF as b2, + #| 0x80..=0xBF as b3, + #| .. rest, + #| ], + #| ) => { + #| let ch = ((b0.to_int() & 0x07) << 18) | + #| ((b1.to_int() & 0x3F) << 12) | + #| ((b2.to_int() & 0x3F) << 6) | + #| (b3.to_int() & 0x3F) + #| let chm = ch - 0x10000 + #| let ch1 = (chm >> 10) + 0xD800 + #| let ch2 = (chm & 0x3FF) + 0xDC00 + #| t.unsafe_set(tlen, ch1.to_byte()) + #| t.unsafe_set(tlen + 1, (ch1 >> 8).to_byte()) + #| t.unsafe_set(tlen + 2, ch2.to_byte()) + #| t.unsafe_set(tlen + 3, (ch2 >> 8).to_byte()) + #| continue (tlen + 4, rest) + #| } + #| (_, _ as bytes) => raise Malformed(bytes) + #| } + #| t.unsafe_reinterpret_as_bytes().to_unchecked_string(offset=0, length=tlen) + #|} + #|pub fn decode_lossy(bytes : BytesView, ignore_bom? : Bool = false) -> String { + #| let bytes = if ignore_bom && bytes is [.. "\xef\xbb\xbf", .. rest] { + #| rest + #| } else { + #| bytes + #| } + #| let t : FixedArray[Byte] = FixedArray::make(bytes.length() * 2, 0) + #| let tlen = loop (0, bytes) { + #| (tlen, []) => tlen + #| ( + #| tlen, + #| [ + #| _..=0x7F as b0, + #| _..=0x7F as b1, + #| _..=0x7F as b2, + #| _..=0x7F as b3, + #| _..=0x7F as b4, + #| _..=0x7F as b5, + #| _..=0x7F as b6, + #| _..=0x7F as b7, + #| .. rest, + #| ], + #| ) => { + #| t.unsafe_set(tlen, b0) + #| t.unsafe_set(tlen + 2, b1) + #| t.unsafe_set(tlen + 4, b2) + #| t.unsafe_set(tlen + 6, b3) + #| t.unsafe_set(tlen + 8, b4) + #| t.unsafe_set(tlen + 10, b5) + #| t.unsafe_set(tlen + 12, b6) + #| t.unsafe_set(tlen + 14, b7) + #| continue (tlen + 16, rest) + #| } + #| (tlen, [0..=0x7F as b, .. rest]) => { + #| t.unsafe_set(tlen, b) + #| continue (tlen + 2, rest) + #| } + #| (tlen, [0xC2..=0xDF as b0, 0x80..=0xBF as b1, .. rest]) => { + #| let ch = ((b0.to_int() & 0x1F) << 6) | (b1.to_int() & 0x3F) + #| t.unsafe_set(tlen, ch.to_byte()) + #| t.unsafe_set(tlen + 1, (ch >> 8).to_byte()) + #| continue (tlen + 2, rest) + #| } + #| ( + #| tlen, + #| [0xE0 as b0, 0xA0..=0xBF as b1, 0x80..=0xBF as b2, .. rest] + #| | [0xE1..=0xEC as b0, 0x80..=0xBF as b1, 0x80..=0xBF as b2, .. rest] + #| | [0xED as b0, 0x80..=0x9F as b1, 0x80..=0xBF as b2, .. rest] + #| | [0xEE..=0xEF as b0, 0x80..=0xBF as b1, 0x80..=0xBF as b2, .. rest], + #| ) => { + #| let ch = ((b0.to_int() & 0x0F) << 12) | + #| ((b1.to_int() & 0x3F) << 6) | + #| (b2.to_int() & 0x3F) + #| t.unsafe_set(tlen, ch.to_byte()) + #| t.unsafe_set(tlen + 1, (ch >> 8).to_byte()) + #| continue (tlen + 2, rest) + #| } + #| ( + #| tlen, + #| [ + #| 0xF0 as b0, + #| 0x90..=0xBF as b1, + #| 0x80..=0xBF as b2, + #| 0x80..=0xBF as b3, + #| .. rest, + #| ] + #| | [ + #| 0xF1..=0xF3 as b0, + #| 0x80..=0xBF as b1, + #| 0x80..=0xBF as b2, + #| 0x80..=0xBF as b3, + #| .. rest, + #| ] + #| | [ + #| 0xF4 as b0, + #| 0x80..=0x8F as b1, + #| 0x80..=0xBF as b2, + #| 0x80..=0xBF as b3, + #| .. rest, + #| ], + #| ) => { + #| let ch = ((b0.to_int() & 0x07) << 18) | + #| ((b1.to_int() & 0x3F) << 12) | + #| ((b2.to_int() & 0x3F) << 6) | + #| (b3.to_int() & 0x3F) + #| let chm = ch - 0x10000 + #| let ch1 = (chm >> 10) + 0xD800 + #| let ch2 = (chm & 0x3FF) + 0xDC00 + #| t.unsafe_set(tlen, ch1.to_byte()) + #| t.unsafe_set(tlen + 1, (ch1 >> 8).to_byte()) + #| t.unsafe_set(tlen + 2, ch2.to_byte()) + #| t.unsafe_set(tlen + 3, (ch2 >> 8).to_byte()) + #| continue (tlen + 4, rest) + #| } + #| (tlen, [0xE0, 0xA0..=0xBF, .. rest]) + #| | (tlen, [0xE1..=0xEC, 0x80..=0xBF, .. rest]) + #| | (tlen, [0xED, 0x80..=0x9F, .. rest]) + #| | (tlen, [0xEE..=0xEF, 0x80..=0xBF, .. rest]) => { + #| t.unsafe_set(tlen, 0xFD) + #| t.unsafe_set(tlen + 1, 0xFF) + #| continue (tlen + 2, rest) + #| } + #| (tlen, [0xF0, 0x90..=0xBF, 0x80..=0xBF, .. rest]) + #| | (tlen, [0xF1..=0xF3, 0x80..=0xBF, 0x80..=0xBF, .. rest]) + #| | (tlen, [0xF4, 0x80..=0x8F, 0x80..=0xBF, .. rest]) => { + #| t.unsafe_set(tlen, 0xFD) + #| t.unsafe_set(tlen + 1, 0xFF) + #| continue (tlen + 2, rest) + #| } + #| (tlen, [0xF0, 0x90..=0xBF, .. rest]) + #| | (tlen, [0xF1..=0xF3, 0x80..=0xBF, .. rest]) + #| | (tlen, [0xF4, 0x80..=0x8F, .. rest]) => { + #| t.unsafe_set(tlen, 0xFD) + #| t.unsafe_set(tlen + 1, 0xFF) + #| continue (tlen + 2, rest) + #| } + #| (tlen, [_, .. rest]) => { + #| t.unsafe_set(tlen, 0xFD) + #| t.unsafe_set(tlen + 1, 0xFF) + #| continue (tlen + 2, rest) + #| } + #| } + #| t.unsafe_reinterpret_as_bytes().to_unchecked_string(offset=0, length=tlen) + #|} + ), + "encode.mbt": ( + #|const U_BOM : Char = '\u{FEFF}' + #|pub fn encode(str : StringView, bom? : Bool = false) -> Bytes { + #| let buffer = @buffer.new(size_hint=str.length() * 4) + #| if bom is true { + #| buffer.write_char_utf8(U_BOM) + #| } + #| buffer.write_string_utf8(str) + #| buffer.to_bytes() + #|} + ) + } ) ///| let moonbitlang_core_env_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/env", - deps={ "moonbitlang/core/builtin": moonbitlang_core_builtin_module }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| "moonbitlang/core/builtin" - #| ], - #| "targets": { - #| "env_wasm.mbt": ["wasm", "wasm-gc"], - #| "env_js.mbt": ["js"], - #| "env_native.mbt": ["native", "llvm"] - #| } - #|} - ), - "env.mbt": ( - #|pub fn args() -> Array[String] { - #| get_cli_args_internal() - #|} - #|pub fn now() -> UInt64 { - #| now_internal() - #|} - #|pub fn current_dir() -> String? { - #| current_dir_internal() - #|} - ), - "env_js.mbt": ( - #|extern "js" fn get_cli_args_internal() -> Array[String] = - #| #| function() { - #| #| if (typeof process !== "undefined" && typeof process.argv !== "undefined") { - #| #| return process.argv; - #| #| } else { - #| #| return []; - #| #| } - #| #| } - #|extern "js" fn now_internal() -> UInt64 = - #| #| function() { - #| #| const nowMs = Date.now(); - #| #| return ({ hi : Number(BigInt(nowMs) >> 32n), lo : nowMs & 0xFFFFFFFF }); - #| #| } - #|extern "js" fn current_dir_internal() -> String? = - #| #| function() { - #| #| if (typeof process !== "undefined" && typeof process.cwd === "function") { - #| #| return process.cwd(); - #| #| } else { - #| #| return null; - #| #| } - #| #| } - ), - "env_native.mbt": ( - #|fn get_cli_args_ffi() -> FixedArray[Bytes] = "$moonbit.get_cli_args" - #|fn get_cli_args_internal() -> Array[String] { - #| let tmp = get_cli_args_ffi() - #| let res = Array::new(capacity=tmp.length()) - #| for i in 0.. String { - #| let res = StringBuilder::new() - #| let len = bytes.length() - #| let mut i = 0 - #| while i < len { - #| let mut c = bytes[i].to_int() - #| if c == 0 { - #| break - #| } else if c < 0x80 { - #| res.write_char(c.unsafe_to_char()) - #| i += 1 - #| } else if c < 0xE0 { - #| if i + 1 >= len { - #| break - #| } - #| c = ((c & 0x1F) << 6) | (bytes[i + 1].to_int() & 0x3F) - #| res.write_char(c.unsafe_to_char()) - #| i += 2 - #| } else if c < 0xF0 { - #| if i + 2 >= len { - #| break - #| } - #| c = ((c & 0x0F) << 12) | - #| ((bytes[i + 1].to_int() & 0x3F) << 6) | - #| (bytes[i + 2].to_int() & 0x3F) - #| res.write_char(c.unsafe_to_char()) - #| i += 3 - #| } else { - #| if i + 3 >= len { - #| break - #| } - #| c = ((c & 0x07) << 18) | - #| ((bytes[i + 1].to_int() & 0x3F) << 12) | - #| ((bytes[i + 2].to_int() & 0x3F) << 6) | - #| (bytes[i + 3].to_int() & 0x3F) - #| c -= 0x10000 - #| res.write_char(((c >> 10) + 0xD800).unsafe_to_char()) - #| res.write_char(((c & 0x3FF) + 0xDC00).unsafe_to_char()) - #| i += 4 - #| } - #| } - #| res.to_string() - #|} - #|extern "c" fn time(ptr : Int) -> UInt64 = "time" - #|fn now_internal() -> UInt64 { - #| time(0) * 1000 - #|} - #|#borrow(ptr) - #|extern "c" fn getcwd(ptr : Bytes, size : Int) -> Int = "getcwd" - #|fn current_dir_internal() -> String? { - #| let buf = Bytes::new(4096) - #| let res = getcwd(buf, buf.length()) - #| if res == 0 { - #| None - #| } else { - #| Some(utf8_bytes_to_mbt_string(buf)) - #| } - #|} - ), - "env_wasm.mbt": ( - #|#external - #|priv type XStringReadHandle - #|#external - #|priv type XExternString - #|fn begin_read_string(s : XExternString) -> XStringReadHandle = "__moonbit_fs_unstable" "begin_read_string" - #|fn string_read_char(handle : XStringReadHandle) -> Int = "__moonbit_fs_unstable" "string_read_char" - #|fn finish_read_string(handle : XStringReadHandle) = "__moonbit_fs_unstable" "finish_read_string" - #|fn string_from_extern(e : XExternString) -> String { - #| let buf = StringBuilder::new() - #| let handle = begin_read_string(e) - #| while true { - #| let ch = string_read_char(handle) - #| if ch == -1 { - #| break - #| } else { - #| buf.write_char(ch.unsafe_to_char()) - #| } - #| } - #| finish_read_string(handle) - #| buf.to_string() - #|} - #|#external - #|priv type XStringArrayReadHandle - #|#external - #|priv type XExternStringArray - #|fn begin_read_string_array(sa : XExternStringArray) -> XStringArrayReadHandle = "__moonbit_fs_unstable" "begin_read_string_array" - #|fn string_array_read_string(handle : XStringArrayReadHandle) -> XExternString = "__moonbit_fs_unstable" "string_array_read_string" - #|fn finish_read_string_array(handle : XStringArrayReadHandle) = "__moonbit_fs_unstable" "finish_read_string_array" - #|fn string_array_from_extern(e : XExternStringArray) -> Array[String] { - #| let buf = Array::new() - #| let handle = begin_read_string_array(e) - #| while true { - #| let extern_str = string_array_read_string(handle) - #| let str = string_from_extern(extern_str) - #| if str == "ffi_end_of_/string_array" { - #| break - #| } else { - #| buf.push(str) - #| } - #| } - #| finish_read_string_array(handle) - #| buf - #|} - #|fn get_cli_args_internal() -> Array[String] { - #| let args = get_cli_args_ffi() - #| string_array_from_extern(args) - #|} - #|fn get_cli_args_ffi() -> XExternStringArray = "__moonbit_fs_unstable" "args_get" - #|fn now_internal() -> UInt64 = "__moonbit_time_unstable" "now" - #|fn current_dir_internal() -> String? { - #| let dir = current_dir_ffi() - #| let dir = string_from_extern(dir) - #| if dir == "" { - #| None - #| } else { - #| Some(dir) - #| } - #|} - #|fn current_dir_ffi() -> XExternString = "__moonbit_fs_unstable" "current_dir" - ), - }, + "env.mbt": ( + #|pub fn args() -> Array[String] { + #| get_cli_args_internal() + #|} + #|pub fn now() -> UInt64 { + #| now_internal() + #|} + #|pub fn current_dir() -> String? { + #| current_dir_internal() + #|} + #|pub fn get_env_var(key : String) -> String? { + #| get_env_var_internal(key) + #|} + #|pub fn get_env_vars() -> Map[String, String] { + #| get_env_vars_internal() + #|} + #|pub fn set_env_var(key : String, value : String) -> Unit { + #| set_env_var_internal(key, value) + #|} + #|pub fn unset_env_var(key : String) -> Unit { + #| unset_env_var_internal(key) + #|} + ), + "env_js.mbt": ( + #|extern "js" fn get_cli_args_internal() -> Array[String] = + #| #| function() { + #| #| if (typeof process !== "undefined" && typeof process.argv !== "undefined") { + #| #| return process.argv; + #| #| } else { + #| #| return []; + #| #| } + #| #| } + #|extern "js" fn now_internal() -> UInt64 = + #| #| function() { + #| #| const nowMs = Date.now(); + #| #| return ({ hi : Number(BigInt(nowMs) >> 32n), lo : nowMs & 0xFFFFFFFF }); + #| #| } + #|extern "js" fn current_dir_internal() -> String? = + #| #| function() { + #| #| if (typeof process !== "undefined" && typeof process.cwd === "function") { + #| #| return process.cwd(); + #| #| } else { + #| #| return null; + #| #| } + #| #| } + #|fn get_env_var_internal(key : String) -> String? { + #| if is_env_var_exists_internal(key) { + #| Some(get_env_var_value_internal(key)) + #| } else { + #| None + #| } + #|} + #|extern "js" fn is_env_var_exists_internal(key : String) -> Bool = + #| #| function(key) { + #| #| if (typeof process === "undefined" || typeof process.env === "undefined") { + #| #| return false; + #| #| } + #| #| return Object.prototype.hasOwnProperty.call(process.env, key); + #| #| } + #|extern "js" fn get_env_var_value_internal(key : String) -> String = + #| #| function(key) { + #| #| if (typeof process === "undefined" || typeof process.env === "undefined") { + #| #| return ""; + #| #| } + #| #| const value = process.env[key]; + #| #| return value === undefined ? "" : String(value); + #| #| } + #|fn get_env_vars_internal() -> Map[String, String] { + #| let tmp = get_env_vars_array_internal() + #| let res = {} + #| for i = 0; i < tmp.length(); i = i + 2 { + #| res[tmp[i]] = tmp[i + 1] + #| } + #| res + #|} + #|extern "js" fn get_env_vars_array_internal() -> Array[String] = + #| #| function() { + #| #| if (typeof process === "undefined" || typeof process.env === "undefined") { + #| #| return []; + #| #| } + #| #| const result = []; + #| #| for (const key in process.env) { + #| #| const value = process.env[key]; + #| #| if (value !== undefined) { + #| #| result.push(key); + #| #| result.push(String(value)); + #| #| } + #| #| } + #| #| return result; + #| #| } + #|fn set_env_var_internal(key : String, value : String) -> Unit { + #| set_env_var_ffi(key, value) + #|} + #|extern "js" fn set_env_var_ffi(key : String, value : String) -> Unit = + #| #| function(key, value) { + #| #| if (typeof process !== "undefined" && typeof process.env !== "undefined") { + #| #| process.env[key] = value; + #| #| } + #| #| } + #|fn unset_env_var_internal(key : String) -> Unit { + #| unset_env_var_ffi(key) + #|} + #|extern "js" fn unset_env_var_ffi(key : String) -> Unit = + #| #| function(key) { + #| #| if (typeof process !== "undefined" && typeof process.env !== "undefined") { + #| #| delete process.env[key]; + #| #| } + #| #| } + ), + "env_native.mbt": ( + #|fn get_cli_args_ffi() -> FixedArray[Bytes] = "$moonbit.get_cli_args" + #|fn get_cli_args_internal() -> Array[String] { + #| let tmp = get_cli_args_ffi() + #| let res = Array::new(capacity=tmp.length()) + #| for t in tmp { + #| res.push(utf8_bytes_to_mbt_string(t)) + #| } + #| res + #|} + #|fn utf8_bytes_to_mbt_string(bytes : Bytes) -> String { + #| let res = StringBuilder::new() + #| let len = bytes.length() + #| let mut i = 0 + #| while i < len { + #| let mut c = bytes[i].to_int() + #| if c == 0 { + #| break + #| } else if c < 0x80 { + #| res.write_char(c.unsafe_to_char()) + #| i += 1 + #| } else if c < 0xE0 { + #| if i + 1 >= len { + #| break + #| } + #| c = ((c & 0x1F) << 6) | (bytes[i + 1].to_int() & 0x3F) + #| res.write_char(c.unsafe_to_char()) + #| i += 2 + #| } else if c < 0xF0 { + #| if i + 2 >= len { + #| break + #| } + #| c = ((c & 0x0F) << 12) | + #| ((bytes[i + 1].to_int() & 0x3F) << 6) | + #| (bytes[i + 2].to_int() & 0x3F) + #| res.write_char(c.unsafe_to_char()) + #| i += 3 + #| } else { + #| if i + 3 >= len { + #| break + #| } + #| c = ((c & 0x07) << 18) | + #| ((bytes[i + 1].to_int() & 0x3F) << 12) | + #| ((bytes[i + 2].to_int() & 0x3F) << 6) | + #| (bytes[i + 3].to_int() & 0x3F) + #| c -= 0x10000 + #| res.write_char(((c >> 10) + 0xD800).unsafe_to_char()) + #| res.write_char(((c & 0x3FF) + 0xDC00).unsafe_to_char()) + #| i += 4 + #| } + #| } + #| res.to_string() + #|} + #|fn mbt_string_to_utf8_bytes(str : String, append_nul : Bool) -> Bytes { + #| let res : Array[Byte] = [] + #| let len = str.length() + #| let mut i = 0 + #| while i < len { + #| let mut c = str.code_unit_at(i).to_int() + #| if 0xD800 <= c && c <= 0xDBFF { + #| c -= 0xD800 + #| i = i + 1 + #| let l = str.code_unit_at(i).to_int() - 0xDC00 + #| c = (c << 10) + l + 0x10000 + #| } + #| if c < 0x80 { + #| res.push(c.to_byte()) + #| } else if c < 0x800 { + #| res.push((0xc0 + (c >> 6)).to_byte()) + #| res.push((0x80 + (c & 0x3f)).to_byte()) + #| } else if c < 0x10000 { + #| res.push((0xe0 + (c >> 12)).to_byte()) + #| res.push((0x80 + ((c >> 6) & 0x3f)).to_byte()) + #| res.push((0x80 + (c & 0x3f)).to_byte()) + #| } else { + #| res.push((0xf0 + (c >> 18)).to_byte()) + #| res.push((0x80 + ((c >> 12) & 0x3f)).to_byte()) + #| res.push((0x80 + ((c >> 6) & 0x3f)).to_byte()) + #| res.push((0x80 + (c & 0x3f)).to_byte()) + #| } + #| i = i + 1 + #| } + #| if append_nul { + #| res.push((0).to_byte()) + #| } + #| Bytes::from_array(res) + #|} + #|extern "c" fn time(ptr : Int) -> UInt64 = "time" + #|fn now_internal() -> UInt64 { + #| time(0) * 1000 + #|} + #|#borrow(ptr) + #|extern "c" fn getcwd(ptr : Bytes, size : Int) -> Int = "getcwd" + #|fn current_dir_internal() -> String? { + #| let buf = Bytes::new(4096) + #| let res = getcwd(buf, buf.length()) + #| if res == 0 { + #| None + #| } else { + #| Some(utf8_bytes_to_mbt_string(buf)) + #| } + #|} + #|fn get_env_var_internal(key : String) -> String? { + #| let key = mbt_string_to_utf8_bytes(key, true) + #| if get_env_var_exists_ffi(key) { + #| Some(utf8_bytes_to_mbt_string(get_env_var_ffi(key))) + #| } else { + #| None + #| } + #|} + #|#borrow(_key) + #|extern "c" fn get_env_var_ffi(_key : Bytes) -> Bytes = "moonbit_rt_get_env_var" + #|#borrow(_key) + #|extern "c" fn get_env_var_exists_ffi(_key : Bytes) -> Bool = "moonbit_rt_get_env_var_exists" + #|fn get_env_vars_internal() -> Map[String, String] { + #| let env_vars = get_env_vars_ffi() + #| let res = {} + #| for i = 0; i < env_vars.length(); i = i + 2 { + #| res[utf8_bytes_to_mbt_string(env_vars[i])] = utf8_bytes_to_mbt_string( + #| env_vars[i + 1], + #| ) + #| } + #| res + #|} + #|extern "c" fn get_env_vars_ffi() -> FixedArray[Bytes] = "moonbit_rt_get_env_vars" + #|fn set_env_var_internal(key : String, value : String) -> Unit { + #| set_env_var_ffi( + #| mbt_string_to_utf8_bytes(key, true), + #| mbt_string_to_utf8_bytes(value, true), + #| ) + #|} + #|#borrow(_key, _value) + #|extern "c" fn set_env_var_ffi(_key : Bytes, _value : Bytes) -> Unit = "moonbit_rt_set_env_var" + #|fn unset_env_var_internal(key : String) -> Unit { + #| unset_env_var_ffi(mbt_string_to_utf8_bytes(key, true)) + #|} + #|#borrow(_key) + #|extern "c" fn unset_env_var_ffi(_key : Bytes) -> Unit = "moonbit_rt_unset_env_var" + ), + "env_wasm.mbt": ( + #|#external + #|priv type XStringReadHandle + #|#external + #|priv type XStringCreateHandle + #|#external + #|priv type XExternString + #|fn begin_create_string() -> XStringCreateHandle = "__moonbit_fs_unstable" "begin_create_string" + #|fn string_append_char(handle : XStringCreateHandle, ch : Char) = "__moonbit_fs_unstable" "string_append_char" + #|fn finish_create_string(handle : XStringCreateHandle) -> XExternString = "__moonbit_fs_unstable" "finish_create_string" + #|fn string_to_extern(s : String) -> XExternString { + #| let handle = begin_create_string() + #| for i = 0; i < s.length(); i = i + 1 { + #| string_append_char(handle, s.code_unit_at(i).unsafe_to_char()) + #| } + #| finish_create_string(handle) + #|} + #|fn begin_read_string(s : XExternString) -> XStringReadHandle = "__moonbit_fs_unstable" "begin_read_string" + #|fn string_read_char(handle : XStringReadHandle) -> Int = "__moonbit_fs_unstable" "string_read_char" + #|fn finish_read_string(handle : XStringReadHandle) = "__moonbit_fs_unstable" "finish_read_string" + #|fn string_from_extern(e : XExternString) -> String { + #| let buf = StringBuilder::new() + #| let handle = begin_read_string(e) + #| while true { + #| let ch = string_read_char(handle) + #| if ch == -1 { + #| break + #| } else { + #| buf.write_char(ch.unsafe_to_char()) + #| } + #| } + #| finish_read_string(handle) + #| buf.to_string() + #|} + #|#external + #|priv type XStringArrayReadHandle + #|#external + #|priv type XExternStringArray + #|fn begin_read_string_array(sa : XExternStringArray) -> XStringArrayReadHandle = "__moonbit_fs_unstable" "begin_read_string_array" + #|fn string_array_read_string(handle : XStringArrayReadHandle) -> XExternString = "__moonbit_fs_unstable" "string_array_read_string" + #|fn finish_read_string_array(handle : XStringArrayReadHandle) = "__moonbit_fs_unstable" "finish_read_string_array" + #|fn string_array_from_extern(e : XExternStringArray) -> Array[String] { + #| let buf = Array::new() + #| let handle = begin_read_string_array(e) + #| while true { + #| let extern_str = string_array_read_string(handle) + #| let str = string_from_extern(extern_str) + #| if str == "ffi_end_of_/string_array" { + #| break + #| } else { + #| buf.push(str) + #| } + #| } + #| finish_read_string_array(handle) + #| buf + #|} + #|fn get_cli_args_internal() -> Array[String] { + #| let args = get_cli_args_ffi() + #| string_array_from_extern(args) + #|} + #|fn get_cli_args_ffi() -> XExternStringArray = "__moonbit_fs_unstable" "args_get" + #|fn now_internal() -> UInt64 = "__moonbit_time_unstable" "now" + #|fn current_dir_internal() -> String? { + #| let dir = current_dir_ffi() + #| let dir = string_from_extern(dir) + #| if dir == "" { + #| None + #| } else { + #| Some(dir) + #| } + #|} + #|fn current_dir_ffi() -> XExternString = "__moonbit_fs_unstable" "current_dir" + #|fn get_env_var_internal(key : String) -> String? { + #| let key = string_to_extern(key) + #| if get_env_var_exists_ffi(key) { + #| Some(string_from_extern(get_env_var_ffi(key))) + #| } else { + #| None + #| } + #|} + #|fn get_env_var_ffi(key : XExternString) -> XExternString = "__moonbit_fs_unstable" "get_env_var" + #|fn get_env_var_exists_ffi(key : XExternString) -> Bool = "__moonbit_fs_unstable" "get_env_var_exists" + #|fn get_env_vars_internal() -> Map[String, String] { + #| let tmp = string_array_from_extern(get_env_vars_ffi()) + #| let res = {} + #| for i = 0; i < tmp.length(); i = i + 2 { + #| res[tmp[i]] = tmp[i + 1] + #| } + #| res + #|} + #|fn get_env_vars_ffi() -> XExternStringArray = "__moonbit_fs_unstable" "get_env_vars" + #|fn set_env_var_internal(key : String, value : String) -> Unit { + #| set_env_var_ffi(string_to_extern(key), string_to_extern(value)) + #|} + #|fn set_env_var_ffi(key : XExternString, value : XExternString) = "__moonbit_fs_unstable" "set_env_var" + #|fn unset_env_var_internal(key : String) -> Unit { + #| unset_env_var_ffi(string_to_extern(key)) + #|} + #|fn unset_env_var_ffi(key : XExternString) = "__moonbit_fs_unstable" "unset_env_var" + ) + } ) ///| let moonbitlang_core_error_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/error", - deps={ "moonbitlang/core/builtin": moonbitlang_core_builtin_module }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": ["moonbitlang/core/builtin"], - #| "test-import": [ - #| "moonbitlang/core/json" - #| ] - #|} - ), - "error.mbt": ( - #|fn Error::to_string(self : Error) -> String = "%error.to_string" - #|pub impl Show for Error with output(self, logger) { - #| logger.write_string(self.to_string()) - #|} - #|fn Error::to_json(self : Error) -> Json = "%error.to_json" - #|pub impl ToJson for Error with to_json(self) { - #| self.to_json() - #|} - ), - }, + "error.mbt": ( + #|fn Error::to_string(self : Error) -> String = "%error.to_string" + #|pub impl Show for Error with output(self, logger) { + #| logger.write_string(self.to_string()) + #|} + #|fn Error::to_json(self : Error) -> Json = "%error.to_json" + #|pub impl ToJson for Error with to_json(self) { + #| self.to_json() + #|} + ) + } ) ///| let moonbitlang_core_float_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/float", - deps={ - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/double": moonbitlang_core_double_module, - "moonbitlang/core/uint": moonbitlang_core_uint_module, - }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": ["moonbitlang/core/builtin", "moonbitlang/core/double", "moonbitlang/core/uint"], - #| "targets": { - #| "round_js.mbt": ["js"], - #| "round_wasm.mbt": ["wasm", "wasm-gc"], - #| "round.mbt": ["not", "js", "wasm", "wasm-gc"], - #| "to_int.mbt": ["not", "wasm", "wasm-gc"], - #| "to_int_wasm.mbt": ["wasm", "wasm-gc"] - #| }, - #| "test-import": ["moonbitlang/core/bytes"] - #|} - ), - "float.mbt": ( - #|pub let not_a_number : Float = Float::reinterpret_from_int(0x7FC00000) - #|pub let infinity : Float = Float::reinterpret_from_int(0x7F800000) - #|pub let neg_infinity : Float = Float::reinterpret_from_int(0xFF800000) - #|pub let max_value : Float = Float::reinterpret_from_int(0x7F7FFFFF) - #|pub let min_value : Float = Float::reinterpret_from_int(0xFF7FFFFF) - #|pub let min_positive : Float = Float::reinterpret_from_int(0x00800000) - #|#as_free_fn(deprecated) - #|pub fn Float::abs(self : Float) -> Float = "%f32.abs" - #|#deprecated - #|pub fn default() -> Float { - #| 0.0 - #|} - ), - "methods.mbt": ( - #|pub impl Show for Float with output(self, logger) { - #| logger.write_string(self.to_double().to_string()) - #|} - #|pub impl Default for Float with default() { - #| 0 - #|} - #|pub impl Hash for Float with hash_combine(self, hasher) { - #| hasher.combine_uint(self.reinterpret_as_uint()) - #|} - #|pub fn Float::to_be_bytes(self : Float) -> Bytes { - #| let uint = self.reinterpret_as_uint() - #| [ - #| (uint >> 24).to_byte(), - #| (uint >> 16).to_byte(), - #| (uint >> 8).to_byte(), - #| uint.to_byte(), - #| ] - #|} - #|pub fn Float::to_le_bytes(self : Float) -> Bytes { - #| let uint = self.reinterpret_as_uint() - #| [ - #| uint.to_byte(), - #| (uint >> 8).to_byte(), - #| (uint >> 16).to_byte(), - #| (uint >> 24).to_byte(), - #| ] - #|} - #|pub fn Float::is_inf(self : Float) -> Bool { - #| self.is_pos_inf() || self.is_neg_inf() - #|} - #|pub fn Float::is_pos_inf(self : Float) -> Bool { - #| self > max_value - #|} - #|pub fn Float::is_neg_inf(self : Float) -> Bool { - #| self < min_value - #|} - #|pub fn Float::is_nan(self : Float) -> Bool { - #| self != self - #|} - #|pub fn Float::is_close( - #| self : Self, - #| other : Self, - #| relative_tolerance? : Self = 1.0e-09, - #| absolute_tolerance? : Self = 0.0, - #|) -> Bool { - #| if relative_tolerance < 0.0 || absolute_tolerance < 0.0 { - #| abort("Tolerances must be non-negative") - #| } - #| if self == other { - #| return true - #| } - #| if self.is_inf() || other.is_inf() { - #| return false - #| } - #| let diff = (other - self).abs() - #| return ( - #| diff <= (relative_tolerance * other).abs() || - #| diff <= (relative_tolerance * self).abs() - #| ) || - #| diff <= absolute_tolerance - #|} - #|pub impl Mod for Float with mod(self : Float, other : Float) -> Float { - #| Float::from_double(self.to_double() % other.to_double()) - #|} - #|#deprecated("Use `..<` in for loop or `until` method instead") - #|#coverage.skip - #|pub fn Float::upto( - #| self : Float, - #| end : Float, - #| inclusive? : Bool = false, - #|) -> Iter[Float] { - #| let mut i = self - #| Iterator::new(() => { - #| guard i < end || (inclusive && i == end) else { None } - #| let result = i - #| if i != end { - #| i += 1 - #| } - #| Some(result) - #| }).iter() - #|} - #|pub fn Float::until( - #| self : Float, - #| end : Float, - #| step? : Float = 1.0, - #| inclusive? : Bool = false, - #|) -> Iter[Float] { - #| if step == 0.0 { - #| return Iter::empty() - #| } - #| let mut curr_value = Some(self) - #| let iter = Iterator::new(() => { - #| guard curr_value is Some(i) else { None } - #| guard (step > 0.0 && i < end) || - #| (step < 0.0 && i > end) || - #| (inclusive && i == end) else { - #| None - #| } - #| let next = i + step - #| if (step > 0.0 && next >= i) || (step < 0.0 && next <= i) { - #| curr_value = Some(next) - #| } else { - #| curr_value = None - #| } - #| Some(i) - #| }) - #| iter.iter() - #|} - #|pub fn Float::to_double(self : Float) -> Double = "%f32.to_f64" - #|pub impl ToJson for Float with to_json(self : Float) -> Json { - #| Json::number(self.to_double()) - #|} - #|pub fn Float::sqrt(self : Float) -> Float = "%f32.sqrt" - #|pub fn Float::reinterpret_as_int(self : Float) -> Int = "%f32.to_i32_reinterpret" - #|pub impl Neg for Float with neg(self) = "%f32.neg" - #|pub impl Add for Float with add(self, other) = "%f32.add" - #|pub impl Sub for Float with sub(self, other) = "%f32.sub" - #|pub impl Mul for Float with mul(self, other) = "%f32.mul" - #|pub impl Div for Float with div(self, other) = "%f32.div" - #|pub impl Eq for Float with equal(self : Float, other : Float) -> Bool = "%f32.eq" - #|#deprecated("Use `a != b` instead") - #|#doc(hidden) - #|pub fn Float::op_neq(self : Float, other : Float) -> Bool = "%f32.ne" - #|pub impl Compare for Float with compare(self, other) = "%f32.compare" - #|pub impl Compare for Float with op_lt(x, y) = "%f32.lt" - #|pub impl Compare for Float with op_le(x, y) = "%f32.le" - #|pub impl Compare for Float with op_gt(x, y) = "%f32.gt" - #|pub impl Compare for Float with op_ge(x, y) = "%f32.ge" - #|pub fn Float::reinterpret_as_uint(self : Float) -> UInt = "%f32.to_i32_reinterpret" - #|pub fn Float::reinterpret_from_int(self : Int) -> Float = "%i32.to_f32_reinterpret" - #|pub fn Float::reinterpret_from_uint(self : UInt) -> Float = "%i32.to_f32_reinterpret" - #|test "Float::reinterpret" { - #| inspect(Float::reinterpret_from_int(1065353216), content="1") - #| inspect(Float::reinterpret_from_uint(0x3F800000), content="1") - #|} - #|pub fn Float::from_int(self : Int) -> Float = "%i32.to_f32" - #|pub fn Float::from_byte(self : Byte) -> Float = "%byte.to_f32" - #|pub fn Float::from_double(self : Double) -> Float = "%f64.to_f32" - #|pub fn Float::from_uint(self : UInt) -> Float = "%u32.to_f32" - #|#cfg(not(target="js")) - #|pub fn Float::from_uint64(self : UInt64) -> Float = "%u64.to_f32" - #|#cfg(target="js") - #|pub fn Float::from_uint64(self : UInt64) -> Float { - #| Float::from_double(self.to_double()) - #|} - #|test "Float::from_uint64" { - #| let n = 42UL - #| inspect(Float::from_uint64(n).to_double(), content="42") - #| let big = 18446744073709551615UL // UInt64::max_value - #| inspect(Float::from_uint64(big).to_double(), content="18446744073709552000") - #|} - #|#cfg(not(target="js")) - #|pub fn Float::from_int64(self : Int64) -> Float = "%i64.to_f32" - #|#cfg(target="js") - #|pub fn Float::from_int64(self : Int64) -> Float { - #| Float::from_double(self.to_double()) - #|} - #|test "Float::from_int64" { - #| let n = 42L - #| let f = Float::from_int64(n) - #| inspect(f.to_double(), content="42") - #|} - ), - "pow.mbt": ( - #|#as_free_fn - #|pub fn Float::pow(self : Float, other : Float) -> Float { - #| Float::from_double(self.to_double().pow(other.to_double())) - #|} - ), - "round.mbt": ( - #|let sign_mask : UInt = 0x8000_0000 - #|let exp_bias = 127 - #|let exp_bits = 8 - #|let frac_bits = 23 - #|#as_free_fn - #|pub fn Float::trunc(self : Float) -> Float { - #| let u32 = self.reinterpret_as_uint() - #| let biased_exp = ((u32 >> frac_bits) & ((0x1U << exp_bits) - 1)).reinterpret_as_int() - #| if biased_exp < exp_bias { - #| return Float::reinterpret_from_uint(u32 & sign_mask) - #| } else if biased_exp >= exp_bias + frac_bits { - #| return self - #| } - #| let mask_shift = biased_exp - exp_bias + exp_bits - #| let trunc_mask = (sign_mask.reinterpret_as_int() >> mask_shift).reinterpret_as_uint() - #| return Float::reinterpret_from_uint(u32 & trunc_mask) - #|} - #|#as_free_fn - #|pub fn Float::ceil(self : Float) -> Float { - #| let trunced = self.trunc() - #| if self > trunced { - #| return trunced + 1.0 - #| } else { - #| return trunced - #| } - #|} - #|#as_free_fn - #|pub fn Float::floor(self : Float) -> Float { - #| let trunced = self.trunc() - #| if self < trunced { - #| return trunced - 1.0 - #| } else { - #| return trunced - #| } - #|} - #|#as_free_fn - #|pub fn Float::round(self : Float) -> Float { - #| floor(self + 0.5) - #|} - ), - "round_js.mbt": ( - #|#as_free_fn - #|pub fn Float::trunc(self : Float) -> Float = "Math" "trunc" - #|#as_free_fn - #|pub fn Float::ceil(self : Float) -> Float = "Math" "ceil" - #|#as_free_fn - #|pub fn Float::floor(self : Float) -> Float = "Math" "floor" - #|#as_free_fn - #|pub fn Float::round(self : Float) -> Float = "Math" "round" - ), - "round_wasm.mbt": ( - #|#as_free_fn - #|pub fn Float::trunc(self : Float) -> Float = "(func (param $f f32) (result f32) (f32.trunc (local.get $f)))" - #|#as_free_fn - #|pub fn Float::ceil(self : Float) -> Float = "(func (param $f f32) (result f32) (f32.ceil (local.get $f)))" - #|#as_free_fn - #|pub fn Float::floor(self : Float) -> Float = "(func (param $f f32) (result f32) (f32.floor (local.get $f)))" - #|#as_free_fn - #|pub fn Float::round(self : Float) -> Float { - #| floor(self + 0.5) - #|} - ), - "to_int.mbt": ( - #|fn Float::to_unchecked_int(self : Float) -> Int = "%f32.to_i32" - #|pub fn Float::to_int(self : Float) -> Int { - #| if self != self { - #| 0 - #| } else if self >= 2147483647 { - #| 2147483647 - #| } else if self <= -2147483648 { - #| -2147483648 - #| } else { - #| self.to_unchecked_int() - #| } - #|} - ), - "to_int_wasm.mbt": ( - #|pub fn Float::to_int(self : Float) -> Int = "%f32.to_i32_saturate" - ), - }, + "float.mbt": ( + #|pub let not_a_number : Float = Float::reinterpret_from_int(0x7FC00000) + #|pub let infinity : Float = Float::reinterpret_from_int(0x7F800000) + #|pub let neg_infinity : Float = Float::reinterpret_from_int(0xFF800000) + #|pub let max_value : Float = Float::reinterpret_from_int(0x7F7FFFFF) + #|pub let min_value : Float = Float::reinterpret_from_int(0xFF7FFFFF) + #|pub let min_positive : Float = Float::reinterpret_from_int(0x00800000) + #|#as_free_fn(deprecated) + #|pub fn Float::abs(self : Float) -> Float = "%f32.abs" + #|#deprecated + #|pub fn default() -> Float { + #| 0.0 + #|} + ), + "methods.mbt": ( + #|pub impl Show for Float with output(self, logger) { + #| logger.write_string(self.to_double().to_string()) + #|} + #|pub impl Default for Float with default() { + #| 0 + #|} + #|pub impl Hash for Float with hash_combine(self, hasher) { + #| hasher.combine_uint(self.reinterpret_as_uint()) + #|} + #|pub fn Float::to_be_bytes(self : Float) -> Bytes { + #| let uint = self.reinterpret_as_uint() + #| [ + #| (uint >> 24).to_byte(), + #| (uint >> 16).to_byte(), + #| (uint >> 8).to_byte(), + #| uint.to_byte(), + #| ] + #|} + #|pub fn Float::to_le_bytes(self : Float) -> Bytes { + #| let uint = self.reinterpret_as_uint() + #| [ + #| uint.to_byte(), + #| (uint >> 8).to_byte(), + #| (uint >> 16).to_byte(), + #| (uint >> 24).to_byte(), + #| ] + #|} + #|pub fn Float::is_inf(self : Float) -> Bool { + #| self.is_pos_inf() || self.is_neg_inf() + #|} + #|pub fn Float::is_pos_inf(self : Float) -> Bool { + #| self > max_value + #|} + #|pub fn Float::is_neg_inf(self : Float) -> Bool { + #| self < min_value + #|} + #|pub fn Float::is_nan(self : Float) -> Bool { + #| self != self + #|} + #|pub fn Float::min(self : Float, other : Float) -> Float { + #| if self.is_nan() { + #| other + #| } else if other.is_nan() { + #| self + #| } else if self < other { + #| self + #| } else { + #| other + #| } + #|} + #|pub fn Float::max(self : Float, other : Float) -> Float { + #| if self.is_nan() { + #| other + #| } else if other.is_nan() { + #| self + #| } else if self > other { + #| self + #| } else { + #| other + #| } + #|} + #|pub fn Float::clamp(self : Float, min~ : Float, max~ : Float) -> Float { + #| guard min <= max + #| if self < min { + #| min + #| } else if self > max { + #| max + #| } else { + #| self + #| } + #|} + #|pub fn Float::lerp(self : Float, target~ : Float, t~ : Float) -> Float { + #| self + (target - self) * t + #|} + #|pub fn Float::signum(self : Float) -> Float { + #| if self < 0.0 { + #| -1.0 + #| } else if self > 0.0 { + #| 1.0 + #| } else { + #| self + #| } + #|} + #|pub fn Float::is_close( + #| self : Self, + #| other : Self, + #| relative_tolerance? : Self = 1.0e-09, + #| absolute_tolerance? : Self = 0.0, + #|) -> Bool { + #| if relative_tolerance < 0.0 || absolute_tolerance < 0.0 { + #| abort("Tolerances must be non-negative") + #| } + #| if self == other { + #| return true + #| } + #| if self.is_inf() || other.is_inf() { + #| return false + #| } + #| let diff = (other - self).abs() + #| return ( + #| diff <= (relative_tolerance * other).abs() || + #| diff <= (relative_tolerance * self).abs() + #| ) || + #| diff <= absolute_tolerance + #|} + #|pub impl Mod for Float with mod(self : Float, other : Float) -> Float { + #| Float::from_double(self.to_double() % other.to_double()) + #|} + #|#deprecated("Use `..<` in for loop or `until` method instead") + #|#coverage.skip + #|pub fn Float::upto( + #| self : Float, + #| end : Float, + #| inclusive? : Bool = false, + #|) -> Iter[Float] { + #| let mut i = self + #| Iter::new(() => { + #| guard i < end || (inclusive && i == end) else { None } + #| let result = i + #| if i != end { + #| i += 1 + #| } + #| Some(result) + #| }) + #|} + #|pub fn Float::until( + #| self : Float, + #| end : Float, + #| step? : Float = 1.0, + #| inclusive? : Bool = false, + #|) -> Iter[Float] { + #| if step == 0.0 { + #| return Iter::empty() + #| } + #| let mut curr_value = Some(self) + #| Iter::new(() => { + #| guard curr_value is Some(i) else { None } + #| guard (step > 0.0 && i < end) || + #| (step < 0.0 && i > end) || + #| (inclusive && i == end) else { + #| None + #| } + #| let next = i + step + #| if (step > 0.0 && next >= i) || (step < 0.0 && next <= i) { + #| curr_value = Some(next) + #| } else { + #| curr_value = None + #| } + #| Some(i) + #| }) + #|} + #|pub fn Float::to_double(self : Float) -> Double = "%f32.to_f64" + #|pub impl ToJson for Float with to_json(self : Float) -> Json { + #| Json::number(self.to_double()) + #|} + #|pub fn Float::sqrt(self : Float) -> Float = "%f32.sqrt" + #|pub fn Float::reinterpret_as_int(self : Float) -> Int = "%f32.to_i32_reinterpret" + #|pub impl Neg for Float with neg(self) = "%f32.neg" + #|pub impl Add for Float with add(self, other) = "%f32.add" + #|pub impl Sub for Float with sub(self, other) = "%f32.sub" + #|pub impl Mul for Float with mul(self, other) = "%f32.mul" + #|pub impl Div for Float with div(self, other) = "%f32.div" + #|pub impl Eq for Float with equal(self : Float, other : Float) -> Bool = "%f32.eq" + #|pub impl Eq for Float with not_equal(self : Float, other : Float) -> Bool = "%f32.ne" + #|#deprecated("Use `a != b` instead") + #|#doc(hidden) + #|pub fn Float::op_neq(self : Float, other : Float) -> Bool = "%f32.ne" + #|pub impl Compare for Float with compare(self, other) = "%f32.compare" + #|pub impl Compare for Float with op_lt(x, y) = "%f32.lt" + #|pub impl Compare for Float with op_le(x, y) = "%f32.le" + #|pub impl Compare for Float with op_gt(x, y) = "%f32.gt" + #|pub impl Compare for Float with op_ge(x, y) = "%f32.ge" + #|pub fn Float::reinterpret_as_uint(self : Float) -> UInt = "%f32.to_i32_reinterpret" + #|pub fn Float::reinterpret_from_int(self : Int) -> Float = "%i32.to_f32_reinterpret" + #|pub fn Float::reinterpret_from_uint(self : UInt) -> Float = "%i32.to_f32_reinterpret" + #|test "Float::reinterpret" { + #| inspect(Float::reinterpret_from_int(1065353216), content="1") + #| inspect(Float::reinterpret_from_uint(0x3F800000), content="1") + #|} + #|pub fn Float::from_int(self : Int) -> Float = "%i32.to_f32" + #|pub fn Float::from_byte(self : Byte) -> Float = "%byte.to_f32" + #|pub fn Float::from_double(self : Double) -> Float = "%f64.to_f32" + #|pub fn Float::from_uint(self : UInt) -> Float = "%u32.to_f32" + #|#cfg(not(target="js")) + #|pub fn Float::from_uint64(self : UInt64) -> Float = "%u64.to_f32" + #|#cfg(target="js") + #|pub fn Float::from_uint64(self : UInt64) -> Float { + #| Float::from_double(self.to_double()) + #|} + #|test "Float::from_uint64" { + #| let n = 42UL + #| inspect(Float::from_uint64(n).to_double(), content="42") + #| let big = 18446744073709551615UL // UInt64::max_value + #| inspect(Float::from_uint64(big).to_double(), content="18446744073709552000") + #|} + #|#cfg(not(target="js")) + #|pub fn Float::from_int64(self : Int64) -> Float = "%i64.to_f32" + #|#cfg(target="js") + #|pub fn Float::from_int64(self : Int64) -> Float { + #| Float::from_double(self.to_double()) + #|} + #|test "Float::from_int64" { + #| let n = 42L + #| let f = Float::from_int64(n) + #| inspect(f.to_double(), content="42") + #|} + ), + "pow.mbt": ( + #|#deprecated("Use `@math.powf` instead") + #|#as_free_fn(deprecated="Use `@math.powf` instead") + #|#warnings("-deprecated") + #|pub fn Float::pow(self : Float, other : Float) -> Float { + #| Float::from_double(self.to_double().pow(other.to_double())) + #|} + ), + "round.mbt": ( + #|let sign_mask : UInt = 0x8000_0000 + #|let exp_bias = 127 + #|let exp_bits = 8 + #|let frac_bits = 23 + #|#as_free_fn + #|pub fn Float::trunc(self : Float) -> Float { + #| let u32 = self.reinterpret_as_uint() + #| let biased_exp = ((u32 >> frac_bits) & ((0x1U << exp_bits) - 1)).reinterpret_as_int() + #| if biased_exp < exp_bias { + #| return Float::reinterpret_from_uint(u32 & sign_mask) + #| } else if biased_exp >= exp_bias + frac_bits { + #| return self + #| } + #| let mask_shift = biased_exp - exp_bias + exp_bits + #| let trunc_mask = (sign_mask.reinterpret_as_int() >> mask_shift).reinterpret_as_uint() + #| return Float::reinterpret_from_uint(u32 & trunc_mask) + #|} + #|#as_free_fn + #|pub fn Float::ceil(self : Float) -> Float { + #| let trunced = self.trunc() + #| if self > trunced { + #| return trunced + 1.0 + #| } else { + #| return trunced + #| } + #|} + #|#as_free_fn + #|pub fn Float::floor(self : Float) -> Float { + #| let trunced = self.trunc() + #| if self < trunced { + #| return trunced - 1.0 + #| } else { + #| return trunced + #| } + #|} + #|#as_free_fn + #|pub fn Float::round(self : Float) -> Float { + #| floor(self + 0.5) + #|} + ), + "round_js.mbt": ( + #|#as_free_fn + #|pub fn Float::trunc(self : Float) -> Float = "Math" "trunc" + #|#as_free_fn + #|pub fn Float::ceil(self : Float) -> Float = "Math" "ceil" + #|#as_free_fn + #|pub fn Float::floor(self : Float) -> Float = "Math" "floor" + #|#as_free_fn + #|pub fn Float::round(self : Float) -> Float = "Math" "round" + ), + "round_wasm.mbt": ( + #|#as_free_fn + #|pub fn Float::trunc(self : Float) -> Float = "(func (param $f f32) (result f32) (f32.trunc (local.get $f)))" + #|#as_free_fn + #|pub fn Float::ceil(self : Float) -> Float = "(func (param $f f32) (result f32) (f32.ceil (local.get $f)))" + #|#as_free_fn + #|pub fn Float::floor(self : Float) -> Float = "(func (param $f f32) (result f32) (f32.floor (local.get $f)))" + #|#as_free_fn + #|pub fn Float::round(self : Float) -> Float { + #| floor(self + 0.5) + #|} + ), + "to_int.mbt": ( + #|fn Float::to_unchecked_int(self : Float) -> Int = "%f32.to_i32" + #|pub fn Float::to_int(self : Float) -> Int { + #| if self != self { + #| 0 + #| } else if self >= 2147483647 { + #| 2147483647 + #| } else if self <= -2147483648 { + #| -2147483648 + #| } else { + #| self.to_unchecked_int() + #| } + #|} + ), + "to_int_wasm.mbt": ( + #|pub fn Float::to_int(self : Float) -> Int = "%f32.to_i32_saturate" + ) + } ) ///| let moonbitlang_core_hashmap_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/hashmap", - deps={ - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/test": moonbitlang_core_test_module, - "moonbitlang/core/array": moonbitlang_core_array_module, - "moonbitlang/core/tuple": moonbitlang_core_tuple_module, - "moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module, - "moonbitlang/core/int": moonbitlang_core_int_module, - }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| "moonbitlang/core/builtin", - #| "moonbitlang/core/test", - #| "moonbitlang/core/array", - #| "moonbitlang/core/tuple", - #| "moonbitlang/core/quickcheck", - #| "moonbitlang/core/int" - #| ], - #| "test-import": ["moonbitlang/core/string", "moonbitlang/core/json"] - #|} - ), - "deprecated.mbt": "", - "hashmap.mbt": ( - #|#as_free_fn - #|pub fn[K, V] HashMap::new(capacity? : Int = 8) -> HashMap[K, V] { - #| let capacity = capacity.next_power_of_two() - #| { - #| size: 0, - #| capacity, - #| entries: FixedArray::make(capacity, None), - #| capacity_mask: capacity - 1, - #| } - #|} - #|#as_free_fn - #|#alias(of, deprecated="Use from_array instead") - #|#as_free_fn(of, deprecated="Use from_array instead") - #|pub fn[K : Hash + Eq, V] HashMap::from_array( - #| arr : ArrayView[(K, V)], - #|) -> HashMap[K, V] { - #| let m = new(capacity=arr.length()) - #| arr.each(e => m.set(e.0, e.1)) - #| m - #|} - #|#alias("_[_]=_") - #|pub fn[K : Hash + Eq, V] HashMap::set( - #| self : HashMap[K, V], - #| key : K, - #| value : V, - #|) -> Unit { - #| self.set_with_hash(key, value, key.hash()) - #|} - #|fn[K : Eq, V] HashMap::set_with_hash( - #| self : HashMap[K, V], - #| key : K, - #| value : V, - #| hash : Int, - #|) -> Unit { - #| if self.size >= self.capacity / 2 { - #| self.grow() - #| } - #| let (idx, psl) = for psl = 0, idx = hash & self.capacity_mask { - #| match self.entries[idx] { - #| None => break (idx, psl) - #| Some(curr_entry) => { - #| if curr_entry.hash == hash && curr_entry.key == key { - #| curr_entry.value = value - #| return - #| } - #| if psl > curr_entry.psl { - #| self.push_away(idx, curr_entry) - #| break (idx, psl) - #| } - #| continue psl + 1, (idx + 1) & self.capacity_mask - #| } - #| } - #| } - #| let entry = { psl, key, value, hash } - #| self.entries[idx] = Some(entry) - #| self.size += 1 - #|} - #|fn[K, V] HashMap::push_away( - #| self : HashMap[K, V], - #| idx : Int, - #| entry : Entry[K, V], - #|) -> Unit { - #| for psl = entry.psl + 1, idx = (idx + 1) & self.capacity_mask, entry = entry { - #| match self.entries[idx] { - #| None => { - #| entry.psl = psl - #| self.entries[idx] = Some(entry) - #| break - #| } - #| Some(curr_entry) => - #| if psl > curr_entry.psl { - #| entry.psl = psl - #| self.entries[idx] = Some(entry) - #| continue curr_entry.psl + 1, - #| (idx + 1) & self.capacity_mask, - #| curr_entry - #| } else { - #| continue psl + 1, (idx + 1) & self.capacity_mask, entry - #| } - #| } - #| } - #|} - #|pub fn[K : Hash + Eq, V] HashMap::get(self : HashMap[K, V], key : K) -> V? { - #| let hash = key.hash() - #| for i = 0, idx = hash & self.capacity_mask { - #| guard self.entries[idx] is Some(entry) else { break None } - #| if entry.hash == hash && entry.key == key { - #| break Some(entry.value) - #| } - #| if i > entry.psl { - #| break None - #| } - #| continue i + 1, (idx + 1) & self.capacity_mask - #| } - #|} - #|#alias("_[_]") - #|pub fn[K : Hash + Eq, V] HashMap::at(self : HashMap[K, V], key : K) -> V { - #| let hash = key.hash() - #| for i = 0, idx = hash & self.capacity_mask { - #| guard self.entries[idx] is Some(entry) - #| if entry.hash == hash && entry.key == key { - #| break entry.value - #| } - #| guard entry.psl <= i - #| continue i + 1, (idx + 1) & self.capacity_mask - #| } - #|} - #|pub fn[K : Hash + Eq, V] HashMap::get_or_init( - #| self : HashMap[K, V], - #| key : K, - #| init : () -> V, - #|) -> V { - #| let hash = key.hash() - #| let (idx, psl, new_value, push_away) = for psl = 0, idx = hash & - #| self.capacity_mask { - #| match self.entries[idx] { - #| Some(entry) => { - #| if entry.hash == hash && entry.key == key { - #| return entry.value - #| } - #| if psl > entry.psl { - #| let new_value = init() - #| break (idx, psl, new_value, Some(entry)) - #| } - #| continue psl + 1, (idx + 1) & self.capacity_mask - #| } - #| None => { - #| let new_value = init() - #| break (idx, psl, new_value, None) - #| } - #| } - #| } - #| if self.size >= self.capacity / 2 { - #| self.grow() - #| self.set_with_hash(key, new_value, hash) - #| } else { - #| if push_away is Some(entry) { - #| self.push_away(idx, entry) - #| } - #| let entry = { psl, hash, key, value: new_value } - #| self.entries[idx] = Some(entry) - #| self.size += 1 - #| } - #| new_value - #|} - #|pub fn[K : Hash + Eq, V] HashMap::get_or_default( - #| self : HashMap[K, V], - #| key : K, - #| default : V, - #|) -> V { - #| let hash = key.hash() - #| for i = 0, idx = hash & self.capacity_mask { - #| guard self.entries[idx] is Some(entry) else { break default } - #| if entry.hash == hash && entry.key == key { - #| break entry.value - #| } - #| if i > entry.psl { - #| break default - #| } - #| continue i + 1, (idx + 1) & self.capacity_mask - #| } - #|} - #|pub fn[K : Hash + Eq, V] HashMap::contains( - #| self : HashMap[K, V], - #| key : K, - #|) -> Bool { - #| let hash = key.hash() - #| for i = 0, idx = hash & self.capacity_mask { - #| guard self.entries[idx] is Some(entry) else { return false } - #| if entry.hash == hash && entry.key == key { - #| return true - #| } - #| if i > entry.psl { - #| return false - #| } - #| continue i + 1, (idx + 1) & self.capacity_mask - #| } - #|} - #|pub fn[K : Hash + Eq, V : Eq] HashMap::contains_kv( - #| self : HashMap[K, V], - #| key : K, - #| value : V, - #|) -> Bool { - #| let hash = key.hash() - #| for i = 0, idx = hash & self.capacity_mask { - #| guard self.entries[idx] is Some(entry) else { return false } - #| if entry.hash == hash && entry.key == key && entry.value == value { - #| return true - #| } - #| if i > entry.psl { - #| return false - #| } - #| continue i + 1, (idx + 1) & self.capacity_mask - #| } - #|} - #|pub fn[K : Hash + Eq, V] HashMap::remove(self : HashMap[K, V], key : K) -> Unit { - #| self.remove_with_hash(key, key.hash()) - #|} - #|fn[K : Eq, V] HashMap::remove_with_hash( - #| self : HashMap[K, V], - #| key : K, - #| hash : Int, - #|) -> Unit { - #| for i = 0, idx = hash & self.capacity_mask { - #| match self.entries[idx] { - #| Some(entry) => { - #| if entry.hash == hash && entry.key == key { - #| self.shift_back(idx) - #| self.size -= 1 - #| break - #| } - #| if i > entry.psl { - #| break - #| } - #| continue i + 1, (idx + 1) & self.capacity_mask - #| } - #| None => break - #| } - #| } - #|} - #|fn[K, V] HashMap::shift_back(self : HashMap[K, V], idx : Int) -> Unit { - #| let next = (idx + 1) & self.capacity_mask - #| match self.entries[next] { - #| None | Some({ psl: 0, .. }) => self.entries[idx] = None - #| Some(entry) => { - #| entry.psl -= 1 - #| self.entries[idx] = Some(entry) - #| self.shift_back(next) - #| } - #| } - #|} - #|fn[K : Eq, V] HashMap::grow(self : HashMap[K, V]) -> Unit { - #| let old_entries = self.entries - #| let new_capacity = self.capacity << 1 - #| self.entries = FixedArray::make(new_capacity, None) - #| self.capacity = new_capacity - #| self.capacity_mask = new_capacity - 1 - #| self.size = 0 - #| for i in 0.. m.set( - #| kv.0, - #| kv.1, - #| )) - #| m - #|} - #|pub impl[K, V] Default for HashMap[K, V] with default() { - #| new() - #|} - #|pub fn[K, V, V2] HashMap::map( - #| self : HashMap[K, V], - #| f : (K, V) -> V2, - #|) -> HashMap[K, V2] { - #| let other = { - #| capacity: self.capacity, - #| entries: FixedArray::make(self.capacity, None), - #| size: self.size, - #| capacity_mask: self.capacity_mask, - #| } - #| if self.size == 0 { - #| return other - #| } - #| for i in 0.. HashMap[K, V] { - #| let other = { - #| capacity: self.capacity, - #| entries: FixedArray::make(self.capacity, None), - #| size: self.size, - #| capacity_mask: self.capacity_mask, - #| } - #| if self.size == 0 { - #| return other - #| } - #| for i in 0.. HashMap[K, V] { - #| let result = self.copy() - #| result.merge_in_place(other) - #| result - #|} - #|pub fn[K : Eq, V] HashMap::merge_in_place( - #| self : HashMap[K, V], - #| other : HashMap[K, V], - #|) -> Unit { - #| for entry in other.entries { - #| if entry is Some({ key, value, hash, .. }) { - #| self.set_with_hash(key, value, hash) - #| } - #| } - #|} - #|priv struct MyString(String) derive(Eq) - #|#coverage.skip - #|impl Hash for MyString with hash(self) { - #| let MyString(self) = self - #| self.length() - #|} - #|#coverage.skip - #|impl Hash for MyString with hash_combine(self, hasher) { - #| hasher.combine_string(self.0) - #|} - #|#coverage.skip - #|impl Show for MyString with output(self, logger) { - #| logger.write_string(self.0) - #|} - #|fn[K : Hash + Eq, V : Eq] verify_content( - #| map : HashMap[K, V], - #| expected : Array[(K, V)], - #|) -> Unit raise { - #| for entry in expected { - #| let (k, v) = entry - #| assert_true(map.contains_kv(k, v)) - #| } - #| assert_eq(map.length(), expected.length()) - #|} - #|test "arbitrary" { - #| let samples : Array[HashMap[String, Int]] = @quickcheck.samples(20) - #| let data = [ - #| [], - #| [], - #| [], - #| [("", 0)], - #| [("", 0)], - #| [], - #| [], - #| [("", 0)], - #| [("", 0)], - #| [("", 0)], - #| [("}\u{11}e", -1), ("", 0), ("0f", -1), ("k", -2)], - #| [("Q", 1), ("", 0), ("\u{1e}", 0)], - #| [("", 0)], - #| [("F:", 0), ("A&", 2), ("v\b", 0), ("", 0), ("#", 0)], - #| [("p(", -2), ("^\u{1e}", 3), ("2x", 1), ("", 3)], - #| [("A", -3), ("", 0), ("/w", 0), ("lD", 0), ("jlF0", 3)], - #| [ - #| ("zd", 2), - #| ("[z\r]j", 4), - #| ("\u{1d}r", -3), - #| ("", 0), - #| ("p=61s\u{14}", -7), - #| ("t|,7X4\"\u{14}", -10), - #| ("HeH\b\u{15}d", 1), - #| ("LC\u{19}", 1), - #| ("\u{0b}", 0), - #| ("\n", 0), - #| ("3", -9), - #| ("v", -1), - #| ], - #| [ - #| ("", -1), - #| ("&\b", -4), - #| ("ob%>j\bD?xboR5", 0), - #| (";:B", -3), - #| ("`", 1), - #| ("OwQCP+@", -1), - #| ("O]k", -3), - #| ("\n^", -3), - #| ("U_-*\u{1c}x\u{18}", -11), - #| ("shU^\u{1d}hd8\u{1d}", 0), - #| ("!\u{1b}63p", 3), - #| ("q", 1), - #| ("R@", 4), - #| ], - #| [("", -4), ("v", -2), (")xh", 1), ("C\u{10}\u{0e}", -3), ("|", 0)], - #| [("", 1), ("b", -1)], - #| ] - #| for i in 0.. 1), content="1") - #| inspect(m.get("a"), content="Some(1)") - #| inspect(m.get_or_init("a", () => 2), content="1") - #| inspect(m.get("a"), content="Some(1)") - #|} - ), - "json.mbt": ( - #|pub impl[K : Show, V : ToJson] ToJson for HashMap[K, V] with to_json(self) { - #| let object = Map::new(capacity=self.capacity) - #| for k, v in self { - #| object[k.to_string()] = v.to_json() - #| } - #| Json::object(object) - #|} - ), - "types.mbt": ( - #|priv struct Entry[K, V] { - #| mut psl : Int - #| hash : Int - #| key : K - #| mut value : V - #|} derive(Show) - #|#alias(T, deprecated) - #|struct HashMap[K, V] { - #| mut entries : FixedArray[Entry[K, V]?] - #| mut capacity : Int - #| mut capacity_mask : Int // capacity_mask = capacity - 1, used to find idx - #| mut size : Int // active key-value pairs count - #|} - #|pub impl[K : Hash + Eq, V : Eq] Eq for HashMap[K, V] with equal( - #| self : HashMap[K, V], - #| that : HashMap[K, V], - #|) -> Bool { - #| guard self.size == that.size else { return false } - #| for k, v in self { - #| guard that.contains_kv(k, v) else { return false } - #| } else { - #| true - #| } - #|} - ), - "utils.mbt": ( - #|fn[K : Show, V : Show] HashMap::_debug_entries(self : HashMap[K, V]) -> String { - #| for s = "", i = 0; i < self.entries.length(); { - #| let s = if i > 0 { s + "," } else { s } - #| match self.entries[i] { - #| None => continue s + "_", i + 1 - #| Some({ psl, key, value, .. }) => - #| continue s + "(\{psl},\{key},\{value})", i + 1 - #| } - #| } else { - #| s - #| } - #|} - #|pub fn[K, V] HashMap::clear(self : HashMap[K, V]) -> Unit { - #| self.entries.fill(None) - #| self.size = 0 - #|} - #|pub fn[K, V] HashMap::iter(self : HashMap[K, V]) -> Iter[(K, V)] { - #| self.iterator().iter() - #|} - #|pub fn[K, V] HashMap::iterator(self : HashMap[K, V]) -> Iterator[(K, V)] { - #| let mut i = 0 - #| let len = self.entries.length() - #| Iterator::new(fn() { - #| while i < len { - #| let entry = self.entries.unsafe_get(i) - #| i += 1 - #| if entry is Some({ key, value, .. }) { - #| return Some((key, value)) - #| } - #| } else { - #| None - #| } - #| }) - #|} - #|pub fn[K, V] HashMap::Iter2(self : HashMap[K, V]) -> Iter2[K, V] { - #| self.iterator() - #|} - #|pub fn[K, V] HashMap::iter2(self : HashMap[K, V]) -> Iter2[K, V] { - #| self.Iter2().iter2() - #|} - #|#as_free_fn - #|pub fn[K : Hash + Eq, V] HashMap::from_iter( - #| iter : Iter[(K, V)], - #|) -> HashMap[K, V] { - #| let m = new() - #| iter.each(e => m[e.0] = e.1) - #| m - #|} - #|#as_free_fn - #|pub fn[K : Hash + Eq, V] HashMap::from_iterator( - #| iter : Iterator[(K, V)], - #|) -> HashMap[K, V] { - #| let m = new() - #| while iter.next() is Some((k, v)) { - #| m[k] = v - #| } - #| m - #|} - #|pub fn[K, V] HashMap::to_array(self : HashMap[K, V]) -> Array[(K, V)] { - #| let mut i = 0 - #| let res = while i < self.capacity { - #| if self.entries[i] is Some({ key, value, .. }) { - #| i += 1 - #| break Array::make(self.size, (key, value)) - #| } - #| i += 1 - #| } else { - #| [] - #| } - #| if !res.is_empty() { - #| let mut res_idx = 1 - #| while res_idx < res.length() && i < self.capacity { - #| if self.entries[i] is Some({ key, value, .. }) { - #| res[res_idx] = (key, value) - #| res_idx += 1 - #| } - #| i += 1 - #| } - #| } - #| res - #|} - #|#alias(size, deprecated) - #|pub fn[K, V] HashMap::length(self : HashMap[K, V]) -> Int { - #| self.size - #|} - #|pub fn[K, V] HashMap::capacity(self : HashMap[K, V]) -> Int { - #| self.capacity - #|} - #|pub fn[K, V] HashMap::is_empty(self : HashMap[K, V]) -> Bool { - #| self.size == 0 - #|} - #|#locals(f) - #|pub fn[K, V] HashMap::each( - #| self : HashMap[K, V], - #| f : (K, V) -> Unit raise?, - #|) -> Unit raise? { - #| for i in 0.. Unit raise?, - #|) -> Unit raise? { - #| for i = 0, idx = 0; i < self.capacity; { - #| match self.entries[i] { - #| Some({ key, value, .. }) => { - #| f(idx, key, value) - #| continue i + 1, idx + 1 - #| } - #| None => continue i + 1, idx - #| } - #| } - #|} - #|pub impl[K : Show, V : Show] Show for HashMap[K, V] with output(self, logger) { - #| logger.write_string("HashMap::from_array([") - #| self.eachi((i, k, v) => { - #| if i > 0 { - #| logger.write_string(", ") - #| } - #| logger - #| ..write_string("(") - #| ..write_object(k) - #| ..write_string(", ") - #| ..write_object(v) - #| ..write_string(")") - #| }) - #| logger.write_string("])") - #|} - #|pub fn[K, V] HashMap::keys(self : HashMap[K, V]) -> Iter[K] { - #| let mut i = 0 - #| let iter = Iterator::new(() => while i < self.entries.length() { - #| let entry = self.entries[i] - #| i += 1 - #| if entry is Some({ key, .. }) { - #| break Some(key) - #| } - #| } else { - #| None - #| }) - #| iter.iter() - #|} - #|pub fn[K, V] HashMap::values(self : HashMap[K, V]) -> Iter[V] { - #| let mut i = 0 - #| let iter = Iterator::new(() => while i < self.entries.length() { - #| let entry = self.entries[i] - #| i += 1 - #| if entry is Some({ value, .. }) { - #| break Some(value) - #| } - #| } else { - #| None - #| }) - #| iter.iter() - #|} - #|#locals(f) - #|pub fn[K, V] HashMap::retain(self : HashMap[K, V], f : (K, V) -> Bool) -> Unit { - #| let size = self.size - #| let mut j = 0 - #| for i = 0; j < size; i = i + 1 { - #| while self.entries[i] is Some(entry) { - #| j = j + 1 - #| if f(entry.key, entry.value) { - #| break - #| } else { - #| self.shift_back(i) - #| self.size -= 1 - #| } - #| } - #| } - #|} - #|test "retain" { - #| let hashmap : HashMap[String, Int] = { - #| capacity: 8, - #| capacity_mask: 7, - #| size: 4, - #| entries: [ - #| Some({ psl: 2, hash: 448974246, key: "c", value: 3 }), - #| Some({ psl: 2, hash: -136509641, key: "d", value: 4 }), - #| None, - #| None, - #| None, - #| None, - #| Some({ psl: 0, hash: 1614946358, key: "a", value: 1 }), - #| Some({ psl: 1, hash: -765931946, key: "b", value: 2 }), - #| ], - #| } - #| hashmap.retain((_k, v) => v % 2 == 0) - #| inspect( - #| hashmap.entries, - #| content=( - #| #|[None, None, None, None, None, None, Some({psl: 0, hash: -765931946, key: "b", value: 2}), Some({psl: 0, hash: -136509641, key: "d", value: 4})] - #| ), - #| ) - #|} - ), - }, + "deprecated.mbt": "", + "hashmap.mbt": ( + #|#as_free_fn + #|pub fn[K, V] HashMap::new(capacity? : Int = 8) -> HashMap[K, V] { + #| let capacity = capacity.next_power_of_two() + #| { + #| size: 0, + #| capacity, + #| entries: FixedArray::make(capacity, None), + #| capacity_mask: capacity - 1, + #| } + #|} + #|#as_free_fn + #|#alias(of, deprecated="Use from_array instead") + #|#as_free_fn(of, deprecated="Use from_array instead") + #|pub fn[K : Hash + Eq, V] HashMap::from_array( + #| arr : ArrayView[(K, V)], + #|) -> HashMap[K, V] { + #| let m = new(capacity=arr.length() * 2) + #| arr.each(e => m.set(e.0, e.1)) + #| m + #|} + #|#alias("_[_]=_") + #|pub fn[K : Hash + Eq, V] HashMap::set( + #| self : HashMap[K, V], + #| key : K, + #| value : V, + #|) -> Unit { + #| self.set_with_hash(key, value, key.hash()) + #|} + #|fn[K : Eq, V] HashMap::set_with_hash( + #| self : HashMap[K, V], + #| key : K, + #| value : V, + #| hash : Int, + #|) -> Unit { + #| for psl = 0, idx = hash & self.capacity_mask { + #| match self.entries[idx] { + #| None => { + #| if self.size >= self.capacity / 2 { + #| self.grow() + #| continue 0, hash & self.capacity_mask + #| } + #| let entry = { psl, key, value, hash } + #| self.entries[idx] = Some(entry) + #| self.size += 1 + #| return + #| } + #| Some(curr_entry) => { + #| if curr_entry.hash == hash && curr_entry.key == key { + #| curr_entry.value = value + #| return + #| } + #| if psl > curr_entry.psl { + #| if self.size >= self.capacity / 2 { + #| self.grow() + #| continue 0, hash & self.capacity_mask + #| } + #| self.push_away(idx, curr_entry) + #| let entry = { psl, key, value, hash } + #| self.entries[idx] = Some(entry) + #| self.size += 1 + #| return + #| } + #| continue psl + 1, (idx + 1) & self.capacity_mask + #| } + #| } + #| } + #|} + #|fn[K, V] HashMap::push_away( + #| self : HashMap[K, V], + #| idx : Int, + #| entry : Entry[K, V], + #|) -> Unit { + #| for psl = entry.psl + 1, idx = (idx + 1) & self.capacity_mask, entry = entry { + #| match self.entries[idx] { + #| None => { + #| entry.psl = psl + #| self.entries[idx] = Some(entry) + #| break + #| } + #| Some(curr_entry) => + #| if psl > curr_entry.psl { + #| entry.psl = psl + #| self.entries[idx] = Some(entry) + #| continue curr_entry.psl + 1, + #| (idx + 1) & self.capacity_mask, + #| curr_entry + #| } else { + #| continue psl + 1, (idx + 1) & self.capacity_mask, entry + #| } + #| } + #| } + #|} + #|pub fn[K : Hash + Eq, V] HashMap::get(self : HashMap[K, V], key : K) -> V? { + #| let hash = key.hash() + #| for i = 0, idx = hash & self.capacity_mask { + #| guard self.entries[idx] is Some(entry) else { break None } + #| if entry.hash == hash && entry.key == key { + #| break Some(entry.value) + #| } + #| if i > entry.psl { + #| break None + #| } + #| continue i + 1, (idx + 1) & self.capacity_mask + #| } + #|} + #|#alias("_[_]") + #|pub fn[K : Hash + Eq, V] HashMap::at(self : HashMap[K, V], key : K) -> V { + #| let hash = key.hash() + #| for i = 0, idx = hash & self.capacity_mask { + #| guard self.entries[idx] is Some(entry) + #| if entry.hash == hash && entry.key == key { + #| break entry.value + #| } + #| guard i <= entry.psl + #| continue i + 1, (idx + 1) & self.capacity_mask + #| } + #|} + #|pub fn[K : Hash + Eq, V] HashMap::get_or_init( + #| self : HashMap[K, V], + #| key : K, + #| init : () -> V, + #|) -> V { + #| let hash = key.hash() + #| let (idx, psl, new_value, push_away) = for psl = 0, idx = hash & + #| self.capacity_mask { + #| match self.entries[idx] { + #| Some(entry) => { + #| if entry.hash == hash && entry.key == key { + #| return entry.value + #| } + #| if psl > entry.psl { + #| let new_value = init() + #| break (idx, psl, new_value, Some(entry)) + #| } + #| continue psl + 1, (idx + 1) & self.capacity_mask + #| } + #| None => { + #| let new_value = init() + #| break (idx, psl, new_value, None) + #| } + #| } + #| } + #| if self.size >= self.capacity / 2 { + #| self.grow() + #| self.set_with_hash(key, new_value, hash) + #| } else { + #| if push_away is Some(entry) { + #| self.push_away(idx, entry) + #| } + #| let entry = { psl, hash, key, value: new_value } + #| self.entries[idx] = Some(entry) + #| self.size += 1 + #| } + #| new_value + #|} + #|pub fn[K : Hash + Eq, V] HashMap::get_or_default( + #| self : HashMap[K, V], + #| key : K, + #| default : V, + #|) -> V { + #| let hash = key.hash() + #| for i = 0, idx = hash & self.capacity_mask { + #| guard self.entries[idx] is Some(entry) else { break default } + #| if entry.hash == hash && entry.key == key { + #| break entry.value + #| } + #| if i > entry.psl { + #| break default + #| } + #| continue i + 1, (idx + 1) & self.capacity_mask + #| } + #|} + #|pub fn[K : Hash + Eq, V] HashMap::contains( + #| self : HashMap[K, V], + #| key : K, + #|) -> Bool { + #| let hash = key.hash() + #| for i = 0, idx = hash & self.capacity_mask { + #| guard self.entries[idx] is Some(entry) else { return false } + #| if entry.hash == hash && entry.key == key { + #| return true + #| } + #| if i > entry.psl { + #| return false + #| } + #| continue i + 1, (idx + 1) & self.capacity_mask + #| } + #|} + #|pub fn[K : Hash + Eq, V : Eq] HashMap::contains_kv( + #| self : HashMap[K, V], + #| key : K, + #| value : V, + #|) -> Bool { + #| let hash = key.hash() + #| for i = 0, idx = hash & self.capacity_mask { + #| guard self.entries[idx] is Some(entry) else { return false } + #| if entry.hash == hash && entry.key == key && entry.value == value { + #| return true + #| } + #| if i > entry.psl { + #| return false + #| } + #| continue i + 1, (idx + 1) & self.capacity_mask + #| } + #|} + #|pub fn[K : Hash + Eq, V] HashMap::remove(self : HashMap[K, V], key : K) -> Unit { + #| self.remove_with_hash(key, key.hash()) + #|} + #|fn[K : Eq, V] HashMap::remove_with_hash( + #| self : HashMap[K, V], + #| key : K, + #| hash : Int, + #|) -> Unit { + #| for i = 0, idx = hash & self.capacity_mask { + #| match self.entries[idx] { + #| Some(entry) => { + #| if entry.hash == hash && entry.key == key { + #| self.shift_back(idx) + #| self.size -= 1 + #| break + #| } + #| if i > entry.psl { + #| break + #| } + #| continue i + 1, (idx + 1) & self.capacity_mask + #| } + #| None => break + #| } + #| } + #|} + #|fn[K, V] HashMap::shift_back(self : HashMap[K, V], idx : Int) -> Unit { + #| let next = (idx + 1) & self.capacity_mask + #| match self.entries[next] { + #| None | Some({ psl: 0, .. }) => self.entries[idx] = None + #| Some(entry) => { + #| entry.psl -= 1 + #| self.entries[idx] = Some(entry) + #| self.shift_back(next) + #| } + #| } + #|} + #|fn[K : Eq, V] HashMap::grow(self : HashMap[K, V]) -> Unit { + #| let old_entries = self.entries + #| let new_capacity = self.capacity << 1 + #| self.entries = FixedArray::make(new_capacity, None) + #| self.capacity = new_capacity + #| self.capacity_mask = new_capacity - 1 + #| self.size = 0 + #| for entry in old_entries { + #| if entry is Some({ key, value, hash, .. }) { + #| self.set_with_hash(key, value, hash) + #| } + #| } + #|} + #|test "of" { + #| let m = from_array([(1, 2), (3, 4)]) + #| inspect(m.get(1), content="Some(2)") + #| inspect(m.get(3), content="Some(4)") + #|} + #|pub impl[K : @quickcheck.Arbitrary + Hash + Eq, V : @quickcheck.Arbitrary] @quickcheck.Arbitrary for HashMap[ + #| K, + #| V, + #|] with arbitrary(size, rs) { + #| let m = new() + #| (@quickcheck.Arbitrary::arbitrary(size, rs) : Iter[(K, V)]).each(kv => { + #| m.set(kv.0, kv.1) + #| }) + #| m + #|} + #|pub impl[K, V] Default for HashMap[K, V] with default() { + #| new() + #|} + #|pub fn[K, V, V2] HashMap::map( + #| self : HashMap[K, V], + #| f : (K, V) -> V2, + #|) -> HashMap[K, V2] { + #| let other = { + #| capacity: self.capacity, + #| entries: FixedArray::make(self.capacity, None), + #| size: self.size, + #| capacity_mask: self.capacity_mask, + #| } + #| if self.size == 0 { + #| return other + #| } + #| for i in 0.. HashMap[K, V] { + #| let other = { + #| capacity: self.capacity, + #| entries: FixedArray::make(self.capacity, None), + #| size: self.size, + #| capacity_mask: self.capacity_mask, + #| } + #| if self.size == 0 { + #| return other + #| } + #| for i in 0.. HashMap[K, V] { + #| let result = self.copy() + #| result.merge_in_place(other) + #| result + #|} + #|pub fn[K : Eq, V] HashMap::merge_in_place( + #| self : HashMap[K, V], + #| other : HashMap[K, V], + #|) -> Unit { + #| if physical_equal(self, other) { + #| return + #| } + #| for entry in other.entries { + #| if entry is Some({ key, value, hash, .. }) { + #| self.set_with_hash(key, value, hash) + #| } + #| } + #|} + #|priv struct MyString(String) derive(Eq) + #|#coverage.skip + #|impl Hash for MyString with hash(self) { + #| let MyString(self) = self + #| self.length() + #|} + #|#coverage.skip + #|impl Hash for MyString with hash_combine(self, hasher) { + #| hasher.combine_string(self.0) + #|} + #|#coverage.skip + #|impl Show for MyString with output(self, logger) { + #| logger.write_string(self.0) + #|} + #|fn[K : Hash + Eq, V : Eq] verify_content( + #| map : HashMap[K, V], + #| expected : Array[(K, V)], + #|) -> Unit raise { + #| for entry in expected { + #| let (k, v) = entry + #| assert_true(map.contains_kv(k, v)) + #| } + #| assert_eq(map.length(), expected.length()) + #|} + #|test "arbitrary" { + #| let samples : Array[HashMap[String, Int]] = @quickcheck.samples(20) + #| let data = [ + #| [], + #| [], + #| [], + #| [("", 0)], + #| [("", 0)], + #| [], + #| [], + #| [("", 0)], + #| [("", 0)], + #| [("", 0)], + #| [("}\u{11}e", -1), ("", 0), ("0f", -1), ("k", -2)], + #| [("Q", 1), ("", 0), ("\u{1e}", 0)], + #| [("", 0)], + #| [("F:", 0), ("A&", 2), ("v\b", 0), ("", 0), ("#", 0)], + #| [("p(", -2), ("^\u{1e}", 3), ("2x", 1), ("", 3)], + #| [("A", -3), ("", 0), ("/w", 0), ("lD", 0), ("jlF0", 3)], + #| [ + #| ("zd", 2), + #| ("[z\r]j", 4), + #| ("\u{1d}r", -3), + #| ("", 0), + #| ("p=61s\u{14}", -7), + #| ("t|,7X4\"\u{14}", -10), + #| ("HeH\b\u{15}d", 1), + #| ("LC\u{19}", 1), + #| ("\u{0b}", 0), + #| ("\n", 0), + #| ("3", -9), + #| ("v", -1), + #| ], + #| [ + #| ("", -1), + #| ("&\b", -4), + #| ("ob%>j\bD?xboR5", 0), + #| (";:B", -3), + #| ("`", 1), + #| ("OwQCP+@", -1), + #| ("O]k", -3), + #| ("\n^", -3), + #| ("U_-*\u{1c}x\u{18}", -11), + #| ("shU^\u{1d}hd8\u{1d}", 0), + #| ("!\u{1b}63p", 3), + #| ("q", 1), + #| ("R@", 4), + #| ], + #| [("", -4), ("v", -2), (")xh", 1), ("C\u{10}\u{0e}", -3), ("|", 0)], + #| [("", 1), ("b", -1)], + #| ] + #| for i, sample in samples { + #| verify_content(sample, data[i]) + #| } + #|} + #|test "set" { + #| let m : HashMap[MyString, Int] = new() + #| m.set("a", 1) + #| m.set("b", 1) + #| m.set("bc", 2) + #| m.set("abc", 3) + #| m.set("cd", 2) + #| m.set("c", 1) + #| m.set("d", 1) + #| inspect(m.length(), content="7") + #|} + #|test "remove" { + #| let m : HashMap[MyString, Int] = new() + #| m.set("a", 1) + #| m.set("ab", 2) + #| m.set("bc", 2) + #| m.set("cd", 2) + #| m.set("abc", 3) + #| m.set("abcdef", 6) + #| m.remove("ab") + #| inspect(m.length(), content="5") + #|} + #|test "remove_unexist_key" { + #| let m : HashMap[MyString, Int] = new() + #| m.set("a", 1) + #| m.set("ab", 2) + #| m.set("abc", 3) + #| m.remove("d") + #| inspect(m.length(), content="3") + #|} + #|test "clear" { + #| let m : HashMap[MyString, Int] = from_array([("a", 1), ("b", 2), ("c", 3)]) + #| m.clear() + #| inspect(m.length(), content="0") + #| inspect(m.capacity(), content="8") + #| for entry in m.entries { + #| @test.same_object(entry, None) + #| } + #|} + #|test "grow" { + #| let m : HashMap[MyString, Int] = new() + #| m.set("C", 1) + #| m.set("Go", 2) + #| m.set("C++", 3) + #| m.set("Java", 4) + #| m.set("Scala", 5) + #| m.set("Julia", 5) + #| inspect(m.length(), content="6") + #| inspect(m.capacity(), content="16") + #| m.set("Cobol", 5) + #| inspect(m.length(), content="7") + #| inspect(m.capacity(), content="16") + #| m.set("Python", 6) + #| m.set("Haskell", 7) + #| m.set("Rescript", 8) + #| inspect(m.length(), content="10") + #| inspect(m.capacity(), content="32") + #| inspect(m.get("C"), content="Some(1)") + #| inspect(m.get("Go"), content="Some(2)") + #| inspect(m.get("C++"), content="Some(3)") + #| inspect(m.get("Java"), content="Some(4)") + #| inspect(m.get("Scala"), content="Some(5)") + #| inspect(m.get("Julia"), content="Some(5)") + #| inspect(m.get("Cobol"), content="Some(5)") + #| inspect(m.get("Python"), content="Some(6)") + #| inspect(m.get("Haskell"), content="Some(7)") + #| inspect(m.get("Rescript"), content="Some(8)") + #|} + #|test "_[_]" { + #| let m : HashMap[MyString, Int] = new() + #| m.set("a", 1) + #| m.set("b", 1) + #| m.set("cc", 2) + #| inspect(m["a"], content="1") + #| inspect(m["b"], content="1") + #| inspect(m["cc"], content="2") + #|} + #|test "get_or_init" { + #| let m : HashMap[MyString, Int] = new() + #| inspect(m.get_or_init("a", () => 1), content="1") + #| inspect(m.get("a"), content="Some(1)") + #| inspect(m.get_or_init("a", () => 2), content="1") + #| inspect(m.get("a"), content="Some(1)") + #|} + ), + "json.mbt": ( + #|pub impl[K : Show, V : ToJson] ToJson for HashMap[K, V] with to_json(self) { + #| let object = Map::new(capacity=self.capacity) + #| for k, v in self { + #| object[k.to_string()] = v.to_json() + #| } + #| Json::object(object) + #|} + ), + "types.mbt": ( + #|priv struct Entry[K, V] { + #| mut psl : Int + #| hash : Int + #| key : K + #| mut value : V + #|} derive(Show) + #|#alias(T, deprecated) + #|struct HashMap[K, V] { + #| mut entries : FixedArray[Entry[K, V]?] + #| mut capacity : Int + #| mut capacity_mask : Int // capacity_mask = capacity - 1, used to find idx + #| mut size : Int // active key-value pairs count + #|} + #|pub impl[K : Hash + Eq, V : Eq] Eq for HashMap[K, V] with equal( + #| self : HashMap[K, V], + #| that : HashMap[K, V], + #|) -> Bool { + #| guard self.size == that.size else { return false } + #| for k, v in self { + #| guard that.contains_kv(k, v) else { return false } + #| } nobreak { + #| true + #| } + #|} + ), + "utils.mbt": ( + #|fn[K : Show, V : Show] HashMap::_debug_entries(self : HashMap[K, V]) -> String { + #| for s = "", i = 0; i < self.entries.length(); { + #| let s = if i > 0 { s + "," } else { s } + #| match self.entries[i] { + #| None => continue s + "_", i + 1 + #| Some({ psl, key, value, .. }) => + #| continue s + "(\{psl},\{key},\{value})", i + 1 + #| } + #| } nobreak { + #| s + #| } + #|} + #|pub fn[K, V] HashMap::clear(self : HashMap[K, V]) -> Unit { + #| self.entries.fill(None) + #| self.size = 0 + #|} + #|#alias(iterator, deprecated) + #|pub fn[K, V] HashMap::iter(self : HashMap[K, V]) -> Iter[(K, V)] { + #| let mut i = 0 + #| let len = self.entries.length() + #| Iter::new(fn() { + #| while i < len { + #| let entry = self.entries.unsafe_get(i) + #| i += 1 + #| if entry is Some({ key, value, .. }) { + #| return Some((key, value)) + #| } + #| } nobreak { + #| None + #| } + #| }) + #|} + #|#alias(iterator2, deprecated) + #|pub fn[K, V] HashMap::iter2(self : HashMap[K, V]) -> Iter2[K, V] { + #| self.iter() + #|} + #|#as_free_fn + #|#alias(from_iterator, deprecated) + #|#as_free_fn(from_iterator, deprecated) + #|pub fn[K : Hash + Eq, V] HashMap::from_iter( + #| iter : Iter[(K, V)], + #|) -> HashMap[K, V] { + #| let m = new() + #| while iter.next() is Some((k, v)) { + #| m[k] = v + #| } + #| m + #|} + #|pub fn[K, V] HashMap::to_array(self : HashMap[K, V]) -> Array[(K, V)] { + #| let mut i = 0 + #| let res = while i < self.capacity { + #| if self.entries[i] is Some({ key, value, .. }) { + #| i += 1 + #| break Array::make(self.size, (key, value)) + #| } + #| i += 1 + #| } nobreak { + #| [] + #| } + #| if !res.is_empty() { + #| let mut res_idx = 1 + #| while res_idx < res.length() && i < self.capacity { + #| if self.entries[i] is Some({ key, value, .. }) { + #| res[res_idx] = (key, value) + #| res_idx += 1 + #| } + #| i += 1 + #| } + #| } + #| res + #|} + #|#alias(size, deprecated) + #|pub fn[K, V] HashMap::length(self : HashMap[K, V]) -> Int { + #| self.size + #|} + #|pub fn[K, V] HashMap::capacity(self : HashMap[K, V]) -> Int { + #| self.capacity + #|} + #|pub fn[K, V] HashMap::is_empty(self : HashMap[K, V]) -> Bool { + #| self.size == 0 + #|} + #|#locals(f) + #|pub fn[K, V] HashMap::each( + #| self : HashMap[K, V], + #| f : (K, V) -> Unit raise?, + #|) -> Unit raise? { + #| for i in 0.. Unit raise?, + #|) -> Unit raise? { + #| for i = 0, idx = 0; i < self.capacity; { + #| match self.entries[i] { + #| Some({ key, value, .. }) => { + #| f(idx, key, value) + #| continue i + 1, idx + 1 + #| } + #| None => continue i + 1, idx + #| } + #| } + #|} + #|pub impl[K : Show, V : Show] Show for HashMap[K, V] with output(self, logger) { + #| logger.write_string("HashMap::from_array([") + #| self.eachi((i, k, v) => { + #| if i > 0 { + #| logger.write_string(", ") + #| } + #| logger.write_string("(") + #| logger.write_object(k) + #| logger.write_string(", ") + #| logger.write_object(v) + #| logger.write_string(")") + #| }) + #| logger.write_string("])") + #|} + #|pub fn[K, V] HashMap::keys(self : HashMap[K, V]) -> Iter[K] { + #| let mut i = 0 + #| let iter = Iter::new(() => { + #| while i < self.entries.length() { + #| let entry = self.entries[i] + #| i += 1 + #| if entry is Some({ key, .. }) { + #| break Some(key) + #| } + #| } nobreak { + #| None + #| } + #| }) + #| iter.iter() + #|} + #|pub fn[K, V] HashMap::values(self : HashMap[K, V]) -> Iter[V] { + #| let mut i = 0 + #| let iter = Iter::new(() => { + #| while i < self.entries.length() { + #| let entry = self.entries[i] + #| i += 1 + #| if entry is Some({ value, .. }) { + #| break Some(value) + #| } + #| } nobreak { + #| None + #| } + #| }) + #| iter.iter() + #|} + #|#locals(f) + #|pub fn[K, V] HashMap::retain(self : HashMap[K, V], f : (K, V) -> Bool) -> Unit { + #| let size = self.size + #| let mut j = 0 + #| for i = 0; j < size; i = i + 1 { + #| while self.entries[i] is Some(entry) { + #| j = j + 1 + #| if f(entry.key, entry.value) { + #| break + #| } else { + #| self.shift_back(i) + #| self.size -= 1 + #| } + #| } + #| } + #|} + #|test "retain" { + #| let hashmap : HashMap[String, Int] = { + #| capacity: 8, + #| capacity_mask: 7, + #| size: 4, + #| entries: [ + #| Some({ psl: 2, hash: 448974246, key: "c", value: 3 }), + #| Some({ psl: 2, hash: -136509641, key: "d", value: 4 }), + #| None, + #| None, + #| None, + #| None, + #| Some({ psl: 0, hash: 1614946358, key: "a", value: 1 }), + #| Some({ psl: 1, hash: -765931946, key: "b", value: 2 }), + #| ], + #| } + #| hashmap.retain((_k, v) => v % 2 == 0) + #| inspect( + #| hashmap.entries, + #| content=( + #| #|[None, None, None, None, None, None, Some({psl: 0, hash: -765931946, key: "b", value: 2}), Some({psl: 0, hash: -136509641, key: "d", value: 4})] + #| ), + #| ) + #|} + ) + } ) ///| let moonbitlang_core_hashset_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/hashset", - deps={ - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/test": moonbitlang_core_test_module, - "moonbitlang/core/array": moonbitlang_core_array_module, - "moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module, - }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| "moonbitlang/core/builtin", - #| "moonbitlang/core/test", - #| "moonbitlang/core/array", - #| "moonbitlang/core/quickcheck" - #| ], - #| "test-import": [ - #| "moonbitlang/core/string", - #| "moonbitlang/core/int", - #| "moonbitlang/core/json" - #| ] - #|} - ), - "deprecated.mbt": "", - "hashset.mbt": ( - #|let default_init_capacity = 8 - #|#as_free_fn - #|pub fn[K] HashSet::new(capacity? : Int = default_init_capacity) -> HashSet[K] { - #| let capacity = capacity.next_power_of_two() - #| { - #| size: 0, - #| capacity, - #| capacity_mask: capacity - 1, - #| grow_at: calc_grow_threshold(capacity), - #| entries: FixedArray::make(capacity, None), - #| } - #|} - #|#as_free_fn - #|#alias(of, deprecated="Use from_array instead") - #|#as_free_fn(of, deprecated="Use from_array instead") - #|pub fn[K : Hash + Eq] HashSet::from_array(arr : ArrayView[K]) -> HashSet[K] { - #| let m = new() - #| arr.each(e => m.add(e)) - #| m - #|} - #|#alias(insert, deprecated) - #|pub fn[K : Hash + Eq] HashSet::add(self : HashSet[K], key : K) -> Unit { - #| self.add_with_hash(key, key.hash()) - #|} - #|fn[K : Eq] HashSet::add_with_hash( - #| self : HashSet[K], - #| key : K, - #| hash : Int, - #|) -> Unit { - #| if self.size >= self.grow_at { - #| self.grow() - #| } - #| let (idx, psl) = for psl = 0, idx = hash & self.capacity_mask { - #| match self.entries[idx] { - #| None => break (idx, psl) - #| Some(curr_entry) => { - #| if curr_entry.hash == hash && curr_entry.key == key { - #| return - #| } - #| if psl > curr_entry.psl { - #| self.push_away(idx, curr_entry) - #| break (idx, psl) - #| } - #| continue psl + 1, (idx + 1) & self.capacity_mask - #| } - #| } - #| } - #| let entry = { psl, key, hash } - #| self.set_entry(entry, idx) - #| self.size += 1 - #|} - #|fn[K] HashSet::push_away( - #| self : HashSet[K], - #| idx : Int, - #| entry : Entry[K], - #|) -> Unit { - #| for psl = entry.psl + 1, idx = (idx + 1) & self.capacity_mask, entry = entry { - #| match self.entries[idx] { - #| None => { - #| entry.psl = psl - #| self.set_entry(entry, idx) - #| break - #| } - #| Some(curr_entry) => - #| if psl > curr_entry.psl { - #| entry.psl = psl - #| self.set_entry(entry, idx) - #| continue curr_entry.psl + 1, - #| (idx + 1) & self.capacity_mask, - #| curr_entry - #| } else { - #| continue psl + 1, (idx + 1) & self.capacity_mask, entry - #| } - #| } - #| } - #|} - #|#inline - #|fn[K] HashSet::set_entry( - #| self : HashSet[K], - #| entry : Entry[K], - #| new_idx : Int, - #|) -> Unit { - #| self.entries[new_idx] = Some(entry) - #|} - #|pub fn[K : Hash + Eq] HashSet::contains(self : HashSet[K], key : K) -> Bool { - #| let hash = key.hash() - #| for i = 0, idx = hash & self.capacity_mask { - #| guard self.entries[idx] is Some(entry) else { break false } - #| if entry.hash == hash && entry.key == key { - #| break true - #| } - #| if i > entry.psl { - #| break false - #| } - #| continue i + 1, (idx + 1) & self.capacity_mask - #| } - #|} - #|pub fn[K : Hash + Eq] HashSet::remove(self : HashSet[K], key : K) -> Unit { - #| let hash = key.hash() - #| for i = 0, idx = hash & self.capacity_mask { - #| guard self.entries[idx] is Some(entry) else { break } - #| if entry.hash == hash && entry.key == key { - #| self.shift_back(idx) - #| self.size -= 1 - #| break - #| } - #| if i > entry.psl { - #| break - #| } - #| continue i + 1, (idx + 1) & self.capacity_mask - #| } - #|} - #|fn[K] HashSet::shift_back(self : HashSet[K], idx : Int) -> Unit { - #| let next = (idx + 1) & self.capacity_mask - #| match self.entries[next] { - #| None | Some({ psl: 0, .. }) => self.entries[idx] = None - #| Some(entry) => { - #| entry.psl -= 1 - #| self.set_entry(entry, idx) - #| self.shift_back(next) - #| } - #| } - #|} - #|fn[K : Eq] HashSet::grow(self : HashSet[K]) -> Unit { - #| if self.capacity == 0 { - #| self.capacity = default_init_capacity - #| self.capacity_mask = self.capacity - 1 - #| self.grow_at = calc_grow_threshold(self.capacity) - #| self.size = 0 - #| self.entries = FixedArray::make(self.capacity, None) - #| return - #| } - #| let old_entries = self.entries - #| self.entries = FixedArray::make(self.capacity * 2, None) - #| self.capacity = self.capacity * 2 - #| self.capacity_mask = self.capacity - 1 - #| self.grow_at = calc_grow_threshold(self.capacity) - #| self.size = 0 - #| for i in 0.. Int { - #| self.size - #|} - #|pub fn[K] HashSet::capacity(self : HashSet[K]) -> Int { - #| self.capacity - #|} - #|pub fn[K] HashSet::is_empty(self : HashSet[K]) -> Bool { - #| self.size == 0 - #|} - #|#locals(f) - #|pub fn[K] HashSet::each( - #| self : HashSet[K], - #| f : (K) -> Unit raise?, - #|) -> Unit raise? { - #| for entry in self.entries { - #| if entry is Some({ key, .. }) { - #| f(key) - #| } - #| } - #|} - #|#locals(f) - #|pub fn[K] HashSet::eachi( - #| self : HashSet[K], - #| f : (Int, K) -> Unit raise?, - #|) -> Unit raise? { - #| let mut idx = 0 - #| for i in 0.. Unit { - #| self.entries.fill(None) - #| self.size = 0 - #|} - #|pub fn[K] HashSet::iter(self : HashSet[K]) -> Iter[K] { - #| self.iterator().iter() - #|} - #|pub fn[K] HashSet::iterator(self : HashSet[K]) -> Iterator[K] { - #| let mut i = 0 - #| let len = self.entries.length() - #| Iterator::new(fn() { - #| while i < len { - #| let entry = self.entries.unsafe_get(i) - #| i += 1 - #| if entry is Some({ key, .. }) { - #| return Some(key) - #| } - #| } else { - #| None - #| } - #| }) - #|} - #|pub fn[K] HashSet::to_array(self : HashSet[K]) -> Array[K] { - #| let arr = Array::new(capacity=self.size) - #| for entry in self.entries { - #| if entry is Some({ key, .. }) { - #| arr.push(key) - #| } - #| } - #| arr - #|} - #|#as_free_fn - #|pub fn[K : Hash + Eq] HashSet::from_iter(iter : Iter[K]) -> HashSet[K] { - #| let s = new() - #| iter.each(e => s.add(e)) - #| s - #|} - #|#as_free_fn - #|pub fn[K : Hash + Eq] HashSet::from_iterator(iter : Iterator[K]) -> HashSet[K] { - #| let s = new() - #| while iter.next() is Some(e) { - #| s.add(e) - #| } - #| s - #|} - #|pub fn[K : Hash + Eq] HashSet::union( - #| self : HashSet[K], - #| other : HashSet[K], - #|) -> HashSet[K] { - #| let m = new() - #| self.each(k => m.add(k)) - #| other.each(k => m.add(k)) - #| m - #|} - #|pub fn[K : Hash + Eq] HashSet::intersection( - #| self : HashSet[K], - #| other : HashSet[K], - #|) -> HashSet[K] { - #| let m = new() - #| self.each(k => if other.contains(k) { m.add(k) }) - #| m - #|} - #|pub fn[K : Hash + Eq] HashSet::difference( - #| self : HashSet[K], - #| other : HashSet[K], - #|) -> HashSet[K] { - #| let m = new() - #| self.each(k => if !other.contains(k) { m.add(k) }) - #| m - #|} - #|pub fn[K : Hash + Eq] HashSet::symmetric_difference( - #| self : HashSet[K], - #| other : HashSet[K], - #|) -> HashSet[K] { - #| let m = new() - #| self.each(k => if !other.contains(k) { m.add(k) }) - #| other.each(k => if !self.contains(k) { m.add(k) }) - #| m - #|} - #|pub fn[K : Hash + Eq] HashSet::is_disjoint( - #| self : HashSet[K], - #| other : HashSet[K], - #|) -> Bool { - #| if self.length() <= other.length() { - #| self.iter().all(k => !other.contains(k)) - #| } else { - #| other.iter().all(k => !self.contains(k)) - #| } - #|} - #|pub fn[K : Hash + Eq] HashSet::is_subset( - #| self : HashSet[K], - #| other : HashSet[K], - #|) -> Bool { - #| if self.length() <= other.length() { - #| self.iter().all(k => other.contains(k)) - #| } else { - #| false - #| } - #|} - #|pub fn[K : Hash + Eq] HashSet::is_superset( - #| self : HashSet[K], - #| other : HashSet[K], - #|) -> Bool { - #| other.is_subset(self) - #|} - #|pub impl[K : Hash + Eq] BitAnd for HashSet[K] with land(self, other) { - #| self.intersection(other) - #|} - #|pub impl[K : Hash + Eq] BitOr for HashSet[K] with lor(self, other) { - #| self.union(other) - #|} - #|pub impl[K : Hash + Eq] BitXOr for HashSet[K] with lxor(self, other) { - #| self.symmetric_difference(other) - #|} - #|pub impl[K : Hash + Eq] Sub for HashSet[K] with sub(self, other) { - #| self.difference(other) - #|} - #|pub impl[X : @quickcheck.Arbitrary + Eq + Hash] @quickcheck.Arbitrary for HashSet[ - #| X, - #|] with arbitrary(size, rs) { - #| @quickcheck.Arbitrary::arbitrary(size, rs) |> from_iter - #|} - #|fn calc_grow_threshold(capacity : Int) -> Int { - #| capacity * 13 / 16 - #|} - #|fn[K : Show] HashSet::_debug_entries(self : HashSet[K]) -> String { - #| let mut s = "" - #| for i in 0.. 0 { - #| s += "," - #| } - #| match self.entries[i] { - #| None => s += "_" - #| Some({ psl, key, .. }) => s += "(\{psl},\{key})" - #| } - #| } - #| s - #|} - #|priv struct MyString(String) derive(Eq) - #|impl Hash for MyString with hash(self) { - #| let MyString(self) = self - #| self.length() - #|} - #|impl Hash for MyString with hash_combine(self, hasher) { - #| let MyString(self) = self - #| hasher.combine_string(self) - #|} - #|impl Show for MyString with output(self, logger) { - #| let MyString(self) = self - #| logger.write_string(self) - #|} - #|test "set" { - #| let m : HashSet[MyString] = new() - #| m.add("a") - #| m.add("b") - #| m.add("bc") - #| m.add("abc") - #| m.add("cd") - #| m.add("c") - #| m.add("d") - #| inspect(m.size, content="7") - #|} - #|test "remove" { - #| let m : HashSet[MyString] = new() - #| fn i(s) { - #| MyString::MyString(s) - #| } - #| m.add("a" |> i) - #| m.add("ab" |> i) - #| m.add("bc" |> i) - #| m.add("cd" |> i) - #| m.add("abc" |> i) - #| m.add("abcdef" |> i) - #| m.remove("ab" |> i) - #| inspect(m.length(), content="5") - #|} - #|test "remove_unexist_key" { - #| let m : HashSet[MyString] = new() - #| fn i(s) { - #| MyString::MyString(s) - #| } - #| m.add("a" |> i) - #| m.add("ab" |> i) - #| m.add("abc" |> i) - #| m.remove("d" |> i) - #| inspect(m.length(), content="3") - #|} - #|test "grow" { - #| let m : HashSet[MyString] = new() - #| fn i(s) { - #| MyString::MyString(s) - #| } - #| m.add("C" |> i) - #| m.add("Go" |> i) - #| m.add("C++" |> i) - #| m.add("Java" |> i) - #| m.add("Scala" |> i) - #| m.add("Julia" |> i) - #| inspect(m.size, content="6") - #| inspect(m.capacity, content="8") - #| m.add("Cobol" |> i) - #| inspect(m.size, content="7") - #| inspect(m.capacity, content="16") - #| m.add("Python" |> i) - #| m.add("Haskell" |> i) - #| m.add("Rescript" |> i) - #| inspect(m.size, content="10") - #| inspect(m.capacity, content="16") - #|} - #|test "clear" { - #| let m : HashSet[MyString] = new() - #| m.clear() - #| inspect(m.length(), content="0") - #| inspect(m.capacity(), content="8") - #| for i in 0.. Bool { - #| let old_size = self.length() - #| self.add(key) - #| self.length() > old_size - #|} - #|pub fn[K : Hash + Eq] HashSet::remove_and_check( - #| self : HashSet[K], - #| key : K, - #|) -> Bool { - #| let old_size = self.size - #| self.remove(key) - #| self.size < old_size - #|} - #|pub fn[K] HashSet::copy(self : HashSet[K]) -> HashSet[K] { - #| let other = { - #| capacity: self.capacity, - #| entries: FixedArray::make(self.capacity, None), - #| size: self.size, - #| capacity_mask: self.capacity_mask, - #| grow_at: self.grow_at, - #| } - #| for i in 0.. HashSet[K] { + #| let capacity = capacity.next_power_of_two() + #| { + #| size: 0, + #| capacity, + #| capacity_mask: capacity - 1, + #| grow_at: calc_grow_threshold(capacity), + #| entries: FixedArray::make(capacity, None), + #| } + #|} + #|#as_free_fn + #|#alias(of, deprecated="Use from_array instead") + #|#as_free_fn(of, deprecated="Use from_array instead") + #|pub fn[K : Hash + Eq] HashSet::from_array(arr : ArrayView[K]) -> HashSet[K] { + #| let m = new() + #| arr.each(e => m.add(e)) + #| m + #|} + #|#alias(insert, deprecated) + #|pub fn[K : Hash + Eq] HashSet::add(self : HashSet[K], key : K) -> Unit { + #| self.add_with_hash(key, key.hash()) + #|} + #|fn[K : Eq] HashSet::add_with_hash( + #| self : HashSet[K], + #| key : K, + #| hash : Int, + #|) -> Unit { + #| if self.size >= self.grow_at { + #| self.grow() + #| } + #| let (idx, psl) = for psl = 0, idx = hash & self.capacity_mask { + #| match self.entries[idx] { + #| None => break (idx, psl) + #| Some(curr_entry) => { + #| if curr_entry.hash == hash && curr_entry.key == key { + #| return + #| } + #| if psl > curr_entry.psl { + #| self.push_away(idx, curr_entry) + #| break (idx, psl) + #| } + #| continue psl + 1, (idx + 1) & self.capacity_mask + #| } + #| } + #| } + #| let entry = { psl, key, hash } + #| self.set_entry(entry, idx) + #| self.size += 1 + #|} + #|fn[K] HashSet::push_away( + #| self : HashSet[K], + #| idx : Int, + #| entry : Entry[K], + #|) -> Unit { + #| for psl = entry.psl + 1, idx = (idx + 1) & self.capacity_mask, entry = entry { + #| match self.entries[idx] { + #| None => { + #| entry.psl = psl + #| self.set_entry(entry, idx) + #| break + #| } + #| Some(curr_entry) => + #| if psl > curr_entry.psl { + #| entry.psl = psl + #| self.set_entry(entry, idx) + #| continue curr_entry.psl + 1, + #| (idx + 1) & self.capacity_mask, + #| curr_entry + #| } else { + #| continue psl + 1, (idx + 1) & self.capacity_mask, entry + #| } + #| } + #| } + #|} + #|#inline + #|fn[K] HashSet::set_entry( + #| self : HashSet[K], + #| entry : Entry[K], + #| new_idx : Int, + #|) -> Unit { + #| self.entries[new_idx] = Some(entry) + #|} + #|pub fn[K : Hash + Eq] HashSet::contains(self : HashSet[K], key : K) -> Bool { + #| let hash = key.hash() + #| for i = 0, idx = hash & self.capacity_mask { + #| guard self.entries[idx] is Some(entry) else { break false } + #| if entry.hash == hash && entry.key == key { + #| break true + #| } + #| if i > entry.psl { + #| break false + #| } + #| continue i + 1, (idx + 1) & self.capacity_mask + #| } + #|} + #|pub fn[K : Hash + Eq] HashSet::remove(self : HashSet[K], key : K) -> Unit { + #| let hash = key.hash() + #| for i = 0, idx = hash & self.capacity_mask { + #| guard self.entries[idx] is Some(entry) else { break } + #| if entry.hash == hash && entry.key == key { + #| self.shift_back(idx) + #| self.size -= 1 + #| break + #| } + #| if i > entry.psl { + #| break + #| } + #| continue i + 1, (idx + 1) & self.capacity_mask + #| } + #|} + #|fn[K] HashSet::shift_back(self : HashSet[K], idx : Int) -> Unit { + #| let next = (idx + 1) & self.capacity_mask + #| match self.entries[next] { + #| None | Some({ psl: 0, .. }) => self.entries[idx] = None + #| Some(entry) => { + #| entry.psl -= 1 + #| self.set_entry(entry, idx) + #| self.shift_back(next) + #| } + #| } + #|} + #|fn[K : Eq] HashSet::grow(self : HashSet[K]) -> Unit { + #| if self.capacity == 0 { + #| self.capacity = default_init_capacity + #| self.capacity_mask = self.capacity - 1 + #| self.grow_at = calc_grow_threshold(self.capacity) + #| self.size = 0 + #| self.entries = FixedArray::make(self.capacity, None) + #| return + #| } + #| let old_entries = self.entries + #| self.entries = FixedArray::make(self.capacity * 2, None) + #| self.capacity = self.capacity * 2 + #| self.capacity_mask = self.capacity - 1 + #| self.grow_at = calc_grow_threshold(self.capacity) + #| self.size = 0 + #| for entry in old_entries { + #| if entry is Some({ key, hash, .. }) { + #| self.add_with_hash(key, hash) + #| } + #| } + #|} + #|pub impl[K : Show] Show for HashSet[K] with output(self, logger) { + #| logger.write_iter(self.iter(), prefix="@hashset.from_array([", suffix="])") + #|} + #|#alias(size, deprecated) + #|pub fn[K] HashSet::length(self : HashSet[K]) -> Int { + #| self.size + #|} + #|pub fn[K] HashSet::capacity(self : HashSet[K]) -> Int { + #| self.capacity + #|} + #|pub fn[K] HashSet::is_empty(self : HashSet[K]) -> Bool { + #| self.size == 0 + #|} + #|#locals(f) + #|pub fn[K] HashSet::each( + #| self : HashSet[K], + #| f : (K) -> Unit raise?, + #|) -> Unit raise? { + #| for entry in self.entries { + #| if entry is Some({ key, .. }) { + #| f(key) + #| } + #| } + #|} + #|#locals(f) + #|pub fn[K] HashSet::eachi( + #| self : HashSet[K], + #| f : (Int, K) -> Unit raise?, + #|) -> Unit raise? { + #| for i in 0.. Unit { + #| self.entries.fill(None) + #| self.size = 0 + #|} + #|#alias(iterator, deprecated) + #|pub fn[K] HashSet::iter(self : HashSet[K]) -> Iter[K] { + #| let mut i = 0 + #| let len = self.entries.length() + #| Iter::new(fn() { + #| while i < len { + #| let entry = self.entries.unsafe_get(i) + #| i += 1 + #| if entry is Some({ key, .. }) { + #| return Some(key) + #| } + #| } nobreak { + #| None + #| } + #| }) + #|} + #|pub fn[K] HashSet::to_array(self : HashSet[K]) -> Array[K] { + #| let arr = Array::new(capacity=self.size) + #| for entry in self.entries { + #| if entry is Some({ key, .. }) { + #| arr.push(key) + #| } + #| } + #| arr + #|} + #|#as_free_fn + #|#alias(from_iterator, deprecated) + #|#as_free_fn(from_iterator, deprecated) + #|pub fn[K : Hash + Eq] HashSet::from_iter(iter : Iter[K]) -> HashSet[K] { + #| let s = new() + #| while iter.next() is Some(e) { + #| s.add(e) + #| } + #| s + #|} + #|pub fn[K : Hash + Eq] HashSet::union( + #| self : HashSet[K], + #| other : HashSet[K], + #|) -> HashSet[K] { + #| let m = new() + #| self.each(k => m.add(k)) + #| other.each(k => m.add(k)) + #| m + #|} + #|pub fn[K : Hash + Eq] HashSet::intersection( + #| self : HashSet[K], + #| other : HashSet[K], + #|) -> HashSet[K] { + #| let m = new() + #| self.each(k => if other.contains(k) { m.add(k) }) + #| m + #|} + #|pub fn[K : Hash + Eq] HashSet::difference( + #| self : HashSet[K], + #| other : HashSet[K], + #|) -> HashSet[K] { + #| let m = new() + #| self.each(k => if !other.contains(k) { m.add(k) }) + #| m + #|} + #|pub fn[K : Hash + Eq] HashSet::symmetric_difference( + #| self : HashSet[K], + #| other : HashSet[K], + #|) -> HashSet[K] { + #| let m = new() + #| self.each(k => if !other.contains(k) { m.add(k) }) + #| other.each(k => if !self.contains(k) { m.add(k) }) + #| m + #|} + #|pub fn[K : Hash + Eq] HashSet::is_disjoint( + #| self : HashSet[K], + #| other : HashSet[K], + #|) -> Bool { + #| if self.length() <= other.length() { + #| self.iter().all(k => !other.contains(k)) + #| } else { + #| other.iter().all(k => !self.contains(k)) + #| } + #|} + #|pub fn[K : Hash + Eq] HashSet::is_subset( + #| self : HashSet[K], + #| other : HashSet[K], + #|) -> Bool { + #| if self.length() <= other.length() { + #| self.iter().all(k => other.contains(k)) + #| } else { + #| false + #| } + #|} + #|pub fn[K : Hash + Eq] HashSet::is_superset( + #| self : HashSet[K], + #| other : HashSet[K], + #|) -> Bool { + #| other.is_subset(self) + #|} + #|pub impl[K : Hash + Eq] BitAnd for HashSet[K] with land(self, other) { + #| self.intersection(other) + #|} + #|pub impl[K : Hash + Eq] BitOr for HashSet[K] with lor(self, other) { + #| self.union(other) + #|} + #|pub impl[K : Hash + Eq] BitXOr for HashSet[K] with lxor(self, other) { + #| self.symmetric_difference(other) + #|} + #|pub impl[K : Hash + Eq] Sub for HashSet[K] with sub(self, other) { + #| self.difference(other) + #|} + #|pub fn[K] HashSet::retain(self : HashSet[K], f : (K) -> Bool) -> Unit { + #| let size = self.size + #| let mut j = 0 + #| for i = 0; j < size; i = i + 1 { + #| while self.entries[i] is Some(entry) { + #| j = j + 1 + #| if f(entry.key) { + #| break + #| } else { + #| self.shift_back(i) + #| self.size -= 1 + #| } + #| } + #| } + #|} + #|pub impl[X : @quickcheck.Arbitrary + Eq + Hash] @quickcheck.Arbitrary for HashSet[ + #| X, + #|] with arbitrary(size, rs) { + #| @quickcheck.Arbitrary::arbitrary(size, rs) |> from_iter + #|} + #|fn calc_grow_threshold(capacity : Int) -> Int { + #| capacity * 13 / 16 + #|} + #|fn[K : Show] HashSet::_debug_entries(self : HashSet[K]) -> String { + #| for i in 0.. 0 { s + "," } else { s } + #| continue match self.entries[i] { + #| None => s + "_" + #| Some({ psl, key, .. }) => s + "(\{psl},\{key})" + #| } + #| } nobreak { + #| s + #| } + #|} + #|priv struct MyString(String) derive(Eq) + #|impl Hash for MyString with hash(self) { + #| let MyString(self) = self + #| self.length() + #|} + #|impl Hash for MyString with hash_combine(self, hasher) { + #| let MyString(self) = self + #| hasher.combine_string(self) + #|} + #|impl Show for MyString with output(self, logger) { + #| let MyString(self) = self + #| logger.write_string(self) + #|} + #|test "set" { + #| let m : HashSet[MyString] = new() + #| m.add("a") + #| m.add("b") + #| m.add("bc") + #| m.add("abc") + #| m.add("cd") + #| m.add("c") + #| m.add("d") + #| inspect(m.size, content="7") + #|} + #|test "remove" { + #| let m : HashSet[MyString] = new() + #| fn i(s) { + #| MyString::MyString(s) + #| } + #| m.add("a" |> i) + #| m.add("ab" |> i) + #| m.add("bc" |> i) + #| m.add("cd" |> i) + #| m.add("abc" |> i) + #| m.add("abcdef" |> i) + #| m.remove("ab" |> i) + #| inspect(m.length(), content="5") + #|} + #|test "remove_unexist_key" { + #| let m : HashSet[MyString] = new() + #| fn i(s) { + #| MyString::MyString(s) + #| } + #| m.add("a" |> i) + #| m.add("ab" |> i) + #| m.add("abc" |> i) + #| m.remove("d" |> i) + #| inspect(m.length(), content="3") + #|} + #|test "grow" { + #| let m : HashSet[MyString] = new() + #| fn i(s) { + #| MyString::MyString(s) + #| } + #| m.add("C" |> i) + #| m.add("Go" |> i) + #| m.add("C++" |> i) + #| m.add("Java" |> i) + #| m.add("Scala" |> i) + #| m.add("Julia" |> i) + #| inspect(m.size, content="6") + #| inspect(m.capacity, content="8") + #| m.add("Cobol" |> i) + #| inspect(m.size, content="7") + #| inspect(m.capacity, content="16") + #| m.add("Python" |> i) + #| m.add("Haskell" |> i) + #| m.add("Rescript" |> i) + #| inspect(m.size, content="10") + #| inspect(m.capacity, content="16") + #|} + #|test "clear" { + #| let m : HashSet[MyString] = new() + #| m.clear() + #| inspect(m.length(), content="0") + #| inspect(m.capacity(), content="8") + #| for entry in m.entries { + #| @test.same_object(entry, None) + #| } + #|} + #|pub fn[K : Hash + Eq] HashSet::add_and_check( + #| self : HashSet[K], + #| key : K, + #|) -> Bool { + #| let old_size = self.length() + #| self.add(key) + #| self.length() > old_size + #|} + #|pub fn[K : Hash + Eq] HashSet::remove_and_check( + #| self : HashSet[K], + #| key : K, + #|) -> Bool { + #| let old_size = self.size + #| self.remove(key) + #| self.size < old_size + #|} + #|#alias(clone, deprecated) + #|pub fn[K] HashSet::copy(self : HashSet[K]) -> HashSet[K] { + #| let other = { + #| capacity: self.capacity, + #| entries: FixedArray::make(self.capacity, None), + #| size: self.size, + #| capacity_mask: self.capacity_mask, + #| grow_at: self.grow_at, + #| } + #| for i in 0.. T[A] { - #| { tree: Tree::empty(), size: 0, shift: 0 } - #|} - #|#as_free_fn - #|pub fn[A] T::make(len : Int, value : A) -> T[A] { - #| let quot = len / branching_factor - #| let rem = len % branching_factor - #| let leaves = if rem == 0 { - #| Array::make(quot, FixedArray::make(branching_factor, value)) - #| } else { - #| let arr : Array[FixedArray[A]] = Array::make( - #| quot + 1, - #| FixedArray::make(branching_factor, value), - #| ) - #| arr[quot] = FixedArray::make(rem, value) - #| arr - #| } - #| let size = len - #| let (shift, cap) = shift_cap_of_size(size) - #| let tree = if size == 0 { Empty } else { from_leaves(leaves[:], cap) } - #| { shift, tree, size } - #|} - #|#as_free_fn - #|pub fn[A] T::makei(len : Int, f : (Int) -> A raise?) -> T[A] raise? { - #| let quot = len / branching_factor - #| let rem = len % branching_factor - #| let leaves = if rem == 0 { - #| Array::makei(quot, k => FixedArray::makei(branching_factor, i => f( - #| k * branching_factor + i, - #| ))) - #| } else { - #| let arr : Array[FixedArray[A]] = Array::make(quot + 1, []) - #| for k in 0.. f( - #| k * branching_factor + i, - #| )) - #| } - #| arr[quot] = FixedArray::makei(rem, i => f(quot * branching_factor + i)) - #| arr - #| } - #| let size = len - #| let (shift, cap) = shift_cap_of_size(size) - #| let tree = if size == 0 { Empty } else { from_leaves(leaves[:], cap) } - #| { shift, tree, size } - #|} - #|#as_free_fn - #|#alias(of, deprecated="Use from_array instead") - #|#as_free_fn(of, deprecated="Use from_array instead") - #|pub fn[A] T::from_array(arr : ArrayView[A]) -> T[A] { - #| makei(arr.length(), i => arr[i]) - #|} - #|#as_free_fn - #|pub fn[A] T::from_iter(iter : Iter[A]) -> T[A] { - #| let mut buf : FixedArray[A] = [] - #| let mut index = 0 - #| let leaves = [] - #| iter.each(x => if index == 0 { - #| buf = FixedArray::make(branching_factor, x) - #| index += 1 - #| } else if index < branching_factor { - #| buf[index] = x - #| index += 1 - #| } else { - #| leaves.push(buf) - #| index = 1 - #| buf = FixedArray::make(branching_factor, x) - #| }) - #| if index == branching_factor { - #| leaves.push(buf) - #| } else if index > 0 { - #| let res = FixedArray::make(index, buf[0]) - #| buf.blit_to(res, len=index) - #| leaves.push(res) - #| } - #| let size = leaves.fold(init=0, (acc, xs) => acc + xs.length()) - #| let (shift, cap) = shift_cap_of_size(size) - #| let tree = if size == 0 { Empty } else { from_leaves(leaves[:], cap) } - #| { shift, tree, size } - #|} - #|#as_free_fn - #|pub fn[A] T::from_iterator(iter : Iterator[A]) -> T[A] { - #| let mut buf : FixedArray[A] = [] - #| let mut index = 0 - #| let leaves = [] - #| while iter.next() is Some(x) { - #| if index == 0 { - #| buf = FixedArray::make(branching_factor, x) - #| index += 1 - #| } else if index < branching_factor { - #| buf[index] = x - #| index += 1 - #| } else { - #| leaves.push(buf) - #| index = 1 - #| buf = FixedArray::make(branching_factor, x) - #| } - #| } - #| if index == branching_factor { - #| leaves.push(buf) - #| } else if index > 0 { - #| let res = FixedArray::make(index, buf[0]) - #| buf.blit_to(res, len=index) - #| leaves.push(res) - #| } - #| let size = leaves.fold(init=0, (acc, xs) => acc + xs.length()) - #| let (shift, cap) = shift_cap_of_size(size) - #| let tree = if size == 0 { Empty } else { from_leaves(leaves[:], cap) } - #| { shift, tree, size } - #|} - #|pub fn[A] T::to_array(self : T[A]) -> Array[A] { - #| if self.is_empty() { - #| [] - #| } else { - #| let arr = Array::make(self.length(), self[0]) - #| self.eachi((i, v) => arr[i] = v) - #| arr - #| } - #|} - #|pub fn[A] T::is_empty(self : T[A]) -> Bool { - #| self.size == 0 - #|} - #|pub fn[A] T::length(self : T[A]) -> Int { - #| self.size - #|} - #|#alias("_[_]") - #|pub fn[A] T::at(self : T[A], index : Int) -> A { - #| if index == 0 { - #| self.tree.get_first() - #| } else if index == self.size - 1 { - #| self.tree.get_last() - #| } else { - #| self.tree.get(index, self.shift) - #| } - #|} - #|pub fn[A] T::get(self : T[A], index : Int) -> A? { - #| guard 0 <= index && index < self.size else { None } - #| Some(self[index]) - #|} - #|pub fn[A] T::set(self : T[A], index : Int, value : A) -> T[A] { - #| { - #| tree: self.tree.set(index, self.shift, value), - #| size: self.size, - #| shift: self.shift, - #| } - #|} - #|pub fn[A] T::push(self : T[A], value : A) -> T[A] { - #| let (tree, shift) = self.tree.push_end(self.shift, value) - #| { tree, size: self.size + 1, shift } - #|} - #|pub fn[A] T::concat(self : T[A], other : T[A]) -> T[A] { - #| if self.is_empty() { - #| return other - #| } - #| if other.is_empty() { - #| return self - #| } - #| let (tree, shift) = Tree::concat( - #| self.tree, - #| self.shift, - #| other.tree, - #| other.shift, - #| true, - #| ) - #| { tree, size: self.size + other.size, shift } - #|} - #|pub impl[A] Add for T[A] with add(self, other) { - #| self.concat(other) - #|} - #|pub fn[A] T::iter(self : T[A]) -> Iter[A] { - #| self.tree.iterator().iter() - #|} - #|pub fn[A] T::iterator(self : T[A]) -> Iterator[A] { - #| self.tree.iterator() - #|} - #|pub fn[A] T::each(self : T[A], f : (A) -> Unit raise?) -> Unit raise? { - #| self.tree.each(f) - #|} - #|pub fn[A] T::eachi(self : T[A], f : (Int, A) -> Unit raise?) -> Unit raise? { - #| self.tree.eachi(f, self.shift, 0) - #|} - #|#alias(fold_left, deprecated) - #|pub fn[A, B] T::fold( - #| self : T[A], - #| init~ : B, - #| f : (B, A) -> B raise?, - #|) -> B raise? { - #| self.tree.fold(init, f) - #|} - #|#alias(fold_right, deprecated) - #|pub fn[A, B] T::rev_fold( - #| self : T[A], - #| init~ : B, - #| f : (B, A) -> B raise?, - #|) -> B raise? { - #| self.tree.rev_fold(init, f) - #|} - #|pub fn[A, B] T::map(self : T[A], f : (A) -> B raise?) -> T[B] raise? { - #| { tree: self.tree.map(f), size: self.size, shift: self.shift } - #|} - #|pub impl[X : @quickcheck.Arbitrary] @quickcheck.Arbitrary for T[X] with arbitrary( - #| size, - #| rs, - #|) { - #| @quickcheck.Arbitrary::arbitrary(size, rs) |> from_array - #|} - #|pub impl[A : Hash] Hash for T[A] with hash_combine(self, hasher) { - #| for e in self { - #| hasher.combine(e) - #| } - #|} - #|pub impl[A : Eq] Eq for T[A] with equal(self, other) { - #| self.size == other.size && self.tree == other.tree - #|} - #|pub impl[A : Show] Show for T[A] with output(self, logger) { - #| logger.write_iter( - #| self.iter(), - #| prefix="@immut/array.from_array([", - #| suffix="])", - #| ) - #|} - #|pub impl[A : Compare] Compare for T[A] with compare(self, other) { - #| let len_self = self.length() - #| let len_other = other.length() - #| let cmp = len_self.compare(len_other) - #| guard cmp is 0 else { return cmp } - #| for i in 0.. Tree[A] { - #| if cap == branching_factor { - #| Leaf(leaves[0]) - #| } else if leaves.length() <= branching_factor { - #| let arr = FixedArray::make(leaves.length(), Empty) - #| for i in 0.. from_leaves( - #| leaves[i * times:(i + 1) * times], - #| child_cap, - #| )) - #| } else { - #| let arr = FixedArray::make(quot + 1, Tree::Empty) - #| for i in 0.. (Int, Int) { - #| let mut cap = branching_factor - #| let mut depth = 0 - #| while cap < size { - #| cap *= branching_factor - #| depth += 1 - #| } - #| let shift = num_bits * depth - #| (shift, cap) - #|} - ), - "deprecated.mbt": ( - #|#deprecated("We don't copy immutable array") - #|#coverage.skip - #|pub fn[A] T::copy(self : T[A]) -> T[A] { - #| fn copy(t : Tree[A]) -> Tree[A] { - #| match t { - #| Leaf(l) => Leaf(l.copy()) - #| Empty => Empty - #| Node(node, sizes) => - #| Node( - #| FixedArray::makei(node.length(), i => copy(node[i])), - #| match sizes { - #| Some(sizes) => Some(FixedArray::copy(sizes)) - #| None => None - #| }, - #| ) - #| } - #| } - #| { tree: copy(self.tree), size: self.size, shift: self.shift } - #|} - ), - "tree.mbt": ( - #|let num_bits = 5 - #|let branching_factor : Int = 1 << num_bits - #|let bitmask : Int = branching_factor - 1 - #|const LINEAR_THRESHOLD : Int = 4 - #|const E_MAX : Int = 2 - #|let e_max_2 : Int = E_MAX / 2 - #|fn[T] Tree::empty() -> Tree[T] { - #| Tree::Empty - #|} - #|fn[T] new_branch_left(leaf : FixedArray[T], shift : Int) -> Tree[T] { - #| match shift { - #| 0 => Leaf(leaf) - #| s => Node([new_branch_left(leaf, s - num_bits)], None) // size is None because we can use radix indexing - #| } - #|} - #|fn[T] Tree::get_first(self : Tree[T]) -> T { - #| match self { - #| Leaf(leaf) => leaf[0] - #| Node(node, _) => node[0].get_first() - #| Empty => abort("Index out of bounds") - #| } - #|} - #|fn[T] Tree::get_last(self : Tree[T]) -> T { - #| match self { - #| Leaf(leaf) => leaf[leaf.length() - 1] - #| Node(node, _) => node[node.length() - 1].get_last() - #| Empty => abort("Index out of bounds") - #| } - #|} - #|fn[T] Tree::get(self : Tree[T], index : Int, shift : Int) -> T { - #| fn get_radix(node : Tree[T], shift : Int) -> T { - #| match node { - #| Leaf(leaf) => leaf[index & bitmask] - #| Node(node, None) => - #| get_radix(node[radix_indexing(index, shift)], shift - num_bits) - #| Node(_, Some(_)) => - #| abort("Unreachable: Node should not have sizes in get_radix") - #| Empty => abort("Index out of bounds") - #| } - #| } - #| match self { - #| Leaf(leaf) => leaf[index] - #| Node(children, Some(sizes)) => { - #| let branch_index = get_branch_index(sizes, index) - #| let sub_index = if branch_index == 0 { - #| index - #| } else { - #| index - sizes[branch_index - 1] - #| } - #| children[branch_index].get(sub_index, shift - num_bits) - #| } - #| Node(_, None) => get_radix(self, shift) - #| Empty => abort("Index out of bounds") - #| } - #|} - #|fn[T] Tree::set(self : Tree[T], index : Int, shift : Int, value : T) -> Tree[T] { - #| fn set_radix(node : Tree[T], shift : Int) -> Tree[T] { - #| match node { - #| Leaf(leaf) => Leaf(immutable_set(leaf, index & bitmask, value)) - #| Node(node, None) => { - #| let sub_idx = radix_indexing(index, shift) - #| Node( - #| immutable_set( - #| node, - #| sub_idx, - #| set_radix(node[radix_indexing(index, shift)], shift - num_bits), - #| ), - #| None, - #| ) - #| } - #| Node(_, Some(_)) => - #| abort("Unreachable: Node should not have sizes in set_radix") - #| Empty => abort("Index out of bounds") - #| } - #| } - #| match self { - #| Leaf(leaf) => Leaf(immutable_set(leaf, index & bitmask, value)) - #| Node(children, Some(sizes)) => { - #| let branch_index = get_branch_index(sizes, index) - #| let sub_index = if branch_index == 0 { - #| index - #| } else { - #| index - sizes[branch_index - 1] - #| } - #| Node( - #| immutable_set( - #| children, - #| branch_index, - #| children[branch_index].set(sub_index, shift - num_bits, value), - #| ), - #| Some(sizes), - #| ) - #| } - #| Node(_children, None) => set_radix(self, shift) - #| Empty => abort("Index out of bounds") - #| } - #|} - #|fn[T] Tree::push_end(self : Tree[T], shift : Int, value : T) -> (Tree[T], Int) { - #| fn update_sizes_last(sizes : FixedArray[Int]?) -> FixedArray[Int]? { - #| match sizes { - #| Some(sizes) => { - #| let new_sizes = sizes.copy() - #| new_sizes[new_sizes.length() - 1] += 1 - #| Some(new_sizes) - #| } - #| None => None - #| } - #| } - #| fn push_sizes_last(sizes : FixedArray[Int]?) -> FixedArray[Int]? { - #| match sizes { - #| Some(sizes) => Some(immutable_push(sizes, 1 + sizes[sizes.length() - 1])) - #| None => None - #| } - #| } - #| fn worker(node : Tree[T], shift : Int) -> Tree[T]? { - #| match node { - #| Leaf(leaf) => { - #| if shift != 0 { - #| abort( - #| "Unreachable: Leaf should not have a non-zero shift, which means we have not reached the bottom of the tree", - #| ) - #| } - #| if leaf.length() < branching_factor { - #| Some(Leaf(immutable_push(leaf, value))) - #| } else { - #| None - #| } - #| } - #| Node(nodes, sizes) => { - #| let len = nodes.length() - #| match worker(nodes[len - 1], shift - num_bits) { - #| Some(new_node) => { - #| let new_nodes = nodes.copy() - #| new_nodes[len - 1] = new_node - #| let sizes = update_sizes_last(sizes) - #| Some(Node(new_nodes, sizes)) - #| } - #| None => - #| if len < branching_factor { - #| let sizes = push_sizes_last(sizes) - #| Some( - #| Node( - #| immutable_push( - #| nodes, - #| new_branch_left([value], shift - num_bits), - #| ), - #| sizes, - #| ), - #| ) - #| } else { - #| None - #| } - #| } - #| } - #| Empty => Some(Leaf([value])) - #| } - #| } - #| match worker(self, shift) { - #| Some(new_tree) => (new_tree, shift) - #| None => { - #| let new_branch = new_branch_left([value], shift) - #| ( - #| match self { - #| Leaf(_leaf) => Node([self, new_branch], None) - #| Node(_nodes, Some(sizes)) => { - #| let len = sizes[sizes.length() - 1] - #| let sizes = FixedArray::from_array([len, 1 + len]) - #| Node([self, new_branch], Some(sizes)) - #| } - #| Node(_nodes, None) => Node([self, new_branch], None) - #| Empty => - #| abort( - #| "Unreachable: Empty tree should have fallen into the Some(new_tree) branch", - #| ) - #| }, - #| shift + num_bits, - #| ) - #| } - #| } - #|} - #|fn[A] Tree::each(self : Tree[A], f : (A) -> Unit raise?) -> Unit raise? { - #| match self { - #| Empty => () - #| Leaf(l) => l.each(f) - #| Node(ns, _) => ns.each(t => t.each(f)) - #| } - #|} - #|fn[A] Tree::iterator(self : Tree[A]) -> Iterator[A] { - #| let mut curr_tree = self - #| let mut curr_index = 0 - #| let parents = [] - #| Iterator::new(fn() { - #| loop curr_tree { - #| Node(children, _) as t if curr_index < children.length() => { - #| let child = children.unsafe_get(curr_index) - #| parents.push((t, curr_index + 1)) - #| curr_tree = child - #| curr_index = 0 - #| continue child - #| } - #| Leaf(elems) if curr_index < elems.length() => { - #| let elem = elems.unsafe_get(curr_index) - #| curr_index += 1 - #| Some(elem) - #| } - #| _ if parents.pop() is Some((parent_tree, parent_index)) => { - #| curr_tree = parent_tree - #| curr_index = parent_index - #| continue parent_tree - #| } - #| _ => None - #| } - #| }) - #|} - #|fn[A] Tree::eachi( - #| self : Tree[A], - #| f : (Int, A) -> Unit raise?, - #| shift : Int, - #| start : Int, - #|) -> Unit raise? { - #| match self { - #| Empty => () - #| Leaf(l) => - #| for i in 0.. { - #| let child_shift = shift - num_bits - #| let mut start = start - #| for i in 0.. { - #| let child_shift = shift - num_bits - #| let mut start = start - #| for i in 0.. B raise?, - #|) -> B raise? { - #| match self { - #| Empty => acc - #| Leaf(l) => l.fold(f, init=acc) - #| Node(n, _) => n.fold((acc, t) => t.fold(acc, f), init=acc) - #| } - #|} - #|fn[A, B] Tree::rev_fold( - #| self : Tree[A], - #| acc : B, - #| f : (B, A) -> B raise?, - #|) -> B raise? { - #| match self { - #| Empty => acc - #| Leaf(l) => l.rev_fold(f, init=acc) - #| Node(n, _) => n.rev_fold((acc, t) => t.rev_fold(acc, f), init=acc) - #| } - #|} - #|fn[A, B] Tree::map(self : Tree[A], f : (A) -> B raise?) -> Tree[B] raise? { - #| match self { - #| Empty => Empty - #| Leaf(l) => Leaf(l.map(f)) - #| Node(n, szs) => - #| Node(FixedArray::makei(n.length(), i => n[i].map(f)), copy_sizes(szs)) - #| } - #|} - #|fn[A] Tree::concat( - #| left : Tree[A], - #| left_shift : Int, - #| right : Tree[A], - #| right_shift : Int, - #| top : Bool, - #|) -> (Tree[A], Int) { - #| if left_shift > right_shift { - #| let (c, c_shift) = Tree::concat( - #| left.right_child(), - #| left_shift - num_bits, - #| right, - #| right_shift, - #| false, - #| ) - #| guard c_shift == left_shift - #| return rebalance(left, c, Empty, left_shift, top) - #| } else if right_shift > left_shift { - #| let (c, c_shift) = Tree::concat( - #| left, - #| left_shift, - #| right.left_child(), - #| right_shift - num_bits, - #| false, - #| ) - #| guard c_shift == right_shift - #| return rebalance(Empty, c, right, right_shift, top) - #| } else if left_shift == 0 { - #| let left_elems = left.leaf_elements() - #| let right_elems = right.leaf_elements() - #| let left_len = left_elems.length() - #| let right_len = right_elems.length() - #| let len = left_len + right_len - #| if top && len <= branching_factor { - #| return ( - #| Leaf( - #| FixedArray::makei(len, (i : Int) => if i < left_len { - #| left_elems[i] - #| } else { - #| right_elems[i - left_len] - #| }), - #| ), - #| 0, - #| ) - #| } else { - #| return ( - #| Node( - #| FixedArray::from_array([left, right]), - #| Some(FixedArray::from_array([left_len, len])), - #| ), - #| num_bits, - #| ) - #| } - #| } else { - #| let (c, c_shift) = Tree::concat( - #| left.right_child(), - #| left_shift - num_bits, - #| right.left_child(), - #| right_shift - num_bits, - #| false, - #| ) - #| guard c_shift == left_shift - #| guard c_shift == right_shift - #| return rebalance(left, c, right, left_shift, top) - #| } - #|} - #|fn[A] rebalance( - #| left : Tree[A], - #| center : Tree[A], - #| right : Tree[A], - #| shift : Int, - #| top : Bool, - #|) -> (Tree[A], Int) { - #| let t = tri_merge(left, center, right) // t is a list of trees of (H-1) height - #| let (nc, nc_len) = redis_plan(t) - #| let new_t = redis(t, nc, nc_len, shift - num_bits) // new_t is a list of trees of (H-1) height - #| guard new_t.length() == nc_len - #| if nc_len <= branching_factor { - #| let node = Node(new_t, compute_sizes(new_t, shift - num_bits)) // node of H height - #| if !top { - #| return (Node(FixedArray::from_array([node]), None), shift + num_bits) - #| } else { - #| return (node, shift) - #| } - #| } else { - #| let new_child_1 = FixedArray::makei(branching_factor, i => new_t[i]) - #| let new_child_2 = FixedArray::makei(new_t.length() - branching_factor, i => new_t[i + - #| branching_factor]) - #| let new_node_1 = Node( - #| new_child_1, - #| compute_sizes(new_child_1, shift - num_bits), - #| ) // height H - #| let new_node_2 = Node( - #| new_child_2, - #| compute_sizes(new_child_2, shift - num_bits), - #| ) // height H - #| let new_children = FixedArray::from_array([new_node_1, new_node_2]) - #| return ( - #| Node(new_children, compute_sizes(new_children, shift)), - #| shift + num_bits, - #| ) // return (H+1) height node - #| } - #|} - #|fn[A] tri_merge( - #| left : Tree[A], - #| center : Tree[A], - #| right : Tree[A], - #|) -> FixedArray[Tree[A]] { - #| if left.is_leaf() || !center.is_node() || right.is_leaf() { - #| abort("Unreachable: input to merge is invalid") - #| } - #| fn get_children(self : Tree[A]) -> FixedArray[Tree[A]] { - #| match self { - #| Node(children, _) => children - #| Empty => [] - #| Leaf(_) => abort("Unreachable") - #| } - #| } - #| let left_children = get_children(left) - #| let center_children = get_children(center) - #| let right_children = get_children(right) - #| let left_len = left_children.length() - #| let left_len = if left_len == 0 { 0 } else { left_len - 1 } - #| let center_len = center_children.length() - #| let right_len = right_children.length() - #| let right_len = if right_len == 0 { 0 } else { right_len - 1 } - #| FixedArray::makei(left_len + center_len + right_len, i => if i < left_len { - #| left_children[i] - #| } else if i < left_len + center_len { - #| center_children[i - left_len] - #| } else if right_len > 0 { - #| right_children[1 + i - left_len - center_len] - #| } else { - #| abort("Unreachable") - #| }) - #|} - #|fn[A] redis_plan(t : FixedArray[Tree[A]]) -> (FixedArray[Int], Int) { - #| let node_counts = FixedArray::makei(t.length(), i => t[i].local_size()) - #| let total_nodes = node_counts.fold(init=0, (acc, x) => acc + x) - #| let opt_len = (total_nodes + branching_factor - 1) / branching_factor - #| let mut new_len = t.length() - #| let mut i = 0 - #| while opt_len + e_max_2 < new_len { - #| while node_counts[i] > branching_factor - e_max_2 { - #| i += 1 - #| } - #| let mut remaining_nodes = node_counts[i] - #| while remaining_nodes > 0 { - #| let min_size = min(remaining_nodes + node_counts[i + 1], branching_factor) - #| node_counts[i] = min_size - #| remaining_nodes = remaining_nodes + node_counts[i + 1] - min_size - #| i += 1 - #| } - #| for j in i..<(new_len - 1) { - #| node_counts[j] = node_counts[j + 1] - #| } - #| new_len -= 1 - #| i -= 1 - #| } - #| return (node_counts, new_len) - #|} - #|fn[A] redis( - #| old_t : FixedArray[Tree[A]], - #| node_counts : FixedArray[Int], - #| node_nums : Int, - #| shift : Int, - #|) -> FixedArray[Tree[A]] { - #| let old_len = old_t.length() - #| let new_t = FixedArray::make(node_nums, Empty) - #| let mut old_offset = 0 - #| let mut j = 0 // the index of in the old tree - #| if shift == 0 { - #| let mut old_leaf_elems = FixedArray::default() - #| let mut old_leaf_len = 0 - #| for i in 0.. FixedArray[Int]? { - #| let len = children.length() - #| let sizes = FixedArray::make(len, 0) - #| let mut sum = 0 - #| let mut flag = true - #| let full_subtree_size = branching_factor << shift - #| for i in 0.. String { - #| String::make(indent, ' ') + s - #| } - #| fn aux(t : Tree[A], ident : Int) { - #| match t { - #| Empty => indent_str("Empty", ident) - #| Leaf(l) => { - #| let mut s = "Leaf(" - #| for i in 0.. { - #| let mut s = indent_str("Node(", ident) + "\n" - #| for i in 0.. Bool { - #| self is Node(_, _) - #|} - #|fn[A] Tree::is_leaf(self : Tree[A]) -> Bool { - #| self is Leaf(_) - #|} - #|fn[A] Tree::right_child(self : Tree[A]) -> Tree[A] { - #| match self { - #| Node(children, _) => children[children.length() - 1] - #| Leaf(_) | Empty => abort("Should not get children on non-`Node`s") - #| } - #|} - #|fn[A] Tree::left_child(self : Tree[A]) -> Tree[A] { - #| match self { - #| Node(children, _) => children[0] - #| Leaf(_) | Empty => abort("Should not get children on non-`Node`s") - #| } - #|} - #|fn[A] Tree::leaf_elements(self : Tree[A]) -> FixedArray[A] { - #| guard self is Leaf(children) else { - #| abort("Should not call `get_leaf_elements` on non-leaf nodes") - #| } - #| children - #|} - #|fn[A] Tree::node_children(self : Tree[A]) -> FixedArray[Tree[A]] { - #| guard self is Node(children, _) else { - #| abort("Should not call `node_children` on non-`Node`s") - #| } - #| children - #|} - #|fn[A] Tree::local_size(self : Tree[A]) -> Int { - #| match self { - #| Empty => 0 - #| Leaf(l) => l.length() - #| Node(children, _) => children.length() - #| } - #|} - #|fn[A] Tree::size(self : Tree[A], shift : Int) -> Int { - #| match self { - #| Empty => 0 - #| Leaf(l) => l.length() - #| Node(_, Some(sizes)) => sizes[sizes.length() - 1] - #| Node(children, None) => { - #| let len_1 = children.length() - 1 - #| (len_1 << shift) + children[len_1].size(shift - num_bits) - #| } - #| } - #|} - ), - "types.mbt": ( - #|struct T[A] { - #| tree : Tree[A] - #| size : Int - #| shift : Int - #|} - #|priv enum Tree[A] { - #| Empty - #| Node(FixedArray[Tree[A]], FixedArray[Int]?) // (Subtrees, Sizes of subtrees) - #| Leaf(FixedArray[A]) - #|} derive(Eq) - ), - "utils.mbt": ( - #|fn[T] immutable_set(arr : FixedArray[T], i : Int, v : T) -> FixedArray[T] { - #| let arr = arr.copy() - #| arr[i] = v - #| arr - #|} - #|fn[T] immutable_push(arr : FixedArray[T], val : T) -> FixedArray[T] { - #| let len = arr.length() - #| let new_arr = FixedArray::make(len + 1, val) - #| arr.blit_to(new_arr, len~) - #| new_arr[len] = val - #| new_arr - #|} - #|fn shr_as_uint(x : Int, y : Int) -> Int { - #| (x.reinterpret_as_uint() >> y).reinterpret_as_int() - #|} - #|fn radix_indexing(index : Int, shift : Int) -> Int { - #| shr_as_uint(index, shift) & bitmask - #|} - #|fn get_branch_index(sizes : FixedArray[Int], index : Int) -> Int { - #| let mut lo = 0 - #| let mut hi = sizes.length() - #| while LINEAR_THRESHOLD < hi - lo { - #| let mid = (lo + hi) / 2 - #| if sizes[mid] <= index { - #| lo = mid - #| } else { - #| hi = mid - #| } - #| } - #| while sizes[lo] <= index { - #| lo += 1 - #| } - #| lo - #|} - #|fn copy_sizes(sizes : FixedArray[Int]?) -> FixedArray[Int]? { - #| match sizes { - #| Some(sizes) => Some(sizes.copy()) - #| None => None - #| } - #|} - #|fn min(a : Int, b : Int) -> Int { - #| if a < b { - #| a - #| } else { - #| b - #| } - #|} - ), - "utils_wbtest2.mbt": ( - #|test "immutable_set" { - #| let arr = FixedArray::from_array([1, 2, 3, 4, 5]) - #| let new_arr = immutable_set(arr, 2, 10) - #| inspect(new_arr[2], content="10") - #| inspect(arr[2], content="3") // Original array unchanged - #| inspect(new_arr.length(), content="5") - #|} - #|test "immutable_push" { - #| let arr = FixedArray::from_array([1, 2, 3]) - #| let new_arr = immutable_push(arr, 4) - #| inspect(new_arr.length(), content="4") - #| inspect(new_arr[3], content="4") - #| inspect(arr.length(), content="3") // Original array unchanged - #|} - #|test "shr_as_uint" { - #| inspect(shr_as_uint(16, 2), content="4") - #| inspect(shr_as_uint(8, 1), content="4") - #| inspect(shr_as_uint(-1, 1), content="2147483647") // Handle negative numbers as unsigned - #|} - #|test "radix_indexing" { - #| inspect(radix_indexing(35, 5), content="1") // 35 >> 5 = 1, 1 & 31 = 1 - #| inspect(radix_indexing(100, 5), content="3") // 100 >> 5 = 3, 3 & 31 = 3 - #| inspect(radix_indexing(7, 5), content="0") // 7 >> 5 = 0, 0 & 31 = 0 - #|} - #|test "get_branch_index" { - #| let sizes = FixedArray::from_array([3, 6, 10, 15]) - #| inspect(get_branch_index(sizes, 2), content="0") // Index 2 is in first branch (contains indexes 0-2) - #| inspect(get_branch_index(sizes, 5), content="1") // Index 5 is in second branch (contains indexes 3-5) - #| inspect(get_branch_index(sizes, 8), content="2") // Index 8 is in third branch (contains indexes 6-9) - #|} - #|test "copy_sizes with Some" { - #| let original = FixedArray::from_array([1, 2, 3]) - #| let sizes = Some(original) - #| let copied = copy_sizes(sizes) - #| match copied { - #| Some(copied_arr) => { - #| inspect(copied_arr.length(), content="3") - #| inspect(copied_arr[0], content="1") - #| inspect(copied_arr[1], content="2") - #| inspect(copied_arr[2], content="3") - #| original[0] = 100 - #| inspect(copied_arr[0], content="1") // Should still be 1 - #| } - #| None => inspect("Should not be None", content="error") - #| } - #|} - #|test "copy_sizes with None" { - #| let sizes : FixedArray[Int]? = None - #| let copied = copy_sizes(sizes) - #| match copied { - #| None => inspect("None copied correctly", content="None copied correctly") - #| Some(_) => inspect("Should be None", content="error") - #| } - #|} - #|test "min function" { - #| inspect(min(5, 3), content="3") - #| inspect(min(1, 10), content="1") - #| inspect(min(-5, 0), content="-5") - #| inspect(min(42, 42), content="42") - #|} - ), - }, + "array.mbt": ( + #|#as_free_fn + #|pub fn[A] T::new() -> T[A] { + #| { tree: Tree::empty(), size: 0, shift: 0 } + #|} + #|#as_free_fn + #|pub fn[A] T::make(len : Int, value : A) -> T[A] { + #| let quot = len / branching_factor + #| let rem = len % branching_factor + #| let leaves = if rem == 0 { + #| Array::make(quot, FixedArray::make(branching_factor, value)) + #| } else { + #| let arr : Array[FixedArray[A]] = Array::make( + #| quot + 1, + #| FixedArray::make(branching_factor, value), + #| ) + #| arr[quot] = FixedArray::make(rem, value) + #| arr + #| } + #| let size = len + #| let (shift, cap) = shift_cap_of_size(size) + #| let tree = if size == 0 { Empty } else { from_leaves(leaves[:], cap) } + #| { shift, tree, size } + #|} + #|#as_free_fn + #|pub fn[A] T::makei(len : Int, f : (Int) -> A raise?) -> T[A] raise? { + #| let quot = len / branching_factor + #| let rem = len % branching_factor + #| let leaves = if rem == 0 { + #| Array::makei(quot, k => { + #| FixedArray::makei(branching_factor, i => f(k * branching_factor + i)) + #| }) + #| } else { + #| let arr : Array[FixedArray[A]] = Array::make(quot + 1, []) + #| for k in 0.. { + #| f(k * branching_factor + i) + #| }) + #| } + #| arr[quot] = FixedArray::makei(rem, i => f(quot * branching_factor + i)) + #| arr + #| } + #| let size = len + #| let (shift, cap) = shift_cap_of_size(size) + #| let tree = if size == 0 { Empty } else { from_leaves(leaves[:], cap) } + #| { shift, tree, size } + #|} + #|#as_free_fn + #|#alias(of, deprecated="Use from_array instead") + #|#as_free_fn(of, deprecated="Use from_array instead") + #|pub fn[A] T::from_array(arr : ArrayView[A]) -> T[A] { + #| makei(arr.length(), i => arr[i]) + #|} + #|#as_free_fn + #|#alias(from_iterator, deprecated) + #|#as_free_fn(from_iterator, deprecated) + #|pub fn[A] T::from_iter(iter : Iter[A]) -> T[A] { + #| let mut buf : FixedArray[A] = [] + #| let mut index = 0 + #| let leaves = [] + #| while iter.next() is Some(x) { + #| if index == 0 { + #| buf = FixedArray::make(branching_factor, x) + #| index += 1 + #| } else if index < branching_factor { + #| buf[index] = x + #| index += 1 + #| } else { + #| leaves.push(buf) + #| index = 1 + #| buf = FixedArray::make(branching_factor, x) + #| } + #| } + #| if index == branching_factor { + #| leaves.push(buf) + #| } else if index > 0 { + #| let res = FixedArray::make(index, buf[0]) + #| buf.blit_to(res, len=index) + #| leaves.push(res) + #| } + #| let size = leaves.fold(init=0, (acc, xs) => acc + xs.length()) + #| let (shift, cap) = shift_cap_of_size(size) + #| let tree = if size == 0 { Empty } else { from_leaves(leaves[:], cap) } + #| { shift, tree, size } + #|} + #|pub fn[A] T::to_array(self : T[A]) -> Array[A] { + #| if self.is_empty() { + #| [] + #| } else { + #| let arr = Array::make(self.length(), self[0]) + #| self.eachi((i, v) => arr[i] = v) + #| arr + #| } + #|} + #|pub fn[A] T::is_empty(self : T[A]) -> Bool { + #| self.size == 0 + #|} + #|pub fn[A] T::length(self : T[A]) -> Int { + #| self.size + #|} + #|#alias("_[_]") + #|pub fn[A] T::at(self : T[A], index : Int) -> A { + #| guard index >= 0 && index < self.size + #| if index == 0 { + #| self.tree.get_first() + #| } else if index == self.size - 1 { + #| self.tree.get_last() + #| } else { + #| self.tree.get(index, self.shift) + #| } + #|} + #|pub fn[A] T::get(self : T[A], index : Int) -> A? { + #| guard 0 <= index && index < self.size else { None } + #| Some(self[index]) + #|} + #|pub fn[A] T::set(self : T[A], index : Int, value : A) -> T[A] { + #| guard index >= 0 && index < self.size + #| { + #| tree: self.tree.set(index, self.shift, value), + #| size: self.size, + #| shift: self.shift, + #| } + #|} + #|pub fn[A] T::push(self : T[A], value : A) -> T[A] { + #| let (tree, shift) = self.tree.push_end(self.shift, value) + #| { tree, size: self.size + 1, shift } + #|} + #|pub fn[A] T::concat(self : T[A], other : T[A]) -> T[A] { + #| if self.is_empty() { + #| return other + #| } + #| if other.is_empty() { + #| return self + #| } + #| let (tree, shift) = Tree::concat( + #| self.tree, + #| self.shift, + #| other.tree, + #| other.shift, + #| true, + #| ) + #| { tree, size: self.size + other.size, shift } + #|} + #|pub impl[A] Add for T[A] with add(self, other) { + #| self.concat(other) + #|} + #|#alias(iterator, deprecated) + #|pub fn[A] T::iter(self : T[A]) -> Iter[A] { + #| self.tree.iter() + #|} + #|pub fn[A] T::each(self : T[A], f : (A) -> Unit raise?) -> Unit raise? { + #| self.tree.each(f) + #|} + #|pub fn[A] T::eachi(self : T[A], f : (Int, A) -> Unit raise?) -> Unit raise? { + #| self.tree.eachi(f, self.shift, 0) + #|} + #|#alias(fold_left, deprecated) + #|pub fn[A, B] T::fold( + #| self : T[A], + #| init~ : B, + #| f : (B, A) -> B raise?, + #|) -> B raise? { + #| self.tree.fold(init, f) + #|} + #|#alias(fold_right, deprecated) + #|pub fn[A, B] T::rev_fold( + #| self : T[A], + #| init~ : B, + #| f : (B, A) -> B raise?, + #|) -> B raise? { + #| self.tree.rev_fold(init, f) + #|} + #|pub fn[A, B] T::map(self : T[A], f : (A) -> B raise?) -> T[B] raise? { + #| { tree: self.tree.map(f), size: self.size, shift: self.shift } + #|} + #|pub impl[X : @quickcheck.Arbitrary] @quickcheck.Arbitrary for T[X] with arbitrary( + #| size, + #| rs, + #|) { + #| @quickcheck.Arbitrary::arbitrary(size, rs) |> from_array + #|} + #|pub impl[A : Hash] Hash for T[A] with hash_combine(self, hasher) { + #| for e in self { + #| hasher.combine(e) + #| } + #|} + #|pub impl[A : Eq] Eq for T[A] with equal(self, other) { + #| physical_equal(self, other) || + #| (self.size == other.size && self.tree == other.tree) + #|} + #|pub impl[A : Show] Show for T[A] with output(self, logger) { + #| logger.write_iter( + #| self.iter(), + #| prefix="@immut/array.from_array([", + #| suffix="])", + #| ) + #|} + #|pub impl[A : Compare] Compare for T[A] with compare(self, other) { + #| let len_self = self.length() + #| let len_other = other.length() + #| let cmp = len_self.compare(len_other) + #| guard cmp is 0 else { return cmp } + #| for i in 0.. Tree[A] { + #| if cap == branching_factor { + #| Leaf(leaves[0]) + #| } else if leaves.length() <= branching_factor { + #| let arr = FixedArray::make(leaves.length(), Empty) + #| for i in 0.. { + #| from_leaves(leaves[i * times:(i + 1) * times], child_cap) + #| }) + #| } else { + #| let arr = FixedArray::make(quot + 1, Tree::Empty) + #| for i in 0.. (Int, Int) { + #| for cap = branching_factor, depth = 0; cap < size; { + #| continue cap * branching_factor, depth + 1 + #| } nobreak { + #| (num_bits * depth, cap) + #| } + #|} + ), + "deprecated.mbt": ( + #|#deprecated("We don't copy immutable array") + #|#coverage.skip + #|#alias(clone, deprecated) + #|pub fn[A] T::copy(self : T[A]) -> T[A] { + #| fn copy(t : Tree[A]) -> Tree[A] { + #| match t { + #| Leaf(l) => Leaf(l.copy()) + #| Empty => Empty + #| Node(node, sizes) => + #| Node( + #| FixedArray::makei(node.length(), i => copy(node[i])), + #| match sizes { + #| Some(sizes) => Some(FixedArray::copy(sizes)) + #| None => None + #| }, + #| ) + #| } + #| } + #| { tree: copy(self.tree), size: self.size, shift: self.shift } + #|} + ), + "tree.mbt": ( + #|let num_bits = 5 + #|let branching_factor : Int = 1 << num_bits + #|let bitmask : Int = branching_factor - 1 + #|const LINEAR_THRESHOLD : Int = 4 + #|const E_MAX : Int = 2 + #|let e_max_2 : Int = E_MAX / 2 + #|fn[T] Tree::empty() -> Tree[T] { + #| Tree::Empty + #|} + #|fn[T] new_branch_left(leaf : FixedArray[T], shift : Int) -> Tree[T] { + #| match shift { + #| 0 => Leaf(leaf) + #| s => Node([new_branch_left(leaf, s - num_bits)], None) // size is None because we can use radix indexing + #| } + #|} + #|fn[T] Tree::get_first(self : Tree[T]) -> T { + #| match self { + #| Leaf(leaf) => leaf[0] + #| Node(node, _) => node[0].get_first() + #| Empty => abort("Index out of bounds") + #| } + #|} + #|fn[T] Tree::get_last(self : Tree[T]) -> T { + #| match self { + #| Leaf(leaf) => leaf[leaf.length() - 1] + #| Node(node, _) => node[node.length() - 1].get_last() + #| Empty => abort("Index out of bounds") + #| } + #|} + #|fn[T] Tree::get(self : Tree[T], index : Int, shift : Int) -> T { + #| fn get_radix(node : Tree[T], shift : Int) -> T { + #| match node { + #| Leaf(leaf) => leaf[index & bitmask] + #| Node(node, None) => + #| get_radix(node[radix_indexing(index, shift)], shift - num_bits) + #| Node(_, Some(_)) => + #| abort("Unreachable: Node should not have sizes in get_radix") + #| Empty => abort("Index out of bounds") + #| } + #| } + #| match self { + #| Leaf(leaf) => leaf[index] + #| Node(children, Some(sizes)) => { + #| let branch_index = get_branch_index(sizes, index) + #| let sub_index = if branch_index == 0 { + #| index + #| } else { + #| index - sizes[branch_index - 1] + #| } + #| children[branch_index].get(sub_index, shift - num_bits) + #| } + #| Node(_, None) => get_radix(self, shift) + #| Empty => abort("Index out of bounds") + #| } + #|} + #|fn[T] Tree::set(self : Tree[T], index : Int, shift : Int, value : T) -> Tree[T] { + #| fn set_radix(node : Tree[T], shift : Int) -> Tree[T] { + #| match node { + #| Leaf(leaf) => Leaf(immutable_set(leaf, index & bitmask, value)) + #| Node(node, None) => { + #| let sub_idx = radix_indexing(index, shift) + #| Node( + #| immutable_set( + #| node, + #| sub_idx, + #| set_radix(node[radix_indexing(index, shift)], shift - num_bits), + #| ), + #| None, + #| ) + #| } + #| Node(_, Some(_)) => + #| abort("Unreachable: Node should not have sizes in set_radix") + #| Empty => abort("Index out of bounds") + #| } + #| } + #| match self { + #| Leaf(leaf) => Leaf(immutable_set(leaf, index & bitmask, value)) + #| Node(children, Some(sizes)) => { + #| let branch_index = get_branch_index(sizes, index) + #| let sub_index = if branch_index == 0 { + #| index + #| } else { + #| index - sizes[branch_index - 1] + #| } + #| Node( + #| immutable_set( + #| children, + #| branch_index, + #| children[branch_index].set(sub_index, shift - num_bits, value), + #| ), + #| Some(sizes), + #| ) + #| } + #| Node(_children, None) => set_radix(self, shift) + #| Empty => abort("Index out of bounds") + #| } + #|} + #|fn[T] Tree::push_end(self : Tree[T], shift : Int, value : T) -> (Tree[T], Int) { + #| fn update_sizes_last(sizes : FixedArray[Int]?) -> FixedArray[Int]? { + #| match sizes { + #| Some(sizes) => { + #| let new_sizes = sizes.copy() + #| new_sizes[new_sizes.length() - 1] += 1 + #| Some(new_sizes) + #| } + #| None => None + #| } + #| } + #| fn push_sizes_last(sizes : FixedArray[Int]?) -> FixedArray[Int]? { + #| match sizes { + #| Some(sizes) => Some(immutable_push(sizes, 1 + sizes[sizes.length() - 1])) + #| None => None + #| } + #| } + #| fn worker(node : Tree[T], shift : Int) -> Tree[T]? { + #| match node { + #| Leaf(leaf) => { + #| if shift != 0 { + #| abort( + #| "Unreachable: Leaf should not have a non-zero shift, which means we have not reached the bottom of the tree", + #| ) + #| } + #| if leaf.length() < branching_factor { + #| Some(Leaf(immutable_push(leaf, value))) + #| } else { + #| None + #| } + #| } + #| Node(nodes, sizes) => { + #| let len = nodes.length() + #| match worker(nodes[len - 1], shift - num_bits) { + #| Some(new_node) => { + #| let new_nodes = nodes.copy() + #| new_nodes[len - 1] = new_node + #| let sizes = update_sizes_last(sizes) + #| Some(Node(new_nodes, sizes)) + #| } + #| None => + #| if len < branching_factor { + #| let sizes = push_sizes_last(sizes) + #| Some( + #| Node( + #| immutable_push( + #| nodes, + #| new_branch_left([value], shift - num_bits), + #| ), + #| sizes, + #| ), + #| ) + #| } else { + #| None + #| } + #| } + #| } + #| Empty => Some(Leaf([value])) + #| } + #| } + #| match worker(self, shift) { + #| Some(new_tree) => (new_tree, shift) + #| None => { + #| let new_branch = new_branch_left([value], shift) + #| ( + #| match self { + #| Leaf(_leaf) => Node([self, new_branch], None) + #| Node(_nodes, Some(sizes)) => { + #| let len = sizes[sizes.length() - 1] + #| let sizes = FixedArray::from_array([len, 1 + len]) + #| Node([self, new_branch], Some(sizes)) + #| } + #| Node(_nodes, None) => Node([self, new_branch], None) + #| Empty => + #| abort( + #| "Unreachable: Empty tree should have fallen into the Some(new_tree) branch", + #| ) + #| }, + #| shift + num_bits, + #| ) + #| } + #| } + #|} + #|fn[A] Tree::each(self : Tree[A], f : (A) -> Unit raise?) -> Unit raise? { + #| match self { + #| Empty => () + #| Leaf(l) => l.each(f) + #| Node(ns, _) => ns.each(t => t.each(f)) + #| } + #|} + #|fn[A] Tree::iter(self : Tree[A]) -> Iter[A] { + #| let mut curr_tree = self + #| let mut curr_index = 0 + #| let parents = [] + #| Iter::new(fn() { + #| loop curr_tree { + #| Node(children, _) as t if curr_index < children.length() => { + #| let child = children.unsafe_get(curr_index) + #| parents.push((t, curr_index + 1)) + #| curr_tree = child + #| curr_index = 0 + #| continue child + #| } + #| Leaf(elems) if curr_index < elems.length() => { + #| let elem = elems.unsafe_get(curr_index) + #| curr_index += 1 + #| Some(elem) + #| } + #| _ if parents.pop() is Some((parent_tree, parent_index)) => { + #| curr_tree = parent_tree + #| curr_index = parent_index + #| continue parent_tree + #| } + #| _ => None + #| } + #| }) + #|} + #|fn[A] Tree::eachi( + #| self : Tree[A], + #| f : (Int, A) -> Unit raise?, + #| shift : Int, + #| start : Int, + #|) -> Unit raise? { + #| match self { + #| Empty => () + #| Leaf(l) => + #| for i in 0.. { + #| let child_shift = shift - num_bits + #| for i in 0.. { + #| let child_shift = shift - num_bits + #| for i in 0.. B raise?, + #|) -> B raise? { + #| match self { + #| Empty => acc + #| Leaf(l) => l.fold(f, init=acc) + #| Node(n, _) => n.fold((acc, t) => t.fold(acc, f), init=acc) + #| } + #|} + #|fn[A, B] Tree::rev_fold( + #| self : Tree[A], + #| acc : B, + #| f : (B, A) -> B raise?, + #|) -> B raise? { + #| match self { + #| Empty => acc + #| Leaf(l) => l.rev_fold(f, init=acc) + #| Node(n, _) => n.rev_fold((acc, t) => t.rev_fold(acc, f), init=acc) + #| } + #|} + #|fn[A, B] Tree::map(self : Tree[A], f : (A) -> B raise?) -> Tree[B] raise? { + #| match self { + #| Empty => Empty + #| Leaf(l) => Leaf(l.map(f)) + #| Node(n, szs) => + #| Node(FixedArray::makei(n.length(), i => n[i].map(f)), copy_sizes(szs)) + #| } + #|} + #|fn[A] Tree::concat( + #| left : Tree[A], + #| left_shift : Int, + #| right : Tree[A], + #| right_shift : Int, + #| top : Bool, + #|) -> (Tree[A], Int) { + #| if left_shift > right_shift { + #| let (c, c_shift) = Tree::concat( + #| left.right_child(), + #| left_shift - num_bits, + #| right, + #| right_shift, + #| false, + #| ) + #| guard c_shift == left_shift + #| return rebalance(left, c, Empty, left_shift, top) + #| } else if right_shift > left_shift { + #| let (c, c_shift) = Tree::concat( + #| left, + #| left_shift, + #| right.left_child(), + #| right_shift - num_bits, + #| false, + #| ) + #| guard c_shift == right_shift + #| return rebalance(Empty, c, right, right_shift, top) + #| } else if left_shift == 0 { + #| let left_elems = left.leaf_elements() + #| let right_elems = right.leaf_elements() + #| let left_len = left_elems.length() + #| let right_len = right_elems.length() + #| let len = left_len + right_len + #| if top && len <= branching_factor { + #| return ( + #| Leaf( + #| FixedArray::makei(len, (i : Int) => { + #| if i < left_len { + #| left_elems[i] + #| } else { + #| right_elems[i - left_len] + #| } + #| }), + #| ), + #| 0, + #| ) + #| } else { + #| return ( + #| Node( + #| FixedArray::from_array([left, right]), + #| Some(FixedArray::from_array([left_len, len])), + #| ), + #| num_bits, + #| ) + #| } + #| } else { + #| let (c, c_shift) = Tree::concat( + #| left.right_child(), + #| left_shift - num_bits, + #| right.left_child(), + #| right_shift - num_bits, + #| false, + #| ) + #| guard c_shift == left_shift + #| guard c_shift == right_shift + #| return rebalance(left, c, right, left_shift, top) + #| } + #|} + #|fn[A] rebalance( + #| left : Tree[A], + #| center : Tree[A], + #| right : Tree[A], + #| shift : Int, + #| top : Bool, + #|) -> (Tree[A], Int) { + #| let t = tri_merge(left, center, right) // t is a list of trees of (H-1) height + #| let (nc, nc_len) = redis_plan(t) + #| let new_t = redis(t, nc, nc_len, shift - num_bits) // new_t is a list of trees of (H-1) height + #| guard new_t.length() == nc_len + #| if nc_len <= branching_factor { + #| let node = Node(new_t, compute_sizes(new_t, shift - num_bits)) // node of H height + #| if !top { + #| return (Node(FixedArray::from_array([node]), None), shift + num_bits) + #| } else { + #| return (node, shift) + #| } + #| } else { + #| let new_child_1 = FixedArray::makei(branching_factor, i => new_t[i]) + #| let new_child_2 = FixedArray::makei(new_t.length() - branching_factor, i => { + #| new_t[i + branching_factor] + #| }) + #| let new_node_1 = Node( + #| new_child_1, + #| compute_sizes(new_child_1, shift - num_bits), + #| ) // height H + #| let new_node_2 = Node( + #| new_child_2, + #| compute_sizes(new_child_2, shift - num_bits), + #| ) // height H + #| let new_children = FixedArray::from_array([new_node_1, new_node_2]) + #| return ( + #| Node(new_children, compute_sizes(new_children, shift)), + #| shift + num_bits, + #| ) // return (H+1) height node + #| } + #|} + #|fn[A] tri_merge( + #| left : Tree[A], + #| center : Tree[A], + #| right : Tree[A], + #|) -> FixedArray[Tree[A]] { + #| if left.is_leaf() || !center.is_node() || right.is_leaf() { + #| abort("Unreachable: input to merge is invalid") + #| } + #| fn get_children(self : Tree[A]) -> FixedArray[Tree[A]] { + #| match self { + #| Node(children, _) => children + #| Empty => [] + #| Leaf(_) => abort("Unreachable") + #| } + #| } + #| let left_children = get_children(left) + #| let center_children = get_children(center) + #| let right_children = get_children(right) + #| let left_len = left_children.length() + #| let left_len = if left_len == 0 { 0 } else { left_len - 1 } + #| let center_len = center_children.length() + #| let right_len = right_children.length() + #| let right_len = if right_len == 0 { 0 } else { right_len - 1 } + #| FixedArray::makei(left_len + center_len + right_len, i => { + #| if i < left_len { + #| left_children[i] + #| } else if i < left_len + center_len { + #| center_children[i - left_len] + #| } else if right_len > 0 { + #| right_children[1 + i - left_len - center_len] + #| } else { + #| abort("Unreachable") + #| } + #| }) + #|} + #|fn[A] redis_plan(t : FixedArray[Tree[A]]) -> (FixedArray[Int], Int) { + #| let node_counts = FixedArray::makei(t.length(), i => t[i].local_size()) + #| let total_nodes = node_counts.fold(init=0, (acc, x) => acc + x) + #| let opt_len = (total_nodes + branching_factor - 1) / branching_factor + #| let mut new_len = t.length() + #| let mut i = 0 + #| while opt_len + e_max_2 < new_len { + #| while node_counts[i] > branching_factor - e_max_2 { + #| i += 1 + #| } + #| let mut remaining_nodes = node_counts[i] + #| while remaining_nodes > 0 { + #| let min_size = min(remaining_nodes + node_counts[i + 1], branching_factor) + #| node_counts[i] = min_size + #| remaining_nodes = remaining_nodes + node_counts[i + 1] - min_size + #| i += 1 + #| } + #| for j in i..<(new_len - 1) { + #| node_counts[j] = node_counts[j + 1] + #| } + #| new_len -= 1 + #| i -= 1 + #| } + #| return (node_counts, new_len) + #|} + #|fn[A] redis( + #| old_t : FixedArray[Tree[A]], + #| node_counts : FixedArray[Int], + #| node_nums : Int, + #| shift : Int, + #|) -> FixedArray[Tree[A]] { + #| let old_len = old_t.length() + #| let new_t = FixedArray::make(node_nums, Empty) + #| let mut old_offset = 0 + #| let mut j = 0 // the index of in the old tree + #| if shift == 0 { + #| let mut old_leaf_elems = FixedArray::default() + #| let mut old_leaf_len = 0 + #| for i in 0.. FixedArray[Int]? { + #| let len = children.length() + #| let sizes = FixedArray::make(len, 0) + #| let mut sum = 0 + #| let mut flag = true + #| let full_subtree_size = branching_factor << shift + #| for i in 0.. String { + #| String::make(indent, ' ') + s + #| } + #| fn aux(t : Tree[A], ident : Int) { + #| match t { + #| Empty => indent_str("Empty", ident) + #| Leaf(l) => { + #| let s = for i in 0.. { + #| let s = for + #| i in 0.. Bool { + #| self is Node(_, _) + #|} + #|fn[A] Tree::is_leaf(self : Tree[A]) -> Bool { + #| self is Leaf(_) + #|} + #|fn[A] Tree::right_child(self : Tree[A]) -> Tree[A] { + #| match self { + #| Node(children, _) => children[children.length() - 1] + #| Leaf(_) | Empty => abort("Should not get children on non-`Node`s") + #| } + #|} + #|fn[A] Tree::left_child(self : Tree[A]) -> Tree[A] { + #| match self { + #| Node(children, _) => children[0] + #| Leaf(_) | Empty => abort("Should not get children on non-`Node`s") + #| } + #|} + #|fn[A] Tree::leaf_elements(self : Tree[A]) -> FixedArray[A] { + #| guard self is Leaf(children) else { + #| abort("Should not call `get_leaf_elements` on non-leaf nodes") + #| } + #| children + #|} + #|fn[A] Tree::node_children(self : Tree[A]) -> FixedArray[Tree[A]] { + #| guard self is Node(children, _) else { + #| abort("Should not call `node_children` on non-`Node`s") + #| } + #| children + #|} + #|fn[A] Tree::local_size(self : Tree[A]) -> Int { + #| match self { + #| Empty => 0 + #| Leaf(l) => l.length() + #| Node(children, _) => children.length() + #| } + #|} + #|fn[A] Tree::size(self : Tree[A], shift : Int) -> Int { + #| match self { + #| Empty => 0 + #| Leaf(l) => l.length() + #| Node(_, Some(sizes)) => sizes[sizes.length() - 1] + #| Node(children, None) => { + #| let len_1 = children.length() - 1 + #| (len_1 << shift) + children[len_1].size(shift - num_bits) + #| } + #| } + #|} + ), + "types.mbt": ( + #|struct T[A] { + #| tree : Tree[A] + #| size : Int + #| shift : Int + #|} + #|priv enum Tree[A] { + #| Empty + #| Node(FixedArray[Tree[A]], FixedArray[Int]?) // (Subtrees, Sizes of subtrees) + #| Leaf(FixedArray[A]) + #|} derive(Eq) + ), + "utils.mbt": ( + #|fn[T] immutable_set(arr : FixedArray[T], i : Int, v : T) -> FixedArray[T] { + #| let arr = arr.copy() + #| arr[i] = v + #| arr + #|} + #|fn[T] immutable_push(arr : FixedArray[T], val : T) -> FixedArray[T] { + #| let len = arr.length() + #| let new_arr = FixedArray::make(len + 1, val) + #| arr.blit_to(new_arr, len~) + #| new_arr[len] = val + #| new_arr + #|} + #|fn shr_as_uint(x : Int, y : Int) -> Int { + #| (x.reinterpret_as_uint() >> y).reinterpret_as_int() + #|} + #|fn radix_indexing(index : Int, shift : Int) -> Int { + #| shr_as_uint(index, shift) & bitmask + #|} + #|fn get_branch_index(sizes : FixedArray[Int], index : Int) -> Int { + #| let lo = for lo = 0, hi = sizes.length(); LINEAR_THRESHOLD < hi - lo; { + #| let mid = (lo + hi) / 2 + #| if sizes[mid] <= index { + #| continue mid, hi + #| } else { + #| continue lo, mid + #| } + #| } nobreak { + #| lo + #| } + #| for lo = lo; sizes[lo] <= index; { + #| continue lo + 1 + #| } nobreak { + #| lo + #| } + #|} + #|fn copy_sizes(sizes : FixedArray[Int]?) -> FixedArray[Int]? { + #| match sizes { + #| Some(sizes) => Some(sizes.copy()) + #| None => None + #| } + #|} + #|fn min(a : Int, b : Int) -> Int { + #| if a < b { + #| a + #| } else { + #| b + #| } + #|} + ), + "utils_wbtest2.mbt": ( + #|test "immutable_set" { + #| let arr = FixedArray::from_array([1, 2, 3, 4, 5]) + #| let new_arr = immutable_set(arr, 2, 10) + #| inspect(new_arr[2], content="10") + #| inspect(arr[2], content="3") // Original array unchanged + #| inspect(new_arr.length(), content="5") + #|} + #|test "immutable_push" { + #| let arr = FixedArray::from_array([1, 2, 3]) + #| let new_arr = immutable_push(arr, 4) + #| inspect(new_arr.length(), content="4") + #| inspect(new_arr[3], content="4") + #| inspect(arr.length(), content="3") // Original array unchanged + #|} + #|test "shr_as_uint" { + #| inspect(shr_as_uint(16, 2), content="4") + #| inspect(shr_as_uint(8, 1), content="4") + #| inspect(shr_as_uint(-1, 1), content="2147483647") // Handle negative numbers as unsigned + #|} + #|test "radix_indexing" { + #| inspect(radix_indexing(35, 5), content="1") // 35 >> 5 = 1, 1 & 31 = 1 + #| inspect(radix_indexing(100, 5), content="3") // 100 >> 5 = 3, 3 & 31 = 3 + #| inspect(radix_indexing(7, 5), content="0") // 7 >> 5 = 0, 0 & 31 = 0 + #|} + #|test "get_branch_index" { + #| let sizes = FixedArray::from_array([3, 6, 10, 15]) + #| inspect(get_branch_index(sizes, 2), content="0") // Index 2 is in first branch (contains indexes 0-2) + #| inspect(get_branch_index(sizes, 5), content="1") // Index 5 is in second branch (contains indexes 3-5) + #| inspect(get_branch_index(sizes, 8), content="2") // Index 8 is in third branch (contains indexes 6-9) + #|} + #|test "copy_sizes with Some" { + #| let original = FixedArray::from_array([1, 2, 3]) + #| let sizes = Some(original) + #| let copied = copy_sizes(sizes) + #| match copied { + #| Some(copied_arr) => { + #| inspect(copied_arr.length(), content="3") + #| inspect(copied_arr[0], content="1") + #| inspect(copied_arr[1], content="2") + #| inspect(copied_arr[2], content="3") + #| original[0] = 100 + #| inspect(copied_arr[0], content="1") // Should still be 1 + #| } + #| None => inspect("Should not be None", content="error") + #| } + #|} + #|test "copy_sizes with None" { + #| let sizes : FixedArray[Int]? = None + #| let copied = copy_sizes(sizes) + #| match copied { + #| None => inspect("None copied correctly", content="None copied correctly") + #| Some(_) => inspect("Should be None", content="error") + #| } + #|} + #|test "min function" { + #| inspect(min(5, 3), content="3") + #| inspect(min(1, 10), content="1") + #| inspect(min(-5, 0), content="-5") + #| inspect(min(42, 42), content="42") + #|} + ) + } ) ///| let moonbitlang_core_immut_hashmap_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/immut/hashmap", - deps={ - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/array": moonbitlang_core_array_module, - "moonbitlang/core/tuple": moonbitlang_core_tuple_module, - "moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module, - "moonbitlang/core/immut/internal/sparse_array": moonbitlang_core_immut_internal_sparse_array_module, - "moonbitlang/core/immut/internal/path": moonbitlang_core_immut_internal_path_module, - "moonbitlang/core/list": moonbitlang_core_list_module, - }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| "moonbitlang/core/builtin", - #| "moonbitlang/core/array", - #| "moonbitlang/core/tuple", - #| "moonbitlang/core/quickcheck", - #| "moonbitlang/core/immut/internal/sparse_array", - #| "moonbitlang/core/immut/internal/path", - #| "moonbitlang/core/list" - #| ], - #| "test-import": [ - #| "moonbitlang/core/int", - #| "moonbitlang/core/string", - #| "moonbitlang/core/option" - #| ] - #|} - ), - "HAMT.mbt": ( - #|#as_free_fn - #|pub fn[K, V] HashMap::new() -> HashMap[K, V] { - #| None - #|} - #|#as_free_fn - #|pub fn[K : Hash, V] HashMap::singleton(key : K, value : V) -> HashMap[K, V] { - #| Some(Flat(key, value, @path.of(key))) - #|} - #|pub fn[K : Eq + Hash, V] HashMap::contains( - #| self : HashMap[K, V], - #| key : K, - #|) -> Bool { - #| self.get(key) is Some(_) - #|} - #|#alias(find, deprecated) - #|pub fn[K : Eq + Hash, V] HashMap::get(self : HashMap[K, V], key : K) -> V? { - #| match self.0 { - #| None => None - #| Some(node) => node.get_with_path(key, @path.of(key)) - #| } - #|} - #|#alias("_[_]") - #|pub fn[K : Eq + Hash, V] HashMap::at(self : HashMap[K, V], key : K) -> V { - #| guard self.0 is Some(node) - #| node.get_with_path(key, @path.of(key)).unwrap() - #|} - #|fn[K : Eq, V] Node::get_with_path( - #| self : Node[K, V], - #| key : K, - #| path : Path, - #|) -> V? { - #| loop (self, path) { - #| (Leaf(key1, value1, bucket), _) => - #| if key == key1 { - #| Some(value1) - #| } else { - #| bucket.lookup(key) - #| } - #| (Flat(key1, value1, path1), path) => - #| if path == path1 && key == key1 { - #| Some(value1) - #| } else { - #| None - #| } - #| (Branch(children), path) => { - #| let idx = path.idx() - #| if children.get(idx) is Some(child) { - #| continue (child, path.next()) - #| } - #| None - #| } - #| } - #|} - #|fn[K, V] join_2( - #| key1 : K, - #| value1 : V, - #| path1 : Path, - #| key2 : K, - #| value2 : V, - #| path2 : Path, - #|) -> Node[K, V] { - #| let idx1 = path1.idx() - #| let idx2 = path2.idx() - #| if idx1 == idx2 { - #| let node = if path1.is_last() { - #| Leaf(key2, value2, @list.singleton((key1, value1))) - #| } else { - #| join_2(key1, value1, path1.next(), key2, value2, path2.next()) - #| } - #| Branch(@sparse_array.singleton(idx1, node)) - #| } else { - #| let (node1, node2) = if path1.is_last() { - #| (Leaf(key1, value1, @list.empty()), Leaf(key2, value2, @list.empty())) - #| } else { - #| (Flat(key1, value1, path1.next()), Flat(key2, value2, path2.next())) - #| } - #| Branch(@sparse_array.doubleton(idx1, node1, idx2, node2)) - #| } - #|} - #|fn[K : Eq, V] Node::add_with_path( - #| self : Node[K, V], - #| key : K, - #| value : V, - #| path : Path, - #|) -> Node[K, V] { - #| match self { - #| Leaf(key1, value1, bucket) => - #| if key == key1 { - #| Leaf(key, value, bucket) - #| } else { - #| let new_bucket = match bucket.find_index(kv => kv.0 == key) { - #| None => bucket - #| Some(index) => bucket.remove_at(index) - #| } - #| Leaf(key, value, new_bucket.add((key1, value1))) - #| } - #| Flat(key1, value1, path1) => - #| if path == path1 && key == key1 { - #| Flat(key1, value, path1) - #| } else { - #| join_2(key1, value1, path1, key, value, path) - #| } - #| Branch(children) => { - #| let idx = path.idx() - #| match children.get(idx) { - #| Some(child) => { - #| let child = child.add_with_path(key, value, path.next()) - #| Branch(children.replace(idx, child)) - #| } - #| None => { - #| let child = Flat(key, value, path.next()) - #| Branch(children.add(idx, child)) - #| } - #| } - #| } - #| } - #|} - #|#alias(filter_with_key, deprecated) - #|pub fn[K, V] HashMap::filter( - #| self : HashMap[K, V], - #| pred : (K, V) -> Bool raise?, - #|) -> HashMap[K, V] raise? { - #| fn go(node) raise? { - #| match node { - #| Leaf(key1, value1, bucket) => { - #| let new_bucket = bucket.filter(kv => pred(kv.0, kv.1)) - #| if pred(key1, value1) { - #| Some(Leaf(key1, value1, new_bucket)) - #| } else { - #| match new_bucket { - #| Empty => None - #| More((k1, v1), tail~) => Some(Leaf(k1, v1, tail)) - #| } - #| } - #| } - #| Flat(key1, value1, _) => - #| if pred(key1, value1) { - #| Some(node) - #| } else { - #| None - #| } - #| Branch(children) => - #| match children.filter(go) { - #| None => None - #| Some(new_children) => Some(Branch(new_children)) - #| } - #| } - #| } - #| match self.0 { - #| None => None - #| Some(node) => go(node) - #| } - #|} - #|#alias(fold_with_key, deprecated) - #|pub fn[K, V, A] HashMap::fold( - #| self : HashMap[K, V], - #| init~ : A, - #| f : (A, K, V) -> A raise?, - #|) -> A raise? { - #| fn go(acc, node) raise? { - #| match node { - #| Leaf(k, v, bucket) => - #| bucket.fold(init=f(acc, k, v), (acc, kv) => f(acc, kv.0, kv.1)) - #| Flat(k, v, _) => f(acc, k, v) - #| Branch(children) => children.data.fold(init=acc, go) - #| } - #| } - #| match self.0 { - #| None => init - #| Some(node) => go(init, node) - #| } - #|} - #|#alias(map_with_key, deprecated) - #|pub fn[K, V, A] HashMap::map( - #| self : HashMap[K, V], - #| f : (K, V) -> A raise?, - #|) -> HashMap[K, A] raise? { - #| fn go(m : Node[K, V]) -> Node[K, A] raise? { - #| match m { - #| Leaf(k, v, bucket) => - #| Leaf(k, f(k, v), bucket.map(kv => (kv.0, f(kv.0, kv.1)))) - #| Flat(k, v, path) => Flat(k, f(k, v), path) - #| Branch(children) => Branch(children.map(go)) - #| } - #| } - #| match self.0 { - #| None => None - #| Some(node) => Some(go(node)) - #| } - #|} - #|pub fn[K : Eq + Hash, V] HashMap::add( - #| self : HashMap[K, V], - #| key : K, - #| value : V, - #|) -> HashMap[K, V] { - #| match self.0 { - #| None => Some(Flat(key, value, @path.of(key))) - #| Some(node) => Some(node.add_with_path(key, value, @path.of(key))) - #| } - #|} - #|pub fn[K : Eq + Hash, V] HashMap::remove( - #| self : HashMap[K, V], - #| key : K, - #|) -> HashMap[K, V] { - #| match self.0 { - #| None => None - #| Some(node) => node.remove_with_path(key, @path.of(key)) - #| } - #|} - #|fn[K : Eq, V] Node::remove_with_path( - #| self : Node[K, V], - #| key : K, - #| path : Path, - #|) -> Node[K, V]? { - #| match self { - #| Leaf(key1, value1, bucket) => - #| if key1 == key { - #| match bucket { - #| @list.Empty => None - #| More((key2, value2), tail~) => Some(Leaf(key2, value2, tail)) - #| } - #| } else if bucket.find_index(kv => kv.0 == key) is Some(index) { - #| Some(Leaf(key1, value1, bucket.remove_at(index))) - #| } else { - #| Some(self) - #| } - #| Flat(key1, _, path1) => - #| if path == path1 && key == key1 { - #| None - #| } else { - #| Some(self) - #| } - #| Branch(children) => { - #| let idx = path.idx() - #| match children.get(idx) { - #| None => Some(self) - #| Some(child) => { - #| let new_child = child.remove_with_path(key, path.next()) - #| let new_children = match (children.length(), new_child) { - #| (1, None) => return None - #| (_, None) => children.remove(idx) - #| (_, Some(new_child)) => children.replace(idx, new_child) - #| } - #| match new_children.data { - #| [Flat(key1, value1, path1)] => - #| Some( - #| Flat( - #| key1, - #| value1, - #| path1.push(new_children.elem_info.first_idx()), - #| ), - #| ) - #| _ => Some(Branch(new_children)) - #| } - #| } - #| } - #| } - #| } - #|} - #|#alias(size, deprecated) - #|pub fn[K, V] HashMap::length(self : HashMap[K, V]) -> Int { - #| fn node_size(node) { - #| match node { - #| Leaf(_, _, bucket) => 1 + bucket.length() - #| Flat(_) => 1 - #| Branch(children) => - #| for i = 0, total_size = 0; i < children.data.length(); { - #| continue i + 1, total_size + node_size(children.data[i]) - #| } else { - #| total_size - #| } - #| } - #| } - #| match self.0 { - #| None => 0 - #| Some(node) => node_size(node) - #| } - #|} - #|#alias(merge) - #|pub fn[K : Eq, V] HashMap::union( - #| self : HashMap[K, V], - #| other : HashMap[K, V], - #|) -> HashMap[K, V] { - #| fn go(node1 : Node[_], node2) { - #| match (node1, node2) { - #| (_, Flat(key2, value2, path2)) => node1.add_with_path(key2, value2, path2) - #| (Flat(key1, value1, path1), _) => - #| match node2.get_with_path(key1, path1) { - #| Some(_) => node2 - #| None => node2.add_with_path(key1, value1, path1) - #| } - #| (Branch(children1), Branch(children2)) => - #| Branch(children1.union(children2, go)) - #| (Leaf(key1, value1, bucket1), Leaf(key2, value2, bucket2)) => { - #| let kvs1 = bucket1.add((key1, value1)) - #| let kvs2 = bucket2.add((key2, value2)) - #| match kvs1.filter(kv => kvs2.lookup(kv.0) is None) { - #| Empty => node2 - #| More(head, tail~) => Leaf(key2, value2, bucket2 + tail.add(head)) - #| } - #| } - #| _ => abort("Unreachable") - #| } - #| } - #| match (self.0, other.0) { - #| (None, x) | (x, None) => x - #| (Some(a), Some(b)) => Some(go(a, b)) - #| } - #|} - #|pub fn[K : Eq, V] HashMap::union_with( - #| self : HashMap[K, V], - #| other : HashMap[K, V], - #| f : (K, V, V) -> V raise?, - #|) -> HashMap[K, V] raise? { - #| fn go(node1 : Node[_], node2) raise? { - #| match (node1, node2) { - #| (_, Flat(key2, value2, path2)) => { - #| let new_value = match node1.get_with_path(key2, path2) { - #| Some(value1) => f(key2, value1, value2) - #| None => value2 - #| } - #| node1.add_with_path(key2, new_value, path2) - #| } - #| (Flat(key1, value1, path1), _) => { - #| let new_value = match node2.get_with_path(key1, path1) { - #| Some(value2) => f(key1, value1, value2) - #| None => value1 - #| } - #| node2.add_with_path(key1, new_value, path1) - #| } - #| (Branch(children1), Branch(children2)) => - #| Branch(children1.union(children2, go)) - #| (Leaf(key1, value1, bucket1), Leaf(key2, value2, bucket2)) => { - #| let kvs1 = bucket1.add((key1, value1)) - #| let kvs2 = bucket2.add((key2, value2)) - #| kvs1.union_with(kvs2, f) - #| } - #| _ => abort("Unreachable") - #| } - #| } - #| match (self.0, other.0) { - #| (None, x) | (x, None) => x - #| (Some(a), Some(b)) => Some(go(a, b)) - #| } - #|} - #|fn[K : Eq, V] @list.List::union_with( - #| self : Self[(K, V)], - #| other : Self[(K, V)], - #| f : (K, V, V) -> V raise?, - #|) -> Node[K, V] raise? { - #| let res = self.to_array() - #| for kv2 in other { - #| for i, kv1 in res { - #| if kv1.0 == kv2.0 { - #| res[i] = (kv1.0, f(kv1.0, kv1.1, kv2.1)) - #| break - #| } - #| } else { - #| res.push(kv2) - #| } - #| } - #| guard @list.from_array(res) is More((k, v), tail~) - #| Leaf(k, v, tail) - #|} - #|pub fn[K : Eq, V] HashMap::intersection( - #| self : HashMap[K, V], - #| other : HashMap[K, V], - #|) -> HashMap[K, V] { - #| fn go(node1 : Node[_], node2) { - #| match (node1, node2) { - #| (_, Flat(key2, _, path2)) => - #| match node1.get_with_path(key2, path2) { - #| Some(_) => Some(node2) - #| None => None - #| } - #| (Flat(key1, _, path1), _) => - #| match node2.get_with_path(key1, path1) { - #| Some(value2) => Some(Flat(key1, value2, path1)) - #| None => None - #| } - #| (Branch(children1), Branch(children2)) => - #| match children1.intersection(children2, go) { - #| None => None - #| Some({ data: [Flat(key, value, path)], elem_info }) => - #| Some(Flat(key, value, path.push(elem_info.first_idx()))) - #| Some(children) => Some(Branch(children)) - #| } - #| (Leaf(key1, value1, bucket1), Leaf(key2, value2, bucket2)) => { - #| let kvs1 = bucket1.add((key1, value1)) - #| let kvs2 = bucket2.add((key2, value2)) - #| match kvs2.filter(kv => kvs1.lookup(kv.0) is Some(_)) { - #| Empty => None - #| More(head, tail~) => Some(Leaf(head.0, head.1, tail)) - #| } - #| } - #| _ => abort("Unreachable") - #| } - #| } - #| match (self.0, other.0) { - #| (None, _) | (_, None) => None - #| (Some(a), Some(b)) => go(a, b) - #| } - #|} - #|pub fn[K : Eq, V] HashMap::intersection_with( - #| self : HashMap[K, V], - #| other : HashMap[K, V], - #| f : (K, V, V) -> V raise?, - #|) -> HashMap[K, V] raise? { - #| fn go(node1 : Node[_], node2) raise? { - #| match (node1, node2) { - #| (_, Flat(key2, value2, path2)) => - #| match node1.get_with_path(key2, path2) { - #| Some(value1) => Some(Flat(key2, f(key2, value1, value2), path2)) - #| None => None - #| } - #| (Flat(key1, value1, path1), _) => - #| match node2.get_with_path(key1, path1) { - #| Some(value2) => Some(Flat(key1, f(key1, value1, value2), path1)) - #| None => None - #| } - #| (Branch(children1), Branch(children2)) => - #| match children1.intersection(children2, go) { - #| None => None - #| Some({ data: [Flat(key, value, path)], elem_info }) => - #| Some(Flat(key, value, path.push(elem_info.first_idx()))) - #| Some(children) => Some(Branch(children)) - #| } - #| (Leaf(key1, value1, bucket1), Leaf(key2, value2, bucket2)) => { - #| let kvs1 = bucket1.add((key1, value1)) - #| let kvs2 = bucket2.add((key2, value2)) - #| kvs1.intersection_with(kvs2, f) - #| } - #| _ => abort("Unreachable") - #| } - #| } - #| match (self.0, other.0) { - #| (None, _) | (_, None) => None - #| (Some(a), Some(b)) => go(a, b) - #| } - #|} - #|fn[K : Eq, V] @list.List::intersection_with( - #| self : Self[(K, V)], - #| other : Self[(K, V)], - #| f : (K, V, V) -> V raise?, - #|) -> Node[K, V]? raise? { - #| let res = [] - #| for kv1 in self { - #| for kv2 in other { - #| if kv1.0 == kv2.0 { - #| res.push((kv1.0, f(kv1.0, kv1.1, kv2.1))) - #| break - #| } - #| } - #| } - #| match @list.from_array(res) { - #| Empty => None - #| More((k, v), tail~) => Some(Leaf(k, v, tail)) - #| } - #|} - #|pub fn[K : Eq, V] HashMap::difference( - #| self : HashMap[K, V], - #| other : HashMap[K, V], - #|) -> HashMap[K, V] { - #| fn go(node1 : Node[_], node2) { - #| match (node1, node2) { - #| (node, Flat(k, _, path)) => node.remove_with_path(k, path) - #| (Flat(key, _, path), _) => - #| match node2.get_with_path(key, path) { - #| Some(_) => None - #| None => Some(node1) - #| } - #| (Branch(children1), Branch(children2)) => - #| match children1.difference(children2, go) { - #| None => None - #| Some({ data: [Flat(key, value, path)], elem_info }) => - #| Some(Flat(key, value, path.push(elem_info.first_idx()))) - #| Some(children) => Some(Branch(children)) - #| } - #| (Leaf(key1, value1, bucket1), Leaf(key2, value2, bucket2)) => { - #| let kvs1 = bucket1.add((key1, value1)) - #| let kvs2 = bucket2.add((key2, value2)) - #| match kvs1.filter(kv => not(kvs2.lookup(kv.0) is Some(_))) { - #| Empty => None - #| More(head, tail~) => Some(Leaf(head.0, head.1, tail)) - #| } - #| } - #| _ => abort("Unreachable") - #| } - #| } - #| match (self.0, other.0) { - #| (None, _) => None - #| (_, None) => self - #| (Some(a), Some(b)) => go(a, b) - #| } - #|} - #|pub fn[K, V] HashMap::each( - #| self : HashMap[K, V], - #| f : (K, V) -> Unit raise?, - #|) -> Unit raise? { - #| fn go(node) raise? { - #| match node { - #| Leaf(k, v, bucket) => { - #| f(k, v) - #| bucket.each(kv => f(kv.0, kv.1)) - #| } - #| Flat(k, v, _) => f(k, v) - #| Branch(children) => children.each(go) - #| } - #| } - #| match self.0 { - #| None => () - #| Some(node) => go(node) - #| } - #|} - #|pub fn[K, V] HashMap::keys(self : HashMap[K, V]) -> Iter[K] { - #| self.iter().map(p => p.0) - #|} - #|#alias(elems, deprecated="Use `values` instead") - #|pub fn[K, V] HashMap::values(self : HashMap[K, V]) -> Iter[V] { - #| self.iter().map(p => p.1) - #|} - #|pub fn[K, V] HashMap::iter(self : HashMap[K, V]) -> Iter[(K, V)] { - #| fn go(node) -> Iter[(K, V)] { - #| match node { - #| Leaf(k, v, bucket) => Iter::singleton((k, v)) + bucket.iter() - #| Flat(k, v, _) => Iter::singleton((k, v)) - #| Branch(children) => children.data.iter().flat_map(go) - #| } - #| } - #| match self.0 { - #| None => Iter::empty() - #| Some(node) => go(node) - #| } - #|} - #|pub fn[K, V] HashMap::iterator(self : HashMap[K, V]) -> Iterator[(K, V)] { - #| enum CurrNode { - #| Tree(Node[K, V]) - #| Bucket(@list.List[(K, V)]) - #| } - #| let empty = Bucket(@list.new()) - #| let mut curr_node = match self.0 { - #| Some(tree) => Tree(tree) - #| None => empty - #| } - #| let mut curr_index = 0 - #| let parents = [] - #| Iterator::new(fn() { - #| loop curr_node { - #| Tree(Flat(k, v, _)) => { - #| curr_node = empty - #| Some((k, v)) - #| } - #| Tree(Leaf(k, v, bucket)) => { - #| curr_node = Bucket(bucket) - #| Some((k, v)) - #| } - #| Bucket(More(pair, tail~)) => { - #| curr_node = Bucket(tail) - #| Some(pair) - #| } - #| Tree(Branch(children)) as n if curr_index < children.length() => { - #| let child = children.data[curr_index] - #| parents.push((n, curr_index + 1)) - #| curr_index = 0 - #| continue Tree(child) - #| } - #| Bucket(Empty) | Tree(Branch(_)) if parents.pop() - #| is Some((parent, parent_index)) => { - #| curr_node = parent - #| curr_index = parent_index - #| continue parent - #| } - #| Bucket(Empty) | Tree(Branch(_)) => None - #| } - #| }) - #|} - #|pub fn[K, V] HashMap::Iter2(self : HashMap[K, V]) -> Iter2[K, V] { - #| self.iterator() - #|} - #|pub fn[K, V] HashMap::iter2(self : HashMap[K, V]) -> Iter2[K, V] { - #| self.Iter2().iter2() - #|} - #|#as_free_fn - #|pub fn[K : Eq + Hash, V] HashMap::from_iter( - #| iter : Iter[(K, V)], - #|) -> HashMap[K, V] { - #| iter.fold(init=new(), (m, e) => m.add(e.0, e.1)) - #|} - #|#as_free_fn - #|pub fn[K : Eq + Hash, V] HashMap::from_iterator( - #| iter : Iterator[(K, V)], - #|) -> HashMap[K, V] { - #| iter.fold(init=new(), (m, e) => m.add(e.0, e.1)) - #|} - #|pub impl[K : Show, V : Show] Show for HashMap[K, V] with output(self, logger) { - #| logger.write_iter( - #| self.iter(), - #| prefix="@immut/hashmap.from_array([", - #| suffix="])", - #| ) - #|} - #|#as_free_fn - #|#alias(of, deprecated="Use from_array instead") - #|#as_free_fn(of, deprecated="Use from_array instead") - #|pub fn[K : Eq + Hash, V] HashMap::from_array( - #| arr : ArrayView[(K, V)], - #|) -> HashMap[K, V] { - #| loop (arr.length(), new()) { - #| (0, map) => map - #| (n, map) => { - #| let (k, v) = arr[n - 1] - #| continue (n - 1, map.add(k, v)) - #| } - #| } - #|} - #|pub fn[K, V] HashMap::to_array(self : HashMap[K, V]) -> Array[(K, V)] { - #| let arr = Array::new(capacity=self.length()) - #| self.each((k, v) => arr.push((k, v))) - #| arr - #|} - #|pub impl[K : Eq + Hash + @quickcheck.Arbitrary, V : @quickcheck.Arbitrary] @quickcheck.Arbitrary for HashMap[ - #| K, - #| V, - #|] with arbitrary(size, rs) { - #| @quickcheck.Arbitrary::arbitrary(size, rs) |> from_array - #|} - #|impl[K : Eq, V : Eq] Eq for Node[K, V] with equal(self, other) { - #| match (self, other) { - #| (Flat(key1, value1, path1), Flat(key2, value2, path2)) => - #| path1 == path2 && key1 == key2 && value1 == value2 - #| (Branch(children1), Branch(children2)) => children1 == children2 - #| (Leaf(key1, value1, bucket1), Leaf(key2, value2, bucket2)) => { - #| guard bucket1.length() == bucket2.length() else { return false } - #| let kvs1 = bucket1.add((key1, value1)) - #| let kvs2 = bucket2.add((key2, value2)) - #| kvs1.all(kv => kvs2.lookup(kv.0) is Some(v) && kv.1 == v) - #| } - #| _ => false - #| } - #|} - #|pub impl[K : Hash, V : Hash] Hash for HashMap[K, V] with hash_combine( - #| self, - #| hasher, - #|) { - #| hasher.combine( - #| self.fold(init=0, (acc, k, v) => acc ^ - #| Hasher::new()..combine((k, v)).finalize()), - #| ) - #|} - ), - "deprecated.mbt": "", - "types.mbt": ( - #|using @path {type Path} - #|priv enum Node[K, V] { - #| Flat(K, V, Path) - #| Leaf(K, V, @list.List[(K, V)]) // use a list of buckets to resolve collision - #| Branch(@sparse_array.SparseArray[Node[K, V]]) - #|} - #|#alias(T, deprecated) - #|struct HashMap[K, V](Node[K, V]?) derive(Eq) - ), - }, + "HAMT.mbt": ( + #|#as_free_fn + #|pub fn[K, V] HashMap::new() -> HashMap[K, V] { + #| None + #|} + #|#as_free_fn + #|pub fn[K : Hash, V] HashMap::singleton(key : K, value : V) -> HashMap[K, V] { + #| Some(Flat(key, value, @path.of(key))) + #|} + #|pub fn[K : Eq + Hash, V] HashMap::contains( + #| self : HashMap[K, V], + #| key : K, + #|) -> Bool { + #| self.get(key) is Some(_) + #|} + #|#alias(find, deprecated) + #|pub fn[K : Eq + Hash, V] HashMap::get(self : HashMap[K, V], key : K) -> V? { + #| match self.0 { + #| None => None + #| Some(node) => node.get_with_path(key, @path.of(key)) + #| } + #|} + #|#alias("_[_]") + #|pub fn[K : Eq + Hash, V] HashMap::at(self : HashMap[K, V], key : K) -> V { + #| guard self.0 is Some(node) + #| node.get_with_path(key, @path.of(key)).unwrap() + #|} + #|fn[K : Eq, V] Node::get_with_path( + #| self : Node[K, V], + #| key : K, + #| path : @path.Path, + #|) -> V? { + #| loop (self, path) { + #| (Leaf(key1, value1, bucket), _) => + #| if key == key1 { + #| Some(value1) + #| } else { + #| bucket.lookup(key) + #| } + #| (Flat(key1, value1, path1), path) => + #| if path == path1 && key == key1 { + #| Some(value1) + #| } else { + #| None + #| } + #| (Branch(children), path) => { + #| let idx = path.idx() + #| if children.get(idx) is Some(child) { + #| continue (child, path.next()) + #| } + #| None + #| } + #| } + #|} + #|fn[K, V] join_2( + #| key1 : K, + #| value1 : V, + #| path1 : @path.Path, + #| key2 : K, + #| value2 : V, + #| path2 : @path.Path, + #|) -> Node[K, V] { + #| let idx1 = path1.idx() + #| let idx2 = path2.idx() + #| if idx1 == idx2 { + #| let node = if path1.is_last() { + #| Leaf(key2, value2, @list.singleton((key1, value1))) + #| } else { + #| join_2(key1, value1, path1.next(), key2, value2, path2.next()) + #| } + #| Branch(@sparse_array.singleton(idx1, node)) + #| } else { + #| let (node1, node2) = if path1.is_last() { + #| (Leaf(key1, value1, @list.empty()), Leaf(key2, value2, @list.empty())) + #| } else { + #| (Flat(key1, value1, path1.next()), Flat(key2, value2, path2.next())) + #| } + #| Branch(@sparse_array.doubleton(idx1, node1, idx2, node2)) + #| } + #|} + #|fn[K : Eq, V] Node::add_with_path( + #| self : Node[K, V], + #| key : K, + #| value : V, + #| path : @path.Path, + #|) -> Node[K, V] { + #| match self { + #| Leaf(key1, value1, bucket) => + #| if key == key1 { + #| Leaf(key, value, bucket) + #| } else { + #| let new_bucket = match bucket.find_index(kv => kv.0 == key) { + #| None => bucket + #| Some(index) => bucket.remove_at(index) + #| } + #| Leaf(key, value, new_bucket.add((key1, value1))) + #| } + #| Flat(key1, value1, path1) => + #| if path == path1 && key == key1 { + #| Flat(key1, value, path1) + #| } else { + #| join_2(key1, value1, path1, key, value, path) + #| } + #| Branch(children) => { + #| let idx = path.idx() + #| match children.get(idx) { + #| Some(child) => { + #| let child = child.add_with_path(key, value, path.next()) + #| Branch(children.replace(idx, child)) + #| } + #| None => { + #| let child = Flat(key, value, path.next()) + #| Branch(children.add(idx, child)) + #| } + #| } + #| } + #| } + #|} + #|#alias(filter_with_key, deprecated) + #|pub fn[K, V] HashMap::filter( + #| self : HashMap[K, V], + #| pred : (K, V) -> Bool raise?, + #|) -> HashMap[K, V] raise? { + #| fn go(node) raise? { + #| match node { + #| Leaf(key1, value1, bucket) => { + #| let new_bucket = bucket.filter(kv => pred(kv.0, kv.1)) + #| if pred(key1, value1) { + #| Some(Leaf(key1, value1, new_bucket)) + #| } else { + #| match new_bucket { + #| Empty => None + #| More((k1, v1), tail~) => Some(Leaf(k1, v1, tail)) + #| } + #| } + #| } + #| Flat(key1, value1, _) => + #| if pred(key1, value1) { + #| Some(node) + #| } else { + #| None + #| } + #| Branch(children) => + #| match children.filter(go) { + #| None => None + #| Some(new_children) => Some(Branch(new_children)) + #| } + #| } + #| } + #| match self.0 { + #| None => None + #| Some(node) => go(node) + #| } + #|} + #|#alias(fold_with_key, deprecated) + #|pub fn[K, V, A] HashMap::fold( + #| self : HashMap[K, V], + #| init~ : A, + #| f : (A, K, V) -> A raise?, + #|) -> A raise? { + #| fn go(acc, node) raise? { + #| match node { + #| Leaf(k, v, bucket) => + #| bucket.fold(init=f(acc, k, v), (acc, kv) => f(acc, kv.0, kv.1)) + #| Flat(k, v, _) => f(acc, k, v) + #| Branch(children) => children.data.fold(init=acc, go) + #| } + #| } + #| match self.0 { + #| None => init + #| Some(node) => go(init, node) + #| } + #|} + #|#alias(map_with_key, deprecated) + #|pub fn[K, V, A] HashMap::map( + #| self : HashMap[K, V], + #| f : (K, V) -> A raise?, + #|) -> HashMap[K, A] raise? { + #| fn go(m : Node[K, V]) -> Node[K, A] raise? { + #| match m { + #| Leaf(k, v, bucket) => + #| Leaf(k, f(k, v), bucket.map(kv => (kv.0, f(kv.0, kv.1)))) + #| Flat(k, v, path) => Flat(k, f(k, v), path) + #| Branch(children) => Branch(children.map(go)) + #| } + #| } + #| match self.0 { + #| None => None + #| Some(node) => Some(go(node)) + #| } + #|} + #|pub fn[K : Eq + Hash, V] HashMap::add( + #| self : HashMap[K, V], + #| key : K, + #| value : V, + #|) -> HashMap[K, V] { + #| match self.0 { + #| None => Some(Flat(key, value, @path.of(key))) + #| Some(node) => Some(node.add_with_path(key, value, @path.of(key))) + #| } + #|} + #|pub fn[K : Eq + Hash, V] HashMap::remove( + #| self : HashMap[K, V], + #| key : K, + #|) -> HashMap[K, V] { + #| match self.0 { + #| None => None + #| Some(node) => node.remove_with_path(key, @path.of(key)) + #| } + #|} + #|fn[K : Eq, V] Node::remove_with_path( + #| self : Node[K, V], + #| key : K, + #| path : @path.Path, + #|) -> Node[K, V]? { + #| match self { + #| Leaf(key1, value1, bucket) => + #| if key1 == key { + #| match bucket { + #| @list.Empty => None + #| More((key2, value2), tail~) => Some(Leaf(key2, value2, tail)) + #| } + #| } else if bucket.find_index(kv => kv.0 == key) is Some(index) { + #| Some(Leaf(key1, value1, bucket.remove_at(index))) + #| } else { + #| Some(self) + #| } + #| Flat(key1, _, path1) => + #| if path == path1 && key == key1 { + #| None + #| } else { + #| Some(self) + #| } + #| Branch(children) => { + #| let idx = path.idx() + #| match children.get(idx) { + #| None => Some(self) + #| Some(child) => { + #| let new_child = child.remove_with_path(key, path.next()) + #| let new_children = match (children.length(), new_child) { + #| (1, None) => return None + #| (_, None) => children.remove(idx) + #| (_, Some(new_child)) => children.replace(idx, new_child) + #| } + #| match new_children.data { + #| [Flat(key1, value1, path1)] => + #| Some( + #| Flat( + #| key1, + #| value1, + #| path1.push(new_children.elem_info.first_idx()), + #| ), + #| ) + #| _ => Some(Branch(new_children)) + #| } + #| } + #| } + #| } + #| } + #|} + #|#alias(size, deprecated) + #|pub fn[K, V] HashMap::length(self : HashMap[K, V]) -> Int { + #| fn node_size(node) { + #| match node { + #| Leaf(_, _, bucket) => 1 + bucket.length() + #| Flat(_) => 1 + #| Branch(children) => + #| for i = 0, total_size = 0; i < children.data.length(); { + #| continue i + 1, total_size + node_size(children.data[i]) + #| } nobreak { + #| total_size + #| } + #| } + #| } + #| match self.0 { + #| None => 0 + #| Some(node) => node_size(node) + #| } + #|} + #|#alias(merge) + #|pub fn[K : Eq, V] HashMap::union( + #| self : HashMap[K, V], + #| other : HashMap[K, V], + #|) -> HashMap[K, V] { + #| fn go(node1 : Node[_], node2) { + #| match (node1, node2) { + #| (_, Flat(key2, value2, path2)) => node1.add_with_path(key2, value2, path2) + #| (Flat(key1, value1, path1), _) => + #| match node2.get_with_path(key1, path1) { + #| Some(_) => node2 + #| None => node2.add_with_path(key1, value1, path1) + #| } + #| (Branch(children1), Branch(children2)) => + #| Branch(children1.union(children2, go)) + #| (Leaf(key1, value1, bucket1), Leaf(key2, value2, bucket2)) => { + #| let kvs1 = bucket1.add((key1, value1)) + #| let kvs2 = bucket2.add((key2, value2)) + #| match kvs1.filter(kv => kvs2.lookup(kv.0) is None) { + #| Empty => node2 + #| More(head, tail~) => Leaf(key2, value2, bucket2 + tail.add(head)) + #| } + #| } + #| _ => abort("Unreachable") + #| } + #| } + #| match (self.0, other.0) { + #| (None, x) | (x, None) => x + #| (Some(a), Some(b)) => Some(go(a, b)) + #| } + #|} + #|pub fn[K : Eq, V] HashMap::union_with( + #| self : HashMap[K, V], + #| other : HashMap[K, V], + #| f : (K, V, V) -> V raise?, + #|) -> HashMap[K, V] raise? { + #| fn go(node1 : Node[_], node2) raise? { + #| match (node1, node2) { + #| (_, Flat(key2, value2, path2)) => { + #| let new_value = match node1.get_with_path(key2, path2) { + #| Some(value1) => f(key2, value1, value2) + #| None => value2 + #| } + #| node1.add_with_path(key2, new_value, path2) + #| } + #| (Flat(key1, value1, path1), _) => { + #| let new_value = match node2.get_with_path(key1, path1) { + #| Some(value2) => f(key1, value1, value2) + #| None => value1 + #| } + #| node2.add_with_path(key1, new_value, path1) + #| } + #| (Branch(children1), Branch(children2)) => + #| Branch(children1.union(children2, go)) + #| (Leaf(key1, value1, bucket1), Leaf(key2, value2, bucket2)) => { + #| let kvs1 = bucket1.add((key1, value1)) + #| let kvs2 = bucket2.add((key2, value2)) + #| kvs1.union_with(kvs2, f) + #| } + #| _ => abort("Unreachable") + #| } + #| } + #| match (self.0, other.0) { + #| (None, x) | (x, None) => x + #| (Some(a), Some(b)) => Some(go(a, b)) + #| } + #|} + #|fn[K : Eq, V] @list.List::union_with( + #| self : Self[(K, V)], + #| other : Self[(K, V)], + #| f : (K, V, V) -> V raise?, + #|) -> Node[K, V] raise? { + #| let res = self.to_array() + #| for kv2 in other { + #| for i, kv1 in res { + #| if kv1.0 == kv2.0 { + #| res[i] = (kv1.0, f(kv1.0, kv1.1, kv2.1)) + #| break + #| } + #| } nobreak { + #| res.push(kv2) + #| } + #| } + #| guard @list.from_array(res) is More((k, v), tail~) + #| Leaf(k, v, tail) + #|} + #|pub fn[K : Eq, V] HashMap::intersection( + #| self : HashMap[K, V], + #| other : HashMap[K, V], + #|) -> HashMap[K, V] { + #| fn go(node1 : Node[_], node2) { + #| match (node1, node2) { + #| (_, Flat(key2, _, path2)) => + #| match node1.get_with_path(key2, path2) { + #| Some(_) => Some(node2) + #| None => None + #| } + #| (Flat(key1, _, path1), _) => + #| match node2.get_with_path(key1, path1) { + #| Some(value2) => Some(Flat(key1, value2, path1)) + #| None => None + #| } + #| (Branch(children1), Branch(children2)) => + #| match children1.intersection(children2, go) { + #| None => None + #| Some({ data: [Flat(key, value, path)], elem_info }) => + #| Some(Flat(key, value, path.push(elem_info.first_idx()))) + #| Some(children) => Some(Branch(children)) + #| } + #| (Leaf(key1, value1, bucket1), Leaf(key2, value2, bucket2)) => { + #| let kvs1 = bucket1.add((key1, value1)) + #| let kvs2 = bucket2.add((key2, value2)) + #| match kvs2.filter(kv => kvs1.lookup(kv.0) is Some(_)) { + #| Empty => None + #| More(head, tail~) => Some(Leaf(head.0, head.1, tail)) + #| } + #| } + #| _ => abort("Unreachable") + #| } + #| } + #| match (self.0, other.0) { + #| (None, _) | (_, None) => None + #| (Some(a), Some(b)) => go(a, b) + #| } + #|} + #|pub fn[K : Eq, V] HashMap::intersection_with( + #| self : HashMap[K, V], + #| other : HashMap[K, V], + #| f : (K, V, V) -> V raise?, + #|) -> HashMap[K, V] raise? { + #| fn go(node1 : Node[_], node2) raise? { + #| match (node1, node2) { + #| (_, Flat(key2, value2, path2)) => + #| match node1.get_with_path(key2, path2) { + #| Some(value1) => Some(Flat(key2, f(key2, value1, value2), path2)) + #| None => None + #| } + #| (Flat(key1, value1, path1), _) => + #| match node2.get_with_path(key1, path1) { + #| Some(value2) => Some(Flat(key1, f(key1, value1, value2), path1)) + #| None => None + #| } + #| (Branch(children1), Branch(children2)) => + #| match children1.intersection(children2, go) { + #| None => None + #| Some({ data: [Flat(key, value, path)], elem_info }) => + #| Some(Flat(key, value, path.push(elem_info.first_idx()))) + #| Some(children) => Some(Branch(children)) + #| } + #| (Leaf(key1, value1, bucket1), Leaf(key2, value2, bucket2)) => { + #| let kvs1 = bucket1.add((key1, value1)) + #| let kvs2 = bucket2.add((key2, value2)) + #| kvs1.intersection_with(kvs2, f) + #| } + #| _ => abort("Unreachable") + #| } + #| } + #| match (self.0, other.0) { + #| (None, _) | (_, None) => None + #| (Some(a), Some(b)) => go(a, b) + #| } + #|} + #|fn[K : Eq, V] @list.List::intersection_with( + #| self : Self[(K, V)], + #| other : Self[(K, V)], + #| f : (K, V, V) -> V raise?, + #|) -> Node[K, V]? raise? { + #| let res = [] + #| for kv1 in self { + #| for kv2 in other { + #| if kv1.0 == kv2.0 { + #| res.push((kv1.0, f(kv1.0, kv1.1, kv2.1))) + #| break + #| } + #| } + #| } + #| match @list.from_array(res) { + #| Empty => None + #| More((k, v), tail~) => Some(Leaf(k, v, tail)) + #| } + #|} + #|pub fn[K : Eq, V] HashMap::difference( + #| self : HashMap[K, V], + #| other : HashMap[K, V], + #|) -> HashMap[K, V] { + #| fn go(node1 : Node[_], node2) { + #| match (node1, node2) { + #| (node, Flat(k, _, path)) => node.remove_with_path(k, path) + #| (Flat(key, _, path), _) => + #| match node2.get_with_path(key, path) { + #| Some(_) => None + #| None => Some(node1) + #| } + #| (Branch(children1), Branch(children2)) => + #| match children1.difference(children2, go) { + #| None => None + #| Some({ data: [Flat(key, value, path)], elem_info }) => + #| Some(Flat(key, value, path.push(elem_info.first_idx()))) + #| Some(children) => Some(Branch(children)) + #| } + #| (Leaf(key1, value1, bucket1), Leaf(key2, value2, bucket2)) => { + #| let kvs1 = bucket1.add((key1, value1)) + #| let kvs2 = bucket2.add((key2, value2)) + #| match kvs1.filter(kv => !(kvs2.lookup(kv.0) is Some(_))) { + #| Empty => None + #| More(head, tail~) => Some(Leaf(head.0, head.1, tail)) + #| } + #| } + #| _ => abort("Unreachable") + #| } + #| } + #| match (self.0, other.0) { + #| (None, _) => None + #| (_, None) => self + #| (Some(a), Some(b)) => go(a, b) + #| } + #|} + #|pub fn[K, V] HashMap::each( + #| self : HashMap[K, V], + #| f : (K, V) -> Unit raise?, + #|) -> Unit raise? { + #| fn go(node) raise? { + #| match node { + #| Leaf(k, v, bucket) => { + #| f(k, v) + #| bucket.each(kv => f(kv.0, kv.1)) + #| } + #| Flat(k, v, _) => f(k, v) + #| Branch(children) => children.each(go) + #| } + #| } + #| match self.0 { + #| None => () + #| Some(node) => go(node) + #| } + #|} + #|pub fn[K, V] HashMap::keys(self : HashMap[K, V]) -> Iter[K] { + #| self.iter().map(p => p.0) + #|} + #|#alias(elems, deprecated="Use `values` instead") + #|pub fn[K, V] HashMap::values(self : HashMap[K, V]) -> Iter[V] { + #| self.iter().map(p => p.1) + #|} + #|#alias(iterator, deprecated) + #|pub fn[K, V] HashMap::iter(self : HashMap[K, V]) -> Iter[(K, V)] { + #| enum CurrNode { + #| Tree(Node[K, V]) + #| Bucket(@list.List[(K, V)]) + #| } + #| let empty = Bucket(@list.new()) + #| let mut curr_node = match self.0 { + #| Some(tree) => Tree(tree) + #| None => empty + #| } + #| let mut curr_index = 0 + #| let parents = [] + #| Iter::new(fn() { + #| loop curr_node { + #| Tree(Flat(k, v, _)) => { + #| curr_node = empty + #| Some((k, v)) + #| } + #| Tree(Leaf(k, v, bucket)) => { + #| curr_node = Bucket(bucket) + #| Some((k, v)) + #| } + #| Bucket(More(pair, tail~)) => { + #| curr_node = Bucket(tail) + #| Some(pair) + #| } + #| Tree(Branch(children)) as n if curr_index < children.length() => { + #| let child = children.data[curr_index] + #| parents.push((n, curr_index + 1)) + #| curr_index = 0 + #| continue Tree(child) + #| } + #| Bucket(Empty) | Tree(Branch(_)) if parents.pop() + #| is Some((parent, parent_index)) => { + #| curr_node = parent + #| curr_index = parent_index + #| continue parent + #| } + #| Bucket(Empty) | Tree(Branch(_)) => None + #| } + #| }) + #|} + #|#alias(iterator2, deprecated) + #|pub fn[K, V] HashMap::iter2(self : HashMap[K, V]) -> Iter2[K, V] { + #| self.iter() + #|} + #|#as_free_fn + #|#alias(from_iterator, deprecated) + #|#as_free_fn(from_iterator, deprecated) + #|pub fn[K : Eq + Hash, V] HashMap::from_iter( + #| iter : Iter[(K, V)], + #|) -> HashMap[K, V] { + #| iter.fold(init=new(), (m, e) => m.add(e.0, e.1)) + #|} + #|pub impl[K : Show, V : Show] Show for HashMap[K, V] with output(self, logger) { + #| logger.write_iter( + #| self.iter(), + #| prefix="@immut/hashmap.from_array([", + #| suffix="])", + #| ) + #|} + #|#as_free_fn + #|#alias(of, deprecated="Use from_array instead") + #|#as_free_fn(of, deprecated="Use from_array instead") + #|pub fn[K : Eq + Hash, V] HashMap::from_array( + #| arr : ArrayView[(K, V)], + #|) -> HashMap[K, V] { + #| loop (arr.length(), new()) { + #| (0, map) => map + #| (n, map) => { + #| let (k, v) = arr[n - 1] + #| continue (n - 1, map.add(k, v)) + #| } + #| } + #|} + #|pub fn[K, V] HashMap::to_array(self : HashMap[K, V]) -> Array[(K, V)] { + #| let arr = Array::new(capacity=self.length()) + #| self.each((k, v) => arr.push((k, v))) + #| arr + #|} + #|pub impl[K : Eq + Hash + @quickcheck.Arbitrary, V : @quickcheck.Arbitrary] @quickcheck.Arbitrary for HashMap[ + #| K, + #| V, + #|] with arbitrary(size, rs) { + #| @quickcheck.Arbitrary::arbitrary(size, rs) |> from_array + #|} + #|impl[K : Eq, V : Eq] Eq for Node[K, V] with equal(self, other) { + #| if physical_equal(self, other) { + #| return true + #| } + #| match (self, other) { + #| (Flat(key1, value1, path1), Flat(key2, value2, path2)) => + #| path1 == path2 && key1 == key2 && value1 == value2 + #| (Branch(children1), Branch(children2)) => children1 == children2 + #| (Leaf(key1, value1, bucket1), Leaf(key2, value2, bucket2)) => { + #| guard bucket1.length() == bucket2.length() else { return false } + #| let kvs1 = bucket1.add((key1, value1)) + #| let kvs2 = bucket2.add((key2, value2)) + #| kvs1.all(kv => kvs2.lookup(kv.0) is Some(v) && kv.1 == v) + #| } + #| _ => false + #| } + #|} + #|pub impl[K : Hash, V : Hash] Hash for HashMap[K, V] with hash_combine( + #| self, + #| hasher, + #|) { + #| hasher.combine( + #| self.fold(init=0, (acc, k, v) => { + #| let h = Hasher::new() + #| h.combine((k, v)) + #| acc ^ h.finalize() + #| }), + #| ) + #|} + ), + "deprecated.mbt": "", + "types.mbt": ( + #|priv enum Node[K, V] { + #| Flat(K, V, @path.Path) + #| Leaf(K, V, @list.List[(K, V)]) // use a list of buckets to resolve collision + #| Branch(@sparse_array.SparseArray[Node[K, V]]) + #|} + #|#alias(T, deprecated) + #|struct HashMap[K, V](Node[K, V]?) derive(Eq) + ) + } ) ///| let moonbitlang_core_immut_hashset_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/immut/hashset", - deps={ - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/array": moonbitlang_core_array_module, - "moonbitlang/core/immut/internal/sparse_array": moonbitlang_core_immut_internal_sparse_array_module, - "moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module, - "moonbitlang/core/immut/internal/path": moonbitlang_core_immut_internal_path_module, - "moonbitlang/core/list": moonbitlang_core_list_module, - }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| "moonbitlang/core/builtin", - #| "moonbitlang/core/array", - #| "moonbitlang/core/immut/internal/sparse_array", - #| "moonbitlang/core/quickcheck", - #| "moonbitlang/core/immut/internal/path", - #| "moonbitlang/core/list" - #| ], - #| "test-import": ["moonbitlang/core/string", "moonbitlang/core/int"] - #|} - ), - "HAMT.mbt": ( - #|#as_free_fn - #|pub fn[A] HashSet::new() -> HashSet[A] { - #| None - #|} - #|pub fn[A : Eq + Hash] HashSet::contains(self : HashSet[A], key : A) -> Bool { - #| self.0 is Some(node) && node.contains(key, @path.of(key)) - #|} - #|fn[A : Eq] Node::contains(self : Node[A], key : A, path : Path) -> Bool { - #| loop (self, path) { - #| (Leaf(key1, bucket), _) => key == key1 || bucket.contains(key) - #| (Flat(key1, path1), path) => path == path1 && key == key1 - #| (Branch(children), path) => { - #| let idx = path.idx() - #| if children.get(idx) is Some(child) { - #| continue (child, path.next()) - #| } - #| false - #| } - #| } - #|} - #|fn[A] join_2(key1 : A, path1 : Path, key2 : A, path2 : Path) -> Node[A] { - #| let idx1 = path1.idx() - #| let idx2 = path2.idx() - #| if idx1 == idx2 { - #| let node = if path1.is_last() { - #| Leaf(key2, @list.singleton(key1)) - #| } else { - #| join_2(key1, path1.next(), key2, path2.next()) - #| } - #| Branch(@sparse_array.singleton(idx1, node)) - #| } else { - #| let (node1, node2) = if path1.is_last() { - #| (Leaf(key1, @list.empty()), Leaf(key2, @list.empty())) - #| } else { - #| (Flat(key1, path1.next()), Flat(key2, path2.next())) - #| } - #| Branch(@sparse_array.doubleton(idx1, node1, idx2, node2)) - #| } - #|} - #|fn[A : Eq] Node::add_with_path(self : Node[A], key : A, path : Path) -> Node[A] { - #| match self { - #| Leaf(key1, bucket) => - #| if key == key1 || bucket.contains(key) { - #| self - #| } else { - #| Leaf(key, bucket.add(key1)) - #| } - #| Flat(key1, path1) => - #| if path == path1 && key == key1 { - #| self - #| } else { - #| join_2(key1, path1, key, path) - #| } - #| Branch(children) => { - #| let idx = path.idx() - #| match children.get(idx) { - #| Some(child) => { - #| let child = child.add_with_path(key, path.next()) - #| Branch(children.replace(idx, child)) - #| } - #| None => { - #| let child = Flat(key, path.next()) - #| Branch(children.add(idx, child)) - #| } - #| } - #| } - #| } - #|} - #|pub fn[A : Eq + Hash] HashSet::add(self : HashSet[A], key : A) -> HashSet[A] { - #| match self.0 { - #| None => Some(Flat(key, @path.of(key))) - #| Some(node) => Some(node.add_with_path(key, @path.of(key))) - #| } - #|} - #|pub fn[A : Eq + Hash] HashSet::remove(self : HashSet[A], key : A) -> HashSet[A] { - #| match self.0 { - #| None => None - #| Some(node) => node.remove_with_path(key, @path.of(key)) - #| } - #|} - #|fn[A : Eq] Node::remove_with_path( - #| self : Node[A], - #| key : A, - #| path : Path, - #|) -> Node[A]? { - #| match self { - #| Leaf(key1, bucket) => - #| if key1 == key { - #| match bucket { - #| @list.Empty => None - #| More(key2, tail=xs) => Some(Leaf(key2, xs)) - #| } - #| } else if bucket.find_index(x => key.equal(x)) is Some(index) { - #| Some(Leaf(key1, bucket.remove_at(index))) - #| } else { - #| Some(self) - #| } - #| Flat(key1, path1) => - #| if path == path1 && key == key1 { - #| None - #| } else { - #| Some(self) - #| } - #| Branch(children) => { - #| let idx = path.idx() - #| match children.get(idx) { - #| None => Some(self) - #| Some(child) => { - #| let new_child = child.remove_with_path(key, path.next()) - #| let new_children = match (children.length(), new_child) { - #| (1, None) => return None - #| (_, None) => children.remove(idx) - #| (_, Some(new_child)) => children.replace(idx, new_child) - #| } - #| match new_children.data { - #| [Flat(key1, path1)] => - #| Some(Flat(key1, path1.push(new_children.elem_info.first_idx()))) - #| _ => Some(Branch(new_children)) - #| } - #| } - #| } - #| } - #| } - #|} - #|#alias(size, deprecated) - #|pub fn[A] HashSet::length(self : HashSet[A]) -> Int { - #| fn node_size(node) { - #| match node { - #| Leaf(_, bucket) => 1 + bucket.length() - #| Flat(_) => 1 - #| Branch(children) => - #| for i = 0, total_size = 0; i < children.data.length(); { - #| continue i + 1, total_size + node_size(children.data[i]) - #| } else { - #| total_size - #| } - #| } - #| } - #| match self.0 { - #| None => 0 - #| Some(node) => node_size(node) - #| } - #|} - #|pub fn[K : Eq] HashSet::union( - #| self : HashSet[K], - #| other : HashSet[K], - #|) -> HashSet[K] { - #| fn go(node1, node2) { - #| match (node1, node2) { - #| (node, Flat(key, path)) | (Flat(key, path), node) => - #| node.add_with_path(key, path) - #| (Branch(children1), Branch(children2)) => - #| Branch(children1.union(children2, go)) - #| (Leaf(key1, bucket1), Leaf(key2, bucket2)) => { - #| let keys1 = bucket1.add(key1) - #| let keys2 = bucket2.add(key2) - #| match keys1.filter(k => !keys2.contains(k)) { - #| Empty => node2 - #| More(head, tail~) => Leaf(key2, bucket2 + tail.add(head)) - #| } - #| } - #| _ => abort("Unreachable") - #| } - #| } - #| match (self.0, other.0) { - #| (None, x) | (x, None) => x - #| (Some(a), Some(b)) => Some(go(a, b)) - #| } - #|} - #|pub fn[K : Eq] HashSet::intersection( - #| self : HashSet[K], - #| other : HashSet[K], - #|) -> HashSet[K] { - #| fn go(node1, node2) { - #| match (node1, node2) { - #| (node, Flat(key, path) as flat) | (Flat(key, path) as flat, node) => - #| if node.contains(key, path) { - #| Some(flat) - #| } else { - #| None - #| } - #| (Branch(children1), Branch(children2)) => - #| match children1.intersection(children2, go) { - #| None => None - #| Some({ data: [Flat(key, path)], elem_info }) => - #| Some(Flat(key, path.push(elem_info.first_idx()))) - #| Some(children) => Some(Branch(children)) - #| } - #| (Leaf(key1, bucket1), Leaf(key2, bucket2)) => { - #| let keys1 = bucket1.add(key1) - #| let keys2 = bucket2.add(key2) - #| match keys1.filter(keys2.contains(_)) { - #| Empty => None - #| More(head, tail~) => Some(Leaf(head, tail)) - #| } - #| } - #| _ => abort("Unreachable") - #| } - #| } - #| match (self.0, other.0) { - #| (None, _) | (_, None) => None - #| (Some(a), Some(b)) => go(a, b) - #| } - #|} - #|pub fn[K : Eq] HashSet::difference( - #| self : HashSet[K], - #| other : HashSet[K], - #|) -> HashSet[K] { - #| fn go(node1 : Node[_], node2) { - #| match (node1, node2) { - #| (node, Flat(k, path)) => node.remove_with_path(k, path) - #| (Flat(key, path) as flat, node) => - #| if node.contains(key, path) { - #| None - #| } else { - #| Some(flat) - #| } - #| (Branch(children1), Branch(children2)) => - #| match children1.difference(children2, go) { - #| None => None - #| Some({ data: [Flat(key, path)], elem_info }) => - #| Some(Flat(key, path.push(elem_info.first_idx()))) - #| Some(children) => Some(Branch(children)) - #| } - #| (Leaf(key1, bucket1), Leaf(key2, bucket2)) => { - #| let keys1 = bucket1.add(key1) - #| let keys2 = bucket2.add(key2) - #| match keys1.filter(k => !keys2.contains(k)) { - #| Empty => None - #| More(head, tail~) => Some(Leaf(head, tail)) - #| } - #| } - #| _ => abort("Unreachable") - #| } - #| } - #| match (self.0, other.0) { - #| (None, _) => None - #| (_, None) => self - #| (Some(a), Some(b)) => go(a, b) - #| } - #|} - #|pub fn[A] HashSet::is_empty(self : HashSet[A]) -> Bool { - #| self.0 is None - #|} - #|pub fn[A] HashSet::each( - #| self : HashSet[A], - #| f : (A) -> Unit raise?, - #|) -> Unit raise? { - #| fn go(node) raise? { - #| match node { - #| Leaf(k, bucket) => { - #| f(k) - #| bucket.each(f) - #| } - #| Flat(k, _) => f(k) - #| Branch(children) => children.each(go) - #| } - #| } - #| match self.0 { - #| None => () - #| Some(node) => go(node) - #| } - #|} - #|pub fn[A] HashSet::iter(self : HashSet[A]) -> Iter[A] { - #| fn go(node) -> Iter[A] { - #| match node { - #| Leaf(k, bucket) => Iter::singleton(k) + bucket.iter() - #| Flat(k, _) => Iter::singleton(k) - #| Branch(children) => children.data.iter().flat_map(go) - #| } - #| } - #| match self.0 { - #| None => Iter::empty() - #| Some(node) => go(node) - #| } - #|} - #|pub fn[A] HashSet::iterator(self : HashSet[A]) -> Iterator[A] { - #| enum CurrNode { - #| Tree(Node[A]) - #| Bucket(@list.List[A]) - #| } - #| let empty = Bucket(@list.new()) - #| let mut curr_node = match self.0 { - #| Some(tree) => Tree(tree) - #| None => empty - #| } - #| let mut curr_index = 0 - #| let parents = [] - #| Iterator::new(fn() { - #| loop curr_node { - #| Tree(Flat(x, _)) => { - #| curr_node = empty - #| Some(x) - #| } - #| Tree(Leaf(x, bucket)) => { - #| curr_node = Bucket(bucket) - #| Some(x) - #| } - #| Bucket(More(x, tail~)) => { - #| curr_node = Bucket(tail) - #| Some(x) - #| } - #| Tree(Branch(children)) as n if curr_index < children.length() => { - #| let child = children.data[curr_index] - #| parents.push((n, curr_index + 1)) - #| curr_index = 0 - #| continue Tree(child) - #| } - #| Bucket(Empty) | Tree(Branch(_)) if parents.pop() - #| is Some((parent, parent_index)) => { - #| curr_node = parent - #| curr_index = parent_index - #| continue parent - #| } - #| Bucket(Empty) | Tree(Branch(_)) => None - #| } - #| }) - #|} - #|#as_free_fn - #|pub fn[A : Eq + Hash] HashSet::from_iter(iter : Iter[A]) -> HashSet[A] { - #| iter.fold(init=new(), (s, e) => s.add(e)) - #|} - #|#as_free_fn - #|pub fn[A : Eq + Hash] HashSet::from_iterator(iter : Iterator[A]) -> HashSet[A] { - #| iter.fold(init=new(), (s, e) => s.add(e)) - #|} - #|pub impl[A : Show] Show for HashSet[A] with output(self, logger) { - #| logger.write_iter( - #| self.iter(), - #| prefix="@immut/hashset.from_array([", - #| suffix="])", - #| ) - #|} - #|#as_free_fn - #|#alias(of, deprecated="Use from_array instead") - #|#as_free_fn(of, deprecated="Use from_array instead") - #|pub fn[A : Eq + Hash] HashSet::from_array(arr : ArrayView[A]) -> HashSet[A] { - #| loop (arr.length(), new()) { - #| (0, set) => set - #| (n, set) => { - #| let k = arr[n - 1] - #| continue (n - 1, set.add(k)) - #| } - #| } - #|} - #|pub impl[A : Hash] Hash for HashSet[A] with hash_combine(self, hasher) { - #| hasher.combine(self.iter().fold(init=0, (x, y) => x ^ y.hash())) - #|} - #|impl[A : Eq] Eq for Node[A] with equal(self, other) { - #| match (self, other) { - #| (Leaf(x, xs), Leaf(y, ys)) => - #| xs.length() == ys.length() && - #| { - #| let keys1 = xs.add(x) - #| let keys2 = ys.add(y) - #| keys1.iter().all(keys2.contains(_)) - #| } - #| (Flat(x, pathx), Flat(y, pathy)) => pathx == pathy && x == y - #| (Branch(xs), Branch(ys)) => xs == ys - #| _ => false - #| } - #|} - #|pub impl[K : Eq + Hash + @quickcheck.Arbitrary] @quickcheck.Arbitrary for HashSet[ - #| K, - #|] with arbitrary(size, rs) { - #| @quickcheck.Arbitrary::arbitrary(size, rs) |> from_array - #|} - #|test "hash" { - #| assert_eq( - #| Hash::hash(from_array([1, 2, 3, 4])), - #| Hash::hash(from_array([3, 2]).add(1).add(4)), - #| ) - #| assert_not_eq( - #| Hash::hash(from_array([1, 2, 3])), - #| Hash::hash(from_array([1, 2, 4])), - #| ) - #|} - #|test "eq" { - #| assert_eq(from_array([1, 2, 3, 4]), from_array([3, 2]).add(1).add(4)) - #| assert_not_eq(from_array([1, 2, 3]), from_array([1, 2, 4])) - #|} - ), - "deprecated.mbt": "", - "types.mbt": ( - #|using @path {type Path} - #|priv enum Node[A] { - #| Flat(A, Path) - #| Leaf(A, @list.List[A]) // use a list of buckets to resolve collision - #| Branch(@sparse_array.SparseArray[Node[A]]) - #|} - #|#alias(T, deprecated) - #|struct HashSet[A](Node[A]?) derive(Eq) - ), - }, + "HAMT.mbt": ( + #|#as_free_fn + #|pub fn[A] HashSet::new() -> HashSet[A] { + #| None + #|} + #|pub fn[A : Eq + Hash] HashSet::contains(self : HashSet[A], key : A) -> Bool { + #| self.0 is Some(node) && node.contains(key, @path.of(key)) + #|} + #|fn[A : Eq] Node::contains(self : Node[A], key : A, path : @path.Path) -> Bool { + #| loop (self, path) { + #| (Leaf(key1, bucket), _) => key == key1 || bucket.contains(key) + #| (Flat(key1, path1), path) => path == path1 && key == key1 + #| (Branch(children), path) => { + #| let idx = path.idx() + #| if children.get(idx) is Some(child) { + #| continue (child, path.next()) + #| } + #| false + #| } + #| } + #|} + #|fn[A] join_2( + #| key1 : A, + #| path1 : @path.Path, + #| key2 : A, + #| path2 : @path.Path, + #|) -> Node[A] { + #| let idx1 = path1.idx() + #| let idx2 = path2.idx() + #| if idx1 == idx2 { + #| let node = if path1.is_last() { + #| Leaf(key2, @list.singleton(key1)) + #| } else { + #| join_2(key1, path1.next(), key2, path2.next()) + #| } + #| Branch(@sparse_array.singleton(idx1, node)) + #| } else { + #| let (node1, node2) = if path1.is_last() { + #| (Leaf(key1, @list.empty()), Leaf(key2, @list.empty())) + #| } else { + #| (Flat(key1, path1.next()), Flat(key2, path2.next())) + #| } + #| Branch(@sparse_array.doubleton(idx1, node1, idx2, node2)) + #| } + #|} + #|fn[A : Eq] Node::add_with_path( + #| self : Node[A], + #| key : A, + #| path : @path.Path, + #|) -> Node[A] { + #| match self { + #| Leaf(key1, bucket) => + #| if key == key1 || bucket.contains(key) { + #| self + #| } else { + #| Leaf(key, bucket.add(key1)) + #| } + #| Flat(key1, path1) => + #| if path == path1 && key == key1 { + #| self + #| } else { + #| join_2(key1, path1, key, path) + #| } + #| Branch(children) => { + #| let idx = path.idx() + #| match children.get(idx) { + #| Some(child) => { + #| let child = child.add_with_path(key, path.next()) + #| Branch(children.replace(idx, child)) + #| } + #| None => { + #| let child = Flat(key, path.next()) + #| Branch(children.add(idx, child)) + #| } + #| } + #| } + #| } + #|} + #|pub fn[A : Eq + Hash] HashSet::add(self : HashSet[A], key : A) -> HashSet[A] { + #| match self.0 { + #| None => Some(Flat(key, @path.of(key))) + #| Some(node) => Some(node.add_with_path(key, @path.of(key))) + #| } + #|} + #|pub fn[A : Eq + Hash] HashSet::remove(self : HashSet[A], key : A) -> HashSet[A] { + #| match self.0 { + #| None => None + #| Some(node) => node.remove_with_path(key, @path.of(key)) + #| } + #|} + #|fn[A : Eq] Node::remove_with_path( + #| self : Node[A], + #| key : A, + #| path : @path.Path, + #|) -> Node[A]? { + #| match self { + #| Leaf(key1, bucket) => + #| if key1 == key { + #| match bucket { + #| @list.Empty => None + #| More(key2, tail=xs) => Some(Leaf(key2, xs)) + #| } + #| } else if bucket.find_index(x => key.equal(x)) is Some(index) { + #| Some(Leaf(key1, bucket.remove_at(index))) + #| } else { + #| Some(self) + #| } + #| Flat(key1, path1) => + #| if path == path1 && key == key1 { + #| None + #| } else { + #| Some(self) + #| } + #| Branch(children) => { + #| let idx = path.idx() + #| match children.get(idx) { + #| None => Some(self) + #| Some(child) => { + #| let new_child = child.remove_with_path(key, path.next()) + #| let new_children = match (children.length(), new_child) { + #| (1, None) => return None + #| (_, None) => children.remove(idx) + #| (_, Some(new_child)) => children.replace(idx, new_child) + #| } + #| match new_children.data { + #| [Flat(key1, path1)] => + #| Some(Flat(key1, path1.push(new_children.elem_info.first_idx()))) + #| _ => Some(Branch(new_children)) + #| } + #| } + #| } + #| } + #| } + #|} + #|#alias(size, deprecated) + #|pub fn[A] HashSet::length(self : HashSet[A]) -> Int { + #| fn node_size(node) { + #| match node { + #| Leaf(_, bucket) => 1 + bucket.length() + #| Flat(_) => 1 + #| Branch(children) => + #| for i = 0, total_size = 0; i < children.data.length(); { + #| continue i + 1, total_size + node_size(children.data[i]) + #| } nobreak { + #| total_size + #| } + #| } + #| } + #| match self.0 { + #| None => 0 + #| Some(node) => node_size(node) + #| } + #|} + #|pub fn[K : Eq] HashSet::union( + #| self : HashSet[K], + #| other : HashSet[K], + #|) -> HashSet[K] { + #| fn go(node1, node2) { + #| match (node1, node2) { + #| (node, Flat(key, path)) | (Flat(key, path), node) => + #| node.add_with_path(key, path) + #| (Branch(children1), Branch(children2)) => + #| Branch(children1.union(children2, go)) + #| (Leaf(key1, bucket1), Leaf(key2, bucket2)) => { + #| let keys1 = bucket1.add(key1) + #| let keys2 = bucket2.add(key2) + #| match keys1.filter(k => !keys2.contains(k)) { + #| Empty => node2 + #| More(head, tail~) => Leaf(key2, bucket2 + tail.add(head)) + #| } + #| } + #| _ => abort("Unreachable") + #| } + #| } + #| match (self.0, other.0) { + #| (None, x) | (x, None) => x + #| (Some(a), Some(b)) => Some(go(a, b)) + #| } + #|} + #|pub fn[K : Eq] HashSet::intersection( + #| self : HashSet[K], + #| other : HashSet[K], + #|) -> HashSet[K] { + #| fn go(node1, node2) { + #| match (node1, node2) { + #| (node, Flat(key, path) as flat) | (Flat(key, path) as flat, node) => + #| if node.contains(key, path) { + #| Some(flat) + #| } else { + #| None + #| } + #| (Branch(children1), Branch(children2)) => + #| match children1.intersection(children2, go) { + #| None => None + #| Some({ data: [Flat(key, path)], elem_info }) => + #| Some(Flat(key, path.push(elem_info.first_idx()))) + #| Some(children) => Some(Branch(children)) + #| } + #| (Leaf(key1, bucket1), Leaf(key2, bucket2)) => { + #| let keys1 = bucket1.add(key1) + #| let keys2 = bucket2.add(key2) + #| match keys1.filter(k => keys2.contains(k)) { + #| Empty => None + #| More(head, tail~) => Some(Leaf(head, tail)) + #| } + #| } + #| _ => abort("Unreachable") + #| } + #| } + #| match (self.0, other.0) { + #| (None, _) | (_, None) => None + #| (Some(a), Some(b)) => go(a, b) + #| } + #|} + #|pub fn[K : Eq] HashSet::difference( + #| self : HashSet[K], + #| other : HashSet[K], + #|) -> HashSet[K] { + #| fn go(node1 : Node[_], node2) { + #| match (node1, node2) { + #| (node, Flat(k, path)) => node.remove_with_path(k, path) + #| (Flat(key, path) as flat, node) => + #| if node.contains(key, path) { + #| None + #| } else { + #| Some(flat) + #| } + #| (Branch(children1), Branch(children2)) => + #| match children1.difference(children2, go) { + #| None => None + #| Some({ data: [Flat(key, path)], elem_info }) => + #| Some(Flat(key, path.push(elem_info.first_idx()))) + #| Some(children) => Some(Branch(children)) + #| } + #| (Leaf(key1, bucket1), Leaf(key2, bucket2)) => { + #| let keys1 = bucket1.add(key1) + #| let keys2 = bucket2.add(key2) + #| match keys1.filter(k => !keys2.contains(k)) { + #| Empty => None + #| More(head, tail~) => Some(Leaf(head, tail)) + #| } + #| } + #| _ => abort("Unreachable") + #| } + #| } + #| match (self.0, other.0) { + #| (None, _) => None + #| (_, None) => self + #| (Some(a), Some(b)) => go(a, b) + #| } + #|} + #|pub fn[A] HashSet::is_empty(self : HashSet[A]) -> Bool { + #| self.0 is None + #|} + #|pub fn[A] HashSet::each( + #| self : HashSet[A], + #| f : (A) -> Unit raise?, + #|) -> Unit raise? { + #| fn go(node) raise? { + #| match node { + #| Leaf(k, bucket) => { + #| f(k) + #| bucket.each(f) + #| } + #| Flat(k, _) => f(k) + #| Branch(children) => children.each(go) + #| } + #| } + #| match self.0 { + #| None => () + #| Some(node) => go(node) + #| } + #|} + #|#alias(iterator, deprecated) + #|pub fn[A] HashSet::iter(self : HashSet[A]) -> Iter[A] { + #| enum CurrNode { + #| Tree(Node[A]) + #| Bucket(@list.List[A]) + #| } + #| let empty = Bucket(@list.new()) + #| let mut curr_node = match self.0 { + #| Some(tree) => Tree(tree) + #| None => empty + #| } + #| let mut curr_index = 0 + #| let parents = [] + #| Iter::new(fn() { + #| loop curr_node { + #| Tree(Flat(x, _)) => { + #| curr_node = empty + #| Some(x) + #| } + #| Tree(Leaf(x, bucket)) => { + #| curr_node = Bucket(bucket) + #| Some(x) + #| } + #| Bucket(More(x, tail~)) => { + #| curr_node = Bucket(tail) + #| Some(x) + #| } + #| Tree(Branch(children)) as n if curr_index < children.length() => { + #| let child = children.data[curr_index] + #| parents.push((n, curr_index + 1)) + #| curr_index = 0 + #| continue Tree(child) + #| } + #| Bucket(Empty) | Tree(Branch(_)) if parents.pop() + #| is Some((parent, parent_index)) => { + #| curr_node = parent + #| curr_index = parent_index + #| continue parent + #| } + #| Bucket(Empty) | Tree(Branch(_)) => None + #| } + #| }) + #|} + #|#as_free_fn + #|#alias(from_iterator, deprecated) + #|#as_free_fn(from_iterator, deprecated) + #|pub fn[A : Eq + Hash] HashSet::from_iter(iter : Iter[A]) -> HashSet[A] { + #| iter.fold(init=new(), (s, e) => s.add(e)) + #|} + #|pub impl[A : Show] Show for HashSet[A] with output(self, logger) { + #| logger.write_iter( + #| self.iter(), + #| prefix="@immut/hashset.from_array([", + #| suffix="])", + #| ) + #|} + #|#as_free_fn + #|#alias(of, deprecated="Use from_array instead") + #|#as_free_fn(of, deprecated="Use from_array instead") + #|pub fn[A : Eq + Hash] HashSet::from_array(arr : ArrayView[A]) -> HashSet[A] { + #| loop (arr.length(), new()) { + #| (0, set) => set + #| (n, set) => { + #| let k = arr[n - 1] + #| continue (n - 1, set.add(k)) + #| } + #| } + #|} + #|pub impl[A : Hash] Hash for HashSet[A] with hash_combine(self, hasher) { + #| hasher.combine(self.iter().fold(init=0, (x, y) => x ^ y.hash())) + #|} + #|impl[A : Eq] Eq for Node[A] with equal(self, other) { + #| if physical_equal(self, other) { + #| return true + #| } + #| match (self, other) { + #| (Leaf(x, xs), Leaf(y, ys)) => + #| xs.length() == ys.length() && + #| ({ + #| let keys1 = xs.add(x) + #| let keys2 = ys.add(y) + #| keys1.iter().all(k => keys2.contains(k)) + #| }) + #| (Flat(x, pathx), Flat(y, pathy)) => pathx == pathy && x == y + #| (Branch(xs), Branch(ys)) => xs == ys + #| _ => false + #| } + #|} + #|pub impl[K : Eq + Hash + @quickcheck.Arbitrary] @quickcheck.Arbitrary for HashSet[ + #| K, + #|] with arbitrary(size, rs) { + #| @quickcheck.Arbitrary::arbitrary(size, rs) |> from_array + #|} + #|test "hash" { + #| assert_eq( + #| Hash::hash(from_array([1, 2, 3, 4])), + #| Hash::hash(from_array([3, 2]).add(1).add(4)), + #| ) + #| assert_not_eq( + #| Hash::hash(from_array([1, 2, 3])), + #| Hash::hash(from_array([1, 2, 4])), + #| ) + #|} + #|test "eq" { + #| assert_eq(from_array([1, 2, 3, 4]), from_array([3, 2]).add(1).add(4)) + #| assert_not_eq(from_array([1, 2, 3]), from_array([1, 2, 4])) + #|} + ), + "deprecated.mbt": "", + "types.mbt": ( + #|priv enum Node[A] { + #| Flat(A, @path.Path) + #| Leaf(A, @list.List[A]) // use a list of buckets to resolve collision + #| Branch(@sparse_array.SparseArray[Node[A]]) + #|} + #|#alias(T, deprecated) + #|struct HashSet[A](Node[A]?) derive(Eq) + ) + } ) ///| let moonbitlang_core_immut_internal_path_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/immut/internal/path", - deps={ "moonbitlang/core/builtin": moonbitlang_core_builtin_module }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": ["moonbitlang/core/builtin"] - #|} - ), - "path.mbt": ( - #|pub(all) struct Path(UInt) derive(Eq) - #|const SEGMENT_LENGTH : Int = 5 - #|const INDEX_MASK : UInt = (1 << SEGMENT_LENGTH) - 1 - #|const SEGMENT_NUM : Int = 32 / SEGMENT_LENGTH - #|const HEAD_TAG : UInt = 0xffffffffU << (SEGMENT_LENGTH * SEGMENT_NUM) - #|pub fn[A : Hash] of(key : A) -> Path { - #| key.hash().reinterpret_as_uint() | HEAD_TAG - #|} - #|const MAX_TAIL : UInt = 0xffffffffU >> (SEGMENT_LENGTH * (SEGMENT_NUM - 1)) - #|pub fn Path::is_last(self : Path) -> Bool { - #| let Path(self) = self - #| self <= MAX_TAIL - #|} - #|pub fn Path::push(self : Path, idx : Int) -> Path { - #| let Path(self) = self - #| (self << SEGMENT_LENGTH) | idx.reinterpret_as_uint() - #|} - #|pub fn Path::idx(self : Path) -> Int { - #| let Path(self) = self - #| (self & INDEX_MASK).reinterpret_as_int() - #|} - #|pub fn Path::next(self : Path) -> Path { - #| let Path(self) = self - #| self >> SEGMENT_LENGTH - #|} - ), - }, + "path.mbt": ( + #|pub struct Path(UInt) derive(Eq) + #|const SEGMENT_LENGTH : Int = 5 + #|const INDEX_MASK : UInt = (1 << SEGMENT_LENGTH) - 1 + #|const SEGMENT_NUM : Int = 32 / SEGMENT_LENGTH + #|const HEAD_TAG : UInt = 0xffffffffU << (SEGMENT_LENGTH * SEGMENT_NUM) + #|pub fn[A : Hash] of(key : A) -> Path { + #| key.hash().reinterpret_as_uint() | HEAD_TAG + #|} + #|const MAX_TAIL : UInt = 0xffffffffU >> (SEGMENT_LENGTH * (SEGMENT_NUM - 1)) + #|pub fn Path::is_last(self : Path) -> Bool { + #| let Path(self) = self + #| self <= MAX_TAIL + #|} + #|pub fn Path::push(self : Path, idx : Int) -> Path { + #| let Path(self) = self + #| (self << SEGMENT_LENGTH) | idx.reinterpret_as_uint() + #|} + #|pub fn Path::idx(self : Path) -> Int { + #| let Path(self) = self + #| (self & INDEX_MASK).reinterpret_as_int() + #|} + #|pub fn Path::next(self : Path) -> Path { + #| let Path(self) = self + #| self >> SEGMENT_LENGTH + #|} + ) + } ) ///| let moonbitlang_core_immut_internal_sparse_array_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/immut/internal/sparse_array", - deps={ - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/array": moonbitlang_core_array_module, - }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": ["moonbitlang/core/builtin", "moonbitlang/core/array"] - #|} - ), - "bitset.mbt": ( - #|pub(all) struct Bitset(UInt) derive(Eq) - #|let empty_bitset : Bitset = Bitset(0) - #|pub fn Bitset::has(self : Bitset, idx : Int) -> Bool { - #| (self.0 & (1U << idx)) != 0 - #|} - #|pub fn Bitset::index_of(self : Bitset, idx : Int) -> Int { - #| (self.0 & ((1U << idx) - 1)).popcnt() - #|} - #|pub fn Bitset::first_idx(self : Bitset) -> Int { - #| self.0.ctz() - #|} - #|pub fn Bitset::union(self : Bitset, other : Bitset) -> Bitset { - #| Bitset(self.0 | other.0) - #|} - #|pub fn Bitset::intersection(self : Bitset, other : Bitset) -> Bitset { - #| Bitset(self.0 & other.0) - #|} - #|pub fn Bitset::add(self : Bitset, idx : Int) -> Bitset { - #| Bitset(self.0 | (1U << idx)) - #|} - #|pub fn Bitset::remove(self : Bitset, idx : Int) -> Bitset { - #| Bitset(self.0 ^ (1U << idx)) - #|} - #|#alias(size, deprecated) - #|pub fn Bitset::length(self : Bitset) -> Int { - #| let Bitset(self) = self - #| self.popcnt() - #|} - #|test "Bitset::has" { - #| let b = empty_bitset.add(2) - #| inspect(b.has(0), content="false") - #| inspect(b.has(2), content="true") - #| let b = b.add(0) - #| inspect(b.has(0), content="true") - #| inspect(b.has(2), content="true") - #|} - #|test "Bitset::index_of" { - #| let b = empty_bitset.add(2) - #| inspect(b.index_of(2), content="0") - #| let b = b.add(0) - #| inspect(b.index_of(2), content="1") - #| let b = b.add(5) - #| inspect(b.index_of(2), content="1") - #| inspect(b.index_of(3), content="2") - #| inspect(b.index_of(4), content="2") - #| inspect(b.index_of(5), content="2") - #| inspect(b.index_of(6), content="3") - #|} - #|test "Bitset::union" { - #| let b1 = empty_bitset.add(2).add(3) - #| let b2 = empty_bitset.add(0).add(1) - #| let b3 = b1.union(b2) - #| inspect(b3.has(0), content="true") - #| inspect(b3.has(1), content="true") - #| inspect(b3.has(2), content="true") - #| inspect(b3.has(3), content="true") - #|} - #|test "Bitset::intersection" { - #| let b1 = empty_bitset.add(2).add(3) - #| let b2 = empty_bitset.add(0).add(1).add(2) - #| let b3 = b1.intersection(b2) - #| inspect(b3.has(0), content="false") - #| inspect(b3.has(1), content="false") - #| inspect(b3.has(2), content="true") - #| inspect(b3.has(3), content="false") - #|} - #|test "Bitset::remove" { - #| let b = empty_bitset.add(2).add(3) - #| inspect(b.has(2), content="true") - #| inspect(b.has(3), content="true") - #| inspect(b.index_of(2), content="0") - #| inspect(b.index_of(3), content="1") - #| let b = b.remove(2) - #| inspect(b.has(2), content="false") - #| inspect(b.has(3), content="true") - #| inspect(b.index_of(3), content="0") - #|} - #|test "Bitset::size" { - #| let b = empty_bitset - #| inspect(b.length(), content="0") - #| let b = b.add(0) - #| inspect(b.length(), content="1") - #| let b = b.add(1) - #| inspect(b.length(), content="2") - #| let b = b.add(1) - #| inspect(b.length(), content="2") - #|} - #|test "Bitset::ctpop" { - #| inspect( - #| ([0, 0xf0f0f0f0, 0x3c3c0ff0] : Array[_]).map(x => x.popcnt()), - #| content="[0, 16, 16]", - #| ) - #|} - ), - "sparse_array.mbt": ( - #|pub(all) struct SparseArray[X] { - #| elem_info : Bitset - #| data : FixedArray[X] - #|} derive(Eq) - #|pub fn[X] empty() -> SparseArray[X] { - #| { elem_info: empty_bitset, data: [] } - #|} - #|pub fn[X] singleton(idx : Int, value : X) -> SparseArray[X] { - #| { elem_info: empty_bitset.add(idx), data: [value] } - #|} - #|pub fn[X] SparseArray::get(self : SparseArray[X], idx : Int) -> X? { - #| if self.elem_info.has(idx) { - #| Some(self.data[self.elem_info.index_of(idx)]) - #| } else { - #| None - #| } - #|} - #|fn[X] SparseArray::unsafe_get(self : SparseArray[X], idx : Int) -> X { - #| self.data[self.elem_info.index_of(idx)] - #|} - #|pub fn[X] doubleton( - #| idx1 : Int, - #| value1 : X, - #| idx2 : Int, - #| value2 : X, - #|) -> SparseArray[X] { - #| { - #| elem_info: empty_bitset.add(idx1).add(idx2), - #| data: if idx1 < idx2 { - #| [value1, value2] - #| } else { - #| [value2, value1] - #| }, - #| } - #|} - #|pub fn[X] SparseArray::add( - #| self : SparseArray[X], - #| idx : Int, - #| value : X, - #|) -> SparseArray[X] { - #| let old_data = self.data - #| let old_len = old_data.length() - #| let new_len = old_len + 1 - #| let pos_of_new_item = self.elem_info.index_of(idx) - #| let new_data = FixedArray::make(new_len, value) - #| old_data.blit_to(new_data, len=pos_of_new_item) - #| old_data.blit_to( - #| new_data, - #| len=old_len - pos_of_new_item, - #| src_offset=pos_of_new_item, - #| dst_offset=pos_of_new_item + 1, - #| ) - #| { elem_info: self.elem_info.add(idx), data: new_data } - #|} - #|pub fn[X] SparseArray::remove( - #| self : SparseArray[X], - #| idx : Int, - #|) -> SparseArray[X] { - #| let old_data = self.data - #| let old_len = old_data.length() - #| let pos_of_removed_item = self.elem_info.index_of(idx) - #| let new_data = FixedArray::make(old_len - 1, old_data.unsafe_get(0)) - #| old_data.blit_to( - #| new_data, - #| len=pos_of_removed_item, - #| src_offset=0, - #| dst_offset=0, - #| ) - #| old_data.blit_to( - #| new_data, - #| len=old_len - pos_of_removed_item - 1, - #| src_offset=pos_of_removed_item + 1, - #| dst_offset=pos_of_removed_item, - #| ) - #| { elem_info: self.elem_info.remove(idx), data: new_data } - #|} - #|pub fn[X] SparseArray::union( - #| self : SparseArray[X], - #| other : SparseArray[X], - #| f : (X, X) -> X raise?, - #|) -> SparseArray[X] raise? { - #| let union_elem_info = self.elem_info.union(other.elem_info) - #| let data = FixedArray::make(union_elem_info.length(), self.data[0]) - #| for rest = union_elem_info, index = 0; rest != empty_bitset; { - #| let idx = rest.first_idx() - #| data[index] = match self.get(idx) { - #| None => other.unsafe_get(idx) - #| Some(value1) => - #| match other.get(idx) { - #| None => value1 - #| Some(value2) => f(value1, value2) - #| } - #| } - #| continue rest.remove(idx), index + 1 - #| } - #| { elem_info: union_elem_info, data } - #|} - #|fn[A] FixedArray::copy_prefix( - #| self : FixedArray[A], - #| len~ : Int, - #|) -> FixedArray[A] { - #| let res = FixedArray::make(len, self[0]) - #| FixedArray::unsafe_blit(res, 0, self, 0, len) - #| res - #|} - #|pub fn[X] SparseArray::intersection( - #| self : SparseArray[X], - #| other : SparseArray[X], - #| f : (X, X) -> X? raise?, - #|) -> SparseArray[X]? raise? { - #| let inter_elem_info = self.elem_info.intersection(other.elem_info) - #| guard inter_elem_info != 0 else { return None } - #| let data = FixedArray::make(inter_elem_info.length(), self.data[0]) - #| for rest = inter_elem_info, index = 0, elem_info = inter_elem_info; rest != 0; { - #| let idx = rest.first_idx() - #| match f(self.unsafe_get(idx), other.unsafe_get(idx)) { - #| Some(value) => { - #| data[index] = value - #| continue rest.remove(idx), index + 1, elem_info - #| } - #| None => continue rest.remove(idx), index, elem_info.remove(idx) - #| } - #| } else { - #| if elem_info == empty_bitset { - #| None - #| } else if elem_info == inter_elem_info { - #| Some({ elem_info, data }) - #| } else { - #| Some({ elem_info, data: data.copy_prefix(len=index) }) - #| } - #| } - #|} - #|pub fn[X] SparseArray::difference( - #| self : SparseArray[X], - #| other : SparseArray[X], - #| f : (X, X) -> X?, - #|) -> SparseArray[X]? { - #| let self_elem_info = self.elem_info - #| let data = FixedArray::make(self_elem_info.length(), self.data[0]) - #| for rest = self_elem_info, index = 0, elem_info = self_elem_info; rest != - #| empty_bitset; { - #| let idx = rest.first_idx() - #| match other.get(idx) { - #| None => { - #| data[index] = self.unsafe_get(idx) - #| continue rest.remove(idx), index + 1, elem_info - #| } - #| Some(value2) => - #| match f(self.unsafe_get(idx), value2) { - #| None => continue rest.remove(idx), index, elem_info.remove(idx) - #| Some(v) => { - #| data[index] = v - #| continue rest.remove(idx), index + 1, elem_info - #| } - #| } - #| } - #| } else { - #| if elem_info == empty_bitset { - #| None - #| } else if elem_info == self_elem_info { - #| Some({ elem_info, data }) - #| } else { - #| Some({ elem_info, data: data.copy_prefix(len=index) }) - #| } - #| } - #|} - #|pub fn[X, Y] SparseArray::map( - #| self : SparseArray[X], - #| f : (X) -> Y raise?, - #|) -> SparseArray[Y] raise? { - #| { elem_info: self.elem_info, data: self.data.map(f) } - #|} - #|pub fn[X] SparseArray::filter( - #| self : SparseArray[X], - #| pred : (X) -> X? raise?, - #|) -> SparseArray[X]? raise? { - #| let self_elem_info = self.elem_info - #| let data = FixedArray::make(self_elem_info.length(), self.data[0]) - #| for rest = self_elem_info, index = 0, elem_info = self_elem_info; rest != - #| empty_bitset; { - #| let idx = rest.first_idx() - #| match pred(self.unsafe_get(idx)) { - #| None => continue rest.remove(idx), index, elem_info.remove(idx) - #| Some(v) => { - #| data[index] = v - #| continue rest.remove(idx), index + 1, elem_info - #| } - #| } - #| } else { - #| if elem_info == empty_bitset { - #| None - #| } else if elem_info == self_elem_info { - #| Some({ elem_info, data }) - #| } else { - #| Some({ elem_info, data: data.copy_prefix(len=index) }) - #| } - #| } - #|} - #|pub fn[X] SparseArray::replace( - #| self : SparseArray[X], - #| idx : Int, - #| value : X, - #|) -> SparseArray[X] { - #| let new_data = self.data.copy() - #| new_data[self.elem_info.index_of(idx)] = value - #| { elem_info: self.elem_info, data: new_data } - #|} - #|#alias(size, deprecated) - #|pub fn[X] SparseArray::length(self : SparseArray[X]) -> Int { - #| self.data.length() - #|} - #|pub fn[X] SparseArray::each( - #| self : SparseArray[X], - #| f : (X) -> Unit raise?, - #|) -> Unit raise? { - #| for i in 0.. T[A] raise @json.JsonDecodeError { - #| @json.from_json(json) - #|} - #|#deprecated - #|#coverage.skip - #|pub fn[A] T::init_(self : T[A]) -> T[A] { - #| fn aux(self) { - #| match self { - #| Nil => Nil - #| Cons(_, Nil) => Nil - #| Cons(head, tail) => Cons(head, aux(tail)) - #| } - #| } - #| aux(self) - #|} - #|#deprecated("use `==` instead") - #|pub fn[A : Eq] T::equal(self : T[A], other : T[A]) -> Bool { - #| loop (self, other) { - #| (Nil, Nil) => true - #| (Cons(h, t), Cons(h1, t1)) => if h == h1 { continue (t, t1) } else { false } - #| (_, _) => false - #| } - #|} - #|#deprecated("use `@immut/list.from_array` instead") - #|#coverage.skip - #|pub fn[A] T::from_array(arr : ArrayView[A]) -> T[A] { - #| from_array(arr) - #|} - #|#deprecated("use `@immut/list.default` instead") - #|#coverage.skip - #|pub fn[X] T::default() -> T[X] { - #| Nil - #|} - #|#deprecated("use `@immut/list.from_iter` instead") - #|#coverage.skip - #|pub fn[A] T::from_iter(iter : Iter[A]) -> T[A] { - #| from_iter(iter) - #|} - #|#deprecated("use `@immut/list.of` instead") - #|#coverage.skip - #|pub fn[A] T::of(arr : ArrayView[A]) -> T[A] { - #| of(arr) - #|} - ), - "list.mbt": ( - #|#deprecated("use `@list` instead") - #|pub fn[A] T::add(self : T[A], head : A) -> T[A] { - #| Cons(head, self) - #|} - #|pub impl[A : Show] Show for T[A] with output(xs, logger) { - #| logger.write_iter(xs.iter(), prefix="@list.from_array([", suffix="])") - #|} - #|pub impl[A : ToJson] ToJson for T[A] with to_json(self) { - #| let capacity = self.length() - #| guard capacity != 0 else { return [] } - #| let jsons = Array::new(capacity~) - #| for a in self { - #| jsons.push(a.to_json()) - #| } - #| Json::array(jsons) - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A : ToJson] T::to_json(self : T[A]) -> Json { - #| ToJson::to_json(self) - #|} - #|pub impl[A : @json.FromJson] @json.FromJson for T[A] with from_json(json, path) { - #| guard json is Array(arr) else { - #| raise @json.JsonDecodeError((path, "@immut/list.from_json: expected array")) - #| } - #| for i = arr.length() - 1, list = Nil; i >= 0; { - #| continue i - 1, list.add(A::from_json(arr[i], path.add_index(i))) - #| } else { - #| list - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A : @json.FromJson] from_json( - #| json : Json, - #|) -> T[A] raise @json.JsonDecodeError { - #| @json.from_json(json) - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A] from_array(arr : ArrayView[A]) -> T[A] { - #| for i = arr.length() - 1, list = Nil; i >= 0; { - #| continue i - 1, Cons(arr[i], list) - #| } else { - #| list - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A] T::length(self : T[A]) -> Int { - #| loop (self, 0) { - #| (Nil, len) => len - #| (Cons(_, rest), acc) => continue (rest, acc + 1) - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A] T::each(self : T[A], f : (A) -> Unit raise?) -> Unit raise? { - #| loop self { - #| Nil => () - #| Cons(head, tail) => { - #| f(head) - #| continue tail - #| } - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A] T::eachi(self : T[A], f : (Int, A) -> Unit raise?) -> Unit raise? { - #| loop (self, 0) { - #| (Nil, _) => () - #| (Cons(x, xs), i) => { - #| f(i, x) - #| continue (xs, i + 1) - #| } - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A, B] T::map(self : T[A], f : (A) -> B) -> T[B] { - #| match self { - #| Nil => Nil - #| Cons(head, tail) => Cons(f(head), tail.map(f)) - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A, B] T::mapi(self : T[A], f : (Int, A) -> B raise?) -> T[B] raise? { - #| fn go(xs : T[A], i : Int, f : (Int, A) -> B raise?) -> T[B] raise? { - #| match xs { - #| Nil => Nil - #| Cons(x, xs) => Cons(f(i, x), go(xs, i + 1, f)) - #| } - #| } - #| go(self, 0, f) - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A, B] T::rev_map(self : T[A], f : (A) -> B raise?) -> T[B] raise? { - #| loop (Nil, self) { - #| (acc, Nil) => acc - #| (acc, Cons(x, xs)) => continue (Cons(f(x), acc), xs) - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A] T::to_array(self : T[A]) -> Array[A] { - #| match self { - #| Nil => [] - #| Cons(x, xs) => { - #| let arr = [x] - #| loop xs { - #| Nil => () - #| Cons(x, xs) => { - #| arr.push(x) - #| continue xs - #| } - #| } - #| arr - #| } - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A] T::filter(self : T[A], f : (A) -> Bool raise?) -> T[A] raise? { - #| match self { - #| Nil => Nil - #| Cons(head, tail) => - #| if f(head) { - #| Cons(head, tail.filter(f)) - #| } else { - #| tail.filter(f) - #| } - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A] T::all(self : T[A], f : (A) -> Bool raise?) -> Bool raise? { - #| loop self { - #| Nil => true - #| Cons(head, tail) => if f(head) { continue tail } else { false } - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A] T::any(self : T[A], f : (A) -> Bool raise?) -> Bool raise? { - #| match self { - #| Nil => false - #| Cons(head, tail) => f(head) || tail.any(f) - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A] T::tail(self : T[A]) -> T[A] { - #| match self { - #| Nil => Nil - #| Cons(_, tail) => tail - #| } - #|} - #|#internal(unsafe, "Panic if the list is empty") - #|#doc(hidden) - #|#deprecated("use `@list` instead") - #|pub fn[A] T::unsafe_head(self : T[A]) -> A { - #| match self { - #| Nil => abort("head of empty list") - #| Cons(head, _) => head - #| } - #|} - #|#coverage.skip - #|#deprecated("use `@list` instead") - #|pub fn[A] T::head_exn(self : T[A]) -> A { - #| self.unsafe_head() - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A] T::head(self : T[A]) -> A? { - #| match self { - #| Nil => None - #| Cons(head, _) => Some(head) - #| } - #|} - #|#internal(unsafe, "Panic if the list is empty") - #|#doc(hidden) - #|#deprecated("use `@list` instead") - #|pub fn[A] T::unsafe_last(self : T[A]) -> A { - #| loop self { - #| Nil => abort("last of empty list") - #| Cons(head, Nil) => head - #| Cons(_, tail) => continue tail - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A] T::last(self : T[A]) -> A? { - #| loop self { - #| Nil => None - #| Cons(head, Nil) => Some(head) - #| Cons(_, tail) => continue tail - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A] T::concat(self : T[A], other : T[A]) -> T[A] { - #| match self { - #| Nil => other - #| Cons(head, tail) => Cons(head, tail.concat(other)) - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A] T::rev_concat(self : T[A], other : T[A]) -> T[A] { - #| loop (self, other) { - #| (Nil, other) => other - #| (Cons(head, tail), other) => continue (tail, Cons(head, other)) - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A] T::rev(self : T[A]) -> T[A] { - #| self.rev_concat(Nil) - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A, B] T::fold( - #| self : T[A], - #| init~ : B, - #| f : (B, A) -> B raise?, - #|) -> B raise? { - #| match self { - #| Nil => init - #| Cons(head, tail) => tail.fold(f, init=f(init, head)) - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A, B] T::rev_fold( - #| self : T[A], - #| init~ : B, - #| f : (A, B) -> B raise?, - #|) -> B raise? { - #| let xs = self.to_array() - #| let mut acc = init - #| for x in xs.rev_iter() { - #| acc = f(x, acc) - #| } - #| acc - #|} - #|#coverage.skip - #|#deprecated("use `@list` instead") - #|pub fn[A, B] T::fold_left( - #| self : T[A], - #| f : (B, A) -> B raise?, - #| init~ : B, - #|) -> B raise? { - #| self.fold(init~, f) - #|} - #|#coverage.skip - #|#deprecated("use `@list.rev_fold` instead") - #|pub fn[A, B] T::fold_right( - #| self : T[A], - #| f : (A, B) -> B raise?, - #| init~ : B, - #|) -> B raise? { - #| match self { - #| Nil => init - #| Cons(head, tail) => f(head, tail.rev_fold(f, init~)) - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A, B] T::foldi( - #| self : T[A], - #| init~ : B, - #| f : (Int, B, A) -> B raise?, - #|) -> B raise? { - #| fn go(xs : T[A], i : Int, f : (Int, B, A) -> B raise?, acc : B) -> B raise? { - #| match xs { - #| Nil => acc - #| Cons(x, xs) => go(xs, i + 1, f, f(i, acc, x)) - #| } - #| } - #| go(self, 0, f, init) - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A, B] T::rev_foldi( - #| self : T[A], - #| init~ : B, - #| f : (Int, A, B) -> B raise?, - #|) -> B raise? { - #| fn go(xs : T[A], i : Int, f : (Int, A, B) -> B raise?, acc : B) -> B raise? { - #| match xs { - #| Nil => acc - #| Cons(x, xs) => f(i, x, go(xs, i + 1, f, acc)) - #| } - #| } - #| go(self, 0, f, init) - #|} - #|#deprecated("use `@list.foldi` instead") - #|pub fn[A, B] T::fold_lefti( - #| self : T[A], - #| f : (Int, B, A) -> B raise?, - #| init~ : B, - #|) -> B raise? { - #| fn go(xs : T[A], i : Int, f : (Int, B, A) -> B raise?, acc : B) -> B raise? { - #| match xs { - #| Nil => acc - #| Cons(x, xs) => go(xs, i + 1, f, f(i, acc, x)) - #| } - #| } - #| go(self, 0, f, init) - #|} - #|#deprecated("use `@list.rev_foldi` instead") - #|pub fn[A, B] T::fold_righti( - #| self : T[A], - #| f : (Int, A, B) -> B raise?, - #| init~ : B, - #|) -> B raise? { - #| fn go(xs : T[A], i : Int, f : (Int, A, B) -> B raise?, acc : B) -> B raise? { - #| match xs { - #| Nil => acc - #| Cons(x, xs) => f(i, x, go(xs, i + 1, f, acc)) - #| } - #| } - #| go(self, 0, f, init) - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A, B] T::zip(self : T[A], other : T[B]) -> T[(A, B)]? { - #| let mut acc = Nil - #| let res = loop (self, other) { - #| (Nil, Nil) => break Some(acc) - #| (Cons(x, xs), Cons(y, ys)) => { - #| acc = Cons((x, y), acc) - #| continue (xs, ys) - #| } - #| (_, _) => break None - #| } - #| res.map(T::rev) - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A, B] T::concat_map(self : T[A], f : (A) -> T[B]) -> T[B] { - #| self.flat_map(f) - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A, B] T::flat_map(self : T[A], f : (A) -> T[B] raise?) -> T[B] raise? { - #| match self { - #| Nil => Nil - #| Cons(head, tail) => f(head).concat(tail.flat_map(f)) - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A, B] T::filter_map(self : T[A], f : (A) -> B?) -> T[B] { - #| loop (Nil, self) { - #| (acc, Nil) => acc.rev() - #| (acc, Cons(x, xs)) => - #| match f(x) { - #| Some(v) => continue (acc.add(v), xs) - #| None => continue (acc, xs) - #| } - #| } - #|} - #|#internal(unsafe, "Panic if the index is out of bounds") - #|#doc(hidden) - #|#deprecated("use `@list` instead") - #|pub fn[A] T::unsafe_nth(self : T[A], n : Int) -> A { - #| loop (self, n) { - #| (Nil, _) => abort("nth: index out of bounds") - #| (Cons(head, _), 0) => head - #| (Cons(_, tail), n) => continue (tail, n - 1) - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A] T::nth_exn(self : T[A], n : Int) -> A { - #| self.unsafe_nth(n) - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A] T::nth(self : T[A], n : Int) -> A? { - #| loop (self, n) { - #| (Nil, _) => None - #| (Cons(head, _), 0) => Some(head) - #| (Cons(_, tail), n) => continue (tail, n - 1) - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A] repeat(n : Int, x : A) -> T[A] { - #| if n == 0 { - #| Nil - #| } else { - #| Cons(x, repeat(n - 1, x)) - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A] T::intersperse(self : T[A], separator : A) -> T[A] { - #| match self { - #| Nil => Nil - #| Cons(head, Nil) => Cons(head, Nil) - #| Cons(head, tail) => Cons(head, Cons(separator, tail.intersperse(separator))) - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A] T::is_empty(self : T[A]) -> Bool { - #| self is Nil - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A, B] T::unzip(self : T[(A, B)]) -> (T[A], T[B]) { - #| let mut xs = Nil - #| let mut ys = Nil - #| loop self.rev() { - #| Nil => break (xs, ys) - #| Cons((x, y), tail) => { - #| xs = Cons(x, xs) - #| ys = Cons(y, ys) - #| continue tail - #| } - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A] T::flatten(self : T[T[A]]) -> T[A] { - #| match self { - #| Nil => Nil - #| Cons(head, tail) => head.concat(tail.flatten()) - #| } - #|} - #|#internal(unsafe, "Panic if the list is empty") - #|#doc(hidden) - #|#deprecated("use `@list` instead") - #|pub fn[A : Compare] T::unsafe_maximum(self : T[A]) -> A { - #| match self { - #| Nil => abort("maximum: empty list") - #| Cons(x, Nil) => x - #| Cons(x, xs) => { - #| let y = xs.unsafe_maximum() - #| if x > y { - #| x - #| } else { - #| y - #| } - #| } - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A : Compare] T::maximum(self : T[A]) -> A? { - #| match self { - #| Nil => None - #| Cons(x, Nil) => Some(x) - #| Cons(x, xs) => - #| match xs.maximum() { - #| None => Some(x) - #| Some(y) => Some(if x > y { x } else { y }) - #| } - #| } - #|} - #|#internal(unsafe, "Panic if the list is empty") - #|#doc(hidden) - #|#deprecated("use `@list` instead") - #|pub fn[A : Compare] T::unsafe_minimum(self : T[A]) -> A { - #| match self { - #| Nil => abort("minimum: empty list") - #| Cons(x, Nil) => x - #| Cons(x, xs) => { - #| let y = xs.unsafe_minimum() - #| if x < y { - #| x - #| } else { - #| y - #| } - #| } - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A : Compare] T::minimum(self : T[A]) -> A? { - #| match self { - #| Nil => None - #| Cons(x, Nil) => Some(x) - #| Cons(x, xs) => - #| match xs.minimum() { - #| None => Some(x) - #| Some(y) => Some(if x < y { x } else { y }) - #| } - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A : Compare] T::sort(self : T[A]) -> T[A] { - #| match self { - #| Nil => Nil - #| Cons(x, xs) => { - #| let smaller = xs.filter(y => y < x) - #| let greater = xs.filter(y => y >= x) - #| smaller.sort().concat(Cons(x, greater.sort())) - #| } - #| } - #|} - #|pub impl[A] Add for T[A] with add(self, other) { - #| self.concat(other) - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A : Eq] T::contains(self : T[A], value : A) -> Bool { - #| loop self { - #| Nil => false - #| Cons(x, xs) => if x == value { true } else { continue xs } - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A, S] unfold(f : (S) -> (A, S)? raise?, init~ : S) -> T[A] raise? { - #| match f(init) { - #| Some((element, new_state)) => Cons(element, unfold(init=new_state, f)) - #| None => Nil - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A] T::take(self : T[A], n : Int) -> T[A] { - #| fn go(n, t) { - #| match (n, t) { - #| (_, Nil) => Nil - #| (1, Cons(x, _)) => Cons(x, Nil) - #| (n, Cons(x, xs)) => Cons(x, go(n - 1, xs)) - #| } - #| } - #| if n <= 0 { - #| Nil - #| } else { - #| go(n, self) - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A] T::drop(self : T[A], n : Int) -> T[A] { - #| if n <= 0 { - #| self - #| } else { - #| loop (n, self) { - #| (_, Nil) => Nil - #| (1, Cons(_, xs)) => xs - #| (n, Cons(_, xs)) => continue (n - 1, xs) - #| } - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A] T::take_while(self : T[A], p : (A) -> Bool) -> T[A] { - #| match self { - #| Nil => Nil - #| Cons(x, xs) => if p(x) { Cons(x, xs.take_while(p)) } else { Nil } - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A] T::drop_while(self : T[A], p : (A) -> Bool raise?) -> T[A] raise? { - #| loop self { - #| Nil => Nil - #| Cons(x, xs) => if p(x) { continue xs } else { Cons(x, xs) } - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A, E] T::scan_left( - #| self : T[A], - #| f : (E, A) -> E raise?, - #| init~ : E, - #|) -> T[E] raise? { - #| Cons( - #| init, - #| match self { - #| Nil => Nil - #| Cons(x, xs) => xs.scan_left(f, init=f(init, x)) - #| }, - #| ) - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A, B] T::scan_right( - #| self : T[A], - #| f : (A, B) -> B raise?, - #| init~ : B, - #|) -> T[B] raise? { - #| match self { - #| Nil => Cons(init, Nil) - #| Cons(x, xs) => { - #| let qs = xs.scan_right(f, init~) - #| Cons(f(x, qs.unsafe_head()), qs) - #| } - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A : Eq, B] T::lookup(self : T[(A, B)], v : A) -> B? { - #| loop self { - #| Nil => None - #| Cons((x, y), xs) => if x == v { Some(y) } else { continue xs } - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A] T::find(self : T[A], f : (A) -> Bool raise?) -> A? raise? { - #| loop self { - #| Nil => None - #| Cons(element, list) => - #| if f(element) { - #| Some(element) - #| } else { - #| continue list - #| } - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A] T::findi(self : T[A], f : (A, Int) -> Bool raise?) -> A? raise? { - #| loop (self, 0) { - #| (list, index) => - #| match list { - #| Nil => None - #| Cons(element, list) => - #| if f(element, index) { - #| Some(element) - #| } else { - #| continue (list, index + 1) - #| } - #| } - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A] T::remove_at(self : T[A], index : Int) -> T[A] { - #| match (index, self) { - #| (0, Cons(_, tail)) => tail - #| (_, Cons(head, tail)) => Cons(head, tail.remove_at(index - 1)) - #| (_, Nil) => Nil - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A : Eq] T::remove(self : T[A], elem : A) -> T[A] { - #| match self { - #| Nil => Nil - #| Cons(head, tail) => - #| if head == elem { - #| tail - #| } else { - #| Cons(head, tail.remove(elem)) - #| } - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A : Eq] T::is_prefix(self : T[A], prefix : T[A]) -> Bool { - #| loop (self, prefix) { - #| (_, Nil) => true - #| (Nil, Cons(_)) => false - #| (Cons(h1, t1), Cons(h2, t2)) => - #| if h1 == h2 { - #| continue (t1, t2) - #| } else { - #| false - #| } - #| } - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A : Eq] T::is_suffix(self : T[A], suffix : T[A]) -> Bool { - #| self.rev().is_prefix(suffix.rev()) - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A] T::intercalate(self : T[T[A]], sep : T[A]) -> T[A] { - #| self.intersperse(sep).flatten() - #|} - #|pub impl[X] Default for T[X] with default() { - #| Nil - #|} - #|#deprecated("use `@list` instead") - #|pub fn[X] default() -> T[X] { - #| Nil - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A] T::iter(self : T[A]) -> Iter[A] { - #| Iter::new(yield_ => loop self { - #| Nil => IterContinue - #| Cons(head, tail) => { - #| if yield_(head) is IterEnd { - #| break IterEnd - #| } - #| continue tail - #| } - #| }) - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A] T::iter2(self : T[A]) -> Iter2[Int, A] { - #| Iter2::new(yield_ => loop (self, 0) { - #| (Nil, _) => IterEnd - #| (Cons(head, tail), i) => { - #| if yield_(i, head) is IterEnd { - #| break IterEnd - #| } - #| continue (tail, i + 1) - #| } - #| }) - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A] from_iter(iter : Iter[A]) -> T[A] { - #| iter.fold(init=Nil, (acc, e) => Cons(e, acc)).rev() - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A] from_iter_rev(iter : Iter[A]) -> T[A] { - #| iter.fold(init=Nil, (acc, e) => Cons(e, acc)) - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A] of(arr : ArrayView[A]) -> T[A] { - #| for i = arr.length() - 1, list = Nil; i >= 0; { - #| continue i - 1, Cons(arr[i], list) - #| } else { - #| list - #| } - #|} - #|pub impl[X : @quickcheck.Arbitrary] @quickcheck.Arbitrary for T[X] with arbitrary( - #| size, - #| rs, - #|) { - #| @quickcheck.Arbitrary::arbitrary(size, rs) |> from_array - #|} - #|#deprecated("use `@list` instead") - #|pub fn[A] singleton(x : A) -> T[A] { - #| Cons(x, Nil) - #|} - #|pub impl[A : Hash] Hash for T[A] with hash_combine(self, hasher) { - #| for e in self { - #| hasher.combine(e) - #| } - #|} - #|pub impl[A : Compare] Compare for T[A] with compare(self, other) { - #| loop (self, other) { - #| (Nil, Nil) => 0 - #| (Nil, Cons(_, _)) => -1 - #| (Cons(_, _), Nil) => 1 - #| (Cons(x, xs), Cons(y, ys)) => { - #| let cmp = x.compare(y) - #| if cmp != 0 { - #| break cmp - #| } else { - #| continue (xs, ys) - #| } - #| } - #| } - #|} - ), - }, + "bitset.mbt": ( + #|pub struct Bitset(UInt) derive(Eq) + #|let empty_bitset : Bitset = Bitset(0) + #|fn Bitset::has(self : Bitset, idx : Int) -> Bool { + #| (self.0 & (1U << idx)) != 0 + #|} + #|fn Bitset::index_of(self : Bitset, idx : Int) -> Int { + #| (self.0 & ((1U << idx) - 1)).popcnt() + #|} + #|pub fn Bitset::first_idx(self : Bitset) -> Int { + #| self.0.ctz() + #|} + #|fn Bitset::union(self : Bitset, other : Bitset) -> Bitset { + #| Bitset(self.0 | other.0) + #|} + #|fn Bitset::intersection(self : Bitset, other : Bitset) -> Bitset { + #| Bitset(self.0 & other.0) + #|} + #|fn Bitset::add(self : Bitset, idx : Int) -> Bitset { + #| Bitset(self.0 | (1U << idx)) + #|} + #|fn Bitset::remove(self : Bitset, idx : Int) -> Bitset { + #| Bitset(self.0 ^ (1U << idx)) + #|} + #|#alias(size, deprecated) + #|fn Bitset::length(self : Bitset) -> Int { + #| let Bitset(self) = self + #| self.popcnt() + #|} + #|test "Bitset::has" { + #| let b = empty_bitset.add(2) + #| inspect(b.has(0), content="false") + #| inspect(b.has(2), content="true") + #| let b = b.add(0) + #| inspect(b.has(0), content="true") + #| inspect(b.has(2), content="true") + #|} + #|test "Bitset::index_of" { + #| let b = empty_bitset.add(2) + #| inspect(b.index_of(2), content="0") + #| let b = b.add(0) + #| inspect(b.index_of(2), content="1") + #| let b = b.add(5) + #| inspect(b.index_of(2), content="1") + #| inspect(b.index_of(3), content="2") + #| inspect(b.index_of(4), content="2") + #| inspect(b.index_of(5), content="2") + #| inspect(b.index_of(6), content="3") + #|} + #|test "Bitset::union" { + #| let b1 = empty_bitset.add(2).add(3) + #| let b2 = empty_bitset.add(0).add(1) + #| let b3 = b1.union(b2) + #| inspect(b3.has(0), content="true") + #| inspect(b3.has(1), content="true") + #| inspect(b3.has(2), content="true") + #| inspect(b3.has(3), content="true") + #|} + #|test "Bitset::intersection" { + #| let b1 = empty_bitset.add(2).add(3) + #| let b2 = empty_bitset.add(0).add(1).add(2) + #| let b3 = b1.intersection(b2) + #| inspect(b3.has(0), content="false") + #| inspect(b3.has(1), content="false") + #| inspect(b3.has(2), content="true") + #| inspect(b3.has(3), content="false") + #|} + #|test "Bitset::remove" { + #| let b = empty_bitset.add(2).add(3) + #| inspect(b.has(2), content="true") + #| inspect(b.has(3), content="true") + #| inspect(b.index_of(2), content="0") + #| inspect(b.index_of(3), content="1") + #| let b = b.remove(2) + #| inspect(b.has(2), content="false") + #| inspect(b.has(3), content="true") + #| inspect(b.index_of(3), content="0") + #|} + #|test "Bitset::size" { + #| let b = empty_bitset + #| inspect(b.length(), content="0") + #| let b = b.add(0) + #| inspect(b.length(), content="1") + #| let b = b.add(1) + #| inspect(b.length(), content="2") + #| let b = b.add(1) + #| inspect(b.length(), content="2") + #|} + #|test "Bitset::ctpop" { + #| inspect( + #| ([0, 0xf0f0f0f0, 0x3c3c0ff0] : Array[_]).map(x => x.popcnt()), + #| content="[0, 16, 16]", + #| ) + #|} + ), + "sparse_array.mbt": ( + #|pub struct SparseArray[X] { + #| elem_info : Bitset + #| data : FixedArray[X] + #|} derive(Eq) + #|pub fn[X] empty() -> SparseArray[X] { + #| { elem_info: empty_bitset, data: [] } + #|} + #|pub fn[X] singleton(idx : Int, value : X) -> SparseArray[X] { + #| { elem_info: empty_bitset.add(idx), data: [value] } + #|} + #|pub fn[X] SparseArray::get(self : SparseArray[X], idx : Int) -> X? { + #| if self.elem_info.has(idx) { + #| Some(self.data[self.elem_info.index_of(idx)]) + #| } else { + #| None + #| } + #|} + #|fn[X] SparseArray::unsafe_get(self : SparseArray[X], idx : Int) -> X { + #| self.data[self.elem_info.index_of(idx)] + #|} + #|pub fn[X] doubleton( + #| idx1 : Int, + #| value1 : X, + #| idx2 : Int, + #| value2 : X, + #|) -> SparseArray[X] { + #| { + #| elem_info: empty_bitset.add(idx1).add(idx2), + #| data: if idx1 < idx2 { + #| [value1, value2] + #| } else { + #| [value2, value1] + #| }, + #| } + #|} + #|pub fn[X] SparseArray::add( + #| self : SparseArray[X], + #| idx : Int, + #| value : X, + #|) -> SparseArray[X] { + #| let old_data = self.data + #| let old_len = old_data.length() + #| let new_len = old_len + 1 + #| let pos_of_new_item = self.elem_info.index_of(idx) + #| let new_data = FixedArray::make(new_len, value) + #| old_data.blit_to(new_data, len=pos_of_new_item) + #| old_data.blit_to( + #| new_data, + #| len=old_len - pos_of_new_item, + #| src_offset=pos_of_new_item, + #| dst_offset=pos_of_new_item + 1, + #| ) + #| { elem_info: self.elem_info.add(idx), data: new_data } + #|} + #|pub fn[X] SparseArray::remove( + #| self : SparseArray[X], + #| idx : Int, + #|) -> SparseArray[X] { + #| let old_data = self.data + #| let old_len = old_data.length() + #| let pos_of_removed_item = self.elem_info.index_of(idx) + #| let new_data = FixedArray::make(old_len - 1, old_data.unsafe_get(0)) + #| old_data.blit_to( + #| new_data, + #| len=pos_of_removed_item, + #| src_offset=0, + #| dst_offset=0, + #| ) + #| old_data.blit_to( + #| new_data, + #| len=old_len - pos_of_removed_item - 1, + #| src_offset=pos_of_removed_item + 1, + #| dst_offset=pos_of_removed_item, + #| ) + #| { elem_info: self.elem_info.remove(idx), data: new_data } + #|} + #|pub fn[X] SparseArray::union( + #| self : SparseArray[X], + #| other : SparseArray[X], + #| f : (X, X) -> X raise?, + #|) -> SparseArray[X] raise? { + #| let union_elem_info = self.elem_info.union(other.elem_info) + #| let data = FixedArray::make(union_elem_info.length(), self.data[0]) + #| for rest = union_elem_info, index = 0; rest != empty_bitset; { + #| let idx = rest.first_idx() + #| data[index] = match self.get(idx) { + #| None => other.unsafe_get(idx) + #| Some(value1) => + #| match other.get(idx) { + #| None => value1 + #| Some(value2) => f(value1, value2) + #| } + #| } + #| continue rest.remove(idx), index + 1 + #| } + #| { elem_info: union_elem_info, data } + #|} + #|fn[A] FixedArray::copy_prefix( + #| self : FixedArray[A], + #| len~ : Int, + #|) -> FixedArray[A] { + #| let res = FixedArray::make(len, self[0]) + #| FixedArray::unsafe_blit(res, 0, self, 0, len) + #| res + #|} + #|pub fn[X] SparseArray::intersection( + #| self : SparseArray[X], + #| other : SparseArray[X], + #| f : (X, X) -> X? raise?, + #|) -> SparseArray[X]? raise? { + #| let inter_elem_info = self.elem_info.intersection(other.elem_info) + #| guard inter_elem_info != 0 else { return None } + #| let data = FixedArray::make(inter_elem_info.length(), self.data[0]) + #| for rest = inter_elem_info, index = 0, elem_info = inter_elem_info; rest != 0; { + #| let idx = rest.first_idx() + #| match f(self.unsafe_get(idx), other.unsafe_get(idx)) { + #| Some(value) => { + #| data[index] = value + #| continue rest.remove(idx), index + 1, elem_info + #| } + #| None => continue rest.remove(idx), index, elem_info.remove(idx) + #| } + #| } nobreak { + #| if elem_info == empty_bitset { + #| None + #| } else if elem_info == inter_elem_info { + #| Some({ elem_info, data }) + #| } else { + #| Some({ elem_info, data: data.copy_prefix(len=index) }) + #| } + #| } + #|} + #|pub fn[X] SparseArray::difference( + #| self : SparseArray[X], + #| other : SparseArray[X], + #| f : (X, X) -> X?, + #|) -> SparseArray[X]? { + #| let self_elem_info = self.elem_info + #| let data = FixedArray::make(self_elem_info.length(), self.data[0]) + #| for rest = self_elem_info, index = 0, elem_info = self_elem_info; rest != + #| empty_bitset; { + #| let idx = rest.first_idx() + #| match other.get(idx) { + #| None => { + #| data[index] = self.unsafe_get(idx) + #| continue rest.remove(idx), index + 1, elem_info + #| } + #| Some(value2) => + #| match f(self.unsafe_get(idx), value2) { + #| None => continue rest.remove(idx), index, elem_info.remove(idx) + #| Some(v) => { + #| data[index] = v + #| continue rest.remove(idx), index + 1, elem_info + #| } + #| } + #| } + #| } nobreak { + #| if elem_info == empty_bitset { + #| None + #| } else if elem_info == self_elem_info { + #| Some({ elem_info, data }) + #| } else { + #| Some({ elem_info, data: data.copy_prefix(len=index) }) + #| } + #| } + #|} + #|pub fn[X, Y] SparseArray::map( + #| self : SparseArray[X], + #| f : (X) -> Y raise?, + #|) -> SparseArray[Y] raise? { + #| { elem_info: self.elem_info, data: self.data.map(f) } + #|} + #|pub fn[X] SparseArray::filter( + #| self : SparseArray[X], + #| pred : (X) -> X? raise?, + #|) -> SparseArray[X]? raise? { + #| let self_elem_info = self.elem_info + #| let data = FixedArray::make(self_elem_info.length(), self.data[0]) + #| for rest = self_elem_info, index = 0, elem_info = self_elem_info; rest != + #| empty_bitset; { + #| let idx = rest.first_idx() + #| match pred(self.unsafe_get(idx)) { + #| None => continue rest.remove(idx), index, elem_info.remove(idx) + #| Some(v) => { + #| data[index] = v + #| continue rest.remove(idx), index + 1, elem_info + #| } + #| } + #| } nobreak { + #| if elem_info == empty_bitset { + #| None + #| } else if elem_info == self_elem_info { + #| Some({ elem_info, data }) + #| } else { + #| Some({ elem_info, data: data.copy_prefix(len=index) }) + #| } + #| } + #|} + #|pub fn[X] SparseArray::replace( + #| self : SparseArray[X], + #| idx : Int, + #| value : X, + #|) -> SparseArray[X] { + #| let new_data = self.data.copy() + #| new_data[self.elem_info.index_of(idx)] = value + #| { elem_info: self.elem_info, data: new_data } + #|} + #|#alias(size, deprecated) + #|pub fn[X] SparseArray::length(self : SparseArray[X]) -> Int { + #| self.data.length() + #|} + #|pub fn[X] SparseArray::each( + #| self : SparseArray[X], + #| f : (X) -> Unit raise?, + #|) -> Unit raise? { + #| for i in 0.. PriorityQueue[A] { - #| { node: Empty, size: 0 } - #|} - #|#as_free_fn - #|#alias(of, deprecated="Use from_array instead") - #|#as_free_fn(of, deprecated="Use from_array instead") - #|pub fn[A : Compare] PriorityQueue::from_array( - #| array : ArrayView[A], - #|) -> PriorityQueue[A] { - #| let mut pq = new() - #| for i in 0.. Array[A] { - #| let arr : Array[A] = [] - #| let stack : Array[Node[A]] = [self.node] - #| while stack.pop() is Some(node) { - #| match node { - #| Empty => () - #| Leaf(a) => arr.push(a) - #| Branch(a, left=l, right=r) => { - #| arr.push(a) - #| stack.push(l) - #| stack.push(r) - #| } - #| } - #| } - #| arr.sort() - #| arr.rev_in_place() - #| arr - #|} - #|pub fn[A : Compare] PriorityQueue::iter(self : PriorityQueue[A]) -> Iter[A] { - #| self.iterator().iter() - #|} - #|pub fn[A : Compare] PriorityQueue::iterator( - #| self : PriorityQueue[A], - #|) -> Iterator[A] { - #| self.to_array().iterator() - #|} - #|#as_free_fn - #|pub fn[A : Compare] PriorityQueue::from_iter( - #| iter : Iter[A], - #|) -> PriorityQueue[A] { - #| iter.fold(init=new(), (s, e) => s.push(e)) - #|} - #|#as_free_fn - #|pub fn[A : Compare] PriorityQueue::from_iterator( - #| iter : Iterator[A], - #|) -> PriorityQueue[A] { - #| iter.fold(init=new(), (s, e) => s.push(e)) - #|} - #|priv struct Path(Int) - #|fn path(size : Int) -> Path { - #| loop (size, 0) { - #| (1, y) => Path(y) - #| (x, y) => continue (x >> 1, (y << 1) | (x & 1)) - #| } - #|} - #|fn Path::is_left(self : Path) -> Bool { - #| (self.0 & 1) == 0 - #|} - #|fn Path::next(self : Path) -> Path { - #| Path(self.0 >> 1) - #|} - #|pub fn[A : Compare] PriorityQueue::pop( - #| self : PriorityQueue[A], - #|) -> PriorityQueue[A]? { - #| match self.node { - #| Empty => None - #| Leaf(_) => Some({ node: Empty, size: 0 }) - #| Branch(_) => { - #| let (value, temp) = self.node.remove_last_leaf(path(self.size)) - #| Some({ node: temp.change_and_down(value), size: self.size - 1 }) - #| } - #| } - #|} - #|fn[A] Node::remove_last_leaf(self : Node[A], path : Path) -> (A, Node[A]) { - #| match self { - #| Empty => abort("Priority queue is empty!") - #| Leaf(a) => (a, Empty) - #| Branch(a, left=Leaf(l_top), right=Empty) => (l_top, Leaf(a)) - #| Branch(a, left=l, right=r) => - #| if path.is_left() { - #| let (e, ld) = l.remove_last_leaf(path.next()) - #| (e, Branch(a, left=ld, right=r)) - #| } else { - #| let (e, rd) = r.remove_last_leaf(path.next()) - #| (e, Branch(a, left=l, right=rd)) - #| } - #| } - #|} - #|fn[A : Compare] Node::change_and_down(self : Node[A], value : A) -> Node[A] { - #| match self { - #| Empty => abort("unreachable") - #| Leaf(_) => Leaf(value) - #| Branch(_, left=l, right=r) => - #| match (l, r) { - #| (Leaf(l_top), Empty) => - #| if value >= l_top { - #| Branch(value, left=l, right=Empty) - #| } else { - #| Branch(l_top, left=Leaf(value), right=Empty) - #| } - #| (Branch(l_top, ..) | Leaf(l_top), Branch(r_top, ..) | Leaf(r_top)) => - #| if value >= l_top && value >= r_top { - #| Branch(value, left=l, right=r) - #| } else if l_top >= r_top { - #| Branch(l_top, left=l.change_and_down(value), right=r) - #| } else { - #| Branch(r_top, left=l, right=r.change_and_down(value)) - #| } - #| _ => abort("unreachable") - #| } - #| } - #|} - #|#internal(unsafe, "Panics if the queue is empty.") - #|#doc(hidden) - #|#alias(pop_exn, deprecated) - #|pub fn[A : Compare] PriorityQueue::unsafe_pop( - #| self : PriorityQueue[A], - #|) -> PriorityQueue[A] { - #| match self.node { - #| Empty => abort("Priority queue is empty!") - #| Leaf(_) => { node: Empty, size: 0 } - #| Branch(_) => { - #| let (value, temp) = self.node.remove_last_leaf(path(self.size)) - #| { node: temp.change_and_down(value), size: self.size - 1 } - #| } - #| } - #|} - #|pub fn[A : Compare] PriorityQueue::push( - #| self : PriorityQueue[A], - #| value : A, - #|) -> PriorityQueue[A] { - #| match self.node { - #| Empty => { node: Leaf(value), size: 1 } - #| Leaf(_) | Branch(_) => { - #| let size = self.size + 1 - #| { node: self.node.push(value, path(size)), size } - #| } - #| } - #|} - #|fn[A : Compare] Node::push(self : Node[A], value : A, path : Path) -> Node[A] { - #| match self { - #| Empty => Leaf(value) - #| Leaf(a) => { - #| let (high, low) = if a > value { (a, value) } else { (value, a) } - #| Branch(high, left=Leaf(low), right=Empty) - #| } - #| Branch(a, left=l, right=r) => { - #| let (high, low) = if a > value { (a, value) } else { (value, a) } - #| if path.is_left() { - #| Branch(high, left=l.push(low, path.next()), right=r) - #| } else { - #| Branch(high, left=l, right=r.push(low, path.next())) - #| } - #| } - #| } - #|} - #|pub fn[A] PriorityQueue::peek(self : PriorityQueue[A]) -> A? { - #| match self.node { - #| Empty => None - #| Leaf(a) => Some(a) - #| Branch(a, ..) => Some(a) - #| } - #|} - #|pub fn[A] PriorityQueue::is_empty(self : PriorityQueue[A]) -> Bool { - #| self.node is Empty - #|} - #|pub fn[A] PriorityQueue::length(self : PriorityQueue[A]) -> Int { - #| self.size - #|} - #|pub impl[A : Show + Compare] Show for PriorityQueue[A] with output(self, logger) { - #| logger.write_iter( - #| self.iter(), - #| prefix="@immut/priority_queue.from_array([", - #| suffix="])", - #| ) - #|} - #|pub impl[X : @quickcheck.Arbitrary + Compare] @quickcheck.Arbitrary for PriorityQueue[ - #| X, - #|] with arbitrary(size, rs) { - #| @quickcheck.Arbitrary::arbitrary(size, rs) |> from_array - #|} - #|pub impl[A : Compare] Eq for PriorityQueue[A] with equal(self, other) { - #| self.length() == other.length() && self.to_array() == other.to_array() - #|} - #|pub impl[A : Hash + Compare] Hash for PriorityQueue[A] with hash_combine( - #| self, - #| hasher, - #|) { - #| for e in self { - #| hasher.combine(e) - #| } - #|} - #|pub impl[A : Compare] Compare for PriorityQueue[A] with compare(self, other) { - #| let len_cmp = self.length().compare(other.length()) - #| if len_cmp != 0 { - #| return len_cmp - #| } - #| let self_arr = self.to_array() - #| let other_arr = other.to_array() - #| for i in 0.. PriorityQueue[A] { + #| { node: Empty, size: 0 } + #|} + #|#as_free_fn + #|#alias(of, deprecated="Use from_array instead") + #|#as_free_fn(of, deprecated="Use from_array instead") + #|pub fn[A : Compare] PriorityQueue::from_array( + #| array : ArrayView[A], + #|) -> PriorityQueue[A] { + #| for x in array; pq = (new() : PriorityQueue[A]) { + #| continue pq.push(x) + #| } nobreak { + #| pq + #| } + #|} + #|pub fn[A : Compare] PriorityQueue::to_array( + #| self : PriorityQueue[A], + #|) -> Array[A] { + #| let arr : Array[A] = [] + #| let stack : Array[Node[A]] = [self.node] + #| while stack.pop() is Some(node) { + #| match node { + #| Empty => () + #| Leaf(a) => arr.push(a) + #| Branch(a, left=l, right=r) => { + #| arr.push(a) + #| stack.push(l) + #| stack.push(r) + #| } + #| } + #| } + #| arr.sort() + #| arr.rev_in_place() + #| arr + #|} + #|#alias(iterator, deprecated) + #|pub fn[A : Compare] PriorityQueue::iter(self : PriorityQueue[A]) -> Iter[A] { + #| self.to_array().iter() + #|} + #|#as_free_fn + #|#alias(from_iterator, deprecated) + #|#as_free_fn(from_iterator, deprecated) + #|pub fn[A : Compare] PriorityQueue::from_iter( + #| iter : Iter[A], + #|) -> PriorityQueue[A] { + #| iter.fold(init=new(), (s, e) => s.push(e)) + #|} + #|priv struct Path(Int) + #|fn path(size : Int) -> Path { + #| loop (size, 0) { + #| (1, y) => Path(y) + #| (x, y) => continue (x >> 1, (y << 1) | (x & 1)) + #| } + #|} + #|fn Path::is_left(self : Path) -> Bool { + #| (self.0 & 1) == 0 + #|} + #|fn Path::next(self : Path) -> Path { + #| Path(self.0 >> 1) + #|} + #|pub fn[A : Compare] PriorityQueue::pop( + #| self : PriorityQueue[A], + #|) -> PriorityQueue[A]? { + #| match self.node { + #| Empty => None + #| Leaf(_) => Some({ node: Empty, size: 0 }) + #| Branch(_) => { + #| let (value, temp) = self.node.remove_last_leaf(path(self.size)) + #| Some({ node: temp.change_and_down(value), size: self.size - 1 }) + #| } + #| } + #|} + #|fn[A] Node::remove_last_leaf(self : Node[A], path : Path) -> (A, Node[A]) { + #| match self { + #| Empty => abort("Priority queue is empty!") + #| Leaf(a) => (a, Empty) + #| Branch(a, left=Leaf(l_top), right=Empty) => (l_top, Leaf(a)) + #| Branch(a, left=l, right=r) => + #| if path.is_left() { + #| let (e, ld) = l.remove_last_leaf(path.next()) + #| (e, Branch(a, left=ld, right=r)) + #| } else { + #| let (e, rd) = r.remove_last_leaf(path.next()) + #| (e, Branch(a, left=l, right=rd)) + #| } + #| } + #|} + #|fn[A : Compare] Node::change_and_down(self : Node[A], value : A) -> Node[A] { + #| match self { + #| Empty => abort("unreachable") + #| Leaf(_) => Leaf(value) + #| Branch(_, left=l, right=r) => + #| match (l, r) { + #| (Leaf(l_top), Empty) => + #| if value >= l_top { + #| Branch(value, left=l, right=Empty) + #| } else { + #| Branch(l_top, left=Leaf(value), right=Empty) + #| } + #| (Branch(l_top, ..) | Leaf(l_top), Branch(r_top, ..) | Leaf(r_top)) => + #| if value >= l_top && value >= r_top { + #| Branch(value, left=l, right=r) + #| } else if l_top >= r_top { + #| Branch(l_top, left=l.change_and_down(value), right=r) + #| } else { + #| Branch(r_top, left=l, right=r.change_and_down(value)) + #| } + #| _ => abort("unreachable") + #| } + #| } + #|} + #|#internal(unsafe, "Panics if the queue is empty.") + #|#doc(hidden) + #|#alias(pop_exn, deprecated) + #|pub fn[A : Compare] PriorityQueue::unsafe_pop( + #| self : PriorityQueue[A], + #|) -> PriorityQueue[A] { + #| match self.node { + #| Empty => abort("Priority queue is empty!") + #| Leaf(_) => { node: Empty, size: 0 } + #| Branch(_) => { + #| let (value, temp) = self.node.remove_last_leaf(path(self.size)) + #| { node: temp.change_and_down(value), size: self.size - 1 } + #| } + #| } + #|} + #|pub fn[A : Compare] PriorityQueue::push( + #| self : PriorityQueue[A], + #| value : A, + #|) -> PriorityQueue[A] { + #| match self.node { + #| Empty => { node: Leaf(value), size: 1 } + #| Leaf(_) | Branch(_) => { + #| let size = self.size + 1 + #| { node: self.node.push(value, path(size)), size } + #| } + #| } + #|} + #|fn[A : Compare] Node::push(self : Node[A], value : A, path : Path) -> Node[A] { + #| match self { + #| Empty => Leaf(value) + #| Leaf(a) => { + #| let (high, low) = if a > value { (a, value) } else { (value, a) } + #| Branch(high, left=Leaf(low), right=Empty) + #| } + #| Branch(a, left=l, right=r) => { + #| let (high, low) = if a > value { (a, value) } else { (value, a) } + #| if path.is_left() { + #| Branch(high, left=l.push(low, path.next()), right=r) + #| } else { + #| Branch(high, left=l, right=r.push(low, path.next())) + #| } + #| } + #| } + #|} + #|pub fn[A] PriorityQueue::peek(self : PriorityQueue[A]) -> A? { + #| match self.node { + #| Empty => None + #| Leaf(a) => Some(a) + #| Branch(a, ..) => Some(a) + #| } + #|} + #|pub fn[A] PriorityQueue::is_empty(self : PriorityQueue[A]) -> Bool { + #| self.node is Empty + #|} + #|pub fn[A] PriorityQueue::length(self : PriorityQueue[A]) -> Int { + #| self.size + #|} + #|pub impl[A : Show + Compare] Show for PriorityQueue[A] with output(self, logger) { + #| logger.write_iter( + #| self.iter(), + #| prefix="@immut/priority_queue.from_array([", + #| suffix="])", + #| ) + #|} + #|pub impl[X : @quickcheck.Arbitrary + Compare] @quickcheck.Arbitrary for PriorityQueue[ + #| X, + #|] with arbitrary(size, rs) { + #| @quickcheck.Arbitrary::arbitrary(size, rs) |> from_array + #|} + #|pub impl[A : Compare] Eq for PriorityQueue[A] with equal(self, other) { + #| physical_equal(self, other) || + #| (self.length() == other.length() && self.to_array() == other.to_array()) + #|} + #|pub impl[A : Hash + Compare] Hash for PriorityQueue[A] with hash_combine( + #| self, + #| hasher, + #|) { + #| for e in self { + #| hasher.combine(e) + #| } + #|} + #|pub impl[A : Compare] Compare for PriorityQueue[A] with compare(self, other) { + #| let len_cmp = self.length().compare(other.length()) + #| if len_cmp != 0 { + #| return len_cmp + #| } + #| let self_arr = self.to_array() + #| let other_arr = other.to_array() + #| for i, x in self_arr { + #| let cmp = x.compare(other_arr[i]) + #| if cmp != 0 { + #| return cmp + #| } + #| } nobreak { + #| return 0 + #| } + #|} + ), + "types.mbt": ( + #|#alias(T, deprecated) + #|struct PriorityQueue[A] { + #| node : Node[A] + #| size : Int + #|} + #|priv enum Node[A] { + #| Empty + #| Leaf(A) + #| Branch(A, left~ : Node[A], right~ : Node[A]) + #|} + #|pub impl[A : ToJson + Compare] ToJson for PriorityQueue[A] with to_json( + #| self : PriorityQueue[A], + #|) { + #| let output : Array[Json] = [] + #| for item in self { + #| output.push(item.to_json()) + #| } + #| Json::array(output) + #|} + ) + } ) ///| let moonbitlang_core_immut_sorted_map_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/immut/sorted_map", - deps={ - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/tuple": moonbitlang_core_tuple_module, - "moonbitlang/core/string": moonbitlang_core_string_module, - "moonbitlang/core/array": moonbitlang_core_array_module, - "moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module, - "moonbitlang/core/json": moonbitlang_core_json_module, - }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| "moonbitlang/core/builtin", - #| "moonbitlang/core/tuple", - #| "moonbitlang/core/string", - #| "moonbitlang/core/array", - #| "moonbitlang/core/quickcheck", - #| "moonbitlang/core/json" - #| ], - #| "targets": { - #| "panic_wbtest.mbt": ["not", "native", "llvm"] - #| } - #|} - ), - "deprecated.mbt": ( - #|#deprecated("Use `map_with_key` instead. `map` will accept `(K, X) -> Y` in the future.") - #|#coverage.skip - #|pub fn[K, X, Y] SortedMap::map( - #| self : SortedMap[K, X], - #| f : (X) -> Y, - #|) -> SortedMap[K, Y] { - #| self.map_with_key((_, value) => f(value)) - #|} - #|#deprecated("Use `foldl_with_key` instead. `fold` will accept `(A, K, V) -> A` in the future.") - #|pub fn[K, V, A] SortedMap::fold( - #| self : SortedMap[K, V], - #| init~ : A, - #| f : (A, V) -> A, - #|) -> A { - #| self.foldl_with_key((acc, _k, v) => f(acc, v), init~) - #|} - #|#deprecated("Use `keys_as_iter` instead. `keys` will return `Iter[K]` instead of `Array[K]` in the future.") - #|#coverage.skip - #|pub fn[K, V] SortedMap::keys(self : SortedMap[K, V]) -> Array[K] { - #| self.iter().map(p => p.0).collect() - #|} - #|#deprecated("Use `values` instead") - #|#coverage.skip - #|pub fn[K, V] SortedMap::elems(self : SortedMap[K, V]) -> Array[V] { - #| self.values().collect() - #|} - #|#deprecated("Use `filter_with_key` instead. `filter` will accept `(K, V) -> Bool` in the future.") - #|#coverage.skip - #|pub fn[K, V] SortedMap::filter( - #| self : SortedMap[K, V], - #| pred : (V) -> Bool raise?, - #|) -> SortedMap[K, V] raise? { - #| self.filter_with_key((_, v) => pred(v)) - #|} - ), - "map.mbt": ( - #|#alias(insert, deprecated) - #|pub fn[K : Compare, V] SortedMap::add( - #| self : SortedMap[K, V], - #| key : K, - #| value : V, - #|) -> SortedMap[K, V] { - #| match self { - #| Empty => singleton(key, value) - #| Tree(k, value=v, l, r, ..) => { - #| let c = key.compare(k) - #| if c == 0 { - #| make_tree(k, value, l, r) - #| } else if c < 0 { - #| balance(k, v, l.add(key, value), r) - #| } else { - #| balance(k, v, l, r.add(key, value)) - #| } - #| } - #| } - #|} - #|fn[K, V] SortedMap::split_max( - #| self : SortedMap[K, V], - #|) -> (K, V, SortedMap[K, V]) { - #| match self { - #| Tree(k, value=v, l, Empty, ..) => (k, v, l) - #| Tree(k, value=v, l, r, ..) => { - #| let (k1, v1, r) = r.split_max() - #| (k1, v1, balance(k, v, l, r)) - #| } - #| Empty => abort("Map::split_max error") - #| } - #|} - #|fn[K, V] SortedMap::split_min( - #| self : SortedMap[K, V], - #|) -> (K, V, SortedMap[K, V]) { - #| match self { - #| Tree(k, value=v, Empty, r, ..) => (k, v, r) - #| Tree(k, value=v, l, r, ..) => { - #| let (k1, v1, l) = l.split_min() - #| (k1, v1, balance(k, v, l, r)) - #| } - #| Empty => abort("Map::split_min error") - #| } - #|} - #|fn[K, V] glue(l : SortedMap[K, V], r : SortedMap[K, V]) -> SortedMap[K, V] { - #| match (l, r) { - #| (Empty, r) => r - #| (l, Empty) => l - #| (l, r) => - #| if l.length() > r.length() { - #| let (k, v, l) = l.split_max() - #| balance(k, v, l, r) - #| } else { - #| let (k, v, r) = r.split_min() - #| balance(k, v, l, r) - #| } - #| } - #|} - #|pub fn[K : Compare, V] SortedMap::remove( - #| self : SortedMap[K, V], - #| key : K, - #|) -> SortedMap[K, V] { - #| match self { - #| Empty => Empty - #| Tree(k, value=v, l, r, ..) => { - #| let c = key.compare(k) - #| if c == 0 { - #| glue(l, r) - #| } else if c < 0 { - #| balance(k, v, l.remove(key), r) - #| } else { - #| balance(k, v, l, r.remove(key)) - #| } - #| } - #| } - #|} - #|pub fn[K, V] SortedMap::filter_with_key( - #| self : SortedMap[K, V], - #| pred : (K, V) -> Bool raise?, - #|) -> SortedMap[K, V] raise? { - #| match self { - #| Empty => Empty - #| Tree(k, value=v, l, r, ..) => - #| if pred(k, v) { - #| balance(k, v, l.filter_with_key(pred), r.filter_with_key(pred)) - #| } else { - #| glue(l.filter_with_key(pred), r.filter_with_key(pred)) - #| } - #| } - #|} - #|pub fn[K, V] SortedMap::to_array(self : SortedMap[K, V]) -> Array[(K, V)] { - #| let arr = [] - #| self.each((k, v) => arr.push((k, v))) - #| arr - #|} - #|pub fn[K : Compare, V] SortedMap::merge( - #| self : SortedMap[K, V], - #| other : SortedMap[K, V], - #|) -> SortedMap[K, V] { - #| let mut result = self - #| other.each((k, v) => result = result.add(k, v)) - #| result - #|} - #|let ratio = 5 - #|fn[K, V] balance( - #| key : K, - #| value : V, - #| l : SortedMap[K, V], - #| r : SortedMap[K, V], - #|) -> SortedMap[K, V] { - #| fn single_l(k1, v1, x, r) { - #| guard r is Tree(k2, value=v2, y, z, ..) - #| make_tree(k2, v2, make_tree(k1, v1, x, y), z) - #| } - #| fn single_r(k2, v2, l, z) { - #| guard l is Tree(k1, value=v1, x, y, ..) - #| make_tree(k1, v1, x, make_tree(k2, v2, y, z)) - #| } - #| fn double_l(k1, v1, x, r) { - #| guard r is Tree(k3, value=v3, Tree(k2, value=v2, y1, y2, ..), z, ..) - #| make_tree(k2, v2, make_tree(k1, v1, x, y1), make_tree(k3, v3, y2, z)) - #| } - #| fn double_r(k3, v3, l, z) { - #| guard l is Tree(k1, value=v1, x, Tree(k2, value=v2, y1, y2, ..), ..) - #| make_tree(k2, v2, make_tree(k1, v1, x, y1), make_tree(k3, v3, y2, z)) - #| } - #| let ln = l.length() - #| let rn = r.length() - #| if ln + rn < 2 { - #| make_tree(key, value, l, r) - #| } else if rn > ratio * ln { - #| guard r is Tree(_, rl, rr, ..) - #| let rln = rl.length() - #| let rrn = rr.length() - #| if rln < rrn { - #| single_l(key, value, l, r) - #| } else { - #| double_l(key, value, l, r) - #| } - #| } else if ln > ratio * rn { - #| guard l is Tree(_, ll, lr, ..) - #| let lln = ll.length() - #| let lrn = lr.length() - #| if lrn < lln { - #| single_r(key, value, l, r) - #| } else { - #| double_r(key, value, l, r) - #| } - #| } else { - #| make_tree(key, value, l, r) - #| } - #|} - #|test "from_array" { - #| let m = from_array([ - #| (3, "three"), - #| (8, "eight"), - #| (1, "one"), - #| (2, "two"), - #| (0, "zero"), - #| ]) - #| inspect( - #| m.debug_tree(), - #| content="(3,three,(1,one,(0,zero,_,_),(2,two,_,_)),(8,eight,_,_))", - #| ) - #|} - #|test "insert" { - #| let m = from_array([(3, "three"), (8, "eight"), (1, "one")]) - #| inspect(m.debug_tree(), content="(3,three,(1,one,_,_),(8,eight,_,_))") - #| let m = m.add(5, "five").add(2, "two").add(0, "zero").add(1, "one_updated") - #| inspect( - #| m.debug_tree(), - #| content="(3,three,(1,one_updated,(0,zero,_,_),(2,two,_,_)),(8,eight,(5,five,_,_),_))", - #| ) - #|} - #|test "remove" { - #| let m1 = from_array([ - #| (3, "three"), - #| (8, "eight"), - #| (1, "one"), - #| (2, "two"), - #| (0, "zero"), - #| ]) - #| inspect( - #| m1.debug_tree(), - #| content="(3,three,(1,one,(0,zero,_,_),(2,two,_,_)),(8,eight,_,_))", - #| ) - #| let m2 = m1.remove(1).remove(3) - #| inspect(m2.debug_tree(), content="(2,two,(0,zero,_,_),(8,eight,_,_))") - #| let m3 = m1.remove(8) - #| inspect( - #| m3.debug_tree(), - #| content="(2,two,(1,one,(0,zero,_,_),_),(3,three,_,_))", - #| ) - #| let e : SortedMap[Int, Int] = Empty - #| inspect(e.remove(1).debug_tree(), content="_") - #|} - #|test "contains" { - #| let m = from_array([ - #| (3, "three"), - #| (8, "eight"), - #| (1, "one"), - #| (2, "two"), - #| (0, "zero"), - #| ]) - #| inspect( - #| m.debug_tree(), - #| content="(3,three,(1,one,(0,zero,_,_),(2,two,_,_)),(8,eight,_,_))", - #| ) - #| inspect(m.contains(8), content="true") - #| inspect(m.contains(2), content="true") - #| inspect(m.contains(4), content="false") - #|} - #|test "map" { - #| let m = from_array([ - #| (3, "three"), - #| (8, "eight"), - #| (1, "one"), - #| (2, "two"), - #| (0, "zero"), - #| ]) - #| let n = m.map_with_key((_, v) => v + "X") - #| assert_eq( - #| n.debug_tree(), - #| "(3,threeX,(1,oneX,(0,zeroX,_,_),(2,twoX,_,_)),(8,eightX,_,_))", - #| ) - #|} - #|test "map_with_key" { - #| let m = from_array([ - #| (3, "three"), - #| (8, "eight"), - #| (1, "one"), - #| (2, "two"), - #| (0, "zero"), - #| ]) - #| let n = m.map_with_key((k, v) => "\{k}-\{v}") - #| assert_eq( - #| n.debug_tree(), - #| "(3,3-three,(1,1-one,(0,0-zero,_,_),(2,2-two,_,_)),(8,8-eight,_,_))", - #| ) - #|} - #|test "filter" { - #| let m = from_array([ - #| (3, "three"), - #| (8, "eight"), - #| (1, "one"), - #| (2, "two"), - #| (0, "zero"), - #| ]) - #| let fm = m.filter_with_key((_, v) => v.length() > 3) - #| inspect(fm.debug_tree(), content="(3,three,(0,zero,_,_),(8,eight,_,_))") - #|} - #|test "filter_with_key" { - #| let m = from_array([ - #| (3, "three"), - #| (8, "eight"), - #| (1, "one"), - #| (2, "two"), - #| (0, "zero"), - #| ]) - #| let fm = m.filter_with_key((k, v) => k > 3 && v.length() > 3) - #| inspect(fm.debug_tree(), content="(8,eight,_,_)") - #|} - #|test "singleton" { - #| let m = singleton(3, "three") - #| inspect(m.debug_tree(), content="(3,three,_,_)") - #|} - #|test "empty" { - #| let m : SortedMap[Int, Int] = new() - #| inspect(m.debug_tree(), content="_") - #|} - #|test "split_max" { - #| let m = from_array([ - #| (3, "three"), - #| (8, "eight"), - #| (1, "one"), - #| (2, "two"), - #| (0, "zero"), - #| ]) - #| assert_eq( - #| m.debug_tree(), - #| "(3,three,(1,one,(0,zero,_,_),(2,two,_,_)),(8,eight,_,_))", - #| ) - #| let (k, v, r) = m.split_max() - #| inspect(k, content="8") - #| inspect(v, content="eight") - #| inspect( - #| r.debug_tree(), - #| content="(2,two,(1,one,(0,zero,_,_),_),(3,three,_,_))", - #| ) - #|} - #|test "split_min" { - #| let m = from_array([ - #| (3, "three"), - #| (8, "eight"), - #| (2, "two"), - #| (1, "one"), - #| (0, "zero"), - #| ]) - #| assert_eq( - #| m.debug_tree(), - #| "(3,three,(1,one,(0,zero,_,_),(2,two,_,_)),(8,eight,_,_))", - #| ) - #| let (k, v, r) = m.split_min() - #| inspect(k, content="0") - #| inspect(v, content="zero") - #| inspect( - #| r.debug_tree(), - #| content="(3,three,(1,one,_,(2,two,_,_)),(8,eight,_,_))", - #| ) - #|} - #|test "glue" { - #| let m = from_array([ - #| (3, "three"), - #| (8, "eight"), - #| (1, "one"), - #| (2, "two"), - #| (0, "zero"), - #| ]) - #| assert_eq( - #| m.debug_tree(), - #| "(3,three,(1,one,(0,zero,_,_),(2,two,_,_)),(8,eight,_,_))", - #| ) - #| let (l, r) = match m { - #| Tree(_, l, r, ..) => (l, r) - #| _ => abort("unreachable") - #| } - #| let m = glue(l, r) - #| inspect( - #| m.debug_tree(), - #| content="(2,two,(1,one,(0,zero,_,_),_),(8,eight,_,_))", - #| ) - #|} - #|test "split_max with non-empty tree" { - #| let m = from_array([ - #| (3, "three"), - #| (8, "eight"), - #| (1, "one"), - #| (2, "two"), - #| (0, "zero"), - #| ]) - #| let (k, v, r) = m.split_max() - #| inspect(k, content="8") - #| inspect(v, content="eight") - #| inspect( - #| r.debug_tree(), - #| content="(2,two,(1,one,(0,zero,_,_),_),(3,three,_,_))", - #| ) - #|} - ), - "traits_impl.mbt": ( - #|pub impl[K, V] Default for SortedMap[K, V] with default() { - #| new() - #|} - #|pub impl[K : Eq, V : Eq] Eq for SortedMap[K, V] with equal(self, other) -> Bool { - #| guard self.length() == other.length() else { return false } - #| let iter = self.iterator() - #| let iter1 = other.iterator() - #| while iter.next() is Some(a) && iter1.next() is Some(b) { - #| guard a == b else { break false } - #| } else { - #| true - #| } - #|} - #|pub impl[K : Compare, V : Compare] Compare for SortedMap[K, V] with compare( - #| self, - #| other, - #|) -> Int { - #| guard self.length() == other.length() else { - #| return self.length() - other.length() - #| } - #| let iter = self.iterator() - #| let iter1 = other.iterator() - #| while iter.next() is Some(a) && iter1.next() is Some(b) { - #| let cmp = a.compare(b) - #| guard cmp is 0 else { break cmp } - #| } else { - #| 0 - #| } - #|} - #|pub impl[K : @quickcheck.Arbitrary + Compare, V : @quickcheck.Arbitrary] @quickcheck.Arbitrary for SortedMap[ - #| K, - #| V, - #|] with arbitrary(size, rs) { - #| @quickcheck.Arbitrary::arbitrary(size, rs) |> from_array - #|} - #|pub impl[K : Hash, V : Hash] Hash for SortedMap[K, V] with hash_combine( - #| self, - #| hasher, - #|) { - #| for e in self { - #| hasher..combine(e.0)..combine(e.1) - #| } - #|} - #|pub impl[K : Show, V : Show] Show for SortedMap[K, V] with output(self, logger) { - #| logger.write_iter( - #| self.iter(), - #| prefix="@immut/sorted_map.from_array([", - #| suffix="])", - #| ) - #|} - #|pub impl[K : Show, V : ToJson] ToJson for SortedMap[K, V] with to_json(self) { - #| let capacity = self.length() - #| guard capacity != 0 else { return Json::object(Map::new()) } - #| let jsons = Map::new(capacity~) - #| self.each((k, v) => jsons[k.to_string()] = v.to_json()) - #| Json::object(jsons) - #|} - #|pub impl[V : @json.FromJson] @json.FromJson for SortedMap[String, V] with from_json( - #| json, - #| path, - #|) { - #| guard json is Object(obj) else { - #| raise @json.JsonDecodeError( - #| (path, "@immut/sorted_map.from_json: expected object"), - #| ) - #| } - #| let mut map = new() - #| for k, v in obj { - #| map = map.add(k, V::from_json(v, path.add_key(k))) - #| } - #| map - #|} - #|#as_free_fn - #|pub fn[V : @json.FromJson] SortedMap::from_json( - #| json : Json, - #|) -> SortedMap[String, V] raise @json.JsonDecodeError { - #| @json.from_json(json) - #|} - ), - "types.mbt": ( - #|#alias(T, deprecated) - #|enum SortedMap[K, V] { - #| Empty - #| Tree(K, value~ : V, size~ : Int, SortedMap[K, V], SortedMap[K, V]) - #|} - ), - "utils.mbt": ( - #|#as_free_fn - #|#alias(empty, deprecated) - #|pub fn[K, V] SortedMap::new() -> SortedMap[K, V] { - #| Empty - #|} - #|#as_free_fn - #|pub fn[K, V] SortedMap::singleton(key : K, value : V) -> SortedMap[K, V] { - #| Tree(key, value~, size=1, Empty, Empty) - #|} - #|pub fn[K : Compare, V] SortedMap::contains( - #| self : SortedMap[K, V], - #| key : K, - #|) -> Bool { - #| loop self { - #| Empty => false - #| Tree(k, l, r, ..) => { - #| let c = key.compare(k) - #| if c == 0 { - #| true - #| } else if c < 0 { - #| continue l - #| } else { - #| continue r - #| } - #| } - #| } - #|} - #|#alias(size, deprecated) - #|pub fn[K, V] SortedMap::length(self : SortedMap[K, V]) -> Int { - #| match self { - #| Empty => 0 - #| Tree(_) as t => t.size - #| } - #|} - #|pub fn[K, V] SortedMap::is_empty(self : SortedMap[K, V]) -> Bool { - #| self.length() == 0 - #|} - #|fn[K, V] make_tree( - #| key : K, - #| value : V, - #| l : SortedMap[K, V], - #| r : SortedMap[K, V], - #|) -> SortedMap[K, V] { - #| let size = l.length() + r.length() + 1 - #| Tree(key, value~, size~, l, r) - #|} - #|#alias(lookup, deprecated) - #|pub fn[K : Compare, V] SortedMap::get(self : SortedMap[K, V], key : K) -> V? { - #| loop self { - #| Empty => None - #| Tree(k, value~, l, r, ..) => { - #| let c = key.compare(k) - #| if c == 0 { - #| Some(value) - #| } else if c < 0 { - #| continue l - #| } else { - #| continue r - #| } - #| } - #| } - #|} - #|#alias("_[_]") - #|pub fn[K : Compare, V] SortedMap::at(self : SortedMap[K, V], key : K) -> V { - #| loop self { - #| Empty => panic() - #| Tree(k, value~, l, r, ..) => { - #| let c = key.compare(k) - #| if c == 0 { - #| value - #| } else if c < 0 { - #| continue l - #| } else { - #| continue r - #| } - #| } - #| } - #|} - #|pub fn[K, V] SortedMap::each( - #| self : SortedMap[K, V], - #| f : (K, V) -> Unit, - #|) -> Unit { - #| match self { - #| Empty => () - #| Tree(k, value~, l, r, ..) => { - #| l.each(f) - #| f(k, value) - #| r.each(f) - #| } - #| } - #|} - #|pub fn[K, V] SortedMap::eachi( - #| self : SortedMap[K, V], - #| f : (Int, K, V) -> Unit, - #|) -> Unit { - #| fn do_eachi(m : SortedMap[K, V], f, i) { - #| match m { - #| Empty => () - #| Tree(k, value~, l, r, ..) => { - #| do_eachi(l, f, i) - #| f(l.length() + i, k, value) - #| do_eachi(r, f, l.length() + i + 1) - #| } - #| } - #| } - #| do_eachi(self, f, 0) - #|} - #|pub fn[K, X, Y] SortedMap::map_with_key( - #| self : SortedMap[K, X], - #| f : (K, X) -> Y, - #|) -> SortedMap[K, Y] { - #| match self { - #| Empty => Empty - #| Tree(k, value~, l, r, size~) => - #| Tree(k, value=f(k, value), size~, l.map_with_key(f), r.map_with_key(f)) - #| } - #|} - #|#alias(foldr_with_key) - #|pub fn[K, V, A] SortedMap::rev_fold( - #| self : SortedMap[K, V], - #| f : (A, K, V) -> A, - #| init~ : A, - #|) -> A { - #| fn go(m : SortedMap[K, V], acc) { - #| match m { - #| Empty => acc - #| Tree(k, value~, l, r, ..) => go(l, f(go(r, acc), k, value)) - #| } - #| } - #| go(self, init) - #|} - #|pub fn[K, V, A] SortedMap::foldl_with_key( - #| self : SortedMap[K, V], - #| f : (A, K, V) -> A, - #| init~ : A, - #|) -> A { - #| fn go(m : SortedMap[K, V], acc) { - #| match m { - #| Empty => acc - #| Tree(k, value~, l, r, ..) => go(r, f(go(l, acc), k, value)) - #| } - #| } - #| go(self, init) - #|} - #|fn[K : Show, V : Show] SortedMap::debug_tree(self : SortedMap[K, V]) -> String { - #| match self { - #| Empty => "_" - #| Tree(k, value~, l, r, ..) => { - #| let l = l.debug_tree() - #| let r = r.debug_tree() - #| "(\{k},\{value},\{l},\{r})" - #| } - #| } - #|} - #|#as_free_fn - #|#alias(of, deprecated="Use from_array instead") - #|#as_free_fn(of, deprecated="Use from_array instead") - #|pub fn[K : Compare, V] SortedMap::from_array( - #| array : ArrayView[(K, V)], - #|) -> SortedMap[K, V] { - #| for i = 0, mp = Empty; i < array.length(); { - #| let (k, v) = array[i] - #| continue i + 1, mp.add(k, v) - #| } else { - #| mp - #| } - #|} - #|pub fn[K, V] SortedMap::iter(self : SortedMap[K, V]) -> Iter[(K, V)] { - #| self.iterator().iter() - #|} - #|pub fn[K, V] SortedMap::iterator(self : SortedMap[K, V]) -> Iterator[(K, V)] { - #| let mut curr_node = self - #| let parents = [] - #| Iterator::new(fn() { - #| loop curr_node { - #| Tree(k, value~, Empty, r, ..) => { - #| curr_node = r - #| Some((k, value)) - #| } - #| Tree(k, value~, l, r, ..) => { - #| parents.push((k, value, r)) - #| continue l - #| } - #| Empty if parents.pop() is Some((k, v, r)) => { - #| curr_node = r - #| Some((k, v)) - #| } - #| Empty => None - #| } - #| }) - #|} - #|pub fn[K, V] SortedMap::Iter2(self : SortedMap[K, V]) -> Iter2[K, V] { - #| self.iterator() - #|} - #|pub fn[K, V] SortedMap::iter2(self : SortedMap[K, V]) -> Iter2[K, V] { - #| self.Iter2().iter2() - #|} - #|#as_free_fn - #|pub fn[K : Compare, V] SortedMap::from_iter( - #| iter : Iter[(K, V)], - #|) -> SortedMap[K, V] { - #| iter.fold(init=new(), (m, e) => m.add(e.0, e.1)) - #|} - #|#as_free_fn - #|pub fn[K : Compare, V] SortedMap::from_iterator( - #| iter : Iterator[(K, V)], - #|) -> SortedMap[K, V] { - #| iter.fold(init=new(), (m, e) => m.add(e.0, e.1)) - #|} - #|pub fn[K, V] SortedMap::keys_as_iter(self : SortedMap[K, V]) -> Iter[K] { - #| self.iter().map(p => p.0) - #|} - #|pub fn[K, V] SortedMap::values(self : SortedMap[K, V]) -> Iter[V] { - #| self.iter().map(p => p.1) - #|} - #|pub fn[K : Show, V : ToJson] SortedMap::to_json(self : SortedMap[K, V]) -> Json { - #| ToJson::to_json(self) - #|} - ), - }, + "deprecated.mbt": ( + #|#deprecated("Use `map_with_key` instead. `map` will accept `(K, X) -> Y` in the future.") + #|#coverage.skip + #|pub fn[K, X, Y] SortedMap::map( + #| self : SortedMap[K, X], + #| f : (X) -> Y, + #|) -> SortedMap[K, Y] { + #| self.map_with_key((_, value) => f(value)) + #|} + #|#deprecated("Use `foldl_with_key` instead. `fold` will accept `(A, K, V) -> A` in the future.") + #|pub fn[K, V, A] SortedMap::fold( + #| self : SortedMap[K, V], + #| init~ : A, + #| f : (A, V) -> A, + #|) -> A { + #| self.foldl_with_key((acc, _k, v) => f(acc, v), init~) + #|} + #|#deprecated("Use `keys_as_iter` instead. `keys` will return `Iter[K]` instead of `Array[K]` in the future.") + #|#coverage.skip + #|pub fn[K, V] SortedMap::keys(self : SortedMap[K, V]) -> Array[K] { + #| self.iter().map(p => p.0).collect() + #|} + #|#deprecated("Use `values` instead") + #|#coverage.skip + #|pub fn[K, V] SortedMap::elems(self : SortedMap[K, V]) -> Array[V] { + #| self.values().collect() + #|} + #|#deprecated("Use `filter_with_key` instead. `filter` will accept `(K, V) -> Bool` in the future.") + #|#coverage.skip + #|pub fn[K, V] SortedMap::filter( + #| self : SortedMap[K, V], + #| pred : (V) -> Bool raise?, + #|) -> SortedMap[K, V] raise? { + #| self.filter_with_key((_, v) => pred(v)) + #|} + ), + "map.mbt": ( + #|#alias(insert, deprecated) + #|pub fn[K : Compare, V] SortedMap::add( + #| self : SortedMap[K, V], + #| key : K, + #| value : V, + #|) -> SortedMap[K, V] { + #| match self { + #| Empty => singleton(key, value) + #| Tree(k, value=v, l, r, ..) => { + #| let c = key.compare(k) + #| if c == 0 { + #| make_tree(k, value, l, r) + #| } else if c < 0 { + #| balance(k, v, l.add(key, value), r) + #| } else { + #| balance(k, v, l, r.add(key, value)) + #| } + #| } + #| } + #|} + #|fn[K, V] SortedMap::split_max( + #| self : SortedMap[K, V], + #|) -> (K, V, SortedMap[K, V]) { + #| match self { + #| Tree(k, value=v, l, Empty, ..) => (k, v, l) + #| Tree(k, value=v, l, r, ..) => { + #| let (k1, v1, r) = r.split_max() + #| (k1, v1, balance(k, v, l, r)) + #| } + #| Empty => abort("Map::split_max error") + #| } + #|} + #|fn[K, V] SortedMap::split_min( + #| self : SortedMap[K, V], + #|) -> (K, V, SortedMap[K, V]) { + #| match self { + #| Tree(k, value=v, Empty, r, ..) => (k, v, r) + #| Tree(k, value=v, l, r, ..) => { + #| let (k1, v1, l) = l.split_min() + #| (k1, v1, balance(k, v, l, r)) + #| } + #| Empty => abort("Map::split_min error") + #| } + #|} + #|fn[K, V] glue(l : SortedMap[K, V], r : SortedMap[K, V]) -> SortedMap[K, V] { + #| match (l, r) { + #| (Empty, r) => r + #| (l, Empty) => l + #| (l, r) => + #| if l.length() > r.length() { + #| let (k, v, l) = l.split_max() + #| balance(k, v, l, r) + #| } else { + #| let (k, v, r) = r.split_min() + #| balance(k, v, l, r) + #| } + #| } + #|} + #|pub fn[K : Compare, V] SortedMap::remove( + #| self : SortedMap[K, V], + #| key : K, + #|) -> SortedMap[K, V] { + #| match self { + #| Empty => Empty + #| Tree(k, value=v, l, r, ..) => { + #| let c = key.compare(k) + #| if c == 0 { + #| glue(l, r) + #| } else if c < 0 { + #| balance(k, v, l.remove(key), r) + #| } else { + #| balance(k, v, l, r.remove(key)) + #| } + #| } + #| } + #|} + #|pub fn[K, V] SortedMap::filter_with_key( + #| self : SortedMap[K, V], + #| pred : (K, V) -> Bool raise?, + #|) -> SortedMap[K, V] raise? { + #| match self { + #| Empty => Empty + #| Tree(k, value=v, l, r, ..) => + #| if pred(k, v) { + #| balance(k, v, l.filter_with_key(pred), r.filter_with_key(pred)) + #| } else { + #| glue(l.filter_with_key(pred), r.filter_with_key(pred)) + #| } + #| } + #|} + #|pub fn[K, V] SortedMap::to_array(self : SortedMap[K, V]) -> Array[(K, V)] { + #| let arr = [] + #| self.each((k, v) => arr.push((k, v))) + #| arr + #|} + #|pub fn[K : Compare, V] SortedMap::merge( + #| self : SortedMap[K, V], + #| other : SortedMap[K, V], + #|) -> SortedMap[K, V] { + #| match (self, other) { + #| (Empty, _) => other + #| (_, Empty) => self + #| (_, Tree(k2, value=v2, l2, r2, ..)) => { + #| let (l1, _, r1) = self.split(k2) + #| let merged_l = l1.merge(l2) + #| let merged_r = r1.merge(r2) + #| join(merged_l, k2, v2, merged_r) + #| } + #| } + #|} + #|fn[K : Compare, V] SortedMap::split( + #| self : SortedMap[K, V], + #| key : K, + #|) -> (SortedMap[K, V], V?, SortedMap[K, V]) { + #| match self { + #| Empty => (Empty, None, Empty) + #| Tree(k, value=v, l, r, ..) => { + #| let c = key.compare(k) + #| if c == 0 { + #| (l, Some(v), r) + #| } else if c < 0 { + #| let (ll, found, lr) = l.split(key) + #| (ll, found, join(lr, k, v, r)) + #| } else { + #| let (rl, found, rr) = r.split(key) + #| (join(l, k, v, rl), found, rr) + #| } + #| } + #| } + #|} + #|fn[K, V] join( + #| l : SortedMap[K, V], + #| k : K, + #| v : V, + #| r : SortedMap[K, V], + #|) -> SortedMap[K, V] { + #| match (l, r) { + #| (Empty, _) => balance(k, v, Empty, r) + #| (_, Empty) => balance(k, v, l, Empty) + #| (Tree(lk, value=lv, ll, lr, size=ls), Tree(rk, value=rv, rl, rr, size=rs)) => + #| if ls * ratio < rs { + #| balance(rk, rv, join(l, k, v, rl), rr) + #| } else if rs * ratio < ls { + #| balance(lk, lv, ll, join(lr, k, v, r)) + #| } else { + #| make_tree(k, v, l, r) + #| } + #| } + #|} + #|let ratio = 5 + #|fn[K, V] balance( + #| key : K, + #| value : V, + #| l : SortedMap[K, V], + #| r : SortedMap[K, V], + #|) -> SortedMap[K, V] { + #| fn single_l(k1, v1, x, r) { + #| guard r is Tree(k2, value=v2, y, z, ..) + #| make_tree(k2, v2, make_tree(k1, v1, x, y), z) + #| } + #| fn single_r(k2, v2, l, z) { + #| guard l is Tree(k1, value=v1, x, y, ..) + #| make_tree(k1, v1, x, make_tree(k2, v2, y, z)) + #| } + #| fn double_l(k1, v1, x, r) { + #| guard r is Tree(k3, value=v3, Tree(k2, value=v2, y1, y2, ..), z, ..) + #| make_tree(k2, v2, make_tree(k1, v1, x, y1), make_tree(k3, v3, y2, z)) + #| } + #| fn double_r(k3, v3, l, z) { + #| guard l is Tree(k1, value=v1, x, Tree(k2, value=v2, y1, y2, ..), ..) + #| make_tree(k2, v2, make_tree(k1, v1, x, y1), make_tree(k3, v3, y2, z)) + #| } + #| let ln = l.length() + #| let rn = r.length() + #| if ln + rn < 2 { + #| make_tree(key, value, l, r) + #| } else if rn > ratio * ln { + #| guard r is Tree(_, rl, rr, ..) + #| let rln = rl.length() + #| let rrn = rr.length() + #| if rln < rrn { + #| single_l(key, value, l, r) + #| } else { + #| double_l(key, value, l, r) + #| } + #| } else if ln > ratio * rn { + #| guard l is Tree(_, ll, lr, ..) + #| let lln = ll.length() + #| let lrn = lr.length() + #| if lrn < lln { + #| single_r(key, value, l, r) + #| } else { + #| double_r(key, value, l, r) + #| } + #| } else { + #| make_tree(key, value, l, r) + #| } + #|} + #|test "from_array" { + #| let m = from_array([ + #| (3, "three"), + #| (8, "eight"), + #| (1, "one"), + #| (2, "two"), + #| (0, "zero"), + #| ]) + #| inspect( + #| m.debug_tree(), + #| content="(3,three,(1,one,(0,zero,_,_),(2,two,_,_)),(8,eight,_,_))", + #| ) + #|} + #|test "insert" { + #| let m = from_array([(3, "three"), (8, "eight"), (1, "one")]) + #| inspect(m.debug_tree(), content="(3,three,(1,one,_,_),(8,eight,_,_))") + #| let m = m.add(5, "five").add(2, "two").add(0, "zero").add(1, "one_updated") + #| inspect( + #| m.debug_tree(), + #| content="(3,three,(1,one_updated,(0,zero,_,_),(2,two,_,_)),(8,eight,(5,five,_,_),_))", + #| ) + #|} + #|test "remove" { + #| let m1 = from_array([ + #| (3, "three"), + #| (8, "eight"), + #| (1, "one"), + #| (2, "two"), + #| (0, "zero"), + #| ]) + #| inspect( + #| m1.debug_tree(), + #| content="(3,three,(1,one,(0,zero,_,_),(2,two,_,_)),(8,eight,_,_))", + #| ) + #| let m2 = m1.remove(1).remove(3) + #| inspect(m2.debug_tree(), content="(2,two,(0,zero,_,_),(8,eight,_,_))") + #| let m3 = m1.remove(8) + #| inspect( + #| m3.debug_tree(), + #| content="(2,two,(1,one,(0,zero,_,_),_),(3,three,_,_))", + #| ) + #| let e : SortedMap[Int, Int] = Empty + #| inspect(e.remove(1).debug_tree(), content="_") + #|} + #|test "contains" { + #| let m = from_array([ + #| (3, "three"), + #| (8, "eight"), + #| (1, "one"), + #| (2, "two"), + #| (0, "zero"), + #| ]) + #| inspect( + #| m.debug_tree(), + #| content="(3,three,(1,one,(0,zero,_,_),(2,two,_,_)),(8,eight,_,_))", + #| ) + #| inspect(m.contains(8), content="true") + #| inspect(m.contains(2), content="true") + #| inspect(m.contains(4), content="false") + #|} + #|test "map" { + #| let m = from_array([ + #| (3, "three"), + #| (8, "eight"), + #| (1, "one"), + #| (2, "two"), + #| (0, "zero"), + #| ]) + #| let n = m.map_with_key((_, v) => v + "X") + #| assert_eq( + #| n.debug_tree(), + #| "(3,threeX,(1,oneX,(0,zeroX,_,_),(2,twoX,_,_)),(8,eightX,_,_))", + #| ) + #|} + #|test "map_with_key" { + #| let m = from_array([ + #| (3, "three"), + #| (8, "eight"), + #| (1, "one"), + #| (2, "two"), + #| (0, "zero"), + #| ]) + #| let n = m.map_with_key((k, v) => "\{k}-\{v}") + #| assert_eq( + #| n.debug_tree(), + #| "(3,3-three,(1,1-one,(0,0-zero,_,_),(2,2-two,_,_)),(8,8-eight,_,_))", + #| ) + #|} + #|test "filter" { + #| let m = from_array([ + #| (3, "three"), + #| (8, "eight"), + #| (1, "one"), + #| (2, "two"), + #| (0, "zero"), + #| ]) + #| let fm = m.filter_with_key((_, v) => v.length() > 3) + #| inspect(fm.debug_tree(), content="(3,three,(0,zero,_,_),(8,eight,_,_))") + #|} + #|test "filter_with_key" { + #| let m = from_array([ + #| (3, "three"), + #| (8, "eight"), + #| (1, "one"), + #| (2, "two"), + #| (0, "zero"), + #| ]) + #| let fm = m.filter_with_key((k, v) => k > 3 && v.length() > 3) + #| inspect(fm.debug_tree(), content="(8,eight,_,_)") + #|} + #|test "singleton" { + #| let m = singleton(3, "three") + #| inspect(m.debug_tree(), content="(3,three,_,_)") + #|} + #|test "empty" { + #| let m : SortedMap[Int, Int] = new() + #| inspect(m.debug_tree(), content="_") + #|} + #|test "split_max" { + #| let m = from_array([ + #| (3, "three"), + #| (8, "eight"), + #| (1, "one"), + #| (2, "two"), + #| (0, "zero"), + #| ]) + #| assert_eq( + #| m.debug_tree(), + #| "(3,three,(1,one,(0,zero,_,_),(2,two,_,_)),(8,eight,_,_))", + #| ) + #| let (k, v, r) = m.split_max() + #| inspect(k, content="8") + #| inspect(v, content="eight") + #| inspect( + #| r.debug_tree(), + #| content="(2,two,(1,one,(0,zero,_,_),_),(3,three,_,_))", + #| ) + #|} + #|test "split_min" { + #| let m = from_array([ + #| (3, "three"), + #| (8, "eight"), + #| (2, "two"), + #| (1, "one"), + #| (0, "zero"), + #| ]) + #| assert_eq( + #| m.debug_tree(), + #| "(3,three,(1,one,(0,zero,_,_),(2,two,_,_)),(8,eight,_,_))", + #| ) + #| let (k, v, r) = m.split_min() + #| inspect(k, content="0") + #| inspect(v, content="zero") + #| inspect( + #| r.debug_tree(), + #| content="(3,three,(1,one,_,(2,two,_,_)),(8,eight,_,_))", + #| ) + #|} + #|test "glue" { + #| let m = from_array([ + #| (3, "three"), + #| (8, "eight"), + #| (1, "one"), + #| (2, "two"), + #| (0, "zero"), + #| ]) + #| assert_eq( + #| m.debug_tree(), + #| "(3,three,(1,one,(0,zero,_,_),(2,two,_,_)),(8,eight,_,_))", + #| ) + #| let (l, r) = match m { + #| Tree(_, l, r, ..) => (l, r) + #| _ => abort("unreachable") + #| } + #| let m = glue(l, r) + #| inspect( + #| m.debug_tree(), + #| content="(2,two,(1,one,(0,zero,_,_),_),(8,eight,_,_))", + #| ) + #|} + #|test "split_max with non-empty tree" { + #| let m = from_array([ + #| (3, "three"), + #| (8, "eight"), + #| (1, "one"), + #| (2, "two"), + #| (0, "zero"), + #| ]) + #| let (k, v, r) = m.split_max() + #| inspect(k, content="8") + #| inspect(v, content="eight") + #| inspect( + #| r.debug_tree(), + #| content="(2,two,(1,one,(0,zero,_,_),_),(3,three,_,_))", + #| ) + #|} + ), + "traits_impl.mbt": ( + #|pub impl[K, V] Default for SortedMap[K, V] with default() { + #| new() + #|} + #|pub impl[K : Eq, V : Eq] Eq for SortedMap[K, V] with equal(self, other) -> Bool { + #| if physical_equal(self, other) { + #| return true + #| } + #| guard self.length() == other.length() else { return false } + #| let iter = self.iter() + #| let iter1 = other.iter() + #| while iter.next() is Some(a) && iter1.next() is Some(b) { + #| guard a == b else { break false } + #| } nobreak { + #| true + #| } + #|} + #|pub impl[K : Compare, V : Compare] Compare for SortedMap[K, V] with compare( + #| self, + #| other, + #|) -> Int { + #| guard self.length() == other.length() else { + #| return self.length() - other.length() + #| } + #| let iter = self.iter() + #| let iter1 = other.iter() + #| while iter.next() is Some(a) && iter1.next() is Some(b) { + #| let cmp = a.compare(b) + #| guard cmp is 0 else { break cmp } + #| } nobreak { + #| 0 + #| } + #|} + #|pub impl[K : @quickcheck.Arbitrary + Compare, V : @quickcheck.Arbitrary] @quickcheck.Arbitrary for SortedMap[ + #| K, + #| V, + #|] with arbitrary(size, rs) { + #| @quickcheck.Arbitrary::arbitrary(size, rs) |> from_array + #|} + #|pub impl[K : Hash, V : Hash] Hash for SortedMap[K, V] with hash_combine( + #| self, + #| hasher, + #|) { + #| for e in self { + #| hasher.combine(e.0) + #| hasher.combine(e.1) + #| } + #|} + #|pub impl[K : Show, V : Show] Show for SortedMap[K, V] with output(self, logger) { + #| logger.write_iter( + #| self.iter(), + #| prefix="@immut/sorted_map.from_array([", + #| suffix="])", + #| ) + #|} + #|pub impl[K : Show, V : ToJson] ToJson for SortedMap[K, V] with to_json(self) { + #| let capacity = self.length() + #| guard capacity != 0 else { return Json::object(Map::new()) } + #| let jsons = Map::new(capacity~) + #| self.each((k, v) => jsons[k.to_string()] = v.to_json()) + #| Json::object(jsons) + #|} + #|pub impl[V : @json.FromJson] @json.FromJson for SortedMap[String, V] with from_json( + #| json, + #| path, + #|) { + #| guard json is Object(obj) else { + #| raise @json.JsonDecodeError( + #| (path, "@immut/sorted_map.from_json: expected object"), + #| ) + #| } + #| for k, v in obj; map = (new() : SortedMap[String, V]) { + #| continue map.add(k, V::from_json(v, path.add_key(k))) + #| } nobreak { + #| map + #| } + #|} + #|#as_free_fn + #|pub fn[V : @json.FromJson] SortedMap::from_json( + #| json : Json, + #|) -> SortedMap[String, V] raise @json.JsonDecodeError { + #| @json.from_json(json) + #|} + ), + "types.mbt": ( + #|#alias(T, deprecated) + #|enum SortedMap[K, V] { + #| Empty + #| Tree(K, value~ : V, size~ : Int, SortedMap[K, V], SortedMap[K, V]) + #|} + ), + "utils.mbt": ( + #|#as_free_fn + #|#alias(empty, deprecated) + #|pub fn[K, V] SortedMap::new() -> SortedMap[K, V] { + #| Empty + #|} + #|#as_free_fn + #|pub fn[K, V] SortedMap::singleton(key : K, value : V) -> SortedMap[K, V] { + #| Tree(key, value~, size=1, Empty, Empty) + #|} + #|pub fn[K : Compare, V] SortedMap::contains( + #| self : SortedMap[K, V], + #| key : K, + #|) -> Bool { + #| loop self { + #| Empty => false + #| Tree(k, l, r, ..) => { + #| let c = key.compare(k) + #| if c == 0 { + #| true + #| } else if c < 0 { + #| continue l + #| } else { + #| continue r + #| } + #| } + #| } + #|} + #|#alias(size, deprecated) + #|pub fn[K, V] SortedMap::length(self : SortedMap[K, V]) -> Int { + #| match self { + #| Empty => 0 + #| Tree(_) as t => t.size + #| } + #|} + #|pub fn[K, V] SortedMap::is_empty(self : SortedMap[K, V]) -> Bool { + #| self.length() == 0 + #|} + #|fn[K, V] make_tree( + #| key : K, + #| value : V, + #| l : SortedMap[K, V], + #| r : SortedMap[K, V], + #|) -> SortedMap[K, V] { + #| let size = l.length() + r.length() + 1 + #| Tree(key, value~, size~, l, r) + #|} + #|#alias(lookup, deprecated) + #|pub fn[K : Compare, V] SortedMap::get(self : SortedMap[K, V], key : K) -> V? { + #| loop self { + #| Empty => None + #| Tree(k, value~, l, r, ..) => { + #| let c = key.compare(k) + #| if c == 0 { + #| Some(value) + #| } else if c < 0 { + #| continue l + #| } else { + #| continue r + #| } + #| } + #| } + #|} + #|#alias("_[_]") + #|pub fn[K : Compare, V] SortedMap::at(self : SortedMap[K, V], key : K) -> V { + #| loop self { + #| Empty => panic() + #| Tree(k, value~, l, r, ..) => { + #| let c = key.compare(k) + #| if c == 0 { + #| value + #| } else if c < 0 { + #| continue l + #| } else { + #| continue r + #| } + #| } + #| } + #|} + #|pub fn[K, V] SortedMap::each( + #| self : SortedMap[K, V], + #| f : (K, V) -> Unit, + #|) -> Unit { + #| match self { + #| Empty => () + #| Tree(k, value~, l, r, ..) => { + #| l.each(f) + #| f(k, value) + #| r.each(f) + #| } + #| } + #|} + #|pub fn[K, V] SortedMap::eachi( + #| self : SortedMap[K, V], + #| f : (Int, K, V) -> Unit, + #|) -> Unit { + #| fn do_eachi(m : SortedMap[K, V], f, i) { + #| match m { + #| Empty => () + #| Tree(k, value~, l, r, ..) => { + #| do_eachi(l, f, i) + #| f(l.length() + i, k, value) + #| do_eachi(r, f, l.length() + i + 1) + #| } + #| } + #| } + #| do_eachi(self, f, 0) + #|} + #|pub fn[K, X, Y] SortedMap::map_with_key( + #| self : SortedMap[K, X], + #| f : (K, X) -> Y, + #|) -> SortedMap[K, Y] { + #| match self { + #| Empty => Empty + #| Tree(k, value~, l, r, size~) => + #| Tree(k, value=f(k, value), size~, l.map_with_key(f), r.map_with_key(f)) + #| } + #|} + #|#alias(foldr_with_key) + #|pub fn[K, V, A] SortedMap::rev_fold( + #| self : SortedMap[K, V], + #| f : (A, K, V) -> A, + #| init~ : A, + #|) -> A { + #| fn go(m : SortedMap[K, V], acc) { + #| match m { + #| Empty => acc + #| Tree(k, value~, l, r, ..) => go(l, f(go(r, acc), k, value)) + #| } + #| } + #| go(self, init) + #|} + #|pub fn[K, V, A] SortedMap::foldl_with_key( + #| self : SortedMap[K, V], + #| f : (A, K, V) -> A, + #| init~ : A, + #|) -> A { + #| fn go(m : SortedMap[K, V], acc) { + #| match m { + #| Empty => acc + #| Tree(k, value~, l, r, ..) => go(r, f(go(l, acc), k, value)) + #| } + #| } + #| go(self, init) + #|} + #|fn[K : Show, V : Show] SortedMap::debug_tree(self : SortedMap[K, V]) -> String { + #| match self { + #| Empty => "_" + #| Tree(k, value~, l, r, ..) => { + #| let l = l.debug_tree() + #| let r = r.debug_tree() + #| "(\{k},\{value},\{l},\{r})" + #| } + #| } + #|} + #|#as_free_fn + #|#alias(of, deprecated="Use from_array instead") + #|#as_free_fn(of, deprecated="Use from_array instead") + #|pub fn[K : Compare, V] SortedMap::from_array( + #| array : ArrayView[(K, V)], + #|) -> SortedMap[K, V] { + #| for i = 0, mp = Empty; i < array.length(); { + #| let (k, v) = array[i] + #| continue i + 1, mp.add(k, v) + #| } nobreak { + #| mp + #| } + #|} + #|#alias(iterator, deprecated) + #|pub fn[K, V] SortedMap::iter(self : SortedMap[K, V]) -> Iter[(K, V)] { + #| let mut curr_node = self + #| let parents = [] + #| Iter::new(fn() { + #| loop curr_node { + #| Tree(k, value~, Empty, r, ..) => { + #| curr_node = r + #| Some((k, value)) + #| } + #| Tree(k, value~, l, r, ..) => { + #| parents.push((k, value, r)) + #| continue l + #| } + #| Empty if parents.pop() is Some((k, v, r)) => { + #| curr_node = r + #| Some((k, v)) + #| } + #| Empty => None + #| } + #| }) + #|} + #|#alias(iterator2, deprecated) + #|pub fn[K, V] SortedMap::iter2(self : SortedMap[K, V]) -> Iter2[K, V] { + #| self.iter() + #|} + #|pub fn[K : Compare, V] SortedMap::range( + #| self : SortedMap[K, V], + #| low~ : K, + #| high~ : K, + #|) -> Iter2[K, V] { + #| let todo_list = [] + #| let mut next_node = self + #| Iter2::new(fn() { + #| loop next_node { + #| Tree(k, value~, l, r, ..) => { + #| let cmp_key_low = k.compare(low) + #| let cmp_key_high = k.compare(high) + #| if cmp_key_low < 0 { + #| continue r + #| } else if cmp_key_high > 0 { + #| continue l + #| } else if l is Empty { + #| next_node = r + #| Some((k, value)) + #| } else { + #| todo_list.push((k, value, r)) + #| continue l + #| } + #| } + #| Empty if todo_list.pop() is Some((k, value, r)) => { + #| next_node = r + #| Some((k, value)) + #| } + #| Empty => None + #| } + #| }) + #|} + #|#as_free_fn + #|#alias(from_iterator, deprecated) + #|#as_free_fn(from_iterator, deprecated) + #|pub fn[K : Compare, V] SortedMap::from_iter( + #| iter : Iter[(K, V)], + #|) -> SortedMap[K, V] { + #| iter.fold(init=new(), (m, e) => m.add(e.0, e.1)) + #|} + #|pub fn[K, V] SortedMap::keys_as_iter(self : SortedMap[K, V]) -> Iter[K] { + #| self.iter().map(p => p.0) + #|} + #|pub fn[K, V] SortedMap::values(self : SortedMap[K, V]) -> Iter[V] { + #| self.iter().map(p => p.1) + #|} + #|pub fn[K, V] SortedMap::rev_keys(self : SortedMap[K, V]) -> Iter[K] { + #| let mut curr_node = self + #| let parents = [] + #| Iter::new(fn() { + #| loop curr_node { + #| Tree(k, l, Empty, ..) => { + #| curr_node = l + #| Some(k) + #| } + #| Tree(k, l, r, ..) => { + #| parents.push((k, l)) + #| continue r + #| } + #| Empty if parents.pop() is Some((k, l)) => { + #| curr_node = l + #| Some(k) + #| } + #| Empty => None + #| } + #| }) + #|} + #|pub fn[K, V] SortedMap::rev_values(self : SortedMap[K, V]) -> Iter[V] { + #| let mut curr_node = self + #| let parents = [] + #| Iter::new(fn() { + #| loop curr_node { + #| Tree(_k, value~, l, Empty, ..) => { + #| curr_node = l + #| Some(value) + #| } + #| Tree(_k, value~, l, r, ..) => { + #| parents.push((value, l)) + #| continue r + #| } + #| Empty if parents.pop() is Some((v, l)) => { + #| curr_node = l + #| Some(v) + #| } + #| Empty => None + #| } + #| }) + #|} + #|pub fn[K : Show, V : ToJson] SortedMap::to_json(self : SortedMap[K, V]) -> Json { + #| ToJson::to_json(self) + #|} + ) + } ) ///| let moonbitlang_core_immut_sorted_set_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/immut/sorted_set", - deps={ - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/array": moonbitlang_core_array_module, - "moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module, - "moonbitlang/core/json": moonbitlang_core_json_module, - }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| "moonbitlang/core/builtin", - #| "moonbitlang/core/array", - #| "moonbitlang/core/quickcheck", - #| "moonbitlang/core/json" - #| ], - #| "targets": { - #| "panic_test.mbt": ["not", "native", "llvm"] - #| } - #|} - ), - "deprecated.mbt": "", - "generic.mbt": ( - #|pub fn[A] SortedSet::iter(self : SortedSet[A]) -> Iter[A] { - #| self.iterator().iter() - #|} - #|pub fn[A] SortedSet::iterator(self : SortedSet[A]) -> Iterator[A] { - #| let mut curr_node = self - #| let parents = [] - #| Iterator::new(fn() { - #| loop curr_node { - #| Node(left=Empty, right~, value~, size=_) => { - #| curr_node = right - #| Some(value) - #| } - #| Node(left~, right~, value~, size=_) => { - #| parents.push((value, right)) - #| continue left - #| } - #| Empty if parents.pop() is Some((value, right)) => { - #| curr_node = right - #| Some(value) - #| } - #| Empty => None - #| } - #| }) - #|} - #|#as_free_fn - #|pub fn[A : Compare] SortedSet::from_iter(iter : Iter[A]) -> SortedSet[A] { - #| iter.fold(init=new(), (s, e) => s.add(e)) - #|} - #|#as_free_fn - #|pub fn[A : Compare] SortedSet::from_iterator( - #| iter : Iterator[A], - #|) -> SortedSet[A] { - #| iter.fold(init=new(), (s, e) => s.add(e)) - #|} - #|test { - #| @json.inspect(from_array([2, 7, 1, 2, 3, 4, 5]), content=[1, 2, 3, 4, 5, 7]) - #|} - #|pub impl[A : Eq] Eq for SortedSet[A] with equal(self, other) -> Bool { - #| guard self.length() == other.length() else { return false } - #| let iter = self.iterator() - #| let iter1 = other.iterator() - #| while iter.next() is Some(a) && iter1.next() is Some(b) { - #| guard a == b else { break false } - #| } else { - #| true - #| } - #|} - #|pub impl[A : Compare] Compare for SortedSet[A] with compare(self, other) -> Int { - #| let my_size = self.length() - #| let other_size = other.length() - #| guard my_size == other_size else { return my_size - other_size } - #| let iter = self.iterator() - #| let iter1 = other.iterator() - #| while iter.next() is Some(a) && iter1.next() is Some(b) { - #| let cmp = a.compare(b) - #| guard cmp is 0 else { break cmp } - #| } else { - #| 0 - #| } - #|} - #|test "Eq - equal sets" { - #| let s1 = from_array([1, 2, 3, 4, 5]) - #| let s2 = from_array([5, 4, 3, 2, 1]) - #| inspect(s1 == s2, content="true") - #|} - #|test "Eq - different elements same size" { - #| let s1 = from_array([1, 2, 3, 4, 5]) - #| let s2 = from_array([1, 2, 3, 4, 6]) - #| inspect(s1 == s2, content="false") - #|} - #|test "Eq - different sizes" { - #| let s1 = from_array([1, 2, 3]) - #| let s2 = from_array([1, 2, 3, 4, 5]) - #| inspect(s1 == s2, content="false") - #|} - #|test "Eq - empty sets" { - #| let s1 : SortedSet[Int] = new() - #| let s2 : SortedSet[Int] = new() - #| inspect(s1 == s2, content="true") - #|} - #|test "Eq - one empty one not" { - #| let s1 : SortedSet[Int] = new() - #| let s2 = from_array([1]) - #| inspect(s1 == s2, content="false") - #|} - #|test "Compare - equal sets" { - #| let s1 = from_array([1, 2, 3]) - #| let s2 = from_array([3, 2, 1]) - #| inspect(s1.compare(s2), content="0") - #|} - #|test "Compare - first smaller by size" { - #| let s1 = from_array([1, 2]) - #| let s2 = from_array([1, 2, 3]) - #| inspect(s1.compare(s2) < 0, content="true") - #|} - #|test "Compare - first larger by size" { - #| let s1 = from_array([1, 2, 3, 4]) - #| let s2 = from_array([1, 2]) - #| inspect(s1.compare(s2) > 0, content="true") - #|} - #|test "Compare - same size first smaller by elements" { - #| let s1 = from_array([1, 2, 3]) - #| let s2 = from_array([1, 2, 4]) - #| inspect(s1.compare(s2) < 0, content="true") - #|} - #|test "Compare - same size first larger by elements" { - #| let s1 = from_array([1, 2, 5]) - #| let s2 = from_array([1, 2, 4]) - #| inspect(s1.compare(s2) > 0, content="true") - #|} - #|test "Compare - empty sets" { - #| let s1 : SortedSet[Int] = new() - #| let s2 : SortedSet[Int] = new() - #| inspect(s1.compare(s2), content="0") - #|} - ), - "immutable_set.mbt": ( - #|#as_free_fn - #|pub fn[A] SortedSet::new() -> SortedSet[A] { - #| Empty - #|} - #|pub impl[A] Default for SortedSet[A] with default() { - #| Empty - #|} - #|#as_free_fn - #|pub fn[A] SortedSet::singleton(value : A) -> SortedSet[A] { - #| Node(left=Empty, value~, right=Empty, size=1) - #|} - #|#as_free_fn - #|#alias(of, deprecated="Use from_array instead") - #|#as_free_fn(of, deprecated="Use from_array instead") - #|pub fn[A : Compare] SortedSet::from_array(array : ArrayView[A]) -> SortedSet[A] { - #| for i = array.length() - 1, set = Empty; i >= 0; { - #| continue i - 1, set.add(array[i]) - #| } else { - #| set - #| } - #|} - #|pub fn[A] SortedSet::to_array(self : SortedSet[A]) -> Array[A] { - #| let arr = [] - #| fn aux(set : SortedSet[A]) { - #| match set { - #| Empty => () - #| Node(left~, value~, right~, ..) => { - #| aux(left) - #| arr.push(value) - #| aux(right) - #| } - #| } - #| } - #| aux(self) - #| arr - #|} - #|pub fn[A] SortedSet::remove_min(self : SortedSet[A]) -> SortedSet[A] { - #| match self { - #| Empty => abort("remove_min: empty ImmutableSet") - #| Node(left~, right~, value~, ..) => - #| if left is Empty { - #| right - #| } else { - #| balance(left.remove_min(), value, right) - #| } - #| } - #|} - #|pub fn[A : Compare] SortedSet::add( - #| self : SortedSet[A], - #| value : A, - #|) -> SortedSet[A] { - #| match self { - #| Empty => Node(left=Empty, value~, right=Empty, size=1) - #| Node(left~, right~, value=node_value, ..) => { - #| let compare_result = value.compare(node_value) - #| if compare_result == 0 { - #| self - #| } else if compare_result < 0 { - #| let ll = left.add(value) - #| if physical_equal(left, ll) { - #| self - #| } else { - #| balance(ll, node_value, right) - #| } - #| } else { - #| let rr = right.add(value) - #| if physical_equal(right, rr) { - #| self - #| } else { - #| balance(left, node_value, rr) - #| } - #| } - #| } - #| } - #|} - #|pub fn[A : Compare] SortedSet::remove( - #| self : SortedSet[A], - #| value : A, - #|) -> SortedSet[A] { - #| match self { - #| Empty => Empty - #| Node(left~, right~, value=node_value, ..) => { - #| let compare_result = value.compare(node_value) - #| if compare_result == 0 { - #| left.merge(right) - #| } else if compare_result < 0 { - #| let new_left = left.remove(value) - #| if physical_equal(left, new_left) { - #| self - #| } else { - #| balance(new_left, node_value, right) - #| } - #| } else { - #| let new_right = right.remove(value) - #| if physical_equal(right, new_right) { - #| self - #| } else { - #| balance(left, node_value, new_right) - #| } - #| } - #| } - #| } - #|} - #|pub fn[A] SortedSet::min(self : SortedSet[A]) -> A { - #| match self { - #| Empty => abort("min: there are no values in sorted_set.") - #| Node(left~, value~, ..) => if left is Empty { value } else { left.min() } - #| } - #|} - #|pub fn[A] SortedSet::min_option(self : SortedSet[A]) -> A? { - #| match self { - #| Empty => None - #| Node(left~, value~, ..) => - #| if left is Empty { - #| Some(value) - #| } else { - #| left.min_option() - #| } - #| } - #|} - #|pub fn[A] SortedSet::max(self : SortedSet[A]) -> A { - #| match self { - #| Empty => abort("max: there are no values in ImmutableSet.") - #| Node(right~, value~, ..) => if right is Empty { value } else { right.max() } - #| } - #|} - #|pub fn[A] SortedSet::max_option(self : SortedSet[A]) -> A? { - #| match self { - #| Empty => None - #| Node(right~, value~, ..) => - #| if right is Empty { - #| Some(value) - #| } else { - #| right.max_option() - #| } - #| } - #|} - #|pub fn[A : Compare] SortedSet::split( - #| self : SortedSet[A], - #| divide : A, - #|) -> (SortedSet[A], Bool, SortedSet[A]) { - #| match self { - #| Empty => (Empty, false, Empty) - #| Node(left~, right~, value~, ..) => { - #| let compare_result = divide.compare(value) - #| if compare_result == 0 { - #| (left, true, right) - #| } else if compare_result < 0 { - #| let (left_left, present, right_left) = left.split(divide) - #| (left_left, present, join(right_left, value, right)) - #| } else { - #| let (left_right, present, right_right) = right.split(divide) - #| (join(left, value, left_right), present, right_right) - #| } - #| } - #| } - #|} - #|pub fn[A] SortedSet::is_empty(self : SortedSet[A]) -> Bool { - #| self is Empty - #|} - #|pub fn[A : Compare] SortedSet::contains(self : SortedSet[A], value : A) -> Bool { - #| match self { - #| Empty => false - #| Node(left~, right~, value=node_value, ..) => { - #| let compare_result = value.compare(node_value) - #| compare_result == 0 || - #| (if compare_result < 0 { left } else { right }).contains(value) - #| } - #| } - #|} - #|pub fn[A : Compare] SortedSet::union( - #| self : SortedSet[A], - #| other : SortedSet[A], - #|) -> SortedSet[A] { - #| match (self, other) { - #| (Empty, _) => other - #| (_, Empty) => self - #| ( - #| Node(left=l1, value=v1, right=r1, size=s1), - #| Node(left=l2, value=v2, right=r2, size=s2), - #| ) => - #| if s1 >= s2 { - #| if s2 == 1 { - #| self.add(v2) - #| } else { - #| let (l2, _, r2) = other.split(v1) - #| join(l1.union(l2), v1, r1.union(r2)) - #| } - #| } else if s1 == 1 { - #| other.add(v1) - #| } else { - #| let (l1, _, r1) = self.split(v2) - #| join(l1.union(l2), v2, r1.union(r2)) - #| } - #| } - #|} - #|pub impl[A : Compare] Add for SortedSet[A] with add(self, other) { - #| return self.union(other) - #|} - #|#alias(inter, deprecated) - #|pub fn[A : Compare] SortedSet::intersection( - #| self : SortedSet[A], - #| other : SortedSet[A], - #|) -> SortedSet[A] { - #| match (self, other) { - #| (Empty, _) | (_, Empty) => Empty - #| (Node(left=l1, value=v1, right=r1, ..), _) => - #| match other.split(v1) { - #| (l2, false, r2) => l1.intersection(l2).concat(r1.intersection(r2)) - #| (l2, true, r2) => join(l1.intersection(l2), v1, r1.intersection(r2)) - #| } - #| } - #|} - #|#alias(diff, deprecated) - #|pub fn[A : Compare] SortedSet::difference( - #| self : SortedSet[A], - #| other : SortedSet[A], - #|) -> SortedSet[A] { - #| match (self, other) { - #| (Empty, _) => Empty - #| (_, Empty) => self - #| (Node(left=l1, value=v1, right=r1, ..), _) => - #| match other.split(v1) { - #| (l2, false, r2) => join(l1.difference(l2), v1, r1.difference(r2)) - #| (l2, true, r2) => l1.difference(l2).concat(r1.difference(r2)) - #| } - #| } - #|} - #|pub fn[A : Compare] SortedSet::symmetric_difference( - #| self : SortedSet[A], - #| other : SortedSet[A], - #|) -> SortedSet[A] { - #| match (self, other) { - #| (Empty, _) => other - #| (_, Empty) => self - #| (Node(left=l1, value=v1, right=r1, ..), _) => - #| match other.split(v1) { - #| (l2, false, r2) => - #| join(l1.symmetric_difference(l2), v1, r1.symmetric_difference(r2)) - #| (l2, true, r2) => - #| l1.symmetric_difference(l2).concat(r1.symmetric_difference(r2)) - #| } - #| } - #|} - #|pub fn[A : Compare] SortedSet::subset( - #| self : SortedSet[A], - #| other : SortedSet[A], - #|) -> Bool { - #| match (self, other) { - #| (Empty, _) => true - #| (_, Empty) => false - #| ( - #| Node(left=l1, value=v1, right=r1, ..), - #| Node(left=l2, value=v2, right=r2, ..), - #| ) => { - #| let compare_result = v1.compare(v2) - #| if compare_result == 0 { - #| l1.subset(l2) && r1.subset(r2) - #| } else if compare_result < 0 { - #| Node(left=l1, value=v1, right=Empty, size=1).subset(l2) && - #| r1.subset(self) - #| } else { - #| Node(left=Empty, value=v1, right=r1, size=1).subset(r2) && - #| l1.subset(self) - #| } - #| } - #| } - #|} - #|pub fn[A : Compare] SortedSet::disjoint( - #| self : SortedSet[A], - #| other : SortedSet[A], - #|) -> Bool { - #| match (self, other) { - #| (Empty, _) | (_, Empty) => true - #| (Node(left=l1, value=v1, right=r1, ..), _) => - #| if physical_equal(self, other) { - #| false - #| } else { - #| match other.split_bis(v1) { - #| NotFound(l2, r2) => l1.disjoint(l2) && r1.disjoint(r2()) - #| Found => false - #| } - #| } - #| } - #|} - #|pub fn[A] SortedSet::each( - #| self : SortedSet[A], - #| f : (A) -> Unit raise?, - #|) -> Unit raise? { - #| match self { - #| Empty => () - #| Node(left~, value~, right~, ..) => { - #| left.each(f) - #| f(value) - #| right.each(f) - #| } - #| } - #|} - #|pub fn[A, B] SortedSet::fold( - #| self : SortedSet[A], - #| init~ : B, - #| f : (B, A) -> B raise?, - #|) -> B raise? { - #| match self { - #| Empty => init - #| Node(left~, value~, right~, ..) => - #| right.fold(init=f(left.fold(init~, f), value), f) - #| } - #|} - #|pub fn[A, B : Compare] SortedSet::map( - #| self : SortedSet[A], - #| f : (A) -> B raise?, - #|) -> SortedSet[B] raise? { - #| match self { - #| Empty => Empty - #| Node(left~, value~, right~, ..) => - #| try_join(left.map(f), f(value), right.map(f)) - #| } - #|} - #|pub fn[A] SortedSet::all( - #| self : SortedSet[A], - #| f : (A) -> Bool raise?, - #|) -> Bool raise? { - #| match self { - #| Empty => true - #| Node(left~, value~, right~, ..) => f(value) && left.all(f) && right.all(f) - #| } - #|} - #|pub fn[A] SortedSet::any( - #| self : SortedSet[A], - #| f : (A) -> Bool raise?, - #|) -> Bool raise? { - #| match self { - #| Empty => false - #| Node(left~, value~, right~, ..) => f(value) || left.any(f) || right.any(f) - #| } - #|} - #|pub fn[A] SortedSet::filter( - #| self : SortedSet[A], - #| f : (A) -> Bool raise?, - #|) -> SortedSet[A] raise? { - #| match self { - #| Empty => Empty - #| Node(left~, value~, right~, ..) => { - #| let l = left.filter(f) - #| let v = f(value) - #| let r = right.filter(f) - #| if v { - #| if physical_equal(l, left) && physical_equal(r, right) { - #| self - #| } else { - #| join(l, value, r) - #| } - #| } else { - #| l.concat(r) - #| } - #| } - #| } - #|} - #|pub impl[A : Show] Show for SortedSet[A] with output(self, logger) { - #| logger.write_iter( - #| self.iter(), - #| prefix="@immut/sorted_set.from_array([", - #| suffix="])", - #| ) - #|} - #|pub impl[A : ToJson] ToJson for SortedSet[A] with to_json(self) { - #| let capacity = self.iter().count() - #| guard capacity != 0 else { return Json::array([]) } - #| let jsons = Array::new(capacity~) - #| self.each(a => jsons.push(a.to_json())) - #| Json::array(jsons) - #|} - #|pub fn[A : ToJson] SortedSet::to_json(self : SortedSet[A]) -> Json { - #| ToJson::to_json(self) - #|} - #|pub impl[A : @json.FromJson + Compare] @json.FromJson for SortedSet[A] with from_json( - #| json, - #| path, - #|) { - #| guard json is Array(arr) else { - #| raise @json.JsonDecodeError( - #| (path, "@immut/sorted_set.from_json: expected array"), - #| ) - #| } - #| let mut set = new() - #| for i, x in arr { - #| set = set.add(A::from_json(x, path.add_index(i))) - #| } - #| set - #|} - #|#as_free_fn - #|pub fn[A : @json.FromJson + Compare] SortedSet::from_json( - #| json : Json, - #|) -> SortedSet[A] raise @json.JsonDecodeError { - #| @json.from_json(json) - #|} - #|pub impl[X : @quickcheck.Arbitrary + Compare] @quickcheck.Arbitrary for SortedSet[ - #| X, - #|] with arbitrary(size, rs) { - #| @quickcheck.Arbitrary::arbitrary(size, rs) |> from_array - #|} - #|const BALANCE_RATIO = 5 - #|priv enum SplitBis[A] { - #| Found - #| NotFound(SortedSet[A], () -> SortedSet[A]) - #|} - #|impl[T] Show for SplitBis[T] with output(self, logger) { - #| match self { - #| Found => logger.write_string("Found") - #| NotFound(_) => logger.write_string("NotFound") - #| } - #|} - #|fn[A : Compare] SortedSet::split_bis( - #| self : SortedSet[A], - #| value : A, - #|) -> SplitBis[A] { - #| match self { - #| Empty => NotFound(Empty, () => Empty) - #| Node(left~, value=node_value, right~, ..) => { - #| let compare_result = value.compare(node_value) - #| if compare_result == 0 { - #| Found - #| } else if compare_result < 0 { - #| match left.split_bis(value) { - #| Found => Found - #| NotFound(ll, rl) => NotFound(ll, () => join(rl(), node_value, right)) - #| } - #| } else { - #| match right.split_bis(value) { - #| Found => Found - #| NotFound(lr, rr) => NotFound(join(left, node_value, lr), rr) - #| } - #| } - #| } - #| } - #|} - #|#alias(size, deprecated) - #|pub fn[A] SortedSet::length(self : SortedSet[A]) -> Int { - #| match self { - #| Empty => 0 - #| Node(size~, ..) => size - #| } - #|} - #|fn[A] create( - #| left : SortedSet[A], - #| value : A, - #| right : SortedSet[A], - #|) -> SortedSet[A] { - #| Node(left~, right~, value~, size=left.length() + right.length() + 1) - #|} - #|fn[A] balance( - #| left : SortedSet[A], - #| value : A, - #| right : SortedSet[A], - #|) -> SortedSet[A] { - #| let left_size = left.length() - #| let right_size = right.length() - #| if left_size + right_size < 2 { - #| create(left, value, right) - #| } else if left_size > right_size * BALANCE_RATIO { - #| match left { - #| Empty => abort("balance: left is empty.") - #| Node(left=ll, value=lv, right=lr, ..) => - #| if ll.length() >= lr.length() { - #| create(ll, lv, create(lr, value, right)) - #| } else { - #| match lr { - #| Empty => abort("balance: right left.right is empty.") - #| Node(left=lrl, value=lrv, right=lrr, ..) => - #| create(create(ll, lv, lrl), lrv, create(lrr, value, right)) - #| } - #| } - #| } - #| } else if right_size > left_size * BALANCE_RATIO { - #| match right { - #| Empty => abort("balance: right is empty") - #| Node(left=rl, value=rv, right=rr, ..) => - #| if rr.length() >= rl.length() { - #| create(create(left, value, rl), rv, rr) - #| } else { - #| match rl { - #| Empty => abort("balance: right.left is empty") - #| Node(left=rll, value=rlv, right=rlr, ..) => - #| create(create(left, value, rll), rlv, create(rlr, rv, rr)) - #| } - #| } - #| } - #| } else { - #| create(left, value, right) - #| } - #|} - #|fn[A] SortedSet::add_min_value(self : SortedSet[A], value : A) -> SortedSet[A] { - #| match self { - #| Empty => singleton(value) - #| Node(left~, value=node_value, right~, ..) => - #| balance(left.add_min_value(value), node_value, right) - #| } - #|} - #|fn[A] SortedSet::add_max_value(self : SortedSet[A], value : A) -> SortedSet[A] { - #| match self { - #| Empty => singleton(value) - #| Node(left~, value=node_value, right~, ..) => - #| balance(left, node_value, right.add_max_value(value)) - #| } - #|} - #|fn[A] join( - #| left : SortedSet[A], - #| value : A, - #| right : SortedSet[A], - #|) -> SortedSet[A] { - #| match (left, right) { - #| (Empty, _) => right.add_min_value(value) - #| (_, Empty) => left.add_max_value(value) - #| ( - #| Node(left=ll, value=lv, right=lr, size=ls), - #| Node(left=rl, value=rv, right=rr, size=rs), - #| ) => - #| if ls > rs * BALANCE_RATIO { - #| balance(ll, lv, join(lr, value, right)) - #| } else if rs > ls * BALANCE_RATIO { - #| balance(join(left, value, rl), rv, rr) - #| } else { - #| create(left, value, right) - #| } - #| } - #|} - #|fn[A : Compare] try_join( - #| left : SortedSet[A], - #| value : A, - #| right : SortedSet[A], - #|) -> SortedSet[A] { - #| if (left == Empty || left.max().compare(value) < 0) && - #| (right == Empty || value.compare(right.min()) < 0) { - #| join(left, value, right) - #| } else { - #| left.union(right.add(value)) - #| } - #|} - #|fn[A] SortedSet::merge( - #| self : SortedSet[A], - #| other : SortedSet[A], - #|) -> SortedSet[A] { - #| match (self, other) { - #| (Empty, _) => other - #| (_, Empty) => self - #| _ => balance(self, other.min(), other.remove_min()) - #| } - #|} - #|fn[A] SortedSet::concat( - #| self : SortedSet[A], - #| other : SortedSet[A], - #|) -> SortedSet[A] { - #| match (self, other) { - #| (Empty, _) => other - #| (_, Empty) => self - #| _ => join(self, other.min(), other.remove_min()) - #| } - #|} - #|pub impl[A : Hash] Hash for SortedSet[A] with hash_combine(self, hasher) { - #| for t in self { - #| t.hash_combine(hasher) - #| } - #|} - #|test "split_bis" { - #| inspect(from_array([1, 2, 3]).split_bis(1), content="Found") - #| inspect(from_array([1, 2, 3]).split_bis(3), content="Found") - #| inspect(from_array([1, 2, 3]).split_bis(0), content="NotFound") - #| inspect(from_array([1, 2, 3]).split_bis(4), content="NotFound") - #|} - #|test "balance with left height greater" { - #| let left = from_array([1, 2, 3]) - #| let value = 4 - #| let right = from_array([5]) - #| let balanced_set = balance(left, value, right) - #| inspect(balanced_set, content="@immut/sorted_set.from_array([1, 2, 3, 4, 5])") - #|} - #|test "balance with right height greater" { - #| let left = from_array([1]) - #| let value = 2 - #| let right = from_array([3, 4, 5]) - #| let balanced_set = balance(left, value, right) - #| inspect(balanced_set, content="@immut/sorted_set.from_array([1, 2, 3, 4, 5])") - #|} - #|test "join with different heights" { - #| let left = from_array([1, 2, 3]) - #| let value = 4 - #| let right = from_array([5, 6, 7]) - #| let joined_set = join(left, value, right) - #| inspect( - #| joined_set, - #| content="@immut/sorted_set.from_array([1, 2, 3, 4, 5, 6, 7])", - #| ) - #|} - #|test "hash" { - #| assert_eq( - #| Hash::hash(from_array([1, 2, 3, 4])), - #| Hash::hash(from_array([3, 2]).add(1).add(4)), - #| ) - #| assert_not_eq( - #| Hash::hash(from_array([1, 2, 3])), - #| Hash::hash(from_array([1, 2, 4])), - #| ) - #|} - ), - "types.mbt": ( - #|#alias(T, deprecated) - #|enum SortedSet[A] { - #| Empty - #| Node(left~ : SortedSet[A], right~ : SortedSet[A], size~ : Int, value~ : A) - #|} - ), - }, + "deprecated.mbt": "", + "generic.mbt": ( + #|#alias(rev_iterator, deprecated) + #|pub fn[A] SortedSet::rev_iter(self : SortedSet[A]) -> Iter[A] { + #| let mut curr_node = self + #| let parents = [] + #| Iter::new(fn() { + #| loop curr_node { + #| Node(left~, right=Empty, value~, ..) => { + #| curr_node = left + #| Some(value) + #| } + #| Node(left~, right~, value~, ..) => { + #| parents.push((value, left)) + #| continue right + #| } + #| Empty if parents.pop() is Some((value, left)) => { + #| curr_node = left + #| Some(value) + #| } + #| Empty => None + #| } + #| }) + #|} + #|#alias(iterator, deprecated) + #|pub fn[A] SortedSet::iter(self : SortedSet[A]) -> Iter[A] { + #| let mut curr_node = self + #| let parents = [] + #| Iter::new(fn() { + #| loop curr_node { + #| Node(left=Empty, right~, value~, size=_) => { + #| curr_node = right + #| Some(value) + #| } + #| Node(left~, right~, value~, size=_) => { + #| parents.push((value, right)) + #| continue left + #| } + #| Empty if parents.pop() is Some((value, right)) => { + #| curr_node = right + #| Some(value) + #| } + #| Empty => None + #| } + #| }) + #|} + #|#as_free_fn + #|#alias(from_iterator, deprecated) + #|#as_free_fn(from_iterator, deprecated) + #|pub fn[A : Compare] SortedSet::from_iter(iter : Iter[A]) -> SortedSet[A] { + #| iter.fold(init=new(), (s, e) => s.add(e)) + #|} + #|test { + #| @json.json_inspect(from_array([2, 7, 1, 2, 3, 4, 5]), content=[ + #| 1, 2, 3, 4, 5, 7, + #| ]) + #|} + #|pub impl[A : Eq] Eq for SortedSet[A] with equal(self, other) -> Bool { + #| if physical_equal(self, other) { + #| return true + #| } + #| guard self.length() == other.length() else { return false } + #| let iter = self.iter() + #| let iter1 = other.iter() + #| while iter.next() is Some(a) && iter1.next() is Some(b) { + #| guard a == b else { break false } + #| } nobreak { + #| true + #| } + #|} + #|pub impl[A : Compare] Compare for SortedSet[A] with compare(self, other) -> Int { + #| let my_size = self.length() + #| let other_size = other.length() + #| guard my_size == other_size else { return my_size - other_size } + #| let iter = self.iter() + #| let iter1 = other.iter() + #| while iter.next() is Some(a) && iter1.next() is Some(b) { + #| let cmp = a.compare(b) + #| guard cmp is 0 else { break cmp } + #| } nobreak { + #| 0 + #| } + #|} + #|test "Eq - equal sets" { + #| let s1 = from_array([1, 2, 3, 4, 5]) + #| let s2 = from_array([5, 4, 3, 2, 1]) + #| inspect(s1 == s2, content="true") + #|} + #|test "Eq - different elements same size" { + #| let s1 = from_array([1, 2, 3, 4, 5]) + #| let s2 = from_array([1, 2, 3, 4, 6]) + #| inspect(s1 == s2, content="false") + #|} + #|test "Eq - different sizes" { + #| let s1 = from_array([1, 2, 3]) + #| let s2 = from_array([1, 2, 3, 4, 5]) + #| inspect(s1 == s2, content="false") + #|} + #|test "Eq - empty sets" { + #| let s1 : SortedSet[Int] = new() + #| let s2 : SortedSet[Int] = new() + #| inspect(s1 == s2, content="true") + #|} + #|test "Eq - one empty one not" { + #| let s1 : SortedSet[Int] = new() + #| let s2 = from_array([1]) + #| inspect(s1 == s2, content="false") + #|} + #|test "Compare - equal sets" { + #| let s1 = from_array([1, 2, 3]) + #| let s2 = from_array([3, 2, 1]) + #| inspect(s1.compare(s2), content="0") + #|} + #|test "Compare - first smaller by size" { + #| let s1 = from_array([1, 2]) + #| let s2 = from_array([1, 2, 3]) + #| inspect(s1.compare(s2) < 0, content="true") + #|} + #|test "Compare - first larger by size" { + #| let s1 = from_array([1, 2, 3, 4]) + #| let s2 = from_array([1, 2]) + #| inspect(s1.compare(s2) > 0, content="true") + #|} + #|test "Compare - same size first smaller by elements" { + #| let s1 = from_array([1, 2, 3]) + #| let s2 = from_array([1, 2, 4]) + #| inspect(s1.compare(s2) < 0, content="true") + #|} + #|test "Compare - same size first larger by elements" { + #| let s1 = from_array([1, 2, 5]) + #| let s2 = from_array([1, 2, 4]) + #| inspect(s1.compare(s2) > 0, content="true") + #|} + #|test "Compare - empty sets" { + #| let s1 : SortedSet[Int] = new() + #| let s2 : SortedSet[Int] = new() + #| inspect(s1.compare(s2), content="0") + #|} + ), + "immutable_set.mbt": ( + #|#as_free_fn + #|pub fn[A] SortedSet::new() -> SortedSet[A] { + #| Empty + #|} + #|pub impl[A] Default for SortedSet[A] with default() { + #| Empty + #|} + #|#as_free_fn + #|pub fn[A] SortedSet::singleton(value : A) -> SortedSet[A] { + #| Node(left=Empty, value~, right=Empty, size=1) + #|} + #|#as_free_fn + #|#alias(of, deprecated="Use from_array instead") + #|#as_free_fn(of, deprecated="Use from_array instead") + #|pub fn[A : Compare] SortedSet::from_array(array : ArrayView[A]) -> SortedSet[A] { + #| for i = array.length() - 1, set = Empty; i >= 0; { + #| continue i - 1, set.add(array[i]) + #| } nobreak { + #| set + #| } + #|} + #|pub fn[A] SortedSet::to_array(self : SortedSet[A]) -> Array[A] { + #| let arr = [] + #| fn aux(set : SortedSet[A]) { + #| match set { + #| Empty => () + #| Node(left~, value~, right~, ..) => { + #| aux(left) + #| arr.push(value) + #| aux(right) + #| } + #| } + #| } + #| aux(self) + #| arr + #|} + #|pub fn[A] SortedSet::remove_min(self : SortedSet[A]) -> SortedSet[A] { + #| match self { + #| Empty => abort("remove_min: empty ImmutableSet") + #| Node(left~, right~, value~, ..) => + #| if left is Empty { + #| right + #| } else { + #| balance(left.remove_min(), value, right) + #| } + #| } + #|} + #|pub fn[A : Compare] SortedSet::add( + #| self : SortedSet[A], + #| value : A, + #|) -> SortedSet[A] { + #| match self { + #| Empty => Node(left=Empty, value~, right=Empty, size=1) + #| Node(left~, right~, value=node_value, ..) => { + #| let compare_result = value.compare(node_value) + #| if compare_result == 0 { + #| self + #| } else if compare_result < 0 { + #| let ll = left.add(value) + #| if physical_equal(left, ll) { + #| self + #| } else { + #| balance(ll, node_value, right) + #| } + #| } else { + #| let rr = right.add(value) + #| if physical_equal(right, rr) { + #| self + #| } else { + #| balance(left, node_value, rr) + #| } + #| } + #| } + #| } + #|} + #|pub fn[A : Compare] SortedSet::remove( + #| self : SortedSet[A], + #| value : A, + #|) -> SortedSet[A] { + #| match self { + #| Empty => Empty + #| Node(left~, right~, value=node_value, ..) => { + #| let compare_result = value.compare(node_value) + #| if compare_result == 0 { + #| left.merge(right) + #| } else if compare_result < 0 { + #| let new_left = left.remove(value) + #| if physical_equal(left, new_left) { + #| self + #| } else { + #| balance(new_left, node_value, right) + #| } + #| } else { + #| let new_right = right.remove(value) + #| if physical_equal(right, new_right) { + #| self + #| } else { + #| balance(left, node_value, new_right) + #| } + #| } + #| } + #| } + #|} + #|pub fn[A] SortedSet::min(self : SortedSet[A]) -> A { + #| match self { + #| Empty => abort("min: there are no values in sorted_set.") + #| Node(left~, value~, ..) => if left is Empty { value } else { left.min() } + #| } + #|} + #|pub fn[A] SortedSet::min_option(self : SortedSet[A]) -> A? { + #| match self { + #| Empty => None + #| Node(left~, value~, ..) => + #| if left is Empty { + #| Some(value) + #| } else { + #| left.min_option() + #| } + #| } + #|} + #|pub fn[A] SortedSet::max(self : SortedSet[A]) -> A { + #| match self { + #| Empty => abort("max: there are no values in ImmutableSet.") + #| Node(right~, value~, ..) => if right is Empty { value } else { right.max() } + #| } + #|} + #|pub fn[A] SortedSet::max_option(self : SortedSet[A]) -> A? { + #| match self { + #| Empty => None + #| Node(right~, value~, ..) => + #| if right is Empty { + #| Some(value) + #| } else { + #| right.max_option() + #| } + #| } + #|} + #|pub fn[A : Compare] SortedSet::split( + #| self : SortedSet[A], + #| divide : A, + #|) -> (SortedSet[A], Bool, SortedSet[A]) { + #| match self { + #| Empty => (Empty, false, Empty) + #| Node(left~, right~, value~, ..) => { + #| let compare_result = divide.compare(value) + #| if compare_result == 0 { + #| (left, true, right) + #| } else if compare_result < 0 { + #| let (left_left, present, right_left) = left.split(divide) + #| (left_left, present, join(right_left, value, right)) + #| } else { + #| let (left_right, present, right_right) = right.split(divide) + #| (join(left, value, left_right), present, right_right) + #| } + #| } + #| } + #|} + #|pub fn[A] SortedSet::is_empty(self : SortedSet[A]) -> Bool { + #| self is Empty + #|} + #|pub fn[A : Compare] SortedSet::contains(self : SortedSet[A], value : A) -> Bool { + #| match self { + #| Empty => false + #| Node(left~, right~, value=node_value, ..) => { + #| let compare_result = value.compare(node_value) + #| compare_result == 0 || + #| (if compare_result < 0 { left } else { right }).contains(value) + #| } + #| } + #|} + #|pub fn[A : Compare] SortedSet::range( + #| self : SortedSet[A], + #| low~ : A, + #| high~ : A, + #|) -> Iter[A] { + #| let todo_list = [] + #| let mut next_node = self + #| Iter::new(fn() { + #| loop next_node { + #| Node(left~, right~, value~, ..) => { + #| let cmp_value_low = value.compare(low) + #| let cmp_value_high = value.compare(high) + #| if cmp_value_low < 0 { + #| continue right + #| } else if cmp_value_high > 0 { + #| continue left + #| } else if left is Empty { + #| next_node = right + #| Some(value) + #| } else { + #| todo_list.push((value, right)) + #| continue left + #| } + #| } + #| Empty if todo_list.pop() is Some((value, right)) => { + #| next_node = right + #| Some(value) + #| } + #| Empty => None + #| } + #| }) + #|} + #|pub fn[A : Compare] SortedSet::union( + #| self : SortedSet[A], + #| other : SortedSet[A], + #|) -> SortedSet[A] { + #| match (self, other) { + #| (Empty, _) => other + #| (_, Empty) => self + #| ( + #| Node(left=l1, value=v1, right=r1, size=s1), + #| Node(left=l2, value=v2, right=r2, size=s2), + #| ) => + #| if s1 >= s2 { + #| if s2 == 1 { + #| self.add(v2) + #| } else { + #| let (l2, _, r2) = other.split(v1) + #| join(l1.union(l2), v1, r1.union(r2)) + #| } + #| } else if s1 == 1 { + #| other.add(v1) + #| } else { + #| let (l1, _, r1) = self.split(v2) + #| join(l1.union(l2), v2, r1.union(r2)) + #| } + #| } + #|} + #|pub impl[A : Compare] Add for SortedSet[A] with add(self, other) { + #| return self.union(other) + #|} + #|#alias(inter, deprecated) + #|pub fn[A : Compare] SortedSet::intersection( + #| self : SortedSet[A], + #| other : SortedSet[A], + #|) -> SortedSet[A] { + #| match (self, other) { + #| (Empty, _) | (_, Empty) => Empty + #| (Node(left=l1, value=v1, right=r1, ..), _) => + #| match other.split(v1) { + #| (l2, false, r2) => l1.intersection(l2).concat(r1.intersection(r2)) + #| (l2, true, r2) => join(l1.intersection(l2), v1, r1.intersection(r2)) + #| } + #| } + #|} + #|#alias(diff, deprecated) + #|pub fn[A : Compare] SortedSet::difference( + #| self : SortedSet[A], + #| other : SortedSet[A], + #|) -> SortedSet[A] { + #| match (self, other) { + #| (Empty, _) => Empty + #| (_, Empty) => self + #| (Node(left=l1, value=v1, right=r1, ..), _) => + #| match other.split(v1) { + #| (l2, false, r2) => join(l1.difference(l2), v1, r1.difference(r2)) + #| (l2, true, r2) => l1.difference(l2).concat(r1.difference(r2)) + #| } + #| } + #|} + #|pub fn[A : Compare] SortedSet::symmetric_difference( + #| self : SortedSet[A], + #| other : SortedSet[A], + #|) -> SortedSet[A] { + #| match (self, other) { + #| (Empty, _) => other + #| (_, Empty) => self + #| (Node(left=l1, value=v1, right=r1, ..), _) => + #| match other.split(v1) { + #| (l2, false, r2) => + #| join(l1.symmetric_difference(l2), v1, r1.symmetric_difference(r2)) + #| (l2, true, r2) => + #| l1.symmetric_difference(l2).concat(r1.symmetric_difference(r2)) + #| } + #| } + #|} + #|pub fn[A : Compare] SortedSet::subset( + #| self : SortedSet[A], + #| other : SortedSet[A], + #|) -> Bool { + #| match (self, other) { + #| (Empty, _) => true + #| (_, Empty) => false + #| ( + #| Node(left=l1, value=v1, right=r1, ..), + #| Node(left=l2, value=v2, right=r2, ..), + #| ) => { + #| let compare_result = v1.compare(v2) + #| if compare_result == 0 { + #| l1.subset(l2) && r1.subset(r2) + #| } else if compare_result < 0 { + #| Node(left=l1, value=v1, right=Empty, size=1).subset(l2) && + #| r1.subset(other) + #| } else { + #| Node(left=Empty, value=v1, right=r1, size=1).subset(r2) && + #| l1.subset(other) + #| } + #| } + #| } + #|} + #|pub fn[A : Compare] SortedSet::disjoint( + #| self : SortedSet[A], + #| other : SortedSet[A], + #|) -> Bool { + #| match (self, other) { + #| (Empty, _) | (_, Empty) => true + #| (Node(left=l1, value=v1, right=r1, ..), _) => + #| if physical_equal(self, other) { + #| false + #| } else { + #| match other.split_bis(v1) { + #| NotFound(l2, r2) => l1.disjoint(l2) && r1.disjoint(r2()) + #| Found => false + #| } + #| } + #| } + #|} + #|pub fn[A] SortedSet::each( + #| self : SortedSet[A], + #| f : (A) -> Unit raise?, + #|) -> Unit raise? { + #| match self { + #| Empty => () + #| Node(left~, value~, right~, ..) => { + #| left.each(f) + #| f(value) + #| right.each(f) + #| } + #| } + #|} + #|pub fn[A, B] SortedSet::fold( + #| self : SortedSet[A], + #| init~ : B, + #| f : (B, A) -> B raise?, + #|) -> B raise? { + #| match self { + #| Empty => init + #| Node(left~, value~, right~, ..) => + #| right.fold(init=f(left.fold(init~, f), value), f) + #| } + #|} + #|pub fn[A, B : Compare] SortedSet::map( + #| self : SortedSet[A], + #| f : (A) -> B raise?, + #|) -> SortedSet[B] raise? { + #| match self { + #| Empty => Empty + #| Node(left~, value~, right~, ..) => + #| try_join(left.map(f), f(value), right.map(f)) + #| } + #|} + #|pub fn[A] SortedSet::all( + #| self : SortedSet[A], + #| f : (A) -> Bool raise?, + #|) -> Bool raise? { + #| match self { + #| Empty => true + #| Node(left~, value~, right~, ..) => f(value) && left.all(f) && right.all(f) + #| } + #|} + #|pub fn[A] SortedSet::any( + #| self : SortedSet[A], + #| f : (A) -> Bool raise?, + #|) -> Bool raise? { + #| match self { + #| Empty => false + #| Node(left~, value~, right~, ..) => f(value) || left.any(f) || right.any(f) + #| } + #|} + #|pub fn[A] SortedSet::filter( + #| self : SortedSet[A], + #| f : (A) -> Bool raise?, + #|) -> SortedSet[A] raise? { + #| match self { + #| Empty => Empty + #| Node(left~, value~, right~, ..) => { + #| let l = left.filter(f) + #| let v = f(value) + #| let r = right.filter(f) + #| if v { + #| if physical_equal(l, left) && physical_equal(r, right) { + #| self + #| } else { + #| join(l, value, r) + #| } + #| } else { + #| l.concat(r) + #| } + #| } + #| } + #|} + #|pub impl[A : Show] Show for SortedSet[A] with output(self, logger) { + #| logger.write_iter( + #| self.iter(), + #| prefix="@immut/sorted_set.from_array([", + #| suffix="])", + #| ) + #|} + #|pub impl[A : ToJson] ToJson for SortedSet[A] with to_json(self) { + #| let capacity = self.iter().count() + #| guard capacity != 0 else { return Json::array([]) } + #| let jsons = Array::new(capacity~) + #| self.each(a => jsons.push(a.to_json())) + #| Json::array(jsons) + #|} + #|pub fn[A : ToJson] SortedSet::to_json(self : SortedSet[A]) -> Json { + #| ToJson::to_json(self) + #|} + #|pub impl[A : @json.FromJson + Compare] @json.FromJson for SortedSet[A] with from_json( + #| json, + #| path, + #|) { + #| guard json is Array(arr) else { + #| raise @json.JsonDecodeError( + #| (path, "@immut/sorted_set.from_json: expected array"), + #| ) + #| } + #| for i, x in arr; set = (new() : SortedSet[A]) { + #| continue set.add(A::from_json(x, path.add_index(i))) + #| } nobreak { + #| set + #| } + #|} + #|#as_free_fn + #|pub fn[A : @json.FromJson + Compare] SortedSet::from_json( + #| json : Json, + #|) -> SortedSet[A] raise @json.JsonDecodeError { + #| @json.from_json(json) + #|} + #|pub impl[X : @quickcheck.Arbitrary + Compare] @quickcheck.Arbitrary for SortedSet[ + #| X, + #|] with arbitrary(size, rs) { + #| @quickcheck.Arbitrary::arbitrary(size, rs) |> from_array + #|} + #|const BALANCE_RATIO = 5 + #|priv enum SplitBis[A] { + #| Found + #| NotFound(SortedSet[A], () -> SortedSet[A]) + #|} + #|impl[T] Show for SplitBis[T] with output(self, logger) { + #| match self { + #| Found => logger.write_string("Found") + #| NotFound(_) => logger.write_string("NotFound") + #| } + #|} + #|fn[A : Compare] SortedSet::split_bis( + #| self : SortedSet[A], + #| value : A, + #|) -> SplitBis[A] { + #| match self { + #| Empty => NotFound(Empty, () => Empty) + #| Node(left~, value=node_value, right~, ..) => { + #| let compare_result = value.compare(node_value) + #| if compare_result == 0 { + #| Found + #| } else if compare_result < 0 { + #| match left.split_bis(value) { + #| Found => Found + #| NotFound(ll, rl) => NotFound(ll, () => join(rl(), node_value, right)) + #| } + #| } else { + #| match right.split_bis(value) { + #| Found => Found + #| NotFound(lr, rr) => NotFound(join(left, node_value, lr), rr) + #| } + #| } + #| } + #| } + #|} + #|#alias(size, deprecated) + #|pub fn[A] SortedSet::length(self : SortedSet[A]) -> Int { + #| match self { + #| Empty => 0 + #| Node(size~, ..) => size + #| } + #|} + #|fn[A] create( + #| left : SortedSet[A], + #| value : A, + #| right : SortedSet[A], + #|) -> SortedSet[A] { + #| Node(left~, right~, value~, size=left.length() + right.length() + 1) + #|} + #|fn[A] balance( + #| left : SortedSet[A], + #| value : A, + #| right : SortedSet[A], + #|) -> SortedSet[A] { + #| let left_size = left.length() + #| let right_size = right.length() + #| if left_size + right_size < 2 { + #| create(left, value, right) + #| } else if left_size > right_size * BALANCE_RATIO { + #| match left { + #| Empty => abort("balance: left is empty.") + #| Node(left=ll, value=lv, right=lr, ..) => + #| if ll.length() >= lr.length() { + #| create(ll, lv, create(lr, value, right)) + #| } else { + #| match lr { + #| Empty => abort("balance: right left.right is empty.") + #| Node(left=lrl, value=lrv, right=lrr, ..) => + #| create(create(ll, lv, lrl), lrv, create(lrr, value, right)) + #| } + #| } + #| } + #| } else if right_size > left_size * BALANCE_RATIO { + #| match right { + #| Empty => abort("balance: right is empty") + #| Node(left=rl, value=rv, right=rr, ..) => + #| if rr.length() >= rl.length() { + #| create(create(left, value, rl), rv, rr) + #| } else { + #| match rl { + #| Empty => abort("balance: right.left is empty") + #| Node(left=rll, value=rlv, right=rlr, ..) => + #| create(create(left, value, rll), rlv, create(rlr, rv, rr)) + #| } + #| } + #| } + #| } else { + #| create(left, value, right) + #| } + #|} + #|fn[A] SortedSet::add_min_value(self : SortedSet[A], value : A) -> SortedSet[A] { + #| match self { + #| Empty => singleton(value) + #| Node(left~, value=node_value, right~, ..) => + #| balance(left.add_min_value(value), node_value, right) + #| } + #|} + #|fn[A] SortedSet::add_max_value(self : SortedSet[A], value : A) -> SortedSet[A] { + #| match self { + #| Empty => singleton(value) + #| Node(left~, value=node_value, right~, ..) => + #| balance(left, node_value, right.add_max_value(value)) + #| } + #|} + #|fn[A] join( + #| left : SortedSet[A], + #| value : A, + #| right : SortedSet[A], + #|) -> SortedSet[A] { + #| match (left, right) { + #| (Empty, _) => right.add_min_value(value) + #| (_, Empty) => left.add_max_value(value) + #| ( + #| Node(left=ll, value=lv, right=lr, size=ls), + #| Node(left=rl, value=rv, right=rr, size=rs), + #| ) => + #| if ls > rs * BALANCE_RATIO { + #| balance(ll, lv, join(lr, value, right)) + #| } else if rs > ls * BALANCE_RATIO { + #| balance(join(left, value, rl), rv, rr) + #| } else { + #| create(left, value, right) + #| } + #| } + #|} + #|fn[A : Compare] try_join( + #| left : SortedSet[A], + #| value : A, + #| right : SortedSet[A], + #|) -> SortedSet[A] { + #| if (left == Empty || left.max().compare(value) < 0) && + #| (right == Empty || value.compare(right.min()) < 0) { + #| join(left, value, right) + #| } else { + #| left.union(right.add(value)) + #| } + #|} + #|fn[A] SortedSet::merge( + #| self : SortedSet[A], + #| other : SortedSet[A], + #|) -> SortedSet[A] { + #| match (self, other) { + #| (Empty, _) => other + #| (_, Empty) => self + #| _ => balance(self, other.min(), other.remove_min()) + #| } + #|} + #|fn[A] SortedSet::concat( + #| self : SortedSet[A], + #| other : SortedSet[A], + #|) -> SortedSet[A] { + #| match (self, other) { + #| (Empty, _) => other + #| (_, Empty) => self + #| _ => join(self, other.min(), other.remove_min()) + #| } + #|} + #|pub impl[A : Hash] Hash for SortedSet[A] with hash_combine(self, hasher) { + #| for t in self { + #| t.hash_combine(hasher) + #| } + #|} + #|test "split_bis" { + #| inspect(from_array([1, 2, 3]).split_bis(1), content="Found") + #| inspect(from_array([1, 2, 3]).split_bis(3), content="Found") + #| inspect(from_array([1, 2, 3]).split_bis(0), content="NotFound") + #| inspect(from_array([1, 2, 3]).split_bis(4), content="NotFound") + #|} + #|test "balance with left height greater" { + #| let left = from_array([1, 2, 3]) + #| let value = 4 + #| let right = from_array([5]) + #| let balanced_set = balance(left, value, right) + #| inspect(balanced_set, content="@immut/sorted_set.from_array([1, 2, 3, 4, 5])") + #|} + #|test "balance with right height greater" { + #| let left = from_array([1]) + #| let value = 2 + #| let right = from_array([3, 4, 5]) + #| let balanced_set = balance(left, value, right) + #| inspect(balanced_set, content="@immut/sorted_set.from_array([1, 2, 3, 4, 5])") + #|} + #|test "join with different heights" { + #| let left = from_array([1, 2, 3]) + #| let value = 4 + #| let right = from_array([5, 6, 7]) + #| let joined_set = join(left, value, right) + #| inspect( + #| joined_set, + #| content="@immut/sorted_set.from_array([1, 2, 3, 4, 5, 6, 7])", + #| ) + #|} + #|test "hash" { + #| assert_eq( + #| Hash::hash(from_array([1, 2, 3, 4])), + #| Hash::hash(from_array([3, 2]).add(1).add(4)), + #| ) + #| assert_not_eq( + #| Hash::hash(from_array([1, 2, 3])), + #| Hash::hash(from_array([1, 2, 4])), + #| ) + #|} + ), + "types.mbt": ( + #|#alias(T, deprecated) + #|enum SortedSet[A] { + #| Empty + #| Node(left~ : SortedSet[A], right~ : SortedSet[A], size~ : Int, value~ : A) + #|} + ) + } ) ///| let moonbitlang_core_int_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/int", - deps={ - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/uint": moonbitlang_core_uint_module, - }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": ["moonbitlang/core/builtin", "moonbitlang/core/uint"], - #| "test-import": [ - #| "moonbitlang/core/bytes", - #| "moonbitlang/core/buffer" - #| ] - #|} - ), - "int.mbt": ( - #|pub let max_value = 2147483647 - #|pub let min_value = -2147483648 - #|#deprecated("Use Int::abs instead") - #|pub fn abs(x : Int) -> Int { - #| Int::abs(x) - #|} - #|#deprecated - #|#doc(hidden) - #|pub fn Int::to_be_bytes(self : Int) -> Bytes { - #| let self = self.reinterpret_as_uint() - #| [ - #| (self >> 24).to_byte(), - #| (self >> 16).to_byte(), - #| (self >> 8).to_byte(), - #| self.to_byte(), - #| ] - #|} - #|#deprecated - #|#doc(hidden) - #|pub fn Int::to_le_bytes(self : Int) -> Bytes { - #| let self = self.reinterpret_as_uint() - #| [ - #| self.to_byte(), - #| (self >> 8).to_byte(), - #| (self >> 16).to_byte(), - #| (self >> 24).to_byte(), - #| ] - #|} - ), - }, + "int.mbt": ( + #|pub const MAX_VALUE = 2147483647 + #|#deprecated("Use `MAX_VALUE` instead") + #|pub let max_value = 2147483647 + #|pub const MIN_VALUE = -2147483648 + #|#deprecated("Use `MIN_VALUE` instead") + #|pub let min_value = -2147483648 + #|#deprecated("Use Int::abs instead") + #|pub fn abs(x : Int) -> Int { + #| Int::abs(x) + #|} + #|#deprecated + #|#doc(hidden) + #|pub fn Int::to_be_bytes(self : Int) -> Bytes { + #| let self = self.reinterpret_as_uint() + #| [ + #| (self >> 24).to_byte(), + #| (self >> 16).to_byte(), + #| (self >> 8).to_byte(), + #| self.to_byte(), + #| ] + #|} + #|#deprecated + #|#doc(hidden) + #|pub fn Int::to_le_bytes(self : Int) -> Bytes { + #| let self = self.reinterpret_as_uint() + #| [ + #| self.to_byte(), + #| (self >> 8).to_byte(), + #| (self >> 16).to_byte(), + #| (self >> 24).to_byte(), + #| ] + #|} + ) + } ) ///| let moonbitlang_core_int16_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/int16", - deps={ "moonbitlang/core/builtin": moonbitlang_core_builtin_module }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": ["moonbitlang/core/builtin"], - #| "test-import": ["moonbitlang/core/uint16", "moonbitlang/core/json"] - #|} - ), - "int16.mbt": ( - #|pub let max_value : Int16 = 32767 - #|pub let min_value : Int16 = -32768 - #|pub impl Add for Int16 with add(self : Int16, that : Int16) -> Int16 { - #| Int16::from_int(self.to_int() + that.to_int()) - #|} - #|pub impl Sub for Int16 with sub(self : Int16, that : Int16) -> Int16 { - #| Int16::from_int(self.to_int() - that.to_int()) - #|} - #|pub impl Mul for Int16 with mul(self : Int16, that : Int16) -> Int16 { - #| Int16::from_int(self.to_int() * that.to_int()) - #|} - #|pub impl Div for Int16 with div(self : Int16, that : Int16) -> Int16 { - #| Int16::from_int(self.to_int() / that.to_int()) - #|} - #|pub impl Mod for Int16 with mod(self : Int16, that : Int16) -> Int16 { - #| Int16::from_int(self.to_int() % that.to_int()) - #|} - #|pub impl Eq for Int16 with equal(self, that) { - #| self.to_int() == that.to_int() - #|} - #|pub impl Compare for Int16 with compare(self, that) { - #| self.to_int().compare(that.to_int()) - #|} - #|pub impl Hash for Int16 with hash_combine(self, hasher) { - #| hasher.combine_int(self.to_int()) - #|} - #|pub impl Shl for Int16 with shl(self : Int16, that : Int) -> Int16 { - #| Int16::from_int(self.to_int() << that) - #|} - #|pub impl Shr for Int16 with shr(self : Int16, that : Int) -> Int16 { - #| Int16::from_int(self.to_int() >> that) - #|} - #|pub impl BitOr for Int16 with lor(self : Int16, that : Int16) -> Int16 { - #| Int16::from_int(self.to_int() | that.to_int()) - #|} - #|pub impl BitAnd for Int16 with land(self : Int16, that : Int16) -> Int16 { - #| Int16::from_int(self.to_int() & that.to_int()) - #|} - #|pub impl BitXOr for Int16 with lxor(self : Int16, that : Int16) -> Int16 { - #| Int16::from_int(self.to_int() ^ that.to_int()) - #|} - #|pub impl Neg for Int16 with neg(self : Int16) -> Int16 { - #| Int16::from_int(-self.to_int()) - #|} - #|pub fn Int16::abs(self : Int16) -> Int16 { - #| if self < 0 { - #| -self - #| } else { - #| self - #| } - #|} - #|pub impl Default for Int16 with default() { - #| 0 - #|} - #|pub impl ToJson for Int16 with to_json(self : Int16) -> Json { - #| Json::number(self.to_int().to_double()) - #|} - #|pub impl Show for Int16 with output(self, logger) { - #| logger.write_string(self.to_string()) - #|} - #|pub fn Int16::reinterpret_as_uint16(self : Int16) -> UInt16 { - #| self.to_int().to_uint16() - #|} - #|pub fn Int16::reinterpret_from_uint16(self : UInt16) -> Int16 { - #| Int16::from_int(self.to_int()) - #|} - #|pub fn Int16::from_int(self : Int) -> Int16 = "%i32_to_i16" - #|pub fn Int16::from_byte(self : Byte) -> Int16 = "%byte_to_i16" - #|#cfg(not(target="js")) - #|pub fn Int16::from_int64(self : Int64) -> Int16 = "%i64_to_i16" - #|#cfg(target="js") - #|pub fn Int16::from_int64(self : Int64) -> Int16 { - #| Int16::from_int(self.to_int()) - #|} - #|#cfg(target="js") - #|pub fn Int16::to_int64(self : Int16) -> Int64 { - #| self.to_int().to_int64() - #|} - #|#cfg(not(target="js")) - #|pub fn Int16::to_int64(self : Int16) -> Int64 = "%i16_to_i64" - #|pub fn Int16::to_int(self : Int16) -> Int = "%i16_to_i32" - #|pub fn Int16::to_byte(self : Int16) -> Byte = "%i16_to_byte" - #|pub fn Int16::to_string(self : Int16, radix? : Int = 10) -> String { - #| self.to_int().to_string(radix~) - #|} - ), - }, + "int16.mbt": ( + #|pub const MAX_VALUE : Int16 = 32767 + #|#deprecated("Use `MAX_VALUE` instead") + #|pub let max_value : Int16 = 32767 + #|pub const MIN_VALUE : Int16 = -32768 + #|#deprecated("Use `MIN_VALUE` instead") + #|pub let min_value : Int16 = -32768 + #|pub impl Add for Int16 with add(self : Int16, that : Int16) -> Int16 { + #| Int16::from_int(self.to_int() + that.to_int()) + #|} + #|pub impl Sub for Int16 with sub(self : Int16, that : Int16) -> Int16 { + #| Int16::from_int(self.to_int() - that.to_int()) + #|} + #|pub impl Mul for Int16 with mul(self : Int16, that : Int16) -> Int16 { + #| Int16::from_int(self.to_int() * that.to_int()) + #|} + #|pub impl Div for Int16 with div(self : Int16, that : Int16) -> Int16 { + #| Int16::from_int(self.to_int() / that.to_int()) + #|} + #|pub impl Mod for Int16 with mod(self : Int16, that : Int16) -> Int16 { + #| Int16::from_int(self.to_int() % that.to_int()) + #|} + #|pub impl Eq for Int16 with equal(self, that) { + #| self.to_int() == that.to_int() + #|} + #|pub impl Eq for Int16 with not_equal(self, that) { + #| self.to_int() != that.to_int() + #|} + #|pub impl Compare for Int16 with compare(self, that) { + #| self.to_int().compare(that.to_int()) + #|} + #|pub impl Hash for Int16 with hash_combine(self, hasher) { + #| hasher.combine_int(self.to_int()) + #|} + #|pub impl Shl for Int16 with shl(self : Int16, that : Int) -> Int16 { + #| Int16::from_int(self.to_int() << that) + #|} + #|pub impl Shr for Int16 with shr(self : Int16, that : Int) -> Int16 { + #| Int16::from_int(self.to_int() >> that) + #|} + #|pub impl BitOr for Int16 with lor(self : Int16, that : Int16) -> Int16 { + #| Int16::from_int(self.to_int() | that.to_int()) + #|} + #|pub impl BitAnd for Int16 with land(self : Int16, that : Int16) -> Int16 { + #| Int16::from_int(self.to_int() & that.to_int()) + #|} + #|pub impl BitXOr for Int16 with lxor(self : Int16, that : Int16) -> Int16 { + #| Int16::from_int(self.to_int() ^ that.to_int()) + #|} + #|pub impl Neg for Int16 with neg(self : Int16) -> Int16 { + #| Int16::from_int(-self.to_int()) + #|} + #|pub fn Int16::abs(self : Int16) -> Int16 { + #| if self < 0 { + #| -self + #| } else { + #| self + #| } + #|} + #|pub impl Default for Int16 with default() { + #| 0 + #|} + #|pub impl ToJson for Int16 with to_json(self : Int16) -> Json { + #| Json::number(self.to_int().to_double()) + #|} + #|pub impl Show for Int16 with output(self, logger) { + #| logger.write_string(self.to_string()) + #|} + #|pub fn Int16::reinterpret_as_uint16(self : Int16) -> UInt16 { + #| self.to_int().to_uint16() + #|} + #|pub fn Int16::reinterpret_from_uint16(self : UInt16) -> Int16 { + #| Int16::from_int(self.to_int()) + #|} + #|pub fn Int16::from_int(self : Int) -> Int16 = "%i32_to_i16" + #|pub fn Int16::from_byte(self : Byte) -> Int16 = "%byte_to_i16" + #|#cfg(not(target="js")) + #|pub fn Int16::from_int64(self : Int64) -> Int16 = "%i64_to_i16" + #|#cfg(target="js") + #|pub fn Int16::from_int64(self : Int64) -> Int16 { + #| Int16::from_int(self.to_int()) + #|} + #|#cfg(target="js") + #|pub fn Int16::to_int64(self : Int16) -> Int64 { + #| self.to_int().to_int64() + #|} + #|#cfg(not(target="js")) + #|pub fn Int16::to_int64(self : Int16) -> Int64 = "%i16_to_i64" + #|pub fn Int16::to_int(self : Int16) -> Int = "%i16_to_i32" + #|pub fn Int16::to_byte(self : Int16) -> Byte = "%i16_to_byte" + #|pub fn Int16::to_string(self : Int16, radix? : Int = 10) -> String { + #| self.to_int().to_string(radix~) + #|} + ) + } ) ///| let moonbitlang_core_int64_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/int64", - deps={ - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/uint64": moonbitlang_core_uint64_module, - "moonbitlang/core/int16": moonbitlang_core_int16_module, - }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": ["moonbitlang/core/builtin", "moonbitlang/core/uint64", "moonbitlang/core/int16"], - #| "test-import": [ - #| "moonbitlang/core/bytes", - #| "moonbitlang/core/buffer" - #| ] - #|} - ), - "int64.mbt": ( - #|pub let max_value = 9223372036854775807L - #|pub let min_value = -9223372036854775808L - #|#deprecated("Use Int64::from_int instead") - #|#doc(hidden) - #|pub fn from_int(i : Int) -> Int64 { - #| i.to_int64() - #|} - #|#deprecated("Use Int64::abs instead") - #|#doc(hidden) - #|pub fn abs(x : Int64) -> Int64 { - #| Int64::abs(x) - #|} - #|#deprecated - #|#doc(hidden) - #|pub fn Int64::to_be_bytes(self : Int64) -> Bytes { - #| self.reinterpret_as_uint64().to_be_bytes() - #|} - #|#deprecated - #|#doc(hidden) - #|pub fn Int64::to_le_bytes(self : Int64) -> Bytes { - #| self.reinterpret_as_uint64().to_le_bytes() - #|} - #|#deprecated("Use `Int16::from_int64` instead") - #|pub fn Int64::to_int16(self : Int64) -> Int16 { - #| Int16::from_int64(self) - #|} - ), - }, + "int64.mbt": ( + #|pub const MAX_VALUE = 9223372036854775807L + #|#deprecated("Use `MAX_VALUE` instead") + #|pub let max_value = 9223372036854775807L + #|pub const MIN_VALUE = -9223372036854775808L + #|#deprecated("Use `MIN_VALUE` instead") + #|pub let min_value = -9223372036854775808L + #|#deprecated("Use Int64::from_int instead") + #|#doc(hidden) + #|pub fn from_int(i : Int) -> Int64 { + #| i.to_int64() + #|} + #|#deprecated("Use Int64::abs instead") + #|#doc(hidden) + #|pub fn abs(x : Int64) -> Int64 { + #| Int64::abs(x) + #|} + #|#deprecated + #|#doc(hidden) + #|pub fn Int64::to_be_bytes(self : Int64) -> Bytes { + #| self.reinterpret_as_uint64().to_be_bytes() + #|} + #|#deprecated + #|#doc(hidden) + #|pub fn Int64::to_le_bytes(self : Int64) -> Bytes { + #| self.reinterpret_as_uint64().to_le_bytes() + #|} + #|#deprecated("Use `Int16::from_int64` instead") + #|pub fn Int64::to_int16(self : Int64) -> Int16 { + #| Int16::from_int64(self) + #|} + ) + } +) + +///| +let moonbitlang_core_internal_regex_engine_automata_module : RuntimePackage = RuntimePackage::new( + "moonbitlang/core/internal/regex_engine/automata", + deps={ }, + files={ + "context.mbt": ( + #|struct Context { + #| mut next_expr_id : Int + #| mut book : SlotBook + #| mut book_dirty : Bool + #|} + #|pub fn Context::new() -> Context { + #| Context::{ + #| next_expr_id: EXPR_ID_RESERVED + 1, + #| book: SlotBook::empty(), + #| book_dirty: false, + #| } + #|} + #|fn Context::new_expr_id(ctx : Context) -> ExprId { + #| let id = ctx.next_expr_id + #| ctx.next_expr_id += 1 + #| id + #|} + ), + "delta.mbt": ( + #|#warnings("-3") + #|priv struct Delta {} + #|#valtype + #|priv struct DeltaContext { + #| c : @shared_types.Rechar + #| prev_cat : @shared_types.Category + #| next_cat : @shared_types.Category + #|} + #|fn delta_rep( + #| outer : Expr, + #| mode : @shared_types.QuantifierMode, + #| pref : @shared_types.Preference, + #| inner : Expr, + #| c : DeltaContext, + #| marks : MarkSlotMap, + #|) -> ThreadSet { + #| let inner_delta = delta_expr(inner, c, marks) + #| let first_match_marks = inner_delta.find_first_match() + #| match mode { + #| Greedy => { + #| let (marks, inner_delta) = match first_match_marks { + #| None => (marks, inner_delta) + #| Some(marks) => (marks, inner_delta.remove_matches()) + #| } + #| ts_seq(pref, inner_delta, outer) + ts_end(marks) + #| } + #| NonGreedy => + #| ts_end(marks) + ts_seq(pref, inner_delta.remove_matches(), outer) + #| } + #|} + #|fn delta_expr(expr : Expr, c : DeltaContext, marks : MarkSlotMap) -> ThreadSet { + #| match expr.def { + #| Chr(cs) => if cs.contains(c.c) { ts_exp(marks, e_eps) } else { ts_empty } + #| Alt(exprs) => + #| exprs.fold(init=ts_empty, (acc, expr) => acc + delta_expr(expr, c, marks)) + #| Seq(pref, first, next) => { + #| let first_delta = delta_expr(first, c, marks) + #| delta_seq(pref, first_delta, next, c) + #| } + #| Rep(mode, pref, body) => delta_rep(expr, mode, pref, body, c, marks) + #| Eps => ts_end(marks) + #| Mark(mark) => ts_end(marks.add_mark(mark)) + #| Before(cat) => + #| if @shared_types.Category::intersects(c.next_cat, cat) { + #| ts_end(marks) + #| } else { + #| ts_empty + #| } + #| After(cat) => + #| if @shared_types.Category::intersects(c.prev_cat, cat) { + #| ts_end(marks) + #| } else { + #| ts_empty + #| } + #| } + #|} + #|fn delta_seq( + #| pref : @shared_types.Preference, + #| first : ThreadSet, + #| next : Expr, + #| c : DeltaContext, + #|) -> ThreadSet { + #| match first.find_first_match() { + #| None => ts_seq(pref, first, next) + #| Some(marks) => + #| match pref { + #| Longest => + #| ts_seq(pref, first.remove_matches(), next) + + #| delta_expr(next, c, marks) + #| Shortest => + #| delta_expr(next, c, marks) + + #| ts_seq(pref, first.remove_matches(), next) + #| First => { + #| let (until_first_match, after_first_match) = first.split_at_first_match() + #| ts_seq(pref, until_first_match, next) + + #| delta_expr(next, c, marks) + + #| ts_seq(pref, after_first_match.remove_matches(), next) + #| } + #| } + #| } + #|} + #|fn delta_thread( + #| thread : Thread, + #| c : DeltaContext, + #| marks : MarkSlotMap, + #|) -> ThreadSet { + #| match thread { + #| End(_) => ts_one(thread) + #| Exp(marks, expr) => delta_expr(expr, c, marks) + #| Seq(pref, first, next) => { + #| let first_delta = delta_threads(first, c, marks) + #| delta_seq(pref, first_delta, next, c) + #| } + #| } + #|} + #|fn delta_threads( + #| curr : ThreadSet, + #| c : DeltaContext, + #| marks : MarkSlotMap, + #|) -> ThreadSet { + #| curr.flat_map(thread => delta_thread(thread, c, marks)) + #|} + #|fn find_slot(ctx~ : Context, desc : ThreadSet) -> Slot { + #| if ctx.book_dirty { + #| ctx.book.clear() + #| } + #| let has_unassigned_slots = for + #| marks in desc.iter_marks() + #| has_unassigned_slots = false { + #| for _mark, slot in marks; has_unassigned_slots = has_unassigned_slots { + #| if slot.is_assigned() { + #| ctx.book.mark_used(slot) + #| continue has_unassigned_slots + #| } else { + #| continue true + #| } + #| } nobreak { + #| continue has_unassigned_slots + #| } + #| } nobreak { + #| has_unassigned_slots + #| } + #| if !has_unassigned_slots { + #| Slot::unassigned() + #| } else { + #| let slot = ctx.book.find_unused() + #| if ctx.book.need_grow(slot) { + #| ctx.book = ctx.book.grow() + #| ctx.book_dirty = false + #| } else { + #| ctx.book_dirty = true + #| } + #| slot + #| } + #|} + #|pub fn delta( + #| ctx~ : Context, + #| state : State, + #| c : @shared_types.Rechar, + #| next_cat~ : @shared_types.Category, + #|) -> State { + #| let prev_cat = state.cat + #| let desc = delta_threads( + #| state.desc, + #| { prev_cat, next_cat, c }, + #| MarkSlotMap::empty(), + #| ) + #| let desc = desc.remove_duplicates(e_eps) + #| let slot = find_slot(ctx~, desc) + #| let desc = if slot.is_assigned() { desc.assign_slot(slot) } else { desc } + #| State::new(slot, next_cat, desc) + #|} + ), + "expr.mbt": ( + #|struct Expr { + #| id : ExprId + #| def : ExprDef + #|} + #|type ExprId = Int + #|const EXPR_ID_EMPTY : ExprId = 0 + #|const EXPR_ID_EPS : ExprId = 1 + #|const EXPR_ID_RESERVED : ExprId = 1 + #|priv enum ExprDef { + #| Chr(@shared_types.RecharSet) + #| Alt(Array[Expr]) + #| Seq(@shared_types.Preference, Expr, Expr) + #| Rep(@shared_types.QuantifierMode, @shared_types.Preference, Expr) + #| Eps + #| Mark(Mark) + #| Before(@shared_types.Category) + #| After(@shared_types.Category) + #|} + #|impl Eq for Expr with equal(self, other) { + #| self.id == other.id + #|} + #|impl Hash for Expr with hash_combine(self, hasher) { + #| hasher.combine(self.id) + #|} + #|pub fn e_copy(ctx~ : Context, e : Expr) -> Expr { + #| match e.def { + #| Chr(c) => e_cset(ctx~, c) + #| Alt(xs) => e_alt(ctx~, xs.map(x => e_copy(ctx~, x))) + #| Seq(pref, x, y) => e_seq(ctx~, pref, e_copy(ctx~, x), e_copy(ctx~, y)) + #| Rep(mode, pref, x) => e_rep(ctx~, mode, pref, e_copy(ctx~, x)) + #| Eps => e_eps + #| Mark(m) => e_mark(ctx~, m) + #| Before(cat) => e_before(ctx~, cat) + #| After(cat) => e_after(ctx~, cat) + #| } + #|} + #|let e_empty : Expr = Expr::{ id: EXPR_ID_EMPTY, def: Alt([]) } + #|pub let e_eps : Expr = Expr::{ id: EXPR_ID_EPS, def: Eps } + #|pub fn is_eps(e : Expr) -> Bool { + #| e.def is Eps + #|} + #|pub fn e_cset(ctx~ : Context, c : @shared_types.RecharSet) -> Expr { + #| if c.is_empty() { + #| e_empty + #| } else { + #| Expr::{ id: ctx.new_expr_id(), def: Chr(c) } + #| } + #|} + #|pub fn e_rep( + #| ctx~ : Context, + #| mode : @shared_types.QuantifierMode, + #| pref : @shared_types.Preference, + #| x : Expr, + #|) -> Expr { + #| Expr::{ id: ctx.new_expr_id(), def: Rep(mode, pref, x) } + #|} + #|pub fn e_mark(ctx~ : Context, m : Mark) -> Expr { + #| Expr::{ id: ctx.new_expr_id(), def: Mark(m) } + #|} + #|pub fn e_before(ctx~ : Context, cat : @shared_types.Category) -> Expr { + #| Expr::{ id: ctx.new_expr_id(), def: Before(cat) } + #|} + #|pub fn e_after(ctx~ : Context, cat : @shared_types.Category) -> Expr { + #| Expr::{ id: ctx.new_expr_id(), def: After(cat) } + #|} + #|pub fn e_alt(ctx~ : Context, xs : Array[Expr]) -> Expr { + #| match xs { + #| [] => e_empty + #| [x] => x + #| xs => Expr::{ id: ctx.new_expr_id(), def: Alt(xs) } + #| } + #|} + #|pub fn e_seq( + #| ctx~ : Context, + #| pref : @shared_types.Preference, + #| x : Expr, + #| y : Expr, + #|) -> Expr { + #| match (x.def, y.def) { + #| (Alt([]), _) => x + #| (_, Alt([])) => y + #| (Eps, _) => y + #| (_, Eps) if pref is First => x + #| _ => Expr::{ id: ctx.new_expr_id(), def: Seq(pref, x, y) } + #| } + #|} + ), + "mark.mbt": ( + #|pub(all) struct Mark(Int) derive(Eq, Hash, Compare) + ), + "mark_slot_map.mbt": ( + #|struct MarkSlotMap(@immut/sorted_map.SortedMap[Mark, Slot]) derive(Eq, Hash) + #|fn MarkSlotMap::empty() -> MarkSlotMap { + #| MarkSlotMap(@immut/sorted_map.SortedMap::new()) + #|} + #|fn MarkSlotMap::add_mark(self : MarkSlotMap, mark : Mark) -> MarkSlotMap { + #| MarkSlotMap(self.0.add(mark, Slot::unassigned())) + #|} + #|fn MarkSlotMap::assign_slot(self : MarkSlotMap, slot : Slot) -> MarkSlotMap { + #| MarkSlotMap( + #| self.0.map_with_key((_mark, prev_slot) => { + #| if prev_slot.is_assigned() { + #| prev_slot + #| } else { + #| slot + #| } + #| }), + #| ) + #|} + #|pub fn MarkSlotMap::get_slot(self : MarkSlotMap, mark : Mark) -> Slot { + #| match self.0.get(mark) { + #| None => Slot::unassigned() + #| Some(slot) => slot + #| } + #|} + #|pub fn MarkSlotMap::iter2(self : MarkSlotMap) -> Iter2[Mark, Slot] { + #| self.0.iter2() + #|} + ), + "slot.mbt": ( + #|#valtype + #|pub struct Slot { + #| index : Int + #|} derive(Eq, Hash) + #|pub fn Slot::from_index(index : Int) -> Slot { + #| { index, } + #|} + #|pub fn Slot::unassigned() -> Slot { + #| { index: 0 } + #|} + #|pub fn Slot::is_assigned(self : Slot) -> Bool { + #| self.index > 0 + #|} + ), + "slot_book.mbt": ( + #|priv struct SlotBook(FixedArray[Int]) + #|fn SlotBook::empty() -> SlotBook { + #| let book = FixedArray::make(4, 0) + #| book[0] = 1 // Reserve index 0 as unassigned slot + #| SlotBook(book) + #|} + #|fn SlotBook::mark_used(self : SlotBook, slot : Slot) -> Unit { + #| debug_assert(() => slot.is_assigned()) + #| let index = slot.index / 32 + #| let bit = slot.index % 32 + #| self.0[index] = self.0[index] | (1 << bit) + #|} + #|fn SlotBook::find_unused(self : SlotBook) -> Slot { + #| for i = 0; i < self.0.length(); i = i + 1 { + #| if self.0[i] != -1 { + #| let bit = self.0[i].lnot().ctz() + #| return Slot::from_index(i * 32 + bit) + #| } + #| } + #| Slot::from_index(self.0.length() * 32) + #|} + #|fn SlotBook::clear(self : SlotBook) -> Unit { + #| self.0.fill(0) + #| self.0[0] = 1 // Reserve index 0 as unassigned slot + #|} + #|fn next_pow_of_two(n : Int) -> Int { + #| if n <= 1 { + #| 1 + #| } else { + #| guard n <= 0x40000000 else { panic() } + #| 1 << (32 - (n - 1).clz()) + #| } + #|} + #|fn SlotBook::need_grow(self : SlotBook, slot : Slot) -> Bool { + #| slot.index >= 32 * self.0.length() + #|} + #|fn SlotBook::grow(self : SlotBook) -> SlotBook { + #| let book = FixedArray::make(next_pow_of_two(self.0.length() + 1), 0) + #| book[0] = 1 // Reserve index 0 as unassigned slot + #| SlotBook(book) + #|} + ), + "state.mbt": ( + #|pub struct State { + #| priv slot : Slot + #| priv cat : @shared_types.Category + #| priv desc : ThreadSet + #| priv hash : Int + #|} + #|pub let st_dummy : State = { + #| slot: Slot::unassigned(), + #| cat: @shared_types.Category::dummy(), + #| desc: ts_empty, + #| hash: -1, + #|} + #|pub enum Status { + #| Failed + #| Match(MarkSlotMap) + #| Running + #|} + #|pub impl Eq for State with equal(self, other) { + #| self.hash == other.hash && + #| self.slot == other.slot && + #| self.cat == other.cat && + #| self.desc == other.desc + #|} + #|pub impl Hash for State with hash_combine(self, hasher) { + #| hasher.combine(self.hash) + #|} + #|fn State::new( + #| slot : Slot, + #| cat : @shared_types.Category, + #| desc : ThreadSet, + #|) -> State { + #| State::{ slot, cat, desc, hash: (slot, cat, desc).hash() } + #|} + #|pub fn State::start(cat : @shared_types.Category, expr : Expr) -> State { + #| State::new(Slot::unassigned(), cat, ts_exp(MarkSlotMap::empty(), expr)) + #|} + #|pub fn State::slot(self : State) -> Slot { + #| self.slot + #|} + #|pub fn State::status(self : State) -> Status { + #| match self.desc.first() { + #| None => Failed + #| Some(End(marks)) => Match(marks) + #| Some(Exp(_) | Seq(_)) => Running + #| } + #|} + ), + "thread.mbt": ( + #|priv enum Thread { + #| End(MarkSlotMap) + #| Exp(MarkSlotMap, Expr) + #| Seq(@shared_types.Preference, ThreadSet, Expr) + #|} derive(Eq, Hash) + ), + "thread_set.mbt": ( + #|priv enum ThreadSet { + #| Empty + #| Node( + #| i~ : ThreadSetNodeInfo, + #| l~ : ThreadSet, + #| t~ : Thread, + #| r~ : ThreadSet, + #| p~ : Int + #| ) + #|} + #|#valtype + #|priv struct ThreadSetNodeInfo { + #| no_match : Bool + #|} + #|fn ThreadSet::is_empty(self : ThreadSet) -> Bool { + #| self is Empty + #|} + #|fn ThreadSet::is_singleton(self : ThreadSet) -> Bool { + #| self is Node(l=Empty, r=Empty, ..) + #|} + #|fn ThreadSet::first(self : ThreadSet) -> Thread? { + #| match self { + #| Empty => None + #| Node(l=Empty, t~, ..) => Some(t) + #| Node(l~, ..) => l.first() + #| } + #|} + #|fn ThreadSet::choose(self : ThreadSet) -> Thread { + #| match self { + #| Node(l=Empty, t~, r=Empty, ..) => t + #| _ => panic() + #| } + #|} + #|fn ThreadSet::no_match(self : ThreadSet) -> Bool { + #| match self { + #| Empty => true + #| Node(i~, ..) => i.no_match + #| } + #|} + #|fn ThreadSet::make_node( + #| l : ThreadSet, + #| t : Thread, + #| r : ThreadSet, + #| p~ : Int, + #|) -> ThreadSet { + #| let i = ThreadSetNodeInfo::{ + #| no_match: !(t is End(_)) && l.no_match() && r.no_match(), + #| } + #| Node(i~, t~, l~, r~, p~) + #|} + #|let rand_state : @ref.Ref[Int] = @ref.Ref(0) + #|fn rand_int() -> Int { + #| rand_state.val = rand_state.val * 1664525 + 1013904223 + #| rand_state.val + #|} + #|fn ThreadSet::singleton(t : Thread) -> ThreadSet { + #| ThreadSet::make_node(Empty, t, Empty, p=rand_int()) + #|} + #|fn ThreadSet::merge(l : ThreadSet, r : ThreadSet) -> ThreadSet { + #| match (l, r) { + #| (Empty, r) => r + #| (l, Empty) => l + #| (Node(..) as l, Node(..) as r) => + #| if l.p > r.p { + #| ThreadSet::make_node(l.l, l.t, ThreadSet::merge(l.r, r), p=l.p) + #| } else { + #| ThreadSet::make_node(ThreadSet::merge(l, r.l), r.t, r.r, p=r.p) + #| } + #| } + #|} + #|impl Add for ThreadSet with add(self, other) { + #| ThreadSet::merge(self, other) + #|} + #|fn ThreadSet::flat_map( + #| self : ThreadSet, + #| f : (Thread) -> ThreadSet, + #|) -> ThreadSet { + #| match self { + #| Empty => Empty + #| Node(l~, t~, r~, ..) => { + #| let l2 = l.flat_map(f) + #| let t2 = f(t) + #| let r2 = r.flat_map(f) + #| l2 + t2 + r2 + #| } + #| } + #|} + #|fn ThreadSet::find_first_match(self : ThreadSet) -> MarkSlotMap? { + #| match self { + #| Empty => None + #| Node(i={ no_match: true }, ..) => None + #| Node(l=Empty, t=End(marks), ..) => Some(marks) + #| Node(l~, t~, r~, ..) => + #| match l.find_first_match() { + #| Some(marks) => Some(marks) + #| None => + #| match t { + #| End(marks) => Some(marks) + #| Exp(_) | Seq(_) => r.find_first_match() + #| } + #| } + #| } + #|} + #|fn ThreadSet::remove_matches(self : ThreadSet) -> ThreadSet { + #| match self { + #| Empty => Empty + #| Node(i={ no_match: true }, ..) => self + #| Node(l~, t~, r~, p~, ..) => + #| match t { + #| End(_) => l.remove_matches() + r.remove_matches() + #| Exp(_) | Seq(_) => + #| ThreadSet::make_node(l.remove_matches(), t, r.remove_matches(), p~) + #| } + #| } + #|} + #|fn ThreadSet::split_at_first_match(self : ThreadSet) -> (ThreadSet, ThreadSet) { + #| match self { + #| Empty => (Empty, Empty) + #| Node(i={ no_match: true }, ..) => (self, Empty) + #| Node(l=Empty | Node(i={ no_match: true }, ..) as l, t=End(_), r~, ..) => + #| (l, r) + #| Node( + #| l=Empty + #| | Node(i={ no_match: true }, ..) as l, + #| t=Exp(_) + #| | Seq(_) as t, + #| r~, + #| p~, + #| .. + #| ) => { + #| let (r1, r2) = r.split_at_first_match() + #| (ThreadSet::make_node(l, t, r1, p~), r2) + #| } + #| Node(l=Node(i={ no_match: false }, ..) as l, t~, r~, p~, ..) => { + #| let (l1, l2) = l.split_at_first_match() + #| (l1, ThreadSet::make_node(l2, t, r, p~)) + #| } + #| } + #|} + #|fn ThreadSet::remove_duplicates(self : ThreadSet, next : Expr) -> ThreadSet { + #| let seen = @hashset.HashSet::new() + #| for thread in self; result = ts_empty { + #| match thread { + #| End(_) => break result + ts_one(thread) + #| Exp(marks, { def: Eps, .. }) => + #| if !seen.contains(next.id) { + #| seen.add(next.id) + #| continue result + ts_exp(marks, next) + #| } else { + #| continue result + #| } + #| Exp(_, { id, .. }) => + #| if !seen.contains(id) { + #| seen.add(id) + #| continue result + ts_one(thread) + #| } else { + #| continue result + #| } + #| Seq(pref, first, next) => { + #| let first_dedup = first.remove_duplicates(next) + #| continue result + ts_seq(pref, first_dedup, next) + #| } + #| } + #| } nobreak { + #| result + #| } + #|} + #|fn ThreadSet::assign_slot(desc : ThreadSet, slot : Slot) -> ThreadSet { + #| guard slot.is_assigned() else { panic() } + #| desc.map(thread => { + #| match thread { + #| End(marks) => End(marks.assign_slot(slot)) + #| Exp(marks, expr) => Exp(marks.assign_slot(slot), expr) + #| Seq(pref, first, next) => Seq(pref, first.assign_slot(slot), next) + #| } + #| }) + #|} + #|fn ThreadSet::iter(self : ThreadSet) -> Iter[Thread] { + #| let mut node = self + #| let parents = [] + #| Iter::new(() => { + #| loop node { + #| Node(t=thread, l=Empty, r=right, ..) => { + #| node = right + #| Some(thread) + #| } + #| Node(t=thread, l=left, r=right, ..) => { + #| parents.push((thread, right)) + #| continue left + #| } + #| Empty if parents.pop() is Some((thread, right)) => { + #| node = right + #| Some(thread) + #| } + #| Empty => None + #| } + #| }) + #|} + #|fn ThreadSet::iter_marks(self : ThreadSet) -> Iter[MarkSlotMap] { + #| self + #| .iter() + #| .flat_map(thread => { + #| match thread { + #| End(marks) | Exp(marks, _) => Iter::singleton(marks) + #| Seq(_pref, first, _next) => first.iter_marks() + #| } + #| }) + #|} + #|fn ThreadSet::map(self : ThreadSet, f : (Thread) -> Thread) -> ThreadSet { + #| match self { + #| Empty => Empty + #| Node(l~, t~, r~, p~, ..) => { + #| let l2 = l.map(f) + #| let b2 = f(t) + #| let r2 = r.map(f) + #| ThreadSet::make_node(l2, b2, r2, p~) + #| } + #| } + #|} + #|let ts_empty : ThreadSet = Empty + #|fn ts_one(t : Thread) -> ThreadSet { + #| ThreadSet::singleton(t) + #|} + #|fn ts_end(marks : MarkSlotMap) -> ThreadSet { + #| ts_one(End(marks)) + #|} + #|fn ts_exp(marks : MarkSlotMap, expr : Expr) -> ThreadSet { + #| ts_one(Exp(marks, expr)) + #|} + #|fn ts_seq( + #| pref : @shared_types.Preference, + #| first : ThreadSet, + #| next : Expr, + #|) -> ThreadSet { + #| if first.is_empty() { + #| ts_empty + #| } else if first.is_singleton() && + #| first.choose() is Exp(marks, { def: Eps, .. }) { + #| ts_exp(marks, next) + #| } else { + #| ts_one(Seq(pref, first, next)) + #| } + #|} + #|impl Eq for ThreadSet with equal(self, other) { + #| let it1 = self.iter() + #| let it2 = other.iter() + #| loop (it1.next(), it2.next()) { + #| (None, None) => true + #| (None, Some(_)) | (Some(_), None) => false + #| (Some(b1), Some(b2)) => + #| if b1 == b2 { + #| continue (it1.next(), it2.next()) + #| } else { + #| false + #| } + #| } + #|} + #|impl Hash for ThreadSet with hash_combine(self, hasher) { + #| for thread in self { + #| hasher.combine(thread) + #| } + #|} + ), + "using.mbt": "" + } +) + +///| +let moonbitlang_core_internal_regex_engine_shared_types_module : RuntimePackage = RuntimePackage::new( + "moonbitlang/core/internal/regex_engine/shared_types", + deps={ }, + files={ + "category.mbt": ( + #|pub struct Category(Int) derive(Eq, Hash) + #|pub fn Category::dummy() -> Category { + #| Category(-1) + #|} + #|pub fn Category::inexistant() -> Category { + #| Category(1) + #|} + #|pub fn Category::word() -> Category { + #| Category(2) + #|} + #|pub fn Category::not_word_start() -> Category { + #| Category(4) + #|} + #|pub fn Category::not_word_end() -> Category { + #| Category(8) + #|} + #|pub fn Category::not_word() -> Category { + #| Category(4 | 8) + #|} + #|pub fn Category::newline() -> Category { + #| Category(16) + #|} + #|pub fn Category::inexistant_or_newline() -> Category { + #| Category(1 | 16) + #|} + #|pub fn Category::inexistant_or_non_word_start() -> Category { + #| Category(1 | 4) + #|} + #|pub fn Category::inexistant_or_non_word_end() -> Category { + #| Category(1 | 8) + #|} + #|pub impl Add for Category with add(cat1, cat2) { + #| Category(cat1.0 | cat2.0) + #|} + #|pub fn Category::intersects(a : Category, b : Category) -> Bool { + #| (a.0 & b.0) != 0 + #|} + ), + "preference.mbt": ( + #|pub(all) enum Preference { + #| Shortest + #| Longest + #| First + #|} derive(Eq, Hash, Debug) + ), + "profile.mbt": ( + #|pub struct Profile { + #| lb : Rechar + #| ub : Rechar + #| valid : RecharSet + #| word : RecharSet + #| word_symbolize_splits : ReadOnlyArray[RecharSet] + #| category : (Rechar) -> Category + #| fn new( + #| valid~ : RecharSet, + #| word~ : RecharSet, + #| word_symbolize_splits? : ReadOnlyArray[RecharSet], + #| category~ : (Rechar) -> Category, + #| ) -> Profile + #|} + #|pub fn Profile::new( + #| valid~ : RecharSet, + #| word~ : RecharSet, + #| word_symbolize_splits? : ReadOnlyArray[RecharSet] = [word], + #| category~ : (Rechar) -> Category, + #|) -> Profile { + #| guard valid.first_interval() is Some((lb, _)) else { panic() } + #| guard valid.last_interval() is Some((_, ub)) else { panic() } + #| Profile::{ lb, ub, valid, word, word_symbolize_splits, category } + #|} + ), + "quantifier_mode.mbt": ( + #|pub(all) enum QuantifierMode { + #| Greedy + #| NonGreedy + #|} derive(Debug) + ), + "rechar.mbt": ( + #|pub using @rechar_set {type Rechar} + ), + "rechar_set.mbt": ( + #|pub using @rechar_set {type RecharSet} + ), + "using.mbt": ( + #|using @debug {trait Debug, type Repr} + #|fn[T : Debug] _suppress_unused_warning_of_debug_trait(x : T) -> Unit { + #| ignore(x.to_repr()) + #|} + ) + } +) + +///| +let moonbitlang_core_internal_regex_engine_shared_types_rechar_set_module : RuntimePackage = RuntimePackage::new( + "moonbitlang/core/internal/regex_engine/shared_types/rechar_set", + deps={ }, + files={ + "rechar.mbt": ( + #|pub type Rechar = Int + ), + "rechar_set.mbt": ( + #|struct RecharSet(Tree) + #|pub fn RecharSet::empty() -> RecharSet { + #| RecharSet(Empty) + #|} + #|pub fn RecharSet::char(c : Rechar) -> RecharSet { + #| RecharSet(nn(Empty, c, c, Empty)) + #|} + #|pub fn RecharSet::char_range(lo : Rechar, hi : Rechar) -> RecharSet { + #| guard lo <= hi else { panic() } + #| RecharSet(nn(Empty, lo, hi, Empty)) + #|} + #|pub fn RecharSet::is_empty(self : RecharSet) -> Bool { + #| self.0 is Empty + #|} + #|pub fn RecharSet::is_subset(self : RecharSet, other : RecharSet) -> Bool { + #| difference(self.0, other.0) is Empty + #|} + #|pub fn RecharSet::first_interval(self : RecharSet) -> (Rechar, Rechar)? { + #| leftmost(self.0) + #|} + #|pub fn RecharSet::last_interval(self : RecharSet) -> (Rechar, Rechar)? { + #| rightmost(self.0) + #|} + #|pub fn RecharSet::contains(self : RecharSet, c : Rechar) -> Bool { + #| loop self.0 { + #| Empty => false + #| Node(l~, lo~, hi~, r~, ..) => + #| if c < lo { + #| continue l + #| } else if c > hi { + #| continue r + #| } else { + #| true + #| } + #| } + #|} + #|fn slice_from(t : Tree, c : Rechar) -> Tree { + #| match t { + #| Empty => Empty + #| Node(l~, lo~, hi~, r~, ..) => + #| if c < lo { + #| bal(slice_from(l, c), lo, hi, r) + #| } else if c > hi { + #| slice_from(r, c) + #| } else { + #| bal(Empty, c, hi, r) + #| } + #| } + #|} + #|fn slice_until(t : Tree, c : Rechar) -> Tree { + #| match t { + #| Empty => Empty + #| Node(l~, lo~, hi~, r~, ..) => + #| if c < lo { + #| slice_until(l, c) + #| } else if c > hi { + #| bal(l, lo, hi, slice_until(r, c)) + #| } else { + #| bal(l, lo, c, Empty) + #| } + #| } + #|} + #|fn slice_before(t : Tree, c : Rechar) -> Tree { + #| if c - 1 >= c { + #| Empty + #| } else { + #| slice_until(t, c - 1) + #| } + #|} + #|fn slice_after(tree : Tree, c : Rechar) -> Tree { + #| if c + 1 <= c { + #| Empty + #| } else { + #| slice_from(tree, c + 1) + #| } + #|} + #|fn leftmost(t : Tree) -> (Rechar, Rechar)? { + #| match t { + #| Empty => None + #| Node(l=Empty, lo~, hi~, ..) => Some((lo, hi)) + #| Node(l~, ..) => leftmost(l) + #| } + #|} + #|fn rightmost(t : Tree) -> (Rechar, Rechar)? { + #| match t { + #| Empty => None + #| Node(lo~, hi~, r=Empty, ..) => Some((lo, hi)) + #| Node(r~, ..) => rightmost(r) + #| } + #|} + #|fn try_merge_left(lo : Rechar, t : Tree) -> (Rechar, Tree) { + #| fn remove_leftmost(t : Tree) -> Tree { + #| match t { + #| Empty => panic() + #| Node(l=Empty, r~, ..) => r + #| Node(l~, lo~, hi~, r~, ..) => bal(remove_leftmost(l), lo, hi, r) + #| } + #| } + #| if leftmost(t) is Some((lo2, hi2)) && hi2 + 1 >= lo { + #| (lo2, remove_leftmost(t)) + #| } else { + #| (lo, t) + #| } + #|} + #|fn try_merge_right(hi : Rechar, t : Tree) -> (Rechar, Tree) { + #| fn remove_rightmost(t : Tree) -> Tree { + #| match t { + #| Empty => panic() + #| Node(l~, r=Empty, ..) => l + #| Node(l~, lo~, hi~, r~, ..) => bal(l, lo, hi, remove_rightmost(r)) + #| } + #| } + #| if rightmost(t) is Some((lo2, hi2)) && lo2 - 1 <= hi { + #| (hi2, remove_rightmost(t)) + #| } else { + #| (hi, t) + #| } + #|} + #|fn union(t1 : Tree, t2 : Tree) -> Tree { + #| match (t1, t2) { + #| (Empty, t) | (t, Empty) => t + #| (Node(w=w1, ..), Node(w=w2, ..)) => { + #| let (larger, smaller) = if w1 >= w2 { (t1, t2) } else { (t2, t1) } + #| guard larger is Node(l~, lo~, hi~, r~, ..) else { panic() } + #| let (lo, l) = { + #| let p = lo - 1 + #| if p >= lo { + #| (lo, Empty) + #| } else { + #| let l = union(l, slice_before(smaller, lo)) + #| try_merge_left(lo, l) + #| } + #| } + #| let (hi, r) = { + #| let s = hi + 1 + #| if s <= hi { + #| (hi, Empty) + #| } else { + #| let r = union(r, slice_after(smaller, hi)) + #| try_merge_right(hi, r) + #| } + #| } + #| bal(l, lo, hi, r) + #| } + #| } + #|} + #|fn intersection(t1 : Tree, t2 : Tree) -> Tree { + #| match (t1, t2) { + #| (Empty, _) | (_, Empty) => Empty + #| (Node(w=w1, ..), Node(w=w2, ..)) => { + #| let (larger, smaller) = if w1 >= w2 { (t1, t2) } else { (t2, t1) } + #| guard larger is Node(l~, lo~, hi~, r~, ..) else { panic() } + #| let left = intersection(l, slice_before(smaller, lo)) + #| let right = intersection(r, slice_after(smaller, hi)) + #| let middle = slice_until(slice_from(smaller, lo), hi) + #| cat(left, cat(middle, right)) + #| } + #| } + #|} + #|fn complement(t : Tree) -> Tree { + #| fn aux(lo : Rechar, hi : Rechar, t : Tree) -> Tree { + #| match t { + #| Empty => nn(Empty, lo, hi, Empty) + #| Node(l~, lo=ilo, hi=ihi, r~, ..) => { + #| let left = { + #| let p = ilo - 1 + #| if p < ilo { + #| aux(lo, p, l) + #| } else { + #| Empty + #| } + #| } + #| let right = { + #| let s = ihi + 1 + #| if s > ihi { + #| aux(s, hi, r) + #| } else { + #| Empty + #| } + #| } + #| cat(left, right) + #| } + #| } + #| } + #| aux(-0x80000000, 0x7FFFFFFF, t) + #|} + #|fn difference(t1 : Tree, t2 : Tree) -> Tree { + #| intersection(t1, complement(t2)) + #|} + #|pub fn RecharSet::union(self : RecharSet, other : RecharSet) -> RecharSet { + #| RecharSet(union(self.0, other.0)) + #|} + #|pub fn RecharSet::intersection( + #| self : RecharSet, + #| other : RecharSet, + #|) -> RecharSet { + #| RecharSet(intersection(self.0, other.0)) + #|} + #|pub fn RecharSet::difference(self : RecharSet, other : RecharSet) -> RecharSet { + #| RecharSet(difference(self.0, other.0)) + #|} + #|pub fn RecharSet::offset_by(self : RecharSet, f : (Int) -> Int) -> RecharSet { + #| fn aux(t : Tree) -> Tree { + #| match t { + #| Empty => Empty + #| Node(l~, lo~, hi~, r~, ..) => bal(aux(l), f(lo), f(hi), aux(r)) + #| } + #| } + #| RecharSet(aux(self.0)) + #|} + #|pub fn RecharSet::intervals(self : RecharSet) -> Iter[(Rechar, Rechar)] { + #| let mut node = self.0 + #| let parents = [] + #| Iter::new(fn() { + #| loop node { + #| Node(l=Empty, lo~, hi~, r~, ..) => { + #| node = r + #| Some((lo, hi)) + #| } + #| Node(l~, lo~, hi~, r~, ..) => { + #| parents.push((lo, hi, r)) + #| continue l + #| } + #| Empty if parents.pop() is Some((lo, hi, r)) => { + #| node = r + #| Some((lo, hi)) + #| } + #| Empty => None + #| } + #| }) + #|} + #|pub fn RecharSet::from_sorted_array( + #| arr : ArrayView[(Rechar, Rechar)], + #|) -> RecharSet { + #| RecharSet(build(arr, 0, arr.length() - 1)) + #|} + #|pub impl Add for RecharSet with add(self, other) { + #| RecharSet::union(self, other) + #|} + #|pub impl Sub for RecharSet with sub(self, other) { + #| RecharSet::difference(self, other) + #|} + #|pub impl BitAnd for RecharSet with land(self, other) { + #| RecharSet::intersection(self, other) + #|} + #|pub impl @debug.Debug for RecharSet with to_repr(self) { + #| @debug.Debug::to_repr(self.intervals().to_array()) + #|} + ), + "tree.mbt": ( + #|priv enum Tree { + #| Empty + #| Node(l~ : Tree, lo~ : Rechar, hi~ : Rechar, r~ : Tree, w~ : Int) + #|} + #|#inline + #|fn nw(tree : Tree) -> Int { + #| match tree { + #| Tree::Empty => 1 + #| Tree::Node(..) as n => n.w + #| } + #|} + #|#inline + #|fn nnw(l : Tree, lo : Rechar, hi : Rechar, r : Tree, w : Int) -> Tree { + #| Node(l~, lo~, hi~, r~, w~) + #|} + #|#inline + #|fn nn(l : Tree, lo : Rechar, hi : Rechar, r : Tree) -> Tree { + #| nnw(l, lo, hi, r, nw(l) + nw(r)) + #|} + #|fn bal(l : Tree, lo : Rechar, hi : Rechar, r : Tree) -> Tree { + #| let lw = nw(l) + #| let rw = nw(r) + #| if rw > 3 * lw { + #| guard r is (Node(..) as r) else { panic() } + #| let rlw = nw(r.l) + #| let rrw = nw(r.r) + #| if rlw < 2 * rrw { + #| let lw = lw + rlw + #| nnw(nnw(l, lo, hi, r.l, lw), r.lo, r.hi, r.r, lw + rrw) + #| } else { + #| guard r.l is (Node(..) as rl) else { panic() } + #| let lw = lw + rlw + #| let rw = nw(rl.r) + rrw + #| nnw( + #| nnw(l, lo, hi, rl.l, lw), + #| rl.lo, + #| rl.hi, + #| nnw(rl.r, r.lo, r.hi, r.r, rw), + #| lw + rw, + #| ) + #| } + #| } else if lw > 3 * rw { + #| guard l is (Node(..) as l) else { panic() } + #| let llw = nw(l.l) + #| let lrw = nw(l.r) + #| if lrw < 2 * llw { + #| let rw = rw + lrw + #| nnw(l.l, l.lo, l.hi, nnw(l.r, lo, hi, r, lrw + rw), llw + rw) + #| } else { + #| guard l.r is (Node(..) as lr) else { panic() } + #| let lw = nw(lr.l) + llw + #| let rw = rw + lrw + #| nnw( + #| nnw(l.l, l.lo, l.hi, lr.l, lw), + #| lr.lo, + #| lr.hi, + #| nnw(lr.r, lo, hi, r, rw), + #| lw + rw, + #| ) + #| } + #| } else { + #| nn(l, lo, hi, r) + #| } + #|} + #|fn cat(l : Tree, r : Tree) -> Tree { + #| match (l, r) { + #| (Tree::Empty, r) => r + #| (l, Tree::Empty) => l + #| (Tree::Node(..) as l, Tree::Node(..) as r) => { + #| fn go(r : Tree) -> Tree { + #| match r { + #| Empty => panic() + #| Node(l=Empty, lo~, hi~, r~, ..) => nn(l, lo, hi, r) + #| Node(l=Node(_) as l, lo~, hi~, r~, ..) => bal(go(l), lo, hi, r) + #| } + #| } + #| go(r) + #| } + #| } + #|} + #|fn build(arr : ArrayView[(Rechar, Rechar)], lo : Int, hi : Int) -> Tree { + #| if lo > hi { + #| Empty + #| } else if lo == hi { + #| let (l, h) = arr[lo] + #| nn(Empty, l, h, Empty) + #| } else { + #| let mid = (lo + hi) / 2 + #| let (l, h) = arr[mid] + #| let left = build(arr, lo, mid - 1) + #| let right = build(arr, mid + 1, hi) + #| nn(left, l, h, right) + #| } + #|} + ) + } ) ///| let moonbitlang_core_json_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/json", - deps={ - "moonbitlang/core/array": moonbitlang_core_array_module, - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/char": moonbitlang_core_char_module, - "moonbitlang/core/double": moonbitlang_core_double_module, - "moonbitlang/core/float": moonbitlang_core_float_module, - "moonbitlang/core/string": moonbitlang_core_string_module, - "moonbitlang/core/strconv": moonbitlang_core_strconv_module, - "moonbitlang/core/option": moonbitlang_core_option_module, - "moonbitlang/core/buffer": moonbitlang_core_buffer_module, - }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| "moonbitlang/core/array", - #| "moonbitlang/core/builtin", - #| "moonbitlang/core/char", - #| "moonbitlang/core/double", - #| "moonbitlang/core/float", - #| "moonbitlang/core/string", - #| "moonbitlang/core/strconv", - #| "moonbitlang/core/option", - #| "moonbitlang/core/buffer" - #| ], - #| "test-import": [ - #| "moonbitlang/core/result", - #| "moonbitlang/core/unit", - #| "moonbitlang/core/bigint", - #| "moonbitlang/core/bytes" - #| ] - #|} - ), - "deprecated.mbt": "", - "from_json.mbt": ( - #|pub(all) suberror JsonDecodeError (JsonPath, String) derive(Eq, Show, ToJson) - #|pub(open) trait FromJson { - #| from_json(Json, JsonPath) -> Self raise JsonDecodeError - #|} - #|pub fn[T : FromJson] from_json( - #| json : Json, - #| path? : JsonPath = Root, - #|) -> T raise JsonDecodeError { - #| FromJson::from_json(json, path) - #|} - #|fn[T] decode_error(path : JsonPath, msg : String) -> T raise JsonDecodeError { - #| raise JsonDecodeError((path, msg)) - #|} - #|pub impl FromJson for Bool with from_json(json, path) { - #| match json { - #| true => true - #| false => false - #| _ => decode_error(path, "Bool::from_json: expected boolean") - #| } - #|} - #|pub impl FromJson for Int with from_json(json, path) { - #| guard json is Number(n, ..) && - #| n != @double.infinity && - #| n != @double.neg_infinity else { - #| decode_error(path, "Int::from_json: expected number") - #| } - #| let max_ok = 2147483647.0 - #| let min_ok = -2147483648.0 - #| if n > max_ok || n < min_ok { - #| decode_error(path, "Int::from_json: overflow") - #| } - #| n.to_int() - #|} - #|pub impl FromJson for Int64 with from_json(json, path) { - #| guard json is String(str) else { - #| decode_error( - #| path, "Int64::from_json: expected number in string representation", - #| ) - #| } - #| @strconv.parse_int64(str) catch { - #| error => decode_error(path, "Int64::from_json: parsing failure \{error}") - #| } - #|} - #|pub impl FromJson for UInt with from_json(json, path) { - #| guard json is Number(n, ..) && - #| n != @double.infinity && - #| n != @double.neg_infinity else { - #| decode_error(path, "UInt::from_json: expected number") - #| } - #| let max_ok = 4294967295.0 - #| if n < 0.0 || n > max_ok { - #| decode_error(path, "UInt::from_json: overflow") - #| } - #| n.to_uint() - #|} - #|pub impl FromJson for UInt64 with from_json(json, path) { - #| guard json is String(str) else { - #| decode_error( - #| path, "UInt64::from_json: expected number in string representation", - #| ) - #| } - #| @strconv.parse_uint64(str) catch { - #| error => decode_error(path, "UInt64::from_json: parsing failure \{error}") - #| } - #|} - #|pub impl FromJson for Double with from_json(json, path) { - #| match json { - #| String("NaN") => @double.not_a_number - #| String("Infinity") => @double.infinity - #| String("-Infinity") => @double.neg_infinity - #| Number(n, ..) if n != @double.infinity && n != @double.neg_infinity => n - #| _ => decode_error(path, "Double::from_json: expected number") - #| } - #|} - #|pub impl FromJson for Float with from_json(json, path) { - #| match json { - #| String("NaN") => @float.not_a_number - #| String("Infinity") => @float.infinity - #| String("-Infinity") => @float.neg_infinity - #| Number(n, ..) if n != @double.infinity && n != @double.neg_infinity => - #| Float::from_double(n) - #| _ => decode_error(path, "Float::from_json: expected number") - #| } - #|} - #|pub impl FromJson for String with from_json(json, path) { - #| guard json is String(a) else { - #| decode_error(path, "String::from_json: expected string") - #| } - #| a - #|} - #|pub impl FromJson for StringView with from_json(json, path) { - #| guard json is String(a) else { - #| decode_error(path, "View::from_json: expected string") - #| } - #| a[:] - #|} - #|pub impl FromJson for Char with from_json(json, path) { - #| guard json is String(a) else { - #| decode_error(path, "Char::from_json: expected string") - #| } - #| let len = a.length() - #| if len == 1 { - #| a.unsafe_charcode_at(0).unsafe_to_char() - #| } else if len == 2 { - #| let c1 = a.unsafe_charcode_at(0) - #| let c2 = a.unsafe_charcode_at(1) - #| if c1 is (0xD800..=0xDBFF) && c2 is (0xDC00..=0xDFFF) { - #| let c3 = (c1 << 10) + c2 - 0x35fdc00 - #| c3.unsafe_to_char() - #| } else { - #| decode_error(path, "Char::from_json: invalid surrogate pair") - #| } - #| } else { - #| decode_error(path, "Char::from_json: expected single character") - #| } - #|} - #|pub impl[X : FromJson] FromJson for Array[X] with from_json(json, path) { - #| guard json is Array(a) else { - #| decode_error(path, "Array::from_json: expected array") - #| } - #| guard JsonPath::Index(path, index=0) is (Index(_) as new_path) - #| a.mapi((i, x) => { - #| new_path.index = i - #| FromJson::from_json(x, new_path) - #| }) - #|} - #|pub impl[X : FromJson] FromJson for ArrayView[X] with from_json(json, path) { - #| guard json is Array(a) else { - #| decode_error(path, "ArrayView::from_json: expected array") - #| } - #| guard JsonPath::Index(path, index=0) is (Index(_) as new_path) - #| a.mapi((i, x) => { - #| new_path.index = i - #| FromJson::from_json(x, new_path) - #| }) - #|} - #|pub impl[X : FromJson] FromJson for FixedArray[X] with from_json(json, path) { - #| guard json is Array(a) else { - #| decode_error(path, "FixedArray::from_json: expected array") - #| } - #| let len = a.length() - #| if len == 0 { - #| return [] - #| } - #| guard JsonPath::Index(path, index=0) is (Index(_) as new_path) - #| let res = FixedArray::make( - #| len, - #| FromJson::from_json(a.unsafe_get(0), new_path), - #| ) - #| for i in 1.. None - #| Array([value]) => Some(FromJson::from_json(value, path.add_index(0))) - #| _ => decode_error(path, "Option::from_json: expected array or null") - #| } - #|} - #|pub impl[Ok : FromJson, Err : FromJson] FromJson for Result[Ok, Err] with from_json( - #| json, - #| path, - #|) { - #| guard json is Object(obj) else { - #| decode_error(path, "Result::from_json: expected object") - #| } - #| if obj.length() != 1 { - #| decode_error(path, "Result::from_json: expected object with one field") - #| } - #| match obj { - #| { "Ok": ok, .. } => Ok(FromJson::from_json(ok, path.add_key("Ok"))) - #| { "Err": err, .. } => Err(FromJson::from_json(err, path.add_key("Err"))) - #| _ => - #| decode_error( - #| path, "Result::from_json: expected object with Ok or Err field", - #| ) - #| } - #|} - #|pub impl FromJson for Unit with from_json(json, path) { - #| guard json is Null else { - #| decode_error(path, "Unit::from_json: expected null") - #| } - #|} - #|pub impl FromJson for Json with from_json(json, _path) { - #| json - #|} - #|pub impl FromJson for Bytes with from_json(json, path) { - #| guard json is String(a) else { - #| decode_error(path, "Bytes::from_json: expected string") - #| } - #| let buffer = @buffer.new(size_hint=a.length()) - #| loop a[:] { - #| [] => () - #| [.. "\\x", '0'..='9' | 'a'..='f' as x, '0'..='9' | 'a'..='f' as y, .. rest] => { - #| let upper = (x.to_int() & 0xF) + (x.to_int() >> 6) * 9 - #| let lower = (y.to_int() & 0xF) + (y.to_int() >> 6) * 9 - #| buffer.write_byte(((upper << 4) | lower).to_byte()) - #| continue rest - #| } - #| [' '..='~' as ch, .. rest] => { - #| guard ch != '\\' && ch != '"' else { - #| decode_error(path, "Bytes::from_json: invalid escape sequence") - #| } - #| buffer.write_byte(ch.to_uint().to_byte()) - #| continue rest - #| } - #| _ => decode_error(path, "Bytes::from_json: invalid byte sequence") - #| } - #| buffer.to_bytes() - #|} - ), - "internal_types.mbt": ( - #|priv struct ParseContext { - #| mut offset : Int - #| input : StringView - #| end_offset : Int - #| mut remaining_available_depth : Int - #|} - #|fn ParseContext::make( - #| input : StringView, - #| max_nesting_depth : Int, - #|) -> ParseContext { - #| { - #| offset: 0, - #| input, - #| end_offset: input.length(), - #| remaining_available_depth: max_nesting_depth, - #| } - #|} - #|priv struct CharClass(Array[(Char, Char)]) - #|fn CharClass::of(array : Array[(Char, Char)]) -> CharClass { - #| CharClass(array) - #|} - #|fn CharClass::contains(self : CharClass, c : Char) -> Bool { - #| let CharClass(self) = self - #| for left = 0, right = self.length(); left < right; { - #| let middle = (left + right) / 2 - #| let (min, max) = self[middle] - #| if c < min { - #| continue left, middle - #| } else if c > max { - #| continue middle + 1, right - #| } else { - #| break true - #| } - #| } else { - #| false - #| } - #|} - #|priv enum Token { - #| Null - #| True - #| False - #| Number(Double, String?) - #| String(String) - #| LBrace - #| RBrace - #| LBracket - #| RBracket - #| Comma - #|} - ), - "json.mbt": ( - #|#deprecated("Suggestion: `if json is Null { Some(()) } else { None }`") - #|pub fn Json::as_null(self : Json) -> Unit? { - #| guard self is Null else { return None } - #| Some(()) - #|} - #|#deprecated("Suggestion: `if json is True { Some(true) } else if json is False { Some(false) } else { None }`") - #|pub fn Json::as_bool(self : Json) -> Bool? { - #| match self { - #| True => Some(true) - #| False => Some(false) - #| _ => None - #| } - #|} - #|#deprecated("Suggestion: `if json is Number(n) { Some(n) } else { None }`") - #|pub fn Json::as_number(self : Json) -> Double? { - #| guard self is Number(n, ..) else { return None } - #| Some(n) - #|} - #|#deprecated("Suggestion: `if json is String(s) { Some(s) } else { None }`") - #|pub fn Json::as_string(self : Json) -> String? { - #| guard self is String(s) else { return None } - #| Some(s) - #|} - #|#deprecated("Suggestion: `if json is Array(array) { Some(array) } else { None }`") - #|pub fn Json::as_array(self : Json) -> Array[Json]? { - #| guard self is Array(arr) else { return None } - #| Some(arr) - #|} - #|#deprecated("Suggestion: `if json is Array(array) { array.get(index) } else { None }`") - #|pub fn Json::item(self : Json, index : Int) -> Json? { - #| if self is Array(arr) { - #| arr.get(index) - #| } else { - #| None - #| } - #|} - #|#deprecated - #|pub fn Json::as_object(self : Json) -> Map[String, Json]? { - #| guard self is Object(obj) else { return None } - #| Some(obj) - #|} - #|#deprecated("Suggestion: `if json is Object(obj) { obj.get(key) } else { None }`") - #|pub fn Json::value(self : Json, key : String) -> Json? { - #| if self is Object(obj) { - #| obj.get(key) - #| } else { - #| None - #| } - #|} - #|fn indent_str(level : Int, indent : Int) -> String { - #| if indent == 0 { - #| "" - #| } else { - #| let spaces = indent * level - #| match spaces { - #| 0 => "\n" - #| 1 => "\n " - #| 2 => "\n " - #| 3 => "\n " - #| 4 => "\n " - #| 5 => "\n " - #| 6 => "\n " - #| 7 => "\n " - #| 8 => "\n " - #| _ => "\n" + " ".repeat(spaces) - #| } - #| } - #|} - #|priv enum WriteFrame { - #| Array(Array[Json], mut i~ : Int) // (arr, index) - #| Object(Iterator[(String, Json)], mut first~ : Bool) // (kvs, first) - #|} - #|struct Replacer((String, Json) -> Json?) - #|pub fn Replacer::new(f : (String, Json) -> Json?) -> Replacer { - #| Replacer(f) - #|} - #|pub fn Replacer::keep(array : ArrayView[StringView]) -> Replacer { - #| Replacer((idx, value) => if array.contains(idx) { Some(value) } else { None }) - #|} - #|pub fn Replacer::exclude(array : ArrayView[StringView]) -> Replacer { - #| Replacer((idx, value) => if array.contains(idx) { None } else { Some(value) }) - #|} - #|pub fn Json::stringify( - #| self : Json, - #| escape_slash? : Bool = false, - #| indent? : Int = 0, - #| replacer? : Replacer, - #|) -> String { - #| let buf = StringBuilder::new(size_hint=0) - #| let stack : Array[WriteFrame] = [] - #| let mut depth = 0 - #| loop Some(self) { - #| Some(value) => { - #| match value { - #| Object(members) => - #| if members.is_empty() { - #| buf.write_string("{}") - #| } else { - #| depth += 1 - #| buf.write_char('{') - #| buf.write_string(indent_str(depth, indent)) - #| stack.push(WriteFrame::Object(members.iterator(), first=true)) - #| } - #| Array(arr) => - #| if arr.is_empty() { - #| buf.write_string("[]") - #| } else { - #| depth += 1 - #| buf.write_char('[') - #| buf.write_string(indent_str(depth, indent)) - #| stack.push(WriteFrame::Array(arr, i=0)) - #| } - #| String(s) => - #| buf - #| ..write_char('\"') - #| ..write_string(escape(s, escape_slash~)) - #| ..write_char('\"') - #| Number(n, repr~) => - #| match repr { - #| None => buf.write_object(n) - #| Some(r) => buf.write_string(r) - #| } - #| True => buf.write_string("true") - #| False => buf.write_string("false") - #| Null => buf.write_string("null") - #| } - #| continue None - #| } - #| None => - #| match stack { - #| [] => break - #| [.., WriteFrame::Array(arr, i~) as frame] => - #| if i < arr.length() { - #| let element = arr[i] - #| frame.i = i + 1 - #| if i > 0 { - #| buf.write_char(',') - #| buf.write_string(indent_str(depth, indent)) - #| } - #| continue Some(element) - #| } else { - #| depth -= 1 - #| ignore(stack.pop()) - #| buf.write_string(indent_str(depth, indent)) - #| buf.write_char(']') - #| continue None - #| } - #| [.., WriteFrame::Object(iterator, first~) as frame] => - #| match iterator.next() { - #| Some((k, v)) => { - #| let mut v2 = v - #| if replacer is Some(replacer) { - #| if replacer(k, v) is Some(v) { - #| v2 = v - #| } else { - #| continue None - #| } - #| } - #| if !first { - #| buf.write_char(',') - #| buf.write_string(indent_str(depth, indent)) - #| } - #| buf - #| ..write_char('\"') - #| ..write_string(escape(k, escape_slash~)) - #| ..write_char('\"') - #| ..write_char(':') - #| if indent > 0 { - #| buf.write_char(' ') - #| } - #| frame.first = false - #| continue Some(v2) - #| } - #| None => { - #| depth -= 1 - #| ignore(stack.pop()) - #| buf.write_string(indent_str(depth, indent)) - #| buf.write_char('}') - #| continue None - #| } - #| } - #| } - #| } - #| buf.to_string() - #|} - #|fn escape(str : String, escape_slash~ : Bool) -> String { - #| let buf = StringBuilder::new(size_hint=str.length()) - #| for c in str { - #| match c { - #| '"' => buf.write_string("\\\"") - #| '\\' => buf.write_string("\\\\") - #| '/' => - #| if escape_slash { - #| buf.write_string("\\/") - #| } else { - #| buf.write_char(c) - #| } - #| '\n' => buf.write_string("\\n") - #| '\r' => buf.write_string("\\r") - #| '\b' => buf.write_string("\\b") - #| '\t' => buf.write_string("\\t") - #| _ => { - #| let code = c.to_int() - #| if code == 0x0C { - #| buf.write_string("\\f") - #| } else if code < ' ' { - #| buf.write_string("\\u00") - #| buf.write_string(code.to_byte().to_hex()) - #| } else { - #| buf.write_char(c) - #| } - #| } - #| } - #| } - #| buf.to_string() - #|} - #|pub fn Json::transform(self : Self, replacer : Replacer) -> Json { - #| match self { - #| Object(members) => - #| members - #| .iterator() - #| .filter_map(pair => { - #| let (k, v) = pair - #| if replacer(k, v) is Some(v2) { - #| Some((k, v2.transform(replacer))) - #| } else { - #| None - #| } - #| }) - #| |> Map::from_iterator() - #| |> Object - #| Array(members) => Array(members.map(m => m.transform(replacer))) - #| value => value - #| } - #|} - #|pub impl ToJson for Json with to_json(self) { - #| self - #|} - #|#callsite(autofill(args_loc, loc)) - #|pub fn inspect( - #| obj : &ToJson, - #| content? : Json, - #| loc~ : SourceLoc, - #| args_loc~ : ArgsLoc, - #|) -> Unit raise InspectError { - #| let loc = loc.to_json_string() - #| let args_loc = args_loc.to_json() - #| let actual = obj.to_json().stringify(escape_slash=false) - #| let want = match content { - #| None => "".to_json().stringify(escape_slash=false) - #| Some(x) => x.stringify(escape_slash=false) - #| } - #| if actual != want { - #| raise InspectError( - #| "@EXPECT_FAILED {\"loc\": \{loc}, \"args_loc\": \{args_loc}, \"expect\": \{want.escape()}, \"actual\": \{actual.escape()}, \"mode\": \"json\"}", - #| ) - #| } - #|} - ), - "json_path.mbt": ( - #|enum JsonPath { - #| Root - #| Key(JsonPath, mut key~ : String) - #| Index(JsonPath, mut index~ : Int) - #|} derive(Eq) - #|pub fn JsonPath::add_index(self : JsonPath, index : Int) -> JsonPath { - #| Index(self, index~) - #|} - #|pub fn JsonPath::add_key(self : JsonPath, key : String) -> JsonPath { - #| Key(self, key~) - #|} - #|pub impl Show for JsonPath with output(self, logger) { - #| fn write_token(logger : &Logger, token : String) -> Unit { - #| if !token.contains_any(chars="~/") { - #| logger.write_string(token) - #| return - #| } - #| for ch in token.iter() { - #| match ch { - #| '~' => logger.write_string("~0") - #| '/' => logger.write_string("~1") - #| _ => logger.write_char(ch) - #| } - #| } - #| } - #| fn build_path(path : JsonPath, logger : &Logger) -> Unit { - #| match path { - #| Root => () - #| Key(parent, key~) => { - #| build_path(parent, logger) - #| logger.write_char('/') - #| write_token(logger, key) - #| } - #| Index(parent, index~) => { - #| build_path(parent, logger) - #| logger.write_char('/') - #| logger.write_object(index) - #| } - #| } - #| } - #| build_path(self, logger) - #|} - #|pub impl ToJson for JsonPath with to_json(self) { - #| String(self.to_string()) - #|} - #|test "show JsonPath - JSON Pointer format" { - #| @builtin.inspect(Root, content="") - #| @builtin.inspect(Root.add_key("foo"), content="/foo") - #| @builtin.inspect(Root.add_index(0), content="/0") - #| let path : JsonPath = Key(Index(Root, index=0), key="foo") - #| @builtin.inspect(path, content="/0/foo") - #| @builtin.inspect(path.add_index(1), content="/0/foo/1") - #| @builtin.inspect(path.add_key("bar"), content="/0/foo/bar") - #| @builtin.inspect( - #| Root.add_key("foo").add_key("foo1").add_index(2), - #| content="/foo/foo1/2", - #| ) - #| @builtin.inspect(Root.add_key("foo").add_key("foo1"), content="/foo/foo1") - #| @builtin.inspect( - #| Root.add_key("foo").add_key("foo1").add_index(2).add_key("bar"), - #| content="/foo/foo1/2/bar", - #| ) - #| @builtin.inspect( - #| Root.add_key("foo").add_key("foo1").add_index(2).add_key("bar").add_index(3), - #| content="/foo/foo1/2/bar/3", - #| ) - #| @builtin.inspect( - #| Root - #| .add_key("foo") - #| .add_key("foo1") - #| .add_index(2) - #| .add_key("bar") - #| .add_index(3) - #| .add_key("baz"), - #| content="/foo/foo1/2/bar/3/baz", - #| ) - #| @builtin.inspect( - #| Root.add_key("foo").add_key("foo1").add_index(2).add_index(3).add_index(4), - #| content="/foo/foo1/2/3/4", - #| ) - #|} - #|test "show JsonPath - special characters escaping" { - #| @builtin.inspect(Root.add_key("foo~bar"), content="/foo~0bar") - #| @builtin.inspect(Root.add_key("foo~~bar~~"), content="/foo~0~0bar~0~0") - #| @builtin.inspect(Root.add_key("foo/bar"), content="/foo~1bar") - #| @builtin.inspect(Root.add_key("foo//bar//"), content="/foo~1~1bar~1~1") - #| @builtin.inspect(Root.add_key("foo~/bar"), content="/foo~0~1bar") - #| @builtin.inspect(Root.add_key("~foo/bar~"), content="/~0foo~1bar~0") - #| @builtin.inspect( - #| Root.add_key("a/b").add_key("c~d").add_index(0).add_key("e~/f"), - #| content="/a~1b/c~0d/0/e~0~1f", - #| ) - #| @builtin.inspect(Root.add_key(""), content="/") - #| @builtin.inspect(Root.add_key("~/"), content="/~0~1") - #|} - #|test "show JsonPath - RFC 6901 compliance examples" { - #| @builtin.inspect(Root, content="") - #| @builtin.inspect(Root.add_key("foo"), content="/foo") - #| @builtin.inspect(Root.add_key("foo").add_index(0), content="/foo/0") - #| @builtin.inspect(Root.add_key(""), content="/") - #| @builtin.inspect(Root.add_key("a/b"), content="/a~1b") - #| @builtin.inspect(Root.add_key("c%d"), content="/c%d") - #| @builtin.inspect(Root.add_key("e^f"), content="/e^f") - #| @builtin.inspect(Root.add_key("g|h"), content="/g|h") - #| @builtin.inspect(Root.add_key("i\\j"), content="/i\\j") - #| @builtin.inspect(Root.add_key("k\"l"), content="/k\"l") - #| @builtin.inspect(Root.add_key(" "), content="/ ") - #| @builtin.inspect(Root.add_key("m~n"), content="/m~0n") - #|} - ), - "lex_main.mbt": ( - #|let non_ascii_whitespace : CharClass = CharClass::of([ - #| ('\u00A0', '\u00A0'), - #| ('\u1680', '\u1680'), - #| ('\u2000', '\u200A'), - #| ('\u2028', '\u2029'), - #| ('\u202F', '\u202F'), - #| ('\u205F', '\u205F'), - #| ('\u3000', '\u3000'), - #| ('\uFEFF', '\uFEFF'), - #|]) - #|fn ParseContext::lex_value( - #| ctx : ParseContext, - #| allow_rbracket~ : Bool, - #|) -> Token raise ParseError { - #| for { - #| match ctx.read_char() { - #| Some('\t' | ' ' | '\n' | '\r') => continue - #| Some('{') => return LBrace - #| Some('[') => return LBracket - #| Some(']') => - #| if allow_rbracket { - #| return RBracket - #| } else { - #| ctx.invalid_char(shift=-1) - #| } - #| Some('n') => { - #| ctx.expect_ascii_char('u') - #| ctx.expect_ascii_char('l') - #| ctx.expect_ascii_char('l') - #| return Null - #| } - #| Some('t') => { - #| ctx.expect_ascii_char('r') - #| ctx.expect_ascii_char('u') - #| ctx.expect_ascii_char('e') - #| return True - #| } - #| Some('f') => { - #| ctx.expect_ascii_char('a') - #| ctx.expect_ascii_char('l') - #| ctx.expect_ascii_char('s') - #| ctx.expect_ascii_char('e') - #| return False - #| } - #| Some('-') => - #| match ctx.read_char() { - #| Some('0') => { - #| let (n, repr) = ctx.lex_zero(start=ctx.offset - 2) - #| return Number(n, repr.map(_.to_string())) - #| } - #| Some(c2) => { - #| if c2 is ('1'..='9') { - #| let (n, repr) = ctx.lex_decimal_integer(start=ctx.offset - 2) - #| return Number(n, repr.map(_.to_string())) - #| } - #| ctx.invalid_char(shift=-1) - #| } - #| None => raise InvalidEof - #| } - #| Some('0') => { - #| let (n, repr) = ctx.lex_zero(start=ctx.offset - 1) - #| return Number(n, repr.map(_.to_string())) - #| } - #| Some('1'..='9') => { - #| let (n, repr) = ctx.lex_decimal_integer(start=ctx.offset - 1) - #| return Number(n, repr.map(_.to_string())) - #| } - #| Some('"') => { - #| let s = ctx.lex_string() - #| return String(s) - #| } - #| Some(c) => { - #| if c > '\u{7f}' && non_ascii_whitespace.contains(c) { - #| continue - #| } - #| let shift = -c.utf16_len() - #| ctx.invalid_char(shift~) - #| } - #| None => raise InvalidEof - #| } - #| } - #|} - ), - "lex_misc.mbt": ( - #|fn ParseContext::read_char(ctx : ParseContext) -> Char? { - #| if ctx.offset < ctx.end_offset { - #| let c1 = ctx.input.unsafe_charcode_at(ctx.offset) - #| ctx.offset += 1 - #| if c1 >= 0xD800 && c1 <= 0xDBFF { - #| if ctx.offset < ctx.end_offset { - #| let c2 = ctx.input.unsafe_charcode_at(ctx.offset) - #| if c2 >= 0xDC00 && c2 <= 0xDFFF { - #| ctx.offset += 1 - #| let c3 = (c1 << 10) + c2 - 0x35fdc00 - #| return Some(c3.unsafe_to_char()) - #| } - #| } - #| } - #| Some(c1.unsafe_to_char()) - #| } else { - #| None - #| } - #|} - #|const SURROGATE_LOW_CHAR = 0xD800 - #|const SURROGATE_HIGH_CHAR = 0xDFFF - #|fn ParseContext::expect_char( - #| ctx : ParseContext, - #| c : Char, - #|) -> Unit raise ParseError { - #| guard ctx.offset < ctx.end_offset else { raise InvalidEof } - #| let c1 = ctx.input.unsafe_charcode_at(ctx.offset) - #| ctx.offset += 1 - #| let c0 = c.to_int() - #| if c0 < 0xFFFF { - #| if c0 != c1 { - #| ctx.invalid_char(shift=-1) - #| } - #| } else { - #| guard c1 is (SURROGATE_LOW_CHAR..=SURROGATE_HIGH_CHAR) && - #| ctx.offset < ctx.end_offset else { - #| ctx.invalid_char(shift=-1) - #| } - #| let c2 = ctx.input.unsafe_charcode_at(ctx.offset) - #| let c3 = (c1 << 10) + c2 - 0x35fdc00 - #| if c3 != c0 { - #| ctx.invalid_char(shift=-1) - #| } else { - #| ctx.offset += 1 // consume and move forward - #| } - #| } - #|} - #|fn ParseContext::expect_ascii_char( - #| ctx : ParseContext, - #| c : Byte, - #|) -> Unit raise ParseError { - #| guard ctx.offset < ctx.end_offset else { raise InvalidEof } - #| let c1 = ctx.input.unsafe_charcode_at(ctx.offset) - #| ctx.offset += 1 - #| if c.to_int() != c1 { - #| ctx.invalid_char(shift=-1) - #| } - #|} - #|test "expect_char" { - #| let ctx = ParseContext::make("abc", 1) - #| ctx.expect_char('a') - #| ctx.expect_char('b') - #| ctx.expect_char('c') - #| inspect(try? ctx.expect_char('d'), content={ "Err": "InvalidEof" }) - #|} - #|test "expect_char with surrogate pair" { - #| let ctx = ParseContext::make("a\u{1F600}bc\u{1F600}c", 1) - #| ctx.expect_char('a') - #| ctx.expect_char((0x1F600).unsafe_to_char()) - #| ctx.expect_char('b') - #| ctx.expect_char('c') - #| ctx.expect_char((0x1F600).unsafe_to_char()) - #| ctx.expect_char('c') - #| inspect(try? ctx.expect_char('d'), content={ "Err": "InvalidEof" }) - #|} - #|fn ParseContext::lex_skip_whitespace(ctx : ParseContext) -> Unit { - #| for { - #| match ctx.read_char() { - #| Some('\t' | ' ' | '\n' | '\r') => continue - #| Some(c) => { - #| if c > '\u{7f}' && non_ascii_whitespace.contains(c) { - #| continue - #| } - #| ctx.offset -= 1 - #| break - #| } - #| None => break - #| } - #| } - #|} - #|fn ParseContext::lex_after_array_value( - #| ctx : ParseContext, - #|) -> Token raise ParseError { - #| ctx.lex_skip_whitespace() - #| match ctx.read_char() { - #| Some(']') => RBracket - #| Some(',') => Comma - #| Some(_) => ctx.invalid_char(shift=-1) - #| None => raise InvalidEof - #| } - #|} - #|fn ParseContext::lex_after_property_name( - #| ctx : ParseContext, - #|) -> Unit raise ParseError { - #| ctx.lex_skip_whitespace() - #| match ctx.read_char() { - #| Some(':') => () - #| Some(_) => ctx.invalid_char(shift=-1) - #| None => raise InvalidEof - #| } - #|} - #|fn ParseContext::lex_after_object_value( - #| ctx : ParseContext, - #|) -> Token raise ParseError { - #| ctx.lex_skip_whitespace() - #| match ctx.read_char() { - #| Some('}') => RBrace - #| Some(',') => Comma - #| Some(_) => ctx.invalid_char(shift=-1) - #| None => raise InvalidEof - #| } - #|} - #|fn ParseContext::lex_property_name( - #| ctx : ParseContext, - #|) -> Token raise ParseError { - #| ctx.lex_skip_whitespace() - #| match ctx.read_char() { - #| Some('}') => RBrace - #| Some('"') => { - #| let s = ctx.lex_string() - #| String(s) - #| } - #| Some(_) => ctx.invalid_char(shift=-1) - #| None => raise InvalidEof - #| } - #|} - #|fn ParseContext::lex_property_name2( - #| ctx : ParseContext, - #|) -> Token raise ParseError { - #| ctx.lex_skip_whitespace() - #| match ctx.read_char() { - #| Some('"') => { - #| let s = ctx.lex_string() - #| String(s) - #| } - #| Some(_) => ctx.invalid_char(shift=-1) - #| None => raise InvalidEof - #| } - #|} - ), - "lex_number.mbt": ( - #|fn ParseContext::lex_decimal_integer( - #| ctx : ParseContext, - #| start~ : Int, - #|) -> (Double, StringView?) raise ParseError { - #| for { - #| match ctx.read_char() { - #| Some('.') => return ctx.lex_decimal_point(start~) - #| Some('e' | 'E') => return ctx.lex_decimal_exponent(start~) - #| Some(c) => { - #| if c >= '0' && c <= '9' { - #| continue - #| } - #| ctx.offset -= 1 - #| return ctx.lex_number_end(start, ctx.offset) - #| } - #| None => return ctx.lex_number_end(start, ctx.offset) - #| } - #| } - #|} - #|fn ParseContext::lex_decimal_point( - #| ctx : ParseContext, - #| start~ : Int, - #|) -> (Double, StringView?) raise ParseError { - #| match ctx.read_char() { - #| Some(c) => - #| if c >= '0' && c <= '9' { - #| ctx.lex_decimal_fraction(start~) - #| } else { - #| ctx.invalid_char(shift=-1) - #| } - #| None => raise InvalidEof - #| } - #|} - #|fn ParseContext::lex_decimal_fraction( - #| ctx : ParseContext, - #| start~ : Int, - #|) -> (Double, StringView?) raise ParseError { - #| for { - #| match ctx.read_char() { - #| Some('e' | 'E') => return ctx.lex_decimal_exponent(start~) - #| Some(c) => { - #| if c >= '0' && c <= '9' { - #| continue - #| } - #| ctx.offset -= 1 - #| return ctx.lex_number_end(start, ctx.offset) - #| } - #| None => return ctx.lex_number_end(start, ctx.offset) - #| } - #| } - #|} - #|fn ParseContext::lex_decimal_exponent( - #| ctx : ParseContext, - #| start~ : Int, - #|) -> (Double, StringView?) raise ParseError { - #| match ctx.read_char() { - #| Some('+') | Some('-') => return ctx.lex_decimal_exponent_sign(start~) - #| Some(c) => { - #| if c >= '0' && c <= '9' { - #| return ctx.lex_decimal_exponent_integer(start~) - #| } - #| ctx.offset -= 1 - #| ctx.invalid_char() - #| } - #| None => raise InvalidEof - #| } - #|} - #|fn ParseContext::lex_decimal_exponent_sign( - #| ctx : ParseContext, - #| start~ : Int, - #|) -> (Double, StringView?) raise ParseError { - #| match ctx.read_char() { - #| Some(c) => { - #| if c >= '0' && c <= '9' { - #| return ctx.lex_decimal_exponent_integer(start~) - #| } - #| ctx.offset -= 1 - #| ctx.invalid_char() - #| } - #| None => raise InvalidEof - #| } - #|} - #|fn ParseContext::lex_decimal_exponent_integer( - #| ctx : ParseContext, - #| start~ : Int, - #|) -> (Double, StringView?) { - #| for { - #| match ctx.read_char() { - #| Some(c) => { - #| if c >= '0' && c <= '9' { - #| continue - #| } - #| ctx.offset -= 1 - #| return ctx.lex_number_end(start, ctx.offset) - #| } - #| None => return ctx.lex_number_end(start, ctx.offset) - #| } - #| } - #|} - #|fn ParseContext::lex_zero( - #| ctx : ParseContext, - #| start~ : Int, - #|) -> (Double, StringView?) raise ParseError { - #| match ctx.read_char() { - #| Some('.') => ctx.lex_decimal_point(start~) - #| Some('e' | 'E') => ctx.lex_decimal_exponent(start~) - #| Some(c) => { - #| if c >= '0' && c <= '9' { - #| ctx.offset -= 1 - #| ctx.invalid_char() - #| } - #| ctx.offset -= 1 - #| return ctx.lex_number_end(start, ctx.offset) - #| } - #| None => return ctx.lex_number_end(start, ctx.offset) - #| } - #|} - #|fn ParseContext::lex_number_end( - #| ctx : ParseContext, - #| start : Int, - #| end : Int, - #|) -> (Double, StringView?) { - #| let s = ctx.input.view(start_offset=start, end_offset=end) - #| if !s.contains(".") && !s.contains("e") && !s.contains("E") { - #| let parsed_int = try? @strconv.parse_int64(s) - #| match parsed_int { - #| Ok(i) if i <= 9007199254740991 && i >= -9007199254740991 => - #| return (i.to_double(), None) - #| _ => - #| return if s is ['-', ..] { - #| (@double.neg_infinity, Some(s)) - #| } else { - #| (@double.infinity, Some(s)) - #| } - #| } - #| } else { - #| let parsed_double = try? @strconv.parse_double(s) - #| match parsed_double { - #| Ok(d) => (d, None) - #| Err(_) => - #| if s is ['-', ..] { - #| (@double.neg_infinity, Some(s)) - #| } else { - #| (@double.infinity, Some(s)) - #| } - #| } - #| } - #|} - ), - "lex_string.mbt": ( - #|fn ParseContext::lex_string(ctx : ParseContext) -> String raise ParseError { - #| let buf = StringBuilder::new() - #| let mut start = ctx.offset - #| fn flush(end : Int) { - #| if start > 0 && end > start { - #| buf.write_view(try! ctx.input[start:end]) - #| } - #| } - #| for { - #| match ctx.read_char() { - #| Some('"') => { - #| flush(ctx.offset - 1) - #| break - #| } - #| Some('\n' | '\r') => ctx.invalid_char(shift=-1) - #| Some('\\') => { - #| flush(ctx.offset - 1) - #| match ctx.read_char() { - #| Some('b') => buf.write_char('\b') - #| Some('f') => buf.write_char('\u{0C}') - #| Some('n') => buf.write_char('\n') - #| Some('r') => buf.write_char('\r') - #| Some('t') => buf.write_char('\t') - #| Some('"') => buf.write_char('"') - #| Some('\\') => buf.write_char('\\') - #| Some('/') => buf.write_char('/') - #| Some('u') => { - #| let c = ctx.lex_hex_digits(4) - #| buf.write_char(c.unsafe_to_char()) - #| } - #| Some(_) => ctx.invalid_char(shift=-1) - #| None => raise InvalidEof - #| } - #| start = ctx.offset - #| } - #| Some(ch) => - #| if ch.to_int() < 32 { - #| ctx.invalid_char(shift=-1) - #| } else { - #| continue - #| } - #| None => raise InvalidEof - #| } - #| } - #| buf.to_string() - #|} - #|fn ParseContext::lex_hex_digits( - #| ctx : ParseContext, - #| n : Int, - #|) -> Int raise ParseError { - #| let mut r = 0 - #| for i in 0.. - #| if c >= 'A' { - #| let d = (c.to_int() & (32).lnot()) - 'A'.to_int() + 10 - #| if d > 15 { - #| ctx.invalid_char(shift=-1) - #| } - #| r = (r << 4) | d - #| } else if c >= '0' { - #| let d = c.to_int() - '0'.to_int() - #| if d > 9 { - #| ctx.invalid_char(shift=-1) - #| } - #| r = (r << 4) | d - #| } else { - #| ctx.invalid_char(shift=-1) - #| } - #| None => raise InvalidEof - #| } - #| } - #| r - #|} - ), - "parse.mbt": ( - #|pub fn valid(input : StringView) -> Bool { - #| try { - #| parse(input) |> ignore - #| true - #| } catch { - #| _ => return false - #| } - #|} - #|#label_migration(max_nesting_depth, fill=false) - #|pub fn parse( - #| input : StringView, - #| max_nesting_depth? : Int = 1024, - #|) -> Json raise ParseError { - #| let ctx = ParseContext::make(input, max_nesting_depth) - #| let val = ctx.parse_value() - #| ctx.lex_skip_whitespace() - #| if ctx.offset >= ctx.end_offset { - #| val - #| } else { - #| ctx.invalid_char() - #| } - #|} - #|fn ParseContext::parse_value(ctx : ParseContext) -> Json raise ParseError { - #| let tok = ctx.lex_value(allow_rbracket=false) - #| ctx.parse_value2(tok) - #|} - #|fn ParseContext::parse_value2( - #| ctx : ParseContext, - #| tok : Token, - #|) -> Json raise ParseError { - #| match tok { - #| Null => null - #| True => Json::boolean(true) - #| False => Json::boolean(false) - #| Number(n, repr) => Json::number(n, repr?) - #| String(s) => Json::string(s) - #| LBrace => ctx.parse_object() - #| LBracket => ctx.parse_array() - #| RBracket | RBrace | Comma => abort("unreachable") - #| } - #|} - #|fn ParseContext::parse_object(ctx : ParseContext) -> Json raise ParseError { - #| if ctx.remaining_available_depth <= 0 { - #| raise DepthLimitExceeded - #| } - #| ctx.remaining_available_depth -= 1 - #| let map = Map::new() - #| loop ctx.lex_property_name() { - #| RBrace => { - #| ctx.remaining_available_depth += 1 - #| Json::object(map) - #| } - #| String(name) => { - #| ctx.lex_after_property_name() - #| map[name] = ctx.parse_value() - #| match ctx.lex_after_object_value() { - #| Comma => continue ctx.lex_property_name2() - #| RBrace => { - #| ctx.remaining_available_depth += 1 - #| Json::object(map) - #| } - #| _ => abort("unreachable") - #| } - #| } - #| _ => abort("unreachable") - #| } - #|} - #|fn ParseContext::parse_array(ctx : ParseContext) -> Json raise ParseError { - #| if ctx.remaining_available_depth <= 0 { - #| raise DepthLimitExceeded - #| } - #| ctx.remaining_available_depth -= 1 - #| let vec = [] - #| loop ctx.lex_value(allow_rbracket=true) { - #| RBracket => { - #| ctx.remaining_available_depth += 1 - #| Json::array(vec) - #| } - #| tok => { - #| vec.push(ctx.parse_value2(tok)) - #| let tok2 = ctx.lex_after_array_value() - #| match tok2 { - #| Comma => continue ctx.lex_value(allow_rbracket=false) - #| RBracket => { - #| ctx.remaining_available_depth += 1 - #| Json::array(vec) - #| } - #| _ => abort("unreachable") - #| } - #| } - #| } - #|} - ), - "tuple_fromjson.mbt": ( - #|pub impl[A : FromJson, B : FromJson] FromJson for (A, B) with from_json( - #| json, - #| path, - #|) { - #| match json { - #| [a, b] => { - #| let a : A = FromJson::from_json(a, path.add_index(0)) - #| let b : B = FromJson::from_json(b, path.add_index(1)) - #| (a, b) - #| } - #| _ => decode_error(path, "expected tuple of size 2") - #| } - #|} - #|pub impl[A : FromJson, B : FromJson, C : FromJson] FromJson for (A, B, C) with from_json( - #| json, - #| path, - #|) { - #| match json { - #| [a, b, c] => { - #| let a : A = FromJson::from_json(a, path.add_index(0)) - #| let b : B = FromJson::from_json(b, path.add_index(1)) - #| let c : C = FromJson::from_json(c, path.add_index(2)) - #| (a, b, c) - #| } - #| _ => decode_error(path, "expected tuple of size 3") - #| } - #|} - #|pub impl[A : FromJson, B : FromJson, C : FromJson, D : FromJson] FromJson for ( - #| A, - #| B, - #| C, - #| D, - #|) with from_json(json, path) { - #| match json { - #| [a, b, c, d] => { - #| let a : A = FromJson::from_json(a, path.add_index(0)) - #| let b : B = FromJson::from_json(b, path.add_index(1)) - #| let c : C = FromJson::from_json(c, path.add_index(2)) - #| let d : D = FromJson::from_json(d, path.add_index(3)) - #| (a, b, c, d) - #| } - #| _ => decode_error(path, "expected tuple of size 4") - #| } - #|} - #|pub impl[A : FromJson, B : FromJson, C : FromJson, D : FromJson, E : FromJson] FromJson for ( - #| A, - #| B, - #| C, - #| D, - #| E, - #|) with from_json(json, path) { - #| match json { - #| [a, b, c, d, e] => { - #| let a : A = FromJson::from_json(a, path.add_index(0)) - #| let b : B = FromJson::from_json(b, path.add_index(1)) - #| let c : C = FromJson::from_json(c, path.add_index(2)) - #| let d : D = FromJson::from_json(d, path.add_index(3)) - #| let e : E = FromJson::from_json(e, path.add_index(4)) - #| (a, b, c, d, e) - #| } - #| _ => decode_error(path, "expected tuple of size 5") - #| } - #|} - #|pub impl[ - #| A : FromJson, - #| B : FromJson, - #| C : FromJson, - #| D : FromJson, - #| E : FromJson, - #| F : FromJson, - #|] FromJson for (A, B, C, D, E, F) with from_json(json, path) { - #| match json { - #| [a, b, c, d, e, f] => { - #| let a : A = FromJson::from_json(a, path.add_index(0)) - #| let b : B = FromJson::from_json(b, path.add_index(1)) - #| let c : C = FromJson::from_json(c, path.add_index(2)) - #| let d : D = FromJson::from_json(d, path.add_index(3)) - #| let e : E = FromJson::from_json(e, path.add_index(4)) - #| let f : F = FromJson::from_json(f, path.add_index(5)) - #| (a, b, c, d, e, f) - #| } - #| _ => decode_error(path, "expected tuple of size 6") - #| } - #|} - #|pub impl[ - #| A : FromJson, - #| B : FromJson, - #| C : FromJson, - #| D : FromJson, - #| E : FromJson, - #| F : FromJson, - #| G : FromJson, - #|] FromJson for (A, B, C, D, E, F, G) with from_json(json, path) { - #| match json { - #| [a, b, c, d, e, f, g] => { - #| let a : A = FromJson::from_json(a, path.add_index(0)) - #| let b : B = FromJson::from_json(b, path.add_index(1)) - #| let c : C = FromJson::from_json(c, path.add_index(2)) - #| let d : D = FromJson::from_json(d, path.add_index(3)) - #| let e : E = FromJson::from_json(e, path.add_index(4)) - #| let f : F = FromJson::from_json(f, path.add_index(5)) - #| let g : G = FromJson::from_json(g, path.add_index(6)) - #| (a, b, c, d, e, f, g) - #| } - #| _ => decode_error(path, "expected tuple of size 7") - #| } - #|} - #|pub impl[ - #| T0 : FromJson, - #| T1 : FromJson, - #| T2 : FromJson, - #| T3 : FromJson, - #| T4 : FromJson, - #| T5 : FromJson, - #| T6 : FromJson, - #| T7 : FromJson, - #|] FromJson for (T0, T1, T2, T3, T4, T5, T6, T7) with from_json(json, path) { - #| match json { - #| [x0, x1, x2, x3, x4, x5, x6, x7] => { - #| let x0 : T0 = FromJson::from_json(x0, path.add_index(0)) - #| let x1 : T1 = FromJson::from_json(x1, path.add_index(1)) - #| let x2 : T2 = FromJson::from_json(x2, path.add_index(2)) - #| let x3 : T3 = FromJson::from_json(x3, path.add_index(3)) - #| let x4 : T4 = FromJson::from_json(x4, path.add_index(4)) - #| let x5 : T5 = FromJson::from_json(x5, path.add_index(5)) - #| let x6 : T6 = FromJson::from_json(x6, path.add_index(6)) - #| let x7 : T7 = FromJson::from_json(x7, path.add_index(7)) - #| (x0, x1, x2, x3, x4, x5, x6, x7) - #| } - #| _ => decode_error(path, "expected tuple of size 8") - #| } - #|} - #|pub impl[ - #| T0 : FromJson, - #| T1 : FromJson, - #| T2 : FromJson, - #| T3 : FromJson, - #| T4 : FromJson, - #| T5 : FromJson, - #| T6 : FromJson, - #| T7 : FromJson, - #| T8 : FromJson, - #|] FromJson for (T0, T1, T2, T3, T4, T5, T6, T7, T8) with from_json(json, path) { - #| match json { - #| [x0, x1, x2, x3, x4, x5, x6, x7, x8] => { - #| let x0 : T0 = FromJson::from_json(x0, path.add_index(0)) - #| let x1 : T1 = FromJson::from_json(x1, path.add_index(1)) - #| let x2 : T2 = FromJson::from_json(x2, path.add_index(2)) - #| let x3 : T3 = FromJson::from_json(x3, path.add_index(3)) - #| let x4 : T4 = FromJson::from_json(x4, path.add_index(4)) - #| let x5 : T5 = FromJson::from_json(x5, path.add_index(5)) - #| let x6 : T6 = FromJson::from_json(x6, path.add_index(6)) - #| let x7 : T7 = FromJson::from_json(x7, path.add_index(7)) - #| let x8 : T8 = FromJson::from_json(x8, path.add_index(8)) - #| (x0, x1, x2, x3, x4, x5, x6, x7, x8) - #| } - #| _ => decode_error(path, "expected tuple of size 9") - #| } - #|} - #|pub impl[ - #| T0 : FromJson, - #| T1 : FromJson, - #| T2 : FromJson, - #| T3 : FromJson, - #| T4 : FromJson, - #| T5 : FromJson, - #| T6 : FromJson, - #| T7 : FromJson, - #| T8 : FromJson, - #| T9 : FromJson, - #|] FromJson for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) with from_json( - #| json, - #| path, - #|) { - #| match json { - #| [x0, x1, x2, x3, x4, x5, x6, x7, x8, x9] => { - #| let x0 : T0 = FromJson::from_json(x0, path.add_index(0)) - #| let x1 : T1 = FromJson::from_json(x1, path.add_index(1)) - #| let x2 : T2 = FromJson::from_json(x2, path.add_index(2)) - #| let x3 : T3 = FromJson::from_json(x3, path.add_index(3)) - #| let x4 : T4 = FromJson::from_json(x4, path.add_index(4)) - #| let x5 : T5 = FromJson::from_json(x5, path.add_index(5)) - #| let x6 : T6 = FromJson::from_json(x6, path.add_index(6)) - #| let x7 : T7 = FromJson::from_json(x7, path.add_index(7)) - #| let x8 : T8 = FromJson::from_json(x8, path.add_index(8)) - #| let x9 : T9 = FromJson::from_json(x9, path.add_index(9)) - #| (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) - #| } - #| _ => decode_error(path, "expected tuple of size 10") - #| } - #|} - #|pub impl[ - #| T0 : FromJson, - #| T1 : FromJson, - #| T2 : FromJson, - #| T3 : FromJson, - #| T4 : FromJson, - #| T5 : FromJson, - #| T6 : FromJson, - #| T7 : FromJson, - #| T8 : FromJson, - #| T9 : FromJson, - #| T10 : FromJson, - #|] FromJson for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) with from_json( - #| json, - #| path, - #|) { - #| match json { - #| [x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10] => { - #| let x0 : T0 = FromJson::from_json(x0, path.add_index(0)) - #| let x1 : T1 = FromJson::from_json(x1, path.add_index(1)) - #| let x2 : T2 = FromJson::from_json(x2, path.add_index(2)) - #| let x3 : T3 = FromJson::from_json(x3, path.add_index(3)) - #| let x4 : T4 = FromJson::from_json(x4, path.add_index(4)) - #| let x5 : T5 = FromJson::from_json(x5, path.add_index(5)) - #| let x6 : T6 = FromJson::from_json(x6, path.add_index(6)) - #| let x7 : T7 = FromJson::from_json(x7, path.add_index(7)) - #| let x8 : T8 = FromJson::from_json(x8, path.add_index(8)) - #| let x9 : T9 = FromJson::from_json(x9, path.add_index(9)) - #| let x10 : T10 = FromJson::from_json(x10, path.add_index(10)) - #| (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10) - #| } - #| _ => decode_error(path, "expected tuple of size 11") - #| } - #|} - #|pub impl[ - #| T0 : FromJson, - #| T1 : FromJson, - #| T2 : FromJson, - #| T3 : FromJson, - #| T4 : FromJson, - #| T5 : FromJson, - #| T6 : FromJson, - #| T7 : FromJson, - #| T8 : FromJson, - #| T9 : FromJson, - #| T10 : FromJson, - #| T11 : FromJson, - #|] FromJson for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) with from_json( - #| json, - #| path, - #|) { - #| match json { - #| [x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11] => { - #| let x0 : T0 = FromJson::from_json(x0, path.add_index(0)) - #| let x1 : T1 = FromJson::from_json(x1, path.add_index(1)) - #| let x2 : T2 = FromJson::from_json(x2, path.add_index(2)) - #| let x3 : T3 = FromJson::from_json(x3, path.add_index(3)) - #| let x4 : T4 = FromJson::from_json(x4, path.add_index(4)) - #| let x5 : T5 = FromJson::from_json(x5, path.add_index(5)) - #| let x6 : T6 = FromJson::from_json(x6, path.add_index(6)) - #| let x7 : T7 = FromJson::from_json(x7, path.add_index(7)) - #| let x8 : T8 = FromJson::from_json(x8, path.add_index(8)) - #| let x9 : T9 = FromJson::from_json(x9, path.add_index(9)) - #| let x10 : T10 = FromJson::from_json(x10, path.add_index(10)) - #| let x11 : T11 = FromJson::from_json(x11, path.add_index(11)) - #| (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11) - #| } - #| _ => decode_error(path, "expected tuple of size 12") - #| } - #|} - #|pub impl[ - #| T0 : FromJson, - #| T1 : FromJson, - #| T2 : FromJson, - #| T3 : FromJson, - #| T4 : FromJson, - #| T5 : FromJson, - #| T6 : FromJson, - #| T7 : FromJson, - #| T8 : FromJson, - #| T9 : FromJson, - #| T10 : FromJson, - #| T11 : FromJson, - #| T12 : FromJson, - #|] FromJson for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) with from_json( - #| json, - #| path, - #|) { - #| match json { - #| [x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12] => { - #| let x0 : T0 = FromJson::from_json(x0, path.add_index(0)) - #| let x1 : T1 = FromJson::from_json(x1, path.add_index(1)) - #| let x2 : T2 = FromJson::from_json(x2, path.add_index(2)) - #| let x3 : T3 = FromJson::from_json(x3, path.add_index(3)) - #| let x4 : T4 = FromJson::from_json(x4, path.add_index(4)) - #| let x5 : T5 = FromJson::from_json(x5, path.add_index(5)) - #| let x6 : T6 = FromJson::from_json(x6, path.add_index(6)) - #| let x7 : T7 = FromJson::from_json(x7, path.add_index(7)) - #| let x8 : T8 = FromJson::from_json(x8, path.add_index(8)) - #| let x9 : T9 = FromJson::from_json(x9, path.add_index(9)) - #| let x10 : T10 = FromJson::from_json(x10, path.add_index(10)) - #| let x11 : T11 = FromJson::from_json(x11, path.add_index(11)) - #| let x12 : T12 = FromJson::from_json(x12, path.add_index(12)) - #| (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12) - #| } - #| _ => decode_error(path, "expected tuple of size 13") - #| } - #|} - #|pub impl[ - #| T0 : FromJson, - #| T1 : FromJson, - #| T2 : FromJson, - #| T3 : FromJson, - #| T4 : FromJson, - #| T5 : FromJson, - #| T6 : FromJson, - #| T7 : FromJson, - #| T8 : FromJson, - #| T9 : FromJson, - #| T10 : FromJson, - #| T11 : FromJson, - #| T12 : FromJson, - #| T13 : FromJson, - #|] FromJson for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) with from_json( - #| json, - #| path, - #|) { - #| match json { - #| [x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13] => { - #| let x0 : T0 = FromJson::from_json(x0, path.add_index(0)) - #| let x1 : T1 = FromJson::from_json(x1, path.add_index(1)) - #| let x2 : T2 = FromJson::from_json(x2, path.add_index(2)) - #| let x3 : T3 = FromJson::from_json(x3, path.add_index(3)) - #| let x4 : T4 = FromJson::from_json(x4, path.add_index(4)) - #| let x5 : T5 = FromJson::from_json(x5, path.add_index(5)) - #| let x6 : T6 = FromJson::from_json(x6, path.add_index(6)) - #| let x7 : T7 = FromJson::from_json(x7, path.add_index(7)) - #| let x8 : T8 = FromJson::from_json(x8, path.add_index(8)) - #| let x9 : T9 = FromJson::from_json(x9, path.add_index(9)) - #| let x10 : T10 = FromJson::from_json(x10, path.add_index(10)) - #| let x11 : T11 = FromJson::from_json(x11, path.add_index(11)) - #| let x12 : T12 = FromJson::from_json(x12, path.add_index(12)) - #| let x13 : T13 = FromJson::from_json(x13, path.add_index(13)) - #| (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13) - #| } - #| _ => decode_error(path, "expected tuple of size 14") - #| } - #|} - #|pub impl[ - #| T0 : FromJson, - #| T1 : FromJson, - #| T2 : FromJson, - #| T3 : FromJson, - #| T4 : FromJson, - #| T5 : FromJson, - #| T6 : FromJson, - #| T7 : FromJson, - #| T8 : FromJson, - #| T9 : FromJson, - #| T10 : FromJson, - #| T11 : FromJson, - #| T12 : FromJson, - #| T13 : FromJson, - #| T14 : FromJson, - #|] FromJson for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14) with from_json( - #| json, - #| path, - #|) { - #| match json { - #| [x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14] => { - #| let x0 : T0 = FromJson::from_json(x0, path.add_index(0)) - #| let x1 : T1 = FromJson::from_json(x1, path.add_index(1)) - #| let x2 : T2 = FromJson::from_json(x2, path.add_index(2)) - #| let x3 : T3 = FromJson::from_json(x3, path.add_index(3)) - #| let x4 : T4 = FromJson::from_json(x4, path.add_index(4)) - #| let x5 : T5 = FromJson::from_json(x5, path.add_index(5)) - #| let x6 : T6 = FromJson::from_json(x6, path.add_index(6)) - #| let x7 : T7 = FromJson::from_json(x7, path.add_index(7)) - #| let x8 : T8 = FromJson::from_json(x8, path.add_index(8)) - #| let x9 : T9 = FromJson::from_json(x9, path.add_index(9)) - #| let x10 : T10 = FromJson::from_json(x10, path.add_index(10)) - #| let x11 : T11 = FromJson::from_json(x11, path.add_index(11)) - #| let x12 : T12 = FromJson::from_json(x12, path.add_index(12)) - #| let x13 : T13 = FromJson::from_json(x13, path.add_index(13)) - #| let x14 : T14 = FromJson::from_json(x14, path.add_index(14)) - #| (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14) - #| } - #| _ => decode_error(path, "expected tuple of size 15") - #| } - #|} - #|pub impl[ - #| T0 : FromJson, - #| T1 : FromJson, - #| T2 : FromJson, - #| T3 : FromJson, - #| T4 : FromJson, - #| T5 : FromJson, - #| T6 : FromJson, - #| T7 : FromJson, - #| T8 : FromJson, - #| T9 : FromJson, - #| T10 : FromJson, - #| T11 : FromJson, - #| T12 : FromJson, - #| T13 : FromJson, - #| T14 : FromJson, - #| T15 : FromJson, - #|] FromJson for ( - #| T0, - #| T1, - #| T2, - #| T3, - #| T4, - #| T5, - #| T6, - #| T7, - #| T8, - #| T9, - #| T10, - #| T11, - #| T12, - #| T13, - #| T14, - #| T15, - #|) with from_json(json, path) { - #| match json { - #| [x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15] => { - #| let x0 : T0 = FromJson::from_json(x0, path.add_index(0)) - #| let x1 : T1 = FromJson::from_json(x1, path.add_index(1)) - #| let x2 : T2 = FromJson::from_json(x2, path.add_index(2)) - #| let x3 : T3 = FromJson::from_json(x3, path.add_index(3)) - #| let x4 : T4 = FromJson::from_json(x4, path.add_index(4)) - #| let x5 : T5 = FromJson::from_json(x5, path.add_index(5)) - #| let x6 : T6 = FromJson::from_json(x6, path.add_index(6)) - #| let x7 : T7 = FromJson::from_json(x7, path.add_index(7)) - #| let x8 : T8 = FromJson::from_json(x8, path.add_index(8)) - #| let x9 : T9 = FromJson::from_json(x9, path.add_index(9)) - #| let x10 : T10 = FromJson::from_json(x10, path.add_index(10)) - #| let x11 : T11 = FromJson::from_json(x11, path.add_index(11)) - #| let x12 : T12 = FromJson::from_json(x12, path.add_index(12)) - #| let x13 : T13 = FromJson::from_json(x13, path.add_index(13)) - #| let x14 : T14 = FromJson::from_json(x14, path.add_index(14)) - #| let x15 : T15 = FromJson::from_json(x15, path.add_index(15)) - #| (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15) - #| } - #| _ => decode_error(path, "expected tuple of size 16") - #| } - #|} - ), - "types.mbt": ( - #|pub(all) struct Position { - #| line : Int // 1-based - #| column : Int // 0-based - #|} derive(Eq, ToJson) - #|pub(all) suberror ParseError { - #| InvalidChar(Position, Char) - #| InvalidEof - #| InvalidNumber(Position, String) - #| InvalidIdentEscape(Position) - #| DepthLimitExceeded - #|} derive(Eq, ToJson) - #|pub impl Show for ParseError with output(self, logger) { - #| match self { - #| InvalidChar({ line, column }, c) => - #| logger - #| ..write_string("Invalid character ") - #| ..write_string(repr(c)) - #| ..write_string(" at line ") - #| ..write_object(line) - #| ..write_string(", column ") - #| ..write_object(column) - #| InvalidEof => logger.write_string("Unexpected end of file") - #| InvalidNumber({ line, column }, s) => - #| logger - #| ..write_string("Invalid number ") - #| ..write_string(s) - #| ..write_string(" at line ") - #| ..write_object(line) - #| ..write_string(", column ") - #| ..write_object(column) - #| InvalidIdentEscape({ line, column }) => - #| logger - #| ..write_string("Invalid escape sequence in identifier at line ") - #| ..write_object(line) - #| ..write_string(", column ") - #| ..write_object(column) - #| DepthLimitExceeded => - #| logger.write_string( - #| "Depth limit exceeded, please increase the max_nesting_depth parameter", - #| ) - #| } - #|} - #|pub impl Show for Json with output(self, logger) { - #| match self { - #| Null => logger.write_string("Null") - #| True => logger.write_string("True") - #| False => logger.write_string("False") - #| Number(n, repr~) => { - #| logger.write_string("Number(") - #| Show::output(n, logger) - #| if repr is Some(_) { - #| logger.write_string(", repr=") - #| Show::output(repr, logger) - #| } - #| logger.write_string(")") - #| } - #| String(s) => { - #| logger.write_string("String(") - #| Show::output(s, logger) - #| logger.write_string(")") - #| } - #| Array(a) => { - #| logger.write_string("Array(") - #| Show::output(a, logger) - #| logger.write_string(")") - #| } - #| Object(o) => { - #| logger.write_string("Object(") - #| Show::output(o, logger) - #| logger.write_string(")") - #| } - #| } - #|} - ), - "utils.mbt": ( - #|fn offset_to_position(input : StringView, offset : Int) -> Position { - #| let mut line = 1 - #| let mut column = 0 - #| for i in 0.. T raise ParseError { - #| let offset = ctx.offset + shift - #| let replacement_char : Char = '\u{fffd}' - #| raise InvalidChar( - #| offset_to_position(ctx.input, offset), - #| ctx.input.get_char(offset).unwrap_or(replacement_char), - #| ) - #|} - ), - }, + "deprecated.mbt": "", + "from_json.mbt": ( + #|pub(all) suberror JsonDecodeError { + #| JsonDecodeError((JsonPath, String)) + #|} derive(Eq, Show, ToJson) + #|pub(open) trait FromJson { + #| from_json(Json, JsonPath) -> Self raise JsonDecodeError + #|} + #|pub fn[T : FromJson] from_json( + #| json : Json, + #| path? : JsonPath = Root, + #|) -> T raise JsonDecodeError { + #| FromJson::from_json(json, path) + #|} + #|fn[T] decode_error(path : JsonPath, msg : String) -> T raise JsonDecodeError { + #| raise JsonDecodeError((path, msg)) + #|} + #|pub impl FromJson for Bool with from_json(json, path) { + #| match json { + #| true => true + #| false => false + #| _ => decode_error(path, "Bool::from_json: expected boolean") + #| } + #|} + #|pub impl FromJson for Int with from_json(json, path) { + #| guard json is Number(n, ..) && + #| n != @double.infinity && + #| n != @double.neg_infinity else { + #| decode_error(path, "Int::from_json: expected number") + #| } + #| let max_ok = 2147483647.0 + #| let min_ok = -2147483648.0 + #| if n > max_ok || n < min_ok { + #| decode_error(path, "Int::from_json: overflow") + #| } + #| n.to_int() + #|} + #|pub impl FromJson for Int64 with from_json(json, path) { + #| guard json is String(str) else { + #| decode_error( + #| path, "Int64::from_json: expected number in string representation", + #| ) + #| } + #| @strconv.parse_int64(str) catch { + #| error => decode_error(path, "Int64::from_json: parsing failure \{error}") + #| } + #|} + #|pub impl FromJson for UInt with from_json(json, path) { + #| guard json is Number(n, ..) && + #| n != @double.infinity && + #| n != @double.neg_infinity else { + #| decode_error(path, "UInt::from_json: expected number") + #| } + #| let max_ok = 4294967295.0 + #| if n < 0.0 || n > max_ok { + #| decode_error(path, "UInt::from_json: overflow") + #| } + #| n.to_uint() + #|} + #|pub impl FromJson for UInt64 with from_json(json, path) { + #| guard json is String(str) else { + #| decode_error( + #| path, "UInt64::from_json: expected number in string representation", + #| ) + #| } + #| @strconv.parse_uint64(str) catch { + #| error => decode_error(path, "UInt64::from_json: parsing failure \{error}") + #| } + #|} + #|pub impl FromJson for Double with from_json(json, path) { + #| match json { + #| String("NaN") => @double.not_a_number + #| String("Infinity") => @double.infinity + #| String("-Infinity") => @double.neg_infinity + #| Number(n, ..) if n != @double.infinity && n != @double.neg_infinity => n + #| _ => decode_error(path, "Double::from_json: expected number") + #| } + #|} + #|pub impl FromJson for Float with from_json(json, path) { + #| match json { + #| String("NaN") => @float.not_a_number + #| String("Infinity") => @float.infinity + #| String("-Infinity") => @float.neg_infinity + #| Number(n, ..) if n != @double.infinity && n != @double.neg_infinity => + #| Float::from_double(n) + #| _ => decode_error(path, "Float::from_json: expected number") + #| } + #|} + #|pub impl FromJson for String with from_json(json, path) { + #| guard json is String(a) else { + #| decode_error(path, "String::from_json: expected string") + #| } + #| a + #|} + #|pub impl FromJson for StringView with from_json(json, path) { + #| guard json is String(a) else { + #| decode_error(path, "View::from_json: expected string") + #| } + #| a[:] + #|} + #|pub impl FromJson for Char with from_json(json, path) { + #| guard json is String(a) else { + #| decode_error(path, "Char::from_json: expected string") + #| } + #| let len = a.length() + #| if len == 1 { + #| a.unsafe_get(0).unsafe_to_char() + #| } else if len == 2 { + #| let c1 = a.unsafe_get(0).to_int() + #| let c2 = a.unsafe_get(1).to_int() + #| if c1 is (0xD800..=0xDBFF) && c2 is (0xDC00..=0xDFFF) { + #| let c3 = (c1 << 10) + c2 - 0x35fdc00 + #| c3.unsafe_to_char() + #| } else { + #| decode_error(path, "Char::from_json: invalid surrogate pair") + #| } + #| } else { + #| decode_error(path, "Char::from_json: expected single character") + #| } + #|} + #|pub impl[X : FromJson] FromJson for Array[X] with from_json(json, path) { + #| guard json is Array(a) else { + #| decode_error(path, "Array::from_json: expected array") + #| } + #| guard JsonPath::Index(path, index=0) is (Index(_) as new_path) + #| a.mapi((i, x) => { + #| new_path.index = i + #| FromJson::from_json(x, new_path) + #| }) + #|} + #|pub impl[X : FromJson] FromJson for ArrayView[X] with from_json(json, path) { + #| guard json is Array(a) else { + #| decode_error(path, "ArrayView::from_json: expected array") + #| } + #| guard JsonPath::Index(path, index=0) is (Index(_) as new_path) + #| a.mapi((i, x) => { + #| new_path.index = i + #| FromJson::from_json(x, new_path) + #| }) + #|} + #|pub impl[X : FromJson] FromJson for FixedArray[X] with from_json(json, path) { + #| guard json is Array(a) else { + #| decode_error(path, "FixedArray::from_json: expected array") + #| } + #| let len = a.length() + #| if len == 0 { + #| return [] + #| } + #| guard JsonPath::Index(path, index=0) is (Index(_) as new_path) + #| let res = FixedArray::make( + #| len, + #| FromJson::from_json(a.unsafe_get(0), new_path), + #| ) + #| for i in 1.. None + #| Array([value]) => Some(FromJson::from_json(value, path.add_index(0))) + #| _ => decode_error(path, "Option::from_json: expected array or null") + #| } + #|} + #|pub impl[Ok : FromJson, Err : FromJson] FromJson for Result[Ok, Err] with from_json( + #| json, + #| path, + #|) { + #| guard json is Object(obj) else { + #| decode_error(path, "Result::from_json: expected object") + #| } + #| if obj.length() != 1 { + #| decode_error(path, "Result::from_json: expected object with one field") + #| } + #| match obj { + #| { "Ok": ok, .. } => Ok(FromJson::from_json(ok, path.add_key("Ok"))) + #| { "Err": err, .. } => Err(FromJson::from_json(err, path.add_key("Err"))) + #| _ => + #| decode_error( + #| path, "Result::from_json: expected object with Ok or Err field", + #| ) + #| } + #|} + #|pub impl FromJson for Unit with from_json(json, path) { + #| guard json is Null else { + #| decode_error(path, "Unit::from_json: expected null") + #| } + #|} + #|pub impl FromJson for Json with from_json(json, _path) { + #| json + #|} + #|pub impl FromJson for Bytes with from_json(json, path) { + #| guard json is String(a) else { + #| decode_error(path, "Bytes::from_json: expected string") + #| } + #| let buffer = @buffer.new(size_hint=a.length()) + #| loop a[:] { + #| [] => () + #| [.. "\\x", '0'..='9' | 'a'..='f' as x, '0'..='9' | 'a'..='f' as y, .. rest] => { + #| let upper = (x.to_int() & 0xF) + (x.to_int() >> 6) * 9 + #| let lower = (y.to_int() & 0xF) + (y.to_int() >> 6) * 9 + #| buffer.write_byte(((upper << 4) | lower).to_byte()) + #| continue rest + #| } + #| [' '..='~' as ch, .. rest] => { + #| guard ch != '\\' && ch != '"' else { + #| decode_error(path, "Bytes::from_json: invalid escape sequence") + #| } + #| buffer.write_byte(ch.to_uint().to_byte()) + #| continue rest + #| } + #| _ => decode_error(path, "Bytes::from_json: invalid byte sequence") + #| } + #| buffer.to_bytes() + #|} + ), + "internal_types.mbt": ( + #|priv struct ParseContext { + #| mut offset : Int + #| input : StringView + #| end_offset : Int + #| mut remaining_available_depth : Int + #|} + #|fn ParseContext::make( + #| input : StringView, + #| max_nesting_depth : Int, + #|) -> ParseContext { + #| { + #| offset: 0, + #| input, + #| end_offset: input.length(), + #| remaining_available_depth: max_nesting_depth, + #| } + #|} + #|priv enum Token { + #| Null + #| True + #| False + #| Number(Double, String?) + #| String(String) + #| LBrace + #| RBrace + #| LBracket + #| RBracket + #| Comma + #|} + ), + "json.mbt": ( + #|#deprecated("Suggestion: `if json is Null { Some(()) } else { None }`") + #|pub fn Json::as_null(self : Json) -> Unit? { + #| guard self is Null else { return None } + #| Some(()) + #|} + #|#deprecated("Suggestion: `if json is True { Some(true) } else if json is False { Some(false) } else { None }`") + #|pub fn Json::as_bool(self : Json) -> Bool? { + #| match self { + #| True => Some(true) + #| False => Some(false) + #| _ => None + #| } + #|} + #|#deprecated("Suggestion: `if json is Number(n) { Some(n) } else { None }`") + #|pub fn Json::as_number(self : Json) -> Double? { + #| guard self is Number(n, ..) else { return None } + #| Some(n) + #|} + #|#deprecated("Suggestion: `if json is String(s) { Some(s) } else { None }`") + #|pub fn Json::as_string(self : Json) -> String? { + #| guard self is String(s) else { return None } + #| Some(s) + #|} + #|#deprecated("Suggestion: `if json is Array(array) { Some(array) } else { None }`") + #|pub fn Json::as_array(self : Json) -> Array[Json]? { + #| guard self is Array(arr) else { return None } + #| Some(arr) + #|} + #|#deprecated("Suggestion: `if json is Array(array) { array.get(index) } else { None }`") + #|pub fn Json::item(self : Json, index : Int) -> Json? { + #| if self is Array(arr) { + #| arr.get(index) + #| } else { + #| None + #| } + #|} + #|#deprecated + #|pub fn Json::as_object(self : Json) -> Map[String, Json]? { + #| guard self is Object(obj) else { return None } + #| Some(obj) + #|} + #|#deprecated("Suggestion: `if json is Object(obj) { obj.get(key) } else { None }`") + #|pub fn Json::value(self : Json, key : String) -> Json? { + #| if self is Object(obj) { + #| obj.get(key) + #| } else { + #| None + #| } + #|} + #|fn indent_str(level : Int, indent : Int) -> String { + #| if indent == 0 { + #| "" + #| } else { + #| let spaces = indent * level + #| match spaces { + #| 0 => "\n" + #| 1 => "\n " + #| 2 => "\n " + #| 3 => "\n " + #| 4 => "\n " + #| 5 => "\n " + #| 6 => "\n " + #| 7 => "\n " + #| 8 => "\n " + #| _ => "\n" + " ".repeat(spaces) + #| } + #| } + #|} + #|priv enum WriteFrame { + #| Array(Array[Json], mut i~ : Int) // (arr, index) + #| Object(Iter[(String, Json)], mut first~ : Bool) // (kvs, first) + #|} + #|pub struct Replacer { + #| priv f : (String, Json) -> Json? + #| fn new(f : (String, Json) -> Json?) -> Replacer + #|} + #|pub fn Replacer::new(f : (String, Json) -> Json?) -> Replacer { + #| { f, } + #|} + #|pub fn Replacer::keep(array : ArrayView[StringView]) -> Replacer { + #| { f: (idx, value) => if array.contains(idx) { Some(value) } else { None } } + #|} + #|pub fn Replacer::exclude(array : ArrayView[StringView]) -> Replacer { + #| { f: (idx, value) => if array.contains(idx) { None } else { Some(value) } } + #|} + #|pub fn Json::stringify( + #| self : Json, + #| escape_slash? : Bool = false, + #| indent? : Int = 0, + #| replacer? : Replacer, + #|) -> String { + #| let buf = StringBuilder::new(size_hint=0) + #| let stack : Array[WriteFrame] = [] + #| let mut depth = 0 + #| loop Some(self) { + #| Some(value) => { + #| match value { + #| Object(members) => + #| if members.is_empty() { + #| buf.write_string("{}") + #| } else { + #| depth += 1 + #| buf.write_char('{') + #| buf.write_string(indent_str(depth, indent)) + #| stack.push(WriteFrame::Object(members.iter(), first=true)) + #| } + #| Array(arr) => + #| if arr.is_empty() { + #| buf.write_string("[]") + #| } else { + #| depth += 1 + #| buf.write_char('[') + #| buf.write_string(indent_str(depth, indent)) + #| stack.push(WriteFrame::Array(arr, i=0)) + #| } + #| String(s) => { + #| buf.write_char('\"') + #| buf.write_string(escape(s, escape_slash~)) + #| buf.write_char('\"') + #| } + #| Number(n, repr~) => + #| match repr { + #| None => buf.write_object(n) + #| Some(r) => buf.write_string(r) + #| } + #| True => buf.write_string("true") + #| False => buf.write_string("false") + #| Null => buf.write_string("null") + #| } + #| continue None + #| } + #| None => + #| match stack { + #| [] => break + #| [.., WriteFrame::Array(arr, i~) as frame] => + #| if i < arr.length() { + #| let element = arr[i] + #| frame.i = i + 1 + #| if i > 0 { + #| buf.write_char(',') + #| buf.write_string(indent_str(depth, indent)) + #| } + #| continue Some(element) + #| } else { + #| depth -= 1 + #| ignore(stack.pop()) + #| buf.write_string(indent_str(depth, indent)) + #| buf.write_char(']') + #| continue None + #| } + #| [.., WriteFrame::Object(iterator, first~) as frame] => + #| match iterator.next() { + #| Some((k, v)) => { + #| let mut v2 = v + #| if replacer is Some(replacer) { + #| if (replacer.f)(k, v) is Some(v) { + #| v2 = v + #| } else { + #| continue None + #| } + #| } + #| if !first { + #| buf.write_char(',') + #| buf.write_string(indent_str(depth, indent)) + #| } + #| buf.write_char('\"') + #| buf.write_string(escape(k, escape_slash~)) + #| buf.write_char('\"') + #| buf.write_char(':') + #| if indent > 0 { + #| buf.write_char(' ') + #| } + #| frame.first = false + #| continue Some(v2) + #| } + #| None => { + #| depth -= 1 + #| ignore(stack.pop()) + #| buf.write_string(indent_str(depth, indent)) + #| buf.write_char('}') + #| continue None + #| } + #| } + #| } + #| } + #| buf.to_string() + #|} + #|fn escape(str : String, escape_slash~ : Bool) -> String { + #| let buf = StringBuilder::new(size_hint=str.length()) + #| for c in str { + #| match c { + #| '"' => buf.write_string("\\\"") + #| '\\' => buf.write_string("\\\\") + #| '/' => + #| if escape_slash { + #| buf.write_string("\\/") + #| } else { + #| buf.write_char(c) + #| } + #| '\n' => buf.write_string("\\n") + #| '\r' => buf.write_string("\\r") + #| '\b' => buf.write_string("\\b") + #| '\t' => buf.write_string("\\t") + #| _ => { + #| let code = c.to_int() + #| if code == 0x0C { + #| buf.write_string("\\f") + #| } else if code < ' ' { + #| buf.write_string("\\u00") + #| buf.write_string(code.to_byte().to_hex()) + #| } else { + #| buf.write_char(c) + #| } + #| } + #| } + #| } + #| buf.to_string() + #|} + #|pub fn Json::transform(self : Self, replacer : Replacer) -> Json { + #| match self { + #| Object(members) => + #| members + #| .iter() + #| .filter_map(pair => { + #| let (k, v) = pair + #| if (replacer.f)(k, v) is Some(v2) { + #| Some((k, v2.transform(replacer))) + #| } else { + #| None + #| } + #| }) + #| |> Map::from_iter() + #| |> Object + #| Array(members) => Array(members.map(m => m.transform(replacer))) + #| value => value + #| } + #|} + #|pub impl ToJson for Json with to_json(self) { + #| self + #|} + #|#callsite(autofill(args_loc, loc)) + #|#alias(inspect, deprecated="Use `json_inspect` without package name instead.") + #|pub fn json_inspect( + #| obj : &ToJson, + #| content? : Json, + #| loc~ : SourceLoc, + #| args_loc~ : ArgsLoc, + #|) -> Unit raise InspectError { + #| let loc = loc.to_json_string() + #| let args_loc = args_loc.to_json() + #| let actual = obj.to_json().stringify(escape_slash=false) + #| let want = match content { + #| None => "".to_json().stringify(escape_slash=false) + #| Some(x) => x.stringify(escape_slash=false) + #| } + #| if actual != want { + #| raise InspectError::InspectError( + #| "@EXPECT_FAILED {\"loc\": \{loc}, \"args_loc\": \{args_loc}, \"expect\": \{want.escape()}, \"actual\": \{actual.escape()}, \"mode\": \"json\"}", + #| ) + #| } + #|} + ), + "json_path.mbt": ( + #|enum JsonPath { + #| Root + #| Key(JsonPath, mut key~ : String) + #| Index(JsonPath, mut index~ : Int) + #|} derive(Eq) + #|pub fn JsonPath::add_index(self : JsonPath, index : Int) -> JsonPath { + #| Index(self, index~) + #|} + #|pub fn JsonPath::add_key(self : JsonPath, key : String) -> JsonPath { + #| Key(self, key~) + #|} + #|pub impl Show for JsonPath with output(self, logger) { + #| fn write_token(logger : &Logger, token : String) -> Unit { + #| if !token.contains_any(chars="~/") { + #| logger.write_string(token) + #| return + #| } + #| for ch in token.iter() { + #| match ch { + #| '~' => logger.write_string("~0") + #| '/' => logger.write_string("~1") + #| _ => logger.write_char(ch) + #| } + #| } + #| } + #| fn build_path(path : JsonPath, logger : &Logger) -> Unit { + #| match path { + #| Root => () + #| Key(parent, key~) => { + #| build_path(parent, logger) + #| logger.write_char('/') + #| write_token(logger, key) + #| } + #| Index(parent, index~) => { + #| build_path(parent, logger) + #| logger.write_char('/') + #| logger.write_object(index) + #| } + #| } + #| } + #| build_path(self, logger) + #|} + #|pub impl ToJson for JsonPath with to_json(self) { + #| String(self.to_string()) + #|} + #|test "show JsonPath - JSON Pointer format" { + #| @builtin.inspect(Root, content="") + #| @builtin.inspect(Root.add_key("foo"), content="/foo") + #| @builtin.inspect(Root.add_index(0), content="/0") + #| let path : JsonPath = Key(Index(Root, index=0), key="foo") + #| @builtin.inspect(path, content="/0/foo") + #| @builtin.inspect(path.add_index(1), content="/0/foo/1") + #| @builtin.inspect(path.add_key("bar"), content="/0/foo/bar") + #| @builtin.inspect( + #| Root.add_key("foo").add_key("foo1").add_index(2), + #| content="/foo/foo1/2", + #| ) + #| @builtin.inspect(Root.add_key("foo").add_key("foo1"), content="/foo/foo1") + #| @builtin.inspect( + #| Root.add_key("foo").add_key("foo1").add_index(2).add_key("bar"), + #| content="/foo/foo1/2/bar", + #| ) + #| @builtin.inspect( + #| Root.add_key("foo").add_key("foo1").add_index(2).add_key("bar").add_index(3), + #| content="/foo/foo1/2/bar/3", + #| ) + #| @builtin.inspect( + #| Root + #| .add_key("foo") + #| .add_key("foo1") + #| .add_index(2) + #| .add_key("bar") + #| .add_index(3) + #| .add_key("baz"), + #| content="/foo/foo1/2/bar/3/baz", + #| ) + #| @builtin.inspect( + #| Root.add_key("foo").add_key("foo1").add_index(2).add_index(3).add_index(4), + #| content="/foo/foo1/2/3/4", + #| ) + #|} + #|test "show JsonPath - special characters escaping" { + #| @builtin.inspect(Root.add_key("foo~bar"), content="/foo~0bar") + #| @builtin.inspect(Root.add_key("foo~~bar~~"), content="/foo~0~0bar~0~0") + #| @builtin.inspect(Root.add_key("foo/bar"), content="/foo~1bar") + #| @builtin.inspect(Root.add_key("foo//bar//"), content="/foo~1~1bar~1~1") + #| @builtin.inspect(Root.add_key("foo~/bar"), content="/foo~0~1bar") + #| @builtin.inspect(Root.add_key("~foo/bar~"), content="/~0foo~1bar~0") + #| @builtin.inspect( + #| Root.add_key("a/b").add_key("c~d").add_index(0).add_key("e~/f"), + #| content="/a~1b/c~0d/0/e~0~1f", + #| ) + #| @builtin.inspect(Root.add_key(""), content="/") + #| @builtin.inspect(Root.add_key("~/"), content="/~0~1") + #|} + #|test "show JsonPath - RFC 6901 compliance examples" { + #| @builtin.inspect(Root, content="") + #| @builtin.inspect(Root.add_key("foo"), content="/foo") + #| @builtin.inspect(Root.add_key("foo").add_index(0), content="/foo/0") + #| @builtin.inspect(Root.add_key(""), content="/") + #| @builtin.inspect(Root.add_key("a/b"), content="/a~1b") + #| @builtin.inspect(Root.add_key("c%d"), content="/c%d") + #| @builtin.inspect(Root.add_key("e^f"), content="/e^f") + #| @builtin.inspect(Root.add_key("g|h"), content="/g|h") + #| @builtin.inspect(Root.add_key("i\\j"), content="/i\\j") + #| @builtin.inspect(Root.add_key("k\"l"), content="/k\"l") + #| @builtin.inspect(Root.add_key(" "), content="/ ") + #| @builtin.inspect(Root.add_key("m~n"), content="/m~0n") + #|} + ), + "lex_main.mbt": ( + #|fn ParseContext::lex_value( + #| ctx : ParseContext, + #| allow_rbracket~ : Bool, + #|) -> Token raise ParseError { + #| ctx.lex_skip_whitespace() + #| match ctx.read_char() { + #| Some('{') => return LBrace + #| Some('[') => return LBracket + #| Some(']') => + #| if allow_rbracket { + #| return RBracket + #| } else { + #| ctx.invalid_char(shift=-1) + #| } + #| Some('n') => { + #| ctx.expect_ascii_char('u') + #| ctx.expect_ascii_char('l') + #| ctx.expect_ascii_char('l') + #| return Null + #| } + #| Some('t') => { + #| ctx.expect_ascii_char('r') + #| ctx.expect_ascii_char('u') + #| ctx.expect_ascii_char('e') + #| return True + #| } + #| Some('f') => { + #| ctx.expect_ascii_char('a') + #| ctx.expect_ascii_char('l') + #| ctx.expect_ascii_char('s') + #| ctx.expect_ascii_char('e') + #| return False + #| } + #| Some('-') => + #| match ctx.read_char() { + #| Some('0') => { + #| let (n, repr) = ctx.lex_zero(start=ctx.offset - 2) + #| return Number(n, repr.map(repr => repr.to_string())) + #| } + #| Some(c2) => { + #| if c2 is ('1'..='9') { + #| let (n, repr) = ctx.lex_decimal_integer(start=ctx.offset - 2) + #| return Number(n, repr.map(repr => repr.to_string())) + #| } + #| ctx.invalid_char(shift=-1) + #| } + #| None => raise InvalidEof + #| } + #| Some('0') => { + #| let (n, repr) = ctx.lex_zero(start=ctx.offset - 1) + #| return Number(n, repr.map(repr => repr.to_string())) + #| } + #| Some('1'..='9') => { + #| let (n, repr) = ctx.lex_decimal_integer(start=ctx.offset - 1) + #| return Number(n, repr.map(repr => repr.to_string())) + #| } + #| Some('"') => { + #| let s = ctx.lex_string() + #| return String(s) + #| } + #| Some(c) => { + #| let shift = -c.utf16_len() + #| ctx.invalid_char(shift~) + #| } + #| None => raise InvalidEof + #| } + #|} + ), + "lex_misc.mbt": ( + #|fn ParseContext::read_char(ctx : ParseContext) -> Char? { + #| if ctx.offset < ctx.end_offset { + #| let c1 = ctx.input.unsafe_get(ctx.offset).to_int() + #| ctx.offset += 1 + #| if c1 >= 0xD800 && c1 <= 0xDBFF { + #| if ctx.offset < ctx.end_offset { + #| let c2 = ctx.input.unsafe_get(ctx.offset).to_int() + #| if c2 >= 0xDC00 && c2 <= 0xDFFF { + #| ctx.offset += 1 + #| let c3 = (c1 << 10) + c2 - 0x35fdc00 + #| return Some(c3.unsafe_to_char()) + #| } + #| } + #| } + #| Some(c1.unsafe_to_char()) + #| } else { + #| None + #| } + #|} + #|const SURROGATE_LOW_CHAR = 0xD800 + #|const SURROGATE_HIGH_CHAR = 0xDFFF + #|fn ParseContext::expect_char( + #| ctx : ParseContext, + #| c : Char, + #|) -> Unit raise ParseError { + #| guard ctx.offset < ctx.end_offset else { raise InvalidEof } + #| let c1 = ctx.input.unsafe_get(ctx.offset).to_int() + #| ctx.offset += 1 + #| let c0 = c.to_int() + #| if c0 < 0xFFFF { + #| if c0 != c1 { + #| ctx.invalid_char(shift=-1) + #| } + #| } else { + #| guard c1 is (SURROGATE_LOW_CHAR..=SURROGATE_HIGH_CHAR) && + #| ctx.offset < ctx.end_offset else { + #| ctx.invalid_char(shift=-1) + #| } + #| let c2 = ctx.input.unsafe_get(ctx.offset).to_int() + #| let c3 = (c1 << 10) + c2 - 0x35fdc00 + #| if c3 != c0 { + #| ctx.invalid_char(shift=-1) + #| } else { + #| ctx.offset += 1 // consume and move forward + #| } + #| } + #|} + #|fn ParseContext::expect_ascii_char( + #| ctx : ParseContext, + #| c : Byte, + #|) -> Unit raise ParseError { + #| guard ctx.offset < ctx.end_offset else { raise InvalidEof } + #| let c1 = ctx.input.unsafe_get(ctx.offset).to_int() + #| ctx.offset += 1 + #| if c.to_int() != c1 { + #| ctx.invalid_char(shift=-1) + #| } + #|} + #|test "expect_char" { + #| let ctx = ParseContext::make("abc", 1) + #| ctx.expect_char('a') + #| ctx.expect_char('b') + #| ctx.expect_char('c') + #| json_inspect(try? ctx.expect_char('d'), content={ "Err": "InvalidEof" }) + #|} + #|test "expect_char with surrogate pair" { + #| let ctx = ParseContext::make("a\u{1F600}bc\u{1F600}c", 1) + #| ctx.expect_char('a') + #| ctx.expect_char((0x1F600).unsafe_to_char()) + #| ctx.expect_char('b') + #| ctx.expect_char('c') + #| ctx.expect_char((0x1F600).unsafe_to_char()) + #| ctx.expect_char('c') + #| json_inspect(try? ctx.expect_char('d'), content={ "Err": "InvalidEof" }) + #|} + #|fn ParseContext::lex_skip_whitespace(ctx : ParseContext) -> Unit { + #| let rest = ctx.input.view(start_offset=ctx.offset, end_offset=ctx.end_offset) + #| lexmatch rest { + #| ("[ \t\r\n]+", next) => ctx.offset = ctx.end_offset - next.length() + #| _ => () + #| } + #|} + #|fn ParseContext::lex_after_array_value( + #| ctx : ParseContext, + #|) -> Token raise ParseError { + #| ctx.lex_skip_whitespace() + #| match ctx.read_char() { + #| Some(']') => RBracket + #| Some(',') => Comma + #| Some(_) => ctx.invalid_char(shift=-1) + #| None => raise InvalidEof + #| } + #|} + #|fn ParseContext::lex_after_property_name( + #| ctx : ParseContext, + #|) -> Unit raise ParseError { + #| ctx.lex_skip_whitespace() + #| match ctx.read_char() { + #| Some(':') => () + #| Some(_) => ctx.invalid_char(shift=-1) + #| None => raise InvalidEof + #| } + #|} + #|fn ParseContext::lex_after_object_value( + #| ctx : ParseContext, + #|) -> Token raise ParseError { + #| ctx.lex_skip_whitespace() + #| match ctx.read_char() { + #| Some('}') => RBrace + #| Some(',') => Comma + #| Some(_) => ctx.invalid_char(shift=-1) + #| None => raise InvalidEof + #| } + #|} + #|fn ParseContext::lex_property_name( + #| ctx : ParseContext, + #|) -> Token raise ParseError { + #| ctx.lex_skip_whitespace() + #| match ctx.read_char() { + #| Some('}') => RBrace + #| Some('"') => { + #| let s = ctx.lex_string() + #| String(s) + #| } + #| Some(_) => ctx.invalid_char(shift=-1) + #| None => raise InvalidEof + #| } + #|} + #|fn ParseContext::lex_property_name2( + #| ctx : ParseContext, + #|) -> Token raise ParseError { + #| ctx.lex_skip_whitespace() + #| match ctx.read_char() { + #| Some('"') => { + #| let s = ctx.lex_string() + #| String(s) + #| } + #| Some(_) => ctx.invalid_char(shift=-1) + #| None => raise InvalidEof + #| } + #|} + ), + "lex_number.mbt": ( + #|fn ParseContext::lex_decimal_integer( + #| ctx : ParseContext, + #| start~ : Int, + #|) -> (Double, StringView?) raise ParseError { + #| for ;; { + #| match ctx.read_char() { + #| Some('.') => return ctx.lex_decimal_point(start~) + #| Some('e' | 'E') => return ctx.lex_decimal_exponent(start~) + #| Some(c) => { + #| if c >= '0' && c <= '9' { + #| continue + #| } + #| ctx.offset -= 1 + #| return ctx.lex_number_end(start, ctx.offset) + #| } + #| None => return ctx.lex_number_end(start, ctx.offset) + #| } + #| } + #|} + #|fn ParseContext::lex_decimal_point( + #| ctx : ParseContext, + #| start~ : Int, + #|) -> (Double, StringView?) raise ParseError { + #| match ctx.read_char() { + #| Some(c) => + #| if c >= '0' && c <= '9' { + #| ctx.lex_decimal_fraction(start~) + #| } else { + #| ctx.invalid_char(shift=-1) + #| } + #| None => raise InvalidEof + #| } + #|} + #|fn ParseContext::lex_decimal_fraction( + #| ctx : ParseContext, + #| start~ : Int, + #|) -> (Double, StringView?) raise ParseError { + #| for ;; { + #| match ctx.read_char() { + #| Some('e' | 'E') => return ctx.lex_decimal_exponent(start~) + #| Some(c) => { + #| if c >= '0' && c <= '9' { + #| continue + #| } + #| ctx.offset -= 1 + #| return ctx.lex_number_end(start, ctx.offset) + #| } + #| None => return ctx.lex_number_end(start, ctx.offset) + #| } + #| } + #|} + #|fn ParseContext::lex_decimal_exponent( + #| ctx : ParseContext, + #| start~ : Int, + #|) -> (Double, StringView?) raise ParseError { + #| match ctx.read_char() { + #| Some('+') | Some('-') => return ctx.lex_decimal_exponent_sign(start~) + #| Some(c) => { + #| if c >= '0' && c <= '9' { + #| return ctx.lex_decimal_exponent_integer(start~) + #| } + #| ctx.offset -= 1 + #| ctx.invalid_char() + #| } + #| None => raise InvalidEof + #| } + #|} + #|fn ParseContext::lex_decimal_exponent_sign( + #| ctx : ParseContext, + #| start~ : Int, + #|) -> (Double, StringView?) raise ParseError { + #| match ctx.read_char() { + #| Some(c) => { + #| if c >= '0' && c <= '9' { + #| return ctx.lex_decimal_exponent_integer(start~) + #| } + #| ctx.offset -= 1 + #| ctx.invalid_char() + #| } + #| None => raise InvalidEof + #| } + #|} + #|fn ParseContext::lex_decimal_exponent_integer( + #| ctx : ParseContext, + #| start~ : Int, + #|) -> (Double, StringView?) { + #| for ;; { + #| match ctx.read_char() { + #| Some(c) => { + #| if c >= '0' && c <= '9' { + #| continue + #| } + #| ctx.offset -= 1 + #| return ctx.lex_number_end(start, ctx.offset) + #| } + #| None => return ctx.lex_number_end(start, ctx.offset) + #| } + #| } + #|} + #|fn ParseContext::lex_zero( + #| ctx : ParseContext, + #| start~ : Int, + #|) -> (Double, StringView?) raise ParseError { + #| match ctx.read_char() { + #| Some('.') => ctx.lex_decimal_point(start~) + #| Some('e' | 'E') => ctx.lex_decimal_exponent(start~) + #| Some(c) => { + #| if c >= '0' && c <= '9' { + #| ctx.offset -= 1 + #| ctx.invalid_char() + #| } + #| ctx.offset -= 1 + #| return ctx.lex_number_end(start, ctx.offset) + #| } + #| None => return ctx.lex_number_end(start, ctx.offset) + #| } + #|} + #|fn ParseContext::lex_number_end( + #| ctx : ParseContext, + #| start : Int, + #| end : Int, + #|) -> (Double, StringView?) { + #| let s = ctx.input.view(start_offset=start, end_offset=end) + #| if !s.contains(".") && !s.contains("e") && !s.contains("E") { + #| let parsed_int = try? @strconv.parse_int64(s) + #| match parsed_int { + #| Ok(i) if i <= 9007199254740991 && i >= -9007199254740991 => + #| return (i.to_double(), None) + #| _ => + #| return if s is ['-', ..] { + #| (@double.neg_infinity, Some(s)) + #| } else { + #| (@double.infinity, Some(s)) + #| } + #| } + #| } else { + #| let parsed_double = try? @strconv.parse_double(s) + #| match parsed_double { + #| Ok(d) => (d, None) + #| Err(_) => + #| if s is ['-', ..] { + #| (@double.neg_infinity, Some(s)) + #| } else { + #| (@double.infinity, Some(s)) + #| } + #| } + #| } + #|} + ), + "lex_string.mbt": ( + #|fn ParseContext::lex_string(ctx : ParseContext) -> String raise ParseError { + #| let buf = StringBuilder::new() + #| let mut start = ctx.offset + #| fn flush(end : Int) { + #| if start > 0 && end > start { + #| buf.write_view(ctx.input[start:end]) + #| } + #| } + #| for ;; { + #| match ctx.read_char() { + #| Some('"') => { + #| flush(ctx.offset - 1) + #| break + #| } + #| Some('\n' | '\r') => ctx.invalid_char(shift=-1) + #| Some('\\') => { + #| flush(ctx.offset - 1) + #| match ctx.read_char() { + #| Some('b') => buf.write_char('\b') + #| Some('f') => buf.write_char('\u{0C}') + #| Some('n') => buf.write_char('\n') + #| Some('r') => buf.write_char('\r') + #| Some('t') => buf.write_char('\t') + #| Some('"') => buf.write_char('"') + #| Some('\\') => buf.write_char('\\') + #| Some('/') => buf.write_char('/') + #| Some('u') => { + #| let c = ctx.lex_hex_digits(4) + #| buf.write_char(c.unsafe_to_char()) + #| } + #| Some(_) => ctx.invalid_char(shift=-1) + #| None => raise InvalidEof + #| } + #| start = ctx.offset + #| } + #| Some(ch) => + #| if ch.to_int() < 32 { + #| ctx.invalid_char(shift=-1) + #| } else { + #| continue + #| } + #| None => raise InvalidEof + #| } + #| } + #| buf.to_string() + #|} + #|fn ParseContext::lex_hex_digits( + #| ctx : ParseContext, + #| n : Int, + #|) -> Int raise ParseError { + #| for _ in 0.. + #| if c >= 'A' { + #| let d = (c.to_int() & (32).lnot()) - 'A'.to_int() + 10 + #| if d > 15 { + #| ctx.invalid_char(shift=-1) + #| } + #| continue (r << 4) | d + #| } else if c >= '0' { + #| let d = c.to_int() - '0'.to_int() + #| if d > 9 { + #| ctx.invalid_char(shift=-1) + #| } + #| continue (r << 4) | d + #| } else { + #| ctx.invalid_char(shift=-1) + #| } + #| None => raise InvalidEof + #| } + #| } nobreak { + #| r + #| } + #|} + ), + "parse.mbt": ( + #|pub fn valid(input : StringView) -> Bool { + #| try { + #| parse(input) |> ignore + #| true + #| } catch { + #| _ => return false + #| } + #|} + #|#label_migration(max_nesting_depth, fill=false) + #|pub fn parse( + #| input : StringView, + #| max_nesting_depth? : Int = 1024, + #|) -> Json raise ParseError { + #| let ctx = ParseContext::make(input, max_nesting_depth) + #| let val = ctx.parse_value() + #| ctx.lex_skip_whitespace() + #| if ctx.offset >= ctx.end_offset { + #| val + #| } else { + #| ctx.invalid_char() + #| } + #|} + #|fn ParseContext::parse_value(ctx : ParseContext) -> Json raise ParseError { + #| let tok = ctx.lex_value(allow_rbracket=false) + #| ctx.parse_value2(tok) + #|} + #|fn ParseContext::parse_value2( + #| ctx : ParseContext, + #| tok : Token, + #|) -> Json raise ParseError { + #| match tok { + #| Null => null + #| True => Json::boolean(true) + #| False => Json::boolean(false) + #| Number(n, repr) => Json::number(n, repr?) + #| String(s) => Json::string(s) + #| LBrace => ctx.parse_object() + #| LBracket => ctx.parse_array() + #| RBracket | RBrace | Comma => abort("unreachable") + #| } + #|} + #|fn ParseContext::parse_object(ctx : ParseContext) -> Json raise ParseError { + #| if ctx.remaining_available_depth <= 0 { + #| raise DepthLimitExceeded + #| } + #| ctx.remaining_available_depth -= 1 + #| let map = Map::new() + #| loop ctx.lex_property_name() { + #| RBrace => { + #| ctx.remaining_available_depth += 1 + #| Json::object(map) + #| } + #| String(name) => { + #| ctx.lex_after_property_name() + #| map[name] = ctx.parse_value() + #| match ctx.lex_after_object_value() { + #| Comma => continue ctx.lex_property_name2() + #| RBrace => { + #| ctx.remaining_available_depth += 1 + #| Json::object(map) + #| } + #| _ => abort("unreachable") + #| } + #| } + #| _ => abort("unreachable") + #| } + #|} + #|fn ParseContext::parse_array(ctx : ParseContext) -> Json raise ParseError { + #| if ctx.remaining_available_depth <= 0 { + #| raise DepthLimitExceeded + #| } + #| ctx.remaining_available_depth -= 1 + #| let vec = [] + #| loop ctx.lex_value(allow_rbracket=true) { + #| RBracket => { + #| ctx.remaining_available_depth += 1 + #| Json::array(vec) + #| } + #| tok => { + #| vec.push(ctx.parse_value2(tok)) + #| let tok2 = ctx.lex_after_array_value() + #| match tok2 { + #| Comma => continue ctx.lex_value(allow_rbracket=false) + #| RBracket => { + #| ctx.remaining_available_depth += 1 + #| Json::array(vec) + #| } + #| _ => abort("unreachable") + #| } + #| } + #| } + #|} + ), + "tuple_fromjson.mbt": ( + #|pub impl[A : FromJson, B : FromJson] FromJson for (A, B) with from_json( + #| json, + #| path, + #|) { + #| match json { + #| [a, b] => { + #| let a : A = FromJson::from_json(a, path.add_index(0)) + #| let b : B = FromJson::from_json(b, path.add_index(1)) + #| (a, b) + #| } + #| _ => decode_error(path, "expected tuple of size 2") + #| } + #|} + #|pub impl[A : FromJson, B : FromJson, C : FromJson] FromJson for (A, B, C) with from_json( + #| json, + #| path, + #|) { + #| match json { + #| [a, b, c] => { + #| let a : A = FromJson::from_json(a, path.add_index(0)) + #| let b : B = FromJson::from_json(b, path.add_index(1)) + #| let c : C = FromJson::from_json(c, path.add_index(2)) + #| (a, b, c) + #| } + #| _ => decode_error(path, "expected tuple of size 3") + #| } + #|} + #|pub impl[A : FromJson, B : FromJson, C : FromJson, D : FromJson] FromJson for ( + #| A, + #| B, + #| C, + #| D, + #|) with from_json(json, path) { + #| match json { + #| [a, b, c, d] => { + #| let a : A = FromJson::from_json(a, path.add_index(0)) + #| let b : B = FromJson::from_json(b, path.add_index(1)) + #| let c : C = FromJson::from_json(c, path.add_index(2)) + #| let d : D = FromJson::from_json(d, path.add_index(3)) + #| (a, b, c, d) + #| } + #| _ => decode_error(path, "expected tuple of size 4") + #| } + #|} + #|pub impl[A : FromJson, B : FromJson, C : FromJson, D : FromJson, E : FromJson] FromJson for ( + #| A, + #| B, + #| C, + #| D, + #| E, + #|) with from_json(json, path) { + #| match json { + #| [a, b, c, d, e] => { + #| let a : A = FromJson::from_json(a, path.add_index(0)) + #| let b : B = FromJson::from_json(b, path.add_index(1)) + #| let c : C = FromJson::from_json(c, path.add_index(2)) + #| let d : D = FromJson::from_json(d, path.add_index(3)) + #| let e : E = FromJson::from_json(e, path.add_index(4)) + #| (a, b, c, d, e) + #| } + #| _ => decode_error(path, "expected tuple of size 5") + #| } + #|} + #|pub impl[ + #| A : FromJson, + #| B : FromJson, + #| C : FromJson, + #| D : FromJson, + #| E : FromJson, + #| F : FromJson, + #|] FromJson for (A, B, C, D, E, F) with from_json(json, path) { + #| match json { + #| [a, b, c, d, e, f] => { + #| let a : A = FromJson::from_json(a, path.add_index(0)) + #| let b : B = FromJson::from_json(b, path.add_index(1)) + #| let c : C = FromJson::from_json(c, path.add_index(2)) + #| let d : D = FromJson::from_json(d, path.add_index(3)) + #| let e : E = FromJson::from_json(e, path.add_index(4)) + #| let f : F = FromJson::from_json(f, path.add_index(5)) + #| (a, b, c, d, e, f) + #| } + #| _ => decode_error(path, "expected tuple of size 6") + #| } + #|} + #|pub impl[ + #| A : FromJson, + #| B : FromJson, + #| C : FromJson, + #| D : FromJson, + #| E : FromJson, + #| F : FromJson, + #| G : FromJson, + #|] FromJson for (A, B, C, D, E, F, G) with from_json(json, path) { + #| match json { + #| [a, b, c, d, e, f, g] => { + #| let a : A = FromJson::from_json(a, path.add_index(0)) + #| let b : B = FromJson::from_json(b, path.add_index(1)) + #| let c : C = FromJson::from_json(c, path.add_index(2)) + #| let d : D = FromJson::from_json(d, path.add_index(3)) + #| let e : E = FromJson::from_json(e, path.add_index(4)) + #| let f : F = FromJson::from_json(f, path.add_index(5)) + #| let g : G = FromJson::from_json(g, path.add_index(6)) + #| (a, b, c, d, e, f, g) + #| } + #| _ => decode_error(path, "expected tuple of size 7") + #| } + #|} + #|pub impl[ + #| T0 : FromJson, + #| T1 : FromJson, + #| T2 : FromJson, + #| T3 : FromJson, + #| T4 : FromJson, + #| T5 : FromJson, + #| T6 : FromJson, + #| T7 : FromJson, + #|] FromJson for (T0, T1, T2, T3, T4, T5, T6, T7) with from_json(json, path) { + #| match json { + #| [x0, x1, x2, x3, x4, x5, x6, x7] => { + #| let x0 : T0 = FromJson::from_json(x0, path.add_index(0)) + #| let x1 : T1 = FromJson::from_json(x1, path.add_index(1)) + #| let x2 : T2 = FromJson::from_json(x2, path.add_index(2)) + #| let x3 : T3 = FromJson::from_json(x3, path.add_index(3)) + #| let x4 : T4 = FromJson::from_json(x4, path.add_index(4)) + #| let x5 : T5 = FromJson::from_json(x5, path.add_index(5)) + #| let x6 : T6 = FromJson::from_json(x6, path.add_index(6)) + #| let x7 : T7 = FromJson::from_json(x7, path.add_index(7)) + #| (x0, x1, x2, x3, x4, x5, x6, x7) + #| } + #| _ => decode_error(path, "expected tuple of size 8") + #| } + #|} + #|pub impl[ + #| T0 : FromJson, + #| T1 : FromJson, + #| T2 : FromJson, + #| T3 : FromJson, + #| T4 : FromJson, + #| T5 : FromJson, + #| T6 : FromJson, + #| T7 : FromJson, + #| T8 : FromJson, + #|] FromJson for (T0, T1, T2, T3, T4, T5, T6, T7, T8) with from_json(json, path) { + #| match json { + #| [x0, x1, x2, x3, x4, x5, x6, x7, x8] => { + #| let x0 : T0 = FromJson::from_json(x0, path.add_index(0)) + #| let x1 : T1 = FromJson::from_json(x1, path.add_index(1)) + #| let x2 : T2 = FromJson::from_json(x2, path.add_index(2)) + #| let x3 : T3 = FromJson::from_json(x3, path.add_index(3)) + #| let x4 : T4 = FromJson::from_json(x4, path.add_index(4)) + #| let x5 : T5 = FromJson::from_json(x5, path.add_index(5)) + #| let x6 : T6 = FromJson::from_json(x6, path.add_index(6)) + #| let x7 : T7 = FromJson::from_json(x7, path.add_index(7)) + #| let x8 : T8 = FromJson::from_json(x8, path.add_index(8)) + #| (x0, x1, x2, x3, x4, x5, x6, x7, x8) + #| } + #| _ => decode_error(path, "expected tuple of size 9") + #| } + #|} + #|pub impl[ + #| T0 : FromJson, + #| T1 : FromJson, + #| T2 : FromJson, + #| T3 : FromJson, + #| T4 : FromJson, + #| T5 : FromJson, + #| T6 : FromJson, + #| T7 : FromJson, + #| T8 : FromJson, + #| T9 : FromJson, + #|] FromJson for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) with from_json( + #| json, + #| path, + #|) { + #| match json { + #| [x0, x1, x2, x3, x4, x5, x6, x7, x8, x9] => { + #| let x0 : T0 = FromJson::from_json(x0, path.add_index(0)) + #| let x1 : T1 = FromJson::from_json(x1, path.add_index(1)) + #| let x2 : T2 = FromJson::from_json(x2, path.add_index(2)) + #| let x3 : T3 = FromJson::from_json(x3, path.add_index(3)) + #| let x4 : T4 = FromJson::from_json(x4, path.add_index(4)) + #| let x5 : T5 = FromJson::from_json(x5, path.add_index(5)) + #| let x6 : T6 = FromJson::from_json(x6, path.add_index(6)) + #| let x7 : T7 = FromJson::from_json(x7, path.add_index(7)) + #| let x8 : T8 = FromJson::from_json(x8, path.add_index(8)) + #| let x9 : T9 = FromJson::from_json(x9, path.add_index(9)) + #| (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) + #| } + #| _ => decode_error(path, "expected tuple of size 10") + #| } + #|} + #|pub impl[ + #| T0 : FromJson, + #| T1 : FromJson, + #| T2 : FromJson, + #| T3 : FromJson, + #| T4 : FromJson, + #| T5 : FromJson, + #| T6 : FromJson, + #| T7 : FromJson, + #| T8 : FromJson, + #| T9 : FromJson, + #| T10 : FromJson, + #|] FromJson for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) with from_json( + #| json, + #| path, + #|) { + #| match json { + #| [x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10] => { + #| let x0 : T0 = FromJson::from_json(x0, path.add_index(0)) + #| let x1 : T1 = FromJson::from_json(x1, path.add_index(1)) + #| let x2 : T2 = FromJson::from_json(x2, path.add_index(2)) + #| let x3 : T3 = FromJson::from_json(x3, path.add_index(3)) + #| let x4 : T4 = FromJson::from_json(x4, path.add_index(4)) + #| let x5 : T5 = FromJson::from_json(x5, path.add_index(5)) + #| let x6 : T6 = FromJson::from_json(x6, path.add_index(6)) + #| let x7 : T7 = FromJson::from_json(x7, path.add_index(7)) + #| let x8 : T8 = FromJson::from_json(x8, path.add_index(8)) + #| let x9 : T9 = FromJson::from_json(x9, path.add_index(9)) + #| let x10 : T10 = FromJson::from_json(x10, path.add_index(10)) + #| (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10) + #| } + #| _ => decode_error(path, "expected tuple of size 11") + #| } + #|} + #|pub impl[ + #| T0 : FromJson, + #| T1 : FromJson, + #| T2 : FromJson, + #| T3 : FromJson, + #| T4 : FromJson, + #| T5 : FromJson, + #| T6 : FromJson, + #| T7 : FromJson, + #| T8 : FromJson, + #| T9 : FromJson, + #| T10 : FromJson, + #| T11 : FromJson, + #|] FromJson for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) with from_json( + #| json, + #| path, + #|) { + #| match json { + #| [x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11] => { + #| let x0 : T0 = FromJson::from_json(x0, path.add_index(0)) + #| let x1 : T1 = FromJson::from_json(x1, path.add_index(1)) + #| let x2 : T2 = FromJson::from_json(x2, path.add_index(2)) + #| let x3 : T3 = FromJson::from_json(x3, path.add_index(3)) + #| let x4 : T4 = FromJson::from_json(x4, path.add_index(4)) + #| let x5 : T5 = FromJson::from_json(x5, path.add_index(5)) + #| let x6 : T6 = FromJson::from_json(x6, path.add_index(6)) + #| let x7 : T7 = FromJson::from_json(x7, path.add_index(7)) + #| let x8 : T8 = FromJson::from_json(x8, path.add_index(8)) + #| let x9 : T9 = FromJson::from_json(x9, path.add_index(9)) + #| let x10 : T10 = FromJson::from_json(x10, path.add_index(10)) + #| let x11 : T11 = FromJson::from_json(x11, path.add_index(11)) + #| (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11) + #| } + #| _ => decode_error(path, "expected tuple of size 12") + #| } + #|} + #|pub impl[ + #| T0 : FromJson, + #| T1 : FromJson, + #| T2 : FromJson, + #| T3 : FromJson, + #| T4 : FromJson, + #| T5 : FromJson, + #| T6 : FromJson, + #| T7 : FromJson, + #| T8 : FromJson, + #| T9 : FromJson, + #| T10 : FromJson, + #| T11 : FromJson, + #| T12 : FromJson, + #|] FromJson for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) with from_json( + #| json, + #| path, + #|) { + #| match json { + #| [x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12] => { + #| let x0 : T0 = FromJson::from_json(x0, path.add_index(0)) + #| let x1 : T1 = FromJson::from_json(x1, path.add_index(1)) + #| let x2 : T2 = FromJson::from_json(x2, path.add_index(2)) + #| let x3 : T3 = FromJson::from_json(x3, path.add_index(3)) + #| let x4 : T4 = FromJson::from_json(x4, path.add_index(4)) + #| let x5 : T5 = FromJson::from_json(x5, path.add_index(5)) + #| let x6 : T6 = FromJson::from_json(x6, path.add_index(6)) + #| let x7 : T7 = FromJson::from_json(x7, path.add_index(7)) + #| let x8 : T8 = FromJson::from_json(x8, path.add_index(8)) + #| let x9 : T9 = FromJson::from_json(x9, path.add_index(9)) + #| let x10 : T10 = FromJson::from_json(x10, path.add_index(10)) + #| let x11 : T11 = FromJson::from_json(x11, path.add_index(11)) + #| let x12 : T12 = FromJson::from_json(x12, path.add_index(12)) + #| (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12) + #| } + #| _ => decode_error(path, "expected tuple of size 13") + #| } + #|} + #|pub impl[ + #| T0 : FromJson, + #| T1 : FromJson, + #| T2 : FromJson, + #| T3 : FromJson, + #| T4 : FromJson, + #| T5 : FromJson, + #| T6 : FromJson, + #| T7 : FromJson, + #| T8 : FromJson, + #| T9 : FromJson, + #| T10 : FromJson, + #| T11 : FromJson, + #| T12 : FromJson, + #| T13 : FromJson, + #|] FromJson for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) with from_json( + #| json, + #| path, + #|) { + #| match json { + #| [x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13] => { + #| let x0 : T0 = FromJson::from_json(x0, path.add_index(0)) + #| let x1 : T1 = FromJson::from_json(x1, path.add_index(1)) + #| let x2 : T2 = FromJson::from_json(x2, path.add_index(2)) + #| let x3 : T3 = FromJson::from_json(x3, path.add_index(3)) + #| let x4 : T4 = FromJson::from_json(x4, path.add_index(4)) + #| let x5 : T5 = FromJson::from_json(x5, path.add_index(5)) + #| let x6 : T6 = FromJson::from_json(x6, path.add_index(6)) + #| let x7 : T7 = FromJson::from_json(x7, path.add_index(7)) + #| let x8 : T8 = FromJson::from_json(x8, path.add_index(8)) + #| let x9 : T9 = FromJson::from_json(x9, path.add_index(9)) + #| let x10 : T10 = FromJson::from_json(x10, path.add_index(10)) + #| let x11 : T11 = FromJson::from_json(x11, path.add_index(11)) + #| let x12 : T12 = FromJson::from_json(x12, path.add_index(12)) + #| let x13 : T13 = FromJson::from_json(x13, path.add_index(13)) + #| (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13) + #| } + #| _ => decode_error(path, "expected tuple of size 14") + #| } + #|} + #|pub impl[ + #| T0 : FromJson, + #| T1 : FromJson, + #| T2 : FromJson, + #| T3 : FromJson, + #| T4 : FromJson, + #| T5 : FromJson, + #| T6 : FromJson, + #| T7 : FromJson, + #| T8 : FromJson, + #| T9 : FromJson, + #| T10 : FromJson, + #| T11 : FromJson, + #| T12 : FromJson, + #| T13 : FromJson, + #| T14 : FromJson, + #|] FromJson for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14) with from_json( + #| json, + #| path, + #|) { + #| match json { + #| [x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14] => { + #| let x0 : T0 = FromJson::from_json(x0, path.add_index(0)) + #| let x1 : T1 = FromJson::from_json(x1, path.add_index(1)) + #| let x2 : T2 = FromJson::from_json(x2, path.add_index(2)) + #| let x3 : T3 = FromJson::from_json(x3, path.add_index(3)) + #| let x4 : T4 = FromJson::from_json(x4, path.add_index(4)) + #| let x5 : T5 = FromJson::from_json(x5, path.add_index(5)) + #| let x6 : T6 = FromJson::from_json(x6, path.add_index(6)) + #| let x7 : T7 = FromJson::from_json(x7, path.add_index(7)) + #| let x8 : T8 = FromJson::from_json(x8, path.add_index(8)) + #| let x9 : T9 = FromJson::from_json(x9, path.add_index(9)) + #| let x10 : T10 = FromJson::from_json(x10, path.add_index(10)) + #| let x11 : T11 = FromJson::from_json(x11, path.add_index(11)) + #| let x12 : T12 = FromJson::from_json(x12, path.add_index(12)) + #| let x13 : T13 = FromJson::from_json(x13, path.add_index(13)) + #| let x14 : T14 = FromJson::from_json(x14, path.add_index(14)) + #| (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14) + #| } + #| _ => decode_error(path, "expected tuple of size 15") + #| } + #|} + #|pub impl[ + #| T0 : FromJson, + #| T1 : FromJson, + #| T2 : FromJson, + #| T3 : FromJson, + #| T4 : FromJson, + #| T5 : FromJson, + #| T6 : FromJson, + #| T7 : FromJson, + #| T8 : FromJson, + #| T9 : FromJson, + #| T10 : FromJson, + #| T11 : FromJson, + #| T12 : FromJson, + #| T13 : FromJson, + #| T14 : FromJson, + #| T15 : FromJson, + #|] FromJson for ( + #| T0, + #| T1, + #| T2, + #| T3, + #| T4, + #| T5, + #| T6, + #| T7, + #| T8, + #| T9, + #| T10, + #| T11, + #| T12, + #| T13, + #| T14, + #| T15, + #|) with from_json(json, path) { + #| match json { + #| [x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15] => { + #| let x0 : T0 = FromJson::from_json(x0, path.add_index(0)) + #| let x1 : T1 = FromJson::from_json(x1, path.add_index(1)) + #| let x2 : T2 = FromJson::from_json(x2, path.add_index(2)) + #| let x3 : T3 = FromJson::from_json(x3, path.add_index(3)) + #| let x4 : T4 = FromJson::from_json(x4, path.add_index(4)) + #| let x5 : T5 = FromJson::from_json(x5, path.add_index(5)) + #| let x6 : T6 = FromJson::from_json(x6, path.add_index(6)) + #| let x7 : T7 = FromJson::from_json(x7, path.add_index(7)) + #| let x8 : T8 = FromJson::from_json(x8, path.add_index(8)) + #| let x9 : T9 = FromJson::from_json(x9, path.add_index(9)) + #| let x10 : T10 = FromJson::from_json(x10, path.add_index(10)) + #| let x11 : T11 = FromJson::from_json(x11, path.add_index(11)) + #| let x12 : T12 = FromJson::from_json(x12, path.add_index(12)) + #| let x13 : T13 = FromJson::from_json(x13, path.add_index(13)) + #| let x14 : T14 = FromJson::from_json(x14, path.add_index(14)) + #| let x15 : T15 = FromJson::from_json(x15, path.add_index(15)) + #| (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15) + #| } + #| _ => decode_error(path, "expected tuple of size 16") + #| } + #|} + ), + "types.mbt": ( + #|pub(all) struct Position { + #| line : Int // 1-based + #| column : Int // 0-based + #|} derive(Eq, ToJson) + #|pub(all) suberror ParseError { + #| InvalidChar(Position, Char) + #| InvalidEof + #| InvalidNumber(Position, String) + #| InvalidIdentEscape(Position) + #| DepthLimitExceeded + #|} derive(Eq, ToJson) + #|pub impl Show for ParseError with output(self, logger) { + #| match self { + #| InvalidChar({ line, column }, c) => { + #| logger.write_string("Invalid character ") + #| logger.write_string(c.escape()) + #| logger.write_string(" at line ") + #| logger.write_object(line) + #| logger.write_string(", column ") + #| logger.write_object(column) + #| } + #| InvalidEof => logger.write_string("Unexpected end of file") + #| InvalidNumber({ line, column }, s) => { + #| logger.write_string("Invalid number ") + #| logger.write_string(s) + #| logger.write_string(" at line ") + #| logger.write_object(line) + #| logger.write_string(", column ") + #| logger.write_object(column) + #| } + #| InvalidIdentEscape({ line, column }) => { + #| logger.write_string("Invalid escape sequence in identifier at line ") + #| logger.write_object(line) + #| logger.write_string(", column ") + #| logger.write_object(column) + #| } + #| DepthLimitExceeded => + #| logger.write_string( + #| "Depth limit exceeded, please increase the max_nesting_depth parameter", + #| ) + #| } + #|} + #|pub impl Show for Json with output(self, logger) { + #| match self { + #| Null => logger.write_string("Null") + #| True => logger.write_string("True") + #| False => logger.write_string("False") + #| Number(n, repr~) => { + #| logger.write_string("Number(") + #| Show::output(n, logger) + #| if repr is Some(_) { + #| logger.write_string(", repr=") + #| Show::output(repr, logger) + #| } + #| logger.write_string(")") + #| } + #| String(s) => { + #| logger.write_string("String(") + #| Show::output(s, logger) + #| logger.write_string(")") + #| } + #| Array(a) => { + #| logger.write_string("Array(") + #| Show::output(a, logger) + #| logger.write_string(")") + #| } + #| Object(o) => { + #| logger.write_string("Object(") + #| Show::output(o, logger) + #| logger.write_string(")") + #| } + #| } + #|} + ), + "utils.mbt": ( + #|fn offset_to_position(input : StringView, offset : Int) -> Position { + #| for i in 0.. T raise ParseError { + #| let offset = ctx.offset + shift + #| let replacement_char : Char = '\u{fffd}' + #| raise InvalidChar( + #| offset_to_position(ctx.input, offset), + #| ctx.input.get_char(offset).unwrap_or(replacement_char), + #| ) + #|} + ) + } ) ///| let moonbitlang_core_list_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/list", - deps={ - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/array": moonbitlang_core_array_module, - "moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module, - "moonbitlang/core/json": moonbitlang_core_json_module, - }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| "moonbitlang/core/builtin", - #| "moonbitlang/core/array", - #| "moonbitlang/core/quickcheck", - #| "moonbitlang/core/json" - #| ], - #| "test-import": [], - #| "targets": { - #| "panic_test.mbt": [ - #| "not", - #| "native" - #| ] - #| } - #|} - ), - "deprecated.mbt": ( - #|#deprecated("use `_.to_array().rev_fold(...)` instead") - #|pub fn[A, B] List::rev_fold(self : List[A], init~ : B, f : (B, A) -> B) -> B { - #| let xs = self.to_array() - #| let mut acc = init - #| for x in xs.rev_iter() { - #| acc = f(acc, x) - #| } - #| acc - #|} - #|#deprecated("use `_.rev().foldi(...)` instead") - #|pub fn[A, B] List::rev_foldi( - #| self : List[A], - #| init~ : B, - #| f : (Int, B, A) -> B, - #|) -> B { - #| self.rev().foldi(init~, (i, b, a) => f(i, b, a)) - #|} - #|#deprecated("use `unsafe_tail` instead") - #|pub fn[A] List::tail(self : List[A]) -> List[A] { - #| match self { - #| Empty => Empty - #| More(_, tail~) => tail - #| } - #|} - ), - "list.mbt": ( - #|#alias(empty) - #|#as_free_fn - #|#as_free_fn(empty) - #|pub fn[A] List::new() -> List[A] { - #| Empty - #|} - #|#as_free_fn - #|#as_free_fn(construct, deprecated="Use cons instead") - #|pub fn[A] List::cons(head : A, tail : List[A]) -> List[A] { - #| More(head, tail~) - #|} - #|#alias(add) - #|pub fn[A] List::prepend(self : List[A], head : A) -> List[A] { - #| More(head, tail=self) - #|} - #|pub impl[A : Show] Show for List[A] with output(xs, logger) { - #| logger.write_iter(xs.iter(), prefix="@list.from_array([", suffix="])") - #|} - #|pub impl[A : ToJson] ToJson for List[A] with to_json(self) { - #| let capacity = self.length() - #| guard capacity != 0 else { return [] } - #| let jsons = Array::new(capacity~) - #| for a in self { - #| jsons.push(a.to_json()) - #| } - #| Json::array(jsons) - #|} - #|pub fn[A : ToJson] List::to_json(self : List[A]) -> Json { - #| ToJson::to_json(self) - #|} - #|pub impl[A : @json.FromJson] @json.FromJson for List[A] with from_json( - #| json, - #| path, - #|) { - #| guard json is Array(arr) else { - #| raise @json.JsonDecodeError((path, "@list.from_json: expected array")) - #| } - #| for i = arr.length() - 1, list = Empty; i >= 0; { - #| continue i - 1, list.prepend(A::from_json(arr[i], path.add_index(i))) - #| } else { - #| list - #| } - #|} - #|#as_free_fn - #|pub fn[A : @json.FromJson] List::from_json( - #| json : Json, - #|) -> List[A] raise @json.JsonDecodeError { - #| @json.from_json(json) - #|} - #|#as_free_fn - #|#alias(of, deprecated="Use from_array instead") - #|#as_free_fn(of, deprecated="Use from_array instead") - #|pub fn[A] List::from_array(arr : ArrayView[A]) -> List[A] { - #| for i = arr.length() - 1, list = Empty; i >= 0; { - #| continue i - 1, More(arr[i], tail=list) - #| } else { - #| list - #| } - #|} - #|pub fn[A] List::length(self : List[A]) -> Int { - #| loop (self, 0) { - #| (Empty, len) => len - #| (More(_, tail=rest), acc) => continue (rest, acc + 1) - #| } - #|} - #|#locals(f) - #|pub fn[A] List::each(self : List[A], f : (A) -> Unit raise?) -> Unit raise? { - #| loop self { - #| Empty => () - #| More(head, tail~) => { - #| f(head) - #| continue tail - #| } - #| } - #|} - #|pub fn[A] List::eachi( - #| self : List[A], - #| f : (Int, A) -> Unit raise?, - #|) -> Unit raise? { - #| loop (self, 0) { - #| (Empty, _) => () - #| (More(x, tail=xs), i) => { - #| f(i, x) - #| continue (xs, i + 1) - #| } - #| } - #|} - #|pub fn[A, B] List::map(self : List[A], f : (A) -> B raise?) -> List[B] raise? { - #| match self { - #| Empty => Empty - #| More(hd, tail~) => { - #| let dest = More(f(hd), tail=Empty) - #| loop (dest, tail) { - #| (_, Empty) => () - #| (More(_) as dest, More(hd, tail~)) => { - #| dest.tail = More(f(hd), tail=Empty) - #| continue (dest.tail, tail) - #| } - #| (Empty, _) => panic() - #| } - #| dest - #| } - #| } - #|} - #|pub fn[A, B] List::mapi( - #| self : List[A], - #| f : (Int, A) -> B raise?, - #|) -> List[B] raise? { - #| match self { - #| Empty => Empty - #| More(hd, tail~) => { - #| let dest = More(f(0, hd), tail=Empty) - #| loop (1, dest, tail) { - #| (_, _, Empty) => () - #| (i, More(_) as dest, More(hd, tail~)) => { - #| dest.tail = More(f(i, hd), tail=Empty) - #| continue (i + 1, dest.tail, tail) - #| } - #| (_, Empty, _) => panic() - #| } - #| dest - #| } - #| } - #|} - #|pub fn[A, B] List::rev_map( - #| self : List[A], - #| f : (A) -> B raise?, - #|) -> List[B] raise? { - #| loop (Empty, self) { - #| (acc, Empty) => acc - #| (acc, More(x, tail=xs)) => continue (More(f(x), tail=acc), xs) - #| } - #|} - #|pub fn[A] List::to_array(self : List[A]) -> Array[A] { - #| match self { - #| Empty => [] - #| More(x, tail=xs) => { - #| let arr = [x] - #| loop xs { - #| Empty => () - #| More(x, tail=xs) => { - #| arr.push(x) - #| continue xs - #| } - #| } - #| arr - #| } - #| } - #|} - #|pub fn[A] List::filter( - #| self : List[A], - #| f : (A) -> Bool raise?, - #|) -> List[A] raise? { - #| loop self { - #| Empty => Empty - #| More(head, tail~) => - #| if !f(head) { - #| continue tail - #| } else { - #| let dest = More(head, tail=Empty) - #| loop (dest, tail) { - #| (_, Empty) => () - #| (More(_) as dest, More(hd, tail~)) => - #| if f(hd) { - #| dest.tail = More(hd, tail=Empty) - #| continue (dest.tail, tail) - #| } else { - #| continue (dest, tail) - #| } - #| (Empty, _) => - #| panic() - #| } - #| dest - #| } - #| } - #|} - #|pub fn[A] List::all(self : List[A], f : (A) -> Bool raise?) -> Bool raise? { - #| loop self { - #| Empty => true - #| More(head, tail~) => if f(head) { continue tail } else { false } - #| } - #|} - #|pub fn[A] List::any(self : List[A], f : (A) -> Bool raise?) -> Bool raise? { - #| loop self { - #| Empty => false - #| More(head, tail~) => if f(head) { true } else { continue tail } - #| } - #|} - #|#internal(unsafe, "Panic if the list is empty") - #|#doc(hidden) - #|pub fn[A] List::unsafe_head(self : List[A]) -> A { - #| match self { - #| Empty => abort("head of empty list") - #| More(head, tail=_) => head - #| } - #|} - #|pub fn[A] List::unsafe_tail(self : List[A]) -> List[A] { - #| match self { - #| Empty => abort("tail of empty list") - #| More(_, tail~) => tail - #| } - #|} - #|pub fn[A] List::head(self : List[A]) -> A? { - #| match self { - #| Empty => None - #| More(head, tail=_) => Some(head) - #| } - #|} - #|#internal(unsafe, "Panic if the list is empty") - #|#doc(hidden) - #|pub fn[A] List::unsafe_last(self : List[A]) -> A { - #| loop self { - #| Empty => abort("last of empty list") - #| More(head, tail=Empty) => head - #| More(_, tail~) => continue tail - #| } - #|} - #|pub fn[A] List::last(self : List[A]) -> A? { - #| loop self { - #| Empty => None - #| More(head, tail=Empty) => Some(head) - #| More(_, tail~) => continue tail - #| } - #|} - #|pub fn[A] List::concat(self : List[A], other : List[A]) -> List[A] { - #| match self { - #| Empty => other - #| More(hd, tail=Empty) => More(hd, tail=other) - #| More(hd, tail~) => { - #| let dest = More(hd, tail=Empty) - #| loop (dest, tail) { - #| (More(_) as dest, Empty) => dest.tail = other - #| (More(_) as dest, More(head, tail~)) => { - #| dest.tail = More(head, tail=Empty) - #| continue (dest.tail, tail) - #| } - #| (Empty, _) => panic() - #| } - #| dest - #| } - #| } - #|} - #|pub fn[A] List::rev_concat(self : List[A], other : List[A]) -> List[A] { - #| loop (self, other) { - #| (Empty, other) => other - #| (More(head, tail~), other) => continue (tail, More(head, tail=other)) - #| } - #|} - #|pub fn[A] List::rev(self : List[A]) -> List[A] { - #| self.rev_concat(Empty) - #|} - #|pub fn[A, B] List::fold( - #| self : List[A], - #| init~ : B, - #| f : (B, A) -> B raise?, - #|) -> B raise? { - #| loop (self, init) { - #| (Empty, acc) => acc - #| (More(head, tail~), acc) => continue (tail, f(acc, head)) - #| } - #|} - #|pub fn[A, B] List::foldi( - #| self : List[A], - #| init~ : B, - #| f : (Int, B, A) -> B raise?, - #|) -> B raise? { - #| fn go( - #| xs : List[A], - #| i : Int, - #| f : (Int, B, A) -> B raise?, - #| acc : B, - #| ) -> B raise? { - #| match xs { - #| Empty => acc - #| More(x, tail=xs) => go(xs, i + 1, f, f(i, acc, x)) - #| } - #| } - #| go(self, 0, f, init) - #|} - #|#as_free_fn - #|pub fn[A, B] List::zip(self : List[A], other : List[B]) -> List[(A, B)] { - #| let res = loop (self, other, Empty) { - #| (Empty, _, acc) => break acc - #| (_, Empty, acc) => break acc - #| (More(x, tail=xs), More(y, tail=ys), acc) => - #| continue (xs, ys, More((x, y), tail=acc)) - #| } - #| res.reverse_in_place() - #|} - #|pub fn[A, B] List::flat_map( - #| self : List[A], - #| f : (A) -> List[B] raise?, - #|) -> List[B] raise? { - #| loop self { - #| Empty => Empty - #| More(head, tail~) => - #| match f(head) { - #| Empty => continue tail - #| More(hd, tail=tl) => { - #| let dest = More(hd, tail=Empty) - #| let dest1 = loop (dest, tl) { - #| (dest, Empty) => dest - #| (More(_) as dest, More(hd, tail~)) => { - #| dest.tail = More(hd, tail=Empty) - #| continue (dest.tail, tail) - #| } - #| (Empty, _) => panic() - #| } - #| loop_over_tail~: loop (dest1, tail) { - #| (_, Empty) => () - #| (More(_) as dest, More(t_hd, tail=Empty)) => dest.tail = f(t_hd) - #| (dest, More(t_hd, tail=t_tl)) => - #| loop (dest, f(t_hd)) { - #| (dest, Empty) => continue loop_over_tail~ (dest, t_tl) - #| (More(_) as dest, More(hd, tail~)) => { - #| dest.tail = More(hd, tail=Empty) - #| continue (dest.tail, tail) - #| } - #| (Empty, _) => panic() - #| } - #| } - #| dest - #| } - #| } - #| } - #|} - #|pub fn[A, B] List::filter_map( - #| self : List[A], - #| f : (A) -> B? raise?, - #|) -> List[B] raise? { - #| loop self { - #| Empty => Empty - #| More(hd, tail~) => - #| match f(hd) { - #| None => continue tail - #| Some(head) => { - #| let dest = More(head, tail=Empty) - #| loop (dest, tail) { - #| (_, Empty) => () - #| (More(_) as dest, More(hd, tail~)) => - #| match f(hd) { - #| None => continue (dest, tail) - #| Some(head) => { - #| dest.tail = More(head, tail=Empty) - #| continue (dest.tail, tail) - #| } - #| } - #| (Empty, _) => panic() - #| } - #| dest - #| } - #| } - #| } - #|} - #|#internal(unsafe, "Panic if the index is out of bounds") - #|#doc(hidden) - #|pub fn[A] List::unsafe_nth(self : List[A], n : Int) -> A { - #| loop (self, n) { - #| (Empty, _) => abort("nth: index out of bounds") - #| (More(head, tail=_), 0) => head - #| (More(_, tail~), n) => continue (tail, n - 1) - #| } - #|} - #|pub fn[A] List::nth(self : List[A], n : Int) -> A? { - #| loop (self, n) { - #| (Empty, _) => None - #| (More(head, tail=_), 0) => Some(head) - #| (More(_, tail~), n) => continue (tail, n - 1) - #| } - #|} - #|#as_free_fn - #|pub fn[A] List::repeat(n : Int, x : A) -> List[A] { - #| loop (Empty, n) { - #| (acc, n) => if n <= 0 { acc } else { continue (More(x, tail=acc), n - 1) } - #| } - #|} - #|pub fn[A] List::intersperse(self : List[A], separator : A) -> List[A] { - #| match self { - #| Empty => Empty - #| More(head, tail=Empty) => More(head, tail=Empty) - #| More(head, tail~) => { - #| let dest = More(head, tail=Empty) - #| loop (dest, tail) { - #| (_, Empty) => () - #| (More(_) as dest, More(hd, tail=tl)) => { - #| let new_tail = More(hd, tail=Empty) - #| dest.tail = More(separator, tail=new_tail) - #| continue (new_tail, tl) - #| } - #| (Empty, _) => panic() - #| } - #| dest - #| } - #| } - #|} - #|pub fn[A] List::is_empty(self : List[A]) -> Bool { - #| self is Empty - #|} - #|pub fn[A, B] List::unzip(self : List[(A, B)]) -> (List[A], List[B]) { - #| match self { - #| Empty => (Empty, Empty) - #| More((x, y), tail~) => { - #| let xs = More(x, tail=Empty) - #| let ys = More(y, tail=Empty) - #| loop (tail, xs, ys) { - #| (Empty, _, _) => () - #| (More((x, y), tail~), More(_) as xptr, More(_) as yptr) => { - #| xptr.tail = More(x, tail=Empty) - #| yptr.tail = More(y, tail=Empty) - #| continue (tail, xptr.tail, yptr.tail) - #| } - #| (_, _, _) => abort("unreachable") - #| } - #| (xs, ys) - #| } - #| } - #|} - #|pub fn[A] List::flatten(self : List[List[A]]) -> List[A] { - #| loop self { - #| Empty => Empty - #| More(head, tail~) => - #| match head { - #| Empty => continue tail - #| More(hd, tail=tl) => { - #| let dest = More(hd, tail=Empty) - #| let dest1 = loop (dest, tl) { - #| (dest, Empty) => dest - #| (More(_) as dest, More(hd, tail~)) => { - #| dest.tail = More(hd, tail=Empty) - #| continue (dest.tail, tail) - #| } - #| (Empty, _) => panic() - #| } - #| loop_over_tail~: loop (dest1, tail) { - #| (_, Empty) => () - #| (More(_) as dest, More(t_hd, tail=Empty)) => dest.tail = t_hd - #| (dest, More(t_hd, tail=t_tl)) => - #| loop (dest, t_hd) { - #| (dest, Empty) => continue loop_over_tail~ (dest, t_tl) - #| (More(_) as dest, More(hd, tail~)) => { - #| dest.tail = More(hd, tail=Empty) - #| continue (dest.tail, tail) - #| } - #| (Empty, _) => panic() - #| } - #| } - #| dest - #| } - #| } - #| } - #|} - #|#internal(unsafe, "Panic if the list is empty") - #|#doc(hidden) - #|pub fn[A : Compare] List::unsafe_maximum(self : List[A]) -> A { - #| match self { - #| Empty => abort("maximum: empty list") - #| More(head, tail~) => - #| loop (tail, head) { - #| (Empty, curr_max) => curr_max - #| (More(item, tail~), curr_max) => - #| continue (tail, if item > curr_max { item } else { curr_max }) - #| } - #| } - #|} - #|pub fn[A : Compare] List::maximum(self : List[A]) -> A? { - #| match self { - #| Empty => None - #| More(head, tail~) => - #| loop (tail, head) { - #| (Empty, curr_max) => Some(curr_max) - #| (More(item, tail~), curr_max) => - #| continue (tail, if item > curr_max { item } else { curr_max }) - #| } - #| } - #|} - #|#internal(unsafe, "Panic if the list is empty") - #|#doc(hidden) - #|pub fn[A : Compare] List::unsafe_minimum(self : List[A]) -> A { - #| match self { - #| Empty => abort("minimum: empty list") - #| More(head, tail~) => - #| loop (tail, head) { - #| (Empty, curr_min) => curr_min - #| (More(item, tail~), curr_min) => - #| continue (tail, if item < curr_min { item } else { curr_min }) - #| } - #| } - #|} - #|pub fn[A : Compare] List::minimum(self : List[A]) -> A? { - #| match self { - #| Empty => None - #| More(head, tail~) => - #| loop (tail, head) { - #| (Empty, curr_min) => Some(curr_min) - #| (More(item, tail~), curr_min) => - #| continue (tail, if item < curr_min { item } else { curr_min }) - #| } - #| } - #|} - #|pub fn[A : Compare] List::sort(self : List[A]) -> List[A] { - #| let arr = self.to_array() - #| arr.sort() - #| from_array(arr) - #|} - #|pub impl[A] Add for List[A] with add(self, other) { - #| self.concat(other) - #|} - #|pub fn[A : Eq] List::contains(self : List[A], value : A) -> Bool { - #| loop self { - #| Empty => false - #| More(x, tail=xs) => if x == value { true } else { continue xs } - #| } - #|} - #|#as_free_fn - #|pub fn[A, S] List::unfold( - #| f : (S) -> (A, S)? raise?, - #| init~ : S, - #|) -> List[A] raise? { - #| match f(init) { - #| None => Empty - #| Some((element, new_state)) => { - #| let dest = More(element, tail=Empty) - #| loop (dest, f(new_state)) { - #| (_, None) => () - #| (More(_) as dest, Some((element, new_state))) => { - #| dest.tail = More(element, tail=Empty) - #| continue (dest.tail, f(new_state)) - #| } - #| (Empty, _) => panic() - #| } - #| dest - #| } - #| } - #|} - #|#as_free_fn - #|pub fn[A, S] List::rev_unfold( - #| f : (S) -> (A, S)? raise?, - #| init~ : S, - #|) -> List[A] raise? { - #| loop (f(init), Empty) { - #| (None, acc) => acc - #| (Some((x, s)), acc) => continue (f(s), More(x, tail=acc)) - #| } - #|} - #|pub fn[A] List::take(self : List[A], n : Int) -> List[A] { - #| if n <= 0 { - #| Empty - #| } else { - #| match self { - #| Empty => Empty - #| More(head, tail~) => { - #| let dest = More(head, tail=Empty) - #| loop (dest, tail, n - 1) { - #| (_, Empty, _) => () - #| (_, _, 0) => () - #| (More(_) as dest, More(x, tail=xs), n) => { - #| dest.tail = More(x, tail=Empty) - #| continue (dest.tail, xs, n - 1) - #| } - #| (Empty, _, _) => panic() - #| } - #| dest - #| } - #| } - #| } - #|} - #|pub fn[A] List::drop(self : List[A], n : Int) -> List[A] { - #| if n <= 0 { - #| self - #| } else { - #| loop (n, self) { - #| (_, Empty) => Empty - #| (1, More(_, tail=xs)) => xs - #| (n, More(_, tail=xs)) => continue (n - 1, xs) - #| } - #| } - #|} - #|pub fn[A] List::take_while( - #| self : List[A], - #| p : (A) -> Bool raise?, - #|) -> List[A] raise? { - #| match self { - #| Empty => Empty - #| More(head, tail~) => - #| if p(head) { - #| let dest = More(head, tail=Empty) - #| loop (dest, tail) { - #| (_, Empty) => () - #| (More(_) as dest, More(x, tail=xs)) if p(x) => { - #| dest.tail = More(x, tail=Empty) - #| continue (dest.tail, xs) - #| } - #| (More(_), _) => () - #| (Empty, _) => panic() - #| } - #| dest - #| } else { - #| Empty - #| } - #| } - #|} - #|pub fn[A] List::drop_while( - #| self : List[A], - #| p : (A) -> Bool raise?, - #|) -> List[A] raise? { - #| loop self { - #| Empty => Empty - #| More(x, tail=xs) => if p(x) { continue xs } else { More(x, tail=xs) } - #| } - #|} - #|pub fn[A, E] List::scan_left( - #| self : List[A], - #| f : (E, A) -> E raise?, - #| init~ : E, - #|) -> List[E] raise? { - #| let dest = More(init, tail=Empty) - #| loop (dest, self, init) { - #| (_, Empty, _) => () - #| (Empty, _, _) => panic() - #| (More(_) as dest, More(x, tail=xs), acc) => { - #| dest.tail = More(f(acc, x), tail=Empty) - #| continue (dest.tail, xs, f(acc, x)) - #| } - #| } - #| dest - #|} - #|pub fn[A, B] List::scan_right( - #| self : List[A], - #| f : (B, A) -> B raise?, - #| init~ : B, - #|) -> List[B] raise? { - #| self.rev().scan_left(f, init~).reverse_in_place() - #|} - #|pub fn[A : Eq, B] List::lookup(self : List[(A, B)], v : A) -> B? { - #| loop self { - #| Empty => None - #| More((x, y), tail=xs) => if x == v { Some(y) } else { continue xs } - #| } - #|} - #|pub fn[A] List::find(self : List[A], f : (A) -> Bool raise?) -> A? raise? { - #| loop self { - #| Empty => None - #| More(element, tail=list) => - #| if f(element) { - #| Some(element) - #| } else { - #| continue list - #| } - #| } - #|} - #|pub fn[A] List::find_index( - #| self : Self[A], - #| f : (A) -> Bool raise?, - #|) -> Int? raise? { - #| loop (self, 0) { - #| (Empty, _) => None - #| (More(element, tail=list), idx) => - #| if f(element) { - #| Some(idx) - #| } else { - #| continue (list, idx + 1) - #| } - #| } - #|} - #|pub fn[A] List::findi(self : List[A], f : (A, Int) -> Bool raise?) -> A? raise? { - #| loop (self, 0) { - #| (list, index) => - #| match list { - #| Empty => None - #| More(element, tail=list) => - #| if f(element, index) { - #| Some(element) - #| } else { - #| continue (list, index + 1) - #| } - #| } - #| } - #|} - #|pub fn[A] List::remove_at(self : List[A], index : Int) -> List[A] { - #| match (index, self) { - #| (_, Empty) => Empty - #| (_..<0, _) => self - #| (0, More(_, tail~)) => tail - #| (n, More(head, tail~)) => { - #| let dest = More(head, tail=Empty) - #| loop (dest, tail, n - 1) { - #| (_, Empty, _) => () - #| (More(_) as dest, More(_, tail~), 0) => dest.tail = tail - #| (More(_) as dest, More(x, tail=xs), n) => { - #| dest.tail = More(x, tail=Empty) - #| continue (dest.tail, xs, n - 1) - #| } - #| (Empty, _, _) => panic() - #| } - #| dest - #| } - #| } - #|} - #|pub fn[A : Eq] List::remove(self : List[A], elem : A) -> List[A] { - #| match self { - #| Empty => Empty - #| More(head, tail~) if head == elem => tail - #| More(head, tail~) => { - #| let dest = More(head, tail~) - #| loop (dest, tail) { - #| (_, Empty) => () - #| (More(_) as dest, More(x, tail=xs)) => - #| if x == elem { - #| dest.tail = xs - #| } else { - #| dest.tail = More(x, tail=Empty) - #| continue (dest.tail, xs) - #| } - #| (Empty, _) => panic() - #| } - #| dest - #| } - #| } - #|} - #|pub fn[A : Eq] List::is_prefix(self : List[A], prefix : List[A]) -> Bool { - #| loop (self, prefix) { - #| (_, Empty) => true - #| (Empty, More(_)) => false - #| (More(h1, tail=t1), More(h2, tail=t2)) => - #| if h1 == h2 { - #| continue (t1, t2) - #| } else { - #| false - #| } - #| } - #|} - #|pub fn[A : Eq] List::is_suffix(self : List[A], suffix : List[A]) -> Bool { - #| self.rev().is_prefix(suffix.rev()) - #|} - #|pub fn[A] List::intercalate(self : List[List[A]], sep : List[A]) -> List[A] { - #| self.intersperse(sep).flatten() - #|} - #|pub impl[X] Default for List[X] with default() { - #| Empty - #|} - #|pub fn[X] default() -> List[X] { - #| Empty - #|} - #|pub fn[A] List::iter(self : List[A]) -> Iter[A] { - #| self.iterator().iter() - #|} - #|pub fn[A] List::iterator(self : List[A]) -> Iterator[A] { - #| let mut next = self - #| Iterator::new(fn() { - #| match next { - #| Empty => None - #| More(head, tail~) => { - #| next = tail - #| Some(head) - #| } - #| } - #| }) - #|} - #|pub fn[A] List::iter2(self : List[A]) -> Iter2[Int, A] { - #| self.Iter2().iter2() - #|} - #|pub fn[A] List::Iter2(self : List[A]) -> Iter2[Int, A] { - #| let mut i = 0 - #| let mut next = self - #| Iter2::new(fn() { - #| match next { - #| Empty => None - #| More(head, tail~) => { - #| let result = (i, head) - #| next = tail - #| i += 1 - #| Some(result) - #| } - #| } - #| }) - #|} - #|#as_free_fn - #|pub fn[A] List::from_iter(iter : Iter[A]) -> List[A] { - #| let mut res = Empty - #| let mut ptr = Empty - #| for x in iter { - #| match (res, ptr) { - #| (Empty, _) => { - #| res = More(x, tail=Empty) - #| ptr = res - #| } - #| (More(_), More(_) as ptr_) => { - #| ptr_.tail = More(x, tail=Empty) - #| ptr = ptr_.tail - #| } - #| (_, _) => panic() - #| } - #| } - #| res - #|} - #|#as_free_fn - #|pub fn[A] List::from_iterator(iter : Iterator[A]) -> List[A] { - #| let mut head = Empty - #| let mut tail = Empty - #| while iter.next() is Some(x) { - #| match tail { - #| Empty => { - #| tail = More(x, tail~) - #| head = tail - #| } - #| More(_) as prev_tail => { - #| tail = More(x, tail=Empty) - #| prev_tail.tail = tail - #| } - #| } - #| } - #| head - #|} - #|#as_free_fn - #|pub fn[A] List::from_iter_rev(iter : Iter[A]) -> List[A] { - #| iter.fold(init=Empty, (acc, e) => More(e, tail=acc)) - #|} - #|#as_free_fn - #|pub fn[A] List::from_iterator_rev(iter : Iterator[A]) -> List[A] { - #| iter.fold(init=Empty, (acc, e) => More(e, tail=acc)) - #|} - #|pub impl[X : @quickcheck.Arbitrary] @quickcheck.Arbitrary for List[X] with arbitrary( - #| size, - #| rs, - #|) { - #| @quickcheck.Arbitrary::arbitrary(size, rs) |> from_array - #|} - #|#as_free_fn - #|pub fn[A] List::singleton(x : A) -> List[A] { - #| More(x, tail=Empty) - #|} - #|pub impl[A : Hash] Hash for List[A] with hash_combine(self, hasher) { - #| for e in self { - #| hasher.combine(e) - #| } - #|} - #|fn[A] List::reverse_in_place(self : List[A]) -> List[A] { - #| match self { - #| Empty | More(_, tail=Empty) => self - #| More(head, tail~) => - #| loop (More(head, tail=Empty), tail) { - #| (result, Empty) => result - #| (result, More(_, tail=xs) as new_result) => { - #| new_result.tail = result - #| continue (new_result, xs) - #| } - #| } - #| } - #|} - #|pub impl[A : Compare] Compare for List[A] with compare(self, other) { - #| loop (self, other) { - #| (Empty, Empty) => 0 - #| (Empty, More(_, tail=_)) => -1 - #| (More(_, tail=_), Empty) => 1 - #| (More(x, tail=xs), More(y, tail=ys)) => { - #| let cmp = x.compare(y) - #| if cmp != 0 { - #| break cmp - #| } else { - #| continue (xs, ys) - #| } - #| } - #| } - #|} - ), - "types.mbt": ( - #|#alias(T, deprecated) - #|pub enum List[A] { - #| Empty - #| More(A, mut tail~ : List[A]) - #|} derive(Eq) - ), - }, + "deprecated.mbt": ( + #|#deprecated("use `_.to_array().rev_fold(...)` instead") + #|pub fn[A, B] List::rev_fold(self : List[A], init~ : B, f : (B, A) -> B) -> B { + #| let xs = self.to_array() + #| for x in xs.rev_iter(); acc = (init : B) { + #| continue f(acc, x) + #| } nobreak { + #| acc + #| } + #|} + #|#deprecated("use `_.rev().foldi(...)` instead") + #|pub fn[A, B] List::rev_foldi( + #| self : List[A], + #| init~ : B, + #| f : (Int, B, A) -> B, + #|) -> B { + #| self.rev().foldi(init~, (i, b, a) => f(i, b, a)) + #|} + #|#deprecated("use `unsafe_tail` instead") + #|pub fn[A] List::tail(self : List[A]) -> List[A] { + #| match self { + #| Empty => Empty + #| More(_, tail~) => tail + #| } + #|} + ), + "list.mbt": ( + #|#alias(empty) + #|#as_free_fn + #|#as_free_fn(empty) + #|pub fn[A] List::new() -> List[A] { + #| Empty + #|} + #|#as_free_fn + #|#as_free_fn(construct, deprecated="Use cons instead") + #|pub fn[A] List::cons(head : A, tail : List[A]) -> List[A] { + #| More(head, tail~) + #|} + #|#alias(add) + #|pub fn[A] List::prepend(self : List[A], head : A) -> List[A] { + #| More(head, tail=self) + #|} + #|pub impl[A : Eq] Eq for List[A] with equal(self, other) -> Bool { + #| if physical_equal(self, other) { + #| return true + #| } + #| match (self, other) { + #| (Empty, Empty) => true + #| (More(x, tail=xs), More(y, tail=ys)) => x == y && xs == ys + #| _ => false + #| } + #|} + #|pub impl[A : Show] Show for List[A] with output(xs, logger) { + #| logger.write_iter(xs.iter(), prefix="@list.from_array([", suffix="])") + #|} + #|pub impl[A : ToJson] ToJson for List[A] with to_json(self) { + #| let capacity = self.length() + #| guard capacity != 0 else { return [] } + #| let jsons = Array::new(capacity~) + #| for a in self { + #| jsons.push(a.to_json()) + #| } + #| Json::array(jsons) + #|} + #|pub fn[A : ToJson] List::to_json(self : List[A]) -> Json { + #| ToJson::to_json(self) + #|} + #|pub impl[A : @json.FromJson] @json.FromJson for List[A] with from_json( + #| json, + #| path, + #|) { + #| guard json is Array(arr) else { + #| raise @json.JsonDecodeError((path, "@list.from_json: expected array")) + #| } + #| for i = arr.length() - 1, list = Empty; i >= 0; { + #| continue i - 1, list.prepend(A::from_json(arr[i], path.add_index(i))) + #| } nobreak { + #| list + #| } + #|} + #|#as_free_fn + #|pub fn[A : @json.FromJson] List::from_json( + #| json : Json, + #|) -> List[A] raise @json.JsonDecodeError { + #| @json.from_json(json) + #|} + #|#as_free_fn + #|#alias(of, deprecated="Use from_array instead") + #|#as_free_fn(of, deprecated="Use from_array instead") + #|pub fn[A] List::from_array(arr : ArrayView[A]) -> List[A] { + #| for i = arr.length() - 1, list = Empty; i >= 0; { + #| continue i - 1, More(arr[i], tail=list) + #| } nobreak { + #| list + #| } + #|} + #|pub fn[A] List::length(self : List[A]) -> Int { + #| loop (self, 0) { + #| (Empty, len) => len + #| (More(_, tail=rest), acc) => continue (rest, acc + 1) + #| } + #|} + #|#locals(f) + #|pub fn[A] List::each(self : List[A], f : (A) -> Unit raise?) -> Unit raise? { + #| loop self { + #| Empty => () + #| More(head, tail~) => { + #| f(head) + #| continue tail + #| } + #| } + #|} + #|pub fn[A] List::eachi( + #| self : List[A], + #| f : (Int, A) -> Unit raise?, + #|) -> Unit raise? { + #| loop (self, 0) { + #| (Empty, _) => () + #| (More(x, tail=xs), i) => { + #| f(i, x) + #| continue (xs, i + 1) + #| } + #| } + #|} + #|pub fn[A, B] List::map(self : List[A], f : (A) -> B raise?) -> List[B] raise? { + #| match self { + #| Empty => Empty + #| More(hd, tail~) => { + #| let dest = More(f(hd), tail=Empty) + #| loop (dest, tail) { + #| (_, Empty) => () + #| (More(_) as dest, More(hd, tail~)) => { + #| dest.tail = More(f(hd), tail=Empty) + #| continue (dest.tail, tail) + #| } + #| (Empty, _) => panic() + #| } + #| dest + #| } + #| } + #|} + #|pub fn[A, B] List::mapi( + #| self : List[A], + #| f : (Int, A) -> B raise?, + #|) -> List[B] raise? { + #| match self { + #| Empty => Empty + #| More(hd, tail~) => { + #| let dest = More(f(0, hd), tail=Empty) + #| loop (1, dest, tail) { + #| (_, _, Empty) => () + #| (i, More(_) as dest, More(hd, tail~)) => { + #| dest.tail = More(f(i, hd), tail=Empty) + #| continue (i + 1, dest.tail, tail) + #| } + #| (_, Empty, _) => panic() + #| } + #| dest + #| } + #| } + #|} + #|pub fn[A, B] List::rev_map( + #| self : List[A], + #| f : (A) -> B raise?, + #|) -> List[B] raise? { + #| loop (Empty, self) { + #| (acc, Empty) => acc + #| (acc, More(x, tail=xs)) => continue (More(f(x), tail=acc), xs) + #| } + #|} + #|pub fn[A] List::to_array(self : List[A]) -> Array[A] { + #| match self { + #| Empty => [] + #| More(x, tail=xs) => { + #| let arr = [x] + #| loop xs { + #| Empty => () + #| More(x, tail=xs) => { + #| arr.push(x) + #| continue xs + #| } + #| } + #| arr + #| } + #| } + #|} + #|pub fn[A] List::filter( + #| self : List[A], + #| f : (A) -> Bool raise?, + #|) -> List[A] raise? { + #| loop self { + #| Empty => Empty + #| More(head, tail~) => + #| if !f(head) { + #| continue tail + #| } else { + #| let dest = More(head, tail=Empty) + #| loop (dest, tail) { + #| (_, Empty) => () + #| (More(_) as dest, More(hd, tail~)) => + #| if f(hd) { + #| dest.tail = More(hd, tail=Empty) + #| continue (dest.tail, tail) + #| } else { + #| continue (dest, tail) + #| } + #| (Empty, _) => + #| panic() + #| } + #| dest + #| } + #| } + #|} + #|pub fn[A] List::all(self : List[A], f : (A) -> Bool raise?) -> Bool raise? { + #| loop self { + #| Empty => true + #| More(head, tail~) => if f(head) { continue tail } else { false } + #| } + #|} + #|pub fn[A] List::any(self : List[A], f : (A) -> Bool raise?) -> Bool raise? { + #| loop self { + #| Empty => false + #| More(head, tail~) => if f(head) { true } else { continue tail } + #| } + #|} + #|#internal(unsafe, "Panic if the list is empty") + #|#doc(hidden) + #|pub fn[A] List::unsafe_head(self : List[A]) -> A { + #| match self { + #| Empty => abort("head of empty list") + #| More(head, tail=_) => head + #| } + #|} + #|pub fn[A] List::unsafe_tail(self : List[A]) -> List[A] { + #| match self { + #| Empty => abort("tail of empty list") + #| More(_, tail~) => tail + #| } + #|} + #|pub fn[A] List::head(self : List[A]) -> A? { + #| match self { + #| Empty => None + #| More(head, tail=_) => Some(head) + #| } + #|} + #|#internal(unsafe, "Panic if the list is empty") + #|#doc(hidden) + #|pub fn[A] List::unsafe_last(self : List[A]) -> A { + #| loop self { + #| Empty => abort("last of empty list") + #| More(head, tail=Empty) => head + #| More(_, tail~) => continue tail + #| } + #|} + #|pub fn[A] List::last(self : List[A]) -> A? { + #| loop self { + #| Empty => None + #| More(head, tail=Empty) => Some(head) + #| More(_, tail~) => continue tail + #| } + #|} + #|pub fn[A] List::concat(self : List[A], other : List[A]) -> List[A] { + #| match self { + #| Empty => other + #| More(hd, tail=Empty) => More(hd, tail=other) + #| More(hd, tail~) => { + #| let dest = More(hd, tail=Empty) + #| loop (dest, tail) { + #| (More(_) as dest, Empty) => dest.tail = other + #| (More(_) as dest, More(head, tail~)) => { + #| dest.tail = More(head, tail=Empty) + #| continue (dest.tail, tail) + #| } + #| (Empty, _) => panic() + #| } + #| dest + #| } + #| } + #|} + #|pub fn[A] List::rev_concat(self : List[A], other : List[A]) -> List[A] { + #| loop (self, other) { + #| (Empty, other) => other + #| (More(head, tail~), other) => continue (tail, More(head, tail=other)) + #| } + #|} + #|pub fn[A] List::rev(self : List[A]) -> List[A] { + #| self.rev_concat(Empty) + #|} + #|pub fn[A, B] List::fold( + #| self : List[A], + #| init~ : B, + #| f : (B, A) -> B raise?, + #|) -> B raise? { + #| loop (self, init) { + #| (Empty, acc) => acc + #| (More(head, tail~), acc) => continue (tail, f(acc, head)) + #| } + #|} + #|pub fn[A, B] List::foldi( + #| self : List[A], + #| init~ : B, + #| f : (Int, B, A) -> B raise?, + #|) -> B raise? { + #| fn go( + #| xs : List[A], + #| i : Int, + #| f : (Int, B, A) -> B raise?, + #| acc : B, + #| ) -> B raise? { + #| match xs { + #| Empty => acc + #| More(x, tail=xs) => go(xs, i + 1, f, f(i, acc, x)) + #| } + #| } + #| go(self, 0, f, init) + #|} + #|#as_free_fn + #|pub fn[A, B] List::zip(self : List[A], other : List[B]) -> List[(A, B)] { + #| let res = loop (self, other, Empty) { + #| (Empty, _, acc) => break acc + #| (_, Empty, acc) => break acc + #| (More(x, tail=xs), More(y, tail=ys), acc) => + #| continue (xs, ys, More((x, y), tail=acc)) + #| } + #| res.reverse_in_place() + #|} + #|pub fn[A, B] List::flat_map( + #| self : List[A], + #| f : (A) -> List[B] raise?, + #|) -> List[B] raise? { + #| loop self { + #| Empty => Empty + #| More(head, tail~) => + #| match f(head) { + #| Empty => continue tail + #| More(hd, tail=tl) => { + #| let dest = More(hd, tail=Empty) + #| let dest1 = loop (dest, tl) { + #| (dest, Empty) => dest + #| (More(_) as dest, More(hd, tail~)) => { + #| dest.tail = More(hd, tail=Empty) + #| continue (dest.tail, tail) + #| } + #| (Empty, _) => panic() + #| } + #| loop_over_tail~: loop (dest1, tail) { + #| (_, Empty) => () + #| (More(_) as dest, More(t_hd, tail=Empty)) => dest.tail = f(t_hd) + #| (dest, More(t_hd, tail=t_tl)) => + #| loop (dest, f(t_hd)) { + #| (dest, Empty) => continue loop_over_tail~ (dest, t_tl) + #| (More(_) as dest, More(hd, tail~)) => { + #| dest.tail = More(hd, tail=Empty) + #| continue (dest.tail, tail) + #| } + #| (Empty, _) => panic() + #| } + #| } + #| dest + #| } + #| } + #| } + #|} + #|pub fn[A, B] List::filter_map( + #| self : List[A], + #| f : (A) -> B? raise?, + #|) -> List[B] raise? { + #| loop self { + #| Empty => Empty + #| More(hd, tail~) => + #| match f(hd) { + #| None => continue tail + #| Some(head) => { + #| let dest = More(head, tail=Empty) + #| loop (dest, tail) { + #| (_, Empty) => () + #| (More(_) as dest, More(hd, tail~)) => + #| match f(hd) { + #| None => continue (dest, tail) + #| Some(head) => { + #| dest.tail = More(head, tail=Empty) + #| continue (dest.tail, tail) + #| } + #| } + #| (Empty, _) => panic() + #| } + #| dest + #| } + #| } + #| } + #|} + #|#internal(unsafe, "Panic if the index is out of bounds") + #|#doc(hidden) + #|pub fn[A] List::unsafe_nth(self : List[A], n : Int) -> A { + #| loop (self, n) { + #| (Empty, _) => abort("nth: index out of bounds") + #| (More(head, tail=_), 0) => head + #| (More(_, tail~), n) => continue (tail, n - 1) + #| } + #|} + #|pub fn[A] List::nth(self : List[A], n : Int) -> A? { + #| loop (self, n) { + #| (Empty, _) => None + #| (More(head, tail=_), 0) => Some(head) + #| (More(_, tail~), n) => continue (tail, n - 1) + #| } + #|} + #|#as_free_fn + #|pub fn[A] List::repeat(n : Int, x : A) -> List[A] { + #| loop (Empty, n) { + #| (acc, n) => if n <= 0 { acc } else { continue (More(x, tail=acc), n - 1) } + #| } + #|} + #|pub fn[A] List::intersperse(self : List[A], separator : A) -> List[A] { + #| match self { + #| Empty => Empty + #| More(head, tail=Empty) => More(head, tail=Empty) + #| More(head, tail~) => { + #| let dest = More(head, tail=Empty) + #| loop (dest, tail) { + #| (_, Empty) => () + #| (More(_) as dest, More(hd, tail=tl)) => { + #| let new_tail = More(hd, tail=Empty) + #| dest.tail = More(separator, tail=new_tail) + #| continue (new_tail, tl) + #| } + #| (Empty, _) => panic() + #| } + #| dest + #| } + #| } + #|} + #|pub fn[A] List::is_empty(self : List[A]) -> Bool { + #| self is Empty + #|} + #|pub fn[A, B] List::unzip(self : List[(A, B)]) -> (List[A], List[B]) { + #| match self { + #| Empty => (Empty, Empty) + #| More((x, y), tail~) => { + #| let xs = More(x, tail=Empty) + #| let ys = More(y, tail=Empty) + #| loop (tail, xs, ys) { + #| (Empty, _, _) => () + #| (More((x, y), tail~), More(_) as xptr, More(_) as yptr) => { + #| xptr.tail = More(x, tail=Empty) + #| yptr.tail = More(y, tail=Empty) + #| continue (tail, xptr.tail, yptr.tail) + #| } + #| (_, _, _) => abort("unreachable") + #| } + #| (xs, ys) + #| } + #| } + #|} + #|pub fn[A] List::flatten(self : List[List[A]]) -> List[A] { + #| loop self { + #| Empty => Empty + #| More(head, tail~) => + #| match head { + #| Empty => continue tail + #| More(hd, tail=tl) => { + #| let dest = More(hd, tail=Empty) + #| let dest1 = loop (dest, tl) { + #| (dest, Empty) => dest + #| (More(_) as dest, More(hd, tail~)) => { + #| dest.tail = More(hd, tail=Empty) + #| continue (dest.tail, tail) + #| } + #| (Empty, _) => panic() + #| } + #| loop_over_tail~: loop (dest1, tail) { + #| (_, Empty) => () + #| (More(_) as dest, More(t_hd, tail=Empty)) => dest.tail = t_hd + #| (dest, More(t_hd, tail=t_tl)) => + #| loop (dest, t_hd) { + #| (dest, Empty) => continue loop_over_tail~ (dest, t_tl) + #| (More(_) as dest, More(hd, tail~)) => { + #| dest.tail = More(hd, tail=Empty) + #| continue (dest.tail, tail) + #| } + #| (Empty, _) => panic() + #| } + #| } + #| dest + #| } + #| } + #| } + #|} + #|#internal(unsafe, "Panic if the list is empty") + #|#doc(hidden) + #|pub fn[A : Compare] List::unsafe_maximum(self : List[A]) -> A { + #| match self { + #| Empty => abort("maximum: empty list") + #| More(head, tail~) => + #| loop (tail, head) { + #| (Empty, curr_max) => curr_max + #| (More(item, tail~), curr_max) => + #| continue (tail, if item > curr_max { item } else { curr_max }) + #| } + #| } + #|} + #|pub fn[A : Compare] List::maximum(self : List[A]) -> A? { + #| match self { + #| Empty => None + #| More(head, tail~) => + #| loop (tail, head) { + #| (Empty, curr_max) => Some(curr_max) + #| (More(item, tail~), curr_max) => + #| continue (tail, if item > curr_max { item } else { curr_max }) + #| } + #| } + #|} + #|#internal(unsafe, "Panic if the list is empty") + #|#doc(hidden) + #|pub fn[A : Compare] List::unsafe_minimum(self : List[A]) -> A { + #| match self { + #| Empty => abort("minimum: empty list") + #| More(head, tail~) => + #| loop (tail, head) { + #| (Empty, curr_min) => curr_min + #| (More(item, tail~), curr_min) => + #| continue (tail, if item < curr_min { item } else { curr_min }) + #| } + #| } + #|} + #|pub fn[A : Compare] List::minimum(self : List[A]) -> A? { + #| match self { + #| Empty => None + #| More(head, tail~) => + #| loop (tail, head) { + #| (Empty, curr_min) => Some(curr_min) + #| (More(item, tail~), curr_min) => + #| continue (tail, if item < curr_min { item } else { curr_min }) + #| } + #| } + #|} + #|pub fn[A : Compare] List::sort(self : List[A]) -> List[A] { + #| let arr = self.to_array() + #| arr.sort() + #| from_array(arr) + #|} + #|pub impl[A] Add for List[A] with add(self, other) { + #| self.concat(other) + #|} + #|pub fn[A : Eq] List::contains(self : List[A], value : A) -> Bool { + #| loop self { + #| Empty => false + #| More(x, tail=xs) => if x == value { true } else { continue xs } + #| } + #|} + #|#as_free_fn + #|pub fn[A, S] List::unfold( + #| f : (S) -> (A, S)? raise?, + #| init~ : S, + #|) -> List[A] raise? { + #| match f(init) { + #| None => Empty + #| Some((element, new_state)) => { + #| let dest = More(element, tail=Empty) + #| loop (dest, f(new_state)) { + #| (_, None) => () + #| (More(_) as dest, Some((element, new_state))) => { + #| dest.tail = More(element, tail=Empty) + #| continue (dest.tail, f(new_state)) + #| } + #| (Empty, _) => panic() + #| } + #| dest + #| } + #| } + #|} + #|#as_free_fn + #|pub fn[A, S] List::rev_unfold( + #| f : (S) -> (A, S)? raise?, + #| init~ : S, + #|) -> List[A] raise? { + #| loop (f(init), Empty) { + #| (None, acc) => acc + #| (Some((x, s)), acc) => continue (f(s), More(x, tail=acc)) + #| } + #|} + #|pub fn[A] List::take(self : List[A], n : Int) -> List[A] { + #| if n <= 0 { + #| Empty + #| } else { + #| match self { + #| Empty => Empty + #| More(head, tail~) => { + #| let dest = More(head, tail=Empty) + #| loop (dest, tail, n - 1) { + #| (_, Empty, _) => () + #| (_, _, 0) => () + #| (More(_) as dest, More(x, tail=xs), n) => { + #| dest.tail = More(x, tail=Empty) + #| continue (dest.tail, xs, n - 1) + #| } + #| (Empty, _, _) => panic() + #| } + #| dest + #| } + #| } + #| } + #|} + #|pub fn[A] List::drop(self : List[A], n : Int) -> List[A] { + #| if n <= 0 { + #| self + #| } else { + #| loop (n, self) { + #| (_, Empty) => Empty + #| (1, More(_, tail=xs)) => xs + #| (n, More(_, tail=xs)) => continue (n - 1, xs) + #| } + #| } + #|} + #|pub fn[A] List::take_while( + #| self : List[A], + #| p : (A) -> Bool raise?, + #|) -> List[A] raise? { + #| match self { + #| Empty => Empty + #| More(head, tail~) => + #| if p(head) { + #| let dest = More(head, tail=Empty) + #| loop (dest, tail) { + #| (_, Empty) => () + #| (More(_) as dest, More(x, tail=xs)) if p(x) => { + #| dest.tail = More(x, tail=Empty) + #| continue (dest.tail, xs) + #| } + #| (More(_), _) => () + #| (Empty, _) => panic() + #| } + #| dest + #| } else { + #| Empty + #| } + #| } + #|} + #|pub fn[A] List::drop_while( + #| self : List[A], + #| p : (A) -> Bool raise?, + #|) -> List[A] raise? { + #| loop self { + #| Empty => Empty + #| More(x, tail=xs) => if p(x) { continue xs } else { More(x, tail=xs) } + #| } + #|} + #|pub fn[A, E] List::scan_left( + #| self : List[A], + #| f : (E, A) -> E raise?, + #| init~ : E, + #|) -> List[E] raise? { + #| let dest = More(init, tail=Empty) + #| loop (dest, self, init) { + #| (_, Empty, _) => () + #| (Empty, _, _) => panic() + #| (More(_) as dest, More(x, tail=xs), acc) => { + #| let next = f(acc, x) + #| dest.tail = More(next, tail=Empty) + #| continue (dest.tail, xs, next) + #| } + #| } + #| dest + #|} + #|pub fn[A, B] List::scan_right( + #| self : List[A], + #| f : (B, A) -> B raise?, + #| init~ : B, + #|) -> List[B] raise? { + #| self.rev().scan_left(f, init~).reverse_in_place() + #|} + #|pub fn[A : Eq, B] List::lookup(self : List[(A, B)], v : A) -> B? { + #| loop self { + #| Empty => None + #| More((x, y), tail=xs) => if x == v { Some(y) } else { continue xs } + #| } + #|} + #|pub fn[A] List::find(self : List[A], f : (A) -> Bool raise?) -> A? raise? { + #| loop self { + #| Empty => None + #| More(element, tail=list) => + #| if f(element) { + #| Some(element) + #| } else { + #| continue list + #| } + #| } + #|} + #|pub fn[A] List::find_index( + #| self : Self[A], + #| f : (A) -> Bool raise?, + #|) -> Int? raise? { + #| loop (self, 0) { + #| (Empty, _) => None + #| (More(element, tail=list), idx) => + #| if f(element) { + #| Some(idx) + #| } else { + #| continue (list, idx + 1) + #| } + #| } + #|} + #|pub fn[A] List::findi(self : List[A], f : (A, Int) -> Bool raise?) -> A? raise? { + #| loop (self, 0) { + #| (list, index) => + #| match list { + #| Empty => None + #| More(element, tail=list) => + #| if f(element, index) { + #| Some(element) + #| } else { + #| continue (list, index + 1) + #| } + #| } + #| } + #|} + #|pub fn[A] List::remove_at(self : List[A], index : Int) -> List[A] { + #| match (index, self) { + #| (_, Empty) => Empty + #| (_..<0, _) => self + #| (0, More(_, tail~)) => tail + #| (n, More(head, tail~)) => { + #| let dest = More(head, tail=Empty) + #| loop (dest, tail, n - 1) { + #| (_, Empty, _) => () + #| (More(_) as dest, More(_, tail~), 0) => dest.tail = tail + #| (More(_) as dest, More(x, tail=xs), n) => { + #| dest.tail = More(x, tail=Empty) + #| continue (dest.tail, xs, n - 1) + #| } + #| (Empty, _, _) => panic() + #| } + #| dest + #| } + #| } + #|} + #|pub fn[A : Eq] List::remove(self : List[A], elem : A) -> List[A] { + #| match self { + #| Empty => Empty + #| More(head, tail~) if head == elem => tail + #| More(head, tail~) => { + #| let dest = More(head, tail~) + #| loop (dest, tail) { + #| (_, Empty) => () + #| (More(_) as dest, More(x, tail=xs)) => + #| if x == elem { + #| dest.tail = xs + #| } else { + #| dest.tail = More(x, tail=Empty) + #| continue (dest.tail, xs) + #| } + #| (Empty, _) => panic() + #| } + #| dest + #| } + #| } + #|} + #|pub fn[A : Eq] List::is_prefix(self : List[A], prefix : List[A]) -> Bool { + #| loop (self, prefix) { + #| (_, Empty) => true + #| (Empty, More(_)) => false + #| (More(h1, tail=t1), More(h2, tail=t2)) => + #| if h1 == h2 { + #| continue (t1, t2) + #| } else { + #| false + #| } + #| } + #|} + #|pub fn[A : Eq] List::is_suffix(self : List[A], suffix : List[A]) -> Bool { + #| self.rev().is_prefix(suffix.rev()) + #|} + #|pub fn[A] List::intercalate(self : List[List[A]], sep : List[A]) -> List[A] { + #| self.intersperse(sep).flatten() + #|} + #|pub impl[X] Default for List[X] with default() { + #| Empty + #|} + #|pub fn[X] default() -> List[X] { + #| Empty + #|} + #|#alias(iterator, deprecated) + #|pub fn[A] List::iter(self : List[A]) -> Iter[A] { + #| let mut next = self + #| Iter::new(fn() { + #| match next { + #| Empty => None + #| More(head, tail~) => { + #| next = tail + #| Some(head) + #| } + #| } + #| }) + #|} + #|#alias(iterator2, deprecated) + #|pub fn[A] List::iter2(self : List[A]) -> Iter2[Int, A] { + #| let mut i = 0 + #| let mut next = self + #| Iter2::new(fn() { + #| match next { + #| Empty => None + #| More(head, tail~) => { + #| let result = (i, head) + #| next = tail + #| i += 1 + #| Some(result) + #| } + #| } + #| }) + #|} + #|#as_free_fn + #|#alias(from_iterator, deprecated) + #|#as_free_fn(from_iterator, deprecated) + #|pub fn[A] List::from_iter(iter : Iter[A]) -> List[A] { + #| let mut head = Empty + #| let mut tail = Empty + #| while iter.next() is Some(x) { + #| match tail { + #| Empty => { + #| tail = More(x, tail~) + #| head = tail + #| } + #| More(_) as prev_tail => { + #| tail = More(x, tail=Empty) + #| prev_tail.tail = tail + #| } + #| } + #| } + #| head + #|} + #|#as_free_fn + #|#alias(from_iterator_rev, deprecated) + #|#as_free_fn(from_iterator_rev, deprecated) + #|pub fn[A] List::from_iter_rev(iter : Iter[A]) -> List[A] { + #| iter.fold(init=Empty, (acc, e) => More(e, tail=acc)) + #|} + #|pub impl[X : @quickcheck.Arbitrary] @quickcheck.Arbitrary for List[X] with arbitrary( + #| size, + #| rs, + #|) { + #| @quickcheck.Arbitrary::arbitrary(size, rs) |> from_array + #|} + #|#as_free_fn + #|pub fn[A] List::singleton(x : A) -> List[A] { + #| More(x, tail=Empty) + #|} + #|pub impl[A : Hash] Hash for List[A] with hash_combine(self, hasher) { + #| for e in self { + #| hasher.combine(e) + #| } + #|} + #|fn[A] List::reverse_in_place(self : List[A]) -> List[A] { + #| match self { + #| Empty | More(_, tail=Empty) => self + #| More(head, tail~) => + #| loop (More(head, tail=Empty), tail) { + #| (result, Empty) => result + #| (result, More(_, tail=xs) as new_result) => { + #| new_result.tail = result + #| continue (new_result, xs) + #| } + #| } + #| } + #|} + #|pub impl[A : Compare] Compare for List[A] with compare(self, other) { + #| loop (self, other) { + #| (Empty, Empty) => 0 + #| (Empty, More(_, tail=_)) => -1 + #| (More(_, tail=_), Empty) => 1 + #| (More(x, tail=xs), More(y, tail=ys)) => { + #| let cmp = x.compare(y) + #| if cmp != 0 { + #| break cmp + #| } else { + #| continue (xs, ys) + #| } + #| } + #| } + #|} + ), + "types.mbt": ( + #|#alias(T, deprecated) + #|pub enum List[A] { + #| Empty + #| More(A, mut tail~ : List[A]) + #|} + ) + } ) ///| let moonbitlang_core_math_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/math", - deps={ - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/double": moonbitlang_core_double_module, - "moonbitlang/core/float": moonbitlang_core_float_module, - "moonbitlang/core/int": moonbitlang_core_int_module, - "moonbitlang/core/bigint": moonbitlang_core_bigint_module, - "moonbitlang/core/random": moonbitlang_core_random_module, - "moonbitlang/core/array": moonbitlang_core_array_module, - }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| "moonbitlang/core/builtin", - #| "moonbitlang/core/double", - #| "moonbitlang/core/float", - #| "moonbitlang/core/int", - #| "moonbitlang/core/bigint", - #| "moonbitlang/core/random", - #| "moonbitlang/core/array" - #| ], - #| "targets" : { - #| "algebraic_double_js.mbt": ["js"], - #| "algebraic_double_nonjs.mbt": ["not", "js"], - #| "exp_double_js.mbt": ["js"], - #| "exp_double_nonjs.mbt": ["not", "js"], - #| "log_double_js.mbt": ["js"], - #| "log_double_nonjs.mbt": ["not", "js"], - #| "pow_double_js.mbt": ["js"], - #| "pow_double_nonjs.mbt": ["not", "js"], - #| "trig_double_js.mbt": ["js"], - #| "trig_double_nonjs.mbt": ["not", "js"], - #| "trig_double_sincos_native.mbt": ["native"], - #| "trig_double_sincos_non_native_or_js.mbt": ["not", "js", "native"], - #| "hyperbolic_double_js.mbt": ["js"], - #| "hyperbolic_double_nonjs.mbt": ["not", "js"], - #| "utils.mbt": ["not", "js"] - #| } - #|} - ), - "algebraic.mbt": ( - #|pub fn cbrtf(x : Float) -> Float { - #| let b1 : UInt = 709958130 // B1 = (127-127.0/3-0.03306235651)*2**23 */ - #| let b2 : UInt = 642849266 // B2 = (127-127.0/3-24/3-0.03306235651)*2**23 */ - #| let mut ui : UInt = x.reinterpret_as_uint() - #| let mut hx : UInt = ui & 0x7fffffff - #| if hx >= 0x7f800000 { - #| return x + x - #| } - #| if hx < 0x00800000 { - #| if hx == 0 { - #| return x - #| } // cbrt(+-0) is itx - #| ui = (x * (0x1.0p24 : Float)).reinterpret_as_uint() - #| hx = ui & 0x7fffffff - #| hx = hx / 3 + b2 - #| } else { - #| hx = hx / 3 + b1 - #| } - #| ui = ui & 0x80000000 - #| ui = ui | hx - #| let dx = x.to_double() - #| let t = Float::reinterpret_from_uint(ui).to_double() - #| let r = t * t * t - #| let t = t * (dx + dx + r) / (dx + r + r) - #| let r = t * t * t - #| let t = t * (dx + dx + r) / (dx + r + r) - #| Float::from_double(t) - #|} - #|pub fn hypotf(x : Float, y : Float) -> Float { - #| let epsilon : Float = 1.1920928955078125e-7 - #| let x = x.abs() - #| let y = y.abs() - #| if x.is_inf() || y.is_inf() { - #| return @float.infinity - #| } - #| let (x, y) = if y > x { (y, x) } else { (x, y) } - #| if x * epsilon >= y { - #| return x - #| } - #| let rat = y / x - #| x * (rat * rat + 1.0).sqrt() - #|} - ), - "algebraic_double_js.mbt": ( - #|pub fn cbrt(x : Double) -> Double = "Math" "cbrt" - #|pub fn hypot(x : Double, y : Double) -> Double = "Math" "hypot" - ), - "algebraic_double_nonjs.mbt": ( - #|pub fn cbrt(x : Double) -> Double { - #| if x.is_inf() || x.is_nan() || x == 0.0 { - #| return x - #| } - #| let b1 : UInt = 715094163 // B1 = (682-0.03306235651)*2**20 - #| let b2 : UInt = 696219795 // B2 = (664-0.03306235651)*2**20 - #| let c = 5.42857142857142815906e-01 // 19/35 = 0x3FE15F15, 0xF15F15F1 - #| let d = -7.05306122448979611050e-01 // -864/1225 = 0xBFE691DE, 0x2532C834 - #| let e = 1.41428571428571436819e+00 // 99/70 = 0x3FF6A0EA, 0x0EA0EA0F - #| let f = 1.60714285714285720630e+00 // 45/28 = 0x3FF9B6DB, 0x6DB6DB6E - #| let g = 3.57142857142857150787e-01 // 5/14 = 0x3FD6DB6D, 0xB6DB6DB7 - #| let hx = get_high_word(x).reinterpret_as_int() - #| let sign = if x < 0.0 { true } else { false } - #| let x = abs(x) - #| let t = if hx < 0x00100000 { - #| let t : UInt64 = 0x43500000_00000000 - #| let t : Double = t.reinterpret_as_double() - #| let t = t * x - #| set_high_word(0, get_high_word(t) / 3 + b2) - #| } else { - #| set_high_word(0, hx.reinterpret_as_uint() / 3 + b1) - #| } - #| let r = t * t / x - #| let s = c + r * t - #| let t = t * (g + f / (s + e + d / s)) - #| let t = set_high_word(0, get_high_word(t) + 0x00000001) - #| let s = t * t - #| let r = x / s - #| let w = t + t - #| let r = (r - t) / (w + r) - #| let t = t + t * r - #| if sign { - #| -t - #| } else { - #| t - #| } - #|} - #|pub fn hypot(x : Double, y : Double) -> Double { - #| if x.is_nan() || y.is_nan() { - #| return @double.not_a_number - #| } - #| if x.is_inf() || y.is_inf() { - #| return @double.infinity - #| } - #| let x = x.abs() - #| let y = y.abs() - #| let double_epsilon : Double = 0x0.0000000000001P-1022 - #| let (x, y) = if y > x { (y, x) } else { (x, y) } - #| if x * double_epsilon >= y { - #| return x - #| } - #| let r = y / x - #| x * (1.0 + r * r).sqrt() - #|} - ), - "deprecated.mbt": ( - #|#deprecated("Use `PI` instead") - #|pub let pi = 0x3.243F6A8885A308CA8A54 - #|#deprecated("Use @cmp.maximum instead") - #|pub fn[T : Compare] maximum(x : T, y : T) -> T { - #| if x > y { - #| x - #| } else { - #| y - #| } - #|} - #|#deprecated("Use @cmp.minimum instead") - #|pub fn[T : Compare] minimum(x : T, y : T) -> T { - #| if x > y { - #| y - #| } else { - #| x - #| } - #|} - ), - "exp.mbt": ( - #|fn top12(x : Float) -> UInt { - #| x.reinterpret_as_uint() >> 20 - #|} - #|fn __math_xflowf(sign : UInt, y : Float) -> Float { - #| return (if sign != 0 { -y } else { y }) * y - #|} - #|fn __math_oflowf(sign : UInt) -> Float { - #| return __math_xflowf(sign, 0x1.0p97) - #|} - #|fn __math_uflowf(sign : UInt) -> Float { - #| return __math_xflowf(sign, 0x1.0p-95) - #|} - #|let exp2f_table_bits = 5 - #|priv struct Exp2fData { - #| tab : FixedArray[UInt64] - #| shift : Double - #| invln2_scaled : Double - #| poly_scaled : FixedArray[Double] - #|} - #|let expf_n : UInt64 = (1 << exp2f_table_bits).to_uint64() - #|let exp2f_data_n : Double = (1 << exp2f_table_bits).to_double() - #|let exp2f_data : Exp2fData = { - #| tab: [ - #| 0x3ff0000000000000, 0x3fefd9b0d3158574, 0x3fefb5586cf9890f, 0x3fef9301d0125b51, - #| 0x3fef72b83c7d517b, 0x3fef54873168b9aa, 0x3fef387a6e756238, 0x3fef1e9df51fdee1, - #| 0x3fef06fe0a31b715, 0x3feef1a7373aa9cb, 0x3feedea64c123422, 0x3feece086061892d, - #| 0x3feebfdad5362a27, 0x3feeb42b569d4f82, 0x3feeab07dd485429, 0x3feea47eb03a5585, - #| 0x3feea09e667f3bcd, 0x3fee9f75e8ec5f74, 0x3feea11473eb0187, 0x3feea589994cce13, - #| 0x3feeace5422aa0db, 0x3feeb737b0cdc5e5, 0x3feec49182a3f090, 0x3feed503b23e255d, - #| 0x3feee89f995ad3ad, 0x3feeff76f2fb5e47, 0x3fef199bdd85529c, 0x3fef3720dcef9069, - #| 0x3fef5818dcfba487, 0x3fef7c97337b9b5f, 0x3fefa4afa2a490da, 0x3fefd0765b6e4540, - #| ], - #| shift: 0x1.8p+52, - #| invln2_scaled: 0x1.71547652b82fep+0 * exp2f_data_n, - #| poly_scaled: [ - #| 0x1.c6af84b912394p-5 / exp2f_data_n / exp2f_data_n / exp2f_data_n, - #| 0x1.ebfce50fac4f3p-3 / exp2f_data_n / exp2f_data_n, - #| 0x1.62e42ff0c52d6p-1 / exp2f_data_n, - #| ], - #|} - #|pub fn expf(x : Float) -> Float { - #| let xd = x.to_double() - #| let abstop = top12(x) & 0x7ff - #| if abstop >= top12(88.0) { - #| if x.reinterpret_as_uint() == @float.neg_infinity.reinterpret_as_uint() { - #| return 0.0 - #| } - #| if abstop >= top12(@float.infinity) { - #| return x + x - #| } - #| if x > 0x1.62e42ep6 { - #| return __math_oflowf(0) - #| } - #| if x < -0x1.9fe368p6 { - #| return __math_uflowf(0) - #| } - #| } - #| let z = exp2f_data.invln2_scaled * xd - #| let kd = z + exp2f_data.shift - #| let ki = kd.reinterpret_as_uint64() - #| let kd = kd - exp2f_data.shift - #| let r = z - kd - #| let t = exp2f_data.tab[(ki % expf_n).to_int()] - #| let t = t + (ki << (52 - exp2f_table_bits)) - #| let s = t.reinterpret_as_double() - #| let z = exp2f_data.poly_scaled[0] * r + exp2f_data.poly_scaled[1] - #| let r2 = r * r - #| let y = exp2f_data.poly_scaled[2] * r + 1 - #| let y = z * r2 + y - #| let y = y * s - #| Float::from_double(y) - #|} - #|pub fn expm1f(x : Float) -> Float { - #| let float_ln2_hi : Float = 6.9314575195e-01 // 0x3f317200 - #| let float_ln2_lo : Float = 1.4286067653e-06 // 0x35bfbe8e - #| let inv_ln2 : Float = 1.4426950216e+00 // 0x3fb8aa3b - #| let mut x = x - #| let q1 : Float = -3.3333212137e-2 // -0x888868.0p-28 - #| let q2 : Float = 1.5807170421e-3 // 0xcf3010.0p-33 - #| let mut hx = x.reinterpret_as_uint() - #| let sign = hx >> 31 != 0 - #| hx = hx & 0x7fffffff - #| if hx >= 0x4195b844 { - #| if hx > 0x7f800000 { - #| return x - #| } - #| if sign { - #| return -1.0 - #| } - #| if hx > 0x42b17217 { - #| x *= (0x1.0p127 : Float) - #| return x - #| } - #| } - #| let mut k : Int = 0 - #| let mut hi : Float = 0 - #| let mut lo : Float = 0 - #| let mut c : Float = 0 - #| if hx > 0x3eb17218 { - #| if hx < 0x3F851592 { - #| if !sign { - #| hi = x - float_ln2_hi - #| lo = float_ln2_lo - #| k = 1 - #| } else { - #| hi = x + float_ln2_hi - #| lo = -float_ln2_lo - #| k = -1 - #| } - #| } else { - #| k = (inv_ln2 * x + (if sign { -0.5 } else { 0.5 })).to_int() - #| hi = x - Float::from_int(k) * float_ln2_hi // t*ln2_hi is exact here - #| lo = Float::from_int(k) * float_ln2_lo - #| } - #| x = hi - lo - #| c = hi - x - lo - #| } else if hx < 0x33000000 { - #| return x - #| } else { - #| k = 0 - #| } - #| let hfx = (0.5 : Float) * x - #| let hxs = x * hfx - #| let r1 = (1.0 : Float) + hxs * (q1 + hxs * q2) - #| let t = (3.0 : Float) - r1 * hfx - #| let mut e = hxs * ((r1 - t) / ((6.0 : Float) - x * t)) - #| if k == 0 { - #| return x - (x * e - hxs) - #| } - #| e = x * (e - c) - c - #| e -= hxs - #| if k == -1 { - #| return (0.5 : Float) * (x - e) - 0.5 - #| } - #| if k == 1 { - #| if x < -0.25 { - #| return -(2.0 : Float) * (e - (x + 0.5)) - #| } - #| return (1.0 : Float) + (2.0 : Float) * (x - e) - #| } - #| let twopk = Float::reinterpret_from_int((0x7f + k) << 23) // 2^k - #| if !(k is (0..=56)) { - #| let mut y = x - e + 1.0 - #| if k == 128 { - #| y = y * 2.0 * (0x1.0p127 : Float) - #| } else { - #| y = y * twopk - #| } - #| return y - 1.0 - #| } - #| let uf = Float::reinterpret_from_int((0x7f - k) << 23) // 2^-k - #| if k < 23 { - #| (x - e + ((1.0 : Float) - uf)) * twopk - #| } else { - #| (x - (e + uf) + 1.0) * twopk - #| } - #|} - ), - "exp_double_js.mbt": ( - #|pub fn exp(x : Double) -> Double = "Math" "exp" - #|pub fn expm1(x : Double) -> Double = "Math" "expm1" - ), - "exp_double_nonjs.mbt": ( - #|pub fn exp(x : Double) -> Double { - #| fn get_high_word(x : Double) -> UInt { - #| (x.reinterpret_as_uint64() >> 32).to_uint() - #| } - #| fn get_low_word(x : Double) -> UInt { - #| x.reinterpret_as_uint64().to_uint() - #| } - #| fn insert_words(ix0 : UInt64, ix1 : UInt64) -> Double { - #| let mut bits : UInt64 = 0 - #| bits = bits | (ix0 << 32) - #| bits = bits | ix1 - #| bits.reinterpret_as_double() - #| } - #| let ori_x = x - #| let mut x = x - #| let one = 1.0 - #| let halF : ReadOnlyArray[Double] = [0.5, -0.5] - #| let o_threshold = 7.09782712893383973096e+02 - #| let u_threshold = -7.45133219101941108420e+02 - #| let ln2HI : ReadOnlyArray[Double] = [ - #| 6.93147180369123816490e-01, -6.93147180369123816490e-01, - #| ] - #| let ln2LO : ReadOnlyArray[Double] = [ - #| 1.90821492927058770002e-10, -1.90821492927058770002e-10, - #| ] - #| let invln2 = 1.44269504088896338700e+00 - #| let p1 = 1.66666666666666019037e-01 - #| let p2 = -2.77777777770155933842e-03 - #| let p3 = 6.61375632143793436117e-05 - #| let p4 = -1.65339022054652515390e-06 - #| let p5 = 4.13813679705723846039e-08 - #| let e = 2.718281828459045 - #| let mut hi = 0.0 - #| let mut lo = 0.0 - #| let huge = 1.0e+300 - #| let twom1000 = 9.33263618503218878990e-302 - #| let two1023 = 8.988465674311579539e307 - #| let mut k : Int = 0 - #| let mut hx : UInt = get_high_word(ori_x) - #| let xsb : Int = ((hx >> 31) & 1).reinterpret_as_int() - #| hx = hx & 0x7FFFFFFF - #| if hx >= 0x40862E42 { - #| if hx >= 0x7FF00000 { - #| let lx : UInt = get_low_word(ori_x) - #| if ((hx & 0xFFFFF) | lx) != 0 { - #| return ori_x + ori_x - #| } else if xsb == 0 { - #| return ori_x - #| } else { - #| return 0.0 - #| } - #| } - #| if ori_x > o_threshold { - #| return huge * huge - #| } - #| if ori_x < u_threshold { - #| return twom1000 * twom1000 - #| } - #| } - #| if hx > 0x3FD62E42 { - #| if hx < 0x3FF0A2B2 { - #| if ori_x == 1.0 { - #| return e - #| } - #| hi = ori_x - ln2HI[xsb] - #| lo = ln2LO[xsb] - #| k = 1 - xsb - xsb - #| } else { - #| k = (invln2 * ori_x + halF[xsb]).to_int() - #| let t = k.to_double() - #| hi = ori_x - t * ln2HI[0] - #| lo = t * ln2LO[0] - #| } - #| x = hi - lo - #| } else if hx < 0x3E300000 { - #| if huge + x > one { - #| return one + x - #| } - #| } else { - #| k = 0 - #| } - #| let t = x * x - #| let twopk = if k >= -1021 { - #| insert_words( - #| (0x3FF00000 + (k.reinterpret_as_uint() << 20).reinterpret_as_int()) - #| .to_int64() - #| .reinterpret_as_uint64(), - #| 0, - #| ) - #| } else { - #| insert_words( - #| 0x3FF00000UL + ((k + 1000).reinterpret_as_uint() << 20).to_uint64(), - #| 0, - #| ) - #| } - #| let c = x - t * (p1 + t * (p2 + t * (p3 + t * (p4 + t * p5)))) - #| if k == 0 { - #| return one - (x * c / (c - 2.0) - x) - #| } - #| let y = one - (lo - x * c / (2.0 - c) - hi) - #| if k >= -1021 { - #| if k == 1024 { - #| return y * 2.0 * two1023 - #| } else { - #| return y * twopk - #| } - #| } else { - #| return y * twopk * twom1000 - #| } - #|} - #|pub fn expm1(x : Double) -> Double { - #| if x.is_nan() { - #| return @double.not_a_number - #| } - #| let o_threshold = 7.09782712893383973096e+02 - #| if x > o_threshold { - #| return @double.infinity - #| } - #| if x.is_inf() { - #| return -1.0 - #| } - #| let huge = 1.0e+300 - #| let tiny = 1.0e-300 - #| let ln2_hi = 6.93147180369123816490e-01 - #| let ln2_lo = 1.90821492927058770002e-10 - #| let invln2 = 1.44269504088896338700e+00 - #| let q1 = -3.33333333333331316428e-02 - #| let q2 = 1.58730158725481460165e-03 - #| let q3 = -7.93650757867487942473e-05 - #| let q4 = 4.00821782732936239552e-06 - #| let q5 = -2.01099218183624371326e-07 - #| let mut x = x - #| let mut hx = get_high_word(x) - #| let xsb : Int = (hx & 0x80000000).reinterpret_as_int() - #| let mut y : Double = if xsb == 0 { x } else { -x } - #| hx = hx & 0x7fffffff - #| if hx >= 0x4043687A { - #| if xsb != 0 { - #| if x + tiny < 0.0 { - #| return tiny - 1.0 - #| } - #| } - #| } - #| let mut hi = 0.0 - #| let mut lo = 0.0 - #| let mut k = 0 - #| let mut c = 0.0 - #| let mut t = 0.0 - #| if hx > 0x3fd62e42 { - #| if hx < 0x3FF0A2B2 { - #| hi = if xsb == 0 { x - ln2_hi } else { x + ln2_hi } - #| lo = if xsb == 0 { ln2_lo } else { -ln2_lo } - #| k = if xsb == 0 { 1 } else { -1 } - #| } else { - #| k = (invln2 * x + (if xsb == 0 { 0.5 } else { -0.5 })).to_int() - #| t = k.to_double() - #| hi = x - t * ln2_hi - #| lo = t * ln2_lo - #| } - #| x = hi - lo - #| c = hi - x - lo - #| } else if hx < 0x3c900000 { - #| t = huge + x - #| return x - (t - (huge + x)) - #| } else { - #| k = 0 - #| } - #| let hfx : Double = 0.5 * x - #| let hxs : Double = x * hfx - #| let r1 : Double = 1.0 + - #| hxs * (q1 + hxs * (q2 + hxs * (q3 + hxs * (q4 + hxs * q5)))) - #| let t : Double = 3.0 - r1 * hfx - #| let e : Double = hxs * ((r1 - t) / (6.0 - x * t)) - #| if k == 0 { - #| return x - (x * e - hxs) - #| } else { - #| let e : Double = x * (e - c) - c - #| let e : Double = e - hxs - #| if k == -1 { - #| return 0.5 * (x - e) - 0.5 - #| } - #| if k == 1 { - #| return if x < -0.25 { - #| -2.0 * (e - (x + 0.5)) - #| } else { - #| 1.0 + 2.0 * (x - e) - #| } - #| } - #| if k <= -2 || k > 56 { - #| y = 1.0 - (e - x) - #| y = set_high_word(y, get_high_word(y) + (k << 20).reinterpret_as_uint()) - #| return y - 1.0 - #| } - #| let mut t : Double = 1.0 - #| if k < 20 { - #| t = set_high_word(0, (0x3ff00000 - (0x200000 >> k)).reinterpret_as_uint()) - #| y = t - (e - x) - #| y = set_high_word(y, get_high_word(y) + (k << 20).reinterpret_as_uint()) - #| } else { - #| t = set_high_word(0, ((0x3ff - k) << 20).reinterpret_as_uint()) - #| y = x - (e + t) + 1.0 - #| y = set_high_word(y, get_high_word(y) + (k << 20).reinterpret_as_uint()) - #| } - #| } - #| y - #|} - ), - "hyperbolic.mbt": ( - #|fn k_expo2f(x : Float) -> Float { - #| let k = 235 - #| let k_ln2 = Float::reinterpret_from_int(0x4322e3bc) - #| let scale = Float::reinterpret_from_int((0x7f + k / 2) << 23) - #| expf(x - k_ln2) * scale * scale - #|} - #|pub fn sinhf(x : Float) -> Float { - #| let mut h : Float = 0.5 - #| let mut ix = x.reinterpret_as_uint() - #| if ix >> 31 != 0 { - #| h = -h - #| } - #| ix = ix & 0x7fffffff - #| let absx = Float::reinterpret_from_uint(ix) - #| let w = ix - #| if w < 0x42b17217 { - #| let t = expm1f(absx) - #| if w < 0x3f800000 { - #| if w < 0x3f800000U - (12U << 23) { - #| return x - #| } - #| return h * ((2.0 : Float) * t - t * t / (t + 1.0)) - #| } - #| return h * (t + t / (t + 1.0)) - #| } - #| h * k_expo2f(absx) * 2.0 - #|} - #|pub fn coshf(x : Float) -> Float { - #| let mut x = x - #| let mut ix = x.reinterpret_as_uint() - #| ix = ix & 0x7fffffff - #| x = Float::reinterpret_from_uint(ix) - #| let w = ix - #| if w < 0x3f317217 { - #| if w < 0x3f800000U - (12U << 23) { - #| return 1.0 - #| } - #| let t = expm1f(x) - #| return (1.0 : Float) + t * t / ((2.0 : Float) * (t + 1.0)) - #| } - #| if w < 0x42b17217 { - #| let t = expf(x) - #| return (t + (1.0 : Float) / t) * 0.5 - #| } - #| k_expo2f(x) - #|} - #|pub fn tanhf(x : Float) -> Float { - #| let mut ix = x.reinterpret_as_uint() - #| let sign = ix >> 31 != 0 - #| ix = ix & 0x7fffffff - #| let x = Float::reinterpret_from_uint(ix) - #| let w = ix - #| let tt = if w > 0x3f0c9f54 { - #| if w > 0x41200000 { - #| (1.0 : Float) + (0.0 : Float) / x - #| } else { - #| let t = expm1f(x * 2.0) - #| (1.0 : Float) - (2.0 : Float) / (t + 2.0) - #| } - #| } else if w > 0x3e82c578 { - #| let t = expm1f(x * 2.0) - #| t / (t + 2.0) - #| } else if w >= 0x00800000 { - #| let t = expm1f(x * -2.0) - #| -t / (t + 2.0) - #| } else { - #| x - #| } - #| if sign { - #| -tt - #| } else { - #| tt - #| } - #|} - #|pub fn asinhf(x : Float) -> Float { - #| let u = x.reinterpret_as_uint() - #| let i = u & 0x7fffffff - #| let sign = u >> 31 != 0 - #| let ln2 : Float = 0.693147180559945309417232121458176568 - #| let x = Float::reinterpret_from_uint(i) - #| let x = if i >= 0x3f800000U + (12U << 23) { - #| lnf(x) + ln2 - #| } else if i >= 0x3f800000U + (1U << 23) { - #| lnf(x * 2.0 + (1.0 : Float) / ((x * x + 1.0).sqrt() + x)) - #| } else if i >= 0x3f800000U - (12U << 23) { - #| ln_1pf(x + x * x / ((x * x + 1.0).sqrt() + 1.0)) - #| } else { - #| x - #| } - #| if sign { - #| -x - #| } else { - #| x - #| } - #|} - #|pub fn acoshf(x : Float) -> Float { - #| let ln2 : Float = 693147180559945309417232121458176568 - #| let u = x.reinterpret_as_uint() - #| let a = u & 0x7fffffffU - #| if a < 0x3f800000U + (1U << 23) { - #| return ln_1pf( - #| x - 1.0 + ((x - 1.0) * (x - 1.0) + (2.0 : Float) * (x - 1.0)).sqrt(), - #| ) - #| } - #| if a < 0x3f800000U + (12U << 23) { - #| return lnf(x * 2.0 - (1.0 : Float) / (x + (x * x - 1.0).sqrt())) - #| } - #| return lnf(x) + ln2 - #|} - #|pub fn atanhf(x : Float) -> Float { - #| let u = x.reinterpret_as_uint() - #| let sign = u >> 31 != 0 - #| let u = u & 0x7fffffff - #| let x = Float::reinterpret_from_uint(u) - #| let x = if u < 0x3f800000U - (1U << 23) { - #| if u < 0x3f800000U - (32U << 23) { - #| x - #| } else { - #| ln_1pf(x * 2.0 + x * 2.0 * x / ((1.0 : Float) - x)) * 0.5 - #| } - #| } else { - #| ln_1pf(x / ((1.0 : Float) - x) * 2.0) * 0.5 - #| } - #| if sign { - #| -x - #| } else { - #| x - #| } - #|} - ), - "hyperbolic_double_js.mbt": ( - #|pub fn sinh(x : Double) -> Double = "Math" "sinh" - #|pub fn cosh(x : Double) -> Double = "Math" "cosh" - #|pub fn tanh(x : Double) -> Double = "Math" "tanh" - #|pub fn asinh(x : Double) -> Double = "Math" "asinh" - #|pub fn acosh(x : Double) -> Double = "Math" "acosh" - #|pub fn atanh(x : Double) -> Double = "Math" "atanh" - ), - "hyperbolic_double_nonjs.mbt": ( - #|pub fn sinh(x : Double) -> Double { - #| if x.is_nan() || x.is_inf() { - #| return x - #| } - #| let ix = get_high_word(x).reinterpret_as_int() & 0x7fffffff - #| let abs_x = x.abs() - #| let shuge = 1.0e307 - #| let h = if x < 0.0 { -0.5 } else { 0.5 } - #| if ix < 0x40360000 { - #| if ix < 0x3e300000 { - #| if shuge + x > 1.0 { - #| return x - #| } - #| } - #| let t = expm1(abs_x) - #| if ix < 0x3ff00000 { - #| return h * (2.0 * t - t * t / (t + 1.0)) - #| } - #| return h * (t + t / (t + 1.0)) - #| } - #| if ix < 0x40862E42 { - #| return h * exp(abs_x) - #| } - #| if abs_x.reinterpret_as_uint64() < 0x408633ce8fb9f87d { - #| let w = exp(0.5 * abs_x) - #| let t = h * w - #| return t * w - #| } - #| x * shuge - #|} - #|pub fn cosh(x : Double) -> Double { - #| if x.is_nan() { - #| return x - #| } - #| if x.is_inf() { - #| return @double.infinity - #| } - #| let ix = get_high_word(x).reinterpret_as_int() & 0x7fffffff - #| if ix < 0x3fd62e43 { - #| let t = expm1(x.abs()) - #| let w = 1.0 + t - #| if ix < 0x3c800000 { - #| return w - #| } - #| return 1.0 + t * t / (w + w) - #| } - #| if ix < 0x40360000 { - #| let t = exp(x.abs()) - #| return 0.5 * t + 0.5 / t - #| } - #| if ix < 0x40862E42 { - #| return (0.5 * x.abs()) |> exp - #| } - #| let lx = get_low_word(x).reinterpret_as_int() - #| if ix < 0x408633ce || (ix == 0x408633ce && lx <= 0x8fb9f87d) { - #| let w = exp(0.5 * x.abs()) - #| let t = 0.5 * w - #| return t * w - #| } - #| @double.infinity - #|} - #|pub fn tanh(x : Double) -> Double { - #| if x.is_nan() { - #| return x - #| } - #| if x.is_pos_inf() { - #| return 1.0 - #| } - #| if x.is_neg_inf() { - #| return -1.0 - #| } - #| let ix = get_high_word(x).reinterpret_as_int() & 0x7fffffff - #| let tiny = 1.0e-300 - #| let z = if ix < 0x40360000 { - #| if ix < 0x3c800000 { - #| x * (1.0 + x) - #| } else if ix >= 0x3ff00000 { - #| let t = (2.0 * x.abs()) |> expm1 - #| 1.0 - 2.0 / (t + 2.0) - #| } else { - #| let t = (-2.0 * x.abs()) |> expm1 - #| -t / (t + 2.0) - #| } - #| } else { - #| 1.0 - tiny - #| } - #| if x >= 0.0 { - #| z - #| } else { - #| -z - #| } - #|} - #|pub fn asinh(x : Double) -> Double { - #| if x.is_nan() || x.is_inf() { - #| return x - #| } - #| let one : Double = 1.0 - #| let ln2 : Double = 6.93147180559945286227e-01 - #| let huge : Double = 1.0e300 - #| let hx = get_high_word(x).reinterpret_as_int() - #| let ix = hx & 0x7fffffff - #| if ix < 0x3e300000 { - #| if huge + x > one { - #| return x - #| } - #| } - #| let w : Double = if ix > 0x41b00000 { - #| ln(x.abs()) + ln2 - #| } else if ix > 0x40000000 { - #| let t = x.abs() - #| (2.0 * t + one / ((x * x + one).sqrt() + t)) |> ln - #| } else { - #| let t = x * x - #| (x.abs() + t / (one + (one + t).sqrt())) |> ln_1p - #| } - #| if hx > 0 { - #| w - #| } else { - #| -w - #| } - #|} - #|pub fn acosh(x : Double) -> Double { - #| let one = 1.0 - #| let hx = get_high_word(x).reinterpret_as_int() - #| if x < 1.0 || x.is_nan() { - #| return @double.not_a_number - #| } else if x == 1.0 { - #| return 0.0 - #| } else if x.is_pos_inf() { - #| return @double.infinity - #| } else if hx >= 0x41b00000 { - #| return ln(x) + LN2 - #| } else if hx > 0x40000000 { - #| let t = x * x - #| return (2.0 * x - one / (x + (t - one).sqrt())) |> ln - #| } else { - #| let t = x - one - #| return (t + (2.0 * t + t * t).sqrt()) |> ln_1p - #| } - #|} - #|pub fn atanh(x : Double) -> Double { - #| let hx : Int = get_high_word(x).reinterpret_as_int() - #| let ix = hx & 0x7fffffff - #| if x.abs() > 1.0 { - #| return @double.not_a_number - #| } - #| if x == 1.0 { - #| return @double.infinity - #| } - #| if x == -1.0 { - #| return @double.neg_infinity - #| } - #| if ix < 0x3e300000 && 1.0e300 + x > 0.0 { - #| return x - #| } - #| let x = x.abs() - #| let t = if x <= 0.5 { - #| let t = x + x - #| 0.5 * ln_1p(t + t * x / (1.0 - x)) - #| } else { - #| 0.5 * ln_1p((x + x) / (1.0 - x)) - #| } - #| if hx >= 0 { - #| t - #| } else { - #| -t - #| } - #|} - ), - "log.mbt": ( - #|let logf_off = 0x3f330000U - #|let logf_table_bits = 4 - #|let logf_n : UInt = 1U << logf_table_bits - #|priv struct LogfData { - #| invc : FixedArray[Double] - #| logc : FixedArray[Double] - #| ln2 : Double - #| poly : FixedArray[Double] - #|} - #|let logf_data : LogfData = { - #| invc: [ - #| 0x1.661ec79f8f3bep+0, 0x1.571ed4aaf883dp+0, 0x1.49539f0f010bp+0, 0x1.3c995b0b80385p+0, - #| 0x1.30d190c8864a5p+0, 0x1.25e227b0b8eap+0, 0x1.1bb4a4a1a343fp+0, 0x1.12358f08ae5bap+0, - #| 0x1.0953f419900a7p+0, 0x1.0p+0, 0x1.e608cfd9a47acp-1, 0x1.ca4b31f026aap-1, 0x1.b2036576afce6p-1, - #| 0x1.9c2d163a1aa2dp-1, 0x1.886e6037841edp-1, 0x1.767dcf5534862p-1, - #| ], - #| logc: [ - #| -0x1.57bf7808caadep-2, -0x1.2bef0a7c06ddbp-2, -0x1.01eae7f513a67p-2, -0x1.b31d8a68224e9p-3, - #| -0x1.6574f0ac07758p-3, -0x1.1aa2bc79c81p-3, -0x1.a4e76ce8c0e5ep-4, -0x1.1973c5a611cccp-4, - #| -0x1.252f438e10c1ep-5, 0x0.0p+0, 0x1.aa5aa5df25984p-5, 0x1.c5e53aa362eb4p-4, - #| 0x1.526e57720db08p-3, 0x1.bc2860d22477p-3, 0x1.1058bc8a07ee1p-2, 0x1.4043057b6ee09p-2, - #| ], - #| ln2: 0x1.62e42fefa39efp-1, - #| poly: [-0x1.00ea348b88334p-2, 0x1.5575b0be00b6ap-2, -0x1.ffffef20a4123p-2], - #|} - #|pub fn lnf(x : Float) -> Float { - #| let mut ix : UInt = x.reinterpret_as_uint() - #| if ix == 0x3f800000U { - #| return 0.0 - #| } - #| if ix - 0x00800000U >= 0x7f800000U - 0x00800000U { - #| if ix * 2 == 0 { - #| return @float.neg_infinity - #| } - #| if ix == 0x7f800000U { - #| return x - #| } - #| if (ix & 0x80000000U) != 0 || ix * 2 >= 0xff000000U { - #| return @float.not_a_number - #| } - #| ix = (x * 0x1.0p23).reinterpret_as_uint() - #| ix -= (23 << 23).reinterpret_as_uint() - #| } - #| let tmp = ix - logf_off - #| let i = ((tmp >> (23 - logf_table_bits)) % logf_n).reinterpret_as_int() - #| let k = tmp.reinterpret_as_int() >> 23 - #| let iz = ix - (tmp & 0xff800000U) - #| let invc = logf_data.invc[i] - #| let logc = logf_data.logc[i] - #| let z = Float::reinterpret_from_uint(iz).to_double() - #| let r = z * invc - 1 - #| let y0 = logc + k.to_double() * logf_data.ln2 - #| let r2 = r * r - #| let y = logf_data.poly[1] * r + logf_data.poly[2] - #| let y = logf_data.poly[0] * r2 + y - #| let y = y * r2 + (y0 + r) - #| Float::from_double(y) - #|} - #|pub fn ln_1pf(x : Float) -> Float { - #| let lg1_f : Float = 0.66666662693 - #| let lg2_f : Float = 0.40000972152 - #| let lg3_f : Float = 0.28498786688 - #| let lg4_f : Float = 0.24279078841 - #| let float_ln2_hi : Float = 6.9314575195e-01 // 0x3f317200 - #| let float_ln2_lo : Float = 1.4286067653e-06 // 0x35bfbe8e - #| let mut ui : UInt = x.reinterpret_as_uint() - #| let mut f : Float = 0 - #| let mut c : Float = 0 - #| let mut iu : UInt = 0 - #| let one : Float = 1.0 - #| let mut k = 1 - #| if ui < 0x3ed413d0 || ui >> 31 > 0 { - #| if ui >= 0xbf800000 { - #| if x == -1.0 { - #| return x / 0.0 - #| } - #| return (x - x) / 0.0 - #| } - #| if ui << 1 < 0x33800000U << 1 { - #| return x - #| } - #| if ui <= 0xbe95f619 { - #| k = 0 - #| c = 0.0 - #| f = x - #| } - #| } else if ui >= 0x7f800000 { - #| return x - #| } - #| if k > 0 { - #| ui = (one + x).reinterpret_as_uint() - #| iu = ui - #| iu += 0x3f800000U - 0x3f3504f3U - #| k = (iu >> 23).reinterpret_as_int() - 0x7f - #| if k < 25 { - #| let fui = Float::reinterpret_from_uint(ui) - #| c = if k >= 2 { one - (fui - x) } else { x - (fui - 1.0) } - #| c /= Float::reinterpret_from_uint(ui) - #| } else { - #| c = 0.0 - #| } - #| iu = (iu & 0x007fffff) + 0x3f3504f3 - #| ui = iu - #| f = Float::reinterpret_from_uint(ui) - 1.0 - #| } - #| let s = f / (f + 2.0) - #| let z = s * s - #| let w = z * z - #| let t1 = w * (lg2_f + w * lg4_f) - #| let t2 = z * (lg1_f + w * lg3_f) - #| let r = t2 + t1 - #| let hfsq = f * f * 0.5 - #| let dk = Float::from_int(k) - #| s * (hfsq + r) + (dk * float_ln2_lo + c) - hfsq + f + dk * float_ln2_hi - #|} - ), - "log_double_js.mbt": ( - #|pub fn ln(x : Double) -> Double = "Math" "log" - #|pub fn log2(x : Double) -> Double = "Math" "log2" - #|pub fn log10(x : Double) -> Double = "Math" "log10" - #|pub fn ln_1p(x : Double) -> Double = "Math" "log1p" - ), - "log_double_nonjs.mbt": ( - #|pub fn ln(x : Double) -> Double { - #| let l1 = 6.666666666666735130e-01 // 3FE55555 55555593 - #| let l2 = 3.999999999940941908e-01 // 3FD99999 9997FA04 - #| let l3 = 2.857142874366239149e-01 // 3FD24924 94229359 - #| let l4 = 2.222219843214978396e-01 // 3FCC71C5 1D8E78AF - #| let l5 = 1.818357216161805012e-01 // 3FC74664 96CB03DE - #| let l6 = 1.531383769920937332e-01 // 3FC39A09 D078C69F - #| let l7 = 1.479819860511658591e-01 // 3FC2F112 DF3E5244 - #| if x < 0.0 { - #| return @double.not_a_number - #| } else if x.is_nan() || x.is_inf() { - #| return x - #| } else if x == 0.0 { - #| return @double.neg_infinity - #| } - #| let (f1, ki) = frexp(x) - #| let (f, k) = if f1 < SQRT2 / 2.0 { - #| (f1 * 2.0 - 1.0, (ki - 1).to_double()) - #| } else { - #| (f1 - 1.0, ki.to_double()) - #| } - #| let s = f / (2.0 + f) - #| let s2 = s * s - #| let s4 = s2 * s2 - #| let t1 = s2 * (l1 + s4 * (l3 + s4 * (l5 + s4 * l7))) - #| let t2 = s4 * (l2 + s4 * (l4 + s4 * l6)) - #| let r = t1 + t2 - #| let hfsq = 0.5 * f * f - #| k * LN2_HI - (hfsq - (s * (hfsq + r) + k * LN2_LO) - f) - #|} - #|pub fn log2(x : Double) -> Double { - #| let (f, e) = frexp(x) - #| if f == 0.5 { - #| return e.to_double() - 1.0 - #| } - #| ln(f) / LN2 + e.to_double() - #|} - #|pub fn log10(x : Double) -> Double { - #| if x < 0.0 { - #| return @double.not_a_number - #| } else if x.is_nan() || x.is_inf() { - #| return x - #| } else if x == 0.0 { - #| return @double.neg_infinity - #| } - #| let ivln10 = 4.34294481903251816668e-01 - #| let log10_2hi = 3.01029995663611771306e-01 - #| let log10_2lo = 3.69423907715893078616e-13 - #| let (f, e) = frexp(x) - #| let (f, e) = if e >= 1 { - #| (f * 2.0, (e - 1).to_double()) - #| } else { - #| (f, e.to_double()) - #| } - #| let z = e * log10_2lo + ivln10 * ln(f) - #| z + e * log10_2hi - #|} - #|pub fn ln_1p(x : Double) -> Double { - #| if x < -1.0 || x.is_nan() { - #| return @double.not_a_number - #| } - #| if x == -1.0 { - #| return @double.neg_infinity - #| } - #| if x.is_inf() { - #| return @double.infinity - #| } - #| let ln2_hi = 6.93147180369123816490e-01 - #| let ln2_lo = 1.90821492927058770002e-10 - #| let two54 = 1.80143985094819840000e+16 - #| let lp1 = 6.666666666666735130e-01 - #| let lp2 = 3.999999999940941908e-01 - #| let lp3 = 2.857142874366239149e-01 - #| let lp4 = 2.222219843214978396e-01 - #| let lp5 = 1.818357216161805012e-01 - #| let lp6 = 1.531383769920937332e-01 - #| let zero = 0.0 - #| let lp7 = 1.479819860511658591e-01 - #| let hx = get_high_word(x).reinterpret_as_int() - #| let ax = hx & 0x7fffffff - #| let mut f = 0.0 - #| let mut c = 0.0 - #| let mut s = 0.0 - #| let mut z = 0.0 - #| let mut r = 0.0 - #| let mut u = 0.0 - #| let mut hu = 0 - #| let mut k = 1 - #| if hx < 0x3FDA827A { - #| if ax < 0x3e200000 { - #| if two54 + x > zero && ax < 0x3c900000 { - #| return x - #| } else { - #| return x - x * x * 0.5 - #| } - #| } - #| if hx > 0 || hx <= 0xbfd2bec3 { - #| k = 0 - #| f = x - #| hu = 1 - #| } - #| } - #| if k != 0 { - #| if hx < 0x43400000 { - #| u = 1.0 + x - #| hu = get_high_word(u).reinterpret_as_int() - #| k = (hu >> 20) - 1023 - #| c = if k > 0 { 1.0 - (u - x) } else { x - (u - 1.0) } - #| c /= u - #| } else { - #| u = x - #| hu = get_high_word(u).reinterpret_as_int() - #| k = (hu >> 20) - 1023 - #| c = 0.0 - #| } - #| hu = hu & 0x000fffff - #| if hu < 0x6a09e { - #| u = set_high_word(u, hu.reinterpret_as_uint() | 0x3ff00000) - #| } else { - #| k += 1 - #| u = set_high_word(u, hu.reinterpret_as_uint() | 0x3fe00000) - #| hu = (0x00100000 - hu) >> 2 - #| } - #| f = u - 1.0 - #| } - #| let hfsq = 0.5 * f * f - #| if hu == 0 { - #| if f == zero { - #| if k == 0 { - #| return zero - #| } else { - #| c += k.to_double() * ln2_lo - #| return k.to_double() * ln2_hi + c - #| } - #| } - #| r = hfsq * (1.0 - 0.66666666666666666 * f) - #| if k == 0 { - #| return f - r - #| } else { - #| return k.to_double() * ln2_hi - (r - (k.to_double() * ln2_lo + c) - f) - #| } - #| } - #| s = f / (2.0 + f) - #| z = s * s - #| r = z * - #| (lp1 + z * (lp2 + z * (lp3 + z * (lp4 + z * (lp5 + z * (lp6 + z * lp7)))))) - #| if k == 0 { - #| return f - (hfsq - s * (hfsq + r)) - #| } else { - #| return k.to_double() * ln2_hi - - #| (hfsq - (s * (hfsq + r) + (k.to_double() * ln2_lo + c)) - f) - #| } - #|} - ), - "pow.mbt": ( - #|pub fn powf(base : Float, exponent : Float) -> Float { - #| let huge : Float = 1.0e30 - #| let tiny : Float = 1.0e-30 - #| let cp : Float = 9.6179670095e-01 // 0x3f76384f =2/(3ln2) */ - #| let cp_h : Float = 9.6191406250e-01 // 0x3f764000 =12b cp */ - #| let cp_l : Float = -1.1736857402e-04 // 0xb8f623c6 =tail of cp_h */ - #| let lg2 : Float = 6.9314718246e-01 // 0x3f317218 */ - #| let lg2_h : Float = 6.93145752e-01 // 0x3f317200 */ - #| let lg2_l : Float = 1.4286067653e-06 // 0x35bfbe8c */ - #| let ovt : Float = 8.0085662595e-08 // -(2**-28)/(log(2)**2) */ - #| let ivln2 : Float = 1.4426950216e+00 // 0x3f317218 */ - #| let ivln2_h : Float = 1.4426879883e+00 // 0x3f317218 */ - #| let ivln2_l : Float = 7.0526075433e-06 // 0x35bfbe8c */ - #| let l1 : Float = 6.0000002384e-01 // 0x3f19999a */ - #| let l2 : Float = 4.2857143283e-01 // 0x3edb6db7 */ - #| let l3 : Float = 3.3333334327e-01 // 0x3eaaaaab */ - #| let l4 : Float = 2.7272811532e-01 // 0x3e8ba305 */ - #| let l5 : Float = 2.3066075146e-01 // 0x3e6c3255 */ - #| let l6 : Float = 2.0697501302e-01 // 0x3e53f142 */ - #| let p1 : Float = 1.6666667163e-01 // 0x3e2aaaab */ - #| let p2 : Float = -2.7777778450e-03 // 0xbb360b61 */ - #| let p3 : Float = 6.6137559770e-05 // 0x388ab355 */ - #| let p4 : Float = -1.6533901999e-06 // 0xb5ddea0e */ - #| let p5 : Float = 4.1381369442e-08 // 0x3331bb4c */ - #| let mut z : Float = 0 - #| let mut ax : Float = 0 - #| let mut z_h : Float = 0 - #| let mut z_l : Float = 0 - #| let mut p_h : Float = 0 - #| let mut p_l : Float = 0 - #| let mut y1 : Float = 0 - #| let mut t1 : Float = 0 - #| let mut t2 : Float = 0 - #| let mut r : Float = 0 - #| let mut s : Float = 0 - #| let mut sn : Float = 0 - #| let mut t : Float = 0 - #| let mut u : Float = 0 - #| let mut v : Float = 0 - #| let mut w : Float = 0 - #| let mut i : Int = 0 - #| let mut j : Int = 0 - #| let mut k : Int = 0 - #| let mut yisint : Int = 0 - #| let mut n : Int = 0 - #| let mut hx : Int = 0 - #| let mut hy : Int = 0 - #| let mut ix : Int = 0 - #| let mut iy : Int = 0 - #| let mut i_s : Int = 0 - #| let (x, y) = (base, exponent) - #| let bp : Array[Float] = [1.0, 1.5] - #| let dp_h : Array[Float] = [0.0, 5.84960938e-01] // 0x3f15c000 */ - #| let dp_l : Array[Float] = [0.0, 1.56322085e-06] // 0x35d1cfdc */ - #| let two24 : Float = 16777216.0 - #| hx = x.reinterpret_as_int() - #| hy = y.reinterpret_as_int() - #| ix = hx & 0x7fffffff - #| iy = hy & 0x7fffffff - #| if iy == 0 { - #| return 1.0 - #| } - #| if hx == 0x3f800000 { - #| return 1.0 - #| } - #| if ix > 0x7f800000 || iy > 0x7f800000 { - #| return x + y - #| } - #| yisint = 0 - #| if hx < 0 { - #| if iy >= 0x4b800000 { - #| yisint = 2 // even integer y - #| } else if iy >= 0x3f800000 { - #| k = (iy >> 23) - 0x7f // exponent - #| j = iy >> (23 - k) - #| if j << (23 - k) == iy { - #| yisint = 2 - (j & 1) - #| } - #| } - #| } - #| if iy == 0x7f800000 { - #| if ix == 0x3f800000 { - #| return 1.0 - #| } else if ix > 0x3f800000 { - #| return if hy >= 0 { y } else { 0.0 } - #| } else { - #| return if hy >= 0 { 0.0 } else { -y } - #| } - #| } - #| if iy == 0x3f800000 { - #| return if hy >= 0 { x } else { (1.0 : Float) / x } - #| } - #| if hy == 0x40000000 { - #| return x * x - #| } - #| if hy == 0x3f000000 && hx >= 0 { - #| return x.sqrt() - #| } - #| ax = x.abs() - #| if ix == 0x7f800000 || ix == 0 || ix == 0x3f800000 { - #| z = ax - #| if hy < 0 { - #| z = (1.0 : Float) / z - #| } - #| if hx < 0 { - #| if ((ix - 0x3f800000) | yisint) == 0 { - #| z = (z - z) / (z - z) // (-1)**non-int is NaN - #| } else if yisint == 1 { - #| z = -z - #| } - #| } // (x<0)**odd = -(|x|**odd) - #| return z - #| } - #| sn = 1.0 // sign of result - #| if hx < 0 { - #| if yisint == 0 { - #| return @float.not_a_number - #| } - #| if yisint == 1 { - #| sn = -1.0 - #| } - #| } - #| if iy > 0x4d000000 { - #| if ix < 0x3f7ffff8 { - #| return if hy < 0 { sn * huge * huge } else { sn * tiny * tiny } - #| } - #| if ix > 0x3f800007 { - #| return if hy > 0 { sn * huge * huge } else { sn * tiny * tiny } - #| } - #| t = ax - 1.0 // t has 20 trailing zeros - #| w = t * t * ((0.5 : Float) - t * ((0.333333333333 : Float) - t * 0.25)) - #| u = ivln2_h * t // IVLN2_H has 16 sig. bits - #| v = t * ivln2_l - w * ivln2 - #| t1 = u + v - #| i_s = t1.reinterpret_as_int() - #| t1 = Float::reinterpret_from_int(i_s & 0xfffff000) - #| t2 = v - (t1 - u) - #| } else { - #| let mut s2 : Float = 0 - #| let mut s_h : Float = 0 - #| let mut s_l : Float = 0 - #| let mut t_h : Float = 0 - #| let mut t_l : Float = 0 - #| n = 0 - #| if ix < 0x00800000 { - #| ax *= two24 - #| n -= 24 - #| ix = ax.reinterpret_as_int() - #| } - #| n += (ix >> 23) - 0x7f - #| j = ix & 0x007fffff - #| ix = j | 0x3f800000 // normalize ix - #| if j <= 0x1cc471 { - #| k = 0 - #| } else if j < 0x5db3d7 { - #| k = 1 - #| } else { - #| k = 0 - #| n += 1 - #| ix -= 0x00800000 - #| } - #| ax = Float::reinterpret_from_int(ix) - #| u = ax - bp[k] - #| v = (1.0 : Float) / (ax + bp[k]) - #| s = u * v - #| s_h = s - #| i_s = s_h.reinterpret_as_int() - #| s_h = Float::reinterpret_from_int(i_s & 0xfffff000) - #| i_s = (((ix.reinterpret_as_uint() >> 1) & 0xfffff000) | 0x20000000).reinterpret_as_int() - #| t_h = Float::reinterpret_from_uint( - #| i_s.reinterpret_as_uint() + 0x00400000 + (k.reinterpret_as_uint() << 21), - #| ) - #| t_l = ax - (t_h - bp[k]) - #| s_l = v * (u - s_h * t_h - s_h * t_l) - #| s2 = s * s - #| r = s2 * s2 * (l1 + s2 * (l2 + s2 * (l3 + s2 * (l4 + s2 * (l5 + s2 * l6))))) - #| r += s_l * (s_h + s) - #| s2 = s_h * s_h - #| t_h = (3.0 : Float) + s2 + r - #| i_s = t_h.reinterpret_as_int() - #| t_h = Float::reinterpret_from_int(i_s & 0xfffff000) - #| t_l = r - (t_h - 3.0 - s2) - #| u = s_h * t_h - #| v = s_l * t_h + t_l * s - #| p_h = u + v - #| i_s = p_h.reinterpret_as_int() - #| p_h = Float::reinterpret_from_int(i_s & 0xfffff000) - #| p_l = v - (p_h - u) - #| z_h = cp_h * p_h // cp_h+cp_l = 2/(3*log2) - #| z_l = cp_l * p_h + p_l * cp + dp_l[k] - #| t = Float::from_int(n) - #| t1 = z_h + z_l + dp_h[k] + t - #| i_s = t1.reinterpret_as_int() - #| t1 = Float::reinterpret_from_int(i_s & 0xfffff000) - #| t2 = z_l - (t1 - t - dp_h[k] - z_h) - #| } - #| i_s = y.reinterpret_as_int() - #| y1 = Float::reinterpret_from_int(i_s & 0xfffff000) - #| p_l = (y - y1) * t1 + y * t2 - #| p_h = y1 * t1 - #| z = p_l + p_h - #| j = z.reinterpret_as_int() - #| if j > 0x43000000 { - #| return sn * huge * huge // overflow - #| } else if j == 0x43000000 { - #| if p_l + ovt > z - p_h { - #| return sn * huge * huge - #| } - #| } else if ( // overflow - #| j & 0x7fffffff - #| ) > - #| 0x43160000 { - #| return sn * tiny * tiny // underflow - #| } else if j.reinterpret_as_uint() == 0xc3160000 && p_l <= z - p_h { - #| return sn * tiny * tiny - #| } // underflow - #| i = j & 0x7fffffff - #| k = (i >> 23) - 0x7f - #| n = 0 - #| if i > 0x3f000000 { - #| n = j + (0x00800000 >> (k + 1)) - #| k = ((n & 0x7fffffff) >> 23) - 0x7f // new k for n - #| t = Float::reinterpret_from_int(n & (0x007fffff >> k).lnot()) - #| n = ((n & 0x007fffff) | 0x00800000) >> (23 - k) - #| if j < 0 { - #| n = -n - #| } - #| p_h -= t - #| } - #| t = p_l + p_h - #| i_s = t.reinterpret_as_int() - #| t = Float::reinterpret_from_int(i_s & 0xffff8000) - #| u = t * lg2_h - #| v = (p_l - (t - p_h)) * lg2 + t * lg2_l - #| z = u + v - #| w = v - (z - u) - #| t = z * z - #| t1 = z - t * (p1 + t * (p2 + t * (p3 + t * (p4 + t * p5)))) - #| r = z * t1 / (t1 - 2.0) - (w + z * w) - #| z = (1.0 : Float) - (r - z) - #| j = z.reinterpret_as_int() - #| j += n << 23 - #| if j >> 23 <= 0 { - #| z = scalbnf(z, n) - #| } else { - #| z = Float::reinterpret_from_int(j) - #| } - #| sn * z - #|} - ), - "pow_double_js.mbt": ( - #|pub fn pow(base : Double, exponent : Double) -> Double = "Math" "pow" - ), - "pow_double_nonjs.mbt": ( - #|let pow_bp : ReadOnlyArray[Double] = [1.0, 1.5] - #|let pow_dp_h : ReadOnlyArray[Double] = [0.0, 5.84962487220764160156e-01] - #|let pow_dp_l : ReadOnlyArray[Double] = [0.0, 1.35003920212974897128e-08] - #|const ZERO = 0.0 - #|const ONE = 1.0 - #|const TWO = 2.0 - #|const POW_two53 = 9007199254740992.0 - #|const POW_huge = 1.0e300 - #|const POW_tiny = 1.0e-300 - #|const POW_L1 = 5.99999999999994648725e-01 - #|const POW_L2 = 4.28571428578550184252e-01 - #|const POW_L3 = 3.33333329818377432918e-01 - #|const POW_L4 = 2.72728123808534006489e-01 - #|const POW_L5 = 2.30660745775561754067e-01 - #|const POW_L6 = 2.06975017800338417784e-01 - #|const POW_P1 = 1.66666666666666019037e-01 - #|const POW_P2 = -2.77777777770155933842e-03 - #|const POW_P3 = 6.61375632143793436117e-05 - #|const POW_P4 = -1.65339022054652515390e-06 - #|const POW_P5 = 4.13813679705723846039e-08 - #|const POW_lg2 = 6.93147180559945286227e-01 - #|const POW_lg2_h = 6.93147182464599609375e-01 - #|const POW_lg2_l = -1.90465429995776804525e-09 - #|const POW_ovt = 8.0085662595372944372e-0017 - #|const POW_cp = 9.61796693925975554329e-01 - #|const POW_cp_h = 9.61796700954437255859e-01 - #|const POW_cp_l = -7.02846165095275826516e-09 - #|const POW_ivln2 = 1.44269504088896338700e+00 - #|const POW_ivln2_h = 1.44269502162933349609e+00 - #|const POW_ivln2_l = 1.92596299112661746887e-08 - #|pub fn pow(x : Double, y : Double) -> Double { - #| fn set_low_word(d : Double, v : UInt) -> Double { - #| let bits : UInt64 = d.reinterpret_as_uint64() - #| let bits = bits & 0xFFFF_FFFF_0000_0000 - #| let bits = bits | v.to_uint64() - #| bits.reinterpret_as_double() - #| } - #| fn set_high_word(d : Double, v : UInt) -> Double { - #| let bits : UInt64 = d.reinterpret_as_uint64() - #| let bits = bits & 0x0000_0000_FFFF_FFFF - #| let bits = bits | (v.to_uint64() << 32) - #| bits.reinterpret_as_double() - #| } - #| fn get_high_word(x : Double) -> UInt { - #| (x.reinterpret_as_uint64() >> 32).to_uint() - #| } - #| fn get_low_word(x : Double) -> UInt { - #| x.reinterpret_as_uint64().to_uint() - #| } - #| let mut z : Double = 0.0 - #| let mut ax : Double = 0.0 - #| let mut z_h : Double = 0.0 - #| let mut z_l : Double = 0.0 - #| let mut p_h : Double = 0.0 - #| let mut p_l : Double = 0.0 - #| let mut y1 : Double = 0.0 - #| let mut t1 : Double = 0.0 - #| let mut t2 : Double = 0.0 - #| let mut r : Double = 0.0 - #| let mut s : Double = 0.0 - #| let mut t : Double = 0.0 - #| let mut u : Double = 0.0 - #| let mut v : Double = 0.0 - #| let mut w : Double = 0.0 - #| let mut i : Int = 0 - #| let mut j : Int = 0 - #| let mut k : Int = 0 - #| let mut yisint : Int = 0 - #| let mut n : Int = 0 - #| let hx : Int = (x.reinterpret_as_uint64() >> 32).to_int() - #| let lx : UInt = (x.reinterpret_as_uint64() & 0xFFFFFFFF).to_uint() - #| let hy : Int = (y.reinterpret_as_uint64() >> 32).to_int() - #| let ly : UInt = (y.reinterpret_as_uint64() & 0xFFFFFFFF).to_uint() - #| let mut ix : Int = hx & 0x7FFFFFFF - #| let iy : Int = hy & 0x7FFFFFFF - #| if (iy.reinterpret_as_uint() | ly) == 0 { - #| return ONE - #| } - #| if ix > 0x7FF00000 || - #| (ix == 0x7FF00000 && lx != 0) || - #| iy > 0x7FF00000 || - #| (iy == 0x7FF00000 && ly != 0) { - #| return x + y - #| } - #| if hx < 0 { - #| if iy >= 0x43400000 { - #| yisint = 2 // even integer y - #| } else if iy >= 0x3ff00000 { - #| k = (iy >> 20) - 0x3ff // exponent - #| if k > 20 { - #| j = (ly >> (52 - k)).reinterpret_as_int() - #| if j << (52 - k) == ly.reinterpret_as_int() { - #| yisint = 2 - (j & 1) - #| } - #| } else if ly == 0 { - #| j = iy >> (20 - k) - #| if j << (20 - k) == iy { - #| yisint = 2 - (j & 1) - #| } - #| } - #| } - #| } - #| if ly == 0 { - #| if iy == 0x7ff00000 { // y is +-inf - #| if ((ix.reinterpret_as_uint() - 0x3ff00000) | lx) == 0 { - #| return y - y // inf**+-1 is NaN - #| } else if ix >= 0x3ff00000 { // (|x|>1)**+-inf = inf,0 - #| return if hy >= 0 { y } else { ZERO } - #| } else { // (|x|<1)**-,+inf = inf,0 - #| return if hy < 0 { -y } else { ZERO } - #| } - #| } - #| if iy == 0x3ff00000 { // y is +-1 - #| if hy < 0 { - #| return ONE / x - #| } else { - #| return x - #| } - #| } - #| if hy == 0x40000000 { // y is 2 - #| return x * x - #| } - #| if hy == 0x3fe00000 { // y is 0.5 - #| if hx >= 0 { // x >= +0 - #| return x.sqrt() - #| } - #| } - #| } - #| ax = x.abs() - #| if lx == 0 { - #| if ix == 0x7ff00000 || ix == 0 || ix == 0x3ff00000 { - #| z = ax // x is +-0,+-inf,+-1 */ - #| if hy < 0 { - #| z = ONE / z // z = (1/|x|) - #| } - #| if hx < 0 { - #| if ((ix - 0x3ff00000) | yisint) == 0 { - #| z = @double.not_a_number - #| } else if yisint == 1 { - #| z = -z // (x<0)**odd = -(|x|**odd) - #| } - #| } - #| return z - #| } - #| } - #| n = (hx >> 31) + 1 - #| if (n | yisint) == 0 { - #| return @double.not_a_number - #| } - #| s = ONE // s (sign of result -ve**odd) = -1 else = 1 - #| if (n | (yisint - 1)) == 0 { - #| s = -ONE // (-ve)**(odd int) - #| } - #| if iy > 0x41e00000 { // if |y| > 2**31 */ - #| if iy > 0x43f00000 { // if |y| > 2**64, must o/uflow */ - #| if ix <= 0x3fefffff { - #| return if hy < 0 { POW_huge * POW_huge } else { POW_tiny * POW_tiny } - #| } - #| if ix >= 0x3ff00000 { - #| return if hy > 0 { POW_huge * POW_huge } else { POW_tiny * POW_tiny } - #| } - #| } - #| if ix < 0x3fefffff { - #| return if hy < 0 { - #| s * POW_huge * POW_huge - #| } else { - #| s * POW_tiny * POW_tiny - #| } - #| } - #| if ix > 0x3ff00000 { - #| return if hy > 0 { - #| s * POW_huge * POW_huge - #| } else { - #| s * POW_tiny * POW_tiny - #| } - #| } - #| t = ax - ONE // t has 20 trailing zeros */ - #| w = t * t * (0.5 - t * (0.3333333333333333333333 - t * 0.25)) - #| u = POW_ivln2_h * t // POW_ivln2_h has 21 sig. bits */ - #| v = t * POW_ivln2_l - w * POW_ivln2 - #| t1 = u + v - #| t1 = set_low_word(t1, 0) - #| t2 = v - (t1 - u) - #| } else { - #| n = 0 - #| if ix < 0x00100000 { - #| ax *= POW_two53 - #| n -= 53 - #| ix = get_high_word(ax).reinterpret_as_int() - #| } - #| n += (ix >> 20) - 0x3ff - #| j = ix & 0x000fffff - #| ix = j | 0x3ff00000 // normalize ix - #| if j <= 0x3988E { - #| k = 0 // |x|> 1) | 0x20000000) + - #| 0x00080000 + - #| (k.reinterpret_as_uint() << 18), - #| ) - #| let mut t_l : Double = ax - (t_h - pow_bp[k]) - #| let s_l : Double = v * (u - s_h * t_h - s_h * t_l) - #| let mut s2 : Double = ss * ss - #| r = s2 * - #| s2 * - #| ( - #| POW_L1 + - #| s2 * - #| (POW_L2 + s2 * (POW_L3 + s2 * (POW_L4 + s2 * (POW_L5 + s2 * POW_L6)))) - #| ) - #| r += s_l * (s_h + ss) - #| s2 = s_h * s_h - #| t_h = 3.0 + s2 + r - #| t_h = set_low_word(t_h, 0) - #| t_l = r - (t_h - 3.0 - s2) - #| u = s_h * t_h - #| v = s_l * t_h + t_l * ss - #| p_h = u + v - #| p_h = set_low_word(p_h, 0) - #| p_l = v - (p_h - u) - #| z_h = POW_cp_h * p_h // cp_h+cp_l = 2/(3*log2) - #| z_l = POW_cp_l * p_h + p_l * POW_cp + pow_dp_l[k] - #| t = n.to_double() - #| t1 = z_h + z_l + pow_dp_h[k] + t - #| t1 = set_low_word(t1, 0) - #| t2 = z_l - (t1 - t - pow_dp_h[k] - z_h) - #| } - #| y1 = y - #| y1 = set_low_word(y1, 0) - #| p_l = (y - y1) * t1 + y * t2 - #| p_h = y1 * t1 - #| z = p_l + p_h - #| j = get_high_word(z).reinterpret_as_int() - #| i = get_low_word(z).reinterpret_as_int() - #| if j >= 0x40900000 { // z >= 1024 - #| if ((j - 0x40900000) | i) != 0 { // if z > 1024 - #| return s * POW_huge * POW_huge // overflow - #| } else if p_l + POW_ovt > z - p_h { - #| return s * POW_huge * POW_huge // overflow - #| } - #| } else if (j & 0x7fffffff) >= 0x4090cc00 { // z <= -1075 - #| if ((j - 0xc090cc00) | i) != 0 { // z < -1075 - #| return s * POW_tiny * POW_tiny // underflow - #| } else if p_l <= z - p_h { - #| return s * POW_tiny * POW_tiny // underflow - #| } - #| } - #| i = j & 0x7fffffff - #| k = (i >> 20) - 0x3ff - #| n = 0 - #| if i > 0x3fe00000 { // if |z| > 0.5, set n = [z+0.5] - #| n = j + (0x00100000 >> (k + 1)) - #| k = ((n & 0x7fffffff) >> 20) - 0x3ff // new k for n - #| t = ZERO - #| t = set_high_word(t, (n & (0x000fffff >> k).lnot()).reinterpret_as_uint()) - #| n = ((n & 0x000fffff) | 0x00100000) >> (20 - k) - #| if j < 0 { - #| n = -n - #| } - #| p_h -= t - #| } - #| t = p_l + p_h - #| t = set_low_word(t, 0) - #| u = t * POW_lg2_h - #| v = (p_l - (t - p_h)) * POW_lg2 + t * POW_lg2_l - #| z = u + v - #| w = v - (z - u) - #| t = z * z - #| t1 = z - - #| t * (POW_P1 + t * (POW_P2 + t * (POW_P3 + t * (POW_P4 + t * POW_P5)))) - #| r = z * t1 / (t1 - TWO - (w + z * w)) - #| z = ONE - (r - z) - #| j = get_high_word(z).reinterpret_as_int() - #| j += (n.reinterpret_as_uint() << 20).reinterpret_as_int() - #| if j >> 20 <= 0 { - #| z = scalbn(z, n) - #| } else { // subnormal output */ - #| let tmp = get_high_word(z).reinterpret_as_int() - #| z = set_high_word( - #| z, - #| (tmp + (n.reinterpret_as_uint() << 20).reinterpret_as_int()).reinterpret_as_uint(), - #| ) - #| } - #| return s * z - #|} - ), - "prime.mbt": ( - #|const DEFAULT_PRIME_TEST_ITERS = 64 - #|let small_primes : Array[@bigint.BigInt] = [ - #| 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, - #| 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, - #| 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, - #| 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, - #| 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, - #| 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, - #| 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, - #| 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, - #| 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, - #| 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, - #| 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, - #| 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, - #| 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, - #| 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, - #| 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, - #| 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, - #| 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, - #| 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, - #| 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, - #| 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, - #| 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, - #| 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, - #| 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, - #| 2351, 2357, 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, - #| 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, 2557, 2579, - #| 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, - #| 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, - #| 2789, 2791, 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, - #| 2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, 3001, 3011, - #| 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137, - #| 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, - #| 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, 3361, - #| 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, - #| 3499, 3511, 3517, 3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, - #| 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697, - #| 3701, 3709, 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821, - #| 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, 3919, 3923, - #| 3929, 3931, 3943, 3947, 3967, 3989, 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, - #| 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, 4153, 4157, - #| 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, 4261, 4271, - #| 4273, 4283, 4289, 4297, 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, - #| 4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, - #| 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637, 4639, 4643, 4649, - #| 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751, 4759, 4783, - #| 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909, - #| 4919, 4931, 4933, 4937, 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, - #| 5009, 5011, 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, 5099, 5101, 5107, 5113, - #| 5119, 5147, 5153, 5167, 5171, 5179, 5189, 5197, 5209, 5227, 5231, 5233, 5237, 5261, - #| 5273, 5279, 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387, 5393, 5399, - #| 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443, 5449, 5471, 5477, 5479, 5483, 5501, - #| 5503, 5507, 5519, 5521, 5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639, - #| 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, 5693, 5701, 5711, 5717, 5737, - #| 5741, 5743, 5749, 5779, 5783, 5791, 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, - #| 5851, 5857, 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, 5953, 5981, - #| 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, 6079, 6089, 6091, 6101, - #| 6113, 6121, 6131, 6133, 6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211, 6217, 6221, - #| 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329, - #| 6337, 6343, 6353, 6359, 6361, 6367, 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, - #| 6469, 6473, 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, 6577, 6581, - #| 6599, 6607, 6619, 6637, 6653, 6659, 6661, 6673, 6679, 6689, 6691, 6701, 6703, 6709, - #| 6719, 6733, 6737, 6761, 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, - #| 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, 6947, 6949, 6959, 6961, - #| 6967, 6971, 6977, 6983, 6991, 6997, 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, - #| 7079, 7103, 7109, 7121, 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, - #| 7219, 7229, 7237, 7243, 7247, 7253, 7283, 7297, 7307, 7309, 7321, 7331, 7333, 7349, - #| 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 7489, 7499, - #| 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, 7573, 7577, 7583, 7589, - #| 7591, 7603, 7607, 7621, 7639, 7643, 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, - #| 7717, 7723, 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, 7841, 7853, - #| 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919, 7927, 7933, 7937, 7949, 7951, 7963, - #| 7993, 8009, 8011, 8017, 8039, 8053, 8059, 8069, 8081, 8087, 8089, 8093, 8101, 8111, - #| 8117, 8123, 8147, 8161, 8167, 8171, 8179, 8191, 8209, 8219, 8221, 8231, 8233, 8237, - #| 8243, 8263, 8269, 8273, 8287, 8291, 8293, 8297, 8311, 8317, 8329, 8353, 8363, 8369, - #| 8377, 8387, 8389, 8419, 8423, 8429, 8431, 8443, 8447, 8461, 8467, 8501, 8513, 8521, - #| 8527, 8537, 8539, 8543, 8563, 8573, 8581, 8597, 8599, 8609, 8623, 8627, 8629, 8641, - #| 8647, 8663, 8669, 8677, 8681, 8689, 8693, 8699, 8707, 8713, 8719, 8731, 8737, 8741, - #| 8747, 8753, 8761, 8779, 8783, 8803, 8807, 8819, 8821, 8831, 8837, 8839, 8849, 8861, - #| 8863, 8867, 8887, 8893, 8923, 8929, 8933, 8941, 8951, 8963, 8969, 8971, 8999, 9001, - #| 9007, 9011, 9013, 9029, 9041, 9043, 9049, 9059, 9067, 9091, 9103, 9109, 9127, 9133, - #| 9137, 9151, 9157, 9161, 9173, 9181, 9187, 9199, 9203, 9209, 9221, 9227, 9239, 9241, - #| 9257, 9277, 9281, 9283, 9293, 9311, 9319, 9323, 9337, 9341, 9343, 9349, 9371, 9377, - #| 9391, 9397, 9403, 9413, 9419, 9421, 9431, 9433, 9437, 9439, 9461, 9463, 9467, 9473, - #| 9479, 9491, 9497, 9511, 9521, 9533, 9539, 9547, 9551, 9587, 9601, 9613, 9619, 9623, - #| 9629, 9631, 9643, 9649, 9661, 9677, 9679, 9689, 9697, 9719, 9721, 9733, 9739, 9743, - #| 9749, 9767, 9769, 9781, 9787, 9791, 9803, 9811, 9817, 9829, 9833, 9839, 9851, 9857, - #| 9859, 9871, 9883, 9887, 9901, 9907, 9923, 9929, 9931, 9941, 9949, 9967, 9973, 10007, - #| 10009, 10037, 10039, 10061, 10067, 10069, 10079, 10091, 10093, 10099, 10103, 10111, - #| 10133, 10139, 10141, 10151, 10159, 10163, 10169, 10177, 10181, 10193, 10211, 10223, - #| 10243, 10247, 10253, 10259, 10267, 10271, 10273, 10289, 10301, 10303, 10313, 10321, - #| 10331, 10333, 10337, 10343, 10357, 10369, 10391, 10399, 10427, 10429, 10433, 10453, - #| 10457, 10459, 10463, 10477, 10487, 10499, 10501, 10513, 10529, 10531, 10559, 10567, - #| 10589, 10597, 10601, 10607, 10613, 10627, 10631, 10639, 10651, 10657, 10663, 10667, - #| 10687, 10691, 10709, 10711, 10723, 10729, 10733, 10739, 10753, 10771, 10781, 10789, - #| 10799, 10831, 10837, 10847, 10853, 10859, 10861, 10867, 10883, 10889, 10891, 10903, - #| 10909, 10937, 10939, 10949, 10957, 10973, 10979, 10987, 10993, 11003, 11027, 11047, - #| 11057, 11059, 11069, 11071, 11083, 11087, 11093, 11113, 11117, 11119, 11131, 11149, - #| 11159, 11161, 11171, 11173, 11177, 11197, 11213, 11239, 11243, 11251, 11257, 11261, - #| 11273, 11279, 11287, 11299, 11311, 11317, 11321, 11329, 11351, 11353, 11369, 11383, - #| 11393, 11399, 11411, 11423, 11437, 11443, 11447, 11467, 11471, 11483, 11489, 11491, - #| 11497, 11503, 11519, 11527, 11549, 11551, 11579, 11587, 11593, 11597, 11617, 11621, - #| 11633, 11657, 11677, 11681, 11689, 11699, 11701, 11717, 11719, 11731, 11743, 11777, - #| 11779, 11783, 11789, 11801, 11807, 11813, 11821, 11827, 11831, 11833, 11839, 11863, - #| 11867, 11887, 11897, 11903, 11909, 11923, 11927, 11933, 11939, 11941, 11953, 11959, - #| 11969, 11971, 11981, 11987, 12007, 12011, 12037, 12041, 12043, 12049, 12071, 12073, - #| 12097, 12101, 12107, 12109, 12113, 12119, 12143, 12149, 12157, 12161, 12163, 12197, - #| 12203, 12211, 12227, 12239, 12241, 12251, 12253, 12263, 12269, 12277, 12281, 12289, - #| 12301, 12323, 12329, 12343, 12347, 12373, 12377, 12379, 12391, 12401, 12409, 12413, - #| 12421, 12433, 12437, 12451, 12457, 12473, 12479, 12487, 12491, 12497, 12503, 12511, - #| 12517, 12527, 12539, 12541, 12547, 12553, 12569, 12577, 12583, 12589, 12601, 12611, - #| 12613, 12619, 12637, 12641, 12647, 12653, 12659, 12671, 12689, 12697, 12703, 12713, - #| 12721, 12739, 12743, 12757, 12763, 12781, 12791, 12799, 12809, 12821, 12823, 12829, - #| 12841, 12853, 12889, 12893, 12899, 12907, 12911, 12917, 12919, 12923, 12941, 12953, - #| 12959, 12967, 12973, 12979, 12983, 13001, 13003, 13007, 13009, 13033, 13037, 13043, - #| 13049, 13063, 13093, 13099, 13103, 13109, 13121, 13127, 13147, 13151, 13159, 13163, - #| 13171, 13177, 13183, 13187, 13217, 13219, 13229, 13241, 13249, 13259, 13267, 13291, - #| 13297, 13309, 13313, 13327, 13331, 13337, 13339, 13367, 13381, 13397, 13399, 13411, - #| 13417, 13421, 13441, 13451, 13457, 13463, 13469, 13477, 13487, 13499, 13513, 13523, - #| 13537, 13553, 13567, 13577, 13591, 13597, 13613, 13619, 13627, 13633, 13649, 13669, - #| 13679, 13681, 13687, 13691, 13693, 13697, 13709, 13711, 13721, 13723, 13729, 13751, - #| 13757, 13759, 13763, 13781, 13789, 13799, 13807, 13829, 13831, 13841, 13859, 13873, - #| 13877, 13879, 13883, 13901, 13903, 13907, 13913, 13921, 13931, 13933, 13963, 13967, - #| 13997, 13999, 14009, 14011, 14029, 14033, 14051, 14057, 14071, 14081, 14083, 14087, - #| 14107, 14143, 14149, 14153, 14159, 14173, 14177, 14197, 14207, 14221, 14243, 14249, - #| 14251, 14281, 14293, 14303, 14321, 14323, 14327, 14341, 14347, 14369, 14387, 14389, - #| 14401, 14407, 14411, 14419, 14423, 14431, 14437, 14447, 14449, 14461, 14479, 14489, - #| 14503, 14519, 14533, 14537, 14543, 14549, 14551, 14557, 14561, 14563, 14591, 14593, - #| 14621, 14627, 14629, 14633, 14639, 14653, 14657, 14669, 14683, 14699, 14713, 14717, - #| 14723, 14731, 14737, 14741, 14747, 14753, 14759, 14767, 14771, 14779, 14783, 14797, - #| 14813, 14821, 14827, 14831, 14843, 14851, 14867, 14869, 14879, 14887, 14891, 14897, - #| 14923, 14929, 14939, 14947, 14951, 14957, 14969, 14983, 15013, 15017, 15031, 15053, - #| 15061, 15073, 15077, 15083, 15091, 15101, 15107, 15121, 15131, 15137, 15139, 15149, - #| 15161, 15173, 15187, 15193, 15199, 15217, 15227, 15233, 15241, 15259, 15263, 15269, - #| 15271, 15277, 15287, 15289, 15299, 15307, 15313, 15319, 15329, 15331, 15349, 15359, - #| 15361, 15373, 15377, 15383, 15391, 15401, 15413, 15427, 15439, 15443, 15451, 15461, - #| 15467, 15473, 15493, 15497, 15511, 15527, 15541, 15551, 15559, 15569, 15581, 15583, - #| 15601, 15607, 15619, 15629, 15641, 15643, 15647, 15649, 15661, 15667, 15671, 15679, - #| 15683, 15727, 15731, 15733, 15737, 15739, 15749, 15761, 15767, 15773, 15787, 15791, - #| 15797, 15803, 15809, 15817, 15823, 15859, 15877, 15881, 15887, 15889, 15901, 15907, - #| 15913, 15919, 15923, 15937, 15959, 15971, 15973, 15991, 16001, 16007, 16033, 16057, - #| 16061, 16063, 16067, 16069, 16073, 16087, 16091, 16097, 16103, 16111, 16127, 16139, - #| 16141, 16183, 16187, 16189, 16193, 16217, 16223, 16229, 16231, 16249, 16253, 16267, - #| 16273, 16301, 16319, 16333, 16339, 16349, 16361, 16363, 16369, 16381, 16411, 16417, - #| 16421, 16427, 16433, 16447, 16451, 16453, 16477, 16481, 16487, 16493, 16519, 16529, - #| 16547, 16553, 16561, 16567, 16573, 16603, 16607, 16619, 16631, 16633, 16649, 16651, - #| 16657, 16661, 16673, 16691, 16693, 16699, 16703, 16729, 16741, 16747, 16759, 16763, - #| 16787, 16811, 16823, 16829, 16831, 16843, 16871, 16879, 16883, 16889, 16901, 16903, - #| 16921, 16927, 16931, 16937, 16943, 16963, 16979, 16981, 16987, 16993, 17011, 17021, - #| 17027, 17029, 17033, 17041, 17047, 17053, 17077, 17093, 17099, 17107, 17117, 17123, - #| 17137, 17159, 17167, 17183, 17189, 17191, 17203, 17207, 17209, 17231, 17239, 17257, - #| 17291, 17293, 17299, 17317, 17321, 17327, 17333, 17341, 17351, 17359, 17377, 17383, - #| 17387, 17389, 17393, 17401, 17417, 17419, 17431, 17443, 17449, 17467, 17471, 17477, - #| 17483, 17489, 17491, 17497, 17509, 17519, 17539, 17551, 17569, 17573, 17579, 17581, - #| 17597, 17599, 17609, 17623, 17627, 17657, 17659, 17669, 17681, 17683, 17707, 17713, - #| 17729, 17737, 17747, 17749, 17761, 17783, 17789, 17791, 17807, 17827, 17837, 17839, - #| 17851, 17863, - #|] - #|pub fn is_probable_prime( - #| number : @bigint.BigInt, - #| rand : @random.Rand, - #| iters? : Int = DEFAULT_PRIME_TEST_ITERS, - #|) -> Bool { - #| if iters <= 0 { - #| abort("non-positive iters for probably prime") - #| } - #| if number <= 1N { - #| return false - #| } - #| if number <= 3N { - #| return true - #| } - #| if number % 2N == 0 { - #| return false - #| } - #| trial_divisions(number) && miller_rabin_test(number, iters, rand) - #|} - #|pub fn probable_prime(bits : Int, rand : @random.Rand) -> @bigint.BigInt { - #| for { - #| let b = rand.bigint(bits) - #| if is_probable_prime(b, rand) { - #| break b - #| } - #| } - #|} - #|fn trial_divisions(n : @bigint.BigInt) -> Bool { - #| let td = match n.bit_length() { - #| _..=512 => 64 - #| 512..=1024 => 128 - #| 1024..=2048 => 384 - #| 2048..=4096 => 1024 - #| _ => 2048 - #| } - #| for i in 1.. Bool { - #| if w <= 3N { - #| abort("candidate of miller rabin test must larger than 3") - #| } - #| let w1 = w - 1N - #| let w3 = w - 3N - #| let a = w1.ctz() - #| let m = w1 >> a - #| let w3_len = w3.bit_length() - #| next~: for i in 0.. Double { - #| let mut n = exp - #| let mut y : Double = x - #| if n > 1023 { - #| y *= 0x1.0p1023 - #| n -= 1023 - #| if n > 1023 { - #| y *= 0x1.0p1023 - #| n -= 1023 - #| if n > 1023 { - #| n = 1023 - #| } - #| } - #| } else if n < -1022 { - #| y *= 0x1.0p-1022 * 0x1.0p53 - #| n += 1022 - 53 - #| if n < -1022 { - #| y *= 0x1.0p-1022 * 0x1.0p53 - #| n += 1022 - 53 - #| if n < -1022 { - #| n = -1022 - #| } - #| } - #| } - #| let ui = (0x3ff + n).to_uint64() << 52 - #| return y * ui.reinterpret_as_double() - #|} - #|pub fn scalbnf(y : Float, exp : Int) -> Float { - #| let mut y = y - #| let mut n = exp - #| if n > 127 { - #| y *= (0x1.0p127 : Float) - #| n -= 127 - #| if n > 127 { - #| y *= (0x1.0p127 : Float) - #| n -= 127 - #| if n > 127 { - #| n = 127 - #| } - #| } - #| } else if n < -126 { - #| y *= (0x1.0p-126 : Float) * 0x1.0p24 - #| n += 126 - 24 - #| if n < -126 { - #| y *= (0x1.0p-126 : Float) * 0x1.0p24 - #| n += 126 - 24 - #| if n < -126 { - #| n = -126 - #| } - #| } - #| } - #| let u = (0x7f + n) << 23 - #| return y * Float::reinterpret_from_int(u) - #|} - #|test "scalbn" { - #| inspect(scalbn(1.5, 2), content="6") - #| inspect(scalbn(2.0, -1), content="1") - #| inspect(scalbn(3.0, 0), content="3") - #| inspect(scalbn(1.0, 1024), content="Infinity") - #| inspect(scalbn(1.0, -1023), content="1.1125369292536007e-308") - #| inspect(scalbn(1.0, 2047), content="Infinity") - #| inspect(scalbn(1.0, -1992), content="0") - #| inspect(scalbn(1.0, 3070), content="Infinity") - #| inspect(scalbn(1.0, -2961), content="0") - #| inspect(scalbn(@double.infinity, 10), content="Infinity") - #| inspect(scalbn(@double.not_a_number, 10), content="NaN") - #| inspect(scalbn(0.0, 10), content="0") - #|} - ), - "trig.mbt": ( - #|pub const PI = 0x3.243F6A8885A308CA8A54 - #|const SIN_SWITCHOVER : Float = 201.15625 - #|const COS_SWITCHOVER : Float = 142.90625 - #|fn mulh(a : UInt, b : UInt) -> UInt { - #| let a = a.to_uint64() - #| let b = b.to_uint64() - #| let res = a * b - #| (res >> 32).to_uint() - #|} - #|fn mul(a : UInt, b : UInt) -> (UInt, UInt) { - #| let a = a.to_uint64() - #| let b = b.to_uint64() - #| let res = a * b - #| ((res >> 32).to_uint(), res.to_uint()) - #|} - #|fn trig_reduce(x : Float, switch_over : Float) -> (Float, Int) { - #| if x.abs() <= switch_over { - #| let mut j : Float = 0.0 - #| let mut r : Float = 0.0 - #| j = x * Float::reinterpret_from_int(0x3f22f983) + - #| Float::reinterpret_from_int(0x4b40_0000) - #| j = Float::from_int(j.reinterpret_as_int() - 0x4b40_0000) - #| r = x - j * Float::reinterpret_from_int(0x3fc90f80) - #| r = r - j * Float::reinterpret_from_int(0x37354440) - #| r = r - j * Float::reinterpret_from_int(0x2c34611a) - #| return (r, j.to_int()) - #| } - #| let xispos = x > 0.0 - #| let mut exp : Int = ((x.reinterpret_as_int() >> 23) & 0xff) - 126 - #| let ix = ((x.reinterpret_as_uint() & 0x007fffff) << 8) | 0x80000000 - #| let ind = exp >> 5 - #| exp = exp & 0x1f - #| let two_over_pi : Array[UInt] = [ - #| 0x00000000, 0x28be60db, 0x9391054a, 0x7f09d5f4, 0x7d4d3770, 0x36d8a566, 0x4f10e410, - #| 0000000000, - #| ] - #| let mut hi = two_over_pi[ind] - #| let mut mi = two_over_pi[ind + 1] - #| let mut lo = two_over_pi[ind + 2] - #| let tp = two_over_pi[ind + 3] - #| if exp > 0 { - #| hi = (hi << exp) | (mi >> (32 - exp)) - #| mi = (mi << exp) | (lo >> (32 - exp)) - #| lo = (lo << exp) | (tp >> (32 - exp)) - #| } - #| let phi = 0U - #| let (h, l) = mul(ix, lo) - #| let plo = phi + l - #| let phi = h + (if plo < l { 1 } else { 0 }) - #| let (h, l) = mul(ix, mi) - #| let mut plo = phi + l - #| let phi = h + (if plo < l { 1 } else { 0 }) - #| let l = ix * hi - #| let mut phi = phi + l - #| let mut q : Int = (phi >> 30).reinterpret_as_int() - #| phi = phi & 0x3fffffff - #| if (phi & 0x2000_0000) != 0 { - #| phi = phi - 0x4000_0000 - #| q = q + 1 - #| } - #| let s : UInt = phi & 0x8000_0000 - #| if phi >= 0x8000_0000 { - #| phi = phi.lnot() - #| plo = 0U - plo - #| phi += if plo == 0 { 1 } else { 0 } - #| } - #| exp = 0 - #| while phi < 0x8000_0000 { - #| phi = (phi << 1) | (plo >> 31) - #| plo = plo << 1 - #| exp = exp - 1 - #| } - #| phi = mulh(phi, 0xc90f_daa2) - #| if phi < 0x8000_0000 { - #| phi = phi << 1 - #| exp = exp - 1 - #| } - #| let mut r = s + - #| ((exp + 128) << 23).reinterpret_as_uint() + - #| (phi >> 8) + - #| (if (phi & 0xff) > 0x7e { 1 } else { 0 }) - #| if !xispos { - #| r = r ^ 0x8000_0000 - #| q = -q - #| } - #| let r = Float::reinterpret_from_uint(r) - #| return (r, q) - #|} - #|fn sinf_poly(x : Float) -> Float { - #| let s = x * x - #| let mut r = Float::reinterpret_from_int(0x3640_5000) - #| r = r * s - Float::reinterpret_from_int(0x3950_3486) - #| r = r * s + Float::reinterpret_from_int(0x3c08_88c1) - #| r = r * s - Float::reinterpret_from_int(0x3e2a_aaab) - #| let t = x * s - #| r = r * t + x - #| r - #|} - #|fn cosf_poly(x : Float) -> Float { - #| let s = x * x - #| let mut r = Float::reinterpret_from_int(0x37cd_4000) - #| r = r * s - Float::reinterpret_from_int(0x3ab6_077d) - #| r = r * s + Float::reinterpret_from_int(0x3d2a_aaa8) - #| r = r * s - Float::reinterpret_from_int(0x3f00_0000) - #| r = r * s + Float::reinterpret_from_int(0x3f80_0000) - #| r - #|} - #|fn sin_cos_core(x : Float, q : Int) -> Float { - #| let mut r = if (q & 1) != 0 { cosf_poly(x) } else { sinf_poly(x) } - #| if (q & 2) != 0 { - #| r = -r - #| } - #| r - #|} - #|fn tanf_poly(x : Float, odd : Bool) -> Float { - #| let x = x.to_double() - #| let coef : ReadOnlyArray[Double] = [ - #| 0.333331395030791399758, // 0x15554d3418c99f.0p-54 */ - #| 0.133392002712976742718, // 0x1112fd38999f72.0p-55 */ - #| 0.0533812378445670393523, // 0x1b54c91d865afe.0p-57 */ - #| 0.0245283181166547278873, // 0x191df3908c33ce.0p-58 */ - #| 0.00297435743359967304927, // 0x185dadfcecf44e.0p-61 */ - #| 0.00946564784943673166728, // 0x1362b9bf971bcd.0p-59 */ - #| ] - #| let z = x * x - #| let mut r = coef[4] + z * coef[5] - #| let t = coef[2] + z * coef[3] - #| let w = z * z - #| let s = z * x - #| let u = coef[0] + z * coef[1] - #| r = x + s * u + s * w * (t + w * r) - #| Float::from_double(if odd { -1.0 / r } else { r }) - #|} - #|pub fn sinf(x : Float) -> Float { - #| if x.is_nan() || x.is_inf() { - #| return @float.not_a_number - #| } - #| if x == 0.0 { - #| return x - #| } - #| let (x, q) = trig_reduce(x, SIN_SWITCHOVER) - #| sin_cos_core(x, q) - #|} - #|pub fn cosf(x : Float) -> Float { - #| if x.is_nan() || x.is_inf() { - #| return @float.not_a_number - #| } - #| if x == 0.0 { - #| return 1.0 - #| } - #| let (x, q) = trig_reduce(x, COS_SWITCHOVER) - #| sin_cos_core(x, q + 1) - #|} - #|pub fn tanf(x : Float) -> Float { - #| if x.is_nan() || x.is_inf() { - #| return @float.not_a_number - #| } - #| if x == 0.0 { - #| return x - #| } - #| let (x, q) = trig_reduce(x, COS_SWITCHOVER) - #| tanf_poly(x, (q & 1) != 0) - #|} - #|pub fn asinf(x : Float) -> Float { - #| let x1p120 = 0x3870000000000000UL.reinterpret_as_double() - #| let pio2 : Double = 1.570796326794896558e+00 - #| let ps0 : Float = 1.6666586697e-01 - #| let ps1 : Float = -4.2743422091e-02 - #| let ps2 : Float = -8.6563630030e-03 - #| let qs2 : Float = -7.0662963390e-01 - #| fn r(z : Float) -> Float { - #| let p = z * (ps0 + z * (ps1 + z * ps2)) - #| let q = z * qs2 + 1.0 - #| p / q - #| } - #| let hx = x.reinterpret_as_uint() - #| let ix = hx & 0x7fffffff - #| if ix >= 0x3f800000 { - #| if ix == 0x3f800000 { - #| return Float::from_double(x.to_double() * pio2 + x1p120) - #| } - #| return @float.not_a_number // asin(|x|>1) is NaN - #| } - #| if ix < 0x3f000000 { - #| if ix is (0x00800000..=0x39800000) { - #| return x - #| } - #| return x + x * r(x * x) - #| } - #| let z = ((1.0 : Float) - x.abs()) * 0.5 - #| let s = z.to_double().sqrt() - #| let x = Float::from_double(pio2 - 2.0 * (s + s * r(z).to_double())) - #| if hx >> 31 != 0 { - #| -x - #| } else { - #| x - #| } - #|} - #|pub fn acosf(x : Float) -> Float { - #| let pio2_hi : Float = 1.5707962513 - #| let pio2_lo : Float = 7.5497894159e-08 - #| let ps0 : Float = 1.6666586697e-01 - #| let ps1 : Float = -4.2743422091e-02 - #| let ps2 : Float = -8.6563630030e-03 - #| let qs1 : Float = -7.0662963390e-01 - #| let one : Float = 1.0 - #| let two : Float = 2.0 - #| fn r(z : Float) -> Float { - #| let p = z * (ps0 + z * (ps1 + z * ps2)) - #| let q = z * qs1 + 1.0 - #| p / q - #| } - #| let hx = x.reinterpret_as_int() - #| let ix = hx & 0x7fffffff - #| if ix >= 0x3f800000 { - #| if ix == 0x3f800000 { - #| if hx >> 31 != 0 { - #| return two * pio2_hi + 0x1.0p-120 - #| } - #| return 0.0 - #| } - #| return @float.not_a_number - #| } - #| if ix < 0x3f000000 { - #| if ix <= 0x32800000 { - #| return pio2_hi + 0x1.0p-120 - #| } - #| return pio2_hi - (x - (pio2_lo - x * r(x * x))) - #| } - #| if hx >> 31 != 0 { - #| let z = (x + 1.0) * 0.5 - #| let s = z.sqrt() - #| let w = r(z) * s - pio2_lo - #| return two * (pio2_hi - (s + w)) - #| } - #| let z = (one - x) * 0.5 - #| let s = z.sqrt() - #| let df = s - #| let c = (z - df * df) / (s + df) - #| let w = r(z) * s + c - #| two * (df + w) - #|} - #|pub fn atanf(x : Float) -> Float { - #| let atanhi : Array[Float] = [ - #| 4.6364760399e-01, 7.8539812565e-01, 9.8279368877e-01, 1.5707962513e+00, - #| ] - #| let atanlo : Array[Float] = [ - #| 5.0121582440e-09, 3.7748947079e-08, 3.4473217170e-08, 7.5497894159e-08, - #| ] - #| let a_t : Array[Float] = [ - #| 3.3333328366e-01, -1.9999158382e-01, 1.4253635705e-01, -1.0648017377e-01, 6.1687607318e-02, - #| ] - #| let ix = x.reinterpret_as_int() - #| let sign = ix >> 31 - #| let ix = ix & 0x7fffffff - #| let mut id = 0 - #| let mut x = x - #| let one : Float = 1.0 - #| let two : Float = 2.0 - #| if ix >= 0x4c800000 { - #| if x.is_nan() { - #| return x - #| } - #| let z = atanhi[3] + 0x1.0p-120 - #| let z = if sign != 0 { -z } else { z } - #| return z - #| } - #| if ix < 0x3ee00000 { - #| if ix < 0x39800000 { - #| return x - #| } - #| id = -1 - #| } else { - #| x = x.abs() - #| if ix < 0x3f980000 { - #| if ix < 0x3f300000 { - #| id = 0 - #| x = (two * x - one) / (two + x) - #| } else { - #| id = 1 - #| x = (x - one) / (x + one) - #| } - #| } else if ix < 0x401c0000 { - #| id = 2 - #| x = (x - 1.5) / (one + x * 1.5) - #| } else { - #| id = 3 - #| x = -one / x - #| } - #| } - #| let z = x * x - #| let w = z * z - #| let s1 = z * (a_t[0] + w * (a_t[2] + w * a_t[4])) - #| let s2 = w * (a_t[1] + w * a_t[3]) - #| if id < 0 { - #| return x - x * (s1 + s2) - #| } - #| let z = atanhi[id] - (x * (s1 + s2) - atanlo[id] - x) - #| if sign != 0 { - #| -z - #| } else { - #| z - #| } - #|} - #|pub fn atan2f(y : Float, x : Float) -> Float { - #| if x.is_nan() || y.is_nan() { - #| return @float.not_a_number - #| } - #| let pi : Float = 3.1415927410e+00 - #| let zero : Float = 0.0 - #| let ix = x.reinterpret_as_uint() - #| let iy = y.reinterpret_as_uint() - #| if ix == 0x3f800000 { - #| return atanf(y) - #| } - #| let m = ((iy >> 31) & 1) | ((ix >> 30) & 2) - #| let ix = ix & 0x7fffffff - #| let iy = iy & 0x7fffffff - #| if iy == 0 { - #| match m { - #| 0 | 1 => return y - #| 2 => return pi - #| _ => return -pi - #| } - #| } - #| if ix == 0 { - #| let res = if (m & 1) != 0 { -pi / 2 } else { pi / 2 } - #| return res - #| } - #| if ix == 0x7f800000 { - #| if iy == 0x7f800000 { - #| match m { - #| 0 => return pi / 4 - #| 1 => return -pi / 4 - #| 2 => return pi * 3.0 / 4 - #| _ => return -pi * 3.0 / 4 - #| } - #| } else { - #| match m { - #| 0 => return 0.0 - #| 1 => return -0.0 - #| 2 => return pi - #| _ => return -pi - #| } - #| } - #| } - #| if ix + (26U << 23) < iy || iy == 0x7f800000 { - #| let res = if (m & 1) != 0 { -pi / 2 } else { pi / 2 } - #| return res - #| } - #| let z = if (m & 2) != 0 && iy + (26U << 23) < ix { - #| zero - #| } else { - #| atanf(y.abs() / x.abs()) - #| } - #| match m { - #| 0 => z - #| 1 => -z - #| 2 => pi - z - #| _ => z - pi - #| } - #|} - ), - "trig_double_js.mbt": ( - #|pub fn sin(x : Double) -> Double = "Math" "sin" - #|pub fn cos(x : Double) -> Double = "Math" "cos" - #|pub fn tan(x : Double) -> Double = "Math" "tan" - #|pub fn asin(x : Double) -> Double = "Math" "asin" - #|pub fn acos(x : Double) -> Double = "Math" "acos" - #|pub fn atan(x : Double) -> Double = "Math" "atan" - #|pub fn atan2(y : Double, x : Double) -> Double = "Math" "atan2" - ), - "trig_double_nonjs.mbt": ( - #|pub fn tan(x : Double) -> Double { - #| if x.is_inf() || x.is_nan() { - #| return @double.not_a_number - #| } - #| let y = Array::make(2, 0.0) - #| let z = 0.0 - #| if x.abs() <= PI_OVER_4 { - #| __kernal_tan(x, z, 1) - #| } else { - #| let n = rem_pio2(x, y) - #| __kernal_tan(y[0], y[1], 1 - ((n & 1) << 1)) - #| } - #|} - #|pub fn asin(x : Double) -> Double { - #| let huge = 1.0e+300 - #| let pio4_hi = 7.85398163397448278999e-01 - #| let pio2_hi = 1.57079632679489655800 - #| let pio2_lo = 6.12323399573676603587e-17 - #| let ps0 = 1.66666666666666657415e-01 - #| let ps1 = -3.25565818622400915405e-01 - #| let ps2 = 2.01212532134862925881e-01 - #| let ps3 = -4.00555345006794114027e-02 - #| let ps4 = 7.91534994289814532176e-04 - #| let ps5 = 3.47933107596021167570e-05 - #| let qs1 = -2.40339491173441421878e+00 - #| let qs2 = 2.02094576023350569471e+00 - #| let qs3 = -6.88283971605453293030e-01 - #| let qs4 = 7.70381505559019352791e-02 - #| let ix = get_high_word(x).reinterpret_as_int() & 0x7fffffff - #| let absx = x.abs() - #| if absx >= 1.0 { - #| if absx == 1.0 { - #| return x * pio2_hi + x * pio2_lo - #| } else { - #| return @double.not_a_number - #| } - #| } else if absx < 0.5 { - #| if ix < 0x3e400000 { - #| if huge + x > 1.0 { - #| return x - #| } - #| } else { - #| let t = x * x - #| let p = t * - #| (ps0 + t * (ps1 + t * (ps2 + t * (ps3 + t * (ps4 + t * ps5))))) - #| let q = 1.0 + t * (qs1 + t * (qs2 + t * (qs3 + t * qs4))) - #| let w = p / q - #| return x + x * w - #| } - #| } - #| let w = 1.0 - absx - #| let t = w * 0.5 - #| let p = t * (ps0 + t * (ps1 + t * (ps2 + t * (ps3 + t * (ps4 + t * ps5))))) - #| let q = 1.0 + t * (qs1 + t * (qs2 + t * (qs3 + t * qs4))) - #| let s = t.sqrt() - #| if ix >= 0x3FEF3333 { - #| let w = p / q - #| let t = pio2_hi - (2.0 * (s + s * w) - pio2_lo) - #| return if x > 0.0 { t } else { -t } - #| } else { - #| let mut w = s - #| w = set_low_word(w, 0) - #| let c = (t - w * w) / (s + w) - #| let r = p / q - #| let p = 2.0 * s * r - (pio2_lo - 2.0 * c) - #| let q = pio4_hi - 2.0 * w - #| let t = pio4_hi - (p - q) - #| return if x > 0.0 { t } else { -t } - #| } - #|} - #|pub fn acos(x : Double) -> Double { - #| let one : Double = 1.0 - #| let pi : Double = 3.14159265358979311600 - #| let pio2_hi : Double = 1.57079632679489655800 - #| let pio2_lo : Double = 6.12323399573676603587e-17 - #| let ps0 : Double = 1.66666666666666657415e-01 - #| let ps1 : Double = -3.25565818622400915405e-01 - #| let ps2 : Double = 2.01212532134862925881e-01 - #| let ps3 : Double = -4.00555345006794114027e-02 - #| let ps4 : Double = 7.91534994289814532176e-04 - #| let ps5 : Double = 3.47933107596021167570e-05 - #| let qs1 : Double = -2.40339491173441421878e+00 - #| let qs2 : Double = 2.02094576023350569471e+00 - #| let qs3 : Double = -6.88283971605453293030e-01 - #| let qs4 : Double = 7.70381505559019352791e-02 - #| let ix = get_high_word(x).reinterpret_as_int() & 0x7fffffff - #| let absx = x.abs() - #| if absx >= 1.0 { - #| if absx == 1.0 { - #| if x > 0 { - #| return 0.0 - #| } else { - #| return pi + 2.0 * pio2_lo - #| } - #| } - #| return @double.not_a_number - #| } - #| if absx < 0.5 { - #| if ix <= 0x3c600000 { - #| return pio2_hi + pio2_lo - #| } - #| let z = x * x - #| let p = z * (ps0 + z * (ps1 + z * (ps2 + z * (ps3 + z * (ps4 + z * ps5))))) - #| let q = one + z * (qs1 + z * (qs2 + z * (qs3 + z * qs4))) - #| let r = p / q - #| pio2_hi - (x - (pio2_lo - x * r)) - #| } else if x < 0 { - #| let z = (one + x) * 0.5 - #| let p = z * (ps0 + z * (ps1 + z * (ps2 + z * (ps3 + z * (ps4 + z * ps5))))) - #| let q = one + z * (qs1 + z * (qs2 + z * (qs3 + z * qs4))) - #| let s = z.sqrt() - #| let r = p / q - #| let w = r * s - pio2_lo - #| pi - 2.0 * (s + w) - #| } else { - #| let z = (one - x) * 0.5 - #| let s = z.sqrt() - #| let df = s - #| let c = (z - df * df) / (s + df) - #| let p = z * (ps0 + z * (ps1 + z * (ps2 + z * (ps3 + z * (ps4 + z * ps5))))) - #| let q = one + z * (qs1 + z * (qs2 + z * (qs3 + z * qs4))) - #| let r = p / q - #| let w = r * s + c - #| 2.0 * (df + w) - #| } - #|} - #|pub fn atan(x : Double) -> Double { - #| if x.is_nan() || x == 0.0 { - #| return x - #| } - #| let atan_hi : ReadOnlyArray[Double] = [ - #| 4.63647609000806093515e-01, 7.85398163397448278999e-01, 9.82793723247329054082e-01, - #| 1.57079632679489655800e+00, - #| ] - #| let atan_lo : ReadOnlyArray[Double] = [ - #| 2.26987774529616870924e-17, 3.06161699786838301793e-17, 1.39033110312309984516e-17, - #| 6.12323399573676603587e-17, - #| ] - #| let a_t : ReadOnlyArray[Double] = [ - #| 3.33333333333329318027e-01, -1.99999999998764832476e-01, 1.42857142725034663711e-01, - #| -1.11111104054623557880e-01, 9.09088713343650656196e-02, -7.69187620504482999495e-02, - #| 6.66107313738753120669e-02, -5.83357013379057348645e-02, 4.97687799461593236017e-02, - #| -3.65315727442169155270e-02, 1.62858201153657823623e-02, - #| ] - #| let one = 1.0 - #| let huge = 1.0e300 - #| let ix = get_high_word(x).reinterpret_as_int() & 0x7fffffff - #| let mut id = 0 - #| let mut z = 0.0 - #| let mut w = 0.0 - #| let mut x = x - #| let x_is_neg = x < 0.0 - #| if ix >= 0x44100000 { - #| if x > 0 { - #| return atan_hi[3] + atan_lo[3] - #| } else { - #| return -atan_hi[3] - atan_lo[3] - #| } - #| } - #| if ix < 0x3fdc0000 { - #| if ix < 0x3e200000 { - #| if huge + x > one { - #| return x - #| } - #| } - #| id = -1 - #| } else { - #| x = x.abs() - #| if ix < 0x3ff30000 { - #| if ix < 0x3fe60000 { - #| id = 0 - #| x = (2.0 * x - one) / (2.0 + x) - #| } else { - #| id = 1 - #| x = (x - one) / (x + one) - #| } - #| } else if ix < 0x40038000 { - #| id = 2 - #| x = (x - 1.5) / (one + 1.5 * x) - #| } else { - #| id = 3 - #| x = -1.0 / x - #| } - #| } - #| z = x * x - #| w = z * z - #| let s1 = z * - #| ( - #| a_t[0] + - #| w * (a_t[2] + w * (a_t[4] + w * (a_t[6] + w * (a_t[8] + w * a_t[10])))) - #| ) - #| let s2 = w * - #| (a_t[1] + w * (a_t[3] + w * (a_t[5] + w * (a_t[7] + w * a_t[9])))) - #| if id < 0 { - #| x - x * (s1 + s2) - #| } else { - #| z = atan_hi[id] - (x * (s1 + s2) - atan_lo[id] - x) - #| if x_is_neg { - #| -z - #| } else { - #| z - #| } - #| } - #|} - #|pub fn atan2(y : Double, x : Double) -> Double { - #| if x.is_nan() || y.is_nan() { - #| return @double.not_a_number - #| } - #| let tiny = 1.0e-300 - #| let zero = 0.0 - #| let pi_o_4 = 7.8539816339744827900E-01 - #| let pi_o_2 = 1.5707963267948965580E+00 - #| let pi = 3.1415926535897931160E+00 - #| let pi_lo = 1.2246467991473531772E-16 - #| let hx = get_high_word(x).reinterpret_as_int() - #| let hy = get_high_word(y).reinterpret_as_int() - #| let ix = hx & 0x7fffffff - #| let iy = hy & 0x7fffffff - #| if x == 1.0 { - #| return atan(y) - #| } - #| let m = ((hy >> 31) & 1) | ((hx >> 30) & 2) - #| if y == 0 { - #| match m { - #| 0 | 1 => return y - #| 2 => return pi + tiny - #| _ => return -pi - tiny - #| } - #| } - #| if x == 0 { - #| return if hy < 0 { -pi_o_2 - tiny } else { pi_o_2 + tiny } - #| } - #| if x.is_inf() { - #| if y.is_inf() { - #| match m { - #| 0 => return pi_o_4 + tiny - #| 1 => return -pi_o_4 - tiny - #| 2 => return 3.0 * pi_o_4 + tiny - #| _ => return -3.0 * pi_o_4 - tiny - #| } - #| } else { - #| match m { - #| 0 => return zero - #| 1 => return -zero - #| 2 => return pi + tiny - #| _ => return -pi - tiny - #| } - #| } - #| } - #| if y.is_inf() { - #| return if hy < 0 { -pi_o_2 - tiny } else { pi_o_2 + tiny } - #| } - #| let k = (iy - ix) >> 20 - #| let z = if k > 60 { - #| pi_o_2 + 0.5 * pi_lo - #| } else if hx < 0 && k < -60 { - #| 0.0 - #| } else { - #| atan(abs(y / x)) - #| } - #| match m { - #| 0 => z - #| 1 => -z - #| 2 => pi - (z - pi_lo) - #| _ => z - pi_lo - pi - #| } - #|} - #|fn rem_pio2(x : Double, y : Array[Double]) -> Int { - #| let hx = get_high_word(x).reinterpret_as_int() - #| let ix : Int = hx & 0x7fffffff - #| let mut z = 0.0 - #| if ix <= 0x3fe921fb { - #| y[0] = x - #| y[1] = 0.0 - #| return 0 - #| } - #| if ix < 0x4002d97c { - #| if hx > 0 { - #| z = x - PIO2_1 - #| if ix != 0x3ff921fb { - #| y[0] = z - PIO2_1T - #| y[1] = z - y[0] - PIO2_1T - #| } else { - #| z = z - PIO2_2 - #| y[0] = z - PIO2_2T - #| y[1] = z - y[0] - PIO2_2T - #| } - #| return 1 - #| } else { - #| z = x + PIO2_1 - #| if ix != 0x3ff921fb { - #| y[0] = z + PIO2_1T - #| y[1] = z - y[0] + PIO2_1T - #| } else { - #| let z = z + PIO2_2 - #| y[0] = z + PIO2_2T - #| y[1] = z - y[0] + PIO2_2T - #| } - #| return -1 - #| } - #| } - #| if ix <= 0x413921fb { - #| let t = x.abs() - #| let n = (t * INV_PIO2 + HALF).to_int() - #| let fn_ = n.to_double() - #| let mut r = t - fn_ * PIO2_1 - #| let mut w = fn_ * PIO2_1T - #| if n < 32 && ix != npio2_hw[n - 1] { - #| y[0] = r - w - #| } else { - #| let j = ix >> 20 - #| y[0] = r - w - #| let i = j - ((get_high_word(y[0]) >> 20).reinterpret_as_int() & 0x7ff) - #| if i > 16 { - #| let t = r - #| w = fn_ * PIO2_2 - #| r = t - w - #| w = fn_ * PIO2_2T - (t - r - w) - #| y[0] = r - w - #| let i = j - ((get_high_word(y[0]) >> 20).reinterpret_as_int() & 0x7ff) - #| if i > 49 { - #| let t = r - #| w = fn_ * PIO2_3 - #| r = t - w - #| w = fn_ * PIO2_3T - (t - r - w) - #| y[0] = r - w - #| } - #| } - #| } - #| y[1] = r - y[0] - w - #| if hx > 0 { - #| return n - #| } else { - #| y[0] = -y[0] - #| y[1] = -y[1] - #| return -n - #| } - #| } - #| if ix >= 0x7ff00000 { - #| y[0] = x - x - #| y[1] = y[0] - #| return 0 - #| } - #| z = set_low_word(z, get_low_word(x)) - #| let e0 = (ix >> 20) - 1046 // e0 = ilogb(z) - 23 - #| z = set_high_word(z, (ix - (e0 << 20)).reinterpret_as_uint()) - #| let tx = [0.0, 0.0, 0.0] - #| for i in 0..<2 { - #| tx[i] = z.to_int().to_double() - #| z = (z - tx[i]) * TWO24 - #| } - #| tx[2] = z - #| let mut nx = 3 - #| while tx[nx - 1] == 0.0 { - #| nx -= 1 - #| } - #| let n = __kernel_rem_pio2(tx, y, e0, nx, 2) - #| if hx > 0 { - #| n - #| } else { - #| y[0] = -y[0] - #| y[1] = -y[1] - #| -n - #| } - #|} - #|fn __kernel_rem_pio2( - #| x : Array[Double], - #| y : Array[Double], - #| e0 : Int, - #| nx : Int, - #| prec : Int, - #|) -> Int { - #| let init_jk : ReadOnlyArray[Int] = [2, 3, 4, 6] - #| let two24 : Double = 16777216.0 // 0x41700000, 0x00000000 - #| let twon24 : Double = 5.96046447753906250000e-08 // 0x3E700000, 0x00000000 - #| let mut jz : Int = 0 - #| let mut jx : Int = 0 - #| let mut jv : Int = 0 - #| let mut jp : Int = 0 - #| let mut jk : Int = 0 - #| let mut carry : Int = 0 - #| let mut n : Int = 0 - #| let iq : Array[Int] = Array::make(20, 0) - #| let mut i : Int = 0 - #| let mut j : Int = 0 - #| let mut k : Int = 0 - #| let mut m : Int = 0 - #| let mut q0 : Int = 0 - #| let mut ih : Int = 0 - #| let mut z : Double = 0 - #| let mut fw : Double = 0 - #| let f : Array[Double] = Array::make(20, 0.0) - #| let fq : Array[Double] = Array::make(20, 0.0) - #| let q : Array[Double] = Array::make(20, 0.0) - #| jk = init_jk[prec] - #| jp = jk - #| jx = nx - 1 - #| jv = (e0 - 3) / 24 - #| if jv < 0 { - #| jv = 0 - #| } - #| q0 = e0 - 24 * (jv + 1) - #| j = jv - jx - #| m = jx + jk - #| i = 0 - #| while i <= m { - #| f[i] = if j < 0 { 0.0 } else { two_over_pi[j].to_double() } - #| i += 1 - #| j += 1 - #| } - #| i = 0 - #| while i <= jk { - #| j = 0 - #| fw = 0.0 - #| while j <= jx { - #| fw += x[j] * f[jx + i - j] - #| j += 1 - #| } - #| q[i] = fw - #| i += 1 - #| } - #| jz = jk - #| let mut recompute = true - #| while recompute { - #| recompute = false - #| i = 0 - #| j = jz - #| z = q[jz] - #| while j > 0 { - #| fw = (twon24 * z).floor() - #| iq[i] = (z - two24 * fw).to_int() - #| z = q[j - 1] + fw - #| i += 1 - #| j -= 1 - #| } - #| z = scalbn(z, q0) // actual value of z - #| z -= 8.0 * (z * 0.125).floor() // trim off integer >= 8 - #| n = z.to_int() - #| z -= n.to_double() - #| ih = 0 - #| if q0 > 0 { - #| i = iq[jz - 1] >> (24 - q0) - #| n += i - #| iq[jz - 1] -= i << (24 - q0) - #| ih = iq[jz - 1] >> (23 - q0) - #| } else if q0 == 0 { - #| ih = iq[jz - 1] >> 23 - #| } else if z >= 0.5 { - #| ih = 2 - #| } - #| if ih > 0 { - #| n += 1 - #| carry = 0 - #| i = 0 - #| while i < jz { - #| j = iq[i] - #| if carry == 0 { - #| if j != 0 { - #| carry = 1 - #| iq[i] = 0x1000000 - j - #| } - #| } else { - #| iq[i] = 0xffffff - j - #| } - #| i += 1 - #| } - #| if q0 > 0 { - #| match q0 { - #| 1 => iq[jz - 1] = iq[jz - 1] & 0x7fffff - #| 2 => iq[jz - 1] = iq[jz - 1] & 0x3fffff - #| _ => () - #| } - #| } - #| if ih == 2 { - #| z = 1.0 - z - #| if carry != 0 { - #| z -= scalbn(1.0, q0) - #| } - #| } - #| } - #| if z == 0.0 { - #| j = 0 - #| i = jz - 1 - #| while i >= jk { - #| j = j | iq[i] - #| i -= 1 - #| } - #| if j == 0 { - #| k = 1 - #| while iq[jk - k] == 0 { - #| k += 1 - #| } - #| i = jz + 1 - #| while i <= jz + k { - #| f[jx + i] = two_over_pi[jv + i].to_double() - #| j = 0 - #| fw = 0.0 - #| while j <= jx { - #| fw += x[j] * f[jx + i - j] - #| j += 1 - #| } - #| q[i] = fw - #| i += 1 - #| } - #| jz += k - #| recompute = true // Continue to recompute - #| continue - #| } - #| } // Skip the rest of the loop and recompute - #| if z == 0.0 { - #| jz -= 1 - #| q0 -= 24 - #| while iq[jz] == 0 { - #| jz -= 1 - #| q0 -= 24 - #| } - #| } else { - #| z = scalbn(z, -q0) - #| if z >= two24 { - #| fw = (twon24 * z).floor() - #| iq[jz] = (z - two24 * fw).to_int() - #| jz += 1 - #| q0 += 24 - #| iq[jz] = fw.to_int() - #| } else { - #| iq[jz] = z.to_int() - #| } - #| } - #| fw = scalbn(1.0, q0) - #| i = jz - #| while i >= 0 { - #| q[i] = fw * iq[i].to_double() - #| fw *= twon24 - #| i -= 1 - #| } - #| i = jz - #| while i >= 0 { - #| fw = 0.0 - #| k = 0 - #| while k <= jp && k <= jz - i { - #| fw += pi_over_2[k] * q[i + k] - #| k += 1 - #| } - #| fq[jz - i] = fw - #| i -= 1 - #| } - #| match prec { - #| 0 => { - #| fw = 0.0 - #| i = jz - #| while i >= 0 { - #| fw += fq[i] - #| i -= 1 - #| } - #| y[0] = if ih == 0 { fw } else { -fw } - #| } - #| 1 | 2 => { - #| fw = 0.0 - #| i = jz - #| while i >= 0 { - #| fw += fq[i] - #| i -= 1 - #| } - #| y[0] = if ih == 0 { fw } else { -fw } - #| fw = fq[0] - fw - #| i = 1 - #| while i <= jz { - #| fw += fq[i] - #| i += 1 - #| } - #| y[1] = if ih == 0 { fw } else { -fw } - #| } - #| 3 => { - #| i = jz - #| while i > 0 { - #| fw = fq[i - 1] + fq[i] - #| fq[i] += fq[i - 1] - fw - #| fq[i - 1] = fw - #| i -= 1 - #| } - #| i = jz - #| while i > 1 { - #| fw = fq[i - 1] + fq[i] - #| fq[i] += fq[i - 1] - fw - #| fq[i - 1] = fw - #| i -= 1 - #| } - #| fw = 0.0 - #| i = jz - #| while i >= 2 { - #| fw += fq[i] - #| i -= 1 - #| } - #| if ih == 0 { - #| y[0] = fq[0] - #| y[1] = fq[1] - #| y[2] = fw - #| } else { - #| y[0] = -fq[0] - #| y[1] = -fq[1] - #| y[2] = -fw - #| } - #| } - #| _ => () - #| } - #| } - #| n & 7 - #|} - #|fn __kernel_sin(x : Double, y : Double, iy : Int) -> Double { - #| let s1 = -1.66666666666666324348e-01 - #| let s2 = 8.33333333332248946124e-03 - #| let s3 = -1.98412698298579493134e-04 - #| let s4 = 2.75573137070700676789e-06 - #| let s5 = -2.50507602534068634195e-08 - #| let s6 = 1.58969099521155010221e-10 - #| let mut z = 0.0 - #| let mut r = 0.0 - #| let mut v = 0.0 - #| let ix = get_high_word(x) & 0x7fffffff - #| if ix < 0x3e400000 { - #| if x.to_int() == 0 { - #| return x - #| } - #| } - #| z = x * x - #| v = z * x - #| r = s2 + z * (s3 + z * (s4 + z * (s5 + z * s6))) - #| if iy == 0 { - #| x + v * (s1 + z * r) - #| } else { - #| x - (z * (0.5 * y - v * r) - y - v * s1) - #| } - #|} - #|fn __kernel_cos(x : Double, y : Double) -> Double { - #| let one = 1.00000000000000000000e+00 - #| let c1 = 4.16666666666666019037e-02 - #| let c2 = -1.38888888888741095749e-03 - #| let c3 = 2.48015872894767294178e-05 - #| let c4 = -2.75573143513906633035e-07 - #| let c5 = 2.08757232129817482790e-09 - #| let c6 = -1.13596475577881948265e-11 - #| let mut a = 0.0 - #| let mut hz = 0.0 - #| let mut z = 0.0 - #| let mut r = 0.0 - #| let mut qx = 0.0 - #| let ix = get_high_word(x) & 0x7fffffff - #| if ix < 0x3e400000 { - #| if x.to_int() == 0 { - #| return one - #| } - #| } - #| z = x * x - #| r = z * (c1 + z * (c2 + z * (c3 + z * (c4 + z * (c5 + z * c6))))) - #| if ix < 0x3fd33333 { - #| return one - (0.5 * z - (z * r - x * y)) - #| } else { - #| if ix > 0x3fe90000 { - #| qx = 0.28125 - #| } else { - #| qx = ((ix - 0x00200000).to_uint64() << 32).reinterpret_as_double() - #| } - #| hz = 0.5 * z - qx - #| a = one - qx - #| return a - (hz - (z * r - x * y)) - #| } - #|} - #|fn __kernal_tan(x : Double, y : Double, iy : Int) -> Double { - #| let one = 1.0 - #| let pio4 = 7.85398163397448278999e-01 - #| let pio4lo = 3.06161699786838301793e-17 - #| let mut x = x - #| let mut y = y - #| let mut z = 0.0 - #| let mut r = 0.0 - #| let mut v = 0.0 - #| let mut w = 0.0 - #| let mut s = 0.0 - #| let t : ReadOnlyArray[Double] = [ - #| 3.33333333333334091986e-01, // 3FD55555, 55555563 */ - #| 1.33333333333201242699e-01, // 3FC11111, 1110FE7A */ - #| 5.39682539762260521377e-02, // 3FABA1BA, 1BB341FE */ - #| 2.18694882948595424599e-02, // 3F9664F4, 8406D637 */ - #| 8.86323982359930005737e-03, // 3F8226E3, E96E8493 */ - #| 3.59207910759131235356e-03, // 3F6D6D22, C9560328 */ - #| 1.45620945432529025516e-03, // 3F57DBC8, FEE08315 */ - #| 5.88041240820264096874e-04, // 3F4344D8, F2F26501 */ - #| 2.46463134818469906812e-04, // 3F3026F7, 1A8D1068 */ - #| 7.81794442939557092300e-05, // 3F147E88, A03792A6 */ - #| 7.14072491382608190305e-05, // 3F12B80F, 32F0A7E9 */ - #| -1.85586374855275456654e-05, // BEF375CB, DB605373 */ - #| 2.59073051863633712884e-05, // 3EFB2A70, 74BF7AD4 */ - #| 1.00000000000000000000e+00, // 3FF00000, 00000000 (one) */ - #| 7.85398163397448278999e-01, // 3FE921FB, 54442D18 (pio4) */ - #| 3.06161699786838301793e-17, // 3C81A626, 33145C07 (pio4lo) */ - #| ] - #| let hx = get_high_word(x).reinterpret_as_int() - #| let ix = hx & 0x7fffffff - #| if ix < 0x3e300000 { - #| if x.to_int() == 0 { - #| if (ix | get_low_word(x).reinterpret_as_int() | (iy + 1)) == 0 { - #| return one / x.abs() - #| } else if iy == 1 { - #| return x - #| } else { - #| w = x + y - #| z = w - #| z = set_low_word(z, 0) - #| v = y - (z - x) - #| let a = -one / w - #| let mut t = a - #| t = set_low_word(t, 0) - #| s = one + t * z - #| return t + a * (s + t * v) - #| } - #| } - #| } - #| if ix >= 0x3fe59428 { - #| if hx < 0 { - #| x = -x - #| y = -y - #| } - #| z = pio4 - x - #| w = pio4lo - y - #| x = z + w - #| y = 0.0 - #| } - #| z = x * x - #| w = z * z - #| r = t[1] + w * (t[3] + w * (t[5] + w * (t[7] + w * (t[9] + w * t[11])))) - #| v = z * - #| (t[2] + w * (t[4] + w * (t[6] + w * (t[8] + w * (t[10] + w * t[12]))))) - #| s = z * x - #| r = y + z * (s * (r + v) + y) - #| r += t[0] * s - #| w = x + r - #| if ix >= 0x3fe59428 { - #| v = iy.to_double() - #| return (1 - ((hx >> 30) & 2)).to_double() * - #| (v - 2.0 * (x - (w * w / (w + v) - r))) - #| } - #| if iy == 1 { - #| w - #| } else { - #| z = w - #| z = set_low_word(z, 0) - #| v = r - (z - x) - #| let a = -1.0 / w - #| let mut t = a - #| t = set_low_word(t, 0) - #| s = 1.0 + t * z - #| t + a * (s + t * v) - #| } - #|} - ), - "trig_double_sincos_native.mbt": ( - #|pub extern "C" fn sin(x : Double) -> Double = "sin" - #|pub extern "C" fn cos(x : Double) -> Double = "cos" - ), - "trig_double_sincos_non_native_or_js.mbt": ( - #|pub fn sin(x : Double) -> Double { - #| if x.is_inf() || x.is_nan() { - #| return @double.not_a_number - #| } - #| let y = [0.0, 0.0] - #| let z = 0.0 - #| if x.abs() <= PI_OVER_4 { - #| return __kernel_sin(x, z, 0) - #| } else { - #| let n = rem_pio2(x, y) - #| match n & 3 { - #| 0 => __kernel_sin(y[0], y[1], 1) - #| 1 => __kernel_cos(y[0], y[1]) - #| 2 => -__kernel_sin(y[0], y[1], 1) - #| _ => -__kernel_cos(y[0], y[1]) - #| } - #| } - #|} - #|pub fn cos(x : Double) -> Double { - #| if x.is_inf() || x.is_nan() { - #| return @double.not_a_number - #| } - #| let y = [0.0, 0.0] - #| let z = 0.0 - #| if x.abs() <= PI_OVER_4 { - #| return __kernel_cos(x, z) - #| } else { - #| let n = rem_pio2(x, y) - #| match n & 3 { - #| 0 => __kernel_cos(y[0], y[1]) - #| 1 => -__kernel_sin(y[0], y[1], 1) - #| 2 => -__kernel_cos(y[0], y[1]) - #| _ => __kernel_sin(y[0], y[1], 1) - #| } - #| } - #|} - ), - "utils.mbt": ( - #|fn abs(x : Double) -> Double { - #| if x < 0.0 { - #| -x - #| } else { - #| x - #| } - #|} - #|let two_over_pi : ReadOnlyArray[Int] = [ - #| 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 0x95993C, 0x439041, - #| 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, - #| 0xFE1DEB, 0x1CB129, 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, - #| 0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, 0x97FFDE, 0x05980F, - #| 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, - #| 0x7527BA, 0xC7EBE5, 0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, - #| 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, 0x91615E, 0xE61B08, - #| 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, 0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, - #| 0x60E27B, 0xC08C6B, - #|] - #|let pi_over_2 : ReadOnlyArray[Double] = [ - #| 1.57079625129699707031e+00, // 0x3FF921FB, 0x40000000 */ - #| 7.54978941586159635335e-08, // 0x3E74442D, 0x00000000 */ - #| 5.39030252995776476554e-15, // 0x3CF84698, 0x80000000 */ - #| 3.28200341580791294123e-22, // 0x3B78CC51, 0x60000000 */ - #| 1.27065575308067607349e-29, // 0x39F01B83, 0x80000000 */ - #| 1.22933308981111328932e-36, // 0x387A2520, 0x40000000 */ - #| 2.73370053816464559624e-44, // 0x36E38222, 0x80000000 */ - #| 2.16741683877804819444e-51, // 0x3569F31D, 0x00000000 */ - #|] - #|let npio2_hw : ReadOnlyArray[Int] = [ - #| 0x3FF921FB, 0x400921FB, 0x4012D97C, 0x401921FB, 0x401F6A7A, 0x4022D97C, 0x4025FDBB, - #| 0x402921FB, 0x402C463A, 0x402F6A7A, 0x4031475C, 0x4032D97C, 0x40346B9C, 0x4035FDBB, - #| 0x40378FDB, 0x403921FB, 0x403AB41B, 0x403C463A, 0x403DD85A, 0x403F6A7A, 0x40407E4C, - #| 0x4041475C, 0x4042106C, 0x4042D97C, 0x4043A28C, 0x40446B9C, 0x404534AC, 0x4045FDBB, - #| 0x4046C6CB, 0x40478FDB, 0x404858EB, 0x404921FB, - #|] - #|const PI_OVER_4 : Double = 0.785398163397448309616 - #|const PIO2_1 : Double = 1.5707963267341256e+00 // 0x3FF921FB, 0x54400000 */ - #|const PIO2_1T : Double = 6.0771005065061922e-11 // 0x3DD0B461, 0x1A600000 */ - #|const PIO2_2 : Double = 6.0771005063039660e-11 // 0x3DD0B461, 0x1A600000 */ - #|const PIO2_2T : Double = 2.0222662487959506e-21 // 0x3BA3198A, 0x2E037073 */ - #|const PIO2_3 : Double = 2.0222662487111665e-21 // 0x3BA3198A, 0x2E037073 */ - #|const PIO2_3T : Double = 8.4784276603688996e-32 // 0x397B839A, 0x252049C1 */ - #|const INV_PIO2 : Double = 6.3661977236758138e-01 // 0x3FE45F30, 0x6DC9C883 */ - #|const HALF : Double = 0.5 - #|const TWO24 : Double = 16777216.0 // 0x41700000, 0x00000000 */ - #|fn set_low_word(d : Double, v : UInt) -> Double { - #| let bits : UInt64 = d.reinterpret_as_uint64() - #| let bits = bits & 0xFFFF_FFFF_0000_0000 - #| let bits = bits | v.to_uint64() - #| bits.reinterpret_as_double() - #|} - #|fn set_high_word(d : Double, v : UInt) -> Double { - #| let bits : UInt64 = d.reinterpret_as_uint64() - #| let bits = bits & 0x0000_0000_FFFF_FFFF - #| let bits = bits | (v.to_uint64() << 32) - #| bits.reinterpret_as_double() - #|} - #|fn get_high_word(x : Double) -> UInt { - #| (x.reinterpret_as_uint64() >> 32).to_uint() - #|} - #|fn get_low_word(x : Double) -> UInt { - #| x.reinterpret_as_uint64().to_uint() - #|} - #|const SQRT2 = 1.41421356237309504880168872420969807856967187537694807317667974 - #|const LN2 = 0.693147180559945309417232121458176568075500134360255254120680009 - #|const LN2_HI = 6.93147180369123816490e-01 // 3fe62e42 fee00000 - #|const LN2_LO = 1.90821492927058770002e-10 // 3dea39ef 35793c76 - #|fn normalize(f : Double) -> (Double, Int) { - #| if f.abs() < @double.min_positive { - #| return (f * (1L << 52).to_double(), -52) - #| } - #| (f, 0) - #|} - #|fn frexp(f : Double) -> (Double, Int) { - #| if f == 0.0 || f.is_inf() || f.is_nan() { - #| return (f, 0) - #| } - #| let (norm_f, exp) = normalize(f) - #| let u = norm_f.reinterpret_as_uint64() - #| let exp = exp + ((u >> 52) & 0x7FF).to_int() - 1022 - #| let frac = ((u & (0x7FFUL << 52).lnot()) | (1022UL << 52)).reinterpret_as_double() - #| return (frac, exp) - #|} - ), - }, + "algebraic.mbt": ( + #|pub fn cbrtf(x : Float) -> Float { + #| let b1 : UInt = 709958130 // B1 = (127-127.0/3-0.03306235651)*2**23 */ + #| let b2 : UInt = 642849266 // B2 = (127-127.0/3-24/3-0.03306235651)*2**23 */ + #| let mut ui : UInt = x.reinterpret_as_uint() + #| let mut hx : UInt = ui & 0x7fffffff + #| if hx >= 0x7f800000 { + #| return x + x + #| } + #| if hx < 0x00800000 { + #| if hx == 0 { + #| return x + #| } // cbrt(+-0) is itx + #| ui = (x * (0x1.0p24 : Float)).reinterpret_as_uint() + #| hx = ui & 0x7fffffff + #| hx = hx / 3 + b2 + #| } else { + #| hx = hx / 3 + b1 + #| } + #| ui = ui & 0x80000000 + #| ui = ui | hx + #| let dx = x.to_double() + #| let t = Float::reinterpret_from_uint(ui).to_double() + #| let r = t * t * t + #| let t = t * (dx + dx + r) / (dx + r + r) + #| let r = t * t * t + #| let t = t * (dx + dx + r) / (dx + r + r) + #| Float::from_double(t) + #|} + #|pub fn hypotf(x : Float, y : Float) -> Float { + #| let epsilon : Float = 1.1920928955078125e-7 + #| let x = x.abs() + #| let y = y.abs() + #| if x.is_inf() || y.is_inf() { + #| return @float.infinity + #| } + #| let (x, y) = if y > x { (y, x) } else { (x, y) } + #| if x * epsilon >= y { + #| return x + #| } + #| let rat = y / x + #| x * (rat * rat + 1.0).sqrt() + #|} + ), + "algebraic_double_js.mbt": ( + #|pub fn cbrt(x : Double) -> Double = "Math" "cbrt" + #|pub fn hypot(x : Double, y : Double) -> Double = "Math" "hypot" + ), + "algebraic_double_nonjs.mbt": ( + #|pub fn cbrt(x : Double) -> Double { + #| if x.is_inf() || x.is_nan() || x == 0.0 { + #| return x + #| } + #| let b1 : UInt = 715094163 // B1 = (682-0.03306235651)*2**20 + #| let b2 : UInt = 696219795 // B2 = (664-0.03306235651)*2**20 + #| let c = 5.42857142857142815906e-01 // 19/35 = 0x3FE15F15, 0xF15F15F1 + #| let d = -7.05306122448979611050e-01 // -864/1225 = 0xBFE691DE, 0x2532C834 + #| let e = 1.41428571428571436819e+00 // 99/70 = 0x3FF6A0EA, 0x0EA0EA0F + #| let f = 1.60714285714285720630e+00 // 45/28 = 0x3FF9B6DB, 0x6DB6DB6E + #| let g = 3.57142857142857150787e-01 // 5/14 = 0x3FD6DB6D, 0xB6DB6DB7 + #| let hx = get_high_word(x).reinterpret_as_int() + #| let sign = if x < 0.0 { true } else { false } + #| let x = abs(x) + #| let t = if hx < 0x00100000 { + #| let t : UInt64 = 0x43500000_00000000 + #| let t : Double = t.reinterpret_as_double() + #| let t = t * x + #| set_high_word(0, get_high_word(t) / 3 + b2) + #| } else { + #| set_high_word(0, hx.reinterpret_as_uint() / 3 + b1) + #| } + #| let r = t * t / x + #| let s = c + r * t + #| let t = t * (g + f / (s + e + d / s)) + #| let t = set_high_word(0, get_high_word(t) + 0x00000001) + #| let s = t * t + #| let r = x / s + #| let w = t + t + #| let r = (r - t) / (w + r) + #| let t = t + t * r + #| if sign { + #| -t + #| } else { + #| t + #| } + #|} + #|pub fn hypot(x : Double, y : Double) -> Double { + #| if x.is_nan() || y.is_nan() { + #| return @double.not_a_number + #| } + #| if x.is_inf() || y.is_inf() { + #| return @double.infinity + #| } + #| let x = x.abs() + #| let y = y.abs() + #| let double_epsilon : Double = 0x0.0000000000001P-1022 + #| let (x, y) = if y > x { (y, x) } else { (x, y) } + #| if x * double_epsilon >= y { + #| return x + #| } + #| let r = y / x + #| x * (1.0 + r * r).sqrt() + #|} + ), + "deprecated.mbt": ( + #|#deprecated("Use `PI` instead") + #|pub let pi = 0x3.243F6A8885A308CA8A54 + #|#deprecated("Use @cmp.maximum instead") + #|pub fn[T : Compare] maximum(x : T, y : T) -> T { + #| if x > y { + #| x + #| } else { + #| y + #| } + #|} + #|#deprecated("Use @cmp.minimum instead") + #|pub fn[T : Compare] minimum(x : T, y : T) -> T { + #| if x > y { + #| y + #| } else { + #| x + #| } + #|} + ), + "exp.mbt": ( + #|fn top12(x : Float) -> UInt { + #| x.reinterpret_as_uint() >> 20 + #|} + #|fn __math_xflowf(sign : UInt, y : Float) -> Float { + #| return (if sign != 0 { -y } else { y }) * y + #|} + #|fn __math_oflowf(sign : UInt) -> Float { + #| return __math_xflowf(sign, 0x1.0p97) + #|} + #|fn __math_uflowf(sign : UInt) -> Float { + #| return __math_xflowf(sign, 0x1.0p-95) + #|} + #|let exp2f_table_bits = 5 + #|priv struct Exp2fData { + #| tab : FixedArray[UInt64] + #| shift : Double + #| invln2_scaled : Double + #| poly_scaled : FixedArray[Double] + #|} + #|let expf_n : UInt64 = (1 << exp2f_table_bits).to_uint64() + #|let exp2f_data_n : Double = (1 << exp2f_table_bits).to_double() + #|let exp2f_data : Exp2fData = { + #| tab: [ + #| 0x3ff0000000000000, 0x3fefd9b0d3158574, 0x3fefb5586cf9890f, 0x3fef9301d0125b51, + #| 0x3fef72b83c7d517b, 0x3fef54873168b9aa, 0x3fef387a6e756238, 0x3fef1e9df51fdee1, + #| 0x3fef06fe0a31b715, 0x3feef1a7373aa9cb, 0x3feedea64c123422, 0x3feece086061892d, + #| 0x3feebfdad5362a27, 0x3feeb42b569d4f82, 0x3feeab07dd485429, 0x3feea47eb03a5585, + #| 0x3feea09e667f3bcd, 0x3fee9f75e8ec5f74, 0x3feea11473eb0187, 0x3feea589994cce13, + #| 0x3feeace5422aa0db, 0x3feeb737b0cdc5e5, 0x3feec49182a3f090, 0x3feed503b23e255d, + #| 0x3feee89f995ad3ad, 0x3feeff76f2fb5e47, 0x3fef199bdd85529c, 0x3fef3720dcef9069, + #| 0x3fef5818dcfba487, 0x3fef7c97337b9b5f, 0x3fefa4afa2a490da, 0x3fefd0765b6e4540, + #| ], + #| shift: 0x1.8p+52, + #| invln2_scaled: 0x1.71547652b82fep+0 * exp2f_data_n, + #| poly_scaled: [ + #| 0x1.c6af84b912394p-5 / exp2f_data_n / exp2f_data_n / exp2f_data_n, + #| 0x1.ebfce50fac4f3p-3 / exp2f_data_n / exp2f_data_n, + #| 0x1.62e42ff0c52d6p-1 / exp2f_data_n, + #| ], + #|} + #|pub fn expf(x : Float) -> Float { + #| let xd = x.to_double() + #| let abstop = top12(x) & 0x7ff + #| if abstop >= top12(88.0) { + #| if x.reinterpret_as_uint() == @float.neg_infinity.reinterpret_as_uint() { + #| return 0.0 + #| } + #| if abstop >= top12(@float.infinity) { + #| return x + x + #| } + #| if x > 0x1.62e42ep6 { + #| return __math_oflowf(0) + #| } + #| if x < -0x1.9fe368p6 { + #| return __math_uflowf(0) + #| } + #| } + #| let z = exp2f_data.invln2_scaled * xd + #| let kd = z + exp2f_data.shift + #| let ki = kd.reinterpret_as_uint64() + #| let kd = kd - exp2f_data.shift + #| let r = z - kd + #| let t = exp2f_data.tab[(ki % expf_n).to_int()] + #| let t = t + (ki << (52 - exp2f_table_bits)) + #| let s = t.reinterpret_as_double() + #| let z = exp2f_data.poly_scaled[0] * r + exp2f_data.poly_scaled[1] + #| let r2 = r * r + #| let y = exp2f_data.poly_scaled[2] * r + 1 + #| let y = z * r2 + y + #| let y = y * s + #| Float::from_double(y) + #|} + #|pub fn expm1f(x : Float) -> Float { + #| let float_ln2_hi : Float = 6.9314575195e-01 // 0x3f317200 + #| let float_ln2_lo : Float = 1.4286067653e-06 // 0x35bfbe8e + #| let inv_ln2 : Float = 1.4426950216e+00 // 0x3fb8aa3b + #| let mut x = x + #| let q1 : Float = -3.3333212137e-2 // -0x888868.0p-28 + #| let q2 : Float = 1.5807170421e-3 // 0xcf3010.0p-33 + #| let mut hx = x.reinterpret_as_uint() + #| let sign = hx >> 31 != 0 + #| hx = hx & 0x7fffffff + #| if hx >= 0x4195b844 { + #| if hx > 0x7f800000 { + #| return x + #| } + #| if sign { + #| return -1.0 + #| } + #| if hx > 0x42b17217 { + #| x *= (0x1.0p127 : Float) + #| return x + #| } + #| } + #| let mut k : Int = 0 + #| let mut hi : Float = 0 + #| let mut lo : Float = 0 + #| let mut c : Float = 0 + #| if hx > 0x3eb17218 { + #| if hx < 0x3F851592 { + #| if !sign { + #| hi = x - float_ln2_hi + #| lo = float_ln2_lo + #| k = 1 + #| } else { + #| hi = x + float_ln2_hi + #| lo = -float_ln2_lo + #| k = -1 + #| } + #| } else { + #| k = (inv_ln2 * x + (if sign { -0.5 } else { 0.5 })).to_int() + #| hi = x - Float::from_int(k) * float_ln2_hi // t*ln2_hi is exact here + #| lo = Float::from_int(k) * float_ln2_lo + #| } + #| x = hi - lo + #| c = hi - x - lo + #| } else if hx < 0x33000000 { + #| return x + #| } else { + #| k = 0 + #| } + #| let hfx = (0.5 : Float) * x + #| let hxs = x * hfx + #| let r1 = (1.0 : Float) + hxs * (q1 + hxs * q2) + #| let t = (3.0 : Float) - r1 * hfx + #| let mut e = hxs * ((r1 - t) / ((6.0 : Float) - x * t)) + #| if k == 0 { + #| return x - (x * e - hxs) + #| } + #| e = x * (e - c) - c + #| e -= hxs + #| if k == -1 { + #| return (0.5 : Float) * (x - e) - 0.5 + #| } + #| if k == 1 { + #| if x < -0.25 { + #| return -(2.0 : Float) * (e - (x + 0.5)) + #| } + #| return (1.0 : Float) + (2.0 : Float) * (x - e) + #| } + #| let twopk = Float::reinterpret_from_int((0x7f + k) << 23) // 2^k + #| if !(k is (0..=56)) { + #| let mut y = x - e + 1.0 + #| if k == 128 { + #| y = y * 2.0 * (0x1.0p127 : Float) + #| } else { + #| y = y * twopk + #| } + #| return y - 1.0 + #| } + #| let uf = Float::reinterpret_from_int((0x7f - k) << 23) // 2^-k + #| if k < 23 { + #| (x - e + ((1.0 : Float) - uf)) * twopk + #| } else { + #| (x - (e + uf) + 1.0) * twopk + #| } + #|} + ), + "exp_double_js.mbt": ( + #|pub fn exp(x : Double) -> Double = "Math" "exp" + #|pub fn expm1(x : Double) -> Double = "Math" "expm1" + ), + "exp_double_nonjs.mbt": ( + #|pub fn exp(x : Double) -> Double { + #| fn get_high_word(x : Double) -> UInt { + #| (x.reinterpret_as_uint64() >> 32).to_uint() + #| } + #| fn get_low_word(x : Double) -> UInt { + #| x.reinterpret_as_uint64().to_uint() + #| } + #| fn insert_words(ix0 : UInt64, ix1 : UInt64) -> Double { + #| let mut bits : UInt64 = 0 + #| bits = bits | (ix0 << 32) + #| bits = bits | ix1 + #| bits.reinterpret_as_double() + #| } + #| let ori_x = x + #| let mut x = x + #| let one = 1.0 + #| let halF : ReadOnlyArray[Double] = [0.5, -0.5] + #| let o_threshold = 7.09782712893383973096e+02 + #| let u_threshold = -7.45133219101941108420e+02 + #| let ln2HI : ReadOnlyArray[Double] = [ + #| 6.93147180369123816490e-01, -6.93147180369123816490e-01, + #| ] + #| let ln2LO : ReadOnlyArray[Double] = [ + #| 1.90821492927058770002e-10, -1.90821492927058770002e-10, + #| ] + #| let invln2 = 1.44269504088896338700e+00 + #| let p1 = 1.66666666666666019037e-01 + #| let p2 = -2.77777777770155933842e-03 + #| let p3 = 6.61375632143793436117e-05 + #| let p4 = -1.65339022054652515390e-06 + #| let p5 = 4.13813679705723846039e-08 + #| let e = 2.718281828459045 + #| let mut hi = 0.0 + #| let mut lo = 0.0 + #| let huge = 1.0e+300 + #| let twom1000 = 9.33263618503218878990e-302 + #| let two1023 = 8.988465674311579539e307 + #| let mut k : Int = 0 + #| let mut hx : UInt = get_high_word(ori_x) + #| let xsb : Int = ((hx >> 31) & 1).reinterpret_as_int() + #| hx = hx & 0x7FFFFFFF + #| if hx >= 0x40862E42 { + #| if hx >= 0x7FF00000 { + #| let lx : UInt = get_low_word(ori_x) + #| if ((hx & 0xFFFFF) | lx) != 0 { + #| return ori_x + ori_x + #| } else if xsb == 0 { + #| return ori_x + #| } else { + #| return 0.0 + #| } + #| } + #| if ori_x > o_threshold { + #| return huge * huge + #| } + #| if ori_x < u_threshold { + #| return twom1000 * twom1000 + #| } + #| } + #| if hx > 0x3FD62E42 { + #| if hx < 0x3FF0A2B2 { + #| if ori_x == 1.0 { + #| return e + #| } + #| hi = ori_x - ln2HI[xsb] + #| lo = ln2LO[xsb] + #| k = 1 - xsb - xsb + #| } else { + #| k = (invln2 * ori_x + halF[xsb]).to_int() + #| let t = k.to_double() + #| hi = ori_x - t * ln2HI[0] + #| lo = t * ln2LO[0] + #| } + #| x = hi - lo + #| } else if hx < 0x3E300000 { + #| if huge + x > one { + #| return one + x + #| } + #| } else { + #| k = 0 + #| } + #| let t = x * x + #| let twopk = if k >= -1021 { + #| insert_words( + #| (0x3FF00000 + (k.reinterpret_as_uint() << 20).reinterpret_as_int()) + #| .to_int64() + #| .reinterpret_as_uint64(), + #| 0, + #| ) + #| } else { + #| insert_words( + #| 0x3FF00000UL + ((k + 1000).reinterpret_as_uint() << 20).to_uint64(), + #| 0, + #| ) + #| } + #| let c = x - t * (p1 + t * (p2 + t * (p3 + t * (p4 + t * p5)))) + #| if k == 0 { + #| return one - (x * c / (c - 2.0) - x) + #| } + #| let y = one - (lo - x * c / (2.0 - c) - hi) + #| if k >= -1021 { + #| if k == 1024 { + #| return y * 2.0 * two1023 + #| } else { + #| return y * twopk + #| } + #| } else { + #| return y * twopk * twom1000 + #| } + #|} + #|pub fn expm1(x : Double) -> Double { + #| if x.is_nan() { + #| return @double.not_a_number + #| } + #| let o_threshold = 7.09782712893383973096e+02 + #| if x > o_threshold { + #| return @double.infinity + #| } + #| if x.is_inf() { + #| return -1.0 + #| } + #| let huge = 1.0e+300 + #| let tiny = 1.0e-300 + #| let ln2_hi = 6.93147180369123816490e-01 + #| let ln2_lo = 1.90821492927058770002e-10 + #| let invln2 = 1.44269504088896338700e+00 + #| let q1 = -3.33333333333331316428e-02 + #| let q2 = 1.58730158725481460165e-03 + #| let q3 = -7.93650757867487942473e-05 + #| let q4 = 4.00821782732936239552e-06 + #| let q5 = -2.01099218183624371326e-07 + #| let mut x = x + #| let mut hx = get_high_word(x) + #| let xsb : Int = (hx & 0x80000000).reinterpret_as_int() + #| let mut y : Double = if xsb == 0 { x } else { -x } + #| hx = hx & 0x7fffffff + #| if hx >= 0x4043687A { + #| if xsb != 0 { + #| if x + tiny < 0.0 { + #| return tiny - 1.0 + #| } + #| } + #| } + #| let mut hi = 0.0 + #| let mut lo = 0.0 + #| let mut k = 0 + #| let mut c = 0.0 + #| let mut t = 0.0 + #| if hx > 0x3fd62e42 { + #| if hx < 0x3FF0A2B2 { + #| hi = if xsb == 0 { x - ln2_hi } else { x + ln2_hi } + #| lo = if xsb == 0 { ln2_lo } else { -ln2_lo } + #| k = if xsb == 0 { 1 } else { -1 } + #| } else { + #| k = (invln2 * x + (if xsb == 0 { 0.5 } else { -0.5 })).to_int() + #| t = k.to_double() + #| hi = x - t * ln2_hi + #| lo = t * ln2_lo + #| } + #| x = hi - lo + #| c = hi - x - lo + #| } else if hx < 0x3c900000 { + #| t = huge + x + #| return x - (t - (huge + x)) + #| } else { + #| k = 0 + #| } + #| let hfx : Double = 0.5 * x + #| let hxs : Double = x * hfx + #| let r1 : Double = 1.0 + + #| hxs * (q1 + hxs * (q2 + hxs * (q3 + hxs * (q4 + hxs * q5)))) + #| let t : Double = 3.0 - r1 * hfx + #| let e : Double = hxs * ((r1 - t) / (6.0 - x * t)) + #| if k == 0 { + #| return x - (x * e - hxs) + #| } else { + #| let e : Double = x * (e - c) - c + #| let e : Double = e - hxs + #| if k == -1 { + #| return 0.5 * (x - e) - 0.5 + #| } + #| if k == 1 { + #| return if x < -0.25 { + #| -2.0 * (e - (x + 0.5)) + #| } else { + #| 1.0 + 2.0 * (x - e) + #| } + #| } + #| if k <= -2 || k > 56 { + #| y = 1.0 - (e - x) + #| y = set_high_word(y, get_high_word(y) + (k << 20).reinterpret_as_uint()) + #| return y - 1.0 + #| } + #| let mut t : Double = 1.0 + #| if k < 20 { + #| t = set_high_word(0, (0x3ff00000 - (0x200000 >> k)).reinterpret_as_uint()) + #| y = t - (e - x) + #| y = set_high_word(y, get_high_word(y) + (k << 20).reinterpret_as_uint()) + #| } else { + #| t = set_high_word(0, ((0x3ff - k) << 20).reinterpret_as_uint()) + #| y = x - (e + t) + 1.0 + #| y = set_high_word(y, get_high_word(y) + (k << 20).reinterpret_as_uint()) + #| } + #| } + #| y + #|} + ), + "hyperbolic.mbt": ( + #|fn k_expo2f(x : Float) -> Float { + #| let k = 235 + #| let k_ln2 = Float::reinterpret_from_int(0x4322e3bc) + #| let scale = Float::reinterpret_from_int((0x7f + k / 2) << 23) + #| expf(x - k_ln2) * scale * scale + #|} + #|pub fn sinhf(x : Float) -> Float { + #| let mut h : Float = 0.5 + #| let mut ix = x.reinterpret_as_uint() + #| if ix >> 31 != 0 { + #| h = -h + #| } + #| ix = ix & 0x7fffffff + #| let absx = Float::reinterpret_from_uint(ix) + #| let w = ix + #| if w < 0x42b17217 { + #| let t = expm1f(absx) + #| if w < 0x3f800000 { + #| if w < 0x3f800000U - (12U << 23) { + #| return x + #| } + #| return h * ((2.0 : Float) * t - t * t / (t + 1.0)) + #| } + #| return h * (t + t / (t + 1.0)) + #| } + #| h * k_expo2f(absx) * 2.0 + #|} + #|pub fn coshf(x : Float) -> Float { + #| let mut x = x + #| let mut ix = x.reinterpret_as_uint() + #| ix = ix & 0x7fffffff + #| x = Float::reinterpret_from_uint(ix) + #| let w = ix + #| if w < 0x3f317217 { + #| if w < 0x3f800000U - (12U << 23) { + #| return 1.0 + #| } + #| let t = expm1f(x) + #| return (1.0 : Float) + t * t / ((2.0 : Float) * (t + 1.0)) + #| } + #| if w < 0x42b17217 { + #| let t = expf(x) + #| return (t + (1.0 : Float) / t) * 0.5 + #| } + #| k_expo2f(x) + #|} + #|pub fn tanhf(x : Float) -> Float { + #| let mut ix = x.reinterpret_as_uint() + #| let sign = ix >> 31 != 0 + #| ix = ix & 0x7fffffff + #| let x = Float::reinterpret_from_uint(ix) + #| let w = ix + #| let tt = if w > 0x3f0c9f54 { + #| if w > 0x41200000 { + #| (1.0 : Float) + (0.0 : Float) / x + #| } else { + #| let t = expm1f(x * 2.0) + #| (1.0 : Float) - (2.0 : Float) / (t + 2.0) + #| } + #| } else if w > 0x3e82c578 { + #| let t = expm1f(x * 2.0) + #| t / (t + 2.0) + #| } else if w >= 0x00800000 { + #| let t = expm1f(x * -2.0) + #| -t / (t + 2.0) + #| } else { + #| x + #| } + #| if sign { + #| -tt + #| } else { + #| tt + #| } + #|} + #|pub fn asinhf(x : Float) -> Float { + #| let u = x.reinterpret_as_uint() + #| let i = u & 0x7fffffff + #| let sign = u >> 31 != 0 + #| let ln2 : Float = 0.693147180559945309417232121458176568 + #| let x = Float::reinterpret_from_uint(i) + #| let x = if i >= 0x3f800000U + (12U << 23) { + #| lnf(x) + ln2 + #| } else if i >= 0x3f800000U + (1U << 23) { + #| lnf(x * 2.0 + (1.0 : Float) / ((x * x + 1.0).sqrt() + x)) + #| } else if i >= 0x3f800000U - (12U << 23) { + #| ln_1pf(x + x * x / ((x * x + 1.0).sqrt() + 1.0)) + #| } else { + #| x + #| } + #| if sign { + #| -x + #| } else { + #| x + #| } + #|} + #|pub fn acoshf(x : Float) -> Float { + #| let ln2 : Float = 693147180559945309417232121458176568 + #| let u = x.reinterpret_as_uint() + #| let a = u & 0x7fffffffU + #| if a < 0x3f800000U + (1U << 23) { + #| return ln_1pf( + #| x - 1.0 + ((x - 1.0) * (x - 1.0) + (2.0 : Float) * (x - 1.0)).sqrt(), + #| ) + #| } + #| if a < 0x3f800000U + (12U << 23) { + #| return lnf(x * 2.0 - (1.0 : Float) / (x + (x * x - 1.0).sqrt())) + #| } + #| return lnf(x) + ln2 + #|} + #|pub fn atanhf(x : Float) -> Float { + #| let u = x.reinterpret_as_uint() + #| let sign = u >> 31 != 0 + #| let u = u & 0x7fffffff + #| let x = Float::reinterpret_from_uint(u) + #| let x = if u < 0x3f800000U - (1U << 23) { + #| if u < 0x3f800000U - (32U << 23) { + #| x + #| } else { + #| ln_1pf(x * 2.0 + x * 2.0 * x / ((1.0 : Float) - x)) * 0.5 + #| } + #| } else { + #| ln_1pf(x / ((1.0 : Float) - x) * 2.0) * 0.5 + #| } + #| if sign { + #| -x + #| } else { + #| x + #| } + #|} + ), + "hyperbolic_double_js.mbt": ( + #|pub fn sinh(x : Double) -> Double = "Math" "sinh" + #|pub fn cosh(x : Double) -> Double = "Math" "cosh" + #|pub fn tanh(x : Double) -> Double = "Math" "tanh" + #|pub fn asinh(x : Double) -> Double = "Math" "asinh" + #|pub fn acosh(x : Double) -> Double = "Math" "acosh" + #|pub fn atanh(x : Double) -> Double = "Math" "atanh" + ), + "hyperbolic_double_nonjs.mbt": ( + #|pub fn sinh(x : Double) -> Double { + #| if x.is_nan() || x.is_inf() { + #| return x + #| } + #| let ix = get_high_word(x).reinterpret_as_int() & 0x7fffffff + #| let abs_x = x.abs() + #| let shuge = 1.0e307 + #| let h = if x < 0.0 { -0.5 } else { 0.5 } + #| if ix < 0x40360000 { + #| if ix < 0x3e300000 { + #| if shuge + x > 1.0 { + #| return x + #| } + #| } + #| let t = expm1(abs_x) + #| if ix < 0x3ff00000 { + #| return h * (2.0 * t - t * t / (t + 1.0)) + #| } + #| return h * (t + t / (t + 1.0)) + #| } + #| if ix < 0x40862E42 { + #| return h * exp(abs_x) + #| } + #| if abs_x.reinterpret_as_uint64() < 0x408633ce8fb9f87d { + #| let w = exp(0.5 * abs_x) + #| let t = h * w + #| return t * w + #| } + #| x * shuge + #|} + #|pub fn cosh(x : Double) -> Double { + #| if x.is_nan() { + #| return x + #| } + #| if x.is_inf() { + #| return @double.infinity + #| } + #| let ix = get_high_word(x).reinterpret_as_int() & 0x7fffffff + #| if ix < 0x3fd62e43 { + #| let t = expm1(x.abs()) + #| let w = 1.0 + t + #| if ix < 0x3c800000 { + #| return w + #| } + #| return 1.0 + t * t / (w + w) + #| } + #| if ix < 0x40360000 { + #| let t = exp(x.abs()) + #| return 0.5 * t + 0.5 / t + #| } + #| if ix < 0x40862E42 { + #| return (0.5 * x.abs()) |> exp + #| } + #| let lx = get_low_word(x).reinterpret_as_int() + #| if ix < 0x408633ce || (ix == 0x408633ce && lx <= 0x8fb9f87d) { + #| let w = exp(0.5 * x.abs()) + #| let t = 0.5 * w + #| return t * w + #| } + #| @double.infinity + #|} + #|pub fn tanh(x : Double) -> Double { + #| if x.is_nan() { + #| return x + #| } + #| if x.is_pos_inf() { + #| return 1.0 + #| } + #| if x.is_neg_inf() { + #| return -1.0 + #| } + #| let ix = get_high_word(x).reinterpret_as_int() & 0x7fffffff + #| let tiny = 1.0e-300 + #| let z = if ix < 0x40360000 { + #| if ix < 0x3c800000 { + #| x * (1.0 + x) + #| } else if ix >= 0x3ff00000 { + #| let t = (2.0 * x.abs()) |> expm1 + #| 1.0 - 2.0 / (t + 2.0) + #| } else { + #| let t = (-2.0 * x.abs()) |> expm1 + #| -t / (t + 2.0) + #| } + #| } else { + #| 1.0 - tiny + #| } + #| if x >= 0.0 { + #| z + #| } else { + #| -z + #| } + #|} + #|pub fn asinh(x : Double) -> Double { + #| if x.is_nan() || x.is_inf() { + #| return x + #| } + #| let one : Double = 1.0 + #| let ln2 : Double = 6.93147180559945286227e-01 + #| let huge : Double = 1.0e300 + #| let hx = get_high_word(x).reinterpret_as_int() + #| let ix = hx & 0x7fffffff + #| if ix < 0x3e300000 { + #| if huge + x > one { + #| return x + #| } + #| } + #| let w : Double = if ix > 0x41b00000 { + #| ln(x.abs()) + ln2 + #| } else if ix > 0x40000000 { + #| let t = x.abs() + #| (2.0 * t + one / ((x * x + one).sqrt() + t)) |> ln + #| } else { + #| let t = x * x + #| (x.abs() + t / (one + (one + t).sqrt())) |> ln_1p + #| } + #| if hx > 0 { + #| w + #| } else { + #| -w + #| } + #|} + #|pub fn acosh(x : Double) -> Double { + #| let one = 1.0 + #| let hx = get_high_word(x).reinterpret_as_int() + #| if x < 1.0 || x.is_nan() { + #| return @double.not_a_number + #| } else if x == 1.0 { + #| return 0.0 + #| } else if x.is_pos_inf() { + #| return @double.infinity + #| } else if hx >= 0x41b00000 { + #| return ln(x) + LN2 + #| } else if hx > 0x40000000 { + #| let t = x * x + #| return (2.0 * x - one / (x + (t - one).sqrt())) |> ln + #| } else { + #| let t = x - one + #| return (t + (2.0 * t + t * t).sqrt()) |> ln_1p + #| } + #|} + #|pub fn atanh(x : Double) -> Double { + #| let hx : Int = get_high_word(x).reinterpret_as_int() + #| let ix = hx & 0x7fffffff + #| if x.abs() > 1.0 { + #| return @double.not_a_number + #| } + #| if x == 1.0 { + #| return @double.infinity + #| } + #| if x == -1.0 { + #| return @double.neg_infinity + #| } + #| if ix < 0x3e300000 && 1.0e300 + x > 0.0 { + #| return x + #| } + #| let x = x.abs() + #| let t = if x <= 0.5 { + #| let t = x + x + #| 0.5 * ln_1p(t + t * x / (1.0 - x)) + #| } else { + #| 0.5 * ln_1p((x + x) / (1.0 - x)) + #| } + #| if hx >= 0 { + #| t + #| } else { + #| -t + #| } + #|} + ), + "log.mbt": ( + #|let logf_off = 0x3f330000U + #|let logf_table_bits = 4 + #|let logf_n : UInt = 1U << logf_table_bits + #|priv struct LogfData { + #| invc : FixedArray[Double] + #| logc : FixedArray[Double] + #| ln2 : Double + #| poly : FixedArray[Double] + #|} + #|let logf_data : LogfData = { + #| invc: [ + #| 0x1.661ec79f8f3bep+0, 0x1.571ed4aaf883dp+0, 0x1.49539f0f010bp+0, 0x1.3c995b0b80385p+0, + #| 0x1.30d190c8864a5p+0, 0x1.25e227b0b8eap+0, 0x1.1bb4a4a1a343fp+0, 0x1.12358f08ae5bap+0, + #| 0x1.0953f419900a7p+0, 0x1.0p+0, 0x1.e608cfd9a47acp-1, 0x1.ca4b31f026aap-1, 0x1.b2036576afce6p-1, + #| 0x1.9c2d163a1aa2dp-1, 0x1.886e6037841edp-1, 0x1.767dcf5534862p-1, + #| ], + #| logc: [ + #| -0x1.57bf7808caadep-2, -0x1.2bef0a7c06ddbp-2, -0x1.01eae7f513a67p-2, -0x1.b31d8a68224e9p-3, + #| -0x1.6574f0ac07758p-3, -0x1.1aa2bc79c81p-3, -0x1.a4e76ce8c0e5ep-4, -0x1.1973c5a611cccp-4, + #| -0x1.252f438e10c1ep-5, 0x0.0p+0, 0x1.aa5aa5df25984p-5, 0x1.c5e53aa362eb4p-4, + #| 0x1.526e57720db08p-3, 0x1.bc2860d22477p-3, 0x1.1058bc8a07ee1p-2, 0x1.4043057b6ee09p-2, + #| ], + #| ln2: 0x1.62e42fefa39efp-1, + #| poly: [-0x1.00ea348b88334p-2, 0x1.5575b0be00b6ap-2, -0x1.ffffef20a4123p-2], + #|} + #|pub fn lnf(x : Float) -> Float { + #| let mut ix : UInt = x.reinterpret_as_uint() + #| if ix == 0x3f800000U { + #| return 0.0 + #| } + #| if ix - 0x00800000U >= 0x7f800000U - 0x00800000U { + #| if ix * 2 == 0 { + #| return @float.neg_infinity + #| } + #| if ix == 0x7f800000U { + #| return x + #| } + #| if (ix & 0x80000000U) != 0 || ix * 2 >= 0xff000000U { + #| return @float.not_a_number + #| } + #| ix = (x * 0x1.0p23).reinterpret_as_uint() + #| ix -= (23 << 23).reinterpret_as_uint() + #| } + #| let tmp = ix - logf_off + #| let i = ((tmp >> (23 - logf_table_bits)) % logf_n).reinterpret_as_int() + #| let k = tmp.reinterpret_as_int() >> 23 + #| let iz = ix - (tmp & 0xff800000U) + #| let invc = logf_data.invc[i] + #| let logc = logf_data.logc[i] + #| let z = Float::reinterpret_from_uint(iz).to_double() + #| let r = z * invc - 1 + #| let y0 = logc + k.to_double() * logf_data.ln2 + #| let r2 = r * r + #| let y = logf_data.poly[1] * r + logf_data.poly[2] + #| let y = logf_data.poly[0] * r2 + y + #| let y = y * r2 + (y0 + r) + #| Float::from_double(y) + #|} + #|pub fn ln_1pf(x : Float) -> Float { + #| let lg1_f : Float = 0.66666662693 + #| let lg2_f : Float = 0.40000972152 + #| let lg3_f : Float = 0.28498786688 + #| let lg4_f : Float = 0.24279078841 + #| let float_ln2_hi : Float = 6.9314575195e-01 // 0x3f317200 + #| let float_ln2_lo : Float = 1.4286067653e-06 // 0x35bfbe8e + #| let mut ui : UInt = x.reinterpret_as_uint() + #| let mut f : Float = 0 + #| let mut c : Float = 0 + #| let mut iu : UInt = 0 + #| let one : Float = 1.0 + #| let mut k = 1 + #| if ui < 0x3ed413d0 || ui >> 31 > 0 { + #| if ui >= 0xbf800000 { + #| if x == -1.0 { + #| return x / 0.0 + #| } + #| return (x - x) / 0.0 + #| } + #| if ui << 1 < 0x33800000U << 1 { + #| return x + #| } + #| if ui <= 0xbe95f619 { + #| k = 0 + #| c = 0.0 + #| f = x + #| } + #| } else if ui >= 0x7f800000 { + #| return x + #| } + #| if k > 0 { + #| ui = (one + x).reinterpret_as_uint() + #| iu = ui + #| iu += 0x3f800000U - 0x3f3504f3U + #| k = (iu >> 23).reinterpret_as_int() - 0x7f + #| if k < 25 { + #| let fui = Float::reinterpret_from_uint(ui) + #| c = if k >= 2 { one - (fui - x) } else { x - (fui - 1.0) } + #| c /= Float::reinterpret_from_uint(ui) + #| } else { + #| c = 0.0 + #| } + #| iu = (iu & 0x007fffff) + 0x3f3504f3 + #| ui = iu + #| f = Float::reinterpret_from_uint(ui) - 1.0 + #| } + #| let s = f / (f + 2.0) + #| let z = s * s + #| let w = z * z + #| let t1 = w * (lg2_f + w * lg4_f) + #| let t2 = z * (lg1_f + w * lg3_f) + #| let r = t2 + t1 + #| let hfsq = f * f * 0.5 + #| let dk = Float::from_int(k) + #| s * (hfsq + r) + (dk * float_ln2_lo + c) - hfsq + f + dk * float_ln2_hi + #|} + ), + "log_double_js.mbt": ( + #|pub fn ln(x : Double) -> Double = "Math" "log" + #|pub fn log2(x : Double) -> Double = "Math" "log2" + #|pub fn log10(x : Double) -> Double = "Math" "log10" + #|pub fn ln_1p(x : Double) -> Double = "Math" "log1p" + ), + "log_double_nonjs.mbt": ( + #|pub fn ln(x : Double) -> Double { + #| let l1 = 6.666666666666735130e-01 // 3FE55555 55555593 + #| let l2 = 3.999999999940941908e-01 // 3FD99999 9997FA04 + #| let l3 = 2.857142874366239149e-01 // 3FD24924 94229359 + #| let l4 = 2.222219843214978396e-01 // 3FCC71C5 1D8E78AF + #| let l5 = 1.818357216161805012e-01 // 3FC74664 96CB03DE + #| let l6 = 1.531383769920937332e-01 // 3FC39A09 D078C69F + #| let l7 = 1.479819860511658591e-01 // 3FC2F112 DF3E5244 + #| if x < 0.0 { + #| return @double.not_a_number + #| } else if x.is_nan() || x.is_inf() { + #| return x + #| } else if x == 0.0 { + #| return @double.neg_infinity + #| } + #| let (f1, ki) = frexp(x) + #| let (f, k) = if f1 < SQRT2 / 2.0 { + #| (f1 * 2.0 - 1.0, (ki - 1).to_double()) + #| } else { + #| (f1 - 1.0, ki.to_double()) + #| } + #| let s = f / (2.0 + f) + #| let s2 = s * s + #| let s4 = s2 * s2 + #| let t1 = s2 * (l1 + s4 * (l3 + s4 * (l5 + s4 * l7))) + #| let t2 = s4 * (l2 + s4 * (l4 + s4 * l6)) + #| let r = t1 + t2 + #| let hfsq = 0.5 * f * f + #| k * LN2_HI - (hfsq - (s * (hfsq + r) + k * LN2_LO) - f) + #|} + #|pub fn log2(x : Double) -> Double { + #| let (f, e) = frexp(x) + #| if f == 0.5 { + #| return e.to_double() - 1.0 + #| } + #| ln(f) / LN2 + e.to_double() + #|} + #|pub fn log10(x : Double) -> Double { + #| if x < 0.0 { + #| return @double.not_a_number + #| } else if x.is_nan() || x.is_inf() { + #| return x + #| } else if x == 0.0 { + #| return @double.neg_infinity + #| } + #| let ivln10 = 4.34294481903251816668e-01 + #| let log10_2hi = 3.01029995663611771306e-01 + #| let log10_2lo = 3.69423907715893078616e-13 + #| let (f, e) = frexp(x) + #| let (f, e) = if e >= 1 { + #| (f * 2.0, (e - 1).to_double()) + #| } else { + #| (f, e.to_double()) + #| } + #| let z = e * log10_2lo + ivln10 * ln(f) + #| z + e * log10_2hi + #|} + #|pub fn ln_1p(x : Double) -> Double { + #| if x < -1.0 || x.is_nan() { + #| return @double.not_a_number + #| } + #| if x == -1.0 { + #| return @double.neg_infinity + #| } + #| if x.is_inf() { + #| return @double.infinity + #| } + #| let ln2_hi = 6.93147180369123816490e-01 + #| let ln2_lo = 1.90821492927058770002e-10 + #| let two54 = 1.80143985094819840000e+16 + #| let lp1 = 6.666666666666735130e-01 + #| let lp2 = 3.999999999940941908e-01 + #| let lp3 = 2.857142874366239149e-01 + #| let lp4 = 2.222219843214978396e-01 + #| let lp5 = 1.818357216161805012e-01 + #| let lp6 = 1.531383769920937332e-01 + #| let zero = 0.0 + #| let lp7 = 1.479819860511658591e-01 + #| let hx = get_high_word(x).reinterpret_as_int() + #| let ax = hx & 0x7fffffff + #| let mut f = 0.0 + #| let mut c = 0.0 + #| let mut s = 0.0 + #| let mut z = 0.0 + #| let mut r = 0.0 + #| let mut u = 0.0 + #| let mut hu = 0 + #| let mut k = 1 + #| if hx < 0x3FDA827A { + #| if ax < 0x3e200000 { + #| if two54 + x > zero && ax < 0x3c900000 { + #| return x + #| } else { + #| return x - x * x * 0.5 + #| } + #| } + #| if hx > 0 || hx <= 0xbfd2bec3 { + #| k = 0 + #| f = x + #| hu = 1 + #| } + #| } + #| if k != 0 { + #| if hx < 0x43400000 { + #| u = 1.0 + x + #| hu = get_high_word(u).reinterpret_as_int() + #| k = (hu >> 20) - 1023 + #| c = if k > 0 { 1.0 - (u - x) } else { x - (u - 1.0) } + #| c /= u + #| } else { + #| u = x + #| hu = get_high_word(u).reinterpret_as_int() + #| k = (hu >> 20) - 1023 + #| c = 0.0 + #| } + #| hu = hu & 0x000fffff + #| if hu < 0x6a09e { + #| u = set_high_word(u, hu.reinterpret_as_uint() | 0x3ff00000) + #| } else { + #| k += 1 + #| u = set_high_word(u, hu.reinterpret_as_uint() | 0x3fe00000) + #| hu = (0x00100000 - hu) >> 2 + #| } + #| f = u - 1.0 + #| } + #| let hfsq = 0.5 * f * f + #| if hu == 0 { + #| if f == zero { + #| if k == 0 { + #| return zero + #| } else { + #| c += k.to_double() * ln2_lo + #| return k.to_double() * ln2_hi + c + #| } + #| } + #| r = hfsq * (1.0 - 0.66666666666666666 * f) + #| if k == 0 { + #| return f - r + #| } else { + #| return k.to_double() * ln2_hi - (r - (k.to_double() * ln2_lo + c) - f) + #| } + #| } + #| s = f / (2.0 + f) + #| z = s * s + #| r = z * + #| (lp1 + z * (lp2 + z * (lp3 + z * (lp4 + z * (lp5 + z * (lp6 + z * lp7)))))) + #| if k == 0 { + #| return f - (hfsq - s * (hfsq + r)) + #| } else { + #| return k.to_double() * ln2_hi - + #| (hfsq - (s * (hfsq + r) + (k.to_double() * ln2_lo + c)) - f) + #| } + #|} + ), + "pow.mbt": ( + #|pub fn powf(base : Float, exponent : Float) -> Float { + #| let huge : Float = 1.0e30 + #| let tiny : Float = 1.0e-30 + #| let cp : Float = 9.6179670095e-01 // 0x3f76384f =2/(3ln2) */ + #| let cp_h : Float = 9.6191406250e-01 // 0x3f764000 =12b cp */ + #| let cp_l : Float = -1.1736857402e-04 // 0xb8f623c6 =tail of cp_h */ + #| let lg2 : Float = 6.9314718246e-01 // 0x3f317218 */ + #| let lg2_h : Float = 6.93145752e-01 // 0x3f317200 */ + #| let lg2_l : Float = 1.4286067653e-06 // 0x35bfbe8c */ + #| let ovt : Float = 8.0085662595e-08 // -(2**-28)/(log(2)**2) */ + #| let ivln2 : Float = 1.4426950216e+00 // 0x3f317218 */ + #| let ivln2_h : Float = 1.4426879883e+00 // 0x3f317218 */ + #| let ivln2_l : Float = 7.0526075433e-06 // 0x35bfbe8c */ + #| let l1 : Float = 6.0000002384e-01 // 0x3f19999a */ + #| let l2 : Float = 4.2857143283e-01 // 0x3edb6db7 */ + #| let l3 : Float = 3.3333334327e-01 // 0x3eaaaaab */ + #| let l4 : Float = 2.7272811532e-01 // 0x3e8ba305 */ + #| let l5 : Float = 2.3066075146e-01 // 0x3e6c3255 */ + #| let l6 : Float = 2.0697501302e-01 // 0x3e53f142 */ + #| let p1 : Float = 1.6666667163e-01 // 0x3e2aaaab */ + #| let p2 : Float = -2.7777778450e-03 // 0xbb360b61 */ + #| let p3 : Float = 6.6137559770e-05 // 0x388ab355 */ + #| let p4 : Float = -1.6533901999e-06 // 0xb5ddea0e */ + #| let p5 : Float = 4.1381369442e-08 // 0x3331bb4c */ + #| let mut z : Float = 0 + #| let mut ax : Float = 0 + #| let mut z_h : Float = 0 + #| let mut z_l : Float = 0 + #| let mut p_h : Float = 0 + #| let mut p_l : Float = 0 + #| let mut y1 : Float = 0 + #| let mut t1 : Float = 0 + #| let mut t2 : Float = 0 + #| let mut r : Float = 0 + #| let mut s : Float = 0 + #| let mut sn : Float = 0 + #| let mut t : Float = 0 + #| let mut u : Float = 0 + #| let mut v : Float = 0 + #| let mut w : Float = 0 + #| let mut i : Int = 0 + #| let mut j : Int = 0 + #| let mut k : Int = 0 + #| let mut yisint : Int = 0 + #| let mut n : Int = 0 + #| let mut hx : Int = 0 + #| let mut hy : Int = 0 + #| let mut ix : Int = 0 + #| let mut iy : Int = 0 + #| let mut i_s : Int = 0 + #| let (x, y) = (base, exponent) + #| let bp : ReadOnlyArray[Float] = [1.0, 1.5] + #| let dp_h : ReadOnlyArray[Float] = [0.0, 5.84960938e-01] // 0x3f15c000 */ + #| let dp_l : ReadOnlyArray[Float] = [0.0, 1.56322085e-06] // 0x35d1cfdc */ + #| let two24 : Float = 16777216.0 + #| hx = x.reinterpret_as_int() + #| hy = y.reinterpret_as_int() + #| ix = hx & 0x7fffffff + #| iy = hy & 0x7fffffff + #| if iy == 0 { + #| return 1.0 + #| } + #| if hx == 0x3f800000 { + #| return 1.0 + #| } + #| if ix > 0x7f800000 || iy > 0x7f800000 { + #| return x + y + #| } + #| yisint = 0 + #| if hx < 0 { + #| if iy >= 0x4b800000 { + #| yisint = 2 // even integer y + #| } else if iy >= 0x3f800000 { + #| k = (iy >> 23) - 0x7f // exponent + #| j = iy >> (23 - k) + #| if j << (23 - k) == iy { + #| yisint = 2 - (j & 1) + #| } + #| } + #| } + #| if iy == 0x7f800000 { + #| if ix == 0x3f800000 { + #| return 1.0 + #| } else if ix > 0x3f800000 { + #| return if hy >= 0 { y } else { 0.0 } + #| } else { + #| return if hy >= 0 { 0.0 } else { -y } + #| } + #| } + #| if iy == 0x3f800000 { + #| return if hy >= 0 { x } else { (1.0 : Float) / x } + #| } + #| if hy == 0x40000000 { + #| return x * x + #| } + #| if hy == 0x3f000000 && hx >= 0 { + #| return x.sqrt() + #| } + #| ax = x.abs() + #| if ix == 0x7f800000 || ix == 0 || ix == 0x3f800000 { + #| z = ax + #| if hy < 0 { + #| z = (1.0 : Float) / z + #| } + #| if hx < 0 { + #| if ((ix - 0x3f800000) | yisint) == 0 { + #| z = (z - z) / (z - z) // (-1)**non-int is NaN + #| } else if yisint == 1 { + #| z = -z + #| } + #| } // (x<0)**odd = -(|x|**odd) + #| return z + #| } + #| sn = 1.0 // sign of result + #| if hx < 0 { + #| if yisint == 0 { + #| return @float.not_a_number + #| } + #| if yisint == 1 { + #| sn = -1.0 + #| } + #| } + #| if iy > 0x4d000000 { + #| if ix < 0x3f7ffff8 { + #| return if hy < 0 { sn * huge * huge } else { sn * tiny * tiny } + #| } + #| if ix > 0x3f800007 { + #| return if hy > 0 { sn * huge * huge } else { sn * tiny * tiny } + #| } + #| t = ax - 1.0 // t has 20 trailing zeros + #| w = t * t * ((0.5 : Float) - t * ((0.333333333333 : Float) - t * 0.25)) + #| u = ivln2_h * t // IVLN2_H has 16 sig. bits + #| v = t * ivln2_l - w * ivln2 + #| t1 = u + v + #| i_s = t1.reinterpret_as_int() + #| t1 = Float::reinterpret_from_int(i_s & 0xfffff000) + #| t2 = v - (t1 - u) + #| } else { + #| let mut s2 : Float = 0 + #| let mut s_h : Float = 0 + #| let mut s_l : Float = 0 + #| let mut t_h : Float = 0 + #| let mut t_l : Float = 0 + #| n = 0 + #| if ix < 0x00800000 { + #| ax *= two24 + #| n -= 24 + #| ix = ax.reinterpret_as_int() + #| } + #| n += (ix >> 23) - 0x7f + #| j = ix & 0x007fffff + #| ix = j | 0x3f800000 // normalize ix + #| if j <= 0x1cc471 { + #| k = 0 + #| } else if j < 0x5db3d7 { + #| k = 1 + #| } else { + #| k = 0 + #| n += 1 + #| ix -= 0x00800000 + #| } + #| ax = Float::reinterpret_from_int(ix) + #| u = ax - bp[k] + #| v = (1.0 : Float) / (ax + bp[k]) + #| s = u * v + #| s_h = s + #| i_s = s_h.reinterpret_as_int() + #| s_h = Float::reinterpret_from_int(i_s & 0xfffff000) + #| i_s = (((ix.reinterpret_as_uint() >> 1) & 0xfffff000) | 0x20000000).reinterpret_as_int() + #| t_h = Float::reinterpret_from_uint( + #| i_s.reinterpret_as_uint() + 0x00400000 + (k.reinterpret_as_uint() << 21), + #| ) + #| t_l = ax - (t_h - bp[k]) + #| s_l = v * (u - s_h * t_h - s_h * t_l) + #| s2 = s * s + #| r = s2 * s2 * (l1 + s2 * (l2 + s2 * (l3 + s2 * (l4 + s2 * (l5 + s2 * l6))))) + #| r += s_l * (s_h + s) + #| s2 = s_h * s_h + #| t_h = (3.0 : Float) + s2 + r + #| i_s = t_h.reinterpret_as_int() + #| t_h = Float::reinterpret_from_int(i_s & 0xfffff000) + #| t_l = r - (t_h - 3.0 - s2) + #| u = s_h * t_h + #| v = s_l * t_h + t_l * s + #| p_h = u + v + #| i_s = p_h.reinterpret_as_int() + #| p_h = Float::reinterpret_from_int(i_s & 0xfffff000) + #| p_l = v - (p_h - u) + #| z_h = cp_h * p_h // cp_h+cp_l = 2/(3*log2) + #| z_l = cp_l * p_h + p_l * cp + dp_l[k] + #| t = Float::from_int(n) + #| t1 = z_h + z_l + dp_h[k] + t + #| i_s = t1.reinterpret_as_int() + #| t1 = Float::reinterpret_from_int(i_s & 0xfffff000) + #| t2 = z_l - (t1 - t - dp_h[k] - z_h) + #| } + #| i_s = y.reinterpret_as_int() + #| y1 = Float::reinterpret_from_int(i_s & 0xfffff000) + #| p_l = (y - y1) * t1 + y * t2 + #| p_h = y1 * t1 + #| z = p_l + p_h + #| j = z.reinterpret_as_int() + #| if j > 0x43000000 { + #| return sn * huge * huge // overflow + #| } else if j == 0x43000000 { + #| if p_l + ovt > z - p_h { + #| return sn * huge * huge + #| } + #| } else if ( // overflow + #| j & 0x7fffffff + #| ) > + #| 0x43160000 { + #| return sn * tiny * tiny // underflow + #| } else if j.reinterpret_as_uint() == 0xc3160000 && p_l <= z - p_h { + #| return sn * tiny * tiny + #| } // underflow + #| i = j & 0x7fffffff + #| k = (i >> 23) - 0x7f + #| n = 0 + #| if i > 0x3f000000 { + #| n = j + (0x00800000 >> (k + 1)) + #| k = ((n & 0x7fffffff) >> 23) - 0x7f // new k for n + #| t = Float::reinterpret_from_int(n & (0x007fffff >> k).lnot()) + #| n = ((n & 0x007fffff) | 0x00800000) >> (23 - k) + #| if j < 0 { + #| n = -n + #| } + #| p_h -= t + #| } + #| t = p_l + p_h + #| i_s = t.reinterpret_as_int() + #| t = Float::reinterpret_from_int(i_s & 0xffff8000) + #| u = t * lg2_h + #| v = (p_l - (t - p_h)) * lg2 + t * lg2_l + #| z = u + v + #| w = v - (z - u) + #| t = z * z + #| t1 = z - t * (p1 + t * (p2 + t * (p3 + t * (p4 + t * p5)))) + #| r = z * t1 / (t1 - 2.0) - (w + z * w) + #| z = (1.0 : Float) - (r - z) + #| j = z.reinterpret_as_int() + #| j += n << 23 + #| if j >> 23 <= 0 { + #| z = scalbnf(z, n) + #| } else { + #| z = Float::reinterpret_from_int(j) + #| } + #| sn * z + #|} + ), + "pow_double_js.mbt": ( + #|pub fn pow(base : Double, exponent : Double) -> Double = "Math" "pow" + ), + "pow_double_nonjs.mbt": ( + #|let pow_bp : ReadOnlyArray[Double] = [1.0, 1.5] + #|let pow_dp_h : ReadOnlyArray[Double] = [0.0, 5.84962487220764160156e-01] + #|let pow_dp_l : ReadOnlyArray[Double] = [0.0, 1.35003920212974897128e-08] + #|const ZERO = 0.0 + #|const ONE = 1.0 + #|const TWO = 2.0 + #|const POW_two53 = 9007199254740992.0 + #|const POW_huge = 1.0e300 + #|const POW_tiny = 1.0e-300 + #|const POW_L1 = 5.99999999999994648725e-01 + #|const POW_L2 = 4.28571428578550184252e-01 + #|const POW_L3 = 3.33333329818377432918e-01 + #|const POW_L4 = 2.72728123808534006489e-01 + #|const POW_L5 = 2.30660745775561754067e-01 + #|const POW_L6 = 2.06975017800338417784e-01 + #|const POW_P1 = 1.66666666666666019037e-01 + #|const POW_P2 = -2.77777777770155933842e-03 + #|const POW_P3 = 6.61375632143793436117e-05 + #|const POW_P4 = -1.65339022054652515390e-06 + #|const POW_P5 = 4.13813679705723846039e-08 + #|const POW_lg2 = 6.93147180559945286227e-01 + #|const POW_lg2_h = 6.93147182464599609375e-01 + #|const POW_lg2_l = -1.90465429995776804525e-09 + #|const POW_ovt = 8.0085662595372944372e-0017 + #|const POW_cp = 9.61796693925975554329e-01 + #|const POW_cp_h = 9.61796700954437255859e-01 + #|const POW_cp_l = -7.02846165095275826516e-09 + #|const POW_ivln2 = 1.44269504088896338700e+00 + #|const POW_ivln2_h = 1.44269502162933349609e+00 + #|const POW_ivln2_l = 1.92596299112661746887e-08 + #|pub fn pow(x : Double, y : Double) -> Double { + #| fn set_low_word(d : Double, v : UInt) -> Double { + #| let bits : UInt64 = d.reinterpret_as_uint64() + #| let bits = bits & 0xFFFF_FFFF_0000_0000 + #| let bits = bits | v.to_uint64() + #| bits.reinterpret_as_double() + #| } + #| fn set_high_word(d : Double, v : UInt) -> Double { + #| let bits : UInt64 = d.reinterpret_as_uint64() + #| let bits = bits & 0x0000_0000_FFFF_FFFF + #| let bits = bits | (v.to_uint64() << 32) + #| bits.reinterpret_as_double() + #| } + #| fn get_high_word(x : Double) -> UInt { + #| (x.reinterpret_as_uint64() >> 32).to_uint() + #| } + #| fn get_low_word(x : Double) -> UInt { + #| x.reinterpret_as_uint64().to_uint() + #| } + #| let mut z : Double = 0.0 + #| let mut ax : Double = 0.0 + #| let mut z_h : Double = 0.0 + #| let mut z_l : Double = 0.0 + #| let mut p_h : Double = 0.0 + #| let mut p_l : Double = 0.0 + #| let mut y1 : Double = 0.0 + #| let mut t1 : Double = 0.0 + #| let mut t2 : Double = 0.0 + #| let mut r : Double = 0.0 + #| let mut s : Double = 0.0 + #| let mut t : Double = 0.0 + #| let mut u : Double = 0.0 + #| let mut v : Double = 0.0 + #| let mut w : Double = 0.0 + #| let mut i : Int = 0 + #| let mut j : Int = 0 + #| let mut k : Int = 0 + #| let mut yisint : Int = 0 + #| let mut n : Int = 0 + #| let hx : Int = (x.reinterpret_as_uint64() >> 32).to_int() + #| let lx : UInt = (x.reinterpret_as_uint64() & 0xFFFFFFFF).to_uint() + #| let hy : Int = (y.reinterpret_as_uint64() >> 32).to_int() + #| let ly : UInt = (y.reinterpret_as_uint64() & 0xFFFFFFFF).to_uint() + #| let mut ix : Int = hx & 0x7FFFFFFF + #| let iy : Int = hy & 0x7FFFFFFF + #| if (iy.reinterpret_as_uint() | ly) == 0 { + #| return ONE + #| } + #| if ix > 0x7FF00000 || + #| (ix == 0x7FF00000 && lx != 0) || + #| iy > 0x7FF00000 || + #| (iy == 0x7FF00000 && ly != 0) { + #| return x + y + #| } + #| if hx < 0 { + #| if iy >= 0x43400000 { + #| yisint = 2 // even integer y + #| } else if iy >= 0x3ff00000 { + #| k = (iy >> 20) - 0x3ff // exponent + #| if k > 20 { + #| j = (ly >> (52 - k)).reinterpret_as_int() + #| if j << (52 - k) == ly.reinterpret_as_int() { + #| yisint = 2 - (j & 1) + #| } + #| } else if ly == 0 { + #| j = iy >> (20 - k) + #| if j << (20 - k) == iy { + #| yisint = 2 - (j & 1) + #| } + #| } + #| } + #| } + #| if ly == 0 { + #| if iy == 0x7ff00000 { // y is +-inf + #| if ((ix.reinterpret_as_uint() - 0x3ff00000) | lx) == 0 { + #| return y - y // inf**+-1 is NaN + #| } else if ix >= 0x3ff00000 { // (|x|>1)**+-inf = inf,0 + #| return if hy >= 0 { y } else { ZERO } + #| } else { // (|x|<1)**-,+inf = inf,0 + #| return if hy < 0 { -y } else { ZERO } + #| } + #| } + #| if iy == 0x3ff00000 { // y is +-1 + #| if hy < 0 { + #| return ONE / x + #| } else { + #| return x + #| } + #| } + #| if hy == 0x40000000 { // y is 2 + #| return x * x + #| } + #| if hy == 0x3fe00000 { // y is 0.5 + #| if hx >= 0 { // x >= +0 + #| return x.sqrt() + #| } + #| } + #| } + #| ax = x.abs() + #| if lx == 0 { + #| if ix == 0x7ff00000 || ix == 0 || ix == 0x3ff00000 { + #| z = ax // x is +-0,+-inf,+-1 */ + #| if hy < 0 { + #| z = ONE / z // z = (1/|x|) + #| } + #| if hx < 0 { + #| if ((ix - 0x3ff00000) | yisint) == 0 { + #| z = @double.not_a_number + #| } else if yisint == 1 { + #| z = -z // (x<0)**odd = -(|x|**odd) + #| } + #| } + #| return z + #| } + #| } + #| n = (hx >> 31) + 1 + #| if (n | yisint) == 0 { + #| return @double.not_a_number + #| } + #| s = ONE // s (sign of result -ve**odd) = -1 else = 1 + #| if (n | (yisint - 1)) == 0 { + #| s = -ONE // (-ve)**(odd int) + #| } + #| if iy > 0x41e00000 { // if |y| > 2**31 */ + #| if iy > 0x43f00000 { // if |y| > 2**64, must o/uflow */ + #| if ix <= 0x3fefffff { + #| return if hy < 0 { POW_huge * POW_huge } else { POW_tiny * POW_tiny } + #| } + #| if ix >= 0x3ff00000 { + #| return if hy > 0 { POW_huge * POW_huge } else { POW_tiny * POW_tiny } + #| } + #| } + #| if ix < 0x3fefffff { + #| return if hy < 0 { + #| s * POW_huge * POW_huge + #| } else { + #| s * POW_tiny * POW_tiny + #| } + #| } + #| if ix > 0x3ff00000 { + #| return if hy > 0 { + #| s * POW_huge * POW_huge + #| } else { + #| s * POW_tiny * POW_tiny + #| } + #| } + #| t = ax - ONE // t has 20 trailing zeros */ + #| w = t * t * (0.5 - t * (0.3333333333333333333333 - t * 0.25)) + #| u = POW_ivln2_h * t // POW_ivln2_h has 21 sig. bits */ + #| v = t * POW_ivln2_l - w * POW_ivln2 + #| t1 = u + v + #| t1 = set_low_word(t1, 0) + #| t2 = v - (t1 - u) + #| } else { + #| n = 0 + #| if ix < 0x00100000 { + #| ax *= POW_two53 + #| n -= 53 + #| ix = get_high_word(ax).reinterpret_as_int() + #| } + #| n += (ix >> 20) - 0x3ff + #| j = ix & 0x000fffff + #| ix = j | 0x3ff00000 // normalize ix + #| if j <= 0x3988E { + #| k = 0 // |x|> 1) | 0x20000000) + + #| 0x00080000 + + #| (k.reinterpret_as_uint() << 18), + #| ) + #| let mut t_l : Double = ax - (t_h - pow_bp[k]) + #| let s_l : Double = v * (u - s_h * t_h - s_h * t_l) + #| let mut s2 : Double = ss * ss + #| r = s2 * + #| s2 * + #| ( + #| POW_L1 + + #| s2 * + #| (POW_L2 + s2 * (POW_L3 + s2 * (POW_L4 + s2 * (POW_L5 + s2 * POW_L6)))) + #| ) + #| r += s_l * (s_h + ss) + #| s2 = s_h * s_h + #| t_h = 3.0 + s2 + r + #| t_h = set_low_word(t_h, 0) + #| t_l = r - (t_h - 3.0 - s2) + #| u = s_h * t_h + #| v = s_l * t_h + t_l * ss + #| p_h = u + v + #| p_h = set_low_word(p_h, 0) + #| p_l = v - (p_h - u) + #| z_h = POW_cp_h * p_h // cp_h+cp_l = 2/(3*log2) + #| z_l = POW_cp_l * p_h + p_l * POW_cp + pow_dp_l[k] + #| t = n.to_double() + #| t1 = z_h + z_l + pow_dp_h[k] + t + #| t1 = set_low_word(t1, 0) + #| t2 = z_l - (t1 - t - pow_dp_h[k] - z_h) + #| } + #| y1 = y + #| y1 = set_low_word(y1, 0) + #| p_l = (y - y1) * t1 + y * t2 + #| p_h = y1 * t1 + #| z = p_l + p_h + #| j = get_high_word(z).reinterpret_as_int() + #| i = get_low_word(z).reinterpret_as_int() + #| if j >= 0x40900000 { // z >= 1024 + #| if ((j - 0x40900000) | i) != 0 { // if z > 1024 + #| return s * POW_huge * POW_huge // overflow + #| } else if p_l + POW_ovt > z - p_h { + #| return s * POW_huge * POW_huge // overflow + #| } + #| } else if (j & 0x7fffffff) >= 0x4090cc00 { // z <= -1075 + #| if ((j - 0xc090cc00) | i) != 0 { // z < -1075 + #| return s * POW_tiny * POW_tiny // underflow + #| } else if p_l <= z - p_h { + #| return s * POW_tiny * POW_tiny // underflow + #| } + #| } + #| i = j & 0x7fffffff + #| k = (i >> 20) - 0x3ff + #| n = 0 + #| if i > 0x3fe00000 { // if |z| > 0.5, set n = [z+0.5] + #| n = j + (0x00100000 >> (k + 1)) + #| k = ((n & 0x7fffffff) >> 20) - 0x3ff // new k for n + #| t = ZERO + #| t = set_high_word(t, (n & (0x000fffff >> k).lnot()).reinterpret_as_uint()) + #| n = ((n & 0x000fffff) | 0x00100000) >> (20 - k) + #| if j < 0 { + #| n = -n + #| } + #| p_h -= t + #| } + #| t = p_l + p_h + #| t = set_low_word(t, 0) + #| u = t * POW_lg2_h + #| v = (p_l - (t - p_h)) * POW_lg2 + t * POW_lg2_l + #| z = u + v + #| w = v - (z - u) + #| t = z * z + #| t1 = z - + #| t * (POW_P1 + t * (POW_P2 + t * (POW_P3 + t * (POW_P4 + t * POW_P5)))) + #| r = z * t1 / (t1 - TWO - (w + z * w)) + #| z = ONE - (r - z) + #| j = get_high_word(z).reinterpret_as_int() + #| j += (n.reinterpret_as_uint() << 20).reinterpret_as_int() + #| if j >> 20 <= 0 { + #| z = scalbn(z, n) + #| } else { // subnormal output */ + #| let tmp = get_high_word(z).reinterpret_as_int() + #| z = set_high_word( + #| z, + #| (tmp + (n.reinterpret_as_uint() << 20).reinterpret_as_int()).reinterpret_as_uint(), + #| ) + #| } + #| return s * z + #|} + ), + "prime.mbt": ( + #|const DEFAULT_PRIME_TEST_ITERS = 64 + #|let small_primes : ReadOnlyArray[@bigint.BigInt] = [ + #| 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, + #| 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, + #| 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, + #| 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, + #| 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, + #| 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, + #| 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, + #| 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, + #| 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, + #| 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, + #| 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, + #| 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, + #| 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, + #| 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, + #| 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, + #| 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, + #| 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, + #| 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, + #| 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, + #| 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, + #| 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, + #| 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, + #| 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, + #| 2351, 2357, 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, + #| 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, 2557, 2579, + #| 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, + #| 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, + #| 2789, 2791, 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, + #| 2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, 3001, 3011, + #| 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137, + #| 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, + #| 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, 3361, + #| 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, + #| 3499, 3511, 3517, 3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, + #| 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697, + #| 3701, 3709, 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821, + #| 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, 3919, 3923, + #| 3929, 3931, 3943, 3947, 3967, 3989, 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, + #| 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, 4153, 4157, + #| 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, 4261, 4271, + #| 4273, 4283, 4289, 4297, 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, + #| 4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, + #| 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637, 4639, 4643, 4649, + #| 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751, 4759, 4783, + #| 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909, + #| 4919, 4931, 4933, 4937, 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, + #| 5009, 5011, 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, 5099, 5101, 5107, 5113, + #| 5119, 5147, 5153, 5167, 5171, 5179, 5189, 5197, 5209, 5227, 5231, 5233, 5237, 5261, + #| 5273, 5279, 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387, 5393, 5399, + #| 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443, 5449, 5471, 5477, 5479, 5483, 5501, + #| 5503, 5507, 5519, 5521, 5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639, + #| 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, 5693, 5701, 5711, 5717, 5737, + #| 5741, 5743, 5749, 5779, 5783, 5791, 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, + #| 5851, 5857, 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, 5953, 5981, + #| 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, 6079, 6089, 6091, 6101, + #| 6113, 6121, 6131, 6133, 6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211, 6217, 6221, + #| 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329, + #| 6337, 6343, 6353, 6359, 6361, 6367, 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, + #| 6469, 6473, 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, 6577, 6581, + #| 6599, 6607, 6619, 6637, 6653, 6659, 6661, 6673, 6679, 6689, 6691, 6701, 6703, 6709, + #| 6719, 6733, 6737, 6761, 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, + #| 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, 6947, 6949, 6959, 6961, + #| 6967, 6971, 6977, 6983, 6991, 6997, 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, + #| 7079, 7103, 7109, 7121, 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, + #| 7219, 7229, 7237, 7243, 7247, 7253, 7283, 7297, 7307, 7309, 7321, 7331, 7333, 7349, + #| 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 7489, 7499, + #| 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, 7573, 7577, 7583, 7589, + #| 7591, 7603, 7607, 7621, 7639, 7643, 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, + #| 7717, 7723, 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, 7841, 7853, + #| 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919, 7927, 7933, 7937, 7949, 7951, 7963, + #| 7993, 8009, 8011, 8017, 8039, 8053, 8059, 8069, 8081, 8087, 8089, 8093, 8101, 8111, + #| 8117, 8123, 8147, 8161, 8167, 8171, 8179, 8191, 8209, 8219, 8221, 8231, 8233, 8237, + #| 8243, 8263, 8269, 8273, 8287, 8291, 8293, 8297, 8311, 8317, 8329, 8353, 8363, 8369, + #| 8377, 8387, 8389, 8419, 8423, 8429, 8431, 8443, 8447, 8461, 8467, 8501, 8513, 8521, + #| 8527, 8537, 8539, 8543, 8563, 8573, 8581, 8597, 8599, 8609, 8623, 8627, 8629, 8641, + #| 8647, 8663, 8669, 8677, 8681, 8689, 8693, 8699, 8707, 8713, 8719, 8731, 8737, 8741, + #| 8747, 8753, 8761, 8779, 8783, 8803, 8807, 8819, 8821, 8831, 8837, 8839, 8849, 8861, + #| 8863, 8867, 8887, 8893, 8923, 8929, 8933, 8941, 8951, 8963, 8969, 8971, 8999, 9001, + #| 9007, 9011, 9013, 9029, 9041, 9043, 9049, 9059, 9067, 9091, 9103, 9109, 9127, 9133, + #| 9137, 9151, 9157, 9161, 9173, 9181, 9187, 9199, 9203, 9209, 9221, 9227, 9239, 9241, + #| 9257, 9277, 9281, 9283, 9293, 9311, 9319, 9323, 9337, 9341, 9343, 9349, 9371, 9377, + #| 9391, 9397, 9403, 9413, 9419, 9421, 9431, 9433, 9437, 9439, 9461, 9463, 9467, 9473, + #| 9479, 9491, 9497, 9511, 9521, 9533, 9539, 9547, 9551, 9587, 9601, 9613, 9619, 9623, + #| 9629, 9631, 9643, 9649, 9661, 9677, 9679, 9689, 9697, 9719, 9721, 9733, 9739, 9743, + #| 9749, 9767, 9769, 9781, 9787, 9791, 9803, 9811, 9817, 9829, 9833, 9839, 9851, 9857, + #| 9859, 9871, 9883, 9887, 9901, 9907, 9923, 9929, 9931, 9941, 9949, 9967, 9973, 10007, + #| 10009, 10037, 10039, 10061, 10067, 10069, 10079, 10091, 10093, 10099, 10103, 10111, + #| 10133, 10139, 10141, 10151, 10159, 10163, 10169, 10177, 10181, 10193, 10211, 10223, + #| 10243, 10247, 10253, 10259, 10267, 10271, 10273, 10289, 10301, 10303, 10313, 10321, + #| 10331, 10333, 10337, 10343, 10357, 10369, 10391, 10399, 10427, 10429, 10433, 10453, + #| 10457, 10459, 10463, 10477, 10487, 10499, 10501, 10513, 10529, 10531, 10559, 10567, + #| 10589, 10597, 10601, 10607, 10613, 10627, 10631, 10639, 10651, 10657, 10663, 10667, + #| 10687, 10691, 10709, 10711, 10723, 10729, 10733, 10739, 10753, 10771, 10781, 10789, + #| 10799, 10831, 10837, 10847, 10853, 10859, 10861, 10867, 10883, 10889, 10891, 10903, + #| 10909, 10937, 10939, 10949, 10957, 10973, 10979, 10987, 10993, 11003, 11027, 11047, + #| 11057, 11059, 11069, 11071, 11083, 11087, 11093, 11113, 11117, 11119, 11131, 11149, + #| 11159, 11161, 11171, 11173, 11177, 11197, 11213, 11239, 11243, 11251, 11257, 11261, + #| 11273, 11279, 11287, 11299, 11311, 11317, 11321, 11329, 11351, 11353, 11369, 11383, + #| 11393, 11399, 11411, 11423, 11437, 11443, 11447, 11467, 11471, 11483, 11489, 11491, + #| 11497, 11503, 11519, 11527, 11549, 11551, 11579, 11587, 11593, 11597, 11617, 11621, + #| 11633, 11657, 11677, 11681, 11689, 11699, 11701, 11717, 11719, 11731, 11743, 11777, + #| 11779, 11783, 11789, 11801, 11807, 11813, 11821, 11827, 11831, 11833, 11839, 11863, + #| 11867, 11887, 11897, 11903, 11909, 11923, 11927, 11933, 11939, 11941, 11953, 11959, + #| 11969, 11971, 11981, 11987, 12007, 12011, 12037, 12041, 12043, 12049, 12071, 12073, + #| 12097, 12101, 12107, 12109, 12113, 12119, 12143, 12149, 12157, 12161, 12163, 12197, + #| 12203, 12211, 12227, 12239, 12241, 12251, 12253, 12263, 12269, 12277, 12281, 12289, + #| 12301, 12323, 12329, 12343, 12347, 12373, 12377, 12379, 12391, 12401, 12409, 12413, + #| 12421, 12433, 12437, 12451, 12457, 12473, 12479, 12487, 12491, 12497, 12503, 12511, + #| 12517, 12527, 12539, 12541, 12547, 12553, 12569, 12577, 12583, 12589, 12601, 12611, + #| 12613, 12619, 12637, 12641, 12647, 12653, 12659, 12671, 12689, 12697, 12703, 12713, + #| 12721, 12739, 12743, 12757, 12763, 12781, 12791, 12799, 12809, 12821, 12823, 12829, + #| 12841, 12853, 12889, 12893, 12899, 12907, 12911, 12917, 12919, 12923, 12941, 12953, + #| 12959, 12967, 12973, 12979, 12983, 13001, 13003, 13007, 13009, 13033, 13037, 13043, + #| 13049, 13063, 13093, 13099, 13103, 13109, 13121, 13127, 13147, 13151, 13159, 13163, + #| 13171, 13177, 13183, 13187, 13217, 13219, 13229, 13241, 13249, 13259, 13267, 13291, + #| 13297, 13309, 13313, 13327, 13331, 13337, 13339, 13367, 13381, 13397, 13399, 13411, + #| 13417, 13421, 13441, 13451, 13457, 13463, 13469, 13477, 13487, 13499, 13513, 13523, + #| 13537, 13553, 13567, 13577, 13591, 13597, 13613, 13619, 13627, 13633, 13649, 13669, + #| 13679, 13681, 13687, 13691, 13693, 13697, 13709, 13711, 13721, 13723, 13729, 13751, + #| 13757, 13759, 13763, 13781, 13789, 13799, 13807, 13829, 13831, 13841, 13859, 13873, + #| 13877, 13879, 13883, 13901, 13903, 13907, 13913, 13921, 13931, 13933, 13963, 13967, + #| 13997, 13999, 14009, 14011, 14029, 14033, 14051, 14057, 14071, 14081, 14083, 14087, + #| 14107, 14143, 14149, 14153, 14159, 14173, 14177, 14197, 14207, 14221, 14243, 14249, + #| 14251, 14281, 14293, 14303, 14321, 14323, 14327, 14341, 14347, 14369, 14387, 14389, + #| 14401, 14407, 14411, 14419, 14423, 14431, 14437, 14447, 14449, 14461, 14479, 14489, + #| 14503, 14519, 14533, 14537, 14543, 14549, 14551, 14557, 14561, 14563, 14591, 14593, + #| 14621, 14627, 14629, 14633, 14639, 14653, 14657, 14669, 14683, 14699, 14713, 14717, + #| 14723, 14731, 14737, 14741, 14747, 14753, 14759, 14767, 14771, 14779, 14783, 14797, + #| 14813, 14821, 14827, 14831, 14843, 14851, 14867, 14869, 14879, 14887, 14891, 14897, + #| 14923, 14929, 14939, 14947, 14951, 14957, 14969, 14983, 15013, 15017, 15031, 15053, + #| 15061, 15073, 15077, 15083, 15091, 15101, 15107, 15121, 15131, 15137, 15139, 15149, + #| 15161, 15173, 15187, 15193, 15199, 15217, 15227, 15233, 15241, 15259, 15263, 15269, + #| 15271, 15277, 15287, 15289, 15299, 15307, 15313, 15319, 15329, 15331, 15349, 15359, + #| 15361, 15373, 15377, 15383, 15391, 15401, 15413, 15427, 15439, 15443, 15451, 15461, + #| 15467, 15473, 15493, 15497, 15511, 15527, 15541, 15551, 15559, 15569, 15581, 15583, + #| 15601, 15607, 15619, 15629, 15641, 15643, 15647, 15649, 15661, 15667, 15671, 15679, + #| 15683, 15727, 15731, 15733, 15737, 15739, 15749, 15761, 15767, 15773, 15787, 15791, + #| 15797, 15803, 15809, 15817, 15823, 15859, 15877, 15881, 15887, 15889, 15901, 15907, + #| 15913, 15919, 15923, 15937, 15959, 15971, 15973, 15991, 16001, 16007, 16033, 16057, + #| 16061, 16063, 16067, 16069, 16073, 16087, 16091, 16097, 16103, 16111, 16127, 16139, + #| 16141, 16183, 16187, 16189, 16193, 16217, 16223, 16229, 16231, 16249, 16253, 16267, + #| 16273, 16301, 16319, 16333, 16339, 16349, 16361, 16363, 16369, 16381, 16411, 16417, + #| 16421, 16427, 16433, 16447, 16451, 16453, 16477, 16481, 16487, 16493, 16519, 16529, + #| 16547, 16553, 16561, 16567, 16573, 16603, 16607, 16619, 16631, 16633, 16649, 16651, + #| 16657, 16661, 16673, 16691, 16693, 16699, 16703, 16729, 16741, 16747, 16759, 16763, + #| 16787, 16811, 16823, 16829, 16831, 16843, 16871, 16879, 16883, 16889, 16901, 16903, + #| 16921, 16927, 16931, 16937, 16943, 16963, 16979, 16981, 16987, 16993, 17011, 17021, + #| 17027, 17029, 17033, 17041, 17047, 17053, 17077, 17093, 17099, 17107, 17117, 17123, + #| 17137, 17159, 17167, 17183, 17189, 17191, 17203, 17207, 17209, 17231, 17239, 17257, + #| 17291, 17293, 17299, 17317, 17321, 17327, 17333, 17341, 17351, 17359, 17377, 17383, + #| 17387, 17389, 17393, 17401, 17417, 17419, 17431, 17443, 17449, 17467, 17471, 17477, + #| 17483, 17489, 17491, 17497, 17509, 17519, 17539, 17551, 17569, 17573, 17579, 17581, + #| 17597, 17599, 17609, 17623, 17627, 17657, 17659, 17669, 17681, 17683, 17707, 17713, + #| 17729, 17737, 17747, 17749, 17761, 17783, 17789, 17791, 17807, 17827, 17837, 17839, + #| 17851, 17863, + #|] + #|pub fn is_probable_prime( + #| number : @bigint.BigInt, + #| rand : @random.Rand, + #| iters? : Int = DEFAULT_PRIME_TEST_ITERS, + #|) -> Bool { + #| if iters <= 0 { + #| abort("non-positive iters for probably prime") + #| } + #| if number <= 1N { + #| return false + #| } + #| if number <= 3N { + #| return true + #| } + #| if number % 2N == 0 { + #| return false + #| } + #| trial_divisions(number) && miller_rabin_test(number, iters, rand) + #|} + #|pub fn probable_prime(bits : Int, rand : @random.Rand) -> @bigint.BigInt { + #| for ;; { + #| let b = rand.bigint(bits) + #| if is_probable_prime(b, rand) { + #| break b + #| } + #| } + #|} + #|fn trial_divisions(n : @bigint.BigInt) -> Bool { + #| let td = match n.bit_length() { + #| _..=512 => 64 + #| 512..=1024 => 128 + #| 1024..=2048 => 384 + #| 2048..=4096 => 1024 + #| _ => 2048 + #| } + #| for i in 1.. Bool { + #| if w <= 3N { + #| abort("candidate of miller rabin test must larger than 3") + #| } + #| let w1 = w - 1N + #| let w3 = w - 3N + #| let a = w1.ctz() + #| let m = w1 >> a + #| let w3_len = w3.bit_length() + #| next~: for _ in 0.. Double { + #| let mut n = exp + #| let mut y : Double = x + #| if n > 1023 { + #| y *= 0x1.0p1023 + #| n -= 1023 + #| if n > 1023 { + #| y *= 0x1.0p1023 + #| n -= 1023 + #| if n > 1023 { + #| n = 1023 + #| } + #| } + #| } else if n < -1022 { + #| y *= 0x1.0p-1022 * 0x1.0p53 + #| n += 1022 - 53 + #| if n < -1022 { + #| y *= 0x1.0p-1022 * 0x1.0p53 + #| n += 1022 - 53 + #| if n < -1022 { + #| n = -1022 + #| } + #| } + #| } + #| let ui = (0x3ff + n).to_uint64() << 52 + #| return y * ui.reinterpret_as_double() + #|} + #|pub fn scalbnf(y : Float, exp : Int) -> Float { + #| let mut y = y + #| let mut n = exp + #| if n > 127 { + #| y *= (0x1.0p127 : Float) + #| n -= 127 + #| if n > 127 { + #| y *= (0x1.0p127 : Float) + #| n -= 127 + #| if n > 127 { + #| n = 127 + #| } + #| } + #| } else if n < -126 { + #| y *= (0x1.0p-126 : Float) * 0x1.0p24 + #| n += 126 - 24 + #| if n < -126 { + #| y *= (0x1.0p-126 : Float) * 0x1.0p24 + #| n += 126 - 24 + #| if n < -126 { + #| n = -126 + #| } + #| } + #| } + #| let u = (0x7f + n) << 23 + #| return y * Float::reinterpret_from_int(u) + #|} + #|test "scalbn" { + #| inspect(scalbn(1.5, 2), content="6") + #| inspect(scalbn(2.0, -1), content="1") + #| inspect(scalbn(3.0, 0), content="3") + #| inspect(scalbn(1.0, 1024), content="Infinity") + #| inspect(scalbn(1.0, -1023), content="1.1125369292536007e-308") + #| inspect(scalbn(1.0, 2047), content="Infinity") + #| inspect(scalbn(1.0, -1992), content="0") + #| inspect(scalbn(1.0, 3070), content="Infinity") + #| inspect(scalbn(1.0, -2961), content="0") + #| inspect(scalbn(@double.infinity, 10), content="Infinity") + #| inspect(scalbn(@double.not_a_number, 10), content="NaN") + #| inspect(scalbn(0.0, 10), content="0") + #|} + ), + "trig.mbt": ( + #|pub const PI = 0x3.243F6A8885A308CA8A54 + #|const SIN_SWITCHOVER : Float = 201.15625 + #|const COS_SWITCHOVER : Float = 142.90625 + #|fn mulh(a : UInt, b : UInt) -> UInt { + #| let a = a.to_uint64() + #| let b = b.to_uint64() + #| let res = a * b + #| (res >> 32).to_uint() + #|} + #|fn mul(a : UInt, b : UInt) -> (UInt, UInt) { + #| let a = a.to_uint64() + #| let b = b.to_uint64() + #| let res = a * b + #| ((res >> 32).to_uint(), res.to_uint()) + #|} + #|fn trig_reduce(x : Float, switch_over : Float) -> (Float, Int) { + #| if x.abs() <= switch_over { + #| let mut j : Float = 0.0 + #| let mut r : Float = 0.0 + #| j = x * Float::reinterpret_from_int(0x3f22f983) + + #| Float::reinterpret_from_int(0x4b40_0000) + #| j = Float::from_int(j.reinterpret_as_int() - 0x4b40_0000) + #| r = x - j * Float::reinterpret_from_int(0x3fc90f80) + #| r = r - j * Float::reinterpret_from_int(0x37354440) + #| r = r - j * Float::reinterpret_from_int(0x2c34611a) + #| return (r, j.to_int()) + #| } + #| let xispos = x > 0.0 + #| let mut exp : Int = ((x.reinterpret_as_int() >> 23) & 0xff) - 126 + #| let ix = ((x.reinterpret_as_uint() & 0x007fffff) << 8) | 0x80000000 + #| let ind = exp >> 5 + #| exp = exp & 0x1f + #| let two_over_pi : ReadOnlyArray[UInt] = [ + #| 0x00000000, 0x28be60db, 0x9391054a, 0x7f09d5f4, 0x7d4d3770, 0x36d8a566, 0x4f10e410, + #| 0000000000, + #| ] + #| let mut hi = two_over_pi[ind] + #| let mut mi = two_over_pi[ind + 1] + #| let mut lo = two_over_pi[ind + 2] + #| let tp = two_over_pi[ind + 3] + #| if exp > 0 { + #| hi = (hi << exp) | (mi >> (32 - exp)) + #| mi = (mi << exp) | (lo >> (32 - exp)) + #| lo = (lo << exp) | (tp >> (32 - exp)) + #| } + #| let phi = 0U + #| let (h, l) = mul(ix, lo) + #| let plo = phi + l + #| let phi = h + (if plo < l { 1 } else { 0 }) + #| let (h, l) = mul(ix, mi) + #| let mut plo = phi + l + #| let phi = h + (if plo < l { 1 } else { 0 }) + #| let l = ix * hi + #| let mut phi = phi + l + #| let mut q : Int = (phi >> 30).reinterpret_as_int() + #| phi = phi & 0x3fffffff + #| if (phi & 0x2000_0000) != 0 { + #| phi = phi - 0x4000_0000 + #| q = q + 1 + #| } + #| let s : UInt = phi & 0x8000_0000 + #| if phi >= 0x8000_0000 { + #| phi = phi.lnot() + #| plo = 0U - plo + #| phi += if plo == 0 { 1 } else { 0 } + #| } + #| exp = 0 + #| while phi < 0x8000_0000 { + #| phi = (phi << 1) | (plo >> 31) + #| plo = plo << 1 + #| exp = exp - 1 + #| } + #| phi = mulh(phi, 0xc90f_daa2) + #| if phi < 0x8000_0000 { + #| phi = phi << 1 + #| exp = exp - 1 + #| } + #| let mut r = s + + #| ((exp + 128) << 23).reinterpret_as_uint() + + #| (phi >> 8) + + #| (if (phi & 0xff) > 0x7e { 1 } else { 0 }) + #| if !xispos { + #| r = r ^ 0x8000_0000 + #| q = -q + #| } + #| let r = Float::reinterpret_from_uint(r) + #| return (r, q) + #|} + #|fn sinf_poly(x : Float) -> Float { + #| let s = x * x + #| let mut r = Float::reinterpret_from_int(0x3640_5000) + #| r = r * s - Float::reinterpret_from_int(0x3950_3486) + #| r = r * s + Float::reinterpret_from_int(0x3c08_88c1) + #| r = r * s - Float::reinterpret_from_int(0x3e2a_aaab) + #| let t = x * s + #| r = r * t + x + #| r + #|} + #|fn cosf_poly(x : Float) -> Float { + #| let s = x * x + #| let mut r = Float::reinterpret_from_int(0x37cd_4000) + #| r = r * s - Float::reinterpret_from_int(0x3ab6_077d) + #| r = r * s + Float::reinterpret_from_int(0x3d2a_aaa8) + #| r = r * s - Float::reinterpret_from_int(0x3f00_0000) + #| r = r * s + Float::reinterpret_from_int(0x3f80_0000) + #| r + #|} + #|fn sin_cos_core(x : Float, q : Int) -> Float { + #| let mut r = if (q & 1) != 0 { cosf_poly(x) } else { sinf_poly(x) } + #| if (q & 2) != 0 { + #| r = -r + #| } + #| r + #|} + #|fn tanf_poly(x : Float, odd : Bool) -> Float { + #| let x = x.to_double() + #| let coef : ReadOnlyArray[Double] = [ + #| 0.333331395030791399758, // 0x15554d3418c99f.0p-54 */ + #| 0.133392002712976742718, // 0x1112fd38999f72.0p-55 */ + #| 0.0533812378445670393523, // 0x1b54c91d865afe.0p-57 */ + #| 0.0245283181166547278873, // 0x191df3908c33ce.0p-58 */ + #| 0.00297435743359967304927, // 0x185dadfcecf44e.0p-61 */ + #| 0.00946564784943673166728, // 0x1362b9bf971bcd.0p-59 */ + #| ] + #| let z = x * x + #| let mut r = coef[4] + z * coef[5] + #| let t = coef[2] + z * coef[3] + #| let w = z * z + #| let s = z * x + #| let u = coef[0] + z * coef[1] + #| r = x + s * u + s * w * (t + w * r) + #| Float::from_double(if odd { -1.0 / r } else { r }) + #|} + #|pub fn sinf(x : Float) -> Float { + #| if x.is_nan() || x.is_inf() { + #| return @float.not_a_number + #| } + #| if x == 0.0 { + #| return x + #| } + #| let (x, q) = trig_reduce(x, SIN_SWITCHOVER) + #| sin_cos_core(x, q) + #|} + #|pub fn cosf(x : Float) -> Float { + #| if x.is_nan() || x.is_inf() { + #| return @float.not_a_number + #| } + #| if x == 0.0 { + #| return 1.0 + #| } + #| let (x, q) = trig_reduce(x, COS_SWITCHOVER) + #| sin_cos_core(x, q + 1) + #|} + #|pub fn tanf(x : Float) -> Float { + #| if x.is_nan() || x.is_inf() { + #| return @float.not_a_number + #| } + #| if x == 0.0 { + #| return x + #| } + #| let (x, q) = trig_reduce(x, COS_SWITCHOVER) + #| tanf_poly(x, (q & 1) != 0) + #|} + #|pub fn asinf(x : Float) -> Float { + #| let x1p120 = 0x3870000000000000UL.reinterpret_as_double() + #| let pio2 : Double = 1.570796326794896558e+00 + #| let ps0 : Float = 1.6666586697e-01 + #| let ps1 : Float = -4.2743422091e-02 + #| let ps2 : Float = -8.6563630030e-03 + #| let qs2 : Float = -7.0662963390e-01 + #| fn r(z : Float) -> Float { + #| let p = z * (ps0 + z * (ps1 + z * ps2)) + #| let q = z * qs2 + 1.0 + #| p / q + #| } + #| let hx = x.reinterpret_as_uint() + #| let ix = hx & 0x7fffffff + #| if ix >= 0x3f800000 { + #| if ix == 0x3f800000 { + #| return Float::from_double(x.to_double() * pio2 + x1p120) + #| } + #| return @float.not_a_number // asin(|x|>1) is NaN + #| } + #| if ix < 0x3f000000 { + #| if ix is (0x00800000..=0x39800000) { + #| return x + #| } + #| return x + x * r(x * x) + #| } + #| let z = ((1.0 : Float) - x.abs()) * 0.5 + #| let s = z.to_double().sqrt() + #| let x = Float::from_double(pio2 - 2.0 * (s + s * r(z).to_double())) + #| if hx >> 31 != 0 { + #| -x + #| } else { + #| x + #| } + #|} + #|pub fn acosf(x : Float) -> Float { + #| let pio2_hi : Float = 1.5707962513 + #| let pio2_lo : Float = 7.5497894159e-08 + #| let ps0 : Float = 1.6666586697e-01 + #| let ps1 : Float = -4.2743422091e-02 + #| let ps2 : Float = -8.6563630030e-03 + #| let qs1 : Float = -7.0662963390e-01 + #| let one : Float = 1.0 + #| let two : Float = 2.0 + #| fn r(z : Float) -> Float { + #| let p = z * (ps0 + z * (ps1 + z * ps2)) + #| let q = z * qs1 + 1.0 + #| p / q + #| } + #| let hx = x.reinterpret_as_int() + #| let ix = hx & 0x7fffffff + #| if ix >= 0x3f800000 { + #| if ix == 0x3f800000 { + #| if hx >> 31 != 0 { + #| return two * pio2_hi + 0x1.0p-120 + #| } + #| return 0.0 + #| } + #| return @float.not_a_number + #| } + #| if ix < 0x3f000000 { + #| if ix <= 0x32800000 { + #| return pio2_hi + 0x1.0p-120 + #| } + #| return pio2_hi - (x - (pio2_lo - x * r(x * x))) + #| } + #| if hx >> 31 != 0 { + #| let z = (x + 1.0) * 0.5 + #| let s = z.sqrt() + #| let w = r(z) * s - pio2_lo + #| return two * (pio2_hi - (s + w)) + #| } + #| let z = (one - x) * 0.5 + #| let s = z.sqrt() + #| let df = s + #| let c = (z - df * df) / (s + df) + #| let w = r(z) * s + c + #| two * (df + w) + #|} + #|pub fn atanf(x : Float) -> Float { + #| let atanhi : ReadOnlyArray[Float] = [ + #| 4.6364760399e-01, 7.8539812565e-01, 9.8279368877e-01, 1.5707962513e+00, + #| ] + #| let atanlo : ReadOnlyArray[Float] = [ + #| 5.0121582440e-09, 3.7748947079e-08, 3.4473217170e-08, 7.5497894159e-08, + #| ] + #| let a_t : ReadOnlyArray[Float] = [ + #| 3.3333328366e-01, -1.9999158382e-01, 1.4253635705e-01, -1.0648017377e-01, 6.1687607318e-02, + #| ] + #| let ix = x.reinterpret_as_int() + #| let sign = ix >> 31 + #| let ix = ix & 0x7fffffff + #| let mut id = 0 + #| let mut x = x + #| let one : Float = 1.0 + #| let two : Float = 2.0 + #| if ix >= 0x4c800000 { + #| if x.is_nan() { + #| return x + #| } + #| let z = atanhi[3] + 0x1.0p-120 + #| let z = if sign != 0 { -z } else { z } + #| return z + #| } + #| if ix < 0x3ee00000 { + #| if ix < 0x39800000 { + #| return x + #| } + #| id = -1 + #| } else { + #| x = x.abs() + #| if ix < 0x3f980000 { + #| if ix < 0x3f300000 { + #| id = 0 + #| x = (two * x - one) / (two + x) + #| } else { + #| id = 1 + #| x = (x - one) / (x + one) + #| } + #| } else if ix < 0x401c0000 { + #| id = 2 + #| x = (x - 1.5) / (one + x * 1.5) + #| } else { + #| id = 3 + #| x = -one / x + #| } + #| } + #| let z = x * x + #| let w = z * z + #| let s1 = z * (a_t[0] + w * (a_t[2] + w * a_t[4])) + #| let s2 = w * (a_t[1] + w * a_t[3]) + #| if id < 0 { + #| return x - x * (s1 + s2) + #| } + #| let z = atanhi[id] - (x * (s1 + s2) - atanlo[id] - x) + #| if sign != 0 { + #| -z + #| } else { + #| z + #| } + #|} + #|pub fn atan2f(y : Float, x : Float) -> Float { + #| if x.is_nan() || y.is_nan() { + #| return @float.not_a_number + #| } + #| let pi : Float = 3.1415927410e+00 + #| let zero : Float = 0.0 + #| let ix = x.reinterpret_as_uint() + #| let iy = y.reinterpret_as_uint() + #| if ix == 0x3f800000 { + #| return atanf(y) + #| } + #| let m = ((iy >> 31) & 1) | ((ix >> 30) & 2) + #| let ix = ix & 0x7fffffff + #| let iy = iy & 0x7fffffff + #| if iy == 0 { + #| match m { + #| 0 | 1 => return y + #| 2 => return pi + #| _ => return -pi + #| } + #| } + #| if ix == 0 { + #| let res = if (m & 1) != 0 { -pi / 2 } else { pi / 2 } + #| return res + #| } + #| if ix == 0x7f800000 { + #| if iy == 0x7f800000 { + #| match m { + #| 0 => return pi / 4 + #| 1 => return -pi / 4 + #| 2 => return pi * 3.0 / 4 + #| _ => return -pi * 3.0 / 4 + #| } + #| } else { + #| match m { + #| 0 => return 0.0 + #| 1 => return -0.0 + #| 2 => return pi + #| _ => return -pi + #| } + #| } + #| } + #| if ix + (26U << 23) < iy || iy == 0x7f800000 { + #| let res = if (m & 1) != 0 { -pi / 2 } else { pi / 2 } + #| return res + #| } + #| let z = if (m & 2) != 0 && iy + (26U << 23) < ix { + #| zero + #| } else { + #| atanf(y.abs() / x.abs()) + #| } + #| match m { + #| 0 => z + #| 1 => -z + #| 2 => pi - z + #| _ => z - pi + #| } + #|} + ), + "trig_double_js.mbt": ( + #|pub fn sin(x : Double) -> Double = "Math" "sin" + #|pub fn cos(x : Double) -> Double = "Math" "cos" + #|pub fn tan(x : Double) -> Double = "Math" "tan" + #|pub fn asin(x : Double) -> Double = "Math" "asin" + #|pub fn acos(x : Double) -> Double = "Math" "acos" + #|pub fn atan(x : Double) -> Double = "Math" "atan" + #|pub fn atan2(y : Double, x : Double) -> Double = "Math" "atan2" + ), + "trig_double_nonjs.mbt": ( + #|pub fn tan(x : Double) -> Double { + #| if x.is_inf() || x.is_nan() { + #| return @double.not_a_number + #| } + #| let y = Array::make(2, 0.0) + #| let z = 0.0 + #| if x.abs() <= PI_OVER_4 { + #| __kernal_tan(x, z, 1) + #| } else { + #| let n = rem_pio2(x, y) + #| __kernal_tan(y[0], y[1], 1 - ((n & 1) << 1)) + #| } + #|} + #|pub fn asin(x : Double) -> Double { + #| let huge = 1.0e+300 + #| let pio4_hi = 7.85398163397448278999e-01 + #| let pio2_hi = 1.57079632679489655800 + #| let pio2_lo = 6.12323399573676603587e-17 + #| let ps0 = 1.66666666666666657415e-01 + #| let ps1 = -3.25565818622400915405e-01 + #| let ps2 = 2.01212532134862925881e-01 + #| let ps3 = -4.00555345006794114027e-02 + #| let ps4 = 7.91534994289814532176e-04 + #| let ps5 = 3.47933107596021167570e-05 + #| let qs1 = -2.40339491173441421878e+00 + #| let qs2 = 2.02094576023350569471e+00 + #| let qs3 = -6.88283971605453293030e-01 + #| let qs4 = 7.70381505559019352791e-02 + #| let ix = get_high_word(x).reinterpret_as_int() & 0x7fffffff + #| let absx = x.abs() + #| if absx >= 1.0 { + #| if absx == 1.0 { + #| return x * pio2_hi + x * pio2_lo + #| } else { + #| return @double.not_a_number + #| } + #| } else if absx < 0.5 { + #| if ix < 0x3e400000 { + #| if huge + x > 1.0 { + #| return x + #| } + #| } else { + #| let t = x * x + #| let p = t * + #| (ps0 + t * (ps1 + t * (ps2 + t * (ps3 + t * (ps4 + t * ps5))))) + #| let q = 1.0 + t * (qs1 + t * (qs2 + t * (qs3 + t * qs4))) + #| let w = p / q + #| return x + x * w + #| } + #| } + #| let w = 1.0 - absx + #| let t = w * 0.5 + #| let p = t * (ps0 + t * (ps1 + t * (ps2 + t * (ps3 + t * (ps4 + t * ps5))))) + #| let q = 1.0 + t * (qs1 + t * (qs2 + t * (qs3 + t * qs4))) + #| let s = t.sqrt() + #| if ix >= 0x3FEF3333 { + #| let w = p / q + #| let t = pio2_hi - (2.0 * (s + s * w) - pio2_lo) + #| return if x > 0.0 { t } else { -t } + #| } else { + #| let mut w = s + #| w = set_low_word(w, 0) + #| let c = (t - w * w) / (s + w) + #| let r = p / q + #| let p = 2.0 * s * r - (pio2_lo - 2.0 * c) + #| let q = pio4_hi - 2.0 * w + #| let t = pio4_hi - (p - q) + #| return if x > 0.0 { t } else { -t } + #| } + #|} + #|pub fn acos(x : Double) -> Double { + #| let one : Double = 1.0 + #| let pi : Double = 3.14159265358979311600 + #| let pio2_hi : Double = 1.57079632679489655800 + #| let pio2_lo : Double = 6.12323399573676603587e-17 + #| let ps0 : Double = 1.66666666666666657415e-01 + #| let ps1 : Double = -3.25565818622400915405e-01 + #| let ps2 : Double = 2.01212532134862925881e-01 + #| let ps3 : Double = -4.00555345006794114027e-02 + #| let ps4 : Double = 7.91534994289814532176e-04 + #| let ps5 : Double = 3.47933107596021167570e-05 + #| let qs1 : Double = -2.40339491173441421878e+00 + #| let qs2 : Double = 2.02094576023350569471e+00 + #| let qs3 : Double = -6.88283971605453293030e-01 + #| let qs4 : Double = 7.70381505559019352791e-02 + #| let ix = get_high_word(x).reinterpret_as_int() & 0x7fffffff + #| let absx = x.abs() + #| if absx >= 1.0 { + #| if absx == 1.0 { + #| if x > 0 { + #| return 0.0 + #| } else { + #| return pi + 2.0 * pio2_lo + #| } + #| } + #| return @double.not_a_number + #| } + #| if absx < 0.5 { + #| if ix <= 0x3c600000 { + #| return pio2_hi + pio2_lo + #| } + #| let z = x * x + #| let p = z * (ps0 + z * (ps1 + z * (ps2 + z * (ps3 + z * (ps4 + z * ps5))))) + #| let q = one + z * (qs1 + z * (qs2 + z * (qs3 + z * qs4))) + #| let r = p / q + #| pio2_hi - (x - (pio2_lo - x * r)) + #| } else if x < 0 { + #| let z = (one + x) * 0.5 + #| let p = z * (ps0 + z * (ps1 + z * (ps2 + z * (ps3 + z * (ps4 + z * ps5))))) + #| let q = one + z * (qs1 + z * (qs2 + z * (qs3 + z * qs4))) + #| let s = z.sqrt() + #| let r = p / q + #| let w = r * s - pio2_lo + #| pi - 2.0 * (s + w) + #| } else { + #| let z = (one - x) * 0.5 + #| let s = z.sqrt() + #| let df = s + #| let c = (z - df * df) / (s + df) + #| let p = z * (ps0 + z * (ps1 + z * (ps2 + z * (ps3 + z * (ps4 + z * ps5))))) + #| let q = one + z * (qs1 + z * (qs2 + z * (qs3 + z * qs4))) + #| let r = p / q + #| let w = r * s + c + #| 2.0 * (df + w) + #| } + #|} + #|pub fn atan(x : Double) -> Double { + #| if x.is_nan() || x == 0.0 { + #| return x + #| } + #| let atan_hi : ReadOnlyArray[Double] = [ + #| 4.63647609000806093515e-01, 7.85398163397448278999e-01, 9.82793723247329054082e-01, + #| 1.57079632679489655800e+00, + #| ] + #| let atan_lo : ReadOnlyArray[Double] = [ + #| 2.26987774529616870924e-17, 3.06161699786838301793e-17, 1.39033110312309984516e-17, + #| 6.12323399573676603587e-17, + #| ] + #| let a_t : ReadOnlyArray[Double] = [ + #| 3.33333333333329318027e-01, -1.99999999998764832476e-01, 1.42857142725034663711e-01, + #| -1.11111104054623557880e-01, 9.09088713343650656196e-02, -7.69187620504482999495e-02, + #| 6.66107313738753120669e-02, -5.83357013379057348645e-02, 4.97687799461593236017e-02, + #| -3.65315727442169155270e-02, 1.62858201153657823623e-02, + #| ] + #| let one = 1.0 + #| let huge = 1.0e300 + #| let ix = get_high_word(x).reinterpret_as_int() & 0x7fffffff + #| let mut id = 0 + #| let mut z = 0.0 + #| let mut w = 0.0 + #| let mut x = x + #| let x_is_neg = x < 0.0 + #| if ix >= 0x44100000 { + #| if x > 0 { + #| return atan_hi[3] + atan_lo[3] + #| } else { + #| return -atan_hi[3] - atan_lo[3] + #| } + #| } + #| if ix < 0x3fdc0000 { + #| if ix < 0x3e200000 { + #| if huge + x > one { + #| return x + #| } + #| } + #| id = -1 + #| } else { + #| x = x.abs() + #| if ix < 0x3ff30000 { + #| if ix < 0x3fe60000 { + #| id = 0 + #| x = (2.0 * x - one) / (2.0 + x) + #| } else { + #| id = 1 + #| x = (x - one) / (x + one) + #| } + #| } else if ix < 0x40038000 { + #| id = 2 + #| x = (x - 1.5) / (one + 1.5 * x) + #| } else { + #| id = 3 + #| x = -1.0 / x + #| } + #| } + #| z = x * x + #| w = z * z + #| let s1 = z * + #| ( + #| a_t[0] + + #| w * (a_t[2] + w * (a_t[4] + w * (a_t[6] + w * (a_t[8] + w * a_t[10])))) + #| ) + #| let s2 = w * + #| (a_t[1] + w * (a_t[3] + w * (a_t[5] + w * (a_t[7] + w * a_t[9])))) + #| if id < 0 { + #| x - x * (s1 + s2) + #| } else { + #| z = atan_hi[id] - (x * (s1 + s2) - atan_lo[id] - x) + #| if x_is_neg { + #| -z + #| } else { + #| z + #| } + #| } + #|} + #|pub fn atan2(y : Double, x : Double) -> Double { + #| if x.is_nan() || y.is_nan() { + #| return @double.not_a_number + #| } + #| let tiny = 1.0e-300 + #| let zero = 0.0 + #| let pi_o_4 = 7.8539816339744827900E-01 + #| let pi_o_2 = 1.5707963267948965580E+00 + #| let pi = 3.1415926535897931160E+00 + #| let pi_lo = 1.2246467991473531772E-16 + #| let hx = get_high_word(x).reinterpret_as_int() + #| let hy = get_high_word(y).reinterpret_as_int() + #| let ix = hx & 0x7fffffff + #| let iy = hy & 0x7fffffff + #| if x == 1.0 { + #| return atan(y) + #| } + #| let m = ((hy >> 31) & 1) | ((hx >> 30) & 2) + #| if y == 0 { + #| match m { + #| 0 | 1 => return y + #| 2 => return pi + tiny + #| _ => return -pi - tiny + #| } + #| } + #| if x == 0 { + #| return if hy < 0 { -pi_o_2 - tiny } else { pi_o_2 + tiny } + #| } + #| if x.is_inf() { + #| if y.is_inf() { + #| match m { + #| 0 => return pi_o_4 + tiny + #| 1 => return -pi_o_4 - tiny + #| 2 => return 3.0 * pi_o_4 + tiny + #| _ => return -3.0 * pi_o_4 - tiny + #| } + #| } else { + #| match m { + #| 0 => return zero + #| 1 => return -zero + #| 2 => return pi + tiny + #| _ => return -pi - tiny + #| } + #| } + #| } + #| if y.is_inf() { + #| return if hy < 0 { -pi_o_2 - tiny } else { pi_o_2 + tiny } + #| } + #| let k = (iy - ix) >> 20 + #| let z = if k > 60 { + #| pi_o_2 + 0.5 * pi_lo + #| } else if hx < 0 && k < -60 { + #| 0.0 + #| } else { + #| atan(abs(y / x)) + #| } + #| match m { + #| 0 => z + #| 1 => -z + #| 2 => pi - (z - pi_lo) + #| _ => z - pi_lo - pi + #| } + #|} + #|fn rem_pio2(x : Double, y : Array[Double]) -> Int { + #| let hx = get_high_word(x).reinterpret_as_int() + #| let ix : Int = hx & 0x7fffffff + #| let mut z = 0.0 + #| if ix <= 0x3fe921fb { + #| y[0] = x + #| y[1] = 0.0 + #| return 0 + #| } + #| if ix < 0x4002d97c { + #| if hx > 0 { + #| z = x - PIO2_1 + #| if ix != 0x3ff921fb { + #| y[0] = z - PIO2_1T + #| y[1] = z - y[0] - PIO2_1T + #| } else { + #| z = z - PIO2_2 + #| y[0] = z - PIO2_2T + #| y[1] = z - y[0] - PIO2_2T + #| } + #| return 1 + #| } else { + #| z = x + PIO2_1 + #| if ix != 0x3ff921fb { + #| y[0] = z + PIO2_1T + #| y[1] = z - y[0] + PIO2_1T + #| } else { + #| let z = z + PIO2_2 + #| y[0] = z + PIO2_2T + #| y[1] = z - y[0] + PIO2_2T + #| } + #| return -1 + #| } + #| } + #| if ix <= 0x413921fb { + #| let t = x.abs() + #| let n = (t * INV_PIO2 + HALF).to_int() + #| let fn_ = n.to_double() + #| let mut r = t - fn_ * PIO2_1 + #| let mut w = fn_ * PIO2_1T + #| if n < 32 && ix != npio2_hw[n - 1] { + #| y[0] = r - w + #| } else { + #| let j = ix >> 20 + #| y[0] = r - w + #| let i = j - ((get_high_word(y[0]) >> 20).reinterpret_as_int() & 0x7ff) + #| if i > 16 { + #| let t = r + #| w = fn_ * PIO2_2 + #| r = t - w + #| w = fn_ * PIO2_2T - (t - r - w) + #| y[0] = r - w + #| let i = j - ((get_high_word(y[0]) >> 20).reinterpret_as_int() & 0x7ff) + #| if i > 49 { + #| let t = r + #| w = fn_ * PIO2_3 + #| r = t - w + #| w = fn_ * PIO2_3T - (t - r - w) + #| y[0] = r - w + #| } + #| } + #| } + #| y[1] = r - y[0] - w + #| if hx > 0 { + #| return n + #| } else { + #| y[0] = -y[0] + #| y[1] = -y[1] + #| return -n + #| } + #| } + #| if ix >= 0x7ff00000 { + #| y[0] = x - x + #| y[1] = y[0] + #| return 0 + #| } + #| z = set_low_word(z, get_low_word(x)) + #| let e0 = (ix >> 20) - 1046 // e0 = ilogb(z) - 23 + #| z = set_high_word(z, (ix - (e0 << 20)).reinterpret_as_uint()) + #| let tx = [0.0, 0.0, 0.0] + #| for i in 0..<2 { + #| tx[i] = z.to_int().to_double() + #| z = (z - tx[i]) * TWO24 + #| } + #| tx[2] = z + #| let mut nx = 3 + #| while tx[nx - 1] == 0.0 { + #| nx -= 1 + #| } + #| let n = __kernel_rem_pio2(tx, y, e0, nx, 2) + #| if hx > 0 { + #| n + #| } else { + #| y[0] = -y[0] + #| y[1] = -y[1] + #| -n + #| } + #|} + #|fn __kernel_rem_pio2( + #| x : Array[Double], + #| y : Array[Double], + #| e0 : Int, + #| nx : Int, + #| prec : Int, + #|) -> Int { + #| let init_jk : ReadOnlyArray[Int] = [2, 3, 4, 6] + #| let two24 : Double = 16777216.0 // 0x41700000, 0x00000000 + #| let twon24 : Double = 5.96046447753906250000e-08 // 0x3E700000, 0x00000000 + #| let mut jz : Int = 0 + #| let mut jx : Int = 0 + #| let mut jv : Int = 0 + #| let mut jp : Int = 0 + #| let mut jk : Int = 0 + #| let mut carry : Int = 0 + #| let mut n : Int = 0 + #| let iq : Array[Int] = Array::make(20, 0) + #| let mut i : Int = 0 + #| let mut j : Int = 0 + #| let mut k : Int = 0 + #| let mut m : Int = 0 + #| let mut q0 : Int = 0 + #| let mut ih : Int = 0 + #| let mut z : Double = 0 + #| let mut fw : Double = 0 + #| let f : Array[Double] = Array::make(20, 0.0) + #| let fq : Array[Double] = Array::make(20, 0.0) + #| let q : Array[Double] = Array::make(20, 0.0) + #| jk = init_jk[prec] + #| jp = jk + #| jx = nx - 1 + #| jv = (e0 - 3) / 24 + #| if jv < 0 { + #| jv = 0 + #| } + #| q0 = e0 - 24 * (jv + 1) + #| j = jv - jx + #| m = jx + jk + #| i = 0 + #| while i <= m { + #| f[i] = if j < 0 { 0.0 } else { two_over_pi[j].to_double() } + #| i += 1 + #| j += 1 + #| } + #| i = 0 + #| while i <= jk { + #| j = 0 + #| fw = 0.0 + #| while j <= jx { + #| fw += x[j] * f[jx + i - j] + #| j += 1 + #| } + #| q[i] = fw + #| i += 1 + #| } + #| jz = jk + #| let mut recompute = true + #| while recompute { + #| recompute = false + #| i = 0 + #| j = jz + #| z = q[jz] + #| while j > 0 { + #| fw = (twon24 * z).floor() + #| iq[i] = (z - two24 * fw).to_int() + #| z = q[j - 1] + fw + #| i += 1 + #| j -= 1 + #| } + #| z = scalbn(z, q0) // actual value of z + #| z -= 8.0 * (z * 0.125).floor() // trim off integer >= 8 + #| n = z.to_int() + #| z -= n.to_double() + #| ih = 0 + #| if q0 > 0 { + #| i = iq[jz - 1] >> (24 - q0) + #| n += i + #| iq[jz - 1] -= i << (24 - q0) + #| ih = iq[jz - 1] >> (23 - q0) + #| } else if q0 == 0 { + #| ih = iq[jz - 1] >> 23 + #| } else if z >= 0.5 { + #| ih = 2 + #| } + #| if ih > 0 { + #| n += 1 + #| carry = 0 + #| i = 0 + #| while i < jz { + #| j = iq[i] + #| if carry == 0 { + #| if j != 0 { + #| carry = 1 + #| iq[i] = 0x1000000 - j + #| } + #| } else { + #| iq[i] = 0xffffff - j + #| } + #| i += 1 + #| } + #| if q0 > 0 { + #| match q0 { + #| 1 => iq[jz - 1] = iq[jz - 1] & 0x7fffff + #| 2 => iq[jz - 1] = iq[jz - 1] & 0x3fffff + #| _ => () + #| } + #| } + #| if ih == 2 { + #| z = 1.0 - z + #| if carry != 0 { + #| z -= scalbn(1.0, q0) + #| } + #| } + #| } + #| if z == 0.0 { + #| j = 0 + #| i = jz - 1 + #| while i >= jk { + #| j = j | iq[i] + #| i -= 1 + #| } + #| if j == 0 { + #| k = 1 + #| while iq[jk - k] == 0 { + #| k += 1 + #| } + #| i = jz + 1 + #| while i <= jz + k { + #| f[jx + i] = two_over_pi[jv + i].to_double() + #| j = 0 + #| fw = 0.0 + #| while j <= jx { + #| fw += x[j] * f[jx + i - j] + #| j += 1 + #| } + #| q[i] = fw + #| i += 1 + #| } + #| jz += k + #| recompute = true // Continue to recompute + #| continue + #| } + #| } // Skip the rest of the loop and recompute + #| if z == 0.0 { + #| jz -= 1 + #| q0 -= 24 + #| while iq[jz] == 0 { + #| jz -= 1 + #| q0 -= 24 + #| } + #| } else { + #| z = scalbn(z, -q0) + #| if z >= two24 { + #| fw = (twon24 * z).floor() + #| iq[jz] = (z - two24 * fw).to_int() + #| jz += 1 + #| q0 += 24 + #| iq[jz] = fw.to_int() + #| } else { + #| iq[jz] = z.to_int() + #| } + #| } + #| fw = scalbn(1.0, q0) + #| i = jz + #| while i >= 0 { + #| q[i] = fw * iq[i].to_double() + #| fw *= twon24 + #| i -= 1 + #| } + #| i = jz + #| while i >= 0 { + #| fw = 0.0 + #| k = 0 + #| while k <= jp && k <= jz - i { + #| fw += pi_over_2[k] * q[i + k] + #| k += 1 + #| } + #| fq[jz - i] = fw + #| i -= 1 + #| } + #| match prec { + #| 0 => { + #| fw = 0.0 + #| i = jz + #| while i >= 0 { + #| fw += fq[i] + #| i -= 1 + #| } + #| y[0] = if ih == 0 { fw } else { -fw } + #| } + #| 1 | 2 => { + #| fw = 0.0 + #| i = jz + #| while i >= 0 { + #| fw += fq[i] + #| i -= 1 + #| } + #| y[0] = if ih == 0 { fw } else { -fw } + #| fw = fq[0] - fw + #| i = 1 + #| while i <= jz { + #| fw += fq[i] + #| i += 1 + #| } + #| y[1] = if ih == 0 { fw } else { -fw } + #| } + #| 3 => { + #| i = jz + #| while i > 0 { + #| fw = fq[i - 1] + fq[i] + #| fq[i] += fq[i - 1] - fw + #| fq[i - 1] = fw + #| i -= 1 + #| } + #| i = jz + #| while i > 1 { + #| fw = fq[i - 1] + fq[i] + #| fq[i] += fq[i - 1] - fw + #| fq[i - 1] = fw + #| i -= 1 + #| } + #| fw = 0.0 + #| i = jz + #| while i >= 2 { + #| fw += fq[i] + #| i -= 1 + #| } + #| if ih == 0 { + #| y[0] = fq[0] + #| y[1] = fq[1] + #| y[2] = fw + #| } else { + #| y[0] = -fq[0] + #| y[1] = -fq[1] + #| y[2] = -fw + #| } + #| } + #| _ => () + #| } + #| } + #| n & 7 + #|} + #|fn __kernel_sin(x : Double, y : Double, iy : Int) -> Double { + #| let s1 = -1.66666666666666324348e-01 + #| let s2 = 8.33333333332248946124e-03 + #| let s3 = -1.98412698298579493134e-04 + #| let s4 = 2.75573137070700676789e-06 + #| let s5 = -2.50507602534068634195e-08 + #| let s6 = 1.58969099521155010221e-10 + #| let mut z = 0.0 + #| let mut r = 0.0 + #| let mut v = 0.0 + #| let ix = get_high_word(x) & 0x7fffffff + #| if ix < 0x3e400000 { + #| if x.to_int() == 0 { + #| return x + #| } + #| } + #| z = x * x + #| v = z * x + #| r = s2 + z * (s3 + z * (s4 + z * (s5 + z * s6))) + #| if iy == 0 { + #| x + v * (s1 + z * r) + #| } else { + #| x - (z * (0.5 * y - v * r) - y - v * s1) + #| } + #|} + #|fn __kernel_cos(x : Double, y : Double) -> Double { + #| let one = 1.00000000000000000000e+00 + #| let c1 = 4.16666666666666019037e-02 + #| let c2 = -1.38888888888741095749e-03 + #| let c3 = 2.48015872894767294178e-05 + #| let c4 = -2.75573143513906633035e-07 + #| let c5 = 2.08757232129817482790e-09 + #| let c6 = -1.13596475577881948265e-11 + #| let mut a = 0.0 + #| let mut hz = 0.0 + #| let mut z = 0.0 + #| let mut r = 0.0 + #| let mut qx = 0.0 + #| let ix = get_high_word(x) & 0x7fffffff + #| if ix < 0x3e400000 { + #| if x.to_int() == 0 { + #| return one + #| } + #| } + #| z = x * x + #| r = z * (c1 + z * (c2 + z * (c3 + z * (c4 + z * (c5 + z * c6))))) + #| if ix < 0x3fd33333 { + #| return one - (0.5 * z - (z * r - x * y)) + #| } else { + #| if ix > 0x3fe90000 { + #| qx = 0.28125 + #| } else { + #| qx = ((ix - 0x00200000).to_uint64() << 32).reinterpret_as_double() + #| } + #| hz = 0.5 * z - qx + #| a = one - qx + #| return a - (hz - (z * r - x * y)) + #| } + #|} + #|fn __kernal_tan(x : Double, y : Double, iy : Int) -> Double { + #| let one = 1.0 + #| let pio4 = 7.85398163397448278999e-01 + #| let pio4lo = 3.06161699786838301793e-17 + #| let mut x = x + #| let mut y = y + #| let mut z = 0.0 + #| let mut r = 0.0 + #| let mut v = 0.0 + #| let mut w = 0.0 + #| let mut s = 0.0 + #| let t : ReadOnlyArray[Double] = [ + #| 3.33333333333334091986e-01, // 3FD55555, 55555563 */ + #| 1.33333333333201242699e-01, // 3FC11111, 1110FE7A */ + #| 5.39682539762260521377e-02, // 3FABA1BA, 1BB341FE */ + #| 2.18694882948595424599e-02, // 3F9664F4, 8406D637 */ + #| 8.86323982359930005737e-03, // 3F8226E3, E96E8493 */ + #| 3.59207910759131235356e-03, // 3F6D6D22, C9560328 */ + #| 1.45620945432529025516e-03, // 3F57DBC8, FEE08315 */ + #| 5.88041240820264096874e-04, // 3F4344D8, F2F26501 */ + #| 2.46463134818469906812e-04, // 3F3026F7, 1A8D1068 */ + #| 7.81794442939557092300e-05, // 3F147E88, A03792A6 */ + #| 7.14072491382608190305e-05, // 3F12B80F, 32F0A7E9 */ + #| -1.85586374855275456654e-05, // BEF375CB, DB605373 */ + #| 2.59073051863633712884e-05, // 3EFB2A70, 74BF7AD4 */ + #| 1.00000000000000000000e+00, // 3FF00000, 00000000 (one) */ + #| 7.85398163397448278999e-01, // 3FE921FB, 54442D18 (pio4) */ + #| 3.06161699786838301793e-17, // 3C81A626, 33145C07 (pio4lo) */ + #| ] + #| let hx = get_high_word(x).reinterpret_as_int() + #| let ix = hx & 0x7fffffff + #| if ix < 0x3e300000 { + #| if x.to_int() == 0 { + #| if (ix | get_low_word(x).reinterpret_as_int() | (iy + 1)) == 0 { + #| return one / x.abs() + #| } else if iy == 1 { + #| return x + #| } else { + #| w = x + y + #| z = w + #| z = set_low_word(z, 0) + #| v = y - (z - x) + #| let a = -one / w + #| let mut t = a + #| t = set_low_word(t, 0) + #| s = one + t * z + #| return t + a * (s + t * v) + #| } + #| } + #| } + #| if ix >= 0x3fe59428 { + #| if hx < 0 { + #| x = -x + #| y = -y + #| } + #| z = pio4 - x + #| w = pio4lo - y + #| x = z + w + #| y = 0.0 + #| } + #| z = x * x + #| w = z * z + #| r = t[1] + w * (t[3] + w * (t[5] + w * (t[7] + w * (t[9] + w * t[11])))) + #| v = z * + #| (t[2] + w * (t[4] + w * (t[6] + w * (t[8] + w * (t[10] + w * t[12]))))) + #| s = z * x + #| r = y + z * (s * (r + v) + y) + #| r += t[0] * s + #| w = x + r + #| if ix >= 0x3fe59428 { + #| v = iy.to_double() + #| return (1 - ((hx >> 30) & 2)).to_double() * + #| (v - 2.0 * (x - (w * w / (w + v) - r))) + #| } + #| if iy == 1 { + #| w + #| } else { + #| z = w + #| z = set_low_word(z, 0) + #| v = r - (z - x) + #| let a = -1.0 / w + #| let mut t = a + #| t = set_low_word(t, 0) + #| s = 1.0 + t * z + #| t + a * (s + t * v) + #| } + #|} + ), + "trig_double_sincos_native.mbt": ( + #|pub extern "C" fn sin(x : Double) -> Double = "sin" + #|pub extern "C" fn cos(x : Double) -> Double = "cos" + ), + "trig_double_sincos_non_native_or_js.mbt": ( + #|pub fn sin(x : Double) -> Double { + #| if x.is_inf() || x.is_nan() { + #| return @double.not_a_number + #| } + #| let y = [0.0, 0.0] + #| let z = 0.0 + #| if x.abs() <= PI_OVER_4 { + #| return __kernel_sin(x, z, 0) + #| } else { + #| let n = rem_pio2(x, y) + #| match n & 3 { + #| 0 => __kernel_sin(y[0], y[1], 1) + #| 1 => __kernel_cos(y[0], y[1]) + #| 2 => -__kernel_sin(y[0], y[1], 1) + #| _ => -__kernel_cos(y[0], y[1]) + #| } + #| } + #|} + #|pub fn cos(x : Double) -> Double { + #| if x.is_inf() || x.is_nan() { + #| return @double.not_a_number + #| } + #| let y = [0.0, 0.0] + #| let z = 0.0 + #| if x.abs() <= PI_OVER_4 { + #| return __kernel_cos(x, z) + #| } else { + #| let n = rem_pio2(x, y) + #| match n & 3 { + #| 0 => __kernel_cos(y[0], y[1]) + #| 1 => -__kernel_sin(y[0], y[1], 1) + #| 2 => -__kernel_cos(y[0], y[1]) + #| _ => __kernel_sin(y[0], y[1], 1) + #| } + #| } + #|} + ), + "utils.mbt": ( + #|fn abs(x : Double) -> Double { + #| if x < 0.0 { + #| -x + #| } else { + #| x + #| } + #|} + #|let two_over_pi : ReadOnlyArray[Int] = [ + #| 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 0x95993C, 0x439041, + #| 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, + #| 0xFE1DEB, 0x1CB129, 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, + #| 0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, 0x97FFDE, 0x05980F, + #| 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, + #| 0x7527BA, 0xC7EBE5, 0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, + #| 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, 0x91615E, 0xE61B08, + #| 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, 0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, + #| 0x60E27B, 0xC08C6B, + #|] + #|let pi_over_2 : ReadOnlyArray[Double] = [ + #| 1.57079625129699707031e+00, // 0x3FF921FB, 0x40000000 */ + #| 7.54978941586159635335e-08, // 0x3E74442D, 0x00000000 */ + #| 5.39030252995776476554e-15, // 0x3CF84698, 0x80000000 */ + #| 3.28200341580791294123e-22, // 0x3B78CC51, 0x60000000 */ + #| 1.27065575308067607349e-29, // 0x39F01B83, 0x80000000 */ + #| 1.22933308981111328932e-36, // 0x387A2520, 0x40000000 */ + #| 2.73370053816464559624e-44, // 0x36E38222, 0x80000000 */ + #| 2.16741683877804819444e-51, // 0x3569F31D, 0x00000000 */ + #|] + #|let npio2_hw : ReadOnlyArray[Int] = [ + #| 0x3FF921FB, 0x400921FB, 0x4012D97C, 0x401921FB, 0x401F6A7A, 0x4022D97C, 0x4025FDBB, + #| 0x402921FB, 0x402C463A, 0x402F6A7A, 0x4031475C, 0x4032D97C, 0x40346B9C, 0x4035FDBB, + #| 0x40378FDB, 0x403921FB, 0x403AB41B, 0x403C463A, 0x403DD85A, 0x403F6A7A, 0x40407E4C, + #| 0x4041475C, 0x4042106C, 0x4042D97C, 0x4043A28C, 0x40446B9C, 0x404534AC, 0x4045FDBB, + #| 0x4046C6CB, 0x40478FDB, 0x404858EB, 0x404921FB, + #|] + #|const PI_OVER_4 : Double = 0.785398163397448309616 + #|const PIO2_1 : Double = 1.5707963267341256e+00 // 0x3FF921FB, 0x54400000 */ + #|const PIO2_1T : Double = 6.0771005065061922e-11 // 0x3DD0B461, 0x1A600000 */ + #|const PIO2_2 : Double = 6.0771005063039660e-11 // 0x3DD0B461, 0x1A600000 */ + #|const PIO2_2T : Double = 2.0222662487959506e-21 // 0x3BA3198A, 0x2E037073 */ + #|const PIO2_3 : Double = 2.0222662487111665e-21 // 0x3BA3198A, 0x2E037073 */ + #|const PIO2_3T : Double = 8.4784276603688996e-32 // 0x397B839A, 0x252049C1 */ + #|const INV_PIO2 : Double = 6.3661977236758138e-01 // 0x3FE45F30, 0x6DC9C883 */ + #|const HALF : Double = 0.5 + #|const TWO24 : Double = 16777216.0 // 0x41700000, 0x00000000 */ + #|fn set_low_word(d : Double, v : UInt) -> Double { + #| let bits : UInt64 = d.reinterpret_as_uint64() + #| let bits = bits & 0xFFFF_FFFF_0000_0000 + #| let bits = bits | v.to_uint64() + #| bits.reinterpret_as_double() + #|} + #|fn set_high_word(d : Double, v : UInt) -> Double { + #| let bits : UInt64 = d.reinterpret_as_uint64() + #| let bits = bits & 0x0000_0000_FFFF_FFFF + #| let bits = bits | (v.to_uint64() << 32) + #| bits.reinterpret_as_double() + #|} + #|fn get_high_word(x : Double) -> UInt { + #| (x.reinterpret_as_uint64() >> 32).to_uint() + #|} + #|fn get_low_word(x : Double) -> UInt { + #| x.reinterpret_as_uint64().to_uint() + #|} + #|const SQRT2 = 1.41421356237309504880168872420969807856967187537694807317667974 + #|const LN2 = 0.693147180559945309417232121458176568075500134360255254120680009 + #|const LN2_HI = 6.93147180369123816490e-01 // 3fe62e42 fee00000 + #|const LN2_LO = 1.90821492927058770002e-10 // 3dea39ef 35793c76 + #|fn normalize(f : Double) -> (Double, Int) { + #| if f.abs() < @double.min_positive { + #| return (f * (1L << 52).to_double(), -52) + #| } + #| (f, 0) + #|} + #|fn frexp(f : Double) -> (Double, Int) { + #| if f == 0.0 || f.is_inf() || f.is_nan() { + #| return (f, 0) + #| } + #| let (norm_f, exp) = normalize(f) + #| let u = norm_f.reinterpret_as_uint64() + #| let exp = exp + ((u >> 52) & 0x7FF).to_int() - 1022 + #| let frac = ((u & (0x7FFUL << 52).lnot()) | (1022UL << 52)).reinterpret_as_double() + #| return (frac, exp) + #|} + ) + } ) ///| let moonbitlang_core_option_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/option", - deps={ "moonbitlang/core/builtin": moonbitlang_core_builtin_module }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| "moonbitlang/core/builtin" - #| ], - #| "test-import" : [ - #| "moonbitlang/core/quickcheck", - #| "moonbitlang/core/json", - #| "moonbitlang/core/array" - #| ], - #| "targets": { - #| "panic_test.mbt": ["not", "native", "llvm"] - #| } - #|} - ), - "deprecated.mbt": ( - #|#deprecated("Use `if condition { Some(value()) } else { None }` instead") - #|pub fn[T] when(condition : Bool, value : () -> T) -> T? { - #| if condition { - #| Some(value()) - #| } else { - #| None - #| } - #|} - #|#deprecated("Use `if !condition { Some(value()) } else { None }` instead") - #|pub fn[T] unless(condition : Bool, value : () -> T) -> T? { - #| if !condition { - #| Some(value()) - #| } else { - #| None - #| } - #|} - #|#deprecated("Use `None` instead") - #|pub fn[T] empty() -> T? { - #| None - #|} - #|#deprecated("Use `Some(value)` instead") - #|pub fn[T] some(value : T) -> T? { - #| Some(value) - #|} - ), - "methods.mbt": "", - "option.mbt": "", - }, + "deprecated.mbt": ( + #|#deprecated("Use `if condition { Some(value()) } else { None }` instead") + #|pub fn[T] when(condition : Bool, value : () -> T) -> T? { + #| if condition { + #| Some(value()) + #| } else { + #| None + #| } + #|} + #|#deprecated("Use `if !condition { Some(value()) } else { None }` instead") + #|pub fn[T] unless(condition : Bool, value : () -> T) -> T? { + #| if !condition { + #| Some(value()) + #| } else { + #| None + #| } + #|} + #|#deprecated("Use `None` instead") + #|pub fn[T] empty() -> T? { + #| None + #|} + #|#deprecated("Use `Some(value)` instead") + #|pub fn[T] some(value : T) -> T? { + #| Some(value) + #|} + ), + "methods.mbt": "", + "option.mbt": "" + } ) ///| let moonbitlang_core_prelude_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/prelude", - deps={ - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/bigint": moonbitlang_core_bigint_module, - "moonbitlang/core/set": moonbitlang_core_set_module, - "moonbitlang/core/json": moonbitlang_core_json_module, - }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| "moonbitlang/core/builtin", - #| "moonbitlang/core/bigint", - #| "moonbitlang/core/set", - #| "moonbitlang/core/json" - #| ], - #| "warn-list": "-test_unqualified_package" - #|} - ), - "prelude.mbt": ( - #|pub using @set {type Set} - #|pub using @bigint {type BigInt} - #|pub using @builtin { - #| abort, - #| assert_eq, - #| assert_not_eq, - #| assert_true, - #| assert_false, - #| fail, - #| ignore, - #| inspect, - #| panic, - #| physical_equal, - #| println, - #| not, - #| repr, - #| dump, - #| trait Eq, - #| trait Compare, - #| trait Hash, - #| trait Logger, - #| trait Show, - #| trait ToJson, - #| trait Default, - #| trait Add, - #| trait Sub, - #| trait Mul, - #| trait Div, - #| trait Mod, - #| trait Neg, - #| trait Shl, - #| trait Shr, - #| trait BitAnd, - #| trait BitOr, - #| trait BitXOr, - #| type ArgsLoc, - #| type Array, - #| type ArrayView, - #| type MutArrayView, - #| type UninitializedArray, - #| type Failure, - #| type Hasher, - #| type Iter, - #| type Iterator, - #| type Iter2, - #| type Iter2, - #| type IterResult, - #| type Json, - #| type Map, - #| type InspectError, - #| type SnapshotError, - #| type SourceLoc, - #| type StringBuilder, - #|} - #|pub fn[T] tap(value : T, f : (T) -> Unit raise) -> T raise { - #| f(value) - #| value - #|} - #|pub fn[T, R] then(value : T, f : (T) -> R raise?) -> R raise? { - #| f(value) - #|} - #|pub let null : Json = @builtin.null - #|pub using @json {trait FromJson} - ), - }, + "prelude.mbt": ( + #|pub using @set {type Set} + #|pub using @bigint {type BigInt} + #|pub using @builtin { + #| abort, + #| assert_eq, + #| assert_not_eq, + #| assert_true, + #| assert_false, + #| debug_assert, + #| fail, + #| ignore, + #| inspect, + #| panic, + #| physical_equal, + #| println, + #| trait Eq, + #| trait Compare, + #| trait Hash, + #| trait Logger, + #| trait Show, + #| trait ToJson, + #| trait Default, + #| trait Add, + #| trait Sub, + #| trait Mul, + #| trait Div, + #| trait Mod, + #| trait Neg, + #| trait Shl, + #| trait Shr, + #| trait BitAnd, + #| trait BitOr, + #| trait BitXOr, + #| type ArgsLoc, + #| type Array, + #| type ArrayView, + #| type MutArrayView, + #| type UninitializedArray, + #| type Failure, + #| type Hasher, + #| type Iter, + #| type Iter2, + #| type Json, + #| type Map, + #| type InspectError, + #| type SnapshotError, + #| type SourceLoc, + #| type StringBuilder, + #|} + #|#deprecated("Use !expr instead") + #|#warnings("-deprecated") + #|pub using @builtin {not} + #|#deprecated("use `to_repr` for debugging representation") + #|#warnings("-deprecated") + #|pub using @builtin {repr} + #|#deprecated + #|#warnings("-deprecated") + #|pub using @builtin {type IterResult} + #|pub using @debug {debug, type Repr, trait Debug, debug_inspect, to_repr} + #|#deprecated("for debugging only, not for production") + #|#warnings("-deprecated") + #|pub using @debug {dump} + #|pub using @string {type Regex} + #|#deprecated("use `value |> x => { ... ; x} instead") + #|pub fn[T] tap(value : T, f : (T) -> Unit raise) -> T raise { + #| f(value) + #| value + #|} + #|#deprecated("use `value |> (x) => {...}` operator instead") + #|pub fn[T, R] then(value : T, f : (T) -> R raise?) -> R raise? { + #| f(value) + #|} + #|pub let null : Json = @builtin.null + #|pub using @json {trait FromJson, json_inspect} + #|#deprecated("The name `Iterator` is deprecated, use `Iter` instead. Note that if you have defined `iterator()` method to support `for .. in` loop, you should also rename `iterator()` to `iter()`. See https://github.com/moonbitlang/core/pull/3127 for more details.") + #|pub type Iterator[X] = Iter[X] + #|#deprecated("The name `Iterator2` is deprecated, use `Iter2` instead. Note that if you have defined `iterator2()` method to support `for .. in` loop, you should also rename `iterator2()` to `iter2()`. See https://github.com/moonbitlang/core/pull/3127 for more details.") + #|pub type Iterator2[X, Y] = Iter2[X, Y] + #|pub using @ref {type Ref} + ) + } ) ///| let moonbitlang_core_priority_queue_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/priority_queue", - deps={ - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/array": moonbitlang_core_array_module, - "moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module, - "moonbitlang/core/quickcheck/splitmix": moonbitlang_core_quickcheck_splitmix_module, - "moonbitlang/core/json": moonbitlang_core_json_module, - }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| "moonbitlang/core/builtin", - #| "moonbitlang/core/array", - #| "moonbitlang/core/quickcheck", - #| "moonbitlang/core/quickcheck/splitmix", - #| "moonbitlang/core/json" - #| ], - #| "test-import": ["moonbitlang/core/random", "moonbitlang/core/cmp"], - #| "targets": { - #| "panic_test.mbt": ["not", "native", "llvm"] - #| } - #|} - ), - "priority_queue.mbt": ( - #|#as_free_fn - #|pub fn[A] PriorityQueue::new() -> PriorityQueue[A] { - #| { len: 0, top: None } - #|} - #|#as_free_fn - #|#alias(of, deprecated="Use from_array instead") - #|#as_free_fn(of, deprecated="Use from_array instead") - #|pub fn[A : Compare] PriorityQueue::from_array( - #| arr : ArrayView[A], - #|) -> PriorityQueue[A] { - #| guard arr is [a0, ..] else { return new() } - #| let len = arr.length() - #| for i = 1, acc = { content: a0, sibling: None, child: None } { - #| if i < len { - #| continue i + 1, meld(acc, { content: arr[i], sibling: None, child: None }) - #| } else { - #| break { len, top: Some(acc) } - #| } - #| } - #|} - #|fn[A] copy_node(x : Node[A]?) -> Node[A]? { - #| match x { - #| None => None - #| Some(node) => - #| Some({ - #| content: node.content, - #| sibling: copy_node(node.sibling), - #| child: copy_node(node.child), - #| }) - #| } - #|} - #|pub fn[A] PriorityQueue::copy(self : PriorityQueue[A]) -> PriorityQueue[A] { - #| let new_que : PriorityQueue[A] = { len: self.len, top: copy_node(self.top) } - #| new_que - #|} - #|pub fn[A : Compare] PriorityQueue::to_array( - #| self : PriorityQueue[A], - #|) -> Array[A] { - #| let arr = Array::new(capacity=self.len) - #| let stack : Array[Node[A]?] = [self.top] - #| while stack.pop() is Some(node) { - #| match node { - #| None => () - #| Some({ content, sibling, child }) => { - #| arr.push(content) - #| stack.push(sibling) - #| stack.push(child) - #| } - #| } - #| } - #| arr.sort() - #| arr.rev_in_place() - #| arr - #|} - #|pub fn[A : Compare] PriorityQueue::iter(self : PriorityQueue[A]) -> Iter[A] { - #| self.iterator().iter() - #|} - #|pub fn[A : Compare] PriorityQueue::iterator( - #| self : PriorityQueue[A], - #|) -> Iterator[A] { - #| self.to_array().iterator() - #|} - #|pub impl[A : ToJson + Compare] ToJson for PriorityQueue[A] with to_json(self) { - #| let arr = [] - #| for x in self { - #| arr.push(x.to_json()) - #| } - #| Json::array(arr) - #|} - #|#as_free_fn - #|pub fn[K : Compare] PriorityQueue::from_iter( - #| iter : Iter[K], - #|) -> PriorityQueue[K] { - #| let s = new() - #| iter.each(e => s.push(e)) - #| s - #|} - #|#as_free_fn - #|pub fn[K : Compare] PriorityQueue::from_iterator( - #| iter : Iterator[K], - #|) -> PriorityQueue[K] { - #| let s = new() - #| while iter.next() is Some(e) { - #| s.push(e) - #| } - #| s - #|} - #|fn[A : Compare] meld(x : Node[A], y : Node[A]) -> Node[A] { - #| if x.content > y.content { - #| y.sibling = x.child - #| x.child = Some(y) - #| x - #| } else { - #| x.sibling = y.child - #| y.child = Some(x) - #| y - #| } - #|} - #|fn[A : Compare] merges(x : Node[A]?) -> Node[A]? { - #| let (x, acc) = match x { - #| None => return None - #| Some({ sibling: None, .. }) as x => return x - #| Some({ sibling: Some({ sibling: s2, .. } as s1), .. } as x) => { - #| x.sibling = None - #| s1.sibling = None - #| (s2, meld(x, s1)) - #| } - #| } - #| loop (x, acc) { - #| (None, acc) => Some(acc) - #| (Some({ sibling: None, .. } as x), acc) => Some(meld(acc, x)) - #| (Some({ sibling: Some({ sibling: s2, .. } as s1), .. } as x), acc) => { - #| x.sibling = None - #| s1.sibling = None - #| continue (s2, meld(acc, meld(x, s1))) - #| } - #| } - #|} - #|pub fn[A] PriorityQueue::length(self : PriorityQueue[A]) -> Int { - #| self.len - #|} - #|#internal(unsafe, "Panic if the queue is empty.") - #|#doc(hidden) - #|pub fn[A : Compare] PriorityQueue::unsafe_pop(self : PriorityQueue[A]) -> Unit { - #| self.top = match self.top { - #| None => abort("The PriorityQueue is empty!") - #| Some({ child, .. }) => merges(child) - #| } - #| self.len -= 1 - #|} - #|pub fn[A : Compare] PriorityQueue::pop(self : PriorityQueue[A]) -> A? { - #| match self.top { - #| None => None - #| Some({ content, child, .. }) => { - #| self.len -= 1 - #| self.top = merges(child) - #| Some(content) - #| } - #| } - #|} - #|pub fn[A : Compare] PriorityQueue::push( - #| self : PriorityQueue[A], - #| value : A, - #|) -> Unit { - #| let x = { content: value, sibling: None, child: None } - #| self.top = match self.top { - #| None => Some(x) - #| Some(top) => Some(meld(top, x)) - #| } - #| self.len += 1 - #|} - #|pub fn[A] PriorityQueue::peek(self : PriorityQueue[A]) -> A? { - #| match self.top { - #| None => None - #| Some({ content, .. }) => Some(content) - #| } - #|} - #|pub fn[A] PriorityQueue::clear(self : PriorityQueue[A]) -> Unit { - #| self.top = None - #| self.len = 0 - #|} - #|pub fn[A] PriorityQueue::is_empty(self : PriorityQueue[A]) -> Bool { - #| self.len == 0 - #|} - #|pub impl[A : Show + Compare] Show for PriorityQueue[A] with output(self, logger) { - #| logger.write_iter( - #| self.iter(), - #| prefix="@priority_queue.from_array([", - #| suffix="])", - #| ) - #|} - #|pub impl[X : @quickcheck.Arbitrary + Compare] @quickcheck.Arbitrary for PriorityQueue[ - #| X, - #|] with arbitrary(size, rs) { - #| let len = if size == 0 { 0 } else { rs.next_positive_int() % size } - #| guard len > 0 else { return new() } - #| for i = 1, acc = { content: X::arbitrary(0, rs), sibling: None, child: None } { - #| if i < len { - #| continue i + 1, - #| meld(acc, { content: X::arbitrary(i, rs), sibling: None, child: None }) - #| } else { - #| break { len, top: Some(acc) } - #| } - #| } - #|} - #|test "priority queue arbitrary" { - #| let samples : Array[PriorityQueue[Int]] = @quickcheck.samples(20) - #| inspect( - #| samples[5:10], - #| content="[@priority_queue.from_array([]), @priority_queue.from_array([]), @priority_queue.from_array([0]), @priority_queue.from_array([0, 0]), @priority_queue.from_array([3, 2, 1, 0, 0, 0, 0])]", - #| ) - #| inspect( - #| samples[11:15], - #| content="[@priority_queue.from_array([0, 0, 0, -1, -2]), @priority_queue.from_array([8, 4, 0, 0, 0, 0, 0, 0, -2, -5]), @priority_queue.from_array([2, 0, 0, -1]), @priority_queue.from_array([0, 0])]", - #| ) - #|} - #|pub impl[K] Default for PriorityQueue[K] with default() { - #| new() - #|} - ), - "types.mbt": ( - #|priv struct Node[A] { - #| content : A - #| mut sibling : Node[A]? - #| mut child : Node[A]? - #|} - #|#alias(T, deprecated="Use PriorityQueue instead") - #|struct PriorityQueue[A] { - #| mut len : Int - #| mut top : Node[A]? - #|} - ), - }, + "priority_queue.mbt": ( + #|#as_free_fn + #|pub fn[A] PriorityQueue::new() -> PriorityQueue[A] { + #| { len: 0, top: None } + #|} + #|#as_free_fn + #|#alias(of, deprecated="Use from_array instead") + #|#as_free_fn(of, deprecated="Use from_array instead") + #|pub fn[A : Compare] PriorityQueue::from_array( + #| arr : ArrayView[A], + #|) -> PriorityQueue[A] { + #| guard arr is [a0, ..] else { return new() } + #| let len = arr.length() + #| for i = 1, acc = { content: a0, sibling: None, child: None } { + #| if i < len { + #| continue i + 1, meld(acc, { content: arr[i], sibling: None, child: None }) + #| } else { + #| break { len, top: Some(acc) } + #| } + #| } + #|} + #|fn[A] copy_node(x : Node[A]?) -> Node[A]? { + #| match x { + #| None => None + #| Some(root) => { + #| let cloned_root : Node[A] = { + #| content: root.content, + #| sibling: None, + #| child: None, + #| } + #| let stack : Array[(Node[A], Node[A])] = [(root, cloned_root)] + #| while stack.pop() is Some((orig, clone)) { + #| if orig.child is Some(child) { + #| let cloned_child : Node[A] = { + #| content: child.content, + #| sibling: None, + #| child: None, + #| } + #| clone.child = Some(cloned_child) + #| stack.push((child, cloned_child)) + #| } + #| if orig.sibling is Some(sib) { + #| let cloned_sib : Node[A] = { + #| content: sib.content, + #| sibling: None, + #| child: None, + #| } + #| clone.sibling = Some(cloned_sib) + #| stack.push((sib, cloned_sib)) + #| } + #| } + #| Some(cloned_root) + #| } + #| } + #|} + #|#alias(clone, deprecated) + #|pub fn[A] PriorityQueue::copy(self : PriorityQueue[A]) -> PriorityQueue[A] { + #| { len: self.len, top: copy_node(self.top) } + #|} + #|pub fn[A : Compare] PriorityQueue::to_array( + #| self : PriorityQueue[A], + #|) -> Array[A] { + #| let arr = Array::new(capacity=self.len) + #| let stack : Array[Node[A]?] = [self.top] + #| while stack.pop() is Some(node) { + #| match node { + #| None => () + #| Some({ content, sibling, child }) => { + #| arr.push(content) + #| stack.push(sibling) + #| stack.push(child) + #| } + #| } + #| } + #| arr.sort() + #| arr.rev_in_place() + #| arr + #|} + #|#alias(iterator, deprecated) + #|pub fn[A : Compare] PriorityQueue::iter(self : PriorityQueue[A]) -> Iter[A] { + #| self.to_array().iter() + #|} + #|pub impl[A : ToJson + Compare] ToJson for PriorityQueue[A] with to_json(self) { + #| let arr = [] + #| for x in self { + #| arr.push(x.to_json()) + #| } + #| Json::array(arr) + #|} + #|#as_free_fn + #|#alias(from_iterator, deprecated) + #|#as_free_fn(from_iterator, deprecated) + #|pub fn[K : Compare] PriorityQueue::from_iter( + #| iter : Iter[K], + #|) -> PriorityQueue[K] { + #| let s = new() + #| while iter.next() is Some(e) { + #| s.push(e) + #| } + #| s + #|} + #|fn[A : Compare] meld(x : Node[A], y : Node[A]) -> Node[A] { + #| if x.content > y.content { + #| y.sibling = x.child + #| x.child = Some(y) + #| x + #| } else { + #| x.sibling = y.child + #| y.child = Some(x) + #| y + #| } + #|} + #|fn[A : Compare] merges(x : Node[A]?) -> Node[A]? { + #| let (x, acc) = match x { + #| None => return None + #| Some({ sibling: None, .. }) as x => return x + #| Some({ sibling: Some({ sibling: s2, .. } as s1), .. } as x) => { + #| x.sibling = None + #| s1.sibling = None + #| (s2, meld(x, s1)) + #| } + #| } + #| loop (x, acc) { + #| (None, acc) => Some(acc) + #| (Some({ sibling: None, .. } as x), acc) => Some(meld(acc, x)) + #| (Some({ sibling: Some({ sibling: s2, .. } as s1), .. } as x), acc) => { + #| x.sibling = None + #| s1.sibling = None + #| continue (s2, meld(acc, meld(x, s1))) + #| } + #| } + #|} + #|pub fn[A] PriorityQueue::length(self : PriorityQueue[A]) -> Int { + #| self.len + #|} + #|#internal(unsafe, "Panic if the queue is empty.") + #|#doc(hidden) + #|pub fn[A : Compare] PriorityQueue::unsafe_pop(self : PriorityQueue[A]) -> Unit { + #| self.top = match self.top { + #| None => abort("The PriorityQueue is empty!") + #| Some({ child, .. }) => merges(child) + #| } + #| self.len -= 1 + #|} + #|pub fn[A : Compare] PriorityQueue::pop(self : PriorityQueue[A]) -> A? { + #| match self.top { + #| None => None + #| Some({ content, child, .. }) => { + #| self.len -= 1 + #| self.top = merges(child) + #| Some(content) + #| } + #| } + #|} + #|pub fn[A : Compare] PriorityQueue::push( + #| self : PriorityQueue[A], + #| value : A, + #|) -> Unit { + #| let x = { content: value, sibling: None, child: None } + #| self.top = match self.top { + #| None => Some(x) + #| Some(top) => Some(meld(top, x)) + #| } + #| self.len += 1 + #|} + #|pub fn[A] PriorityQueue::peek(self : PriorityQueue[A]) -> A? { + #| match self.top { + #| None => None + #| Some({ content, .. }) => Some(content) + #| } + #|} + #|pub fn[A] PriorityQueue::clear(self : PriorityQueue[A]) -> Unit { + #| self.top = None + #| self.len = 0 + #|} + #|pub fn[A] PriorityQueue::is_empty(self : PriorityQueue[A]) -> Bool { + #| self.len == 0 + #|} + #|pub impl[A : Show + Compare] Show for PriorityQueue[A] with output(self, logger) { + #| logger.write_iter( + #| self.iter(), + #| prefix="@priority_queue.from_array([", + #| suffix="])", + #| ) + #|} + #|pub impl[X : @quickcheck.Arbitrary + Compare] @quickcheck.Arbitrary for PriorityQueue[ + #| X, + #|] with arbitrary(size, rs) { + #| let len = if size == 0 { 0 } else { rs.next_positive_int() % size } + #| guard len > 0 else { return new() } + #| for i = 1, acc = { content: X::arbitrary(0, rs), sibling: None, child: None } { + #| if i < len { + #| continue i + 1, + #| meld(acc, { content: X::arbitrary(i, rs), sibling: None, child: None }) + #| } else { + #| break { len, top: Some(acc) } + #| } + #| } + #|} + #|test "priority queue arbitrary" { + #| let samples : Array[PriorityQueue[Int]] = @quickcheck.samples(20) + #| inspect( + #| samples[5:10], + #| content="[@priority_queue.from_array([]), @priority_queue.from_array([]), @priority_queue.from_array([0]), @priority_queue.from_array([0, 0]), @priority_queue.from_array([3, 2, 1, 0, 0, 0, 0])]", + #| ) + #| inspect( + #| samples[11:15], + #| content="[@priority_queue.from_array([0, 0, 0, -1, -2]), @priority_queue.from_array([8, 4, 0, 0, 0, 0, 0, 0, -2, -5]), @priority_queue.from_array([2, 0, 0, -1]), @priority_queue.from_array([0, 0])]", + #| ) + #|} + #|pub impl[K] Default for PriorityQueue[K] with default() { + #| new() + #|} + ), + "types.mbt": ( + #|priv struct Node[A] { + #| content : A + #| mut sibling : Node[A]? + #| mut child : Node[A]? + #|} + #|#alias(T, deprecated="Use PriorityQueue instead") + #|struct PriorityQueue[A] { + #| mut len : Int + #| mut top : Node[A]? + #|} + ) + } ) ///| let moonbitlang_core_queue_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/queue", - deps={ - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module, - }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": ["moonbitlang/core/builtin", "moonbitlang/core/quickcheck"], - #| "test-import": ["moonbitlang/core/array"], - #| "targets": { - #| "panic_test.mbt": ["not", "native", "llvm"] - #| } - #|} - ), - "deprecated.mbt": "", - "queue.mbt": ( - #|#as_free_fn - #|pub fn[A] Queue::new() -> Queue[A] { - #| { length: 0, first: None, last: None } - #|} - #|#as_free_fn - #|#alias(of, deprecated="Use from_array instead") - #|#as_free_fn(of, deprecated="Use from_array instead") - #|pub fn[A] Queue::from_array(arr : ArrayView[A]) -> Queue[A] { - #| guard arr.length() > 0 else { return new() } - #| let length = arr.length() - #| let last = { content: arr[length - 1], next: None } - #| let first = for i = length - 2, x = last; i >= 0; { - #| continue i - 1, { content: arr[i], next: Some(x) } - #| } else { - #| x - #| } - #| { length, first: Some(first), last: Some(last) } - #|} - #|pub impl[A : Show] Show for Queue[A] with output(self, logger) { - #| logger.write_iter(self.iter(), prefix="@queue.from_array([", suffix="])") - #|} - #|impl[A : Eq] Eq for Queue[A] with equal(self, other) { - #| self.length == other.length && self.first == other.first - #|} - #|pub fn[A] Queue::clear(self : Queue[A]) -> Unit { - #| self.length = 0 - #| self.first = None - #| self.last = None - #|} - #|pub fn[A] Queue::length(self : Queue[A]) -> Int { - #| self.length - #|} - #|pub fn[A] Queue::is_empty(self : Queue[A]) -> Bool { - #| self.length == 0 - #|} - #|pub fn[A] Queue::push(self : Queue[A], x : A) -> Unit { - #| let cell = Some({ content: x, next: None }) - #| match self.last { - #| None => { - #| self.length = 1 - #| self.first = cell - #| self.last = cell - #| } - #| Some(last) => { - #| last.next = cell - #| self.length += 1 - #| self.last = cell - #| } - #| } - #|} - #|#internal(unsafe, "Panics if the queue is empty.") - #|#doc(hidden) - #|#alias(peek_exn, deprecated) - #|pub fn[A] Queue::unsafe_peek(self : Queue[A]) -> A { - #| match self.first { - #| None => abort("Queue is empty") - #| Some(first) => first.content - #| } - #|} - #|pub fn[A] Queue::peek(self : Queue[A]) -> A? { - #| match self.first { - #| None => None - #| Some(first) => Some(first.content) - #| } - #|} - #|#internal(unsafe, "Panics if the queue is empty.") - #|#doc(hidden) - #|#alias(pop_exn, deprecated) - #|pub fn[A] Queue::unsafe_pop(self : Queue[A]) -> A { - #| match self.first { - #| None => abort("Queue is empty") - #| Some({ content, next: None }) => { - #| self.clear() - #| content - #| } - #| Some({ content, next }) => { - #| self.length -= 1 - #| self.first = next - #| content - #| } - #| } - #|} - #|pub fn[A] Queue::pop(self : Queue[A]) -> A? { - #| match self.first { - #| None => None - #| Some({ content, next: None }) => { - #| self.clear() - #| Some(content) - #| } - #| Some({ content, next }) => { - #| self.length -= 1 - #| self.first = next - #| Some(content) - #| } - #| } - #|} - #|pub fn[A] Queue::each(self : Queue[A], f : (A) -> Unit) -> Unit { - #| loop self.first { - #| Some({ content, next }) => { - #| f(content) - #| continue next - #| } - #| None => () - #| } - #|} - #|pub fn[A] Queue::eachi(self : Queue[A], f : (Int, A) -> Unit) -> Unit { - #| loop (self.first, 0) { - #| (Some({ content, next }), index) => { - #| f(index, content) - #| continue (next, index + 1) - #| } - #| (None, _) => () - #| } - #|} - #|pub fn[A, B] Queue::fold(self : Queue[A], init~ : B, f : (B, A) -> B) -> B { - #| loop (self.first, init) { - #| (None, acc) => acc - #| (Some({ content, next }), acc) => continue (next, f(acc, content)) - #| } - #|} - #|pub fn[A] Queue::copy(self : Queue[A]) -> Queue[A] { - #| guard self.first is Some({ content, next }) else { return new() } - #| let first = { content, next: None } - #| let last = loop (first, next) { - #| (pre, Some({ content, next })) => { - #| let curr = { content, next: None } - #| pre.next = Some(curr) - #| continue (curr, next) - #| } - #| (pre, None) => pre - #| } - #| { length: self.length, first: Some(first), last: Some(last) } - #|} - #|pub fn[A] Queue::transfer(self : Queue[A], dst : Queue[A]) -> Unit { - #| if self.length > 0 { - #| match dst.last { - #| None => { - #| dst.length = self.length - #| dst.first = self.first - #| dst.last = self.last - #| self.clear() - #| } - #| Some(last) => { - #| last.next = self.first - #| dst.length = dst.length + self.length - #| dst.last = self.last - #| self.clear() - #| } - #| } - #| } - #|} - #|pub fn[A] Queue::iter(self : Queue[A]) -> Iter[A] { - #| self.iterator().iter() - #|} - #|pub fn[A] Queue::iterator(self : Queue[A]) -> Iterator[A] { - #| let mut next_node = self.first - #| Iterator::new(fn() { - #| match next_node { - #| None => None - #| Some({ content, next }) => { - #| next_node = next - #| Some(content) - #| } - #| } - #| }) - #|} - #|#as_free_fn - #|pub fn[A] Queue::from_iter(iter : Iter[A]) -> Queue[A] { - #| let q = new() - #| iter.each(e => q.push(e)) - #| q - #|} - #|#as_free_fn - #|pub fn[A] Queue::from_iterator(iter : Iterator[A]) -> Queue[A] { - #| let q = new() - #| while iter.next() is Some(e) { - #| q.push(e) - #| } - #| q - #|} - #|test "from_fixed_array_2" { - #| let q = from_array([1, 2, 3, 4]) - #| q.push(11) - #| assert_eq(q, from_array([1, 2, 3, 4, 11])) - #| q.unsafe_pop() |> ignore - #| assert_eq(q, from_array([2, 3, 4, 11])) - #|} - #|test "from_array_2" { - #| let q = from_array([1, 2, 3, 4]) - #| q.push(11) - #| assert_eq(q, from_array([1, 2, 3, 4, 11])) - #| q.unsafe_pop() |> ignore - #| assert_eq(q, from_array([2, 3, 4, 11])) - #|} - #|test "equal" { - #| let queue = from_array([1, 2, 3, 4]) - #| let queue2 = from_array([1, 2, 3, 4]) - #| let queue3 = from_array([1, 2, 3, 5]) - #| assert_true(queue == queue2) - #| assert_false(queue == queue3) - #| queue.unsafe_pop() |> ignore - #| assert_false(queue == queue2) - #| assert_eq(queue, from_array([2, 3, 4])) - #|} - #|test "push" { - #| let queue : Queue[Int] = new() - #| queue.push(1) - #| queue.push(2) - #| queue.push(3) - #| queue.push(1) - #| assert_eq(queue.length(), 4) - #| assert_eq(queue, from_array([1, 2, 3, 1])) - #|} - #|test "copy" { - #| let queue : Queue[Int] = from_array([1, 2, 3, 4]) - #| let queue2 : Queue[Int] = queue.copy() - #| assert_eq(queue2.length(), 4) - #| assert_eq(queue2, from_array([1, 2, 3, 4])) - #| assert_eq(queue.length(), 4) - #| assert_eq(queue, from_array([1, 2, 3, 4])) - #|} - #|test "transfer" { - #| let queue : Queue[Int] = from_array([1, 2, 3, 4]) - #| let queue2 : Queue[Int] = from_array([5, 6, 7, 8]) - #| queue.transfer(queue2) - #| assert_eq(queue.length(), 0) - #| assert_eq(queue2.length(), 8) - #| assert_eq(queue2, from_array([5, 6, 7, 8, 1, 2, 3, 4])) - #|} - #|test "cell_equal" { - #| assert_false(from_array([]).first == from_array([1]).first) - #|} - #|pub impl[X : @quickcheck.Arbitrary] @quickcheck.Arbitrary for Queue[X] with arbitrary( - #| size, - #| rs, - #|) { - #| @quickcheck.Arbitrary::arbitrary(size, rs) |> from_iter - #|} - ), - "types.mbt": ( - #|priv struct Cons[A] { - #| content : A - #| mut next : Cons[A]? - #|} derive(Eq) - #|#alias(T, deprecated) - #|struct Queue[A] { - #| mut length : Int - #| mut first : Cons[A]? - #| mut last : Cons[A]? - #|} - ), - }, + "deprecated.mbt": "", + "queue.mbt": ( + #|#as_free_fn + #|pub fn[A] Queue::new() -> Queue[A] { + #| { length: 0, first: None, last: None } + #|} + #|#as_free_fn + #|#alias(of, deprecated="Use from_array instead") + #|#as_free_fn(of, deprecated="Use from_array instead") + #|pub fn[A] Queue::from_array(arr : ArrayView[A]) -> Queue[A] { + #| guard arr.length() > 0 else { return new() } + #| let length = arr.length() + #| let last = { content: arr[length - 1], next: None } + #| let first = for i = length - 2, x = last; i >= 0; { + #| continue i - 1, { content: arr[i], next: Some(x) } + #| } nobreak { + #| x + #| } + #| { length, first: Some(first), last: Some(last) } + #|} + #|pub impl[A : Show] Show for Queue[A] with output(self, logger) { + #| logger.write_iter(self.iter(), prefix="@queue.from_array([", suffix="])") + #|} + #|impl[A : Eq] Eq for Queue[A] with equal(self, other) { + #| self.length == other.length && self.first == other.first + #|} + #|pub fn[A] Queue::clear(self : Queue[A]) -> Unit { + #| self.length = 0 + #| self.first = None + #| self.last = None + #|} + #|pub fn[A] Queue::length(self : Queue[A]) -> Int { + #| self.length + #|} + #|pub fn[A] Queue::is_empty(self : Queue[A]) -> Bool { + #| self.length == 0 + #|} + #|pub fn[A] Queue::push(self : Queue[A], x : A) -> Unit { + #| let cell = Some({ content: x, next: None }) + #| match self.last { + #| None => { + #| self.length = 1 + #| self.first = cell + #| self.last = cell + #| } + #| Some(last) => { + #| last.next = cell + #| self.length += 1 + #| self.last = cell + #| } + #| } + #|} + #|#internal(unsafe, "Panics if the queue is empty.") + #|#doc(hidden) + #|#alias(peek_exn, deprecated) + #|pub fn[A] Queue::unsafe_peek(self : Queue[A]) -> A { + #| match self.first { + #| None => abort("Queue is empty") + #| Some(first) => first.content + #| } + #|} + #|pub fn[A] Queue::peek(self : Queue[A]) -> A? { + #| self.first.map(first => first.content) + #|} + #|#internal(unsafe, "Panics if the queue is empty.") + #|#doc(hidden) + #|#alias(pop_exn, deprecated) + #|pub fn[A] Queue::unsafe_pop(self : Queue[A]) -> A { + #| match self.first { + #| None => abort("Queue is empty") + #| Some({ content, next: None }) => { + #| self.clear() + #| content + #| } + #| Some({ content, next }) => { + #| self.length -= 1 + #| self.first = next + #| content + #| } + #| } + #|} + #|pub fn[A] Queue::pop(self : Queue[A]) -> A? { + #| match self.first { + #| None => None + #| Some({ content, next: None }) => { + #| self.clear() + #| Some(content) + #| } + #| Some({ content, next }) => { + #| self.length -= 1 + #| self.first = next + #| Some(content) + #| } + #| } + #|} + #|pub fn[A] Queue::each(self : Queue[A], f : (A) -> Unit) -> Unit { + #| loop self.first { + #| Some({ content, next }) => { + #| f(content) + #| continue next + #| } + #| None => () + #| } + #|} + #|pub fn[A] Queue::eachi(self : Queue[A], f : (Int, A) -> Unit) -> Unit { + #| loop (self.first, 0) { + #| (Some({ content, next }), index) => { + #| f(index, content) + #| continue (next, index + 1) + #| } + #| (None, _) => () + #| } + #|} + #|pub fn[A, B] Queue::fold(self : Queue[A], init~ : B, f : (B, A) -> B) -> B { + #| loop (self.first, init) { + #| (None, acc) => acc + #| (Some({ content, next }), acc) => continue (next, f(acc, content)) + #| } + #|} + #|#alias(clone, deprecated) + #|pub fn[A] Queue::copy(self : Queue[A]) -> Queue[A] { + #| guard self.first is Some({ content, next }) else { return new() } + #| let first = { content, next: None } + #| let last = loop (first, next) { + #| (pre, Some({ content, next })) => { + #| let curr = { content, next: None } + #| pre.next = Some(curr) + #| continue (curr, next) + #| } + #| (pre, None) => pre + #| } + #| { length: self.length, first: Some(first), last: Some(last) } + #|} + #|pub fn[A] Queue::transfer(self : Queue[A], dst : Queue[A]) -> Unit { + #| if physical_equal(self, dst) { + #| return // no-op for self-transfer + #| } + #| if self.length > 0 { + #| match dst.last { + #| None => { + #| dst.length = self.length + #| dst.first = self.first + #| dst.last = self.last + #| self.clear() + #| } + #| Some(last) => { + #| last.next = self.first + #| dst.length = dst.length + self.length + #| dst.last = self.last + #| self.clear() + #| } + #| } + #| } + #|} + #|#alias(iterator, deprecated) + #|pub fn[A] Queue::iter(self : Queue[A]) -> Iter[A] { + #| let mut next_node = self.first + #| Iter::new(fn() { + #| match next_node { + #| None => None + #| Some({ content, next }) => { + #| next_node = next + #| Some(content) + #| } + #| } + #| }) + #|} + #|#as_free_fn + #|#alias(from_iterator, deprecated) + #|#as_free_fn(from_iterator, deprecated) + #|pub fn[A] Queue::from_iter(iter : Iter[A]) -> Queue[A] { + #| let q = new() + #| while iter.next() is Some(e) { + #| q.push(e) + #| } + #| q + #|} + #|test "from_fixed_array_2" { + #| let q = from_array([1, 2, 3, 4]) + #| q.push(11) + #| assert_eq(q, from_array([1, 2, 3, 4, 11])) + #| q.unsafe_pop() |> ignore + #| assert_eq(q, from_array([2, 3, 4, 11])) + #|} + #|test "from_array_2" { + #| let q = from_array([1, 2, 3, 4]) + #| q.push(11) + #| assert_eq(q, from_array([1, 2, 3, 4, 11])) + #| q.unsafe_pop() |> ignore + #| assert_eq(q, from_array([2, 3, 4, 11])) + #|} + #|test "equal" { + #| let queue = from_array([1, 2, 3, 4]) + #| let queue2 = from_array([1, 2, 3, 4]) + #| let queue3 = from_array([1, 2, 3, 5]) + #| assert_true(queue == queue2) + #| assert_false(queue == queue3) + #| queue.unsafe_pop() |> ignore + #| assert_false(queue == queue2) + #| assert_eq(queue, from_array([2, 3, 4])) + #|} + #|test "push" { + #| let queue : Queue[Int] = new() + #| queue.push(1) + #| queue.push(2) + #| queue.push(3) + #| queue.push(1) + #| assert_eq(queue.length(), 4) + #| assert_eq(queue, from_array([1, 2, 3, 1])) + #|} + #|test "copy" { + #| let queue : Queue[Int] = from_array([1, 2, 3, 4]) + #| let queue2 : Queue[Int] = queue.copy() + #| assert_eq(queue2.length(), 4) + #| assert_eq(queue2, from_array([1, 2, 3, 4])) + #| assert_eq(queue.length(), 4) + #| assert_eq(queue, from_array([1, 2, 3, 4])) + #|} + #|test "transfer" { + #| let queue : Queue[Int] = from_array([1, 2, 3, 4]) + #| let queue2 : Queue[Int] = from_array([5, 6, 7, 8]) + #| queue.transfer(queue2) + #| assert_eq(queue.length(), 0) + #| assert_eq(queue2.length(), 8) + #| assert_eq(queue2, from_array([5, 6, 7, 8, 1, 2, 3, 4])) + #|} + #|test "cell_equal" { + #| assert_false(from_array([]).first == from_array([1]).first) + #|} + #|pub impl[X : @quickcheck.Arbitrary] @quickcheck.Arbitrary for Queue[X] with arbitrary( + #| size, + #| rs, + #|) { + #| @quickcheck.Arbitrary::arbitrary(size, rs) |> from_iter + #|} + ), + "types.mbt": ( + #|priv struct Cons[A] { + #| content : A + #| mut next : Cons[A]? + #|} derive(Eq) + #|#alias(T, deprecated) + #|struct Queue[A] { + #| mut length : Int + #| mut first : Cons[A]? + #| mut last : Cons[A]? + #|} + ) + } ) ///| let moonbitlang_core_quickcheck_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/quickcheck", - deps={ - "moonbitlang/core/quickcheck/splitmix": moonbitlang_core_quickcheck_splitmix_module, - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/char": moonbitlang_core_char_module, - "moonbitlang/core/array": moonbitlang_core_array_module, - }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| "moonbitlang/core/quickcheck/splitmix", - #| "moonbitlang/core/builtin", - #| "moonbitlang/core/char", - #| "moonbitlang/core/array" - #| ], - #| "test-import": [ - #| "moonbitlang/core/bigint", - #| "moonbitlang/core/float", - #| "moonbitlang/core/double", - #| "moonbitlang/core/tuple", - #| "moonbitlang/core/bytes" - #| ] - #|} - ), - "arbitrary.mbt": ( - #|pub(open) trait Arbitrary { - #| arbitrary(Int, @splitmix.RandomState) -> Self - #|} - #|pub impl Arbitrary for Unit with arbitrary(_, _) { - #| () - #|} - #|pub impl Arbitrary for Bool with arbitrary(_, rs) { - #| rs.next_double() < 0.5 - #|} - #|pub impl Arbitrary for Int with arbitrary(size, rs) { - #| if size == 0 { - #| 0 - #| } else { - #| rs.next_int() % size - #| } - #|} - #|pub impl Arbitrary for UInt with arbitrary(size, rs) { - #| if size == 0 { - #| 0 - #| } else { - #| rs.next_uint() % size.reinterpret_as_uint() - #| } - #|} - #|pub impl Arbitrary for Byte with arbitrary(_, rs) { - #| rs.next_uint().to_byte() - #|} - #|pub impl Arbitrary for Bytes with arbitrary(size, rs) { - #| if size == 0 { - #| Bytes::new(0) - #| } else { - #| let sz = rs.next_positive_int() % size - #| Bytes::makei(sz, _ => Arbitrary::arbitrary(size, rs)) - #| } - #|} - #|pub impl Arbitrary for Int64 with arbitrary(size, rs) { - #| if size == 0 { - #| 0 - #| } else { - #| rs.next_int64() % size.to_int64() - #| } - #|} - #|pub impl Arbitrary for UInt64 with arbitrary(size, rs) { - #| if size == 0 { - #| 0 - #| } else { - #| rs.next_uint64() % size.to_uint64() - #| } - #|} - #|pub impl Arbitrary for Float with arbitrary(_, rs) { - #| rs.next_float() - #|} - #|pub impl Arbitrary for Double with arbitrary(_, rs) { - #| rs.next_double() - #|} - #|pub impl Arbitrary for Char with arbitrary(_, rs) { - #| ((rs.next_uint() % 128) |> UInt::reinterpret_as_int).unsafe_to_char() - #|} - #|pub impl Arbitrary for String with arbitrary(size, rs) { - #| let len = if size == 0 { 0 } else { rs.next_positive_int() % size } - #| let mut s = "" - #| for i in 0.. { - #| guard i < len else { None } - #| let elem = X::arbitrary(i, rs) - #| i += 1 - #| Some(elem) - #| }) - #|} - #|pub impl[X : Arbitrary] Arbitrary for Iter[X] with arbitrary(size, rs) { - #| let iter : Iterator[X] = Arbitrary::arbitrary(size, rs) - #| iter.iter() - #|} - #|pub fn[T : Arbitrary] gen(size? : Int, state? : @splitmix.RandomState) -> T { - #| let size = match size { - #| None => 0 - #| Some(x) => x - #| } - #| let state = match state { - #| None => @splitmix.RandomState::default() - #| Some(x) => x - #| } - #| Arbitrary::arbitrary(size, state) - #|} - #|pub impl[X : Arbitrary] Arbitrary for X? with arbitrary(i, rs) { - #| if rs.next_double() < 0.3 { - #| None - #| } else { - #| Some(Arbitrary::arbitrary(i, rs)) - #| } - #|} - #|pub impl[T : Arbitrary, E : Arbitrary] Arbitrary for Result[T, E] with arbitrary( - #| size, - #| rs, - #|) { - #| if Arbitrary::arbitrary(size, rs) { - #| Ok(T::arbitrary(size, rs)) - #| } else { - #| Err(E::arbitrary(size, rs)) - #| } - #|} - #|pub impl[X : Arbitrary] Arbitrary for FixedArray[X] with arbitrary(size, rs) { - #| let len = if size == 0 { 0 } else { rs.next_positive_int() % size } - #| FixedArray::makei(len, i => X::arbitrary(i, rs)) - #|} - #|pub impl[A : Arbitrary] Arbitrary for ArrayView[A] with arbitrary(size, rs) { - #| let arr : Array[A] = Arbitrary::arbitrary(size, rs) - #| arr[:] - #|} - #|pub impl[X : Arbitrary] Arbitrary for Array[X] with arbitrary(size, rs) { - #| let len = if size == 0 { 0 } else { rs.next_positive_int() % size } - #| Array::makei(len, x => X::arbitrary(x, rs)) - #|} - ), - "utils.mbt": ( - #|pub fn[X : Arbitrary] samples(x : Int) -> Array[X] { - #| let rs = @splitmix.new() - #| let array = Array::make(x, X::arbitrary(0, rs)) - #| for i in 1.. Self + #|} + #|pub impl Arbitrary for Unit with arbitrary(_, _) { + #| () + #|} + #|pub impl Arbitrary for Bool with arbitrary(_, rs) { + #| rs.next_double() < 0.5 + #|} + #|pub impl Arbitrary for Int with arbitrary(size, rs) { + #| if size == 0 { + #| 0 + #| } else { + #| rs.next_int() % size + #| } + #|} + #|pub impl Arbitrary for UInt with arbitrary(size, rs) { + #| if size == 0 { + #| 0 + #| } else { + #| rs.next_uint() % size.reinterpret_as_uint() + #| } + #|} + #|pub impl Arbitrary for Byte with arbitrary(_, rs) { + #| rs.next_uint().to_byte() + #|} + #|pub impl Arbitrary for Bytes with arbitrary(size, rs) { + #| if size == 0 { + #| Bytes::new(0) + #| } else { + #| let sz = rs.next_positive_int() % size + #| Bytes::makei(sz, _ => Arbitrary::arbitrary(size, rs)) + #| } + #|} + #|pub impl Arbitrary for Int64 with arbitrary(size, rs) { + #| if size == 0 { + #| 0 + #| } else { + #| rs.next_int64() % size.to_int64() + #| } + #|} + #|pub impl Arbitrary for UInt64 with arbitrary(size, rs) { + #| if size == 0 { + #| 0 + #| } else { + #| rs.next_uint64() % size.to_uint64() + #| } + #|} + #|pub impl Arbitrary for Float with arbitrary(_, rs) { + #| rs.next_float() + #|} + #|pub impl Arbitrary for Double with arbitrary(_, rs) { + #| rs.next_double() + #|} + #|pub impl Arbitrary for Char with arbitrary(_, rs) { + #| ((rs.next_uint() % 128) |> UInt::reinterpret_as_int).unsafe_to_char() + #|} + #|pub impl Arbitrary for String with arbitrary(size, rs) { + #| let len = if size == 0 { 0 } else { rs.next_positive_int() % size } + #| for i in 0.. { + #| guard i < len else { None } + #| let elem = X::arbitrary(i, rs) + #| i += 1 + #| Some(elem) + #| }) + #|} + #|pub fn[T : Arbitrary] gen(size? : Int, state? : @splitmix.RandomState) -> T { + #| let size = match size { + #| None => 0 + #| Some(x) => x + #| } + #| let state = match state { + #| None => @splitmix.RandomState::default() + #| Some(x) => x + #| } + #| Arbitrary::arbitrary(size, state) + #|} + #|pub impl[X : Arbitrary] Arbitrary for X? with arbitrary(i, rs) { + #| if rs.next_double() < 0.3 { + #| None + #| } else { + #| Some(Arbitrary::arbitrary(i, rs)) + #| } + #|} + #|pub impl[T : Arbitrary, E : Arbitrary] Arbitrary for Result[T, E] with arbitrary( + #| size, + #| rs, + #|) { + #| if Arbitrary::arbitrary(size, rs) { + #| Ok(T::arbitrary(size, rs)) + #| } else { + #| Err(E::arbitrary(size, rs)) + #| } + #|} + #|pub impl[X : Arbitrary] Arbitrary for FixedArray[X] with arbitrary(size, rs) { + #| let len = if size == 0 { 0 } else { rs.next_positive_int() % size } + #| FixedArray::makei(len, i => X::arbitrary(i, rs)) + #|} + #|pub impl[A : Arbitrary] Arbitrary for ArrayView[A] with arbitrary(size, rs) { + #| let arr : Array[A] = Arbitrary::arbitrary(size, rs) + #| arr[:] + #|} + #|pub impl[X : Arbitrary] Arbitrary for Array[X] with arbitrary(size, rs) { + #| let len = if size == 0 { 0 } else { rs.next_positive_int() % size } + #| Array::makei(len, x => X::arbitrary(x, rs)) + #|} + ), + "utils.mbt": ( + #|pub fn[X : Arbitrary] samples(x : Int) -> Array[X] { + #| let rs = @splitmix.new() + #| let array = Array::make(x, X::arbitrary(0, rs)) + #| for i in 1.. RandomState { - #| new(seed~) - #|} - ), - "random.mbt": ( - #|struct RandomState { - #| mut seed : UInt64 - #| gamma : UInt64 - #|} derive(Show) - #|let golden_gamma : UInt64 = 0x9e3779b97f4a7c15 - #|let double_ulp : Double = 1.0 / (1L << 53).to_double() - #|let float_ulp : Float = 1.0F / Float::from_int64(1L << 24) - #|pub fn new(seed? : UInt64 = 37) -> RandomState { - #| { seed: mix64(seed), gamma: mix_gamma(seed + golden_gamma) } - #|} - #|pub fn RandomState::clone(self : RandomState) -> RandomState { - #| { ..self } - #|} - #|pub fn RandomState::next(self : RandomState) -> Unit { - #| self.next_uint64() |> ignore - #|} - #|pub fn RandomState::next_uint64(self : RandomState) -> UInt64 { - #| let { seed, gamma } = self - #| self.seed = seed + gamma - #| mix64(self.seed) - #|} - #|pub fn RandomState::next_uint(self : RandomState) -> UInt { - #| self.next_uint64().to_uint() - #|} - #|pub fn RandomState::next_int64(self : RandomState) -> Int64 { - #| self.next_uint64().reinterpret_as_int64() - #|} - #|pub fn RandomState::next_two_uint(self : RandomState) -> (UInt, UInt) { - #| let g = self.next_uint64() - #| ((g >> 32).to_uint(), g.to_uint()) - #|} - #|pub fn RandomState::next_int(self : RandomState) -> Int { - #| self.next_uint().reinterpret_as_int() - #|} - #|pub fn RandomState::next_positive_int(self : RandomState) -> Int { - #| let r = self.next_int() - #| match r { - #| -2147483648 => 2147483647 - #| 0 => 1 - #| r if r < 0 => -r - #| r => r - #| } - #|} - #|pub fn RandomState::next_float(self : RandomState) -> Float { - #| let u = self.next_uint64() - #| Float::from_uint64(u >> 40) * float_ulp - #|} - #|pub fn RandomState::next_double(self : RandomState) -> Double { - #| let u = self.next_uint64() - #| (u >> 11).to_double() * double_ulp - #|} - #|pub fn RandomState::split(self : RandomState) -> RandomState { - #| let seed1 = self.seed + self.gamma - #| self.seed = seed1 + self.gamma - #| { seed: mix64(seed1), gamma: mix_gamma(self.seed) } - #|} - #|fn shift_xor(n : Int, w : UInt64) -> UInt64 { - #| w ^ (w >> n) - #|} - #|fn shift_xor_mul(n : Int, k : UInt64, w : UInt64) -> UInt64 { - #| shift_xor(n, w) * k - #|} - #|fn mix64(z0 : UInt64) -> UInt64 { - #| let z1 = shift_xor_mul(30, 0xff51afd7ed558ccd, z0) - #| let z2 = shift_xor_mul(33, 0xc4ceb9fe1a85ec53, z1) - #| shift_xor(33, z2) - #|} - #|fn mix64variant13(z0 : UInt64) -> UInt64 { - #| let z1 = shift_xor_mul(30, 0xbf58476d1ce4e5b9, z0) - #| let z2 = shift_xor_mul(27, 0x94d049bb133111eb, z1) - #| shift_xor(31, z2) - #|} - #|fn mix_gamma(z0 : UInt64) -> UInt64 { - #| let z1 = mix64variant13(z0 | 1) - #| let n = (z1 | (z1 >> 1)).popcnt() - #| if n >= 24 { - #| z1 - #| } else { - #| z1 ^ 0xaaaaaaaaaaaaaaaa - #| } - #|} - #|pub impl Default for RandomState with default() { - #| new() - #|} - #|test "non-zero default" { - #| let rs = RandomState::default() - #| assert_not_eq(rs.seed, 0) - #| assert_not_eq(rs.gamma, 0) - #|} - ), - }, + "deprecated.mbt": ( + #|#deprecated("use `@splitmix.new` instead") + #|pub fn RandomState::new(seed? : UInt64 = 37) -> RandomState { + #| new(seed~) + #|} + ), + "random.mbt": ( + #|struct RandomState { + #| mut seed : UInt64 + #| gamma : UInt64 + #|} derive(Show) + #|let golden_gamma : UInt64 = 0x9e3779b97f4a7c15 + #|let double_ulp : Double = 1.0 / (1L << 53).to_double() + #|let float_ulp : Float = 1.0F / Float::from_int64(1L << 24) + #|pub fn new(seed? : UInt64 = 37) -> RandomState { + #| { seed: mix64(seed), gamma: mix_gamma(seed + golden_gamma) } + #|} + #|pub fn RandomState::clone(self : RandomState) -> RandomState { + #| { ..self } + #|} + #|pub fn RandomState::next(self : RandomState) -> Unit { + #| self.next_uint64() |> ignore + #|} + #|pub fn RandomState::next_uint64(self : RandomState) -> UInt64 { + #| let { seed, gamma } = self + #| self.seed = seed + gamma + #| mix64(self.seed) + #|} + #|pub fn RandomState::next_uint(self : RandomState) -> UInt { + #| self.next_uint64().to_uint() + #|} + #|pub fn RandomState::next_int64(self : RandomState) -> Int64 { + #| self.next_uint64().reinterpret_as_int64() + #|} + #|pub fn RandomState::next_two_uint(self : RandomState) -> (UInt, UInt) { + #| let g = self.next_uint64() + #| ((g >> 32).to_uint(), g.to_uint()) + #|} + #|pub fn RandomState::next_int(self : RandomState) -> Int { + #| self.next_uint().reinterpret_as_int() + #|} + #|pub fn RandomState::next_positive_int(self : RandomState) -> Int { + #| let r = self.next_int() + #| match r { + #| -2147483648 => 2147483647 + #| 0 => 1 + #| r if r < 0 => -r + #| r => r + #| } + #|} + #|pub fn RandomState::next_float(self : RandomState) -> Float { + #| let u = self.next_uint64() + #| Float::from_uint64(u >> 40) * float_ulp + #|} + #|pub fn RandomState::next_double(self : RandomState) -> Double { + #| let u = self.next_uint64() + #| (u >> 11).to_double() * double_ulp + #|} + #|pub fn RandomState::split(self : RandomState) -> RandomState { + #| let seed1 = self.seed + self.gamma + #| self.seed = seed1 + self.gamma + #| { seed: mix64(seed1), gamma: mix_gamma(self.seed) } + #|} + #|fn shift_xor(n : Int, w : UInt64) -> UInt64 { + #| w ^ (w >> n) + #|} + #|fn shift_xor_mul(n : Int, k : UInt64, w : UInt64) -> UInt64 { + #| shift_xor(n, w) * k + #|} + #|fn mix64(z0 : UInt64) -> UInt64 { + #| let z1 = shift_xor_mul(30, 0xff51afd7ed558ccd, z0) + #| let z2 = shift_xor_mul(33, 0xc4ceb9fe1a85ec53, z1) + #| shift_xor(33, z2) + #|} + #|fn mix64variant13(z0 : UInt64) -> UInt64 { + #| let z1 = shift_xor_mul(30, 0xbf58476d1ce4e5b9, z0) + #| let z2 = shift_xor_mul(27, 0x94d049bb133111eb, z1) + #| shift_xor(31, z2) + #|} + #|fn mix_gamma(z0 : UInt64) -> UInt64 { + #| let z1 = mix64variant13(z0 | 1) + #| let n = (z1 | (z1 >> 1)).popcnt() + #| if n >= 24 { + #| z1 + #| } else { + #| z1 ^ 0xaaaaaaaaaaaaaaaa + #| } + #|} + #|pub impl Default for RandomState with default() { + #| new() + #|} + #|test "non-zero default" { + #| let rs = RandomState::default() + #| assert_not_eq(rs.seed, 0) + #| assert_not_eq(rs.gamma, 0) + #|} + ) + } ) ///| let moonbitlang_core_random_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/random", - deps={ - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/double": moonbitlang_core_double_module, - "moonbitlang/core/float": moonbitlang_core_float_module, - "moonbitlang/core/random/internal/random_source": moonbitlang_core_random_internal_random_source_module, - "moonbitlang/core/bigint": moonbitlang_core_bigint_module, - }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| "moonbitlang/core/builtin", - #| "moonbitlang/core/double", - #| "moonbitlang/core/float", - #| "moonbitlang/core/random/internal/random_source", - #| "moonbitlang/core/bigint" - #| ], - #| "test-import": [ - #| "moonbitlang/core/bench" - #| ] - #|} - ), - "deprecated.mbt": ( - #|#deprecated("Use `Rand::new()` instead") - #|pub fn new(seed? : Bytes = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ123456") -> Rand { - #| if seed.length() != 32 { - #| abort("seed must be 32 bytes long") - #| } - #| @random_source.ChaCha8::new(seed) as &Source - #|} - #|#deprecated("You may use `Rand::chacha8(seed~)` instead of `Rand::new(chacha8(seed~))") - #|pub fn chacha8(seed? : Bytes = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ123456") -> &Source { - #| @random_source.ChaCha8::new(seed) - #|} - ), - "random.mbt": ( - #|struct Rand(&Source) - #|pub(open) trait Source { - #| next(Self) -> UInt64 - #|} - #|impl Source for @random_source.ChaCha8 with next(self : @random_source.ChaCha8) -> UInt64 { - #| for { - #| if self.next() is Some(x) { - #| return x - #| } - #| self.refill() - #| } - #|} - #|pub fn Rand::chacha8( - #| seed? : Bytes = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ123456", - #|) -> Rand { - #| if seed.length() != 32 { - #| abort("seed must be 32 bytes long") - #| } - #| Rand(@random_source.ChaCha8::new(seed) as &Source) - #|} - #|pub fn Rand::new(generator? : &Source) -> Rand { - #| match generator { - #| None => Rand::chacha8() - #| Some(gen) => Rand(gen) - #| } - #|} - #|fn Rand::next(self : Rand) -> UInt64 { - #| let Rand(s) = self - #| s.next() - #|} - #|test "next" { - #| let r = Rand::new() - #| let n = r.next() - #| let exp = 13219109469176600229UL - #| assert_eq(n, exp) - #|} - #|pub fn Rand::int(self : Rand, limit? : Int = 0) -> Int { - #| if limit == 0 { - #| (self.next() >> 33).to_int() - #| } else { - #| self.uint(limit=limit.reinterpret_as_uint()).reinterpret_as_int() - #| } - #|} - #|pub fn Rand::int64(self : Rand, limit? : Int64 = 0) -> Int64 { - #| if limit == 0 { - #| let mask : UInt64 = (1UL << 63) - 1UL - #| return (self.next() & mask).reinterpret_as_int64() - #| } else { - #| self.uint64(limit=limit.reinterpret_as_uint64()).reinterpret_as_int64() - #| } - #|} - #|pub fn Rand::uint(self : Rand, limit? : UInt = 0) -> UInt { - #| if limit == 0 { - #| return self.next().to_uint() - #| } - #| self.uint64(limit=limit.to_uint64()).to_uint() - #|} - #|test "uint" { - #| let r = Rand::new() - #| let n = r.uint(limit=10U) - #| inspect(n, content="7") - #| let n = r.uint(limit=10U) - #| inspect(n, content="0") - #| let n = r.uint(limit=10U) - #| inspect(n, content="5") - #|} - #|pub fn Rand::uint64(self : Rand, limit? : UInt64 = 0) -> UInt64 { - #| if limit == 0 { - #| return self.next() - #| } else if (limit & (limit - 1)) == 0 { - #| return self.next() & (limit - 1) - #| } - #| let mut r = umul128(self.next(), limit) - #| if r.lo < limit { - #| let thresh = limit.lnot() % limit - #| while r.lo < thresh { - #| r = umul128(self.next(), limit) - #| } - #| } - #| r.hi - #|} - #|test "UInt64" { - #| let r = Rand::new() - #| let n = r.uint64() - #| let exp = 13219109469176600229UL - #| assert_eq(n, exp) - #| let r = Rand::new() - #| let n = r.uint64(limit=10UL) - #| inspect(n, content="7") - #| let n = r.uint64(limit=10UL) - #| inspect(n, content="0") - #| let n = r.uint64(limit=10UL) - #| inspect(n, content="5") - #|} - #|pub fn Rand::double(self : Rand) -> Double { - #| Double::convert_uint64(self.next() << 11 >> 11) / - #| Double::convert_uint64(1UL << 53) - #|} - #|test "double" { - #| let r = Rand::new() - #| let n = r.double() - #| inspect(n, content="0.615969772029264") - #|} - #|pub fn Rand::float(self : Rand) -> Float { - #| Float::from_uint(self.uint() << 8 >> 8) / Float::from_uint(1U << 24) - #|} - #|pub fn Rand::boolean(self : Rand) -> Bool { - #| (self.next() & 1) == 1 - #|} - #|pub fn Rand::bigint(self : Rand, bits : Int) -> @bigint.BigInt { - #| let mod = bits % 8 - #| let len = if mod == 0 { bits / 8 } else { bits / 8 + 1 } - #| let bytes = Bytes::makei(len, i => if i == 0 && mod != 0 { - #| let mask = (1U << mod) - 1U - #| (self.uint(limit=256) & mask).to_byte() - #| } else { - #| self.uint(limit=256).to_byte() - #| }) - #| @bigint.BigInt::from_octets(bytes) - #|} - #|test "bigint" { - #| let r = Rand::new() - #| inspect(r.bigint(1), content="1") - #| inspect(r.bigint(3), content="4") - #| inspect(r.bigint(7), content="124") - #| inspect(r.bigint(8), content="214") - #| inspect(r.bigint(32), content="2910404175") - #| inspect(r.bigint(40), content="714745001576") - #| inspect(r.bigint(64), content="13430064486797060338") - #| inspect(r.bigint(128), content="251068071753473224445949321151725639522") - #|} - #|#valtype - #|priv struct UInt128 { - #| hi : UInt64 - #| lo : UInt64 - #|} - #|fn umul128(a : UInt64, b : UInt64) -> UInt128 { - #| let aLo = a & 0xffffffff - #| let aHi = a >> 32 - #| let bLo = b & 0xffffffff - #| let bHi = b >> 32 - #| let x = aLo * bLo - #| let y = aHi * bLo + (x >> 32) - #| let z = aLo * bHi + (y & 0xffffffff) - #| let w = aHi * bHi + (y >> 32) + (z >> 32) - #| { hi: w, lo: a * b } - #|} - #|test "umul128" { - #| let r = umul128(0x123456789ABCDEF0, 0xFEDCBA9876543210) - #| assert_eq(r.hi, 1305938385386173474UL) - #| assert_eq(r.lo, 2552847189736476416UL) - #|} - #|test "umul128: handles small numbers correctly" { - #| let r = umul128(1UL, 1UL) - #| assert_eq(r.hi, 0UL) - #| assert_eq(r.lo, 1UL) - #|} - #|test "umul128: handles large numbers correctly" { - #| let r = umul128(1UL, 0xFFFFFFFFFFFFFFFFUL) - #| assert_eq(r.hi, 0UL) - #| assert_eq(r.lo, 0xFFFFFFFFFFFFFFFFUL) - #|} - #|test "umul128: handles zero correctly" { - #| let r = umul128(0UL, 0UL) - #| assert_eq(r.hi, 0UL) - #| assert_eq(r.lo, 0UL) - #|} - #|pub fn Rand::shuffle( - #| self : Rand, - #| limit : Int, - #| swap : (Int, Int) -> Unit, - #|) -> Unit { - #| if limit < 0 { - #| abort("Rand::shuffle: invalid argument limit") - #| } - #| for i = limit - 1; i > 0; i = i - 1 { - #| let j = self.int(limit=i + 1) - #| swap(i, j) - #| } - #|} - #|test "shuffle" { - #| let r = Rand::new() - #| let a = [1, 2, 3, 4, 5] - #| r.shuffle(a.length(), (i : Int, j : Int) => { - #| let t = a[i] - #| a[i] = a[j] - #| a[j] = t - #| }) - #| inspect(a, content="[3, 5, 2, 1, 4]") - #|} - ), - }, + "deprecated.mbt": ( + #|#deprecated("Use `Rand::new()` instead") + #|pub fn new(seed? : Bytes = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ123456") -> Rand { + #| if seed.length() != 32 { + #| abort("seed must be 32 bytes long") + #| } + #| @random_source.ChaCha8::new(seed) as &Source + #|} + #|#deprecated("You may use `Rand::chacha8(seed~)` instead of `Rand::new(chacha8(seed~))") + #|pub fn chacha8(seed? : Bytes = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ123456") -> &Source { + #| @random_source.ChaCha8::new(seed) + #|} + ), + "random.mbt": ( + #|struct Rand(&Source) + #|pub(open) trait Source { + #| next(Self) -> UInt64 + #|} + #|impl Source for @random_source.ChaCha8 with next(self : @random_source.ChaCha8) -> UInt64 { + #| for ;; { + #| if self.next() is Some(x) { + #| return x + #| } + #| self.refill() + #| } + #|} + #|pub fn Rand::chacha8( + #| seed? : Bytes = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ123456", + #|) -> Rand { + #| if seed.length() != 32 { + #| abort("seed must be 32 bytes long") + #| } + #| Rand(@random_source.ChaCha8::new(seed) as &Source) + #|} + #|pub fn Rand::new(generator? : &Source) -> Rand { + #| match generator { + #| None => Rand::chacha8() + #| Some(gen) => Rand(gen) + #| } + #|} + #|fn Rand::next(self : Rand) -> UInt64 { + #| let Rand(s) = self + #| s.next() + #|} + #|test "next" { + #| let r = Rand::new() + #| let n = r.next() + #| let exp = 13219109469176600229UL + #| assert_eq(n, exp) + #|} + #|pub fn Rand::int(self : Rand, limit? : Int = 0) -> Int { + #| if limit == 0 { + #| (self.next() >> 33).to_int() + #| } else { + #| self.uint(limit=limit.reinterpret_as_uint()).reinterpret_as_int() + #| } + #|} + #|pub fn Rand::int64(self : Rand, limit? : Int64 = 0) -> Int64 { + #| if limit == 0 { + #| let mask : UInt64 = (1UL << 63) - 1UL + #| return (self.next() & mask).reinterpret_as_int64() + #| } else { + #| self.uint64(limit=limit.reinterpret_as_uint64()).reinterpret_as_int64() + #| } + #|} + #|pub fn Rand::uint(self : Rand, limit? : UInt = 0) -> UInt { + #| if limit == 0 { + #| return self.next().to_uint() + #| } + #| self.uint64(limit=limit.to_uint64()).to_uint() + #|} + #|test "uint" { + #| let r = Rand::new() + #| let n = r.uint(limit=10U) + #| inspect(n, content="7") + #| let n = r.uint(limit=10U) + #| inspect(n, content="0") + #| let n = r.uint(limit=10U) + #| inspect(n, content="5") + #|} + #|pub fn Rand::uint64(self : Rand, limit? : UInt64 = 0) -> UInt64 { + #| if limit == 0 { + #| return self.next() + #| } else if (limit & (limit - 1)) == 0 { + #| return self.next() & (limit - 1) + #| } + #| let r = umul128(self.next(), limit) + #| if r.lo >= limit { + #| return r.hi + #| } + #| let thresh = limit.lnot() % limit + #| for r = r; r.lo < thresh; { + #| continue umul128(self.next(), limit) + #| } nobreak { + #| r.hi + #| } + #|} + #|test "UInt64" { + #| let r = Rand::new() + #| let n = r.uint64() + #| let exp = 13219109469176600229UL + #| assert_eq(n, exp) + #| let r = Rand::new() + #| let n = r.uint64(limit=10UL) + #| inspect(n, content="7") + #| let n = r.uint64(limit=10UL) + #| inspect(n, content="0") + #| let n = r.uint64(limit=10UL) + #| inspect(n, content="5") + #|} + #|pub fn Rand::double(self : Rand) -> Double { + #| Double::convert_uint64(self.next() << 11 >> 11) / + #| Double::convert_uint64(1UL << 53) + #|} + #|test "double" { + #| let r = Rand::new() + #| let n = r.double() + #| inspect(n, content="0.615969772029264") + #|} + #|pub fn Rand::float(self : Rand) -> Float { + #| Float::from_uint(self.uint() << 8 >> 8) / Float::from_uint(1U << 24) + #|} + #|pub fn Rand::boolean(self : Rand) -> Bool { + #| (self.next() & 1) == 1 + #|} + #|pub fn Rand::bigint(self : Rand, bits : Int) -> @bigint.BigInt { + #| let mod = bits % 8 + #| let len = if mod == 0 { bits / 8 } else { bits / 8 + 1 } + #| let bytes = Bytes::makei(len, i => { + #| if i == 0 && mod != 0 { + #| let mask = (1U << mod) - 1U + #| (self.uint(limit=256) & mask).to_byte() + #| } else { + #| self.uint(limit=256).to_byte() + #| } + #| }) + #| @bigint.BigInt::from_octets(bytes) + #|} + #|test "bigint" { + #| let r = Rand::new() + #| inspect(r.bigint(1), content="1") + #| inspect(r.bigint(3), content="4") + #| inspect(r.bigint(7), content="124") + #| inspect(r.bigint(8), content="214") + #| inspect(r.bigint(32), content="2910404175") + #| inspect(r.bigint(40), content="714745001576") + #| inspect(r.bigint(64), content="13430064486797060338") + #| inspect(r.bigint(128), content="251068071753473224445949321151725639522") + #|} + #|#valtype + #|priv struct UInt128 { + #| hi : UInt64 + #| lo : UInt64 + #|} + #|fn umul128(a : UInt64, b : UInt64) -> UInt128 { + #| let aLo = a & 0xffffffff + #| let aHi = a >> 32 + #| let bLo = b & 0xffffffff + #| let bHi = b >> 32 + #| let x = aLo * bLo + #| let y = aHi * bLo + (x >> 32) + #| let z = aLo * bHi + (y & 0xffffffff) + #| let w = aHi * bHi + (y >> 32) + (z >> 32) + #| { hi: w, lo: a * b } + #|} + #|test "umul128" { + #| let r = umul128(0x123456789ABCDEF0, 0xFEDCBA9876543210) + #| assert_eq(r.hi, 1305938385386173474UL) + #| assert_eq(r.lo, 2552847189736476416UL) + #|} + #|test "umul128: handles small numbers correctly" { + #| let r = umul128(1UL, 1UL) + #| assert_eq(r.hi, 0UL) + #| assert_eq(r.lo, 1UL) + #|} + #|test "umul128: handles large numbers correctly" { + #| let r = umul128(1UL, 0xFFFFFFFFFFFFFFFFUL) + #| assert_eq(r.hi, 0UL) + #| assert_eq(r.lo, 0xFFFFFFFFFFFFFFFFUL) + #|} + #|test "umul128: handles zero correctly" { + #| let r = umul128(0UL, 0UL) + #| assert_eq(r.hi, 0UL) + #| assert_eq(r.lo, 0UL) + #|} + #|pub fn Rand::shuffle( + #| self : Rand, + #| limit : Int, + #| swap : (Int, Int) -> Unit, + #|) -> Unit { + #| if limit < 0 { + #| abort("Rand::shuffle: invalid argument limit") + #| } + #| for i in limit>..1 { + #| let j = self.int(limit=i + 1) + #| swap(i, j) + #| } + #|} + #|test "shuffle" { + #| let r = Rand::new() + #| let a = [1, 2, 3, 4, 5] + #| r.shuffle(a.length(), (i : Int, j : Int) => { + #| let t = a[i] + #| a[i] = a[j] + #| a[j] = t + #| }) + #| inspect(a, content="[3, 5, 2, 1, 4]") + #|} + ) + } ) ///| let moonbitlang_core_random_internal_random_source_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/random/internal/random_source", - deps={ - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/array": moonbitlang_core_array_module, - "moonbitlang/core/bytes": moonbitlang_core_bytes_module, - }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| "moonbitlang/core/builtin", - #| "moonbitlang/core/array", - #| "moonbitlang/core/bytes" - #| ] - #|} - ), - "random_source_chacha.mbt": ( - #|struct ChaCha8 { - #| buffer : FixedArray[UInt] - #| seed : FixedArray[UInt] - #| mut i : UInt - #| mut n : UInt - #| mut counter : UInt - #|} - #|pub fn ChaCha8::new(seed : Bytes) -> ChaCha8 { - #| let seed = FixedArray::makei(SEED_CHUNK_NUM * 2, i => match seed[i * 4:] { - #| [u32le(x), ..] => x - #| _ => abort("seed must be 32 bytes long") - #| }) - #| let buffer = FixedArray::make(BUFFER_CHUNK_NUM * 2, 0U) - #| chacha_block(seed, buffer, 0) - #| { seed, buffer, counter: 0, i: 0, n: BUFFER_CHUNK_NUM.reinterpret_as_uint() } - #|} - #|const COUNTER_INC = 4U - #|const COUNTER_MAX = 16U - #|const BUFFER_CHUNK_NUM = 32 - #|const SEED_CHUNK_NUM = 4 - #|pub fn ChaCha8::next(self : ChaCha8) -> UInt64? { - #| let i = self.i - #| if i >= self.n { - #| return None - #| } - #| self.i = i + 1 - #| let index = i.reinterpret_as_int() & (BUFFER_CHUNK_NUM - 1) - #| let lo = self.buffer[index * 2].to_uint64() - #| let hi = self.buffer[index * 2 + 1].to_uint64() - #| Some((hi << 32) | lo) - #|} - #|pub fn ChaCha8::refill(self : ChaCha8) -> Unit { - #| self.counter += COUNTER_INC - #| if self.counter == COUNTER_MAX { - #| self.buffer.blit_to( - #| self.seed, - #| len=SEED_CHUNK_NUM * 2, - #| src_offset=(BUFFER_CHUNK_NUM - SEED_CHUNK_NUM) * 2, - #| ) - #| self.counter = 0 - #| } - #| chacha_block(self.seed, self.buffer, self.counter) - #| self.i = 0 - #| self.n = if self.counter == COUNTER_MAX - COUNTER_INC { - #| (BUFFER_CHUNK_NUM - SEED_CHUNK_NUM).reinterpret_as_uint() - #| } else { - #| BUFFER_CHUNK_NUM.reinterpret_as_uint() - #| } - #|} - #|#valtype - #|priv struct Quadruple(UInt, UInt, UInt, UInt) - #|fn chacha_block( - #| seed : FixedArray[UInt], - #| buf : FixedArray[UInt], - #| counter : UInt, - #|) -> Unit { - #| fn qr(t : Quadruple) -> Quadruple { - #| let Quadruple(a, b, c, d) = t - #| let a = a + b - #| let d = d ^ a - #| let d = (d << 16) | (d >> 16) - #| let c = c + d - #| let b = b ^ c - #| let b = (b << 12) | (b >> 20) - #| let a = a + b - #| let d = d ^ a - #| let d = (d << 8) | (d >> 24) - #| let c = c + d - #| let b = b ^ c - #| let b = (b << 7) | (b >> 25) - #| Quadruple(a, b, c, d) - #| } - #| setup(seed, buf, counter) - #| for i in 0..<4 { - #| let mut b0 = buf[0 * 4 + i] - #| let mut b1 = buf[1 * 4 + i] - #| let mut b2 = buf[2 * 4 + i] - #| let mut b3 = buf[3 * 4 + i] - #| let mut b4 = buf[4 * 4 + i] - #| let mut b5 = buf[5 * 4 + i] - #| let mut b6 = buf[6 * 4 + i] - #| let mut b7 = buf[7 * 4 + i] - #| let mut b8 = buf[8 * 4 + i] - #| let mut b9 = buf[9 * 4 + i] - #| let mut b10 = buf[10 * 4 + i] - #| let mut b11 = buf[11 * 4 + i] - #| let mut b12 = buf[12 * 4 + i] - #| let mut b13 = buf[13 * 4 + i] - #| let mut b14 = buf[14 * 4 + i] - #| let mut b15 = buf[15 * 4 + i] - #| for round in 0..<4 { - #| let Quadruple(tb1_0, tb1_1, tb1_2, tb1_3) = qr(Quadruple(b0, b4, b8, b12)) - #| b0 = tb1_0 - #| b4 = tb1_1 - #| b8 = tb1_2 - #| b12 = tb1_3 - #| let Quadruple(tb2_0, tb2_1, tb2_2, tb2_3) = qr(Quadruple(b1, b5, b9, b13)) - #| b1 = tb2_0 - #| b5 = tb2_1 - #| b9 = tb2_2 - #| b13 = tb2_3 - #| let Quadruple(tb3_0, tb3_1, tb3_2, tb3_3) = qr( - #| Quadruple(b2, b6, b10, b14), - #| ) - #| b2 = tb3_0 - #| b6 = tb3_1 - #| b10 = tb3_2 - #| b14 = tb3_3 - #| let Quadruple(tb4_0, tb4_1, tb4_2, tb4_3) = qr( - #| Quadruple(b3, b7, b11, b15), - #| ) - #| b3 = tb4_0 - #| b7 = tb4_1 - #| b11 = tb4_2 - #| b15 = tb4_3 - #| let Quadruple(tb5_0, tb5_1, tb5_2, tb5_3) = qr( - #| Quadruple(b0, b5, b10, b15), - #| ) - #| b0 = tb5_0 - #| b5 = tb5_1 - #| b10 = tb5_2 - #| b15 = tb5_3 - #| let Quadruple(tb6_0, tb6_1, tb6_2, tb6_3) = qr( - #| Quadruple(b1, b6, b11, b12), - #| ) - #| b1 = tb6_0 - #| b6 = tb6_1 - #| b11 = tb6_2 - #| b12 = tb6_3 - #| let Quadruple(tb7_0, tb7_1, tb7_2, tb7_3) = qr(Quadruple(b2, b7, b8, b13)) - #| b2 = tb7_0 - #| b7 = tb7_1 - #| b8 = tb7_2 - #| b13 = tb7_3 - #| let Quadruple(tb8_0, tb8_1, tb8_2, tb8_3) = qr(Quadruple(b3, b4, b9, b14)) - #| b3 = tb8_0 - #| b4 = tb8_1 - #| b9 = tb8_2 - #| b14 = tb8_3 - #| } - #| buf[0 * 4 + i] = b0 - #| buf[1 * 4 + i] = b1 - #| buf[2 * 4 + i] = b2 - #| buf[3 * 4 + i] = b3 - #| buf[4 * 4 + i] += b4 - #| buf[5 * 4 + i] += b5 - #| buf[6 * 4 + i] += b6 - #| buf[7 * 4 + i] += b7 - #| buf[8 * 4 + i] += b8 - #| buf[9 * 4 + i] += b9 - #| buf[10 * 4 + i] += b10 - #| buf[11 * 4 + i] += b11 - #| buf[12 * 4 + i] = b12 - #| buf[13 * 4 + i] = b13 - #| buf[14 * 4 + i] = b14 - #| buf[15 * 4 + i] = b15 - #| } - #|} - #|fn setup( - #| seed : FixedArray[UInt], - #| b32 : FixedArray[UInt], - #| counter : UInt, - #|) -> Unit { - #| b32[0 * 4 + 0] = 0x61707865 - #| b32[0 * 4 + 1] = 0x61707865 - #| b32[0 * 4 + 2] = 0x61707865 - #| b32[0 * 4 + 3] = 0x61707865 - #| b32[1 * 4 + 0] = 0x3320646e - #| b32[1 * 4 + 1] = 0x3320646e - #| b32[1 * 4 + 2] = 0x3320646e - #| b32[1 * 4 + 3] = 0x3320646e - #| b32[2 * 4 + 0] = 0x79622d32 - #| b32[2 * 4 + 1] = 0x79622d32 - #| b32[2 * 4 + 2] = 0x79622d32 - #| b32[2 * 4 + 3] = 0x79622d32 - #| b32[3 * 4 + 0] = 0x6b206574 - #| b32[3 * 4 + 1] = 0x6b206574 - #| b32[3 * 4 + 2] = 0x6b206574 - #| b32[3 * 4 + 3] = 0x6b206574 - #| b32[4 * 4 + 0] = seed[0] - #| b32[4 * 4 + 1] = seed[0] - #| b32[4 * 4 + 2] = seed[0] - #| b32[4 * 4 + 3] = seed[0] - #| b32[5 * 4 + 0] = seed[1] - #| b32[5 * 4 + 1] = seed[1] - #| b32[5 * 4 + 2] = seed[1] - #| b32[5 * 4 + 3] = seed[1] - #| b32[6 * 4 + 0] = seed[2] - #| b32[6 * 4 + 1] = seed[2] - #| b32[6 * 4 + 2] = seed[2] - #| b32[6 * 4 + 3] = seed[2] - #| b32[7 * 4 + 0] = seed[3] - #| b32[7 * 4 + 1] = seed[3] - #| b32[7 * 4 + 2] = seed[3] - #| b32[7 * 4 + 3] = seed[3] - #| b32[8 * 4 + 0] = seed[4] - #| b32[8 * 4 + 1] = seed[4] - #| b32[8 * 4 + 2] = seed[4] - #| b32[8 * 4 + 3] = seed[4] - #| b32[9 * 4 + 0] = seed[5] - #| b32[9 * 4 + 1] = seed[5] - #| b32[9 * 4 + 2] = seed[5] - #| b32[9 * 4 + 3] = seed[5] - #| b32[10 * 4 + 0] = seed[6] - #| b32[10 * 4 + 1] = seed[6] - #| b32[10 * 4 + 2] = seed[6] - #| b32[10 * 4 + 3] = seed[6] - #| b32[11 * 4 + 0] = seed[7] - #| b32[11 * 4 + 1] = seed[7] - #| b32[11 * 4 + 2] = seed[7] - #| b32[11 * 4 + 3] = seed[7] - #| b32[12 * 4 + 0] = counter + 0 - #| b32[12 * 4 + 1] = counter + 1 - #| b32[12 * 4 + 2] = counter + 2 - #| b32[12 * 4 + 3] = counter + 3 - #| b32[13 * 4 + 0] = 0 - #| b32[13 * 4 + 1] = 0 - #| b32[13 * 4 + 2] = 0 - #| b32[13 * 4 + 3] = 0 - #| b32[14 * 4 + 0] = 0 - #| b32[14 * 4 + 1] = 0 - #| b32[14 * 4 + 2] = 0 - #| b32[14 * 4 + 3] = 0 - #| b32[15 * 4 + 0] = 0 - #| b32[15 * 4 + 1] = 0 - #| b32[15 * 4 + 2] = 0 - #| b32[15 * 4 + 3] = 0 - #|} - #|test "BUFFER_CHUNK_NUM is power of 2" { - #| assert_eq(BUFFER_CHUNK_NUM.clz() + BUFFER_CHUNK_NUM.ctz(), 31) - #|} - #|test "output" { - #| let s = ChaCha8::new(b"ABCDEFGHIJKLMNOPQRSTUVWXYZ123456") - #| let res = Array::new(capacity=372) - #| fn uint64(s : ChaCha8) -> UInt64 { - #| for { - #| if s.next() is Some(x) { - #| return x - #| } - #| s.refill() - #| } - #| } - #| for i in 0..<372 { - #| let x = uint64(s) - #| res.push(x) - #| } - #| let expected = [ - #| 13219109469176600229UL, 1252193259764759612UL, 10098646897834928252UL, 9142445797040479446UL, - #| 14963947397558572717UL, 1011356013395962489UL, 4360278772332321598UL, 11266561239126549327UL, - #| 16103107970030431910UL, 3951155890335085418UL, 17217491508779737119UL, 620366957612729398UL, - #| 15701003340574544488UL, 16946962128229337786UL, 5734710318278665825UL, 14107018073513584172UL, - #| 10514695901183618686UL, 8668570317698669510UL, 6644195231047269920UL, 5695522258251995816UL, - #| 18173674537264966642UL, 6561080880156464316UL, 7896566770606135777UL, 17198961315715285235UL, - #| 3258233649777561765UL, 4039019003980269744UL, 17199080872890330697UL, 17597083911441838460UL, - #| 9541597232904836516UL, 10269632480771352091UL, 1791309313159652499UL, 1121290688170442051UL, - #| 14767415290099658880UL, 18264015867885335344UL, 10795746865526236211UL, 7814966709161082135UL, - #| 5056082071174014306UL, 6606687772221963370UL, 902460967827941768UL, 15247644503822243389UL, - #| 13837920613503741631UL, 6215820458297045417UL, 2701601382099612372UL, 8049443921449462014UL, - #| 12580932726856406240UL, 5068579462968063859UL, 2054759765710618254UL, 8060325759976441792UL, - #| 3952703220727229276UL, 11868554197401451959UL, 5611917470950228677UL, 14826085289999852455UL, - #| 18131733951999902497UL, 6983040833037131399UL, 15098965934858340182UL, 7162487557317849930UL, - #| 389612597396113390UL, 5480468948381420210UL, 14924541494497045954UL, 438038016380948435UL, - #| 15107526033745383085UL, 3577988464916041960UL, 12379376873809997548UL, 4629939204773816090UL, - #| 4382836348202044776UL, 15911307370497934714UL, 16912525941835256446UL, 1749399752872286892UL, - #| 17865934552210109010UL, 6342441227090084049UL, 6679300346758746971UL, 16633103117551110662UL, - #| 369926567391976152UL, 3270154504052173416UL, 12351442307584366520UL, 14053856752323452444UL, - #| 5700095014850418212UL, 18134114469714363192UL, 11060594460025237009UL, 1231359220627153402UL, - #| 562452272787830041UL, 2978775404523127572UL, 4722226048622717816UL, 6253931703231703629UL, - #| 9215422719337958629UL, 3873253580645818250UL, 1288530853271360801UL, 11001669669030575221UL, - #| 15088099745414120440UL, 10121311161118028787UL, 2646319338087045047UL, 8736474933647836016UL, - #| 10270419548610515257UL, 4775977266197392933UL, 5858955664787759631UL, 15884112255303985129UL, - #| 1570402559843208890UL, 14683984304255533684UL, 4590793746421620769UL, 15088822470495597798UL, - #| 430063278371467896UL, 17951554591419905623UL, 871816740556950425UL, 17903421440867820178UL, - #| 13750571273678813240UL, 17408919480923799904UL, 14550467517685344003UL, 17801022151644150006UL, - #| 15135601085914355452UL, 3483086720686978374UL, 9411102566564534151UL, 1565275101947305404UL, - #| 18195171881473325257UL, 3771067494878101692UL, 7443114766343082856UL, 1311911009840065015UL, - #| 1031414546975514137UL, 16727931877057143004UL, 420176525623228030UL, 16779254430513255833UL, - #| 2085321528439172864UL, 14769502908867070793UL, 3476754806476653326UL, 9663999206884821105UL, - #| 6864012991572870279UL, 2719468417766812445UL, 13735767778024137757UL, 7331676388138190150UL, - #| 15110277136215905228UL, 118894811326561078UL, 6308935423749160781UL, 1857610629058673910UL, - #| 15843686394045370811UL, 10951543581626859443UL, 3587431610669043023UL, 670469650389812154UL, - #| 476209600999700306UL, 6589566024609793738UL, 8281611217869782149UL, 15129277549214352190UL, - #| 13446421929377692845UL, 17071158676955966275UL, 7349330903428905191UL, 3277698994734830674UL, - #| 14731635658592643043UL, 5477400073429632652UL, 67518392538487036UL, 11035168000757098093UL, - #| 9797693702590129641UL, 14649582299731326424UL, 15236666389149272153UL, 16511980240231261314UL, - #| 2249833951459307500UL, 13214955418772830438UL, 329963039908253864UL, 8574511220958401562UL, - #| 4538345089129965474UL, 16353802882881726632UL, 8935276449126753317UL, 13532443277699696063UL, - #| 8669346374187395779UL, 17810417737921607796UL, 3904677225590828551UL, 10264576476552345822UL, - #| 3042606770072189440UL, 12878478126980245939UL, 17862138228081367377UL, 16992359172961651842UL, - #| 17034107108697981338UL, 12909026467335450156UL, 2470441546010339704UL, 3634699771143106326UL, - #| 366960336551226348UL, 5510841956427041079UL, 15461212383052875073UL, 16433279593065139848UL, - #| 4486890193637877972UL, 14360905330534596440UL, 4449385520993789019UL, 3743094329222006520UL, - #| 2212668117926313829UL, 4681723502265844963UL, 13296513799272088946UL, 2343616111600662093UL, - #| 14717171566066041529UL, 11738831003851491807UL, 15851419960104864784UL, 8132762647638440149UL, - #| 3464418631265929631UL, 340027485718840165UL, 8395791638092059350UL, 3109485649064359417UL, - #| 10944349985020042736UL, 6522608726689095595UL, 17803052569896648610UL, 2064238649661354599UL, - #| 4092763376312896325UL, 15988266335744638521UL, 16848187183754420180UL, 199841868197609864UL, - #| 17491157950173501157UL, 12533485177359032661UL, 6254686503080376974UL, 5499127381395659705UL, - #| 10487847042307388775UL, 12368654789669906974UL, 2361938659724380109UL, 8148818964487342298UL, - #| 12717021730603072605UL, 15728257831000719154UL, 15823591063810279774UL, 6928887951986678348UL, - #| 17959062744186568888UL, 16016655507227678734UL, 14898526437837544110UL, 16974466848830908932UL, - #| 15320157178342639871UL, 8261903640164714632UL, 14435417271854760UL, 9182672404209601003UL, - #| 5994285655773158181UL, 15654703508405219038UL, 16079243345868226083UL, 10784497444694088416UL, - #| 4442318623009455690UL, 7578904045792755239UL, 4660917127407640248UL, 1338871040102977572UL, - #| 7923968833761895669UL, 16874906449763725362UL, 6867431507591727612UL, 6311558572587278442UL, - #| 11133241125491102835UL, 11738312930013082355UL, 11475845091361842759UL, 1643869946623606078UL, - #| 10415771985971144045UL, 16177299554619494974UL, 539570561320537202UL, 14686903393511273001UL, - #| 4445884513647149105UL, 5098090666552700373UL, 15054419504752089185UL, 3474469100259604016UL, - #| 6290470378995655110UL, 12581245818984890955UL, 12787308417917333104UL, 15615073174539148765UL, - #| 12984984669203863910UL, 5985056152809872019UL, 11524779172526084917UL, 12665285781050723551UL, - #| 17258307941988319274UL, 1228317169172941352UL, 11160397433235040502UL, 9071341095814202162UL, - #| 16466220084500004578UL, 17881879368693790694UL, 11823018491644357805UL, 16578188432210840351UL, - #| 9406010430949605407UL, 11905115929048085077UL, 9944213925190004442UL, 7029678422186467496UL, - #| 11401152387492259905UL, 10919895159361451251UL, 8495109194203518959UL, 16018667729961568082UL, - #| 167446916071967039UL, 5832416432401633017UL, 2555624166217836526UL, 4693948454793001376UL, - #| 15027938303073958689UL, 3816085682362256244UL, 3185235675206645589UL, 14811052307061536715UL, - #| 16390566561388972206UL, 16262619695511054469UL, 18052593823409859051UL, 3945540604022845918UL, - #| 15826009464703323776UL, 7719326347171925540UL, 9769778031520080067UL, 421859423473436660UL, - #| 13367093898566883586UL, 6779889834239319169UL, 609582038820777224UL, 8614685872506396309UL, - #| 4322299411370527537UL, 12846241946314463225UL, 7603764924892388925UL, 14478986206635481787UL, - #| 12755177540574038518UL, 6194314060039108547UL, 7432498317049243916UL, 13744344095303706494UL, - #| 4564573594452194471UL, 15206391374377392170UL, 14985029622013689232UL, 14328768324291300885UL, - #| 10654090591156151429UL, 7338671807663089189UL, 16334907285225846266UL, 7423398075744368270UL, - #| 13908293662617472937UL, 17175512688958868014UL, 7864028190390018941UL, 13126986956610526127UL, - #| 7926473773501694475UL, 1941817884837167576UL, 15856689629067382306UL, 11177334980354607906UL, - #| 7146885710676518584UL, 15983324774902192370UL, 17386093453964105449UL, 4150817240659351930UL, - #| 7715942048190956297UL, 7276773301104081815UL, 13271959532491042945UL, 1194118668544183835UL, - #| 17605071903565571062UL, 8948583740938417863UL, 3864418170274807074UL, 3699237212540510096UL, - #| 14714003198217388528UL, 14269453830925281739UL, 8957047989018367339UL, 12402048382093370001UL, - #| 11758047802384768757UL, 7093460309329455699UL, 384408371497488372UL, 1458858056370266940UL, - #| 15774153359596962328UL, 5577985376535770293UL, 3965786813088619889UL, 17835800480481320920UL, - #| 32994991092960231UL, 17146972595756459521UL, 12264557860820767038UL, 13718959782553074566UL, - #| 1372337231943282583UL, 15958043944784669526UL, 17520298198669188203UL, 3031291504644241637UL, - #| 6514984797562383624UL, 4345071177348538448UL, 3359260195018829989UL, 2607793539626362761UL, - #| 16792663172613334423UL, 9898393582456908268UL, 2786478731415243607UL, 12029113901756054096UL, - #| 3691479334576095829UL, 11929280456476427793UL, 18327972477027512052UL, 254886074006853656UL, - #| 2927328918014182935UL, 4439939690082200099UL, 5969478689443458641UL, 14369317615642310767UL, - #| 17764732325494572140UL, 10115938472474762880UL, 369466901724782737UL, 2269989694701338999UL, - #| 1231466417883291608UL, 4918841702239877720UL, 13883670878602349637UL, 11470126477371023265UL, - #| 17128636052794644986UL, 205335811880395712UL, 12443170494233065292UL, 15986026963143729439UL, - #| ] - #| assert_eq(res, expected) - #|} - ), - }, + "random_source_chacha.mbt": ( + #|struct ChaCha8 { + #| buffer : FixedArray[UInt] + #| seed : FixedArray[UInt] + #| mut i : UInt + #| mut n : UInt + #| mut counter : UInt + #|} + #|pub fn ChaCha8::new(seed : Bytes) -> ChaCha8 { + #| let seed = FixedArray::makei(SEED_CHUNK_NUM * 2, i => { + #| match seed[i * 4:] { + #| [u32le(x), ..] => x + #| _ => abort("seed must be 32 bytes long") + #| } + #| }) + #| let buffer = FixedArray::make(BUFFER_CHUNK_NUM * 2, 0U) + #| chacha_block(seed, buffer, 0) + #| { seed, buffer, counter: 0, i: 0, n: BUFFER_CHUNK_NUM.reinterpret_as_uint() } + #|} + #|const COUNTER_INC = 4U + #|const COUNTER_MAX = 16U + #|const BUFFER_CHUNK_NUM = 32 + #|const SEED_CHUNK_NUM = 4 + #|pub fn ChaCha8::next(self : ChaCha8) -> UInt64? { + #| let i = self.i + #| if i >= self.n { + #| return None + #| } + #| self.i = i + 1 + #| let index = i.reinterpret_as_int() & (BUFFER_CHUNK_NUM - 1) + #| let lo = self.buffer[index * 2].to_uint64() + #| let hi = self.buffer[index * 2 + 1].to_uint64() + #| Some((hi << 32) | lo) + #|} + #|pub fn ChaCha8::refill(self : ChaCha8) -> Unit { + #| self.counter += COUNTER_INC + #| if self.counter == COUNTER_MAX { + #| self.buffer.blit_to( + #| self.seed, + #| len=SEED_CHUNK_NUM * 2, + #| src_offset=(BUFFER_CHUNK_NUM - SEED_CHUNK_NUM) * 2, + #| ) + #| self.counter = 0 + #| } + #| chacha_block(self.seed, self.buffer, self.counter) + #| self.i = 0 + #| self.n = if self.counter == COUNTER_MAX - COUNTER_INC { + #| (BUFFER_CHUNK_NUM - SEED_CHUNK_NUM).reinterpret_as_uint() + #| } else { + #| BUFFER_CHUNK_NUM.reinterpret_as_uint() + #| } + #|} + #|#valtype + #|priv struct Quadruple(UInt, UInt, UInt, UInt) + #|fn chacha_block( + #| seed : FixedArray[UInt], + #| buf : FixedArray[UInt], + #| counter : UInt, + #|) -> Unit { + #| fn qr(t : Quadruple) -> Quadruple { + #| let Quadruple(a, b, c, d) = t + #| let a = a + b + #| let d = d ^ a + #| let d = (d << 16) | (d >> 16) + #| let c = c + d + #| let b = b ^ c + #| let b = (b << 12) | (b >> 20) + #| let a = a + b + #| let d = d ^ a + #| let d = (d << 8) | (d >> 24) + #| let c = c + d + #| let b = b ^ c + #| let b = (b << 7) | (b >> 25) + #| Quadruple(a, b, c, d) + #| } + #| setup(seed, buf, counter) + #| for i in 0..<4 { + #| let mut b0 = buf[0 * 4 + i] + #| let mut b1 = buf[1 * 4 + i] + #| let mut b2 = buf[2 * 4 + i] + #| let mut b3 = buf[3 * 4 + i] + #| let mut b4 = buf[4 * 4 + i] + #| let mut b5 = buf[5 * 4 + i] + #| let mut b6 = buf[6 * 4 + i] + #| let mut b7 = buf[7 * 4 + i] + #| let mut b8 = buf[8 * 4 + i] + #| let mut b9 = buf[9 * 4 + i] + #| let mut b10 = buf[10 * 4 + i] + #| let mut b11 = buf[11 * 4 + i] + #| let mut b12 = buf[12 * 4 + i] + #| let mut b13 = buf[13 * 4 + i] + #| let mut b14 = buf[14 * 4 + i] + #| let mut b15 = buf[15 * 4 + i] + #| for _ in 0..<4 { + #| let Quadruple(tb1_0, tb1_1, tb1_2, tb1_3) = qr(Quadruple(b0, b4, b8, b12)) + #| b0 = tb1_0 + #| b4 = tb1_1 + #| b8 = tb1_2 + #| b12 = tb1_3 + #| let Quadruple(tb2_0, tb2_1, tb2_2, tb2_3) = qr(Quadruple(b1, b5, b9, b13)) + #| b1 = tb2_0 + #| b5 = tb2_1 + #| b9 = tb2_2 + #| b13 = tb2_3 + #| let Quadruple(tb3_0, tb3_1, tb3_2, tb3_3) = qr( + #| Quadruple(b2, b6, b10, b14), + #| ) + #| b2 = tb3_0 + #| b6 = tb3_1 + #| b10 = tb3_2 + #| b14 = tb3_3 + #| let Quadruple(tb4_0, tb4_1, tb4_2, tb4_3) = qr( + #| Quadruple(b3, b7, b11, b15), + #| ) + #| b3 = tb4_0 + #| b7 = tb4_1 + #| b11 = tb4_2 + #| b15 = tb4_3 + #| let Quadruple(tb5_0, tb5_1, tb5_2, tb5_3) = qr( + #| Quadruple(b0, b5, b10, b15), + #| ) + #| b0 = tb5_0 + #| b5 = tb5_1 + #| b10 = tb5_2 + #| b15 = tb5_3 + #| let Quadruple(tb6_0, tb6_1, tb6_2, tb6_3) = qr( + #| Quadruple(b1, b6, b11, b12), + #| ) + #| b1 = tb6_0 + #| b6 = tb6_1 + #| b11 = tb6_2 + #| b12 = tb6_3 + #| let Quadruple(tb7_0, tb7_1, tb7_2, tb7_3) = qr(Quadruple(b2, b7, b8, b13)) + #| b2 = tb7_0 + #| b7 = tb7_1 + #| b8 = tb7_2 + #| b13 = tb7_3 + #| let Quadruple(tb8_0, tb8_1, tb8_2, tb8_3) = qr(Quadruple(b3, b4, b9, b14)) + #| b3 = tb8_0 + #| b4 = tb8_1 + #| b9 = tb8_2 + #| b14 = tb8_3 + #| } + #| buf[0 * 4 + i] = b0 + #| buf[1 * 4 + i] = b1 + #| buf[2 * 4 + i] = b2 + #| buf[3 * 4 + i] = b3 + #| buf[4 * 4 + i] += b4 + #| buf[5 * 4 + i] += b5 + #| buf[6 * 4 + i] += b6 + #| buf[7 * 4 + i] += b7 + #| buf[8 * 4 + i] += b8 + #| buf[9 * 4 + i] += b9 + #| buf[10 * 4 + i] += b10 + #| buf[11 * 4 + i] += b11 + #| buf[12 * 4 + i] = b12 + #| buf[13 * 4 + i] = b13 + #| buf[14 * 4 + i] = b14 + #| buf[15 * 4 + i] = b15 + #| } + #|} + #|fn setup( + #| seed : FixedArray[UInt], + #| b32 : FixedArray[UInt], + #| counter : UInt, + #|) -> Unit { + #| b32[0 * 4 + 0] = 0x61707865 + #| b32[0 * 4 + 1] = 0x61707865 + #| b32[0 * 4 + 2] = 0x61707865 + #| b32[0 * 4 + 3] = 0x61707865 + #| b32[1 * 4 + 0] = 0x3320646e + #| b32[1 * 4 + 1] = 0x3320646e + #| b32[1 * 4 + 2] = 0x3320646e + #| b32[1 * 4 + 3] = 0x3320646e + #| b32[2 * 4 + 0] = 0x79622d32 + #| b32[2 * 4 + 1] = 0x79622d32 + #| b32[2 * 4 + 2] = 0x79622d32 + #| b32[2 * 4 + 3] = 0x79622d32 + #| b32[3 * 4 + 0] = 0x6b206574 + #| b32[3 * 4 + 1] = 0x6b206574 + #| b32[3 * 4 + 2] = 0x6b206574 + #| b32[3 * 4 + 3] = 0x6b206574 + #| b32[4 * 4 + 0] = seed[0] + #| b32[4 * 4 + 1] = seed[0] + #| b32[4 * 4 + 2] = seed[0] + #| b32[4 * 4 + 3] = seed[0] + #| b32[5 * 4 + 0] = seed[1] + #| b32[5 * 4 + 1] = seed[1] + #| b32[5 * 4 + 2] = seed[1] + #| b32[5 * 4 + 3] = seed[1] + #| b32[6 * 4 + 0] = seed[2] + #| b32[6 * 4 + 1] = seed[2] + #| b32[6 * 4 + 2] = seed[2] + #| b32[6 * 4 + 3] = seed[2] + #| b32[7 * 4 + 0] = seed[3] + #| b32[7 * 4 + 1] = seed[3] + #| b32[7 * 4 + 2] = seed[3] + #| b32[7 * 4 + 3] = seed[3] + #| b32[8 * 4 + 0] = seed[4] + #| b32[8 * 4 + 1] = seed[4] + #| b32[8 * 4 + 2] = seed[4] + #| b32[8 * 4 + 3] = seed[4] + #| b32[9 * 4 + 0] = seed[5] + #| b32[9 * 4 + 1] = seed[5] + #| b32[9 * 4 + 2] = seed[5] + #| b32[9 * 4 + 3] = seed[5] + #| b32[10 * 4 + 0] = seed[6] + #| b32[10 * 4 + 1] = seed[6] + #| b32[10 * 4 + 2] = seed[6] + #| b32[10 * 4 + 3] = seed[6] + #| b32[11 * 4 + 0] = seed[7] + #| b32[11 * 4 + 1] = seed[7] + #| b32[11 * 4 + 2] = seed[7] + #| b32[11 * 4 + 3] = seed[7] + #| b32[12 * 4 + 0] = counter + 0 + #| b32[12 * 4 + 1] = counter + 1 + #| b32[12 * 4 + 2] = counter + 2 + #| b32[12 * 4 + 3] = counter + 3 + #| b32[13 * 4 + 0] = 0 + #| b32[13 * 4 + 1] = 0 + #| b32[13 * 4 + 2] = 0 + #| b32[13 * 4 + 3] = 0 + #| b32[14 * 4 + 0] = 0 + #| b32[14 * 4 + 1] = 0 + #| b32[14 * 4 + 2] = 0 + #| b32[14 * 4 + 3] = 0 + #| b32[15 * 4 + 0] = 0 + #| b32[15 * 4 + 1] = 0 + #| b32[15 * 4 + 2] = 0 + #| b32[15 * 4 + 3] = 0 + #|} + #|test "BUFFER_CHUNK_NUM is power of 2" { + #| assert_eq(BUFFER_CHUNK_NUM.clz() + BUFFER_CHUNK_NUM.ctz(), 31) + #|} + #|test "output" { + #| let s = ChaCha8::new(b"ABCDEFGHIJKLMNOPQRSTUVWXYZ123456") + #| let res = Array::new(capacity=372) + #| fn uint64(s : ChaCha8) -> UInt64 { + #| for ;; { + #| if s.next() is Some(x) { + #| return x + #| } + #| s.refill() + #| } + #| } + #| for _ in 0..<372 { + #| let x = uint64(s) + #| res.push(x) + #| } + #| let expected = [ + #| 13219109469176600229UL, 1252193259764759612UL, 10098646897834928252UL, 9142445797040479446UL, + #| 14963947397558572717UL, 1011356013395962489UL, 4360278772332321598UL, 11266561239126549327UL, + #| 16103107970030431910UL, 3951155890335085418UL, 17217491508779737119UL, 620366957612729398UL, + #| 15701003340574544488UL, 16946962128229337786UL, 5734710318278665825UL, 14107018073513584172UL, + #| 10514695901183618686UL, 8668570317698669510UL, 6644195231047269920UL, 5695522258251995816UL, + #| 18173674537264966642UL, 6561080880156464316UL, 7896566770606135777UL, 17198961315715285235UL, + #| 3258233649777561765UL, 4039019003980269744UL, 17199080872890330697UL, 17597083911441838460UL, + #| 9541597232904836516UL, 10269632480771352091UL, 1791309313159652499UL, 1121290688170442051UL, + #| 14767415290099658880UL, 18264015867885335344UL, 10795746865526236211UL, 7814966709161082135UL, + #| 5056082071174014306UL, 6606687772221963370UL, 902460967827941768UL, 15247644503822243389UL, + #| 13837920613503741631UL, 6215820458297045417UL, 2701601382099612372UL, 8049443921449462014UL, + #| 12580932726856406240UL, 5068579462968063859UL, 2054759765710618254UL, 8060325759976441792UL, + #| 3952703220727229276UL, 11868554197401451959UL, 5611917470950228677UL, 14826085289999852455UL, + #| 18131733951999902497UL, 6983040833037131399UL, 15098965934858340182UL, 7162487557317849930UL, + #| 389612597396113390UL, 5480468948381420210UL, 14924541494497045954UL, 438038016380948435UL, + #| 15107526033745383085UL, 3577988464916041960UL, 12379376873809997548UL, 4629939204773816090UL, + #| 4382836348202044776UL, 15911307370497934714UL, 16912525941835256446UL, 1749399752872286892UL, + #| 17865934552210109010UL, 6342441227090084049UL, 6679300346758746971UL, 16633103117551110662UL, + #| 369926567391976152UL, 3270154504052173416UL, 12351442307584366520UL, 14053856752323452444UL, + #| 5700095014850418212UL, 18134114469714363192UL, 11060594460025237009UL, 1231359220627153402UL, + #| 562452272787830041UL, 2978775404523127572UL, 4722226048622717816UL, 6253931703231703629UL, + #| 9215422719337958629UL, 3873253580645818250UL, 1288530853271360801UL, 11001669669030575221UL, + #| 15088099745414120440UL, 10121311161118028787UL, 2646319338087045047UL, 8736474933647836016UL, + #| 10270419548610515257UL, 4775977266197392933UL, 5858955664787759631UL, 15884112255303985129UL, + #| 1570402559843208890UL, 14683984304255533684UL, 4590793746421620769UL, 15088822470495597798UL, + #| 430063278371467896UL, 17951554591419905623UL, 871816740556950425UL, 17903421440867820178UL, + #| 13750571273678813240UL, 17408919480923799904UL, 14550467517685344003UL, 17801022151644150006UL, + #| 15135601085914355452UL, 3483086720686978374UL, 9411102566564534151UL, 1565275101947305404UL, + #| 18195171881473325257UL, 3771067494878101692UL, 7443114766343082856UL, 1311911009840065015UL, + #| 1031414546975514137UL, 16727931877057143004UL, 420176525623228030UL, 16779254430513255833UL, + #| 2085321528439172864UL, 14769502908867070793UL, 3476754806476653326UL, 9663999206884821105UL, + #| 6864012991572870279UL, 2719468417766812445UL, 13735767778024137757UL, 7331676388138190150UL, + #| 15110277136215905228UL, 118894811326561078UL, 6308935423749160781UL, 1857610629058673910UL, + #| 15843686394045370811UL, 10951543581626859443UL, 3587431610669043023UL, 670469650389812154UL, + #| 476209600999700306UL, 6589566024609793738UL, 8281611217869782149UL, 15129277549214352190UL, + #| 13446421929377692845UL, 17071158676955966275UL, 7349330903428905191UL, 3277698994734830674UL, + #| 14731635658592643043UL, 5477400073429632652UL, 67518392538487036UL, 11035168000757098093UL, + #| 9797693702590129641UL, 14649582299731326424UL, 15236666389149272153UL, 16511980240231261314UL, + #| 2249833951459307500UL, 13214955418772830438UL, 329963039908253864UL, 8574511220958401562UL, + #| 4538345089129965474UL, 16353802882881726632UL, 8935276449126753317UL, 13532443277699696063UL, + #| 8669346374187395779UL, 17810417737921607796UL, 3904677225590828551UL, 10264576476552345822UL, + #| 3042606770072189440UL, 12878478126980245939UL, 17862138228081367377UL, 16992359172961651842UL, + #| 17034107108697981338UL, 12909026467335450156UL, 2470441546010339704UL, 3634699771143106326UL, + #| 366960336551226348UL, 5510841956427041079UL, 15461212383052875073UL, 16433279593065139848UL, + #| 4486890193637877972UL, 14360905330534596440UL, 4449385520993789019UL, 3743094329222006520UL, + #| 2212668117926313829UL, 4681723502265844963UL, 13296513799272088946UL, 2343616111600662093UL, + #| 14717171566066041529UL, 11738831003851491807UL, 15851419960104864784UL, 8132762647638440149UL, + #| 3464418631265929631UL, 340027485718840165UL, 8395791638092059350UL, 3109485649064359417UL, + #| 10944349985020042736UL, 6522608726689095595UL, 17803052569896648610UL, 2064238649661354599UL, + #| 4092763376312896325UL, 15988266335744638521UL, 16848187183754420180UL, 199841868197609864UL, + #| 17491157950173501157UL, 12533485177359032661UL, 6254686503080376974UL, 5499127381395659705UL, + #| 10487847042307388775UL, 12368654789669906974UL, 2361938659724380109UL, 8148818964487342298UL, + #| 12717021730603072605UL, 15728257831000719154UL, 15823591063810279774UL, 6928887951986678348UL, + #| 17959062744186568888UL, 16016655507227678734UL, 14898526437837544110UL, 16974466848830908932UL, + #| 15320157178342639871UL, 8261903640164714632UL, 14435417271854760UL, 9182672404209601003UL, + #| 5994285655773158181UL, 15654703508405219038UL, 16079243345868226083UL, 10784497444694088416UL, + #| 4442318623009455690UL, 7578904045792755239UL, 4660917127407640248UL, 1338871040102977572UL, + #| 7923968833761895669UL, 16874906449763725362UL, 6867431507591727612UL, 6311558572587278442UL, + #| 11133241125491102835UL, 11738312930013082355UL, 11475845091361842759UL, 1643869946623606078UL, + #| 10415771985971144045UL, 16177299554619494974UL, 539570561320537202UL, 14686903393511273001UL, + #| 4445884513647149105UL, 5098090666552700373UL, 15054419504752089185UL, 3474469100259604016UL, + #| 6290470378995655110UL, 12581245818984890955UL, 12787308417917333104UL, 15615073174539148765UL, + #| 12984984669203863910UL, 5985056152809872019UL, 11524779172526084917UL, 12665285781050723551UL, + #| 17258307941988319274UL, 1228317169172941352UL, 11160397433235040502UL, 9071341095814202162UL, + #| 16466220084500004578UL, 17881879368693790694UL, 11823018491644357805UL, 16578188432210840351UL, + #| 9406010430949605407UL, 11905115929048085077UL, 9944213925190004442UL, 7029678422186467496UL, + #| 11401152387492259905UL, 10919895159361451251UL, 8495109194203518959UL, 16018667729961568082UL, + #| 167446916071967039UL, 5832416432401633017UL, 2555624166217836526UL, 4693948454793001376UL, + #| 15027938303073958689UL, 3816085682362256244UL, 3185235675206645589UL, 14811052307061536715UL, + #| 16390566561388972206UL, 16262619695511054469UL, 18052593823409859051UL, 3945540604022845918UL, + #| 15826009464703323776UL, 7719326347171925540UL, 9769778031520080067UL, 421859423473436660UL, + #| 13367093898566883586UL, 6779889834239319169UL, 609582038820777224UL, 8614685872506396309UL, + #| 4322299411370527537UL, 12846241946314463225UL, 7603764924892388925UL, 14478986206635481787UL, + #| 12755177540574038518UL, 6194314060039108547UL, 7432498317049243916UL, 13744344095303706494UL, + #| 4564573594452194471UL, 15206391374377392170UL, 14985029622013689232UL, 14328768324291300885UL, + #| 10654090591156151429UL, 7338671807663089189UL, 16334907285225846266UL, 7423398075744368270UL, + #| 13908293662617472937UL, 17175512688958868014UL, 7864028190390018941UL, 13126986956610526127UL, + #| 7926473773501694475UL, 1941817884837167576UL, 15856689629067382306UL, 11177334980354607906UL, + #| 7146885710676518584UL, 15983324774902192370UL, 17386093453964105449UL, 4150817240659351930UL, + #| 7715942048190956297UL, 7276773301104081815UL, 13271959532491042945UL, 1194118668544183835UL, + #| 17605071903565571062UL, 8948583740938417863UL, 3864418170274807074UL, 3699237212540510096UL, + #| 14714003198217388528UL, 14269453830925281739UL, 8957047989018367339UL, 12402048382093370001UL, + #| 11758047802384768757UL, 7093460309329455699UL, 384408371497488372UL, 1458858056370266940UL, + #| 15774153359596962328UL, 5577985376535770293UL, 3965786813088619889UL, 17835800480481320920UL, + #| 32994991092960231UL, 17146972595756459521UL, 12264557860820767038UL, 13718959782553074566UL, + #| 1372337231943282583UL, 15958043944784669526UL, 17520298198669188203UL, 3031291504644241637UL, + #| 6514984797562383624UL, 4345071177348538448UL, 3359260195018829989UL, 2607793539626362761UL, + #| 16792663172613334423UL, 9898393582456908268UL, 2786478731415243607UL, 12029113901756054096UL, + #| 3691479334576095829UL, 11929280456476427793UL, 18327972477027512052UL, 254886074006853656UL, + #| 2927328918014182935UL, 4439939690082200099UL, 5969478689443458641UL, 14369317615642310767UL, + #| 17764732325494572140UL, 10115938472474762880UL, 369466901724782737UL, 2269989694701338999UL, + #| 1231466417883291608UL, 4918841702239877720UL, 13883670878602349637UL, 11470126477371023265UL, + #| 17128636052794644986UL, 205335811880395712UL, 12443170494233065292UL, 15986026963143729439UL, + #| ] + #| assert_eq(res, expected) + #|} + ) + } ) ///| let moonbitlang_core_ref_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/ref", - deps={ - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module, - }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": ["moonbitlang/core/builtin", "moonbitlang/core/quickcheck"], - #| "test-import": [] - #|} - ), - "ref.mbt": ( - #|pub impl[X : Show] Show for Ref[X] with output(self, logger) { - #| logger..write_string("{val: ")..write_object(self.val)..write_string("}") - #|} - #|pub fn[T] Ref::new(x : T) -> Ref[T] { - #| { val: x } - #|} - #|test "to_string" { - #| inspect(new(3), content="{val: 3}") - #|} - #|pub fn[T] new(x : T) -> Ref[T] { - #| { val: x } - #|} - #|pub fn[T, R] Ref::map(self : Ref[T], f : (T) -> R raise?) -> Ref[R] raise? { - #| { val: f(self.val) } - #|} - #|pub fn[T, R] Ref::protect(self : Ref[T], a : T, f : () -> R raise?) -> R raise? { - #| let old = self.val - #| self.val = a - #| try f() catch { - #| err => { - #| self.val = old - #| raise err - #| } - #| } noraise { - #| r => { - #| self.val = old - #| r - #| } - #| } - #|} - #|#as_free_fn - #|pub fn[T] Ref::swap(self : Ref[T], that : Ref[T]) -> Unit { - #| let tmp = self.val - #| self.val = that.val - #| that.val = tmp - #|} - #|test "swap" { - #| let x = new(1) - #| let y = new(2) - #| swap(x, y) - #| inspect(x.val, content="2") - #| inspect(y.val, content="1") - #|} - #|pub fn[T] Ref::update(self : Ref[T], f : (T) -> T raise?) -> Unit raise? { - #| self.val = f(self.val) - #|} - #|test "decr" { - #| let a = new(1) - #| a.val -= 1 - #| inspect(a.val, content="0") - #| a.val -= 5 - #| inspect(a.val, content="-5") - #|} - #|test "incr" { - #| let a = new(1) - #| a.val += 1 - #| inspect(a.val, content="2") - #| a.val += 5 - #| inspect(a.val, content="7") - #|} - #|pub impl[X : @quickcheck.Arbitrary] @quickcheck.Arbitrary for Ref[X] with arbitrary( - #| size, - #| rs, - #|) { - #| new(X::arbitrary(size, rs)) - #|} - ), - }, + "ref.mbt": ( + #|pub(all) struct Ref[T] { + #| mut val : T + #| fn[T] new(value : T) -> Ref[T] + #|} + #|pub impl[X : Show] Show for Ref[X] with output(self, logger) { + #| logger.write_string("{val: ") + #| logger.write_object(self.val) + #| logger.write_string("}") + #|} + #|pub fn[T] Ref::new(x : T) -> Ref[T] { + #| { val: x } + #|} + #|test "to_string" { + #| inspect(new(3), content="{val: 3}") + #|} + #|pub fn[T] new(x : T) -> Ref[T] { + #| { val: x } + #|} + #|pub fn[T, R] Ref::map(self : Ref[T], f : (T) -> R raise?) -> Ref[R] raise? { + #| { val: f(self.val) } + #|} + #|pub fn[T, R] Ref::protect(self : Ref[T], a : T, f : () -> R raise?) -> R raise? { + #| let old = self.val + #| self.val = a + #| try f() catch { + #| err => { + #| self.val = old + #| raise err + #| } + #| } noraise { + #| r => { + #| self.val = old + #| r + #| } + #| } + #|} + #|#as_free_fn + #|pub fn[T] Ref::swap(self : Ref[T], that : Ref[T]) -> Unit { + #| let tmp = self.val + #| self.val = that.val + #| that.val = tmp + #|} + #|test "swap" { + #| let x = new(1) + #| let y = new(2) + #| swap(x, y) + #| inspect(x.val, content="2") + #| inspect(y.val, content="1") + #|} + #|pub fn[T] Ref::update(self : Ref[T], f : (T) -> T raise?) -> Unit raise? { + #| self.val = f(self.val) + #|} + #|test "decr" { + #| let a = new(1) + #| a.val -= 1 + #| inspect(a.val, content="0") + #| a.val -= 5 + #| inspect(a.val, content="-5") + #|} + #|test "incr" { + #| let a = new(1) + #| a.val += 1 + #| inspect(a.val, content="2") + #| a.val += 5 + #| inspect(a.val, content="7") + #|} + #|pub impl[X : @quickcheck.Arbitrary] @quickcheck.Arbitrary for Ref[X] with arbitrary( + #| size, + #| rs, + #|) { + #| new(X::arbitrary(size, rs)) + #|} + ) + } ) ///| let moonbitlang_core_result_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/result", - deps={ "moonbitlang/core/builtin": moonbitlang_core_builtin_module }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": ["moonbitlang/core/builtin"], - #| "targets": { - #| "panic_test.mbt": ["not", "native", "llvm"] - #| } - #|} - ), - "deprecated.mbt": ( - #|#deprecated("Use `Ok(value)` instead") - #|pub fn[T, E] ok(value : T) -> Result[T, E] { - #| Ok(value) - #|} - #|#deprecated("Use `Err(value)` instead") - #|pub fn[T, E] err(value : E) -> Result[T, E] { - #| Err(value) - #|} - #|#deprecated("use `x is Ok(_)` instead") - #|pub fn[T, E] Result::is_ok(self : Result[T, E]) -> Bool { - #| self is Ok(_) - #|} - #|#deprecated("use `x is Err(_)` instead") - #|pub fn[T, E] Result::is_err(self : Result[T, E]) -> Bool { - #| self is Err(_) - #|} - #|#deprecated("use `match result { Ok(value) => ok(value); Err(error) => err(error) }` instead") - #|pub fn[T, E, V] Result::fold( - #| self : Result[T, E], - #| ok : (T) -> V, - #| err : (E) -> V, - #|) -> V { - #| match self { - #| Ok(value) => ok(value) - #| Err(error) => err(error) - #| } - #|} - ), - }, + "deprecated.mbt": ( + #|#deprecated("Use `Ok(value)` instead") + #|pub fn[T, E] ok(value : T) -> Result[T, E] { + #| Ok(value) + #|} + #|#deprecated("Use `Err(value)` instead") + #|pub fn[T, E] err(value : E) -> Result[T, E] { + #| Err(value) + #|} + #|#deprecated("use `x is Ok(_)` instead") + #|pub fn[T, E] Result::is_ok(self : Result[T, E]) -> Bool { + #| self is Ok(_) + #|} + #|#deprecated("use `x is Err(_)` instead") + #|pub fn[T, E] Result::is_err(self : Result[T, E]) -> Bool { + #| self is Err(_) + #|} + #|#deprecated("use `match result { Ok(value) => ok(value); Err(error) => err(error) }` instead") + #|pub fn[T, E, V] Result::fold( + #| self : Result[T, E], + #| ok : (T) -> V, + #| err : (E) -> V, + #|) -> V { + #| match self { + #| Ok(value) => ok(value) + #| Err(error) => err(error) + #| } + #|} + ) + } ) ///| let moonbitlang_core_set_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/set", - deps={ - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/int": moonbitlang_core_int_module, - }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| "moonbitlang/core/builtin", - #| "moonbitlang/core/int" - #| ], - #| "test-import": [ - #| "moonbitlang/core/json", - #| "moonbitlang/core/array" - #| ] - #|} - ), - "deprecated.mbt": "", - "grow_heuristic.mbt": ( - #|fn calc_grow_threshold(capacity : Int) -> Int { - #| capacity * 13 / 16 - #|} - ), - "linked_hash_set.mbt": ( - #|priv struct Entry[K] { - #| mut prev : Int - #| mut next : Entry[K]? - #| mut psl : Int - #| hash : Int - #| key : K - #|} derive(Show) - #|struct Set[K] { - #| mut entries : FixedArray[Entry[K]?] - #| mut size : Int // active keys count - #| mut capacity : Int // current capacity - #| mut capacity_mask : Int // capacity_mask = capacity - 1, used to find idx - #| mut grow_at : Int // threshold that triggers grow - #| mut head : Entry[K]? // head of linked list - #| mut tail : Int // tail of linked list - #|} - #|#as_free_fn - #|pub fn[K] Set::new(capacity? : Int = 8) -> Set[K] { - #| let capacity = capacity.next_power_of_two() - #| { - #| size: 0, - #| capacity, - #| capacity_mask: capacity - 1, - #| grow_at: calc_grow_threshold(capacity), - #| entries: FixedArray::make(capacity, None), - #| head: None, - #| tail: -1, - #| } - #|} - #|#as_free_fn - #|#alias(of, deprecated="Use from_array instead") - #|#as_free_fn(of, deprecated="Use from_array instead") - #|pub fn[K : Hash + Eq] Set::from_array(arr : ArrayView[K]) -> Set[K] { - #| let length = arr.length() - #| let mut capacity = length.next_power_of_two() - #| if length > calc_grow_threshold(capacity) { - #| capacity *= 2 - #| } - #| let m = Set::new(capacity~) - #| for e in arr { - #| m.add(e) - #| } - #| m - #|} - #|#alias(insert, deprecated) - #|pub fn[K : Hash + Eq] Set::add(self : Set[K], key : K) -> Unit { - #| self.add_with_hash(key, key.hash()) - #|} - #|fn[K : Eq] Set::add_with_hash(self : Set[K], key : K, hash : Int) -> Unit { - #| if self.size >= self.grow_at { - #| self.grow() - #| } - #| let (idx, psl) = for psl = 0, idx = hash & self.capacity_mask { - #| match self.entries[idx] { - #| None => break (idx, psl) - #| Some(curr_entry) => { - #| if curr_entry.hash == hash && curr_entry.key == key { - #| return - #| } - #| if psl > curr_entry.psl { - #| self.push_away(idx, curr_entry) - #| break (idx, psl) - #| } - #| continue psl + 1, (idx + 1) & self.capacity_mask - #| } - #| } - #| } - #| let entry = { prev: self.tail, next: None, psl, key, hash } - #| self.add_entry_to_tail(idx, entry) - #|} - #|fn[K] Set::push_away(self : Set[K], idx : Int, entry : Entry[K]) -> Unit { - #| for psl = entry.psl + 1, idx = (idx + 1) & self.capacity_mask, entry = entry { - #| match self.entries[idx] { - #| None => { - #| entry.psl = psl - #| self.set_entry(entry, idx) - #| break - #| } - #| Some(curr_entry) => - #| if psl > curr_entry.psl { - #| entry.psl = psl - #| self.set_entry(entry, idx) - #| continue curr_entry.psl + 1, - #| (idx + 1) & self.capacity_mask, - #| curr_entry - #| } else { - #| continue psl + 1, (idx + 1) & self.capacity_mask, entry - #| } - #| } - #| } - #|} - #|fn[K] Set::set_entry(self : Set[K], entry : Entry[K], new_idx : Int) -> Unit { - #| self.entries[new_idx] = Some(entry) - #| match entry.next { - #| None => self.tail = new_idx - #| Some(next) => next.prev = new_idx - #| } - #|} - #|pub fn[K : Hash + Eq] Set::add_and_check(self : Set[K], key : K) -> Bool { - #| if self.size >= self.grow_at { - #| self.grow() - #| } - #| let hash = key.hash() - #| let (idx, psl, added) = for psl = 0, idx = hash & self.capacity_mask { - #| match self.entries[idx] { - #| None => break (idx, psl, true) - #| Some(curr_entry) => { - #| if curr_entry.hash == hash && curr_entry.key == key { - #| break (idx, psl, false) - #| } - #| if psl > curr_entry.psl { - #| self.push_away(idx, curr_entry) - #| break (idx, psl, true) - #| } - #| continue psl + 1, (idx + 1) & self.capacity_mask - #| } - #| } - #| } - #| if added { - #| let entry = { prev: self.tail, next: None, psl, key, hash } - #| self.add_entry_to_tail(idx, entry) - #| } - #| added - #|} - #|pub fn[K : Hash + Eq] Set::contains(self : Set[K], key : K) -> Bool { - #| let hash = key.hash() - #| for i = 0, idx = hash & self.capacity_mask { - #| guard self.entries[idx] is Some(entry) else { break false } - #| if entry.hash == hash && entry.key == key { - #| break true - #| } - #| if i > entry.psl { - #| break false - #| } - #| continue i + 1, (idx + 1) & self.capacity_mask - #| } - #|} - #|pub fn[K : Hash + Eq] Set::remove(self : Set[K], key : K) -> Unit { - #| let hash = key.hash() - #| for i = 0, idx = hash & self.capacity_mask { - #| guard self.entries[idx] is Some(entry) else { break } - #| if entry.hash == hash && entry.key == key { - #| self.remove_entry(entry) - #| self.shift_back(idx) - #| self.size -= 1 - #| break - #| } - #| if i > entry.psl { - #| break - #| } - #| continue i + 1, (idx + 1) & self.capacity_mask - #| } - #|} - #|pub fn[K : Hash + Eq] Set::remove_and_check(self : Set[K], key : K) -> Bool { - #| let hash = key.hash() - #| for i = 0, idx = hash & self.capacity_mask { - #| guard self.entries[idx] is Some(entry) else { break false } - #| if entry.hash == hash && entry.key == key { - #| self.remove_entry(entry) - #| self.shift_back(idx) - #| self.size -= 1 - #| break true - #| } - #| if i > entry.psl { - #| break false - #| } - #| continue i + 1, (idx + 1) & self.capacity_mask - #| } - #|} - #|fn[K] Set::add_entry_to_tail( - #| self : Set[K], - #| idx : Int, - #| entry : Entry[K], - #|) -> Unit { - #| match self.tail { - #| -1 => self.head = Some(entry) - #| tail => self.entries[tail].unwrap().next = Some(entry) - #| } - #| self.tail = idx - #| self.entries[idx] = Some(entry) - #| self.size += 1 - #|} - #|fn[K] Set::remove_entry(self : Set[K], entry : Entry[K]) -> Unit { - #| match entry.prev { - #| -1 => self.head = entry.next - #| idx => self.entries[idx].unwrap().next = entry.next - #| } - #| match entry.next { - #| None => self.tail = entry.prev - #| Some(next) => next.prev = entry.prev - #| } - #|} - #|fn[K] Set::shift_back(self : Set[K], idx : Int) -> Unit { - #| let next = (idx + 1) & self.capacity_mask - #| match self.entries[next] { - #| None | Some({ psl: 0, .. }) => self.entries[idx] = None - #| Some(entry) => { - #| entry.psl -= 1 - #| self.set_entry(entry, idx) - #| self.shift_back(next) - #| } - #| } - #|} - #|fn[K : Eq] Set::grow(self : Set[K]) -> Unit { - #| let old_head = self.head - #| let new_capacity = self.capacity << 1 - #| self.entries = FixedArray::make(new_capacity, None) - #| self.capacity = new_capacity - #| self.capacity_mask = new_capacity - 1 - #| self.grow_at = calc_grow_threshold(self.capacity) - #| self.size = 0 - #| self.head = None - #| self.tail = -1 - #| loop old_head { - #| Some({ next, key, hash, .. }) => { - #| self.add_with_hash(key, hash) - #| continue next - #| } - #| None => break - #| } - #|} - #|pub impl[K : Show] Show for Set[K] with output(self, logger) { - #| logger.write_string("{") - #| loop (0, self.head) { - #| (_, None) => logger.write_string("}") - #| (i, Some({ key, next, .. })) => { - #| if i > 0 { - #| logger.write_string(", ") - #| } - #| logger.write_object(key) - #| continue (i + 1, next) - #| } - #| } - #|} - #|#alias(size, deprecated) - #|pub fn[K] Set::length(self : Set[K]) -> Int { - #| self.size - #|} - #|pub fn[K] Set::capacity(self : Set[K]) -> Int { - #| self.capacity - #|} - #|pub fn[K] Set::is_empty(self : Set[K]) -> Bool { - #| self.size == 0 - #|} - #|#locals(f) - #|pub fn[K] Set::each(self : Set[K], f : (K) -> Unit raise?) -> Unit raise? { - #| loop self.head { - #| Some({ key, next, .. }) => { - #| f(key) - #| continue next - #| } - #| None => break - #| } - #|} - #|#locals(f) - #|pub fn[K] Set::eachi(self : Set[K], f : (Int, K) -> Unit raise?) -> Unit raise? { - #| loop (0, self.head) { - #| (i, Some({ key, next, .. })) => { - #| f(i, key) - #| continue (i + 1, next) - #| } - #| (_, None) => break - #| } - #|} - #|pub fn[K] Set::clear(self : Set[K]) -> Unit { - #| self.entries.fill(None) - #| self.size = 0 - #| self.head = None - #| self.tail = -1 - #|} - #|pub fn[K] Set::iter(self : Set[K]) -> Iter[K] { - #| self.iterator().iter() - #|} - #|pub fn[K] Set::iterator(self : Set[K]) -> Iterator[K] { - #| let mut curr_entry = self.head - #| Iterator::new(fn() { - #| match curr_entry { - #| Some({ key, next, .. }) => { - #| curr_entry = next - #| Some(key) - #| } - #| None => None - #| } - #| }) - #|} - #|pub fn[K] Set::to_array(self : Set[K]) -> Array[K] { - #| let arr = Array::new(capacity=self.size) - #| loop self.head { - #| Some({ key, next, .. }) => { - #| arr.push(key) - #| continue next - #| } - #| None => break - #| } - #| arr - #|} - #|pub impl[K : Hash + Eq] Eq for Set[K] with equal(self, other) { - #| guard self.size == other.size else { return false } - #| for k in self { - #| guard other.contains(k) else { return false } - #| } else { - #| true - #| } - #|} - #|#as_free_fn - #|pub fn[K : Hash + Eq] Set::from_iter(iter : Iter[K]) -> Set[K] { - #| let m = Set::new() - #| for e in iter { - #| m.add(e) - #| } - #| m - #|} - #|#as_free_fn - #|pub fn[K : Hash + Eq] Set::from_iterator(iter : Iterator[K]) -> Set[K] { - #| let m = Set::new() - #| while iter.next() is Some(e) { - #| m.add(e) - #| } - #| m - #|} - #|pub impl[K] Default for Set[K] with default() { - #| Set::new() - #|} - #|pub fn[K] Set::copy(self : Set[K]) -> Set[K] { - #| let other = { - #| capacity: self.capacity, - #| entries: FixedArray::make(self.capacity, None), - #| size: self.size, - #| capacity_mask: self.capacity_mask, - #| grow_at: self.grow_at, - #| head: None, - #| tail: self.tail, - #| } - #| if self.size == 0 { - #| return other - #| } - #| guard self.entries[self.tail] is Some(last) - #| loop (last, self.tail, None) { - #| ({ prev, psl, hash, key, .. }, idx, next) => { - #| let new_entry = { prev, next, psl, hash, key } - #| other.entries[idx] = Some(new_entry) - #| if prev != -1 { - #| continue (self.entries[prev].unwrap(), prev, Some(new_entry)) - #| } else { - #| other.head = Some(new_entry) - #| } - #| } - #| } - #| other - #|} - #|pub fn[K : Hash + Eq] Set::difference(self : Set[K], other : Set[K]) -> Set[K] { - #| let m = Set::new() - #| self.each(k => if !other.contains(k) { m.add(k) }) - #| m - #|} - #|pub fn[K : Hash + Eq] Set::symmetric_difference( - #| self : Set[K], - #| other : Set[K], - #|) -> Set[K] { - #| let m = Set::new() - #| self.each(k => if !other.contains(k) { m.add(k) }) - #| other.each(k => if !self.contains(k) { m.add(k) }) - #| m - #|} - #|pub fn[K : Hash + Eq] Set::union(self : Set[K], other : Set[K]) -> Set[K] { - #| let m = Set::new() - #| self.each(k => m.add(k)) - #| other.each(k => m.add(k)) - #| m - #|} - #|pub fn[K : Hash + Eq] Set::intersection( - #| self : Set[K], - #| other : Set[K], - #|) -> Set[K] { - #| let m = Set::new() - #| self.each(k => if other.contains(k) { m.add(k) }) - #| m - #|} - #|pub impl[X : ToJson] ToJson for Set[X] with to_json(self) { - #| let res = Array::new(capacity=self.size) - #| for v in self { - #| res.push(v.to_json()) - #| } - #| Json::array(res) - #|} - #|pub fn[K : Hash + Eq] Set::is_disjoint(self : Set[K], other : Set[K]) -> Bool { - #| if self.length() <= other.length() { - #| for k in self { - #| if other.contains(k) { - #| return false - #| } - #| } - #| } else { - #| for k in other { - #| if self.contains(k) { - #| return false - #| } - #| } - #| } - #| true - #|} - #|pub fn[K : Hash + Eq] Set::is_subset(self : Set[K], other : Set[K]) -> Bool { - #| if self.length() <= other.length() { - #| for k in self { - #| if !other.contains(k) { - #| return false - #| } - #| } - #| true - #| } else { - #| false - #| } - #|} - #|pub fn[K : Hash + Eq] Set::is_superset(self : Set[K], other : Set[K]) -> Bool { - #| other.is_subset(self) - #|} - #|pub impl[K : Hash + Eq] BitAnd for Set[K] with land(self, other) { - #| self.intersection(other) - #|} - #|pub impl[K : Hash + Eq] BitOr for Set[K] with lor(self, other) { - #| self.union(other) - #|} - #|pub impl[K : Hash + Eq] BitXOr for Set[K] with lxor(self, other) { - #| self.symmetric_difference(other) - #|} - #|pub impl[K : Hash + Eq] Sub for Set[K] with sub(self, other) { - #| self.difference(other) - #|} - ), - }, + "deprecated.mbt": "", + "grow_heuristic.mbt": ( + #|fn calc_grow_threshold(capacity : Int) -> Int { + #| capacity * 13 / 16 + #|} + ), + "linked_hash_set.mbt": ( + #|priv struct Entry[K] { + #| mut prev : Int + #| mut next : Entry[K]? + #| mut psl : Int + #| hash : Int + #| key : K + #|} derive(Show) + #|struct Set[K] { + #| mut entries : FixedArray[Entry[K]?] + #| mut size : Int // active keys count + #| mut capacity : Int // current capacity + #| mut capacity_mask : Int // capacity_mask = capacity - 1, used to find idx + #| mut grow_at : Int // threshold that triggers grow + #| mut head : Entry[K]? // head of linked list + #| mut tail : Int // tail of linked list + #|} + #|#as_free_fn + #|pub fn[K] Set::new(capacity? : Int = 8) -> Set[K] { + #| let capacity = capacity.next_power_of_two() + #| { + #| size: 0, + #| capacity, + #| capacity_mask: capacity - 1, + #| grow_at: calc_grow_threshold(capacity), + #| entries: FixedArray::make(capacity, None), + #| head: None, + #| tail: -1, + #| } + #|} + #|#as_free_fn + #|#alias(of, deprecated="Use from_array instead") + #|#as_free_fn(of, deprecated="Use from_array instead") + #|pub fn[K : Hash + Eq] Set::from_array(arr : ArrayView[K]) -> Set[K] { + #| let length = arr.length() + #| let mut capacity = length.next_power_of_two() + #| if length > calc_grow_threshold(capacity) { + #| capacity *= 2 + #| } + #| let m = Set::new(capacity~) + #| for e in arr { + #| m.add(e) + #| } + #| m + #|} + #|#alias(insert, deprecated) + #|pub fn[K : Hash + Eq] Set::add(self : Set[K], key : K) -> Unit { + #| self.add_with_hash(key, key.hash()) + #|} + #|fn[K : Eq] Set::add_with_hash(self : Set[K], key : K, hash : Int) -> Unit { + #| if self.size >= self.grow_at { + #| self.grow() + #| } + #| let (idx, psl) = for psl = 0, idx = hash & self.capacity_mask { + #| match self.entries[idx] { + #| None => break (idx, psl) + #| Some(curr_entry) => { + #| if curr_entry.hash == hash && curr_entry.key == key { + #| return + #| } + #| if psl > curr_entry.psl { + #| self.push_away(idx, curr_entry) + #| break (idx, psl) + #| } + #| continue psl + 1, (idx + 1) & self.capacity_mask + #| } + #| } + #| } + #| let entry = { prev: self.tail, next: None, psl, key, hash } + #| self.add_entry_to_tail(idx, entry) + #|} + #|fn[K] Set::push_away(self : Set[K], idx : Int, entry : Entry[K]) -> Unit { + #| for psl = entry.psl + 1, idx = (idx + 1) & self.capacity_mask, entry = entry { + #| match self.entries[idx] { + #| None => { + #| entry.psl = psl + #| self.set_entry(entry, idx) + #| break + #| } + #| Some(curr_entry) => + #| if psl > curr_entry.psl { + #| entry.psl = psl + #| self.set_entry(entry, idx) + #| continue curr_entry.psl + 1, + #| (idx + 1) & self.capacity_mask, + #| curr_entry + #| } else { + #| continue psl + 1, (idx + 1) & self.capacity_mask, entry + #| } + #| } + #| } + #|} + #|fn[K] Set::set_entry(self : Set[K], entry : Entry[K], new_idx : Int) -> Unit { + #| self.entries[new_idx] = Some(entry) + #| match entry.next { + #| None => self.tail = new_idx + #| Some(next) => next.prev = new_idx + #| } + #|} + #|pub fn[K : Hash + Eq] Set::add_and_check(self : Set[K], key : K) -> Bool { + #| if self.size >= self.grow_at { + #| self.grow() + #| } + #| let hash = key.hash() + #| let (idx, psl, added) = for psl = 0, idx = hash & self.capacity_mask { + #| match self.entries[idx] { + #| None => break (idx, psl, true) + #| Some(curr_entry) => { + #| if curr_entry.hash == hash && curr_entry.key == key { + #| break (idx, psl, false) + #| } + #| if psl > curr_entry.psl { + #| self.push_away(idx, curr_entry) + #| break (idx, psl, true) + #| } + #| continue psl + 1, (idx + 1) & self.capacity_mask + #| } + #| } + #| } + #| if added { + #| let entry = { prev: self.tail, next: None, psl, key, hash } + #| self.add_entry_to_tail(idx, entry) + #| } + #| added + #|} + #|pub fn[K : Hash + Eq] Set::contains(self : Set[K], key : K) -> Bool { + #| let hash = key.hash() + #| for i = 0, idx = hash & self.capacity_mask { + #| guard self.entries[idx] is Some(entry) else { break false } + #| if entry.hash == hash && entry.key == key { + #| break true + #| } + #| if i > entry.psl { + #| break false + #| } + #| continue i + 1, (idx + 1) & self.capacity_mask + #| } + #|} + #|pub fn[K : Hash + Eq] Set::remove(self : Set[K], key : K) -> Unit { + #| let hash = key.hash() + #| for i = 0, idx = hash & self.capacity_mask { + #| guard self.entries[idx] is Some(entry) else { break } + #| if entry.hash == hash && entry.key == key { + #| self.remove_entry(entry) + #| self.shift_back(idx) + #| self.size -= 1 + #| break + #| } + #| if i > entry.psl { + #| break + #| } + #| continue i + 1, (idx + 1) & self.capacity_mask + #| } + #|} + #|pub fn[K : Hash + Eq] Set::remove_and_check(self : Set[K], key : K) -> Bool { + #| let hash = key.hash() + #| for i = 0, idx = hash & self.capacity_mask { + #| guard self.entries[idx] is Some(entry) else { break false } + #| if entry.hash == hash && entry.key == key { + #| self.remove_entry(entry) + #| self.shift_back(idx) + #| self.size -= 1 + #| break true + #| } + #| if i > entry.psl { + #| break false + #| } + #| continue i + 1, (idx + 1) & self.capacity_mask + #| } + #|} + #|fn[K] Set::add_entry_to_tail( + #| self : Set[K], + #| idx : Int, + #| entry : Entry[K], + #|) -> Unit { + #| match self.tail { + #| -1 => self.head = Some(entry) + #| tail => self.entries[tail].unwrap().next = Some(entry) + #| } + #| self.tail = idx + #| self.entries[idx] = Some(entry) + #| self.size += 1 + #|} + #|fn[K] Set::remove_entry(self : Set[K], entry : Entry[K]) -> Unit { + #| match entry.prev { + #| -1 => self.head = entry.next + #| idx => self.entries[idx].unwrap().next = entry.next + #| } + #| match entry.next { + #| None => self.tail = entry.prev + #| Some(next) => next.prev = entry.prev + #| } + #|} + #|fn[K] Set::shift_back(self : Set[K], idx : Int) -> Unit { + #| let next = (idx + 1) & self.capacity_mask + #| match self.entries[next] { + #| None | Some({ psl: 0, .. }) => self.entries[idx] = None + #| Some(entry) => { + #| entry.psl -= 1 + #| self.set_entry(entry, idx) + #| self.shift_back(next) + #| } + #| } + #|} + #|fn[K : Eq] Set::grow(self : Set[K]) -> Unit { + #| let old_head = self.head + #| let new_capacity = self.capacity << 1 + #| self.entries = FixedArray::make(new_capacity, None) + #| self.capacity = new_capacity + #| self.capacity_mask = new_capacity - 1 + #| self.grow_at = calc_grow_threshold(self.capacity) + #| self.size = 0 + #| self.head = None + #| self.tail = -1 + #| loop old_head { + #| Some({ next, key, hash, .. }) => { + #| self.add_with_hash(key, hash) + #| continue next + #| } + #| None => break + #| } + #|} + #|pub impl[K : Show] Show for Set[K] with output(self, logger) { + #| logger.write_string("{") + #| loop (0, self.head) { + #| (_, None) => logger.write_string("}") + #| (i, Some({ key, next, .. })) => { + #| if i > 0 { + #| logger.write_string(", ") + #| } + #| logger.write_object(key) + #| continue (i + 1, next) + #| } + #| } + #|} + #|#alias(size, deprecated) + #|pub fn[K] Set::length(self : Set[K]) -> Int { + #| self.size + #|} + #|pub fn[K] Set::capacity(self : Set[K]) -> Int { + #| self.capacity + #|} + #|pub fn[K] Set::is_empty(self : Set[K]) -> Bool { + #| self.size == 0 + #|} + #|#locals(f) + #|pub fn[K] Set::each(self : Set[K], f : (K) -> Unit raise?) -> Unit raise? { + #| loop self.head { + #| Some({ key, next, .. }) => { + #| f(key) + #| continue next + #| } + #| None => break + #| } + #|} + #|#locals(f) + #|pub fn[K] Set::eachi(self : Set[K], f : (Int, K) -> Unit raise?) -> Unit raise? { + #| loop (0, self.head) { + #| (i, Some({ key, next, .. })) => { + #| f(i, key) + #| continue (i + 1, next) + #| } + #| (_, None) => break + #| } + #|} + #|pub fn[K] Set::clear(self : Set[K]) -> Unit { + #| self.entries.fill(None) + #| self.size = 0 + #| self.head = None + #| self.tail = -1 + #|} + #|#alias(iterator, deprecated) + #|pub fn[K] Set::iter(self : Set[K]) -> Iter[K] { + #| let mut curr_entry = self.head + #| Iter::new(fn() { + #| match curr_entry { + #| Some({ key, next, .. }) => { + #| curr_entry = next + #| Some(key) + #| } + #| None => None + #| } + #| }) + #|} + #|pub fn[K] Set::to_array(self : Set[K]) -> Array[K] { + #| let arr = Array::new(capacity=self.size) + #| loop self.head { + #| Some({ key, next, .. }) => { + #| arr.push(key) + #| continue next + #| } + #| None => break + #| } + #| arr + #|} + #|pub impl[K : Hash + Eq] Eq for Set[K] with equal(self, other) { + #| guard self.size == other.size else { return false } + #| for k in self { + #| guard other.contains(k) else { return false } + #| } nobreak { + #| true + #| } + #|} + #|#as_free_fn + #|#alias(from_iterator, deprecated) + #|#as_free_fn(from_iterator, deprecated) + #|pub fn[K : Hash + Eq] Set::from_iter(iter : Iter[K]) -> Set[K] { + #| let m = Set::new() + #| while iter.next() is Some(e) { + #| m.add(e) + #| } + #| m + #|} + #|pub impl[K] Default for Set[K] with default() { + #| Set::new() + #|} + #|#alias(clone, deprecated) + #|pub fn[K] Set::copy(self : Set[K]) -> Set[K] { + #| let other = { + #| capacity: self.capacity, + #| entries: FixedArray::make(self.capacity, None), + #| size: self.size, + #| capacity_mask: self.capacity_mask, + #| grow_at: self.grow_at, + #| head: None, + #| tail: self.tail, + #| } + #| if self.size == 0 { + #| return other + #| } + #| guard self.entries[self.tail] is Some(last) + #| loop (last, self.tail, None) { + #| ({ prev, psl, hash, key, .. }, idx, next) => { + #| let new_entry = { prev, next, psl, hash, key } + #| other.entries[idx] = Some(new_entry) + #| if prev != -1 { + #| continue (self.entries[prev].unwrap(), prev, Some(new_entry)) + #| } else { + #| other.head = Some(new_entry) + #| } + #| } + #| } + #| other + #|} + #|pub fn[K : Hash + Eq] Set::difference(self : Set[K], other : Set[K]) -> Set[K] { + #| let m = Set::new() + #| self.each(k => if !other.contains(k) { m.add(k) }) + #| m + #|} + #|pub fn[K : Hash + Eq] Set::symmetric_difference( + #| self : Set[K], + #| other : Set[K], + #|) -> Set[K] { + #| let m = Set::new() + #| self.each(k => if !other.contains(k) { m.add(k) }) + #| other.each(k => if !self.contains(k) { m.add(k) }) + #| m + #|} + #|pub fn[K : Hash + Eq] Set::union(self : Set[K], other : Set[K]) -> Set[K] { + #| let m = Set::new() + #| self.each(k => m.add(k)) + #| other.each(k => m.add(k)) + #| m + #|} + #|pub fn[K : Hash + Eq] Set::intersection( + #| self : Set[K], + #| other : Set[K], + #|) -> Set[K] { + #| let m = Set::new() + #| self.each(k => if other.contains(k) { m.add(k) }) + #| m + #|} + #|pub impl[X : ToJson] ToJson for Set[X] with to_json(self) { + #| let res = Array::new(capacity=self.size) + #| for v in self { + #| res.push(v.to_json()) + #| } + #| Json::array(res) + #|} + #|pub fn[K : Hash + Eq] Set::is_disjoint(self : Set[K], other : Set[K]) -> Bool { + #| if self.length() <= other.length() { + #| for k in self { + #| if other.contains(k) { + #| return false + #| } + #| } + #| } else { + #| for k in other { + #| if self.contains(k) { + #| return false + #| } + #| } + #| } + #| true + #|} + #|pub fn[K : Hash + Eq] Set::is_subset(self : Set[K], other : Set[K]) -> Bool { + #| if self.length() <= other.length() { + #| for k in self { + #| if !other.contains(k) { + #| return false + #| } + #| } + #| true + #| } else { + #| false + #| } + #|} + #|pub fn[K : Hash + Eq] Set::is_superset(self : Set[K], other : Set[K]) -> Bool { + #| other.is_subset(self) + #|} + #|pub impl[K : Hash + Eq] BitAnd for Set[K] with land(self, other) { + #| self.intersection(other) + #|} + #|pub impl[K : Hash + Eq] BitOr for Set[K] with lor(self, other) { + #| self.union(other) + #|} + #|pub impl[K : Hash + Eq] BitXOr for Set[K] with lxor(self, other) { + #| self.symmetric_difference(other) + #|} + #|pub impl[K : Hash + Eq] Sub for Set[K] with sub(self, other) { + #| self.difference(other) + #|} + ) + } ) ///| let moonbitlang_core_sorted_map_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/sorted_map", - deps={ - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/option": moonbitlang_core_option_module, - "moonbitlang/core/tuple": moonbitlang_core_tuple_module, - "moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module, - "moonbitlang/core/json": moonbitlang_core_json_module, - "moonbitlang/core/string": moonbitlang_core_string_module, - }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| "moonbitlang/core/builtin", - #| "moonbitlang/core/option", - #| "moonbitlang/core/tuple", - #| "moonbitlang/core/quickcheck", - #| "moonbitlang/core/json", - #| "moonbitlang/core/string" - #| ], - #| "test-import": ["moonbitlang/core/array"] - #|} - ), - "deprecated.mbt": ( - #|#deprecated("Use `keys_as_iter` instead. `keys` will return `Iter[K]` instead of `Array[K]` in the future.") - #|#coverage.skip - #|pub fn[K, V] SortedMap::keys(self : SortedMap[K, V]) -> Array[K] { - #| let keys = Array::new(capacity=self.size) - #| self.each(fn(k, _v) { keys.push(k) }) - #| keys - #|} - #|#deprecated("Use `values_as_iter` instead. `values` will return `Iter[V]` instead of `Array[V]` in the future.") - #|#coverage.skip - #|pub fn[K, V] SortedMap::values(self : SortedMap[K, V]) -> Array[V] { - #| let values = Array::new(capacity=self.size) - #| self.each(fn(_k, v) { values.push(v) }) - #| values - #|} - ), - "map.mbt": ( - #|pub impl[K : Eq, V : Eq] Eq for SortedMap[K, V] with equal(self, other) { - #| guard self.size == other.size else { return false } - #| let iter = self.iterator() - #| let iter1 = other.iterator() - #| while iter.next() is Some(a) && iter1.next() is Some(b) { - #| guard a == b else { break false } - #| } else { - #| true - #| } - #|} - #|#as_free_fn - #|pub fn[K, V] SortedMap::new() -> SortedMap[K, V] { - #| { root: None, size: 0 } - #|} - #|#as_free_fn - #|#alias(of, deprecated="Use from_array instead") - #|#as_free_fn(of, deprecated="Use from_array instead") - #|pub fn[K : Compare, V] SortedMap::from_array( - #| entries : ArrayView[(K, V)], - #|) -> SortedMap[K, V] { - #| let map = { root: None, size: 0 } - #| for e in entries { - #| map.set(e.0, e.1) - #| } - #| map - #|} - #|#alias("_[_]=_") - #|#alias(add, deprecated="Use set instead") - #|pub fn[K : Compare, V] SortedMap::set( - #| self : SortedMap[K, V], - #| key : K, - #| value : V, - #|) -> Unit { - #| let (new_root, inserted) = add_node(self.root, key, value) - #| if self.root != new_root { - #| self.root = new_root - #| } - #| if inserted { - #| self.size += 1 - #| } - #|} - #|pub fn[K : Compare, V] SortedMap::remove( - #| self : SortedMap[K, V], - #| key : K, - #|) -> Unit { - #| if self.root is Some(old_root) { - #| let (new_root, deleted) = delete_node(old_root, key) - #| if self.root != new_root { - #| self.root = new_root - #| } - #| if deleted { - #| self.size -= 1 - #| } - #| } - #|} - #|pub fn[K : Compare, V] SortedMap::get(self : SortedMap[K, V], key : K) -> V? { - #| loop self.root { - #| Some(node) => { - #| let cmp = key.compare(node.key) - #| if cmp == 0 { - #| break Some(node.value) - #| } else if cmp > 0 { - #| continue node.right - #| } else { - #| continue node.left - #| } - #| } - #| None => break None - #| } - #|} - #|#alias("_[_]") - #|pub fn[K : Compare, V] SortedMap::at(self : SortedMap[K, V], key : K) -> V { - #| loop self.root { - #| Some(node) => { - #| let cmp = key.compare(node.key) - #| if cmp == 0 { - #| break node.value - #| } else if cmp > 0 { - #| continue node.right - #| } else { - #| continue node.left - #| } - #| } - #| None => panic() - #| } - #|} - #|pub fn[K : Compare, V] SortedMap::contains( - #| self : SortedMap[K, V], - #| key : K, - #|) -> Bool { - #| match self.get(key) { - #| Some(_) => true - #| None => false - #| } - #|} - #|pub fn[K, V] SortedMap::is_empty(self : SortedMap[K, V]) -> Bool { - #| self.size == 0 - #|} - #|#alias(size, deprecated) - #|pub fn[K, V] SortedMap::length(self : SortedMap[K, V]) -> Int { - #| self.size - #|} - #|pub fn[K, V] SortedMap::clear(self : SortedMap[K, V]) -> Unit { - #| self.root = None - #| self.size = 0 - #|} - #|pub fn[K, V] SortedMap::each( - #| self : SortedMap[K, V], - #| f : (K, V) -> Unit raise?, - #|) -> Unit raise? { - #| fn dfs(root : Node[K, V]?) -> Unit raise? { - #| if root is Some(root) { - #| dfs(root.left) - #| f(root.key, root.value) - #| dfs(root.right) - #| } - #| } - #| dfs(self.root) - #|} - #|pub fn[K, V] SortedMap::eachi( - #| self : SortedMap[K, V], - #| f : (Int, K, V) -> Unit raise?, - #|) -> Unit raise? { - #| let mut i = 0 - #| self.each((k, v) => { - #| f(i, k, v) - #| i = i + 1 - #| }) - #|} - #|pub fn[K, V] SortedMap::keys_as_iter(self : SortedMap[K, V]) -> Iter[K] { - #| let todo_list = [] - #| let mut next_node = self.root - #| Iterator::new(fn() { - #| loop next_node { - #| Some({ left, key, value: _, right, height: _ }) => { - #| todo_list.push((key, right)) - #| continue left - #| } - #| None if todo_list.pop() is Some((key, right)) => { - #| next_node = right - #| Some(key) - #| } - #| None => None - #| } - #| }).iter() - #|} - #|pub fn[K, V] SortedMap::values_as_iter(self : SortedMap[K, V]) -> Iter[V] { - #| let todo_list = [] - #| let mut next_node = self.root - #| Iterator::new(fn() { - #| loop next_node { - #| Some({ left, key: _, value, right, height: _ }) => { - #| todo_list.push((value, right)) - #| continue left - #| } - #| None if todo_list.pop() is Some((value, right)) => { - #| next_node = right - #| Some(value) - #| } - #| None => None - #| } - #| }).iter() - #|} - #|pub fn[K, V] SortedMap::to_array(self : SortedMap[K, V]) -> Array[(K, V)] { - #| let arr = Array::new(capacity=self.size) - #| self.each((k, v) => arr.push((k, v))) - #| arr - #|} - #|pub fn[K, V] SortedMap::iter(self : SortedMap[K, V]) -> Iter[(K, V)] { - #| self.iterator().iter() - #|} - #|pub fn[K, V] SortedMap::iter2(self : SortedMap[K, V]) -> Iter2[K, V] { - #| self.Iter2().iter2() - #|} - #|pub fn[K, V] SortedMap::iterator(self : SortedMap[K, V]) -> Iterator[(K, V)] { - #| let todo_list = [] - #| let mut next_node = self.root - #| Iterator::new(fn() { - #| loop next_node { - #| Some({ left, key, value, right, height: _ }) => { - #| todo_list.push((key, value, right)) - #| continue left - #| } - #| None if todo_list.pop() is Some((key, value, right)) => { - #| next_node = right - #| Some((key, value)) - #| } - #| None => None - #| } - #| }) - #|} - #|pub fn[K, V] SortedMap::Iter2(self : SortedMap[K, V]) -> Iter2[K, V] { - #| self.iterator() - #|} - #|#as_free_fn - #|pub fn[K : Compare, V] SortedMap::from_iter( - #| iter : Iter[(K, V)], - #|) -> SortedMap[K, V] { - #| let m = new() - #| iter.each(e => m[e.0] = e.1) - #| m - #|} - #|#as_free_fn - #|pub fn[K : Compare, V] SortedMap::from_iterator( - #| iter : Iterator[(K, V)], - #|) -> SortedMap[K, V] { - #| let m = new() - #| while iter.next() is Some((k, v)) { - #| m[k] = v - #| } - #| m - #|} - #|pub impl[K : @quickcheck.Arbitrary + Compare, V : @quickcheck.Arbitrary] @quickcheck.Arbitrary for SortedMap[ - #| K, - #| V, - #|] with arbitrary(size, rs) { - #| @quickcheck.Arbitrary::arbitrary(size, rs) |> from_iter - #|} - #|pub fn[K : Compare, V] SortedMap::range( - #| self : SortedMap[K, V], - #| low : K, - #| high : K, - #|) -> Iter2[K, V] { - #| let todo_list = [] - #| let mut next_node = self.root - #| Iter2::new(fn() { - #| loop next_node { - #| Some({ left, key, value, right, height: _ }) => { - #| let cmp_key_low = key.compare(low) - #| let cmp_key_high = key.compare(high) - #| if cmp_key_low < 0 { - #| continue right - #| } else if cmp_key_high > 0 { - #| continue left - #| } else if left is None { - #| next_node = right - #| Some((key, value)) - #| } else { - #| todo_list.push((key, value, right)) - #| continue left - #| } - #| } - #| None if todo_list.pop() is Some((key, value, right)) => { - #| next_node = right - #| Some((key, value)) - #| } - #| None => None - #| } - #| }).iter2() - #|} - #|pub fn[K, V] SortedMap::copy(self : SortedMap[K, V]) -> SortedMap[K, V] { - #| fn copy_node(node : Node[K, V]?) -> Node[K, V]? { - #| match node { - #| None => None - #| Some({ key, value, left, right, height }) => - #| Some({ - #| key, - #| value, - #| left: copy_node(left), - #| right: copy_node(right), - #| height, - #| }) - #| } - #| } - #| { root: copy_node(self.root), size: self.size } - #|} - #|pub fn[K : Compare, V] SortedMap::merge( - #| self : SortedMap[K, V], - #| other : SortedMap[K, V], - #|) -> SortedMap[K, V] { - #| let result = self.copy() - #| other.each((k, v) => result.set(k, v)) - #| result - #|} - #|pub fn[K : Compare, V] SortedMap::merge_in_place( - #| self : SortedMap[K, V], - #| other : SortedMap[K, V], - #|) -> Unit { - #| other.each((k, v) => self.set(k, v)) - #|} - #|fn[K, V] replace_root_with_min( - #| root : Node[K, V], - #| node : Node[K, V], - #|) -> Node[K, V]? { - #| let (l, r) = (node.left, node.right) - #| match l { - #| None => { - #| root.key = node.key - #| root.value = node.value - #| r - #| } - #| Some(ln) => { - #| node.left = replace_root_with_min(root, ln) - #| Some(balance(node)) - #| } - #| } - #|} - #|fn[K, V] Node::update_height(self : Node[K, V]) -> Unit { - #| self.height = 1 + max(height(self.left), height(self.right)) - #|} - #|fn[K, V] height_ge(x1 : Node[K, V]?, x2 : Node[K, V]?) -> Bool { - #| match x2 { - #| None => true - #| Some(n2) => - #| match x1 { - #| None => false - #| Some(n1) => n1.height >= n2.height - #| } - #| } - #|} - #|fn[K, V] balance(root : Node[K, V]) -> Node[K, V] { - #| let (l, r) = (root.left, root.right) - #| let (hl, hr) = (height(l), height(r)) - #| let new_root = if hl > hr + 1 { - #| let { left: ll, right: lr, .. } = l.unwrap() - #| if height_ge(ll, lr) { - #| rotate_r(root) - #| } else { - #| rotate_lr(root) - #| } - #| } else if hr > hl + 1 { - #| let { left: rl, right: rr, .. } = r.unwrap() - #| if height_ge(rr, rl) { - #| rotate_l(root) - #| } else { - #| rotate_rl(root) - #| } - #| } else { - #| root - #| } - #| new_root.update_height() - #| new_root - #|} - #|fn[K, V] rotate_l(n : Node[K, V]) -> Node[K, V] { - #| let r = n.right.unwrap() - #| n.right = r.left - #| r.left = Some(n) - #| n.update_height() - #| r.update_height() - #| r - #|} - #|fn[K, V] rotate_r(n : Node[K, V]) -> Node[K, V] { - #| let l = n.left.unwrap() - #| n.left = l.right - #| l.right = Some(n) - #| n.update_height() - #| l.update_height() - #| l - #|} - #|fn[K, V] rotate_lr(n : Node[K, V]) -> Node[K, V] { - #| let l = n.left.unwrap() - #| let v = rotate_l(l) - #| n.left = Some(v) - #| rotate_r(n) - #|} - #|fn[K, V] rotate_rl(n : Node[K, V]) -> Node[K, V] { - #| let r = n.right.unwrap() - #| let v = rotate_r(r) - #| n.right = Some(v) - #| rotate_l(n) - #|} - #|fn[K : Compare, V] add_node( - #| root : Node[K, V]?, - #| key : K, - #| value : V, - #|) -> (Node[K, V]?, Bool) { - #| match root { - #| None => (Some(new_node(key, value)), true) - #| Some(n) => - #| if key == n.key { - #| n.value = value - #| (Some(n), false) - #| } else { - #| let (l, r) = (n.left, n.right) - #| if key < n.key { - #| let (nl, inserted) = add_node(l, key, value) - #| n.left = nl - #| (Some(balance(n)), inserted) - #| } else { - #| let (nr, inserted) = add_node(r, key, value) - #| n.right = nr - #| (Some(balance(n)), inserted) - #| } - #| } - #| } - #|} - #|fn[K : Compare, V] delete_node( - #| root : Node[K, V], - #| key : K, - #|) -> (Node[K, V]?, Bool) { - #| if key == root.key { - #| let (l, r) = (root.left, root.right) - #| let n = match (l, r) { - #| (Some(_), Some(nr)) => { - #| root.right = replace_root_with_min(root, nr) - #| Some(balance(root)) - #| } - #| (None, Some(_)) => r - #| (Some(_), None) | (None, None) => l - #| } - #| (n, true) - #| } else if key < root.key { - #| match root.left { - #| None => (Some(root), false) - #| Some(l) => { - #| let (nl, deleted) = delete_node(l, key) - #| root.left = nl - #| (Some(balance(root)), deleted) - #| } - #| } - #| } else { - #| match root.right { - #| None => (Some(root), false) - #| Some(r) => { - #| let (nr, deleted) = delete_node(r, key) - #| root.right = nr - #| (Some(balance(root)), deleted) - #| } - #| } - #| } - #|} - #|test "new" { - #| let map : SortedMap[Int, String] = new() - #| inspect(map.debug_tree(), content="_") - #| inspect(map.length(), content="0") - #|} - #|test "of" { - #| let map = from_array([(3, "c"), (2, "b"), (1, "a")]) - #| inspect(map.debug_tree(), content="([2]2,b,([1]1,a,_,_),([1]3,c,_,_))") - #| inspect(map.length(), content="3") - #|} - #|test "add1" { - #| let map = new() - #| map.set(6, "a") - #| map.set(5, "b") - #| map.set(4, "c") - #| map.set(3, "d") - #| map.set(2, "e") - #| map.set(1, "f") - #| inspect( - #| map.debug_tree(), - #| content="([3]3,d,([2]2,e,([1]1,f,_,_),_),([2]5,b,([1]4,c,_,_),([1]6,a,_,_)))", - #| ) - #| inspect(map.length(), content="6") - #|} - #|test "add2" { - #| let map = new() - #| map.set(1, "a") - #| map.set(2, "b") - #| map.set(3, "c") - #| map.set(4, "d") - #| map.set(5, "e") - #| map.set(6, "f") - #| inspect( - #| map.debug_tree(), - #| content="([3]4,d,([2]2,b,([1]1,a,_,_),([1]3,c,_,_)),([2]5,e,_,([1]6,f,_,_)))", - #| ) - #| inspect(map.length(), content="6") - #|} - #|test "add3" { - #| let map = new() - #| map.set(4, "a") - #| map.set(1, "b") - #| map.set(3, "c") - #| map.set(2, "d") - #| inspect( - #| map.debug_tree(), - #| content="([3]3,c,([2]1,b,_,([1]2,d,_,_)),([1]4,a,_,_))", - #| ) - #|} - #|test "add4" { - #| let map = new() - #| map.set(1, "a") - #| map.set(4, "b") - #| map.set(2, "c") - #| map.set(3, "d") - #| inspect( - #| map.debug_tree(), - #| content="([3]2,c,([1]1,a,_,_),([2]4,b,([1]3,d,_,_),_))", - #| ) - #|} - #|test "add duplicate key" { - #| let map = from_array([(3, "c"), (2, "b"), (1, "a")]) - #| inspect(map.debug_tree(), content="([2]2,b,([1]1,a,_,_),([1]3,c,_,_))") - #| map.set(1, "x") - #| inspect(map.debug_tree(), content="([2]2,b,([1]1,x,_,_),([1]3,c,_,_))") - #|} - #|test "remove" { - #| let map = from_array([ - #| (1, "a"), - #| (2, "b"), - #| (3, "c"), - #| (4, "d"), - #| (5, "e"), - #| (6, "f"), - #| (7, "g"), - #| (8, "h"), - #| ]) - #| inspect( - #| map.debug_tree(), - #| content="([4]4,d,([2]2,b,([1]1,a,_,_),([1]3,c,_,_)),([3]6,f,([1]5,e,_,_),([2]7,g,_,([1]8,h,_,_))))", - #| ) - #| inspect(map.length(), content="8") - #| map.remove(6) - #| inspect( - #| map.debug_tree(), - #| content="([3]4,d,([2]2,b,([1]1,a,_,_),([1]3,c,_,_)),([2]7,g,([1]5,e,_,_),([1]8,h,_,_)))", - #| ) - #| inspect(map.length(), content="7") - #| map.remove(4) - #| inspect( - #| map.debug_tree(), - #| content="([3]5,e,([2]2,b,([1]1,a,_,_),([1]3,c,_,_)),([2]7,g,_,([1]8,h,_,_)))", - #| ) - #| inspect(map.length(), content="6") - #| map.remove(2) - #| inspect( - #| map.debug_tree(), - #| content="([3]5,e,([2]3,c,([1]1,a,_,_),_),([2]7,g,_,([1]8,h,_,_)))", - #| ) - #| inspect(map.length(), content="5") - #| map.remove(3) - #| inspect( - #| map.debug_tree(), - #| content="([3]5,e,([1]1,a,_,_),([2]7,g,_,([1]8,h,_,_)))", - #| ) - #| inspect(map.length(), content="4") - #| map.remove(5) - #| inspect(map.debug_tree(), content="([2]7,g,([1]1,a,_,_),([1]8,h,_,_))") - #| inspect(map.length(), content="3") - #| map.remove(7) - #| inspect(map.debug_tree(), content="([2]8,h,([1]1,a,_,_),_)") - #| inspect(map.length(), content="2") - #| map.remove(8) - #| inspect(map.debug_tree(), content="([1]1,a,_,_)") - #| inspect(map.length(), content="1") - #| map.remove(1) - #| inspect(map.debug_tree(), content="_") - #| inspect(map.size, content="0") - #|} - #|test "_[_]=_" { - #| let map = new() - #| map[1] = "a" - #| map[2] = "b" - #| map[3] = "c" - #| inspect(map.debug_tree(), content="([2]2,b,([1]1,a,_,_),([1]3,c,_,_))") - #|} - #|test "clear" { - #| let map = from_array([(3, "c"), (2, "b"), (1, "a")]) - #| map.clear() - #| inspect(map.debug_tree(), content="_") - #| inspect(map.length(), content="0") - #|} - #|test "copy" { - #| let map1 = from_array([ - #| (1, "a"), - #| (2, "b"), - #| (3, "c"), - #| (4, "d"), - #| (5, "e"), - #| (6, "f"), - #| ]) - #| let map2 = map1.copy() - #| inspect(map1.debug_tree(), content=map2.debug_tree()) - #| inspect(map1.length(), content="6") - #| inspect(map2.length(), content="6") - #| map2.set(7, "g") - #| inspect(map1.length(), content="6") - #| inspect(map2.length(), content="7") - #| inspect(map1.get(7), content="None") - #| inspect(map2.get(7), content="Some(\"g\")") - #| map1.remove(1) - #| inspect(map1.length(), content="5") - #| inspect(map2.length(), content="7") - #| inspect(map1.get(1), content="None") - #| inspect(map2.get(1), content="Some(\"a\")") - #|} - #|pub impl[K, V] Default for SortedMap[K, V] with default() { - #| new() - #|} - ), - "types.mbt": ( - #|priv struct Node[K, V] { - #| mut key : K - #| mut value : V - #| mut left : Node[K, V]? - #| mut right : Node[K, V]? - #| mut height : Int - #|} - #|#alias(T, deprecated) - #|struct SortedMap[K, V] { - #| mut root : Node[K, V]? - #| mut size : Int - #|} - ), - "utils.mbt": ( - #|fn[K, V] new_node(key : K, value : V) -> Node[K, V] { - #| { key, value, left: None, right: None, height: 1 } - #|} - #|impl[K : Eq, V] Eq for Node[K, V] with equal(self, other) { - #| self.key == other.key - #|} - #|fn max(x : Int, y : Int) -> Int { - #| if x > y { - #| x - #| } else { - #| y - #| } - #|} - #|fn[K, V] height(node : Node[K, V]?) -> Int { - #| match node { - #| None => 0 - #| Some(n) => n.height - #| } - #|} - #|fn[K : Show, V : Show] Node::debug_node(self : Node[K, V]) -> String { - #| let l = match self.left { - #| Some(left) => left.debug_node() - #| None => "_" - #| } - #| let r = match self.right { - #| Some(right) => right.debug_node() - #| None => "_" - #| } - #| "([\{self.height}]\{self.key},\{self.value},\{l},\{r})" - #|} - #|fn[K : Show, V : Show] SortedMap::debug_tree(self : SortedMap[K, V]) -> String { - #| match self.root { - #| Some(root) => root.debug_node() - #| None => "_" - #| } - #|} - #|pub impl[K : Show, V : Show] Show for SortedMap[K, V] with output(self, logger) { - #| logger.write_iter(self.iter(), prefix="@sorted_map.from_array([", suffix="])") - #|} - #|pub impl[K : Show, V : ToJson] ToJson for SortedMap[K, V] with to_json(self) { - #| let capacity = self.length() - #| guard capacity != 0 else { return Json::object(Map::new()) } - #| let jsons = Map::new(capacity~) - #| self.each((k, v) => jsons[k.to_string()] = v.to_json()) - #| Json::object(jsons) - #|} - #|pub impl[V : @json.FromJson] @json.FromJson for SortedMap[String, V] with from_json( - #| json, - #| path, - #|) { - #| guard json is Object(obj) else { - #| raise @json.JsonDecodeError( - #| (path, "@sorted_map.from_json: expected object"), - #| ) - #| } - #| let map = new() - #| for k, v in obj { - #| map.set(k, V::from_json(v, path.add_key(k))) - #| } - #| map - #|} - ), - }, + "deprecated.mbt": ( + #|#deprecated("Use `keys_as_iter` instead. `keys` will return `Iter[K]` instead of `Array[K]` in the future.") + #|#coverage.skip + #|pub fn[K, V] SortedMap::keys(self : SortedMap[K, V]) -> Array[K] { + #| let keys = Array::new(capacity=self.size) + #| self.each((k, _v) => keys.push(k)) + #| keys + #|} + #|#deprecated("Use `values_as_iter` instead. `values` will return `Iter[V]` instead of `Array[V]` in the future.") + #|#coverage.skip + #|pub fn[K, V] SortedMap::values(self : SortedMap[K, V]) -> Array[V] { + #| let values = Array::new(capacity=self.size) + #| self.each((_k, v) => values.push(v)) + #| values + #|} + ), + "map.mbt": ( + #|pub impl[K : Eq, V : Eq] Eq for SortedMap[K, V] with equal(self, other) { + #| guard self.size == other.size else { return false } + #| let iter = self.iter() + #| let iter1 = other.iter() + #| while iter.next() is Some(a) && iter1.next() is Some(b) { + #| guard a == b else { break false } + #| } nobreak { + #| true + #| } + #|} + #|#as_free_fn + #|pub fn[K, V] SortedMap::new() -> SortedMap[K, V] { + #| { root: None, size: 0 } + #|} + #|#as_free_fn + #|#alias(of, deprecated="Use from_array instead") + #|#as_free_fn(of, deprecated="Use from_array instead") + #|pub fn[K : Compare, V] SortedMap::from_array( + #| entries : ArrayView[(K, V)], + #|) -> SortedMap[K, V] { + #| let map = { root: None, size: 0 } + #| for e in entries { + #| map.set(e.0, e.1) + #| } + #| map + #|} + #|#alias("_[_]=_") + #|#alias(add, deprecated="Use set instead") + #|pub fn[K : Compare, V] SortedMap::set( + #| self : SortedMap[K, V], + #| key : K, + #| value : V, + #|) -> Unit { + #| let (new_root, inserted) = add_node(self.root, key, value) + #| if self.root != new_root { + #| self.root = new_root + #| } + #| if inserted { + #| self.size += 1 + #| } + #|} + #|pub fn[K : Compare, V] SortedMap::remove( + #| self : SortedMap[K, V], + #| key : K, + #|) -> Unit { + #| if self.root is Some(old_root) { + #| let (new_root, deleted) = delete_node(old_root, key) + #| if self.root != new_root { + #| self.root = new_root + #| } + #| if deleted { + #| self.size -= 1 + #| } + #| } + #|} + #|pub fn[K : Compare, V] SortedMap::get(self : SortedMap[K, V], key : K) -> V? { + #| loop self.root { + #| Some(node) => { + #| let cmp = key.compare(node.key) + #| if cmp == 0 { + #| break Some(node.value) + #| } else if cmp > 0 { + #| continue node.right + #| } else { + #| continue node.left + #| } + #| } + #| None => break None + #| } + #|} + #|#alias("_[_]") + #|pub fn[K : Compare, V] SortedMap::at(self : SortedMap[K, V], key : K) -> V { + #| loop self.root { + #| Some(node) => { + #| let cmp = key.compare(node.key) + #| if cmp == 0 { + #| break node.value + #| } else if cmp > 0 { + #| continue node.right + #| } else { + #| continue node.left + #| } + #| } + #| None => panic() + #| } + #|} + #|pub fn[K : Compare, V] SortedMap::get_or_init( + #| self : SortedMap[K, V], + #| key : K, + #| init : () -> V, + #|) -> V { + #| match self.get(key) { + #| Some(v) => v + #| None => { + #| let v = init() + #| self.set(key, v) + #| v + #| } + #| } + #|} + #|pub fn[K : Compare, V] SortedMap::get_or_default( + #| self : SortedMap[K, V], + #| key : K, + #| default : V, + #|) -> V { + #| match self.get(key) { + #| Some(v) => v + #| None => default + #| } + #|} + #|pub fn[K : Compare, V] SortedMap::contains( + #| self : SortedMap[K, V], + #| key : K, + #|) -> Bool { + #| self.get(key) is Some(_) + #|} + #|pub fn[K, V] SortedMap::is_empty(self : SortedMap[K, V]) -> Bool { + #| self.size == 0 + #|} + #|#alias(size, deprecated) + #|pub fn[K, V] SortedMap::length(self : SortedMap[K, V]) -> Int { + #| self.size + #|} + #|pub fn[K, V] SortedMap::clear(self : SortedMap[K, V]) -> Unit { + #| self.root = None + #| self.size = 0 + #|} + #|pub fn[K, V] SortedMap::each( + #| self : SortedMap[K, V], + #| f : (K, V) -> Unit raise?, + #|) -> Unit raise? { + #| fn dfs(root : Node[K, V]?) -> Unit raise? { + #| if root is Some(root) { + #| dfs(root.left) + #| f(root.key, root.value) + #| dfs(root.right) + #| } + #| } + #| dfs(self.root) + #|} + #|pub fn[K, V] SortedMap::eachi( + #| self : SortedMap[K, V], + #| f : (Int, K, V) -> Unit raise?, + #|) -> Unit raise? { + #| let mut i = 0 + #| self.each((k, v) => { + #| f(i, k, v) + #| i = i + 1 + #| }) + #|} + #|pub fn[K, V] SortedMap::keys_as_iter(self : SortedMap[K, V]) -> Iter[K] { + #| let todo_list = [] + #| let mut next_node = self.root + #| Iter::new(fn() { + #| loop next_node { + #| Some({ left, key, value: _, right, height: _ }) => { + #| todo_list.push((key, right)) + #| continue left + #| } + #| None if todo_list.pop() is Some((key, right)) => { + #| next_node = right + #| Some(key) + #| } + #| None => None + #| } + #| }) + #|} + #|pub fn[K, V] SortedMap::values_as_iter(self : SortedMap[K, V]) -> Iter[V] { + #| let todo_list = [] + #| let mut next_node = self.root + #| Iter::new(fn() { + #| loop next_node { + #| Some({ left, key: _, value, right, height: _ }) => { + #| todo_list.push((value, right)) + #| continue left + #| } + #| None if todo_list.pop() is Some((value, right)) => { + #| next_node = right + #| Some(value) + #| } + #| None => None + #| } + #| }) + #|} + #|pub fn[K, V] SortedMap::to_array(self : SortedMap[K, V]) -> Array[(K, V)] { + #| let arr = Array::new(capacity=self.size) + #| self.each((k, v) => arr.push((k, v))) + #| arr + #|} + #|#alias(iterator, deprecated) + #|pub fn[K, V] SortedMap::iter(self : SortedMap[K, V]) -> Iter[(K, V)] { + #| let todo_list = [] + #| let mut next_node = self.root + #| Iter::new(fn() { + #| loop next_node { + #| Some({ left, key, value, right, height: _ }) => { + #| todo_list.push((key, value, right)) + #| continue left + #| } + #| None if todo_list.pop() is Some((key, value, right)) => { + #| next_node = right + #| Some((key, value)) + #| } + #| None => None + #| } + #| }) + #|} + #|#alias(iterator2, deprecated) + #|pub fn[K, V] SortedMap::iter2(self : SortedMap[K, V]) -> Iter2[K, V] { + #| self.iter() + #|} + #|#as_free_fn + #|#alias(from_iterator, deprecated) + #|#as_free_fn(from_iterator, deprecated) + #|pub fn[K : Compare, V] SortedMap::from_iter( + #| iter : Iter[(K, V)], + #|) -> SortedMap[K, V] { + #| let m = new() + #| while iter.next() is Some((k, v)) { + #| m[k] = v + #| } + #| m + #|} + #|pub impl[K : @quickcheck.Arbitrary + Compare, V : @quickcheck.Arbitrary] @quickcheck.Arbitrary for SortedMap[ + #| K, + #| V, + #|] with arbitrary(size, rs) { + #| @quickcheck.Arbitrary::arbitrary(size, rs) |> from_iter + #|} + #|pub fn[K : Compare, V] SortedMap::range( + #| self : SortedMap[K, V], + #| low : K, + #| high : K, + #|) -> Iter2[K, V] { + #| let todo_list = [] + #| let mut next_node = self.root + #| Iter2::new(fn() { + #| loop next_node { + #| Some({ left, key, value, right, height: _ }) => { + #| let cmp_key_low = key.compare(low) + #| let cmp_key_high = key.compare(high) + #| if cmp_key_low < 0 { + #| continue right + #| } else if cmp_key_high > 0 { + #| continue left + #| } else if left is None { + #| next_node = right + #| Some((key, value)) + #| } else { + #| todo_list.push((key, value, right)) + #| continue left + #| } + #| } + #| None if todo_list.pop() is Some((key, value, right)) => { + #| next_node = right + #| Some((key, value)) + #| } + #| None => None + #| } + #| }).iter2() + #|} + #|#alias(clone, deprecated) + #|pub fn[K, V] SortedMap::copy(self : SortedMap[K, V]) -> SortedMap[K, V] { + #| fn copy_node(node : Node[K, V]?) -> Node[K, V]? { + #| match node { + #| None => None + #| Some({ key, value, left, right, height }) => + #| Some({ + #| key, + #| value, + #| left: copy_node(left), + #| right: copy_node(right), + #| height, + #| }) + #| } + #| } + #| { root: copy_node(self.root), size: self.size } + #|} + #|pub fn[K : Compare, V] SortedMap::merge( + #| self : SortedMap[K, V], + #| other : SortedMap[K, V], + #|) -> SortedMap[K, V] { + #| let result = self.copy() + #| other.each((k, v) => result.set(k, v)) + #| result + #|} + #|pub fn[K : Compare, V] SortedMap::merge_in_place( + #| self : SortedMap[K, V], + #| other : SortedMap[K, V], + #|) -> Unit { + #| other.each((k, v) => self.set(k, v)) + #|} + #|fn[K, V] replace_root_with_min( + #| root : Node[K, V], + #| node : Node[K, V], + #|) -> Node[K, V]? { + #| let (l, r) = (node.left, node.right) + #| match l { + #| None => { + #| root.key = node.key + #| root.value = node.value + #| r + #| } + #| Some(ln) => { + #| node.left = replace_root_with_min(root, ln) + #| Some(balance(node)) + #| } + #| } + #|} + #|fn[K, V] Node::update_height(self : Node[K, V]) -> Unit { + #| self.height = 1 + max(height(self.left), height(self.right)) + #|} + #|fn[K, V] height_ge(x1 : Node[K, V]?, x2 : Node[K, V]?) -> Bool { + #| match x2 { + #| None => true + #| Some(n2) => + #| match x1 { + #| None => false + #| Some(n1) => n1.height >= n2.height + #| } + #| } + #|} + #|fn[K, V] balance(root : Node[K, V]) -> Node[K, V] { + #| let (l, r) = (root.left, root.right) + #| let (hl, hr) = (height(l), height(r)) + #| let new_root = if hl > hr + 1 { + #| let { left: ll, right: lr, .. } = l.unwrap() + #| if height_ge(ll, lr) { + #| rotate_r(root) + #| } else { + #| rotate_lr(root) + #| } + #| } else if hr > hl + 1 { + #| let { left: rl, right: rr, .. } = r.unwrap() + #| if height_ge(rr, rl) { + #| rotate_l(root) + #| } else { + #| rotate_rl(root) + #| } + #| } else { + #| root + #| } + #| new_root.update_height() + #| new_root + #|} + #|fn[K, V] rotate_l(n : Node[K, V]) -> Node[K, V] { + #| let r = n.right.unwrap() + #| n.right = r.left + #| r.left = Some(n) + #| n.update_height() + #| r.update_height() + #| r + #|} + #|fn[K, V] rotate_r(n : Node[K, V]) -> Node[K, V] { + #| let l = n.left.unwrap() + #| n.left = l.right + #| l.right = Some(n) + #| n.update_height() + #| l.update_height() + #| l + #|} + #|fn[K, V] rotate_lr(n : Node[K, V]) -> Node[K, V] { + #| let l = n.left.unwrap() + #| let v = rotate_l(l) + #| n.left = Some(v) + #| rotate_r(n) + #|} + #|fn[K, V] rotate_rl(n : Node[K, V]) -> Node[K, V] { + #| let r = n.right.unwrap() + #| let v = rotate_r(r) + #| n.right = Some(v) + #| rotate_l(n) + #|} + #|fn[K : Compare, V] add_node( + #| root : Node[K, V]?, + #| key : K, + #| value : V, + #|) -> (Node[K, V]?, Bool) { + #| match root { + #| None => (Some(new_node(key, value)), true) + #| Some(n) => + #| if key == n.key { + #| n.value = value + #| (Some(n), false) + #| } else { + #| let (l, r) = (n.left, n.right) + #| if key < n.key { + #| let (nl, inserted) = add_node(l, key, value) + #| n.left = nl + #| (Some(balance(n)), inserted) + #| } else { + #| let (nr, inserted) = add_node(r, key, value) + #| n.right = nr + #| (Some(balance(n)), inserted) + #| } + #| } + #| } + #|} + #|fn[K : Compare, V] delete_node( + #| root : Node[K, V], + #| key : K, + #|) -> (Node[K, V]?, Bool) { + #| if key == root.key { + #| let (l, r) = (root.left, root.right) + #| let n = match (l, r) { + #| (Some(_), Some(nr)) => { + #| root.right = replace_root_with_min(root, nr) + #| Some(balance(root)) + #| } + #| (None, Some(_)) => r + #| (Some(_), None) | (None, None) => l + #| } + #| (n, true) + #| } else if key < root.key { + #| match root.left { + #| None => (Some(root), false) + #| Some(l) => { + #| let (nl, deleted) = delete_node(l, key) + #| root.left = nl + #| (Some(balance(root)), deleted) + #| } + #| } + #| } else { + #| match root.right { + #| None => (Some(root), false) + #| Some(r) => { + #| let (nr, deleted) = delete_node(r, key) + #| root.right = nr + #| (Some(balance(root)), deleted) + #| } + #| } + #| } + #|} + #|test "new" { + #| let map : SortedMap[Int, String] = new() + #| inspect(map.debug_tree(), content="_") + #| inspect(map.length(), content="0") + #|} + #|test "of" { + #| let map = from_array([(3, "c"), (2, "b"), (1, "a")]) + #| inspect(map.debug_tree(), content="([2]2,b,([1]1,a,_,_),([1]3,c,_,_))") + #| inspect(map.length(), content="3") + #|} + #|test "add1" { + #| let map = new() + #| map.set(6, "a") + #| map.set(5, "b") + #| map.set(4, "c") + #| map.set(3, "d") + #| map.set(2, "e") + #| map.set(1, "f") + #| inspect( + #| map.debug_tree(), + #| content="([3]3,d,([2]2,e,([1]1,f,_,_),_),([2]5,b,([1]4,c,_,_),([1]6,a,_,_)))", + #| ) + #| inspect(map.length(), content="6") + #|} + #|test "add2" { + #| let map = new() + #| map.set(1, "a") + #| map.set(2, "b") + #| map.set(3, "c") + #| map.set(4, "d") + #| map.set(5, "e") + #| map.set(6, "f") + #| inspect( + #| map.debug_tree(), + #| content="([3]4,d,([2]2,b,([1]1,a,_,_),([1]3,c,_,_)),([2]5,e,_,([1]6,f,_,_)))", + #| ) + #| inspect(map.length(), content="6") + #|} + #|test "add3" { + #| let map = new() + #| map.set(4, "a") + #| map.set(1, "b") + #| map.set(3, "c") + #| map.set(2, "d") + #| inspect( + #| map.debug_tree(), + #| content="([3]3,c,([2]1,b,_,([1]2,d,_,_)),([1]4,a,_,_))", + #| ) + #|} + #|test "add4" { + #| let map = new() + #| map.set(1, "a") + #| map.set(4, "b") + #| map.set(2, "c") + #| map.set(3, "d") + #| inspect( + #| map.debug_tree(), + #| content="([3]2,c,([1]1,a,_,_),([2]4,b,([1]3,d,_,_),_))", + #| ) + #|} + #|test "add duplicate key" { + #| let map = from_array([(3, "c"), (2, "b"), (1, "a")]) + #| inspect(map.debug_tree(), content="([2]2,b,([1]1,a,_,_),([1]3,c,_,_))") + #| map.set(1, "x") + #| inspect(map.debug_tree(), content="([2]2,b,([1]1,x,_,_),([1]3,c,_,_))") + #|} + #|test "remove" { + #| let map = from_array([ + #| (1, "a"), + #| (2, "b"), + #| (3, "c"), + #| (4, "d"), + #| (5, "e"), + #| (6, "f"), + #| (7, "g"), + #| (8, "h"), + #| ]) + #| inspect( + #| map.debug_tree(), + #| content="([4]4,d,([2]2,b,([1]1,a,_,_),([1]3,c,_,_)),([3]6,f,([1]5,e,_,_),([2]7,g,_,([1]8,h,_,_))))", + #| ) + #| inspect(map.length(), content="8") + #| map.remove(6) + #| inspect( + #| map.debug_tree(), + #| content="([3]4,d,([2]2,b,([1]1,a,_,_),([1]3,c,_,_)),([2]7,g,([1]5,e,_,_),([1]8,h,_,_)))", + #| ) + #| inspect(map.length(), content="7") + #| map.remove(4) + #| inspect( + #| map.debug_tree(), + #| content="([3]5,e,([2]2,b,([1]1,a,_,_),([1]3,c,_,_)),([2]7,g,_,([1]8,h,_,_)))", + #| ) + #| inspect(map.length(), content="6") + #| map.remove(2) + #| inspect( + #| map.debug_tree(), + #| content="([3]5,e,([2]3,c,([1]1,a,_,_),_),([2]7,g,_,([1]8,h,_,_)))", + #| ) + #| inspect(map.length(), content="5") + #| map.remove(3) + #| inspect( + #| map.debug_tree(), + #| content="([3]5,e,([1]1,a,_,_),([2]7,g,_,([1]8,h,_,_)))", + #| ) + #| inspect(map.length(), content="4") + #| map.remove(5) + #| inspect(map.debug_tree(), content="([2]7,g,([1]1,a,_,_),([1]8,h,_,_))") + #| inspect(map.length(), content="3") + #| map.remove(7) + #| inspect(map.debug_tree(), content="([2]8,h,([1]1,a,_,_),_)") + #| inspect(map.length(), content="2") + #| map.remove(8) + #| inspect(map.debug_tree(), content="([1]1,a,_,_)") + #| inspect(map.length(), content="1") + #| map.remove(1) + #| inspect(map.debug_tree(), content="_") + #| inspect(map.size, content="0") + #|} + #|test "_[_]=_" { + #| let map = new() + #| map[1] = "a" + #| map[2] = "b" + #| map[3] = "c" + #| inspect(map.debug_tree(), content="([2]2,b,([1]1,a,_,_),([1]3,c,_,_))") + #|} + #|test "clear" { + #| let map = from_array([(3, "c"), (2, "b"), (1, "a")]) + #| map.clear() + #| inspect(map.debug_tree(), content="_") + #| inspect(map.length(), content="0") + #|} + #|test "copy" { + #| let map1 = from_array([ + #| (1, "a"), + #| (2, "b"), + #| (3, "c"), + #| (4, "d"), + #| (5, "e"), + #| (6, "f"), + #| ]) + #| let map2 = map1.copy() + #| inspect(map1.debug_tree(), content=map2.debug_tree()) + #| inspect(map1.length(), content="6") + #| inspect(map2.length(), content="6") + #| map2.set(7, "g") + #| inspect(map1.length(), content="6") + #| inspect(map2.length(), content="7") + #| inspect(map1.get(7), content="None") + #| inspect(map2.get(7), content="Some(\"g\")") + #| map1.remove(1) + #| inspect(map1.length(), content="5") + #| inspect(map2.length(), content="7") + #| inspect(map1.get(1), content="None") + #| inspect(map2.get(1), content="Some(\"a\")") + #|} + #|pub impl[K, V] Default for SortedMap[K, V] with default() { + #| new() + #|} + ), + "types.mbt": ( + #|priv struct Node[K, V] { + #| mut key : K + #| mut value : V + #| mut left : Node[K, V]? + #| mut right : Node[K, V]? + #| mut height : Int + #|} + #|#alias(T, deprecated) + #|struct SortedMap[K, V] { + #| mut root : Node[K, V]? + #| mut size : Int + #|} + ), + "utils.mbt": ( + #|fn[K, V] new_node(key : K, value : V) -> Node[K, V] { + #| { key, value, left: None, right: None, height: 1 } + #|} + #|impl[K : Eq, V] Eq for Node[K, V] with equal(self, other) { + #| self.key == other.key + #|} + #|fn max(x : Int, y : Int) -> Int { + #| if x > y { + #| x + #| } else { + #| y + #| } + #|} + #|fn[K, V] height(node : Node[K, V]?) -> Int { + #| match node { + #| None => 0 + #| Some(n) => n.height + #| } + #|} + #|fn[K : Show, V : Show] Node::debug_node(self : Node[K, V]) -> String { + #| let l = match self.left { + #| Some(left) => left.debug_node() + #| None => "_" + #| } + #| let r = match self.right { + #| Some(right) => right.debug_node() + #| None => "_" + #| } + #| "([\{self.height}]\{self.key},\{self.value},\{l},\{r})" + #|} + #|fn[K : Show, V : Show] SortedMap::debug_tree(self : SortedMap[K, V]) -> String { + #| match self.root { + #| Some(root) => root.debug_node() + #| None => "_" + #| } + #|} + #|pub impl[K : Show, V : Show] Show for SortedMap[K, V] with output(self, logger) { + #| logger.write_iter(self.iter(), prefix="@sorted_map.from_array([", suffix="])") + #|} + #|pub impl[K : Show, V : ToJson] ToJson for SortedMap[K, V] with to_json(self) { + #| let capacity = self.length() + #| guard capacity != 0 else { return Json::object(Map::new()) } + #| let jsons = Map::new(capacity~) + #| self.each((k, v) => jsons[k.to_string()] = v.to_json()) + #| Json::object(jsons) + #|} + #|pub impl[V : @json.FromJson] @json.FromJson for SortedMap[String, V] with from_json( + #| json, + #| path, + #|) { + #| guard json is Object(obj) else { + #| raise @json.JsonDecodeError( + #| (path, "@sorted_map.from_json: expected object"), + #| ) + #| } + #| let map = new() + #| for k, v in obj { + #| map.set(k, V::from_json(v, path.add_key(k))) + #| } + #| map + #|} + ) + } ) ///| let moonbitlang_core_sorted_set_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/sorted_set", - deps={ - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/option": moonbitlang_core_option_module, - "moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module, - }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": ["moonbitlang/core/builtin", "moonbitlang/core/option", "moonbitlang/core/quickcheck"], - #| "test-import": ["moonbitlang/core/array"] - #|} - ), - "deprecated.mbt": "", - "set.mbt": ( - #|#as_free_fn - #|pub fn[V] SortedSet::new() -> SortedSet[V] { - #| { root: None, size: 0 } - #|} - #|#as_free_fn - #|pub fn[V] SortedSet::singleton(value : V) -> SortedSet[V] { - #| { root: Some({ value, left: None, right: None, height: 1 }), size: 1 } - #|} - #|#as_free_fn - #|#alias(of, deprecated="Use from_array instead") - #|#as_free_fn(of, deprecated="Use from_array instead") - #|pub fn[V : Compare] SortedSet::from_array(array : ArrayView[V]) -> SortedSet[V] { - #| let set = new() - #| for i in 0.. SortedSet[V] { - #| match self.root { - #| None => new() - #| Some(_) => { root: copy_tree(self.root), size: self.size } - #| } - #|} - #|fn[V] copy_tree(node : Node[V]?) -> Node[V]? { - #| match node { - #| None => None - #| Some(node) => { - #| let left = copy_tree(node.left) - #| let right = copy_tree(node.right) - #| let new_node = new_node(node.value, left~, right~, height=node.height) - #| Some(new_node) - #| } - #| } - #|} - #|fn[V] new_node( - #| value : V, - #| left? : Node[V]? = None, - #| right? : Node[V]? = None, - #| height? : Int = 1, - #|) -> Node[V] { - #| { value, left, right, height } - #|} - #|fn[V] new_node_update_height( - #| value : V, - #| left~ : Node[V]?, - #| right~ : Node[V]?, - #|) -> Node[V] { - #| { value, left, right, height: max(height(left), height(right)) + 1 } - #|} - #|pub fn[V : Compare] SortedSet::add(self : SortedSet[V], value : V) -> Unit { - #| let (new_root, inserted) = add_node(self.root, value) - #| if self.root != new_root { - #| self.root = new_root - #| } - #| if inserted { - #| self.size += 1 - #| } - #|} - #|pub fn[V : Compare] SortedSet::remove(self : SortedSet[V], value : V) -> Unit { - #| if self.root is Some(old_root) { - #| let (new_root, deleted) = delete_node(old_root, value) - #| if self.root != new_root { - #| self.root = new_root - #| } - #| if deleted { - #| self.size -= 1 - #| } - #| } - #|} - #|pub fn[V : Compare] SortedSet::contains(self : SortedSet[V], value : V) -> Bool { - #| loop (self.root, value) { - #| (None, _) => false - #| (Some(node), value) => { - #| let compare_result = value.compare(node.value) - #| if compare_result == 0 { - #| true - #| } else if compare_result < 0 { - #| continue (node.left, value) - #| } else { - #| continue (node.right, value) - #| } - #| } - #| } - #|} - #|pub fn[V : Compare] SortedSet::union( - #| self : SortedSet[V], - #| src : SortedSet[V], - #|) -> SortedSet[V] { - #| fn aux(a : Node[V]?, b : Node[V]?) -> Node[V]? { - #| match (a, b) { - #| (Some(_), None) => a - #| (None, Some(_)) => b - #| (Some({ value: va, left: la, right: ra, .. }), Some(_)) => { - #| let (l, r) = split(b, va) - #| Some(join(aux(la, l), va, aux(ra, r))) - #| } - #| (None, None) => None - #| } - #| } - #| match (self.root, src.root) { - #| (Some(_), Some(_)) => { - #| let t1 = copy_tree(self.root) - #| let t2 = copy_tree(src.root) - #| let t = aux(t1, t2) - #| let mut ct = 0 - #| let ret = { root: t, size: 0 } - #| ret.each(_x => ct = ct + 1) - #| ret.size = ct - #| ret - #| } - #| (Some(_), None) => { root: copy_tree(self.root), size: self.size } - #| (None, Some(_)) => { root: copy_tree(src.root), size: src.size } - #| (None, None) => new() - #| } - #|} - #|fn[V : Compare] split(root : Node[V]?, value : V) -> (Node[V]?, Node[V]?) { - #| match root { - #| None => (None, None) - #| Some(node) => { - #| let comp = value.compare(node.value) - #| if comp == 0 { - #| (node.left, node.right) - #| } else if comp < 0 { - #| let (l, r) = split(node.left, value) - #| (l, Some(join(r, node.value, node.right))) - #| } else { - #| let (l, r) = split(node.right, value) - #| (Some(join(node.left, node.value, l)), r) - #| } - #| } - #| } - #|} - #|fn[V] join(left : Node[V]?, value : V, right : Node[V]?) -> Node[V] { - #| let (hl, hr) = (height(left), height(right)) - #| if hl > hr + 1 { - #| join_right(left, value, right) - #| } else if hr > hl + 1 { - #| join_left(left, value, right) - #| } else { - #| new_node_update_height(value, left~, right~) - #| } - #|} - #|fn[V] join_left(l : Node[V]?, v : V, r : Node[V]?) -> Node[V] { - #| let { value: rv, left: rl, right: rr, .. } = r.unwrap() - #| let node = if height(rl) <= height(l) + 1 { - #| let new_l = new_node_update_height(left=l, v, right=rl) - #| if height(Some(new_l)) <= height(rr) + 1 { - #| new_node_update_height(left=Some(new_l), rv, right=rr) - #| } else { - #| let new_l = rotate_l(new_l) - #| let new = new_node_update_height(left=Some(new_l), rv, right=rr) - #| rotate_r(new) - #| } - #| } else { - #| let new_l = join_left(l, v, rl) - #| let new = new_node_update_height(left=Some(new_l), rv, right=rr) - #| if height(Some(new_l)) <= height(rr) + 1 { - #| new - #| } else { - #| rotate_r(new) - #| } - #| } - #| node.update_height() - #| node - #|} - #|fn[V] join_right(l : Node[V]?, v : V, r : Node[V]?) -> Node[V] { - #| let { value: lv, left: ll, right: lr, .. } = l.unwrap() - #| let node = if height(lr) <= height(r) + 1 { - #| let new_r = new_node_update_height(left=lr, v, right=r) - #| if height(Some(new_r)) <= height(ll) + 1 { - #| new_node_update_height(left=ll, lv, right=Some(new_r)) - #| } else { - #| let new_r = rotate_r(new_r) - #| let new = new_node_update_height(left=ll, lv, right=Some(new_r)) - #| rotate_l(new) - #| } - #| } else { - #| let new_r = join_right(lr, v, r) - #| let new = new_node_update_height(left=ll, lv, right=Some(new_r)) - #| if height(Some(new_r)) <= height(ll) + 1 { - #| new - #| } else { - #| rotate_l(new) - #| } - #| } - #| node.update_height() - #| node - #|} - #|#alias(diff, deprecated) - #|pub fn[V : Compare] SortedSet::difference( - #| self : SortedSet[V], - #| src : SortedSet[V], - #|) -> SortedSet[V] { - #| let ret = new() - #| self.each(x => if !src.contains(x) { ret.add(x) }) - #| ret - #|} - #|pub fn[V : Compare] SortedSet::symmetric_difference( - #| self : SortedSet[V], - #| other : SortedSet[V], - #|) -> SortedSet[V] { - #| let set1 = self.difference(other) - #| let set2 = other.difference(self) - #| set1.union(set2) - #|} - #|#alias(intersect, deprecated) - #|pub fn[V : Compare] SortedSet::intersection( - #| self : SortedSet[V], - #| src : SortedSet[V], - #|) -> SortedSet[V] { - #| let ret = new() - #| self.each(x => if src.contains(x) { ret.add(x) }) - #| ret - #|} - #|pub fn[V : Compare] SortedSet::subset( - #| self : SortedSet[V], - #| src : SortedSet[V], - #|) -> Bool { - #| let mut ret = true - #| self.each(x => if !src.contains(x) { ret = false }) - #| ret - #|} - #|pub fn[V : Compare] SortedSet::disjoint( - #| self : SortedSet[V], - #| src : SortedSet[V], - #|) -> Bool { - #| let mut ret = true - #| self.each(x => if src.contains(x) { ret = false }) - #| ret - #|} - #|pub impl[V : Eq] Eq for SortedSet[V] with equal(self, other) { - #| guard self.size == other.size else { return false } - #| let iter = self.iterator() - #| let iter1 = other.iterator() - #| while iter.next() is Some(a) && iter1.next() is Some(b) { - #| guard a == b else { break false } - #| } else { - #| true - #| } - #|} - #|pub fn[V] SortedSet::is_empty(self : SortedSet[V]) -> Bool { - #| self.root is None - #|} - #|#alias(size, deprecated) - #|pub fn[V] SortedSet::length(self : SortedSet[V]) -> Int { - #| self.size - #|} - #|pub fn[V] SortedSet::each( - #| self : SortedSet[V], - #| f : (V) -> Unit raise?, - #|) -> Unit raise? { - #| fn dfs(root : Node[V]?) -> Unit raise? { - #| if root is Some(root) { - #| dfs(root.left) - #| f(root.value) - #| dfs(root.right) - #| } - #| } - #| dfs(self.root) - #|} - #|pub fn[V] SortedSet::eachi( - #| self : SortedSet[V], - #| f : (Int, V) -> Unit raise?, - #|) -> Unit raise? { - #| let mut i = 0 - #| self.each(v => { - #| f(i, v) - #| i = i + 1 - #| }) - #|} - #|pub fn[V] SortedSet::to_array(self : SortedSet[V]) -> Array[V] { - #| if self.size == 0 { - #| [] - #| } else { - #| let padding = self.root.unwrap().value - #| let arr = Array::make(self.size, padding) - #| let mut i = 0 - #| fn dfs(root : Node[V]?) -> Unit { - #| if root is Some(root) { - #| dfs(root.left) - #| arr[i] = root.value - #| i = i + 1 - #| dfs(root.right) - #| } - #| } - #| dfs(self.root) - #| arr - #| } - #|} - #|pub fn[V] SortedSet::iter(self : SortedSet[V]) -> Iter[V] { - #| self.iterator().iter() - #|} - #|pub fn[V] SortedSet::iterator(self : SortedSet[V]) -> Iterator[V] { - #| let mut curr_node = self.root - #| let parents = [] - #| Iterator::new(fn() { - #| loop curr_node { - #| Some({ left: None, value, right, height: _ }) => { - #| curr_node = right - #| Some(value) - #| } - #| Some({ left, value, right, height: _ }) => { - #| parents.push((value, right)) - #| continue left - #| } - #| None if parents.pop() is Some((value, right)) => { - #| curr_node = right - #| Some(value) - #| } - #| None => None - #| } - #| }) - #|} - #|#as_free_fn - #|pub fn[V : Compare] SortedSet::from_iter(iter : Iter[V]) -> SortedSet[V] { - #| let s = new() - #| iter.each(e => s.add(e)) - #| s - #|} - #|#as_free_fn - #|pub fn[V : Compare] SortedSet::from_iterator( - #| iter : Iterator[V], - #|) -> SortedSet[V] { - #| let s = new() - #| while iter.next() is Some(e) { - #| s.add(e) - #| } - #| s - #|} - #|pub impl[V : Show] Show for SortedSet[V] with output(self, logger) { - #| logger.write_iter(self.iter(), prefix="@sorted_set.from_array([", suffix="])") - #|} - #|pub impl[X : @quickcheck.Arbitrary + Compare] @quickcheck.Arbitrary for SortedSet[ - #| X, - #|] with arbitrary(size, rs) { - #| @quickcheck.Arbitrary::arbitrary(size, rs) |> from_iter - #|} - #|impl[T : Show] Show for Node[T] with output(self, logger) { - #| let x = { root: Some(self), size: 0 } // Hack for test - #| logger.write_iter(x.iter()) - #|} - #|pub fn[V : Compare] SortedSet::range( - #| self : SortedSet[V], - #| low : V, - #| high : V, - #|) -> Iter[V] { - #| let mut curr_node = self.root - #| let parents = [] - #| let iter = Iterator::new(() => loop curr_node { - #| Some({ value, left, right, height: _ }) => { - #| let cmp_key_low = value.compare(low) - #| let cmp_key_high = value.compare(high) - #| if cmp_key_low < 0 { - #| continue right - #| } else if cmp_key_high > 0 { - #| continue left - #| } else if left is None { - #| curr_node = right - #| Some(value) - #| } else { - #| parents.push((value, right)) - #| continue left - #| } - #| } - #| None if parents.pop() is Some((value, right)) => { - #| curr_node = right - #| Some(value) - #| } - #| None => None - #| }) - #| iter.iter() - #|} - #|fn[V] replace_root_with_min(root : Node[V], node : Node[V]) -> Node[V]? { - #| let (l, r) = (node.left, node.right) - #| match l { - #| None => { - #| root.value = node.value - #| r - #| } - #| Some(ln) => { - #| node.left = replace_root_with_min(root, ln) - #| Some(balance(node)) - #| } - #| } - #|} - #|fn[V] Node::update_height(self : Node[V]) -> Unit { - #| self.height = 1 + max(height(self.left), height(self.right)) - #|} - #|fn[V] height_ge(x1 : Node[V]?, x2 : Node[V]?) -> Bool { - #| match x2 { - #| None => true - #| Some(n2) => - #| match x1 { - #| None => false - #| Some(n1) => n1.height >= n2.height - #| } - #| } - #|} - #|fn[V] balance(root : Node[V]) -> Node[V] { - #| let (l, r) = (root.left, root.right) - #| let (hl, hr) = (height(l), height(r)) - #| let new_root = if hl > hr + 1 { - #| let { left: ll, right: lr, .. } = l.unwrap() - #| if height_ge(ll, lr) { - #| rotate_r(root) - #| } else { - #| rotate_lr(root) - #| } - #| } else if hr > hl + 1 { - #| let { left: rl, right: rr, .. } = r.unwrap() - #| if height_ge(rr, rl) { - #| rotate_l(root) - #| } else { - #| rotate_rl(root) - #| } - #| } else { - #| root - #| } - #| new_root.update_height() - #| new_root - #|} - #|fn[V] rotate_l(n : Node[V]) -> Node[V] { - #| let r = n.right.unwrap() - #| n.right = r.left - #| r.left = Some(n) - #| n.update_height() - #| r.update_height() - #| r - #|} - #|fn[V] rotate_r(n : Node[V]) -> Node[V] { - #| let l = n.left.unwrap() - #| n.left = l.right - #| l.right = Some(n) - #| n.update_height() - #| l.update_height() - #| l - #|} - #|fn[V] rotate_lr(n : Node[V]) -> Node[V] { - #| let l = n.left.unwrap() - #| let v = rotate_l(l) - #| n.left = Some(v) - #| rotate_r(n) - #|} - #|fn[V] rotate_rl(n : Node[V]) -> Node[V] { - #| let r = n.right.unwrap() - #| let v = rotate_r(r) - #| n.right = Some(v) - #| rotate_l(n) - #|} - #|fn[V : Compare] add_node(root : Node[V]?, value : V) -> (Node[V]?, Bool) { - #| match root { - #| None => (Some(new_node(value)), true) - #| Some(n) => { - #| let comp = value.compare(n.value) - #| if comp == 0 { - #| n.value = value - #| (Some(n), false) - #| } else { - #| let (l, r) = (n.left, n.right) - #| if comp < 0 { - #| let (nl, inserted) = add_node(l, value) - #| n.left = nl - #| (Some(balance(n)), inserted) - #| } else { - #| let (nr, inserted) = add_node(r, value) - #| n.right = nr - #| (Some(balance(n)), inserted) - #| } - #| } - #| } - #| } - #|} - #|fn[V : Compare] delete_node(root : Node[V], value : V) -> (Node[V]?, Bool) { - #| let comp = value.compare(root.value) - #| if comp == 0 { - #| let (l, r) = (root.left, root.right) - #| let n = match (l, r) { - #| (Some(_), Some(nr)) => { - #| root.right = replace_root_with_min(root, nr) - #| Some(balance(root)) - #| } - #| (None, Some(_)) => r - #| (Some(_), None) | (None, None) => l - #| } - #| (n, true) - #| } else if comp < 0 { - #| match root.left { - #| None => (Some(root), false) - #| Some(l) => { - #| let (nl, deleted) = delete_node(l, value) - #| root.left = nl - #| (Some(balance(root)), deleted) - #| } - #| } - #| } else { - #| match root.right { - #| None => (Some(root), false) - #| Some(r) => { - #| let (nr, deleted) = delete_node(r, value) - #| root.right = nr - #| (Some(balance(root)), deleted) - #| } - #| } - #| } - #|} - #|test "copy" { - #| let set = from_array([1, 2, 3, 4, 5]) - #| let copied_set = set.copy() - #| inspect(copied_set, content="@sorted_set.from_array([1, 2, 3, 4, 5])") - #| inspect(set.debug_tree() == copied_set.debug_tree(), content="true") - #| let set : SortedSet[Int] = from_array([]) - #| let copied_set = set.copy() - #| inspect(copied_set, content="@sorted_set.from_array([])") - #| inspect(set.debug_tree() == copied_set.debug_tree(), content="true") - #|} - #|test "union" { - #| let set1 = from_array([1, 2, 3]) - #| let set2 = from_array([4, 5, 6]) - #| let set3 = set1.union(set2) - #| inspect(set3, content="@sorted_set.from_array([1, 2, 3, 4, 5, 6])") - #| inspect( - #| set3.debug_tree(), - #| content="([3]3,([2]2,([1]1,_,_),_),([2]5,([1]4,_,_),([1]6,_,_)))", - #| ) - #| let set1 = from_array([1, 2, 3]) - #| let set2 = from_array([2, 3, 4]) - #| let set3 = set1.union(set2) - #| inspect(set3, content="@sorted_set.from_array([1, 2, 3, 4])") - #| inspect(set3.debug_tree(), content="([3]2,([1]1,_,_),([2]3,_,([1]4,_,_)))") - #| let set1 = from_array([1, 2, 3]) - #| let set2 = from_array([2, 3]) - #| let set3 = set1.union(set2) - #| inspect(set3, content="@sorted_set.from_array([1, 2, 3])") - #| inspect(set3.debug_tree(), content="([2]2,([1]1,_,_),([1]3,_,_))") - #| let set1 : SortedSet[Int] = new() - #| let set2 = new() - #| let set3 = set1.union(set2) - #| inspect(set3, content="@sorted_set.from_array([])") - #| inspect(set3.debug_tree(), content="_") - #| let set1 = from_array([1, 2, 3]) - #| let set2 = from_array([]) - #| let set3 = set1.union(set2) - #| inspect(set3, content="@sorted_set.from_array([1, 2, 3])") - #| inspect(set3.debug_tree(), content="([2]2,([1]1,_,_),([1]3,_,_))") - #| let set1 = from_array([]) - #| let set2 = from_array([1, 2, 3]) - #| let set3 = set1.union(set2) - #| inspect(set3, content="@sorted_set.from_array([1, 2, 3])") - #| inspect(set3.debug_tree(), content="([2]2,([1]1,_,_),([1]3,_,_))") - #| let set1 = from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) - #| let set2 = from_array([11, 12, 13, 14, 15, 16, 17, 18, 19, 20]) - #| let set3 = set1.union(set2) - #| inspect( - #| set3, - #| content="@sorted_set.from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20])", - #| ) - #| inspect( - #| set3.debug_tree(), - #| content="([5]14,([4]8,([3]4,([2]2,([1]1,_,_),([1]3,_,_)),([2]6,([1]5,_,_),([1]7,_,_))),([3]12,([2]10,([1]9,_,_),([1]11,_,_)),([1]13,_,_))),([3]18,([2]16,([1]15,_,_),([1]17,_,_)),([2]19,_,([1]20,_,_))))", - #| ) - #| let set1 = from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) - #| let set2 = from_array([6, 7, 8, 9, 10, 11, 12, 13, 14, 15]) - #| let set3 = set1.union(set2) - #| inspect( - #| set3, - #| content="@sorted_set.from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])", - #| ) - #| inspect( - #| set3.debug_tree(), - #| content="([5]11,([4]4,([2]2,([1]1,_,_),([1]3,_,_)),([3]8,([2]6,([1]5,_,_),([1]7,_,_)),([2]9,_,([1]10,_,_)))),([3]13,([1]12,_,_),([2]14,_,([1]15,_,_))))", - #| ) - #| let set1 = from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) - #| let set2 = from_array([6, 7, 8, 9, 10]) - #| let set3 = set1.union(set2) - #| inspect( - #| set3, - #| content="@sorted_set.from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])", - #| ) - #| inspect( - #| set3.debug_tree(), - #| content="([4]4,([2]2,([1]1,_,_),([1]3,_,_)),([3]8,([2]6,([1]5,_,_),([1]7,_,_)),([2]9,_,([1]10,_,_))))", - #| ) - #|} - #|test "split" { - #| let (l, r) = split(from_array([7, 2, 9, 4, 5, 6, 3, 8, 1]).root, 5) - #| inspect(l, content="Some([1, 2, 3, 4])") - #| inspect(r, content="Some([6, 7, 8, 9])") - #| let (l, r) = split(from_array([7, 2, 9, 4, 5, 6, 3, 8, 1]).root, 0) - #| inspect(l, content="None") - #| inspect(r, content="Some([1, 2, 3, 4, 5, 6, 7, 8, 9])") - #| let (l, r) = split(from_array([7, 2, 9, 4, 5, 6, 3, 8, 1]).root, 10) - #| inspect(l, content="Some([1, 2, 3, 4, 5, 6, 7, 8, 9])") - #| inspect(r, content="None") - #| let (l, r) = split(from_array([7, 2, 9, 4, 5, 6, 3, 8, 1]).root, 4) - #| inspect(l, content="Some([1, 2, 3])") - #| inspect(r, content="Some([5, 6, 7, 8, 9])") - #| let (l, r) = split(from_array([]).root, 7) - #| inspect(l, content="None") - #| inspect(r, content="None") - #| let (l, r) = split( - #| from_array([ - #| 0, 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, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, - #| 98, 99, 100, - #| ]).root, - #| 50, - #| ) - #| inspect( - #| l, - #| content="Some([0, 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])", - #| ) - #| inspect( - #| r, - #| content="Some([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, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100])", - #| ) - #|} - #|test "join" { - #| let l = from_array([13, 8, 17, 1, 11, 15, 25, 6]) - #| let r = from_array([27, 28, 40, 35, 33]) - #| inspect( - #| join(l.root, 26, r.root), - #| content="[1, 6, 8, 11, 13, 15, 17, 25, 26, 27, 28, 33, 35, 40]", - #| ) - #| let l = from_array([3, 2, 5, 1, 4]) - #| let r = from_array([7]) - #| inspect(join(l.root, 6, r.root), content="[1, 2, 3, 4, 5, 6, 7]") - #| let l = from_array([3, 2, 5, 1, 4]) - #| let r = from_array([]) - #| inspect(join(l.root, 6, r.root), content="[1, 2, 3, 4, 5, 6]") - #| let l = from_array([]) - #| let r = from_array([]) - #| inspect(join(l.root, 6, r.root), content="[6]") - #| let l = from_array([]) - #| let r = from_array([7, 8, 9, 10, 11, 12]) - #| inspect(join(l.root, 6, r.root), content="[6, 7, 8, 9, 10, 11, 12]") - #|} - #|test "add to empty set" { - #| let set = new() - #| set.add(1) - #| assert_eq(set.contains(1), true) - #| inspect(set.debug_tree(), content="([1]1,_,_)") - #|} - #|test "add to non-empty set" { - #| let set = new() - #| set.add(1) - #| set.add(2) - #| assert_eq(set.contains(1), true) - #| assert_eq(set.contains(2), true) - #| inspect(set.debug_tree(), content="([2]1,_,([1]2,_,_))") - #|} - #|test "add duplicate value" { - #| let set = new() - #| set.add(1) - #| set.add(1) - #| assert_eq(set.contains(1), true) - #| assert_eq(set.length(), 1) - #| inspect(set.debug_tree(), content="([1]1,_,_)") - #|} - #|test "add multiple values" { - #| let set = new() - #| set.add(1) - #| set.add(2) - #| set.add(3) - #| assert_eq(set.contains(1), true) - #| assert_eq(set.contains(2), true) - #| assert_eq(set.contains(3), true) - #| assert_eq(set.length(), 3) - #| inspect(set.debug_tree(), content="([2]2,([1]1,_,_),([1]3,_,_))") - #|} - #|test "add_and_remove" { - #| let set = from_array([7, 2, 9, 4, 5, 6, 3, 8, 1]) - #| set.remove(8) - #| inspect(set, content="@sorted_set.from_array([1, 2, 3, 4, 5, 6, 7, 9])") - #| inspect( - #| set.debug_tree(), - #| content="([4]5,([3]3,([2]2,([1]1,_,_),_),([1]4,_,_)),([2]7,([1]6,_,_),([1]9,_,_)))", - #| ) - #| let set = from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) - #| set.remove(1) - #| inspect(set, content="@sorted_set.from_array([2, 3, 4, 5, 6, 7, 8, 9, 10])") - #| inspect( - #| set.debug_tree(), - #| content="([4]4,([2]2,_,([1]3,_,_)),([3]8,([2]6,([1]5,_,_),([1]7,_,_)),([2]9,_,([1]10,_,_))))", - #| ) - #| set.remove(5) - #| inspect(set, content="@sorted_set.from_array([2, 3, 4, 6, 7, 8, 9, 10])") - #| inspect( - #| set.debug_tree(), - #| content="([4]4,([2]2,_,([1]3,_,_)),([3]8,([2]6,_,([1]7,_,_)),([2]9,_,([1]10,_,_))))", - #| ) - #| set.remove(10) - #| inspect(set, content="@sorted_set.from_array([2, 3, 4, 6, 7, 8, 9])") - #| inspect( - #| set.debug_tree(), - #| content="([4]4,([2]2,_,([1]3,_,_)),([3]8,([2]6,_,([1]7,_,_)),([1]9,_,_)))", - #| ) - #| set.remove(4) - #| inspect(set, content="@sorted_set.from_array([2, 3, 6, 7, 8, 9])") - #| inspect( - #| set.debug_tree(), - #| content="([3]6,([2]2,_,([1]3,_,_)),([2]8,([1]7,_,_),([1]9,_,_)))", - #| ) - #| set.add(1) - #| inspect(set, content="@sorted_set.from_array([1, 2, 3, 6, 7, 8, 9])") - #| inspect( - #| set.debug_tree(), - #| content="([3]6,([2]2,([1]1,_,_),([1]3,_,_)),([2]8,([1]7,_,_),([1]9,_,_)))", - #| ) - #| set.add(5) - #| inspect(set, content="@sorted_set.from_array([1, 2, 3, 5, 6, 7, 8, 9])") - #| inspect( - #| set.debug_tree(), - #| content="([4]6,([3]2,([1]1,_,_),([2]3,_,([1]5,_,_))),([2]8,([1]7,_,_),([1]9,_,_)))", - #| ) - #| set.add(10) - #| inspect(set, content="@sorted_set.from_array([1, 2, 3, 5, 6, 7, 8, 9, 10])") - #| inspect( - #| set.debug_tree(), - #| content="([4]6,([3]2,([1]1,_,_),([2]3,_,([1]5,_,_))),([3]8,([1]7,_,_),([2]9,_,([1]10,_,_))))", - #| ) - #| set.add(4) - #| inspect( - #| set, - #| content="@sorted_set.from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])", - #| ) - #| inspect( - #| set.debug_tree(), - #| content="([4]6,([3]2,([1]1,_,_),([2]4,([1]3,_,_),([1]5,_,_))),([3]8,([1]7,_,_),([2]9,_,([1]10,_,_))))", - #| ) - #| set.add(11) - #| inspect( - #| set, - #| content="@sorted_set.from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])", - #| ) - #| inspect( - #| set.debug_tree(), - #| content="([4]6,([3]2,([1]1,_,_),([2]4,([1]3,_,_),([1]5,_,_))),([3]8,([1]7,_,_),([2]10,([1]9,_,_),([1]11,_,_))))", - #| ) - #| set.remove(11) - #| inspect( - #| set, - #| content="@sorted_set.from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])", - #| ) - #| inspect( - #| set.debug_tree(), - #| content="([4]6,([3]2,([1]1,_,_),([2]4,([1]3,_,_),([1]5,_,_))),([3]8,([1]7,_,_),([2]10,([1]9,_,_),_)))", - #| ) - #| set.remove(12) - #| inspect( - #| set, - #| content="@sorted_set.from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])", - #| ) - #| set.add(10) - #| inspect( - #| set, - #| content="@sorted_set.from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])", - #| ) - #| set.remove(1) - #| inspect(set, content="@sorted_set.from_array([2, 3, 4, 5, 6, 7, 8, 9, 10])") - #| inspect( - #| set.debug_tree(), - #| content="([4]6,([3]4,([2]2,_,([1]3,_,_)),([1]5,_,_)),([3]8,([1]7,_,_),([2]10,([1]9,_,_),_)))", - #| ) - #| set.remove(2) - #| inspect(set, content="@sorted_set.from_array([3, 4, 5, 6, 7, 8, 9, 10])") - #| inspect( - #| set.debug_tree(), - #| content="([4]6,([2]4,([1]3,_,_),([1]5,_,_)),([3]8,([1]7,_,_),([2]10,([1]9,_,_),_)))", - #| ) - #| set.remove(3) - #| inspect(set, content="@sorted_set.from_array([4, 5, 6, 7, 8, 9, 10])") - #| inspect( - #| set.debug_tree(), - #| content="([4]6,([2]4,_,([1]5,_,_)),([3]8,([1]7,_,_),([2]10,([1]9,_,_),_)))", - #| ) - #| set.remove(4) - #| inspect(set, content="@sorted_set.from_array([5, 6, 7, 8, 9, 10])") - #| inspect( - #| set.debug_tree(), - #| content="([3]8,([2]6,([1]5,_,_),([1]7,_,_)),([2]10,([1]9,_,_),_))", - #| ) - #| set.remove(5) - #| inspect(set, content="@sorted_set.from_array([6, 7, 8, 9, 10])") - #| inspect( - #| set.debug_tree(), - #| content="([3]8,([2]6,_,([1]7,_,_)),([2]10,([1]9,_,_),_))", - #| ) - #| set.remove(6) - #| inspect(set, content="@sorted_set.from_array([7, 8, 9, 10])") - #| inspect(set.debug_tree(), content="([3]8,([1]7,_,_),([2]10,([1]9,_,_),_))") - #| set.remove(7) - #| inspect(set, content="@sorted_set.from_array([8, 9, 10])") - #| inspect(set.debug_tree(), content="([2]9,([1]8,_,_),([1]10,_,_))") - #| set.remove(8) - #| inspect(set, content="@sorted_set.from_array([9, 10])") - #| inspect(set.debug_tree(), content="([2]9,_,([1]10,_,_))") - #| set.remove(9) - #| inspect(set, content="@sorted_set.from_array([10])") - #| inspect(set.debug_tree(), content="([1]10,_,_)") - #| set.remove(10) - #| inspect(set, content="@sorted_set.from_array([])") - #| inspect(set.debug_tree(), content="_") - #| let set = from_array([7, 2, 9, 4, 5, 6, 3, 1]) - #| set.remove(3) - #| inspect(set, content="@sorted_set.from_array([1, 2, 4, 5, 6, 7, 9])") - #| inspect( - #| set.debug_tree(), - #| content="([3]5,([2]2,([1]1,_,_),([1]4,_,_)),([2]7,([1]6,_,_),([1]9,_,_)))", - #| ) - #| set.remove(2) - #| inspect(set, content="@sorted_set.from_array([1, 4, 5, 6, 7, 9])") - #| inspect( - #| set.debug_tree(), - #| content="([3]5,([2]4,([1]1,_,_),_),([2]7,([1]6,_,_),([1]9,_,_)))", - #| ) - #| set.remove(5) - #| inspect(set, content="@sorted_set.from_array([1, 4, 6, 7, 9])") - #| inspect( - #| set.debug_tree(), - #| content="([3]6,([2]4,([1]1,_,_),_),([2]7,_,([1]9,_,_)))", - #| ) - #| set.remove(9) - #| inspect(set, content="@sorted_set.from_array([1, 4, 6, 7])") - #| inspect(set.debug_tree(), content="([3]6,([2]4,([1]1,_,_),_),([1]7,_,_))") - #| set.remove(1) - #| inspect(set, content="@sorted_set.from_array([4, 6, 7])") - #| inspect(set.debug_tree(), content="([2]6,([1]4,_,_),([1]7,_,_))") - #| set.remove(7) - #| inspect(set, content="@sorted_set.from_array([4, 6])") - #| inspect(set.debug_tree(), content="([2]6,([1]4,_,_),_)") - #| set.remove(4) - #| inspect(set, content="@sorted_set.from_array([6])") - #| inspect(set.debug_tree(), content="([1]6,_,_)") - #| set.remove(6) - #| inspect(set, content="@sorted_set.from_array([])") - #| inspect(set.debug_tree(), content="_") - #|} - #|pub impl[K] Default for SortedSet[K] with default() { - #| new() - #|} - ), - "types.mbt": ( - #|#alias(T, deprecated) - #|struct SortedSet[V] { - #| mut root : Node[V]? - #| mut size : Int - #|} - #|priv struct Node[V] { - #| mut value : V - #| mut left : Node[V]? - #| mut right : Node[V]? - #| mut height : Int - #|} - ), - "utils.mbt": ( - #|impl[V : Eq] Eq for Node[V] with equal(self, other) { - #| self.value == other.value - #|} - #|fn max(x : Int, y : Int) -> Int { - #| if x > y { - #| x - #| } else { - #| y - #| } - #|} - #|fn[V] height(node : Node[V]?) -> Int { - #| match node { - #| None => 0 - #| Some(n) => n.height - #| } - #|} - #|fn[V : Show] Node::debug_node(self : Node[V]) -> String { - #| let l = match self.left { - #| Some(left) => left.debug_node() - #| None => "_" - #| } - #| let r = match self.right { - #| Some(right) => right.debug_node() - #| None => "_" - #| } - #| let value = self.value - #| let height = self.height - #| "([\{height}]\{value},\{l},\{r})" - #|} - #|fn[V : Show] SortedSet::debug_tree(self : SortedSet[V]) -> String { - #| match self.root { - #| Some(root) => root.debug_node() - #| None => "_" - #| } - #|} - ), - }, + "deprecated.mbt": "", + "set.mbt": ( + #|#as_free_fn + #|pub fn[V] SortedSet::new() -> SortedSet[V] { + #| { root: None, size: 0 } + #|} + #|#as_free_fn + #|pub fn[V] SortedSet::singleton(value : V) -> SortedSet[V] { + #| { root: Some({ value, left: None, right: None, height: 1 }), size: 1 } + #|} + #|#as_free_fn + #|#alias(of, deprecated="Use from_array instead") + #|#as_free_fn(of, deprecated="Use from_array instead") + #|pub fn[V : Compare] SortedSet::from_array(array : ArrayView[V]) -> SortedSet[V] { + #| let set = new() + #| for x in array { + #| set.add(x) + #| } + #| set + #|} + #|#alias(deep_clone, deprecated) + #|#alias(clone, deprecated) + #|pub fn[V] SortedSet::copy(self : SortedSet[V]) -> SortedSet[V] { + #| match self.root { + #| None => new() + #| Some(_) => { root: copy_tree(self.root), size: self.size } + #| } + #|} + #|fn[V] copy_tree(node : Node[V]?) -> Node[V]? { + #| match node { + #| None => None + #| Some(node) => { + #| let left = copy_tree(node.left) + #| let right = copy_tree(node.right) + #| let new_node = new_node(node.value, left~, right~, height=node.height) + #| Some(new_node) + #| } + #| } + #|} + #|fn[V] new_node( + #| value : V, + #| left? : Node[V]? = None, + #| right? : Node[V]? = None, + #| height? : Int = 1, + #|) -> Node[V] { + #| { value, left, right, height } + #|} + #|fn[V] new_node_update_height( + #| value : V, + #| left~ : Node[V]?, + #| right~ : Node[V]?, + #|) -> Node[V] { + #| { value, left, right, height: max(height(left), height(right)) + 1 } + #|} + #|pub fn[V : Compare] SortedSet::add(self : SortedSet[V], value : V) -> Unit { + #| let (new_root, inserted) = add_node(self.root, value) + #| if self.root != new_root { + #| self.root = new_root + #| } + #| if inserted { + #| self.size += 1 + #| } + #|} + #|pub fn[V : Compare] SortedSet::remove(self : SortedSet[V], value : V) -> Unit { + #| if self.root is Some(old_root) { + #| let (new_root, deleted) = delete_node(old_root, value) + #| if self.root != new_root { + #| self.root = new_root + #| } + #| if deleted { + #| self.size -= 1 + #| } + #| } + #|} + #|pub fn[V : Compare] SortedSet::contains(self : SortedSet[V], value : V) -> Bool { + #| loop (self.root, value) { + #| (None, _) => false + #| (Some(node), value) => { + #| let compare_result = value.compare(node.value) + #| if compare_result == 0 { + #| true + #| } else if compare_result < 0 { + #| continue (node.left, value) + #| } else { + #| continue (node.right, value) + #| } + #| } + #| } + #|} + #|pub fn[V : Compare] SortedSet::union( + #| self : SortedSet[V], + #| src : SortedSet[V], + #|) -> SortedSet[V] { + #| fn aux(a : Node[V]?, b : Node[V]?) -> Node[V]? { + #| match (a, b) { + #| (Some(_), None) => a + #| (None, Some(_)) => b + #| (Some({ value: va, left: la, right: ra, .. }), Some(_)) => { + #| let (l, r) = split(b, va) + #| Some(join(aux(la, l), va, aux(ra, r))) + #| } + #| (None, None) => None + #| } + #| } + #| match (self.root, src.root) { + #| (Some(_), Some(_)) => { + #| let t1 = copy_tree(self.root) + #| let t2 = copy_tree(src.root) + #| let t = aux(t1, t2) + #| let mut ct = 0 + #| let ret = { root: t, size: 0 } + #| ret.each(_x => ct = ct + 1) + #| ret.size = ct + #| ret + #| } + #| (Some(_), None) => { root: copy_tree(self.root), size: self.size } + #| (None, Some(_)) => { root: copy_tree(src.root), size: src.size } + #| (None, None) => new() + #| } + #|} + #|fn[V : Compare] split(root : Node[V]?, value : V) -> (Node[V]?, Node[V]?) { + #| match root { + #| None => (None, None) + #| Some(node) => { + #| let comp = value.compare(node.value) + #| if comp == 0 { + #| (node.left, node.right) + #| } else if comp < 0 { + #| let (l, r) = split(node.left, value) + #| (l, Some(join(r, node.value, node.right))) + #| } else { + #| let (l, r) = split(node.right, value) + #| (Some(join(node.left, node.value, l)), r) + #| } + #| } + #| } + #|} + #|fn[V] join(left : Node[V]?, value : V, right : Node[V]?) -> Node[V] { + #| let (hl, hr) = (height(left), height(right)) + #| if hl > hr + 1 { + #| join_right(left, value, right) + #| } else if hr > hl + 1 { + #| join_left(left, value, right) + #| } else { + #| new_node_update_height(value, left~, right~) + #| } + #|} + #|fn[V] join_left(l : Node[V]?, v : V, r : Node[V]?) -> Node[V] { + #| let { value: rv, left: rl, right: rr, .. } = r.unwrap() + #| let node = if height(rl) <= height(l) + 1 { + #| let new_l = new_node_update_height(left=l, v, right=rl) + #| if height(Some(new_l)) <= height(rr) + 1 { + #| new_node_update_height(left=Some(new_l), rv, right=rr) + #| } else { + #| let new_l = rotate_l(new_l) + #| let new = new_node_update_height(left=Some(new_l), rv, right=rr) + #| rotate_r(new) + #| } + #| } else { + #| let new_l = join_left(l, v, rl) + #| let new = new_node_update_height(left=Some(new_l), rv, right=rr) + #| if height(Some(new_l)) <= height(rr) + 1 { + #| new + #| } else { + #| rotate_r(new) + #| } + #| } + #| node.update_height() + #| node + #|} + #|fn[V] join_right(l : Node[V]?, v : V, r : Node[V]?) -> Node[V] { + #| let { value: lv, left: ll, right: lr, .. } = l.unwrap() + #| let node = if height(lr) <= height(r) + 1 { + #| let new_r = new_node_update_height(left=lr, v, right=r) + #| if height(Some(new_r)) <= height(ll) + 1 { + #| new_node_update_height(left=ll, lv, right=Some(new_r)) + #| } else { + #| let new_r = rotate_r(new_r) + #| let new = new_node_update_height(left=ll, lv, right=Some(new_r)) + #| rotate_l(new) + #| } + #| } else { + #| let new_r = join_right(lr, v, r) + #| let new = new_node_update_height(left=ll, lv, right=Some(new_r)) + #| if height(Some(new_r)) <= height(ll) + 1 { + #| new + #| } else { + #| rotate_l(new) + #| } + #| } + #| node.update_height() + #| node + #|} + #|#alias(diff, deprecated) + #|pub fn[V : Compare] SortedSet::difference( + #| self : SortedSet[V], + #| src : SortedSet[V], + #|) -> SortedSet[V] { + #| let ret = new() + #| self.each(x => if !src.contains(x) { ret.add(x) }) + #| ret + #|} + #|pub fn[V : Compare] SortedSet::symmetric_difference( + #| self : SortedSet[V], + #| other : SortedSet[V], + #|) -> SortedSet[V] { + #| let set1 = self.difference(other) + #| let set2 = other.difference(self) + #| set1.union(set2) + #|} + #|#alias(intersect, deprecated) + #|pub fn[V : Compare] SortedSet::intersection( + #| self : SortedSet[V], + #| src : SortedSet[V], + #|) -> SortedSet[V] { + #| let ret = new() + #| self.each(x => if src.contains(x) { ret.add(x) }) + #| ret + #|} + #|pub fn[V : Compare] SortedSet::subset( + #| self : SortedSet[V], + #| src : SortedSet[V], + #|) -> Bool { + #| self.iter().all(x => src.contains(x)) + #|} + #|pub fn[V : Compare] SortedSet::disjoint( + #| self : SortedSet[V], + #| src : SortedSet[V], + #|) -> Bool { + #| self.iter().all(x => !src.contains(x)) + #|} + #|pub impl[V : Eq] Eq for SortedSet[V] with equal(self, other) { + #| guard self.size == other.size else { return false } + #| let iter = self.iter() + #| let iter1 = other.iter() + #| while iter.next() is Some(a) && iter1.next() is Some(b) { + #| guard a == b else { break false } + #| } nobreak { + #| true + #| } + #|} + #|pub fn[V] SortedSet::is_empty(self : SortedSet[V]) -> Bool { + #| self.root is None + #|} + #|#alias(size, deprecated) + #|pub fn[V] SortedSet::length(self : SortedSet[V]) -> Int { + #| self.size + #|} + #|pub fn[V] SortedSet::each( + #| self : SortedSet[V], + #| f : (V) -> Unit raise?, + #|) -> Unit raise? { + #| fn dfs(root : Node[V]?) -> Unit raise? { + #| if root is Some(root) { + #| dfs(root.left) + #| f(root.value) + #| dfs(root.right) + #| } + #| } + #| dfs(self.root) + #|} + #|pub fn[V] SortedSet::eachi( + #| self : SortedSet[V], + #| f : (Int, V) -> Unit raise?, + #|) -> Unit raise? { + #| let mut i = 0 + #| self.each(v => { + #| f(i, v) + #| i = i + 1 + #| }) + #|} + #|pub fn[V] SortedSet::to_array(self : SortedSet[V]) -> Array[V] { + #| if self.size == 0 { + #| [] + #| } else { + #| let padding = self.root.unwrap().value + #| let arr = Array::make(self.size, padding) + #| let mut i = 0 + #| fn dfs(root : Node[V]?) -> Unit { + #| if root is Some(root) { + #| dfs(root.left) + #| arr[i] = root.value + #| i = i + 1 + #| dfs(root.right) + #| } + #| } + #| dfs(self.root) + #| arr + #| } + #|} + #|#alias(iterator, deprecated) + #|pub fn[V] SortedSet::iter(self : SortedSet[V]) -> Iter[V] { + #| let mut curr_node = self.root + #| let parents = [] + #| Iter::new(fn() { + #| loop curr_node { + #| Some({ left: None, value, right, height: _ }) => { + #| curr_node = right + #| Some(value) + #| } + #| Some({ left, value, right, height: _ }) => { + #| parents.push((value, right)) + #| continue left + #| } + #| None if parents.pop() is Some((value, right)) => { + #| curr_node = right + #| Some(value) + #| } + #| None => None + #| } + #| }) + #|} + #|#as_free_fn + #|#alias(from_iterator, deprecated) + #|#as_free_fn(from_iterator, deprecated) + #|pub fn[V : Compare] SortedSet::from_iter(iter : Iter[V]) -> SortedSet[V] { + #| let s = new() + #| while iter.next() is Some(e) { + #| s.add(e) + #| } + #| s + #|} + #|pub impl[V : Show] Show for SortedSet[V] with output(self, logger) { + #| logger.write_iter(self.iter(), prefix="@sorted_set.from_array([", suffix="])") + #|} + #|pub impl[X : @quickcheck.Arbitrary + Compare] @quickcheck.Arbitrary for SortedSet[ + #| X, + #|] with arbitrary(size, rs) { + #| @quickcheck.Arbitrary::arbitrary(size, rs) |> from_iter + #|} + #|impl[T : Show] Show for Node[T] with output(self, logger) { + #| let x = { root: Some(self), size: 0 } // Hack for test + #| logger.write_iter(x.iter()) + #|} + #|pub fn[V : Compare] SortedSet::range( + #| self : SortedSet[V], + #| low : V, + #| high : V, + #|) -> Iter[V] { + #| let mut curr_node = self.root + #| let parents = [] + #| let iter = Iter::new(() => { + #| loop curr_node { + #| Some({ value, left, right, height: _ }) => { + #| let cmp_key_low = value.compare(low) + #| let cmp_key_high = value.compare(high) + #| if cmp_key_low < 0 { + #| continue right + #| } else if cmp_key_high > 0 { + #| continue left + #| } else if left is None { + #| curr_node = right + #| Some(value) + #| } else { + #| parents.push((value, right)) + #| continue left + #| } + #| } + #| None if parents.pop() is Some((value, right)) => { + #| curr_node = right + #| Some(value) + #| } + #| None => None + #| } + #| }) + #| iter.iter() + #|} + #|fn[V] replace_root_with_min(root : Node[V], node : Node[V]) -> Node[V]? { + #| let (l, r) = (node.left, node.right) + #| match l { + #| None => { + #| root.value = node.value + #| r + #| } + #| Some(ln) => { + #| node.left = replace_root_with_min(root, ln) + #| Some(balance(node)) + #| } + #| } + #|} + #|fn[V] Node::update_height(self : Node[V]) -> Unit { + #| self.height = 1 + max(height(self.left), height(self.right)) + #|} + #|fn[V] height_ge(x1 : Node[V]?, x2 : Node[V]?) -> Bool { + #| match x2 { + #| None => true + #| Some(n2) => + #| match x1 { + #| None => false + #| Some(n1) => n1.height >= n2.height + #| } + #| } + #|} + #|fn[V] balance(root : Node[V]) -> Node[V] { + #| let (l, r) = (root.left, root.right) + #| let (hl, hr) = (height(l), height(r)) + #| let new_root = if hl > hr + 1 { + #| let { left: ll, right: lr, .. } = l.unwrap() + #| if height_ge(ll, lr) { + #| rotate_r(root) + #| } else { + #| rotate_lr(root) + #| } + #| } else if hr > hl + 1 { + #| let { left: rl, right: rr, .. } = r.unwrap() + #| if height_ge(rr, rl) { + #| rotate_l(root) + #| } else { + #| rotate_rl(root) + #| } + #| } else { + #| root + #| } + #| new_root.update_height() + #| new_root + #|} + #|fn[V] rotate_l(n : Node[V]) -> Node[V] { + #| let r = n.right.unwrap() + #| n.right = r.left + #| r.left = Some(n) + #| n.update_height() + #| r.update_height() + #| r + #|} + #|fn[V] rotate_r(n : Node[V]) -> Node[V] { + #| let l = n.left.unwrap() + #| n.left = l.right + #| l.right = Some(n) + #| n.update_height() + #| l.update_height() + #| l + #|} + #|fn[V] rotate_lr(n : Node[V]) -> Node[V] { + #| let l = n.left.unwrap() + #| let v = rotate_l(l) + #| n.left = Some(v) + #| rotate_r(n) + #|} + #|fn[V] rotate_rl(n : Node[V]) -> Node[V] { + #| let r = n.right.unwrap() + #| let v = rotate_r(r) + #| n.right = Some(v) + #| rotate_l(n) + #|} + #|fn[V : Compare] add_node(root : Node[V]?, value : V) -> (Node[V]?, Bool) { + #| match root { + #| None => (Some(new_node(value)), true) + #| Some(n) => { + #| let comp = value.compare(n.value) + #| if comp == 0 { + #| n.value = value + #| (Some(n), false) + #| } else { + #| let (l, r) = (n.left, n.right) + #| if comp < 0 { + #| let (nl, inserted) = add_node(l, value) + #| n.left = nl + #| (Some(balance(n)), inserted) + #| } else { + #| let (nr, inserted) = add_node(r, value) + #| n.right = nr + #| (Some(balance(n)), inserted) + #| } + #| } + #| } + #| } + #|} + #|fn[V : Compare] delete_node(root : Node[V], value : V) -> (Node[V]?, Bool) { + #| let comp = value.compare(root.value) + #| if comp == 0 { + #| let (l, r) = (root.left, root.right) + #| let n = match (l, r) { + #| (Some(_), Some(nr)) => { + #| root.right = replace_root_with_min(root, nr) + #| Some(balance(root)) + #| } + #| (None, Some(_)) => r + #| (Some(_), None) | (None, None) => l + #| } + #| (n, true) + #| } else if comp < 0 { + #| match root.left { + #| None => (Some(root), false) + #| Some(l) => { + #| let (nl, deleted) = delete_node(l, value) + #| root.left = nl + #| (Some(balance(root)), deleted) + #| } + #| } + #| } else { + #| match root.right { + #| None => (Some(root), false) + #| Some(r) => { + #| let (nr, deleted) = delete_node(r, value) + #| root.right = nr + #| (Some(balance(root)), deleted) + #| } + #| } + #| } + #|} + #|test "copy" { + #| let set = from_array([1, 2, 3, 4, 5]) + #| let copied_set = set.copy() + #| inspect(copied_set, content="@sorted_set.from_array([1, 2, 3, 4, 5])") + #| inspect(set.debug_tree() == copied_set.debug_tree(), content="true") + #| let set : SortedSet[Int] = from_array([]) + #| let copied_set = set.copy() + #| inspect(copied_set, content="@sorted_set.from_array([])") + #| inspect(set.debug_tree() == copied_set.debug_tree(), content="true") + #|} + #|test "union" { + #| let set1 = from_array([1, 2, 3]) + #| let set2 = from_array([4, 5, 6]) + #| let set3 = set1.union(set2) + #| inspect(set3, content="@sorted_set.from_array([1, 2, 3, 4, 5, 6])") + #| inspect( + #| set3.debug_tree(), + #| content="([3]3,([2]2,([1]1,_,_),_),([2]5,([1]4,_,_),([1]6,_,_)))", + #| ) + #| let set1 = from_array([1, 2, 3]) + #| let set2 = from_array([2, 3, 4]) + #| let set3 = set1.union(set2) + #| inspect(set3, content="@sorted_set.from_array([1, 2, 3, 4])") + #| inspect(set3.debug_tree(), content="([3]2,([1]1,_,_),([2]3,_,([1]4,_,_)))") + #| let set1 = from_array([1, 2, 3]) + #| let set2 = from_array([2, 3]) + #| let set3 = set1.union(set2) + #| inspect(set3, content="@sorted_set.from_array([1, 2, 3])") + #| inspect(set3.debug_tree(), content="([2]2,([1]1,_,_),([1]3,_,_))") + #| let set1 : SortedSet[Int] = new() + #| let set2 = new() + #| let set3 = set1.union(set2) + #| inspect(set3, content="@sorted_set.from_array([])") + #| inspect(set3.debug_tree(), content="_") + #| let set1 = from_array([1, 2, 3]) + #| let set2 = from_array([]) + #| let set3 = set1.union(set2) + #| inspect(set3, content="@sorted_set.from_array([1, 2, 3])") + #| inspect(set3.debug_tree(), content="([2]2,([1]1,_,_),([1]3,_,_))") + #| let set1 = from_array([]) + #| let set2 = from_array([1, 2, 3]) + #| let set3 = set1.union(set2) + #| inspect(set3, content="@sorted_set.from_array([1, 2, 3])") + #| inspect(set3.debug_tree(), content="([2]2,([1]1,_,_),([1]3,_,_))") + #| let set1 = from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) + #| let set2 = from_array([11, 12, 13, 14, 15, 16, 17, 18, 19, 20]) + #| let set3 = set1.union(set2) + #| inspect( + #| set3, + #| content="@sorted_set.from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20])", + #| ) + #| inspect( + #| set3.debug_tree(), + #| content="([5]14,([4]8,([3]4,([2]2,([1]1,_,_),([1]3,_,_)),([2]6,([1]5,_,_),([1]7,_,_))),([3]12,([2]10,([1]9,_,_),([1]11,_,_)),([1]13,_,_))),([3]18,([2]16,([1]15,_,_),([1]17,_,_)),([2]19,_,([1]20,_,_))))", + #| ) + #| let set1 = from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) + #| let set2 = from_array([6, 7, 8, 9, 10, 11, 12, 13, 14, 15]) + #| let set3 = set1.union(set2) + #| inspect( + #| set3, + #| content="@sorted_set.from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])", + #| ) + #| inspect( + #| set3.debug_tree(), + #| content="([5]11,([4]4,([2]2,([1]1,_,_),([1]3,_,_)),([3]8,([2]6,([1]5,_,_),([1]7,_,_)),([2]9,_,([1]10,_,_)))),([3]13,([1]12,_,_),([2]14,_,([1]15,_,_))))", + #| ) + #| let set1 = from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) + #| let set2 = from_array([6, 7, 8, 9, 10]) + #| let set3 = set1.union(set2) + #| inspect( + #| set3, + #| content="@sorted_set.from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])", + #| ) + #| inspect( + #| set3.debug_tree(), + #| content="([4]4,([2]2,([1]1,_,_),([1]3,_,_)),([3]8,([2]6,([1]5,_,_),([1]7,_,_)),([2]9,_,([1]10,_,_))))", + #| ) + #|} + #|test "split" { + #| let (l, r) = split(from_array([7, 2, 9, 4, 5, 6, 3, 8, 1]).root, 5) + #| inspect(l, content="Some([1, 2, 3, 4])") + #| inspect(r, content="Some([6, 7, 8, 9])") + #| let (l, r) = split(from_array([7, 2, 9, 4, 5, 6, 3, 8, 1]).root, 0) + #| inspect(l, content="None") + #| inspect(r, content="Some([1, 2, 3, 4, 5, 6, 7, 8, 9])") + #| let (l, r) = split(from_array([7, 2, 9, 4, 5, 6, 3, 8, 1]).root, 10) + #| inspect(l, content="Some([1, 2, 3, 4, 5, 6, 7, 8, 9])") + #| inspect(r, content="None") + #| let (l, r) = split(from_array([7, 2, 9, 4, 5, 6, 3, 8, 1]).root, 4) + #| inspect(l, content="Some([1, 2, 3])") + #| inspect(r, content="Some([5, 6, 7, 8, 9])") + #| let (l, r) = split(from_array([]).root, 7) + #| inspect(l, content="None") + #| inspect(r, content="None") + #| let (l, r) = split( + #| from_array([ + #| 0, 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, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + #| 98, 99, 100, + #| ]).root, + #| 50, + #| ) + #| inspect( + #| l, + #| content="Some([0, 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])", + #| ) + #| inspect( + #| r, + #| content="Some([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, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100])", + #| ) + #|} + #|test "join" { + #| let l = from_array([13, 8, 17, 1, 11, 15, 25, 6]) + #| let r = from_array([27, 28, 40, 35, 33]) + #| inspect( + #| join(l.root, 26, r.root), + #| content="[1, 6, 8, 11, 13, 15, 17, 25, 26, 27, 28, 33, 35, 40]", + #| ) + #| let l = from_array([3, 2, 5, 1, 4]) + #| let r = from_array([7]) + #| inspect(join(l.root, 6, r.root), content="[1, 2, 3, 4, 5, 6, 7]") + #| let l = from_array([3, 2, 5, 1, 4]) + #| let r = from_array([]) + #| inspect(join(l.root, 6, r.root), content="[1, 2, 3, 4, 5, 6]") + #| let l = from_array([]) + #| let r = from_array([]) + #| inspect(join(l.root, 6, r.root), content="[6]") + #| let l = from_array([]) + #| let r = from_array([7, 8, 9, 10, 11, 12]) + #| inspect(join(l.root, 6, r.root), content="[6, 7, 8, 9, 10, 11, 12]") + #|} + #|test "add to empty set" { + #| let set = new() + #| set.add(1) + #| assert_eq(set.contains(1), true) + #| inspect(set.debug_tree(), content="([1]1,_,_)") + #|} + #|test "add to non-empty set" { + #| let set = new() + #| set.add(1) + #| set.add(2) + #| assert_eq(set.contains(1), true) + #| assert_eq(set.contains(2), true) + #| inspect(set.debug_tree(), content="([2]1,_,([1]2,_,_))") + #|} + #|test "add duplicate value" { + #| let set = new() + #| set.add(1) + #| set.add(1) + #| assert_eq(set.contains(1), true) + #| assert_eq(set.length(), 1) + #| inspect(set.debug_tree(), content="([1]1,_,_)") + #|} + #|test "add multiple values" { + #| let set = new() + #| set.add(1) + #| set.add(2) + #| set.add(3) + #| assert_eq(set.contains(1), true) + #| assert_eq(set.contains(2), true) + #| assert_eq(set.contains(3), true) + #| assert_eq(set.length(), 3) + #| inspect(set.debug_tree(), content="([2]2,([1]1,_,_),([1]3,_,_))") + #|} + #|test "add_and_remove" { + #| let set = from_array([7, 2, 9, 4, 5, 6, 3, 8, 1]) + #| set.remove(8) + #| inspect(set, content="@sorted_set.from_array([1, 2, 3, 4, 5, 6, 7, 9])") + #| inspect( + #| set.debug_tree(), + #| content="([4]5,([3]3,([2]2,([1]1,_,_),_),([1]4,_,_)),([2]7,([1]6,_,_),([1]9,_,_)))", + #| ) + #| let set = from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) + #| set.remove(1) + #| inspect(set, content="@sorted_set.from_array([2, 3, 4, 5, 6, 7, 8, 9, 10])") + #| inspect( + #| set.debug_tree(), + #| content="([4]4,([2]2,_,([1]3,_,_)),([3]8,([2]6,([1]5,_,_),([1]7,_,_)),([2]9,_,([1]10,_,_))))", + #| ) + #| set.remove(5) + #| inspect(set, content="@sorted_set.from_array([2, 3, 4, 6, 7, 8, 9, 10])") + #| inspect( + #| set.debug_tree(), + #| content="([4]4,([2]2,_,([1]3,_,_)),([3]8,([2]6,_,([1]7,_,_)),([2]9,_,([1]10,_,_))))", + #| ) + #| set.remove(10) + #| inspect(set, content="@sorted_set.from_array([2, 3, 4, 6, 7, 8, 9])") + #| inspect( + #| set.debug_tree(), + #| content="([4]4,([2]2,_,([1]3,_,_)),([3]8,([2]6,_,([1]7,_,_)),([1]9,_,_)))", + #| ) + #| set.remove(4) + #| inspect(set, content="@sorted_set.from_array([2, 3, 6, 7, 8, 9])") + #| inspect( + #| set.debug_tree(), + #| content="([3]6,([2]2,_,([1]3,_,_)),([2]8,([1]7,_,_),([1]9,_,_)))", + #| ) + #| set.add(1) + #| inspect(set, content="@sorted_set.from_array([1, 2, 3, 6, 7, 8, 9])") + #| inspect( + #| set.debug_tree(), + #| content="([3]6,([2]2,([1]1,_,_),([1]3,_,_)),([2]8,([1]7,_,_),([1]9,_,_)))", + #| ) + #| set.add(5) + #| inspect(set, content="@sorted_set.from_array([1, 2, 3, 5, 6, 7, 8, 9])") + #| inspect( + #| set.debug_tree(), + #| content="([4]6,([3]2,([1]1,_,_),([2]3,_,([1]5,_,_))),([2]8,([1]7,_,_),([1]9,_,_)))", + #| ) + #| set.add(10) + #| inspect(set, content="@sorted_set.from_array([1, 2, 3, 5, 6, 7, 8, 9, 10])") + #| inspect( + #| set.debug_tree(), + #| content="([4]6,([3]2,([1]1,_,_),([2]3,_,([1]5,_,_))),([3]8,([1]7,_,_),([2]9,_,([1]10,_,_))))", + #| ) + #| set.add(4) + #| inspect( + #| set, + #| content="@sorted_set.from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])", + #| ) + #| inspect( + #| set.debug_tree(), + #| content="([4]6,([3]2,([1]1,_,_),([2]4,([1]3,_,_),([1]5,_,_))),([3]8,([1]7,_,_),([2]9,_,([1]10,_,_))))", + #| ) + #| set.add(11) + #| inspect( + #| set, + #| content="@sorted_set.from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])", + #| ) + #| inspect( + #| set.debug_tree(), + #| content="([4]6,([3]2,([1]1,_,_),([2]4,([1]3,_,_),([1]5,_,_))),([3]8,([1]7,_,_),([2]10,([1]9,_,_),([1]11,_,_))))", + #| ) + #| set.remove(11) + #| inspect( + #| set, + #| content="@sorted_set.from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])", + #| ) + #| inspect( + #| set.debug_tree(), + #| content="([4]6,([3]2,([1]1,_,_),([2]4,([1]3,_,_),([1]5,_,_))),([3]8,([1]7,_,_),([2]10,([1]9,_,_),_)))", + #| ) + #| set.remove(12) + #| inspect( + #| set, + #| content="@sorted_set.from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])", + #| ) + #| set.add(10) + #| inspect( + #| set, + #| content="@sorted_set.from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])", + #| ) + #| set.remove(1) + #| inspect(set, content="@sorted_set.from_array([2, 3, 4, 5, 6, 7, 8, 9, 10])") + #| inspect( + #| set.debug_tree(), + #| content="([4]6,([3]4,([2]2,_,([1]3,_,_)),([1]5,_,_)),([3]8,([1]7,_,_),([2]10,([1]9,_,_),_)))", + #| ) + #| set.remove(2) + #| inspect(set, content="@sorted_set.from_array([3, 4, 5, 6, 7, 8, 9, 10])") + #| inspect( + #| set.debug_tree(), + #| content="([4]6,([2]4,([1]3,_,_),([1]5,_,_)),([3]8,([1]7,_,_),([2]10,([1]9,_,_),_)))", + #| ) + #| set.remove(3) + #| inspect(set, content="@sorted_set.from_array([4, 5, 6, 7, 8, 9, 10])") + #| inspect( + #| set.debug_tree(), + #| content="([4]6,([2]4,_,([1]5,_,_)),([3]8,([1]7,_,_),([2]10,([1]9,_,_),_)))", + #| ) + #| set.remove(4) + #| inspect(set, content="@sorted_set.from_array([5, 6, 7, 8, 9, 10])") + #| inspect( + #| set.debug_tree(), + #| content="([3]8,([2]6,([1]5,_,_),([1]7,_,_)),([2]10,([1]9,_,_),_))", + #| ) + #| set.remove(5) + #| inspect(set, content="@sorted_set.from_array([6, 7, 8, 9, 10])") + #| inspect( + #| set.debug_tree(), + #| content="([3]8,([2]6,_,([1]7,_,_)),([2]10,([1]9,_,_),_))", + #| ) + #| set.remove(6) + #| inspect(set, content="@sorted_set.from_array([7, 8, 9, 10])") + #| inspect(set.debug_tree(), content="([3]8,([1]7,_,_),([2]10,([1]9,_,_),_))") + #| set.remove(7) + #| inspect(set, content="@sorted_set.from_array([8, 9, 10])") + #| inspect(set.debug_tree(), content="([2]9,([1]8,_,_),([1]10,_,_))") + #| set.remove(8) + #| inspect(set, content="@sorted_set.from_array([9, 10])") + #| inspect(set.debug_tree(), content="([2]9,_,([1]10,_,_))") + #| set.remove(9) + #| inspect(set, content="@sorted_set.from_array([10])") + #| inspect(set.debug_tree(), content="([1]10,_,_)") + #| set.remove(10) + #| inspect(set, content="@sorted_set.from_array([])") + #| inspect(set.debug_tree(), content="_") + #| let set = from_array([7, 2, 9, 4, 5, 6, 3, 1]) + #| set.remove(3) + #| inspect(set, content="@sorted_set.from_array([1, 2, 4, 5, 6, 7, 9])") + #| inspect( + #| set.debug_tree(), + #| content="([3]5,([2]2,([1]1,_,_),([1]4,_,_)),([2]7,([1]6,_,_),([1]9,_,_)))", + #| ) + #| set.remove(2) + #| inspect(set, content="@sorted_set.from_array([1, 4, 5, 6, 7, 9])") + #| inspect( + #| set.debug_tree(), + #| content="([3]5,([2]4,([1]1,_,_),_),([2]7,([1]6,_,_),([1]9,_,_)))", + #| ) + #| set.remove(5) + #| inspect(set, content="@sorted_set.from_array([1, 4, 6, 7, 9])") + #| inspect( + #| set.debug_tree(), + #| content="([3]6,([2]4,([1]1,_,_),_),([2]7,_,([1]9,_,_)))", + #| ) + #| set.remove(9) + #| inspect(set, content="@sorted_set.from_array([1, 4, 6, 7])") + #| inspect(set.debug_tree(), content="([3]6,([2]4,([1]1,_,_),_),([1]7,_,_))") + #| set.remove(1) + #| inspect(set, content="@sorted_set.from_array([4, 6, 7])") + #| inspect(set.debug_tree(), content="([2]6,([1]4,_,_),([1]7,_,_))") + #| set.remove(7) + #| inspect(set, content="@sorted_set.from_array([4, 6])") + #| inspect(set.debug_tree(), content="([2]6,([1]4,_,_),_)") + #| set.remove(4) + #| inspect(set, content="@sorted_set.from_array([6])") + #| inspect(set.debug_tree(), content="([1]6,_,_)") + #| set.remove(6) + #| inspect(set, content="@sorted_set.from_array([])") + #| inspect(set.debug_tree(), content="_") + #|} + #|pub impl[K] Default for SortedSet[K] with default() { + #| new() + #|} + ), + "types.mbt": ( + #|#alias(T, deprecated) + #|struct SortedSet[V] { + #| mut root : Node[V]? + #| mut size : Int + #|} + #|priv struct Node[V] { + #| mut value : V + #| mut left : Node[V]? + #| mut right : Node[V]? + #| mut height : Int + #|} + ), + "utils.mbt": ( + #|impl[V : Eq] Eq for Node[V] with equal(self, other) { + #| self.value == other.value + #|} + #|fn max(x : Int, y : Int) -> Int { + #| if x > y { + #| x + #| } else { + #| y + #| } + #|} + #|fn[V] height(node : Node[V]?) -> Int { + #| match node { + #| None => 0 + #| Some(n) => n.height + #| } + #|} + #|fn[V : Show] Node::debug_node(self : Node[V]) -> String { + #| let l = match self.left { + #| Some(left) => left.debug_node() + #| None => "_" + #| } + #| let r = match self.right { + #| Some(right) => right.debug_node() + #| None => "_" + #| } + #| let value = self.value + #| let height = self.height + #| "([\{height}]\{value},\{l},\{r})" + #|} + #|fn[V : Show] SortedSet::debug_tree(self : SortedSet[V]) -> String { + #| match self.root { + #| Some(root) => root.debug_node() + #| None => "_" + #| } + #|} + ) + } ) ///| let moonbitlang_core_strconv_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/strconv", - deps={ - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/double": moonbitlang_core_double_module, - "moonbitlang/core/uint64": moonbitlang_core_uint64_module, - "moonbitlang/core/string": moonbitlang_core_string_module, - "moonbitlang/core/char": moonbitlang_core_char_module, - "moonbitlang/core/array": moonbitlang_core_array_module, - }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| "moonbitlang/core/builtin", - #| "moonbitlang/core/double", - #| "moonbitlang/core/uint64", - #| "moonbitlang/core/string", - #| "moonbitlang/core/char", - #| "moonbitlang/core/array" - #| ] - #|} - ), - "bool.mbt": ( - #|pub fn parse_bool(str : StringView) -> Bool raise StrConvError { - #| match str { - #| "1" | "t" | "T" | "true" | "TRUE" | "True" => true - #| "0" | "f" | "F" | "false" | "FALSE" | "False" => false - #| _ => syntax_err() - #| } - #|} - #|test "parse_bool" { - #| let tests : Array[(String, Result[Bool, String])] = [ - #| ("", Err(syntax_err_str)), - #| ("zutomayo", Err(syntax_err_str)), - #| ("0", Ok(false)), - #| ("f", Ok(false)), - #| ("F", Ok(false)), - #| ("FALSE", Ok(false)), - #| ("false", Ok(false)), - #| ("False", Ok(false)), - #| ("1", Ok(true)), - #| ("t", Ok(true)), - #| ("T", Ok(true)), - #| ("TRUE", Ok(true)), - #| ("true", Ok(true)), - #| ("True", Ok(true)), - #| ] - #| for i in 0.. Err(err) - #| }, - #| t.1, - #| ) - #| } - #|} - ), - "decimal.mbt": ( - #|let max_shift = 59 - #|let powtab : ReadOnlyArray[Int] = [ - #| 1, 3, 6, 9, 13, 16, 19, 23, 26, 29, 33, 36, 39, 43, 46, 49, 53, 56, 59, - #|] - #|fn Decimal::new_priv() -> Decimal { - #| { - #| digits: FixedArray::make(800, Byte::default()), - #| digits_num: 0, - #| decimal_point: 0, - #| negative: false, - #| truncated: false, - #| } - #|} - #|fn Decimal::from_int64_priv(v : Int64) -> Decimal { - #| let d = Decimal::new_priv() - #| d.assign(v) - #| d - #|} - #|fn parse_decimal_priv(str : StringView) -> Decimal raise StrConvError { - #| parse_decimal_from_view(str) - #|} - #|fn parse_decimal_from_view(str : StringView) -> Decimal raise StrConvError { - #| let d = Decimal::new_priv() - #| let mut has_dp = false - #| let mut has_digits = false - #| let rest = match str { - #| ['-', .. rest] => { - #| d.negative = true - #| rest - #| } - #| ['+', .. rest] => rest - #| _ => str - #| } - #| let rest = loop rest { - #| ['_', .. rest] => continue rest - #| ['.', .. rest] => { - #| guard !has_dp else { syntax_err() } - #| has_dp = true - #| d.decimal_point = d.digits_num - #| continue rest - #| } - #| ['0'..='9' as digit, .. rest] => { - #| has_digits = true - #| if digit == '0' && d.digits_num == 0 { - #| d.decimal_point -= 1 - #| continue rest - #| } - #| if d.digits_num < d.digits.length() { - #| d.digits[d.digits_num] = (digit.to_int() - '0').to_byte() - #| d.digits_num += 1 - #| } else if digit != '0' { - #| d.truncated = true - #| } - #| continue rest - #| } - #| rest => rest - #| } - #| guard has_digits else { syntax_err() } - #| if !has_dp { - #| d.decimal_point = d.digits_num - #| } - #| let rest = match rest { - #| ['e' | 'E', .. rest] => { - #| let mut exp_sign = 1 - #| let rest = match rest { - #| ['+', .. rest] => rest - #| ['-', .. rest] => { - #| exp_sign = -1 - #| rest - #| } - #| rest => rest - #| } - #| guard rest is ['0'..='9', ..] else { syntax_err() } - #| let mut exp = 0 - #| let rest = loop rest { - #| ['_', .. rest] => continue rest - #| ['0'..='9' as digit, .. rest] => { - #| exp = exp * 10 + (digit.to_int() - '0') - #| continue rest - #| } - #| rest => rest - #| } - #| d.decimal_point += exp_sign * exp - #| rest - #| } - #| rest => rest - #| } - #| guard rest is [] else { syntax_err() } - #| d.trim() - #| d - #|} - #|fn Decimal::to_double_priv(self : Decimal) -> Double raise StrConvError { - #| let mut exponent = 0 - #| let mut mantissa = 0L - #| if self.digits_num == 0 || self.decimal_point < -330 { - #| mantissa = 0 - #| exponent = double_info.bias - #| let bits = assemble_bits(mantissa, exponent, self.negative) - #| return bits.reinterpret_as_double() - #| } - #| if self.decimal_point > 310 { - #| range_err() - #| } - #| while self.decimal_point > 0 { - #| let mut n = 0 - #| if self.decimal_point >= powtab.length() { - #| n = 60 - #| } else { - #| n = powtab[self.decimal_point] - #| } - #| self.shift_priv(-n) - #| exponent += n - #| } - #| while self.decimal_point < 0 || - #| (self.decimal_point == 0 && self.digits[0].to_int() < 5) { - #| let mut n = 0 - #| if -self.decimal_point >= powtab.length() { - #| n = 60 - #| } else { - #| n = powtab[-self.decimal_point] - #| } - #| self.shift_priv(n) - #| exponent -= n - #| } - #| exponent -= 1 - #| if exponent < double_info.bias + 1 { - #| let n = double_info.bias + 1 - exponent - #| self.shift_priv(-n) - #| exponent += n - #| } - #| if exponent - double_info.bias >= (1 << double_info.exponent_bits) - 1 { - #| range_err() - #| } - #| self.shift_priv(double_info.mantissa_bits + 1) - #| mantissa = self.rounded_integer() - #| if mantissa == 2L << double_info.mantissa_bits { - #| mantissa = mantissa >> 1 - #| exponent += 1 - #| if exponent - double_info.bias >= (1 << double_info.exponent_bits) - 1 { - #| range_err() - #| } - #| } - #| if (mantissa & (1L << double_info.mantissa_bits)) == 0L { - #| exponent = double_info.bias - #| } - #| let bits = assemble_bits(mantissa, exponent, self.negative) - #| bits.reinterpret_as_double() - #|} - #|fn Decimal::shift_priv(self : Decimal, s : Int) -> Unit { - #| if self.digits_num == 0 { - #| return - #| } - #| let mut s = s - #| if s > 0 { - #| while s > max_shift { - #| self.left_shift(max_shift) - #| s -= max_shift - #| } - #| self.left_shift(s) - #| } - #| if s < 0 { - #| while s < -max_shift { - #| self.right_shift(max_shift) - #| s += max_shift - #| } - #| self.right_shift(-s) - #| } - #|} - #|fn assemble_bits(mantissa : Int64, exponent : Int, negative : Bool) -> Int64 { - #| let biased_exp = exponent - double_info.bias - #| let mut bits = mantissa & ((1L << double_info.mantissa_bits) - 1L) - #| let exp_bits = (biased_exp & ((1 << double_info.exponent_bits) - 1)).to_int64() - #| bits = bits | (exp_bits << double_info.mantissa_bits) - #| if negative { - #| bits = bits | (1L << double_info.mantissa_bits << double_info.exponent_bits) - #| } - #| bits - #|} - #|fn Decimal::rounded_integer(self : Decimal) -> Int64 { - #| if self.decimal_point > 20 { - #| return 0xFFFFFFFFFFFFFFFFL - #| } - #| let mut n = 0L - #| let mut i = 0 - #| while i < self.decimal_point && i < self.digits_num { - #| n = n * 10L + self.digits[i].to_int64() - #| i += 1 - #| } - #| while i < self.decimal_point { - #| n *= 10L - #| i += 1 - #| } - #| if self.should_round_up(self.decimal_point) { - #| n += 1L - #| } - #| n - #|} - #|fn Decimal::should_round_up(self : Decimal, d : Int) -> Bool { - #| if d < 0 || d >= self.digits_num { - #| return false - #| } - #| if self.digits[d].to_int() == 5 && d + 1 == self.digits_num { - #| if self.truncated { - #| return true - #| } - #| return d > 0 && self.digits[d - 1].to_int() % 2 != 0 - #| } - #| self.digits[d].to_int() >= 5 - #|} - #|fn Decimal::assign(self : Decimal, v : Int64) -> Unit { - #| let buf = FixedArray::make(24, Byte::default()) - #| let mut n = 0 - #| let mut v = v - #| while v > 0 { - #| let v1 = v / 10 - #| buf[n] = (v - v1 * 10).to_byte() - #| n += 1 - #| v = v1 - #| } - #| self.digits_num = 0 - #| for i = n - 1; i >= 0; i = i - 1 { - #| self.digits[self.digits_num] = buf[i] - #| self.digits_num += 1 - #| } - #| self.decimal_point = self.digits_num - #| self.trim() - #|} - #|fn Decimal::right_shift(self : Decimal, s : Int) -> Unit { - #| let mut read_index = 0 - #| let mut write_index = 0 - #| let mut acc = 0UL - #| while acc >> s == 0 { - #| if read_index >= self.digits_num { - #| while acc >> s == 0 { - #| acc *= 10 - #| read_index += 1 - #| } - #| break - #| } - #| let d = self.digits[read_index] - #| acc = acc * 10 + d.to_int64().reinterpret_as_uint64() - #| read_index += 1 - #| } - #| self.decimal_point -= read_index - 1 - #| let mask = (1UL << s) - 1 - #| while read_index < self.digits_num { - #| let out = acc >> s - #| self.digits[write_index] = out.to_byte() - #| write_index += 1 - #| acc = acc & mask - #| let d = self.digits[read_index] - #| acc = acc * 10 + d.to_int64().reinterpret_as_uint64() - #| read_index += 1 - #| } - #| while acc > 0 { - #| let out = acc >> s - #| if write_index < self.digits.length() { - #| self.digits[write_index] = out.to_byte() - #| write_index += 1 - #| } else if out > 0 { - #| self.truncated = true - #| } - #| acc = acc & mask - #| acc = acc * 10 - #| } - #| self.digits_num = write_index - #| self.trim() - #|} - #|let left_shift_cheats : ReadOnlyArray[(Int, String)] = [ - #| (0, ""), - #| (1, "5"), // * 2 - #| (1, "25"), // * 4 - #| (1, "125"), // * 8 - #| (2, "625"), // * 16 - #| (2, "3125"), // * 32 - #| (2, "15625"), // * 64 - #| (3, "78125"), // * 128 - #| (3, "390625"), // * 256 - #| (3, "1953125"), // * 512 - #| (4, "9765625"), // * 1024 - #| (4, "48828125"), // * 2048 - #| (4, "244140625"), // * 4096 - #| (4, "1220703125"), // * 8192 - #| (5, "6103515625"), // * 16384 - #| (5, "30517578125"), // * 32768 - #| (5, "152587890625"), // * 65536 - #| (6, "762939453125"), // * 131072 - #| (6, "3814697265625"), // * 262144 - #| (6, "19073486328125"), // * 524288 - #| (7, "95367431640625"), // * 1048576 - #| (7, "476837158203125"), // * 2097152 - #| (7, "2384185791015625"), // * 4194304 - #| (7, "11920928955078125"), // * 8388608 - #| (8, "59604644775390625"), // * 16777216 - #| (8, "298023223876953125"), // * 33554432 - #| (8, "1490116119384765625"), // * 67108864 - #| (9, "7450580596923828125"), // * 134217728 - #| (9, "37252902984619140625"), // * 268435456 - #| (9, "186264514923095703125"), // * 536870912 - #| (10, "931322574615478515625"), // * 1073741824 - #| (10, "4656612873077392578125"), // * 2147483648 - #| (10, "23283064365386962890625"), // * 4294967296 - #| (10, "116415321826934814453125"), // * 8589934592 - #| (11, "582076609134674072265625"), // * 17179869184 - #| (11, "2910383045673370361328125"), // * 34359738368 - #| (11, "14551915228366851806640625"), // * 68719476736 - #| (12, "72759576141834259033203125"), // * 137438953472 - #| (12, "363797880709171295166015625"), // * 274877906944 - #| (12, "1818989403545856475830078125"), // * 549755813888 - #| (13, "9094947017729282379150390625"), // * 1099511627776 - #| (13, "45474735088646411895751953125"), // * 2199023255552 - #| (13, "227373675443232059478759765625"), // * 4398046511104 - #| (13, "1136868377216160297393798828125"), // * 8796093022208 - #| (14, "5684341886080801486968994140625"), // * 17592186044416 - #| (14, "28421709430404007434844970703125"), // * 35184372088832 - #| (14, "142108547152020037174224853515625"), // * 70368744177664 - #| (15, "710542735760100185871124267578125"), // * 140737488355328 - #| (15, "3552713678800500929355621337890625"), // * 281474976710656 - #| (15, "17763568394002504646778106689453125"), // * 562949953421312 - #| (16, "88817841970012523233890533447265625"), // * 1125899906842624 - #| (16, "444089209850062616169452667236328125"), // * 2251799813685248 - #| (16, "2220446049250313080847263336181640625"), // * 4503599627370496 - #| (16, "11102230246251565404236316680908203125"), // * 9007199254740992 - #| (17, "55511151231257827021181583404541015625"), // * 18014398509481984 - #| (17, "277555756156289135105907917022705078125"), // * 36028797018963968 - #| (17, "1387778780781445675529539585113525390625"), // * 72057594037927936 - #| (18, "6938893903907228377647697925567626953125"), // * 144115188075855872 - #| (18, "34694469519536141888238489627838134765625"), // * 288230376151711744 - #| (18, "173472347597680709441192448139190673828125"), // * 576460752303423488 - #| (19, "867361737988403547205962240695953369140625"), // * 1152921504606846976 - #|] - #|fn Decimal::new_digits(self : Decimal, s : Int) -> Int { - #| let new_digits = left_shift_cheats[s].0 - #| let cheat_num = left_shift_cheats[s].1 - #| let mut less = false - #| for i in 0..= self.digits_num { - #| less = true - #| break - #| } - #| let d = cheat_num.unsafe_charcode_at(i) - '0' - #| if self.digits[i].to_int() != d { - #| less = self.digits[i].to_int() < d - #| break - #| } - #| } - #| if less { - #| new_digits - 1 - #| } else { - #| new_digits - #| } - #|} - #|fn Decimal::left_shift(self : Decimal, s : Int) -> Unit { - #| let new_digits = self.new_digits(s) - #| let mut read_index = self.digits_num - #| let mut write_index = self.digits_num + new_digits - #| let mut acc = 0L - #| read_index -= 1 - #| while read_index >= 0 { - #| let d = self.digits[read_index].to_int64() - #| acc += d << s - #| let quo = acc / 10L - #| let rem = (acc - quo * 10L).to_int() - #| write_index -= 1 - #| if write_index < self.digits.length() { - #| self.digits[write_index] = rem.to_byte() - #| } else if rem != 0 { - #| self.truncated = true - #| } - #| acc = quo - #| read_index -= 1 - #| } - #| while acc > 0L { - #| let quo = acc / 10L - #| let rem = (acc - 10L * quo).to_int() - #| write_index -= 1 - #| if write_index < self.digits.length() { - #| self.digits[write_index] = rem.to_byte() - #| } else if rem != 0 { - #| self.truncated = true - #| } - #| acc = quo - #| } - #| self.digits_num += new_digits - #| if self.digits_num > self.digits.length() { - #| self.digits_num = self.digits.length() - #| } - #| self.decimal_point += new_digits - #| self.trim() - #|} - #|fn Decimal::trim(self : Decimal) -> Unit { - #| while self.digits_num > 0 && self.digits[self.digits_num - 1] == 0 { - #| self.digits_num -= 1 - #| } - #| if self.digits_num == 0 { - #| self.decimal_point = 0 - #| } - #|} - #|pub impl Show for Decimal with output(self, logger) { - #| if self.digits_num == 0 { - #| logger.write_char('0') - #| return - #| } - #| if self.decimal_point <= 0 { - #| logger.write_string("0.") - #| for i in 0..<-self.decimal_point { - #| logger.write_char('0') - #| } - #| for i in 0.. String { - #| Show::to_string(self) - #|} - #|test "new" { - #| let hpd = Decimal::from_int64_priv(1L) - #| inspect(hpd.digits.length(), content="800") - #| inspect(hpd.digits_num, content="1") - #| inspect(hpd.decimal_point, content="1") - #| inspect(hpd.negative, content="false") - #| inspect(hpd.truncated, content="false") - #|} - #|test "from_int64" { - #| let hpd = Decimal::from_int64_priv(123456789L) - #| inspect(hpd.to_string(), content="123456789") - #|} - #|test "parse_decimal" { - #| let s = "0.0000000000000000000000000000007888609052210118054117285652827862296732064351090230047702789306640625" - #| assert_eq(parse_decimal_priv(s).to_string(), s) - #| assert_eq(parse_decimal_priv("1.0e-10").to_string(), "0.0000000001") - #|} - #|test "to_string" { - #| let hpd = Decimal::from_int64_priv(123456789L) - #| hpd.decimal_point = 1 - #| inspect(hpd.to_string(), content="1.23456789") - #| hpd.decimal_point = 0 - #| inspect(hpd.to_string(), content="0.123456789") - #| hpd.decimal_point = -1 - #| inspect(hpd.to_string(), content="0.0123456789") - #| hpd.decimal_point = 10 - #| inspect(hpd.to_string(), content="1234567890") - #|} - #|test "shift" { - #| let tests : Array[_] = [ - #| (0L, 100, "0"), - #| (0L, -100, "0"), - #| (1L, 100, "1267650600228229401496703205376"), - #| ( - #| 1L, -100, "0.0000000000000000000000000000007888609052210118054117285652827862296732064351090230047702789306640625", - #| ), - #| (12345678L, 8, "3160493568"), - #| (12345678L, -8, "48225.3046875"), - #| (195312L, 9, "99999744"), - #| (1953125L, 9, "1000000000"), - #| ] - #| for i in 0.. 20" { - #| let decimal = Decimal::new_priv() - #| decimal.negative = false - #| decimal.decimal_point = 25 // This is > 20 but < 310 - #| decimal.digits_num = 1 - #| decimal.digits[0] = (1 : Int).to_byte() - #| decimal.truncated = false - #| let result = decimal.rounded_integer() - #| inspect(result, content="-1") // Should be Int64::max_value - #|} - #|test "corner cases" { - #| inspect(try? parse_decimal_priv(".123"), content="Ok(0.123)") - #| inspect(try? parse_decimal_priv("."), content="Err(invalid syntax)") - #| inspect(try? parse_decimal_priv("-"), content="Err(invalid syntax)") - #|} - #|test "parse_double mantissa normalization boundary" { - #| inspect(parse_double("1.9999999999999999"), content="2") - #| inspect(parse_double("9007199254740991.5"), content="9007199254740992") - #|} - ), - "deprecated.mbt": ( - #|#deprecated("Decimal will be changed to private. Use `@strconv.parse_double` instead", skip_current_package=true) - #|struct Decimal { - #| digits : FixedArray[Byte] - #| mut digits_num : Int - #| mut decimal_point : Int - #| mut negative : Bool - #| mut truncated : Bool - #|} - #|#deprecated("Decimal will be changed to private. Use `@strconv.parse_double` instead") - #|pub fn Decimal::new() -> Decimal { - #| Decimal::new_priv() - #|} - #|#deprecated("Decimal will be changed to private. Use `@strconv.parse_double` instead") - #|pub fn Decimal::from_int64(v : Int64) -> Decimal { - #| Decimal::from_int64_priv(v) - #|} - #|#deprecated("use `@strconv.parse_double` instead") - #|pub fn parse_decimal(str : StringView) -> Decimal raise StrConvError { - #| parse_decimal_from_view(str) - #|} - #|#deprecated("use `@strconv.parse_double` instead") - #|pub fn Decimal::parse_decimal(str : StringView) -> Decimal raise StrConvError { - #| parse_decimal_from_view(str) - #|} - #|#deprecated("use `@strconv.parse_double` instead to avoid using this method.") - #|pub fn Decimal::to_double(self : Decimal) -> Double raise StrConvError { - #| self.to_double_priv() - #|} - #|#deprecated("use `@strconv.parse_double` instead to avoid using this method.") - #|pub fn Decimal::shift(self : Decimal, s : Int) -> Unit { - #| self.shift_priv(s) - #|} - #|#deprecated("use `@strconv.from_str` instead") - #|pub fn[A : FromStr] parse(str : StringView) -> A raise StrConvError { - #| A::from_str(str) - #|} - ), - "double.mbt": ( - #|priv struct FloatInfo { - #| mantissa_bits : Int - #| exponent_bits : Int - #| bias : Int - #|} - #|let double_info : FloatInfo = { - #| mantissa_bits: 52, - #| exponent_bits: 11, - #| bias: -1023, - #|} - #|let mantissa_explicit_bits = 52 - #|let min_exponent_fast_path : Int64 = -22L - #|let max_exponent_fast_path : Int64 = 22L - #|let max_exponent_disguised_fast_path : Int64 = 37L - #|let max_mantissa_fast_path : UInt64 = 2UL << mantissa_explicit_bits - #|pub fn parse_double(str : StringView) -> Double raise StrConvError { - #| guard str.length() > 0 else { syntax_err() } - #| guard check_underscore(str) else { syntax_err() } - #| match parse_number(str) { - #| None => parse_inf_nan(str) - #| Some(num) => - #| match num.try_fast_path() { - #| Some(value) => value - #| None => parse_decimal_priv(str).to_double_priv() // fallback to slow path - #| } - #| } - #|} - #|fn Number::is_fast_path(self : Number) -> Bool { - #| min_exponent_fast_path <= self.exponent && - #| self.exponent <= max_exponent_disguised_fast_path && - #| self.mantissa <= max_mantissa_fast_path && - #| !self.many_digits - #|} - #|let table : ReadOnlyArray[Double] = [ - #| 1.0, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, 10000000.0, 100000000.0, - #| 1000000000.0, 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0, - #| 100000000000000.0, 1000000000000000.0, 10000000000000000.0, 100000000000000000.0, - #| 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0, 1000000000000000000000.0, - #| 10000000000000000000000.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, - #|] - #|fn pow10_fast_path(exponent : Int) -> Double { - #| table[exponent & 31] - #|} - #|let int_pow10 : ReadOnlyArray[UInt64] = [ - #| 1UL, 10UL, 100UL, 1000UL, 10000UL, 100000UL, 1000000UL, 10000000UL, 100000000UL, - #| 1000000000UL, 10000000000UL, 100000000000UL, 1000000000000UL, 10000000000000UL, - #| 100000000000000UL, 1000000000000000UL, - #|] - #|fn Number::try_fast_path(self : Number) -> Double? { - #| if self.is_fast_path() { - #| let mut value = if self.exponent <= max_exponent_fast_path { - #| let value = Double::convert_uint64(self.mantissa) - #| if self.exponent < 0L { - #| value / pow10_fast_path(-self.exponent.to_int()) - #| } else { - #| value * pow10_fast_path(self.exponent.to_int()) - #| } - #| } else { - #| let shift = self.exponent - max_exponent_fast_path - #| let mantissa = match - #| checked_mul(self.mantissa, int_pow10[shift.to_int()]) { - #| Some(m) => m - #| None => return None - #| } - #| if mantissa > max_mantissa_fast_path { - #| return None - #| } - #| Double::convert_uint64(mantissa) * - #| pow10_fast_path(max_exponent_fast_path.to_int()) - #| } - #| if self.negative { - #| value = -value - #| } - #| Some(value) - #| } else { - #| None - #| } - #|} - #|test "parse_double" { - #| let tests : Array[(String, Result[Double, String])] = [ - #| ("", Err(syntax_err_str)), - #| ("1x", Err(syntax_err_str)), - #| ("1.1.", Err(syntax_err_str)), - #| ("1e", Err(syntax_err_str)), - #| ("1e-", Err(syntax_err_str)), - #| (".e-1", Err(syntax_err_str)), - #| ("1", Ok(1.0)), - #| ("+1", Ok(1.0)), - #| ("1e23", Ok(1.0e23)), - #| ("1E23", Ok(1.0e23)), - #| ("100000000000000000000000", Ok(1.0e23)), - #| ("1e-100", Ok(1.0e-100)), - #| ("123456700", Ok(1.234567e+08)), - #| ("99999999999999974834176", Ok(9.999999999999997e+22)), - #| ("100000000000000000000001", Ok(1.0000000000000001e+23)), - #| ("100000000000000008388608", Ok(1.0000000000000001e+23)), - #| ("100000000000000016777215", Ok(1.0000000000000001e+23)), - #| ("100000000000000016777216", Ok(1.0000000000000003e+23)), - #| ("-1", Ok(-1.0)), - #| ("-0.1", Ok(-0.1)), - #| ("-0", Ok(-0.0)), - #| ("1e-20", Ok(1.0e-20)), - #| ("625e-3", Ok(0.625)), - #| ("6.62607015e-34", Ok(6.62607015e-34)), - #| ("2.2250738585072012e-308", Ok(2.2250738585072014e-308)), - #| ("2.2250738585072011e-308", Ok(2.225073858507201e-308)), - #| ("0", Ok(0.0)), - #| ("0e0", Ok(0.0)), - #| ("-0e0", Ok(-0.0)), - #| ("+0e0", Ok(0.0)), - #| ("0e-0", Ok(0.0)), - #| ("-0e-0", Ok(-0.0)), - #| ("+0e-0", Ok(0.0)), - #| ("0e+0", Ok(0.0)), - #| ("-0e+0", Ok(-0.0)), - #| ("+0e+0", Ok(0.0)), - #| ("0e+01234567890123456789", Ok(0.0)), - #| ("0.00e-01234567890123456789", Ok(0.0)), - #| ("-0e+01234567890123456789", Ok(-0.0)), - #| ("-0.00e-01234567890123456789", Ok(-0.0)), - #| ("0e292", Ok(0.0)), - #| ("0e347", Ok(0.0)), - #| ("0e348", Ok(0.0)), - #| ("-0e291", Ok(-0.0)), - #| ("-0e292", Ok(-0.0)), - #| ("-0e347", Ok(-0.0)), - #| ("-0e348", Ok(-0.0)), - #| ("1.7976931348623157e308", Ok(1.7976931348623157e308)), - #| ("-1.7976931348623157e308", Ok(-1.7976931348623157e308)), - #| ("1.7976931348623158e308", Ok(1.7976931348623157e308)), - #| ("-1.7976931348623158e308", Ok(-1.7976931348623157e308)), - #| ("1e308", Ok(1.0e308)), - #| ( - #| "1.7976931348623159e308", - #| Err( - #| range_err_str, - #| ), - #| ), - #| ( - #| "-1.7976931348623159e308", - #| Err( - #| range_err_str, - #| ), - #| ), - #| ("2e308", Err(range_err_str)), - #| ("1e309", Err(range_err_str)), - #| ("1e310", Err(range_err_str)), - #| ("1e400", Err(range_err_str)), - #| ("1e40000", Err(range_err_str)), - #| ("1e-305", Ok(1.0e-305)), - #| ("1e-306", Ok(1.0e-306)), - #| ("1e-307", Ok(1.0e-307)), - #| ("1e-308", Ok(1.0e-308)), - #| ("1e-309", Ok(1.0e-309)), - #| ("1e-310", Ok(1.0e-310)), - #| ("1e-322", Ok(1.0e-322)), - #| ("5e-324", Ok(5.0e-324)), - #| ("4e-324", Ok(5.0e-324)), - #| ("3e-324", Ok(5.0e-324)), - #| ("2e-324", Ok(0.0)), - #| ("1e-350", Ok(0.0)), - #| ("1e-400000", Ok(0.0)), - #| ("1_23.50_0_0e+1_2", Ok(1.235e+14)), - #| ("-_123.5e+12", Err(syntax_err_str)), - #| ("+_123.5e+12", Err(syntax_err_str)), - #| ("_123.5e+12", Err(syntax_err_str)), - #| ("1__23.5e+12", Err(syntax_err_str)), - #| ("123_.5e+12", Err(syntax_err_str)), - #| ("123._5e+12", Err(syntax_err_str)), - #| ("123.5_e+12", Err(syntax_err_str)), - #| ("123.5__0e+12", Err(syntax_err_str)), - #| ("123.5e_+12", Err(syntax_err_str)), - #| ("123.5e+_12", Err(syntax_err_str)), - #| ("123.5e_-12", Err(syntax_err_str)), - #| ("123.5e-_12", Err(syntax_err_str)), - #| ("123.5e+1__2", Err(syntax_err_str)), - #| ("123.5e+12_", Err(syntax_err_str)), - #| ] - #| for i in 0.. Err(err) - #| }, - #| t.1, - #| ) - #| } - #|} - #|test "parse_double_inf" { - #| assert_eq(parse_double("inf"), @double.infinity) - #| assert_eq(parse_double("+Inf"), @double.infinity) - #| assert_eq(parse_double("-Inf"), @double.neg_infinity) - #| assert_eq(parse_double("+Infinity"), @double.infinity) - #| assert_eq(parse_double("-Infinity"), @double.neg_infinity) - #| assert_eq(parse_double("+INFINITY"), @double.infinity) - #| assert_eq(parse_double("-INFINITY"), @double.neg_infinity) - #|} - #|test "parse_double_nan" { - #| assert_true(parse_double("nan").is_nan()) - #| assert_true(parse_double("NaN").is_nan()) - #| assert_true(parse_double("NAN").is_nan()) - #|} - ), - "errors.mbt": ( - #|pub(all) suberror StrConvError String - #|pub impl Show for StrConvError with output(self, logger) { - #| match self { - #| StrConvError(err) => logger.write_string(err) - #| } - #|} - #|let range_err_str = "value out of range" - #|let syntax_err_str = "invalid syntax" - #|let base_err_str = "invalid base" - #|fn[T] range_err() -> T raise StrConvError { - #| raise StrConvError(range_err_str) - #|} - #|fn[T] syntax_err() -> T raise StrConvError { - #| raise StrConvError(syntax_err_str) - #|} - #|fn[T] base_err() -> T raise StrConvError { - #| raise StrConvError(base_err_str) - #|} - ), - "int.mbt": ( - #|const INT_MIN = 0x80000000 - #|const INT_MAX = 0x7fffffff - #|const INT64_MIN = -0x8000000000000000L - #|const INT64_MAX = 0x7fffffffffffffffL - #|fn check_and_consume_base( - #| view : StringView, - #| base : Int, - #|) -> (Int, StringView, Bool) raise StrConvError { - #| if base == 0 { - #| match view { - #| ['0', 'x' | 'X', .. rest] => (16, rest, true) - #| ['0', 'o' | 'O', .. rest] => (8, rest, true) - #| ['0', 'b' | 'B', .. rest] => (2, rest, true) - #| _ => (10, view, false) - #| } - #| } else { - #| match view { - #| ['0', 'x' | 'X', .. rest] if base == 16 => (16, rest, true) - #| ['0', 'o' | 'O', .. rest] if base == 8 => (8, rest, true) - #| ['0', 'b' | 'B', .. rest] if base == 2 => (2, rest, true) - #| _ => if base is (2..=36) { (base, view, false) } else { base_err() } - #| } - #| } - #|} - #|test { - #| inspect(try? parse_int64("0b01", base=3), content="Err(invalid syntax)") - #| inspect(try? parse_int64("0x01", base=3), content="Err(invalid syntax)") - #| inspect(try? parse_int64("0o01", base=3), content="Err(invalid syntax)") - #|} - #|pub fn parse_int64( - #| str : StringView, - #| base? : Int = 0, - #|) -> Int64 raise StrConvError { - #| guard str != "" else { syntax_err() } - #| let (neg, rest) = match str.view() { - #| ['+', .. rest] => (false, rest) - #| ['-', .. rest] => (true, rest) - #| rest => (false, rest) - #| } - #| let (num_base, rest, allow_underscore) = check_and_consume_base(rest, base) - #| let overflow_threshold = overflow_threshold(num_base, neg) - #| let has_digit = rest - #| is (['0'..='9' | 'a'..='z' | 'A'..='Z', ..] - #| | ['_', '0'..='9' | 'a'..='z' | 'A'..='Z', ..]) - #| guard has_digit else { syntax_err() } - #| loop (rest, 0L, allow_underscore) { - #| (['_'], _, _) => - #| syntax_err() - #| (['_', ..], _, false) => syntax_err() - #| (['_', .. rest], acc, true) => continue (rest, acc, false) - #| ([c, .. rest], acc, _) => { - #| let c = c.to_int() - #| let d = match c { - #| '0'..='9' => c - '0' - #| 'a'..='z' => c + (10 - 'a') - #| 'A'..='Z' => c + (10 - 'A') - #| _ => syntax_err() - #| } - #| guard d < num_base else { syntax_err() } - #| if neg { - #| guard acc >= overflow_threshold else { range_err() } - #| let next_acc = acc * num_base.to_int64() - d.to_int64() - #| guard next_acc <= acc else { range_err() } - #| continue (rest, next_acc, true) - #| } else { - #| guard acc < overflow_threshold else { range_err() } - #| let next_acc = acc * num_base.to_int64() + d.to_int64() - #| guard next_acc >= acc else { range_err() } - #| continue (rest, next_acc, true) - #| } - #| } - #| ([], acc, _) => acc - #| } - #|} - #|pub fn parse_int(str : StringView, base? : Int = 0) -> Int raise StrConvError { - #| let n = parse_int64(str, base~) - #| if n < INT_MIN.to_int64() || n > INT_MAX.to_int64() { - #| range_err() - #| } - #| n.to_int() - #|} - #|fn check_underscore(str : StringView) -> Bool { - #| let rest = match str { - #| ['+' | '-', .. rest] => rest - #| rest => rest - #| } - #| let (rest, allow_underscore, hex) = match rest { - #| ['0', 'x' | 'X', .. rest] => (rest, true, true) - #| ['0', 'o' | 'O', .. rest] => (rest, true, false) - #| ['0', 'b' | 'B', .. rest] => (rest, true, false) - #| rest => (rest, false, false) - #| } - #| fn is_digit(c : Char) -> Bool { - #| c is ('0'..='9') || (hex && c is ('a'..='f' | 'A'..='F')) - #| } - #| let follow_underscore = false - #| loop (rest, allow_underscore, follow_underscore) { - #| ([], _, _) => true - #| (['_'], _, _) => false - #| (['_', ..], false, _) => false - #| (['_', .. rest], true, _) => continue (rest, false, true) - #| ([c, .. rest], _, follow_underscore) => - #| if is_digit(c) { - #| continue (rest, true, false) - #| } else if follow_underscore { - #| false - #| } else { - #| continue (rest, false, false) - #| } - #| } - #|} - #|fn determine_base(s : String) -> Int { - #| match s { - #| ['0', 'x' | 'X', ..] => 16 - #| ['0', 'o' | 'O', ..] => 8 - #| ['0', 'b' | 'B', ..] => 2 - #| _ => 10 - #| } - #|} - #|fn overflow_threshold(base : Int, neg : Bool) -> Int64 { - #| if !neg { - #| if base == 10 { - #| INT64_MAX / 10L + 1L - #| } else if base == 16 { - #| INT64_MAX / 16L + 1L - #| } else { - #| INT64_MAX / base.to_int64() + 1L - #| } - #| } else if base == 10 { - #| INT64_MIN / 10L - #| } else if base == 16 { - #| INT64_MIN / 16L - #| } else { - #| INT64_MIN / base.to_int64() - #| } - #|} - #|test "check_underscore" { - #| assert_true(check_underscore("123")) - #| assert_true(check_underscore("0x123")) - #| assert_true(check_underscore("0o123")) - #| assert_true(check_underscore("0b101")) - #| assert_true(check_underscore("1_2_3")) - #| assert_true(check_underscore("0x_1_2_3_A_F")) - #| assert_true(check_underscore("0o_1_2_3")) - #| assert_true(check_underscore("0b_1_0_1")) - #| assert_false(check_underscore("1__2_3")) - #| assert_false(check_underscore("_123")) - #| assert_false(check_underscore("123_")) - #|} - #|test "determine_base" { - #| inspect(determine_base("1234"), content="10") - #| inspect(determine_base("0x1234"), content="16") - #| inspect(determine_base("0X1234"), content="16") - #| inspect(determine_base("0o1234"), content="8") - #| inspect(determine_base("0O1234"), content="8") - #| inspect(determine_base("0b1010"), content="2") - #| inspect(determine_base("0B1010"), content="2") - #|} - #|test "parse_int64" { - #| let tests : Array[(String, Result[Int64, String])] = [ - #| ("", Err(syntax_err_str)), - #| ("0", Ok(0L)), - #| ("-0", Ok(0L)), - #| ("+0", Ok(0L)), - #| ("1", Ok(1L)), - #| ("-1", Ok(-1L)), - #| ("+1", Ok(1L)), - #| ("12345", Ok(12345L)), - #| ("-12345", Ok(-12345L)), - #| ("012345", Ok(12345L)), - #| ("-012345", Ok(-12345L)), - #| ("9876543210", Ok(9876543210L)), - #| ("-9876543210", Ok(-9876543210L)), - #| ("9223372036854775807", Ok(9223372036854775807L)), - #| ("-9223372036854775807", Ok(-9223372036854775807L)), - #| ("9223372036854775808", Err(range_err_str)), - #| ("-9223372036854775808", Ok(-9223372036854775808L)), - #| ("9223372036854775809", Err(range_err_str)), - #| ("-9223372036854775809", Err(range_err_str)), - #| ("-1_2_3_4_5", Ok(-12345L)), - #| ("-_12345", Err(syntax_err_str)), - #| ("_12345", Err(syntax_err_str)), - #| ("1__2345", Err(syntax_err_str)), - #| ("12345_", Err(syntax_err_str)), - #| ("12345%", Err(syntax_err_str)), - #| ] - #| for i in 0.. Err(err) - #| }, - #| t.1, - #| ) - #| } - #|} - #|test "parse_int64_base" { - #| let tests : Array[(String, Int, Result[Int64, String])] = [ - #| ("", 0, Err(syntax_err_str)), - #| ("0", 0, Ok(0L)), - #| ("-0", 0, Ok(0L)), - #| ("1", 0, Ok(1L)), - #| ("-1", 0, Ok(-1L)), - #| ("12345", 0, Ok(12345L)), - #| ("-12345", 0, Ok(-12345L)), - #| ("012345", 0, Ok(12345L)), - #| ("-012345", 0, Ok(-12345L)), - #| ("0x12345", 0, Ok(0x12345L)), - #| ("-0x12345", 0, Ok(-0x12345L)), - #| ("9876543210", 0, Ok(9876543210L)), - #| ("-9876543210", 0, Ok(-9876543210L)), - #| ("9223372036854775807", 0, Ok(9223372036854775807L)), - #| ("-9223372036854775807", 0, Ok(-9223372036854775807L)), - #| ("9223372036854775808", 0, Err(range_err_str)), - #| ("12345x", 0, Err(syntax_err_str)), - #| ("-12345x", 0, Err(syntax_err_str)), - #| ("-9223372036854775808", 0, Ok(-9223372036854775808L)), - #| ("9223372036854775809", 0, Err(range_err_str)), - #| ("-9223372036854775809", 0, Err(range_err_str)), - #| ("h", 18, Ok(17L)), - #| ("10", 25, Ok(25L)), - #| ( - #| "moonbit", - #| 35, - #| Ok( - #| ( - #| ((((22L * 35L + 24L) * 35L + 24L) * 35L + 23L) * 35L + 11L) * 35L + - #| 18L - #| ) * - #| 35L + - #| 29L, - #| ), - #| ), - #| ( - #| "moonbit", - #| 36, - #| Ok( - #| ( - #| ((((22L * 36L + 24L) * 36L + 24L) * 36L + 23L) * 36L + 11L) * 36L + - #| 18L - #| ) * - #| 36L + - #| 29L, - #| ), - #| ), - #| ("0", 2, Ok(0L)), - #| ("-1", 2, Ok(-1L)), - #| ("1010", 2, Ok(10L)), - #| ("1000000000000000", 2, Ok(1L << 15)), - #| ( - #| "111111111111111111111111111111111111111111111111111111111111111", - #| 2, - #| Ok((1L << 63) - 1L), - #| ), - #| ( - #| "1000000000000000000000000000000000000000000000000000000000000000", - #| 2, - #| Err(range_err_str), - #| ), - #| ( - #| "-1000000000000000000000000000000000000000000000000000000000000000", - #| 2, - #| Ok(-1L << 63), - #| ), - #| ( - #| "-1000000000000000000000000000000000000000000000000000000000000001", - #| 2, - #| Err(range_err_str), - #| ), - #| ("-10", 8, Ok(-8L)), - #| ("57635436545", 8, Ok(0o57635436545L)), - #| ("100000000", 8, Ok(1L << 24)), - #| ("10", 16, Ok(16L)), - #| ("-123456789abcdef", 16, Ok(-0x123456789abcdefL)), - #| ("7fffffffffffffff", 16, Ok((1L << 63) - 1L)), - #| ("-0x_1_2_3_4_5", 0, Ok(-0x12345L)), - #| ("0x_1_2_3_4_5", 0, Ok(0x12345L)), - #| ("-_0x12345", 0, Err(syntax_err_str)), - #| ("_-0x12345", 0, Err(syntax_err_str)), - #| ("_0x12345", 0, Err(syntax_err_str)), - #| ("0x__12345", 0, Err(syntax_err_str)), - #| ("0x1__2345", 0, Err(syntax_err_str)), - #| ("0x1234__5", 0, Err(syntax_err_str)), - #| ("0x12345_", 0, Err(syntax_err_str)), - #| ("-0_1_2_3_4_5", 0, Ok(-12345L)), - #| ("0_1_2_3_4_5", 0, Ok(12345L)), - #| ("-_012345", 0, Err(syntax_err_str)), - #| ("_-012345", 0, Err(syntax_err_str)), - #| ("_012345", 0, Err(syntax_err_str)), - #| ("0__12345", 0, Err(syntax_err_str)), - #| ("01234__5", 0, Err(syntax_err_str)), - #| ("012345_", 0, Err(syntax_err_str)), - #| ("+0xf", 0, Ok(0xfL)), - #| ("-0xf", 0, Ok(-0xfL)), - #| ("0x+f", 0, Err(syntax_err_str)), - #| ("0x-f", 0, Err(syntax_err_str)), - #| ] - #| for i in 0.. Err(err) - #| }, - #| t.2, - #| ) - #| } - #|} - #|test "parse_int" { - #| let tests : Array[(String, Result[Int, String])] = [ - #| ("", Err(syntax_err_str)), - #| ("0", Ok(0)), - #| ("-0", Ok(0)), - #| ("1", Ok(1)), - #| ("-1", Ok(-1)), - #| ("12345", Ok(12345)), - #| ("-12345", Ok(-12345)), - #| ("012345", Ok(12345)), - #| ("-012345", Ok(-12345)), - #| ("12345x", Err(syntax_err_str)), - #| ("-12345x", Err(syntax_err_str)), - #| ("987654321", Ok(987654321)), - #| ("-987654321", Ok(-987654321)), - #| ("2147483647", Ok((1 << 31) - 1)), - #| ("-2147483647", Ok(-((1 << 31) - 1))), - #| ("2147483648", Err(range_err_str)), - #| ("-2147483648", Ok(-1 << 31)), - #| ("2147483649", Err(range_err_str)), - #| ("-2147483649", Err(range_err_str)), - #| ("-1_2_3_4_5", Ok(-12345)), - #| ("-_12345", Err(syntax_err_str)), - #| ("_12345", Err(syntax_err_str)), - #| ("1__2345", Err(syntax_err_str)), - #| ("12345_", Err(syntax_err_str)), - #| ("123%45", Err(syntax_err_str)), - #| ] - #| for i in 0.. Err(err) - #| }, - #| t.1, - #| ) - #| } - #|} - ), - "number.mbt": ( - #|let min_19digit_int : UInt64 = 100_0000_0000_0000_0000UL - #|priv struct Number { - #| exponent : Int64 - #| mantissa : UInt64 - #| negative : Bool - #| many_digits : Bool - #|} - #|fn parse_digits(s : StringView, x : UInt64) -> (StringView, UInt64, Int) { - #| s.fold_digits(x, (digit, acc : UInt64) => acc * 10UL + - #| UInt64::extend_uint(digit.reinterpret_as_uint())) - #|} - #|fn try_parse_19digits(s : StringView, x : UInt64) -> (StringView, UInt64, Int) { - #| let mut x = x - #| let mut len = 0 - #| loop s { - #| ['0'..='9' as ch, .. rest] if x < min_19digit_int => { - #| len += 1 - #| x = x * 10UL + - #| UInt64::extend_uint((ch.to_int() - '0').reinterpret_as_uint()) // no overflows here - #| continue rest - #| } - #| ['_', .. rest] => continue rest - #| s => return (s, x, len) - #| } - #|} - #|fn parse_scientific(s : StringView) -> (StringView, Int64)? { - #| let mut s = s - #| let exp_num = 0L - #| let mut neg_exp = false - #| if s is ['+' | '-' as ch, .. rest] { - #| neg_exp = ch == '-' - #| s = rest - #| } - #| if s is ['0'..='9', ..] { - #| let (s, exp_num, _) = s.fold_digits(exp_num, (digit, exp_num : Int64) => if exp_num < - #| 0x10000L { - #| 10L * exp_num + digit.to_int64() // no overflows here - #| } else { - #| exp_num - #| }) - #| if neg_exp { - #| Some((s, -exp_num)) - #| } else { - #| Some((s, exp_num)) - #| } - #| } else { - #| None - #| } - #|} - #|fn parse_number(s : StringView) -> Number? raise StrConvError { - #| let start = s - #| let (s, negative) = match s { - #| ['-', .. rest] => (rest, true) - #| ['+', .. rest] | rest => (rest, false) - #| } - #| if s.is_empty() { - #| return None - #| } - #| let (s, mantissa, consumed) = parse_digits(s, 0UL) - #| let mut mantissa = mantissa - #| let mut s = s - #| let mut n_digits = consumed - #| let mut n_after_dot = 0 - #| let mut exponent = 0L - #| if s is ['.', .. rest] { - #| s = rest - #| let (new_s, new_mantissa, consumed_digit) = parse_digits(s, mantissa) - #| s = new_s - #| mantissa = new_mantissa - #| n_after_dot = consumed_digit - #| exponent = -n_after_dot.to_int64() - #| } - #| n_digits += n_after_dot - #| if n_digits == 0 { - #| return None - #| } - #| let exp_number = 0L - #| if s is ['e' | 'E', .. rest] { - #| let (new_s, exp_number) = match parse_scientific(rest) { - #| Some(res) => res - #| None => return None - #| } - #| s = new_s - #| exponent += exp_number - #| } - #| guard s is "" else { syntax_err() } - #| if n_digits <= 19 { - #| return Some({ exponent, mantissa, negative, many_digits: false }) - #| } - #| n_digits -= 19 - #| let mut many_digits = false - #| loop start { - #| ['0' | '.' as ch, .. rest] => { - #| n_digits -= (ch.to_int() - 46) / 2 // '0' = b'.' + 2 - #| continue rest - #| } - #| _ => () - #| } - #| let mut mantissa = mantissa - #| if n_digits > 0 { - #| many_digits = true - #| mantissa = 0UL - #| let s = start - #| let (s, new_mantissa, consumed_digit) = try_parse_19digits(s, mantissa) - #| mantissa = new_mantissa - #| exponent = (if mantissa >= min_19digit_int { - #| consumed_digit // big int - #| } else { - #| guard s is [_, .. s] else { return None } - #| let (_, new_mantissa, consumed_digit) = try_parse_19digits(s, mantissa) - #| mantissa = new_mantissa - #| consumed_digit - #| }).to_int64() - #| exponent += exp_number - #| } // add back the explicit part - #| Some({ exponent, mantissa, negative, many_digits }) - #|} - #|fn parse_inf_nan(rest : StringView) -> Double raise StrConvError { - #| let (pos, rest) = match rest { - #| ['-', .. rest] => (false, rest) - #| ['+', .. rest] | rest => (true, rest) - #| } - #| match rest { - #| ['n' | 'N', 'a' | 'A', 'n' | 'N'] => @double.not_a_number - #| ['i' | 'I', 'n' | 'N', 'f' | 'F', .. rest] => { - #| guard rest - #| is ([] | ['i' | 'I', 'n' | 'N', 'i' | 'I', 't' | 'T', 'y' | 'Y']) else { - #| syntax_err() - #| } - #| if pos { - #| @double.infinity - #| } else { - #| @double.neg_infinity - #| } - #| } - #| _ => syntax_err() - #| } - #|} - #|fn checked_mul(a : UInt64, b : UInt64) -> UInt64? { - #| if a == 0UL || b == 0UL { - #| return Some(0UL) - #| } - #| if a == 1UL { - #| return Some(b) - #| } - #| if b == 1UL { - #| return Some(a) - #| } - #| if b.clz() == 0 || a.clz() == 0 { - #| return None - #| } - #| let quotient : UInt64 = @uint64.max_value / b - #| if a > quotient { - #| return None - #| } - #| Some(a * b) - #|} - ), - "string_view.mbt": ( - #|fn[T] StringView::fold_digits( - #| self : Self, - #| init : T, - #| f : (Int, T) -> T, - #|) -> (Self, T, Int) { - #| let mut ret = init - #| let mut len = 0 - #| let mut str = self - #| while str is [ch, .. rest] { - #| if ch is ('0'..='9') { - #| len += 1 - #| ret = f(ch.to_int() - '0', ret) - #| } else if ch != '_' { - #| break - #| } - #| str = rest - #| } - #| (str, ret, len) - #|} - ), - "traits.mbt": ( - #|pub(open) trait FromStr { - #| #as_free_fn - #| from_str(StringView) -> Self raise StrConvError = _ - #| #deprecated("use `from_str` instead", skip_current_package=true) - #| from_string(String) -> Self raise StrConvError = _ - #|} - #|#deprecated("replace `impl from_string` with `impl from_str`") - #|impl FromStr with from_str(str) { - #| FromStr::from_string(str.to_string()) - #|} - #|impl FromStr with from_string(str) { - #| FromStr::from_str(str) - #|} - #|pub impl FromStr for Bool with from_str(str) { - #| parse_bool(str) - #|} - #|pub impl FromStr for Int with from_str(str) { - #| parse_int(str) - #|} - #|pub impl FromStr for Int64 with from_str(str) { - #| parse_int64(str) - #|} - #|pub impl FromStr for UInt with from_str(str) { - #| parse_uint(str) - #|} - #|pub impl FromStr for UInt64 with from_str(str) { - #| parse_uint64(str) - #|} - #|pub impl FromStr for Double with from_str(str) { - #| parse_double(str) - #|} - #|test "parse" { - #| let b : Bool = from_str("true") - #| inspect(b, content="true") - #| let i : Int = from_str("12345") - #| inspect(i, content="12345") - #| let i64 : Int64 = from_str("9223372036854775807") - #| assert_eq(i64, 9223372036854775807L) - #| let ui : UInt = from_str("4294967295") - #| inspect(ui, content="4294967295") - #| let ui64 : UInt64 = from_str("18446744073709551615") - #| assert_eq(ui64, 18446744073709551615UL) - #| let d : Double = from_str("1234.56789") - #| assert_eq(d, 1234.56789) - #|} - ), - "uint.mbt": ( - #|const UINT_MAX : UInt = 0xffffffff - #|const UINT64_MAX : UInt64 = 0xffffffffffffffffUL - #|pub fn parse_uint64( - #| str : StringView, - #| base? : Int = 0, - #|) -> UInt64 raise StrConvError { - #| guard str != "" else { syntax_err() } - #| if str is ['+' | '-', ..] { - #| syntax_err() - #| } - #| let (num_base, rest, allow_underscore) = check_and_consume_base(str, base) - #| let overflow_threshold = match num_base { - #| 10 => UINT64_MAX / 10 + 1 - #| 16 => UINT64_MAX / 16 + 1 - #| _ => UINT64_MAX / num_base.to_uint64() + 1 - #| } - #| let has_digit = rest - #| is (['0'..='9' | 'a'..='z' | 'A'..='Z', ..] - #| | ['_', '0'..='9' | 'a'..='z' | 'A'..='Z', ..]) - #| guard has_digit else { syntax_err() } - #| loop (rest, 0UL, allow_underscore) { - #| (['_'], _, _) => - #| syntax_err() - #| (['_', ..], _, false) => syntax_err() - #| (['_', .. rest], acc, true) => continue (rest, acc, false) - #| ([c, .. rest], acc, _) => { - #| let c = c.to_int() - #| let d = match c { - #| '0'..='9' => c - '0' - #| 'a'..='z' => c + (10 - 'a') - #| 'A'..='Z' => c + (10 - 'A') - #| _ => syntax_err() - #| } - #| guard d < num_base else { syntax_err() } - #| guard acc < overflow_threshold else { range_err() } - #| let next_acc = acc * num_base.to_uint64() + d.to_uint64() - #| guard next_acc >= acc && next_acc <= UINT64_MAX else { range_err() } - #| continue (rest, next_acc, true) - #| } - #| ([], acc, _) => acc - #| } - #|} - #|pub fn parse_uint(str : StringView, base? : Int = 0) -> UInt raise StrConvError { - #| let n = parse_uint64(str, base~) - #| if n > UINT_MAX.to_uint64() { - #| range_err() - #| } - #| n.to_uint() - #|} - #|test "parse_uint64" { - #| let tests : Array[(String, Result[UInt64, String])] = [ - #| ("", Err(syntax_err_str)), - #| ("0", Ok(0UL)), - #| ("-0", Err(syntax_err_str)), - #| ("+0", Err(syntax_err_str)), - #| ("1", Ok(1UL)), - #| ("-1", Err(syntax_err_str)), - #| ("12345", Ok(12345UL)), - #| ("-12345", Err(syntax_err_str)), - #| ("012345", Ok(12345UL)), - #| ("9876543210", Ok(9876543210UL)), - #| ("18446744073709551615", Ok(18446744073709551615UL)), - #| ("18446744073709551616", Err(range_err_str)), - #| ("1_2_3_4_5", Ok(12345UL)), - #| ("_12345", Err(syntax_err_str)), - #| ("1__2345", Err(syntax_err_str)), - #| ("12345_", Err(syntax_err_str)), - #| ("12345%", Err(syntax_err_str)), - #| ] - #| for i in 0.. Err(err) - #| }, - #| t.1, - #| ) - #| } - #|} - #|test "parse_uint64_base" { - #| let tests : Array[(String, Int, Result[UInt64, String])] = [ - #| ("", 0, Err(syntax_err_str)), - #| ("0", 0, Ok(0UL)), - #| ("1", 0, Ok(1UL)), - #| ("12345", 0, Ok(12345UL)), - #| ("012345", 0, Ok(12345UL)), - #| ("0x12345", 0, Ok(0x12345UL)), - #| ("9876543210", 0, Ok(9876543210UL)), - #| ("18446744073709551615", 0, Ok(UINT64_MAX)), - #| ("0xffffffffffffffff", 0, Ok(UINT64_MAX)), - #| ("18446744073709551616", 0, Err(range_err_str)), - #| ("12345x", 0, Err(syntax_err_str)), - #| ("-12345x", 0, Err(syntax_err_str)), - #| ("h", 18, Ok(17UL)), - #| ("10", 25, Ok(25UL)), - #| ( - #| "moonbit", - #| 35, - #| Ok( - #| ( - #| ((((22UL * 35UL + 24UL) * 35UL + 24UL) * 35UL + 23UL) * 35UL + 11UL) * - #| 35UL + - #| 18UL - #| ) * - #| 35UL + - #| 29UL, - #| ), - #| ), - #| ( - #| "moonbit", - #| 36, - #| Ok( - #| ( - #| ((((22UL * 36UL + 24UL) * 36UL + 24UL) * 36UL + 23UL) * 36UL + 11UL) * - #| 36UL + - #| 18UL - #| ) * - #| 36UL + - #| 29UL, - #| ), - #| ), - #| ("0", 2, Ok(0UL)), - #| ("-1", 2, Err(syntax_err_str)), - #| ("1010", 2, Ok(10UL)), - #| ("1000000000000000", 2, Ok(1UL << 15)), - #| ( - #| "1111111111111111111111111111111111111111111111111111111111111111", - #| 2, - #| Ok(UINT64_MAX), - #| ), - #| ( - #| "1000000000000000000000000000000000000000000000000000000000000000", - #| 2, - #| Ok(1UL << 63), - #| ), - #| ("10", 8, Ok(8UL)), - #| ("57635436545", 8, Ok(0o57635436545UL)), - #| ("100000000", 8, Ok(1UL << 24)), - #| ("10", 16, Ok(16UL)), - #| ("ffffffffffffffff", 16, Ok(UINT64_MAX)), - #| ("0x_1_2_3_4_5", 0, Ok(0x12345UL)), - #| ("-_0x12345", 0, Err(syntax_err_str)), - #| ("_-0x12345", 0, Err(syntax_err_str)), - #| ("_0x12345", 0, Err(syntax_err_str)), - #| ("0x__12345", 0, Err(syntax_err_str)), - #| ("0x1__2345", 0, Err(syntax_err_str)), - #| ("0x1234__5", 0, Err(syntax_err_str)), - #| ("0x12345_", 0, Err(syntax_err_str)), - #| ("0_1_2_3_4_5", 0, Ok(12345UL)), - #| ("-_012345", 0, Err(syntax_err_str)), - #| ("_-012345", 0, Err(syntax_err_str)), - #| ("_012345", 0, Err(syntax_err_str)), - #| ("0__12345", 0, Err(syntax_err_str)), - #| ("01234__5", 0, Err(syntax_err_str)), - #| ("012345_", 0, Err(syntax_err_str)), - #| ("0xf", 0, Ok(0xfUL)), - #| ("-0xf", 0, Err(syntax_err_str)), - #| ("0x+f", 0, Err(syntax_err_str)), - #| ("0x-f", 0, Err(syntax_err_str)), - #| ] - #| for i in 0.. Err(err) - #| }, - #| t.2, - #| ) - #| } - #|} - #|test "parse_uint" { - #| let tests : Array[(String, Result[UInt, String])] = [ - #| ("", Err(syntax_err_str)), - #| ("0", Ok(0)), - #| ("-0", Err(syntax_err_str)), - #| ("+0", Err(syntax_err_str)), - #| ("1", Ok(1)), - #| ("-1", Err(syntax_err_str)), - #| ("12345", Ok(12345)), - #| ("012345", Ok(12345)), - #| ("12345x", Err(syntax_err_str)), - #| ("-12345x", Err(syntax_err_str)), - #| ("987654321", Ok(987654321)), - #| ("4294967295", Ok(UINT_MAX)), - #| ("0xffffffff", Ok(UINT_MAX)), - #| ("4294967296", Err(range_err_str)), - #| ("1_2_3_4_5", Ok(12345)), - #| ("-_12345", Err(syntax_err_str)), - #| ("_12345", Err(syntax_err_str)), - #| ("1__2345", Err(syntax_err_str)), - #| ("12345_", Err(syntax_err_str)), - #| ("123%45", Err(syntax_err_str)), - #| ] - #| for i in 0.. Err(err) - #| }, - #| t.1, - #| ) - #| } - #|} - #|test "parse_uint64 uppercase hex and invalid base" { - #| inspect(try? parse_uint64("ABCD", base=16), content="Ok(43981)") - #| inspect(try? parse_uint64("1234", base=37), content="Err(invalid base)") - #|} - ), - }, + "bool.mbt": ( + #|pub fn parse_bool(str : StringView) -> Bool raise StrConvError { + #| lexmatch str { + #| "(true|TRUE|True|t|T|1)" => true + #| "(false|FALSE|False|f|F|0)" => false + #| _ => syntax_err() + #| } + #|} + #|test "parse_bool" { + #| let tests : Array[(String, Result[Bool, String])] = [ + #| ("", Err(syntax_err_str)), + #| ("zutomayo", Err(syntax_err_str)), + #| ("0", Ok(false)), + #| ("f", Ok(false)), + #| ("F", Ok(false)), + #| ("FALSE", Ok(false)), + #| ("false", Ok(false)), + #| ("False", Ok(false)), + #| ("1", Ok(true)), + #| ("t", Ok(true)), + #| ("T", Ok(true)), + #| ("TRUE", Ok(true)), + #| ("true", Ok(true)), + #| ("True", Ok(true)), + #| ] + #| for t in tests { + #| assert_eq( + #| Result::Ok(parse_bool(t.0)) catch { + #| StrConvError(err) => Err(err) + #| }, + #| t.1, + #| ) + #| } + #|} + ), + "decimal.mbt": ( + #|let max_shift = 59 + #|let powtab : ReadOnlyArray[Int] = [ + #| 1, 3, 6, 9, 13, 16, 19, 23, 26, 29, 33, 36, 39, 43, 46, 49, 53, 56, 59, + #|] + #|fn Decimal::new_priv() -> Decimal { + #| { + #| digits: FixedArray::make(800, Byte::default()), + #| digits_num: 0, + #| decimal_point: 0, + #| negative: false, + #| truncated: false, + #| } + #|} + #|fn Decimal::from_int64_priv(v : Int64) -> Decimal { + #| let d = Decimal::new_priv() + #| d.assign(v) + #| d + #|} + #|fn parse_decimal_priv(str : StringView) -> Decimal raise StrConvError { + #| parse_decimal_from_view(str) + #|} + #|fn parse_decimal_from_view(str : StringView) -> Decimal raise StrConvError { + #| let d = Decimal::new_priv() + #| let mut has_dp = false + #| let mut has_digits = false + #| let rest = match str { + #| ['-', .. rest] => { + #| d.negative = true + #| rest + #| } + #| ['+', .. rest] => rest + #| _ => str + #| } + #| let rest = loop rest { + #| ['_', .. rest] => continue rest + #| ['.', .. rest] => { + #| guard !has_dp else { syntax_err() } + #| has_dp = true + #| d.decimal_point = d.digits_num + #| continue rest + #| } + #| ['0'..='9' as digit, .. rest] => { + #| has_digits = true + #| if digit == '0' && d.digits_num == 0 { + #| d.decimal_point -= 1 + #| continue rest + #| } + #| if d.digits_num < d.digits.length() { + #| d.digits[d.digits_num] = (digit.to_int() - '0').to_byte() + #| d.digits_num += 1 + #| } else if digit != '0' { + #| d.truncated = true + #| } + #| continue rest + #| } + #| rest => rest + #| } + #| guard has_digits else { syntax_err() } + #| if !has_dp { + #| d.decimal_point = d.digits_num + #| } + #| let rest = match rest { + #| ['e' | 'E', .. rest] => { + #| let mut exp_sign = 1 + #| let rest = match rest { + #| ['+', .. rest] => rest + #| ['-', .. rest] => { + #| exp_sign = -1 + #| rest + #| } + #| rest => rest + #| } + #| guard rest is ['0'..='9', ..] else { syntax_err() } + #| let mut exp = 0 + #| let rest = loop rest { + #| ['_', .. rest] => continue rest + #| ['0'..='9' as digit, .. rest] => { + #| exp = exp * 10 + (digit.to_int() - '0') + #| continue rest + #| } + #| rest => rest + #| } + #| d.decimal_point += exp_sign * exp + #| rest + #| } + #| rest => rest + #| } + #| guard rest is [] else { syntax_err() } + #| d.trim() + #| d + #|} + #|fn Decimal::to_double_priv(self : Decimal) -> Double raise StrConvError { + #| let mut exponent = 0 + #| let mut mantissa = 0L + #| if self.digits_num == 0 || self.decimal_point < -330 { + #| mantissa = 0 + #| exponent = double_info.bias + #| let bits = assemble_bits(mantissa, exponent, self.negative) + #| return bits.reinterpret_as_double() + #| } + #| if self.decimal_point > 310 { + #| range_err() + #| } + #| while self.decimal_point > 0 { + #| let mut n = 0 + #| if self.decimal_point >= powtab.length() { + #| n = 60 + #| } else { + #| n = powtab[self.decimal_point] + #| } + #| self.shift_priv(-n) + #| exponent += n + #| } + #| while self.decimal_point < 0 || + #| (self.decimal_point == 0 && self.digits[0].to_int() < 5) { + #| let mut n = 0 + #| if -self.decimal_point >= powtab.length() { + #| n = 60 + #| } else { + #| n = powtab[-self.decimal_point] + #| } + #| self.shift_priv(n) + #| exponent -= n + #| } + #| exponent -= 1 + #| if exponent < double_info.bias + 1 { + #| let n = double_info.bias + 1 - exponent + #| self.shift_priv(-n) + #| exponent += n + #| } + #| if exponent - double_info.bias >= (1 << double_info.exponent_bits) - 1 { + #| range_err() + #| } + #| self.shift_priv(double_info.mantissa_bits + 1) + #| mantissa = self.rounded_integer() + #| if mantissa == 2L << double_info.mantissa_bits { + #| mantissa = mantissa >> 1 + #| exponent += 1 + #| if exponent - double_info.bias >= (1 << double_info.exponent_bits) - 1 { + #| range_err() + #| } + #| } + #| if (mantissa & (1L << double_info.mantissa_bits)) == 0L { + #| exponent = double_info.bias + #| } + #| let bits = assemble_bits(mantissa, exponent, self.negative) + #| bits.reinterpret_as_double() + #|} + #|fn Decimal::shift_priv(self : Decimal, s : Int) -> Unit { + #| if self.digits_num == 0 { + #| return + #| } + #| let mut s = s + #| if s > 0 { + #| while s > max_shift { + #| self.left_shift(max_shift) + #| s -= max_shift + #| } + #| self.left_shift(s) + #| } + #| if s < 0 { + #| while s < -max_shift { + #| self.right_shift(max_shift) + #| s += max_shift + #| } + #| self.right_shift(-s) + #| } + #|} + #|fn assemble_bits(mantissa : Int64, exponent : Int, negative : Bool) -> Int64 { + #| let biased_exp = exponent - double_info.bias + #| let mut bits = mantissa & ((1L << double_info.mantissa_bits) - 1L) + #| let exp_bits = (biased_exp & ((1 << double_info.exponent_bits) - 1)).to_int64() + #| bits = bits | (exp_bits << double_info.mantissa_bits) + #| if negative { + #| bits = bits | (1L << double_info.mantissa_bits << double_info.exponent_bits) + #| } + #| bits + #|} + #|fn Decimal::rounded_integer(self : Decimal) -> Int64 { + #| if self.decimal_point > 20 { + #| return 0xFFFFFFFFFFFFFFFFL + #| } + #| let (n, i) = for n = 0L, i = 0; i < self.decimal_point && i < self.digits_num; { + #| continue n * 10L + self.digits[i].to_int64(), i + 1 + #| } nobreak { + #| (n, i) + #| } + #| let n = for n = n, i = i; i < self.decimal_point; { + #| continue n * 10L, i + 1 + #| } nobreak { + #| n + #| } + #| if self.should_round_up(self.decimal_point) { + #| n + 1L + #| } else { + #| n + #| } + #|} + #|fn Decimal::should_round_up(self : Decimal, d : Int) -> Bool { + #| if d < 0 || d >= self.digits_num { + #| return false + #| } + #| if self.digits[d].to_int() == 5 && d + 1 == self.digits_num { + #| if self.truncated { + #| return true + #| } + #| return d > 0 && self.digits[d - 1].to_int() % 2 != 0 + #| } + #| self.digits[d].to_int() >= 5 + #|} + #|fn Decimal::assign(self : Decimal, v : Int64) -> Unit { + #| let buf = FixedArray::make(24, Byte::default()) + #| let n = for n = 0, v = v; v > 0; { + #| let v1 = v / 10 + #| buf[n] = (v - v1 * 10).to_byte() + #| continue n + 1, v1 + #| } nobreak { + #| n + #| } + #| self.digits_num = 0 + #| for i in n>..0 { + #| self.digits[self.digits_num] = buf[i] + #| self.digits_num += 1 + #| } + #| self.decimal_point = self.digits_num + #| self.trim() + #|} + #|fn Decimal::right_shift(self : Decimal, s : Int) -> Unit { + #| let mut read_index = 0 + #| let mut write_index = 0 + #| let mut acc = 0UL + #| while acc >> s == 0 { + #| if read_index >= self.digits_num { + #| while acc >> s == 0 { + #| acc *= 10 + #| read_index += 1 + #| } + #| break + #| } + #| let d = self.digits[read_index] + #| acc = acc * 10 + d.to_int64().reinterpret_as_uint64() + #| read_index += 1 + #| } + #| self.decimal_point -= read_index - 1 + #| let mask = (1UL << s) - 1 + #| while read_index < self.digits_num { + #| let out = acc >> s + #| self.digits[write_index] = out.to_byte() + #| write_index += 1 + #| acc = acc & mask + #| let d = self.digits[read_index] + #| acc = acc * 10 + d.to_int64().reinterpret_as_uint64() + #| read_index += 1 + #| } + #| while acc > 0 { + #| let out = acc >> s + #| if write_index < self.digits.length() { + #| self.digits[write_index] = out.to_byte() + #| write_index += 1 + #| } else if out > 0 { + #| self.truncated = true + #| } + #| acc = acc & mask + #| acc = acc * 10 + #| } + #| self.digits_num = write_index + #| self.trim() + #|} + #|let left_shift_cheats : ReadOnlyArray[(Int, String)] = [ + #| (0, ""), + #| (1, "5"), // * 2 + #| (1, "25"), // * 4 + #| (1, "125"), // * 8 + #| (2, "625"), // * 16 + #| (2, "3125"), // * 32 + #| (2, "15625"), // * 64 + #| (3, "78125"), // * 128 + #| (3, "390625"), // * 256 + #| (3, "1953125"), // * 512 + #| (4, "9765625"), // * 1024 + #| (4, "48828125"), // * 2048 + #| (4, "244140625"), // * 4096 + #| (4, "1220703125"), // * 8192 + #| (5, "6103515625"), // * 16384 + #| (5, "30517578125"), // * 32768 + #| (5, "152587890625"), // * 65536 + #| (6, "762939453125"), // * 131072 + #| (6, "3814697265625"), // * 262144 + #| (6, "19073486328125"), // * 524288 + #| (7, "95367431640625"), // * 1048576 + #| (7, "476837158203125"), // * 2097152 + #| (7, "2384185791015625"), // * 4194304 + #| (7, "11920928955078125"), // * 8388608 + #| (8, "59604644775390625"), // * 16777216 + #| (8, "298023223876953125"), // * 33554432 + #| (8, "1490116119384765625"), // * 67108864 + #| (9, "7450580596923828125"), // * 134217728 + #| (9, "37252902984619140625"), // * 268435456 + #| (9, "186264514923095703125"), // * 536870912 + #| (10, "931322574615478515625"), // * 1073741824 + #| (10, "4656612873077392578125"), // * 2147483648 + #| (10, "23283064365386962890625"), // * 4294967296 + #| (10, "116415321826934814453125"), // * 8589934592 + #| (11, "582076609134674072265625"), // * 17179869184 + #| (11, "2910383045673370361328125"), // * 34359738368 + #| (11, "14551915228366851806640625"), // * 68719476736 + #| (12, "72759576141834259033203125"), // * 137438953472 + #| (12, "363797880709171295166015625"), // * 274877906944 + #| (12, "1818989403545856475830078125"), // * 549755813888 + #| (13, "9094947017729282379150390625"), // * 1099511627776 + #| (13, "45474735088646411895751953125"), // * 2199023255552 + #| (13, "227373675443232059478759765625"), // * 4398046511104 + #| (13, "1136868377216160297393798828125"), // * 8796093022208 + #| (14, "5684341886080801486968994140625"), // * 17592186044416 + #| (14, "28421709430404007434844970703125"), // * 35184372088832 + #| (14, "142108547152020037174224853515625"), // * 70368744177664 + #| (15, "710542735760100185871124267578125"), // * 140737488355328 + #| (15, "3552713678800500929355621337890625"), // * 281474976710656 + #| (15, "17763568394002504646778106689453125"), // * 562949953421312 + #| (16, "88817841970012523233890533447265625"), // * 1125899906842624 + #| (16, "444089209850062616169452667236328125"), // * 2251799813685248 + #| (16, "2220446049250313080847263336181640625"), // * 4503599627370496 + #| (16, "11102230246251565404236316680908203125"), // * 9007199254740992 + #| (17, "55511151231257827021181583404541015625"), // * 18014398509481984 + #| (17, "277555756156289135105907917022705078125"), // * 36028797018963968 + #| (17, "1387778780781445675529539585113525390625"), // * 72057594037927936 + #| (18, "6938893903907228377647697925567626953125"), // * 144115188075855872 + #| (18, "34694469519536141888238489627838134765625"), // * 288230376151711744 + #| (18, "173472347597680709441192448139190673828125"), // * 576460752303423488 + #| (19, "867361737988403547205962240695953369140625"), // * 1152921504606846976 + #|] + #|fn Decimal::new_digits(self : Decimal, s : Int) -> Int { + #| let new_digits = left_shift_cheats[s].0 + #| let cheat_num = left_shift_cheats[s].1 + #| let less = for i in 0..= self.digits_num { + #| break true + #| } + #| let d = cheat_num.unsafe_get(i).to_int() - '0'.to_int() + #| if self.digits[i].to_int() != d { + #| break self.digits[i].to_int() < d + #| } + #| } nobreak { + #| false + #| } + #| if less { + #| new_digits - 1 + #| } else { + #| new_digits + #| } + #|} + #|fn Decimal::left_shift(self : Decimal, s : Int) -> Unit { + #| let new_digits = self.new_digits(s) + #| let mut read_index = self.digits_num + #| let mut write_index = self.digits_num + new_digits + #| let mut acc = 0L + #| read_index -= 1 + #| while read_index >= 0 { + #| let d = self.digits[read_index].to_int64() + #| acc += d << s + #| let quo = acc / 10L + #| let rem = (acc - quo * 10L).to_int() + #| write_index -= 1 + #| if write_index < self.digits.length() { + #| self.digits[write_index] = rem.to_byte() + #| } else if rem != 0 { + #| self.truncated = true + #| } + #| acc = quo + #| read_index -= 1 + #| } + #| while acc > 0L { + #| let quo = acc / 10L + #| let rem = (acc - 10L * quo).to_int() + #| write_index -= 1 + #| if write_index < self.digits.length() { + #| self.digits[write_index] = rem.to_byte() + #| } else if rem != 0 { + #| self.truncated = true + #| } + #| acc = quo + #| } + #| self.digits_num += new_digits + #| if self.digits_num > self.digits.length() { + #| self.digits_num = self.digits.length() + #| } + #| self.decimal_point += new_digits + #| self.trim() + #|} + #|fn Decimal::trim(self : Decimal) -> Unit { + #| while self.digits_num > 0 && self.digits[self.digits_num - 1] == 0 { + #| self.digits_num -= 1 + #| } + #| if self.digits_num == 0 { + #| self.decimal_point = 0 + #| } + #|} + #|pub impl Show for Decimal with output(self, logger) { + #| if self.digits_num == 0 { + #| logger.write_char('0') + #| return + #| } + #| if self.decimal_point <= 0 { + #| logger.write_string("0.") + #| for _ in 0..<-self.decimal_point { + #| logger.write_char('0') + #| } + #| for i in 0.. String { + #| Show::to_string(self) + #|} + #|test "new" { + #| let hpd = Decimal::from_int64_priv(1L) + #| inspect(hpd.digits.length(), content="800") + #| inspect(hpd.digits_num, content="1") + #| inspect(hpd.decimal_point, content="1") + #| inspect(hpd.negative, content="false") + #| inspect(hpd.truncated, content="false") + #|} + #|test "from_int64" { + #| let hpd = Decimal::from_int64_priv(123456789L) + #| inspect(hpd.to_string(), content="123456789") + #|} + #|test "parse_decimal" { + #| let s = "0.0000000000000000000000000000007888609052210118054117285652827862296732064351090230047702789306640625" + #| assert_eq(parse_decimal_priv(s).to_string(), s) + #| assert_eq(parse_decimal_priv("1.0e-10").to_string(), "0.0000000001") + #|} + #|test "to_string" { + #| let hpd = Decimal::from_int64_priv(123456789L) + #| hpd.decimal_point = 1 + #| inspect(hpd.to_string(), content="1.23456789") + #| hpd.decimal_point = 0 + #| inspect(hpd.to_string(), content="0.123456789") + #| hpd.decimal_point = -1 + #| inspect(hpd.to_string(), content="0.0123456789") + #| hpd.decimal_point = 10 + #| inspect(hpd.to_string(), content="1234567890") + #|} + #|test "shift" { + #| let tests : Array[_] = [ + #| (0L, 100, "0"), + #| (0L, -100, "0"), + #| (1L, 100, "1267650600228229401496703205376"), + #| ( + #| 1L, -100, "0.0000000000000000000000000000007888609052210118054117285652827862296732064351090230047702789306640625", + #| ), + #| (12345678L, 8, "3160493568"), + #| (12345678L, -8, "48225.3046875"), + #| (195312L, 9, "99999744"), + #| (1953125L, 9, "1000000000"), + #| ] + #| for t in tests { + #| let d = Decimal::from_int64_priv(t.0) + #| d.shift_priv(t.1) + #| assert_eq(d.to_string(), t.2) + #| } + #|} + #|test "parse decimal with underscore" { + #| inspect(parse_decimal_priv("1e1_2"), content="1000000000000") + #| inspect(parse_decimal_priv("1e12"), content="1000000000000") + #| inspect(parse_decimal_priv("1_2_3"), content="123") + #|} + #|test "parse decimal error" { + #| inspect(try? parse_decimal_priv("1e"), content="Err(invalid syntax)") + #| inspect(try? parse_decimal_priv("1e+"), content="Err(invalid syntax)") + #| inspect(try? parse_decimal_priv("1e_"), content="Err(invalid syntax)") + #| inspect(try? parse_decimal_priv("1-23"), content="Err(invalid syntax)") + #| inspect(try? parse_decimal_priv("1.2.3"), content="Err(invalid syntax)") + #|} + #|test "parse decimal with large numbers" { + #| let s = String::make(100, '9') + #| inspect(parse_decimal_priv(s), content=s) + #|} + #|test "should_round_up when truncated and half-way" { + #| let decimal = parse_decimal_priv("12.50") + #| inspect(decimal.to_double_priv(), content="12.5") + #|} + #|test "parse_decimal with large numbers and truncation" { + #| let s = String::make(1000, '9') + #| inspect(parse_decimal_priv(s), content=String::make(800, '9')) + #|} + #|test "rounded_integer overflow when decimal_point > 20" { + #| let decimal = Decimal::new_priv() + #| decimal.negative = false + #| decimal.decimal_point = 25 // This is > 20 but < 310 + #| decimal.digits_num = 1 + #| decimal.digits[0] = (1 : Int).to_byte() + #| decimal.truncated = false + #| let result = decimal.rounded_integer() + #| inspect(result, content="-1") // Should be Int64::max_value + #|} + #|test "corner cases" { + #| inspect(try? parse_decimal_priv(".123"), content="Ok(0.123)") + #| inspect(try? parse_decimal_priv("."), content="Err(invalid syntax)") + #| inspect(try? parse_decimal_priv("-"), content="Err(invalid syntax)") + #|} + #|test "parse_double mantissa normalization boundary" { + #| inspect(parse_double("1.9999999999999999"), content="2") + #| inspect(parse_double("9007199254740991.5"), content="9007199254740992") + #|} + ), + "deprecated.mbt": ( + #|#deprecated("Decimal will be changed to private. Use `@strconv.parse_double` instead", skip_current_package=true) + #|struct Decimal { + #| digits : FixedArray[Byte] + #| mut digits_num : Int + #| mut decimal_point : Int + #| mut negative : Bool + #| mut truncated : Bool + #|} + #|#deprecated("Decimal will be changed to private. Use `@strconv.parse_double` instead") + #|pub fn Decimal::new() -> Decimal { + #| Decimal::new_priv() + #|} + #|#deprecated("Decimal will be changed to private. Use `@strconv.parse_double` instead") + #|pub fn Decimal::from_int64(v : Int64) -> Decimal { + #| Decimal::from_int64_priv(v) + #|} + #|#deprecated("use `@strconv.parse_double` instead") + #|pub fn parse_decimal(str : StringView) -> Decimal raise StrConvError { + #| parse_decimal_from_view(str) + #|} + #|#deprecated("use `@strconv.parse_double` instead") + #|pub fn Decimal::parse_decimal(str : StringView) -> Decimal raise StrConvError { + #| parse_decimal_from_view(str) + #|} + #|#deprecated("use `@strconv.parse_double` instead to avoid using this method.") + #|pub fn Decimal::to_double(self : Decimal) -> Double raise StrConvError { + #| self.to_double_priv() + #|} + #|#deprecated("use `@strconv.parse_double` instead to avoid using this method.") + #|pub fn Decimal::shift(self : Decimal, s : Int) -> Unit { + #| self.shift_priv(s) + #|} + #|#deprecated("use `@strconv.from_str` instead") + #|pub fn[A : FromStr] parse(str : StringView) -> A raise StrConvError { + #| A::from_str(str) + #|} + ), + "double.mbt": ( + #|priv struct FloatInfo { + #| mantissa_bits : Int + #| exponent_bits : Int + #| bias : Int + #|} + #|let double_info : FloatInfo = { + #| mantissa_bits: 52, + #| exponent_bits: 11, + #| bias: -1023, + #|} + #|let mantissa_explicit_bits = 52 + #|let min_exponent_fast_path : Int64 = -22L + #|let max_exponent_fast_path : Int64 = 22L + #|let max_exponent_disguised_fast_path : Int64 = 37L + #|let max_mantissa_fast_path : UInt64 = 2UL << mantissa_explicit_bits + #|pub fn parse_double(str : StringView) -> Double raise StrConvError { + #| guard str.length() > 0 else { syntax_err() } + #| guard check_underscore(str) else { syntax_err() } + #| match parse_number(str) { + #| None => parse_inf_nan(str) + #| Some(num) => + #| match num.try_fast_path() { + #| Some(value) => value + #| None => parse_decimal_priv(str).to_double_priv() // fallback to slow path + #| } + #| } + #|} + #|fn Number::is_fast_path(self : Number) -> Bool { + #| min_exponent_fast_path <= self.exponent && + #| self.exponent <= max_exponent_disguised_fast_path && + #| self.mantissa <= max_mantissa_fast_path && + #| !self.many_digits + #|} + #|let table : ReadOnlyArray[Double] = [ + #| 1.0, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, 10000000.0, 100000000.0, + #| 1000000000.0, 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0, + #| 100000000000000.0, 1000000000000000.0, 10000000000000000.0, 100000000000000000.0, + #| 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0, 1000000000000000000000.0, + #| 10000000000000000000000.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + #|] + #|fn pow10_fast_path(exponent : Int) -> Double { + #| table[exponent & 31] + #|} + #|let int_pow10 : ReadOnlyArray[UInt64] = [ + #| 1UL, 10UL, 100UL, 1000UL, 10000UL, 100000UL, 1000000UL, 10000000UL, 100000000UL, + #| 1000000000UL, 10000000000UL, 100000000000UL, 1000000000000UL, 10000000000000UL, + #| 100000000000000UL, 1000000000000000UL, + #|] + #|fn Number::try_fast_path(self : Number) -> Double? { + #| if self.is_fast_path() { + #| let mut value = if self.exponent <= max_exponent_fast_path { + #| let value = Double::convert_uint64(self.mantissa) + #| if self.exponent < 0L { + #| value / pow10_fast_path(-self.exponent.to_int()) + #| } else { + #| value * pow10_fast_path(self.exponent.to_int()) + #| } + #| } else { + #| let shift = self.exponent - max_exponent_fast_path + #| let mantissa = match + #| checked_mul(self.mantissa, int_pow10[shift.to_int()]) { + #| Some(m) => m + #| None => return None + #| } + #| if mantissa > max_mantissa_fast_path { + #| return None + #| } + #| Double::convert_uint64(mantissa) * + #| pow10_fast_path(max_exponent_fast_path.to_int()) + #| } + #| if self.negative { + #| value = -value + #| } + #| Some(value) + #| } else { + #| None + #| } + #|} + #|test "parse_double" { + #| let tests : Array[(String, Result[Double, String])] = [ + #| ("", Err(syntax_err_str)), + #| ("1x", Err(syntax_err_str)), + #| ("1.1.", Err(syntax_err_str)), + #| ("1e", Err(syntax_err_str)), + #| ("1e-", Err(syntax_err_str)), + #| (".e-1", Err(syntax_err_str)), + #| ("1", Ok(1.0)), + #| ("+1", Ok(1.0)), + #| ("1e23", Ok(1.0e23)), + #| ("1E23", Ok(1.0e23)), + #| ("100000000000000000000000", Ok(1.0e23)), + #| ("1e-100", Ok(1.0e-100)), + #| ("123456700", Ok(1.234567e+08)), + #| ("99999999999999974834176", Ok(9.999999999999997e+22)), + #| ("100000000000000000000001", Ok(1.0000000000000001e+23)), + #| ("100000000000000008388608", Ok(1.0000000000000001e+23)), + #| ("100000000000000016777215", Ok(1.0000000000000001e+23)), + #| ("100000000000000016777216", Ok(1.0000000000000003e+23)), + #| ("-1", Ok(-1.0)), + #| ("-0.1", Ok(-0.1)), + #| ("-0", Ok(-0.0)), + #| ("1e-20", Ok(1.0e-20)), + #| ("625e-3", Ok(0.625)), + #| ("6.62607015e-34", Ok(6.62607015e-34)), + #| ("2.2250738585072012e-308", Ok(2.2250738585072014e-308)), + #| ("2.2250738585072011e-308", Ok(2.225073858507201e-308)), + #| ("0", Ok(0.0)), + #| ("0e0", Ok(0.0)), + #| ("-0e0", Ok(-0.0)), + #| ("+0e0", Ok(0.0)), + #| ("0e-0", Ok(0.0)), + #| ("-0e-0", Ok(-0.0)), + #| ("+0e-0", Ok(0.0)), + #| ("0e+0", Ok(0.0)), + #| ("-0e+0", Ok(-0.0)), + #| ("+0e+0", Ok(0.0)), + #| ("0e+01234567890123456789", Ok(0.0)), + #| ("0.00e-01234567890123456789", Ok(0.0)), + #| ("-0e+01234567890123456789", Ok(-0.0)), + #| ("-0.00e-01234567890123456789", Ok(-0.0)), + #| ("0e292", Ok(0.0)), + #| ("0e347", Ok(0.0)), + #| ("0e348", Ok(0.0)), + #| ("-0e291", Ok(-0.0)), + #| ("-0e292", Ok(-0.0)), + #| ("-0e347", Ok(-0.0)), + #| ("-0e348", Ok(-0.0)), + #| ("1.7976931348623157e308", Ok(1.7976931348623157e308)), + #| ("-1.7976931348623157e308", Ok(-1.7976931348623157e308)), + #| ("1.7976931348623158e308", Ok(1.7976931348623157e308)), + #| ("-1.7976931348623158e308", Ok(-1.7976931348623157e308)), + #| ("1e308", Ok(1.0e308)), + #| ( + #| "1.7976931348623159e308", + #| Err( + #| range_err_str, + #| ), + #| ), + #| ( + #| "-1.7976931348623159e308", + #| Err( + #| range_err_str, + #| ), + #| ), + #| ("2e308", Err(range_err_str)), + #| ("1e309", Err(range_err_str)), + #| ("1e310", Err(range_err_str)), + #| ("1e400", Err(range_err_str)), + #| ("1e40000", Err(range_err_str)), + #| ("1e-305", Ok(1.0e-305)), + #| ("1e-306", Ok(1.0e-306)), + #| ("1e-307", Ok(1.0e-307)), + #| ("1e-308", Ok(1.0e-308)), + #| ("1e-309", Ok(1.0e-309)), + #| ("1e-310", Ok(1.0e-310)), + #| ("1e-322", Ok(1.0e-322)), + #| ("5e-324", Ok(5.0e-324)), + #| ("4e-324", Ok(5.0e-324)), + #| ("3e-324", Ok(5.0e-324)), + #| ("2e-324", Ok(0.0)), + #| ("1e-350", Ok(0.0)), + #| ("1e-400000", Ok(0.0)), + #| ("1_23.50_0_0e+1_2", Ok(1.235e+14)), + #| ("-_123.5e+12", Err(syntax_err_str)), + #| ("+_123.5e+12", Err(syntax_err_str)), + #| ("_123.5e+12", Err(syntax_err_str)), + #| ("1__23.5e+12", Err(syntax_err_str)), + #| ("123_.5e+12", Err(syntax_err_str)), + #| ("123._5e+12", Err(syntax_err_str)), + #| ("123.5_e+12", Err(syntax_err_str)), + #| ("123.5__0e+12", Err(syntax_err_str)), + #| ("123.5e_+12", Err(syntax_err_str)), + #| ("123.5e+_12", Err(syntax_err_str)), + #| ("123.5e_-12", Err(syntax_err_str)), + #| ("123.5e-_12", Err(syntax_err_str)), + #| ("123.5e+1__2", Err(syntax_err_str)), + #| ("123.5e+12_", Err(syntax_err_str)), + #| ] + #| for t in tests { + #| assert_eq( + #| Result::Ok(parse_double(t.0)) catch { + #| StrConvError(err) => Err(err) + #| }, + #| t.1, + #| ) + #| } + #|} + #|test "parse_double_inf" { + #| assert_eq(parse_double("inf"), @double.infinity) + #| assert_eq(parse_double("+Inf"), @double.infinity) + #| assert_eq(parse_double("-Inf"), @double.neg_infinity) + #| assert_eq(parse_double("+Infinity"), @double.infinity) + #| assert_eq(parse_double("-Infinity"), @double.neg_infinity) + #| assert_eq(parse_double("+INFINITY"), @double.infinity) + #| assert_eq(parse_double("-INFINITY"), @double.neg_infinity) + #|} + #|test "parse_double_nan" { + #| assert_true(parse_double("nan").is_nan()) + #| assert_true(parse_double("NaN").is_nan()) + #| assert_true(parse_double("NAN").is_nan()) + #|} + ), + "errors.mbt": ( + #|pub(all) suberror StrConvError { + #| StrConvError(String) + #|} + #|pub impl Show for StrConvError with output(self, logger) { + #| match self { + #| StrConvError(err) => logger.write_string(err) + #| } + #|} + #|let range_err_str = "value out of range" + #|let syntax_err_str = "invalid syntax" + #|let base_err_str = "invalid base" + #|fn[T] range_err() -> T raise StrConvError { + #| raise StrConvError(range_err_str) + #|} + #|fn[T] syntax_err() -> T raise StrConvError { + #| raise StrConvError(syntax_err_str) + #|} + #|fn[T] base_err() -> T raise StrConvError { + #| raise StrConvError(base_err_str) + #|} + ), + "int.mbt": ( + #|const INT_MIN = 0x80000000 + #|const INT_MAX = 0x7fffffff + #|const INT64_MIN = -0x8000000000000000L + #|const INT64_MAX = 0x7fffffffffffffffL + #|fn check_and_consume_base( + #| view : StringView, + #| base : Int, + #|) -> (Int, StringView, Bool) raise StrConvError { + #| if base == 0 { + #| match view { + #| ['0', 'x' | 'X', .. rest] => (16, rest, true) + #| ['0', 'o' | 'O', .. rest] => (8, rest, true) + #| ['0', 'b' | 'B', .. rest] => (2, rest, true) + #| _ => (10, view, false) + #| } + #| } else { + #| match view { + #| ['0', 'x' | 'X', .. rest] if base == 16 => (16, rest, true) + #| ['0', 'o' | 'O', .. rest] if base == 8 => (8, rest, true) + #| ['0', 'b' | 'B', .. rest] if base == 2 => (2, rest, true) + #| _ => if base is (2..=36) { (base, view, false) } else { base_err() } + #| } + #| } + #|} + #|test { + #| inspect(try? parse_int64("0b01", base=3), content="Err(invalid syntax)") + #| inspect(try? parse_int64("0x01", base=3), content="Err(invalid syntax)") + #| inspect(try? parse_int64("0o01", base=3), content="Err(invalid syntax)") + #|} + #|pub fn parse_int64( + #| str : StringView, + #| base? : Int = 0, + #|) -> Int64 raise StrConvError { + #| guard str != "" else { syntax_err() } + #| let (neg, rest) = match str.view() { + #| ['+', .. rest] => (false, rest) + #| ['-', .. rest] => (true, rest) + #| rest => (false, rest) + #| } + #| let (num_base, rest, allow_underscore) = check_and_consume_base(rest, base) + #| let overflow_threshold = overflow_threshold(num_base, neg) + #| let has_digit = rest + #| is (['0'..='9' | 'a'..='z' | 'A'..='Z', ..] + #| | ['_', '0'..='9' | 'a'..='z' | 'A'..='Z', ..]) + #| guard has_digit else { syntax_err() } + #| loop (rest, 0L, allow_underscore) { + #| (['_'], _, _) => + #| syntax_err() + #| (['_', ..], _, false) => syntax_err() + #| (['_', .. rest], acc, true) => continue (rest, acc, false) + #| ([c, .. rest], acc, _) => { + #| let c = c.to_int() + #| let d = match c { + #| '0'..='9' => c - '0' + #| 'a'..='z' => c + (10 - 'a') + #| 'A'..='Z' => c + (10 - 'A') + #| _ => syntax_err() + #| } + #| guard d < num_base else { syntax_err() } + #| if neg { + #| guard acc >= overflow_threshold else { range_err() } + #| let next_acc = acc * num_base.to_int64() - d.to_int64() + #| guard next_acc <= acc else { range_err() } + #| continue (rest, next_acc, true) + #| } else { + #| guard acc < overflow_threshold else { range_err() } + #| let next_acc = acc * num_base.to_int64() + d.to_int64() + #| guard next_acc >= acc else { range_err() } + #| continue (rest, next_acc, true) + #| } + #| } + #| ([], acc, _) => acc + #| } + #|} + #|pub fn parse_int(str : StringView, base? : Int = 0) -> Int raise StrConvError { + #| let n = parse_int64(str, base~) + #| if n < INT_MIN.to_int64() || n > INT_MAX.to_int64() { + #| range_err() + #| } + #| n.to_int() + #|} + #|fn check_underscore(str : StringView) -> Bool { + #| let rest = match str { + #| ['+' | '-', .. rest] => rest + #| rest => rest + #| } + #| let (rest, allow_underscore, hex) = lexmatch rest { + #| ("0[xX]", rest) => (rest, true, true) + #| ("0[oO]", rest) => (rest, true, false) + #| ("0[bB]", rest) => (rest, true, false) + #| _ => (rest, false, false) + #| } + #| fn is_digit(c : Char) -> Bool { + #| c is ('0'..='9') || (hex && c is ('a'..='f' | 'A'..='F')) + #| } + #| let follow_underscore = false + #| loop (rest, allow_underscore, follow_underscore) { + #| ([], _, _) => true + #| (['_'], _, _) => false + #| (['_', ..], false, _) => false + #| (['_', .. rest], true, _) => continue (rest, false, true) + #| ([c, .. rest], _, follow_underscore) => + #| if is_digit(c) { + #| continue (rest, true, false) + #| } else if follow_underscore { + #| false + #| } else { + #| continue (rest, false, false) + #| } + #| } + #|} + #|fn overflow_threshold(base : Int, neg : Bool) -> Int64 { + #| if !neg { + #| if base == 10 { + #| INT64_MAX / 10L + 1L + #| } else if base == 16 { + #| INT64_MAX / 16L + 1L + #| } else { + #| INT64_MAX / base.to_int64() + 1L + #| } + #| } else if base == 10 { + #| INT64_MIN / 10L + #| } else if base == 16 { + #| INT64_MIN / 16L + #| } else { + #| INT64_MIN / base.to_int64() + #| } + #|} + ), + "number.mbt": ( + #|let min_19digit_int : UInt64 = 100_0000_0000_0000_0000UL + #|priv struct Number { + #| exponent : Int64 + #| mantissa : UInt64 + #| negative : Bool + #| many_digits : Bool + #|} + #|fn parse_digits(s : StringView, x : UInt64) -> (StringView, UInt64, Int) { + #| s.fold_digits(x, (digit, acc : UInt64) => { + #| acc * 10UL + UInt64::extend_uint(digit.reinterpret_as_uint()) + #| }) + #|} + #|fn try_parse_19digits(s : StringView, x : UInt64) -> (StringView, UInt64, Int) { + #| let mut x = x + #| let mut len = 0 + #| loop s { + #| ['0'..='9' as ch, .. rest] if x < min_19digit_int => { + #| len += 1 + #| x = x * 10UL + + #| UInt64::extend_uint((ch.to_int() - '0').reinterpret_as_uint()) // no overflows here + #| continue rest + #| } + #| ['_', .. rest] => continue rest + #| s => return (s, x, len) + #| } + #|} + #|fn parse_scientific(s : StringView) -> (StringView, Int64)? { + #| let mut s = s + #| let exp_num = 0L + #| let mut neg_exp = false + #| if s is ['+' | '-' as ch, .. rest] { + #| neg_exp = ch == '-' + #| s = rest + #| } + #| if s is ['0'..='9', ..] { + #| let (s, exp_num, _) = s.fold_digits(exp_num, (digit, exp_num : Int64) => { + #| if exp_num < 0x10000L { + #| 10L * exp_num + digit.to_int64() // no overflows here + #| } else { + #| exp_num + #| } + #| }) + #| if neg_exp { + #| Some((s, -exp_num)) + #| } else { + #| Some((s, exp_num)) + #| } + #| } else { + #| None + #| } + #|} + #|fn parse_number(s : StringView) -> Number? raise StrConvError { + #| let start = s + #| let (s, negative) = match s { + #| ['-', .. rest] => (rest, true) + #| ['+', .. rest] | rest => (rest, false) + #| } + #| if s.is_empty() { + #| return None + #| } + #| let (s, mantissa, consumed) = parse_digits(s, 0UL) + #| let mut mantissa = mantissa + #| let mut s = s + #| let mut n_digits = consumed + #| let mut n_after_dot = 0 + #| let mut exponent = 0L + #| if s is ['.', .. rest] { + #| s = rest + #| let (new_s, new_mantissa, consumed_digit) = parse_digits(s, mantissa) + #| s = new_s + #| mantissa = new_mantissa + #| n_after_dot = consumed_digit + #| exponent = -n_after_dot.to_int64() + #| } + #| n_digits += n_after_dot + #| if n_digits == 0 { + #| return None + #| } + #| let exp_number = 0L + #| if s is ['e' | 'E', .. rest] { + #| let (new_s, exp_number) = match parse_scientific(rest) { + #| Some(res) => res + #| None => return None + #| } + #| s = new_s + #| exponent += exp_number + #| } + #| guard s is "" else { syntax_err() } + #| if n_digits <= 19 { + #| return Some({ exponent, mantissa, negative, many_digits: false }) + #| } + #| n_digits -= 19 + #| let mut many_digits = false + #| loop start { + #| ['0' | '.' as ch, .. rest] => { + #| n_digits -= (ch.to_int() - 46) / 2 // '0' = b'.' + 2 + #| continue rest + #| } + #| _ => () + #| } + #| let mut mantissa = mantissa + #| if n_digits > 0 { + #| many_digits = true + #| mantissa = 0UL + #| let s = start + #| let (s, new_mantissa, consumed_digit) = try_parse_19digits(s, mantissa) + #| mantissa = new_mantissa + #| exponent = (if mantissa >= min_19digit_int { + #| consumed_digit // big int + #| } else { + #| guard s is [_, .. s] else { return None } + #| let (_, new_mantissa, consumed_digit) = try_parse_19digits(s, mantissa) + #| mantissa = new_mantissa + #| consumed_digit + #| }).to_int64() + #| exponent += exp_number + #| } // add back the explicit part + #| Some({ exponent, mantissa, negative, many_digits }) + #|} + #|fn parse_inf_nan(rest : StringView) -> Double raise StrConvError { + #| let (pos, rest) = match rest { + #| ['-', .. rest] => (false, rest) + #| ['+', .. rest] | rest => (true, rest) + #| } + #| lexmatch rest { + #| "(?i:nan)" => @double.not_a_number + #| "(?i:inf(inity)?)" => + #| if pos { + #| @double.infinity + #| } else { + #| @double.neg_infinity + #| } + #| _ => syntax_err() + #| } + #|} + #|fn checked_mul(a : UInt64, b : UInt64) -> UInt64? { + #| if a == 0UL || b == 0UL { + #| return Some(0UL) + #| } + #| if a == 1UL { + #| return Some(b) + #| } + #| if b == 1UL { + #| return Some(a) + #| } + #| if b.clz() == 0 || a.clz() == 0 { + #| return None + #| } + #| let quotient : UInt64 = @uint64.MAX_VALUE / b + #| if a > quotient { + #| return None + #| } + #| Some(a * b) + #|} + ), + "string_view.mbt": ( + #|fn[T] StringView::fold_digits( + #| self : Self, + #| init : T, + #| f : (Int, T) -> T, + #|) -> (Self, T, Int) { + #| let mut ret = init + #| let mut len = 0 + #| let mut str = self + #| while str is [ch, .. rest] { + #| if ch is ('0'..='9') { + #| len += 1 + #| ret = f(ch.to_int() - '0', ret) + #| } else if ch != '_' { + #| break + #| } + #| str = rest + #| } + #| (str, ret, len) + #|} + ), + "traits.mbt": ( + #|pub(open) trait FromStr { + #| #as_free_fn + #| from_str(StringView) -> Self raise StrConvError = _ + #| #deprecated("use `from_str` instead", skip_current_package=true) + #| from_string(String) -> Self raise StrConvError = _ + #|} + #|#deprecated("replace `impl from_string` with `impl from_str`") + #|impl FromStr with from_str(str) { + #| FromStr::from_string(str.to_string()) + #|} + #|impl FromStr with from_string(str) { + #| FromStr::from_str(str) + #|} + #|pub impl FromStr for Bool with from_str(str) { + #| parse_bool(str) + #|} + #|pub impl FromStr for Int with from_str(str) { + #| parse_int(str) + #|} + #|pub impl FromStr for Int64 with from_str(str) { + #| parse_int64(str) + #|} + #|pub impl FromStr for UInt with from_str(str) { + #| parse_uint(str) + #|} + #|pub impl FromStr for UInt64 with from_str(str) { + #| parse_uint64(str) + #|} + #|pub impl FromStr for Double with from_str(str) { + #| parse_double(str) + #|} + #|test "parse" { + #| let b : Bool = from_str("true") + #| inspect(b, content="true") + #| let i : Int = from_str("12345") + #| inspect(i, content="12345") + #| let i64 : Int64 = from_str("9223372036854775807") + #| assert_eq(i64, 9223372036854775807L) + #| let ui : UInt = from_str("4294967295") + #| inspect(ui, content="4294967295") + #| let ui64 : UInt64 = from_str("18446744073709551615") + #| assert_eq(ui64, 18446744073709551615UL) + #| let d : Double = from_str("1234.56789") + #| assert_eq(d, 1234.56789) + #|} + ), + "uint.mbt": ( + #|const UINT_MAX : UInt = 0xffffffff + #|const UINT64_MAX : UInt64 = 0xffffffffffffffffUL + #|pub fn parse_uint64( + #| str : StringView, + #| base? : Int = 0, + #|) -> UInt64 raise StrConvError { + #| guard str != "" else { syntax_err() } + #| if str is ['+' | '-', ..] { + #| syntax_err() + #| } + #| let (num_base, rest, allow_underscore) = check_and_consume_base(str, base) + #| let overflow_threshold = match num_base { + #| 10 => UINT64_MAX / 10 + 1 + #| 16 => UINT64_MAX / 16 + 1 + #| _ => UINT64_MAX / num_base.to_uint64() + 1 + #| } + #| let has_digit = rest + #| is (['0'..='9' | 'a'..='z' | 'A'..='Z', ..] + #| | ['_', '0'..='9' | 'a'..='z' | 'A'..='Z', ..]) + #| guard has_digit else { syntax_err() } + #| loop (rest, 0UL, allow_underscore) { + #| (['_'], _, _) => + #| syntax_err() + #| (['_', ..], _, false) => syntax_err() + #| (['_', .. rest], acc, true) => continue (rest, acc, false) + #| ([c, .. rest], acc, _) => { + #| let c = c.to_int() + #| let d = match c { + #| '0'..='9' => c - '0' + #| 'a'..='z' => c + (10 - 'a') + #| 'A'..='Z' => c + (10 - 'A') + #| _ => syntax_err() + #| } + #| guard d < num_base else { syntax_err() } + #| guard acc < overflow_threshold else { range_err() } + #| let next_acc = acc * num_base.to_uint64() + d.to_uint64() + #| guard next_acc >= acc && next_acc <= UINT64_MAX else { range_err() } + #| continue (rest, next_acc, true) + #| } + #| ([], acc, _) => acc + #| } + #|} + #|pub fn parse_uint(str : StringView, base? : Int = 0) -> UInt raise StrConvError { + #| let n = parse_uint64(str, base~) + #| if n > UINT_MAX.to_uint64() { + #| range_err() + #| } + #| n.to_uint() + #|} + #|test "parse_uint64" { + #| let tests : Array[(String, Result[UInt64, String])] = [ + #| ("", Err(syntax_err_str)), + #| ("0", Ok(0UL)), + #| ("-0", Err(syntax_err_str)), + #| ("+0", Err(syntax_err_str)), + #| ("1", Ok(1UL)), + #| ("-1", Err(syntax_err_str)), + #| ("12345", Ok(12345UL)), + #| ("-12345", Err(syntax_err_str)), + #| ("012345", Ok(12345UL)), + #| ("9876543210", Ok(9876543210UL)), + #| ("18446744073709551615", Ok(18446744073709551615UL)), + #| ("18446744073709551616", Err(range_err_str)), + #| ("1_2_3_4_5", Ok(12345UL)), + #| ("_12345", Err(syntax_err_str)), + #| ("1__2345", Err(syntax_err_str)), + #| ("12345_", Err(syntax_err_str)), + #| ("12345%", Err(syntax_err_str)), + #| ] + #| for t in tests { + #| assert_eq( + #| Result::Ok(parse_uint64(t.0)) catch { + #| StrConvError(err) => Err(err) + #| }, + #| t.1, + #| ) + #| } + #|} + #|test "parse_uint64_base" { + #| let tests : Array[(String, Int, Result[UInt64, String])] = [ + #| ("", 0, Err(syntax_err_str)), + #| ("0", 0, Ok(0UL)), + #| ("1", 0, Ok(1UL)), + #| ("12345", 0, Ok(12345UL)), + #| ("012345", 0, Ok(12345UL)), + #| ("0x12345", 0, Ok(0x12345UL)), + #| ("9876543210", 0, Ok(9876543210UL)), + #| ("18446744073709551615", 0, Ok(UINT64_MAX)), + #| ("0xffffffffffffffff", 0, Ok(UINT64_MAX)), + #| ("18446744073709551616", 0, Err(range_err_str)), + #| ("12345x", 0, Err(syntax_err_str)), + #| ("-12345x", 0, Err(syntax_err_str)), + #| ("h", 18, Ok(17UL)), + #| ("10", 25, Ok(25UL)), + #| ( + #| "moonbit", + #| 35, + #| Ok( + #| ( + #| ((((22UL * 35UL + 24UL) * 35UL + 24UL) * 35UL + 23UL) * 35UL + 11UL) * + #| 35UL + + #| 18UL + #| ) * + #| 35UL + + #| 29UL, + #| ), + #| ), + #| ( + #| "moonbit", + #| 36, + #| Ok( + #| ( + #| ((((22UL * 36UL + 24UL) * 36UL + 24UL) * 36UL + 23UL) * 36UL + 11UL) * + #| 36UL + + #| 18UL + #| ) * + #| 36UL + + #| 29UL, + #| ), + #| ), + #| ("0", 2, Ok(0UL)), + #| ("-1", 2, Err(syntax_err_str)), + #| ("1010", 2, Ok(10UL)), + #| ("1000000000000000", 2, Ok(1UL << 15)), + #| ( + #| "1111111111111111111111111111111111111111111111111111111111111111", + #| 2, + #| Ok(UINT64_MAX), + #| ), + #| ( + #| "1000000000000000000000000000000000000000000000000000000000000000", + #| 2, + #| Ok(1UL << 63), + #| ), + #| ("10", 8, Ok(8UL)), + #| ("57635436545", 8, Ok(0o57635436545UL)), + #| ("100000000", 8, Ok(1UL << 24)), + #| ("10", 16, Ok(16UL)), + #| ("ffffffffffffffff", 16, Ok(UINT64_MAX)), + #| ("0x_1_2_3_4_5", 0, Ok(0x12345UL)), + #| ("-_0x12345", 0, Err(syntax_err_str)), + #| ("_-0x12345", 0, Err(syntax_err_str)), + #| ("_0x12345", 0, Err(syntax_err_str)), + #| ("0x__12345", 0, Err(syntax_err_str)), + #| ("0x1__2345", 0, Err(syntax_err_str)), + #| ("0x1234__5", 0, Err(syntax_err_str)), + #| ("0x12345_", 0, Err(syntax_err_str)), + #| ("0_1_2_3_4_5", 0, Ok(12345UL)), + #| ("-_012345", 0, Err(syntax_err_str)), + #| ("_-012345", 0, Err(syntax_err_str)), + #| ("_012345", 0, Err(syntax_err_str)), + #| ("0__12345", 0, Err(syntax_err_str)), + #| ("01234__5", 0, Err(syntax_err_str)), + #| ("012345_", 0, Err(syntax_err_str)), + #| ("0xf", 0, Ok(0xfUL)), + #| ("-0xf", 0, Err(syntax_err_str)), + #| ("0x+f", 0, Err(syntax_err_str)), + #| ("0x-f", 0, Err(syntax_err_str)), + #| ] + #| for t in tests { + #| assert_eq( + #| Result::Ok(parse_uint64(t.0, base=t.1)) catch { + #| StrConvError(err) => Err(err) + #| }, + #| t.2, + #| ) + #| } + #|} + #|test "parse_uint" { + #| let tests : Array[(String, Result[UInt, String])] = [ + #| ("", Err(syntax_err_str)), + #| ("0", Ok(0)), + #| ("-0", Err(syntax_err_str)), + #| ("+0", Err(syntax_err_str)), + #| ("1", Ok(1)), + #| ("-1", Err(syntax_err_str)), + #| ("12345", Ok(12345)), + #| ("012345", Ok(12345)), + #| ("12345x", Err(syntax_err_str)), + #| ("-12345x", Err(syntax_err_str)), + #| ("987654321", Ok(987654321)), + #| ("4294967295", Ok(UINT_MAX)), + #| ("0xffffffff", Ok(UINT_MAX)), + #| ("4294967296", Err(range_err_str)), + #| ("1_2_3_4_5", Ok(12345)), + #| ("-_12345", Err(syntax_err_str)), + #| ("_12345", Err(syntax_err_str)), + #| ("1__2345", Err(syntax_err_str)), + #| ("12345_", Err(syntax_err_str)), + #| ("123%45", Err(syntax_err_str)), + #| ] + #| for t in tests { + #| assert_eq( + #| Result::Ok(parse_uint(t.0)) catch { + #| StrConvError(err) => Err(err) + #| }, + #| t.1, + #| ) + #| } + #|} + #|test "parse_uint64 uppercase hex and invalid base" { + #| inspect(try? parse_uint64("ABCD", base=16), content="Ok(43981)") + #| inspect(try? parse_uint64("1234", base=37), content="Err(invalid base)") + #|} + ) + } ) ///| let moonbitlang_core_string_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/string", - deps={ - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/char": moonbitlang_core_char_module, - }, - files={ - "moon.pkg.json": ( - #|{ - #| "import": ["moonbitlang/core/builtin", "moonbitlang/core/char"], - #| "test-import": [ - #| "moonbitlang/core/list", - #| "moonbitlang/core/json", - #| "moonbitlang/core/array", - #| "moonbitlang/core/quickcheck", - #| { - #| "path": "moonbitlang/core/encoding/utf8", - #| "alias": "encoding/utf8" - #| }, - #| { - #| "path": "moonbitlang/core/encoding/utf16", - #| "alias": "encoding/utf16" - #| } - #| ], - #| "targets": { - #| "panic_test.mbt": ["not", "native", "llvm"] - #| } - #|} - ), - "string.mbt": ( - #|#deprecated - #|pub fn from_array(chars : ArrayView[Char]) -> String { - #| String::from_array(chars) - #|} - #|#deprecated - #|pub fn from_iter(iter : Iter[Char]) -> String { - #| String::from_iter(iter) - #|} - #|#deprecated - #|pub fn from_iterator(iter : Iterator[Char]) -> String { - #| String::from_iterator(iter) - #|} - #|pub fn default() -> String { - #| "" - #|} - ), - "utils.mbt": ( - #|fn code_point_of_surrogate_pair(leading : UInt16, trailing : UInt16) -> Char { - #| ((leading - 0xD800).to_int() * 0x400 + trailing.to_int() - 0xDC00 + 0x10000).unsafe_to_char() - #|} - #|test "code_point_of_surrogate_pair" { - #| let s = "😀" - #| let leading = s.code_unit_at(0) - #| let trailing = s.code_unit_at(1) - #| inspect(code_point_of_surrogate_pair(leading, trailing), content="😀") - #|} - #|test "is_leading_surrogate" { - #| inspect("🤣".code_unit_at(0).is_leading_surrogate(), content="true") - #| inspect("🤣".code_unit_at(1).is_leading_surrogate(), content="false") - #|} - #|test "is_trailing_surrogate" { - #| inspect("🤣".code_unit_at(0).is_trailing_surrogate(), content="false") - #| inspect("🤣".code_unit_at(1).is_trailing_surrogate(), content="true") - #|} - #|test "is_surrogate" { - #| inspect((0xD800).is_surrogate(), content="true") // Leading surrogate - #| inspect((0xDBFF).is_surrogate(), content="true") // Leading surrogate - #| inspect((0xDC00).is_surrogate(), content="true") // Trailing surrogate - #| inspect((0xDFFF).is_surrogate(), content="true") // Trailing surrogate - #| inspect((0xD7FF).is_surrogate(), content="false") // Just before surrogates - #| inspect((0xE000).is_surrogate(), content="false") // Just after surrogates - #| inspect((0x41).is_surrogate(), content="false") // Regular ASCII 'A' - #|} - ), - "view.mbt": ( - #|#deprecated("Use `StringView` instead") - #|pub type View = StringView - #|pub using @builtin {trait ToStringView} - ), - }, -) - -///| -let moonbitlang_core_string_regex_module : RuntimePackage = RuntimePackage::new( - "moonbitlang/core/string/regex", - deps={ - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "regex_impl": moonbitlang_core_string_regex_internal_regexp_module, - }, - files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| "moonbitlang/core/builtin", - #| { "path": "moonbitlang/core/string/regex/internal/regexp", "alias": "regex_impl" } - #| ], - #| "test-import": [ - #| "moonbitlang/core/option", - #| "moonbitlang/core/error", - #| "moonbitlang/core/string" - #| ] - #|} - ), - "regex.mbt": ( - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|struct MatchResult(@regex_impl.MatchResult, @regex_impl.Regexp) - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn MatchResult::before(self : Self) -> StringView { - #| self.0.before() - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn MatchResult::after(self : Self) -> StringView { - #| self.0.after() - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn MatchResult::content(self : Self) -> StringView { - #| self.0.get(0).unwrap() - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn MatchResult::group(self : Self, index : Int) -> StringView? { - #| self.0.get(index) - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn MatchResult::named_group(self : Self, name : String) -> StringView? { - #| if self.1.group_by_name(name) is Some(index) { - #| self.0.get(index) - #| } else { - #| None - #| } - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|struct Regex(@regex_impl.Regexp) - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn compile(pattern : StringView) -> Regex raise { - #| @regex_impl.compile(pattern) - #|} - #|#internal(experimental, "subject to breaking change without notice") - #|#doc(hidden) - #|pub fn Regex::execute(self : Self, input : StringView) -> MatchResult? { - #| match self.0.match_(input) { - #| None => None - #| Some(result) => Some(MatchResult(result, self.0)) - #| } - #|} - ), - }, -) - -///| -let moonbitlang_core_string_regex_internal_regexp_module : RuntimePackage = RuntimePackage::new( - "moonbitlang/core/string/regex/internal/regexp", - deps={ - "moonbitlang/core/string/regex/internal/regexp/internal/parse": moonbitlang_core_string_regex_internal_regexp_internal_parse_module, - "moonbitlang/core/string/regex/internal/regexp/internal/vm": moonbitlang_core_string_regex_internal_regexp_internal_vm_module, - "moonbitlang/core/string/regex/internal/regexp/internal/ast": moonbitlang_core_string_regex_internal_regexp_internal_ast_module, - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/array": moonbitlang_core_array_module, - "moonbitlang/core/string": moonbitlang_core_string_module, - }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| "moonbitlang/core/string/regex/internal/regexp/internal/parse", - #| "moonbitlang/core/string/regex/internal/regexp/internal/vm", - #| "moonbitlang/core/string/regex/internal/regexp/internal/ast", - #| "moonbitlang/core/builtin", - #| "moonbitlang/core/array", - #| "moonbitlang/core/string" - #| ], - #| "test-import": [ - #| "moonbitlang/core/option" - #| ], - #| "wbtest-import": [ - #| "moonbitlang/core/json", - #| "moonbitlang/core/result" - #| ] - #|} - ), - "alias.mbt": ( - #|pub using @parse {type RegexpError} - #|using @parse {parse, type ParseResult} - #|using @vm {type Instruction, vm} - ), - "todo.mbt": ( - #|test "to be discussed" { - #| parse("[][]").ast - #| |> inspect( - #| content="Concat([CharClass([], neg=false), CharClass([], neg=false)])", - #| ) - #|} - #|test "to be fixed" { - #| let result = parse("(|a)*").compile().execute("aaa") - #| inspect( - #| result.get(0), - #| content=( - #| #|Some("") - #| ), - #| ) - #| let result = parse("(|a)+").compile().execute("aaa") - #| inspect( - #| result.get(0), - #| content=( - #| #|Some("") - #| ), - #| ) - #|} - ), - "top.mbt": ( - #|struct Regexp { - #| instructions : Array[Instruction] - #| map : Map[String, Int] - #| capture : Int - #|} - #|fn ParseResult::compile(self : Self) -> Regexp { - #| { - #| instructions: self.ast.compile(), - #| map: self.capture_map, - #| capture: self.captures, - #| } - #|} - #|pub fn compile( - #| regexp : StringView, - #| flags? : StringView = "", - #|) -> Regexp raise RegexpError { - #| regexp - #| |> parse(flags={ - #| multiline: flags.contains("m"), - #| singleline: flags.contains("s"), - #| ignore_case: flags.contains("i"), - #| }) - #| |> ParseResult::compile() - #|} - #|pub fn Regexp::group_by_name(self : Regexp, name : String) -> Int? { - #| self.map.get(name) - #|} - #|pub fn Regexp::group_count(self : Regexp) -> Int { - #| self.capture - #|} - #|pub fn Regexp::group_names(self : Regexp) -> Array[String] { - #| self.map.keys().collect() - #|} - #|pub fn Regexp::execute(self : Regexp, input : StringView) -> MatchResult { - #| let captures = vm(self.instructions, input, self.capture) - #| let (before, after) = if captures is [0..<_ as start, 0..<_ as end, ..] { - #| (input.view(end_offset=start), input.view(start_offset=end)) - #| } else { - #| (input, input.view(start_offset=input.length())) - #| } - #| { input, captures, names: self.map, before, after } - #|} - #|#deprecated("Use `Regexp::execute` and `MatchResult::before`/`after` instead.") - #|pub fn Regexp::execute_with_remainder( - #| self : Regexp, - #| input : StringView, - #|) -> (MatchResult, StringView) { - #| let captures = vm(self.instructions, input, self.capture) - #| if captures is [0..<_ as start, 0..<_ as end, ..] { - #| ( - #| { - #| input, - #| captures, - #| names: self.map, - #| before: input.view(end_offset=start), - #| after: input.view(start_offset=end), - #| }, - #| input.view(start_offset=end), - #| ) - #| } else { - #| ( - #| { - #| input, - #| captures, - #| names: self.map, - #| before: input, - #| after: input.view(start_offset=input.length()), - #| }, - #| input, - #| ) - #| } - #|} - #|pub fn Regexp::match_(self : Regexp, input : StringView) -> MatchResult? { - #| let captures = vm(self.instructions, input, self.capture) - #| guard captures is [0..<_ as start, 0..<_ as end, ..] else { return None } - #| let before = input.view(end_offset=start) - #| let after = input.view(start_offset=end) - #| Some({ input, captures, names: self.map, before, after }) - #|} - #|struct MatchResult { - #| input : StringView - #| captures : Array[Int] - #| names : Map[String, Int] - #| before : StringView - #| after : StringView - #|} - #|pub fn MatchResult::matched(self : Self) -> Bool { - #| not(self.captures is []) - #|} - #|pub fn MatchResult::get(self : Self, index : Int) -> StringView? { - #| if self.captures.is_empty() || - #| index < 0 || - #| index >= self.captures.length() / 2 { - #| return None - #| } - #| let start = self.captures[index * 2] - #| let end = self.captures[index * 2 + 1] - #| if start < 0 || end < start || end > self.input.length() { - #| return None - #| } - #| Some(self.input.view(start_offset=start, end_offset=end)) - #|} - #|pub fn MatchResult::groups(self : Self) -> Map[String, StringView] { - #| self.names - #| .iter() - #| .filter_map(p => if self.get(p.1) is Some(content) { - #| Some((p.0, content)) - #| } else { - #| None - #| }) - #| |> Map::from_iter - #|} - #|pub fn MatchResult::results(self : Self) -> Array[StringView?] { - #| let results = [] - #| for i = 0; i < self.captures.length() / 2; i = i + 1 { - #| let start = self.captures[i * 2] - #| let end = self.captures[i * 2 + 1] - #| if start == -1 && end == -1 { - #| results.push(None) - #| } else { - #| results.push(Some(self.input.view(start_offset=start, end_offset=end))) - #| } - #| } - #| results - #|} - #|pub fn MatchResult::before(self : Self) -> StringView { - #| self.before - #|} - #|pub fn MatchResult::after(self : Self) -> StringView { - #| self.after - #|} - #|test "rest method" { - #| let engine = compile("hello") - #| let result = engine.execute("hello world") - #| inspect(result.matched(), content="true") - #| inspect(result.before(), content="") - #| inspect(result.after(), content=" world") - #| let result2 = engine.execute("say hello") - #| inspect(result2.matched(), content="true") - #| inspect(result2.before(), content="say ") - #| inspect(result2.after(), content="") - #| let result3 = engine.execute("hi there") - #| inspect(result3.matched(), content="false") - #| inspect(result3.before(), content="hi there") - #| inspect(result3.after(), content="") - #| inspect("Test rest method completed", content="Test rest method completed") - #|} - #|test "rest method with capture groups" { - #| let engine = compile("(\\w+)\\s+") - #| let result = engine.execute("hello world test") - #| inspect(result.matched(), content="true") - #| inspect( - #| result.get(0), - #| content=( - #| #|Some("hello ") - #| ), - #| ) - #| inspect( - #| result.get(1), - #| content=( - #| #|Some("hello") - #| ), - #| ) - #| inspect(result.after(), content="world test") - #| let engine2 = compile(".*") - #| let result2 = engine2.execute("everything") - #| inspect(result2.matched(), content="true") - #| inspect( - #| result2.get(0), - #| content=( - #| #|Some("everything") - #| ), - #| ) - #| inspect(result2.after(), content="") - #|} - #|test "rest method usage example" { - #| let engine = compile("\\b\\w+\\b") - #| let mut input : StringView = "word1 word2 word3" - #| let result1 = engine.execute(input) - #| inspect( - #| result1.get(0), - #| content=( - #| #|Some("word1") - #| ), - #| ) - #| input = result1.after() - #| let result2 = engine.execute(input) - #| inspect( - #| result2.get(0), - #| content=( - #| #|Some("word2") - #| ), - #| ) - #| inspect(result2.after(), content=" word3") - #|} - ), - }, + "regex.mbt": ( + #|pub struct Regex { + #| priv pat : @re.Pattern + #| priv mut re : @re.Regex? + #| fn new(pattern : StringView) -> Regex raise + #|} + #|const MAX_REPEAT_QUANTIFIER = 256 + #|using @debug {trait Debug, type Repr} + #|struct MatchResult { + #| input : StringView + #| group_names : ReadOnlyArray[String?] + #| result : @re.MatchResult + #|} derive(Debug) + #|pub fn MatchResult::before(self : MatchResult) -> StringView { + #| guard self.result.group(0) is Some((start, _end)) else { panic() } + #| self.input[0:start] + #|} + #|pub fn MatchResult::after(self : MatchResult) -> StringView { + #| guard self.result.group(0) is Some((_start, end)) else { panic() } + #| self.input[end:self.input.length()] + #|} + #|pub fn MatchResult::content(self : MatchResult) -> StringView { + #| guard self.result.group(0) is Some((start, end)) else { panic() } + #| self.input[start:end] + #|} + #|pub fn MatchResult::group(self : MatchResult, group_index : Int) -> StringView? { + #| match self.result.group(group_index) { + #| None => None + #| Some((start, end)) => Some(self.input[start:end]) + #| } + #|} + #|pub fn MatchResult::named_group( + #| self : MatchResult, + #| name : String, + #|) -> StringView? { + #| match self.group_names.search(Some(name)) { + #| None => None + #| Some(index) => self.group(index) + #| } + #|} + #|#internal(internal, "not intended for public use") + #|#doc(hidden) + #|pub fn Regex::internal_compile_pattern(pat : Pattern) -> Regex { + #| let lowered_pat = re_lower_to_utf16(pat.0) + #| { pat: pat.0, re: Some(@re.compile(profile=re_profile_utf16, lowered_pat)) } + #|} + #|#internal(internal, "not intended for public use") + #|#doc(hidden) + #|pub fn Regex::internal_from_string(pat : String) -> Regex { + #| try! Regex::new(pat[:]) + #|} + #|fn Regex::re(self : Regex) -> @re.Regex { + #| match self.re { + #| Some(re) => re + #| None => { + #| let lowered_pat = re_lower_to_utf16(self.pat) + #| let re = @re.compile(profile=re_profile_utf16, lowered_pat) + #| self.re = Some(re) + #| re + #| } + #| } + #|} + #|pub fn Regex::new(pattern : StringView) -> Regex raise { + #| let pat = @regex_parser.parse( + #| profile=re_profile_unicode, + #| pattern, + #| mode=String, + #| ) + #| { pat, re: None } + #|} + #|pub fn Regex::unsafe_from_string(pattern : StringView) -> Regex { + #| try! Regex::new(pattern) + #|} + #|pub fn Regex::string(str : StringView) -> Regex { + #| let pat = @re.seq( + #| ReadOnlyArray::from_array( + #| str.to_array().map(b => @re.char(@re.RecharSet::char(b.to_int()))), + #| ), + #| ) + #| { pat, re: None } + #|} + #|pub fn Regex::repeat( + #| self : Regex, + #| min? : Int = 0, + #| max? : Int, + #| greedy? : Bool = true, + #|) -> Regex { + #| guard min >= 0 && min <= MAX_REPEAT_QUANTIFIER else { panic() } + #| guard max is None || + #| (max is Some(max) && max >= min && max <= MAX_REPEAT_QUANTIFIER) else { + #| panic() + #| } + #| { + #| pat: @re.quantifier(self.pat, { + #| min, + #| max, + #| mode: if greedy { + #| Greedy + #| } else { + #| NonGreedy + #| }, + #| }), + #| re: None, + #| } + #|} + #|pub impl Add for Regex with add(self, other) -> Regex { + #| { pat: @re.seq([self.pat, other.pat]), re: None } + #|} + #|pub impl BitOr for Regex with lor(self, other) -> Regex { + #| { pat: @re.alt([self.pat, other.pat]), re: None } + #|} + #|pub fn Regex::execute( + #| self : Regex, + #| input : StringView, + #| last_index? : Int = 0, + #|) -> MatchResult? { + #| match self.re().execute(input, last_index) { + #| None => None + #| Some(result) => + #| Some(MatchResult::{ input, group_names: self.re().group_names(), result }) + #| } + #|} + #|pub fn Regex::capture(self : Regex, group_name : String) -> Regex { + #| { pat: @re.capture(name=group_name, self.pat), re: None } + #|} + ), + "regex_methods.mbt": ( + #|fn StringView::next_char_index(self : StringView, index : Int) -> Int { + #| if index < self.length() && self.unsafe_get(index).is_leading_surrogate() { + #| index + 2 + #| } else { + #| index + 1 + #| } + #|} + #|pub fn Regex::replace_by( + #| regex : Regex, + #| str : StringView, + #| replacer : (MatchResult) -> StringView, + #| limit? : Int, + #|) -> StringView { + #| let mut buf : StringBuilder? = None + #| let copy_index = for copy_index = 0, search_index = 0, replaced = 0; search_index <= + #| str.length(); { + #| if limit is Some(limit) && replaced >= limit { + #| break copy_index + #| } + #| match regex.execute(str, last_index=search_index) { + #| None => break copy_index + #| Some(m) => { + #| guard m.result.group(0) is Some((start, end)) else { break copy_index } + #| let b = match buf { + #| Some(b) => b + #| None => { + #| let b = StringBuilder::new() + #| buf = Some(b) + #| b + #| } + #| } + #| b.write_stringview(str[copy_index:start]) + #| b.write_stringview(replacer(m)) + #| let search_index = if start == end { + #| str.next_char_index(end) + #| } else { + #| end + #| } + #| continue end, search_index, replaced + 1 + #| } + #| } + #| } nobreak { + #| copy_index + #| } + #| match buf { + #| None => str + #| Some(b) => { + #| b.write_stringview(str[copy_index:]) + #| b.to_string()[:] + #| } + #| } + #|} + #|pub fn Regex::find(regex : Regex, str : StringView) -> Iter[MatchResult] { + #| let mut search_index = 0 + #| let len = str.length() + #| Iter::new(() => { + #| guard search_index <= len else { None } + #| match regex.execute(str, last_index=search_index) { + #| None => None + #| Some(m) => { + #| guard m.result.group(0) is Some((start, end)) else { return None } + #| search_index = if start == end { str.next_char_index(end) } else { end } + #| Some(m) + #| } + #| } + #| }) + #|} + #|pub fn Regex::split(regex : Regex, str : StringView) -> Iter[StringView] { + #| let mut copy_index = 0 + #| let mut search_index = 0 + #| let len = str.length() + #| let mut done = false + #| Iter::new(() => { + #| guard !done else { None } + #| while search_index <= len { + #| match regex.execute(str, last_index=search_index) { + #| None => { + #| done = true + #| return Some(str[copy_index:]) + #| } + #| Some(m) => { + #| guard m.result.group(0) is Some((start, end)) else { + #| done = true + #| return Some(str[copy_index:]) + #| } + #| let part = str[copy_index:start] + #| copy_index = end + #| search_index = if start == end { + #| str.next_char_index(end) + #| } else { + #| end + #| } + #| return Some(part) + #| } + #| } + #| } + #| done = true + #| Some(str[copy_index:]) + #| }) + #|} + ), + "regex_pattern.mbt": ( + #|#internal(internal, "not intended for public use") + #|#doc(hidden) + #|struct Pattern(@re.Pattern) + #|#internal(internal, "not intended for public use") + #|#doc(hidden) + #|pub fn Pattern::epsilon() -> Pattern { + #| Pattern(@re.epsilon) + #|} + #|#internal(internal, "not intended for public use") + #|#doc(hidden) + #|pub fn Pattern::empty() -> Pattern { + #| Pattern(@re.empty) + #|} + #|#internal(internal, "not intended for public use") + #|#doc(hidden) + #|pub fn Pattern::char_range(lo : Int, hi : Int) -> Pattern { + #| Pattern(@re.char(@re.RecharSet::char_range(lo, hi))) + #|} + #|#internal(internal, "not intended for public use") + #|#doc(hidden) + #|pub fn Pattern::char_set(cs : ReadOnlyArray[(Int, Int)]) -> Pattern { + #| Pattern(@re.char(@re.RecharSet::from_sorted_array(cs))) + #|} + #|#internal(internal, "not intended for public use") + #|#doc(hidden) + #|pub fn Pattern::seq(pats : ReadOnlyArray[Pattern]) -> Pattern { + #| Pattern(@re.seq(pats.map(p => p.0))) + #|} + #|#internal(internal, "not intended for public use") + #|#doc(hidden) + #|pub fn Pattern::alt(pats : ReadOnlyArray[Pattern]) -> Pattern { + #| Pattern(@re.alt(pats.map(p => p.0))) + #|} + #|#internal(internal, "not intended for public use") + #|#doc(hidden) + #|pub fn Pattern::quantifier( + #| pat : Pattern, + #| min~ : Int, + #| max~ : Int?, + #| greedy~ : Bool, + #|) -> Pattern { + #| Pattern( + #| @re.quantifier(pat.0, { + #| min, + #| max, + #| mode: if greedy { + #| Greedy + #| } else { + #| NonGreedy + #| }, + #| }), + #| ) + #|} + #|#internal(internal, "not intended for public use") + #|#doc(hidden) + #|pub fn Pattern::capture(pat : Pattern, name? : String) -> Pattern { + #| Pattern(@re.capture(pat.0, name?)) + #|} + #|#internal(internal, "not intended for public use") + #|#doc(hidden) + #|pub fn Pattern::start_of_input() -> Pattern { + #| Pattern(@re.start_of_input) + #|} + #|#internal(internal, "not intended for public use") + #|#doc(hidden) + #|pub fn Pattern::end_of_input() -> Pattern { + #| Pattern(@re.end_of_input) + #|} + ), + "regex_profile.mbt": ( + #|let word_set : @re.RecharSet = @re.RecharSet::char_range('a', 'z') + + #| @re.RecharSet::char_range('A', 'Z') + + #| @re.RecharSet::char_range('0', '9') + + #| @re.RecharSet::char('_') + #|let re_profile_unicode : @re.Profile = Profile( + #| valid=@re.RecharSet::char_range(0, 0x10FFFF) - + #| @re.RecharSet::char_range(0xD800, 0xDFFF), + #| word=word_set, + #| category=c => { + #| match c { + #| 'a'..='z' | 'A'..='Z' | '0'..='9' | '_' => @re.Category::word() + #| '\n' => @re.Category::newline() + @re.Category::not_word() + #| _ => @re.Category::not_word() + #| } + #| }, + #|) + #|let re_profile_utf16 : @re.Profile = Profile( + #| valid=@re.RecharSet::char_range(0, 0xFFFF), + #| word=re_profile_unicode.word, + #| word_symbolize_splits=[ + #| word_set, + #| @re.RecharSet::char_range(0xD800, 0xDBFF), + #| @re.RecharSet::char_range(0xDC00, 0xDFFF), + #| ], + #| category=c => { + #| match c { + #| 0xD800..=0xDBFF => @re.Category::not_word_start() + #| 0xDC00..=0xDFFF => @re.Category::not_word_end() + #| _ => (re_profile_unicode.category)(c) + #| } + #| }, + #|) + ), + "regex_utf16.mbt": ( + #|fn re_surrogate_pair(codepoint : Int) -> (Int, Int) { + #| let cp = codepoint - 0x10000 + #| let high = 0xD800 + ((cp >> 10) & 0x3FF) + #| let low = 0xDC00 + (cp & 0x3FF) + #| (high, low) + #|} + #|fn re_lower_cset(cs : @re.RecharSet) -> @re.Pattern { + #| let cset1 = cs & @re.RecharSet::char_range(0x0000, 0xFFFF) + #| let cset2 = cs & @re.RecharSet::char_range(0x10000, 0x10FFFF) + #| let alts = [] + #| if !cset1.is_empty() { + #| alts.push(@re.char(cset1)) + #| } + #| for interval in cset2.intervals() { + #| let (lo, hi) = interval + #| if lo == hi { + #| let pair = re_surrogate_pair(lo) + #| alts.push( + #| @re.seq([ + #| @re.char(@re.RecharSet::char(pair.0)), + #| @re.char(@re.RecharSet::char(pair.1)), + #| ]), + #| ) + #| } else { + #| let lo = re_surrogate_pair(lo) + #| let hi = re_surrogate_pair(hi) + #| if lo.0 == hi.0 { + #| alts.push( + #| @re.seq([ + #| @re.char(@re.RecharSet::char(lo.0)), + #| @re.char(@re.RecharSet::char_range(lo.1, hi.1)), + #| ]), + #| ) + #| } else { + #| alts.push( + #| @re.seq([ + #| @re.char(@re.RecharSet::char(lo.0)), + #| @re.char(@re.RecharSet::char_range(lo.1, 0xDFFF)), + #| ]), + #| ) + #| if lo.0 + 1 < hi.0 { + #| alts.push( + #| @re.seq([ + #| @re.char(@re.RecharSet::char_range(lo.0 + 1, hi.0 - 1)), + #| @re.char(@re.RecharSet::char_range(0xDC00, 0xDFFF)), + #| ]), + #| ) + #| } + #| alts.push( + #| @re.seq([ + #| @re.char(@re.RecharSet::char(hi.0)), + #| @re.char(@re.RecharSet::char_range(0xDC00, hi.1)), + #| ]), + #| ) + #| } + #| } + #| } + #| @re.shortest(@re.alt(ReadOnlyArray::from_array(alts))) + #|} + #|fn re_lower_to_utf16(ast : @re.Pattern) -> @re.Pattern { + #| match ast.desc { + #| Char(cs) => re_lower_cset(cs) + #| Sequence(exprs) => @re.seq(exprs.map(e => re_lower_to_utf16(e))) + #| Alternation(exprs) => @re.alt(exprs.map(e => re_lower_to_utf16(e))) + #| Quantifier(q, expr) => @re.quantifier(re_lower_to_utf16(expr), q) + #| Preference(p, expr) => @re.preference(p, re_lower_to_utf16(expr)) + #| Capture(name~, expr) => @re.capture(name?, re_lower_to_utf16(expr)) + #| Assertion(a) => @re.assertion(a) + #| } + #|} + ), + "string.mbt": ( + #|#deprecated + #|#doc(hidden) + #|pub fn from_array(chars : ArrayView[Char]) -> String { + #| String::from_array(chars) + #|} + #|#deprecated + #|#doc(hidden) + #|pub fn from_iter(iter : Iter[Char]) -> String { + #| String::from_iter(iter) + #|} + #|#deprecated + #|#doc(hidden) + #|pub fn from_iterator(iter : Iter[Char]) -> String { + #| String::from_iter(iter) + #|} + #|#deprecated("Use `String::default` instead") + #|#doc(hidden) + #|pub fn default() -> String { + #| "" + #|} + ), + "utils.mbt": ( + #|fn code_point_of_surrogate_pair(leading : UInt16, trailing : UInt16) -> Char { + #| ((leading - 0xD800).to_int() * 0x400 + trailing.to_int() - 0xDC00 + 0x10000).unsafe_to_char() + #|} + #|test "code_point_of_surrogate_pair" { + #| let s = "😀" + #| let leading = s.code_unit_at(0) + #| let trailing = s.code_unit_at(1) + #| inspect(code_point_of_surrogate_pair(leading, trailing), content="😀") + #|} + #|test "is_leading_surrogate" { + #| inspect("🤣".code_unit_at(0).is_leading_surrogate(), content="true") + #| inspect("🤣".code_unit_at(1).is_leading_surrogate(), content="false") + #|} + #|test "is_trailing_surrogate" { + #| inspect("🤣".code_unit_at(0).is_trailing_surrogate(), content="false") + #| inspect("🤣".code_unit_at(1).is_trailing_surrogate(), content="true") + #|} + #|test "is_surrogate" { + #| inspect((0xD800).is_surrogate(), content="true") // Leading surrogate + #| inspect((0xDBFF).is_surrogate(), content="true") // Leading surrogate + #| inspect((0xDC00).is_surrogate(), content="true") // Trailing surrogate + #| inspect((0xDFFF).is_surrogate(), content="true") // Trailing surrogate + #| inspect((0xD7FF).is_surrogate(), content="false") // Just before surrogates + #| inspect((0xE000).is_surrogate(), content="false") // Just after surrogates + #| inspect((0x41).is_surrogate(), content="false") // Regular ASCII 'A' + #|} + ), + "view.mbt": ( + #|pub using @builtin {trait ToStringView} + #|#deprecated("@string.View is deprecated, use StringView instead.") + #|pub type View = StringView + ) + } ) ///| -let moonbitlang_core_string_regex_internal_regexp_internal_ast_module : RuntimePackage = RuntimePackage::new( - "moonbitlang/core/string/regex/internal/regexp/internal/ast", - deps={ - "vm": moonbitlang_core_string_regex_internal_regexp_internal_vm_module, - "unicode": moonbitlang_core_string_regex_internal_regexp_internal_unicode_module, - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/array": moonbitlang_core_array_module, - "moonbitlang/core/string": moonbitlang_core_string_module, - "moonbitlang/core/int": moonbitlang_core_int_module, - "moonbitlang/core/char": moonbitlang_core_char_module, - }, +let moonbitlang_core_string_internal_regex_engine_module : RuntimePackage = RuntimePackage::new( + "moonbitlang/core/string/internal/regex_engine", + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| { "path": "moonbitlang/core/string/regex/internal/regexp/internal/vm", "alias": "vm" }, - #| { "path": "moonbitlang/core/string/regex/internal/regexp/internal/unicode", "alias": "unicode" }, - #| "moonbitlang/core/builtin", - #| "moonbitlang/core/array", - #| "moonbitlang/core/string", - #| "moonbitlang/core/int", - #| "moonbitlang/core/char" - #| ], - #| "wbtest-import": [ - #| "moonbitlang/core/json" - #| ] - #|} - ), - "alias.mbt": ( - #|using @vm {type Instruction, type Predicate} - #|using @unicode {simplify_char_ranges, compute_char_class_complement} - ), - "compile.mbt": ( - #|pub(all) enum Ast { - #| Empty - #| CharClass(Array[Char], neg~ : Bool) - #| Assertion(Predicate) - #| Capture(Ast, index~ : Int) - #| ZeroOrMore(Ast, greedy~ : Bool) - #| OneOrMore(Ast, greedy~ : Bool) - #| ZeroOrOne(Ast, greedy~ : Bool) - #| Repeat(Ast, greedy~ : Bool, min~ : UInt, max~ : UInt?) - #| Concat(Array[Ast]) - #| Alternate(Ast, Ast) - #|} derive(Show) - #|fn Ast::compile_aux(regex : Ast, instructions : Array[Instruction]) -> Unit { - #| match regex { - #| Empty => () - #| CharClass(chars, neg~) => - #| if neg { - #| let complement = compute_char_class_complement(chars) - #| instructions.push(Char(complement)) - #| } else { - #| let simplified = simplify_char_ranges(chars) - #| instructions.push(Char(simplified)) - #| } - #| Assertion(pred) => instructions.push(Assertion(pred)) - #| Capture(inner, index=capture) => { - #| instructions.push(Save(capture * 2)) - #| inner.compile_aux(instructions) - #| instructions.push(Save(capture * 2 + 1)) - #| } - #| ZeroOrMore(inner, greedy~) => { - #| let split_pos = instructions.length() - #| instructions.push(Split(-1, -1)) - #| inner.compile_aux(instructions) - #| let next_pos = instructions.length() - #| if not(greedy) { - #| instructions.push(Split(next_pos + 1, split_pos + 1)) - #| instructions[split_pos] = Split(next_pos + 1, split_pos + 1) - #| } else { - #| instructions.push(Split(split_pos + 1, next_pos + 1)) - #| instructions[split_pos] = Split(split_pos + 1, next_pos + 1) - #| } - #| } - #| OneOrMore(inner, greedy~) => { - #| let jmp_pos = instructions.length() - #| inner.compile_aux(instructions) - #| let next_pos = instructions.length() - #| if not(greedy) { - #| instructions.push(Split(next_pos + 1, jmp_pos)) - #| } else { - #| instructions.push(Split(jmp_pos, next_pos + 1)) - #| } - #| } - #| ZeroOrOne(inner, greedy~) => { - #| let split_pos = instructions.length() - #| instructions.push(Split(-1, -1)) - #| inner.compile_aux(instructions) - #| if not(greedy) { - #| instructions[split_pos] = Split(instructions.length(), split_pos + 1) - #| } else { - #| instructions[split_pos] = Split(split_pos + 1, instructions.length()) - #| } - #| } - #| Repeat(greedy~, min~, max~, inner) => - #| if max is Some(max) { - #| for i in 0U.. ignore - #| } - #| let jmp_pos = instructions.length() - #| if not(greedy) { - #| for pos in split_pos { - #| instructions[pos] = Split(jmp_pos, pos + 1) - #| } - #| } else { - #| for pos in split_pos { - #| instructions[pos] = Split(pos + 1, jmp_pos) - #| } - #| } - #| } else { - #| for i in 0U.. - #| for regex in regexs { - #| regex.compile_aux(instructions) - #| } - #| Alternate(left, right) => { - #| let split_pos = instructions.length() - #| instructions.push(Split(-1, -1)) - #| left.compile_aux(instructions) - #| let jmp_pos = instructions.length() - #| instructions.push(Jump(-1)) - #| right.compile_aux(instructions) - #| instructions[split_pos] = Split(split_pos + 1, jmp_pos + 1) - #| instructions[jmp_pos] = Jump(instructions.length()) - #| } - #| } - #|} - #|pub fn Ast::compile(self : Ast) -> Array[Instruction] { - #| let instructions : Array[Instruction] = [ - #| Split(3, 1), - #| Char(['\u{0}', '\u{10FFFF}']), - #| Jump(0), - #| ] - #| instructions.push(Save(0)) - #| self.compile_aux(instructions) - #| instructions.push(Save(1)) - #| instructions.push(Matched) - #| instructions - #|} - #|pub impl ToJson for Ast with to_json(self) { - #| match self { - #| Empty => "Empty" - #| CharClass(chars, neg~) => ["CharClass neg=\{neg}", chars.map(c => repr(c))] - #| Assertion(pred) => "Assertion \{pred}" - #| Capture(inner, index~) => ["Capture \{index}", inner] - #| ZeroOrMore(inner, greedy~) => ["ZeroOrMore greedy=\{greedy}", inner] - #| OneOrMore(inner, greedy~) => ["OneOrMore greedy=\{greedy}", inner] - #| ZeroOrOne(inner, greedy~) => ["ZeroOrOne greedy=\{greedy}", inner] - #| Repeat(greedy~, min~, max~, inner) => - #| if max is Some(max) { - #| ["Repeat {\{min}, \{max}} greedy=\{greedy}", inner] - #| } else { - #| ["Repeat {\{min},} greedy=\{greedy}", inner] - #| } - #| Concat(regexs) => [..regexs.map(_.to_json())] - #| Alternate(left, right) => ["Alternate", left, right] - #| } - #|} - ), - }, + "compile.mbt": ( + #|pub fn compile(profile~ : Profile, ast : Pattern) -> Regex { + #| let ast = if ast.is_anchored() { + #| capture(ast) + #| } else { + #| seq([ + #| shortest( + #| quantifier(char(profile.valid), { min: 0, max: None, mode: Greedy }), + #| ), + #| capture(ast), + #| ]) + #| } + #| let symbol_map = @symbol_map.new() + #| symbolize(profile~, symbol_map~, ast) + #| let (symbol_table, symbol_repr) = symbol_map.finalize(profile.lb, profile.ub) + #| let ctx = @automata.Context::new() + #| let tc = TranslateContext::new(ctx, symbol_table) + #| let (expr, pref) = translate(tc, ast) + #| let expr = enforce_pref(tc.ctx, First, pref, expr) + #| Regex::new( + #| profile, + #| ctx, + #| expr, + #| ReadOnlyArray::from_array(tc.groups), + #| symbol_table, + #| symbol_repr, + #| ) + #|} + ), + "execute.mbt": ( + #|using @debug {trait Debug, type Repr} + #|struct MatchResult(Array[Int]) derive(Debug) + #|const NULL_SYMBOL : Rechar = -1 + #|fn category_from_symbol( + #| profile~ : Profile, + #| symbol_repr~ : ReadOnlyArray[Rechar], + #| symbol : Rechar, + #|) -> Category { + #| if symbol is NULL_SYMBOL { + #| Category::inexistant() + #| } else { + #| (profile.category)(symbol_repr[symbol]) + #| } + #|} + #|pub fn MatchResult::group(self : MatchResult, index : Int) -> (Int, Int)? { + #| let start_pos = self.0.get(index * 2) + #| guard start_pos is Some(start_pos) && start_pos >= 0 else { None } + #| let end_pos = self.0[index * 2 + 1] + #| guard end_pos >= 0 else { panic() } + #| Some((start_pos, end_pos)) + #|} + #|pub fn Regex::execute( + #| self : Regex, + #| input : StringView, + #| last_index : Int, + #|) -> MatchResult? { + #| guard last_index >= 0 && last_index <= input.length() else { panic() } + #| let symbol_table = self.symbol_table + #| let prev_cat = category_from_symbol( + #| profile=self.profile, + #| symbol_repr=self.symbol_repr, + #| if last_index == 0 { + #| NULL_SYMBOL + #| } else { + #| let ch = input.unsafe_get(last_index - 1).to_int() + #| symbol_table.map(ch) + #| }, + #| ) + #| let start_state_id = self.stablize_start_state(prev_cat) + #| let positions = Positions::new() + #| let mut transition_table = self.transition_table + #| let data = input.data() + #| let mut pos = input.start_offset() + last_index + #| let end = input.start_offset() + input.length() + #| let mut state_id = start_state_id + #| while pos < end { + #| let ch = data.unsafe_get(pos).to_int() + #| let symbol = symbol_table.map(ch) + #| let transition_index = state_id.transition_base() + symbol + #| let prev_state_id = state_id + #| state_id = transition_table.unsafe_get(transition_index) + #| if state_id.is_pending() { + #| state_id = self.stablize_next_state(prev_state_id, symbol) + #| transition_table = self.transition_table + #| transition_table[transition_index] = state_id + #| } + #| let slot = state_id.slot() + #| if slot.index >= positions.0.length() { + #| positions.0.resize(slot.index + 8, -1) + #| } + #| positions.0[slot.index] = pos + #| if state_id.is_break() { + #| break + #| } + #| pos += 1 + #| } + #| let state = self.get_state(state_id) + #| let matched = match state.status() { + #| Failed => None + #| Running => { + #| let next_cat = category_from_symbol( + #| profile=self.profile, + #| symbol_repr=self.symbol_repr, + #| if pos >= end { + #| NULL_SYMBOL + #| } else { + #| let ch = data.unsafe_get(pos).to_int() + #| symbol_table.map(ch) + #| }, + #| ) + #| let (slot, status) = self.stablize_final(state_id, state, next_cat) + #| match status { + #| Failed | Running => None + #| Match(marks) => { + #| positions.set(slot, pos) + #| Some(marks) + #| } + #| } + #| } + #| Match(marks) => Some(marks) + #| } + #| match matched { + #| None => None + #| Some(marks) => { + #| let mark_pos = Array::make(self.groups.length() * 2, -1) + #| let shift = input.start_offset() + #| for mark, slot in marks { + #| mark_pos[mark.0] = positions.get(slot) - shift + #| } + #| Some(MatchResult(mark_pos)) + #| } + #| } + #|} + ), + "positions.mbt": ( + #|priv struct Positions(Array[Int]) + #|fn Positions::new() -> Positions { + #| Positions(Array::make(8, -1)) + #|} + #|#alias("_[_]=_") + #|fn Positions::set(self : Positions, slot : @automata.Slot, pos : Int) -> Unit { + #| if slot.index >= self.0.length() { + #| self.0.resize(slot.index + 8, -1) + #| } + #| self.0[slot.index] = pos + #|} + #|#alias("_[_]") + #|fn Positions::get(self : Positions, slot : @automata.Slot) -> Int { + #| if slot.index >= self.0.length() { + #| -1 + #| } else { + #| self.0[slot.index] + #| } + #|} + ), + "regex.mbt": ( + #|struct Regex { + #| profile : Profile + #| ctx : @automata.Context + #| expr : @automata.Expr + #| groups : ReadOnlyArray[String?] + #| symbol_table : @symbol_map.Table + #| symbol_repr : ReadOnlyArray[Rechar] + #| start_states : Array[(Category, StateId)] + #| state_table : @hashmap.HashMap[@automata.State, StateId] + #| mut transition_table : FixedArray[StateId] + #| mut final_table : FixedArray[ + #| @list.List[(Category, @automata.Slot, @automata.Status)], + #| ] + #| mut states : FixedArray[@automata.State] + #| mut num_states : Int + #|} + #|pub fn Regex::group_names(self : Regex) -> ReadOnlyArray[String?] { + #| self.groups + #|} + #|fn Regex::new( + #| profile : Profile, + #| ctx : @automata.Context, + #| expr : @automata.Expr, + #| groups : ReadOnlyArray[String?], + #| symbol_table : @symbol_map.Table, + #| symbol_repr : ReadOnlyArray[Rechar], + #|) -> Regex { + #| Regex::{ + #| profile, + #| ctx, + #| expr, + #| groups, + #| symbol_table, + #| symbol_repr, + #| start_states: [], + #| state_table: @hashmap.HashMap::new(), + #| transition_table: [], + #| final_table: [], + #| states: [], + #| num_states: 0, + #| } + #|} + #|fn Regex::num_symbols(self : Regex) -> Int { + #| self.symbol_repr.length() + #|} + ), + "state_id.mbt": ( + #|priv struct StateId(Int64) + #|let pending_state_id : StateId = -1 + #|fn StateId::new( + #| index~ : Int, + #| slot~ : @automata.Slot, + #| is_break~ : Bool, + #| num_symbols~ : Int, + #|) -> StateId { + #| debug_assert(() => { + #| index <= 0b1111_1111_1111_1111_1110 && + #| slot.index <= 0b111_1111_1111 && + #| num_symbols <= 0b111_1111_1110 + #| }) + #| let transition_base = index * num_symbols + #| let encoded_index = if is_break { -2 - index } else { index } + #| let id = StateId( + #| (((encoded_index << 11) | slot.index).to_int64() << 32) | + #| transition_base.to_int64(), + #| ) + #| debug_assert(() => { + #| id.index() == index && id.slot() == slot && id.is_break() == is_break + #| }) + #| id + #|} + #|fn StateId::is_pending(self : StateId) -> Bool { + #| self.0 == -1 + #|} + #|fn StateId::is_break(self : StateId) -> Bool { + #| self.0 < -1 + #|} + #|fn StateId::transition_base(self : StateId) -> Int { + #| self.0.to_int() + #|} + #|fn StateId::index(self : StateId) -> Int { + #| let x = (self.0 >> 43).to_int() + #| if x < 0 { + #| -(x + 2) + #| } else { + #| x + #| } + #|} + #|fn StateId::slot(self : StateId) -> @automata.Slot { + #| @automata.Slot::from_index((self.0 >> 32).to_int() & 0b111_1111_1111) + #|} + ), + "states.mbt": ( + #|fn Regex::get_state(self : Regex, state_id : StateId) -> @automata.State { + #| self.states.unsafe_get(state_id.index()) + #|} + #|fn Regex::stablize_start_state(self : Regex, prev_cat : Category) -> StateId { + #| for i in 0.. StateId { + #| self.state_table.get_or_init(state, () => { + #| let index = self.num_states + #| self.num_states += 1 + #| let num_symbols = self.num_symbols() + #| if index >= self.states.length() { + #| let new_states_len = Int::max(self.states.length() * 2, 4) + #| let new_states = FixedArray::make(new_states_len, @automata.st_dummy) + #| self.states.blit_to(new_states, len=self.states.length()) + #| let new_transition_table = FixedArray::make( + #| new_states_len * num_symbols, + #| pending_state_id, + #| ) + #| self.transition_table.blit_to( + #| new_transition_table, + #| len=self.transition_table.length(), + #| ) + #| let new_final_table = FixedArray::make(new_states_len, @list.empty()) + #| self.final_table.blit_to(new_final_table, len=self.final_table.length()) + #| self.states = new_states + #| self.transition_table = new_transition_table + #| self.final_table = new_final_table + #| } + #| self.states[index] = state + #| let state_id = StateId::new( + #| index~, + #| slot=state.slot(), + #| is_break=state.status() is (Match(_) | Failed), + #| num_symbols~, + #| ) + #| state_id + #| }) + #|} + #|fn Regex::stablize_next_state( + #| self : Regex, + #| prev_state_id : StateId, + #| symbol : Rechar, + #|) -> StateId { + #| let cat = category_from_symbol( + #| profile=self.profile, + #| symbol_repr=self.symbol_repr, + #| symbol, + #| ) + #| let prev_state = self.get_state(prev_state_id) + #| let state = @automata.delta(ctx=self.ctx, prev_state, symbol, next_cat=cat) + #| self.stablize_state(state) + #|} + #|fn Regex::stablize_final( + #| self : Regex, + #| state_id : StateId, + #| state : @automata.State, + #| next_cat : Category, + #|) -> (@automata.Slot, @automata.Status) { + #| let state_index = state_id.index() + #| loop self.final_table[state_index] { + #| Empty => { + #| let next_state = @automata.delta( + #| ctx=self.ctx, + #| state, + #| NULL_SYMBOL, + #| next_cat~, + #| ) + #| let slot = next_state.slot() + #| let status = next_state.status() + #| self.final_table[state_index] = @list.cons( + #| (next_cat, slot, status), + #| self.final_table[state_index], + #| ) + #| (slot, status) + #| } + #| More(head, tail~) => + #| if head.0 == next_cat { + #| (head.1, head.2) + #| } else { + #| continue tail + #| } + #| } + #|} + ), + "symbolize.mbt": ( + #|fn symbolize( + #| profile~ : Profile, + #| symbol_map~ : @symbol_map.SymbolMap, + #| expr : Pattern, + #|) -> Unit { + #| fn aux(expr : Pattern) { + #| match expr.desc { + #| Char(s) => symbol_map.split(s) + #| Sequence(l) => l.each(aux) + #| Alternation(l) => l.each(aux) + #| Quantifier(_, r) => aux(r) + #| Assertion(StartOfLine) | Assertion(EndOfLine) => + #| symbol_map.split(RecharSet::char('\n')) + #| Assertion(StartOfWord) + #| | Assertion(EndOfWord) + #| | Assertion(NotWordBoundary) => + #| for split in profile.word_symbolize_splits { + #| symbol_map.split(split) + #| } + #| Assertion(StartOfInput) | Assertion(EndOfInput) => () + #| Preference(_, r) => aux(r) + #| Capture(r, ..) => aux(r) + #| } + #| } + #| aux(expr) + #|} + ), + "translate.mbt": ( + #|priv struct TranslateContext { + #| ctx : @automata.Context + #| pref : Preference + #| groups : Array[String?] + #| symbol_table : @symbol_map.Table + #|} + #|fn TranslateContext::new( + #| ctx : @automata.Context, + #| symbol_table : @symbol_map.Table, + #|) -> TranslateContext { + #| TranslateContext::{ ctx, pref: First, groups: [], symbol_table } + #|} + #|fn translate( + #| tc : TranslateContext, + #| ast : Pattern, + #|) -> (@automata.Expr, Preference) { + #| let { ctx, pref, groups, symbol_table } = tc + #| match ast.desc { + #| Char(c) => (@automata.e_cset(ctx~, symbol_table.map_set(c)), pref) + #| Sequence(exprs) => (transl_seq(tc, exprs), pref) + #| Alternation(exprs) => { + #| let alts = [] + #| for expr in exprs { + #| let (cr, pref2) = translate(tc, expr) + #| alts.push(enforce_pref(ctx, pref, pref2, cr)) + #| } + #| (@automata.e_alt(ctx~, alts), pref) + #| } + #| Quantifier(q, expr) => { + #| let (cr, pref2) = translate(tc, expr) + #| let rem = match q.max { + #| None => @automata.e_rep(ctx~, q.mode, pref2, cr) + #| Some(max) => { + #| let repeater = match q.mode { + #| Greedy => + #| rem => { + #| @automata.e_alt(ctx~, [ + #| @automata.e_seq(ctx~, pref2, @automata.e_copy(ctx~, cr), rem), + #| @automata.e_eps, + #| ]) + #| } + #| NonGreedy => + #| rem => { + #| @automata.e_alt(ctx~, [ + #| @automata.e_eps, + #| @automata.e_seq(ctx~, pref2, @automata.e_copy(ctx~, cr), rem), + #| ]) + #| } + #| } + #| iter(max - q.min, repeater, @automata.e_eps) + #| } + #| } + #| let result = iter( + #| q.min, + #| rem => @automata.e_seq(ctx~, pref2, @automata.e_copy(ctx~, cr), rem), + #| rem, + #| ) + #| (result, pref) + #| } + #| Preference(pref2, expr) => { + #| let (cr, pref3) = translate({ ..tc, pref: pref2 }, expr) + #| (enforce_pref(ctx, pref2, pref3, cr), pref2) + #| } + #| Capture(name~, expr) => { + #| let group_index = groups.length() + #| groups.push(name) + #| let (cr, pref2) = translate(tc, expr) + #| ( + #| @automata.e_seq( + #| ctx~, + #| First, + #| @automata.e_mark(ctx~, @automata.Mark(group_index * 2)), + #| @automata.e_seq( + #| ctx~, + #| First, + #| cr, + #| @automata.e_mark(ctx~, @automata.Mark(group_index * 2 + 1)), + #| ), + #| ), + #| pref2, + #| ) + #| } + #| Assertion(asrt) => (transl_asrt(ctx, asrt), pref) + #| } + #|} + #|fn transl_asrt(ctx : @automata.Context, asrt : Assertion) -> @automata.Expr { + #| match asrt { + #| StartOfLine => @automata.e_after(ctx~, Category::inexistant_or_newline()) + #| EndOfLine => @automata.e_before(ctx~, Category::inexistant_or_newline()) + #| StartOfWord => + #| @automata.e_seq( + #| ctx~, + #| First, + #| @automata.e_after(ctx~, Category::inexistant_or_non_word_end()), + #| @automata.e_before(ctx~, Category::word()), + #| ) + #| EndOfWord => + #| @automata.e_seq( + #| ctx~, + #| First, + #| @automata.e_after(ctx~, Category::word()), + #| @automata.e_before(ctx~, Category::inexistant_or_non_word_start()), + #| ) + #| NotWordBoundary => + #| @automata.e_alt(ctx~, [ + #| @automata.e_seq( + #| ctx~, + #| First, + #| @automata.e_after(ctx~, Category::word()), + #| @automata.e_before(ctx~, Category::word()), + #| ), + #| @automata.e_seq( + #| ctx~, + #| First, + #| @automata.e_after(ctx~, Category::inexistant_or_non_word_end()), + #| @automata.e_before(ctx~, Category::inexistant_or_non_word_start()), + #| ), + #| ]) + #| StartOfInput => @automata.e_after(ctx~, Category::inexistant()) + #| EndOfInput => @automata.e_before(ctx~, Category::inexistant()) + #| } + #|} + #|fn transl_seq( + #| tc : TranslateContext, + #| exprs : ReadOnlyArray[Pattern], + #|) -> @automata.Expr { + #| fn compose( + #| pref2 : Preference, + #| cr : @automata.Expr, + #| cr2 : @automata.Expr, + #| ) -> @automata.Expr { + #| if @automata.is_eps(cr2) { + #| enforce_pref(tc.ctx, tc.pref, pref2, cr) + #| } else if @automata.is_eps(cr) { + #| cr2 + #| } else { + #| @automata.e_seq(ctx=tc.ctx, pref2, cr, cr2) + #| } + #| } + #| fn go(i : Int) -> @automata.Expr { + #| if i >= exprs.length() { + #| @automata.e_eps + #| } else { + #| let (cr, pref2) = translate(tc, exprs[i]) + #| let cr2 = go(i + 1) + #| compose(pref2, cr, cr2) + #| } + #| } + #| go(0) + #|} + #|fn enforce_pref( + #| ctx : @automata.Context, + #| pref : Preference, + #| pref2 : Preference, + #| cr : @automata.Expr, + #|) -> @automata.Expr { + #| match (pref, pref2) { + #| (First, First) => cr + #| (First, k) => @automata.e_seq(ctx~, k, cr, @automata.e_eps) + #| _ => cr + #| } + #|} + #|fn[T] iter(n : Int, f : (T) -> T, init : T) -> T { + #| if n == 0 { + #| init + #| } else { + #| iter(n - 1, f, f(init)) + #| } + #|} + ), + "using.mbt": ( + #|pub using @shared_types { + #| type Profile, + #| type Rechar, + #| type RecharSet, + #| type Preference, + #| type Category, + #| type QuantifierMode, + #|} + #|pub using @ast { + #| type Pattern, + #| type Assertion, + #| type Quantifier, + #| char, + #| epsilon, + #| seq, + #| empty, + #| alt, + #| quantifier, + #| preference, + #| shortest, + #| longest, + #| first, + #| capture, + #| assertion, + #| start_of_input, + #| end_of_input, + #| start_of_line, + #| end_of_line, + #| start_of_word, + #| end_of_word, + #| not_word_boundary, + #|} + ) + } ) ///| -let moonbitlang_core_string_regex_internal_regexp_internal_parse_module : RuntimePackage = RuntimePackage::new( - "moonbitlang/core/string/regex/internal/regexp/internal/parse", - deps={ - "moonbitlang/core/string/regex/internal/regexp/internal/vm": moonbitlang_core_string_regex_internal_regexp_internal_vm_module, - "moonbitlang/core/string/regex/internal/regexp/internal/ast": moonbitlang_core_string_regex_internal_regexp_internal_ast_module, - "moonbitlang/core/string/regex/internal/regexp/internal/unicode": moonbitlang_core_string_regex_internal_regexp_internal_unicode_module, - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/array": moonbitlang_core_array_module, - "moonbitlang/core/string": moonbitlang_core_string_module, - "moonbitlang/core/int": moonbitlang_core_int_module, - "moonbitlang/core/char": moonbitlang_core_char_module, - "moonbitlang/core/set": moonbitlang_core_set_module, - }, +let moonbitlang_core_string_internal_regex_engine_ast_module : RuntimePackage = RuntimePackage::new( + "moonbitlang/core/string/internal/regex_engine/ast", + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| "moonbitlang/core/string/regex/internal/regexp/internal/vm", - #| "moonbitlang/core/string/regex/internal/regexp/internal/ast", - #| "moonbitlang/core/string/regex/internal/regexp/internal/unicode", - #| "moonbitlang/core/builtin", - #| "moonbitlang/core/array", - #| "moonbitlang/core/string", - #| "moonbitlang/core/int", - #| "moonbitlang/core/char", - #| "moonbitlang/core/set" - #| ], - #| "wbtest-import": [ - #| "moonbitlang/core/json", - #| "moonbitlang/core/result" - #| ] - #|} - ), - "alias.mbt": ( - #|using @ast {type Ast} - #|using @unicode {case_insensitive_char_class, compute_char_class_complement} - #|let ranges_is_digit = @unicode.ranges_is_digit - #|let ranges_is_not_digit = @unicode.ranges_is_not_digit - #|let ranges_is_word = @unicode.ranges_is_word - #|let ranges_is_not_word = @unicode.ranges_is_not_word - #|let ranges_is_white_space_or_line_terminator = @unicode.ranges_is_white_space_or_line_terminator - #|let ranges_is_not_white_space_or_line_terminator = @unicode.ranges_is_not_white_space_or_line_terminator - #|let ranges_any = @unicode.ranges_any - #|let ranges_any_not_new_line = @unicode.ranges_any_not_new_line - ), - "parse.mbt": ( - #|priv struct Parser { - #| mut input : StringView - #| mut flags : Flags - #| mut captures : Int - #| current_capture_scope : @set.Set[Int] - #| capture_map : Map[String, Int] - #|} - #|pub(all) struct ParseResult { - #| ast : Ast - #| captures : Int - #| capture_map : Map[String, Int] - #|} derive(ToJson) - #|pub(all) struct Flags { - #| multiline : Bool - #| singleline : Bool - #| ignore_case : Bool - #|} derive(Default) - #|pub enum Err { - #| InternalError // Internal error - #| InvalidCharClass // Invalid character class - #| InvalidEscape // Invalid escape sequence - #| InvalidNamedCapture // Invalid named capture group - #| InvalidRepeatOp // Invalid repeat operator - #| InvalidRepeatSize // Invalid repeat count - #| MissingBracket // Missing right bracket ] - #| MissingParenthesis // Missing right parenthesis ) - #| MissingRepeatArgument // Missing repeat argument - #| TrailingBackslash // Trailing backslash - #| UnexpectedParenthesis // Unexpected parenthesis - #|} derive(Show) - #|pub suberror RegexpError { - #| RegexpError(err~ : Err, source_fragment~ : StringView) - #|} derive(Show) - #|fn Parser::new(input : StringView, flags : Flags) -> Parser { - #| Parser::{ - #| input, - #| flags, - #| captures: 1, - #| capture_map: {}, - #| current_capture_scope: @set.Set::new(), - #| } - #|} - #|pub fn parse( - #| regex : StringView, - #| flags? : Flags = Flags::default(), - #|) -> ParseResult raise RegexpError { - #| let parser = Parser::new(regex, flags) - #| let result = parser.parse_expression() - #| if parser.input is [')', ..] { - #| raise RegexpError(err=UnexpectedParenthesis, source_fragment=parser.input) - #| } - #| { ast: result, capture_map: parser.capture_map, captures: parser.captures } - #|} - #|fn Parser::parse_expression(self : Parser) -> Ast raise RegexpError { - #| let mut left = self.parse_sequence() - #| while self.input is ['|', .. rest] { - #| self.input = rest // consume '|' - #| let right = self.parse_sequence() - #| left = Ast::Alternate(left, right) - #| } - #| left - #|} - #|fn Parser::parse_sequence(self : Parser) -> Ast raise RegexpError { - #| let sequence = [] - #| while self.input is [ch, ..] && ch != '|' && ch != ')' { - #| let term = self.parse_term() - #| sequence.push(term) - #| } - #| match sequence { - #| [] => Ast::Empty - #| [regex] => regex - #| _ => Ast::Concat(sequence) - #| } - #|} - #|fn Parser::parse_term(self : Parser) -> Ast raise RegexpError { - #| let mut base = self.parse_factor() - #| match self.input { - #| [.. "*?", .. rest] => { - #| self.input = rest // consume '*?' - #| base = ZeroOrMore(base, greedy=false) - #| } - #| [.. "*", .. rest] => { - #| self.input = rest // consume '*' - #| base = ZeroOrMore(base, greedy=true) - #| } - #| [.. "+?", .. rest] => { - #| self.input = rest // consume '+?' - #| base = OneOrMore(base, greedy=false) - #| } - #| [.. "+", .. rest] => { - #| self.input = rest // consume '+' - #| base = OneOrMore(base, greedy=true) - #| } - #| [.. "??", .. rest] => { - #| self.input = rest // consume '??' - #| base = ZeroOrOne(base, greedy=false) - #| } - #| [.. "?", .. rest] => { - #| self.input = rest // consume '?' - #| base = ZeroOrOne(base, greedy=true) - #| } - #| ['{', .. rest] => { - #| self.input = rest - #| let repeat_result = self.parse_repeat() - #| let greedy = match self.input { - #| ['?', .. rest] => { - #| self.input = rest // consume '?' - #| false - #| } - #| _ => true - #| } - #| base = Repeat(base, greedy~, min=repeat_result.0, max=repeat_result.1) - #| } - #| _ => () - #| } - #| base - #|} - #|fn Parser::parse_factor(self : Parser) -> Ast raise RegexpError { - #| match self.input { - #| [.. "(?", .. rest] as capture => - #| match rest { - #| ['<', .. rest] => { - #| let captures = self.captures - #| self.captures += 1 - #| self.input = rest // consume '(?<' - #| let name = self.parse_group_name() - #| guard self.input is ['>', .. rest] else { - #| raise RegexpError( - #| err=InvalidNamedCapture, - #| source_fragment=self.input, - #| ) - #| } - #| self.input = rest // consume '>' - #| self.current_capture_scope.add(captures) - #| let expr = self.parse_expression() - #| self.current_capture_scope.remove(captures) - #| guard self.input is [')', .. rest] else { - #| raise RegexpError( - #| err=MissingParenthesis, - #| source_fragment=self.input, - #| ) - #| } - #| self.input = rest // consume ')' - #| if self.capture_map.contains(name) { // check for duplicate named capture - #| raise RegexpError(err=InvalidNamedCapture, source_fragment=capture) - #| } - #| self.capture_map.set(name, captures) - #| Capture(expr, index=captures) - #| } - #| _ => { - #| self.input = rest // consume '(?' - #| let old_flags = self.flags - #| let new_flags = self.parse_flags() - #| self.flags = new_flags - #| let expr = self.parse_expression() - #| guard self.input is [')', .. rest] else { - #| raise RegexpError( - #| err=MissingParenthesis, - #| source_fragment=self.input, - #| ) - #| } - #| self.input = rest // consume ')' - #| self.flags = old_flags // restore original flags - #| expr - #| } - #| } - #| ['(', .. rest] => { - #| let captures = self.captures - #| self.captures += 1 - #| self.input = rest // consume '(' - #| self.current_capture_scope.add(captures) - #| let expr = self.parse_expression() - #| self.current_capture_scope.remove(captures) - #| guard self.input is [')', .. rest] else { - #| raise RegexpError(err=MissingParenthesis, source_fragment=self.input) - #| } - #| self.input = rest // consume ')' - #| Capture(expr, index=captures) - #| } - #| ['[', .. rest] => { - #| self.input = rest - #| self.parse_char_class() - #| } - #| ['.', .. rest] => { - #| self.input = rest // consume '.' - #| if self.flags.singleline { - #| CharClass(ranges_any, neg=false) - #| } else { - #| CharClass(ranges_any_not_new_line, neg=false) - #| } - #| } - #| ['^', .. rest] => { - #| self.input = rest // consume '^' - #| if self.flags.multiline { - #| Assertion(BeginLine) - #| } else { - #| Assertion(BeginText) - #| } - #| } - #| ['$', .. rest] => { - #| self.input = rest // consume '$' - #| if self.flags.multiline { - #| Assertion(EndLine) - #| } else { - #| Assertion(EndText) - #| } - #| } - #| ['\\', .. rest] as escape => { - #| guard rest is [c, .. rest] else { - #| raise RegexpError(err=TrailingBackslash, source_fragment=self.input) - #| } - #| self.input = rest // consume '\' and the character - #| match c { - #| 'b' => Assertion(WordBoundary) // Word boundary assertion - #| 'B' => Assertion(NoWordBoundary) // Non-word boundary assertion - #| 'd' => CharClass(ranges_is_digit, neg=false) // Digit character class - #| 'D' => CharClass(ranges_is_not_digit, neg=false) // Non-digit character class - #| 'w' => CharClass(ranges_is_word, neg=false) // Word character class - #| 'W' => CharClass(ranges_is_not_word, neg=false) // Non-word character class - #| 's' => CharClass(ranges_is_white_space_or_line_terminator, neg=false) // Whitespace character class - #| 'S' => - #| CharClass(ranges_is_not_white_space_or_line_terminator, neg=false) // Non-whitespace character class - #| 't' => CharClass(['\t', '\t'], neg=false) // Tab - #| 'n' => CharClass(['\n', '\n'], neg=false) // Newline - #| 'v' => CharClass(['\u{b}', '\u{b}'], neg=false) // Vertical tab - #| 'f' => CharClass(['\u{c}', '\u{c}'], neg=false) // Form feed - #| 'r' => CharClass(['\r', '\r'], neg=false) // Carriage return - #| 'p' | 'P' as flag => { - #| let property_name = self.parse_unicode_property() - #| self.parse_general_category(property_name, flag == 'P') - #| } - #| 'u' => { - #| let unicode_char = self.parse_unicode_escape() - #| CharClass([unicode_char, unicode_char], neg=false) - #| } - #| '0' => - #| if rest is ['0'..='9', ..] { - #| raise RegexpError(err=InvalidEscape, source_fragment=escape) - #| } else { - #| self.input = rest - #| CharClass(['\u{0}', '\u{0}'], neg=false) // Null character - #| } - #| 'c' | 'k' | '1'..='9' => - #| raise RegexpError(err=InvalidEscape, source_fragment=escape) - #| _ => - #| if self.flags.ignore_case { - #| CharClass(case_insensitive_char_class([c, c]), neg=false) - #| } else { - #| CharClass([c, c], neg=false) - #| } - #| } - #| } - #| [c, ..] if Parser::is_special_char(c) => - #| raise RegexpError(err=InvalidEscape, source_fragment=self.input) - #| [c, .. rest] => { - #| self.input = rest - #| if self.flags.ignore_case { - #| CharClass(case_insensitive_char_class([c, c]), neg=false) - #| } else { - #| CharClass([c, c], neg=false) - #| } - #| } - #| "" => raise RegexpError(err=InternalError, source_fragment=self.input) - #| } - #|} - #|fn Parser::parse_char_class(self : Parser) -> Ast raise RegexpError { - #| let neg = if self.input is ['^', .. rest] { - #| self.input = rest // consume '^' - #| true - #| } else { - #| false - #| } - #| let chars = [] - #| while self.input is [ch, .. rest] && ch != ']' { - #| let escape = rest - #| let start_char = match ch { - #| '\\' => { - #| guard rest is [ch, .. rest] else { - #| raise RegexpError(err=TrailingBackslash, source_fragment=self.input) - #| } - #| self.input = rest - #| match ch { - #| 'd' => { - #| ranges_is_digit.each(chars.push(_)) // digit character class - #| continue - #| } - #| 'D' => { - #| ranges_is_not_digit.each(chars.push(_)) // non-digit character class - #| continue - #| } - #| 'w' => { - #| ranges_is_word.each(chars.push(_)) // word character class - #| continue - #| } - #| 'W' => { - #| ranges_is_not_word.each(chars.push(_)) // non-word character class - #| continue - #| } - #| 's' => { - #| ranges_is_white_space_or_line_terminator.each(chars.push(_)) // whitespace character class - #| continue - #| } - #| 'S' => { - #| ranges_is_not_white_space_or_line_terminator.each(chars.push(_)) // non-whitespace character class - #| continue - #| } - #| 'p' | 'P' as flag => { - #| let property_name = self.parse_unicode_property() - #| guard self.parse_general_category(property_name, flag == 'P') - #| is CharClass(class, neg~) - #| if neg { - #| compute_char_class_complement(class).each(chars.push(_)) - #| } else { - #| class.each(chars.push(_)) - #| } - #| continue - #| } - #| 't' => '\t' - #| 'n' => '\n' - #| 'v' => '\u{b}' - #| 'f' => '\u{c}' - #| 'r' => '\r' - #| 'b' => '\u{8}' - #| 'u' => - #| self.parse_unicode_escape() - #| 'c' | 'k' => - #| raise RegexpError(err=InvalidEscape, source_fragment=escape) - #| _ => ch - #| } - #| } - #| _ => { - #| self.input = rest - #| ch - #| } - #| } - #| if self.input is (['-', .. rest] as range_rest) { - #| let input_copy = self.input - #| self.input = rest // consume '-' - #| if self.input is [ch, .. rest] && ch != ']' { - #| let end_char = match ch { - #| '\\' => { - #| guard rest is [ch, .. rest] else { - #| raise RegexpError( - #| err=TrailingBackslash, - #| source_fragment=self.input, - #| ) - #| } - #| self.input = rest - #| match ch { - #| 't' => '\t' - #| 'n' => '\n' - #| 'v' => '\u{b}' - #| 'f' => '\u{c}' - #| 'r' => '\r' - #| 'b' => '\u{8}' // backspace - #| 'u' => - #| self.parse_unicode_escape() - #| 'd' | 'D' | 'w' | 'W' | 's' | 'S' | 'p' | 'P' => - #| raise RegexpError( - #| err=InvalidCharClass, - #| source_fragment=range_rest, - #| ) - #| 'c' | 'k' => - #| raise RegexpError(err=InvalidEscape, source_fragment=self.input) - #| _ => ch - #| } - #| } - #| _ => { - #| self.input = rest - #| ch - #| } - #| } - #| if end_char < start_char { - #| raise RegexpError(err=InvalidCharClass, source_fragment=self.input) - #| } - #| chars.push(start_char) - #| chars.push(end_char) - #| } else { - #| self.input = input_copy // Restore input state - #| chars.push(start_char) - #| chars.push(start_char) - #| } - #| } else { - #| chars.push(start_char) - #| chars.push(start_char) - #| } - #| } - #| guard self.input is [']', .. rest] else { - #| raise RegexpError(err=MissingBracket, source_fragment=self.input) - #| } - #| self.input = rest // consume ']' - #| if self.flags.ignore_case { - #| CharClass(case_insensitive_char_class(chars), neg~) - #| } else { - #| CharClass(chars, neg~) - #| } - #|} - #|fn Parser::is_special_char(c : Char) -> Bool { - #| c is ('*' | '+' | '?' | '|' | '(' | ')' | '[' | ']' | '{' | '.' | '^' | '$') - #|} - #|fn Parser::parse_repeat(self : Parser) -> (UInt, UInt?) raise RegexpError { - #| let min = self.parse_number() - #| match self.input { - #| ['}', .. rest] => { - #| self.input = rest - #| (min, Some(min)) - #| } - #| [',', .. rest] => { - #| self.input = rest // consume ',' - #| match self.input { - #| ['}', .. rest] => { - #| self.input = rest - #| (min, None) - #| } - #| _ => { - #| let max = self.parse_number() - #| guard self.input is ['}', .. rest] else { - #| raise RegexpError(err=InvalidRepeatOp, source_fragment=self.input) - #| } - #| self.input = rest // consume '}' - #| if max < min { - #| raise RegexpError(err=InvalidRepeatSize, source_fragment=self.input) - #| } - #| (min, Some(max)) - #| } - #| } - #| } - #| _ => raise RegexpError(err=InvalidRepeatOp, source_fragment=self.input) - #| } - #|} - #|fn Parser::parse_number(self : Parser) -> UInt raise RegexpError { - #| let mut result = 0U - #| let mut has_digits = false - #| while self.input is [ch, .. rest] && ch >= '0' && ch <= '9' { - #| has_digits = true - #| result = result * 10U + (ch.to_int() - '0'.to_int()).reinterpret_as_uint() - #| self.input = rest - #| } - #| if not(has_digits) { - #| raise RegexpError(err=MissingRepeatArgument, source_fragment=self.input) - #| } - #| result - #|} - #|fn Parser::parse_group_name(self : Parser) -> String raise RegexpError { - #| let mut name = "" - #| let mut first = true - #| while self.input is [ch, .. rest] && ch != '>' { - #| if first { - #| if ch is ('a'..='z' | 'A'..='Z' | '_') { - #| name += ch.to_string() - #| self.input = rest - #| first = false - #| } else { - #| raise RegexpError(err=InvalidNamedCapture, source_fragment=self.input) - #| } - #| } else if ch is ('a'..='z' | 'A'..='Z' | '0'..='9' | '_') { - #| name += ch.to_string() - #| self.input = rest - #| } else { - #| raise RegexpError(err=InvalidNamedCapture, source_fragment=self.input) - #| } - #| } - #| if name == "" { - #| raise RegexpError(err=InvalidNamedCapture, source_fragment=self.input) - #| } - #| name - #|} - #|fn Parser::parse_flags(self : Parser) -> Flags raise RegexpError { - #| let mut flag = { ..self.flags } - #| let mut positive = true - #| loop self.input { - #| [':', .. rest] => { - #| self.input = rest // consume - #| return flag - #| } - #| ['m', .. rest] => { - #| flag = { ..flag, multiline: positive } - #| continue rest - #| } - #| ['s', .. rest] => { - #| flag = { ..flag, singleline: positive } - #| continue rest - #| } - #| ['i', .. rest] => { - #| flag = { ..flag, ignore_case: positive } - #| continue rest - #| } - #| ['-', .. rest] if positive => { - #| positive = false // Switch to negation mode - #| continue rest - #| } - #| [_, ..] | [] => - #| raise RegexpError(err=InvalidRepeatOp, source_fragment=self.input) - #| } - #|} - #|fn Parser::parse_unicode_escape(self : Parser) -> Char raise RegexpError { - #| match self.input { - #| ['{', .. rest] => { - #| let num = rest - #| self.input = rest // consume '{' - #| let mut codepoint = 0 - #| let mut len = 0 - #| while self.input is [ch, .. rest] && ch != '}' { - #| match ch { - #| '0'..='9' as ch => { - #| codepoint = (codepoint << 4) | (ch.to_int() - '0'.to_int()) - #| self.input = rest - #| } - #| 'a'..='f' as ch => { - #| codepoint = (codepoint << 4) | (ch.to_int() - 'a'.to_int() + 10) - #| self.input = rest - #| } - #| 'A'..='F' as ch => { - #| codepoint = (codepoint << 4) | (ch.to_int() - 'A'.to_int() + 10) - #| self.input = rest - #| } - #| _ => raise RegexpError(err=InvalidEscape, source_fragment=self.input) - #| } - #| len += 1 - #| if len > 6 { - #| raise RegexpError(err=InvalidEscape, source_fragment=num) - #| } - #| } - #| if len == 0 { - #| raise RegexpError(err=InvalidEscape, source_fragment=num) - #| } - #| guard self.input is ['}', .. rest] - #| self.input = rest // consume '}' - #| if codepoint < 0 || codepoint > 0x10FFFF { - #| raise RegexpError(err=InvalidEscape, source_fragment=num) - #| } - #| codepoint.unsafe_to_char() - #| } - #| _ => { - #| let mut codepoint = 0 - #| for i in 0..<4 { - #| match self.input { - #| ['0'..='9' as ch, .. rest] => { - #| codepoint = (codepoint << 4) | (ch.to_int() - '0'.to_int()) - #| self.input = rest - #| } - #| ['a'..='f' as ch, .. rest] => { - #| codepoint = (codepoint << 4) | (ch.to_int() - 'a'.to_int() + 10) - #| self.input = rest - #| } - #| ['A'..='F' as ch, .. rest] => { - #| codepoint = (codepoint << 4) | (ch.to_int() - 'A'.to_int() + 10) - #| self.input = rest - #| } - #| _ => raise RegexpError(err=InvalidEscape, source_fragment=self.input) - #| } - #| } - #| codepoint.unsafe_to_char() - #| } - #| } - #|} - #|fn Parser::parse_unicode_property(self : Parser) -> String raise RegexpError { - #| guard self.input is ['{', .. rest] else { - #| raise RegexpError(err=InvalidCharClass, source_fragment=self.input) - #| } - #| self.input = rest // consume '{' - #| let chars = [] - #| while self.input is [ch, .. rest] && ch != '}' { - #| chars.push(ch) - #| self.input = rest - #| } - #| guard self.input is ['}', .. rest] else { - #| raise RegexpError(err=InvalidCharClass, source_fragment=self.input) - #| } - #| self.input = rest // consume '}' - #| String::from_iter(chars.iter()) - #|} - #|fn Parser::parse_general_category( - #| self : Parser, - #| property_name : String, - #| neg : Bool, - #|) -> Ast raise RegexpError { - #| let normalized_name = match - #| @unicode.general_category_property_value_alises.get(property_name) { - #| Some(name) => name - #| None => raise RegexpError(err=InvalidCharClass, source_fragment=self.input) - #| } - #| guard @unicode.general_category_ranges.get(normalized_name) is Some(ranges) - #| CharClass(ranges, neg~) - #|} - ), - }, + "pattern.mbt": ( + #|pub(all) struct Quantifier { + #| min : Int + #| max : Int? + #| mode : @shared_types.QuantifierMode + #|} derive(Debug) + #|pub enum Assertion { + #| StartOfInput + #| EndOfInput + #| StartOfLine + #| EndOfLine + #| StartOfWord + #| EndOfWord + #| NotWordBoundary + #|} derive(Debug) + #|pub struct Pattern { + #| desc : PatternDesc + #| nullable : Bool + #|} + #|pub impl Debug for Pattern with to_repr(self) { + #| self.desc.to_repr() + #|} + #|pub enum PatternDesc { + #| Char(@shared_types.RecharSet) + #| Sequence(ReadOnlyArray[Pattern]) + #| Alternation(ReadOnlyArray[Pattern]) + #| Quantifier(Quantifier, Pattern) + #| Preference(@shared_types.Preference, Pattern) + #| Capture(name~ : String?, Pattern) + #| Assertion(Assertion) + #|} derive(Debug) + #|pub fn Pattern::is_anchored(self : Pattern) -> Bool { + #| match self.desc { + #| Char(_) => false + #| Sequence(exprs) => exprs.any(e => e.is_anchored()) + #| Alternation(exprs) => exprs.all(e => e.is_anchored()) + #| Quantifier(q, expr) => q.min > 0 && expr.is_anchored() + #| Preference(_, expr) => expr.is_anchored() + #| Capture(expr, ..) => expr.is_anchored() + #| Assertion(StartOfInput) => true + #| Assertion(_) => false + #| } + #|} + #|pub fn char(cs : @shared_types.RecharSet) -> Pattern { + #| if cs.is_empty() { + #| empty + #| } else { + #| Pattern::{ desc: Char(cs), nullable: false } + #| } + #|} + #|pub let epsilon : Pattern = Pattern::{ desc: Sequence([]), nullable: true } + #|pub fn seq(exprs : ReadOnlyArray[Pattern]) -> Pattern { + #| let flatten = [] + #| for expr in exprs { + #| if expr.desc is Sequence(nested) { + #| for e in nested { + #| flatten.push(e) + #| } + #| } else { + #| flatten.push(expr) + #| } + #| } + #| match flatten { + #| [] => epsilon + #| [expr] => expr + #| exprs => + #| Pattern::{ + #| desc: Sequence(ReadOnlyArray::from_array(exprs)), + #| nullable: exprs.all(e => e.nullable), + #| } + #| } + #|} + #|pub let empty : Pattern = Pattern::{ desc: Alternation([]), nullable: false } + #|pub fn alt(exprs : ReadOnlyArray[Pattern]) -> Pattern { + #| match exprs { + #| [] => empty + #| [expr] => expr + #| exprs => + #| Pattern::{ + #| desc: Alternation(exprs), + #| nullable: exprs.any(e => e.nullable), + #| } + #| } + #|} + #|pub fn quantifier(expr : Pattern, q : Quantifier) -> Pattern { + #| guard q.min >= 0 else { panic() } + #| guard q.max is None || (q.max is Some(max) && max >= q.min) else { panic() } + #| Pattern::{ desc: Quantifier(q, expr), nullable: expr.nullable || q.min == 0 } + #|} + #|pub fn preference(pref : @shared_types.Preference, expr : Pattern) -> Pattern { + #| if expr.desc is Char(_) { + #| expr + #| } else { + #| Pattern::{ desc: Preference(pref, expr), nullable: expr.nullable } + #| } + #|} + #|pub fn longest(expr : Pattern) -> Pattern { + #| preference(Longest, expr) + #|} + #|pub fn shortest(expr : Pattern) -> Pattern { + #| preference(Shortest, expr) + #|} + #|pub fn first(expr : Pattern) -> Pattern { + #| preference(First, expr) + #|} + #|pub fn capture(name? : String, expr : Pattern) -> Pattern { + #| Pattern::{ desc: Capture(name~, expr), nullable: expr.nullable } + #|} + #|pub fn assertion(a : Assertion) -> Pattern { + #| Pattern::{ desc: Assertion(a), nullable: true } + #|} + #|pub let start_of_input : Pattern = assertion(StartOfInput) + #|pub let end_of_input : Pattern = assertion(EndOfInput) + #|pub let start_of_line : Pattern = assertion(StartOfLine) + #|pub let end_of_line : Pattern = assertion(EndOfLine) + #|pub let start_of_word : Pattern = assertion(StartOfWord) + #|pub let end_of_word : Pattern = assertion(EndOfWord) + #|pub let not_word_boundary : Pattern = assertion(NotWordBoundary) + ), + "using.mbt": ( + #|using @debug {trait Debug, type Repr} + #|fn[T : Debug] _suppress_unused_warning_of_debug_trait(x : T) -> Unit { + #| ignore(x.to_repr()) + #|} + ) + } ) ///| -let moonbitlang_core_string_regex_internal_regexp_internal_unicode_module : RuntimePackage = RuntimePackage::new( - "moonbitlang/core/string/regex/internal/regexp/internal/unicode", - deps={ - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/array": moonbitlang_core_array_module, - "moonbitlang/core/string": moonbitlang_core_string_module, - "moonbitlang/core/int": moonbitlang_core_int_module, - "moonbitlang/core/char": moonbitlang_core_char_module, - }, +let moonbitlang_core_string_internal_regex_engine_symbol_map_module : RuntimePackage = RuntimePackage::new( + "moonbitlang/core/string/internal/regex_engine/symbol_map", + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| "moonbitlang/core/builtin", - #| "moonbitlang/core/array", - #| "moonbitlang/core/string", - #| "moonbitlang/core/int", - #| "moonbitlang/core/char" - #| ] - #|} - ), - "case_folding.mbt": ( - #|const DATA : String = - #| $|\u{61}\u{41}\u{41}\u{61}\u{62}\u{42}\u{42}\u{62}\u{63}\u{43}\u{43}\u{63}\u{64}\u{44}\u{44}\u{64}\u{65}\u{45}\u{45}\u{65}\u{66}\u{46}\u{46}\u{66}\u{67}\u{47}\u{47}\u{67}\u{68}\u{48}\u{48}\u{68}\u{69}\u{49}\u{49}\u{69}\u{6a}\u{4a}\u{4a}\u{6a}\u{6b}\u{4b}\u{4b}\u{212a}\u{212a}\u{6b}\u{6c}\u{4c}\u{4c}\u{6c}\u{6d}\u{4d}\u{4d}\u{6d}\u{6e}\u{4e}\u{4e}\u{6e}\u{6f}\u{4f}\u{4f}\u{6f}\u{70}\u{50}\u{50}\u{70}\u{71}\u{51}\u{51}\u{71}\u{72}\u{52}\u{52}\u{72}\u{73}\u{53}\u{53}\u{17f}\u{17f}\u{73}\u{74}\u{54}\u{54}\u{74}\u{75}\u{55}\u{55}\u{75}\u{76}\u{56}\u{56}\u{76}\u{77}\u{57}\u{57}\u{77}\u{78}\u{58}\u{58}\u{78}\u{79}\u{59}\u{59}\u{79}\u{7a}\u{5a}\u{5a}\u{7a}\u{3bc}\u{b5}\u{b5}\u{39c}\u{39c}\u{3bc}\u{e0}\u{c0}\u{c0}\u{e0}\u{e1}\u{c1}\u{c1}\u{e1}\u{e2}\u{c2}\u{c2}\u{e2}\u{e3}\u{c3}\u{c3}\u{e3}\u{e4}\u{c4}\u{c4}\u{e4}\u{e5}\u{c5}\u{c5}\u{212b}\u{212b}\u{e5}\u{e6}\u{c6}\u{c6}\u{e6}\u{e7}\u{c7}\u{c7}\u{e7}\u{e8}\u{c8}\u{c8}\u{e8}\u{e9}\u{c9}\u{c9}\u{e9}\u{ea}\u{ca}\u{ca}\u{ea}\u{eb}\u{cb}\u{cb}\u{eb}\u{ec}\u{cc}\u{cc}\u{ec}\u{ed}\u{cd}\u{cd}\u{ed}\u{ee}\u{ce}\u{ce}\u{ee}\u{ef}\u{cf}\u{cf}\u{ef}\u{f0}\u{d0}\u{d0}\u{f0}\u{f1}\u{d1}\u{d1}\u{f1}\u{f2}\u{d2}\u{d2}\u{f2}\u{f3}\u{d3}\u{d3}\u{f3}\u{f4}\u{d4}\u{d4}\u{f4}\u{f5}\u{d5}\u{d5}\u{f5}\u{f6}\u{d6}\u{d6}\u{f6}\u{f8}\u{d8}\u{d8}\u{f8}\u{f9}\u{d9}\u{d9}\u{f9}\u{fa}\u{da}\u{da}\u{fa}\u{fb}\u{db}\u{db}\u{fb}\u{fc}\u{dc}\u{dc}\u{fc}\u{fd}\u{dd}\u{dd}\u{fd}\u{fe}\u{de}\u{de}\u{fe}\u{101}\u{100}\u{100}\u{101}\u{103}\u{102}\u{102}\u{103}\u{105}\u{104}\u{104}\u{105}\u{107}\u{106}\u{106}\u{107}\u{109}\u{108}\u{108}\u{109}\u{10b}\u{10a}\u{10a}\u{10b}\u{10d}\u{10c}\u{10c}\u{10d}\u{10f}\u{10e}\u{10e}\u{10f}\u{111}\u{110}\u{110}\u{111}\u{113}\u{112}\u{112}\u{113}\u{115}\u{114}\u{114}\u{115}\u{117}\u{116}\u{116}\u{117}\u{119}\u{118}\u{118}\u{119}\u{11b}\u{11a}\u{11a}\u{11b}\u{11d}\u{11c}\u{11c}\u{11d}\u{11f}\u{11e}\u{11e}\u{11f}\u{121}\u{120}\u{120}\u{121}\u{123}\u{122}\u{122}\u{123}\u{125}\u{124}\u{124}\u{125}\u{127}\u{126}\u{126}\u{127}\u{129}\u{128}\u{128}\u{129}\u{12b}\u{12a}\u{12a}\u{12b}\u{12d}\u{12c}\u{12c}\u{12d}\u{12f}\u{12e}\u{12e}\u{12f}\u{133}\u{132}\u{132}\u{133}\u{135}\u{134}\u{134}\u{135}\u{137}\u{136}\u{136}\u{137}\u{13a}\u{139}\u{139}\u{13a}\u{13c}\u{13b}\u{13b}\u{13c}\u{13e}\u{13d}\u{13d}\u{13e}\u{140}\u{13f}\u{13f}\u{140}\u{142}\u{141}\u{141}\u{142}\u{144}\u{143}\u{143}\u{144}\u{146}\u{145}\u{145}\u{146}\u{148}\u{147}\u{147}\u{148}\u{14b}\u{14a}\u{14a}\u{14b}\u{14d}\u{14c}\u{14c}\u{14d}\u{14f}\u{14e}\u{14e}\u{14f}\u{151}\u{150}\u{150}\u{151}\u{153}\u{152}\u{152}\u{153}\u{155}\u{154}\u{154}\u{155}\u{157}\u{156}\u{156}\u{157}\u{159}\u{158}\u{158}\u{159}\u{15b}\u{15a}\u{15a}\u{15b}\u{15d}\u{15c}\u{15c}\u{15d}\u{15f}\u{15e}\u{15e}\u{15f}\u{161}\u{160}\u{160}\u{161}\u{163}\u{162}\u{162}\u{163}\u{165}\u{164}\u{164}\u{165}\u{167}\u{166}\u{166}\u{167}\u{169}\u{168}\u{168}\u{169}\u{16b}\u{16a}\u{16a}\u{16b}\u{16d}\u{16c}\u{16c}\u{16d}\u{16f}\u{16e}\u{16e}\u{16f}\u{171}\u{170}\u{170}\u{171}\u{173}\u{172}\u{172}\u{173}\u{175}\u{174}\u{174}\u{175}\u{177}\u{176}\u{176}\u{177}\u{ff}\u{178}\u{178}\u{ff}\u{17a}\u{179}\u{179}\u{17a}\u{17c}\u{17b}\u{17b}\u{17c}\u{17e}\u{17d}\u{17d}\u{17e}\u{253}\u{181}\u{181}\u{253}\u{183}\u{182}\u{182}\u{183}\u{185}\u{184}\u{184}\u{185}\u{254}\u{186}\u{186}\u{254}\u{188}\u{187}\u{187}\u{188}\u{256}\u{189}\u{189}\u{256}\u{257}\u{18a}\u{18a}\u{257}\u{18c}\u{18b}\u{18b}\u{18c}\u{1dd}\u{18e}\u{18e}\u{1dd}\u{259}\u{18f}\u{18f}\u{259}\u{25b}\u{190}\u{190}\u{25b}\u{192}\u{191}\u{191}\u{192}\u{260}\u{193}\u{193}\u{260}\u{263}\u{194}\u{194}\u{263}\u{269}\u{196}\u{196}\u{269}\u{268}\u{197}\u{197}\u{268}\u{199}\u{198}\u{198}\u{199}\u{26f}\u{19c}\u{19c}\u{26f}\u{272}\u{19d}\u{19d}\u{272}\u{275}\u{19f}\u{19f}\u{275}\u{1a1}\u{1a0}\u{1a0}\u{1a1}\u{1a3}\u{1a2}\u{1a2}\u{1a3}\u{1a5}\u{1a4}\u{1a4}\u{1a5}\u{280}\u{1a6}\u{1a6}\u{280}\u{1a8}\u{1a7}\u{1a7}\u{1a8}\u{283}\u{1a9}\u{1a9}\u{283}\u{1ad}\u{1ac}\u{1ac}\u{1ad}\u{288}\u{1ae}\u{1ae}\u{288}\u{1b0}\u{1af}\u{1af}\u{1b0}\u{28a}\u{1b1}\u{1b1}\u{28a}\u{28b}\u{1b2}\u{1b2}\u{28b}\u{1b4}\u{1b3}\u{1b3}\u{1b4}\u{1b6}\u{1b5}\u{1b5}\u{1b6}\u{292}\u{1b7}\u{1b7}\u{292}\u{1b9}\u{1b8}\u{1b8}\u{1b9}\u{1bd}\u{1bc}\u{1bc}\u{1bd}\u{1c6}\u{1c4}\u{1c4}\u{1c5}\u{1c5}\u{1c6}\u{1c9}\u{1c7}\u{1c7}\u{1c8}\u{1c8}\u{1c9}\u{1cc}\u{1ca}\u{1ca}\u{1cb}\u{1cb}\u{1cc}\u{1ce}\u{1cd}\u{1cd}\u{1ce}\u{1d0}\u{1cf}\u{1cf}\u{1d0}\u{1d2}\u{1d1}\u{1d1}\u{1d2}\u{1d4}\u{1d3}\u{1d3}\u{1d4}\u{1d6}\u{1d5}\u{1d5}\u{1d6}\u{1d8}\u{1d7}\u{1d7}\u{1d8}\u{1da}\u{1d9}\u{1d9}\u{1da}\u{1dc}\u{1db}\u{1db}\u{1dc}\u{1df}\u{1de}\u{1de}\u{1df}\u{1e1}\u{1e0}\u{1e0}\u{1e1}\u{1e3}\u{1e2}\u{1e2}\u{1e3}\u{1e5}\u{1e4}\u{1e4}\u{1e5}\u{1e7}\u{1e6}\u{1e6}\u{1e7}\u{1e9}\u{1e8}\u{1e8}\u{1e9}\u{1eb}\u{1ea}\u{1ea}\u{1eb}\u{1ed}\u{1ec}\u{1ec}\u{1ed}\u{1ef}\u{1ee}\u{1ee}\u{1ef}\u{1f3}\u{1f1}\u{1f1}\u{1f2}\u{1f2}\u{1f3}\u{1f5}\u{1f4}\u{1f4}\u{1f5}\u{195}\u{1f6}\u{1f6}\u{195}\u{1bf}\u{1f7}\u{1f7}\u{1bf}\u{1f9}\u{1f8}\u{1f8}\u{1f9}\u{1fb}\u{1fa}\u{1fa}\u{1fb}\u{1fd}\u{1fc}\u{1fc}\u{1fd}\u{1ff}\u{1fe}\u{1fe}\u{1ff}\u{201}\u{200}\u{200}\u{201}\u{203}\u{202}\u{202}\u{203}\u{205}\u{204}\u{204}\u{205}\u{207}\u{206}\u{206}\u{207}\u{209}\u{208}\u{208}\u{209}\u{20b}\u{20a}\u{20a}\u{20b}\u{20d}\u{20c}\u{20c}\u{20d}\u{20f}\u{20e}\u{20e}\u{20f}\u{211}\u{210}\u{210}\u{211}\u{213}\u{212}\u{212}\u{213}\u{215}\u{214}\u{214}\u{215}\u{217}\u{216}\u{216}\u{217}\u{219}\u{218}\u{218}\u{219}\u{21b}\u{21a}\u{21a}\u{21b}\u{21d}\u{21c}\u{21c}\u{21d}\u{21f}\u{21e}\u{21e}\u{21f}\u{19e}\u{220}\u{220}\u{19e}\u{223}\u{222}\u{222}\u{223}\u{225}\u{224}\u{224}\u{225}\u{227}\u{226}\u{226}\u{227}\u{229}\u{228}\u{228}\u{229}\u{22b}\u{22a}\u{22a}\u{22b}\u{22d}\u{22c}\u{22c}\u{22d}\u{22f}\u{22e}\u{22e}\u{22f}\u{231}\u{230}\u{230}\u{231}\u{233}\u{232}\u{232}\u{233}\u{2c65}\u{23a}\u{23a}\u{2c65}\u{23c}\u{23b}\u{23b}\u{23c}\u{19a}\u{23d}\u{23d}\u{19a}\u{2c66}\u{23e}\u{23e}\u{2c66}\u{242}\u{241}\u{241}\u{242}\u{180}\u{243}\u{243}\u{180}\u{289}\u{244}\u{244}\u{289}\u{28c}\u{245}\u{245}\u{28c}\u{247}\u{246}\u{246}\u{247}\u{249}\u{248}\u{248}\u{249}\u{24b}\u{24a}\u{24a}\u{24b}\u{24d}\u{24c}\u{24c}\u{24d}\u{24f}\u{24e}\u{24e}\u{24f}\u{3b9}\u{345}\u{345}\u{399}\u{399}\u{1fbe}\u{1fbe}\u{3b9}\u{371}\u{370}\u{370}\u{371}\u{373}\u{372}\u{372}\u{373}\u{377}\u{376}\u{376}\u{377}\u{3f3}\u{37f}\u{37f}\u{3f3}\u{3ac}\u{386}\u{386}\u{3ac}\u{3ad}\u{388}\u{388}\u{3ad}\u{3ae}\u{389}\u{389}\u{3ae}\u{3af}\u{38a}\u{38a}\u{3af}\u{3cc}\u{38c}\u{38c}\u{3cc}\u{3cd}\u{38e}\u{38e}\u{3cd}\u{3ce}\u{38f}\u{38f}\u{3ce}\u{3b1}\u{391}\u{391}\u{3b1}\u{3b2}\u{392}\u{392}\u{3d0}\u{3d0}\u{3b2}\u{3b3}\u{393}\u{393}\u{3b3}\u{3b4}\u{394}\u{394}\u{3b4}\u{3b5}\u{395}\u{395}\u{3f5}\u{3f5}\u{3b5}\u{3b6}\u{396}\u{396}\u{3b6}\u{3b7}\u{397}\u{397}\u{3b7}\u{3b8}\u{398}\u{398}\u{3d1}\u{3d1}\u{3f4}\u{3f4}\u{3b8}\u{3ba}\u{39a}\u{39a}\u{3f0}\u{3f0}\u{3ba}\u{3bb}\u{39b}\u{39b}\u{3bb}\u{3bd}\u{39d}\u{39d}\u{3bd}\u{3be}\u{39e}\u{39e}\u{3be}\u{3bf}\u{39f}\u{39f}\u{3bf}\u{3c0}\u{3a0}\u{3a0}\u{3d6}\u{3d6}\u{3c0}\u{3c1}\u{3a1}\u{3a1}\u{3f1}\u{3f1}\u{3c1}\u{3c3}\u{3a3}\u{3a3}\u{3c2}\u{3c2}\u{3c3}\u{3c4}\u{3a4}\u{3a4}\u{3c4}\u{3c5}\u{3a5}\u{3a5}\u{3c5}\u{3c6}\u{3a6}\u{3a6}\u{3d5}\u{3d5}\u{3c6}\u{3c7}\u{3a7}\u{3a7}\u{3c7}\u{3c8}\u{3a8}\u{3a8}\u{3c8}\u{3c9}\u{3a9}\u{3a9}\u{2126}\u{2126}\u{3c9}\u{3ca}\u{3aa}\u{3aa}\u{3ca}\u{3cb}\u{3ab}\u{3ab}\u{3cb}\u{3d7}\u{3cf}\u{3cf}\u{3d7}\u{3d9}\u{3d8}\u{3d8}\u{3d9}\u{3db}\u{3da}\u{3da}\u{3db}\u{3dd}\u{3dc}\u{3dc}\u{3dd}\u{3df}\u{3de}\u{3de}\u{3df}\u{3e1}\u{3e0}\u{3e0}\u{3e1}\u{3e3}\u{3e2}\u{3e2}\u{3e3}\u{3e5}\u{3e4}\u{3e4}\u{3e5}\u{3e7}\u{3e6}\u{3e6}\u{3e7}\u{3e9}\u{3e8}\u{3e8}\u{3e9}\u{3eb}\u{3ea}\u{3ea}\u{3eb}\u{3ed}\u{3ec}\u{3ec}\u{3ed}\u{3ef}\u{3ee}\u{3ee}\u{3ef}\u{3f8}\u{3f7}\u{3f7}\u{3f8}\u{3f2}\u{3f9}\u{3f9}\u{3f2}\u{3fb}\u{3fa}\u{3fa}\u{3fb}\u{37b}\u{3fd}\u{3fd}\u{37b}\u{37c}\u{3fe}\u{3fe}\u{37c}\u{37d}\u{3ff}\u{3ff}\u{37d}\u{450}\u{400}\u{400}\u{450}\u{451}\u{401}\u{401}\u{451}\u{452}\u{402}\u{402}\u{452}\u{453}\u{403}\u{403}\u{453}\u{454}\u{404}\u{404}\u{454}\u{455}\u{405}\u{405}\u{455}\u{456}\u{406}\u{406}\u{456}\u{457}\u{407}\u{407}\u{457}\u{458}\u{408}\u{408}\u{458}\u{459}\u{409}\u{409}\u{459}\u{45a}\u{40a}\u{40a}\u{45a}\u{45b}\u{40b}\u{40b}\u{45b}\u{45c}\u{40c}\u{40c}\u{45c}\u{45d}\u{40d}\u{40d}\u{45d}\u{45e}\u{40e}\u{40e}\u{45e}\u{45f}\u{40f}\u{40f}\u{45f}\u{430}\u{410}\u{410}\u{430}\u{431}\u{411}\u{411}\u{431}\u{432}\u{412}\u{412}\u{1c80}\u{1c80}\u{432}\u{433}\u{413}\u{413}\u{433}\u{434}\u{414}\u{414}\u{1c81}\u{1c81}\u{434}\u{435}\u{415}\u{415}\u{435}\u{436}\u{416}\u{416}\u{436}\u{437}\u{417}\u{417}\u{437}\u{438}\u{418}\u{418}\u{438}\u{439}\u{419}\u{419}\u{439}\u{43a}\u{41a}\u{41a}\u{43a}\u{43b}\u{41b}\u{41b}\u{43b}\u{43c}\u{41c}\u{41c}\u{43c}\u{43d}\u{41d}\u{41d}\u{43d}\u{43e}\u{41e}\u{41e}\u{1c82}\u{1c82}\u{43e}\u{43f}\u{41f}\u{41f}\u{43f}\u{440}\u{420}\u{420}\u{440}\u{441}\u{421}\u{421}\u{1c83}\u{1c83}\u{441}\u{442}\u{422}\u{422}\u{1c84}\u{1c84}\u{1c85}\u{1c85}\u{442}\u{443}\u{423}\u{423}\u{443}\u{444}\u{424}\u{424}\u{444}\u{445}\u{425}\u{425}\u{445}\u{446}\u{426}\u{426}\u{446}\u{447}\u{427}\u{427}\u{447}\u{448}\u{428}\u{428}\u{448}\u{449}\u{429}\u{429}\u{449}\u{44a}\u{42a}\u{42a}\u{1c86}\u{1c86}\u{44a}\u{44b}\u{42b}\u{42b}\u{44b}\u{44c}\u{42c}\u{42c}\u{44c}\u{44d}\u{42d}\u{42d}\u{44d}\u{44e}\u{42e}\u{42e}\u{44e}\u{44f}\u{42f}\u{42f}\u{44f}\u{461}\u{460}\u{460}\u{461}\u{463}\u{462}\u{462}\u{1c87}\u{1c87}\u{463}\u{465}\u{464}\u{464}\u{465}\u{467}\u{466}\u{466}\u{467}\u{469}\u{468}\u{468}\u{469}\u{46b}\u{46a}\u{46a}\u{46b}\u{46d}\u{46c}\u{46c}\u{46d}\u{46f}\u{46e}\u{46e}\u{46f}\u{471}\u{470}\u{470}\u{471}\u{473}\u{472}\u{472}\u{473}\u{475}\u{474}\u{474}\u{475}\u{477}\u{476}\u{476}\u{477}\u{479}\u{478}\u{478}\u{479}\u{47b}\u{47a}\u{47a}\u{47b}\u{47d}\u{47c}\u{47c}\u{47d}\u{47f}\u{47e}\u{47e}\u{47f}\u{481}\u{480}\u{480}\u{481}\u{48b}\u{48a}\u{48a}\u{48b}\u{48d}\u{48c}\u{48c}\u{48d}\u{48f}\u{48e}\u{48e}\u{48f}\u{491}\u{490}\u{490}\u{491}\u{493}\u{492}\u{492}\u{493}\u{495}\u{494}\u{494}\u{495}\u{497}\u{496}\u{496}\u{497}\u{499}\u{498}\u{498}\u{499}\u{49b}\u{49a}\u{49a}\u{49b}\u{49d}\u{49c}\u{49c}\u{49d}\u{49f}\u{49e}\u{49e}\u{49f}\u{4a1}\u{4a0}\u{4a0}\u{4a1}\u{4a3}\u{4a2}\u{4a2}\u{4a3}\u{4a5}\u{4a4}\u{4a4}\u{4a5}\u{4a7}\u{4a6}\u{4a6}\u{4a7}\u{4a9}\u{4a8}\u{4a8}\u{4a9}\u{4ab}\u{4aa}\u{4aa}\u{4ab}\u{4ad}\u{4ac}\u{4ac}\u{4ad}\u{4af}\u{4ae}\u{4ae}\u{4af}\u{4b1}\u{4b0}\u{4b0}\u{4b1}\u{4b3}\u{4b2}\u{4b2}\u{4b3}\u{4b5}\u{4b4}\u{4b4}\u{4b5}\u{4b7}\u{4b6}\u{4b6}\u{4b7}\u{4b9}\u{4b8}\u{4b8}\u{4b9}\u{4bb}\u{4ba}\u{4ba}\u{4bb}\u{4bd}\u{4bc}\u{4bc}\u{4bd}\u{4bf}\u{4be}\u{4be}\u{4bf}\u{4cf}\u{4c0}\u{4c0}\u{4cf}\u{4c2}\u{4c1}\u{4c1}\u{4c2}\u{4c4}\u{4c3}\u{4c3}\u{4c4}\u{4c6}\u{4c5}\u{4c5}\u{4c6}\u{4c8}\u{4c7}\u{4c7}\u{4c8}\u{4ca}\u{4c9}\u{4c9}\u{4ca}\u{4cc}\u{4cb}\u{4cb}\u{4cc}\u{4ce}\u{4cd}\u{4cd}\u{4ce}\u{4d1}\u{4d0}\u{4d0}\u{4d1}\u{4d3}\u{4d2}\u{4d2}\u{4d3}\u{4d5}\u{4d4}\u{4d4}\u{4d5}\u{4d7}\u{4d6}\u{4d6}\u{4d7}\u{4d9}\u{4d8}\u{4d8}\u{4d9}\u{4db}\u{4da}\u{4da}\u{4db}\u{4dd}\u{4dc}\u{4dc}\u{4dd}\u{4df}\u{4de}\u{4de}\u{4df}\u{4e1}\u{4e0}\u{4e0}\u{4e1}\u{4e3}\u{4e2}\u{4e2}\u{4e3}\u{4e5}\u{4e4}\u{4e4}\u{4e5}\u{4e7}\u{4e6}\u{4e6}\u{4e7}\u{4e9}\u{4e8}\u{4e8}\u{4e9}\u{4eb}\u{4ea}\u{4ea}\u{4eb}\u{4ed}\u{4ec}\u{4ec}\u{4ed}\u{4ef}\u{4ee}\u{4ee}\u{4ef}\u{4f1}\u{4f0}\u{4f0}\u{4f1}\u{4f3}\u{4f2}\u{4f2}\u{4f3}\u{4f5}\u{4f4}\u{4f4}\u{4f5}\u{4f7}\u{4f6}\u{4f6}\u{4f7}\u{4f9}\u{4f8}\u{4f8}\u{4f9}\u{4fb}\u{4fa}\u{4fa}\u{4fb}\u{4fd}\u{4fc}\u{4fc}\u{4fd}\u{4ff}\u{4fe}\u{4fe}\u{4ff}\u{501}\u{500}\u{500}\u{501}\u{503}\u{502}\u{502}\u{503}\u{505}\u{504}\u{504}\u{505}\u{507}\u{506}\u{506}\u{507}\u{509}\u{508}\u{508}\u{509}\u{50b}\u{50a}\u{50a}\u{50b}\u{50d}\u{50c}\u{50c}\u{50d}\u{50f}\u{50e}\u{50e}\u{50f}\u{511}\u{510}\u{510}\u{511}\u{513}\u{512}\u{512}\u{513}\u{515}\u{514}\u{514}\u{515}\u{517}\u{516}\u{516}\u{517}\u{519}\u{518}\u{518}\u{519}\u{51b}\u{51a}\u{51a}\u{51b}\u{51d}\u{51c}\u{51c}\u{51d}\u{51f}\u{51e}\u{51e}\u{51f}\u{521}\u{520}\u{520}\u{521}\u{523}\u{522}\u{522}\u{523}\u{525}\u{524}\u{524}\u{525}\u{527}\u{526}\u{526}\u{527}\u{529}\u{528}\u{528}\u{529}\u{52b}\u{52a}\u{52a}\u{52b}\u{52d}\u{52c}\u{52c}\u{52d}\u{52f}\u{52e}\u{52e}\u{52f}\u{561}\u{531}\u{531}\u{561}\u{562}\u{532}\u{532}\u{562}\u{563}\u{533}\u{533}\u{563}\u{564}\u{534}\u{534}\u{564}\u{565}\u{535}\u{535}\u{565}\u{566}\u{536}\u{536}\u{566}\u{567}\u{537}\u{537}\u{567}\u{568}\u{538}\u{538}\u{568}\u{569}\u{539}\u{539}\u{569}\u{56a}\u{53a}\u{53a}\u{56a}\u{56b}\u{53b}\u{53b}\u{56b}\u{56c}\u{53c}\u{53c}\u{56c}\u{56d}\u{53d}\u{53d}\u{56d}\u{56e}\u{53e}\u{53e}\u{56e}\u{56f}\u{53f}\u{53f}\u{56f}\u{570}\u{540}\u{540}\u{570}\u{571}\u{541}\u{541}\u{571}\u{572}\u{542}\u{542}\u{572}\u{573}\u{543}\u{543}\u{573}\u{574}\u{544}\u{544}\u{574}\u{575}\u{545}\u{545}\u{575}\u{576}\u{546}\u{546}\u{576}\u{577}\u{547}\u{547}\u{577}\u{578}\u{548}\u{548}\u{578}\u{579}\u{549}\u{549}\u{579}\u{57a}\u{54a}\u{54a}\u{57a}\u{57b}\u{54b}\u{54b}\u{57b}\u{57c}\u{54c}\u{54c}\u{57c}\u{57d}\u{54d}\u{54d}\u{57d}\u{57e}\u{54e}\u{54e}\u{57e}\u{57f}\u{54f}\u{54f}\u{57f}\u{580}\u{550}\u{550}\u{580}\u{581}\u{551}\u{551}\u{581}\u{582}\u{552}\u{552}\u{582}\u{583}\u{553}\u{553}\u{583}\u{584}\u{554}\u{554}\u{584}\u{585}\u{555}\u{555}\u{585}\u{586}\u{556}\u{556}\u{586}\u{2d00}\u{10a0}\u{10a0}\u{2d00}\u{2d01}\u{10a1}\u{10a1}\u{2d01}\u{2d02}\u{10a2}\u{10a2}\u{2d02}\u{2d03}\u{10a3}\u{10a3}\u{2d03}\u{2d04}\u{10a4}\u{10a4}\u{2d04}\u{2d05}\u{10a5}\u{10a5}\u{2d05}\u{2d06}\u{10a6}\u{10a6}\u{2d06}\u{2d07}\u{10a7}\u{10a7}\u{2d07}\u{2d08}\u{10a8}\u{10a8}\u{2d08}\u{2d09}\u{10a9}\u{10a9}\u{2d09}\u{2d0a}\u{10aa}\u{10aa}\u{2d0a}\u{2d0b}\u{10ab}\u{10ab}\u{2d0b}\u{2d0c}\u{10ac}\u{10ac}\u{2d0c}\u{2d0d}\u{10ad}\u{10ad}\u{2d0d}\u{2d0e}\u{10ae}\u{10ae}\u{2d0e}\u{2d0f}\u{10af}\u{10af}\u{2d0f}\u{2d10}\u{10b0}\u{10b0}\u{2d10}\u{2d11}\u{10b1}\u{10b1}\u{2d11}\u{2d12}\u{10b2}\u{10b2}\u{2d12}\u{2d13}\u{10b3}\u{10b3}\u{2d13}\u{2d14}\u{10b4}\u{10b4}\u{2d14}\u{2d15}\u{10b5}\u{10b5}\u{2d15}\u{2d16}\u{10b6}\u{10b6}\u{2d16}\u{2d17}\u{10b7}\u{10b7}\u{2d17}\u{2d18}\u{10b8}\u{10b8}\u{2d18}\u{2d19}\u{10b9}\u{10b9}\u{2d19}\u{2d1a}\u{10ba}\u{10ba}\u{2d1a}\u{2d1b}\u{10bb}\u{10bb}\u{2d1b}\u{2d1c}\u{10bc}\u{10bc}\u{2d1c}\u{2d1d}\u{10bd}\u{10bd}\u{2d1d}\u{2d1e}\u{10be}\u{10be}\u{2d1e}\u{2d1f}\u{10bf}\u{10bf}\u{2d1f}\u{2d20}\u{10c0}\u{10c0}\u{2d20}\u{2d21}\u{10c1}\u{10c1}\u{2d21}\u{2d22}\u{10c2}\u{10c2}\u{2d22}\u{2d23}\u{10c3}\u{10c3}\u{2d23}\u{2d24}\u{10c4}\u{10c4}\u{2d24}\u{2d25}\u{10c5}\u{10c5}\u{2d25}\u{2d27}\u{10c7}\u{10c7}\u{2d27}\u{2d2d}\u{10cd}\u{10cd}\u{2d2d}\u{13f0}\u{13f8}\u{13f8}\u{13f0}\u{13f1}\u{13f9}\u{13f9}\u{13f1}\u{13f2}\u{13fa}\u{13fa}\u{13f2}\u{13f3}\u{13fb}\u{13fb}\u{13f3}\u{13f4}\u{13fc}\u{13fc}\u{13f4}\u{13f5}\u{13fd}\u{13fd}\u{13f5}\u{a64b}\u{1c88}\u{1c88}\u{a64a}\u{a64a}\u{a64b}\u{1c8a}\u{1c89}\u{1c89}\u{1c8a}\u{10d0}\u{1c90}\u{1c90}\u{10d0}\u{10d1}\u{1c91}\u{1c91}\u{10d1}\u{10d2}\u{1c92}\u{1c92}\u{10d2}\u{10d3}\u{1c93}\u{1c93}\u{10d3}\u{10d4}\u{1c94}\u{1c94}\u{10d4}\u{10d5}\u{1c95}\u{1c95}\u{10d5}\u{10d6}\u{1c96}\u{1c96}\u{10d6}\u{10d7}\u{1c97}\u{1c97}\u{10d7}\u{10d8}\u{1c98}\u{1c98}\u{10d8}\u{10d9}\u{1c99}\u{1c99}\u{10d9}\u{10da}\u{1c9a}\u{1c9a}\u{10da}\u{10db}\u{1c9b}\u{1c9b}\u{10db}\u{10dc}\u{1c9c}\u{1c9c}\u{10dc}\u{10dd}\u{1c9d}\u{1c9d}\u{10dd}\u{10de}\u{1c9e}\u{1c9e}\u{10de}\u{10df}\u{1c9f}\u{1c9f}\u{10df}\u{10e0}\u{1ca0}\u{1ca0}\u{10e0}\u{10e1}\u{1ca1}\u{1ca1}\u{10e1}\u{10e2}\u{1ca2}\u{1ca2}\u{10e2}\u{10e3}\u{1ca3}\u{1ca3}\u{10e3}\u{10e4}\u{1ca4}\u{1ca4}\u{10e4}\u{10e5}\u{1ca5}\u{1ca5}\u{10e5}\u{10e6}\u{1ca6}\u{1ca6}\u{10e6}\u{10e7}\u{1ca7}\u{1ca7}\u{10e7}\u{10e8}\u{1ca8}\u{1ca8}\u{10e8}\u{10e9}\u{1ca9}\u{1ca9}\u{10e9}\u{10ea}\u{1caa}\u{1caa}\u{10ea}\u{10eb}\u{1cab}\u{1cab}\u{10eb}\u{10ec}\u{1cac}\u{1cac}\u{10ec}\u{10ed}\u{1cad}\u{1cad}\u{10ed}\u{10ee}\u{1cae}\u{1cae}\u{10ee}\u{10ef}\u{1caf}\u{1caf}\u{10ef}\u{10f0}\u{1cb0}\u{1cb0}\u{10f0}\u{10f1}\u{1cb1}\u{1cb1}\u{10f1}\u{10f2}\u{1cb2}\u{1cb2}\u{10f2}\u{10f3}\u{1cb3}\u{1cb3}\u{10f3}\u{10f4}\u{1cb4}\u{1cb4}\u{10f4}\u{10f5}\u{1cb5}\u{1cb5}\u{10f5}\u{10f6}\u{1cb6}\u{1cb6}\u{10f6}\u{10f7}\u{1cb7}\u{1cb7}\u{10f7}\u{10f8}\u{1cb8}\u{1cb8}\u{10f8}\u{10f9}\u{1cb9}\u{1cb9}\u{10f9}\u{10fa}\u{1cba}\u{1cba}\u{10fa}\u{10fd}\u{1cbd}\u{1cbd}\u{10fd}\u{10fe}\u{1cbe}\u{1cbe}\u{10fe}\u{10ff}\u{1cbf}\u{1cbf}\u{10ff}\u{1e01}\u{1e00}\u{1e00}\u{1e01}\u{1e03}\u{1e02}\u{1e02}\u{1e03}\u{1e05}\u{1e04}\u{1e04}\u{1e05}\u{1e07}\u{1e06}\u{1e06}\u{1e07}\u{1e09}\u{1e08}\u{1e08}\u{1e09}\u{1e0b}\u{1e0a}\u{1e0a}\u{1e0b}\u{1e0d}\u{1e0c}\u{1e0c}\u{1e0d}\u{1e0f}\u{1e0e}\u{1e0e}\u{1e0f}\u{1e11}\u{1e10}\u{1e10}\u{1e11}\u{1e13}\u{1e12}\u{1e12}\u{1e13}\u{1e15}\u{1e14}\u{1e14}\u{1e15}\u{1e17}\u{1e16}\u{1e16}\u{1e17}\u{1e19}\u{1e18}\u{1e18}\u{1e19}\u{1e1b}\u{1e1a}\u{1e1a}\u{1e1b}\u{1e1d}\u{1e1c}\u{1e1c}\u{1e1d}\u{1e1f}\u{1e1e}\u{1e1e}\u{1e1f}\u{1e21}\u{1e20}\u{1e20}\u{1e21}\u{1e23}\u{1e22}\u{1e22}\u{1e23}\u{1e25}\u{1e24}\u{1e24}\u{1e25}\u{1e27}\u{1e26}\u{1e26}\u{1e27}\u{1e29}\u{1e28}\u{1e28}\u{1e29}\u{1e2b}\u{1e2a}\u{1e2a}\u{1e2b}\u{1e2d}\u{1e2c}\u{1e2c}\u{1e2d}\u{1e2f}\u{1e2e}\u{1e2e}\u{1e2f}\u{1e31}\u{1e30}\u{1e30}\u{1e31}\u{1e33}\u{1e32}\u{1e32}\u{1e33}\u{1e35}\u{1e34}\u{1e34}\u{1e35}\u{1e37}\u{1e36}\u{1e36}\u{1e37}\u{1e39}\u{1e38}\u{1e38}\u{1e39}\u{1e3b}\u{1e3a}\u{1e3a}\u{1e3b}\u{1e3d}\u{1e3c}\u{1e3c}\u{1e3d}\u{1e3f}\u{1e3e}\u{1e3e}\u{1e3f}\u{1e41}\u{1e40}\u{1e40}\u{1e41}\u{1e43}\u{1e42}\u{1e42}\u{1e43}\u{1e45}\u{1e44}\u{1e44}\u{1e45}\u{1e47}\u{1e46}\u{1e46}\u{1e47}\u{1e49}\u{1e48}\u{1e48}\u{1e49}\u{1e4b}\u{1e4a}\u{1e4a}\u{1e4b}\u{1e4d}\u{1e4c}\u{1e4c}\u{1e4d}\u{1e4f}\u{1e4e}\u{1e4e}\u{1e4f}\u{1e51}\u{1e50}\u{1e50}\u{1e51}\u{1e53}\u{1e52}\u{1e52}\u{1e53}\u{1e55}\u{1e54}\u{1e54}\u{1e55}\u{1e57}\u{1e56}\u{1e56}\u{1e57}\u{1e59}\u{1e58}\u{1e58}\u{1e59}\u{1e5b}\u{1e5a}\u{1e5a}\u{1e5b}\u{1e5d}\u{1e5c}\u{1e5c}\u{1e5d}\u{1e5f}\u{1e5e}\u{1e5e}\u{1e5f}\u{1e61}\u{1e60}\u{1e60}\u{1e9b}\u{1e9b}\u{1e61}\u{1e63}\u{1e62}\u{1e62}\u{1e63}\u{1e65}\u{1e64}\u{1e64}\u{1e65}\u{1e67}\u{1e66}\u{1e66}\u{1e67}\u{1e69}\u{1e68}\u{1e68}\u{1e69}\u{1e6b}\u{1e6a}\u{1e6a}\u{1e6b}\u{1e6d}\u{1e6c}\u{1e6c}\u{1e6d}\u{1e6f}\u{1e6e}\u{1e6e}\u{1e6f}\u{1e71}\u{1e70}\u{1e70}\u{1e71}\u{1e73}\u{1e72}\u{1e72}\u{1e73}\u{1e75}\u{1e74}\u{1e74}\u{1e75}\u{1e77}\u{1e76}\u{1e76}\u{1e77}\u{1e79}\u{1e78}\u{1e78}\u{1e79}\u{1e7b}\u{1e7a}\u{1e7a}\u{1e7b}\u{1e7d}\u{1e7c}\u{1e7c}\u{1e7d}\u{1e7f}\u{1e7e}\u{1e7e}\u{1e7f}\u{1e81}\u{1e80}\u{1e80}\u{1e81}\u{1e83}\u{1e82}\u{1e82}\u{1e83}\u{1e85}\u{1e84}\u{1e84}\u{1e85}\u{1e87}\u{1e86}\u{1e86}\u{1e87}\u{1e89}\u{1e88}\u{1e88}\u{1e89}\u{1e8b}\u{1e8a}\u{1e8a}\u{1e8b}\u{1e8d}\u{1e8c}\u{1e8c}\u{1e8d}\u{1e8f}\u{1e8e}\u{1e8e}\u{1e8f}\u{1e91}\u{1e90}\u{1e90}\u{1e91}\u{1e93}\u{1e92}\u{1e92}\u{1e93}\u{1e95}\u{1e94}\u{1e94}\u{1e95}\u{df}\u{1e9e}\u{1e9e}\u{df}\u{1ea1}\u{1ea0}\u{1ea0}\u{1ea1}\u{1ea3}\u{1ea2}\u{1ea2}\u{1ea3}\u{1ea5}\u{1ea4}\u{1ea4}\u{1ea5}\u{1ea7}\u{1ea6}\u{1ea6}\u{1ea7}\u{1ea9}\u{1ea8}\u{1ea8}\u{1ea9}\u{1eab}\u{1eaa}\u{1eaa}\u{1eab}\u{1ead}\u{1eac}\u{1eac}\u{1ead}\u{1eaf}\u{1eae}\u{1eae}\u{1eaf}\u{1eb1}\u{1eb0}\u{1eb0}\u{1eb1}\u{1eb3}\u{1eb2}\u{1eb2}\u{1eb3}\u{1eb5}\u{1eb4}\u{1eb4}\u{1eb5}\u{1eb7}\u{1eb6}\u{1eb6}\u{1eb7}\u{1eb9}\u{1eb8}\u{1eb8}\u{1eb9}\u{1ebb}\u{1eba}\u{1eba}\u{1ebb}\u{1ebd}\u{1ebc}\u{1ebc}\u{1ebd}\u{1ebf}\u{1ebe}\u{1ebe}\u{1ebf}\u{1ec1}\u{1ec0}\u{1ec0}\u{1ec1}\u{1ec3}\u{1ec2}\u{1ec2}\u{1ec3}\u{1ec5}\u{1ec4}\u{1ec4}\u{1ec5}\u{1ec7}\u{1ec6}\u{1ec6}\u{1ec7}\u{1ec9}\u{1ec8}\u{1ec8}\u{1ec9}\u{1ecb}\u{1eca}\u{1eca}\u{1ecb}\u{1ecd}\u{1ecc}\u{1ecc}\u{1ecd}\u{1ecf}\u{1ece}\u{1ece}\u{1ecf}\u{1ed1}\u{1ed0}\u{1ed0}\u{1ed1}\u{1ed3}\u{1ed2}\u{1ed2}\u{1ed3}\u{1ed5}\u{1ed4}\u{1ed4}\u{1ed5}\u{1ed7}\u{1ed6}\u{1ed6}\u{1ed7}\u{1ed9}\u{1ed8}\u{1ed8}\u{1ed9}\u{1edb}\u{1eda}\u{1eda}\u{1edb}\u{1edd}\u{1edc}\u{1edc}\u{1edd}\u{1edf}\u{1ede}\u{1ede}\u{1edf}\u{1ee1}\u{1ee0}\u{1ee0}\u{1ee1}\u{1ee3}\u{1ee2}\u{1ee2}\u{1ee3}\u{1ee5}\u{1ee4}\u{1ee4}\u{1ee5}\u{1ee7}\u{1ee6}\u{1ee6}\u{1ee7}\u{1ee9}\u{1ee8}\u{1ee8}\u{1ee9}\u{1eeb}\u{1eea}\u{1eea}\u{1eeb}\u{1eed}\u{1eec}\u{1eec}\u{1eed}\u{1eef}\u{1eee}\u{1eee}\u{1eef}\u{1ef1}\u{1ef0}\u{1ef0}\u{1ef1}\u{1ef3}\u{1ef2}\u{1ef2}\u{1ef3}\u{1ef5}\u{1ef4}\u{1ef4}\u{1ef5}\u{1ef7}\u{1ef6}\u{1ef6}\u{1ef7}\u{1ef9}\u{1ef8}\u{1ef8}\u{1ef9}\u{1efb}\u{1efa}\u{1efa}\u{1efb}\u{1efd}\u{1efc}\u{1efc}\u{1efd}\u{1eff}\u{1efe}\u{1efe}\u{1eff}\u{1f00}\u{1f08}\u{1f08}\u{1f00}\u{1f01}\u{1f09}\u{1f09}\u{1f01}\u{1f02}\u{1f0a}\u{1f0a}\u{1f02}\u{1f03}\u{1f0b}\u{1f0b}\u{1f03}\u{1f04}\u{1f0c}\u{1f0c}\u{1f04}\u{1f05}\u{1f0d}\u{1f0d}\u{1f05}\u{1f06}\u{1f0e}\u{1f0e}\u{1f06}\u{1f07}\u{1f0f}\u{1f0f}\u{1f07}\u{1f10}\u{1f18}\u{1f18}\u{1f10}\u{1f11}\u{1f19}\u{1f19}\u{1f11}\u{1f12}\u{1f1a}\u{1f1a}\u{1f12}\u{1f13}\u{1f1b}\u{1f1b}\u{1f13}\u{1f14}\u{1f1c}\u{1f1c}\u{1f14}\u{1f15}\u{1f1d}\u{1f1d}\u{1f15}\u{1f20}\u{1f28}\u{1f28}\u{1f20}\u{1f21}\u{1f29}\u{1f29}\u{1f21}\u{1f22}\u{1f2a}\u{1f2a}\u{1f22}\u{1f23}\u{1f2b}\u{1f2b}\u{1f23}\u{1f24}\u{1f2c}\u{1f2c}\u{1f24}\u{1f25}\u{1f2d}\u{1f2d}\u{1f25}\u{1f26}\u{1f2e}\u{1f2e}\u{1f26}\u{1f27}\u{1f2f}\u{1f2f}\u{1f27}\u{1f30}\u{1f38}\u{1f38}\u{1f30}\u{1f31}\u{1f39}\u{1f39}\u{1f31}\u{1f32}\u{1f3a}\u{1f3a}\u{1f32}\u{1f33}\u{1f3b}\u{1f3b}\u{1f33}\u{1f34}\u{1f3c}\u{1f3c}\u{1f34}\u{1f35}\u{1f3d}\u{1f3d}\u{1f35}\u{1f36}\u{1f3e}\u{1f3e}\u{1f36}\u{1f37}\u{1f3f}\u{1f3f}\u{1f37}\u{1f40}\u{1f48}\u{1f48}\u{1f40}\u{1f41}\u{1f49}\u{1f49}\u{1f41}\u{1f42}\u{1f4a}\u{1f4a}\u{1f42}\u{1f43}\u{1f4b}\u{1f4b}\u{1f43}\u{1f44}\u{1f4c}\u{1f4c}\u{1f44}\u{1f45}\u{1f4d}\u{1f4d}\u{1f45}\u{1f51}\u{1f59}\u{1f59}\u{1f51}\u{1f53}\u{1f5b}\u{1f5b}\u{1f53}\u{1f55}\u{1f5d}\u{1f5d}\u{1f55}\u{1f57}\u{1f5f}\u{1f5f}\u{1f57}\u{1f60}\u{1f68}\u{1f68}\u{1f60}\u{1f61}\u{1f69}\u{1f69}\u{1f61}\u{1f62}\u{1f6a}\u{1f6a}\u{1f62}\u{1f63}\u{1f6b}\u{1f6b}\u{1f63}\u{1f64}\u{1f6c}\u{1f6c}\u{1f64}\u{1f65}\u{1f6d}\u{1f6d}\u{1f65}\u{1f66}\u{1f6e}\u{1f6e}\u{1f66}\u{1f67}\u{1f6f}\u{1f6f}\u{1f67}\u{1f80}\u{1f88}\u{1f88}\u{1f80}\u{1f81}\u{1f89}\u{1f89}\u{1f81}\u{1f82}\u{1f8a}\u{1f8a}\u{1f82}\u{1f83}\u{1f8b}\u{1f8b}\u{1f83}\u{1f84}\u{1f8c}\u{1f8c}\u{1f84}\u{1f85}\u{1f8d}\u{1f8d}\u{1f85}\u{1f86}\u{1f8e}\u{1f8e}\u{1f86}\u{1f87}\u{1f8f}\u{1f8f}\u{1f87}\u{1f90}\u{1f98}\u{1f98}\u{1f90}\u{1f91}\u{1f99}\u{1f99}\u{1f91}\u{1f92}\u{1f9a}\u{1f9a}\u{1f92}\u{1f93}\u{1f9b}\u{1f9b}\u{1f93}\u{1f94}\u{1f9c}\u{1f9c}\u{1f94}\u{1f95}\u{1f9d}\u{1f9d}\u{1f95}\u{1f96}\u{1f9e}\u{1f9e}\u{1f96}\u{1f97}\u{1f9f}\u{1f9f}\u{1f97}\u{1fa0}\u{1fa8}\u{1fa8}\u{1fa0}\u{1fa1}\u{1fa9}\u{1fa9}\u{1fa1}\u{1fa2}\u{1faa}\u{1faa}\u{1fa2}\u{1fa3}\u{1fab}\u{1fab}\u{1fa3}\u{1fa4}\u{1fac}\u{1fac}\u{1fa4}\u{1fa5}\u{1fad}\u{1fad}\u{1fa5}\u{1fa6}\u{1fae}\u{1fae}\u{1fa6}\u{1fa7}\u{1faf}\u{1faf}\u{1fa7}\u{1fb0}\u{1fb8}\u{1fb8}\u{1fb0}\u{1fb1}\u{1fb9}\u{1fb9}\u{1fb1}\u{1f70}\u{1fba}\u{1fba}\u{1f70}\u{1f71}\u{1fbb}\u{1fbb}\u{1f71}\u{1fb3}\u{1fbc}\u{1fbc}\u{1fb3}\u{1f72}\u{1fc8}\u{1fc8}\u{1f72}\u{1f73}\u{1fc9}\u{1fc9}\u{1f73}\u{1f74}\u{1fca}\u{1fca}\u{1f74}\u{1f75}\u{1fcb}\u{1fcb}\u{1f75}\u{1fc3}\u{1fcc}\u{1fcc}\u{1fc3}\u{390}\u{1fd3}\u{1fd3}\u{390}\u{1fd0}\u{1fd8}\u{1fd8}\u{1fd0}\u{1fd1}\u{1fd9}\u{1fd9}\u{1fd1}\u{1f76}\u{1fda}\u{1fda}\u{1f76}\u{1f77}\u{1fdb}\u{1fdb}\u{1f77}\u{3b0}\u{1fe3}\u{1fe3}\u{3b0}\u{1fe0}\u{1fe8}\u{1fe8}\u{1fe0}\u{1fe1}\u{1fe9}\u{1fe9}\u{1fe1}\u{1f7a}\u{1fea}\u{1fea}\u{1f7a}\u{1f7b}\u{1feb}\u{1feb}\u{1f7b}\u{1fe5}\u{1fec}\u{1fec}\u{1fe5}\u{1f78}\u{1ff8}\u{1ff8}\u{1f78}\u{1f79}\u{1ff9}\u{1ff9}\u{1f79}\u{1f7c}\u{1ffa}\u{1ffa}\u{1f7c}\u{1f7d}\u{1ffb}\u{1ffb}\u{1f7d}\u{1ff3}\u{1ffc}\u{1ffc}\u{1ff3}\u{214e}\u{2132}\u{2132}\u{214e}\u{2170}\u{2160}\u{2160}\u{2170}\u{2171}\u{2161}\u{2161}\u{2171}\u{2172}\u{2162}\u{2162}\u{2172}\u{2173}\u{2163}\u{2163}\u{2173}\u{2174}\u{2164}\u{2164}\u{2174}\u{2175}\u{2165}\u{2165}\u{2175}\u{2176}\u{2166}\u{2166}\u{2176}\u{2177}\u{2167}\u{2167}\u{2177}\u{2178}\u{2168}\u{2168}\u{2178}\u{2179}\u{2169}\u{2169}\u{2179}\u{217a}\u{216a}\u{216a}\u{217a}\u{217b}\u{216b}\u{216b}\u{217b}\u{217c}\u{216c}\u{216c}\u{217c}\u{217d}\u{216d}\u{216d}\u{217d}\u{217e}\u{216e}\u{216e}\u{217e}\u{217f}\u{216f}\u{216f}\u{217f}\u{2184}\u{2183}\u{2183}\u{2184}\u{24d0}\u{24b6}\u{24b6}\u{24d0}\u{24d1}\u{24b7}\u{24b7}\u{24d1}\u{24d2}\u{24b8}\u{24b8}\u{24d2}\u{24d3}\u{24b9}\u{24b9}\u{24d3}\u{24d4}\u{24ba}\u{24ba}\u{24d4}\u{24d5}\u{24bb}\u{24bb}\u{24d5}\u{24d6}\u{24bc}\u{24bc}\u{24d6}\u{24d7}\u{24bd}\u{24bd}\u{24d7}\u{24d8}\u{24be}\u{24be}\u{24d8}\u{24d9}\u{24bf}\u{24bf}\u{24d9}\u{24da}\u{24c0}\u{24c0}\u{24da}\u{24db}\u{24c1}\u{24c1}\u{24db}\u{24dc}\u{24c2}\u{24c2}\u{24dc}\u{24dd}\u{24c3}\u{24c3}\u{24dd}\u{24de}\u{24c4}\u{24c4}\u{24de}\u{24df}\u{24c5}\u{24c5}\u{24df}\u{24e0}\u{24c6}\u{24c6}\u{24e0}\u{24e1}\u{24c7}\u{24c7}\u{24e1}\u{24e2}\u{24c8}\u{24c8}\u{24e2}\u{24e3}\u{24c9}\u{24c9}\u{24e3}\u{24e4}\u{24ca}\u{24ca}\u{24e4}\u{24e5}\u{24cb}\u{24cb}\u{24e5}\u{24e6}\u{24cc}\u{24cc}\u{24e6}\u{24e7}\u{24cd}\u{24cd}\u{24e7}\u{24e8}\u{24ce}\u{24ce}\u{24e8}\u{24e9}\u{24cf}\u{24cf}\u{24e9}\u{2c30}\u{2c00}\u{2c00}\u{2c30}\u{2c31}\u{2c01}\u{2c01}\u{2c31}\u{2c32}\u{2c02}\u{2c02}\u{2c32}\u{2c33}\u{2c03}\u{2c03}\u{2c33}\u{2c34}\u{2c04}\u{2c04}\u{2c34}\u{2c35}\u{2c05}\u{2c05}\u{2c35}\u{2c36}\u{2c06}\u{2c06}\u{2c36}\u{2c37}\u{2c07}\u{2c07}\u{2c37}\u{2c38}\u{2c08}\u{2c08}\u{2c38}\u{2c39}\u{2c09}\u{2c09}\u{2c39}\u{2c3a}\u{2c0a}\u{2c0a}\u{2c3a}\u{2c3b}\u{2c0b}\u{2c0b}\u{2c3b}\u{2c3c}\u{2c0c}\u{2c0c}\u{2c3c}\u{2c3d}\u{2c0d}\u{2c0d}\u{2c3d}\u{2c3e}\u{2c0e}\u{2c0e}\u{2c3e}\u{2c3f}\u{2c0f}\u{2c0f}\u{2c3f}\u{2c40}\u{2c10}\u{2c10}\u{2c40}\u{2c41}\u{2c11}\u{2c11}\u{2c41}\u{2c42}\u{2c12}\u{2c12}\u{2c42}\u{2c43}\u{2c13}\u{2c13}\u{2c43}\u{2c44}\u{2c14}\u{2c14}\u{2c44}\u{2c45}\u{2c15}\u{2c15}\u{2c45}\u{2c46}\u{2c16}\u{2c16}\u{2c46}\u{2c47}\u{2c17}\u{2c17}\u{2c47}\u{2c48}\u{2c18}\u{2c18}\u{2c48}\u{2c49}\u{2c19}\u{2c19}\u{2c49}\u{2c4a}\u{2c1a}\u{2c1a}\u{2c4a}\u{2c4b}\u{2c1b}\u{2c1b}\u{2c4b}\u{2c4c}\u{2c1c}\u{2c1c}\u{2c4c}\u{2c4d}\u{2c1d}\u{2c1d}\u{2c4d}\u{2c4e}\u{2c1e}\u{2c1e}\u{2c4e}\u{2c4f}\u{2c1f}\u{2c1f}\u{2c4f}\u{2c50}\u{2c20}\u{2c20}\u{2c50}\u{2c51}\u{2c21}\u{2c21}\u{2c51}\u{2c52}\u{2c22}\u{2c22}\u{2c52}\u{2c53}\u{2c23}\u{2c23}\u{2c53}\u{2c54}\u{2c24}\u{2c24}\u{2c54}\u{2c55}\u{2c25}\u{2c25}\u{2c55}\u{2c56}\u{2c26}\u{2c26}\u{2c56}\u{2c57}\u{2c27}\u{2c27}\u{2c57}\u{2c58}\u{2c28}\u{2c28}\u{2c58}\u{2c59}\u{2c29}\u{2c29}\u{2c59}\u{2c5a}\u{2c2a}\u{2c2a}\u{2c5a}\u{2c5b}\u{2c2b}\u{2c2b}\u{2c5b}\u{2c5c}\u{2c2c}\u{2c2c}\u{2c5c}\u{2c5d}\u{2c2d}\u{2c2d}\u{2c5d}\u{2c5e}\u{2c2e}\u{2c2e}\u{2c5e}\u{2c5f}\u{2c2f}\u{2c2f}\u{2c5f}\u{2c61}\u{2c60}\u{2c60}\u{2c61}\u{26b}\u{2c62}\u{2c62}\u{26b}\u{1d7d}\u{2c63}\u{2c63}\u{1d7d}\u{27d}\u{2c64}\u{2c64}\u{27d}\u{2c68}\u{2c67}\u{2c67}\u{2c68}\u{2c6a}\u{2c69}\u{2c69}\u{2c6a}\u{2c6c}\u{2c6b}\u{2c6b}\u{2c6c}\u{251}\u{2c6d}\u{2c6d}\u{251}\u{271}\u{2c6e}\u{2c6e}\u{271}\u{250}\u{2c6f}\u{2c6f}\u{250}\u{252}\u{2c70}\u{2c70}\u{252}\u{2c73}\u{2c72}\u{2c72}\u{2c73}\u{2c76}\u{2c75}\u{2c75}\u{2c76}\u{23f}\u{2c7e}\u{2c7e}\u{23f}\u{240}\u{2c7f}\u{2c7f}\u{240}\u{2c81}\u{2c80}\u{2c80}\u{2c81}\u{2c83}\u{2c82}\u{2c82}\u{2c83}\u{2c85}\u{2c84}\u{2c84}\u{2c85}\u{2c87}\u{2c86}\u{2c86}\u{2c87}\u{2c89}\u{2c88}\u{2c88}\u{2c89}\u{2c8b}\u{2c8a}\u{2c8a}\u{2c8b}\u{2c8d}\u{2c8c}\u{2c8c}\u{2c8d}\u{2c8f}\u{2c8e}\u{2c8e}\u{2c8f}\u{2c91}\u{2c90}\u{2c90}\u{2c91}\u{2c93}\u{2c92}\u{2c92}\u{2c93}\u{2c95}\u{2c94}\u{2c94}\u{2c95}\u{2c97}\u{2c96}\u{2c96}\u{2c97}\u{2c99}\u{2c98}\u{2c98}\u{2c99}\u{2c9b}\u{2c9a}\u{2c9a}\u{2c9b}\u{2c9d}\u{2c9c}\u{2c9c}\u{2c9d}\u{2c9f}\u{2c9e}\u{2c9e}\u{2c9f}\u{2ca1}\u{2ca0}\u{2ca0}\u{2ca1}\u{2ca3}\u{2ca2}\u{2ca2}\u{2ca3}\u{2ca5}\u{2ca4}\u{2ca4}\u{2ca5}\u{2ca7}\u{2ca6}\u{2ca6}\u{2ca7}\u{2ca9}\u{2ca8}\u{2ca8}\u{2ca9}\u{2cab}\u{2caa}\u{2caa}\u{2cab}\u{2cad}\u{2cac}\u{2cac}\u{2cad}\u{2caf}\u{2cae}\u{2cae}\u{2caf}\u{2cb1}\u{2cb0}\u{2cb0}\u{2cb1}\u{2cb3}\u{2cb2}\u{2cb2}\u{2cb3}\u{2cb5}\u{2cb4}\u{2cb4}\u{2cb5}\u{2cb7}\u{2cb6}\u{2cb6}\u{2cb7}\u{2cb9}\u{2cb8}\u{2cb8}\u{2cb9}\u{2cbb}\u{2cba}\u{2cba}\u{2cbb}\u{2cbd}\u{2cbc}\u{2cbc}\u{2cbd}\u{2cbf}\u{2cbe}\u{2cbe}\u{2cbf}\u{2cc1}\u{2cc0}\u{2cc0}\u{2cc1}\u{2cc3}\u{2cc2}\u{2cc2}\u{2cc3}\u{2cc5}\u{2cc4}\u{2cc4}\u{2cc5}\u{2cc7}\u{2cc6}\u{2cc6}\u{2cc7}\u{2cc9}\u{2cc8}\u{2cc8}\u{2cc9}\u{2ccb}\u{2cca}\u{2cca}\u{2ccb}\u{2ccd}\u{2ccc}\u{2ccc}\u{2ccd}\u{2ccf}\u{2cce}\u{2cce}\u{2ccf}\u{2cd1}\u{2cd0}\u{2cd0}\u{2cd1}\u{2cd3}\u{2cd2}\u{2cd2}\u{2cd3}\u{2cd5}\u{2cd4}\u{2cd4}\u{2cd5}\u{2cd7}\u{2cd6}\u{2cd6}\u{2cd7}\u{2cd9}\u{2cd8}\u{2cd8}\u{2cd9}\u{2cdb}\u{2cda}\u{2cda}\u{2cdb}\u{2cdd}\u{2cdc}\u{2cdc}\u{2cdd}\u{2cdf}\u{2cde}\u{2cde}\u{2cdf}\u{2ce1}\u{2ce0}\u{2ce0}\u{2ce1}\u{2ce3}\u{2ce2}\u{2ce2}\u{2ce3}\u{2cec}\u{2ceb}\u{2ceb}\u{2cec}\u{2cee}\u{2ced}\u{2ced}\u{2cee}\u{2cf3}\u{2cf2}\u{2cf2}\u{2cf3}\u{a641}\u{a640}\u{a640}\u{a641}\u{a643}\u{a642}\u{a642}\u{a643}\u{a645}\u{a644}\u{a644}\u{a645}\u{a647}\u{a646}\u{a646}\u{a647}\u{a649}\u{a648}\u{a648}\u{a649}\u{a64d}\u{a64c}\u{a64c}\u{a64d}\u{a64f}\u{a64e}\u{a64e}\u{a64f}\u{a651}\u{a650}\u{a650}\u{a651}\u{a653}\u{a652}\u{a652}\u{a653}\u{a655}\u{a654}\u{a654}\u{a655}\u{a657}\u{a656}\u{a656}\u{a657}\u{a659}\u{a658}\u{a658}\u{a659}\u{a65b}\u{a65a}\u{a65a}\u{a65b}\u{a65d}\u{a65c}\u{a65c}\u{a65d}\u{a65f}\u{a65e}\u{a65e}\u{a65f}\u{a661}\u{a660}\u{a660}\u{a661}\u{a663}\u{a662}\u{a662}\u{a663}\u{a665}\u{a664}\u{a664}\u{a665}\u{a667}\u{a666}\u{a666}\u{a667}\u{a669}\u{a668}\u{a668}\u{a669}\u{a66b}\u{a66a}\u{a66a}\u{a66b}\u{a66d}\u{a66c}\u{a66c}\u{a66d}\u{a681}\u{a680}\u{a680}\u{a681}\u{a683}\u{a682}\u{a682}\u{a683}\u{a685}\u{a684}\u{a684}\u{a685}\u{a687}\u{a686}\u{a686}\u{a687}\u{a689}\u{a688}\u{a688}\u{a689}\u{a68b}\u{a68a}\u{a68a}\u{a68b}\u{a68d}\u{a68c}\u{a68c}\u{a68d}\u{a68f}\u{a68e}\u{a68e}\u{a68f}\u{a691}\u{a690}\u{a690}\u{a691}\u{a693}\u{a692}\u{a692}\u{a693}\u{a695}\u{a694}\u{a694}\u{a695}\u{a697}\u{a696}\u{a696}\u{a697}\u{a699}\u{a698}\u{a698}\u{a699}\u{a69b}\u{a69a}\u{a69a}\u{a69b}\u{a723}\u{a722}\u{a722}\u{a723}\u{a725}\u{a724}\u{a724}\u{a725}\u{a727}\u{a726}\u{a726}\u{a727}\u{a729}\u{a728}\u{a728}\u{a729}\u{a72b}\u{a72a}\u{a72a}\u{a72b}\u{a72d}\u{a72c}\u{a72c}\u{a72d}\u{a72f}\u{a72e}\u{a72e}\u{a72f}\u{a733}\u{a732}\u{a732}\u{a733}\u{a735}\u{a734}\u{a734}\u{a735}\u{a737}\u{a736}\u{a736}\u{a737}\u{a739}\u{a738}\u{a738}\u{a739}\u{a73b}\u{a73a}\u{a73a}\u{a73b}\u{a73d}\u{a73c}\u{a73c}\u{a73d}\u{a73f}\u{a73e}\u{a73e}\u{a73f}\u{a741}\u{a740}\u{a740}\u{a741}\u{a743}\u{a742}\u{a742}\u{a743}\u{a745}\u{a744}\u{a744}\u{a745}\u{a747}\u{a746}\u{a746}\u{a747}\u{a749}\u{a748}\u{a748}\u{a749}\u{a74b}\u{a74a}\u{a74a}\u{a74b}\u{a74d}\u{a74c}\u{a74c}\u{a74d}\u{a74f}\u{a74e}\u{a74e}\u{a74f}\u{a751}\u{a750}\u{a750}\u{a751}\u{a753}\u{a752}\u{a752}\u{a753}\u{a755}\u{a754}\u{a754}\u{a755}\u{a757}\u{a756}\u{a756}\u{a757}\u{a759}\u{a758}\u{a758}\u{a759}\u{a75b}\u{a75a}\u{a75a}\u{a75b}\u{a75d}\u{a75c}\u{a75c}\u{a75d}\u{a75f}\u{a75e}\u{a75e}\u{a75f}\u{a761}\u{a760}\u{a760}\u{a761}\u{a763}\u{a762}\u{a762}\u{a763}\u{a765}\u{a764}\u{a764}\u{a765}\u{a767}\u{a766}\u{a766}\u{a767}\u{a769}\u{a768}\u{a768}\u{a769}\u{a76b}\u{a76a}\u{a76a}\u{a76b}\u{a76d}\u{a76c}\u{a76c}\u{a76d}\u{a76f}\u{a76e}\u{a76e}\u{a76f}\u{a77a}\u{a779}\u{a779}\u{a77a}\u{a77c}\u{a77b}\u{a77b}\u{a77c}\u{1d79}\u{a77d}\u{a77d}\u{1d79}\u{a77f}\u{a77e}\u{a77e}\u{a77f}\u{a781}\u{a780}\u{a780}\u{a781}\u{a783}\u{a782}\u{a782}\u{a783}\u{a785}\u{a784}\u{a784}\u{a785}\u{a787}\u{a786}\u{a786}\u{a787}\u{a78c}\u{a78b}\u{a78b}\u{a78c}\u{265}\u{a78d}\u{a78d}\u{265}\u{a791}\u{a790}\u{a790}\u{a791}\u{a793}\u{a792}\u{a792}\u{a793}\u{a797}\u{a796}\u{a796}\u{a797}\u{a799}\u{a798}\u{a798}\u{a799}\u{a79b}\u{a79a}\u{a79a}\u{a79b}\u{a79d}\u{a79c}\u{a79c}\u{a79d}\u{a79f}\u{a79e}\u{a79e}\u{a79f}\u{a7a1}\u{a7a0}\u{a7a0}\u{a7a1}\u{a7a3}\u{a7a2}\u{a7a2}\u{a7a3}\u{a7a5}\u{a7a4}\u{a7a4}\u{a7a5}\u{a7a7}\u{a7a6}\u{a7a6}\u{a7a7}\u{a7a9}\u{a7a8}\u{a7a8}\u{a7a9}\u{266}\u{a7aa}\u{a7aa}\u{266}\u{25c}\u{a7ab}\u{a7ab}\u{25c}\u{261}\u{a7ac}\u{a7ac}\u{261}\u{26c}\u{a7ad}\u{a7ad}\u{26c}\u{26a}\u{a7ae}\u{a7ae}\u{26a}\u{29e}\u{a7b0}\u{a7b0}\u{29e}\u{287}\u{a7b1}\u{a7b1}\u{287}\u{29d}\u{a7b2}\u{a7b2}\u{29d}\u{ab53}\u{a7b3}\u{a7b3}\u{ab53}\u{a7b5}\u{a7b4}\u{a7b4}\u{a7b5}\u{a7b7}\u{a7b6}\u{a7b6}\u{a7b7}\u{a7b9}\u{a7b8}\u{a7b8}\u{a7b9}\u{a7bb}\u{a7ba}\u{a7ba}\u{a7bb}\u{a7bd}\u{a7bc}\u{a7bc}\u{a7bd}\u{a7bf}\u{a7be}\u{a7be}\u{a7bf}\u{a7c1}\u{a7c0}\u{a7c0}\u{a7c1}\u{a7c3}\u{a7c2}\u{a7c2}\u{a7c3}\u{a794}\u{a7c4}\u{a7c4}\u{a794}\u{282}\u{a7c5}\u{a7c5}\u{282}\u{1d8e}\u{a7c6}\u{a7c6}\u{1d8e}\u{a7c8}\u{a7c7}\u{a7c7}\u{a7c8}\u{a7ca}\u{a7c9}\u{a7c9}\u{a7ca}\u{264}\u{a7cb}\u{a7cb}\u{264}\u{a7cd}\u{a7cc}\u{a7cc}\u{a7cd}\u{a7d1}\u{a7d0}\u{a7d0}\u{a7d1}\u{a7d7}\u{a7d6}\u{a7d6}\u{a7d7}\u{a7d9}\u{a7d8}\u{a7d8}\u{a7d9}\u{a7db}\u{a7da}\u{a7da}\u{a7db}\u{19b}\u{a7dc}\u{a7dc}\u{19b}\u{a7f6}\u{a7f5}\u{a7f5}\u{a7f6}\u{13a0}\u{ab70}\u{ab70}\u{13a0}\u{13a1}\u{ab71}\u{ab71}\u{13a1}\u{13a2}\u{ab72}\u{ab72}\u{13a2}\u{13a3}\u{ab73}\u{ab73}\u{13a3}\u{13a4}\u{ab74}\u{ab74}\u{13a4}\u{13a5}\u{ab75}\u{ab75}\u{13a5}\u{13a6}\u{ab76}\u{ab76}\u{13a6}\u{13a7}\u{ab77}\u{ab77}\u{13a7}\u{13a8}\u{ab78}\u{ab78}\u{13a8}\u{13a9}\u{ab79}\u{ab79}\u{13a9}\u{13aa}\u{ab7a}\u{ab7a}\u{13aa}\u{13ab}\u{ab7b}\u{ab7b}\u{13ab}\u{13ac}\u{ab7c}\u{ab7c}\u{13ac}\u{13ad}\u{ab7d}\u{ab7d}\u{13ad}\u{13ae}\u{ab7e}\u{ab7e}\u{13ae}\u{13af}\u{ab7f}\u{ab7f}\u{13af}\u{13b0}\u{ab80}\u{ab80}\u{13b0}\u{13b1}\u{ab81}\u{ab81}\u{13b1}\u{13b2}\u{ab82}\u{ab82}\u{13b2}\u{13b3}\u{ab83}\u{ab83}\u{13b3}\u{13b4}\u{ab84}\u{ab84}\u{13b4}\u{13b5}\u{ab85}\u{ab85}\u{13b5}\u{13b6}\u{ab86}\u{ab86}\u{13b6}\u{13b7}\u{ab87}\u{ab87}\u{13b7}\u{13b8}\u{ab88}\u{ab88}\u{13b8}\u{13b9}\u{ab89}\u{ab89}\u{13b9}\u{13ba}\u{ab8a}\u{ab8a}\u{13ba}\u{13bb}\u{ab8b}\u{ab8b}\u{13bb}\u{13bc}\u{ab8c}\u{ab8c}\u{13bc}\u{13bd}\u{ab8d}\u{ab8d}\u{13bd}\u{13be}\u{ab8e}\u{ab8e}\u{13be}\u{13bf}\u{ab8f}\u{ab8f}\u{13bf}\u{13c0}\u{ab90}\u{ab90}\u{13c0}\u{13c1}\u{ab91}\u{ab91}\u{13c1}\u{13c2}\u{ab92}\u{ab92}\u{13c2}\u{13c3}\u{ab93}\u{ab93}\u{13c3}\u{13c4}\u{ab94}\u{ab94}\u{13c4}\u{13c5}\u{ab95}\u{ab95}\u{13c5}\u{13c6}\u{ab96}\u{ab96}\u{13c6}\u{13c7}\u{ab97}\u{ab97}\u{13c7}\u{13c8}\u{ab98}\u{ab98}\u{13c8}\u{13c9}\u{ab99}\u{ab99}\u{13c9}\u{13ca}\u{ab9a}\u{ab9a}\u{13ca}\u{13cb}\u{ab9b}\u{ab9b}\u{13cb}\u{13cc}\u{ab9c}\u{ab9c}\u{13cc}\u{13cd}\u{ab9d}\u{ab9d}\u{13cd}\u{13ce}\u{ab9e}\u{ab9e}\u{13ce}\u{13cf}\u{ab9f}\u{ab9f}\u{13cf}\u{13d0}\u{aba0}\u{aba0}\u{13d0}\u{13d1}\u{aba1}\u{aba1}\u{13d1}\u{13d2}\u{aba2}\u{aba2}\u{13d2}\u{13d3}\u{aba3}\u{aba3}\u{13d3}\u{13d4}\u{aba4}\u{aba4}\u{13d4}\u{13d5}\u{aba5}\u{aba5}\u{13d5}\u{13d6}\u{aba6}\u{aba6}\u{13d6}\u{13d7}\u{aba7}\u{aba7}\u{13d7}\u{13d8}\u{aba8}\u{aba8}\u{13d8}\u{13d9}\u{aba9}\u{aba9}\u{13d9}\u{13da}\u{abaa}\u{abaa}\u{13da}\u{13db}\u{abab}\u{abab}\u{13db}\u{13dc}\u{abac}\u{abac}\u{13dc}\u{13dd}\u{abad}\u{abad}\u{13dd}\u{13de}\u{abae}\u{abae}\u{13de}\u{13df}\u{abaf}\u{abaf}\u{13df}\u{13e0}\u{abb0}\u{abb0}\u{13e0}\u{13e1}\u{abb1}\u{abb1}\u{13e1}\u{13e2}\u{abb2}\u{abb2}\u{13e2}\u{13e3}\u{abb3}\u{abb3}\u{13e3}\u{13e4}\u{abb4}\u{abb4}\u{13e4}\u{13e5}\u{abb5}\u{abb5}\u{13e5}\u{13e6}\u{abb6}\u{abb6}\u{13e6}\u{13e7}\u{abb7}\u{abb7}\u{13e7}\u{13e8}\u{abb8}\u{abb8}\u{13e8}\u{13e9}\u{abb9}\u{abb9}\u{13e9}\u{13ea}\u{abba}\u{abba}\u{13ea}\u{13eb}\u{abbb}\u{abbb}\u{13eb}\u{13ec}\u{abbc}\u{abbc}\u{13ec}\u{13ed}\u{abbd}\u{abbd}\u{13ed}\u{13ee}\u{abbe}\u{abbe}\u{13ee}\u{13ef}\u{abbf}\u{abbf}\u{13ef}\u{fb06}\u{fb05}\u{fb05}\u{fb06}\u{ff41}\u{ff21}\u{ff21}\u{ff41}\u{ff42}\u{ff22}\u{ff22}\u{ff42}\u{ff43}\u{ff23}\u{ff23}\u{ff43}\u{ff44}\u{ff24}\u{ff24}\u{ff44}\u{ff45}\u{ff25}\u{ff25}\u{ff45}\u{ff46}\u{ff26}\u{ff26}\u{ff46}\u{ff47}\u{ff27}\u{ff27}\u{ff47}\u{ff48}\u{ff28}\u{ff28}\u{ff48}\u{ff49}\u{ff29}\u{ff29}\u{ff49}\u{ff4a}\u{ff2a}\u{ff2a}\u{ff4a}\u{ff4b}\u{ff2b}\u{ff2b}\u{ff4b}\u{ff4c}\u{ff2c}\u{ff2c}\u{ff4c}\u{ff4d}\u{ff2d}\u{ff2d}\u{ff4d}\u{ff4e}\u{ff2e}\u{ff2e}\u{ff4e}\u{ff4f}\u{ff2f}\u{ff2f}\u{ff4f}\u{ff50}\u{ff30}\u{ff30}\u{ff50}\u{ff51}\u{ff31}\u{ff31}\u{ff51}\u{ff52}\u{ff32}\u{ff32}\u{ff52}\u{ff53}\u{ff33}\u{ff33}\u{ff53}\u{ff54}\u{ff34}\u{ff34}\u{ff54}\u{ff55}\u{ff35}\u{ff35}\u{ff55}\u{ff56}\u{ff36}\u{ff36}\u{ff56}\u{ff57}\u{ff37}\u{ff37}\u{ff57}\u{ff58}\u{ff38}\u{ff38}\u{ff58}\u{ff59}\u{ff39}\u{ff39}\u{ff59}\u{ff5a}\u{ff3a}\u{ff3a}\u{ff5a}\u{10428}\u{10400}\u{10400}\u{10428}\u{10429}\u{10401}\u{10401}\u{10429}\u{1042a}\u{10402}\u{10402}\u{1042a}\u{1042b}\u{10403}\u{10403}\u{1042b}\u{1042c}\u{10404}\u{10404}\u{1042c}\u{1042d}\u{10405}\u{10405}\u{1042d}\u{1042e}\u{10406}\u{10406}\u{1042e}\u{1042f}\u{10407}\u{10407}\u{1042f}\u{10430}\u{10408}\u{10408}\u{10430}\u{10431}\u{10409}\u{10409}\u{10431}\u{10432}\u{1040a}\u{1040a}\u{10432}\u{10433}\u{1040b}\u{1040b}\u{10433}\u{10434}\u{1040c}\u{1040c}\u{10434}\u{10435}\u{1040d}\u{1040d}\u{10435}\u{10436}\u{1040e}\u{1040e}\u{10436}\u{10437}\u{1040f}\u{1040f}\u{10437}\u{10438}\u{10410}\u{10410}\u{10438}\u{10439}\u{10411}\u{10411}\u{10439}\u{1043a}\u{10412}\u{10412}\u{1043a}\u{1043b}\u{10413}\u{10413}\u{1043b}\u{1043c}\u{10414}\u{10414}\u{1043c}\u{1043d}\u{10415}\u{10415}\u{1043d}\u{1043e}\u{10416}\u{10416}\u{1043e}\u{1043f}\u{10417}\u{10417}\u{1043f}\u{10440}\u{10418}\u{10418}\u{10440}\u{10441}\u{10419}\u{10419}\u{10441}\u{10442}\u{1041a}\u{1041a}\u{10442}\u{10443}\u{1041b}\u{1041b}\u{10443}\u{10444}\u{1041c}\u{1041c}\u{10444}\u{10445}\u{1041d}\u{1041d}\u{10445}\u{10446}\u{1041e}\u{1041e}\u{10446}\u{10447}\u{1041f}\u{1041f}\u{10447}\u{10448}\u{10420}\u{10420}\u{10448}\u{10449}\u{10421}\u{10421}\u{10449}\u{1044a}\u{10422}\u{10422}\u{1044a}\u{1044b}\u{10423}\u{10423}\u{1044b}\u{1044c}\u{10424}\u{10424}\u{1044c}\u{1044d}\u{10425}\u{10425}\u{1044d}\u{1044e}\u{10426}\u{10426}\u{1044e}\u{1044f}\u{10427}\u{10427}\u{1044f}\u{104d8}\u{104b0}\u{104b0}\u{104d8}\u{104d9}\u{104b1}\u{104b1}\u{104d9}\u{104da}\u{104b2}\u{104b2}\u{104da}\u{104db}\u{104b3}\u{104b3}\u{104db}\u{104dc}\u{104b4}\u{104b4}\u{104dc}\u{104dd}\u{104b5}\u{104b5}\u{104dd}\u{104de}\u{104b6}\u{104b6}\u{104de}\u{104df}\u{104b7}\u{104b7}\u{104df}\u{104e0}\u{104b8}\u{104b8}\u{104e0}\u{104e1}\u{104b9}\u{104b9}\u{104e1}\u{104e2}\u{104ba}\u{104ba}\u{104e2}\u{104e3}\u{104bb}\u{104bb}\u{104e3}\u{104e4}\u{104bc}\u{104bc}\u{104e4}\u{104e5}\u{104bd}\u{104bd}\u{104e5}\u{104e6}\u{104be}\u{104be}\u{104e6}\u{104e7}\u{104bf}\u{104bf}\u{104e7}\u{104e8}\u{104c0}\u{104c0}\u{104e8}\u{104e9}\u{104c1}\u{104c1}\u{104e9}\u{104ea}\u{104c2}\u{104c2}\u{104ea}\u{104eb}\u{104c3}\u{104c3}\u{104eb}\u{104ec}\u{104c4}\u{104c4}\u{104ec}\u{104ed}\u{104c5}\u{104c5}\u{104ed}\u{104ee}\u{104c6}\u{104c6}\u{104ee}\u{104ef}\u{104c7}\u{104c7}\u{104ef}\u{104f0}\u{104c8}\u{104c8}\u{104f0}\u{104f1}\u{104c9}\u{104c9}\u{104f1}\u{104f2}\u{104ca}\u{104ca}\u{104f2}\u{104f3}\u{104cb}\u{104cb}\u{104f3}\u{104f4}\u{104cc}\u{104cc}\u{104f4}\u{104f5}\u{104cd}\u{104cd}\u{104f5}\u{104f6}\u{104ce}\u{104ce}\u{104f6}\u{104f7}\u{104cf}\u{104cf}\u{104f7}\u{104f8}\u{104d0}\u{104d0}\u{104f8}\u{104f9}\u{104d1}\u{104d1}\u{104f9}\u{104fa}\u{104d2}\u{104d2}\u{104fa}\u{104fb}\u{104d3}\u{104d3}\u{104fb}\u{10597}\u{10570}\u{10570}\u{10597}\u{10598}\u{10571}\u{10571}\u{10598}\u{10599}\u{10572}\u{10572}\u{10599}\u{1059a}\u{10573}\u{10573}\u{1059a}\u{1059b}\u{10574}\u{10574}\u{1059b}\u{1059c}\u{10575}\u{10575}\u{1059c}\u{1059d}\u{10576}\u{10576}\u{1059d}\u{1059e}\u{10577}\u{10577}\u{1059e}\u{1059f}\u{10578}\u{10578}\u{1059f}\u{105a0}\u{10579}\u{10579}\u{105a0}\u{105a1}\u{1057a}\u{1057a}\u{105a1}\u{105a3}\u{1057c}\u{1057c}\u{105a3}\u{105a4}\u{1057d}\u{1057d}\u{105a4}\u{105a5}\u{1057e}\u{1057e}\u{105a5}\u{105a6}\u{1057f}\u{1057f}\u{105a6}\u{105a7}\u{10580}\u{10580}\u{105a7}\u{105a8}\u{10581}\u{10581}\u{105a8}\u{105a9}\u{10582}\u{10582}\u{105a9}\u{105aa}\u{10583}\u{10583}\u{105aa}\u{105ab}\u{10584}\u{10584}\u{105ab}\u{105ac}\u{10585}\u{10585}\u{105ac}\u{105ad}\u{10586}\u{10586}\u{105ad}\u{105ae}\u{10587}\u{10587}\u{105ae}\u{105af}\u{10588}\u{10588}\u{105af}\u{105b0}\u{10589}\u{10589}\u{105b0}\u{105b1}\u{1058a}\u{1058a}\u{105b1}\u{105b3}\u{1058c}\u{1058c}\u{105b3}\u{105b4}\u{1058d}\u{1058d}\u{105b4}\u{105b5}\u{1058e}\u{1058e}\u{105b5}\u{105b6}\u{1058f}\u{1058f}\u{105b6}\u{105b7}\u{10590}\u{10590}\u{105b7}\u{105b8}\u{10591}\u{10591}\u{105b8}\u{105b9}\u{10592}\u{10592}\u{105b9}\u{105bb}\u{10594}\u{10594}\u{105bb}\u{105bc}\u{10595}\u{10595}\u{105bc}\u{10cc0}\u{10c80}\u{10c80}\u{10cc0}\u{10cc1}\u{10c81}\u{10c81}\u{10cc1}\u{10cc2}\u{10c82}\u{10c82}\u{10cc2}\u{10cc3}\u{10c83}\u{10c83}\u{10cc3}\u{10cc4}\u{10c84}\u{10c84}\u{10cc4}\u{10cc5}\u{10c85}\u{10c85}\u{10cc5}\u{10cc6}\u{10c86}\u{10c86}\u{10cc6}\u{10cc7}\u{10c87}\u{10c87}\u{10cc7}\u{10cc8}\u{10c88}\u{10c88}\u{10cc8}\u{10cc9}\u{10c89}\u{10c89}\u{10cc9}\u{10cca}\u{10c8a}\u{10c8a}\u{10cca}\u{10ccb}\u{10c8b}\u{10c8b}\u{10ccb}\u{10ccc}\u{10c8c}\u{10c8c}\u{10ccc}\u{10ccd}\u{10c8d}\u{10c8d}\u{10ccd}\u{10cce}\u{10c8e}\u{10c8e}\u{10cce}\u{10ccf}\u{10c8f}\u{10c8f}\u{10ccf}\u{10cd0}\u{10c90}\u{10c90}\u{10cd0}\u{10cd1}\u{10c91}\u{10c91}\u{10cd1}\u{10cd2}\u{10c92}\u{10c92}\u{10cd2}\u{10cd3}\u{10c93}\u{10c93}\u{10cd3}\u{10cd4}\u{10c94}\u{10c94}\u{10cd4}\u{10cd5}\u{10c95}\u{10c95}\u{10cd5}\u{10cd6}\u{10c96}\u{10c96}\u{10cd6}\u{10cd7}\u{10c97}\u{10c97}\u{10cd7}\u{10cd8}\u{10c98}\u{10c98}\u{10cd8}\u{10cd9}\u{10c99}\u{10c99}\u{10cd9}\u{10cda}\u{10c9a}\u{10c9a}\u{10cda}\u{10cdb}\u{10c9b}\u{10c9b}\u{10cdb}\u{10cdc}\u{10c9c}\u{10c9c}\u{10cdc}\u{10cdd}\u{10c9d}\u{10c9d}\u{10cdd}\u{10cde}\u{10c9e}\u{10c9e}\u{10cde}\u{10cdf}\u{10c9f}\u{10c9f}\u{10cdf}\u{10ce0}\u{10ca0}\u{10ca0}\u{10ce0}\u{10ce1}\u{10ca1}\u{10ca1}\u{10ce1}\u{10ce2}\u{10ca2}\u{10ca2}\u{10ce2}\u{10ce3}\u{10ca3}\u{10ca3}\u{10ce3}\u{10ce4}\u{10ca4}\u{10ca4}\u{10ce4}\u{10ce5}\u{10ca5}\u{10ca5}\u{10ce5}\u{10ce6}\u{10ca6}\u{10ca6}\u{10ce6}\u{10ce7}\u{10ca7}\u{10ca7}\u{10ce7}\u{10ce8}\u{10ca8}\u{10ca8}\u{10ce8}\u{10ce9}\u{10ca9}\u{10ca9}\u{10ce9}\u{10cea}\u{10caa}\u{10caa}\u{10cea}\u{10ceb}\u{10cab}\u{10cab}\u{10ceb}\u{10cec}\u{10cac}\u{10cac}\u{10cec}\u{10ced}\u{10cad}\u{10cad}\u{10ced}\u{10cee}\u{10cae}\u{10cae}\u{10cee}\u{10cef}\u{10caf}\u{10caf}\u{10cef}\u{10cf0}\u{10cb0}\u{10cb0}\u{10cf0}\u{10cf1}\u{10cb1}\u{10cb1}\u{10cf1}\u{10cf2}\u{10cb2}\u{10cb2}\u{10cf2}\u{10d70}\u{10d50}\u{10d50}\u{10d70}\u{10d71}\u{10d51}\u{10d51}\u{10d71}\u{10d72}\u{10d52}\u{10d52}\u{10d72}\u{10d73}\u{10d53}\u{10d53}\u{10d73}\u{10d74}\u{10d54}\u{10d54}\u{10d74}\u{10d75}\u{10d55}\u{10d55}\u{10d75}\u{10d76}\u{10d56}\u{10d56}\u{10d76}\u{10d77}\u{10d57}\u{10d57}\u{10d77}\u{10d78}\u{10d58}\u{10d58}\u{10d78}\u{10d79}\u{10d59}\u{10d59}\u{10d79}\u{10d7a}\u{10d5a}\u{10d5a}\u{10d7a}\u{10d7b}\u{10d5b}\u{10d5b}\u{10d7b}\u{10d7c}\u{10d5c}\u{10d5c}\u{10d7c}\u{10d7d}\u{10d5d}\u{10d5d}\u{10d7d}\u{10d7e}\u{10d5e}\u{10d5e}\u{10d7e}\u{10d7f}\u{10d5f}\u{10d5f}\u{10d7f}\u{10d80}\u{10d60}\u{10d60}\u{10d80}\u{10d81}\u{10d61}\u{10d61}\u{10d81}\u{10d82}\u{10d62}\u{10d62}\u{10d82}\u{10d83}\u{10d63}\u{10d63}\u{10d83}\u{10d84}\u{10d64}\u{10d64}\u{10d84}\u{10d85}\u{10d65}\u{10d65}\u{10d85}\u{118c0}\u{118a0}\u{118a0}\u{118c0}\u{118c1}\u{118a1}\u{118a1}\u{118c1}\u{118c2}\u{118a2}\u{118a2}\u{118c2}\u{118c3}\u{118a3}\u{118a3}\u{118c3}\u{118c4}\u{118a4}\u{118a4}\u{118c4}\u{118c5}\u{118a5}\u{118a5}\u{118c5}\u{118c6}\u{118a6}\u{118a6}\u{118c6}\u{118c7}\u{118a7}\u{118a7}\u{118c7}\u{118c8}\u{118a8}\u{118a8}\u{118c8}\u{118c9}\u{118a9}\u{118a9}\u{118c9}\u{118ca}\u{118aa}\u{118aa}\u{118ca}\u{118cb}\u{118ab}\u{118ab}\u{118cb}\u{118cc}\u{118ac}\u{118ac}\u{118cc}\u{118cd}\u{118ad}\u{118ad}\u{118cd}\u{118ce}\u{118ae}\u{118ae}\u{118ce}\u{118cf}\u{118af}\u{118af}\u{118cf}\u{118d0}\u{118b0}\u{118b0}\u{118d0}\u{118d1}\u{118b1}\u{118b1}\u{118d1}\u{118d2}\u{118b2}\u{118b2}\u{118d2}\u{118d3}\u{118b3}\u{118b3}\u{118d3}\u{118d4}\u{118b4}\u{118b4}\u{118d4}\u{118d5}\u{118b5}\u{118b5}\u{118d5}\u{118d6}\u{118b6}\u{118b6}\u{118d6}\u{118d7}\u{118b7}\u{118b7}\u{118d7}\u{118d8}\u{118b8}\u{118b8}\u{118d8}\u{118d9}\u{118b9}\u{118b9}\u{118d9}\u{118da}\u{118ba}\u{118ba}\u{118da}\u{118db}\u{118bb}\u{118bb}\u{118db}\u{118dc}\u{118bc}\u{118bc}\u{118dc}\u{118dd}\u{118bd}\u{118bd}\u{118dd}\u{118de}\u{118be}\u{118be}\u{118de}\u{118df}\u{118bf}\u{118bf}\u{118df}\u{16e60}\u{16e40}\u{16e40}\u{16e60}\u{16e61}\u{16e41}\u{16e41}\u{16e61}\u{16e62}\u{16e42}\u{16e42}\u{16e62}\u{16e63}\u{16e43}\u{16e43}\u{16e63}\u{16e64}\u{16e44}\u{16e44}\u{16e64}\u{16e65}\u{16e45}\u{16e45}\u{16e65}\u{16e66}\u{16e46}\u{16e46}\u{16e66}\u{16e67}\u{16e47}\u{16e47}\u{16e67}\u{16e68}\u{16e48}\u{16e48}\u{16e68}\u{16e69}\u{16e49}\u{16e49}\u{16e69}\u{16e6a}\u{16e4a}\u{16e4a}\u{16e6a}\u{16e6b}\u{16e4b}\u{16e4b}\u{16e6b}\u{16e6c}\u{16e4c}\u{16e4c}\u{16e6c}\u{16e6d}\u{16e4d}\u{16e4d}\u{16e6d}\u{16e6e}\u{16e4e}\u{16e4e}\u{16e6e}\u{16e6f}\u{16e4f}\u{16e4f}\u{16e6f}\u{16e70}\u{16e50}\u{16e50}\u{16e70}\u{16e71}\u{16e51}\u{16e51}\u{16e71}\u{16e72}\u{16e52}\u{16e52}\u{16e72}\u{16e73}\u{16e53}\u{16e53}\u{16e73}\u{16e74}\u{16e54}\u{16e54}\u{16e74}\u{16e75}\u{16e55}\u{16e55}\u{16e75}\u{16e76}\u{16e56}\u{16e56}\u{16e76}\u{16e77}\u{16e57}\u{16e57}\u{16e77}\u{16e78}\u{16e58}\u{16e58}\u{16e78}\u{16e79}\u{16e59}\u{16e59}\u{16e79}\u{16e7a}\u{16e5a}\u{16e5a}\u{16e7a}\u{16e7b}\u{16e5b}\u{16e5b}\u{16e7b}\u{16e7c}\u{16e5c}\u{16e5c}\u{16e7c}\u{16e7d}\u{16e5d}\u{16e5d}\u{16e7d}\u{16e7e}\u{16e5e}\u{16e5e}\u{16e7e}\u{16e7f}\u{16e5f}\u{16e5f}\u{16e7f}\u{1e922}\u{1e900}\u{1e900}\u{1e922}\u{1e923}\u{1e901}\u{1e901}\u{1e923}\u{1e924}\u{1e902}\u{1e902}\u{1e924}\u{1e925}\u{1e903}\u{1e903}\u{1e925}\u{1e926}\u{1e904}\u{1e904}\u{1e926}\u{1e927}\u{1e905}\u{1e905}\u{1e927}\u{1e928}\u{1e906}\u{1e906}\u{1e928}\u{1e929}\u{1e907}\u{1e907}\u{1e929}\u{1e92a}\u{1e908}\u{1e908}\u{1e92a}\u{1e92b}\u{1e909}\u{1e909}\u{1e92b}\u{1e92c}\u{1e90a}\u{1e90a}\u{1e92c}\u{1e92d}\u{1e90b}\u{1e90b}\u{1e92d}\u{1e92e}\u{1e90c}\u{1e90c}\u{1e92e}\u{1e92f}\u{1e90d}\u{1e90d}\u{1e92f}\u{1e930}\u{1e90e}\u{1e90e}\u{1e930}\u{1e931}\u{1e90f}\u{1e90f}\u{1e931}\u{1e932}\u{1e910}\u{1e910}\u{1e932}\u{1e933}\u{1e911}\u{1e911}\u{1e933}\u{1e934}\u{1e912}\u{1e912}\u{1e934}\u{1e935}\u{1e913}\u{1e913}\u{1e935}\u{1e936}\u{1e914}\u{1e914}\u{1e936}\u{1e937}\u{1e915}\u{1e915}\u{1e937}\u{1e938}\u{1e916}\u{1e916}\u{1e938}\u{1e939}\u{1e917}\u{1e917}\u{1e939}\u{1e93a}\u{1e918}\u{1e918}\u{1e93a}\u{1e93b}\u{1e919}\u{1e919}\u{1e93b}\u{1e93c}\u{1e91a}\u{1e91a}\u{1e93c}\u{1e93d}\u{1e91b}\u{1e91b}\u{1e93d}\u{1e93e}\u{1e91c}\u{1e91c}\u{1e93e}\u{1e93f}\u{1e91d}\u{1e91d}\u{1e93f}\u{1e940}\u{1e91e}\u{1e91e}\u{1e940}\u{1e941}\u{1e91f}\u{1e91f}\u{1e941}\u{1e942}\u{1e920}\u{1e920}\u{1e942}\u{1e943}\u{1e921}\u{1e921}\u{1e943} - #|let case_folding : Map[Char, Char] = { - #| let map = Map::new(capacity=3000) - #| loop DATA[:] { - #| [ch1, ch2, .. rest] => { - #| map[ch1] = ch2 - #| continue rest - #| } - #| [_] => panic() - #| [] => () - #| } - #| map - #|} - #|const MIN_FOLD : Char = '\u{41}' - #|const MAX_FOLD : Char = '\u{1e943}' - ), - "chars.mbt": ( - #|pub let ranges_is_digit : Array[Char] = ['0', '9'] - #|pub let ranges_is_not_digit : Array[Char] = ['\u{0}', '/', ':', '\u{10FFFF}'] - #|pub let ranges_is_word : Array[Char] = ['0', '9', 'A', 'Z', '_', '_', 'a', 'z'] - #|pub let ranges_is_not_word : Array[Char] = [ - #| '\u{0}', '/', ':', '@', '[', '^', '`', '`', '{', '\u{10FFFF}', - #|] - #|pub let ranges_any : Array[Char] = ['\u{0}', '\u{10FFFF}'] - #|pub let ranges_any_not_new_line : Array[Char] = [ - #| '\u{0}', '\u{9}', '\u{11}', '\u{10FFFF}', - #|] - #|pub let ranges_is_white_space_or_line_terminator : Array[Char] = [ - #| '\u{9}', '\u{D}', '\u{20}', '\u{20}', '\u{A0}', '\u{A0}', '\u{1680}', '\u{1680}', - #| '\u{2000}', '\u{200A}', '\u{2028}', '\u{2029}', '\u{202F}', '\u{202F}', '\u{205F}', - #| '\u{205F}', '\u{3000}', '\u{3000}', '\u{FEFF}', '\u{FEFF}', - #|] - #|pub let ranges_is_not_white_space_or_line_terminator : Array[Char] = [ - #| '\u{00}', '\u{8}', '\u{E}', '\u{1F}', '\u{21}', '\u{9f}', '\u{A1}', '\u{167F}', - #| '\u{1681}', '\u{1FFF}', '\u{200B}', '\u{2027}', '\u{202a}', '\u{202E}', '\u{2030}', - #| '\u{205E}', '\u{2060}', '\u{2FFF}', '\u{3001}', '\u{FEFE}', '\u{FF00}', '\u{10ffff}', - #|] - #|test "ordered range" { - #| for - #| range in [ - #| ranges_is_digit, ranges_is_not_digit, ranges_is_word, ranges_is_not_word, ranges_any, - #| ranges_any_not_new_line, ranges_is_white_space_or_line_terminator, - #| ] { - #| assert_eq(simplify_char_ranges(range), range) - #| } - #|} - #|pub fn is_word_char_at(input : StringView, sp : Int) -> Bool { - #| if sp == -1 || sp == input.length() { - #| return false - #| } - #| let c = input.get_char(sp).unwrap() - #| is_word_char(c) - #|} - #|fn is_word_char(c : Char) -> Bool { - #| return c is ('a'..='z' | 'A'..='Z' | '0'..='9' | '_') - #|} - #|test "is word char" { - #| for i in 0..<256 { - #| let ch = i.unsafe_to_char() - #| assert_eq(is_word_char(ch), char_in_ranges(ch, ranges_is_word)) - #| } - #|} - #|pub fn char_in_ranges(ch : Char, chars : Array[Char]) -> Bool { - #| let mut left = 0 - #| let mut right = chars.length() / 2 - 1 - #| while left <= right { - #| let mid = (left + right) / 2 - #| let start = chars[mid * 2] - #| let end = chars[mid * 2 + 1] - #| if ch < start { - #| right = mid - 1 - #| } else if ch > end { - #| left = mid + 1 - #| } else { - #| return true - #| } - #| } - #| return false - #|} - #|pub fn simplify_char_ranges(chars : Array[Char]) -> Array[Char] { - #| if chars.length() == 0 { - #| return [] - #| } - #| let ranges = [] - #| for i = 0; i < chars.length(); i = i + 2 { - #| let start = chars[i] - #| let end = chars[i + 1] - #| ranges.push((start, end)) - #| } - #| ranges.sort_by_key(range => range.0) - #| let simplified = [] - #| let mut current_start = '\u{0}' - #| let mut current_end = '\u{0}' - #| if ranges.length() > 0 { - #| current_start = ranges[0].0 - #| current_end = ranges[0].1 - #| for range in ranges[1:] { - #| let (next_start, next_end) = range - #| if next_start <= (current_end.to_int() + 1).unsafe_to_char() { - #| current_end = if current_end > next_end { - #| current_end - #| } else { - #| next_end - #| } - #| } else { - #| simplified.push(current_start) - #| simplified.push(current_end) - #| current_start = next_start - #| current_end = next_end - #| } - #| } - #| simplified.push(current_start) - #| simplified.push(current_end) - #| } - #| simplified - #|} - #|test "simplify char ranges" { - #| inspect(simplify_char_ranges(['A', 'z', 'A', 'Z']), content="['A', 'z']") - #|} - #|pub fn compute_char_class_complement(chars : Array[Char]) -> Array[Char] { - #| let simplified = simplify_char_ranges(chars) - #| if simplified.length() == 0 { - #| return ['\u{0}', '\u{10FFFF}'] - #| } - #| let complement = [] - #| let min_char = '\u{0}' - #| let max_char = '\u{10FFFF}' - #| if simplified[0] > min_char { - #| complement.push(min_char) - #| complement.push((simplified[0].to_int() - 1).unsafe_to_char()) - #| } - #| for i = 0; i < simplified.length() / 2 - 1; i = i + 1 { - #| let current_end = simplified[i * 2 + 1] - #| let next_start = simplified[(i + 1) * 2] - #| let gap_start = (current_end.to_int() + 1).unsafe_to_char() - #| let gap_end = (next_start.to_int() - 1).unsafe_to_char() - #| if gap_start <= gap_end { - #| complement.push(gap_start) - #| complement.push(gap_end) - #| } - #| } - #| let last_end = simplified[simplified.length() - 1] - #| if last_end < max_char { - #| complement.push((last_end.to_int() + 1).unsafe_to_char()) - #| complement.push(max_char) - #| } - #| complement - #|} - #|test "compute complement of charclass" { - #| assert_eq(ranges_is_digit, compute_char_class_complement(ranges_is_not_digit)) - #| assert_eq(ranges_is_not_digit, compute_char_class_complement(ranges_is_digit)) - #| assert_eq(ranges_is_word, compute_char_class_complement(ranges_is_not_word)) - #| assert_eq(ranges_is_not_word, compute_char_class_complement(ranges_is_word)) - #| assert_eq( - #| ranges_is_not_white_space_or_line_terminator, - #| compute_char_class_complement(ranges_is_white_space_or_line_terminator), - #| ) - #| inspect( - #| compute_char_class_complement([]), - #| content="['\\u{00}', '\\u{10ffff}']", - #| ) - #|} - #|pub fn case_insensitive_char_class(chars : Array[Char]) -> Array[Char] { - #| let result = [] - #| for i in 0..<(chars.length() / 2) { - #| let mut start = chars[i * 2] - #| let mut end = chars[i * 2 + 1] - #| if (start <= MIN_FOLD && end >= MAX_FOLD) || - #| end < MIN_FOLD || - #| start > MAX_FOLD { - #| result..push(start)..push(end) - #| continue - #| } - #| if start < MIN_FOLD { - #| result..push(start)..push((MIN_FOLD.to_int() - 1).unsafe_to_char()) - #| start = MIN_FOLD - #| } else if end > MAX_FOLD { - #| result..push((MAX_FOLD.to_int() + 1).unsafe_to_char())..push(end) - #| end = MAX_FOLD - #| } - #| for c in start.to_int()..=end.to_int() { - #| let char = c.unsafe_to_char() - #| let mut ch0 = char - #| result..push(char)..push(char) - #| while case_folding.get(ch0) is Some(ch) && ch != char { - #| result.push(ch) - #| result.push(ch) - #| ch0 = ch - #| } - #| } - #| } - #| simplify_char_ranges(result) - #|} - #|test "case insensitive char class" { - #| inspect( - #| case_insensitive_char_class(['a', 'z']), - #| content="['A', 'Z', 'a', 'z', 'ſ', 'ſ', 'K', 'K']", - #| ) - #| inspect( - #| case_insensitive_char_class(['A', 'Z']), - #| content="['A', 'Z', 'a', 'z', 'ſ', 'ſ', 'K', 'K']", - #| ) - #| inspect( - #| case_insensitive_char_class(['\u{0}', '\n']), - #| content="['\\u{00}', '\\n']", - #| ) - #| inspect( - #| case_insensitive_char_class(['!', 'z']), - #| content="['!', 'z', 'ſ', 'ſ', 'K', 'K']", - #| ) - #| inspect(case_insensitive_char_class(['B', '🀄']), content="['A', '🀄']") - #| inspect( - #| case_insensitive_char_class(['🀄', '🀡']), - #| content="['🀄', '🀡']", - #| ) - #|} - ), - "general_category.mbt": ( - #|pub let general_category_ranges : Map[String, Array[Char]] = { - #| "LC": LC.iter().collect(), - #| "L": L.iter().collect(), - #| "M": M.iter().collect(), - #| "N": N.iter().collect(), - #| "P": P.iter().collect(), - #| "S": S.iter().collect(), - #| "Z": Z.iter().collect(), - #| "C": C.iter().collect(), - #| "Cn": Cn.iter().collect(), - #| "Cc": Cc.iter().collect(), - #| "Zs": Zs.iter().collect(), - #| "Po": Po.iter().collect(), - #| "Sc": Sc.iter().collect(), - #| "Ps": Ps.iter().collect(), - #| "Pe": Pe.iter().collect(), - #| "Sm": Sm.iter().collect(), - #| "Pd": Pd.iter().collect(), - #| "Nd": Nd.iter().collect(), - #| "Lu": Lu.iter().collect(), - #| "Sk": Sk.iter().collect(), - #| "Pc": Pc.iter().collect(), - #| "Ll": Ll.iter().collect(), - #| "So": So.iter().collect(), - #| "Lo": Lo.iter().collect(), - #| "Pi": Pi.iter().collect(), - #| "Cf": Cf.iter().collect(), - #| "No": No.iter().collect(), - #| "Pf": Pf.iter().collect(), - #| "Lt": Lt.iter().collect(), - #| "Lm": Lm.iter().collect(), - #| "Mn": Mn.iter().collect(), - #| "Me": Me.iter().collect(), - #| "Mc": Mc.iter().collect(), - #| "Nl": Nl.iter().collect(), - #| "Zl": Zl.iter().collect(), - #| "Zp": Zp.iter().collect(), - #| "Cs": cs, - #| "Co": Co.iter().collect(), - #|} - #|const LC : String = - #| $|\u{41}\u{5a}\u{61}\u{7a}\u{b5}\u{b5}\u{c0}\u{d6}\u{d8}\u{f6}\u{f8}\u{1ba}\u{1bc}\u{1bf}\u{1c4}\u{293}\u{295}\u{2af}\u{370}\u{373}\u{376}\u{377}\u{37b}\u{37d}\u{37f}\u{37f}\u{386}\u{386}\u{388}\u{38a}\u{38c}\u{38c}\u{38e}\u{3a1}\u{3a3}\u{3f5}\u{3f7}\u{481}\u{48a}\u{52f}\u{531}\u{556}\u{560}\u{588}\u{10a0}\u{10c5}\u{10c7}\u{10c7}\u{10cd}\u{10cd}\u{10d0}\u{10fa}\u{10fd}\u{10ff}\u{13a0}\u{13f5}\u{13f8}\u{13fd}\u{1c80}\u{1c8a}\u{1c90}\u{1cba}\u{1cbd}\u{1cbf}\u{1d00}\u{1d2b}\u{1d6b}\u{1d77}\u{1d79}\u{1d9a}\u{1e00}\u{1f15}\u{1f18}\u{1f1d}\u{1f20}\u{1f45}\u{1f48}\u{1f4d}\u{1f50}\u{1f57}\u{1f59}\u{1f59}\u{1f5b}\u{1f5b}\u{1f5d}\u{1f5d}\u{1f5f}\u{1f7d}\u{1f80}\u{1fb4}\u{1fb6}\u{1fbc}\u{1fbe}\u{1fbe}\u{1fc2}\u{1fc4}\u{1fc6}\u{1fcc}\u{1fd0}\u{1fd3}\u{1fd6}\u{1fdb}\u{1fe0}\u{1fec}\u{1ff2}\u{1ff4}\u{1ff6}\u{1ffc}\u{2102}\u{2102}\u{2107}\u{2107}\u{210a}\u{2113}\u{2115}\u{2115}\u{2119}\u{211d}\u{2124}\u{2124}\u{2126}\u{2126}\u{2128}\u{2128}\u{212a}\u{212d}\u{212f}\u{2134}\u{2139}\u{2139}\u{213c}\u{213f}\u{2145}\u{2149}\u{214e}\u{214e}\u{2183}\u{2184}\u{2c00}\u{2c7b}\u{2c7e}\u{2ce4}\u{2ceb}\u{2cee}\u{2cf2}\u{2cf3}\u{2d00}\u{2d25}\u{2d27}\u{2d27}\u{2d2d}\u{2d2d}\u{a640}\u{a66d}\u{a680}\u{a69b}\u{a722}\u{a76f}\u{a771}\u{a787}\u{a78b}\u{a78e}\u{a790}\u{a7cd}\u{a7d0}\u{a7d1}\u{a7d3}\u{a7d3}\u{a7d5}\u{a7dc}\u{a7f5}\u{a7f6}\u{a7fa}\u{a7fa}\u{ab30}\u{ab5a}\u{ab60}\u{ab68}\u{ab70}\u{abbf}\u{fb00}\u{fb06}\u{fb13}\u{fb17}\u{ff21}\u{ff3a}\u{ff41}\u{ff5a}\u{10400}\u{1044f}\u{104b0}\u{104d3}\u{104d8}\u{104fb}\u{10570}\u{1057a}\u{1057c}\u{1058a}\u{1058c}\u{10592}\u{10594}\u{10595}\u{10597}\u{105a1}\u{105a3}\u{105b1}\u{105b3}\u{105b9}\u{105bb}\u{105bc}\u{10c80}\u{10cb2}\u{10cc0}\u{10cf2}\u{10d50}\u{10d65}\u{10d70}\u{10d85}\u{118a0}\u{118df}\u{16e40}\u{16e7f}\u{1d400}\u{1d454}\u{1d456}\u{1d49c}\u{1d49e}\u{1d49f}\u{1d4a2}\u{1d4a2}\u{1d4a5}\u{1d4a6}\u{1d4a9}\u{1d4ac}\u{1d4ae}\u{1d4b9}\u{1d4bb}\u{1d4bb}\u{1d4bd}\u{1d4c3}\u{1d4c5}\u{1d505}\u{1d507}\u{1d50a}\u{1d50d}\u{1d514}\u{1d516}\u{1d51c}\u{1d51e}\u{1d539}\u{1d53b}\u{1d53e}\u{1d540}\u{1d544}\u{1d546}\u{1d546}\u{1d54a}\u{1d550}\u{1d552}\u{1d6a5}\u{1d6a8}\u{1d6c0}\u{1d6c2}\u{1d6da}\u{1d6dc}\u{1d6fa}\u{1d6fc}\u{1d714}\u{1d716}\u{1d734}\u{1d736}\u{1d74e}\u{1d750}\u{1d76e}\u{1d770}\u{1d788}\u{1d78a}\u{1d7a8}\u{1d7aa}\u{1d7c2}\u{1d7c4}\u{1d7cb}\u{1df00}\u{1df09}\u{1df0b}\u{1df1e}\u{1df25}\u{1df2a}\u{1e900}\u{1e943} - #|const L : String = - #| $|\u{41}\u{5a}\u{61}\u{7a}\u{aa}\u{aa}\u{b5}\u{b5}\u{ba}\u{ba}\u{c0}\u{d6}\u{d8}\u{f6}\u{f8}\u{2c1}\u{2c6}\u{2d1}\u{2e0}\u{2e4}\u{2ec}\u{2ec}\u{2ee}\u{2ee}\u{370}\u{374}\u{376}\u{377}\u{37a}\u{37d}\u{37f}\u{37f}\u{386}\u{386}\u{388}\u{38a}\u{38c}\u{38c}\u{38e}\u{3a1}\u{3a3}\u{3f5}\u{3f7}\u{481}\u{48a}\u{52f}\u{531}\u{556}\u{559}\u{559}\u{560}\u{588}\u{5d0}\u{5ea}\u{5ef}\u{5f2}\u{620}\u{64a}\u{66e}\u{66f}\u{671}\u{6d3}\u{6d5}\u{6d5}\u{6e5}\u{6e6}\u{6ee}\u{6ef}\u{6fa}\u{6fc}\u{6ff}\u{6ff}\u{710}\u{710}\u{712}\u{72f}\u{74d}\u{7a5}\u{7b1}\u{7b1}\u{7ca}\u{7ea}\u{7f4}\u{7f5}\u{7fa}\u{7fa}\u{800}\u{815}\u{81a}\u{81a}\u{824}\u{824}\u{828}\u{828}\u{840}\u{858}\u{860}\u{86a}\u{870}\u{887}\u{889}\u{88e}\u{8a0}\u{8c9}\u{904}\u{939}\u{93d}\u{93d}\u{950}\u{950}\u{958}\u{961}\u{971}\u{980}\u{985}\u{98c}\u{98f}\u{990}\u{993}\u{9a8}\u{9aa}\u{9b0}\u{9b2}\u{9b2}\u{9b6}\u{9b9}\u{9bd}\u{9bd}\u{9ce}\u{9ce}\u{9dc}\u{9dd}\u{9df}\u{9e1}\u{9f0}\u{9f1}\u{9fc}\u{9fc}\u{a05}\u{a0a}\u{a0f}\u{a10}\u{a13}\u{a28}\u{a2a}\u{a30}\u{a32}\u{a33}\u{a35}\u{a36}\u{a38}\u{a39}\u{a59}\u{a5c}\u{a5e}\u{a5e}\u{a72}\u{a74}\u{a85}\u{a8d}\u{a8f}\u{a91}\u{a93}\u{aa8}\u{aaa}\u{ab0}\u{ab2}\u{ab3}\u{ab5}\u{ab9}\u{abd}\u{abd}\u{ad0}\u{ad0}\u{ae0}\u{ae1}\u{af9}\u{af9}\u{b05}\u{b0c}\u{b0f}\u{b10}\u{b13}\u{b28}\u{b2a}\u{b30}\u{b32}\u{b33}\u{b35}\u{b39}\u{b3d}\u{b3d}\u{b5c}\u{b5d}\u{b5f}\u{b61}\u{b71}\u{b71}\u{b83}\u{b83}\u{b85}\u{b8a}\u{b8e}\u{b90}\u{b92}\u{b95}\u{b99}\u{b9a}\u{b9c}\u{b9c}\u{b9e}\u{b9f}\u{ba3}\u{ba4}\u{ba8}\u{baa}\u{bae}\u{bb9}\u{bd0}\u{bd0}\u{c05}\u{c0c}\u{c0e}\u{c10}\u{c12}\u{c28}\u{c2a}\u{c39}\u{c3d}\u{c3d}\u{c58}\u{c5a}\u{c5d}\u{c5d}\u{c60}\u{c61}\u{c80}\u{c80}\u{c85}\u{c8c}\u{c8e}\u{c90}\u{c92}\u{ca8}\u{caa}\u{cb3}\u{cb5}\u{cb9}\u{cbd}\u{cbd}\u{cdd}\u{cde}\u{ce0}\u{ce1}\u{cf1}\u{cf2}\u{d04}\u{d0c}\u{d0e}\u{d10}\u{d12}\u{d3a}\u{d3d}\u{d3d}\u{d4e}\u{d4e}\u{d54}\u{d56}\u{d5f}\u{d61}\u{d7a}\u{d7f}\u{d85}\u{d96}\u{d9a}\u{db1}\u{db3}\u{dbb}\u{dbd}\u{dbd}\u{dc0}\u{dc6}\u{e01}\u{e30}\u{e32}\u{e33}\u{e40}\u{e46}\u{e81}\u{e82}\u{e84}\u{e84}\u{e86}\u{e8a}\u{e8c}\u{ea3}\u{ea5}\u{ea5}\u{ea7}\u{eb0}\u{eb2}\u{eb3}\u{ebd}\u{ebd}\u{ec0}\u{ec4}\u{ec6}\u{ec6}\u{edc}\u{edf}\u{f00}\u{f00}\u{f40}\u{f47}\u{f49}\u{f6c}\u{f88}\u{f8c}\u{1000}\u{102a}\u{103f}\u{103f}\u{1050}\u{1055}\u{105a}\u{105d}\u{1061}\u{1061}\u{1065}\u{1066}\u{106e}\u{1070}\u{1075}\u{1081}\u{108e}\u{108e}\u{10a0}\u{10c5}\u{10c7}\u{10c7}\u{10cd}\u{10cd}\u{10d0}\u{10fa}\u{10fc}\u{1248}\u{124a}\u{124d}\u{1250}\u{1256}\u{1258}\u{1258}\u{125a}\u{125d}\u{1260}\u{1288}\u{128a}\u{128d}\u{1290}\u{12b0}\u{12b2}\u{12b5}\u{12b8}\u{12be}\u{12c0}\u{12c0}\u{12c2}\u{12c5}\u{12c8}\u{12d6}\u{12d8}\u{1310}\u{1312}\u{1315}\u{1318}\u{135a}\u{1380}\u{138f}\u{13a0}\u{13f5}\u{13f8}\u{13fd}\u{1401}\u{166c}\u{166f}\u{167f}\u{1681}\u{169a}\u{16a0}\u{16ea}\u{16f1}\u{16f8}\u{1700}\u{1711}\u{171f}\u{1731}\u{1740}\u{1751}\u{1760}\u{176c}\u{176e}\u{1770}\u{1780}\u{17b3}\u{17d7}\u{17d7}\u{17dc}\u{17dc}\u{1820}\u{1878}\u{1880}\u{1884}\u{1887}\u{18a8}\u{18aa}\u{18aa}\u{18b0}\u{18f5}\u{1900}\u{191e}\u{1950}\u{196d}\u{1970}\u{1974}\u{1980}\u{19ab}\u{19b0}\u{19c9}\u{1a00}\u{1a16}\u{1a20}\u{1a54}\u{1aa7}\u{1aa7}\u{1b05}\u{1b33}\u{1b45}\u{1b4c}\u{1b83}\u{1ba0}\u{1bae}\u{1baf}\u{1bba}\u{1be5}\u{1c00}\u{1c23}\u{1c4d}\u{1c4f}\u{1c5a}\u{1c7d}\u{1c80}\u{1c8a}\u{1c90}\u{1cba}\u{1cbd}\u{1cbf}\u{1ce9}\u{1cec}\u{1cee}\u{1cf3}\u{1cf5}\u{1cf6}\u{1cfa}\u{1cfa}\u{1d00}\u{1dbf}\u{1e00}\u{1f15}\u{1f18}\u{1f1d}\u{1f20}\u{1f45}\u{1f48}\u{1f4d}\u{1f50}\u{1f57}\u{1f59}\u{1f59}\u{1f5b}\u{1f5b}\u{1f5d}\u{1f5d}\u{1f5f}\u{1f7d}\u{1f80}\u{1fb4}\u{1fb6}\u{1fbc}\u{1fbe}\u{1fbe}\u{1fc2}\u{1fc4}\u{1fc6}\u{1fcc}\u{1fd0}\u{1fd3}\u{1fd6}\u{1fdb}\u{1fe0}\u{1fec}\u{1ff2}\u{1ff4}\u{1ff6}\u{1ffc}\u{2071}\u{2071}\u{207f}\u{207f}\u{2090}\u{209c}\u{2102}\u{2102}\u{2107}\u{2107}\u{210a}\u{2113}\u{2115}\u{2115}\u{2119}\u{211d}\u{2124}\u{2124}\u{2126}\u{2126}\u{2128}\u{2128}\u{212a}\u{212d}\u{212f}\u{2139}\u{213c}\u{213f}\u{2145}\u{2149}\u{214e}\u{214e}\u{2183}\u{2184}\u{2c00}\u{2ce4}\u{2ceb}\u{2cee}\u{2cf2}\u{2cf3}\u{2d00}\u{2d25}\u{2d27}\u{2d27}\u{2d2d}\u{2d2d}\u{2d30}\u{2d67}\u{2d6f}\u{2d6f}\u{2d80}\u{2d96}\u{2da0}\u{2da6}\u{2da8}\u{2dae}\u{2db0}\u{2db6}\u{2db8}\u{2dbe}\u{2dc0}\u{2dc6}\u{2dc8}\u{2dce}\u{2dd0}\u{2dd6}\u{2dd8}\u{2dde}\u{2e2f}\u{2e2f}\u{3005}\u{3006}\u{3031}\u{3035}\u{303b}\u{303c}\u{3041}\u{3096}\u{309d}\u{309f}\u{30a1}\u{30fa}\u{30fc}\u{30ff}\u{3105}\u{312f}\u{3131}\u{318e}\u{31a0}\u{31bf}\u{31f0}\u{31ff}\u{3400}\u{4dbf}\u{4e00}\u{a48c}\u{a4d0}\u{a4fd}\u{a500}\u{a60c}\u{a610}\u{a61f}\u{a62a}\u{a62b}\u{a640}\u{a66e}\u{a67f}\u{a69d}\u{a6a0}\u{a6e5}\u{a717}\u{a71f}\u{a722}\u{a788}\u{a78b}\u{a7cd}\u{a7d0}\u{a7d1}\u{a7d3}\u{a7d3}\u{a7d5}\u{a7dc}\u{a7f2}\u{a801}\u{a803}\u{a805}\u{a807}\u{a80a}\u{a80c}\u{a822}\u{a840}\u{a873}\u{a882}\u{a8b3}\u{a8f2}\u{a8f7}\u{a8fb}\u{a8fb}\u{a8fd}\u{a8fe}\u{a90a}\u{a925}\u{a930}\u{a946}\u{a960}\u{a97c}\u{a984}\u{a9b2}\u{a9cf}\u{a9cf}\u{a9e0}\u{a9e4}\u{a9e6}\u{a9ef}\u{a9fa}\u{a9fe}\u{aa00}\u{aa28}\u{aa40}\u{aa42}\u{aa44}\u{aa4b}\u{aa60}\u{aa76}\u{aa7a}\u{aa7a}\u{aa7e}\u{aaaf}\u{aab1}\u{aab1}\u{aab5}\u{aab6}\u{aab9}\u{aabd}\u{aac0}\u{aac0}\u{aac2}\u{aac2}\u{aadb}\u{aadd}\u{aae0}\u{aaea}\u{aaf2}\u{aaf4}\u{ab01}\u{ab06}\u{ab09}\u{ab0e}\u{ab11}\u{ab16}\u{ab20}\u{ab26}\u{ab28}\u{ab2e}\u{ab30}\u{ab5a}\u{ab5c}\u{ab69}\u{ab70}\u{abe2}\u{ac00}\u{d7a3}\u{d7b0}\u{d7c6}\u{d7cb}\u{d7fb}\u{f900}\u{fa6d}\u{fa70}\u{fad9}\u{fb00}\u{fb06}\u{fb13}\u{fb17}\u{fb1d}\u{fb1d}\u{fb1f}\u{fb28}\u{fb2a}\u{fb36}\u{fb38}\u{fb3c}\u{fb3e}\u{fb3e}\u{fb40}\u{fb41}\u{fb43}\u{fb44}\u{fb46}\u{fbb1}\u{fbd3}\u{fd3d}\u{fd50}\u{fd8f}\u{fd92}\u{fdc7}\u{fdf0}\u{fdfb}\u{fe70}\u{fe74}\u{fe76}\u{fefc}\u{ff21}\u{ff3a}\u{ff41}\u{ff5a}\u{ff66}\u{ffbe}\u{ffc2}\u{ffc7}\u{ffca}\u{ffcf}\u{ffd2}\u{ffd7}\u{ffda}\u{ffdc}\u{10000}\u{1000b}\u{1000d}\u{10026}\u{10028}\u{1003a}\u{1003c}\u{1003d}\u{1003f}\u{1004d}\u{10050}\u{1005d}\u{10080}\u{100fa}\u{10280}\u{1029c}\u{102a0}\u{102d0}\u{10300}\u{1031f}\u{1032d}\u{10340}\u{10342}\u{10349}\u{10350}\u{10375}\u{10380}\u{1039d}\u{103a0}\u{103c3}\u{103c8}\u{103cf}\u{10400}\u{1049d}\u{104b0}\u{104d3}\u{104d8}\u{104fb}\u{10500}\u{10527}\u{10530}\u{10563}\u{10570}\u{1057a}\u{1057c}\u{1058a}\u{1058c}\u{10592}\u{10594}\u{10595}\u{10597}\u{105a1}\u{105a3}\u{105b1}\u{105b3}\u{105b9}\u{105bb}\u{105bc}\u{105c0}\u{105f3}\u{10600}\u{10736}\u{10740}\u{10755}\u{10760}\u{10767}\u{10780}\u{10785}\u{10787}\u{107b0}\u{107b2}\u{107ba}\u{10800}\u{10805}\u{10808}\u{10808}\u{1080a}\u{10835}\u{10837}\u{10838}\u{1083c}\u{1083c}\u{1083f}\u{10855}\u{10860}\u{10876}\u{10880}\u{1089e}\u{108e0}\u{108f2}\u{108f4}\u{108f5}\u{10900}\u{10915}\u{10920}\u{10939}\u{10980}\u{109b7}\u{109be}\u{109bf}\u{10a00}\u{10a00}\u{10a10}\u{10a13}\u{10a15}\u{10a17}\u{10a19}\u{10a35}\u{10a60}\u{10a7c}\u{10a80}\u{10a9c}\u{10ac0}\u{10ac7}\u{10ac9}\u{10ae4}\u{10b00}\u{10b35}\u{10b40}\u{10b55}\u{10b60}\u{10b72}\u{10b80}\u{10b91}\u{10c00}\u{10c48}\u{10c80}\u{10cb2}\u{10cc0}\u{10cf2}\u{10d00}\u{10d23}\u{10d4a}\u{10d65}\u{10d6f}\u{10d85}\u{10e80}\u{10ea9}\u{10eb0}\u{10eb1}\u{10ec2}\u{10ec4}\u{10f00}\u{10f1c}\u{10f27}\u{10f27}\u{10f30}\u{10f45}\u{10f70}\u{10f81}\u{10fb0}\u{10fc4}\u{10fe0}\u{10ff6}\u{11003}\u{11037}\u{11071}\u{11072}\u{11075}\u{11075}\u{11083}\u{110af}\u{110d0}\u{110e8}\u{11103}\u{11126}\u{11144}\u{11144}\u{11147}\u{11147}\u{11150}\u{11172}\u{11176}\u{11176}\u{11183}\u{111b2}\u{111c1}\u{111c4}\u{111da}\u{111da}\u{111dc}\u{111dc}\u{11200}\u{11211}\u{11213}\u{1122b}\u{1123f}\u{11240}\u{11280}\u{11286}\u{11288}\u{11288}\u{1128a}\u{1128d}\u{1128f}\u{1129d}\u{1129f}\u{112a8}\u{112b0}\u{112de}\u{11305}\u{1130c}\u{1130f}\u{11310}\u{11313}\u{11328}\u{1132a}\u{11330}\u{11332}\u{11333}\u{11335}\u{11339}\u{1133d}\u{1133d}\u{11350}\u{11350}\u{1135d}\u{11361}\u{11380}\u{11389}\u{1138b}\u{1138b}\u{1138e}\u{1138e}\u{11390}\u{113b5}\u{113b7}\u{113b7}\u{113d1}\u{113d1}\u{113d3}\u{113d3}\u{11400}\u{11434}\u{11447}\u{1144a}\u{1145f}\u{11461}\u{11480}\u{114af}\u{114c4}\u{114c5}\u{114c7}\u{114c7}\u{11580}\u{115ae}\u{115d8}\u{115db}\u{11600}\u{1162f}\u{11644}\u{11644}\u{11680}\u{116aa}\u{116b8}\u{116b8}\u{11700}\u{1171a}\u{11740}\u{11746}\u{11800}\u{1182b}\u{118a0}\u{118df}\u{118ff}\u{11906}\u{11909}\u{11909}\u{1190c}\u{11913}\u{11915}\u{11916}\u{11918}\u{1192f}\u{1193f}\u{1193f}\u{11941}\u{11941}\u{119a0}\u{119a7}\u{119aa}\u{119d0}\u{119e1}\u{119e1}\u{119e3}\u{119e3}\u{11a00}\u{11a00}\u{11a0b}\u{11a32}\u{11a3a}\u{11a3a}\u{11a50}\u{11a50}\u{11a5c}\u{11a89}\u{11a9d}\u{11a9d}\u{11ab0}\u{11af8}\u{11bc0}\u{11be0}\u{11c00}\u{11c08}\u{11c0a}\u{11c2e}\u{11c40}\u{11c40}\u{11c72}\u{11c8f}\u{11d00}\u{11d06}\u{11d08}\u{11d09}\u{11d0b}\u{11d30}\u{11d46}\u{11d46}\u{11d60}\u{11d65}\u{11d67}\u{11d68}\u{11d6a}\u{11d89}\u{11d98}\u{11d98}\u{11ee0}\u{11ef2}\u{11f02}\u{11f02}\u{11f04}\u{11f10}\u{11f12}\u{11f33}\u{11fb0}\u{11fb0}\u{12000}\u{12399}\u{12480}\u{12543}\u{12f90}\u{12ff0}\u{13000}\u{1342f}\u{13441}\u{13446}\u{13460}\u{143fa}\u{14400}\u{14646}\u{16100}\u{1611d}\u{16800}\u{16a38}\u{16a40}\u{16a5e}\u{16a70}\u{16abe}\u{16ad0}\u{16aed}\u{16b00}\u{16b2f}\u{16b40}\u{16b43}\u{16b63}\u{16b77}\u{16b7d}\u{16b8f}\u{16d40}\u{16d6c}\u{16e40}\u{16e7f}\u{16f00}\u{16f4a}\u{16f50}\u{16f50}\u{16f93}\u{16f9f}\u{16fe0}\u{16fe1}\u{16fe3}\u{16fe3}\u{17000}\u{187f7}\u{18800}\u{18cd5}\u{18cff}\u{18d08}\u{1aff0}\u{1aff3}\u{1aff5}\u{1affb}\u{1affd}\u{1affe}\u{1b000}\u{1b122}\u{1b132}\u{1b132}\u{1b150}\u{1b152}\u{1b155}\u{1b155}\u{1b164}\u{1b167}\u{1b170}\u{1b2fb}\u{1bc00}\u{1bc6a}\u{1bc70}\u{1bc7c}\u{1bc80}\u{1bc88}\u{1bc90}\u{1bc99}\u{1d400}\u{1d454}\u{1d456}\u{1d49c}\u{1d49e}\u{1d49f}\u{1d4a2}\u{1d4a2}\u{1d4a5}\u{1d4a6}\u{1d4a9}\u{1d4ac}\u{1d4ae}\u{1d4b9}\u{1d4bb}\u{1d4bb}\u{1d4bd}\u{1d4c3}\u{1d4c5}\u{1d505}\u{1d507}\u{1d50a}\u{1d50d}\u{1d514}\u{1d516}\u{1d51c}\u{1d51e}\u{1d539}\u{1d53b}\u{1d53e}\u{1d540}\u{1d544}\u{1d546}\u{1d546}\u{1d54a}\u{1d550}\u{1d552}\u{1d6a5}\u{1d6a8}\u{1d6c0}\u{1d6c2}\u{1d6da}\u{1d6dc}\u{1d6fa}\u{1d6fc}\u{1d714}\u{1d716}\u{1d734}\u{1d736}\u{1d74e}\u{1d750}\u{1d76e}\u{1d770}\u{1d788}\u{1d78a}\u{1d7a8}\u{1d7aa}\u{1d7c2}\u{1d7c4}\u{1d7cb}\u{1df00}\u{1df1e}\u{1df25}\u{1df2a}\u{1e030}\u{1e06d}\u{1e100}\u{1e12c}\u{1e137}\u{1e13d}\u{1e14e}\u{1e14e}\u{1e290}\u{1e2ad}\u{1e2c0}\u{1e2eb}\u{1e4d0}\u{1e4eb}\u{1e5d0}\u{1e5ed}\u{1e5f0}\u{1e5f0}\u{1e7e0}\u{1e7e6}\u{1e7e8}\u{1e7eb}\u{1e7ed}\u{1e7ee}\u{1e7f0}\u{1e7fe}\u{1e800}\u{1e8c4}\u{1e900}\u{1e943}\u{1e94b}\u{1e94b}\u{1ee00}\u{1ee03}\u{1ee05}\u{1ee1f}\u{1ee21}\u{1ee22}\u{1ee24}\u{1ee24}\u{1ee27}\u{1ee27}\u{1ee29}\u{1ee32}\u{1ee34}\u{1ee37}\u{1ee39}\u{1ee39}\u{1ee3b}\u{1ee3b}\u{1ee42}\u{1ee42}\u{1ee47}\u{1ee47}\u{1ee49}\u{1ee49}\u{1ee4b}\u{1ee4b}\u{1ee4d}\u{1ee4f}\u{1ee51}\u{1ee52}\u{1ee54}\u{1ee54}\u{1ee57}\u{1ee57}\u{1ee59}\u{1ee59}\u{1ee5b}\u{1ee5b}\u{1ee5d}\u{1ee5d}\u{1ee5f}\u{1ee5f}\u{1ee61}\u{1ee62}\u{1ee64}\u{1ee64}\u{1ee67}\u{1ee6a}\u{1ee6c}\u{1ee72}\u{1ee74}\u{1ee77}\u{1ee79}\u{1ee7c}\u{1ee7e}\u{1ee7e}\u{1ee80}\u{1ee89}\u{1ee8b}\u{1ee9b}\u{1eea1}\u{1eea3}\u{1eea5}\u{1eea9}\u{1eeab}\u{1eebb}\u{20000}\u{2a6df}\u{2a700}\u{2b739}\u{2b740}\u{2b81d}\u{2b820}\u{2cea1}\u{2ceb0}\u{2ebe0}\u{2ebf0}\u{2ee5d}\u{2f800}\u{2fa1d}\u{30000}\u{3134a}\u{31350}\u{323af} - #|const M : String = - #| $|\u{300}\u{36f}\u{483}\u{489}\u{591}\u{5bd}\u{5bf}\u{5bf}\u{5c1}\u{5c2}\u{5c4}\u{5c5}\u{5c7}\u{5c7}\u{610}\u{61a}\u{64b}\u{65f}\u{670}\u{670}\u{6d6}\u{6dc}\u{6df}\u{6e4}\u{6e7}\u{6e8}\u{6ea}\u{6ed}\u{711}\u{711}\u{730}\u{74a}\u{7a6}\u{7b0}\u{7eb}\u{7f3}\u{7fd}\u{7fd}\u{816}\u{819}\u{81b}\u{823}\u{825}\u{827}\u{829}\u{82d}\u{859}\u{85b}\u{897}\u{89f}\u{8ca}\u{8e1}\u{8e3}\u{903}\u{93a}\u{93c}\u{93e}\u{94f}\u{951}\u{957}\u{962}\u{963}\u{981}\u{983}\u{9bc}\u{9bc}\u{9be}\u{9c4}\u{9c7}\u{9c8}\u{9cb}\u{9cd}\u{9d7}\u{9d7}\u{9e2}\u{9e3}\u{9fe}\u{9fe}\u{a01}\u{a03}\u{a3c}\u{a3c}\u{a3e}\u{a42}\u{a47}\u{a48}\u{a4b}\u{a4d}\u{a51}\u{a51}\u{a70}\u{a71}\u{a75}\u{a75}\u{a81}\u{a83}\u{abc}\u{abc}\u{abe}\u{ac5}\u{ac7}\u{ac9}\u{acb}\u{acd}\u{ae2}\u{ae3}\u{afa}\u{aff}\u{b01}\u{b03}\u{b3c}\u{b3c}\u{b3e}\u{b44}\u{b47}\u{b48}\u{b4b}\u{b4d}\u{b55}\u{b57}\u{b62}\u{b63}\u{b82}\u{b82}\u{bbe}\u{bc2}\u{bc6}\u{bc8}\u{bca}\u{bcd}\u{bd7}\u{bd7}\u{c00}\u{c04}\u{c3c}\u{c3c}\u{c3e}\u{c44}\u{c46}\u{c48}\u{c4a}\u{c4d}\u{c55}\u{c56}\u{c62}\u{c63}\u{c81}\u{c83}\u{cbc}\u{cbc}\u{cbe}\u{cc4}\u{cc6}\u{cc8}\u{cca}\u{ccd}\u{cd5}\u{cd6}\u{ce2}\u{ce3}\u{cf3}\u{cf3}\u{d00}\u{d03}\u{d3b}\u{d3c}\u{d3e}\u{d44}\u{d46}\u{d48}\u{d4a}\u{d4d}\u{d57}\u{d57}\u{d62}\u{d63}\u{d81}\u{d83}\u{dca}\u{dca}\u{dcf}\u{dd4}\u{dd6}\u{dd6}\u{dd8}\u{ddf}\u{df2}\u{df3}\u{e31}\u{e31}\u{e34}\u{e3a}\u{e47}\u{e4e}\u{eb1}\u{eb1}\u{eb4}\u{ebc}\u{ec8}\u{ece}\u{f18}\u{f19}\u{f35}\u{f35}\u{f37}\u{f37}\u{f39}\u{f39}\u{f3e}\u{f3f}\u{f71}\u{f84}\u{f86}\u{f87}\u{f8d}\u{f97}\u{f99}\u{fbc}\u{fc6}\u{fc6}\u{102b}\u{103e}\u{1056}\u{1059}\u{105e}\u{1060}\u{1062}\u{1064}\u{1067}\u{106d}\u{1071}\u{1074}\u{1082}\u{108d}\u{108f}\u{108f}\u{109a}\u{109d}\u{135d}\u{135f}\u{1712}\u{1715}\u{1732}\u{1734}\u{1752}\u{1753}\u{1772}\u{1773}\u{17b4}\u{17d3}\u{17dd}\u{17dd}\u{180b}\u{180d}\u{180f}\u{180f}\u{1885}\u{1886}\u{18a9}\u{18a9}\u{1920}\u{192b}\u{1930}\u{193b}\u{1a17}\u{1a1b}\u{1a55}\u{1a5e}\u{1a60}\u{1a7c}\u{1a7f}\u{1a7f}\u{1ab0}\u{1ace}\u{1b00}\u{1b04}\u{1b34}\u{1b44}\u{1b6b}\u{1b73}\u{1b80}\u{1b82}\u{1ba1}\u{1bad}\u{1be6}\u{1bf3}\u{1c24}\u{1c37}\u{1cd0}\u{1cd2}\u{1cd4}\u{1ce8}\u{1ced}\u{1ced}\u{1cf4}\u{1cf4}\u{1cf7}\u{1cf9}\u{1dc0}\u{1dff}\u{20d0}\u{20f0}\u{2cef}\u{2cf1}\u{2d7f}\u{2d7f}\u{2de0}\u{2dff}\u{302a}\u{302f}\u{3099}\u{309a}\u{a66f}\u{a672}\u{a674}\u{a67d}\u{a69e}\u{a69f}\u{a6f0}\u{a6f1}\u{a802}\u{a802}\u{a806}\u{a806}\u{a80b}\u{a80b}\u{a823}\u{a827}\u{a82c}\u{a82c}\u{a880}\u{a881}\u{a8b4}\u{a8c5}\u{a8e0}\u{a8f1}\u{a8ff}\u{a8ff}\u{a926}\u{a92d}\u{a947}\u{a953}\u{a980}\u{a983}\u{a9b3}\u{a9c0}\u{a9e5}\u{a9e5}\u{aa29}\u{aa36}\u{aa43}\u{aa43}\u{aa4c}\u{aa4d}\u{aa7b}\u{aa7d}\u{aab0}\u{aab0}\u{aab2}\u{aab4}\u{aab7}\u{aab8}\u{aabe}\u{aabf}\u{aac1}\u{aac1}\u{aaeb}\u{aaef}\u{aaf5}\u{aaf6}\u{abe3}\u{abea}\u{abec}\u{abed}\u{fb1e}\u{fb1e}\u{fe00}\u{fe0f}\u{fe20}\u{fe2f}\u{101fd}\u{101fd}\u{102e0}\u{102e0}\u{10376}\u{1037a}\u{10a01}\u{10a03}\u{10a05}\u{10a06}\u{10a0c}\u{10a0f}\u{10a38}\u{10a3a}\u{10a3f}\u{10a3f}\u{10ae5}\u{10ae6}\u{10d24}\u{10d27}\u{10d69}\u{10d6d}\u{10eab}\u{10eac}\u{10efc}\u{10eff}\u{10f46}\u{10f50}\u{10f82}\u{10f85}\u{11000}\u{11002}\u{11038}\u{11046}\u{11070}\u{11070}\u{11073}\u{11074}\u{1107f}\u{11082}\u{110b0}\u{110ba}\u{110c2}\u{110c2}\u{11100}\u{11102}\u{11127}\u{11134}\u{11145}\u{11146}\u{11173}\u{11173}\u{11180}\u{11182}\u{111b3}\u{111c0}\u{111c9}\u{111cc}\u{111ce}\u{111cf}\u{1122c}\u{11237}\u{1123e}\u{1123e}\u{11241}\u{11241}\u{112df}\u{112ea}\u{11300}\u{11303}\u{1133b}\u{1133c}\u{1133e}\u{11344}\u{11347}\u{11348}\u{1134b}\u{1134d}\u{11357}\u{11357}\u{11362}\u{11363}\u{11366}\u{1136c}\u{11370}\u{11374}\u{113b8}\u{113c0}\u{113c2}\u{113c2}\u{113c5}\u{113c5}\u{113c7}\u{113ca}\u{113cc}\u{113d0}\u{113d2}\u{113d2}\u{113e1}\u{113e2}\u{11435}\u{11446}\u{1145e}\u{1145e}\u{114b0}\u{114c3}\u{115af}\u{115b5}\u{115b8}\u{115c0}\u{115dc}\u{115dd}\u{11630}\u{11640}\u{116ab}\u{116b7}\u{1171d}\u{1172b}\u{1182c}\u{1183a}\u{11930}\u{11935}\u{11937}\u{11938}\u{1193b}\u{1193e}\u{11940}\u{11940}\u{11942}\u{11943}\u{119d1}\u{119d7}\u{119da}\u{119e0}\u{119e4}\u{119e4}\u{11a01}\u{11a0a}\u{11a33}\u{11a39}\u{11a3b}\u{11a3e}\u{11a47}\u{11a47}\u{11a51}\u{11a5b}\u{11a8a}\u{11a99}\u{11c2f}\u{11c36}\u{11c38}\u{11c3f}\u{11c92}\u{11ca7}\u{11ca9}\u{11cb6}\u{11d31}\u{11d36}\u{11d3a}\u{11d3a}\u{11d3c}\u{11d3d}\u{11d3f}\u{11d45}\u{11d47}\u{11d47}\u{11d8a}\u{11d8e}\u{11d90}\u{11d91}\u{11d93}\u{11d97}\u{11ef3}\u{11ef6}\u{11f00}\u{11f01}\u{11f03}\u{11f03}\u{11f34}\u{11f3a}\u{11f3e}\u{11f42}\u{11f5a}\u{11f5a}\u{13440}\u{13440}\u{13447}\u{13455}\u{1611e}\u{1612f}\u{16af0}\u{16af4}\u{16b30}\u{16b36}\u{16f4f}\u{16f4f}\u{16f51}\u{16f87}\u{16f8f}\u{16f92}\u{16fe4}\u{16fe4}\u{16ff0}\u{16ff1}\u{1bc9d}\u{1bc9e}\u{1cf00}\u{1cf2d}\u{1cf30}\u{1cf46}\u{1d165}\u{1d169}\u{1d16d}\u{1d172}\u{1d17b}\u{1d182}\u{1d185}\u{1d18b}\u{1d1aa}\u{1d1ad}\u{1d242}\u{1d244}\u{1da00}\u{1da36}\u{1da3b}\u{1da6c}\u{1da75}\u{1da75}\u{1da84}\u{1da84}\u{1da9b}\u{1da9f}\u{1daa1}\u{1daaf}\u{1e000}\u{1e006}\u{1e008}\u{1e018}\u{1e01b}\u{1e021}\u{1e023}\u{1e024}\u{1e026}\u{1e02a}\u{1e08f}\u{1e08f}\u{1e130}\u{1e136}\u{1e2ae}\u{1e2ae}\u{1e2ec}\u{1e2ef}\u{1e4ec}\u{1e4ef}\u{1e5ee}\u{1e5ef}\u{1e8d0}\u{1e8d6}\u{1e944}\u{1e94a}\u{e0100}\u{e01ef} - #|const N : String = - #| $|\u{30}\u{39}\u{b2}\u{b3}\u{b9}\u{b9}\u{bc}\u{be}\u{660}\u{669}\u{6f0}\u{6f9}\u{7c0}\u{7c9}\u{966}\u{96f}\u{9e6}\u{9ef}\u{9f4}\u{9f9}\u{a66}\u{a6f}\u{ae6}\u{aef}\u{b66}\u{b6f}\u{b72}\u{b77}\u{be6}\u{bf2}\u{c66}\u{c6f}\u{c78}\u{c7e}\u{ce6}\u{cef}\u{d58}\u{d5e}\u{d66}\u{d78}\u{de6}\u{def}\u{e50}\u{e59}\u{ed0}\u{ed9}\u{f20}\u{f33}\u{1040}\u{1049}\u{1090}\u{1099}\u{1369}\u{137c}\u{16ee}\u{16f0}\u{17e0}\u{17e9}\u{17f0}\u{17f9}\u{1810}\u{1819}\u{1946}\u{194f}\u{19d0}\u{19da}\u{1a80}\u{1a89}\u{1a90}\u{1a99}\u{1b50}\u{1b59}\u{1bb0}\u{1bb9}\u{1c40}\u{1c49}\u{1c50}\u{1c59}\u{2070}\u{2070}\u{2074}\u{2079}\u{2080}\u{2089}\u{2150}\u{2182}\u{2185}\u{2189}\u{2460}\u{249b}\u{24ea}\u{24ff}\u{2776}\u{2793}\u{2cfd}\u{2cfd}\u{3007}\u{3007}\u{3021}\u{3029}\u{3038}\u{303a}\u{3192}\u{3195}\u{3220}\u{3229}\u{3248}\u{324f}\u{3251}\u{325f}\u{3280}\u{3289}\u{32b1}\u{32bf}\u{a620}\u{a629}\u{a6e6}\u{a6ef}\u{a830}\u{a835}\u{a8d0}\u{a8d9}\u{a900}\u{a909}\u{a9d0}\u{a9d9}\u{a9f0}\u{a9f9}\u{aa50}\u{aa59}\u{abf0}\u{abf9}\u{ff10}\u{ff19}\u{10107}\u{10133}\u{10140}\u{10178}\u{1018a}\u{1018b}\u{102e1}\u{102fb}\u{10320}\u{10323}\u{10341}\u{10341}\u{1034a}\u{1034a}\u{103d1}\u{103d5}\u{104a0}\u{104a9}\u{10858}\u{1085f}\u{10879}\u{1087f}\u{108a7}\u{108af}\u{108fb}\u{108ff}\u{10916}\u{1091b}\u{109bc}\u{109bd}\u{109c0}\u{109cf}\u{109d2}\u{109ff}\u{10a40}\u{10a48}\u{10a7d}\u{10a7e}\u{10a9d}\u{10a9f}\u{10aeb}\u{10aef}\u{10b58}\u{10b5f}\u{10b78}\u{10b7f}\u{10ba9}\u{10baf}\u{10cfa}\u{10cff}\u{10d30}\u{10d39}\u{10d40}\u{10d49}\u{10e60}\u{10e7e}\u{10f1d}\u{10f26}\u{10f51}\u{10f54}\u{10fc5}\u{10fcb}\u{11052}\u{1106f}\u{110f0}\u{110f9}\u{11136}\u{1113f}\u{111d0}\u{111d9}\u{111e1}\u{111f4}\u{112f0}\u{112f9}\u{11450}\u{11459}\u{114d0}\u{114d9}\u{11650}\u{11659}\u{116c0}\u{116c9}\u{116d0}\u{116e3}\u{11730}\u{1173b}\u{118e0}\u{118f2}\u{11950}\u{11959}\u{11bf0}\u{11bf9}\u{11c50}\u{11c6c}\u{11d50}\u{11d59}\u{11da0}\u{11da9}\u{11f50}\u{11f59}\u{11fc0}\u{11fd4}\u{12400}\u{1246e}\u{16130}\u{16139}\u{16a60}\u{16a69}\u{16ac0}\u{16ac9}\u{16b50}\u{16b59}\u{16b5b}\u{16b61}\u{16d70}\u{16d79}\u{16e80}\u{16e96}\u{1ccf0}\u{1ccf9}\u{1d2c0}\u{1d2d3}\u{1d2e0}\u{1d2f3}\u{1d360}\u{1d378}\u{1d7ce}\u{1d7ff}\u{1e140}\u{1e149}\u{1e2f0}\u{1e2f9}\u{1e4f0}\u{1e4f9}\u{1e5f1}\u{1e5fa}\u{1e8c7}\u{1e8cf}\u{1e950}\u{1e959}\u{1ec71}\u{1ecab}\u{1ecad}\u{1ecaf}\u{1ecb1}\u{1ecb4}\u{1ed01}\u{1ed2d}\u{1ed2f}\u{1ed3d}\u{1f100}\u{1f10c}\u{1fbf0}\u{1fbf9} - #|const P : String = - #| $|\u{21}\u{23}\u{25}\u{2a}\u{2c}\u{2f}\u{3a}\u{3b}\u{3f}\u{40}\u{5b}\u{5d}\u{5f}\u{5f}\u{7b}\u{7b}\u{7d}\u{7d}\u{a1}\u{a1}\u{a7}\u{a7}\u{ab}\u{ab}\u{b6}\u{b7}\u{bb}\u{bb}\u{bf}\u{bf}\u{37e}\u{37e}\u{387}\u{387}\u{55a}\u{55f}\u{589}\u{58a}\u{5be}\u{5be}\u{5c0}\u{5c0}\u{5c3}\u{5c3}\u{5c6}\u{5c6}\u{5f3}\u{5f4}\u{609}\u{60a}\u{60c}\u{60d}\u{61b}\u{61b}\u{61d}\u{61f}\u{66a}\u{66d}\u{6d4}\u{6d4}\u{700}\u{70d}\u{7f7}\u{7f9}\u{830}\u{83e}\u{85e}\u{85e}\u{964}\u{965}\u{970}\u{970}\u{9fd}\u{9fd}\u{a76}\u{a76}\u{af0}\u{af0}\u{c77}\u{c77}\u{c84}\u{c84}\u{df4}\u{df4}\u{e4f}\u{e4f}\u{e5a}\u{e5b}\u{f04}\u{f12}\u{f14}\u{f14}\u{f3a}\u{f3d}\u{f85}\u{f85}\u{fd0}\u{fd4}\u{fd9}\u{fda}\u{104a}\u{104f}\u{10fb}\u{10fb}\u{1360}\u{1368}\u{1400}\u{1400}\u{166e}\u{166e}\u{169b}\u{169c}\u{16eb}\u{16ed}\u{1735}\u{1736}\u{17d4}\u{17d6}\u{17d8}\u{17da}\u{1800}\u{180a}\u{1944}\u{1945}\u{1a1e}\u{1a1f}\u{1aa0}\u{1aa6}\u{1aa8}\u{1aad}\u{1b4e}\u{1b4f}\u{1b5a}\u{1b60}\u{1b7d}\u{1b7f}\u{1bfc}\u{1bff}\u{1c3b}\u{1c3f}\u{1c7e}\u{1c7f}\u{1cc0}\u{1cc7}\u{1cd3}\u{1cd3}\u{2010}\u{2027}\u{2030}\u{2043}\u{2045}\u{2051}\u{2053}\u{205e}\u{207d}\u{207e}\u{208d}\u{208e}\u{2308}\u{230b}\u{2329}\u{232a}\u{2768}\u{2775}\u{27c5}\u{27c6}\u{27e6}\u{27ef}\u{2983}\u{2998}\u{29d8}\u{29db}\u{29fc}\u{29fd}\u{2cf9}\u{2cfc}\u{2cfe}\u{2cff}\u{2d70}\u{2d70}\u{2e00}\u{2e2e}\u{2e30}\u{2e4f}\u{2e52}\u{2e5d}\u{3001}\u{3003}\u{3008}\u{3011}\u{3014}\u{301f}\u{3030}\u{3030}\u{303d}\u{303d}\u{30a0}\u{30a0}\u{30fb}\u{30fb}\u{a4fe}\u{a4ff}\u{a60d}\u{a60f}\u{a673}\u{a673}\u{a67e}\u{a67e}\u{a6f2}\u{a6f7}\u{a874}\u{a877}\u{a8ce}\u{a8cf}\u{a8f8}\u{a8fa}\u{a8fc}\u{a8fc}\u{a92e}\u{a92f}\u{a95f}\u{a95f}\u{a9c1}\u{a9cd}\u{a9de}\u{a9df}\u{aa5c}\u{aa5f}\u{aade}\u{aadf}\u{aaf0}\u{aaf1}\u{abeb}\u{abeb}\u{fd3e}\u{fd3f}\u{fe10}\u{fe19}\u{fe30}\u{fe52}\u{fe54}\u{fe61}\u{fe63}\u{fe63}\u{fe68}\u{fe68}\u{fe6a}\u{fe6b}\u{ff01}\u{ff03}\u{ff05}\u{ff0a}\u{ff0c}\u{ff0f}\u{ff1a}\u{ff1b}\u{ff1f}\u{ff20}\u{ff3b}\u{ff3d}\u{ff3f}\u{ff3f}\u{ff5b}\u{ff5b}\u{ff5d}\u{ff5d}\u{ff5f}\u{ff65}\u{10100}\u{10102}\u{1039f}\u{1039f}\u{103d0}\u{103d0}\u{1056f}\u{1056f}\u{10857}\u{10857}\u{1091f}\u{1091f}\u{1093f}\u{1093f}\u{10a50}\u{10a58}\u{10a7f}\u{10a7f}\u{10af0}\u{10af6}\u{10b39}\u{10b3f}\u{10b99}\u{10b9c}\u{10d6e}\u{10d6e}\u{10ead}\u{10ead}\u{10f55}\u{10f59}\u{10f86}\u{10f89}\u{11047}\u{1104d}\u{110bb}\u{110bc}\u{110be}\u{110c1}\u{11140}\u{11143}\u{11174}\u{11175}\u{111c5}\u{111c8}\u{111cd}\u{111cd}\u{111db}\u{111db}\u{111dd}\u{111df}\u{11238}\u{1123d}\u{112a9}\u{112a9}\u{113d4}\u{113d5}\u{113d7}\u{113d8}\u{1144b}\u{1144f}\u{1145a}\u{1145b}\u{1145d}\u{1145d}\u{114c6}\u{114c6}\u{115c1}\u{115d7}\u{11641}\u{11643}\u{11660}\u{1166c}\u{116b9}\u{116b9}\u{1173c}\u{1173e}\u{1183b}\u{1183b}\u{11944}\u{11946}\u{119e2}\u{119e2}\u{11a3f}\u{11a46}\u{11a9a}\u{11a9c}\u{11a9e}\u{11aa2}\u{11b00}\u{11b09}\u{11be1}\u{11be1}\u{11c41}\u{11c45}\u{11c70}\u{11c71}\u{11ef7}\u{11ef8}\u{11f43}\u{11f4f}\u{11fff}\u{11fff}\u{12470}\u{12474}\u{12ff1}\u{12ff2}\u{16a6e}\u{16a6f}\u{16af5}\u{16af5}\u{16b37}\u{16b3b}\u{16b44}\u{16b44}\u{16d6d}\u{16d6f}\u{16e97}\u{16e9a}\u{16fe2}\u{16fe2}\u{1bc9f}\u{1bc9f}\u{1da87}\u{1da8b}\u{1e5ff}\u{1e5ff}\u{1e95e}\u{1e95f} - #|const S : String = - #| $|\u{24}\u{24}\u{2b}\u{2b}\u{3c}\u{3e}\u{5e}\u{5e}\u{60}\u{60}\u{7c}\u{7c}\u{7e}\u{7e}\u{a2}\u{a6}\u{a8}\u{a9}\u{ac}\u{ac}\u{ae}\u{b1}\u{b4}\u{b4}\u{b8}\u{b8}\u{d7}\u{d7}\u{f7}\u{f7}\u{2c2}\u{2c5}\u{2d2}\u{2df}\u{2e5}\u{2eb}\u{2ed}\u{2ed}\u{2ef}\u{2ff}\u{375}\u{375}\u{384}\u{385}\u{3f6}\u{3f6}\u{482}\u{482}\u{58d}\u{58f}\u{606}\u{608}\u{60b}\u{60b}\u{60e}\u{60f}\u{6de}\u{6de}\u{6e9}\u{6e9}\u{6fd}\u{6fe}\u{7f6}\u{7f6}\u{7fe}\u{7ff}\u{888}\u{888}\u{9f2}\u{9f3}\u{9fa}\u{9fb}\u{af1}\u{af1}\u{b70}\u{b70}\u{bf3}\u{bfa}\u{c7f}\u{c7f}\u{d4f}\u{d4f}\u{d79}\u{d79}\u{e3f}\u{e3f}\u{f01}\u{f03}\u{f13}\u{f13}\u{f15}\u{f17}\u{f1a}\u{f1f}\u{f34}\u{f34}\u{f36}\u{f36}\u{f38}\u{f38}\u{fbe}\u{fc5}\u{fc7}\u{fcc}\u{fce}\u{fcf}\u{fd5}\u{fd8}\u{109e}\u{109f}\u{1390}\u{1399}\u{166d}\u{166d}\u{17db}\u{17db}\u{1940}\u{1940}\u{19de}\u{19ff}\u{1b61}\u{1b6a}\u{1b74}\u{1b7c}\u{1fbd}\u{1fbd}\u{1fbf}\u{1fc1}\u{1fcd}\u{1fcf}\u{1fdd}\u{1fdf}\u{1fed}\u{1fef}\u{1ffd}\u{1ffe}\u{2044}\u{2044}\u{2052}\u{2052}\u{207a}\u{207c}\u{208a}\u{208c}\u{20a0}\u{20c0}\u{2100}\u{2101}\u{2103}\u{2106}\u{2108}\u{2109}\u{2114}\u{2114}\u{2116}\u{2118}\u{211e}\u{2123}\u{2125}\u{2125}\u{2127}\u{2127}\u{2129}\u{2129}\u{212e}\u{212e}\u{213a}\u{213b}\u{2140}\u{2144}\u{214a}\u{214d}\u{214f}\u{214f}\u{218a}\u{218b}\u{2190}\u{2307}\u{230c}\u{2328}\u{232b}\u{2429}\u{2440}\u{244a}\u{249c}\u{24e9}\u{2500}\u{2767}\u{2794}\u{27c4}\u{27c7}\u{27e5}\u{27f0}\u{2982}\u{2999}\u{29d7}\u{29dc}\u{29fb}\u{29fe}\u{2b73}\u{2b76}\u{2b95}\u{2b97}\u{2bff}\u{2ce5}\u{2cea}\u{2e50}\u{2e51}\u{2e80}\u{2e99}\u{2e9b}\u{2ef3}\u{2f00}\u{2fd5}\u{2ff0}\u{2fff}\u{3004}\u{3004}\u{3012}\u{3013}\u{3020}\u{3020}\u{3036}\u{3037}\u{303e}\u{303f}\u{309b}\u{309c}\u{3190}\u{3191}\u{3196}\u{319f}\u{31c0}\u{31e5}\u{31ef}\u{31ef}\u{3200}\u{321e}\u{322a}\u{3247}\u{3250}\u{3250}\u{3260}\u{327f}\u{328a}\u{32b0}\u{32c0}\u{33ff}\u{4dc0}\u{4dff}\u{a490}\u{a4c6}\u{a700}\u{a716}\u{a720}\u{a721}\u{a789}\u{a78a}\u{a828}\u{a82b}\u{a836}\u{a839}\u{aa77}\u{aa79}\u{ab5b}\u{ab5b}\u{ab6a}\u{ab6b}\u{fb29}\u{fb29}\u{fbb2}\u{fbc2}\u{fd40}\u{fd4f}\u{fdcf}\u{fdcf}\u{fdfc}\u{fdff}\u{fe62}\u{fe62}\u{fe64}\u{fe66}\u{fe69}\u{fe69}\u{ff04}\u{ff04}\u{ff0b}\u{ff0b}\u{ff1c}\u{ff1e}\u{ff3e}\u{ff3e}\u{ff40}\u{ff40}\u{ff5c}\u{ff5c}\u{ff5e}\u{ff5e}\u{ffe0}\u{ffe6}\u{ffe8}\u{ffee}\u{fffc}\u{fffd}\u{10137}\u{1013f}\u{10179}\u{10189}\u{1018c}\u{1018e}\u{10190}\u{1019c}\u{101a0}\u{101a0}\u{101d0}\u{101fc}\u{10877}\u{10878}\u{10ac8}\u{10ac8}\u{10d8e}\u{10d8f}\u{1173f}\u{1173f}\u{11fd5}\u{11ff1}\u{16b3c}\u{16b3f}\u{16b45}\u{16b45}\u{1bc9c}\u{1bc9c}\u{1cc00}\u{1ccef}\u{1cd00}\u{1ceb3}\u{1cf50}\u{1cfc3}\u{1d000}\u{1d0f5}\u{1d100}\u{1d126}\u{1d129}\u{1d164}\u{1d16a}\u{1d16c}\u{1d183}\u{1d184}\u{1d18c}\u{1d1a9}\u{1d1ae}\u{1d1ea}\u{1d200}\u{1d241}\u{1d245}\u{1d245}\u{1d300}\u{1d356}\u{1d6c1}\u{1d6c1}\u{1d6db}\u{1d6db}\u{1d6fb}\u{1d6fb}\u{1d715}\u{1d715}\u{1d735}\u{1d735}\u{1d74f}\u{1d74f}\u{1d76f}\u{1d76f}\u{1d789}\u{1d789}\u{1d7a9}\u{1d7a9}\u{1d7c3}\u{1d7c3}\u{1d800}\u{1d9ff}\u{1da37}\u{1da3a}\u{1da6d}\u{1da74}\u{1da76}\u{1da83}\u{1da85}\u{1da86}\u{1e14f}\u{1e14f}\u{1e2ff}\u{1e2ff}\u{1ecac}\u{1ecac}\u{1ecb0}\u{1ecb0}\u{1ed2e}\u{1ed2e}\u{1eef0}\u{1eef1}\u{1f000}\u{1f02b}\u{1f030}\u{1f093}\u{1f0a0}\u{1f0ae}\u{1f0b1}\u{1f0bf}\u{1f0c1}\u{1f0cf}\u{1f0d1}\u{1f0f5}\u{1f10d}\u{1f1ad}\u{1f1e6}\u{1f202}\u{1f210}\u{1f23b}\u{1f240}\u{1f248}\u{1f250}\u{1f251}\u{1f260}\u{1f265}\u{1f300}\u{1f6d7}\u{1f6dc}\u{1f6ec}\u{1f6f0}\u{1f6fc}\u{1f700}\u{1f776}\u{1f77b}\u{1f7d9}\u{1f7e0}\u{1f7eb}\u{1f7f0}\u{1f7f0}\u{1f800}\u{1f80b}\u{1f810}\u{1f847}\u{1f850}\u{1f859}\u{1f860}\u{1f887}\u{1f890}\u{1f8ad}\u{1f8b0}\u{1f8bb}\u{1f8c0}\u{1f8c1}\u{1f900}\u{1fa53}\u{1fa60}\u{1fa6d}\u{1fa70}\u{1fa7c}\u{1fa80}\u{1fa89}\u{1fa8f}\u{1fac6}\u{1face}\u{1fadc}\u{1fadf}\u{1fae9}\u{1faf0}\u{1faf8}\u{1fb00}\u{1fb92}\u{1fb94}\u{1fbef} - #|const Z : String = - #| $|\u{20}\u{20}\u{a0}\u{a0}\u{1680}\u{1680}\u{2000}\u{200a}\u{2028}\u{2029}\u{202f}\u{202f}\u{205f}\u{205f}\u{3000}\u{3000} - #|const C : String = - #| $|\u{0}\u{1f}\u{7f}\u{9f}\u{ad}\u{605}\u{61c}\u{61c}\u{6dd}\u{896}\u{8e2}\u{8e2}\u{180e}\u{180e}\u{200b}\u{200f}\u{202a}\u{202e}\u{2060}\u{fffb}\u{110bd}\u{110cf}\u{13430}\u{1343f}\u{1bca0}\u{1cbff}\u{1d173}\u{10fffd} - #|const Cn : String = - #| $|\u{378}\u{379}\u{380}\u{383}\u{38b}\u{38b}\u{38d}\u{38d}\u{3a2}\u{3a2}\u{530}\u{530}\u{557}\u{558}\u{58b}\u{58c}\u{590}\u{590}\u{5c8}\u{5cf}\u{5eb}\u{5ee}\u{5f5}\u{5ff}\u{70e}\u{70e}\u{74b}\u{74c}\u{7b2}\u{7bf}\u{7fb}\u{7fc}\u{82e}\u{82f}\u{83f}\u{83f}\u{85c}\u{85d}\u{85f}\u{85f}\u{86b}\u{86f}\u{88f}\u{88f}\u{892}\u{896}\u{984}\u{984}\u{98d}\u{98e}\u{991}\u{992}\u{9a9}\u{9a9}\u{9b1}\u{9b1}\u{9b3}\u{9b5}\u{9ba}\u{9bb}\u{9c5}\u{9c6}\u{9c9}\u{9ca}\u{9cf}\u{9d6}\u{9d8}\u{9db}\u{9de}\u{9de}\u{9e4}\u{9e5}\u{9ff}\u{a00}\u{a04}\u{a04}\u{a0b}\u{a0e}\u{a11}\u{a12}\u{a29}\u{a29}\u{a31}\u{a31}\u{a34}\u{a34}\u{a37}\u{a37}\u{a3a}\u{a3b}\u{a3d}\u{a3d}\u{a43}\u{a46}\u{a49}\u{a4a}\u{a4e}\u{a50}\u{a52}\u{a58}\u{a5d}\u{a5d}\u{a5f}\u{a65}\u{a77}\u{a80}\u{a84}\u{a84}\u{a8e}\u{a8e}\u{a92}\u{a92}\u{aa9}\u{aa9}\u{ab1}\u{ab1}\u{ab4}\u{ab4}\u{aba}\u{abb}\u{ac6}\u{ac6}\u{aca}\u{aca}\u{ace}\u{acf}\u{ad1}\u{adf}\u{ae4}\u{ae5}\u{af2}\u{af8}\u{b00}\u{b00}\u{b04}\u{b04}\u{b0d}\u{b0e}\u{b11}\u{b12}\u{b29}\u{b29}\u{b31}\u{b31}\u{b34}\u{b34}\u{b3a}\u{b3b}\u{b45}\u{b46}\u{b49}\u{b4a}\u{b4e}\u{b54}\u{b58}\u{b5b}\u{b5e}\u{b5e}\u{b64}\u{b65}\u{b78}\u{b81}\u{b84}\u{b84}\u{b8b}\u{b8d}\u{b91}\u{b91}\u{b96}\u{b98}\u{b9b}\u{b9b}\u{b9d}\u{b9d}\u{ba0}\u{ba2}\u{ba5}\u{ba7}\u{bab}\u{bad}\u{bba}\u{bbd}\u{bc3}\u{bc5}\u{bc9}\u{bc9}\u{bce}\u{bcf}\u{bd1}\u{bd6}\u{bd8}\u{be5}\u{bfb}\u{bff}\u{c0d}\u{c0d}\u{c11}\u{c11}\u{c29}\u{c29}\u{c3a}\u{c3b}\u{c45}\u{c45}\u{c49}\u{c49}\u{c4e}\u{c54}\u{c57}\u{c57}\u{c5b}\u{c5c}\u{c5e}\u{c5f}\u{c64}\u{c65}\u{c70}\u{c76}\u{c8d}\u{c8d}\u{c91}\u{c91}\u{ca9}\u{ca9}\u{cb4}\u{cb4}\u{cba}\u{cbb}\u{cc5}\u{cc5}\u{cc9}\u{cc9}\u{cce}\u{cd4}\u{cd7}\u{cdc}\u{cdf}\u{cdf}\u{ce4}\u{ce5}\u{cf0}\u{cf0}\u{cf4}\u{cff}\u{d0d}\u{d0d}\u{d11}\u{d11}\u{d45}\u{d45}\u{d49}\u{d49}\u{d50}\u{d53}\u{d64}\u{d65}\u{d80}\u{d80}\u{d84}\u{d84}\u{d97}\u{d99}\u{db2}\u{db2}\u{dbc}\u{dbc}\u{dbe}\u{dbf}\u{dc7}\u{dc9}\u{dcb}\u{dce}\u{dd5}\u{dd5}\u{dd7}\u{dd7}\u{de0}\u{de5}\u{df0}\u{df1}\u{df5}\u{e00}\u{e3b}\u{e3e}\u{e5c}\u{e80}\u{e83}\u{e83}\u{e85}\u{e85}\u{e8b}\u{e8b}\u{ea4}\u{ea4}\u{ea6}\u{ea6}\u{ebe}\u{ebf}\u{ec5}\u{ec5}\u{ec7}\u{ec7}\u{ecf}\u{ecf}\u{eda}\u{edb}\u{ee0}\u{eff}\u{f48}\u{f48}\u{f6d}\u{f70}\u{f98}\u{f98}\u{fbd}\u{fbd}\u{fcd}\u{fcd}\u{fdb}\u{fff}\u{10c6}\u{10c6}\u{10c8}\u{10cc}\u{10ce}\u{10cf}\u{1249}\u{1249}\u{124e}\u{124f}\u{1257}\u{1257}\u{1259}\u{1259}\u{125e}\u{125f}\u{1289}\u{1289}\u{128e}\u{128f}\u{12b1}\u{12b1}\u{12b6}\u{12b7}\u{12bf}\u{12bf}\u{12c1}\u{12c1}\u{12c6}\u{12c7}\u{12d7}\u{12d7}\u{1311}\u{1311}\u{1316}\u{1317}\u{135b}\u{135c}\u{137d}\u{137f}\u{139a}\u{139f}\u{13f6}\u{13f7}\u{13fe}\u{13ff}\u{169d}\u{169f}\u{16f9}\u{16ff}\u{1716}\u{171e}\u{1737}\u{173f}\u{1754}\u{175f}\u{176d}\u{176d}\u{1771}\u{1771}\u{1774}\u{177f}\u{17de}\u{17df}\u{17ea}\u{17ef}\u{17fa}\u{17ff}\u{181a}\u{181f}\u{1879}\u{187f}\u{18ab}\u{18af}\u{18f6}\u{18ff}\u{191f}\u{191f}\u{192c}\u{192f}\u{193c}\u{193f}\u{1941}\u{1943}\u{196e}\u{196f}\u{1975}\u{197f}\u{19ac}\u{19af}\u{19ca}\u{19cf}\u{19db}\u{19dd}\u{1a1c}\u{1a1d}\u{1a5f}\u{1a5f}\u{1a7d}\u{1a7e}\u{1a8a}\u{1a8f}\u{1a9a}\u{1a9f}\u{1aae}\u{1aaf}\u{1acf}\u{1aff}\u{1b4d}\u{1b4d}\u{1bf4}\u{1bfb}\u{1c38}\u{1c3a}\u{1c4a}\u{1c4c}\u{1c8b}\u{1c8f}\u{1cbb}\u{1cbc}\u{1cc8}\u{1ccf}\u{1cfb}\u{1cff}\u{1f16}\u{1f17}\u{1f1e}\u{1f1f}\u{1f46}\u{1f47}\u{1f4e}\u{1f4f}\u{1f58}\u{1f58}\u{1f5a}\u{1f5a}\u{1f5c}\u{1f5c}\u{1f5e}\u{1f5e}\u{1f7e}\u{1f7f}\u{1fb5}\u{1fb5}\u{1fc5}\u{1fc5}\u{1fd4}\u{1fd5}\u{1fdc}\u{1fdc}\u{1ff0}\u{1ff1}\u{1ff5}\u{1ff5}\u{1fff}\u{1fff}\u{2065}\u{2065}\u{2072}\u{2073}\u{208f}\u{208f}\u{209d}\u{209f}\u{20c1}\u{20cf}\u{20f1}\u{20ff}\u{218c}\u{218f}\u{242a}\u{243f}\u{244b}\u{245f}\u{2b74}\u{2b75}\u{2b96}\u{2b96}\u{2cf4}\u{2cf8}\u{2d26}\u{2d26}\u{2d28}\u{2d2c}\u{2d2e}\u{2d2f}\u{2d68}\u{2d6e}\u{2d71}\u{2d7e}\u{2d97}\u{2d9f}\u{2da7}\u{2da7}\u{2daf}\u{2daf}\u{2db7}\u{2db7}\u{2dbf}\u{2dbf}\u{2dc7}\u{2dc7}\u{2dcf}\u{2dcf}\u{2dd7}\u{2dd7}\u{2ddf}\u{2ddf}\u{2e5e}\u{2e7f}\u{2e9a}\u{2e9a}\u{2ef4}\u{2eff}\u{2fd6}\u{2fef}\u{3040}\u{3040}\u{3097}\u{3098}\u{3100}\u{3104}\u{3130}\u{3130}\u{318f}\u{318f}\u{31e6}\u{31ee}\u{321f}\u{321f}\u{a48d}\u{a48f}\u{a4c7}\u{a4cf}\u{a62c}\u{a63f}\u{a6f8}\u{a6ff}\u{a7ce}\u{a7cf}\u{a7d2}\u{a7d2}\u{a7d4}\u{a7d4}\u{a7dd}\u{a7f1}\u{a82d}\u{a82f}\u{a83a}\u{a83f}\u{a878}\u{a87f}\u{a8c6}\u{a8cd}\u{a8da}\u{a8df}\u{a954}\u{a95e}\u{a97d}\u{a97f}\u{a9ce}\u{a9ce}\u{a9da}\u{a9dd}\u{a9ff}\u{a9ff}\u{aa37}\u{aa3f}\u{aa4e}\u{aa4f}\u{aa5a}\u{aa5b}\u{aac3}\u{aada}\u{aaf7}\u{ab00}\u{ab07}\u{ab08}\u{ab0f}\u{ab10}\u{ab17}\u{ab1f}\u{ab27}\u{ab27}\u{ab2f}\u{ab2f}\u{ab6c}\u{ab6f}\u{abee}\u{abef}\u{abfa}\u{abff}\u{d7a4}\u{d7af}\u{d7c7}\u{d7ca}\u{d7fc}\u{d7ff}\u{fa6e}\u{fa6f}\u{fada}\u{faff}\u{fb07}\u{fb12}\u{fb18}\u{fb1c}\u{fb37}\u{fb37}\u{fb3d}\u{fb3d}\u{fb3f}\u{fb3f}\u{fb42}\u{fb42}\u{fb45}\u{fb45}\u{fbc3}\u{fbd2}\u{fd90}\u{fd91}\u{fdc8}\u{fdce}\u{fdd0}\u{fdef}\u{fe1a}\u{fe1f}\u{fe53}\u{fe53}\u{fe67}\u{fe67}\u{fe6c}\u{fe6f}\u{fe75}\u{fe75}\u{fefd}\u{fefe}\u{ff00}\u{ff00}\u{ffbf}\u{ffc1}\u{ffc8}\u{ffc9}\u{ffd0}\u{ffd1}\u{ffd8}\u{ffd9}\u{ffdd}\u{ffdf}\u{ffe7}\u{ffe7}\u{ffef}\u{fff8}\u{fffe}\u{ffff}\u{1000c}\u{1000c}\u{10027}\u{10027}\u{1003b}\u{1003b}\u{1003e}\u{1003e}\u{1004e}\u{1004f}\u{1005e}\u{1007f}\u{100fb}\u{100ff}\u{10103}\u{10106}\u{10134}\u{10136}\u{1018f}\u{1018f}\u{1019d}\u{1019f}\u{101a1}\u{101cf}\u{101fe}\u{1027f}\u{1029d}\u{1029f}\u{102d1}\u{102df}\u{102fc}\u{102ff}\u{10324}\u{1032c}\u{1034b}\u{1034f}\u{1037b}\u{1037f}\u{1039e}\u{1039e}\u{103c4}\u{103c7}\u{103d6}\u{103ff}\u{1049e}\u{1049f}\u{104aa}\u{104af}\u{104d4}\u{104d7}\u{104fc}\u{104ff}\u{10528}\u{1052f}\u{10564}\u{1056e}\u{1057b}\u{1057b}\u{1058b}\u{1058b}\u{10593}\u{10593}\u{10596}\u{10596}\u{105a2}\u{105a2}\u{105b2}\u{105b2}\u{105ba}\u{105ba}\u{105bd}\u{105bf}\u{105f4}\u{105ff}\u{10737}\u{1073f}\u{10756}\u{1075f}\u{10768}\u{1077f}\u{10786}\u{10786}\u{107b1}\u{107b1}\u{107bb}\u{107ff}\u{10806}\u{10807}\u{10809}\u{10809}\u{10836}\u{10836}\u{10839}\u{1083b}\u{1083d}\u{1083e}\u{10856}\u{10856}\u{1089f}\u{108a6}\u{108b0}\u{108df}\u{108f3}\u{108f3}\u{108f6}\u{108fa}\u{1091c}\u{1091e}\u{1093a}\u{1093e}\u{10940}\u{1097f}\u{109b8}\u{109bb}\u{109d0}\u{109d1}\u{10a04}\u{10a04}\u{10a07}\u{10a0b}\u{10a14}\u{10a14}\u{10a18}\u{10a18}\u{10a36}\u{10a37}\u{10a3b}\u{10a3e}\u{10a49}\u{10a4f}\u{10a59}\u{10a5f}\u{10aa0}\u{10abf}\u{10ae7}\u{10aea}\u{10af7}\u{10aff}\u{10b36}\u{10b38}\u{10b56}\u{10b57}\u{10b73}\u{10b77}\u{10b92}\u{10b98}\u{10b9d}\u{10ba8}\u{10bb0}\u{10bff}\u{10c49}\u{10c7f}\u{10cb3}\u{10cbf}\u{10cf3}\u{10cf9}\u{10d28}\u{10d2f}\u{10d3a}\u{10d3f}\u{10d66}\u{10d68}\u{10d86}\u{10d8d}\u{10d90}\u{10e5f}\u{10e7f}\u{10e7f}\u{10eaa}\u{10eaa}\u{10eae}\u{10eaf}\u{10eb2}\u{10ec1}\u{10ec5}\u{10efb}\u{10f28}\u{10f2f}\u{10f5a}\u{10f6f}\u{10f8a}\u{10faf}\u{10fcc}\u{10fdf}\u{10ff7}\u{10fff}\u{1104e}\u{11051}\u{11076}\u{1107e}\u{110c3}\u{110cc}\u{110ce}\u{110cf}\u{110e9}\u{110ef}\u{110fa}\u{110ff}\u{11135}\u{11135}\u{11148}\u{1114f}\u{11177}\u{1117f}\u{111e0}\u{111e0}\u{111f5}\u{111ff}\u{11212}\u{11212}\u{11242}\u{1127f}\u{11287}\u{11287}\u{11289}\u{11289}\u{1128e}\u{1128e}\u{1129e}\u{1129e}\u{112aa}\u{112af}\u{112eb}\u{112ef}\u{112fa}\u{112ff}\u{11304}\u{11304}\u{1130d}\u{1130e}\u{11311}\u{11312}\u{11329}\u{11329}\u{11331}\u{11331}\u{11334}\u{11334}\u{1133a}\u{1133a}\u{11345}\u{11346}\u{11349}\u{1134a}\u{1134e}\u{1134f}\u{11351}\u{11356}\u{11358}\u{1135c}\u{11364}\u{11365}\u{1136d}\u{1136f}\u{11375}\u{1137f}\u{1138a}\u{1138a}\u{1138c}\u{1138d}\u{1138f}\u{1138f}\u{113b6}\u{113b6}\u{113c1}\u{113c1}\u{113c3}\u{113c4}\u{113c6}\u{113c6}\u{113cb}\u{113cb}\u{113d6}\u{113d6}\u{113d9}\u{113e0}\u{113e3}\u{113ff}\u{1145c}\u{1145c}\u{11462}\u{1147f}\u{114c8}\u{114cf}\u{114da}\u{1157f}\u{115b6}\u{115b7}\u{115de}\u{115ff}\u{11645}\u{1164f}\u{1165a}\u{1165f}\u{1166d}\u{1167f}\u{116ba}\u{116bf}\u{116ca}\u{116cf}\u{116e4}\u{116ff}\u{1171b}\u{1171c}\u{1172c}\u{1172f}\u{11747}\u{117ff}\u{1183c}\u{1189f}\u{118f3}\u{118fe}\u{11907}\u{11908}\u{1190a}\u{1190b}\u{11914}\u{11914}\u{11917}\u{11917}\u{11936}\u{11936}\u{11939}\u{1193a}\u{11947}\u{1194f}\u{1195a}\u{1199f}\u{119a8}\u{119a9}\u{119d8}\u{119d9}\u{119e5}\u{119ff}\u{11a48}\u{11a4f}\u{11aa3}\u{11aaf}\u{11af9}\u{11aff}\u{11b0a}\u{11bbf}\u{11be2}\u{11bef}\u{11bfa}\u{11bff}\u{11c09}\u{11c09}\u{11c37}\u{11c37}\u{11c46}\u{11c4f}\u{11c6d}\u{11c6f}\u{11c90}\u{11c91}\u{11ca8}\u{11ca8}\u{11cb7}\u{11cff}\u{11d07}\u{11d07}\u{11d0a}\u{11d0a}\u{11d37}\u{11d39}\u{11d3b}\u{11d3b}\u{11d3e}\u{11d3e}\u{11d48}\u{11d4f}\u{11d5a}\u{11d5f}\u{11d66}\u{11d66}\u{11d69}\u{11d69}\u{11d8f}\u{11d8f}\u{11d92}\u{11d92}\u{11d99}\u{11d9f}\u{11daa}\u{11edf}\u{11ef9}\u{11eff}\u{11f11}\u{11f11}\u{11f3b}\u{11f3d}\u{11f5b}\u{11faf}\u{11fb1}\u{11fbf}\u{11ff2}\u{11ffe}\u{1239a}\u{123ff}\u{1246f}\u{1246f}\u{12475}\u{1247f}\u{12544}\u{12f8f}\u{12ff3}\u{12fff}\u{13456}\u{1345f}\u{143fb}\u{143ff}\u{14647}\u{160ff}\u{1613a}\u{167ff}\u{16a39}\u{16a3f}\u{16a5f}\u{16a5f}\u{16a6a}\u{16a6d}\u{16abf}\u{16abf}\u{16aca}\u{16acf}\u{16aee}\u{16aef}\u{16af6}\u{16aff}\u{16b46}\u{16b4f}\u{16b5a}\u{16b5a}\u{16b62}\u{16b62}\u{16b78}\u{16b7c}\u{16b90}\u{16d3f}\u{16d7a}\u{16e3f}\u{16e9b}\u{16eff}\u{16f4b}\u{16f4e}\u{16f88}\u{16f8e}\u{16fa0}\u{16fdf}\u{16fe5}\u{16fef}\u{16ff2}\u{16fff}\u{187f8}\u{187ff}\u{18cd6}\u{18cfe}\u{18d09}\u{1afef}\u{1aff4}\u{1aff4}\u{1affc}\u{1affc}\u{1afff}\u{1afff}\u{1b123}\u{1b131}\u{1b133}\u{1b14f}\u{1b153}\u{1b154}\u{1b156}\u{1b163}\u{1b168}\u{1b16f}\u{1b2fc}\u{1bbff}\u{1bc6b}\u{1bc6f}\u{1bc7d}\u{1bc7f}\u{1bc89}\u{1bc8f}\u{1bc9a}\u{1bc9b}\u{1bca4}\u{1cbff}\u{1ccfa}\u{1ccff}\u{1ceb4}\u{1ceff}\u{1cf2e}\u{1cf2f}\u{1cf47}\u{1cf4f}\u{1cfc4}\u{1cfff}\u{1d0f6}\u{1d0ff}\u{1d127}\u{1d128}\u{1d1eb}\u{1d1ff}\u{1d246}\u{1d2bf}\u{1d2d4}\u{1d2df}\u{1d2f4}\u{1d2ff}\u{1d357}\u{1d35f}\u{1d379}\u{1d3ff}\u{1d455}\u{1d455}\u{1d49d}\u{1d49d}\u{1d4a0}\u{1d4a1}\u{1d4a3}\u{1d4a4}\u{1d4a7}\u{1d4a8}\u{1d4ad}\u{1d4ad}\u{1d4ba}\u{1d4ba}\u{1d4bc}\u{1d4bc}\u{1d4c4}\u{1d4c4}\u{1d506}\u{1d506}\u{1d50b}\u{1d50c}\u{1d515}\u{1d515}\u{1d51d}\u{1d51d}\u{1d53a}\u{1d53a}\u{1d53f}\u{1d53f}\u{1d545}\u{1d545}\u{1d547}\u{1d549}\u{1d551}\u{1d551}\u{1d6a6}\u{1d6a7}\u{1d7cc}\u{1d7cd}\u{1da8c}\u{1da9a}\u{1daa0}\u{1daa0}\u{1dab0}\u{1deff}\u{1df1f}\u{1df24}\u{1df2b}\u{1dfff}\u{1e007}\u{1e007}\u{1e019}\u{1e01a}\u{1e022}\u{1e022}\u{1e025}\u{1e025}\u{1e02b}\u{1e02f}\u{1e06e}\u{1e08e}\u{1e090}\u{1e0ff}\u{1e12d}\u{1e12f}\u{1e13e}\u{1e13f}\u{1e14a}\u{1e14d}\u{1e150}\u{1e28f}\u{1e2af}\u{1e2bf}\u{1e2fa}\u{1e2fe}\u{1e300}\u{1e4cf}\u{1e4fa}\u{1e5cf}\u{1e5fb}\u{1e5fe}\u{1e600}\u{1e7df}\u{1e7e7}\u{1e7e7}\u{1e7ec}\u{1e7ec}\u{1e7ef}\u{1e7ef}\u{1e7ff}\u{1e7ff}\u{1e8c5}\u{1e8c6}\u{1e8d7}\u{1e8ff}\u{1e94c}\u{1e94f}\u{1e95a}\u{1e95d}\u{1e960}\u{1ec70}\u{1ecb5}\u{1ed00}\u{1ed3e}\u{1edff}\u{1ee04}\u{1ee04}\u{1ee20}\u{1ee20}\u{1ee23}\u{1ee23}\u{1ee25}\u{1ee26}\u{1ee28}\u{1ee28}\u{1ee33}\u{1ee33}\u{1ee38}\u{1ee38}\u{1ee3a}\u{1ee3a}\u{1ee3c}\u{1ee41}\u{1ee43}\u{1ee46}\u{1ee48}\u{1ee48}\u{1ee4a}\u{1ee4a}\u{1ee4c}\u{1ee4c}\u{1ee50}\u{1ee50}\u{1ee53}\u{1ee53}\u{1ee55}\u{1ee56}\u{1ee58}\u{1ee58}\u{1ee5a}\u{1ee5a}\u{1ee5c}\u{1ee5c}\u{1ee5e}\u{1ee5e}\u{1ee60}\u{1ee60}\u{1ee63}\u{1ee63}\u{1ee65}\u{1ee66}\u{1ee6b}\u{1ee6b}\u{1ee73}\u{1ee73}\u{1ee78}\u{1ee78}\u{1ee7d}\u{1ee7d}\u{1ee7f}\u{1ee7f}\u{1ee8a}\u{1ee8a}\u{1ee9c}\u{1eea0}\u{1eea4}\u{1eea4}\u{1eeaa}\u{1eeaa}\u{1eebc}\u{1eeef}\u{1eef2}\u{1efff}\u{1f02c}\u{1f02f}\u{1f094}\u{1f09f}\u{1f0af}\u{1f0b0}\u{1f0c0}\u{1f0c0}\u{1f0d0}\u{1f0d0}\u{1f0f6}\u{1f0ff}\u{1f1ae}\u{1f1e5}\u{1f203}\u{1f20f}\u{1f23c}\u{1f23f}\u{1f249}\u{1f24f}\u{1f252}\u{1f25f}\u{1f266}\u{1f2ff}\u{1f6d8}\u{1f6db}\u{1f6ed}\u{1f6ef}\u{1f6fd}\u{1f6ff}\u{1f777}\u{1f77a}\u{1f7da}\u{1f7df}\u{1f7ec}\u{1f7ef}\u{1f7f1}\u{1f7ff}\u{1f80c}\u{1f80f}\u{1f848}\u{1f84f}\u{1f85a}\u{1f85f}\u{1f888}\u{1f88f}\u{1f8ae}\u{1f8af}\u{1f8bc}\u{1f8bf}\u{1f8c2}\u{1f8ff}\u{1fa54}\u{1fa5f}\u{1fa6e}\u{1fa6f}\u{1fa7d}\u{1fa7f}\u{1fa8a}\u{1fa8e}\u{1fac7}\u{1facd}\u{1fadd}\u{1fade}\u{1faea}\u{1faef}\u{1faf9}\u{1faff}\u{1fb93}\u{1fb93}\u{1fbfa}\u{1ffff}\u{2a6e0}\u{2a6ff}\u{2b73a}\u{2b73f}\u{2b81e}\u{2b81f}\u{2cea2}\u{2ceaf}\u{2ebe1}\u{2ebef}\u{2ee5e}\u{2f7ff}\u{2fa1e}\u{2ffff}\u{3134b}\u{3134f}\u{323b0}\u{e0000}\u{e0002}\u{e001f}\u{e0080}\u{e00ff}\u{e01f0}\u{effff}\u{ffffe}\u{fffff} - #|const Cc : String = - #| $|\u{0}\u{1f}\u{7f}\u{9f} - #|const Zs : String = - #| $|\u{20}\u{20}\u{a0}\u{a0}\u{1680}\u{1680}\u{2000}\u{200a}\u{202f}\u{202f}\u{205f}\u{205f}\u{3000}\u{3000} - #|const Po : String = - #| $|\u{21}\u{23}\u{25}\u{27}\u{2a}\u{2a}\u{2c}\u{2c}\u{2e}\u{2f}\u{3a}\u{3b}\u{3f}\u{40}\u{5c}\u{5c}\u{a1}\u{a1}\u{a7}\u{a7}\u{b6}\u{b7}\u{bf}\u{bf}\u{37e}\u{37e}\u{387}\u{387}\u{55a}\u{55f}\u{589}\u{589}\u{5c0}\u{5c0}\u{5c3}\u{5c3}\u{5c6}\u{5c6}\u{5f3}\u{5f4}\u{609}\u{60a}\u{60c}\u{60d}\u{61b}\u{61b}\u{61d}\u{61f}\u{66a}\u{66d}\u{6d4}\u{6d4}\u{700}\u{70d}\u{7f7}\u{7f9}\u{830}\u{83e}\u{85e}\u{85e}\u{964}\u{965}\u{970}\u{970}\u{9fd}\u{9fd}\u{a76}\u{a76}\u{af0}\u{af0}\u{c77}\u{c77}\u{c84}\u{c84}\u{df4}\u{df4}\u{e4f}\u{e4f}\u{e5a}\u{e5b}\u{f04}\u{f12}\u{f14}\u{f14}\u{f85}\u{f85}\u{fd0}\u{fd4}\u{fd9}\u{fda}\u{104a}\u{104f}\u{10fb}\u{10fb}\u{1360}\u{1368}\u{166e}\u{166e}\u{16eb}\u{16ed}\u{1735}\u{1736}\u{17d4}\u{17d6}\u{17d8}\u{17da}\u{1800}\u{1805}\u{1807}\u{180a}\u{1944}\u{1945}\u{1a1e}\u{1a1f}\u{1aa0}\u{1aa6}\u{1aa8}\u{1aad}\u{1b4e}\u{1b4f}\u{1b5a}\u{1b60}\u{1b7d}\u{1b7f}\u{1bfc}\u{1bff}\u{1c3b}\u{1c3f}\u{1c7e}\u{1c7f}\u{1cc0}\u{1cc7}\u{1cd3}\u{1cd3}\u{2016}\u{2017}\u{2020}\u{2027}\u{2030}\u{2038}\u{203b}\u{203e}\u{2041}\u{2043}\u{2047}\u{2051}\u{2053}\u{2053}\u{2055}\u{205e}\u{2cf9}\u{2cfc}\u{2cfe}\u{2cff}\u{2d70}\u{2d70}\u{2e00}\u{2e01}\u{2e06}\u{2e08}\u{2e0b}\u{2e0b}\u{2e0e}\u{2e16}\u{2e18}\u{2e19}\u{2e1b}\u{2e1b}\u{2e1e}\u{2e1f}\u{2e2a}\u{2e2e}\u{2e30}\u{2e39}\u{2e3c}\u{2e3f}\u{2e41}\u{2e41}\u{2e43}\u{2e4f}\u{2e52}\u{2e54}\u{3001}\u{3003}\u{303d}\u{303d}\u{30fb}\u{30fb}\u{a4fe}\u{a4ff}\u{a60d}\u{a60f}\u{a673}\u{a673}\u{a67e}\u{a67e}\u{a6f2}\u{a6f7}\u{a874}\u{a877}\u{a8ce}\u{a8cf}\u{a8f8}\u{a8fa}\u{a8fc}\u{a8fc}\u{a92e}\u{a92f}\u{a95f}\u{a95f}\u{a9c1}\u{a9cd}\u{a9de}\u{a9df}\u{aa5c}\u{aa5f}\u{aade}\u{aadf}\u{aaf0}\u{aaf1}\u{abeb}\u{abeb}\u{fe10}\u{fe16}\u{fe19}\u{fe19}\u{fe30}\u{fe30}\u{fe45}\u{fe46}\u{fe49}\u{fe4c}\u{fe50}\u{fe52}\u{fe54}\u{fe57}\u{fe5f}\u{fe61}\u{fe68}\u{fe68}\u{fe6a}\u{fe6b}\u{ff01}\u{ff03}\u{ff05}\u{ff07}\u{ff0a}\u{ff0a}\u{ff0c}\u{ff0c}\u{ff0e}\u{ff0f}\u{ff1a}\u{ff1b}\u{ff1f}\u{ff20}\u{ff3c}\u{ff3c}\u{ff61}\u{ff61}\u{ff64}\u{ff65}\u{10100}\u{10102}\u{1039f}\u{1039f}\u{103d0}\u{103d0}\u{1056f}\u{1056f}\u{10857}\u{10857}\u{1091f}\u{1091f}\u{1093f}\u{1093f}\u{10a50}\u{10a58}\u{10a7f}\u{10a7f}\u{10af0}\u{10af6}\u{10b39}\u{10b3f}\u{10b99}\u{10b9c}\u{10f55}\u{10f59}\u{10f86}\u{10f89}\u{11047}\u{1104d}\u{110bb}\u{110bc}\u{110be}\u{110c1}\u{11140}\u{11143}\u{11174}\u{11175}\u{111c5}\u{111c8}\u{111cd}\u{111cd}\u{111db}\u{111db}\u{111dd}\u{111df}\u{11238}\u{1123d}\u{112a9}\u{112a9}\u{113d4}\u{113d5}\u{113d7}\u{113d8}\u{1144b}\u{1144f}\u{1145a}\u{1145b}\u{1145d}\u{1145d}\u{114c6}\u{114c6}\u{115c1}\u{115d7}\u{11641}\u{11643}\u{11660}\u{1166c}\u{116b9}\u{116b9}\u{1173c}\u{1173e}\u{1183b}\u{1183b}\u{11944}\u{11946}\u{119e2}\u{119e2}\u{11a3f}\u{11a46}\u{11a9a}\u{11a9c}\u{11a9e}\u{11aa2}\u{11b00}\u{11b09}\u{11be1}\u{11be1}\u{11c41}\u{11c45}\u{11c70}\u{11c71}\u{11ef7}\u{11ef8}\u{11f43}\u{11f4f}\u{11fff}\u{11fff}\u{12470}\u{12474}\u{12ff1}\u{12ff2}\u{16a6e}\u{16a6f}\u{16af5}\u{16af5}\u{16b37}\u{16b3b}\u{16b44}\u{16b44}\u{16d6d}\u{16d6f}\u{16e97}\u{16e9a}\u{16fe2}\u{16fe2}\u{1bc9f}\u{1bc9f}\u{1da87}\u{1da8b}\u{1e5ff}\u{1e5ff}\u{1e95e}\u{1e95f} - #|const Sc : String = - #| $|\u{24}\u{24}\u{a2}\u{a5}\u{58f}\u{58f}\u{60b}\u{60b}\u{7fe}\u{7ff}\u{9f2}\u{9f3}\u{9fb}\u{9fb}\u{af1}\u{af1}\u{bf9}\u{bf9}\u{e3f}\u{e3f}\u{17db}\u{17db}\u{20a0}\u{20c0}\u{a838}\u{a838}\u{fdfc}\u{fdfc}\u{fe69}\u{fe69}\u{ff04}\u{ff04}\u{ffe0}\u{ffe1}\u{ffe5}\u{ffe6}\u{11fdd}\u{11fe0}\u{1e2ff}\u{1e2ff}\u{1ecb0}\u{1ecb0} - #|const Ps : String = - #| $|\u{28}\u{28}\u{5b}\u{5b}\u{7b}\u{7b}\u{f3a}\u{f3a}\u{f3c}\u{f3c}\u{169b}\u{169b}\u{201a}\u{201a}\u{201e}\u{201e}\u{2045}\u{2045}\u{207d}\u{207d}\u{208d}\u{208d}\u{2308}\u{2308}\u{230a}\u{230a}\u{2329}\u{2329}\u{2768}\u{2768}\u{276a}\u{276a}\u{276c}\u{276c}\u{276e}\u{276e}\u{2770}\u{2770}\u{2772}\u{2772}\u{2774}\u{2774}\u{27c5}\u{27c5}\u{27e6}\u{27e6}\u{27e8}\u{27e8}\u{27ea}\u{27ea}\u{27ec}\u{27ec}\u{27ee}\u{27ee}\u{2983}\u{2983}\u{2985}\u{2985}\u{2987}\u{2987}\u{2989}\u{2989}\u{298b}\u{298b}\u{298d}\u{298d}\u{298f}\u{298f}\u{2991}\u{2991}\u{2993}\u{2993}\u{2995}\u{2995}\u{2997}\u{2997}\u{29d8}\u{29d8}\u{29da}\u{29da}\u{29fc}\u{29fc}\u{2e22}\u{2e22}\u{2e24}\u{2e24}\u{2e26}\u{2e26}\u{2e28}\u{2e28}\u{2e42}\u{2e42}\u{2e55}\u{2e55}\u{2e57}\u{2e57}\u{2e59}\u{2e59}\u{2e5b}\u{2e5b}\u{3008}\u{3008}\u{300a}\u{300a}\u{300c}\u{300c}\u{300e}\u{300e}\u{3010}\u{3010}\u{3014}\u{3014}\u{3016}\u{3016}\u{3018}\u{3018}\u{301a}\u{301a}\u{301d}\u{301d}\u{fd3f}\u{fd3f}\u{fe17}\u{fe17}\u{fe35}\u{fe35}\u{fe37}\u{fe37}\u{fe39}\u{fe39}\u{fe3b}\u{fe3b}\u{fe3d}\u{fe3d}\u{fe3f}\u{fe3f}\u{fe41}\u{fe41}\u{fe43}\u{fe43}\u{fe47}\u{fe47}\u{fe59}\u{fe59}\u{fe5b}\u{fe5b}\u{fe5d}\u{fe5d}\u{ff08}\u{ff08}\u{ff3b}\u{ff3b}\u{ff5b}\u{ff5b}\u{ff5f}\u{ff5f}\u{ff62}\u{ff62} - #|const Pe : String = - #| $|\u{29}\u{29}\u{5d}\u{5d}\u{7d}\u{7d}\u{f3b}\u{f3b}\u{f3d}\u{f3d}\u{169c}\u{169c}\u{2046}\u{2046}\u{207e}\u{207e}\u{208e}\u{208e}\u{2309}\u{2309}\u{230b}\u{230b}\u{232a}\u{232a}\u{2769}\u{2769}\u{276b}\u{276b}\u{276d}\u{276d}\u{276f}\u{276f}\u{2771}\u{2771}\u{2773}\u{2773}\u{2775}\u{2775}\u{27c6}\u{27c6}\u{27e7}\u{27e7}\u{27e9}\u{27e9}\u{27eb}\u{27eb}\u{27ed}\u{27ed}\u{27ef}\u{27ef}\u{2984}\u{2984}\u{2986}\u{2986}\u{2988}\u{2988}\u{298a}\u{298a}\u{298c}\u{298c}\u{298e}\u{298e}\u{2990}\u{2990}\u{2992}\u{2992}\u{2994}\u{2994}\u{2996}\u{2996}\u{2998}\u{2998}\u{29d9}\u{29d9}\u{29db}\u{29db}\u{29fd}\u{29fd}\u{2e23}\u{2e23}\u{2e25}\u{2e25}\u{2e27}\u{2e27}\u{2e29}\u{2e29}\u{2e56}\u{2e56}\u{2e58}\u{2e58}\u{2e5a}\u{2e5a}\u{2e5c}\u{2e5c}\u{3009}\u{3009}\u{300b}\u{300b}\u{300d}\u{300d}\u{300f}\u{300f}\u{3011}\u{3011}\u{3015}\u{3015}\u{3017}\u{3017}\u{3019}\u{3019}\u{301b}\u{301b}\u{301e}\u{301f}\u{fd3e}\u{fd3e}\u{fe18}\u{fe18}\u{fe36}\u{fe36}\u{fe38}\u{fe38}\u{fe3a}\u{fe3a}\u{fe3c}\u{fe3c}\u{fe3e}\u{fe3e}\u{fe40}\u{fe40}\u{fe42}\u{fe42}\u{fe44}\u{fe44}\u{fe48}\u{fe48}\u{fe5a}\u{fe5a}\u{fe5c}\u{fe5c}\u{fe5e}\u{fe5e}\u{ff09}\u{ff09}\u{ff3d}\u{ff3d}\u{ff5d}\u{ff5d}\u{ff60}\u{ff60}\u{ff63}\u{ff63} - #|const Sm : String = - #| $|\u{2b}\u{2b}\u{3c}\u{3e}\u{7c}\u{7c}\u{7e}\u{7e}\u{ac}\u{ac}\u{b1}\u{b1}\u{d7}\u{d7}\u{f7}\u{f7}\u{3f6}\u{3f6}\u{606}\u{608}\u{2044}\u{2044}\u{2052}\u{2052}\u{207a}\u{207c}\u{208a}\u{208c}\u{2118}\u{2118}\u{2140}\u{2144}\u{214b}\u{214b}\u{2190}\u{2194}\u{219a}\u{219b}\u{21a0}\u{21a0}\u{21a3}\u{21a3}\u{21a6}\u{21a6}\u{21ae}\u{21ae}\u{21ce}\u{21cf}\u{21d2}\u{21d2}\u{21d4}\u{21d4}\u{21f4}\u{22ff}\u{2320}\u{2321}\u{237c}\u{237c}\u{239b}\u{23b3}\u{23dc}\u{23e1}\u{25b7}\u{25b7}\u{25c1}\u{25c1}\u{25f8}\u{25ff}\u{266f}\u{266f}\u{27c0}\u{27c4}\u{27c7}\u{27e5}\u{27f0}\u{27ff}\u{2900}\u{2982}\u{2999}\u{29d7}\u{29dc}\u{29fb}\u{29fe}\u{2aff}\u{2b30}\u{2b44}\u{2b47}\u{2b4c}\u{fb29}\u{fb29}\u{fe62}\u{fe62}\u{fe64}\u{fe66}\u{ff0b}\u{ff0b}\u{ff1c}\u{ff1e}\u{ff5c}\u{ff5c}\u{ff5e}\u{ff5e}\u{ffe2}\u{ffe2}\u{ffe9}\u{ffec}\u{10d8e}\u{10d8f}\u{1d6c1}\u{1d6c1}\u{1d6db}\u{1d6db}\u{1d6fb}\u{1d6fb}\u{1d715}\u{1d715}\u{1d735}\u{1d735}\u{1d74f}\u{1d74f}\u{1d76f}\u{1d76f}\u{1d789}\u{1d789}\u{1d7a9}\u{1d7a9}\u{1d7c3}\u{1d7c3}\u{1eef0}\u{1eef1} - #|const Pd : String = - #| $|\u{2d}\u{2d}\u{58a}\u{58a}\u{5be}\u{5be}\u{1400}\u{1400}\u{1806}\u{1806}\u{2010}\u{2015}\u{2e17}\u{2e17}\u{2e1a}\u{2e1a}\u{2e3a}\u{2e3b}\u{2e40}\u{2e40}\u{2e5d}\u{2e5d}\u{301c}\u{301c}\u{3030}\u{3030}\u{30a0}\u{30a0}\u{fe31}\u{fe32}\u{fe58}\u{fe58}\u{fe63}\u{fe63}\u{ff0d}\u{ff0d}\u{10d6e}\u{10d6e}\u{10ead}\u{10ead} - #|const Nd : String = - #| $|\u{30}\u{39}\u{660}\u{669}\u{6f0}\u{6f9}\u{7c0}\u{7c9}\u{966}\u{96f}\u{9e6}\u{9ef}\u{a66}\u{a6f}\u{ae6}\u{aef}\u{b66}\u{b6f}\u{be6}\u{bef}\u{c66}\u{c6f}\u{ce6}\u{cef}\u{d66}\u{d6f}\u{de6}\u{def}\u{e50}\u{e59}\u{ed0}\u{ed9}\u{f20}\u{f29}\u{1040}\u{1049}\u{1090}\u{1099}\u{17e0}\u{17e9}\u{1810}\u{1819}\u{1946}\u{194f}\u{19d0}\u{19d9}\u{1a80}\u{1a89}\u{1a90}\u{1a99}\u{1b50}\u{1b59}\u{1bb0}\u{1bb9}\u{1c40}\u{1c49}\u{1c50}\u{1c59}\u{a620}\u{a629}\u{a8d0}\u{a8d9}\u{a900}\u{a909}\u{a9d0}\u{a9d9}\u{a9f0}\u{a9f9}\u{aa50}\u{aa59}\u{abf0}\u{abf9}\u{ff10}\u{ff19}\u{104a0}\u{104a9}\u{10d30}\u{10d39}\u{10d40}\u{10d49}\u{11066}\u{1106f}\u{110f0}\u{110f9}\u{11136}\u{1113f}\u{111d0}\u{111d9}\u{112f0}\u{112f9}\u{11450}\u{11459}\u{114d0}\u{114d9}\u{11650}\u{11659}\u{116c0}\u{116c9}\u{116d0}\u{116e3}\u{11730}\u{11739}\u{118e0}\u{118e9}\u{11950}\u{11959}\u{11bf0}\u{11bf9}\u{11c50}\u{11c59}\u{11d50}\u{11d59}\u{11da0}\u{11da9}\u{11f50}\u{11f59}\u{16130}\u{16139}\u{16a60}\u{16a69}\u{16ac0}\u{16ac9}\u{16b50}\u{16b59}\u{16d70}\u{16d79}\u{1ccf0}\u{1ccf9}\u{1d7ce}\u{1d7ff}\u{1e140}\u{1e149}\u{1e2f0}\u{1e2f9}\u{1e4f0}\u{1e4f9}\u{1e5f1}\u{1e5fa}\u{1e950}\u{1e959}\u{1fbf0}\u{1fbf9} - #|const Lu : String = - #| $|\u{41}\u{5a}\u{c0}\u{d6}\u{d8}\u{de}\u{100}\u{100}\u{102}\u{102}\u{104}\u{104}\u{106}\u{106}\u{108}\u{108}\u{10a}\u{10a}\u{10c}\u{10c}\u{10e}\u{10e}\u{110}\u{110}\u{112}\u{112}\u{114}\u{114}\u{116}\u{116}\u{118}\u{118}\u{11a}\u{11a}\u{11c}\u{11c}\u{11e}\u{11e}\u{120}\u{120}\u{122}\u{122}\u{124}\u{124}\u{126}\u{126}\u{128}\u{128}\u{12a}\u{12a}\u{12c}\u{12c}\u{12e}\u{12e}\u{130}\u{130}\u{132}\u{132}\u{134}\u{134}\u{136}\u{136}\u{139}\u{139}\u{13b}\u{13b}\u{13d}\u{13d}\u{13f}\u{13f}\u{141}\u{141}\u{143}\u{143}\u{145}\u{145}\u{147}\u{147}\u{14a}\u{14a}\u{14c}\u{14c}\u{14e}\u{14e}\u{150}\u{150}\u{152}\u{152}\u{154}\u{154}\u{156}\u{156}\u{158}\u{158}\u{15a}\u{15a}\u{15c}\u{15c}\u{15e}\u{15e}\u{160}\u{160}\u{162}\u{162}\u{164}\u{164}\u{166}\u{166}\u{168}\u{168}\u{16a}\u{16a}\u{16c}\u{16c}\u{16e}\u{16e}\u{170}\u{170}\u{172}\u{172}\u{174}\u{174}\u{176}\u{176}\u{178}\u{179}\u{17b}\u{17b}\u{17d}\u{17d}\u{181}\u{182}\u{184}\u{184}\u{186}\u{187}\u{189}\u{18b}\u{18e}\u{191}\u{193}\u{194}\u{196}\u{198}\u{19c}\u{19d}\u{19f}\u{1a0}\u{1a2}\u{1a2}\u{1a4}\u{1a4}\u{1a6}\u{1a7}\u{1a9}\u{1a9}\u{1ac}\u{1ac}\u{1ae}\u{1af}\u{1b1}\u{1b3}\u{1b5}\u{1b5}\u{1b7}\u{1b8}\u{1bc}\u{1bc}\u{1c4}\u{1c4}\u{1c7}\u{1c7}\u{1ca}\u{1ca}\u{1cd}\u{1cd}\u{1cf}\u{1cf}\u{1d1}\u{1d1}\u{1d3}\u{1d3}\u{1d5}\u{1d5}\u{1d7}\u{1d7}\u{1d9}\u{1d9}\u{1db}\u{1db}\u{1de}\u{1de}\u{1e0}\u{1e0}\u{1e2}\u{1e2}\u{1e4}\u{1e4}\u{1e6}\u{1e6}\u{1e8}\u{1e8}\u{1ea}\u{1ea}\u{1ec}\u{1ec}\u{1ee}\u{1ee}\u{1f1}\u{1f1}\u{1f4}\u{1f4}\u{1f6}\u{1f8}\u{1fa}\u{1fa}\u{1fc}\u{1fc}\u{1fe}\u{1fe}\u{200}\u{200}\u{202}\u{202}\u{204}\u{204}\u{206}\u{206}\u{208}\u{208}\u{20a}\u{20a}\u{20c}\u{20c}\u{20e}\u{20e}\u{210}\u{210}\u{212}\u{212}\u{214}\u{214}\u{216}\u{216}\u{218}\u{218}\u{21a}\u{21a}\u{21c}\u{21c}\u{21e}\u{21e}\u{220}\u{220}\u{222}\u{222}\u{224}\u{224}\u{226}\u{226}\u{228}\u{228}\u{22a}\u{22a}\u{22c}\u{22c}\u{22e}\u{22e}\u{230}\u{230}\u{232}\u{232}\u{23a}\u{23b}\u{23d}\u{23e}\u{241}\u{241}\u{243}\u{246}\u{248}\u{248}\u{24a}\u{24a}\u{24c}\u{24c}\u{24e}\u{24e}\u{370}\u{370}\u{372}\u{372}\u{376}\u{376}\u{37f}\u{37f}\u{386}\u{386}\u{388}\u{38a}\u{38c}\u{38c}\u{38e}\u{38f}\u{391}\u{3a1}\u{3a3}\u{3ab}\u{3cf}\u{3cf}\u{3d2}\u{3d4}\u{3d8}\u{3d8}\u{3da}\u{3da}\u{3dc}\u{3dc}\u{3de}\u{3de}\u{3e0}\u{3e0}\u{3e2}\u{3e2}\u{3e4}\u{3e4}\u{3e6}\u{3e6}\u{3e8}\u{3e8}\u{3ea}\u{3ea}\u{3ec}\u{3ec}\u{3ee}\u{3ee}\u{3f4}\u{3f4}\u{3f7}\u{3f7}\u{3f9}\u{3fa}\u{3fd}\u{42f}\u{460}\u{460}\u{462}\u{462}\u{464}\u{464}\u{466}\u{466}\u{468}\u{468}\u{46a}\u{46a}\u{46c}\u{46c}\u{46e}\u{46e}\u{470}\u{470}\u{472}\u{472}\u{474}\u{474}\u{476}\u{476}\u{478}\u{478}\u{47a}\u{47a}\u{47c}\u{47c}\u{47e}\u{47e}\u{480}\u{480}\u{48a}\u{48a}\u{48c}\u{48c}\u{48e}\u{48e}\u{490}\u{490}\u{492}\u{492}\u{494}\u{494}\u{496}\u{496}\u{498}\u{498}\u{49a}\u{49a}\u{49c}\u{49c}\u{49e}\u{49e}\u{4a0}\u{4a0}\u{4a2}\u{4a2}\u{4a4}\u{4a4}\u{4a6}\u{4a6}\u{4a8}\u{4a8}\u{4aa}\u{4aa}\u{4ac}\u{4ac}\u{4ae}\u{4ae}\u{4b0}\u{4b0}\u{4b2}\u{4b2}\u{4b4}\u{4b4}\u{4b6}\u{4b6}\u{4b8}\u{4b8}\u{4ba}\u{4ba}\u{4bc}\u{4bc}\u{4be}\u{4be}\u{4c0}\u{4c1}\u{4c3}\u{4c3}\u{4c5}\u{4c5}\u{4c7}\u{4c7}\u{4c9}\u{4c9}\u{4cb}\u{4cb}\u{4cd}\u{4cd}\u{4d0}\u{4d0}\u{4d2}\u{4d2}\u{4d4}\u{4d4}\u{4d6}\u{4d6}\u{4d8}\u{4d8}\u{4da}\u{4da}\u{4dc}\u{4dc}\u{4de}\u{4de}\u{4e0}\u{4e0}\u{4e2}\u{4e2}\u{4e4}\u{4e4}\u{4e6}\u{4e6}\u{4e8}\u{4e8}\u{4ea}\u{4ea}\u{4ec}\u{4ec}\u{4ee}\u{4ee}\u{4f0}\u{4f0}\u{4f2}\u{4f2}\u{4f4}\u{4f4}\u{4f6}\u{4f6}\u{4f8}\u{4f8}\u{4fa}\u{4fa}\u{4fc}\u{4fc}\u{4fe}\u{4fe}\u{500}\u{500}\u{502}\u{502}\u{504}\u{504}\u{506}\u{506}\u{508}\u{508}\u{50a}\u{50a}\u{50c}\u{50c}\u{50e}\u{50e}\u{510}\u{510}\u{512}\u{512}\u{514}\u{514}\u{516}\u{516}\u{518}\u{518}\u{51a}\u{51a}\u{51c}\u{51c}\u{51e}\u{51e}\u{520}\u{520}\u{522}\u{522}\u{524}\u{524}\u{526}\u{526}\u{528}\u{528}\u{52a}\u{52a}\u{52c}\u{52c}\u{52e}\u{52e}\u{531}\u{556}\u{10a0}\u{10c5}\u{10c7}\u{10c7}\u{10cd}\u{10cd}\u{13a0}\u{13f5}\u{1c89}\u{1c89}\u{1c90}\u{1cba}\u{1cbd}\u{1cbf}\u{1e00}\u{1e00}\u{1e02}\u{1e02}\u{1e04}\u{1e04}\u{1e06}\u{1e06}\u{1e08}\u{1e08}\u{1e0a}\u{1e0a}\u{1e0c}\u{1e0c}\u{1e0e}\u{1e0e}\u{1e10}\u{1e10}\u{1e12}\u{1e12}\u{1e14}\u{1e14}\u{1e16}\u{1e16}\u{1e18}\u{1e18}\u{1e1a}\u{1e1a}\u{1e1c}\u{1e1c}\u{1e1e}\u{1e1e}\u{1e20}\u{1e20}\u{1e22}\u{1e22}\u{1e24}\u{1e24}\u{1e26}\u{1e26}\u{1e28}\u{1e28}\u{1e2a}\u{1e2a}\u{1e2c}\u{1e2c}\u{1e2e}\u{1e2e}\u{1e30}\u{1e30}\u{1e32}\u{1e32}\u{1e34}\u{1e34}\u{1e36}\u{1e36}\u{1e38}\u{1e38}\u{1e3a}\u{1e3a}\u{1e3c}\u{1e3c}\u{1e3e}\u{1e3e}\u{1e40}\u{1e40}\u{1e42}\u{1e42}\u{1e44}\u{1e44}\u{1e46}\u{1e46}\u{1e48}\u{1e48}\u{1e4a}\u{1e4a}\u{1e4c}\u{1e4c}\u{1e4e}\u{1e4e}\u{1e50}\u{1e50}\u{1e52}\u{1e52}\u{1e54}\u{1e54}\u{1e56}\u{1e56}\u{1e58}\u{1e58}\u{1e5a}\u{1e5a}\u{1e5c}\u{1e5c}\u{1e5e}\u{1e5e}\u{1e60}\u{1e60}\u{1e62}\u{1e62}\u{1e64}\u{1e64}\u{1e66}\u{1e66}\u{1e68}\u{1e68}\u{1e6a}\u{1e6a}\u{1e6c}\u{1e6c}\u{1e6e}\u{1e6e}\u{1e70}\u{1e70}\u{1e72}\u{1e72}\u{1e74}\u{1e74}\u{1e76}\u{1e76}\u{1e78}\u{1e78}\u{1e7a}\u{1e7a}\u{1e7c}\u{1e7c}\u{1e7e}\u{1e7e}\u{1e80}\u{1e80}\u{1e82}\u{1e82}\u{1e84}\u{1e84}\u{1e86}\u{1e86}\u{1e88}\u{1e88}\u{1e8a}\u{1e8a}\u{1e8c}\u{1e8c}\u{1e8e}\u{1e8e}\u{1e90}\u{1e90}\u{1e92}\u{1e92}\u{1e94}\u{1e94}\u{1e9e}\u{1e9e}\u{1ea0}\u{1ea0}\u{1ea2}\u{1ea2}\u{1ea4}\u{1ea4}\u{1ea6}\u{1ea6}\u{1ea8}\u{1ea8}\u{1eaa}\u{1eaa}\u{1eac}\u{1eac}\u{1eae}\u{1eae}\u{1eb0}\u{1eb0}\u{1eb2}\u{1eb2}\u{1eb4}\u{1eb4}\u{1eb6}\u{1eb6}\u{1eb8}\u{1eb8}\u{1eba}\u{1eba}\u{1ebc}\u{1ebc}\u{1ebe}\u{1ebe}\u{1ec0}\u{1ec0}\u{1ec2}\u{1ec2}\u{1ec4}\u{1ec4}\u{1ec6}\u{1ec6}\u{1ec8}\u{1ec8}\u{1eca}\u{1eca}\u{1ecc}\u{1ecc}\u{1ece}\u{1ece}\u{1ed0}\u{1ed0}\u{1ed2}\u{1ed2}\u{1ed4}\u{1ed4}\u{1ed6}\u{1ed6}\u{1ed8}\u{1ed8}\u{1eda}\u{1eda}\u{1edc}\u{1edc}\u{1ede}\u{1ede}\u{1ee0}\u{1ee0}\u{1ee2}\u{1ee2}\u{1ee4}\u{1ee4}\u{1ee6}\u{1ee6}\u{1ee8}\u{1ee8}\u{1eea}\u{1eea}\u{1eec}\u{1eec}\u{1eee}\u{1eee}\u{1ef0}\u{1ef0}\u{1ef2}\u{1ef2}\u{1ef4}\u{1ef4}\u{1ef6}\u{1ef6}\u{1ef8}\u{1ef8}\u{1efa}\u{1efa}\u{1efc}\u{1efc}\u{1efe}\u{1efe}\u{1f08}\u{1f0f}\u{1f18}\u{1f1d}\u{1f28}\u{1f2f}\u{1f38}\u{1f3f}\u{1f48}\u{1f4d}\u{1f59}\u{1f59}\u{1f5b}\u{1f5b}\u{1f5d}\u{1f5d}\u{1f5f}\u{1f5f}\u{1f68}\u{1f6f}\u{1fb8}\u{1fbb}\u{1fc8}\u{1fcb}\u{1fd8}\u{1fdb}\u{1fe8}\u{1fec}\u{1ff8}\u{1ffb}\u{2102}\u{2102}\u{2107}\u{2107}\u{210b}\u{210d}\u{2110}\u{2112}\u{2115}\u{2115}\u{2119}\u{211d}\u{2124}\u{2124}\u{2126}\u{2126}\u{2128}\u{2128}\u{212a}\u{212d}\u{2130}\u{2133}\u{213e}\u{213f}\u{2145}\u{2145}\u{2183}\u{2183}\u{2c00}\u{2c2f}\u{2c60}\u{2c60}\u{2c62}\u{2c64}\u{2c67}\u{2c67}\u{2c69}\u{2c69}\u{2c6b}\u{2c6b}\u{2c6d}\u{2c70}\u{2c72}\u{2c72}\u{2c75}\u{2c75}\u{2c7e}\u{2c80}\u{2c82}\u{2c82}\u{2c84}\u{2c84}\u{2c86}\u{2c86}\u{2c88}\u{2c88}\u{2c8a}\u{2c8a}\u{2c8c}\u{2c8c}\u{2c8e}\u{2c8e}\u{2c90}\u{2c90}\u{2c92}\u{2c92}\u{2c94}\u{2c94}\u{2c96}\u{2c96}\u{2c98}\u{2c98}\u{2c9a}\u{2c9a}\u{2c9c}\u{2c9c}\u{2c9e}\u{2c9e}\u{2ca0}\u{2ca0}\u{2ca2}\u{2ca2}\u{2ca4}\u{2ca4}\u{2ca6}\u{2ca6}\u{2ca8}\u{2ca8}\u{2caa}\u{2caa}\u{2cac}\u{2cac}\u{2cae}\u{2cae}\u{2cb0}\u{2cb0}\u{2cb2}\u{2cb2}\u{2cb4}\u{2cb4}\u{2cb6}\u{2cb6}\u{2cb8}\u{2cb8}\u{2cba}\u{2cba}\u{2cbc}\u{2cbc}\u{2cbe}\u{2cbe}\u{2cc0}\u{2cc0}\u{2cc2}\u{2cc2}\u{2cc4}\u{2cc4}\u{2cc6}\u{2cc6}\u{2cc8}\u{2cc8}\u{2cca}\u{2cca}\u{2ccc}\u{2ccc}\u{2cce}\u{2cce}\u{2cd0}\u{2cd0}\u{2cd2}\u{2cd2}\u{2cd4}\u{2cd4}\u{2cd6}\u{2cd6}\u{2cd8}\u{2cd8}\u{2cda}\u{2cda}\u{2cdc}\u{2cdc}\u{2cde}\u{2cde}\u{2ce0}\u{2ce0}\u{2ce2}\u{2ce2}\u{2ceb}\u{2ceb}\u{2ced}\u{2ced}\u{2cf2}\u{2cf2}\u{a640}\u{a640}\u{a642}\u{a642}\u{a644}\u{a644}\u{a646}\u{a646}\u{a648}\u{a648}\u{a64a}\u{a64a}\u{a64c}\u{a64c}\u{a64e}\u{a64e}\u{a650}\u{a650}\u{a652}\u{a652}\u{a654}\u{a654}\u{a656}\u{a656}\u{a658}\u{a658}\u{a65a}\u{a65a}\u{a65c}\u{a65c}\u{a65e}\u{a65e}\u{a660}\u{a660}\u{a662}\u{a662}\u{a664}\u{a664}\u{a666}\u{a666}\u{a668}\u{a668}\u{a66a}\u{a66a}\u{a66c}\u{a66c}\u{a680}\u{a680}\u{a682}\u{a682}\u{a684}\u{a684}\u{a686}\u{a686}\u{a688}\u{a688}\u{a68a}\u{a68a}\u{a68c}\u{a68c}\u{a68e}\u{a68e}\u{a690}\u{a690}\u{a692}\u{a692}\u{a694}\u{a694}\u{a696}\u{a696}\u{a698}\u{a698}\u{a69a}\u{a69a}\u{a722}\u{a722}\u{a724}\u{a724}\u{a726}\u{a726}\u{a728}\u{a728}\u{a72a}\u{a72a}\u{a72c}\u{a72c}\u{a72e}\u{a72e}\u{a732}\u{a732}\u{a734}\u{a734}\u{a736}\u{a736}\u{a738}\u{a738}\u{a73a}\u{a73a}\u{a73c}\u{a73c}\u{a73e}\u{a73e}\u{a740}\u{a740}\u{a742}\u{a742}\u{a744}\u{a744}\u{a746}\u{a746}\u{a748}\u{a748}\u{a74a}\u{a74a}\u{a74c}\u{a74c}\u{a74e}\u{a74e}\u{a750}\u{a750}\u{a752}\u{a752}\u{a754}\u{a754}\u{a756}\u{a756}\u{a758}\u{a758}\u{a75a}\u{a75a}\u{a75c}\u{a75c}\u{a75e}\u{a75e}\u{a760}\u{a760}\u{a762}\u{a762}\u{a764}\u{a764}\u{a766}\u{a766}\u{a768}\u{a768}\u{a76a}\u{a76a}\u{a76c}\u{a76c}\u{a76e}\u{a76e}\u{a779}\u{a779}\u{a77b}\u{a77b}\u{a77d}\u{a77e}\u{a780}\u{a780}\u{a782}\u{a782}\u{a784}\u{a784}\u{a786}\u{a786}\u{a78b}\u{a78b}\u{a78d}\u{a78d}\u{a790}\u{a790}\u{a792}\u{a792}\u{a796}\u{a796}\u{a798}\u{a798}\u{a79a}\u{a79a}\u{a79c}\u{a79c}\u{a79e}\u{a79e}\u{a7a0}\u{a7a0}\u{a7a2}\u{a7a2}\u{a7a4}\u{a7a4}\u{a7a6}\u{a7a6}\u{a7a8}\u{a7a8}\u{a7aa}\u{a7ae}\u{a7b0}\u{a7b4}\u{a7b6}\u{a7b6}\u{a7b8}\u{a7b8}\u{a7ba}\u{a7ba}\u{a7bc}\u{a7bc}\u{a7be}\u{a7be}\u{a7c0}\u{a7c0}\u{a7c2}\u{a7c2}\u{a7c4}\u{a7c7}\u{a7c9}\u{a7c9}\u{a7cb}\u{a7cc}\u{a7d0}\u{a7d0}\u{a7d6}\u{a7d6}\u{a7d8}\u{a7d8}\u{a7da}\u{a7da}\u{a7dc}\u{a7dc}\u{a7f5}\u{a7f5}\u{ff21}\u{ff3a}\u{10400}\u{10427}\u{104b0}\u{104d3}\u{10570}\u{1057a}\u{1057c}\u{1058a}\u{1058c}\u{10592}\u{10594}\u{10595}\u{10c80}\u{10cb2}\u{10d50}\u{10d65}\u{118a0}\u{118bf}\u{16e40}\u{16e5f}\u{1d400}\u{1d419}\u{1d434}\u{1d44d}\u{1d468}\u{1d481}\u{1d49c}\u{1d49c}\u{1d49e}\u{1d49f}\u{1d4a2}\u{1d4a2}\u{1d4a5}\u{1d4a6}\u{1d4a9}\u{1d4ac}\u{1d4ae}\u{1d4b5}\u{1d4d0}\u{1d4e9}\u{1d504}\u{1d505}\u{1d507}\u{1d50a}\u{1d50d}\u{1d514}\u{1d516}\u{1d51c}\u{1d538}\u{1d539}\u{1d53b}\u{1d53e}\u{1d540}\u{1d544}\u{1d546}\u{1d546}\u{1d54a}\u{1d550}\u{1d56c}\u{1d585}\u{1d5a0}\u{1d5b9}\u{1d5d4}\u{1d5ed}\u{1d608}\u{1d621}\u{1d63c}\u{1d655}\u{1d670}\u{1d689}\u{1d6a8}\u{1d6c0}\u{1d6e2}\u{1d6fa}\u{1d71c}\u{1d734}\u{1d756}\u{1d76e}\u{1d790}\u{1d7a8}\u{1d7ca}\u{1d7ca}\u{1e900}\u{1e921} - #|const Sk : String = - #| $|\u{5e}\u{5e}\u{60}\u{60}\u{a8}\u{a8}\u{af}\u{af}\u{b4}\u{b4}\u{b8}\u{b8}\u{2c2}\u{2c5}\u{2d2}\u{2df}\u{2e5}\u{2eb}\u{2ed}\u{2ed}\u{2ef}\u{2ff}\u{375}\u{375}\u{384}\u{385}\u{888}\u{888}\u{1fbd}\u{1fbd}\u{1fbf}\u{1fc1}\u{1fcd}\u{1fcf}\u{1fdd}\u{1fdf}\u{1fed}\u{1fef}\u{1ffd}\u{1ffe}\u{309b}\u{309c}\u{a700}\u{a716}\u{a720}\u{a721}\u{a789}\u{a78a}\u{ab5b}\u{ab5b}\u{ab6a}\u{ab6b}\u{fbb2}\u{fbc2}\u{ff3e}\u{ff3e}\u{ff40}\u{ff40}\u{ffe3}\u{ffe3}\u{1f3fb}\u{1f3ff} - #|const Pc : String = - #| $|\u{5f}\u{5f}\u{203f}\u{2040}\u{2054}\u{2054}\u{fe33}\u{fe34}\u{fe4d}\u{fe4f}\u{ff3f}\u{ff3f} - #|const Ll : String = - #| $|\u{61}\u{7a}\u{b5}\u{b5}\u{df}\u{f6}\u{f8}\u{ff}\u{101}\u{101}\u{103}\u{103}\u{105}\u{105}\u{107}\u{107}\u{109}\u{109}\u{10b}\u{10b}\u{10d}\u{10d}\u{10f}\u{10f}\u{111}\u{111}\u{113}\u{113}\u{115}\u{115}\u{117}\u{117}\u{119}\u{119}\u{11b}\u{11b}\u{11d}\u{11d}\u{11f}\u{11f}\u{121}\u{121}\u{123}\u{123}\u{125}\u{125}\u{127}\u{127}\u{129}\u{129}\u{12b}\u{12b}\u{12d}\u{12d}\u{12f}\u{12f}\u{131}\u{131}\u{133}\u{133}\u{135}\u{135}\u{137}\u{138}\u{13a}\u{13a}\u{13c}\u{13c}\u{13e}\u{13e}\u{140}\u{140}\u{142}\u{142}\u{144}\u{144}\u{146}\u{146}\u{148}\u{149}\u{14b}\u{14b}\u{14d}\u{14d}\u{14f}\u{14f}\u{151}\u{151}\u{153}\u{153}\u{155}\u{155}\u{157}\u{157}\u{159}\u{159}\u{15b}\u{15b}\u{15d}\u{15d}\u{15f}\u{15f}\u{161}\u{161}\u{163}\u{163}\u{165}\u{165}\u{167}\u{167}\u{169}\u{169}\u{16b}\u{16b}\u{16d}\u{16d}\u{16f}\u{16f}\u{171}\u{171}\u{173}\u{173}\u{175}\u{175}\u{177}\u{177}\u{17a}\u{17a}\u{17c}\u{17c}\u{17e}\u{180}\u{183}\u{183}\u{185}\u{185}\u{188}\u{188}\u{18c}\u{18d}\u{192}\u{192}\u{195}\u{195}\u{199}\u{19b}\u{19e}\u{19e}\u{1a1}\u{1a1}\u{1a3}\u{1a3}\u{1a5}\u{1a5}\u{1a8}\u{1a8}\u{1aa}\u{1ab}\u{1ad}\u{1ad}\u{1b0}\u{1b0}\u{1b4}\u{1b4}\u{1b6}\u{1b6}\u{1b9}\u{1ba}\u{1bd}\u{1bf}\u{1c6}\u{1c6}\u{1c9}\u{1c9}\u{1cc}\u{1cc}\u{1ce}\u{1ce}\u{1d0}\u{1d0}\u{1d2}\u{1d2}\u{1d4}\u{1d4}\u{1d6}\u{1d6}\u{1d8}\u{1d8}\u{1da}\u{1da}\u{1dc}\u{1dd}\u{1df}\u{1df}\u{1e1}\u{1e1}\u{1e3}\u{1e3}\u{1e5}\u{1e5}\u{1e7}\u{1e7}\u{1e9}\u{1e9}\u{1eb}\u{1eb}\u{1ed}\u{1ed}\u{1ef}\u{1f0}\u{1f3}\u{1f3}\u{1f5}\u{1f5}\u{1f9}\u{1f9}\u{1fb}\u{1fb}\u{1fd}\u{1fd}\u{1ff}\u{1ff}\u{201}\u{201}\u{203}\u{203}\u{205}\u{205}\u{207}\u{207}\u{209}\u{209}\u{20b}\u{20b}\u{20d}\u{20d}\u{20f}\u{20f}\u{211}\u{211}\u{213}\u{213}\u{215}\u{215}\u{217}\u{217}\u{219}\u{219}\u{21b}\u{21b}\u{21d}\u{21d}\u{21f}\u{21f}\u{221}\u{221}\u{223}\u{223}\u{225}\u{225}\u{227}\u{227}\u{229}\u{229}\u{22b}\u{22b}\u{22d}\u{22d}\u{22f}\u{22f}\u{231}\u{231}\u{233}\u{239}\u{23c}\u{23c}\u{23f}\u{240}\u{242}\u{242}\u{247}\u{247}\u{249}\u{249}\u{24b}\u{24b}\u{24d}\u{24d}\u{24f}\u{293}\u{295}\u{2af}\u{371}\u{371}\u{373}\u{373}\u{377}\u{377}\u{37b}\u{37d}\u{390}\u{390}\u{3ac}\u{3ce}\u{3d0}\u{3d1}\u{3d5}\u{3d7}\u{3d9}\u{3d9}\u{3db}\u{3db}\u{3dd}\u{3dd}\u{3df}\u{3df}\u{3e1}\u{3e1}\u{3e3}\u{3e3}\u{3e5}\u{3e5}\u{3e7}\u{3e7}\u{3e9}\u{3e9}\u{3eb}\u{3eb}\u{3ed}\u{3ed}\u{3ef}\u{3f3}\u{3f5}\u{3f5}\u{3f8}\u{3f8}\u{3fb}\u{3fc}\u{430}\u{45f}\u{461}\u{461}\u{463}\u{463}\u{465}\u{465}\u{467}\u{467}\u{469}\u{469}\u{46b}\u{46b}\u{46d}\u{46d}\u{46f}\u{46f}\u{471}\u{471}\u{473}\u{473}\u{475}\u{475}\u{477}\u{477}\u{479}\u{479}\u{47b}\u{47b}\u{47d}\u{47d}\u{47f}\u{47f}\u{481}\u{481}\u{48b}\u{48b}\u{48d}\u{48d}\u{48f}\u{48f}\u{491}\u{491}\u{493}\u{493}\u{495}\u{495}\u{497}\u{497}\u{499}\u{499}\u{49b}\u{49b}\u{49d}\u{49d}\u{49f}\u{49f}\u{4a1}\u{4a1}\u{4a3}\u{4a3}\u{4a5}\u{4a5}\u{4a7}\u{4a7}\u{4a9}\u{4a9}\u{4ab}\u{4ab}\u{4ad}\u{4ad}\u{4af}\u{4af}\u{4b1}\u{4b1}\u{4b3}\u{4b3}\u{4b5}\u{4b5}\u{4b7}\u{4b7}\u{4b9}\u{4b9}\u{4bb}\u{4bb}\u{4bd}\u{4bd}\u{4bf}\u{4bf}\u{4c2}\u{4c2}\u{4c4}\u{4c4}\u{4c6}\u{4c6}\u{4c8}\u{4c8}\u{4ca}\u{4ca}\u{4cc}\u{4cc}\u{4ce}\u{4cf}\u{4d1}\u{4d1}\u{4d3}\u{4d3}\u{4d5}\u{4d5}\u{4d7}\u{4d7}\u{4d9}\u{4d9}\u{4db}\u{4db}\u{4dd}\u{4dd}\u{4df}\u{4df}\u{4e1}\u{4e1}\u{4e3}\u{4e3}\u{4e5}\u{4e5}\u{4e7}\u{4e7}\u{4e9}\u{4e9}\u{4eb}\u{4eb}\u{4ed}\u{4ed}\u{4ef}\u{4ef}\u{4f1}\u{4f1}\u{4f3}\u{4f3}\u{4f5}\u{4f5}\u{4f7}\u{4f7}\u{4f9}\u{4f9}\u{4fb}\u{4fb}\u{4fd}\u{4fd}\u{4ff}\u{4ff}\u{501}\u{501}\u{503}\u{503}\u{505}\u{505}\u{507}\u{507}\u{509}\u{509}\u{50b}\u{50b}\u{50d}\u{50d}\u{50f}\u{50f}\u{511}\u{511}\u{513}\u{513}\u{515}\u{515}\u{517}\u{517}\u{519}\u{519}\u{51b}\u{51b}\u{51d}\u{51d}\u{51f}\u{51f}\u{521}\u{521}\u{523}\u{523}\u{525}\u{525}\u{527}\u{527}\u{529}\u{529}\u{52b}\u{52b}\u{52d}\u{52d}\u{52f}\u{52f}\u{560}\u{588}\u{10d0}\u{10fa}\u{10fd}\u{10ff}\u{13f8}\u{13fd}\u{1c80}\u{1c88}\u{1c8a}\u{1c8a}\u{1d00}\u{1d2b}\u{1d6b}\u{1d77}\u{1d79}\u{1d9a}\u{1e01}\u{1e01}\u{1e03}\u{1e03}\u{1e05}\u{1e05}\u{1e07}\u{1e07}\u{1e09}\u{1e09}\u{1e0b}\u{1e0b}\u{1e0d}\u{1e0d}\u{1e0f}\u{1e0f}\u{1e11}\u{1e11}\u{1e13}\u{1e13}\u{1e15}\u{1e15}\u{1e17}\u{1e17}\u{1e19}\u{1e19}\u{1e1b}\u{1e1b}\u{1e1d}\u{1e1d}\u{1e1f}\u{1e1f}\u{1e21}\u{1e21}\u{1e23}\u{1e23}\u{1e25}\u{1e25}\u{1e27}\u{1e27}\u{1e29}\u{1e29}\u{1e2b}\u{1e2b}\u{1e2d}\u{1e2d}\u{1e2f}\u{1e2f}\u{1e31}\u{1e31}\u{1e33}\u{1e33}\u{1e35}\u{1e35}\u{1e37}\u{1e37}\u{1e39}\u{1e39}\u{1e3b}\u{1e3b}\u{1e3d}\u{1e3d}\u{1e3f}\u{1e3f}\u{1e41}\u{1e41}\u{1e43}\u{1e43}\u{1e45}\u{1e45}\u{1e47}\u{1e47}\u{1e49}\u{1e49}\u{1e4b}\u{1e4b}\u{1e4d}\u{1e4d}\u{1e4f}\u{1e4f}\u{1e51}\u{1e51}\u{1e53}\u{1e53}\u{1e55}\u{1e55}\u{1e57}\u{1e57}\u{1e59}\u{1e59}\u{1e5b}\u{1e5b}\u{1e5d}\u{1e5d}\u{1e5f}\u{1e5f}\u{1e61}\u{1e61}\u{1e63}\u{1e63}\u{1e65}\u{1e65}\u{1e67}\u{1e67}\u{1e69}\u{1e69}\u{1e6b}\u{1e6b}\u{1e6d}\u{1e6d}\u{1e6f}\u{1e6f}\u{1e71}\u{1e71}\u{1e73}\u{1e73}\u{1e75}\u{1e75}\u{1e77}\u{1e77}\u{1e79}\u{1e79}\u{1e7b}\u{1e7b}\u{1e7d}\u{1e7d}\u{1e7f}\u{1e7f}\u{1e81}\u{1e81}\u{1e83}\u{1e83}\u{1e85}\u{1e85}\u{1e87}\u{1e87}\u{1e89}\u{1e89}\u{1e8b}\u{1e8b}\u{1e8d}\u{1e8d}\u{1e8f}\u{1e8f}\u{1e91}\u{1e91}\u{1e93}\u{1e93}\u{1e95}\u{1e9d}\u{1e9f}\u{1e9f}\u{1ea1}\u{1ea1}\u{1ea3}\u{1ea3}\u{1ea5}\u{1ea5}\u{1ea7}\u{1ea7}\u{1ea9}\u{1ea9}\u{1eab}\u{1eab}\u{1ead}\u{1ead}\u{1eaf}\u{1eaf}\u{1eb1}\u{1eb1}\u{1eb3}\u{1eb3}\u{1eb5}\u{1eb5}\u{1eb7}\u{1eb7}\u{1eb9}\u{1eb9}\u{1ebb}\u{1ebb}\u{1ebd}\u{1ebd}\u{1ebf}\u{1ebf}\u{1ec1}\u{1ec1}\u{1ec3}\u{1ec3}\u{1ec5}\u{1ec5}\u{1ec7}\u{1ec7}\u{1ec9}\u{1ec9}\u{1ecb}\u{1ecb}\u{1ecd}\u{1ecd}\u{1ecf}\u{1ecf}\u{1ed1}\u{1ed1}\u{1ed3}\u{1ed3}\u{1ed5}\u{1ed5}\u{1ed7}\u{1ed7}\u{1ed9}\u{1ed9}\u{1edb}\u{1edb}\u{1edd}\u{1edd}\u{1edf}\u{1edf}\u{1ee1}\u{1ee1}\u{1ee3}\u{1ee3}\u{1ee5}\u{1ee5}\u{1ee7}\u{1ee7}\u{1ee9}\u{1ee9}\u{1eeb}\u{1eeb}\u{1eed}\u{1eed}\u{1eef}\u{1eef}\u{1ef1}\u{1ef1}\u{1ef3}\u{1ef3}\u{1ef5}\u{1ef5}\u{1ef7}\u{1ef7}\u{1ef9}\u{1ef9}\u{1efb}\u{1efb}\u{1efd}\u{1efd}\u{1eff}\u{1f07}\u{1f10}\u{1f15}\u{1f20}\u{1f27}\u{1f30}\u{1f37}\u{1f40}\u{1f45}\u{1f50}\u{1f57}\u{1f60}\u{1f67}\u{1f70}\u{1f7d}\u{1f80}\u{1f87}\u{1f90}\u{1f97}\u{1fa0}\u{1fa7}\u{1fb0}\u{1fb4}\u{1fb6}\u{1fb7}\u{1fbe}\u{1fbe}\u{1fc2}\u{1fc4}\u{1fc6}\u{1fc7}\u{1fd0}\u{1fd3}\u{1fd6}\u{1fd7}\u{1fe0}\u{1fe7}\u{1ff2}\u{1ff4}\u{1ff6}\u{1ff7}\u{210a}\u{210a}\u{210e}\u{210f}\u{2113}\u{2113}\u{212f}\u{212f}\u{2134}\u{2134}\u{2139}\u{2139}\u{213c}\u{213d}\u{2146}\u{2149}\u{214e}\u{214e}\u{2184}\u{2184}\u{2c30}\u{2c5f}\u{2c61}\u{2c61}\u{2c65}\u{2c66}\u{2c68}\u{2c68}\u{2c6a}\u{2c6a}\u{2c6c}\u{2c6c}\u{2c71}\u{2c71}\u{2c73}\u{2c74}\u{2c76}\u{2c7b}\u{2c81}\u{2c81}\u{2c83}\u{2c83}\u{2c85}\u{2c85}\u{2c87}\u{2c87}\u{2c89}\u{2c89}\u{2c8b}\u{2c8b}\u{2c8d}\u{2c8d}\u{2c8f}\u{2c8f}\u{2c91}\u{2c91}\u{2c93}\u{2c93}\u{2c95}\u{2c95}\u{2c97}\u{2c97}\u{2c99}\u{2c99}\u{2c9b}\u{2c9b}\u{2c9d}\u{2c9d}\u{2c9f}\u{2c9f}\u{2ca1}\u{2ca1}\u{2ca3}\u{2ca3}\u{2ca5}\u{2ca5}\u{2ca7}\u{2ca7}\u{2ca9}\u{2ca9}\u{2cab}\u{2cab}\u{2cad}\u{2cad}\u{2caf}\u{2caf}\u{2cb1}\u{2cb1}\u{2cb3}\u{2cb3}\u{2cb5}\u{2cb5}\u{2cb7}\u{2cb7}\u{2cb9}\u{2cb9}\u{2cbb}\u{2cbb}\u{2cbd}\u{2cbd}\u{2cbf}\u{2cbf}\u{2cc1}\u{2cc1}\u{2cc3}\u{2cc3}\u{2cc5}\u{2cc5}\u{2cc7}\u{2cc7}\u{2cc9}\u{2cc9}\u{2ccb}\u{2ccb}\u{2ccd}\u{2ccd}\u{2ccf}\u{2ccf}\u{2cd1}\u{2cd1}\u{2cd3}\u{2cd3}\u{2cd5}\u{2cd5}\u{2cd7}\u{2cd7}\u{2cd9}\u{2cd9}\u{2cdb}\u{2cdb}\u{2cdd}\u{2cdd}\u{2cdf}\u{2cdf}\u{2ce1}\u{2ce1}\u{2ce3}\u{2ce4}\u{2cec}\u{2cec}\u{2cee}\u{2cee}\u{2cf3}\u{2cf3}\u{2d00}\u{2d25}\u{2d27}\u{2d27}\u{2d2d}\u{2d2d}\u{a641}\u{a641}\u{a643}\u{a643}\u{a645}\u{a645}\u{a647}\u{a647}\u{a649}\u{a649}\u{a64b}\u{a64b}\u{a64d}\u{a64d}\u{a64f}\u{a64f}\u{a651}\u{a651}\u{a653}\u{a653}\u{a655}\u{a655}\u{a657}\u{a657}\u{a659}\u{a659}\u{a65b}\u{a65b}\u{a65d}\u{a65d}\u{a65f}\u{a65f}\u{a661}\u{a661}\u{a663}\u{a663}\u{a665}\u{a665}\u{a667}\u{a667}\u{a669}\u{a669}\u{a66b}\u{a66b}\u{a66d}\u{a66d}\u{a681}\u{a681}\u{a683}\u{a683}\u{a685}\u{a685}\u{a687}\u{a687}\u{a689}\u{a689}\u{a68b}\u{a68b}\u{a68d}\u{a68d}\u{a68f}\u{a68f}\u{a691}\u{a691}\u{a693}\u{a693}\u{a695}\u{a695}\u{a697}\u{a697}\u{a699}\u{a699}\u{a69b}\u{a69b}\u{a723}\u{a723}\u{a725}\u{a725}\u{a727}\u{a727}\u{a729}\u{a729}\u{a72b}\u{a72b}\u{a72d}\u{a72d}\u{a72f}\u{a731}\u{a733}\u{a733}\u{a735}\u{a735}\u{a737}\u{a737}\u{a739}\u{a739}\u{a73b}\u{a73b}\u{a73d}\u{a73d}\u{a73f}\u{a73f}\u{a741}\u{a741}\u{a743}\u{a743}\u{a745}\u{a745}\u{a747}\u{a747}\u{a749}\u{a749}\u{a74b}\u{a74b}\u{a74d}\u{a74d}\u{a74f}\u{a74f}\u{a751}\u{a751}\u{a753}\u{a753}\u{a755}\u{a755}\u{a757}\u{a757}\u{a759}\u{a759}\u{a75b}\u{a75b}\u{a75d}\u{a75d}\u{a75f}\u{a75f}\u{a761}\u{a761}\u{a763}\u{a763}\u{a765}\u{a765}\u{a767}\u{a767}\u{a769}\u{a769}\u{a76b}\u{a76b}\u{a76d}\u{a76d}\u{a76f}\u{a76f}\u{a771}\u{a778}\u{a77a}\u{a77a}\u{a77c}\u{a77c}\u{a77f}\u{a77f}\u{a781}\u{a781}\u{a783}\u{a783}\u{a785}\u{a785}\u{a787}\u{a787}\u{a78c}\u{a78c}\u{a78e}\u{a78e}\u{a791}\u{a791}\u{a793}\u{a795}\u{a797}\u{a797}\u{a799}\u{a799}\u{a79b}\u{a79b}\u{a79d}\u{a79d}\u{a79f}\u{a79f}\u{a7a1}\u{a7a1}\u{a7a3}\u{a7a3}\u{a7a5}\u{a7a5}\u{a7a7}\u{a7a7}\u{a7a9}\u{a7a9}\u{a7af}\u{a7af}\u{a7b5}\u{a7b5}\u{a7b7}\u{a7b7}\u{a7b9}\u{a7b9}\u{a7bb}\u{a7bb}\u{a7bd}\u{a7bd}\u{a7bf}\u{a7bf}\u{a7c1}\u{a7c1}\u{a7c3}\u{a7c3}\u{a7c8}\u{a7c8}\u{a7ca}\u{a7ca}\u{a7cd}\u{a7cd}\u{a7d1}\u{a7d1}\u{a7d3}\u{a7d3}\u{a7d5}\u{a7d5}\u{a7d7}\u{a7d7}\u{a7d9}\u{a7d9}\u{a7db}\u{a7db}\u{a7f6}\u{a7f6}\u{a7fa}\u{a7fa}\u{ab30}\u{ab5a}\u{ab60}\u{ab68}\u{ab70}\u{abbf}\u{fb00}\u{fb06}\u{fb13}\u{fb17}\u{ff41}\u{ff5a}\u{10428}\u{1044f}\u{104d8}\u{104fb}\u{10597}\u{105a1}\u{105a3}\u{105b1}\u{105b3}\u{105b9}\u{105bb}\u{105bc}\u{10cc0}\u{10cf2}\u{10d70}\u{10d85}\u{118c0}\u{118df}\u{16e60}\u{16e7f}\u{1d41a}\u{1d433}\u{1d44e}\u{1d454}\u{1d456}\u{1d467}\u{1d482}\u{1d49b}\u{1d4b6}\u{1d4b9}\u{1d4bb}\u{1d4bb}\u{1d4bd}\u{1d4c3}\u{1d4c5}\u{1d4cf}\u{1d4ea}\u{1d503}\u{1d51e}\u{1d537}\u{1d552}\u{1d56b}\u{1d586}\u{1d59f}\u{1d5ba}\u{1d5d3}\u{1d5ee}\u{1d607}\u{1d622}\u{1d63b}\u{1d656}\u{1d66f}\u{1d68a}\u{1d6a5}\u{1d6c2}\u{1d6da}\u{1d6dc}\u{1d6e1}\u{1d6fc}\u{1d714}\u{1d716}\u{1d71b}\u{1d736}\u{1d74e}\u{1d750}\u{1d755}\u{1d770}\u{1d788}\u{1d78a}\u{1d78f}\u{1d7aa}\u{1d7c2}\u{1d7c4}\u{1d7c9}\u{1d7cb}\u{1d7cb}\u{1df00}\u{1df09}\u{1df0b}\u{1df1e}\u{1df25}\u{1df2a}\u{1e922}\u{1e943} - #|const So : String = - #| $|\u{a6}\u{a6}\u{a9}\u{a9}\u{ae}\u{ae}\u{b0}\u{b0}\u{482}\u{482}\u{58d}\u{58e}\u{60e}\u{60f}\u{6de}\u{6de}\u{6e9}\u{6e9}\u{6fd}\u{6fe}\u{7f6}\u{7f6}\u{9fa}\u{9fa}\u{b70}\u{b70}\u{bf3}\u{bf8}\u{bfa}\u{bfa}\u{c7f}\u{c7f}\u{d4f}\u{d4f}\u{d79}\u{d79}\u{f01}\u{f03}\u{f13}\u{f13}\u{f15}\u{f17}\u{f1a}\u{f1f}\u{f34}\u{f34}\u{f36}\u{f36}\u{f38}\u{f38}\u{fbe}\u{fc5}\u{fc7}\u{fcc}\u{fce}\u{fcf}\u{fd5}\u{fd8}\u{109e}\u{109f}\u{1390}\u{1399}\u{166d}\u{166d}\u{1940}\u{1940}\u{19de}\u{19ff}\u{1b61}\u{1b6a}\u{1b74}\u{1b7c}\u{2100}\u{2101}\u{2103}\u{2106}\u{2108}\u{2109}\u{2114}\u{2114}\u{2116}\u{2117}\u{211e}\u{2123}\u{2125}\u{2125}\u{2127}\u{2127}\u{2129}\u{2129}\u{212e}\u{212e}\u{213a}\u{213b}\u{214a}\u{214a}\u{214c}\u{214d}\u{214f}\u{214f}\u{218a}\u{218b}\u{2195}\u{2199}\u{219c}\u{219f}\u{21a1}\u{21a2}\u{21a4}\u{21a5}\u{21a7}\u{21ad}\u{21af}\u{21cd}\u{21d0}\u{21d1}\u{21d3}\u{21d3}\u{21d5}\u{21f3}\u{2300}\u{2307}\u{230c}\u{231f}\u{2322}\u{2328}\u{232b}\u{237b}\u{237d}\u{239a}\u{23b4}\u{23db}\u{23e2}\u{2429}\u{2440}\u{244a}\u{249c}\u{24e9}\u{2500}\u{25b6}\u{25b8}\u{25c0}\u{25c2}\u{25f7}\u{2600}\u{266e}\u{2670}\u{2767}\u{2794}\u{27bf}\u{2800}\u{28ff}\u{2b00}\u{2b2f}\u{2b45}\u{2b46}\u{2b4d}\u{2b73}\u{2b76}\u{2b95}\u{2b97}\u{2bff}\u{2ce5}\u{2cea}\u{2e50}\u{2e51}\u{2e80}\u{2e99}\u{2e9b}\u{2ef3}\u{2f00}\u{2fd5}\u{2ff0}\u{2fff}\u{3004}\u{3004}\u{3012}\u{3013}\u{3020}\u{3020}\u{3036}\u{3037}\u{303e}\u{303f}\u{3190}\u{3191}\u{3196}\u{319f}\u{31c0}\u{31e5}\u{31ef}\u{31ef}\u{3200}\u{321e}\u{322a}\u{3247}\u{3250}\u{3250}\u{3260}\u{327f}\u{328a}\u{32b0}\u{32c0}\u{33ff}\u{4dc0}\u{4dff}\u{a490}\u{a4c6}\u{a828}\u{a82b}\u{a836}\u{a837}\u{a839}\u{a839}\u{aa77}\u{aa79}\u{fd40}\u{fd4f}\u{fdcf}\u{fdcf}\u{fdfd}\u{fdff}\u{ffe4}\u{ffe4}\u{ffe8}\u{ffe8}\u{ffed}\u{ffee}\u{fffc}\u{fffd}\u{10137}\u{1013f}\u{10179}\u{10189}\u{1018c}\u{1018e}\u{10190}\u{1019c}\u{101a0}\u{101a0}\u{101d0}\u{101fc}\u{10877}\u{10878}\u{10ac8}\u{10ac8}\u{1173f}\u{1173f}\u{11fd5}\u{11fdc}\u{11fe1}\u{11ff1}\u{16b3c}\u{16b3f}\u{16b45}\u{16b45}\u{1bc9c}\u{1bc9c}\u{1cc00}\u{1ccef}\u{1cd00}\u{1ceb3}\u{1cf50}\u{1cfc3}\u{1d000}\u{1d0f5}\u{1d100}\u{1d126}\u{1d129}\u{1d164}\u{1d16a}\u{1d16c}\u{1d183}\u{1d184}\u{1d18c}\u{1d1a9}\u{1d1ae}\u{1d1ea}\u{1d200}\u{1d241}\u{1d245}\u{1d245}\u{1d300}\u{1d356}\u{1d800}\u{1d9ff}\u{1da37}\u{1da3a}\u{1da6d}\u{1da74}\u{1da76}\u{1da83}\u{1da85}\u{1da86}\u{1e14f}\u{1e14f}\u{1ecac}\u{1ecac}\u{1ed2e}\u{1ed2e}\u{1f000}\u{1f02b}\u{1f030}\u{1f093}\u{1f0a0}\u{1f0ae}\u{1f0b1}\u{1f0bf}\u{1f0c1}\u{1f0cf}\u{1f0d1}\u{1f0f5}\u{1f10d}\u{1f1ad}\u{1f1e6}\u{1f202}\u{1f210}\u{1f23b}\u{1f240}\u{1f248}\u{1f250}\u{1f251}\u{1f260}\u{1f265}\u{1f300}\u{1f3fa}\u{1f400}\u{1f6d7}\u{1f6dc}\u{1f6ec}\u{1f6f0}\u{1f6fc}\u{1f700}\u{1f776}\u{1f77b}\u{1f7d9}\u{1f7e0}\u{1f7eb}\u{1f7f0}\u{1f7f0}\u{1f800}\u{1f80b}\u{1f810}\u{1f847}\u{1f850}\u{1f859}\u{1f860}\u{1f887}\u{1f890}\u{1f8ad}\u{1f8b0}\u{1f8bb}\u{1f8c0}\u{1f8c1}\u{1f900}\u{1fa53}\u{1fa60}\u{1fa6d}\u{1fa70}\u{1fa7c}\u{1fa80}\u{1fa89}\u{1fa8f}\u{1fac6}\u{1face}\u{1fadc}\u{1fadf}\u{1fae9}\u{1faf0}\u{1faf8}\u{1fb00}\u{1fb92}\u{1fb94}\u{1fbef} - #|const Lo : String = - #| $|\u{aa}\u{aa}\u{ba}\u{ba}\u{1bb}\u{1bb}\u{1c0}\u{1c3}\u{294}\u{294}\u{5d0}\u{5ea}\u{5ef}\u{5f2}\u{620}\u{63f}\u{641}\u{64a}\u{66e}\u{66f}\u{671}\u{6d3}\u{6d5}\u{6d5}\u{6ee}\u{6ef}\u{6fa}\u{6fc}\u{6ff}\u{6ff}\u{710}\u{710}\u{712}\u{72f}\u{74d}\u{7a5}\u{7b1}\u{7b1}\u{7ca}\u{7ea}\u{800}\u{815}\u{840}\u{858}\u{860}\u{86a}\u{870}\u{887}\u{889}\u{88e}\u{8a0}\u{8c8}\u{904}\u{939}\u{93d}\u{93d}\u{950}\u{950}\u{958}\u{961}\u{972}\u{980}\u{985}\u{98c}\u{98f}\u{990}\u{993}\u{9a8}\u{9aa}\u{9b0}\u{9b2}\u{9b2}\u{9b6}\u{9b9}\u{9bd}\u{9bd}\u{9ce}\u{9ce}\u{9dc}\u{9dd}\u{9df}\u{9e1}\u{9f0}\u{9f1}\u{9fc}\u{9fc}\u{a05}\u{a0a}\u{a0f}\u{a10}\u{a13}\u{a28}\u{a2a}\u{a30}\u{a32}\u{a33}\u{a35}\u{a36}\u{a38}\u{a39}\u{a59}\u{a5c}\u{a5e}\u{a5e}\u{a72}\u{a74}\u{a85}\u{a8d}\u{a8f}\u{a91}\u{a93}\u{aa8}\u{aaa}\u{ab0}\u{ab2}\u{ab3}\u{ab5}\u{ab9}\u{abd}\u{abd}\u{ad0}\u{ad0}\u{ae0}\u{ae1}\u{af9}\u{af9}\u{b05}\u{b0c}\u{b0f}\u{b10}\u{b13}\u{b28}\u{b2a}\u{b30}\u{b32}\u{b33}\u{b35}\u{b39}\u{b3d}\u{b3d}\u{b5c}\u{b5d}\u{b5f}\u{b61}\u{b71}\u{b71}\u{b83}\u{b83}\u{b85}\u{b8a}\u{b8e}\u{b90}\u{b92}\u{b95}\u{b99}\u{b9a}\u{b9c}\u{b9c}\u{b9e}\u{b9f}\u{ba3}\u{ba4}\u{ba8}\u{baa}\u{bae}\u{bb9}\u{bd0}\u{bd0}\u{c05}\u{c0c}\u{c0e}\u{c10}\u{c12}\u{c28}\u{c2a}\u{c39}\u{c3d}\u{c3d}\u{c58}\u{c5a}\u{c5d}\u{c5d}\u{c60}\u{c61}\u{c80}\u{c80}\u{c85}\u{c8c}\u{c8e}\u{c90}\u{c92}\u{ca8}\u{caa}\u{cb3}\u{cb5}\u{cb9}\u{cbd}\u{cbd}\u{cdd}\u{cde}\u{ce0}\u{ce1}\u{cf1}\u{cf2}\u{d04}\u{d0c}\u{d0e}\u{d10}\u{d12}\u{d3a}\u{d3d}\u{d3d}\u{d4e}\u{d4e}\u{d54}\u{d56}\u{d5f}\u{d61}\u{d7a}\u{d7f}\u{d85}\u{d96}\u{d9a}\u{db1}\u{db3}\u{dbb}\u{dbd}\u{dbd}\u{dc0}\u{dc6}\u{e01}\u{e30}\u{e32}\u{e33}\u{e40}\u{e45}\u{e81}\u{e82}\u{e84}\u{e84}\u{e86}\u{e8a}\u{e8c}\u{ea3}\u{ea5}\u{ea5}\u{ea7}\u{eb0}\u{eb2}\u{eb3}\u{ebd}\u{ebd}\u{ec0}\u{ec4}\u{edc}\u{edf}\u{f00}\u{f00}\u{f40}\u{f47}\u{f49}\u{f6c}\u{f88}\u{f8c}\u{1000}\u{102a}\u{103f}\u{103f}\u{1050}\u{1055}\u{105a}\u{105d}\u{1061}\u{1061}\u{1065}\u{1066}\u{106e}\u{1070}\u{1075}\u{1081}\u{108e}\u{108e}\u{1100}\u{1248}\u{124a}\u{124d}\u{1250}\u{1256}\u{1258}\u{1258}\u{125a}\u{125d}\u{1260}\u{1288}\u{128a}\u{128d}\u{1290}\u{12b0}\u{12b2}\u{12b5}\u{12b8}\u{12be}\u{12c0}\u{12c0}\u{12c2}\u{12c5}\u{12c8}\u{12d6}\u{12d8}\u{1310}\u{1312}\u{1315}\u{1318}\u{135a}\u{1380}\u{138f}\u{1401}\u{166c}\u{166f}\u{167f}\u{1681}\u{169a}\u{16a0}\u{16ea}\u{16f1}\u{16f8}\u{1700}\u{1711}\u{171f}\u{1731}\u{1740}\u{1751}\u{1760}\u{176c}\u{176e}\u{1770}\u{1780}\u{17b3}\u{17dc}\u{17dc}\u{1820}\u{1842}\u{1844}\u{1878}\u{1880}\u{1884}\u{1887}\u{18a8}\u{18aa}\u{18aa}\u{18b0}\u{18f5}\u{1900}\u{191e}\u{1950}\u{196d}\u{1970}\u{1974}\u{1980}\u{19ab}\u{19b0}\u{19c9}\u{1a00}\u{1a16}\u{1a20}\u{1a54}\u{1b05}\u{1b33}\u{1b45}\u{1b4c}\u{1b83}\u{1ba0}\u{1bae}\u{1baf}\u{1bba}\u{1be5}\u{1c00}\u{1c23}\u{1c4d}\u{1c4f}\u{1c5a}\u{1c77}\u{1ce9}\u{1cec}\u{1cee}\u{1cf3}\u{1cf5}\u{1cf6}\u{1cfa}\u{1cfa}\u{2135}\u{2138}\u{2d30}\u{2d67}\u{2d80}\u{2d96}\u{2da0}\u{2da6}\u{2da8}\u{2dae}\u{2db0}\u{2db6}\u{2db8}\u{2dbe}\u{2dc0}\u{2dc6}\u{2dc8}\u{2dce}\u{2dd0}\u{2dd6}\u{2dd8}\u{2dde}\u{3006}\u{3006}\u{303c}\u{303c}\u{3041}\u{3096}\u{309f}\u{309f}\u{30a1}\u{30fa}\u{30ff}\u{30ff}\u{3105}\u{312f}\u{3131}\u{318e}\u{31a0}\u{31bf}\u{31f0}\u{31ff}\u{3400}\u{4dbf}\u{4e00}\u{a014}\u{a016}\u{a48c}\u{a4d0}\u{a4f7}\u{a500}\u{a60b}\u{a610}\u{a61f}\u{a62a}\u{a62b}\u{a66e}\u{a66e}\u{a6a0}\u{a6e5}\u{a78f}\u{a78f}\u{a7f7}\u{a7f7}\u{a7fb}\u{a801}\u{a803}\u{a805}\u{a807}\u{a80a}\u{a80c}\u{a822}\u{a840}\u{a873}\u{a882}\u{a8b3}\u{a8f2}\u{a8f7}\u{a8fb}\u{a8fb}\u{a8fd}\u{a8fe}\u{a90a}\u{a925}\u{a930}\u{a946}\u{a960}\u{a97c}\u{a984}\u{a9b2}\u{a9e0}\u{a9e4}\u{a9e7}\u{a9ef}\u{a9fa}\u{a9fe}\u{aa00}\u{aa28}\u{aa40}\u{aa42}\u{aa44}\u{aa4b}\u{aa60}\u{aa6f}\u{aa71}\u{aa76}\u{aa7a}\u{aa7a}\u{aa7e}\u{aaaf}\u{aab1}\u{aab1}\u{aab5}\u{aab6}\u{aab9}\u{aabd}\u{aac0}\u{aac0}\u{aac2}\u{aac2}\u{aadb}\u{aadc}\u{aae0}\u{aaea}\u{aaf2}\u{aaf2}\u{ab01}\u{ab06}\u{ab09}\u{ab0e}\u{ab11}\u{ab16}\u{ab20}\u{ab26}\u{ab28}\u{ab2e}\u{abc0}\u{abe2}\u{ac00}\u{d7a3}\u{d7b0}\u{d7c6}\u{d7cb}\u{d7fb}\u{f900}\u{fa6d}\u{fa70}\u{fad9}\u{fb1d}\u{fb1d}\u{fb1f}\u{fb28}\u{fb2a}\u{fb36}\u{fb38}\u{fb3c}\u{fb3e}\u{fb3e}\u{fb40}\u{fb41}\u{fb43}\u{fb44}\u{fb46}\u{fbb1}\u{fbd3}\u{fd3d}\u{fd50}\u{fd8f}\u{fd92}\u{fdc7}\u{fdf0}\u{fdfb}\u{fe70}\u{fe74}\u{fe76}\u{fefc}\u{ff66}\u{ff6f}\u{ff71}\u{ff9d}\u{ffa0}\u{ffbe}\u{ffc2}\u{ffc7}\u{ffca}\u{ffcf}\u{ffd2}\u{ffd7}\u{ffda}\u{ffdc}\u{10000}\u{1000b}\u{1000d}\u{10026}\u{10028}\u{1003a}\u{1003c}\u{1003d}\u{1003f}\u{1004d}\u{10050}\u{1005d}\u{10080}\u{100fa}\u{10280}\u{1029c}\u{102a0}\u{102d0}\u{10300}\u{1031f}\u{1032d}\u{10340}\u{10342}\u{10349}\u{10350}\u{10375}\u{10380}\u{1039d}\u{103a0}\u{103c3}\u{103c8}\u{103cf}\u{10450}\u{1049d}\u{10500}\u{10527}\u{10530}\u{10563}\u{105c0}\u{105f3}\u{10600}\u{10736}\u{10740}\u{10755}\u{10760}\u{10767}\u{10800}\u{10805}\u{10808}\u{10808}\u{1080a}\u{10835}\u{10837}\u{10838}\u{1083c}\u{1083c}\u{1083f}\u{10855}\u{10860}\u{10876}\u{10880}\u{1089e}\u{108e0}\u{108f2}\u{108f4}\u{108f5}\u{10900}\u{10915}\u{10920}\u{10939}\u{10980}\u{109b7}\u{109be}\u{109bf}\u{10a00}\u{10a00}\u{10a10}\u{10a13}\u{10a15}\u{10a17}\u{10a19}\u{10a35}\u{10a60}\u{10a7c}\u{10a80}\u{10a9c}\u{10ac0}\u{10ac7}\u{10ac9}\u{10ae4}\u{10b00}\u{10b35}\u{10b40}\u{10b55}\u{10b60}\u{10b72}\u{10b80}\u{10b91}\u{10c00}\u{10c48}\u{10d00}\u{10d23}\u{10d4a}\u{10d4d}\u{10d4f}\u{10d4f}\u{10e80}\u{10ea9}\u{10eb0}\u{10eb1}\u{10ec2}\u{10ec4}\u{10f00}\u{10f1c}\u{10f27}\u{10f27}\u{10f30}\u{10f45}\u{10f70}\u{10f81}\u{10fb0}\u{10fc4}\u{10fe0}\u{10ff6}\u{11003}\u{11037}\u{11071}\u{11072}\u{11075}\u{11075}\u{11083}\u{110af}\u{110d0}\u{110e8}\u{11103}\u{11126}\u{11144}\u{11144}\u{11147}\u{11147}\u{11150}\u{11172}\u{11176}\u{11176}\u{11183}\u{111b2}\u{111c1}\u{111c4}\u{111da}\u{111da}\u{111dc}\u{111dc}\u{11200}\u{11211}\u{11213}\u{1122b}\u{1123f}\u{11240}\u{11280}\u{11286}\u{11288}\u{11288}\u{1128a}\u{1128d}\u{1128f}\u{1129d}\u{1129f}\u{112a8}\u{112b0}\u{112de}\u{11305}\u{1130c}\u{1130f}\u{11310}\u{11313}\u{11328}\u{1132a}\u{11330}\u{11332}\u{11333}\u{11335}\u{11339}\u{1133d}\u{1133d}\u{11350}\u{11350}\u{1135d}\u{11361}\u{11380}\u{11389}\u{1138b}\u{1138b}\u{1138e}\u{1138e}\u{11390}\u{113b5}\u{113b7}\u{113b7}\u{113d1}\u{113d1}\u{113d3}\u{113d3}\u{11400}\u{11434}\u{11447}\u{1144a}\u{1145f}\u{11461}\u{11480}\u{114af}\u{114c4}\u{114c5}\u{114c7}\u{114c7}\u{11580}\u{115ae}\u{115d8}\u{115db}\u{11600}\u{1162f}\u{11644}\u{11644}\u{11680}\u{116aa}\u{116b8}\u{116b8}\u{11700}\u{1171a}\u{11740}\u{11746}\u{11800}\u{1182b}\u{118ff}\u{11906}\u{11909}\u{11909}\u{1190c}\u{11913}\u{11915}\u{11916}\u{11918}\u{1192f}\u{1193f}\u{1193f}\u{11941}\u{11941}\u{119a0}\u{119a7}\u{119aa}\u{119d0}\u{119e1}\u{119e1}\u{119e3}\u{119e3}\u{11a00}\u{11a00}\u{11a0b}\u{11a32}\u{11a3a}\u{11a3a}\u{11a50}\u{11a50}\u{11a5c}\u{11a89}\u{11a9d}\u{11a9d}\u{11ab0}\u{11af8}\u{11bc0}\u{11be0}\u{11c00}\u{11c08}\u{11c0a}\u{11c2e}\u{11c40}\u{11c40}\u{11c72}\u{11c8f}\u{11d00}\u{11d06}\u{11d08}\u{11d09}\u{11d0b}\u{11d30}\u{11d46}\u{11d46}\u{11d60}\u{11d65}\u{11d67}\u{11d68}\u{11d6a}\u{11d89}\u{11d98}\u{11d98}\u{11ee0}\u{11ef2}\u{11f02}\u{11f02}\u{11f04}\u{11f10}\u{11f12}\u{11f33}\u{11fb0}\u{11fb0}\u{12000}\u{12399}\u{12480}\u{12543}\u{12f90}\u{12ff0}\u{13000}\u{1342f}\u{13441}\u{13446}\u{13460}\u{143fa}\u{14400}\u{14646}\u{16100}\u{1611d}\u{16800}\u{16a38}\u{16a40}\u{16a5e}\u{16a70}\u{16abe}\u{16ad0}\u{16aed}\u{16b00}\u{16b2f}\u{16b63}\u{16b77}\u{16b7d}\u{16b8f}\u{16d43}\u{16d6a}\u{16f00}\u{16f4a}\u{16f50}\u{16f50}\u{17000}\u{187f7}\u{18800}\u{18cd5}\u{18cff}\u{18d08}\u{1b000}\u{1b122}\u{1b132}\u{1b132}\u{1b150}\u{1b152}\u{1b155}\u{1b155}\u{1b164}\u{1b167}\u{1b170}\u{1b2fb}\u{1bc00}\u{1bc6a}\u{1bc70}\u{1bc7c}\u{1bc80}\u{1bc88}\u{1bc90}\u{1bc99}\u{1df0a}\u{1df0a}\u{1e100}\u{1e12c}\u{1e14e}\u{1e14e}\u{1e290}\u{1e2ad}\u{1e2c0}\u{1e2eb}\u{1e4d0}\u{1e4ea}\u{1e5d0}\u{1e5ed}\u{1e5f0}\u{1e5f0}\u{1e7e0}\u{1e7e6}\u{1e7e8}\u{1e7eb}\u{1e7ed}\u{1e7ee}\u{1e7f0}\u{1e7fe}\u{1e800}\u{1e8c4}\u{1ee00}\u{1ee03}\u{1ee05}\u{1ee1f}\u{1ee21}\u{1ee22}\u{1ee24}\u{1ee24}\u{1ee27}\u{1ee27}\u{1ee29}\u{1ee32}\u{1ee34}\u{1ee37}\u{1ee39}\u{1ee39}\u{1ee3b}\u{1ee3b}\u{1ee42}\u{1ee42}\u{1ee47}\u{1ee47}\u{1ee49}\u{1ee49}\u{1ee4b}\u{1ee4b}\u{1ee4d}\u{1ee4f}\u{1ee51}\u{1ee52}\u{1ee54}\u{1ee54}\u{1ee57}\u{1ee57}\u{1ee59}\u{1ee59}\u{1ee5b}\u{1ee5b}\u{1ee5d}\u{1ee5d}\u{1ee5f}\u{1ee5f}\u{1ee61}\u{1ee62}\u{1ee64}\u{1ee64}\u{1ee67}\u{1ee6a}\u{1ee6c}\u{1ee72}\u{1ee74}\u{1ee77}\u{1ee79}\u{1ee7c}\u{1ee7e}\u{1ee7e}\u{1ee80}\u{1ee89}\u{1ee8b}\u{1ee9b}\u{1eea1}\u{1eea3}\u{1eea5}\u{1eea9}\u{1eeab}\u{1eebb}\u{20000}\u{2a6df}\u{2a700}\u{2b739}\u{2b740}\u{2b81d}\u{2b820}\u{2cea1}\u{2ceb0}\u{2ebe0}\u{2ebf0}\u{2ee5d}\u{2f800}\u{2fa1d}\u{30000}\u{3134a}\u{31350}\u{323af} - #|const Pi : String = - #| $|\u{ab}\u{ab}\u{2018}\u{2018}\u{201b}\u{201c}\u{201f}\u{201f}\u{2039}\u{2039}\u{2e02}\u{2e02}\u{2e04}\u{2e04}\u{2e09}\u{2e09}\u{2e0c}\u{2e0c}\u{2e1c}\u{2e1c}\u{2e20}\u{2e20} - #|const Cf : String = - #| $|\u{ad}\u{ad}\u{600}\u{605}\u{61c}\u{61c}\u{6dd}\u{6dd}\u{70f}\u{70f}\u{890}\u{891}\u{8e2}\u{8e2}\u{180e}\u{180e}\u{200b}\u{200f}\u{202a}\u{202e}\u{2060}\u{2064}\u{2066}\u{206f}\u{feff}\u{feff}\u{fff9}\u{fffb}\u{110bd}\u{110bd}\u{110cd}\u{110cd}\u{13430}\u{1343f}\u{1bca0}\u{1bca3}\u{1d173}\u{1d17a}\u{e0001}\u{e0001}\u{e0020}\u{e007f} - #|const No : String = - #| $|\u{b2}\u{b3}\u{b9}\u{b9}\u{bc}\u{be}\u{9f4}\u{9f9}\u{b72}\u{b77}\u{bf0}\u{bf2}\u{c78}\u{c7e}\u{d58}\u{d5e}\u{d70}\u{d78}\u{f2a}\u{f33}\u{1369}\u{137c}\u{17f0}\u{17f9}\u{19da}\u{19da}\u{2070}\u{2070}\u{2074}\u{2079}\u{2080}\u{2089}\u{2150}\u{215f}\u{2189}\u{2189}\u{2460}\u{249b}\u{24ea}\u{24ff}\u{2776}\u{2793}\u{2cfd}\u{2cfd}\u{3192}\u{3195}\u{3220}\u{3229}\u{3248}\u{324f}\u{3251}\u{325f}\u{3280}\u{3289}\u{32b1}\u{32bf}\u{a830}\u{a835}\u{10107}\u{10133}\u{10175}\u{10178}\u{1018a}\u{1018b}\u{102e1}\u{102fb}\u{10320}\u{10323}\u{10858}\u{1085f}\u{10879}\u{1087f}\u{108a7}\u{108af}\u{108fb}\u{108ff}\u{10916}\u{1091b}\u{109bc}\u{109bd}\u{109c0}\u{109cf}\u{109d2}\u{109ff}\u{10a40}\u{10a48}\u{10a7d}\u{10a7e}\u{10a9d}\u{10a9f}\u{10aeb}\u{10aef}\u{10b58}\u{10b5f}\u{10b78}\u{10b7f}\u{10ba9}\u{10baf}\u{10cfa}\u{10cff}\u{10e60}\u{10e7e}\u{10f1d}\u{10f26}\u{10f51}\u{10f54}\u{10fc5}\u{10fcb}\u{11052}\u{11065}\u{111e1}\u{111f4}\u{1173a}\u{1173b}\u{118ea}\u{118f2}\u{11c5a}\u{11c6c}\u{11fc0}\u{11fd4}\u{16b5b}\u{16b61}\u{16e80}\u{16e96}\u{1d2c0}\u{1d2d3}\u{1d2e0}\u{1d2f3}\u{1d360}\u{1d378}\u{1e8c7}\u{1e8cf}\u{1ec71}\u{1ecab}\u{1ecad}\u{1ecaf}\u{1ecb1}\u{1ecb4}\u{1ed01}\u{1ed2d}\u{1ed2f}\u{1ed3d}\u{1f100}\u{1f10c} - #|const Pf : String = - #| $|\u{bb}\u{bb}\u{2019}\u{2019}\u{201d}\u{201d}\u{203a}\u{203a}\u{2e03}\u{2e03}\u{2e05}\u{2e05}\u{2e0a}\u{2e0a}\u{2e0d}\u{2e0d}\u{2e1d}\u{2e1d}\u{2e21}\u{2e21} - #|const Lt : String = - #| $|\u{1c5}\u{1c5}\u{1c8}\u{1c8}\u{1cb}\u{1cb}\u{1f2}\u{1f2}\u{1f88}\u{1f8f}\u{1f98}\u{1f9f}\u{1fa8}\u{1faf}\u{1fbc}\u{1fbc}\u{1fcc}\u{1fcc}\u{1ffc}\u{1ffc} - #|const Lm : String = - #| $|\u{2b0}\u{2c1}\u{2c6}\u{2d1}\u{2e0}\u{2e4}\u{2ec}\u{2ec}\u{2ee}\u{2ee}\u{374}\u{374}\u{37a}\u{37a}\u{559}\u{559}\u{640}\u{640}\u{6e5}\u{6e6}\u{7f4}\u{7f5}\u{7fa}\u{7fa}\u{81a}\u{81a}\u{824}\u{824}\u{828}\u{828}\u{8c9}\u{8c9}\u{971}\u{971}\u{e46}\u{e46}\u{ec6}\u{ec6}\u{10fc}\u{10fc}\u{17d7}\u{17d7}\u{1843}\u{1843}\u{1aa7}\u{1aa7}\u{1c78}\u{1c7d}\u{1d2c}\u{1d6a}\u{1d78}\u{1d78}\u{1d9b}\u{1dbf}\u{2071}\u{2071}\u{207f}\u{207f}\u{2090}\u{209c}\u{2c7c}\u{2c7d}\u{2d6f}\u{2d6f}\u{2e2f}\u{2e2f}\u{3005}\u{3005}\u{3031}\u{3035}\u{303b}\u{303b}\u{309d}\u{309e}\u{30fc}\u{30fe}\u{a015}\u{a015}\u{a4f8}\u{a4fd}\u{a60c}\u{a60c}\u{a67f}\u{a67f}\u{a69c}\u{a69d}\u{a717}\u{a71f}\u{a770}\u{a770}\u{a788}\u{a788}\u{a7f2}\u{a7f4}\u{a7f8}\u{a7f9}\u{a9cf}\u{a9cf}\u{a9e6}\u{a9e6}\u{aa70}\u{aa70}\u{aadd}\u{aadd}\u{aaf3}\u{aaf4}\u{ab5c}\u{ab5f}\u{ab69}\u{ab69}\u{ff70}\u{ff70}\u{ff9e}\u{ff9f}\u{10780}\u{10785}\u{10787}\u{107b0}\u{107b2}\u{107ba}\u{10d4e}\u{10d4e}\u{10d6f}\u{10d6f}\u{16b40}\u{16b43}\u{16d40}\u{16d42}\u{16d6b}\u{16d6c}\u{16f93}\u{16f9f}\u{16fe0}\u{16fe1}\u{16fe3}\u{16fe3}\u{1aff0}\u{1aff3}\u{1aff5}\u{1affb}\u{1affd}\u{1affe}\u{1e030}\u{1e06d}\u{1e137}\u{1e13d}\u{1e4eb}\u{1e4eb}\u{1e94b}\u{1e94b} - #|const Mn : String = - #| $|\u{300}\u{36f}\u{483}\u{487}\u{591}\u{5bd}\u{5bf}\u{5bf}\u{5c1}\u{5c2}\u{5c4}\u{5c5}\u{5c7}\u{5c7}\u{610}\u{61a}\u{64b}\u{65f}\u{670}\u{670}\u{6d6}\u{6dc}\u{6df}\u{6e4}\u{6e7}\u{6e8}\u{6ea}\u{6ed}\u{711}\u{711}\u{730}\u{74a}\u{7a6}\u{7b0}\u{7eb}\u{7f3}\u{7fd}\u{7fd}\u{816}\u{819}\u{81b}\u{823}\u{825}\u{827}\u{829}\u{82d}\u{859}\u{85b}\u{897}\u{89f}\u{8ca}\u{8e1}\u{8e3}\u{902}\u{93a}\u{93a}\u{93c}\u{93c}\u{941}\u{948}\u{94d}\u{94d}\u{951}\u{957}\u{962}\u{963}\u{981}\u{981}\u{9bc}\u{9bc}\u{9c1}\u{9c4}\u{9cd}\u{9cd}\u{9e2}\u{9e3}\u{9fe}\u{9fe}\u{a01}\u{a02}\u{a3c}\u{a3c}\u{a41}\u{a42}\u{a47}\u{a48}\u{a4b}\u{a4d}\u{a51}\u{a51}\u{a70}\u{a71}\u{a75}\u{a75}\u{a81}\u{a82}\u{abc}\u{abc}\u{ac1}\u{ac5}\u{ac7}\u{ac8}\u{acd}\u{acd}\u{ae2}\u{ae3}\u{afa}\u{aff}\u{b01}\u{b01}\u{b3c}\u{b3c}\u{b3f}\u{b3f}\u{b41}\u{b44}\u{b4d}\u{b4d}\u{b55}\u{b56}\u{b62}\u{b63}\u{b82}\u{b82}\u{bc0}\u{bc0}\u{bcd}\u{bcd}\u{c00}\u{c00}\u{c04}\u{c04}\u{c3c}\u{c3c}\u{c3e}\u{c40}\u{c46}\u{c48}\u{c4a}\u{c4d}\u{c55}\u{c56}\u{c62}\u{c63}\u{c81}\u{c81}\u{cbc}\u{cbc}\u{cbf}\u{cbf}\u{cc6}\u{cc6}\u{ccc}\u{ccd}\u{ce2}\u{ce3}\u{d00}\u{d01}\u{d3b}\u{d3c}\u{d41}\u{d44}\u{d4d}\u{d4d}\u{d62}\u{d63}\u{d81}\u{d81}\u{dca}\u{dca}\u{dd2}\u{dd4}\u{dd6}\u{dd6}\u{e31}\u{e31}\u{e34}\u{e3a}\u{e47}\u{e4e}\u{eb1}\u{eb1}\u{eb4}\u{ebc}\u{ec8}\u{ece}\u{f18}\u{f19}\u{f35}\u{f35}\u{f37}\u{f37}\u{f39}\u{f39}\u{f71}\u{f7e}\u{f80}\u{f84}\u{f86}\u{f87}\u{f8d}\u{f97}\u{f99}\u{fbc}\u{fc6}\u{fc6}\u{102d}\u{1030}\u{1032}\u{1037}\u{1039}\u{103a}\u{103d}\u{103e}\u{1058}\u{1059}\u{105e}\u{1060}\u{1071}\u{1074}\u{1082}\u{1082}\u{1085}\u{1086}\u{108d}\u{108d}\u{109d}\u{109d}\u{135d}\u{135f}\u{1712}\u{1714}\u{1732}\u{1733}\u{1752}\u{1753}\u{1772}\u{1773}\u{17b4}\u{17b5}\u{17b7}\u{17bd}\u{17c6}\u{17c6}\u{17c9}\u{17d3}\u{17dd}\u{17dd}\u{180b}\u{180d}\u{180f}\u{180f}\u{1885}\u{1886}\u{18a9}\u{18a9}\u{1920}\u{1922}\u{1927}\u{1928}\u{1932}\u{1932}\u{1939}\u{193b}\u{1a17}\u{1a18}\u{1a1b}\u{1a1b}\u{1a56}\u{1a56}\u{1a58}\u{1a5e}\u{1a60}\u{1a60}\u{1a62}\u{1a62}\u{1a65}\u{1a6c}\u{1a73}\u{1a7c}\u{1a7f}\u{1a7f}\u{1ab0}\u{1abd}\u{1abf}\u{1ace}\u{1b00}\u{1b03}\u{1b34}\u{1b34}\u{1b36}\u{1b3a}\u{1b3c}\u{1b3c}\u{1b42}\u{1b42}\u{1b6b}\u{1b73}\u{1b80}\u{1b81}\u{1ba2}\u{1ba5}\u{1ba8}\u{1ba9}\u{1bab}\u{1bad}\u{1be6}\u{1be6}\u{1be8}\u{1be9}\u{1bed}\u{1bed}\u{1bef}\u{1bf1}\u{1c2c}\u{1c33}\u{1c36}\u{1c37}\u{1cd0}\u{1cd2}\u{1cd4}\u{1ce0}\u{1ce2}\u{1ce8}\u{1ced}\u{1ced}\u{1cf4}\u{1cf4}\u{1cf8}\u{1cf9}\u{1dc0}\u{1dff}\u{20d0}\u{20dc}\u{20e1}\u{20e1}\u{20e5}\u{20f0}\u{2cef}\u{2cf1}\u{2d7f}\u{2d7f}\u{2de0}\u{2dff}\u{302a}\u{302d}\u{3099}\u{309a}\u{a66f}\u{a66f}\u{a674}\u{a67d}\u{a69e}\u{a69f}\u{a6f0}\u{a6f1}\u{a802}\u{a802}\u{a806}\u{a806}\u{a80b}\u{a80b}\u{a825}\u{a826}\u{a82c}\u{a82c}\u{a8c4}\u{a8c5}\u{a8e0}\u{a8f1}\u{a8ff}\u{a8ff}\u{a926}\u{a92d}\u{a947}\u{a951}\u{a980}\u{a982}\u{a9b3}\u{a9b3}\u{a9b6}\u{a9b9}\u{a9bc}\u{a9bd}\u{a9e5}\u{a9e5}\u{aa29}\u{aa2e}\u{aa31}\u{aa32}\u{aa35}\u{aa36}\u{aa43}\u{aa43}\u{aa4c}\u{aa4c}\u{aa7c}\u{aa7c}\u{aab0}\u{aab0}\u{aab2}\u{aab4}\u{aab7}\u{aab8}\u{aabe}\u{aabf}\u{aac1}\u{aac1}\u{aaec}\u{aaed}\u{aaf6}\u{aaf6}\u{abe5}\u{abe5}\u{abe8}\u{abe8}\u{abed}\u{abed}\u{fb1e}\u{fb1e}\u{fe00}\u{fe0f}\u{fe20}\u{fe2f}\u{101fd}\u{101fd}\u{102e0}\u{102e0}\u{10376}\u{1037a}\u{10a01}\u{10a03}\u{10a05}\u{10a06}\u{10a0c}\u{10a0f}\u{10a38}\u{10a3a}\u{10a3f}\u{10a3f}\u{10ae5}\u{10ae6}\u{10d24}\u{10d27}\u{10d69}\u{10d6d}\u{10eab}\u{10eac}\u{10efc}\u{10eff}\u{10f46}\u{10f50}\u{10f82}\u{10f85}\u{11001}\u{11001}\u{11038}\u{11046}\u{11070}\u{11070}\u{11073}\u{11074}\u{1107f}\u{11081}\u{110b3}\u{110b6}\u{110b9}\u{110ba}\u{110c2}\u{110c2}\u{11100}\u{11102}\u{11127}\u{1112b}\u{1112d}\u{11134}\u{11173}\u{11173}\u{11180}\u{11181}\u{111b6}\u{111be}\u{111c9}\u{111cc}\u{111cf}\u{111cf}\u{1122f}\u{11231}\u{11234}\u{11234}\u{11236}\u{11237}\u{1123e}\u{1123e}\u{11241}\u{11241}\u{112df}\u{112df}\u{112e3}\u{112ea}\u{11300}\u{11301}\u{1133b}\u{1133c}\u{11340}\u{11340}\u{11366}\u{1136c}\u{11370}\u{11374}\u{113bb}\u{113c0}\u{113ce}\u{113ce}\u{113d0}\u{113d0}\u{113d2}\u{113d2}\u{113e1}\u{113e2}\u{11438}\u{1143f}\u{11442}\u{11444}\u{11446}\u{11446}\u{1145e}\u{1145e}\u{114b3}\u{114b8}\u{114ba}\u{114ba}\u{114bf}\u{114c0}\u{114c2}\u{114c3}\u{115b2}\u{115b5}\u{115bc}\u{115bd}\u{115bf}\u{115c0}\u{115dc}\u{115dd}\u{11633}\u{1163a}\u{1163d}\u{1163d}\u{1163f}\u{11640}\u{116ab}\u{116ab}\u{116ad}\u{116ad}\u{116b0}\u{116b5}\u{116b7}\u{116b7}\u{1171d}\u{1171d}\u{1171f}\u{1171f}\u{11722}\u{11725}\u{11727}\u{1172b}\u{1182f}\u{11837}\u{11839}\u{1183a}\u{1193b}\u{1193c}\u{1193e}\u{1193e}\u{11943}\u{11943}\u{119d4}\u{119d7}\u{119da}\u{119db}\u{119e0}\u{119e0}\u{11a01}\u{11a0a}\u{11a33}\u{11a38}\u{11a3b}\u{11a3e}\u{11a47}\u{11a47}\u{11a51}\u{11a56}\u{11a59}\u{11a5b}\u{11a8a}\u{11a96}\u{11a98}\u{11a99}\u{11c30}\u{11c36}\u{11c38}\u{11c3d}\u{11c3f}\u{11c3f}\u{11c92}\u{11ca7}\u{11caa}\u{11cb0}\u{11cb2}\u{11cb3}\u{11cb5}\u{11cb6}\u{11d31}\u{11d36}\u{11d3a}\u{11d3a}\u{11d3c}\u{11d3d}\u{11d3f}\u{11d45}\u{11d47}\u{11d47}\u{11d90}\u{11d91}\u{11d95}\u{11d95}\u{11d97}\u{11d97}\u{11ef3}\u{11ef4}\u{11f00}\u{11f01}\u{11f36}\u{11f3a}\u{11f40}\u{11f40}\u{11f42}\u{11f42}\u{11f5a}\u{11f5a}\u{13440}\u{13440}\u{13447}\u{13455}\u{1611e}\u{16129}\u{1612d}\u{1612f}\u{16af0}\u{16af4}\u{16b30}\u{16b36}\u{16f4f}\u{16f4f}\u{16f8f}\u{16f92}\u{16fe4}\u{16fe4}\u{1bc9d}\u{1bc9e}\u{1cf00}\u{1cf2d}\u{1cf30}\u{1cf46}\u{1d167}\u{1d169}\u{1d17b}\u{1d182}\u{1d185}\u{1d18b}\u{1d1aa}\u{1d1ad}\u{1d242}\u{1d244}\u{1da00}\u{1da36}\u{1da3b}\u{1da6c}\u{1da75}\u{1da75}\u{1da84}\u{1da84}\u{1da9b}\u{1da9f}\u{1daa1}\u{1daaf}\u{1e000}\u{1e006}\u{1e008}\u{1e018}\u{1e01b}\u{1e021}\u{1e023}\u{1e024}\u{1e026}\u{1e02a}\u{1e08f}\u{1e08f}\u{1e130}\u{1e136}\u{1e2ae}\u{1e2ae}\u{1e2ec}\u{1e2ef}\u{1e4ec}\u{1e4ef}\u{1e5ee}\u{1e5ef}\u{1e8d0}\u{1e8d6}\u{1e944}\u{1e94a}\u{e0100}\u{e01ef} - #|const Me : String = - #| $|\u{488}\u{489}\u{1abe}\u{1abe}\u{20dd}\u{20e0}\u{20e2}\u{20e4}\u{a670}\u{a672} - #|const Mc : String = - #| $|\u{903}\u{903}\u{93b}\u{93b}\u{93e}\u{940}\u{949}\u{94c}\u{94e}\u{94f}\u{982}\u{983}\u{9be}\u{9c0}\u{9c7}\u{9c8}\u{9cb}\u{9cc}\u{9d7}\u{9d7}\u{a03}\u{a03}\u{a3e}\u{a40}\u{a83}\u{a83}\u{abe}\u{ac0}\u{ac9}\u{ac9}\u{acb}\u{acc}\u{b02}\u{b03}\u{b3e}\u{b3e}\u{b40}\u{b40}\u{b47}\u{b48}\u{b4b}\u{b4c}\u{b57}\u{b57}\u{bbe}\u{bbf}\u{bc1}\u{bc2}\u{bc6}\u{bc8}\u{bca}\u{bcc}\u{bd7}\u{bd7}\u{c01}\u{c03}\u{c41}\u{c44}\u{c82}\u{c83}\u{cbe}\u{cbe}\u{cc0}\u{cc4}\u{cc7}\u{cc8}\u{cca}\u{ccb}\u{cd5}\u{cd6}\u{cf3}\u{cf3}\u{d02}\u{d03}\u{d3e}\u{d40}\u{d46}\u{d48}\u{d4a}\u{d4c}\u{d57}\u{d57}\u{d82}\u{d83}\u{dcf}\u{dd1}\u{dd8}\u{ddf}\u{df2}\u{df3}\u{f3e}\u{f3f}\u{f7f}\u{f7f}\u{102b}\u{102c}\u{1031}\u{1031}\u{1038}\u{1038}\u{103b}\u{103c}\u{1056}\u{1057}\u{1062}\u{1064}\u{1067}\u{106d}\u{1083}\u{1084}\u{1087}\u{108c}\u{108f}\u{108f}\u{109a}\u{109c}\u{1715}\u{1715}\u{1734}\u{1734}\u{17b6}\u{17b6}\u{17be}\u{17c5}\u{17c7}\u{17c8}\u{1923}\u{1926}\u{1929}\u{192b}\u{1930}\u{1931}\u{1933}\u{1938}\u{1a19}\u{1a1a}\u{1a55}\u{1a55}\u{1a57}\u{1a57}\u{1a61}\u{1a61}\u{1a63}\u{1a64}\u{1a6d}\u{1a72}\u{1b04}\u{1b04}\u{1b35}\u{1b35}\u{1b3b}\u{1b3b}\u{1b3d}\u{1b41}\u{1b43}\u{1b44}\u{1b82}\u{1b82}\u{1ba1}\u{1ba1}\u{1ba6}\u{1ba7}\u{1baa}\u{1baa}\u{1be7}\u{1be7}\u{1bea}\u{1bec}\u{1bee}\u{1bee}\u{1bf2}\u{1bf3}\u{1c24}\u{1c2b}\u{1c34}\u{1c35}\u{1ce1}\u{1ce1}\u{1cf7}\u{1cf7}\u{302e}\u{302f}\u{a823}\u{a824}\u{a827}\u{a827}\u{a880}\u{a881}\u{a8b4}\u{a8c3}\u{a952}\u{a953}\u{a983}\u{a983}\u{a9b4}\u{a9b5}\u{a9ba}\u{a9bb}\u{a9be}\u{a9c0}\u{aa2f}\u{aa30}\u{aa33}\u{aa34}\u{aa4d}\u{aa4d}\u{aa7b}\u{aa7b}\u{aa7d}\u{aa7d}\u{aaeb}\u{aaeb}\u{aaee}\u{aaef}\u{aaf5}\u{aaf5}\u{abe3}\u{abe4}\u{abe6}\u{abe7}\u{abe9}\u{abea}\u{abec}\u{abec}\u{11000}\u{11000}\u{11002}\u{11002}\u{11082}\u{11082}\u{110b0}\u{110b2}\u{110b7}\u{110b8}\u{1112c}\u{1112c}\u{11145}\u{11146}\u{11182}\u{11182}\u{111b3}\u{111b5}\u{111bf}\u{111c0}\u{111ce}\u{111ce}\u{1122c}\u{1122e}\u{11232}\u{11233}\u{11235}\u{11235}\u{112e0}\u{112e2}\u{11302}\u{11303}\u{1133e}\u{1133f}\u{11341}\u{11344}\u{11347}\u{11348}\u{1134b}\u{1134d}\u{11357}\u{11357}\u{11362}\u{11363}\u{113b8}\u{113ba}\u{113c2}\u{113c2}\u{113c5}\u{113c5}\u{113c7}\u{113ca}\u{113cc}\u{113cd}\u{113cf}\u{113cf}\u{11435}\u{11437}\u{11440}\u{11441}\u{11445}\u{11445}\u{114b0}\u{114b2}\u{114b9}\u{114b9}\u{114bb}\u{114be}\u{114c1}\u{114c1}\u{115af}\u{115b1}\u{115b8}\u{115bb}\u{115be}\u{115be}\u{11630}\u{11632}\u{1163b}\u{1163c}\u{1163e}\u{1163e}\u{116ac}\u{116ac}\u{116ae}\u{116af}\u{116b6}\u{116b6}\u{1171e}\u{1171e}\u{11720}\u{11721}\u{11726}\u{11726}\u{1182c}\u{1182e}\u{11838}\u{11838}\u{11930}\u{11935}\u{11937}\u{11938}\u{1193d}\u{1193d}\u{11940}\u{11940}\u{11942}\u{11942}\u{119d1}\u{119d3}\u{119dc}\u{119df}\u{119e4}\u{119e4}\u{11a39}\u{11a39}\u{11a57}\u{11a58}\u{11a97}\u{11a97}\u{11c2f}\u{11c2f}\u{11c3e}\u{11c3e}\u{11ca9}\u{11ca9}\u{11cb1}\u{11cb1}\u{11cb4}\u{11cb4}\u{11d8a}\u{11d8e}\u{11d93}\u{11d94}\u{11d96}\u{11d96}\u{11ef5}\u{11ef6}\u{11f03}\u{11f03}\u{11f34}\u{11f35}\u{11f3e}\u{11f3f}\u{11f41}\u{11f41}\u{1612a}\u{1612c}\u{16f51}\u{16f87}\u{16ff0}\u{16ff1}\u{1d165}\u{1d166}\u{1d16d}\u{1d172} - #|const Nl : String = - #| $|\u{16ee}\u{16f0}\u{2160}\u{2182}\u{2185}\u{2188}\u{3007}\u{3007}\u{3021}\u{3029}\u{3038}\u{303a}\u{a6e6}\u{a6ef}\u{10140}\u{10174}\u{10341}\u{10341}\u{1034a}\u{1034a}\u{103d1}\u{103d5}\u{12400}\u{1246e} - #|const Zl : String = - #| $|\u{2028}\u{2028} - #|const Zp : String = - #| $|\u{2029}\u{2029} - #|let cs : Array[Char] = [(0xd800).unsafe_to_char(), (0xdfff).unsafe_to_char()] - #|const Co : String = - #| $|\u{e000}\u{f8ff}\u{f0000}\u{ffffd}\u{100000}\u{10fffd} - ), - "property_value_alises.mbt": ( - #|pub let general_category_property_value_alises : Map[String, String] = { - #| "C": "C", - #| "Other": "C", - #| "Cc": "Cc", - #| "Control": "Cc", - #| "cntrl": "Cc", - #| "Cf": "Cf", - #| "Format": "Cf", - #| "Cn": "Cn", - #| "Unassigned": "Cn", - #| "Co": "Co", - #| "Private_Use": "Co", - #| "Cs": "Cs", - #| "Surrogate": "Cs", - #| "L": "L", - #| "Letter": "L", - #| "LC": "LC", - #| "Cased_Letter": "LC", - #| "Ll": "Ll", - #| "Lowercase_Letter": "Ll", - #| "Lm": "Lm", - #| "Modifier_Letter": "Lm", - #| "Lo": "Lo", - #| "Other_Letter": "Lo", - #| "Lt": "Lt", - #| "Titlecase_Letter": "Lt", - #| "Lu": "Lu", - #| "Uppercase_Letter": "Lu", - #| "M": "M", - #| "Mark": "M", - #| "Combining_Mark": "M", - #| "Mc": "Mc", - #| "Spacing_Mark": "Mc", - #| "Me": "Me", - #| "Enclosing_Mark": "Me", - #| "Mn": "Mn", - #| "Nonspacing_Mark": "Mn", - #| "N": "N", - #| "Number": "N", - #| "Nd": "Nd", - #| "Decimal_Number": "Nd", - #| "digit": "Nd", - #| "Nl": "Nl", - #| "Letter_Number": "Nl", - #| "No": "No", - #| "Other_Number": "No", - #| "P": "P", - #| "Punctuation": "P", - #| "punct": "P", - #| "Pc": "Pc", - #| "Connector_Punctuation": "Pc", - #| "Pd": "Pd", - #| "Dash_Punctuation": "Pd", - #| "Pe": "Pe", - #| "Close_Punctuation": "Pe", - #| "Pf": "Pf", - #| "Final_Punctuation": "Pf", - #| "Pi": "Pi", - #| "Initial_Punctuation": "Pi", - #| "Po": "Po", - #| "Other_Punctuation": "Po", - #| "Ps": "Ps", - #| "Open_Punctuation": "Ps", - #| "S": "S", - #| "Symbol": "S", - #| "Sc": "Sc", - #| "Currency_Symbol": "Sc", - #| "Sk": "Sk", - #| "Modifier_Symbol": "Sk", - #| "Sm": "Sm", - #| "Math_Symbol": "Sm", - #| "So": "So", - #| "Other_Symbol": "So", - #| "Z": "Z", - #| "Separator": "Z", - #| "Zl": "Zl", - #| "Line_Separator": "Zl", - #| "Zp": "Zp", - #| "Paragraph_Separator": "Zp", - #| "Zs": "Zs", - #| "Space_Separator": "Zs", - #|} - ), - }, + "symbol_map.mbt": ( + #|struct SymbolMap(@sorted_set.SortedSet[Rechar]) + #|pub fn new() -> SymbolMap { + #| SymbolMap(@sorted_set.new()) + #|} + #|pub fn SymbolMap::split( + #| self : SymbolMap, + #| set : @shared_types.RecharSet, + #|) -> Unit { + #| for interval in set.intervals() { + #| let (start, stop) = interval + #| self.0.add(start) + #| if stop + 1 > stop { + #| self.0.add(stop + 1) + #| } + #| } + #|} + #|pub fn SymbolMap::finalize( + #| self : SymbolMap, + #| lb : @shared_types.Rechar, + #| ub : @shared_types.Rechar, + #|) -> (Table, ReadOnlyArray[@shared_types.Rechar]) { + #| guard lb >= 0 else { panic() } + #| let repr = [] + #| let table = Array::make(128, -1) + #| if ub < 128 { + #| self.each_intervals(0, ub, (lo, hi) => { + #| let symbol = repr.length() + #| repr.push(Int::max(lo, lb)) + #| for c in lo..<=hi { + #| table[c] = symbol + #| } + #| }) + #| } else { + #| self.each_intervals(0, 127, (lo, hi) => { + #| let symbol = repr.length() + #| repr.push(Int::max(lo, lb)) + #| for c in lo..<=hi { + #| table[c] = symbol + #| } + #| }) + #| self.each_intervals(128, ub, (lo, hi) => { + #| let symbol = repr.length() + #| repr.push(Int::max(lo, lb)) + #| table.push(lo) + #| table.push(hi) + #| table.push(symbol) + #| }) + #| } + #| (Table(FixedArray::from_array(table)), ReadOnlyArray::from_array(repr)) + #|} + #|#locals(f) + #|fn SymbolMap::each_intervals( + #| self : SymbolMap, + #| lb : @shared_types.Rechar, + #| ub : @shared_types.Rechar, + #| f : (@shared_types.Rechar, @shared_types.Rechar) -> Unit, + #|) -> Unit { + #| if self.0.is_empty() { + #| f(lb, ub) + #| } else { + #| let last_stop = for stop in self.0; last_stop = lb { + #| if stop > ub { + #| break last_stop + #| } + #| if stop - 1 >= last_stop { + #| f(last_stop, stop - 1) + #| continue stop + #| } else { + #| continue last_stop + #| } + #| } nobreak { + #| last_stop + #| } + #| if ub >= last_stop { + #| f(last_stop, ub) + #| } + #| } + #|} + ), + "table.mbt": ( + #|struct Table(FixedArray[Rechar]) + #|pub fn Table::map(self : Table, c : Rechar) -> Rechar { + #| if c < 128 { + #| self.0.unsafe_get(c) + #| } else { + #| let arr = self.0 + #| let mut left = 0 + #| let mut right = (arr.length() - 128) / 3 - 1 + #| while left <= right { + #| let mid = left + (right - left) / 2 + #| let entry_base = 128 + mid * 3 + #| if c < arr[entry_base] { + #| right = mid - 1 + #| } else if c > arr[entry_base + 1] { + #| left = mid + 1 + #| } else { + #| return arr[entry_base + 2] + #| } + #| } + #| panic() + #| } + #|} + #|pub fn Table::map_set(self : Table, set : RecharSet) -> RecharSet { + #| set.offset_by(c => self.map(c)) + #|} + ), + "using.mbt": ( + #|using @shared_types {type Rechar, type RecharSet} + ) + } ) ///| -let moonbitlang_core_string_regex_internal_regexp_internal_vm_module : RuntimePackage = RuntimePackage::new( - "moonbitlang/core/string/regex/internal/regexp/internal/vm", - deps={ - "unicode": moonbitlang_core_string_regex_internal_regexp_internal_unicode_module, - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/array": moonbitlang_core_array_module, - "moonbitlang/core/string": moonbitlang_core_string_module, - "moonbitlang/core/int": moonbitlang_core_int_module, - "moonbitlang/core/char": moonbitlang_core_char_module, - }, +let moonbitlang_core_string_internal_regex_parser_module : RuntimePackage = RuntimePackage::new( + "moonbitlang/core/string/internal/regex_parser", + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| { "path": "moonbitlang/core/string/regex/internal/regexp/internal/unicode", "alias": "unicode" }, - #| "moonbitlang/core/builtin", - #| "moonbitlang/core/array", - #| "moonbitlang/core/string", - #| "moonbitlang/core/int", - #| "moonbitlang/core/char" - #| ], - #| "wbtest-import": [ - #| "moonbitlang/core/test" - #| ] - #|} - ), - "alias.mbt": ( - #|using @unicode {char_in_ranges, is_word_char_at} - ), - "impl.mbt": ( - #|pub(all) enum Instruction { - #| Matched - #| Save(Int) - #| Char(Array[Char]) - #| Jump(Int) - #| Split(Int, Int) - #| Assertion(Predicate) - #|} - #|pub impl ToJson for Instruction with to_json(self) { - #| match self { - #| Matched => "Matched" - #| Save(i) => ["Save", i] - #| Char(chars) => ["Chars", chars.map(c => repr(c))] - #| Jump(i) => ["Jump", i] - #| Split(i1, i2) => ["Split", i1, i2] - #| Assertion(pred) => ["Assertion", pred] - #| } - #|} - #|pub(all) enum Predicate { - #| BeginText - #| EndText - #| BeginLine - #| EndLine - #| WordBoundary - #| NoWordBoundary - #|} derive(Show, ToJson) - #|priv struct Thread { - #| pc : Int - #| sp : Int - #| captures : Array[Int] - #|} - #|fn add_thread( - #| content : StringView, - #| instructions : Array[Instruction], - #| inst_gen : Array[Int], - #| thread : Thread, - #| clist : Array[Thread], - #|) -> Unit { - #| if inst_gen[thread.pc] == thread.sp { - #| return - #| } - #| inst_gen[thread.pc] = thread.sp - #| match instructions[thread.pc] { - #| Save(i) => { - #| thread.captures[i] = thread.sp - #| add_thread( - #| content, - #| instructions, - #| inst_gen, - #| { ..thread, pc: thread.pc + 1, captures: thread.captures }, - #| clist, - #| ) - #| } - #| Jump(i) => - #| add_thread( - #| content, - #| instructions, - #| inst_gen, - #| { ..thread, pc: i, captures: thread.captures }, - #| clist, - #| ) - #| Split(i1, i2) => { - #| add_thread( - #| content, - #| instructions, - #| inst_gen, - #| { ..thread, pc: i1, captures: thread.captures.copy() }, - #| clist, - #| ) - #| add_thread( - #| content, - #| instructions, - #| inst_gen, - #| { ..thread, pc: i2, captures: thread.captures }, - #| clist, - #| ) - #| } - #| Assertion(pred) => { - #| let sp = thread.sp - #| let assertion = match pred { - #| BeginText => sp == 0 - #| EndText => sp == content.length() - #| BeginLine => sp == 0 || content.code_unit_at(sp - 1) == '\n' - #| EndLine => sp == content.length() || content.code_unit_at(sp) == '\n' - #| WordBoundary => - #| is_word_char_at(content, sp - 1) != is_word_char_at(content, sp) - #| NoWordBoundary => - #| is_word_char_at(content, sp - 1) == is_word_char_at(content, sp) - #| } - #| if assertion { - #| add_thread( - #| content, - #| instructions, - #| inst_gen, - #| { ..thread, pc: thread.pc + 1, captures: thread.captures }, - #| clist, - #| ) - #| } - #| } - #| _ => clist.push(thread) - #| } - #|} - #|pub fn vm( - #| instructions : Array[Instruction], - #| input : StringView, - #| captures : Int, - #|) -> Array[Int] { - #| guard instructions is [.., Save(1), Matched] - #| let inst_gen = Array::make(instructions.length(), -1) - #| let mut clist = Array::new(capacity=instructions.length()) - #| let mut nlist = Array::new(capacity=instructions.length()) - #| let mut matched : Array[Int] = [] - #| add_thread( - #| input, - #| instructions, - #| inst_gen, - #| { sp: 0, pc: 0, captures: Array::make(captures * 2, -1) }, - #| clist, - #| ) - #| for sp = 0; sp <= input.length(); { - #| if clist.is_empty() { - #| break - #| } - #| let actual_char = if sp == input.length() { - #| (-1).unsafe_to_char() - #| } else { - #| input.get_char(sp).unwrap() - #| } - #| let next_sp = if actual_char.to_int() > 0xFFFF { sp + 2 } else { sp + 1 } - #| for thread in clist { - #| let { pc, captures, sp: thread_sp } = thread - #| if thread_sp > sp { - #| nlist.push(thread) - #| continue - #| } - #| guard thread_sp == sp - #| if instructions[pc] is Matched { - #| matched = captures - #| break - #| } - #| match instructions[pc] { - #| Char(chars) => - #| if char_in_ranges(actual_char, chars) { - #| add_thread( - #| input, - #| instructions, - #| inst_gen, - #| { pc: pc + 1, captures, sp: next_sp }, - #| nlist, - #| ) - #| } - #| _ => panic() - #| } - #| } - #| let tmp = clist - #| clist = nlist - #| nlist = tmp - #| nlist.clear() - #| continue next_sp - #| } - #| return matched - #|} - ), - }, + "parser.mbt": ( + #|priv type Parser + #|priv enum CharOrClass { + #| Char(Rechar) + #| Class(RecharSet) + #|} + #|const MAX_QUANT = 256 + #|fn Parser::class_atom( + #| rest : StringView, + #| ctx~ : ParserContext, + #|) -> (StringView, CharOrClass) raise ParserError { + #| lexmatch rest with longest { + #| ("\\" "[dDsSwW]", _) => + #| raise ctx.error_at(rest, HINT_USE_POSIX_CHARACTER_CLASS) + #| ("\\" "b", rest) => (rest, Char('\b')) + #| ("\\" "f", rest) => (rest, Char('\f')) + #| ("\\" "n", rest) => (rest, Char('\n')) + #| ("\\" "r", rest) => (rest, Char('\r')) + #| ("\\" "t", rest) => (rest, Char('\t')) + #| ("\\" "x" ("[0-9A-Fa-f]{2}" as hex), rest) => { + #| if ctx.mode is String { + #| raise ctx.error_at(rest, HINT_BYTE_ESCAPE_NOT_ALLOWED) + #| } + #| (rest, Char(hex2i(hex))) + #| } + #| ("\\" "u" ("[0-9A-Fa-f]{4}" as hex), rest2) => { + #| if ctx.mode is Bytes { + #| raise ctx.error_at(rest, HINT_UNICODE_ESCAPE_NOT_ALLOWED) + #| } + #| let c = hex2i(hex) + #| guard ctx.profile.valid.contains(c) else { + #| raise ctx.error_at(rest, HINT_CHARACTER_OUT_OF_RANGE) + #| } + #| (rest2, Char(c)) + #| } + #| ("\\" "u" "[{]" ("[0-9A-Fa-f]{1,6}" as hex) "[}]", rest) => { + #| if ctx.mode is Bytes { + #| raise ctx.error_at(rest, HINT_UNICODE_ESCAPE_NOT_ALLOWED) + #| } + #| let c = hex2i(hex) + #| guard ctx.profile.valid.contains(c) else { + #| raise ctx.error_at(rest, HINT_CHARACTER_OUT_OF_RANGE) + #| } + #| (rest, Char(c)) + #| } + #| ("\\" ("[\^$\\.*+?()\[\]{}|/\"\-:&]" as c), rest) => + #| (rest, Char(c.to_int())) + #| ("\[:ascii:\]", rest) => (rest, Class(posix_cset_ascii)) + #| ("\[:upper:\]", rest) => (rest, Class(posix_cset_upper)) + #| ("\[:lower:\]", rest) => (rest, Class(posix_cset_lower)) + #| ("\[:alpha:\]", rest) => (rest, Class(posix_cset_alpha)) + #| ("\[:alnum:\]", rest) => (rest, Class(posix_cset_alnum)) + #| ("\[:digit:\]", rest) => (rest, Class(posix_cset_digit)) + #| ("\[:xdigit:\]", rest) => (rest, Class(posix_cset_xdigit)) + #| ("\[:blank:\]", rest) => (rest, Class(posix_cset_blank)) + #| ("\[:space:\]", rest) => (rest, Class(posix_cset_space)) + #| ("\[:word:\]", rest) => (rest, Class(ctx.profile.word)) + #| ("\[:[A-Za-z0-9_\-]+:\]", _) => + #| raise ctx.error_at(rest, HINT_UNSUPPORTED_POSIX_CLASS) + #| ("\[:", _) => raise ctx.error_at(rest, HINT_INVALID_POSIX_CLASS) + #| ("." as c, rest) => { + #| guard ctx.profile.valid.contains(c.to_int()) else { + #| raise ctx.error_at(rest, HINT_CHARACTER_OUT_OF_RANGE) + #| } + #| (rest, Char(c.to_int())) + #| } + #| _ => panic() + #| } + #|} + #|fn Parser::class_contents( + #| rest : StringView, + #| ctx~ : ParserContext, + #|) -> (StringView, RecharSet) raise ParserError { + #| outer~: for rest = rest, char_set = RecharSet::empty() { + #| match rest { + #| [] => raise ctx.error_at(rest, HINT_UNCLOSED_CHAR_CLASS) + #| [']', ..] => break (rest, char_set) + #| _ => { + #| let (rest, left) = match rest { + #| ['[', ':', ..] => + #| Parser::class_atom(rest, ctx~) + #| ['[', ..] => + #| raise ctx.error_at(rest, HINT_UNSUPPORTED_NESTED_CHAR_CLASS) + #| _ => Parser::class_atom(rest, ctx~) + #| } + #| let (rest, left_set) = match left { + #| Char(c) => + #| match rest { + #| ['-', '-', ..] => + #| raise ctx.error_at(rest, HINT_UNSUPPORTED_CLASS_SET_EXPRESSION) + #| ['-', ']', ..] => raise ctx.error_at(rest, HINT_DASH_AT_BOUNDARY) + #| ['-', .. rest] => { + #| let (rest2, right) = Parser::class_atom(rest, ctx~) + #| match right { + #| Char(c2) => { + #| guard c <= c2 else { + #| raise ctx.error_at(rest, HINT_INVALID_CHAR_RANGE) + #| } + #| (rest2, RecharSet::char_range(c, c2)) + #| } + #| Class(_) => + #| raise ctx.error_at( + #| rest, + #| offset=1, + #| HINT_CHAR_RANGE_OVER_SETS, + #| ) + #| } + #| } + #| _ => (rest, RecharSet::char(c)) + #| } + #| Class(cs) => (rest, cs) + #| } + #| let char_set = char_set + left_set + #| match rest { + #| [.. "--", ..] => + #| raise ctx.error_at(rest, HINT_UNSUPPORTED_CLASS_SET_EXPRESSION) + #| [.. "&&", ..] => + #| raise ctx.error_at(rest, HINT_UNSUPPORTED_CLASS_SET_EXPRESSION) + #| _ => continue outer~ rest, char_set + #| } + #| } + #| } + #| } + #|} + #|fn Parser::character_class( + #| rest : StringView, + #| ctx~ : ParserContext, + #|) -> (StringView, RecharSet) raise ParserError { + #| let (rest, neg) = match rest { + #| ['[', '^', .. rest] => (rest, true) + #| ['[', .. rest] => (rest, false) + #| _ => raise ctx.error_at(rest, HINT_UNEXPECTED_CHAR) + #| } + #| match rest { + #| ['-', ..] => raise ctx.error_at(rest, HINT_DASH_AT_BOUNDARY) + #| _ => () + #| } + #| let (rest, char_set) = Parser::class_contents(rest, ctx~) + #| match rest { + #| [']', .. rest] => + #| ( + #| rest, + #| if neg { + #| ctx.profile.valid - char_set + #| } else { + #| char_set & ctx.profile.valid + #| }, + #| ) + #| [] => raise ctx.error_at(rest, HINT_UNCLOSED_CHAR_CLASS) + #| _ => panic() + #| } + #|} + #|fn Parser::quantifier_opt( + #| rest : StringView, + #| ctx~ : ParserContext, + #|) -> (StringView, Quantifier?) raise ParserError { + #| let (rest, range) = lexmatch rest with longest { + #| ("\*", rest) => (rest, Some((0, None))) + #| ("\+", rest) => (rest, Some((1, None))) + #| ("\?", rest) => (rest, Some((0, Some(1)))) + #| ("[{]" ("[0-9]+" as min) "[}]", rest) => { + #| let min = Parser::quant_bound(min, ctx~) + #| (rest, Some((min, Some(min)))) + #| } + #| ("[{]" ("[0-9]+" as min) "," "[}]", rest) => { + #| let min = Parser::quant_bound(min, ctx~) + #| (rest, Some((min, None))) + #| } + #| ("[{]" ("[0-9]+" as min) "," ("[0-9]+" as max) "[}]", rest) => { + #| let min = Parser::quant_bound(min, ctx~) + #| let max = Parser::quant_bound(max, ctx~) + #| guard min <= max else { + #| raise ctx.error_at(rest, HINT_INVALID_QUANTIFIER) + #| } + #| (rest, Some((min, Some(max)))) + #| } + #| ("[{]", _) => raise ctx.error_at(rest, HINT_INVALID_QUANTIFIER) + #| _ => (rest, None) + #| } + #| match range { + #| Some((min, max)) => { + #| let rest0 = rest + #| let (rest, mode) = match rest { + #| ['?', .. rest] => (rest, QuantifierMode::NonGreedy) + #| ['+', ..] => + #| raise ctx.error_at(rest0, HINT_UNSUPPORTED_POSSESSIVE_QUANTIFIER) + #| _ => (rest, Greedy) + #| } + #| (rest, Some({ min, max, mode })) + #| } + #| None => (rest, None) + #| } + #|} + #|fn Parser::quant_bound( + #| digits : StringView, + #| ctx~ : ParserContext, + #|) -> Int raise ParserError { + #| for c in digits; value = 0 { + #| let digit = c.to_int() - '0'.to_int() + #| let next = value * 10 + digit + #| guard next <= MAX_QUANT else { + #| raise ctx.error_at(digits, HINT_QUANTIFIER_TOO_LARGE) + #| } + #| continue next + #| } nobreak { + #| value + #| } + #|} + #|fn Parser::term( + #| rest : StringView, + #| ctx~ : ParserContext, + #|) -> (StringView, Pattern) raise ParserError { + #| let (rest, pat, is_assertion) = lexmatch rest with longest { + #| ("\^", rest) => (rest, @re.start_of_input, true) + #| ("\$", rest) => (rest, @re.end_of_input, true) + #| ("\\" "b", rest) => + #| (rest, @re.alt([@re.start_of_word, @re.end_of_word]), true) + #| ("\\" "B", rest) => (rest, @re.not_word_boundary, true) + #| ("\\" "[dDsSwW]", _) => + #| raise ctx.error_at(rest, HINT_USE_POSIX_CHARACTER_CLASS) + #| ("\\" "f", rest) => (rest, @re.char(RecharSet::char('\f')), false) + #| ("\\" "n", rest) => (rest, @re.char(RecharSet::char('\n')), false) + #| ("\\" "r", rest) => (rest, @re.char(RecharSet::char('\r')), false) + #| ("\\" "t", rest) => (rest, @re.char(RecharSet::char('\t')), false) + #| ("\\" "v", rest) => (rest, @re.char(RecharSet::char('\u{0b}')), false) + #| ("\\" "x" ("[0-9A-Fa-f]{2}" as hex), rest) => { + #| if ctx.mode is String { + #| raise ctx.error_at(rest, HINT_BYTE_ESCAPE_NOT_ALLOWED) + #| } + #| (rest, @re.char(RecharSet::char(hex2i(hex))), false) + #| } + #| ("\\" "u" ("[0-9A-Fa-f]{4}" as hex), rest) => { + #| if ctx.mode is Bytes { + #| raise ctx.error_at(rest, HINT_UNICODE_ESCAPE_NOT_ALLOWED) + #| } + #| let c = hex2i(hex) + #| guard ctx.profile.valid.contains(c) else { + #| raise ctx.error_at(rest, HINT_CHARACTER_OUT_OF_RANGE) + #| } + #| (rest, @re.char(RecharSet::char(c)), false) + #| } + #| ("\\" "u" "[{]" ("[0-9A-Fa-f]{1,6}" as hex) "[}]", rest) => { + #| if ctx.mode is Bytes { + #| raise ctx.error_at(rest, HINT_UNICODE_ESCAPE_NOT_ALLOWED) + #| } + #| let c = hex2i(hex) + #| guard ctx.profile.valid.contains(c) else { + #| raise ctx.error_at(rest, HINT_CHARACTER_OUT_OF_RANGE) + #| } + #| (rest, @re.char(RecharSet::char(c)), false) + #| } + #| ("\\" ("[\^$\\.*+?()\[\]{}|/\"]" as c), rest) => + #| (rest, @re.char(RecharSet::char(c.to_int())), false) + #| ("\\" ".", _) => raise ctx.error_at(rest, HINT_INVALID_ESCAPE) + #| ("\.", rest) => (rest, @re.char(ctx.profile.valid), false) + #| ("\(\?=", _) => raise ctx.error_at(rest, HINT_UNSUPPORTED_LOOKAHEAD) + #| ("\(\?!", _) => + #| raise ctx.error_at(rest, HINT_UNSUPPORTED_NEGATIVE_LOOKAHEAD) + #| ("\(\?<=", _) => raise ctx.error_at(rest, HINT_UNSUPPORTED_LOOKBEHIND) + #| ("\(\? + #| raise ctx.error_at(rest, HINT_UNSUPPORTED_NEGATIVE_LOOKBEHIND) + #| ("\(\?<" ("[A-Za-z_][A-Za-z0-9_]*" as name) ">", rest) => { + #| let (rest, pat) = Parser::parse_group_continue(rest, ctx~) + #| (rest, @re.capture(name=name.to_string(), pat), false) + #| } + #| ("\(\?:", rest) => { + #| let (rest, pat) = Parser::parse_group_continue(rest, ctx~) + #| (rest, pat, false) + #| } + #| ("\(\?<", _) => raise ctx.error_at(rest, HINT_INVALID_GROUP) + #| ("\(\?" ("[A-Za-z]+" as modifier) ":", rest) => + #| match modifier { + #| "i" => { + #| let need_process = !ctx.ignore_case + #| let (rest, pat) = Parser::parse_group_continue(rest, ctx={ + #| ..ctx, + #| ignore_case: true, + #| }) + #| ( + #| rest, + #| if need_process { + #| pattern_map_char(pat, ignore_case) + #| } else { + #| pat + #| }, + #| false, + #| ) + #| } + #| _ => raise ctx.error_at(rest, HINT_INVALID_GROUP) + #| } + #| ("\(", rest) => { + #| let (rest, pat) = Parser::parse_group_continue(rest, ctx~) + #| (rest, @re.capture(pat), false) + #| } + #| ("\[:", _) => raise ctx.error_at(rest, HINT_BARE_POSIX_CLASS) + #| ("\[", _) => { + #| let (rest, char_set) = Parser::character_class(rest, ctx~) + #| (rest, @re.char(char_set), false) + #| } + #| ("[\^$\\.*+?()\[\]{}|]", _) => + #| raise ctx.error_at(rest, HINT_UNEXPECTED_CHAR) + #| ("." as c, rest2) => { + #| guard ctx.profile.valid.contains(c.to_int()) else { + #| raise ctx.error_at(rest, HINT_CHARACTER_OUT_OF_RANGE) + #| } + #| (rest2, @re.char(RecharSet::char(c.to_int())), false) + #| } + #| _ => raise ctx.error_at(rest, HINT_UNEXPECTED_CHAR) + #| } + #| if !is_assertion { + #| let (rest, quantifier) = Parser::quantifier_opt(rest, ctx~) + #| match quantifier { + #| Some(q) => (rest, @re.quantifier(pat, q)) + #| None => (rest, pat) + #| } + #| } else { + #| (rest, pat) + #| } + #|} + #|fn Parser::alternative( + #| rest : StringView, + #| ctx~ : ParserContext, + #|) -> (StringView, Pattern) raise ParserError { + #| let seq = [] + #| let rest = for rest = rest { + #| match rest { + #| [] | ['|' | ')', ..] => break rest + #| _ => { + #| let (rest, pat) = Parser::term(rest, ctx~) + #| seq.push(pat) + #| continue rest + #| } + #| } + #| } + #| (rest, @re.seq(ReadOnlyArray::from_array(seq))) + #|} + #|fn Parser::parse_group_continue( + #| rest : StringView, + #| ctx~ : ParserContext, + #|) -> (StringView, Pattern) raise ParserError { + #| let (rest, pat) = Parser::disjunction(rest, ctx~) + #| match rest { + #| [')', .. rest] => (rest, pat) + #| [] => raise ctx.error_at(rest, HINT_UNCLOSED_GROUP) + #| _ => raise ctx.error_at(rest, HINT_UNEXPECTED_CHAR) + #| } + #|} + #|fn Parser::disjunction( + #| rest : StringView, + #| ctx~ : ParserContext, + #|) -> (StringView, Pattern) raise ParserError { + #| let alts = [] + #| let (rest, alt) = Parser::alternative(rest, ctx~) + #| alts.push(alt) + #| let rest = for rest = rest { + #| match rest { + #| ['|', .. rest] => { + #| let (rest, pat) = Parser::alternative(rest, ctx~) + #| alts.push(pat) + #| continue rest + #| } + #| _ => break rest + #| } + #| } + #| (rest, @re.alt(ReadOnlyArray::from_array(alts))) + #|} + #|pub fn parse( + #| profile~ : Profile, + #| mode~ : Mode, + #| pattern : StringView, + #|) -> Pattern raise ParserError { + #| let ctx = ParserContext::new(profile~, base=pattern.start_offset(), mode~) + #| let (rest, pat) = Parser::disjunction(pattern, ctx~) + #| if !rest.is_empty() { + #| raise ctx.error_at(rest, HINT_UNEXPECTED_CHAR) + #| } + #| pat + #|} + ), + "parser_context.mbt": ( + #|pub(all) enum Mode { + #| Bytes + #| String + #|} + #|priv struct ParserContext { + #| profile : Profile + #| base : Int + #| ignore_case : Bool + #| mode : Mode + #|} + #|fn ParserContext::new( + #| profile~ : Profile, + #| base~ : Int, + #| mode~ : Mode, + #|) -> ParserContext { + #| ParserContext::{ profile, base, ignore_case: false, mode } + #|} + #|fn ParserContext::error_at( + #| self : ParserContext, + #| view : StringView, + #| hint : String, + #| offset? : Int = 0, + #|) -> ParserError { + #| ParserError(at=view.start_offset() - self.base + offset, hint~) + #|} + ), + "parser_error.mbt": ( + #|suberror ParserError { + #| ParserError(at~ : Int, hint~ : String) + #|} derive(Debug) + #|pub impl Show for ParserError with output(self, logger) { + #| match self { + #| ParserError(at~, hint~) => { + #| logger.write_string("ParserError at position ") + #| logger.write_object(at) + #| logger.write_string(": ") + #| logger.write_string(hint) + #| } + #| } + #|} + #|const HINT_UNCLOSED_CHAR_CLASS = "Unclosed character class" + #|const HINT_UNCLOSED_GROUP = "Unclosed group" + #|const HINT_UNEXPECTED_CHAR = "Unexpected character" + #|const HINT_QUANTIFIER_TOO_LARGE = "Quantifier too large" + #|const HINT_INVALID_QUANTIFIER = "Invalid quantifier" + #|const HINT_INVALID_ESCAPE = "Invalid escape sequence" + #|const HINT_UNICODE_ESCAPE_NOT_ALLOWED = "Unicode escape sequences are not allowed" + #|const HINT_BYTE_ESCAPE_NOT_ALLOWED = "Byte escape sequences are not allowed" + #|const HINT_CHARACTER_OUT_OF_RANGE = "Character out of range" + #|const HINT_INVALID_GROUP = "Invalid group" + #|const HINT_UNSUPPORTED_LOOKAHEAD = "Unsupported lookahead assertion" + #|const HINT_UNSUPPORTED_NEGATIVE_LOOKAHEAD = "Unsupported negative lookahead assertion" + #|const HINT_UNSUPPORTED_LOOKBEHIND = "Unsupported lookbehind assertion" + #|const HINT_UNSUPPORTED_NEGATIVE_LOOKBEHIND = "Unsupported negative lookbehind assertion" + #|const HINT_INVALID_POSIX_CLASS = "Invalid POSIX character class" + #|const HINT_BARE_POSIX_CLASS = "Invalid character class, bare POSIX character class not allowed" + #|const HINT_UNSUPPORTED_POSIX_CLASS = "Unsupported POSIX character class" + #|const HINT_CHAR_RANGE_OVER_SETS = "Character class range over sets" + #|const HINT_INVALID_CHAR_RANGE = "Invalid character class range" + #|const HINT_UNSUPPORTED_CLASS_SET_EXPRESSION = "Unsupported character class set expression" + #|const HINT_UNSUPPORTED_POSSESSIVE_QUANTIFIER = "Unsupported possessive quantifier" + #|const HINT_UNSUPPORTED_NESTED_CHAR_CLASS = "Unsupported nested character class" + #|const HINT_USE_POSIX_CHARACTER_CLASS = "Use POSIX character class instead of \\w, \\W, \\d, \\D, \\s, \\S" + #|const HINT_DASH_AT_BOUNDARY = "Dash at the start or end of character class is not supported, use \\- to match a literal dash" + ), + "parser_util.mbt": ( + #|fn hex2i(hex : StringView) -> Int { + #| for c in hex; value = 0 { + #| let value = value * 16 + #| match c { + #| '0'..='9' => continue value + (c.to_int() - '0'.to_int()) + #| 'a'..='f' => continue value + (c.to_int() - 'a'.to_int() + 10) + #| 'A'..='F' => continue value + (c.to_int() - 'A'.to_int() + 10) + #| _ => panic() + #| } + #| } nobreak { + #| value + #| } + #|} + #|fn pattern_map_char(pat : Pattern, f : (RecharSet) -> RecharSet) -> Pattern { + #| match pat.desc { + #| Capture(name~, pat) => @re.capture(name?, pattern_map_char(pat, f)) + #| Preference(pref, pat) => @re.preference(pref, pattern_map_char(pat, f)) + #| Quantifier(quant, pat) => @re.quantifier(pattern_map_char(pat, f), quant) + #| Alternation(pats) => @re.alt(pats.map(p => pattern_map_char(p, f))) + #| Sequence(pats) => @re.seq(pats.map(p => pattern_map_char(p, f))) + #| Char(c) => @re.char(f(c)) + #| Assertion(a) => @re.assertion(a) + #| } + #|} + #|fn ignore_case(cs : RecharSet) -> RecharSet { + #| cs + + #| (cs & @re.RecharSet::char_range('A', 'Z')).offset_by(it => it + 32) + + #| (cs & @re.RecharSet::char_range('a', 'z')).offset_by(it => it - 32) + #|} + #|let posix_cset_ascii : RecharSet = RecharSet::char_range(0, 0x7f) + #|let posix_cset_upper : RecharSet = RecharSet::char_range('A', 'Z') + #|let posix_cset_lower : RecharSet = RecharSet::char_range('a', 'z') + #|let posix_cset_alpha : RecharSet = posix_cset_upper + posix_cset_lower + #|let posix_cset_digit : RecharSet = RecharSet::char_range('0', '9') + #|let posix_cset_xdigit : RecharSet = posix_cset_digit + + #| RecharSet::char_range('a', 'f') + + #| RecharSet::char_range('A', 'F') + #|let posix_cset_alnum : RecharSet = posix_cset_alpha + posix_cset_digit + #|let posix_cset_space : RecharSet = RecharSet::char(' ') + + #| RecharSet::char('\t') + + #| RecharSet::char('\n') + + #| RecharSet::char('\r') + + #| RecharSet::char('\u{000B}') + + #| RecharSet::char('\f') + #|let posix_cset_blank : RecharSet = RecharSet::char(' ') + RecharSet::char('\t') + ), + "using.mbt": ( + #|using @re { + #| type Profile, + #| type Rechar, + #| type RecharSet, + #| type Quantifier, + #| type QuantifierMode, + #| type Pattern, + #|} + #|using @debug {trait Debug, type Repr} + ) + } ) ///| let moonbitlang_core_test_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/test", - deps={ "moonbitlang/core/builtin": moonbitlang_core_builtin_module }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| "moonbitlang/core/builtin" - #| ] - #|} - ), - "test.mbt": ( - #|fn[T : Show] debug_string(t : T) -> String { - #| let buf = StringBuilder::new(size_hint=50) - #| t.output(buf) - #| buf.to_string() - #|} - #|#callsite(autofill(loc)) - #|pub fn[T : Show] same_object(a : T, b : T, loc~ : SourceLoc) -> Unit raise { - #| if !physical_equal(a, b) { - #| let a = debug_string(a) - #| let b = debug_string(b) - #| fail("`\{a} is \{b}`", loc~) - #| } - #|} - #|#callsite(autofill(loc)) - #|#alias(is_not, deprecated) - #|pub fn[T : Show] not_same_object(a : T, b : T, loc~ : SourceLoc) -> Unit raise { - #| if physical_equal(a, b) { - #| let a = debug_string(a) - #| let b = debug_string(b) - #| fail("`!(\{a} is \{b})`", loc~) - #| } - #|} - #|#callsite(autofill(loc)) - #|pub fn[T] fail(msg : String, loc~ : SourceLoc) -> T raise { - #| @builtin.fail(msg, loc~) - #|} - #|pub fn Test::write(self : Test, obj : &Show) -> Unit { - #| self.buffer.write_string(obj.to_string()) - #|} - #|pub fn Test::writeln(self : Test, obj : &Show) -> Unit { - #| self.write(obj) - #| self.buffer.write_char('\n') - #|} - #|#callsite(autofill(args_loc, loc)) - #|pub fn Test::snapshot( - #| self : Test, - #| filename~ : String, - #| loc~ : SourceLoc, - #| args_loc~ : ArgsLoc, - #|) -> Unit raise SnapshotError { - #| let loc = loc.to_json_string() - #| let args_loc = args_loc.to_json() - #| let actual = self.buffer.to_string().escape() - #| let expect = filename.escape() - #| raise SnapshotError( - #| "@SNAPSHOT_TESTING {\"loc\": \{loc}, \"args_loc\": \{args_loc}, \"expect\": \{expect}, \"actual\": \{actual}, \"snapshot\": true}", - #| ) - #|} - #|pub fn Test::name(self : Self) -> String { - #| self.name - #|} - ), - "types.mbt": ( - #|#alias(T, deprecated) - #|struct Test { - #| name : String - #| buffer : StringBuilder - #|} - #|#as_free_fn - #|pub fn Test::new(name : String) -> Test { - #| { name, buffer: StringBuilder::new() } - #|} - ), - }, + "test.mbt": ( + #|fn[T : Show] debug_string(t : T) -> String { + #| let buf = StringBuilder::new(size_hint=50) + #| t.output(buf) + #| buf.to_string() + #|} + #|#callsite(autofill(loc)) + #|pub fn[T : Show] same_object(a : T, b : T, loc~ : SourceLoc) -> Unit raise { + #| if !physical_equal(a, b) { + #| let a = debug_string(a) + #| let b = debug_string(b) + #| fail("`\{a} is \{b}`", loc~) + #| } + #|} + #|#callsite(autofill(loc)) + #|#alias(is_not, deprecated) + #|pub fn[T : Show] not_same_object(a : T, b : T, loc~ : SourceLoc) -> Unit raise { + #| if physical_equal(a, b) { + #| let a = debug_string(a) + #| let b = debug_string(b) + #| fail("`!(\{a} is \{b})`", loc~) + #| } + #|} + #|#callsite(autofill(loc)) + #|pub fn[T] fail(msg : String, loc~ : SourceLoc) -> T raise { + #| @builtin.fail(msg, loc~) + #|} + #|pub fn Test::write(self : Test, obj : &Show) -> Unit { + #| self.buffer.write_string(obj.to_string()) + #|} + #|pub fn Test::writeln(self : Test, obj : &Show) -> Unit { + #| self.write(obj) + #| self.buffer.write_char('\n') + #|} + #|#callsite(autofill(args_loc, loc)) + #|pub fn Test::snapshot( + #| self : Test, + #| filename~ : String, + #| loc~ : SourceLoc, + #| args_loc~ : ArgsLoc, + #|) -> Unit raise SnapshotError { + #| let loc = loc.to_json_string() + #| let args_loc = args_loc.to_json() + #| let actual = self.buffer.to_string().escape() + #| let expect = filename.escape() + #| raise SnapshotError::SnapshotError( + #| "@SNAPSHOT_TESTING {\"loc\": \{loc}, \"args_loc\": \{args_loc}, \"expect\": \{expect}, \"actual\": \{actual}, \"snapshot\": true}", + #| ) + #|} + #|pub fn Test::name(self : Self) -> String { + #| self.name + #|} + ), + "types.mbt": ( + #|#alias(T, deprecated) + #|struct Test { + #| name : String + #| buffer : StringBuilder + #|} + #|#as_free_fn + #|pub fn Test::new(name : String) -> Test { + #| { name, buffer: StringBuilder::new() } + #|} + ) + } ) ///| let moonbitlang_core_tuple_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/tuple", - deps={ - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module, - "moonbitlang/core/quickcheck/splitmix": moonbitlang_core_quickcheck_splitmix_module, - }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": [ - #| "moonbitlang/core/builtin", - #| "moonbitlang/core/quickcheck", - #| "moonbitlang/core/quickcheck/splitmix" - #| ], - #| "test-import": [ - #| "moonbitlang/core/char" - #| ] - #|} - ), - "deprecated.mbt": ( - #|#deprecated - #|#coverage.skip - #|pub fn[T, U] pair(x : T, y : U) -> (T, U) { - #| (x, y) - #|} - #|#deprecated("use `tuple.0` instead") - #|#coverage.skip - #|pub fn[T, U] fst(tuple : (T, U)) -> T { - #| tuple.0 - #|} - #|#deprecated("use `tuple.1` instead") - #|#coverage.skip - #|pub fn[T, U] snd(tuple : (T, U)) -> U { - #| tuple.1 - #|} - #|#deprecated("use `{ let (a,b) = tuple; (f(a),b) }` instead") - #|#coverage.skip - #|pub fn[T, U, V] map_fst(f : (T) -> U, tuple : (T, V)) -> (U, V) { - #| (f(tuple.0), tuple.1) - #|} - #|#deprecated("use `{ let (a,b) = tuple; (a,f(b)) }` instead") - #|#coverage.skip - #|pub fn[T, U, V] map_snd(f : (T) -> U, tuple : (V, T)) -> (V, U) { - #| (tuple.0, f(tuple.1)) - #|} - #|#deprecated("use `{ let (a,b) = tuple; (f(a),f(b)) }` instead") - #|#coverage.skip - #|pub fn[T, U, V, W] map_both( - #| f : (T) -> U, - #| g : (V) -> W, - #| tuple : (T, V), - #|) -> (U, W) { - #| (f(tuple.0), g(tuple.1)) - #|} - #|#deprecated - #|#coverage.skip - #|pub fn[T, U] swap(tuple : (T, U)) -> (U, T) { - #| (tuple.1, tuple.0) - #|} - #|#deprecated - #|#coverage.skip - #|pub fn[T, U, V] curry(f : (T, U) -> V) -> (T) -> (U) -> V { - #| (x : T) => (y : U) => f(x, y) - #|} - #|#deprecated - #|#coverage.skip - #|pub fn[T, U, V] uncurry(f : (T) -> (U) -> V) -> (T, U) -> V { - #| (x : T, y : U) => f(x)(y) - #|} - ), - "tuple_arbitrary.mbt": ( - #|using @quickcheck {trait Arbitrary} - #|pub impl[A : Arbitrary, B : Arbitrary] Arbitrary for (A, B) with arbitrary( - #| size, - #| r0, - #|) { - #| let r1 = r0.split() - #| (Arbitrary::arbitrary(size, r0), Arbitrary::arbitrary(size, r1)) - #|} - #|pub impl[A : Arbitrary, B : Arbitrary, C : Arbitrary] Arbitrary for (A, B, C) with arbitrary( - #| size, - #| r0, - #|) { - #| let r1 = r0.split() - #| let (v1, v2) = Arbitrary::arbitrary(size, r1) - #| (Arbitrary::arbitrary(size, r0), v1, v2) - #|} - #|pub impl[A : Arbitrary, B : Arbitrary, C : Arbitrary, D : Arbitrary] Arbitrary for ( - #| A, - #| B, - #| C, - #| D, - #|) with arbitrary(size, r0) { - #| let r1 = r0.split() - #| let (v1, v2, v3) = Arbitrary::arbitrary(size, r1) - #| (Arbitrary::arbitrary(size, r0), v1, v2, v3) - #|} - #|pub impl[ - #| A : Arbitrary, - #| B : Arbitrary, - #| C : Arbitrary, - #| D : Arbitrary, - #| E : Arbitrary, - #|] Arbitrary for (A, B, C, D, E) with arbitrary(size, r0) { - #| let r1 = r0.split() - #| let (v1, v2, v3, v4) = Arbitrary::arbitrary(size, r1) - #| (Arbitrary::arbitrary(size, r0), v1, v2, v3, v4) - #|} - #|pub impl[ - #| A : Arbitrary, - #| B : Arbitrary, - #| C : Arbitrary, - #| D : Arbitrary, - #| E : Arbitrary, - #| F : Arbitrary, - #|] Arbitrary for (A, B, C, D, E, F) with arbitrary(size, r0) { - #| let r1 = r0.split() - #| let (v1, v2, v3, v4, v5) = Arbitrary::arbitrary(size, r1) - #| (Arbitrary::arbitrary(size, r0), v1, v2, v3, v4, v5) - #|} - #|pub impl[ - #| A : Arbitrary, - #| B : Arbitrary, - #| C : Arbitrary, - #| D : Arbitrary, - #| E : Arbitrary, - #| F : Arbitrary, - #| G : Arbitrary, - #|] Arbitrary for (A, B, C, D, E, F, G) with arbitrary(size, r0) { - #| let r1 = r0.split() - #| let (v1, v2, v3, v4, v5, v6) = Arbitrary::arbitrary(size, r1) - #| (Arbitrary::arbitrary(size, r0), v1, v2, v3, v4, v5, v6) - #|} - ), - "tuple_default.mbt": ( - #|pub impl[A : Default, B : Default] Default for (A, B) with default() { - #| (Default::default(), Default::default()) - #|} - #|pub impl[A : Default, B : Default, C : Default] Default for (A, B, C) with default() { - #| (Default::default(), Default::default(), Default::default()) - #|} - #|pub impl[A : Default, B : Default, C : Default, D : Default] Default for ( - #| A, - #| B, - #| C, - #| D, - #|) with default() { - #| ( - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| ) - #|} - #|pub impl[A : Default, B : Default, C : Default, D : Default, E : Default] Default for ( - #| A, - #| B, - #| C, - #| D, - #| E, - #|) with default() { - #| ( - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| ) - #|} - #|pub impl[ - #| A : Default, - #| B : Default, - #| C : Default, - #| D : Default, - #| E : Default, - #| F : Default, - #|] Default for (A, B, C, D, E, F) with default() { - #| ( - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| ) - #|} - #|pub impl[ - #| A : Default, - #| B : Default, - #| C : Default, - #| D : Default, - #| E : Default, - #| F : Default, - #| G : Default, - #|] Default for (A, B, C, D, E, F, G) with default() { - #| ( - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| ) - #|} - #|pub impl[ - #| A : Default, - #| B : Default, - #| C : Default, - #| D : Default, - #| E : Default, - #| F : Default, - #| G : Default, - #| H : Default, - #|] Default for (A, B, C, D, E, F, G, H) with default() { - #| ( - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| ) - #|} - #|pub impl[ - #| A : Default, - #| B : Default, - #| C : Default, - #| D : Default, - #| E : Default, - #| F : Default, - #| G : Default, - #| H : Default, - #| I : Default, - #|] Default for (A, B, C, D, E, F, G, H, I) with default() { - #| ( - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| ) - #|} - #|pub impl[ - #| A : Default, - #| B : Default, - #| C : Default, - #| D : Default, - #| E : Default, - #| F : Default, - #| G : Default, - #| H : Default, - #| I : Default, - #| J : Default, - #|] Default for (A, B, C, D, E, F, G, H, I, J) with default() { - #| ( - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| ) - #|} - #|pub impl[ - #| A : Default, - #| B : Default, - #| C : Default, - #| D : Default, - #| E : Default, - #| F : Default, - #| G : Default, - #| H : Default, - #| I : Default, - #| J : Default, - #| K : Default, - #|] Default for (A, B, C, D, E, F, G, H, I, J, K) with default() { - #| ( - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| ) - #|} - #|pub impl[ - #| A : Default, - #| B : Default, - #| C : Default, - #| D : Default, - #| E : Default, - #| F : Default, - #| G : Default, - #| H : Default, - #| I : Default, - #| J : Default, - #| K : Default, - #| L : Default, - #|] Default for (A, B, C, D, E, F, G, H, I, J, K, L) with default() { - #| ( - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| ) - #|} - #|pub impl[ - #| A : Default, - #| B : Default, - #| C : Default, - #| D : Default, - #| E : Default, - #| F : Default, - #| G : Default, - #| H : Default, - #| I : Default, - #| J : Default, - #| K : Default, - #| L : Default, - #| M : Default, - #|] Default for (A, B, C, D, E, F, G, H, I, J, K, L, M) with default() { - #| ( - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| ) - #|} - #|pub impl[ - #| A : Default, - #| B : Default, - #| C : Default, - #| D : Default, - #| E : Default, - #| F : Default, - #| G : Default, - #| H : Default, - #| I : Default, - #| J : Default, - #| K : Default, - #| L : Default, - #| M : Default, - #| N : Default, - #|] Default for (A, B, C, D, E, F, G, H, I, J, K, L, M, N) with default() { - #| ( - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| ) - #|} - #|pub impl[ - #| A : Default, - #| B : Default, - #| C : Default, - #| D : Default, - #| E : Default, - #| F : Default, - #| G : Default, - #| H : Default, - #| I : Default, - #| J : Default, - #| K : Default, - #| L : Default, - #| M : Default, - #| N : Default, - #| O : Default, - #|] Default for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O) with default() { - #| ( - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| ) - #|} - #|pub impl[ - #| A : Default, - #| B : Default, - #| C : Default, - #| D : Default, - #| E : Default, - #| F : Default, - #| G : Default, - #| H : Default, - #| I : Default, - #| J : Default, - #| K : Default, - #| L : Default, - #| M : Default, - #| N : Default, - #| O : Default, - #| P : Default, - #|] Default for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P) with default() { - #| ( - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| Default::default(), - #| ) - #|} - ), - }, + "deprecated.mbt": ( + #|#deprecated + #|#coverage.skip + #|pub fn[T, U] pair(x : T, y : U) -> (T, U) { + #| (x, y) + #|} + #|#deprecated("use `tuple.0` instead") + #|#coverage.skip + #|pub fn[T, U] fst(tuple : (T, U)) -> T { + #| tuple.0 + #|} + #|#deprecated("use `tuple.1` instead") + #|#coverage.skip + #|pub fn[T, U] snd(tuple : (T, U)) -> U { + #| tuple.1 + #|} + #|#deprecated("use `{ let (a,b) = tuple; (f(a),b) }` instead") + #|#coverage.skip + #|pub fn[T, U, V] map_fst(f : (T) -> U, tuple : (T, V)) -> (U, V) { + #| (f(tuple.0), tuple.1) + #|} + #|#deprecated("use `{ let (a,b) = tuple; (a,f(b)) }` instead") + #|#coverage.skip + #|pub fn[T, U, V] map_snd(f : (T) -> U, tuple : (V, T)) -> (V, U) { + #| (tuple.0, f(tuple.1)) + #|} + #|#deprecated("use `{ let (a,b) = tuple; (f(a),f(b)) }` instead") + #|#coverage.skip + #|pub fn[T, U, V, W] map_both( + #| f : (T) -> U, + #| g : (V) -> W, + #| tuple : (T, V), + #|) -> (U, W) { + #| (f(tuple.0), g(tuple.1)) + #|} + #|#deprecated + #|#coverage.skip + #|pub fn[T, U] swap(tuple : (T, U)) -> (U, T) { + #| (tuple.1, tuple.0) + #|} + #|#deprecated + #|#coverage.skip + #|pub fn[T, U, V] curry(f : (T, U) -> V) -> (T) -> (U) -> V { + #| (x : T) => (y : U) => f(x, y) + #|} + #|#deprecated + #|#coverage.skip + #|pub fn[T, U, V] uncurry(f : (T) -> (U) -> V) -> (T, U) -> V { + #| (x : T, y : U) => f(x)(y) + #|} + ), + "tuple_arbitrary.mbt": ( + #|pub impl[A : @quickcheck.Arbitrary, B : @quickcheck.Arbitrary] @quickcheck.Arbitrary for ( + #| A, + #| B, + #|) with arbitrary(size, r0) { + #| let r1 = r0.split() + #| ( + #| @quickcheck.Arbitrary::arbitrary(size, r0), + #| @quickcheck.Arbitrary::arbitrary(size, r1), + #| ) + #|} + #|pub impl[ + #| A : @quickcheck.Arbitrary, + #| B : @quickcheck.Arbitrary, + #| C : @quickcheck.Arbitrary, + #|] @quickcheck.Arbitrary for (A, B, C) with arbitrary(size, r0) { + #| let r1 = r0.split() + #| let (v1, v2) = @quickcheck.Arbitrary::arbitrary(size, r1) + #| (@quickcheck.Arbitrary::arbitrary(size, r0), v1, v2) + #|} + #|pub impl[ + #| A : @quickcheck.Arbitrary, + #| B : @quickcheck.Arbitrary, + #| C : @quickcheck.Arbitrary, + #| D : @quickcheck.Arbitrary, + #|] @quickcheck.Arbitrary for (A, B, C, D) with arbitrary(size, r0) { + #| let r1 = r0.split() + #| let (v1, v2, v3) = @quickcheck.Arbitrary::arbitrary(size, r1) + #| (@quickcheck.Arbitrary::arbitrary(size, r0), v1, v2, v3) + #|} + #|pub impl[ + #| A : @quickcheck.Arbitrary, + #| B : @quickcheck.Arbitrary, + #| C : @quickcheck.Arbitrary, + #| D : @quickcheck.Arbitrary, + #| E : @quickcheck.Arbitrary, + #|] @quickcheck.Arbitrary for (A, B, C, D, E) with arbitrary(size, r0) { + #| let r1 = r0.split() + #| let (v1, v2, v3, v4) = @quickcheck.Arbitrary::arbitrary(size, r1) + #| (@quickcheck.Arbitrary::arbitrary(size, r0), v1, v2, v3, v4) + #|} + #|pub impl[ + #| A : @quickcheck.Arbitrary, + #| B : @quickcheck.Arbitrary, + #| C : @quickcheck.Arbitrary, + #| D : @quickcheck.Arbitrary, + #| E : @quickcheck.Arbitrary, + #| F : @quickcheck.Arbitrary, + #|] @quickcheck.Arbitrary for (A, B, C, D, E, F) with arbitrary(size, r0) { + #| let r1 = r0.split() + #| let (v1, v2, v3, v4, v5) = @quickcheck.Arbitrary::arbitrary(size, r1) + #| (@quickcheck.Arbitrary::arbitrary(size, r0), v1, v2, v3, v4, v5) + #|} + #|pub impl[ + #| A : @quickcheck.Arbitrary, + #| B : @quickcheck.Arbitrary, + #| C : @quickcheck.Arbitrary, + #| D : @quickcheck.Arbitrary, + #| E : @quickcheck.Arbitrary, + #| F : @quickcheck.Arbitrary, + #| G : @quickcheck.Arbitrary, + #|] @quickcheck.Arbitrary for (A, B, C, D, E, F, G) with arbitrary(size, r0) { + #| let r1 = r0.split() + #| let (v1, v2, v3, v4, v5, v6) = @quickcheck.Arbitrary::arbitrary(size, r1) + #| (@quickcheck.Arbitrary::arbitrary(size, r0), v1, v2, v3, v4, v5, v6) + #|} + ), + "tuple_default.mbt": ( + #|pub impl[A : Default, B : Default] Default for (A, B) with default() { + #| (Default::default(), Default::default()) + #|} + #|pub impl[A : Default, B : Default, C : Default] Default for (A, B, C) with default() { + #| (Default::default(), Default::default(), Default::default()) + #|} + #|pub impl[A : Default, B : Default, C : Default, D : Default] Default for ( + #| A, + #| B, + #| C, + #| D, + #|) with default() { + #| ( + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| ) + #|} + #|pub impl[A : Default, B : Default, C : Default, D : Default, E : Default] Default for ( + #| A, + #| B, + #| C, + #| D, + #| E, + #|) with default() { + #| ( + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| ) + #|} + #|pub impl[ + #| A : Default, + #| B : Default, + #| C : Default, + #| D : Default, + #| E : Default, + #| F : Default, + #|] Default for (A, B, C, D, E, F) with default() { + #| ( + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| ) + #|} + #|pub impl[ + #| A : Default, + #| B : Default, + #| C : Default, + #| D : Default, + #| E : Default, + #| F : Default, + #| G : Default, + #|] Default for (A, B, C, D, E, F, G) with default() { + #| ( + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| ) + #|} + #|pub impl[ + #| A : Default, + #| B : Default, + #| C : Default, + #| D : Default, + #| E : Default, + #| F : Default, + #| G : Default, + #| H : Default, + #|] Default for (A, B, C, D, E, F, G, H) with default() { + #| ( + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| ) + #|} + #|pub impl[ + #| A : Default, + #| B : Default, + #| C : Default, + #| D : Default, + #| E : Default, + #| F : Default, + #| G : Default, + #| H : Default, + #| I : Default, + #|] Default for (A, B, C, D, E, F, G, H, I) with default() { + #| ( + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| ) + #|} + #|pub impl[ + #| A : Default, + #| B : Default, + #| C : Default, + #| D : Default, + #| E : Default, + #| F : Default, + #| G : Default, + #| H : Default, + #| I : Default, + #| J : Default, + #|] Default for (A, B, C, D, E, F, G, H, I, J) with default() { + #| ( + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| ) + #|} + #|pub impl[ + #| A : Default, + #| B : Default, + #| C : Default, + #| D : Default, + #| E : Default, + #| F : Default, + #| G : Default, + #| H : Default, + #| I : Default, + #| J : Default, + #| K : Default, + #|] Default for (A, B, C, D, E, F, G, H, I, J, K) with default() { + #| ( + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| ) + #|} + #|pub impl[ + #| A : Default, + #| B : Default, + #| C : Default, + #| D : Default, + #| E : Default, + #| F : Default, + #| G : Default, + #| H : Default, + #| I : Default, + #| J : Default, + #| K : Default, + #| L : Default, + #|] Default for (A, B, C, D, E, F, G, H, I, J, K, L) with default() { + #| ( + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| ) + #|} + #|pub impl[ + #| A : Default, + #| B : Default, + #| C : Default, + #| D : Default, + #| E : Default, + #| F : Default, + #| G : Default, + #| H : Default, + #| I : Default, + #| J : Default, + #| K : Default, + #| L : Default, + #| M : Default, + #|] Default for (A, B, C, D, E, F, G, H, I, J, K, L, M) with default() { + #| ( + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| ) + #|} + #|pub impl[ + #| A : Default, + #| B : Default, + #| C : Default, + #| D : Default, + #| E : Default, + #| F : Default, + #| G : Default, + #| H : Default, + #| I : Default, + #| J : Default, + #| K : Default, + #| L : Default, + #| M : Default, + #| N : Default, + #|] Default for (A, B, C, D, E, F, G, H, I, J, K, L, M, N) with default() { + #| ( + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| ) + #|} + #|pub impl[ + #| A : Default, + #| B : Default, + #| C : Default, + #| D : Default, + #| E : Default, + #| F : Default, + #| G : Default, + #| H : Default, + #| I : Default, + #| J : Default, + #| K : Default, + #| L : Default, + #| M : Default, + #| N : Default, + #| O : Default, + #|] Default for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O) with default() { + #| ( + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| ) + #|} + #|pub impl[ + #| A : Default, + #| B : Default, + #| C : Default, + #| D : Default, + #| E : Default, + #| F : Default, + #| G : Default, + #| H : Default, + #| I : Default, + #| J : Default, + #| K : Default, + #| L : Default, + #| M : Default, + #| N : Default, + #| O : Default, + #| P : Default, + #|] Default for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P) with default() { + #| ( + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| Default::default(), + #| ) + #|} + ) + } ) ///| let moonbitlang_core_uint_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/uint", - deps={ "moonbitlang/core/builtin": moonbitlang_core_builtin_module }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": ["moonbitlang/core/builtin"], - #| "test-import": ["moonbitlang/core/bytes", "moonbitlang/core/buffer"] - #|} - ), - "uint.mbt": ( - #|pub let min_value : UInt = 0U - #|pub let max_value : UInt = 4294967295U - #|pub fn UInt::to_int64(self : UInt) -> Int64 { - #| self.to_uint64().reinterpret_as_int64() - #|} - #|pub impl Default for UInt with default() { - #| 0 - #|} - #|pub fn default() -> UInt { - #| 0 - #|} - #|#deprecated - #|#doc(hidden) - #|pub fn UInt::to_be_bytes(self : UInt) -> Bytes { - #| [ - #| (self >> 24).to_byte(), - #| (self >> 16).to_byte(), - #| (self >> 8).to_byte(), - #| self.to_byte(), - #| ] - #|} - #|#deprecated - #|#doc(hidden) - #|pub fn UInt::to_le_bytes(self : UInt) -> Bytes { - #| [ - #| self.to_byte(), - #| (self >> 8).to_byte(), - #| (self >> 16).to_byte(), - #| (self >> 24).to_byte(), - #| ] - #|} - ), - }, + "uint.mbt": ( + #|pub const MIN_VALUE : UInt = 0U + #|#deprecated("Use `MIN_VALUE` instead") + #|pub let min_value : UInt = 0U + #|pub const MAX_VALUE : UInt = 4294967295U + #|#deprecated("Use `MAX_VALUE` instead") + #|pub let max_value : UInt = 4294967295U + #|pub fn UInt::to_int64(self : UInt) -> Int64 { + #| self.to_uint64().reinterpret_as_int64() + #|} + #|pub impl Default for UInt with default() { + #| 0 + #|} + #|pub fn default() -> UInt { + #| 0 + #|} + #|#deprecated + #|#doc(hidden) + #|pub fn UInt::to_be_bytes(self : UInt) -> Bytes { + #| [ + #| (self >> 24).to_byte(), + #| (self >> 16).to_byte(), + #| (self >> 8).to_byte(), + #| self.to_byte(), + #| ] + #|} + #|#deprecated + #|#doc(hidden) + #|pub fn UInt::to_le_bytes(self : UInt) -> Bytes { + #| [ + #| self.to_byte(), + #| (self >> 8).to_byte(), + #| (self >> 16).to_byte(), + #| (self >> 24).to_byte(), + #| ] + #|} + ) + } ) ///| let moonbitlang_core_uint16_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/uint16", - deps={ - "moonbitlang/core/builtin": moonbitlang_core_builtin_module, - "moonbitlang/core/int16": moonbitlang_core_int16_module, - }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": ["moonbitlang/core/builtin", "moonbitlang/core/int16"], - #| "test-import": ["moonbitlang/core/char", "moonbitlang/core/json"] - #|} - ), - "uint16.mbt": ( - #|pub let max_value : UInt16 = 65535 - #|pub let min_value : UInt16 = 0 - #|#deprecated("Use `Int16::reinterpret_from_uint16` instead") - #|pub fn UInt16::reinterpret_as_int16(self : UInt16) -> Int16 { - #| Int16::from_int(self.to_int()) - #|} - ), - }, + "uint16.mbt": ( + #|pub const MAX_VALUE : UInt16 = 65535 + #|#deprecated("Use `MAX_VALUE` instead") + #|pub let max_value : UInt16 = 65535 + #|pub const MIN_VALUE : UInt16 = 0 + #|#deprecated("Use `MIN_VALUE` instead") + #|pub let min_value : UInt16 = 0 + #|#deprecated("Use `Int16::reinterpret_from_uint16` instead") + #|pub fn UInt16::reinterpret_as_int16(self : UInt16) -> Int16 { + #| Int16::from_int(self.to_int()) + #|} + ) + } ) ///| let moonbitlang_core_uint64_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/uint64", - deps={ "moonbitlang/core/builtin": moonbitlang_core_builtin_module }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": ["moonbitlang/core/builtin"], - #| "test-import": ["moonbitlang/core/double", "moonbitlang/core/bytes"] - #|} - ), - "uint64.mbt": ( - #|pub let min_value : UInt64 = 0UL - #|pub let max_value : UInt64 = 18446744073709551615UL - #|pub fn UInt64::to_be_bytes(self : UInt64) -> Bytes { - #| [ - #| (self >> 56).to_byte(), - #| (self >> 48).to_byte(), - #| (self >> 40).to_byte(), - #| (self >> 32).to_byte(), - #| (self >> 24).to_byte(), - #| (self >> 16).to_byte(), - #| (self >> 8).to_byte(), - #| self.to_byte(), - #| ] - #|} - #|pub fn UInt64::to_le_bytes(self : UInt64) -> Bytes { - #| [ - #| self.to_byte(), - #| (self >> 8).to_byte(), - #| (self >> 16).to_byte(), - #| (self >> 24).to_byte(), - #| (self >> 32).to_byte(), - #| (self >> 40).to_byte(), - #| (self >> 48).to_byte(), - #| (self >> 56).to_byte(), - #| ] - #|} - ), - }, + "uint64.mbt": ( + #|pub const MIN_VALUE : UInt64 = 0UL + #|#deprecated("Use `MIN_VALUE` instead") + #|pub let min_value : UInt64 = 0UL + #|pub const MAX_VALUE : UInt64 = 18446744073709551615UL + #|#deprecated("Use `MAX_VALUE` instead") + #|pub let max_value : UInt64 = 18446744073709551615UL + ) + } ) ///| let moonbitlang_core_unit_module : RuntimePackage = RuntimePackage::new( "moonbitlang/core/unit", - deps={ "moonbitlang/core/builtin": moonbitlang_core_builtin_module }, + deps={ }, files={ - "moon.pkg.json": ( - #|{ - #| "import": ["moonbitlang/core/builtin"] - #|} - ), - "unit.mbt": ( - #|pub fn Unit::to_string(_ : Self) -> String { - #| "()" - #|} - #|pub impl Hash for Unit with hash_combine(_, hasher) -> Unit { - #| hasher.combine_unit() - #|} - #|pub impl Default for Unit with default() -> Unit { - #| () - #|} - #|pub fn default() -> Unit { - #| () - #|} - #|pub impl Compare for Unit with compare(_, _) { - #| 0 - #|} - ), - }, -) + "unit.mbt": ( + #|#deprecated("Use `Unit::default` instead") + #|pub fn default() -> Unit { + #| () + #|} + ) + } +) \ No newline at end of file diff --git a/interpreter/env.mbt b/interpreter/env.mbt index 5e8afa6..74194cf 100644 --- a/interpreter/env.mbt +++ b/interpreter/env.mbt @@ -51,7 +51,7 @@ pub fn RuntimeEnvironment::create_closure_env( // 只捕获不可变变量的值,可变变量通过父环境引用 self.values.each(fn(key, value) { let is_mutable = self.mutable_vars.get(key).unwrap_or(false) - if not(is_mutable) { + if !is_mutable { // 不可变变量:捕获当前值 values.set(key, value) mutable_vars.set(key, false) diff --git a/interpreter/expression_visitors.mbt b/interpreter/expression_visitors.mbt index 7f1d74b..32123f3 100644 --- a/interpreter/expression_visitors.mbt +++ b/interpreter/expression_visitors.mbt @@ -149,6 +149,25 @@ fn ClosureInterpreter::visit_array( Array(final_array) } +///| +fn ClosureInterpreter::call_struct_constr( + self : ClosureInterpreter, + pkg_name : String?, + type_name : String, + field_values : @list.List[@syntax.Argument], +) -> RuntimeValue? raise ControlFlow { + let pkg = match pkg_name { + Some(name) => self.find_pkg(name) + None => self.current_pkg + } + let ty = pkg.find_static_type(type_name) + if pkg.struct_constrs.get(type_name) is Some(constr_name) { + self.execute_static_method_call(ty, constr_name, field_values) |> Some + } else { + None + } +} + ///| /// 处理函数调用 fn ClosureInterpreter::visit_apply( @@ -161,6 +180,18 @@ fn ClosureInterpreter::visit_apply( Ident(id={ name, .. }, ..) => self.call_by_name(name, args) // 处理构造函数调用,如 Some(5) Constr(constr~, ..) => { + match constr.extra_info { + TypeName(_) => () + Package(pkg_name) if self.call_struct_constr( + Some(pkg_name), + constr.name.name, + args, + ) + is Some(result) => return result + NoExtraInfo if self.call_struct_constr(None, constr.name.name, args) + is Some(result) => return result + _ => () + } let fields = args .map(arg => { match arg.kind { diff --git a/interpreter/fs.mbt b/interpreter/fs.mbt index 5a08df3..a54f7e3 100644 --- a/interpreter/fs.mbt +++ b/interpreter/fs.mbt @@ -13,6 +13,7 @@ pub let fs_package : RuntimePackage = { trait_aliases: Map::new(), fn_aliases: Map::new(), trait_methods: Map::new(), + struct_constrs: Map::new(), values: fs_methods.map((_, v) => Fn({ val: v, ty: Internal })), env, deps: Map::new(), diff --git a/interpreter/hashmap.mbt b/interpreter/hashmap.mbt index d3976d1..694c245 100644 --- a/interpreter/hashmap.mbt +++ b/interpreter/hashmap.mbt @@ -417,7 +417,7 @@ let hash_map_to_string_fn : RuntimeFunction = ctx => { sb.write_string("{") let mut first = true map.each(fn(key, val) { - if not(first) { + if !first { sb.write_string(", ") } first = false diff --git a/interpreter/interpreter.mbt b/interpreter/interpreter.mbt index 3024c4d..b3568c2 100644 --- a/interpreter/interpreter.mbt +++ b/interpreter/interpreter.mbt @@ -53,7 +53,7 @@ pub fn ClosureInterpreter::add_embedded_method( method_name : String, f : RuntimeFunction, ) -> Unit { - if not(self.embedded_methods.contains(type_name)) { + if !self.embedded_methods.contains(type_name) { self.embedded_methods.set(type_name, Map::new()) } self.embedded_methods.get(type_name).unwrap().set(method_name, f) @@ -271,6 +271,12 @@ pub fn ClosureInterpreter::top_visit( TopTypeDef(def) => { match def { { tycon, params, components, deriving, .. } => { + if def.components is Record(constr_decl=Some(constr_decl), ..) { + self.current_pkg.struct_constrs.set( + def.tycon, + constr_decl.name.name, + ) + } self.current_pkg.type_definitions.set(tycon, def) // 处理泛型类型参数 @@ -402,6 +408,7 @@ pub fn ClosureInterpreter::top_visit( } _ => () } + DeclNone => () } Unit } diff --git a/interpreter/iter2.mbt b/interpreter/iter2.mbt index 21d7b3f..29f2dcb 100644 --- a/interpreter/iter2.mbt +++ b/interpreter/iter2.mbt @@ -22,24 +22,21 @@ pub let iter2_methods : Map[String, RuntimeFunction] = { let iter2_run_fn : RuntimeFunction = ctx => { match ctx.args { [{ val: Iter2(iter2), .. }, { val: Fn(func), .. }] => { - let result = iter2.run(fn(a, b) { + for a, b in iter2 { try { match ctx.context.call(func.val, ctx.pkg, [ { val: a, kind: Positional }, { val: b, kind: Positional }, ]) { - Unit => IterEnd - _ => IterContinue + Unit => continue + _ => break } } catch { - _ => IterEnd + _ => break } - }) - match result { - IterEnd => Unit - IterContinue => Unit } + Unit } _ => Unit } diff --git a/interpreter/module.mbt b/interpreter/module.mbt index f8a20e1..c2d3807 100644 --- a/interpreter/module.mbt +++ b/interpreter/module.mbt @@ -27,21 +27,41 @@ pub fn ModuleInfo::get_zip_url(self : ModuleInfo) -> String noraise { "\{url_base}/\{self.name}\{v}.zip" } +///| +/// Wrapper around @syntax.TraitDecl with placeholder ToJson implementation. +struct TraitDecl(@syntax.TraitDecl) + +///| +impl ToJson for TraitDecl with to_json(self) { + { "name": self.0.name.name } +} + +///| +/// Wrapper around @syntax.TypeDecl with placeholder ToJson implementation +/// and optional constructor information introduced since 0.8.0. +struct TypeDecl(@syntax.TypeDecl) + +///| +impl ToJson for TypeDecl with to_json(self) { + { "name": self.0.tycon } +} + ///| pub(all) struct RuntimePackage { name : String - traits : Map[String, @syntax.TraitDecl] + traits : Map[String, TraitDecl] // 函数别名存储 - 存储函数名到其实际实现的映射 fn_aliases : Map[String, RuntimeValue] - type_aliases : Map[String, WithType[@syntax.TypeDecl]] + type_aliases : Map[String, WithType[TypeDecl]] // trait 别名存储 - 存储 trait 名到其实际实现的映射 - trait_aliases : Map[String, WithType[@syntax.TraitDecl]] + trait_aliases : Map[String, WithType[TraitDecl]] // 存根 - 存储函数名到其实际实现的映射 stubs : Map[String, String] // 类型定义 - type_definitions : Map[String, @syntax.TypeDecl] + type_definitions : Map[String, TypeDecl] // 类型派生的trait映射 - 存储类型名到其derive的trait列表 type_derived_traits : Map[String, Array[String]] // type_name -> [trait_name] + struct_constrs : Map[String, String] // 构造函数集合 - 存储构造函数名 constructors : Map[String, String] // constructor_name -> type_name struct_methods : Map[String, Map[String, RuntimeValue]] @@ -104,6 +124,7 @@ pub fn RuntimePackage::new( deps: deps.unwrap_or(Map::new()), files: files.unwrap_or(Map::new()), loaded: false, + struct_constrs: Map::new(), } } diff --git a/interpreter/pattern_matching.mbt b/interpreter/pattern_matching.mbt index 96cc22f..a455463 100644 --- a/interpreter/pattern_matching.mbt +++ b/interpreter/pattern_matching.mbt @@ -217,7 +217,7 @@ pub fn ClosureInterpreter::match_case( while true { match pat_list { @list.More(pat, tail=pat_tail) => { - if not(self.match_case(values[index], pat)) { + if !self.match_case(values[index], pat) { return false } pat_list = pat_tail @@ -245,7 +245,7 @@ pub fn ClosureInterpreter::match_case( @list.More(array_pat, tail=pat_tail) => { match array_pat { @syntax.ArrayPattern::Pattern(pat) => - if not(self.match_case(values[index], pat)) { + if !self.match_case(values[index], pat) { return false } _ => return false // 其他数组模式暂不支持 @@ -273,7 +273,7 @@ pub fn ClosureInterpreter::match_case( for pat_field in pat_fields { match record_fields.get(pat_field.label.name) { Some(field_value) => - if not(self.match_case(field_value, pat_field.pattern)) { + if !self.match_case(field_value, pat_field.pattern) { return false } None => return false @@ -307,7 +307,7 @@ pub fn ClosureInterpreter::match_case( @list.More(pat_arg, tail=pat_tail) => { // 提取参数模式并递归匹配 let arg_pattern = pat_arg.pat - if not(self.match_case(fields[index].value, arg_pattern)) { + if !self.match_case(fields[index].value, arg_pattern) { return false } match pat_arg.kind { diff --git a/interpreter/pkg.generated.mbti b/interpreter/pkg.generated.mbti index 46f27fc..53b875d 100644 --- a/interpreter/pkg.generated.mbti +++ b/interpreter/pkg.generated.mbti @@ -134,12 +134,9 @@ pub(all) struct ModuleInfo { keywords : Array[String]? description : String? source : String? -} +} derive(Show, ToJson, @json.FromJson) pub fn ModuleInfo::get_zip_url(Self) -> String pub fn ModuleInfo::new(String, version? : String, readme? : String, repository? : String, license? : String, keywords? : Array[String], description? : String, source? : String, deps? : Map[String, String]) -> Self -pub impl Show for ModuleInfo -pub impl ToJson for ModuleInfo -pub impl @json.FromJson for ModuleInfo pub(all) struct RuntimeArgument { val : RuntimeValue @@ -157,7 +154,7 @@ pub(all) struct RuntimeEnvironment { values : Map[String, RuntimeValue] mutable_vars : Map[String, Bool] parent : RuntimeEnvironment? -} +} derive(ToJson) pub fn RuntimeEnvironment::copy(Self) -> Self pub fn RuntimeEnvironment::create_closure_env(Self) -> Self pub fn RuntimeEnvironment::find(Self, String) -> RuntimeValue? @@ -165,7 +162,6 @@ pub fn RuntimeEnvironment::new(parent? : Self, values? : Map[String, RuntimeValu pub fn RuntimeEnvironment::set(Self, String, RuntimeValue) -> Unit pub fn RuntimeEnvironment::set_mutable_variable(Self, String, RuntimeValue) -> Unit pub fn RuntimeEnvironment::update(Self, String, RuntimeValue) -> Unit -pub impl ToJson for RuntimeEnvironment pub(all) enum RuntimeErrorType { ErrorType(RuntimeType) @@ -173,10 +169,9 @@ pub(all) enum RuntimeErrorType { NoErrorType Noraise MaybeError(RuntimeType) -} +} derive(ToJson) pub impl Eq for RuntimeErrorType pub impl Show for RuntimeErrorType -pub impl ToJson for RuntimeErrorType pub(all) struct RuntimeFunctionContext { context : ClosureInterpreter @@ -189,23 +184,21 @@ pub enum RuntimeLocation { FunctionCall(String) ControlFlow(String) LetMut(String) -} -pub impl Show for RuntimeLocation +} derive(Show) pub(all) struct RuntimeModule { meta : ModuleInfo pkgs : Map[String, RuntimePackage] -} -pub impl ToJson for RuntimeModule +} derive(ToJson) pub(all) struct RuntimePackage { name : String - traits : Map[String, @syntax.TraitDecl] + traits : Map[String, TraitDecl] fn_aliases : Map[String, RuntimeValue] - type_aliases : Map[String, WithType[@syntax.TypeDecl]] - trait_aliases : Map[String, WithType[@syntax.TraitDecl]] + type_aliases : Map[String, WithType[TypeDecl]] + trait_aliases : Map[String, WithType[TraitDecl]] stubs : Map[String, String] - type_definitions : Map[String, @syntax.TypeDecl] + type_definitions : Map[String, TypeDecl] type_derived_traits : Map[String, Array[String]] constructors : Map[String, String] struct_methods : Map[String, Map[String, RuntimeValue]] @@ -215,7 +208,7 @@ pub(all) struct RuntimePackage { deps : Map[String, RuntimePackage] files : Map[String, String] mut loaded : Bool -} +} derive(ToJson) pub fn RuntimePackage::check_type_constraint(Self, RuntimeValue, @syntax.Type) -> Bool pub fn RuntimePackage::cons(Self, String, Array[RuntimeValue]) -> RuntimeValue pub fn RuntimePackage::cons_with_labels(Self, String, Array[(String?, RuntimeValue, Bool)]) -> RuntimeValue @@ -225,7 +218,6 @@ pub fn RuntimePackage::find_stub(Self, String) -> String pub fn RuntimePackage::is_constructor(Self, String) -> Bool pub fn RuntimePackage::new(String, deps? : Map[String, Self], files? : Map[String, String]) -> Self pub fn RuntimePackage::set(Self, String, RuntimeValue) -> Unit -pub impl ToJson for RuntimePackage pub(all) enum RuntimeType { Any @@ -235,7 +227,7 @@ pub(all) enum RuntimeType { Option(RuntimeType) Object(pkg~ : RuntimePackage, name~ : String) Internal -} +} derive(ToJson) pub fn RuntimeType::any() -> Self pub fn RuntimeType::array() -> Self pub fn RuntimeType::array_view() -> Self @@ -266,7 +258,6 @@ pub fn RuntimeType::uint64() -> Self pub fn RuntimeType::uninitialized_array() -> Self pub impl Eq for RuntimeType pub impl Show for RuntimeType -pub impl ToJson for RuntimeType pub(all) enum RuntimeValue { Unit @@ -316,11 +307,14 @@ pub impl Hash for RuntimeValue pub impl Show for RuntimeValue pub impl ToJson for RuntimeValue +type TraitDecl + +type TypeDecl + pub struct WithType[T] { val : T ty : RuntimeType -} -pub impl[T : ToJson] ToJson for WithType[T] +} derive(ToJson) // Type aliases pub type RuntimeFunction = (RuntimeFunctionContext) -> RuntimeValue raise ControlFlow diff --git a/interpreter/runtime_value.mbt b/interpreter/runtime_value.mbt index f88714d..1acc648 100644 --- a/interpreter/runtime_value.mbt +++ b/interpreter/runtime_value.mbt @@ -485,7 +485,7 @@ fn compare_types( while true { match (tys_a, tys_b) { (@list.More(ty_a, tail=tail_a), @list.More(ty_b, tail=tail_b)) => { - if not(compare_type_signatures(ty_a, ty_b)) { + if !compare_type_signatures(ty_a, ty_b) { return false } tys_a = tail_a diff --git a/interpreter/type_env.mbt b/interpreter/type_env.mbt index 8eee944..c25cb09 100644 --- a/interpreter/type_env.mbt +++ b/interpreter/type_env.mbt @@ -244,7 +244,7 @@ fn ClosureInterpreter::parse_function_type( ///| pub fn RuntimeType::bool() -> RuntimeType { - Object(pkg=moonbitlang_core_bool_module, name="Bool") + Object(pkg=moonbitlang_core_builtin_module, name="Bool") } ///| diff --git a/interpreter/type_operations.mbt b/interpreter/type_operations.mbt index 7e065c8..900c494 100644 --- a/interpreter/type_operations.mbt +++ b/interpreter/type_operations.mbt @@ -13,7 +13,7 @@ fn RuntimePackage::infer_struct_type_from_fields( .fold(init="Any", fn(result, entry) { let (type_name, type_def) = entry match type_def.components { - Record(struct_fields) => { + Record(fields=struct_fields, ..) => { let all_matched = struct_fields.all(sf => { current_fields.iter().any(cf => sf.name.label == cf) }) diff --git a/interpreter/utils.mbt b/interpreter/utils.mbt index 90ddf1a..fe606a5 100644 --- a/interpreter/utils.mbt +++ b/interpreter/utils.mbt @@ -11,39 +11,35 @@ fn fromCharCode(hex : StringView, base : Int) -> Char { ///| pub fn manualUnescape(input : StringView, buf : StringBuilder) -> Unit { - try { - loop input { - // EOF - "" => break - rest => - continue { - let (c, rest) = lexmatch rest with longest { - ("\\n", rest) => ('\n', rest) - ("\\t", rest) => ('\t', rest) - ("\\r", rest) => ('\r', rest) - // Backspace - ("\\b", rest) => ('\b', rest) - // Unicode escape - ("\\u[0-9a-fA-F]{4}" as raw, rest) => - (fromCharCode(raw[2:], 16), rest) - ("\\x[0-9a-fA-F]{2}" as raw, rest) => - (fromCharCode(raw[2:], 16), rest) - // Unicode escape with braces - ("\\u[{][0-9a-fA-F]+[}]" as raw, rest) => - (fromCharCode(raw[3:-1], 16), rest) - // Octal escape - ("\\o[0-3][0-7]{2}" as raw, rest) => - (fromCharCode(raw[2:], 8), rest) - ("\\\\", rest) => ('\\', rest) - ("." as c, rest) => (c, rest) - _ => break - } - buf.write_char(c) - rest + loop input { + // EOF + "" => break + rest => + continue { + let (c, rest) = lexmatch rest with longest { + ("\\n", rest) => ('\n', rest) + ("\\t", rest) => ('\t', rest) + ("\\r", rest) => ('\r', rest) + // Backspace + ("\\b", rest) => ('\b', rest) + // Unicode escape + ("\\u[0-9a-fA-F]{4}" as raw, rest) => + (fromCharCode(raw[2:], 16), rest) + ("\\x[0-9a-fA-F]{2}" as raw, rest) => + (fromCharCode(raw[2:], 16), rest) + // Unicode escape with braces + ("\\u[{][0-9a-fA-F]+[}]" as raw, rest) => + (fromCharCode(raw[3:-1], 16), rest) + // Octal escape + ("\\o[0-3][0-7]{2}" as raw, rest) => + (fromCharCode(raw[2:], 8), rest) + ("\\\\", rest) => ('\\', rest) + ("." as c, rest) => (c, rest) + _ => break } - } - } catch { - _ => () + buf.write_char(c) + rest + } } } diff --git a/moon.mod.json b/moon.mod.json index d8e5d2f..9a92731 100644 --- a/moon.mod.json +++ b/moon.mod.json @@ -2,7 +2,7 @@ "name": "oboard/moonbit-eval", "version": "0.8.19", "deps": { - "moonbitlang/parser": "0.1.13", + "moonbitlang/parser": "0.2.3", "moonbitlang/x": "0.4.38" }, "readme": "README.md", diff --git a/test/control_flow.mbt b/test/control_flow.mbt index 7a92159..870a708 100644 --- a/test/control_flow.mbt +++ b/test/control_flow.mbt @@ -98,7 +98,7 @@ test "for_loops" { #| println("even: \{i}") #| continue i + 1, acc + i #| } - #|} else { + #|} nobreak { #| acc #|} ), diff --git a/test/struct_constr.mbt b/test/struct_constr.mbt new file mode 100644 index 0000000..40d4a1b --- /dev/null +++ b/test/struct_constr.mbt @@ -0,0 +1,20 @@ +///| +test "struct_constr" { + let vm = MoonBitVM::new() + inspect( + vm.eval( + ( + #|struct Person { + #| name: String, + #| fn new(name : String) -> Person + #|} + #|fn Person::new(name: String) -> Person { + #| { name } + #|} + ), + top=true, + ), + content="()", + ) + inspect(vm.eval("Person(\"Alice\").name"), content="Alice") +}