///|
/// 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,
"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,
"immut/vector": moonbitlang_core_immut_vector_module,
"moonbitlang/core/immut/vector": moonbitlang_core_immut_vector_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,
"internal/strconv": moonbitlang_core_internal_strconv_module,
"moonbitlang/core/internal/strconv": moonbitlang_core_internal_strconv_module,
"json": moonbitlang_core_json_module,
"moonbitlang/core/json": moonbitlang_core_json_module,
"lazy": moonbitlang_core_lazy_module,
"moonbitlang/core/lazy": moonbitlang_core_lazy_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,
"range": moonbitlang_core_range_module,
"moonbitlang/core/range": moonbitlang_core_range_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 {
{
start: { fname: "", lnum: 0, bol: 0, cnum: 0 },
end: { fname: "", lnum: 0, bol: 0, cnum: 0 },
}
}
///|
let moonbitlang_core_abort_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/abort",
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={
"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]
#|} derive(@debug.Debug)
#|pub fn ArgGroup::ArgGroup(
#| name : StringView,
#| required? : Bool = false,
#| multiple? : Bool = true,
#| args? : ArrayView[String] = [],
#| requires? : ArrayView[String] = [],
#| conflicts_with? : ArrayView[String] = [],
#|) -> ArgGroup {
#| {
#| name: name.to_owned(),
#| required,
#| multiple,
#| args: args.to_owned(),
#| requires: requires.to_owned(),
#| conflicts_with: conflicts_with.to_owned(),
#| }
#|}
#|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_owned(),
#| required,
#| multiple,
#| args: args.to_owned(),
#| requires: requires.to_owned(),
#| conflicts_with: conflicts_with.to_owned(),
#| }
#|}
),
"arg_spec.mbt": (
#|#warnings("-deprecated_syntax")
#|pub(all) enum FlagAction {
#| SetTrue
#| SetFalse
#| Count
#| Help
#| Version
#|} derive(Eq, Show, @debug.Debug)
#|#warnings("-deprecated_syntax")
#|pub(all) enum OptionAction {
#| Set
#| Append
#|} derive(Eq, Show, @debug.Debug)
#|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
#|} derive(@debug.Debug)
#|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
#| )
#|} derive(@debug.Debug)
#|pub struct FlagArg {
#| priv arg : Arg
#|} derive(@debug.Debug)
#|pub fn FlagArg::FlagArg(
#| 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_owned()
#| let long = if long == "" { None } else { Some(long.to_owned()) }
#| let about = about.map(v => v.to_owned())
#| let env = env.map(v => v.to_owned())
#| {
#| arg: {
#| name,
#| about,
#| env,
#| global,
#| hidden,
#| requires: requires.to_owned(),
#| conflicts_with: conflicts_with.to_owned(),
#| required,
#| info: FlagInfo(short~, long~, action~, negatable~),
#| multiple: false,
#| },
#| }
#|}
#|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_owned()
#| let long = if long == "" { None } else { Some(long.to_owned()) }
#| let about = about.map(v => v.to_owned())
#| let env = env.map(v => v.to_owned())
#| {
#| arg: {
#| name,
#| about,
#| env,
#| global,
#| hidden,
#| requires: requires.to_owned(),
#| conflicts_with: conflicts_with.to_owned(),
#| required,
#| info: FlagInfo(short~, long~, action~, negatable~),
#| multiple: false,
#| },
#| }
#|}
#|pub struct OptionArg {
#| priv arg : Arg
#|} derive(@debug.Debug)
#|pub fn OptionArg::OptionArg(
#| 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_owned()
#| let long = if long == "" { None } else { Some(long.to_owned()) }
#| let about = about.map(v => v.to_owned())
#| let env = env.map(v => v.to_owned())
#| {
#| arg: {
#| name,
#| about,
#| env,
#| requires: requires.to_owned(),
#| conflicts_with: conflicts_with.to_owned(),
#| required,
#| global,
#| hidden,
#| info: OptionInfo(
#| short~,
#| long~,
#| action~,
#| default_values=default_values.map(values => values.to_owned()),
#| allow_hyphen_values~,
#| ),
#| multiple: action is Append,
#| },
#| }
#|}
#|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_owned()
#| let long = if long == "" { None } else { Some(long.to_owned()) }
#| let about = about.map(v => v.to_owned())
#| let env = env.map(v => v.to_owned())
#| {
#| arg: {
#| name,
#| about,
#| env,
#| requires: requires.to_owned(),
#| conflicts_with: conflicts_with.to_owned(),
#| required,
#| global,
#| hidden,
#| info: OptionInfo(
#| short~,
#| long~,
#| action~,
#| default_values=default_values.map(values => values.to_owned()),
#| allow_hyphen_values~,
#| ),
#| multiple: action is Append,
#| },
#| }
#|}
#|pub struct PositionArg {
#| priv arg : Arg
#|} derive(@debug.Debug)
#|pub fn PositionArg::PositionArg(
#| 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_owned()
#| let about = about.map(v => v.to_owned())
#| let env = env.map(v => v.to_owned())
#| {
#| arg: {
#| name,
#| about,
#| env,
#| requires: requires.to_owned(),
#| conflicts_with: conflicts_with.to_owned(),
#| required: false,
#| global,
#| hidden,
#| info: PositionalInfo(
#| num_args~,
#| default_values=default_values.map(values => values.to_owned()),
#| allow_hyphen_values~,
#| ),
#| multiple: range_allows_multiple(num_args),
#| },
#| }
#|}
#|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_owned()
#| let about = about.map(v => v.to_owned())
#| let env = env.map(v => v.to_owned())
#| {
#| arg: {
#| name,
#| about,
#| env,
#| requires: requires.to_owned(),
#| conflicts_with: conflicts_with.to_owned(),
#| required: false,
#| global,
#| hidden,
#| info: PositionalInfo(
#| num_args~,
#| default_values=default_values.map(values => values.to_owned()),
#| 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?
#|} derive(@debug.Debug)
#|pub fn Command::Command(
#| 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_owned()
#| let cmd = Command::{
#| name: name.to_owned(),
#| args: parsed_args,
#| groups,
#| subcommands: subcommands.to_owned(),
#| about: about.map(v => v.to_owned()),
#| version: version.map(v => v.to_owned()),
#| 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::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_owned()
#| let cmd = Command::{
#| name: name.to_owned(),
#| args: parsed_args,
#| groups,
#| subcommands: subcommands.to_owned(),
#| about: about.map(v => v.to_owned()),
#| version: version.map(v => v.to_owned()),
#| 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] = Map([]),
#|) -> Matches raise {
#| try {
#| let raw = parse_command(self, argv, env, [], Map([]), Map([]), 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([])
#| let values = Map([])
#| let flag_counts = Map([])
#| let sources = Map([])
#| 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)
#| }
#|}
#|impl @debug.Debug for ArgError with to_repr(self) {
#| match self {
#| Message(msg) => @debug.Repr::literal(msg)
#| }
#|}
#|test "ArgError debug keeps display text" {
#| let err : Error = ArgError::Message(
#| (
#| $|error: unexpected argument '--bad' found
#| $|
#| $|Usage: demo [options]
#| ),
#| )
#| inspect(
#| err.to_string(),
#| content=(
#| #|error: unexpected argument '--bad' found
#| #|
#| #|Usage: demo [options]
#| ),
#| )
#|}
#|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)
#|} derive(@debug.Debug)
#|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 parts = [
#| required_option_usage(cmd),
#| if has_options(cmd) {
#| "[options]"
#| } else {
#| ""
#| },
#| positional_usage(cmd),
#| subcommand_usage(cmd),
#| ].filter(p => p != "")
#| if parts.is_empty() {
#| ""
#| } else {
#| " " + parts.join(" ")
#| }
#|}
#|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 {
#| cmd.args.any(arg => {
#| !arg.hidden &&
#| arg.info is (OptionInfo(long~, short~, ..) | FlagInfo(long~, short~, ..)) &&
#| (long is Some(_) || short is Some(_)) &&
#| !is_required_arg(arg)
#| })
#|}
#|fn required_option_usage(cmd : Command) -> String {
#| [
#| for arg in cmd.args if !(arg.hidden ||
#| !is_required_arg(arg) ||
#| arg.info is PositionalInfo(_)) &&
#| required_option_token(arg) is Some(token) => token
#| ].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 {
#| args.any(arg => {
#| arg.info is (OptionInfo(long~, ..) | FlagInfo(long~, ..)) &&
#| long is Some(long) &&
#| long == name
#| })
#|}
#|fn has_short_option(args : Array[Arg], value : Char) -> Bool {
#| args.any(arg => {
#| arg.info is (OptionInfo(short~, ..) | FlagInfo(short~, ..)) &&
#| short is Some(short) &&
#| short == value
#| })
#|}
#|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] {
#| format_entries(
#| [
#| for arg in positional_args(cmd.args) {
#| guard !arg.hidden else { continue }
#| (positional_display(arg), arg_doc(arg))
#| }
#| ],
#| )
#|}
#|fn subcommand_entries(cmd : Command) -> Array[String] {
#| let display = [
#| for sub in cmd.subcommands {
#| guard !sub.hidden else { continue }
#| (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.is_empty() {
#| if keep_empty {
#| (
#| $|
#| $|
#| $|\{header}
#| )
#| } else {
#| ""
#| }
#| } else {
#| let body = lines.join("\n")
#| (
#| $|
#| $|
#| $|\{header}
#| $|\{body}
#| )
#| }
#|}
#|fn format_entries(display : Array[(String, String)]) -> Array[String] {
#| let max_len = display.fold(init=0, (acc, item) => acc.max(item.0.length()))
#| fn fmt(name : String, doc : String) -> String {
#| let padding = " ".repeat(max_len - name.length() + 2)
#| " \{name}\{padding}\{doc}"
#| }
#| [
#| for item in display { fmt(item.0, item.1) }
#| ]
#|}
#|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.is_empty() {
#| 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 = []
#| if arg.env is Some(env_name) {
#| notes.push("[env: \{env_name}]")
#| }
#| 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 {
#| help_subcommand_enabled(cmd) || cmd.subcommands.any(sub => !sub.hidden)
#|}
#|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.is_empty() {
#| group.name
#| } else {
#| let tags_text = tags.join(" ")
#| "\{group.name} \{tags_text}"
#| }
#|}
#|fn group_members(cmd : Command, group : ArgGroup) -> String {
#| [
#| for arg in cmd.args {
#| guard !arg.hidden && arg_in_group(arg, group) else { continue }
#| group_member_display(arg)
#| }
#| ].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}
#|#warnings("-deprecated_syntax")
#|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 : StringView,
#| 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() -> ArrayView[String] {
#| let args = @env.args()
#| if args.length() > 1 {
#| args[1:]
#| } 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 {
#| guard args.search_by(arg => {
#| arg.name == member_name
#| })
#| is Some(idx) &&
#| !args[idx].hidden else { continue }
#| arg_usage_token_for_group(args[idx])
#| }
#| ]
#| if members.is_empty() {
#| 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 {
#| if cmd.build_error is Some(err) {
#| raise err
#| }
#| let args = cmd.args
#| let groups = cmd.groups
#| let subcommands = cmd.subcommands
#| if cmd.arg_required_else_help && argv.is_empty() {
#| 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_from_string(name) {
#| None =>
#| if name is [.. "no-", .. target] &&
#| long_index.get_from_string(target)
#| 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_owned()
#| 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:]
#| 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:]
#| 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)
#| if parent_matches.parsed_subcommand is 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))
#| }
#| 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 : StringView,
#| 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_from_string(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 if parent_source is Some(_) {
#| parent_source
#| } else {
#| 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()
#| }
#| if child_source is Some(src) {
#| parent.value_sources[name] = src
#| }
#| } else if parent_vals is Some(pv) && pv.length() > 0 {
#| parent.values[name] = pv.copy()
#| if parent_source is Some(src) {
#| parent.value_sources[name] = src
#| }
#| }
#| }
#| } 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()
#| }
#| if child_source is Some(src) {
#| parent.value_sources[name] = src
#| }
#| } else if parent_vals is Some(pv) && pv.length() > 0 {
#| parent.values[name] = pv.copy()
#| if parent_source is Some(src) {
#| parent.value_sources[name] = src
#| }
#| }
#| }
#|}
#|fn merge_global_flag_from_child(
#| parent : Matches,
#| child : Matches,
#| arg : Arg,
#| name : String,
#|) -> Unit {
#| guard child.flags.get(name) is Some(v) else { return }
#| 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
#| }
#| if strongest_source(parent_source, child_source) is Some(src) {
#| parent.flag_sources[name] = src
#| }
#| } 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
#| if child_source is Some(src) {
#| parent.flag_sources[name] = src
#| }
#| }
#| }
#| } 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
#| if child_source is Some(src) {
#| parent.flag_sources[name] = src
#| }
#| }
#| }
#|}
#|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([])
#| 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(_)) {
#| if parent.values.get(name) is Some(values) {
#| child.values[name] = values.copy()
#| if parent.value_sources.get(name) is Some(src) {
#| child.value_sources[name] = src
#| }
#| }
#| } else if parent.flags.get(name) is Some(v) {
#| child.flags[name] = v
#| if parent.flag_sources.get(name) is Some(src) {
#| child.flag_sources[name] = src
#| }
#| if arg.info is FlagInfo(action=Count, ..) &&
#| parent.counts.get(name) is Some(c) {
#| child.counts[name] = c
#| }
#| }
#| }
#| if child.parsed_subcommand is Some((sub_name, sub_m)) {
#| propagate_globals_to_child(parent, sub_m, globals, Set([]))
#| child.parsed_subcommand = Some((sub_name, sub_m))
#| }
#|}
),
"parser_lookup.mbt": (
#|fn build_long_index(
#| globals : Array[Arg],
#| args : Array[Arg],
#|) -> Map[String, Arg] {
#| Map(
#| [
#| for arg in [..globals, ..args] if arg.info
#| is (FlagInfo(long~, ..) | OptionInfo(long~, ..)) &&
#| long is Some(name) => (name, arg)
#| ],
#| )
#|}
#|fn build_short_index(globals : Array[Arg], args : Array[Arg]) -> Map[Char, Arg] {
#| Map(
#| [
#| for arg in [..globals, ..args] if arg.info
#| is (FlagInfo(short~, ..) | OptionInfo(short~, ..)) &&
#| short is Some(value) => (value, arg)
#| ],
#| )
#|}
#|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([ for arg in args { guard !arg.global else { continue }; arg.name } ])
#|}
#|fn resolve_help_target(
#| cmd : Command,
#| argv : ArrayView[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) -> (StringView, String?) {
#| let parts = [ for part in arg.split("=") { part } ]
#| if parts.length() <= 1 {
#| let name = match parts[0].strip_prefix("--") {
#| Some(view) => view
#| None => parts[0]
#| }
#| (name, None)
#| } else {
#| let name = match parts[0].strip_prefix("--") {
#| Some(view) => view
#| None => parts[0]
#| }
#| let value = parts[1:].join("=")
#| (name, Some(value))
#| }
#|}
),
"parser_positionals.mbt": (
#|fn positional_args(args : Array[Arg]) -> Array[Arg] {
#| [
#| for arg in args { guard arg.info is PositionalInfo(_) else { continue }; arg }
#| ]
#|}
#|fn next_positional(positionals : Array[Arg], collected : Array[String]) -> Arg? {
#| let target = collected.length()
#| let total = target + 1
#| for idx, arg in positionals; cursor = 0 {
#| if cursor >= total {
#| break None
#| }
#| 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_from_string(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 is ['-', .. rest] else { return false }
#| for ch in rest {
#| if ch is ('0'..='9') {
#| continue
#| } else {
#| break false
#| }
#| } nobreak {
#| true
#| }
#|}
),
"parser_suggest.mbt": (
#|fn suggest_long(name : StringView, 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 : StringView, 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 : StringView, b : StringView) -> 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::makei(n + 1, j => j)
#| let mut curr = Array::make(n + 1, 0)
#| for i in 1..<(m + 1) {
#| curr[0] = i
#| for j2 in 1..<(n + 1) {
#| 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
#| }
#| }
#| let temp = prev
#| prev = curr
#| curr = temp
#| }
#| 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([]),
#|) -> ValidationCtx {
#| {
#| inherited_global_names: inherited_global_names.copy(),
#| seen_names: Set([]),
#| seen_long: Set([]),
#| seen_short: Set([]),
#| 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 {
#| if cmd.build_error is Some(err) {
#| raise err
#| }
#| 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([])
#| let arg_seen : @set.Set[String] = Set([])
#| 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.is_empty() {
#| return
#| }
#| let arg_index : @set.Set[String] = Set([])
#| 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.is_empty() {
#| return
#| }
#| let seen : @set.Set[String] = Set([])
#| 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.is_empty() {
#| 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.is_empty() {
#| return
#| }
#| let group_presence = Map([])
#| let group_seen : @set.Set[String] = Set([])
#| let arg_seen : @set.Set[String] = Set([])
#| 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 @string.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_owned()
#| 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": (
#|#warnings("-deprecated_syntax-deprecated")
#|pub struct ValueRange {
#| priv lower : Int
#| priv upper : Int?
#|} derive(Eq, Show, @debug.Debug)
#|pub fn ValueRange::ValueRange(lower? : Int = 0, upper? : Int) -> ValueRange {
#| { lower, upper }
#|}
#|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={},
files={
"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={},
files={
"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 = for trial = 1 {
#| 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()
#| @test.assert_eq(b.summaries.length(), 0)
#| b.keep(123)
#| @test.assert_eq(b.summaries.length(), 0)
#| b.keep(456)
#| @test.assert_eq(b.summaries.length(), 0)
#|}
),
"debug.mbt": (
#|using @debug {trait Debug, type Repr}
#|pub impl Debug for Bench with to_repr(self) {
#| Repr::opaque_(
#| "Bench",
#| Repr::array(self.summaries.map(s => @debug.to_repr(s))),
#| )
#|}
#|pub impl Debug for Timestamp with to_repr(_) {
#| Repr::opaque_("Timestamp", Repr::omitted())
#|}
),
"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, @debug.Debug)
#|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" {
#| @test.assert_eq(std_dev_pct(mean=0.0, std_dev=5.0), 0.0)
#|}
#|test "median_abs_dev_pct zero median" {
#| @test.assert_eq(median_abs_dev_pct(median=0.0, median_abs_dev=3.0), 0.0)
#|}
#|test "percentile edge cases" {
#| @test.assert_eq(percentile(sorted_data=[42.0], pct=50.0), 42.0)
#| @test.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()
#| let summaries = []
#| { buffer, summaries, _storage: @ref.new(()) }
#|}
),
},
)
///|
let moonbitlang_core_bigint_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/bigint",
deps={},
files={
"bigint.mbt": (
#|pub impl ToJson for BigInt with to_json(self : BigInt) -> Json {
#| Json::string(self.to_string())
#|}
#|pub impl Show for BigInt with to_string(self) {
#| BigInt::to_string(self)
#|}
#|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())
#|}
#|pub impl @debug.Debug for BigInt with to_repr(self) {
#| @debug.Repr::integer(self.to_string())
#|}
),
"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 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 : BytesView, signum? : Int = 1) -> BigInt {
#| if signum < 0 {
#| return -1N * BigInt::from_octets(octets, signum=1)
#| }
#| if signum == 0 {
#| return 0N
#| }
#| let str = StringBuilder()
#| 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 = []
#| for v = self {
#| if v > 0 {
#| buf.push(v.to_byte())
#| continue v >> 8
#| } else {
#| break
#| }
#| }
#| 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.asIntN(64, x)
#|pub fn BigInt::from_uint64(x : UInt64) -> BigInt = "%identity"
#|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) + z) % 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
#|}
#|using @debug {trait Debug, type Repr}
#|priv enum Sign {
#| Positive
#| Negative
#|} derive(Eq, @debug.Debug)
#|test "internal repr" {
#| struct BigIntRepr {
#| limbs : FixedArray[UInt]
#| sign : Sign
#| len : Int
#| } derive(Debug)
#| fn convert(b : BigInt) -> BigIntRepr {
#| { limbs: b.limbs, sign: b.sign, len: b.len }
#| }
#| @debug.debug_inspect(
#| [0N, 1, 2, 3, 4, -1, -2, -3, -4].map(convert),
#| content=(
#| #|[
#| #| { limbs: , sign: Positive, len: 1 },
#| #| { limbs: , sign: Positive, len: 1 },
#| #| { limbs: , sign: Positive, len: 1 },
#| #| { limbs: , sign: Positive, len: 1 },
#| #| { limbs: , sign: Positive, len: 1 },
#| #| { limbs: , sign: Negative, len: 1 },
#| #| { limbs: , sign: Negative, len: 1 },
#| #| { limbs: , sign: Negative, len: 1 },
#| #| { limbs: , sign: Negative, len: 1 },
#| #|]
#| ),
#| )
#|}
#|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)
#| let result = { limbs: new_limbs, sign: self.sign, len: new_len }
#| if self.sign == Negative {
#| for i in 0....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 {
#| let mut has_remainder = carry != 0UL
#| if !has_remainder {
#| for i in 0.. 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
#|}
#|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 = []
#| for v = value {
#| if v > zero {
#| let (q, r) = BigInt::grade_school_div(v, base)
#| digits.push(char_from_digit(r.to_int()))
#| continue q
#| } else {
#| break
#| }
#| }
#| let builder = StringBuilder(
#| 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(
#| 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 % modulus
#| let mut base = (self % modulus + modulus) % modulus
#| 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 : BytesView, 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 total_bits = 0
#| for i in 0.. 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_owned()
#|}
),
"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(size_hint=self.len * digits_per_limb + 2)
#| builder.write_char('-')
#| builder
#| } else {
#| StringBuilder(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={},
files={
"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 : BytesView) -> Buffer {
#| let val_len = bytes.length()
#| let buf = new(size_hint=val_len)
#| buf.data.blit_from_bytes(0, bytes.data(), bytes.start_offset(), 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 : BytesView) -> Unit {
#| self.write_bytesview(value)
#|}
#|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())
#|}
),
"debug.mbt": (
#|using @debug {trait Debug, type Repr}
#|pub impl Debug for Buffer with to_repr(self) {
#| Repr::opaque_("Buffer", @debug.to_repr(self.to_bytes().to_array()))
#|}
#|#deprecated("use `to_repr(a)` instead", skip_current_package=true)
#|pub fn Buffer::to_repr(self : Buffer) -> Repr {
#| @debug.to_repr(self)
#|}
#|test "Debug for Buffer" {
#| let buf = new()
#| buf.write_bytes(b"ab")
#| @debug.debug_inspect(buf, content="")
#|}
),
"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={},
files={
"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.is_empty() {
#| 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 : ArrayView[T],
#|) -> Bool {
#| self[:].starts_with(prefix)
#|}
#|pub fn[T : Eq] Array::ends_with(self : Array[T], suffix : ArrayView[T]) -> Bool {
#| self[:].ends_with(suffix)
#|}
#|pub fn[T : Eq] Array::strip_prefix(
#| self : Array[T],
#| prefix : ArrayView[T],
#|) -> ArrayView[T]? {
#| self[:].strip_prefix(prefix)
#|}
#|pub fn[T : Eq] Array::strip_suffix(
#| self : Array[T],
#| suffix : ArrayView[T],
#|) -> ArrayView[T]? {
#| self[:].strip_suffix(suffix)
#|}
#|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? {
#| for v in self; j = 0 {
#| if f(v) {
#| self.unsafe_set(j, v)
#| continue j + 1
#| }
#| continue 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] {
#| if times < 0 {
#| abort("negative repeat count")
#| }
#| let len = self.length()
#| if times == 0 || len == 0 {
#| return []
#| }
#| let total = len * times
#| guard total / times == len else { abort("repeat result too large") }
#| let v = Array::new(capacity=total)
#| 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, x in self; acc = init {
#| continue f(i, acc, x)
#| } 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 in len>..0; acc = init {
#| continue 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)
#|}
#|#locals(f)
#|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 {
#| if iter.size_hint() is Some(n) {
#| self.reserve_capacity(self.length() + n)
#| }
#| for x in iter {
#| self.push(x)
#| }
#|}
#|#locals(rand)
#|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
#|}
#|#locals(f)
#|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)
#| },
#| size_hint=length,
#| ).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)
#| assert_true(dst == [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)
#| assert_true(dst == [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)
#| assert_true(dst == [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)
#| assert_true(dst == [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)
#| assert_true(dst == [0, 0, 2, 3, 0])
#| src[0:2].blit_to(src, dst_offset=3)
#| assert_true(src == [1, 2, 3, 1, 2])
#| src[0:0].blit_to(dst, dst_offset=0)
#| assert_true(dst == [0, 0, 2, 3, 0])
#| src[0:5].blit_to(dst)
#| assert_true(dst == [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)
#| assert_true(dst == [0, 30, 40, 0, 0])
#| src[1:4].blit_to(dst, dst_offset=2)
#| assert_true(dst == [0, 30, 20, 30, 40])
#| src[4:5].blit_to(dst, dst_offset=4)
#| assert_true(dst == [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)
#| assert_true(dst == [5, 0, 0, 0, 0])
#| src[0:1].blit_to(dst, dst_offset=4)
#| assert_true(dst == [5, 0, 0, 0, 1])
#| src[3:5].blit_to(dst, dst_offset=3)
#| assert_true(dst == [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]
#| assert_true(dst == [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)
#| assert_true(dst == [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)
#| assert_true(dst == [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)
#| assert_true(dst == [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)
#| assert_true(dst == [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)
#| assert_true(dst == [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)
#| assert_true(arr == [1, 1, 3, 4, 5])
#| let arr2 : FixedArray[_] = [3, 1, 4, 1, 5]
#| arr2.sort_by_key(x => -x)
#| assert_true(arr2 == [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)
#| assert_true(arr == [1, 2, 3, 4, 5])
#|}
#|test "FixedArray::sort_by: edge cases" {
#| let empty_arr : FixedArray[Int] = []
#| empty_arr.sort_by((a, b) => a - b)
#| assert_true(empty_arr == [])
#| let single_element_arr : FixedArray[_] = [1]
#| single_element_arr.sort_by((a, b) => a - b)
#| assert_true(single_element_arr == [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)
#| assert_true(random_arr1 == [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)
#| assert_true(random_arr2 == [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)
#| assert_true(random_arr3 == [-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)
#| assert_true(large_arr == expected)
#|}
#|test "FixedArray::sort_by: negative numbers" {
#| let negative_arr : FixedArray[_] = [-5, -3, -2, -4, -1]
#| negative_arr.sort_by((a, b) => a - b)
#| assert_true(negative_arr == [-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)
#| assert_true(mixed_arr == [-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_true(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_true(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 : UninitializedArray[T] = UninitializedArray::make(buf_len)
#| UninitializedArray::unsafe_blit(buf, 0, arr.buf(), arr.start() + mid, buf_len)
#| let buf_remaining = for p1 = mid - 1, p2 = buf_len - 1, p = mid + buf_len - 1; p1 >=
#| 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
#| }
#| if buf_remaining >= 0 {
#| UninitializedArray::unsafe_blit(
#| arr.buf(),
#| arr.start(),
#| buf,
#| 0,
#| buf_remaining + 1,
#| )
#| }
#|}
#|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_true(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_true(arr == [1, 2, 3, 4, 5])
#| let arr : FixedArray[_] = [5, 5, 5, 5, 1]
#| f(arr.mut_view())
#| assert_true(arr == [1, 5, 5, 5, 5])
#| let arr : FixedArray[_] = [1, 2, 3, 4, 5]
#| f(arr.mut_view())
#| assert_true(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_true(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_true(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_true(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.is_empty() {
#| 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
#| }
#| },
#| size_hint=if include_empty { len + 1 } else { len },
#| )
#|}
#|pub fn[T] ArrayView::chunks(
#| self : ArrayView[T],
#| size : Int,
#|) -> 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] ArrayView::chunk_by(
#| self : ArrayView[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])
#|}
#|#alias(iterator, deprecated)
#|pub fn[X] ArrayView::iter(self : ArrayView[X]) -> Iter[X] {
#| let mut i = 0
#| let len = self.length()
#| Iter::new(
#| fn() {
#| guard i < len else { None }
#| let elem = self.unsafe_get(i)
#| i += 1
#| Some(elem)
#| },
#| size_hint=len,
#| )
#|}
#|#alias(rev_iterator, deprecated)
#|pub fn[X] ArrayView::rev_iter(self : ArrayView[X]) -> Iter[X] {
#| let len = self.length()
#| let mut i = len
#| Iter::new(
#| fn() {
#| guard i > 0 else { None }
#| i -= 1
#| Some(self.unsafe_get(i))
#| },
#| size_hint=len,
#| )
#|}
#|#alias(iterator2, deprecated)
#|pub fn[X] ArrayView::iter2(self : ArrayView[X]) -> Iter2[Int, X] {
#| let mut i = 0
#| let len = self.length()
#| Iter2::new(
#| fn() {
#| guard i < len else { None }
#| let result = Some((i, self.unsafe_get(i)))
#| i += 1
#| result
#| },
#| size_hint=len,
#| )
#|}
#|#locals(f)
#|pub fn[T] ArrayView::each(
#| self : ArrayView[T],
#| f : (T) -> Unit raise?,
#|) -> Unit raise? {
#| for v in self {
#| f(v)
#| }
#|}
#|#locals(f)
#|pub fn[T] ArrayView::eachi(
#| self : ArrayView[T],
#| f : (Int, T) -> Unit raise?,
#|) -> Unit raise? {
#| for i, v in self {
#| f(i, v)
#| }
#|}
#|#locals(f)
#|pub fn[T] ArrayView::rev_each(
#| self : ArrayView[T],
#| f : (T) -> Unit raise?,
#|) -> Unit raise? {
#| let len = self.length()
#| for i in 0.. Unit raise?,
#|) -> Unit raise? {
#| let len = self.length()
#| for i in 0.. Bool raise?,
#|) -> Bool raise? {
#| for v in self {
#| if !f(v) {
#| return false
#| }
#| }
#| true
#|}
#|#locals(f)
#|#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, x in self {
#| if x == value {
#| break Some(i)
#| }
#| } nobreak {
#| None
#| }
#|}
#|#locals(f)
#|pub fn[T] ArrayView::search_by(
#| self : ArrayView[T],
#| f : (T) -> Bool raise?,
#|) -> Int? raise? {
#| for i, v in self {
#| if f(v) {
#| break Some(i)
#| }
#| } nobreak {
#| None
#| }
#|}
#|pub fn[T : Eq] ArrayView::starts_with(
#| self : ArrayView[T],
#| prefix : ArrayView[T],
#|) -> 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.. ArrayView[T]? {
#| if self.starts_with(prefix) {
#| Some(self[prefix.length():])
#| } else {
#| None
#| }
#|}
#|pub fn[T : Eq] ArrayView::strip_suffix(
#| self : ArrayView[T],
#| suffix : ArrayView[T],
#|) -> ArrayView[T]? {
#| if self.ends_with(suffix) {
#| Some(self[:self.length() - suffix.length()])
#| } else {
#| None
#| }
#|}
#|pub fn[T : Compare] ArrayView::binary_search(
#| self : ArrayView[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
#| }
#| } 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)
#| }
#| }
#|}
#|#locals(f)
#|pub fn[A, B] ArrayView::fold(
#| self : ArrayView[A],
#| init~ : B,
#| f : (B, A) -> B raise?,
#|) -> B raise? {
#| for x in self; acc = init {
#| continue f(acc, x)
#| } nobreak {
#| acc
#| }
#|}
#|#locals(f)
#|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
#| }
#|}
#|#locals(f)
#|pub fn[A, B] ArrayView::foldi(
#| self : ArrayView[A],
#| init~ : B,
#| f : (Int, B, A) -> B raise?,
#|) -> B raise? {
#| for i, x in self; acc = init {
#| continue f(i, acc, x)
#| } nobreak {
#| acc
#| }
#|}
#|#locals(f)
#|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 in len>..0; acc = init {
#| continue f(len - i - 1, acc, self[i])
#| } nobreak {
#| acc
#| }
#|}
#|#locals(f)
#|pub fn[T, U] ArrayView::map(
#| self : ArrayView[T],
#| f : (T) -> U raise?,
#|) -> Array[U] raise? {
#| let arr = Array::make_uninit(self.length())
#| for i, x in self {
#| arr.unsafe_set(i, f(x))
#| }
#| arr
#|}
#|#locals(f)
#|pub fn[T, U] ArrayView::mapi(
#| self : ArrayView[T],
#| f : (Int, T) -> U raise?,
#|) -> Array[U] raise? {
#| let arr = Array::make_uninit(self.length())
#| for i, x in self {
#| arr.unsafe_set(i, f(i, x))
#| }
#| arr
#|}
#|#locals(f)
#|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
#|}
#|#locals(f)
#|pub fn[A, B] ArrayView::filter_map(
#| self : ArrayView[A],
#| f : (A) -> B? raise?,
#|) -> Array[B] raise? {
#| let result = []
#| for x in self {
#| if f(x) is Some(x) {
#| result.push(x)
#| }
#| }
#| result
#|}
#|#alias(to_array, deprecated)
#|pub fn[T] ArrayView::to_owned(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(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.. Array[T] {
#| let len = self.length()
#| let arr = Array::make_uninit(len)
#| for i in 0.. Bool {
#| if self.length() != other.length() {
#| return false
#| }
#| for i, x in self {
#| if !(x == other[i]) {
#| return false
#| }
#| } nobreak {
#| true
#| }
#|}
#|pub impl[T : Compare] Compare for ArrayView[T] with compare(self, other) -> 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, x in self {
#| let cmp = x.compare(other[i])
#| guard cmp == 0 else { break cmp }
#| } nobreak {
#| 0
#| }
#|}
#|pub impl[A : Hash] Hash for ArrayView[A] with hash_combine(self, hasher) {
#| for e in self {
#| hasher.combine(e)
#| }
#|}
#|pub impl[T] Add for ArrayView[T] with add(self, other) {
#| let len_self = self.length()
#| let len_other = other.length()
#| let result = Array::make_uninit(len_self + len_other)
#| UninitializedArray::unsafe_blit(
#| result.buffer(),
#| 0,
#| self.buf(),
#| self.start(),
#| len_self,
#| )
#| UninitializedArray::unsafe_blit(
#| result.buffer(),
#| len_self,
#| other.buf(),
#| other.start(),
#| len_other,
#| )
#| result
#|}
),
"assert.mbt": (
#|fn[T : Show] debug_string(t : T) -> String {
#| let buf = StringBuilder(size_hint=50)
#| t.output(buf)
#| buf.to_string()
#|}
#|#deprecated("use `using @test {assert_eq}` instead", skip_current_package=true)
#|#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~)
#| }
#|}
#|#deprecated("use `using @test {assert_not_eq}` instead", skip_current_package=true)
#|#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? : StringView, loc~ : SourceLoc) -> Unit raise {
#| if !x {
#| let fail_msg : StringView = 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? : StringView,
#| loc~ : SourceLoc,
#|) -> Unit raise {
#| if x {
#| let fail_msg : StringView = 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) {
#| logger.write_string(self.repr())
#|}
#|pub impl Show for SourceLoc with to_string(self) {
#| self.repr()
#|}
#|priv struct SourceLocRepr {
#| filename : StringView
#| start_line : StringView
#| start_column : StringView
#| end_line : StringView
#| end_column : StringView
#|}
#|fn SourceLocRepr::parse(repr : String) -> SourceLocRepr {
#| lexmatch repr[:] with longest {
#| (
#| (".+" as filename)
#| ":"
#| ("[[:digit:]]+" as start_line)
#| ":"
#| ("[[:digit:]]+" as start_column)
#| "-"
#| ("[[:digit:]]+" as end_line)
#| ":"
#| ("[[:digit:]]+" as end_column)
#| "@"
#| ("[^:]*" as _module)
#| ) => { filename, start_line, start_column, end_line, end_column }
#| _ => panic()
#| }
#|}
#|fn SourceLocRepr::to_json_string(self : SourceLocRepr) -> String {
#| let sb = StringBuilder()
#| 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?])
#|#warnings("-deprecated")
#|pub impl Show for ArgsLoc with output(self, logger) {
#| let ArgsLoc(arr) = self
#| arr.output(logger)
#|}
#|pub fn ArgsLoc::to_json(self : ArgsLoc) -> String {
#| let buf = StringBuilder(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)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_byte_aligned(
#| bs : ArrayView[Byte],
#| byte_offset : Int,
#|) -> UInt {
#| bs.unsafe_get(byte_offset).to_uint()
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_byte_signed_aligned(
#| bs : ArrayView[Byte],
#| byte_offset : Int,
#|) -> Int {
#| bs.unsafe_get(byte_offset).to_uint().extend_sign(8)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_uint16_le_aligned(
#| bs : ArrayView[Byte],
#| byte_offset : Int,
#|) -> UInt {
#| fixedarray_read_uint16_le(
#| buffer_to_fixedarray(bs.buf()),
#| bs.start() + byte_offset,
#| ).to_uint()
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_uint16_be_aligned(
#| bs : ArrayView[Byte],
#| byte_offset : Int,
#|) -> UInt {
#| fixedarray_read_uint16_be(
#| buffer_to_fixedarray(bs.buf()),
#| bs.start() + byte_offset,
#| ).to_uint()
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_int16_le_aligned(
#| bs : ArrayView[Byte],
#| byte_offset : Int,
#|) -> Int {
#| bs.unsafe_extract_uint16_le_aligned(byte_offset).extend_sign(16)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_int16_be_aligned(
#| bs : ArrayView[Byte],
#| byte_offset : Int,
#|) -> Int {
#| bs.unsafe_extract_uint16_be_aligned(byte_offset).extend_sign(16)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_uint_le_aligned(
#| bs : ArrayView[Byte],
#| byte_offset : Int,
#|) -> UInt {
#| fixedarray_read_uint32_le(
#| buffer_to_fixedarray(bs.buf()),
#| bs.start() + byte_offset,
#| )
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_uint_be_aligned(
#| bs : ArrayView[Byte],
#| byte_offset : Int,
#|) -> UInt {
#| fixedarray_read_uint32_be(
#| buffer_to_fixedarray(bs.buf()),
#| bs.start() + byte_offset,
#| )
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_int_le_aligned(
#| bs : ArrayView[Byte],
#| byte_offset : Int,
#|) -> Int {
#| bs.unsafe_extract_uint_le_aligned(byte_offset).reinterpret_as_int()
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_int_be_aligned(
#| bs : ArrayView[Byte],
#| byte_offset : Int,
#|) -> Int {
#| bs.unsafe_extract_uint_be_aligned(byte_offset).reinterpret_as_int()
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_uint64_le_aligned(
#| bs : ArrayView[Byte],
#| byte_offset : Int,
#|) -> UInt64 {
#| fixedarray_read_uint64_le(
#| buffer_to_fixedarray(bs.buf()),
#| bs.start() + byte_offset,
#| )
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_uint64_be_aligned(
#| bs : ArrayView[Byte],
#| byte_offset : Int,
#|) -> UInt64 {
#| fixedarray_read_uint64_be(
#| buffer_to_fixedarray(bs.buf()),
#| bs.start() + byte_offset,
#| )
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_int64_le_aligned(
#| bs : ArrayView[Byte],
#| byte_offset : Int,
#|) -> Int64 {
#| bs.unsafe_extract_uint64_le_aligned(byte_offset).reinterpret_as_int64()
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_int64_be_aligned(
#| bs : ArrayView[Byte],
#| byte_offset : Int,
#|) -> Int64 {
#| bs.unsafe_extract_uint64_be_aligned(byte_offset).reinterpret_as_int64()
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_byte_aligned(
#| bs : BytesView,
#| byte_offset : Int,
#|) -> UInt {
#| bs.unsafe_get(byte_offset).to_uint()
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_byte_signed_aligned(
#| bs : BytesView,
#| byte_offset : Int,
#|) -> Int {
#| bs.unsafe_get(byte_offset).to_uint().extend_sign(8)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_uint16_le_aligned(
#| bs : BytesView,
#| byte_offset : Int,
#|) -> UInt {
#| bs.unsafe_read_uint16_le(byte_offset).to_uint()
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_uint16_be_aligned(
#| bs : BytesView,
#| byte_offset : Int,
#|) -> UInt {
#| bs.unsafe_read_uint16_be(byte_offset).to_uint()
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_int16_le_aligned(
#| bs : BytesView,
#| byte_offset : Int,
#|) -> Int {
#| bs.unsafe_extract_uint16_le_aligned(byte_offset).extend_sign(16)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_int16_be_aligned(
#| bs : BytesView,
#| byte_offset : Int,
#|) -> Int {
#| bs.unsafe_extract_uint16_be_aligned(byte_offset).extend_sign(16)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_uint_le_aligned(
#| bs : BytesView,
#| byte_offset : Int,
#|) -> UInt {
#| bs.unsafe_read_uint32_le(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_uint_be_aligned(
#| bs : BytesView,
#| byte_offset : Int,
#|) -> UInt {
#| bs.unsafe_read_uint32_be(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_int_le_aligned(
#| bs : BytesView,
#| byte_offset : Int,
#|) -> Int {
#| bs.unsafe_read_uint32_le(byte_offset).reinterpret_as_int()
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_int_be_aligned(
#| bs : BytesView,
#| byte_offset : Int,
#|) -> Int {
#| bs.unsafe_read_uint32_be(byte_offset).reinterpret_as_int()
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_uint64_le_aligned(
#| bs : BytesView,
#| byte_offset : Int,
#|) -> UInt64 {
#| bs.unsafe_read_uint64_le(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_uint64_be_aligned(
#| bs : BytesView,
#| byte_offset : Int,
#|) -> UInt64 {
#| bs.unsafe_read_uint64_be(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_int64_le_aligned(
#| bs : BytesView,
#| byte_offset : Int,
#|) -> Int64 {
#| bs.unsafe_read_uint64_le(byte_offset).reinterpret_as_int64()
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_int64_be_aligned(
#| bs : BytesView,
#| byte_offset : Int,
#|) -> Int64 {
#| bs.unsafe_read_uint64_be(byte_offset).reinterpret_as_int64()
#|}
),
"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"
#|#locals(value)
#|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_uninit(len)
#| UninitializedArray::unsafe_blit_fixed(
#| rv.buffer(),
#| 0,
#| unsafe_from_bytes(self),
#| 0,
#| len,
#| )
#| rv
#|}
#|pub fn BytesView::to_array(self : BytesView) -> Array[Byte] {
#| let len = self.length()
#| let rv = Array::make_uninit(len)
#| UninitializedArray::unsafe_blit_fixed(
#| rv.buffer(),
#| 0,
#| unsafe_from_bytes(self.data()),
#| self.start_offset(),
#| len,
#| )
#| rv
#|}
#|#alias(iterator, deprecated)
#|pub fn Bytes::iter(self : Bytes) -> 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)
#| },
#| size_hint=len,
#| )
#|}
#|#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)
#| },
#| size_hint=len,
#| )
#|}
#|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)
#| rv.blit_from_bytes(0, self, 0, len_self)
#| rv.blit_from_bytes(len_self, other, 0, len_other)
#| unsafe_to_bytes(rv)
#|}
#|pub impl Hash for Bytes with hash_combine(self, hasher) {
#| hasher.combine(self[:])
#|}
#|pub fn Bytes::repeat(self : Self, count : Int) -> Bytes {
#| if count < 0 {
#| abort("negative repeat count")
#| }
#| if count == 0 || self.is_empty() {
#| return []
#| }
#| if count == 1 {
#| return self
#| }
#| let len = self.length()
#| let total = len * count
#| guard total / count == len else { abort("repeat result too large") }
#| 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": (
#|#borrow(bytes)
#|#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())
#| }
#|}
#|#borrow(bytes)
#|#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())
#| }
#|}
#|#borrow(bytes)
#|#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())
#| }
#|}
#|#borrow(bytes)
#|#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())
#| }
#|}
#|#borrow(bytes)
#|#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())
#| }
#|}
#|#borrow(bytes)
#|#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())
#| }
#|}
#|#borrow(bytes)
#|#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
#| }
#|}
#|#borrow(bytes)
#|#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
#| }
#|}
#|#borrow(bytes)
#|#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
#| }
#|}
#|#borrow(bytes)
#|#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
#| }
#|}
#|#borrow(bytes)
#|#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
#| }
#|}
#|#borrow(bytes)
#|#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)
#|}
#|fn buffer_to_fixedarray(buf : UninitializedArray[Byte]) -> FixedArray[Byte] = "%identity"
#|#borrow(bytes)
#|#intrinsic("%bytes.unsafe_read_uint16_le")
#|fn fixedarray_read_uint16_le(bytes : FixedArray[Byte], index : Int) -> UInt16 {
#| for i in 0..<=1; result = (0 : UInt16) {
#| continue result | (bytes.unsafe_get(i + index).to_uint16() << (8 * i))
#| } nobreak {
#| result
#| }
#|}
#|#borrow(bytes)
#|#intrinsic("%bytes.unsafe_read_uint16_be")
#|fn fixedarray_read_uint16_be(bytes : FixedArray[Byte], 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
#| }
#|}
#|#borrow(bytes)
#|#intrinsic("%bytes.unsafe_read_uint32_le")
#|fn fixedarray_read_uint32_le(bytes : FixedArray[Byte], index : Int) -> UInt {
#| for i in 0..<=3; result = (0 : UInt) {
#| continue result | (bytes.unsafe_get(i + index).to_uint() << (8 * i))
#| } nobreak {
#| result
#| }
#|}
#|#borrow(bytes)
#|#intrinsic("%bytes.unsafe_read_uint32_be")
#|fn fixedarray_read_uint32_be(bytes : FixedArray[Byte], 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
#| }
#|}
#|#borrow(bytes)
#|#intrinsic("%bytes.unsafe_read_uint64_le")
#|fn fixedarray_read_uint64_le(bytes : FixedArray[Byte], index : Int) -> UInt64 {
#| for i in 0..<=7; result = (0 : UInt64) {
#| continue result | (bytes.unsafe_get(i + index).to_uint64() << (8 * i))
#| } nobreak {
#| result
#| }
#|}
#|#borrow(bytes)
#|#intrinsic("%bytes.unsafe_read_uint64_be")
#|fn fixedarray_read_uint64_be(bytes : FixedArray[Byte], 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
#| }
#|}
),
"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)
#|}
#|pub fn Bytes::get_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 { None }
#| Some(BytesView::make(self, start, end - start))
#|}
#|pub fn BytesView::get_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 { None }
#| Some(BytesView::make(self.bytes(), self.start() + 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)
#| },
#| size_hint=len,
#| )
#|}
#|#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)
#| },
#| size_hint=len,
#| )
#|}
#|#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 (b' '..=b'~') && byte != b'"' && byte != b'\\' {
#| 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, byte in self {
#| guard byte == other.unsafe_get(i) else { return false }
#| }
#| true
#|}
#|pub impl Compare for BytesView with compare(self, other) -> 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, b1 in self {
#| let b2 = other.unsafe_get(i)
#| let cmp = b1.compare(b2)
#| guard cmp == 0 else { return cmp }
#| }
#| 0
#|}
#|pub fn BytesView::lexical_compare(self : BytesView, other : BytesView) -> 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()
#|}
#|#alias(to_bytes, deprecated="Use `to_owned` to allocate an owned `Bytes` from a `BytesView`")
#|pub fn BytesView::to_owned(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()
#| for byte in self {
#| if byte is (b' '..=b'~') && byte != b'"' && byte != b'\\' {
#| 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()
#| 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 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()
#| 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 `Map([], capacity=...)` instead")
#|pub fn[K, V] Map::new(capacity? : Int = default_init_capacity) -> Map[K, V] {
#| new_map(capacity)
#|}
#|#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)
#|}
#|#intrinsic("%f64.to_string")
#|pub fn Double::to_string(self : Double) -> String {
#| ryu_to_string(self)
#|}
#|pub impl Show for Double with to_string(self) {
#| Double::to_string(self)
#|}
#|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 len = to - from
#| let buffer = FixedArray::make(len, UInt16::default())
#| for i in 0.. 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_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_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_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": (
#|#warnings("-deprecated_syntax")
#|pub(all) suberror Failure {
#| Failure(String)
#|} derive(ToJson, Show)
#|#callsite(autofill(loc))
#|pub fn[T] fail(msg : StringView, 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)
#|}
#|#locals(f)
#|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")
#|}
#|#locals(f)
#|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")
#|}
#|#locals(f)
#|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")
#|}
#|#locals(f)
#|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")
#|}
#|#locals(f)
#|pub fn[T, U] FixedArray::map(
#| self : FixedArray[T],
#| f : (T) -> U raise?,
#|) -> FixedArray[U] raise? {
#| if self.is_empty() {
#| return []
#| }
#| let res = FixedArray::make(self.length(), f(self[0]))
#| for i in 1.. x)
#| assert_true(empty == [])
#| let simple_arr : FixedArray[_] = [6]
#| let simple_doubled = simple_arr.map(x => x * 2)
#| assert_true(simple_doubled == [12])
#| let arr : FixedArray[_] = [1, 2, 3, 4, 5]
#| let doubled = arr.map(x => x * 2)
#| assert_true(doubled == [2, 4, 6, 8, 10])
#|}
#|#locals(f)
#|pub fn[T, U] FixedArray::mapi(
#| self : FixedArray[T],
#| f : (Int, T) -> U raise?,
#|) -> FixedArray[U] raise? {
#| if self.is_empty() {
#| return []
#| }
#| let res = FixedArray::make(self.length(), f(0, self[0]))
#| for i in 1.. x + i)
#| assert_true(empty == [])
#| let simple_arr : FixedArray[_] = [6]
#| let simple_doubled = simple_arr.mapi((i, x) => x * 2 + i)
#| assert_true(simple_doubled == [12])
#| let arr : FixedArray[_] = [1, 2, 3, 4, 5]
#| let doubled = arr.mapi((i, x) => x * 2 + i)
#| assert_true(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_true(array == [1, 2, 3, 4, 5])
#|}
#|#locals(f)
#|pub fn[A, B] FixedArray::fold(
#| self : FixedArray[A],
#| init~ : B,
#| f : (B, A) -> B raise?,
#|) -> B raise? {
#| for x in self; acc = init {
#| continue f(acc, x)
#| } 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")
#|}
#|#locals(f)
#|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")
#|}
#|#locals(f)
#|pub fn[A, B] FixedArray::foldi(
#| self : FixedArray[A],
#| init~ : B,
#| f : (Int, B, A) -> B raise?,
#|) -> B raise? {
#| for i, x in self; acc = init {
#| continue f(i, acc, x)
#| } 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")
#|}
#|#locals(f)
#|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 in len>..0; acc = init {
#| continue 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_true(arr == [1])
#| }
#| {
#| let arr : FixedArray[_] = [1, 2]
#| arr.swap(0, 0)
#| assert_true(arr == [1, 2])
#| arr.swap(0, 1)
#| assert_true(arr == [2, 1])
#| }
#| let arr : FixedArray[_] = [1, 2, 3, 4, 5]
#| arr.swap(3, 3)
#| assert_true(arr == [1, 2, 3, 4, 5])
#| arr.swap(1, 3)
#| assert_true(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_true(arr == [])
#| }
#| {
#| let arr : FixedArray[_] = [6]
#| arr.fill(5)
#| assert_true(arr == [5])
#| }
#| let arr : FixedArray[_] = [0, 0, 0, 0, 0]
#| arr.fill(3)
#| assert_true(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_true(arr.search(3) == None)
#| assert_true(arr.search(-1) == None)
#| }
#| {
#| let arr : FixedArray[_] = [3]
#| assert_true(arr.search(3) == Some(0))
#| assert_true(arr.search(-1) == None)
#| }
#| let arr : FixedArray[_] = [1, 2, 3, 4, 5]
#| assert_true(arr.search(1) == Some(0))
#| assert_true(arr.search(5) == Some(4))
#| assert_true(arr.search(3) == Some(2))
#| assert_true(arr.search(-1) == None)
#|}
#|pub fn[T : Eq] FixedArray::contains(self : FixedArray[T], value : T) -> Bool {
#| for x in self {
#| if x == value {
#| return true
#| }
#| }
#| false
#|}
#|test "contains" {
#| {
#| let arr : FixedArray[Int] = []
#| assert_false(arr.contains(3))
#| assert_false(arr.contains(-1))
#| }
#| {
#| let arr : FixedArray[_] = [3]
#| assert_true(arr.contains(3))
#| assert_false(arr.contains(-1))
#| }
#| let arr : FixedArray[_] = [3, 4, 5]
#| assert_true(arr.contains(3))
#| assert_true(arr.contains(4))
#| assert_true(arr.contains(5))
#| assert_false(arr.contains(6))
#|}
#|pub fn[T : Eq] FixedArray::starts_with(
#| self : FixedArray[T],
#| prefix : ArrayView[T],
#|) -> 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 : ArrayView[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, x in self {
#| if x != that[i] {
#| return false
#| }
#| }
#| true
#|}
#|pub impl[T : Hash] Hash for FixedArray[T] with hash_combine(self, hasher) {
#| for v in self {
#| v.hash_combine(hasher)
#| }
#|}
#|test "equal" {
#| {
#| inspect(([] : FixedArray[Int]) == [], content="true")
#| inspect(([] : FixedArray[_]) == [1], content="false")
#| inspect(([1, 2] : FixedArray[_]) == [], content="false")
#| }
#| {
#| inspect(([1] : FixedArray[_]) == [1], content="true")
#| inspect(([1] : FixedArray[_]) == [2], content="false")
#| inspect(([1, 2] : FixedArray[_]) == [1], content="false")
#| inspect(([1] : FixedArray[_]) == [1, 2], content="false")
#| }
#| inspect(([1, 2, 3, 4, 5] : FixedArray[_]) == [1, 2, 3, 4, 5], content="true")
#| inspect(([1, 2, 3, 4, 5] : FixedArray[_]) == [1, 2, 3, 4], content="false")
#| inspect(([1, 2, 3, 4] : FixedArray[_]) == [1, 2, 3, 4, 5], content="false")
#| inspect(([1, 2, 3, 4, 5] : FixedArray[_]) == [6, 2, 3, 4, 5], content="false")
#| inspect(([1, 2, 3, 4, 5] : FixedArray[_]) == [1, 2, 6, 4, 5], content="false")
#| inspect(([1, 2, 3, 4, 5] : FixedArray[_]) == [1, 2, 3, 4, 6], content="false")
#|}
#|pub impl[T : Compare] Compare for FixedArray[T] with compare(self, other) {
#| 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.. {
#| if i < slen {
#| self[i]
#| } else {
#| other[i - slen]
#| }
#| })
#|}
#|test "add" {
#| {
#| assert_true(([] : FixedArray[Int]) + [] == [])
#| assert_true(([] : FixedArray[_]) + [1, 2, 3, 4, 5] == [1, 2, 3, 4, 5])
#| assert_true(([1, 2, 3, 4, 5] : FixedArray[_]) + [] == [1, 2, 3, 4, 5])
#| }
#| {
#| assert_true(([1] : FixedArray[_]) + [2] == [1, 2])
#| assert_true(([1] : FixedArray[_]) + [1, 2, 3, 4, 5] == [1, 1, 2, 3, 4, 5])
#| assert_true(([1, 2, 3, 4, 5] : FixedArray[_]) + [1] == [1, 2, 3, 4, 5, 1])
#| }
#| assert_true(
#| ([1, 2, 3, 4, 5] : FixedArray[_]) + [6, 7, 8, 9, 10] ==
#| [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()
#| 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": (
#|#owned(dst, src)
#|#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]
#| }
#| }
#|}
#|#owned(dst, src)
#|#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)
#|}
#|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"
#|pub using @abort {abort}
#|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"
#|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] {
#| until_impl(self, end, step, inclusive)
#|}
#|pub fn Int64::until(
#| self : Int64,
#| end : Int64,
#| step? : Int64 = 1L,
#| inclusive? : Bool = false,
#|) -> Iter[Int64] {
#| until_impl(self, end, step, inclusive)
#|}
#|pub fn Double::until(
#| self : Double,
#| end : Double,
#| step? : Double = 1.0,
#| inclusive? : Bool = false,
#|) -> Iter[Double] {
#| until_impl(self, end, step, inclusive)
#|}
),
"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] {
#| f : () -> X?
#| mut size_hint : Int?
#|}
#|#alias(peek, deprecated)
#|#alias(head)
#|pub fn[X] Iter::next(self : Iter[X]) -> X? {
#| let result = (self.f)()
#| match (result, self.size_hint) {
#| (Some(_), Some(n)) =>
#| self.size_hint = if n > 0 { Some(n - 1) } else { Some(0) }
#| (None, _) => self.size_hint = Some(0)
#| _ => ()
#| }
#| result
#|}
#|pub fn[X] Iter::size_hint(self : Iter[X]) -> Int? {
#| self.size_hint
#|}
#|#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
#| }
#| }
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[X : Show] Show for Iter[X]
#|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) {
#| [
#| for x in self { x }
#| ]
#|}
#|#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?, size_hint? : Int) -> Iter[X] {
#| let size_hint = match size_hint {
#| Some(n) if n > 0 => Some(n)
#| Some(_) => Some(0)
#| None => None
#| }
#| { f, size_hint }
#|}
#|pub fn[X] Iter::empty() -> Iter[X] {
#| Iter::new(() => None, size_hint=0)
#|}
#|pub fn[X] Iter::singleton(elem : X) -> Iter[X] {
#| let mut consumed = false
#| Iter::new(
#| fn() {
#| if consumed {
#| None
#| } else {
#| consumed = true
#| Some(elem)
#| }
#| },
#| size_hint=1,
#| )
#|}
#|pub fn[X] Iter::repeat(x : X) -> Iter[X] {
#| Iter::new(() => Some(x))
#|}
#|pub fn[X] Iter::filter(self : Iter[X], f : (X) -> Bool) -> Iter[X] {
#| Iter::new(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] {
#| {
#| f: fn() {
#| match self.next() {
#| Some(x) => Some(f(x))
#| None => None
#| }
#| },
#| size_hint: self.size_hint,
#| }
#|}
#|pub fn[X, Y] Iter::mapi(self : Iter[X], f : (Int, X) -> Y) -> Iter[Y] {
#| let mut i = 0
#| {
#| f: fn() {
#| match self.next() {
#| Some(x) => {
#| let result = f(i, x)
#| i += 1
#| Some(result)
#| }
#| None => None
#| }
#| },
#| size_hint: self.size_hint,
#| }
#|}
#|pub fn[X, Y] Iter::filter_map(self : Iter[X], f : (X) -> Y?) -> Iter[Y] {
#| Iter::new(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())
#| Iter::new(fn() {
#| guard current_iter is Some(iter) else { None }
#| for x = iter.next() {
#| match x {
#| Some(_) as elem => break elem
#| None => {
#| guard self.next() is Some(x) else { break 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 : StringView) -> String {
#| let result = StringBuilder()
#| if self.next() is Some(x) {
#| result.write_string(x)
#| while self.next() is Some(x) {
#| result.write_view(sep)
#| result.write_string(x)
#| }
#| }
#| result.to_string()
#|}
#|pub fn[X] Iter::tap(self : Iter[X], f : (X) -> Unit) -> Iter[X] {
#| {
#| f: fn() {
#| let result = self.next()
#| if result is Some(x) {
#| f(x)
#| }
#| result
#| },
#| size_hint: self.size_hint,
#| }
#|}
#|pub fn[X] Iter::take(self : Iter[X], n : Int) -> Iter[X] {
#| let mut remaining = n
#| let size_hint = match self.size_hint {
#| Some(_) if n <= 0 => Some(0)
#| Some(len) if n < len => Some(n)
#| Some(len) => Some(len)
#| None if n <= 0 => Some(0)
#| None => None
#| }
#| {
#| f: fn() {
#| guard remaining > 0 else { None }
#| let result = self.next()
#| if result is Some(_) {
#| remaining -= 1
#| }
#| result
#| },
#| size_hint,
#| }
#|}
#|pub fn[X] Iter::take_while(self : Iter[X], f : (X) -> Bool) -> Iter[X] {
#| let mut still_running = true
#| Iter::new(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
#| Iter::new(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
#| let size_hint = match self.size_hint {
#| Some(len) if n <= 0 => Some(len)
#| Some(len) if n < len => Some(len - n)
#| Some(_) => Some(0)
#| None => None
#| }
#| {
#| f: fn() {
#| while remaining > 0 {
#| guard self.next() is Some(_) else { break None }
#| remaining -= 1
#| } nobreak {
#| self.next()
#| }
#| },
#| size_hint,
#| }
#|}
#|pub fn[X] Iter::drop_while(self : Iter[X], f : (X) -> Bool) -> Iter[X] {
#| let mut dropped = false
#| Iter::new(fn() {
#| if !dropped {
#| dropped = true
#| for x = self.next() {
#| match x {
#| Some(x) if f(x) => continue self.next()
#| result => break 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
#| let size_hint = match (self.size_hint, other.size_hint) {
#| (Some(n), Some(m)) => Some(n + m)
#| _ => None
#| }
#| {
#| f: fn() {
#| if in_first {
#| let result = self.next()
#| if result is None {
#| in_first = false
#| other.next()
#| } else {
#| result
#| }
#| } else {
#| other.next()
#| }
#| },
#| size_hint,
#| }
#|}
#|#alias(combine)
#|pub fn[X, Y] Iter::zip(self : Iter[X], other : Iter[Y]) -> Iter[(X, Y)] {
#| let size_hint = match (self.size_hint, other.size_hint) {
#| (Some(n), Some(m)) if n < m => Some(n)
#| (Some(_), Some(m)) => Some(m)
#| (Some(0), _) => Some(0)
#| (_, Some(0)) => Some(0)
#| _ => None
#| }
#| {
#| f: fn() {
#| guard self.next() is Some(x) else { None }
#| guard other.next() is Some(y) else { None }
#| Some((x, y))
#| },
#| size_hint,
#| }
#|}
#|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 = match self.size_hint {
#| Some(n) => Array::new(capacity=n)
#| None => []
#| }
#| 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
#| Iter2({
#| f: () => {
#| guard self.next() is Some(elem) else { None }
#| let result = Some((i, elem))
#| i += 1
#| result
#| },
#| size_hint: self.size_hint,
#| })
#|}
#|pub fn[X] Iter::last(self : Iter[X]) -> X? {
#| for x = (None : X?), y = self.next() {
#| match (x, y) {
#| (last, None) => break 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
#| let size_hint = match self.size_hint {
#| Some(0) => Some(0)
#| Some(n) => Some(n * 2 - 1)
#| None => None
#| }
#| {
#| f: 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
#| }
#| }
#| },
#| size_hint,
#| }
#|}
#|#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
#| let size_hint = match self.size_hint {
#| Some(_) if end <= start => Some(0)
#| Some(len) if start >= len => Some(0)
#| Some(len) if end < len => Some(end - start)
#| Some(len) => Some(len - start)
#| None if end <= start => Some(0)
#| None => None
#| }
#| {
#| f: 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
#| },
#| size_hint,
#| }
#| }
#| }
#|}
#|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)?, size_hint? : Int) -> Iter2[X, Y] {
#| let size_hint = match size_hint {
#| Some(n) if n > 0 => Some(n)
#| Some(_) => Some(0)
#| None => None
#| }
#| Iter2({ f, size_hint })
#|}
#|#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()
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[X : Show, Y : Show] Show for Iter2[X, Y]
#|#warnings("-deprecated")
#|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([], 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
#|}
#|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
#|}
#|let default_init_capacity = 8
#|fn[K, V] new_map(capacity : Int) -> 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,
#| }
#|}
#|fn capacity_for_length(length : Int) -> Int {
#| let mut capacity = length.next_power_of_two()
#| if length > calc_grow_threshold(capacity) {
#| capacity *= 2
#| }
#| capacity
#|}
#|#alias(from_array)
#|pub fn[K : Hash + Eq, V] Map::Map(
#| arr : ArrayView[(K, V)],
#| capacity? : Int,
#|) -> Map[K, V] {
#| let length = arr.length()
#| let capacity = match capacity {
#| Some(capacity) => capacity.max(capacity_for_length(length))
#| None =>
#| if length == 0 {
#| default_init_capacity
#| } else {
#| capacity_for_length(length)
#| }
#| }
#| let m = new_map(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::update_or_default(
#| self : Map[K, V],
#| key : K,
#| default : V,
#| f : (V) -> V,
#|) -> Unit {
#| let hash = key.hash()
#| let (idx, psl, push_away) = for psl = 0, idx = hash & self.capacity_mask {
#| match self.entries[idx] {
#| Some(entry) => {
#| if entry.hash == hash && entry.key == key {
#| entry.value = f(entry.value)
#| return
#| }
#| if psl > entry.psl {
#| break (idx, psl, Some(entry))
#| }
#| continue psl + 1, (idx + 1) & self.capacity_mask
#| }
#| None => break (idx, psl, None)
#| }
#| }
#| if self.size >= self.grow_at {
#| self.grow()
#| self.set_with_hash(key, default, hash)
#| } else {
#| if push_away is Some(entry) {
#| self.push_away(idx, entry)
#| }
#| let entry = { prev: self.tail, next: None, psl, hash, key, value: default }
#| self.add_entry_to_tail(idx, entry)
#| }
#|}
#|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 {
#| for cur = idx {
#| let next = (cur + 1) & self.capacity_mask
#| match self.entries[next] {
#| None | Some({ psl: 0, .. }) => {
#| self.entries[cur] = None
#| break
#| }
#| Some(entry) => {
#| entry.psl -= 1
#| self.set_entry(entry, cur)
#| continue 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
#| for x = old_head {
#| match x {
#| 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
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[K : Show, V : Show] Show for Map[K, V]
#|pub impl[K : Show, V : Show] Show for Map[K, V] with output(self, logger) {
#| logger.write_string("{")
#| for x = 0, y = self.head {
#| match (x, y) {
#| (_, None) => break 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? {
#| for x = self.head {
#| match x {
#| 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? {
#| for x = 0, y = self.head {
#| match (x, y) {
#| (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
#| let len = self.size
#| let mut remaining = len
#| Iter::new(
#| fn() {
#| guard remaining > 0 && curr_entry is Some({ key, value, next, .. }) else {
#| None
#| }
#| curr_entry = next
#| remaining -= 1
#| Some((key, value))
#| },
#| size_hint=len,
#| )
#|}
#|#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
#| let len = self.size
#| let mut remaining = len
#| Iter::new(
#| fn() {
#| guard remaining > 0 && curr_entry is Some({ key, next, .. }) else { None }
#| curr_entry = next
#| remaining -= 1
#| Some(key)
#| },
#| size_hint=len,
#| )
#|}
#|pub fn[K, V] Map::values(self : Map[K, V]) -> Iter[V] {
#| let mut curr_entry = self.head
#| let len = self.size
#| let mut remaining = len
#| Iter::new(
#| fn() {
#| guard remaining > 0 && curr_entry is Some({ value, next, .. }) else {
#| None
#| }
#| curr_entry = next
#| remaining -= 1
#| Some(value)
#| },
#| size_hint=len,
#| )
#|}
#|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
#| for x = self.head {
#| match x {
#| 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 m = new_map(capacity_for_length(length))
#| for e in arr {
#| m.set(e.0, e.1)
#| }
#| m
#|}
#|#alias(from_iterator, deprecated)
#|pub fn[K : Hash + Eq, V] Map::from_iter(iter : Iter[(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() {
#| new_map(default_init_capacity)
#|}
#|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)
#| for entry = last, idx = self.tail, next = (None : Entry[K, V2]?) {
#| let { prev, psl, hash, key, value, .. } = entry
#| 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)
#| break
#| }
#| }
#| 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)
#| for entry = last, idx = self.tail, next = (None : Entry[K, V]?) {
#| let { prev, psl, hash, key, value, .. } = entry
#| 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)
#| break
#| }
#| }
#| 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
#| }
#| for x = other.head {
#| match x {
#| 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 {
#| for x = self.head, y = false {
#| match (x, y) {
#| (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
#| }
#| break
#| }
#| }
#| }
#|}
#|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)
#|}
#|#alias(to_array, deprecated)
#|pub fn[T] MutArrayView::to_owned(self : MutArrayView[T]) -> Array[T] {
#| self[:].to_owned()
#|}
#|#alias(iterator, deprecated)
#|pub fn[X] MutArrayView::iter(self : MutArrayView[X]) -> Iter[X] {
#| let mut i = 0
#| let len = self.length()
#| Iter::new(
#| fn() {
#| guard i < len else { None }
#| let elem = self.unsafe_get(i)
#| i += 1
#| Some(elem)
#| },
#| size_hint=len,
#| )
#|}
#|#alias(rev_iterator, deprecated)
#|pub fn[X] MutArrayView::rev_iter(self : MutArrayView[X]) -> Iter[X] {
#| let len = self.length()
#| let mut i = len
#| Iter::new(
#| fn() {
#| guard i > 0 else { None }
#| i -= 1
#| Some(self.unsafe_get(i))
#| },
#| size_hint=len,
#| )
#|}
#|#alias(iterator2, deprecated)
#|pub fn[X] MutArrayView::iter2(self : MutArrayView[X]) -> Iter2[Int, X] {
#| let mut i = 0
#| let len = self.length()
#| Iter2::new(
#| fn() {
#| guard i < len else { None }
#| let result = Some((i, self.unsafe_get(i)))
#| i += 1
#| result
#| },
#| size_hint=len,
#| )
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[X : Show] Show for MutArrayView[X]
#|#warnings("-deprecated")
#|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
#|}
#|pub(open) trait Sub {
#| sub(Self, Self) -> Self
#|}
#|pub(open) trait Mul {
#| mul(Self, Self) -> Self
#|}
#|pub(open) trait Div {
#| div(Self, Self) -> Self
#|}
#|pub(open) trait Neg {
#| neg(Self) -> Self
#|}
#|pub(open) trait Mod {
#| 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
#|}
#|pub(open) trait Shr {
#| shr(Self, Int) -> Self
#|}
),
"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
#| }
#|}
#|#deprecated("Option does not have a meaningful string representation")
#|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
#|}
),
"range.mbt": (
#|fn[T : Add + Compare + Default] until_impl(
#| start : T,
#| end : T,
#| step : T,
#| inclusive : Bool,
#|) -> Iter[T] {
#| let zero = T::default()
#| if step == zero {
#| return Iter::empty()
#| }
#| let mut i = start
#| let mut done = false
#| Iter::new(() => {
#| guard !done else { None }
#| guard (step > zero && i < end) ||
#| (step < zero && i > end) ||
#| (inclusive && i == end) else {
#| None
#| }
#| let value = i
#| let next = i + step
#| if (step > zero && next >= i) || (step < zero && next <= i) {
#| i = next
#| } else {
#| done = true
#| }
#| Some(value)
#| })
#|}
),
"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 : ArrayView[T],
#|) -> Bool {
#| self[:].starts_with(prefix)
#|}
#|pub fn[T : Eq] ReadOnlyArray::ends_with(
#| self : ReadOnlyArray[T],
#| suffix : ArrayView[T],
#|) -> Bool {
#| self[:].ends_with(suffix)
#|}
#|#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())
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[T : Show] Show for ReadOnlyArray[T]
#|#warnings("-deprecated")
#|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_true(y == Ok(42))
#| assert_true(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_true(y == Err("error!"))
#| assert_true(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_true(y == Ok(6))
#| assert_true(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_true(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_true(z == Some(6))
#| assert_true(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
#| }
#|}
#|#warnings("-deprecated")
#|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" {
#| let result = try
#| (Err(Failure("This is serious")) : Result[Unit, Failure]).unwrap_or_error()
#| |> Ok
#| catch {
#| Failure(msg) => Err(msg)
#| }
#| assert_true(result == 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 Unit with to_string(_self) {
#| "()"
#|}
#|pub impl Show for Bool with to_string(self) {
#| if self {
#| "true"
#| } else {
#| "false"
#| }
#|}
#|pub impl Show for Int with to_string(self) {
#| Int::to_string(self)
#|}
#|pub impl Show for Int64 with to_string(self) {
#| Int64::to_string(self)
#|}
#|pub impl Show for UInt with to_string(self) {
#| UInt::to_string(self)
#|}
#|pub impl Show for UInt64 with to_string(self) {
#| UInt64::to_string(self)
#|}
#|pub impl Show for Byte with to_string(self) {
#| Byte::to_string(self)
#|}
#|pub impl Show for UInt16 with to_string(self) {
#| UInt16::to_string(self)
#|}
#|pub fn Byte::to_hex(b : Byte) -> String {
#| fn to_hex_digit(i : Byte) -> Char {
#| if i < 10 {
#| (i + b'0').to_char()
#| } else {
#| (i + b'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()
#| self[:].escape_to(buf, quote~)
#| buf.to_string()
#|}
#|pub fn StringView::escape(
#| self : StringView,
#| quote? : Bool = true,
#|) -> StringView {
#| let buf = StringBuilder()
#| 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 to_string(self) {
#| self
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[X : Show] Show for X?
#|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(")")
#| }
#| }
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[T : Show, E : Show] Show for Result[T, E]
#|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(")")
#| }
#| }
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[X : Show] Show for FixedArray[X]
#|pub impl[X : Show] Show for FixedArray[X] with output(self, logger) {
#| logger.write_iter(self.iter())
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[X : Show] Show for Array[X]
#|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(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::compare_ignore_ascii_case(self : String, other : String) -> Int {
#| self[:].compare_ignore_ascii_case(other)
#|}
#|pub fn String::equal_ignore_ascii_case(self : String, other : String) -> Bool {
#| self[:].equal_ignore_ascii_case(other)
#|}
#|pub fn String::from_array(chars : ArrayView[Char]) -> String {
#| let buf = StringBuilder(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()
#| 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" {
#| assert_true(boyer_moore_horspool_find("abc", "") == Some(0))
#| assert_true(boyer_moore_horspool_find("ab", "abcd") == None)
#|}
#|test "boyer_moore_horspool_rev_find edge cases" {
#| assert_true(boyer_moore_horspool_rev_find("abc", "") == Some(3))
#| assert_true(boyer_moore_horspool_rev_find("ab", "abcd") == None)
#|}
#|pub fn String::find(self : String, str : StringView) -> Int? {
#| self[:].find(str)
#|}
#|test "find" {
#| assert_true("hello".find("o") == Some(4))
#| assert_true("hello".find("l") == Some(2))
#| assert_true("hello".find("hello") == Some(0))
#| assert_true("hello".find("h") == Some(0))
#| assert_true("hello".find("") == Some(0))
#| assert_true("hello".find("world") == None)
#| assert_true("".find("") == Some(0))
#| assert_true("".find("a") == None)
#| assert_true("hello hello".find("hello") == Some(0))
#| assert_true("aaa".find("aa") == Some(0))
#| assert_true("😀😀".find("😀") == Some(0))
#| assert_true(
#| ("😀😀aa".repeat(20) + "😀😀😀😀").find("😀😀😀😀") ==
#| Some(120),
#| )
#| assert_true(
#| ("😀😀😀😀" + "😀😀aa".repeat(20)).find("😀😀😀😀") ==
#| Some(0),
#| )
#|}
#|#locals(pred)
#|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" {
#| assert_true("hello".find_by(c => c == 'o') == Some(4))
#| assert_true("hello".find_by(c => c == 'l') == Some(2))
#| assert_true("hello".find_by(c => c == 'z') == None)
#| assert_true("".find_by(c => c == 'a') == None)
#| assert_true("hello".find_by(c => c is ('0'..='9')) == None)
#| assert_true("hello123".find_by(c => c is ('0'..='9')) == Some(5))
#| assert_true("hello".find_by(c => c is ('A'..='Z')) == None)
#| assert_true("Hello".find_by(c => c is ('A'..='Z')) == Some(0))
#| assert_true("αβγ".find_by(c => c == 'β') == Some(1))
#| assert_true("😀😁😂".find_by(c => c == '😂') == 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" {
#| assert_true("hello".rev_find("o") == Some(4))
#| assert_true("hello".rev_find("l") == Some(3))
#| assert_true("hello".rev_find("hello") == Some(0))
#| assert_true("hello".rev_find("h") == Some(0))
#| assert_true("hello".rev_find("") == Some(5))
#| assert_true("hello".rev_find("world") == None)
#| assert_true("".rev_find("") == Some(0))
#| assert_true("".rev_find("a") == None)
#| assert_true("hello hello".rev_find("hello") == Some(6))
#| assert_true("aaa".rev_find("aa") == Some(1))
#| assert_true("😀😀".rev_find("😀") == Some(2))
#| assert_true(
#| ("😀😀aa".repeat(20) + "😀😀😀😀").rev_find("😀😀😀😀") ==
#| Some(120),
#| )
#| assert_true(
#| ("😀😀😀😀" + "😀😀aa".repeat(20)).rev_find("😀😀😀😀") ==
#| 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" {
#| assert_true("hello world".strip_prefix("hello ") == Some("world"[:]))
#| assert_true("hello world".strip_prefix("hi ") == None)
#| assert_true("hello".strip_prefix("hello") == Some(""[:]))
#| assert_true("".strip_prefix("") == Some(""[:]))
#| assert_true("".strip_prefix("a") == None)
#| assert_true("abc".strip_prefix("") == Some("abc"[:]))
#| assert_true("😀hello".strip_prefix("😀") == Some("hello"[:]))
#| assert_true("😀😃hello".strip_prefix("😀😃") == Some("hello"[:]))
#|}
#|test "strip_suffix" {
#| assert_true("hello world".strip_suffix(" world") == Some("hello"[:]))
#| assert_true("hello world".strip_suffix(" moon") == None)
#| assert_true("hello".strip_suffix("hello") == Some(""[:]))
#| assert_true("".strip_suffix("") == Some(""[:]))
#| assert_true("".strip_suffix("a") == None)
#| assert_true("abc".strip_suffix("") == Some("abc"[:]))
#| assert_true("hello😀".strip_suffix("😀") == Some("hello"[:]))
#| assert_true("hello😀😃".strip_suffix("😀😃") == 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"[:]
#| assert_true(view.strip_prefix("hello ") == Some("world"[:]))
#| assert_true(view.strip_prefix("hi ") == None)
#| assert_true(view.strip_prefix("hello world") == Some(""[:]))
#| assert_true(view.strip_prefix("") == Some("hello world"[:]))
#| let empty_view = ""[:]
#| assert_true(empty_view.strip_prefix("") == Some(""[:]))
#| assert_true(empty_view.strip_prefix("a") == None)
#| let unicode_view = "😀hello😃"[:]
#| assert_true(unicode_view.strip_prefix("😀") == Some("hello😃"[:]))
#| assert_true(unicode_view.strip_prefix("😃") == None)
#|}
#|test "View::strip_suffix" {
#| let view = "hello world"[:]
#| assert_true(view.strip_suffix(" world") == Some("hello"[:]))
#| assert_true(view.strip_suffix(" moon") == None)
#| assert_true(view.strip_suffix("hello world") == Some(""[:]))
#| assert_true(view.strip_suffix("") == Some("hello world"[:]))
#| let empty_view = ""[:]
#| assert_true(empty_view.strip_suffix("") == Some(""[:]))
#| assert_true(empty_view.strip_suffix("a") == None)
#| let unicode_view = "😀hello😃"[:]
#| assert_true(unicode_view.strip_suffix("😃") == Some("😀hello"[:]))
#| assert_true(unicode_view.strip_suffix("😀") == None)
#|}
#|test "View::to_array" {
#| let view = "Hello🤣"[:]
#| let chars = view.to_array()
#| assert_true(chars == ['H', 'e', 'l', 'l', 'o', '🤣'])
#| let empty_view = ""[:]
#| let empty_chars = empty_view.to_array()
#| assert_true(empty_chars == [])
#| let sub_view = "Hello World"[6:11] // "World"
#| let sub_chars = sub_view.to_array()
#| assert_true(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 {
#| for x = self {
#| match x {
#| [] as v => break v
#| [c, .. rest] as v =>
#| if chars.contains_char(c) {
#| continue rest
#| } else {
#| break 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 {
#| for x = self {
#| match x {
#| [] as v => break v
#| [.. rest, c] as v =>
#| if chars.contains_char(c) {
#| continue rest
#| } else {
#| break 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_owned() }
#| 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_owned() }
#| 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 => abort("negative repeat count")
#| 0 => ""
#| 1 => self
#| _ => {
#| let len = self.length()
#| let total = len * n
#| guard len == 0 || total / n == len else {
#| abort("repeat result too large")
#| }
#| let buf = StringBuilder(size_hint=total)
#| let str = self.to_owned()
#| for _ in 0.. String {
#| match n {
#| _..<0 => abort("negative repeat count")
#| 0 => ""
#| 1 => self
#| _ => {
#| let len = self.length()
#| let total = len * n
#| guard len == 0 || total / n == len else {
#| abort("repeat result too large")
#| }
#| let buf = StringBuilder(size_hint=total)
#| let str = self.to_string()
#| for _ in 0.. String {
#| let buf = StringBuilder(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_true(
#| "a,b,c".split(",").map(x => x.to_owned()).collect() == ["a", "b", "c"],
#| )
#| assert_true(
#| "a,b,c".split("").map(x => x.to_owned()).collect() ==
#| ["a", ",", "b", ",", "c"],
#| )
#| assert_true(
#| "apple::orange::banana".split("::").map(x => x.to_owned()).collect() ==
#| ["apple", "orange", "banana"],
#| )
#| assert_true(
#| "abc".split("").map(x => x.to_owned()).collect() == ["a", "b", "c"],
#| )
#| assert_true("hello".split(",").map(x => x.to_owned()).collect() == ["hello"])
#| assert_true(
#| ",a,b,c".split(",").map(x => x.to_owned()).collect() == ["", "a", "b", "c"],
#| )
#| assert_true(
#| "a,b,c,".split(",").map(x => x.to_owned()).collect() == ["a", "b", "c", ""],
#| )
#| assert_true(
#| "a,b,c".split("").map(x => x.to_owned()).collect() ==
#| ["a", ",", "b", ",", "c"],
#| )
#| assert_true("".split("").map(x => x.to_owned()).collect() == [])
#| assert_true("".split(",").map(x => x.to_owned()).collect() == [""])
#| assert_true(
#| "😀,😃,😄".split(",").map(x => x.to_owned()).collect() ==
#| ["😀", "😃", "😄"],
#| )
#| assert_true(
#| "a😀b😀c".split("😀").map(x => x.to_owned()).collect() ==
#| ["a", "b", "c"],
#| )
#|}
#|test "split_once before after" {
#| assert_true("a=b=c".split_once("=") == Some(("a"[:], "b=c"[:])))
#| assert_true("a=b=c".before("=") == Some("a"[:]))
#| assert_true("a=b=c".after("=") == Some("b=c"[:]))
#| assert_true("nope".split_once("=") == None)
#| assert_true("nope".before("=") == None)
#| assert_true("nope".after("=") == None)
#| assert_true("".split_once("") == Some((""[:], ""[:])))
#| assert_true("".before("") == Some(""[:]))
#| assert_true("".after("") == Some(""[:]))
#| assert_true("hello".split_once("") == Some((""[:], "hello"[:])))
#| assert_true("hello".before("") == Some(""[:]))
#| assert_true("hello".after("") == Some("hello"[:]))
#| assert_true("😊::🚀".split_once("::") == Some(("😊"[:], "🚀"[:])))
#|}
#|test "rev_split_once rev_before rev_after" {
#| assert_true("a=b=c".rev_split_once("=") == Some(("a=b"[:], "c"[:])))
#| assert_true("a=b=c".rev_before("=") == Some("a=b"[:]))
#| assert_true("a=b=c".rev_after("=") == Some("c"[:]))
#| assert_true("nope".rev_split_once("=") == None)
#| assert_true("nope".rev_before("=") == None)
#| assert_true("nope".rev_after("=") == None)
#| assert_true("a/b/c.txt".rev_before("/") == Some("a/b"[:]))
#| assert_true("a/b/c.txt".rev_after("/") == Some("c.txt"[:]))
#| assert_true("one=two".rev_split_once("=") == Some(("one"[:], "two"[:])))
#| assert_true(
#| "😊::🚀::⭐".rev_split_once("::") == 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(size_hint=len)
#| let old_len = old.length()
#| let new = new.to_owned()
#| 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(size_hint=len)
#| let old_len = old.length()
#| let new = new.to_owned()
#| 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(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(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(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(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!")
#|}
#|#locals(f)
#|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_true(
#| "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
#| })
#| assert_true(result is Err(Failure("found l")))
#|}
#|#locals(f)
#|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_true(
#| "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
#| })
#| assert_true(result is 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"
#| assert_true(s.get(0) == Some(104))
#| assert_true(s.get(4) == Some(111))
#| assert_true(s.get(5) == None)
#| assert_true(s.get(-1) == None)
#| let s = "a🤣b"
#| assert_true(s.get(0) == Some(97))
#| assert_true(s.get(1) == Some(55358))
#| assert_true(s.get(2) == Some(56611))
#| assert_true(s.get(3) == Some(98))
#| assert_true(s.get(4) == None)
#|}
#|test "View::get basic cases" {
#| let v = "hello"[1:-1]
#| assert_true(v.get(0) == Some(101))
#| assert_true(v.get(2) == Some(108))
#| assert_true(v.get(3) == None)
#| assert_true(v.get(-1) == None)
#| let v = "ab🤣cd"[1:-1]
#| assert_true(v.get(0) == Some(98))
#| assert_true(v.get(1) == Some(55358))
#| assert_true(v.get(2) == 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"
#| assert_true(s.get_char(0) == Some('h'))
#| assert_true(s.get_char(1) == Some('e'))
#| assert_true(s.get_char(4) == Some('o'))
#| assert_true(s.get_char(5) == None)
#| assert_true(s.get_char(-1) == None)
#| let s = "a🤣b"
#| assert_true(s.get_char(0) == Some('a'))
#| assert_true(s.get_char(1) == Some('🤣'))
#| assert_true(s.get_char(2) == None) // Second half of surrogate pair is not a valid char
#| assert_true(s.get_char(3) == Some('b'))
#| assert_true(s.get_char(4) == None)
#|}
#|test "View::get_char basic cases" {
#| let s = "a🤣b"
#| let v = s[0:-1]
#| assert_true(v.get_char(0) == Some('a'))
#| assert_true(v.get_char(1) == Some('🤣'))
#| assert_true(v.get_char(2) == None)
#| assert_true(v.get_char(3) == None)
#| assert_true(v.get_char(4) == None)
#| let v2 = s[1:3] // Only contains the emoji surrogate pair
#| assert_true(v2.get_char(0) == Some('🤣'))
#| assert_true(v2.get_char(1) == None)
#| assert_true(v2.get_char(2) == None)
#|}
),
"stringbuilder.mbt": (
#|#alias(write)
#|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[UInt16]
#| mut len : Int
#|}
#|#alias(new)
#|pub fn StringBuilder::StringBuilder(size_hint? : Int = 0) -> StringBuilder {
#| let initial = if size_hint < 1 { 1 } else { (size_hint + 1) / 2 }
#| let data : FixedArray[UInt16] = 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, UInt16::default())
#| new_data.unsafe_blit(0, self.data, 0, self.len)
#| self.data = new_data
#|}
#|fn FixedArray::unsafe_blit_from_string(
#| self : FixedArray[UInt16],
#| dst_offset : Int,
#| str : String,
#| str_offset : Int,
#| len : Int,
#|) -> Unit {
#| let end_str_offset = str_offset + len
#| for i = str_offset, j = dst_offset; i < end_str_offset; i = i + 1, j = j + 1 {
#| self[j] = str.unsafe_get(i)
#| }
#|}
#|pub impl Logger for StringBuilder with write_string(self, str) {
#| let str_len = str.length()
#| self.grow_if_necessary(self.len + str_len)
#| self.data.unsafe_blit_from_string(self.len, str, 0, str_len)
#| self.len += str_len
#|}
#|pub impl Logger for StringBuilder with write_char(self, ch) {
#| let code = ch.to_uint()
#| if code <= 0xFFFFU {
#| self.grow_if_necessary(self.len + 1)
#| self.data[self.len] = code.to_uint16()
#| self.len += 1
#| } else if code <= 0x10FFFFU {
#| self.grow_if_necessary(self.len + 2)
#| let code = code - 0x10000U
#| self.data[self.len] = (0xD800U + (code >> 10)).to_uint16()
#| self.data[self.len + 1] = (0xDC00U + code.land(0x3FFU)).to_uint16()
#| self.len += 2
#| } else {
#| abort("invalid code point")
#| }
#|}
#|pub impl Logger for StringBuilder with write_view(
#| self : StringBuilder,
#| str : StringView,
#|) -> Unit {
#| let str_len = str.length()
#| self.grow_if_necessary(self.len + str_len)
#| self.data.unsafe_blit_from_string(
#| self.len,
#| str.data(),
#| str.start_offset(),
#| str_len,
#| )
#| self.len += str_len
#|}
#|pub fn StringBuilder::to_string(self : StringBuilder) -> String {
#| if self.len == self.data.length() {
#| unsafe_fixedarray_uint16_to_string(self.data)
#| } else {
#| let data = FixedArray::make(self.len, UInt16::default())
#| data.unsafe_blit(0, self.data, 0, self.len)
#| unsafe_fixedarray_uint16_to_string(data)
#| }
#|}
#|pub impl Show for StringBuilder with to_string(self) {
#| StringBuilder::to_string(self)
#|}
#|pub fn StringBuilder::reset(self : StringBuilder) -> Unit {
#| self.data = FixedArray::make(self.data.length(), UInt16::default())
#| self.len = 0
#|}
),
"stringbuilder_concat.mbt": (
#|struct StringBuilder {
#| mut val : String
#|}
#|#alias(new)
#|pub fn StringBuilder::StringBuilder(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_owned()
#|}
#|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)
#|}
#|#alias(to_string, deprecated="Use `to_owned` to allocate an owned String from a StringView; use `Show::to_string` or format strings for display")
#|pub fn StringView::to_owned(self : StringView) -> String {
#| self.str().unsafe_substring(start=self.start(), end=self.end())
#|}
#|pub impl Show for StringView with to_string(self) {
#| self.to_owned()
#|}
#|#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.. UInt16 {
#| if c >= ('A' : UInt16) && c <= ('Z' : UInt16) {
#| c + (32 : UInt16)
#| } else {
#| c
#| }
#|}
#|pub fn StringView::compare_ignore_ascii_case(
#| self : StringView,
#| other : StringView,
#|) -> 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 {
#| let len = self.length()
#| if len != other.length() {
#| return false
#| }
#| 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)
#|}
#|pub fn String::get_view(
#| 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 else { None }
#| if start < len && self.unsafe_get(start).is_trailing_surrogate() {
#| return None
#| }
#| if end < len && self.unsafe_get(end).is_trailing_surrogate() {
#| return None
#| }
#| Some(StringView::make_view(self, start, end))
#|}
#|pub fn StringView::get_view(
#| 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() else {
#| None
#| }
#| if abs_start < str_len &&
#| self.str().unsafe_get(abs_start).is_trailing_surrogate() {
#| return None
#| }
#| if abs_end < str_len && self.str().unsafe_get(abs_end).is_trailing_surrogate() {
#| return None
#| }
#| Some(StringView::make_view(self.str(), abs_start, abs_end))
#|}
#|#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_owned())
#|}
#|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) => BigInt.asIntN(64, num).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) => num.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
#| 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 = _
#| write(Self, &Show) -> Unit = _
#|}
#|impl Logger with write(self, show) {
#| show.output(self)
#|}
#|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])
#|}
#|#must_implement_one(output, to_string)
#|pub(open) trait Show {
#| output(Self, &Logger) -> Unit = _
#| to_string(Self) -> String = _
#|}
#|impl Show with output(self, logger) {
#| logger.write_string(self.to_string())
#|}
#|impl Show with to_string(self) {
#| let logger = StringBuilder()
#| 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()
#| t.output(logger)
#| logger.to_string()
#|}
),
"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": (
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[A : Show, B : Show] Show for (A, B)
#|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(")")
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[A : Show, B : Show, C : Show] Show for (A, B, C)
#|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(")")
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[A : Show, B : Show, C : Show, D : Show] Show for (A, B, C, D)
#|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(")")
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[A : Show, B : Show, C : Show, D : Show, E : Show] Show for (
#| A,
#| B,
#| C,
#| D,
#| E,
#|)
#|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(")")
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[A : Show, B : Show, C : Show, D : Show, E : Show, F : Show] Show for (
#| A,
#| B,
#| C,
#| D,
#| E,
#| F,
#|)
#|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(")")
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|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,
#|)
#|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(")")
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|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)
#|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(")")
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|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)
#|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(")")
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|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)
#|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(")")
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|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)
#|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(")")
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|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)
#|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(")")
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|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)
#|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(")")
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|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)
#|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(")")
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|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)
#|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(")")
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|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,
#|)
#|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={},
files={
"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={},
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
),
"deprecated.mbt": (
#|#deprecated("Bytes regex APIs are deprecated and will be removed.", skip_current_package=true)
#|#internal(experimental, "subject to breaking change without notice")
#|struct BytesRegex(@re.Regex)
#|#deprecated("Bytes regex APIs are deprecated and will be removed.", skip_current_package=true)
#|#internal(experimental, "subject to breaking change without notice")
#|struct MatchResult {
#| input : BytesView
#| group_names : ReadOnlyArray[String?]
#| result : @re.MatchResult
#|}
#|#deprecated("Bytes regex APIs are deprecated and will be removed.", skip_current_package=true)
#|#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]
#|}
#|#deprecated("Bytes regex APIs are deprecated and will be removed.", skip_current_package=true)
#|#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()]
#|}
#|#deprecated("Bytes regex APIs are deprecated and will be removed.", skip_current_package=true)
#|#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]
#|}
#|#deprecated("Bytes regex APIs are deprecated and will be removed.", skip_current_package=true)
#|#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])
#| }
#|}
#|#deprecated("Bytes regex APIs are deprecated and will be removed.", skip_current_package=true)
#|#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)
#|}
#|#deprecated("Bytes regex APIs are deprecated and will be removed.", skip_current_package=true)
#|#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 start_state in self.start_states {
#| let (cat2, state_id) = start_state
#| if cat2 == cat {
#| return state_id
#| }
#| }
#| let state_id = find_state(
#| self.state_table,
#| self.states,
#| self.symbol_repr.length(),
#| @automata.State::start(cat, self.expr),
#| )
#| self.start_states.push((cat, state_id))
#| state_id
#|}
#|pub fn[T : Input] Regex::execute(
#| self : Regex,
#| input : T,
#| lastIndex : Int,
#|) -> 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) = for entry = state.final_ {
#| match entry {
#| 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_)
#| break (slot, status)
#| }
#| More(head, tail~) =>
#| if head.0 == final_cat {
#| break (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([]),
#| 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)
#| 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 {
#| for i = n, acc = init {
#| if i == 0 {
#| break acc
#| } else {
#| continue i - 1, f(acc)
#| }
#| }
#|}
),
"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) {
#| @debug.to_repr(self.desc)
#|}
#|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}
),
},
)
///|
let moonbitlang_core_bytes_internal_regex_engine_symbol_map_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/bytes/internal/regex_engine/symbol_map",
deps={},
files={
"dense_table.mbt": (
#|priv struct DenseTableWithZeroLb(FixedArray[@shared_types.Rechar])
#|impl Table for DenseTableWithZeroLb with map(self, c) {
#| self.0.unsafe_get(c)
#|}
#|priv struct DenseTable(FixedArray[@shared_types.Rechar], @shared_types.Rechar)
#|impl Table for DenseTable with map(self, c) {
#| self.0.unsafe_get(c - self.1)
#|}
),
"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.SortedSet([]))
#|}
#|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 {
#| self.finalize_dense(lb, ub)
#| } else {
#| self.finalize_sparse(lb, ub)
#| }
#|}
#|fn SymbolMap::finalize_dense(
#| self : SymbolMap,
#| lb : @shared_types.Rechar,
#| ub : @shared_types.Rechar,
#|) -> (&Table, 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 - lb] = symbol
#| }
#| })
#| (
#| if lb == 0 {
#| DenseTableWithZeroLb(table) as &Table
#| } else {
#| DenseTable(table, lb) as &Table
#| },
#| ReadOnlyArray::from_array(repr),
#| )
#|}
#|fn SymbolMap::finalize_sparse(
#| self : SymbolMap,
#| lb : @shared_types.Rechar,
#| ub : @shared_types.Rechar,
#|) -> (&Table, 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)) as &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 - 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={},
files={ "char_util.mbt": "" },
)
///|
let moonbitlang_core_cmp_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/cmp",
deps={},
files={
"cmp.mbt": (
#|#warnings("-deprecated_syntax")
#|pub(all) struct Reverse[T](T) derive(Eq, Show, Hash, @debug.Debug)
#|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={
"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_owned()))
#|}
#|pub impl Debug for Bytes with to_repr(self) {
#| Repr::opaque_("Bytes", Repr::array(self.to_array().map(x => to_repr(x))))
#|}
#|pub impl Debug for BytesView with to_repr(self) {
#| Repr::opaque_("BytesView", Repr::array(self.to_array().map(x => 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 => to_repr(x)))
#|}
#|pub impl[T : Debug] Debug for ArrayView[T] with to_repr(self) {
#| Repr::opaque_("ArrayView", Repr::array(self.map(x => to_repr(x))))
#|}
#|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 => to_repr(x))))
#|}
#|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 => to_repr(x))))
#|}
#|pub impl[T : Debug] Debug for T? with to_repr(self) {
#| match self {
#| None => Repr::ctor("None", [])
#| Some(x) => Repr::ctor("Some", [(None, to_repr(x))])
#| }
#|}
#|pub impl[T : Debug, E : Debug] Debug for Result[T, E] with to_repr(self) {
#| match self {
#| Ok(x) => Repr::ctor("Ok", [(None, to_repr(x))])
#| Err(e) => Repr::ctor("Err", [(None, to_repr(e))])
#| }
#|}
#|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 => to_repr(x))))
#|}
#|pub impl Debug for StringBuilder with to_repr(self) {
#| Repr::string(self.to_string())
#|}
#|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
#| (to_repr(k), to_repr(v))
#| }),
#| )
#|}
#|pub impl Debug for Json with to_repr(self) {
#| match self {
#| Null => Repr::ctor("Null", [])
#| True => Repr::ctor("True", [])
#| False => Repr::ctor("False", [])
#| Number(number, repr~) =>
#| match repr {
#| None => Repr::ctor("Number", [(None, to_repr(number))])
#| Some(_) =>
#| Repr::ctor("Number", [
#| (None, to_repr(number)),
#| (Some("repr"), to_repr(repr)),
#| ])
#| }
#| String(string) => Repr::ctor("String", [(None, to_repr(string))])
#| Array(array) => Repr::ctor("Array", [(None, to_repr(array))])
#| Object(object) => Repr::ctor("Object", [(None, to_repr(object))])
#| }
#|}
#|pub impl Debug for SourceLoc with to_repr(self) {
#| Repr::opaque_("SourceLoc", Repr::string(self.to_string()))
#|}
#|#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 = to_repr(a)
#| let repr_b = 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 "core builtin 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 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\")")
#|}
#|#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)
#| }
#|}
#|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))])
#| }
#|}
#|#warnings("-deprecated")
#|pub impl Debug for BenchError with to_repr(self) {
#| match self {
#| BenchError(msg) => Repr::ctor("BenchError", [(None, Repr::string(msg))])
#| }
#|}
#|pub impl Debug for ArgsLoc with to_repr(self) {
#| let ArgsLoc(arr) = self
#| Repr::opaque_("ArgsLoc", to_repr(arr))
#|}
#|pub impl Debug for Hasher with to_repr(_) {
#| Repr::opaque_("Hasher", Repr::omitted())
#|}
#|#warnings("-deprecated")
#|pub impl Debug for IterResult with to_repr(self) {
#| match self {
#| IterEnd => Repr::ctor("IterEnd", [])
#| IterContinue => Repr::ctor("IterContinue", [])
#| }
#|}
#|pub impl[T] Debug for UninitializedArray[T] with to_repr(_) {
#| Repr::opaque_("UninitializedArray", Repr::omitted())
#|}
#|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(
#| left.prune_info(max_depth=Some(d)),
#| right.prune_info(max_depth=Some(d)),
#| )
#| Extra1(x) => Extra1(x.prune_info(max_depth=Some(d)))
#| Extra2(x) => Extra2(x.prune_info(max_depth=Some(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,
#| label.pretty_print(children),
#| )
#| }
#| Different(left, right) => {
#| let children : Array[Content] = [
#| left.render_repr(threshold),
#| right.render_repr(threshold),
#| ]
#| 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] = [x.render_repr(threshold)]
#| with_resizing(
#| 0,
#| threshold,
#| match children {
#| [x] => no_parens(mark_removed(use_ansi, x.no_wrap()))
#| _ => empty_content()
#| },
#| )
#| }
#| Extra2(x) => {
#| let children : Array[Content] = [x.render_repr(threshold)]
#| 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 Repr::prune_info(
#| self : Repr,
#| replacement? : Repr = Repr::omitted(),
#| max_depth~ : Int?,
#|) -> Repr {
#| match max_depth {
#| None => self
#| Some(depth) => {
#| 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), self)
#| }
#| }
#|}
#|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] &&
#| (for rest = rest {
#| match rest {
#| ['a'..='z' | 'A'..='Z' | '0'..='9' | '_', .. rest] => continue rest
#| [_, ..] => break false
#| [] => break true
#| }
#| })
#|}
#|fn pretty_print_label(name : String) -> String {
#| if is_unquoted_key(name) {
#| name
#| } else {
#| name.escape()
#| }
#|}
#|fn Repr::pretty_print(self : Repr, children : Array[Content]) -> Content {
#| match self {
#| UnitLit => comma_seq("(", ")", [])
#| Integer(s) =>
#| no_parens(content_parens(if s is ['-', ..] { 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(x.escape()))
#| 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, .. rest] => {
#| 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, .. rest] =>
#| 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, .. rest] =>
#| no_parens(
#| content_parens(1 + v.size, [label + ": " + first, ..rest]),
#| )
#| }
#| }
#| _ => empty_content()
#| }
#| Omitted => parens(verbatim("..."))
#| }
#|}
#|fn Repr::render_repr(self : Repr, threshold : Int) -> Content {
#| let label = self.shallow()
#| let children = self.children().map(child => child.render_repr(threshold))
#| with_resizing(info_size(label), threshold, label.pretty_print(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 = r.prune_info(max_depth~)
#| print_content(info.render_repr(threshold).no_wrap())
#|}
#|pub impl Show for Repr with output(self, logger) {
#| logger.write_string(render(self))
#|}
#|pub impl Debug for Repr with to_repr(self) {
#| 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[StringView] = []
#| for m in middle {
#| let t = m.trim()
#| if t != "" {
#| parts.push(t)
#| }
#| }
#| let joined0 = parts.join(" ")
#| let joined : StringView = match joined0.strip_suffix(",") {
#| Some(sv) => sv
#| None => joined0[:]
#| }
#| if first == "{" {
#| let s1 = match joined.strip_prefix(" ") {
#| Some(sv) => sv
#| None => joined
#| }
#| let inner = match s1.strip_suffix(" ") {
#| Some(sv) => sv
#| None => s1
#| }
#| if inner == "" {
#| ["{}"]
#| } else {
#| ["{ \{inner} }"]
#| }
#| } else {
#| ["[\{joined}]"]
#| }
#| } else if first.has_suffix("(") && last == ")" {
#| let parts : Array[StringView] = []
#| for m in middle {
#| let t = m.trim()
#| if t != "" {
#| parts.push(t)
#| }
#| }
#| let joined0 = parts.join(" ")
#| let joined : StringView = match joined0.strip_suffix(",") {
#| Some(sv) => sv
#| 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()
#| 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)
#| }
#|}
),
"tuple_debug.mbt": (
#|pub impl[A : Debug, B : Debug] Debug for (A, B) with to_repr(self) {
#| let (a, b) = self
#| Repr::tuple([to_repr(a), to_repr(b)])
#|}
#|pub impl[A : Debug, B : Debug, C : Debug] Debug for (A, B, C) with to_repr(self) {
#| let (a, b, c) = self
#| Repr::tuple([to_repr(a), to_repr(b), to_repr(c)])
#|}
#|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([to_repr(a), to_repr(b), to_repr(c), to_repr(d)])
#|}
#|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([to_repr(a), to_repr(b), to_repr(c), to_repr(d), to_repr(e)])
#|}
#|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([
#| to_repr(a),
#| to_repr(b),
#| to_repr(c),
#| to_repr(d),
#| to_repr(e),
#| to_repr(f),
#| ])
#|}
#|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([
#| to_repr(a),
#| to_repr(b),
#| to_repr(c),
#| to_repr(d),
#| to_repr(e),
#| to_repr(f),
#| to_repr(g),
#| ])
#|}
#|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([
#| to_repr(a),
#| to_repr(b),
#| to_repr(c),
#| to_repr(d),
#| to_repr(e),
#| to_repr(f),
#| to_repr(g),
#| to_repr(h),
#| ])
#|}
#|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([
#| to_repr(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),
#| ])
#|}
#|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([
#| to_repr(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),
#| ])
#|}
#|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([
#| to_repr(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),
#| ])
#|}
#|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([
#| to_repr(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),
#| ])
#|}
#|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([
#| to_repr(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),
#| ])
#|}
#|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([
#| to_repr(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),
#| ])
#|}
#|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([
#| to_repr(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),
#| ])
#|}
#|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([
#| to_repr(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),
#| ])
#|}
#|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([
#| to_repr(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),
#| ])
#|}
#|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([
#| to_repr(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),
#| ])
#|}
#|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([
#| to_repr(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),
#| ])
#|}
#|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([
#| to_repr(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),
#| ])
#|}
#|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([
#| to_repr(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),
#| ])
#|}
#|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([
#| to_repr(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),
#| ])
#|}
),
},
)
///|
let moonbitlang_core_deque_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/deque",
deps={},
files={
"debug.mbt": (
#|using @debug {trait Debug, type Repr}
#|pub impl[A : Debug] Debug for Deque[A] with to_repr(self) {
#| Repr::opaque_(
#| "Deque",
#| Repr::array(self.to_array().map(x => @debug.to_repr(x))),
#| )
#|}
#|#deprecated("use `to_repr(a)` instead", skip_current_package=true)
#|pub fn[A : Debug] Deque::to_repr(self : Deque[A]) -> Repr {
#| @debug.to_repr(self)
#|}
#|test "Debug for Deque" {
#| let dq : Deque[Int] = from_array([1, 2, 3])
#| @debug.debug_inspect(dq, content="")
#|}
),
"deprecated.mbt": (
#|#deprecated("Use `Deque([], capacity=...)` instead")
#|#as_free_fn(deprecated="Use `Deque([], capacity=...)` instead")
#|pub fn[A] Deque::new(capacity? : Int = 0) -> Deque[A] {
#| new_deque(capacity)
#|}
),
"deque.mbt": (
#|fn[T] set_null(buffer : UninitializedArray[T], index : Int) = "%fixedarray.set_null"
#|fn[A] new_deque(capacity : Int) -> 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()
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[A : Show] Show for Deque[A]
#|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)
#| self.unsafe_blit_to(buf, 0)
#| other.unsafe_blit_to(buf, self.len)
#| Deque::{ buf, len, head: 0 }
#|}
#|test "add_empty" {
#| let empty1 : Deque[Int] = new_deque(0)
#| let empty2 : Deque[Int] = new_deque(0)
#| let result = empty1 + empty2
#| inspect(result.len, content="0")
#| inspect(result.is_empty(), content="true")
#|}
#|#alias(from_array)
#|#as_free_fn(from_array)
#|#alias(of, deprecated="Use from_array instead")
#|#as_free_fn(of, deprecated="Use from_array instead")
#|pub fn[A] Deque::Deque(arr : ArrayView[A], capacity? : Int) -> Deque[A] {
#| let len = arr.length()
#| let capacity = match capacity {
#| Some(capacity) => capacity.max(len)
#| None => len
#| }
#| let buf = UninitializedArray::make(capacity)
#| 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)
#| self.unsafe_blit_to(buf, 0)
#| 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)
#| self.unsafe_blit_to(new_buf, 0)
#| self.head = 0
#| self.buf = new_buf
#|}
#|pub fn[A] Deque::front(self : Deque[A]) -> 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_deque(0)
#| for i in 0..<10 {
#| dq.push_front(i)
#| }
#| for _ in 0..<10 {
#| dq.unsafe_pop_front()
#| }
#| @test.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])
#| }
#|}
#|fn[A] Deque::unsafe_blit_to(
#| self : Deque[A],
#| dst : UninitializedArray[A],
#| dst_offset : Int,
#|) -> Unit {
#| guard self.len != 0 else { return }
#| let (front, back) = self.as_views()
#| dst.unsafe_blit(dst_offset, self.buf, front.start_offset(), front.length())
#| dst.unsafe_blit(
#| dst_offset + front.length(),
#| self.buf,
#| back.start_offset(),
#| back.length(),
#| )
#|}
#|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)
#| }
#|}
#|#locals(f)
#|pub fn[A] Deque::eachi(self : Deque[A], f : (Int, A) -> Unit) -> Unit {
#| for i, v in self {
#| f(i, v)
#| }
#|}
#|#locals(f)
#|pub fn[A] Deque::rev_each(self : Deque[A], f : (A) -> Unit) -> Unit {
#| for v in self.rev_iter() {
#| f(v)
#| }
#|}
#|#locals(f)
#|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_deque(0)
#| } 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_deque(0)
#| } 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)
#|}
#|#locals(f)
#|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
#| let len = self.len
#| Iter::new(
#| fn() {
#| guard index < len else { None }
#| let elem = self.buf[(self.head + index) % self.buf.length()]
#| index += 1
#| Some(elem)
#| },
#| size_hint=len,
#| )
#|}
#|#alias(iterator2, deprecated)
#|pub fn[A] Deque::iter2(self : Deque[A]) -> Iter2[Int, A] {
#| let mut index = 0
#| let len = self.len
#| Iter2::new(
#| fn() {
#| guard index < len else { None }
#| let result = (index, self.buf[(self.head + index) % self.buf.length()])
#| index += 1
#| Some(result)
#| },
#| size_hint=len,
#| )
#|}
#|#alias(rev_iterator, deprecated)
#|pub fn[A] Deque::rev_iter(self : Deque[A]) -> Iter[A] {
#| let len = self.len
#| let mut index = len
#| Iter::new(
#| fn() {
#| guard index > 0 else { None }
#| index -= 1
#| Some(self.buf[(self.head + index) % self.buf.length()])
#| },
#| size_hint=len,
#| )
#|}
#|#alias(rev_iterator2, deprecated)
#|pub fn[A] Deque::rev_iter2(self : Deque[A]) -> Iter2[Int, A] {
#| let len = self.len
#| let mut rev_index = len
#| Iter2::new(
#| fn() {
#| guard rev_index > 0 else { None }
#| let index = len - rev_index
#| rev_index -= 1
#| Some((index, self.buf[(self.head + rev_index) % self.buf.length()]))
#| },
#| size_hint=len,
#| )
#|}
#|#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_deque(0)
#| 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_owned()
#| self.iter().join(str)
#|}
#|pub impl[A : ToJson] ToJson for Deque[A] with to_json(self : Deque[A]) -> Json {
#| [
#| for x in self { x }
#| ]
#|}
#|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([], 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_deque(0)
#| }
#| 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.., )
#| ),
#| )
#| ignore(deque.drain(start=0, len=2))
#| @debug.debug_inspect(
#| deque.as_views(),
#| content=(
#| #|(, )
#| ),
#| )
#| deque.push_back(31)
#| deque.push_back(32)
#| @debug.debug_inspect(
#| deque.as_views(),
#| content=(
#| #|(, )
#| ),
#| )
#| ignore(deque.pop_front())
#|}
#|#locals(cmp)
#|pub fn[A] Deque::binary_search_by(
#| self : Deque[A],
#| cmp : (A) -> 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={},
files={
"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_encoding_ascii_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/encoding/ascii",
deps={},
files={
"decode.mbt": (
#|pub suberror Malformed {
#| Malformed(BytesView)
#|} derive(@debug.Debug)
#|fn unsafe_fixedarray_uint16_to_string(buffer : FixedArray[UInt16]) -> String = "%string.unsafe_from_uint16_fixedarray"
#|fn finish_string(buffer : FixedArray[UInt16], len : Int) -> String {
#| if len == buffer.length() {
#| unsafe_fixedarray_uint16_to_string(buffer)
#| } else {
#| let data = FixedArray::make(len, UInt16::default())
#| data.unsafe_blit(0, buffer, 0, len)
#| unsafe_fixedarray_uint16_to_string(data)
#| }
#|}
#|pub fn decode(bytes : BytesView) -> String raise Malformed {
#| let t : FixedArray[UInt16] = FixedArray::make(bytes.length(), 0)
#| let tlen = for tlen = 0, bs = bytes {
#| match (tlen, bs) {
#| (tlen, []) => break tlen
#| (tlen, [0..=0x7F as b, .. rest]) => {
#| t.unsafe_set(tlen, b.to_uint16())
#| continue tlen + 1, rest
#| }
#| (_, _ as bytes) => raise Malformed(bytes)
#| }
#| }
#| finish_string(t, tlen)
#|}
#|pub fn decode_lossy(bytes : BytesView) -> String {
#| let t : FixedArray[UInt16] = FixedArray::make(bytes.length(), 0)
#| let tlen = for tlen = 0, bs = bytes {
#| match (tlen, bs) {
#| (tlen, []) => break tlen
#| (tlen, [0..=0x7F as b, .. rest]) => {
#| t.unsafe_set(tlen, b.to_uint16())
#| continue tlen + 1, rest
#| }
#| (tlen, [_, .. rest]) => {
#| t.unsafe_set(tlen, 0xFFFD)
#| continue tlen + 1, rest
#| }
#| }
#| }
#| finish_string(t, 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)
#|} derive(@debug.Debug)
#|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(size_hint~)
#| for remaining = bytes {
#| match remaining {
#| [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('=')
#| }
#| break
#| }
#| [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("==")
#| }
#| break
#| }
#| [] => break
#| }
#| }
#| builder.to_string()
#|}
),
},
)
///|
let moonbitlang_core_encoding_utf16_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/encoding/utf16",
deps={},
files={
"decode.mbt": (
#|pub suberror Malformed {
#| Malformed(BytesView)
#|} derive(@debug.Debug)
#|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 [.. b"\xff\xfe", .. rest] {
#| rest
#| } else if endianness is Big && bytes is [.. b"\xfe\xff", .. rest] {
#| rest
#| } else {
#| bytes
#| }
#| } else {
#| bytes
#| }
#| if endianness is Little {
#| for x = bytes {
#| match x {
#| [] => break
#| [
#| 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
#| for x = bytes {
#| match x {
#| [] => break
#| [
#| 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 [.. b"\xff\xfe", .. rest] {
#| rest
#| } else if endianness is Big && bytes is [.. b"\xfe\xff", .. rest] {
#| rest
#| } else {
#| bytes
#| }
#| } else {
#| bytes
#| }
#| let builder = StringBuilder(size_hint=bytes.length())
#| if endianness is Little {
#| for x = bytes {
#| match x {
#| [] => break
#| [
#| 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)
#| break
#| }
#| }
#| }
#| } else {
#| for x = bytes {
#| match x {
#| [] => break
#| [
#| 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)
#| break
#| }
#| }
#| }
#| }
#| 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
#|} derive(@debug.Debug)
),
},
)
///|
let moonbitlang_core_encoding_utf8_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/encoding/utf8",
deps={},
files={
"decode.mbt": (
#|pub suberror Malformed {
#| Malformed(BytesView)
#|} derive(@debug.Debug)
#|pub fn decode(
#| bytes : BytesView,
#| ignore_bom? : Bool = false,
#|) -> String raise Malformed {
#| let bytes = if ignore_bom && bytes is [.. b"\xef\xbb\xbf", .. rest] {
#| rest
#| } else {
#| bytes
#| }
#| let t : FixedArray[Byte] = FixedArray::make(bytes.length() * 2, 0)
#| let tlen = for tlen = 0, bs = bytes {
#| match (tlen, bs) {
#| (tlen, []) => break 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 [.. b"\xef\xbb\xbf", .. rest] {
#| rest
#| } else {
#| bytes
#| }
#| let t : FixedArray[Byte] = FixedArray::make(bytes.length() * 2, 0)
#| let tlen = for tlen = 0, bs = bytes {
#| match (tlen, bs) {
#| (tlen, []) => break 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 UTF8_BOM_0 : Byte = b'\xEF'
#|const UTF8_BOM_1 : Byte = b'\xBB'
#|const UTF8_BOM_2 : Byte = b'\xBF'
#|pub fn encode(str : StringView, bom? : Bool = false) -> Bytes {
#| let length = str.length()
#| let utf8_length = for i = 0, utf8_length = 0; i < length; {
#| let code = str.unsafe_get(i)
#| if code < 0x80 {
#| continue i + 1, utf8_length + 1
#| } else if code < 0x800 {
#| continue i + 1, utf8_length + 2
#| } else if code.is_leading_surrogate() &&
#| i + 1 < length &&
#| str.unsafe_get(i + 1).is_trailing_surrogate() {
#| continue i + 2, utf8_length + 4
#| } else if code.is_surrogate() {
#| abort("invalid surrogate pair")
#| } else {
#| continue i + 1, utf8_length + 3
#| }
#| } nobreak {
#| if bom {
#| 3 + utf8_length
#| } else {
#| utf8_length
#| }
#| }
#| let arr = FixedArray::make(utf8_length, b'\x00')
#| for i = 0, offset = (if bom {
#| arr[0] = UTF8_BOM_0
#| arr[1] = UTF8_BOM_1
#| arr[2] = UTF8_BOM_2
#| 3
#| } else {
#| 0
#| }); i < length; {
#| let code_unit = str.unsafe_get(i)
#| let code = code_unit.to_int()
#| if code < 0x80 {
#| arr[offset] = code.to_byte()
#| continue i + 1, offset + 1
#| } else if code < 0x800 {
#| arr[offset] = (0xC0 + (code >> 6)).to_byte()
#| arr[offset + 1] = (0x80 + (code & 0x3F)).to_byte()
#| continue i + 1, offset + 2
#| } else if code_unit.is_leading_surrogate() && i + 1 < length {
#| let trailing = str.unsafe_get(i + 1)
#| if trailing.is_trailing_surrogate() {
#| let code = ((code - 0xD800) << 10) +
#| (trailing.to_int() - 0xDC00) +
#| 0x10000
#| arr[offset] = (0xF0 + (code >> 18)).to_byte()
#| arr[offset + 1] = (0x80 + ((code >> 12) & 0x3F)).to_byte()
#| arr[offset + 2] = (0x80 + ((code >> 6) & 0x3F)).to_byte()
#| arr[offset + 3] = (0x80 + (code & 0x3F)).to_byte()
#| continue i + 2, offset + 4
#| } else {
#| abort("invalid surrogate pair")
#| }
#| } else if code_unit.is_surrogate() {
#| abort("invalid surrogate pair")
#| } else {
#| arr[offset] = (0xE0 + (code >> 12)).to_byte()
#| arr[offset + 1] = (0x80 + ((code >> 6) & 0x3F)).to_byte()
#| arr[offset + 2] = (0x80 + (code & 0x3F)).to_byte()
#| continue i + 1, offset + 3
#| }
#| }
#| arr.unsafe_reinterpret_as_bytes()
#|}
),
},
)
///|
let moonbitlang_core_env_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/env",
deps={},
files={
"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 BigInt.asUintN(64, BigInt(nowMs));
#| #| }
#|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] {
#| [
#| for t in get_cli_args_ffi() { utf8_bytes_to_mbt_string(t) }
#| ]
#|}
#|fn utf8_bytes_to_mbt_string(bytes : Bytes) -> String {
#| let res = StringBuilder()
#| 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 now_internal() -> UInt64 = "moonbit_get_ms_since_epoch"
#|#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 in 0.. 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()
#| 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 = []
#| 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={},
files={
"debug.mbt": (
#|using @debug {trait Debug, type Repr}
#|fn error_to_repr(e : Error) -> Repr = "%error.to_repr"
#|pub impl Debug for Error with to_repr(self) {
#| error_to_repr(self)
#|}
#|#deprecated("use `to_repr(a)` instead", skip_current_package=true)
#|pub fn Error::to_repr(self : Error) -> Repr {
#| @debug.to_repr(self)
#|}
#|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.debug_inspect(e, content="InspectError(\"test error\")")
#| Ok(_) => fail("expected error")
#| }
#|}
),
"error.mbt": (
#|fn Error::to_string(self : Error) -> String = "%error.to_string"
#|pub impl Show for Error with to_string(self) {
#| Error::to_string(self)
#|}
#|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={},
files={
"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 to_string(self) {
#| 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())
#|}
#|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={},
files={
"debug.mbt": (
#|using @debug {trait Debug, type Repr}
#|pub impl[K : Debug, V : Debug] Debug for HashMap[K, V] with to_repr(self) {
#| let entries : Array[(Repr, Repr)] = self
#| .to_array()
#| .map(kv => (@debug.to_repr(kv.0), @debug.to_repr(kv.1)))
#| Repr::opaque_("HashMap", Repr::map(entries))
#|}
#|#deprecated("use `to_repr(a)` instead", skip_current_package=true)
#|pub fn[K : Debug, V : Debug] HashMap::to_repr(self : HashMap[K, V]) -> Repr {
#| @debug.to_repr(self)
#|}
#|test "Debug for HashMap" {
#| let hm : HashMap[Int, String] = from_array([(2, "b")])
#| @debug.debug_inspect(
#| hm,
#| content=(
#| #|
#| ),
#| )
#|}
),
"deprecated.mbt": (
#|#deprecated("Use `HashMap([], capacity=...)` instead")
#|#as_free_fn(deprecated="Use `HashMap([], capacity=...)` instead")
#|pub fn[K, V] HashMap::new(
#| capacity? : Int = default_init_capacity,
#|) -> HashMap[K, V] {
#| new_hashmap(capacity)
#|}
),
"hashmap.mbt": (
#|let default_init_capacity = 8
#|fn[K, V] new_hashmap(capacity : Int) -> HashMap[K, V] {
#| let capacity = capacity.next_power_of_two()
#| {
#| size: 0,
#| capacity,
#| entries: FixedArray::make(capacity, None),
#| capacity_mask: capacity - 1,
#| }
#|}
#|fn capacity_for_length(length : Int) -> Int {
#| (length * 2).next_power_of_two()
#|}
#|#alias(from_array)
#|#as_free_fn(from_array)
#|#alias(of, deprecated="Use from_array instead")
#|#as_free_fn(of, deprecated="Use from_array instead")
#|pub fn[K : Hash + Eq, V] HashMap::HashMap(
#| arr : ArrayView[(K, V)],
#| capacity? : Int,
#|) -> HashMap[K, V] {
#| let length = arr.length()
#| let capacity = match capacity {
#| Some(capacity) => capacity.max(capacity_for_length(length))
#| None =>
#| if length == 0 {
#| default_init_capacity
#| } else {
#| capacity_for_length(length)
#| }
#| }
#| let m = new_hashmap(capacity)
#| 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::update_or_default(
#| self : HashMap[K, V],
#| key : K,
#| default : V,
#| f : (V) -> V,
#|) -> Unit {
#| let hash = key.hash()
#| let (idx, psl, push_away) = for psl = 0, idx = hash & self.capacity_mask {
#| match self.entries[idx] {
#| Some(entry) => {
#| if entry.hash == hash && entry.key == key {
#| entry.value = f(entry.value)
#| return
#| }
#| if psl > entry.psl {
#| break (idx, psl, Some(entry))
#| }
#| continue psl + 1, (idx + 1) & self.capacity_mask
#| }
#| None => break (idx, psl, None)
#| }
#| }
#| if self.size >= self.capacity / 2 {
#| self.grow()
#| self.set_with_hash(key, default, hash)
#| } else {
#| if push_away is Some(entry) {
#| self.push_away(idx, entry)
#| }
#| let entry = { psl, hash, key, value: default }
#| self.entries[idx] = Some(entry)
#| self.size += 1
#| }
#|}
#|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 {
#| for cur = idx {
#| let next = (cur + 1) & self.capacity_mask
#| match self.entries[next] {
#| None | Some({ psl: 0, .. }) => {
#| self.entries[cur] = None
#| break
#| }
#| Some(entry) => {
#| entry.psl -= 1
#| self.entries[cur] = Some(entry)
#| continue 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)])
#| @debug.debug_inspect(m.get(1), content="Some(2)")
#| @debug.debug_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_hashmap(default_init_capacity)
#| (@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_hashmap(default_init_capacity)
#|}
#|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, Debug)
#|#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)
#|}
#|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_true(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_hashmap(default_init_capacity)
#| 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_hashmap(default_init_capacity)
#| 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_hashmap(default_init_capacity)
#| 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.assert_same_object(entry, None)
#| }
#|}
#|test "grow" {
#| let m : HashMap[MyString, Int] = new_hashmap(default_init_capacity)
#| 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")
#| @debug.debug_inspect(m.get("C"), content="Some(1)")
#| @debug.debug_inspect(m.get("Go"), content="Some(2)")
#| @debug.debug_inspect(m.get("C++"), content="Some(3)")
#| @debug.debug_inspect(m.get("Java"), content="Some(4)")
#| @debug.debug_inspect(m.get("Scala"), content="Some(5)")
#| @debug.debug_inspect(m.get("Julia"), content="Some(5)")
#| @debug.debug_inspect(m.get("Cobol"), content="Some(5)")
#| @debug.debug_inspect(m.get("Python"), content="Some(6)")
#| @debug.debug_inspect(m.get("Haskell"), content="Some(7)")
#| @debug.debug_inspect(m.get("Rescript"), content="Some(8)")
#|}
#|test "_[_]" {
#| let m : HashMap[MyString, Int] = new_hashmap(default_init_capacity)
#| 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_hashmap(default_init_capacity)
#| inspect(m.get_or_init("a", () => 1), content="1")
#| @debug.debug_inspect(m.get("a"), content="Some(1)")
#| inspect(m.get_or_init("a", () => 2), content="1")
#| @debug.debug_inspect(m.get("a"), content="Some(1)")
#|}
),
"json.mbt": (
#|pub impl[K : Show, V : ToJson] ToJson for HashMap[K, V] with to_json(self) {
#| Json::object(
#| Map(
#| capacity=self.capacity,
#| [
#| for k, v in self { (k.to_string(), v.to_json()) }
#| ],
#| ),
#| )
#|}
),
"types.mbt": (
#|#warnings("-deprecated_syntax")
#|priv struct Entry[K, V] {
#| mut psl : Int
#| hash : Int
#| key : K
#| mut value : V
#|} derive(Debug)
#|#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
#| }
#| },
#| size_hint=self.size,
#| )
#|}
#|#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_hashmap(default_init_capacity)
#| 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
#| }
#| }
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[K : Show, V : Show] Show for HashMap[K, V]
#|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
#| }
#| },
#| size_hint=self.size,
#| )
#| 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
#| }
#| },
#| size_hint=self.size,
#| )
#| 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)
#| @debug.debug_inspect(
#| hashmap.entries,
#| content=(
#| #|
#| ),
#| )
#|}
),
},
)
///|
let moonbitlang_core_hashset_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/hashset",
deps={},
files={
"debug.mbt": (
#|using @debug {trait Debug, type Repr}
#|pub impl[K : Debug] Debug for HashSet[K] with to_repr(self) {
#| let xs : Array[Repr] = self.to_array().map(x => @debug.to_repr(x))
#| Repr::opaque_("HashSet", Repr::array(xs))
#|}
#|#deprecated("use `to_repr(a)` instead", skip_current_package=true)
#|pub fn[K : Debug] HashSet::to_repr(self : HashSet[K]) -> Repr {
#| @debug.to_repr(self)
#|}
#|test "Debug for HashSet" {
#| let hs : HashSet[Int] = from_array([1])
#| @debug.debug_inspect(hs, content="")
#|}
),
"deprecated.mbt": (
#|#deprecated("Use `HashSet([], capacity=...)` instead")
#|#as_free_fn(deprecated="Use `HashSet([], capacity=...)` instead")
#|pub fn[K] HashSet::new(capacity? : Int = default_init_capacity) -> HashSet[K] {
#| new_hashset(capacity)
#|}
),
"hashset.mbt": (
#|let default_init_capacity = 8
#|fn[K] new_hashset(capacity : Int) -> 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),
#| }
#|}
#|fn capacity_for_length(length : Int) -> Int {
#| let mut capacity = length.next_power_of_two()
#| if length > calc_grow_threshold(capacity) {
#| capacity *= 2
#| }
#| capacity
#|}
#|#alias(from_array)
#|#as_free_fn(from_array)
#|#alias(of, deprecated="Use from_array instead")
#|#as_free_fn(of, deprecated="Use from_array instead")
#|pub fn[K : Hash + Eq] HashSet::HashSet(
#| arr : ArrayView[K],
#| capacity? : Int,
#|) -> HashSet[K] {
#| let length = arr.length()
#| let capacity = match capacity {
#| Some(capacity) => capacity.max(capacity_for_length(length))
#| None => default_init_capacity.max(capacity_for_length(length))
#| }
#| let m = new_hashset(capacity)
#| 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 {
#| for cur = idx {
#| let next = (cur + 1) & self.capacity_mask
#| match self.entries[next] {
#| None | Some({ psl: 0, .. }) => {
#| self.entries[cur] = None
#| break
#| }
#| Some(entry) => {
#| entry.psl -= 1
#| self.set_entry(entry, cur)
#| continue 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)
#| }
#| }
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[K : Show] Show for HashSet[K]
#|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
#| }
#| },
#| size_hint=self.size,
#| )
#|}
#|pub fn[K] HashSet::to_array(self : HashSet[K]) -> Array[K] {
#| [
#| for entry in self.entries { guard entry is Some({ key, .. }) else { continue }; key }
#| ]
#|}
#|#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_hashset(default_init_capacity)
#| 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_hashset(default_init_capacity)
#| 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_hashset(default_init_capacity)
#| 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_hashset(default_init_capacity)
#| 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_hashset(default_init_capacity)
#| 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)
#|}
#|#locals(f)
#|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, Debug)
#|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)
#|}
#|test "set" {
#| let m : HashSet[MyString] = new_hashset(default_init_capacity)
#| 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_hashset(default_init_capacity)
#| 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_hashset(default_init_capacity)
#| 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_hashset(default_init_capacity)
#| 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_hashset(default_init_capacity)
#| m.clear()
#| inspect(m.length(), content="0")
#| inspect(m.capacity(), content="8")
#| for entry in m.entries {
#| @test.assert_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,
#| }
#| self.entries.blit_to(other.entries, len=self.capacity)
#| other
#|}
#|pub impl[X : ToJson] ToJson for HashSet[X] with to_json(self) {
#| [
#| for entry in self.entries { guard entry is Some({ key, .. }) else { continue }; key }
#| ]
#|}
#|pub impl[K] Default for HashSet[K] with default() {
#| new_hashset(default_init_capacity)
#|}
),
"types.mbt": (
#|#warnings("-deprecated_syntax")
#|priv struct Entry[K] {
#| mut psl : Int
#| hash : Int
#| key : K
#|} derive(Debug)
#|#alias(T, deprecated)
#|struct HashSet[K] {
#| mut entries : FixedArray[Entry[K]?]
#| mut size : Int // active key 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
#|}
),
},
)
///|
let moonbitlang_core_immut_array_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/immut/array",
deps={},
files={
"array.mbt": (
#|#deprecated("Use the corresponding function in `immut/vector` instead", skip_current_package=true)
#|#as_free_fn(deprecated="Use the corresponding function in `immut/vector` instead")
#|pub fn[A] T::new() -> T[A] {
#| { tree: Tree::empty(), size: 0, shift: 0 }
#|}
#|#deprecated("Use the corresponding function in `immut/vector` instead", skip_current_package=true)
#|#as_free_fn(deprecated="Use the corresponding function in `immut/vector` instead")
#|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 }
#|}
#|#deprecated("Use the corresponding function in `immut/vector` instead", skip_current_package=true)
#|#as_free_fn(deprecated="Use the corresponding function in `immut/vector` instead")
#|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 }
#|}
#|#deprecated("Use the corresponding function in `immut/vector` instead", skip_current_package=true)
#|#as_free_fn(deprecated="Use the corresponding function in `immut/vector` instead")
#|#alias(of, deprecated="Use the corresponding function in `immut/vector` instead")
#|#as_free_fn(of, deprecated="Use the corresponding function in `immut/vector` instead")
#|pub fn[A] T::from_array(arr : ArrayView[A]) -> T[A] {
#| T::makei(arr.length(), i => arr[i])
#|}
#|#deprecated("Use the corresponding function in `immut/vector` instead", skip_current_package=true)
#|#as_free_fn(deprecated="Use the corresponding function in `immut/vector` instead")
#|#alias(from_iterator, deprecated="Use the corresponding function in `immut/vector` instead")
#|#as_free_fn(from_iterator, deprecated="Use the corresponding function in `immut/vector` instead")
#|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 }
#|}
#|#deprecated("Use the corresponding function in `immut/vector` instead", skip_current_package=true)
#|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
#| }
#|}
#|#deprecated("Use the corresponding function in `immut/vector` instead", skip_current_package=true)
#|pub fn[A] T::is_empty(self : T[A]) -> Bool {
#| self.size == 0
#|}
#|#deprecated("Use the corresponding function in `immut/vector` instead", skip_current_package=true)
#|pub fn[A] T::length(self : T[A]) -> Int {
#| self.size
#|}
#|#deprecated("Use the corresponding function in `immut/vector` instead", skip_current_package=true)
#|#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)
#| }
#|}
#|#deprecated("Use the corresponding function in `immut/vector` instead", skip_current_package=true)
#|pub fn[A] T::get(self : T[A], index : Int) -> A? {
#| guard 0 <= index && index < self.size else { None }
#| Some(self[index])
#|}
#|#deprecated("Use the corresponding function in `immut/vector` instead", skip_current_package=true)
#|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,
#| }
#|}
#|#deprecated("Use the corresponding function in `immut/vector` instead", skip_current_package=true)
#|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 }
#|}
#|#deprecated("Use the corresponding function in `immut/vector` instead", skip_current_package=true)
#|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)
#|}
#|#deprecated("Use the corresponding function in `immut/vector` instead", skip_current_package=true)
#|#alias(iterator, deprecated="Use the corresponding function in `immut/vector` instead")
#|pub fn[A] T::iter(self : T[A]) -> Iter[A] {
#| let iter = self.tree.iter()
#| Iter::new(() => iter.next(), size_hint=self.size)
#|}
#|#deprecated("Use the corresponding function in `immut/vector` instead", skip_current_package=true)
#|pub fn[A] T::each(self : T[A], f : (A) -> Unit raise?) -> Unit raise? {
#| self.tree.each(f)
#|}
#|#deprecated("Use the corresponding function in `immut/vector` instead", skip_current_package=true)
#|pub fn[A] T::eachi(self : T[A], f : (Int, A) -> Unit raise?) -> Unit raise? {
#| self.tree.eachi(f, self.shift, 0)
#|}
#|#deprecated("Use the corresponding function in `immut/vector` instead", skip_current_package=true)
#|#alias(fold_left, deprecated="Use the corresponding function in `immut/vector` instead")
#|pub fn[A, B] T::fold(
#| self : T[A],
#| init~ : B,
#| f : (B, A) -> B raise?,
#|) -> B raise? {
#| self.tree.fold(init, f)
#|}
#|#deprecated("Use the corresponding function in `immut/vector` instead", skip_current_package=true)
#|#alias(fold_right, deprecated="Use the corresponding function in `immut/vector` instead")
#|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)
#|}
#|#deprecated("Use the corresponding function in `immut/vector` instead", skip_current_package=true)
#|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) |> T::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)
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[A : Show] Show for T[A]
#|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, leaf in leaves {
#| arr[i] = Leaf(leaf)
#| }
#| Node(arr, None)
#| } else {
#| let len = leaves.length() * branching_factor
#| let child_cap = cap / branching_factor
#| let quot = len / child_cap
#| let rem = len % child_cap
#| let times = child_cap / branching_factor
#| let arr = if rem == 0 {
#| FixedArray::makei(quot, i => {
#| 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)
#| }
#|}
),
"debug.mbt": (
#|using @debug {trait Debug, type Repr}
#|pub impl[A : Debug] Debug for T[A] with to_repr(self) {
#| Repr::opaque_(
#| "Array",
#| Repr::array(self.to_array().map(x => @debug.to_repr(x))),
#| )
#|}
#|#deprecated("Use the corresponding function in `immut/vector` instead", skip_current_package=true)
#|pub fn[A : Debug] T::to_repr(self : T[A]) -> Repr {
#| @debug.to_repr(self)
#|}
#|test "Debug for Array" {
#| let xs : T[Int] = T::from_array([1, 2, 3])
#| @debug.debug_inspect(xs, content="")
#|}
),
"deprecated.mbt": (
#|#deprecated("Use the corresponding function in `immut/vector` instead", skip_current_package=true)
#|#coverage.skip
#|#alias(clone, deprecated="Use the corresponding function in `immut/vector` instead")
#|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 {
#| for cur = self {
#| match cur {
#| Leaf(leaf) => break leaf[0]
#| Node(node, _) => continue node[0]
#| Empty => abort("Index out of bounds")
#| }
#| }
#|}
#|fn[T] Tree::get_last(self : Tree[T]) -> T {
#| for cur = self {
#| match cur {
#| Leaf(leaf) => break leaf[leaf.length() - 1]
#| Node(node, _) => continue node[node.length() - 1]
#| 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 {
#| for cur = node, s = shift {
#| match cur {
#| Leaf(leaf) => break leaf[index & bitmask]
#| Node(node, None) =>
#| continue node[radix_indexing(index, s)], s - 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() {
#| for tree = curr_tree {
#| match 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
#| break Some(elem)
#| }
#| _ if parents.pop() is Some((parent_tree, parent_index)) => {
#| curr_tree = parent_tree
#| curr_index = parent_index
#| continue parent_tree
#| }
#| _ => break 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, x in l {
#| f(start + i, x)
#| }
#| Node(ns, None) => {
#| let child_shift = shift - num_bits
#| for child in ns; start = start {
#| child.eachi(f, child_shift, start)
#| continue start + (1 << shift)
#| }
#| }
#| Node(ns, Some(sizes)) => {
#| let child_shift = shift - num_bits
#| for i, child in ns; start = start {
#| child.eachi(f, child_shift, start)
#| continue start + sizes[i]
#| }
#| }
#| }
#|}
#|fn[A, B] Tree::fold(
#| self : Tree[A],
#| acc : B,
#| f : (B, A) -> 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={},
files={
"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? {
#| for node = self, path = path {
#| match (node, path) {
#| (Leaf(key1, value1, bucket), _) =>
#| break if key == key1 { Some(value1) } else { bucket.lookup(key) }
#| (Flat(key1, value1, path1), path) =>
#| break 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()
#| }
#| break 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 child in children.data; total_size = 0 {
#| continue total_size + node_size(child)
#| } 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)
#| }
#| }
#| if self.0 is 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() {
#| for cn = curr_node {
#| match cn {
#| Tree(Flat(k, v, _)) => {
#| curr_node = empty
#| break Some((k, v))
#| }
#| Tree(Leaf(k, v, bucket)) => {
#| curr_node = Bucket(bucket)
#| break Some((k, v))
#| }
#| Bucket(More(pair, tail~)) => {
#| curr_node = Bucket(tail)
#| break 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(_)) => break 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))
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[K : Show, V : Show] Show for HashMap[K, V]
#|#warnings("-deprecated")
#|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] {
#| for n = arr.length(), map = new() {
#| match (n, map) {
#| (0, map) => break 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)] {
#| [
#| for k, v in self { (k, v) }
#| ]
#|}
#|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()
#| }),
#| )
#|}
),
"debug.mbt": (
#|using @debug {trait Debug, type Repr}
#|pub impl[K : Debug, V : Debug] Debug for HashMap[K, V] with to_repr(self) {
#| let entries : Array[(Repr, Repr)] = self
#| .to_array()
#| .map(kv => (@debug.to_repr(kv.0), @debug.to_repr(kv.1)))
#| Repr::opaque_("HashMap", Repr::map(entries))
#|}
#|#deprecated("use `to_repr(a)` instead", skip_current_package=true)
#|pub fn[K : Debug, V : Debug] HashMap::to_repr(self : HashMap[K, V]) -> Repr {
#| @debug.to_repr(self)
#|}
#|test "Debug for HashMap" {
#| let hm : HashMap[Int, String] = from_array([(2, "b")])
#| @debug.debug_inspect(
#| hm,
#| content=(
#| #|
#| ),
#| )
#|}
),
"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={},
files={
"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 {
#| for s = self, p = path {
#| match (s, p) {
#| (Leaf(key1, bucket), _) => break key == key1 || bucket.contains(key)
#| (Flat(key1, path1), path) => break path == path1 && key == key1
#| (Branch(children), path) => {
#| let idx = path.idx()
#| if children.get(idx) is Some(child) {
#| continue child, path.next()
#| }
#| break 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 child in children.data; total_size = 0 {
#| continue total_size + node_size(child)
#| } 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)
#| }
#| }
#| if self.0 is 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() {
#| for cn = curr_node {
#| match cn {
#| Tree(Flat(x, _)) => {
#| curr_node = empty
#| break Some(x)
#| }
#| Tree(Leaf(x, bucket)) => {
#| curr_node = Bucket(bucket)
#| break Some(x)
#| }
#| Bucket(More(x, tail~)) => {
#| curr_node = Bucket(tail)
#| break 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(_)) => break 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))
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[A : Show] Show for HashSet[A]
#|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] {
#| for n = arr.length(), set = new() {
#| match (n, set) {
#| (0, set) => break 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" {
#| @test.assert_eq(
#| Hash::hash(from_array([1, 2, 3, 4])),
#| Hash::hash(from_array([3, 2]).add(1).add(4)),
#| )
#| @test.assert_not_eq(
#| Hash::hash(from_array([1, 2, 3])),
#| Hash::hash(from_array([1, 2, 4])),
#| )
#|}
#|test "eq" {
#| @test.assert_eq(from_array([1, 2, 3, 4]), from_array([3, 2]).add(1).add(4))
#| @test.assert_not_eq(from_array([1, 2, 3]), from_array([1, 2, 4]))
#|}
),
"debug.mbt": (
#|using @debug {trait Debug, type Repr}
#|pub impl[K : Debug] Debug for HashSet[K] with to_repr(self) {
#| Repr::opaque_("HashSet", Repr::array([ for x in self { @debug.to_repr(x) } ]))
#|}
#|#deprecated("use `to_repr(a)` instead", skip_current_package=true)
#|pub fn[K : Debug] HashSet::to_repr(self : HashSet[K]) -> Repr {
#| @debug.to_repr(self)
#|}
#|test "Debug for HashSet" {
#| let hs : HashSet[Int] = from_array([3])
#| @debug.debug_inspect(hs, content="")
#|}
),
"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={},
files={
"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={},
files={
"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" {
#| @debug.debug_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.. @debug.to_repr(x))
#| Repr::opaque_("PriorityQueue", Repr::array(xs))
#|}
#|#deprecated("use `to_repr(a)` instead", skip_current_package=true)
#|pub fn[A : Debug + Compare] PriorityQueue::to_repr(
#| self : PriorityQueue[A],
#|) -> Repr {
#| @debug.to_repr(self)
#|}
#|test "Debug for PriorityQueue" {
#| let pq : PriorityQueue[Int] = from_array([3, 1, 2])
#| @debug.debug_inspect(pq, content="")
#|}
),
"deprecated.mbt": (
#|#deprecated("Use `PriorityQueue([])` instead")
#|#as_free_fn(deprecated="Use `PriorityQueue([])` instead")
#|pub fn[A] PriorityQueue::new() -> PriorityQueue[A] {
#| new_priority_queue()
#|}
),
"priority_queue.mbt": (
#|fn[A] new_priority_queue() -> PriorityQueue[A] {
#| { node: Empty, size: 0 }
#|}
#|#alias(from_array)
#|#as_free_fn(from_array)
#|#alias(of, deprecated="Use from_array instead")
#|#as_free_fn(of, deprecated="Use from_array instead")
#|pub fn[A : Compare] PriorityQueue::PriorityQueue(
#| array : ArrayView[A],
#|) -> PriorityQueue[A] {
#| for x in array; pq = (new_priority_queue() : 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_priority_queue(), (s, e) => s.push(e))
#|}
#|priv struct Path(Int)
#|fn path(size : Int) -> Path {
#| for x = size, y = 0 {
#| match (x, y) {
#| (1, y) => break 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
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[A : Show + Compare] Show for PriorityQueue[A]
#|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],
#|) {
#| [
#| for item in self { item }
#| ]
#|}
),
},
)
///|
let moonbitlang_core_immut_sorted_map_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/immut/sorted_map",
deps={},
files={
"debug.mbt": (
#|using @debug {trait Debug, type Repr}
#|pub impl[K : Debug, V : Debug] Debug for SortedMap[K, V] with to_repr(self) {
#| Repr::opaque_(
#| "SortedMap",
#| Repr::map(
#| self.to_array().map(kv => (@debug.to_repr(kv.0), @debug.to_repr(kv.1))),
#| ),
#| )
#|}
#|#deprecated("use `to_repr(a)` instead", skip_current_package=true)
#|pub fn[K : Debug, V : Debug] SortedMap::to_repr(self : SortedMap[K, V]) -> Repr {
#| @debug.to_repr(self)
#|}
#|test "Debug for SortedMap" {
#| let sm : SortedMap[Int, String] = from_array([(1, "a"), (2, "b")])
#| @debug.debug_inspect(
#| sm,
#| content=(
#| #|
#| ),
#| )
#|}
),
"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)] {
#| [
#| for k, v in self { (k, v) }
#| ]
#|}
#|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")
#| @test.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}")
#| @test.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"),
#| ])
#| @test.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"),
#| ])
#| @test.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"),
#| ])
#| @test.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)
#| }
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[K : Show, V : Show] Show for SortedMap[K, V]
#|#warnings("-deprecated")
#|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) {
#| Json::object(
#| Map(
#| capacity=self.length(),
#| [
#| for k, v in self { (k.to_string(), v.to_json()) }
#| ],
#| ),
#| )
#|}
#|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 {
#| for x = self {
#| match x {
#| Empty => break false
#| Tree(k, l, r, ..) => {
#| let c = key.compare(k)
#| if c == 0 {
#| break 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? {
#| for x = self {
#| match x {
#| Empty => break None
#| Tree(k, value~, l, r, ..) => {
#| let c = key.compare(k)
#| if c == 0 {
#| break 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 {
#| for x = self {
#| match x {
#| Empty => break panic()
#| Tree(k, value~, l, r, ..) => {
#| let c = key.compare(k)
#| if c == 0 {
#| break 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 item in array; mp = Empty {
#| let (k, v) = item
#| continue 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() {
#| for x = curr_node {
#| match x {
#| Tree(k, value~, Empty, r, ..) => {
#| curr_node = r
#| break 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
#| break Some((k, v))
#| }
#| Empty => break None
#| }
#| }
#| },
#| size_hint=self.length(),
#| )
#|}
#|#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() {
#| for x = next_node {
#| match x {
#| 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
#| break 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
#| break Some((k, value))
#| }
#| Empty => break 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() {
#| for x = curr_node {
#| match x {
#| Tree(k, l, Empty, ..) => {
#| curr_node = l
#| break Some(k)
#| }
#| Tree(k, l, r, ..) => {
#| parents.push((k, l))
#| continue r
#| }
#| Empty if parents.pop() is Some((k, l)) => {
#| curr_node = l
#| break Some(k)
#| }
#| Empty => break None
#| }
#| }
#| },
#| size_hint=self.length(),
#| )
#|}
#|pub fn[K, V] SortedMap::rev_values(self : SortedMap[K, V]) -> Iter[V] {
#| let mut curr_node = self
#| let parents = []
#| Iter::new(
#| fn() {
#| for x = curr_node {
#| match x {
#| Tree(_k, value~, l, Empty, ..) => {
#| curr_node = l
#| break Some(value)
#| }
#| Tree(_k, value~, l, r, ..) => {
#| parents.push((value, l))
#| continue r
#| }
#| Empty if parents.pop() is Some((v, l)) => {
#| curr_node = l
#| break Some(v)
#| }
#| Empty => break None
#| }
#| }
#| },
#| size_hint=self.length(),
#| )
#|}
#|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={},
files={
"debug.mbt": (
#|using @debug {trait Debug, type Repr}
#|pub impl[K : Debug] Debug for SortedSet[K] with to_repr(self) {
#| Repr::opaque_(
#| "SortedSet",
#| Repr::array(self.to_array().map(x => @debug.to_repr(x))),
#| )
#|}
#|#deprecated("use `to_repr(a)` instead", skip_current_package=true)
#|pub fn[K : Debug] SortedSet::to_repr(self : SortedSet[K]) -> Repr {
#| @debug.to_repr(self)
#|}
#|test "Debug for SortedSet" {
#| let ss : SortedSet[Int] = from_array([3, 1, 2])
#| @debug.debug_inspect(ss, content="")
#|}
),
"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() {
#| for x = curr_node {
#| match x {
#| Node(left~, right=Empty, value~, ..) => {
#| curr_node = left
#| break Some(value)
#| }
#| Node(left~, right~, value~, ..) => {
#| parents.push((value, left))
#| continue right
#| }
#| Empty if parents.pop() is Some((value, left)) => {
#| curr_node = left
#| break Some(value)
#| }
#| Empty => break None
#| }
#| }
#| },
#| size_hint=self.length(),
#| )
#|}
#|#alias(iterator, deprecated)
#|pub fn[A] SortedSet::iter(self : SortedSet[A]) -> Iter[A] {
#| let mut curr_node = self
#| let parents = []
#| Iter::new(
#| fn() {
#| for x = curr_node {
#| match x {
#| Node(left=Empty, right~, value~, size=_) => {
#| curr_node = right
#| break Some(value)
#| }
#| Node(left~, right~, value~, size=_) => {
#| parents.push((value, right))
#| continue left
#| }
#| Empty if parents.pop() is Some((value, right)) => {
#| curr_node = right
#| break Some(value)
#| }
#| Empty => break None
#| }
#| }
#| },
#| size_hint=self.length(),
#| )
#|}
#|#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 {
#| for cur = self {
#| match cur {
#| Empty => abort("min: there are no values in sorted_set.")
#| Node(left~, value~, ..) =>
#| if left is Empty {
#| break value
#| } else {
#| continue left
#| }
#| }
#| }
#|}
#|pub fn[A] SortedSet::min_option(self : SortedSet[A]) -> A? {
#| for cur = self {
#| match cur {
#| Empty => break None
#| Node(left~, value~, ..) =>
#| if left is Empty {
#| break Some(value)
#| } else {
#| continue left
#| }
#| }
#| }
#|}
#|pub fn[A] SortedSet::max(self : SortedSet[A]) -> A {
#| for cur = self {
#| match cur {
#| Empty => abort("max: there are no values in ImmutableSet.")
#| Node(right~, value~, ..) =>
#| if right is Empty {
#| break value
#| } else {
#| continue right
#| }
#| }
#| }
#|}
#|pub fn[A] SortedSet::max_option(self : SortedSet[A]) -> A? {
#| for cur = self {
#| match cur {
#| Empty => break None
#| Node(right~, value~, ..) =>
#| if right is Empty {
#| break Some(value)
#| } else {
#| continue right
#| }
#| }
#| }
#|}
#|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() {
#| for x = next_node {
#| match x {
#| 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
#| break Some(value)
#| } else {
#| todo_list.push((value, right))
#| continue left
#| }
#| }
#| Empty if todo_list.pop() is Some((value, right)) => {
#| next_node = right
#| break Some(value)
#| }
#| Empty => break 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)
#| }
#| }
#| }
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[A : Show] Show for SortedSet[A]
#|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) {
#| [
#| for a in self { a }
#| ]
#|}
#|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)
#| @debug.debug_inspect(
#| balanced_set,
#| content=(
#| #|
#| ),
#| )
#|}
#|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)
#| @debug.debug_inspect(
#| balanced_set,
#| content=(
#| #|
#| ),
#| )
#|}
#|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)
#| @debug.debug_inspect(
#| joined_set,
#| content=(
#| #|
#| ),
#| )
#|}
#|test "hash" {
#| @test.assert_eq(
#| Hash::hash(from_array([1, 2, 3, 4])),
#| Hash::hash(from_array([3, 2]).add(1).add(4)),
#| )
#| @test.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_immut_vector_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/immut/vector",
deps={},
files={
"debug.mbt": (
#|using @debug {trait Debug, type Repr}
#|pub impl[A : Debug] Debug for Vector[A] with to_repr(self) {
#| Repr::opaque_(
#| "Vector",
#| Repr::array(self.to_array().map(x => @debug.to_repr(x))),
#| )
#|}
#|#deprecated("use `to_repr(a)` instead", skip_current_package=true)
#|pub fn[A : Debug] Vector::to_repr(self : Vector[A]) -> Repr {
#| @debug.to_repr(self)
#|}
#|test "Debug for Vector" {
#| let xs : Vector[Int] = from_array([1, 2, 3])
#| @debug.debug_inspect(xs, content="")
#|}
),
"deprecated.mbt": (
#|#deprecated("We don't copy immutable vector")
#|#coverage.skip
#|#alias(clone, deprecated)
#|pub fn[A] Vector::copy(self : Vector[A]) -> Vector[A] {
#| self
#|}
),
"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(self : Tree[T], index : Int, shift : Int) -> T {
#| fn get_radix(node : Tree[T], shift : Int) -> T {
#| for cur = node, s = shift {
#| match cur {
#| Leaf(leaf) => break leaf[index & bitmask]
#| Node(node, None) =>
#| continue node[radix_indexing(index, s)], s - 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 : Eq] Tree::contains(self : Tree[A], value : A) -> Bool {
#| match self {
#| Empty => false
#| Leaf(elems) =>
#| for elem in elems {
#| guard elem != value else { break true }
#| } nobreak {
#| false
#| }
#| Node(children, _) =>
#| for child in children {
#| guard !child.contains(value) else { break true }
#| } nobreak {
#| false
#| }
#| }
#|}
#|fn[A] Tree::iter(self : Tree[A]) -> Iter[A] {
#| let mut curr_tree = self
#| let mut curr_index = 0
#| let parents = []
#| Iter::new(fn() {
#| for tree = curr_tree {
#| match 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
#| break Some(elem)
#| }
#| _ if parents.pop() is Some((parent_tree, parent_index)) => {
#| curr_tree = parent_tree
#| curr_index = parent_index
#| continue parent_tree
#| }
#| _ => break 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, x in l {
#| f(start + i, x)
#| }
#| Node(ns, None) => {
#| let child_shift = shift - num_bits
#| for child in ns; start = start {
#| child.eachi(f, child_shift, start)
#| continue start + (1 << shift)
#| }
#| }
#| Node(ns, Some(sizes)) => {
#| let child_shift = shift - num_bits
#| for i, child in ns; offset = 0 {
#| child.eachi(f, child_shift, start + offset)
#| continue sizes[i]
#| }
#| }
#| }
#|}
#|fn[A, B] Tree::fold(
#| self : Tree[A],
#| acc : B,
#| f : (B, A) -> 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..)]>,
#| #| Some(),
#| #|)
#| ),
#| )
#| @debug.debug_inspect(
#| Node([Empty, Leaf([42])], Some([0, 1])),
#| content=(
#| #|Node(
#| #| )]>,
#| #| Some(),
#| #|)
#| ),
#| )
#|}
),
"tree_append.mbt": (
#|fn append_sizes_last(sizes : FixedArray[Int]?, delta : Int) -> FixedArray[Int]? {
#| match sizes {
#| Some(sizes) => {
#| let new_sizes = sizes.copy()
#| new_sizes[new_sizes.length() - 1] += delta
#| Some(new_sizes)
#| }
#| None => None
#| }
#|}
#|fn push_sizes_last(sizes : FixedArray[Int]?, delta : Int) -> FixedArray[Int]? {
#| match sizes {
#| Some(sizes) =>
#| Some(immutable_push(sizes, delta + sizes[sizes.length() - 1]))
#| None => None
#| }
#|}
#|fn[T] Tree::append_right_leaf(
#| self : Tree[T],
#| shift : Int,
#| leaf : FixedArray[T],
#|) -> (Tree[T], Int) {
#| let delta = leaf.length()
#| guard delta > 0 else { return (self, shift) }
#| fn worker(
#| node : Tree[T],
#| shift : Int,
#| leaf : FixedArray[T],
#| delta : Int,
#| ) -> Tree[T]? {
#| match node {
#| Leaf(elems) => {
#| guard shift == 0 else {
#| abort("Unreachable: Leaf should only appear at shift 0")
#| }
#| if elems.length() + delta <= branching_factor {
#| Some(Leaf(immutable_concat(elems, leaf)))
#| } else {
#| None
#| }
#| }
#| Node(nodes, sizes) => {
#| let len = nodes.length()
#| match worker(nodes[len - 1], shift - num_bits, leaf, delta) {
#| Some(new_node) =>
#| Some(
#| Node(
#| immutable_set(nodes, len - 1, new_node),
#| append_sizes_last(sizes, delta),
#| ),
#| )
#| None =>
#| if len < branching_factor {
#| Some(
#| Node(
#| immutable_push(nodes, new_branch_left(leaf, shift - num_bits)),
#| push_sizes_last(sizes, delta),
#| ),
#| )
#| } else {
#| None
#| }
#| }
#| }
#| Empty => Some(Leaf(leaf))
#| }
#| }
#| match worker(self, shift, leaf, delta) {
#| Some(new_tree) => (new_tree, shift)
#| None => {
#| let new_branch = new_branch_left(leaf, shift)
#| (
#| match self {
#| Leaf(_) => Node([self, new_branch], None)
#| Node(_, Some(sizes)) => {
#| let len = sizes[sizes.length() - 1]
#| Node([self, new_branch], Some([len, len + delta]))
#| }
#| Node(_, None) => Node([self, new_branch], None)
#| Empty =>
#| abort("Unreachable: Empty tree should have been handled in worker")
#| },
#| shift + num_bits,
#| )
#| }
#| }
#|}
#|fn[T] Tree::concat_with_suffix(
#| left : Tree[T],
#| left_shift : Int,
#| suffix : FixedArray[T],
#| right : Tree[T],
#| right_shift : Int,
#| top : Bool,
#|) -> (Tree[T], Int) {
#| if suffix.length() == 0 {
#| return Tree::concat(left, left_shift, right, right_shift, top)
#| }
#| if left_shift > right_shift {
#| let (c, c_shift) = Tree::concat_with_suffix(
#| left.right_child(),
#| left_shift - num_bits,
#| suffix,
#| right,
#| right_shift,
#| false,
#| )
#| guard c_shift == left_shift
#| rebalance(left, c, Empty, left_shift, top)
#| } else if right_shift > left_shift {
#| let (c, c_shift) = Tree::concat_with_suffix(
#| left,
#| left_shift,
#| suffix,
#| right.left_child(),
#| right_shift - num_bits,
#| false,
#| )
#| guard c_shift == right_shift
#| rebalance(Empty, c, right, right_shift, top)
#| } else if left_shift == 0 {
#| let leaves = FixedArray::from_array([left, Leaf(suffix), right])
#| let (node_counts, new_len) = redis_plan(leaves)
#| let new_children = redis(leaves, node_counts, new_len, 0)
#| if top && new_len == 1 {
#| (new_children[0], 0)
#| } else {
#| let node = Node(new_children, compute_sizes(new_children, 0))
#| (node, num_bits)
#| }
#| } else {
#| let (c, c_shift) = Tree::concat_with_suffix(
#| left.right_child(),
#| left_shift - num_bits,
#| suffix,
#| right.left_child(),
#| right_shift - num_bits,
#| false,
#| )
#| guard c_shift == left_shift
#| guard c_shift == right_shift
#| rebalance(left, c, right, left_shift, top)
#| }
#|}
),
"tree_pop.mbt": (
#|fn[A] Tree::last_leaf_elements(self : Tree[A]) -> FixedArray[A] {
#| match self {
#| Leaf(leaf) => leaf
#| Node(children, _) => children[children.length() - 1].last_leaf_elements()
#| Empty => abort("Empty tree has no last leaf")
#| }
#|}
#|fn[A] Tree::pop_rightmost_leaf(self : Tree[A], shift : Int) -> Tree[A] {
#| match self {
#| Empty => Empty
#| Leaf(_) => Empty
#| Node(children, _) => {
#| let last_index = children.length() - 1
#| let new_last = children[last_index].pop_rightmost_leaf(shift - num_bits)
#| if new_last is Empty {
#| if last_index == 0 {
#| Empty
#| } else {
#| let new_children = immutable_slice(children, 0, last_index)
#| Node(new_children, compute_sizes(new_children, shift - num_bits))
#| }
#| } else {
#| let new_children = immutable_set(children, last_index, new_last)
#| Node(new_children, compute_sizes(new_children, shift - num_bits))
#| }
#| }
#| }
#|}
#|fn[A] Tree::shrink_top(self : Tree[A], shift : Int) -> (Tree[A], Int) {
#| let mut current_shift = shift
#| for tree = self {
#| match tree {
#| Node(children, _) if current_shift > 0 && children.length() == 1 => {
#| current_shift -= num_bits
#| continue children[0]
#| }
#| Empty => break (Empty, 0)
#| current => break (current, current_shift)
#| }
#| }
#|}
),
"tree_slice.mbt": (
#|fn[A] Tree::slice_right(self : Tree[A], shift : Int, end : Int) -> Tree[A] {
#| guard end > 0 else { return Empty }
#| guard end < self.size(shift) else { return self }
#| match self {
#| Empty => Empty
#| Leaf(leaf) => Leaf(immutable_slice(leaf, 0, end))
#| Node(children, sizes) => {
#| let child_shift = shift - num_bits
#| let child_index = match sizes {
#| Some(sizes) => get_branch_index(sizes, end - 1)
#| None => radix_indexing(end - 1, shift)
#| }
#| let child_start = match sizes {
#| Some(sizes) => if child_index == 0 { 0 } else { sizes[child_index - 1] }
#| None => child_index * (1 << shift)
#| }
#| let new_len = child_index + 1
#| let new_children = FixedArray::make(new_len, children[0])
#| for i in 0.. Tree[A] {
#| guard start > 0 else { return self }
#| match self {
#| Empty => Empty
#| Leaf(leaf) => Leaf(immutable_slice(leaf, start, leaf.length()))
#| Node(children, sizes) => {
#| let child_shift = shift - num_bits
#| let child_index = match sizes {
#| Some(sizes) => get_branch_index(sizes, start)
#| None => radix_indexing(start, shift)
#| }
#| let child_start = match sizes {
#| Some(sizes) =>
#| if child_index == 0 {
#| start
#| } else {
#| start - sizes[child_index - 1]
#| }
#| None => start - child_index * (1 << shift)
#| }
#| let new_len = children.length() - child_index
#| let new_children = FixedArray::make(
#| new_len,
#| children[child_index].slice_left(child_shift, child_start),
#| )
#| for i in 1.. 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 Vector[A] {
#| tree : Tree[A]
#| tail : FixedArray[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, @debug.Debug)
),
"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[T] immutable_concat(
#| left : FixedArray[T],
#| right : FixedArray[T],
#|) -> FixedArray[T] {
#| let left_len = left.length()
#| let right_len = right.length()
#| if left_len == 0 {
#| right.copy()
#| } else if right_len == 0 {
#| left.copy()
#| } else {
#| FixedArray::makei(left_len + right_len, i => {
#| if i < left_len {
#| left[i]
#| } else {
#| right[i - left_len]
#| }
#| })
#| }
#|}
#|fn[T] immutable_slice(
#| arr : FixedArray[T],
#| start : Int,
#| end : Int,
#|) -> FixedArray[T] {
#| let len = end - start
#| if len <= 0 {
#| []
#| } else {
#| FixedArray::makei(len, i => arr[start + i])
#| }
#|}
#|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")
#|}
),
"vector.mbt": (
#|#as_free_fn
#|pub fn[A] Vector::new() -> Vector[A] {
#| make_t(Tree::empty(), [], 0, 0)
#|}
#|#as_free_fn
#|pub fn[A] Vector::singleton(value : A) -> Vector[A] {
#| make_t(Tree::empty(), [value], 1, 0)
#|}
#|#as_free_fn
#|pub fn[A] Vector::make(len : Int, value : A) -> Vector[A] {
#| guard len > 0 else { new() }
#| let tail_len = tail_len_of_size(len)
#| let tree_len = len - tail_len
#| let tail = FixedArray::make(tail_len, value)
#| let (tree, shift) = if tree_len == 0 {
#| (Tree::empty(), 0)
#| } else {
#| let leaves = Array::make(
#| tree_len / branching_factor,
#| FixedArray::make(branching_factor, value),
#| )
#| let (shift, cap) = shift_cap_of_size(tree_len)
#| (from_leaves(leaves, cap), shift)
#| }
#| make_t(tree, tail, len, shift)
#|}
#|#as_free_fn
#|pub fn[A] Vector::makei(len : Int, f : (Int) -> A raise?) -> Vector[A] raise? {
#| guard len > 0 else { new() }
#| let tail_len = tail_len_of_size(len)
#| let tree_len = len - tail_len
#| let tail = FixedArray::makei(tail_len, i => f(tree_len + i))
#| let (tree, shift) = if tree_len == 0 {
#| (Tree::empty(), 0)
#| } else {
#| let quot = tree_len / branching_factor
#| let leaves : Array[FixedArray[A]] = Array::make(quot, [])
#| for k in 0.. {
#| f(k * branching_factor + i)
#| })
#| }
#| let (shift, cap) = shift_cap_of_size(tree_len)
#| (from_leaves(leaves, cap), shift)
#| }
#| make_t(tree, tail, len, shift)
#|}
#|#alias(from_array)
#|#as_free_fn(from_array)
#|#alias(of, deprecated="Use from_array instead")
#|#as_free_fn(of, deprecated="Use from_array instead")
#|pub fn[A] Vector::Vector(arr : ArrayView[A]) -> Vector[A] {
#| Vector::makei(arr.length(), i => arr[i])
#|}
#|#as_free_fn
#|#alias(from_iterator, deprecated)
#|#as_free_fn(from_iterator, deprecated)
#|pub fn[A] Vector::from_iter(iter : Iter[A]) -> Vector[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 == 0 {
#| return new()
#| }
#| let tail = if index == branching_factor {
#| if leaves.is_empty() {
#| buf
#| } else {
#| leaves.push(buf)
#| []
#| }
#| } else {
#| let res = FixedArray::make(index, buf[0])
#| buf.blit_to(res, len=index)
#| res
#| }
#| let tree_len = leaves.length() * branching_factor
#| let (tree, shift) = if tree_len == 0 {
#| (Tree::empty(), 0)
#| } else {
#| let (shift, cap) = shift_cap_of_size(tree_len)
#| (from_leaves(leaves, cap), shift)
#| }
#| make_t(tree, tail, tree_len + tail.length(), shift)
#|}
#|pub fn[A] Vector::to_array(self : Vector[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] Vector::is_empty(self : Vector[A]) -> Bool {
#| self.size == 0
#|}
#|pub fn[A] Vector::length(self : Vector[A]) -> Int {
#| self.size
#|}
#|fn[A] Vector::tail_offset(self : Vector[A]) -> Int {
#| self.size - self.tail.length()
#|}
#|#alias("_[_]")
#|pub fn[A] Vector::at(self : Vector[A], index : Int) -> A {
#| guard index >= 0 && index < self.size
#| let tail_offset = self.tail_offset()
#| if index >= tail_offset {
#| self.tail[index - tail_offset]
#| } else {
#| self.tree.get(index, self.shift)
#| }
#|}
#|pub fn[A] Vector::get(self : Vector[A], index : Int) -> A? {
#| guard 0 <= index && index < self.size else { None }
#| Some(self[index])
#|}
#|pub fn[A] Vector::peek(self : Vector[A]) -> A? {
#| if self.size == 0 {
#| None
#| } else {
#| Some(self[self.size - 1])
#| }
#|}
#|pub fn[A : Eq] Vector::contains(self : Vector[A], value : A) -> Bool {
#| if self.tree.contains(value) {
#| return true
#| }
#| self.tail.contains(value)
#|}
#|pub fn[A] Vector::set(self : Vector[A], index : Int, value : A) -> Vector[A] {
#| guard index >= 0 && index < self.size
#| let tail_len = self.tail.length()
#| if tail_len == 0 {
#| make_t(
#| self.tree.set(index, self.shift, value),
#| self.tail,
#| self.size,
#| self.shift,
#| )
#| } else {
#| let tail_offset = self.tail_offset()
#| if index >= tail_offset {
#| make_t(
#| self.tree,
#| immutable_set(self.tail, index - tail_offset, value),
#| self.size,
#| self.shift,
#| )
#| } else {
#| make_t(
#| self.tree.set(index, self.shift, value),
#| self.tail,
#| self.size,
#| self.shift,
#| )
#| }
#| }
#|}
#|pub fn[A] Vector::push(self : Vector[A], value : A) -> Vector[A] {
#| if self.tail.length() < branching_factor {
#| make_t(
#| self.tree,
#| immutable_push(self.tail, value),
#| self.size + 1,
#| self.shift,
#| )
#| } else {
#| let (tree, shift) = if self.tree is Empty {
#| (Leaf(self.tail), 0)
#| } else {
#| self.tree.append_right_leaf(self.shift, self.tail)
#| }
#| make_t(tree, [value], self.size + 1, shift)
#| }
#|}
#|pub fn[A] Vector::pop(self : Vector[A]) -> Vector[A]? {
#| if self.size == 0 {
#| None
#| } else if self.size == 1 {
#| Some(new())
#| } else if self.tail.length() > 1 {
#| Some(
#| make_t(
#| self.tree,
#| immutable_slice(self.tail, 0, self.tail.length() - 1),
#| self.size - 1,
#| self.shift,
#| ),
#| )
#| } else if self.tail.length() == 1 {
#| let new_tail = self.tree.last_leaf_elements()
#| let (tree, shift) = self.tree
#| .pop_rightmost_leaf(self.shift)
#| .shrink_top(self.shift)
#| Some(make_t(tree, new_tail, self.size - 1, shift))
#| } else {
#| let last_leaf = self.tree.last_leaf_elements()
#| if last_leaf.length() > 1 {
#| let (tree, shift) = self.tree
#| .pop_rightmost_leaf(self.shift)
#| .shrink_top(self.shift)
#| Some(
#| make_t(
#| tree,
#| immutable_slice(last_leaf, 0, last_leaf.length() - 1),
#| self.size - 1,
#| shift,
#| ),
#| )
#| } else {
#| let stripped = self.tree.pop_rightmost_leaf(self.shift)
#| let (promoted_tree, promoted_shift) = stripped.shrink_top(self.shift)
#| if promoted_tree is Empty {
#| Some(new())
#| } else {
#| let new_tail = promoted_tree.last_leaf_elements()
#| let (tree, shift) = promoted_tree
#| .pop_rightmost_leaf(promoted_shift)
#| .shrink_top(promoted_shift)
#| Some(make_t(tree, new_tail, self.size - 1, shift))
#| }
#| }
#| }
#|}
#|pub fn[A] Vector::concat(self : Vector[A], other : Vector[A]) -> Vector[A] {
#| if self.is_empty() {
#| return other
#| }
#| if other.is_empty() {
#| return self
#| }
#| let size = self.size + other.size
#| if other.tree is Empty {
#| let combined_tail_len = self.tail.length() + other.tail.length()
#| if combined_tail_len <= branching_factor {
#| return make_t(
#| self.tree,
#| immutable_concat(self.tail, other.tail),
#| size,
#| self.shift,
#| )
#| } else if self.tail.length() == 0 {
#| return make_t(self.tree, other.tail, size, self.shift)
#| } else {
#| let (tree, shift) = self.normalize_tree()
#| return make_t(tree, other.tail, size, shift)
#| }
#| }
#| let (tree, shift) = if self.tree is Empty {
#| Tree::concat(Leaf(self.tail), 0, other.tree, other.shift, true)
#| } else if self.tail.length() == 0 {
#| Tree::concat(self.tree, self.shift, other.tree, other.shift, true)
#| } else {
#| Tree::concat_with_suffix(
#| self.tree,
#| self.shift,
#| self.tail,
#| other.tree,
#| other.shift,
#| true,
#| )
#| }
#| make_t(tree, other.tail, size, shift)
#|}
#|pub fn[A] Vector::split(
#| self : Vector[A],
#| index : Int,
#|) -> (Vector[A], Vector[A]) {
#| guard 0 <= index && index <= self.size else { abort("Index out of bounds") }
#| (self.slice_unchecked(0, index), self.slice_unchecked(index, self.size))
#|}
#|pub fn[A] Vector::take(self : Vector[A], count : Int) -> Vector[A] {
#| let end = if count <= 0 { 0 } else { min(count, self.size) }
#| self.slice_unchecked(0, end)
#|}
#|pub fn[A] Vector::drop(self : Vector[A], count : Int) -> Vector[A] {
#| let start = if count <= 0 { 0 } else { min(count, self.size) }
#| self.slice_unchecked(start, self.size)
#|}
#|pub fn[A] Vector::slice(self : Vector[A], start : Int, end : Int) -> Vector[A] {
#| guard start <= end else { abort("start index greater than end index") }
#| guard 0 <= start && end <= self.size else { abort("Index out of bounds") }
#| self.slice_unchecked(start, end)
#|}
#|pub impl[A] Add for Vector[A] with add(self, other) {
#| self.concat(other)
#|}
#|#alias(iterator, deprecated)
#|pub fn[A] Vector::iter(self : Vector[A]) -> Iter[A] {
#| let tree_iter = self.tree.iter()
#| let tail_iter = self.tail.iter()
#| let iter = tree_iter.concat(tail_iter)
#| Iter::new(() => iter.next(), size_hint=self.size)
#|}
#|pub fn[A] Vector::each(self : Vector[A], f : (A) -> Unit raise?) -> Unit raise? {
#| self.tree.each(f)
#| self.tail.each(f)
#|}
#|pub fn[A] Vector::eachi(
#| self : Vector[A],
#| f : (Int, A) -> Unit raise?,
#|) -> Unit raise? {
#| self.tree.eachi(f, self.shift, 0)
#| let tail_offset = self.tail_offset()
#| for i, x in self.tail {
#| f(tail_offset + i, x)
#| }
#|}
#|#alias(fold_left, deprecated)
#|pub fn[A, B] Vector::fold(
#| self : Vector[A],
#| init~ : B,
#| f : (B, A) -> B raise?,
#|) -> B raise? {
#| let acc = self.tree.fold(init, f)
#| self.tail.fold(f, init=acc)
#|}
#|#alias(fold_right, deprecated)
#|pub fn[A, B] Vector::rev_fold(
#| self : Vector[A],
#| init~ : B,
#| f : (B, A) -> B raise?,
#|) -> B raise? {
#| let acc = self.tail.rev_fold(f, init~)
#| self.tree.rev_fold(acc, f)
#|}
#|pub fn[A, B] Vector::map(
#| self : Vector[A],
#| f : (A) -> B raise?,
#|) -> Vector[B] raise? {
#| make_t(self.tree.map(f), self.tail.map(f), self.size, self.shift)
#|}
#|pub fn[A] Vector::filter(
#| self : Vector[A],
#| f : (A) -> Bool raise?,
#|) -> Vector[A] raise? {
#| let arr : Array[A] = Array::new(capacity=self.size)
#| self.each(value => if f(value) { arr.push(value) })
#| from_array(arr)
#|}
#|pub fn[A] Vector::rev(self : Vector[A]) -> Vector[A] {
#| if self.size == 0 {
#| new()
#| } else {
#| let arr = Array::make(self.size, self[0])
#| self.eachi((i, value) => arr[self.size - 1 - i] = value)
#| from_array(arr)
#| }
#|}
#|pub impl[X : @quickcheck.Arbitrary] @quickcheck.Arbitrary for Vector[X] with arbitrary(
#| size,
#| rs,
#|) {
#| @quickcheck.Arbitrary::arbitrary(size, rs) |> Vector::from_array
#|}
#|pub impl[A : Hash] Hash for Vector[A] with hash_combine(self, hasher) {
#| for e in self {
#| hasher.combine(e)
#| }
#|}
#|pub impl[A : Eq] Eq for Vector[A] with equal(self, other) {
#| if physical_equal(self, other) {
#| true
#| } else if self.size != other.size {
#| false
#| } else {
#| let left = self.iter()
#| let right = other.iter()
#| for _ in 0.. if a != b { return false }
#| _ => return false
#| }
#| }
#| true
#| }
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[A : Show] Show for Vector[A]
#|pub impl[A : Show] Show for Vector[A] with output(self, logger) {
#| logger.write_iter(
#| self.iter(),
#| prefix="@immut/vector.from_array([",
#| suffix="])",
#| )
#|}
#|pub impl[A : ToJson] ToJson for Vector[A] with to_json(self) {
#| [
#| for value in self { value }
#| ]
#|}
#|pub impl[A : @json.FromJson] @json.FromJson for Vector[A] with from_json(
#| json,
#| path,
#|) {
#| guard json is Json::Array(arr) else {
#| raise @json.JsonDecodeError(
#| (path, "@immut/vector.from_json: expected array"),
#| )
#| }
#| let len = arr.length()
#| guard len != 0 else { return new() }
#| let values : Array[A] = Array::new(capacity=len)
#| for i, value in arr {
#| values.push(A::from_json(value, path.add_index(i)))
#| }
#| Vector::from_array(values)
#|}
#|pub impl[A : Compare] Compare for Vector[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.. Vector[A] {
#| { tree, tail, size, shift }
#|}
#|fn[A] from_leaves(leaves : ArrayView[FixedArray[A]], cap : Int) -> Tree[A] {
#| if cap == branching_factor {
#| Leaf(leaves[0])
#| } else if leaves.length() <= branching_factor {
#| let arr = FixedArray::make(leaves.length(), Empty)
#| for i, leaf in leaves {
#| arr[i] = Leaf(leaf)
#| }
#| Node(arr, None)
#| } else {
#| let len = leaves.length() * branching_factor
#| let child_cap = cap / branching_factor
#| let quot = len / child_cap
#| let rem = len % child_cap
#| let times = child_cap / branching_factor
#| let arr = if rem == 0 {
#| FixedArray::makei(quot, i => {
#| from_leaves(leaves[i * times:(i + 1) * times], child_cap)
#| })
#| } else {
#| let arr = FixedArray::make(quot + 1, Tree::Empty)
#| for i in 0.. Int {
#| if size <= branching_factor {
#| size
#| } else {
#| let rem = size % branching_factor
#| if rem == 0 {
#| 0
#| } else {
#| rem
#| }
#| }
#|}
#|fn[A] Vector::normalize_tree(self : Vector[A]) -> (Tree[A], Int) {
#| if self.size == 0 {
#| (Tree::empty(), 0)
#| } else if self.tail.length() == 0 {
#| (self.tree, self.shift)
#| } else if self.tail_offset() == 0 {
#| (Leaf(self.tail), 0)
#| } else if self.tail.length() == 1 {
#| self.tree.push_end(self.shift, self.tail[0])
#| } else {
#| self.tree.append_right_leaf(self.shift, self.tail)
#| }
#|}
#|fn[A] Vector::slice_unchecked(
#| self : Vector[A],
#| start : Int,
#| end : Int,
#|) -> Vector[A] {
#| let len = end - start
#| if len == 0 {
#| new()
#| } else if start == 0 && end == self.size {
#| self
#| } else {
#| let tail_offset = self.tail_offset()
#| if start >= tail_offset {
#| make_t(
#| Empty,
#| immutable_slice(self.tail, start - tail_offset, end - tail_offset),
#| len,
#| 0,
#| )
#| } else {
#| let tree_end = min(end, tail_offset)
#| let sliced_tree = if tree_end == tail_offset {
#| self.tree
#| } else {
#| self.tree.slice_right(self.shift, tree_end)
#| }
#| let sliced_tree = if start == 0 {
#| sliced_tree
#| } else {
#| sliced_tree.slice_left(self.shift, start)
#| }
#| let (tree, shift) = sliced_tree.shrink_top(self.shift)
#| let tail = if end > tail_offset {
#| immutable_slice(self.tail, 0, end - tail_offset)
#| } else {
#| []
#| }
#| make_t(tree, tail, len, shift)
#| }
#| }
#|}
#|fn shift_cap_of_size(size : Int) -> (Int, Int) {
#| for cap = branching_factor, depth = 0; cap < size; {
#| continue cap * branching_factor, depth + 1
#| } nobreak {
#| (num_bits * depth, cap)
#| }
#|}
),
},
)
///|
let moonbitlang_core_int_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/int",
deps={},
files={
"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={},
files={
"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 to_string(self) {
#| Int16::to_string(self)
#|}
#|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={},
files={
"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, word in self.0 {
#| if word != -1 {
#| let bit = word.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(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([])
#| 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(() => {
#| for curr = node {
#| match curr {
#| Node(t=thread, l=Empty, r=right, ..) => {
#| node = right
#| break 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
#| break Some(thread)
#| }
#| Empty => break 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()
#| for v1 = it1.next(), v2 = it2.next() {
#| match (v1, v2) {
#| (None, None) => break true
#| (None, Some(_)) | (Some(_), None) => break false
#| (Some(b1), Some(b2)) =>
#| if b1 == b2 {
#| continue it1.next(), it2.next()
#| } else {
#| break 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
#|}
#|pub fn Profile::Profile(
#| 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 }
#|}
#|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}
),
},
)
///|
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 {
#| for node = self.0 {
#| match node {
#| Empty => break false
#| Node(l~, lo~, hi~, r~, ..) =>
#| if c < lo {
#| continue l
#| } else if c > hi {
#| continue r
#| } else {
#| break 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)? {
#| for cur = t {
#| match cur {
#| Empty => break None
#| Node(l=Empty, lo~, hi~, ..) => break Some((lo, hi))
#| Node(l~, ..) => continue l
#| }
#| }
#|}
#|fn rightmost(t : Tree) -> (Rechar, Rechar)? {
#| for cur = t {
#| match cur {
#| Empty => break None
#| Node(lo~, hi~, r=Empty, ..) => break Some((lo, hi))
#| Node(r~, ..) => continue 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() {
#| for curr = node {
#| match curr {
#| Node(l=Empty, lo~, hi~, r~, ..) => {
#| node = r
#| break 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
#| break Some((lo, hi))
#| }
#| Empty => break 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.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_internal_strconv_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/internal/strconv",
deps={},
files={
"strconv_bool.mbt": (
#|pub fn parse_bool(str : StringView) -> Bool raise {
#| lexmatch str with longest {
#| "(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 {
#| @test.assert_eq(
#| Result::Ok(parse_bool(t.0)) catch {
#| Failure::Failure(err) => Err(err)
#| err => Err(err.to_string())
#| },
#| t.1,
#| )
#| }
#|}
),
"strconv_decimal.mbt": (
#|let max_shift = 59
#|priv struct Decimal {
#| digits : FixedArray[Byte]
#| mut digits_num : Int
#| mut decimal_point : Int
#| mut negative : Bool
#| mut truncated : Bool
#|}
#|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 {
#| parse_decimal_from_view(str)
#|}
#|fn parse_decimal_from_view(str : StringView) -> Decimal raise {
#| 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 = for rest = rest {
#| match 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 => break 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 exp_limit = if exp_sign > 0 {
#| if d.decimal_point < 311 {
#| 311 - d.decimal_point
#| } else {
#| 0
#| }
#| } else if d.decimal_point > -331 {
#| d.decimal_point + 331
#| } else {
#| 0
#| }
#| let mut exp = 0
#| let rest = for rest = rest {
#| match rest {
#| ['_', .. rest] => continue rest
#| ['0'..='9' as digit, .. rest] => {
#| if exp < exp_limit {
#| exp = exp * 10 + (digit.to_int() - '0')
#| if exp > exp_limit {
#| exp = exp_limit
#| }
#| }
#| continue rest
#| }
#| rest => break 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 {
#| 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
#| }
#|}
#|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"
#| @test.assert_eq(parse_decimal_priv(s).to_string(), s)
#| @test.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)
#| @test.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" {
#| assert_true((try? parse_decimal_priv("1e")) is Err(Failure("invalid syntax")))
#| assert_true(
#| (try? parse_decimal_priv("1e+")) is Err(Failure("invalid syntax")),
#| )
#| assert_true(
#| (try? parse_decimal_priv("1e_")) is Err(Failure("invalid syntax")),
#| )
#| assert_true(
#| (try? parse_decimal_priv("1-23")) is Err(Failure("invalid syntax")),
#| )
#| assert_true(
#| (try? parse_decimal_priv("1.2.3")) is Err(Failure("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" {
#| assert_true((try? parse_decimal_priv(".123")) is Ok(_))
#| assert_true((try? parse_decimal_priv(".")) is Err(Failure("invalid syntax")))
#| assert_true((try? parse_decimal_priv("-")) is Err(Failure("invalid syntax")))
#|}
#|test "parse_double mantissa normalization boundary" {
#| inspect(parse_double("1.9999999999999999"), content="2")
#| inspect(parse_double("9007199254740991.5"), content="9007199254740992")
#|}
),
"strconv_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 {
#| 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 {
#| @test.assert_eq(
#| Result::Ok(parse_double(t.0)) catch {
#| Failure::Failure(err) => Err(err)
#| err => Err(err.to_string())
#| },
#| t.1,
#| )
#| }
#|}
#|test "parse_double_inf" {
#| @test.assert_eq(parse_double("inf"), @double.infinity)
#| @test.assert_eq(parse_double("+Inf"), @double.infinity)
#| @test.assert_eq(parse_double("-Inf"), @double.neg_infinity)
#| @test.assert_eq(parse_double("+Infinity"), @double.infinity)
#| @test.assert_eq(parse_double("-Infinity"), @double.neg_infinity)
#| @test.assert_eq(parse_double("+INFINITY"), @double.infinity)
#| @test.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())
#|}
),
"strconv_errors.mbt": (
#|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 {
#| raise Failure::Failure(range_err_str)
#|}
#|fn[T] syntax_err() -> T raise {
#| raise Failure::Failure(syntax_err_str)
#|}
#|fn[T] base_err() -> T raise {
#| raise Failure::Failure(base_err_str)
#|}
),
"strconv_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 {
#| 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 {
#| assert_true(
#| (try? parse_int64("0b01", base=3)) is Err(Failure("invalid syntax")),
#| )
#| assert_true(
#| (try? parse_int64("0x01", base=3)) is Err(Failure("invalid syntax")),
#| )
#| assert_true(
#| (try? parse_int64("0o01", base=3)) is Err(Failure("invalid syntax")),
#| )
#|}
#|pub fn parse_int64(str : StringView, base? : Int = 0) -> Int64 raise {
#| 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() }
#| for rest = rest, acc = 0L, allow_underscore = allow_underscore {
#| match (rest, acc, 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, _) => break acc
#| }
#| }
#|}
#|pub fn parse_int(str : StringView, base? : Int = 0) -> Int raise {
#| 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 with longest {
#| ("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
#| for rest = rest, allow_underscore = allow_underscore, follow_underscore = follow_underscore {
#| match (rest, allow_underscore, follow_underscore) {
#| ([], _, _) => break true
#| (['_'], _, _) => break false
#| (['_', ..], false, _) => break false
#| (['_', .. rest], true, _) => continue rest, false, true
#| ([c, .. rest], _, follow_underscore) =>
#| if is_digit(c) {
#| continue rest, true, false
#| } else if follow_underscore {
#| break 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()
#| }
#|}
),
"strconv_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
#| for s = s {
#| match 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 => break (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 {
#| 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
#| for s = start {
#| match s {
#| ['0' | '.' as ch, .. rest] => {
#| n_digits -= (ch.to_int() - 46) / 2 // '0' = b'.' + 2
#| continue rest
#| }
#| _ => break
#| }
#| }
#| 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 {
#| let (pos, rest) = match rest {
#| ['-', .. rest] => (false, rest)
#| ['+', .. rest] | rest => (true, rest)
#| }
#| lexmatch rest with longest {
#| "(?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)
#|}
),
"strconv_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)
#|}
),
"strconv_uint.mbt": (
#|const UINT_MAX : UInt = 0xffffffff
#|const UINT64_MAX : UInt64 = 0xffffffffffffffffUL
#|pub fn parse_uint64(str : StringView, base? : Int = 0) -> UInt64 raise {
#| 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() }
#| for rest = rest, acc = 0UL, allow_underscore = allow_underscore {
#| match (rest, acc, 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, _) => break acc
#| }
#| }
#|}
#|pub fn parse_uint(str : StringView, base? : Int = 0) -> UInt raise {
#| 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 {
#| @test.assert_eq(
#| Result::Ok(parse_uint64(t.0)) catch {
#| Failure::Failure(err) => Err(err)
#| err => Err(err.to_string())
#| },
#| 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 {
#| @test.assert_eq(
#| Result::Ok(parse_uint64(t.0, base=t.1)) catch {
#| Failure::Failure(err) => Err(err)
#| err => Err(err.to_string())
#| },
#| 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 {
#| @test.assert_eq(
#| Result::Ok(parse_uint(t.0)) catch {
#| Failure::Failure(err) => Err(err)
#| err => Err(err.to_string())
#| },
#| t.1,
#| )
#| }
#|}
#|test "parse_uint64 uppercase hex and invalid base" {
#| assert_true((try? parse_uint64("ABCD", base=16)) is Ok(43981))
#| assert_true(
#| (try? parse_uint64("1234", base=37)) is Err(Failure("invalid base")),
#| )
#|}
),
},
)
///|
let moonbitlang_core_json_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/json",
deps={},
files={
"deprecated.mbt": "",
"from_json.mbt": (
#|#warnings("-deprecated_syntax")
#|pub(all) suberror JsonDecodeError {
#| JsonDecodeError((JsonPath, String))
#|} derive(Eq, Show, ToJson, @debug.Debug)
#|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",
#| )
#| }
#| @internal/strconv.parse_int64(str) catch {
#| Failure::Failure(error) =>
#| decode_error(path, "Int64::from_json: parsing failure \{error}")
#| 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",
#| )
#| }
#| @internal/strconv.parse_uint64(str) catch {
#| Failure::Failure(error) =>
#| decode_error(path, "UInt64::from_json: parsing failure \{error}")
#| 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())
#| for x = a[:] {
#| match x {
#| [] => break
#| [
#| .. "\\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?
#|} derive(@debug.Debug)
#|pub fn Replacer::Replacer(f : (String, Json) -> Json?) -> Replacer {
#| { f, }
#|}
#|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(size_hint=0)
#| let stack : Array[WriteFrame] = []
#| let mut depth = 0
#| for x = Some(self) {
#| match x {
#| 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(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, @debug.Debug)
#|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(b'u')
#| ctx.expect_ascii_char(b'l')
#| ctx.expect_ascii_char(b'l')
#| return Null
#| }
#| Some('t') => {
#| ctx.expect_ascii_char(b'r')
#| ctx.expect_ascii_char(b'u')
#| ctx.expect_ascii_char(b'e')
#| return True
#| }
#| Some('f') => {
#| ctx.expect_ascii_char(b'a')
#| ctx.expect_ascii_char(b'l')
#| ctx.expect_ascii_char(b's')
#| ctx.expect_ascii_char(b'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_owned()))
#| }
#| 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_owned()))
#| }
#| 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_owned()))
#| }
#| Some('1'..='9') => {
#| let (n, repr) = ctx.lex_decimal_integer(start=ctx.offset - 1)
#| return Number(n, repr.map(repr => repr.to_owned()))
#| }
#| 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 with longest {
#| ("[ \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 is ('0'..='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 is ('0'..='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 is ('0'..='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 is ('0'..='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 is ('0'..='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 is ('0'..='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 is ('0'..='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? @internal/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? @internal/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()
#| 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([])
#| for x = ctx.lex_property_name() {
#| match x {
#| RBrace => {
#| ctx.remaining_available_depth += 1
#| break 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
#| break 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 = []
#| for x = ctx.lex_value(allow_rbracket=true) {
#| match x {
#| RBracket => {
#| ctx.remaining_available_depth += 1
#| break 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
#| break 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, @debug.Debug)
#|pub(all) suberror ParseError {
#| InvalidChar(Position, Char)
#| InvalidEof
#| InvalidNumber(Position, String)
#| InvalidIdentEscape(Position)
#| DepthLimitExceeded
#|} derive(Eq, ToJson, @debug.Debug)
#|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",
#| )
#| }
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl Show for Json
#|#warnings("-deprecated")
#|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(repr) {
#| logger.write_string(", repr=")
#| logger.write_string("Some(")
#| Show::output(repr, logger)
#| logger.write_string(")")
#| }
#| 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_lazy_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/lazy",
deps={},
files={
"lazy.mbt": (
#|priv enum LazyState[A] {
#| Unforced(() -> A)
#| Forcing
#| Forced(A)
#|}
#|struct Lazy[A] {
#| mut state : LazyState[A]
#|}
#|pub fn[A] Lazy::Lazy(thunk : () -> A) -> Lazy[A] {
#| { state: Unforced(thunk) }
#|}
#|pub fn[A] Lazy::ready(value : A) -> Lazy[A] {
#| { state: Forced(value) }
#|}
#|pub fn[A] Lazy::force(self : Lazy[A]) -> A {
#| match self.state {
#| Forced(v) => v
#| Forcing => abort("Lazy::force: reentrant force on the same cell")
#| Unforced(thunk) => {
#| self.state = Forcing
#| let v = thunk()
#| self.state = Forced(v)
#| v
#| }
#| }
#|}
),
},
)
///|
let moonbitlang_core_list_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/list",
deps={},
files={
"debug.mbt": (
#|using @debug {trait Debug, type Repr}
#|pub impl[A : Debug] Debug for List[A] with to_repr(self) {
#| Repr::opaque_(
#| "List",
#| Repr::array(self.to_array().map(x => @debug.to_repr(x))),
#| )
#|}
#|#deprecated("use `to_repr(a)` instead", skip_current_package=true)
#|pub fn[A : Debug] List::to_repr(self : List[A]) -> Repr {
#| @debug.to_repr(self)
#|}
#|test "Debug for List" {
#| let xs : List[Int] = from_array([1, 2, 3])
#| @debug.debug_inspect(xs, content="")
#|}
),
"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
#| }
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[A : Show] Show for List[A]
#|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 {
#| for x = self, acc = 0 {
#| match (x, acc) {
#| (Empty, len) => break 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? {
#| for x = self {
#| match x {
#| Empty => break
#| More(head, tail~) => {
#| f(head)
#| continue tail
#| }
#| }
#| }
#|}
#|#locals(f)
#|pub fn[A] List::eachi(
#| self : List[A],
#| f : (Int, A) -> Unit raise?,
#|) -> Unit raise? {
#| for x = self, i = 0 {
#| match (x, i) {
#| (Empty, _) => break
#| (More(x, tail=xs), i) => {
#| f(i, x)
#| continue xs, i + 1
#| }
#| }
#| }
#|}
#|#locals(f)
#|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)
#| for d = dest, t = tail {
#| match (d, t) {
#| (_, Empty) => break
#| (More(_) as dest, More(hd, tail~)) => {
#| dest.tail = More(f(hd), tail=Empty)
#| continue dest.tail, tail
#| }
#| (Empty, _) => panic()
#| }
#| }
#| dest
#| }
#| }
#|}
#|#locals(f)
#|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)
#| for i = 1, d = dest, t = tail {
#| match (i, d, t) {
#| (_, _, Empty) => break
#| (i, More(_) as dest, More(hd, tail~)) => {
#| dest.tail = More(f(i, hd), tail=Empty)
#| continue i + 1, dest.tail, tail
#| }
#| (_, Empty, _) => panic()
#| }
#| }
#| dest
#| }
#| }
#|}
#|#locals(f)
#|pub fn[A, B] List::rev_map(
#| self : List[A],
#| f : (A) -> B raise?,
#|) -> List[B] raise? {
#| for a = Empty, b = self {
#| match (a, b) {
#| (acc, Empty) => break acc
#| (acc, More(x, tail=xs)) => continue More(f(x), tail=acc), xs
#| }
#| }
#|}
#|pub fn[A] List::to_array(self : List[A]) -> Array[A] {
#| [
#| for x in self { x }
#| ]
#|}
#|#locals(f)
#|pub fn[A] List::filter(
#| self : List[A],
#| f : (A) -> Bool raise?,
#|) -> List[A] raise? {
#| for x = self {
#| match x {
#| Empty => break Empty
#| More(head, tail~) =>
#| if !f(head) {
#| continue tail
#| } else {
#| let dest = More(head, tail=Empty)
#| for d = dest, t = tail {
#| match (d, t) {
#| (_, Empty) => break
#| (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()
#| }
#| }
#| break dest
#| }
#| }
#| }
#|}
#|#locals(f)
#|pub fn[A] List::all(self : List[A], f : (A) -> Bool raise?) -> Bool raise? {
#| for x = self {
#| match x {
#| Empty => break true
#| More(head, tail~) => if f(head) { continue tail } else { break false }
#| }
#| }
#|}
#|#locals(f)
#|pub fn[A] List::any(self : List[A], f : (A) -> Bool raise?) -> Bool raise? {
#| for x = self {
#| match x {
#| Empty => break false
#| More(head, tail~) => if f(head) { break 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 {
#| for x = self {
#| match x {
#| Empty => break abort("last of empty list")
#| More(head, tail=Empty) => break head
#| More(_, tail~) => continue tail
#| }
#| }
#|}
#|pub fn[A] List::last(self : List[A]) -> A? {
#| for x = self {
#| match x {
#| Empty => break None
#| More(head, tail=Empty) => break 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)
#| for d = dest, t = tail {
#| match (d, t) {
#| (More(_) as dest, Empty) => {
#| dest.tail = other
#| break
#| }
#| (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] {
#| for a = self, b = other {
#| match (a, b) {
#| (Empty, other) => break 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)
#|}
#|#locals(f)
#|pub fn[A, B] List::fold(
#| self : List[A],
#| init~ : B,
#| f : (B, A) -> B raise?,
#|) -> B raise? {
#| for x = self, acc = init {
#| match (x, acc) {
#| (Empty, acc) => break acc
#| (More(head, tail~), acc) => continue tail, f(acc, head)
#| }
#| }
#|}
#|#locals(f)
#|pub fn[A, B] List::foldi(
#| self : List[A],
#| init~ : B,
#| f : (Int, B, A) -> B raise?,
#|) -> B raise? {
#| for xs = self, i = 0, acc = init {
#| match xs {
#| Empty => break acc
#| More(x, tail=rest) => continue rest, i + 1, f(i, acc, x)
#| }
#| }
#|}
#|#as_free_fn
#|pub fn[A, B] List::zip(self : List[A], other : List[B]) -> List[(A, B)] {
#| let res = for a = self, b = other, acc = Empty {
#| match (a, b, acc) {
#| (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()
#|}
#|#locals(f)
#|pub fn[A, B] List::flat_map(
#| self : List[A],
#| f : (A) -> List[B] raise?,
#|) -> List[B] raise? {
#| for x = self {
#| match x {
#| Empty => break Empty
#| More(head, tail~) =>
#| match f(head) {
#| Empty => continue tail
#| More(hd, tail=tl) => {
#| let dest = More(hd, tail=Empty)
#| let dest1 = for d = dest, t = tl {
#| match (d, t) {
#| (dest, Empty) => break dest
#| (More(_) as dest, More(hd, tail~)) => {
#| dest.tail = More(hd, tail=Empty)
#| continue dest.tail, tail
#| }
#| (Empty, _) => panic()
#| }
#| }
#| loop_over_tail~: for d = dest1, t = tail {
#| match (d, t) {
#| (_, Empty) => break
#| (More(_) as dest, More(t_hd, tail=Empty)) => {
#| dest.tail = f(t_hd)
#| break
#| }
#| (dest, More(t_hd, tail=t_tl)) =>
#| for d2 = dest, t2 = f(t_hd) {
#| match (d2, t2) {
#| (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()
#| }
#| }
#| }
#| }
#| break dest
#| }
#| }
#| }
#| }
#|}
#|#locals(f)
#|pub fn[A, B] List::filter_map(
#| self : List[A],
#| f : (A) -> B? raise?,
#|) -> List[B] raise? {
#| for x = self {
#| match x {
#| Empty => break Empty
#| More(hd, tail~) =>
#| match f(hd) {
#| None => continue tail
#| Some(head) => {
#| let dest = More(head, tail=Empty)
#| for d = dest, t = tail {
#| match (d, t) {
#| (_, Empty) => break
#| (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()
#| }
#| }
#| break 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 {
#| for x = self, i = n {
#| match (x, i) {
#| (Empty, _) => break abort("nth: index out of bounds")
#| (More(head, tail=_), 0) => break head
#| (More(_, tail~), n) => continue tail, n - 1
#| }
#| }
#|}
#|pub fn[A] List::nth(self : List[A], n : Int) -> A? {
#| for x = self, i = n {
#| match (x, i) {
#| (Empty, _) => break None
#| (More(head, tail=_), 0) => break Some(head)
#| (More(_, tail~), n) => continue tail, n - 1
#| }
#| }
#|}
#|#as_free_fn
#|pub fn[A] List::repeat(n : Int, x : A) -> List[A] {
#| if n < 0 {
#| abort("negative repeat count")
#| }
#| for acc = Empty, i = n {
#| match (acc, i) {
#| (acc, n) =>
#| if n <= 0 {
#| break 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)
#| for d = dest, t = tail {
#| match (d, t) {
#| (_, Empty) => break
#| (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)
#| for a = tail, b = xs, c = ys {
#| match (a, b, c) {
#| (Empty, _, _) => break
#| (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
#| }
#| (_, _, _) => break abort("unreachable")
#| }
#| }
#| (xs, ys)
#| }
#| }
#|}
#|pub fn[A] List::flatten(self : List[List[A]]) -> List[A] {
#| for x = self {
#| match x {
#| Empty => break Empty
#| More(head, tail~) =>
#| match head {
#| Empty => continue tail
#| More(hd, tail=tl) => {
#| let dest = More(hd, tail=Empty)
#| let dest1 = for d = dest, t = tl {
#| match (d, t) {
#| (dest, Empty) => break dest
#| (More(_) as dest, More(hd, tail~)) => {
#| dest.tail = More(hd, tail=Empty)
#| continue dest.tail, tail
#| }
#| (Empty, _) => panic()
#| }
#| }
#| loop_over_tail~: for d = dest1, t = tail {
#| match (d, t) {
#| (_, Empty) => break
#| (More(_) as dest, More(t_hd, tail=Empty)) => {
#| dest.tail = t_hd
#| break
#| }
#| (dest, More(t_hd, tail=t_tl)) =>
#| for d2 = dest, t2 = t_hd {
#| match (d2, t2) {
#| (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()
#| }
#| }
#| }
#| }
#| break 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~) =>
#| for a = tail, b = head {
#| match (a, b) {
#| (Empty, curr_max) => break 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~) =>
#| for a = tail, b = head {
#| match (a, b) {
#| (Empty, curr_max) => break 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~) =>
#| for a = tail, b = head {
#| match (a, b) {
#| (Empty, curr_min) => break 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~) =>
#| for a = tail, b = head {
#| match (a, b) {
#| (Empty, curr_min) => break 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 {
#| for cur = self {
#| match cur {
#| Empty => break false
#| More(x, tail=xs) => if x == value { break true } else { continue xs }
#| }
#| }
#|}
#|#as_free_fn
#|#locals(f)
#|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)
#| for d = dest, t = f(new_state) {
#| match (d, t) {
#| (_, None) => break
#| (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
#|#locals(f)
#|pub fn[A, S] List::rev_unfold(
#| f : (S) -> (A, S)? raise?,
#| init~ : S,
#|) -> List[A] raise? {
#| for a = f(init), b = Empty {
#| match (a, b) {
#| (None, acc) => break 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)
#| for d = dest, t = tail, i = n - 1 {
#| match (d, t, i) {
#| (_, Empty, _) => break
#| (_, _, 0) => break
#| (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 {
#| for a = n, b = self {
#| match (a, b) {
#| (_, Empty) => break Empty
#| (1, More(_, tail=xs)) => break xs
#| (n, More(_, tail=xs)) => continue n - 1, xs
#| }
#| }
#| }
#|}
#|#locals(p)
#|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)
#| for d = dest, t = tail {
#| match (d, t) {
#| (_, Empty) => break
#| (More(_) as dest, More(x, tail=xs)) if p(x) => {
#| dest.tail = More(x, tail=Empty)
#| continue dest.tail, xs
#| }
#| (More(_), _) => break
#| (Empty, _) => panic()
#| }
#| }
#| dest
#| } else {
#| Empty
#| }
#| }
#|}
#|#locals(p)
#|pub fn[A] List::drop_while(
#| self : List[A],
#| p : (A) -> Bool raise?,
#|) -> List[A] raise? {
#| for cur = self {
#| match cur {
#| Empty => break Empty
#| More(x, tail=xs) =>
#| if p(x) {
#| continue xs
#| } else {
#| break More(x, tail=xs)
#| }
#| }
#| }
#|}
#|#locals(f)
#|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)
#| for d = dest, s = self, a = init {
#| match (d, s, a) {
#| (_, Empty, _) => break
#| (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? {
#| for cur = self {
#| match cur {
#| Empty => break None
#| More((x, y), tail=xs) => if x == v { break Some(y) } else { continue xs }
#| }
#| }
#|}
#|#locals(f)
#|pub fn[A] List::find(self : List[A], f : (A) -> Bool raise?) -> A? raise? {
#| for cur = self {
#| match cur {
#| Empty => break None
#| More(element, tail=list) =>
#| if f(element) {
#| break Some(element)
#| } else {
#| continue list
#| }
#| }
#| }
#|}
#|#locals(f)
#|pub fn[A] List::find_index(
#| self : Self[A],
#| f : (A) -> Bool raise?,
#|) -> Int? raise? {
#| for cur = self, idx = 0 {
#| match (cur, idx) {
#| (Empty, _) => break None
#| (More(element, tail=list), idx) =>
#| if f(element) {
#| break Some(idx)
#| } else {
#| continue list, idx + 1
#| }
#| }
#| }
#|}
#|#locals(f)
#|pub fn[A] List::findi(self : List[A], f : (A, Int) -> Bool raise?) -> A? raise? {
#| for list = self, index = 0 {
#| match list {
#| Empty => break None
#| More(element, tail=list) =>
#| if f(element, index) {
#| break 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)
#| for d = dest, t = tail, i = n - 1 {
#| match (d, t, i) {
#| (_, Empty, _) => break
#| (More(_) as dest, More(_, tail~), 0) => {
#| dest.tail = tail
#| break
#| }
#| (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~)
#| for d = dest, t = tail {
#| match (d, t) {
#| (_, Empty) => break
#| (More(_) as dest, More(x, tail=xs)) =>
#| if x == elem {
#| dest.tail = xs
#| break
#| } 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 {
#| for a = self, b = prefix {
#| match (a, b) {
#| (_, Empty) => break true
#| (Empty, More(_)) => break false
#| (More(h1, tail=t1), More(h2, tail=t2)) =>
#| if h1 == h2 {
#| continue t1, t2
#| } else {
#| break 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~) =>
#| for a = More(head, tail=Empty), b = tail {
#| match (a, b) {
#| (result, Empty) => break 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) {
#| for a = self, b = other {
#| match (a, b) {
#| (Empty, Empty) => break 0
#| (Empty, More(_, tail=_)) => break -1
#| (More(_, tail=_), Empty) => break 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={},
files={
"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={},
files={
"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={},
files={
"prelude.mbt": (
#|pub using @set {type Set}
#|pub using @bigint {type BigInt}
#|#warnings("-deprecated")
#|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}
#|pub using @lazy {type Lazy}
),
},
)
///|
let moonbitlang_core_priority_queue_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/priority_queue",
deps={},
files={
"debug.mbt": (
#|using @debug {trait Debug, type Repr}
#|pub impl[A : Debug + Compare] Debug for PriorityQueue[A] with to_repr(self) {
#| let xs : Array[Repr] = self.to_array().map(x => @debug.to_repr(x))
#| Repr::opaque_("PriorityQueue", Repr::array(xs))
#|}
#|#deprecated("use `to_repr(a)` instead", skip_current_package=true)
#|pub fn[A : Debug + Compare] PriorityQueue::to_repr(
#| self : PriorityQueue[A],
#|) -> Repr {
#| @debug.to_repr(self)
#|}
#|test "Debug for PriorityQueue" {
#| let pq : PriorityQueue[Int] = from_array([3, 1, 2])
#| @debug.debug_inspect(pq, content="")
#|}
),
"deprecated.mbt": (
#|#deprecated("Use `PriorityQueue([])` instead")
#|#as_free_fn(deprecated="Use `PriorityQueue([])` instead")
#|pub fn[A] PriorityQueue::new() -> PriorityQueue[A] {
#| new_priority_queue()
#|}
),
"priority_queue.mbt": (
#|fn[A] new_priority_queue() -> PriorityQueue[A] {
#| { len: 0, top: None }
#|}
#|#alias(from_array)
#|#as_free_fn(from_array)
#|#alias(of, deprecated="Use from_array instead")
#|#as_free_fn(of, deprecated="Use from_array instead")
#|pub fn[A : Compare] PriorityQueue::PriorityQueue(
#| arr : ArrayView[A],
#|) -> PriorityQueue[A] {
#| guard arr is [a0, ..] else { return new_priority_queue() }
#| 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) {
#| [
#| for x in self { x }
#| ]
#|}
#|#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_priority_queue()
#| 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))
#| }
#| }
#| for siblings = x, merged = acc {
#| match (siblings, merged) {
#| (None, acc) => break Some(acc)
#| (Some({ sibling: None, .. } as x), acc) => break 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
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[A : Show + Compare] Show for PriorityQueue[A]
#|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_priority_queue() }
#| 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)
#| @debug.debug_inspect(
#| samples[5:10],
#| content=(
#| #|,
#| #| ,
#| #| ,
#| #| ,
#| #| ,
#| #| ]>
#| ),
#| )
#| @debug.debug_inspect(
#| samples[11:15],
#| content=(
#| #|,
#| #| ,
#| #| ,
#| #| ,
#| #| ]>
#| ),
#| )
#|}
#|pub impl[K] Default for PriorityQueue[K] with default() {
#| new_priority_queue()
#|}
),
"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={},
files={
"debug.mbt": (
#|using @debug {trait Debug, type Repr}
#|pub impl[A : Debug] Debug for Queue[A] with to_repr(self) {
#| Repr::opaque_("Queue", Repr::array([ for x in self { @debug.to_repr(x) } ]))
#|}
#|#deprecated("use `to_repr(a)` instead", skip_current_package=true)
#|pub fn[A : Debug] Queue::to_repr(self : Queue[A]) -> Repr {
#| @debug.to_repr(self)
#|}
#|test "Debug for Queue" {
#| let q : Queue[Int] = from_array([1, 2, 3])
#| @debug.debug_inspect(q, content="")
#|}
),
"deprecated.mbt": (
#|#deprecated("Use `Queue([])` instead")
#|#as_free_fn(deprecated="Use `Queue([])` instead")
#|pub fn[A] Queue::new() -> Queue[A] {
#| new_queue()
#|}
),
"queue.mbt": (
#|fn[A] new_queue() -> Queue[A] {
#| { length: 0, first: None, last: None }
#|}
#|#alias(from_array)
#|#as_free_fn(from_array)
#|#alias(of, deprecated="Use from_array instead")
#|#as_free_fn(of, deprecated="Use from_array instead")
#|pub fn[A] Queue::Queue(arr : ArrayView[A]) -> Queue[A] {
#| guard arr.length() > 0 else { return new_queue() }
#| 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) }
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[A : Show] Show for Queue[A]
#|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)
#| }
#| }
#|}
#|#locals(f)
#|pub fn[A] Queue::each(self : Queue[A], f : (A) -> Unit) -> Unit {
#| for x = self.first {
#| match x {
#| Some({ content, next }) => {
#| f(content)
#| continue next
#| }
#| None => break ()
#| }
#| }
#|}
#|#locals(f)
#|pub fn[A] Queue::eachi(self : Queue[A], f : (Int, A) -> Unit) -> Unit {
#| for x = self.first, index = 0 {
#| match (x, index) {
#| (Some({ content, next }), index) => {
#| f(index, content)
#| continue next, index + 1
#| }
#| (None, _) => break ()
#| }
#| }
#|}
#|#locals(f)
#|pub fn[A, B] Queue::fold(self : Queue[A], init~ : B, f : (B, A) -> B) -> B {
#| for x = self.first, acc = init {
#| match (x, acc) {
#| (None, acc) => break 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_queue() }
#| let first = { content, next: None }
#| let last = for pre = first, n = next {
#| match (pre, n) {
#| (pre, Some({ content, next })) => {
#| let curr = { content, next: None }
#| pre.next = Some(curr)
#| continue curr, next
#| }
#| (pre, None) => break 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
#| let len = self.length
#| let mut remaining = len
#| Iter::new(
#| fn() {
#| guard remaining > 0 && next_node is Some({ content, next }) else { None }
#| next_node = next
#| remaining -= 1
#| Some(content)
#| },
#| size_hint=len,
#| )
#|}
#|#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_queue()
#| 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)
#| @test.assert_eq(q, from_array([1, 2, 3, 4, 11]))
#| q.unsafe_pop() |> ignore
#| @test.assert_eq(q, from_array([2, 3, 4, 11]))
#|}
#|test "from_array_2" {
#| let q = from_array([1, 2, 3, 4])
#| q.push(11)
#| @test.assert_eq(q, from_array([1, 2, 3, 4, 11]))
#| q.unsafe_pop() |> ignore
#| @test.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)
#| @test.assert_eq(queue, from_array([2, 3, 4]))
#|}
#|test "push" {
#| let queue : Queue[Int] = new_queue()
#| queue.push(1)
#| queue.push(2)
#| queue.push(3)
#| queue.push(1)
#| @test.assert_eq(queue.length(), 4)
#| @test.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()
#| @test.assert_eq(queue2.length(), 4)
#| @test.assert_eq(queue2, from_array([1, 2, 3, 4]))
#| @test.assert_eq(queue.length(), 4)
#| @test.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)
#| @test.assert_eq(queue.length(), 0)
#| @test.assert_eq(queue2.length(), 8)
#| @test.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={},
files={
"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 }
#| 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 = size.unwrap_or(0)
#| let state = state.unwrap_or_else(() => @splitmix.RandomState::default())
#| 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": (
#|#warnings("-deprecated_syntax")
#|struct RandomState {
#| mut seed : UInt64
#| gamma : UInt64
#|} derive(Show, @debug.Debug)
#|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()
#| @test.assert_not_eq(rs.seed, 0)
#| @test.assert_not_eq(rs.gamma, 0)
#|}
),
},
)
///|
let moonbitlang_core_random_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/random",
deps={},
files={
"debug.mbt": (
#|using @debug {trait Debug, type Repr}
#|pub impl Debug for Rand with to_repr(_) {
#| Repr::opaque_("Rand", Repr::omitted())
#|}
),
"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
#| @test.assert_eq(n, exp)
#|}
#|pub fn Rand::int(self : Rand, limit? : Int = 0) -> Int {
#| if limit < 0 {
#| abort("Rand::int: invalid argument limit")
#| }
#| 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 {
#| abort("Rand::int64: invalid argument limit")
#| }
#| 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
#| @test.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)
#| @test.assert_eq(r.hi, 1305938385386173474UL)
#| @test.assert_eq(r.lo, 2552847189736476416UL)
#|}
#|test "umul128: handles small numbers correctly" {
#| let r = umul128(1UL, 1UL)
#| @test.assert_eq(r.hi, 0UL)
#| @test.assert_eq(r.lo, 1UL)
#|}
#|test "umul128: handles large numbers correctly" {
#| let r = umul128(1UL, 0xFFFFFFFFFFFFFFFFUL)
#| @test.assert_eq(r.hi, 0UL)
#| @test.assert_eq(r.lo, 0xFFFFFFFFFFFFFFFFUL)
#|}
#|test "umul128: handles zero correctly" {
#| let r = umul128(0UL, 0UL)
#| @test.assert_eq(r.hi, 0UL)
#| @test.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
#| })
#| @debug.debug_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={},
files={
"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 : BytesView) -> 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" {
#| @test.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,
#| ]
#| @test.assert_eq(res, expected)
#|}
),
},
)
///|
let moonbitlang_core_range_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/range",
deps={},
files={
"range.mbt": (
#|priv enum Direction {
#| Backward
#| Still
#| Forward
#|}
#|trait Step: Add + Compare {
#| direction(Self) -> Int
#| step_one() -> Self
#|}
#|pub impl Step for Int with direction(self) {
#| if self > 0 {
#| 1
#| } else if self < 0 {
#| -1
#| } else {
#| 0
#| }
#|}
#|pub impl Step for Int with step_one() {
#| 1
#|}
#|pub impl Step for Int64 with direction(self) {
#| if self > 0L {
#| 1
#| } else if self < 0L {
#| -1
#| } else {
#| 0
#| }
#|}
#|pub impl Step for Int64 with step_one() {
#| 1L
#|}
#|pub impl Step for UInt with direction(self) {
#| if self > 0U {
#| 1
#| } else {
#| 0
#| }
#|}
#|pub impl Step for UInt with step_one() {
#| 1U
#|}
#|pub impl Step for UInt64 with direction(self) {
#| if self > 0UL {
#| 1
#| } else {
#| 0
#| }
#|}
#|pub impl Step for UInt64 with step_one() {
#| 1UL
#|}
#|pub impl Step for Float with direction(self) {
#| if self > (0.0 : Float) {
#| 1
#| } else if self < (0.0 : Float) {
#| -1
#| } else {
#| 0
#| }
#|}
#|pub impl Step for Float with step_one() {
#| (1.0 : Float)
#|}
#|pub impl Step for Double with direction(self) {
#| if self > 0.0 {
#| 1
#| } else if self < 0.0 {
#| -1
#| } else {
#| 0
#| }
#|}
#|pub impl Step for Double with step_one() {
#| 1.0
#|}
#|pub impl Step for Int16 with direction(self) {
#| if self > (0 : Int16) {
#| 1
#| } else if self < (0 : Int16) {
#| -1
#| } else {
#| 0
#| }
#|}
#|pub impl Step for Int16 with step_one() {
#| (1 : Int16)
#|}
#|pub impl Step for UInt16 with direction(self) {
#| if self > (0 : UInt16) {
#| 1
#| } else {
#| 0
#| }
#|}
#|pub impl Step for UInt16 with step_one() {
#| (1 : UInt16)
#|}
#|pub impl Step for Byte with direction(self) {
#| if self > (0 : Byte) {
#| 1
#| } else {
#| 0
#| }
#|}
#|pub impl Step for Byte with step_one() {
#| (1 : Byte)
#|}
#|pub impl Step for @bigint.BigInt with direction(self) {
#| if self > 0N {
#| 1
#| } else if self < 0N {
#| -1
#| } else {
#| 0
#| }
#|}
#|pub impl Step for @bigint.BigInt with step_one() {
#| 1N
#|}
#|pub fn[T : Step] iter(
#| from~ : T,
#| to~ : T,
#| step? : T = T::step_one(),
#| inclusive? : Bool = false,
#|) -> Iter[T] {
#| let n = T::direction(step)
#| let dir : Direction = if n > 0 {
#| Forward
#| } else if n < 0 {
#| Backward
#| } else {
#| Still
#| }
#| let mut i = from
#| let mut done = false
#| Iter::new(() => {
#| guard !done else { None }
#| let in_range = match dir {
#| Forward => i.compare(to) < 0
#| Backward => i.compare(to) > 0
#| Still => false
#| }
#| guard in_range || (inclusive && i == to) else { None }
#| let value = i
#| let next = i + step
#| let progress = match dir {
#| Forward => next.compare(i) > 0
#| Backward => next.compare(i) < 0
#| Still => false
#| }
#| if progress {
#| i = next
#| } else {
#| done = true
#| }
#| Some(value)
#| })
#|}
),
},
)
///|
let moonbitlang_core_ref_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/ref",
deps={},
files={
"debug.mbt": (
#|using @debug {trait Debug, type Repr}
#|pub impl[T : Debug] Debug for Ref[T] with to_repr(self) {
#| Repr::opaque_("Ref", @debug.to_repr(self.val))
#|}
#|#deprecated("use `to_repr(a)` instead", skip_current_package=true)
#|pub fn[T : Debug] Ref::to_repr(self : Ref[T]) -> Repr {
#| @debug.to_repr(self)
#|}
#|test "Debug for Ref" {
#| let r : Ref[Int] = new(1)
#| @debug.debug_inspect(r, content="")
#|}
),
"ref.mbt": (
#|pub(all) struct Ref[T] {
#| mut val : T
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[X : Show] Show for Ref[X]
#|pub impl[X : Show] Show for Ref[X] with output(self, logger) {
#| logger.write_string("{val: ")
#| logger.write_object(self.val)
#| logger.write_string("}")
#|}
#|#alias(new, deprecated)
#|pub fn[T] Ref::Ref(x : T) -> Ref[T] {
#| { val: x }
#|}
#|test "to_string" {
#| @debug.debug_inspect(
#| new(3),
#| content=(
#| #|
#| ),
#| )
#|}
#|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={},
files={
"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={},
files={
"debug.mbt": (
#|using @debug {trait Debug, type Repr}
#|pub impl[K : Debug] Debug for Set[K] with to_repr(self) {
#| Repr::opaque_("Set", Repr::array(self.to_array().map(x => @debug.to_repr(x))))
#|}
#|test "Debug for Set" {
#| let s : Set[Int] = from_array([1, 2, 3])
#| @debug.debug_inspect(s, content="")
#|}
),
"deprecated.mbt": (
#|#deprecated("Use `Set([], capacity=...)` instead")
#|#as_free_fn(deprecated="Use `Set([], capacity=...)` instead")
#|pub fn[K] Set::new(capacity? : Int = default_init_capacity) -> Set[K] {
#| new_set(capacity)
#|}
),
"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
#|}
#|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
#|}
#|let default_init_capacity = 8
#|fn[K] new_set(capacity : Int) -> 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,
#| }
#|}
#|fn capacity_for_length(length : Int) -> Int {
#| let mut capacity = length.next_power_of_two()
#| if length > calc_grow_threshold(capacity) {
#| capacity *= 2
#| }
#| capacity
#|}
#|#alias(from_array)
#|#as_free_fn(from_array)
#|#alias(of, deprecated="Use from_array instead")
#|#as_free_fn(of, deprecated="Use from_array instead")
#|pub fn[K : Hash + Eq] Set::Set(arr : ArrayView[K], capacity? : Int) -> Set[K] {
#| let length = arr.length()
#| let capacity = match capacity {
#| Some(capacity) => capacity.max(capacity_for_length(length))
#| None =>
#| if length == 0 {
#| default_init_capacity
#| } else {
#| capacity_for_length(length)
#| }
#| }
#| let m = new_set(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 {
#| for cur = idx {
#| let next = (cur + 1) & self.capacity_mask
#| match self.entries[next] {
#| None | Some({ psl: 0, .. }) => {
#| self.entries[cur] = None
#| break
#| }
#| Some(entry) => {
#| entry.psl -= 1
#| self.set_entry(entry, cur)
#| continue 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
#| for x = old_head {
#| match x {
#| Some({ next, key, hash, .. }) => {
#| self.add_with_hash(key, hash)
#| continue next
#| }
#| None => break
#| }
#| }
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[K : Show] Show for Set[K]
#|pub impl[K : Show] Show for Set[K] with output(self, logger) {
#| logger.write_string("{")
#| for i = 0, curr = self.head {
#| match (i, curr) {
#| (_, None) => break 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? {
#| for x = self.head {
#| match x {
#| 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? {
#| for i = 0, curr = self.head {
#| match (i, curr) {
#| (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
#| let len = self.size
#| let mut remaining = len
#| Iter::new(
#| fn() {
#| guard remaining > 0 && curr_entry is Some({ key, next, .. }) else { None }
#| curr_entry = next
#| remaining -= 1
#| Some(key)
#| },
#| size_hint=len,
#| )
#|}
#|pub fn[K] Set::to_array(self : Set[K]) -> Array[K] {
#| let arr = Array::new(capacity=self.size)
#| for x = self.head {
#| match x {
#| 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 = new_set(default_init_capacity)
#| while iter.next() is Some(e) {
#| m.add(e)
#| }
#| m
#|}
#|pub impl[K] Default for Set[K] with default() {
#| new_set(default_init_capacity)
#|}
#|#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)
#| for entry = last, idx = self.tail, next = (None : Entry[K]?) {
#| match (entry, idx, next) {
#| ({ 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)
#| break
#| }
#| }
#| }
#| }
#| other
#|}
#|pub fn[K : Hash + Eq] Set::difference(self : Set[K], other : Set[K]) -> Set[K] {
#| let m = new_set(default_init_capacity)
#| 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 = new_set(default_init_capacity)
#| 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 = new_set(default_init_capacity)
#| 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 = new_set(default_init_capacity)
#| 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={},
files={
"debug.mbt": (
#|using @debug {trait Debug, type Repr}
#|pub impl[K : Debug, V : Debug] Debug for SortedMap[K, V] with to_repr(self) {
#| Repr::opaque_(
#| "SortedMap",
#| Repr::map(
#| self.to_array().map(kv => (@debug.to_repr(kv.0), @debug.to_repr(kv.1))),
#| ),
#| )
#|}
#|test "Debug for SortedMap" {
#| let sm : SortedMap[Int, String] = from_array([(1, "a"), (2, "b")])
#| @debug.debug_inspect(
#| sm,
#| content=(
#| #|
#| ),
#| )
#|}
),
"deprecated.mbt": (
#|#deprecated("Use `SortedMap([])` instead")
#|#as_free_fn(deprecated="Use `SortedMap([])` instead")
#|pub fn[K, V] SortedMap::new() -> SortedMap[K, V] {
#| new_sorted_map()
#|}
#|#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
#| }
#|}
#|fn[K, V] new_sorted_map() -> SortedMap[K, V] {
#| { root: None, size: 0 }
#|}
#|#alias(from_array)
#|#as_free_fn(from_array)
#|#alias(of, deprecated="Use from_array instead")
#|#as_free_fn(of, deprecated="Use from_array instead")
#|pub fn[K : Compare, V] SortedMap::SortedMap(
#| entries : ArrayView[(K, V)],
#|) -> SortedMap[K, V] {
#| let map = new_sorted_map()
#| 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? {
#| for x = self.root {
#| match x {
#| 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 {
#| for x = self.root {
#| match x {
#| 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::update_or_default(
#| self : SortedMap[K, V],
#| key : K,
#| default : V,
#| f : (V) -> V,
#|) -> Unit {
#| let (new_root, inserted) = update_or_default_node(self.root, key, default, f)
#| if self.root != new_root {
#| self.root = new_root
#| }
#| if inserted {
#| self.size += 1
#| }
#|}
#|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() {
#| for x = next_node {
#| match x {
#| 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
#| break Some(key)
#| }
#| None => break None
#| }
#| }
#| },
#| size_hint=self.size,
#| )
#|}
#|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() {
#| for x = next_node {
#| match x {
#| 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
#| break Some(value)
#| }
#| None => break None
#| }
#| }
#| },
#| size_hint=self.size,
#| )
#|}
#|pub fn[K, V] SortedMap::to_array(self : SortedMap[K, V]) -> Array[(K, V)] {
#| [
#| for k, v in self { (k, v) }
#| ]
#|}
#|#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() {
#| for x = next_node {
#| match x {
#| 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
#| break Some((key, value))
#| }
#| None => break None
#| }
#| }
#| },
#| size_hint=self.size,
#| )
#|}
#|#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_sorted_map()
#| 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() {
#| for x = next_node {
#| match x {
#| 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
#| break 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
#| break Some((key, value))
#| }
#| None => break 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] update_or_default_node(
#| root : Node[K, V]?,
#| key : K,
#| default : V,
#| f : (V) -> V,
#|) -> (Node[K, V]?, Bool) {
#| match root {
#| None => (Some(new_node(key, default)), true)
#| Some(n) =>
#| if key == n.key {
#| n.value = f(n.value)
#| (Some(n), false)
#| } else {
#| let (l, r) = (n.left, n.right)
#| if key < n.key {
#| let (nl, inserted) = update_or_default_node(l, key, default, f)
#| n.left = nl
#| (Some(balance(n)), inserted)
#| } else {
#| let (nr, inserted) = update_or_default_node(r, key, default, f)
#| 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_sorted_map()
#| 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_sorted_map()
#| 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_sorted_map()
#| 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_sorted_map()
#| 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_sorted_map()
#| 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_sorted_map()
#| 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")
#| @debug.debug_inspect(map1.get(7), content="None")
#| @debug.debug_inspect(map2.get(7), content="Some(\"g\")")
#| map1.remove(1)
#| inspect(map1.length(), content="5")
#| inspect(map2.length(), content="7")
#| @debug.debug_inspect(map1.get(1), content="None")
#| @debug.debug_inspect(map2.get(1), content="Some(\"a\")")
#|}
#|pub impl[K, V] Default for SortedMap[K, V] with default() {
#| new_sorted_map()
#|}
),
"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 => "_"
#| }
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[K : Show, V : Show] Show for SortedMap[K, V]
#|#warnings("-deprecated")
#|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) {
#| Json::object(
#| Map(
#| capacity=self.length(),
#| [
#| for k, v in self { (k.to_string(), v.to_json()) }
#| ],
#| ),
#| )
#|}
#|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_sorted_map()
#| 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={},
files={
"debug.mbt": (
#|using @debug {trait Debug, type Repr}
#|pub impl[V : Debug] Debug for SortedSet[V] with to_repr(self) {
#| Repr::opaque_(
#| "SortedSet",
#| Repr::array(self.to_array().map(x => @debug.to_repr(x))),
#| )
#|}
#|test "Debug for SortedSet" {
#| let ss : SortedSet[Int] = from_array([3, 1, 2])
#| @debug.debug_inspect(ss, content="")
#|}
),
"deprecated.mbt": (
#|#deprecated("Use `SortedSet([])` instead")
#|#as_free_fn(deprecated="Use `SortedSet([])` instead")
#|pub fn[V] SortedSet::new() -> SortedSet[V] {
#| new_sorted_set()
#|}
),
"set.mbt": (
#|fn[V] new_sorted_set() -> 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 }
#|}
#|#alias(from_array)
#|#as_free_fn(from_array)
#|#alias(of, deprecated="Use from_array instead")
#|#as_free_fn(of, deprecated="Use from_array instead")
#|pub fn[V : Compare] SortedSet::SortedSet(array : ArrayView[V]) -> SortedSet[V] {
#| let set = new_sorted_set()
#| 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_sorted_set()
#| 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 {
#| for root = self.root, value = value {
#| match (root, value) {
#| (None, _) => break false
#| (Some(node), value) => {
#| let compare_result = value.compare(node.value)
#| if compare_result == 0 {
#| break 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_sorted_set()
#| }
#|}
#|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_sorted_set()
#| 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_sorted_set()
#| 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() {
#| for x = curr_node {
#| match x {
#| Some({ left: None, value, right, height: _ }) => {
#| curr_node = right
#| break Some(value)
#| }
#| Some({ left, value, right, height: _ }) => {
#| parents.push((value, right))
#| continue left
#| }
#| None if parents.pop() is Some((value, right)) => {
#| curr_node = right
#| break Some(value)
#| }
#| None => break None
#| }
#| }
#| },
#| size_hint=self.size,
#| )
#|}
#|#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_sorted_set()
#| while iter.next() is Some(e) {
#| s.add(e)
#| }
#| s
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[V : Show] Show for SortedSet[V]
#|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
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|impl[T : Show] Show for Node[T]
#|impl[T : Show] Show for Node[T] with output(self, logger) {
#| fn count(root : Node[T]?) -> Int {
#| match root {
#| None => 0
#| Some(root) => count(root.left) + count(root.right) + 1
#| }
#| }
#| let x = { root: Some(self), size: count(Some(self)) }
#| 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(() => {
#| for x = curr_node {
#| match x {
#| 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
#| break Some(value)
#| } else {
#| parents.push((value, right))
#| continue left
#| }
#| }
#| None if parents.pop() is Some((value, right)) => {
#| curr_node = right
#| break Some(value)
#| }
#| None => break 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()
#| @debug.debug_inspect(
#| copied_set,
#| content=(
#| #|
#| ),
#| )
#| inspect(set.debug_tree() == copied_set.debug_tree(), content="true")
#| let set : SortedSet[Int] = from_array([])
#| let copied_set = set.copy()
#| @debug.debug_inspect(
#| copied_set,
#| content=(
#| #|
#| ),
#| )
#| 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)
#| @debug.debug_inspect(
#| set3,
#| content=(
#| #|
#| ),
#| )
#| 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)
#| @debug.debug_inspect(
#| set3,
#| content=(
#| #|
#| ),
#| )
#| 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)
#| @debug.debug_inspect(
#| set3,
#| content=(
#| #|
#| ),
#| )
#| inspect(set3.debug_tree(), content="([2]2,([1]1,_,_),([1]3,_,_))")
#| let set1 : SortedSet[Int] = new_sorted_set()
#| let set2 = new_sorted_set()
#| let set3 = set1.union(set2)
#| @debug.debug_inspect(
#| set3,
#| content=(
#| #|
#| ),
#| )
#| inspect(set3.debug_tree(), content="_")
#| let set1 = from_array([1, 2, 3])
#| let set2 = from_array([])
#| let set3 = set1.union(set2)
#| @debug.debug_inspect(
#| set3,
#| content=(
#| #|
#| ),
#| )
#| 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)
#| @debug.debug_inspect(
#| set3,
#| content=(
#| #|
#| ),
#| )
#| 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)
#| @debug.debug_inspect(
#| set3,
#| content=(
#| #|
#| ),
#| )
#| 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)
#| @debug.debug_inspect(
#| set3,
#| content=(
#| #|
#| ),
#| )
#| 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)
#| @debug.debug_inspect(
#| set3,
#| content=(
#| #|
#| ),
#| )
#| 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,_,_))))",
#| )
#|}
#|#warnings("-deprecated")
#|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" {
#| fn join_to_array(
#| l : SortedSet[Int],
#| value : Int,
#| r : SortedSet[Int],
#| ) -> Array[Int] {
#| let root = join(l.root, value, r.root)
#| ({ root: Some(root), size: l.size + r.size + 1 } : SortedSet[Int]).to_array()
#| }
#| let l = from_array([13, 8, 17, 1, 11, 15, 25, 6])
#| let r = from_array([27, 28, 40, 35, 33])
#| @debug.debug_inspect(
#| join_to_array(l, 26, r),
#| 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])
#| @debug.debug_inspect(
#| join_to_array(l, 6, r),
#| content=(
#| #|[1, 2, 3, 4, 5, 6, 7]
#| ),
#| )
#| let l = from_array([3, 2, 5, 1, 4])
#| let r = from_array([])
#| @debug.debug_inspect(
#| join_to_array(l, 6, r),
#| content=(
#| #|[1, 2, 3, 4, 5, 6]
#| ),
#| )
#| let l = from_array([])
#| let r = from_array([])
#| @debug.debug_inspect(
#| join_to_array(l, 6, r),
#| content=(
#| #|[6]
#| ),
#| )
#| let l = from_array([])
#| let r = from_array([7, 8, 9, 10, 11, 12])
#| @debug.debug_inspect(
#| join_to_array(l, 6, r),
#| content=(
#| #|[6, 7, 8, 9, 10, 11, 12]
#| ),
#| )
#|}
#|test "add to empty set" {
#| let set = new_sorted_set()
#| set.add(1)
#| @test.assert_eq(set.contains(1), true)
#| inspect(set.debug_tree(), content="([1]1,_,_)")
#|}
#|test "add to non-empty set" {
#| let set = new_sorted_set()
#| set.add(1)
#| set.add(2)
#| @test.assert_eq(set.contains(1), true)
#| @test.assert_eq(set.contains(2), true)
#| inspect(set.debug_tree(), content="([2]1,_,([1]2,_,_))")
#|}
#|test "add duplicate value" {
#| let set = new_sorted_set()
#| set.add(1)
#| set.add(1)
#| @test.assert_eq(set.contains(1), true)
#| @test.assert_eq(set.length(), 1)
#| inspect(set.debug_tree(), content="([1]1,_,_)")
#|}
#|test "add multiple values" {
#| let set = new_sorted_set()
#| set.add(1)
#| set.add(2)
#| set.add(3)
#| @test.assert_eq(set.contains(1), true)
#| @test.assert_eq(set.contains(2), true)
#| @test.assert_eq(set.contains(3), true)
#| @test.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)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| 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)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| 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)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(
#| set.debug_tree(),
#| content="([4]4,([2]2,_,([1]3,_,_)),([3]8,([2]6,_,([1]7,_,_)),([2]9,_,([1]10,_,_))))",
#| )
#| set.remove(10)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(
#| set.debug_tree(),
#| content="([4]4,([2]2,_,([1]3,_,_)),([3]8,([2]6,_,([1]7,_,_)),([1]9,_,_)))",
#| )
#| set.remove(4)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(
#| set.debug_tree(),
#| content="([3]6,([2]2,_,([1]3,_,_)),([2]8,([1]7,_,_),([1]9,_,_)))",
#| )
#| set.add(1)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(
#| set.debug_tree(),
#| content="([3]6,([2]2,([1]1,_,_),([1]3,_,_)),([2]8,([1]7,_,_),([1]9,_,_)))",
#| )
#| set.add(5)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(
#| set.debug_tree(),
#| content="([4]6,([3]2,([1]1,_,_),([2]3,_,([1]5,_,_))),([2]8,([1]7,_,_),([1]9,_,_)))",
#| )
#| set.add(10)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| 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)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| 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)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| 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)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| 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)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| set.add(10)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| set.remove(1)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| 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)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(
#| set.debug_tree(),
#| content="([4]6,([2]4,([1]3,_,_),([1]5,_,_)),([3]8,([1]7,_,_),([2]10,([1]9,_,_),_)))",
#| )
#| set.remove(3)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(
#| set.debug_tree(),
#| content="([4]6,([2]4,_,([1]5,_,_)),([3]8,([1]7,_,_),([2]10,([1]9,_,_),_)))",
#| )
#| set.remove(4)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(
#| set.debug_tree(),
#| content="([3]8,([2]6,([1]5,_,_),([1]7,_,_)),([2]10,([1]9,_,_),_))",
#| )
#| set.remove(5)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(
#| set.debug_tree(),
#| content="([3]8,([2]6,_,([1]7,_,_)),([2]10,([1]9,_,_),_))",
#| )
#| set.remove(6)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(set.debug_tree(), content="([3]8,([1]7,_,_),([2]10,([1]9,_,_),_))")
#| set.remove(7)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(set.debug_tree(), content="([2]9,([1]8,_,_),([1]10,_,_))")
#| set.remove(8)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(set.debug_tree(), content="([2]9,_,([1]10,_,_))")
#| set.remove(9)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(set.debug_tree(), content="([1]10,_,_)")
#| set.remove(10)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(set.debug_tree(), content="_")
#| let set = from_array([7, 2, 9, 4, 5, 6, 3, 1])
#| set.remove(3)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(
#| set.debug_tree(),
#| content="([3]5,([2]2,([1]1,_,_),([1]4,_,_)),([2]7,([1]6,_,_),([1]9,_,_)))",
#| )
#| set.remove(2)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(
#| set.debug_tree(),
#| content="([3]5,([2]4,([1]1,_,_),_),([2]7,([1]6,_,_),([1]9,_,_)))",
#| )
#| set.remove(5)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(
#| set.debug_tree(),
#| content="([3]6,([2]4,([1]1,_,_),_),([2]7,_,([1]9,_,_)))",
#| )
#| set.remove(9)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(set.debug_tree(), content="([3]6,([2]4,([1]1,_,_),_),([1]7,_,_))")
#| set.remove(1)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(set.debug_tree(), content="([2]6,([1]4,_,_),([1]7,_,_))")
#| set.remove(7)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(set.debug_tree(), content="([2]6,([1]4,_,_),_)")
#| set.remove(4)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(set.debug_tree(), content="([1]6,_,_)")
#| set.remove(6)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(set.debug_tree(), content="_")
#|}
#|pub impl[K] Default for SortedSet[K] with default() {
#| new_sorted_set()
#|}
),
"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
#|} derive(@debug.Debug)
),
"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={},
files={
"bool.mbt": (
#|#deprecated("use `@string.parse_bool` instead", skip_current_package=true)
#|pub fn parse_bool(str : StringView) -> Bool raise StrConvError {
#| lexmatch str with longest {
#| "(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 = for s = rest {
#| match s {
#| ['_', .. 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 => break 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 exp_limit = if exp_sign > 0 {
#| if d.decimal_point < 311 {
#| 311 - d.decimal_point
#| } else {
#| 0
#| }
#| } else if d.decimal_point > -331 {
#| d.decimal_point + 331
#| } else {
#| 0
#| }
#| let mut exp = 0
#| let rest = for s = rest {
#| match s {
#| ['_', .. rest] => continue rest
#| ['0'..='9' as digit, .. rest] => {
#| if exp < exp_limit {
#| exp = exp * 10 + (digit.to_int() - '0')
#| if exp > exp_limit {
#| exp = exp_limit
#| }
#| }
#| continue rest
#| }
#| rest => break 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("use `@string.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
#|} derive(@debug.Debug)
#|#deprecated("use `@string.parse_double` instead", skip_current_package=true)
#|pub fn Decimal::new() -> Decimal {
#| Decimal::new_priv()
#|}
#|#deprecated("use `@string.parse_double` instead", skip_current_package=true)
#|pub fn Decimal::from_int64(v : Int64) -> Decimal {
#| Decimal::from_int64_priv(v)
#|}
#|#deprecated("use `@string.parse_double` instead", skip_current_package=true)
#|pub fn parse_decimal(str : StringView) -> Decimal raise StrConvError {
#| parse_decimal_from_view(str)
#|}
#|#deprecated("use `@string.parse_double` instead", skip_current_package=true)
#|pub fn Decimal::parse_decimal(str : StringView) -> Decimal raise StrConvError {
#| parse_decimal_from_view(str)
#|}
#|#deprecated("use `@string.parse_double` instead", skip_current_package=true)
#|pub fn Decimal::to_double(self : Decimal) -> Double raise StrConvError {
#| self.to_double_priv()
#|}
#|#deprecated("use `@string.parse_double` instead", skip_current_package=true)
#|pub fn Decimal::shift(self : Decimal, s : Int) -> Unit {
#| self.shift_priv(s)
#|}
#|#deprecated("use `@string.from_str` instead", skip_current_package=true)
#|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
#|#deprecated("use `@string.parse_double` instead", skip_current_package=true)
#|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": (
#|#deprecated("use `@string` parsing APIs instead", skip_current_package=true)
#|pub(all) suberror StrConvError {
#| StrConvError(String)
#|} derive(@debug.Debug)
#|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)")
#|}
#|#deprecated("use `@string.parse_int64` instead", skip_current_package=true)
#|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() }
#| for s = rest, acc = 0L, au = allow_underscore {
#| match (s, acc, au) {
#| (['_'], _, _) =>
#| 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, _) => break acc
#| }
#| }
#|}
#|#deprecated("use `@string.parse_int` instead", skip_current_package=true)
#|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 with longest {
#| ("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
#| for s = rest, au = allow_underscore, fu = follow_underscore {
#| match (s, au, fu) {
#| ([], _, _) => break true
#| (['_'], _, _) => break false
#| (['_', ..], false, _) => break false
#| (['_', .. rest], true, _) => continue rest, false, true
#| ([c, .. rest], _, fu) =>
#| if is_digit(c) {
#| continue rest, true, false
#| } else if fu {
#| break 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
#| for s = s {
#| match 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
#| for s = start {
#| match s {
#| ['0' | '.' as ch, .. rest] => {
#| n_digits -= (ch.to_int() - 46) / 2 // '0' = b'.' + 2
#| continue rest
#| }
#| _ => break
#| }
#| }
#| 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 with longest {
#| "(?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": (
#|#deprecated("use `@string.FromStr` instead", skip_current_package=true)
#|pub(open) trait FromStr {
#| #as_free_fn
#| #deprecated("use `@string.from_str` instead", skip_current_package=true)
#| from_str(StringView) -> Self raise StrConvError = _
#| #deprecated("use `@string.from_str` instead", skip_current_package=true)
#| from_string(String) -> Self raise StrConvError = _
#|}
#|#deprecated("replace `impl @strconv.FromStr::from_string` with `impl @string.FromStr::from_str`", skip_current_package=true)
#|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
#|#deprecated("use `@string.parse_uint64` instead", skip_current_package=true)
#|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() }
#| for s = rest, acc = 0UL, au = allow_underscore {
#| match (s, acc, au) {
#| (['_'], _, _) =>
#| 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, _) => break acc
#| }
#| }
#|}
#|#deprecated("use `@string.parse_uint` instead", skip_current_package=true)
#|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={},
files={
"regex.mbt": (
#|pub struct Regex {
#| priv pat : @re.Pattern
#| priv mut re : @re.Regex?
#|}
#|pub fn Regex::Regex(pattern : StringView) -> Regex raise {
#| let pat = @regex_parser.parse(
#| profile=re_profile_unicode,
#| pattern,
#| mode=String,
#| )
#| { pat, re: None }
#|}
#|const MAX_REPEAT_QUANTIFIER = 256
#|using @debug {trait Debug, type Repr}
#|pub impl Debug for Regex with to_repr(self) {
#| Repr::opaque_("Regex", @debug.to_repr(self.pat))
#|}
#|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,
#| }
#|}
#|#intrinsic("%regex.seq")
#|pub impl Add for Regex with add(self, other) -> Regex {
#| { pat: @re.seq([self.pat, other.pat]), re: None }
#|}
#|#intrinsic("%regex.alt")
#|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()
#| 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)
#| }
#|}
),
"strconv.mbt": (
#|pub using @internal/strconv {
#| parse_int64,
#| parse_int,
#| parse_uint64,
#| parse_uint,
#| parse_bool,
#| parse_double,
#|}
),
"strconv_traits.mbt": (
#|pub(open) trait FromStr {
#| #as_free_fn
#| from_str(StringView) -> Self raise
#|}
#|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")
#| @test.assert_eq(i64, 9223372036854775807L)
#| let ui : UInt = from_str("4294967295")
#| inspect(ui, content="4294967295")
#| let ui64 : UInt64 = from_str("18446744073709551615")
#| @test.assert_eq(ui64, 18446744073709551615UL)
#| let d : Double = from_str("1234.56789")
#| @test.assert_eq(d, 1234.56789)
#|}
),
"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_internal_regex_engine_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/string/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))
#|}
#|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([]),
#| 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 start_state in self.start_states {
#| let (cat, state_id) = start_state
#| if cat == prev_cat {
#| return state_id
#| }
#| }
#| let state_id = self.stablize_state(
#| @automata.State::start(prev_cat, self.expr),
#| )
#| self.start_states.push((prev_cat, state_id))
#| state_id
#|}
#|fn Regex::stablize_state(self : Regex, state : @automata.State) -> 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()
#| for entry = self.final_table[state_index] {
#| match entry {
#| 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],
#| )
#| break (slot, status)
#| }
#| More(head, tail~) =>
#| if head.0 == next_cat {
#| break (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 {
#| for i = n, acc = init {
#| if i == 0 {
#| break acc
#| } else {
#| continue i - 1, f(acc)
#| }
#| }
#|}
),
"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_internal_regex_engine_ast_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/string/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) {
#| @debug.to_repr(self.desc)
#|}
#|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}
),
},
)
///|
let moonbitlang_core_string_internal_regex_engine_symbol_map_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/string/internal/regex_engine/symbol_map",
deps={},
files={
"symbol_map.mbt": (
#|struct SymbolMap(@sorted_set.SortedSet[Rechar])
#|pub fn new() -> SymbolMap {
#| SymbolMap(@sorted_set.SortedSet([]))
#|}
#|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_internal_regex_parser_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/string/internal/regex_parser",
deps={},
files={
"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_owned(), 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={},
files={
"test.mbt": (
#|using @debug {trait Debug}
#|fn[T : Show] debug_string(t : T) -> String {
#| let buf = StringBuilder(size_hint=50)
#| t.output(buf)
#| buf.to_string()
#|}
#|#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 => "`\{@debug.to_string(a)} != \{@debug.to_string(b)}`"
#| }
#| fail(fail_msg, loc~)
#| }
#|}
#|#callsite(autofill(loc))
#|pub fn[T : Eq + Debug] 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.to_string(a)} == \{@debug.to_string(b)}`"
#| }
#| fail(fail_msg, loc~)
#| }
#|}
#|#deprecated("use `@test.assert_same_object` instead", skip_current_package=true)
#|#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))
#|pub fn[T : Debug] assert_same_object(
#| a : T,
#| b : T,
#| loc~ : SourceLoc,
#|) -> Unit raise {
#| if !physical_equal(a, b) {
#| let a = @debug.to_string(a)
#| let b = @debug.to_string(b)
#| fail("`\{a} is \{b}`", loc~)
#| }
#|}
#|#deprecated("use `@test.assert_not_same_object` instead", skip_current_package=true)
#|#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 : Debug] assert_not_same_object(
#| a : T,
#| b : T,
#| loc~ : SourceLoc,
#|) -> Unit raise {
#| if physical_equal(a, b) {
#| let a = @debug.to_string(a)
#| let b = @debug.to_string(b)
#| fail("`!(\{a} is \{b})`", loc~)
#| }
#|}
#|#callsite(autofill(loc))
#|pub fn[T] fail(msg : StringView, 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
#|} derive(@debug.Debug)
#|#as_free_fn
#|pub fn Test::new(name : String) -> Test {
#| { name, buffer: StringBuilder() }
#|}
),
},
)
///|
let moonbitlang_core_tuple_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/tuple",
deps={},
files={
"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={},
files={
"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={},
files={
"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={},
files={
"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={},
files={
"unit.mbt": (
#|#deprecated("Use `Unit::default` instead")
#|pub fn default() -> Unit {
#| ()
#|}
),
},
)
|