///|
/// 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 { #| () #|} ), }, )