From 2899f1536c80f31fc9b20cf32cc26e4fdf03d0bf Mon Sep 17 00:00:00 2001 From: mertcandav Date: Wed, 4 Sep 2024 11:09:51 +0300 Subject: [PATCH] codebase: execute julefmt with latest convensions --- src/julec/compile.jule | 672 +- src/julec/handle/ansi.jule | 30 +- src/julec/handle/logger.jule | 128 +- src/julec/handle/throw.jule | 4 +- src/julec/main.jule | 244 +- src/julec/obj/cxx/expr.jule | 3256 ++-- src/julec/obj/cxx/ident.jule | 388 +- src/julec/obj/cxx/object.jule | 2620 ++-- src/julec/obj/cxx/scope.jule | 2074 +-- src/julec/obj/cxx/test.jule | 282 +- src/julec/obj/cxx/type.jule | 896 +- src/julec/obj/determine.jule | 112 +- src/julec/obj/ir.jule | 270 +- src/julec/obj/lookup.jule | 86 +- src/julec/obj/order.jule | 82 +- src/julec/obj/walk.jule | 46 +- src/julec/opt/boundary.jule | 244 +- src/julec/opt/data.jule | 42 +- src/julec/opt/deadcode/define.jule | 534 +- src/julec/opt/deadcode/expr.jule | 536 +- src/julec/opt/deadcode/scope.jule | 472 +- src/julec/opt/dynamic.jule | 208 +- src/julec/opt/equal.jule | 124 +- src/julec/opt/expr.jule | 1598 +- src/julec/opt/flag.jule | 42 +- src/julec/opt/model.jule | 70 +- src/julec/opt/nil.jule | 160 +- src/julec/opt/optimizer.jule | 200 +- src/julec/opt/scope.jule | 1374 +- src/julec/windows.jule | 22 +- std/bytes/bytes.jule | 494 +- std/comptime/type.jule | 56 +- std/conv/atob.jule | 24 +- std/conv/atof.jule | 1268 +- std/conv/atoi.jule | 262 +- std/conv/decimal.jule | 586 +- std/conv/eisel_lemire.jule | 1640 +-- std/conv/error.jule | 10 +- std/conv/ftoa.jule | 996 +- std/conv/ftoaryu.jule | 948 +- std/conv/itoa.jule | 284 +- std/encoding/ascii85/ascii85.jule | 440 +- std/encoding/ascii85/ascii85_test.jule | 78 +- std/encoding/ascii85/error.jule | 2 +- std/encoding/base32/base32.jule | 216 +- std/encoding/base32/base32_test.jule | 152 +- std/encoding/base64/base64.jule | 254 +- std/encoding/base64/base64_test.jule | 160 +- std/encoding/binary/big_endian.jule | 124 +- std/encoding/binary/little_endian.jule | 124 +- std/encoding/csv/error.jule | 18 +- std/encoding/csv/reader.jule | 680 +- std/encoding/csv/writer.jule | 218 +- std/encoding/json/buffer.jule | 160 +- std/encoding/json/decode.jule | 1540 +- std/encoding/json/decode_test.jule | 198 +- std/encoding/json/encode.jule | 774 +- std/encoding/json/encode_test.jule | 394 +- std/encoding/json/error.jule | 16 +- std/encoding/json/escape.jule | 4 +- std/encoding/json/validate.jule | 30 +- std/encoding/json/validate_test.jule | 220 +- std/env/error.jule | 70 +- std/env/error_windows.jule | 38 +- std/env/proc.jule | 14 +- std/env/proc_unix.jule | 24 +- std/env/proc_windows.jule | 28 +- std/flag/flag.jule | 492 +- std/fmt/format.jule | 2 +- std/fmt/print.jule | 48 +- std/fs/dir.jule | 4 +- std/fs/dir_unix.jule | 94 +- std/fs/dir_windows.jule | 92 +- std/fs/error.jule | 238 +- std/fs/file.jule | 196 +- std/fs/file_unix.jule | 130 +- std/fs/file_windows.jule | 188 +- std/fs/path/path.jule | 324 +- std/fs/path/path_unix.jule | 32 +- std/fs/path/path_windows.jule | 240 +- std/fs/stat.jule | 22 +- std/fs/stat_unix.jule | 44 +- std/fs/stat_windows.jule | 44 +- std/hash/adler32/adler32.jule | 144 +- std/hash/adler32/adler32_test.jule | 104 +- std/hash/fnv/fnv.jule | 314 +- std/hash/fnv/fnv_test.jule | 94 +- std/hash/hash.jule | 38 +- std/internal/byteorder/byteorder.jule | 140 +- std/internal/cmp/cmp.jule | 16 +- std/internal/conv/atoi.jule | 84 +- std/internal/conv/atoi_test.jule | 80 +- std/internal/conv/itoa.jule | 48 +- std/internal/conv/itoa_test.jule | 40 +- std/internal/dynar/dynar.jule | 166 +- std/internal/fastbytes/fastbytes.jule | 100 +- std/internal/fastbytes/fastbytes_test.jule | 84 +- std/internal/fmt/format.jule | 216 +- std/internal/strings/builder.jule | 114 +- std/internal/zsys/io_unix.jule | 6 +- std/io/byte.jule | 78 +- std/io/file.jule | 126 +- std/io/io.jule | 18 +- std/io/scan.jule | 108 +- std/io/stream.jule | 12 +- std/jule/ast/ast.jule | 8 +- std/jule/ast/node.jule | 718 +- std/jule/build/cpp.jule | 58 +- std/jule/build/directive.jule | 18 +- std/jule/build/env.jule | 28 +- std/jule/build/log.jule | 662 +- std/jule/build/platform.jule | 30 +- std/jule/constant/const.jule | 1146 +- std/jule/constant/lit/bytes.jule | 212 +- std/jule/importer/annotation.jule | 170 +- std/jule/importer/directive_eval.jule | 238 +- std/jule/importer/importer.jule | 318 +- std/jule/importer/var.jule | 92 +- std/jule/integrated/conv.jule | 130 +- std/jule/integrated/mem.jule | 24 +- std/jule/internal/mod/export.jule | 12 +- std/jule/internal/mod/mod.jule | 70 +- std/jule/lex/file.jule | 88 +- std/jule/lex/lex.jule | 1440 +- std/jule/lex/token.jule | 718 +- std/jule/parser/assign.jule | 58 +- std/jule/parser/expr.jule | 2138 +-- std/jule/parser/parse.jule | 56 +- std/jule/parser/parser.jule | 3750 ++--- std/jule/parser/scope.jule | 2282 +-- std/jule/parser/type.jule | 748 +- std/jule/sema/analysis.jule | 92 +- std/jule/sema/builtin.jule | 2056 +-- std/jule/sema/comptime.jule | 2564 ++-- std/jule/sema/constrait.jule | 326 +- std/jule/sema/directive.jule | 344 +- std/jule/sema/enum.jule | 118 +- std/jule/sema/eval.jule | 8956 +++++------ std/jule/sema/fn.jule | 688 +- std/jule/sema/impl.jule | 24 +- std/jule/sema/lookup.jule | 48 +- std/jule/sema/model.jule | 270 +- std/jule/sema/package.jule | 544 +- std/jule/sema/pattern.jule | 520 +- std/jule/sema/scope.jule | 4176 +++--- std/jule/sema/sema.jule | 5696 +++---- std/jule/sema/struct.jule | 574 +- std/jule/sema/symbol.jule | 1348 +- std/jule/sema/table.jule | 468 +- std/jule/sema/trait.jule | 104 +- std/jule/sema/type.jule | 3312 ++--- std/jule/sema/type2.jule | 2668 ++-- std/jule/sema/var.jule | 68 +- std/jule/types/bits.jule | 256 +- std/jule/types/comp.jule | 82 +- std/jule/types/kind.jule | 62 +- std/jule/types/limits.jule | 138 +- std/maps/maps.jule | 52 +- std/maps/maps_test.jule | 200 +- std/math/acosh.jule | 28 +- std/math/asin.jule | 42 +- std/math/asinh.jule | 54 +- std/math/atan.jule | 60 +- std/math/atan2.jule | 76 +- std/math/atanh.jule | 58 +- std/math/big/bits.jule | 488 +- std/math/big/bits_test.jule | 38 +- std/math/big/conv.jule | 532 +- std/math/big/conv_test.jule | 86 +- std/math/big/error.jule | 2 +- std/math/big/int.jule | 978 +- std/math/big/int_test.jule | 476 +- std/math/big/nat.jule | 878 +- std/math/big/nat_test.jule | 412 +- std/math/bits.jule | 38 +- std/math/bits/bits.jule | 542 +- std/math/bits/bits_tables.jule | 120 +- std/math/cbrt.jule | 84 +- std/math/cmplx/abs.jule | 8 +- std/math/cmplx/asin.jule | 362 +- std/math/cmplx/cmplx.jule | 282 +- std/math/cmplx/exp.jule | 44 +- std/math/cmplx/log.jule | 18 +- std/math/cmplx/phase.jule | 10 +- std/math/cmplx/polar.jule | 12 +- std/math/cmplx/pow.jule | 74 +- std/math/cmplx/rect.jule | 10 +- std/math/cmplx/sin.jule | 286 +- std/math/cmplx/sqrt.jule | 104 +- std/math/cmplx/tan.jule | 474 +- std/math/copysign.jule | 4 +- std/math/dim.jule | 88 +- std/math/erf.jule | 272 +- std/math/erfinv.jule | 74 +- std/math/exp.jule | 142 +- std/math/expm1.jule | 208 +- std/math/floor.jule | 150 +- std/math/fma.jule | 262 +- std/math/frexp.jule | 28 +- std/math/gamma.jule | 238 +- std/math/hypot.jule | 32 +- std/math/j0.jule | 518 +- std/math/j1.jule | 518 +- std/math/jn.jule | 474 +- std/math/ldexp.jule | 58 +- std/math/lgamma.jule | 480 +- std/math/log.jule | 70 +- std/math/log10.jule | 14 +- std/math/log1p.jule | 192 +- std/math/logb.jule | 44 +- std/math/mod.jule | 40 +- std/math/modf.jule | 32 +- std/math/nextafter.jule | 52 +- std/math/pow.jule | 216 +- std/math/pow10.jule | 36 +- std/math/rand/rand.jule | 202 +- std/math/remainder.jule | 94 +- std/math/sin.jule | 204 +- std/math/sincos.jule | 102 +- std/math/sinh.jule | 70 +- std/math/sqrt.jule | 90 +- std/math/tan.jule | 104 +- std/math/tanh.jule | 56 +- std/math/trig_reduce.jule | 126 +- std/mem/builtin_test.jule | 20 +- std/mem/heap.jule | 74 +- std/net/addr.jule | 406 +- std/net/conv.jule | 10 +- std/net/ip.jule | 386 +- std/net/ip_addr.jule | 560 +- std/net/mac.jule | 166 +- std/net/mac_test.jule | 164 +- std/net/net.jule | 30 +- std/net/sock.jule | 54 +- std/net/sock_unix.jule | 196 +- std/net/sock_windows.jule | 180 +- std/net/tcp.jule | 68 +- std/net/tcp_conn.jule | 184 +- std/net/tcp_listener.jule | 562 +- std/net/u128.jule | 4 +- std/net/udp.jule | 68 +- std/net/udp_conn.jule | 478 +- std/process/cmd.jule | 56 +- std/process/cmd_unix.jule | 200 +- std/process/cmd_windows.jule | 294 +- std/process/error.jule | 10 +- std/process/error_unix.jule | 24 +- std/process/error_windows.jule | 20 +- std/queue/queue.jule | 194 +- std/slices/slices.jule | 78 +- std/slices/slices_test.jule | 120 +- std/slices/sort.jule | 34 +- std/slices/sort_test.jule | 102 +- std/slices/sortfunc.jule | 512 +- std/slices/sortordered.jule | 516 +- std/stack/stack.jule | 190 +- std/strings/compare.jule | 42 +- std/strings/strings.jule | 446 +- std/sync/atomic/atomic.jule | 184 +- std/sync/mutex.jule | 78 +- std/sync/once.jule | 116 +- std/sync/waitgroup.jule | 90 +- std/sys/net.jule | 32 +- std/sys/net_unix.jule | 28 +- std/sys/net_windows.jule | 38 +- std/sys/syscall.jule | 6 +- std/sys/syscall_unix.jule | 16 +- std/sys/syscall_windows.jule | 52 +- std/testing/t.jule | 106 +- std/thread/thread.jule | 108 +- std/time/duration.jule | 370 +- std/time/thread.jule | 6 +- std/time/time.jule | 434 +- std/unicode/digit.jule | 8 +- std/unicode/graphic.jule | 66 +- std/unicode/letter.jule | 320 +- std/unicode/tables.jule | 14686 +++++++++---------- std/unicode/utf16/utf16.jule | 138 +- std/unicode/utf8/utf8.jule | 856 +- std/unsafe/conv.jule | 64 +- std/vec/vec.jule | 422 +- tests/arrays/main.jule | 12 +- tests/assertion/main.jule | 6 +- tests/basic_calculator/main.jule | 64 +- tests/comptime/match.jule | 80 +- tests/concurrency/main.jule | 20 +- tests/exceptionals/main.jule | 70 +- tests/generics/main.jule | 48 +- tests/levenshtein_distance/main.jule | 84 +- tests/maps/main.jule | 40 +- tests/operator_overloading/main.jule | 280 +- tests/quicksort/main.jule | 38 +- tests/sleep/main.jule | 20 +- tests/syntax/main.jule | 436 +- tests/traits/main.jule | 74 +- 295 files changed, 61278 insertions(+), 61278 deletions(-) diff --git a/src/julec/compile.jule b/src/julec/compile.jule index c7c7c5f9c..6b33c04b2 100644 --- a/src/julec/compile.jule +++ b/src/julec/compile.jule @@ -12,19 +12,19 @@ use std::fs::{FsError, OFlag, File, Directory, Status} use path for std::fs::path use integrated for std::jule::integrated use std::jule::sema::{ - ImportInfo, - Package, - SemaFlag, + ImportInfo, + Package, + SemaFlag, } use build for std::jule::build::{ - self, - LogMsg, - Log, - PathStdlib, - EntryPoint, - InitFn, - Logf, - IsValidCppExt, + self, + LogMsg, + Log, + PathStdlib, + EntryPoint, + InitFn, + Logf, + IsValidCppExt, } use types for std::jule::types use std::process::{ProcessError, Cmd} @@ -35,394 +35,394 @@ static mut OutName = "ir.cpp" static mut Out = "" fn init() { - // Configure compiler to default by platform - // Compiler path will be set by compiler before compilation if still unassigned. - env::Compiler = "clang" + // Configure compiler to default by platform + // Compiler path will be set by compiler before compilation if still unassigned. + env::Compiler = "clang" } fn openOutput(&path: str): &File { - dir := path::Dir(path) - - Status.Of(dir) else { - Directory.Create(dir) else { - Throw("a problem occurs when code generation") - } - } - - ret File.Create(path) else { - Throw("a problem occurs when code generation") - use nil - } + dir := path::Dir(path) + + Status.Of(dir) else { + Directory.Create(dir) else { + Throw("a problem occurs when code generation") + } + } + + ret File.Create(path) else { + Throw("a problem occurs when code generation") + use nil + } } // Remove generated objects for compilation. fn clearObjects() { - File.Remove(getCompilePath()) else { - outln("a problem occurs when object cleaning") - ret - } - - // All created objects are cleaned. - // So, deletes directory if empty after cleaned all objects, - // if not, leaves the directory. - Directory.Remove(OutDir) else {} + File.Remove(getCompilePath()) else { + outln("a problem occurs when object cleaning") + ret + } + + // All created objects are cleaned. + // So, deletes directory if empty after cleaned all objects, + // if not, leaves the directory. + Directory.Remove(OutDir) else {} } // Compie generated IR. fn compileIr(compiler: str, compilerCmd: str) { - mut cmd := Cmd.New(compiler) - cmd.Args = strings::Split(compilerCmd, " ", -1) - cmd.Spawn() else { - match error { - | ProcessError.NotExist: - AnsiEscape.Print(AnsiEscape.RedSeq, "back-end compiler could not used because of compiler path is not exist") - | ProcessError.Denied: - AnsiEscape.Print(AnsiEscape.RedSeq, "back-end compiler could not used because of permission denied") - |: - AnsiEscape.Print(AnsiEscape.RedSeq, "back-end compiler could not used because of unknown problem") - } - Throw("") - } - status := cmd.Wait()! - if status != 0 { - errorMessage := "\n>>> your backend compiler (" + env::Compiler + `) reports problems + mut cmd := Cmd.New(compiler) + cmd.Args = strings::Split(compilerCmd, " ", -1) + cmd.Spawn() else { + match error { + | ProcessError.NotExist: + AnsiEscape.Print(AnsiEscape.RedSeq, "back-end compiler could not used because of compiler path is not exist") + | ProcessError.Denied: + AnsiEscape.Print(AnsiEscape.RedSeq, "back-end compiler could not used because of permission denied") + |: + AnsiEscape.Print(AnsiEscape.RedSeq, "back-end compiler could not used because of unknown problem") + } + Throw("") + } + status := cmd.Wait()! + if status != 0 { + errorMessage := "\n>>> your backend compiler (" + env::Compiler + `) reports problems >>> please check errors above >>> is this a compiler problem, please report us: https://github.com/julelang/jule/issues/new/choose` - AnsiEscape.Print(AnsiEscape.RedSeq, errorMessage) - Throw("") - } + AnsiEscape.Print(AnsiEscape.RedSeq, errorMessage) + Throw("") + } - clearObjects() + clearObjects() } fn isCppSourceFile(path: str): bool { - offset := strings::FindLastByte(path, '.') - if offset == -1 { - ret false - } - ret IsValidCppExt(path[offset:]) + offset := strings::FindLastByte(path, '.') + if offset == -1 { + ret false + } + ret IsValidCppExt(path[offset:]) } fn pushCompCmdClang(mut &cmd: StrBuilder) { - // Disable all warnings. - cmd.WriteStr("-Wno-everything ") - - // Set C++ standard. - cmd.WriteStr("--std=") - match env::CppStd { - | "cpp14": - cmd.WriteStr("c++14") - | "cpp17": - cmd.WriteStr("c++17") - | "cpp20": - cmd.WriteStr("c++20") - } - cmd.WriteByte(' ') - - if env::Production { - cmd.WriteStr("-O3 ") // Enable all optimizations. - cmd.WriteStr("-flto ") // Enable LTO. - cmd.WriteStr("-DNDEBUG ") // Define NDEBUG, turn off assertions. - cmd.WriteStr("-fomit-frame-pointer ") // Do not use frame pointer. - } else { - cmd.WriteStr("-O0 ") // No optimization. - } + // Disable all warnings. + cmd.WriteStr("-Wno-everything ") + + // Set C++ standard. + cmd.WriteStr("--std=") + match env::CppStd { + | "cpp14": + cmd.WriteStr("c++14") + | "cpp17": + cmd.WriteStr("c++17") + | "cpp20": + cmd.WriteStr("c++20") + } + cmd.WriteByte(' ') + + if env::Production { + cmd.WriteStr("-O3 ") // Enable all optimizations. + cmd.WriteStr("-flto ") // Enable LTO. + cmd.WriteStr("-DNDEBUG ") // Define NDEBUG, turn off assertions. + cmd.WriteStr("-fomit-frame-pointer ") // Do not use frame pointer. + } else { + cmd.WriteStr("-O0 ") // No optimization. + } } fn pushCompCmdGcc(mut &cmd: StrBuilder) { - // Disable all warnings. - cmd.WriteStr("-w ") - - // Set C++ standard. - cmd.WriteStr("--std=") - match env::CppStd { - | "cpp14": - cmd.WriteStr("c++14") - | "cpp17": - cmd.WriteStr("c++17") - | "cpp20": - cmd.WriteStr("c++20") - } - cmd.WriteByte(' ') - - if env::Production { - cmd.WriteStr("-O3 ") // Enable all optimizations. - cmd.WriteStr("-DNDEBUG ") // Define NDEBUG, turn off assertions. - cmd.WriteStr("-fomit-frame-pointer ") // Do not use frame pointer. - } else { - cmd.WriteStr("-O0 ") // No optimization. - } + // Disable all warnings. + cmd.WriteStr("-w ") + + // Set C++ standard. + cmd.WriteStr("--std=") + match env::CppStd { + | "cpp14": + cmd.WriteStr("c++14") + | "cpp17": + cmd.WriteStr("c++17") + | "cpp20": + cmd.WriteStr("c++20") + } + cmd.WriteByte(' ') + + if env::Production { + cmd.WriteStr("-O3 ") // Enable all optimizations. + cmd.WriteStr("-DNDEBUG ") // Define NDEBUG, turn off assertions. + cmd.WriteStr("-fomit-frame-pointer ") // Do not use frame pointer. + } else { + cmd.WriteStr("-O0 ") // No optimization. + } } // Generate compile command for backend-compiler. fn genCompileCmd(sourcePath: str, &ir: &IR): (str, str) { - &compiler := env::CompilerPath - mut cmd := StrBuilder.New(1 << 6) - - match env::Compiler { - | "gcc": - pushCompCmdGcc(cmd) - | "clang": - pushCompCmdClang(cmd) - } - - // Push binded source files. - for _, u in ir.Used { - if u.Binded && isCppSourceFile(u.Path) { - cmd.WriteStr(u.Path) - cmd.WriteByte(' ') - } - } - - if Out != "" { - cmd.WriteStr("-o ") - cmd.WriteStr(Out) - cmd.WriteByte(' ') - } - cmd.WriteStr(sourcePath) - - // Push passes. - for _, pass in ir.Passes { - cmd.WriteByte(' ') - cmd.WriteStr(pass) - } - - // Link necessary libraries for Windows. - if build::Os == build::DistOs.Windows { - cmd.WriteStr(" -lshell32") - } - - ret compiler, cmd.Str() + &compiler := env::CompilerPath + mut cmd := StrBuilder.New(1 << 6) + + match env::Compiler { + | "gcc": + pushCompCmdGcc(cmd) + | "clang": + pushCompCmdClang(cmd) + } + + // Push binded source files. + for _, u in ir.Used { + if u.Binded && isCppSourceFile(u.Path) { + cmd.WriteStr(u.Path) + cmd.WriteByte(' ') + } + } + + if Out != "" { + cmd.WriteStr("-o ") + cmd.WriteStr(Out) + cmd.WriteByte(' ') + } + cmd.WriteStr(sourcePath) + + // Push passes. + for _, pass in ir.Passes { + cmd.WriteByte(' ') + cmd.WriteStr(pass) + } + + // Link necessary libraries for Windows. + if build::Os == build::DistOs.Windows { + cmd.WriteStr(" -lshell32") + } + + ret compiler, cmd.Str() } fn getCompilePath(): str { - // Return command-line argument form - // instead of absolute path. - ret path::Join(OutDir, OutName) + // Return command-line argument form + // instead of absolute path. + ret path::Join(OutDir, OutName) } fn applyTargetIndependentOptimizations(mut &ir: &IR) { - mut opt := Optimizer.New(ir) - opt.Optimize() + mut opt := Optimizer.New(ir) + opt.Optimize() } fn checkCompilerFlag() { - match env::Compiler { - | "": - Throw("missing option value: --compiler") - | "clang": - if env::CompilerPath == "" { - env::CompilerPath = "clang++" - } - | "gcc": - if env::CompilerPath == "" { - env::CompilerPath = "g++" - } - |: - Throw("invalid option value for --compiler: " + env::Compiler) - } + match env::Compiler { + | "": + Throw("missing option value: --compiler") + | "clang": + if env::CompilerPath == "" { + env::CompilerPath = "clang++" + } + | "gcc": + if env::CompilerPath == "" { + env::CompilerPath = "g++" + } + |: + Throw("invalid option value for --compiler: " + env::Compiler) + } } fn checkTargetArch(arch: str) { - if arch != build::DistArch.Amd64 && - arch != build::DistArch.Arm64 && - arch != build::DistArch.I386 { - Throw("--target: unsupported/undefined architecture: " + arch) - } + if arch != build::DistArch.Amd64 && + arch != build::DistArch.Arm64 && + arch != build::DistArch.I386 { + Throw("--target: unsupported/undefined architecture: " + arch) + } } fn checkTargetOs(os: str) { - if os != build::DistOs.Windows && - os != build::DistOs.Linux && - os != build::DistOs.Darwin { - Throw("--target: unsupported/undefined operating system: " + os) - } + if os != build::DistOs.Windows && + os != build::DistOs.Linux && + os != build::DistOs.Darwin { + Throw("--target: unsupported/undefined operating system: " + os) + } } fn checkTargetFlag(&target: str) { - if target == "" { - Throw("missing option value: --target") - } - - parts := strings::Split(target, "-", -1) - if len(parts) != 2 { - Throw("--target: undefined platform target format: " + target) - } - - os, arch := parts[0], parts[1] - - if os != "native" { - checkTargetOs(os) - build::Os = os - } - if arch != "native" { - checkTargetArch(arch) - build::Arch = arch - } - types::UpdateTarget() + if target == "" { + Throw("missing option value: --target") + } + + parts := strings::Split(target, "-", -1) + if len(parts) != 2 { + Throw("--target: undefined platform target format: " + target) + } + + os, arch := parts[0], parts[1] + + if os != "native" { + checkTargetOs(os) + build::Os = os + } + if arch != "native" { + checkTargetArch(arch) + build::Arch = arch + } + types::UpdateTarget() } fn checkOptFlag(&opt: str) { - if opt == "" { - Throw("missing option value: --opt") - } - - match opt { - | "L0": - break - | "L1": - opt::PushOptLevel(OptLevel.L1) - |: - Throw("--opt: invalid optimization level: " + opt) - } + if opt == "" { + Throw("missing option value: --opt") + } + + match opt { + | "L0": + break + | "L1": + opt::PushOptLevel(OptLevel.L1) + |: + Throw("--opt: invalid optimization level: " + opt) + } } fn checkCppStdFlag() { - match env::CppStd { - | "cpp14" - | "cpp17" - | "cpp20": - break - |: - Throw("--cppstd: invalid cpp standard: " + env::CppStd) - } + match env::CppStd { + | "cpp14" + | "cpp17" + | "cpp20": + break + |: + Throw("--cppstd: invalid cpp standard: " + env::CppStd) + } } fn checkFlags(&args: []str): []str { - mut opt := "L0" - mut target := "native-native" - - mut fs := FlagSet.New() - - fs.AddVar[str](unsafe { (&str)(&opt) }, "opt", 0, "Optimization level") - fs.AddVar[str](unsafe { (&str)(&target) }, "target", 0, "Target system") - fs.AddVar[str](unsafe { (&str)(&Out) }, "out", 'o', "Output identifier") - fs.AddVar[bool](unsafe { (&bool)(&env::Shadowing) }, "shadowing", 0, "Allow shadowing") - fs.AddVar[bool](unsafe { (&bool)(&env::Transpilation) }, "transpile", 't', "Transpile code") - fs.AddVar[str](unsafe { (&str)(&env::Compiler) }, "compiler", 0, "Backend compiler") - fs.AddVar[str](unsafe { (&str)(&env::CompilerPath) }, "compiler-path", 0, "Path of backend compiler") - fs.AddVar[bool](unsafe { (&bool)(&env::Production) }, "production", 'p', "Compile for production") - fs.AddVar[bool](unsafe { (&bool)(&env::RC) }, "disable-rc", 0, "Disable reference counting") - fs.AddVar[bool](unsafe { (&bool)(&env::Safety) }, "disable-safety", 0, "Disable safety") - fs.AddVar[str](unsafe { (&str)(&env::CppStd) }, "cppstd", 0, "C++ standard") - fs.AddVar[bool](unsafe { (&bool)(&opt::Copy) }, "opt-copy", 0, "Copy optimization") - fs.AddVar[bool](unsafe { (&bool)(&opt::Deadcode) }, "opt-deadcode", 0, "Deadcode optimization") - fs.AddVar[bool](unsafe { (&bool)(&opt::Append) }, "opt-append", 0, "Append optimization") - fs.AddVar[bool](unsafe { (&bool)(&opt::Math) }, "opt-math", 0, "Math optimization") - fs.AddVar[bool](unsafe { (&bool)(&opt::Access) }, "opt-access", 0, "Access optimization") - fs.AddVar[bool](unsafe { (&bool)(&opt::Inline) }, "opt-inline", 0, "Inline optimization") - fs.AddVar[bool](unsafe { (&bool)(&opt::Ptr) }, "opt-ptr", 0, "Pointer optimizations") - fs.AddVar[bool](unsafe { (&bool)(&opt::Cond) }, "opt-cond", 0, "Conditional optimizations") - fs.AddVar[bool](unsafe { (&bool)(&opt::Str) }, "opt-str", 0, "String optimizations") - fs.AddVar[bool](unsafe { (&bool)(&opt::Slice) }, "opt-slice", 0, "Slice optimizations") - fs.AddVar[bool](unsafe { (&bool)(&opt::Assign) }, "opt-assign", 0, "Assignment optimizations") - fs.AddVar[bool](unsafe { (&bool)(&opt::Exceptional) }, "opt-exceptional", 0, "Exceptional optimizations") - fs.AddVar[bool](unsafe { (&bool)(&opt::Iter) }, "opt-iter", 0, "Iterations optimizations") - fs.AddVar[bool](unsafe { (&bool)(&opt::Dynamic) }, "opt-dynamic", 0, "Dynamic programming optimizations") - - mut content := fs.Parse(args) else { - Throw(str(error)) - use nil // Avoid error. - } - - checkCompilerFlag() - checkCppStdFlag() - checkTargetFlag(target) - checkOptFlag(opt) - - ret content + mut opt := "L0" + mut target := "native-native" + + mut fs := FlagSet.New() + + fs.AddVar[str](unsafe { (&str)(&opt) }, "opt", 0, "Optimization level") + fs.AddVar[str](unsafe { (&str)(&target) }, "target", 0, "Target system") + fs.AddVar[str](unsafe { (&str)(&Out) }, "out", 'o', "Output identifier") + fs.AddVar[bool](unsafe { (&bool)(&env::Shadowing) }, "shadowing", 0, "Allow shadowing") + fs.AddVar[bool](unsafe { (&bool)(&env::Transpilation) }, "transpile", 't', "Transpile code") + fs.AddVar[str](unsafe { (&str)(&env::Compiler) }, "compiler", 0, "Backend compiler") + fs.AddVar[str](unsafe { (&str)(&env::CompilerPath) }, "compiler-path", 0, "Path of backend compiler") + fs.AddVar[bool](unsafe { (&bool)(&env::Production) }, "production", 'p', "Compile for production") + fs.AddVar[bool](unsafe { (&bool)(&env::RC) }, "disable-rc", 0, "Disable reference counting") + fs.AddVar[bool](unsafe { (&bool)(&env::Safety) }, "disable-safety", 0, "Disable safety") + fs.AddVar[str](unsafe { (&str)(&env::CppStd) }, "cppstd", 0, "C++ standard") + fs.AddVar[bool](unsafe { (&bool)(&opt::Copy) }, "opt-copy", 0, "Copy optimization") + fs.AddVar[bool](unsafe { (&bool)(&opt::Deadcode) }, "opt-deadcode", 0, "Deadcode optimization") + fs.AddVar[bool](unsafe { (&bool)(&opt::Append) }, "opt-append", 0, "Append optimization") + fs.AddVar[bool](unsafe { (&bool)(&opt::Math) }, "opt-math", 0, "Math optimization") + fs.AddVar[bool](unsafe { (&bool)(&opt::Access) }, "opt-access", 0, "Access optimization") + fs.AddVar[bool](unsafe { (&bool)(&opt::Inline) }, "opt-inline", 0, "Inline optimization") + fs.AddVar[bool](unsafe { (&bool)(&opt::Ptr) }, "opt-ptr", 0, "Pointer optimizations") + fs.AddVar[bool](unsafe { (&bool)(&opt::Cond) }, "opt-cond", 0, "Conditional optimizations") + fs.AddVar[bool](unsafe { (&bool)(&opt::Str) }, "opt-str", 0, "String optimizations") + fs.AddVar[bool](unsafe { (&bool)(&opt::Slice) }, "opt-slice", 0, "Slice optimizations") + fs.AddVar[bool](unsafe { (&bool)(&opt::Assign) }, "opt-assign", 0, "Assignment optimizations") + fs.AddVar[bool](unsafe { (&bool)(&opt::Exceptional) }, "opt-exceptional", 0, "Exceptional optimizations") + fs.AddVar[bool](unsafe { (&bool)(&opt::Iter) }, "opt-iter", 0, "Iterations optimizations") + fs.AddVar[bool](unsafe { (&bool)(&opt::Dynamic) }, "opt-dynamic", 0, "Dynamic programming optimizations") + + mut content := fs.Parse(args) else { + Throw(str(error)) + use nil // Avoid error. + } + + checkCompilerFlag() + checkCppStdFlag() + checkTargetFlag(target) + checkOptFlag(opt) + + ret content } fn setupSemaFlags(mut &flags: SemaFlag) { - if env::Shadowing { - flags |= SemaFlag.Shadowing - } + if env::Shadowing { + flags |= SemaFlag.Shadowing + } } fn buildIr(&args: []str): &IR { - content := checkFlags(args) - - mut semaFlags := SemaFlag.Default - setupSemaFlags(semaFlags) - - if len(content) == 0 { - Throw(Logf(LogMsg.MissingCompilePath)) - } else if len(content) > 1 { - Throw("undefined content: " + content[1]) - } - mut path, ok := path::Abs(content[0]) - if !ok { - Throw("compile path could not processed because of a problem") - } - - // Check standard library. - inf := Status.Of(PathStdlib) else { - Throw(Logf(LogMsg.StdlibNotExist)) - ret nil // Avoid error. - } - if !inf.IsDir() { - Throw(Logf(LogMsg.StdlibNotExist)) - } - - mut ir, logs := IR.Build(path, semaFlags) - - if ir == nil && logs == nil { - Throw(Logf(LogMsg.NoFileInEntryPackage, path)) - } - - if logs != nil { - Logger.PrintLogs(logs) - Throw("") - } - - ret ir + content := checkFlags(args) + + mut semaFlags := SemaFlag.Default + setupSemaFlags(semaFlags) + + if len(content) == 0 { + Throw(Logf(LogMsg.MissingCompilePath)) + } else if len(content) > 1 { + Throw("undefined content: " + content[1]) + } + mut path, ok := path::Abs(content[0]) + if !ok { + Throw("compile path could not processed because of a problem") + } + + // Check standard library. + inf := Status.Of(PathStdlib) else { + Throw(Logf(LogMsg.StdlibNotExist)) + ret nil // Avoid error. + } + if !inf.IsDir() { + Throw(Logf(LogMsg.StdlibNotExist)) + } + + mut ir, logs := IR.Build(path, semaFlags) + + if ir == nil && logs == nil { + Throw(Logf(LogMsg.NoFileInEntryPackage, path)) + } + + if logs != nil { + Logger.PrintLogs(logs) + Throw("") + } + + ret ir } // Process compile command by "ARGS" global. fn compileCommand(mut &args: []str) { - args = args[1:] // Remove program path. - if args[0] == "test" { - env::Test = true - args = args[1:] - } - mut ir := buildIr(args) - - const Binded = false - - if !env::Test { - mut main := ir.Main.FindFn(EntryPoint, Binded) - if main == nil { - Throw(Logf(LogMsg.NoEntryPoint)) - } - } - - applyTargetIndependentOptimizations(ir) - - // See compiler reference (1) - ir.Order() - - compPath := getCompilePath() - compiler, compilerCmd := genCompileCmd(compPath, ir) - - mut oc := cxx::ObjectCoder.New(ir, cxx::SerializationInfo{ - Compiler: compiler, - CompilerCommand: compilerCmd, - }) - if env::Test { - mut tc := cxx::TestCoder.New(oc) - tc.Serialize() - } else { - oc.Serialize() - } - - mut file := openOutput(compPath) - file.Write(unsafe { oc.Buf.Buf() }) else { - Throw("object code could not write") - } - file.Close()! - - if !env::Transpilation { - compileIr(compiler, compilerCmd) - } + args = args[1:] // Remove program path. + if args[0] == "test" { + env::Test = true + args = args[1:] + } + mut ir := buildIr(args) + + const Binded = false + + if !env::Test { + mut main := ir.Main.FindFn(EntryPoint, Binded) + if main == nil { + Throw(Logf(LogMsg.NoEntryPoint)) + } + } + + applyTargetIndependentOptimizations(ir) + + // See compiler reference (1) + ir.Order() + + compPath := getCompilePath() + compiler, compilerCmd := genCompileCmd(compPath, ir) + + mut oc := cxx::ObjectCoder.New(ir, cxx::SerializationInfo{ + Compiler: compiler, + CompilerCommand: compilerCmd, + }) + if env::Test { + mut tc := cxx::TestCoder.New(oc) + tc.Serialize() + } else { + oc.Serialize() + } + + mut file := openOutput(compPath) + file.Write(unsafe { oc.Buf.Buf() }) else { + Throw("object code could not write") + } + file.Close()! + + if !env::Transpilation { + compileIr(compiler, compilerCmd) + } } \ No newline at end of file diff --git a/src/julec/handle/ansi.jule b/src/julec/handle/ansi.jule index ebb31fdf7..d12f67686 100644 --- a/src/julec/handle/ansi.jule +++ b/src/julec/handle/ansi.jule @@ -4,21 +4,21 @@ struct AnsiEscape {} impl AnsiEscape { - const ResetSeq = "\033[0m" - const BoldSeq = "\u001b[1m" - const RedSeq = "\033[31m" - const BrightMagentaSeq = "\033[95m" + const ResetSeq = "\033[0m" + const BoldSeq = "\u001b[1m" + const RedSeq = "\033[31m" + const BrightMagentaSeq = "\033[95m" - // Reset all ANSI formatting. - static fn Reset() { - out(AnsiEscape.ResetSeq) - } + // Reset all ANSI formatting. + static fn Reset() { + out(AnsiEscape.ResetSeq) + } - // Print with ANSI sequence. - // Resets ANSI after print. - static fn Print(escape: str, text: str) { - out(escape) - out(text) - AnsiEscape.Reset() - } + // Print with ANSI sequence. + // Resets ANSI after print. + static fn Print(escape: str, text: str) { + out(escape) + out(text) + AnsiEscape.Reset() + } } \ No newline at end of file diff --git a/src/julec/handle/logger.jule b/src/julec/handle/logger.jule index aca903cca..fa43026fe 100644 --- a/src/julec/handle/logger.jule +++ b/src/julec/handle/logger.jule @@ -10,73 +10,73 @@ use strings for std::strings struct Logger {} impl Logger { - // Prints flag log. - static fn LogFlat(&l: Log) { - outln(l.Text) - } + // Prints flag log. + static fn LogFlat(&l: Log) { + outln(l.Text) + } - // Prints error log. - static fn LogError(&l: Log) { - out(AnsiEscape.RedSeq) - out("error: ") - out(l.Text) - AnsiEscape.Reset() + // Prints error log. + static fn LogError(&l: Log) { + out(AnsiEscape.RedSeq) + out("error: ") + out(l.Text) + AnsiEscape.Reset() - if len(l.Path) != 0 { - out("\n --> ") - out(l.Path) - } - if l.Row != 0 && l.Column != 0 { - out(":") - out(conv::Itoa(l.Row)) - out(":") - out(conv::Itoa(l.Column)) - } - if len(l.Line) != 0 { - // For correct handling, trim leading and trailing space bytes. - // Also replace tabs with spaces for deterministic size. - mut line := strings::Trim(l.Line, "\r\n\v\b\t ") - line = strings::Replace(line, "\t", " ", -1) + if len(l.Path) != 0 { + out("\n --> ") + out(l.Path) + } + if l.Row != 0 && l.Column != 0 { + out(":") + out(conv::Itoa(l.Row)) + out(":") + out(conv::Itoa(l.Column)) + } + if len(l.Line) != 0 { + // For correct handling, trim leading and trailing space bytes. + // Also replace tabs with spaces for deterministic size. + mut line := strings::Trim(l.Line, "\r\n\v\b\t ") + line = strings::Replace(line, "\t", " ", -1) - mut offset := len(l.Line) - len(line) + 1 - out("\n ") - row := conv::Itoa(l.Row) - out(row) - out(" | ") - out(line) - out("\n ") - out(strings::Repeat(" ", len(row))) - out(" | ") - out(strings::Repeat(" ", l.Column - offset)) - out("^") - if len(l.Suggestion) != 0 { - out("\n ") - out(strings::Repeat(" ", len(row))) - out(" | ") - AnsiEscape.Print(AnsiEscape.BrightMagentaSeq, "suggestion: ") - out(l.Suggestion) - } - } - outln("\n") - } + mut offset := len(l.Line) - len(line) + 1 + out("\n ") + row := conv::Itoa(l.Row) + out(row) + out(" | ") + out(line) + out("\n ") + out(strings::Repeat(" ", len(row))) + out(" | ") + out(strings::Repeat(" ", l.Column - offset)) + out("^") + if len(l.Suggestion) != 0 { + out("\n ") + out(strings::Repeat(" ", len(row))) + out(" | ") + AnsiEscape.Print(AnsiEscape.BrightMagentaSeq, "suggestion: ") + out(l.Suggestion) + } + } + outln("\n") + } - // Log. - static fn Log(&l: Log) { - match l.Kind { - | LogKind.Flat: - Logger.LogFlat(l) - | LogKind.Error: - Logger.LogError(l) - } - } + // Log. + static fn Log(&l: Log) { + match l.Kind { + | LogKind.Flat: + Logger.LogFlat(l) + | LogKind.Error: + Logger.LogError(l) + } + } - // Prints all logs. - static fn PrintLogs(&logs: []Log) { - for _, l in logs { - Logger.Log(l) - } - out("=== ") - out(conv::Itoa(len(logs))) - outln(" error generated ===") - } + // Prints all logs. + static fn PrintLogs(&logs: []Log) { + for _, l in logs { + Logger.Log(l) + } + out("=== ") + out(conv::Itoa(len(logs))) + outln(" error generated ===") + } } \ No newline at end of file diff --git a/src/julec/handle/throw.jule b/src/julec/handle/throw.jule index 9e2a2e0ab..7530f2576 100644 --- a/src/julec/handle/throw.jule +++ b/src/julec/handle/throw.jule @@ -7,6 +7,6 @@ use process for std::process const ErrorExitCode = 1 fn Throw(msg: str) { - outln(msg) - process::Exit(ErrorExitCode) + outln(msg) + process::Exit(ErrorExitCode) } \ No newline at end of file diff --git a/src/julec/main.jule b/src/julec/main.jule index 9751a409f..29ae604a4 100644 --- a/src/julec/main.jule +++ b/src/julec/main.jule @@ -20,158 +20,158 @@ const CmdMod = "mod" // Map for "julec help" command. static HelpMap: [...][2]str = [ - [CmdHelp, "Show help"], - [CmdVersion, "Show version"], - [CmdTool, "Tools for effective Jule"], - [CmdJulenv, "Show information about native jule environment"], - [CmdMod, "Module management"], + [CmdHelp, "Show help"], + [CmdVersion, "Show version"], + [CmdTool, "Tools for effective Jule"], + [CmdJulenv, "Show information about native jule environment"], + [CmdMod, "Module management"], ] fn printErrorMessage(msg: str) { - outln(msg) + outln(msg) } // Command: julec help fn help(&args: []str) { - if len(args) > 2 { - printErrorMessage("invalid command: " + args[2]) - ret - } - - mut max := len(HelpMap[0][0]) - for _, k in HelpMap { - n := len(k[0]) - if n > max { - max = n - } - } - - mut s := StrBuilder.New(1 << 5) - const Space = 5 // Space of between command name and description. - for i, part in HelpMap { - s.WriteStr(part[0]) - s.WriteStr(strings::Repeat(" ", (max - len(part[0])) + Space)) - s.WriteStr(part[1]) - if i+1 < len(HelpMap) { - s.WriteByte('\n') - } - } - outln(s) + if len(args) > 2 { + printErrorMessage("invalid command: " + args[2]) + ret + } + + mut max := len(HelpMap[0][0]) + for _, k in HelpMap { + n := len(k[0]) + if n > max { + max = n + } + } + + mut s := StrBuilder.New(1 << 5) + const Space = 5 // Space of between command name and description. + for i, part in HelpMap { + s.WriteStr(part[0]) + s.WriteStr(strings::Repeat(" ", (max - len(part[0])) + Space)) + s.WriteStr(part[1]) + if i+1 < len(HelpMap) { + s.WriteByte('\n') + } + } + outln(s) } // Command: julec version fn version(&args: []str) { - if len(args) > 2 { - printErrorMessage("invalid command: " + args[2]) - ret - } - outln(jule::Version) + if len(args) > 2 { + printErrorMessage("invalid command: " + args[2]) + ret + } + outln(jule::Version) } // Command: julec tool distos fn toolDistos() { - out("supported operating systems:\n ") - out(build::DistOs.Windows) - out(" ") - out(build::DistOs.Linux) - out(" ") - out(build::DistOs.Darwin) - outln("") + out("supported operating systems:\n ") + out(build::DistOs.Windows) + out(" ") + out(build::DistOs.Linux) + out(" ") + out(build::DistOs.Darwin) + outln("") } // Command: julec tool distarch fn toolDistarch() { - out("supported architects:\n ") - out(build::DistArch.Amd64) - out(" ") - out(build::DistArch.I386) - out(" ") - out(build::DistArch.Arm64) - outln("") + out("supported architects:\n ") + out(build::DistArch.Amd64) + out(" ") + out(build::DistArch.I386) + out(" ") + out(build::DistArch.Arm64) + outln("") } // Command: julec tool fn tool(&args: []str) { - if len(args) == 2 { - outln(`tool commands: + if len(args) == 2 { + outln(`tool commands: distos Lists all supported operating systems distarch Lists all supported architects`) - ret - } else if len(args) > 3 { - printErrorMessage("invalid command: " + args[3]) - ret - } - - cmd := args[2] - match cmd { - | "distos": - toolDistos() - | "distarch": - toolDistarch() - |: - printErrorMessage("undefined command: " + cmd) - } + ret + } else if len(args) > 3 { + printErrorMessage("invalid command: " + args[3]) + ret + } + + cmd := args[2] + match cmd { + | "distos": + toolDistos() + | "distarch": + toolDistarch() + |: + printErrorMessage("undefined command: " + cmd) + } } // Command: julec julenv fn julenv(&args: []str) { - if len(args) > 2 { - printErrorMessage("invalid command: " + args[2]) - ret - } - outln("julec version: " + jule::Version) - outln("architecture: " + std::env::Arch) - outln("operating system: " + std::env::Os) - outln("default compiler: " + env::Compiler) - outln("default C++ standard: " + env::CppStd) + if len(args) > 2 { + printErrorMessage("invalid command: " + args[2]) + ret + } + outln("julec version: " + jule::Version) + outln("architecture: " + std::env::Arch) + outln("operating system: " + std::env::Os) + outln("default compiler: " + env::Compiler) + outln("default C++ standard: " + env::CppStd) } // Command: julec mod fn mod(&args: []str) { - if len(args) == 2 { - outln("command is not given, try julec mod init") - ret - } - - if len(args) > 3 { - printErrorMessage("invalid command: " + args[3]) - ret - } - - match args[2] { - | "init": // julec mod init - File.Write(build::ModuleFile, [], 0o660) else { - printErrorMessage("module could not generated because of a problem") - } - |: - printErrorMessage("invalid command: " + args[2]) - } + if len(args) == 2 { + outln("command is not given, try julec mod init") + ret + } + + if len(args) > 3 { + printErrorMessage("invalid command: " + args[3]) + ret + } + + match args[2] { + | "init": // julec mod init + File.Write(build::ModuleFile, [], 0o660) else { + printErrorMessage("module could not generated because of a problem") + } + |: + printErrorMessage("invalid command: " + args[2]) + } } // Try to process compiler commands. // Reports whether "ARGS" is command and processed. fn processCommand(&args: []str): bool { - match args[1] { - | CmdHelp: - help(args) - | CmdVersion: - version(args) - | CmdTool: - tool(args) - | CmdJulenv: - julenv(args) - | CmdMod: - mod(args) - |: - ret false - } - - ret true + match args[1] { + | CmdHelp: + help(args) + | CmdVersion: + version(args) + | CmdTool: + tool(args) + | CmdJulenv: + julenv(args) + | CmdMod: + mod(args) + |: + ret false + } + + ret true } fn showInfo() { - outln( - `JuleC is a tool for Jule source code and developers. + outln( + `JuleC is a tool for Jule source code and developers. Commands: help Show help @@ -186,18 +186,18 @@ Compilation: } fn main() { - mut args := std::env::Args() + mut args := std::env::Args() - // Not started with arguments. - // Here is "2" but "args" always have one element for store program name. - if len(args) < 2 { - showInfo() - ret - } + // Not started with arguments. + // Here is "2" but "args" always have one element for store program name. + if len(args) < 2 { + showInfo() + ret + } - if processCommand(args) { - ret - } + if processCommand(args) { + ret + } - compileCommand(args) + compileCommand(args) } \ No newline at end of file diff --git a/src/julec/obj/cxx/expr.jule b/src/julec/obj/cxx/expr.jule index 5d2321d53..0eac6033a 100644 --- a/src/julec/obj/cxx/expr.jule +++ b/src/julec/obj/cxx/expr.jule @@ -5,15 +5,15 @@ use obj use env use opt::{ - RefExprModel, - UnsafeBinaryExprModel, - UnsafeIndexingExprModel, - PushToSliceExprModel, - AppendToSliceExprModel, - StrCompExprModel, - EmptyCompareExprModel, - UnsafeDerefExprModel, - UnsafeCastingExprModel, + RefExprModel, + UnsafeBinaryExprModel, + UnsafeIndexingExprModel, + PushToSliceExprModel, + AppendToSliceExprModel, + StrCompExprModel, + EmptyCompareExprModel, + UnsafeDerefExprModel, + UnsafeCastingExprModel, } use conv for std::conv use std::env::{Arch} @@ -22,60 +22,60 @@ use std::jule::build::{Directive, Is64Bit} use std::jule::constant::{Const} use std::jule::lex::{Token, TokenId, TokenKind} use std::jule::sema::{ - Trait, - Var, - FnIns, - StructIns, - TypeKind, - Data, - Value, - ExprModel, - BinaryExprModel, - UnaryExprModel, - StructLitExprModel, - AllocStructLitExprModel, - CastingExprModel, - Stmt, - FnCallExprModel, - SliceExprModel, - IndexingExprModel, - AnonFnExprModel, - MapExprModel, - SlicingExprModel, - TraitSubIdentExprModel, - StructSubIdentExprModel, - ArrayExprModel, - TupleExprModel, - BuiltinOutCallExprModel, - BuiltinOutlnCallExprModel, - BuiltinNewCallExprModel, - BuiltinPanicCallExprModel, - BuiltinAssertCallExprModel, - BuiltinMakeCallExprModel, - BuiltinAppendCallExprModel, - BuiltinErrorCallExprModel, - BuiltinCopyCallExprModel, - BuiltinLenCallExprModel, - BuiltinCapCallExprModel, - BuiltinDeleteCallExprModel, - SizeofExprModel, - AlignofExprModel, - RuneExprModel, - StructStaticIdentExprModel, - IntegratedToStrExprModel, - BackendEmitExprModel, - FreeExprModel, - OperandExprModel, - Scope, + Trait, + Var, + FnIns, + StructIns, + TypeKind, + Data, + Value, + ExprModel, + BinaryExprModel, + UnaryExprModel, + StructLitExprModel, + AllocStructLitExprModel, + CastingExprModel, + Stmt, + FnCallExprModel, + SliceExprModel, + IndexingExprModel, + AnonFnExprModel, + MapExprModel, + SlicingExprModel, + TraitSubIdentExprModel, + StructSubIdentExprModel, + ArrayExprModel, + TupleExprModel, + BuiltinOutCallExprModel, + BuiltinOutlnCallExprModel, + BuiltinNewCallExprModel, + BuiltinPanicCallExprModel, + BuiltinAssertCallExprModel, + BuiltinMakeCallExprModel, + BuiltinAppendCallExprModel, + BuiltinErrorCallExprModel, + BuiltinCopyCallExprModel, + BuiltinLenCallExprModel, + BuiltinCapCallExprModel, + BuiltinDeleteCallExprModel, + SizeofExprModel, + AlignofExprModel, + RuneExprModel, + StructStaticIdentExprModel, + IntegratedToStrExprModel, + BackendEmitExprModel, + FreeExprModel, + OperandExprModel, + Scope, } use types for std::jule::types::{ - MaxF32, - MaxF64, - MinF32, - MinF64, - MaxI64, - MinI64, - MaxU64, + MaxF32, + MaxF64, + MinF32, + MinF64, + MaxI64, + MinI64, + MaxU64, } use math for std::math use strings for std::strings::{StrBuilder} @@ -91,1599 +91,1599 @@ type PrimKind: types::TypeKind // Common group of semantic analysis expression model types and optimizer specific types. enum compExprModel: type { - ExprModel: ExprModel, - str, // For built-in expressions. - &UnsafeBinaryExprModel, - &UnsafeIndexingExprModel, - &StrCompExprModel, - &RefExprModel, - &EmptyCompareExprModel, - &UnsafeDerefExprModel, - &UnsafeCastingExprModel, + ExprModel: ExprModel, + str, // For built-in expressions. + &UnsafeBinaryExprModel, + &UnsafeIndexingExprModel, + &StrCompExprModel, + &RefExprModel, + &EmptyCompareExprModel, + &UnsafeDerefExprModel, + &UnsafeCastingExprModel, } struct exprCoder { - oc: &ObjectCoder + oc: &ObjectCoder - // It will executed before common variable handling algorithm. - // If it returns true, common algorithm will not be executed. - varPrefixes: []fn(mut v: &Var): bool + // It will executed before common variable handling algorithm. + // If it returns true, common algorithm will not be executed. + varPrefixes: []fn(mut v: &Var): bool } impl exprCoder { - static fn new(mut &oc: &ObjectCoder): &exprCoder { - ret &exprCoder{ - oc: oc, - } - } - - fn string(mut &self, &c: &Const) { - content := c.ReadStr() - if len(content) == 0 { // Empty. - self.oc.write(typeCoder.Str + "()") - ret - } - len := conv::FmtInt(i64(len(content)), 10) - self.oc.write(typeCoder.Str) - self.oc.write("::lit(") - cstrLit(self.oc.Buf, content) - self.oc.write(", ") - self.oc.write(len) - self.oc.write(")") - } - - fn boolean(mut &self, b: bool) { - if b { - self.oc.write("true") - } else { - self.oc.write("false") - } - } - - fn nilLit(mut &self) { - self.oc.write("nullptr") - } - - fn ftoaSpecialCases(mut &self, &x: f64): bool { - match { - | math::IsNaN(x): - self.oc.write("NAN") - | math::IsInf(x, 1): - self.oc.write("INFINITY") - | math::IsInf(x, -1): - self.oc.write("-INFINITY") - |: - ret false - } - ret true - } - - fn float32(mut &self, &c: &Const) { - x := c.AsF64() - - // Special cases. - if self.ftoaSpecialCases(x) { - ret - } - - match { - | x == MaxF32: - self.oc.write("jule::MAX_F32") - | x == MinF32: - self.oc.write("jule::MIN_F32") - |: - ftoa(self.oc.Buf, x, 1 << 5) - self.oc.write("f") - } - } - - fn float64(mut &self, &c: &Const) { - x := c.AsF64() - - // Special cases. - if self.ftoaSpecialCases(x) { - ret - } - - match { - | x == MaxF64: - self.oc.write("jule::MAX_F64") - | x == MinF64: - self.oc.write("jule::MIN_F64") - |: - ftoa(self.oc.Buf, x, 1 << 6) - } - } - - fn constant(mut &self, mut c: &Const) { - match { - | c.IsStr(): - self.string(c) - | c.IsBool(): - self.boolean(c.ReadBool()) - | c.IsF64(): - match { - | c.Kind == PrimKind.F32: - self.float32(c) - |: - self.float64(c) - } - | c.IsI64(): - itoa(self.oc.Buf, c.ReadI64()) - | c.IsU64(): - utoa(self.oc.Buf, c.ReadU64()) - | c.IsNil(): - self.nilLit() - |: - self.oc.write("") - } - } - - fn divByZeroBinary(mut &self, &op: &Token, mut &l: &OperandExprModel, mut &r: &OperandExprModel) { - self.oc.write("jule::") - match op.Id { - | TokenId.Solidus - | TokenId.SolidusEq: - self.oc.write("div(") - | TokenId.Percent - | TokenId.PercentEq: - self.oc.write("mod(") - } - - if !env::Production { - self.oc.write("\"") - self.oc.locInfo(op) - self.oc.write("\",") - } - self.possibleRefExpr(l.Model) - self.oc.write(",") - self.possibleRefExpr(r.Model) - self.oc.write(")") - } - - fn unsafeBinary(mut &self, mut m: &BinaryExprModel) { - if m.Op.Id == TokenId.Eqs || m.Op.Id == TokenId.NotEq { - // If this binary operator comparing type. - // The m.Left is will be one always. - if obj::IsAny(m.Left.Kind) { - if !m.Right.Kind.IsNil() && !obj::IsAny(m.Right.Kind) { - self.oc.write("(") - if m.Op.Id == TokenId.NotEq { - self.oc.write("!") - } - i := self.oc.pushAnyType(m.Right.Kind) - self.oc.write(anyTypeIdent) - self.oc.write(conv::Itoa(i)) - self.oc.write("_compare(") - self.possibleRefExpr(m.Left.Model) - self.oc.write(", ") - self.possibleRefExpr(m.Right.Model) - self.oc.write("))") - ret - } - } - } - self.oc.write("(") - self.possibleRefExpr(m.Left.Model) - self.oc.write(" ") - self.oc.write(m.Op.Kind) - self.oc.write(" ") - self.possibleRefExpr(m.Right.Model) - self.oc.write(")") - } - - fn binary(mut &self, mut m: &BinaryExprModel) { - match m.Op.Id { - | TokenId.Solidus | TokenId.Percent: - // Do not check division of structures safety. - if m.Left.Kind.Struct() == nil { - self.divByZeroBinary(m.Op, m.Left, m.Right) - ret - } - } - self.unsafeBinary(m) - } - - fn var(mut &self, mut m: &Var) { - for _, prefix in self.varPrefixes { - if prefix(m) { - ret - } - } - if m.Binded { - d := obj::FindDirective(m.Directives, Directive.Namespace) - if d != nil { - self.oc.writeBytes(concatAllParts(d.Args...)) - self.oc.write("::") - } - } - identCoder.var(self.oc.Buf, m) - } - - fn structureIns(mut &self, mut m: &StructIns) { - self.oc.tc.structureIns(self.oc.Buf, m) - } - - fn unary(mut &self, mut m: &UnaryExprModel) { - match m.Op.Id { - | TokenId.Caret: - self.oc.write("(~(") - self.possibleRefExpr(m.Expr.Model) - self.oc.write("))") - ret - | TokenId.Star: - if env::Production || m.Expr.Kind.Sptr() == nil { - break - } - self.possibleRefExpr(m.Expr.Model) - self.oc.write(".get(\"") - self.oc.locInfo(m.Op) - self.oc.write("\")") - ret - } - self.oc.write("(") - self.oc.write(m.Op.Kind) - self.oc.write("(") - self.possibleRefExpr(m.Expr.Model) - self.oc.write("))") - } - - fn structureLit(mut &self, mut m: &StructLitExprModel) { - if m.Strct.Decl.Binded { - self.oc.write("(") - } - self.oc.tc.structureIns(self.oc.Buf, m.Strct) - if m.Strct.Decl.Binded { - self.oc.write(")") - } - self.oc.write("{") - if len(m.Args) > 0 { - // Fields are should be in order. - // In other words, GCC will produce error(s). - iter: - for i, f in m.Strct.Fields { - for (_, mut arg) in m.Args { - if arg.Field == f { - self.oc.write(".") - identCoder.field(self.oc.Buf, arg.Field.Decl) - self.oc.write("=") - self.possibleRefExpr(arg.Expr.Model) - if len(m.Strct.Fields)-i > 1 { - self.oc.write(", ") - } - continue iter - } - } - } - } - self.oc.write("}") - } - - fn allocStructure(mut &self, mut m: &AllocStructLitExprModel) { - self.oc.write("jule::new_ptr<") - identCoder.structureIns(self.oc.Buf, m.Lit.Strct) - self.oc.write(">(") - self.structureLit(m.Lit) - self.oc.write(")") - } - - fn possibleRefExpr(mut &self, expr: compExprModel) { - match type expr { - | &Var: - v := (&Var)(expr) - if v.Reference { - self.oc.write("(*(") - self.model(expr) - self.oc.write("))") - ret - } - } - self.model(expr) - } - - fn castTraitFromTrait(mut &self, mut &m: &CastingExprModel, mut t1: &Trait, mut t2: &Trait) { - self.possibleRefExpr(m.Expr.Model) - self.oc.write(".map(") - self.oc.pushAndWriteMaskMapper(t1, t2) - self.oc.write(")") - } - - // Casting expression. - // - // Special cases: - // - The any type castings should be came first than others. - // Otherwise, code generation might be wrong because the - // uses special casting algorithms. - fn casting(mut &self, mut m: &CastingExprModel) { - match { - | obj::IsAny(m.Kind): - if m.ExprKind.IsNil() { - self.oc.write(typeCoder.Any + "()") - ret - } - if m.ExprKind.TypeEnum() != nil { - self.possibleRefExpr(m.Expr.Model) - ret - } - i := self.oc.pushAnyType(m.ExprKind) - self.oc.write(typeCoder.Any + "(") - match type m.Expr.Model { - | &Const: - prim := m.ExprKind.Prim() - if prim != nil && types::IsInt(prim.Kind) { - self.oc.write("static_cast<") - self.oc.tc.prim(self.oc.Buf, prim) - self.oc.write(">(") - self.possibleRefExpr(m.Expr.Model) - self.oc.write(")") - break - } - fall - |: - self.possibleRefExpr(m.Expr.Model) - } - self.oc.write(", &" + anyTypeIdent) - self.oc.write(conv::Itoa(i)) - self.oc.write(")") - ret - | obj::IsAny(m.ExprKind): - self.possibleRefExpr(m.Expr.Model) - self.oc.write(".") - if m.Kind.Sptr() != nil { - self.oc.write("cast_ptr<") - self.oc.tc.kind(self.oc.Buf, m.Kind.Sptr().Elem) - } else { - self.oc.write("cast<") - self.oc.tc.kind(self.oc.Buf, m.Kind) - } - self.oc.write(">(") - if !env::Production { - self.oc.write("\"") - self.oc.locInfo(m.Token) - self.oc.write("\", ") - } - self.oc.write("&" + anyTypeIdent) - self.oc.write(conv::Itoa(self.oc.pushAnyType(m.Kind))) - self.oc.write(")") - ret - | m.ExprKind.Ptr() != nil - | m.Kind.Ptr() != nil: - self.oc.write("((") - self.oc.tc.kind(self.oc.Buf, m.Kind) - self.oc.write(")(") - self.possibleRefExpr(m.Expr.Model) - self.oc.write("))") - ret - | m.ExprKind.Trait() != nil: - if m.Kind.Trait() != nil { - self.castTraitFromTrait(m, m.Kind.Trait(), m.ExprKind.Trait()) - ret - } - self.possibleRefExpr(m.Expr.Model) - self.oc.write(".") - if m.Kind.Sptr() != nil { - self.oc.write("cast_ptr<") - self.oc.tc.kind(self.oc.Buf, m.Kind.Sptr().Elem) - } else { - self.oc.write("cast<") - self.oc.tc.kind(self.oc.Buf, m.Kind) - } - self.oc.write(">(") - if !env::Production { - self.oc.write("\"") - self.oc.locInfo(m.Token) - self.oc.write("\", ") - } - self.oc.write("(" + typeCoder.Trait + "::Type*)&") - identCoder.traitDecl(self.oc.Buf, m.ExprKind.Trait()) - self.oc.write("_mptr_data") - self.oc.write(conv::Itoa(obj::FindTraitTypeOffset(m.ExprKind.Trait(), m.Kind))) - self.oc.write(")") - ret - | m.Kind.Trait() != nil: - self.oc.tc.kind(self.oc.Buf, m.Kind) - self.oc.write("(") - self.possibleRefExpr(m.Expr.Model) - self.oc.write(", (" + typeCoder.Trait + "::Type*)&") - identCoder.traitDecl(self.oc.Buf, m.Kind.Trait()) - self.oc.write("_mptr_data") - self.oc.write(conv::Itoa(obj::FindTraitTypeOffset(m.Kind.Trait(), m.ExprKind))) - self.oc.write(")") - ret - } - prim := m.Kind.Prim() - eprim := m.ExprKind.Prim() - if eprim != nil && prim != nil && prim.IsStr() { - if eprim.IsU8() { - self.oc.write(typeCoder.Str + "::from_byte(") - } else { - self.oc.write(typeCoder.Str + "::from_rune(") - } - self.possibleRefExpr(m.Expr.Model) - self.oc.write(")") - ret - } - self.oc.write("static_cast<") - self.oc.tc.kind(self.oc.Buf, m.Kind) - self.oc.write(">(") - self.possibleRefExpr(m.Expr.Model) - self.oc.write(")") - } - - fn models(mut &self, mut args: []ExprModel) { - if len(args) == 0 { - ret - } - for (i, mut a) in args { - self.possibleRefExpr(a) - if len(args)-i > 1 { - self.oc.write(",") - } - } - } - - fn args(mut &self, mut &m: &FnCallExprModel) { - mut j := 0 - if m.Func.Owner != nil && !m.Func.Decl.Statically || - len(m.Func.Params) > 0 && m.Func.Params[0].Decl.IsSelf() { - j++ // Skip receiver parameter. - } - for i, arg in m.Args { - p := m.Func.Params[j] - if p.Decl != nil && p.Decl.Reference { - match type arg { - | &Var: - v := (&Var)(arg) - if v.Reference { - self.model(arg) - goto end - } - } - self.oc.write("&(") - self.model(arg) - self.oc.write(")") - goto end - } - self.possibleRefExpr(arg) - end: - if len(m.Args)-i > 1 { - self.oc.write(", ") - } - j++ - } - } - - fn modelForCall(mut &self, mut expr: compExprModel) { - match type expr { - | &FnIns: - self.funcIns((&FnIns)(expr)) - ret - | &StructSubIdentExprModel: - mut ssie := (&StructSubIdentExprModel)(expr) - if ssie.Method != nil { - self.funcIns(ssie.Method) - ret - } - } - self.possibleRefExpr(expr) - } - - fn pushCallInf(mut &self, &m: &FnCallExprModel) { - if env::Production || !m.Func.Anon { - self.oc.write("(") - ret - } - if m.Func.Anon { - match type m.Expr { - | &StructSubIdentExprModel: - if (&StructSubIdentExprModel)(m.Expr).Field.Decl.Owner.Binded { - self.oc.write("(") - ret - } - } - self.oc.write(".call") - } - self.oc.write("(\"") - self.oc.locInfo(m.Token) - self.oc.write("\"") - if len(m.Args) != 0 { - self.oc.write(", ") - } - } - - fn isWrapped(mut &self, mut &m: &FnCallExprModel): bool { - if !m.Func.IsBuiltin() && len(m.Func.Decl.Params) > 0 && m.Func.Decl.Params[0].IsSelf() { - match type m.Expr { - | &StructSubIdentExprModel: - mut ssie := (&StructSubIdentExprModel)(m.Expr) - match { - | m.Func.Decl.Params[0].IsRef() - | ssie.Expr.Kind.Sptr() != nil: - break - |: - if ssie.Expr.Kind.Struct() != nil { - if !ssie.Expr.Lvalue { - self.oc.write("({ auto _wrap_copy = ") - self.model(ssie.Expr.Model) - self.oc.write("; ") - ret true - } - } - } - } - } - ret false - } - - fn writeReceiver(mut &self, mut m: compExprModel): (safeDeref: bool) { - match type m { - | &UnaryExprModel: - self.possibleRefExpr((&UnaryExprModel)(m).Expr.Model) - ret true - | &UnsafeDerefExprModel: - self.possibleRefExpr((&UnsafeDerefExprModel)(m).Base.Expr.Model) - ret false - |: - panic("implementation mistake, this panic call should be unreachable") - } - } - - fn pureFuncCall(mut &self, mut &m: &FnCallExprModel) { - wrapped := self.isWrapped(m) - self.modelForCall(m.Expr) - if !m.Func.IsBuiltin() { - if m.Func.Decl.Binded && len(m.Func.Generics) > 0 { - if !obj::HasDirective(m.Func.Decl.Directives, Directive.Cdef) { - self.oc.write("<") - for (i, mut g) in m.Func.Generics { - self.oc.tc.kind(self.oc.Buf, g.Kind) - if len(m.Func.Generics)-i > 1 { - self.oc.write(", ") - } - } - self.oc.write(">") - } - } - } - self.pushCallInf(m) - if m.Func.AsAnon && !m.Func.Anon { - // Function used as anonymous. - // So pass nullptr to ctx parameter. - // Do not pass nullptr if function is anonymous, - // beacause it stores ctx data internally and it will pass. - self.oc.write("nullptr") - if len(m.Args) > 0 { - self.oc.write(", ") - } - } - if !m.Func.IsBuiltin() && len(m.Func.Decl.Params) > 0 && m.Func.Decl.Params[0].IsSelf() { - match type m.Expr { - | &StructSubIdentExprModel: - mut ssie := (&StructSubIdentExprModel)(m.Expr) - match { - | m.Func.Decl.Params[0].IsRef(): - // Ignore dereferencing, use data directly to call method. - _ = self.writeReceiver(ssie.Expr.Model) - | ssie.Expr.Kind.Sptr() != nil: - // Ignore dereferencing, use data directly to call [ptr] method. - safe := self.writeReceiver(ssie.Expr.Model) - if safe { - self.oc.write(".ptr(") - if !env::Production { - self.oc.write("\"") - self.oc.locInfo(m.Token) - self.oc.write("\"") - } - self.oc.write(")") - } - |: - if ssie.Expr.Kind.Struct() != nil { - match type ssie.Expr.Model { - | &Var: - v := (&Var)(ssie.Expr.Model) - if v.Reference { - break - } - fall - |: - // Add address taking operation for non-pointers. - self.oc.write("&") - } - } - if wrapped { - self.oc.write("_wrap_copy") - } else if ssie.Expr.Kind.Ptr() == nil { - self.model(ssie.Expr.Model) - } else { - // Ignore dereferencing, use data directly to call method. - self.possibleRefExpr((&UnaryExprModel)(ssie.Expr.Model).Expr.Model) - } - } - if len(m.Args) > 0 { - self.oc.write(", ") - } - | &TraitSubIdentExprModel: - self.possibleRefExpr((&TraitSubIdentExprModel)(m.Expr).Expr) - self.oc.write(".data") - if len(m.Args) > 0 { - self.oc.write(", ") - } - } - } - self.args(m) - self.oc.write(")") - - if wrapped { - self.oc.write("; })") - } - } - - fn coFuncCall(mut &self, mut &m: &FnCallExprModel) { - self.oc.write("{\n") - self.oc.addIndent() - mut head := StrBuilder.New(1 << 5) - head.WriteStr("std::thread([") - if m.Func.Owner != nil { - head.WriteStr(identCoder.Self) - if len(m.Args) > 0 { - head.WriteStr(", ") - } - } - for i, arg in m.Args { - if i > 0 { - head.WriteStr(", ") - } - match type arg { - | &Var: - mut v := (&Var)(arg) - identCoder.var(head, v) - continue - } - name := "_co_arg_" + conv::Itoa(i) - head.WriteStr(name) - self.oc.indent() - self.oc.tc.kind(self.oc.Buf, m.Func.Params[i].Kind) - self.oc.write(" ") - if m.Func.Params[i].Decl.Reference { - self.oc.write("&") - } - self.oc.write(name) - self.oc.write(" = ") - self.possibleRefExpr(arg) - self.oc.write(";\n") - argS := any(name) - m.Args[i] = unsafe { *(*ExprModel)(&argS) } - } - self.oc.indent() - self.oc.Buf.Write(unsafe { head.Buf() }) - self.oc.write("](void) mutable -> void {\n") - self.oc.addIndent() - self.oc.indent() - self.pureFuncCall(m) - self.oc.write(";\n") - self.oc.doneIndent() - self.oc.indent() - self.oc.write("}).detach();\n") - self.oc.doneIndent() - self.oc.indent() - self.oc.write("}") - } - - fn writeUseExpr(mut &self, mut &f: &FnIns, mut d: &Data) { - if d.Kind.Tup() == nil { - self.possibleRefExpr(d.Model) - self.oc.write(";") - ret - } - mut tup := (&TupleExprModel)(d.Model) - self.oc.tc.rc.tup(self.oc.Buf, f.Result.Tup()) - self.oc.write("{") - for i, data in tup.Datas { - self.oc.write("." + resultArgName) - self.oc.write(conv::Itoa(i)) - self.oc.write("=") - self.possibleRefExpr(data.Model) - if len(tup.Datas)-i > 1 { - self.oc.write(", ") - } - } - self.oc.write("};") - } - - fn funcCall(mut &self, mut m: &FnCallExprModel) { - if m.IsCo { - // Do not check for exceptionals, - // exceptional functions cannot be called with co. - self.coFuncCall(m) - ret - } - if m.Func.IsBuiltin() || - !m.Func.Decl.Exceptional || - m.Except != nil && len(m.Except.Stmts) == 0 { - self.pureFuncCall(m) - ret - } - - // Generate code for exceptional. - self.oc.write("({\n") - self.oc.addIndent() - self.oc.indent() - self.oc.write("auto except = ") - self.pureFuncCall(m) - self.oc.write(";\n") - self.oc.indent() - if m.Except != nil { - if m.Func.Result == nil || !m.Assigned { - self.oc.write("if (!except.ok()) ") - self.oc.sc.scope(m.Except) - self.oc.write("\n") - } else { - forwarded := obj::IsForwarded(m.Except) - self.oc.write("(except.ok()) ? (except.result) : (") - if forwarded { - self.oc.write("{") - } - mut stmt := m.Except.Stmts[len(m.Except.Stmts)-1] - match type stmt { - | &Data: - m.Except.Stmts = m.Except.Stmts[:len(m.Except.Stmts)-1] - self.oc.write("{\n") - self.oc.addIndent() - self.oc.sc.scopeStmts(m.Except) - self.oc.write("\n") - self.oc.indent() - self.writeUseExpr(m.Func, (&Data)(stmt)) - self.oc.write("\n") - self.oc.doneIndent() - self.oc.indent() - self.oc.write("}") - |: - self.oc.sc.scope(m.Except) - } - if forwarded { - self.oc.write(" ") - self.initExpr(m.Func.Result) - self.oc.write(";}") - } - self.oc.write(");\n") - } - self.oc.doneIndent() - } else { - self.oc.write(`if (!except.ok()) jule::panic(jule::Str("unhandled exceptional: ") + except.error.type->to_str(except.error.data) + jule::Str("\nlocation: `) - self.oc.locInfo(m.Token) - self.oc.write("\"));\n") - if !m.Func.Decl.IsVoid() { - self.oc.indent() - self.oc.write("(except.result);\n") - } - self.oc.doneIndent() - } - - self.oc.indent() - self.oc.write("})") - } - - fn slice(mut &self, mut m: &SliceExprModel) { - if len(m.Elems) == 0 { - self.oc.tc.asSlice(self.oc.Buf, m.ElemKind) - self.oc.write("()") - ret - } - self.oc.tc.asSlice(self.oc.Buf, m.ElemKind) - self.oc.write("::make({") - self.models(m.Elems) - self.oc.write("})") - } - - fn indexing(mut &self, mut m: &IndexingExprModel) { - match type m.Expr.Model { - | &Const: - // Cosntant string indexed. Use fast way, avoid making literal. - self.oc.write(typeCoder.Str + "::at(") - if !env::Production { - self.oc.write("\"") - self.oc.locInfo(m.Token) - self.oc.write("\", ") - } - self.oc.write("reinterpret_cast(") - s := (&Const)(m.Expr.Model).ReadStr() - cstrLit(self.oc.Buf, s) - self.oc.write("), ") - self.oc.write(conv::Itoa(len(s))) - self.oc.write(", ") - self.possibleRefExpr(m.Index.Model) - self.oc.write(")") - ret - } - - self.possibleRefExpr(m.Expr.Model) - // Index access with safety measures. - match { - | env::Production - | m.Expr.Kind.Ptr() != nil - | m.Expr.Kind.Map() != nil - | obj::IsExprComesFromBind(m.Expr): - self.oc.write("[") - self.possibleRefExpr(m.Index.Model) - self.oc.write("]") - |: - self.oc.write(".at(\"") - self.oc.locInfo(m.Token) - self.oc.write("\", ") - self.possibleRefExpr(m.Index.Model) - self.oc.write(")") - } - } - - fn unsafeIndexing(mut &self, mut m: &UnsafeIndexingExprModel) { - self.possibleRefExpr(m.Node.Expr.Model) - // Index access with safety measures. - match { - | env::Production - | m.Node.Expr.Kind.Ptr() != nil - | m.Node.Expr.Kind.Map() != nil: - self.oc.write("[") - self.possibleRefExpr(m.Node.Index.Model) - self.oc.write("]") - |: - self.oc.write(".__at(") - self.possibleRefExpr(m.Node.Index.Model) - self.oc.write(")") - } - } - - fn anonFunc(mut &self, mut m: &AnonFnExprModel) { - closure := obj::IsClosure(m) - ident := self.oc.pushAnonFn(m) - self.oc.write("jule::__new_closure<") - self.oc.tc.anonFunc(self.oc.Buf, m.Func) - self.oc.write(">((void*)") - self.oc.write(ident) - if closure { - self.oc.write(", jule::Ptr<") - self.oc.write(ident) - self.oc.write(anonFnCtxSuffix) - self.oc.write(">::make(") - self.oc.write(ident) - self.oc.write(anonFnCtxSuffix + "{") - for (i, mut v) in m.Captured { - self.oc.write(".") - identCoder.var(self.oc.Buf, v) - self.oc.write("=") - self.var(v) - if len(m.Captured)-i > 1 { - self.oc.write(",") - } - } - self.oc.write("}).as<" + typeCoder.Uintptr + ">(), ") - self.oc.write(ident) - self.oc.write(anonFnCtxHandlerSuffix + ")") - } else { - self.oc.write(", nullptr, nullptr)") - } - } - - fn mapExpr(mut &self, mut m: &MapExprModel) { - self.oc.write(typeCoder.Map + "<") - self.oc.tc.kind(self.oc.Buf, m.KeyKind) - self.oc.write(", ") - self.oc.tc.kind(self.oc.Buf, m.ValKind) - self.oc.write(">({") - if len(m.Entries) > 0 { - for (i, mut pair) in m.Entries { - self.oc.write("{") - self.possibleRefExpr(pair.Key) - self.oc.write(",") - self.possibleRefExpr(pair.Val) - self.oc.write("}") - if len(m.Entries)-i > 1 { - self.oc.write(",") - } - } - } - self.oc.write("})") - } - - fn slicing(mut &self, mut m: &SlicingExprModel) { - self.possibleRefExpr(m.Expr) - self.oc.write(".slice(") - if !env::Production { - self.oc.write("\"") - self.oc.locInfo(m.Token) - self.oc.write("\", ") - } - self.possibleRefExpr(m.Left) - if m.Right != nil { - self.oc.write(", ") - self.possibleRefExpr(m.Right) - } - self.oc.write(")") - } - - fn traitSub(mut &self, mut m: &TraitSubIdentExprModel) { - self.oc.write("((") - identCoder.traitDecl(self.oc.Buf, m.Trt) - self.oc.write("MptrData") - self.oc.write("*)") - self.possibleRefExpr(m.Expr) - self.oc.write(".safe_type(") - if !env::Production { - self.oc.write("\"") - self.oc.locInfo(m.Token) - self.oc.write("\"") - } - self.oc.write("))->") - identCoder.func(self.oc.Buf, m.Method) - } - - fn structureSub(mut &self, mut m: &StructSubIdentExprModel) { - self.possibleRefExpr(m.Expr.Model) - if m.Field == nil { - ret - } - self.oc.write(".") - identCoder.field(self.oc.Buf, m.Field.Decl) - } - - fn array(mut &self, mut m: &ArrayExprModel) { - self.oc.tc.array(self.oc.Buf, m.Kind) - if len(m.Elems) == 0 { - self.oc.write("()") - ret - } - - // Filled. - if len(m.Elems) == 2 && m.Elems[1] == nil { - self.oc.write("(") - self.possibleRefExpr(m.Elems[0]) - self.oc.write(")") - ret - } - - self.oc.write("({") - self.models(m.Elems) - self.oc.write("})") - ret - } - - // Writes complete expression model of function instance. - // Usefull for strict type safety. - fn funcInsCommon(mut &self, mut m: &FnIns) { - self.oc.tc.func(self.oc.Buf, m) - self.oc.write("(") - self.funcIns(m) - self.oc.write(")") - } - - fn funcIns(mut &self, mut m: &FnIns) { - if m.Decl != nil && m.Decl.Binded { - d := obj::FindDirective(m.Decl.Directives, Directive.Namespace) - if d != nil { - self.oc.writeBytes(concatAllParts(d.Args...)) - self.oc.write("::") - } - } - identCoder.funcIns(self.oc.Buf, m) - } - - fn tuple(mut &self, mut m: &TupleExprModel) { - for (i, mut d) in m.Datas { - self.possibleRefExpr(d.Model) - self.oc.write(";") - if len(m.Datas)-i > 1 { - self.oc.write("\n") - self.oc.indent() - } - } - } - - fn newCall(mut &self, mut m: &BuiltinNewCallExprModel) { - self.oc.write("jule::new_ptr<") - self.oc.tc.kind(self.oc.Buf, m.Kind) - self.oc.write(">(") - if m.Init != nil { - self.possibleRefExpr(m.Init) - } - self.oc.write(")") - } - - fn outCall(mut &self, mut m: &BuiltinOutCallExprModel) { - if m.Debug && env::Production { - ret - } - self.oc.write("jule::out(") - self.possibleRefExpr(m.Expr) - self.oc.write(")") - } - - fn outlnCall(mut &self, mut m: &BuiltinOutlnCallExprModel) { - if m.Debug && env::Production { - ret - } - self.oc.write("jule::outln(") - self.possibleRefExpr(m.Expr) - self.oc.write(")") - } - - fn panicCall(mut &self, mut m: &BuiltinPanicCallExprModel) { - self.oc.write("jule::panic(") - self.possibleRefExpr(m.Expr) - self.oc.write(` + jule::Str("\nlocation: `) - self.oc.locInfo(m.Token) - self.oc.write("\"));") - } - - fn assertCall(mut &self, mut m: &BuiltinAssertCallExprModel) { - if env::Production { - ret - } - self.oc.write("if (!(") - self.possibleRefExpr(m.Expr) - self.oc.write(")) jule::panic(jule::Str(") - cstrLit(self.oc.Buf, m.Log) - self.oc.write(`) + jule::Str("\nlocation: `) - self.oc.locInfo(m.Token) - self.oc.write("\"));") - } - - fn errorCall(mut &self, mut m: &BuiltinErrorCallExprModel) { - self.oc.write("return ") - if m.Func.Decl.IsVoid() { - match type m.Err.Model { - | &Var: - v := (&Var)(m.Err.Model) - if v.Ident == TokenKind.Error { - self.oc.write("jule::VoidExceptional{.error=std::move(except.error)}") - ret - } - } - self.oc.write("jule::VoidExceptional{.error=" + typeCoder.Any + "(") - } else { - self.oc.write("jule::Exceptional<") - self.oc.tc.rc.codeMut1(self.oc.Buf, m.Func.Result) - match type m.Err.Model { - | &Var: - v := (&Var)(m.Err.Model) - if v.Ident == TokenKind.Error { - self.oc.write(">{.error=except.error}") - ret - } - } - self.oc.write(">{.error=" + typeCoder.Any + "(") - } - self.possibleRefExpr(m.Err.Model) - i := self.oc.pushAnyType(m.Err.Kind) - self.oc.write(", &" + anyTypeIdent) - self.oc.write(conv::Itoa(i)) - self.oc.write(")}") - } - - fn copyCall(mut &self, mut m: &BuiltinCopyCallExprModel) { - self.oc.write("jule::copy(") - self.possibleRefExpr(m.Dest.Model) - self.oc.write(", ") - self.possibleRefExpr(m.Src.Model) - self.oc.write(")") - } - - fn lenCall(mut &self, mut m: &BuiltinLenCallExprModel) { - self.possibleRefExpr(m.Expr.Model) - self.oc.write(".len()") - } - - fn capCall(mut &self, mut m: &BuiltinCapCallExprModel) { - self.possibleRefExpr(m.Expr.Model) - self.oc.write(".cap()") - } - - fn deleteCall(mut &self, mut m: &BuiltinDeleteCallExprModel) { - self.possibleRefExpr(m.Dest.Model) - if m.Key != nil { - self.oc.write(".del(") - self.possibleRefExpr(m.Key.Model) - self.oc.write(")") - } else { - self.oc.write(".clear()") - } - } - - fn makeCallSlice(mut &self, mut &m: &BuiltinMakeCallExprModel) { - mut slice := m.Kind.Slc() - self.oc.tc.kind(self.oc.Buf, m.Kind) - self.oc.write("::alloc(") - self.possibleRefExpr(m.Len) - self.oc.write(", ") - if m.Cap != nil { - self.possibleRefExpr(m.Cap) - } else { - self.possibleRefExpr(m.Len) - } - if shouldInitialized(slice.Elem) { - self.oc.write(", ") - self.initExpr(slice.Elem) - } - self.oc.write(")") - } - - fn makeCallStr(mut &self, mut &m: &BuiltinMakeCallExprModel) { - self.oc.write(typeCoder.Str) - self.oc.write("::alloc(") - self.possibleRefExpr(m.Len) - if m.Cap != nil { - self.oc.write(", ") - self.possibleRefExpr(m.Cap) - } - self.oc.write(")") - } - - fn makeCall(mut &self, mut m: &BuiltinMakeCallExprModel) { - if m.Kind.Slc() != nil { - self.makeCallSlice(m) - ret - } - self.makeCallStr(m) - } - - fn pushToSlice(mut &self, mut m: &PushToSliceExprModel) { - // Use l-value advantage and define reference variable to destination - // in the child scope to avoid potential repeated high-cost memory access overhead. - const destIdent = "__jule_push_dest" - - self.oc.write("{ ") - self.oc.tc.asSlice(self.oc.Buf, m.Elems.ElemKind) - - mut ptr := false - match type m.Dest { - | &UnaryExprModel: - // Use raw pointer directly if exist. - mut u := (&UnaryExprModel)(m.Dest) - if u.Expr.Kind.Ptr() != nil { - self.oc.write(" *" + destIdent + " = ") - self.possibleRefExpr(u.Expr.Model) - self.oc.write("; ") - ptr = true - break - } - fall - |: - self.oc.write(" &" + destIdent + " = ") - self.possibleRefExpr(m.Dest) - self.oc.write("; ") - } - // Pushed single item. - if len(m.Elems.Elems) == 1 { - if ptr { - self.oc.write(destIdent + "->push(") - } else { - self.oc.write(destIdent + ".push(") - } - self.possibleRefExpr(m.Elems.Elems[0]) - self.oc.write("); }") - ret - } - // Pushed more than single item. - // Pre-allocate enough capacity if not exist for appendation. - if ptr { - self.oc.write(destIdent + "->alloc_for_append(") - } else { - self.oc.write(destIdent + ".alloc_for_append(") - } - self.oc.write(conv::Itoa(len(m.Elems.Elems))) - self.oc.write("); ") - for (_, mut e) in m.Elems.Elems { - self.oc.write(destIdent) - // Use the "__push" method to skip allocation boundary checking. - if ptr { - self.oc.write("->__push(") - } else { - self.oc.write(".__push(") - } - self.possibleRefExpr(e) - self.oc.write("); ") - } - self.oc.write("}") - } - - fn appendToSlice(mut &self, mut m: &AppendToSliceExprModel) { - self.oc.write("(") - self.possibleRefExpr(m.Dest) - self.oc.write(").append(") - self.possibleRefExpr(m.Slice) - self.oc.write(");") - } - - fn appendCall(mut &self, mut m: &BuiltinAppendCallExprModel) { - self.oc.write("jule::append(") - self.possibleRefExpr(m.Dest) - self.oc.write(",") - self.possibleRefExpr(m.Elements) - self.oc.write(")") - } - - fn sizeof(mut &self, mut m: &SizeofExprModel) { - self.oc.write("sizeof(") - self.possibleRefExpr(m.Expr) - self.oc.write(")") - } - - fn alignof(mut &self, mut m: &AlignofExprModel) { - self.oc.write("alignof(") - self.possibleRefExpr(m.Expr) - self.oc.write(")") - } - - fn runeLit(mut &self, m: &RuneExprModel) { - if m.Code <= 127 { // ASCII. - self.oc.Buf.WriteByte('\'') - mut b := sbtoa(byte(m.Code)) - if b == "'" { - self.oc.Buf.WriteByte('\\') - } - self.oc.Buf.WriteStr(b) - self.oc.Buf.WriteByte('\'') - ret - } - itoa(self.oc.Buf, i64(m.Code)) - } - - fn structureStatic(mut &self, mut m: &StructStaticIdentExprModel) { - identCoder.funcIns(self.oc.Buf, m.Method) - } - - fn integratedToStr(mut &self, mut m: &IntegratedToStrExprModel) { - self.oc.write("jule::to_str(") - self.possibleRefExpr(m.Expr) - self.oc.write(")") - } - - fn backendEmit(mut &self, mut m: &BackendEmitExprModel) { - if len(m.Exprs) == 0 { - self.oc.write(m.Code) - ret - } - n := self.oc.Buf.Len() - mut args := make([]any, len(m.Exprs)) - for (i, mut expr) in m.Exprs { - self.possibleRefExpr(expr) - mut buf := unsafe { self.oc.Buf.Buf() } - args[i] = str(buf[n:]) - unsafe { self.oc.Buf.SetBuf(buf[:n]) } - } - self.oc.write(fmt::Format(m.Code, args...)) - } - - fn free(mut &self, mut m: &FreeExprModel) { - self.possibleRefExpr(m.Expr) - if env::RC { - self.oc.write(".dealloc()") - ret - } - self.oc.write(".__free()") - } - - fn strComp(mut &self, mut m: &StrCompExprModel) { - if m.NotEq { - self.oc.write("(!") - } - s := m.Right.ReadStr() - self.possibleRefExpr(m.Left) - self.oc.write(".equal(") - cstrLit(self.oc.Buf, s) - self.oc.write(", ") - self.oc.write(conv::Itoa(len(s))) - self.oc.write(")") - if m.NotEq { - self.oc.write(")") - } - } - - fn emptyCompare(mut &self, mut m: &EmptyCompareExprModel) { - if m.Neg { - self.oc.write("!") - } - self.oc.write("(") - self.possibleRefExpr(m.Expr) - self.oc.write(").empty()") - } - - fn unsafeDeref(mut &self, mut m: &UnsafeDerefExprModel) { - match { - | m.Base.Expr.Kind.Sptr() != nil: - self.oc.write("(*") - self.possibleRefExpr(m.Base.Expr.Model) - self.oc.write(".alloc)") - |: - panic("implementation mistake, this panic call should be unreachable") - } - } - - fn unsafeCasting(mut &self, mut m: &UnsafeCastingExprModel) { - match { - | obj::IsAny(m.Base.ExprKind): - self.possibleRefExpr(m.Base.Expr.Model) - if m.Base.Kind.Sptr() != nil { - self.oc.write(".unsafe_cast_ptr<") - self.oc.tc.kind(self.oc.Buf, m.Base.Kind.Sptr().Elem) - } else { - self.oc.write(".unsafe_cast<") - self.oc.tc.kind(self.oc.Buf, m.Base.Kind) - } - self.oc.write(">()") - |: - panic("implementation mistake, this panic call should be unreachable") - } - } - - fn model(mut &self, mut m: compExprModel) { - match type m { - | str: - self.oc.write(str(m)) - | &TypeKind: - self.oc.tc.kind(self.oc.Buf, (&TypeKind)(m)) - | &Const: - self.constant((&Const)(m)) - | &Var: - self.var((&Var)(m)) - | &StructIns: - self.structureIns((&StructIns)(m)) - | &FnIns: - self.funcInsCommon((&FnIns)(m)) - | &UnsafeBinaryExprModel: - self.unsafeBinary((&UnsafeBinaryExprModel)(m).Node) - | &BinaryExprModel: - self.binary((&BinaryExprModel)(m)) - | &UnaryExprModel: - self.unary((&UnaryExprModel)(m)) - | &StructLitExprModel: - self.structureLit((&StructLitExprModel)(m)) - | &AllocStructLitExprModel: - self.allocStructure((&AllocStructLitExprModel)(m)) - | &CastingExprModel: - self.casting((&CastingExprModel)(m)) - | &FnCallExprModel: - self.funcCall((&FnCallExprModel)(m)) - | &SliceExprModel: - self.slice((&SliceExprModel)(m)) - | &ArrayExprModel: - self.array((&ArrayExprModel)(m)) - | &UnsafeIndexingExprModel: - self.unsafeIndexing((&UnsafeIndexingExprModel)(m)) - | &IndexingExprModel: - self.indexing((&IndexingExprModel)(m)) - | &AnonFnExprModel: - self.anonFunc((&AnonFnExprModel)(m)) - | &MapExprModel: - self.mapExpr((&MapExprModel)(m)) - | &SlicingExprModel: - self.slicing((&SlicingExprModel)(m)) - | &TraitSubIdentExprModel: - self.traitSub((&TraitSubIdentExprModel)(m)) - | &StructSubIdentExprModel: - self.structureSub((&StructSubIdentExprModel)(m)) - | &TupleExprModel: - self.tuple((&TupleExprModel)(m)) - | &BuiltinOutCallExprModel: - self.outCall((&BuiltinOutCallExprModel)(m)) - | &BuiltinOutlnCallExprModel: - self.outlnCall((&BuiltinOutlnCallExprModel)(m)) - | &BuiltinNewCallExprModel: - self.newCall((&BuiltinNewCallExprModel)(m)) - | &BuiltinPanicCallExprModel: - self.panicCall((&BuiltinPanicCallExprModel)(m)) - | &BuiltinAssertCallExprModel: - self.assertCall((&BuiltinAssertCallExprModel)(m)) - | &BuiltinErrorCallExprModel: - self.errorCall((&BuiltinErrorCallExprModel)(m)) - | &BuiltinMakeCallExprModel: - self.makeCall((&BuiltinMakeCallExprModel)(m)) - | &BuiltinAppendCallExprModel: - self.appendCall((&BuiltinAppendCallExprModel)(m)) - | &BuiltinCopyCallExprModel: - self.copyCall((&BuiltinCopyCallExprModel)(m)) - | &BuiltinLenCallExprModel: - self.lenCall((&BuiltinLenCallExprModel)(m)) - | &BuiltinCapCallExprModel: - self.capCall((&BuiltinCapCallExprModel)(m)) - | &BuiltinDeleteCallExprModel: - self.deleteCall((&BuiltinDeleteCallExprModel)(m)) - | &SizeofExprModel: - self.sizeof((&SizeofExprModel)(m)) - | &AlignofExprModel: - self.alignof((&AlignofExprModel)(m)) - | &RuneExprModel: - self.runeLit((&RuneExprModel)(m)) - | &StructStaticIdentExprModel: - self.structureStatic((&StructStaticIdentExprModel)(m)) - | &IntegratedToStrExprModel: - self.integratedToStr((&IntegratedToStrExprModel)(m)) - | &BackendEmitExprModel: - self.backendEmit((&BackendEmitExprModel)(m)) - | &FreeExprModel: - self.free((&FreeExprModel)(m)) - | &StrCompExprModel: - self.strComp((&StrCompExprModel)(m)) - | &RefExprModel: - self.var((&RefExprModel)(m).Var) - | &EmptyCompareExprModel: - self.emptyCompare((&EmptyCompareExprModel)(m)) - | &UnsafeDerefExprModel: - self.unsafeDeref((&UnsafeDerefExprModel)(m)) - | &UnsafeCastingExprModel: - self.unsafeCasting((&UnsafeCastingExprModel)(m)) - |: - self.oc.write("") - } - } - - fn initExpr(mut &self, mut t: &TypeKind) { - if t.NilCompatible() { - if t.Ptr() != nil { - self.oc.write("nullptr") - } else { - self.oc.tc.kind(self.oc.Buf, t) - self.oc.write("(nullptr)") - } - ret - } - mut tup := t.Tup() - if tup != nil { - self.oc.tc.rc.tup(self.oc.Buf, tup) - self.oc.write("{") - for (i, mut tt) in tup.Types { - if !shouldInitialized(tt) { - continue - } - self.oc.write("." + resultArgName) - self.oc.write(conv::Itoa(i)) - self.oc.write("=") - self.initExpr(tt) - if len(tup.Types)-i > 1 { - self.oc.write(", ") - } - } - self.oc.write("}") - ret - } - mut enm := t.Enum() - if enm != nil { - self.model(enm.Items[0].Value.Data.Model) - ret - } - prim := t.Prim() - if prim != nil { - if types::IsNum(prim.Kind) { - self.oc.write("0") - } else if prim.IsBool() { - self.oc.write("false") - } else if prim.IsStr() { - self.oc.write(typeCoder.Str + "()") - } - ret - } - if t.Arr() != nil { - mut arr := t.Arr() - self.oc.tc.kind(self.oc.Buf, t) - self.oc.write("(") - self.initExpr(arr.Elem) - self.oc.write(")") - ret - } - mut s := t.Struct() - if s != nil && s.Decl.Binded && obj::FindDirective(s.Decl.Directives, Directive.Typedef) == nil { - self.oc.write("(") - self.oc.tc.kind(self.oc.Buf, t) - self.oc.write("){}") - ret - } - self.oc.tc.kind(self.oc.Buf, t) - self.oc.write("()") - } + static fn new(mut &oc: &ObjectCoder): &exprCoder { + ret &exprCoder{ + oc: oc, + } + } + + fn string(mut &self, &c: &Const) { + content := c.ReadStr() + if len(content) == 0 { // Empty. + self.oc.write(typeCoder.Str + "()") + ret + } + len := conv::FmtInt(i64(len(content)), 10) + self.oc.write(typeCoder.Str) + self.oc.write("::lit(") + cstrLit(self.oc.Buf, content) + self.oc.write(", ") + self.oc.write(len) + self.oc.write(")") + } + + fn boolean(mut &self, b: bool) { + if b { + self.oc.write("true") + } else { + self.oc.write("false") + } + } + + fn nilLit(mut &self) { + self.oc.write("nullptr") + } + + fn ftoaSpecialCases(mut &self, &x: f64): bool { + match { + | math::IsNaN(x): + self.oc.write("NAN") + | math::IsInf(x, 1): + self.oc.write("INFINITY") + | math::IsInf(x, -1): + self.oc.write("-INFINITY") + |: + ret false + } + ret true + } + + fn float32(mut &self, &c: &Const) { + x := c.AsF64() + + // Special cases. + if self.ftoaSpecialCases(x) { + ret + } + + match { + | x == MaxF32: + self.oc.write("jule::MAX_F32") + | x == MinF32: + self.oc.write("jule::MIN_F32") + |: + ftoa(self.oc.Buf, x, 1 << 5) + self.oc.write("f") + } + } + + fn float64(mut &self, &c: &Const) { + x := c.AsF64() + + // Special cases. + if self.ftoaSpecialCases(x) { + ret + } + + match { + | x == MaxF64: + self.oc.write("jule::MAX_F64") + | x == MinF64: + self.oc.write("jule::MIN_F64") + |: + ftoa(self.oc.Buf, x, 1 << 6) + } + } + + fn constant(mut &self, mut c: &Const) { + match { + | c.IsStr(): + self.string(c) + | c.IsBool(): + self.boolean(c.ReadBool()) + | c.IsF64(): + match { + | c.Kind == PrimKind.F32: + self.float32(c) + |: + self.float64(c) + } + | c.IsI64(): + itoa(self.oc.Buf, c.ReadI64()) + | c.IsU64(): + utoa(self.oc.Buf, c.ReadU64()) + | c.IsNil(): + self.nilLit() + |: + self.oc.write("") + } + } + + fn divByZeroBinary(mut &self, &op: &Token, mut &l: &OperandExprModel, mut &r: &OperandExprModel) { + self.oc.write("jule::") + match op.Id { + | TokenId.Solidus + | TokenId.SolidusEq: + self.oc.write("div(") + | TokenId.Percent + | TokenId.PercentEq: + self.oc.write("mod(") + } + + if !env::Production { + self.oc.write("\"") + self.oc.locInfo(op) + self.oc.write("\",") + } + self.possibleRefExpr(l.Model) + self.oc.write(",") + self.possibleRefExpr(r.Model) + self.oc.write(")") + } + + fn unsafeBinary(mut &self, mut m: &BinaryExprModel) { + if m.Op.Id == TokenId.Eqs || m.Op.Id == TokenId.NotEq { + // If this binary operator comparing type. + // The m.Left is will be one always. + if obj::IsAny(m.Left.Kind) { + if !m.Right.Kind.IsNil() && !obj::IsAny(m.Right.Kind) { + self.oc.write("(") + if m.Op.Id == TokenId.NotEq { + self.oc.write("!") + } + i := self.oc.pushAnyType(m.Right.Kind) + self.oc.write(anyTypeIdent) + self.oc.write(conv::Itoa(i)) + self.oc.write("_compare(") + self.possibleRefExpr(m.Left.Model) + self.oc.write(", ") + self.possibleRefExpr(m.Right.Model) + self.oc.write("))") + ret + } + } + } + self.oc.write("(") + self.possibleRefExpr(m.Left.Model) + self.oc.write(" ") + self.oc.write(m.Op.Kind) + self.oc.write(" ") + self.possibleRefExpr(m.Right.Model) + self.oc.write(")") + } + + fn binary(mut &self, mut m: &BinaryExprModel) { + match m.Op.Id { + | TokenId.Solidus | TokenId.Percent: + // Do not check division of structures safety. + if m.Left.Kind.Struct() == nil { + self.divByZeroBinary(m.Op, m.Left, m.Right) + ret + } + } + self.unsafeBinary(m) + } + + fn var(mut &self, mut m: &Var) { + for _, prefix in self.varPrefixes { + if prefix(m) { + ret + } + } + if m.Binded { + d := obj::FindDirective(m.Directives, Directive.Namespace) + if d != nil { + self.oc.writeBytes(concatAllParts(d.Args...)) + self.oc.write("::") + } + } + identCoder.var(self.oc.Buf, m) + } + + fn structureIns(mut &self, mut m: &StructIns) { + self.oc.tc.structureIns(self.oc.Buf, m) + } + + fn unary(mut &self, mut m: &UnaryExprModel) { + match m.Op.Id { + | TokenId.Caret: + self.oc.write("(~(") + self.possibleRefExpr(m.Expr.Model) + self.oc.write("))") + ret + | TokenId.Star: + if env::Production || m.Expr.Kind.Sptr() == nil { + break + } + self.possibleRefExpr(m.Expr.Model) + self.oc.write(".get(\"") + self.oc.locInfo(m.Op) + self.oc.write("\")") + ret + } + self.oc.write("(") + self.oc.write(m.Op.Kind) + self.oc.write("(") + self.possibleRefExpr(m.Expr.Model) + self.oc.write("))") + } + + fn structureLit(mut &self, mut m: &StructLitExprModel) { + if m.Strct.Decl.Binded { + self.oc.write("(") + } + self.oc.tc.structureIns(self.oc.Buf, m.Strct) + if m.Strct.Decl.Binded { + self.oc.write(")") + } + self.oc.write("{") + if len(m.Args) > 0 { + // Fields are should be in order. + // In other words, GCC will produce error(s). + iter: + for i, f in m.Strct.Fields { + for (_, mut arg) in m.Args { + if arg.Field == f { + self.oc.write(".") + identCoder.field(self.oc.Buf, arg.Field.Decl) + self.oc.write("=") + self.possibleRefExpr(arg.Expr.Model) + if len(m.Strct.Fields)-i > 1 { + self.oc.write(", ") + } + continue iter + } + } + } + } + self.oc.write("}") + } + + fn allocStructure(mut &self, mut m: &AllocStructLitExprModel) { + self.oc.write("jule::new_ptr<") + identCoder.structureIns(self.oc.Buf, m.Lit.Strct) + self.oc.write(">(") + self.structureLit(m.Lit) + self.oc.write(")") + } + + fn possibleRefExpr(mut &self, expr: compExprModel) { + match type expr { + | &Var: + v := (&Var)(expr) + if v.Reference { + self.oc.write("(*(") + self.model(expr) + self.oc.write("))") + ret + } + } + self.model(expr) + } + + fn castTraitFromTrait(mut &self, mut &m: &CastingExprModel, mut t1: &Trait, mut t2: &Trait) { + self.possibleRefExpr(m.Expr.Model) + self.oc.write(".map(") + self.oc.pushAndWriteMaskMapper(t1, t2) + self.oc.write(")") + } + + // Casting expression. + // + // Special cases: + // - The any type castings should be came first than others. + // Otherwise, code generation might be wrong because the + // uses special casting algorithms. + fn casting(mut &self, mut m: &CastingExprModel) { + match { + | obj::IsAny(m.Kind): + if m.ExprKind.IsNil() { + self.oc.write(typeCoder.Any + "()") + ret + } + if m.ExprKind.TypeEnum() != nil { + self.possibleRefExpr(m.Expr.Model) + ret + } + i := self.oc.pushAnyType(m.ExprKind) + self.oc.write(typeCoder.Any + "(") + match type m.Expr.Model { + | &Const: + prim := m.ExprKind.Prim() + if prim != nil && types::IsInt(prim.Kind) { + self.oc.write("static_cast<") + self.oc.tc.prim(self.oc.Buf, prim) + self.oc.write(">(") + self.possibleRefExpr(m.Expr.Model) + self.oc.write(")") + break + } + fall + |: + self.possibleRefExpr(m.Expr.Model) + } + self.oc.write(", &" + anyTypeIdent) + self.oc.write(conv::Itoa(i)) + self.oc.write(")") + ret + | obj::IsAny(m.ExprKind): + self.possibleRefExpr(m.Expr.Model) + self.oc.write(".") + if m.Kind.Sptr() != nil { + self.oc.write("cast_ptr<") + self.oc.tc.kind(self.oc.Buf, m.Kind.Sptr().Elem) + } else { + self.oc.write("cast<") + self.oc.tc.kind(self.oc.Buf, m.Kind) + } + self.oc.write(">(") + if !env::Production { + self.oc.write("\"") + self.oc.locInfo(m.Token) + self.oc.write("\", ") + } + self.oc.write("&" + anyTypeIdent) + self.oc.write(conv::Itoa(self.oc.pushAnyType(m.Kind))) + self.oc.write(")") + ret + | m.ExprKind.Ptr() != nil + | m.Kind.Ptr() != nil: + self.oc.write("((") + self.oc.tc.kind(self.oc.Buf, m.Kind) + self.oc.write(")(") + self.possibleRefExpr(m.Expr.Model) + self.oc.write("))") + ret + | m.ExprKind.Trait() != nil: + if m.Kind.Trait() != nil { + self.castTraitFromTrait(m, m.Kind.Trait(), m.ExprKind.Trait()) + ret + } + self.possibleRefExpr(m.Expr.Model) + self.oc.write(".") + if m.Kind.Sptr() != nil { + self.oc.write("cast_ptr<") + self.oc.tc.kind(self.oc.Buf, m.Kind.Sptr().Elem) + } else { + self.oc.write("cast<") + self.oc.tc.kind(self.oc.Buf, m.Kind) + } + self.oc.write(">(") + if !env::Production { + self.oc.write("\"") + self.oc.locInfo(m.Token) + self.oc.write("\", ") + } + self.oc.write("(" + typeCoder.Trait + "::Type*)&") + identCoder.traitDecl(self.oc.Buf, m.ExprKind.Trait()) + self.oc.write("_mptr_data") + self.oc.write(conv::Itoa(obj::FindTraitTypeOffset(m.ExprKind.Trait(), m.Kind))) + self.oc.write(")") + ret + | m.Kind.Trait() != nil: + self.oc.tc.kind(self.oc.Buf, m.Kind) + self.oc.write("(") + self.possibleRefExpr(m.Expr.Model) + self.oc.write(", (" + typeCoder.Trait + "::Type*)&") + identCoder.traitDecl(self.oc.Buf, m.Kind.Trait()) + self.oc.write("_mptr_data") + self.oc.write(conv::Itoa(obj::FindTraitTypeOffset(m.Kind.Trait(), m.ExprKind))) + self.oc.write(")") + ret + } + prim := m.Kind.Prim() + eprim := m.ExprKind.Prim() + if eprim != nil && prim != nil && prim.IsStr() { + if eprim.IsU8() { + self.oc.write(typeCoder.Str + "::from_byte(") + } else { + self.oc.write(typeCoder.Str + "::from_rune(") + } + self.possibleRefExpr(m.Expr.Model) + self.oc.write(")") + ret + } + self.oc.write("static_cast<") + self.oc.tc.kind(self.oc.Buf, m.Kind) + self.oc.write(">(") + self.possibleRefExpr(m.Expr.Model) + self.oc.write(")") + } + + fn models(mut &self, mut args: []ExprModel) { + if len(args) == 0 { + ret + } + for (i, mut a) in args { + self.possibleRefExpr(a) + if len(args)-i > 1 { + self.oc.write(",") + } + } + } + + fn args(mut &self, mut &m: &FnCallExprModel) { + mut j := 0 + if m.Func.Owner != nil && !m.Func.Decl.Statically || + len(m.Func.Params) > 0 && m.Func.Params[0].Decl.IsSelf() { + j++ // Skip receiver parameter. + } + for i, arg in m.Args { + p := m.Func.Params[j] + if p.Decl != nil && p.Decl.Reference { + match type arg { + | &Var: + v := (&Var)(arg) + if v.Reference { + self.model(arg) + goto end + } + } + self.oc.write("&(") + self.model(arg) + self.oc.write(")") + goto end + } + self.possibleRefExpr(arg) + end: + if len(m.Args)-i > 1 { + self.oc.write(", ") + } + j++ + } + } + + fn modelForCall(mut &self, mut expr: compExprModel) { + match type expr { + | &FnIns: + self.funcIns((&FnIns)(expr)) + ret + | &StructSubIdentExprModel: + mut ssie := (&StructSubIdentExprModel)(expr) + if ssie.Method != nil { + self.funcIns(ssie.Method) + ret + } + } + self.possibleRefExpr(expr) + } + + fn pushCallInf(mut &self, &m: &FnCallExprModel) { + if env::Production || !m.Func.Anon { + self.oc.write("(") + ret + } + if m.Func.Anon { + match type m.Expr { + | &StructSubIdentExprModel: + if (&StructSubIdentExprModel)(m.Expr).Field.Decl.Owner.Binded { + self.oc.write("(") + ret + } + } + self.oc.write(".call") + } + self.oc.write("(\"") + self.oc.locInfo(m.Token) + self.oc.write("\"") + if len(m.Args) != 0 { + self.oc.write(", ") + } + } + + fn isWrapped(mut &self, mut &m: &FnCallExprModel): bool { + if !m.Func.IsBuiltin() && len(m.Func.Decl.Params) > 0 && m.Func.Decl.Params[0].IsSelf() { + match type m.Expr { + | &StructSubIdentExprModel: + mut ssie := (&StructSubIdentExprModel)(m.Expr) + match { + | m.Func.Decl.Params[0].IsRef() + | ssie.Expr.Kind.Sptr() != nil: + break + |: + if ssie.Expr.Kind.Struct() != nil { + if !ssie.Expr.Lvalue { + self.oc.write("({ auto _wrap_copy = ") + self.model(ssie.Expr.Model) + self.oc.write("; ") + ret true + } + } + } + } + } + ret false + } + + fn writeReceiver(mut &self, mut m: compExprModel): (safeDeref: bool) { + match type m { + | &UnaryExprModel: + self.possibleRefExpr((&UnaryExprModel)(m).Expr.Model) + ret true + | &UnsafeDerefExprModel: + self.possibleRefExpr((&UnsafeDerefExprModel)(m).Base.Expr.Model) + ret false + |: + panic("implementation mistake, this panic call should be unreachable") + } + } + + fn pureFuncCall(mut &self, mut &m: &FnCallExprModel) { + wrapped := self.isWrapped(m) + self.modelForCall(m.Expr) + if !m.Func.IsBuiltin() { + if m.Func.Decl.Binded && len(m.Func.Generics) > 0 { + if !obj::HasDirective(m.Func.Decl.Directives, Directive.Cdef) { + self.oc.write("<") + for (i, mut g) in m.Func.Generics { + self.oc.tc.kind(self.oc.Buf, g.Kind) + if len(m.Func.Generics)-i > 1 { + self.oc.write(", ") + } + } + self.oc.write(">") + } + } + } + self.pushCallInf(m) + if m.Func.AsAnon && !m.Func.Anon { + // Function used as anonymous. + // So pass nullptr to ctx parameter. + // Do not pass nullptr if function is anonymous, + // beacause it stores ctx data internally and it will pass. + self.oc.write("nullptr") + if len(m.Args) > 0 { + self.oc.write(", ") + } + } + if !m.Func.IsBuiltin() && len(m.Func.Decl.Params) > 0 && m.Func.Decl.Params[0].IsSelf() { + match type m.Expr { + | &StructSubIdentExprModel: + mut ssie := (&StructSubIdentExprModel)(m.Expr) + match { + | m.Func.Decl.Params[0].IsRef(): + // Ignore dereferencing, use data directly to call method. + _ = self.writeReceiver(ssie.Expr.Model) + | ssie.Expr.Kind.Sptr() != nil: + // Ignore dereferencing, use data directly to call [ptr] method. + safe := self.writeReceiver(ssie.Expr.Model) + if safe { + self.oc.write(".ptr(") + if !env::Production { + self.oc.write("\"") + self.oc.locInfo(m.Token) + self.oc.write("\"") + } + self.oc.write(")") + } + |: + if ssie.Expr.Kind.Struct() != nil { + match type ssie.Expr.Model { + | &Var: + v := (&Var)(ssie.Expr.Model) + if v.Reference { + break + } + fall + |: + // Add address taking operation for non-pointers. + self.oc.write("&") + } + } + if wrapped { + self.oc.write("_wrap_copy") + } else if ssie.Expr.Kind.Ptr() == nil { + self.model(ssie.Expr.Model) + } else { + // Ignore dereferencing, use data directly to call method. + self.possibleRefExpr((&UnaryExprModel)(ssie.Expr.Model).Expr.Model) + } + } + if len(m.Args) > 0 { + self.oc.write(", ") + } + | &TraitSubIdentExprModel: + self.possibleRefExpr((&TraitSubIdentExprModel)(m.Expr).Expr) + self.oc.write(".data") + if len(m.Args) > 0 { + self.oc.write(", ") + } + } + } + self.args(m) + self.oc.write(")") + + if wrapped { + self.oc.write("; })") + } + } + + fn coFuncCall(mut &self, mut &m: &FnCallExprModel) { + self.oc.write("{\n") + self.oc.addIndent() + mut head := StrBuilder.New(1 << 5) + head.WriteStr("std::thread([") + if m.Func.Owner != nil { + head.WriteStr(identCoder.Self) + if len(m.Args) > 0 { + head.WriteStr(", ") + } + } + for i, arg in m.Args { + if i > 0 { + head.WriteStr(", ") + } + match type arg { + | &Var: + mut v := (&Var)(arg) + identCoder.var(head, v) + continue + } + name := "_co_arg_" + conv::Itoa(i) + head.WriteStr(name) + self.oc.indent() + self.oc.tc.kind(self.oc.Buf, m.Func.Params[i].Kind) + self.oc.write(" ") + if m.Func.Params[i].Decl.Reference { + self.oc.write("&") + } + self.oc.write(name) + self.oc.write(" = ") + self.possibleRefExpr(arg) + self.oc.write(";\n") + argS := any(name) + m.Args[i] = unsafe { *(*ExprModel)(&argS) } + } + self.oc.indent() + self.oc.Buf.Write(unsafe { head.Buf() }) + self.oc.write("](void) mutable -> void {\n") + self.oc.addIndent() + self.oc.indent() + self.pureFuncCall(m) + self.oc.write(";\n") + self.oc.doneIndent() + self.oc.indent() + self.oc.write("}).detach();\n") + self.oc.doneIndent() + self.oc.indent() + self.oc.write("}") + } + + fn writeUseExpr(mut &self, mut &f: &FnIns, mut d: &Data) { + if d.Kind.Tup() == nil { + self.possibleRefExpr(d.Model) + self.oc.write(";") + ret + } + mut tup := (&TupleExprModel)(d.Model) + self.oc.tc.rc.tup(self.oc.Buf, f.Result.Tup()) + self.oc.write("{") + for i, data in tup.Datas { + self.oc.write("." + resultArgName) + self.oc.write(conv::Itoa(i)) + self.oc.write("=") + self.possibleRefExpr(data.Model) + if len(tup.Datas)-i > 1 { + self.oc.write(", ") + } + } + self.oc.write("};") + } + + fn funcCall(mut &self, mut m: &FnCallExprModel) { + if m.IsCo { + // Do not check for exceptionals, + // exceptional functions cannot be called with co. + self.coFuncCall(m) + ret + } + if m.Func.IsBuiltin() || + !m.Func.Decl.Exceptional || + m.Except != nil && len(m.Except.Stmts) == 0 { + self.pureFuncCall(m) + ret + } + + // Generate code for exceptional. + self.oc.write("({\n") + self.oc.addIndent() + self.oc.indent() + self.oc.write("auto except = ") + self.pureFuncCall(m) + self.oc.write(";\n") + self.oc.indent() + if m.Except != nil { + if m.Func.Result == nil || !m.Assigned { + self.oc.write("if (!except.ok()) ") + self.oc.sc.scope(m.Except) + self.oc.write("\n") + } else { + forwarded := obj::IsForwarded(m.Except) + self.oc.write("(except.ok()) ? (except.result) : (") + if forwarded { + self.oc.write("{") + } + mut stmt := m.Except.Stmts[len(m.Except.Stmts)-1] + match type stmt { + | &Data: + m.Except.Stmts = m.Except.Stmts[:len(m.Except.Stmts)-1] + self.oc.write("{\n") + self.oc.addIndent() + self.oc.sc.scopeStmts(m.Except) + self.oc.write("\n") + self.oc.indent() + self.writeUseExpr(m.Func, (&Data)(stmt)) + self.oc.write("\n") + self.oc.doneIndent() + self.oc.indent() + self.oc.write("}") + |: + self.oc.sc.scope(m.Except) + } + if forwarded { + self.oc.write(" ") + self.initExpr(m.Func.Result) + self.oc.write(";}") + } + self.oc.write(");\n") + } + self.oc.doneIndent() + } else { + self.oc.write(`if (!except.ok()) jule::panic(jule::Str("unhandled exceptional: ") + except.error.type->to_str(except.error.data) + jule::Str("\nlocation: `) + self.oc.locInfo(m.Token) + self.oc.write("\"));\n") + if !m.Func.Decl.IsVoid() { + self.oc.indent() + self.oc.write("(except.result);\n") + } + self.oc.doneIndent() + } + + self.oc.indent() + self.oc.write("})") + } + + fn slice(mut &self, mut m: &SliceExprModel) { + if len(m.Elems) == 0 { + self.oc.tc.asSlice(self.oc.Buf, m.ElemKind) + self.oc.write("()") + ret + } + self.oc.tc.asSlice(self.oc.Buf, m.ElemKind) + self.oc.write("::make({") + self.models(m.Elems) + self.oc.write("})") + } + + fn indexing(mut &self, mut m: &IndexingExprModel) { + match type m.Expr.Model { + | &Const: + // Cosntant string indexed. Use fast way, avoid making literal. + self.oc.write(typeCoder.Str + "::at(") + if !env::Production { + self.oc.write("\"") + self.oc.locInfo(m.Token) + self.oc.write("\", ") + } + self.oc.write("reinterpret_cast(") + s := (&Const)(m.Expr.Model).ReadStr() + cstrLit(self.oc.Buf, s) + self.oc.write("), ") + self.oc.write(conv::Itoa(len(s))) + self.oc.write(", ") + self.possibleRefExpr(m.Index.Model) + self.oc.write(")") + ret + } + + self.possibleRefExpr(m.Expr.Model) + // Index access with safety measures. + match { + | env::Production + | m.Expr.Kind.Ptr() != nil + | m.Expr.Kind.Map() != nil + | obj::IsExprComesFromBind(m.Expr): + self.oc.write("[") + self.possibleRefExpr(m.Index.Model) + self.oc.write("]") + |: + self.oc.write(".at(\"") + self.oc.locInfo(m.Token) + self.oc.write("\", ") + self.possibleRefExpr(m.Index.Model) + self.oc.write(")") + } + } + + fn unsafeIndexing(mut &self, mut m: &UnsafeIndexingExprModel) { + self.possibleRefExpr(m.Node.Expr.Model) + // Index access with safety measures. + match { + | env::Production + | m.Node.Expr.Kind.Ptr() != nil + | m.Node.Expr.Kind.Map() != nil: + self.oc.write("[") + self.possibleRefExpr(m.Node.Index.Model) + self.oc.write("]") + |: + self.oc.write(".__at(") + self.possibleRefExpr(m.Node.Index.Model) + self.oc.write(")") + } + } + + fn anonFunc(mut &self, mut m: &AnonFnExprModel) { + closure := obj::IsClosure(m) + ident := self.oc.pushAnonFn(m) + self.oc.write("jule::__new_closure<") + self.oc.tc.anonFunc(self.oc.Buf, m.Func) + self.oc.write(">((void*)") + self.oc.write(ident) + if closure { + self.oc.write(", jule::Ptr<") + self.oc.write(ident) + self.oc.write(anonFnCtxSuffix) + self.oc.write(">::make(") + self.oc.write(ident) + self.oc.write(anonFnCtxSuffix + "{") + for (i, mut v) in m.Captured { + self.oc.write(".") + identCoder.var(self.oc.Buf, v) + self.oc.write("=") + self.var(v) + if len(m.Captured)-i > 1 { + self.oc.write(",") + } + } + self.oc.write("}).as<" + typeCoder.Uintptr + ">(), ") + self.oc.write(ident) + self.oc.write(anonFnCtxHandlerSuffix + ")") + } else { + self.oc.write(", nullptr, nullptr)") + } + } + + fn mapExpr(mut &self, mut m: &MapExprModel) { + self.oc.write(typeCoder.Map + "<") + self.oc.tc.kind(self.oc.Buf, m.KeyKind) + self.oc.write(", ") + self.oc.tc.kind(self.oc.Buf, m.ValKind) + self.oc.write(">({") + if len(m.Entries) > 0 { + for (i, mut pair) in m.Entries { + self.oc.write("{") + self.possibleRefExpr(pair.Key) + self.oc.write(",") + self.possibleRefExpr(pair.Val) + self.oc.write("}") + if len(m.Entries)-i > 1 { + self.oc.write(",") + } + } + } + self.oc.write("})") + } + + fn slicing(mut &self, mut m: &SlicingExprModel) { + self.possibleRefExpr(m.Expr) + self.oc.write(".slice(") + if !env::Production { + self.oc.write("\"") + self.oc.locInfo(m.Token) + self.oc.write("\", ") + } + self.possibleRefExpr(m.Left) + if m.Right != nil { + self.oc.write(", ") + self.possibleRefExpr(m.Right) + } + self.oc.write(")") + } + + fn traitSub(mut &self, mut m: &TraitSubIdentExprModel) { + self.oc.write("((") + identCoder.traitDecl(self.oc.Buf, m.Trt) + self.oc.write("MptrData") + self.oc.write("*)") + self.possibleRefExpr(m.Expr) + self.oc.write(".safe_type(") + if !env::Production { + self.oc.write("\"") + self.oc.locInfo(m.Token) + self.oc.write("\"") + } + self.oc.write("))->") + identCoder.func(self.oc.Buf, m.Method) + } + + fn structureSub(mut &self, mut m: &StructSubIdentExprModel) { + self.possibleRefExpr(m.Expr.Model) + if m.Field == nil { + ret + } + self.oc.write(".") + identCoder.field(self.oc.Buf, m.Field.Decl) + } + + fn array(mut &self, mut m: &ArrayExprModel) { + self.oc.tc.array(self.oc.Buf, m.Kind) + if len(m.Elems) == 0 { + self.oc.write("()") + ret + } + + // Filled. + if len(m.Elems) == 2 && m.Elems[1] == nil { + self.oc.write("(") + self.possibleRefExpr(m.Elems[0]) + self.oc.write(")") + ret + } + + self.oc.write("({") + self.models(m.Elems) + self.oc.write("})") + ret + } + + // Writes complete expression model of function instance. + // Usefull for strict type safety. + fn funcInsCommon(mut &self, mut m: &FnIns) { + self.oc.tc.func(self.oc.Buf, m) + self.oc.write("(") + self.funcIns(m) + self.oc.write(")") + } + + fn funcIns(mut &self, mut m: &FnIns) { + if m.Decl != nil && m.Decl.Binded { + d := obj::FindDirective(m.Decl.Directives, Directive.Namespace) + if d != nil { + self.oc.writeBytes(concatAllParts(d.Args...)) + self.oc.write("::") + } + } + identCoder.funcIns(self.oc.Buf, m) + } + + fn tuple(mut &self, mut m: &TupleExprModel) { + for (i, mut d) in m.Datas { + self.possibleRefExpr(d.Model) + self.oc.write(";") + if len(m.Datas)-i > 1 { + self.oc.write("\n") + self.oc.indent() + } + } + } + + fn newCall(mut &self, mut m: &BuiltinNewCallExprModel) { + self.oc.write("jule::new_ptr<") + self.oc.tc.kind(self.oc.Buf, m.Kind) + self.oc.write(">(") + if m.Init != nil { + self.possibleRefExpr(m.Init) + } + self.oc.write(")") + } + + fn outCall(mut &self, mut m: &BuiltinOutCallExprModel) { + if m.Debug && env::Production { + ret + } + self.oc.write("jule::out(") + self.possibleRefExpr(m.Expr) + self.oc.write(")") + } + + fn outlnCall(mut &self, mut m: &BuiltinOutlnCallExprModel) { + if m.Debug && env::Production { + ret + } + self.oc.write("jule::outln(") + self.possibleRefExpr(m.Expr) + self.oc.write(")") + } + + fn panicCall(mut &self, mut m: &BuiltinPanicCallExprModel) { + self.oc.write("jule::panic(") + self.possibleRefExpr(m.Expr) + self.oc.write(` + jule::Str("\nlocation: `) + self.oc.locInfo(m.Token) + self.oc.write("\"));") + } + + fn assertCall(mut &self, mut m: &BuiltinAssertCallExprModel) { + if env::Production { + ret + } + self.oc.write("if (!(") + self.possibleRefExpr(m.Expr) + self.oc.write(")) jule::panic(jule::Str(") + cstrLit(self.oc.Buf, m.Log) + self.oc.write(`) + jule::Str("\nlocation: `) + self.oc.locInfo(m.Token) + self.oc.write("\"));") + } + + fn errorCall(mut &self, mut m: &BuiltinErrorCallExprModel) { + self.oc.write("return ") + if m.Func.Decl.IsVoid() { + match type m.Err.Model { + | &Var: + v := (&Var)(m.Err.Model) + if v.Ident == TokenKind.Error { + self.oc.write("jule::VoidExceptional{.error=std::move(except.error)}") + ret + } + } + self.oc.write("jule::VoidExceptional{.error=" + typeCoder.Any + "(") + } else { + self.oc.write("jule::Exceptional<") + self.oc.tc.rc.codeMut1(self.oc.Buf, m.Func.Result) + match type m.Err.Model { + | &Var: + v := (&Var)(m.Err.Model) + if v.Ident == TokenKind.Error { + self.oc.write(">{.error=except.error}") + ret + } + } + self.oc.write(">{.error=" + typeCoder.Any + "(") + } + self.possibleRefExpr(m.Err.Model) + i := self.oc.pushAnyType(m.Err.Kind) + self.oc.write(", &" + anyTypeIdent) + self.oc.write(conv::Itoa(i)) + self.oc.write(")}") + } + + fn copyCall(mut &self, mut m: &BuiltinCopyCallExprModel) { + self.oc.write("jule::copy(") + self.possibleRefExpr(m.Dest.Model) + self.oc.write(", ") + self.possibleRefExpr(m.Src.Model) + self.oc.write(")") + } + + fn lenCall(mut &self, mut m: &BuiltinLenCallExprModel) { + self.possibleRefExpr(m.Expr.Model) + self.oc.write(".len()") + } + + fn capCall(mut &self, mut m: &BuiltinCapCallExprModel) { + self.possibleRefExpr(m.Expr.Model) + self.oc.write(".cap()") + } + + fn deleteCall(mut &self, mut m: &BuiltinDeleteCallExprModel) { + self.possibleRefExpr(m.Dest.Model) + if m.Key != nil { + self.oc.write(".del(") + self.possibleRefExpr(m.Key.Model) + self.oc.write(")") + } else { + self.oc.write(".clear()") + } + } + + fn makeCallSlice(mut &self, mut &m: &BuiltinMakeCallExprModel) { + mut slice := m.Kind.Slc() + self.oc.tc.kind(self.oc.Buf, m.Kind) + self.oc.write("::alloc(") + self.possibleRefExpr(m.Len) + self.oc.write(", ") + if m.Cap != nil { + self.possibleRefExpr(m.Cap) + } else { + self.possibleRefExpr(m.Len) + } + if shouldInitialized(slice.Elem) { + self.oc.write(", ") + self.initExpr(slice.Elem) + } + self.oc.write(")") + } + + fn makeCallStr(mut &self, mut &m: &BuiltinMakeCallExprModel) { + self.oc.write(typeCoder.Str) + self.oc.write("::alloc(") + self.possibleRefExpr(m.Len) + if m.Cap != nil { + self.oc.write(", ") + self.possibleRefExpr(m.Cap) + } + self.oc.write(")") + } + + fn makeCall(mut &self, mut m: &BuiltinMakeCallExprModel) { + if m.Kind.Slc() != nil { + self.makeCallSlice(m) + ret + } + self.makeCallStr(m) + } + + fn pushToSlice(mut &self, mut m: &PushToSliceExprModel) { + // Use l-value advantage and define reference variable to destination + // in the child scope to avoid potential repeated high-cost memory access overhead. + const destIdent = "__jule_push_dest" + + self.oc.write("{ ") + self.oc.tc.asSlice(self.oc.Buf, m.Elems.ElemKind) + + mut ptr := false + match type m.Dest { + | &UnaryExprModel: + // Use raw pointer directly if exist. + mut u := (&UnaryExprModel)(m.Dest) + if u.Expr.Kind.Ptr() != nil { + self.oc.write(" *" + destIdent + " = ") + self.possibleRefExpr(u.Expr.Model) + self.oc.write("; ") + ptr = true + break + } + fall + |: + self.oc.write(" &" + destIdent + " = ") + self.possibleRefExpr(m.Dest) + self.oc.write("; ") + } + // Pushed single item. + if len(m.Elems.Elems) == 1 { + if ptr { + self.oc.write(destIdent + "->push(") + } else { + self.oc.write(destIdent + ".push(") + } + self.possibleRefExpr(m.Elems.Elems[0]) + self.oc.write("); }") + ret + } + // Pushed more than single item. + // Pre-allocate enough capacity if not exist for appendation. + if ptr { + self.oc.write(destIdent + "->alloc_for_append(") + } else { + self.oc.write(destIdent + ".alloc_for_append(") + } + self.oc.write(conv::Itoa(len(m.Elems.Elems))) + self.oc.write("); ") + for (_, mut e) in m.Elems.Elems { + self.oc.write(destIdent) + // Use the "__push" method to skip allocation boundary checking. + if ptr { + self.oc.write("->__push(") + } else { + self.oc.write(".__push(") + } + self.possibleRefExpr(e) + self.oc.write("); ") + } + self.oc.write("}") + } + + fn appendToSlice(mut &self, mut m: &AppendToSliceExprModel) { + self.oc.write("(") + self.possibleRefExpr(m.Dest) + self.oc.write(").append(") + self.possibleRefExpr(m.Slice) + self.oc.write(");") + } + + fn appendCall(mut &self, mut m: &BuiltinAppendCallExprModel) { + self.oc.write("jule::append(") + self.possibleRefExpr(m.Dest) + self.oc.write(",") + self.possibleRefExpr(m.Elements) + self.oc.write(")") + } + + fn sizeof(mut &self, mut m: &SizeofExprModel) { + self.oc.write("sizeof(") + self.possibleRefExpr(m.Expr) + self.oc.write(")") + } + + fn alignof(mut &self, mut m: &AlignofExprModel) { + self.oc.write("alignof(") + self.possibleRefExpr(m.Expr) + self.oc.write(")") + } + + fn runeLit(mut &self, m: &RuneExprModel) { + if m.Code <= 127 { // ASCII. + self.oc.Buf.WriteByte('\'') + mut b := sbtoa(byte(m.Code)) + if b == "'" { + self.oc.Buf.WriteByte('\\') + } + self.oc.Buf.WriteStr(b) + self.oc.Buf.WriteByte('\'') + ret + } + itoa(self.oc.Buf, i64(m.Code)) + } + + fn structureStatic(mut &self, mut m: &StructStaticIdentExprModel) { + identCoder.funcIns(self.oc.Buf, m.Method) + } + + fn integratedToStr(mut &self, mut m: &IntegratedToStrExprModel) { + self.oc.write("jule::to_str(") + self.possibleRefExpr(m.Expr) + self.oc.write(")") + } + + fn backendEmit(mut &self, mut m: &BackendEmitExprModel) { + if len(m.Exprs) == 0 { + self.oc.write(m.Code) + ret + } + n := self.oc.Buf.Len() + mut args := make([]any, len(m.Exprs)) + for (i, mut expr) in m.Exprs { + self.possibleRefExpr(expr) + mut buf := unsafe { self.oc.Buf.Buf() } + args[i] = str(buf[n:]) + unsafe { self.oc.Buf.SetBuf(buf[:n]) } + } + self.oc.write(fmt::Format(m.Code, args...)) + } + + fn free(mut &self, mut m: &FreeExprModel) { + self.possibleRefExpr(m.Expr) + if env::RC { + self.oc.write(".dealloc()") + ret + } + self.oc.write(".__free()") + } + + fn strComp(mut &self, mut m: &StrCompExprModel) { + if m.NotEq { + self.oc.write("(!") + } + s := m.Right.ReadStr() + self.possibleRefExpr(m.Left) + self.oc.write(".equal(") + cstrLit(self.oc.Buf, s) + self.oc.write(", ") + self.oc.write(conv::Itoa(len(s))) + self.oc.write(")") + if m.NotEq { + self.oc.write(")") + } + } + + fn emptyCompare(mut &self, mut m: &EmptyCompareExprModel) { + if m.Neg { + self.oc.write("!") + } + self.oc.write("(") + self.possibleRefExpr(m.Expr) + self.oc.write(").empty()") + } + + fn unsafeDeref(mut &self, mut m: &UnsafeDerefExprModel) { + match { + | m.Base.Expr.Kind.Sptr() != nil: + self.oc.write("(*") + self.possibleRefExpr(m.Base.Expr.Model) + self.oc.write(".alloc)") + |: + panic("implementation mistake, this panic call should be unreachable") + } + } + + fn unsafeCasting(mut &self, mut m: &UnsafeCastingExprModel) { + match { + | obj::IsAny(m.Base.ExprKind): + self.possibleRefExpr(m.Base.Expr.Model) + if m.Base.Kind.Sptr() != nil { + self.oc.write(".unsafe_cast_ptr<") + self.oc.tc.kind(self.oc.Buf, m.Base.Kind.Sptr().Elem) + } else { + self.oc.write(".unsafe_cast<") + self.oc.tc.kind(self.oc.Buf, m.Base.Kind) + } + self.oc.write(">()") + |: + panic("implementation mistake, this panic call should be unreachable") + } + } + + fn model(mut &self, mut m: compExprModel) { + match type m { + | str: + self.oc.write(str(m)) + | &TypeKind: + self.oc.tc.kind(self.oc.Buf, (&TypeKind)(m)) + | &Const: + self.constant((&Const)(m)) + | &Var: + self.var((&Var)(m)) + | &StructIns: + self.structureIns((&StructIns)(m)) + | &FnIns: + self.funcInsCommon((&FnIns)(m)) + | &UnsafeBinaryExprModel: + self.unsafeBinary((&UnsafeBinaryExprModel)(m).Node) + | &BinaryExprModel: + self.binary((&BinaryExprModel)(m)) + | &UnaryExprModel: + self.unary((&UnaryExprModel)(m)) + | &StructLitExprModel: + self.structureLit((&StructLitExprModel)(m)) + | &AllocStructLitExprModel: + self.allocStructure((&AllocStructLitExprModel)(m)) + | &CastingExprModel: + self.casting((&CastingExprModel)(m)) + | &FnCallExprModel: + self.funcCall((&FnCallExprModel)(m)) + | &SliceExprModel: + self.slice((&SliceExprModel)(m)) + | &ArrayExprModel: + self.array((&ArrayExprModel)(m)) + | &UnsafeIndexingExprModel: + self.unsafeIndexing((&UnsafeIndexingExprModel)(m)) + | &IndexingExprModel: + self.indexing((&IndexingExprModel)(m)) + | &AnonFnExprModel: + self.anonFunc((&AnonFnExprModel)(m)) + | &MapExprModel: + self.mapExpr((&MapExprModel)(m)) + | &SlicingExprModel: + self.slicing((&SlicingExprModel)(m)) + | &TraitSubIdentExprModel: + self.traitSub((&TraitSubIdentExprModel)(m)) + | &StructSubIdentExprModel: + self.structureSub((&StructSubIdentExprModel)(m)) + | &TupleExprModel: + self.tuple((&TupleExprModel)(m)) + | &BuiltinOutCallExprModel: + self.outCall((&BuiltinOutCallExprModel)(m)) + | &BuiltinOutlnCallExprModel: + self.outlnCall((&BuiltinOutlnCallExprModel)(m)) + | &BuiltinNewCallExprModel: + self.newCall((&BuiltinNewCallExprModel)(m)) + | &BuiltinPanicCallExprModel: + self.panicCall((&BuiltinPanicCallExprModel)(m)) + | &BuiltinAssertCallExprModel: + self.assertCall((&BuiltinAssertCallExprModel)(m)) + | &BuiltinErrorCallExprModel: + self.errorCall((&BuiltinErrorCallExprModel)(m)) + | &BuiltinMakeCallExprModel: + self.makeCall((&BuiltinMakeCallExprModel)(m)) + | &BuiltinAppendCallExprModel: + self.appendCall((&BuiltinAppendCallExprModel)(m)) + | &BuiltinCopyCallExprModel: + self.copyCall((&BuiltinCopyCallExprModel)(m)) + | &BuiltinLenCallExprModel: + self.lenCall((&BuiltinLenCallExprModel)(m)) + | &BuiltinCapCallExprModel: + self.capCall((&BuiltinCapCallExprModel)(m)) + | &BuiltinDeleteCallExprModel: + self.deleteCall((&BuiltinDeleteCallExprModel)(m)) + | &SizeofExprModel: + self.sizeof((&SizeofExprModel)(m)) + | &AlignofExprModel: + self.alignof((&AlignofExprModel)(m)) + | &RuneExprModel: + self.runeLit((&RuneExprModel)(m)) + | &StructStaticIdentExprModel: + self.structureStatic((&StructStaticIdentExprModel)(m)) + | &IntegratedToStrExprModel: + self.integratedToStr((&IntegratedToStrExprModel)(m)) + | &BackendEmitExprModel: + self.backendEmit((&BackendEmitExprModel)(m)) + | &FreeExprModel: + self.free((&FreeExprModel)(m)) + | &StrCompExprModel: + self.strComp((&StrCompExprModel)(m)) + | &RefExprModel: + self.var((&RefExprModel)(m).Var) + | &EmptyCompareExprModel: + self.emptyCompare((&EmptyCompareExprModel)(m)) + | &UnsafeDerefExprModel: + self.unsafeDeref((&UnsafeDerefExprModel)(m)) + | &UnsafeCastingExprModel: + self.unsafeCasting((&UnsafeCastingExprModel)(m)) + |: + self.oc.write("") + } + } + + fn initExpr(mut &self, mut t: &TypeKind) { + if t.NilCompatible() { + if t.Ptr() != nil { + self.oc.write("nullptr") + } else { + self.oc.tc.kind(self.oc.Buf, t) + self.oc.write("(nullptr)") + } + ret + } + mut tup := t.Tup() + if tup != nil { + self.oc.tc.rc.tup(self.oc.Buf, tup) + self.oc.write("{") + for (i, mut tt) in tup.Types { + if !shouldInitialized(tt) { + continue + } + self.oc.write("." + resultArgName) + self.oc.write(conv::Itoa(i)) + self.oc.write("=") + self.initExpr(tt) + if len(tup.Types)-i > 1 { + self.oc.write(", ") + } + } + self.oc.write("}") + ret + } + mut enm := t.Enum() + if enm != nil { + self.model(enm.Items[0].Value.Data.Model) + ret + } + prim := t.Prim() + if prim != nil { + if types::IsNum(prim.Kind) { + self.oc.write("0") + } else if prim.IsBool() { + self.oc.write("false") + } else if prim.IsStr() { + self.oc.write(typeCoder.Str + "()") + } + ret + } + if t.Arr() != nil { + mut arr := t.Arr() + self.oc.tc.kind(self.oc.Buf, t) + self.oc.write("(") + self.initExpr(arr.Elem) + self.oc.write(")") + ret + } + mut s := t.Struct() + if s != nil && s.Decl.Binded && obj::FindDirective(s.Decl.Directives, Directive.Typedef) == nil { + self.oc.write("(") + self.oc.tc.kind(self.oc.Buf, t) + self.oc.write("){}") + ret + } + self.oc.tc.kind(self.oc.Buf, t) + self.oc.write("()") + } } fn decomposeCommonEsq(b: byte): str { - match b { - | '\\': - ret "\\\\" - | '\'': - ret "'" - | '"': - ret `\"` - | '\a': - ret `\a` - | '\b': - ret `\b` - | '\f': - ret `\f` - | '\n': - ret `\n` - | '\r': - ret `\r` - | '\t': - ret `\t` - | '\v': - ret `\v` - |: - ret "" - } + match b { + | '\\': + ret "\\\\" + | '\'': + ret "'" + | '"': + ret `\"` + | '\a': + ret `\a` + | '\b': + ret `\b` + | '\f': + ret `\f` + | '\n': + ret `\n` + | '\r': + ret `\r` + | '\t': + ret `\t` + | '\v': + ret `\v` + |: + ret "" + } } fn sbtoa(b: byte): str { - if b == 0 { - ret "\\x00" - } - if b < utf8::RuneSelf { // ASCII, fast way. - seq := decomposeCommonEsq(b) - if seq != "" { - ret seq - } - if 32 <= b && b <= 126 { - ret str(b) - } - } - seq := conv::FmtUint(u64(b), 8) - if len(seq) == 2 { - ret "\\0" + seq - } - ret "\\" + seq + if b == 0 { + ret "\\x00" + } + if b < utf8::RuneSelf { // ASCII, fast way. + seq := decomposeCommonEsq(b) + if seq != "" { + ret seq + } + if 32 <= b && b <= 126 { + ret str(b) + } + } + seq := conv::FmtUint(u64(b), 8) + if len(seq) == 2 { + ret "\\0" + seq + } + ret "\\" + seq } fn cstrBytes(mut &s: StrBuilder, ctx: str) { - for _, b in ctx { - s.WriteStr(sbtoa(b)) - } + for _, b in ctx { + s.WriteStr(sbtoa(b)) + } } fn cstrLit(mut &s: StrBuilder, ctx: str) { - s.WriteByte('"') - cstrBytes(s, ctx) - s.WriteByte('"') + s.WriteByte('"') + cstrBytes(s, ctx) + s.WriteByte('"') } fn ftoa(mut &s: StrBuilder, f: f64, bitsize: int) { - if bitsize != 32 { - if f == f64(i64(f)) { - itoa(s, i64(f)) - ret - } - if f == f64(u64(f)) { - utoa(s, u64(f)) - ret - } - } - m := conv::FmtFloat(f, 'f', -1, bitsize) - s.WriteStr(m) - if !strings::Contains(m, ".") { - s.WriteStr(".0") - } + if bitsize != 32 { + if f == f64(i64(f)) { + itoa(s, i64(f)) + ret + } + if f == f64(u64(f)) { + utoa(s, u64(f)) + ret + } + } + m := conv::FmtFloat(f, 'f', -1, bitsize) + s.WriteStr(m) + if !strings::Contains(m, ".") { + s.WriteStr(".0") + } } fn itoa(mut &s: StrBuilder, x: i64) { - match { - | x == MaxI64: - s.WriteStr("jule::MAX_I64") - ret - | x == MinI64: - s.WriteStr("jule::MIN_I64") - ret - } - - s.WriteStr(conv::FmtInt(x, 10)) - if Is64Bit(Arch) { - s.WriteByte('L') - } - s.WriteByte('L') + match { + | x == MaxI64: + s.WriteStr("jule::MAX_I64") + ret + | x == MinI64: + s.WriteStr("jule::MIN_I64") + ret + } + + s.WriteStr(conv::FmtInt(x, 10)) + if Is64Bit(Arch) { + s.WriteByte('L') + } + s.WriteByte('L') } fn utoa(mut &s: StrBuilder, x: u64) { - match { - | x == MaxU64: - s.WriteStr("jule::MAX_U64") - ret - } - - s.WriteStr(conv::FmtUint(x, 10)) - if Is64Bit(Arch) { - s.WriteByte('L') - } - s.WriteStr("LU") + match { + | x == MaxU64: + s.WriteStr("jule::MAX_U64") + ret + } + + s.WriteStr(conv::FmtUint(x, 10)) + if Is64Bit(Arch) { + s.WriteByte('L') + } + s.WriteStr("LU") } \ No newline at end of file diff --git a/src/julec/obj/cxx/ident.jule b/src/julec/obj/cxx/ident.jule index 5324e9dd4..5fad8ec3c 100644 --- a/src/julec/obj/cxx/ident.jule +++ b/src/julec/obj/cxx/ident.jule @@ -9,14 +9,14 @@ use conv for std::conv use std::jule::build::{EntryPoint, Directive} use std::jule::lex::{TokenKind, IsAnonIdent, IsIgnoreIdent} use std::jule::sema::{ - Fn, - FnIns, - Trait, - Struct, - StructIns, - Field, - Var, - Param, + Fn, + FnIns, + Trait, + Struct, + StructIns, + Field, + Var, + Param, } use utf8 for std::unicode::utf8 use std::strings::{StrBuilder} @@ -27,190 +27,190 @@ const initCallerIdent = "__jule_call_initializers" struct identCoder {} impl identCoder { - const Self = "_self_" - - // Write identifiers to buf. If identifier contains unicode runes, - // handle as ASCII characters. Some backend compilers are not supports - // unicode identifiers and causes compile errors. - static fn writeIdentTo(mut &buf: StrBuilder, &ident: str) { - for _, b in ident { - if b >= utf8::RuneSelf { - // ident contains unicode runes. - goto unicode - } - } - // ident is ASCII, append directly. - buf.WriteStr(ident) - ret - unicode: - for _, r in []rune(ident) { - if r < utf8::RuneSelf { // ASCII - // Cast to byte to enable compiler optimization. - // Append directy to buf. - buf.WriteByte(byte(r)) - continue - } - // Unicode, handle as ASCII. - buf.WriteStr(conv::FmtInt(i64(r), 0xF)) - } - } - - // Writes cpp output identifier form of given identifier. - // - // Parameters: - // - ident: Identifier. - // - addr: Pointer address of package file handler. - static fn toOut(mut &buf: StrBuilder, ident: str, addr: uintptr) { - buf.WriteByte('_') - if addr != 0 { - buf.WriteStr(conv::FmtUint(u64(addr), 0xF)) - buf.WriteByte('_') - } - identCoder.writeIdentTo(buf, ident) - } - - // Writes cpp output local identifier form of given identifier. - // - // Parameters: - // - row: Row of definition. - // - col: Column of definition. - // - ident: Identifier of definition. - static fn toLocal(mut &buf: StrBuilder, row: int, col: int, &ident: str) { - buf.WriteByte('_') - buf.WriteStr(conv::Itoa(row)) - buf.WriteStr(conv::Itoa(col)) - buf.WriteByte('_') - identCoder.writeIdentTo(buf, ident) - } - - static fn func(mut &buf: StrBuilder, &f: &Fn) { - match { - | f.Binded: - buf.WriteStr(f.Ident) - ret - | f.Ident == EntryPoint: - buf.WriteStr("entry_point") - ret - | f.IsMethod(): - if f.Statically { - buf.WriteStr("static_") - } - } - identCoder.toOut(buf, f.Ident, uintptr(f)) - } - - static fn funcIns(mut &buf: StrBuilder, &f: &FnIns) { - if f.IsBuiltin() { - // Do not use [identCoder.writeIdentTo] for this. - // Built-in functions are always ASCII. - buf.WriteStr("jule::") - buf.WriteStr(f.Decl.Ident) - ret - } - if f.Decl.Binded || len(f.Generics) == 0 { - identCoder.func(buf, f.Decl) - ret - } - identCoder.toOut(buf, f.Decl.Ident, uintptr(f)) - } - - static fn traitDecl(mut &buf: StrBuilder, t: &Trait) { - identCoder.toOut(buf, t.Ident, uintptr(t)) - } - - static fn param(mut &buf: StrBuilder, &p: &Param) { - if IsAnonIdent(p.Ident) || IsIgnoreIdent(p.Ident) { - ret - } - if p.IsSelf() { - buf.WriteStr(identCoder.Self) - ret - } - if p.Token == nil { - identCoder.toLocal(buf, 0, 0, p.Ident) - ret - } - identCoder.toLocal(buf, p.Token.Row, p.Token.Column, p.Ident) - } - - static fn structure(mut &buf: StrBuilder, &s: &Struct) { - if s.Binded { - if !obj::HasDirective(s.Directives, Directive.Typedef) { - buf.WriteStr("struct ") - } - buf.WriteStr(s.Ident) - ret - } - identCoder.toOut(buf, s.Ident, uintptr(s)) - } - - static fn structureIns(mut &buf: StrBuilder, &s: &StructIns) { - if s.Decl.Binded || len(s.Generics) == 0 { - identCoder.structure(buf, s.Decl) - ret - } - identCoder.toOut(buf, s.Decl.Ident, uintptr(s)) - } - - static fn field(mut &buf: StrBuilder, &f: &Field) { - if f.Owner.Binded { - buf.WriteStr(f.Ident) - ret - } - buf.WriteStr("_field_") - identCoder.writeIdentTo(buf, f.Ident) - } - - // Returns output identifier of variable. - static fn var(mut &buf: StrBuilder, mut v: &Var) { - match { - | v.Binded: - buf.WriteStr(v.Ident) - | v.Ident == TokenKind.Error: - buf.WriteStr("except.error") - | v.Ident == TokenKind.Self: - buf.WriteStr(identCoder.Self) - | v.RetOrder == -1: - // The single return variable is just this one. - // Return directly [resultName] because of generated with this identifier. - buf.WriteStr(resultName) - | v.RetOrder >= 0: - buf.WriteStr(resultName + "." + resultArgName) - buf.WriteStr(conv::Itoa(v.RetOrder)) - | v.Scope != nil: - identCoder.toLocal(buf, v.Token.Row, v.Token.Column, v.Ident) - |: - identCoder.toOut(buf, v.Ident, uintptr(v)) - } - } - - static fn iterBegin(mut &buf: StrBuilder, it: uintptr) { - buf.WriteStr("_iter_begin_") - buf.WriteStr(conv::FmtUint(u64(it), 0xF)) - } - - static fn iterEnd(mut &buf: StrBuilder, it: uintptr) { - buf.WriteStr("_iter_end_") - buf.WriteStr(conv::FmtUint(u64(it), 0xF)) - } - - static fn iterNext(mut &buf: StrBuilder, it: uintptr) { - buf.WriteStr("_iter_next_") - buf.WriteStr(conv::FmtUint(u64(it), 0xF)) - } - - static fn label(mut &buf: StrBuilder, u: uintptr) { - buf.WriteStr("_julec_label_") - buf.WriteStr(conv::FmtUint(u64(u), 0xF)) - } - - static fn matchEnd(mut &buf: StrBuilder, m: uintptr) { - buf.WriteStr("_match_end_") - buf.WriteStr(conv::FmtUint(u64(m), 0xF)) - } - - static fn caseBegin(mut &buf: StrBuilder, c: uintptr) { - buf.WriteStr("_case_begin_") - buf.WriteStr(conv::FmtUint(u64(c), 0xF)) - } + const Self = "_self_" + + // Write identifiers to buf. If identifier contains unicode runes, + // handle as ASCII characters. Some backend compilers are not supports + // unicode identifiers and causes compile errors. + static fn writeIdentTo(mut &buf: StrBuilder, &ident: str) { + for _, b in ident { + if b >= utf8::RuneSelf { + // ident contains unicode runes. + goto unicode + } + } + // ident is ASCII, append directly. + buf.WriteStr(ident) + ret + unicode: + for _, r in []rune(ident) { + if r < utf8::RuneSelf { // ASCII + // Cast to byte to enable compiler optimization. + // Append directy to buf. + buf.WriteByte(byte(r)) + continue + } + // Unicode, handle as ASCII. + buf.WriteStr(conv::FmtInt(i64(r), 0xF)) + } + } + + // Writes cpp output identifier form of given identifier. + // + // Parameters: + // - ident: Identifier. + // - addr: Pointer address of package file handler. + static fn toOut(mut &buf: StrBuilder, ident: str, addr: uintptr) { + buf.WriteByte('_') + if addr != 0 { + buf.WriteStr(conv::FmtUint(u64(addr), 0xF)) + buf.WriteByte('_') + } + identCoder.writeIdentTo(buf, ident) + } + + // Writes cpp output local identifier form of given identifier. + // + // Parameters: + // - row: Row of definition. + // - col: Column of definition. + // - ident: Identifier of definition. + static fn toLocal(mut &buf: StrBuilder, row: int, col: int, &ident: str) { + buf.WriteByte('_') + buf.WriteStr(conv::Itoa(row)) + buf.WriteStr(conv::Itoa(col)) + buf.WriteByte('_') + identCoder.writeIdentTo(buf, ident) + } + + static fn func(mut &buf: StrBuilder, &f: &Fn) { + match { + | f.Binded: + buf.WriteStr(f.Ident) + ret + | f.Ident == EntryPoint: + buf.WriteStr("entry_point") + ret + | f.IsMethod(): + if f.Statically { + buf.WriteStr("static_") + } + } + identCoder.toOut(buf, f.Ident, uintptr(f)) + } + + static fn funcIns(mut &buf: StrBuilder, &f: &FnIns) { + if f.IsBuiltin() { + // Do not use [identCoder.writeIdentTo] for this. + // Built-in functions are always ASCII. + buf.WriteStr("jule::") + buf.WriteStr(f.Decl.Ident) + ret + } + if f.Decl.Binded || len(f.Generics) == 0 { + identCoder.func(buf, f.Decl) + ret + } + identCoder.toOut(buf, f.Decl.Ident, uintptr(f)) + } + + static fn traitDecl(mut &buf: StrBuilder, t: &Trait) { + identCoder.toOut(buf, t.Ident, uintptr(t)) + } + + static fn param(mut &buf: StrBuilder, &p: &Param) { + if IsAnonIdent(p.Ident) || IsIgnoreIdent(p.Ident) { + ret + } + if p.IsSelf() { + buf.WriteStr(identCoder.Self) + ret + } + if p.Token == nil { + identCoder.toLocal(buf, 0, 0, p.Ident) + ret + } + identCoder.toLocal(buf, p.Token.Row, p.Token.Column, p.Ident) + } + + static fn structure(mut &buf: StrBuilder, &s: &Struct) { + if s.Binded { + if !obj::HasDirective(s.Directives, Directive.Typedef) { + buf.WriteStr("struct ") + } + buf.WriteStr(s.Ident) + ret + } + identCoder.toOut(buf, s.Ident, uintptr(s)) + } + + static fn structureIns(mut &buf: StrBuilder, &s: &StructIns) { + if s.Decl.Binded || len(s.Generics) == 0 { + identCoder.structure(buf, s.Decl) + ret + } + identCoder.toOut(buf, s.Decl.Ident, uintptr(s)) + } + + static fn field(mut &buf: StrBuilder, &f: &Field) { + if f.Owner.Binded { + buf.WriteStr(f.Ident) + ret + } + buf.WriteStr("_field_") + identCoder.writeIdentTo(buf, f.Ident) + } + + // Returns output identifier of variable. + static fn var(mut &buf: StrBuilder, mut v: &Var) { + match { + | v.Binded: + buf.WriteStr(v.Ident) + | v.Ident == TokenKind.Error: + buf.WriteStr("except.error") + | v.Ident == TokenKind.Self: + buf.WriteStr(identCoder.Self) + | v.RetOrder == -1: + // The single return variable is just this one. + // Return directly [resultName] because of generated with this identifier. + buf.WriteStr(resultName) + | v.RetOrder >= 0: + buf.WriteStr(resultName + "." + resultArgName) + buf.WriteStr(conv::Itoa(v.RetOrder)) + | v.Scope != nil: + identCoder.toLocal(buf, v.Token.Row, v.Token.Column, v.Ident) + |: + identCoder.toOut(buf, v.Ident, uintptr(v)) + } + } + + static fn iterBegin(mut &buf: StrBuilder, it: uintptr) { + buf.WriteStr("_iter_begin_") + buf.WriteStr(conv::FmtUint(u64(it), 0xF)) + } + + static fn iterEnd(mut &buf: StrBuilder, it: uintptr) { + buf.WriteStr("_iter_end_") + buf.WriteStr(conv::FmtUint(u64(it), 0xF)) + } + + static fn iterNext(mut &buf: StrBuilder, it: uintptr) { + buf.WriteStr("_iter_next_") + buf.WriteStr(conv::FmtUint(u64(it), 0xF)) + } + + static fn label(mut &buf: StrBuilder, u: uintptr) { + buf.WriteStr("_julec_label_") + buf.WriteStr(conv::FmtUint(u64(u), 0xF)) + } + + static fn matchEnd(mut &buf: StrBuilder, m: uintptr) { + buf.WriteStr("_match_end_") + buf.WriteStr(conv::FmtUint(u64(m), 0xF)) + } + + static fn caseBegin(mut &buf: StrBuilder, c: uintptr) { + buf.WriteStr("_case_begin_") + buf.WriteStr(conv::FmtUint(u64(c), 0xF)) + } } \ No newline at end of file diff --git a/src/julec/obj/cxx/object.jule b/src/julec/obj/cxx/object.jule index ea0f509ad..f08b355d8 100644 --- a/src/julec/obj/cxx/object.jule +++ b/src/julec/obj/cxx/object.jule @@ -10,33 +10,33 @@ use conv for std::conv use comptime for std::comptime use jule for std::jule use build for std::jule::build::{ - Directive, + Directive, } use std::jule::lex::{ - Token, - TokenId, - IsIgnoreIdent, - IsAnonIdent, + Token, + TokenId, + IsIgnoreIdent, + IsAnonIdent, } use std::jule::sema::{ - FuncPattern, - Package, - SymbolTable, - Param, - ParamIns, - Trait, - Struct, - FieldIns, - Var, - StructIns, - Fn, - FnIns, - TypeKind, - Prim, - Sptr, - TypeSymbol, - Operators, - AnonFnExprModel, + FuncPattern, + Package, + SymbolTable, + Param, + ParamIns, + Trait, + Struct, + FieldIns, + Var, + StructIns, + Fn, + FnIns, + TypeKind, + Prim, + Sptr, + TypeSymbol, + Operators, + AnonFnExprModel, } use types for std::jule::types use path for std::fs::path @@ -53,1331 +53,1331 @@ const indentKind = '\t' // General pointer type for GC pointers. static mut generalGCPtr = &TypeKind{ - Kind: &Sptr{ - Elem: &TypeKind{ - Kind: &Prim{ - Kind: types::TypeKind.Uintptr, - }, - }, - }, + Kind: &Sptr{ + Elem: &TypeKind{ + Kind: &Prim{ + Kind: types::TypeKind.Uintptr, + }, + }, + }, } struct SerializationInfo { - Compiler: str - CompilerCommand: str + Compiler: str + CompilerCommand: str } struct traitCast { - t1: &Trait - t2: &Trait + t1: &Trait + t2: &Trait } struct anonHash { - expr: &AnonFnExprModel - ident: str + expr: &AnonFnExprModel + ident: str } struct ObjectCoder { - // Internal buffer which is commonly used. - Buf: StrBuilder + // Internal buffer which is commonly used. + Buf: StrBuilder - resultDecls: StrBuilder // Struct wrappers for multi-ret function types. - anyObj: StrBuilder // Type handlers and others for the type. - anonObj: StrBuilder // Anonymous functions. - deallocObj: StrBuilder // Deallocation function for [self.deallocated] types. + resultDecls: StrBuilder // Struct wrappers for multi-ret function types. + anyObj: StrBuilder // Type handlers and others for the type. + anonObj: StrBuilder // Anonymous functions. + deallocObj: StrBuilder // Deallocation function for [self.deallocated] types. - ir: &IR - info: SerializationInfo - anons: []&anonHash - deallocated: []&TypeKind // GC deallocated types for dynamic programming. + ir: &IR + info: SerializationInfo + anons: []&anonHash + deallocated: []&TypeKind // GC deallocated types for dynamic programming. - // Current indentation. - indentBuffer: []byte + // Current indentation. + indentBuffer: []byte - resultMap: map[str]bool - anyTypeMap: []&TypeKind - traitCastMap: []traitCast + resultMap: map[str]bool + anyTypeMap: []&TypeKind + traitCastMap: []traitCast - // Pairs for methods and structure instances. - // Used to avoid duplicated wrapper function generation. - traitMetMap: map[&FnIns][]uintptr + // Pairs for methods and structure instances. + // Used to avoid duplicated wrapper function generation. + traitMetMap: map[&FnIns][]uintptr - ec: &exprCoder - sc: &scopeCoder - tc: &typeCoder + ec: &exprCoder + sc: &scopeCoder + tc: &typeCoder - headPos: int - declPos: int - wrapPos: int + headPos: int + declPos: int + wrapPos: int } impl ObjectCoder { - static fn New(mut &ir: &IR, info: SerializationInfo): &ObjectCoder { - mut oc := &ObjectCoder{ - ir: ir, - info: info, - } - oc.ec = exprCoder.new(oc) - oc.sc = scopeCoder.new(oc) - oc.tc = typeCoder.new(oc) - ret oc - } - - fn write(mut &self, s: str) { - self.Buf.WriteStr(s) - } - - fn writeBytes(mut &self, b: []byte) { - self.Buf.Write(b) - } - - // Increase indentation. - fn addIndent(mut &self) { - self.indentBuffer = append(self.indentBuffer, indentKind) - } - - // Decrase indentation. - fn doneIndent(mut &self) { - self.indentBuffer = self.indentBuffer[:len(self.indentBuffer)-1] - } - - // Writes indention string by indentBuffer. - fn indent(mut &self) { - self.Buf.Write(self.indentBuffer) - } - - fn findAnyType(mut &self, mut &t: &TypeKind): int { - for (i, mut at) in self.anyTypeMap { - if at.Equal(t) { - ret i - } - } - ret -1 - } - - fn pushDealloc(mut &self, mut t: &TypeKind): int { - for i, dt in self.deallocated { - if dt.Equal(t) { - ret i - } - } - i := len(self.deallocated) - self.deallocated = append(self.deallocated, t) - self.deallocObj.WriteStr("void " + deallocatedTypeIdent) - self.deallocObj.WriteStr(conv::Itoa(i)) - self.deallocObj.WriteStr("(jule::Ptr &alloc) noexcept { alloc.__as<") - self.tc.kind(self.deallocObj, t) - self.deallocObj.WriteStr(">().dealloc(); }\n") - ret i - } - - fn pushAnonFn(mut &self, mut &m: &AnonFnExprModel): (ident: str) { - closure := obj::IsClosure(m) - if closure { // Closure? - // Handle identifier and generate ctx. - self.anonObj.WriteStr("struct ") - l := self.anonObj.Len() - self.anonObj.WriteStr("__jule_anon_") - self.anonObj.WriteStr(conv::FmtUint(u64(uintptr(m.Func)), 0xF)) - ident = str(unsafe { self.anonObj.Buf()[l:] }) - self.anonObj.WriteStr(anonFnCtxSuffix + "{\n") - for (_, mut v) in m.Captured { - self.anonObj.WriteByte(indentKind) // 1x indent - self.tc.kind(self.anonObj, v.Kind.Kind) - self.anonObj.WriteByte(' ') - if v.Reference { - self.anonObj.WriteByte('*') - } - identCoder.var(self.anonObj, v) - self.anonObj.WriteStr(";\n") - } - self.anonObj.WriteStr("};\n") - - // Ctx handler function. - self.anonObj.WriteStr("static void ") - self.anonObj.WriteStr(ident) - self.anonObj.WriteStr(anonFnCtxHandlerSuffix + "(jule::Ptr<" + typeCoder.Uintptr + "> &ptr) { ptr.__as<") - self.anonObj.WriteStr(ident) - self.anonObj.WriteStr(anonFnCtxSuffix + ">().dealloc(); }\n") - } else { - ident = "__jule_anon" - ident += conv::FmtUint(u64(uintptr(m.Func)), 0xF) - } - - // Anonymous function. - self.anons = append(self.anons, &anonHash{expr: m, ident: ident}) - self.anonFuncInsDecl(m, ident) - self.anonObj.WriteByte('\n') - ret - } - - fn pushAnyType(mut &self, mut t: &TypeKind): int { - if t.Enum() != nil { - t = t.Enum().Kind.Kind - } - mut i := self.findAnyType(t) - if i != -1 { - ret i - } - i = len(self.anyTypeMap) - self.anyTypeMap = append(self.anyTypeMap, t) - si := conv::Itoa(i) - if t.Sptr() != nil { - mut elemKind := StrBuilder.New(40) - self.tc.kind(elemKind, t.Sptr().Elem) - - // Deallocator function. - di := self.pushDealloc(t.Sptr().Elem) - - // Type structure. - self.anyObj.WriteStr("struct " + typeCoder.Any + "::Type ") - self.anyObj.WriteStr(anyTypeIdent) - self.anyObj.WriteStr(si) - self.anyObj.WriteStr("{.dealloc=" + deallocatedTypeIdent) - self.anyObj.WriteStr(conv::Itoa(di)) - self.anyObj.WriteStr(", .eq=jule::ptr_equal, .to_str=jule::ptr_to_str};\n") - - // comparison function. - self.anyObj.WriteStr(typeCoder.Bool + " " + anyTypeIdent) - self.anyObj.WriteStr(si) - self.anyObj.WriteStr("_compare(const " + typeCoder.Any + " &any, const ") - self.tc.asSptr(self.anyObj, unsafe { elemKind.Buf() }) - self.anyObj.WriteStr(" &other) { return any.type == &" + anyTypeIdent) - self.anyObj.WriteStr(si) - self.anyObj.WriteStr(" && jule::ptr_equal(any.data.alloc, other.alloc); }\n") - } else { - comparable := t.Comparable() - mut kindB := StrBuilder.New(40) - self.tc.kind(kindB, t) - kind := unsafe { kindB.Buf() } - - // Deallocator function. - di := self.pushDealloc(t) - - if comparable { - // eq function. - self.anyObj.WriteStr(typeCoder.Bool + " " + anyTypeIdent) - self.anyObj.WriteStr(si) - self.anyObj.WriteStr("_eq(void *alloc, void *other) noexcept { return *reinterpret_cast<") - self.anyObj.Write(kind) - self.anyObj.WriteStr("*>(alloc) == *reinterpret_cast<") - self.anyObj.Write(kind) - self.anyObj.WriteStr("*>(other); }\n") - } - - // to_str function. - self.anyObj.WriteStr(typeCoder.Str + " " + anyTypeIdent) - self.anyObj.WriteStr(si) - self.anyObj.WriteStr("_to_str(const void *alloc) noexcept { return jule::to_str(*reinterpret_cast<") - if t.Ptr() == nil { - self.anyObj.WriteStr("const ") - self.anyObj.Write(kind) - } else { - self.anyObj.Write(kind) - self.anyObj.WriteStr("* const") - } - self.anyObj.WriteStr("*>(alloc)); }\n") - - // Type structure. - self.anyObj.WriteStr("struct " + typeCoder.Any + "::Type ") - self.anyObj.WriteStr(anyTypeIdent) - self.anyObj.WriteStr(si) - self.anyObj.WriteStr("{.dealloc=" + deallocatedTypeIdent) - self.anyObj.WriteStr(conv::Itoa(di)) - self.anyObj.WriteStr(", ") - if comparable { - self.anyObj.WriteStr(".eq=" + anyTypeIdent) - self.anyObj.WriteStr(si) - self.anyObj.WriteStr("_eq, ") - } - self.anyObj.WriteStr(".to_str=" + anyTypeIdent) - self.anyObj.WriteStr(si) - self.anyObj.WriteStr("_to_str};\n") - - if comparable { - // compare function. - self.anyObj.WriteStr(typeCoder.Bool + " " + anyTypeIdent) - self.anyObj.WriteStr(si) - self.anyObj.WriteStr("_compare(const " + typeCoder.Any + " &any, const ") - self.anyObj.Write(kind) - self.anyObj.WriteStr(" &other) { return any.type == &" + anyTypeIdent) - self.anyObj.WriteStr(si) - self.anyObj.WriteStr(" && " + anyTypeIdent) - self.anyObj.WriteStr(si) - self.anyObj.WriteStr("_eq(any.data.alloc, (void*)&other); }\n") - } - } - ret i - } - - fn pushResultIns(mut &self, mut &f: &FnIns) { - s := str(self.tc.rc.code(f.Result)) - _, ok := self.resultMap[s] - if ok { - ret - } - self.resultMap[s] = false - self.resultDecls.WriteStr("struct ") - self.resultDecls.WriteStr(s) - self.resultDecls.WriteStr(" {\n") - for (i, mut t) in f.Result.Tup().Types { - self.resultDecls.WriteByte(indentKind) - self.tc.kind(self.resultDecls, t) - self.resultDecls.WriteByte(' ') - self.resultDecls.WriteStr(resultArgName) - self.resultDecls.WriteStr(conv::Itoa(i)) - self.resultDecls.WriteStr(";\n") - } - self.resultDecls.WriteStr("};\n") - } - - fn pushResult(mut &self, mut &f: &Fn) { - if f.IsVoid() || len(f.Result.Idents) <= 1 { - ret - } - mut n := len(f.Instances) - if len(f.Generics) == 0 { - n = 1 - } - for (_, mut ins) in f.Instances[:n] { - self.pushResultIns(ins) - } - } - - fn pushAndWriteMaskMapper(mut &self, mut t1: &Trait, mut t2: &Trait) { - mut ident := StrBuilder.New(1 << 5) - ident.WriteStr("__jule_trait_offset_mapper_") - ident.WriteStr(conv::FmtUint(u64(uintptr(t2)), 0xF)) - ident.WriteStr("_to_") - ident.WriteStr(conv::FmtUint(u64(uintptr(t1)), 0xF)) - self.Buf.Write(unsafe { ident.Buf() }) - - // Lookup and push if this match is not exist. - for _, m in self.traitCastMap { - if m.t1 == t1 && m.t2 == t2 { - ret - } - } - - self.traitCastMap = append(self.traitCastMap, traitCast{t1: t1, t2: t2}) - - // Not exist, push. - const data = "data" - self.anyObj.WriteStr("void *") - self.anyObj.Write(unsafe { ident.Buf() }) - self.anyObj.WriteStr("(const void *" + data + ") noexcept { ") - - mut t1Ident := StrBuilder.New(1 << 4) - mut t2Ident := StrBuilder.New(1 << 4) - identCoder.traitDecl(t1Ident, t1) - identCoder.traitDecl(t2Ident, t2) - - for (_, mut s1) in t1.Implemented { - for _, s2 in t2.Implemented { - if s1 == s2 { - for (_, mut s1i) in s1.Instances { - i1 := obj::FindTraitTypeOffsetS(t1, s1i) - i2 := obj::FindTraitTypeOffsetS(t2, s1i) - self.anyObj.WriteStr("if (data == &") - self.anyObj.Write(unsafe { t2Ident.Buf() }) - self.anyObj.WriteStr("_mptr_data") - self.anyObj.WriteStr(conv::Itoa(i2)) - self.anyObj.WriteStr(") return &") - self.anyObj.Write(unsafe { t1Ident.Buf() }) - self.anyObj.WriteStr("_mptr_data") - self.anyObj.WriteStr(conv::Itoa(i1)) - self.anyObj.WriteStr("; ") - } - } - } - } - self.anyObj.WriteStr(" jule::panic(\"trait casting failed because of an implementation mistake, this is a JuleC bug\"); return nullptr; }\n") - } - - // Writes location information of token as cstr bytes. - fn locInfo(mut &self, &t: &Token) { - &loc := t.File.Path - - // Normalize path if production compilation enabled. - if env::Production { - match { - | strings::HasPrefix(loc, build::PathStdlib): - // Remove absolute path prefix of standard library. - // Just keeps "std/" prefix. - cstrBytes(self.Buf, loc[len(path::Dir(build::PathStdlib))+1:]) - | strings::HasPrefix(loc, self.ir.Root): - // Remove absolute path prefix of root package. - // Just keeps "[package_dir]/" prefix. - cstrBytes(self.Buf, loc[len(path::Dir(self.ir.Root))+1:]) - |: - cstrBytes(self.Buf, loc) - } - } else { - cstrBytes(self.Buf, loc) - } - self.write(":") - self.write(conv::Itoa(t.Row)) - self.write(":") - self.write(conv::Itoa(t.Column)) - } - - fn head(mut &self) { - time := Time.Now() - abs := time.Abs() - self.write("// Auto generated by JuleC.\n") - self.write("// JuleC version: ") - self.write(jule::Version) - self.write("\n") - self.write("// Date: ") - self.write(conv::FmtUint(abs.Day, 10)) - self.write("/") - self.write(conv::FmtUint(abs.Month, 10)) - self.write("/") - self.write(conv::FmtUint(abs.Year, 10)) - self.write(" (DD/MM/YYYY) UTC\n//\n// Recomended Compile Command;\n// ") - self.write(self.info.Compiler) - self.write(" ") - self.write(self.info.CompilerCommand) - self.write("\n\n") - - if env::Production { - self.write("#define __JULE_ENABLE__PRODUCTION\n") - } - if !env::RC { - self.write("#define __JULE_DISABLE__REFERENCE_COUNTING\n") - } - if !env::Safety { - self.write("#define __JULE_DISABLE__SAFETY\n") - } - - // Include binded libraries here, before the API header. - // See developer reference (4). - self.links() - - self.write("\n\n#include \"") - self.write(build::PathApi) - self.write("\"\n\n") - } - - fn links(mut &self) { - for _, used in self.ir.Used { - match { - | !used.Binded: - continue - | build::IsStdHeaderPath(used.Path): - self.write("#include ") - self.write(used.Path) - self.write("\n") - | build::IsValidHeaderExt(path::Ext(used.Path)): - self.write("#include \"") - self.write(used.Path) - self.write("\"\n") - } - } - } - - fn prepareStructure(mut self, mut &s: &Struct) { - for (_, mut ins) in s.Instances { - for (_, mut m) in ins.Methods { - if m.Statically { - continue - } - for (_, mut mins) in m.Instances { - mut p := mins.Params[0] - mut kind := StrBuilder.New(40) - self.tc.kind(kind, p.Kind) - if !p.Decl.IsRef() { - kind.WriteStr("*") - } - p.Kind = &TypeKind{ - Kind: &customType{ - kind: kind.Str(), - }, - } - } - } - } - } - - fn prepareStructures(mut &self) { - for (_, mut s) in self.ir.Ordered.Structs { - if s.Token != nil { - self.prepareStructure(s) - } - } - } - - fn structurePlainDecl(mut &self, mut &s: &Struct) { - for (_, mut ins) in s.Instances { - self.write("struct ") - identCoder.structureIns(self.Buf, ins) - self.write(";\n") - } - } - - fn structurePlainDecls(mut &self) { - for (_, mut s) in self.ir.Ordered.Structs { - if s.Token != nil { - self.structurePlainDecl(s) - } - } - } - - fn fieldDecl(mut &self, mut &f: &FieldIns) { - self.tc.kind(self.Buf, f.Kind) - self.write(" ") - identCoder.field(self.Buf, f.Decl) - if f.Default == nil { - if shouldInitialized(f.Kind) { - self.write(" = ") - // No default expression. - // Use default expression of data-type. - self.ec.initExpr(f.Kind) - } - } else { - self.write(" = ") - self.ec.possibleRefExpr(f.Default.Model) - } - self.write(";") - } - - fn structureDestructor(mut &self, mut &s: &StructIns) { - // Dispose method must be non-static - const Static = false - disposeMethod := s.FindMethod("Dispose", Static) - mut disposed := FuncPattern.Dispose(disposeMethod) - // Call destructor if implemented. - if !disposed { - ret - } - self.write("~") - identCoder.structureIns(self.Buf, s) - self.write("(void) { ") - identCoder.func(self.Buf, disposeMethod) - self.write("(this); }") - } - - fn structureOperatorEq(mut &self, ident: []byte, mut &s: &StructIns) { - if !s.Comparable { - ret - } - // Operator overloading. - if s.Operators.Eq != nil { - self.structureOperator(ident, s.Operators.Eq, "==") - ret - } - - self.indent() - if opt::Inline { - self.write("inline ") - } - self.write("bool operator==(") - self.writeBytes(ident) - self.write(" _other) {") - if len(s.Fields) > 0 { - self.addIndent() - self.write("\n") - self.indent() - self.write("return ") - self.addIndent() - mut writed := false - for (_, mut f) in s.Fields { - // Skip binded struct kinds. - strct := f.Kind.Struct() - if strct != nil && strct.Decl != nil && strct.Decl.Binded { - continue - } - if writed { - self.write(" &&") - } - writed = true - self.write("\n") - self.indent() - self.write("this->") - mut fIdent := StrBuilder.New(len(f.Decl.Ident)) - identCoder.field(fIdent, f.Decl) - self.writeBytes(unsafe { fIdent.Buf() }) - self.write(" == _other.") - self.writeBytes(unsafe { fIdent.Buf() }) - } - self.doneIndent() - if !writed { - self.write("true") - } - self.write(";\n") - self.doneIndent() - self.indent() - self.write("}") - } else { - self.write(" return true; }") - } - self.write("\n\n") - } - - fn structureOperatorNotEq(mut &self, ident: []byte, mut &s: &StructIns) { - if !s.Comparable { - ret - } - self.indent() - if opt::Inline { - self.write("inline ") - } - self.write("bool operator!=(") - self.writeBytes(ident) - self.write(" _other) { return !this->operator==(_other); }\n\n") - } - - // Write operator overloading forwarding for reserved function. - fn structureOperator(mut &self, ident: []byte, mut &f: &FnIns, op: str) { - if f == nil { - ret - } - - unary := len(f.Params) == 1 // Just self parameter. - assignment := f.Decl.IsVoid() - - self.indent() - if opt::Inline { - self.write("inline ") - } - if assignment { - self.writeBytes(ident) - self.write("&") - } else { - if f.Result.Prim() == nil { - // If result type is not primitive, always structure's itself. - self.writeBytes(ident) - } else { - // Logical. - self.write(typeCoder.Bool) - } - } - self.write(" operator") - self.write(op) - self.write("(") - if !unary { - mut p := f.Params[1] - self.tc.paramIns(self.Buf, p) - self.write(" _other") - } - self.write(") { ") - if !assignment { - self.write("return ") - } - identCoder.funcIns(self.Buf, f) - if !unary { - self.write("(this, _other); ") - if assignment { - self.write("return *this; ") - } - self.write("}") - } else { - self.write("(this); }") - } - self.write("\n\n") - } - - fn structureOperators(mut &self, mut &s: &StructIns) { - mut sb := StrBuilder.New(40) - identCoder.structureIns(sb, s) - ident := unsafe { sb.Buf() } - - // Binary. - self.structureOperatorEq(ident, s) - self.structureOperatorNotEq(ident, s) - self.structureOperator(ident, s.Operators.Gt, ">") - self.structureOperator(ident, s.Operators.GtEq, ">=") - self.structureOperator(ident, s.Operators.Lt, "<") - self.structureOperator(ident, s.Operators.LtEq, "<=") - self.structureOperator(ident, s.Operators.Shl, "<<") - self.structureOperator(ident, s.Operators.Shr, ">>") - self.structureOperator(ident, s.Operators.Add, "+") - self.structureOperator(ident, s.Operators.Sub, "-") - self.structureOperator(ident, s.Operators.Div, "/") - self.structureOperator(ident, s.Operators.Mul, "*") - self.structureOperator(ident, s.Operators.Mod, "%") - self.structureOperator(ident, s.Operators.BitAnd, "&") - self.structureOperator(ident, s.Operators.BitOr, "|") - self.structureOperator(ident, s.Operators.BitXor, "^") - - // Unary. - self.structureOperator(ident, s.Operators.Neg, "-") - self.structureOperator(ident, s.Operators.Pos, "+") - self.structureOperator(ident, s.Operators.BitNot, "~") - - // Assignment. - self.structureOperator(ident, s.Operators.AddAssign, "+=") - self.structureOperator(ident, s.Operators.SubAssign, "-=") - self.structureOperator(ident, s.Operators.DivAssign, "/=") - self.structureOperator(ident, s.Operators.MulAssign, "*=") - self.structureOperator(ident, s.Operators.ModAssign, "%=") - self.structureOperator(ident, s.Operators.ShlAssign, "<<=") - self.structureOperator(ident, s.Operators.ShrAssign, ">>=") - self.structureOperator(ident, s.Operators.BitOrAssign, "|=") - self.structureOperator(ident, s.Operators.BitAndAssign, "&=") - self.structureOperator(ident, s.Operators.BitXorAssign, "^=") - } - - fn structureInsDecl(mut &self, mut &s: &StructIns) { - for (_, mut m) in s.Methods { - // Operator methods are declared by [structureDecl]. - if isHeadDecl(m) { - self.funcDecl(m, false) - } - } - self.write("struct ") - identCoder.structureIns(self.Buf, s) - self.write(" {\n") - - self.addIndent() - for (_, mut f) in s.Fields { - self.indent() - self.fieldDecl(f) - self.write("\n") - } - - self.indent() - self.structureDestructor(s) - self.write("\n\n") - - self.structureOperators(s) - self.write("\n") - - self.doneIndent() - self.indent() - self.write("};") - } - - fn structureDecl(mut &self, mut &s: &Struct) { - for (_, mut ins) in s.Instances { - self.structureInsDecl(ins) - } - } - - fn structureDecls(mut &self) { - for (_, mut s) in self.ir.Ordered.Structs { - if s.Token != nil { - self.structureDecl(s) - self.write("\n") - } - } - } - - fn structureMethodDecls(mut &self) { - for (_, mut s) in self.ir.Ordered.Structs { - if s.Token != nil { - for (_, mut ins) in s.Instances { - for (_, mut m) in ins.Methods { - // Operator methods are declared by [structureDecl]. - if !isHeadDecl(m) { - self.pushResult(m) - self.funcDecl(m, false) - } - } - } - } - } - } - - // The ident parameter means this function is anon, mostly. - // But this parameter not only for anonymous functions. - // It also useable as custom identifiers for functions. - fn funcHead(mut &self, mut &buf: StrBuilder, mut &f: &FnIns, ptr: bool, ident: str) { - if !ptr && opt::Inline && !f.Decl.IsEntryPoint() { - buf.WriteStr("inline ") - } - self.tc.funcInsResult(buf, f) - if ptr { - buf.WriteStr("(*") - identCoder.funcIns(buf, f) - buf.WriteByte(')') - } else { - buf.WriteByte(' ') - if ident == "" { - identCoder.funcIns(buf, f) - } else { - buf.WriteStr(ident) - } - } - } - - fn funcDeclIns(mut &self, mut &f: &FnIns, ptr: bool) { - self.indent() - self.funcHead(self.Buf, f, ptr, "") - self.paramsIns(self.Buf, f) - self.write(";\n") - } - - fn funcDecl(mut &self, mut &f: &Fn, ptr: bool) { - for (_, mut c) in f.Instances { - self.funcDeclIns(c, ptr) - } - } - - fn funcDeclTrait(mut &self, mut &f: &Fn) { - for (_, mut c) in f.Instances { - mut k := c.Params[0].Kind - c.Params[0].Kind = generalGCPtr - self.funcDeclIns(c, true) - c.Params[0].Kind = k - } - } - - fn funcDecls(mut &self) { - obj::IterPackages(self.ir, fn(mut &pkg: &Package) { - obj::IterFiles(pkg, fn(mut &file: &SymbolTable) { - for (_, mut f) in file.Funcs { - if !f.Binded && f.Token != nil { - self.pushResult(f) - self.funcDecl(f, false) - } - } - }) - }) - } - - fn traitDataTypeMethods(mut &self, mut &t: &Trait) { - obj::IterTraitMethods(t, fn(mut &m: &Fn) { - mut ins := m.Instances[0] - for (i, mut ip) in ins.Params[1:] { - if IsAnonIdent(ip.Decl.Ident) { - ip.Decl.Ident = "_" + conv::Itoa(i) - } - } - self.pushResult(m) - self.funcDeclTrait(m) - }) - } - - fn traitDataTypes(mut &self) { - obj::IterPackages(self.ir, fn(mut &pkg: &Package) { - obj::IterFiles(pkg, fn(mut &file: &SymbolTable) { - for (_, mut t) in file.Traits { - if t.Token == nil || len(t.Implemented) == 0 { - continue - } - self.write("struct ") - identCoder.traitDecl(self.Buf, t) - self.write("MptrData") - self.write(" {\n") - self.addIndent() - self.indent() - self.write("void (*dealloc)(" + typeCoder.Ptr + "<" + typeCoder.Uintptr + ">&);\n") - self.traitDataTypeMethods(t) - self.doneIndent() - self.indent() - self.write("};\n\n") - } - }) - }) - } - - fn paramIns(mut &self, mut &buf: StrBuilder, mut &p: &ParamIns) { - self.tc.paramIns(buf, p) - buf.WriteByte(' ') - identCoder.param(buf, p.Decl) - } - - fn paramsIns(mut &self, mut &buf: StrBuilder, mut &f: &FnIns) { - if !f.AsAnon && len(f.Params) == 0 { - buf.WriteStr("(void)") - ret - } - buf.WriteByte('(') - if f.AsAnon { - buf.WriteStr(ctxParamType + " " + ctxParamIdent) - if len(f.Params) > 0 { - buf.WriteStr(", ") - } - } - for (i, mut p) in f.Params { - self.paramIns(buf, p) - if len(f.Params)-i > 1 { - buf.WriteStr(", ") - } - } - buf.WriteByte(')') - } - - fn varInitExpr(mut &self, mut &v: &Var, init: fn()) { - if v.Statically { - self.write("static ") - } - - self.tc.kind(self.Buf, v.Kind.Kind) - self.write(" ") - if v.Reference { - self.write("*") - } - identCoder.var(self.Buf, v) - if init != nil { - self.write(" = ") - init() - } - self.write(";") - } - - fn var(mut &self, mut v: &Var) { - if IsIgnoreIdent(v.Ident) { - ret - } - if v.Value != nil && v.Value.Expr != nil { - if v.Value.Data.Model != nil { - if v.Reference { - self.varInitExpr(v, fn() { - self.write("&(") - self.ec.model(v.Value.Data.Model) - self.write(")") - }) - } else { - self.varInitExpr(v, fn() { self.ec.possibleRefExpr(v.Value.Data.Model) }) - } - ret - } - self.varInitExpr(v, nil) - ret - } - if v.Reference { - self.varInitExpr(v, fn() { self.write("nullptr") }) - ret - } - if shouldInitialized(v.Kind.Kind) { - self.varInitExpr(v, fn() { self.ec.initExpr(v.Kind.Kind) }) - ret - } - self.varInitExpr(v, nil) - } - - fn anonFuncInsDecl(mut &self, mut &m: &AnonFnExprModel, ident: str) { - self.funcHead(self.anonObj, m.Func, false, ident) - self.paramsIns(self.anonObj, m.Func) - self.anonObj.WriteByte(';') - } - - fn anonFuncIns(mut &self, mut &m: &AnonFnExprModel, ident: str) { - self.funcHead(self.Buf, m.Func, false, ident) - self.paramsIns(self.Buf, m.Func) - self.write(" ") - self.sc.anonFuncScope(m, ident) - if m.Func.Scope != nil { - self.write("\n\n") - } - } - - fn funcIns(mut &self, mut &f: &FnIns, ident: str) { - self.funcHead(self.Buf, f, false, ident) - self.paramsIns(self.Buf, f) - self.write(" ") - self.sc.funcScope(f) - if f.Scope != nil { - self.write("\n\n") - } - } - - fn func(mut &self, mut &f: &Fn) { - for (_, mut ins) in f.Instances { - self.funcIns(ins, "") - } - } - - fn funcTrait(mut &self, &s: &StructIns, mut &f: &FnIns) { - f.Scope = nil - - mut nident := StrBuilder.New(30) - nident.WriteStr("__jule_trait_method_") - nident.WriteStr(conv::FmtUint(u64(uintptr(f)), 0xF)) - nident.WriteStr("_") - nident.WriteStr(conv::FmtUint(u64(uintptr(s)), 0xF)) - - mut k := f.Params[0].Kind - f.Params[0].Kind = generalGCPtr - self.funcIns(f, nident.Str()) - f.Params[0].Kind = k - } - - fn findTraitMetMap(mut &self, mut &m: &Fn): (&FnIns, bool) { - mut mins := m.Instances[0] - for (mut f, _) in self.traitMetMap { - if f.Decl.Public == m.Public && - f.Decl.Ident == m.Ident && - f.EqualFn(mins) { - ret f, true - } - } - ret mins, false - } - - fn traitWrapper(mut &self, mut &t: &Trait, mut &m: &Fn) { - impls: - for (_, mut imp) in t.Implemented { - mut mepf, exist := self.findTraitMetMap(m) - if exist { - // Is handled pair? - mut vals := self.traitMetMap[mepf] - for _, val in vals { - if val == uintptr(imp) { - // Exist, skip this step. - continue impls - } - } - self.traitMetMap[mepf] = append(vals, uintptr(imp)) - } else { - self.traitMetMap[mepf] = append(make([]uintptr, 0), uintptr(imp)) - } - for (_, mut ins) in imp.Instances { - self.funcTrait(ins, mepf) - - mut sm := ins.FindMethod(m.Ident, false) - if sm == nil || len(sm.Instances) == 0 { - ret - } - - self.addIndent() - self.write("{\n") - self.indent() - if m.Exceptional || !m.IsVoid() { - self.write("return ") - } - identCoder.func(self.Buf, sm) - self.write("(") - self.write("_self_.as<") - self.tc.structureIns(self.Buf, ins) - self.write(">()") - - ptr := !m.Params[0].IsRef() - if ptr { - self.write(".alloc") - } - for _, mp in m.Params[1:] { - self.write(", ") - identCoder.param(self.Buf, mp) - } - self.write(");\n}\n") - self.doneIndent() - } - } - } - - fn traitWrappers(mut &self) { - obj::IterPackages(self.ir, fn(mut &pkg: &Package) { - obj::IterFiles(pkg, fn(mut &file: &SymbolTable) { - for (_, mut t) in file.Traits { - if len(t.Implemented) == 0 { - continue - } - obj::IterTraitMethods(t, fn(mut &m: &Fn) { - self.traitWrapper(t, m) - }) - } - }) - }) - } - - fn traitDataMethods(mut &self, mut &t: &Trait, s: &StructIns) { - obj::IterTraitMethods(t, fn(mut &m: &Fn) { - self.indent() - self.write(".") - identCoder.func(self.Buf, m) - self.write("=__jule_trait_method_") - mepf, exist := self.findTraitMetMap(m) - if !exist { - panic("implementation mistake, [traitDataMethods] could not found MepMap record") - } - self.write(conv::FmtUint(u64(uintptr(mepf)), 0xF)) - self.write("_") - self.write(conv::FmtUint(u64(uintptr(s)), 0xF)) - self.write(",\n") - }) - } - - fn traitData(mut &self, mut &t: &Trait, i: int, mut &s: &StructIns) { - mut ident := StrBuilder.New(len(t.Ident)) - identCoder.traitDecl(ident, t) - self.write("static ") - self.writeBytes(unsafe { ident.Buf() }) - self.write("MptrData ") - self.writeBytes(unsafe { ident.Buf() }) - self.write("_mptr_data") - self.write(conv::Itoa(i)) - self.write(" {\n") - self.addIndent() - self.indent() - self.write(".dealloc=" + deallocatedTypeIdent) - self.write(conv::Itoa(self.pushDealloc(&TypeKind{Kind: s}))) - self.write(",\n") - self.traitDataMethods(t, s) - self.doneIndent() - self.write("};\n") - } - - fn traitDatas(mut &self) { - obj::IterPackages(self.ir, fn(mut &pkg: &Package) { - obj::IterFiles(pkg, fn(mut &file: &SymbolTable) { - for (_, mut t) in file.Traits { - mut i := 0 - for (_, mut s) in t.Implemented { - for (_, mut ins) in s.Instances { - self.traitData(t, i, ins) - i++ - } - } - } - }) - }) - } - - fn globals(mut &self) { - for (_, mut v) in self.ir.Ordered.Globals { - self.tc.kind(self.Buf, v.Kind.Kind) - self.write(" ") - identCoder.var(self.Buf, v) - self.write(" = ") - self.ec.model(v.Value.Data.Model) - self.write(";\n") - } - } - - fn decls(mut &self) { - self.structurePlainDecls() - self.structureDecls() - self.headPos = self.Buf.Len() - self.structureMethodDecls() - self.funcDecls() - self.write("\n\n") - self.traitDataTypes() - self.write("\n\n") - self.wrapPos = self.Buf.Len() - self.traitWrappers() - self.write("\n\n") - self.traitDatas() - self.write("\n\n") - self.declPos = self.Buf.Len() - self.globals() - } - - fn structureMethods(mut &self, mut &s: &StructIns) { - for (_, mut f) in s.Methods { - self.func(f) - self.write("\n\n") - } - } - - fn structureOstream(mut &self, mut &s: &StructIns) { - self.indent() - self.write("std::ostream &operator<<(std::ostream &_Stream, ") - identCoder.structureIns(self.Buf, s) - self.write(" _Src) {\n") - self.addIndent() - self.indent() - - mut fts := s.FindMethod("Str", false) - if FuncPattern.Str(fts) { - self.write("_Stream << ") - identCoder.func(self.Buf, fts) - self.write("(&_Src);\n") - } else { - self.write(`_Stream << "`) - cstrBytes(self.Buf, s.Decl.Ident) - self.write("{\";\n") - - for (i, mut f) in s.Fields { - self.indent() - self.write(`_Stream << "`) - cstrBytes(self.Buf, f.Decl.Ident) - self.write(`:`) - - // Skip binded struct kinds. - strct := f.Kind.Struct() - if strct != nil && strct.Decl != nil && strct.Decl.Binded { - self.write(` cpp.`) - identCoder.field(self.Buf, f.Decl) - self.write(`"`) - } else { - self.write(`" << _Src.`) - identCoder.field(self.Buf, f.Decl) - } - if i+1 < len(s.Fields) { - self.write(" << \", \"") - } - self.write(";\n") - } - - self.indent() - self.write("_Stream << \"}\";\n") - } - - self.indent() - self.write("return _Stream;\n") - - self.doneIndent() - self.write("}") - } - - fn structureIns(mut &self, mut &s: &StructIns) { - self.structureMethods(s) - self.write("\n\n") - self.structureOstream(s) - } - - fn structure(mut &self, mut &s: &Struct) { - for (_, mut ins) in s.Instances { - self.structureIns(ins) - self.write("\n\n") - } - } - - fn structures(mut &self) { - for (_, mut s) in self.ir.Ordered.Structs { - if s.Token != nil { - self.structure(s) - self.write("\n\n") - } - } - } - - fn funcs(mut &self) { - obj::IterPackages(self.ir, fn(mut &pkg: &Package) { - obj::IterFiles(pkg, fn(mut &file: &SymbolTable) { - for (_, mut f) in file.Funcs { - if !env::Test && obj::HasDirective(f.Directives, Directive.Test) { - continue - } - if !f.Binded && f.Token != nil { - self.func(f) - self.write("\n\n") - } - } - }) - }) - } - - fn pushInit(mut &self, mut &pkg: &Package) { - obj::IterFiles(pkg, fn(mut &file: &SymbolTable) { - for _, f in file.Funcs { - if f.Ident == build::InitFn { - self.indent() - identCoder.func(self.Buf, f) - self.write("();\n") - } - } - }) - } - - fn anonHashes(mut &self) { - // Use recursive algorithm, because anonymous function may have - // anonymous functions, so [self.anons] may grow. - // Make sure all whether all anonymous functions are handled. - repeat: - mut anons := self.anons - self.anons = nil - for (_, mut h) in anons { - self.anonFuncIns(h.expr, h.ident) - } - if len(self.anons) > 0 { - goto repeat - } - } - - fn initCaller(mut &self) { - self.write("void " + initCallerIdent + "(void) {\n") - self.addIndent() - obj::IterPackages(self.ir, fn(mut &pkg: &Package) { - self.pushInit(pkg) - }) - self.doneIndent() - self.write("\n}") - } - - fn end(mut &self) { - self.write(`int main(int argc, char *argv[], char *envp[]) { + static fn New(mut &ir: &IR, info: SerializationInfo): &ObjectCoder { + mut oc := &ObjectCoder{ + ir: ir, + info: info, + } + oc.ec = exprCoder.new(oc) + oc.sc = scopeCoder.new(oc) + oc.tc = typeCoder.new(oc) + ret oc + } + + fn write(mut &self, s: str) { + self.Buf.WriteStr(s) + } + + fn writeBytes(mut &self, b: []byte) { + self.Buf.Write(b) + } + + // Increase indentation. + fn addIndent(mut &self) { + self.indentBuffer = append(self.indentBuffer, indentKind) + } + + // Decrase indentation. + fn doneIndent(mut &self) { + self.indentBuffer = self.indentBuffer[:len(self.indentBuffer)-1] + } + + // Writes indention string by indentBuffer. + fn indent(mut &self) { + self.Buf.Write(self.indentBuffer) + } + + fn findAnyType(mut &self, mut &t: &TypeKind): int { + for (i, mut at) in self.anyTypeMap { + if at.Equal(t) { + ret i + } + } + ret -1 + } + + fn pushDealloc(mut &self, mut t: &TypeKind): int { + for i, dt in self.deallocated { + if dt.Equal(t) { + ret i + } + } + i := len(self.deallocated) + self.deallocated = append(self.deallocated, t) + self.deallocObj.WriteStr("void " + deallocatedTypeIdent) + self.deallocObj.WriteStr(conv::Itoa(i)) + self.deallocObj.WriteStr("(jule::Ptr &alloc) noexcept { alloc.__as<") + self.tc.kind(self.deallocObj, t) + self.deallocObj.WriteStr(">().dealloc(); }\n") + ret i + } + + fn pushAnonFn(mut &self, mut &m: &AnonFnExprModel): (ident: str) { + closure := obj::IsClosure(m) + if closure { // Closure? + // Handle identifier and generate ctx. + self.anonObj.WriteStr("struct ") + l := self.anonObj.Len() + self.anonObj.WriteStr("__jule_anon_") + self.anonObj.WriteStr(conv::FmtUint(u64(uintptr(m.Func)), 0xF)) + ident = str(unsafe { self.anonObj.Buf()[l:] }) + self.anonObj.WriteStr(anonFnCtxSuffix + "{\n") + for (_, mut v) in m.Captured { + self.anonObj.WriteByte(indentKind) // 1x indent + self.tc.kind(self.anonObj, v.Kind.Kind) + self.anonObj.WriteByte(' ') + if v.Reference { + self.anonObj.WriteByte('*') + } + identCoder.var(self.anonObj, v) + self.anonObj.WriteStr(";\n") + } + self.anonObj.WriteStr("};\n") + + // Ctx handler function. + self.anonObj.WriteStr("static void ") + self.anonObj.WriteStr(ident) + self.anonObj.WriteStr(anonFnCtxHandlerSuffix + "(jule::Ptr<" + typeCoder.Uintptr + "> &ptr) { ptr.__as<") + self.anonObj.WriteStr(ident) + self.anonObj.WriteStr(anonFnCtxSuffix + ">().dealloc(); }\n") + } else { + ident = "__jule_anon" + ident += conv::FmtUint(u64(uintptr(m.Func)), 0xF) + } + + // Anonymous function. + self.anons = append(self.anons, &anonHash{expr: m, ident: ident}) + self.anonFuncInsDecl(m, ident) + self.anonObj.WriteByte('\n') + ret + } + + fn pushAnyType(mut &self, mut t: &TypeKind): int { + if t.Enum() != nil { + t = t.Enum().Kind.Kind + } + mut i := self.findAnyType(t) + if i != -1 { + ret i + } + i = len(self.anyTypeMap) + self.anyTypeMap = append(self.anyTypeMap, t) + si := conv::Itoa(i) + if t.Sptr() != nil { + mut elemKind := StrBuilder.New(40) + self.tc.kind(elemKind, t.Sptr().Elem) + + // Deallocator function. + di := self.pushDealloc(t.Sptr().Elem) + + // Type structure. + self.anyObj.WriteStr("struct " + typeCoder.Any + "::Type ") + self.anyObj.WriteStr(anyTypeIdent) + self.anyObj.WriteStr(si) + self.anyObj.WriteStr("{.dealloc=" + deallocatedTypeIdent) + self.anyObj.WriteStr(conv::Itoa(di)) + self.anyObj.WriteStr(", .eq=jule::ptr_equal, .to_str=jule::ptr_to_str};\n") + + // comparison function. + self.anyObj.WriteStr(typeCoder.Bool + " " + anyTypeIdent) + self.anyObj.WriteStr(si) + self.anyObj.WriteStr("_compare(const " + typeCoder.Any + " &any, const ") + self.tc.asSptr(self.anyObj, unsafe { elemKind.Buf() }) + self.anyObj.WriteStr(" &other) { return any.type == &" + anyTypeIdent) + self.anyObj.WriteStr(si) + self.anyObj.WriteStr(" && jule::ptr_equal(any.data.alloc, other.alloc); }\n") + } else { + comparable := t.Comparable() + mut kindB := StrBuilder.New(40) + self.tc.kind(kindB, t) + kind := unsafe { kindB.Buf() } + + // Deallocator function. + di := self.pushDealloc(t) + + if comparable { + // eq function. + self.anyObj.WriteStr(typeCoder.Bool + " " + anyTypeIdent) + self.anyObj.WriteStr(si) + self.anyObj.WriteStr("_eq(void *alloc, void *other) noexcept { return *reinterpret_cast<") + self.anyObj.Write(kind) + self.anyObj.WriteStr("*>(alloc) == *reinterpret_cast<") + self.anyObj.Write(kind) + self.anyObj.WriteStr("*>(other); }\n") + } + + // to_str function. + self.anyObj.WriteStr(typeCoder.Str + " " + anyTypeIdent) + self.anyObj.WriteStr(si) + self.anyObj.WriteStr("_to_str(const void *alloc) noexcept { return jule::to_str(*reinterpret_cast<") + if t.Ptr() == nil { + self.anyObj.WriteStr("const ") + self.anyObj.Write(kind) + } else { + self.anyObj.Write(kind) + self.anyObj.WriteStr("* const") + } + self.anyObj.WriteStr("*>(alloc)); }\n") + + // Type structure. + self.anyObj.WriteStr("struct " + typeCoder.Any + "::Type ") + self.anyObj.WriteStr(anyTypeIdent) + self.anyObj.WriteStr(si) + self.anyObj.WriteStr("{.dealloc=" + deallocatedTypeIdent) + self.anyObj.WriteStr(conv::Itoa(di)) + self.anyObj.WriteStr(", ") + if comparable { + self.anyObj.WriteStr(".eq=" + anyTypeIdent) + self.anyObj.WriteStr(si) + self.anyObj.WriteStr("_eq, ") + } + self.anyObj.WriteStr(".to_str=" + anyTypeIdent) + self.anyObj.WriteStr(si) + self.anyObj.WriteStr("_to_str};\n") + + if comparable { + // compare function. + self.anyObj.WriteStr(typeCoder.Bool + " " + anyTypeIdent) + self.anyObj.WriteStr(si) + self.anyObj.WriteStr("_compare(const " + typeCoder.Any + " &any, const ") + self.anyObj.Write(kind) + self.anyObj.WriteStr(" &other) { return any.type == &" + anyTypeIdent) + self.anyObj.WriteStr(si) + self.anyObj.WriteStr(" && " + anyTypeIdent) + self.anyObj.WriteStr(si) + self.anyObj.WriteStr("_eq(any.data.alloc, (void*)&other); }\n") + } + } + ret i + } + + fn pushResultIns(mut &self, mut &f: &FnIns) { + s := str(self.tc.rc.code(f.Result)) + _, ok := self.resultMap[s] + if ok { + ret + } + self.resultMap[s] = false + self.resultDecls.WriteStr("struct ") + self.resultDecls.WriteStr(s) + self.resultDecls.WriteStr(" {\n") + for (i, mut t) in f.Result.Tup().Types { + self.resultDecls.WriteByte(indentKind) + self.tc.kind(self.resultDecls, t) + self.resultDecls.WriteByte(' ') + self.resultDecls.WriteStr(resultArgName) + self.resultDecls.WriteStr(conv::Itoa(i)) + self.resultDecls.WriteStr(";\n") + } + self.resultDecls.WriteStr("};\n") + } + + fn pushResult(mut &self, mut &f: &Fn) { + if f.IsVoid() || len(f.Result.Idents) <= 1 { + ret + } + mut n := len(f.Instances) + if len(f.Generics) == 0 { + n = 1 + } + for (_, mut ins) in f.Instances[:n] { + self.pushResultIns(ins) + } + } + + fn pushAndWriteMaskMapper(mut &self, mut t1: &Trait, mut t2: &Trait) { + mut ident := StrBuilder.New(1 << 5) + ident.WriteStr("__jule_trait_offset_mapper_") + ident.WriteStr(conv::FmtUint(u64(uintptr(t2)), 0xF)) + ident.WriteStr("_to_") + ident.WriteStr(conv::FmtUint(u64(uintptr(t1)), 0xF)) + self.Buf.Write(unsafe { ident.Buf() }) + + // Lookup and push if this match is not exist. + for _, m in self.traitCastMap { + if m.t1 == t1 && m.t2 == t2 { + ret + } + } + + self.traitCastMap = append(self.traitCastMap, traitCast{t1: t1, t2: t2}) + + // Not exist, push. + const data = "data" + self.anyObj.WriteStr("void *") + self.anyObj.Write(unsafe { ident.Buf() }) + self.anyObj.WriteStr("(const void *" + data + ") noexcept { ") + + mut t1Ident := StrBuilder.New(1 << 4) + mut t2Ident := StrBuilder.New(1 << 4) + identCoder.traitDecl(t1Ident, t1) + identCoder.traitDecl(t2Ident, t2) + + for (_, mut s1) in t1.Implemented { + for _, s2 in t2.Implemented { + if s1 == s2 { + for (_, mut s1i) in s1.Instances { + i1 := obj::FindTraitTypeOffsetS(t1, s1i) + i2 := obj::FindTraitTypeOffsetS(t2, s1i) + self.anyObj.WriteStr("if (data == &") + self.anyObj.Write(unsafe { t2Ident.Buf() }) + self.anyObj.WriteStr("_mptr_data") + self.anyObj.WriteStr(conv::Itoa(i2)) + self.anyObj.WriteStr(") return &") + self.anyObj.Write(unsafe { t1Ident.Buf() }) + self.anyObj.WriteStr("_mptr_data") + self.anyObj.WriteStr(conv::Itoa(i1)) + self.anyObj.WriteStr("; ") + } + } + } + } + self.anyObj.WriteStr(" jule::panic(\"trait casting failed because of an implementation mistake, this is a JuleC bug\"); return nullptr; }\n") + } + + // Writes location information of token as cstr bytes. + fn locInfo(mut &self, &t: &Token) { + &loc := t.File.Path + + // Normalize path if production compilation enabled. + if env::Production { + match { + | strings::HasPrefix(loc, build::PathStdlib): + // Remove absolute path prefix of standard library. + // Just keeps "std/" prefix. + cstrBytes(self.Buf, loc[len(path::Dir(build::PathStdlib))+1:]) + | strings::HasPrefix(loc, self.ir.Root): + // Remove absolute path prefix of root package. + // Just keeps "[package_dir]/" prefix. + cstrBytes(self.Buf, loc[len(path::Dir(self.ir.Root))+1:]) + |: + cstrBytes(self.Buf, loc) + } + } else { + cstrBytes(self.Buf, loc) + } + self.write(":") + self.write(conv::Itoa(t.Row)) + self.write(":") + self.write(conv::Itoa(t.Column)) + } + + fn head(mut &self) { + time := Time.Now() + abs := time.Abs() + self.write("// Auto generated by JuleC.\n") + self.write("// JuleC version: ") + self.write(jule::Version) + self.write("\n") + self.write("// Date: ") + self.write(conv::FmtUint(abs.Day, 10)) + self.write("/") + self.write(conv::FmtUint(abs.Month, 10)) + self.write("/") + self.write(conv::FmtUint(abs.Year, 10)) + self.write(" (DD/MM/YYYY) UTC\n//\n// Recomended Compile Command;\n// ") + self.write(self.info.Compiler) + self.write(" ") + self.write(self.info.CompilerCommand) + self.write("\n\n") + + if env::Production { + self.write("#define __JULE_ENABLE__PRODUCTION\n") + } + if !env::RC { + self.write("#define __JULE_DISABLE__REFERENCE_COUNTING\n") + } + if !env::Safety { + self.write("#define __JULE_DISABLE__SAFETY\n") + } + + // Include binded libraries here, before the API header. + // See developer reference (4). + self.links() + + self.write("\n\n#include \"") + self.write(build::PathApi) + self.write("\"\n\n") + } + + fn links(mut &self) { + for _, used in self.ir.Used { + match { + | !used.Binded: + continue + | build::IsStdHeaderPath(used.Path): + self.write("#include ") + self.write(used.Path) + self.write("\n") + | build::IsValidHeaderExt(path::Ext(used.Path)): + self.write("#include \"") + self.write(used.Path) + self.write("\"\n") + } + } + } + + fn prepareStructure(mut self, mut &s: &Struct) { + for (_, mut ins) in s.Instances { + for (_, mut m) in ins.Methods { + if m.Statically { + continue + } + for (_, mut mins) in m.Instances { + mut p := mins.Params[0] + mut kind := StrBuilder.New(40) + self.tc.kind(kind, p.Kind) + if !p.Decl.IsRef() { + kind.WriteStr("*") + } + p.Kind = &TypeKind{ + Kind: &customType{ + kind: kind.Str(), + }, + } + } + } + } + } + + fn prepareStructures(mut &self) { + for (_, mut s) in self.ir.Ordered.Structs { + if s.Token != nil { + self.prepareStructure(s) + } + } + } + + fn structurePlainDecl(mut &self, mut &s: &Struct) { + for (_, mut ins) in s.Instances { + self.write("struct ") + identCoder.structureIns(self.Buf, ins) + self.write(";\n") + } + } + + fn structurePlainDecls(mut &self) { + for (_, mut s) in self.ir.Ordered.Structs { + if s.Token != nil { + self.structurePlainDecl(s) + } + } + } + + fn fieldDecl(mut &self, mut &f: &FieldIns) { + self.tc.kind(self.Buf, f.Kind) + self.write(" ") + identCoder.field(self.Buf, f.Decl) + if f.Default == nil { + if shouldInitialized(f.Kind) { + self.write(" = ") + // No default expression. + // Use default expression of data-type. + self.ec.initExpr(f.Kind) + } + } else { + self.write(" = ") + self.ec.possibleRefExpr(f.Default.Model) + } + self.write(";") + } + + fn structureDestructor(mut &self, mut &s: &StructIns) { + // Dispose method must be non-static + const Static = false + disposeMethod := s.FindMethod("Dispose", Static) + mut disposed := FuncPattern.Dispose(disposeMethod) + // Call destructor if implemented. + if !disposed { + ret + } + self.write("~") + identCoder.structureIns(self.Buf, s) + self.write("(void) { ") + identCoder.func(self.Buf, disposeMethod) + self.write("(this); }") + } + + fn structureOperatorEq(mut &self, ident: []byte, mut &s: &StructIns) { + if !s.Comparable { + ret + } + // Operator overloading. + if s.Operators.Eq != nil { + self.structureOperator(ident, s.Operators.Eq, "==") + ret + } + + self.indent() + if opt::Inline { + self.write("inline ") + } + self.write("bool operator==(") + self.writeBytes(ident) + self.write(" _other) {") + if len(s.Fields) > 0 { + self.addIndent() + self.write("\n") + self.indent() + self.write("return ") + self.addIndent() + mut writed := false + for (_, mut f) in s.Fields { + // Skip binded struct kinds. + strct := f.Kind.Struct() + if strct != nil && strct.Decl != nil && strct.Decl.Binded { + continue + } + if writed { + self.write(" &&") + } + writed = true + self.write("\n") + self.indent() + self.write("this->") + mut fIdent := StrBuilder.New(len(f.Decl.Ident)) + identCoder.field(fIdent, f.Decl) + self.writeBytes(unsafe { fIdent.Buf() }) + self.write(" == _other.") + self.writeBytes(unsafe { fIdent.Buf() }) + } + self.doneIndent() + if !writed { + self.write("true") + } + self.write(";\n") + self.doneIndent() + self.indent() + self.write("}") + } else { + self.write(" return true; }") + } + self.write("\n\n") + } + + fn structureOperatorNotEq(mut &self, ident: []byte, mut &s: &StructIns) { + if !s.Comparable { + ret + } + self.indent() + if opt::Inline { + self.write("inline ") + } + self.write("bool operator!=(") + self.writeBytes(ident) + self.write(" _other) { return !this->operator==(_other); }\n\n") + } + + // Write operator overloading forwarding for reserved function. + fn structureOperator(mut &self, ident: []byte, mut &f: &FnIns, op: str) { + if f == nil { + ret + } + + unary := len(f.Params) == 1 // Just self parameter. + assignment := f.Decl.IsVoid() + + self.indent() + if opt::Inline { + self.write("inline ") + } + if assignment { + self.writeBytes(ident) + self.write("&") + } else { + if f.Result.Prim() == nil { + // If result type is not primitive, always structure's itself. + self.writeBytes(ident) + } else { + // Logical. + self.write(typeCoder.Bool) + } + } + self.write(" operator") + self.write(op) + self.write("(") + if !unary { + mut p := f.Params[1] + self.tc.paramIns(self.Buf, p) + self.write(" _other") + } + self.write(") { ") + if !assignment { + self.write("return ") + } + identCoder.funcIns(self.Buf, f) + if !unary { + self.write("(this, _other); ") + if assignment { + self.write("return *this; ") + } + self.write("}") + } else { + self.write("(this); }") + } + self.write("\n\n") + } + + fn structureOperators(mut &self, mut &s: &StructIns) { + mut sb := StrBuilder.New(40) + identCoder.structureIns(sb, s) + ident := unsafe { sb.Buf() } + + // Binary. + self.structureOperatorEq(ident, s) + self.structureOperatorNotEq(ident, s) + self.structureOperator(ident, s.Operators.Gt, ">") + self.structureOperator(ident, s.Operators.GtEq, ">=") + self.structureOperator(ident, s.Operators.Lt, "<") + self.structureOperator(ident, s.Operators.LtEq, "<=") + self.structureOperator(ident, s.Operators.Shl, "<<") + self.structureOperator(ident, s.Operators.Shr, ">>") + self.structureOperator(ident, s.Operators.Add, "+") + self.structureOperator(ident, s.Operators.Sub, "-") + self.structureOperator(ident, s.Operators.Div, "/") + self.structureOperator(ident, s.Operators.Mul, "*") + self.structureOperator(ident, s.Operators.Mod, "%") + self.structureOperator(ident, s.Operators.BitAnd, "&") + self.structureOperator(ident, s.Operators.BitOr, "|") + self.structureOperator(ident, s.Operators.BitXor, "^") + + // Unary. + self.structureOperator(ident, s.Operators.Neg, "-") + self.structureOperator(ident, s.Operators.Pos, "+") + self.structureOperator(ident, s.Operators.BitNot, "~") + + // Assignment. + self.structureOperator(ident, s.Operators.AddAssign, "+=") + self.structureOperator(ident, s.Operators.SubAssign, "-=") + self.structureOperator(ident, s.Operators.DivAssign, "/=") + self.structureOperator(ident, s.Operators.MulAssign, "*=") + self.structureOperator(ident, s.Operators.ModAssign, "%=") + self.structureOperator(ident, s.Operators.ShlAssign, "<<=") + self.structureOperator(ident, s.Operators.ShrAssign, ">>=") + self.structureOperator(ident, s.Operators.BitOrAssign, "|=") + self.structureOperator(ident, s.Operators.BitAndAssign, "&=") + self.structureOperator(ident, s.Operators.BitXorAssign, "^=") + } + + fn structureInsDecl(mut &self, mut &s: &StructIns) { + for (_, mut m) in s.Methods { + // Operator methods are declared by [structureDecl]. + if isHeadDecl(m) { + self.funcDecl(m, false) + } + } + self.write("struct ") + identCoder.structureIns(self.Buf, s) + self.write(" {\n") + + self.addIndent() + for (_, mut f) in s.Fields { + self.indent() + self.fieldDecl(f) + self.write("\n") + } + + self.indent() + self.structureDestructor(s) + self.write("\n\n") + + self.structureOperators(s) + self.write("\n") + + self.doneIndent() + self.indent() + self.write("};") + } + + fn structureDecl(mut &self, mut &s: &Struct) { + for (_, mut ins) in s.Instances { + self.structureInsDecl(ins) + } + } + + fn structureDecls(mut &self) { + for (_, mut s) in self.ir.Ordered.Structs { + if s.Token != nil { + self.structureDecl(s) + self.write("\n") + } + } + } + + fn structureMethodDecls(mut &self) { + for (_, mut s) in self.ir.Ordered.Structs { + if s.Token != nil { + for (_, mut ins) in s.Instances { + for (_, mut m) in ins.Methods { + // Operator methods are declared by [structureDecl]. + if !isHeadDecl(m) { + self.pushResult(m) + self.funcDecl(m, false) + } + } + } + } + } + } + + // The ident parameter means this function is anon, mostly. + // But this parameter not only for anonymous functions. + // It also useable as custom identifiers for functions. + fn funcHead(mut &self, mut &buf: StrBuilder, mut &f: &FnIns, ptr: bool, ident: str) { + if !ptr && opt::Inline && !f.Decl.IsEntryPoint() { + buf.WriteStr("inline ") + } + self.tc.funcInsResult(buf, f) + if ptr { + buf.WriteStr("(*") + identCoder.funcIns(buf, f) + buf.WriteByte(')') + } else { + buf.WriteByte(' ') + if ident == "" { + identCoder.funcIns(buf, f) + } else { + buf.WriteStr(ident) + } + } + } + + fn funcDeclIns(mut &self, mut &f: &FnIns, ptr: bool) { + self.indent() + self.funcHead(self.Buf, f, ptr, "") + self.paramsIns(self.Buf, f) + self.write(";\n") + } + + fn funcDecl(mut &self, mut &f: &Fn, ptr: bool) { + for (_, mut c) in f.Instances { + self.funcDeclIns(c, ptr) + } + } + + fn funcDeclTrait(mut &self, mut &f: &Fn) { + for (_, mut c) in f.Instances { + mut k := c.Params[0].Kind + c.Params[0].Kind = generalGCPtr + self.funcDeclIns(c, true) + c.Params[0].Kind = k + } + } + + fn funcDecls(mut &self) { + obj::IterPackages(self.ir, fn(mut &pkg: &Package) { + obj::IterFiles(pkg, fn(mut &file: &SymbolTable) { + for (_, mut f) in file.Funcs { + if !f.Binded && f.Token != nil { + self.pushResult(f) + self.funcDecl(f, false) + } + } + }) + }) + } + + fn traitDataTypeMethods(mut &self, mut &t: &Trait) { + obj::IterTraitMethods(t, fn(mut &m: &Fn) { + mut ins := m.Instances[0] + for (i, mut ip) in ins.Params[1:] { + if IsAnonIdent(ip.Decl.Ident) { + ip.Decl.Ident = "_" + conv::Itoa(i) + } + } + self.pushResult(m) + self.funcDeclTrait(m) + }) + } + + fn traitDataTypes(mut &self) { + obj::IterPackages(self.ir, fn(mut &pkg: &Package) { + obj::IterFiles(pkg, fn(mut &file: &SymbolTable) { + for (_, mut t) in file.Traits { + if t.Token == nil || len(t.Implemented) == 0 { + continue + } + self.write("struct ") + identCoder.traitDecl(self.Buf, t) + self.write("MptrData") + self.write(" {\n") + self.addIndent() + self.indent() + self.write("void (*dealloc)(" + typeCoder.Ptr + "<" + typeCoder.Uintptr + ">&);\n") + self.traitDataTypeMethods(t) + self.doneIndent() + self.indent() + self.write("};\n\n") + } + }) + }) + } + + fn paramIns(mut &self, mut &buf: StrBuilder, mut &p: &ParamIns) { + self.tc.paramIns(buf, p) + buf.WriteByte(' ') + identCoder.param(buf, p.Decl) + } + + fn paramsIns(mut &self, mut &buf: StrBuilder, mut &f: &FnIns) { + if !f.AsAnon && len(f.Params) == 0 { + buf.WriteStr("(void)") + ret + } + buf.WriteByte('(') + if f.AsAnon { + buf.WriteStr(ctxParamType + " " + ctxParamIdent) + if len(f.Params) > 0 { + buf.WriteStr(", ") + } + } + for (i, mut p) in f.Params { + self.paramIns(buf, p) + if len(f.Params)-i > 1 { + buf.WriteStr(", ") + } + } + buf.WriteByte(')') + } + + fn varInitExpr(mut &self, mut &v: &Var, init: fn()) { + if v.Statically { + self.write("static ") + } + + self.tc.kind(self.Buf, v.Kind.Kind) + self.write(" ") + if v.Reference { + self.write("*") + } + identCoder.var(self.Buf, v) + if init != nil { + self.write(" = ") + init() + } + self.write(";") + } + + fn var(mut &self, mut v: &Var) { + if IsIgnoreIdent(v.Ident) { + ret + } + if v.Value != nil && v.Value.Expr != nil { + if v.Value.Data.Model != nil { + if v.Reference { + self.varInitExpr(v, fn() { + self.write("&(") + self.ec.model(v.Value.Data.Model) + self.write(")") + }) + } else { + self.varInitExpr(v, fn() { self.ec.possibleRefExpr(v.Value.Data.Model) }) + } + ret + } + self.varInitExpr(v, nil) + ret + } + if v.Reference { + self.varInitExpr(v, fn() { self.write("nullptr") }) + ret + } + if shouldInitialized(v.Kind.Kind) { + self.varInitExpr(v, fn() { self.ec.initExpr(v.Kind.Kind) }) + ret + } + self.varInitExpr(v, nil) + } + + fn anonFuncInsDecl(mut &self, mut &m: &AnonFnExprModel, ident: str) { + self.funcHead(self.anonObj, m.Func, false, ident) + self.paramsIns(self.anonObj, m.Func) + self.anonObj.WriteByte(';') + } + + fn anonFuncIns(mut &self, mut &m: &AnonFnExprModel, ident: str) { + self.funcHead(self.Buf, m.Func, false, ident) + self.paramsIns(self.Buf, m.Func) + self.write(" ") + self.sc.anonFuncScope(m, ident) + if m.Func.Scope != nil { + self.write("\n\n") + } + } + + fn funcIns(mut &self, mut &f: &FnIns, ident: str) { + self.funcHead(self.Buf, f, false, ident) + self.paramsIns(self.Buf, f) + self.write(" ") + self.sc.funcScope(f) + if f.Scope != nil { + self.write("\n\n") + } + } + + fn func(mut &self, mut &f: &Fn) { + for (_, mut ins) in f.Instances { + self.funcIns(ins, "") + } + } + + fn funcTrait(mut &self, &s: &StructIns, mut &f: &FnIns) { + f.Scope = nil + + mut nident := StrBuilder.New(30) + nident.WriteStr("__jule_trait_method_") + nident.WriteStr(conv::FmtUint(u64(uintptr(f)), 0xF)) + nident.WriteStr("_") + nident.WriteStr(conv::FmtUint(u64(uintptr(s)), 0xF)) + + mut k := f.Params[0].Kind + f.Params[0].Kind = generalGCPtr + self.funcIns(f, nident.Str()) + f.Params[0].Kind = k + } + + fn findTraitMetMap(mut &self, mut &m: &Fn): (&FnIns, bool) { + mut mins := m.Instances[0] + for (mut f, _) in self.traitMetMap { + if f.Decl.Public == m.Public && + f.Decl.Ident == m.Ident && + f.EqualFn(mins) { + ret f, true + } + } + ret mins, false + } + + fn traitWrapper(mut &self, mut &t: &Trait, mut &m: &Fn) { + impls: + for (_, mut imp) in t.Implemented { + mut mepf, exist := self.findTraitMetMap(m) + if exist { + // Is handled pair? + mut vals := self.traitMetMap[mepf] + for _, val in vals { + if val == uintptr(imp) { + // Exist, skip this step. + continue impls + } + } + self.traitMetMap[mepf] = append(vals, uintptr(imp)) + } else { + self.traitMetMap[mepf] = append(make([]uintptr, 0), uintptr(imp)) + } + for (_, mut ins) in imp.Instances { + self.funcTrait(ins, mepf) + + mut sm := ins.FindMethod(m.Ident, false) + if sm == nil || len(sm.Instances) == 0 { + ret + } + + self.addIndent() + self.write("{\n") + self.indent() + if m.Exceptional || !m.IsVoid() { + self.write("return ") + } + identCoder.func(self.Buf, sm) + self.write("(") + self.write("_self_.as<") + self.tc.structureIns(self.Buf, ins) + self.write(">()") + + ptr := !m.Params[0].IsRef() + if ptr { + self.write(".alloc") + } + for _, mp in m.Params[1:] { + self.write(", ") + identCoder.param(self.Buf, mp) + } + self.write(");\n}\n") + self.doneIndent() + } + } + } + + fn traitWrappers(mut &self) { + obj::IterPackages(self.ir, fn(mut &pkg: &Package) { + obj::IterFiles(pkg, fn(mut &file: &SymbolTable) { + for (_, mut t) in file.Traits { + if len(t.Implemented) == 0 { + continue + } + obj::IterTraitMethods(t, fn(mut &m: &Fn) { + self.traitWrapper(t, m) + }) + } + }) + }) + } + + fn traitDataMethods(mut &self, mut &t: &Trait, s: &StructIns) { + obj::IterTraitMethods(t, fn(mut &m: &Fn) { + self.indent() + self.write(".") + identCoder.func(self.Buf, m) + self.write("=__jule_trait_method_") + mepf, exist := self.findTraitMetMap(m) + if !exist { + panic("implementation mistake, [traitDataMethods] could not found MepMap record") + } + self.write(conv::FmtUint(u64(uintptr(mepf)), 0xF)) + self.write("_") + self.write(conv::FmtUint(u64(uintptr(s)), 0xF)) + self.write(",\n") + }) + } + + fn traitData(mut &self, mut &t: &Trait, i: int, mut &s: &StructIns) { + mut ident := StrBuilder.New(len(t.Ident)) + identCoder.traitDecl(ident, t) + self.write("static ") + self.writeBytes(unsafe { ident.Buf() }) + self.write("MptrData ") + self.writeBytes(unsafe { ident.Buf() }) + self.write("_mptr_data") + self.write(conv::Itoa(i)) + self.write(" {\n") + self.addIndent() + self.indent() + self.write(".dealloc=" + deallocatedTypeIdent) + self.write(conv::Itoa(self.pushDealloc(&TypeKind{Kind: s}))) + self.write(",\n") + self.traitDataMethods(t, s) + self.doneIndent() + self.write("};\n") + } + + fn traitDatas(mut &self) { + obj::IterPackages(self.ir, fn(mut &pkg: &Package) { + obj::IterFiles(pkg, fn(mut &file: &SymbolTable) { + for (_, mut t) in file.Traits { + mut i := 0 + for (_, mut s) in t.Implemented { + for (_, mut ins) in s.Instances { + self.traitData(t, i, ins) + i++ + } + } + } + }) + }) + } + + fn globals(mut &self) { + for (_, mut v) in self.ir.Ordered.Globals { + self.tc.kind(self.Buf, v.Kind.Kind) + self.write(" ") + identCoder.var(self.Buf, v) + self.write(" = ") + self.ec.model(v.Value.Data.Model) + self.write(";\n") + } + } + + fn decls(mut &self) { + self.structurePlainDecls() + self.structureDecls() + self.headPos = self.Buf.Len() + self.structureMethodDecls() + self.funcDecls() + self.write("\n\n") + self.traitDataTypes() + self.write("\n\n") + self.wrapPos = self.Buf.Len() + self.traitWrappers() + self.write("\n\n") + self.traitDatas() + self.write("\n\n") + self.declPos = self.Buf.Len() + self.globals() + } + + fn structureMethods(mut &self, mut &s: &StructIns) { + for (_, mut f) in s.Methods { + self.func(f) + self.write("\n\n") + } + } + + fn structureOstream(mut &self, mut &s: &StructIns) { + self.indent() + self.write("std::ostream &operator<<(std::ostream &_Stream, ") + identCoder.structureIns(self.Buf, s) + self.write(" _Src) {\n") + self.addIndent() + self.indent() + + mut fts := s.FindMethod("Str", false) + if FuncPattern.Str(fts) { + self.write("_Stream << ") + identCoder.func(self.Buf, fts) + self.write("(&_Src);\n") + } else { + self.write(`_Stream << "`) + cstrBytes(self.Buf, s.Decl.Ident) + self.write("{\";\n") + + for (i, mut f) in s.Fields { + self.indent() + self.write(`_Stream << "`) + cstrBytes(self.Buf, f.Decl.Ident) + self.write(`:`) + + // Skip binded struct kinds. + strct := f.Kind.Struct() + if strct != nil && strct.Decl != nil && strct.Decl.Binded { + self.write(` cpp.`) + identCoder.field(self.Buf, f.Decl) + self.write(`"`) + } else { + self.write(`" << _Src.`) + identCoder.field(self.Buf, f.Decl) + } + if i+1 < len(s.Fields) { + self.write(" << \", \"") + } + self.write(";\n") + } + + self.indent() + self.write("_Stream << \"}\";\n") + } + + self.indent() + self.write("return _Stream;\n") + + self.doneIndent() + self.write("}") + } + + fn structureIns(mut &self, mut &s: &StructIns) { + self.structureMethods(s) + self.write("\n\n") + self.structureOstream(s) + } + + fn structure(mut &self, mut &s: &Struct) { + for (_, mut ins) in s.Instances { + self.structureIns(ins) + self.write("\n\n") + } + } + + fn structures(mut &self) { + for (_, mut s) in self.ir.Ordered.Structs { + if s.Token != nil { + self.structure(s) + self.write("\n\n") + } + } + } + + fn funcs(mut &self) { + obj::IterPackages(self.ir, fn(mut &pkg: &Package) { + obj::IterFiles(pkg, fn(mut &file: &SymbolTable) { + for (_, mut f) in file.Funcs { + if !env::Test && obj::HasDirective(f.Directives, Directive.Test) { + continue + } + if !f.Binded && f.Token != nil { + self.func(f) + self.write("\n\n") + } + } + }) + }) + } + + fn pushInit(mut &self, mut &pkg: &Package) { + obj::IterFiles(pkg, fn(mut &file: &SymbolTable) { + for _, f in file.Funcs { + if f.Ident == build::InitFn { + self.indent() + identCoder.func(self.Buf, f) + self.write("();\n") + } + } + }) + } + + fn anonHashes(mut &self) { + // Use recursive algorithm, because anonymous function may have + // anonymous functions, so [self.anons] may grow. + // Make sure all whether all anonymous functions are handled. + repeat: + mut anons := self.anons + self.anons = nil + for (_, mut h) in anons { + self.anonFuncIns(h.expr, h.ident) + } + if len(self.anons) > 0 { + goto repeat + } + } + + fn initCaller(mut &self) { + self.write("void " + initCallerIdent + "(void) {\n") + self.addIndent() + obj::IterPackages(self.ir, fn(mut &pkg: &Package) { + self.pushInit(pkg) + }) + self.doneIndent() + self.write("\n}") + } + + fn end(mut &self) { + self.write(`int main(int argc, char *argv[], char *envp[]) { jule::setup_argv(argc, argv); jule::setup_envp(envp); __jule_call_initializers(); `) - if env::Test { - self.write("test_point();") - } else { - self.write("entry_point();") - } + if env::Test { + self.write("test_point();") + } else { + self.write("entry_point();") + } - self.write(` + self.write(` return EXIT_SUCCESS; }`) - } - - fn insertBuf(mut &self, mut &buf: StrBuilder, pos: int) { - if buf.Len() > 0 { - mut head := make([]byte, 0, self.Buf.Len() + buf.Len()) - head = append(head, unsafe { self.Buf.Buf() }[:pos]...) - head = append(head, unsafe { buf.Buf() }...) - head = append(head, unsafe { self.Buf.Buf() }[pos:]...) - unsafe { self.Buf.SetBuf(head) } - } - } - - fn serializeHead(mut &self) { - self.prepareStructures() - self.head() - self.write("\n") - self.decls() - - self.insertBuf(self.resultDecls, self.headPos) - self.wrapPos += self.resultDecls.Len() - self.declPos += self.resultDecls.Len() - - self.write("\n") - self.structures() - self.funcs() - self.initCaller() - self.write("\n\n") - - self.anonHashes() - - self.insertBuf(self.deallocObj, self.wrapPos) - self.wrapPos += self.deallocObj.Len() - self.declPos += self.deallocObj.Len() - - self.insertBuf(self.anyObj, self.declPos) - self.declPos += self.anyObj.Len() - - self.insertBuf(self.anonObj, self.declPos) - self.declPos += self.anonObj.Len() - } - - fn Serialize(mut &self) { - self.serializeHead() - self.end() - } + } + + fn insertBuf(mut &self, mut &buf: StrBuilder, pos: int) { + if buf.Len() > 0 { + mut head := make([]byte, 0, self.Buf.Len() + buf.Len()) + head = append(head, unsafe { self.Buf.Buf() }[:pos]...) + head = append(head, unsafe { buf.Buf() }...) + head = append(head, unsafe { self.Buf.Buf() }[pos:]...) + unsafe { self.Buf.SetBuf(head) } + } + } + + fn serializeHead(mut &self) { + self.prepareStructures() + self.head() + self.write("\n") + self.decls() + + self.insertBuf(self.resultDecls, self.headPos) + self.wrapPos += self.resultDecls.Len() + self.declPos += self.resultDecls.Len() + + self.write("\n") + self.structures() + self.funcs() + self.initCaller() + self.write("\n\n") + + self.anonHashes() + + self.insertBuf(self.deallocObj, self.wrapPos) + self.wrapPos += self.deallocObj.Len() + self.declPos += self.deallocObj.Len() + + self.insertBuf(self.anyObj, self.declPos) + self.declPos += self.anyObj.Len() + + self.insertBuf(self.anonObj, self.declPos) + self.declPos += self.anonObj.Len() + } + + fn Serialize(mut &self) { + self.serializeHead() + self.end() + } } // Concatenate all strings into single string. fn concatAllParts(parts: ...&Token): []byte { - mut n := 0 - for _, part in parts { - n += len(part.Kind) - } - if n == 0 { - ret nil - } - mut s := StrBuilder.New(n) - for _, p in parts { - s.WriteStr(p.Kind) - } - ret unsafe { s.Buf() } + mut n := 0 + for _, part in parts { + n += len(part.Kind) + } + if n == 0 { + ret nil + } + mut s := StrBuilder.New(n) + for _, p in parts { + s.WriteStr(p.Kind) + } + ret unsafe { s.Buf() } } // Reports whether the m is a method which is declarated top of the struct. fn isHeadDecl(mut &m: &Fn): bool { - if len(m.Generics) > 0 || len(m.Instances) == 0 { - ret false - } - if obj::IsOpMethod(m) { - ret true - } - mut mi := m.Instances[0] - const Static = false - ret FuncPattern.Dispose(mi.Owner.FindMethod("Dispose", Static)) + if len(m.Generics) > 0 || len(m.Instances) == 0 { + ret false + } + if obj::IsOpMethod(m) { + ret true + } + mut mi := m.Instances[0] + const Static = false + ret FuncPattern.Dispose(mi.Owner.FindMethod("Dispose", Static)) } \ No newline at end of file diff --git a/src/julec/obj/cxx/scope.jule b/src/julec/obj/cxx/scope.jule index 2226a0086..4065ec9dd 100644 --- a/src/julec/obj/cxx/scope.jule +++ b/src/julec/obj/cxx/scope.jule @@ -5,45 +5,45 @@ use obj use env use opt::{ - self, - PushToSliceExprModel, - AppendToSliceExprModel, - MutSlicingExprModel, - SwapExprModel, - ExceptionalForwardingExprModel, - StrRuneIter, + self, + PushToSliceExprModel, + AppendToSliceExprModel, + MutSlicingExprModel, + SwapExprModel, + ExceptionalForwardingExprModel, + StrRuneIter, } use conv for std::conv use lex for std::jule::lex::{TokenKind} use std::jule::constant::{Const} use std::jule::sema::{ - Data, - Stmt, - FnIns, - Var, - Scope, - If, - Conditional, - InfIter, - WhileIter, - RangeIter, - ContSt, - BreakSt, - Label, - GotoSt, - Postfix, - Assign, - MultiAssign, - Match, - Case, - FallSt, - RetSt, - TupleExprModel, - TypeKind, - SlicingExprModel, - IndexingExprModel, - FnCallExprModel, - AnonFnExprModel, + Data, + Stmt, + FnIns, + Var, + Scope, + If, + Conditional, + InfIter, + WhileIter, + RangeIter, + ContSt, + BreakSt, + Label, + GotoSt, + Postfix, + Assign, + MultiAssign, + Match, + Case, + FallSt, + RetSt, + TupleExprModel, + TypeKind, + SlicingExprModel, + IndexingExprModel, + FnCallExprModel, + AnonFnExprModel, } use std::strings::{StrBuilder} @@ -56,1022 +56,1022 @@ static assignArgName = "__jule_assign_arg" // Common group of semantic analysis stmt types and optimizer specific types. enum compStmt: type { - Stmt: Stmt, - &PushToSliceExprModel, - &AppendToSliceExprModel, - &MutSlicingExprModel, - &SwapExprModel, - &ExceptionalForwardingExprModel, - &StrRuneIter, + Stmt: Stmt, + &PushToSliceExprModel, + &AppendToSliceExprModel, + &MutSlicingExprModel, + &SwapExprModel, + &ExceptionalForwardingExprModel, + &StrRuneIter, } struct scopeCoder { - oc: &ObjectCoder + oc: &ObjectCoder } impl scopeCoder { - static fn new(mut &oc: &ObjectCoder): &scopeCoder { - ret &scopeCoder{ - oc: oc, - } - } - - // Common head object-code for iterations of all kind. - fn iterHead[T](mut &self, &it: T, mut &ref: bool, begin: str) { - self.oc.write("{\n") - self.oc.addIndent() - self.oc.indent() - self.oc.write("auto expr = ") - if opt::Copy && isCopyOptimizable(it.Expr) { - ref = true - match type it.Expr.Model { - | &Var: - v := (&Var)(it.Expr.Model) - if v.Reference { - self.oc.ec.model(it.Expr.Model) - break - } - fall - |: - self.oc.write("&(") - self.oc.ec.model(it.Expr.Model) - self.oc.write(")") - } - } else { - self.oc.ec.possibleRefExpr(it.Expr.Model) - } - self.oc.write(";\n") - self.oc.indent() - self.oc.write("auto it = expr") - if ref { - self.oc.write("->") - } else { - self.oc.write(".") - } - self.oc.write("begin();\n") - self.oc.indent() - self.oc.write("auto expr_end = expr") - if ref { - self.oc.write("->") - } else { - self.oc.write(".") - } - self.oc.write("end();\n") - self.oc.indent() - self.oc.write(begin) - self.oc.write(":;\n") - self.oc.indent() - self.oc.write("if (it != expr_end) {\n") - self.oc.addIndent() - self.oc.indent() - } - - fn rangeIndexIter(mut &self, mut &it: &RangeIter) { - mut sb := StrBuilder.New(1 << 6) - identCoder.iterBegin(sb, uintptr(it)) - begin := sb.Str() - sb.Clear() - identCoder.iterNext(sb, uintptr(it)) - next := sb.Str() - - mut ref := false - self.iterHead(it, ref, begin) - if it.KeyA != nil { - self.oc.varInitExpr(it.KeyA, fn() { - if ref { - self.oc.write("it - expr->begin()") - } else { - self.oc.write("it - expr.begin()") - } - }) - self.oc.write("\n") - self.oc.indent() - } - if it.KeyB != nil { - it.KeyB.Reference = opt::Copy && isIterCopyOptimizable(it.Expr, it.KeyB) - self.oc.varInitExpr(it.KeyB, fn() { - unsafe { - if it.KeyB.Reference { - self.oc.write("it") - } else { - self.oc.write("*it") - } - } - }) - self.oc.write("\n") - self.oc.indent() - } - self.scope(it.Scope) - self.oc.write("\n") - self.oc.indent() - self.oc.write(next) - self.oc.write(":;\n") - self.oc.indent() - self.oc.write("++it;\n") - self.oc.indent() - if it.KeyA != nil { - identCoder.var(self.oc.Buf, it.KeyA) - self.oc.write("++;\n") - self.oc.indent() - } - self.oc.write("goto ") - self.oc.write(begin) - self.oc.write(";\n") - - // Close if. - self.oc.doneIndent() - self.oc.indent() - self.oc.write("}\n") - - self.oc.indent() - identCoder.iterEnd(self.oc.Buf, uintptr(it)) - self.oc.write(":;\n") - - // Close scope. - self.oc.doneIndent() - self.oc.indent() - self.oc.write("}") - } - - fn rangeHashmapIter(mut &self, mut &it: &RangeIter) { - mut sb := StrBuilder.New(1 << 6) - identCoder.iterBegin(sb, uintptr(it)) - begin := sb.Str() - sb.Clear() - identCoder.iterNext(sb, uintptr(it)) - next := sb.Str() - - mut ref := false - self.iterHead(it, ref, begin) - if it.KeyA != nil { - self.oc.varInitExpr(it.KeyA, fn() { self.oc.write("it->first") }) - self.oc.write("\n") - self.oc.indent() - } - if it.KeyB != nil { - self.oc.varInitExpr(it.KeyB, fn() { self.oc.write("it->second") }) - self.oc.write("\n") - self.oc.indent() - } - self.scope(it.Scope) - self.oc.write("\n") - self.oc.indent() - self.oc.write(next) - self.oc.write(":;\n") - self.oc.indent() - self.oc.write("++it;\n") - self.oc.indent() - self.oc.write("goto ") - self.oc.write(begin) - self.oc.write(";\n") - - // Close if. - self.oc.doneIndent() - self.oc.indent() - self.oc.write("}\n") - - self.oc.indent() - identCoder.iterEnd(self.oc.Buf, uintptr(it)) - self.oc.write(":;\n") - - // Close scope. - self.oc.doneIndent() - self.oc.indent() - self.oc.write("}") - } - - fn strRuneIter(mut &self, mut it: &StrRuneIter) { - mut sb := StrBuilder.New(1 << 6) - identCoder.iterBegin(sb, uintptr(it.Base)) - begin := sb.Str() - sb.Clear() - identCoder.iterNext(sb, uintptr(it.Base)) - next := sb.Str() - - self.oc.write("{\n") - self.oc.addIndent() - self.oc.indent() - - mut ref := false - self.oc.write("auto expr = ") - if opt::Copy && isCopyOptimizable(it.Expr) { - ref = true - match type it.Expr.Model { - | &Var: - v := (&Var)(it.Expr.Model) - if v.Reference { - self.oc.ec.model(it.Expr.Model) - break - } - fall - |: - self.oc.write("&(") - self.oc.ec.model(it.Expr.Model) - self.oc.write(")") - } - } else { - self.oc.ec.possibleRefExpr(it.Expr.Model) - } - self.oc.write(";\n") - self.oc.indent() - self.oc.write("char *it = expr") - if ref { - self.oc.write("->") - } else { - self.oc.write(".") - } - self.oc.write("operator char*();\n") - self.oc.indent() - self.oc.write("const char *end = it + expr") - if ref { - self.oc.write("->") - } else { - self.oc.write(".") - } - self.oc.write("len();\n") - self.oc.indent() - - // Variables. - if it.Base.KeyA != nil { - self.oc.varInitExpr(it.Base.KeyA, fn() { self.oc.write("0") }) - self.oc.write("\n") - self.oc.indent() - } - self.oc.write("std::size_t len;\n") - self.oc.indent() - if it.Base.KeyB != nil { - self.oc.varInitExpr(it.Base.KeyB, nil) - self.oc.write("\n") - self.oc.indent() - } - self.oc.write(begin) - self.oc.write(":;\n") - self.oc.indent() - self.oc.write("std::tie(") - if it.Base.KeyB != nil { - identCoder.var(self.oc.Buf, it.Base.KeyB) - } else { - self.oc.write("std::ignore") - } - self.oc.write(", len) = jule::utf8_decode_rune_str(it, end - it") - self.oc.write(");\n") - self.oc.indent() - - self.oc.write("if (it < end) {\n") - self.oc.addIndent() - self.oc.indent() - self.scope(it.Base.Scope) - self.oc.write("\n") - self.oc.indent() - self.oc.write(next) - self.oc.write(":;\n") - self.oc.indent() - self.oc.write("it += len;\n") - self.oc.indent() - if it.Base.KeyA != nil { - identCoder.var(self.oc.Buf, it.Base.KeyA) - self.oc.write("++;\n") - self.oc.indent() - } - self.oc.write("goto ") - self.oc.write(begin) - self.oc.write(";\n") - - // Close if. - self.oc.doneIndent() - self.oc.indent() - self.oc.write("}\n") - - // Close scope. - self.oc.doneIndent() - self.oc.indent() - self.oc.write("}") - } - - fn ifCase(mut &self, mut i: &If) { - if i.Expr != nil { - self.oc.write("if (") - self.oc.ec.possibleRefExpr(i.Expr) - self.oc.write(") ") - } - self.scope(i.Scope) - } - - fn conditional(mut &self, mut c: &Conditional) { - mut writed := false - for (_, mut elif) in c.Elifs { - if elif == nil { - continue - } - if writed { - self.oc.write(" else ") - } - writed = true - self.ifCase(elif) - } - if c.Default != nil { - if writed { - self.oc.write(" else ") - } - self.scope(c.Default.Scope) - } - } - - fn infIter(mut &self, mut it: &InfIter) { - self.oc.write("for (;;) {\n") - self.oc.addIndent() // Indent scope. - self.oc.indent() - self.scope(it.Scope) - self.oc.doneIndent() - self.oc.write("\n") - self.oc.indent() - identCoder.iterNext(self.oc.Buf, uintptr(it)) - self.oc.write(":;\n") - self.oc.indent() - self.oc.write("}\n") - self.oc.indent() - identCoder.iterEnd(self.oc.Buf, uintptr(it)) - self.oc.write(":;") - } - - fn whileIter(mut &self, mut it: &WhileIter) { - if it.Expr != nil && it.Next == nil { - self.oc.write("while (") - self.oc.ec.possibleRefExpr(it.Expr) - self.oc.write(") {") - } else { - self.oc.write("for (; ") - if it.Expr != nil { - self.oc.ec.possibleRefExpr(it.Expr) - } - self.oc.write("; ") - if it.Next != nil { - self.st(it.Next) - } - self.oc.write(") {") - } - - if len(it.Scope.Stmts) == 0 { - self.oc.write("}") - ret - } - - self.oc.write("\n") - self.oc.addIndent() - self.oc.indent() - self.scope(it.Scope) - self.oc.write("\n") - self.oc.doneIndent() - self.oc.indent() - - identCoder.iterNext(self.oc.Buf, uintptr(it)) - self.oc.write(":;\n") - self.oc.indent() - self.oc.write("}\n") - self.oc.indent() - identCoder.iterEnd(self.oc.Buf, uintptr(it)) - self.oc.write(":;") - } - - fn rangeIter(mut &self, mut it: &RangeIter) { - match { - | it.Expr.Kind.Slc() != nil: - self.rangeIndexIter(it) - | it.Expr.Kind.Arr() != nil: - self.rangeIndexIter(it) - | it.Expr.Kind.Map() != nil: - self.rangeHashmapIter(it) - |: - self.rangeIndexIter(it) // Str - } - } - - fn cont(mut &self, c: &ContSt) { - self.oc.write("goto ") - identCoder.iterNext(self.oc.Buf, c.It) - } - - fn label(mut &self, l: &Label) { - identCoder.label(self.oc.Buf, uintptr(l)) - self.oc.write(":") - } - - fn gotoSt(mut &self, gt: &GotoSt) { - self.oc.write("goto ") - identCoder.label(self.oc.Buf, uintptr(gt.Label)) - } - - fn postfix(mut &self, mut p: &Postfix) { - self.oc.write("(") - self.oc.ec.possibleRefExpr(p.Expr) - self.oc.write(")") - self.oc.write(p.Op) - } - - fn assign(mut &self, mut a: &Assign) { - self.oc.ec.possibleRefExpr(a.Left.Model) - self.oc.write(a.Op.Kind) - self.oc.ec.possibleRefExpr(a.Right.Model) - } - - fn mapLookupAssign(mut &self, mut &a: &MultiAssign) { - mut iem := (&IndexingExprModel)(a.Right) - self.oc.ec.possibleRefExpr(iem.Expr.Model) - self.oc.write(".lookup(") - self.oc.ec.possibleRefExpr(iem.Index.Model) - self.oc.write(", ") - if a.Left[0] != nil { - self.oc.write("&(") - self.oc.ec.possibleRefExpr(a.Left[0].Model) - self.oc.write("), ") - } else { - self.oc.write("nullptr, ") - } - if a.Left[1] != nil { - self.oc.write("&(") - self.oc.ec.possibleRefExpr(a.Left[1].Model) - self.oc.write(")") - } else { - self.oc.write("nullptr") - } - self.oc.write(")") - } - - fn multiAssignTup(mut &self, mut &a: &MultiAssign) { - self.oc.write("({\n") - self.oc.addIndent() - - mut tup := (&TupleExprModel)(a.Right) - - for (i, mut r) in tup.Datas { - self.oc.indent() - mut l := a.Left[i] - if l != nil { - match type l.Model { - | &Var: - mut v := (&Var)(l.Model) - // If variable is reference and uninitialized, - // it should be declared in this multiple-assignment. - if v.Reference && !v.IsInitialized() { - identCoder.var(self.oc.Buf, v) - self.oc.write(" = &(") - self.oc.ec.possibleRefExpr(r.Model) - self.oc.write(");\n") - a.Left[i] = nil // Ignore handling for following statements. - continue - } - } - self.oc.tc.kind(self.oc.Buf, l.Kind) - self.oc.write(" ") - identCoder.toOut(self.oc.Buf, assignArgName, uintptr(i)) - self.oc.write(" = ") - } - self.oc.ec.possibleRefExpr(r.Model) - self.oc.write(";\n") - } - - for (i, mut l) in a.Left { - if l == nil { - continue - } - self.oc.indent() - self.oc.ec.possibleRefExpr(l.Model) - self.oc.write(" = ") - identCoder.toOut(self.oc.Buf, assignArgName, uintptr(i)) - self.oc.write(";\n") - } - - self.oc.doneIndent() - self.oc.indent() - self.oc.write("})") - } - - fn multiAssignFn(mut &self, mut &a: &MultiAssign) { - self.oc.write("({\n") - self.oc.addIndent() - self.oc.indent() - - mut f := (&FnCallExprModel)(a.Right) - self.oc.tc.rc.codeMut1(self.oc.Buf, f.Func.Result) - self.oc.write(" " + assignResultName + " = ") - self.oc.ec.possibleRefExpr(a.Right) - self.oc.write(";\n") - - mut tup := f.Func.Result.Tup() - for (i, mut l) in a.Left { - if l != nil { - const r = assignResultName + "." + resultArgName - self.oc.indent() - self.oc.ec.possibleRefExpr(l.Model) - match { - | tup.Types[i].Equal(l.Kind): - self.oc.write(" = " + r) - self.oc.write(conv::Itoa(i)) - | obj::IsAny(l.Kind): - self.oc.write(" = " + typeCoder.Any + "(" + r) - self.oc.write(conv::Itoa(i)) - self.oc.write(", &" + anyTypeIdent) - self.oc.write(conv::Itoa(self.oc.pushAnyType(tup.Types[i]))) - self.oc.write(")") - |: - // It should be trait. - if tup.Types[i].Trait() != nil { // Different traits, cast. - self.oc.write(" = ") - mut t1 := l.Kind.Trait() - mut t2 := tup.Types[i].Trait() - self.oc.write(r) - self.oc.write(conv::Itoa(i)) - self.oc.write(".map<") - identCoder.traitDecl(self.oc.Buf, t1) - self.oc.write(">(") - self.oc.pushAndWriteMaskMapper(t1, t2) - self.oc.write(")") - break - } - t := l.Kind.Trait() - self.oc.write(" = " + typeCoder.Trait + "(" + r) - self.oc.write(conv::Itoa(i)) - self.oc.write(", (" + typeCoder.Trait + "::Type*)&") - identCoder.traitDecl(self.oc.Buf, t) - self.oc.write("_mptr_data") - self.oc.write(conv::Itoa(obj::FindTraitTypeOffset(t, tup.Types[i]))) - self.oc.write(")") - } - self.oc.write(";\n") - } - } - - self.oc.doneIndent() - self.oc.indent() - self.oc.write("})") - } - - fn multiAssign(mut &self, mut a: &MultiAssign) { - // Write declarations without no initialization. - // It will initialize with assignments. - for (_, mut d) in a.Decls { - self.oc.varInitExpr(d, nil) - self.oc.write("\n") - self.oc.indent() - } - - // Special cases. - match type a.Right { - | &IndexingExprModel: // Map lookup. - self.mapLookupAssign(a) - ret - } - - match type a.Right { - | &TupleExprModel: - self.multiAssignTup(a) - | &FnCallExprModel: - self.multiAssignFn(a) - |: - panic("this panic call should be unreachable") - } - } - - fn matchExpr(mut &self, mut m: &Match): fn() { - if !m.Expr.IsConst() { - ret fn() { self.oc.write(matchExpr) } - } - if !m.Expr.Constant.IsBool() || !m.Expr.Constant.ReadBool() { - ret fn() { self.oc.ec.possibleRefExpr(m.Expr.Model) } - } - ret nil - } - - fn case(mut &self, mut m: &Match, mut c: &Case) { - if len(c.Exprs) != 0 && !m.Comptime { - if len(m.Cases) > 0 && m.Cases[0] == c { - self.oc.write("if (") - } else { - self.oc.write("else if (") - } - for (i, mut expr) in c.Exprs { - match { - | !m.TypeMatch: - caseExpr := self.matchExpr(m) - if m.Expr.GoodOperand(expr) { - if caseExpr != nil { - caseExpr() - self.oc.write(" == ") - } - self.oc.ec.possibleRefExpr(expr.Model) - } else { - self.oc.ec.possibleRefExpr(expr.Model) - if caseExpr != nil { - self.oc.write(" == ") - caseExpr() - } - } - |: - self.oc.write(matchExpr) - mut tk := (&TypeKind)(expr.Model) - if m.Expr.Kind.Trait() != nil { - self.oc.write(".type_is(") - self.oc.ec.boolean(expr.Kind.Sptr() != nil) - self.oc.write(", (const " + typeCoder.Trait + "::Type*)&") - identCoder.traitDecl(self.oc.Buf, m.Expr.Kind.Trait()) - self.oc.write("_mptr_data") - self.oc.write(conv::Itoa(obj::FindTraitTypeOffset(m.Expr.Kind.Trait(), expr.Kind))) - self.oc.write(")") - } else { // Any type. - j := self.oc.pushAnyType(tk) - self.oc.write(".type == &" + anyTypeIdent) - self.oc.write(conv::Itoa(j)) - } - } - - if len(c.Exprs)-i > 1 { - self.oc.write(" || ") - } - } - self.oc.write(") ") - } else if m.Default == c && len(m.Cases) != 0 { - self.oc.indent() - self.oc.write("else ") - } - - self.oc.addIndent() - - self.oc.write("{\n") - self.oc.indent() - identCoder.caseBegin(self.oc.Buf, uintptr(c)) - self.oc.write(":;\n") - if len(c.Scope.Stmts) > 0 { - self.oc.indent() - self.scope(c.Scope) - self.oc.write("\n") - } - - self.oc.doneIndent() - - self.oc.indent() - self.oc.write("}") - } - - fn matchSt(mut &self, mut m: &Match) { - if len(m.Cases) == 0 && m.Default == nil { - ret - } - - if m.Comptime && (m.Default == nil || len(m.Default.Scope.Stmts) == 0) { - ret - } - - self.oc.write("{\n") - - self.oc.addIndent() - - self.oc.indent() - - // Constant expressions generated as literals in conditions. - if !m.Comptime && !m.Expr.IsConst() { - if opt::Copy && isCopyOptimizable(m.Expr) { - self.oc.write("auto &_match_expr{ ") - } else { - self.oc.write("auto _match_expr{ ") - } - self.oc.ec.possibleRefExpr(m.Expr.Model) - self.oc.write(" };\n") - self.oc.indent() - } - - if len(m.Cases) > 0 { - for (_, mut c) in m.Cases { - if c == nil { - continue - } - self.oc.write("\n") - self.oc.indent() - self.case(m, c) - } - } - - if m.Default != nil { - self.oc.write("\n") - self.case(m, m.Default) - } - - self.oc.write("\n") - self.oc.indent() - identCoder.matchEnd(self.oc.Buf, uintptr(m)) - self.oc.write(":;") - self.oc.write("\n") - - self.oc.doneIndent() - - self.oc.indent() - self.oc.write("}") - } - - fn fallSt(mut &self, f: &FallSt) { - self.oc.write("goto ") - identCoder.caseBegin(self.oc.Buf, f.DestCase) - } - - fn breakSt(mut &self, b: &BreakSt) { - self.oc.write("goto ") - if b.It != 0 { - identCoder.iterEnd(self.oc.Buf, b.It) - } else { - identCoder.matchEnd(self.oc.Buf, b.Mtch) - } - } - - fn setResult(mut &self, mut r: &RetSt) { - if len(r.Func.Decl.Result.Idents) == 1 { - self.oc.write(resultName + " = ") - self.oc.ec.possibleRefExpr(r.Expr) - self.oc.write(";\n") - self.oc.indent() - ret - } - match type r.Expr { - | &TupleExprModel: - mut datas := (&TupleExprModel)(r.Expr).Datas - for i, data in datas { - self.oc.write(resultName + "." + resultArgName) - self.oc.write(conv::Itoa(i)) - self.oc.write(" = ") - self.oc.ec.possibleRefExpr(data.Model) - self.oc.write(";\n") - self.oc.indent() - } - | &FnCallExprModel: - self.oc.write(resultName + " = std::move(") - self.oc.ec.model(r.Expr) - self.oc.write(");\n") - |: - panic("implementation mistake, this panic call should be unreachable") - } - } - - fn retSt(mut &self, mut r: &RetSt) { - // Void. - if r.Func.Decl.IsVoid() { - if r.Func.Decl.Exceptional { - self.oc.write("return jule::VoidExceptional{};") - ret - } - self.oc.write("return;") - ret - } else if len(r.Func.Decl.Result.Idents) == 0 { - if r.Func.Decl.Exceptional { - self.oc.write("return jule::Exceptional<") - self.oc.tc.kind(self.oc.Buf, r.Func.Result) - self.oc.write(">{.result=") - self.oc.ec.possibleRefExpr(r.Expr) - self.oc.write("};") - } else { - self.oc.write("return ") - self.oc.ec.possibleRefExpr(r.Expr) - self.oc.write(";") - } - ret - } - - if r.Expr != nil { - self.setResult(r) - } - if r.Func.Decl.Exceptional { - self.oc.write("return jule::Exceptional<") - self.oc.tc.rc.codeMut1(self.oc.Buf, r.Func.Result) - self.oc.write(">{.result=" + resultName + "};") - } else { - self.oc.write("return " + resultName + ";") - } - } - - fn var(mut &self, mut v: &Var) { - if !v.Constant { - self.oc.var(v) - } - } - - fn mutSlicing(mut &self, mut m: &MutSlicingExprModel) { - self.oc.write("(") - self.oc.ec.possibleRefExpr(m.Expr) - self.oc.write(").mut_slice(") - if !env::Production { - self.oc.write("\"") - self.oc.locInfo(m.Token) - self.oc.write("\", ") - } - self.oc.ec.possibleRefExpr(m.Left) - if m.Right != nil { - self.oc.write(", ") - self.oc.ec.possibleRefExpr(m.Right) - } - self.oc.write(");") - } - - fn swap(mut &self, mut m: &SwapExprModel) { - self.oc.write("std::swap(") - self.oc.ec.possibleRefExpr(m.Left.Model) - self.oc.write(", ") - self.oc.ec.possibleRefExpr(m.Right.Model) - self.oc.write(")") - } - - fn exceptionalForwarding(mut &self, mut m: &ExceptionalForwardingExprModel) { - self.oc.write("return ") - self.oc.ec.pureFuncCall(m.Expr) - } - - // Generates C++ code of statement. - fn st(mut &self, mut st: compStmt) { - if st == nil { - ret - } - match type st { - | &Scope: - self.scope((&Scope)(st)) - | &Var: - self.var((&Var)(st)) - | &Data: - self.oc.ec.model((&Data)(st).Model) - | &Conditional: - self.conditional((&Conditional)(st)) - | &InfIter: - self.infIter((&InfIter)(st)) - | &WhileIter: - self.whileIter((&WhileIter)(st)) - | &RangeIter: - self.rangeIter((&RangeIter)(st)) - | &ContSt: - self.cont((&ContSt)(st)) - | &Label: - self.label((&Label)(st)) - | &GotoSt: - self.gotoSt((&GotoSt)(st)) - | &Postfix: - self.postfix((&Postfix)(st)) - | &Assign: - self.assign((&Assign)(st)) - | &MultiAssign: - self.multiAssign((&MultiAssign)(st)) - | &Match: - self.matchSt((&Match)(st)) - | &FallSt: - self.fallSt((&FallSt)(st)) - | &BreakSt: - self.breakSt((&BreakSt)(st)) - | &RetSt: - self.retSt((&RetSt)(st)) - | &PushToSliceExprModel: - self.oc.ec.pushToSlice((&PushToSliceExprModel)(st)) - | &AppendToSliceExprModel: - self.oc.ec.appendToSlice((&AppendToSliceExprModel)(st)) - | &MutSlicingExprModel: - self.mutSlicing((&MutSlicingExprModel)(st)) - | &SwapExprModel: - self.swap((&SwapExprModel)(st)) - | &ExceptionalForwardingExprModel: - self.exceptionalForwarding((&ExceptionalForwardingExprModel)(st)) - | &StrRuneIter: - self.strRuneIter((&StrRuneIter)(st)) - |: - self.oc.write("") - } - } - - fn scopeStmts(mut &self, mut &s: &Scope) { - for (_, mut st) in s.Stmts { - self.oc.indent() - self.st(st) - self.oc.write(";\n") - } - } - - // Generates C++ code of scope. - fn scope(mut &self, mut s: &Scope) { - self.oc.addIndent() - if s.Deferred { - self.oc.write("__JULE_DEFER(") - } - self.oc.write("{\n") - self.scopeStmts(s) - self.oc.doneIndent() - self.oc.indent() - self.oc.write("}") - if s.Deferred { - self.oc.write(");") - } - } - - fn commonFuncScope(mut &self, mut &f: &FnIns) { - if !f.Decl.IsVoid() { - mut tup := f.Result.Tup() - if tup != nil { - self.oc.indent() - self.oc.tc.rc.tup(self.oc.Buf, tup) - self.oc.write(" " + resultName + ";\n") - for (i, mut t) in tup.Types { - if shouldInitialized(t) { - self.oc.indent() - self.oc.write(resultName + "." + resultArgName) - self.oc.write(conv::Itoa(i)) - self.oc.write(" = ") - self.oc.ec.initExpr(t) - self.oc.write(";\n") - } - } - } else if len(f.Decl.Result.Idents) == 1 { - // Non-tuple signle return type with identifier. - // Use [resultName] as identifier. - self.oc.indent() - self.oc.tc.kind(self.oc.Buf, f.Result) - self.oc.write(" " + resultName) - if shouldInitialized(f.Result) { - self.oc.write(" = ") - self.oc.ec.initExpr(f.Result) - } - self.oc.write(";\n") - } - } - self.scopeStmts(f.Scope) - if f.Decl.Exceptional && f.Decl.IsVoid() { - // Just for void exceptionals. - // Other cases checked by semantic analsis and disallowed - // if they are not returns. - self.oc.indent() - self.oc.write("return jule::VoidExceptional{};\n") - } - } - - fn anonFuncScope(mut &self, mut m: &AnonFnExprModel, ident: str) { - if m.Func.Scope == nil { - ret - } - closure := obj::IsClosure(m) - if closure { - self.oc.ec.varPrefixes = append(self.oc.ec.varPrefixes, fn(mut v: &Var): bool { ret captureVarHandling(self.oc, m, v) }) - } - self.oc.write("{\n") - self.oc.addIndent() - - if closure { - // Get ctx. - self.oc.indent() - self.oc.write(typeCoder.Ptr + "<") - self.oc.write(ident) - self.oc.write(anonFnCtxSuffix + "> " + closureCtxIdent + " = " + ctxParamIdent + ".as<") - self.oc.write(ident) - self.oc.write(anonFnCtxSuffix + ">();\n") - } - - self.commonFuncScope(m.Func) - - self.oc.doneIndent() - self.oc.indent() - self.oc.write("}") - if closure { - self.oc.ec.varPrefixes = self.oc.ec.varPrefixes[:len(self.oc.ec.varPrefixes)-1] - } - } - - // Generates C++ code of function's scope. - fn funcScope(mut &self, mut f: &FnIns) { - if f.Scope == nil { - ret - } - self.oc.write("{\n") - self.oc.addIndent() - self.commonFuncScope(f) - self.oc.doneIndent() - self.oc.indent() - self.oc.write("}") - } + static fn new(mut &oc: &ObjectCoder): &scopeCoder { + ret &scopeCoder{ + oc: oc, + } + } + + // Common head object-code for iterations of all kind. + fn iterHead[T](mut &self, &it: T, mut &ref: bool, begin: str) { + self.oc.write("{\n") + self.oc.addIndent() + self.oc.indent() + self.oc.write("auto expr = ") + if opt::Copy && isCopyOptimizable(it.Expr) { + ref = true + match type it.Expr.Model { + | &Var: + v := (&Var)(it.Expr.Model) + if v.Reference { + self.oc.ec.model(it.Expr.Model) + break + } + fall + |: + self.oc.write("&(") + self.oc.ec.model(it.Expr.Model) + self.oc.write(")") + } + } else { + self.oc.ec.possibleRefExpr(it.Expr.Model) + } + self.oc.write(";\n") + self.oc.indent() + self.oc.write("auto it = expr") + if ref { + self.oc.write("->") + } else { + self.oc.write(".") + } + self.oc.write("begin();\n") + self.oc.indent() + self.oc.write("auto expr_end = expr") + if ref { + self.oc.write("->") + } else { + self.oc.write(".") + } + self.oc.write("end();\n") + self.oc.indent() + self.oc.write(begin) + self.oc.write(":;\n") + self.oc.indent() + self.oc.write("if (it != expr_end) {\n") + self.oc.addIndent() + self.oc.indent() + } + + fn rangeIndexIter(mut &self, mut &it: &RangeIter) { + mut sb := StrBuilder.New(1 << 6) + identCoder.iterBegin(sb, uintptr(it)) + begin := sb.Str() + sb.Clear() + identCoder.iterNext(sb, uintptr(it)) + next := sb.Str() + + mut ref := false + self.iterHead(it, ref, begin) + if it.KeyA != nil { + self.oc.varInitExpr(it.KeyA, fn() { + if ref { + self.oc.write("it - expr->begin()") + } else { + self.oc.write("it - expr.begin()") + } + }) + self.oc.write("\n") + self.oc.indent() + } + if it.KeyB != nil { + it.KeyB.Reference = opt::Copy && isIterCopyOptimizable(it.Expr, it.KeyB) + self.oc.varInitExpr(it.KeyB, fn() { + unsafe { + if it.KeyB.Reference { + self.oc.write("it") + } else { + self.oc.write("*it") + } + } + }) + self.oc.write("\n") + self.oc.indent() + } + self.scope(it.Scope) + self.oc.write("\n") + self.oc.indent() + self.oc.write(next) + self.oc.write(":;\n") + self.oc.indent() + self.oc.write("++it;\n") + self.oc.indent() + if it.KeyA != nil { + identCoder.var(self.oc.Buf, it.KeyA) + self.oc.write("++;\n") + self.oc.indent() + } + self.oc.write("goto ") + self.oc.write(begin) + self.oc.write(";\n") + + // Close if. + self.oc.doneIndent() + self.oc.indent() + self.oc.write("}\n") + + self.oc.indent() + identCoder.iterEnd(self.oc.Buf, uintptr(it)) + self.oc.write(":;\n") + + // Close scope. + self.oc.doneIndent() + self.oc.indent() + self.oc.write("}") + } + + fn rangeHashmapIter(mut &self, mut &it: &RangeIter) { + mut sb := StrBuilder.New(1 << 6) + identCoder.iterBegin(sb, uintptr(it)) + begin := sb.Str() + sb.Clear() + identCoder.iterNext(sb, uintptr(it)) + next := sb.Str() + + mut ref := false + self.iterHead(it, ref, begin) + if it.KeyA != nil { + self.oc.varInitExpr(it.KeyA, fn() { self.oc.write("it->first") }) + self.oc.write("\n") + self.oc.indent() + } + if it.KeyB != nil { + self.oc.varInitExpr(it.KeyB, fn() { self.oc.write("it->second") }) + self.oc.write("\n") + self.oc.indent() + } + self.scope(it.Scope) + self.oc.write("\n") + self.oc.indent() + self.oc.write(next) + self.oc.write(":;\n") + self.oc.indent() + self.oc.write("++it;\n") + self.oc.indent() + self.oc.write("goto ") + self.oc.write(begin) + self.oc.write(";\n") + + // Close if. + self.oc.doneIndent() + self.oc.indent() + self.oc.write("}\n") + + self.oc.indent() + identCoder.iterEnd(self.oc.Buf, uintptr(it)) + self.oc.write(":;\n") + + // Close scope. + self.oc.doneIndent() + self.oc.indent() + self.oc.write("}") + } + + fn strRuneIter(mut &self, mut it: &StrRuneIter) { + mut sb := StrBuilder.New(1 << 6) + identCoder.iterBegin(sb, uintptr(it.Base)) + begin := sb.Str() + sb.Clear() + identCoder.iterNext(sb, uintptr(it.Base)) + next := sb.Str() + + self.oc.write("{\n") + self.oc.addIndent() + self.oc.indent() + + mut ref := false + self.oc.write("auto expr = ") + if opt::Copy && isCopyOptimizable(it.Expr) { + ref = true + match type it.Expr.Model { + | &Var: + v := (&Var)(it.Expr.Model) + if v.Reference { + self.oc.ec.model(it.Expr.Model) + break + } + fall + |: + self.oc.write("&(") + self.oc.ec.model(it.Expr.Model) + self.oc.write(")") + } + } else { + self.oc.ec.possibleRefExpr(it.Expr.Model) + } + self.oc.write(";\n") + self.oc.indent() + self.oc.write("char *it = expr") + if ref { + self.oc.write("->") + } else { + self.oc.write(".") + } + self.oc.write("operator char*();\n") + self.oc.indent() + self.oc.write("const char *end = it + expr") + if ref { + self.oc.write("->") + } else { + self.oc.write(".") + } + self.oc.write("len();\n") + self.oc.indent() + + // Variables. + if it.Base.KeyA != nil { + self.oc.varInitExpr(it.Base.KeyA, fn() { self.oc.write("0") }) + self.oc.write("\n") + self.oc.indent() + } + self.oc.write("std::size_t len;\n") + self.oc.indent() + if it.Base.KeyB != nil { + self.oc.varInitExpr(it.Base.KeyB, nil) + self.oc.write("\n") + self.oc.indent() + } + self.oc.write(begin) + self.oc.write(":;\n") + self.oc.indent() + self.oc.write("std::tie(") + if it.Base.KeyB != nil { + identCoder.var(self.oc.Buf, it.Base.KeyB) + } else { + self.oc.write("std::ignore") + } + self.oc.write(", len) = jule::utf8_decode_rune_str(it, end - it") + self.oc.write(");\n") + self.oc.indent() + + self.oc.write("if (it < end) {\n") + self.oc.addIndent() + self.oc.indent() + self.scope(it.Base.Scope) + self.oc.write("\n") + self.oc.indent() + self.oc.write(next) + self.oc.write(":;\n") + self.oc.indent() + self.oc.write("it += len;\n") + self.oc.indent() + if it.Base.KeyA != nil { + identCoder.var(self.oc.Buf, it.Base.KeyA) + self.oc.write("++;\n") + self.oc.indent() + } + self.oc.write("goto ") + self.oc.write(begin) + self.oc.write(";\n") + + // Close if. + self.oc.doneIndent() + self.oc.indent() + self.oc.write("}\n") + + // Close scope. + self.oc.doneIndent() + self.oc.indent() + self.oc.write("}") + } + + fn ifCase(mut &self, mut i: &If) { + if i.Expr != nil { + self.oc.write("if (") + self.oc.ec.possibleRefExpr(i.Expr) + self.oc.write(") ") + } + self.scope(i.Scope) + } + + fn conditional(mut &self, mut c: &Conditional) { + mut writed := false + for (_, mut elif) in c.Elifs { + if elif == nil { + continue + } + if writed { + self.oc.write(" else ") + } + writed = true + self.ifCase(elif) + } + if c.Default != nil { + if writed { + self.oc.write(" else ") + } + self.scope(c.Default.Scope) + } + } + + fn infIter(mut &self, mut it: &InfIter) { + self.oc.write("for (;;) {\n") + self.oc.addIndent() // Indent scope. + self.oc.indent() + self.scope(it.Scope) + self.oc.doneIndent() + self.oc.write("\n") + self.oc.indent() + identCoder.iterNext(self.oc.Buf, uintptr(it)) + self.oc.write(":;\n") + self.oc.indent() + self.oc.write("}\n") + self.oc.indent() + identCoder.iterEnd(self.oc.Buf, uintptr(it)) + self.oc.write(":;") + } + + fn whileIter(mut &self, mut it: &WhileIter) { + if it.Expr != nil && it.Next == nil { + self.oc.write("while (") + self.oc.ec.possibleRefExpr(it.Expr) + self.oc.write(") {") + } else { + self.oc.write("for (; ") + if it.Expr != nil { + self.oc.ec.possibleRefExpr(it.Expr) + } + self.oc.write("; ") + if it.Next != nil { + self.st(it.Next) + } + self.oc.write(") {") + } + + if len(it.Scope.Stmts) == 0 { + self.oc.write("}") + ret + } + + self.oc.write("\n") + self.oc.addIndent() + self.oc.indent() + self.scope(it.Scope) + self.oc.write("\n") + self.oc.doneIndent() + self.oc.indent() + + identCoder.iterNext(self.oc.Buf, uintptr(it)) + self.oc.write(":;\n") + self.oc.indent() + self.oc.write("}\n") + self.oc.indent() + identCoder.iterEnd(self.oc.Buf, uintptr(it)) + self.oc.write(":;") + } + + fn rangeIter(mut &self, mut it: &RangeIter) { + match { + | it.Expr.Kind.Slc() != nil: + self.rangeIndexIter(it) + | it.Expr.Kind.Arr() != nil: + self.rangeIndexIter(it) + | it.Expr.Kind.Map() != nil: + self.rangeHashmapIter(it) + |: + self.rangeIndexIter(it) // Str + } + } + + fn cont(mut &self, c: &ContSt) { + self.oc.write("goto ") + identCoder.iterNext(self.oc.Buf, c.It) + } + + fn label(mut &self, l: &Label) { + identCoder.label(self.oc.Buf, uintptr(l)) + self.oc.write(":") + } + + fn gotoSt(mut &self, gt: &GotoSt) { + self.oc.write("goto ") + identCoder.label(self.oc.Buf, uintptr(gt.Label)) + } + + fn postfix(mut &self, mut p: &Postfix) { + self.oc.write("(") + self.oc.ec.possibleRefExpr(p.Expr) + self.oc.write(")") + self.oc.write(p.Op) + } + + fn assign(mut &self, mut a: &Assign) { + self.oc.ec.possibleRefExpr(a.Left.Model) + self.oc.write(a.Op.Kind) + self.oc.ec.possibleRefExpr(a.Right.Model) + } + + fn mapLookupAssign(mut &self, mut &a: &MultiAssign) { + mut iem := (&IndexingExprModel)(a.Right) + self.oc.ec.possibleRefExpr(iem.Expr.Model) + self.oc.write(".lookup(") + self.oc.ec.possibleRefExpr(iem.Index.Model) + self.oc.write(", ") + if a.Left[0] != nil { + self.oc.write("&(") + self.oc.ec.possibleRefExpr(a.Left[0].Model) + self.oc.write("), ") + } else { + self.oc.write("nullptr, ") + } + if a.Left[1] != nil { + self.oc.write("&(") + self.oc.ec.possibleRefExpr(a.Left[1].Model) + self.oc.write(")") + } else { + self.oc.write("nullptr") + } + self.oc.write(")") + } + + fn multiAssignTup(mut &self, mut &a: &MultiAssign) { + self.oc.write("({\n") + self.oc.addIndent() + + mut tup := (&TupleExprModel)(a.Right) + + for (i, mut r) in tup.Datas { + self.oc.indent() + mut l := a.Left[i] + if l != nil { + match type l.Model { + | &Var: + mut v := (&Var)(l.Model) + // If variable is reference and uninitialized, + // it should be declared in this multiple-assignment. + if v.Reference && !v.IsInitialized() { + identCoder.var(self.oc.Buf, v) + self.oc.write(" = &(") + self.oc.ec.possibleRefExpr(r.Model) + self.oc.write(");\n") + a.Left[i] = nil // Ignore handling for following statements. + continue + } + } + self.oc.tc.kind(self.oc.Buf, l.Kind) + self.oc.write(" ") + identCoder.toOut(self.oc.Buf, assignArgName, uintptr(i)) + self.oc.write(" = ") + } + self.oc.ec.possibleRefExpr(r.Model) + self.oc.write(";\n") + } + + for (i, mut l) in a.Left { + if l == nil { + continue + } + self.oc.indent() + self.oc.ec.possibleRefExpr(l.Model) + self.oc.write(" = ") + identCoder.toOut(self.oc.Buf, assignArgName, uintptr(i)) + self.oc.write(";\n") + } + + self.oc.doneIndent() + self.oc.indent() + self.oc.write("})") + } + + fn multiAssignFn(mut &self, mut &a: &MultiAssign) { + self.oc.write("({\n") + self.oc.addIndent() + self.oc.indent() + + mut f := (&FnCallExprModel)(a.Right) + self.oc.tc.rc.codeMut1(self.oc.Buf, f.Func.Result) + self.oc.write(" " + assignResultName + " = ") + self.oc.ec.possibleRefExpr(a.Right) + self.oc.write(";\n") + + mut tup := f.Func.Result.Tup() + for (i, mut l) in a.Left { + if l != nil { + const r = assignResultName + "." + resultArgName + self.oc.indent() + self.oc.ec.possibleRefExpr(l.Model) + match { + | tup.Types[i].Equal(l.Kind): + self.oc.write(" = " + r) + self.oc.write(conv::Itoa(i)) + | obj::IsAny(l.Kind): + self.oc.write(" = " + typeCoder.Any + "(" + r) + self.oc.write(conv::Itoa(i)) + self.oc.write(", &" + anyTypeIdent) + self.oc.write(conv::Itoa(self.oc.pushAnyType(tup.Types[i]))) + self.oc.write(")") + |: + // It should be trait. + if tup.Types[i].Trait() != nil { // Different traits, cast. + self.oc.write(" = ") + mut t1 := l.Kind.Trait() + mut t2 := tup.Types[i].Trait() + self.oc.write(r) + self.oc.write(conv::Itoa(i)) + self.oc.write(".map<") + identCoder.traitDecl(self.oc.Buf, t1) + self.oc.write(">(") + self.oc.pushAndWriteMaskMapper(t1, t2) + self.oc.write(")") + break + } + t := l.Kind.Trait() + self.oc.write(" = " + typeCoder.Trait + "(" + r) + self.oc.write(conv::Itoa(i)) + self.oc.write(", (" + typeCoder.Trait + "::Type*)&") + identCoder.traitDecl(self.oc.Buf, t) + self.oc.write("_mptr_data") + self.oc.write(conv::Itoa(obj::FindTraitTypeOffset(t, tup.Types[i]))) + self.oc.write(")") + } + self.oc.write(";\n") + } + } + + self.oc.doneIndent() + self.oc.indent() + self.oc.write("})") + } + + fn multiAssign(mut &self, mut a: &MultiAssign) { + // Write declarations without no initialization. + // It will initialize with assignments. + for (_, mut d) in a.Decls { + self.oc.varInitExpr(d, nil) + self.oc.write("\n") + self.oc.indent() + } + + // Special cases. + match type a.Right { + | &IndexingExprModel: // Map lookup. + self.mapLookupAssign(a) + ret + } + + match type a.Right { + | &TupleExprModel: + self.multiAssignTup(a) + | &FnCallExprModel: + self.multiAssignFn(a) + |: + panic("this panic call should be unreachable") + } + } + + fn matchExpr(mut &self, mut m: &Match): fn() { + if !m.Expr.IsConst() { + ret fn() { self.oc.write(matchExpr) } + } + if !m.Expr.Constant.IsBool() || !m.Expr.Constant.ReadBool() { + ret fn() { self.oc.ec.possibleRefExpr(m.Expr.Model) } + } + ret nil + } + + fn case(mut &self, mut m: &Match, mut c: &Case) { + if len(c.Exprs) != 0 && !m.Comptime { + if len(m.Cases) > 0 && m.Cases[0] == c { + self.oc.write("if (") + } else { + self.oc.write("else if (") + } + for (i, mut expr) in c.Exprs { + match { + | !m.TypeMatch: + caseExpr := self.matchExpr(m) + if m.Expr.GoodOperand(expr) { + if caseExpr != nil { + caseExpr() + self.oc.write(" == ") + } + self.oc.ec.possibleRefExpr(expr.Model) + } else { + self.oc.ec.possibleRefExpr(expr.Model) + if caseExpr != nil { + self.oc.write(" == ") + caseExpr() + } + } + |: + self.oc.write(matchExpr) + mut tk := (&TypeKind)(expr.Model) + if m.Expr.Kind.Trait() != nil { + self.oc.write(".type_is(") + self.oc.ec.boolean(expr.Kind.Sptr() != nil) + self.oc.write(", (const " + typeCoder.Trait + "::Type*)&") + identCoder.traitDecl(self.oc.Buf, m.Expr.Kind.Trait()) + self.oc.write("_mptr_data") + self.oc.write(conv::Itoa(obj::FindTraitTypeOffset(m.Expr.Kind.Trait(), expr.Kind))) + self.oc.write(")") + } else { // Any type. + j := self.oc.pushAnyType(tk) + self.oc.write(".type == &" + anyTypeIdent) + self.oc.write(conv::Itoa(j)) + } + } + + if len(c.Exprs)-i > 1 { + self.oc.write(" || ") + } + } + self.oc.write(") ") + } else if m.Default == c && len(m.Cases) != 0 { + self.oc.indent() + self.oc.write("else ") + } + + self.oc.addIndent() + + self.oc.write("{\n") + self.oc.indent() + identCoder.caseBegin(self.oc.Buf, uintptr(c)) + self.oc.write(":;\n") + if len(c.Scope.Stmts) > 0 { + self.oc.indent() + self.scope(c.Scope) + self.oc.write("\n") + } + + self.oc.doneIndent() + + self.oc.indent() + self.oc.write("}") + } + + fn matchSt(mut &self, mut m: &Match) { + if len(m.Cases) == 0 && m.Default == nil { + ret + } + + if m.Comptime && (m.Default == nil || len(m.Default.Scope.Stmts) == 0) { + ret + } + + self.oc.write("{\n") + + self.oc.addIndent() + + self.oc.indent() + + // Constant expressions generated as literals in conditions. + if !m.Comptime && !m.Expr.IsConst() { + if opt::Copy && isCopyOptimizable(m.Expr) { + self.oc.write("auto &_match_expr{ ") + } else { + self.oc.write("auto _match_expr{ ") + } + self.oc.ec.possibleRefExpr(m.Expr.Model) + self.oc.write(" };\n") + self.oc.indent() + } + + if len(m.Cases) > 0 { + for (_, mut c) in m.Cases { + if c == nil { + continue + } + self.oc.write("\n") + self.oc.indent() + self.case(m, c) + } + } + + if m.Default != nil { + self.oc.write("\n") + self.case(m, m.Default) + } + + self.oc.write("\n") + self.oc.indent() + identCoder.matchEnd(self.oc.Buf, uintptr(m)) + self.oc.write(":;") + self.oc.write("\n") + + self.oc.doneIndent() + + self.oc.indent() + self.oc.write("}") + } + + fn fallSt(mut &self, f: &FallSt) { + self.oc.write("goto ") + identCoder.caseBegin(self.oc.Buf, f.DestCase) + } + + fn breakSt(mut &self, b: &BreakSt) { + self.oc.write("goto ") + if b.It != 0 { + identCoder.iterEnd(self.oc.Buf, b.It) + } else { + identCoder.matchEnd(self.oc.Buf, b.Mtch) + } + } + + fn setResult(mut &self, mut r: &RetSt) { + if len(r.Func.Decl.Result.Idents) == 1 { + self.oc.write(resultName + " = ") + self.oc.ec.possibleRefExpr(r.Expr) + self.oc.write(";\n") + self.oc.indent() + ret + } + match type r.Expr { + | &TupleExprModel: + mut datas := (&TupleExprModel)(r.Expr).Datas + for i, data in datas { + self.oc.write(resultName + "." + resultArgName) + self.oc.write(conv::Itoa(i)) + self.oc.write(" = ") + self.oc.ec.possibleRefExpr(data.Model) + self.oc.write(";\n") + self.oc.indent() + } + | &FnCallExprModel: + self.oc.write(resultName + " = std::move(") + self.oc.ec.model(r.Expr) + self.oc.write(");\n") + |: + panic("implementation mistake, this panic call should be unreachable") + } + } + + fn retSt(mut &self, mut r: &RetSt) { + // Void. + if r.Func.Decl.IsVoid() { + if r.Func.Decl.Exceptional { + self.oc.write("return jule::VoidExceptional{};") + ret + } + self.oc.write("return;") + ret + } else if len(r.Func.Decl.Result.Idents) == 0 { + if r.Func.Decl.Exceptional { + self.oc.write("return jule::Exceptional<") + self.oc.tc.kind(self.oc.Buf, r.Func.Result) + self.oc.write(">{.result=") + self.oc.ec.possibleRefExpr(r.Expr) + self.oc.write("};") + } else { + self.oc.write("return ") + self.oc.ec.possibleRefExpr(r.Expr) + self.oc.write(";") + } + ret + } + + if r.Expr != nil { + self.setResult(r) + } + if r.Func.Decl.Exceptional { + self.oc.write("return jule::Exceptional<") + self.oc.tc.rc.codeMut1(self.oc.Buf, r.Func.Result) + self.oc.write(">{.result=" + resultName + "};") + } else { + self.oc.write("return " + resultName + ";") + } + } + + fn var(mut &self, mut v: &Var) { + if !v.Constant { + self.oc.var(v) + } + } + + fn mutSlicing(mut &self, mut m: &MutSlicingExprModel) { + self.oc.write("(") + self.oc.ec.possibleRefExpr(m.Expr) + self.oc.write(").mut_slice(") + if !env::Production { + self.oc.write("\"") + self.oc.locInfo(m.Token) + self.oc.write("\", ") + } + self.oc.ec.possibleRefExpr(m.Left) + if m.Right != nil { + self.oc.write(", ") + self.oc.ec.possibleRefExpr(m.Right) + } + self.oc.write(");") + } + + fn swap(mut &self, mut m: &SwapExprModel) { + self.oc.write("std::swap(") + self.oc.ec.possibleRefExpr(m.Left.Model) + self.oc.write(", ") + self.oc.ec.possibleRefExpr(m.Right.Model) + self.oc.write(")") + } + + fn exceptionalForwarding(mut &self, mut m: &ExceptionalForwardingExprModel) { + self.oc.write("return ") + self.oc.ec.pureFuncCall(m.Expr) + } + + // Generates C++ code of statement. + fn st(mut &self, mut st: compStmt) { + if st == nil { + ret + } + match type st { + | &Scope: + self.scope((&Scope)(st)) + | &Var: + self.var((&Var)(st)) + | &Data: + self.oc.ec.model((&Data)(st).Model) + | &Conditional: + self.conditional((&Conditional)(st)) + | &InfIter: + self.infIter((&InfIter)(st)) + | &WhileIter: + self.whileIter((&WhileIter)(st)) + | &RangeIter: + self.rangeIter((&RangeIter)(st)) + | &ContSt: + self.cont((&ContSt)(st)) + | &Label: + self.label((&Label)(st)) + | &GotoSt: + self.gotoSt((&GotoSt)(st)) + | &Postfix: + self.postfix((&Postfix)(st)) + | &Assign: + self.assign((&Assign)(st)) + | &MultiAssign: + self.multiAssign((&MultiAssign)(st)) + | &Match: + self.matchSt((&Match)(st)) + | &FallSt: + self.fallSt((&FallSt)(st)) + | &BreakSt: + self.breakSt((&BreakSt)(st)) + | &RetSt: + self.retSt((&RetSt)(st)) + | &PushToSliceExprModel: + self.oc.ec.pushToSlice((&PushToSliceExprModel)(st)) + | &AppendToSliceExprModel: + self.oc.ec.appendToSlice((&AppendToSliceExprModel)(st)) + | &MutSlicingExprModel: + self.mutSlicing((&MutSlicingExprModel)(st)) + | &SwapExprModel: + self.swap((&SwapExprModel)(st)) + | &ExceptionalForwardingExprModel: + self.exceptionalForwarding((&ExceptionalForwardingExprModel)(st)) + | &StrRuneIter: + self.strRuneIter((&StrRuneIter)(st)) + |: + self.oc.write("") + } + } + + fn scopeStmts(mut &self, mut &s: &Scope) { + for (_, mut st) in s.Stmts { + self.oc.indent() + self.st(st) + self.oc.write(";\n") + } + } + + // Generates C++ code of scope. + fn scope(mut &self, mut s: &Scope) { + self.oc.addIndent() + if s.Deferred { + self.oc.write("__JULE_DEFER(") + } + self.oc.write("{\n") + self.scopeStmts(s) + self.oc.doneIndent() + self.oc.indent() + self.oc.write("}") + if s.Deferred { + self.oc.write(");") + } + } + + fn commonFuncScope(mut &self, mut &f: &FnIns) { + if !f.Decl.IsVoid() { + mut tup := f.Result.Tup() + if tup != nil { + self.oc.indent() + self.oc.tc.rc.tup(self.oc.Buf, tup) + self.oc.write(" " + resultName + ";\n") + for (i, mut t) in tup.Types { + if shouldInitialized(t) { + self.oc.indent() + self.oc.write(resultName + "." + resultArgName) + self.oc.write(conv::Itoa(i)) + self.oc.write(" = ") + self.oc.ec.initExpr(t) + self.oc.write(";\n") + } + } + } else if len(f.Decl.Result.Idents) == 1 { + // Non-tuple signle return type with identifier. + // Use [resultName] as identifier. + self.oc.indent() + self.oc.tc.kind(self.oc.Buf, f.Result) + self.oc.write(" " + resultName) + if shouldInitialized(f.Result) { + self.oc.write(" = ") + self.oc.ec.initExpr(f.Result) + } + self.oc.write(";\n") + } + } + self.scopeStmts(f.Scope) + if f.Decl.Exceptional && f.Decl.IsVoid() { + // Just for void exceptionals. + // Other cases checked by semantic analsis and disallowed + // if they are not returns. + self.oc.indent() + self.oc.write("return jule::VoidExceptional{};\n") + } + } + + fn anonFuncScope(mut &self, mut m: &AnonFnExprModel, ident: str) { + if m.Func.Scope == nil { + ret + } + closure := obj::IsClosure(m) + if closure { + self.oc.ec.varPrefixes = append(self.oc.ec.varPrefixes, fn(mut v: &Var): bool { ret captureVarHandling(self.oc, m, v) }) + } + self.oc.write("{\n") + self.oc.addIndent() + + if closure { + // Get ctx. + self.oc.indent() + self.oc.write(typeCoder.Ptr + "<") + self.oc.write(ident) + self.oc.write(anonFnCtxSuffix + "> " + closureCtxIdent + " = " + ctxParamIdent + ".as<") + self.oc.write(ident) + self.oc.write(anonFnCtxSuffix + ">();\n") + } + + self.commonFuncScope(m.Func) + + self.oc.doneIndent() + self.oc.indent() + self.oc.write("}") + if closure { + self.oc.ec.varPrefixes = self.oc.ec.varPrefixes[:len(self.oc.ec.varPrefixes)-1] + } + } + + // Generates C++ code of function's scope. + fn funcScope(mut &self, mut f: &FnIns) { + if f.Scope == nil { + ret + } + self.oc.write("{\n") + self.oc.addIndent() + self.commonFuncScope(f) + self.oc.doneIndent() + self.oc.indent() + self.oc.write("}") + } } fn isCopyOptimizable(&expr: &Data): bool { - if !expr.Lvalue { - ret false - } - match type expr.Model { - | &SlicingExprModel: - ret false - } - ret true + if !expr.Lvalue { + ret false + } + match type expr.Model { + | &SlicingExprModel: + ret false + } + ret true } fn isIterCopyOptimizable(&expr: &Data, &v: &Var): bool { - if !expr.Lvalue && !expr.Kind.Mutable() { - ret true - } - ret !v.Mutable && !expr.Mutable + if !expr.Lvalue && !expr.Kind.Mutable() { + ret true + } + ret !v.Mutable && !expr.Mutable } fn captureVarHandling(mut &oc: &ObjectCoder, mut &m: &AnonFnExprModel, mut &v: &Var): bool { - for _, cv in m.Captured { - if cv == v { - oc.write(closureCtxIdent + ".alloc->") - identCoder.var(oc.Buf, v) - ret true - } - } - ret false + for _, cv in m.Captured { + if cv == v { + oc.write(closureCtxIdent + ".alloc->") + identCoder.var(oc.Buf, v) + ret true + } + } + ret false } \ No newline at end of file diff --git a/src/julec/obj/cxx/test.jule b/src/julec/obj/cxx/test.jule index 5cfb1c51e..b8810f760 100644 --- a/src/julec/obj/cxx/test.jule +++ b/src/julec/obj/cxx/test.jule @@ -5,155 +5,155 @@ use env use obj::{self, IR} use std::jule::build::{ - Directive, + Directive, } use std::jule::sema::{ - ImportInfo, - Package, - Fn, - FnIns, - StructIns, + ImportInfo, + Package, + Fn, + FnIns, + StructIns, } use std::strings::{StrBuilder} struct TestCoder { - t: &StructIns - tmReset: &Fn - tmFailed: &Fn - tmSkipped: &Fn + t: &StructIns + tmReset: &Fn + tmFailed: &Fn + tmSkipped: &Fn - oc: &ObjectCoder + oc: &ObjectCoder } impl TestCoder { - static fn New(mut &oc: &ObjectCoder): &TestCoder { - ret &TestCoder{ - oc: oc, - } - } - - fn findTestingPackage(mut &self): &ImportInfo { - for (_, mut imp) in self.oc.ir.Used { - if imp.LinkPath == "std::testing" { - ret imp - } - } - ret nil - } - - fn appendTest(mut &self, mut f: &FnIns) { - self.oc.indent() - self.callTmReset() - self.oc.write(";\n") - self.oc.indent() - self.oc.write("std::cout << \">>> TEST RUNNING: \" ") - cstrLit(self.oc.Buf, f.Decl.Ident) - self.oc.write(" << std::endl;\n") - self.oc.indent() - identCoder.funcIns(self.oc.Buf, f) - self.oc.write("(_t);\n") - self.oc.indent() - self.oc.write("post_test();\n") - } - - fn appendPackageTests(mut &self, mut &p: &Package) { - for (_, mut file) in p.Files { - for (_, mut f) in file.Funcs { - if obj::HasDirective(f.Directives, Directive.Test) { - self.appendTest(f.Instances[0]) - } - } - } - } - - fn readyTestingPackage(mut &self): bool { - mut p := self.findTestingPackage() - if p == nil { - // std::testing is not used. - // So, developers cannot write valid test functions. - ret false - } - - self.t = p.FindStruct("T", false).Instances[0] - - self.tmReset = self.t.FindMethod("reset", false) - self.tmFailed = self.t.FindMethod("Failed", false) - self.tmSkipped = self.t.FindMethod("Skipped", false) - ret true - } - - fn callTmReset(mut &self) { - identCoder.func(self.oc.Buf, self.tmReset) - self.oc.write("(_t)") - } - - fn callTmFailed(mut &self) { - identCoder.func(self.oc.Buf, self.tmFailed) - self.oc.write("(_t)") - } - - fn callTmSkipped(mut &self) { - identCoder.func(self.oc.Buf, self.tmSkipped) - self.oc.write("(_t)") - } - - // Serialize tests and test point. - // Appends to object code. - fn Serialize(mut &self) { - self.oc.serializeHead() - defer { - self.oc.end() - } - - self.oc.write("\nvoid test_point(void) {\n") - self.oc.addIndent() - self.oc.indent() - - if !self.readyTestingPackage() { - self.oc.write("}") - self.oc.doneIndent() - ret - } - - mut tb := StrBuilder.New(40) - self.oc.tc.structureIns(tb, self.t) - self.oc.tc.asSptr(self.oc.Buf, unsafe { tb.Buf() }) - self.oc.write(" _t = jule::new_ptr<") - self.oc.writeBytes(unsafe { tb.Buf() }) - self.oc.write(">(); _t.ref = nullptr;\n") - - self.oc.indent() - self.oc.write("jule::Uint total = 0, failed = 0, skipped = 0;\n") - self.oc.indent() - - self.oc.write("auto post_test = [&](void) {\n") - self.oc.addIndent() - self.oc.indent() - self.oc.write("++total;\n") - self.oc.indent() - self.oc.write("if (") - self.callTmFailed() - self.oc.write(") { ++failed; std::cout << \" [*] FAILED\" << std::endl; }\n") - self.oc.indent() - self.oc.write("else if (") - self.callTmSkipped() - self.oc.write(") { ++skipped; std::cout << \" [*] SKIPPED\" << std::endl; }\n") - self.oc.indent() - self.oc.write("else { std::cout << \" [*] PASSED\" << std::endl; }\n") - self.oc.doneIndent() - self.oc.indent() - self.oc.write("};\n") - - self.appendPackageTests(self.oc.ir.Main) - - self.oc.write("\n\n") - self.oc.indent() - self.oc.write("std::cout << std::endl << \"total tests: \" << total << \" skipped: \" << skipped << \" failed: \" << failed << \" pass: \" << total-failed-skipped << std::endl;\n") - self.oc.indent() - self.oc.write("if (failed != 0) std::exit(1);\n") - - self.oc.doneIndent() - self.oc.indent() - self.oc.write("}\n") - } + static fn New(mut &oc: &ObjectCoder): &TestCoder { + ret &TestCoder{ + oc: oc, + } + } + + fn findTestingPackage(mut &self): &ImportInfo { + for (_, mut imp) in self.oc.ir.Used { + if imp.LinkPath == "std::testing" { + ret imp + } + } + ret nil + } + + fn appendTest(mut &self, mut f: &FnIns) { + self.oc.indent() + self.callTmReset() + self.oc.write(";\n") + self.oc.indent() + self.oc.write("std::cout << \">>> TEST RUNNING: \" ") + cstrLit(self.oc.Buf, f.Decl.Ident) + self.oc.write(" << std::endl;\n") + self.oc.indent() + identCoder.funcIns(self.oc.Buf, f) + self.oc.write("(_t);\n") + self.oc.indent() + self.oc.write("post_test();\n") + } + + fn appendPackageTests(mut &self, mut &p: &Package) { + for (_, mut file) in p.Files { + for (_, mut f) in file.Funcs { + if obj::HasDirective(f.Directives, Directive.Test) { + self.appendTest(f.Instances[0]) + } + } + } + } + + fn readyTestingPackage(mut &self): bool { + mut p := self.findTestingPackage() + if p == nil { + // std::testing is not used. + // So, developers cannot write valid test functions. + ret false + } + + self.t = p.FindStruct("T", false).Instances[0] + + self.tmReset = self.t.FindMethod("reset", false) + self.tmFailed = self.t.FindMethod("Failed", false) + self.tmSkipped = self.t.FindMethod("Skipped", false) + ret true + } + + fn callTmReset(mut &self) { + identCoder.func(self.oc.Buf, self.tmReset) + self.oc.write("(_t)") + } + + fn callTmFailed(mut &self) { + identCoder.func(self.oc.Buf, self.tmFailed) + self.oc.write("(_t)") + } + + fn callTmSkipped(mut &self) { + identCoder.func(self.oc.Buf, self.tmSkipped) + self.oc.write("(_t)") + } + + // Serialize tests and test point. + // Appends to object code. + fn Serialize(mut &self) { + self.oc.serializeHead() + defer { + self.oc.end() + } + + self.oc.write("\nvoid test_point(void) {\n") + self.oc.addIndent() + self.oc.indent() + + if !self.readyTestingPackage() { + self.oc.write("}") + self.oc.doneIndent() + ret + } + + mut tb := StrBuilder.New(40) + self.oc.tc.structureIns(tb, self.t) + self.oc.tc.asSptr(self.oc.Buf, unsafe { tb.Buf() }) + self.oc.write(" _t = jule::new_ptr<") + self.oc.writeBytes(unsafe { tb.Buf() }) + self.oc.write(">(); _t.ref = nullptr;\n") + + self.oc.indent() + self.oc.write("jule::Uint total = 0, failed = 0, skipped = 0;\n") + self.oc.indent() + + self.oc.write("auto post_test = [&](void) {\n") + self.oc.addIndent() + self.oc.indent() + self.oc.write("++total;\n") + self.oc.indent() + self.oc.write("if (") + self.callTmFailed() + self.oc.write(") { ++failed; std::cout << \" [*] FAILED\" << std::endl; }\n") + self.oc.indent() + self.oc.write("else if (") + self.callTmSkipped() + self.oc.write(") { ++skipped; std::cout << \" [*] SKIPPED\" << std::endl; }\n") + self.oc.indent() + self.oc.write("else { std::cout << \" [*] PASSED\" << std::endl; }\n") + self.oc.doneIndent() + self.oc.indent() + self.oc.write("};\n") + + self.appendPackageTests(self.oc.ir.Main) + + self.oc.write("\n\n") + self.oc.indent() + self.oc.write("std::cout << std::endl << \"total tests: \" << total << \" skipped: \" << skipped << \" failed: \" << failed << \" pass: \" << total-failed-skipped << std::endl;\n") + self.oc.indent() + self.oc.write("if (failed != 0) std::exit(1);\n") + + self.oc.doneIndent() + self.oc.indent() + self.oc.write("}\n") + } } \ No newline at end of file diff --git a/src/julec/obj/cxx/type.jule b/src/julec/obj/cxx/type.jule index 89ef0c6cb..76a7cb23c 100644 --- a/src/julec/obj/cxx/type.jule +++ b/src/julec/obj/cxx/type.jule @@ -8,24 +8,24 @@ use ast for std::jule::ast use conv for std::conv use std::jule::build::{Directive} use std::jule::sema::{ - Prim, - Tuple, - Sptr, - Ptr, - Slc, - Enum, - TypeEnum, - TypeKind, - Map, - Trait, - Struct, - StructIns, - FnIns, - Arr, - ParamIns, - Fn, - Param, - Kind, + Prim, + Tuple, + Sptr, + Ptr, + Slc, + Enum, + TypeEnum, + TypeKind, + Map, + Trait, + Struct, + StructIns, + FnIns, + Arr, + ParamIns, + Fn, + Param, + Kind, } use types for std::jule::types use std::strings::{StrBuilder} @@ -33,456 +33,456 @@ use std::strings::{StrBuilder} const ctxParamType = typeCoder.Ptr + "<" + typeCoder.Uintptr + ">" struct customType { - kind: str + kind: str } impl Kind for customType { - fn Str(self): str { - ret self.kind - } + fn Str(self): str { + ret self.kind + } - fn Equal(&self, k: &TypeKind): bool { - ret false - } + fn Equal(&self, k: &TypeKind): bool { + ret false + } } struct typeCoder { - oc: &ObjectCoder - rc: &resultCoder + oc: &ObjectCoder + rc: &resultCoder } impl typeCoder { - const Any = "jule::Any" - const Str = "jule::Str" - const Map = "jule::Map" - const Ptr = "jule::Ptr" - const Sptr = "jule::Sptr" - const Slice = "jule::Slice" - const Trait = "jule::Trait" - const Array = "jule::Array" - const Fn = "jule::Fn" - const Bool = "jule::Bool" - const Int = "jule::Int" - const Uintptr = "jule::Uintptr" - const U8 = "jule::U8" - - static fn new(mut &oc: &ObjectCoder): &typeCoder { - mut tc := &typeCoder{oc: oc} - tc.rc = resultCoder.new(tc) - ret tc - } - - // Writes given identifier as Jule type identifier. - fn toType(mut self, mut &buf: StrBuilder, mut id: str) { - if id != types::TypeKind.Uintptr { - id = types::RealKindOf(id) - } - buf.WriteStr("jule::") - if 97 <= id[0] && id[0] <= 122 { - buf.WriteByte(id[0] - 32) // To upper first byte. - } else { - buf.WriteByte(id[0]) - } - buf.WriteStr(id[1:]) - } - - // Generates C++ code of Prim TypeKind. - fn prim(mut self, mut &buf: StrBuilder, p: &Prim) { - self.toType(buf, p.Kind) - } - - // Generates C++ code of Tupe TypeKind. - fn tuple(mut self, mut &buf: StrBuilder, mut t: &Tuple) { - buf.WriteStr("std::tuple<") - for (i, mut tk) in t.Types { - self.kind(buf, tk) - if len(t.Types)-i > 1 { - buf.WriteByte(',') - } - } - buf.WriteByte('>') - } - - // Generates C++ code of smart pointer type with element type. - fn asSptr(mut self, mut &buf: StrBuilder, elem: []byte) { - buf.WriteStr(typeCoder.Ptr + "<") - buf.Write(elem) - buf.WriteByte('>') - } - - // Generates C++ code of smart pointer TypeKind. - fn sptr(mut self, mut &buf: StrBuilder, mut sptr: &Sptr) { - buf.WriteStr(typeCoder.Ptr + "<") - self.kind(buf, sptr.Elem) - buf.WriteByte('>') - } - - // Generates C++ code of Ptr TypeKind. - fn ptr(mut self, mut &buf: StrBuilder, mut p: &Ptr) { - const CppPointerMask = "*" - if p.IsUnsafe() { - buf.WriteStr("void" + CppPointerMask) - } else { - self.kind(buf, p.Elem) - buf.WriteStr(CppPointerMask) - } - } - - // Generates C++ code of Enum TypeKind. - fn enumDecl(mut self, mut &buf: StrBuilder, mut e: &Enum) { - self.kind(buf, e.Kind.Kind) - } - - // Generates C++ code of TypeEnum TypeKind. - fn typeEnumDecl(mut self, mut &buf: StrBuilder, mut e: &TypeEnum) { - buf.WriteStr(typeCoder.Any) - } - - fn asSlice(mut self, mut &buf: StrBuilder, mut elem: &TypeKind) { - buf.WriteStr(typeCoder.Slice + "<") - self.kind(buf, elem) - buf.WriteByte('>') - } - - // Generates C++ code of Slc TypeKind. - fn slice(mut self, mut &buf: StrBuilder, mut s: &Slc) { - self.asSlice(buf, s.Elem) - } - - // Generates C++ code of Map TypeKind. - fn mapType(mut self, mut &buf: StrBuilder, mut m: &Map) { - buf.WriteStr(typeCoder.Map + "<") - self.kind(buf, m.Key) - buf.WriteByte(',') - self.kind(buf, m.Val) - buf.WriteByte('>') - } - - // Generates C++ code of Struct TypeKind. - fn structure(mut self, mut &buf: StrBuilder, s: &Struct) { - identCoder.structure(buf, s) - } - - // Generates C++ code of Struct instance TypeKind. - fn structureIns(mut self, mut &buf: StrBuilder, mut s: &StructIns) { - if !s.Decl.Binded { - identCoder.structureIns(buf, s) - ret - } - d := obj::FindDirective(s.Decl.Directives, Directive.Namespace) - if d != nil { - buf.Write(concatAllParts(d.Args...)) - buf.WriteStr("::") - } - identCoder.structureIns(buf, s) - if len(s.Generics) > 0 { - buf.WriteByte('<') - for (i, mut g) in s.Generics { - self.kind(buf, g.Kind) - if len(s.Generics)-i > 1 { - buf.WriteByte(',') - } - } - buf.WriteByte('>') - } - } - - // Generates C++ code of Arr TypeKind. - fn array(mut self, mut &buf: StrBuilder, mut a: &Arr) { - buf.WriteStr(typeCoder.Array + "<") - self.kind(buf, a.Elem) - buf.WriteByte(',') - buf.WriteStr(conv::Itoa(a.N)) - buf.WriteByte('>') - } - - // Generates C++ prototype code of parameter. - fn param(mut self, mut &buf: StrBuilder, mut &p: &Param) { - if p.Variadic { - buf.WriteStr(typeCoder.Slice + "<") - self.kind(buf, p.Kind.Kind) - buf.WriteByte('>') - } else { - self.kind(buf, p.Kind.Kind) - } - if p.Reference { - buf.WriteByte('*') - } - } - - // Generates C++ prototype code of parameter instance. - fn paramIns(mut self, mut &buf: StrBuilder, mut &p: &ParamIns) { - if p.Decl.Variadic { - buf.WriteStr(typeCoder.Slice + "<") - self.kind(buf, p.Kind) - buf.WriteByte('>') - } else { - self.kind(buf, p.Kind) - } - if p.Decl.Reference { - buf.WriteByte('*') - } - } - - // Generates C++ code of function's result type. - fn funcResult(mut self, mut &buf: StrBuilder, mut &f: &Fn) { - if f.IsVoid() { - if f.Exceptional { - buf.WriteStr("jule::VoidExceptional") - ret - } - buf.WriteStr("void") - } - if f.Exceptional { - buf.WriteStr("jule::Exceptional<") - self.kind(buf, f.Result.Kind.Kind) - buf.WriteByte('>') - ret - } - self.kind(buf, f.Result.Kind.Kind) - } - - // Generates C++ code of function instance's result type. - fn funcInsResult(mut self, mut &s: StrBuilder, mut &f: &FnIns) { - if f.Decl.IsVoid() { - if f.Decl.Exceptional { - s.WriteStr("jule::VoidExceptional") - } else { - s.WriteStr("void") - } - ret - } - if f.Decl.Exceptional { - s.WriteStr("jule::Exceptional<") - self.rc.codeMut1(s, f.Result) - s.WriteByte('>') - ret - } - self.rc.codeMut1(s, f.Result) - } - - fn anonFunc(mut self, mut &buf: StrBuilder, mut f: &FnIns) { - if f.Result != nil && f.Result.Tup() != nil { - self.oc.pushResultIns(f) - } - self.funcInsResult(buf, f) - if len(f.Params) == 0 { - ret - } - buf.WriteByte(',') - for (i, mut param) in f.Params { - if param.Decl.IsSelf() { - continue - } - self.paramIns(buf, param) - if len(f.Params)-i > 1 { - buf.WriteByte(',') - } - } - } - - // Generates C++ code of Fn TypeKind. - fn func(mut self, mut &buf: StrBuilder, mut f: &FnIns) { - buf.WriteStr(typeCoder.Fn + "<") - self.anonFunc(buf, f) - buf.WriteByte('>') - } - - // Generates C++ code of TypeKind. - fn kind(mut self, mut &buf: StrBuilder, mut k: &TypeKind) { - match { - | k.Struct() != nil: - self.structureIns(buf, k.Struct()) - ret - | k.Binded(): - // As we can see here, bind defines use pure identifiers directly. - // So, if you hesitate about a type that causes wrong code generation, - // write relevant algorithms above this case. - buf.WriteStr(k.BindIdent) - ret - | k.Prim() != nil: - self.prim(buf, k.Prim()) - ret - | k.Tup() != nil: - self.tuple(buf, k.Tup()) - ret - | k.Sptr() != nil: - self.sptr(buf, k.Sptr()) - ret - | k.Ptr() != nil: - self.ptr(buf, k.Ptr()) - ret - | k.Enum() != nil: - self.enumDecl(buf, k.Enum()) - ret - | k.TypeEnum() != nil: - self.typeEnumDecl(buf, k.TypeEnum()) - ret - | k.Slc() != nil: - self.slice(buf, k.Slc()) - ret - | k.Map() != nil: - self.mapType(buf, k.Map()) - ret - | k.Trait() != nil: - buf.WriteStr(typeCoder.Trait) - ret - | k.Arr() != nil: - self.array(buf, k.Arr()) - ret - | k.Fn() != nil: - self.func(buf, k.Fn()) - ret - } - match type k.Kind { - | &customType: - buf.WriteStr((&customType)(k.Kind).kind) - |: - buf.WriteStr("[]") - } - } + const Any = "jule::Any" + const Str = "jule::Str" + const Map = "jule::Map" + const Ptr = "jule::Ptr" + const Sptr = "jule::Sptr" + const Slice = "jule::Slice" + const Trait = "jule::Trait" + const Array = "jule::Array" + const Fn = "jule::Fn" + const Bool = "jule::Bool" + const Int = "jule::Int" + const Uintptr = "jule::Uintptr" + const U8 = "jule::U8" + + static fn new(mut &oc: &ObjectCoder): &typeCoder { + mut tc := &typeCoder{oc: oc} + tc.rc = resultCoder.new(tc) + ret tc + } + + // Writes given identifier as Jule type identifier. + fn toType(mut self, mut &buf: StrBuilder, mut id: str) { + if id != types::TypeKind.Uintptr { + id = types::RealKindOf(id) + } + buf.WriteStr("jule::") + if 97 <= id[0] && id[0] <= 122 { + buf.WriteByte(id[0] - 32) // To upper first byte. + } else { + buf.WriteByte(id[0]) + } + buf.WriteStr(id[1:]) + } + + // Generates C++ code of Prim TypeKind. + fn prim(mut self, mut &buf: StrBuilder, p: &Prim) { + self.toType(buf, p.Kind) + } + + // Generates C++ code of Tupe TypeKind. + fn tuple(mut self, mut &buf: StrBuilder, mut t: &Tuple) { + buf.WriteStr("std::tuple<") + for (i, mut tk) in t.Types { + self.kind(buf, tk) + if len(t.Types)-i > 1 { + buf.WriteByte(',') + } + } + buf.WriteByte('>') + } + + // Generates C++ code of smart pointer type with element type. + fn asSptr(mut self, mut &buf: StrBuilder, elem: []byte) { + buf.WriteStr(typeCoder.Ptr + "<") + buf.Write(elem) + buf.WriteByte('>') + } + + // Generates C++ code of smart pointer TypeKind. + fn sptr(mut self, mut &buf: StrBuilder, mut sptr: &Sptr) { + buf.WriteStr(typeCoder.Ptr + "<") + self.kind(buf, sptr.Elem) + buf.WriteByte('>') + } + + // Generates C++ code of Ptr TypeKind. + fn ptr(mut self, mut &buf: StrBuilder, mut p: &Ptr) { + const CppPointerMask = "*" + if p.IsUnsafe() { + buf.WriteStr("void" + CppPointerMask) + } else { + self.kind(buf, p.Elem) + buf.WriteStr(CppPointerMask) + } + } + + // Generates C++ code of Enum TypeKind. + fn enumDecl(mut self, mut &buf: StrBuilder, mut e: &Enum) { + self.kind(buf, e.Kind.Kind) + } + + // Generates C++ code of TypeEnum TypeKind. + fn typeEnumDecl(mut self, mut &buf: StrBuilder, mut e: &TypeEnum) { + buf.WriteStr(typeCoder.Any) + } + + fn asSlice(mut self, mut &buf: StrBuilder, mut elem: &TypeKind) { + buf.WriteStr(typeCoder.Slice + "<") + self.kind(buf, elem) + buf.WriteByte('>') + } + + // Generates C++ code of Slc TypeKind. + fn slice(mut self, mut &buf: StrBuilder, mut s: &Slc) { + self.asSlice(buf, s.Elem) + } + + // Generates C++ code of Map TypeKind. + fn mapType(mut self, mut &buf: StrBuilder, mut m: &Map) { + buf.WriteStr(typeCoder.Map + "<") + self.kind(buf, m.Key) + buf.WriteByte(',') + self.kind(buf, m.Val) + buf.WriteByte('>') + } + + // Generates C++ code of Struct TypeKind. + fn structure(mut self, mut &buf: StrBuilder, s: &Struct) { + identCoder.structure(buf, s) + } + + // Generates C++ code of Struct instance TypeKind. + fn structureIns(mut self, mut &buf: StrBuilder, mut s: &StructIns) { + if !s.Decl.Binded { + identCoder.structureIns(buf, s) + ret + } + d := obj::FindDirective(s.Decl.Directives, Directive.Namespace) + if d != nil { + buf.Write(concatAllParts(d.Args...)) + buf.WriteStr("::") + } + identCoder.structureIns(buf, s) + if len(s.Generics) > 0 { + buf.WriteByte('<') + for (i, mut g) in s.Generics { + self.kind(buf, g.Kind) + if len(s.Generics)-i > 1 { + buf.WriteByte(',') + } + } + buf.WriteByte('>') + } + } + + // Generates C++ code of Arr TypeKind. + fn array(mut self, mut &buf: StrBuilder, mut a: &Arr) { + buf.WriteStr(typeCoder.Array + "<") + self.kind(buf, a.Elem) + buf.WriteByte(',') + buf.WriteStr(conv::Itoa(a.N)) + buf.WriteByte('>') + } + + // Generates C++ prototype code of parameter. + fn param(mut self, mut &buf: StrBuilder, mut &p: &Param) { + if p.Variadic { + buf.WriteStr(typeCoder.Slice + "<") + self.kind(buf, p.Kind.Kind) + buf.WriteByte('>') + } else { + self.kind(buf, p.Kind.Kind) + } + if p.Reference { + buf.WriteByte('*') + } + } + + // Generates C++ prototype code of parameter instance. + fn paramIns(mut self, mut &buf: StrBuilder, mut &p: &ParamIns) { + if p.Decl.Variadic { + buf.WriteStr(typeCoder.Slice + "<") + self.kind(buf, p.Kind) + buf.WriteByte('>') + } else { + self.kind(buf, p.Kind) + } + if p.Decl.Reference { + buf.WriteByte('*') + } + } + + // Generates C++ code of function's result type. + fn funcResult(mut self, mut &buf: StrBuilder, mut &f: &Fn) { + if f.IsVoid() { + if f.Exceptional { + buf.WriteStr("jule::VoidExceptional") + ret + } + buf.WriteStr("void") + } + if f.Exceptional { + buf.WriteStr("jule::Exceptional<") + self.kind(buf, f.Result.Kind.Kind) + buf.WriteByte('>') + ret + } + self.kind(buf, f.Result.Kind.Kind) + } + + // Generates C++ code of function instance's result type. + fn funcInsResult(mut self, mut &s: StrBuilder, mut &f: &FnIns) { + if f.Decl.IsVoid() { + if f.Decl.Exceptional { + s.WriteStr("jule::VoidExceptional") + } else { + s.WriteStr("void") + } + ret + } + if f.Decl.Exceptional { + s.WriteStr("jule::Exceptional<") + self.rc.codeMut1(s, f.Result) + s.WriteByte('>') + ret + } + self.rc.codeMut1(s, f.Result) + } + + fn anonFunc(mut self, mut &buf: StrBuilder, mut f: &FnIns) { + if f.Result != nil && f.Result.Tup() != nil { + self.oc.pushResultIns(f) + } + self.funcInsResult(buf, f) + if len(f.Params) == 0 { + ret + } + buf.WriteByte(',') + for (i, mut param) in f.Params { + if param.Decl.IsSelf() { + continue + } + self.paramIns(buf, param) + if len(f.Params)-i > 1 { + buf.WriteByte(',') + } + } + } + + // Generates C++ code of Fn TypeKind. + fn func(mut self, mut &buf: StrBuilder, mut f: &FnIns) { + buf.WriteStr(typeCoder.Fn + "<") + self.anonFunc(buf, f) + buf.WriteByte('>') + } + + // Generates C++ code of TypeKind. + fn kind(mut self, mut &buf: StrBuilder, mut k: &TypeKind) { + match { + | k.Struct() != nil: + self.structureIns(buf, k.Struct()) + ret + | k.Binded(): + // As we can see here, bind defines use pure identifiers directly. + // So, if you hesitate about a type that causes wrong code generation, + // write relevant algorithms above this case. + buf.WriteStr(k.BindIdent) + ret + | k.Prim() != nil: + self.prim(buf, k.Prim()) + ret + | k.Tup() != nil: + self.tuple(buf, k.Tup()) + ret + | k.Sptr() != nil: + self.sptr(buf, k.Sptr()) + ret + | k.Ptr() != nil: + self.ptr(buf, k.Ptr()) + ret + | k.Enum() != nil: + self.enumDecl(buf, k.Enum()) + ret + | k.TypeEnum() != nil: + self.typeEnumDecl(buf, k.TypeEnum()) + ret + | k.Slc() != nil: + self.slice(buf, k.Slc()) + ret + | k.Map() != nil: + self.mapType(buf, k.Map()) + ret + | k.Trait() != nil: + buf.WriteStr(typeCoder.Trait) + ret + | k.Arr() != nil: + self.array(buf, k.Arr()) + ret + | k.Fn() != nil: + self.func(buf, k.Fn()) + ret + } + match type k.Kind { + | &customType: + buf.WriteStr((&customType)(k.Kind).kind) + |: + buf.WriteStr("[]") + } + } } struct resultCoder { - tc: &typeCoder + tc: &typeCoder } impl resultCoder { - const Map = "m" - const Slice = "s" - const Ptr = "p" - const Sptr = "x" - const Array = "a" - const Reference = "r" - const Fn = "f" - - static fn new(mut &tc: &typeCoder): &resultCoder { - ret &resultCoder{tc: tc} - } - - fn ptr(mut self, mut &s: StrBuilder, mut p: &Ptr) { - s.WriteStr(resultCoder.Ptr) - self.codeMut(s, p.Elem) - } - - fn sptr(mut self, mut &s: StrBuilder, mut p: &Sptr) { - s.WriteStr(resultCoder.Sptr) - self.codeMut(s, p.Elem) - } - - fn mapType(mut self, mut &s: StrBuilder, mut p: &Map) { - s.WriteStr(resultCoder.Map) - self.codeMut(s, p.Key) - self.codeMut(s, p.Val) - } - - fn slice(mut self, mut &s: StrBuilder, mut slc: &Slc) { - s.WriteStr(resultCoder.Slice) - self.codeMut(s, slc.Elem) - } - - fn arr(mut self, mut &s: StrBuilder, mut arr: &Arr) { - s.WriteStr(resultCoder.Array) - s.WriteStr(conv::FmtInt(i64(arr.N), 16)) - self.codeMut(s, arr.Elem) - } - - fn func(mut self, mut &s: StrBuilder, mut f: &FnIns) { - s.WriteStr(resultCoder.Fn) - for (_, mut p) in f.Params { - if p.Decl.Reference { - s.WriteStr(resultCoder.Reference) - } - self.codeMut(s, p.Kind) - } - if f.Result != nil { - self.codeMut(s, f.Result) - } - } - - fn tup(mut self, mut &s: StrBuilder, mut tup: &Tuple) { - for (_, mut t) in tup.Types { - s.WriteStr("__jule_tuple_") - self.codeMut(s, t) - } - } - - fn codeMut(mut self, mut &s: StrBuilder, mut &t: &TypeKind) { - match type t.Kind { - | &Ptr: - self.ptr(s, (&Ptr)(t.Kind)) - | &Sptr: - self.sptr(s, (&Sptr)(t.Kind)) - | &Map: - self.mapType(s, (&Map)(t.Kind)) - | &Slc: - self.slice(s, (&Slc)(t.Kind)) - | &Arr: - self.arr(s, (&Arr)(t.Kind)) - | &FnIns: - self.func(s, (&FnIns)(t.Kind)) - | &Enum: - te := (&Enum)(t.Kind) - identCoder.toOut(s, te.Ident, uintptr(te)) - | &TypeEnum: - te := (&TypeEnum)(t.Kind) - identCoder.toOut(s, te.Ident, uintptr(te)) - | &StructIns: - mut si := (&StructIns)(t.Kind) - identCoder.structureIns(s, si) - | &Trait: - mut trt := (&Trait)(t.Kind) - identCoder.traitDecl(s, trt) - | &Prim: - s.WriteStr((&Prim)(t.Kind).Kind) - | &Tuple: - self.tup(s, (&Tuple)(t.Kind)) - |: - panic("this panic call should be unreachable") - } - } - - fn codeMut1(mut self, mut &s: StrBuilder, mut &t: &TypeKind) { - mut tup := t.Tup() - if tup != nil { - self.tup(s, tup) - } else { - self.tc.kind(s, t) - } - } - - fn code(mut self, mut &t: &TypeKind): []byte { - mut s := StrBuilder.New(20) - self.codeMut(s, t) - ret unsafe { s.Buf() } - } + const Map = "m" + const Slice = "s" + const Ptr = "p" + const Sptr = "x" + const Array = "a" + const Reference = "r" + const Fn = "f" + + static fn new(mut &tc: &typeCoder): &resultCoder { + ret &resultCoder{tc: tc} + } + + fn ptr(mut self, mut &s: StrBuilder, mut p: &Ptr) { + s.WriteStr(resultCoder.Ptr) + self.codeMut(s, p.Elem) + } + + fn sptr(mut self, mut &s: StrBuilder, mut p: &Sptr) { + s.WriteStr(resultCoder.Sptr) + self.codeMut(s, p.Elem) + } + + fn mapType(mut self, mut &s: StrBuilder, mut p: &Map) { + s.WriteStr(resultCoder.Map) + self.codeMut(s, p.Key) + self.codeMut(s, p.Val) + } + + fn slice(mut self, mut &s: StrBuilder, mut slc: &Slc) { + s.WriteStr(resultCoder.Slice) + self.codeMut(s, slc.Elem) + } + + fn arr(mut self, mut &s: StrBuilder, mut arr: &Arr) { + s.WriteStr(resultCoder.Array) + s.WriteStr(conv::FmtInt(i64(arr.N), 16)) + self.codeMut(s, arr.Elem) + } + + fn func(mut self, mut &s: StrBuilder, mut f: &FnIns) { + s.WriteStr(resultCoder.Fn) + for (_, mut p) in f.Params { + if p.Decl.Reference { + s.WriteStr(resultCoder.Reference) + } + self.codeMut(s, p.Kind) + } + if f.Result != nil { + self.codeMut(s, f.Result) + } + } + + fn tup(mut self, mut &s: StrBuilder, mut tup: &Tuple) { + for (_, mut t) in tup.Types { + s.WriteStr("__jule_tuple_") + self.codeMut(s, t) + } + } + + fn codeMut(mut self, mut &s: StrBuilder, mut &t: &TypeKind) { + match type t.Kind { + | &Ptr: + self.ptr(s, (&Ptr)(t.Kind)) + | &Sptr: + self.sptr(s, (&Sptr)(t.Kind)) + | &Map: + self.mapType(s, (&Map)(t.Kind)) + | &Slc: + self.slice(s, (&Slc)(t.Kind)) + | &Arr: + self.arr(s, (&Arr)(t.Kind)) + | &FnIns: + self.func(s, (&FnIns)(t.Kind)) + | &Enum: + te := (&Enum)(t.Kind) + identCoder.toOut(s, te.Ident, uintptr(te)) + | &TypeEnum: + te := (&TypeEnum)(t.Kind) + identCoder.toOut(s, te.Ident, uintptr(te)) + | &StructIns: + mut si := (&StructIns)(t.Kind) + identCoder.structureIns(s, si) + | &Trait: + mut trt := (&Trait)(t.Kind) + identCoder.traitDecl(s, trt) + | &Prim: + s.WriteStr((&Prim)(t.Kind).Kind) + | &Tuple: + self.tup(s, (&Tuple)(t.Kind)) + |: + panic("this panic call should be unreachable") + } + } + + fn codeMut1(mut self, mut &s: StrBuilder, mut &t: &TypeKind) { + mut tup := t.Tup() + if tup != nil { + self.tup(s, tup) + } else { + self.tc.kind(s, t) + } + } + + fn code(mut self, mut &t: &TypeKind): []byte { + mut s := StrBuilder.New(20) + self.codeMut(s, t) + ret unsafe { s.Buf() } + } } // Reports whether type should initialized. // If the type API implemented structure of something like that, initialization is redundant. // Let the constructor do it's job. fn shouldInitialized(mut &t: &TypeKind): bool { - prim := t.Prim() - if prim != nil { - ret !prim.IsAny() && !prim.IsStr() - } - match { - | t.Sptr() != nil: - ret false - | t.Map() != nil: - ret false - | t.Slc() != nil: - ret false - | t.Trait() != nil: - ret false - | t.Fn() != nil: - ret false - | t.Arr() != nil: - mut arr := t.Arr() - ret shouldInitialized(arr.Elem) - | t.Struct() != nil: - ret false - |: - ret true - } + prim := t.Prim() + if prim != nil { + ret !prim.IsAny() && !prim.IsStr() + } + match { + | t.Sptr() != nil: + ret false + | t.Map() != nil: + ret false + | t.Slc() != nil: + ret false + | t.Trait() != nil: + ret false + | t.Fn() != nil: + ret false + | t.Arr() != nil: + mut arr := t.Arr() + ret shouldInitialized(arr.Elem) + | t.Struct() != nil: + ret false + |: + ret true + } } \ No newline at end of file diff --git a/src/julec/obj/determine.jule b/src/julec/obj/determine.jule index 5029ca990..b102bfbb1 100644 --- a/src/julec/obj/determine.jule +++ b/src/julec/obj/determine.jule @@ -6,54 +6,54 @@ use comptime for std::comptime use path for std::fs::path use build for std::jule::build use std::jule::sema::{ - Scope, - Fn, - Var, - FnIns, - StructIns, - StructSubIdentExprModel, - Data, - AnonFnExprModel, - TypeKind, - BuiltinErrorCallExprModel, + Scope, + Fn, + Var, + FnIns, + StructIns, + StructSubIdentExprModel, + Data, + AnonFnExprModel, + TypeKind, + BuiltinErrorCallExprModel, } use strings for std::strings // Reports whether exceptional scope s forwards exceptional. fn IsForwarded(&s: &Scope): bool { - last := s.Stmts[len(s.Stmts)-1] - match type last { - | &Data: - match type (&Data)(last).Model { - | &BuiltinErrorCallExprModel: - ret true - |: - ret false - } - |: - ret true - } + last := s.Stmts[len(s.Stmts)-1] + match type last { + | &Data: + match type (&Data)(last).Model { + | &BuiltinErrorCallExprModel: + ret true + |: + ret false + } + |: + ret true + } } // Reports whether expression comes from binded define. fn IsExprComesFromBind(&d: &Data): bool { - match type d.Model { - | &Var: - ret (&Var)(d.Model).Binded - | &StructSubIdentExprModel: - ret (&StructSubIdentExprModel)(d.Model).Owner.Decl.Binded - |: - ret false - } + match type d.Model { + | &Var: + ret (&Var)(d.Model).Binded + | &StructSubIdentExprModel: + ret (&StructSubIdentExprModel)(d.Model).Owner.Decl.Binded + |: + ret false + } } // Reports whether type is handled as type. fn IsAny(mut &t: &TypeKind): bool { - if t.TypeEnum() != nil { - ret true - } - prim := t.Prim() - ret prim != nil && prim.IsAny() + if t.TypeEnum() != nil { + ret true + } + prim := t.Prim() + ret prim != nil && prim.IsAny() } // Reports whether anonymous function is closure. @@ -61,28 +61,28 @@ fn IsClosure(&m: &AnonFnExprModel): bool { ret len(m.Captured) > 0 } // Reports whether the m is operator overloading method. fn IsOpMethod(&m: &Fn): bool { - if len(m.Generics) > 0 || len(m.Instances) == 0 { - ret false - } - mi := m.Instances[0] - const tableT = comptime::TypeOf(mi.Owner.Operators) - const tableV = comptime::ValueOf(mi.Owner.Operators) - const for _, field in tableT.Fields() { - if mi == tableV.Field(field.Name()).Unwrap() { - ret true - } - } - ret false + if len(m.Generics) > 0 || len(m.Instances) == 0 { + ret false + } + mi := m.Instances[0] + const tableT = comptime::TypeOf(mi.Owner.Operators) + const tableV = comptime::ValueOf(mi.Owner.Operators) + const for _, field in tableT.Fields() { + if mi == tableV.Field(field.Name()).Unwrap() { + ret true + } + } + ret false } // Reports the f function of owner is implements a trait's method. fn IsTraitMethod(mut &owner: &StructIns, &f: &FnIns): bool { - for (_, mut t) in owner.Decl.Implements { - if t.FindMethod(f.Decl.Ident) != nil { - ret true - } - } - ret false + for (_, mut t) in owner.Decl.Implements { + if t.FindMethod(f.Decl.Ident) != nil { + ret true + } + } + ret false } // Reports whether f is standard library package p. @@ -90,7 +90,7 @@ fn IsTraitMethod(mut &owner: &StructIns, &f: &FnIns): bool { // - IsStdPackage(f, "math") for std::math // - IsStdPackage(f, "math/big") for std::math::big fn IsStdPackage(&f: str, p: str): bool { - // Do not handle '/' separators of p, because it - // valid path separator for all supported platforms. - ret strings::HasPrefix(f, path::Join(build::PathStdlib, p)) + // Do not handle '/' separators of p, because it + // valid path separator for all supported platforms. + ret strings::HasPrefix(f, path::Join(build::PathStdlib, p)) } \ No newline at end of file diff --git a/src/julec/obj/ir.jule b/src/julec/obj/ir.jule index 7f2f6d8cc..4e016958a 100644 --- a/src/julec/obj/ir.jule +++ b/src/julec/obj/ir.jule @@ -9,156 +9,156 @@ use sema for std::jule::sema // Intermediate representation of code for compiler. struct IR { - // Directory of root package. - Root: str - Passes: []str - Main: &sema::Package - Used: []&sema::ImportInfo - Ordered: OrderedDefines + // Directory of root package. + Root: str + Passes: []str + Main: &sema::Package + Used: []&sema::ImportInfo + Ordered: OrderedDefines } impl IR { - // Returns compiler IR of source code. - // Returned IR is lexed, parsed, and analyzed. - // - // - Returns nil reference and nil logs if path has not any Jule file. - // - Returns nil reference and logs if exist any log. - // - Returns IR and nil logs if everything is fine. - static fn Build(path: str, flags: sema::SemaFlag): (&IR, []Log) { - mut importer := JuleImporter.New(buildCompileInfo()) - mut files, mut logs := importer.ImportPackage(path, true) - if len(logs) > 0 { - ret nil, logs - } - root := path - - if len(files) == 0 { - ret nil, nil - } - - mut pkg, logs := sema::AnalyzePackage(files, importer, flags) - if len(logs) > 0 { - ret nil, logs - } - - mut ir := &IR{ - Root: root, - Main: pkg, - Used: importer.AllPackages(), - } - ir.Passes = getAllUniquePasses(ir.Main, ir.Used) - - ret ir, nil - } + // Returns compiler IR of source code. + // Returned IR is lexed, parsed, and analyzed. + // + // - Returns nil reference and nil logs if path has not any Jule file. + // - Returns nil reference and logs if exist any log. + // - Returns IR and nil logs if everything is fine. + static fn Build(path: str, flags: sema::SemaFlag): (&IR, []Log) { + mut importer := JuleImporter.New(buildCompileInfo()) + mut files, mut logs := importer.ImportPackage(path, true) + if len(logs) > 0 { + ret nil, logs + } + root := path + + if len(files) == 0 { + ret nil, nil + } + + mut pkg, logs := sema::AnalyzePackage(files, importer, flags) + if len(logs) > 0 { + ret nil, logs + } + + mut ir := &IR{ + Root: root, + Main: pkg, + Used: importer.AllPackages(), + } + ir.Passes = getAllUniquePasses(ir.Main, ir.Used) + + ret ir, nil + } } impl IR { - fn appendStructs(self, mut &p: &sema::Package, mut &buffer: []&sema::Struct) { - for (_, mut f) in p.Files { - for (_, mut s) in f.Structs { - if !s.Binded { - buffer = append(buffer, s) - } - } - } - } - - // Returns all structures of main package and used pakcages. - // Ignores binded declarations. - fn GetAllStructures(mut self): []&sema::Struct { - let mut buffer: []&sema::Struct = nil - self.appendStructs(self.Main, buffer) - for (_, mut u) in self.Used { - if !u.Binded { - self.appendStructs(u.Package, buffer) - } - } - ret buffer - } - - fn appendGlobals(self, mut &p: &sema::Package, mut &buffer: []&sema::Var) { - for (_, mut f) in p.Files { - for (_, mut v) in f.Vars { - if v.Token != nil && !v.Binded && !v.Constant { - buffer = append(buffer, v) - } - } - } - } - - // Returns all globals of main package and used pakcages. - // Ignores binded declarations and constants. - fn GetAllGlobals(mut self): []&sema::Var { - let mut buffer: []&sema::Var = nil - self.appendGlobals(self.Main, buffer) - for (_, mut u) in self.Used { - if !u.Binded { - self.appendGlobals(u.Package, buffer) - } - } - ret buffer - } - - // Order defines at update ordered field of instance. - fn Order(mut self) { - self.Ordered.Structs = self.GetAllStructures() - self.Ordered.Globals = self.GetAllGlobals() - order(self.Ordered.Structs) - order(self.Ordered.Globals) - } + fn appendStructs(self, mut &p: &sema::Package, mut &buffer: []&sema::Struct) { + for (_, mut f) in p.Files { + for (_, mut s) in f.Structs { + if !s.Binded { + buffer = append(buffer, s) + } + } + } + } + + // Returns all structures of main package and used pakcages. + // Ignores binded declarations. + fn GetAllStructures(mut self): []&sema::Struct { + let mut buffer: []&sema::Struct = nil + self.appendStructs(self.Main, buffer) + for (_, mut u) in self.Used { + if !u.Binded { + self.appendStructs(u.Package, buffer) + } + } + ret buffer + } + + fn appendGlobals(self, mut &p: &sema::Package, mut &buffer: []&sema::Var) { + for (_, mut f) in p.Files { + for (_, mut v) in f.Vars { + if v.Token != nil && !v.Binded && !v.Constant { + buffer = append(buffer, v) + } + } + } + } + + // Returns all globals of main package and used pakcages. + // Ignores binded declarations and constants. + fn GetAllGlobals(mut self): []&sema::Var { + let mut buffer: []&sema::Var = nil + self.appendGlobals(self.Main, buffer) + for (_, mut u) in self.Used { + if !u.Binded { + self.appendGlobals(u.Package, buffer) + } + } + ret buffer + } + + // Order defines at update ordered field of instance. + fn Order(mut self) { + self.Ordered.Structs = self.GetAllStructures() + self.Ordered.Globals = self.GetAllGlobals() + order(self.Ordered.Structs) + order(self.Ordered.Globals) + } } fn pushPasses(mut &p: &sema::Package, mut &passes: []str) { - for (_, mut f) in p.Files { - push: - for _, pass in f.Passes { - if pass.Text == "" { - continue - } - for _, cpass in passes { - if cpass == pass.Text { - continue push - } - } - passes = append(passes, pass.Text) - } - } + for (_, mut f) in p.Files { + push: + for _, pass in f.Passes { + if pass.Text == "" { + continue + } + for _, cpass in passes { + if cpass == pass.Text { + continue push + } + } + passes = append(passes, pass.Text) + } + } } fn getAllUniquePasses(mut &pkg: &sema::Package, mut uses: []&sema::ImportInfo): []str { - let mut passes: []str = nil + let mut passes: []str = nil - pushPasses(pkg, passes) - for (_, mut u) in uses { - if !u.Binded { - pushPasses(u.Package, passes) - } - } + pushPasses(pkg, passes) + for (_, mut u) in uses { + if !u.Binded { + pushPasses(u.Package, passes) + } + } - ret passes + ret passes } fn buildCompileInfo(): CompileInfo { - mut info := CompileInfo{ - Prod: env::Production, - Test: env::Test, - } - - match env::Compiler { - | Compiler.Clang: - info.Compiler = Compiler.Clang - | Compiler.GCC: - info.Compiler = Compiler.GCC - } - - match env::CppStd { - | CppStd.Cpp14: - info.CppStd = CppStd.Cpp14 - | CppStd.Cpp17: - info.CppStd = CppStd.Cpp17 - | CppStd.Cpp20: - info.CppStd = CppStd.Cpp20 - } - - ret info + mut info := CompileInfo{ + Prod: env::Production, + Test: env::Test, + } + + match env::Compiler { + | Compiler.Clang: + info.Compiler = Compiler.Clang + | Compiler.GCC: + info.Compiler = Compiler.GCC + } + + match env::CppStd { + | CppStd.Cpp14: + info.CppStd = CppStd.Cpp14 + | CppStd.Cpp17: + info.CppStd = CppStd.Cpp17 + | CppStd.Cpp20: + info.CppStd = CppStd.Cpp20 + } + + ret info } \ No newline at end of file diff --git a/src/julec/obj/lookup.jule b/src/julec/obj/lookup.jule index adc4aa13a..9235c8ead 100644 --- a/src/julec/obj/lookup.jule +++ b/src/julec/obj/lookup.jule @@ -7,27 +7,27 @@ use std::jule::sema::{Trait, StructIns, TypeKind} // Returns directive if exist. fn FindDirective(mut &directives: []&ast::Directive, tag: str): &ast::Directive { - for (_, mut dr) in directives { - if dr.Tag.Kind == tag { - ret dr - } - } - ret nil + for (_, mut dr) in directives { + if dr.Tag.Kind == tag { + ret dr + } + } + ret nil } // Reports whether directive is exist. fn HasDirective(&directives: []&ast::Directive, tag: str): bool { - ret FindDirective(unsafe { *(&directives) }, tag) != nil + ret FindDirective(unsafe { *(&directives) }, tag) != nil } // Reports whether trait have method in this identifier. fn ContainsTraitMethod(mut &t: &Trait, &ident: str): bool { - for _, m in t.Methods { - if m.Ident == ident { - ret true - } - } - ret false + for _, m in t.Methods { + if m.Ident == ident { + ret true + } + } + ret false } // Data offset of empty trait. @@ -35,39 +35,39 @@ const emptyTraitOffset = 0 // Returns index of structu ins by trait implements. fn FindTraitTypeOffsetS(t: &Trait, mut s: &StructIns): int { - if len(t.Implemented) == 0 { - ret emptyTraitOffset - } - mut i := 0 - for _, si in t.Implemented { - if s.Decl == si { - for _, ins in si.Instances { - if ins == s { - ret i - } - i++ - } - break - } else { - i += len(si.Instances) - } - } - ret -1 + if len(t.Implemented) == 0 { + ret emptyTraitOffset + } + mut i := 0 + for _, si in t.Implemented { + if s.Decl == si { + for _, ins in si.Instances { + if ins == s { + ret i + } + i++ + } + break + } else { + i += len(si.Instances) + } + } + ret -1 } // Same as [FindTraitTypeOffsetS] but designed for TypeKind based lookup. // It checks structure instances even used with smart pointer. fn FindTraitTypeOffset(t: &Trait, mut k: &TypeKind): int { - if len(t.Implemented) == 0 { - ret emptyTraitOffset - } - let mut s: &StructIns = nil - if k.Sptr() != nil { - k = k.Sptr().Elem - } - s = k.Struct() - if s == nil { - ret -1 - } - ret FindTraitTypeOffsetS(t, s) + if len(t.Implemented) == 0 { + ret emptyTraitOffset + } + let mut s: &StructIns = nil + if k.Sptr() != nil { + k = k.Sptr().Elem + } + s = k.Struct() + if s == nil { + ret -1 + } + ret FindTraitTypeOffsetS(t, s) } \ No newline at end of file diff --git a/src/julec/obj/order.jule b/src/julec/obj/order.jule index f550c6d7b..ca14cb9ce 100644 --- a/src/julec/obj/order.jule +++ b/src/julec/obj/order.jule @@ -6,55 +6,55 @@ use std::jule::sema::{Struct, Var} // Collection for ordered defines. struct OrderedDefines { - Structs: []&Struct - Globals: []&Var + Structs: []&Struct + Globals: []&Var } // Reports whether type in correct order by dependencies. fn isOrdered[T](&t: &T, s: []&T): bool { lookup: - for _, d in t.Depends { - const match type T { - | Var: - if d.Constant { - // Skip constant variables for dependency analysis. - // It is not cost for runtime, so it is not an real-memory dependency. - continue - } - } - for _, o in s { - if d == o { - continue lookup - } - } - // Dependency is not ordered. - // All dependencies should be ordered first. - ret false - } - ret true + for _, d in t.Depends { + const match type T { + | Var: + if d.Constant { + // Skip constant variables for dependency analysis. + // It is not cost for runtime, so it is not an real-memory dependency. + continue + } + } + for _, o in s { + if d == o { + continue lookup + } + } + // Dependency is not ordered. + // All dependencies should be ordered first. + ret false + } + ret true } fn order[T](mut &s: []&T) { - mut i := 0 + mut i := 0 repeat: - mut j := i + mut j := i iter: - for j < len(s); j++ { - mut t := s[j] - for _, o in s[:i] { - if t == o { - // Do not iterate if already iterated and added to ordered list. - continue iter - } - } - if isOrdered(t, s[:i]) { - if i != j { - s[i], s[j] = s[j], s[i] - } - i++ - } - } - if i < len(s) { - goto repeat - } + for j < len(s); j++ { + mut t := s[j] + for _, o in s[:i] { + if t == o { + // Do not iterate if already iterated and added to ordered list. + continue iter + } + } + if isOrdered(t, s[:i]) { + if i != j { + s[i], s[j] = s[j], s[i] + } + i++ + } + } + if i < len(s) { + goto repeat + } } \ No newline at end of file diff --git a/src/julec/obj/walk.jule b/src/julec/obj/walk.jule index 671984f32..7e6e437dd 100644 --- a/src/julec/obj/walk.jule +++ b/src/julec/obj/walk.jule @@ -5,40 +5,40 @@ use std::jule::sema::{Package, SymbolTable, Trait, Fn} fn IterPackages(mut &ir: &IR, f: fn(mut &pkg: &Package)) { - for (_, mut used) in ir.Used { - if !used.Binded { - f(used.Package) - } - } - f(ir.Main) + for (_, mut used) in ir.Used { + if !used.Binded { + f(used.Package) + } + } + f(ir.Main) } fn IterFiles(mut &pkg: &Package, f: fn(mut &f: &SymbolTable)) { - for (_, mut file) in pkg.Files { - f(file) - } + for (_, mut file) in pkg.Files { + f(file) + } } fn iterTraitInheritMethods(mut &base: &Trait, mut &t: &Trait, f: fn(mut &m: &Fn)) { - iterTraitInheritMethods1(base, t, f) - for (_, mut m) in t.Methods { - if !ContainsTraitMethod(base, m.Ident) { // Do not iterate iterated method. - f(m) - } - } + iterTraitInheritMethods1(base, t, f) + for (_, mut m) in t.Methods { + if !ContainsTraitMethod(base, m.Ident) { // Do not iterate iterated method. + f(m) + } + } } fn iterTraitInheritMethods1(mut &base: &Trait, mut &t: &Trait, f: fn(mut &m: &Fn)) { - for (_, mut inh) in t.Inherits { - mut t2 := inh.Kind.Trait() - iterTraitInheritMethods(base, t2, f) - } + for (_, mut inh) in t.Inherits { + mut t2 := inh.Kind.Trait() + iterTraitInheritMethods(base, t2, f) + } } // Iterates methods of trait, including inherited methods. fn IterTraitMethods(mut &t: &Trait, f: fn(mut &m: &Fn)) { - for (_, mut m) in t.Methods { - f(m) - } - iterTraitInheritMethods1(t, t, f) + for (_, mut m) in t.Methods { + f(m) + } + iterTraitInheritMethods1(t, t, f) } \ No newline at end of file diff --git a/src/julec/opt/boundary.jule b/src/julec/opt/boundary.jule index 234b4792d..a25bdab43 100644 --- a/src/julec/opt/boundary.jule +++ b/src/julec/opt/boundary.jule @@ -9,75 +9,75 @@ use std::jule::sema::{Var, StructSubIdentExprModel, UnaryExprModel, ExprModel, T const invalidBoundary = uintptr(0x0) struct boundaryVar { - var: uintptr - maxSize: []ExprModel + var: uintptr + maxSize: []ExprModel } // Information wrapper for boundary analysis. struct boundary { - vars: []boundaryVar + vars: []boundaryVar } impl boundary { - // Appends variable with initial maximum size expression. - // If variable is already exist, updates maximum size information. - fn pushVar(mut self, var: uintptr, mut maxSize: ExprModel) { - if !Access || var == invalidBoundary { - // Ignore it, because this optimizations within scope of the --opt-access flag. - ret - } - if !isValidBoundaryInfo(maxSize) { - ret - } - for (_, mut v) in self.vars { - if v.var == var { - for i, max in v.maxSize { - if fitsSize(maxSize, max) { - // Maximum size is fits, so new size is larger than current size. - v.maxSize[i] = maxSize - ret - } - } - v.maxSize = append(v.maxSize, maxSize) - ret - } - } - // Not exist, append new one. - for (_, mut v) in self.vars { - if v.var == invalidBoundary { - // Empty place, use here instead of append. - v.var = var - v.maxSize = append(v.maxSize, maxSize) - ret - } - } - self.vars = append(self.vars, boundaryVar{var: var, maxSize: [maxSize]}) - } + // Appends variable with initial maximum size expression. + // If variable is already exist, updates maximum size information. + fn pushVar(mut self, var: uintptr, mut maxSize: ExprModel) { + if !Access || var == invalidBoundary { + // Ignore it, because this optimizations within scope of the --opt-access flag. + ret + } + if !isValidBoundaryInfo(maxSize) { + ret + } + for (_, mut v) in self.vars { + if v.var == var { + for i, max in v.maxSize { + if fitsSize(maxSize, max) { + // Maximum size is fits, so new size is larger than current size. + v.maxSize[i] = maxSize + ret + } + } + v.maxSize = append(v.maxSize, maxSize) + ret + } + } + // Not exist, append new one. + for (_, mut v) in self.vars { + if v.var == invalidBoundary { + // Empty place, use here instead of append. + v.var = var + v.maxSize = append(v.maxSize, maxSize) + ret + } + } + self.vars = append(self.vars, boundaryVar{var: var, maxSize: [maxSize]}) + } - fn removeVar(mut self, var: uintptr): bool { - if var != invalidBoundary { - for (_, mut v) in self.vars { - if v.var == var { - v.var = invalidBoundary - v.maxSize = v.maxSize[:0] - ret true - } - } - } - ret false - } + fn removeVar(mut self, var: uintptr): bool { + if var != invalidBoundary { + for (_, mut v) in self.vars { + if v.var == var { + v.var = invalidBoundary + v.maxSize = v.maxSize[:0] + ret true + } + } + } + ret false + } - // Reports whether maximum size of variable is fits with given expression. - fn fitsMaxSize(mut self, var: uintptr, expr: ExprModel): bool { - if var != invalidBoundary { - for _, v in self.vars { - if v.var == var { - ret fitsMaxSize(v.maxSize, expr) != -1 - } - } - } - ret false - } + // Reports whether maximum size of variable is fits with given expression. + fn fitsMaxSize(mut self, var: uintptr, expr: ExprModel): bool { + if var != invalidBoundary { + for _, v in self.vars { + if v.var == var { + ret fitsMaxSize(v.maxSize, expr) != -1 + } + } + } + ret false + } } // Reports whether model is valid maximum size information for boundary analysis. @@ -87,80 +87,80 @@ fn isValidBoundaryInfo(m: ExprModel): bool { ret fitsSize(m, m) } // In other words, reports whether: max >= expr // Returns index number of max size which is fit, otherwise -1. fn fitsMaxSize(max: []ExprModel, expr: ExprModel): int { - for i, m in max { - if fitsSize(m, expr) { - ret i - } - } - ret -1 + for i, m in max { + if fitsSize(m, expr) { + ret i + } + } + ret -1 } fn fitsSize(e1: ExprModel, e2: ExprModel): bool { - if typeData(e1) != typeData(e2) { - ret false - } - match type e1 { - | &Const: - exprConst := (&Const)(e2) - ret exprConst.AsF64() >= 0 && (&Const)(e1).GtEq(*exprConst) - | &Var: - ret e1 == e2 - | &StructSubIdentExprModel: - ssi1 := (&StructSubIdentExprModel)(e1) - ssi2 := (&StructSubIdentExprModel)(e2) - ret equalModels(ssi1.Expr.Model, ssi2.Expr.Model) && ssi1.Field == ssi2.Field - | &UnaryExprModel: - uem1 := (&UnaryExprModel)(e1) - uem2 := (&UnaryExprModel)(e2) - if uem1.Op.Id != TokenId.Star || uem1.Op.Id != uem2.Op.Id { - ret false - } - ret fitsSize(uem1.Expr.Model, uem2.Expr.Model) - |: - ret false - } + if typeData(e1) != typeData(e2) { + ret false + } + match type e1 { + | &Const: + exprConst := (&Const)(e2) + ret exprConst.AsF64() >= 0 && (&Const)(e1).GtEq(*exprConst) + | &Var: + ret e1 == e2 + | &StructSubIdentExprModel: + ssi1 := (&StructSubIdentExprModel)(e1) + ssi2 := (&StructSubIdentExprModel)(e2) + ret equalModels(ssi1.Expr.Model, ssi2.Expr.Model) && ssi1.Field == ssi2.Field + | &UnaryExprModel: + uem1 := (&UnaryExprModel)(e1) + uem2 := (&UnaryExprModel)(e2) + if uem1.Op.Id != TokenId.Star || uem1.Op.Id != uem2.Op.Id { + ret false + } + ret fitsSize(uem1.Expr.Model, uem2.Expr.Model) + |: + ret false + } } fn possibleBoundaryRemove(mut &b: &boundary, model: ExprModel) { - // Clear if size data mutating. - for (_, mut v) in b.vars { - for i, max in v.maxSize { - if equalModels(max, model) { - v.maxSize = append(v.maxSize[:i], v.maxSize[i+1:]...) - break - } - } - } + // Clear if size data mutating. + for (_, mut v) in b.vars { + for i, max in v.maxSize { + if equalModels(max, model) { + v.maxSize = append(v.maxSize[:i], v.maxSize[i+1:]...) + break + } + } + } } fn isBoundaryRiskyType(mut t: &TypeKind): bool { - // Reports true for not-arrays because array's size cannot be changed. - ret t.Arr() == nil + // Reports true for not-arrays because array's size cannot be changed. + ret t.Arr() == nil } fn isBoundaryValidType(mut t: &TypeKind): bool { ret t.Slc() != nil || t.Arr() != nil } fn getBoundaryVar(m: ExprModel): uintptr { - if !Access { - ret invalidBoundary - } - match type m { - | &Var: - v := (&Var)(m) - if !v.Reference { - // Variable is not reference, return address of it. - ret uintptr((&Var)(m)) - } - // Variable is reference, it should be initialized at source code. - // Investigate the initial expression for variable address. - ret getBoundaryVar(v.Value.Data.Model) - | &StructSubIdentExprModel: - ret uintptr((&StructSubIdentExprModel)(m).Field) - | &UnaryExprModel: - uem := (&UnaryExprModel)(m) - if uem.Op.Id == TokenId.Star { // Dereferencing. - ret getBoundaryVar(uem.Expr.Model) - } - } - ret invalidBoundary + if !Access { + ret invalidBoundary + } + match type m { + | &Var: + v := (&Var)(m) + if !v.Reference { + // Variable is not reference, return address of it. + ret uintptr((&Var)(m)) + } + // Variable is reference, it should be initialized at source code. + // Investigate the initial expression for variable address. + ret getBoundaryVar(v.Value.Data.Model) + | &StructSubIdentExprModel: + ret uintptr((&StructSubIdentExprModel)(m).Field) + | &UnaryExprModel: + uem := (&UnaryExprModel)(m) + if uem.Op.Id == TokenId.Star { // Dereferencing. + ret getBoundaryVar(uem.Expr.Model) + } + } + ret invalidBoundary } \ No newline at end of file diff --git a/src/julec/opt/data.jule b/src/julec/opt/data.jule index 8d825f647..c8ad7466e 100644 --- a/src/julec/opt/data.jule +++ b/src/julec/opt/data.jule @@ -8,33 +8,33 @@ static mut emptyData = new(data) // Immutable copy for data. struct dataCheckpoint { - boundary: boundary - nils: nils - dynamic: dynamic + boundary: boundary + nils: nils + dynamic: dynamic } // All-in-one all analysis information structures. struct data { - boundary: &boundary - nils: &nils - dynamic: &dynamic + boundary: &boundary + nils: &nils + dynamic: &dynamic } impl data { - fn getCheckpoint(mut self): dataCheckpoint { - mut c := dataCheckpoint{} - c.boundary.vars = append(make([]boundaryVar, 0), self.boundary.vars...) - for i in c.boundary.vars { - c.boundary.vars[i].maxSize = append(make([]ExprModel, 0), c.boundary.vars[i].maxSize...) - } - c.nils.vars = append(make([]nilVar, 0), self.nils.vars...) - c.dynamic.vars = append(make([]dynamicVar, 0), self.dynamic.vars...) - ret c - } + fn getCheckpoint(mut self): dataCheckpoint { + mut c := dataCheckpoint{} + c.boundary.vars = append(make([]boundaryVar, 0), self.boundary.vars...) + for i in c.boundary.vars { + c.boundary.vars[i].maxSize = append(make([]ExprModel, 0), c.boundary.vars[i].maxSize...) + } + c.nils.vars = append(make([]nilVar, 0), self.nils.vars...) + c.dynamic.vars = append(make([]dynamicVar, 0), self.dynamic.vars...) + ret c + } - fn loadCheckpoint(mut self, mut &c: dataCheckpoint) { - *self.boundary = c.boundary - *self.nils = c.nils - *self.dynamic = c.dynamic - } + fn loadCheckpoint(mut self, mut &c: dataCheckpoint) { + *self.boundary = c.boundary + *self.nils = c.nils + *self.dynamic = c.dynamic + } } \ No newline at end of file diff --git a/src/julec/opt/deadcode/define.jule b/src/julec/opt/deadcode/define.jule index 04c8d3605..41e270fbb 100644 --- a/src/julec/opt/deadcode/define.jule +++ b/src/julec/opt/deadcode/define.jule @@ -8,301 +8,301 @@ use comptime for std::comptime use build for std::jule::build::{Directive} use ast for std::jule::ast use std::jule::sema::{ - Package, - SymbolTable, - ReferenceStack, - Var, - Fn, - FnIns, - Struct, - StructIns, - Trait, + Package, + SymbolTable, + ReferenceStack, + Var, + Fn, + FnIns, + Struct, + StructIns, + Trait, } struct liveTable { - vars: []&Var - fns: []&FnIns - structs: []&StructIns - traits: []&Trait + vars: []&Var + fns: []&FnIns + structs: []&StructIns + traits: []&Trait } struct ObjectDeadCode { - live: liveTable - ir: &IR + live: liveTable + ir: &IR } impl ObjectDeadCode { - static fn new(mut &ir: &IR): &ObjectDeadCode { - ret &ObjectDeadCode{ - ir: ir, - } - } + static fn new(mut &ir: &IR): &ObjectDeadCode { + ret &ObjectDeadCode{ + ir: ir, + } + } - fn isLive[T](mut &self, &t: T): bool { - let mut live: []T = nil - const match type T { - | &FnIns: - live = self.live.fns - | &Var: - live = self.live.vars - | &StructIns: - live = self.live.structs - | &Trait: - live = self.live.traits - } - for i in live { - if live[i] == t { - ret true - } - } - ret false - } + fn isLive[T](mut &self, &t: T): bool { + let mut live: []T = nil + const match type T { + | &FnIns: + live = self.live.fns + | &Var: + live = self.live.vars + | &StructIns: + live = self.live.structs + | &Trait: + live = self.live.traits + } + for i in live { + if live[i] == t { + ret true + } + } + ret false + } - fn pushLive[T](mut &self, mut t: T) { - const match type T { - | &Var: - self.live.vars = append(self.live.vars, t) - | &FnIns: - self.live.fns = append(self.live.fns, t) - | &StructIns: - self.live.structs = append(self.live.structs, t) - | &Trait: - self.live.traits = append(self.live.traits, t) - } - } + fn pushLive[T](mut &self, mut t: T) { + const match type T { + | &Var: + self.live.vars = append(self.live.vars, t) + | &FnIns: + self.live.fns = append(self.live.fns, t) + | &StructIns: + self.live.structs = append(self.live.structs, t) + | &Trait: + self.live.traits = append(self.live.traits, t) + } + } - fn setReferencesAsLive(mut &self, mut &rs: &ReferenceStack) { - if rs == nil { - ret - } - mut i := 0 - for i < rs.Len(); i++ { - mut ref := rs.At(i) - match type ref { - | &Trait: - mut t := (&Trait)(ref) - if self.isLive[&Trait](t) { - continue - } - self.pushLive[&Trait](t) - for (_, mut ins) in t.Methods { - for (_, mut mins) in ins.Instances { - if self.isLive[&FnIns](mins) { - continue - } - self.pushLive[&FnIns](mins) - self.setReferencesAsLive(mins.Refers) - } - } - | &FnIns: - mut f := (&FnIns)(ref) - if self.isLive[&FnIns](f) { - break - } - if f.Owner != nil && !f.Decl.Statically { - if !self.isLive[&StructIns](f.Owner) { - self.pushLive[&StructIns](f.Owner) - self.setReferencesAsLive(f.Owner.Refers) - } - } - self.pushLive[&FnIns](f) - self.setReferencesAsLive(f.Refers) - | &Var: - mut v := (&Var)(ref) - if self.isLive[&Var](v) { - break - } - self.pushLive[&Var](v) - self.setReferencesAsLive(v.Refers) - | &StructIns: - mut s := (&StructIns)(ref) - if self.isLive[&StructIns](s) { - break - } - self.pushLive[&StructIns](s) - self.setReferencesAsLive(s.Refers) - for (_, mut m) in s.Methods { - for (_, mut ins) in m.Instances { - if self.isLive[&FnIns](ins) { - continue - } + fn setReferencesAsLive(mut &self, mut &rs: &ReferenceStack) { + if rs == nil { + ret + } + mut i := 0 + for i < rs.Len(); i++ { + mut ref := rs.At(i) + match type ref { + | &Trait: + mut t := (&Trait)(ref) + if self.isLive[&Trait](t) { + continue + } + self.pushLive[&Trait](t) + for (_, mut ins) in t.Methods { + for (_, mut mins) in ins.Instances { + if self.isLive[&FnIns](mins) { + continue + } + self.pushLive[&FnIns](mins) + self.setReferencesAsLive(mins.Refers) + } + } + | &FnIns: + mut f := (&FnIns)(ref) + if self.isLive[&FnIns](f) { + break + } + if f.Owner != nil && !f.Decl.Statically { + if !self.isLive[&StructIns](f.Owner) { + self.pushLive[&StructIns](f.Owner) + self.setReferencesAsLive(f.Owner.Refers) + } + } + self.pushLive[&FnIns](f) + self.setReferencesAsLive(f.Refers) + | &Var: + mut v := (&Var)(ref) + if self.isLive[&Var](v) { + break + } + self.pushLive[&Var](v) + self.setReferencesAsLive(v.Refers) + | &StructIns: + mut s := (&StructIns)(ref) + if self.isLive[&StructIns](s) { + break + } + self.pushLive[&StructIns](s) + self.setReferencesAsLive(s.Refers) + for (_, mut m) in s.Methods { + for (_, mut ins) in m.Instances { + if self.isLive[&FnIns](ins) { + continue + } - // Set trait implemented methods as alive. - // Push as live the method if implements a trait's method. - // Other methods will be marked as live by referenced defines, - // no need for special tracking algorithm to caught. - if obj::IsTraitMethod(s, ins) { - self.pushLive[&FnIns](ins) - self.setReferencesAsLive(ins.Refers) - } + // Set trait implemented methods as alive. + // Push as live the method if implements a trait's method. + // Other methods will be marked as live by referenced defines, + // no need for special tracking algorithm to caught. + if obj::IsTraitMethod(s, ins) { + self.pushLive[&FnIns](ins) + self.setReferencesAsLive(ins.Refers) + } - // Set operator overloading methods as alive. - // Just cannot track whether operator overloading is used yet. - // So, removing these methods may cause compilation problems. - const vs = comptime::ValueOf(*s) - const om = vs.Field("Operators") - const for _, field in om.Type().Fields() { - if ins == om.Field(field.Name()).Unwrap() { - self.pushLive[&FnIns](ins) - self.setReferencesAsLive(ins.Refers) - } - } - } - } - } - } - } + // Set operator overloading methods as alive. + // Just cannot track whether operator overloading is used yet. + // So, removing these methods may cause compilation problems. + const vs = comptime::ValueOf(*s) + const om = vs.Field("Operators") + const for _, field in om.Type().Fields() { + if ins == om.Field(field.Name()).Unwrap() { + self.pushLive[&FnIns](ins) + self.setReferencesAsLive(ins.Refers) + } + } + } + } + } + } + } - fn inits(mut &self, mut &pkg: &Package) { - for (_, mut file) in pkg.Files { - for (_, mut f) in file.Funcs { - if f.Ident == build::InitFn { - mut ins := f.Instances[0] - self.live.fns = append(self.live.fns, ins) - self.setReferencesAsLive(ins.Refers) - } - } - } - } + fn inits(mut &self, mut &pkg: &Package) { + for (_, mut file) in pkg.Files { + for (_, mut f) in file.Funcs { + if f.Ident == build::InitFn { + mut ins := f.Instances[0] + self.live.fns = append(self.live.fns, ins) + self.setReferencesAsLive(ins.Refers) + } + } + } + } - fn collectLivePackage(mut &self, mut &pkg: &Package) { - // Collect live references based on initializer functions. - self.inits(pkg) + fn collectLivePackage(mut &self, mut &pkg: &Package) { + // Collect live references based on initializer functions. + self.inits(pkg) - // Collect test functions if test compilation is enabled. - if env::Test { - for (_, mut file) in pkg.Files { - for (_, mut f) in file.Funcs { - if obj::HasDirective(f.Directives, Directive.Test) { - mut ins := f.Instances[0] - self.live.fns = append(self.live.fns, ins) - self.setReferencesAsLive(ins.Refers) - } - } - } - } - } + // Collect test functions if test compilation is enabled. + if env::Test { + for (_, mut file) in pkg.Files { + for (_, mut f) in file.Funcs { + if obj::HasDirective(f.Directives, Directive.Test) { + mut ins := f.Instances[0] + self.live.fns = append(self.live.fns, ins) + self.setReferencesAsLive(ins.Refers) + } + } + } + } + } - fn collectLive(mut &self) { - for (_, mut used) in self.ir.Used { - if !used.Binded { - self.collectLivePackage(used.Package) - } - } - self.collectLivePackage(self.ir.Main) + fn collectLive(mut &self) { + for (_, mut used) in self.ir.Used { + if !used.Binded { + self.collectLivePackage(used.Package) + } + } + self.collectLivePackage(self.ir.Main) - // Push live references based on entry point. - mut main := self.ir.Main.FindFn(build::EntryPoint, false) - mut ins := main.Instances[0] - self.live.fns = append(self.live.fns, ins) - self.setReferencesAsLive(ins.Refers) - } + // Push live references based on entry point. + mut main := self.ir.Main.FindFn(build::EntryPoint, false) + mut ins := main.Instances[0] + self.live.fns = append(self.live.fns, ins) + self.setReferencesAsLive(ins.Refers) + } - fn removeDeadGlobals(mut &self, mut &vars: []&Var) { - mut i := 0 - for i < len(vars) { - v := vars[i] - if self.isLive[&Var](v) { - i++ - continue - } - vars = append(vars[:i], vars[i+1:]...) - } - } + fn removeDeadGlobals(mut &self, mut &vars: []&Var) { + mut i := 0 + for i < len(vars) { + v := vars[i] + if self.isLive[&Var](v) { + i++ + continue + } + vars = append(vars[:i], vars[i+1:]...) + } + } - fn removeDeadFns(mut &self, mut &funcs: []&Fn) { - mut i := 0 - for i < len(funcs) { - mut f := funcs[i] - mut j := 0 - for j < len(f.Instances) { - ins := f.Instances[j] - if self.isLive[&FnIns](ins) { - j++ - continue - } - f.Instances = append(f.Instances[:j], f.Instances[j+1:]...) - } - if len(f.Instances) == 0 { - funcs = append(funcs[:i], funcs[i+1:]...) - continue - } - i++ - } - } + fn removeDeadFns(mut &self, mut &funcs: []&Fn) { + mut i := 0 + for i < len(funcs) { + mut f := funcs[i] + mut j := 0 + for j < len(f.Instances) { + ins := f.Instances[j] + if self.isLive[&FnIns](ins) { + j++ + continue + } + f.Instances = append(f.Instances[:j], f.Instances[j+1:]...) + } + if len(f.Instances) == 0 { + funcs = append(funcs[:i], funcs[i+1:]...) + continue + } + i++ + } + } - fn removeDeadStructs(mut &self, mut &structs: []&Struct) { - mut i := 0 - for i < len(structs) { - mut s := structs[i] - mut j := 0 - for j < len(s.Instances) { - mut ins := s.Instances[j] - self.removeDeadFns(ins.Methods) - if len(ins.Methods) != 0 || self.isLive[&StructIns](ins) { - j++ - continue - } - s.Instances = append(s.Instances[:j], s.Instances[j+1:]...) - } - if len(s.Instances) == 0 { - structs = append(structs[:i], structs[i+1:]...) - continue - } - i++ - } - } + fn removeDeadStructs(mut &self, mut &structs: []&Struct) { + mut i := 0 + for i < len(structs) { + mut s := structs[i] + mut j := 0 + for j < len(s.Instances) { + mut ins := s.Instances[j] + self.removeDeadFns(ins.Methods) + if len(ins.Methods) != 0 || self.isLive[&StructIns](ins) { + j++ + continue + } + s.Instances = append(s.Instances[:j], s.Instances[j+1:]...) + } + if len(s.Instances) == 0 { + structs = append(structs[:i], structs[i+1:]...) + continue + } + i++ + } + } - fn removeDeadTraits(mut &self, mut &traits: []&Trait) { - mut i := 0 - for i < len(traits) { - mut t := traits[i] - if !self.isLive[&Trait](t) { - traits = append(traits[:i], traits[i+1:]...) - continue - } - mut j := 0 - for j < len(t.Implemented) { - s := t.Implemented[j] - if len(s.Instances) > 0 { - j++ - continue - } - t.Implemented = append(t.Implemented[:j], t.Implemented[j+1:]...) - } - i++ - } - } + fn removeDeadTraits(mut &self, mut &traits: []&Trait) { + mut i := 0 + for i < len(traits) { + mut t := traits[i] + if !self.isLive[&Trait](t) { + traits = append(traits[:i], traits[i+1:]...) + continue + } + mut j := 0 + for j < len(t.Implemented) { + s := t.Implemented[j] + if len(s.Instances) > 0 { + j++ + continue + } + t.Implemented = append(t.Implemented[:j], t.Implemented[j+1:]...) + } + i++ + } + } - fn removeDeadsFile(mut &self, mut &file: &SymbolTable) { - self.removeDeadFns(file.Funcs) - self.removeDeadStructs(file.Structs) - self.removeDeadTraits(file.Traits) - self.removeDeadGlobals(file.Vars) - } + fn removeDeadsFile(mut &self, mut &file: &SymbolTable) { + self.removeDeadFns(file.Funcs) + self.removeDeadStructs(file.Structs) + self.removeDeadTraits(file.Traits) + self.removeDeadGlobals(file.Vars) + } - fn removeDeadsPackage(mut &self, mut &pkg: &Package) { - for (_, mut file) in pkg.Files { - self.removeDeadsFile(file) - } - } + fn removeDeadsPackage(mut &self, mut &pkg: &Package) { + for (_, mut file) in pkg.Files { + self.removeDeadsFile(file) + } + } - fn removeDeads(mut &self) { - for (_, mut used) in self.ir.Used { - if !used.Binded { - self.removeDeadsPackage(used.Package) - } - } - self.removeDeadsPackage(self.ir.Main) - } + fn removeDeads(mut &self) { + for (_, mut used) in self.ir.Used { + if !used.Binded { + self.removeDeadsPackage(used.Package) + } + } + self.removeDeadsPackage(self.ir.Main) + } - fn elimanate(mut &self) { - self.collectLive() - self.removeDeads() - } + fn elimanate(mut &self) { + self.collectLive() + self.removeDeads() + } } fn EliminateDefines(mut &ir: &IR) { - mut ocd := ObjectDeadCode.new(ir) - ocd.elimanate() + mut ocd := ObjectDeadCode.new(ir) + ocd.elimanate() } \ No newline at end of file diff --git a/src/julec/opt/deadcode/expr.jule b/src/julec/opt/deadcode/expr.jule index d76905b7a..f57bee363 100644 --- a/src/julec/opt/deadcode/expr.jule +++ b/src/julec/opt/deadcode/expr.jule @@ -3,279 +3,279 @@ // license that can be found in the LICENSE file. use std::jule::sema::{ - Data, - ExprModel, - BinaryExprModel, - OperandExprModel, - UnaryExprModel, - StructLitExprModel, - AllocStructLitExprModel, - CastingExprModel, - FnCallExprModel, - SliceExprModel, - ArrayExprModel, - IndexingExprModel, - AnonFnExprModel, - MapExprModel, - SlicingExprModel, - TraitSubIdentExprModel, - StructSubIdentExprModel, - TupleExprModel, - BuiltinNewCallExprModel, - BuiltinOutCallExprModel, - BuiltinOutlnCallExprModel, - BuiltinPanicCallExprModel, - BuiltinAssertCallExprModel, - BuiltinErrorCallExprModel, - BuiltinMakeCallExprModel, - BuiltinAppendCallExprModel, - BuiltinLenCallExprModel, - BuiltinCapCallExprModel, - BuiltinDeleteCallExprModel, - SizeofExprModel, - AlignofExprModel, - IntegratedToStrExprModel, - FreeExprModel, - BackendEmitExprModel, + Data, + ExprModel, + BinaryExprModel, + OperandExprModel, + UnaryExprModel, + StructLitExprModel, + AllocStructLitExprModel, + CastingExprModel, + FnCallExprModel, + SliceExprModel, + ArrayExprModel, + IndexingExprModel, + AnonFnExprModel, + MapExprModel, + SlicingExprModel, + TraitSubIdentExprModel, + StructSubIdentExprModel, + TupleExprModel, + BuiltinNewCallExprModel, + BuiltinOutCallExprModel, + BuiltinOutlnCallExprModel, + BuiltinPanicCallExprModel, + BuiltinAssertCallExprModel, + BuiltinErrorCallExprModel, + BuiltinMakeCallExprModel, + BuiltinAppendCallExprModel, + BuiltinLenCallExprModel, + BuiltinCapCallExprModel, + BuiltinDeleteCallExprModel, + SizeofExprModel, + AlignofExprModel, + IntegratedToStrExprModel, + FreeExprModel, + BackendEmitExprModel, } // Dead code eliminate optimizer for expressions. struct exprDeadCode { - mut s: &scopeDeadCode + mut s: &scopeDeadCode } impl exprDeadCode { - static fn new(mut &s: &scopeDeadCode): exprDeadCode { - ret exprDeadCode{ - s: s, - } - } - - fn binary(self, mut m: &BinaryExprModel) { - self.optimize(m.Left.Model) - self.optimize(m.Right.Model) - } - - fn unary(self, mut m: &UnaryExprModel) { - self.optimize(m.Expr.Model) - } - - fn structureLit(self, mut m: &StructLitExprModel) { - for (_, mut arg) in m.Args { - self.optimize(arg.Expr.Model) - } - } - - fn allocStructure(self, mut m: &AllocStructLitExprModel) { - self.structureLit(m.Lit) - } - - fn casting(self, mut m: &CastingExprModel) { - self.optimize(m.Expr.Model) - } - - fn args(self, mut &args: []ExprModel) { - for (_, mut arg) in args { - self.optimize(arg) - } - } - - fn funcCall(self, mut m: &FnCallExprModel) { - self.optimize(m.Expr) - self.args(m.Args) - if m.Except != nil { - self.s.optimizeBodyChildExceptional(m.Except) - } - } - - fn slice(self, mut m: &SliceExprModel) { - self.args(m.Elems) - } - - fn array(self, mut m: &ArrayExprModel) { - if len(m.Elems) == 2 && m.Elems[1] == nil { - self.optimize(unsafe { *(&m.Elems[0]) }) - } - self.args(m.Elems) - } - - fn indexing(self, mut m: &IndexingExprModel) { - self.optimize(m.Expr.Model) - self.optimize(m.Index.Model) - } - - fn anonFunc(self, mut m: &AnonFnExprModel) { - eliminateDeadCodeOfScope(m.Func.Scope) - } - - fn mapExpr(self, mut m: &MapExprModel) { - for (_, mut pair) in m.Entries { - self.optimize(pair.Key) - self.optimize(pair.Val) - } - } - - fn slicing(self, mut m: &SlicingExprModel) { - self.optimize(m.Expr) - self.optimize(m.Left) - if m.Right != nil { - self.optimize(m.Right) - } - } - - fn traitSub(self, mut m: &TraitSubIdentExprModel) { - self.optimize(m.Expr) - } - - fn structureSub(self, mut m: &StructSubIdentExprModel) { - self.optimize(m.Expr.Model) - } - - fn tuple(self, mut m: &TupleExprModel) { - for (_, mut d) in m.Datas { - self.optimize(d.Model) - } - } - - fn newCall(self, mut m: &BuiltinNewCallExprModel) { - if m.Init != nil { - self.optimize(m.Init) - } - } - - fn outCall(self, mut m: &BuiltinOutCallExprModel) { - self.optimize(m.Expr) - } - - fn outlnCall(self, mut m: &BuiltinOutlnCallExprModel) { - self.optimize(m.Expr) - } - - fn panicCall(self, mut m: &BuiltinPanicCallExprModel) { - self.optimize(m.Expr) - } - - fn assertCall(self, mut m: &BuiltinAssertCallExprModel) { - self.optimize(m.Expr) - } - - fn errorCall(self, mut m: &BuiltinErrorCallExprModel) { - self.optimize(m.Err.Model) - } - - fn makeCall(self, mut m: &BuiltinMakeCallExprModel) { - if m.Len != nil { - self.optimize(m.Len) - } - if m.Cap != nil { - self.optimize(m.Cap) - } - } - - fn appendCall(self, mut m: &BuiltinAppendCallExprModel) { - self.optimize(m.Dest) - self.optimize(m.Elements) - } - - fn lenCall(self, mut m: &BuiltinLenCallExprModel) { - self.optimize(m.Expr.Model) - } - - fn capCall(self, mut m: &BuiltinCapCallExprModel) { - self.optimize(m.Expr.Model) - } - - fn deleteCall(self, mut m: &BuiltinDeleteCallExprModel) { - self.optimize(m.Dest.Model) - if m.Key != nil { - self.optimize(m.Key.Model) - } - } - - fn sizeof(self, mut m: &SizeofExprModel) { - self.optimize(m.Expr) - } - - fn alignof(self, mut m: &AlignofExprModel) { - self.optimize(m.Expr) - } - - fn integratedToStr(self, mut m: &IntegratedToStrExprModel) { - self.optimize(m.Expr) - } - - fn free(self, mut m: &FreeExprModel) { - self.optimize(m.Expr) - } - - fn backendEmit(self, mut m: &BackendEmitExprModel) { - self.args(m.Exprs) - } - - fn optimize(self, mut &model: ExprModel) { - match type model { - | &BinaryExprModel: - self.binary((&BinaryExprModel)(model)) - | &UnaryExprModel: - self.unary((&UnaryExprModel)(model)) - | &StructLitExprModel: - self.structureLit((&StructLitExprModel)(model)) - | &AllocStructLitExprModel: - self.allocStructure((&AllocStructLitExprModel)(model)) - | &CastingExprModel: - self.casting((&CastingExprModel)(model)) - | &FnCallExprModel: - self.funcCall((&FnCallExprModel)(model)) - | &SliceExprModel: - self.slice((&SliceExprModel)(model)) - | &ArrayExprModel: - self.array((&ArrayExprModel)(model)) - | &IndexingExprModel: - self.indexing((&IndexingExprModel)(model)) - | &AnonFnExprModel: - self.anonFunc((&AnonFnExprModel)(model)) - | &MapExprModel: - self.mapExpr((&MapExprModel)(model)) - | &SlicingExprModel: - self.slicing((&SlicingExprModel)(model)) - | &TraitSubIdentExprModel: - self.traitSub((&TraitSubIdentExprModel)(model)) - | &StructSubIdentExprModel: - self.structureSub((&StructSubIdentExprModel)(model)) - | &TupleExprModel: - self.tuple((&TupleExprModel)(model)) - | &BuiltinOutCallExprModel: - self.outCall((&BuiltinOutCallExprModel)(model)) - | &BuiltinOutlnCallExprModel: - self.outlnCall((&BuiltinOutlnCallExprModel)(model)) - | &BuiltinNewCallExprModel: - self.newCall((&BuiltinNewCallExprModel)(model)) - | &BuiltinPanicCallExprModel: - self.panicCall((&BuiltinPanicCallExprModel)(model)) - | &BuiltinAssertCallExprModel: - self.assertCall((&BuiltinAssertCallExprModel)(model)) - | &BuiltinErrorCallExprModel: - self.errorCall((&BuiltinErrorCallExprModel)(model)) - | &BuiltinMakeCallExprModel: - self.makeCall((&BuiltinMakeCallExprModel)(model)) - | &BuiltinAppendCallExprModel: - self.appendCall((&BuiltinAppendCallExprModel)(model)) - | &BuiltinLenCallExprModel: - self.lenCall((&BuiltinLenCallExprModel)(model)) - | &BuiltinCapCallExprModel: - self.capCall((&BuiltinCapCallExprModel)(model)) - | &BuiltinDeleteCallExprModel: - self.deleteCall((&BuiltinDeleteCallExprModel)(model)) - | &SizeofExprModel: - self.sizeof((&SizeofExprModel)(model)) - | &AlignofExprModel: - self.alignof((&AlignofExprModel)(model)) - | &IntegratedToStrExprModel: - self.integratedToStr((&IntegratedToStrExprModel)(model)) - | &FreeExprModel: - self.free((&FreeExprModel)(model)) - | &BackendEmitExprModel: - self.backendEmit((&BackendEmitExprModel)(model)) - } - } + static fn new(mut &s: &scopeDeadCode): exprDeadCode { + ret exprDeadCode{ + s: s, + } + } + + fn binary(self, mut m: &BinaryExprModel) { + self.optimize(m.Left.Model) + self.optimize(m.Right.Model) + } + + fn unary(self, mut m: &UnaryExprModel) { + self.optimize(m.Expr.Model) + } + + fn structureLit(self, mut m: &StructLitExprModel) { + for (_, mut arg) in m.Args { + self.optimize(arg.Expr.Model) + } + } + + fn allocStructure(self, mut m: &AllocStructLitExprModel) { + self.structureLit(m.Lit) + } + + fn casting(self, mut m: &CastingExprModel) { + self.optimize(m.Expr.Model) + } + + fn args(self, mut &args: []ExprModel) { + for (_, mut arg) in args { + self.optimize(arg) + } + } + + fn funcCall(self, mut m: &FnCallExprModel) { + self.optimize(m.Expr) + self.args(m.Args) + if m.Except != nil { + self.s.optimizeBodyChildExceptional(m.Except) + } + } + + fn slice(self, mut m: &SliceExprModel) { + self.args(m.Elems) + } + + fn array(self, mut m: &ArrayExprModel) { + if len(m.Elems) == 2 && m.Elems[1] == nil { + self.optimize(unsafe { *(&m.Elems[0]) }) + } + self.args(m.Elems) + } + + fn indexing(self, mut m: &IndexingExprModel) { + self.optimize(m.Expr.Model) + self.optimize(m.Index.Model) + } + + fn anonFunc(self, mut m: &AnonFnExprModel) { + eliminateDeadCodeOfScope(m.Func.Scope) + } + + fn mapExpr(self, mut m: &MapExprModel) { + for (_, mut pair) in m.Entries { + self.optimize(pair.Key) + self.optimize(pair.Val) + } + } + + fn slicing(self, mut m: &SlicingExprModel) { + self.optimize(m.Expr) + self.optimize(m.Left) + if m.Right != nil { + self.optimize(m.Right) + } + } + + fn traitSub(self, mut m: &TraitSubIdentExprModel) { + self.optimize(m.Expr) + } + + fn structureSub(self, mut m: &StructSubIdentExprModel) { + self.optimize(m.Expr.Model) + } + + fn tuple(self, mut m: &TupleExprModel) { + for (_, mut d) in m.Datas { + self.optimize(d.Model) + } + } + + fn newCall(self, mut m: &BuiltinNewCallExprModel) { + if m.Init != nil { + self.optimize(m.Init) + } + } + + fn outCall(self, mut m: &BuiltinOutCallExprModel) { + self.optimize(m.Expr) + } + + fn outlnCall(self, mut m: &BuiltinOutlnCallExprModel) { + self.optimize(m.Expr) + } + + fn panicCall(self, mut m: &BuiltinPanicCallExprModel) { + self.optimize(m.Expr) + } + + fn assertCall(self, mut m: &BuiltinAssertCallExprModel) { + self.optimize(m.Expr) + } + + fn errorCall(self, mut m: &BuiltinErrorCallExprModel) { + self.optimize(m.Err.Model) + } + + fn makeCall(self, mut m: &BuiltinMakeCallExprModel) { + if m.Len != nil { + self.optimize(m.Len) + } + if m.Cap != nil { + self.optimize(m.Cap) + } + } + + fn appendCall(self, mut m: &BuiltinAppendCallExprModel) { + self.optimize(m.Dest) + self.optimize(m.Elements) + } + + fn lenCall(self, mut m: &BuiltinLenCallExprModel) { + self.optimize(m.Expr.Model) + } + + fn capCall(self, mut m: &BuiltinCapCallExprModel) { + self.optimize(m.Expr.Model) + } + + fn deleteCall(self, mut m: &BuiltinDeleteCallExprModel) { + self.optimize(m.Dest.Model) + if m.Key != nil { + self.optimize(m.Key.Model) + } + } + + fn sizeof(self, mut m: &SizeofExprModel) { + self.optimize(m.Expr) + } + + fn alignof(self, mut m: &AlignofExprModel) { + self.optimize(m.Expr) + } + + fn integratedToStr(self, mut m: &IntegratedToStrExprModel) { + self.optimize(m.Expr) + } + + fn free(self, mut m: &FreeExprModel) { + self.optimize(m.Expr) + } + + fn backendEmit(self, mut m: &BackendEmitExprModel) { + self.args(m.Exprs) + } + + fn optimize(self, mut &model: ExprModel) { + match type model { + | &BinaryExprModel: + self.binary((&BinaryExprModel)(model)) + | &UnaryExprModel: + self.unary((&UnaryExprModel)(model)) + | &StructLitExprModel: + self.structureLit((&StructLitExprModel)(model)) + | &AllocStructLitExprModel: + self.allocStructure((&AllocStructLitExprModel)(model)) + | &CastingExprModel: + self.casting((&CastingExprModel)(model)) + | &FnCallExprModel: + self.funcCall((&FnCallExprModel)(model)) + | &SliceExprModel: + self.slice((&SliceExprModel)(model)) + | &ArrayExprModel: + self.array((&ArrayExprModel)(model)) + | &IndexingExprModel: + self.indexing((&IndexingExprModel)(model)) + | &AnonFnExprModel: + self.anonFunc((&AnonFnExprModel)(model)) + | &MapExprModel: + self.mapExpr((&MapExprModel)(model)) + | &SlicingExprModel: + self.slicing((&SlicingExprModel)(model)) + | &TraitSubIdentExprModel: + self.traitSub((&TraitSubIdentExprModel)(model)) + | &StructSubIdentExprModel: + self.structureSub((&StructSubIdentExprModel)(model)) + | &TupleExprModel: + self.tuple((&TupleExprModel)(model)) + | &BuiltinOutCallExprModel: + self.outCall((&BuiltinOutCallExprModel)(model)) + | &BuiltinOutlnCallExprModel: + self.outlnCall((&BuiltinOutlnCallExprModel)(model)) + | &BuiltinNewCallExprModel: + self.newCall((&BuiltinNewCallExprModel)(model)) + | &BuiltinPanicCallExprModel: + self.panicCall((&BuiltinPanicCallExprModel)(model)) + | &BuiltinAssertCallExprModel: + self.assertCall((&BuiltinAssertCallExprModel)(model)) + | &BuiltinErrorCallExprModel: + self.errorCall((&BuiltinErrorCallExprModel)(model)) + | &BuiltinMakeCallExprModel: + self.makeCall((&BuiltinMakeCallExprModel)(model)) + | &BuiltinAppendCallExprModel: + self.appendCall((&BuiltinAppendCallExprModel)(model)) + | &BuiltinLenCallExprModel: + self.lenCall((&BuiltinLenCallExprModel)(model)) + | &BuiltinCapCallExprModel: + self.capCall((&BuiltinCapCallExprModel)(model)) + | &BuiltinDeleteCallExprModel: + self.deleteCall((&BuiltinDeleteCallExprModel)(model)) + | &SizeofExprModel: + self.sizeof((&SizeofExprModel)(model)) + | &AlignofExprModel: + self.alignof((&AlignofExprModel)(model)) + | &IntegratedToStrExprModel: + self.integratedToStr((&IntegratedToStrExprModel)(model)) + | &FreeExprModel: + self.free((&FreeExprModel)(model)) + | &BackendEmitExprModel: + self.backendEmit((&BackendEmitExprModel)(model)) + } + } } \ No newline at end of file diff --git a/src/julec/opt/deadcode/scope.jule b/src/julec/opt/deadcode/scope.jule index 1819d5611..decb13d52 100644 --- a/src/julec/opt/deadcode/scope.jule +++ b/src/julec/opt/deadcode/scope.jule @@ -4,279 +4,279 @@ use obj::{IR} use std::jule::sema::{ - Package, - Fn, - Scope, - Stmt, - Data, - RetSt, - Label, - GotoSt, - BuiltinErrorCallExprModel, - BuiltinPanicCallExprModel, - RangeIter, - WhileIter, - InfIter, - Conditional, - Match, - ExprModel, - Assign, - MultiAssign, + Package, + Fn, + Scope, + Stmt, + Data, + RetSt, + Label, + GotoSt, + BuiltinErrorCallExprModel, + BuiltinPanicCallExprModel, + RangeIter, + WhileIter, + InfIter, + Conditional, + Match, + ExprModel, + Assign, + MultiAssign, } // Dead code eliminate optimizer for scopes. struct scopeDeadCode { - parent: &scopeDeadCode - s: &Scope - stmts: *[]Stmt - i: int // Position. - labels: &[]&Label - gotos: &[]&GotoSt - except: bool + parent: &scopeDeadCode + s: &Scope + stmts: *[]Stmt + i: int // Position. + labels: &[]&Label + gotos: &[]&GotoSt + except: bool } impl scopeDeadCode { - fn optimizeChild(mut &self, mut &s: &Scope) { - mut sdc := &scopeDeadCode{ - parent: self, - s: s, - stmts: &s.Stmts, - labels: self.labels, - gotos: self.gotos, - } - unsafe { sdc.optimizeStmts() } - } + fn optimizeChild(mut &self, mut &s: &Scope) { + mut sdc := &scopeDeadCode{ + parent: self, + s: s, + stmts: &s.Stmts, + labels: self.labels, + gotos: self.gotos, + } + unsafe { sdc.optimizeStmts() } + } - fn optimizeBodyChildExceptional(mut &self, mut &s: &Scope) { - mut sdc := &scopeDeadCode{ - s: s, - stmts: &s.Stmts, - labels: self.labels, - gotos: self.gotos, - except: true, - } - unsafe { sdc.optimizeStmts() } - } + fn optimizeBodyChildExceptional(mut &self, mut &s: &Scope) { + mut sdc := &scopeDeadCode{ + s: s, + stmts: &s.Stmts, + labels: self.labels, + gotos: self.gotos, + except: true, + } + unsafe { sdc.optimizeStmts() } + } - fn optimizeBodyChild(mut &self, mut &s: &Scope) { - mut sdc := &scopeDeadCode{ - s: s, - stmts: &s.Stmts, - labels: self.labels, - gotos: self.gotos, - } - unsafe { sdc.optimizeStmts() } - } + fn optimizeBodyChild(mut &self, mut &s: &Scope) { + mut sdc := &scopeDeadCode{ + s: s, + stmts: &s.Stmts, + labels: self.labels, + gotos: self.gotos, + } + unsafe { sdc.optimizeStmts() } + } - fn optimizeExprModel(mut &self, mut &model: ExprModel) { - edc := exprDeadCode.new(self) - edc.optimize(model) - } + fn optimizeExprModel(mut &self, mut &model: ExprModel) { + edc := exprDeadCode.new(self) + edc.optimize(model) + } - fn eliminateFollowed(mut self) { - if len(*self.gotos) != 0 { - ret - } - unsafe { - *self.stmts = (*self.stmts)[:self.i+1] - } - mut parent := self.parent - for parent != nil { - unsafe { - *parent.stmts = (*parent.stmts)[:parent.i+1] - } - parent = parent.parent - } - } + fn eliminateFollowed(mut self) { + if len(*self.gotos) != 0 { + ret + } + unsafe { + *self.stmts = (*self.stmts)[:self.i+1] + } + mut parent := self.parent + for parent != nil { + unsafe { + *parent.stmts = (*parent.stmts)[:parent.i+1] + } + parent = parent.parent + } + } - fn pushGoto(mut &self, mut gt: &GotoSt) { - mut i := 0 - for i < len(*self.labels); i++ { - if gt.Ident == (*self.labels)[i].Ident { - ret - } - } - *self.gotos = append(*self.gotos, gt) - } + fn pushGoto(mut &self, mut gt: &GotoSt) { + mut i := 0 + for i < len(*self.labels); i++ { + if gt.Ident == (*self.labels)[i].Ident { + ret + } + } + *self.gotos = append(*self.gotos, gt) + } - fn pushLabel(mut &self, mut l: &Label) { - mut i := 0 - for i < len(*self.gotos) { - if l.Ident == (*self.gotos)[i].Ident { - copy((*self.gotos)[i:], (*self.gotos)[i+1:]) - *self.gotos = (*self.gotos)[:len(*self.gotos)-1] - continue - } - i++ - } - *self.labels = append(*self.labels, l) - } + fn pushLabel(mut &self, mut l: &Label) { + mut i := 0 + for i < len(*self.gotos) { + if l.Ident == (*self.gotos)[i].Ident { + copy((*self.gotos)[i:], (*self.gotos)[i+1:]) + *self.gotos = (*self.gotos)[:len(*self.gotos)-1] + continue + } + i++ + } + *self.labels = append(*self.labels, l) + } - fn optimizeRangeIter(mut &self, mut it: &RangeIter) { - self.optimizeExprModel(it.Expr.Model) - self.optimizeBodyChild(it.Scope) - } + fn optimizeRangeIter(mut &self, mut it: &RangeIter) { + self.optimizeExprModel(it.Expr.Model) + self.optimizeBodyChild(it.Scope) + } - fn optimizeWhileIter(mut &self, mut it: &WhileIter) { - self.optimizeExprModel(it.Expr) - if it.Next != nil { - self.optimizeStmt(it.Next) - } - self.optimizeBodyChild(it.Scope) - } + fn optimizeWhileIter(mut &self, mut it: &WhileIter) { + self.optimizeExprModel(it.Expr) + if it.Next != nil { + self.optimizeStmt(it.Next) + } + self.optimizeBodyChild(it.Scope) + } - fn optimizeInfIter(mut &self, mut it: &InfIter) { - self.optimizeBodyChild(it.Scope) - } + fn optimizeInfIter(mut &self, mut it: &InfIter) { + self.optimizeBodyChild(it.Scope) + } - fn optimizeConditional(mut &self, mut c: &Conditional) { - for (_, mut case) in c.Elifs { - if case != nil { - self.optimizeExprModel(case.Expr) - self.optimizeBodyChild(case.Scope) - } - } - if c.Default != nil { - if len(c.Elifs) == 0 { - // Use just child. - // There one case, this default scope can accepted as plain anonymous scope. - self.optimizeChild(c.Default.Scope) - } else { - self.optimizeBodyChild(c.Default.Scope) - } - } - } + fn optimizeConditional(mut &self, mut c: &Conditional) { + for (_, mut case) in c.Elifs { + if case != nil { + self.optimizeExprModel(case.Expr) + self.optimizeBodyChild(case.Scope) + } + } + if c.Default != nil { + if len(c.Elifs) == 0 { + // Use just child. + // There one case, this default scope can accepted as plain anonymous scope. + self.optimizeChild(c.Default.Scope) + } else { + self.optimizeBodyChild(c.Default.Scope) + } + } + } - fn optimizeMatch(mut &self, mut m: &Match) { - for (_, mut case) in m.Cases { - for (_, mut expr) in case.Exprs { - self.optimizeExprModel(expr.Model) - } - self.optimizeBodyChild(case.Scope) - } - if m.Default != nil { - if len(m.Cases) == 0 { - // Use just child. - // There one case, this default scope can accepted as plain anonymous scope. - self.optimizeChild(m.Default.Scope) - } else { - self.optimizeBodyChild(m.Default.Scope) - } - } - } + fn optimizeMatch(mut &self, mut m: &Match) { + for (_, mut case) in m.Cases { + for (_, mut expr) in case.Exprs { + self.optimizeExprModel(expr.Model) + } + self.optimizeBodyChild(case.Scope) + } + if m.Default != nil { + if len(m.Cases) == 0 { + // Use just child. + // There one case, this default scope can accepted as plain anonymous scope. + self.optimizeChild(m.Default.Scope) + } else { + self.optimizeBodyChild(m.Default.Scope) + } + } + } - fn optimizeAssign(mut &self, mut assign: &Assign) { - self.optimizeExprModel(assign.Left.Model) - self.optimizeExprModel(assign.Right.Model) - } + fn optimizeAssign(mut &self, mut assign: &Assign) { + self.optimizeExprModel(assign.Left.Model) + self.optimizeExprModel(assign.Right.Model) + } - fn optimizeMultiAssign(mut &self, mut assign: &MultiAssign) { - for (_, mut l) in assign.Left { - if l != nil { - self.optimizeExprModel(l.Model) - } - } - self.optimizeExprModel(assign.Right) - } + fn optimizeMultiAssign(mut &self, mut assign: &MultiAssign) { + for (_, mut l) in assign.Left { + if l != nil { + self.optimizeExprModel(l.Model) + } + } + self.optimizeExprModel(assign.Right) + } - fn optimizeStmt(mut &self, mut st: Stmt) { - match type st { - | &Scope: - mut scope := (&Scope)(st) - if scope.Deferred { - eliminateDeadCodeOfScope(scope) - } else { - self.optimizeChild(scope) - } - | &RangeIter: - self.optimizeRangeIter((&RangeIter)(st)) - | &WhileIter: - self.optimizeWhileIter((&WhileIter)(st)) - | &InfIter: - self.optimizeInfIter((&InfIter)(st)) - | &Conditional: - self.optimizeConditional((&Conditional)(st)) - | &Match: - self.optimizeMatch((&Match)(st)) - | &Assign: - self.optimizeAssign((&Assign)(st)) - | &MultiAssign: - self.optimizeMultiAssign((&MultiAssign)(st)) - | &Data: - mut d := (&Data)(st) - if self.except { - break - } - match type d.Model { - | &BuiltinErrorCallExprModel - | &BuiltinPanicCallExprModel: - // Remove followed statements of the function call. - // Unreachable code. - self.eliminateFollowed() - |: - self.optimizeExprModel(d.Model) - } - | &RetSt: - // Remove followed statements of the return statement. - // Unreachable code. - self.eliminateFollowed() - | &GotoSt: - self.pushGoto((&GotoSt)(st)) - // Remove followed statements of the return statement. - // Unreachable code. - self.eliminateFollowed() - | &Label: - self.pushLabel((&Label)(st)) - } - } + fn optimizeStmt(mut &self, mut st: Stmt) { + match type st { + | &Scope: + mut scope := (&Scope)(st) + if scope.Deferred { + eliminateDeadCodeOfScope(scope) + } else { + self.optimizeChild(scope) + } + | &RangeIter: + self.optimizeRangeIter((&RangeIter)(st)) + | &WhileIter: + self.optimizeWhileIter((&WhileIter)(st)) + | &InfIter: + self.optimizeInfIter((&InfIter)(st)) + | &Conditional: + self.optimizeConditional((&Conditional)(st)) + | &Match: + self.optimizeMatch((&Match)(st)) + | &Assign: + self.optimizeAssign((&Assign)(st)) + | &MultiAssign: + self.optimizeMultiAssign((&MultiAssign)(st)) + | &Data: + mut d := (&Data)(st) + if self.except { + break + } + match type d.Model { + | &BuiltinErrorCallExprModel + | &BuiltinPanicCallExprModel: + // Remove followed statements of the function call. + // Unreachable code. + self.eliminateFollowed() + |: + self.optimizeExprModel(d.Model) + } + | &RetSt: + // Remove followed statements of the return statement. + // Unreachable code. + self.eliminateFollowed() + | &GotoSt: + self.pushGoto((&GotoSt)(st)) + // Remove followed statements of the return statement. + // Unreachable code. + self.eliminateFollowed() + | &Label: + self.pushLabel((&Label)(st)) + } + } - unsafe fn optimizeStmts(mut &self) { - self.i = 0 - for self.i < len(*self.stmts); self.i++ { - self.optimizeStmt((*self.stmts)[self.i]) - } - } + unsafe fn optimizeStmts(mut &self) { + self.i = 0 + for self.i < len(*self.stmts); self.i++ { + self.optimizeStmt((*self.stmts)[self.i]) + } + } } fn eliminateDeadCodeOfScope(mut s: &Scope) { - labels := make([]&Label, 0, 1 << 4) - gotos := make([]&GotoSt, 0, 1 << 4) - mut sdc := &scopeDeadCode{ - s: s, - stmts: &s.Stmts, - labels: unsafe { (&[]&Label)(&labels) }, - gotos: unsafe { (&[]&GotoSt)(&gotos) }, - } - unsafe { sdc.optimizeStmts() } + labels := make([]&Label, 0, 1 << 4) + gotos := make([]&GotoSt, 0, 1 << 4) + mut sdc := &scopeDeadCode{ + s: s, + stmts: &s.Stmts, + labels: unsafe { (&[]&Label)(&labels) }, + gotos: unsafe { (&[]&GotoSt)(&gotos) }, + } + unsafe { sdc.optimizeStmts() } } // Eliminates dead functions. fn eliminateScopeFunctions(mut &funcs: []&Fn) { - for (_, mut func) in funcs { - for (_, mut ins) in func.Instances { - eliminateDeadCodeOfScope(ins.Scope) - } - } + for (_, mut func) in funcs { + for (_, mut ins) in func.Instances { + eliminateDeadCodeOfScope(ins.Scope) + } + } } fn eliminateFunctionsScopePackage(mut &pkg: &Package) { - for (_, mut f) in pkg.Files { - eliminateScopeFunctions(f.Funcs) - } + for (_, mut f) in pkg.Files { + eliminateScopeFunctions(f.Funcs) + } } fn eliminateScopePackage(mut &pkg: &Package) { - eliminateFunctionsScopePackage(pkg) + eliminateFunctionsScopePackage(pkg) } // Eliminate dead scope codes. fn EliminateScopes(mut &ir: &IR) { - mut i := len(ir.Used) - 1 - for i >= 0; i-- { - mut u := ir.Used[i] - if !u.Binded { - eliminateScopePackage(u.Package) - } - } - eliminateScopePackage(ir.Main) + mut i := len(ir.Used) - 1 + for i >= 0; i-- { + mut u := ir.Used[i] + if !u.Binded { + eliminateScopePackage(u.Package) + } + } + eliminateScopePackage(ir.Main) } \ No newline at end of file diff --git a/src/julec/opt/dynamic.jule b/src/julec/opt/dynamic.jule index d3dfc2701..fe70611a3 100644 --- a/src/julec/opt/dynamic.jule +++ b/src/julec/opt/dynamic.jule @@ -5,133 +5,133 @@ use obj use std::jule::lex::{TokenId} use std::jule::sema::{ - Data, - Var, - TypeKind, - ExprModel, - StructSubIdentExprModel, - UnaryExprModel, - CastingExprModel, + Data, + Var, + TypeKind, + ExprModel, + StructSubIdentExprModel, + UnaryExprModel, + CastingExprModel, } const invalidDynamic = uintptr(0x0) struct dynamicVar { - var: uintptr - kind: &TypeKind + var: uintptr + kind: &TypeKind } // Information wrapper for type analysis for dynamic types. struct dynamic { - vars: []dynamicVar + vars: []dynamicVar } impl dynamic { - // Appends variable with initial kind. - // If variable is already exist, updates kind information. - fn pushVar(mut &self, var: uintptr, mut kind: &TypeKind) { - if !Dynamic || var == invalidDynamic { - // Ignore it, because this optimizations within scope of the --opt-access flag. - ret - } - kind = isTypeGuaranteedDynamicData(self, kind, nil) // Just accept guaranteed types as kind. - for (_, mut v) in self.vars { - if v.var == var { - v.kind = kind - ret - } - } - // Not exist, append new one. - for (_, mut v) in self.vars { - if v.var == invalidDynamic { - // Empty place, use here instead of append. - v.var, v.kind = var, kind - ret - } - } - self.vars = append(self.vars, dynamicVar{var: var, kind: kind}) - } + // Appends variable with initial kind. + // If variable is already exist, updates kind information. + fn pushVar(mut &self, var: uintptr, mut kind: &TypeKind) { + if !Dynamic || var == invalidDynamic { + // Ignore it, because this optimizations within scope of the --opt-access flag. + ret + } + kind = isTypeGuaranteedDynamicData(self, kind, nil) // Just accept guaranteed types as kind. + for (_, mut v) in self.vars { + if v.var == var { + v.kind = kind + ret + } + } + // Not exist, append new one. + for (_, mut v) in self.vars { + if v.var == invalidDynamic { + // Empty place, use here instead of append. + v.var, v.kind = var, kind + ret + } + } + self.vars = append(self.vars, dynamicVar{var: var, kind: kind}) + } - fn removeVar(mut self, var: uintptr): bool { - if var != invalidDynamic { - for (_, mut v) in self.vars { - if v.var == var { - v.var = invalidDynamic - v.kind = nil - ret true - } - } - } - ret false - } + fn removeVar(mut self, var: uintptr): bool { + if var != invalidDynamic { + for (_, mut v) in self.vars { + if v.var == var { + v.var = invalidDynamic + v.kind = nil + ret true + } + } + } + ret false + } - // Reports whether variable is fits with kind. - fn isFits(mut self, var: uintptr, kind: &TypeKind): bool { - if var != invalidDynamic { - for _, v in self.vars { - if v.var == var { - ret v.kind != nil && v.kind.Equal(kind) - } - } - } - ret false - } + // Reports whether variable is fits with kind. + fn isFits(mut self, var: uintptr, kind: &TypeKind): bool { + if var != invalidDynamic { + for _, v in self.vars { + if v.var == var { + ret v.kind != nil && v.kind.Equal(kind) + } + } + } + ret false + } } fn possibleDynamicRemove(mut &d: &dynamic, m: ExprModel) { - if d != nil { - _ = d.removeVar(getDynamicVar(m)) - } + if d != nil { + _ = d.removeVar(getDynamicVar(m)) + } } fn isDynamicValidType(mut t: &TypeKind): bool { ret obj::IsAny(t) } fn isTypeGuaranteedDynamicData(mut &dy: &dynamic, mut t: &TypeKind, mut m: ExprModel): &TypeKind { - isAny := obj::IsAny(t) - if !isAny && t.Trait() == nil { - ret t - } - if !isAny { - ret nil - } - match type m { - | &CastingExprModel: - mut cem := (&CastingExprModel)(m) - ret isTypeGuaranteedDynamicData(dy, cem.ExprKind, cem.Expr.Model) - } - var := getDynamicVar(m) - if var == invalidDynamic { - ret nil - } - for (_, mut v) in dy.vars { - if v.var == var { - ret v.kind - } - } - ret nil + isAny := obj::IsAny(t) + if !isAny && t.Trait() == nil { + ret t + } + if !isAny { + ret nil + } + match type m { + | &CastingExprModel: + mut cem := (&CastingExprModel)(m) + ret isTypeGuaranteedDynamicData(dy, cem.ExprKind, cem.Expr.Model) + } + var := getDynamicVar(m) + if var == invalidDynamic { + ret nil + } + for (_, mut v) in dy.vars { + if v.var == var { + ret v.kind + } + } + ret nil } fn getDynamicVar(m: ExprModel): uintptr { - if !Dynamic { - ret invalidDynamic - } - match type m { - | &Var: - v := (&Var)(m) - if !v.Reference { - // Variable is not reference, return address of it. - ret uintptr((&Var)(m)) - } - // Variable is reference, it should be initialized at source code. - // Investigate the initial expression for variable address. - ret getDynamicVar(v.Value.Data.Model) - | &StructSubIdentExprModel: - ret uintptr((&StructSubIdentExprModel)(m).Field) - | &UnaryExprModel: - uem := (&UnaryExprModel)(m) - if uem.Op.Id == TokenId.Star { // Dereferencing. - ret getDynamicVar(uem.Expr.Model) - } - } - ret invalidDynamic + if !Dynamic { + ret invalidDynamic + } + match type m { + | &Var: + v := (&Var)(m) + if !v.Reference { + // Variable is not reference, return address of it. + ret uintptr((&Var)(m)) + } + // Variable is reference, it should be initialized at source code. + // Investigate the initial expression for variable address. + ret getDynamicVar(v.Value.Data.Model) + | &StructSubIdentExprModel: + ret uintptr((&StructSubIdentExprModel)(m).Field) + | &UnaryExprModel: + uem := (&UnaryExprModel)(m) + if uem.Op.Id == TokenId.Star { // Dereferencing. + ret getDynamicVar(uem.Expr.Model) + } + } + ret invalidDynamic } \ No newline at end of file diff --git a/src/julec/opt/equal.jule b/src/julec/opt/equal.jule index 37492c0d3..606f978c1 100644 --- a/src/julec/opt/equal.jule +++ b/src/julec/opt/equal.jule @@ -5,90 +5,90 @@ use integ for std::jule::integrated use std::jule::constant::{Const} use std::jule::sema::{ - ExprModel, - Var, - CastingExprModel, - UnaryExprModel, - IndexingExprModel, - BinaryExprModel, - StructSubIdentExprModel, + ExprModel, + Var, + CastingExprModel, + UnaryExprModel, + IndexingExprModel, + BinaryExprModel, + StructSubIdentExprModel, } fn typeData(&m: ExprModel): uintptr { - ret unsafe { uintptr(integ::Emit[*unsafe]("({}).type", m)) } + ret unsafe { uintptr(integ::Emit[*unsafe]("({}).type", m)) } } fn equalConst(l: &Const, r: &Const): bool { - match { - | l.IsI64(): - ret r.IsI64() && l.ReadI64() == r.ReadI64() - | l.IsU64(): - ret r.IsU64() && l.ReadU64() == r.ReadU64() - | l.IsF64(): - ret r.IsF64() && l.ReadF64() == r.ReadF64() - | l.IsStr(): - ret r.IsStr() && l.ReadStr() == r.ReadStr() - | l.IsBool(): - ret r.IsBool() && l.ReadBool() == r.ReadBool() - | l.IsNil(): - ret r.IsNil() - |: - ret false - } + match { + | l.IsI64(): + ret r.IsI64() && l.ReadI64() == r.ReadI64() + | l.IsU64(): + ret r.IsU64() && l.ReadU64() == r.ReadU64() + | l.IsF64(): + ret r.IsF64() && l.ReadF64() == r.ReadF64() + | l.IsStr(): + ret r.IsStr() && l.ReadStr() == r.ReadStr() + | l.IsBool(): + ret r.IsBool() && l.ReadBool() == r.ReadBool() + | l.IsNil(): + ret r.IsNil() + |: + ret false + } } fn equalCasting(l: &CastingExprModel, r: &CastingExprModel): bool { - if !l.Kind.Equal(r.Kind) { - ret false - } - ret equalModels(l.Expr.Model, r.Expr.Model) + if !l.Kind.Equal(r.Kind) { + ret false + } + ret equalModels(l.Expr.Model, r.Expr.Model) } fn equalUnary(l: &UnaryExprModel, r: &UnaryExprModel): bool { - if l.Op.Id != r.Op.Id || l.Op.Kind != r.Op.Kind { - ret false - } - ret equalModels(l.Expr.Model, r.Expr.Model) + if l.Op.Id != r.Op.Id || l.Op.Kind != r.Op.Kind { + ret false + } + ret equalModels(l.Expr.Model, r.Expr.Model) } fn equalIndexing(l: &IndexingExprModel, r: &IndexingExprModel): bool { - ret equalModels(l.Expr.Model, r.Expr.Model) && - equalModels(l.Index.Model, r.Index.Model) + ret equalModels(l.Expr.Model, r.Expr.Model) && + equalModels(l.Index.Model, r.Index.Model) } fn equalBinary(l: &BinaryExprModel, r: &BinaryExprModel): bool { - if l.Op.Id != r.Op.Id || l.Op.Kind != r.Op.Kind { - ret false - } - ret equalModels(l.Left.Model, r.Left.Model) && - equalModels(l.Right.Model, r.Right.Model) + if l.Op.Id != r.Op.Id || l.Op.Kind != r.Op.Kind { + ret false + } + ret equalModels(l.Left.Model, r.Left.Model) && + equalModels(l.Right.Model, r.Right.Model) } // Reports whether expressions are equal. // Designed lvalue equality comparison oriented, // such as swap statement value comparisons. fn equalModels(l: ExprModel, r: ExprModel): bool { - if typeData(l) != typeData(r) { - ret false - } - match type l { - | &Var: - ret (&Var)(l) == (&Var)(r) - | &StructSubIdentExprModel: - li := (&StructSubIdentExprModel)(l) - ri := (&StructSubIdentExprModel)(r) - ret li.Field == ri.Field && equalModels(li.Expr.Model, ri.Expr.Model) - | &Const: - ret equalConst((&Const)(l), (&Const)(r)) - | &CastingExprModel: - ret equalCasting((&CastingExprModel)(l), (&CastingExprModel)(r)) - | &UnaryExprModel: - ret equalUnary((&UnaryExprModel)(l), (&UnaryExprModel)(r)) - | &IndexingExprModel: - ret equalIndexing((&IndexingExprModel)(l), (&IndexingExprModel)(r)) - | &BinaryExprModel: - ret equalBinary((&BinaryExprModel)(l), (&BinaryExprModel)(r)) - |: - ret false - } + if typeData(l) != typeData(r) { + ret false + } + match type l { + | &Var: + ret (&Var)(l) == (&Var)(r) + | &StructSubIdentExprModel: + li := (&StructSubIdentExprModel)(l) + ri := (&StructSubIdentExprModel)(r) + ret li.Field == ri.Field && equalModels(li.Expr.Model, ri.Expr.Model) + | &Const: + ret equalConst((&Const)(l), (&Const)(r)) + | &CastingExprModel: + ret equalCasting((&CastingExprModel)(l), (&CastingExprModel)(r)) + | &UnaryExprModel: + ret equalUnary((&UnaryExprModel)(l), (&UnaryExprModel)(r)) + | &IndexingExprModel: + ret equalIndexing((&IndexingExprModel)(l), (&IndexingExprModel)(r)) + | &BinaryExprModel: + ret equalBinary((&BinaryExprModel)(l), (&BinaryExprModel)(r)) + |: + ret false + } } \ No newline at end of file diff --git a/src/julec/opt/expr.jule b/src/julec/opt/expr.jule index ee86a3d35..2fa1812e5 100644 --- a/src/julec/opt/expr.jule +++ b/src/julec/opt/expr.jule @@ -7,763 +7,763 @@ use math for std::math use std::jule::constant::{Const} use std::jule::lex::{TokenId, TokenKind} use std::jule::sema::{ - Scope, - Data, - Var, - FnIns, - ParamIns, - ExprModel, - BinaryExprModel, - OperandExprModel, - UnaryExprModel, - StructLitExprModel, - AllocStructLitExprModel, - CastingExprModel, - FnCallExprModel, - SliceExprModel, - ArrayExprModel, - IndexingExprModel, - AnonFnExprModel, - MapExprModel, - SlicingExprModel, - TraitSubIdentExprModel, - StructSubIdentExprModel, - TupleExprModel, - BuiltinNewCallExprModel, - BuiltinOutCallExprModel, - BuiltinOutlnCallExprModel, - BuiltinPanicCallExprModel, - BuiltinAssertCallExprModel, - BuiltinErrorCallExprModel, - BuiltinMakeCallExprModel, - BuiltinAppendCallExprModel, - BuiltinLenCallExprModel, - BuiltinCapCallExprModel, - BuiltinDeleteCallExprModel, - SizeofExprModel, - AlignofExprModel, - IntegratedToStrExprModel, - FreeExprModel, - BackendEmitExprModel, + Scope, + Data, + Var, + FnIns, + ParamIns, + ExprModel, + BinaryExprModel, + OperandExprModel, + UnaryExprModel, + StructLitExprModel, + AllocStructLitExprModel, + CastingExprModel, + FnCallExprModel, + SliceExprModel, + ArrayExprModel, + IndexingExprModel, + AnonFnExprModel, + MapExprModel, + SlicingExprModel, + TraitSubIdentExprModel, + StructSubIdentExprModel, + TupleExprModel, + BuiltinNewCallExprModel, + BuiltinOutCallExprModel, + BuiltinOutlnCallExprModel, + BuiltinPanicCallExprModel, + BuiltinAssertCallExprModel, + BuiltinErrorCallExprModel, + BuiltinMakeCallExprModel, + BuiltinAppendCallExprModel, + BuiltinLenCallExprModel, + BuiltinCapCallExprModel, + BuiltinDeleteCallExprModel, + SizeofExprModel, + AlignofExprModel, + IntegratedToStrExprModel, + FreeExprModel, + BackendEmitExprModel, } use types for std::jule::types // Expression optimizer that applies target-independent optimizations. struct exprOptimizer { - mut model: &ExprModel - mut data: &data // Should be non-nil guaranteed. + mut model: &ExprModel + mut data: &data // Should be non-nil guaranteed. } impl exprOptimizer { - static fn optimize(mut &model: ExprModel) { - exprOptimizer.optimizeData(model, emptyData) - } - - static fn optimizeData(mut &model: ExprModel, mut &d: &data) { - // Do optimizatitons if any enabled. - if exprEnabled { - mut exop := &exprOptimizer{ - model: unsafe { (&ExprModel)(&model) }, - data: d, - } - exop.do() - } - } - - fn selfCmpCond(self, mut &m: &BinaryExprModel): bool { - if !equalModels(m.Left.Model, m.Right.Model) { - ret false - } - match m.Op.Id { - | TokenId.Eqs - | TokenId.LtEq - | TokenId.GtEq: - // Operators used with itself: ==, <=, >=. - // Evaluation will be always true. - *self.model = Const.NewBool(true) - ret true - | TokenId.NotEq - | TokenId.Lt - | TokenId.Gt: - // Operators used with itself: !=, <, >. - // Evaluation will be always false. - *self.model = Const.NewBool(false) - ret true - |: - ret false - } - } - - fn boolCond(self, mut &m: &BinaryExprModel): bool { - lp := m.Left.Kind.Prim() - if lp == nil || !lp.IsBool() { - ret false - } - match type m.Left.Model { - | &Const: - // Equality comparison, swap operation is safe and will not change - // the behavior of the program. - m.Left, m.Right = m.Right, m.Left - |: - match type m.Right.Model { - | &Const: - break - |: - ret false - } - } - mut c := (&Const)(m.Right.Model) - match m.Op.Id { - | TokenId.DblAmper: - if c.ReadBool() { - // Use left operand as model directly. - // Logical and with constant true exprssion is always will be true. - // The non-constant left operand should be true, - // this is the only important thing. So eliminate constant true. - *self.model = m.Left.Model - } else { - // Logical and with constant false expression. - // Binary expression is always will be false. - c.SetBool(false) - *self.model = c - } - ret true - | TokenId.DblVline: - if c.ReadBool() { - // Logical or with constant true expression. - // Binary expression is always will be true. - c.SetBool(true) - *self.model = c - } else { - // Use left operand as model directly. - // Logical or with constant false exprssion is always will be false. - // The non-constant left operand should be true, - // this is the only important thing. So eliminate constant false. - *self.model = m.Left.Model - } - ret true - |: - } - ret false - } - - fn strCond(self, mut m: &BinaryExprModel): bool { - lp := m.Left.Kind.Prim() - if lp == nil || !lp.IsStr() { - ret false - } - if m.Op.Id != TokenId.Eqs && m.Op.Id != TokenId.NotEq { - ret false - } - match type m.Left.Model { - | &Const: - // Equality comparison, swap operation is safe and will not change - // the behavior of the program. - m.Left, m.Right = m.Right, m.Left - |: - match type m.Right.Model { - | &Const: - break - |: - ret false - } - } - mut c := (&Const)(m.Right.Model) - match m.Op.Id { - | TokenId.Eqs: - if c.ReadStr() == "" { - mut model := any(&EmptyCompareExprModel{ - Expr: m.Left.Model, - Neg: false, - }) - *self.model = unsafe { *(*ExprModel)(&model) } - break - } - mut model := any(&StrCompExprModel{ - Left: m.Left.Model, - Right: c, - NotEq: false, - }) - *self.model = unsafe { *(*ExprModel)(&model) } - | TokenId.NotEq: - if c.ReadStr() == "" { - mut model := any(&EmptyCompareExprModel{ - Expr: m.Left.Model, - Neg: true, - }) - *self.model = unsafe { *(*ExprModel)(&model) } - break - } - mut model := any(&StrCompExprModel{ - Left: m.Left.Model, - Right: c, - NotEq: true, - }) - *self.model = unsafe { *(*ExprModel)(&model) } - } - ret true - } - - fn tryNeutralElement1(self, mut &m: &BinaryExprModel, mut c: &Const, &nc: &OperandExprModel): bool { - if c.IsStr() { // Constant is string, check for string optimizations. - if !Str { - ret false - } - if c.ReadStr() == "" && m.Op.Id == TokenId.Plus { - // Concatenation with empty string, use the non-constnat operand's model. - *self.model = nc.Model - ret true - } - ret false - } - - // Following algoritms are designed for zero-constant math operations. - // So make required conditions are guaranteed. - if !Math || c.AsF64() != 0 { - ret false - } - match m.Op.Id { - | TokenId.Shl - | TokenId.Shr: - // If the constant expression is shifter, use the right operand's model. - if nc == m.Left { - *self.model = nc.Model - ret true - } - // If the shifter expression is non-constant, shifted value is constant-zero. - // Use zero-constant directly. - *self.model = c - ret true - | TokenId.Star: - c.SetI64(0) - *self.model = c - ret true - | TokenId.Plus - | TokenId.Minus: - *self.model = nc.Model - ret true - } - ret false - } - - // Tries optimize binary expression for neutral elements. - // Specialized in math optimizations. - fn tryNeutralElement(self, mut &m: &BinaryExprModel): bool { - // For netural element optimization, one of the operands should be constant. - match type m.Left.Model { - | &Const: - mut c := (&Const)(m.Left.Model) - ret self.tryNeutralElement1(m, c, m.Right) - } - match type m.Right.Model { - | &Const: - mut c := (&Const)(m.Right.Model) - ret self.tryNeutralElement1(m, c, m.Left) - } - ret false - } - - fn checkBinaryForBoundary(self, mut &m: &BinaryExprModel) { - if self.data.boundary == nil { - ret - } - match type m.Left.Model { - | &BuiltinLenCallExprModel: - mut blc := (&BuiltinLenCallExprModel)(m.Left.Model) - if !isBoundaryValidType(blc.Expr.Kind) { - ret - } - if m.Op.Id != TokenId.Gt && m.Op.Id != TokenId.Eqs { - ret - } - // len(x) > y, len(x) == y (constant) - // Max guaranteed size of x is y. - if m.Op.Id == TokenId.Eqs { - match type m.Right.Model { - | &Const: - mut c := new(Const, *(&Const)(m.Right.Model)) // Do not mutate binary operand. - c.Sub(*Const.NewI64(1)) - self.data.boundary.pushVar(getBoundaryVar(blc.Expr.Model), c) - } - ret - } - self.data.boundary.pushVar(getBoundaryVar(blc.Expr.Model), m.Right.Model) - ret - } - match type m.Right.Model { - | &BuiltinLenCallExprModel: - mut blc := (&BuiltinLenCallExprModel)(m.Right.Model) - if !isBoundaryValidType(blc.Expr.Kind) { - ret - } - if m.Op.Id != TokenId.Lt && m.Op.Id != TokenId.Eqs { - ret - } - // y < len(x), y (constant) == len(x) - // Max guaranteed size of x is y. - if m.Op.Id == TokenId.Eqs { - match type m.Left.Model { - | &Const: - mut c := new(Const, *(&Const)(m.Left.Model)) // Do not mutate binary operand. - c.Sub(*Const.NewI64(1)) - self.data.boundary.pushVar(getBoundaryVar(blc.Expr.Model), c) - } - ret - } - self.data.boundary.pushVar(getBoundaryVar(blc.Expr.Model), m.Left.Model) - ret - } - } - - fn checkBinaryForNil(self, mut &m: &BinaryExprModel) { - if self.data.nils == nil { - ret - } - mut var := getNilVar(m.Left.Model) - if var != invalidNil { - if !isNilValidType(m.Left.Kind) { - ret - } - match type m.Right.Model { - | &Const: - // No need to check whether constant variable is nil. - // It only can be nil. - self.data.nils.pushVar(var, m.Op.Id == TokenId.NotEq) - } - ret - } - var = getNilVar(m.Right.Model) - if var != invalidNil { - if !isNilValidType(m.Right.Kind) { - ret - } - match type m.Left.Model { - | &Const: - // No need to check whether constant variable is nil. - // It only can be nil. - self.data.nils.pushVar(var, m.Op.Id == TokenId.NotEq) - } - ret - } - } - - fn binary(self, mut m: &BinaryExprModel) { - self.checkBinaryForBoundary(m) - self.checkBinaryForNil(m) - - exprOptimizer.optimizeData(m.Left.Model, self.data) - exprOptimizer.optimizeData(m.Right.Model, self.data) - - if Cond { - match { - | self.strCond(m) - | self.boolCond(m) - | self.selfCmpCond(m): - ret - } - } - - if self.tryNeutralElement(m) { - ret - } - - if !Math { - ret - } - - // Check whether the right operand is constant for safety. - // The following algorithms assumes the right operand is constant. - match type m.Right.Model { - | &Const: - break - |: - ret - } - - // Break optimizations if types are not primitive. - // No need for checking whether types are arithmetic, - // because relevant operators are conly avaliable for arithmetic primitives. - lp := m.Left.Kind.Prim() - if lp == nil { - ret - } - rp := m.Right.Kind.Prim() - if rp == nil { - ret - } - - match m.Op.Id { - | TokenId.Star: - ok, x := checkForBitShiftOpt(m.Left, m.Right) - if ok { - m.Op.Id = TokenId.Shl - m.Op.Kind = TokenKind.Shl - mut c := (&Const)(m.Right.Model) - c.SetU64(x) - // No need to set model as UnsafeBinaryExprModel, - // shl is not checked at runtime, so it is optimize enough. - ret - } - | TokenId.Solidus: - ok, x := checkForBitShiftOpt(m.Left, m.Right) - if ok { - m.Op.Id = TokenId.Shr - m.Op.Kind = TokenKind.Shr - mut c := (&Const)(m.Right.Model) - c.SetU64(x) - // No need to set model as UnsafeBinaryExprModel, - // shr is not checked at runtime, so it is optimize enough. - ret - } - | TokenId.Percent: - mut c := (&Const)(m.Right.Model) - if c.AsF64() == 0b10 { - m.Op.Id = TokenId.Amper - m.Op.Kind = TokenKind.Amper - c.SetI64(1) - // No need to set model as UnsafeBinaryExprModel, - // bitwise and is not checked at runtime, so it is optimize enough. - ret - } - |: - // Eliminate unsupported operators. - ret - } - // Update model as UnsafeBinaryExprModel because it is safe, comptime checked. - // There is no risk like zero-division. - mut model := any(&UnsafeBinaryExprModel{Node: m}) - *self.model = unsafe { *(*ExprModel)(&model) } - } - - fn unary(self, mut m: &UnaryExprModel) { - exprOptimizer.optimizeData(m.Expr.Model, self.data) - if !Ptr { - ret - } - match m.Op.Id { - | TokenId.Star: - match type m.Expr.Model { - | &UnaryExprModel: - mut um := (&UnaryExprModel)(m.Expr.Model) - if um.Op.Id == TokenId.Amper { - // Remove pointer overhead. - // Expression is: *(&x) - // Simplify to: x - *self.model = um.Expr.Model - ret - } - ret - } - if !Access { - ret - } - if self.data.nils != nil && isNilValidType(m.Expr.Kind) { - var := getNilVar(m.Expr.Model) - if self.data.nils.isSafe(var) { - mut model := any(&UnsafeDerefExprModel{Base: m}) - *self.model = unsafe { *(*ExprModel)(&model) } - ret - } - // Now this varible is safe until it mutated. - self.data.nils.pushVar(var, true) - } - | TokenId.Amper: - match type m.Expr.Model { - | &Var: - mut v := (&Var)(m.Expr.Model) - if v.Reference { - mut model := any(&RefExprModel{Var: v}) - *self.model = unsafe { *(*ExprModel)(&model) } - } - } - } - } - - fn structureLit(self, mut m: &StructLitExprModel) { - for (_, mut arg) in m.Args { - if self.data.boundary != nil { - if isBoundaryRiskyType(arg.Expr.Kind) { - possibleBoundaryRemove(self.data.boundary, arg) - } - } - if self.data.nils != nil { - possibleNilRemove(self.data.nils, arg.Expr.Model) - } - if self.data.dynamic != nil { - possibleDynamicRemove(self.data.dynamic, arg.Expr.Model) - } - exprOptimizer.optimizeData(arg.Expr.Model, self.data) - } - } - - fn allocStructure(self, mut m: &AllocStructLitExprModel) { - self.structureLit(m.Lit) - } - - fn casting(self, mut m: &CastingExprModel) { - valid := isDynamicValidType(m.ExprKind) - var := getDynamicVar(m.Expr.Model) - if valid && self.data.dynamic != nil && self.data.dynamic.isFits(var, m.Kind) { - mut model := any(&UnsafeCastingExprModel{Base: m}) - *self.model = unsafe { *(*ExprModel)(&model) } - ret - } - exprOptimizer.optimizeData(m.Expr.Model, self.data) - if self.data.dynamic != nil && valid { - self.data.dynamic.pushVar(var, m.Kind) - } - } - - fn args(self, mut params: []&ParamIns, mut &args: []ExprModel) { - for (i, mut arg) in args { - if i < len(params) { - mut p := params[i] - if p.Decl.Mutable && p.Decl.Reference { - if self.data.boundary != nil { - if isBoundaryRiskyType(p.Kind) { - possibleBoundaryRemove(self.data.boundary, arg) - } - } - if self.data.nils != nil { - possibleNilRemove(self.data.nils, arg) - } - if self.data.dynamic != nil { - possibleDynamicRemove(self.data.dynamic, arg) - } - } - } - exprOptimizer.optimizeData(arg, self.data) - args[i] = arg - } - } - - fn scope(self, mut &s: &Scope) { - mut scopt := scopeOptimizer.new(s) - scopt.data = self.data - scopt.optimize() - } - - fn funcCall(self, mut m: &FnCallExprModel) { - exprOptimizer.optimizeData(m.Expr, self.data) - self.args(m.Func.Params, m.Args) - if m.Except != nil { - self.scope(m.Except) - } - } - - fn slice(self, mut m: &SliceExprModel) { - self.args(nil, m.Elems) - } - - fn array(self, mut m: &ArrayExprModel) { - if len(m.Elems) == 2 && m.Elems[1] == nil { - mut elem := m.Elems[0] - exprOptimizer.optimizeData(elem, self.data) - m.Elems[0] = elem - } - self.args(nil, m.Elems) - } - - fn indexing(self, mut m: &IndexingExprModel) { - exprOptimizer.optimizeData(m.Expr.Model, self.data) - exprOptimizer.optimizeData(m.Index.Model, self.data) - if !Access { - ret - } - - array := m.Expr.Kind.Arr() != nil - // Constants checked by semantic analysis for arrays, safe. - if array && m.Index.IsConst() { - mut model := any(&UnsafeIndexingExprModel{Node: m}) - *self.model = unsafe { *(*ExprModel)(&model) } - ret - } - - if self.data.boundary != nil && isBoundaryValidType(m.Expr.Kind) { - var := getBoundaryVar(m.Expr.Model) - if self.data.boundary.fitsMaxSize(var, m.Index.Model) { - mut model := any(&UnsafeIndexingExprModel{Node: m}) - *self.model = unsafe { *(*ExprModel)(&model) } - ret - } - self.data.boundary.pushVar(var, m.Index.Model) - } - } - - fn anonFunc(self, mut m: &AnonFnExprModel) { - self.scope(m.Func.Scope) - } - - fn mapExpr(self, mut m: &MapExprModel) { - for (_, mut pair) in m.Entries { - exprOptimizer.optimizeData(pair.Key, self.data) - exprOptimizer.optimizeData(pair.Val, self.data) - } - } - - fn slicing(self, mut m: &SlicingExprModel) { - exprOptimizer.optimizeData(m.Expr, self.data) - exprOptimizer.optimizeData(m.Left, self.data) - if m.Right != nil { - exprOptimizer.optimizeData(m.Right, self.data) - } - } - - fn traitSub(self, mut m: &TraitSubIdentExprModel) { - exprOptimizer.optimizeData(m.Expr, self.data) - } - - fn structureSub(self, mut m: &StructSubIdentExprModel) { - exprOptimizer.optimizeData(m.Expr.Model, self.data) - } - - fn tuple(self, mut m: &TupleExprModel) { - for (_, mut d) in m.Datas { - exprOptimizer.optimizeData(d.Model, self.data) - } - } - - fn newCall(self, mut m: &BuiltinNewCallExprModel) { - if m.Init != nil { - exprOptimizer.optimizeData(m.Init, self.data) - } - } - - fn outCall(self, mut m: &BuiltinOutCallExprModel) { - exprOptimizer.optimizeData(m.Expr, self.data) - } - - fn outlnCall(self, mut m: &BuiltinOutlnCallExprModel) { - exprOptimizer.optimizeData(m.Expr, self.data) - } - - fn panicCall(self, mut m: &BuiltinPanicCallExprModel) { - exprOptimizer.optimizeData(m.Expr, self.data) - } - - fn assertCall(self, mut m: &BuiltinAssertCallExprModel) { - exprOptimizer.optimizeData(m.Expr, self.data) - } - - fn errorCall(self, mut m: &BuiltinErrorCallExprModel) { - exprOptimizer.optimizeData(m.Err.Model, self.data) - } - - fn makeCall(self, mut m: &BuiltinMakeCallExprModel) { - if m.Len != nil { - exprOptimizer.optimizeData(m.Len, self.data) - } - if m.Cap != nil { - exprOptimizer.optimizeData(m.Cap, self.data) - } - } - - fn appendCall(self, mut m: &BuiltinAppendCallExprModel) { - exprOptimizer.optimizeData(m.Dest, self.data) - exprOptimizer.optimizeData(m.Elements, self.data) - } - - fn lenCall(self, mut m: &BuiltinLenCallExprModel) { - exprOptimizer.optimizeData(m.Expr.Model, self.data) - } - - fn capCall(self, mut m: &BuiltinCapCallExprModel) { - exprOptimizer.optimizeData(m.Expr.Model, self.data) - } - - fn deleteCall(self, mut m: &BuiltinDeleteCallExprModel) { - exprOptimizer.optimizeData(m.Dest.Model, self.data) - if m.Key != nil { - exprOptimizer.optimizeData(m.Key.Model, self.data) - } - } - - fn sizeof(self, mut m: &SizeofExprModel) { - exprOptimizer.optimizeData(m.Expr, self.data) - } - - fn alignof(self, mut m: &AlignofExprModel) { - exprOptimizer.optimizeData(m.Expr, self.data) - } - - fn integratedToStr(self, mut m: &IntegratedToStrExprModel) { - exprOptimizer.optimizeData(m.Expr, self.data) - } - - fn free(self, mut m: &FreeExprModel) { - exprOptimizer.optimizeData(m.Expr, self.data) - } - - fn backendEmit(self, mut m: &BackendEmitExprModel) { - self.args(nil, m.Exprs) - } - - fn do(self) { - match type *self.model { - | &BinaryExprModel: - self.binary((&BinaryExprModel)(*self.model)) - | &UnaryExprModel: - self.unary((&UnaryExprModel)(*self.model)) - | &StructLitExprModel: - self.structureLit((&StructLitExprModel)(*self.model)) - | &AllocStructLitExprModel: - self.allocStructure((&AllocStructLitExprModel)(*self.model)) - | &CastingExprModel: - self.casting((&CastingExprModel)(*self.model)) - | &FnCallExprModel: - self.funcCall((&FnCallExprModel)(*self.model)) - | &SliceExprModel: - self.slice((&SliceExprModel)(*self.model)) - | &ArrayExprModel: - self.array((&ArrayExprModel)(*self.model)) - | &IndexingExprModel: - self.indexing((&IndexingExprModel)(*self.model)) - | &AnonFnExprModel: - self.anonFunc((&AnonFnExprModel)(*self.model)) - | &MapExprModel: - self.mapExpr((&MapExprModel)(*self.model)) - | &SlicingExprModel: - self.slicing((&SlicingExprModel)(*self.model)) - | &TraitSubIdentExprModel: - self.traitSub((&TraitSubIdentExprModel)(*self.model)) - | &StructSubIdentExprModel: - self.structureSub((&StructSubIdentExprModel)(*self.model)) - | &TupleExprModel: - self.tuple((&TupleExprModel)(*self.model)) - | &BuiltinOutCallExprModel: - self.outCall((&BuiltinOutCallExprModel)(*self.model)) - | &BuiltinOutlnCallExprModel: - self.outlnCall((&BuiltinOutlnCallExprModel)(*self.model)) - | &BuiltinNewCallExprModel: - self.newCall((&BuiltinNewCallExprModel)(*self.model)) - | &BuiltinPanicCallExprModel: - self.panicCall((&BuiltinPanicCallExprModel)(*self.model)) - | &BuiltinAssertCallExprModel: - self.assertCall((&BuiltinAssertCallExprModel)(*self.model)) - | &BuiltinErrorCallExprModel: - self.errorCall((&BuiltinErrorCallExprModel)(*self.model)) - | &BuiltinMakeCallExprModel: - self.makeCall((&BuiltinMakeCallExprModel)(*self.model)) - | &BuiltinAppendCallExprModel: - self.appendCall((&BuiltinAppendCallExprModel)(*self.model)) - | &BuiltinLenCallExprModel: - self.lenCall((&BuiltinLenCallExprModel)(*self.model)) - | &BuiltinCapCallExprModel: - self.capCall((&BuiltinCapCallExprModel)(*self.model)) - | &BuiltinDeleteCallExprModel: - self.deleteCall((&BuiltinDeleteCallExprModel)(*self.model)) - | &SizeofExprModel: - self.sizeof((&SizeofExprModel)(*self.model)) - | &AlignofExprModel: - self.alignof((&AlignofExprModel)(*self.model)) - | &IntegratedToStrExprModel: - self.integratedToStr((&IntegratedToStrExprModel)(*self.model)) - | &FreeExprModel: - self.free((&FreeExprModel)(*self.model)) - | &BackendEmitExprModel: - self.backendEmit((&BackendEmitExprModel)(*self.model)) - } - } + static fn optimize(mut &model: ExprModel) { + exprOptimizer.optimizeData(model, emptyData) + } + + static fn optimizeData(mut &model: ExprModel, mut &d: &data) { + // Do optimizatitons if any enabled. + if exprEnabled { + mut exop := &exprOptimizer{ + model: unsafe { (&ExprModel)(&model) }, + data: d, + } + exop.do() + } + } + + fn selfCmpCond(self, mut &m: &BinaryExprModel): bool { + if !equalModels(m.Left.Model, m.Right.Model) { + ret false + } + match m.Op.Id { + | TokenId.Eqs + | TokenId.LtEq + | TokenId.GtEq: + // Operators used with itself: ==, <=, >=. + // Evaluation will be always true. + *self.model = Const.NewBool(true) + ret true + | TokenId.NotEq + | TokenId.Lt + | TokenId.Gt: + // Operators used with itself: !=, <, >. + // Evaluation will be always false. + *self.model = Const.NewBool(false) + ret true + |: + ret false + } + } + + fn boolCond(self, mut &m: &BinaryExprModel): bool { + lp := m.Left.Kind.Prim() + if lp == nil || !lp.IsBool() { + ret false + } + match type m.Left.Model { + | &Const: + // Equality comparison, swap operation is safe and will not change + // the behavior of the program. + m.Left, m.Right = m.Right, m.Left + |: + match type m.Right.Model { + | &Const: + break + |: + ret false + } + } + mut c := (&Const)(m.Right.Model) + match m.Op.Id { + | TokenId.DblAmper: + if c.ReadBool() { + // Use left operand as model directly. + // Logical and with constant true exprssion is always will be true. + // The non-constant left operand should be true, + // this is the only important thing. So eliminate constant true. + *self.model = m.Left.Model + } else { + // Logical and with constant false expression. + // Binary expression is always will be false. + c.SetBool(false) + *self.model = c + } + ret true + | TokenId.DblVline: + if c.ReadBool() { + // Logical or with constant true expression. + // Binary expression is always will be true. + c.SetBool(true) + *self.model = c + } else { + // Use left operand as model directly. + // Logical or with constant false exprssion is always will be false. + // The non-constant left operand should be true, + // this is the only important thing. So eliminate constant false. + *self.model = m.Left.Model + } + ret true + |: + } + ret false + } + + fn strCond(self, mut m: &BinaryExprModel): bool { + lp := m.Left.Kind.Prim() + if lp == nil || !lp.IsStr() { + ret false + } + if m.Op.Id != TokenId.Eqs && m.Op.Id != TokenId.NotEq { + ret false + } + match type m.Left.Model { + | &Const: + // Equality comparison, swap operation is safe and will not change + // the behavior of the program. + m.Left, m.Right = m.Right, m.Left + |: + match type m.Right.Model { + | &Const: + break + |: + ret false + } + } + mut c := (&Const)(m.Right.Model) + match m.Op.Id { + | TokenId.Eqs: + if c.ReadStr() == "" { + mut model := any(&EmptyCompareExprModel{ + Expr: m.Left.Model, + Neg: false, + }) + *self.model = unsafe { *(*ExprModel)(&model) } + break + } + mut model := any(&StrCompExprModel{ + Left: m.Left.Model, + Right: c, + NotEq: false, + }) + *self.model = unsafe { *(*ExprModel)(&model) } + | TokenId.NotEq: + if c.ReadStr() == "" { + mut model := any(&EmptyCompareExprModel{ + Expr: m.Left.Model, + Neg: true, + }) + *self.model = unsafe { *(*ExprModel)(&model) } + break + } + mut model := any(&StrCompExprModel{ + Left: m.Left.Model, + Right: c, + NotEq: true, + }) + *self.model = unsafe { *(*ExprModel)(&model) } + } + ret true + } + + fn tryNeutralElement1(self, mut &m: &BinaryExprModel, mut c: &Const, &nc: &OperandExprModel): bool { + if c.IsStr() { // Constant is string, check for string optimizations. + if !Str { + ret false + } + if c.ReadStr() == "" && m.Op.Id == TokenId.Plus { + // Concatenation with empty string, use the non-constnat operand's model. + *self.model = nc.Model + ret true + } + ret false + } + + // Following algoritms are designed for zero-constant math operations. + // So make required conditions are guaranteed. + if !Math || c.AsF64() != 0 { + ret false + } + match m.Op.Id { + | TokenId.Shl + | TokenId.Shr: + // If the constant expression is shifter, use the right operand's model. + if nc == m.Left { + *self.model = nc.Model + ret true + } + // If the shifter expression is non-constant, shifted value is constant-zero. + // Use zero-constant directly. + *self.model = c + ret true + | TokenId.Star: + c.SetI64(0) + *self.model = c + ret true + | TokenId.Plus + | TokenId.Minus: + *self.model = nc.Model + ret true + } + ret false + } + + // Tries optimize binary expression for neutral elements. + // Specialized in math optimizations. + fn tryNeutralElement(self, mut &m: &BinaryExprModel): bool { + // For netural element optimization, one of the operands should be constant. + match type m.Left.Model { + | &Const: + mut c := (&Const)(m.Left.Model) + ret self.tryNeutralElement1(m, c, m.Right) + } + match type m.Right.Model { + | &Const: + mut c := (&Const)(m.Right.Model) + ret self.tryNeutralElement1(m, c, m.Left) + } + ret false + } + + fn checkBinaryForBoundary(self, mut &m: &BinaryExprModel) { + if self.data.boundary == nil { + ret + } + match type m.Left.Model { + | &BuiltinLenCallExprModel: + mut blc := (&BuiltinLenCallExprModel)(m.Left.Model) + if !isBoundaryValidType(blc.Expr.Kind) { + ret + } + if m.Op.Id != TokenId.Gt && m.Op.Id != TokenId.Eqs { + ret + } + // len(x) > y, len(x) == y (constant) + // Max guaranteed size of x is y. + if m.Op.Id == TokenId.Eqs { + match type m.Right.Model { + | &Const: + mut c := new(Const, *(&Const)(m.Right.Model)) // Do not mutate binary operand. + c.Sub(*Const.NewI64(1)) + self.data.boundary.pushVar(getBoundaryVar(blc.Expr.Model), c) + } + ret + } + self.data.boundary.pushVar(getBoundaryVar(blc.Expr.Model), m.Right.Model) + ret + } + match type m.Right.Model { + | &BuiltinLenCallExprModel: + mut blc := (&BuiltinLenCallExprModel)(m.Right.Model) + if !isBoundaryValidType(blc.Expr.Kind) { + ret + } + if m.Op.Id != TokenId.Lt && m.Op.Id != TokenId.Eqs { + ret + } + // y < len(x), y (constant) == len(x) + // Max guaranteed size of x is y. + if m.Op.Id == TokenId.Eqs { + match type m.Left.Model { + | &Const: + mut c := new(Const, *(&Const)(m.Left.Model)) // Do not mutate binary operand. + c.Sub(*Const.NewI64(1)) + self.data.boundary.pushVar(getBoundaryVar(blc.Expr.Model), c) + } + ret + } + self.data.boundary.pushVar(getBoundaryVar(blc.Expr.Model), m.Left.Model) + ret + } + } + + fn checkBinaryForNil(self, mut &m: &BinaryExprModel) { + if self.data.nils == nil { + ret + } + mut var := getNilVar(m.Left.Model) + if var != invalidNil { + if !isNilValidType(m.Left.Kind) { + ret + } + match type m.Right.Model { + | &Const: + // No need to check whether constant variable is nil. + // It only can be nil. + self.data.nils.pushVar(var, m.Op.Id == TokenId.NotEq) + } + ret + } + var = getNilVar(m.Right.Model) + if var != invalidNil { + if !isNilValidType(m.Right.Kind) { + ret + } + match type m.Left.Model { + | &Const: + // No need to check whether constant variable is nil. + // It only can be nil. + self.data.nils.pushVar(var, m.Op.Id == TokenId.NotEq) + } + ret + } + } + + fn binary(self, mut m: &BinaryExprModel) { + self.checkBinaryForBoundary(m) + self.checkBinaryForNil(m) + + exprOptimizer.optimizeData(m.Left.Model, self.data) + exprOptimizer.optimizeData(m.Right.Model, self.data) + + if Cond { + match { + | self.strCond(m) + | self.boolCond(m) + | self.selfCmpCond(m): + ret + } + } + + if self.tryNeutralElement(m) { + ret + } + + if !Math { + ret + } + + // Check whether the right operand is constant for safety. + // The following algorithms assumes the right operand is constant. + match type m.Right.Model { + | &Const: + break + |: + ret + } + + // Break optimizations if types are not primitive. + // No need for checking whether types are arithmetic, + // because relevant operators are conly avaliable for arithmetic primitives. + lp := m.Left.Kind.Prim() + if lp == nil { + ret + } + rp := m.Right.Kind.Prim() + if rp == nil { + ret + } + + match m.Op.Id { + | TokenId.Star: + ok, x := checkForBitShiftOpt(m.Left, m.Right) + if ok { + m.Op.Id = TokenId.Shl + m.Op.Kind = TokenKind.Shl + mut c := (&Const)(m.Right.Model) + c.SetU64(x) + // No need to set model as UnsafeBinaryExprModel, + // shl is not checked at runtime, so it is optimize enough. + ret + } + | TokenId.Solidus: + ok, x := checkForBitShiftOpt(m.Left, m.Right) + if ok { + m.Op.Id = TokenId.Shr + m.Op.Kind = TokenKind.Shr + mut c := (&Const)(m.Right.Model) + c.SetU64(x) + // No need to set model as UnsafeBinaryExprModel, + // shr is not checked at runtime, so it is optimize enough. + ret + } + | TokenId.Percent: + mut c := (&Const)(m.Right.Model) + if c.AsF64() == 0b10 { + m.Op.Id = TokenId.Amper + m.Op.Kind = TokenKind.Amper + c.SetI64(1) + // No need to set model as UnsafeBinaryExprModel, + // bitwise and is not checked at runtime, so it is optimize enough. + ret + } + |: + // Eliminate unsupported operators. + ret + } + // Update model as UnsafeBinaryExprModel because it is safe, comptime checked. + // There is no risk like zero-division. + mut model := any(&UnsafeBinaryExprModel{Node: m}) + *self.model = unsafe { *(*ExprModel)(&model) } + } + + fn unary(self, mut m: &UnaryExprModel) { + exprOptimizer.optimizeData(m.Expr.Model, self.data) + if !Ptr { + ret + } + match m.Op.Id { + | TokenId.Star: + match type m.Expr.Model { + | &UnaryExprModel: + mut um := (&UnaryExprModel)(m.Expr.Model) + if um.Op.Id == TokenId.Amper { + // Remove pointer overhead. + // Expression is: *(&x) + // Simplify to: x + *self.model = um.Expr.Model + ret + } + ret + } + if !Access { + ret + } + if self.data.nils != nil && isNilValidType(m.Expr.Kind) { + var := getNilVar(m.Expr.Model) + if self.data.nils.isSafe(var) { + mut model := any(&UnsafeDerefExprModel{Base: m}) + *self.model = unsafe { *(*ExprModel)(&model) } + ret + } + // Now this varible is safe until it mutated. + self.data.nils.pushVar(var, true) + } + | TokenId.Amper: + match type m.Expr.Model { + | &Var: + mut v := (&Var)(m.Expr.Model) + if v.Reference { + mut model := any(&RefExprModel{Var: v}) + *self.model = unsafe { *(*ExprModel)(&model) } + } + } + } + } + + fn structureLit(self, mut m: &StructLitExprModel) { + for (_, mut arg) in m.Args { + if self.data.boundary != nil { + if isBoundaryRiskyType(arg.Expr.Kind) { + possibleBoundaryRemove(self.data.boundary, arg) + } + } + if self.data.nils != nil { + possibleNilRemove(self.data.nils, arg.Expr.Model) + } + if self.data.dynamic != nil { + possibleDynamicRemove(self.data.dynamic, arg.Expr.Model) + } + exprOptimizer.optimizeData(arg.Expr.Model, self.data) + } + } + + fn allocStructure(self, mut m: &AllocStructLitExprModel) { + self.structureLit(m.Lit) + } + + fn casting(self, mut m: &CastingExprModel) { + valid := isDynamicValidType(m.ExprKind) + var := getDynamicVar(m.Expr.Model) + if valid && self.data.dynamic != nil && self.data.dynamic.isFits(var, m.Kind) { + mut model := any(&UnsafeCastingExprModel{Base: m}) + *self.model = unsafe { *(*ExprModel)(&model) } + ret + } + exprOptimizer.optimizeData(m.Expr.Model, self.data) + if self.data.dynamic != nil && valid { + self.data.dynamic.pushVar(var, m.Kind) + } + } + + fn args(self, mut params: []&ParamIns, mut &args: []ExprModel) { + for (i, mut arg) in args { + if i < len(params) { + mut p := params[i] + if p.Decl.Mutable && p.Decl.Reference { + if self.data.boundary != nil { + if isBoundaryRiskyType(p.Kind) { + possibleBoundaryRemove(self.data.boundary, arg) + } + } + if self.data.nils != nil { + possibleNilRemove(self.data.nils, arg) + } + if self.data.dynamic != nil { + possibleDynamicRemove(self.data.dynamic, arg) + } + } + } + exprOptimizer.optimizeData(arg, self.data) + args[i] = arg + } + } + + fn scope(self, mut &s: &Scope) { + mut scopt := scopeOptimizer.new(s) + scopt.data = self.data + scopt.optimize() + } + + fn funcCall(self, mut m: &FnCallExprModel) { + exprOptimizer.optimizeData(m.Expr, self.data) + self.args(m.Func.Params, m.Args) + if m.Except != nil { + self.scope(m.Except) + } + } + + fn slice(self, mut m: &SliceExprModel) { + self.args(nil, m.Elems) + } + + fn array(self, mut m: &ArrayExprModel) { + if len(m.Elems) == 2 && m.Elems[1] == nil { + mut elem := m.Elems[0] + exprOptimizer.optimizeData(elem, self.data) + m.Elems[0] = elem + } + self.args(nil, m.Elems) + } + + fn indexing(self, mut m: &IndexingExprModel) { + exprOptimizer.optimizeData(m.Expr.Model, self.data) + exprOptimizer.optimizeData(m.Index.Model, self.data) + if !Access { + ret + } + + array := m.Expr.Kind.Arr() != nil + // Constants checked by semantic analysis for arrays, safe. + if array && m.Index.IsConst() { + mut model := any(&UnsafeIndexingExprModel{Node: m}) + *self.model = unsafe { *(*ExprModel)(&model) } + ret + } + + if self.data.boundary != nil && isBoundaryValidType(m.Expr.Kind) { + var := getBoundaryVar(m.Expr.Model) + if self.data.boundary.fitsMaxSize(var, m.Index.Model) { + mut model := any(&UnsafeIndexingExprModel{Node: m}) + *self.model = unsafe { *(*ExprModel)(&model) } + ret + } + self.data.boundary.pushVar(var, m.Index.Model) + } + } + + fn anonFunc(self, mut m: &AnonFnExprModel) { + self.scope(m.Func.Scope) + } + + fn mapExpr(self, mut m: &MapExprModel) { + for (_, mut pair) in m.Entries { + exprOptimizer.optimizeData(pair.Key, self.data) + exprOptimizer.optimizeData(pair.Val, self.data) + } + } + + fn slicing(self, mut m: &SlicingExprModel) { + exprOptimizer.optimizeData(m.Expr, self.data) + exprOptimizer.optimizeData(m.Left, self.data) + if m.Right != nil { + exprOptimizer.optimizeData(m.Right, self.data) + } + } + + fn traitSub(self, mut m: &TraitSubIdentExprModel) { + exprOptimizer.optimizeData(m.Expr, self.data) + } + + fn structureSub(self, mut m: &StructSubIdentExprModel) { + exprOptimizer.optimizeData(m.Expr.Model, self.data) + } + + fn tuple(self, mut m: &TupleExprModel) { + for (_, mut d) in m.Datas { + exprOptimizer.optimizeData(d.Model, self.data) + } + } + + fn newCall(self, mut m: &BuiltinNewCallExprModel) { + if m.Init != nil { + exprOptimizer.optimizeData(m.Init, self.data) + } + } + + fn outCall(self, mut m: &BuiltinOutCallExprModel) { + exprOptimizer.optimizeData(m.Expr, self.data) + } + + fn outlnCall(self, mut m: &BuiltinOutlnCallExprModel) { + exprOptimizer.optimizeData(m.Expr, self.data) + } + + fn panicCall(self, mut m: &BuiltinPanicCallExprModel) { + exprOptimizer.optimizeData(m.Expr, self.data) + } + + fn assertCall(self, mut m: &BuiltinAssertCallExprModel) { + exprOptimizer.optimizeData(m.Expr, self.data) + } + + fn errorCall(self, mut m: &BuiltinErrorCallExprModel) { + exprOptimizer.optimizeData(m.Err.Model, self.data) + } + + fn makeCall(self, mut m: &BuiltinMakeCallExprModel) { + if m.Len != nil { + exprOptimizer.optimizeData(m.Len, self.data) + } + if m.Cap != nil { + exprOptimizer.optimizeData(m.Cap, self.data) + } + } + + fn appendCall(self, mut m: &BuiltinAppendCallExprModel) { + exprOptimizer.optimizeData(m.Dest, self.data) + exprOptimizer.optimizeData(m.Elements, self.data) + } + + fn lenCall(self, mut m: &BuiltinLenCallExprModel) { + exprOptimizer.optimizeData(m.Expr.Model, self.data) + } + + fn capCall(self, mut m: &BuiltinCapCallExprModel) { + exprOptimizer.optimizeData(m.Expr.Model, self.data) + } + + fn deleteCall(self, mut m: &BuiltinDeleteCallExprModel) { + exprOptimizer.optimizeData(m.Dest.Model, self.data) + if m.Key != nil { + exprOptimizer.optimizeData(m.Key.Model, self.data) + } + } + + fn sizeof(self, mut m: &SizeofExprModel) { + exprOptimizer.optimizeData(m.Expr, self.data) + } + + fn alignof(self, mut m: &AlignofExprModel) { + exprOptimizer.optimizeData(m.Expr, self.data) + } + + fn integratedToStr(self, mut m: &IntegratedToStrExprModel) { + exprOptimizer.optimizeData(m.Expr, self.data) + } + + fn free(self, mut m: &FreeExprModel) { + exprOptimizer.optimizeData(m.Expr, self.data) + } + + fn backendEmit(self, mut m: &BackendEmitExprModel) { + self.args(nil, m.Exprs) + } + + fn do(self) { + match type *self.model { + | &BinaryExprModel: + self.binary((&BinaryExprModel)(*self.model)) + | &UnaryExprModel: + self.unary((&UnaryExprModel)(*self.model)) + | &StructLitExprModel: + self.structureLit((&StructLitExprModel)(*self.model)) + | &AllocStructLitExprModel: + self.allocStructure((&AllocStructLitExprModel)(*self.model)) + | &CastingExprModel: + self.casting((&CastingExprModel)(*self.model)) + | &FnCallExprModel: + self.funcCall((&FnCallExprModel)(*self.model)) + | &SliceExprModel: + self.slice((&SliceExprModel)(*self.model)) + | &ArrayExprModel: + self.array((&ArrayExprModel)(*self.model)) + | &IndexingExprModel: + self.indexing((&IndexingExprModel)(*self.model)) + | &AnonFnExprModel: + self.anonFunc((&AnonFnExprModel)(*self.model)) + | &MapExprModel: + self.mapExpr((&MapExprModel)(*self.model)) + | &SlicingExprModel: + self.slicing((&SlicingExprModel)(*self.model)) + | &TraitSubIdentExprModel: + self.traitSub((&TraitSubIdentExprModel)(*self.model)) + | &StructSubIdentExprModel: + self.structureSub((&StructSubIdentExprModel)(*self.model)) + | &TupleExprModel: + self.tuple((&TupleExprModel)(*self.model)) + | &BuiltinOutCallExprModel: + self.outCall((&BuiltinOutCallExprModel)(*self.model)) + | &BuiltinOutlnCallExprModel: + self.outlnCall((&BuiltinOutlnCallExprModel)(*self.model)) + | &BuiltinNewCallExprModel: + self.newCall((&BuiltinNewCallExprModel)(*self.model)) + | &BuiltinPanicCallExprModel: + self.panicCall((&BuiltinPanicCallExprModel)(*self.model)) + | &BuiltinAssertCallExprModel: + self.assertCall((&BuiltinAssertCallExprModel)(*self.model)) + | &BuiltinErrorCallExprModel: + self.errorCall((&BuiltinErrorCallExprModel)(*self.model)) + | &BuiltinMakeCallExprModel: + self.makeCall((&BuiltinMakeCallExprModel)(*self.model)) + | &BuiltinAppendCallExprModel: + self.appendCall((&BuiltinAppendCallExprModel)(*self.model)) + | &BuiltinLenCallExprModel: + self.lenCall((&BuiltinLenCallExprModel)(*self.model)) + | &BuiltinCapCallExprModel: + self.capCall((&BuiltinCapCallExprModel)(*self.model)) + | &BuiltinDeleteCallExprModel: + self.deleteCall((&BuiltinDeleteCallExprModel)(*self.model)) + | &SizeofExprModel: + self.sizeof((&SizeofExprModel)(*self.model)) + | &AlignofExprModel: + self.alignof((&AlignofExprModel)(*self.model)) + | &IntegratedToStrExprModel: + self.integratedToStr((&IntegratedToStrExprModel)(*self.model)) + | &FreeExprModel: + self.free((&FreeExprModel)(*self.model)) + | &BackendEmitExprModel: + self.backendEmit((&BackendEmitExprModel)(*self.model)) + } + } } // Checks for bit-shifting optimizations. @@ -777,58 +777,58 @@ impl exprOptimizer { // As a result: returns whether bit-shifting is possible and what nth power of 2^r. // Assumes the model r is constant. fn checkForBitShiftOpt(&l: &OperandExprModel, &r: &OperandExprModel): (ok: bool, x: u64) { - if !types::IsInt(l.Kind.Str()) || !types::IsInt(r.Kind.Str()) { - ret false, 0 - } - x = (&Const)(r.Model).AsU64() - if x == 0 || x%2 != 0 { - ret false, 0 - } - j := math::Log2(f64(x)) - z := u64(j) - if f64(z) != j { - ret false, 0 - } - ret true, z + if !types::IsInt(l.Kind.Str()) || !types::IsInt(r.Kind.Str()) { + ret false, 0 + } + x = (&Const)(r.Model).AsU64() + if x == 0 || x%2 != 0 { + ret false, 0 + } + j := math::Log2(f64(x)) + z := u64(j) + if f64(z) != j { + ret false, 0 + } + ret true, z } // Reports l and r the same lvalue expression. fn areSameLvalueExprModel(&l: ExprModel, &r: ExprModel): bool { - match type l { - | &Var: - // Compare values directly. - // If the l and r have same pointers, means same variable. - ret l == r - | &StructSubIdentExprModel: - match type r { - | &StructSubIdentExprModel: - break - |: - ret false - } - lsi := (&StructSubIdentExprModel)(l) - rsi := (&StructSubIdentExprModel)(r) - // Compare fields directly. - // If the l and r have same pointers, - // means same variable of same struct instance. - if lsi.Field != rsi.Field { - ret false - } - // Check head expressions used for field access. - ret areSameLvalueExprModel(lsi.Expr.Model, rsi.Expr.Model) - | &UnaryExprModel: - match type r { - | &UnaryExprModel: - ul := (&UnaryExprModel)(l) - ur := (&UnaryExprModel)(r) - // Unary operators should have the same operator. - // The operator does not matter. - if ul.Op.Id != ur.Op.Id || ul.Op.Kind != ur.Op.Kind { - ret false - } - // Check expressions used for unary. - ret areSameLvalueExprModel(ul.Expr.Model, ur.Expr.Model) - } - } - ret false + match type l { + | &Var: + // Compare values directly. + // If the l and r have same pointers, means same variable. + ret l == r + | &StructSubIdentExprModel: + match type r { + | &StructSubIdentExprModel: + break + |: + ret false + } + lsi := (&StructSubIdentExprModel)(l) + rsi := (&StructSubIdentExprModel)(r) + // Compare fields directly. + // If the l and r have same pointers, + // means same variable of same struct instance. + if lsi.Field != rsi.Field { + ret false + } + // Check head expressions used for field access. + ret areSameLvalueExprModel(lsi.Expr.Model, rsi.Expr.Model) + | &UnaryExprModel: + match type r { + | &UnaryExprModel: + ul := (&UnaryExprModel)(l) + ur := (&UnaryExprModel)(r) + // Unary operators should have the same operator. + // The operator does not matter. + if ul.Op.Id != ur.Op.Id || ul.Op.Kind != ur.Op.Kind { + ret false + } + // Check expressions used for unary. + ret areSameLvalueExprModel(ul.Expr.Model, ur.Expr.Model) + } + } + ret false } \ No newline at end of file diff --git a/src/julec/opt/flag.jule b/src/julec/opt/flag.jule index 082b7dca9..993ae1a67 100644 --- a/src/julec/opt/flag.jule +++ b/src/julec/opt/flag.jule @@ -4,13 +4,13 @@ // JuleC optimization levels. enum OptLevel { - // No optimization. - L0, + // No optimization. + L0, - // Passed flags: - // Copy, Deadcode, Append, Math, Access, Inline, Ptr, - // Cond, Str, Slice, Assign, Exceptional, Iter, Dynamic - L1, + // Passed flags: + // Copy, Deadcode, Append, Math, Access, Inline, Ptr, + // Cond, Str, Slice, Assign, Exceptional, Iter, Dynamic + L1, } static mut Copy = false @@ -30,20 +30,20 @@ static mut Dynamic = false // Pushes optimization flags related with optimization level. fn PushOptLevel(level: OptLevel) { - l1 := level >= OptLevel.L1 + l1 := level >= OptLevel.L1 - Copy = l1 - Deadcode = l1 - Append = l1 - Math = l1 - Access = l1 - Inline = l1 - Ptr = l1 - Cond = l1 - Str = l1 - Slice = l1 - Assign = l1 - Exceptional = l1 - Iter = l1 - Dynamic = l1 + Copy = l1 + Deadcode = l1 + Append = l1 + Math = l1 + Access = l1 + Inline = l1 + Ptr = l1 + Cond = l1 + Str = l1 + Slice = l1 + Assign = l1 + Exceptional = l1 + Iter = l1 + Dynamic = l1 } \ No newline at end of file diff --git a/src/julec/opt/model.jule b/src/julec/opt/model.jule index 4937e2a6e..6ee42c2f0 100644 --- a/src/julec/opt/model.jule +++ b/src/julec/opt/model.jule @@ -5,78 +5,78 @@ use std::jule::lex::{Token} use std::jule::constant::{Const} use std::jule::sema::{ - Data, - Var, - TypeKind, - ExprModel, - BinaryExprModel, - IndexingExprModel, - BuiltinAppendCallExprModel, - SliceExprModel, - FnCallExprModel, - RangeIter, - UnaryExprModel, - CastingExprModel, + Data, + Var, + TypeKind, + ExprModel, + BinaryExprModel, + IndexingExprModel, + BuiltinAppendCallExprModel, + SliceExprModel, + FnCallExprModel, + RangeIter, + UnaryExprModel, + CastingExprModel, } struct ExceptionalForwardingExprModel { - Expr: &FnCallExprModel + Expr: &FnCallExprModel } struct SwapExprModel { - Left: &Data - Right: &Data + Left: &Data + Right: &Data } struct EmptyCompareExprModel { - Expr: ExprModel - Neg: bool + Expr: ExprModel + Neg: bool } struct RefExprModel { - Var: &Var + Var: &Var } struct StrCompExprModel { - Left: ExprModel - Right: &Const - NotEq: bool + Left: ExprModel + Right: &Const + NotEq: bool } struct MutSlicingExprModel { - Token: &Token - Expr: ExprModel - Left: ExprModel - Right: ExprModel + Token: &Token + Expr: ExprModel + Left: ExprModel + Right: ExprModel } struct UnsafeBinaryExprModel { - Node: &BinaryExprModel + Node: &BinaryExprModel } struct UnsafeIndexingExprModel { - Node: &IndexingExprModel + Node: &IndexingExprModel } struct PushToSliceExprModel { - Dest: ExprModel - Elems: &SliceExprModel + Dest: ExprModel + Elems: &SliceExprModel } struct AppendToSliceExprModel { - Dest: ExprModel - Slice: ExprModel + Dest: ExprModel + Slice: ExprModel } struct StrRuneIter { - Expr: &Data - Base: &RangeIter + Expr: &Data + Base: &RangeIter } struct UnsafeDerefExprModel { - Base: &UnaryExprModel + Base: &UnaryExprModel } struct UnsafeCastingExprModel { - Base: &CastingExprModel + Base: &CastingExprModel } \ No newline at end of file diff --git a/src/julec/opt/nil.jule b/src/julec/opt/nil.jule index 218770afc..d86232a58 100644 --- a/src/julec/opt/nil.jule +++ b/src/julec/opt/nil.jule @@ -4,109 +4,109 @@ use std::jule::lex::{TokenId} use std::jule::sema::{ - Var, - TypeKind, - ExprModel, - StructSubIdentExprModel, - BuiltinNewCallExprModel, + Var, + TypeKind, + ExprModel, + StructSubIdentExprModel, + BuiltinNewCallExprModel, } const invalidNil = uintptr(0x0) struct nilVar { - var: uintptr - safe: bool + var: uintptr + safe: bool } // Information wrapper for nil analysis. struct nils { - vars: []nilVar + vars: []nilVar } impl nils { - // Appends variable with initial safety state. - // If variable is already exist, updates safety information. - fn pushVar(mut self, var: uintptr, safe: bool) { - if !Access || var == invalidNil { - // Ignore it, because this optimizations within scope of the --opt-access flag. - ret - } - for (_, mut v) in self.vars { - if v.var == var { - v.safe = safe - ret - } - } - // Not exist, append new one. - for (_, mut v) in self.vars { - if v.var == invalidNil { - // Empty place, use here instead of append. - v.var = var - v.safe = safe - ret - } - } - self.vars = append(self.vars, nilVar{var: var, safe: safe}) - } + // Appends variable with initial safety state. + // If variable is already exist, updates safety information. + fn pushVar(mut self, var: uintptr, safe: bool) { + if !Access || var == invalidNil { + // Ignore it, because this optimizations within scope of the --opt-access flag. + ret + } + for (_, mut v) in self.vars { + if v.var == var { + v.safe = safe + ret + } + } + // Not exist, append new one. + for (_, mut v) in self.vars { + if v.var == invalidNil { + // Empty place, use here instead of append. + v.var = var + v.safe = safe + ret + } + } + self.vars = append(self.vars, nilVar{var: var, safe: safe}) + } - fn removeVar(mut self, var: uintptr): bool { - if var != invalidNil { - for (_, mut v) in self.vars { - if v.var == var { - v.var = invalidNil - v.safe = false - ret true - } - } - } - ret false - } + fn removeVar(mut self, var: uintptr): bool { + if var != invalidNil { + for (_, mut v) in self.vars { + if v.var == var { + v.var = invalidNil + v.safe = false + ret true + } + } + } + ret false + } - // Reports whether variable is safe. - fn isSafe(mut self, var: uintptr): bool { - if var != invalidNil { - for _, v in self.vars { - if v.var == var { - ret v.safe - } - } - } - ret false - } + // Reports whether variable is safe. + fn isSafe(mut self, var: uintptr): bool { + if var != invalidNil { + for _, v in self.vars { + if v.var == var { + ret v.safe + } + } + } + ret false + } } fn possibleNilRemove(mut &n: &nils, m: ExprModel) { - if n != nil { - _ = n.removeVar(getNilVar(m)) - } + if n != nil { + _ = n.removeVar(getNilVar(m)) + } } fn isGuaranteedNonNilExpr(mut &n: &nils, m: ExprModel): bool { - match type m { - | &BuiltinNewCallExprModel: - ret true - } - ret n != nil && n.isSafe(getNilVar(m)) + match type m { + | &BuiltinNewCallExprModel: + ret true + } + ret n != nil && n.isSafe(getNilVar(m)) } fn isNilValidType(mut t: &TypeKind): bool { ret t.Sptr() != nil } fn getNilVar(m: ExprModel): uintptr { - if !Access { - ret invalidBoundary - } - match type m { - | &Var: - v := (&Var)(m) - if !v.Reference { - // Variable is not reference, return address of it. - ret uintptr((&Var)(m)) - } - // Variable is reference, it should be initialized at source code. - // Investigate the initial expression for variable address. - ret getNilVar(v.Value.Data.Model) - | &StructSubIdentExprModel: - ret uintptr((&StructSubIdentExprModel)(m).Field) - } - ret invalidBoundary + if !Access { + ret invalidBoundary + } + match type m { + | &Var: + v := (&Var)(m) + if !v.Reference { + // Variable is not reference, return address of it. + ret uintptr((&Var)(m)) + } + // Variable is reference, it should be initialized at source code. + // Investigate the initial expression for variable address. + ret getNilVar(v.Value.Data.Model) + | &StructSubIdentExprModel: + ret uintptr((&StructSubIdentExprModel)(m).Field) + } + ret invalidBoundary } \ No newline at end of file diff --git a/src/julec/opt/optimizer.jule b/src/julec/opt/optimizer.jule index 46669c4a0..b3090cafe 100644 --- a/src/julec/opt/optimizer.jule +++ b/src/julec/opt/optimizer.jule @@ -6,10 +6,10 @@ use env use obj::{IR} use deadcode for opt::deadcode use std::jule::sema::{ - Package, - Var, - Fn, - Struct, + Package, + Var, + Fn, + Struct, } static mut exprEnabled = false @@ -18,106 +18,106 @@ static mut scopeEnabled = false // Target-independent optimizer for IR. // Use this optimizer for all optimizations with single instance. struct Optimizer { - ir: &IR + ir: &IR } impl Optimizer { - // Returns new optimizer for IR. - static fn New(mut &ir: &IR): &Optimizer { - ret &Optimizer{ - ir: ir, - } - } - - fn optimizeGlobal(mut self, mut &v: &Var) { - if !v.Binded { - exprOptimizer.optimize(v.Value.Data.Model) - } - } - - fn optimizeFunction(mut self, mut &func: &Fn) { - if func.Binded { - ret - } - for (_, mut ins) in func.Instances { - mut so := scopeOptimizer.new(ins.Scope) - so.optimize() - } - } - - fn optimizeStruct(mut self, mut &s: &Struct) { - if s.Binded { - ret - } - for (_, mut ins) in s.Instances { - for (_, mut f) in ins.Fields { - if f.Default != nil { - exprOptimizer.optimize(f.Default.Model) - } - } - for (_, mut m) in ins.Methods { - self.optimizeFunction(m) - } - } - } - - fn optimizeGlobals(mut self, mut &p: &Package) { - for (_, mut f) in p.Files { - for (_, mut v) in f.Vars { - self.optimizeGlobal(v) - } - } - } - - fn optimizeFunctions(mut self, mut &p: &Package) { - for (_, mut f) in p.Files { - for (_, mut func) in f.Funcs { - self.optimizeFunction(func) - } - } - } - - fn optimizeStructs(mut self, mut &p: &Package) { - for (_, mut f) in p.Files { - for (_, mut s) in f.Structs { - self.optimizeStruct(s) - } - } - } - - fn optimizePackage(mut self, mut &p: &Package) { - self.optimizeGlobals(p) - self.optimizeFunctions(p) - self.optimizeStructs(p) - } - - // Optimizes IR by enabled optimizations. - fn Optimize(mut self) { - detectEnabled() - - // See compiler reference (2) - if Deadcode { - deadcode::EliminateDefines(self.ir) - } - - if scopeEnabled || exprEnabled { - for (_, mut u) in self.ir.Used { - if !u.Binded { - self.optimizePackage(u.Package) - } - } - self.optimizePackage(self.ir.Main) - } - - // See compiler reference (3) - if Deadcode { - deadcode::EliminateScopes(self.ir) - } - } + // Returns new optimizer for IR. + static fn New(mut &ir: &IR): &Optimizer { + ret &Optimizer{ + ir: ir, + } + } + + fn optimizeGlobal(mut self, mut &v: &Var) { + if !v.Binded { + exprOptimizer.optimize(v.Value.Data.Model) + } + } + + fn optimizeFunction(mut self, mut &func: &Fn) { + if func.Binded { + ret + } + for (_, mut ins) in func.Instances { + mut so := scopeOptimizer.new(ins.Scope) + so.optimize() + } + } + + fn optimizeStruct(mut self, mut &s: &Struct) { + if s.Binded { + ret + } + for (_, mut ins) in s.Instances { + for (_, mut f) in ins.Fields { + if f.Default != nil { + exprOptimizer.optimize(f.Default.Model) + } + } + for (_, mut m) in ins.Methods { + self.optimizeFunction(m) + } + } + } + + fn optimizeGlobals(mut self, mut &p: &Package) { + for (_, mut f) in p.Files { + for (_, mut v) in f.Vars { + self.optimizeGlobal(v) + } + } + } + + fn optimizeFunctions(mut self, mut &p: &Package) { + for (_, mut f) in p.Files { + for (_, mut func) in f.Funcs { + self.optimizeFunction(func) + } + } + } + + fn optimizeStructs(mut self, mut &p: &Package) { + for (_, mut f) in p.Files { + for (_, mut s) in f.Structs { + self.optimizeStruct(s) + } + } + } + + fn optimizePackage(mut self, mut &p: &Package) { + self.optimizeGlobals(p) + self.optimizeFunctions(p) + self.optimizeStructs(p) + } + + // Optimizes IR by enabled optimizations. + fn Optimize(mut self) { + detectEnabled() + + // See compiler reference (2) + if Deadcode { + deadcode::EliminateDefines(self.ir) + } + + if scopeEnabled || exprEnabled { + for (_, mut u) in self.ir.Used { + if !u.Binded { + self.optimizePackage(u.Package) + } + } + self.optimizePackage(self.ir.Main) + } + + // See compiler reference (3) + if Deadcode { + deadcode::EliminateScopes(self.ir) + } + } } fn detectEnabled() { - exprEnabled = Ptr || Math || Access || Cond - scopeEnabled = Cond || Append || Copy || Str || Slice || Assign || Exceptional || - Iter || Dynamic + exprEnabled = Ptr || Math || Access || Cond + scopeEnabled = Cond || Append || Copy || Str || Slice || Assign || Exceptional || + Iter || Dynamic } \ No newline at end of file diff --git a/src/julec/opt/scope.jule b/src/julec/opt/scope.jule index 12e690e09..244c7040c 100644 --- a/src/julec/opt/scope.jule +++ b/src/julec/opt/scope.jule @@ -9,714 +9,714 @@ use std::jule::build::{PathStdlib} use std::jule::constant::{Const} use std::jule::lex::{TokenId, TokenKind} use sema for std::jule::sema::{ - Var, - Data, - Scope, - Stmt, - ExprModel, - FnCallExprModel, - Conditional, - CastingExprModel, - If, - Else, - Case, - Match, - RangeIter, - WhileIter, - InfIter, - MultiAssign, - RetSt, - BinaryExprModel, - OperandExprModel, - BuiltinAppendCallExprModel, - SliceExprModel, - StructSubIdentExprModel, - SlicingExprModel, - FallSt, - TupleExprModel, - BuiltinErrorCallExprModel, - Postfix, + Var, + Data, + Scope, + Stmt, + ExprModel, + FnCallExprModel, + Conditional, + CastingExprModel, + If, + Else, + Case, + Match, + RangeIter, + WhileIter, + InfIter, + MultiAssign, + RetSt, + BinaryExprModel, + OperandExprModel, + BuiltinAppendCallExprModel, + SliceExprModel, + StructSubIdentExprModel, + SlicingExprModel, + FallSt, + TupleExprModel, + BuiltinErrorCallExprModel, + Postfix, } use strings for std::strings // Scope optimizer that applies target-independent optimizations. struct scopeOptimizer { - parent: &scopeOptimizer - i: int - scope: &Scope - data: &data // Should be non-nil guaranteed. + parent: &scopeOptimizer + i: int + scope: &Scope + data: &data // Should be non-nil guaranteed. } impl scopeOptimizer { - static fn new(mut scope: &Scope): &scopeOptimizer { - mut sc := &scopeOptimizer{ - scope: scope, - data: &data{ - boundary: new(boundary), - nils: new(nils), - dynamic: new(dynamic), - }, - } - ret sc - } - - fn setCurrentStmt(mut &self, mut stmt: any) { - self.scope.Stmts[self.i] = unsafe { *(*Stmt)(&stmt) } - } - - // Removes current statement. - fn removeCurrent(mut &self) { - self.scope.Stmts = append(self.scope.Stmts[:self.i], self.scope.Stmts[self.i+1:]...) - } - - fn isLastStmt(mut &self): bool { - mut r := self - for r != nil; r = r.parent { - if len(r.scope.Stmts)-r.i != 1 { - ret false - } - } - ret true - } - - fn isIter(mut &self): bool { - mut r := self.parent - for r != nil; r = r.parent { - match type r.scope.Stmts[r.i] { - | &RangeIter - | &WhileIter - | &InfIter: - ret true - } - } - ret false - } - - fn optimizeData(mut &self, mut d: &Data) { - match type d.Model { - | &FnCallExprModel: - mut m := (&FnCallExprModel)(d.Model) - if env::Production { - if !m.Func.IsBuiltin() && - obj::IsStdPackage(m.Func.Decl.Token.File.Path, "debug") { - self.setCurrentStmt(nil) - ret - } - } - exprOptimizer.optimizeData(d.Model, self.data) - if Exceptional && - m.Func.Decl.Exceptional && - m.Except != nil && - len(m.Except.Stmts) == 1 && - obj::IsForwarded(m.Except) && - self.isLastStmt() && - !self.isIter() { - self.setCurrentStmt(&ExceptionalForwardingExprModel{Expr: m}) - } - ret - } - exprOptimizer.optimizeData(d.Model, self.data) - } - - fn optimizeVar(mut &self, mut v: &Var) { - if v.Value != nil { - if self.data.nils != nil && - isNilValidType(v.Kind.Kind) && - isGuaranteedNonNilExpr(self.data.nils, v.Value.Data.Model) { - const safe = true - self.data.nils.pushVar(getNilVar(v), safe) - } - if self.data.dynamic != nil { - mut kind := isTypeGuaranteedDynamicData( - self.data.dynamic, v.Kind.Kind, v.Value.Data.Model) - if kind != nil { - if isDynamicValidType(v.Kind.Kind) { - self.data.dynamic.pushVar(getDynamicVar(v), kind) - } - } - } - exprOptimizer.optimizeData(v.Value.Data.Model, self.data) - } - } - - fn optimizeConditional(mut &self, mut c: &Conditional) { - mut checkpoint := self.data.getCheckpoint() - for (_, mut elif) in c.Elifs { - exprOptimizer.optimizeData(elif.Expr, self.data) - self.optimizeChild(elif.Scope) - if len(c.Elifs) > 1 || c.Default != nil { - self.data.loadCheckpoint(checkpoint) - } - } - if c.Default != nil { - self.optimizeChild(c.Default.Scope) - self.data.loadCheckpoint(checkpoint) - } - - if !Cond { - ret - } - - mut constCase := false // Has cosntant true case. - - // Remove unnecessary trailing cases that comes after constant true case. - for (i, mut elif) in c.Elifs { - if !isConstantValidConditionalCase(elif) { - continue - } - constCase = true - c.Elifs = c.Elifs[:i] - c.Default = &Else{ - Scope: elif.Scope, - } - break - } - - if len(c.Elifs) == 0 { - ret - } - - // Remove unreachable cases. - mut i := &c.Elifs[0] - end := &c.Elifs[len(c.Elifs)-1] - for i <= end; i++ { - unsafe { - if isUnreachableConditionalCase(*i) { - *i = nil - } - } - } - - if len(c.Elifs) == 0 { - ret - } - - // Skip one-case checking if const-case is not exist. - if !constCase { - ret - } - - mut only := -1 - for j, elif in c.Elifs { - if elif != nil { - if only != -1 { - // Break checking, there is more than one case. - ret - } - only = j - } - } - - // Here is one case. - if only != -1 { - self.setCurrentStmt(c.Elifs[only].Scope) - } - } - - fn buildDefaultConstantTrueCase(mut &self, mut case: &Case, mut &i: int, mut &m: &Match) { - case.Exprs = nil // Remove expressions to remove eval overhead. - start := i - loop: - for { - if len(case.Scope.Stmts) == 0 { - break - } - mut &stmt := unsafe { *(&case.Scope.Stmts[len(case.Scope.Stmts)-1]) } - match type stmt { - | &FallSt: - i++ - if i >= len(m.Cases) { - stmt = m.Default.Scope - break loop - } - case = m.Cases[i] - stmt = case.Scope - |: - break loop - } - } - m.Default = m.Cases[start] - m.Cases = m.Cases[:start] - } - - fn optimizeMatch(mut &self, mut m: &Match) { - mut var := invalidDynamic - if Dynamic && m.TypeMatch { - var = getDynamicVar(m.Expr.Model) - } - mut checkpoint := self.data.getCheckpoint() - for (_, mut case) in m.Cases { - for (_, mut expr) in case.Exprs { - exprOptimizer.optimizeData(expr.Model, self.data) - } - if len(case.Exprs) == 1 && self.data.dynamic != nil { - // We can know the exact kind of dynamic type if expression is single. - mut kind := isTypeGuaranteedDynamicData(self.data.dynamic, case.Exprs[0].Kind, nil) - if kind != nil { - self.data.dynamic.pushVar(var, kind) - } else { - self.data.dynamic.removeVar(var) - } - } - self.optimizeChild(case.Scope) - if len(m.Cases) > 1 || m.Default != nil { - self.data.loadCheckpoint(checkpoint) - } - } - if m.Default != nil { - self.optimizeChild(m.Default.Scope) - self.data.loadCheckpoint(checkpoint) - } - - if !Cond { - ret - } - - mut constCase := false // Has cosntant true case. - - // Remove unnecessary trailing cases that comes after constant true case. - for (mut i, mut case) in m.Cases { - if !isConstantValidMatchCase(case) { - continue - } - constCase = true - self.buildDefaultConstantTrueCase(case, i, m) - break - } - - if len(m.Cases) == 0 { - ret - } - - // Remove unreachable cases. - mut i := &m.Cases[0] - end := &m.Cases[len(m.Cases)-1] - for i <= end; i++ { - unsafe { - if isUnreachableMatchCase(*i) { - *i = nil - } - } - } - - // Skip one-case checking if const-case is not exist. - if !constCase { - ret - } - - mut only := -1 - for j, case in m.Cases { - if case != nil { - if only != -1 { - // Break checking, there is more than one case. - ret - } - only = j - } - } - - // Here is one case. - if only != -1 { - self.setCurrentStmt(m.Cases[only].Scope) - } - } - - fn optimizeRangeIter(mut &self, mut it: &RangeIter) { - // Optimize scope first, following alrgorithms related with expression. - // It might be skip this, so scope optimizater should be guaranteed to run. - if self.data.boundary != nil && it.KeyA != nil { - // Add index variable to boundary analysis. - self.data.boundary.pushVar(getBoundaryVar(it.Expr.Model), it.KeyA) - } - self.optimizeChild(it.Scope) - - if Iter { - match type it.Expr.Model { - | &CastingExprModel: - mut cem := (&CastingExprModel)(it.Expr.Model) - eprim := cem.ExprKind.Prim() - if eprim == nil || !eprim.IsStr() { - break - } - mut s := cem.Kind.Slc() - if s == nil { - break - } - prim := s.Elem.Prim() - if prim == nil { - break - } - match { - | prim.IsU8(): - // Expression is: []byte(str) - // Use string expression directly, byte casting is unnecessary. - it.Expr = cem.Expr - | prim.IsI32(): - // Expression is: []rune(str) - // Avoid making allocation, iterate runes of string. - exprOptimizer.optimizeData(cem.Expr.Model, self.data) // Optimize string expression. - self.setCurrentStmt(&StrRuneIter{ - Expr: cem.Expr, - Base: it, - }) - ret - } - } - } - exprOptimizer.optimizeData(it.Expr.Model, self.data) - } - - fn optimizeWhileIter(mut &self, mut it: &WhileIter) { - exprOptimizer.optimizeData(it.Expr, self.data) - self.optimizeStmt(it.Next) - self.optimizeChild(it.Scope) - } - - fn substr(mut &self, mut a: &sema::Assign): bool { - if a.Op.Id != TokenId.Eq { - ret false - } - match type a.Right.Model { - | &SlicingExprModel: - mut sem := (&SlicingExprModel)(a.Right.Model) - if equalModels(a.Left.Model, sem.Expr) { - self.setCurrentStmt(&MutSlicingExprModel{ - Token: sem.Token, - Expr: sem.Expr, - Left: sem.Left, - Right: sem.Right, - }) - ret true - } - } - ret false - } - - fn strAssign(mut &self, mut a: &sema::Assign): bool { - if !Str { - ret false - } - lp := a.Left.Kind.Prim() - if lp == nil || !lp.IsStr() { - ret false - } - ret self.substr(a) - } - - fn sliceAssign(mut &self, mut a: &sema::Assign): bool { - if !Slice || a.Left.Kind.Slc() == nil { - ret false - } - // [self.substr] applies this optimization without type dependence. - ret self.substr(a) - } - - fn optimizePostfix(mut &self, mut postfix: &Postfix) { - if self.data.boundary != nil { - possibleBoundaryRemove(self.data.boundary, postfix.Expr) - } - exprOptimizer.optimizeData(postfix.Expr, self.data) - } - - fn optimizeAssign(mut &self, mut assign: &sema::Assign) { - if assign.Op.Id == TokenId.Eq && - equalModels(assign.Left.Model, assign.Right.Model) { - self.removeCurrent() - self.i-- // In next iteration, point to correct statement. - ret - } - - if self.data.boundary != nil { - if isBoundaryRiskyType(assign.Left.Kind) { - possibleBoundaryRemove(self.data.boundary, assign.Left.Model) - } - } - if self.data.nils != nil { - if isGuaranteedNonNilExpr(self.data.nils, assign.Right.Model) { - if isNilValidType(assign.Left.Kind) { - const safe = true - self.data.nils.pushVar(getNilVar(assign.Left.Model), safe) - } - } else { - possibleNilRemove(self.data.nils, assign.Left.Model) - } - } - if self.data.dynamic != nil { - mut kind := isTypeGuaranteedDynamicData( - self.data.dynamic, assign.Right.Kind, assign.Right.Model) - if kind != nil { - if isDynamicValidType(assign.Left.Kind) { - self.data.dynamic.pushVar(getDynamicVar(assign.Left.Model), kind) - } - } else { - possibleDynamicRemove(self.data.dynamic, assign.Left.Model) - } - } - - match { - | self.strAssign(assign) - | self.sliceAssign(assign): - ret - } - - exprOptimizer.optimizeData(assign.Left.Model, self.data) - exprOptimizer.optimizeData(assign.Right.Model, self.data) - - match assign.Op.Id { - | TokenId.SolidusEq | TokenId.PercentEq: - // Do not check division of structures safety. - if !Math || assign.Left.Kind.Struct() != nil { - break - } - oldId, oldKind := assign.Op.Id, assign.Op.Kind - match assign.Op.Id { - | TokenId.SolidusEq: - assign.Op.Id = TokenId.Solidus - assign.Op.Kind = TokenKind.Solidus - | TokenId.PercentEq: - assign.Op.Id = TokenId.Percent - assign.Op.Kind = TokenKind.Percent - |: - panic("implementation mistake, this panic call should be unreachable") - } - mut model := ExprModel(&BinaryExprModel{ - Op: assign.Op, - Left: assign.Left, - Right: assign.Right, - }) - exprOptimizer.optimizeData(model, self.data) - match type model { - | &BinaryExprModel: - assign.Right = new(OperandExprModel, *assign.Right) - assign.Op.Id = TokenId.Eq - assign.Op.Kind = TokenKind.Eq - assign.Right.Model = model - ret - } - assign.Op.Id = oldId - assign.Op.Kind = oldKind - ret - } - - if Append { - match type assign.Right.Model { - | &BuiltinAppendCallExprModel: - mut m := (&BuiltinAppendCallExprModel)(assign.Right.Model) - if !areSameLvalueExprModel(assign.Left.Model, m.Dest) { - ret - } - match type m.Elements { - | &SliceExprModel: - // Push items one-by-one for self-appended memory. - self.setCurrentStmt(&PushToSliceExprModel{ - Dest: m.Dest, - Elems: (&SliceExprModel)(m.Elements), - }) - |: - // Append directly if appended to slice and assigned to the same memory. - self.setCurrentStmt(&AppendToSliceExprModel{ - Dest: assign.Left.Model, - Slice: m.Elements, - }) - } - } - } - } - - fn tryOptimizeSwap(mut &self, mut &assign: &MultiAssign): bool { - if !Assign || len(assign.Left) != 2 || - assign.Left[0] == nil || assign.Left[1] == nil { - ret false - } - let mut tup: &TupleExprModel - match type assign.Right { - | &TupleExprModel: - tup = (&TupleExprModel)(assign.Right) - } - if tup == nil || len(tup.Datas) != 2 { - ret false - } - - // Catch self assignments. - if equalModels(assign.Left[0].Model, tup.Datas[0].Model) && - equalModels(assign.Left[1].Model, tup.Datas[1].Model) { - self.removeCurrent() - self.i-- // In next iteration, point to correct statement. - ret true - } - - // Catch swaps. - if !equalModels(assign.Left[0].Model, tup.Datas[1].Model) || - !equalModels(assign.Left[1].Model, tup.Datas[0].Model) { - ret false - } - mut model := &SwapExprModel{ - Left: assign.Left[0], - Right: assign.Left[1], - } - exprOptimizer.optimizeData(model.Left.Model, self.data) - exprOptimizer.optimizeData(model.Right.Model, self.data) - self.setCurrentStmt(model) - ret true - } - - fn optimizeMultiAssign(mut &self, mut assign: &MultiAssign) { - if self.tryOptimizeSwap(assign) { - // Swap operation can skip the following algorithm. - // As far as tested, following analysis are not necessary. - ret - } - - mut tup := (&TupleExprModel)(nil) - match type assign.Right { - | &TupleExprModel: - tup = (&TupleExprModel)(assign.Right) - } - for (i, mut l) in assign.Left { - if l != nil { - if self.data.boundary != nil { - if isBoundaryRiskyType(l.Kind) { - possibleBoundaryRemove(self.data.boundary, l.Model) - } - } - if self.data.nils != nil { - if tup != nil && isGuaranteedNonNilExpr(self.data.nils, tup.Datas[i].Model) { - if isNilValidType(l.Kind) { - const safe = true - self.data.nils.pushVar(getNilVar(l.Model), safe) - } - } else { - possibleNilRemove(self.data.nils, l.Model) - } - } - if self.data.dynamic != nil && tup != nil { - mut kind := isTypeGuaranteedDynamicData( - self.data.dynamic, tup.Datas[i].Kind, tup.Datas[i].Model) - if kind != nil { - if isDynamicValidType(l.Kind) { - self.data.dynamic.pushVar(getDynamicVar(l.Model), kind) - } - } else { - possibleDynamicRemove(self.data.dynamic, l.Model) - } - } - exprOptimizer.optimizeData(l.Model, self.data) - } - } - exprOptimizer.optimizeData(assign.Right, self.data) - } - - fn optimizeRet(mut &self, mut r: &RetSt) { - exprOptimizer.optimizeData(r.Expr, self.data) - - // Break algorithm is exceptional-specific optimizations are not enabled. - // The following algorithms tries to apply specific optimizations for exceptionals. - if !Exceptional { - ret - } - match type r.Expr { - | &FnCallExprModel: - break - |: - ret - } - mut fc := (&FnCallExprModel)(r.Expr) - if !fc.Func.Decl.Exceptional || - fc.Except == nil || - len(fc.Except.Stmts) != 1 || - !obj::IsForwarded(fc.Except) { - ret - } - self.setCurrentStmt(&ExceptionalForwardingExprModel{Expr: fc}) - } - - fn optimizeStmt(mut &self, mut stmt: Stmt) { - match type stmt { - | &Scope: - self.optimizeChild((&Scope)(stmt)) - | &Data: - self.optimizeData((&Data)(stmt)) - | &Var: - self.optimizeVar((&Var)(stmt)) - | &Conditional: - self.optimizeConditional((&Conditional)(stmt)) - | &RangeIter: - self.optimizeRangeIter((&RangeIter)(stmt)) - | &WhileIter: - self.optimizeWhileIter((&WhileIter)(stmt)) - | &InfIter: - self.optimizeChild((&InfIter)(stmt).Scope) - | &sema::Assign: - self.optimizeAssign((&sema::Assign)(stmt)) - | &MultiAssign: - self.optimizeMultiAssign((&MultiAssign)(stmt)) - | &Match: - self.optimizeMatch((&Match)(stmt)) - | &RetSt: - self.optimizeRet((&RetSt)(stmt)) - | &Postfix: - self.optimizePostfix((&Postfix)(stmt)) - } - } - - fn optimizeChild(mut &self, mut child: &Scope) { - mut so := scopeOptimizer.new(child) - so.parent = self - so.data = self.data - so.optimize() - } - - // Optimizes scope by enabled optimizations. - fn optimize(mut &self) { - self.i = 0 - for self.i < len(self.scope.Stmts); self.i++ { - self.optimizeStmt(self.scope.Stmts[self.i]) - } - } + static fn new(mut scope: &Scope): &scopeOptimizer { + mut sc := &scopeOptimizer{ + scope: scope, + data: &data{ + boundary: new(boundary), + nils: new(nils), + dynamic: new(dynamic), + }, + } + ret sc + } + + fn setCurrentStmt(mut &self, mut stmt: any) { + self.scope.Stmts[self.i] = unsafe { *(*Stmt)(&stmt) } + } + + // Removes current statement. + fn removeCurrent(mut &self) { + self.scope.Stmts = append(self.scope.Stmts[:self.i], self.scope.Stmts[self.i+1:]...) + } + + fn isLastStmt(mut &self): bool { + mut r := self + for r != nil; r = r.parent { + if len(r.scope.Stmts)-r.i != 1 { + ret false + } + } + ret true + } + + fn isIter(mut &self): bool { + mut r := self.parent + for r != nil; r = r.parent { + match type r.scope.Stmts[r.i] { + | &RangeIter + | &WhileIter + | &InfIter: + ret true + } + } + ret false + } + + fn optimizeData(mut &self, mut d: &Data) { + match type d.Model { + | &FnCallExprModel: + mut m := (&FnCallExprModel)(d.Model) + if env::Production { + if !m.Func.IsBuiltin() && + obj::IsStdPackage(m.Func.Decl.Token.File.Path, "debug") { + self.setCurrentStmt(nil) + ret + } + } + exprOptimizer.optimizeData(d.Model, self.data) + if Exceptional && + m.Func.Decl.Exceptional && + m.Except != nil && + len(m.Except.Stmts) == 1 && + obj::IsForwarded(m.Except) && + self.isLastStmt() && + !self.isIter() { + self.setCurrentStmt(&ExceptionalForwardingExprModel{Expr: m}) + } + ret + } + exprOptimizer.optimizeData(d.Model, self.data) + } + + fn optimizeVar(mut &self, mut v: &Var) { + if v.Value != nil { + if self.data.nils != nil && + isNilValidType(v.Kind.Kind) && + isGuaranteedNonNilExpr(self.data.nils, v.Value.Data.Model) { + const safe = true + self.data.nils.pushVar(getNilVar(v), safe) + } + if self.data.dynamic != nil { + mut kind := isTypeGuaranteedDynamicData( + self.data.dynamic, v.Kind.Kind, v.Value.Data.Model) + if kind != nil { + if isDynamicValidType(v.Kind.Kind) { + self.data.dynamic.pushVar(getDynamicVar(v), kind) + } + } + } + exprOptimizer.optimizeData(v.Value.Data.Model, self.data) + } + } + + fn optimizeConditional(mut &self, mut c: &Conditional) { + mut checkpoint := self.data.getCheckpoint() + for (_, mut elif) in c.Elifs { + exprOptimizer.optimizeData(elif.Expr, self.data) + self.optimizeChild(elif.Scope) + if len(c.Elifs) > 1 || c.Default != nil { + self.data.loadCheckpoint(checkpoint) + } + } + if c.Default != nil { + self.optimizeChild(c.Default.Scope) + self.data.loadCheckpoint(checkpoint) + } + + if !Cond { + ret + } + + mut constCase := false // Has cosntant true case. + + // Remove unnecessary trailing cases that comes after constant true case. + for (i, mut elif) in c.Elifs { + if !isConstantValidConditionalCase(elif) { + continue + } + constCase = true + c.Elifs = c.Elifs[:i] + c.Default = &Else{ + Scope: elif.Scope, + } + break + } + + if len(c.Elifs) == 0 { + ret + } + + // Remove unreachable cases. + mut i := &c.Elifs[0] + end := &c.Elifs[len(c.Elifs)-1] + for i <= end; i++ { + unsafe { + if isUnreachableConditionalCase(*i) { + *i = nil + } + } + } + + if len(c.Elifs) == 0 { + ret + } + + // Skip one-case checking if const-case is not exist. + if !constCase { + ret + } + + mut only := -1 + for j, elif in c.Elifs { + if elif != nil { + if only != -1 { + // Break checking, there is more than one case. + ret + } + only = j + } + } + + // Here is one case. + if only != -1 { + self.setCurrentStmt(c.Elifs[only].Scope) + } + } + + fn buildDefaultConstantTrueCase(mut &self, mut case: &Case, mut &i: int, mut &m: &Match) { + case.Exprs = nil // Remove expressions to remove eval overhead. + start := i + loop: + for { + if len(case.Scope.Stmts) == 0 { + break + } + mut &stmt := unsafe { *(&case.Scope.Stmts[len(case.Scope.Stmts)-1]) } + match type stmt { + | &FallSt: + i++ + if i >= len(m.Cases) { + stmt = m.Default.Scope + break loop + } + case = m.Cases[i] + stmt = case.Scope + |: + break loop + } + } + m.Default = m.Cases[start] + m.Cases = m.Cases[:start] + } + + fn optimizeMatch(mut &self, mut m: &Match) { + mut var := invalidDynamic + if Dynamic && m.TypeMatch { + var = getDynamicVar(m.Expr.Model) + } + mut checkpoint := self.data.getCheckpoint() + for (_, mut case) in m.Cases { + for (_, mut expr) in case.Exprs { + exprOptimizer.optimizeData(expr.Model, self.data) + } + if len(case.Exprs) == 1 && self.data.dynamic != nil { + // We can know the exact kind of dynamic type if expression is single. + mut kind := isTypeGuaranteedDynamicData(self.data.dynamic, case.Exprs[0].Kind, nil) + if kind != nil { + self.data.dynamic.pushVar(var, kind) + } else { + self.data.dynamic.removeVar(var) + } + } + self.optimizeChild(case.Scope) + if len(m.Cases) > 1 || m.Default != nil { + self.data.loadCheckpoint(checkpoint) + } + } + if m.Default != nil { + self.optimizeChild(m.Default.Scope) + self.data.loadCheckpoint(checkpoint) + } + + if !Cond { + ret + } + + mut constCase := false // Has cosntant true case. + + // Remove unnecessary trailing cases that comes after constant true case. + for (mut i, mut case) in m.Cases { + if !isConstantValidMatchCase(case) { + continue + } + constCase = true + self.buildDefaultConstantTrueCase(case, i, m) + break + } + + if len(m.Cases) == 0 { + ret + } + + // Remove unreachable cases. + mut i := &m.Cases[0] + end := &m.Cases[len(m.Cases)-1] + for i <= end; i++ { + unsafe { + if isUnreachableMatchCase(*i) { + *i = nil + } + } + } + + // Skip one-case checking if const-case is not exist. + if !constCase { + ret + } + + mut only := -1 + for j, case in m.Cases { + if case != nil { + if only != -1 { + // Break checking, there is more than one case. + ret + } + only = j + } + } + + // Here is one case. + if only != -1 { + self.setCurrentStmt(m.Cases[only].Scope) + } + } + + fn optimizeRangeIter(mut &self, mut it: &RangeIter) { + // Optimize scope first, following alrgorithms related with expression. + // It might be skip this, so scope optimizater should be guaranteed to run. + if self.data.boundary != nil && it.KeyA != nil { + // Add index variable to boundary analysis. + self.data.boundary.pushVar(getBoundaryVar(it.Expr.Model), it.KeyA) + } + self.optimizeChild(it.Scope) + + if Iter { + match type it.Expr.Model { + | &CastingExprModel: + mut cem := (&CastingExprModel)(it.Expr.Model) + eprim := cem.ExprKind.Prim() + if eprim == nil || !eprim.IsStr() { + break + } + mut s := cem.Kind.Slc() + if s == nil { + break + } + prim := s.Elem.Prim() + if prim == nil { + break + } + match { + | prim.IsU8(): + // Expression is: []byte(str) + // Use string expression directly, byte casting is unnecessary. + it.Expr = cem.Expr + | prim.IsI32(): + // Expression is: []rune(str) + // Avoid making allocation, iterate runes of string. + exprOptimizer.optimizeData(cem.Expr.Model, self.data) // Optimize string expression. + self.setCurrentStmt(&StrRuneIter{ + Expr: cem.Expr, + Base: it, + }) + ret + } + } + } + exprOptimizer.optimizeData(it.Expr.Model, self.data) + } + + fn optimizeWhileIter(mut &self, mut it: &WhileIter) { + exprOptimizer.optimizeData(it.Expr, self.data) + self.optimizeStmt(it.Next) + self.optimizeChild(it.Scope) + } + + fn substr(mut &self, mut a: &sema::Assign): bool { + if a.Op.Id != TokenId.Eq { + ret false + } + match type a.Right.Model { + | &SlicingExprModel: + mut sem := (&SlicingExprModel)(a.Right.Model) + if equalModels(a.Left.Model, sem.Expr) { + self.setCurrentStmt(&MutSlicingExprModel{ + Token: sem.Token, + Expr: sem.Expr, + Left: sem.Left, + Right: sem.Right, + }) + ret true + } + } + ret false + } + + fn strAssign(mut &self, mut a: &sema::Assign): bool { + if !Str { + ret false + } + lp := a.Left.Kind.Prim() + if lp == nil || !lp.IsStr() { + ret false + } + ret self.substr(a) + } + + fn sliceAssign(mut &self, mut a: &sema::Assign): bool { + if !Slice || a.Left.Kind.Slc() == nil { + ret false + } + // [self.substr] applies this optimization without type dependence. + ret self.substr(a) + } + + fn optimizePostfix(mut &self, mut postfix: &Postfix) { + if self.data.boundary != nil { + possibleBoundaryRemove(self.data.boundary, postfix.Expr) + } + exprOptimizer.optimizeData(postfix.Expr, self.data) + } + + fn optimizeAssign(mut &self, mut assign: &sema::Assign) { + if assign.Op.Id == TokenId.Eq && + equalModels(assign.Left.Model, assign.Right.Model) { + self.removeCurrent() + self.i-- // In next iteration, point to correct statement. + ret + } + + if self.data.boundary != nil { + if isBoundaryRiskyType(assign.Left.Kind) { + possibleBoundaryRemove(self.data.boundary, assign.Left.Model) + } + } + if self.data.nils != nil { + if isGuaranteedNonNilExpr(self.data.nils, assign.Right.Model) { + if isNilValidType(assign.Left.Kind) { + const safe = true + self.data.nils.pushVar(getNilVar(assign.Left.Model), safe) + } + } else { + possibleNilRemove(self.data.nils, assign.Left.Model) + } + } + if self.data.dynamic != nil { + mut kind := isTypeGuaranteedDynamicData( + self.data.dynamic, assign.Right.Kind, assign.Right.Model) + if kind != nil { + if isDynamicValidType(assign.Left.Kind) { + self.data.dynamic.pushVar(getDynamicVar(assign.Left.Model), kind) + } + } else { + possibleDynamicRemove(self.data.dynamic, assign.Left.Model) + } + } + + match { + | self.strAssign(assign) + | self.sliceAssign(assign): + ret + } + + exprOptimizer.optimizeData(assign.Left.Model, self.data) + exprOptimizer.optimizeData(assign.Right.Model, self.data) + + match assign.Op.Id { + | TokenId.SolidusEq | TokenId.PercentEq: + // Do not check division of structures safety. + if !Math || assign.Left.Kind.Struct() != nil { + break + } + oldId, oldKind := assign.Op.Id, assign.Op.Kind + match assign.Op.Id { + | TokenId.SolidusEq: + assign.Op.Id = TokenId.Solidus + assign.Op.Kind = TokenKind.Solidus + | TokenId.PercentEq: + assign.Op.Id = TokenId.Percent + assign.Op.Kind = TokenKind.Percent + |: + panic("implementation mistake, this panic call should be unreachable") + } + mut model := ExprModel(&BinaryExprModel{ + Op: assign.Op, + Left: assign.Left, + Right: assign.Right, + }) + exprOptimizer.optimizeData(model, self.data) + match type model { + | &BinaryExprModel: + assign.Right = new(OperandExprModel, *assign.Right) + assign.Op.Id = TokenId.Eq + assign.Op.Kind = TokenKind.Eq + assign.Right.Model = model + ret + } + assign.Op.Id = oldId + assign.Op.Kind = oldKind + ret + } + + if Append { + match type assign.Right.Model { + | &BuiltinAppendCallExprModel: + mut m := (&BuiltinAppendCallExprModel)(assign.Right.Model) + if !areSameLvalueExprModel(assign.Left.Model, m.Dest) { + ret + } + match type m.Elements { + | &SliceExprModel: + // Push items one-by-one for self-appended memory. + self.setCurrentStmt(&PushToSliceExprModel{ + Dest: m.Dest, + Elems: (&SliceExprModel)(m.Elements), + }) + |: + // Append directly if appended to slice and assigned to the same memory. + self.setCurrentStmt(&AppendToSliceExprModel{ + Dest: assign.Left.Model, + Slice: m.Elements, + }) + } + } + } + } + + fn tryOptimizeSwap(mut &self, mut &assign: &MultiAssign): bool { + if !Assign || len(assign.Left) != 2 || + assign.Left[0] == nil || assign.Left[1] == nil { + ret false + } + let mut tup: &TupleExprModel + match type assign.Right { + | &TupleExprModel: + tup = (&TupleExprModel)(assign.Right) + } + if tup == nil || len(tup.Datas) != 2 { + ret false + } + + // Catch self assignments. + if equalModels(assign.Left[0].Model, tup.Datas[0].Model) && + equalModels(assign.Left[1].Model, tup.Datas[1].Model) { + self.removeCurrent() + self.i-- // In next iteration, point to correct statement. + ret true + } + + // Catch swaps. + if !equalModels(assign.Left[0].Model, tup.Datas[1].Model) || + !equalModels(assign.Left[1].Model, tup.Datas[0].Model) { + ret false + } + mut model := &SwapExprModel{ + Left: assign.Left[0], + Right: assign.Left[1], + } + exprOptimizer.optimizeData(model.Left.Model, self.data) + exprOptimizer.optimizeData(model.Right.Model, self.data) + self.setCurrentStmt(model) + ret true + } + + fn optimizeMultiAssign(mut &self, mut assign: &MultiAssign) { + if self.tryOptimizeSwap(assign) { + // Swap operation can skip the following algorithm. + // As far as tested, following analysis are not necessary. + ret + } + + mut tup := (&TupleExprModel)(nil) + match type assign.Right { + | &TupleExprModel: + tup = (&TupleExprModel)(assign.Right) + } + for (i, mut l) in assign.Left { + if l != nil { + if self.data.boundary != nil { + if isBoundaryRiskyType(l.Kind) { + possibleBoundaryRemove(self.data.boundary, l.Model) + } + } + if self.data.nils != nil { + if tup != nil && isGuaranteedNonNilExpr(self.data.nils, tup.Datas[i].Model) { + if isNilValidType(l.Kind) { + const safe = true + self.data.nils.pushVar(getNilVar(l.Model), safe) + } + } else { + possibleNilRemove(self.data.nils, l.Model) + } + } + if self.data.dynamic != nil && tup != nil { + mut kind := isTypeGuaranteedDynamicData( + self.data.dynamic, tup.Datas[i].Kind, tup.Datas[i].Model) + if kind != nil { + if isDynamicValidType(l.Kind) { + self.data.dynamic.pushVar(getDynamicVar(l.Model), kind) + } + } else { + possibleDynamicRemove(self.data.dynamic, l.Model) + } + } + exprOptimizer.optimizeData(l.Model, self.data) + } + } + exprOptimizer.optimizeData(assign.Right, self.data) + } + + fn optimizeRet(mut &self, mut r: &RetSt) { + exprOptimizer.optimizeData(r.Expr, self.data) + + // Break algorithm is exceptional-specific optimizations are not enabled. + // The following algorithms tries to apply specific optimizations for exceptionals. + if !Exceptional { + ret + } + match type r.Expr { + | &FnCallExprModel: + break + |: + ret + } + mut fc := (&FnCallExprModel)(r.Expr) + if !fc.Func.Decl.Exceptional || + fc.Except == nil || + len(fc.Except.Stmts) != 1 || + !obj::IsForwarded(fc.Except) { + ret + } + self.setCurrentStmt(&ExceptionalForwardingExprModel{Expr: fc}) + } + + fn optimizeStmt(mut &self, mut stmt: Stmt) { + match type stmt { + | &Scope: + self.optimizeChild((&Scope)(stmt)) + | &Data: + self.optimizeData((&Data)(stmt)) + | &Var: + self.optimizeVar((&Var)(stmt)) + | &Conditional: + self.optimizeConditional((&Conditional)(stmt)) + | &RangeIter: + self.optimizeRangeIter((&RangeIter)(stmt)) + | &WhileIter: + self.optimizeWhileIter((&WhileIter)(stmt)) + | &InfIter: + self.optimizeChild((&InfIter)(stmt).Scope) + | &sema::Assign: + self.optimizeAssign((&sema::Assign)(stmt)) + | &MultiAssign: + self.optimizeMultiAssign((&MultiAssign)(stmt)) + | &Match: + self.optimizeMatch((&Match)(stmt)) + | &RetSt: + self.optimizeRet((&RetSt)(stmt)) + | &Postfix: + self.optimizePostfix((&Postfix)(stmt)) + } + } + + fn optimizeChild(mut &self, mut child: &Scope) { + mut so := scopeOptimizer.new(child) + so.parent = self + so.data = self.data + so.optimize() + } + + // Optimizes scope by enabled optimizations. + fn optimize(mut &self) { + self.i = 0 + for self.i < len(self.scope.Stmts); self.i++ { + self.optimizeStmt(self.scope.Stmts[self.i]) + } + } } fn isConstantValidConditionalCase(&i: &If): bool { - match type i.Expr { - | &Const: - c := (&Const)(i.Expr) - ret c.IsBool() && c.ReadBool() - } - ret false + match type i.Expr { + | &Const: + c := (&Const)(i.Expr) + ret c.IsBool() && c.ReadBool() + } + ret false } fn isUnreachableExpr(&expr: ExprModel): bool { - match type expr { - | &Const: - c := (&Const)(expr) - ret c.IsBool() && !c.ReadBool() - | &BinaryExprModel: - m := (&BinaryExprModel)(expr) - if m.Op.Id == TokenId.DblAmper { - ret isUnreachableExpr(m.Left.Model) || - isUnreachableExpr(m.Right.Model) - } - } - ret false + match type expr { + | &Const: + c := (&Const)(expr) + ret c.IsBool() && !c.ReadBool() + | &BinaryExprModel: + m := (&BinaryExprModel)(expr) + if m.Op.Id == TokenId.DblAmper { + ret isUnreachableExpr(m.Left.Model) || + isUnreachableExpr(m.Right.Model) + } + } + ret false } fn isConstantValidMatchCase(&case: &Case): bool { - for _, expr in case.Exprs { - if expr.IsConst() && expr.Constant.IsBool() && expr.Constant.ReadBool() { - ret true - } - } - ret false + for _, expr in case.Exprs { + if expr.IsConst() && expr.Constant.IsBool() && expr.Constant.ReadBool() { + ret true + } + } + ret false } fn isUnreachableConditionalCase(&i: &If): bool { - ret isUnreachableExpr(i.Expr) + ret isUnreachableExpr(i.Expr) } fn isUnreachableMatchCase(&case: &Case): bool { - for _, expr in case.Exprs { - if !isUnreachableExpr(expr.Model) { - ret false - } - } - ret true + for _, expr in case.Exprs { + if !isUnreachableExpr(expr.Model) { + ret false + } + } + ret true } \ No newline at end of file diff --git a/src/julec/windows.jule b/src/julec/windows.jule index ceead4f22..72a73a5a6 100644 --- a/src/julec/windows.jule +++ b/src/julec/windows.jule @@ -16,20 +16,20 @@ use sys for std::sys const enableVirtualTerminalProcessing = 0x0004 fn enableVtp() { - hOut := sys::GetStdHandle(uintptr(sys::STD_OUTPUT_HANDLE)) - if hOut == sys::InvalidHandle { - ret - } + hOut := sys::GetStdHandle(uintptr(sys::STD_OUTPUT_HANDLE)) + if hOut == sys::InvalidHandle { + ret + } - mut dwMode := 0 - if !sys::GetConsoleMode(hOut, dwMode) { - ret - } + mut dwMode := 0 + if !sys::GetConsoleMode(hOut, dwMode) { + ret + } - dwMode |= enableVirtualTerminalProcessing - _ = sys::SetConsoleMode(hOut, dwMode) + dwMode |= enableVirtualTerminalProcessing + _ = sys::SetConsoleMode(hOut, dwMode) } fn init() { - enableVtp() + enableVtp() } \ No newline at end of file diff --git a/std/bytes/bytes.jule b/std/bytes/bytes.jule index 7da10e594..f958a33b0 100644 --- a/std/bytes/bytes.jule +++ b/std/bytes/bytes.jule @@ -14,56 +14,56 @@ use fastbytes for std::internal::fastbytes // Returns bytes that equals to concatenation of n-count s. // Returns nil slice is n <= 0. fn Repeat(s: []byte, mut n: int): []byte { - if n <= 0 { - ret nil - } - if len(s) > int.Max/n { - panic("std::bytes: repeat: integer buffer size overflow") - } + if n <= 0 { + ret nil + } + if len(s) > int.Max/n { + panic("std::bytes: repeat: integer buffer size overflow") + } - mut buff := make([]byte, len(s) * n) - mut i := 0 - for n > 0; n-- { - i += copy(buff[i:], s) - } - ret buff + mut buff := make([]byte, len(s) * n) + mut i := 0 + for n > 0; n-- { + i += copy(buff[i:], s) + } + ret buff } fn hasPrefix(&s: []byte, &sub: []byte, mut start: int): bool { - if len(sub) == 0 || len(s)-start < len(sub) { - ret false - } - for _, sb in sub { - if s[start] != sb { - ret false - } - start++ - } - ret true + if len(sub) == 0 || len(s)-start < len(sub) { + ret false + } + for _, sb in sub { + if s[start] != sb { + ret false + } + start++ + } + ret true } // Reports byte slice has prefix as specified sub-slice or not. fn HasPrefix(s: []byte, sub: []byte): bool { - ret hasPrefix(s, sub, 0) + ret hasPrefix(s, sub, 0) } fn hasSuffix(&s: []byte, &sub: []byte, mut start: int): bool { - if len(sub) == 0 || len(s)-start < len(sub) { - ret false - } + if len(sub) == 0 || len(s)-start < len(sub) { + ret false + } - start = len(s) - start - for i in sub { - if s[start-i-1] != sub[len(sub)-i-1] { - ret false - } - } - ret true + start = len(s) - start + for i in sub { + if s[start-i-1] != sub[len(sub)-i-1] { + ret false + } + } + ret true } // Reports byte slice has suffix as specified sub-slice or not. fn HasSuffix(s: []byte, sub: []byte): bool { - ret hasSuffix(s, sub, 0) + ret hasSuffix(s, sub, 0) } // Returns index of first matched item with specified sub-slice, @@ -71,22 +71,22 @@ fn HasSuffix(s: []byte, sub: []byte): bool { // of slice to right. Starts searching s at given index. // Returns -1, if i < 0 || i >= len(s). fn FindAt(s: []byte, sub: []byte, mut i: int): int { - if i < 0 || len(s) < len(sub) || len(sub) == 0 { - ret -1 - } - for i < len(s); i++ { - if hasPrefix(s, sub, i) { - ret i - } - } - ret -1 + if i < 0 || len(s) < len(sub) || len(sub) == 0 { + ret -1 + } + for i < len(s); i++ { + if hasPrefix(s, sub, i) { + ret i + } + } + ret -1 } // Returns index of first matched item with specified sub-slice, // returns -1 if not exist any match. Starts searching at left // of slice to right. fn Find(s: []byte, sub: []byte): int { - ret FindAt(s, sub, 0) + ret FindAt(s, sub, 0) } // Returns index of first matched item with specified sub-slice, @@ -94,73 +94,73 @@ fn Find(s: []byte, sub: []byte): int { // of slice to left. Starts searching s at given index. // Returns -1, if i < 0 || i >= len(s). fn FindLastAt(s: []byte, sub: []byte, i: int): int { - mut j := i - len(sub) + 1 - if len(sub) == 0 || i < 0 || i >= len(s) || j < 0 { - ret -1 - } + mut j := i - len(sub) + 1 + if len(sub) == 0 || i < 0 || i >= len(s) || j < 0 { + ret -1 + } loop: - for j >= 0; j-- { - mut k := j - mut z := 0 - for z < len(sub); k, z = k + 1, z + 1 { - if s[k] != sub[z] { - continue loop - } - } - ret j - } - ret -1 + for j >= 0; j-- { + mut k := j + mut z := 0 + for z < len(sub); k, z = k + 1, z + 1 { + if s[k] != sub[z] { + continue loop + } + } + ret j + } + ret -1 } // Returns index of first matched item with specified sub-slice, // returns -1 if not exist any match. Starts searching at right // of slice to left. fn FindLast(s: []byte, sub: []byte): int { - ret FindLastAt(s, sub, len(s) - 1) + ret FindLastAt(s, sub, len(s) - 1) } // Returns index of first matched item with specified byte, // returns -1 if not exist any match. Starts searching at left // of slice to right. fn FindByte(s: []byte, b: byte): int { - ret fastbytes::FindByte(s, b) + ret fastbytes::FindByte(s, b) } // Returns index of first matched item with specified byte, // returns -1 if not exist any match. Starts searching at right // of slice to left. fn FindLastByte(s: []byte, b: byte): int { - ret fastbytes::FindLastByte(s, b) + ret fastbytes::FindLastByte(s, b) } // Returns index of first matched item with specified rune, // returns -1 if not exist any match. Starts searching at left // of slice to right. fn FindRune(s: []byte, r: rune): int { - mut i := 0 - for i < len(s) { - br, n := utf8::DecodeRune(s[i:]) - if r == br { - ret i - } - i += n - } - ret -1 + mut i := 0 + for i < len(s) { + br, n := utf8::DecodeRune(s[i:]) + if r == br { + ret i + } + i += n + } + ret -1 } // Returns index of first matched item with specified rune, // returns -1 if not exist any match. Starts searching at right // of slice to left. fn FindLastRune(s: []byte, r: rune): int { - mut i := len(s) - for i > 0 { - br, n := utf8::DecodeLastRune(s[:i]) - if r == br { - ret i - 1 - } - i -= n - } - ret -1 + mut i := len(s) + for i > 0 { + br, n := utf8::DecodeLastRune(s[:i]) + if r == br { + ret i - 1 + } + i -= n + } + ret -1 } // Returns index of first matched item with finder function, @@ -168,24 +168,24 @@ fn FindLastRune(s: []byte, r: rune): int { // of slice to right. Starts searching s at given index. // Returns -1, if i < 0. fn FindFnAt(s: []byte, mut i: int, f: fn(mut rune): bool): int { - if i < 0 { - ret -1 - } - for i < len(s) { - r, n := utf8::DecodeRune(s[i:]) - if f(r) { - ret i - } - i += n - } - ret -1 + if i < 0 { + ret -1 + } + for i < len(s) { + r, n := utf8::DecodeRune(s[i:]) + if f(r) { + ret i + } + i += n + } + ret -1 } // Returns index of first matched item with finder function, // returns -1 if not exist any match. Starts searching at left // of slice to right. fn FindFn(s: []byte, f: fn(mut rune): bool): int { - ret FindFnAt(s, 0, f) + ret FindFnAt(s, 0, f) } // Returns index of first matched item with finder function, @@ -193,54 +193,54 @@ fn FindFn(s: []byte, f: fn(mut rune): bool): int { // of slice to left. Starts searching s at given index. // Returns -1, if i < 0 || i >= len(s). fn FindFnLastAt(s: []byte, mut i: int, f: fn(mut rune): bool): int { - if i < 0 || i >= len(s) { - ret -1 - } - for i > 0 { - r, n := utf8::DecodeRune(s[i:]) - if f(r) { - ret i - } - i -= n - } - ret -1 + if i < 0 || i >= len(s) { + ret -1 + } + for i > 0 { + r, n := utf8::DecodeRune(s[i:]) + if f(r) { + ret i + } + i -= n + } + ret -1 } // Returns index of first matched item with finder function, // returns -1 if not exist any match. Starts searching at right // of slice to left. fn FindFnLast(s: []byte, f: fn(mut rune): bool): int { - ret FindFnLastAt(s, len(s) - 1, f) + ret FindFnLastAt(s, len(s) - 1, f) } // Returns index of first matched item with any of runes, // returns -1 if not exist any match. Starts searching at left // of slice to right. fn FindAny(s: []byte, runes: []byte): int { - mut i := 0 - for i < len(s) { - r, n := utf8::DecodeRune(s[i:]) - if FindRune(runes, r) != -1 { - ret i - } - i += n - } - ret -1 + mut i := 0 + for i < len(s) { + r, n := utf8::DecodeRune(s[i:]) + if FindRune(runes, r) != -1 { + ret i + } + i += n + } + ret -1 } // Returns index of first matched item with any of runes, // returns -1 if not exist any match. Starts searching at right // of slice to left. fn FindLastAny(s: []byte, runes: []byte): int { - mut i := len(s) - for i > 0 { - r, n := utf8::DecodeLastRune(s[:i]) - if FindRune(runes, r) != -1 { - ret i - 1 - } - i -= n - } - ret -1 + mut i := len(s) + for i > 0 { + r, n := utf8::DecodeLastRune(s[:i]) + if FindRune(runes, r) != -1 { + ret i - 1 + } + i -= n + } + ret -1 } // Splits the slice into the specified number of parts to the specified sub-slice. @@ -248,75 +248,75 @@ fn FindLastAny(s: []byte, runes: []byte): int { // Returns empty slice if n is equals to zero. // Returns all parts if n less than zero. fn Split(mut s: []byte, sub: []byte, mut n: int): [][]byte { - mut cap := n - if n < 0 { - cap = 1 << 3 - } - mut parts := make([][]byte, 0, cap) - if n == 0 { - ret parts - } - if n < 0 { - n = len(s) - } - mut i := 0 - for n > 0; n-- { - j := FindAt(s, sub, i) - if j == -1 { - break - } - parts = append(parts, s[i:j]) - i = j + len(sub) - } - if n > 0 && i < len(s) { - parts = append(parts, s[i:]) - } - ret parts + mut cap := n + if n < 0 { + cap = 1 << 3 + } + mut parts := make([][]byte, 0, cap) + if n == 0 { + ret parts + } + if n < 0 { + n = len(s) + } + mut i := 0 + for n > 0; n-- { + j := FindAt(s, sub, i) + if j == -1 { + break + } + parts = append(parts, s[i:j]) + i = j + len(sub) + } + if n > 0 && i < len(s) { + parts = append(parts, s[i:]) + } + ret parts } // Reports whether slice includes sub-slice. fn Contains(s: []byte, sub: []byte): bool { - ret FindAt(s, sub, 0) != -1 + ret FindAt(s, sub, 0) != -1 } // Reports whether slice includes byte. fn ContainsByte(s: []byte, b: byte): bool { - ret FindByte(s, b) != -1 + ret FindByte(s, b) != -1 } // Reports whether slice includes rune. fn ContainsRune(s: []byte, r: rune): bool { - ret FindRune(s, r) != -1 + ret FindRune(s, r) != -1 } // Reports whether slice includes any of runes. fn ContainsAny(s: []byte, runes: []byte): bool { - ret FindAny(s, runes) != -1 + ret FindAny(s, runes) != -1 } // Counts the number of non-overlapping instances of sub-slice in s. // Returns zero if sub-slice is empty. fn Count(s: []byte, sub: []byte): int { - if len(sub) == 0 { - ret 0 - } - mut n := 0 - mut i := 0 - for { - j := FindAt(s, sub, i) - if j == -1 { - break - } - n++ - i = j + len(sub) - } - ret n + if len(sub) == 0 { + ret 0 + } + mut n := 0 + mut i := 0 + for { + j := FindAt(s, sub, i) + if j == -1 { + break + } + n++ + i = j + len(sub) + } + ret n } // Reports whether two byte slices are the same length and contains same bytes. // The nil slice considered as zero-length empty slice. fn Equal(s1: []byte, s2: []byte): bool { - ret fastbytes::Equal(s1, s2) + ret fastbytes::Equal(s1, s2) } // Replaces all sub-slices matching sub in the slice with new. @@ -324,126 +324,126 @@ fn Equal(s1: []byte, s2: []byte): bool { // Replaces all matches if n less than zero. // This function may return mutable copy of s, of new slice allocation. fn Replace(mut s: []byte, sub: []byte, new: []byte, mut n: int): []byte { - if n == 0 || Equal(sub, new) { - ret s - } - - m := Count(s, sub) - if m == 0 { - ret s - } - if n < 0 || m < n { - n = m - } - - mut ss := make([]byte, 0, len(s) + n * (len(new) - len(sub))) - mut i := 0 - for n > 0; n-- { - j := FindAt(s, sub, i) - if j == -1 { - break - } - ss = append(ss, s[i:j]...) - ss = append(ss, new...) - i = j + len(sub) - } - ss = append(ss, s[i:]...) - ret ss + if n == 0 || Equal(sub, new) { + ret s + } + + m := Count(s, sub) + if m == 0 { + ret s + } + if n < 0 || m < n { + n = m + } + + mut ss := make([]byte, 0, len(s) + n * (len(new) - len(sub))) + mut i := 0 + for n > 0; n-- { + j := FindAt(s, sub, i) + if j == -1 { + break + } + ss = append(ss, s[i:j]...) + ss = append(ss, new...) + i = j + len(sub) + } + ss = append(ss, s[i:]...) + ret ss } // Returns a immutable copy of the slice s with all its characters modified // according to the mapping function. If mapping returns a negative value, // the character is dropped from the slice with no replacement. fn Map(s: []byte, mapping: fn(mut rune): rune): []byte { - mut ss := make([]byte, 0, len(s)) - mut i := 0 - for i < len(s) { - mut r, n := utf8::DecodeRune(s[i:]) - i += n - r = mapping(r) - if r >= 0 { - ss = utf8::AppendRune(ss, r) - } - } - ret ss + mut ss := make([]byte, 0, len(s)) + mut i := 0 + for i < len(s) { + mut r, n := utf8::DecodeRune(s[i:]) + i += n + r = mapping(r) + if r >= 0 { + ss = utf8::AppendRune(ss, r) + } + } + ret ss } // Returns s with all Unicode letters mapped to their lower case. // Returns immutable new slice allocation. fn ToLower(s: []byte): []byte { - ret Map(s, unicode::ToLower) + ret Map(s, unicode::ToLower) } // Returns s with all Unicode letters mapped to their upper case. // Returns immutable new slice allocation. fn ToUpper(s: []byte): []byte { - ret Map(s, unicode::ToUpper) + ret Map(s, unicode::ToUpper) } // Trims slice by specified runes at left. // Cutset should include runes to trim. // Returns mutable copy of s. fn TrimLeft(mut s: []byte, cutset: []byte): []byte { - mut i := 0 - for i < len(s) { - r, n := utf8::DecodeRune(s[i:]) - if FindRune(cutset, r) == -1 { - s = s[i:] - break - } - i += n - } - ret s + mut i := 0 + for i < len(s) { + r, n := utf8::DecodeRune(s[i:]) + if FindRune(cutset, r) == -1 { + s = s[i:] + break + } + i += n + } + ret s } // Trims slice by specified runes at right. // Cutset should include runes to trim. // Returns mutable copy of s. fn TrimRight(mut s: []byte, cutset: []byte): []byte { - mut i := len(s) - for i > 0 { - r, n := utf8::DecodeLastRune(s[:i]) - if FindRune(cutset, r) == -1 { - s = s[:i] - break - } - i -= n - } - ret s + mut i := len(s) + for i > 0 { + r, n := utf8::DecodeLastRune(s[:i]) + if FindRune(cutset, r) == -1 { + s = s[:i] + break + } + i -= n + } + ret s } // Trims slice by specified runes at left and right. // Cutset should include runes to trim. // Returns mutable copy of s. fn Trim(mut s: []byte, cutset: []byte): []byte { - ret TrimRight(TrimLeft(s, cutset), cutset) + ret TrimRight(TrimLeft(s, cutset), cutset) } // Concatenates the parts of its first argument to create a single slice. // The separator sep is placed between parts in the resulting slice. fn Join(parts: [][]byte, sep: []byte): []byte { - if len(parts) == 0 { - ret make([]byte, 0) - } - mut s := make([]byte, len(parts[0])) - copy(s, parts[0]) - for _, part in parts[1:] { - s = append(s, sep...) - s = append(s, part...) - } - ret s + if len(parts) == 0 { + ret make([]byte, 0) + } + mut s := make([]byte, len(parts[0])) + copy(s, parts[0]) + for _, part in parts[1:] { + s = append(s, sep...) + s = append(s, part...) + } + ret s } // Returns runes from UTF-8 encoded bytes. fn Runes(s: []byte): []rune { - mut runes := make([]rune, 0, utf8::RuneCount(s)) - mut i := 0 - for i < len(s) { - r, n := utf8::DecodeRune(s[i:]) - i += n - runes = append(runes, r) - } - ret runes + mut runes := make([]rune, 0, utf8::RuneCount(s)) + mut i := 0 + for i < len(s) { + r, n := utf8::DecodeRune(s[i:]) + i += n + runes = append(runes, r) + } + ret runes } // Cut slices s around the first instance of sep, @@ -453,9 +453,9 @@ fn Runes(s: []byte): []rune { // // Cut returns slices of the original slice s, not copies. fn Cut(mut s: []byte, sep: []byte): (before: []byte, after: []byte, found: bool) { - i := Find(s, sep) - if i >= 0 { - ret s[:i], s[i+len(sep):], true - } - ret s, nil, false + i := Find(s, sep) + if i >= 0 { + ret s[:i], s[i+len(sep):], true + } + ret s, nil, false } \ No newline at end of file diff --git a/std/comptime/type.jule b/std/comptime/type.jule index d57b1e90e..ec7a353c1 100644 --- a/std/comptime/type.jule +++ b/std/comptime/type.jule @@ -4,34 +4,34 @@ // Type kinds. enum Kind { - Void, // Void - Int, // int - Uint, // uint - Uintptr, // uinptr - I8, // i8 - I16, // i16 - I32, // i32 - I64, // i64 - U8, // u8 - U16, // u16 - U32, // u32 - U64, // u64 - F32, // f32 - F64, // f64 - Str, // str - Bool, // bool - Any, // any - Array, // Array - Slice, // Slice - Map, // Map - Struct, // Structure - Trait, // Trait - Enum, // Enum - Ptr, // Raw pointer - UnsafePtr, // Unsafe raw pointer - SmartPtr, // Smart pointer - Func, // Function - Tuple, // Tuple + Void, // Void + Int, // int + Uint, // uint + Uintptr, // uinptr + I8, // i8 + I16, // i16 + I32, // i32 + I64, // i64 + U8, // u8 + U16, // u16 + U32, // u32 + U64, // u64 + F32, // f32 + F64, // f64 + Str, // str + Bool, // bool + Any, // any + Array, // Array + Slice, // Slice + Map, // Map + Struct, // Structure + Trait, // Trait + Enum, // Enum + Ptr, // Raw pointer + UnsafePtr, // Unsafe raw pointer + SmartPtr, // Smart pointer + Func, // Function + Tuple, // Tuple } // Returns compile-time type information. diff --git a/std/conv/atob.jule b/std/conv/atob.jule index 068cad996..600d09e2b 100644 --- a/std/conv/atob.jule +++ b/std/conv/atob.jule @@ -39,20 +39,20 @@ // It accepts 1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False. // Any other value throws exception. fn ConvBool(s: str)!: bool { - match s { - | "1" | "t" | "T" | "true" | "TRUE" | "True": - ret true - | "0" | "f" | "F" | "false" | "FALSE" | "False": - ret false - |: - error(ConvError.InvalidSyntax) - } + match s { + | "1" | "t" | "T" | "true" | "TRUE" | "True": + ret true + | "0" | "f" | "F" | "false" | "FALSE" | "False": + ret false + |: + error(ConvError.InvalidSyntax) + } } // Returns "true" or "false" according to the value of b. fn FmtBool(b: bool): str { - if b { - ret "true" - } - ret "false" + if b { + ret "true" + } + ret "false" } \ No newline at end of file diff --git a/std/conv/atof.jule b/std/conv/atof.jule index 050698a5b..e4d6e5d74 100644 --- a/std/conv/atof.jule +++ b/std/conv/atof.jule @@ -44,21 +44,21 @@ const optimize = true // prefix of s and prefix, with the character case of s ignored. // The prefix argument must be all lower-case. fn commonPrefixLenIgnoreCase(s: str, prefix: str): int { - mut n := len(prefix) - if n > len(s) { - n = len(s) - } - mut i := 0 - for i < n; i++ { - mut c := s[i] - if 'A' <= c && c <= 'Z' { - c += 'a' - 'A' - } - if c != prefix[i] { - ret i - } - } - ret n + mut n := len(prefix) + if n > len(s) { + n = len(s) + } + mut i := 0 + for i < n; i++ { + mut c := s[i] + if 'A' <= c && c <= 'Z' { + c += 'a' - 'A' + } + if c != prefix[i] { + ret i + } + } + ret n } // Returns the floating-point value for the special, @@ -67,372 +67,372 @@ fn commonPrefixLenIgnoreCase(s: str, prefix: str): int { // of these representations and n is the length of that prefix. // The character case is ignored. fn special(s: str): (f: f64, n: int, ok: bool) { - if len(s) == 0 { - ret 0, 0, false - } - mut sign := 1 - mut nsign := 0 - match s[0] { - | '+' | '-': - if s[0] == '-' { - sign = -1 - } - nsign = 1 - unsafe { - // Break immutabilty, do not change content, just slicing. - mut sp := &s - *sp = (*sp)[1:] - } - fall - | 'i' | 'I': - mut caseN := commonPrefixLenIgnoreCase(s, "infinity") - // Anything longer than "inf" is ok, but if we - // don't have "infinity", only consume "inf". - if 3 < caseN && caseN < 8 { - caseN = 3 - } - if caseN == 3 || caseN == 8 { - ret math::Inf(sign), nsign + n, true - } - | 'n' | 'N': - if commonPrefixLenIgnoreCase(s, "NaN") == 3 { - ret math::NaN(), 3, true - } - } - ret 0, 0, false + if len(s) == 0 { + ret 0, 0, false + } + mut sign := 1 + mut nsign := 0 + match s[0] { + | '+' | '-': + if s[0] == '-' { + sign = -1 + } + nsign = 1 + unsafe { + // Break immutabilty, do not change content, just slicing. + mut sp := &s + *sp = (*sp)[1:] + } + fall + | 'i' | 'I': + mut caseN := commonPrefixLenIgnoreCase(s, "infinity") + // Anything longer than "inf" is ok, but if we + // don't have "infinity", only consume "inf". + if 3 < caseN && caseN < 8 { + caseN = 3 + } + if caseN == 3 || caseN == 8 { + ret math::Inf(sign), nsign + n, true + } + | 'n' | 'N': + if commonPrefixLenIgnoreCase(s, "NaN") == 3 { + ret math::NaN(), 3, true + } + } + ret 0, 0, false } // Reads a decimal or hexadecimal mantissa and exponent from a float // string representation in s; the number may be followed by other characters. // Reports the number of bytes consumed (i), and whether the number is valid (ok). fn readFloat(&s: str): (mantissa: u64, exp: int, neg: bool, trunc: bool, hex: bool, i: int, ok: bool) { - // optional sign - if i >= len(s) { - ret - } - match { - | s[i] == '+': - i++ - | s[i] == '-': - neg = true - i++ - } - - // digits - mut base := u64(10) - mut maxMantDigits := 19 // 10^19 fits in u64 - mut expChar := 'e' - if i+2 < len(s) && s[i] == '0' && lower(s[i+1]) == 'x' { - base = 16 - maxMantDigits = 16 // 16^16 fits in u64 - i += 2 - expChar = 'p' - hex = true - } - mut sawdot := false - mut sawdigits := false - mut nd := 0 - mut ndMant := 0 - mut dp := 0 - for i < len(s); i++ { - c := s[i] - match { - | c == '_': - continue - | c == '.': - if sawdot { - goto loop_end - } - sawdot = true - dp = nd - continue - | '0' <= c && c <= '9': - sawdigits = true - if c == '0' && nd == 0 { // ignore leading zeros - dp-- - continue - } - nd++ - if ndMant < maxMantDigits { - mantissa *= base - mantissa += u64(c - '0') - ndMant++ - } else if c != '0' { - trunc = true - } - continue - | base == 16 && 'a' <= lower(c) && lower(c) <= 'f': - sawdigits = true - nd++ - if ndMant < maxMantDigits { - mantissa *= 16 - mantissa += u64(lower(c) - 'a' + 10) - ndMant++ - } else { - trunc = true - } - continue - } - break - } + // optional sign + if i >= len(s) { + ret + } + match { + | s[i] == '+': + i++ + | s[i] == '-': + neg = true + i++ + } + + // digits + mut base := u64(10) + mut maxMantDigits := 19 // 10^19 fits in u64 + mut expChar := 'e' + if i+2 < len(s) && s[i] == '0' && lower(s[i+1]) == 'x' { + base = 16 + maxMantDigits = 16 // 16^16 fits in u64 + i += 2 + expChar = 'p' + hex = true + } + mut sawdot := false + mut sawdigits := false + mut nd := 0 + mut ndMant := 0 + mut dp := 0 + for i < len(s); i++ { + c := s[i] + match { + | c == '_': + continue + | c == '.': + if sawdot { + goto loop_end + } + sawdot = true + dp = nd + continue + | '0' <= c && c <= '9': + sawdigits = true + if c == '0' && nd == 0 { // ignore leading zeros + dp-- + continue + } + nd++ + if ndMant < maxMantDigits { + mantissa *= base + mantissa += u64(c - '0') + ndMant++ + } else if c != '0' { + trunc = true + } + continue + | base == 16 && 'a' <= lower(c) && lower(c) <= 'f': + sawdigits = true + nd++ + if ndMant < maxMantDigits { + mantissa *= 16 + mantissa += u64(lower(c) - 'a' + 10) + ndMant++ + } else { + trunc = true + } + continue + } + break + } loop_end: - if !sawdigits { - ret - } - if !sawdot { - dp = nd - } - - if base == 16 { - dp *= 4 - ndMant *= 4 - } - - // optional exponent moves decimal point. - // if we read a very large, very long number, - // just be sure to move the decimal point by - // a lot (say, 100000). it doesn't matter if it's - // not the exact number. - if i < len(s) && lower(s[i]) == expChar { - i++ - if i >= len(s) { - ret - } - mut esign := 1 - if s[i] == '+' { - i++ - } else if s[i] == '-' { - i++ - esign = -1 - } - if i >= len(s) || s[i] < '0' || s[i] > '9' { - ret - } - mut e := 0 - for i < len(s) && ('0' <= s[i] && s[i] <= '9' || s[i] == '_'); i++ { - if s[i] == '_' { - continue - } - if e < 10000 { - e = e * 10 + int(s[i]) - '0' - } - } - dp += e * esign - } else if base == 16 { - // Must have exponent. - ret - } - - if mantissa != 0 { - exp = dp - ndMant - } - - ok = true - ret + if !sawdigits { + ret + } + if !sawdot { + dp = nd + } + + if base == 16 { + dp *= 4 + ndMant *= 4 + } + + // optional exponent moves decimal point. + // if we read a very large, very long number, + // just be sure to move the decimal point by + // a lot (say, 100000). it doesn't matter if it's + // not the exact number. + if i < len(s) && lower(s[i]) == expChar { + i++ + if i >= len(s) { + ret + } + mut esign := 1 + if s[i] == '+' { + i++ + } else if s[i] == '-' { + i++ + esign = -1 + } + if i >= len(s) || s[i] < '0' || s[i] > '9' { + ret + } + mut e := 0 + for i < len(s) && ('0' <= s[i] && s[i] <= '9' || s[i] == '_'); i++ { + if s[i] == '_' { + continue + } + if e < 10000 { + e = e * 10 + int(s[i]) - '0' + } + } + dp += e * esign + } else if base == 16 { + // Must have exponent. + ret + } + + if mantissa != 0 { + exp = dp - ndMant + } + + ok = true + ret } // Decimal power of ten to binary power of two. static powtab = [1, 3, 6, 9, 13, 16, 19, 23, 26] impl decimal { - fn set(mut self, s: []byte): (ok: bool) { - mut i := 0 - self.neg = false - self.trunc = false - - // optional sign - if i >= len(s) { - ret - } - match { - | s[i] == '+': - i++ - | s[i] == '-': - self.neg = true - i++ - } - - // digits - mut sawdot := false - mut sawdigits := false - for i < len(s); i++ { - match { - | s[i] == '_': - continue - | s[i] == '.': - if sawdot { - ret - } - sawdot = true - self.dp = self.nd - continue - | '0' <= s[i] && s[i] <= '9': - sawdigits = true - if s[i] == '0' && self.nd == 0 { // ignore leading zeros - self.dp-- - continue - } - if self.nd < len(self.d) { - self.d[self.nd] = s[i] - self.nd++ - } else if s[i] != '0' { - self.trunc = true - } - continue - } - break - } - if !sawdigits { - ret - } - if !sawdot { - self.dp = self.nd - } - - // optional exponent moves decimal point. - // if we read a very large, very long number, - // just be sure to move the decimal point by - // a lot (say, 100000). it doesn't matter if it's - // not the exact number. - if i < len(s) && lower(s[i]) == 'e' { - i++ - if i >= len(s) { - ret - } - mut esign := 1 - if s[i] == '+' { - i++ - } else if s[i] == '-' { - i++ - esign = -1 - } - if i >= len(s) || s[i] < '0' || s[i] > '9' { - ret - } - mut e := 0 - for i < len(s) && ('0' <= s[i] && s[i] <= '9' || s[i] == '_'); i++ { - if s[i] == '_' { - continue - } - if e < 10000 { - e = e * 10 + int(s[i]) - '0' - } - } - self.dp += e * esign - } - - if i != len(s) { - ret - } - - ok = true - ret - } - - fn floatBits(mut self, &flt: floatInfo): (b: u64, overflow: bool) { - mut exp := 0 - mut mant := u64(0) - - // Zero is always a special case. - if self.nd == 0 { - mant = 0 - exp = flt.bias - goto out - } - - // Obvious overflow/underflow. - // These bounds are for 64-bit floats. - // Will have to change if we want to support 80-bit floats in the future. - if self.dp > 310 { - goto overflow - } - if self.dp < -330 { - // zero - mant = 0 - exp = flt.bias - goto out - } - - // Scale by powers of two until in range [0.5, 1.0) - exp = 0 - for self.dp > 0 { - mut n := 0 - if self.dp >= len(powtab) { - n = 27 - } else { - n = powtab[self.dp] - } - self.shift(-n) - exp += n - } - for self.dp < 0 || self.dp == 0 && self.d[0] < '5' { - mut n := 0 - if -self.dp >= len(powtab) { - n = 27 - } else { - n = powtab[-self.dp] - } - self.shift(n) - exp -= n - } - - // Our range is [0.5,1) but floating point range is [1,2). - exp-- - - // Minimum representable exponent is flt.bias+1. - // If the exponent is smaller, move it up and - // adjust d accordingly. - if exp < flt.bias+1 { - n := flt.bias + 1 - exp - self.shift(-n) - exp += n - } - - if exp-flt.bias >= int(1<>= 1 - exp++ - if exp-flt.bias >= int(1<= len(s) { + ret + } + match { + | s[i] == '+': + i++ + | s[i] == '-': + self.neg = true + i++ + } + + // digits + mut sawdot := false + mut sawdigits := false + for i < len(s); i++ { + match { + | s[i] == '_': + continue + | s[i] == '.': + if sawdot { + ret + } + sawdot = true + self.dp = self.nd + continue + | '0' <= s[i] && s[i] <= '9': + sawdigits = true + if s[i] == '0' && self.nd == 0 { // ignore leading zeros + self.dp-- + continue + } + if self.nd < len(self.d) { + self.d[self.nd] = s[i] + self.nd++ + } else if s[i] != '0' { + self.trunc = true + } + continue + } + break + } + if !sawdigits { + ret + } + if !sawdot { + self.dp = self.nd + } + + // optional exponent moves decimal point. + // if we read a very large, very long number, + // just be sure to move the decimal point by + // a lot (say, 100000). it doesn't matter if it's + // not the exact number. + if i < len(s) && lower(s[i]) == 'e' { + i++ + if i >= len(s) { + ret + } + mut esign := 1 + if s[i] == '+' { + i++ + } else if s[i] == '-' { + i++ + esign = -1 + } + if i >= len(s) || s[i] < '0' || s[i] > '9' { + ret + } + mut e := 0 + for i < len(s) && ('0' <= s[i] && s[i] <= '9' || s[i] == '_'); i++ { + if s[i] == '_' { + continue + } + if e < 10000 { + e = e * 10 + int(s[i]) - '0' + } + } + self.dp += e * esign + } + + if i != len(s) { + ret + } + + ok = true + ret + } + + fn floatBits(mut self, &flt: floatInfo): (b: u64, overflow: bool) { + mut exp := 0 + mut mant := u64(0) + + // Zero is always a special case. + if self.nd == 0 { + mant = 0 + exp = flt.bias + goto out + } + + // Obvious overflow/underflow. + // These bounds are for 64-bit floats. + // Will have to change if we want to support 80-bit floats in the future. + if self.dp > 310 { + goto overflow + } + if self.dp < -330 { + // zero + mant = 0 + exp = flt.bias + goto out + } + + // Scale by powers of two until in range [0.5, 1.0) + exp = 0 + for self.dp > 0 { + mut n := 0 + if self.dp >= len(powtab) { + n = 27 + } else { + n = powtab[self.dp] + } + self.shift(-n) + exp += n + } + for self.dp < 0 || self.dp == 0 && self.d[0] < '5' { + mut n := 0 + if -self.dp >= len(powtab) { + n = 27 + } else { + n = powtab[-self.dp] + } + self.shift(n) + exp -= n + } + + // Our range is [0.5,1) but floating point range is [1,2). + exp-- + + // Minimum representable exponent is flt.bias+1. + // If the exponent is smaller, move it up and + // adjust d accordingly. + if exp < flt.bias+1 { + n := flt.bias + 1 - exp + self.shift(-n) + exp += n + } + + if exp-flt.bias >= int(1<>= 1 + exp++ + if exp-flt.bias >= int(1<>f64info.mantbits != 0 { - ret - } - f = f64(mantissa) - if neg { - f = -f - } - match { - | exp == 0: - // an integer. - ret f, true - // Exact integers are <= 10^15. - // Exact powers of ten are <= 10^22. - | exp > 0 && exp <= 15+22: // int * 10^k - // If exponent is big but number of digits is not, - // can move a few zeros into the integer part. - if exp > 22 { - f *= f64pow10[exp-22] - exp = 22 - } - if f > 1e15 || f < -1e15 { - // the exponent was really too large. - ret - } - ret f * f64pow10[exp], true - | exp < 0 && exp >= -22: // int / 10^k - ret f / f64pow10[-exp], true - } - ret + if mantissa>>f64info.mantbits != 0 { + ret + } + f = f64(mantissa) + if neg { + f = -f + } + match { + | exp == 0: + // an integer. + ret f, true + // Exact integers are <= 10^15. + // Exact powers of ten are <= 10^22. + | exp > 0 && exp <= 15+22: // int * 10^k + // If exponent is big but number of digits is not, + // can move a few zeros into the integer part. + if exp > 22 { + f *= f64pow10[exp-22] + exp = 22 + } + if f > 1e15 || f < -1e15 { + // the exponent was really too large. + ret + } + ret f * f64pow10[exp], true + | exp < 0 && exp >= -22: // int / 10^k + ret f / f64pow10[-exp], true + } + ret } // If possible to convert decimal representation to 64-bit float f exactly, @@ -484,68 +484,68 @@ fn atof64Exact(mantissa: u64, mut exp: int, neg: bool): (f: f64, ok: bool) { // value is exact integer / exact power of ten // These all produce potentially inexact but correctly rounded answers. fn atof64exact(mantissa: u64, mut exp: int, neg: bool): (f: f64, ok: bool) { - if mantissa>>f64info.mantbits != 0 { - ret - } - f = f64(mantissa) - if neg { - f = -f - } - match { - | exp == 0: - // an integer. - ret f, true - // Exact integers are <= 10^15. - // Exact powers of ten are <= 10^22. - | exp > 0 && exp <= 15+22: // int * 10^k - // If exponent is big but number of digits is not, - // can move a few zeros into the integer part. - if exp > 22 { - f *= f64pow10[exp-22] - exp = 22 - } - if f > 1e15 || f < -1e15 { - // the exponent was really too large. - ret - } - ret f * f64pow10[exp], true - | exp < 0 && exp >= -22: // int / 10^k - ret f / f64pow10[-exp], true - } - ret + if mantissa>>f64info.mantbits != 0 { + ret + } + f = f64(mantissa) + if neg { + f = -f + } + match { + | exp == 0: + // an integer. + ret f, true + // Exact integers are <= 10^15. + // Exact powers of ten are <= 10^22. + | exp > 0 && exp <= 15+22: // int * 10^k + // If exponent is big but number of digits is not, + // can move a few zeros into the integer part. + if exp > 22 { + f *= f64pow10[exp-22] + exp = 22 + } + if f > 1e15 || f < -1e15 { + // the exponent was really too large. + ret + } + ret f * f64pow10[exp], true + | exp < 0 && exp >= -22: // int / 10^k + ret f / f64pow10[-exp], true + } + ret } // If possible to compute mantissa*10^exp to 32-bit float f exactly, // entirely in floating-point math, do so, avoiding the machinery above. fn atof32exact(mantissa: u64, mut exp: int, mut neg: bool): (f: f32, ok: bool) { - if mantissa>>f32info.mantbits != 0 { - ret - } - f = f32(mantissa) - if neg { - f = -f - } - match { - | exp == 0: - ret f, true - // Exact integers are <= 10^7. - // Exact powers of ten are <= 10^10. - | exp > 0 && exp <= 7+10: // int * 10^k - // If exponent is big but number of digits is not, - // can move a few zeros into the integer part. - if exp > 10 { - f *= f32pow10[exp-10] - exp = 10 - } - if f > 1e7 || f < -1e7 { - // the exponent was really too large. - ret - } - ret f * f32pow10[exp], true - | exp < 0 && exp >= -10: // int / 10^k - ret f / f32pow10[-exp], true - } - ret + if mantissa>>f32info.mantbits != 0 { + ret + } + f = f32(mantissa) + if neg { + f = -f + } + match { + | exp == 0: + ret f, true + // Exact integers are <= 10^7. + // Exact powers of ten are <= 10^10. + | exp > 0 && exp <= 7+10: // int * 10^k + // If exponent is big but number of digits is not, + // can move a few zeros into the integer part. + if exp > 10 { + f *= f32pow10[exp-10] + exp = 10 + } + if f > 1e7 || f < -1e7 { + // the exponent was really too large. + ret + } + ret f * f32pow10[exp], true + | exp < 0 && exp >= -10: // int / 10^k + ret f / f32pow10[-exp], true + } + ret } // Converts the hex floating-point string s @@ -554,191 +554,191 @@ fn atof32exact(mantissa: u64, mut exp: int, mut neg: bool): (f: f32, ok: bool) { // The string s has already been parsed into a mantissa, exponent, and sign (neg==true for negative). // If trunc is true, trailing non-zero bits have been omitted from the mantissa. fn atofHex(&flt: floatInfo, mut mantissa: u64, mut exp: int, neg: bool, trunc: bool): (f64, ConvError) { - maxExp := int(1 << flt.expbits) + flt.bias - 2 - minExp := flt.bias + 1 - exp += int(flt.mantbits) // mantissa now implicitly divided by 2^mantbits. - - // Shift mantissa and exponent to bring representation into float range. - // Eventually we want a mantissa with a leading 1-bit followed by mantbits other bits. - // For rounding, we need two more, where the bottom bit represents - // whether that bit or any later bit was non-zero. - // (If the mantissa has already lost non-zero bits, trunc is true, - // and we OR in a 1 below after shifting left appropriately.) - for mantissa != 0 && mantissa>>(flt.mantbits+2) == 0 { - mantissa <<= 1 - exp-- - } - if trunc { - mantissa |= 1 - } - for mantissa>>(1 + flt.mantbits + 2) != 0 { - mantissa = mantissa >> 1 | mantissa & 1 - exp++ - } - - // If exponent is too negative, - // denormalize in hopes of making it representable. - // (The -2 is for the rounding bits.) - for mantissa > 1 && exp < minExp-2 { - mantissa = mantissa >> 1 | mantissa & 1 - exp++ - } - - // Round using two bottom bits. - mut round := mantissa & 3 - mantissa >>= 2 - round |= mantissa & 1 // round to even (round up if mantissa is odd) - exp += 2 - if round == 3 { - mantissa++ - if mantissa == 1<<(1 + flt.mantbits) { - mantissa >>= 1 - exp++ - } - } - - if mantissa>>flt.mantbits == 0 { // Denormal or zero. - exp = flt.bias - } - mut err := ConvError.Ok - if exp > maxExp { // infinity and range error - mantissa = u64(1 << flt.mantbits) - exp = maxExp + 1 - err = ConvError.OutOfRange - } - - mut bits := mantissa & (1 << flt.mantbits - 1) - bits |= u64((exp - flt.bias) & int(1 << flt.expbits - 1)) << flt.mantbits - if neg { - bits |= 1 << flt.mantbits << flt.expbits - } - if flt == f32info { - ret f64(math::F32FromBits(u32(bits))), err - } - ret math::F64FromBits(bits), err + maxExp := int(1 << flt.expbits) + flt.bias - 2 + minExp := flt.bias + 1 + exp += int(flt.mantbits) // mantissa now implicitly divided by 2^mantbits. + + // Shift mantissa and exponent to bring representation into float range. + // Eventually we want a mantissa with a leading 1-bit followed by mantbits other bits. + // For rounding, we need two more, where the bottom bit represents + // whether that bit or any later bit was non-zero. + // (If the mantissa has already lost non-zero bits, trunc is true, + // and we OR in a 1 below after shifting left appropriately.) + for mantissa != 0 && mantissa>>(flt.mantbits+2) == 0 { + mantissa <<= 1 + exp-- + } + if trunc { + mantissa |= 1 + } + for mantissa>>(1 + flt.mantbits + 2) != 0 { + mantissa = mantissa >> 1 | mantissa & 1 + exp++ + } + + // If exponent is too negative, + // denormalize in hopes of making it representable. + // (The -2 is for the rounding bits.) + for mantissa > 1 && exp < minExp-2 { + mantissa = mantissa >> 1 | mantissa & 1 + exp++ + } + + // Round using two bottom bits. + mut round := mantissa & 3 + mantissa >>= 2 + round |= mantissa & 1 // round to even (round up if mantissa is odd) + exp += 2 + if round == 3 { + mantissa++ + if mantissa == 1<<(1 + flt.mantbits) { + mantissa >>= 1 + exp++ + } + } + + if mantissa>>flt.mantbits == 0 { // Denormal or zero. + exp = flt.bias + } + mut err := ConvError.Ok + if exp > maxExp { // infinity and range error + mantissa = u64(1 << flt.mantbits) + exp = maxExp + 1 + err = ConvError.OutOfRange + } + + mut bits := mantissa & (1 << flt.mantbits - 1) + bits |= u64((exp - flt.bias) & int(1 << flt.expbits - 1)) << flt.mantbits + if neg { + bits |= 1 << flt.mantbits << flt.expbits + } + if flt == f32info { + ret f64(math::F32FromBits(u32(bits))), err + } + ret math::F64FromBits(bits), err } fn atof32(s: str): (f: f32, n: int, err: ConvError) { - { - val, _n, ok := special(s) - if ok { - ret f32(val), _n, ConvError.Ok - } - } - - mantissa, exp, neg, trunc, hex, _n, mut ok := readFloat(s) - n = _n - if !ok { - ret 0, n, ConvError.InvalidSyntax - } - - if hex { - mut ff := 0. - ff, err = atofHex(f32info, mantissa, exp, neg, trunc) - ret f32(ff), n, err - } - - if optimize { - // Try pure floating-point arithmetic conversion, and if that fails, - // the Eisel-Lemire algorithm. - if !trunc { - f, ok = atof32exact(mantissa, exp, neg) - if ok { - ret f, n, ConvError.Ok - } - } - f, ok = eiselLemire32(mantissa, exp, neg) - if ok { - if !trunc { - ret f, n, ConvError.Ok - } - // Even if the mantissa was truncated, we may - // have found the correct result. Confirm by - // converting the upper mantissa bound. - mut fUp := f32(0) - fUp, ok = eiselLemire32(mantissa + 1, exp, neg) - if ok && f == fUp { - ret f, n, ConvError.Ok - } - } - } - - // Slow fallback. - mut d := decimal{} - if !d.set(unsafe::StrBytes(s)[:n]) { - ret 0, n, ConvError.InvalidSyntax - } - b, ovf := d.floatBits(f32info) - f = math::F32FromBits(u32(b)) - if ovf { - err = ConvError.OutOfRange - } - ret f, n, err + { + val, _n, ok := special(s) + if ok { + ret f32(val), _n, ConvError.Ok + } + } + + mantissa, exp, neg, trunc, hex, _n, mut ok := readFloat(s) + n = _n + if !ok { + ret 0, n, ConvError.InvalidSyntax + } + + if hex { + mut ff := 0. + ff, err = atofHex(f32info, mantissa, exp, neg, trunc) + ret f32(ff), n, err + } + + if optimize { + // Try pure floating-point arithmetic conversion, and if that fails, + // the Eisel-Lemire algorithm. + if !trunc { + f, ok = atof32exact(mantissa, exp, neg) + if ok { + ret f, n, ConvError.Ok + } + } + f, ok = eiselLemire32(mantissa, exp, neg) + if ok { + if !trunc { + ret f, n, ConvError.Ok + } + // Even if the mantissa was truncated, we may + // have found the correct result. Confirm by + // converting the upper mantissa bound. + mut fUp := f32(0) + fUp, ok = eiselLemire32(mantissa + 1, exp, neg) + if ok && f == fUp { + ret f, n, ConvError.Ok + } + } + } + + // Slow fallback. + mut d := decimal{} + if !d.set(unsafe::StrBytes(s)[:n]) { + ret 0, n, ConvError.InvalidSyntax + } + b, ovf := d.floatBits(f32info) + f = math::F32FromBits(u32(b)) + if ovf { + err = ConvError.OutOfRange + } + ret f, n, err } fn atof64(s: str): (f: f64, n: int, err: ConvError) { - { - val, _n, ok := special(s) - if ok { - ret val, _n, ConvError.Ok - } - } - - mantissa, exp, neg, trunc, hex, _n, mut ok := readFloat(s) - n = _n - if !ok { - ret 0, n, ConvError.InvalidSyntax - } - - if hex { - f, err = atofHex(f64info, mantissa, exp, neg, trunc) - ret f, n, err - } - - if optimize { - // Try pure floating-point arithmetic conversion, and if that fails, - // the Eisel-Lemire algorithm. - if !trunc { - f, ok = atof64exact(mantissa, exp, neg) - if ok { - ret f, n, ConvError.Ok - } - } - f, ok = eiselLemire64(mantissa, exp, neg) - if ok { - if !trunc { - ret f, n, ConvError.Ok - } - // Even if the mantissa was truncated, we may - // have found the correct result. Confirm by - // converting the upper mantissa bound. - mut fUp := 0. - fUp, ok = eiselLemire64(mantissa + 1, exp, neg) - if ok && f == fUp { - ret f, n, ConvError.Ok - } - } - } - - // Slow fallback. - mut d := decimal{} - if !d.set(unsafe::StrBytes(s)[:n]) { - ret 0, n, ConvError.InvalidSyntax - } - b, ovf := d.floatBits(f64info) - f = math::F64FromBits(b) - if ovf { - err = ConvError.OutOfRange - } - ret f, n, err + { + val, _n, ok := special(s) + if ok { + ret val, _n, ConvError.Ok + } + } + + mantissa, exp, neg, trunc, hex, _n, mut ok := readFloat(s) + n = _n + if !ok { + ret 0, n, ConvError.InvalidSyntax + } + + if hex { + f, err = atofHex(f64info, mantissa, exp, neg, trunc) + ret f, n, err + } + + if optimize { + // Try pure floating-point arithmetic conversion, and if that fails, + // the Eisel-Lemire algorithm. + if !trunc { + f, ok = atof64exact(mantissa, exp, neg) + if ok { + ret f, n, ConvError.Ok + } + } + f, ok = eiselLemire64(mantissa, exp, neg) + if ok { + if !trunc { + ret f, n, ConvError.Ok + } + // Even if the mantissa was truncated, we may + // have found the correct result. Confirm by + // converting the upper mantissa bound. + mut fUp := 0. + fUp, ok = eiselLemire64(mantissa + 1, exp, neg) + if ok && f == fUp { + ret f, n, ConvError.Ok + } + } + } + + // Slow fallback. + mut d := decimal{} + if !d.set(unsafe::StrBytes(s)[:n]) { + ret 0, n, ConvError.InvalidSyntax + } + b, ovf := d.floatBits(f64info) + f = math::F64FromBits(b) + if ovf { + err = ConvError.OutOfRange + } + ret f, n, err } fn parseFloatPrefix(&s: str, bitSize: int): (f64, int, ConvError) { - if bitSize == 32 { - f, n, err := atof32(s) - ret f64(f), n, err - } - ret atof64(s) + if bitSize == 32 { + f, n, err := atof32(s) + ret f64(f), n, err + } + ret atof64(s) } // Converts the string s to a floating-point number @@ -766,12 +766,12 @@ fn parseFloatPrefix(&s: str, bitSize: int): (f64, int, ConvError) { // Recognizes the string "NaN", and the (possibly signed) strings "inf" and "infinity" // as their respective special floating point values. It ignores case when matching. fn ParseFloat(s: str, bitSize: int)!: f64 { - f, n, err := parseFloatPrefix(s, bitSize) - if n != len(s) && (err == ConvError.Ok || err != ConvError.InvalidSyntax) { - error(ConvError.InvalidSyntax) - } - if err != ConvError.Ok { - error(err) - } - ret f + f, n, err := parseFloatPrefix(s, bitSize) + if n != len(s) && (err == ConvError.Ok || err != ConvError.InvalidSyntax) { + error(ConvError.InvalidSyntax) + } + if err != ConvError.Ok { + error(err) + } + ret f } \ No newline at end of file diff --git a/std/conv/atoi.jule b/std/conv/atoi.jule index fc13c547d..123af92a0 100644 --- a/std/conv/atoi.jule +++ b/std/conv/atoi.jule @@ -45,110 +45,110 @@ const IntSize = _INT_SIZE // Instead of writing c == 'x' || c == 'X' one can write lower(c) == 'x'. // Note that lower of non-letters can produce other non-letters. fn lower(c: byte): byte { - ret c | ('x' - 'X') + ret c | ('x' - 'X') } fn parseUint(mut &s: str, mut base: int, mut bitSize: int): (u64, ConvError) { - if s == "" { - ret 0, ConvError.InvalidSyntax - } - - match { - | 2 <= base && base <= 36: - // valid base; nothing to do - | base == 0: - // Look for octal, hex prefix. - base = 10 - if s[0] == '0' { - match { - | len(s) >= 3 && lower(s[1]) == 'b': - base = 2 - s = s[2:] - | len(s) >= 3 && lower(s[1]) == 'o': - base = 8 - s = s[2:] - | len(s) >= 3 && lower(s[1]) == 'x': - base = 16 - s = s[2:] - |: - base = 8 - s = s[1:] - } - } - |: - ret 0, ConvError.InvalidBase - } - - if bitSize == 0 { - bitSize = IntSize - } else if bitSize < 0 || bitSize > 64 { - ret 0, ConvError.InvalidBitSize - } - - // Cutoff is the smallest number such that cutoff*base > u64.Max. - // Use compile-time constants for common cases. - mut cutoff := u64(0) - match base { - | 10: - cutoff = u64.Max / 10 + 1 - | 16: - cutoff = u64.Max / 16 + 1 - |: - cutoff = u64.Max / u64(base) + 1 - } - - mut maxVal := u64(0) - match bitSize { - | 32: - maxVal = u32.Max - | 64: - maxVal = u64.Max - } - - mut n := u64(0) - for _, c in s { - mut d := byte(0) - match { - | '0' <= c && c <= '9': - d = c - '0' - | 'a' <= lower(c) && lower(c) <= 'z': - d = lower(c) - 'a' + 10 - | c == '_': - continue - |: - ret 0, ConvError.InvalidSyntax - } - - if d >= byte(base) { - ret 0, ConvError.InvalidSyntax - } - - if n >= cutoff { - // n*base overflows - ret maxVal, ConvError.OutOfRange - } - n *= u64(base) - - n1 := n + u64(d) - if n1 < n || n1 > maxVal { - // n+d overflows - ret maxVal, ConvError.OutOfRange - } - n = n1 - } - - ret n, ConvError.Ok + if s == "" { + ret 0, ConvError.InvalidSyntax + } + + match { + | 2 <= base && base <= 36: + // valid base; nothing to do + | base == 0: + // Look for octal, hex prefix. + base = 10 + if s[0] == '0' { + match { + | len(s) >= 3 && lower(s[1]) == 'b': + base = 2 + s = s[2:] + | len(s) >= 3 && lower(s[1]) == 'o': + base = 8 + s = s[2:] + | len(s) >= 3 && lower(s[1]) == 'x': + base = 16 + s = s[2:] + |: + base = 8 + s = s[1:] + } + } + |: + ret 0, ConvError.InvalidBase + } + + if bitSize == 0 { + bitSize = IntSize + } else if bitSize < 0 || bitSize > 64 { + ret 0, ConvError.InvalidBitSize + } + + // Cutoff is the smallest number such that cutoff*base > u64.Max. + // Use compile-time constants for common cases. + mut cutoff := u64(0) + match base { + | 10: + cutoff = u64.Max / 10 + 1 + | 16: + cutoff = u64.Max / 16 + 1 + |: + cutoff = u64.Max / u64(base) + 1 + } + + mut maxVal := u64(0) + match bitSize { + | 32: + maxVal = u32.Max + | 64: + maxVal = u64.Max + } + + mut n := u64(0) + for _, c in s { + mut d := byte(0) + match { + | '0' <= c && c <= '9': + d = c - '0' + | 'a' <= lower(c) && lower(c) <= 'z': + d = lower(c) - 'a' + 10 + | c == '_': + continue + |: + ret 0, ConvError.InvalidSyntax + } + + if d >= byte(base) { + ret 0, ConvError.InvalidSyntax + } + + if n >= cutoff { + // n*base overflows + ret maxVal, ConvError.OutOfRange + } + n *= u64(base) + + n1 := n + u64(d) + if n1 < n || n1 > maxVal { + // n+d overflows + ret maxVal, ConvError.OutOfRange + } + n = n1 + } + + ret n, ConvError.Ok } // Is like ParseInt but for unsigned numbers. // // A sign prefix is not permitted. fn ParseUint(mut s: str, mut base: int, mut bitSize: int)!: u64 { - un, err := parseUint(s, base, bitSize) - if err != ConvError.Ok { - error(err) - } - ret un + un, err := parseUint(s, base, bitSize) + if err != ConvError.Ok { + error(err) + } + ret un } // Interprets a string s in the given base (0, 2 to 36) and @@ -170,44 +170,44 @@ fn ParseUint(mut s: str, mut base: int, mut bitSize: int)!: u64 { // if the value corresponding to s cannot be represented by a signed integer of // the given size, exception = ConvError.OutOfRange. fn ParseInt(mut s: str, base: int, mut bitSize: int)!: i64 { - if s == "" { - error(ConvError.InvalidSyntax) - } - - // Pick off leading sign. - mut neg := false - if s[0] == '+' { - s = s[1:] - } else if s[0] == '-' { - neg = true - s = s[1:] - } - - // Convert unsigned and check range. - mut un, err := parseUint(s, base, bitSize) - if err != ConvError.Ok && err != ConvError.OutOfRange { - error(err) - } - - if bitSize == 0 { - bitSize = IntSize - } - - cutoff := u64(1 << uint(bitSize - 1)) - if !neg && un >= cutoff { - error(ConvError.OutOfRange) - } - if neg && un > cutoff { - error(ConvError.OutOfRange) - } - mut n := i64(un) - if neg { - n = -n - } - ret n + if s == "" { + error(ConvError.InvalidSyntax) + } + + // Pick off leading sign. + mut neg := false + if s[0] == '+' { + s = s[1:] + } else if s[0] == '-' { + neg = true + s = s[1:] + } + + // Convert unsigned and check range. + mut un, err := parseUint(s, base, bitSize) + if err != ConvError.Ok && err != ConvError.OutOfRange { + error(err) + } + + if bitSize == 0 { + bitSize = IntSize + } + + cutoff := u64(1 << uint(bitSize - 1)) + if !neg && un >= cutoff { + error(ConvError.OutOfRange) + } + if neg && un > cutoff { + error(ConvError.OutOfRange) + } + mut n := i64(un) + if neg { + n = -n + } + ret n } // Is equivalent to ParseInt(s, 10, 0), converted to int. fn Atoi(s: str)!: int { - ret int(ParseInt(s, 10, 0) else { error(error) }) + ret int(ParseInt(s, 10, 0) else { error(error) }) } \ No newline at end of file diff --git a/std/conv/decimal.jule b/std/conv/decimal.jule index bc658f2c2..7de441881 100644 --- a/std/conv/decimal.jule +++ b/std/conv/decimal.jule @@ -57,16 +57,16 @@ const maxShift = uintSize - 4 // // Credit for this trick goes to Ken. struct leftCheat { - delta: int // number of new digits - cutoff: str // minus one digit if original < a. + delta: int // number of new digits + cutoff: str // minus one digit if original < a. } static leftCheats: []leftCheat = [ - // Leading digits of 1/2^i = 5^i. - // 5^23 is not an exact 64-bit floating point number, - // so have to use bc for the math. - // Go up to 60 to be large enough for 32bit and 64bit platforms. - /* + // Leading digits of 1/2^i = 5^i. + // 5^23 is not an exact 64-bit floating point number, + // so have to use bc for the math. + // Go up to 60 to be large enough for 32bit and 64bit platforms. + /* seq 60 | sed 's/^/5^/' | bc | awk 'BEGIN{ print "\t{ 0, \"\" }," } { @@ -74,339 +74,339 @@ static leftCheats: []leftCheat = [ printf("\t{ %d, \"%s\" },\t// * %d\n", int(log2*NR+1), $0, 2**NR) }' - */ - {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 + */ + {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 ] struct decimal { - d: [800]byte // digits, big-endian representation - nd: int // number of digits used - dp: int // decimal point - neg: bool // negative flag - trunc: bool // discarded nonzero digits beyond d[:nd] + d: [800]byte // digits, big-endian representation + nd: int // number of digits used + dp: int // decimal point + neg: bool // negative flag + trunc: bool // discarded nonzero digits beyond d[:nd] } impl decimal { - // Assign v. - fn assign(mut self, mut v: u64) { - let mut buf: [24]byte + // Assign v. + fn assign(mut self, mut v: u64) { + let mut buf: [24]byte - // Write reversed decimal in buf. - mut n := 0 - for v > 0 { - v1 := v / 10 - v -= 10 * v1 - buf[n] = byte(v + '0') - n++ - v = v1 - } + // Write reversed decimal in buf. + mut n := 0 + for v > 0 { + v1 := v / 10 + v -= 10 * v1 + buf[n] = byte(v + '0') + n++ + v = v1 + } - // Reverse again to produce forward decimal in a.d. - self.nd = 0 - n-- - for n >= 0; n-- { - self.d[self.nd] = buf[n] - self.nd++ - } - self.dp = self.nd - trim(self) - } + // Reverse again to produce forward decimal in a.d. + self.nd = 0 + n-- + for n >= 0; n-- { + self.d[self.nd] = buf[n] + self.nd++ + } + self.dp = self.nd + trim(self) + } - // Binary shift left (k > 0) or right (k < 0). - fn shift(mut self, mut k: int) { - match { - | self.nd == 0: - // nothing to do: a == 0 - | k > 0: - for k > maxShift { - leftShift(self, maxShift) - k -= maxShift - } - leftShift(self, uint(k)) - | k < 0: - for k < -maxShift { - rightShift(self, maxShift) - k += maxShift - } - rightShift(self, uint(-k)) - } - } + // Binary shift left (k > 0) or right (k < 0). + fn shift(mut self, mut k: int) { + match { + | self.nd == 0: + // nothing to do: a == 0 + | k > 0: + for k > maxShift { + leftShift(self, maxShift) + k -= maxShift + } + leftShift(self, uint(k)) + | k < 0: + for k < -maxShift { + rightShift(self, maxShift) + k += maxShift + } + rightShift(self, uint(-k)) + } + } - // Round a down to nd digits (or fewer). - fn roundDown(mut self, nd: int) { - if nd < 0 || nd >= self.nd { - ret - } - self.nd = nd - trim(self) - } + // Round a down to nd digits (or fewer). + fn roundDown(mut self, nd: int) { + if nd < 0 || nd >= self.nd { + ret + } + self.nd = nd + trim(self) + } - // Round a up to nd digits (or fewer). - fn roundUp(mut self, nd: int) { - if nd < 0 || nd >= self.nd { - ret - } + // Round a up to nd digits (or fewer). + fn roundUp(mut self, nd: int) { + if nd < 0 || nd >= self.nd { + ret + } - // round up - mut i := nd - 1 - for i >= 0; i-- { - c := self.d[i] - if c < '9' { // can stop after this digit - self.d[i]++ - self.nd = i + 1 - ret - } - } + // round up + mut i := nd - 1 + for i >= 0; i-- { + c := self.d[i] + if c < '9' { // can stop after this digit + self.d[i]++ + self.nd = i + 1 + ret + } + } - // Number is all 9s. - // Change to single 1 with adjusted decimal point. - self.d[0] = '1' - self.nd = 1 - self.dp++ - } + // Number is all 9s. + // Change to single 1 with adjusted decimal point. + self.d[0] = '1' + self.nd = 1 + self.dp++ + } - // Round a to nd digits (or fewer). - // If nd is zero, it means we're rounding - // just to the left of the digits, as in - // 0.09 -> 0.1. - fn round(mut self, nd: int) { - if nd < 0 || nd >= self.nd { - ret - } - if shouldRoundUp(self, nd) { - self.roundUp(nd) - } else { - self.roundDown(nd) - } - } + // Round a to nd digits (or fewer). + // If nd is zero, it means we're rounding + // just to the left of the digits, as in + // 0.09 -> 0.1. + fn round(mut self, nd: int) { + if nd < 0 || nd >= self.nd { + ret + } + if shouldRoundUp(self, nd) { + self.roundUp(nd) + } else { + self.roundDown(nd) + } + } - // Extract integer part, rounded appropriately. - // No guarantees about overflow. - fn roundedInteger(mut self): u64 { - if self.dp > 20 { - ret 0xFFFFFFFFFFFFFFFF - } - mut i := 0 - mut n := u64(0) - for i < self.dp && i < self.nd; i++ { - n = n * 10 + u64(self.d[i] - '0') - } - for i < self.dp; i++ { - n *= 10 - } - if shouldRoundUp(self, self.dp) { - n++ - } - ret n - } + // Extract integer part, rounded appropriately. + // No guarantees about overflow. + fn roundedInteger(mut self): u64 { + if self.dp > 20 { + ret 0xFFFFFFFFFFFFFFFF + } + mut i := 0 + mut n := u64(0) + for i < self.dp && i < self.nd; i++ { + n = n * 10 + u64(self.d[i] - '0') + } + for i < self.dp; i++ { + n *= 10 + } + if shouldRoundUp(self, self.dp) { + n++ + } + ret n + } } fn digitZero(mut dst: []byte): int { - for i in dst { - dst[i] = '0' - } - ret len(dst) + for i in dst { + dst[i] = '0' + } + ret len(dst) } // Trailing zeros from number. // (They are meaningless; the decimal point is tracked // independent of the number of digits.) fn trim(mut &a: decimal) { - for a.nd > 0 && a.d[a.nd-1] == '0' { - a.nd-- - } - if a.nd == 0 { - a.dp = 0 - } + for a.nd > 0 && a.d[a.nd-1] == '0' { + a.nd-- + } + if a.nd == 0 { + a.dp = 0 + } } // Binary shift right (/ 2) by k bits. k <= maxShift to avoid overflow. fn rightShift(mut &a: decimal, k: uint) { - mut r := 0 // read pointer - mut w := 0 // write pointer + mut r := 0 // read pointer + mut w := 0 // write pointer - // Pick up enough leading digits to cover first shift. - mut n := uint(0) - for n>>k == 0; r++ { - if r >= a.nd { - if n == 0 { - // a == 0; shouldn't get here, but handle anyway. - a.nd = 0 - ret - } - for n>>k == 0 { - n = n * 10 - r++ - } - break - } - c := uint(a.d[r]) - n = n * 10 + c - '0' - } - a.dp -= r - 1 + // Pick up enough leading digits to cover first shift. + mut n := uint(0) + for n>>k == 0; r++ { + if r >= a.nd { + if n == 0 { + // a == 0; shouldn't get here, but handle anyway. + a.nd = 0 + ret + } + for n>>k == 0 { + n = n * 10 + r++ + } + break + } + c := uint(a.d[r]) + n = n * 10 + c - '0' + } + a.dp -= r - 1 - mask := uint(1 << k) - 1 + mask := uint(1 << k) - 1 - // Pick up a digit, put down a digit. - for r < a.nd; r++ { - c := uint(a.d[r]) - dig := n >> k - n &= mask - a.d[w] = byte(dig + '0') - w++ - n = n * 10 + c - '0' - } + // Pick up a digit, put down a digit. + for r < a.nd; r++ { + c := uint(a.d[r]) + dig := n >> k + n &= mask + a.d[w] = byte(dig + '0') + w++ + n = n * 10 + c - '0' + } - // Put down extra digits. - for n > 0 { - dig := n >> k - n &= mask - if w < len(a.d) { - a.d[w] = byte(dig + '0') - w++ - } else if dig > 0 { - a.trunc = true - } - n = n * 10 - } + // Put down extra digits. + for n > 0 { + dig := n >> k + n &= mask + if w < len(a.d) { + a.d[w] = byte(dig + '0') + w++ + } else if dig > 0 { + a.trunc = true + } + n = n * 10 + } - a.nd = w - trim(a) + a.nd = w + trim(a) } // Is the leading prefix of b lexicographically less than s? fn prefixIsLessThan(b: [800]byte, end: int, &s: str): bool { - mut i := 0 - for i < len(s); i++ { - if i >= end { - ret true - } - if b[i] != s[i] { - ret b[i] < s[i] - } - } - ret false + mut i := 0 + for i < len(s); i++ { + if i >= end { + ret true + } + if b[i] != s[i] { + ret b[i] < s[i] + } + } + ret false } // Binary shift left (* 2) by k bits. k <= maxShift to avoid overflow. fn leftShift(mut &a: decimal, k: uint) { - mut delta := leftCheats[k].delta - if prefixIsLessThan(a.d, a.nd, unsafe { *(&leftCheats[k].cutoff) }) { - delta-- - } + mut delta := leftCheats[k].delta + if prefixIsLessThan(a.d, a.nd, unsafe { *(&leftCheats[k].cutoff) }) { + delta-- + } - mut r := a.nd // read index - mut w := a.nd + delta // write index + mut r := a.nd // read index + mut w := a.nd + delta // write index - // Pick up a digit, put down a digit. - mut n := uint(0) - r-- - for r >= 0; r-- { - n += (uint(a.d[r]) - '0') << k - quo := n / 10 - rem := n - 10 * quo - w-- - if w < len(a.d) { - a.d[w] = byte(rem + '0') - } else if rem != 0 { - a.trunc = true - } - n = quo - } + // Pick up a digit, put down a digit. + mut n := uint(0) + r-- + for r >= 0; r-- { + n += (uint(a.d[r]) - '0') << k + quo := n / 10 + rem := n - 10 * quo + w-- + if w < len(a.d) { + a.d[w] = byte(rem + '0') + } else if rem != 0 { + a.trunc = true + } + n = quo + } - // Put down extra digits. - for n > 0 { - quo := n / 10 - rem := n - 10 * quo - w-- - if w < len(a.d) { - a.d[w] = byte(rem + '0') - } else if rem != 0 { - a.trunc = true - } - n = quo - } + // Put down extra digits. + for n > 0 { + quo := n / 10 + rem := n - 10 * quo + w-- + if w < len(a.d) { + a.d[w] = byte(rem + '0') + } else if rem != 0 { + a.trunc = true + } + n = quo + } - a.nd += delta - if a.nd >= len(a.d) { - a.nd = len(a.d) - } - a.dp += delta - trim(a) + a.nd += delta + if a.nd >= len(a.d) { + a.nd = len(a.d) + } + a.dp += delta + trim(a) } // If we chop a at nd digits, should we round up? fn shouldRoundUp(&a: decimal, nd: int): bool { - if nd < 0 || nd >= a.nd { - ret false - } - if a.d[nd] == '5' && nd+1 == a.nd { // exactly halfway - round to even - // if we truncated, a little higher than what's recorded - always round up - if a.trunc { - ret true - } - ret nd > 0 && (a.d[nd-1]-'0')%2 != 0 - } - // not halfway - digit tells all - ret a.d[nd] >= '5' + if nd < 0 || nd >= a.nd { + ret false + } + if a.d[nd] == '5' && nd+1 == a.nd { // exactly halfway - round to even + // if we truncated, a little higher than what's recorded - always round up + if a.trunc { + ret true + } + ret nd > 0 && (a.d[nd-1]-'0')%2 != 0 + } + // not halfway - digit tells all + ret a.d[nd] >= '5' } \ No newline at end of file diff --git a/std/conv/eisel_lemire.jule b/std/conv/eisel_lemire.jule index 55719be9e..c28a17ba0 100644 --- a/std/conv/eisel_lemire.jule +++ b/std/conv/eisel_lemire.jule @@ -39,147 +39,147 @@ use math for std::math use bits for std::math::bits fn eiselLemire64(mut man: u64, exp10: int, neg: bool): (f: f64, ok: bool) { - // The terse comments in this function body refer to sections of the - // https://nigeltao.github.io/blog/2020/eisel-lemire.html blog post. + // The terse comments in this function body refer to sections of the + // https://nigeltao.github.io/blog/2020/eisel-lemire.html blog post. - // Exp10 Range. - if man == 0 { - if neg { - f = math::F64FromBits(0x8000000000000000) // Negative zero. - } - ret f, true - } - if exp10 < detailedPowsOfTenMinExp10 || detailedPowsOfTenMaxExp10 < exp10 { - ret 0, false - } + // Exp10 Range. + if man == 0 { + if neg { + f = math::F64FromBits(0x8000000000000000) // Negative zero. + } + ret f, true + } + if exp10 < detailedPowsOfTenMinExp10 || detailedPowsOfTenMaxExp10 < exp10 { + ret 0, false + } - // Normalization. - clz := bits::LeadingZeros64(man) - man <<= uint(clz) - const f64ExponentBias = 1023 - mut retExp2 := u64(217706 * exp10 >> 16 + 64 + f64ExponentBias) - u64(clz) + // Normalization. + clz := bits::LeadingZeros64(man) + man <<= uint(clz) + const f64ExponentBias = 1023 + mut retExp2 := u64(217706 * exp10 >> 16 + 64 + f64ExponentBias) - u64(clz) - // Multiplication. - mut xHi, mut xLo := bits::Mul64(man, detailedPowsOfTen[exp10-detailedPowsOfTenMinExp10][1]) + // Multiplication. + mut xHi, mut xLo := bits::Mul64(man, detailedPowsOfTen[exp10-detailedPowsOfTenMinExp10][1]) - // Wider Approximation. - if xHi&0x1FF == 0x1FF && xLo+man < man { - yHi, yLo := bits::Mul64(man, detailedPowsOfTen[exp10-detailedPowsOfTenMinExp10][0]) - mut mergedHi, mergedLo := xHi, xLo + yHi - if mergedLo < xLo { - mergedHi++ - } - if mergedHi&0x1FF == 0x1FF && mergedLo+1 == 0 && yLo+man < man { - ret 0, false - } - xHi, xLo = mergedHi, mergedLo - } + // Wider Approximation. + if xHi&0x1FF == 0x1FF && xLo+man < man { + yHi, yLo := bits::Mul64(man, detailedPowsOfTen[exp10-detailedPowsOfTenMinExp10][0]) + mut mergedHi, mergedLo := xHi, xLo + yHi + if mergedLo < xLo { + mergedHi++ + } + if mergedHi&0x1FF == 0x1FF && mergedLo+1 == 0 && yLo+man < man { + ret 0, false + } + xHi, xLo = mergedHi, mergedLo + } - // Shifting to 54 Bits. - msb := xHi >> 63 - mut retMantissa := xHi >> (msb + 9) - retExp2 -= 1 ^ msb + // Shifting to 54 Bits. + msb := xHi >> 63 + mut retMantissa := xHi >> (msb + 9) + retExp2 -= 1 ^ msb - // Half-way Ambiguity. - if xLo == 0 && xHi&0x1FF == 0 && retMantissa&3 == 1 { - ret 0, false - } + // Half-way Ambiguity. + if xLo == 0 && xHi&0x1FF == 0 && retMantissa&3 == 1 { + ret 0, false + } - // From 54 to 53 Bits. - retMantissa += retMantissa & 1 - retMantissa >>= 1 - if retMantissa>>53 > 0 { - retMantissa >>= 1 - retExp2 += 1 - } - // ret_exp2 is a u64. Zero or underflow means that we're in subnormal - // f64 space. 0x7FF or above means that we're in inf/NaN f64 space. - // - // The if block is equivalent to (but has fewer branches than): - // if retExp2 <= 0 || retExp2 >= 0x7FF { etc } - if retExp2-1 >= 0x7FF-1 { - ret 0, false - } - mut retBits := retExp2 << 52 | retMantissa & 0x000FFFFFFFFFFFFF - if neg { - retBits |= 0x8000000000000000 - } - ret math::F64FromBits(retBits), true + // From 54 to 53 Bits. + retMantissa += retMantissa & 1 + retMantissa >>= 1 + if retMantissa>>53 > 0 { + retMantissa >>= 1 + retExp2 += 1 + } + // ret_exp2 is a u64. Zero or underflow means that we're in subnormal + // f64 space. 0x7FF or above means that we're in inf/NaN f64 space. + // + // The if block is equivalent to (but has fewer branches than): + // if retExp2 <= 0 || retExp2 >= 0x7FF { etc } + if retExp2-1 >= 0x7FF-1 { + ret 0, false + } + mut retBits := retExp2 << 52 | retMantissa & 0x000FFFFFFFFFFFFF + if neg { + retBits |= 0x8000000000000000 + } + ret math::F64FromBits(retBits), true } fn eiselLemire32(mut man: u64, exp10: int, neg: bool): (f: f32, ok: bool) { - // The terse comments in this function body refer to sections of the - // https://nigeltao.github.io/blog/2020/eisel-lemire.html blog post. - // - // That blog post discusses the f64 flavor (11 exponent bits with a - // -1023 bias, 52 mantissa bits) of the algorithm, but the same approach - // applies to the f32 flavor (8 exponent bits with a -127 bias, 23 - // mantissa bits). The computation here happens with 64-bit values (e.g. - // man, x_hi, ret_mantissa) before finally converting to a 32-bit float. + // The terse comments in this function body refer to sections of the + // https://nigeltao.github.io/blog/2020/eisel-lemire.html blog post. + // + // That blog post discusses the f64 flavor (11 exponent bits with a + // -1023 bias, 52 mantissa bits) of the algorithm, but the same approach + // applies to the f32 flavor (8 exponent bits with a -127 bias, 23 + // mantissa bits). The computation here happens with 64-bit values (e.g. + // man, x_hi, ret_mantissa) before finally converting to a 32-bit float. - // Exp10 Range. - if man == 0 { - if neg { - f = math::F32FromBits(0x80000000) // Negative zero. - } - ret f, true - } - if exp10 < detailedPowsOfTenMinExp10 || detailedPowsOfTenMaxExp10 < exp10 { - ret 0, false - } + // Exp10 Range. + if man == 0 { + if neg { + f = math::F32FromBits(0x80000000) // Negative zero. + } + ret f, true + } + if exp10 < detailedPowsOfTenMinExp10 || detailedPowsOfTenMaxExp10 < exp10 { + ret 0, false + } - // Normalization. - clz := bits::LeadingZeros64(man) - man <<= uint(clz) - const f32ExponentBias = 127 - mut retExp2 := u64(217706 * exp10 >> 16 + 64 + f32ExponentBias) - u64(clz) + // Normalization. + clz := bits::LeadingZeros64(man) + man <<= uint(clz) + const f32ExponentBias = 127 + mut retExp2 := u64(217706 * exp10 >> 16 + 64 + f32ExponentBias) - u64(clz) - // Multiplication. - mut x_hi, mut x_lo := bits::Mul64(man, detailedPowsOfTen[exp10-detailedPowsOfTenMinExp10][1]) + // Multiplication. + mut x_hi, mut x_lo := bits::Mul64(man, detailedPowsOfTen[exp10-detailedPowsOfTenMinExp10][1]) - // Wider Approximation. - if x_hi&0x3FFFFFFFFF == 0x3FFFFFFFFF && x_lo+man < man { - y_hi, y_lo := bits::Mul64(man, detailedPowsOfTen[exp10-detailedPowsOfTenMinExp10][0]) - mut merged_hi, merged_lo := x_hi, x_lo + y_hi - if merged_lo < x_lo { - merged_hi++ - } - if merged_hi&0x3FFFFFFFFF == 0x3FFFFFFFFF && merged_lo+1 == 0 && y_lo+man < man { - ret 0, false - } - x_hi, x_lo = merged_hi, merged_lo - } + // Wider Approximation. + if x_hi&0x3FFFFFFFFF == 0x3FFFFFFFFF && x_lo+man < man { + y_hi, y_lo := bits::Mul64(man, detailedPowsOfTen[exp10-detailedPowsOfTenMinExp10][0]) + mut merged_hi, merged_lo := x_hi, x_lo + y_hi + if merged_lo < x_lo { + merged_hi++ + } + if merged_hi&0x3FFFFFFFFF == 0x3FFFFFFFFF && merged_lo+1 == 0 && y_lo+man < man { + ret 0, false + } + x_hi, x_lo = merged_hi, merged_lo + } - // Shifting to 54 Bits (and for float32, it's shifting to 25 bits). - msb := x_hi >> 63 - mut retMantissa := x_hi >> (msb + 38) - retExp2 -= 1 ^ msb + // Shifting to 54 Bits (and for float32, it's shifting to 25 bits). + msb := x_hi >> 63 + mut retMantissa := x_hi >> (msb + 38) + retExp2 -= 1 ^ msb - // Half-way Ambiguity. - if x_lo == 0 && x_hi&0x3FFFFFFFFF == 0 && retMantissa&3 == 1 { - ret 0, false - } + // Half-way Ambiguity. + if x_lo == 0 && x_hi&0x3FFFFFFFFF == 0 && retMantissa&3 == 1 { + ret 0, false + } - // From 54 to 53 Bits (and for f32, it's from 25 to 24 bits). - retMantissa += retMantissa & 1 - retMantissa >>= 1 - if retMantissa>>24 > 0 { - retMantissa >>= 1 - retExp2 += 1 - } - // retExp2 is a u64. Zero or underflow means that we're in subnormal - // f32 space. 0xFF or above means that we're in inf/NaN f32 space. - // - // The if block is equivalent to (but has fewer branches than): - // if retExp2 <= 0 || retExp2 >= 0xFF { etc } - if retExp2-1 >= 0xFF-1 { - ret 0, false - } - mut retBits := retExp2 << 23 | retMantissa & 0x007FFFFF - if neg { - retBits |= 0x80000000 - } - ret math::F32FromBits(u32(retBits)), true + // From 54 to 53 Bits (and for f32, it's from 25 to 24 bits). + retMantissa += retMantissa & 1 + retMantissa >>= 1 + if retMantissa>>24 > 0 { + retMantissa >>= 1 + retExp2 += 1 + } + // retExp2 is a u64. Zero or underflow means that we're in subnormal + // f32 space. 0xFF or above means that we're in inf/NaN f32 space. + // + // The if block is equivalent to (but has fewer branches than): + // if retExp2 <= 0 || retExp2 >= 0xFF { etc } + if retExp2-1 >= 0xFF-1 { + ret 0, false + } + mut retBits := retExp2 << 23 | retMantissa & 0x007FFFFF + if neg { + retBits |= 0x80000000 + } + ret math::F32FromBits(u32(retBits)), true } // detailed_pows_of_ten{min,max}exp10 is the power of 10 represented by the @@ -199,700 +199,700 @@ const detailedPowsOfTenMaxExp10 = +347 // The table based of this generated table: // https://github.com/google/wuffs/blob/ba3818cb6b473a2ed0b38ecfc07dbbd3a97e8ae7/script/print-mpb-powers-of-10.go static detailedPowsOfTen: [...][2]u64 = [ - [0x1732C869CD60E453, 0xFA8FD5A0081C0288], // 1e-348 - [0x0E7FBD42205C8EB4, 0x9C99E58405118195], // 1e-347 - [0x521FAC92A873B261, 0xC3C05EE50655E1FA], // 1e-346 - [0xE6A797B752909EF9, 0xF4B0769E47EB5A78], // 1e-345 - [0x9028BED2939A635C, 0x98EE4A22ECF3188B], // 1e-344 - [0x7432EE873880FC33, 0xBF29DCABA82FDEAE], // 1e-343 - [0x113FAA2906A13B3F, 0xEEF453D6923BD65A], // 1e-342 - [0x4AC7CA59A424C507, 0x9558B4661B6565F8], // 1e-341 - [0x5D79BCF00D2DF649, 0xBAAEE17FA23EBF76], // 1e-340 - [0xF4D82C2C107973DC, 0xE95A99DF8ACE6F53], // 1e-339 - [0x79071B9B8A4BE869, 0x91D8A02BB6C10594], // 1e-338 - [0x9748E2826CDEE284, 0xB64EC836A47146F9], // 1e-337 - [0xFD1B1B2308169B25, 0xE3E27A444D8D98B7], // 1e-336 - [0xFE30F0F5E50E20F7, 0x8E6D8C6AB0787F72], // 1e-335 - [0xBDBD2D335E51A935, 0xB208EF855C969F4F], // 1e-334 - [0xAD2C788035E61382, 0xDE8B2B66B3BC4723], // 1e-333 - [0x4C3BCB5021AFCC31, 0x8B16FB203055AC76], // 1e-332 - [0xDF4ABE242A1BBF3D, 0xADDCB9E83C6B1793], // 1e-331 - [0xD71D6DAD34A2AF0D, 0xD953E8624B85DD78], // 1e-330 - [0x8672648C40E5AD68, 0x87D4713D6F33AA6B], // 1e-329 - [0x680EFDAF511F18C2, 0xA9C98D8CCB009506], // 1e-328 - [0x0212BD1B2566DEF2, 0xD43BF0EFFDC0BA48], // 1e-327 - [0x014BB630F7604B57, 0x84A57695FE98746D], // 1e-326 - [0x419EA3BD35385E2D, 0xA5CED43B7E3E9188], // 1e-325 - [0x52064CAC828675B9, 0xCF42894A5DCE35EA], // 1e-324 - [0x7343EFEBD1940993, 0x818995CE7AA0E1B2], // 1e-323 - [0x1014EBE6C5F90BF8, 0xA1EBFB4219491A1F], // 1e-322 - [0xD41A26E077774EF6, 0xCA66FA129F9B60A6], // 1e-321 - [0x8920B098955522B4, 0xFD00B897478238D0], // 1e-320 - [0x55B46E5F5D5535B0, 0x9E20735E8CB16382], // 1e-319 - [0xEB2189F734AA831D, 0xC5A890362FDDBC62], // 1e-318 - [0xA5E9EC7501D523E4, 0xF712B443BBD52B7B], // 1e-317 - [0x47B233C92125366E, 0x9A6BB0AA55653B2D], // 1e-316 - [0x999EC0BB696E840A, 0xC1069CD4EABE89F8], // 1e-315 - [0xC00670EA43CA250D, 0xF148440A256E2C76], // 1e-314 - [0x380406926A5E5728, 0x96CD2A865764DBCA], // 1e-313 - [0xC605083704F5ECF2, 0xBC807527ED3E12BC], // 1e-312 - [0xF7864A44C633682E, 0xEBA09271E88D976B], // 1e-311 - [0x7AB3EE6AFBE0211D, 0x93445B8731587EA3], // 1e-310 - [0x5960EA05BAD82964, 0xB8157268FDAE9E4C], // 1e-309 - [0x6FB92487298E33BD, 0xE61ACF033D1A45DF], // 1e-308 - [0xA5D3B6D479F8E056, 0x8FD0C16206306BAB], // 1e-307 - [0x8F48A4899877186C, 0xB3C4F1BA87BC8696], // 1e-306 - [0x331ACDABFE94DE87, 0xE0B62E2929ABA83C], // 1e-305 - [0x9FF0C08B7F1D0B14, 0x8C71DCD9BA0B4925], // 1e-304 - [0x07ECF0AE5EE44DD9, 0xAF8E5410288E1B6F], // 1e-303 - [0xC9E82CD9F69D6150, 0xDB71E91432B1A24A], // 1e-302 - [0xBE311C083A225CD2, 0x892731AC9FAF056E], // 1e-301 - [0x6DBD630A48AAF406, 0xAB70FE17C79AC6CA], // 1e-300 - [0x092CBBCCDAD5B108, 0xD64D3D9DB981787D], // 1e-299 - [0x25BBF56008C58EA5, 0x85F0468293F0EB4E], // 1e-298 - [0xAF2AF2B80AF6F24E, 0xA76C582338ED2621], // 1e-297 - [0x1AF5AF660DB4AEE1, 0xD1476E2C07286FAA], // 1e-296 - [0x50D98D9FC890ED4D, 0x82CCA4DB847945CA], // 1e-295 - [0xE50FF107BAB528A0, 0xA37FCE126597973C], // 1e-294 - [0x1E53ED49A96272C8, 0xCC5FC196FEFD7D0C], // 1e-293 - [0x25E8E89C13BB0F7A, 0xFF77B1FCBEBCDC4F], // 1e-292 - [0x77B191618C54E9AC, 0x9FAACF3DF73609B1], // 1e-291 - [0xD59DF5B9EF6A2417, 0xC795830D75038C1D], // 1e-290 - [0x4B0573286B44AD1D, 0xF97AE3D0D2446F25], // 1e-289 - [0x4EE367F9430AEC32, 0x9BECCE62836AC577], // 1e-288 - [0x229C41F793CDA73F, 0xC2E801FB244576D5], // 1e-287 - [0x6B43527578C1110F, 0xF3A20279ED56D48A], // 1e-286 - [0x830A13896B78AAA9, 0x9845418C345644D6], // 1e-285 - [0x23CC986BC656D553, 0xBE5691EF416BD60C], // 1e-284 - [0x2CBFBE86B7EC8AA8, 0xEDEC366B11C6CB8F], // 1e-283 - [0x7BF7D71432F3D6A9, 0x94B3A202EB1C3F39], // 1e-282 - [0xDAF5CCD93FB0CC53, 0xB9E08A83A5E34F07], // 1e-281 - [0xD1B3400F8F9CFF68, 0xE858AD248F5C22C9], // 1e-280 - [0x23100809B9C21FA1, 0x91376C36D99995BE], // 1e-279 - [0xABD40A0C2832A78A, 0xB58547448FFFFB2D], // 1e-278 - [0x16C90C8F323F516C, 0xE2E69915B3FFF9F9], // 1e-277 - [0xAE3DA7D97F6792E3, 0x8DD01FAD907FFC3B], // 1e-276 - [0x99CD11CFDF41779C, 0xB1442798F49FFB4A], // 1e-275 - [0x40405643D711D583, 0xDD95317F31C7FA1D], // 1e-274 - [0x482835EA666B2572, 0x8A7D3EEF7F1CFC52], // 1e-273 - [0xDA3243650005EECF, 0xAD1C8EAB5EE43B66], // 1e-272 - [0x90BED43E40076A82, 0xD863B256369D4A40], // 1e-271 - [0x5A7744A6E804A291, 0x873E4F75E2224E68], // 1e-270 - [0x711515D0A205CB36, 0xA90DE3535AAAE202], // 1e-269 - [0x0D5A5B44CA873E03, 0xD3515C2831559A83], // 1e-268 - [0xE858790AFE9486C2, 0x8412D9991ED58091], // 1e-267 - [0x626E974DBE39A872, 0xA5178FFF668AE0B6], // 1e-266 - [0xFB0A3D212DC8128F, 0xCE5D73FF402D98E3], // 1e-265 - [0x7CE66634BC9D0B99, 0x80FA687F881C7F8E], // 1e-264 - [0x1C1FFFC1EBC44E80, 0xA139029F6A239F72], // 1e-263 - [0xA327FFB266B56220, 0xC987434744AC874E], // 1e-262 - [0x4BF1FF9F0062BAA8, 0xFBE9141915D7A922], // 1e-261 - [0x6F773FC3603DB4A9, 0x9D71AC8FADA6C9B5], // 1e-260 - [0xCB550FB4384D21D3, 0xC4CE17B399107C22], // 1e-259 - [0x7E2A53A146606A48, 0xF6019DA07F549B2B], // 1e-258 - [0x2EDA7444CBFC426D, 0x99C102844F94E0FB], // 1e-257 - [0xFA911155FEFB5308, 0xC0314325637A1939], // 1e-256 - [0x793555AB7EBA27CA, 0xF03D93EEBC589F88], // 1e-255 - [0x4BC1558B2F3458DE, 0x96267C7535B763B5], // 1e-254 - [0x9EB1AAEDFB016F16, 0xBBB01B9283253CA2], // 1e-253 - [0x465E15A979C1CADC, 0xEA9C227723EE8BCB], // 1e-252 - [0x0BFACD89EC191EC9, 0x92A1958A7675175F], // 1e-251 - [0xCEF980EC671F667B, 0xB749FAED14125D36], // 1e-250 - [0x82B7E12780E7401A, 0xE51C79A85916F484], // 1e-249 - [0xD1B2ECB8B0908810, 0x8F31CC0937AE58D2], // 1e-248 - [0x861FA7E6DCB4AA15, 0xB2FE3F0B8599EF07], // 1e-247 - [0x67A791E093E1D49A, 0xDFBDCECE67006AC9], // 1e-246 - [0xE0C8BB2C5C6D24E0, 0x8BD6A141006042BD], // 1e-245 - [0x58FAE9F773886E18, 0xAECC49914078536D], // 1e-244 - [0xAF39A475506A899E, 0xDA7F5BF590966848], // 1e-243 - [0x6D8406C952429603, 0x888F99797A5E012D], // 1e-242 - [0xC8E5087BA6D33B83, 0xAAB37FD7D8F58178], // 1e-241 - [0xFB1E4A9A90880A64, 0xD5605FCDCF32E1D6], // 1e-240 - [0x5CF2EEA09A55067F, 0x855C3BE0A17FCD26], // 1e-239 - [0xF42FAA48C0EA481E, 0xA6B34AD8C9DFC06F], // 1e-238 - [0xF13B94DAF124DA26, 0xD0601D8EFC57B08B], // 1e-237 - [0x76C53D08D6B70858, 0x823C12795DB6CE57], // 1e-236 - [0x54768C4B0C64CA6E, 0xA2CB1717B52481ED], // 1e-235 - [0xA9942F5DCF7DFD09, 0xCB7DDCDDA26DA268], // 1e-234 - [0xD3F93B35435D7C4C, 0xFE5D54150B090B02], // 1e-233 - [0xC47BC5014A1A6DAF, 0x9EFA548D26E5A6E1], // 1e-232 - [0x359AB6419CA1091B, 0xC6B8E9B0709F109A], // 1e-231 - [0xC30163D203C94B62, 0xF867241C8CC6D4C0], // 1e-230 - [0x79E0DE63425DCF1D, 0x9B407691D7FC44F8], // 1e-229 - [0x985915FC12F542E4, 0xC21094364DFB5636], // 1e-228 - [0x3E6F5B7B17B2939D, 0xF294B943E17A2BC4], // 1e-227 - [0xA705992CEECF9C42, 0x979CF3CA6CEC5B5A], // 1e-226 - [0x50C6FF782A838353, 0xBD8430BD08277231], // 1e-225 - [0xA4F8BF5635246428, 0xECE53CEC4A314EBD], // 1e-224 - [0x871B7795E136BE99, 0x940F4613AE5ED136], // 1e-223 - [0x28E2557B59846E3F, 0xB913179899F68584], // 1e-222 - [0x331AEADA2FE589CF, 0xE757DD7EC07426E5], // 1e-221 - [0x3FF0D2C85DEF7621, 0x9096EA6F3848984F], // 1e-220 - [0x0FED077A756B53A9, 0xB4BCA50B065ABE63], // 1e-219 - [0xD3E8495912C62894, 0xE1EBCE4DC7F16DFB], // 1e-218 - [0x64712DD7ABBBD95C, 0x8D3360F09CF6E4BD], // 1e-217 - [0xBD8D794D96AACFB3, 0xB080392CC4349DEC], // 1e-216 - [0xECF0D7A0FC5583A0, 0xDCA04777F541C567], // 1e-215 - [0xF41686C49DB57244, 0x89E42CAAF9491B60], // 1e-214 - [0x311C2875C522CED5, 0xAC5D37D5B79B6239], // 1e-213 - [0x7D633293366B828B, 0xD77485CB25823AC7], // 1e-212 - [0xAE5DFF9C02033197, 0x86A8D39EF77164BC], // 1e-211 - [0xD9F57F830283FDFC, 0xA8530886B54DBDEB], // 1e-210 - [0xD072DF63C324FD7B, 0xD267CAA862A12D66], // 1e-209 - [0x4247CB9E59F71E6D, 0x8380DEA93DA4BC60], // 1e-208 - [0x52D9BE85F074E608, 0xA46116538D0DEB78], // 1e-207 - [0x67902E276C921F8B, 0xCD795BE870516656], // 1e-206 - [0x00BA1CD8A3DB53B6, 0x806BD9714632DFF6], // 1e-205 - [0x80E8A40ECCD228A4, 0xA086CFCD97BF97F3], // 1e-204 - [0x6122CD128006B2CD, 0xC8A883C0FDAF7DF0], // 1e-203 - [0x796B805720085F81, 0xFAD2A4B13D1B5D6C], // 1e-202 - [0xCBE3303674053BB0, 0x9CC3A6EEC6311A63], // 1e-201 - [0xBEDBFC4411068A9C, 0xC3F490AA77BD60FC], // 1e-200 - [0xEE92FB5515482D44, 0xF4F1B4D515ACB93B], // 1e-199 - [0x751BDD152D4D1C4A, 0x991711052D8BF3C5], // 1e-198 - [0xD262D45A78A0635D, 0xBF5CD54678EEF0B6], // 1e-197 - [0x86FB897116C87C34, 0xEF340A98172AACE4], // 1e-196 - [0xD45D35E6AE3D4DA0, 0x9580869F0E7AAC0E], // 1e-195 - [0x8974836059CCA109, 0xBAE0A846D2195712], // 1e-194 - [0x2BD1A438703FC94B, 0xE998D258869FACD7], // 1e-193 - [0x7B6306A34627DDCF, 0x91FF83775423CC06], // 1e-192 - [0x1A3BC84C17B1D542, 0xB67F6455292CBF08], // 1e-191 - [0x20CABA5F1D9E4A93, 0xE41F3D6A7377EECA], // 1e-190 - [0x547EB47B7282EE9C, 0x8E938662882AF53E], // 1e-189 - [0xE99E619A4F23AA43, 0xB23867FB2A35B28D], // 1e-188 - [0x6405FA00E2EC94D4, 0xDEC681F9F4C31F31], // 1e-187 - [0xDE83BC408DD3DD04, 0x8B3C113C38F9F37E], // 1e-186 - [0x9624AB50B148D445, 0xAE0B158B4738705E], // 1e-185 - [0x3BADD624DD9B0957, 0xD98DDAEE19068C76], // 1e-184 - [0xE54CA5D70A80E5D6, 0x87F8A8D4CFA417C9], // 1e-183 - [0x5E9FCF4CCD211F4C, 0xA9F6D30A038D1DBC], // 1e-182 - [0x7647C3200069671F, 0xD47487CC8470652B], // 1e-181 - [0x29ECD9F40041E073, 0x84C8D4DFD2C63F3B], // 1e-180 - [0xF468107100525890, 0xA5FB0A17C777CF09], // 1e-179 - [0x7182148D4066EEB4, 0xCF79CC9DB955C2CC], // 1e-178 - [0xC6F14CD848405530, 0x81AC1FE293D599BF], // 1e-177 - [0xB8ADA00E5A506A7C, 0xA21727DB38CB002F], // 1e-176 - [0xA6D90811F0E4851C, 0xCA9CF1D206FDC03B], // 1e-175 - [0x908F4A166D1DA663, 0xFD442E4688BD304A], // 1e-174 - [0x9A598E4E043287FE, 0x9E4A9CEC15763E2E], // 1e-173 - [0x40EFF1E1853F29FD, 0xC5DD44271AD3CDBA], // 1e-172 - [0xD12BEE59E68EF47C, 0xF7549530E188C128], // 1e-171 - [0x82BB74F8301958CE, 0x9A94DD3E8CF578B9], // 1e-170 - [0xE36A52363C1FAF01, 0xC13A148E3032D6E7], // 1e-169 - [0xDC44E6C3CB279AC1, 0xF18899B1BC3F8CA1], // 1e-168 - [0x29AB103A5EF8C0B9, 0x96F5600F15A7B7E5], // 1e-167 - [0x7415D448F6B6F0E7, 0xBCB2B812DB11A5DE], // 1e-166 - [0x111B495B3464AD21, 0xEBDF661791D60F56], // 1e-165 - [0xCAB10DD900BEEC34, 0x936B9FCEBB25C995], // 1e-164 - [0x3D5D514F40EEA742, 0xB84687C269EF3BFB], // 1e-163 - [0x0CB4A5A3112A5112, 0xE65829B3046B0AFA], // 1e-162 - [0x47F0E785EABA72AB, 0x8FF71A0FE2C2E6DC], // 1e-161 - [0x59ED216765690F56, 0xB3F4E093DB73A093], // 1e-160 - [0x306869C13EC3532C, 0xE0F218B8D25088B8], // 1e-159 - [0x1E414218C73A13FB, 0x8C974F7383725573], // 1e-158 - [0xE5D1929EF90898FA, 0xAFBD2350644EEACF], // 1e-157 - [0xDF45F746B74ABF39, 0xDBAC6C247D62A583], // 1e-156 - [0x6B8BBA8C328EB783, 0x894BC396CE5DA772], // 1e-155 - [0x066EA92F3F326564, 0xAB9EB47C81F5114F], // 1e-154 - [0xC80A537B0EFEFEBD, 0xD686619BA27255A2], // 1e-153 - [0xBD06742CE95F5F36, 0x8613FD0145877585], // 1e-152 - [0x2C48113823B73704, 0xA798FC4196E952E7], // 1e-151 - [0xF75A15862CA504C5, 0xD17F3B51FCA3A7A0], // 1e-150 - [0x9A984D73DBE722FB, 0x82EF85133DE648C4], // 1e-149 - [0xC13E60D0D2E0EBBA, 0xA3AB66580D5FDAF5], // 1e-148 - [0x318DF905079926A8, 0xCC963FEE10B7D1B3], // 1e-147 - [0xFDF17746497F7052, 0xFFBBCFE994E5C61F], // 1e-146 - [0xFEB6EA8BEDEFA633, 0x9FD561F1FD0F9BD3], // 1e-145 - [0xFE64A52EE96B8FC0, 0xC7CABA6E7C5382C8], // 1e-144 - [0x3DFDCE7AA3C673B0, 0xF9BD690A1B68637B], // 1e-143 - [0x06BEA10CA65C084E, 0x9C1661A651213E2D], // 1e-142 - [0x486E494FCFF30A62, 0xC31BFA0FE5698DB8], // 1e-141 - [0x5A89DBA3C3EFCCFA, 0xF3E2F893DEC3F126], // 1e-140 - [0xF89629465A75E01C, 0x986DDB5C6B3A76B7], // 1e-139 - [0xF6BBB397F1135823, 0xBE89523386091465], // 1e-138 - [0x746AA07DED582E2C, 0xEE2BA6C0678B597F], // 1e-137 - [0xA8C2A44EB4571CDC, 0x94DB483840B717EF], // 1e-136 - [0x92F34D62616CE413, 0xBA121A4650E4DDEB], // 1e-135 - [0x77B020BAF9C81D17, 0xE896A0D7E51E1566], // 1e-134 - [0x0ACE1474DC1D122E, 0x915E2486EF32CD60], // 1e-133 - [0x0D819992132456BA, 0xB5B5ADA8AAFF80B8], // 1e-132 - [0x10E1FFF697ED6C69, 0xE3231912D5BF60E6], // 1e-131 - [0xCA8D3FFA1EF463C1, 0x8DF5EFABC5979C8F], // 1e-130 - [0xBD308FF8A6B17CB2, 0xB1736B96B6FD83B3], // 1e-129 - [0xAC7CB3F6D05DDBDE, 0xDDD0467C64BCE4A0], // 1e-128 - [0x6BCDF07A423AA96B, 0x8AA22C0DBEF60EE4], // 1e-127 - [0x86C16C98D2C953C6, 0xAD4AB7112EB3929D], // 1e-126 - [0xE871C7BF077BA8B7, 0xD89D64D57A607744], // 1e-125 - [0x11471CD764AD4972, 0x87625F056C7C4A8B], // 1e-124 - [0xD598E40D3DD89BCF, 0xA93AF6C6C79B5D2D], // 1e-123 - [0x4AFF1D108D4EC2C3, 0xD389B47879823479], // 1e-122 - [0xCEDF722A585139BA, 0x843610CB4BF160CB], // 1e-121 - [0xC2974EB4EE658828, 0xA54394FE1EEDB8FE], // 1e-120 - [0x733D226229FEEA32, 0xCE947A3DA6A9273E], // 1e-119 - [0x0806357D5A3F525F, 0x811CCC668829B887], // 1e-118 - [0xCA07C2DCB0CF26F7, 0xA163FF802A3426A8], // 1e-117 - [0xFC89B393DD02F0B5, 0xC9BCFF6034C13052], // 1e-116 - [0xBBAC2078D443ACE2, 0xFC2C3F3841F17C67], // 1e-115 - [0xD54B944B84AA4C0D, 0x9D9BA7832936EDC0], // 1e-114 - [0x0A9E795E65D4DF11, 0xC5029163F384A931], // 1e-113 - [0x4D4617B5FF4A16D5, 0xF64335BCF065D37D], // 1e-112 - [0x504BCED1BF8E4E45, 0x99EA0196163FA42E], // 1e-111 - [0xE45EC2862F71E1D6, 0xC06481FB9BCF8D39], // 1e-110 - [0x5D767327BB4E5A4C, 0xF07DA27A82C37088], // 1e-109 - [0x3A6A07F8D510F86F, 0x964E858C91BA2655], // 1e-108 - [0x890489F70A55368B, 0xBBE226EFB628AFEA], // 1e-107 - [0x2B45AC74CCEA842E, 0xEADAB0ABA3B2DBE5], // 1e-106 - [0x3B0B8BC90012929D, 0x92C8AE6B464FC96F], // 1e-105 - [0x09CE6EBB40173744, 0xB77ADA0617E3BBCB], // 1e-104 - [0xCC420A6A101D0515, 0xE55990879DDCAABD], // 1e-103 - [0x9FA946824A12232D, 0x8F57FA54C2A9EAB6], // 1e-102 - [0x47939822DC96ABF9, 0xB32DF8E9F3546564], // 1e-101 - [0x59787E2B93BC56F7, 0xDFF9772470297EBD], // 1e-100 - [0x57EB4EDB3C55B65A, 0x8BFBEA76C619EF36], // 1e-99 - [0xEDE622920B6B23F1, 0xAEFAE51477A06B03], // 1e-98 - [0xE95FAB368E45ECED, 0xDAB99E59958885C4], // 1e-97 - [0x11DBCB0218EBB414, 0x88B402F7FD75539B], // 1e-96 - [0xD652BDC29F26A119, 0xAAE103B5FCD2A881], // 1e-95 - [0x4BE76D3346F0495F, 0xD59944A37C0752A2], // 1e-94 - [0x6F70A4400C562DDB, 0x857FCAE62D8493A5], // 1e-93 - [0xCB4CCD500F6BB952, 0xA6DFBD9FB8E5B88E], // 1e-92 - [0x7E2000A41346A7A7, 0xD097AD07A71F26B2], // 1e-91 - [0x8ED400668C0C28C8, 0x825ECC24C873782F], // 1e-90 - [0x728900802F0F32FA, 0xA2F67F2DFA90563B], // 1e-89 - [0x4F2B40A03AD2FFB9, 0xCBB41EF979346BCA], // 1e-88 - [0xE2F610C84987BFA8, 0xFEA126B7D78186BC], // 1e-87 - [0x0DD9CA7D2DF4D7C9, 0x9F24B832E6B0F436], // 1e-86 - [0x91503D1C79720DBB, 0xC6EDE63FA05D3143], // 1e-85 - [0x75A44C6397CE912A, 0xF8A95FCF88747D94], // 1e-84 - [0xC986AFBE3EE11ABA, 0x9B69DBE1B548CE7C], // 1e-83 - [0xFBE85BADCE996168, 0xC24452DA229B021B], // 1e-82 - [0xFAE27299423FB9C3, 0xF2D56790AB41C2A2], // 1e-81 - [0xDCCD879FC967D41A, 0x97C560BA6B0919A5], // 1e-80 - [0x5400E987BBC1C920, 0xBDB6B8E905CB600F], // 1e-79 - [0x290123E9AAB23B68, 0xED246723473E3813], // 1e-78 - [0xF9A0B6720AAF6521, 0x9436C0760C86E30B], // 1e-77 - [0xF808E40E8D5B3E69, 0xB94470938FA89BCE], // 1e-76 - [0xB60B1D1230B20E04, 0xE7958CB87392C2C2], // 1e-75 - [0xB1C6F22B5E6F48C2, 0x90BD77F3483BB9B9], // 1e-74 - [0x1E38AEB6360B1AF3, 0xB4ECD5F01A4AA828], // 1e-73 - [0x25C6DA63C38DE1B0, 0xE2280B6C20DD5232], // 1e-72 - [0x579C487E5A38AD0E, 0x8D590723948A535F], // 1e-71 - [0x2D835A9DF0C6D851, 0xB0AF48EC79ACE837], // 1e-70 - [0xF8E431456CF88E65, 0xDCDB1B2798182244], // 1e-69 - [0x1B8E9ECB641B58FF, 0x8A08F0F8BF0F156B], // 1e-68 - [0xE272467E3D222F3F, 0xAC8B2D36EED2DAC5], // 1e-67 - [0x5B0ED81DCC6ABB0F, 0xD7ADF884AA879177], // 1e-66 - [0x98E947129FC2B4E9, 0x86CCBB52EA94BAEA], // 1e-65 - [0x3F2398D747B36224, 0xA87FEA27A539E9A5], // 1e-64 - [0x8EEC7F0D19A03AAD, 0xD29FE4B18E88640E], // 1e-63 - [0x1953CF68300424AC, 0x83A3EEEEF9153E89], // 1e-62 - [0x5FA8C3423C052DD7, 0xA48CEAAAB75A8E2B], // 1e-61 - [0x3792F412CB06794D, 0xCDB02555653131B6], // 1e-60 - [0xE2BBD88BBEE40BD0, 0x808E17555F3EBF11], // 1e-59 - [0x5B6ACEAEAE9D0EC4, 0xA0B19D2AB70E6ED6], // 1e-58 - [0xF245825A5A445275, 0xC8DE047564D20A8B], // 1e-57 - [0xEED6E2F0F0D56712, 0xFB158592BE068D2E], // 1e-56 - [0x55464DD69685606B, 0x9CED737BB6C4183D], // 1e-55 - [0xAA97E14C3C26B886, 0xC428D05AA4751E4C], // 1e-54 - [0xD53DD99F4B3066A8, 0xF53304714D9265DF], // 1e-53 - [0xE546A8038EFE4029, 0x993FE2C6D07B7FAB], // 1e-52 - [0xDE98520472BDD033, 0xBF8FDB78849A5F96], // 1e-51 - [0x963E66858F6D4440, 0xEF73D256A5C0F77C], // 1e-50 - [0xDDE7001379A44AA8, 0x95A8637627989AAD], // 1e-49 - [0x5560C018580D5D52, 0xBB127C53B17EC159], // 1e-48 - [0xAAB8F01E6E10B4A6, 0xE9D71B689DDE71AF], // 1e-47 - [0xCAB3961304CA70E8, 0x9226712162AB070D], // 1e-46 - [0x3D607B97C5FD0D22, 0xB6B00D69BB55C8D1], // 1e-45 - [0x8CB89A7DB77C506A, 0xE45C10C42A2B3B05], // 1e-44 - [0x77F3608E92ADB242, 0x8EB98A7A9A5B04E3], // 1e-43 - [0x55F038B237591ED3, 0xB267ED1940F1C61C], // 1e-42 - [0x6B6C46DEC52F6688, 0xDF01E85F912E37A3], // 1e-41 - [0x2323AC4B3B3DA015, 0x8B61313BBABCE2C6], // 1e-40 - [0xABEC975E0A0D081A, 0xAE397D8AA96C1B77], // 1e-39 - [0x96E7BD358C904A21, 0xD9C7DCED53C72255], // 1e-38 - [0x7E50D64177DA2E54, 0x881CEA14545C7575], // 1e-37 - [0xDDE50BD1D5D0B9E9, 0xAA242499697392D2], // 1e-36 - [0x955E4EC64B44E864, 0xD4AD2DBFC3D07787], // 1e-35 - [0xBD5AF13BEF0B113E, 0x84EC3C97DA624AB4], // 1e-34 - [0xECB1AD8AEACDD58E, 0xA6274BBDD0FADD61], // 1e-33 - [0x67DE18EDA5814AF2, 0xCFB11EAD453994BA], // 1e-32 - [0x80EACF948770CED7, 0x81CEB32C4B43FCF4], // 1e-31 - [0xA1258379A94D028D, 0xA2425FF75E14FC31], // 1e-30 - [0x096EE45813A04330, 0xCAD2F7F5359A3B3E], // 1e-29 - [0x8BCA9D6E188853FC, 0xFD87B5F28300CA0D], // 1e-28 - [0x775EA264CF55347D, 0x9E74D1B791E07E48], // 1e-27 - [0x95364AFE032A819D, 0xC612062576589DDA], // 1e-26 - [0x3A83DDBD83F52204, 0xF79687AED3EEC551], // 1e-25 - [0xC4926A9672793542, 0x9ABE14CD44753B52], // 1e-24 - [0x75B7053C0F178293, 0xC16D9A0095928A27], // 1e-23 - [0x5324C68B12DD6338, 0xF1C90080BAF72CB1], // 1e-22 - [0xD3F6FC16EBCA5E03, 0x971DA05074DA7BEE], // 1e-21 - [0x88F4BB1CA6BCF584, 0xBCE5086492111AEA], // 1e-20 - [0x2B31E9E3D06C32E5, 0xEC1E4A7DB69561A5], // 1e-19 - [0x3AFF322E62439FCF, 0x9392EE8E921D5D07], // 1e-18 - [0x09BEFEB9FAD487C2, 0xB877AA3236A4B449], // 1e-17 - [0x4C2EBE687989A9B3, 0xE69594BEC44DE15B], // 1e-16 - [0x0F9D37014BF60A10, 0x901D7CF73AB0ACD9], // 1e-15 - [0x538484C19EF38C94, 0xB424DC35095CD80F], // 1e-14 - [0x2865A5F206B06FB9, 0xE12E13424BB40E13], // 1e-13 - [0xF93F87B7442E45D3, 0x8CBCCC096F5088CB], // 1e-12 - [0xF78F69A51539D748, 0xAFEBFF0BCB24AAFE], // 1e-11 - [0xB573440E5A884D1B, 0xDBE6FECEBDEDD5BE], // 1e-10 - [0x31680A88F8953030, 0x89705F4136B4A597], // 1e-9 - [0xFDC20D2B36BA7C3D, 0xABCC77118461CEFC], // 1e-8 - [0x3D32907604691B4C, 0xD6BF94D5E57A42BC], // 1e-7 - [0xA63F9A49C2C1B10F, 0x8637BD05AF6C69B5], // 1e-6 - [0x0FCF80DC33721D53, 0xA7C5AC471B478423], // 1e-5 - [0xD3C36113404EA4A8, 0xD1B71758E219652B], // 1e-4 - [0x645A1CAC083126E9, 0x83126E978D4FDF3B], // 1e-3 - [0x3D70A3D70A3D70A3, 0xA3D70A3D70A3D70A], // 1e-2 - [0xCCCCCCCCCCCCCCCC, 0xCCCCCCCCCCCCCCCC], // 1e-1 - [0x0000000000000000, 0x8000000000000000], // 1e0 - [0x0000000000000000, 0xA000000000000000], // 1e1 - [0x0000000000000000, 0xC800000000000000], // 1e2 - [0x0000000000000000, 0xFA00000000000000], // 1e3 - [0x0000000000000000, 0x9C40000000000000], // 1e4 - [0x0000000000000000, 0xC350000000000000], // 1e5 - [0x0000000000000000, 0xF424000000000000], // 1e6 - [0x0000000000000000, 0x9896800000000000], // 1e7 - [0x0000000000000000, 0xBEBC200000000000], // 1e8 - [0x0000000000000000, 0xEE6B280000000000], // 1e9 - [0x0000000000000000, 0x9502F90000000000], // 1e10 - [0x0000000000000000, 0xBA43B74000000000], // 1e11 - [0x0000000000000000, 0xE8D4A51000000000], // 1e12 - [0x0000000000000000, 0x9184E72A00000000], // 1e13 - [0x0000000000000000, 0xB5E620F480000000], // 1e14 - [0x0000000000000000, 0xE35FA931A0000000], // 1e15 - [0x0000000000000000, 0x8E1BC9BF04000000], // 1e16 - [0x0000000000000000, 0xB1A2BC2EC5000000], // 1e17 - [0x0000000000000000, 0xDE0B6B3A76400000], // 1e18 - [0x0000000000000000, 0x8AC7230489E80000], // 1e19 - [0x0000000000000000, 0xAD78EBC5AC620000], // 1e20 - [0x0000000000000000, 0xD8D726B7177A8000], // 1e21 - [0x0000000000000000, 0x878678326EAC9000], // 1e22 - [0x0000000000000000, 0xA968163F0A57B400], // 1e23 - [0x0000000000000000, 0xD3C21BCECCEDA100], // 1e24 - [0x0000000000000000, 0x84595161401484A0], // 1e25 - [0x0000000000000000, 0xA56FA5B99019A5C8], // 1e26 - [0x0000000000000000, 0xCECB8F27F4200F3A], // 1e27 - [0x4000000000000000, 0x813F3978F8940984], // 1e28 - [0x5000000000000000, 0xA18F07D736B90BE5], // 1e29 - [0xA400000000000000, 0xC9F2C9CD04674EDE], // 1e30 - [0x4D00000000000000, 0xFC6F7C4045812296], // 1e31 - [0xF020000000000000, 0x9DC5ADA82B70B59D], // 1e32 - [0x6C28000000000000, 0xC5371912364CE305], // 1e33 - [0xC732000000000000, 0xF684DF56C3E01BC6], // 1e34 - [0x3C7F400000000000, 0x9A130B963A6C115C], // 1e35 - [0x4B9F100000000000, 0xC097CE7BC90715B3], // 1e36 - [0x1E86D40000000000, 0xF0BDC21ABB48DB20], // 1e37 - [0x1314448000000000, 0x96769950B50D88F4], // 1e38 - [0x17D955A000000000, 0xBC143FA4E250EB31], // 1e39 - [0x5DCFAB0800000000, 0xEB194F8E1AE525FD], // 1e40 - [0x5AA1CAE500000000, 0x92EFD1B8D0CF37BE], // 1e41 - [0xF14A3D9E40000000, 0xB7ABC627050305AD], // 1e42 - [0x6D9CCD05D0000000, 0xE596B7B0C643C719], // 1e43 - [0xE4820023A2000000, 0x8F7E32CE7BEA5C6F], // 1e44 - [0xDDA2802C8A800000, 0xB35DBF821AE4F38B], // 1e45 - [0xD50B2037AD200000, 0xE0352F62A19E306E], // 1e46 - [0x4526F422CC340000, 0x8C213D9DA502DE45], // 1e47 - [0x9670B12B7F410000, 0xAF298D050E4395D6], // 1e48 - [0x3C0CDD765F114000, 0xDAF3F04651D47B4C], // 1e49 - [0xA5880A69FB6AC800, 0x88D8762BF324CD0F], // 1e50 - [0x8EEA0D047A457A00, 0xAB0E93B6EFEE0053], // 1e51 - [0x72A4904598D6D880, 0xD5D238A4ABE98068], // 1e52 - [0x47A6DA2B7F864750, 0x85A36366EB71F041], // 1e53 - [0x999090B65F67D924, 0xA70C3C40A64E6C51], // 1e54 - [0xFFF4B4E3F741CF6D, 0xD0CF4B50CFE20765], // 1e55 - [0xBFF8F10E7A8921A4, 0x82818F1281ED449F], // 1e56 - [0xAFF72D52192B6A0D, 0xA321F2D7226895C7], // 1e57 - [0x9BF4F8A69F764490, 0xCBEA6F8CEB02BB39], // 1e58 - [0x02F236D04753D5B4, 0xFEE50B7025C36A08], // 1e59 - [0x01D762422C946590, 0x9F4F2726179A2245], // 1e60 - [0x424D3AD2B7B97EF5, 0xC722F0EF9D80AAD6], // 1e61 - [0xD2E0898765A7DEB2, 0xF8EBAD2B84E0D58B], // 1e62 - [0x63CC55F49F88EB2F, 0x9B934C3B330C8577], // 1e63 - [0x3CBF6B71C76B25FB, 0xC2781F49FFCFA6D5], // 1e64 - [0x8BEF464E3945EF7A, 0xF316271C7FC3908A], // 1e65 - [0x97758BF0E3CBB5AC, 0x97EDD871CFDA3A56], // 1e66 - [0x3D52EEED1CBEA317, 0xBDE94E8E43D0C8EC], // 1e67 - [0x4CA7AAA863EE4BDD, 0xED63A231D4C4FB27], // 1e68 - [0x8FE8CAA93E74EF6A, 0x945E455F24FB1CF8], // 1e69 - [0xB3E2FD538E122B44, 0xB975D6B6EE39E436], // 1e70 - [0x60DBBCA87196B616, 0xE7D34C64A9C85D44], // 1e71 - [0xBC8955E946FE31CD, 0x90E40FBEEA1D3A4A], // 1e72 - [0x6BABAB6398BDBE41, 0xB51D13AEA4A488DD], // 1e73 - [0xC696963C7EED2DD1, 0xE264589A4DCDAB14], // 1e74 - [0xFC1E1DE5CF543CA2, 0x8D7EB76070A08AEC], // 1e75 - [0x3B25A55F43294BCB, 0xB0DE65388CC8ADA8], // 1e76 - [0x49EF0EB713F39EBE, 0xDD15FE86AFFAD912], // 1e77 - [0x6E3569326C784337, 0x8A2DBF142DFCC7AB], // 1e78 - [0x49C2C37F07965404, 0xACB92ED9397BF996], // 1e79 - [0xDC33745EC97BE906, 0xD7E77A8F87DAF7FB], // 1e80 - [0x69A028BB3DED71A3, 0x86F0AC99B4E8DAFD], // 1e81 - [0xC40832EA0D68CE0C, 0xA8ACD7C0222311BC], // 1e82 - [0xF50A3FA490C30190, 0xD2D80DB02AABD62B], // 1e83 - [0x792667C6DA79E0FA, 0x83C7088E1AAB65DB], // 1e84 - [0x577001B891185938, 0xA4B8CAB1A1563F52], // 1e85 - [0xED4C0226B55E6F86, 0xCDE6FD5E09ABCF26], // 1e86 - [0x544F8158315B05B4, 0x80B05E5AC60B6178], // 1e87 - [0x696361AE3DB1C721, 0xA0DC75F1778E39D6], // 1e88 - [0x03BC3A19CD1E38E9, 0xC913936DD571C84C], // 1e89 - [0x04AB48A04065C723, 0xFB5878494ACE3A5F], // 1e90 - [0x62EB0D64283F9C76, 0x9D174B2DCEC0E47B], // 1e91 - [0x3BA5D0BD324F8394, 0xC45D1DF942711D9A], // 1e92 - [0xCA8F44EC7EE36479, 0xF5746577930D6500], // 1e93 - [0x7E998B13CF4E1ECB, 0x9968BF6ABBE85F20], // 1e94 - [0x9E3FEDD8C321A67E, 0xBFC2EF456AE276E8], // 1e95 - [0xC5CFE94EF3EA101E, 0xEFB3AB16C59B14A2], // 1e96 - [0xBBA1F1D158724A12, 0x95D04AEE3B80ECE5], // 1e97 - [0x2A8A6E45AE8EDC97, 0xBB445DA9CA61281F], // 1e98 - [0xF52D09D71A3293BD, 0xEA1575143CF97226], // 1e99 - [0x593C2626705F9C56, 0x924D692CA61BE758], // 1e100 - [0x6F8B2FB00C77836C, 0xB6E0C377CFA2E12E], // 1e101 - [0x0B6DFB9C0F956447, 0xE498F455C38B997A], // 1e102 - [0x4724BD4189BD5EAC, 0x8EDF98B59A373FEC], // 1e103 - [0x58EDEC91EC2CB657, 0xB2977EE300C50FE7], // 1e104 - [0x2F2967B66737E3ED, 0xDF3D5E9BC0F653E1], // 1e105 - [0xBD79E0D20082EE74, 0x8B865B215899F46C], // 1e106 - [0xECD8590680A3AA11, 0xAE67F1E9AEC07187], // 1e107 - [0xE80E6F4820CC9495, 0xDA01EE641A708DE9], // 1e108 - [0x3109058D147FDCDD, 0x884134FE908658B2], // 1e109 - [0xBD4B46F0599FD415, 0xAA51823E34A7EEDE], // 1e110 - [0x6C9E18AC7007C91A, 0xD4E5E2CDC1D1EA96], // 1e111 - [0x03E2CF6BC604DDB0, 0x850FADC09923329E], // 1e112 - [0x84DB8346B786151C, 0xA6539930BF6BFF45], // 1e113 - [0xE612641865679A63, 0xCFE87F7CEF46FF16], // 1e114 - [0x4FCB7E8F3F60C07E, 0x81F14FAE158C5F6E], // 1e115 - [0xE3BE5E330F38F09D, 0xA26DA3999AEF7749], // 1e116 - [0x5CADF5BFD3072CC5, 0xCB090C8001AB551C], // 1e117 - [0x73D9732FC7C8F7F6, 0xFDCB4FA002162A63], // 1e118 - [0x2867E7FDDCDD9AFA, 0x9E9F11C4014DDA7E], // 1e119 - [0xB281E1FD541501B8, 0xC646D63501A1511D], // 1e120 - [0x1F225A7CA91A4226, 0xF7D88BC24209A565], // 1e121 - [0x3375788DE9B06958, 0x9AE757596946075F], // 1e122 - [0x0052D6B1641C83AE, 0xC1A12D2FC3978937], // 1e123 - [0xC0678C5DBD23A49A, 0xF209787BB47D6B84], // 1e124 - [0xF840B7BA963646E0, 0x9745EB4D50CE6332], // 1e125 - [0xB650E5A93BC3D898, 0xBD176620A501FBFF], // 1e126 - [0xA3E51F138AB4CEBE, 0xEC5D3FA8CE427AFF], // 1e127 - [0xC66F336C36B10137, 0x93BA47C980E98CDF], // 1e128 - [0xB80B0047445D4184, 0xB8A8D9BBE123F017], // 1e129 - [0xA60DC059157491E5, 0xE6D3102AD96CEC1D], // 1e130 - [0x87C89837AD68DB2F, 0x9043EA1AC7E41392], // 1e131 - [0x29BABE4598C311FB, 0xB454E4A179DD1877], // 1e132 - [0xF4296DD6FEF3D67A, 0xE16A1DC9D8545E94], // 1e133 - [0x1899E4A65F58660C, 0x8CE2529E2734BB1D], // 1e134 - [0x5EC05DCFF72E7F8F, 0xB01AE745B101E9E4], // 1e135 - [0x76707543F4FA1F73, 0xDC21A1171D42645D], // 1e136 - [0x6A06494A791C53A8, 0x899504AE72497EBA], // 1e137 - [0x0487DB9D17636892, 0xABFA45DA0EDBDE69], // 1e138 - [0x45A9D2845D3C42B6, 0xD6F8D7509292D603], // 1e139 - [0x0B8A2392BA45A9B2, 0x865B86925B9BC5C2], // 1e140 - [0x8E6CAC7768D7141E, 0xA7F26836F282B732], // 1e141 - [0x3207D795430CD926, 0xD1EF0244AF2364FF], // 1e142 - [0x7F44E6BD49E807B8, 0x8335616AED761F1F], // 1e143 - [0x5F16206C9C6209A6, 0xA402B9C5A8D3A6E7], // 1e144 - [0x36DBA887C37A8C0F, 0xCD036837130890A1], // 1e145 - [0xC2494954DA2C9789, 0x802221226BE55A64], // 1e146 - [0xF2DB9BAA10B7BD6C, 0xA02AA96B06DEB0FD], // 1e147 - [0x6F92829494E5ACC7, 0xC83553C5C8965D3D], // 1e148 - [0xCB772339BA1F17F9, 0xFA42A8B73ABBF48C], // 1e149 - [0xFF2A760414536EFB, 0x9C69A97284B578D7], // 1e150 - [0xFEF5138519684ABA, 0xC38413CF25E2D70D], // 1e151 - [0x7EB258665FC25D69, 0xF46518C2EF5B8CD1], // 1e152 - [0xEF2F773FFBD97A61, 0x98BF2F79D5993802], // 1e153 - [0xAAFB550FFACFD8FA, 0xBEEEFB584AFF8603], // 1e154 - [0x95BA2A53F983CF38, 0xEEAABA2E5DBF6784], // 1e155 - [0xDD945A747BF26183, 0x952AB45CFA97A0B2], // 1e156 - [0x94F971119AEEF9E4, 0xBA756174393D88DF], // 1e157 - [0x7A37CD5601AAB85D, 0xE912B9D1478CEB17], // 1e158 - [0xAC62E055C10AB33A, 0x91ABB422CCB812EE], // 1e159 - [0x577B986B314D6009, 0xB616A12B7FE617AA], // 1e160 - [0xED5A7E85FDA0B80B, 0xE39C49765FDF9D94], // 1e161 - [0x14588F13BE847307, 0x8E41ADE9FBEBC27D], // 1e162 - [0x596EB2D8AE258FC8, 0xB1D219647AE6B31C], // 1e163 - [0x6FCA5F8ED9AEF3BB, 0xDE469FBD99A05FE3], // 1e164 - [0x25DE7BB9480D5854, 0x8AEC23D680043BEE], // 1e165 - [0xAF561AA79A10AE6A, 0xADA72CCC20054AE9], // 1e166 - [0x1B2BA1518094DA04, 0xD910F7FF28069DA4], // 1e167 - [0x90FB44D2F05D0842, 0x87AA9AFF79042286], // 1e168 - [0x353A1607AC744A53, 0xA99541BF57452B28], // 1e169 - [0x42889B8997915CE8, 0xD3FA922F2D1675F2], // 1e170 - [0x69956135FEBADA11, 0x847C9B5D7C2E09B7], // 1e171 - [0x43FAB9837E699095, 0xA59BC234DB398C25], // 1e172 - [0x94F967E45E03F4BB, 0xCF02B2C21207EF2E], // 1e173 - [0x1D1BE0EEBAC278F5, 0x8161AFB94B44F57D], // 1e174 - [0x6462D92A69731732, 0xA1BA1BA79E1632DC], // 1e175 - [0x7D7B8F7503CFDCFE, 0xCA28A291859BBF93], // 1e176 - [0x5CDA735244C3D43E, 0xFCB2CB35E702AF78], // 1e177 - [0x3A0888136AFA64A7, 0x9DEFBF01B061ADAB], // 1e178 - [0x088AAA1845B8FDD0, 0xC56BAEC21C7A1916], // 1e179 - [0x8AAD549E57273D45, 0xF6C69A72A3989F5B], // 1e180 - [0x36AC54E2F678864B, 0x9A3C2087A63F6399], // 1e181 - [0x84576A1BB416A7DD, 0xC0CB28A98FCF3C7F], // 1e182 - [0x656D44A2A11C51D5, 0xF0FDF2D3F3C30B9F], // 1e183 - [0x9F644AE5A4B1B325, 0x969EB7C47859E743], // 1e184 - [0x873D5D9F0DDE1FEE, 0xBC4665B596706114], // 1e185 - [0xA90CB506D155A7EA, 0xEB57FF22FC0C7959], // 1e186 - [0x09A7F12442D588F2, 0x9316FF75DD87CBD8], // 1e187 - [0x0C11ED6D538AEB2F, 0xB7DCBF5354E9BECE], // 1e188 - [0x8F1668C8A86DA5FA, 0xE5D3EF282A242E81], // 1e189 - [0xF96E017D694487BC, 0x8FA475791A569D10], // 1e190 - [0x37C981DCC395A9AC, 0xB38D92D760EC4455], // 1e191 - [0x85BBE253F47B1417, 0xE070F78D3927556A], // 1e192 - [0x93956D7478CCEC8E, 0x8C469AB843B89562], // 1e193 - [0x387AC8D1970027B2, 0xAF58416654A6BABB], // 1e194 - [0x06997B05FCC0319E, 0xDB2E51BFE9D0696A], // 1e195 - [0x441FECE3BDF81F03, 0x88FCF317F22241E2], // 1e196 - [0xD527E81CAD7626C3, 0xAB3C2FDDEEAAD25A], // 1e197 - [0x8A71E223D8D3B074, 0xD60B3BD56A5586F1], // 1e198 - [0xF6872D5667844E49, 0x85C7056562757456], // 1e199 - [0xB428F8AC016561DB, 0xA738C6BEBB12D16C], // 1e200 - [0xE13336D701BEBA52, 0xD106F86E69D785C7], // 1e201 - [0xECC0024661173473, 0x82A45B450226B39C], // 1e202 - [0x27F002D7F95D0190, 0xA34D721642B06084], // 1e203 - [0x31EC038DF7B441F4, 0xCC20CE9BD35C78A5], // 1e204 - [0x7E67047175A15271, 0xFF290242C83396CE], // 1e205 - [0x0F0062C6E984D386, 0x9F79A169BD203E41], // 1e206 - [0x52C07B78A3E60868, 0xC75809C42C684DD1], // 1e207 - [0xA7709A56CCDF8A82, 0xF92E0C3537826145], // 1e208 - [0x88A66076400BB691, 0x9BBCC7A142B17CCB], // 1e209 - [0x6ACFF893D00EA435, 0xC2ABF989935DDBFE], // 1e210 - [0x0583F6B8C4124D43, 0xF356F7EBF83552FE], // 1e211 - [0xC3727A337A8B704A, 0x98165AF37B2153DE], // 1e212 - [0x744F18C0592E4C5C, 0xBE1BF1B059E9A8D6], // 1e213 - [0x1162DEF06F79DF73, 0xEDA2EE1C7064130C], // 1e214 - [0x8ADDCB5645AC2BA8, 0x9485D4D1C63E8BE7], // 1e215 - [0x6D953E2BD7173692, 0xB9A74A0637CE2EE1], // 1e216 - [0xC8FA8DB6CCDD0437, 0xE8111C87C5C1BA99], // 1e217 - [0x1D9C9892400A22A2, 0x910AB1D4DB9914A0], // 1e218 - [0x2503BEB6D00CAB4B, 0xB54D5E4A127F59C8], // 1e219 - [0x2E44AE64840FD61D, 0xE2A0B5DC971F303A], // 1e220 - [0x5CEAECFED289E5D2, 0x8DA471A9DE737E24], // 1e221 - [0x7425A83E872C5F47, 0xB10D8E1456105DAD], // 1e222 - [0xD12F124E28F77719, 0xDD50F1996B947518], // 1e223 - [0x82BD6B70D99AAA6F, 0x8A5296FFE33CC92F], // 1e224 - [0x636CC64D1001550B, 0xACE73CBFDC0BFB7B], // 1e225 - [0x3C47F7E05401AA4E, 0xD8210BEFD30EFA5A], // 1e226 - [0x65ACFAEC34810A71, 0x8714A775E3E95C78], // 1e227 - [0x7F1839A741A14D0D, 0xA8D9D1535CE3B396], // 1e228 - [0x1EDE48111209A050, 0xD31045A8341CA07C], // 1e229 - [0x934AED0AAB460432, 0x83EA2B892091E44D], // 1e230 - [0xF81DA84D5617853F, 0xA4E4B66B68B65D60], // 1e231 - [0x36251260AB9D668E, 0xCE1DE40642E3F4B9], // 1e232 - [0xC1D72B7C6B426019, 0x80D2AE83E9CE78F3], // 1e233 - [0xB24CF65B8612F81F, 0xA1075A24E4421730], // 1e234 - [0xDEE033F26797B627, 0xC94930AE1D529CFC], // 1e235 - [0x169840EF017DA3B1, 0xFB9B7CD9A4A7443C], // 1e236 - [0x8E1F289560EE864E, 0x9D412E0806E88AA5], // 1e237 - [0xF1A6F2BAB92A27E2, 0xC491798A08A2AD4E], // 1e238 - [0xAE10AF696774B1DB, 0xF5B5D7EC8ACB58A2], // 1e239 - [0xACCA6DA1E0A8EF29, 0x9991A6F3D6BF1765], // 1e240 - [0x17FD090A58D32AF3, 0xBFF610B0CC6EDD3F], // 1e241 - [0xDDFC4B4CEF07F5B0, 0xEFF394DCFF8A948E], // 1e242 - [0x4ABDAF101564F98E, 0x95F83D0A1FB69CD9], // 1e243 - [0x9D6D1AD41ABE37F1, 0xBB764C4CA7A4440F], // 1e244 - [0x84C86189216DC5ED, 0xEA53DF5FD18D5513], // 1e245 - [0x32FD3CF5B4E49BB4, 0x92746B9BE2F8552C], // 1e246 - [0x3FBC8C33221DC2A1, 0xB7118682DBB66A77], // 1e247 - [0x0FABAF3FEAA5334A, 0xE4D5E82392A40515], // 1e248 - [0x29CB4D87F2A7400E, 0x8F05B1163BA6832D], // 1e249 - [0x743E20E9EF511012, 0xB2C71D5BCA9023F8], // 1e250 - [0x914DA9246B255416, 0xDF78E4B2BD342CF6], // 1e251 - [0x1AD089B6C2F7548E, 0x8BAB8EEFB6409C1A], // 1e252 - [0xA184AC2473B529B1, 0xAE9672ABA3D0C320], // 1e253 - [0xC9E5D72D90A2741E, 0xDA3C0F568CC4F3E8], // 1e254 - [0x7E2FA67C7A658892, 0x8865899617FB1871], // 1e255 - [0xDDBB901B98FEEAB7, 0xAA7EEBFB9DF9DE8D], // 1e256 - [0x552A74227F3EA565, 0xD51EA6FA85785631], // 1e257 - [0xD53A88958F87275F, 0x8533285C936B35DE], // 1e258 - [0x8A892ABAF368F137, 0xA67FF273B8460356], // 1e259 - [0x2D2B7569B0432D85, 0xD01FEF10A657842C], // 1e260 - [0x9C3B29620E29FC73, 0x8213F56A67F6B29B], // 1e261 - [0x8349F3BA91B47B8F, 0xA298F2C501F45F42], // 1e262 - [0x241C70A936219A73, 0xCB3F2F7642717713], // 1e263 - [0xED238CD383AA0110, 0xFE0EFB53D30DD4D7], // 1e264 - [0xF4363804324A40AA, 0x9EC95D1463E8A506], // 1e265 - [0xB143C6053EDCD0D5, 0xC67BB4597CE2CE48], // 1e266 - [0xDD94B7868E94050A, 0xF81AA16FDC1B81DA], // 1e267 - [0xCA7CF2B4191C8326, 0x9B10A4E5E9913128], // 1e268 - [0xFD1C2F611F63A3F0, 0xC1D4CE1F63F57D72], // 1e269 - [0xBC633B39673C8CEC, 0xF24A01A73CF2DCCF], // 1e270 - [0xD5BE0503E085D813, 0x976E41088617CA01], // 1e271 - [0x4B2D8644D8A74E18, 0xBD49D14AA79DBC82], // 1e272 - [0xDDF8E7D60ED1219E, 0xEC9C459D51852BA2], // 1e273 - [0xCABB90E5C942B503, 0x93E1AB8252F33B45], // 1e274 - [0x3D6A751F3B936243, 0xB8DA1662E7B00A17], // 1e275 - [0x0CC512670A783AD4, 0xE7109BFBA19C0C9D], // 1e276 - [0x27FB2B80668B24C5, 0x906A617D450187E2], // 1e277 - [0xB1F9F660802DEDF6, 0xB484F9DC9641E9DA], // 1e278 - [0x5E7873F8A0396973, 0xE1A63853BBD26451], // 1e279 - [0xDB0B487B6423E1E8, 0x8D07E33455637EB2], // 1e280 - [0x91CE1A9A3D2CDA62, 0xB049DC016ABC5E5F], // 1e281 - [0x7641A140CC7810FB, 0xDC5C5301C56B75F7], // 1e282 - [0xA9E904C87FCB0A9D, 0x89B9B3E11B6329BA], // 1e283 - [0x546345FA9FBDCD44, 0xAC2820D9623BF429], // 1e284 - [0xA97C177947AD4095, 0xD732290FBACAF133], // 1e285 - [0x49ED8EABCCCC485D, 0x867F59A9D4BED6C0], // 1e286 - [0x5C68F256BFFF5A74, 0xA81F301449EE8C70], // 1e287 - [0x73832EEC6FFF3111, 0xD226FC195C6A2F8C], // 1e288 - [0xC831FD53C5FF7EAB, 0x83585D8FD9C25DB7], // 1e289 - [0xBA3E7CA8B77F5E55, 0xA42E74F3D032F525], // 1e290 - [0x28CE1BD2E55F35EB, 0xCD3A1230C43FB26F], // 1e291 - [0x7980D163CF5B81B3, 0x80444B5E7AA7CF85], // 1e292 - [0xD7E105BCC332621F, 0xA0555E361951C366], // 1e293 - [0x8DD9472BF3FEFAA7, 0xC86AB5C39FA63440], // 1e294 - [0xB14F98F6F0FEB951, 0xFA856334878FC150], // 1e295 - [0x6ED1BF9A569F33D3, 0x9C935E00D4B9D8D2], // 1e296 - [0x0A862F80EC4700C8, 0xC3B8358109E84F07], // 1e297 - [0xCD27BB612758C0FA, 0xF4A642E14C6262C8], // 1e298 - [0x8038D51CB897789C, 0x98E7E9CCCFBD7DBD], // 1e299 - [0xE0470A63E6BD56C3, 0xBF21E44003ACDD2C], // 1e300 - [0x1858CCFCE06CAC74, 0xEEEA5D5004981478], // 1e301 - [0x0F37801E0C43EBC8, 0x95527A5202DF0CCB], // 1e302 - [0xD30560258F54E6BA, 0xBAA718E68396CFFD], // 1e303 - [0x47C6B82EF32A2069, 0xE950DF20247C83FD], // 1e304 - [0x4CDC331D57FA5441, 0x91D28B7416CDD27E], // 1e305 - [0xE0133FE4ADF8E952, 0xB6472E511C81471D], // 1e306 - [0x58180FDDD97723A6, 0xE3D8F9E563A198E5], // 1e307 - [0x570F09EAA7EA7648, 0x8E679C2F5E44FF8F], // 1e308 - [0x2CD2CC6551E513DA, 0xB201833B35D63F73], // 1e309 - [0xF8077F7EA65E58D1, 0xDE81E40A034BCF4F], // 1e310 - [0xFB04AFAF27FAF782, 0x8B112E86420F6191], // 1e311 - [0x79C5DB9AF1F9B563, 0xADD57A27D29339F6], // 1e312 - [0x18375281AE7822BC, 0xD94AD8B1C7380874], // 1e313 - [0x8F2293910D0B15B5, 0x87CEC76F1C830548], // 1e314 - [0xB2EB3875504DDB22, 0xA9C2794AE3A3C69A], // 1e315 - [0x5FA60692A46151EB, 0xD433179D9C8CB841], // 1e316 - [0xDBC7C41BA6BCD333, 0x849FEEC281D7F328], // 1e317 - [0x12B9B522906C0800, 0xA5C7EA73224DEFF3], // 1e318 - [0xD768226B34870A00, 0xCF39E50FEAE16BEF], // 1e319 - [0xE6A1158300D46640, 0x81842F29F2CCE375], // 1e320 - [0x60495AE3C1097FD0, 0xA1E53AF46F801C53], // 1e321 - [0x385BB19CB14BDFC4, 0xCA5E89B18B602368], // 1e322 - [0x46729E03DD9ED7B5, 0xFCF62C1DEE382C42], // 1e323 - [0x6C07A2C26A8346D1, 0x9E19DB92B4E31BA9], // 1e324 - [0xC7098B7305241885, 0xC5A05277621BE293], // 1e325 - [0xB8CBEE4FC66D1EA7, 0xF70867153AA2DB38], // 1e326 - [0x737F74F1DC043328, 0x9A65406D44A5C903], // 1e327 - [0x505F522E53053FF2, 0xC0FE908895CF3B44], // 1e328 - [0x647726B9E7C68FEF, 0xF13E34AABB430A15], // 1e329 - [0x5ECA783430DC19F5, 0x96C6E0EAB509E64D], // 1e330 - [0xB67D16413D132072, 0xBC789925624C5FE0], // 1e331 - [0xE41C5BD18C57E88F, 0xEB96BF6EBADF77D8], // 1e332 - [0x8E91B962F7B6F159, 0x933E37A534CBAAE7], // 1e333 - [0x723627BBB5A4ADB0, 0xB80DC58E81FE95A1], // 1e334 - [0xCEC3B1AAA30DD91C, 0xE61136F2227E3B09], // 1e335 - [0x213A4F0AA5E8A7B1, 0x8FCAC257558EE4E6], // 1e336 - [0xA988E2CD4F62D19D, 0xB3BD72ED2AF29E1F], // 1e337 - [0x93EB1B80A33B8605, 0xE0ACCFA875AF45A7], // 1e338 - [0xBC72F130660533C3, 0x8C6C01C9498D8B88], // 1e339 - [0xEB8FAD7C7F8680B4, 0xAF87023B9BF0EE6A], // 1e340 - [0xA67398DB9F6820E1, 0xDB68C2CA82ED2A05], // 1e341 - [0x88083F8943A1148C, 0x892179BE91D43A43], // 1e342 - [0x6A0A4F6B948959B0, 0xAB69D82E364948D4], // 1e343 - [0x848CE34679ABB01C, 0xD6444E39C3DB9B09], // 1e344 - [0xF2D80E0C0C0B4E11, 0x85EAB0E41A6940E5], // 1e345 - [0x6F8E118F0F0E2195, 0xA7655D1D2103911F], // 1e346 - [0x4B7195F2D2D1A9FB, 0xD13EB46469447567], // 1e347 + [0x1732C869CD60E453, 0xFA8FD5A0081C0288], // 1e-348 + [0x0E7FBD42205C8EB4, 0x9C99E58405118195], // 1e-347 + [0x521FAC92A873B261, 0xC3C05EE50655E1FA], // 1e-346 + [0xE6A797B752909EF9, 0xF4B0769E47EB5A78], // 1e-345 + [0x9028BED2939A635C, 0x98EE4A22ECF3188B], // 1e-344 + [0x7432EE873880FC33, 0xBF29DCABA82FDEAE], // 1e-343 + [0x113FAA2906A13B3F, 0xEEF453D6923BD65A], // 1e-342 + [0x4AC7CA59A424C507, 0x9558B4661B6565F8], // 1e-341 + [0x5D79BCF00D2DF649, 0xBAAEE17FA23EBF76], // 1e-340 + [0xF4D82C2C107973DC, 0xE95A99DF8ACE6F53], // 1e-339 + [0x79071B9B8A4BE869, 0x91D8A02BB6C10594], // 1e-338 + [0x9748E2826CDEE284, 0xB64EC836A47146F9], // 1e-337 + [0xFD1B1B2308169B25, 0xE3E27A444D8D98B7], // 1e-336 + [0xFE30F0F5E50E20F7, 0x8E6D8C6AB0787F72], // 1e-335 + [0xBDBD2D335E51A935, 0xB208EF855C969F4F], // 1e-334 + [0xAD2C788035E61382, 0xDE8B2B66B3BC4723], // 1e-333 + [0x4C3BCB5021AFCC31, 0x8B16FB203055AC76], // 1e-332 + [0xDF4ABE242A1BBF3D, 0xADDCB9E83C6B1793], // 1e-331 + [0xD71D6DAD34A2AF0D, 0xD953E8624B85DD78], // 1e-330 + [0x8672648C40E5AD68, 0x87D4713D6F33AA6B], // 1e-329 + [0x680EFDAF511F18C2, 0xA9C98D8CCB009506], // 1e-328 + [0x0212BD1B2566DEF2, 0xD43BF0EFFDC0BA48], // 1e-327 + [0x014BB630F7604B57, 0x84A57695FE98746D], // 1e-326 + [0x419EA3BD35385E2D, 0xA5CED43B7E3E9188], // 1e-325 + [0x52064CAC828675B9, 0xCF42894A5DCE35EA], // 1e-324 + [0x7343EFEBD1940993, 0x818995CE7AA0E1B2], // 1e-323 + [0x1014EBE6C5F90BF8, 0xA1EBFB4219491A1F], // 1e-322 + [0xD41A26E077774EF6, 0xCA66FA129F9B60A6], // 1e-321 + [0x8920B098955522B4, 0xFD00B897478238D0], // 1e-320 + [0x55B46E5F5D5535B0, 0x9E20735E8CB16382], // 1e-319 + [0xEB2189F734AA831D, 0xC5A890362FDDBC62], // 1e-318 + [0xA5E9EC7501D523E4, 0xF712B443BBD52B7B], // 1e-317 + [0x47B233C92125366E, 0x9A6BB0AA55653B2D], // 1e-316 + [0x999EC0BB696E840A, 0xC1069CD4EABE89F8], // 1e-315 + [0xC00670EA43CA250D, 0xF148440A256E2C76], // 1e-314 + [0x380406926A5E5728, 0x96CD2A865764DBCA], // 1e-313 + [0xC605083704F5ECF2, 0xBC807527ED3E12BC], // 1e-312 + [0xF7864A44C633682E, 0xEBA09271E88D976B], // 1e-311 + [0x7AB3EE6AFBE0211D, 0x93445B8731587EA3], // 1e-310 + [0x5960EA05BAD82964, 0xB8157268FDAE9E4C], // 1e-309 + [0x6FB92487298E33BD, 0xE61ACF033D1A45DF], // 1e-308 + [0xA5D3B6D479F8E056, 0x8FD0C16206306BAB], // 1e-307 + [0x8F48A4899877186C, 0xB3C4F1BA87BC8696], // 1e-306 + [0x331ACDABFE94DE87, 0xE0B62E2929ABA83C], // 1e-305 + [0x9FF0C08B7F1D0B14, 0x8C71DCD9BA0B4925], // 1e-304 + [0x07ECF0AE5EE44DD9, 0xAF8E5410288E1B6F], // 1e-303 + [0xC9E82CD9F69D6150, 0xDB71E91432B1A24A], // 1e-302 + [0xBE311C083A225CD2, 0x892731AC9FAF056E], // 1e-301 + [0x6DBD630A48AAF406, 0xAB70FE17C79AC6CA], // 1e-300 + [0x092CBBCCDAD5B108, 0xD64D3D9DB981787D], // 1e-299 + [0x25BBF56008C58EA5, 0x85F0468293F0EB4E], // 1e-298 + [0xAF2AF2B80AF6F24E, 0xA76C582338ED2621], // 1e-297 + [0x1AF5AF660DB4AEE1, 0xD1476E2C07286FAA], // 1e-296 + [0x50D98D9FC890ED4D, 0x82CCA4DB847945CA], // 1e-295 + [0xE50FF107BAB528A0, 0xA37FCE126597973C], // 1e-294 + [0x1E53ED49A96272C8, 0xCC5FC196FEFD7D0C], // 1e-293 + [0x25E8E89C13BB0F7A, 0xFF77B1FCBEBCDC4F], // 1e-292 + [0x77B191618C54E9AC, 0x9FAACF3DF73609B1], // 1e-291 + [0xD59DF5B9EF6A2417, 0xC795830D75038C1D], // 1e-290 + [0x4B0573286B44AD1D, 0xF97AE3D0D2446F25], // 1e-289 + [0x4EE367F9430AEC32, 0x9BECCE62836AC577], // 1e-288 + [0x229C41F793CDA73F, 0xC2E801FB244576D5], // 1e-287 + [0x6B43527578C1110F, 0xF3A20279ED56D48A], // 1e-286 + [0x830A13896B78AAA9, 0x9845418C345644D6], // 1e-285 + [0x23CC986BC656D553, 0xBE5691EF416BD60C], // 1e-284 + [0x2CBFBE86B7EC8AA8, 0xEDEC366B11C6CB8F], // 1e-283 + [0x7BF7D71432F3D6A9, 0x94B3A202EB1C3F39], // 1e-282 + [0xDAF5CCD93FB0CC53, 0xB9E08A83A5E34F07], // 1e-281 + [0xD1B3400F8F9CFF68, 0xE858AD248F5C22C9], // 1e-280 + [0x23100809B9C21FA1, 0x91376C36D99995BE], // 1e-279 + [0xABD40A0C2832A78A, 0xB58547448FFFFB2D], // 1e-278 + [0x16C90C8F323F516C, 0xE2E69915B3FFF9F9], // 1e-277 + [0xAE3DA7D97F6792E3, 0x8DD01FAD907FFC3B], // 1e-276 + [0x99CD11CFDF41779C, 0xB1442798F49FFB4A], // 1e-275 + [0x40405643D711D583, 0xDD95317F31C7FA1D], // 1e-274 + [0x482835EA666B2572, 0x8A7D3EEF7F1CFC52], // 1e-273 + [0xDA3243650005EECF, 0xAD1C8EAB5EE43B66], // 1e-272 + [0x90BED43E40076A82, 0xD863B256369D4A40], // 1e-271 + [0x5A7744A6E804A291, 0x873E4F75E2224E68], // 1e-270 + [0x711515D0A205CB36, 0xA90DE3535AAAE202], // 1e-269 + [0x0D5A5B44CA873E03, 0xD3515C2831559A83], // 1e-268 + [0xE858790AFE9486C2, 0x8412D9991ED58091], // 1e-267 + [0x626E974DBE39A872, 0xA5178FFF668AE0B6], // 1e-266 + [0xFB0A3D212DC8128F, 0xCE5D73FF402D98E3], // 1e-265 + [0x7CE66634BC9D0B99, 0x80FA687F881C7F8E], // 1e-264 + [0x1C1FFFC1EBC44E80, 0xA139029F6A239F72], // 1e-263 + [0xA327FFB266B56220, 0xC987434744AC874E], // 1e-262 + [0x4BF1FF9F0062BAA8, 0xFBE9141915D7A922], // 1e-261 + [0x6F773FC3603DB4A9, 0x9D71AC8FADA6C9B5], // 1e-260 + [0xCB550FB4384D21D3, 0xC4CE17B399107C22], // 1e-259 + [0x7E2A53A146606A48, 0xF6019DA07F549B2B], // 1e-258 + [0x2EDA7444CBFC426D, 0x99C102844F94E0FB], // 1e-257 + [0xFA911155FEFB5308, 0xC0314325637A1939], // 1e-256 + [0x793555AB7EBA27CA, 0xF03D93EEBC589F88], // 1e-255 + [0x4BC1558B2F3458DE, 0x96267C7535B763B5], // 1e-254 + [0x9EB1AAEDFB016F16, 0xBBB01B9283253CA2], // 1e-253 + [0x465E15A979C1CADC, 0xEA9C227723EE8BCB], // 1e-252 + [0x0BFACD89EC191EC9, 0x92A1958A7675175F], // 1e-251 + [0xCEF980EC671F667B, 0xB749FAED14125D36], // 1e-250 + [0x82B7E12780E7401A, 0xE51C79A85916F484], // 1e-249 + [0xD1B2ECB8B0908810, 0x8F31CC0937AE58D2], // 1e-248 + [0x861FA7E6DCB4AA15, 0xB2FE3F0B8599EF07], // 1e-247 + [0x67A791E093E1D49A, 0xDFBDCECE67006AC9], // 1e-246 + [0xE0C8BB2C5C6D24E0, 0x8BD6A141006042BD], // 1e-245 + [0x58FAE9F773886E18, 0xAECC49914078536D], // 1e-244 + [0xAF39A475506A899E, 0xDA7F5BF590966848], // 1e-243 + [0x6D8406C952429603, 0x888F99797A5E012D], // 1e-242 + [0xC8E5087BA6D33B83, 0xAAB37FD7D8F58178], // 1e-241 + [0xFB1E4A9A90880A64, 0xD5605FCDCF32E1D6], // 1e-240 + [0x5CF2EEA09A55067F, 0x855C3BE0A17FCD26], // 1e-239 + [0xF42FAA48C0EA481E, 0xA6B34AD8C9DFC06F], // 1e-238 + [0xF13B94DAF124DA26, 0xD0601D8EFC57B08B], // 1e-237 + [0x76C53D08D6B70858, 0x823C12795DB6CE57], // 1e-236 + [0x54768C4B0C64CA6E, 0xA2CB1717B52481ED], // 1e-235 + [0xA9942F5DCF7DFD09, 0xCB7DDCDDA26DA268], // 1e-234 + [0xD3F93B35435D7C4C, 0xFE5D54150B090B02], // 1e-233 + [0xC47BC5014A1A6DAF, 0x9EFA548D26E5A6E1], // 1e-232 + [0x359AB6419CA1091B, 0xC6B8E9B0709F109A], // 1e-231 + [0xC30163D203C94B62, 0xF867241C8CC6D4C0], // 1e-230 + [0x79E0DE63425DCF1D, 0x9B407691D7FC44F8], // 1e-229 + [0x985915FC12F542E4, 0xC21094364DFB5636], // 1e-228 + [0x3E6F5B7B17B2939D, 0xF294B943E17A2BC4], // 1e-227 + [0xA705992CEECF9C42, 0x979CF3CA6CEC5B5A], // 1e-226 + [0x50C6FF782A838353, 0xBD8430BD08277231], // 1e-225 + [0xA4F8BF5635246428, 0xECE53CEC4A314EBD], // 1e-224 + [0x871B7795E136BE99, 0x940F4613AE5ED136], // 1e-223 + [0x28E2557B59846E3F, 0xB913179899F68584], // 1e-222 + [0x331AEADA2FE589CF, 0xE757DD7EC07426E5], // 1e-221 + [0x3FF0D2C85DEF7621, 0x9096EA6F3848984F], // 1e-220 + [0x0FED077A756B53A9, 0xB4BCA50B065ABE63], // 1e-219 + [0xD3E8495912C62894, 0xE1EBCE4DC7F16DFB], // 1e-218 + [0x64712DD7ABBBD95C, 0x8D3360F09CF6E4BD], // 1e-217 + [0xBD8D794D96AACFB3, 0xB080392CC4349DEC], // 1e-216 + [0xECF0D7A0FC5583A0, 0xDCA04777F541C567], // 1e-215 + [0xF41686C49DB57244, 0x89E42CAAF9491B60], // 1e-214 + [0x311C2875C522CED5, 0xAC5D37D5B79B6239], // 1e-213 + [0x7D633293366B828B, 0xD77485CB25823AC7], // 1e-212 + [0xAE5DFF9C02033197, 0x86A8D39EF77164BC], // 1e-211 + [0xD9F57F830283FDFC, 0xA8530886B54DBDEB], // 1e-210 + [0xD072DF63C324FD7B, 0xD267CAA862A12D66], // 1e-209 + [0x4247CB9E59F71E6D, 0x8380DEA93DA4BC60], // 1e-208 + [0x52D9BE85F074E608, 0xA46116538D0DEB78], // 1e-207 + [0x67902E276C921F8B, 0xCD795BE870516656], // 1e-206 + [0x00BA1CD8A3DB53B6, 0x806BD9714632DFF6], // 1e-205 + [0x80E8A40ECCD228A4, 0xA086CFCD97BF97F3], // 1e-204 + [0x6122CD128006B2CD, 0xC8A883C0FDAF7DF0], // 1e-203 + [0x796B805720085F81, 0xFAD2A4B13D1B5D6C], // 1e-202 + [0xCBE3303674053BB0, 0x9CC3A6EEC6311A63], // 1e-201 + [0xBEDBFC4411068A9C, 0xC3F490AA77BD60FC], // 1e-200 + [0xEE92FB5515482D44, 0xF4F1B4D515ACB93B], // 1e-199 + [0x751BDD152D4D1C4A, 0x991711052D8BF3C5], // 1e-198 + [0xD262D45A78A0635D, 0xBF5CD54678EEF0B6], // 1e-197 + [0x86FB897116C87C34, 0xEF340A98172AACE4], // 1e-196 + [0xD45D35E6AE3D4DA0, 0x9580869F0E7AAC0E], // 1e-195 + [0x8974836059CCA109, 0xBAE0A846D2195712], // 1e-194 + [0x2BD1A438703FC94B, 0xE998D258869FACD7], // 1e-193 + [0x7B6306A34627DDCF, 0x91FF83775423CC06], // 1e-192 + [0x1A3BC84C17B1D542, 0xB67F6455292CBF08], // 1e-191 + [0x20CABA5F1D9E4A93, 0xE41F3D6A7377EECA], // 1e-190 + [0x547EB47B7282EE9C, 0x8E938662882AF53E], // 1e-189 + [0xE99E619A4F23AA43, 0xB23867FB2A35B28D], // 1e-188 + [0x6405FA00E2EC94D4, 0xDEC681F9F4C31F31], // 1e-187 + [0xDE83BC408DD3DD04, 0x8B3C113C38F9F37E], // 1e-186 + [0x9624AB50B148D445, 0xAE0B158B4738705E], // 1e-185 + [0x3BADD624DD9B0957, 0xD98DDAEE19068C76], // 1e-184 + [0xE54CA5D70A80E5D6, 0x87F8A8D4CFA417C9], // 1e-183 + [0x5E9FCF4CCD211F4C, 0xA9F6D30A038D1DBC], // 1e-182 + [0x7647C3200069671F, 0xD47487CC8470652B], // 1e-181 + [0x29ECD9F40041E073, 0x84C8D4DFD2C63F3B], // 1e-180 + [0xF468107100525890, 0xA5FB0A17C777CF09], // 1e-179 + [0x7182148D4066EEB4, 0xCF79CC9DB955C2CC], // 1e-178 + [0xC6F14CD848405530, 0x81AC1FE293D599BF], // 1e-177 + [0xB8ADA00E5A506A7C, 0xA21727DB38CB002F], // 1e-176 + [0xA6D90811F0E4851C, 0xCA9CF1D206FDC03B], // 1e-175 + [0x908F4A166D1DA663, 0xFD442E4688BD304A], // 1e-174 + [0x9A598E4E043287FE, 0x9E4A9CEC15763E2E], // 1e-173 + [0x40EFF1E1853F29FD, 0xC5DD44271AD3CDBA], // 1e-172 + [0xD12BEE59E68EF47C, 0xF7549530E188C128], // 1e-171 + [0x82BB74F8301958CE, 0x9A94DD3E8CF578B9], // 1e-170 + [0xE36A52363C1FAF01, 0xC13A148E3032D6E7], // 1e-169 + [0xDC44E6C3CB279AC1, 0xF18899B1BC3F8CA1], // 1e-168 + [0x29AB103A5EF8C0B9, 0x96F5600F15A7B7E5], // 1e-167 + [0x7415D448F6B6F0E7, 0xBCB2B812DB11A5DE], // 1e-166 + [0x111B495B3464AD21, 0xEBDF661791D60F56], // 1e-165 + [0xCAB10DD900BEEC34, 0x936B9FCEBB25C995], // 1e-164 + [0x3D5D514F40EEA742, 0xB84687C269EF3BFB], // 1e-163 + [0x0CB4A5A3112A5112, 0xE65829B3046B0AFA], // 1e-162 + [0x47F0E785EABA72AB, 0x8FF71A0FE2C2E6DC], // 1e-161 + [0x59ED216765690F56, 0xB3F4E093DB73A093], // 1e-160 + [0x306869C13EC3532C, 0xE0F218B8D25088B8], // 1e-159 + [0x1E414218C73A13FB, 0x8C974F7383725573], // 1e-158 + [0xE5D1929EF90898FA, 0xAFBD2350644EEACF], // 1e-157 + [0xDF45F746B74ABF39, 0xDBAC6C247D62A583], // 1e-156 + [0x6B8BBA8C328EB783, 0x894BC396CE5DA772], // 1e-155 + [0x066EA92F3F326564, 0xAB9EB47C81F5114F], // 1e-154 + [0xC80A537B0EFEFEBD, 0xD686619BA27255A2], // 1e-153 + [0xBD06742CE95F5F36, 0x8613FD0145877585], // 1e-152 + [0x2C48113823B73704, 0xA798FC4196E952E7], // 1e-151 + [0xF75A15862CA504C5, 0xD17F3B51FCA3A7A0], // 1e-150 + [0x9A984D73DBE722FB, 0x82EF85133DE648C4], // 1e-149 + [0xC13E60D0D2E0EBBA, 0xA3AB66580D5FDAF5], // 1e-148 + [0x318DF905079926A8, 0xCC963FEE10B7D1B3], // 1e-147 + [0xFDF17746497F7052, 0xFFBBCFE994E5C61F], // 1e-146 + [0xFEB6EA8BEDEFA633, 0x9FD561F1FD0F9BD3], // 1e-145 + [0xFE64A52EE96B8FC0, 0xC7CABA6E7C5382C8], // 1e-144 + [0x3DFDCE7AA3C673B0, 0xF9BD690A1B68637B], // 1e-143 + [0x06BEA10CA65C084E, 0x9C1661A651213E2D], // 1e-142 + [0x486E494FCFF30A62, 0xC31BFA0FE5698DB8], // 1e-141 + [0x5A89DBA3C3EFCCFA, 0xF3E2F893DEC3F126], // 1e-140 + [0xF89629465A75E01C, 0x986DDB5C6B3A76B7], // 1e-139 + [0xF6BBB397F1135823, 0xBE89523386091465], // 1e-138 + [0x746AA07DED582E2C, 0xEE2BA6C0678B597F], // 1e-137 + [0xA8C2A44EB4571CDC, 0x94DB483840B717EF], // 1e-136 + [0x92F34D62616CE413, 0xBA121A4650E4DDEB], // 1e-135 + [0x77B020BAF9C81D17, 0xE896A0D7E51E1566], // 1e-134 + [0x0ACE1474DC1D122E, 0x915E2486EF32CD60], // 1e-133 + [0x0D819992132456BA, 0xB5B5ADA8AAFF80B8], // 1e-132 + [0x10E1FFF697ED6C69, 0xE3231912D5BF60E6], // 1e-131 + [0xCA8D3FFA1EF463C1, 0x8DF5EFABC5979C8F], // 1e-130 + [0xBD308FF8A6B17CB2, 0xB1736B96B6FD83B3], // 1e-129 + [0xAC7CB3F6D05DDBDE, 0xDDD0467C64BCE4A0], // 1e-128 + [0x6BCDF07A423AA96B, 0x8AA22C0DBEF60EE4], // 1e-127 + [0x86C16C98D2C953C6, 0xAD4AB7112EB3929D], // 1e-126 + [0xE871C7BF077BA8B7, 0xD89D64D57A607744], // 1e-125 + [0x11471CD764AD4972, 0x87625F056C7C4A8B], // 1e-124 + [0xD598E40D3DD89BCF, 0xA93AF6C6C79B5D2D], // 1e-123 + [0x4AFF1D108D4EC2C3, 0xD389B47879823479], // 1e-122 + [0xCEDF722A585139BA, 0x843610CB4BF160CB], // 1e-121 + [0xC2974EB4EE658828, 0xA54394FE1EEDB8FE], // 1e-120 + [0x733D226229FEEA32, 0xCE947A3DA6A9273E], // 1e-119 + [0x0806357D5A3F525F, 0x811CCC668829B887], // 1e-118 + [0xCA07C2DCB0CF26F7, 0xA163FF802A3426A8], // 1e-117 + [0xFC89B393DD02F0B5, 0xC9BCFF6034C13052], // 1e-116 + [0xBBAC2078D443ACE2, 0xFC2C3F3841F17C67], // 1e-115 + [0xD54B944B84AA4C0D, 0x9D9BA7832936EDC0], // 1e-114 + [0x0A9E795E65D4DF11, 0xC5029163F384A931], // 1e-113 + [0x4D4617B5FF4A16D5, 0xF64335BCF065D37D], // 1e-112 + [0x504BCED1BF8E4E45, 0x99EA0196163FA42E], // 1e-111 + [0xE45EC2862F71E1D6, 0xC06481FB9BCF8D39], // 1e-110 + [0x5D767327BB4E5A4C, 0xF07DA27A82C37088], // 1e-109 + [0x3A6A07F8D510F86F, 0x964E858C91BA2655], // 1e-108 + [0x890489F70A55368B, 0xBBE226EFB628AFEA], // 1e-107 + [0x2B45AC74CCEA842E, 0xEADAB0ABA3B2DBE5], // 1e-106 + [0x3B0B8BC90012929D, 0x92C8AE6B464FC96F], // 1e-105 + [0x09CE6EBB40173744, 0xB77ADA0617E3BBCB], // 1e-104 + [0xCC420A6A101D0515, 0xE55990879DDCAABD], // 1e-103 + [0x9FA946824A12232D, 0x8F57FA54C2A9EAB6], // 1e-102 + [0x47939822DC96ABF9, 0xB32DF8E9F3546564], // 1e-101 + [0x59787E2B93BC56F7, 0xDFF9772470297EBD], // 1e-100 + [0x57EB4EDB3C55B65A, 0x8BFBEA76C619EF36], // 1e-99 + [0xEDE622920B6B23F1, 0xAEFAE51477A06B03], // 1e-98 + [0xE95FAB368E45ECED, 0xDAB99E59958885C4], // 1e-97 + [0x11DBCB0218EBB414, 0x88B402F7FD75539B], // 1e-96 + [0xD652BDC29F26A119, 0xAAE103B5FCD2A881], // 1e-95 + [0x4BE76D3346F0495F, 0xD59944A37C0752A2], // 1e-94 + [0x6F70A4400C562DDB, 0x857FCAE62D8493A5], // 1e-93 + [0xCB4CCD500F6BB952, 0xA6DFBD9FB8E5B88E], // 1e-92 + [0x7E2000A41346A7A7, 0xD097AD07A71F26B2], // 1e-91 + [0x8ED400668C0C28C8, 0x825ECC24C873782F], // 1e-90 + [0x728900802F0F32FA, 0xA2F67F2DFA90563B], // 1e-89 + [0x4F2B40A03AD2FFB9, 0xCBB41EF979346BCA], // 1e-88 + [0xE2F610C84987BFA8, 0xFEA126B7D78186BC], // 1e-87 + [0x0DD9CA7D2DF4D7C9, 0x9F24B832E6B0F436], // 1e-86 + [0x91503D1C79720DBB, 0xC6EDE63FA05D3143], // 1e-85 + [0x75A44C6397CE912A, 0xF8A95FCF88747D94], // 1e-84 + [0xC986AFBE3EE11ABA, 0x9B69DBE1B548CE7C], // 1e-83 + [0xFBE85BADCE996168, 0xC24452DA229B021B], // 1e-82 + [0xFAE27299423FB9C3, 0xF2D56790AB41C2A2], // 1e-81 + [0xDCCD879FC967D41A, 0x97C560BA6B0919A5], // 1e-80 + [0x5400E987BBC1C920, 0xBDB6B8E905CB600F], // 1e-79 + [0x290123E9AAB23B68, 0xED246723473E3813], // 1e-78 + [0xF9A0B6720AAF6521, 0x9436C0760C86E30B], // 1e-77 + [0xF808E40E8D5B3E69, 0xB94470938FA89BCE], // 1e-76 + [0xB60B1D1230B20E04, 0xE7958CB87392C2C2], // 1e-75 + [0xB1C6F22B5E6F48C2, 0x90BD77F3483BB9B9], // 1e-74 + [0x1E38AEB6360B1AF3, 0xB4ECD5F01A4AA828], // 1e-73 + [0x25C6DA63C38DE1B0, 0xE2280B6C20DD5232], // 1e-72 + [0x579C487E5A38AD0E, 0x8D590723948A535F], // 1e-71 + [0x2D835A9DF0C6D851, 0xB0AF48EC79ACE837], // 1e-70 + [0xF8E431456CF88E65, 0xDCDB1B2798182244], // 1e-69 + [0x1B8E9ECB641B58FF, 0x8A08F0F8BF0F156B], // 1e-68 + [0xE272467E3D222F3F, 0xAC8B2D36EED2DAC5], // 1e-67 + [0x5B0ED81DCC6ABB0F, 0xD7ADF884AA879177], // 1e-66 + [0x98E947129FC2B4E9, 0x86CCBB52EA94BAEA], // 1e-65 + [0x3F2398D747B36224, 0xA87FEA27A539E9A5], // 1e-64 + [0x8EEC7F0D19A03AAD, 0xD29FE4B18E88640E], // 1e-63 + [0x1953CF68300424AC, 0x83A3EEEEF9153E89], // 1e-62 + [0x5FA8C3423C052DD7, 0xA48CEAAAB75A8E2B], // 1e-61 + [0x3792F412CB06794D, 0xCDB02555653131B6], // 1e-60 + [0xE2BBD88BBEE40BD0, 0x808E17555F3EBF11], // 1e-59 + [0x5B6ACEAEAE9D0EC4, 0xA0B19D2AB70E6ED6], // 1e-58 + [0xF245825A5A445275, 0xC8DE047564D20A8B], // 1e-57 + [0xEED6E2F0F0D56712, 0xFB158592BE068D2E], // 1e-56 + [0x55464DD69685606B, 0x9CED737BB6C4183D], // 1e-55 + [0xAA97E14C3C26B886, 0xC428D05AA4751E4C], // 1e-54 + [0xD53DD99F4B3066A8, 0xF53304714D9265DF], // 1e-53 + [0xE546A8038EFE4029, 0x993FE2C6D07B7FAB], // 1e-52 + [0xDE98520472BDD033, 0xBF8FDB78849A5F96], // 1e-51 + [0x963E66858F6D4440, 0xEF73D256A5C0F77C], // 1e-50 + [0xDDE7001379A44AA8, 0x95A8637627989AAD], // 1e-49 + [0x5560C018580D5D52, 0xBB127C53B17EC159], // 1e-48 + [0xAAB8F01E6E10B4A6, 0xE9D71B689DDE71AF], // 1e-47 + [0xCAB3961304CA70E8, 0x9226712162AB070D], // 1e-46 + [0x3D607B97C5FD0D22, 0xB6B00D69BB55C8D1], // 1e-45 + [0x8CB89A7DB77C506A, 0xE45C10C42A2B3B05], // 1e-44 + [0x77F3608E92ADB242, 0x8EB98A7A9A5B04E3], // 1e-43 + [0x55F038B237591ED3, 0xB267ED1940F1C61C], // 1e-42 + [0x6B6C46DEC52F6688, 0xDF01E85F912E37A3], // 1e-41 + [0x2323AC4B3B3DA015, 0x8B61313BBABCE2C6], // 1e-40 + [0xABEC975E0A0D081A, 0xAE397D8AA96C1B77], // 1e-39 + [0x96E7BD358C904A21, 0xD9C7DCED53C72255], // 1e-38 + [0x7E50D64177DA2E54, 0x881CEA14545C7575], // 1e-37 + [0xDDE50BD1D5D0B9E9, 0xAA242499697392D2], // 1e-36 + [0x955E4EC64B44E864, 0xD4AD2DBFC3D07787], // 1e-35 + [0xBD5AF13BEF0B113E, 0x84EC3C97DA624AB4], // 1e-34 + [0xECB1AD8AEACDD58E, 0xA6274BBDD0FADD61], // 1e-33 + [0x67DE18EDA5814AF2, 0xCFB11EAD453994BA], // 1e-32 + [0x80EACF948770CED7, 0x81CEB32C4B43FCF4], // 1e-31 + [0xA1258379A94D028D, 0xA2425FF75E14FC31], // 1e-30 + [0x096EE45813A04330, 0xCAD2F7F5359A3B3E], // 1e-29 + [0x8BCA9D6E188853FC, 0xFD87B5F28300CA0D], // 1e-28 + [0x775EA264CF55347D, 0x9E74D1B791E07E48], // 1e-27 + [0x95364AFE032A819D, 0xC612062576589DDA], // 1e-26 + [0x3A83DDBD83F52204, 0xF79687AED3EEC551], // 1e-25 + [0xC4926A9672793542, 0x9ABE14CD44753B52], // 1e-24 + [0x75B7053C0F178293, 0xC16D9A0095928A27], // 1e-23 + [0x5324C68B12DD6338, 0xF1C90080BAF72CB1], // 1e-22 + [0xD3F6FC16EBCA5E03, 0x971DA05074DA7BEE], // 1e-21 + [0x88F4BB1CA6BCF584, 0xBCE5086492111AEA], // 1e-20 + [0x2B31E9E3D06C32E5, 0xEC1E4A7DB69561A5], // 1e-19 + [0x3AFF322E62439FCF, 0x9392EE8E921D5D07], // 1e-18 + [0x09BEFEB9FAD487C2, 0xB877AA3236A4B449], // 1e-17 + [0x4C2EBE687989A9B3, 0xE69594BEC44DE15B], // 1e-16 + [0x0F9D37014BF60A10, 0x901D7CF73AB0ACD9], // 1e-15 + [0x538484C19EF38C94, 0xB424DC35095CD80F], // 1e-14 + [0x2865A5F206B06FB9, 0xE12E13424BB40E13], // 1e-13 + [0xF93F87B7442E45D3, 0x8CBCCC096F5088CB], // 1e-12 + [0xF78F69A51539D748, 0xAFEBFF0BCB24AAFE], // 1e-11 + [0xB573440E5A884D1B, 0xDBE6FECEBDEDD5BE], // 1e-10 + [0x31680A88F8953030, 0x89705F4136B4A597], // 1e-9 + [0xFDC20D2B36BA7C3D, 0xABCC77118461CEFC], // 1e-8 + [0x3D32907604691B4C, 0xD6BF94D5E57A42BC], // 1e-7 + [0xA63F9A49C2C1B10F, 0x8637BD05AF6C69B5], // 1e-6 + [0x0FCF80DC33721D53, 0xA7C5AC471B478423], // 1e-5 + [0xD3C36113404EA4A8, 0xD1B71758E219652B], // 1e-4 + [0x645A1CAC083126E9, 0x83126E978D4FDF3B], // 1e-3 + [0x3D70A3D70A3D70A3, 0xA3D70A3D70A3D70A], // 1e-2 + [0xCCCCCCCCCCCCCCCC, 0xCCCCCCCCCCCCCCCC], // 1e-1 + [0x0000000000000000, 0x8000000000000000], // 1e0 + [0x0000000000000000, 0xA000000000000000], // 1e1 + [0x0000000000000000, 0xC800000000000000], // 1e2 + [0x0000000000000000, 0xFA00000000000000], // 1e3 + [0x0000000000000000, 0x9C40000000000000], // 1e4 + [0x0000000000000000, 0xC350000000000000], // 1e5 + [0x0000000000000000, 0xF424000000000000], // 1e6 + [0x0000000000000000, 0x9896800000000000], // 1e7 + [0x0000000000000000, 0xBEBC200000000000], // 1e8 + [0x0000000000000000, 0xEE6B280000000000], // 1e9 + [0x0000000000000000, 0x9502F90000000000], // 1e10 + [0x0000000000000000, 0xBA43B74000000000], // 1e11 + [0x0000000000000000, 0xE8D4A51000000000], // 1e12 + [0x0000000000000000, 0x9184E72A00000000], // 1e13 + [0x0000000000000000, 0xB5E620F480000000], // 1e14 + [0x0000000000000000, 0xE35FA931A0000000], // 1e15 + [0x0000000000000000, 0x8E1BC9BF04000000], // 1e16 + [0x0000000000000000, 0xB1A2BC2EC5000000], // 1e17 + [0x0000000000000000, 0xDE0B6B3A76400000], // 1e18 + [0x0000000000000000, 0x8AC7230489E80000], // 1e19 + [0x0000000000000000, 0xAD78EBC5AC620000], // 1e20 + [0x0000000000000000, 0xD8D726B7177A8000], // 1e21 + [0x0000000000000000, 0x878678326EAC9000], // 1e22 + [0x0000000000000000, 0xA968163F0A57B400], // 1e23 + [0x0000000000000000, 0xD3C21BCECCEDA100], // 1e24 + [0x0000000000000000, 0x84595161401484A0], // 1e25 + [0x0000000000000000, 0xA56FA5B99019A5C8], // 1e26 + [0x0000000000000000, 0xCECB8F27F4200F3A], // 1e27 + [0x4000000000000000, 0x813F3978F8940984], // 1e28 + [0x5000000000000000, 0xA18F07D736B90BE5], // 1e29 + [0xA400000000000000, 0xC9F2C9CD04674EDE], // 1e30 + [0x4D00000000000000, 0xFC6F7C4045812296], // 1e31 + [0xF020000000000000, 0x9DC5ADA82B70B59D], // 1e32 + [0x6C28000000000000, 0xC5371912364CE305], // 1e33 + [0xC732000000000000, 0xF684DF56C3E01BC6], // 1e34 + [0x3C7F400000000000, 0x9A130B963A6C115C], // 1e35 + [0x4B9F100000000000, 0xC097CE7BC90715B3], // 1e36 + [0x1E86D40000000000, 0xF0BDC21ABB48DB20], // 1e37 + [0x1314448000000000, 0x96769950B50D88F4], // 1e38 + [0x17D955A000000000, 0xBC143FA4E250EB31], // 1e39 + [0x5DCFAB0800000000, 0xEB194F8E1AE525FD], // 1e40 + [0x5AA1CAE500000000, 0x92EFD1B8D0CF37BE], // 1e41 + [0xF14A3D9E40000000, 0xB7ABC627050305AD], // 1e42 + [0x6D9CCD05D0000000, 0xE596B7B0C643C719], // 1e43 + [0xE4820023A2000000, 0x8F7E32CE7BEA5C6F], // 1e44 + [0xDDA2802C8A800000, 0xB35DBF821AE4F38B], // 1e45 + [0xD50B2037AD200000, 0xE0352F62A19E306E], // 1e46 + [0x4526F422CC340000, 0x8C213D9DA502DE45], // 1e47 + [0x9670B12B7F410000, 0xAF298D050E4395D6], // 1e48 + [0x3C0CDD765F114000, 0xDAF3F04651D47B4C], // 1e49 + [0xA5880A69FB6AC800, 0x88D8762BF324CD0F], // 1e50 + [0x8EEA0D047A457A00, 0xAB0E93B6EFEE0053], // 1e51 + [0x72A4904598D6D880, 0xD5D238A4ABE98068], // 1e52 + [0x47A6DA2B7F864750, 0x85A36366EB71F041], // 1e53 + [0x999090B65F67D924, 0xA70C3C40A64E6C51], // 1e54 + [0xFFF4B4E3F741CF6D, 0xD0CF4B50CFE20765], // 1e55 + [0xBFF8F10E7A8921A4, 0x82818F1281ED449F], // 1e56 + [0xAFF72D52192B6A0D, 0xA321F2D7226895C7], // 1e57 + [0x9BF4F8A69F764490, 0xCBEA6F8CEB02BB39], // 1e58 + [0x02F236D04753D5B4, 0xFEE50B7025C36A08], // 1e59 + [0x01D762422C946590, 0x9F4F2726179A2245], // 1e60 + [0x424D3AD2B7B97EF5, 0xC722F0EF9D80AAD6], // 1e61 + [0xD2E0898765A7DEB2, 0xF8EBAD2B84E0D58B], // 1e62 + [0x63CC55F49F88EB2F, 0x9B934C3B330C8577], // 1e63 + [0x3CBF6B71C76B25FB, 0xC2781F49FFCFA6D5], // 1e64 + [0x8BEF464E3945EF7A, 0xF316271C7FC3908A], // 1e65 + [0x97758BF0E3CBB5AC, 0x97EDD871CFDA3A56], // 1e66 + [0x3D52EEED1CBEA317, 0xBDE94E8E43D0C8EC], // 1e67 + [0x4CA7AAA863EE4BDD, 0xED63A231D4C4FB27], // 1e68 + [0x8FE8CAA93E74EF6A, 0x945E455F24FB1CF8], // 1e69 + [0xB3E2FD538E122B44, 0xB975D6B6EE39E436], // 1e70 + [0x60DBBCA87196B616, 0xE7D34C64A9C85D44], // 1e71 + [0xBC8955E946FE31CD, 0x90E40FBEEA1D3A4A], // 1e72 + [0x6BABAB6398BDBE41, 0xB51D13AEA4A488DD], // 1e73 + [0xC696963C7EED2DD1, 0xE264589A4DCDAB14], // 1e74 + [0xFC1E1DE5CF543CA2, 0x8D7EB76070A08AEC], // 1e75 + [0x3B25A55F43294BCB, 0xB0DE65388CC8ADA8], // 1e76 + [0x49EF0EB713F39EBE, 0xDD15FE86AFFAD912], // 1e77 + [0x6E3569326C784337, 0x8A2DBF142DFCC7AB], // 1e78 + [0x49C2C37F07965404, 0xACB92ED9397BF996], // 1e79 + [0xDC33745EC97BE906, 0xD7E77A8F87DAF7FB], // 1e80 + [0x69A028BB3DED71A3, 0x86F0AC99B4E8DAFD], // 1e81 + [0xC40832EA0D68CE0C, 0xA8ACD7C0222311BC], // 1e82 + [0xF50A3FA490C30190, 0xD2D80DB02AABD62B], // 1e83 + [0x792667C6DA79E0FA, 0x83C7088E1AAB65DB], // 1e84 + [0x577001B891185938, 0xA4B8CAB1A1563F52], // 1e85 + [0xED4C0226B55E6F86, 0xCDE6FD5E09ABCF26], // 1e86 + [0x544F8158315B05B4, 0x80B05E5AC60B6178], // 1e87 + [0x696361AE3DB1C721, 0xA0DC75F1778E39D6], // 1e88 + [0x03BC3A19CD1E38E9, 0xC913936DD571C84C], // 1e89 + [0x04AB48A04065C723, 0xFB5878494ACE3A5F], // 1e90 + [0x62EB0D64283F9C76, 0x9D174B2DCEC0E47B], // 1e91 + [0x3BA5D0BD324F8394, 0xC45D1DF942711D9A], // 1e92 + [0xCA8F44EC7EE36479, 0xF5746577930D6500], // 1e93 + [0x7E998B13CF4E1ECB, 0x9968BF6ABBE85F20], // 1e94 + [0x9E3FEDD8C321A67E, 0xBFC2EF456AE276E8], // 1e95 + [0xC5CFE94EF3EA101E, 0xEFB3AB16C59B14A2], // 1e96 + [0xBBA1F1D158724A12, 0x95D04AEE3B80ECE5], // 1e97 + [0x2A8A6E45AE8EDC97, 0xBB445DA9CA61281F], // 1e98 + [0xF52D09D71A3293BD, 0xEA1575143CF97226], // 1e99 + [0x593C2626705F9C56, 0x924D692CA61BE758], // 1e100 + [0x6F8B2FB00C77836C, 0xB6E0C377CFA2E12E], // 1e101 + [0x0B6DFB9C0F956447, 0xE498F455C38B997A], // 1e102 + [0x4724BD4189BD5EAC, 0x8EDF98B59A373FEC], // 1e103 + [0x58EDEC91EC2CB657, 0xB2977EE300C50FE7], // 1e104 + [0x2F2967B66737E3ED, 0xDF3D5E9BC0F653E1], // 1e105 + [0xBD79E0D20082EE74, 0x8B865B215899F46C], // 1e106 + [0xECD8590680A3AA11, 0xAE67F1E9AEC07187], // 1e107 + [0xE80E6F4820CC9495, 0xDA01EE641A708DE9], // 1e108 + [0x3109058D147FDCDD, 0x884134FE908658B2], // 1e109 + [0xBD4B46F0599FD415, 0xAA51823E34A7EEDE], // 1e110 + [0x6C9E18AC7007C91A, 0xD4E5E2CDC1D1EA96], // 1e111 + [0x03E2CF6BC604DDB0, 0x850FADC09923329E], // 1e112 + [0x84DB8346B786151C, 0xA6539930BF6BFF45], // 1e113 + [0xE612641865679A63, 0xCFE87F7CEF46FF16], // 1e114 + [0x4FCB7E8F3F60C07E, 0x81F14FAE158C5F6E], // 1e115 + [0xE3BE5E330F38F09D, 0xA26DA3999AEF7749], // 1e116 + [0x5CADF5BFD3072CC5, 0xCB090C8001AB551C], // 1e117 + [0x73D9732FC7C8F7F6, 0xFDCB4FA002162A63], // 1e118 + [0x2867E7FDDCDD9AFA, 0x9E9F11C4014DDA7E], // 1e119 + [0xB281E1FD541501B8, 0xC646D63501A1511D], // 1e120 + [0x1F225A7CA91A4226, 0xF7D88BC24209A565], // 1e121 + [0x3375788DE9B06958, 0x9AE757596946075F], // 1e122 + [0x0052D6B1641C83AE, 0xC1A12D2FC3978937], // 1e123 + [0xC0678C5DBD23A49A, 0xF209787BB47D6B84], // 1e124 + [0xF840B7BA963646E0, 0x9745EB4D50CE6332], // 1e125 + [0xB650E5A93BC3D898, 0xBD176620A501FBFF], // 1e126 + [0xA3E51F138AB4CEBE, 0xEC5D3FA8CE427AFF], // 1e127 + [0xC66F336C36B10137, 0x93BA47C980E98CDF], // 1e128 + [0xB80B0047445D4184, 0xB8A8D9BBE123F017], // 1e129 + [0xA60DC059157491E5, 0xE6D3102AD96CEC1D], // 1e130 + [0x87C89837AD68DB2F, 0x9043EA1AC7E41392], // 1e131 + [0x29BABE4598C311FB, 0xB454E4A179DD1877], // 1e132 + [0xF4296DD6FEF3D67A, 0xE16A1DC9D8545E94], // 1e133 + [0x1899E4A65F58660C, 0x8CE2529E2734BB1D], // 1e134 + [0x5EC05DCFF72E7F8F, 0xB01AE745B101E9E4], // 1e135 + [0x76707543F4FA1F73, 0xDC21A1171D42645D], // 1e136 + [0x6A06494A791C53A8, 0x899504AE72497EBA], // 1e137 + [0x0487DB9D17636892, 0xABFA45DA0EDBDE69], // 1e138 + [0x45A9D2845D3C42B6, 0xD6F8D7509292D603], // 1e139 + [0x0B8A2392BA45A9B2, 0x865B86925B9BC5C2], // 1e140 + [0x8E6CAC7768D7141E, 0xA7F26836F282B732], // 1e141 + [0x3207D795430CD926, 0xD1EF0244AF2364FF], // 1e142 + [0x7F44E6BD49E807B8, 0x8335616AED761F1F], // 1e143 + [0x5F16206C9C6209A6, 0xA402B9C5A8D3A6E7], // 1e144 + [0x36DBA887C37A8C0F, 0xCD036837130890A1], // 1e145 + [0xC2494954DA2C9789, 0x802221226BE55A64], // 1e146 + [0xF2DB9BAA10B7BD6C, 0xA02AA96B06DEB0FD], // 1e147 + [0x6F92829494E5ACC7, 0xC83553C5C8965D3D], // 1e148 + [0xCB772339BA1F17F9, 0xFA42A8B73ABBF48C], // 1e149 + [0xFF2A760414536EFB, 0x9C69A97284B578D7], // 1e150 + [0xFEF5138519684ABA, 0xC38413CF25E2D70D], // 1e151 + [0x7EB258665FC25D69, 0xF46518C2EF5B8CD1], // 1e152 + [0xEF2F773FFBD97A61, 0x98BF2F79D5993802], // 1e153 + [0xAAFB550FFACFD8FA, 0xBEEEFB584AFF8603], // 1e154 + [0x95BA2A53F983CF38, 0xEEAABA2E5DBF6784], // 1e155 + [0xDD945A747BF26183, 0x952AB45CFA97A0B2], // 1e156 + [0x94F971119AEEF9E4, 0xBA756174393D88DF], // 1e157 + [0x7A37CD5601AAB85D, 0xE912B9D1478CEB17], // 1e158 + [0xAC62E055C10AB33A, 0x91ABB422CCB812EE], // 1e159 + [0x577B986B314D6009, 0xB616A12B7FE617AA], // 1e160 + [0xED5A7E85FDA0B80B, 0xE39C49765FDF9D94], // 1e161 + [0x14588F13BE847307, 0x8E41ADE9FBEBC27D], // 1e162 + [0x596EB2D8AE258FC8, 0xB1D219647AE6B31C], // 1e163 + [0x6FCA5F8ED9AEF3BB, 0xDE469FBD99A05FE3], // 1e164 + [0x25DE7BB9480D5854, 0x8AEC23D680043BEE], // 1e165 + [0xAF561AA79A10AE6A, 0xADA72CCC20054AE9], // 1e166 + [0x1B2BA1518094DA04, 0xD910F7FF28069DA4], // 1e167 + [0x90FB44D2F05D0842, 0x87AA9AFF79042286], // 1e168 + [0x353A1607AC744A53, 0xA99541BF57452B28], // 1e169 + [0x42889B8997915CE8, 0xD3FA922F2D1675F2], // 1e170 + [0x69956135FEBADA11, 0x847C9B5D7C2E09B7], // 1e171 + [0x43FAB9837E699095, 0xA59BC234DB398C25], // 1e172 + [0x94F967E45E03F4BB, 0xCF02B2C21207EF2E], // 1e173 + [0x1D1BE0EEBAC278F5, 0x8161AFB94B44F57D], // 1e174 + [0x6462D92A69731732, 0xA1BA1BA79E1632DC], // 1e175 + [0x7D7B8F7503CFDCFE, 0xCA28A291859BBF93], // 1e176 + [0x5CDA735244C3D43E, 0xFCB2CB35E702AF78], // 1e177 + [0x3A0888136AFA64A7, 0x9DEFBF01B061ADAB], // 1e178 + [0x088AAA1845B8FDD0, 0xC56BAEC21C7A1916], // 1e179 + [0x8AAD549E57273D45, 0xF6C69A72A3989F5B], // 1e180 + [0x36AC54E2F678864B, 0x9A3C2087A63F6399], // 1e181 + [0x84576A1BB416A7DD, 0xC0CB28A98FCF3C7F], // 1e182 + [0x656D44A2A11C51D5, 0xF0FDF2D3F3C30B9F], // 1e183 + [0x9F644AE5A4B1B325, 0x969EB7C47859E743], // 1e184 + [0x873D5D9F0DDE1FEE, 0xBC4665B596706114], // 1e185 + [0xA90CB506D155A7EA, 0xEB57FF22FC0C7959], // 1e186 + [0x09A7F12442D588F2, 0x9316FF75DD87CBD8], // 1e187 + [0x0C11ED6D538AEB2F, 0xB7DCBF5354E9BECE], // 1e188 + [0x8F1668C8A86DA5FA, 0xE5D3EF282A242E81], // 1e189 + [0xF96E017D694487BC, 0x8FA475791A569D10], // 1e190 + [0x37C981DCC395A9AC, 0xB38D92D760EC4455], // 1e191 + [0x85BBE253F47B1417, 0xE070F78D3927556A], // 1e192 + [0x93956D7478CCEC8E, 0x8C469AB843B89562], // 1e193 + [0x387AC8D1970027B2, 0xAF58416654A6BABB], // 1e194 + [0x06997B05FCC0319E, 0xDB2E51BFE9D0696A], // 1e195 + [0x441FECE3BDF81F03, 0x88FCF317F22241E2], // 1e196 + [0xD527E81CAD7626C3, 0xAB3C2FDDEEAAD25A], // 1e197 + [0x8A71E223D8D3B074, 0xD60B3BD56A5586F1], // 1e198 + [0xF6872D5667844E49, 0x85C7056562757456], // 1e199 + [0xB428F8AC016561DB, 0xA738C6BEBB12D16C], // 1e200 + [0xE13336D701BEBA52, 0xD106F86E69D785C7], // 1e201 + [0xECC0024661173473, 0x82A45B450226B39C], // 1e202 + [0x27F002D7F95D0190, 0xA34D721642B06084], // 1e203 + [0x31EC038DF7B441F4, 0xCC20CE9BD35C78A5], // 1e204 + [0x7E67047175A15271, 0xFF290242C83396CE], // 1e205 + [0x0F0062C6E984D386, 0x9F79A169BD203E41], // 1e206 + [0x52C07B78A3E60868, 0xC75809C42C684DD1], // 1e207 + [0xA7709A56CCDF8A82, 0xF92E0C3537826145], // 1e208 + [0x88A66076400BB691, 0x9BBCC7A142B17CCB], // 1e209 + [0x6ACFF893D00EA435, 0xC2ABF989935DDBFE], // 1e210 + [0x0583F6B8C4124D43, 0xF356F7EBF83552FE], // 1e211 + [0xC3727A337A8B704A, 0x98165AF37B2153DE], // 1e212 + [0x744F18C0592E4C5C, 0xBE1BF1B059E9A8D6], // 1e213 + [0x1162DEF06F79DF73, 0xEDA2EE1C7064130C], // 1e214 + [0x8ADDCB5645AC2BA8, 0x9485D4D1C63E8BE7], // 1e215 + [0x6D953E2BD7173692, 0xB9A74A0637CE2EE1], // 1e216 + [0xC8FA8DB6CCDD0437, 0xE8111C87C5C1BA99], // 1e217 + [0x1D9C9892400A22A2, 0x910AB1D4DB9914A0], // 1e218 + [0x2503BEB6D00CAB4B, 0xB54D5E4A127F59C8], // 1e219 + [0x2E44AE64840FD61D, 0xE2A0B5DC971F303A], // 1e220 + [0x5CEAECFED289E5D2, 0x8DA471A9DE737E24], // 1e221 + [0x7425A83E872C5F47, 0xB10D8E1456105DAD], // 1e222 + [0xD12F124E28F77719, 0xDD50F1996B947518], // 1e223 + [0x82BD6B70D99AAA6F, 0x8A5296FFE33CC92F], // 1e224 + [0x636CC64D1001550B, 0xACE73CBFDC0BFB7B], // 1e225 + [0x3C47F7E05401AA4E, 0xD8210BEFD30EFA5A], // 1e226 + [0x65ACFAEC34810A71, 0x8714A775E3E95C78], // 1e227 + [0x7F1839A741A14D0D, 0xA8D9D1535CE3B396], // 1e228 + [0x1EDE48111209A050, 0xD31045A8341CA07C], // 1e229 + [0x934AED0AAB460432, 0x83EA2B892091E44D], // 1e230 + [0xF81DA84D5617853F, 0xA4E4B66B68B65D60], // 1e231 + [0x36251260AB9D668E, 0xCE1DE40642E3F4B9], // 1e232 + [0xC1D72B7C6B426019, 0x80D2AE83E9CE78F3], // 1e233 + [0xB24CF65B8612F81F, 0xA1075A24E4421730], // 1e234 + [0xDEE033F26797B627, 0xC94930AE1D529CFC], // 1e235 + [0x169840EF017DA3B1, 0xFB9B7CD9A4A7443C], // 1e236 + [0x8E1F289560EE864E, 0x9D412E0806E88AA5], // 1e237 + [0xF1A6F2BAB92A27E2, 0xC491798A08A2AD4E], // 1e238 + [0xAE10AF696774B1DB, 0xF5B5D7EC8ACB58A2], // 1e239 + [0xACCA6DA1E0A8EF29, 0x9991A6F3D6BF1765], // 1e240 + [0x17FD090A58D32AF3, 0xBFF610B0CC6EDD3F], // 1e241 + [0xDDFC4B4CEF07F5B0, 0xEFF394DCFF8A948E], // 1e242 + [0x4ABDAF101564F98E, 0x95F83D0A1FB69CD9], // 1e243 + [0x9D6D1AD41ABE37F1, 0xBB764C4CA7A4440F], // 1e244 + [0x84C86189216DC5ED, 0xEA53DF5FD18D5513], // 1e245 + [0x32FD3CF5B4E49BB4, 0x92746B9BE2F8552C], // 1e246 + [0x3FBC8C33221DC2A1, 0xB7118682DBB66A77], // 1e247 + [0x0FABAF3FEAA5334A, 0xE4D5E82392A40515], // 1e248 + [0x29CB4D87F2A7400E, 0x8F05B1163BA6832D], // 1e249 + [0x743E20E9EF511012, 0xB2C71D5BCA9023F8], // 1e250 + [0x914DA9246B255416, 0xDF78E4B2BD342CF6], // 1e251 + [0x1AD089B6C2F7548E, 0x8BAB8EEFB6409C1A], // 1e252 + [0xA184AC2473B529B1, 0xAE9672ABA3D0C320], // 1e253 + [0xC9E5D72D90A2741E, 0xDA3C0F568CC4F3E8], // 1e254 + [0x7E2FA67C7A658892, 0x8865899617FB1871], // 1e255 + [0xDDBB901B98FEEAB7, 0xAA7EEBFB9DF9DE8D], // 1e256 + [0x552A74227F3EA565, 0xD51EA6FA85785631], // 1e257 + [0xD53A88958F87275F, 0x8533285C936B35DE], // 1e258 + [0x8A892ABAF368F137, 0xA67FF273B8460356], // 1e259 + [0x2D2B7569B0432D85, 0xD01FEF10A657842C], // 1e260 + [0x9C3B29620E29FC73, 0x8213F56A67F6B29B], // 1e261 + [0x8349F3BA91B47B8F, 0xA298F2C501F45F42], // 1e262 + [0x241C70A936219A73, 0xCB3F2F7642717713], // 1e263 + [0xED238CD383AA0110, 0xFE0EFB53D30DD4D7], // 1e264 + [0xF4363804324A40AA, 0x9EC95D1463E8A506], // 1e265 + [0xB143C6053EDCD0D5, 0xC67BB4597CE2CE48], // 1e266 + [0xDD94B7868E94050A, 0xF81AA16FDC1B81DA], // 1e267 + [0xCA7CF2B4191C8326, 0x9B10A4E5E9913128], // 1e268 + [0xFD1C2F611F63A3F0, 0xC1D4CE1F63F57D72], // 1e269 + [0xBC633B39673C8CEC, 0xF24A01A73CF2DCCF], // 1e270 + [0xD5BE0503E085D813, 0x976E41088617CA01], // 1e271 + [0x4B2D8644D8A74E18, 0xBD49D14AA79DBC82], // 1e272 + [0xDDF8E7D60ED1219E, 0xEC9C459D51852BA2], // 1e273 + [0xCABB90E5C942B503, 0x93E1AB8252F33B45], // 1e274 + [0x3D6A751F3B936243, 0xB8DA1662E7B00A17], // 1e275 + [0x0CC512670A783AD4, 0xE7109BFBA19C0C9D], // 1e276 + [0x27FB2B80668B24C5, 0x906A617D450187E2], // 1e277 + [0xB1F9F660802DEDF6, 0xB484F9DC9641E9DA], // 1e278 + [0x5E7873F8A0396973, 0xE1A63853BBD26451], // 1e279 + [0xDB0B487B6423E1E8, 0x8D07E33455637EB2], // 1e280 + [0x91CE1A9A3D2CDA62, 0xB049DC016ABC5E5F], // 1e281 + [0x7641A140CC7810FB, 0xDC5C5301C56B75F7], // 1e282 + [0xA9E904C87FCB0A9D, 0x89B9B3E11B6329BA], // 1e283 + [0x546345FA9FBDCD44, 0xAC2820D9623BF429], // 1e284 + [0xA97C177947AD4095, 0xD732290FBACAF133], // 1e285 + [0x49ED8EABCCCC485D, 0x867F59A9D4BED6C0], // 1e286 + [0x5C68F256BFFF5A74, 0xA81F301449EE8C70], // 1e287 + [0x73832EEC6FFF3111, 0xD226FC195C6A2F8C], // 1e288 + [0xC831FD53C5FF7EAB, 0x83585D8FD9C25DB7], // 1e289 + [0xBA3E7CA8B77F5E55, 0xA42E74F3D032F525], // 1e290 + [0x28CE1BD2E55F35EB, 0xCD3A1230C43FB26F], // 1e291 + [0x7980D163CF5B81B3, 0x80444B5E7AA7CF85], // 1e292 + [0xD7E105BCC332621F, 0xA0555E361951C366], // 1e293 + [0x8DD9472BF3FEFAA7, 0xC86AB5C39FA63440], // 1e294 + [0xB14F98F6F0FEB951, 0xFA856334878FC150], // 1e295 + [0x6ED1BF9A569F33D3, 0x9C935E00D4B9D8D2], // 1e296 + [0x0A862F80EC4700C8, 0xC3B8358109E84F07], // 1e297 + [0xCD27BB612758C0FA, 0xF4A642E14C6262C8], // 1e298 + [0x8038D51CB897789C, 0x98E7E9CCCFBD7DBD], // 1e299 + [0xE0470A63E6BD56C3, 0xBF21E44003ACDD2C], // 1e300 + [0x1858CCFCE06CAC74, 0xEEEA5D5004981478], // 1e301 + [0x0F37801E0C43EBC8, 0x95527A5202DF0CCB], // 1e302 + [0xD30560258F54E6BA, 0xBAA718E68396CFFD], // 1e303 + [0x47C6B82EF32A2069, 0xE950DF20247C83FD], // 1e304 + [0x4CDC331D57FA5441, 0x91D28B7416CDD27E], // 1e305 + [0xE0133FE4ADF8E952, 0xB6472E511C81471D], // 1e306 + [0x58180FDDD97723A6, 0xE3D8F9E563A198E5], // 1e307 + [0x570F09EAA7EA7648, 0x8E679C2F5E44FF8F], // 1e308 + [0x2CD2CC6551E513DA, 0xB201833B35D63F73], // 1e309 + [0xF8077F7EA65E58D1, 0xDE81E40A034BCF4F], // 1e310 + [0xFB04AFAF27FAF782, 0x8B112E86420F6191], // 1e311 + [0x79C5DB9AF1F9B563, 0xADD57A27D29339F6], // 1e312 + [0x18375281AE7822BC, 0xD94AD8B1C7380874], // 1e313 + [0x8F2293910D0B15B5, 0x87CEC76F1C830548], // 1e314 + [0xB2EB3875504DDB22, 0xA9C2794AE3A3C69A], // 1e315 + [0x5FA60692A46151EB, 0xD433179D9C8CB841], // 1e316 + [0xDBC7C41BA6BCD333, 0x849FEEC281D7F328], // 1e317 + [0x12B9B522906C0800, 0xA5C7EA73224DEFF3], // 1e318 + [0xD768226B34870A00, 0xCF39E50FEAE16BEF], // 1e319 + [0xE6A1158300D46640, 0x81842F29F2CCE375], // 1e320 + [0x60495AE3C1097FD0, 0xA1E53AF46F801C53], // 1e321 + [0x385BB19CB14BDFC4, 0xCA5E89B18B602368], // 1e322 + [0x46729E03DD9ED7B5, 0xFCF62C1DEE382C42], // 1e323 + [0x6C07A2C26A8346D1, 0x9E19DB92B4E31BA9], // 1e324 + [0xC7098B7305241885, 0xC5A05277621BE293], // 1e325 + [0xB8CBEE4FC66D1EA7, 0xF70867153AA2DB38], // 1e326 + [0x737F74F1DC043328, 0x9A65406D44A5C903], // 1e327 + [0x505F522E53053FF2, 0xC0FE908895CF3B44], // 1e328 + [0x647726B9E7C68FEF, 0xF13E34AABB430A15], // 1e329 + [0x5ECA783430DC19F5, 0x96C6E0EAB509E64D], // 1e330 + [0xB67D16413D132072, 0xBC789925624C5FE0], // 1e331 + [0xE41C5BD18C57E88F, 0xEB96BF6EBADF77D8], // 1e332 + [0x8E91B962F7B6F159, 0x933E37A534CBAAE7], // 1e333 + [0x723627BBB5A4ADB0, 0xB80DC58E81FE95A1], // 1e334 + [0xCEC3B1AAA30DD91C, 0xE61136F2227E3B09], // 1e335 + [0x213A4F0AA5E8A7B1, 0x8FCAC257558EE4E6], // 1e336 + [0xA988E2CD4F62D19D, 0xB3BD72ED2AF29E1F], // 1e337 + [0x93EB1B80A33B8605, 0xE0ACCFA875AF45A7], // 1e338 + [0xBC72F130660533C3, 0x8C6C01C9498D8B88], // 1e339 + [0xEB8FAD7C7F8680B4, 0xAF87023B9BF0EE6A], // 1e340 + [0xA67398DB9F6820E1, 0xDB68C2CA82ED2A05], // 1e341 + [0x88083F8943A1148C, 0x892179BE91D43A43], // 1e342 + [0x6A0A4F6B948959B0, 0xAB69D82E364948D4], // 1e343 + [0x848CE34679ABB01C, 0xD6444E39C3DB9B09], // 1e344 + [0xF2D80E0C0C0B4E11, 0x85EAB0E41A6940E5], // 1e345 + [0x6F8E118F0F0E2195, 0xA7655D1D2103911F], // 1e346 + [0x4B7195F2D2D1A9FB, 0xD13EB46469447567], // 1e347 ] \ No newline at end of file diff --git a/std/conv/error.jule b/std/conv/error.jule index 971011f08..e1267cfe1 100644 --- a/std/conv/error.jule +++ b/std/conv/error.jule @@ -4,9 +4,9 @@ // Error codes of conv package. enum ConvError { - Ok, // No problem. Defined to using internally, any exceptional is not be this code. - OutOfRange, // Indicates that a value is out of range for the target type. - InvalidSyntax, // Indicates that a value does not have the right syntax for the target type. - InvalidBase, // Indicates that a base is invalid. - InvalidBitSize, // Indicates that a bit size is invalid. + Ok, // No problem. Defined to using internally, any exceptional is not be this code. + OutOfRange, // Indicates that a value is out of range for the target type. + InvalidSyntax, // Indicates that a value does not have the right syntax for the target type. + InvalidBase, // Indicates that a base is invalid. + InvalidBitSize, // Indicates that a bit size is invalid. } \ No newline at end of file diff --git a/std/conv/ftoa.jule b/std/conv/ftoa.jule index 553203848..f1e3c2d71 100644 --- a/std/conv/ftoa.jule +++ b/std/conv/ftoa.jule @@ -39,19 +39,19 @@ use std::unsafe use math for std::math struct floatInfo { - mantbits: uint - expbits: uint - bias: int + mantbits: uint + expbits: uint + bias: int } static f32info = floatInfo{23, 8, -127} static f64info = floatInfo{52, 11, -1023} struct decimalSlice { - d: []byte - nd: int - dp: int - neg: bool + d: []byte + nd: int + dp: int + neg: bool } // Converts the floating-point number f to a string, @@ -77,532 +77,532 @@ struct decimalSlice { // The special precision -1 uses the smallest number of digits // necessary such that parse_float will return f exactly. fn FmtFloat(f: f64, fmt: byte, prec: int, bitSize: int): str { - // Return value of [genericFtoa] can be converted with [unsafe::StrFromBytes] safely. - // It returns always head pointer of slice, so deallocation is safe. - // There is no need to make new allocation for string. - ret unsafe::StrFromBytes( - genericFtoa(make([]byte, 0, max(prec + 4 + 1, 24 + 1)), f, fmt, prec, bitSize)) + // Return value of [genericFtoa] can be converted with [unsafe::StrFromBytes] safely. + // It returns always head pointer of slice, so deallocation is safe. + // There is no need to make new allocation for string. + ret unsafe::StrFromBytes( + genericFtoa(make([]byte, 0, max(prec + 4 + 1, 24 + 1)), f, fmt, prec, bitSize)) } fn genericFtoa(mut dst: []byte, val: f64, fmt: byte, mut prec: int, bitSize: int): []byte { - mut bits := u64(0) - let mut flt: &floatInfo = nil - match bitSize { - | 32: - bits = u64(math::F32Bits(f32(val))) - flt = unsafe { (&floatInfo)(&f32info) } - | 64: - bits = math::F64Bits(val) - flt = unsafe { (&floatInfo)(&f64info) } - |: - panic("std::conv: illegal bitSize") - } - - neg := bits>>(flt.expbits + flt.mantbits) != 0 - mut exp := int(bits >> flt.mantbits) & int(1 << flt.expbits - 1) - mut mant := bits & (u64(1) << flt.mantbits - 1) - - match exp { - | int(1 << flt.expbits - 1): - // +inf, NaN - match { - | mant != 0: - ret append(dst, "nan"...) - | neg: - ret append(dst, "-inf"...) - |: - ret append(dst, "+inf"...) - } - | 0: - // denormalized - exp++ - |: - // add implicit top bit - mant |= u64(1) << flt.mantbits - } - exp += flt.bias - - // Pick off easy binary, hex formats. - if fmt == 'b' { - ret fmtB(dst, neg, mant, exp, *flt) - } - if fmt == 'x' || fmt == 'X' { - ret fmtX(dst, prec, fmt, neg, mant, exp, *flt) - } - - if !optimize { - ret bigFtoa(dst, prec, fmt, neg, mant, exp, *flt) - } - - mut digs := decimalSlice{} - mut ok := false - // Negative precision means "only as much as needed to be exact." - shortest := prec < 0 - if shortest { - // Use Ryu algorithm. - digs.d = make([]byte, 32) - ryuFtoaShortest(digs, mant, exp - int(flt.mantbits), *flt) - ok = true - // Precision for shortest representation mode. - match fmt { - | 'e' | 'E': - prec = max(digs.nd - 1, 0) - | 'f': - prec = max(digs.nd - digs.dp, 0) - | 'g' | 'G': - prec = digs.nd - } - } else if fmt != 'f' { - // Fixed number of digits. - mut digits := prec - match fmt { - | 'e' | 'E': - digits++ - | 'g' | 'G': - if prec == 0 { - prec = 1 - } - digits = prec - |: - // Invalid mode. - digits = 1 - } - if bitSize == 32 && digits <= 9 { - digs.d = make([]byte, 24) - ryuFtoaFixed32(digs, u32(mant), exp - int(flt.mantbits), digits) - ok = true - } else if digits <= 18 { - digs.d = make([]byte, 24) - ryuFtoaFixed64(digs, mant, exp - int(flt.mantbits), digits) - ok = true - } - } - if !ok { - ret bigFtoa(dst, prec, fmt, neg, mant, exp, *flt) - } - ret fmtDigits(dst, shortest, neg, digs, prec, fmt) + mut bits := u64(0) + let mut flt: &floatInfo = nil + match bitSize { + | 32: + bits = u64(math::F32Bits(f32(val))) + flt = unsafe { (&floatInfo)(&f32info) } + | 64: + bits = math::F64Bits(val) + flt = unsafe { (&floatInfo)(&f64info) } + |: + panic("std::conv: illegal bitSize") + } + + neg := bits>>(flt.expbits + flt.mantbits) != 0 + mut exp := int(bits >> flt.mantbits) & int(1 << flt.expbits - 1) + mut mant := bits & (u64(1) << flt.mantbits - 1) + + match exp { + | int(1 << flt.expbits - 1): + // +inf, NaN + match { + | mant != 0: + ret append(dst, "nan"...) + | neg: + ret append(dst, "-inf"...) + |: + ret append(dst, "+inf"...) + } + | 0: + // denormalized + exp++ + |: + // add implicit top bit + mant |= u64(1) << flt.mantbits + } + exp += flt.bias + + // Pick off easy binary, hex formats. + if fmt == 'b' { + ret fmtB(dst, neg, mant, exp, *flt) + } + if fmt == 'x' || fmt == 'X' { + ret fmtX(dst, prec, fmt, neg, mant, exp, *flt) + } + + if !optimize { + ret bigFtoa(dst, prec, fmt, neg, mant, exp, *flt) + } + + mut digs := decimalSlice{} + mut ok := false + // Negative precision means "only as much as needed to be exact." + shortest := prec < 0 + if shortest { + // Use Ryu algorithm. + digs.d = make([]byte, 32) + ryuFtoaShortest(digs, mant, exp - int(flt.mantbits), *flt) + ok = true + // Precision for shortest representation mode. + match fmt { + | 'e' | 'E': + prec = max(digs.nd - 1, 0) + | 'f': + prec = max(digs.nd - digs.dp, 0) + | 'g' | 'G': + prec = digs.nd + } + } else if fmt != 'f' { + // Fixed number of digits. + mut digits := prec + match fmt { + | 'e' | 'E': + digits++ + | 'g' | 'G': + if prec == 0 { + prec = 1 + } + digits = prec + |: + // Invalid mode. + digits = 1 + } + if bitSize == 32 && digits <= 9 { + digs.d = make([]byte, 24) + ryuFtoaFixed32(digs, u32(mant), exp - int(flt.mantbits), digits) + ok = true + } else if digits <= 18 { + digs.d = make([]byte, 24) + ryuFtoaFixed64(digs, mant, exp - int(flt.mantbits), digits) + ok = true + } + } + if !ok { + ret bigFtoa(dst, prec, fmt, neg, mant, exp, *flt) + } + ret fmtDigits(dst, shortest, neg, digs, prec, fmt) } // Uses multiprecision computations to format a float. fn bigFtoa(mut dst: []byte, mut prec: int, fmt: byte, neg: bool, - mant: u64, exp: int, &flt: floatInfo): []byte { - mut d := decimal{} - d.assign(mant) - d.shift(exp - int(flt.mantbits)) - mut digs := decimalSlice{} - shortest := prec < 0 - if shortest { - roundShortest(d, mant, exp, flt) - digs = decimalSlice{d: d.d[:], nd: d.nd, dp: d.dp} - // Precision for shortest representation mode. - match fmt { - | 'e' | 'E': - prec = digs.nd - 1 - | 'f': - prec = max(digs.nd - digs.dp, 0) - | 'g' | 'G': - prec = digs.nd - } - } else { - // Round appropriately. - match fmt { - | 'e' | 'E': - d.round(prec + 1) - | 'f': - d.round(d.dp + prec) - | 'g' | 'G': - if prec == 0 { - prec = 1 - } - d.round(prec) - } - digs = decimalSlice{d: d.d[:], nd: d.nd, dp: d.dp} - } - ret fmtDigits(dst, shortest, neg, digs, prec, fmt) + mant: u64, exp: int, &flt: floatInfo): []byte { + mut d := decimal{} + d.assign(mant) + d.shift(exp - int(flt.mantbits)) + mut digs := decimalSlice{} + shortest := prec < 0 + if shortest { + roundShortest(d, mant, exp, flt) + digs = decimalSlice{d: d.d[:], nd: d.nd, dp: d.dp} + // Precision for shortest representation mode. + match fmt { + | 'e' | 'E': + prec = digs.nd - 1 + | 'f': + prec = max(digs.nd - digs.dp, 0) + | 'g' | 'G': + prec = digs.nd + } + } else { + // Round appropriately. + match fmt { + | 'e' | 'E': + d.round(prec + 1) + | 'f': + d.round(d.dp + prec) + | 'g' | 'G': + if prec == 0 { + prec = 1 + } + d.round(prec) + } + digs = decimalSlice{d: d.d[:], nd: d.nd, dp: d.dp} + } + ret fmtDigits(dst, shortest, neg, digs, prec, fmt) } fn fmtDigits(mut dst: []byte, shortest: bool, neg: bool, - digs: decimalSlice, mut prec: int, fmt: byte): []byte { - match fmt { - | 'e' | 'E': - ret fmtE(dst, neg, digs, prec, fmt) - | 'f': - ret fmtF(dst, neg, digs, prec) - | 'g' | 'G': - // trailing fractional zeros in 'e' form will be trimmed. - mut eprec := prec - if eprec > digs.nd && digs.nd >= digs.dp { - eprec = digs.nd - } - // %e is used if the exponent from the conversion - // is less than -4 or greater than or equal to the precision. - // if precision was the shortest possible, use precision 6 for this decision. - if shortest { - eprec = 6 - } - exp := digs.dp - 1 - if exp < -4 || exp >= eprec { - if prec > digs.nd { - prec = digs.nd - } - ret fmtE(dst, neg, digs, prec - 1, fmt + 'e' - 'g') - } - if prec > digs.dp { - prec = digs.nd - } - ret fmtF(dst, neg, digs, max(prec - digs.dp, 0)) - } - - // unknown format - ret append(dst, '%', fmt) + digs: decimalSlice, mut prec: int, fmt: byte): []byte { + match fmt { + | 'e' | 'E': + ret fmtE(dst, neg, digs, prec, fmt) + | 'f': + ret fmtF(dst, neg, digs, prec) + | 'g' | 'G': + // trailing fractional zeros in 'e' form will be trimmed. + mut eprec := prec + if eprec > digs.nd && digs.nd >= digs.dp { + eprec = digs.nd + } + // %e is used if the exponent from the conversion + // is less than -4 or greater than or equal to the precision. + // if precision was the shortest possible, use precision 6 for this decision. + if shortest { + eprec = 6 + } + exp := digs.dp - 1 + if exp < -4 || exp >= eprec { + if prec > digs.nd { + prec = digs.nd + } + ret fmtE(dst, neg, digs, prec - 1, fmt + 'e' - 'g') + } + if prec > digs.dp { + prec = digs.nd + } + ret fmtF(dst, neg, digs, max(prec - digs.dp, 0)) + } + + // unknown format + ret append(dst, '%', fmt) } // Rounds d (= mant * 2^exp) to the shortest number of digits // that will let the original floating point value be precisely reconstructed. fn roundShortest(mut &d: decimal, mant: u64, exp: int, &flt: floatInfo) { - // If mantissa is zero, the number is zero; stop now. - if mant == 0 { - d.nd = 0 - ret - } - - // Compute upper and lower such that any decimal number - // between upper and lower (possibly inclusive) - // will round to the original floating point number. - - // We may see at once that the number is already shortest. - // - // Suppose d is not denormal, so that 2^exp <= d < 10^dp. - // The closest shorter number is at least 10^(dp-nd) away. - // The lower/upper bounds computed below are at distance - // at most 2^(exp-mantbits). - // - // So the number is already shortest if 10^(dp-nd) > 2^(exp-mantbits), - // or equivalently log2(10)*(dp-nd) > exp-mantbits. - // It is true if 332/100*(dp-nd) >= exp-mantbits (log2(10) > 3.32). - minexp := flt.bias + 1 // minimum possible exponent - if exp > minexp && 332*(d.dp-d.nd) >= 100*(exp-int(flt.mantbits)) { - // The number is already shortest. - ret - } - - // d = mant << (exp - mantbits) - // Next highest floating point number is mant+1 << exp-mantbits. - // Our upper bound is halfway between, mant*2+1 << exp-mantbits-1. - mut upper := decimal{} - upper.assign(mant * 2 + 1) - upper.shift(exp - int(flt.mantbits) - 1) - - // d = mant << (exp - mantbits) - // Next lowest floating point number is mant-1 << exp-mantbits, - // unless mant-1 drops the significant bit and exp is not the minimum exp, - // in which case the next lowest is mant*2-1 << exp-mantbits-1. - // Either way, call it mantlo << explo-mantbits. - // Our lower bound is halfway between, mantlo*2+1 << explo-mantbits-1. - mut mantlo := u64(0) - mut explo := 0 - if mant > 1<= d.nd { - break - } - li := ui - upper.dp + lower.dp - mut l := byte('0') // lower digit - if li >= 0 && li < lower.nd { - l = lower.d[li] - } - mut m := byte('0') // middle digit - if mi >= 0 { - m = d.d[mi] - } - mut u := byte('0') // upper digit - if ui < upper.nd { - u = upper.d[ui] - } - - // Okay to round down (truncate) if lower has a different digit - // or if lower is inclusive and is exactly the result of rounding - // down (i.e., and we have reached the final digit of lower). - okdown := l != m || inclusive && li+1 == lower.nd - - match { - | upperdelta == 0 && m+1 < u: - // Example: - // m = 12345xxx - // u = 12347xxx - upperdelta = 2 - | upperdelta == 0 && m != u: - // Example: - // m = 12345xxx - // u = 12346xxx - upperdelta = 1 - | upperdelta == 1 && (m != '9' || u != '0'): - // Example: - // m = 1234598x - // u = 1234600x - upperdelta = 2 - } - // Okay to round up if upper has a different digit and either upper - // is inclusive or upper is bigger than the result of rounding up. - okup := upperdelta > 0 && (inclusive || upperdelta > 1 || ui+1 < upper.nd) - - // If it's okay to do either, then round to the nearest one. - // If it's okay to do only one, do it. - match { - | okdown && okup: - d.round(mi + 1) - ret - | okdown: - d.roundDown(mi + 1) - ret - | okup: - d.roundUp(mi + 1) - ret - } - } + // If mantissa is zero, the number is zero; stop now. + if mant == 0 { + d.nd = 0 + ret + } + + // Compute upper and lower such that any decimal number + // between upper and lower (possibly inclusive) + // will round to the original floating point number. + + // We may see at once that the number is already shortest. + // + // Suppose d is not denormal, so that 2^exp <= d < 10^dp. + // The closest shorter number is at least 10^(dp-nd) away. + // The lower/upper bounds computed below are at distance + // at most 2^(exp-mantbits). + // + // So the number is already shortest if 10^(dp-nd) > 2^(exp-mantbits), + // or equivalently log2(10)*(dp-nd) > exp-mantbits. + // It is true if 332/100*(dp-nd) >= exp-mantbits (log2(10) > 3.32). + minexp := flt.bias + 1 // minimum possible exponent + if exp > minexp && 332*(d.dp-d.nd) >= 100*(exp-int(flt.mantbits)) { + // The number is already shortest. + ret + } + + // d = mant << (exp - mantbits) + // Next highest floating point number is mant+1 << exp-mantbits. + // Our upper bound is halfway between, mant*2+1 << exp-mantbits-1. + mut upper := decimal{} + upper.assign(mant * 2 + 1) + upper.shift(exp - int(flt.mantbits) - 1) + + // d = mant << (exp - mantbits) + // Next lowest floating point number is mant-1 << exp-mantbits, + // unless mant-1 drops the significant bit and exp is not the minimum exp, + // in which case the next lowest is mant*2-1 << exp-mantbits-1. + // Either way, call it mantlo << explo-mantbits. + // Our lower bound is halfway between, mantlo*2+1 << explo-mantbits-1. + mut mantlo := u64(0) + mut explo := 0 + if mant > 1<= d.nd { + break + } + li := ui - upper.dp + lower.dp + mut l := byte('0') // lower digit + if li >= 0 && li < lower.nd { + l = lower.d[li] + } + mut m := byte('0') // middle digit + if mi >= 0 { + m = d.d[mi] + } + mut u := byte('0') // upper digit + if ui < upper.nd { + u = upper.d[ui] + } + + // Okay to round down (truncate) if lower has a different digit + // or if lower is inclusive and is exactly the result of rounding + // down (i.e., and we have reached the final digit of lower). + okdown := l != m || inclusive && li+1 == lower.nd + + match { + | upperdelta == 0 && m+1 < u: + // Example: + // m = 12345xxx + // u = 12347xxx + upperdelta = 2 + | upperdelta == 0 && m != u: + // Example: + // m = 12345xxx + // u = 12346xxx + upperdelta = 1 + | upperdelta == 1 && (m != '9' || u != '0'): + // Example: + // m = 1234598x + // u = 1234600x + upperdelta = 2 + } + // Okay to round up if upper has a different digit and either upper + // is inclusive or upper is bigger than the result of rounding up. + okup := upperdelta > 0 && (inclusive || upperdelta > 1 || ui+1 < upper.nd) + + // If it's okay to do either, then round to the nearest one. + // If it's okay to do only one, do it. + match { + | okdown && okup: + d.round(mi + 1) + ret + | okdown: + d.roundDown(mi + 1) + ret + | okup: + d.roundUp(mi + 1) + ret + } + } } // %e: -d.ddddde±dd fn fmtE(mut dst: []byte, neg: bool, d: decimalSlice, prec: int, fmt: byte): []byte { - // sign - if neg { - dst = append(dst, '-') - } - - // first digit - mut ch := '0' - if d.nd != 0 { - ch = d.d[0] - } - dst = append(dst, ch) - - // .moredigits - if prec > 0 { - dst = append(dst, '.') - mut i := 1 - m := min(d.nd, prec + 1) - if i < m { - dst = append(dst, d.d[i:m]...) - i = m - } - for i <= prec; i++ { - dst = append(dst, '0') - } - } - - // e± - dst = append(dst, fmt) - mut exp := d.dp - 1 - if d.nd == 0 { // special case: 0 has exponent 0 - exp = 0 - } - if exp < 0 { - ch = '-' - exp = -exp - } else { - ch = '+' - } - dst = append(dst, ch) - - // dd or ddd - match { - | exp < 10: - dst = append(dst, '0', byte(exp) + '0') - | exp < 100: - dst = append(dst, byte(exp / 10) + '0', byte(exp % 10) + '0') - |: - dst = append(dst, byte(exp / 100) + '0', byte(exp / 10) % 10 + '0', byte(exp % 10) + '0') - } - - ret dst + // sign + if neg { + dst = append(dst, '-') + } + + // first digit + mut ch := '0' + if d.nd != 0 { + ch = d.d[0] + } + dst = append(dst, ch) + + // .moredigits + if prec > 0 { + dst = append(dst, '.') + mut i := 1 + m := min(d.nd, prec + 1) + if i < m { + dst = append(dst, d.d[i:m]...) + i = m + } + for i <= prec; i++ { + dst = append(dst, '0') + } + } + + // e± + dst = append(dst, fmt) + mut exp := d.dp - 1 + if d.nd == 0 { // special case: 0 has exponent 0 + exp = 0 + } + if exp < 0 { + ch = '-' + exp = -exp + } else { + ch = '+' + } + dst = append(dst, ch) + + // dd or ddd + match { + | exp < 10: + dst = append(dst, '0', byte(exp) + '0') + | exp < 100: + dst = append(dst, byte(exp / 10) + '0', byte(exp % 10) + '0') + |: + dst = append(dst, byte(exp / 100) + '0', byte(exp / 10) % 10 + '0', byte(exp % 10) + '0') + } + + ret dst } // %f: -ddddddd.ddddd fn fmtF(mut dst: []byte, neg: bool, d: decimalSlice, prec: int): []byte { - // sign - if neg { - dst = append(dst, '-') - } - - // integer, padded with zeros as needed. - if d.dp > 0 { - mut m := min(d.nd, d.dp) - dst = append(dst, d.d[:m]...) - for m < d.dp; m++ { - dst = append(dst, '0') - } - } else { - dst = append(dst, '0') - } - // fraction - if prec > 0 { - dst = append(dst, '.') - mut i := 0 - for i < prec; i++ { - mut ch := byte('0') - j := d.dp + i - if 0 <= j && j < d.nd { - ch = d.d[j] - } - dst = append(dst, ch) - } - } - ret dst + // sign + if neg { + dst = append(dst, '-') + } + + // integer, padded with zeros as needed. + if d.dp > 0 { + mut m := min(d.nd, d.dp) + dst = append(dst, d.d[:m]...) + for m < d.dp; m++ { + dst = append(dst, '0') + } + } else { + dst = append(dst, '0') + } + // fraction + if prec > 0 { + dst = append(dst, '.') + mut i := 0 + for i < prec; i++ { + mut ch := byte('0') + j := d.dp + i + if 0 <= j && j < d.nd { + ch = d.d[j] + } + dst = append(dst, ch) + } + } + ret dst } // %b: -ddddddddp±ddd fn fmtB(mut dst: []byte, neg: bool, mant: u64, mut exp: int, &flt: floatInfo): []byte { - // sign - if neg { - dst = append(dst, '-') - } - - // mantissa - dst, _ = fmtBits(dst, mant, 10, false, true) - - // p - dst = append(dst, 'p') - - // ±exponent - exp -= int(flt.mantbits) - if exp >= 0 { - dst = append(dst, '+') - } - dst, _ = fmtBits(dst, u64(exp), 10, exp < 0, true) - ret dst + // sign + if neg { + dst = append(dst, '-') + } + + // mantissa + dst, _ = fmtBits(dst, mant, 10, false, true) + + // p + dst = append(dst, 'p') + + // ±exponent + exp -= int(flt.mantbits) + if exp >= 0 { + dst = append(dst, '+') + } + dst, _ = fmtBits(dst, u64(exp), 10, exp < 0, true) + ret dst } // %x: -0x1.yyyyyyyyp±ddd or -0x0p+0. (y is hex digit, d is decimal digit) fn fmtX(mut dst: []byte, prec: int, fmt: byte, neg: bool, - mut mant: u64, mut exp: int, &flt: floatInfo): []byte { - if mant == 0 { - exp = 0 - } - - // Shift digits so leading 1 (if any) is at bit 1<<60. - mant <<= 60 - flt.mantbits - for mant != 0 && mant&(1<<60) == 0 { - mant <<= 1 - exp-- - } - - // Round if requested. - if prec >= 0 && prec < 15 { - shift := uint(prec * 4) - extra := (mant << shift) & (1 << 60 - 1) - mant >>= 60 - shift - if extra|(mant & 1) > 1<<59 { - mant++ - } - mant <<= 60 - shift - if mant&(1 << 61) != 0 { - // Wrapped around. - mant >>= 1 - exp++ - } - } - - mut hex := "" - if fmt == 'X' { - hex = upperhex - } else { - hex = lowerhex - } - - // sign, 0x, leading digit - if neg { - dst = append(dst, '-') - } - dst = append(dst, '0', fmt, '0' + byte((mant >> 60) & 1)) - - // .fraction - mant <<= 4 // remove leading 0 or 1 - if prec < 0 && mant != 0 { - dst = append(dst, '.') - for mant != 0 { - dst = append(dst, hex[(mant>>60)&15]) - mant <<= 4 - } - } else if prec > 0 { - dst = append(dst, '.') - mut i := 0 - for i < prec; i++ { - dst = append(dst, hex[(mant>>60)&15]) - mant <<= 4 - } - } - - // p± - mut ch := byte('P') - if fmt == lower(fmt) { - ch = 'p' - } - dst = append(dst, ch) - if exp < 0 { - ch = '-' - exp = -exp - } else { - ch = '+' - } - dst = append(dst, ch) - - // dd or ddd or dddd - match { - | exp < 100: - dst = append(dst, byte(exp / 10) + '0', byte(exp % 10) + '0') - | exp < 1000: - dst = append(dst, byte(exp / 100) + '0', byte((exp / 10) % 10) + '0', byte(exp % 10) + '0') - |: - dst = append(dst, byte(exp / 1000) + '0', byte(exp / 100) % 10 + '0', byte((exp / 10) % 10) + '0', byte(exp % 10) + '0') - } - ret dst + mut mant: u64, mut exp: int, &flt: floatInfo): []byte { + if mant == 0 { + exp = 0 + } + + // Shift digits so leading 1 (if any) is at bit 1<<60. + mant <<= 60 - flt.mantbits + for mant != 0 && mant&(1<<60) == 0 { + mant <<= 1 + exp-- + } + + // Round if requested. + if prec >= 0 && prec < 15 { + shift := uint(prec * 4) + extra := (mant << shift) & (1 << 60 - 1) + mant >>= 60 - shift + if extra|(mant & 1) > 1<<59 { + mant++ + } + mant <<= 60 - shift + if mant&(1 << 61) != 0 { + // Wrapped around. + mant >>= 1 + exp++ + } + } + + mut hex := "" + if fmt == 'X' { + hex = upperhex + } else { + hex = lowerhex + } + + // sign, 0x, leading digit + if neg { + dst = append(dst, '-') + } + dst = append(dst, '0', fmt, '0' + byte((mant >> 60) & 1)) + + // .fraction + mant <<= 4 // remove leading 0 or 1 + if prec < 0 && mant != 0 { + dst = append(dst, '.') + for mant != 0 { + dst = append(dst, hex[(mant>>60)&15]) + mant <<= 4 + } + } else if prec > 0 { + dst = append(dst, '.') + mut i := 0 + for i < prec; i++ { + dst = append(dst, hex[(mant>>60)&15]) + mant <<= 4 + } + } + + // p± + mut ch := byte('P') + if fmt == lower(fmt) { + ch = 'p' + } + dst = append(dst, ch) + if exp < 0 { + ch = '-' + exp = -exp + } else { + ch = '+' + } + dst = append(dst, ch) + + // dd or ddd or dddd + match { + | exp < 100: + dst = append(dst, byte(exp / 10) + '0', byte(exp % 10) + '0') + | exp < 1000: + dst = append(dst, byte(exp / 100) + '0', byte((exp / 10) % 10) + '0', byte(exp % 10) + '0') + |: + dst = append(dst, byte(exp / 1000) + '0', byte(exp / 100) % 10 + '0', byte((exp / 10) % 10) + '0', byte(exp % 10) + '0') + } + ret dst } fn min(a: int, b: int): int { - if a < b { - ret a - } - ret b + if a < b { + ret a + } + ret b } fn max(a: int, b: int): int { - if a > b { - ret a - } - ret b + if a > b { + ret a + } + ret b } \ No newline at end of file diff --git a/std/conv/ftoaryu.jule b/std/conv/ftoaryu.jule index e28e8b5fe..7089eba92 100644 --- a/std/conv/ftoaryu.jule +++ b/std/conv/ftoaryu.jule @@ -47,326 +47,326 @@ use bits for std::math::bits // Formats mant*(2^exp) with prec decimal digits. fn ryuFtoaFixed32(mut &d: decimalSlice, mut mant: u32, exp: int, prec: int) { - if prec < 0 { - panic("ryuFtoaFixed32 called with negative prec") - } - if prec > 9 { - panic("ryuFtoaFixed32 called with prec > 9") - } - // Zero input. - if mant == 0 { - d.nd, d.dp = 0, 0 - ret - } - // Renormalize to a 25-bit mantissa. - mut e2 := exp - b := bits::Len32(mant) - if b < 25 { - mant <<= uint(25 - b) - e2 += int(b) - 25 - } - // Choose an exponent such that rounded mant*(2^e2)*(10^q) has - // at least prec decimal digits, i.e - // mant*(2^e2)*(10^q) >= 10^(prec-1) - // Because mant >= 2^24, it is enough to choose: - // 2^(e2+24) >= 10^(-q+prec-1) - // or q = -mulByLog2_log10(e2+24) + prec - 1 - q := -mulByLog2Log10(e2 + 24) + prec - 1 + if prec < 0 { + panic("ryuFtoaFixed32 called with negative prec") + } + if prec > 9 { + panic("ryuFtoaFixed32 called with prec > 9") + } + // Zero input. + if mant == 0 { + d.nd, d.dp = 0, 0 + ret + } + // Renormalize to a 25-bit mantissa. + mut e2 := exp + b := bits::Len32(mant) + if b < 25 { + mant <<= uint(25 - b) + e2 += int(b) - 25 + } + // Choose an exponent such that rounded mant*(2^e2)*(10^q) has + // at least prec decimal digits, i.e + // mant*(2^e2)*(10^q) >= 10^(prec-1) + // Because mant >= 2^24, it is enough to choose: + // 2^(e2+24) >= 10^(-q+prec-1) + // or q = -mulByLog2_log10(e2+24) + prec - 1 + q := -mulByLog2Log10(e2 + 24) + prec - 1 - // Now compute mant*(2^e2)*(10^q). - // Is it an exact computation? - // Only small positive powers of 10 are exact (5^28 has 66 bits). - mut exact := q <= 27 && q >= 0 + // Now compute mant*(2^e2)*(10^q). + // Is it an exact computation? + // Only small positive powers of 10 are exact (5^28 has 66 bits). + mut exact := q <= 27 && q >= 0 - mut di, dexp2, mut d0 := mult64bitPow10(mant, e2, q) - if dexp2 >= 0 { - panic("not enough significant bits after mult64bitPow10") - } - // As a special case, computation might still be exact, if exponent - // was negative and if it amounts to computing an exact division. - // In that case, we ignore all lower bits. - // Note that division by 10^11 cannot be exact as 5^11 has 26 bits. - if q < 0 && q >= -10 && divisibleByPow5(u64(mant), -q) { - exact = true - d0 = true - } - // Remove extra lower bits and keep rounding info. - extra := uint(-dexp2) - extraMask := u32(1 << extra - 1) + mut di, dexp2, mut d0 := mult64bitPow10(mant, e2, q) + if dexp2 >= 0 { + panic("not enough significant bits after mult64bitPow10") + } + // As a special case, computation might still be exact, if exponent + // was negative and if it amounts to computing an exact division. + // In that case, we ignore all lower bits. + // Note that division by 10^11 cannot be exact as 5^11 has 26 bits. + if q < 0 && q >= -10 && divisibleByPow5(u64(mant), -q) { + exact = true + d0 = true + } + // Remove extra lower bits and keep rounding info. + extra := uint(-dexp2) + extraMask := u32(1 << extra - 1) - mut dfrac := u32(0) - di, dfrac = di >> extra, di & extraMask - mut roundUp := false - if exact { - // If we computed an exact product, d + 1/2 - // should round to d+1 if 'd' is odd. - roundUp = (dfrac > 1<<(extra-1) || - (dfrac == 1<<(extra-1) && !d0) || - (dfrac == 1<<(extra-1) && d0 && di&1 == 1)) - } else { - // otherwise, d+1/2 always rounds up because - // we truncated below. - roundUp = dfrac>>(extra - 1) == 1 - } - if dfrac != 0 { - d0 = false - } - // Proceed to the requested number of digits - formatDecimal(d, u64(di), !d0, roundUp, prec) - // Adjust exponent - d.dp -= q + mut dfrac := u32(0) + di, dfrac = di >> extra, di & extraMask + mut roundUp := false + if exact { + // If we computed an exact product, d + 1/2 + // should round to d+1 if 'd' is odd. + roundUp = (dfrac > 1<<(extra-1) || + (dfrac == 1<<(extra-1) && !d0) || + (dfrac == 1<<(extra-1) && d0 && di&1 == 1)) + } else { + // otherwise, d+1/2 always rounds up because + // we truncated below. + roundUp = dfrac>>(extra - 1) == 1 + } + if dfrac != 0 { + d0 = false + } + // Proceed to the requested number of digits + formatDecimal(d, u64(di), !d0, roundUp, prec) + // Adjust exponent + d.dp -= q } // Formats mant*(2^exp) with prec decimal digits. fn ryuFtoaFixed64(mut &d: decimalSlice, mut mant: u64, exp: int, prec: int) { - if prec > 18 { - panic("ryuFtoaFixed64 called with prec > 18") - } - // Zero input. - if mant == 0 { - d.nd, d.dp = 0, 0 - ret - } - // Renormalize to a 55-bit mantissa. - mut e2 := exp - b := bits::Len64(mant) - if b < 55 { - mant = mant << uint(55 - b) - e2 += int(b) - 55 - } - // Choose an exponent such that rounded mant*(2^e2)*(10^q) has - // at least prec decimal digits, i.e - // mant*(2^e2)*(10^q) >= 10^(prec-1) - // Because mant >= 2^54, it is enough to choose: - // 2^(e2+54) >= 10^(-q+prec-1) - // or q = -mulByLog2Log10(e2+54) + prec - 1 - // - // The minimal required exponent is -mulByLog2Log10(1025)+18 = -291 - // The maximal required exponent is mulByLog2Log10(1074)+18 = 342 - q := -mulByLog2Log10(e2 + 54) + prec - 1 + if prec > 18 { + panic("ryuFtoaFixed64 called with prec > 18") + } + // Zero input. + if mant == 0 { + d.nd, d.dp = 0, 0 + ret + } + // Renormalize to a 55-bit mantissa. + mut e2 := exp + b := bits::Len64(mant) + if b < 55 { + mant = mant << uint(55 - b) + e2 += int(b) - 55 + } + // Choose an exponent such that rounded mant*(2^e2)*(10^q) has + // at least prec decimal digits, i.e + // mant*(2^e2)*(10^q) >= 10^(prec-1) + // Because mant >= 2^54, it is enough to choose: + // 2^(e2+54) >= 10^(-q+prec-1) + // or q = -mulByLog2Log10(e2+54) + prec - 1 + // + // The minimal required exponent is -mulByLog2Log10(1025)+18 = -291 + // The maximal required exponent is mulByLog2Log10(1074)+18 = 342 + q := -mulByLog2Log10(e2 + 54) + prec - 1 - // Now compute mant*(2^e2)*(10^q). - // Is it an exact computation? - // Only small positive powers of 10 are exact (5^55 has 128 bits). - mut exact := q <= 55 && q >= 0 + // Now compute mant*(2^e2)*(10^q). + // Is it an exact computation? + // Only small positive powers of 10 are exact (5^55 has 128 bits). + mut exact := q <= 55 && q >= 0 - mut di, dexp2, mut d0 := mult128bitPow10(mant, e2, q) - if dexp2 >= 0 { - panic("not enough significant bits after mult128bitPow10") - } - // As a special case, computation might still be exact, if exponent - // was negative and if it amounts to computing an exact division. - // In that case, we ignore all lower bits. - // Note that division by 10^23 cannot be exact as 5^23 has 54 bits. - if q < 0 && q >= -22 && divisibleByPow5(mant, -q) { - exact = true - d0 = true - } - // Remove extra lower bits and keep rounding info. - extra := uint(-dexp2) - extraMask := u64(1 << extra - 1) + mut di, dexp2, mut d0 := mult128bitPow10(mant, e2, q) + if dexp2 >= 0 { + panic("not enough significant bits after mult128bitPow10") + } + // As a special case, computation might still be exact, if exponent + // was negative and if it amounts to computing an exact division. + // In that case, we ignore all lower bits. + // Note that division by 10^23 cannot be exact as 5^23 has 54 bits. + if q < 0 && q >= -22 && divisibleByPow5(mant, -q) { + exact = true + d0 = true + } + // Remove extra lower bits and keep rounding info. + extra := uint(-dexp2) + extraMask := u64(1 << extra - 1) - mut dfrac := u64(0) - di, dfrac = di >> extra, di & extraMask - mut roundUp := false - if exact { - // If we computed an exact product, d + 1/2 - // should round to d+1 if 'd' is odd. - roundUp = (dfrac > 1<<(extra-1) || - (dfrac == 1<<(extra-1) && !d0) || - (dfrac == 1<<(extra-1) && d0 && di&1 == 1)) - } else { - // otherwise, d+1/2 always rounds up because - // we truncated below. - roundUp = dfrac>>(extra - 1) == 1 - } - if dfrac != 0 { - d0 = false - } - // Proceed to the requested number of digits - formatDecimal(d, di, !d0, roundUp, prec) - // Adjust exponent - d.dp -= q + mut dfrac := u64(0) + di, dfrac = di >> extra, di & extraMask + mut roundUp := false + if exact { + // If we computed an exact product, d + 1/2 + // should round to d+1 if 'd' is odd. + roundUp = (dfrac > 1<<(extra-1) || + (dfrac == 1<<(extra-1) && !d0) || + (dfrac == 1<<(extra-1) && d0 && di&1 == 1)) + } else { + // otherwise, d+1/2 always rounds up because + // we truncated below. + roundUp = dfrac>>(extra - 1) == 1 + } + if dfrac != 0 { + d0 = false + } + // Proceed to the requested number of digits + formatDecimal(d, di, !d0, roundUp, prec) + // Adjust exponent + d.dp -= q } static u64pow10: [...]u64 = [ - 1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, - 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, + 1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, ] // Fills d with at most prec decimal digits // of mantissa m. The boolean trunc indicates whether m // is truncated compared to the original number being formatted. fn formatDecimal(mut &d: decimalSlice, mut m: u64, mut trunc: bool, mut roundUp: bool, prec: int) { - max := u64pow10[prec] - mut trimmed := 0 - for m >= max { - a, b := m / 10, m % 10 - m = a - trimmed++ - if b > 5 { - roundUp = true - } else if b < 5 { - roundUp = false - } else { // b == 5 - // round up if there are trailing digits, - // or if the new value of m is odd (round-to-even convention) - roundUp = trunc || m&1 == 1 - } - if b != 0 { - trunc = true - } - } - if roundUp { - m++ - } - if m >= max { - // Happens if di was originally 99999....xx - m /= 10 - trimmed++ - } - // render digits (similar to formatBits) - mut n := uint(prec) - d.nd = int(prec) - mut v := m - for v >= 100 { - mut v1 := u64(0) - mut v2 := u64(0) - if v>>32 == 0 { - v1, v2 = u64(u32(v) / 100), u64(u32(v) % 100) - } else { - v1, v2 = v / 100, v % 100 - } - n -= 2 - d.d[n+1] = smallsStr[2*v2+1] - d.d[n+0] = smallsStr[2*v2+0] - v = v1 - } - if v > 0 { - n-- - d.d[n] = smallsStr[2*v+1] - } - if v >= 10 { - n-- - d.d[n] = smallsStr[2*v] - } - for d.d[d.nd-1] == '0' { - d.nd-- - trimmed++ - } - d.dp = d.nd + trimmed + max := u64pow10[prec] + mut trimmed := 0 + for m >= max { + a, b := m / 10, m % 10 + m = a + trimmed++ + if b > 5 { + roundUp = true + } else if b < 5 { + roundUp = false + } else { // b == 5 + // round up if there are trailing digits, + // or if the new value of m is odd (round-to-even convention) + roundUp = trunc || m&1 == 1 + } + if b != 0 { + trunc = true + } + } + if roundUp { + m++ + } + if m >= max { + // Happens if di was originally 99999....xx + m /= 10 + trimmed++ + } + // render digits (similar to formatBits) + mut n := uint(prec) + d.nd = int(prec) + mut v := m + for v >= 100 { + mut v1 := u64(0) + mut v2 := u64(0) + if v>>32 == 0 { + v1, v2 = u64(u32(v) / 100), u64(u32(v) % 100) + } else { + v1, v2 = v / 100, v % 100 + } + n -= 2 + d.d[n+1] = smallsStr[2*v2+1] + d.d[n+0] = smallsStr[2*v2+0] + v = v1 + } + if v > 0 { + n-- + d.d[n] = smallsStr[2*v+1] + } + if v >= 10 { + n-- + d.d[n] = smallsStr[2*v] + } + for d.d[d.nd-1] == '0' { + d.nd-- + trimmed++ + } + d.dp = d.nd + trimmed } // Formats mant*2^exp with prec decimal digits. fn ryuFtoaShortest(mut &d: decimalSlice, mut mant: u64, exp: int, &flt: floatInfo) { - if mant == 0 { - d.nd, d.dp = 0, 0 - ret - } - // If input is an exact integer with fewer bits than the mantissa, - // the previous and next integer are not admissible representations. - if exp <= 0 && bits::TrailingZeros64(mant) >= -exp { - mant >>= uint(-exp) - ryuDigits(d, mant, mant, mant, true, false) - ret - } - ml, mc, mu, mut e2 := computeBounds(mant, exp, flt) - if e2 == 0 { - ryuDigits(d, ml, mc, mu, true, false) - ret - } - // Find 10^q *larger* than 2^-e2 - q := mulByLog2Log10(-e2) + 1 + if mant == 0 { + d.nd, d.dp = 0, 0 + ret + } + // If input is an exact integer with fewer bits than the mantissa, + // the previous and next integer are not admissible representations. + if exp <= 0 && bits::TrailingZeros64(mant) >= -exp { + mant >>= uint(-exp) + ryuDigits(d, mant, mant, mant, true, false) + ret + } + ml, mc, mu, mut e2 := computeBounds(mant, exp, flt) + if e2 == 0 { + ryuDigits(d, ml, mc, mu, true, false) + ret + } + // Find 10^q *larger* than 2^-e2 + q := mulByLog2Log10(-e2) + 1 - // We are going to multiply by 10^q using 128-bit arithmetic. - // The exponent is the same for all 3 numbers. - mut dl := u64(0) - mut dc := u64(0) - mut du := u64(0) - mut dl0 := false - mut dc0 := false - mut du0 := false - if flt == f32info { - mut dl32 := u32(0) - mut dc32 := u32(0) - mut du32 := u32(0) - dl32, _, dl0 = mult64bitPow10(u32(ml), e2, q) - dc32, _, dc0 = mult64bitPow10(u32(mc), e2, q) - du32, e2, du0 = mult64bitPow10(u32(mu), e2, q) - dl, dc, du = u64(dl32), u64(dc32), u64(du32) - } else { - dl, _, dl0 = mult128bitPow10(ml, e2, q) - dc, _, dc0 = mult128bitPow10(mc, e2, q) - du, e2, du0 = mult128bitPow10(mu, e2, q) - } - if e2 >= 0 { - panic("not enough significant bits after mult128bitPow10") - } - // Is it an exact computation? - if q > 55 { - // Large positive powers of ten are not exact - dl0, dc0, du0 = false, false, false - } - if q < 0 && q >= -24 { - // Division by a power of ten may be exact. - // (note that 5^25 is a 59-bit number so division by 5^25 is never exact). - if divisibleByPow5(ml, -q) { - dl0 = true - } - if divisibleByPow5(mc, -q) { - dc0 = true - } - if divisibleByPow5(mu, -q) { - du0 = true - } - } - // Express the results (dl, dc, du)*2^e2 as integers. - // Extra bits must be removed and rounding hints computed. - extra := uint(-e2) - extraMask := u64(1 << extra - 1) - // Now compute the floored, integral base 10 mantissas. - mut fracl := u64(0) - dl, fracl = dl >> extra, dl & extraMask - mut fracc := u64(0) - dc, fracc = dc >> extra, dc & extraMask - mut fracu := u64(0) - du, fracu = du >> extra, du & extraMask - // Is it allowed to use 'du' as a result? - // It is always allowed when it is truncated, but also - // if it is exact and the original binary mantissa is even - // When disallowed, we can subtract 1. - mut uok := !du0 || fracu > 0 - if du0 && fracu == 0 { - uok = mant&1 == 0 - } - if !uok { - du-- - } - // Is 'dc' the correctly rounded base 10 mantissa? - // The correct rounding might be dc+1 - mut cup := false // don't round up. - if dc0 { - // If we computed an exact product, the half integer - // should round to next (even) integer if 'dc' is odd. - cup = (fracc > 1<<(extra-1) || - (fracc == 1<<(extra-1) && dc&1 == 1)) - } else { - // otherwise, the result is a lower truncation of the ideal - // result. - cup = fracc>>(extra - 1) == 1 - } - // Is 'dl' an allowed representation? - // Only if it is an exact value, and if the original binary mantissa - // was even. - lok := dl0 && fracl == 0 && (mant&1 == 0) - if !lok { - dl++ - } - // We need to remember whether the trimmed digits of 'dc' are zero. - c0 := dc0 && fracc == 0 - // render digits - ryuDigits(d, dl, dc, du, c0, cup) - d.dp -= q + // We are going to multiply by 10^q using 128-bit arithmetic. + // The exponent is the same for all 3 numbers. + mut dl := u64(0) + mut dc := u64(0) + mut du := u64(0) + mut dl0 := false + mut dc0 := false + mut du0 := false + if flt == f32info { + mut dl32 := u32(0) + mut dc32 := u32(0) + mut du32 := u32(0) + dl32, _, dl0 = mult64bitPow10(u32(ml), e2, q) + dc32, _, dc0 = mult64bitPow10(u32(mc), e2, q) + du32, e2, du0 = mult64bitPow10(u32(mu), e2, q) + dl, dc, du = u64(dl32), u64(dc32), u64(du32) + } else { + dl, _, dl0 = mult128bitPow10(ml, e2, q) + dc, _, dc0 = mult128bitPow10(mc, e2, q) + du, e2, du0 = mult128bitPow10(mu, e2, q) + } + if e2 >= 0 { + panic("not enough significant bits after mult128bitPow10") + } + // Is it an exact computation? + if q > 55 { + // Large positive powers of ten are not exact + dl0, dc0, du0 = false, false, false + } + if q < 0 && q >= -24 { + // Division by a power of ten may be exact. + // (note that 5^25 is a 59-bit number so division by 5^25 is never exact). + if divisibleByPow5(ml, -q) { + dl0 = true + } + if divisibleByPow5(mc, -q) { + dc0 = true + } + if divisibleByPow5(mu, -q) { + du0 = true + } + } + // Express the results (dl, dc, du)*2^e2 as integers. + // Extra bits must be removed and rounding hints computed. + extra := uint(-e2) + extraMask := u64(1 << extra - 1) + // Now compute the floored, integral base 10 mantissas. + mut fracl := u64(0) + dl, fracl = dl >> extra, dl & extraMask + mut fracc := u64(0) + dc, fracc = dc >> extra, dc & extraMask + mut fracu := u64(0) + du, fracu = du >> extra, du & extraMask + // Is it allowed to use 'du' as a result? + // It is always allowed when it is truncated, but also + // if it is exact and the original binary mantissa is even + // When disallowed, we can subtract 1. + mut uok := !du0 || fracu > 0 + if du0 && fracu == 0 { + uok = mant&1 == 0 + } + if !uok { + du-- + } + // Is 'dc' the correctly rounded base 10 mantissa? + // The correct rounding might be dc+1 + mut cup := false // don't round up. + if dc0 { + // If we computed an exact product, the half integer + // should round to next (even) integer if 'dc' is odd. + cup = (fracc > 1<<(extra-1) || + (fracc == 1<<(extra-1) && dc&1 == 1)) + } else { + // otherwise, the result is a lower truncation of the ideal + // result. + cup = fracc>>(extra - 1) == 1 + } + // Is 'dl' an allowed representation? + // Only if it is an exact value, and if the original binary mantissa + // was even. + lok := dl0 && fracl == 0 && (mant&1 == 0) + if !lok { + dl++ + } + // We need to remember whether the trimmed digits of 'dc' are zero. + c0 := dc0 && fracc == 0 + // render digits + ryuDigits(d, dl, dc, du, c0, cup) + d.dp -= q } // Returns std::math::floor(x * log(2)/log(10)) for an integer x in @@ -375,8 +375,8 @@ fn ryuFtoaShortest(mut &d: decimalSlice, mut mant: u64, exp: int, &flt: floatInf // The range restriction lets us work in faster integer arithmetic instead of // slower floating point arithmetic. Correctness is verified by unit tests. fn mulByLog2Log10(x: int): int { - // log(2)/log(10) ≈ 0.30102999566 ≈ 78913 / 2^18 - ret (x * 78913) >> 18 + // log(2)/log(10) ≈ 0.30102999566 ≈ 78913 / 2^18 + ret (x * 78913) >> 18 } // Returns std::math::floor(x * log(10)/log(2)) for an integer x in @@ -385,141 +385,141 @@ fn mulByLog2Log10(x: int): int { // The range restriction lets us work in faster integer arithmetic instead of // slower floating point arithmetic. Correctness is verified by unit tests. fn mulByLog10Log2(x: int): int { - // log(10)/log(2) ≈ 3.32192809489 ≈ 108853 / 2^15 - ret (x * 108853) >> 15 + // log(10)/log(2) ≈ 3.32192809489 ≈ 108853 / 2^15 + ret (x * 108853) >> 15 } // Returns a floating-point vector (l, c, u)×2^e2 // where the mantissas are 55-bit (or 26-bit) integers, describing the interval // represented by the input f64 or f32. fn computeBounds(mant: u64, exp: int, - &flt: floatInfo): (lower: u64, central: u64, upper: u64, e2: int) { - if mant != 1< 5e8) || (clo == 5e8 && cup) - ryuDigits32(d, lhi, chi, uhi, c0, cup, 8) - d.dp += 9 - } else { - d.nd = 0 - // emit high part - mut n := uint(9) - mut v := chi - for v > 0 { - v1, v2 := v / 10, v % 10 - v = v1 - n-- - d.d[n] = byte(v2 + '0') - } - d.d = d.d[n:] - d.nd = int(9 - n) - // emit low part - ryuDigits32(d, llo, clo, ulo, c0, cup, d.nd + 8) - } - // trim trailing zeros - for d.nd > 0 && d.d[d.nd-1] == '0' { - d.nd-- - } - // trim initial zeros - for d.nd > 0 && d.d[0] == '0' { - d.nd-- - d.dp-- - d.d = d.d[1:] - } + mut lhi, llo := divmod1e9(lower) + chi, clo := divmod1e9(central) + uhi, ulo := divmod1e9(upper) + if uhi == 0 { + // only low digits (for denormals) + ryuDigits32(d, llo, clo, ulo, c0, cup, 8) + } else if lhi < uhi { + // truncate 9 digits at once. + if llo != 0 { + lhi++ + } + c0 = c0 && clo == 0 + cup = (clo > 5e8) || (clo == 5e8 && cup) + ryuDigits32(d, lhi, chi, uhi, c0, cup, 8) + d.dp += 9 + } else { + d.nd = 0 + // emit high part + mut n := uint(9) + mut v := chi + for v > 0 { + v1, v2 := v / 10, v % 10 + v = v1 + n-- + d.d[n] = byte(v2 + '0') + } + d.d = d.d[n:] + d.nd = int(9 - n) + // emit low part + ryuDigits32(d, llo, clo, ulo, c0, cup, d.nd + 8) + } + // trim trailing zeros + for d.nd > 0 && d.d[d.nd-1] == '0' { + d.nd-- + } + // trim initial zeros + for d.nd > 0 && d.d[0] == '0' { + d.nd-- + d.dp-- + d.d = d.d[1:] + } } // Emits decimal digits for a number less than 1e9. fn ryuDigits32(mut &d: decimalSlice, mut lower: u32, mut central: u32, - mut upper: u32, mut c0: bool, mut cup: bool, mut endindex: int) { - if upper == 0 { - d.dp = endindex + 1 - ret - } - mut trimmed := 0 - // Remember last trimmed digit to check for round-up. - // c0 will be used to remember zeroness of following digits. - mut cNextDigit := 0 - for upper > 0 { - // Repeatedly compute: - // l = ceil(lower / 10^k) - // c = round(central / 10^k) - // u = floor(upper / 10^k) - // and stop when c goes out of the (l, u) interval. - l := (lower + 9) / 10 - mut c, mut cdigit := central / 10, central % 10 - u := upper / 10 - if l > u { - // don't trim the last digit as it is forbidden to go below l - // other, trim and exit now. - break - } - // Check that we didn't cross the lower boundary. - // The case where l < u but c == l-1 is essentially impossible, - // but may happen if: - // lower = ..11 - // central = ..19 - // upper = ..31 - // and means that 'central' is very close but less than - // an integer ending with many zeros, and usually - // the "round-up" logic hides the problem. - if l == c+1 && c < u { - c++ - cdigit = 0 - cup = false - } - trimmed++ - // Remember trimmed digits of c - c0 = c0 && cNextDigit == 0 - cNextDigit = int(cdigit) - lower, central, upper = l, c, u - } - // should we round up? - if trimmed > 0 { - cup = (cNextDigit > 5 || - (cNextDigit == 5 && !c0) || - (cNextDigit == 5 && c0 && central&1 == 1)) - } - if central < upper && cup { - central++ - } - // We know where the number ends, fill directly - endindex -= trimmed - mut v := central - mut n := endindex - for n > d.nd { - v1, v2 := v / 100, v % 100 - d.d[n] = smallsStr[2*v2+1] - d.d[n-1] = smallsStr[2*v2+0] - n -= 2 - v = v1 - } - if n == d.nd { - d.d[n] = byte(v + '0') - } - d.nd = endindex + 1 - d.dp = d.nd + trimmed + mut upper: u32, mut c0: bool, mut cup: bool, mut endindex: int) { + if upper == 0 { + d.dp = endindex + 1 + ret + } + mut trimmed := 0 + // Remember last trimmed digit to check for round-up. + // c0 will be used to remember zeroness of following digits. + mut cNextDigit := 0 + for upper > 0 { + // Repeatedly compute: + // l = ceil(lower / 10^k) + // c = round(central / 10^k) + // u = floor(upper / 10^k) + // and stop when c goes out of the (l, u) interval. + l := (lower + 9) / 10 + mut c, mut cdigit := central / 10, central % 10 + u := upper / 10 + if l > u { + // don't trim the last digit as it is forbidden to go below l + // other, trim and exit now. + break + } + // Check that we didn't cross the lower boundary. + // The case where l < u but c == l-1 is essentially impossible, + // but may happen if: + // lower = ..11 + // central = ..19 + // upper = ..31 + // and means that 'central' is very close but less than + // an integer ending with many zeros, and usually + // the "round-up" logic hides the problem. + if l == c+1 && c < u { + c++ + cdigit = 0 + cup = false + } + trimmed++ + // Remember trimmed digits of c + c0 = c0 && cNextDigit == 0 + cNextDigit = int(cdigit) + lower, central, upper = l, c, u + } + // should we round up? + if trimmed > 0 { + cup = (cNextDigit > 5 || + (cNextDigit == 5 && !c0) || + (cNextDigit == 5 && c0 && central&1 == 1)) + } + if central < upper && cup { + central++ + } + // We know where the number ends, fill directly + endindex -= trimmed + mut v := central + mut n := endindex + for n > d.nd { + v1, v2 := v / 100, v % 100 + d.d[n] = smallsStr[2*v2+1] + d.d[n-1] = smallsStr[2*v2+0] + n -= 2 + v = v1 + } + if n == d.nd { + d.d[n] = byte(v + '0') + } + d.nd = endindex + 1 + d.dp = d.nd + trimmed } // Takes a floating-point input with a 25-bit @@ -532,22 +532,22 @@ fn ryuDigits32(mut &d: decimalSlice, mut lower: u32, mut central: u32, // m*2^e2 * round(10^q) = resM * 2^resE + ε // exact = ε == 0 fn mult64bitPow10(m: u32, mut e2: int, q: int): (resM: u32, resE: int, exact: bool) { - if q == 0 { - // P == 1<<63 - ret m << 6, e2 - 6, true - } - if q < detailedPowsOfTenMinExp10 || detailedPowsOfTenMaxExp10 < q { - // This never happens due to the range of f32/f64 exponent - panic("mult64bitPow10: power of 10 is out of range") - } - mut pow := detailedPowsOfTen[q-detailedPowsOfTenMinExp10][1] - if q < 0 { - // Inverse powers of ten must be rounded up. - pow += 1 - } - hi, lo := bits::Mul64(u64(m), pow) - e2 += mulByLog10Log2(q) - 63 + 57 - ret u32(hi << 7 | lo >> 57), e2, lo<<7 == 0 + if q == 0 { + // P == 1<<63 + ret m << 6, e2 - 6, true + } + if q < detailedPowsOfTenMinExp10 || detailedPowsOfTenMaxExp10 < q { + // This never happens due to the range of f32/f64 exponent + panic("mult64bitPow10: power of 10 is out of range") + } + mut pow := detailedPowsOfTen[q-detailedPowsOfTenMinExp10][1] + if q < 0 { + // Inverse powers of ten must be rounded up. + pow += 1 + } + hi, lo := bits::Mul64(u64(m), pow) + e2 += mulByLog10Log2(q) - 63 + 57 + ret u32(hi << 7 | lo >> 57), e2, lo<<7 == 0 } // Takes a floating-point input with a 55-bit @@ -560,51 +560,51 @@ fn mult64bitPow10(m: u32, mut e2: int, q: int): (resM: u32, resE: int, exact: bo // m*2^e2 * round(10^q) = resM * 2^resE + ε // exact = ε == 0 fn mult128bitPow10(m: u64, mut e2: int, q: int): (resM: u64, resE: int, exact: bool) { - if q == 0 { - // P == 1<<127 - ret m << 8, e2 - 8, true - } - if q < detailedPowsOfTenMinExp10 || detailedPowsOfTenMaxExp10 < q { - // This never happens due to the range of f32/f64 exponent - panic("mult128bitPow10: power of 10 is out of range") - } - mut pow := detailedPowsOfTen[q-detailedPowsOfTenMinExp10] - if q < 0 { - // Inverse powers of ten must be rounded up. - pow[0] += 1 - } - e2 += mulByLog10Log2(q) - 127 + 119 + if q == 0 { + // P == 1<<127 + ret m << 8, e2 - 8, true + } + if q < detailedPowsOfTenMinExp10 || detailedPowsOfTenMaxExp10 < q { + // This never happens due to the range of f32/f64 exponent + panic("mult128bitPow10: power of 10 is out of range") + } + mut pow := detailedPowsOfTen[q-detailedPowsOfTenMinExp10] + if q < 0 { + // Inverse powers of ten must be rounded up. + pow[0] += 1 + } + e2 += mulByLog10Log2(q) - 127 + 119 - // long multiplication - l1, l0 := bits::Mul64(m, pow[0]) - mut h1, h0 := bits::Mul64(m, pow[1]) - mid, carry := bits::Add64(l1, h0, 0) - h1 += carry - ret h1 << 9 | mid >> 55, e2, mid<<9 == 0 && l0 == 0 + // long multiplication + l1, l0 := bits::Mul64(m, pow[0]) + mut h1, h0 := bits::Mul64(m, pow[1]) + mid, carry := bits::Add64(l1, h0, 0) + h1 += carry + ret h1 << 9 | mid >> 55, e2, mid<<9 == 0 && l0 == 0 } fn divisibleByPow5(mut m: u64, k: int): bool { - if m == 0 { - ret true - } - mut i := 0 - for i < k; i++ { - if m%5 != 0 { - ret false - } - m /= 5 - } - ret true + if m == 0 { + ret true + } + mut i := 0 + for i < k; i++ { + if m%5 != 0 { + ret false + } + m /= 5 + } + ret true } // Computes quotient and remainder of division by 1e9, // avoiding runtime u64 division on 32-bit platforms. fn divmod1e9(x: u64): (u32, u32) { - if !host32bit { - ret u32(x / 1e9), u32(x % 1e9) - } - // Use the same sequence of operations as the amd64 compiler. - hi, _ := bits::Mul64(x >> 1, 0x89705f4136b4a598) // binary digits of 1e-9 - q := hi >> 28 - ret u32(q), u32(x - q * 1e9) + if !host32bit { + ret u32(x / 1e9), u32(x % 1e9) + } + // Use the same sequence of operations as the amd64 compiler. + hi, _ := bits::Mul64(x >> 1, 0x89705f4136b4a598) // binary digits of 1e-9 + q := hi >> 28 + ret u32(q), u32(x - q * 1e9) } \ No newline at end of file diff --git a/std/conv/itoa.jule b/std/conv/itoa.jule index c416c8879..64a080637 100644 --- a/std/conv/itoa.jule +++ b/std/conv/itoa.jule @@ -45,56 +45,56 @@ const digits = "0123456789abcdefghijklmnopqrstuvwxyz" const host32bit = ^uint(0)>>32 == 0 const smallsStr = "00010203040506070809" + - "10111213141516171819" + - "20212223242526272829" + - "30313233343536373839" + - "40414243444546474849" + - "50515253545556575859" + - "60616263646566676869" + - "70717273747576777879" + - "80818283848586878889" + - "90919293949596979899" + "10111213141516171819" + + "20212223242526272829" + + "30313233343536373839" + + "40414243444546474849" + + "50515253545556575859" + + "60616263646566676869" + + "70717273747576777879" + + "80818283848586878889" + + "90919293949596979899" // Returns the string representation of i in the given base, // for 2 <= base <= 36. The result uses the lower-case letters 'a' to 'z' // for digit values >= 10. fn FmtUint(i: u64, base: int): str { - if fastSmalls && i < nSmalls && base == 10 { - ret small(int(i)) - } - _, s := fmtBits(nil, i, base, false, false) - ret s + if fastSmalls && i < nSmalls && base == 10 { + ret small(int(i)) + } + _, s := fmtBits(nil, i, base, false, false) + ret s } // Returns the string representation of i in the given base, // for 2 <= base <= 36. The result uses the lower-case letters 'a' to 'z' // for digit values >= 10. fn FmtInt(i: i64, base: int): str { - if fastSmalls && 0 <= i && i < nSmalls && base == 10 { - ret small(int(i)) - } - _, s := fmtBits(nil, u64(i), base, i < 0, false) - ret s + if fastSmalls && 0 <= i && i < nSmalls && base == 10 { + ret small(int(i)) + } + _, s := fmtBits(nil, u64(i), base, i < 0, false) + ret s } // Is equivalent to FmtInt(i64(i), 10). fn Itoa(i: int): str { - ret FmtInt(i64(i), 10) + ret FmtInt(i64(i), 10) } // Returns the string for an i with 0 <= i < nSmalls. fn small(i: int): str { - if i < 10 { - ret str(byte('0' + i)) - } - mut buf := make([]byte, 3) - buf[0] = smallsStr[i<<1] - buf[1] = smallsStr[i<<1+1] - ret unsafe::StrFromBytes(buf[:2]) + if i < 10 { + ret str(byte('0' + i)) + } + mut buf := make([]byte, 3) + buf[0] = smallsStr[i<<1] + buf[1] = smallsStr[i<<1+1] + ret unsafe::StrFromBytes(buf[:2]) } fn isPowerOfTwo(x: int): bool { - ret x&(x - 1) == 0 + ret x&(x - 1) == 0 } // Computes the string representation of u in the given base. @@ -103,118 +103,118 @@ fn isPowerOfTwo(x: int): bool { // returned as the first result value; otherwise the string is returned // as the second result value. fn fmtBits(mut dst: []byte, mut u: u64, base: int, neg: bool, append_: bool): (d: []byte, s: str) { - if base < 2 || base > len(digits) { - panic("std::conv: illegal base") - } - // 2 <= base && base <= len(digits) - - mut a := make([]byte, 64 + 1) // +1 for sign of 64bit value in base 2 - mut i := len(a) - - if neg { - u = -u - } - - // convert bits - // We use uint values where we can because those will - // fit into a single register even on a 32bit machine. - match { - | base == 10: - // common case: use constants for / because - // the compiler can optimize it into a multiply+shift - - if host32bit { - // convert the lower digits using 32bit operations - for u >= 1e9 { - // Avoid using r = a%b in addition to q = a/b - // since 64bit division and modulo operations - // are calculated by runtime functions on 32bit machines. - q := u / 1e9 - mut us := uint(u - q * 1e9) // u % 1e9 fits into a uint - mut j := 4 - for j > 0; j-- { - is := us % 100 * 2 - us /= 100 - i -= 2 - a[i+1] = smallsStr[is+1] - a[i+0] = smallsStr[is+0] - } - - // us < 10, since it contains the last digit - // from the initial 9-digit us. - i-- - a[i] = smallsStr[us*2+1] - - u = q - } - // u < 1e9 - } - - // u guaranteed to fit into a uint - mut us := uint(u) - for us >= 100 { - is := us % 100 * 2 - us /= 100 - i -= 2 - a[i+1] = smallsStr[is+1] - a[i+0] = smallsStr[is+0] - } - - // us < 100 - is := us * 2 - i-- - a[i] = smallsStr[is+1] - if us >= 10 { - i-- - a[i] = smallsStr[is] - } - | isPowerOfTwo(base): - // Use shifts and masks instead of / and %. - // Base is a power of 2 and 2 <= base <= len(digits) where len(digits) is 36. - // The largest power of 2 below or equal to 36 is 32, which is 1 << 5; - // i.e., the largest possible shift count is 5. By &-ind that value with - // the constant 7 we tell the compiler that the shift count is always - // less than 8 which is smaller than any register width. This allows - // the compiler to generate better code for the shift operation. - shift := uint(bits::TrailingZeros(uint(base))) & 0b111 - b := u64(base) - m := uint(base) - 1 // == 1<= b { - i-- - a[i] = digits[uint(u)&m] - u >>= shift - } - // u < base - i-- - a[i] = digits[uint(u)] - |: - // general case - b := u64(base) - for u >= b { - i-- - // Avoid using r = a%b in addition to q = a/b - // since 64bit division and modulo operations - // are calculated by runtime functions on 32bit machines. - q := u / b - a[i] = digits[uint(u-q*b)] - u = q - } - // u < base - i-- - a[i] = digits[uint(u)] - } - - // add sign, if any - if neg { - i-- - a[i] = '-' - } - - if append_ { - d = append(dst, a[i:]...) - ret - } - n := copy(a, a[i:]) - s = unsafe::StrFromBytes(a[:n]) - ret + if base < 2 || base > len(digits) { + panic("std::conv: illegal base") + } + // 2 <= base && base <= len(digits) + + mut a := make([]byte, 64 + 1) // +1 for sign of 64bit value in base 2 + mut i := len(a) + + if neg { + u = -u + } + + // convert bits + // We use uint values where we can because those will + // fit into a single register even on a 32bit machine. + match { + | base == 10: + // common case: use constants for / because + // the compiler can optimize it into a multiply+shift + + if host32bit { + // convert the lower digits using 32bit operations + for u >= 1e9 { + // Avoid using r = a%b in addition to q = a/b + // since 64bit division and modulo operations + // are calculated by runtime functions on 32bit machines. + q := u / 1e9 + mut us := uint(u - q * 1e9) // u % 1e9 fits into a uint + mut j := 4 + for j > 0; j-- { + is := us % 100 * 2 + us /= 100 + i -= 2 + a[i+1] = smallsStr[is+1] + a[i+0] = smallsStr[is+0] + } + + // us < 10, since it contains the last digit + // from the initial 9-digit us. + i-- + a[i] = smallsStr[us*2+1] + + u = q + } + // u < 1e9 + } + + // u guaranteed to fit into a uint + mut us := uint(u) + for us >= 100 { + is := us % 100 * 2 + us /= 100 + i -= 2 + a[i+1] = smallsStr[is+1] + a[i+0] = smallsStr[is+0] + } + + // us < 100 + is := us * 2 + i-- + a[i] = smallsStr[is+1] + if us >= 10 { + i-- + a[i] = smallsStr[is] + } + | isPowerOfTwo(base): + // Use shifts and masks instead of / and %. + // Base is a power of 2 and 2 <= base <= len(digits) where len(digits) is 36. + // The largest power of 2 below or equal to 36 is 32, which is 1 << 5; + // i.e., the largest possible shift count is 5. By &-ind that value with + // the constant 7 we tell the compiler that the shift count is always + // less than 8 which is smaller than any register width. This allows + // the compiler to generate better code for the shift operation. + shift := uint(bits::TrailingZeros(uint(base))) & 0b111 + b := u64(base) + m := uint(base) - 1 // == 1<= b { + i-- + a[i] = digits[uint(u)&m] + u >>= shift + } + // u < base + i-- + a[i] = digits[uint(u)] + |: + // general case + b := u64(base) + for u >= b { + i-- + // Avoid using r = a%b in addition to q = a/b + // since 64bit division and modulo operations + // are calculated by runtime functions on 32bit machines. + q := u / b + a[i] = digits[uint(u-q*b)] + u = q + } + // u < base + i-- + a[i] = digits[uint(u)] + } + + // add sign, if any + if neg { + i-- + a[i] = '-' + } + + if append_ { + d = append(dst, a[i:]...) + ret + } + n := copy(a, a[i:]) + s = unsafe::StrFromBytes(a[:n]) + ret } \ No newline at end of file diff --git a/std/encoding/ascii85/ascii85.jule b/std/encoding/ascii85/ascii85.jule index 7776f407e..bd27d3b6b 100644 --- a/std/encoding/ascii85/ascii85.jule +++ b/std/encoding/ascii85/ascii85.jule @@ -39,19 +39,19 @@ use io for std::io // Returns the maximum length of an encoding of n source bytes. fn MaxEncodeLen(n: int): int { - ret (n + 3) / 4 * 5 + ret (n + 3) / 4 * 5 } // Returns new Ascii85 encoder for stream. // Encoder forwards any exception. fn NewEncoder(mut w: io::Writer): io::WriterCloser { - ret encoder.new(w) + ret encoder.new(w) } // Returns new Ascii85 decoder for stream. // Decoder forwards any exception. fn NewDecoder(mut r: io::Reader): io::Reader { - ret decoder.new(r) + ret decoder.new(r) } // Encodes src into at most MaxEncodeLen(len(src)) @@ -64,64 +64,64 @@ fn NewDecoder(mut r: io::Reader): io::Reader { // Often, ascii85-encoded data is wrapped in <~ and ~> symbols. // The encode does not add these. fn Encode(mut dest: []byte, src: []byte): int { - if len(src) == 0 { - ret 0 - } + if len(src) == 0 { + ret 0 + } - mut n := 0 - for len(src) > 0 { - dest[0] = 0 - dest[1] = 0 - dest[2] = 0 - dest[3] = 0 - dest[4] = 0 + mut n := 0 + for len(src) > 0 { + dest[0] = 0 + dest[1] = 0 + dest[2] = 0 + dest[3] = 0 + dest[4] = 0 - // Unpack 4 bytes into u32 to repack into base 85 5-byte. - mut v := u32(0) - match len(src) { - | 3: - v |= u32(src[2]) << 8 - fall - | 2: - v |= u32(src[1]) << 16 - fall - | 1: - v |= u32(src[0]) << 24 - |: - v |= u32(src[3]) - v |= u32(src[2]) << 8 - v |= u32(src[1]) << 16 - v |= u32(src[0]) << 24 - } + // Unpack 4 bytes into u32 to repack into base 85 5-byte. + mut v := u32(0) + match len(src) { + | 3: + v |= u32(src[2]) << 8 + fall + | 2: + v |= u32(src[1]) << 16 + fall + | 1: + v |= u32(src[0]) << 24 + |: + v |= u32(src[3]) + v |= u32(src[2]) << 8 + v |= u32(src[1]) << 16 + v |= u32(src[0]) << 24 + } - // Special case: zero (!!!!!) shortens to z. - if v == 0 && len(src) >= 4 { - dest[0] = 'z' - dest = dest[1:] - unsafe { *(&src) = (*(&src))[4:] } - n++ - continue - } + // Special case: zero (!!!!!) shortens to z. + if v == 0 && len(src) >= 4 { + dest[0] = 'z' + dest = dest[1:] + unsafe { *(&src) = (*(&src))[4:] } + n++ + continue + } - // Otherwise, 5 base 85 digits starting at !. - mut i := 4 - for i >= 0; i-- { - dest[i] = '!' + byte(v % 85) - v /= 85 - } + // Otherwise, 5 base 85 digits starting at !. + mut i := 4 + for i >= 0; i-- { + dest[i] = '!' + byte(v % 85) + v /= 85 + } - // If src was short, discard the low destination bytes. - mut m := 5 - if len(src) < 4 { - m -= 4 - len(src) - unsafe { *(&src) = nil } - } else { - unsafe { *(&src) = (*(&src))[4:] } - } - dest = dest[m:] - n += m - } - ret n + // If src was short, discard the low destination bytes. + mut m := 5 + if len(src) < 4 { + m -= 4 - len(src) + unsafe { *(&src) = nil } + } else { + unsafe { *(&src) = (*(&src))[4:] } + } + dest = dest[m:] + n += m + } + ret n } // Decodes src into dest, returning both the number @@ -137,191 +137,191 @@ fn Encode(mut dest: []byte, src: []byte): int { // // NewDecoder wraps an std::io::Reader trait around decode. fn Decode(mut dest: []byte, src: []byte, flush: bool)!: (ndst: int, nsrc: int) { - mut v := u32(0) - mut nb := 0 - for i, b in src { - if len(dest)-ndst < 4 { - ret - } - match { - | b <= ' ': - continue - | b == 'z' && nb == 0: - nb = 5 - v = 0 - | '!' <= b && b <= 'u': - v = v * 85 + u32(b - '!') - nb++ - |: - error(DecodeError.Format) - } - if nb == 5 { - nsrc = i + 1 - dest[ndst] = byte(v >> 24) - dest[ndst+1] = byte(v >> 16) - dest[ndst+2] = byte(v >> 8) - dest[ndst+3] = byte(v) - ndst += 4 - nb = 0 - v = 0 - } - } - if flush { - nsrc = len(src) - if nb > 0 { - // The number of output bytes in the last fragment - // is the number of leftover input bytes - 1: - // the extra byte provides enough bits to cover - // the inefficiency of the encoding for the block. - if nb == 1 { - error(DecodeError.Format) - } - mut j := nb - for j < 5; j++ { - // The short encoding truncated the output value. - // We have to assume the worst case values (digit 84) - // in order to ensure that the top bits are correct. - v = v * 85 + 84 - } - j = 0 - for j < nb-1; j++ { - dest[ndst] = byte(v >> 24) - v <<= 8 - ndst++ - } - } - } - ret + mut v := u32(0) + mut nb := 0 + for i, b in src { + if len(dest)-ndst < 4 { + ret + } + match { + | b <= ' ': + continue + | b == 'z' && nb == 0: + nb = 5 + v = 0 + | '!' <= b && b <= 'u': + v = v * 85 + u32(b - '!') + nb++ + |: + error(DecodeError.Format) + } + if nb == 5 { + nsrc = i + 1 + dest[ndst] = byte(v >> 24) + dest[ndst+1] = byte(v >> 16) + dest[ndst+2] = byte(v >> 8) + dest[ndst+3] = byte(v) + ndst += 4 + nb = 0 + v = 0 + } + } + if flush { + nsrc = len(src) + if nb > 0 { + // The number of output bytes in the last fragment + // is the number of leftover input bytes - 1: + // the extra byte provides enough bits to cover + // the inefficiency of the encoding for the block. + if nb == 1 { + error(DecodeError.Format) + } + mut j := nb + for j < 5; j++ { + // The short encoding truncated the output value. + // We have to assume the worst case values (digit 84) + // in order to ensure that the top bits are correct. + v = v * 85 + 84 + } + j = 0 + for j < nb-1; j++ { + dest[ndst] = byte(v >> 24) + v <<= 8 + ndst++ + } + } + } + ret } struct encoder { - w: io::Writer - buf: []byte // buffered data waiting to be encoded - nbuf: int // number of bytes in buf - out: []byte // output buffer + w: io::Writer + buf: []byte // buffered data waiting to be encoded + nbuf: int // number of bytes in buf + out: []byte // output buffer } impl io::WriterCloser for encoder { - fn Write(mut self, dest: []byte)!: (n: int) { - // Leading fringe. - if self.nbuf > 0 { - mut i := 0 - for i < len(dest) && self.nbuf < 4; i++ { - self.buf[self.nbuf] = dest[i] - self.nbuf++ - } - n += i - unsafe { *(&dest) = (*(&dest))[i:] } - if self.nbuf < 4 { - ret - } - nout := Encode(self.out, self.buf) - self.w.Write(self.out[:nout]) else { error(error) } - self.nbuf = 0 - } + fn Write(mut self, dest: []byte)!: (n: int) { + // Leading fringe. + if self.nbuf > 0 { + mut i := 0 + for i < len(dest) && self.nbuf < 4; i++ { + self.buf[self.nbuf] = dest[i] + self.nbuf++ + } + n += i + unsafe { *(&dest) = (*(&dest))[i:] } + if self.nbuf < 4 { + ret + } + nout := Encode(self.out, self.buf) + self.w.Write(self.out[:nout]) else { error(error) } + self.nbuf = 0 + } - // Large interior chunks. - for len(dest) >= 4 { - mut nn := (len(self.out) / 5) << 2 - if nn > len(dest) { - nn = len(dest) - } - nn -= nn % 4 - if nn > 0 { - nout := Encode(self.out, dest[:nn]) - self.w.Write(self.out[:nout]) else { error(error) } - } - n += nn - unsafe { *(&dest) = (*(&dest))[nn:] } - } + // Large interior chunks. + for len(dest) >= 4 { + mut nn := (len(self.out) / 5) << 2 + if nn > len(dest) { + nn = len(dest) + } + nn -= nn % 4 + if nn > 0 { + nout := Encode(self.out, dest[:nn]) + self.w.Write(self.out[:nout]) else { error(error) } + } + n += nn + unsafe { *(&dest) = (*(&dest))[nn:] } + } - // Trailing fringe. - _ = copy(self.buf, dest) - self.nbuf = len(dest) - n += len(dest) - ret - } + // Trailing fringe. + _ = copy(self.buf, dest) + self.nbuf = len(dest) + n += len(dest) + ret + } - // Close flushes any pending output from the encoder. - // It is an error to call write after calling close. - fn Close(mut self)! { - // If there's anything left in the buffer, flush it out. - if self.nbuf > 0 { - nout := Encode(self.out, self.buf[:self.nbuf]) - self.nbuf = 0 - self.w.Write(self.out[:nout]) else { error(error) } - } - } + // Close flushes any pending output from the encoder. + // It is an error to call write after calling close. + fn Close(mut self)! { + // If there's anything left in the buffer, flush it out. + if self.nbuf > 0 { + nout := Encode(self.out, self.buf[:self.nbuf]) + self.nbuf = 0 + self.w.Write(self.out[:nout]) else { error(error) } + } + } } impl encoder { - static fn new(mut w: io::Writer): &encoder { - ret &encoder{ - w: w, - buf: make([]byte, 4), - out: make([]byte, 1 << 10), - } - } + static fn new(mut w: io::Writer): &encoder { + ret &encoder{ + w: w, + buf: make([]byte, 4), + out: make([]byte, 1 << 10), + } + } } struct decoder { - r: io::Reader - buf: []byte // leftover input - nbuf: int - out: []byte // leftover decoded output - outbuf: []byte + r: io::Reader + buf: []byte // leftover input + nbuf: int + out: []byte // leftover decoded output + outbuf: []byte } impl io::Reader for decoder { - fn Read(mut self, mut p: []byte)!: (n: int) { - if len(p) == 0 { - ret 0 - } - for { - // Copy leftover output from last decode. - if len(self.out) > 0 { - n = copy(p, self.out) - self.out = self.out[n:] - ret - } + fn Read(mut self, mut p: []byte)!: (n: int) { + if len(p) == 0 { + ret 0 + } + for { + // Copy leftover output from last decode. + if len(self.out) > 0 { + n = copy(p, self.out) + self.out = self.out[n:] + ret + } - // Decode leftover input from last read. - mut nn, mut nsrc, mut ndst := 0, 0, 0 - if self.nbuf > 0 { - ndst, nsrc = Decode(self.outbuf, self.buf[:self.nbuf], true) else { error(error) } - if ndst > 0 { - self.out = self.outbuf[:ndst] - self.nbuf = copy(self.buf, self.buf[nsrc:self.nbuf]) - continue // copy out and return - } - if ndst == 0 { - // Special case: input buffer is mostly filled with non-data bytes. - // Filter out such bytes to make room for more input. - mut off := 0 - mut i := 0 - for i < self.nbuf; i++ { - if self.buf[i] > ' ' { - self.buf[off] = self.buf[i] - off++ - } - } - self.nbuf = off - } - } + // Decode leftover input from last read. + mut nn, mut nsrc, mut ndst := 0, 0, 0 + if self.nbuf > 0 { + ndst, nsrc = Decode(self.outbuf, self.buf[:self.nbuf], true) else { error(error) } + if ndst > 0 { + self.out = self.outbuf[:ndst] + self.nbuf = copy(self.buf, self.buf[nsrc:self.nbuf]) + continue // copy out and return + } + if ndst == 0 { + // Special case: input buffer is mostly filled with non-data bytes. + // Filter out such bytes to make room for more input. + mut off := 0 + mut i := 0 + for i < self.nbuf; i++ { + if self.buf[i] > ' ' { + self.buf[off] = self.buf[i] + off++ + } + } + self.nbuf = off + } + } - // Read more data. - nn = self.r.Read(self.buf[self.nbuf:]) else { error(error) } - self.nbuf += nn - } - } + // Read more data. + nn = self.r.Read(self.buf[self.nbuf:]) else { error(error) } + self.nbuf += nn + } + } } impl decoder { - static fn new(mut r: io::Reader): &decoder { - ret &decoder{ - r: r, - buf: make([]byte, 1 << 10), - outbuf: make([]byte, 1 << 10), - } - } + static fn new(mut r: io::Reader): &decoder { + ret &decoder{ + r: r, + buf: make([]byte, 1 << 10), + outbuf: make([]byte, 1 << 10), + } + } } \ No newline at end of file diff --git a/std/encoding/ascii85/ascii85_test.jule b/std/encoding/ascii85/ascii85_test.jule index dbbcb4ae6..a5547ce39 100644 --- a/std/encoding/ascii85/ascii85_test.jule +++ b/std/encoding/ascii85/ascii85_test.jule @@ -7,51 +7,51 @@ use std::testing::{T} static encodeDecodeMap = [ - [[]byte("BOu!rDdP(J/RN^?Ebo7"), []byte("hello_---_world")], - [[]byte("@:E_WAS,RgC27X/@q'=mE,W\\\"Fa8(LGB!"), []byte("abcdefghjklvcbnmpoıuytrwq")], - [[]byte("E,8HbE,TJF3*13:1GC[HFYcil8j-K93&re5Z\"nA9FD>`2Df>"), []byte("plSfpoj08Wtj3059u3PRJ=^2893ıkr3tjomop")], - [[]byte("/lQIPCK\"q:90H?*<-;8<:ae1t8QSl(5>#!UCb00N@kL5bB2qE8934SZ?TgnN85rD]8ln_9"), []byte(".SiDkSiFK=W)TuWOP(5PIWTg?JWSl,f.c.FigUFiKWFP_=GIHTPOJWM)")], + [[]byte("BOu!rDdP(J/RN^?Ebo7"), []byte("hello_---_world")], + [[]byte("@:E_WAS,RgC27X/@q'=mE,W\\\"Fa8(LGB!"), []byte("abcdefghjklvcbnmpoıuytrwq")], + [[]byte("E,8HbE,TJF3*13:1GC[HFYcil8j-K93&re5Z\"nA9FD>`2Df>"), []byte("plSfpoj08Wtj3059u3PRJ=^2893ıkr3tjomop")], + [[]byte("/lQIPCK\"q:90H?*<-;8<:ae1t8QSl(5>#!UCb00N@kL5bB2qE8934SZ?TgnN85rD]8ln_9"), []byte(".SiDkSiFK=W)TuWOP(5PIWTg?JWSl,f.c.FigUFiKWFP_=GIHTPOJWM)")], ] #test fn testEncode(t: &T) { - mut r := make([]byte, 1 << 8) - for _, case in encodeDecodeMap { - n := Encode(r, case[1]) - p := r[:n] - d := case[0] - if len(p) != len(d) { - t.Fail() - continue - } - for i in p { - if p[i] != d[i] { - t.Fail() - break - } - } - } + mut r := make([]byte, 1 << 8) + for _, case in encodeDecodeMap { + n := Encode(r, case[1]) + p := r[:n] + d := case[0] + if len(p) != len(d) { + t.Fail() + continue + } + for i in p { + if p[i] != d[i] { + t.Fail() + break + } + } + } } #test fn testDecode(t: &T) { - mut r := make([]byte, 1 << 8) - for _, case in encodeDecodeMap { - n, _ := Decode(r, case[0], true) else { - t.Fail() - continue - } - p := r[:n] - d := case[1] - if len(p) != len(d) { - t.Fail() - continue - } - for i in p { - if p[i] != d[i] { - t.Fail() - break - } - } - } + mut r := make([]byte, 1 << 8) + for _, case in encodeDecodeMap { + n, _ := Decode(r, case[0], true) else { + t.Fail() + continue + } + p := r[:n] + d := case[1] + if len(p) != len(d) { + t.Fail() + continue + } + for i in p { + if p[i] != d[i] { + t.Fail() + break + } + } + } } \ No newline at end of file diff --git a/std/encoding/ascii85/error.jule b/std/encoding/ascii85/error.jule index a909bc5aa..1184a4342 100644 --- a/std/encoding/ascii85/error.jule +++ b/std/encoding/ascii85/error.jule @@ -4,5 +4,5 @@ // Error codes of decode operations. enum DecodeError { - Format, + Format, } \ No newline at end of file diff --git a/std/encoding/base32/base32.jule b/std/encoding/base32/base32.jule index 58c70e29c..2643d926b 100644 --- a/std/encoding/base32/base32.jule +++ b/std/encoding/base32/base32.jule @@ -13,30 +13,30 @@ static t32 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567" const paddingByte = '=' fn lenNoPad(b: []byte): int { - mut i := len(b) - 1 - for i >= 0 && b[i] == paddingByte; i-- {} - ret i + 1 + mut i := len(b) - 1 + for i >= 0 && b[i] == paddingByte; i-- {} + ret i + 1 } fn encodeLen(n: int, pad: bool): int { - if pad { - ret (n + 4) / 5 << 3 - } - ret n / 5 << 3 + (n % 5 << 3 + 4) / 5 + if pad { + ret (n + 4) / 5 << 3 + } + ret n / 5 << 3 + (n % 5 << 3 + 4) / 5 } // Returns length of encoded bytes of b. fn EncodeLen(b: []byte, pad: bool): int { - ret encodeLen(len(b), pad) + ret encodeLen(len(b), pad) } // Returns length of decoded bytes of b. fn DecodeLen(b: []byte): int { - if len(b) == 0 { - ret 0 - } - n := lenNoPad(b) - ret n >> 3 * 5 + n % 8 * 5 >> 3 + if len(b) == 0 { + ret 0 + } + n := lenNoPad(b) + ret n >> 3 * 5 + n % 8 * 5 >> 3 } // Encodes source bytes into dest with standard base32 table. @@ -44,77 +44,77 @@ fn DecodeLen(b: []byte): int { // Adds padding if pad is true. // Algorithm will call the append function to append dest. fn Encode(src: []byte, pad: bool): []byte { - n := encodeLen(len(src), pad) - if n == 0 { - ret nil - } - t := &t32[0] - mut bits := u64(0) - mut buffer := u32(0) - mut dest := make([]byte, n) - mut p := &dest[0] - for _, b in src { - buffer <<= 8 - buffer += u32(b) - bits += 8 - for bits >= 5; p++ { - unsafe { *p = t[(buffer>>(bits-5))&0x3F] } - buffer &= ^(0x1F << (bits - 5)) - bits -= 5 - } - } + n := encodeLen(len(src), pad) + if n == 0 { + ret nil + } + t := &t32[0] + mut bits := u64(0) + mut buffer := u32(0) + mut dest := make([]byte, n) + mut p := &dest[0] + for _, b in src { + buffer <<= 8 + buffer += u32(b) + bits += 8 + for bits >= 5; p++ { + unsafe { *p = t[(buffer>>(bits-5))&0x3F] } + buffer &= ^(0x1F << (bits - 5)) + bits -= 5 + } + } - match len(src) % 5 { - | 1: - buffer <<= 2 - unsafe { *p = t[buffer&0x1F] } - if pad { - p++ - unsafe { *p = paddingByte } - p++ - unsafe { *p = paddingByte } - p++ - unsafe { *p = paddingByte } - p++ - unsafe { *p = paddingByte } - p++ - unsafe { *p = paddingByte } - p++ - unsafe { *p = paddingByte } - } - | 2: - buffer <<= 4 - unsafe { *p = t[buffer&0x1F] } - if pad { - p++ - unsafe { *p = paddingByte } - p++ - unsafe { *p = paddingByte } - p++ - unsafe { *p = paddingByte } - p++ - unsafe { *p = paddingByte } - } - | 3: - buffer <<= 1 - unsafe { *p = t[buffer&0x1F] } - if pad { - p++ - unsafe { *p = paddingByte } - p++ - unsafe { *p = paddingByte } - p++ - unsafe { *p = paddingByte } - } - | 4: - buffer <<= 3 - unsafe { *p = t[buffer&0x1F] } - if pad { - p++ - unsafe { *p = paddingByte } - } - } - ret dest + match len(src) % 5 { + | 1: + buffer <<= 2 + unsafe { *p = t[buffer&0x1F] } + if pad { + p++ + unsafe { *p = paddingByte } + p++ + unsafe { *p = paddingByte } + p++ + unsafe { *p = paddingByte } + p++ + unsafe { *p = paddingByte } + p++ + unsafe { *p = paddingByte } + p++ + unsafe { *p = paddingByte } + } + | 2: + buffer <<= 4 + unsafe { *p = t[buffer&0x1F] } + if pad { + p++ + unsafe { *p = paddingByte } + p++ + unsafe { *p = paddingByte } + p++ + unsafe { *p = paddingByte } + p++ + unsafe { *p = paddingByte } + } + | 3: + buffer <<= 1 + unsafe { *p = t[buffer&0x1F] } + if pad { + p++ + unsafe { *p = paddingByte } + p++ + unsafe { *p = paddingByte } + p++ + unsafe { *p = paddingByte } + } + | 4: + buffer <<= 3 + unsafe { *p = t[buffer&0x1F] } + if pad { + p++ + unsafe { *p = paddingByte } + } + } + ret dest } // Decodes source bytes into dest with standard base32 table. @@ -122,29 +122,29 @@ fn Encode(src: []byte, pad: bool): []byte { // Detects padding by default, no required padding specification. // Algorithm will call the append function to append dest. fn Decode(src: []byte): []byte { - n := DecodeLen(src) - if n == 0 { - ret nil - } - mut buffer := u32(0) - mut bits := u64(0) - mut dest := make([]byte, n) - mut p := &dest[0] - for _, b in src { - i := fastbytes::FindByteStr(t32, b) - buffer <<= 5 - bits += 5 - if i != -1 { - buffer += u32(31 - (31 - i)) - } - if bits >= 8 { - if b != paddingByte { - unsafe { *p = byte(buffer >> (bits - 8)) } - p++ - } - buffer &= ^(0xFF << (bits - 8)) - bits -= 8 - } - } - ret dest + n := DecodeLen(src) + if n == 0 { + ret nil + } + mut buffer := u32(0) + mut bits := u64(0) + mut dest := make([]byte, n) + mut p := &dest[0] + for _, b in src { + i := fastbytes::FindByteStr(t32, b) + buffer <<= 5 + bits += 5 + if i != -1 { + buffer += u32(31 - (31 - i)) + } + if bits >= 8 { + if b != paddingByte { + unsafe { *p = byte(buffer >> (bits - 8)) } + p++ + } + buffer &= ^(0xFF << (bits - 8)) + bits -= 8 + } + } + ret dest } \ No newline at end of file diff --git a/std/encoding/base32/base32_test.jule b/std/encoding/base32/base32_test.jule index 815631ffd..eecf111fd 100644 --- a/std/encoding/base32/base32_test.jule +++ b/std/encoding/base32/base32_test.jule @@ -7,100 +7,100 @@ use std::testing::{T} static encodeDecodeMap = [ - // RFC 4648 examples. - [[]byte(""), []byte("")], - [[]byte("f"), []byte("MY======")], - [[]byte("fo"), []byte("MZXQ====")], - [[]byte("foo"), []byte("MZXW6===")], - [[]byte("foob"), []byte("MZXW6YQ=")], - [[]byte("fooba"), []byte("MZXW6YTB")], - [[]byte("foobar"), []byte("MZXW6YTBOI======")], + // RFC 4648 examples. + [[]byte(""), []byte("")], + [[]byte("f"), []byte("MY======")], + [[]byte("fo"), []byte("MZXQ====")], + [[]byte("foo"), []byte("MZXW6===")], + [[]byte("foob"), []byte("MZXW6YQ=")], + [[]byte("fooba"), []byte("MZXW6YTB")], + [[]byte("foobar"), []byte("MZXW6YTBOI======")], - // Wikipedia examples, converted to base32. - [[]byte("sure."), []byte("ON2XEZJO")], - [[]byte("sure"), []byte("ON2XEZI=")], - [[]byte("sur"), []byte("ON2XE===")], - [[]byte("su"), []byte("ON2Q====")], - [[]byte("leasure."), []byte("NRSWC43VOJSS4===")], - [[]byte("easure."), []byte("MVQXG5LSMUXA====")], - [[]byte("asure."), []byte("MFZXK4TFFY======")], + // Wikipedia examples, converted to base32. + [[]byte("sure."), []byte("ON2XEZJO")], + [[]byte("sure"), []byte("ON2XEZI=")], + [[]byte("sur"), []byte("ON2XE===")], + [[]byte("su"), []byte("ON2Q====")], + [[]byte("leasure."), []byte("NRSWC43VOJSS4===")], + [[]byte("easure."), []byte("MVQXG5LSMUXA====")], + [[]byte("asure."), []byte("MFZXK4TFFY======")], ] #test fn testEncode(t: &T) { - for _, case in encodeDecodeMap { - r := Encode(case[0], true) - d := case[1] - if len(r) != len(d) { - t.Fail() - continue - } - for i in r { - if r[i] != d[i] { - t.Fail() - break - } - } - } + for _, case in encodeDecodeMap { + r := Encode(case[0], true) + d := case[1] + if len(r) != len(d) { + t.Fail() + continue + } + for i in r { + if r[i] != d[i] { + t.Fail() + break + } + } + } } #test fn testDecode(t: &T) { - for _, case in encodeDecodeMap { - r := Decode(case[1]) - d := case[0] - if len(r) != len(d) { - t.Fail() - continue - } - for i in r { - if r[i] != d[i] { - t.Fail() - break - } - } - } + for _, case in encodeDecodeMap { + r := Decode(case[1]) + d := case[0] + if len(r) != len(d) { + t.Fail() + continue + } + for i in r { + if r[i] != d[i] { + t.Fail() + break + } + } + } } fn removePad(b: []byte): []byte { - mut bm := unsafe { *(&b) } - mut i := len(b) - 1 - for i >= 0 && b[i] == paddingByte; i-- {} - ret bm[:i+1] + mut bm := unsafe { *(&b) } + mut i := len(b) - 1 + for i >= 0 && b[i] == paddingByte; i-- {} + ret bm[:i+1] } #test fn testEncodeNoPad(t: &T) { - for _, case in encodeDecodeMap { - r := Encode(case[0], false) - d := removePad(case[1]) - if len(r) != len(d) { - t.Fail() - continue - } - for i in r { - if r[i] != d[i] { - t.Fail() - break - } - } - } + for _, case in encodeDecodeMap { + r := Encode(case[0], false) + d := removePad(case[1]) + if len(r) != len(d) { + t.Fail() + continue + } + for i in r { + if r[i] != d[i] { + t.Fail() + break + } + } + } } #test fn testDecodeNoPad(t: &T) { - for _, case in encodeDecodeMap { - r := Decode(case[1]) - d := removePad(case[0]) - if len(r) != len(d) { - t.Fail() - continue - } - for i in r { - if r[i] != d[i] { - t.Fail() - break - } - } - } + for _, case in encodeDecodeMap { + r := Decode(case[1]) + d := removePad(case[0]) + if len(r) != len(d) { + t.Fail() + continue + } + for i in r { + if r[i] != d[i] { + t.Fail() + break + } + } + } } \ No newline at end of file diff --git a/std/encoding/base64/base64.jule b/std/encoding/base64/base64.jule index 7cbe6fa94..b20e494b8 100644 --- a/std/encoding/base64/base64.jule +++ b/std/encoding/base64/base64.jule @@ -9,13 +9,13 @@ static t64e = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" // Decoding table for t64e. static t64d: [...]i32 = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 63, 62, 62, 63, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, 0, 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, 0, - 0, 0, 0, 63, 0, 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, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 63, 62, 62, 63, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, 0, 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, 0, + 0, 0, 0, 63, 0, 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, ] // Standard byte for padding. @@ -23,161 +23,161 @@ const paddingByte = '=' // Returns length of encoded bytes of b. fn EncodeLen(b: []byte, pad: bool): int { - if !pad { - ret len(b) / 3 << 2 + (len(b) % 3 * 8 + 5) / 6 - } - ret (len(b) + 2) / 3 << 2 + if !pad { + ret len(b) / 3 << 2 + (len(b) % 3 * 8 + 5) / 6 + } + ret (len(b) + 2) / 3 << 2 } fn decodeLen(&b: []byte): (n: int, l: int, pad1: bool, pad2: bool) { - if len(b) == 0 { - ret - } - p := &b[0] - pad1 = len(b) > 0 && (len(b)%4 != 0 || unsafe { p[len(b)-1] } == paddingByte) - l = (len(b) + 3) / 4 - if pad1 { - l-- - } - l = l << 2 - pad2 = pad1 && len(b) > l+2 && unsafe { p[l+2] } != paddingByte - n = l >> 2 * 3 - if pad1 { - n++ - if pad2 { - n++ - } - } - ret + if len(b) == 0 { + ret + } + p := &b[0] + pad1 = len(b) > 0 && (len(b)%4 != 0 || unsafe { p[len(b)-1] } == paddingByte) + l = (len(b) + 3) / 4 + if pad1 { + l-- + } + l = l << 2 + pad2 = pad1 && len(b) > l+2 && unsafe { p[l+2] } != paddingByte + n = l >> 2 * 3 + if pad1 { + n++ + if pad2 { + n++ + } + } + ret } // Returns length of decoded bytes of b. fn DecodeLen(b: []byte): int { - n, _, _, _ := decodeLen(b) - ret n + n, _, _, _ := decodeLen(b) + ret n } fn encode(&src: []byte, pad: bool): []byte { - n := EncodeLen(src, pad) - if n <= len(src) { - ret nil - } - mut dest := make([]byte, n) - mut j := &dest[0] - mut i := &src[0] - end := i + len(src) - table := &t64e[0] - for i+3 <= end; i += 3 { - unsafe { - *j = table[i[0]>>2] - j++ - *j = table[((i[0]&0x03)<<4)|(i[1]>>4)] - j++ - *j = table[((i[1]&0x0f)<<2)|(i[2]>>6)] - j++ - *j = table[i[2]&0x3f] - j++ - } - } - if i < end { - unsafe { - *j = table[i[0]>>2] - j++ - if i+1 == end { - *j = table[(i[0]&0x03)<<4] - j++ - if pad { - *j = paddingByte - j++ - } - } else { - *j = table[((i[0]&0x03)<<4)|(i[1]>>4)] - j++ - *j = table[(i[1]&0x0f)<<2] - j++ - } - if pad { - *j = paddingByte - j++ - } - } - } - ret dest + n := EncodeLen(src, pad) + if n <= len(src) { + ret nil + } + mut dest := make([]byte, n) + mut j := &dest[0] + mut i := &src[0] + end := i + len(src) + table := &t64e[0] + for i+3 <= end; i += 3 { + unsafe { + *j = table[i[0]>>2] + j++ + *j = table[((i[0]&0x03)<<4)|(i[1]>>4)] + j++ + *j = table[((i[1]&0x0f)<<2)|(i[2]>>6)] + j++ + *j = table[i[2]&0x3f] + j++ + } + } + if i < end { + unsafe { + *j = table[i[0]>>2] + j++ + if i+1 == end { + *j = table[(i[0]&0x03)<<4] + j++ + if pad { + *j = paddingByte + j++ + } + } else { + *j = table[((i[0]&0x03)<<4)|(i[1]>>4)] + j++ + *j = table[(i[1]&0x0f)<<2] + j++ + } + if pad { + *j = paddingByte + j++ + } + } + } + ret dest } // Encodes source bytes with standard base64 table. // Returns encoded base64 bytes if success, nil slice if not. // Adds padding if pad is true. fn Encode(src: []byte, pad: bool): []byte { - ret encode(src, pad) + ret encode(src, pad) } // Encodes source bytes with url base64 table. // It is typically used for URLs and file names. // Returns encoded base64 bytes if success, nil slice if not. fn EncodeUrl(src: []byte): []byte { - const Padding = false - mut r := encode(src, Padding) - for i, b in r { - match b { - | '+': - r[i] = '-' - | '/': - r[i] = '_' - } - } - ret r + const Padding = false + mut r := encode(src, Padding) + for i, b in r { + match b { + | '+': + r[i] = '-' + | '/': + r[i] = '_' + } + } + ret r } fn decode(&src: []byte): []byte { - n, l, pad1, pad2 := decodeLen(src) - if n == 0 { - ret nil - } - mut dest := make([]byte, n) - - mut d := &dest[0] - p := &src[0] - - // Use pointer for table to skip boundary-checking cost. - ip := &t64d[0] - - mut i := 0 - for i < l; i += 4 { - unsafe { - k := ip[p[i]] << 18 | ip[p[i+1]] << 12 | ip[p[i+2]] << 6 | ip[p[i+3]] - *d = byte(k >> 16) - d++ - *d = byte(k >> 8 & 0xFF) - d++ - *d = byte(k & 0xFF) - d++ - } - } - if pad1 { - unsafe { - mut k := ip[p[l]] << 18 | ip[p[l+1]] << 12 - *d = byte(k >> 16) - if pad2 { - d++ - k |= ip[p[l+2]] << 6 - *d = byte(k >> 8 & 0xFF) - } - } - } - ret dest + n, l, pad1, pad2 := decodeLen(src) + if n == 0 { + ret nil + } + mut dest := make([]byte, n) + + mut d := &dest[0] + p := &src[0] + + // Use pointer for table to skip boundary-checking cost. + ip := &t64d[0] + + mut i := 0 + for i < l; i += 4 { + unsafe { + k := ip[p[i]] << 18 | ip[p[i+1]] << 12 | ip[p[i+2]] << 6 | ip[p[i+3]] + *d = byte(k >> 16) + d++ + *d = byte(k >> 8 & 0xFF) + d++ + *d = byte(k & 0xFF) + d++ + } + } + if pad1 { + unsafe { + mut k := ip[p[l]] << 18 | ip[p[l+1]] << 12 + *d = byte(k >> 16) + if pad2 { + d++ + k |= ip[p[l+2]] << 6 + *d = byte(k >> 8 & 0xFF) + } + } + } + ret dest } // Decodes source bytes with standard base64 table. // Returns decoded bytes if success, nil slice if not. // Detects padding by default, no required padding specification. fn Decode(src: []byte): []byte { - ret decode(src) + ret decode(src) } // Decodes source bytes with url base64 table. // It is typically used for URLs and file names. // Returns decoded bytes if success, nil slice if not. fn DecodeUrl(src: []byte): []byte { - ret decode(src) + ret decode(src) } \ No newline at end of file diff --git a/std/encoding/base64/base64_test.jule b/std/encoding/base64/base64_test.jule index 0ddf1284c..59d189a1e 100644 --- a/std/encoding/base64/base64_test.jule +++ b/std/encoding/base64/base64_test.jule @@ -7,105 +7,105 @@ use std::testing::{T} static encodeDecodeMap = [ - // RFC 3548 examples. - [[]byte("\x14\xfb\x9c\x03\xd9\x7e"), []byte("FPucA9l+")], - [[]byte("\x14\xfb\x9c\x03\xd9"), []byte("FPucA9k=")], - [[]byte("\x14\xfb\x9c\x03"), []byte("FPucAw==")], + // RFC 3548 examples. + [[]byte("\x14\xfb\x9c\x03\xd9\x7e"), []byte("FPucA9l+")], + [[]byte("\x14\xfb\x9c\x03\xd9"), []byte("FPucA9k=")], + [[]byte("\x14\xfb\x9c\x03"), []byte("FPucAw==")], - // RFC 4648 examples. - [[]byte(""), []byte("")], - [[]byte("f"), []byte("Zg==")], - [[]byte("fo"), []byte("Zm8=")], - [[]byte("foo"), []byte("Zm9v")], - [[]byte("foob"), []byte("Zm9vYg==")], - [[]byte("fooba"), []byte("Zm9vYmE=")], - [[]byte("foobar"), []byte("Zm9vYmFy")], + // RFC 4648 examples. + [[]byte(""), []byte("")], + [[]byte("f"), []byte("Zg==")], + [[]byte("fo"), []byte("Zm8=")], + [[]byte("foo"), []byte("Zm9v")], + [[]byte("foob"), []byte("Zm9vYg==")], + [[]byte("fooba"), []byte("Zm9vYmE=")], + [[]byte("foobar"), []byte("Zm9vYmFy")], - // Wikipedia examples. - [[]byte("sure."), []byte("c3VyZS4=")], - [[]byte("sure"), []byte("c3VyZQ==")], - [[]byte("sur"), []byte("c3Vy")], - [[]byte("su"), []byte("c3U=")], - [[]byte("leasure."), []byte("bGVhc3VyZS4=")], - [[]byte("easure."), []byte("ZWFzdXJlLg==")], - [[]byte("asure."), []byte("YXN1cmUu")], + // Wikipedia examples. + [[]byte("sure."), []byte("c3VyZS4=")], + [[]byte("sure"), []byte("c3VyZQ==")], + [[]byte("sur"), []byte("c3Vy")], + [[]byte("su"), []byte("c3U=")], + [[]byte("leasure."), []byte("bGVhc3VyZS4=")], + [[]byte("easure."), []byte("ZWFzdXJlLg==")], + [[]byte("asure."), []byte("YXN1cmUu")], ] #test fn testEncode(t: &T) { - for _, case in encodeDecodeMap { - r := Encode(case[0], true) - d := case[1] - if len(r) != len(d) { - t.Fail() - continue - } - for i in r { - if r[i] != d[i] { - t.Fail() - break - } - } - } + for _, case in encodeDecodeMap { + r := Encode(case[0], true) + d := case[1] + if len(r) != len(d) { + t.Fail() + continue + } + for i in r { + if r[i] != d[i] { + t.Fail() + break + } + } + } } #test fn testDecode(t: &T) { - for _, case in encodeDecodeMap { - r := Decode(case[1]) - d := case[0] - if len(r) != len(d) { - t.Fail() - continue - } - for i in r { - if r[i] != d[i] { - t.Fail() - break - } - } - } + for _, case in encodeDecodeMap { + r := Decode(case[1]) + d := case[0] + if len(r) != len(d) { + t.Fail() + continue + } + for i in r { + if r[i] != d[i] { + t.Fail() + break + } + } + } } fn removePad(b: []byte): []byte { - mut bm := unsafe { *(&b) } - mut i := len(b) - 1 - for i >= 0 && b[i] == paddingByte; i-- {} - ret bm[:i+1] + mut bm := unsafe { *(&b) } + mut i := len(b) - 1 + for i >= 0 && b[i] == paddingByte; i-- {} + ret bm[:i+1] } #test fn testEncodeNoPad(t: &T) { - for _, case in encodeDecodeMap { - r := Encode(case[0], false) - d := removePad(case[1]) - if len(r) != len(d) { - t.Fail() - continue - } - for i in r { - if r[i] != d[i] { - t.Fail() - break - } - } - } + for _, case in encodeDecodeMap { + r := Encode(case[0], false) + d := removePad(case[1]) + if len(r) != len(d) { + t.Fail() + continue + } + for i in r { + if r[i] != d[i] { + t.Fail() + break + } + } + } } #test fn testDecodeNoPad(t: &T) { - for _, case in encodeDecodeMap { - r := Decode(case[1]) - d := removePad(case[0]) - if len(r) != len(d) { - t.Fail() - continue - } - for i in r { - if r[i] != d[i] { - t.Fail() - break - } - } - } + for _, case in encodeDecodeMap { + r := Decode(case[1]) + d := removePad(case[0]) + if len(r) != len(d) { + t.Fail() + continue + } + for i in r { + if r[i] != d[i] { + t.Fail() + break + } + } + } } \ No newline at end of file diff --git a/std/encoding/binary/big_endian.jule b/std/encoding/binary/big_endian.jule index ad537a076..89669489f 100644 --- a/std/encoding/binary/big_endian.jule +++ b/std/encoding/binary/big_endian.jule @@ -6,74 +6,74 @@ struct BigEndian {} impl BigEndian { - // Encodes unsigned 16-bit integer into 2-bytes slice. - static fn PutU16(mut b: []byte, x: u16) { - b[0] = byte(x >> 8) - b[1] = byte(x) - } + // Encodes unsigned 16-bit integer into 2-bytes slice. + static fn PutU16(mut b: []byte, x: u16) { + b[0] = byte(x >> 8) + b[1] = byte(x) + } - // Encodes unsigned 16-bit integer and appends to slice. - static fn AppendU16(mut b: []byte, x: u16) { - b = append(b, - byte(x >> 8), - byte(x)) - } + // Encodes unsigned 16-bit integer and appends to slice. + static fn AppendU16(mut b: []byte, x: u16) { + b = append(b, + byte(x >> 8), + byte(x)) + } - // Decodes unsigned 16-bit integer from 2-bytes. - static fn DecodeU16(b: []byte): u16 { - ret u16(b[1]) | u16(b[0]) << 8 - } + // Decodes unsigned 16-bit integer from 2-bytes. + static fn DecodeU16(b: []byte): u16 { + ret u16(b[1]) | u16(b[0]) << 8 + } - // Encodes unsigned 32-bit integer into 4-bytes slice. - static fn PutU32(mut b: []byte, x: u32) { - b[0] = byte(x >> 24) - b[1] = byte(x >> 16) - b[2] = byte(x >> 8) - b[3] = byte(x) - } + // Encodes unsigned 32-bit integer into 4-bytes slice. + static fn PutU32(mut b: []byte, x: u32) { + b[0] = byte(x >> 24) + b[1] = byte(x >> 16) + b[2] = byte(x >> 8) + b[3] = byte(x) + } - // Encodes unsigned 32-bit integer and appends to slice. - static fn AppendU32(mut b: []byte, x: u32) { - b = append(b, - byte(x >> 24), - byte(x >> 16), - byte(x >> 8), - byte(x)) - } + // Encodes unsigned 32-bit integer and appends to slice. + static fn AppendU32(mut b: []byte, x: u32) { + b = append(b, + byte(x >> 24), + byte(x >> 16), + byte(x >> 8), + byte(x)) + } - // Decodes unsigned 32-bit integer from 4-bytes. - static fn DecodeU32(b: []byte): u32 { - ret u32(b[3]) | u32(b[2]) << 8 | u32(b[1]) << 16 | u32(b[0]) << 24 - } + // Decodes unsigned 32-bit integer from 4-bytes. + static fn DecodeU32(b: []byte): u32 { + ret u32(b[3]) | u32(b[2]) << 8 | u32(b[1]) << 16 | u32(b[0]) << 24 + } - // Encodes unsigned 64-bit integer into 8-bytes slice. - static fn PutU64(mut b: []byte, x: u64) { - b[0] = byte(x >> 56) - b[1] = byte(x >> 48) - b[2] = byte(x >> 40) - b[3] = byte(x >> 32) - b[4] = byte(x >> 24) - b[5] = byte(x >> 16) - b[6] = byte(x >> 8) - b[7] = byte(x) - } + // Encodes unsigned 64-bit integer into 8-bytes slice. + static fn PutU64(mut b: []byte, x: u64) { + b[0] = byte(x >> 56) + b[1] = byte(x >> 48) + b[2] = byte(x >> 40) + b[3] = byte(x >> 32) + b[4] = byte(x >> 24) + b[5] = byte(x >> 16) + b[6] = byte(x >> 8) + b[7] = byte(x) + } - // Encodes unsigned 64-bit integer and appends to slice. - static fn AppendU64(mut b: []byte, x: u64) { - b = append(b, - byte(x >> 56), - byte(x >> 48), - byte(x >> 40), - byte(x >> 32), - byte(x >> 24), - byte(x >> 16), - byte(x >> 8), - byte(x)) - } + // Encodes unsigned 64-bit integer and appends to slice. + static fn AppendU64(mut b: []byte, x: u64) { + b = append(b, + byte(x >> 56), + byte(x >> 48), + byte(x >> 40), + byte(x >> 32), + byte(x >> 24), + byte(x >> 16), + byte(x >> 8), + byte(x)) + } - // Decodes unsigned 64-bit integer from 8-bytes. - static fn DecodeU64(b: []byte): u64 { - ret u64(b[7]) | u64(b[6]) << 8 | u64(b[5]) << 16 | u64(b[4]) << 24 | - u64(b[3]) << 32 | u64(b[2]) << 40 | u64(b[1]) << 48 | u64(b[0]) << 56 - } + // Decodes unsigned 64-bit integer from 8-bytes. + static fn DecodeU64(b: []byte): u64 { + ret u64(b[7]) | u64(b[6]) << 8 | u64(b[5]) << 16 | u64(b[4]) << 24 | + u64(b[3]) << 32 | u64(b[2]) << 40 | u64(b[1]) << 48 | u64(b[0]) << 56 + } } \ No newline at end of file diff --git a/std/encoding/binary/little_endian.jule b/std/encoding/binary/little_endian.jule index fcc641f2b..d06d0f51d 100644 --- a/std/encoding/binary/little_endian.jule +++ b/std/encoding/binary/little_endian.jule @@ -6,74 +6,74 @@ struct LittleEndian {} impl LittleEndian { - // Encodes unsigned 16-bit integer into 2-bytes slice. - static fn PutU16(mut b: []byte, x: u16) { - b[0] = byte(x) - b[1] = byte(x >> 8) - } + // Encodes unsigned 16-bit integer into 2-bytes slice. + static fn PutU16(mut b: []byte, x: u16) { + b[0] = byte(x) + b[1] = byte(x >> 8) + } - // Encodes unsigned 16-bit integer and appends to slice. - static fn AppendU16(mut b: []byte, x: u16) { - b = append(b, - byte(x), - byte(x >> 8)) - } + // Encodes unsigned 16-bit integer and appends to slice. + static fn AppendU16(mut b: []byte, x: u16) { + b = append(b, + byte(x), + byte(x >> 8)) + } - // Decodes unsigned 16-bit integer from 2-bytes. - static fn DecodeU16(b: []byte): u16 { - ret u16(b[0]) | u16(b[1]) << 8 - } + // Decodes unsigned 16-bit integer from 2-bytes. + static fn DecodeU16(b: []byte): u16 { + ret u16(b[0]) | u16(b[1]) << 8 + } - // Encodes unsigned 32-bit integer into 4-bytes slice. - static fn PutU32(mut b: []byte, x: u32) { - b[0] = byte(x) - b[1] = byte(x >> 8) - b[2] = byte(x >> 16) - b[3] = byte(x >> 24) - } + // Encodes unsigned 32-bit integer into 4-bytes slice. + static fn PutU32(mut b: []byte, x: u32) { + b[0] = byte(x) + b[1] = byte(x >> 8) + b[2] = byte(x >> 16) + b[3] = byte(x >> 24) + } - // Encodes unsigned 32-bit integer and appends to slice. - static fn AppendU32(mut b: []byte, x: u32) { - b = append(b, - byte(x), - byte(x >> 8), - byte(x >> 16), - byte(x >> 24)) - } + // Encodes unsigned 32-bit integer and appends to slice. + static fn AppendU32(mut b: []byte, x: u32) { + b = append(b, + byte(x), + byte(x >> 8), + byte(x >> 16), + byte(x >> 24)) + } - // Decodes unsigned 32-bit integer from 4-bytes. - static fn DecodeU32(b: []byte): u32 { - ret u32(b[0]) | u32(b[1]) << 8 | u32(b[2]) << 16 | u32(b[3]) << 24 - } + // Decodes unsigned 32-bit integer from 4-bytes. + static fn DecodeU32(b: []byte): u32 { + ret u32(b[0]) | u32(b[1]) << 8 | u32(b[2]) << 16 | u32(b[3]) << 24 + } - // Encodes unsigned 64-bit integer into 8-bytes slice. - static fn PutU64(mut b: []byte, x: u64) { - b[0] = byte(x) - b[1] = byte(x >> 8) - b[2] = byte(x >> 16) - b[3] = byte(x >> 24) - b[4] = byte(x >> 32) - b[5] = byte(x >> 40) - b[6] = byte(x >> 48) - b[7] = byte(x >> 56) - } + // Encodes unsigned 64-bit integer into 8-bytes slice. + static fn PutU64(mut b: []byte, x: u64) { + b[0] = byte(x) + b[1] = byte(x >> 8) + b[2] = byte(x >> 16) + b[3] = byte(x >> 24) + b[4] = byte(x >> 32) + b[5] = byte(x >> 40) + b[6] = byte(x >> 48) + b[7] = byte(x >> 56) + } - // Encodes unsigned 64-bit integer and appends to slice. - static fn AppendU64(mut b: []byte, x: u64) { - b = append(b, - byte(x), - byte(x >> 8), - byte(x >> 16), - byte(x >> 24), - byte(x >> 32), - byte(x >> 40), - byte(x >> 48), - byte(x >> 56)) - } + // Encodes unsigned 64-bit integer and appends to slice. + static fn AppendU64(mut b: []byte, x: u64) { + b = append(b, + byte(x), + byte(x >> 8), + byte(x >> 16), + byte(x >> 24), + byte(x >> 32), + byte(x >> 40), + byte(x >> 48), + byte(x >> 56)) + } - // Decodes unsigned 64-bit integer from 8-bytes. - static fn DecodeU64(b: []byte): u64 { - ret u64(b[0]) | u64(b[1]) << 8 | u64(b[2]) << 16 | u64(b[3]) << 24 | - u64(b[4]) << 32 | u64(b[5]) << 40 | u64(b[6]) << 48 | u64(b[7]) << 56 - } + // Decodes unsigned 64-bit integer from 8-bytes. + static fn DecodeU64(b: []byte): u64 { + ret u64(b[0]) | u64(b[1]) << 8 | u64(b[2]) << 16 | u64(b[3]) << 24 | + u64(b[4]) << 32 | u64(b[5]) << 40 | u64(b[6]) << 48 | u64(b[7]) << 56 + } } \ No newline at end of file diff --git a/std/encoding/csv/error.jule b/std/encoding/csv/error.jule index 66ace9ac3..4a0819e7e 100644 --- a/std/encoding/csv/error.jule +++ b/std/encoding/csv/error.jule @@ -4,18 +4,18 @@ // CSV error codes. enum CsvError { - Read, - FieldCount, - InvalidDelim, - BareQuote, - Quote, + Read, + FieldCount, + InvalidDelim, + BareQuote, + Quote, } // A ParseError is returned for parsing errors. // Line and column numbers are 1-indexed. struct ParseError { - StartLine: int // Line where the record starts - Line: int // Line where the error occurred - Column: int // Column (1-based byte index) where the error occurred - Err: CsvError // The actual error + StartLine: int // Line where the record starts + Line: int // Line where the error occurred + Column: int // Column (1-based byte index) where the error occurred + Err: CsvError // The actual error } \ No newline at end of file diff --git a/std/encoding/csv/reader.jule b/std/encoding/csv/reader.jule index 4e90a44f2..814841f33 100644 --- a/std/encoding/csv/reader.jule +++ b/std/encoding/csv/reader.jule @@ -90,8 +90,8 @@ use utf8 for std::unicode::utf8 // Holds the position of a field in the current line. struct position { - line: int - col: int + line: int + col: int } // A Reader reads records from a CSV-encoded file. @@ -104,356 +104,356 @@ struct position { // including in multiline field values, so that the returned data does // not depend on which line-ending convention an input file uses. struct Reader { - // The field delimiter. - // It is set to comma (',') by NewReader. - // Comma must be a valid rune and must not be \r, \n, - // or the Unicode replacement character (0xFFFD). - Comma: rune - - // Comment, if not 0, is the comment character. Lines beginning with the - // Comment character without preceding whitespace are ignored. - // With leading whitespace the Comment character becomes part of the - // field, even if Trim_leading_space is true. - // Comment must be a valid rune and must not be \r, \n, - // or the Unicode replacement character (0xFFFD). - // It must also not be equal to comma. - Comment: rune - - // The number of expected fields per record. - // If fields_per_record is positive, read requires each record to - // have the given number of fields. If fields_per_record is 0, read sets it to - // the number of fields in the first record, so that future records must - // have the same field count. If fields_per_record is negative, no check is - // made and records may have a variable number of fields. - FieldsPerRecord: int - - // If it is true, a quote may appear in an unquoted field and a - // non-doubled quote may appear in a quoted field. - LazyQuotes: bool - - // If it is true, leading white space in a field is ignored. - // This is done even if the field delimiter, comma, is white space. - TrimLeadingSpace: bool - - // Controls whether calls to read may return a slice sharing - // the backing array of the previous call's returned slice for performance. - // By default, each call to read returns newly allocated memory owned by the caller. - ReuseRecord: bool - - s: &io::Scanner - - // The current line being read in the CSV file. - numLine: int - - // The input stream byte offset of the current reader position. - offset: int - - // rawBuffer is a line buffer only used by the readLine method. - rawBuffer: []byte - - // Holds the unescaped fields, one after another. - // The fields can be accessed by using the indexes in field_indexes. - // E.g., For the row `a,"b","c""d",e`, recordBuffer will contain `abc"de` - // and field_indexes will contain the indexes [1, 2, 5, 6]. - recordBuffer: []byte - - // Index of fields inside record_buffer. - // The i'th field ends at offset field_indexes[i] in record_buffer. - fieldIndexes: []int - - // fieldPositions is an index of field positions for the - // last record returned by Read. - fieldPositions: []position - - // Record cache and only used when reuse_record == true. - lastRecord: []str + // The field delimiter. + // It is set to comma (',') by NewReader. + // Comma must be a valid rune and must not be \r, \n, + // or the Unicode replacement character (0xFFFD). + Comma: rune + + // Comment, if not 0, is the comment character. Lines beginning with the + // Comment character without preceding whitespace are ignored. + // With leading whitespace the Comment character becomes part of the + // field, even if Trim_leading_space is true. + // Comment must be a valid rune and must not be \r, \n, + // or the Unicode replacement character (0xFFFD). + // It must also not be equal to comma. + Comment: rune + + // The number of expected fields per record. + // If fields_per_record is positive, read requires each record to + // have the given number of fields. If fields_per_record is 0, read sets it to + // the number of fields in the first record, so that future records must + // have the same field count. If fields_per_record is negative, no check is + // made and records may have a variable number of fields. + FieldsPerRecord: int + + // If it is true, a quote may appear in an unquoted field and a + // non-doubled quote may appear in a quoted field. + LazyQuotes: bool + + // If it is true, leading white space in a field is ignored. + // This is done even if the field delimiter, comma, is white space. + TrimLeadingSpace: bool + + // Controls whether calls to read may return a slice sharing + // the backing array of the previous call's returned slice for performance. + // By default, each call to read returns newly allocated memory owned by the caller. + ReuseRecord: bool + + s: &io::Scanner + + // The current line being read in the CSV file. + numLine: int + + // The input stream byte offset of the current reader position. + offset: int + + // rawBuffer is a line buffer only used by the readLine method. + rawBuffer: []byte + + // Holds the unescaped fields, one after another. + // The fields can be accessed by using the indexes in field_indexes. + // E.g., For the row `a,"b","c""d",e`, recordBuffer will contain `abc"de` + // and field_indexes will contain the indexes [1, 2, 5, 6]. + recordBuffer: []byte + + // Index of fields inside record_buffer. + // The i'th field ends at offset field_indexes[i] in record_buffer. + fieldIndexes: []int + + // fieldPositions is an index of field positions for the + // last record returned by Read. + fieldPositions: []position + + // Record cache and only used when reuse_record == true. + lastRecord: []str } impl Reader { - // Returns new Reader instance that reads r. - static fn New(mut r: io::Reader): &Reader { - ret &Reader{ - Comma: ',', - s: io::Scanner.New(r), - } - } - - // Returns the input stream byte offset of the current reader - // position. The offset gives the location of the end of the most recently - // read row and the beginning of the next row. - fn InputOffset(self): int { - ret self.offset - } - - // Reads one record (a slice of fields) from r. - // If the record has an unexpected number of fields, - // read returns the [CsvError.FieldCount] as exception. - // If there is no data left to be read, read returns nil. - // If [self.ReuseRecord] is true, the returned slice may be shared - // between multiple calls to read. - // Exception can be CsvError or ParseError, and forwards reader's exceptions. - fn Read(mut self)!: (record: []str) { - if self.ReuseRecord { - record = self.readRecord(self.lastRecord) else { error(error) } - self.lastRecord = record - } else { - record = self.readRecord(nil) else { error(error) } - } - ret - } - - // Returns the line and column corresponding to - // the start of the field with the given index in the slice most recently - // returned by [read]. Numbering of lines and columns starts at 1; - // columns are counted in bytes, not runes. - // - // If this is called with an out-of-bounds index, it panics. - fn FieldPos(self, field: int): (line: int, column: int) { - if field < 0 || field >= len(self.fieldPositions) { - panic("std::encoding::csv: Reader: out of range index passed to field_pos") - } - p := &self.fieldPositions[field] - unsafe { - ret p.line, p.col - } - } - - // Reads all the remaining records from r. - // Each record is a slice of fields. - // Exception can be CsvError or ParseError, and forwards reader errors. - fn ReadAll(mut self)!: (records: [][]str) { - for { - mut record := self.readRecord(nil) else { error(error) } - if len(record) == 0 { - break - } - records = append(records, record) - } - ret - } - - // Reads the next line (with the trailing endline). - // If EOF is hit without a trailing endline, it will be omitted. - // The result is only valid until the next call to read_line. - fn readLine(mut self)!: []byte { - scan := self.s.Scan() else { error(error) } - if !scan { - ret nil - } - mut line := self.s.Bytes() - if len(line) == 0 { - ret nil - } - self.numLine++ - self.offset += len(line) - - // Normalize \r\n to \n on all input lines. - if len(line) >= 2 && line[len(line)-2] == '\r' && line[len(line)-1] == '\n' { - line[len(line)-2] = '\n' - line = line[:len(line)-1] - } - ret line - } - - fn readRecord(mut self, mut dst: []str)!: []str { - if self.Comma == self.Comment || - !validDelim(self.Comma) || - (self.Comment != 0 && !validDelim(self.Comment)) { - error(CsvError.InvalidDelim) - } - - // Read line (automatically skipping past empty lines and any comments). - let mut line: []byte - for { - line = self.readLine() else { error(error) } - if line == nil { - ret nil - } - if self.Comment != 0 && nextRune(line) == self.Comment { - line = nil - continue // Skip comment lines - } - if len(line) == lengthNl(line) { - line = nil - continue // Skip empty lines - } - break - } - - // Parse each field in the record. - const QuoteLen = len(`"`) - commaLen := utf8::RuneLen(self.Comma) - mut recLine := self.numLine // Starting line for record - self.recordBuffer = self.recordBuffer[:0] - self.fieldIndexes = self.fieldIndexes[:0] - self.fieldPositions = self.fieldPositions[:0] - mut pos := position{line: self.numLine, col: 1} - parseField: - for { - if self.TrimLeadingSpace { - mut i := bytes::FindFn(line, fn(mut r: rune): bool { - ret !unicode::IsSpace(r) - }) - if i == -1 { - i = len(line) - pos.col -= lengthNl(line) - } - line = line[i:] - pos.col += i - } - if len(line) == 0 || line[0] != '"' { - // Non-quoted string field - i := bytes::FindRune(line, self.Comma) - mut field := line - if i >= 0 { - field = field[:i] - } else { - field = field[:len(field)-lengthNl(field)] - } - // Check to make sure a quote does not appear in field. - if !self.LazyQuotes { - j := bytes::FindByte(field, '"') - if j >= 0 { - error(&ParseError{ - StartLine: recLine, - Line: self.numLine, - Column: pos.col + j, - Err: CsvError.BareQuote, - }) - break parseField - } - } - self.recordBuffer = append(self.recordBuffer, field...) - self.fieldIndexes = append(self.fieldIndexes, len(self.recordBuffer)) - self.fieldPositions = append(self.fieldPositions, pos) - if i >= 0 { - line = line[i+commaLen:] - pos.col += i + commaLen - continue parseField - } - break parseField - } else { - // Quoted string field - fieldPos := pos - line = line[QuoteLen:] - pos.col += QuoteLen - for { - i := bytes::FindByte(line, '"') - if i >= 0 { - // Hit next quote. - self.recordBuffer = append(self.recordBuffer, line[:i]...) - line = line[i+QuoteLen:] - pos.col += i + QuoteLen - rn := nextRune(line) - match { - | rn == '"': - // `""` sequence (append quote). - self.recordBuffer = append(self.recordBuffer, '"') - line = line[QuoteLen:] - pos.col += QuoteLen - | rn == self.Comma: - // `",` sequence (end of field). - line = line[commaLen:] - pos.col += commaLen - self.fieldIndexes = append(self.fieldIndexes, len(self.recordBuffer)) - self.fieldPositions = append(self.fieldPositions, fieldPos) - continue parseField - | lengthNl(line) == len(line): - // `"\n` sequence (end of line). - self.fieldIndexes = append(self.fieldIndexes, len(self.recordBuffer)) - self.fieldPositions = append(self.fieldPositions, fieldPos) - break parseField - | self.LazyQuotes: - // `"` sequence (bare quote). - self.recordBuffer = append(self.recordBuffer, '"') - |: - // `"*` sequence (invalid non-escaped quote). - error(&ParseError{ - StartLine: recLine, - Line: self.numLine, - Column: pos.col - QuoteLen, - Err: CsvError.Quote, - }) - break parseField - } - } else if len(line) > 0 { - // Hit end of line (copy all data so far). - self.recordBuffer = append(self.recordBuffer, line...) - pos.col += len(line) - line = self.readLine() else { error(error) } - if len(line) > 0 { - pos.line++ - pos.col = 1 - } - } else { - // Abrupt end of file (EOF or error). - if !self.LazyQuotes { - error(&ParseError{ - StartLine: recLine, - Line: pos.line, - Column: pos.col, - Err: CsvError.Quote, - }) - break parseField - } - self.fieldIndexes = append(self.fieldIndexes, len(self.recordBuffer)) - self.fieldPositions = append(self.fieldPositions, fieldPos) - break parseField - } - } - } - } - - // Create a single string and create slices out of it. - // This pins the memory of the fields together, but allocates once. - s := str(self.recordBuffer) // Convert to string once to batch allocations - if cap(dst) < len(self.fieldIndexes) { - dst = make([]str, len(self.fieldIndexes)) - } else { - dst = dst[:0] - } - mut preIdx := 0 - for i, idx in self.fieldIndexes { - dst[i] = s[preIdx:idx] - preIdx = idx - } - - // Check or update the expected fields per record. - if self.FieldsPerRecord > 0 { - if len(dst) != self.FieldsPerRecord { - error(&ParseError{ - StartLine: recLine, - Line: recLine, - Column: 1, - Err: CsvError.FieldCount, - }) - } - } else if self.FieldsPerRecord == 0 { - self.FieldsPerRecord = len(dst) - } - ret dst - } + // Returns new Reader instance that reads r. + static fn New(mut r: io::Reader): &Reader { + ret &Reader{ + Comma: ',', + s: io::Scanner.New(r), + } + } + + // Returns the input stream byte offset of the current reader + // position. The offset gives the location of the end of the most recently + // read row and the beginning of the next row. + fn InputOffset(self): int { + ret self.offset + } + + // Reads one record (a slice of fields) from r. + // If the record has an unexpected number of fields, + // read returns the [CsvError.FieldCount] as exception. + // If there is no data left to be read, read returns nil. + // If [self.ReuseRecord] is true, the returned slice may be shared + // between multiple calls to read. + // Exception can be CsvError or ParseError, and forwards reader's exceptions. + fn Read(mut self)!: (record: []str) { + if self.ReuseRecord { + record = self.readRecord(self.lastRecord) else { error(error) } + self.lastRecord = record + } else { + record = self.readRecord(nil) else { error(error) } + } + ret + } + + // Returns the line and column corresponding to + // the start of the field with the given index in the slice most recently + // returned by [read]. Numbering of lines and columns starts at 1; + // columns are counted in bytes, not runes. + // + // If this is called with an out-of-bounds index, it panics. + fn FieldPos(self, field: int): (line: int, column: int) { + if field < 0 || field >= len(self.fieldPositions) { + panic("std::encoding::csv: Reader: out of range index passed to field_pos") + } + p := &self.fieldPositions[field] + unsafe { + ret p.line, p.col + } + } + + // Reads all the remaining records from r. + // Each record is a slice of fields. + // Exception can be CsvError or ParseError, and forwards reader errors. + fn ReadAll(mut self)!: (records: [][]str) { + for { + mut record := self.readRecord(nil) else { error(error) } + if len(record) == 0 { + break + } + records = append(records, record) + } + ret + } + + // Reads the next line (with the trailing endline). + // If EOF is hit without a trailing endline, it will be omitted. + // The result is only valid until the next call to read_line. + fn readLine(mut self)!: []byte { + scan := self.s.Scan() else { error(error) } + if !scan { + ret nil + } + mut line := self.s.Bytes() + if len(line) == 0 { + ret nil + } + self.numLine++ + self.offset += len(line) + + // Normalize \r\n to \n on all input lines. + if len(line) >= 2 && line[len(line)-2] == '\r' && line[len(line)-1] == '\n' { + line[len(line)-2] = '\n' + line = line[:len(line)-1] + } + ret line + } + + fn readRecord(mut self, mut dst: []str)!: []str { + if self.Comma == self.Comment || + !validDelim(self.Comma) || + (self.Comment != 0 && !validDelim(self.Comment)) { + error(CsvError.InvalidDelim) + } + + // Read line (automatically skipping past empty lines and any comments). + let mut line: []byte + for { + line = self.readLine() else { error(error) } + if line == nil { + ret nil + } + if self.Comment != 0 && nextRune(line) == self.Comment { + line = nil + continue // Skip comment lines + } + if len(line) == lengthNl(line) { + line = nil + continue // Skip empty lines + } + break + } + + // Parse each field in the record. + const QuoteLen = len(`"`) + commaLen := utf8::RuneLen(self.Comma) + mut recLine := self.numLine // Starting line for record + self.recordBuffer = self.recordBuffer[:0] + self.fieldIndexes = self.fieldIndexes[:0] + self.fieldPositions = self.fieldPositions[:0] + mut pos := position{line: self.numLine, col: 1} + parseField: + for { + if self.TrimLeadingSpace { + mut i := bytes::FindFn(line, fn(mut r: rune): bool { + ret !unicode::IsSpace(r) + }) + if i == -1 { + i = len(line) + pos.col -= lengthNl(line) + } + line = line[i:] + pos.col += i + } + if len(line) == 0 || line[0] != '"' { + // Non-quoted string field + i := bytes::FindRune(line, self.Comma) + mut field := line + if i >= 0 { + field = field[:i] + } else { + field = field[:len(field)-lengthNl(field)] + } + // Check to make sure a quote does not appear in field. + if !self.LazyQuotes { + j := bytes::FindByte(field, '"') + if j >= 0 { + error(&ParseError{ + StartLine: recLine, + Line: self.numLine, + Column: pos.col + j, + Err: CsvError.BareQuote, + }) + break parseField + } + } + self.recordBuffer = append(self.recordBuffer, field...) + self.fieldIndexes = append(self.fieldIndexes, len(self.recordBuffer)) + self.fieldPositions = append(self.fieldPositions, pos) + if i >= 0 { + line = line[i+commaLen:] + pos.col += i + commaLen + continue parseField + } + break parseField + } else { + // Quoted string field + fieldPos := pos + line = line[QuoteLen:] + pos.col += QuoteLen + for { + i := bytes::FindByte(line, '"') + if i >= 0 { + // Hit next quote. + self.recordBuffer = append(self.recordBuffer, line[:i]...) + line = line[i+QuoteLen:] + pos.col += i + QuoteLen + rn := nextRune(line) + match { + | rn == '"': + // `""` sequence (append quote). + self.recordBuffer = append(self.recordBuffer, '"') + line = line[QuoteLen:] + pos.col += QuoteLen + | rn == self.Comma: + // `",` sequence (end of field). + line = line[commaLen:] + pos.col += commaLen + self.fieldIndexes = append(self.fieldIndexes, len(self.recordBuffer)) + self.fieldPositions = append(self.fieldPositions, fieldPos) + continue parseField + | lengthNl(line) == len(line): + // `"\n` sequence (end of line). + self.fieldIndexes = append(self.fieldIndexes, len(self.recordBuffer)) + self.fieldPositions = append(self.fieldPositions, fieldPos) + break parseField + | self.LazyQuotes: + // `"` sequence (bare quote). + self.recordBuffer = append(self.recordBuffer, '"') + |: + // `"*` sequence (invalid non-escaped quote). + error(&ParseError{ + StartLine: recLine, + Line: self.numLine, + Column: pos.col - QuoteLen, + Err: CsvError.Quote, + }) + break parseField + } + } else if len(line) > 0 { + // Hit end of line (copy all data so far). + self.recordBuffer = append(self.recordBuffer, line...) + pos.col += len(line) + line = self.readLine() else { error(error) } + if len(line) > 0 { + pos.line++ + pos.col = 1 + } + } else { + // Abrupt end of file (EOF or error). + if !self.LazyQuotes { + error(&ParseError{ + StartLine: recLine, + Line: pos.line, + Column: pos.col, + Err: CsvError.Quote, + }) + break parseField + } + self.fieldIndexes = append(self.fieldIndexes, len(self.recordBuffer)) + self.fieldPositions = append(self.fieldPositions, fieldPos) + break parseField + } + } + } + } + + // Create a single string and create slices out of it. + // This pins the memory of the fields together, but allocates once. + s := str(self.recordBuffer) // Convert to string once to batch allocations + if cap(dst) < len(self.fieldIndexes) { + dst = make([]str, len(self.fieldIndexes)) + } else { + dst = dst[:0] + } + mut preIdx := 0 + for i, idx in self.fieldIndexes { + dst[i] = s[preIdx:idx] + preIdx = idx + } + + // Check or update the expected fields per record. + if self.FieldsPerRecord > 0 { + if len(dst) != self.FieldsPerRecord { + error(&ParseError{ + StartLine: recLine, + Line: recLine, + Column: 1, + Err: CsvError.FieldCount, + }) + } + } else if self.FieldsPerRecord == 0 { + self.FieldsPerRecord = len(dst) + } + ret dst + } } fn validDelim(r: rune): bool { - ret r != 0 && - r != '"' && - r != '\r' && - r != '\n' && - utf8::ValidRune(r) && - r != utf8::RuneError + ret r != 0 && + r != '"' && + r != '\r' && + r != '\n' && + utf8::ValidRune(r) && + r != utf8::RuneError } // Returns the next rune in b or utf8::RuneError. fn nextRune(b: []byte): rune { - r, _ := utf8::DecodeRune(b) - ret r + r, _ := utf8::DecodeRune(b) + ret r } // Reports the number of bytes for the trailing \n. fn lengthNl(b: []byte): int { - if len(b) > 0 && b[len(b)-1] == '\n' { - ret 1 - } - ret 0 + if len(b) > 0 && b[len(b)-1] == '\n' { + ret 1 + } + ret 0 } \ No newline at end of file diff --git a/std/encoding/csv/writer.jule b/std/encoding/csv/writer.jule index 8d49f8197..d0837a042 100644 --- a/std/encoding/csv/writer.jule +++ b/std/encoding/csv/writer.jule @@ -56,127 +56,127 @@ use utf8 for std::unicode::utf8 // Flush method to guarantee all data has been forwarded to // the underlying io::Writer. struct Writer { - Comma: rune // Field delimiter (set to ',' by new) - UseCrlf: bool // True to use \r\n as the line terminator + Comma: rune // Field delimiter (set to ',' by new) + UseCrlf: bool // True to use \r\n as the line terminator - w: io::Writer + w: io::Writer } impl Writer { - // Returns new Writer instance that writes w. - static fn New(mut w: io::Writer): &Writer { - ret &Writer{ - Comma: ',', - w: w, - } - } + // Returns new Writer instance that writes w. + static fn New(mut w: io::Writer): &Writer { + ret &Writer{ + Comma: ',', + w: w, + } + } - // Reports whether our field must be enclosed in quotes. - // Fields with a comma, fields with a quote or newline, and - // fields which start with a space must be enclosed in quotes. - // We used to quote empty strings, but we do not anymore (as of Go 1.4). - // The two representations should be equivalent, but Postgres distinguishes - // quoted vs non-quoted empty string during database imports, and it has - // an option to force the quoted behavior for non-quoted CSV but it has - // no option to force the non-quoted behavior for quoted CSV, making - // CSV with quoted empty strings strictly less useful. - // Not quoting the empty string also makes this package match the behavior - // of Microsoft Excel and Google Drive. - // For Postgres, quote the data terminating string `\.`. - fn fieldNeedsQuotes(self, field: []byte): bool { - if len(field) == 0 { - ret false - } - if len(field) == 2 && field[0] == '\\' && field[1] == '.' { - ret true - } - if self.Comma < utf8::RuneSelf { - mut i := 0 - for i < len(field); i++ { - c := field[i] - if c == '\n' || c == '\r' || c == '"' || c == byte(self.Comma) { - ret true - } - } - } else if bytes::ContainsRune(field, self.Comma) || - bytes::ContainsAny(field, unsafe::StrBytes("\"\r\n")) { - ret true - } - r1, _ := utf8::DecodeRune(field) - ret unicode::IsSpace(r1) - } + // Reports whether our field must be enclosed in quotes. + // Fields with a comma, fields with a quote or newline, and + // fields which start with a space must be enclosed in quotes. + // We used to quote empty strings, but we do not anymore (as of Go 1.4). + // The two representations should be equivalent, but Postgres distinguishes + // quoted vs non-quoted empty string during database imports, and it has + // an option to force the quoted behavior for non-quoted CSV but it has + // no option to force the non-quoted behavior for quoted CSV, making + // CSV with quoted empty strings strictly less useful. + // Not quoting the empty string also makes this package match the behavior + // of Microsoft Excel and Google Drive. + // For Postgres, quote the data terminating string `\.`. + fn fieldNeedsQuotes(self, field: []byte): bool { + if len(field) == 0 { + ret false + } + if len(field) == 2 && field[0] == '\\' && field[1] == '.' { + ret true + } + if self.Comma < utf8::RuneSelf { + mut i := 0 + for i < len(field); i++ { + c := field[i] + if c == '\n' || c == '\r' || c == '"' || c == byte(self.Comma) { + ret true + } + } + } else if bytes::ContainsRune(field, self.Comma) || + bytes::ContainsAny(field, unsafe::StrBytes("\"\r\n")) { + ret true + } + r1, _ := utf8::DecodeRune(field) + ret unicode::IsSpace(r1) + } - // Writes a single CSV record along with any necessary quoting. - // A record is a slice of strings with each string being one field. - // Forwards any exceptional from internal objects such as writer. - fn Write(mut self, record: []str)! { - if !validDelim(self.Comma) { - error(CsvError.InvalidDelim) - } - for (n, mut field) in record { - if n > 0 { - mut bytes := make([]byte, utf8::UTFMax) - j := utf8::EncodeRune(bytes, self.Comma) - self.w.Write(bytes[:j]) else { error(error) } - } + // Writes a single CSV record along with any necessary quoting. + // A record is a slice of strings with each string being one field. + // Forwards any exceptional from internal objects such as writer. + fn Write(mut self, record: []str)! { + if !validDelim(self.Comma) { + error(CsvError.InvalidDelim) + } + for (n, mut field) in record { + if n > 0 { + mut bytes := make([]byte, utf8::UTFMax) + j := utf8::EncodeRune(bytes, self.Comma) + self.w.Write(bytes[:j]) else { error(error) } + } - // Use fb instead of field to avoid copying. - mut fb := unsafe::StrBytes(field) + // Use fb instead of field to avoid copying. + mut fb := unsafe::StrBytes(field) - // If we don't have to have a quoted field then just - // write out the field and continue to the next field. - if !self.fieldNeedsQuotes(fb) { - self.w.Write(fb) else { error(error) } - continue - } + // If we don't have to have a quoted field then just + // write out the field and continue to the next field. + if !self.fieldNeedsQuotes(fb) { + self.w.Write(fb) else { error(error) } + continue + } - self.w.Write(['"']) else { error(error) } + self.w.Write(['"']) else { error(error) } - for len(fb) > 0 { - // Search for special characters. - mut i := bytes::FindAny(fb, unsafe::StrBytes("\"\r\n")) - if i < 0 { - i = len(fb) - } + for len(fb) > 0 { + // Search for special characters. + mut i := bytes::FindAny(fb, unsafe::StrBytes("\"\r\n")) + if i < 0 { + i = len(fb) + } - // Copy verbatim everything before the special character. - self.w.Write(fb[:i]) else { error(error) } - fb = fb[i:] + // Copy verbatim everything before the special character. + self.w.Write(fb[:i]) else { error(error) } + fb = fb[i:] - // Encode the special character. - if len(fb) > 0 { - match fb[0] { - | '"': - self.w.Write(unsafe::StrBytes(`""`)) else { error(error) } - | '\r': - if !self.UseCrlf { - self.w.Write(['\r']) else { error(error) } - } - | '\n': - if self.UseCrlf { - self.w.Write(unsafe::StrBytes("\r\n")) else { error(error) } - } else { - self.w.Write(unsafe::StrBytes("\n")) else { error(error) } - } - } - fb = fb[1:] - } - } + // Encode the special character. + if len(fb) > 0 { + match fb[0] { + | '"': + self.w.Write(unsafe::StrBytes(`""`)) else { error(error) } + | '\r': + if !self.UseCrlf { + self.w.Write(['\r']) else { error(error) } + } + | '\n': + if self.UseCrlf { + self.w.Write(unsafe::StrBytes("\r\n")) else { error(error) } + } else { + self.w.Write(unsafe::StrBytes("\n")) else { error(error) } + } + } + fb = fb[1:] + } + } - self.w.Write(unsafe::StrBytes("\"")) else { error(error) } - } - if self.UseCrlf { - self.w.Write(unsafe::StrBytes("\r\n")) else { error(error) } - } else { - self.w.Write(unsafe::StrBytes("\n")) else { error(error) } - } - } + self.w.Write(unsafe::StrBytes("\"")) else { error(error) } + } + if self.UseCrlf { + self.w.Write(unsafe::StrBytes("\r\n")) else { error(error) } + } else { + self.w.Write(unsafe::StrBytes("\n")) else { error(error) } + } + } - // Writes multiple CSV records using [Writer.Write] and - // forwording any exception. - fn WriteAll(mut self, records: [][]str)! { - for _, record in records { - self.Write(record) else { error(error) } - } - } + // Writes multiple CSV records using [Writer.Write] and + // forwording any exception. + fn WriteAll(mut self, records: [][]str)! { + for _, record in records { + self.Write(record) else { error(error) } + } + } } \ No newline at end of file diff --git a/std/encoding/json/buffer.jule b/std/encoding/json/buffer.jule index 5a390359a..9847af861 100644 --- a/std/encoding/json/buffer.jule +++ b/std/encoding/json/buffer.jule @@ -7,98 +7,98 @@ const smallBufferSize = 1 << 6 // Buffer implementation for encoding algorithms. struct buffer { - buf: []byte // contents are the bytes buf[off : len(buf)] - off: int // read at &buf[off], write at &buf[len(buf)] + buf: []byte // contents are the bytes buf[off : len(buf)] + off: int // read at &buf[off], write at &buf[len(buf)] } impl buffer { - // Returns the number of bytes of the unread portion of the buffer; - fn len(self): int { ret len(self.buf) - self.off } + // Returns the number of bytes of the unread portion of the buffer; + fn len(self): int { ret len(self.buf) - self.off } - // Cap returns the capacity of the buffer's underlying byte slice, that is, the - // total space allocated for the buffer's data. - fn cap(self): int { ret cap(self.buf) } + // Cap returns the capacity of the buffer's underlying byte slice, that is, the + // total space allocated for the buffer's data. + fn cap(self): int { ret cap(self.buf) } - // Returns a slice of length self.len() holding the unread portion of the buffer. - // The slice is valid for use only until the next buffer modification (that is, - // only until the next call to a method like [Buffer.Write] or [Buffer.Reset]. - // The slice aliases the buffer content at least until the next buffer modification, - // so immediate changes to the slice will affect the result of future reads. - fn bytes(mut self): []byte { ret self.buf[self.off:] } + // Returns a slice of length self.len() holding the unread portion of the buffer. + // The slice is valid for use only until the next buffer modification (that is, + // only until the next call to a method like [Buffer.Write] or [Buffer.Reset]. + // The slice aliases the buffer content at least until the next buffer modification, + // so immediate changes to the slice will affect the result of future reads. + fn bytes(mut self): []byte { ret self.buf[self.off:] } - // Resets the buffer to be empty, but it retains - // the underlying storage for use by future writes. - fn reset(mut self) { - self.buf = self.buf[:0] - self.off = 0 - } + // Resets the buffer to be empty, but it retains + // the underlying storage for use by future writes. + fn reset(mut self) { + self.buf = self.buf[:0] + self.off = 0 + } - // Grows the buffer to guarantee space for n more bytes. - // It returns the index where bytes should be written. - // If the buffer can't grow it will panic. - fn grow(mut self, n: int): int { - m := self.len() - // Try to grow by means of a reslice. - if n <= cap(self.buf)-m { - self.buf = self.buf[:m+n] - ret m - } - // If buffer is empty, reset to recover space. - if m == 0 && self.off != 0 { - self.reset() - } - if self.buf == nil && n <= smallBufferSize { - self.buf = make([]byte, n, smallBufferSize) - ret 0 - } - c := cap(self.buf) - if n <= c/2-m { - // We can slide things down instead of allocating a new - // slice. We only need m+n <= c to slide, but - // we instead let capacity get twice as large so we - // don't spend all our time copying. - copy(self.buf, self.buf[self.off:]) - } else if c > int.Max-c-n { - panic("buffer too large") - } else { - // Add self.off to account for self.buf[:self.off] being sliced off the front. - self.buf = growSlice(self.buf[self.off:], self.off + n) - } - // Restore self.off and len(self.buf). - self.off = 0 - self.buf = self.buf[:m+n] - ret m - } + // Grows the buffer to guarantee space for n more bytes. + // It returns the index where bytes should be written. + // If the buffer can't grow it will panic. + fn grow(mut self, n: int): int { + m := self.len() + // Try to grow by means of a reslice. + if n <= cap(self.buf)-m { + self.buf = self.buf[:m+n] + ret m + } + // If buffer is empty, reset to recover space. + if m == 0 && self.off != 0 { + self.reset() + } + if self.buf == nil && n <= smallBufferSize { + self.buf = make([]byte, n, smallBufferSize) + ret 0 + } + c := cap(self.buf) + if n <= c/2-m { + // We can slide things down instead of allocating a new + // slice. We only need m+n <= c to slide, but + // we instead let capacity get twice as large so we + // don't spend all our time copying. + copy(self.buf, self.buf[self.off:]) + } else if c > int.Max-c-n { + panic("buffer too large") + } else { + // Add self.off to account for self.buf[:self.off] being sliced off the front. + self.buf = growSlice(self.buf[self.off:], self.off + n) + } + // Restore self.off and len(self.buf). + self.off = 0 + self.buf = self.buf[:m+n] + ret m + } - // Appends the contents of p to the buffer, growing the buffer as - // needed. The return value n is the length of p; err is always nil. If the - // buffer becomes too large, write will panics. - fn write(mut self, p: []byte): int { - m := self.grow(len(p)) - ret copy(self.buf[m:], p) - } + // Appends the contents of p to the buffer, growing the buffer as + // needed. The return value n is the length of p; err is always nil. If the + // buffer becomes too large, write will panics. + fn write(mut self, p: []byte): int { + m := self.grow(len(p)) + ret copy(self.buf[m:], p) + } - // Same as write, but for strings. - fn writeStr(mut self, s: str): int { - m := self.grow(len(s)) - ret copy(self.buf[m:], s) - } + // Same as write, but for strings. + fn writeStr(mut self, s: str): int { + m := self.grow(len(s)) + ret copy(self.buf[m:], s) + } - // Appends the byte c to the buffer, growing the buffer as needed. - // If the buffer becomes too large, writeByte will panics. - fn writeByte(mut self, c: byte) { - m := self.grow(1) - self.buf[m] = c - } + // Appends the byte c to the buffer, growing the buffer as needed. + // If the buffer becomes too large, writeByte will panics. + fn writeByte(mut self, c: byte) { + m := self.grow(1) + self.buf[m] = c + } } // Grows b by n, preserving the original content of b. fn growSlice(b: []byte, n: int): []byte { - mut c := len(b) + n - if c < cap(b)<<1 { - c = cap(b) << 1 - } - mut b2 := make([]byte, len(b), c) - copy(b2, b) - ret b2 + mut c := len(b) + n + if c < cap(b)<<1 { + c = cap(b) << 1 + } + mut b2 := make([]byte, len(b), c) + copy(b2, b) + ret b2 } \ No newline at end of file diff --git a/std/encoding/json/decode.jule b/std/encoding/json/decode.jule index 87c0b6413..f7f4f26de 100644 --- a/std/encoding/json/decode.jule +++ b/std/encoding/json/decode.jule @@ -19,512 +19,512 @@ const maxNestingDepth = 10000 // being scanned. If the parser is inside a nested value // the parseState describes the nested state, outermost at entry 0. enum parseState { - Object, // parsing object key (before colon) - Array, // parsing array value + Object, // parsing object key (before colon) + Array, // parsing array value } struct jsonDecoder { - data: []byte - mut i: int // Read offset for data. + data: []byte + mut i: int // Read offset for data. - // Stack of what we're in the middle of - array values, object keys, object values. - mut parseState: []parseState + // Stack of what we're in the middle of - array values, object keys, object values. + mut parseState: []parseState } impl jsonDecoder { - fn eof(self): bool { - ret self.i >= len(self.data) - } - - fn skipSpace(self) { - for !self.eof() && isSpace(self.data[self.i]); self.i++ {} - } - - // Scans to the end of what was started. - // Checks syntax errors. - fn skip(self)! { - mut b := self.data[self.i] - if b != '[' && b != '{' { // Literal. - self.scanValidLit() else { error(error) } - ret - } - depth := len(self.parseState) - mut colon := false - for !self.eof() { - b = self.data[self.i] - if isSpace(b) { - self.skipSpace() - continue - } - match b { - | '{': - self.i++ - self.pushParseState(parseState.Object) else { error(error) } - | '[': - self.pushParseState(parseState.Array) else { error(error) } - self.i++ - | '}': - if colon || self.parseState[len(self.parseState)-1] != parseState.Object { - error(JSONDecodeError.InvalidValue) - } - self.popParseState() - self.i++ - if depth >= len(self.parseState) { - ret - } - | ']': - if colon || self.parseState[len(self.parseState)-1] != parseState.Array { - error(JSONDecodeError.InvalidToken) - } - self.popParseState() - self.i++ - if depth >= len(self.parseState) { - ret - } - | ':': - if colon { - error(JSONDecodeError.InvalidToken) - } - if self.parseState[len(self.parseState)-1] != parseState.Object { - error(JSONDecodeError.InvalidToken) - } - if len(self.data)-self.i <= 1 || self.data[self.i-1] != '"' { - error(JSONDecodeError.InvalidToken) - } - self.i++ - colon = true - continue - | ',': - if colon { - error(JSONDecodeError.InvalidToken) - } - self.i++ - self.skipSpace() - if self.parseState[len(self.parseState)-1] == parseState.Object { - if self.eof() || self.data[self.i] != '"' { - error(JSONDecodeError.InvalidToken) - } - self.scanValidLit() else { error(error) } - self.skipSpace() - if self.eof() || self.data[self.i] != ':' { - error(JSONDecodeError.InvalidToken) - } - self.i++ - colon = true - continue - } - if self.eof() { - error(JSONDecodeError.InvalidToken) - } - b = self.data[self.i] - if b == ',' || b == ':' || b == '}' || b == ']' { - error(JSONDecodeError.InvalidToken) - } - | '-' | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' - | '"' | 't' | 'f' | 'n': - self.scanValidLit() else { error(error) } - |: - error(JSONDecodeError.InvalidValue) - } - colon = false - } - error(JSONDecodeError.InvalidValue) - } - - // Calls the [scanLit] and checks it with the [isValidLit] function. - fn scanValidLit(self)!: []byte { - mut lit := self.scanLit() else { error(error) } - if !isValidLit(lit) { - error(JSONDecodeError.InvalidValue) - } - ret lit - } - - // Scans inputs quicky, not checks validity. - // Only checks for length. - fn scanLit(self)!: []byte { - i := self.i - Match: - match self.data[self.i] { - | '"': // string - self.i++ - for !self.eof(); self.i++ { - match self.data[self.i] { - | '\\': - self.i++ - | '"': - self.i++ // tokenize the closing quote too - break Match - } - } - | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '-': // number - self.i++ - for !self.eof(); self.i++ { - match self.data[self.i] { - | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' - | '.' | 'e' | 'E' | '+' | '-': - continue - |: - break Match - } - } - | 't': // true - self.i += len("true") - | 'f': // false - self.i += len("false") - | 'n': // null - self.i += len("null") - |: - error(JSONDecodeError.InvalidToken) - } - if self.i > len(self.data) { - error(JSONDecodeError.InvalidValue) - } - // Keep immutability, it will not be mutated. - ret unsafe { (*(&self.data))[i:self.i] } - } - - // Pushes a new parse state p onto the parse stack. - // Throws exceptional if maxNestingDepth was exceeded. - fn pushParseState(self, newParseState: parseState)! { - self.parseState = append(self.parseState, newParseState) - if len(self.parseState) > maxNestingDepth { - error(JSONDecodeError.ExceededMaxDepth) - } - } - - // Pops a parse state (already obtained) off the stack - // and updates self.step accordingly. - fn popParseState(self) { - self.parseState = self.parseState[:len(self.parseState)-1] - } - - fn array[T](self, mut &a: T)! { - const t = comptime::TypeOf(T) - comptime::TypeAlias(elem, t.Elem()) - self.i++ - self.skipSpace() - if !self.eof() && self.data[self.i] == ']' { - self.i++ - ret - } - const match t.Kind() { - | comptime::Kind.Slice: - a = a[:0] // Keep capacity, but clear current elements. - } - self.pushParseState(parseState.Array) else { error(error) } - mut i := 0 - for { - // Look ahead for ] - can only happen on first iteration. - self.skipSpace() - if self.eof() { - error(JSONDecodeError.InvalidValue) - } - const match t.Kind() { - | comptime::Kind.Array: - if i >= len(a) { - // Ran out of fixed array. - error(JSONDecodeError.InvalidValue) - } - self.value(a[i]) else { error(error) } - | comptime::Kind.Slice: - let mut v: elem - self.value(v) else { error(error) } - a = append(a, v) - |: - panic("std::encoding::json: unimplemented type, this panic call should be unreachable") - } - i++ - self.skipSpace() - if self.eof() { - error(JSONDecodeError.InvalidValue) - } - // Next token must be , or ]. - b := self.data[self.i] - if b == ',' { - self.i++ - continue - } - if b == ']' { - self.i++ - break - } - panic("std::encoding::json: implementation mistake, this panic call should be unreachable") - } - self.popParseState() - if i < len(a) { - const match t.Kind() { - | comptime::Kind.Array: - // Assign to default value of array's zero remainder. - let mut default: elem - for i < len(a); i++ { - a[i] = default - } - | comptime::Kind.Slice: - // Truncate the slice. - a = a[:i] - |: - panic("std::encoding::json: unimplemented type, this panic call should be unreachable") - } - } - } - - fn objectMap[Map: map[K]V, K, V](self, mut &m: Map)! { - const keyT = comptime::TypeOf(K) - const match type K { - | str | int | i8 | i16 | i32 | i64 | uint | uintptr | u8 | u16 | u32 | u64: - break - |: - error(JSONEncodeError.UnsupportedType) - } - self.i++ - if !self.eof() && self.data[self.i] == '}' { - self.i++ - ret - } - self.pushParseState(parseState.Object) else { error(error) } - const quoted = keyT.Kind() == comptime::Kind.Str - for { - self.skipSpace() - if self.eof() || self.data[self.i] != '"' { - error(JSONDecodeError.InvalidToken) - } - // Don't check validity for literal, following algorithms will check it. - lit := self.scanLit() else { error(error) } - self.skipSpace() - if self.eof() || self.data[self.i] != ':' { - error(JSONDecodeError.InvalidToken) - } - self.i++ - self.skipSpace() - if self.eof() { - error(JSONDecodeError.InvalidValue) - } - let mut value: V - self.value(value) else { error(error) } - const match { - | quoted: - // String type, assign directly to the key. - // Use [self.decodeStr] method to efficient string handling. - mut s := "" - decodeString(s, lit) else { error(error) } - m[s] = value - |: - // Quoted non-string type, parse unqoted value by type to assign. - key := unquoteBytes(lit) - if key == nil { - panic("std::encoding::json: implementation mistake, this panic call should be unreachable") - } - let mut keyV: K - const match type K { - | int | i8 | i16 | i32 | i64: - decodeInt(keyV, key) else { error(error) } - | uint | uintptr | u8 | u16 | u32 | u64: - decodeUint(keyV, key) else { error(error) } - |: - panic("std::encoding::json: unimplemented type, this panic call should be unreachable") - } - m[keyV] = value - } - self.skipSpace() - if self.eof() { - error(JSONDecodeError.InvalidValue) - } - b := self.data[self.i] - if b == ',' { - self.i++ - continue - } - if b == '}' { - self.i++ - break - } - panic("std::encoding::json: implementation mistake, this panic call should be unreachable") - } - self.popParseState() - } - - fn objectStruct[T](self, mut &t: T)! { - self.i++ - self.skipSpace() - if !self.eof() && self.data[self.i] == '}' { - self.i++ - ret - } - self.pushParseState(parseState.Object) else { error(error) } - for { - self.skipSpace() - if self.eof() || self.data[self.i] != '"' { - error(JSONDecodeError.InvalidToken) - } - // Don't check validity for literal, following algorithms will check it. - lit := self.scanLit() else { error(error) } - self.skipSpace() - if self.eof() || self.data[self.i] != ':' { - error(JSONDecodeError.InvalidToken) - } - self.i++ - self.skipSpace() - if self.eof() { - error(JSONDecodeError.InvalidValue) - } - key := unquoteBytes(lit) - if key == nil { - error(JSONDecodeError.InvalidValue) - } - keyS := unsafe::BytesStr(key) - // To avoid unused error. - // Empty or no-public field structure may cause compile error(s). - _ = keyS - const tt = comptime::TypeOf(T) - const vt = comptime::ValueOf(t) - const fields = tt.Fields() - const for _, field in fields { - const match { - | field.Public(): - if keyS == field.Name() { - const fieldV = vt.Field(field.Name()) - self.value(fieldV.Unwrap()) else { error(error) } - // Skip undecoded field handling and trailing if blocks if exist. - goto fieldDecoded - } - } - } - // Skip JSON object field if is not decoded for struct. - self.skip() else { error(error) } - // To avoid unused error. - // Empty or no-public field structure may cause compile error(s). - goto fieldDecoded - fieldDecoded: - self.skipSpace() - if self.eof() { - error(JSONDecodeError.InvalidValue) - } - b := self.data[self.i] - if b == ',' { - self.i++ - continue - } - if b == '}' { - self.i++ - break - } - error(JSONDecodeError.InvalidValue) - } - self.popParseState() - } - - fn value1[T](self, mut &t: T)! { - const tt = comptime::TypeOf(T) - b := self.data[self.i] - match b { - | '{': // Object. - const match tt.Kind() { - | comptime::Kind.Map: - self.objectMap(t) else { error(error) } - ret - | comptime::Kind.Struct: - self.objectStruct(t) else { error(error) } - ret - |: - error(JSONDecodeError.InvalidValue) - } - | '[': // Array. - const match tt.Kind() { - | comptime::Kind.Array - | comptime::Kind.Slice: - self.array(t) else { error(error) } - ret - |: - error(JSONDecodeError.InvalidValue) - } - | '"': // String literal. - const match type T { - | str: - // Don't check validity for literal, following algorithms will check it. - lit := self.scanLit() else { error(error) } - decodeString(t, lit) else { error(error) } - ret - | []byte: - lit := self.scanLit() else { error(error) } - mut s2 := unquoteBytes(lit) - if s2 == nil { - error(JSONDecodeError.InvalidValue) - } - t = base64::Decode(s2) - ret - |: - error(JSONDecodeError.InvalidValue) - } - | 'n': // Null literal. - self.scanValidLit() else { error(error) } - const match { - | tt.CanNil(): - t = nil - ret - |: - error(JSONDecodeError.InvalidValue) - } - | 't' | 'f': // Boolean literal. - self.scanValidLit() else { error(error) } - const match type T { - | bool: - t = b == 't' - ret - |: - error(JSONDecodeError.InvalidValue) - } - } - if b == '-' || b == '0' || '1' <= b && b <= '9' { - // Don't check validity for literal, following algorithms will check it. - lit := self.scanLit() else { error(error) } - _ = lit // Avoid unused error. - const match type T { - | int | i8 | i16 | i32 | i64: - decodeInt(t, lit) else { error(error) } - ret - | uint | uintptr | u8 | u16 | u32 | u64: - decodeUInt(t, lit) else { error(error) } - ret - | f32 | f64: - decodeFloat(t, lit) else { error(error) } - ret - |: - error(JSONDecodeError.InvalidValue) - } - } - error(JSONDecodeError.MissingBeginningOfValue) - } - - fn value[T](self, mut &t: T)! { - const tt = comptime::TypeOf(T) - const match tt.Kind() { - | comptime::Kind.SmartPtr: - b := self.data[self.i] - if b == 'n' { // Null literal. - self.scanValidLit() else { error(error) } - t = nil - ret - } - if t == nil { - comptime::TypeAlias(elem, tt.Elem()) - t = new(elem) - } - self.value1(*t) else { error(error) } - |: - self.value1(t) else { error(error) } - } - } - - fn decode[T](self, mut &t: T)! { - self.skipSpace() - if !self.eof() { - self.value(t) else { error(error) } - } - if len(self.data)-self.i > 0 { - error(JSONDecodeError.UnexpectedEnd) - } - } + fn eof(self): bool { + ret self.i >= len(self.data) + } + + fn skipSpace(self) { + for !self.eof() && isSpace(self.data[self.i]); self.i++ {} + } + + // Scans to the end of what was started. + // Checks syntax errors. + fn skip(self)! { + mut b := self.data[self.i] + if b != '[' && b != '{' { // Literal. + self.scanValidLit() else { error(error) } + ret + } + depth := len(self.parseState) + mut colon := false + for !self.eof() { + b = self.data[self.i] + if isSpace(b) { + self.skipSpace() + continue + } + match b { + | '{': + self.i++ + self.pushParseState(parseState.Object) else { error(error) } + | '[': + self.pushParseState(parseState.Array) else { error(error) } + self.i++ + | '}': + if colon || self.parseState[len(self.parseState)-1] != parseState.Object { + error(JSONDecodeError.InvalidValue) + } + self.popParseState() + self.i++ + if depth >= len(self.parseState) { + ret + } + | ']': + if colon || self.parseState[len(self.parseState)-1] != parseState.Array { + error(JSONDecodeError.InvalidToken) + } + self.popParseState() + self.i++ + if depth >= len(self.parseState) { + ret + } + | ':': + if colon { + error(JSONDecodeError.InvalidToken) + } + if self.parseState[len(self.parseState)-1] != parseState.Object { + error(JSONDecodeError.InvalidToken) + } + if len(self.data)-self.i <= 1 || self.data[self.i-1] != '"' { + error(JSONDecodeError.InvalidToken) + } + self.i++ + colon = true + continue + | ',': + if colon { + error(JSONDecodeError.InvalidToken) + } + self.i++ + self.skipSpace() + if self.parseState[len(self.parseState)-1] == parseState.Object { + if self.eof() || self.data[self.i] != '"' { + error(JSONDecodeError.InvalidToken) + } + self.scanValidLit() else { error(error) } + self.skipSpace() + if self.eof() || self.data[self.i] != ':' { + error(JSONDecodeError.InvalidToken) + } + self.i++ + colon = true + continue + } + if self.eof() { + error(JSONDecodeError.InvalidToken) + } + b = self.data[self.i] + if b == ',' || b == ':' || b == '}' || b == ']' { + error(JSONDecodeError.InvalidToken) + } + | '-' | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' + | '"' | 't' | 'f' | 'n': + self.scanValidLit() else { error(error) } + |: + error(JSONDecodeError.InvalidValue) + } + colon = false + } + error(JSONDecodeError.InvalidValue) + } + + // Calls the [scanLit] and checks it with the [isValidLit] function. + fn scanValidLit(self)!: []byte { + mut lit := self.scanLit() else { error(error) } + if !isValidLit(lit) { + error(JSONDecodeError.InvalidValue) + } + ret lit + } + + // Scans inputs quicky, not checks validity. + // Only checks for length. + fn scanLit(self)!: []byte { + i := self.i + Match: + match self.data[self.i] { + | '"': // string + self.i++ + for !self.eof(); self.i++ { + match self.data[self.i] { + | '\\': + self.i++ + | '"': + self.i++ // tokenize the closing quote too + break Match + } + } + | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '-': // number + self.i++ + for !self.eof(); self.i++ { + match self.data[self.i] { + | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' + | '.' | 'e' | 'E' | '+' | '-': + continue + |: + break Match + } + } + | 't': // true + self.i += len("true") + | 'f': // false + self.i += len("false") + | 'n': // null + self.i += len("null") + |: + error(JSONDecodeError.InvalidToken) + } + if self.i > len(self.data) { + error(JSONDecodeError.InvalidValue) + } + // Keep immutability, it will not be mutated. + ret unsafe { (*(&self.data))[i:self.i] } + } + + // Pushes a new parse state p onto the parse stack. + // Throws exceptional if maxNestingDepth was exceeded. + fn pushParseState(self, newParseState: parseState)! { + self.parseState = append(self.parseState, newParseState) + if len(self.parseState) > maxNestingDepth { + error(JSONDecodeError.ExceededMaxDepth) + } + } + + // Pops a parse state (already obtained) off the stack + // and updates self.step accordingly. + fn popParseState(self) { + self.parseState = self.parseState[:len(self.parseState)-1] + } + + fn array[T](self, mut &a: T)! { + const t = comptime::TypeOf(T) + comptime::TypeAlias(elem, t.Elem()) + self.i++ + self.skipSpace() + if !self.eof() && self.data[self.i] == ']' { + self.i++ + ret + } + const match t.Kind() { + | comptime::Kind.Slice: + a = a[:0] // Keep capacity, but clear current elements. + } + self.pushParseState(parseState.Array) else { error(error) } + mut i := 0 + for { + // Look ahead for ] - can only happen on first iteration. + self.skipSpace() + if self.eof() { + error(JSONDecodeError.InvalidValue) + } + const match t.Kind() { + | comptime::Kind.Array: + if i >= len(a) { + // Ran out of fixed array. + error(JSONDecodeError.InvalidValue) + } + self.value(a[i]) else { error(error) } + | comptime::Kind.Slice: + let mut v: elem + self.value(v) else { error(error) } + a = append(a, v) + |: + panic("std::encoding::json: unimplemented type, this panic call should be unreachable") + } + i++ + self.skipSpace() + if self.eof() { + error(JSONDecodeError.InvalidValue) + } + // Next token must be , or ]. + b := self.data[self.i] + if b == ',' { + self.i++ + continue + } + if b == ']' { + self.i++ + break + } + panic("std::encoding::json: implementation mistake, this panic call should be unreachable") + } + self.popParseState() + if i < len(a) { + const match t.Kind() { + | comptime::Kind.Array: + // Assign to default value of array's zero remainder. + let mut default: elem + for i < len(a); i++ { + a[i] = default + } + | comptime::Kind.Slice: + // Truncate the slice. + a = a[:i] + |: + panic("std::encoding::json: unimplemented type, this panic call should be unreachable") + } + } + } + + fn objectMap[Map: map[K]V, K, V](self, mut &m: Map)! { + const keyT = comptime::TypeOf(K) + const match type K { + | str | int | i8 | i16 | i32 | i64 | uint | uintptr | u8 | u16 | u32 | u64: + break + |: + error(JSONEncodeError.UnsupportedType) + } + self.i++ + if !self.eof() && self.data[self.i] == '}' { + self.i++ + ret + } + self.pushParseState(parseState.Object) else { error(error) } + const quoted = keyT.Kind() == comptime::Kind.Str + for { + self.skipSpace() + if self.eof() || self.data[self.i] != '"' { + error(JSONDecodeError.InvalidToken) + } + // Don't check validity for literal, following algorithms will check it. + lit := self.scanLit() else { error(error) } + self.skipSpace() + if self.eof() || self.data[self.i] != ':' { + error(JSONDecodeError.InvalidToken) + } + self.i++ + self.skipSpace() + if self.eof() { + error(JSONDecodeError.InvalidValue) + } + let mut value: V + self.value(value) else { error(error) } + const match { + | quoted: + // String type, assign directly to the key. + // Use [self.decodeStr] method to efficient string handling. + mut s := "" + decodeString(s, lit) else { error(error) } + m[s] = value + |: + // Quoted non-string type, parse unqoted value by type to assign. + key := unquoteBytes(lit) + if key == nil { + panic("std::encoding::json: implementation mistake, this panic call should be unreachable") + } + let mut keyV: K + const match type K { + | int | i8 | i16 | i32 | i64: + decodeInt(keyV, key) else { error(error) } + | uint | uintptr | u8 | u16 | u32 | u64: + decodeUint(keyV, key) else { error(error) } + |: + panic("std::encoding::json: unimplemented type, this panic call should be unreachable") + } + m[keyV] = value + } + self.skipSpace() + if self.eof() { + error(JSONDecodeError.InvalidValue) + } + b := self.data[self.i] + if b == ',' { + self.i++ + continue + } + if b == '}' { + self.i++ + break + } + panic("std::encoding::json: implementation mistake, this panic call should be unreachable") + } + self.popParseState() + } + + fn objectStruct[T](self, mut &t: T)! { + self.i++ + self.skipSpace() + if !self.eof() && self.data[self.i] == '}' { + self.i++ + ret + } + self.pushParseState(parseState.Object) else { error(error) } + for { + self.skipSpace() + if self.eof() || self.data[self.i] != '"' { + error(JSONDecodeError.InvalidToken) + } + // Don't check validity for literal, following algorithms will check it. + lit := self.scanLit() else { error(error) } + self.skipSpace() + if self.eof() || self.data[self.i] != ':' { + error(JSONDecodeError.InvalidToken) + } + self.i++ + self.skipSpace() + if self.eof() { + error(JSONDecodeError.InvalidValue) + } + key := unquoteBytes(lit) + if key == nil { + error(JSONDecodeError.InvalidValue) + } + keyS := unsafe::BytesStr(key) + // To avoid unused error. + // Empty or no-public field structure may cause compile error(s). + _ = keyS + const tt = comptime::TypeOf(T) + const vt = comptime::ValueOf(t) + const fields = tt.Fields() + const for _, field in fields { + const match { + | field.Public(): + if keyS == field.Name() { + const fieldV = vt.Field(field.Name()) + self.value(fieldV.Unwrap()) else { error(error) } + // Skip undecoded field handling and trailing if blocks if exist. + goto fieldDecoded + } + } + } + // Skip JSON object field if is not decoded for struct. + self.skip() else { error(error) } + // To avoid unused error. + // Empty or no-public field structure may cause compile error(s). + goto fieldDecoded + fieldDecoded: + self.skipSpace() + if self.eof() { + error(JSONDecodeError.InvalidValue) + } + b := self.data[self.i] + if b == ',' { + self.i++ + continue + } + if b == '}' { + self.i++ + break + } + error(JSONDecodeError.InvalidValue) + } + self.popParseState() + } + + fn value1[T](self, mut &t: T)! { + const tt = comptime::TypeOf(T) + b := self.data[self.i] + match b { + | '{': // Object. + const match tt.Kind() { + | comptime::Kind.Map: + self.objectMap(t) else { error(error) } + ret + | comptime::Kind.Struct: + self.objectStruct(t) else { error(error) } + ret + |: + error(JSONDecodeError.InvalidValue) + } + | '[': // Array. + const match tt.Kind() { + | comptime::Kind.Array + | comptime::Kind.Slice: + self.array(t) else { error(error) } + ret + |: + error(JSONDecodeError.InvalidValue) + } + | '"': // String literal. + const match type T { + | str: + // Don't check validity for literal, following algorithms will check it. + lit := self.scanLit() else { error(error) } + decodeString(t, lit) else { error(error) } + ret + | []byte: + lit := self.scanLit() else { error(error) } + mut s2 := unquoteBytes(lit) + if s2 == nil { + error(JSONDecodeError.InvalidValue) + } + t = base64::Decode(s2) + ret + |: + error(JSONDecodeError.InvalidValue) + } + | 'n': // Null literal. + self.scanValidLit() else { error(error) } + const match { + | tt.CanNil(): + t = nil + ret + |: + error(JSONDecodeError.InvalidValue) + } + | 't' | 'f': // Boolean literal. + self.scanValidLit() else { error(error) } + const match type T { + | bool: + t = b == 't' + ret + |: + error(JSONDecodeError.InvalidValue) + } + } + if b == '-' || b == '0' || '1' <= b && b <= '9' { + // Don't check validity for literal, following algorithms will check it. + lit := self.scanLit() else { error(error) } + _ = lit // Avoid unused error. + const match type T { + | int | i8 | i16 | i32 | i64: + decodeInt(t, lit) else { error(error) } + ret + | uint | uintptr | u8 | u16 | u32 | u64: + decodeUInt(t, lit) else { error(error) } + ret + | f32 | f64: + decodeFloat(t, lit) else { error(error) } + ret + |: + error(JSONDecodeError.InvalidValue) + } + } + error(JSONDecodeError.MissingBeginningOfValue) + } + + fn value[T](self, mut &t: T)! { + const tt = comptime::TypeOf(T) + const match tt.Kind() { + | comptime::Kind.SmartPtr: + b := self.data[self.i] + if b == 'n' { // Null literal. + self.scanValidLit() else { error(error) } + t = nil + ret + } + if t == nil { + comptime::TypeAlias(elem, tt.Elem()) + t = new(elem) + } + self.value1(*t) else { error(error) } + |: + self.value1(t) else { error(error) } + } + } + + fn decode[T](self, mut &t: T)! { + self.skipSpace() + if !self.eof() { + self.value(t) else { error(error) } + } + if len(self.data)-self.i > 0 { + error(JSONDecodeError.UnexpectedEnd) + } + } } // Implements decoding of JSON as defined in RFC 7159. @@ -580,204 +580,204 @@ impl jsonDecoder { // it is recommended that a data type can carry a maximum of 10000 nested data. // However, tousands of nested-data is always risky even below 10000. fn Decode[T](data: []byte, mut &t: T)! { - decoder := jsonDecoder{ - data: data, - i: 0, - } - decoder.decode(t) else { error(error) } + decoder := jsonDecoder{ + data: data, + i: 0, + } + decoder.decode(t) else { error(error) } } fn isSpace(c: byte): bool { - ret c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n') + ret c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n') } // getu4 decodes \uXXXX from the beginning of s, returning the hex value, // or it returns -1. fn getu4(s: []byte): rune { - if len(s) < 6 || s[0] != '\\' || s[1] != 'u' { - ret -1 - } - mut r := rune(0) - for (_, mut c) in s[2:6] { - match { - | '0' <= c && c <= '9': - c = c - '0' - | 'a' <= c && c <= 'f': - c = c - 'a' + 10 - | 'A' <= c && c <= 'F': - c = c - 'A' + 10 - |: - ret -1 - } - r <<= 4 - r += rune(c) - } - ret r + if len(s) < 6 || s[0] != '\\' || s[1] != 'u' { + ret -1 + } + mut r := rune(0) + for (_, mut c) in s[2:6] { + match { + | '0' <= c && c <= '9': + c = c - '0' + | 'a' <= c && c <= 'f': + c = c - 'a' + 10 + | 'A' <= c && c <= 'F': + c = c - 'A' + 10 + |: + ret -1 + } + r <<= 4 + r += rune(c) + } + ret r } // Returns nil if failed. fn unquoteBytes(s: []byte): (t: []byte) { - if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' { - ret - } - unsafe { *(&s) = (*(&s))[1:len(s)-1] } - - // Check for unusual characters. If there are none, - // then no unquoting is needed, so return a slice of the - // original bytes. - mut r := 0 - for r < len(s) { - c := s[r] - if c == '\\' || c == '"' || c < ' ' { - break - } - if c < utf8::RuneSelf { - r++ - continue - } - rr, size := utf8::DecodeRune(s[r:]) - if rr == utf8::RuneError && size == 1 { - break - } - r += size - } - if r == len(s) { - ret unsafe { *(&s) } - } - - mut b := make([]byte, len(s) + utf8::UTFMax << 1) - mut w := copy(b, s[:r]) - for r < len(s) { - // Out of room? Can only happen if s is full of - // malformed UTF-8 and we're replacing each - // byte with RuneError. - if w >= len(b)-utf8::UTFMax<<1 { - mut nb := make([]byte, (len(b) + utf8::UTFMax) << 1) - copy(nb, b[:w]) - b = nb - } - c := s[r] - match { - | c == '\\': - r++ - if r >= len(s) { - ret nil - } - match s[r] { - | '"' | '\\' | '/' | '\'': - b[w] = s[r] - r++ - w++ - | 'b': - b[w] = '\b' - r++ - w++ - | 'f': - b[w] = '\f' - r++ - w++ - | 'n': - b[w] = '\n' - r++ - w++ - | 'r': - b[w] = '\r' - r++ - w++ - | 't': - b[w] = '\t' - r++ - w++ - | 'u': - r-- - mut rr := getu4(s[r:]) - if rr < 0 { - ret nil - } - r += 6 - if utf16::IsSurrogate(rr) { - rr1 := getu4(s[r:]) - dec := utf16::DecodeRune(rr, rr1) - if dec != unicode::ReplacementChar { - // A valid pair; consume. - r += 6 - w += utf8::EncodeRune(b[w:], dec) - break - } - // Invalid surrogate; fall back to replacement rune. - rr = unicode::ReplacementChar - } - w += utf8::EncodeRune(b[w:], rr) - |: - ret nil - } - | c == '"' | c < ' ': - // Quote, control characters are invalid. - ret nil - | c < utf8::RuneSelf: - // ASCII - b[w] = c - r++ - w++ - |: - // Coerce to well-formed UTF-8. - rr, size := utf8::DecodeRune(s[r:]) - r += size - w += utf8::EncodeRune(b[w:], rr) - } - } - ret b[:w] + if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' { + ret + } + unsafe { *(&s) = (*(&s))[1:len(s)-1] } + + // Check for unusual characters. If there are none, + // then no unquoting is needed, so return a slice of the + // original bytes. + mut r := 0 + for r < len(s) { + c := s[r] + if c == '\\' || c == '"' || c < ' ' { + break + } + if c < utf8::RuneSelf { + r++ + continue + } + rr, size := utf8::DecodeRune(s[r:]) + if rr == utf8::RuneError && size == 1 { + break + } + r += size + } + if r == len(s) { + ret unsafe { *(&s) } + } + + mut b := make([]byte, len(s) + utf8::UTFMax << 1) + mut w := copy(b, s[:r]) + for r < len(s) { + // Out of room? Can only happen if s is full of + // malformed UTF-8 and we're replacing each + // byte with RuneError. + if w >= len(b)-utf8::UTFMax<<1 { + mut nb := make([]byte, (len(b) + utf8::UTFMax) << 1) + copy(nb, b[:w]) + b = nb + } + c := s[r] + match { + | c == '\\': + r++ + if r >= len(s) { + ret nil + } + match s[r] { + | '"' | '\\' | '/' | '\'': + b[w] = s[r] + r++ + w++ + | 'b': + b[w] = '\b' + r++ + w++ + | 'f': + b[w] = '\f' + r++ + w++ + | 'n': + b[w] = '\n' + r++ + w++ + | 'r': + b[w] = '\r' + r++ + w++ + | 't': + b[w] = '\t' + r++ + w++ + | 'u': + r-- + mut rr := getu4(s[r:]) + if rr < 0 { + ret nil + } + r += 6 + if utf16::IsSurrogate(rr) { + rr1 := getu4(s[r:]) + dec := utf16::DecodeRune(rr, rr1) + if dec != unicode::ReplacementChar { + // A valid pair; consume. + r += 6 + w += utf8::EncodeRune(b[w:], dec) + break + } + // Invalid surrogate; fall back to replacement rune. + rr = unicode::ReplacementChar + } + w += utf8::EncodeRune(b[w:], rr) + |: + ret nil + } + | c == '"' | c < ' ': + // Quote, control characters are invalid. + ret nil + | c < utf8::RuneSelf: + // ASCII + b[w] = c + r++ + w++ + |: + // Coerce to well-formed UTF-8. + rr, size := utf8::DecodeRune(s[r:]) + r += size + w += utf8::EncodeRune(b[w:], rr) + } + } + ret b[:w] } fn decodeInt[T](mut &t: T, lit: []byte)! { - // Use [unsafe::ByteStr] instead of casting. - // The byte buffer will not change, so it's safe and efficient. - n := conv::ParseInt(unsafe::BytesStr(lit), 0xA, 1 << 6) else { error(JSONDecodeError.InvalidValue) } - if n < i64(T.Min) || i64(T.Max) < n { - error(JSONDecodeError.InvalidValue) - } - t = (T)(n) + // Use [unsafe::ByteStr] instead of casting. + // The byte buffer will not change, so it's safe and efficient. + n := conv::ParseInt(unsafe::BytesStr(lit), 0xA, 1 << 6) else { error(JSONDecodeError.InvalidValue) } + if n < i64(T.Min) || i64(T.Max) < n { + error(JSONDecodeError.InvalidValue) + } + t = (T)(n) } fn decodeUInt[T](mut &t: T, lit: []byte)! { - // Use [unsafe::ByteStr] instead of casting. - // The byte buffer will not change, so it's safe and efficient. - n := conv::ParseUint(unsafe::BytesStr(lit), 0xA, 1 << 6) else { error(JSONDecodeError.InvalidValue) } - if u64(T.Max) < n { - error(JSONDecodeError.InvalidValue) - } - t = (T)(n) + // Use [unsafe::ByteStr] instead of casting. + // The byte buffer will not change, so it's safe and efficient. + n := conv::ParseUint(unsafe::BytesStr(lit), 0xA, 1 << 6) else { error(JSONDecodeError.InvalidValue) } + if u64(T.Max) < n { + error(JSONDecodeError.InvalidValue) + } + t = (T)(n) } fn decodeFloat[T](mut &t: T, lit: []byte)! { - // Use [unsafe::ByteStr] instead of casting. - // The byte buffer will not change, so it's safe and efficient. - n := conv::ParseFloat(unsafe::BytesStr(lit), 1 << 6) else { error(JSONDecodeError.InvalidValue) } - if f64(T.Max) < n { - error(JSONDecodeError.InvalidValue) - } - t = (T)(n) + // Use [unsafe::ByteStr] instead of casting. + // The byte buffer will not change, so it's safe and efficient. + n := conv::ParseFloat(unsafe::BytesStr(lit), 1 << 6) else { error(JSONDecodeError.InvalidValue) } + if f64(T.Max) < n { + error(JSONDecodeError.InvalidValue) + } + t = (T)(n) } fn decodeString(mut &s: str, lit: []byte)! { - mut s2 := unquoteBytes(lit) - if s2 == nil { - error(JSONDecodeError.InvalidValue) - } - if len(s2) == 0 { - s = "" - ret - } - if &lit[1] == &s2[0] { - // Returned mutable slice from self.data slice. - // We should to cast string to make new allocation. - s = str(s2) - } else { - // Returned slice from new allocation. - // First element always will point to head element of allocation. - // So we can return as string directly without making new allocation. - s = unsafe::StrFromBytes(s2) - } + mut s2 := unquoteBytes(lit) + if s2 == nil { + error(JSONDecodeError.InvalidValue) + } + if len(s2) == 0 { + s = "" + ret + } + if &lit[1] == &s2[0] { + // Returned mutable slice from self.data slice. + // We should to cast string to make new allocation. + s = str(s2) + } else { + // Returned slice from new allocation. + // First element always will point to head element of allocation. + // So we can return as string directly without making new allocation. + s = unsafe::StrFromBytes(s2) + } } // Reports whether the literal b is valid JSON string literal. @@ -785,37 +785,37 @@ fn decodeString(mut &s: str, lit: []byte)! { // See https://tools.ietf.org/html/rfc7159#section-7 // and https://www.json.org/img/string.png fn isValidString(b: []byte): bool { - if len(b) == 1 { - ret false - } - mut i := 1 + if len(b) == 1 { + ret false + } + mut i := 1 For: - for i < len(b); i++ { - match b[i] { - | '\\': - i++ - if i >= len(b) { - ret false - } - match b[i] { - | '"' | '\\' | '/' | '\'' | 'b' | 'f' | 'r' | 't' | 'n': - i++ - | 'u': - mut rr := getu4(b[i-1:]) - if rr < 0 { - ret false - } - i += 5 - |: - ret false - } - | '"': - i++ // Tokenize the closing quote too. - break For - } - } - // Make sure we are at the end. - ret i == len(b) + for i < len(b); i++ { + match b[i] { + | '\\': + i++ + if i >= len(b) { + ret false + } + match b[i] { + | '"' | '\\' | '/' | '\'' | 'b' | 'f' | 'r' | 't' | 'n': + i++ + | 'u': + mut rr := getu4(b[i-1:]) + if rr < 0 { + ret false + } + i += 5 + |: + ret false + } + | '"': + i++ // Tokenize the closing quote too. + break For + } + } + // Make sure we are at the end. + ret i == len(b) } // Reports whether the literal b is valid JSON number literal. @@ -824,76 +824,76 @@ For: // See https://tools.ietf.org/html/rfc7159#section-6 // and https://www.json.org/img/number.png fn isValidNumber(mut b: []byte): bool { - if len(b) == 0 { - ret false - } - - // Optional - - if b[0] == '-' { - b = b[1:] - if len(b) == 0 { - ret false - } - } - - // Digits - match { - | b[0] == '0': - b = b[1:] - | '1' <= b[0] && b[0] <= '9': - b = b[1:] - for len(b) > 0 && '0' <= b[0] && b[0] <= '9' { - b = b[1:] - } - |: - ret false - } - - // . followed by 1 or more digits. - if len(b) >= 2 && b[0] == '.' && '0' <= b[1] && b[1] <= '9' { - b = b[2:] - for len(b) > 0 && '0' <= b[0] && b[0] <= '9' { - b = b[1:] - } - } - - // e or E followed by an optional - or + and - // 1 or more digits. - if len(b) >= 2 && (b[0] == 'e' || b[0] == 'E') { - b = b[1:] - if b[0] == '+' || b[0] == '-' { - b = b[1:] - if len(b) == 0 { - ret false - } - } - for len(b) > 0 && '0' <= b[0] && b[0] <= '9' { - b = b[1:] - } - } - - // Make sure we are at the end. - ret len(b) == 0 + if len(b) == 0 { + ret false + } + + // Optional - + if b[0] == '-' { + b = b[1:] + if len(b) == 0 { + ret false + } + } + + // Digits + match { + | b[0] == '0': + b = b[1:] + | '1' <= b[0] && b[0] <= '9': + b = b[1:] + for len(b) > 0 && '0' <= b[0] && b[0] <= '9' { + b = b[1:] + } + |: + ret false + } + + // . followed by 1 or more digits. + if len(b) >= 2 && b[0] == '.' && '0' <= b[1] && b[1] <= '9' { + b = b[2:] + for len(b) > 0 && '0' <= b[0] && b[0] <= '9' { + b = b[1:] + } + } + + // e or E followed by an optional - or + and + // 1 or more digits. + if len(b) >= 2 && (b[0] == 'e' || b[0] == 'E') { + b = b[1:] + if b[0] == '+' || b[0] == '-' { + b = b[1:] + if len(b) == 0 { + ret false + } + } + for len(b) > 0 && '0' <= b[0] && b[0] <= '9' { + b = b[1:] + } + } + + // Make sure we are at the end. + ret len(b) == 0 } // Reports whether literal b is syntatically and semantically correct. // This function implements the JSON grammar. fn isValidLit(b: []byte): bool { - if len(b) == 0 { - ret false - } - match b[0] { - | 't': - ret len(b) == 4 && b[1] == 'r' && b[2] == 'u' && b[3] == 'e' - | 'f': - ret len(b) == 5 && b[1] == 'a' && b[2] == 'l' && b[3] == 's' && b[4] == 'e' - | 'n': - ret len(b) == 4 && b[1] == 'u' && b[2] == 'l' && b[3] == 'l' - | '"': - ret isValidString(b) - | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '-': - ret isValidNumber(unsafe { *(&b) }) - |: - ret false - } + if len(b) == 0 { + ret false + } + match b[0] { + | 't': + ret len(b) == 4 && b[1] == 'r' && b[2] == 'u' && b[3] == 'e' + | 'f': + ret len(b) == 5 && b[1] == 'a' && b[2] == 'l' && b[3] == 's' && b[4] == 'e' + | 'n': + ret len(b) == 4 && b[1] == 'u' && b[2] == 'l' && b[3] == 'l' + | '"': + ret isValidString(b) + | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '-': + ret isValidNumber(unsafe { *(&b) }) + |: + ret false + } } \ No newline at end of file diff --git a/std/encoding/json/decode_test.jule b/std/encoding/json/decode_test.jule index ad528d14f..f36f3420f 100644 --- a/std/encoding/json/decode_test.jule +++ b/std/encoding/json/decode_test.jule @@ -8,135 +8,135 @@ use std::testing::{T} #test fn testDecodeStr(t: &T) { - for i, case in strCases { - if i == 3 || i == 7 { - // Skip error rune cases. - continue - } - mut s := "" - Decode(case.output, s) else { - t.Errorf("Decode(case.output) failed") - ret - } - if s != case.input { - t.Errorf("expected {} for {}, found {}", case.input, case.output, s) - } - } + for i, case in strCases { + if i == 3 || i == 7 { + // Skip error rune cases. + continue + } + mut s := "" + Decode(case.output, s) else { + t.Errorf("Decode(case.output) failed") + ret + } + if s != case.input { + t.Errorf("expected {} for {}, found {}", case.input, case.output, s) + } + } } #test fn testDecodeMapStrKey(t: &T) { - const json = `{"foo": "foo key","bar": "bar key", "baz": "baz key"}` - let mut m: map[str]str = nil - Decode([]byte(json), m) else { - t.Errorf("Decode({}, map[str]str) failed", json) - ret - } - _, mut ok := m["foo"] - t.Assert(ok, `m["foo"] is not exist`) - _, ok = m["bar"] - t.Assert(ok, `m["bar"] is not exist`) - _, ok := m["baz"] - t.Assert(ok, `m["baz"] is not exist`) + const json = `{"foo": "foo key","bar": "bar key", "baz": "baz key"}` + let mut m: map[str]str = nil + Decode([]byte(json), m) else { + t.Errorf("Decode({}, map[str]str) failed", json) + ret + } + _, mut ok := m["foo"] + t.Assert(ok, `m["foo"] is not exist`) + _, ok = m["bar"] + t.Assert(ok, `m["bar"] is not exist`) + _, ok := m["baz"] + t.Assert(ok, `m["baz"] is not exist`) } #test fn testDecodeMapNumKey(t: &T) { - const json = `{"234": "foo key","49": "bar key", "0": "baz key"}` - let mut m: map[int]str = nil - Decode([]byte(json), m) else { - t.Errorf("Decode({}, map[int]str) failed", json) - ret - } - _, mut ok := m[234] - t.Assert(ok, `m[234] is not exist`) - _, ok = m[49] - t.Assert(ok, `m[49] is not exist`) - _, ok := m[0] - t.Assert(ok, `m[0] is not exist`) + const json = `{"234": "foo key","49": "bar key", "0": "baz key"}` + let mut m: map[int]str = nil + Decode([]byte(json), m) else { + t.Errorf("Decode({}, map[int]str) failed", json) + ret + } + _, mut ok := m[234] + t.Assert(ok, `m[234] is not exist`) + _, ok = m[49] + t.Assert(ok, `m[49] is not exist`) + _, ok := m[0] + t.Assert(ok, `m[0] is not exist`) } #test fn testDecodeArray(t: &T) { - const json = `["foo", "bar", "baz"]` - let mut a: [3]str - Decode([]byte(json), a) else { - t.Errorf("Decode({}) failed", json) - ret - } - t.Assert(a[0] == "foo", `a[0] != "foo"`) - t.Assert(a[1] == "bar", `a[1] != "bar"`) - t.Assert(a[2] == "baz", `a[2] != "baz"`) + const json = `["foo", "bar", "baz"]` + let mut a: [3]str + Decode([]byte(json), a) else { + t.Errorf("Decode({}) failed", json) + ret + } + t.Assert(a[0] == "foo", `a[0] != "foo"`) + t.Assert(a[1] == "bar", `a[1] != "bar"`) + t.Assert(a[2] == "baz", `a[2] != "baz"`) } #test fn testDecodeArrayWithRemainder(t: &T) { - const json = `["foo", "bar", "baz"]` - let mut a: [5]str = ["foo", "foo", "foo", "foo", "foo"] - Decode([]byte(json), a) else { - t.Errorf("Decode({}) failed", json) - ret - } - t.Assert(a[0] == "foo", `a[0] != "foo"`) - t.Assert(a[1] == "bar", `a[1] != "bar"`) - t.Assert(a[2] == "baz", `a[2] != "baz"`) - t.Assert(a[3] == "", `a[3] != ""`) - t.Assert(a[4] == "", `a[4] != ""`) + const json = `["foo", "bar", "baz"]` + let mut a: [5]str = ["foo", "foo", "foo", "foo", "foo"] + Decode([]byte(json), a) else { + t.Errorf("Decode({}) failed", json) + ret + } + t.Assert(a[0] == "foo", `a[0] != "foo"`) + t.Assert(a[1] == "bar", `a[1] != "bar"`) + t.Assert(a[2] == "baz", `a[2] != "baz"`) + t.Assert(a[3] == "", `a[3] != ""`) + t.Assert(a[4] == "", `a[4] != ""`) } #test fn testDecodeSlice(t: &T) { - const json = `["foo", "bar", "baz"]` - mut s := []str(nil) - Decode([]byte(json), s) else { - t.Errorf("Decode({}) failed", json) - ret - } - t.Assert(len(s) == 3, `len(s) != 3`) - t.Assert(s[0] == "foo", `s[0] != "foo"`) - t.Assert(s[1] == "bar", `s[1] != "bar"`) - t.Assert(s[2] == "baz", `s[2] != "baz"`) + const json = `["foo", "bar", "baz"]` + mut s := []str(nil) + Decode([]byte(json), s) else { + t.Errorf("Decode({}) failed", json) + ret + } + t.Assert(len(s) == 3, `len(s) != 3`) + t.Assert(s[0] == "foo", `s[0] != "foo"`) + t.Assert(s[1] == "bar", `s[1] != "bar"`) + t.Assert(s[2] == "baz", `s[2] != "baz"`) } #test fn testDecodeSliceWithRemainder(t: &T) { - const json = `["foo", "bar", "baz"]` - mut s := ["foo", "foo", "foo", "foo", "foo"] - Decode([]byte(json), s) else { - t.Errorf("Decode({}) failed", json) - ret - } - t.Assert(len(s) == 3, `len(s) != 3`) - t.Assert(s[0] == "foo", `s[0] != "foo"`) - t.Assert(s[1] == "bar", `s[1] != "bar"`) - t.Assert(s[2] == "baz", `s[2] != "baz"`) + const json = `["foo", "bar", "baz"]` + mut s := ["foo", "foo", "foo", "foo", "foo"] + Decode([]byte(json), s) else { + t.Errorf("Decode({}) failed", json) + ret + } + t.Assert(len(s) == 3, `len(s) != 3`) + t.Assert(s[0] == "foo", `s[0] != "foo"`) + t.Assert(s[1] == "bar", `s[1] != "bar"`) + t.Assert(s[2] == "baz", `s[2] != "baz"`) } #test fn testDecodeByteSlice(t: &T) { - for _, case in encodeByteSliceCases { - mut bytes := []byte(nil) - Decode(case.output, bytes) else { - t.Errorf("Decode({}) failed", case.output) - ret - } - if len(bytes) != len(case.input) { - t.Errorf("expected {} for {}, found {}", case.input, case.output, bytes) - continue - } - for i in bytes { - if bytes[i] != case.input[i] { - t.Errorf("expected {} for {}, found {}", case.input, case.output, bytes) - break - } - } - } + for _, case in encodeByteSliceCases { + mut bytes := []byte(nil) + Decode(case.output, bytes) else { + t.Errorf("Decode({}) failed", case.output) + ret + } + if len(bytes) != len(case.input) { + t.Errorf("expected {} for {}, found {}", case.input, case.output, bytes) + continue + } + for i in bytes { + if bytes[i] != case.input[i] { + t.Errorf("expected {} for {}, found {}", case.input, case.output, bytes) + break + } + } + } } #test fn testDecodeBigHead(t: &T) { - mut out := (&encodeTree)(nil) - Decode(bigBytes, out) else { - t.Errorf("Decode(bigBytes) failed") - } + mut out := (&encodeTree)(nil) + Decode(bigBytes, out) else { + t.Errorf("Decode(bigBytes) failed") + } } \ No newline at end of file diff --git a/std/encoding/json/encode.jule b/std/encoding/json/encode.jule index 419ead847..48c14fedf 100644 --- a/std/encoding/json/encode.jule +++ b/std/encoding/json/encode.jule @@ -23,25 +23,25 @@ const hex = "0123456789abcdef" // algorithms. Thus, we can have separated algorithms for plain and // indentation-based encoding algorithms. enum encodeFlagType: type { - // Flag type for plain JSON encoding without indentation. - // When this type used for Flag type, indentation algorithms will be excluded. - Plain: int, + // Flag type for plain JSON encoding without indentation. + // When this type used for Flag type, indentation algorithms will be excluded. + Plain: int, - // Flag type for JSON encoding with indentation. - // When this type used for Flag type, indentation algorithms will be included. - // Indentation algorithms does not appends indentation during encoding, - // because it is not efficient enought as far as tested. Probably causes too - // many reallocation. Therefore, just appends the newline when indentation needed, - // this newlines also part of the encoded JSON result. After encoding, - // bytes should be handled and indentation should be appended after each newline. - // Except indentations, it will append whitespace after colons and etc. to buffer. - // So, just newlines should be handled, minor whitespaces will be handled by encoder. - // The encoder also computes the total count of bytes for indentations. Thus, - // we can know the exact size of the buffer including indentations with - // calculation like this: len(encoder.buf.bytes()) + encoder.total - // So if needed to making new allocation to handle indentations after encoding, - // we can allocate new buffer with exact size without wasted memory. - Indent: uint, + // Flag type for JSON encoding with indentation. + // When this type used for Flag type, indentation algorithms will be included. + // Indentation algorithms does not appends indentation during encoding, + // because it is not efficient enought as far as tested. Probably causes too + // many reallocation. Therefore, just appends the newline when indentation needed, + // this newlines also part of the encoded JSON result. After encoding, + // bytes should be handled and indentation should be appended after each newline. + // Except indentations, it will append whitespace after colons and etc. to buffer. + // So, just newlines should be handled, minor whitespaces will be handled by encoder. + // The encoder also computes the total count of bytes for indentations. Thus, + // we can know the exact size of the buffer including indentations with + // calculation like this: len(encoder.buf.bytes()) + encoder.total + // So if needed to making new allocation to handle indentations after encoding, + // we can allocate new buffer with exact size without wasted memory. + Indent: uint, } // JSON encoder with/without indentation. @@ -49,359 +49,359 @@ enum encodeFlagType: type { // See documentation of the [encodeFlagType]. // See documentation of the Encode[T] for encoding details. struct jsonEncoder { - buf: buffer // Common internal buffer to encode JSON. - indent: int // Length of bytes per indentation. - depth: int // Current depth. - total: int // Total count of bytes for indentations. - escapeHTML: bool + buf: buffer // Common internal buffer to encode JSON. + indent: int // Length of bytes per indentation. + depth: int // Current depth. + total: int // Total count of bytes for indentations. + escapeHTML: bool } impl jsonEncoder { - fn encodeNil(mut self) { - self.buf.writeStr("null") - } + fn encodeNil(mut self) { + self.buf.writeStr("null") + } - fn encodeBool(mut self, b: bool) { - if b { - self.buf.writeStr("true") - } else { - self.buf.writeStr("false") - } - } + fn encodeBool(mut self, b: bool) { + if b { + self.buf.writeStr("true") + } else { + self.buf.writeStr("false") + } + } - fn encodeInt(mut self, x: i64) { - self.buf.writeStr(conv::FmtInt(x, 0xA)) - } + fn encodeInt(mut self, x: i64) { + self.buf.writeStr(conv::FmtInt(x, 0xA)) + } - fn encodeUint(mut self, x: u64) { - self.buf.writeStr(conv::FmtUint(x, 0xA)) - } + fn encodeUint(mut self, x: u64) { + self.buf.writeStr(conv::FmtUint(x, 0xA)) + } - fn encodeFloat(mut self, f: f64, bits: int)! { - if math::IsNaN(f) || math::IsInf(f, 0) { - error(JSONEncodeError.UnsupportedFloatValue) - } - mut fmt := 'f' - abs := math::Abs(f) - // Note: Must use f32 comparisons for underlying f32 value to get precise cutoffs right. - if abs != 0 { - if bits == 1<<6 && (abs < 1e-6 || abs >= 1e21) || bits == 1<<5 && (f32(abs) < 1e-6 || f32(abs) >= 1e21) { - fmt = 'e' - } - } - s := conv::FmtFloat(f, fmt, -1, 1 << 6) - mut sb := unsafe::StrBytes(s) - if fmt == 'e' { - // clean up e-09 to e-9 - n := len(s) - if n >= 4 && sb[n-4] == 'e' && sb[n-3] == '-' && sb[n-2] == '0' { - sb[n-2] = sb[n-1] - sb = sb[:n-1] - } - } - self.buf.write(sb) - } + fn encodeFloat(mut self, f: f64, bits: int)! { + if math::IsNaN(f) || math::IsInf(f, 0) { + error(JSONEncodeError.UnsupportedFloatValue) + } + mut fmt := 'f' + abs := math::Abs(f) + // Note: Must use f32 comparisons for underlying f32 value to get precise cutoffs right. + if abs != 0 { + if bits == 1<<6 && (abs < 1e-6 || abs >= 1e21) || bits == 1<<5 && (f32(abs) < 1e-6 || f32(abs) >= 1e21) { + fmt = 'e' + } + } + s := conv::FmtFloat(f, fmt, -1, 1 << 6) + mut sb := unsafe::StrBytes(s) + if fmt == 'e' { + // clean up e-09 to e-9 + n := len(s) + if n >= 4 && sb[n-4] == 'e' && sb[n-3] == '-' && sb[n-2] == '0' { + sb[n-2] = sb[n-1] + sb = sb[:n-1] + } + } + self.buf.write(sb) + } - fn encodeStr(mut self, s: str) { - self.buf.writeByte('"') - mut start := 0 - mut i := 0 - for i < len(s) { - b := s[i] - if b < utf8::RuneSelf { - if isHTMLSafe(b) || (!self.escapeHTML && isSafe(b)) { - i++ - continue - } - self.buf.writeStr(s[start:i]) - match b { - | '\\': - self.buf.writeStr(`\\`) - | '"': - self.buf.writeStr(`\"`) - | '\b': - self.buf.writeStr(`\b`) - | '\f': - self.buf.writeStr(`\f`) - | '\n': - self.buf.writeStr(`\n`) - | '\r': - self.buf.writeStr(`\r`) - | '\t': - self.buf.writeStr(`\t`) - |: - // This encodes bytes < 0x20 except for \b, \f, \n, \r and \t. - // If escapeHTML is set, it also escapes <, >, and & - // because they can lead to security holes when - // user-controlled strings are rendered into JSON - // and served to some browsers. - self.buf.writeStr(`\u00`) - self.buf.writeByte(hex[b>>4]) - self.buf.writeByte(hex[b&0xF]) - } - i++ - start = i - continue - } - mut n := len(s) - i - if n > utf8::UTFMax { - n = utf8::UTFMax - } - c, size := utf8::DecodeRuneStr(s[i:i+n]) - if c == utf8::RuneError && size == 1 { - self.buf.writeStr(s[start:i]) - self.buf.writeStr(`\ufffd`) - i += size - start = i - continue - } - // U+2028 is LINE SEPARATOR. - // U+2029 is PARAGRAPH SEPARATOR. - // They are both technically valid characters in JSON strings, - // but don't work in JSONP, which has to be evaluated as JavaScript, - // and can lead to security holes there. It is valid JSON to - // escape them, so we do so unconditionally. - // See https://en.wikipedia.org/wiki/JSON#Safety. - if c == '\u2028' || c == '\u2029' { - self.buf.writeStr(s[start:i]) - self.buf.writeStr(`\u202`) - self.buf.writeByte(hex[c&0xF]) - i += size - start = i - continue - } - i += size - } - self.buf.writeStr(s[start:]) - self.buf.writeByte('"') - } + fn encodeStr(mut self, s: str) { + self.buf.writeByte('"') + mut start := 0 + mut i := 0 + for i < len(s) { + b := s[i] + if b < utf8::RuneSelf { + if isHTMLSafe(b) || (!self.escapeHTML && isSafe(b)) { + i++ + continue + } + self.buf.writeStr(s[start:i]) + match b { + | '\\': + self.buf.writeStr(`\\`) + | '"': + self.buf.writeStr(`\"`) + | '\b': + self.buf.writeStr(`\b`) + | '\f': + self.buf.writeStr(`\f`) + | '\n': + self.buf.writeStr(`\n`) + | '\r': + self.buf.writeStr(`\r`) + | '\t': + self.buf.writeStr(`\t`) + |: + // This encodes bytes < 0x20 except for \b, \f, \n, \r and \t. + // If escapeHTML is set, it also escapes <, >, and & + // because they can lead to security holes when + // user-controlled strings are rendered into JSON + // and served to some browsers. + self.buf.writeStr(`\u00`) + self.buf.writeByte(hex[b>>4]) + self.buf.writeByte(hex[b&0xF]) + } + i++ + start = i + continue + } + mut n := len(s) - i + if n > utf8::UTFMax { + n = utf8::UTFMax + } + c, size := utf8::DecodeRuneStr(s[i:i+n]) + if c == utf8::RuneError && size == 1 { + self.buf.writeStr(s[start:i]) + self.buf.writeStr(`\ufffd`) + i += size + start = i + continue + } + // U+2028 is LINE SEPARATOR. + // U+2029 is PARAGRAPH SEPARATOR. + // They are both technically valid characters in JSON strings, + // but don't work in JSONP, which has to be evaluated as JavaScript, + // and can lead to security holes there. It is valid JSON to + // escape them, so we do so unconditionally. + // See https://en.wikipedia.org/wiki/JSON#Safety. + if c == '\u2028' || c == '\u2029' { + self.buf.writeStr(s[start:i]) + self.buf.writeStr(`\u202`) + self.buf.writeByte(hex[c&0xF]) + i += size + start = i + continue + } + i += size + } + self.buf.writeStr(s[start:]) + self.buf.writeByte('"') + } - fn encodeByteSlice(mut self, &s: []byte) { - const Padding = true // Padding for Base64 encoding. - self.buf.writeByte('"') - self.buf.write(base64::Encode(s, Padding)) - self.buf.writeByte('"') - } + fn encodeByteSlice(mut self, &s: []byte) { + const Padding = true // Padding for Base64 encoding. + self.buf.writeByte('"') + self.buf.write(base64::Encode(s, Padding)) + self.buf.writeByte('"') + } - fn encodeStruct[T, Flag](mut self, &t: T)! { - const tt = comptime::TypeOf(T) - const useIndent = comptime::TypeOf(Flag) == comptime::TypeOf(encodeFlagType.Indent) - self.buf.writeByte('{') - const match { - | useIndent: - self.depth++ - self.total += self.depth * self.indent - self.buf.writeByte('\n') - } - const vt = comptime::ValueOf(t) - const fields = tt.Fields() - const for i, field in fields { - const match { - | field.Public(): - const match { - | i > 0 && useIndent: - self.total += self.depth * self.indent - self.buf.writeByte('\n') - } - self.buf.writeStr("\"" + field.Name() + "\":") - const fieldValue = vt.Field(field.Name()) - comptime::TypeAlias(fieldType, fieldValue.Type()) - const match type Flag { - | encodeFlagType.Indent: - self.buf.writeByte(' ') - } - self.encode[fieldType, Flag](fieldValue.Unwrap()) else { error(error) } - const match { - | i < len(fields)-1: - self.buf.writeByte(',') - } - } - } - const match { - | useIndent: - self.total += self.depth * self.indent - self.depth-- - self.buf.writeByte('\n') - } - self.buf.writeByte('}') - } + fn encodeStruct[T, Flag](mut self, &t: T)! { + const tt = comptime::TypeOf(T) + const useIndent = comptime::TypeOf(Flag) == comptime::TypeOf(encodeFlagType.Indent) + self.buf.writeByte('{') + const match { + | useIndent: + self.depth++ + self.total += self.depth * self.indent + self.buf.writeByte('\n') + } + const vt = comptime::ValueOf(t) + const fields = tt.Fields() + const for i, field in fields { + const match { + | field.Public(): + const match { + | i > 0 && useIndent: + self.total += self.depth * self.indent + self.buf.writeByte('\n') + } + self.buf.writeStr("\"" + field.Name() + "\":") + const fieldValue = vt.Field(field.Name()) + comptime::TypeAlias(fieldType, fieldValue.Type()) + const match type Flag { + | encodeFlagType.Indent: + self.buf.writeByte(' ') + } + self.encode[fieldType, Flag](fieldValue.Unwrap()) else { error(error) } + const match { + | i < len(fields)-1: + self.buf.writeByte(',') + } + } + } + const match { + | useIndent: + self.total += self.depth * self.indent + self.depth-- + self.buf.writeByte('\n') + } + self.buf.writeByte('}') + } - fn encodeMap[T, Flag](mut self, &t: T)! { - const tt = comptime::TypeOf(T) - const keyT = tt.Key() - const valT = tt.Value() - match keyT.Kind() { - | comptime::Kind.Str - | comptime::Kind.Int - | comptime::Kind.I8 - | comptime::Kind.I16 - | comptime::Kind.I32 - | comptime::Kind.I64 - | comptime::Kind.Uint - | comptime::Kind.Uintptr - | comptime::Kind.U8 - | comptime::Kind.U16 - | comptime::Kind.U32 - | comptime::Kind.U64: - break - |: - error(JSONEncodeError.UnsupportedType) - } - if t == nil { - self.encodeNil() - ret - } - const quoted = keyT.Kind() == comptime::Kind.Str - const useIndent = comptime::TypeOf(Flag) == comptime::TypeOf(encodeFlagType.Indent) - self.buf.writeByte('{') - const match { - | useIndent: - self.depth++ - self.total += self.depth * self.indent - self.buf.writeByte('\n') - } - mut first := true - comptime::TypeAlias(keyType, tt.Key()) - comptime::TypeAlias(valType, tt.Value()) - for k, v in t { - if !first { - self.buf.writeByte(',') - const match { - | useIndent: - self.total += self.depth * self.indent - self.buf.writeByte('\n') - } - } - // No need to check Flag. The key type cannot be/include - // indentation-sensitive type. Look at this function's - // implementation to see match-type conditions for the key type. - const match { - | quoted: - self.encode[keyType, Flag](k) else { error(error) } - |: - self.buf.writeByte('"') - self.encode[keyType, Flag](k) else { error(error) } - self.buf.writeByte('"') - } - self.buf.writeByte(':') - const match { - | useIndent: - self.buf.writeByte(' ') - } - self.encode[valType, Flag](v) else { error(error) } - first = false - } - const match { - | useIndent: - self.total += self.depth * self.indent - self.depth-- - self.buf.writeByte('\n') - } - self.buf.writeByte('}') - } + fn encodeMap[T, Flag](mut self, &t: T)! { + const tt = comptime::TypeOf(T) + const keyT = tt.Key() + const valT = tt.Value() + match keyT.Kind() { + | comptime::Kind.Str + | comptime::Kind.Int + | comptime::Kind.I8 + | comptime::Kind.I16 + | comptime::Kind.I32 + | comptime::Kind.I64 + | comptime::Kind.Uint + | comptime::Kind.Uintptr + | comptime::Kind.U8 + | comptime::Kind.U16 + | comptime::Kind.U32 + | comptime::Kind.U64: + break + |: + error(JSONEncodeError.UnsupportedType) + } + if t == nil { + self.encodeNil() + ret + } + const quoted = keyT.Kind() == comptime::Kind.Str + const useIndent = comptime::TypeOf(Flag) == comptime::TypeOf(encodeFlagType.Indent) + self.buf.writeByte('{') + const match { + | useIndent: + self.depth++ + self.total += self.depth * self.indent + self.buf.writeByte('\n') + } + mut first := true + comptime::TypeAlias(keyType, tt.Key()) + comptime::TypeAlias(valType, tt.Value()) + for k, v in t { + if !first { + self.buf.writeByte(',') + const match { + | useIndent: + self.total += self.depth * self.indent + self.buf.writeByte('\n') + } + } + // No need to check Flag. The key type cannot be/include + // indentation-sensitive type. Look at this function's + // implementation to see match-type conditions for the key type. + const match { + | quoted: + self.encode[keyType, Flag](k) else { error(error) } + |: + self.buf.writeByte('"') + self.encode[keyType, Flag](k) else { error(error) } + self.buf.writeByte('"') + } + self.buf.writeByte(':') + const match { + | useIndent: + self.buf.writeByte(' ') + } + self.encode[valType, Flag](v) else { error(error) } + first = false + } + const match { + | useIndent: + self.total += self.depth * self.indent + self.depth-- + self.buf.writeByte('\n') + } + self.buf.writeByte('}') + } - fn encodeArray[T, Flag](mut self, &t: T)! { - const useIndent = comptime::TypeOf(Flag) == comptime::TypeOf(encodeFlagType.Indent) - self.buf.writeByte('[') - const match { - | useIndent: - self.depth++ - self.total += self.depth * self.indent - self.buf.writeByte('\n') - } - comptime::TypeAlias(elem, comptime::TypeOf(t).Elem()) - for i, e in t { - if i > 0 { - self.buf.writeByte(',') - const match { - | useIndent: - self.total += self.depth * self.indent - self.buf.writeByte('\n') - } - } - self.encode[elem, Flag](e) else { error(error) } - } - const match { - | useIndent: - self.total += self.depth * self.indent - self.depth-- - self.buf.writeByte('\n') - } - self.buf.writeByte(']') - } + fn encodeArray[T, Flag](mut self, &t: T)! { + const useIndent = comptime::TypeOf(Flag) == comptime::TypeOf(encodeFlagType.Indent) + self.buf.writeByte('[') + const match { + | useIndent: + self.depth++ + self.total += self.depth * self.indent + self.buf.writeByte('\n') + } + comptime::TypeAlias(elem, comptime::TypeOf(t).Elem()) + for i, e in t { + if i > 0 { + self.buf.writeByte(',') + const match { + | useIndent: + self.total += self.depth * self.indent + self.buf.writeByte('\n') + } + } + self.encode[elem, Flag](e) else { error(error) } + } + const match { + | useIndent: + self.total += self.depth * self.indent + self.depth-- + self.buf.writeByte('\n') + } + self.buf.writeByte(']') + } - // Checks nil case for slices, then forwards to the [encodeArray] method. - // Also uses base64-encoding algorithm for the []byte type. - // Non-nil slices and arrays should have same outputs. - fn encodeSlice[T, Flag](mut self, &t: T)! { - if t == nil { - self.encodeNil() - ret - } - const match type T { - | []byte: - self.encodeByteSlice(t) - |: - self.encodeArray[T, Flag](t) else { error(error) } - } - } + // Checks nil case for slices, then forwards to the [encodeArray] method. + // Also uses base64-encoding algorithm for the []byte type. + // Non-nil slices and arrays should have same outputs. + fn encodeSlice[T, Flag](mut self, &t: T)! { + if t == nil { + self.encodeNil() + ret + } + const match type T { + | []byte: + self.encodeByteSlice(t) + |: + self.encodeArray[T, Flag](t) else { error(error) } + } + } - fn encode[T, Flag](mut self, &t: T)! { - const tt = comptime::TypeOf(T) - const match { - | tt.Binded(): - error(JSONEncodeError.UnsupportedType) - } - const match type T { - | int | i8 | i16 | i32 | i64: - self.encodeInt(i64(t)) - ret - | uint | uintptr | u8 | u16 | u32 | u64: - self.encodeUint(u64(t)) - ret - | f32: - self.encodeFloat(f64(t), 1 << 5) else { error(error) } - ret - | f64: - self.encodeFloat(t, 1 << 6) else { error(error) } - ret - | bool: - self.encodeBool(t) - ret - | str: - self.encodeStr(t) - ret - } - const match tt.Kind() { - | comptime::Kind.SmartPtr: - // Avoid to implement as a function. - // Fills call stack faster especially with recursive structures. - // Handle smart pointers here quicky and forward to relevant encoder. - if t == nil { - self.encodeNil() - } else { - comptime::TypeAlias(elem, tt.Elem()) - self.encode[elem, Flag](*t) else { error(error) } - } - | comptime::Kind.Struct: - self.encodeStruct[T, Flag](t) else { error(error) } - | comptime::Kind.Map: - self.encodeMap[T, Flag](t) else { error(error) } - | comptime::Kind.Array: - self.encodeArray[T, Flag](t) else { error(error) } - | comptime::Kind.Slice: - self.encodeSlice[T, Flag](t) else { error(error) } - |: - error(JSONEncodeError.UnsupportedType) - } - } + fn encode[T, Flag](mut self, &t: T)! { + const tt = comptime::TypeOf(T) + const match { + | tt.Binded(): + error(JSONEncodeError.UnsupportedType) + } + const match type T { + | int | i8 | i16 | i32 | i64: + self.encodeInt(i64(t)) + ret + | uint | uintptr | u8 | u16 | u32 | u64: + self.encodeUint(u64(t)) + ret + | f32: + self.encodeFloat(f64(t), 1 << 5) else { error(error) } + ret + | f64: + self.encodeFloat(t, 1 << 6) else { error(error) } + ret + | bool: + self.encodeBool(t) + ret + | str: + self.encodeStr(t) + ret + } + const match tt.Kind() { + | comptime::Kind.SmartPtr: + // Avoid to implement as a function. + // Fills call stack faster especially with recursive structures. + // Handle smart pointers here quicky and forward to relevant encoder. + if t == nil { + self.encodeNil() + } else { + comptime::TypeAlias(elem, tt.Elem()) + self.encode[elem, Flag](*t) else { error(error) } + } + | comptime::Kind.Struct: + self.encodeStruct[T, Flag](t) else { error(error) } + | comptime::Kind.Map: + self.encodeMap[T, Flag](t) else { error(error) } + | comptime::Kind.Array: + self.encodeArray[T, Flag](t) else { error(error) } + | comptime::Kind.Slice: + self.encodeSlice[T, Flag](t) else { error(error) } + |: + error(JSONEncodeError.UnsupportedType) + } + } } // Returns jsonEncoder with default configuration. fn encoder(): jsonEncoder { - ret jsonEncoder{ - escapeHTML: true, - } + ret jsonEncoder{ + escapeHTML: true, + } } // Implements encoding of JSON as defined in RFC 7159. @@ -462,42 +462,42 @@ fn encoder(): jsonEncoder { // it is recommended that a data type can carry a maximum of 10000 nested data. // However, tousands of nested-data is always risky even below 10000. fn Encode[T](t: T)!: []byte { - mut encoder := encoder() - encoder.encode[T, encodeFlagType.Plain](t) else { error(error) } - ret encoder.buf.bytes() + mut encoder := encoder() + encoder.encode[T, encodeFlagType.Plain](t) else { error(error) } + ret encoder.buf.bytes() } // Same as Encode[T] function but enables identation. fn EncodeIndent[T](t: T, indent: str)!: []byte { - mut encoder := encoder() - encoder.indent = len(indent) - encoder.encode[T, encodeFlagType.Indent](t) else { error(error) } - mut bytes := encoder.buf.bytes() - if encoder.total == 0 { - ret bytes - } - // Handle indentation. - // See documentation of [encodeFlagType.Indent]. - mut buf := make([]byte, len(bytes) + encoder.total) - mut depth := 0 - mut p := &buf[0] // Use raw pointer to mutate buffer efficiently. - for _, b in bytes { - unsafe { *p = b } - p++ - match b { - | '[' | '{': - depth++ - | ']' | '}': - depth-- - | '\n': - mut i := 0 - for i < depth; i++ { - for _, ib in indent { - unsafe { *p = ib } - p++ - } - } - } - } - ret buf + mut encoder := encoder() + encoder.indent = len(indent) + encoder.encode[T, encodeFlagType.Indent](t) else { error(error) } + mut bytes := encoder.buf.bytes() + if encoder.total == 0 { + ret bytes + } + // Handle indentation. + // See documentation of [encodeFlagType.Indent]. + mut buf := make([]byte, len(bytes) + encoder.total) + mut depth := 0 + mut p := &buf[0] // Use raw pointer to mutate buffer efficiently. + for _, b in bytes { + unsafe { *p = b } + p++ + match b { + | '[' | '{': + depth++ + | ']' | '}': + depth-- + | '\n': + mut i := 0 + for i < depth; i++ { + for _, ib in indent { + unsafe { *p = ib } + p++ + } + } + } + } + ret buf } \ No newline at end of file diff --git a/std/encoding/json/encode_test.jule b/std/encoding/json/encode_test.jule index c6b34808b..bf275c935 100644 --- a/std/encoding/json/encode_test.jule +++ b/std/encoding/json/encode_test.jule @@ -8,218 +8,218 @@ use std::testing::{T} use base64 for std::encoding::base64 fn encodeMapXKey[Map](t: &T, m: Map, kind: str) { - bytes := Encode(m) else { - t.Errorf("Encode({}) failed", kind) - ret - } - if !Valid(bytes) { - t.Errorf("Valid() returns false for Encode({})", kind) - } + bytes := Encode(m) else { + t.Errorf("Encode({}) failed", kind) + ret + } + if !Valid(bytes) { + t.Errorf("Valid() returns false for Encode({})", kind) + } } #test fn testEncodeMapStrKey(t: &T) { - let encodeMap: map[str]str = { - "foo": "foo value", - "bar": "bar value", - "baz": "baz value", - } - encodeMapXKey(t, encodeMap, "map[str]str") + let encodeMap: map[str]str = { + "foo": "foo value", + "bar": "bar value", + "baz": "baz value", + } + encodeMapXKey(t, encodeMap, "map[str]str") } #test fn testEncodeMapNumKey(t: &T) { - let encodeMap: map[int]str = { - 234: "foo value", - 49: "bar value", - 0: "baz value", - } - encodeMapXKey(t, encodeMap, "map[int]str") + let encodeMap: map[int]str = { + 234: "foo value", + 49: "bar value", + 0: "baz value", + } + encodeMapXKey(t, encodeMap, "map[int]str") } #test fn testEncodeSlice(t: &T) { - s := ["foo", "bar", "baz"] - bytes := Encode(s) else { - t.Errorf("Encode([]str) failed") - ret - } - if !Valid(bytes) { - t.Errorf("Valid() returns false for Encode([]str)") - } + s := ["foo", "bar", "baz"] + bytes := Encode(s) else { + t.Errorf("Encode([]str) failed") + ret + } + if !Valid(bytes) { + t.Errorf("Valid() returns false for Encode([]str)") + } } #test fn testEncodeArray(t: &T) { - let a: [...]str = ["foo", "bar", "baz"] - bytes := Encode(a) else { - t.Errorf("Encode([3]str) failed") - ret - } - if !Valid(bytes) { - t.Errorf("Valid() returns false for Encode([3]str)") - } + let a: [...]str = ["foo", "bar", "baz"] + bytes := Encode(a) else { + t.Errorf("Encode([3]str) failed") + ret + } + if !Valid(bytes) { + t.Errorf("Valid() returns false for Encode([3]str)") + } } #test fn testEncodeNum(t: &T) { - nums := [ - 0., - -0, - 1, - -1, - 0.1, - -0.1, - 1234, - -1234, - 12.34, - -12.34, - 12E0, - 12E1, - 12e34, - 12E-0, - 12e+1, - 12e-34, - -12E0, - -12E1, - -12e34, - -12E-0, - -12e+1, - -12e-34, - 1.2E0, - 1.2E1, - 1.2e34, - 1.2E-0, - 1.2e+1, - 1.2e-34, - -1.2E0, - -1.2E1, - -1.2e34, - -1.2E-0, - -1.2e+1, - -1.2e-34, - 0E0, - 0E1, - 0e34, - 0E-0, - 0e+1, - 0e-34, - -0E0, - -0E1, - -0e34, - -0E-0, - -0e+1, - -0e-34, - ] - bytes := Encode(nums) else { - t.Errorf("Encode(nums) failed") - ret - } - if !Valid(bytes) { - t.Errorf("Valid() returns false for Encode(nums)") - } + nums := [ + 0., + -0, + 1, + -1, + 0.1, + -0.1, + 1234, + -1234, + 12.34, + -12.34, + 12E0, + 12E1, + 12e34, + 12E-0, + 12e+1, + 12e-34, + -12E0, + -12E1, + -12e34, + -12E-0, + -12e+1, + -12e-34, + 1.2E0, + 1.2E1, + 1.2e34, + 1.2E-0, + 1.2e+1, + 1.2e-34, + -1.2E0, + -1.2E1, + -1.2e34, + -1.2E-0, + -1.2e+1, + -1.2e-34, + 0E0, + 0E1, + 0e34, + 0E-0, + 0e+1, + 0e-34, + -0E0, + -0E1, + -0e34, + -0E-0, + -0e+1, + -0e-34, + ] + bytes := Encode(nums) else { + t.Errorf("Encode(nums) failed") + ret + } + if !Valid(bytes) { + t.Errorf("Valid() returns false for Encode(nums)") + } } struct strCase { - input: str - output: []byte + input: str + output: []byte } static strCases: []strCase = [ - {"", []byte(`""`)}, - {"hello world", []byte(`"hello world"`)}, - {"baykuş", []byte(`"baykuş"`)}, - {"\"hello\xffworld\"", []byte(`"\"hello\ufffdworld\""`)}, - {"foo", []byte(`"foo"`)}, - {"baz", []byte(`"baz"`)}, - {"a\u1234", [34, 97, 225, 136, 180, 34]}, - {"\"hello\xed\xa0\x80\xed\xb0\x80world\"", []byte(`"\"hello\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdworld\""`)}, - {"\x00", []byte(`"\u0000"`)}, - {"\x01", []byte(`"\u0001"`)}, - {"\x02", []byte(`"\u0002"`)}, - {"\x03", []byte(`"\u0003"`)}, - {"\x04", []byte(`"\u0004"`)}, - {"\x05", []byte(`"\u0005"`)}, - {"\x06", []byte(`"\u0006"`)}, - {"\x07", []byte(`"\u0007"`)}, - {"\x08", []byte(`"\b"`)}, - {"\x09", []byte(`"\t"`)}, - {"\x0a", []byte(`"\n"`)}, - {"\x0b", []byte(`"\u000b"`)}, - {"\x0c", []byte(`"\f"`)}, - {"\x0d", []byte(`"\r"`)}, - {"\x0e", []byte(`"\u000e"`)}, - {"\x0f", []byte(`"\u000f"`)}, - {"\x10", []byte(`"\u0010"`)}, - {"\x11", []byte(`"\u0011"`)}, - {"\x12", []byte(`"\u0012"`)}, - {"\x13", []byte(`"\u0013"`)}, - {"\x14", []byte(`"\u0014"`)}, - {"\x15", []byte(`"\u0015"`)}, - {"\x16", []byte(`"\u0016"`)}, - {"\x17", []byte(`"\u0017"`)}, - {"\x18", []byte(`"\u0018"`)}, - {"\x19", []byte(`"\u0019"`)}, - {"\x1a", []byte(`"\u001a"`)}, - {"\x1b", []byte(`"\u001b"`)}, - {"\x1c", []byte(`"\u001c"`)}, - {"\x1d", []byte(`"\u001d"`)}, - {"\x1e", []byte(`"\u001e"`)}, - {"\x1f", []byte(`"\u001f"`)}, + {"", []byte(`""`)}, + {"hello world", []byte(`"hello world"`)}, + {"baykuş", []byte(`"baykuş"`)}, + {"\"hello\xffworld\"", []byte(`"\"hello\ufffdworld\""`)}, + {"foo", []byte(`"foo"`)}, + {"baz", []byte(`"baz"`)}, + {"a\u1234", [34, 97, 225, 136, 180, 34]}, + {"\"hello\xed\xa0\x80\xed\xb0\x80world\"", []byte(`"\"hello\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdworld\""`)}, + {"\x00", []byte(`"\u0000"`)}, + {"\x01", []byte(`"\u0001"`)}, + {"\x02", []byte(`"\u0002"`)}, + {"\x03", []byte(`"\u0003"`)}, + {"\x04", []byte(`"\u0004"`)}, + {"\x05", []byte(`"\u0005"`)}, + {"\x06", []byte(`"\u0006"`)}, + {"\x07", []byte(`"\u0007"`)}, + {"\x08", []byte(`"\b"`)}, + {"\x09", []byte(`"\t"`)}, + {"\x0a", []byte(`"\n"`)}, + {"\x0b", []byte(`"\u000b"`)}, + {"\x0c", []byte(`"\f"`)}, + {"\x0d", []byte(`"\r"`)}, + {"\x0e", []byte(`"\u000e"`)}, + {"\x0f", []byte(`"\u000f"`)}, + {"\x10", []byte(`"\u0010"`)}, + {"\x11", []byte(`"\u0011"`)}, + {"\x12", []byte(`"\u0012"`)}, + {"\x13", []byte(`"\u0013"`)}, + {"\x14", []byte(`"\u0014"`)}, + {"\x15", []byte(`"\u0015"`)}, + {"\x16", []byte(`"\u0016"`)}, + {"\x17", []byte(`"\u0017"`)}, + {"\x18", []byte(`"\u0018"`)}, + {"\x19", []byte(`"\u0019"`)}, + {"\x1a", []byte(`"\u001a"`)}, + {"\x1b", []byte(`"\u001b"`)}, + {"\x1c", []byte(`"\u001c"`)}, + {"\x1d", []byte(`"\u001d"`)}, + {"\x1e", []byte(`"\u001e"`)}, + {"\x1f", []byte(`"\u001f"`)}, ] #test fn testEncodeStr(t: &T) { - for _, case in strCases { - bytes := Encode(case.input) else { - t.Errorf("Encode(stsr) failed") - ret - } - if len(bytes) != len(case.output) { - t.Errorf("expected {} for {}, found {}", case.output, case.input, bytes) - continue - } - for i in bytes { - if bytes[i] != case.output[i] { - t.Errorf("expected {} for {}, found {}", case.output, case.input, bytes) - break - } - } - } + for _, case in strCases { + bytes := Encode(case.input) else { + t.Errorf("Encode(stsr) failed") + ret + } + if len(bytes) != len(case.output) { + t.Errorf("expected {} for {}, found {}", case.output, case.input, bytes) + continue + } + for i in bytes { + if bytes[i] != case.output[i] { + t.Errorf("expected {} for {}, found {}", case.output, case.input, bytes) + break + } + } + } } struct encodeByteSliceCase { - input: []byte - output: []byte + input: []byte + output: []byte } static encodeByteSliceCases: []encodeByteSliceCase = [ - {input: []byte(`foobar`), output: []byte(`"Zm9vYmFy"`)}, - {input: []byte(`hello world`), output: []byte(`"aGVsbG8gd29ybGQ="`)}, - {input: []byte("\"hello\xed\xa0\x80\xed\xb0\x80world\""), output: []byte(`"ImhlbGxv7aCA7bCAd29ybGQi"`)}, + {input: []byte(`foobar`), output: []byte(`"Zm9vYmFy"`)}, + {input: []byte(`hello world`), output: []byte(`"aGVsbG8gd29ybGQ="`)}, + {input: []byte("\"hello\xed\xa0\x80\xed\xb0\x80world\""), output: []byte(`"ImhlbGxv7aCA7bCAd29ybGQi"`)}, ] #test fn testEncodeByteSlice(t: &T) { - for _, case in encodeByteSliceCases { - bytes := Encode(case.input) else { - t.Errorf("Encode({}) failed", case.input) - ret - } - if !Valid(bytes) { - t.Errorf("Valid() returns false for Encode({})", case.input) - } - if len(bytes) != len(case.output) { - t.Errorf("expected {} for {}, found {}", case.output, case.input, bytes) - continue - } - for i in bytes { - if bytes[i] != case.output[i] { - t.Errorf("expected {} for {}, found {}", case.output, case.input, bytes) - break - } - } - } + for _, case in encodeByteSliceCases { + bytes := Encode(case.input) else { + t.Errorf("Encode({}) failed", case.input) + ret + } + if !Valid(bytes) { + t.Errorf("Valid() returns false for Encode({})", case.input) + } + if len(bytes) != len(case.output) { + t.Errorf("expected {} for {}, found {}", case.output, case.input, bytes) + continue + } + for i in bytes { + if bytes[i] != case.output[i] { + t.Errorf("expected {} for {}, found {}", case.output, case.input, bytes) + break + } + } + } } // Head node of pseudo big JSON. @@ -230,36 +230,36 @@ static mut bigBytes = []byte(nil) // Encode tree is base structure for the pseudo big JSON. struct encodeTree { - Str1: str - Str2: str - Num1: int - Num2: f64 - Bool: bool - Node: &encodeTree + Str1: str + Str2: str + Num1: int + Num2: f64 + Bool: bool + Node: &encodeTree } fn init() { - // Build pseudo big JSON. - bigHead = &encodeTree{} - mut it := bigHead - mut i := 0 - for i < 3000; i++ { - it.Str1 = "FooBarBaz" - it.Str2 = "BazBarFoo" - it.Num1 = 22 - it.Num2 = -1.2e-34 - it.Node = &encodeTree{} - it = it.Node - } + // Build pseudo big JSON. + bigHead = &encodeTree{} + mut it := bigHead + mut i := 0 + for i < 3000; i++ { + it.Str1 = "FooBarBaz" + it.Str2 = "BazBarFoo" + it.Num1 = 22 + it.Num2 = -1.2e-34 + it.Node = &encodeTree{} + it = it.Node + } } #test fn testEncodeBigHead(t: &T) { - bigBytes = Encode(bigHead) else { - t.Errorf("Encode(bigHead) failed") - ret - } - if !Valid(bigBytes) { - t.Errorf("Valid() returns false for Encode(bigHead)") - } + bigBytes = Encode(bigHead) else { + t.Errorf("Encode(bigHead) failed") + ret + } + if !Valid(bigBytes) { + t.Errorf("Valid() returns false for Encode(bigHead)") + } } \ No newline at end of file diff --git a/std/encoding/json/error.jule b/std/encoding/json/error.jule index 2a161512a..9a42ccbd1 100755 --- a/std/encoding/json/error.jule +++ b/std/encoding/json/error.jule @@ -4,16 +4,16 @@ // JSON encoding error codes. enum JSONEncodeError { - UnsupportedType, - UnsupportedFloatValue, // NaN or ±Inf + UnsupportedType, + UnsupportedFloatValue, // NaN or ±Inf } // JSON decoding error codes. enum JSONDecodeError { - UnsupportedType, - UnexpectedEnd, // Unexpected end of JSON input. - ExceededMaxDepth, - MissingBeginningOfValue, - InvalidToken, - InvalidValue, + UnsupportedType, + UnexpectedEnd, // Unexpected end of JSON input. + ExceededMaxDepth, + MissingBeginningOfValue, + InvalidToken, + InvalidValue, } \ No newline at end of file diff --git a/std/encoding/json/escape.jule b/std/encoding/json/escape.jule index 6d5f71b7a..e480f84bb 100644 --- a/std/encoding/json/escape.jule +++ b/std/encoding/json/escape.jule @@ -9,7 +9,7 @@ // All values are true except for the ASCII control characters (0-31), the // double quote ("), and the backslash character ("\"). fn isSafe(b: byte): bool { - ret b != '"' && b != '\\' && b > 31 + ret b != '"' && b != '\\' && b > 31 } // Returns the value true if the ASCII character with the given @@ -20,5 +20,5 @@ fn isSafe(b: byte): bool { // double quote ("), the backslash character ("\"), HTML opening and closing // tags ("<" and ">"), and the ampersand ("&"). fn isHTMLSafe(b: byte): bool { - ret b != '"' && b != '&' && b != '<' && b != '>' && b != '\\' && b > 31 + ret b != '"' && b != '&' && b != '<' && b != '>' && b != '\\' && b > 31 } \ No newline at end of file diff --git a/std/encoding/json/validate.jule b/std/encoding/json/validate.jule index d9d20a8d0..d4418eeb9 100644 --- a/std/encoding/json/validate.jule +++ b/std/encoding/json/validate.jule @@ -4,19 +4,19 @@ // Reports whether data is a valid JSON. fn Valid(data: []byte): bool { - decoder := jsonDecoder{ - data: data, - i: 0, - } - decoder.skipSpace() - if decoder.eof() { - ret false - } - for { - decoder.skip() else { ret false } - if decoder.eof() { - break - } - } - ret true + decoder := jsonDecoder{ + data: data, + i: 0, + } + decoder.skipSpace() + if decoder.eof() { + ret false + } + for { + decoder.skip() else { ret false } + if decoder.eof() { + break + } + } + ret true } \ No newline at end of file diff --git a/std/encoding/json/validate_test.jule b/std/encoding/json/validate_test.jule index b4dd74a44..28b733986 100644 --- a/std/encoding/json/validate_test.jule +++ b/std/encoding/json/validate_test.jule @@ -7,135 +7,135 @@ use std::testing::{T} struct validCase { - data: str - ok: bool + data: str + ok: bool } static validCases: []validCase = [ - {``, false}, - {`foo`, false}, - {`}{`, false}, - {`{]`, false}, - {`{}`, true}, - {`{"foo":"bar"}`, true}, - {`{"foo":"bar","bar":{"baz":["qux"]}}`, true}, - {`"hello world"`, true}, - {`""`, true}, - {`{},`, false}, - {`,{}`, false}, - {`{`, false}, - {`nul`, false}, - {`null`, true}, - {`nulll`, false}, - {`true`, true}, - {`false`, true}, - {`fal`, false}, - {`tru`, false}, - {` `, false}, - {`1234`, true}, - {`{ "foo": null, "bar": { "baz": [] } }`, true}, - {`{ "foo": null, "bar": { "baz": [}] } }`, false}, - {`{ "foo": null, "bar": { "baz": nul } }`, false}, + {``, false}, + {`foo`, false}, + {`}{`, false}, + {`{]`, false}, + {`{}`, true}, + {`{"foo":"bar"}`, true}, + {`{"foo":"bar","bar":{"baz":["qux"]}}`, true}, + {`"hello world"`, true}, + {`""`, true}, + {`{},`, false}, + {`,{}`, false}, + {`{`, false}, + {`nul`, false}, + {`null`, true}, + {`nulll`, false}, + {`true`, true}, + {`false`, true}, + {`fal`, false}, + {`tru`, false}, + {` `, false}, + {`1234`, true}, + {`{ "foo": null, "bar": { "baz": [] } }`, true}, + {`{ "foo": null, "bar": { "baz": [}] } }`, false}, + {`{ "foo": null, "bar": { "baz": nul } }`, false}, ] static validNumberCases = [ - "0", - "-0", - "1", - "-1", - "0.1", - "-0.1", - "1234", - "-1234", - "12.34", - "-12.34", - "12E0", - "12E1", - "12e34", - "12E-0", - "12e+1", - "12e-34", - "-12E0", - "-12E1", - "-12e34", - "-12E-0", - "-12e+1", - "-12e-34", - "1.2E0", - "1.2E1", - "1.2e34", - "1.2E-0", - "1.2e+1", - "1.2e-34", - "-1.2E0", - "-1.2E1", - "-1.2e34", - "-1.2E-0", - "-1.2e+1", - "-1.2e-34", - "0E0", - "0E1", - "0e34", - "0E-0", - "0e+1", - "0e-34", - "-0E0", - "-0E1", - "-0e34", - "-0E-0", - "-0e+1", - "-0e-34", + "0", + "-0", + "1", + "-1", + "0.1", + "-0.1", + "1234", + "-1234", + "12.34", + "-12.34", + "12E0", + "12E1", + "12e34", + "12E-0", + "12e+1", + "12e-34", + "-12E0", + "-12E1", + "-12e34", + "-12E-0", + "-12e+1", + "-12e-34", + "1.2E0", + "1.2E1", + "1.2e34", + "1.2E-0", + "1.2e+1", + "1.2e-34", + "-1.2E0", + "-1.2E1", + "-1.2e34", + "-1.2E-0", + "-1.2e+1", + "-1.2e-34", + "0E0", + "0E1", + "0e34", + "0E-0", + "0e+1", + "0e-34", + "-0E0", + "-0E1", + "-0e34", + "-0E-0", + "-0e+1", + "-0e-34", ] static invalidNumberCases = [ - "", - " ", - "invalid", - "1.0.1", - "1..1", - "-1-2", - "012a42", - "01.2", - "012", - "12E12.12", - "1e2e3", - "1e+-2", - "1e--23", - "1e", - "e1", - "1e+", - "1ea", - "1a", - "1.a", - "1.", - "01", - "1.e1", + "", + " ", + "invalid", + "1.0.1", + "1..1", + "-1-2", + "012a42", + "01.2", + "012", + "12E12.12", + "1e2e3", + "1e+-2", + "1e--23", + "1e", + "e1", + "1e+", + "1ea", + "1a", + "1.a", + "1.", + "01", + "1.e1", ] #test fn testValid(t: &T) { - for _, case in validCases { - ok := Valid([]byte(case.data)) - if ok != case.ok { - t.Errorf("expected {} for {}, found {}", case.ok, case.data, ok) - } - } + for _, case in validCases { + ok := Valid([]byte(case.data)) + if ok != case.ok { + t.Errorf("expected {} for {}, found {}", case.ok, case.data, ok) + } + } } #test fn testValidForValidNumbers(t: &T) { - for _, case in validNumberCases { - if !Valid([]byte(case)) { - t.Errorf("{} should be valid", case) - } - } + for _, case in validNumberCases { + if !Valid([]byte(case)) { + t.Errorf("{} should be valid", case) + } + } } #test fn testValidForInvalidNumbers(t: &T) { - for _, case in invalidNumberCases { - if Valid([]byte(case)) { - t.Errorf("{} should be invalid", case) - } - } + for _, case in invalidNumberCases { + if Valid([]byte(case)) { + t.Errorf("{} should be invalid", case) + } + } } \ No newline at end of file diff --git a/std/env/error.jule b/std/env/error.jule index 5220ac3ce..d47d06f28 100644 --- a/std/env/error.jule +++ b/std/env/error.jule @@ -3,47 +3,47 @@ // license that can be found in the LICENSE file. use std::sys::{ - GetLastErrno, - EACCES, - EIO, - ELOOP, - ENAMETOOLONG, - ENOENT, - ENOTDIR, - ENOMEM, + GetLastErrno, + EACCES, + EIO, + ELOOP, + ENAMETOOLONG, + ENOENT, + ENOTDIR, + ENOMEM, } // Env error codes. enum EnvError { - Denied, // Search permission is denied for a component of the path prefix - IO, // Input/Output error, an error occurred while reading from the file system - Loop, // A loop exists in symbolic links encountered during resolution of the path argument - LongPath, // The length of the path argument exceeds maxium path length or a pathname component is longer than maximum name length - NotExist, // A component of path does not name an existing file or path is an empty string - NotDir, // A component of the path prefix is not a directory - InsufficientMemory, // Insufficient memory to complete the operation - Device, // Device did not respond + Denied, // Search permission is denied for a component of the path prefix + IO, // Input/Output error, an error occurred while reading from the file system + Loop, // A loop exists in symbolic links encountered during resolution of the path argument + LongPath, // The length of the path argument exceeds maxium path length or a pathname component is longer than maximum name length + NotExist, // A component of path does not name an existing file or path is an empty string + NotDir, // A component of the path prefix is not a directory + InsufficientMemory, // Insufficient memory to complete the operation + Device, // Device did not respond } // Returns last os error by errno. fn getLastOsError(): EnvError { - err := GetLastErrno() - match err { - | EACCES: - ret EnvError.Denied - | EIO: - ret EnvError.IO - | ELOOP: - ret EnvError.Loop - | ENAMETOOLONG: - ret EnvError.LongPath - | ENOENT: - ret EnvError.NotExist - | ENOTDIR: - ret EnvError.NotDir - | ENOMEM: - ret EnvError.InsufficientMemory - |: - ret EnvError.IO - } + err := GetLastErrno() + match err { + | EACCES: + ret EnvError.Denied + | EIO: + ret EnvError.IO + | ELOOP: + ret EnvError.Loop + | ENAMETOOLONG: + ret EnvError.LongPath + | ENOENT: + ret EnvError.NotExist + | ENOTDIR: + ret EnvError.NotDir + | ENOMEM: + ret EnvError.InsufficientMemory + |: + ret EnvError.IO + } } \ No newline at end of file diff --git a/std/env/error_windows.jule b/std/env/error_windows.jule index c784ccf5c..931a360cd 100644 --- a/std/env/error_windows.jule +++ b/std/env/error_windows.jule @@ -3,27 +3,27 @@ // license that can be found in the LICENSE file. use std::sys::{ - GetLastError, - ERROR_ACCESS_DENIED, - ERROR_FILE_NOT_FOUND, - ERROR_NOT_READY, - ERROR_INVALID_NAME, - ERROR_PATH_NOT_FOUND, + GetLastError, + ERROR_ACCESS_DENIED, + ERROR_FILE_NOT_FOUND, + ERROR_NOT_READY, + ERROR_INVALID_NAME, + ERROR_PATH_NOT_FOUND, } // Returns last os error by error number of windows. fn getLastOsErrorWindows(): EnvError { - err := GetLastError() - match err { - | ERROR_ACCESS_DENIED: - ret EnvError.Denied - | ERROR_PATH_NOT_FOUND: - ret EnvError.NotExist - | ERROR_NOT_READY: - ret EnvError.Device - | ERROR_INVALID_NAME: - ret EnvError.NotExist - |: - ret EnvError.Denied - } + err := GetLastError() + match err { + | ERROR_ACCESS_DENIED: + ret EnvError.Denied + | ERROR_PATH_NOT_FOUND: + ret EnvError.NotExist + | ERROR_NOT_READY: + ret EnvError.Device + | ERROR_INVALID_NAME: + ret EnvError.NotExist + |: + ret EnvError.Denied + } } \ No newline at end of file diff --git a/std/env/proc.jule b/std/env/proc.jule index 413a071ad..b1b40e635 100644 --- a/std/env/proc.jule +++ b/std/env/proc.jule @@ -13,12 +13,12 @@ cpp fn env(): []str // Returns command-line arguments. // Starts with the program name. fn Args(): []str { - ret cpp.args() + ret cpp.args() } // Returns envrionment variables. fn Env(): []str { - ret cpp.env() + ret cpp.env() } // Returns an absolute path name of the current working @@ -27,7 +27,7 @@ fn Env(): []str { // Possible errors: // Denied fn WorkingDir()!: str { - ret getwd() else { error(error) } + ret getwd() else { error(error) } } // Changes the current working directory to the given directory. @@ -36,8 +36,8 @@ fn WorkingDir()!: str { // Denied IO Loop LongPath NotExist NotDir InsufficientMemory // Device fn SetWorkingDir(path: str)! { - if path == "" { - error(EnvError.NotDir) - } - chdir(path) else { error(error) } + if path == "" { + error(EnvError.NotDir) + } + chdir(path) else { error(error) } } \ No newline at end of file diff --git a/std/env/proc_unix.jule b/std/env/proc_unix.jule index 519f89c64..f6d1fd93c 100644 --- a/std/env/proc_unix.jule +++ b/std/env/proc_unix.jule @@ -8,21 +8,21 @@ use sys for std::sys // Possible errors: // Denied fn getwd()!: str { - mut buf := unsafe { sys::Getcwd(nil, 0) } - if buf == nil { - error(getLastOsError()) - } - pwd := unsafe { integ::BytePtrToStr(buf) } - unsafe { integ::Free(buf) } - ret pwd + mut buf := unsafe { sys::Getcwd(nil, 0) } + if buf == nil { + error(getLastOsError()) + } + pwd := unsafe { integ::BytePtrToStr(buf) } + unsafe { integ::Free(buf) } + ret pwd } // Possible errors: // Denied IO Loop LongPath NotExist NotDir InsufficientMemory fn chdir(path: str)! { - s := integ::StrToBytes(path) - if unsafe { sys::Chdir(&s[0]) } == 0 { - ret - } - error(getLastOsError()) + s := integ::StrToBytes(path) + if unsafe { sys::Chdir(&s[0]) } == 0 { + ret + } + error(getLastOsError()) } \ No newline at end of file diff --git a/std/env/proc_windows.jule b/std/env/proc_windows.jule index 66da31235..091b44369 100644 --- a/std/env/proc_windows.jule +++ b/std/env/proc_windows.jule @@ -4,28 +4,28 @@ use integ for std::jule::integrated use std::sys::{ - MAX_PATH, - GetCurrentDirectory, - SetCurrentDirectory, + MAX_PATH, + GetCurrentDirectory, + SetCurrentDirectory, } // Possible errors: // Denied fn getwd()!: str { - let mut buf: [MAX_PATH + 1]u16 - n := unsafe { GetCurrentDirectory(u32(len(buf)), &buf[0]) } - if n == 0 { - error(getLastOsErrorWindows()) - } - ret unsafe { integ::U16PtrToStr(&buf[0]) } + let mut buf: [MAX_PATH + 1]u16 + n := unsafe { GetCurrentDirectory(u32(len(buf)), &buf[0]) } + if n == 0 { + error(getLastOsErrorWindows()) + } + ret unsafe { integ::U16PtrToStr(&buf[0]) } } // Possible errors: // Denied NotExist Device fn chdir(path: str)! { - utf16Path := integ::UTF16FromStr(path) - if unsafe { SetCurrentDirectory(&utf16Path[0]) } { - ret - } - error(getLastOsErrorWindows()) + utf16Path := integ::UTF16FromStr(path) + if unsafe { SetCurrentDirectory(&utf16Path[0]) } { + ret + } + error(getLastOsErrorWindows()) } \ No newline at end of file diff --git a/std/flag/flag.jule b/std/flag/flag.jule index ca44c4121..b01f70403 100644 --- a/std/flag/flag.jule +++ b/std/flag/flag.jule @@ -9,32 +9,32 @@ const bitSize = 0b1000000 // Common behaviors of flags. trait CommonFlag { - // Returns name of flag. - fn Name(self): str + // Returns name of flag. + fn Name(self): str - // Returns short name of flag. - fn Short(self): rune + // Returns short name of flag. + fn Short(self): rune - // Returns description of flag. - fn What(self): str + // Returns description of flag. + fn What(self): str - // Resets data to default. - fn Reset(mut self) + // Resets data to default. + fn Reset(mut self) } struct Flag[T] { - name: str - short: rune - default: T - what: str - data: &T + name: str + short: rune + default: T + what: str + data: &T } impl CommonFlag for Flag { - fn Name(self): str { ret self.name } - fn What(self): str { ret self.what } - fn Reset(mut self) { *self.data = self.default } - fn Short(self): rune { ret self.short } + fn Name(self): str { ret self.name } + fn What(self): str { ret self.what } + fn Reset(mut self) { *self.data = self.default } + fn Short(self): rune { ret self.short } } // Flag for i64 type. @@ -54,245 +54,245 @@ type StrFlag: &Flag[str] // Flag parser for command-line arguments. struct FlagSet { - flags: []CommonFlag + flags: []CommonFlag } impl FlagSet { - // Returns new flagset. - static fn New(): &FlagSet { - ret &FlagSet{ - flags: make([]CommonFlag, 0, 20), - } - } + // Returns new flagset. + static fn New(): &FlagSet { + ret &FlagSet{ + flags: make([]CommonFlag, 0, 20), + } + } } impl FlagSet { - // Returns flag by name, returns nil if not exist. - fn FindFlag(mut self, name: str): CommonFlag { - for (_, mut flag) in self.flags { - if flag.Name() == name { - ret flag - } - } - ret nil - } - - // Returns flag by short name, returns nil if not exist. - fn FindFlagShort(mut self, name: rune): CommonFlag { - for (_, mut flag) in self.flags { - if flag.Short() == name { - ret flag - } - } - ret nil - } - - // Returns all flags. - fn Flags(mut self): []CommonFlag { - ret self.flags - } - - // Parse arguments and process flags. - // Returns non-flag content. - // Exceptional always is string and holds error message. - // - // Syntax: - // Long names can be used with double dash (--). Short names can be - // used with a single dash (-). When Boolean flags are used, they use - // the opposite of their default values. Floating-point values are the - // same as the `parse_float` function provided by std::conv package. - // Decimal, octal, binary and hexadecimal formats are supported for - // signed and unsigned integer types. String types accept values ​​directly. - // - // Octal values are represented by starts with 0o or 0 prefix. - // Hexadecimal values are represented by starts with 0x prefix. - // Binary values are represented by starts with 0b prefix. - // - // A space is required to give a value. When a single dash (-) is used, - // all following characters are considered short names and thus collective - // use is allowed. If the short name flags used need values, the values ​ - // should follow respectively. - fn Parse(mut self, args: []str)!: []str { - mut ap := argParser{ - set: self, - args: unsafe { *(&args) }, - } - ap.parse() else { error(error) } - ret ap.content - } - - // Resets all flags to default value. - fn Reset(mut self) { - for _, f in self.flags { - f.Reset() - } - } - - fn addFlagCommon[T](mut self, name: str, short: rune, what: str): &Flag[T] { - if self.FindFlag(name) != nil { - panic("std::flag: FlagSet.Add[T]: flag is already exist in this name: " + name) - } - - if short != 0 && self.FindFlagShort(short) != nil { - panic("std::flag: FlagSet.Add[T]: flag is already exist in this short name: " + str(short)) - } - - mut flag := &Flag[T]{ - name: name, - short: short, - what: what, - } - self.flags = append(self.flags, flag) - ret flag - } - - // Adds new flag and returns allocated reference variable. - // Panics if name or short name is alreadys exist. - // Zero (0) short names will be ignored. - // Panics if used unsupported type. - // - // Supported types are: - // - i64 - // - u64 - // - f64 - // - str - // - bool - fn Add[T: i64 | u64 | f64 | bool | str](mut self, name: str, short: rune, default: T, what: str): &T { - mut flag := self.addFlagCommon[T](name, short, what) - flag.data = new(T, default) - ret flag.data - } - - // Same with add method but do not allocates new reference, uses existing. - fn AddVar[T: i64 | u64 | f64 | bool | str](mut self, mut var: &T, name: str, short: rune, what: str) { - if var == nil { - panic("std::flag: FlatSet.AddVar[T]: variable is nil") - } - mut flag := self.addFlagCommon[T](name, short, what) - flag.default = *var - flag.data = var - } + // Returns flag by name, returns nil if not exist. + fn FindFlag(mut self, name: str): CommonFlag { + for (_, mut flag) in self.flags { + if flag.Name() == name { + ret flag + } + } + ret nil + } + + // Returns flag by short name, returns nil if not exist. + fn FindFlagShort(mut self, name: rune): CommonFlag { + for (_, mut flag) in self.flags { + if flag.Short() == name { + ret flag + } + } + ret nil + } + + // Returns all flags. + fn Flags(mut self): []CommonFlag { + ret self.flags + } + + // Parse arguments and process flags. + // Returns non-flag content. + // Exceptional always is string and holds error message. + // + // Syntax: + // Long names can be used with double dash (--). Short names can be + // used with a single dash (-). When Boolean flags are used, they use + // the opposite of their default values. Floating-point values are the + // same as the `parse_float` function provided by std::conv package. + // Decimal, octal, binary and hexadecimal formats are supported for + // signed and unsigned integer types. String types accept values ​​directly. + // + // Octal values are represented by starts with 0o or 0 prefix. + // Hexadecimal values are represented by starts with 0x prefix. + // Binary values are represented by starts with 0b prefix. + // + // A space is required to give a value. When a single dash (-) is used, + // all following characters are considered short names and thus collective + // use is allowed. If the short name flags used need values, the values ​ + // should follow respectively. + fn Parse(mut self, args: []str)!: []str { + mut ap := argParser{ + set: self, + args: unsafe { *(&args) }, + } + ap.parse() else { error(error) } + ret ap.content + } + + // Resets all flags to default value. + fn Reset(mut self) { + for _, f in self.flags { + f.Reset() + } + } + + fn addFlagCommon[T](mut self, name: str, short: rune, what: str): &Flag[T] { + if self.FindFlag(name) != nil { + panic("std::flag: FlagSet.Add[T]: flag is already exist in this name: " + name) + } + + if short != 0 && self.FindFlagShort(short) != nil { + panic("std::flag: FlagSet.Add[T]: flag is already exist in this short name: " + str(short)) + } + + mut flag := &Flag[T]{ + name: name, + short: short, + what: what, + } + self.flags = append(self.flags, flag) + ret flag + } + + // Adds new flag and returns allocated reference variable. + // Panics if name or short name is alreadys exist. + // Zero (0) short names will be ignored. + // Panics if used unsupported type. + // + // Supported types are: + // - i64 + // - u64 + // - f64 + // - str + // - bool + fn Add[T: i64 | u64 | f64 | bool | str](mut self, name: str, short: rune, default: T, what: str): &T { + mut flag := self.addFlagCommon[T](name, short, what) + flag.data = new(T, default) + ret flag.data + } + + // Same with add method but do not allocates new reference, uses existing. + fn AddVar[T: i64 | u64 | f64 | bool | str](mut self, mut var: &T, name: str, short: rune, what: str) { + if var == nil { + panic("std::flag: FlatSet.AddVar[T]: variable is nil") + } + mut flag := self.addFlagCommon[T](name, short, what) + flag.default = *var + flag.data = var + } } struct argParser { - set: FlagSet - args: []str - content: []str - i: int + set: FlagSet + args: []str + content: []str + i: int } impl argParser { - fn parseInteger[T](self, &s: str, parser: fn(s: str, base: int): (T, bool)): (x: T, ok: bool) { - match { - | s == "": - ret 0, false - | strings::HasPrefix(s, "0x"): // Hexadecimal - x, ok = parser(s[2:], 0b00010000) - | strings::HasPrefix(s, "0b"): // Binary - x, ok = parser(s[2:], 0b10) - | strings::HasPrefix(s, "0o"): // Octal - x, ok = parser(s[2:], 0b1000) - | s[0] == '0': // Octal - x, ok = parser(s[1:], 0b1000) - |: - // Decimal - x, ok = parser(s, 0b1010) - } - ret - } - - fn getData(mut self): str { - if self.i+1 >= len(self.args) { - ret "" - } - self.i++ - ret self.args[self.i] - } - - fn processFlag(mut self, mut &flag: CommonFlag)! { - match type flag { - | BoolFlag: - mut bf := BoolFlag(flag) - *bf.data = !bf.default - ret - } - - data := self.getData() - if data == "" { - error("--" + flag.Name() + ": expression missing") - } - - match type flag { - | IntFlag: - mut intf := IntFlag(flag) - (*intf.data), ok := self.parseInteger[i64](data, fn(s: str, base: int): (i64, bool) { - ret conv::ParseInt(s, base, bitSize) else { ret 0, false }, true - }) - if !ok { - error("--" + flag.Name() + ": expression must be valid signed integer") - } - | UintFlag: - mut uintf := UintFlag(flag) - (*uintf.data), ok := self.parseInteger[u64](data, fn(s: str, base: int): (u64, bool) { - ret conv::ParseUint(s, base, bitSize) else { ret 0, false }, true - }) - if !ok { - error("--" + flag.Name() + ": expression must be valid unsigned integer") - } - | FloatFlag: - mut ff := FloatFlag(flag) - *ff.data = conv::ParseFloat(data, bitSize) else { - error("--" + flag.Name() + ": expression must be valid floating-point") - } - | StrFlag: - *StrFlag(flag).data = data - } - } - - fn singleDash(mut self, &arg: str)! { - if len(arg) == 1 { // Just dash. - error(arg + ": missing argument") - } - // Start at 1 to skip dash. - for _, r in []rune(arg[1:]) { - mut flag := self.set.FindFlagShort(r) - if flag == nil { - error(arg + ": flag is not exist: " + str(r)) - } - self.processFlag(flag) else { error(error) } - } - } - - fn doubleDash(mut self, &arg: str)! { - if len(arg) == 2 { // Just dash. - error(arg + ": missing argument") - } - mut flag := self.set.FindFlag(arg[2:]) // Start at 2 to skip dashes. - if flag == nil { - error(arg + ": flag is not exist") - } - self.processFlag(flag) else { error(error) } - } - - fn tryArg(mut self)! { - arg := self.args[self.i] - if len(self.args) == 0 { - ret - } - if arg[0] == '-' { - if len(arg) > 1 && arg[1] == '-' { - self.doubleDash(arg) else { error(error) } - ret - } - self.singleDash(arg) else { error(error) } - ret - } - self.content = append(self.content, arg) - } - - fn parse(mut self)! { - for self.i < len(self.args); self.i++ { - self.tryArg() else { error(error) } - } - } + fn parseInteger[T](self, &s: str, parser: fn(s: str, base: int): (T, bool)): (x: T, ok: bool) { + match { + | s == "": + ret 0, false + | strings::HasPrefix(s, "0x"): // Hexadecimal + x, ok = parser(s[2:], 0b00010000) + | strings::HasPrefix(s, "0b"): // Binary + x, ok = parser(s[2:], 0b10) + | strings::HasPrefix(s, "0o"): // Octal + x, ok = parser(s[2:], 0b1000) + | s[0] == '0': // Octal + x, ok = parser(s[1:], 0b1000) + |: + // Decimal + x, ok = parser(s, 0b1010) + } + ret + } + + fn getData(mut self): str { + if self.i+1 >= len(self.args) { + ret "" + } + self.i++ + ret self.args[self.i] + } + + fn processFlag(mut self, mut &flag: CommonFlag)! { + match type flag { + | BoolFlag: + mut bf := BoolFlag(flag) + *bf.data = !bf.default + ret + } + + data := self.getData() + if data == "" { + error("--" + flag.Name() + ": expression missing") + } + + match type flag { + | IntFlag: + mut intf := IntFlag(flag) + (*intf.data), ok := self.parseInteger[i64](data, fn(s: str, base: int): (i64, bool) { + ret conv::ParseInt(s, base, bitSize) else { ret 0, false }, true + }) + if !ok { + error("--" + flag.Name() + ": expression must be valid signed integer") + } + | UintFlag: + mut uintf := UintFlag(flag) + (*uintf.data), ok := self.parseInteger[u64](data, fn(s: str, base: int): (u64, bool) { + ret conv::ParseUint(s, base, bitSize) else { ret 0, false }, true + }) + if !ok { + error("--" + flag.Name() + ": expression must be valid unsigned integer") + } + | FloatFlag: + mut ff := FloatFlag(flag) + *ff.data = conv::ParseFloat(data, bitSize) else { + error("--" + flag.Name() + ": expression must be valid floating-point") + } + | StrFlag: + *StrFlag(flag).data = data + } + } + + fn singleDash(mut self, &arg: str)! { + if len(arg) == 1 { // Just dash. + error(arg + ": missing argument") + } + // Start at 1 to skip dash. + for _, r in []rune(arg[1:]) { + mut flag := self.set.FindFlagShort(r) + if flag == nil { + error(arg + ": flag is not exist: " + str(r)) + } + self.processFlag(flag) else { error(error) } + } + } + + fn doubleDash(mut self, &arg: str)! { + if len(arg) == 2 { // Just dash. + error(arg + ": missing argument") + } + mut flag := self.set.FindFlag(arg[2:]) // Start at 2 to skip dashes. + if flag == nil { + error(arg + ": flag is not exist") + } + self.processFlag(flag) else { error(error) } + } + + fn tryArg(mut self)! { + arg := self.args[self.i] + if len(self.args) == 0 { + ret + } + if arg[0] == '-' { + if len(arg) > 1 && arg[1] == '-' { + self.doubleDash(arg) else { error(error) } + ret + } + self.singleDash(arg) else { error(error) } + ret + } + self.content = append(self.content, arg) + } + + fn parse(mut self)! { + for self.i < len(self.args); self.i++ { + self.tryArg() else { error(error) } + } + } } \ No newline at end of file diff --git a/std/fmt/format.jule b/std/fmt/format.jule index 6aa9e4fd0..c96b1e97a 100644 --- a/std/fmt/format.jule +++ b/std/fmt/format.jule @@ -29,5 +29,5 @@ use fmt for std::internal::fmt // - format("{} {}") = "{} {}" // - format("{} is the {}", "Pi Number") = "Pi Number is the {}" fn Format(fmt: str, args: ...any): str { - ret unsafe::StrFromBytes(fmt::Format(fmt, args...)) + ret unsafe::StrFromBytes(fmt::Format(fmt, args...)) } \ No newline at end of file diff --git a/std/fmt/print.jule b/std/fmt/print.jule index a5b9c87ad..8af8162fd 100644 --- a/std/fmt/print.jule +++ b/std/fmt/print.jule @@ -11,57 +11,57 @@ use std::internal::strings::{StrBuilder} // Prints arguments to file by default formatting. // See documentation of format function for formatting. fn Fprint(mut f: &File, args: ...any) { - mut sb := StrBuilder.New(20) - for _, arg in args { - fmt::FmtByDefault(sb, arg) - f.Write(unsafe { sb.Buf() }) else { - panic("std::fmt: Fprint: error occurs when printing") - } - // Do not use the [Clear] method to avoid making new allocations. - // The buffer used temporarily, so just clear the length, not capacity. - unsafe { sb.SetBuf(sb.Buf()[:0]) } - } + mut sb := StrBuilder.New(20) + for _, arg in args { + fmt::FmtByDefault(sb, arg) + f.Write(unsafe { sb.Buf() }) else { + panic("std::fmt: Fprint: error occurs when printing") + } + // Do not use the [Clear] method to avoid making new allocations. + // The buffer used temporarily, so just clear the length, not capacity. + unsafe { sb.SetBuf(sb.Buf()[:0]) } + } } // Prints arguments to file by default formatting. // Prints new-line after arguments. // See documentation of format function for formatting. fn Fprintln(mut f: &File, args: ...any) { - Fprint(f, args...) - Fprintf(f, "\n") + Fprint(f, args...) + Fprintf(f, "\n") } // Prints result of formatting to file. // See documentation of format function for formatting. fn Fprintf(mut f: &File, fmt: str, args: ...any) { - format := fmt::Format(fmt, args...) - f.Write(format) else { - panic("std::fmt: Fprintf: error occurs when printing") - } + format := fmt::Format(fmt, args...) + f.Write(format) else { + panic("std::fmt: Fprintf: error occurs when printing") + } } // Prints result of formatting to stdout. // See documentation of format function for formatting. fn Printf(fmt: str, args: ...any) { - Fprintf(io::Stdout().File(), fmt, args...) + Fprintf(io::Stdout().File(), fmt, args...) } // Prints arguments by default formatting to stdout. fn Print(args: ...any) { - Fprint(io::Stdout().File(), args...) + Fprint(io::Stdout().File(), args...) } // Prints arguments by default formatting to stdout. // Prints new-line after arguments. fn Println(args: ...any) { - Fprintln(io::Stdout().File(), args...) + Fprintln(io::Stdout().File(), args...) } // Returns string result of arguments by default formatting. fn Sprint(args: ...any): str { - mut buf := StrBuilder.New(100) - for _, arg in args { - fmt::FmtByDefault(buf, arg) - } - ret buf.Str() + mut buf := StrBuilder.New(100) + for _, arg in args { + fmt::FmtByDefault(buf, arg) + } + ret buf.Str() } \ No newline at end of file diff --git a/std/fs/dir.jule b/std/fs/dir.jule index f2f7e4ba6..60ea7a2f7 100644 --- a/std/fs/dir.jule +++ b/std/fs/dir.jule @@ -4,8 +4,8 @@ // Directory entry. struct DirEntry { - Name: str - Stat: &Status + Name: str + Stat: &Status } // Directory. diff --git a/std/fs/dir_unix.jule b/std/fs/dir_unix.jule index 405594a15..5496a4602 100644 --- a/std/fs/dir_unix.jule +++ b/std/fs/dir_unix.jule @@ -7,53 +7,53 @@ use integ for std::jule::integrated use sys for std::sys impl Directory { - // Reads the named directory and returs all its directory entries can read. - // - // Possible errors: - // Denied InvalidDescriptor PerProcessLimit SystemWideLimit - // NotExist InsufficientMemory NotDir - static fn Read(path: str)!: (dirents: []&DirEntry) { - s := integ::StrToBytes(path) - mut dir := unsafe { sys::Opendir(&s[0]) } - if dir == nil { - error(getLastFsError()) - } - for { - dirent := unsafe { sys::Readdir(dir) } - if dirent == nil { - break - } - name := unsafe { integ::BytePtrToStr((*u8)(dirent.d_name)) } - mut stat := Status.Of(path::Join(path, name)) else { error(error) } - dirents = append(dirents, &DirEntry{ - Name: name, - Stat: stat, - }) - } - _ = unsafe { sys::Closedir(dir) } - ret - } + // Reads the named directory and returs all its directory entries can read. + // + // Possible errors: + // Denied InvalidDescriptor PerProcessLimit SystemWideLimit + // NotExist InsufficientMemory NotDir + static fn Read(path: str)!: (dirents: []&DirEntry) { + s := integ::StrToBytes(path) + mut dir := unsafe { sys::Opendir(&s[0]) } + if dir == nil { + error(getLastFsError()) + } + for { + dirent := unsafe { sys::Readdir(dir) } + if dirent == nil { + break + } + name := unsafe { integ::BytePtrToStr((*u8)(dirent.d_name)) } + mut stat := Status.Of(path::Join(path, name)) else { error(error) } + dirents = append(dirents, &DirEntry{ + Name: name, + Stat: stat, + }) + } + _ = unsafe { sys::Closedir(dir) } + ret + } - // Creates directory. - // - // Possible errors: Denied Exist ReadOnly NoSpace - static fn Create(path: str)! { - // NOTICE - // Also can has EMLINK error-code. - // Make sure this situation should documented or not. - s := integ::StrToBytes(path) - if unsafe { sys::Mkdir(&s[0], 0700) } != 0 { - error(getLastFsError()) - } - } + // Creates directory. + // + // Possible errors: Denied Exist ReadOnly NoSpace + static fn Create(path: str)! { + // NOTICE + // Also can has EMLINK error-code. + // Make sure this situation should documented or not. + s := integ::StrToBytes(path) + if unsafe { sys::Mkdir(&s[0], 0700) } != 0 { + error(getLastFsError()) + } + } - // Removes empty directory. - // - // Possible errors: Denined NotExist NotEmpty SyncIO IO Loop NotDir - static fn Remove(path: str)! { - s := integ::StrToBytes(path) - if unsafe { sys::Rmdir(&s[0]) } != 0 { - error(getLastFsError()) - } - } + // Removes empty directory. + // + // Possible errors: Denined NotExist NotEmpty SyncIO IO Loop NotDir + static fn Remove(path: str)! { + s := integ::StrToBytes(path) + if unsafe { sys::Rmdir(&s[0]) } != 0 { + error(getLastFsError()) + } + } } \ No newline at end of file diff --git a/std/fs/dir_windows.jule b/std/fs/dir_windows.jule index 2a9576836..5c6af48e0 100644 --- a/std/fs/dir_windows.jule +++ b/std/fs/dir_windows.jule @@ -7,53 +7,53 @@ use integ for std::jule::integrated use sys for std::sys impl Directory { - // Reads the named directory and returs all its directory entries can read. - // - // Possible errors: - // Denied InvalidDescriptor PerProcessLimit SystemWideLimit - // NotExist InsufficientMemory NotDir - static fn Read(path: str)!: (dirents: []&DirEntry) { - utf16Path := integ::UTF16FromStr(path::Join(path, "*")) - mut data := sys::Win32FindData{} - handle := unsafe { sys::FindFirstFile(&utf16Path[0], &data) } - if handle == sys::InvalidHandle { - ret - } - for { - mut entry := &DirEntry{ - Name: unsafe { integ::U16PtrToStr((*u16)(data.cFileName)) }, - } - entry.Stat = Status.Of(path::Join(path, entry.Name)) else { error(error) } - dirents = append(dirents, entry) - if unsafe { sys::FindNextFile(handle, &data) } == 0 { - break - } - } - sys::FindClose(handle) - ret - } + // Reads the named directory and returs all its directory entries can read. + // + // Possible errors: + // Denied InvalidDescriptor PerProcessLimit SystemWideLimit + // NotExist InsufficientMemory NotDir + static fn Read(path: str)!: (dirents: []&DirEntry) { + utf16Path := integ::UTF16FromStr(path::Join(path, "*")) + mut data := sys::Win32FindData{} + handle := unsafe { sys::FindFirstFile(&utf16Path[0], &data) } + if handle == sys::InvalidHandle { + ret + } + for { + mut entry := &DirEntry{ + Name: unsafe { integ::U16PtrToStr((*u16)(data.cFileName)) }, + } + entry.Stat = Status.Of(path::Join(path, entry.Name)) else { error(error) } + dirents = append(dirents, entry) + if unsafe { sys::FindNextFile(handle, &data) } == 0 { + break + } + } + sys::FindClose(handle) + ret + } - // Creates directory. - // - // Possible errors: Denied Exist ReadOnly NoSpace - static fn Create(path: str)! { - // NOTICE - // Also can has EMLINK error-code. - // Make sure this situation should documented or not. + // Creates directory. + // + // Possible errors: Denied Exist ReadOnly NoSpace + static fn Create(path: str)! { + // NOTICE + // Also can has EMLINK error-code. + // Make sure this situation should documented or not. - utf16Path := integ::UTF16FromStr(path) - if unsafe { !std::sys::CreateDirectory(&utf16Path[0]) } { - error(getLastFsError()) - } - } + utf16Path := integ::UTF16FromStr(path) + if unsafe { !std::sys::CreateDirectory(&utf16Path[0]) } { + error(getLastFsError()) + } + } - // Removes empty directory. - // - // Possible errors: Denined NotExist NotEmpty SyncIO IO Loop NotDir - static fn Remove(path: str)! { - utf16Path := integ::UTF16FromStr(path) - if unsafe { !std::sys::RemoveDirectory(&utf16Path[0]) } { - error(getLastFsError()) - } - } + // Removes empty directory. + // + // Possible errors: Denined NotExist NotEmpty SyncIO IO Loop NotDir + static fn Remove(path: str)! { + utf16Path := integ::UTF16FromStr(path) + if unsafe { !std::sys::RemoveDirectory(&utf16Path[0]) } { + error(getLastFsError()) + } + } } \ No newline at end of file diff --git a/std/fs/error.jule b/std/fs/error.jule index 78d87bc3d..14ae3607d 100644 --- a/std/fs/error.jule +++ b/std/fs/error.jule @@ -3,131 +3,131 @@ // license that can be found in the LICENSE file. use std::sys::{ - GetLastErrno, - EACCES, - EIO, - ELOOP, - ENAMETOOLONG, - ENOENT, - ENOTDIR, - EOVERFLOW, - EBADF, - EMFILE, - ENFILE, - ENOMEM, - EEXIST, - EINTR, - EINVAL, - EISDIR, - ENOSR, - ENOSPC, - ENXIO, - EROFS, - EAGAIN, - ETXTBSY, - EFBIG, - EPIPE, - ERANGE, - ESPIPE, - ENOBUFS, - EBADMSG, - ENOTEMPTY, - EBUSY, + GetLastErrno, + EACCES, + EIO, + ELOOP, + ENAMETOOLONG, + ENOENT, + ENOTDIR, + EOVERFLOW, + EBADF, + EMFILE, + ENFILE, + ENOMEM, + EEXIST, + EINTR, + EINVAL, + EISDIR, + ENOSR, + ENOSPC, + ENXIO, + EROFS, + EAGAIN, + ETXTBSY, + EFBIG, + EPIPE, + ERANGE, + ESPIPE, + ENOBUFS, + EBADMSG, + ENOTEMPTY, + EBUSY, } // File system error codes. enum FsError { - Denied, // Search permission is denied for a component of the path prefix - IO, // Input/Output error, an error occurred while reading from the file system - Loop, // A loop exists in symbolic links encountered during resolution of the path argument - LongPath, // The length of the path argument exceeds maxium path length or a pathname component is longer than maximum name length - NotExist, // A component of path does not name an existing file or path is an empty string - NotDir, // A component of the path prefix is not a directory - Overflow, // The file size in bytes or the number of blocks allocated to the file or the file serial number cannot be represented correctly in the structure pointed to by buf - InvalidDescriptor, // fd is not a valid file descriptor opened for reading - PerProcessLimit, // The per-process limit on the number of open file descriptors has been reached - SystemWideLimit, // The system-wide limit on the total number of open files has been reached - InsufficientMemory, // Insufficient memory to complete the operation - Exist, // A component of path does name an existing file - Signal, // A signal was caught during - SyncIO, // The implementation does not support synchronized I/O for this file - IsDir, // The named file is a directory and flag includes O_WRONLY or O_RDWR - UnableStream, // The path argument names a STREAMS-based file and the system is unable to allocate a STREAM - NoSpace, // There is no space on the drive - Device, // Device did not respond - ReadOnly, // Read-only filesystem - Retry, // Resource temporarily unavailable - Busy, // File is busy - Big, // File too large - Pipe, // Broken pipe - Range, // Input is outside the range - Seek, // Illegal seek - Buffer, // No buffer space available - BadMessage, // Not a data message - NotEmpty, // Not empty + Denied, // Search permission is denied for a component of the path prefix + IO, // Input/Output error, an error occurred while reading from the file system + Loop, // A loop exists in symbolic links encountered during resolution of the path argument + LongPath, // The length of the path argument exceeds maxium path length or a pathname component is longer than maximum name length + NotExist, // A component of path does not name an existing file or path is an empty string + NotDir, // A component of the path prefix is not a directory + Overflow, // The file size in bytes or the number of blocks allocated to the file or the file serial number cannot be represented correctly in the structure pointed to by buf + InvalidDescriptor, // fd is not a valid file descriptor opened for reading + PerProcessLimit, // The per-process limit on the number of open file descriptors has been reached + SystemWideLimit, // The system-wide limit on the total number of open files has been reached + InsufficientMemory, // Insufficient memory to complete the operation + Exist, // A component of path does name an existing file + Signal, // A signal was caught during + SyncIO, // The implementation does not support synchronized I/O for this file + IsDir, // The named file is a directory and flag includes O_WRONLY or O_RDWR + UnableStream, // The path argument names a STREAMS-based file and the system is unable to allocate a STREAM + NoSpace, // There is no space on the drive + Device, // Device did not respond + ReadOnly, // Read-only filesystem + Retry, // Resource temporarily unavailable + Busy, // File is busy + Big, // File too large + Pipe, // Broken pipe + Range, // Input is outside the range + Seek, // Illegal seek + Buffer, // No buffer space available + BadMessage, // Not a data message + NotEmpty, // Not empty } // Returns last filesystem error by errno. fn getLastFsError(): FsError { - err := GetLastErrno() - match err { - | EACCES: - ret FsError.Denied - | EIO: - ret FsError.IO - | ELOOP: - ret FsError.Loop - | ENAMETOOLONG: - ret FsError.LongPath - | ENOENT: - ret FsError.NotExist - | ENOTDIR: - ret FsError.NotDir - | EOVERFLOW: - ret FsError.Overflow - | EBADF: - ret FsError.InvalidDescriptor - | EMFILE: - ret FsError.PerProcessLimit - | ENFILE: - ret FsError.SystemWideLimit - | ENOMEM: - ret FsError.InsufficientMemory - | EEXIST: - ret FsError.Exist - | EINTR: - ret FsError.Signal - | EINVAL: - ret FsError.SyncIO - | EISDIR: - ret FsError.IsDir - | ENOSR: - ret FsError.UnableStream - | ENOSPC: - ret FsError.NoSpace - | ENXIO: - ret FsError.Device - | EROFS: - ret FsError.ReadOnly - | EAGAIN: - ret FsError.Retry - | ETXTBSY | EBUSY: - ret FsError.Busy - | EFBIG: - ret FsError.Big - | EPIPE: - ret FsError.Pipe - | ERANGE: - ret FsError.Range - | ESPIPE: - ret FsError.Seek - | ENOBUFS: - ret FsError.Buffer - | EBADMSG: - ret FsError.BadMessage - | ENOTEMPTY: - ret FsError.NotEmpty - |: - ret FsError.IO - } + err := GetLastErrno() + match err { + | EACCES: + ret FsError.Denied + | EIO: + ret FsError.IO + | ELOOP: + ret FsError.Loop + | ENAMETOOLONG: + ret FsError.LongPath + | ENOENT: + ret FsError.NotExist + | ENOTDIR: + ret FsError.NotDir + | EOVERFLOW: + ret FsError.Overflow + | EBADF: + ret FsError.InvalidDescriptor + | EMFILE: + ret FsError.PerProcessLimit + | ENFILE: + ret FsError.SystemWideLimit + | ENOMEM: + ret FsError.InsufficientMemory + | EEXIST: + ret FsError.Exist + | EINTR: + ret FsError.Signal + | EINVAL: + ret FsError.SyncIO + | EISDIR: + ret FsError.IsDir + | ENOSR: + ret FsError.UnableStream + | ENOSPC: + ret FsError.NoSpace + | ENXIO: + ret FsError.Device + | EROFS: + ret FsError.ReadOnly + | EAGAIN: + ret FsError.Retry + | ETXTBSY | EBUSY: + ret FsError.Busy + | EFBIG: + ret FsError.Big + | EPIPE: + ret FsError.Pipe + | ERANGE: + ret FsError.Range + | ESPIPE: + ret FsError.Seek + | ENOBUFS: + ret FsError.Buffer + | EBADMSG: + ret FsError.BadMessage + | ENOTEMPTY: + ret FsError.NotEmpty + |: + ret FsError.IO + } } \ No newline at end of file diff --git a/std/fs/file.jule b/std/fs/file.jule index 74f1f21b0..f921e179e 100644 --- a/std/fs/file.jule +++ b/std/fs/file.jule @@ -7,23 +7,23 @@ use sys for std::sys // Seek whence values. enum Seek: int { - Set: 0, // Seek relative to the origin of the file - Cur: 1, // Seek relative to the current offset - End: 2, // Seek relative to the end + Set: 0, // Seek relative to the origin of the file + Cur: 1, // Seek relative to the current offset + End: 2, // Seek relative to the end } // Flags to open wrapping those of the underlying system. // Not all flags may be implemented on a given system. // Exactly one of Rdonly, Wronly, or Rdwr must be specified. enum OFlag: int { - Rdonly: sys::O_RDONLY, // Open the file read-only - Wronly: sys::O_WRONLY, // Open the file write-only - Rdwr: sys::O_RDWR, // Open the file read-write - Append: sys::O_APPEND, // Append data to the file when writing - Create: sys::O_CREAT, // Create a new file if none exists - Excl: sys::O_EXCL, // Used with OFlag.Create, file must not exist - Sync: sys::O_SYNC, // Open for synchronous I/O - Trunc: sys::O_TRUNC, // Truncate regular writable file when opened + Rdonly: sys::O_RDONLY, // Open the file read-only + Wronly: sys::O_WRONLY, // Open the file write-only + Rdwr: sys::O_RDWR, // Open the file read-write + Append: sys::O_APPEND, // Append data to the file when writing + Create: sys::O_CREAT, // Create a new file if none exists + Excl: sys::O_EXCL, // Used with OFlag.Create, file must not exist + Sync: sys::O_SYNC, // Open for synchronous I/O + Trunc: sys::O_TRUNC, // Truncate regular writable file when opened } // The file stream handle. @@ -37,103 +37,103 @@ enum OFlag: int { // for console handlers depending on the operating system. // For example, Windows has an overhead for UTF-16 processing. struct File { - handle: uintptr + handle: uintptr } impl File { - // Returns new &File by handle. - static fn New(handle: uintptr): &File { - ret &File{ - handle: handle, - } - } + // Returns new &File by handle. + static fn New(handle: uintptr): &File { + ret &File{ + handle: handle, + } + } - // Creates or truncates the named file. If the file already exists, - // it is truncated. If the file does not exist, it is created with mode 0666 - // (before umask). If successful, methods on the returned File can - // be used for I/O; the associated file descriptor has mode OFlag.Rdwr. - static fn Create(path: str)!: &File { - ret File.Open(path, OFlag.Rdwr | OFlag.Create | OFlag.Trunc, 0666) else { error(error) } - } + // Creates or truncates the named file. If the file already exists, + // it is truncated. If the file does not exist, it is created with mode 0666 + // (before umask). If successful, methods on the returned File can + // be used for I/O; the associated file descriptor has mode OFlag.Rdwr. + static fn Create(path: str)!: &File { + ret File.Open(path, OFlag.Rdwr | OFlag.Create | OFlag.Trunc, 0666) else { error(error) } + } - // Reads bytes of file. - // First, learns byte-size of file. - // Then reads bytes and returns buffer. - // - // Possible errors: - // Denied Exist Signal SyncIO IO IsDir Loop PerProcessLimit LongPath - // SystemWideLimit NotExist UnableStream NoSpace NotDir Device Overflow - // ReadOnly Retry Busy Device Seek InsufficientMemory Buffer - static fn Read(path: str)!: []byte { - s := Status.Of(path) else { error(error) } - if !s.IsReg() { - error(FsError.IsDir) - } + // Reads bytes of file. + // First, learns byte-size of file. + // Then reads bytes and returns buffer. + // + // Possible errors: + // Denied Exist Signal SyncIO IO IsDir Loop PerProcessLimit LongPath + // SystemWideLimit NotExist UnableStream NoSpace NotDir Device Overflow + // ReadOnly Retry Busy Device Seek InsufficientMemory Buffer + static fn Read(path: str)!: []byte { + s := Status.Of(path) else { error(error) } + if !s.IsReg() { + error(FsError.IsDir) + } - mut sz := int(s.Size()) - if sz != int(s.Size()) { - sz = 0 - } - // Following information adopted from Go; - // If a file claims a small size, read at least 512 bytes. - // In particular, files in Linux's /proc claim size 0 but - // then do not work right if read in small pieces, - // so an initial read of 1 byte would not work correctly. - if sz < 1<<9 { - sz = 1<<9 - } + mut sz := int(s.Size()) + if sz != int(s.Size()) { + sz = 0 + } + // Following information adopted from Go; + // If a file claims a small size, read at least 512 bytes. + // In particular, files in Linux's /proc claim size 0 but + // then do not work right if read in small pieces, + // so an initial read of 1 byte would not work correctly. + if sz < 1<<9 { + sz = 1 << 9 + } - mut f := File.Open(path, OFlag.Rdonly, 0) else { error(error) } - mut buf := make([]byte, sz) - mut n := 0 - for n < sz { - rn := f.Read(buf[n:]) else { error(error) } - if rn == 0 { - break - } - n += rn - } - f.Close() else { error(error) } - ret buf[:n] - } + mut f := File.Open(path, OFlag.Rdonly, 0) else { error(error) } + mut buf := make([]byte, sz) + mut n := 0 + for n < sz { + rn := f.Read(buf[n:]) else { error(error) } + if rn == 0 { + break + } + n += rn + } + f.Close() else { error(error) } + ret buf[:n] + } - // Writes data to the named file, creating it if necessary. - // If the file does not exist, creates it with permissions perm (before umask); - // otherwise truncates it before writing, without changing permissions. - // Since requires multiple system calls to complete, a failure mid-operation - // can leave the file in a partially written state. - static fn Write(path: str, data: []byte, perm: int)! { - mut f := File.Open(path, OFlag.Wronly | OFlag.Create | OFlag.Trunc, perm) else { error(error) } - mut n := 0 - for n < len(data) { - n += f.Write(data[n:]) else { error(error) } - } - f.Close() else { error(error) } - } + // Writes data to the named file, creating it if necessary. + // If the file does not exist, creates it with permissions perm (before umask); + // otherwise truncates it before writing, without changing permissions. + // Since requires multiple system calls to complete, a failure mid-operation + // can leave the file in a partially written state. + static fn Write(path: str, data: []byte, perm: int)! { + mut f := File.Open(path, OFlag.Wronly | OFlag.Create | OFlag.Trunc, perm) else { error(error) } + mut n := 0 + for n < len(data) { + n += f.Write(data[n:]) else { error(error) } + } + f.Close() else { error(error) } + } } impl File { - // Sets offset to next Read/Write operation and returns the new offset. - // whence: 0 (Seek.Set) means, relative to the origin of the file, 1 (Seek.Cur) - // means relative to the current offset, and 2 (Seek.End) means relative to end. - // - // Possible errors: - // InvalidDescriptor SyncIO Overflow Seek - fn Seek(mut self, offset: int, origin: Seek)!: int { - pos := sys::Seek(int(self.handle), offset, int(origin)) - if pos == -1 { - error(getLastFsError()) - } - ret pos - } + // Sets offset to next Read/Write operation and returns the new offset. + // whence: 0 (Seek.Set) means, relative to the origin of the file, 1 (Seek.Cur) + // means relative to the current offset, and 2 (Seek.End) means relative to end. + // + // Possible errors: + // InvalidDescriptor SyncIO Overflow Seek + fn Seek(mut self, offset: int, origin: Seek)!: int { + pos := sys::Seek(int(self.handle), offset, int(origin)) + if pos == -1 { + error(getLastFsError()) + } + ret pos + } - // Closes file handle. - // - // Possible errors: - // InvalidDescriptor Signal IO - fn Close(mut self)! { - if sys::Close(int(self.handle)) == -1 { - error(getLastFsError()) - } - } + // Closes file handle. + // + // Possible errors: + // InvalidDescriptor Signal IO + fn Close(mut self)! { + if sys::Close(int(self.handle)) == -1 { + error(getLastFsError()) + } + } } \ No newline at end of file diff --git a/std/fs/file_unix.jule b/std/fs/file_unix.jule index 75047b481..78f023efd 100644 --- a/std/fs/file_unix.jule +++ b/std/fs/file_unix.jule @@ -7,74 +7,74 @@ use sys for std::sys use zsys for std::internal::zsys impl File { - // Opens file stream with named file, specified flag - // (OFlag.Rdwr, OFlag.Trunc etc.) and perm. If named file does - // not exist and OFlag.Creat flag is passed, will created with - // mode (before umask). If successful, returns File reference with handle - // to file stream and the reference can used for I/O operations. - // - // Possible errors: - // Denied Exist Signal SyncIO IO IsDir Loop PerProcessLimit LongPath - // SystemWideLimit NotExist UnableStream NoSpace NotDir Device Overflow - // ReadOnly Retry Busy - static fn Open(path: str, flag: OFlag, mode: int)!: &File { - s := integ::StrToBytes(path) - handle := unsafe { sys::Open(&s[0], int(flag), mode) } - if handle == -1 { - error(getLastFsError()) - } - ret File.New(uintptr(handle)) - } + // Opens file stream with named file, specified flag + // (OFlag.Rdwr, OFlag.Trunc etc.) and perm. If named file does + // not exist and OFlag.Creat flag is passed, will created with + // mode (before umask). If successful, returns File reference with handle + // to file stream and the reference can used for I/O operations. + // + // Possible errors: + // Denied Exist Signal SyncIO IO IsDir Loop PerProcessLimit LongPath + // SystemWideLimit NotExist UnableStream NoSpace NotDir Device Overflow + // ReadOnly Retry Busy + static fn Open(path: str, flag: OFlag, mode: int)!: &File { + s := integ::StrToBytes(path) + handle := unsafe { sys::Open(&s[0], int(flag), mode) } + if handle == -1 { + error(getLastFsError()) + } + ret File.New(uintptr(handle)) + } - // Removes named file. - // - // Possible errors: - // Denined Busy LongPath NotExist InsufficientMemory NotDir - static fn Remove(path: str)! { - s := integ::StrToBytes(path) - if unsafe { sys::Unlink(&s[0]) } != 0 { - error(getLastFsError()) - } - } + // Removes named file. + // + // Possible errors: + // Denined Busy LongPath NotExist InsufficientMemory NotDir + static fn Remove(path: str)! { + s := integ::StrToBytes(path) + if unsafe { sys::Unlink(&s[0]) } != 0 { + error(getLastFsError()) + } + } } impl File { - // Writes bytes to handle and returns writed byte count. - // The number of bytes written can never exceed the length of the buf. - // - // Possible errors: - // Retry InvalidDescriptor Big Signal IO NoSpace Pipe Range SyncIO - // Seek Device Buffer - fn Write(mut self, buf: []byte)!: (n: int) { - if len(buf) == 0 { - ret 0 - } - zsys::HandleRW(buf) - n = unsafe { sys::Write(int(self.handle), &buf[0], uint(len(buf))) } - if n == -1 { - error(getLastFsError()) - } - ret n - } + // Writes bytes to handle and returns writed byte count. + // The number of bytes written can never exceed the length of the buf. + // + // Possible errors: + // Retry InvalidDescriptor Big Signal IO NoSpace Pipe Range SyncIO + // Seek Device Buffer + fn Write(mut self, buf: []byte)!: (n: int) { + if len(buf) == 0 { + ret 0 + } + zsys::HandleRW(buf) + n = unsafe { sys::Write(int(self.handle), &buf[0], uint(len(buf))) } + if n == -1 { + error(getLastFsError()) + } + ret n + } - // Read bytes to buffer from handle and returns readed byte count. - // The number of bytes readed can never exceed the length of the buf. - // If the buf is larger than the number of bytes that can be read, - // the buffer will not cause an overflow. Offset will be shifted - // by the number of bytes read. - // - // Possible errors: - // Retry InvalidDescriptor Signal SyncIO IO IsDir Overflow Buffer - // InsufficientMemory Device Seek - fn Read(mut self, mut buf: []byte)!: (n: int) { - if len(buf) == 0 { - ret 0 - } - zsys::HandleRW(buf) - n = unsafe { sys::Read(int(self.handle), &buf[0], uint(len(buf))) } - if n == -1 { - error(getLastFsError()) - } - ret n - } + // Read bytes to buffer from handle and returns readed byte count. + // The number of bytes readed can never exceed the length of the buf. + // If the buf is larger than the number of bytes that can be read, + // the buffer will not cause an overflow. Offset will be shifted + // by the number of bytes read. + // + // Possible errors: + // Retry InvalidDescriptor Signal SyncIO IO IsDir Overflow Buffer + // InsufficientMemory Device Seek + fn Read(mut self, mut buf: []byte)!: (n: int) { + if len(buf) == 0 { + ret 0 + } + zsys::HandleRW(buf) + n = unsafe { sys::Read(int(self.handle), &buf[0], uint(len(buf))) } + if n == -1 { + error(getLastFsError()) + } + ret n + } } \ No newline at end of file diff --git a/std/fs/file_windows.jule b/std/fs/file_windows.jule index 55fdc3a51..d10af78e3 100644 --- a/std/fs/file_windows.jule +++ b/std/fs/file_windows.jule @@ -9,112 +9,112 @@ use utf16 for std::unicode::utf16 use zsys for std::internal::zsys impl File { - // Opens file stream with named file, specified flag - // (OFlag.Rdwr, OFlag.Trunc etc.) and perm. If named file does - // not exist and OFlag.Creat flag is passed, will created with - // mode (before umask). If successful, returns File reference with handle - // to file stream and the reference can used for I/O operations. - // - // Possible errors: - // Denied Exist Signal SyncIO IO IsDir Loop PerProcessLimit LongPath - // SystemWideLimit NotExist UnableStream NoSpace NotDir Device Overflow - // ReadOnly Retry Busy - static fn Open(path: str, flag: OFlag, mode: int)!: &File { - utf16Path := integ::UTF16FromStr(path) - handle := unsafe { sys::Wopen(&utf16Path[0], int(flag), mode) } - if handle == -1 { - error(getLastFsError()) - } - ret File.New(uintptr(handle)) - } + // Opens file stream with named file, specified flag + // (OFlag.Rdwr, OFlag.Trunc etc.) and perm. If named file does + // not exist and OFlag.Creat flag is passed, will created with + // mode (before umask). If successful, returns File reference with handle + // to file stream and the reference can used for I/O operations. + // + // Possible errors: + // Denied Exist Signal SyncIO IO IsDir Loop PerProcessLimit LongPath + // SystemWideLimit NotExist UnableStream NoSpace NotDir Device Overflow + // ReadOnly Retry Busy + static fn Open(path: str, flag: OFlag, mode: int)!: &File { + utf16Path := integ::UTF16FromStr(path) + handle := unsafe { sys::Wopen(&utf16Path[0], int(flag), mode) } + if handle == -1 { + error(getLastFsError()) + } + ret File.New(uintptr(handle)) + } - // Removes named file. - // - // Possible errors: - // Denined Busy LongPath NotExist InsufficientMemory NotDir - static fn Remove(path: str)! { - utf16Path := integ::UTF16FromStr(path) - if unsafe { !sys::DeleteFile(&utf16Path[0]) } { - error(getLastFsError()) - } - } + // Removes named file. + // + // Possible errors: + // Denined Busy LongPath NotExist InsufficientMemory NotDir + static fn Remove(path: str)! { + utf16Path := integ::UTF16FromStr(path) + if unsafe { !sys::DeleteFile(&utf16Path[0]) } { + error(getLastFsError()) + } + } } impl File { - // Writes bytes to handle and returns writed byte count. - // The number of bytes written can never exceed the length of the buf. - // - // Possible errors: - // Retry InvalidDescriptor Big Signal IO NoSpace Pipe Range SyncIO - // Seek Device Buffer - fn Write(mut self, buf: []byte)!: (n: int) { - if len(buf) == 0 { - ret 0 - } + // Writes bytes to handle and returns writed byte count. + // The number of bytes written can never exceed the length of the buf. + // + // Possible errors: + // Retry InvalidDescriptor Big Signal IO NoSpace Pipe Range SyncIO + // Seek Device Buffer + fn Write(mut self, buf: []byte)!: (n: int) { + if len(buf) == 0 { + ret 0 + } - if isConsoleHandle(self.handle) { - utf16Buf := integ::UTF16FromStr(str(buf)) - ok := unsafe { sys::WriteConsole(self.handle, &utf16Buf[0], len(utf16Buf), n, nil) } - if !ok { - error(getLastFsError()) - } - ret n - } + if isConsoleHandle(self.handle) { + utf16Buf := integ::UTF16FromStr(str(buf)) + ok := unsafe { sys::WriteConsole(self.handle, &utf16Buf[0], len(utf16Buf), n, nil) } + if !ok { + error(getLastFsError()) + } + ret n + } - zsys::HandleRW(buf) - n = unsafe { sys::Write(int(self.handle), &buf[0], uint(len(buf))) } - if n == -1 { - error(getLastFsError()) - } - ret n - } + zsys::HandleRW(buf) + n = unsafe { sys::Write(int(self.handle), &buf[0], uint(len(buf))) } + if n == -1 { + error(getLastFsError()) + } + ret n + } - // Read bytes to buffer from handle and returns readed byte count. - // The number of bytes readed can never exceed the length of the buf. - // If the buf is larger than the number of bytes that can be read, - // the buffer will not cause an overflow. Offset will be shifted - // by the number of bytes read. - // - // Possible errors: - // Retry InvalidDescriptor Signal SyncIO IO IsDir Overflow Buffer - // InsufficientMemory Device Seek - fn Read(mut self, mut buf: []byte)!: (n: int) { - if len(buf) == 0 { - ret 0 - } + // Read bytes to buffer from handle and returns readed byte count. + // The number of bytes readed can never exceed the length of the buf. + // If the buf is larger than the number of bytes that can be read, + // the buffer will not cause an overflow. Offset will be shifted + // by the number of bytes read. + // + // Possible errors: + // Retry InvalidDescriptor Signal SyncIO IO IsDir Overflow Buffer + // InsufficientMemory Device Seek + fn Read(mut self, mut buf: []byte)!: (n: int) { + if len(buf) == 0 { + ret 0 + } - if isConsoleHandle(self.handle) { - mut codepage := make([]u16, len(buf)) - ok := unsafe { sys::ReadConsole(self.handle, &codepage[0], len(buf), n) } - if !ok { - error(getLastFsError()) - } + if isConsoleHandle(self.handle) { + mut codepage := make([]u16, len(buf)) + ok := unsafe { sys::ReadConsole(self.handle, &codepage[0], len(buf), n) } + if !ok { + error(getLastFsError()) + } - runes := utf16::Decode(codepage[:n]) - n = 0 - for _, r in runes { - size := utf8::RuneLen(r) - if n+size > len(buf) { - break - } - _ = utf8::EncodeRune(buf[n:], r) - n += size - } + runes := utf16::Decode(codepage[:n]) + n = 0 + for _, r in runes { + size := utf8::RuneLen(r) + if n+size > len(buf) { + break + } + _ = utf8::EncodeRune(buf[n:], r) + n += size + } - ret n - } + ret n + } - zsys::HandleRW(buf) - n = unsafe { sys::Read(int(self.handle), &buf[0], uint(len(buf))) } - if n == -1 { - error(getLastFsError()) - } - ret n - } + zsys::HandleRW(buf) + n = unsafe { sys::Read(int(self.handle), &buf[0], uint(len(buf))) } + if n == -1 { + error(getLastFsError()) + } + ret n + } } fn isConsoleHandle(handle: uintptr): bool { - ret handle == sys::STDIN || - handle == sys::STDOUT || - handle == sys::STDERR + ret handle == sys::STDIN || + handle == sys::STDOUT || + handle == sys::STDERR } \ No newline at end of file diff --git a/std/fs/path/path.jule b/std/fs/path/path.jule index 42cc71d00..d6106be19 100644 --- a/std/fs/path/path.jule +++ b/std/fs/path/path.jule @@ -44,40 +44,40 @@ use strings for std::strings // and retrieving the final string. It does not allocate a buffer // to hold the output until that output diverges from s. struct lazyBuff { - path: str - buff: []byte - w: int - volAndPath: str - volLen: int + path: str + buff: []byte + w: int + volAndPath: str + volLen: int } impl lazyBuff { - fn index(mut self, i: int): byte { - if self.buff != nil { - ret self.buff[i] - } - ret self.path[i] - } + fn index(mut self, i: int): byte { + if self.buff != nil { + ret self.buff[i] + } + ret self.path[i] + } - fn append(mut self, c: byte) { - if self.buff == nil { - if self.w < len(self.path) && self.path[self.w] == c { - self.w++ - ret - } - self.buff = make([]byte, len(self.path)) - copy(self.buff, self.path[:self.w]) - } - self.buff[self.w] = c - self.w++ - } + fn append(mut self, c: byte) { + if self.buff == nil { + if self.w < len(self.path) && self.path[self.w] == c { + self.w++ + ret + } + self.buff = make([]byte, len(self.path)) + copy(self.buff, self.path[:self.w]) + } + self.buff[self.w] = c + self.w++ + } - fn string(mut self): str { - if self.buff == nil { - ret self.volAndPath[:self.volLen+self.w] - } - ret self.volAndPath[:self.volLen] + unsafe::BytesStr(self.buff[:self.w]) - } + fn string(mut self): str { + if self.buff == nil { + ret self.volAndPath[:self.volLen+self.w] + } + ret self.volAndPath[:self.volLen] + unsafe::BytesStr(self.buff[:self.w]) + } } // Returns the shortest path name equivalent to path @@ -107,113 +107,113 @@ impl lazyBuff { // See also Rob Pike, “Lexical File Names in Plan 9 or Getting Dot-Dot Right” // https://9p.io/sys/doc/lexnames.html fn Clean(mut path: str): str { - originalPath := path - volLen := volumeNameLen(path) - path = path[volLen:] - if path == "" { - if volLen > 1 && IsPathSep(originalPath[0]) && IsPathSep(originalPath[1]) { - // should be UNC - ret FromSlash(originalPath) - } - ret originalPath + "." - } - rooted := IsPathSep(path[0]) + originalPath := path + volLen := volumeNameLen(path) + path = path[volLen:] + if path == "" { + if volLen > 1 && IsPathSep(originalPath[0]) && IsPathSep(originalPath[1]) { + // should be UNC + ret FromSlash(originalPath) + } + ret originalPath + "." + } + rooted := IsPathSep(path[0]) - // Invariants: - // reading from path; r is index of next byte to process. - // writing to buf; w is index of next byte to write. - // dotdot is index in buf where .. must stop, either because - // it is the leading slash or it is a leading ../../.. prefix. - n := len(path) - mut out := lazyBuff{ - path: path, - volAndPath: originalPath, - volLen: volLen, - } - mut r, mut dotdot := 0, 0 - if rooted { - out.append(Separator) - r, dotdot = 1, 1 - } + // Invariants: + // reading from path; r is index of next byte to process. + // writing to buf; w is index of next byte to write. + // dotdot is index in buf where .. must stop, either because + // it is the leading slash or it is a leading ../../.. prefix. + n := len(path) + mut out := lazyBuff{ + path: path, + volAndPath: originalPath, + volLen: volLen, + } + mut r, mut dotdot := 0, 0 + if rooted { + out.append(Separator) + r, dotdot = 1, 1 + } - for r < n { - match { - | IsPathSep(path[r]): - // empty path element - r++ - | path[r] == '.' && (r+1 == n || IsPathSep(path[r+1])): - // . element - r++ - | path[r] == '.' && path[r+1] == '.' && (r+2 == n || IsPathSep(path[r+2])): - // .. element: remove to last separator - r += 2 - match { - | out.w > dotdot: - // can backtrack - out.w-- - for out.w > dotdot && !IsPathSep(out.index(out.w)) { - out.w-- - } - | !rooted: - // cannot backtrack, but not rooted, so append .. element. - if out.w > 0 { - out.append(Separator) - } - out.append('.') - out.append('.') - dotdot = out.w - } - |: - // real path element. - // add slash if needed - if rooted && out.w != 1 || !rooted && out.w != 0 { - out.append(Separator) - } - // If a ':' appears in the path element at the start of a Windows path, - // insert a .\ at the beginning to avoid converting relative paths - // like a/../c: into c:. - if env::Os == "windows" && out.w == 0 && out.volLen == 0 && r != 0 { - mut i := r - for i < n && !IsPathSep(path[i]); i++ { - if path[i] == ':' { - out.append('.') - out.append(Separator) - break - } - } - } - // copy element - for r < n && !IsPathSep(path[r]); r++ { - out.append(path[r]) - } - } - } + for r < n { + match { + | IsPathSep(path[r]): + // empty path element + r++ + | path[r] == '.' && (r+1 == n || IsPathSep(path[r+1])): + // . element + r++ + | path[r] == '.' && path[r+1] == '.' && (r+2 == n || IsPathSep(path[r+2])): + // .. element: remove to last separator + r += 2 + match { + | out.w > dotdot: + // can backtrack + out.w-- + for out.w > dotdot && !IsPathSep(out.index(out.w)) { + out.w-- + } + | !rooted: + // cannot backtrack, but not rooted, so append .. element. + if out.w > 0 { + out.append(Separator) + } + out.append('.') + out.append('.') + dotdot = out.w + } + |: + // real path element. + // add slash if needed + if rooted && out.w != 1 || !rooted && out.w != 0 { + out.append(Separator) + } + // If a ':' appears in the path element at the start of a Windows path, + // insert a .\ at the beginning to avoid converting relative paths + // like a/../c: into c:. + if env::Os == "windows" && out.w == 0 && out.volLen == 0 && r != 0 { + mut i := r + for i < n && !IsPathSep(path[i]); i++ { + if path[i] == ':' { + out.append('.') + out.append(Separator) + break + } + } + } + // copy element + for r < n && !IsPathSep(path[r]); r++ { + out.append(path[r]) + } + } + } - // Turn empty string into "." - if out.w == 0 { - out.append('.') - } - ret FromSlash(out.string()) + // Turn empty string into "." + if out.w == 0 { + out.append('.') + } + ret FromSlash(out.string()) } // Returns the result of replacing each separator character // in path with a slash ('/') character. Multiple separators are // replaced by multiple slashes. fn ToSlash(path: str): str { - if Separator == '/' { - ret path - } - ret strings::Replace(path, str(Separator), "/", -1) + if Separator == '/' { + ret path + } + ret strings::Replace(path, str(Separator), "/", -1) } // Returns the result of replacing each slash ('/') character // in path with a separator character. Multiple slashes are replaced // by multiple separators. fn FromSlash(path: str): str { - if Separator == '/' { - ret path - } - ret strings::Replace(path, "/", str(Separator), -1) + if Separator == '/' { + ret path + } + ret strings::Replace(path, "/", str(Separator), -1) } // Joins any number of path elements into a single path, @@ -229,13 +229,13 @@ fn Join(elem: ...str): str { ret join(elem...) } // The extension is the suffix beginning at the final dot // in the final element of path; it is empty if there is no dot. fn Ext(path: str): str { - mut i := len(path) - 1 - for i >= 0 && !IsPathSep(path[i]); i-- { - if path[i] == '.' { - ret path[i:] - } - } - ret "" + mut i := len(path) - 1 + for i >= 0 && !IsPathSep(path[i]); i-- { + if path[i] == '.' { + ret path[i:] + } + } + ret "" } // Returns an absolute representation of path. @@ -250,28 +250,28 @@ fn Abs(path: str): (str, bool) { ret abs(path) } // If the path is empty, base returns ".". // If the path consists entirely of separators, base returns a single separator. fn Base(mut path: str): str { - if path == "" { - ret "." - } - // Strip trailing slashes. - for len(path) > 0 && IsPathSep(path[len(path)-1]) { - path = path[0:len(path)-1] - } - // Throw away volume name - path = path[len(VolumeName(path)):] - // Find the last element - mut i := len(path) - 1 - for i >= 0 && !IsPathSep(path[i]) { - i-- - } - if i >= 0 { - path = path[i+1:] - } - // If empty now, it had only slashes. - if path == "" { - ret str(Separator) - } - ret path + if path == "" { + ret "." + } + // Strip trailing slashes. + for len(path) > 0 && IsPathSep(path[len(path)-1]) { + path = path[0:len(path)-1] + } + // Throw away volume name + path = path[len(VolumeName(path)):] + // Find the last element + mut i := len(path) - 1 + for i >= 0 && !IsPathSep(path[i]) { + i-- + } + if i >= 0 { + path = path[i+1:] + } + // If empty now, it had only slashes. + if path == "" { + ret str(Separator) + } + ret path } // Returns all but the last element of path, typically the path's directory. @@ -281,17 +281,17 @@ fn Base(mut path: str): str { // If the path consists entirely of separators, dir returns a single separator. // The returned path does not end in a separator unless it is the root directory. fn Dir(path: str): str { - vol := VolumeName(path) - mut i := len(path) - 1 - for i >= len(vol) && !IsPathSep(path[i]) { - i-- - } - dir := Clean(path[len(vol):i+1]) - if dir == "." && len(vol) > 2 { - // must be UNC - ret vol - } - ret vol + dir + vol := VolumeName(path) + mut i := len(path) - 1 + for i >= len(vol) && !IsPathSep(path[i]) { + i-- + } + dir := Clean(path[len(vol):i+1]) + if dir == "." && len(vol) > 2 { + // must be UNC + ret vol + } + ret vol + dir } // Returns leading volume name. @@ -299,5 +299,5 @@ fn Dir(path: str): str { // Given "\\host\share\foo" it returns "\\host\share". // On other platforms it returns empty string. fn VolumeName(path: str): str { - ret FromSlash(path[:volumeNameLen(path)]) + ret FromSlash(path[:volumeNameLen(path)]) } \ No newline at end of file diff --git a/std/fs/path/path_unix.jule b/std/fs/path/path_unix.jule index e4e4845b7..7892c6065 100644 --- a/std/fs/path/path_unix.jule +++ b/std/fs/path/path_unix.jule @@ -46,35 +46,35 @@ const ListSeparator = ':' // Reports whether c is path separator. fn IsPathSep(c: u8): bool { - ret Separator == c + ret Separator == c } // Reports whether the path is absolute. fn IsAbs(path: str): bool { - ret strings::HasPrefix(path, "/") + ret strings::HasPrefix(path, "/") } // Returns length of the leading volume name on Windows. // It returns 0 elsewhere. fn volumeNameLen(path: str): int { - ret 0 + ret 0 } fn abs(path: str): (str, ok: bool) { - if IsAbs(path) { - ret Clean(path), true - } - wd := WorkingDir() else { - ret "", false - } - ret join(wd, path), true + if IsAbs(path) { + ret Clean(path), true + } + wd := WorkingDir() else { + ret "", false + } + ret join(wd, path), true } fn join(elem: ...str): str { - for i, e in elem { - if e != "" { - ret Clean(strings::Join(elem[i:], str(Separator))) - } - } - ret "" + for i, e in elem { + if e != "" { + ret Clean(strings::Join(elem[i:], str(Separator))) + } + } + ret "" } \ No newline at end of file diff --git a/std/fs/path/path_windows.jule b/std/fs/path/path_windows.jule index 3b521db10..2006a3497 100644 --- a/std/fs/path/path_windows.jule +++ b/std/fs/path/path_windows.jule @@ -47,33 +47,33 @@ const ListSeparator = ';' // Reports whether c is path separator. fn IsPathSep(c: u8): bool { - ret c == Separator || c == '/' + ret c == Separator || c == '/' } fn isSlash(c: u8): bool { ret c == '\\' || c == '/' } fn toUpper(c: byte): byte { - if 'a' <= c && c <= 'z' { - ret c - ('a' - 'A') - } - ret c + if 'a' <= c && c <= 'z' { + ret c - ('a' - 'A') + } + ret c } // Reports whether the path is absolute. fn IsAbs(mut path: str): bool { - l := volumeNameLen(path) - if l == 0 { - ret false - } - // If the volume name starts with a double slash, this is an absolute path. - if isSlash(path[0]) && isSlash(path[1]) { - ret true - } - path = path[l:] - if path == "" { - ret false - } - ret isSlash(path[0]) + l := volumeNameLen(path) + if l == 0 { + ret false + } + // If the volume name starts with a double slash, this is an absolute path. + if isSlash(path[0]) && isSlash(path[1]) { + ret true + } + path = path[l:] + if path == "" { + ret false + } + ret isSlash(path[0]) } // Returns length of the leading volume name on Windows. @@ -81,119 +81,119 @@ fn IsAbs(mut path: str): bool { // // See: https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats fn volumeNameLen(path: str): int { - if len(path) < 2 { - ret 0 - } - // with drive letter - c := path[0] - if path[1] == ':' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') { - ret 2 - } - // UNC and DOS device paths start with two slashes. - if !isSlash(path[0]) || !isSlash(path[1]) { - ret 0 - } - p1, mut rest, _ := cutPath(path[2:]) - mut p2 := "" - mut ok := false - p2, rest, ok = cutPath(rest) - if !ok { - ret len(path) - } - if p1 != "." && p1 != "?" { - // This is a UNC path: \\${HOST}\${SHARE}\ - ret len(path) - len(rest) - 1 - } - // This is a DOS device path. - if len(p2) == 3 && toUpper(p2[0]) == 'U' && toUpper(p2[1]) == 'N' && toUpper(p2[2]) == 'C' { - // This is a DOS device path that links to a UNC: \\.\UNC\${HOST}\${SHARE}\ - _, rest, _ = cutPath(rest) // host - _, rest, ok = cutPath(rest) // share - if !ok { - ret len(path) - } - } - ret len(path) - len(rest) - 1 + if len(path) < 2 { + ret 0 + } + // with drive letter + c := path[0] + if path[1] == ':' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') { + ret 2 + } + // UNC and DOS device paths start with two slashes. + if !isSlash(path[0]) || !isSlash(path[1]) { + ret 0 + } + p1, mut rest, _ := cutPath(path[2:]) + mut p2 := "" + mut ok := false + p2, rest, ok = cutPath(rest) + if !ok { + ret len(path) + } + if p1 != "." && p1 != "?" { + // This is a UNC path: \\${HOST}\${SHARE}\ + ret len(path) - len(rest) - 1 + } + // This is a DOS device path. + if len(p2) == 3 && toUpper(p2[0]) == 'U' && toUpper(p2[1]) == 'N' && toUpper(p2[2]) == 'C' { + // This is a DOS device path that links to a UNC: \\.\UNC\${HOST}\${SHARE}\ + _, rest, _ = cutPath(rest) // host + _, rest, ok = cutPath(rest) // share + if !ok { + ret len(path) + } + } + ret len(path) - len(rest) - 1 } // Slices path around the first path separator. fn cutPath(path: str): (before: str, after: str, found: bool) { - for i in path { - if isSlash(path[i]) { - ret path[:i], path[i+1:], true - } - } - ret path, "", false + for i in path { + if isSlash(path[i]) { + ret path[:i], path[i+1:], true + } + } + ret path, "", false } fn fullPath(name: str): (path: str, ok: bool) { - utf16Name := integ::UTF16FromStr(name) - p := &utf16Name[0] - mut n := u32(100) - for { - mut buf := make([]u16, n) - n = unsafe { sys::GetFullPathName(p, u32(len(buf)), &buf[0], nil) } - if n == 0 { - ret "", false - } - if n <= u32(len(buf)) { - ret integ::UTF16ToStr(buf[:n]), true - } - } - ret "", false + utf16Name := integ::UTF16FromStr(name) + p := &utf16Name[0] + mut n := u32(100) + for { + mut buf := make([]u16, n) + n = unsafe { sys::GetFullPathName(p, u32(len(buf)), &buf[0], nil) } + if n == 0 { + ret "", false + } + if n <= u32(len(buf)) { + ret integ::UTF16ToStr(buf[:n]), true + } + } + ret "", false } fn abs(mut path: str): (str, ok: bool) { - if path == "" { - // full_path returns an error on empty path, because it's not a valid path. - // To implement Abs behavior of returning working directory on empty string input, - // special-case empty path by changing it to "." path. See golang.org/issue/24441. - path = "." - } - path, ok = fullPath(path) - if !ok { - ret "", false - } - ret Clean(path), true + if path == "" { + // full_path returns an error on empty path, because it's not a valid path. + // To implement Abs behavior of returning working directory on empty string input, + // special-case empty path by changing it to "." path. See golang.org/issue/24441. + path = "." + } + path, ok = fullPath(path) + if !ok { + ret "", false + } + ret Clean(path), true } fn join(mut elem: ...str): str { - mut s := StrBuilder.New(1 << 4) - mut lastChar := byte(0) - for (_, mut e) in elem { - match { - | s.Len() == 0: - // Add the first non-empty path element unchanged. - | isSlash(lastChar): - // If the path ends in a slash, strip any leading slashes from the next - // path element to avoid creating a UNC path (any path starting with "\\") - // from non-UNC elements. - // - // The correct behavior for join when the first element is an incomplete UNC - // path (for example, "\\") is underspecified. We currently join subsequent - // elements so join("\\", "host", "share") produces "\\host\share". - for len(e) > 0 && isSlash(e[0]) { - e = e[1:] - } - | lastChar == ':': - // If the path ends in a colon, keep the path relative to the current directory - // on a drive and don't add a separator. Preserve leading slashes in the next - // path element, which may make the path absolute. - // - // join(`C:`, `f`) = `C:f` - // join(`C:`, `\f`) = `C:\f` - |: - // In all other cases, add a separator between elements. - s.WriteByte('\\') - lastChar = '\\' - } - if len(e) > 0 { - s.WriteStr(e) - lastChar = e[len(e)-1] - } - } - if s.Len() == 0 { - ret "" - } - ret Clean(s.Str()) + mut s := StrBuilder.New(1 << 4) + mut lastChar := byte(0) + for (_, mut e) in elem { + match { + | s.Len() == 0: + // Add the first non-empty path element unchanged. + | isSlash(lastChar): + // If the path ends in a slash, strip any leading slashes from the next + // path element to avoid creating a UNC path (any path starting with "\\") + // from non-UNC elements. + // + // The correct behavior for join when the first element is an incomplete UNC + // path (for example, "\\") is underspecified. We currently join subsequent + // elements so join("\\", "host", "share") produces "\\host\share". + for len(e) > 0 && isSlash(e[0]) { + e = e[1:] + } + | lastChar == ':': + // If the path ends in a colon, keep the path relative to the current directory + // on a drive and don't add a separator. Preserve leading slashes in the next + // path element, which may make the path absolute. + // + // join(`C:`, `f`) = `C:f` + // join(`C:`, `\f`) = `C:\f` + |: + // In all other cases, add a separator between elements. + s.WriteByte('\\') + lastChar = '\\' + } + if len(e) > 0 { + s.WriteStr(e) + lastChar = e[len(e)-1] + } + } + if s.Len() == 0 { + ret "" + } + ret Clean(s.Str()) } \ No newline at end of file diff --git a/std/fs/stat.jule b/std/fs/stat.jule index 9bd592629..2c2c64e38 100644 --- a/std/fs/stat.jule +++ b/std/fs/stat.jule @@ -5,24 +5,24 @@ use sys for std::sys enum statusMode { - Na: 0 << 0, - Dir: 1 << 0, - Reg: 1 << 1, + Na: 0 << 0, + Dir: 1 << 0, + Reg: 1 << 1, } // Status information. struct Status { - mode: statusMode - size: uint + mode: statusMode + size: uint } impl Status { - // Reports path is directory or not. - fn IsDir(self): bool { ret self.mode&statusMode.Dir == statusMode.Dir } + // Reports path is directory or not. + fn IsDir(self): bool { ret self.mode&statusMode.Dir == statusMode.Dir } - // Reports path is regular file or not. - fn IsReg(self): bool { ret self.mode&statusMode.Reg == statusMode.Reg } + // Reports path is regular file or not. + fn IsReg(self): bool { ret self.mode&statusMode.Reg == statusMode.Reg } - // Total size in bytes of regular file or symbolic link. - fn Size(self): uint { ret self.size } + // Total size in bytes of regular file or symbolic link. + fn Size(self): uint { ret self.size } } \ No newline at end of file diff --git a/std/fs/stat_unix.jule b/std/fs/stat_unix.jule index 02b1da0af..315c82774 100644 --- a/std/fs/stat_unix.jule +++ b/std/fs/stat_unix.jule @@ -6,26 +6,26 @@ use integ for std::jule::integrated use sys for std::sys impl Status { - // Returns a Status describing the path. - // - // Possible errors: Denied IO Loop LongPath NotExist NotDir Overflow - static fn Of(path: str)!: &Status { - if path == "" { - error(FsError.NotExist) - } - mut handle := sys::SysStat{} - s := integ::StrToBytes(path) - code := unsafe { sys::Stat(&s[0], &handle) } - if code == -1 { - error(getLastFsError()) - } - mut stat := new(Status) - stat.size = handle.st_size - if handle.st_mode&sys::S_IFDIR == sys::S_IFDIR { - stat.mode |= statusMode.Dir - } else if handle.st_mode&sys::S_IFREG == sys::S_IFREG { - stat.mode |= statusMode.Reg - } - ret stat - } + // Returns a Status describing the path. + // + // Possible errors: Denied IO Loop LongPath NotExist NotDir Overflow + static fn Of(path: str)!: &Status { + if path == "" { + error(FsError.NotExist) + } + mut handle := sys::SysStat{} + s := integ::StrToBytes(path) + code := unsafe { sys::Stat(&s[0], &handle) } + if code == -1 { + error(getLastFsError()) + } + mut stat := new(Status) + stat.size = handle.st_size + if handle.st_mode&sys::S_IFDIR == sys::S_IFDIR { + stat.mode |= statusMode.Dir + } else if handle.st_mode&sys::S_IFREG == sys::S_IFREG { + stat.mode |= statusMode.Reg + } + ret stat + } } \ No newline at end of file diff --git a/std/fs/stat_windows.jule b/std/fs/stat_windows.jule index 6a598fea1..8f5b0b27c 100644 --- a/std/fs/stat_windows.jule +++ b/std/fs/stat_windows.jule @@ -6,26 +6,26 @@ use integ for std::jule::integrated use sys for std::sys impl Status { - // Returns a Status describing the path. - // - // Possible errors: Denied IO Loop LongPath NotExist NotDir Overflow - static fn Of(path: str)!: &Status { - if path == "" { - error(FsError.NotExist) - } - utf16Path := integ::UTF16FromStr(path) - mut handle := std::sys::SysStat{} - code := unsafe { sys::Wstat(&utf16Path[0], &handle) } - if code == -1 { - error(getLastFsError()) - } - mut stat := new(Status) - stat.size = handle.st_size - if handle.st_mode&sys::S_IFDIR == sys::S_IFDIR { - stat.mode |= statusMode.Dir - } else if handle.st_mode&sys::S_IFREG == sys::S_IFREG { - stat.mode |= statusMode.Reg - } - ret stat - } + // Returns a Status describing the path. + // + // Possible errors: Denied IO Loop LongPath NotExist NotDir Overflow + static fn Of(path: str)!: &Status { + if path == "" { + error(FsError.NotExist) + } + utf16Path := integ::UTF16FromStr(path) + mut handle := std::sys::SysStat{} + code := unsafe { sys::Wstat(&utf16Path[0], &handle) } + if code == -1 { + error(getLastFsError()) + } + mut stat := new(Status) + stat.size = handle.st_size + if handle.st_mode&sys::S_IFDIR == sys::S_IFDIR { + stat.mode |= statusMode.Dir + } else if handle.st_mode&sys::S_IFREG == sys::S_IFREG { + stat.mode |= statusMode.Reg + } + ret stat + } } \ No newline at end of file diff --git a/std/hash/adler32/adler32.jule b/std/hash/adler32/adler32.jule index f495016e5..83cbf238c 100644 --- a/std/hash/adler32/adler32.jule +++ b/std/hash/adler32/adler32.jule @@ -63,81 +63,81 @@ const marshaledSize = len(magic) + 4 type digest: u32 struct Adler32 { - d: digest + d: digest } impl hash::Hash32 for Adler32 {} impl Adler32 { - // The size of an Adler-32 checksum in bytes. - const Size = 4 - - // Returns a new hash::Hash32 computing the Adler-32 checksum. Its - // Sum method will lay the value out in big-endian byte order. - static fn New(): hash::Hash32 { - mut d := new(Adler32) - d.Reset() - ret d - } - - // Returns the Adler-32 checksum of data. - static fn Checksum(data: []byte): u32 { - mut d := Adler32{d: 1} - d.update(data) - ret u32(d.d) - } - - // Add p to the running checksum. - fn update(mut self, p: []byte) { - mut s1 := u32(self.d & 0xffff) - mut s2 := u32(self.d >> 16) - for len(p) > 0 { - let mut q: []byte = nil - if len(p) > nmax { - unsafe { - // Break immutability for p. - *(&p), q = (*(&p))[:nmax], (*(&p))[nmax:] - } - } - for len(p) >= 4 { - s1 += u32(p[0]) - s2 += s1 - s1 += u32(p[1]) - s2 += s1 - s1 += u32(p[2]) - s2 += s1 - s1 += u32(p[3]) - s2 += s1 - unsafe { *(&p) = (*(&p))[4:] } - } - for _, x in p { - s1 += u32(x) - s2 += s1 - } - s1 %= mod - s2 %= mod - unsafe { *(&p) = q } - } - self.d = digest(s2 << 16 | s1) - } - - fn Reset(mut self) { - self.d = 1 - } - - fn Size(self): int { ret Adler32.Size } - - fn BlockSize(self): int { ret 4 } - - fn Sum(self, mut dest: []byte): []byte { - s := u32(self.d) - ret append(dest, byte(s >> 24), byte(s >> 16), byte(s >> 8), byte(s)) - } - - fn Sum32(self): u32 { ret u32(self.d) } - - fn Write(mut self, p: []byte)!: (n: int) { - self.update(p) - ret len(p) - } + // The size of an Adler-32 checksum in bytes. + const Size = 4 + + // Returns a new hash::Hash32 computing the Adler-32 checksum. Its + // Sum method will lay the value out in big-endian byte order. + static fn New(): hash::Hash32 { + mut d := new(Adler32) + d.Reset() + ret d + } + + // Returns the Adler-32 checksum of data. + static fn Checksum(data: []byte): u32 { + mut d := Adler32{d: 1} + d.update(data) + ret u32(d.d) + } + + // Add p to the running checksum. + fn update(mut self, p: []byte) { + mut s1 := u32(self.d & 0xffff) + mut s2 := u32(self.d >> 16) + for len(p) > 0 { + let mut q: []byte = nil + if len(p) > nmax { + unsafe { + // Break immutability for p. + *(&p), q = (*(&p))[:nmax], (*(&p))[nmax:] + } + } + for len(p) >= 4 { + s1 += u32(p[0]) + s2 += s1 + s1 += u32(p[1]) + s2 += s1 + s1 += u32(p[2]) + s2 += s1 + s1 += u32(p[3]) + s2 += s1 + unsafe { *(&p) = (*(&p))[4:] } + } + for _, x in p { + s1 += u32(x) + s2 += s1 + } + s1 %= mod + s2 %= mod + unsafe { *(&p) = q } + } + self.d = digest(s2 << 16 | s1) + } + + fn Reset(mut self) { + self.d = 1 + } + + fn Size(self): int { ret Adler32.Size } + + fn BlockSize(self): int { ret 4 } + + fn Sum(self, mut dest: []byte): []byte { + s := u32(self.d) + ret append(dest, byte(s >> 24), byte(s >> 16), byte(s >> 8), byte(s)) + } + + fn Sum32(self): u32 { ret u32(self.d) } + + fn Write(mut self, p: []byte)!: (n: int) { + self.update(p) + ret len(p) + } } \ No newline at end of file diff --git a/std/hash/adler32/adler32_test.jule b/std/hash/adler32/adler32_test.jule index 1b1ff04d2..75de9469d 100644 --- a/std/hash/adler32/adler32_test.jule +++ b/std/hash/adler32/adler32_test.jule @@ -9,63 +9,63 @@ use std::testing::{T} use strings for std::strings struct case { - out: u32 - input: str + out: u32 + input: str } static cases: []case = [ - {0x00000001, ""}, - {0x00620062, "a"}, - {0x012600c4, "ab"}, - {0x024d0127, "abc"}, - {0x03d8018b, "abcd"}, - {0x05c801f0, "abcde"}, - {0x081e0256, "abcdef"}, - {0x0adb02bd, "abcdefg"}, - {0x0e000325, "abcdefgh"}, - {0x118e038e, "abcdefghi"}, - {0x158603f8, "abcdefghij"}, - {0x158603f8, "abcdefghij"}, - {0x3f090f02, "Discard medicine more than two years old."}, - {0x46d81477, "He who has a shady past knows that nice guys finish last."}, - {0x40ee0ee1, "I wouldn't marry him with a ten foot pole."}, - {0x16661315, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"}, - {0x5b2e1480, "The days of the digital watch are numbered. -Tom Stoppard"}, - {0x8c3c09ea, "Nepal premier won't resign."}, - {0x45ac18fd, "For every action there is an equal and opposite government program."}, - {0x53c61462, "His money is twice tainted: 'taint yours and 'taint mine."}, - {0x7e511e63, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"}, - {0xe4801a6a, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"}, - {0x61b507df, "size: a.out: bad magic"}, - {0xb8631171, "The major problem is with sendmail. -Mark Horton"}, - {0x8b5e1904, "Give me a rock, paper and scissors and I will move the world. CCFestoon"}, - {0x7cc6102b, "If the enemy is within range, then so are you."}, - {0x700318e7, "It's well we cannot hear the screams/That we create in others' dreams."}, - {0x1e601747, "You remind me of a TV show, but that's all right: I watch it anyway."}, - {0xb55b0b09, "C is as portable as Stonehedge!!"}, - {0x39111dd0, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"}, - {0x91dd304f, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"}, - {0x2e5d1316, "How can you write a big system without C++? -Paul Glick"}, - {0xd0201df6, "'Invariant assertions' is the most elegant programming technique! -Tom Szymanski"}, - {0x211297c8, strings::Repeat("\xff", 5548) + "8"}, - {0xbaa198c8, strings::Repeat("\xff", 5549) + "9"}, - {0x553499be, strings::Repeat("\xff", 5550) + "0"}, - {0xf0c19abe, strings::Repeat("\xff", 5551) + "1"}, - {0x8d5c9bbe, strings::Repeat("\xff", 5552) + "2"}, - {0x2af69cbe, strings::Repeat("\xff", 5553) + "3"}, - {0xc9809dbe, strings::Repeat("\xff", 5554) + "4"}, - {0x69189ebe, strings::Repeat("\xff", 5555) + "5"}, - {0x86af0001, strings::Repeat("\x00", 1e5)}, - {0x79660b4d, strings::Repeat("a", 1e5)}, - {0x110588ee, strings::Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 1e4)}, + {0x00000001, ""}, + {0x00620062, "a"}, + {0x012600c4, "ab"}, + {0x024d0127, "abc"}, + {0x03d8018b, "abcd"}, + {0x05c801f0, "abcde"}, + {0x081e0256, "abcdef"}, + {0x0adb02bd, "abcdefg"}, + {0x0e000325, "abcdefgh"}, + {0x118e038e, "abcdefghi"}, + {0x158603f8, "abcdefghij"}, + {0x158603f8, "abcdefghij"}, + {0x3f090f02, "Discard medicine more than two years old."}, + {0x46d81477, "He who has a shady past knows that nice guys finish last."}, + {0x40ee0ee1, "I wouldn't marry him with a ten foot pole."}, + {0x16661315, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"}, + {0x5b2e1480, "The days of the digital watch are numbered. -Tom Stoppard"}, + {0x8c3c09ea, "Nepal premier won't resign."}, + {0x45ac18fd, "For every action there is an equal and opposite government program."}, + {0x53c61462, "His money is twice tainted: 'taint yours and 'taint mine."}, + {0x7e511e63, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"}, + {0xe4801a6a, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"}, + {0x61b507df, "size: a.out: bad magic"}, + {0xb8631171, "The major problem is with sendmail. -Mark Horton"}, + {0x8b5e1904, "Give me a rock, paper and scissors and I will move the world. CCFestoon"}, + {0x7cc6102b, "If the enemy is within range, then so are you."}, + {0x700318e7, "It's well we cannot hear the screams/That we create in others' dreams."}, + {0x1e601747, "You remind me of a TV show, but that's all right: I watch it anyway."}, + {0xb55b0b09, "C is as portable as Stonehedge!!"}, + {0x39111dd0, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"}, + {0x91dd304f, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"}, + {0x2e5d1316, "How can you write a big system without C++? -Paul Glick"}, + {0xd0201df6, "'Invariant assertions' is the most elegant programming technique! -Tom Szymanski"}, + {0x211297c8, strings::Repeat("\xff", 5548) + "8"}, + {0xbaa198c8, strings::Repeat("\xff", 5549) + "9"}, + {0x553499be, strings::Repeat("\xff", 5550) + "0"}, + {0xf0c19abe, strings::Repeat("\xff", 5551) + "1"}, + {0x8d5c9bbe, strings::Repeat("\xff", 5552) + "2"}, + {0x2af69cbe, strings::Repeat("\xff", 5553) + "3"}, + {0xc9809dbe, strings::Repeat("\xff", 5554) + "4"}, + {0x69189ebe, strings::Repeat("\xff", 5555) + "5"}, + {0x86af0001, strings::Repeat("\x00", 1e5)}, + {0x79660b4d, strings::Repeat("a", 1e5)}, + {0x110588ee, strings::Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 1e4)}, ] #test fn testChecksum(t: &T) { - for _, case in cases { - s := Adler32.Checksum(unsafe::StrBytes(case.input)) - if s != case.out { - t.Errorf("expected {} for {}, found {}", case.out, case.input, s) - } - } + for _, case in cases { + s := Adler32.Checksum(unsafe::StrBytes(case.input)) + if s != case.out { + t.Errorf("expected {} for {}, found {}", case.out, case.input, s) + } + } } \ No newline at end of file diff --git a/std/hash/fnv/fnv.jule b/std/hash/fnv/fnv.jule index 2c862c22b..d87d8c453 100644 --- a/std/hash/fnv/fnv.jule +++ b/std/hash/fnv/fnv.jule @@ -58,200 +58,200 @@ const prime128Lower = 0x13b const prime128Shift = 24 struct fnv32 { - s: u32 + s: u32 } impl hash::Hash32 for fnv32 { - fn Sum32(self): u32 { ret self.s } - fn Size(self): int { ret 4 } - fn BlockSize(self): int { ret 1 } - fn Reset(mut self) { self.s = offset32 } - - fn Write(mut self, d: []byte)!: int { - for _, c in d { - self.s *= prime32 - self.s ^= u32(c) - } - ret len(d) - } - - fn Sum(self, mut d: []byte): []byte { - ret byteorder::BeAppendU32(d, self.s) - } + fn Sum32(self): u32 { ret self.s } + fn Size(self): int { ret 4 } + fn BlockSize(self): int { ret 1 } + fn Reset(mut self) { self.s = offset32 } + + fn Write(mut self, d: []byte)!: int { + for _, c in d { + self.s *= prime32 + self.s ^= u32(c) + } + ret len(d) + } + + fn Sum(self, mut d: []byte): []byte { + ret byteorder::BeAppendU32(d, self.s) + } } struct fnv32a { - s: u32 + s: u32 } impl hash::Hash32 for fnv32a { - fn Sum32(self): u32 { ret self.s } - fn Size(self): int { ret 4 } - fn BlockSize(self): int { ret 1 } - fn Reset(mut self) { self.s = offset32 } - - fn Write(mut self, d: []byte)!: int { - for _, c in d { - self.s ^= u32(c) - self.s *= prime32 - } - ret len(d) - } - - fn Sum(self, mut d: []byte): []byte { - ret byteorder::BeAppendU32(d, self.s) - } + fn Sum32(self): u32 { ret self.s } + fn Size(self): int { ret 4 } + fn BlockSize(self): int { ret 1 } + fn Reset(mut self) { self.s = offset32 } + + fn Write(mut self, d: []byte)!: int { + for _, c in d { + self.s ^= u32(c) + self.s *= prime32 + } + ret len(d) + } + + fn Sum(self, mut d: []byte): []byte { + ret byteorder::BeAppendU32(d, self.s) + } } struct fnv64 { - s: u64 + s: u64 } impl hash::Hash64 for fnv64 { - fn Sum64(self): u64 { ret self.s } - fn Size(self): int { ret 8 } - fn BlockSize(self): int { ret 1 } - fn Reset(mut self) { self.s = offset64 } - - fn Write(mut self, d: []byte)!: int { - for _, c in d { - self.s *= prime64 - self.s ^= u64(c) - } - ret len(d) - } - - fn Sum(self, mut d: []byte): []byte { - ret byteorder::BeAppendU64(d, self.s) - } + fn Sum64(self): u64 { ret self.s } + fn Size(self): int { ret 8 } + fn BlockSize(self): int { ret 1 } + fn Reset(mut self) { self.s = offset64 } + + fn Write(mut self, d: []byte)!: int { + for _, c in d { + self.s *= prime64 + self.s ^= u64(c) + } + ret len(d) + } + + fn Sum(self, mut d: []byte): []byte { + ret byteorder::BeAppendU64(d, self.s) + } } struct fnv64a { - s: u64 + s: u64 } impl hash::Hash64 for fnv64a { - fn Sum64(self): u64 { ret self.s } - fn Size(self): int { ret 8 } - fn BlockSize(self): int { ret 1 } - fn Reset(mut self) { self.s = offset64 } - - fn Write(mut self, d: []byte)!: int { - for _, c in d { - self.s ^= u64(c) - self.s *= prime64 - } - ret len(d) - } - - fn Sum(self, mut d: []byte): []byte { - ret byteorder::BeAppendU64(d, self.s) - } + fn Sum64(self): u64 { ret self.s } + fn Size(self): int { ret 8 } + fn BlockSize(self): int { ret 1 } + fn Reset(mut self) { self.s = offset64 } + + fn Write(mut self, d: []byte)!: int { + for _, c in d { + self.s ^= u64(c) + self.s *= prime64 + } + ret len(d) + } + + fn Sum(self, mut d: []byte): []byte { + ret byteorder::BeAppendU64(d, self.s) + } } struct fnv128 { - s: [2]u64 + s: [2]u64 } impl hash::Hash for fnv128 { - fn Size(self): int { ret 16 } - fn BlockSize(self): int { ret 1 } - - fn Reset(mut self) { - self.s[0] = offset128Higher - self.s[1] = offset128Lower - } - - fn Write(mut self, d: []byte)!: int { - for _, c in d { - mut s0, s1 := bits::Mul64(prime128Lower, self.s[1]) - s0 += self.s[1] << prime128Shift + prime128Lower * self.s[0] - self.s[1] = s1 - self.s[0] = s0 - self.s[1] ^= u64(c) - } - ret len(d) - } - - fn Sum(self, mut d: []byte): []byte { - mut r := byteorder::BeAppendU64(d, self.s[0]) - ret byteorder::BeAppendU64(r, self.s[1]) - } + fn Size(self): int { ret 16 } + fn BlockSize(self): int { ret 1 } + + fn Reset(mut self) { + self.s[0] = offset128Higher + self.s[1] = offset128Lower + } + + fn Write(mut self, d: []byte)!: int { + for _, c in d { + mut s0, s1 := bits::Mul64(prime128Lower, self.s[1]) + s0 += self.s[1] << prime128Shift + prime128Lower * self.s[0] + self.s[1] = s1 + self.s[0] = s0 + self.s[1] ^= u64(c) + } + ret len(d) + } + + fn Sum(self, mut d: []byte): []byte { + mut r := byteorder::BeAppendU64(d, self.s[0]) + ret byteorder::BeAppendU64(r, self.s[1]) + } } struct fnv128a { - s: [2]u64 + s: [2]u64 } impl hash::Hash for fnv128a { - fn Size(self): int { ret 16 } - fn BlockSize(self): int { ret 1 } - - fn Reset(mut self) { - self.s[0] = offset128Higher - self.s[1] = offset128Lower - } - - fn Write(mut self, d: []byte)!: int { - for _, c in d { - self.s[1] ^= u64(c) - mut s0, s1 := bits::Mul64(prime128Lower, self.s[1]) - s0 += self.s[1] << prime128Shift + prime128Lower * self.s[0] - self.s[1] = s1 - self.s[0] = s0 - } - ret len(d) - } - - fn Sum(self, mut d: []byte): []byte { - mut r := byteorder::BeAppendU64(d, self.s[0]) - ret byteorder::BeAppendU64(r, self.s[1]) - } + fn Size(self): int { ret 16 } + fn BlockSize(self): int { ret 1 } + + fn Reset(mut self) { + self.s[0] = offset128Higher + self.s[1] = offset128Lower + } + + fn Write(mut self, d: []byte)!: int { + for _, c in d { + self.s[1] ^= u64(c) + mut s0, s1 := bits::Mul64(prime128Lower, self.s[1]) + s0 += self.s[1] << prime128Shift + prime128Lower * self.s[0] + self.s[1] = s1 + self.s[0] = s0 + } + ret len(d) + } + + fn Sum(self, mut d: []byte): []byte { + mut r := byteorder::BeAppendU64(d, self.s[0]) + ret byteorder::BeAppendU64(r, self.s[1]) + } } // Static method wrapper for FNV-1 algorithms. struct Fnv {} impl Fnv { - // Returns a new 32-bit FNV-1 [hash::Hash]. - // Its Sum method will lay the value out in big-endian byte order. - static fn New32(): hash::Hash32 { - ret fnv32{s: offset32} - } - - // Returns a new 64-bit FNV-1 [hash::Hash]. - // Its Sum method will lay the value out in big-endian byte order. - static fn New64(): hash::Hash64 { - ret fnv64{s: offset64} - } - - // Returns a new 128-bit FNV-1 [hash::Hash]. - // Its Sum method will lay the value out in big-endian byte order. - static fn New128(): hash::Hash { - mut h := fnv128{} - h.s[0] = offset128Higher - h.s[1] = offset128Lower - ret h - } - - // Returns a new 32-bit FNV-1a [hash::Hash]. - // Its Sum method will lay the value out in big-endian byte order. - static fn New32a(): hash::Hash32 { - ret fnv32a{s: offset32} - } - - // Returns a new 64-bit FNV-1a [hash::Hash]. - // Its Sum method will lay the value out in big-endian byte order. - static fn New64a(): hash::Hash64 { - ret fnv64a{s: offset64} - } - - // Returns a new 128-bit FNV-1a [hash::Hash]. - // Its Sum method will lay the value out in big-endian byte order. - static fn New128a(): hash::Hash { - mut h := fnv128a{} - h.s[0] = offset128Higher - h.s[1] = offset128Lower - ret h - } + // Returns a new 32-bit FNV-1 [hash::Hash]. + // Its Sum method will lay the value out in big-endian byte order. + static fn New32(): hash::Hash32 { + ret fnv32{s: offset32} + } + + // Returns a new 64-bit FNV-1 [hash::Hash]. + // Its Sum method will lay the value out in big-endian byte order. + static fn New64(): hash::Hash64 { + ret fnv64{s: offset64} + } + + // Returns a new 128-bit FNV-1 [hash::Hash]. + // Its Sum method will lay the value out in big-endian byte order. + static fn New128(): hash::Hash { + mut h := fnv128{} + h.s[0] = offset128Higher + h.s[1] = offset128Lower + ret h + } + + // Returns a new 32-bit FNV-1a [hash::Hash]. + // Its Sum method will lay the value out in big-endian byte order. + static fn New32a(): hash::Hash32 { + ret fnv32a{s: offset32} + } + + // Returns a new 64-bit FNV-1a [hash::Hash]. + // Its Sum method will lay the value out in big-endian byte order. + static fn New64a(): hash::Hash64 { + ret fnv64a{s: offset64} + } + + // Returns a new 128-bit FNV-1a [hash::Hash]. + // Its Sum method will lay the value out in big-endian byte order. + static fn New128a(): hash::Hash { + mut h := fnv128a{} + h.s[0] = offset128Higher + h.s[1] = offset128Lower + ret h + } } \ No newline at end of file diff --git a/std/hash/fnv/fnv_test.jule b/std/hash/fnv/fnv_test.jule index ae8165d43..2424fcad0 100644 --- a/std/hash/fnv/fnv_test.jule +++ b/std/hash/fnv/fnv_test.jule @@ -10,96 +10,96 @@ use hash for std::hash use fastbytes for std::internal::fastbytes struct case { - out: []byte - input: str + out: []byte + input: str } static case32: []case = [ - {[0x81, 0x1c, 0x9d, 0xc5], ""}, - {[0x05, 0x0c, 0x5d, 0x7e], "a"}, - {[0x70, 0x77, 0x2d, 0x38], "ab"}, - {[0x43, 0x9c, 0x2f, 0x4b], "abc"}, + {[0x81, 0x1c, 0x9d, 0xc5], ""}, + {[0x05, 0x0c, 0x5d, 0x7e], "a"}, + {[0x70, 0x77, 0x2d, 0x38], "ab"}, + {[0x43, 0x9c, 0x2f, 0x4b], "abc"}, ] static case32a: []case = [ - {[0x81, 0x1c, 0x9d, 0xc5], ""}, - {[0xe4, 0x0c, 0x29, 0x2c], "a"}, - {[0x4d, 0x25, 0x05, 0xca], "ab"}, - {[0x1a, 0x47, 0xe9, 0x0b], "abc"}, + {[0x81, 0x1c, 0x9d, 0xc5], ""}, + {[0xe4, 0x0c, 0x29, 0x2c], "a"}, + {[0x4d, 0x25, 0x05, 0xca], "ab"}, + {[0x1a, 0x47, 0xe9, 0x0b], "abc"}, ] static case64: []case = [ - {[0xcb, 0xf2, 0x9c, 0xe4, 0x84, 0x22, 0x23, 0x25], ""}, - {[0xaf, 0x63, 0xbd, 0x4c, 0x86, 0x01, 0xb7, 0xbe], "a"}, - {[0x08, 0x32, 0x67, 0x07, 0xb4, 0xeb, 0x37, 0xb8], "ab"}, - {[0xd8, 0xdc, 0xca, 0x18, 0x6b, 0xaf, 0xad, 0xcb], "abc"}, + {[0xcb, 0xf2, 0x9c, 0xe4, 0x84, 0x22, 0x23, 0x25], ""}, + {[0xaf, 0x63, 0xbd, 0x4c, 0x86, 0x01, 0xb7, 0xbe], "a"}, + {[0x08, 0x32, 0x67, 0x07, 0xb4, 0xeb, 0x37, 0xb8], "ab"}, + {[0xd8, 0xdc, 0xca, 0x18, 0x6b, 0xaf, 0xad, 0xcb], "abc"}, ] static case64a: []case = [ - {[0xcb, 0xf2, 0x9c, 0xe4, 0x84, 0x22, 0x23, 0x25], ""}, - {[0xaf, 0x63, 0xdc, 0x4c, 0x86, 0x01, 0xec, 0x8c], "a"}, - {[0x08, 0x9c, 0x44, 0x07, 0xb5, 0x45, 0x98, 0x6a], "ab"}, - {[0xe7, 0x1f, 0xa2, 0x19, 0x05, 0x41, 0x57, 0x4b], "abc"}, + {[0xcb, 0xf2, 0x9c, 0xe4, 0x84, 0x22, 0x23, 0x25], ""}, + {[0xaf, 0x63, 0xdc, 0x4c, 0x86, 0x01, 0xec, 0x8c], "a"}, + {[0x08, 0x9c, 0x44, 0x07, 0xb5, 0x45, 0x98, 0x6a], "ab"}, + {[0xe7, 0x1f, 0xa2, 0x19, 0x05, 0x41, 0x57, 0x4b], "abc"}, ] static case128: []case = [ - {[0x6c, 0x62, 0x27, 0x2e, 0x07, 0xbb, 0x01, 0x42, 0x62, 0xb8, 0x21, 0x75, 0x62, 0x95, 0xc5, 0x8d], ""}, - {[0xd2, 0x28, 0xcb, 0x69, 0x10, 0x1a, 0x8c, 0xaf, 0x78, 0x91, 0x2b, 0x70, 0x4e, 0x4a, 0x14, 0x1e], "a"}, - {[0x8, 0x80, 0x94, 0x5a, 0xee, 0xab, 0x1b, 0xe9, 0x5a, 0xa0, 0x73, 0x30, 0x55, 0x26, 0xc0, 0x88], "ab"}, - {[0xa6, 0x8b, 0xb2, 0xa4, 0x34, 0x8b, 0x58, 0x22, 0x83, 0x6d, 0xbc, 0x78, 0xc6, 0xae, 0xe7, 0x3b], "abc"}, + {[0x6c, 0x62, 0x27, 0x2e, 0x07, 0xbb, 0x01, 0x42, 0x62, 0xb8, 0x21, 0x75, 0x62, 0x95, 0xc5, 0x8d], ""}, + {[0xd2, 0x28, 0xcb, 0x69, 0x10, 0x1a, 0x8c, 0xaf, 0x78, 0x91, 0x2b, 0x70, 0x4e, 0x4a, 0x14, 0x1e], "a"}, + {[0x8, 0x80, 0x94, 0x5a, 0xee, 0xab, 0x1b, 0xe9, 0x5a, 0xa0, 0x73, 0x30, 0x55, 0x26, 0xc0, 0x88], "ab"}, + {[0xa6, 0x8b, 0xb2, 0xa4, 0x34, 0x8b, 0x58, 0x22, 0x83, 0x6d, 0xbc, 0x78, 0xc6, 0xae, 0xe7, 0x3b], "abc"}, ] static case128a: []case = [ - {[0x6c, 0x62, 0x27, 0x2e, 0x07, 0xbb, 0x01, 0x42, 0x62, 0xb8, 0x21, 0x75, 0x62, 0x95, 0xc5, 0x8d], ""}, - {[0xd2, 0x28, 0xcb, 0x69, 0x6f, 0x1a, 0x8c, 0xaf, 0x78, 0x91, 0x2b, 0x70, 0x4e, 0x4a, 0x89, 0x64], "a"}, - {[0x08, 0x80, 0x95, 0x44, 0xbb, 0xab, 0x1b, 0xe9, 0x5a, 0xa0, 0x73, 0x30, 0x55, 0xb6, 0x9a, 0x62], "ab"}, - {[0xa6, 0x8d, 0x62, 0x2c, 0xec, 0x8b, 0x58, 0x22, 0x83, 0x6d, 0xbc, 0x79, 0x77, 0xaf, 0x7f, 0x3b], "abc"}, + {[0x6c, 0x62, 0x27, 0x2e, 0x07, 0xbb, 0x01, 0x42, 0x62, 0xb8, 0x21, 0x75, 0x62, 0x95, 0xc5, 0x8d], ""}, + {[0xd2, 0x28, 0xcb, 0x69, 0x6f, 0x1a, 0x8c, 0xaf, 0x78, 0x91, 0x2b, 0x70, 0x4e, 0x4a, 0x89, 0x64], "a"}, + {[0x08, 0x80, 0x95, 0x44, 0xbb, 0xab, 0x1b, 0xe9, 0x5a, 0xa0, 0x73, 0x30, 0x55, 0xb6, 0x9a, 0x62], "ab"}, + {[0xa6, 0x8d, 0x62, 0x2c, 0xec, 0x8b, 0x58, 0x22, 0x83, 0x6d, 0xbc, 0x79, 0x77, 0xaf, 0x7f, 0x3b], "abc"}, ] fn testCase(t: &T, mut h: hash::Hash, &cases: []case) { - for _, c in cases { - h.Reset() - n := h.Write(unsafe::StrBytes(c.input)) else { - t.Errorf("write error: {}", error) - continue - } - if n != len(c.input) { - t.Errorf("wrote only {} out of {} bytes", n, len(c.input)) - continue - } - actual := h.Sum(nil) - if !fastbytes::Equal(c.out, actual) { - t.Errorf("hash({}) = {} want {}", c.input, actual, c.out) - } - } + for _, c in cases { + h.Reset() + n := h.Write(unsafe::StrBytes(c.input)) else { + t.Errorf("write error: {}", error) + continue + } + if n != len(c.input) { + t.Errorf("wrote only {} out of {} bytes", n, len(c.input)) + continue + } + actual := h.Sum(nil) + if !fastbytes::Equal(c.out, actual) { + t.Errorf("hash({}) = {} want {}", c.input, actual, c.out) + } + } } #test fn testCase32(t: &T) { - testCase(t, Fnv.New32(), case32) + testCase(t, Fnv.New32(), case32) } #test fn testCase32a(t: &T) { - testCase(t, Fnv.New32a(), case32a) + testCase(t, Fnv.New32a(), case32a) } #test fn testCase64(t: &T) { - testCase(t, Fnv.New64(), case64) + testCase(t, Fnv.New64(), case64) } #test fn testCase64a(t: &T) { - testCase(t, Fnv.New64a(), case64a) + testCase(t, Fnv.New64a(), case64a) } #test fn testCase128(t: &T) { - testCase(t, Fnv.New128(), case128) + testCase(t, Fnv.New128(), case128) } #test fn testCase128a(t: &T) { - testCase(t, Fnv.New128a(), case128a) + testCase(t, Fnv.New128a(), case128a) } \ No newline at end of file diff --git a/std/hash/hash.jule b/std/hash/hash.jule index 853140e05..6be09ef78 100644 --- a/std/hash/hash.jule +++ b/std/hash/hash.jule @@ -39,35 +39,35 @@ use io for std::io // The common trait implemented by all hash functions. trait Hash { - // Implements same mehod as io::Writer trait. - // But it will not throws any exceptional. - io::Writer + // Implements same mehod as io::Writer trait. + // But it will not throws any exceptional. + io::Writer - // Appends the current hash to b and returns the resulting slice. - // It does not change the underlying hash state. - fn Sum(self, mut b: []byte): []byte + // Appends the current hash to b and returns the resulting slice. + // It does not change the underlying hash state. + fn Sum(self, mut b: []byte): []byte - // Resets the Hash to its initial state. - fn Reset(mut self) + // Resets the Hash to its initial state. + fn Reset(mut self) - // Returns the number of bytes Sum will return. - fn Size(self): int + // Returns the number of bytes Sum will return. + fn Size(self): int - // Returns the hash's underlying block size. - // The Write method must be able to accept any amount - // of data, but it may operate more efficiently if all writes - // are a multiple of the block size. - fn BlockSize(self): int + // Returns the hash's underlying block size. + // The Write method must be able to accept any amount + // of data, but it may operate more efficiently if all writes + // are a multiple of the block size. + fn BlockSize(self): int } // Common trait implemented by all 32-bit hash functions. trait Hash32 { - Hash - fn Sum32(self): u32 + Hash + fn Sum32(self): u32 } // Common trait implemented by all 64-bit hash functions. trait Hash64 { - Hash - fn Sum64(self): u64 + Hash + fn Sum64(self): u64 } \ No newline at end of file diff --git a/std/internal/byteorder/byteorder.jule b/std/internal/byteorder/byteorder.jule index f605ccd7d..370386124 100644 --- a/std/internal/byteorder/byteorder.jule +++ b/std/internal/byteorder/byteorder.jule @@ -39,125 +39,125 @@ // ==================================================== fn LeU16(b: []byte): u16 { - ret u16(b[0]) | u16(b[1]) << 8 + ret u16(b[0]) | u16(b[1]) << 8 } fn LePutU16(mut b: []byte, v: u16) { - b[0] = byte(v) - b[1] = byte(v >> 8) + b[0] = byte(v) + b[1] = byte(v >> 8) } fn LeAppendU16(mut b: []byte, v: u16): []byte { - ret append(b, - byte(v), - byte(v >> 8)) + ret append(b, + byte(v), + byte(v >> 8)) } fn LeU32(b: []byte): u32 { - ret u32(b[3]) << 24 | u32(b[2]) << 16 | u32(b[1]) << 8 | u32(b[0]) + ret u32(b[3]) << 24 | u32(b[2]) << 16 | u32(b[1]) << 8 | u32(b[0]) } fn LePutU32(mut b: []byte, v: u32) { - b[3] = byte(v >> 24) - b[2] = byte(v >> 16) - b[1] = byte(v >> 8) - b[0] = byte(v) + b[3] = byte(v >> 24) + b[2] = byte(v >> 16) + b[1] = byte(v >> 8) + b[0] = byte(v) } fn LeAppendU32(mut b: []byte, v: u32): []byte { - ret append(b, - byte(v), - byte(v >> 8), - byte(v >> 16), - byte(v >> 24)) + ret append(b, + byte(v), + byte(v >> 8), + byte(v >> 16), + byte(v >> 24)) } fn LeU64(mut b: []byte): u64 { - ret u64(b[7]) << 56 | u64(b[6]) << 48 | u64(b[5]) << 40 | u64(b[4]) << 32 | - u64(b[3]) << 24 | u64(b[2]) << 16 | u64(b[1]) << 8 | u64(b[0]) + ret u64(b[7]) << 56 | u64(b[6]) << 48 | u64(b[5]) << 40 | u64(b[4]) << 32 | + u64(b[3]) << 24 | u64(b[2]) << 16 | u64(b[1]) << 8 | u64(b[0]) } fn LePutU64(mut b: []byte, v: u64) { - b[7] = byte(v >> 56) - b[6] = byte(v >> 48) - b[5] = byte(v >> 40) - b[4] = byte(v >> 32) - b[3] = byte(v >> 24) - b[2] = byte(v >> 16) - b[1] = byte(v >> 8) - b[0] = byte(v) + b[7] = byte(v >> 56) + b[6] = byte(v >> 48) + b[5] = byte(v >> 40) + b[4] = byte(v >> 32) + b[3] = byte(v >> 24) + b[2] = byte(v >> 16) + b[1] = byte(v >> 8) + b[0] = byte(v) } fn LeAppendU64(mut b: []byte, v: u64): []byte { - ret append(b, - byte(v), - byte(v >> 8), - byte(v >> 16), - byte(v >> 24), - byte(v >> 32), - byte(v >> 40), - byte(v >> 48), - byte(v >> 56)) + ret append(b, + byte(v), + byte(v >> 8), + byte(v >> 16), + byte(v >> 24), + byte(v >> 32), + byte(v >> 40), + byte(v >> 48), + byte(v >> 56)) } fn BeU16(b: []byte): u16 { - ret u16(b[1]) | u16(b[0]) << 8 + ret u16(b[1]) | u16(b[0]) << 8 } fn BePutU16(mut b: []byte, v: u16) { - b[1] = byte(v) - b[0] = byte(v >> 8) + b[1] = byte(v) + b[0] = byte(v >> 8) } fn BeAppendU16(mut b: []byte, v: u16): []byte { - ret append(b, - byte(v >> 8), - byte(v)) + ret append(b, + byte(v >> 8), + byte(v)) } fn BeU32(b: []byte): u32 { - ret u32(b[0]) << 24 | u32(b[1]) << 16 | u32(b[2]) << 8 | u32(b[3]) + ret u32(b[0]) << 24 | u32(b[1]) << 16 | u32(b[2]) << 8 | u32(b[3]) } fn BePutU32(mut b: []byte, v: u32) { - b[3] = byte(v) - b[2] = byte(v >> 8) - b[1] = byte(v >> 16) - b[0] = byte(v >> 24) + b[3] = byte(v) + b[2] = byte(v >> 8) + b[1] = byte(v >> 16) + b[0] = byte(v >> 24) } fn BeAppendU32(mut b: []byte, v: u32): []byte { - ret append(b, - byte(v >> 24), - byte(v >> 16), - byte(v >> 8), - byte(v)) + ret append(b, + byte(v >> 24), + byte(v >> 16), + byte(v >> 8), + byte(v)) } fn BeU64(b: []byte): u64 { - ret u64(b[7]) | u64(b[6]) << 8 | u64(b[5]) << 16 | u64(b[4]) << 24 | - u64(b[3]) << 32 | u64(b[2]) << 40 | u64(b[1]) << 48 | u64(b[0]) << 56 + ret u64(b[7]) | u64(b[6]) << 8 | u64(b[5]) << 16 | u64(b[4]) << 24 | + u64(b[3]) << 32 | u64(b[2]) << 40 | u64(b[1]) << 48 | u64(b[0]) << 56 } fn BePutU64(mut b: []byte, v: u64) { - b[7] = byte(v) - b[6] = byte(v >> 8) - b[5] = byte(v >> 16) - b[4] = byte(v >> 24) - b[3] = byte(v >> 32) - b[2] = byte(v >> 40) - b[1] = byte(v >> 48) - b[0] = byte(v >> 56) + b[7] = byte(v) + b[6] = byte(v >> 8) + b[5] = byte(v >> 16) + b[4] = byte(v >> 24) + b[3] = byte(v >> 32) + b[2] = byte(v >> 40) + b[1] = byte(v >> 48) + b[0] = byte(v >> 56) } fn BeAppendU64(mut b: []byte, v: u64): []byte { - ret append(b, - byte(v >> 56), - byte(v >> 48), - byte(v >> 40), - byte(v >> 32), - byte(v >> 24), - byte(v >> 16), - byte(v >> 8), - byte(v)) + ret append(b, + byte(v >> 56), + byte(v >> 48), + byte(v >> 40), + byte(v >> 32), + byte(v >> 24), + byte(v >> 16), + byte(v >> 8), + byte(v)) } \ No newline at end of file diff --git a/std/internal/cmp/cmp.jule b/std/internal/cmp/cmp.jule index cb0f31058..db91ac095 100644 --- a/std/internal/cmp/cmp.jule +++ b/std/internal/cmp/cmp.jule @@ -6,17 +6,17 @@ // For floating-point types, a NaN is considered less than any non-NaN, // and -0.0 is not less than (is equal to) 0.0. fn Less[T: ordered](x: T, y: T): bool { - const match type T { - | f32 | f64: - if isNaN(x) && !isNaN(y) { - ret true - } - } - ret x < y + const match type T { + | f32 | f64: + if isNaN(x) && !isNaN(y) { + ret true + } + } + ret x < y } // isNaN reports whether x is a NaN without requiring the math package. // This will always return false if T is not floating-point. fn isNaN[T](x: T): bool { - ret x != x + ret x != x } \ No newline at end of file diff --git a/std/internal/conv/atoi.jule b/std/internal/conv/atoi.jule index 8e87bf5f3..f6c8d81e0 100755 --- a/std/internal/conv/atoi.jule +++ b/std/internal/conv/atoi.jule @@ -5,55 +5,55 @@ // Converts decimal byte pointer to int. // Return integer and success state. unsafe fn AtoiBp(mut b: *byte, mut n: int): (i: int, ok: bool) { - mut neg := *b == '-' - if neg { - if n == 1 { - ret - } - n-- - b++ - } - for n > 0; n-- { - if '0' <= *b && *b <= '9' { - i *= 10 - i += int(*b - '0') - } else { - ret - } - b++ - } - ok = true - if neg { - i = -i - } - ret + mut neg := *b == '-' + if neg { + if n == 1 { + ret + } + n-- + b++ + } + for n > 0; n-- { + if '0' <= *b && *b <= '9' { + i *= 10 + i += int(*b - '0') + } else { + ret + } + b++ + } + ok = true + if neg { + i = -i + } + ret } // Same as AtoiBp. fn Atoi(&s: str): (i: int, ok: bool) { - i, ok = unsafe { AtoiBp(&s[0], len(s)) } - ret + i, ok = unsafe { AtoiBp(&s[0], len(s)) } + ret } // Converts hexadecimal bytes of string to int. // Returns number, characters consumed, success state. fn Xbtoi(&s: []byte): (n: int, i: int, ok: bool) { - for i < len(s); i++ { - if '0' <= s[i] && s[i] <= '9' { - n <<= 4 - n += int(s[i] - '0') - } else if 'a' <= s[i] && s[i] <= 'f' { - n <<= 4 - n += int(s[i] - 'a') + 10 - } else if 'A' <= s[i] && s[i] <= 'F' { - n <<= 4 - n += int(s[i] - 'A') + 10 - } else { - break - } - } - if i == 0 { - ret 0, i, false - } - ret n, i, true + for i < len(s); i++ { + if '0' <= s[i] && s[i] <= '9' { + n <<= 4 + n += int(s[i] - '0') + } else if 'a' <= s[i] && s[i] <= 'f' { + n <<= 4 + n += int(s[i] - 'a') + 10 + } else if 'A' <= s[i] && s[i] <= 'F' { + n <<= 4 + n += int(s[i] - 'A') + 10 + } else { + break + } + } + if i == 0 { + ret 0, i, false + } + ret n, i, true } \ No newline at end of file diff --git a/std/internal/conv/atoi_test.jule b/std/internal/conv/atoi_test.jule index 424b8eb36..8fa2514ad 100644 --- a/std/internal/conv/atoi_test.jule +++ b/std/internal/conv/atoi_test.jule @@ -7,61 +7,61 @@ use std::testing::{T} struct atoiCase { - s: str - n: int - ok: bool + s: str + n: int + ok: bool } static casesAtoi: []atoiCase = [ - {"000983", 983, true}, - {"-873", -873, true}, - {"98837792362", 98837792362, true}, - {"-0000333444", -333444, true}, - {"-", 0, false}, - {"-3837avc", 0, false}, - {"44_2", 0, false}, + {"000983", 983, true}, + {"-873", -873, true}, + {"98837792362", 98837792362, true}, + {"-0000333444", -333444, true}, + {"-", 0, false}, + {"-3837avc", 0, false}, + {"44_2", 0, false}, ] struct xbtoiCase { - s: []byte - n: int - i: int - ok: bool + s: []byte + n: int + i: int + ok: bool } static casesXbtoi: []xbtoiCase = [ - {[]byte("FFA43"), 0xFFA43, 5, true}, - {[]byte("3344F"), 0x3344F, 5, true}, - {[]byte("0"), 0x0, 1, true}, - {[]byte("000009922A"), 0x9922A, 10, true}, - {[]byte("3837FGH"), 0x3837F, 5, true}, - {[]byte("44F2P"), 0x44F2, 4, true}, - {[]byte("F"), 0xF, 1, true}, - {[]byte("HHKLRF44AA4"), 0x0, 0, false}, + {[]byte("FFA43"), 0xFFA43, 5, true}, + {[]byte("3344F"), 0x3344F, 5, true}, + {[]byte("0"), 0x0, 1, true}, + {[]byte("000009922A"), 0x9922A, 10, true}, + {[]byte("3837FGH"), 0x3837F, 5, true}, + {[]byte("44F2P"), 0x44F2, 4, true}, + {[]byte("F"), 0xF, 1, true}, + {[]byte("HHKLRF44AA4"), 0x0, 0, false}, ] #test fn testAtoi(t: &T) { - for _, case in casesAtoi { - n, ok := Atoi(case.s) - if ok != case.ok { - t.Errorf("expected {} success result for {}, found {}", case.ok, case.s, ok) - } else if ok && n != case.n { - t.Errorf("expected {} for {}, found {}", case.n, case.s, n) - } - } + for _, case in casesAtoi { + n, ok := Atoi(case.s) + if ok != case.ok { + t.Errorf("expected {} success result for {}, found {}", case.ok, case.s, ok) + } else if ok && n != case.n { + t.Errorf("expected {} for {}, found {}", case.n, case.s, n) + } + } } #test fn testXbtoi(t: &T) { - for _, case in casesXbtoi { - n, i, ok := Xbtoi(case.s) - if ok != case.ok { - t.Errorf("expected {} success result for {}, found {}", case.ok, str(case.s), ok) - } else if i != case.i { - t.Errorf("expected i {} for {}, found {}", case.i, str(case.s), i) - } else if ok && n != case.n { - t.Errorf("expected {} for {}, found {}", case.n, str(case.s), n) - } - } + for _, case in casesXbtoi { + n, i, ok := Xbtoi(case.s) + if ok != case.ok { + t.Errorf("expected {} success result for {}, found {}", case.ok, str(case.s), ok) + } else if i != case.i { + t.Errorf("expected i {} for {}, found {}", case.i, str(case.s), i) + } else if ok && n != case.n { + t.Errorf("expected {} for {}, found {}", case.n, str(case.s), n) + } + } } \ No newline at end of file diff --git a/std/internal/conv/itoa.jule b/std/internal/conv/itoa.jule index d20cda5fe..9367b51d5 100755 --- a/std/internal/conv/itoa.jule +++ b/std/internal/conv/itoa.jule @@ -6,35 +6,35 @@ use std::unsafe // Returns x in decimal string format. fn Itoa(x: int): str { - if x < 0 { - ret "-" + Utoa(uint(-x)) - } - ret Utoa(uint(x)) + if x < 0 { + ret "-" + Utoa(uint(-x)) + } + ret Utoa(uint(x)) } // Returns x in decimal string format. fn Utoa(mut x: uint): str { - if x == 0 { - ret "0" - } - mut buf := make([]byte, 20) // big enough for 64bit value base 10 - mut i := 0 - for x >= 10 { - q := x / 10 - buf[i] = byte('0' + x - q * 10) - i++ - x = q - } - // x < 10 - buf[i] = byte('0' + x) - buf = buf[:i+1] - rev(buf) - ret unsafe::StrFromBytes(buf) + if x == 0 { + ret "0" + } + mut buf := make([]byte, 20) // big enough for 64bit value base 10 + mut i := 0 + for x >= 10 { + q := x / 10 + buf[i] = byte('0' + x - q * 10) + i++ + x = q + } + // x < 10 + buf[i] = byte('0' + x) + buf = buf[:i+1] + rev(buf) + ret unsafe::StrFromBytes(buf) } fn rev(mut &b: []byte) { - mut i := 0 - for i < len(b)>>1; i++ { - b[i], b[len(b)-1-i] = b[len(b)-1-i], b[i] - } + mut i := 0 + for i < len(b)>>1; i++ { + b[i], b[len(b)-1-i] = b[len(b)-1-i], b[i] + } } \ No newline at end of file diff --git a/std/internal/conv/itoa_test.jule b/std/internal/conv/itoa_test.jule index 3bf342510..9b6fc8287 100644 --- a/std/internal/conv/itoa_test.jule +++ b/std/internal/conv/itoa_test.jule @@ -7,37 +7,37 @@ use std::testing::{T} struct itoaCase { - i: int - s: str + i: int + s: str } static casesItoa: []itoaCase = [ - {-983, "-983"}, - {-873, "-873"}, - {98837792362, "98837792362"}, - {-333444, "-333444"}, - {0, "0"}, + {-983, "-983"}, + {-873, "-873"}, + {98837792362, "98837792362"}, + {-333444, "-333444"}, + {0, "0"}, ] struct utoaCase { - i: uint - s: str + i: uint + s: str } static casesUtoa: []utoaCase = [ - {983, "983"}, - {873, "873"}, - {98837792362, "98837792362"}, - {333444, "333444"}, - {0, "0"}, + {983, "983"}, + {873, "873"}, + {98837792362, "98837792362"}, + {333444, "333444"}, + {0, "0"}, ] #test fn testUtoa(t: &T) { - for _, case in casesUtoa { - s := Utoa(case.i) - if s != case.s { - t.Errorf("expected {} for {}, found {}", case.s, case.i, s) - } - } + for _, case in casesUtoa { + s := Utoa(case.i) + if s != case.s { + t.Errorf("expected {} for {}, found {}", case.s, case.i, s) + } + } } \ No newline at end of file diff --git a/std/internal/dynar/dynar.jule b/std/internal/dynar/dynar.jule index 4d3379142..83ffcdc8b 100644 --- a/std/internal/dynar/dynar.jule +++ b/std/internal/dynar/dynar.jule @@ -8,16 +8,16 @@ cpp use "dynar.hpp" #typedef #namespace "jule_std" cpp struct DynarBuffer[T] { - heap: *T - len: int - cap: int + heap: *T + len: int + cap: int } #namespace "std" cpp unsafe fn copy(mut start: *unsafe, mut end: *unsafe, mut dest: *unsafe) unsafe fn copy[T](mut dest: *T, mut buff: *T, len: int) { - cpp.copy(buff, buff + len, dest) + cpp.copy(buff, buff + len, dest) } // Dynamic allocation on heap, suitable for dynamic array scenarios. @@ -31,93 +31,93 @@ unsafe fn copy[T](mut dest: *T, mut buff: *T, len: int) { // However, this functions have not any safet checks for performance purposes. // Use this structure carefully. struct Dynar[T] { - Buff: cpp.DynarBuffer[T] + Buff: cpp.DynarBuffer[T] } impl Dynar { - static fn New(): Dynar[T] { - ret Dynar[T]{} - } + static fn New(): Dynar[T] { + ret Dynar[T]{} + } - // Deallocate heap. - fn Dispose(mut self) { - self.Buff.len = 0 - self.Buff.cap = 0 - unsafe { - integ::DeleteArray[T](self.Buff.heap) - } - self.Buff.heap = nil - } + // Deallocate heap. + fn Dispose(mut self) { + self.Buff.len = 0 + self.Buff.cap = 0 + unsafe { + integ::DeleteArray[T](self.Buff.heap) + } + self.Buff.heap = nil + } - // Resizes heap. It will allocate new allocation by size and - // copies old elements into new heap after allocation, then - // deallocates old heap allocation. - // Reports whether process completed successfuly. - fn Resize(mut self, n: int): bool { - mut newHeap := integ::NewArray[T](n) - if newHeap == nil { - ret false - } - if self.Buff.heap == nil { - self.Buff.heap = newHeap - self.Buff.cap = n - ret true - } - unsafe { - mut size := n - if self.Buff.len <= n { - size = self.Buff.len - } - if self.Buff.len > 0 { - copy[T](newHeap, self.Buff.heap, size) - } - unsafe { - integ::DeleteArray[T](self.Buff.heap) - } - self.Buff.heap = newHeap - } - self.Buff.cap = n - ret true - } + // Resizes heap. It will allocate new allocation by size and + // copies old elements into new heap after allocation, then + // deallocates old heap allocation. + // Reports whether process completed successfuly. + fn Resize(mut self, n: int): bool { + mut newHeap := integ::NewArray[T](n) + if newHeap == nil { + ret false + } + if self.Buff.heap == nil { + self.Buff.heap = newHeap + self.Buff.cap = n + ret true + } + unsafe { + mut size := n + if self.Buff.len <= n { + size = self.Buff.len + } + if self.Buff.len > 0 { + copy[T](newHeap, self.Buff.heap, size) + } + unsafe { + integ::DeleteArray[T](self.Buff.heap) + } + self.Buff.heap = newHeap + } + self.Buff.cap = n + ret true + } - // Returns pointer that points to first element of buffer. - fn Begin(mut self): *T { - ret self.Buff.heap - } + // Returns pointer that points to first element of buffer. + fn Begin(mut self): *T { + ret self.Buff.heap + } - // Returns pointer that points to end of the last element of buffer. - fn End(mut self): *T { - ret self.Buff.heap + self.Buff.len - } + // Returns pointer that points to end of the last element of buffer. + fn End(mut self): *T { + ret self.Buff.heap + self.Buff.len + } - // Shift elements to right by n until reach i (including i). - // Starts at end of buffer, goes to left step by step. - fn ShiftRight(mut self, i: int, n: int) { - mut j := self.End() - 1 - k := self.Begin() + i - for j >= k; j-- { - unsafe { - *(j + n) = *j - } - } - } + // Shift elements to right by n until reach i (including i). + // Starts at end of buffer, goes to left step by step. + fn ShiftRight(mut self, i: int, n: int) { + mut j := self.End() - 1 + k := self.Begin() + i + for j >= k; j-- { + unsafe { + *(j + n) = *j + } + } + } - // Shift elements to left by n until reach j (excluding j), start at i. - fn ShiftLeft(mut self, i: int, j: int, n: int) { - mut k := self.Begin() + i - l := self.Begin() + j - for k < l; k++ { - unsafe { - *(k - n) = *k - } - } - } + // Shift elements to left by n until reach j (excluding j), start at i. + fn ShiftLeft(mut self, i: int, j: int, n: int) { + mut k := self.Begin() + i + l := self.Begin() + j + for k < l; k++ { + unsafe { + *(k - n) = *k + } + } + } - // Set buffer elements, starts at i. - // Uses p for read data, reads n elements and assigns to buffer. - fn Set(mut self, i: int, mut p: *T, n: int) { - unsafe { - copy[T](self.Begin() + i, p, n) - } - } + // Set buffer elements, starts at i. + // Uses p for read data, reads n elements and assigns to buffer. + fn Set(mut self, i: int, mut p: *T, n: int) { + unsafe { + copy[T](self.Begin() + i, p, n) + } + } } \ No newline at end of file diff --git a/std/internal/fastbytes/fastbytes.jule b/std/internal/fastbytes/fastbytes.jule index 75a85a0c6..fa6297566 100644 --- a/std/internal/fastbytes/fastbytes.jule +++ b/std/internal/fastbytes/fastbytes.jule @@ -8,77 +8,77 @@ // Reports whether two byte slices are the same length and contains same bytes. // The nil slice considered as zero-length empty slice. fn Equal(s1: []byte, s2: []byte): bool { - match { - | len(s1) != len(s2): - ret false - | len(s1) == 0: - ret true - } - end := &s1[len(s1)-1] - mut it1 := &s1[0] - mut it2 := &s2[0] - for it1 <= end { - unsafe { - if *it1 != *it2 { - ret false - } - } - it1++ - it2++ - } - ret true + match { + | len(s1) != len(s2): + ret false + | len(s1) == 0: + ret true + } + end := &s1[len(s1)-1] + mut it1 := &s1[0] + mut it2 := &s2[0] + for it1 <= end { + unsafe { + if *it1 != *it2 { + ret false + } + } + it1++ + it2++ + } + ret true } // Returns index of first matched item with specified byte, // returns -1 if not exist any match. Starts searching at left // of slice to right. fn FindByte(s: []byte, b: byte): int { - // Trust optimizations of compiler. - for i, se in s { - if se == b { - ret i - } - } - ret -1 + // Trust optimizations of compiler. + for i, se in s { + if se == b { + ret i + } + } + ret -1 } fn findLastByte(begin: *byte, mut end: *byte, b: byte): int { - mut it := end - for it >= begin; it-- { - unsafe { - if (*it == b) { - ret int(it - begin) - } - } - } - ret -1 + mut it := end + for it >= begin; it-- { + unsafe { + if (*it == b) { + ret int(it - begin) + } + } + } + ret -1 } // Returns index of first matched item with specified byte, // returns -1 if not exist any match. Starts searching at right // of slice to left. fn FindLastByte(s: []byte, b: byte): int { - if len(s) == 0 { - ret -1 - } - ret findLastByte(&s[0], &s[len(s)-1], b) + if len(s) == 0 { + ret -1 + } + ret findLastByte(&s[0], &s[len(s)-1], b) } // Same as FindByte, but takes string as byte stack. fn FindByteStr(s: str, b: byte): int { - // Trust optimizations of compiler. - for i, se in s { - if se == b { - ret i - } - } - ret -1 + // Trust optimizations of compiler. + for i, se in s { + if se == b { + ret i + } + } + ret -1 } // Same as FindLastByte, but takes string as byte stack. fn FindLastByteStr(s: str, b: byte): int { - if len(s) == 0 { - ret -1 - } - ret findLastByte(&s[0], &s[len(s)-1], b) + if len(s) == 0 { + ret -1 + } + ret findLastByte(&s[0], &s[len(s)-1], b) } \ No newline at end of file diff --git a/std/internal/fastbytes/fastbytes_test.jule b/std/internal/fastbytes/fastbytes_test.jule index fb52933a9..e9ef27f2e 100644 --- a/std/internal/fastbytes/fastbytes_test.jule +++ b/std/internal/fastbytes/fastbytes_test.jule @@ -7,70 +7,70 @@ use std::testing::{T} struct equalCase { - s1: []byte - s2: []byte - ok: bool + s1: []byte + s2: []byte + ok: bool } struct findByteCase { - bytes: []byte - b: byte - i: int + bytes: []byte + b: byte + i: int } static casesEqual: []equalCase = [ - {[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], true}, - {[]byte("abcd üöpşç"), []byte("abcd üöpşç"), true}, - {[], [], true}, - {nil, nil, true}, - {[], nil, true}, - {[1, 2, 3, 4, 5], [1, 2, 3, 4, 5, 6], false}, - {[1, 2, 3, 4, 5], [1, 2, 3, 4], false}, - {[1, 2, 3, 4], [1, 2, 3, 4, 5], false}, - {[1, 2, 3, 4], [], false}, - {[1, 2, 3, 4], nil, false}, + {[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], true}, + {[]byte("abcd üöpşç"), []byte("abcd üöpşç"), true}, + {[], [], true}, + {nil, nil, true}, + {[], nil, true}, + {[1, 2, 3, 4, 5], [1, 2, 3, 4, 5, 6], false}, + {[1, 2, 3, 4, 5], [1, 2, 3, 4], false}, + {[1, 2, 3, 4], [1, 2, 3, 4, 5], false}, + {[1, 2, 3, 4], [], false}, + {[1, 2, 3, 4], nil, false}, ] static casesFindByte: []findByteCase = [ - {[1, 2, 3, 4, 5, 6, 5, 4], 89, -1}, - {[1, 2, 3, 4, 5, 6, 5, 4], 1, 0}, - {[1, 2, 3, 4, 5, 6, 5, 4], 4, 3}, - {[1, 2, 3, 4, 5, 6, 5, 4], 5, 4}, + {[1, 2, 3, 4, 5, 6, 5, 4], 89, -1}, + {[1, 2, 3, 4, 5, 6, 5, 4], 1, 0}, + {[1, 2, 3, 4, 5, 6, 5, 4], 4, 3}, + {[1, 2, 3, 4, 5, 6, 5, 4], 5, 4}, ] static casesFindLastByte: []findByteCase = [ - {[1, 2, 3, 4, 5, 6, 5, 4], 89, -1}, - {[1, 2, 3, 4, 5, 6, 5, 4], 1, 0}, - {[1, 2, 3, 4, 5, 6, 5, 4], 4, 7}, - {[1, 2, 3, 4, 5, 6, 5, 4], 5, 6}, + {[1, 2, 3, 4, 5, 6, 5, 4], 89, -1}, + {[1, 2, 3, 4, 5, 6, 5, 4], 1, 0}, + {[1, 2, 3, 4, 5, 6, 5, 4], 4, 7}, + {[1, 2, 3, 4, 5, 6, 5, 4], 5, 6}, ] #test fn testEqual(t: &T) { - for _, case in casesEqual { - ok := Equal(case.s1, case.s2) - if ok != case.ok { - t.Errorf("expected {} for Equal({}, {}), found {}", case.ok, case.s1, case.s2, ok) - } - } + for _, case in casesEqual { + ok := Equal(case.s1, case.s2) + if ok != case.ok { + t.Errorf("expected {} for Equal({}, {}), found {}", case.ok, case.s1, case.s2, ok) + } + } } #test fn testFindByte(t: &T) { - for _, case in casesFindByte { - i := FindByte(case.bytes, case.b) - if i != case.i { - t.Errorf("expected {} for FindByte({}, {}), found {}", case.i, case.bytes, case.b, i) - } - } + for _, case in casesFindByte { + i := FindByte(case.bytes, case.b) + if i != case.i { + t.Errorf("expected {} for FindByte({}, {}), found {}", case.i, case.bytes, case.b, i) + } + } } #test fn testFindLastByte(t: &T) { - for _, case in casesFindLastByte { - i := FindLastByte(case.bytes, case.b) - if i != case.i { - t.Errorf("expected {} for FindByte({}, {}), found {}", case.i, case.bytes, case.b, i) - } - } + for _, case in casesFindLastByte { + i := FindLastByte(case.bytes, case.b) + if i != case.i { + t.Errorf("expected {} for FindByte({}, {}), found {}", case.i, case.bytes, case.b, i) + } + } } \ No newline at end of file diff --git a/std/internal/fmt/format.jule b/std/internal/fmt/format.jule index 6550edcd0..ef3388c4f 100644 --- a/std/internal/fmt/format.jule +++ b/std/internal/fmt/format.jule @@ -9,14 +9,14 @@ use utf8 for std::unicode::utf8 use std::internal::strings::{StrBuilder} fn findFormatPrefix(&bytes: []byte, mut i: int): int { - for i < len(bytes) { - r, size := utf8::DecodeRune(bytes[i:]) - if r == '{' { - ret i - } - i += size - } - ret -1 + for i < len(bytes) { + r, size := utf8::DecodeRune(bytes[i:]) + if r == '{' { + ret i + } + i += size + } + ret -1 } // Returns range of {...}, included braces. @@ -25,122 +25,122 @@ fn findFormatPrefix(&bytes: []byte, mut i: int): int { // i is points to position of last brace and +1 offset in the end. // Returns nil slice if there is no match. fn getFormatRange(mut &i: int, mut &bytes: []byte): []byte { - start := i - mut braces := 0 - for i < len(bytes) { - r, size := utf8::DecodeRune(bytes[i:]) - i += size - match r { - | '{': - braces++ - | '}': - braces-- - if braces == 0 { - ret bytes[start:i] - } - } - } - ret nil + start := i + mut braces := 0 + for i < len(bytes) { + r, size := utf8::DecodeRune(bytes[i:]) + i += size + match r { + | '{': + braces++ + | '}': + braces-- + if braces == 0 { + ret bytes[start:i] + } + } + } + ret nil } // Formats arg by default format and appends to buf. fn FmtByDefault(mut &buf: StrBuilder, &arg: any) { - if arg == nil { - buf.WriteStr("") - ret - } - match type arg { - | f32: - buf.WriteStr(conv::FmtFloat(f64(f32(arg)), 'g', -1, 32)) - | f64: - buf.WriteStr(conv::FmtFloat(f64(arg), 'g', -1, 64)) - | i8: - buf.WriteStr(conv::FmtInt(i64(i8(arg)), 10)) - | i16: - buf.WriteStr(conv::FmtInt(i64(i16(arg)), 10)) - | i32: - buf.WriteStr(conv::FmtInt(i64(i32(arg)), 10)) - | i64: - buf.WriteStr(conv::FmtInt(i64(arg), 10)) - | u8: - buf.WriteStr(conv::FmtUint(u64(u8(arg)), 10)) - | u16: - buf.WriteStr(conv::FmtUint(u64(u16(arg)), 10)) - | u32: - buf.WriteStr(conv::FmtUint(u64(u32(arg)), 10)) - | u64: - buf.WriteStr(conv::FmtUint(u64(arg), 10)) - | str: - buf.WriteStr(str(arg)) - | bool: - if bool(arg) { - buf.WriteStr("true") - } else { - buf.WriteStr("false") - } - |: - buf.WriteStr(integ::ToStr(arg)) - } + if arg == nil { + buf.WriteStr("") + ret + } + match type arg { + | f32: + buf.WriteStr(conv::FmtFloat(f64(f32(arg)), 'g', -1, 32)) + | f64: + buf.WriteStr(conv::FmtFloat(f64(arg), 'g', -1, 64)) + | i8: + buf.WriteStr(conv::FmtInt(i64(i8(arg)), 10)) + | i16: + buf.WriteStr(conv::FmtInt(i64(i16(arg)), 10)) + | i32: + buf.WriteStr(conv::FmtInt(i64(i32(arg)), 10)) + | i64: + buf.WriteStr(conv::FmtInt(i64(arg), 10)) + | u8: + buf.WriteStr(conv::FmtUint(u64(u8(arg)), 10)) + | u16: + buf.WriteStr(conv::FmtUint(u64(u16(arg)), 10)) + | u32: + buf.WriteStr(conv::FmtUint(u64(u32(arg)), 10)) + | u64: + buf.WriteStr(conv::FmtUint(u64(arg), 10)) + | str: + buf.WriteStr(str(arg)) + | bool: + if bool(arg) { + buf.WriteStr("true") + } else { + buf.WriteStr("false") + } + |: + buf.WriteStr(integ::ToStr(arg)) + } } fn applyFmtByDefault(mut &buf: StrBuilder, mut &j: int, args: ...any) { - arg := args[j] - j++ - FmtByDefault(buf, arg) + arg := args[j] + j++ + FmtByDefault(buf, arg) } // Returns result of formatting. // Parameter j is the position of argument list. fn applyFmt(mut &fmt: []byte, mut &buf: StrBuilder, mut &j: int, args: ...any) { - // {} - if len(fmt) == 2 { - applyFmtByDefault(buf, j, args...) - ret - } - // {{}} = {} - if len(fmt) == 4 && - fmt[0] == '{' && - fmt[1] == '{' && - fmt[2] == '}' && - fmt[3] == '}' { - buf.WriteStr("{}") - ret - } - buf.Write(fmt) + // {} + if len(fmt) == 2 { + applyFmtByDefault(buf, j, args...) + ret + } + // {{}} = {} + if len(fmt) == 4 && + fmt[0] == '{' && + fmt[1] == '{' && + fmt[2] == '}' && + fmt[3] == '}' { + buf.WriteStr("{}") + ret + } + buf.Write(fmt) } // See the [std::fmt::Format] function. // For this function, returned []byte is might be string literal actually. // Be careful about mutating it. fn Format(fmt: str, args: ...any): []byte { - mut fmtBytes := unsafe::StrBytes(fmt) - if len(args) == 0 { - ret fmtBytes - } - mut i := findFormatPrefix(fmtBytes, 0) - if i == -1 { - ret fmtBytes - } - mut j := 0 - mut last := 0 - mut buf := StrBuilder.New(len(fmt)) - for i != -1; i = findFormatPrefix(fmtBytes, i) { - buf.Write(fmtBytes[last:i]) - mut format := getFormatRange(i, fmtBytes) - if format == nil { - continue - } - applyFmt(format, buf, j, args...) - if j >= len(args) { - buf.Write(fmtBytes[i:]) - last = len(fmtBytes) - break - } - // Set last positioning to latest value of i. - last = i - } - if last < len(fmtBytes) { - buf.Write(fmtBytes[last:]) - } - ret unsafe { buf.Buf() } + mut fmtBytes := unsafe::StrBytes(fmt) + if len(args) == 0 { + ret fmtBytes + } + mut i := findFormatPrefix(fmtBytes, 0) + if i == -1 { + ret fmtBytes + } + mut j := 0 + mut last := 0 + mut buf := StrBuilder.New(len(fmt)) + for i != -1; i = findFormatPrefix(fmtBytes, i) { + buf.Write(fmtBytes[last:i]) + mut format := getFormatRange(i, fmtBytes) + if format == nil { + continue + } + applyFmt(format, buf, j, args...) + if j >= len(args) { + buf.Write(fmtBytes[i:]) + last = len(fmtBytes) + break + } + // Set last positioning to latest value of i. + last = i + } + if last < len(fmtBytes) { + buf.Write(fmtBytes[last:]) + } + ret unsafe { buf.Buf() } } \ No newline at end of file diff --git a/std/internal/strings/builder.jule b/std/internal/strings/builder.jule index 3f746ece0..14fc81147 100644 --- a/std/internal/strings/builder.jule +++ b/std/internal/strings/builder.jule @@ -7,74 +7,74 @@ use utf8 for std::unicode::utf8 // See [std::strings] for documentation. struct StrBuilder { - buf: []byte + buf: []byte } impl StrBuilder { - // Returns new string builder with capacity. - static fn New(cap: int): StrBuilder { - if cap < 0 { - panic("std::strings: StrBuilder.New: cap < 0") - } - ret StrBuilder{ - buf: make([]byte, 0, cap), - } - } + // Returns new string builder with capacity. + static fn New(cap: int): StrBuilder { + if cap < 0 { + panic("std::strings: StrBuilder.New: cap < 0") + } + ret StrBuilder{ + buf: make([]byte, 0, cap), + } + } - // Writes bytes to buffer. - fn Write(mut self, b: []byte) { - self.buf = append(self.buf, b...) - } + // Writes bytes to buffer. + fn Write(mut self, b: []byte) { + self.buf = append(self.buf, b...) + } - // Writes bytes to buffer. - fn WriteStr(mut self, s: str) { - self.buf = append(self.buf, s...) - } + // Writes bytes to buffer. + fn WriteStr(mut self, s: str) { + self.buf = append(self.buf, s...) + } - // Writes byte to buffer. - fn WriteByte(mut self, b: byte) { - self.buf = append(self.buf, b) - } + // Writes byte to buffer. + fn WriteByte(mut self, b: byte) { + self.buf = append(self.buf, b) + } - // Writes rune into buffer. - fn WriteRune(mut self, r: rune) { - if r < utf8::RuneSelf { // ASCII, fast way. - self.buf = append(self.buf, byte(r)) - ret - } - self.WriteStr(str(r)) - } + // Writes rune into buffer. + fn WriteRune(mut self, r: rune) { + if r < utf8::RuneSelf { // ASCII, fast way. + self.buf = append(self.buf, byte(r)) + ret + } + self.WriteStr(str(r)) + } - // Returns as string, then calls the [Clear] method. - fn Str(mut self): str { - mut s := unsafe::StrFromBytes(self.buf) - self.Clear() // Clear common buffer for safety. - ret s - } + // Returns as string, then calls the [Clear] method. + fn Str(mut self): str { + mut s := unsafe::StrFromBytes(self.buf) + self.Clear() // Clear common buffer for safety. + ret s + } - // Clears buffer. - // After calling this function, write calls will allocate new buffer. - fn Clear(mut self) { - self.buf = nil - } + // Clears buffer. + // After calling this function, write calls will allocate new buffer. + fn Clear(mut self) { + self.buf = nil + } - // Returns length of buffer. - fn Len(self): int { - ret len(self.buf) - } + // Returns length of buffer. + fn Len(self): int { + ret len(self.buf) + } - // Returns capacity of buffer. - fn Cap(self): int { - ret cap(self.buf) - } + // Returns capacity of buffer. + fn Cap(self): int { + ret cap(self.buf) + } - // Returns mutable buffer for low-level interactions. - unsafe fn Buf(mut self): []byte { - ret self.buf - } + // Returns mutable buffer for low-level interactions. + unsafe fn Buf(mut self): []byte { + ret self.buf + } - // Sets mutable internal buffer for low-level interactions. - unsafe fn SetBuf(mut self, mut buf: []byte) { - self.buf = buf - } + // Sets mutable internal buffer for low-level interactions. + unsafe fn SetBuf(mut self, mut buf: []byte) { + self.buf = buf + } } \ No newline at end of file diff --git a/std/internal/zsys/io_unix.jule b/std/internal/zsys/io_unix.jule index 95c6ce20e..eb03f5ac2 100644 --- a/std/internal/zsys/io_unix.jule +++ b/std/internal/zsys/io_unix.jule @@ -12,7 +12,7 @@ const MaxRW = 1 << 30 fn handleRW(&b: []byte) { - if len(b) > MaxRW { - unsafe { *(&b) = (*(&b))[:MaxRW] } - } + if len(b) > MaxRW { + unsafe { *(&b) = (*(&b))[:MaxRW] } + } } \ No newline at end of file diff --git a/std/io/byte.jule b/std/io/byte.jule index e4f188ffb..10b3f374e 100644 --- a/std/io/byte.jule +++ b/std/io/byte.jule @@ -7,7 +7,7 @@ // Does not clearing internal buffer at all. // Large buffers can be memory hungry. struct ByteStream { - buff: []byte + buff: []byte } impl Reader for ByteStream {} @@ -15,46 +15,46 @@ impl Writer for ByteStream {} impl Stream for ByteStream {} impl ByteStream { - // Returns new ByteStream instance. - static fn New(): &ByteStream { - ret new(ByteStream) - } + // Returns new ByteStream instance. + static fn New(): &ByteStream { + ret new(ByteStream) + } - // Reports whether buffer have readable data. - fn Data(self): bool { - ret len(self.buff) != 0 - } + // Reports whether buffer have readable data. + fn Data(self): bool { + ret len(self.buff) != 0 + } - // Removes readed bytes from buffer. - // Maybe help to reduce memory usage for large buffers. - fn Fit(mut self) { - if !self.Data() { - self.buff = nil - ret - } - mut buff := make([]byte, len(self.buff)) - _ = copy(buff, self.buff) - self.buff = buff - } + // Removes readed bytes from buffer. + // Maybe help to reduce memory usage for large buffers. + fn Fit(mut self) { + if !self.Data() { + self.buff = nil + ret + } + mut buff := make([]byte, len(self.buff)) + _ = copy(buff, self.buff) + self.buff = buff + } - // Read bytes to buffer from stream and returns readed byte count. - // The number of bytes readed can never exceed the length of the buff. - // If the buff is larger than the number of bytes that can be read, - // the buffer will not cause an overflow. - fn Read(mut self, mut buff: []byte)!: (n: int) { - if !self.Data() { - ret 0 - } - n = copy(buff, self.buff) - self.buff = self.buff[n:] - ret - } + // Read bytes to buffer from stream and returns readed byte count. + // The number of bytes readed can never exceed the length of the buff. + // If the buff is larger than the number of bytes that can be read, + // the buffer will not cause an overflow. + fn Read(mut self, mut buff: []byte)!: (n: int) { + if !self.Data() { + ret 0 + } + n = copy(buff, self.buff) + self.buff = self.buff[n:] + ret + } - // Writes bytes to stream and returns writed byte count. - // The number of bytes written can never exceed the length of the buff. - fn Write(mut self, buff: []byte)!: (n: int) { - n = len(buff) - self.buff = append(self.buff, buff...) - ret - } + // Writes bytes to stream and returns writed byte count. + // The number of bytes written can never exceed the length of the buff. + fn Write(mut self, buff: []byte)!: (n: int) { + n = len(buff) + self.buff = append(self.buff, buff...) + ret + } } \ No newline at end of file diff --git a/std/io/file.jule b/std/io/file.jule index b87e7f903..d957b071a 100644 --- a/std/io/file.jule +++ b/std/io/file.jule @@ -9,14 +9,14 @@ use std::internal::strings::{StrBuilder} // Stream implementation for file handles. // Uses internally mutable buffer. struct FileStream { - buff: &File + buff: &File } impl FileStream { - // Returns new FileStream instance for file. - static fn New(mut f: &File): &FileStream { - ret &FileStream{buff: f} - } + // Returns new FileStream instance for file. + static fn New(mut f: &File): &FileStream { + ret &FileStream{buff: f} + } } impl Reader for FileStream {} @@ -24,68 +24,68 @@ impl Writer for FileStream {} impl Stream for FileStream {} impl FileStream { - // Returns internal file buffer. - fn File(mut self): &File { - ret self.buff - } + // Returns internal file buffer. + fn File(mut self): &File { + ret self.buff + } - // Read bytes to buffer from stream and returns readed byte count. - // The number of bytes readed can never exceed the length of the buff. - // If the buff is larger than the number of bytes that can be read, - // the buffer will not cause an overflow. - fn Read(mut self, mut buff: []byte)!: (n: int) { - ret self.buff.Read(buff) else { error(error) } - } + // Read bytes to buffer from stream and returns readed byte count. + // The number of bytes readed can never exceed the length of the buff. + // If the buff is larger than the number of bytes that can be read, + // the buffer will not cause an overflow. + fn Read(mut self, mut buff: []byte)!: (n: int) { + ret self.buff.Read(buff) else { error(error) } + } - // Writes bytes to stream and returns writed byte count. - // The number of bytes written can never exceed the length of the buff. - fn Write(mut self, buff: []byte)!: (n: int) { - ret self.buff.Write(buff) else { error(error) } - } + // Writes bytes to stream and returns writed byte count. + // The number of bytes written can never exceed the length of the buff. + fn Write(mut self, buff: []byte)!: (n: int) { + ret self.buff.Write(buff) else { error(error) } + } - // Same as read_line method, but returns in bytes. - fn ReadLineBytes(mut self)!: []byte { - const LINE_DELIMITER = '\n' + // Same as read_line method, but returns in bytes. + fn ReadLineBytes(mut self)!: []byte { + const LINE_DELIMITER = '\n' - mut buff := make([]byte, 1, 1024) - let mut partBuff: bufferArray - mut part := unsafe::Slice(&partBuff[0], len(partBuff)) - for { - n := self.buff.Read(part) else { error(error) } - if n == 0 { - break - } - if part[n-1] == LINE_DELIMITER { - buff = append(buff, part[:n-1]...) - break - } - buff = append(buff, part[:n]...) - } - clearCr(buff) - ret buff - } + mut buff := make([]byte, 1, 1024) + let mut partBuff: bufferArray + mut part := unsafe::Slice(&partBuff[0], len(partBuff)) + for { + n := self.buff.Read(part) else { error(error) } + if n == 0 { + break + } + if part[n-1] == LINE_DELIMITER { + buff = append(buff, part[:n-1]...) + break + } + buff = append(buff, part[:n]...) + } + clearCr(buff) + ret buff + } - // Reads line from file handle via &File.read method. - // Returns bytes until end of the line, line delimiter is not included. - // Returns zero-length string when reached EOF. - fn ReadLine(mut self)!: str { - const LINE_DELIMITER = '\n' + // Reads line from file handle via &File.read method. + // Returns bytes until end of the line, line delimiter is not included. + // Returns zero-length string when reached EOF. + fn ReadLine(mut self)!: str { + const LINE_DELIMITER = '\n' - mut buf := StrBuilder.New(1 << 10) - let mut partBuff: bufferArray - mut part := unsafe::Slice(&partBuff[0], len(partBuff)) - for { - n := self.buff.Read(part) else { error(error) } - if n == 0 { - break - } - if part[n-1] == LINE_DELIMITER { - buf.Write(part[:n-1]) - break - } - buf.Write(part[:n]) - } - unsafe { buf.SetBuf(clearCr(buf.Buf())) } - ret buf.Str() - } + mut buf := StrBuilder.New(1 << 10) + let mut partBuff: bufferArray + mut part := unsafe::Slice(&partBuff[0], len(partBuff)) + for { + n := self.buff.Read(part) else { error(error) } + if n == 0 { + break + } + if part[n-1] == LINE_DELIMITER { + buf.Write(part[:n-1]) + break + } + buf.Write(part[:n]) + } + unsafe { buf.SetBuf(clearCr(buf.Buf())) } + ret buf.Str() + } } \ No newline at end of file diff --git a/std/io/io.jule b/std/io/io.jule index 26d8b5088..44f5155df 100644 --- a/std/io/io.jule +++ b/std/io/io.jule @@ -13,21 +13,21 @@ type bufferArray: [128]bufferArrayElem // Returns FileStream for stdin. fn Stdin(): &FileStream { - static mut stdin = File.New(sys::STDIN) - static mut stream = FileStream.New(stdin) - ret unsafe { (&FileStream)((*FileStream)(stream)) } + static mut stdin = File.New(sys::STDIN) + static mut stream = FileStream.New(stdin) + ret unsafe { (&FileStream)((*FileStream)(stream)) } } // Returns FileStream for stdout. fn Stdout(): &FileStream { - static mut stdout = File.New(sys::STDOUT) - static mut stream = FileStream.New(stdout) - ret unsafe { (&FileStream)((*FileStream)(stream)) } + static mut stdout = File.New(sys::STDOUT) + static mut stream = FileStream.New(stdout) + ret unsafe { (&FileStream)((*FileStream)(stream)) } } // Returns FileStream for stderr. fn Stderr(): &FileStream { - static mut stderr = File.New(sys::STDERR) - static mut stream = FileStream.New(stderr) - ret unsafe { (&FileStream)((*FileStream)(stream)) } + static mut stderr = File.New(sys::STDERR) + static mut stream = FileStream.New(stderr) + ret unsafe { (&FileStream)((*FileStream)(stream)) } } \ No newline at end of file diff --git a/std/io/scan.jule b/std/io/scan.jule index 8f405d669..93b2d290e 100644 --- a/std/io/scan.jule +++ b/std/io/scan.jule @@ -8,75 +8,75 @@ use std::fs::{File} // Scanner for files or etc. // Scans bytes line-by-line. struct Scanner { - mut r: Reader - mut b: []byte + mut r: Reader + mut b: []byte } impl Scanner { - const bufferSize = 1 << 10 + const bufferSize = 1 << 10 - // New &Scanner from Reader. - static fn New(mut r: Reader): &Scanner { - ret &Scanner{ - r: r, - b: make([]byte, 0, Scanner.bufferSize), - } - } + // New &Scanner from Reader. + static fn New(mut r: Reader): &Scanner { + ret &Scanner{ + r: r, + b: make([]byte, 0, Scanner.bufferSize), + } + } - // New &Scanner from &File. - // Uses &FileStream for Reader trait compatibility. - static fn Newf(mut f: &File): &Scanner { - ret &Scanner{ - r: FileStream.New(f), - b: make([]byte, 0, Scanner.bufferSize), - } - } + // New &Scanner from &File. + // Uses &FileStream for Reader trait compatibility. + static fn Newf(mut f: &File): &Scanner { + ret &Scanner{ + r: FileStream.New(f), + b: make([]byte, 0, Scanner.bufferSize), + } + } } impl Scanner { - fn reset(self) { - self.b = self.b[:0] - } + fn reset(self) { + self.b = self.b[:0] + } - // Returns bytes of recent scan. - // Returned slice is mutable copy of buffer. - // The next [Scan] call will write into same internal allocation. - fn Bytes(self): []byte { ret self.b } + // Returns bytes of recent scan. + // Returned slice is mutable copy of buffer. + // The next [Scan] call will write into same internal allocation. + fn Bytes(self): []byte { ret self.b } - // Returns text from bytes of recent scan. - fn Text(self): str { ret str(self.b) } + // Returns text from bytes of recent scan. + fn Text(self): str { ret str(self.b) } - // Scans line from handle via read method. - // Scans bytes until end of the line, line delimiter is not included. - // Reports whether readed byte into buffer. - // Forwards any exceptional. - fn Scan(self)!: bool { - const LINE_DELIMITER = '\n' + // Scans line from handle via read method. + // Scans bytes until end of the line, line delimiter is not included. + // Reports whether readed byte into buffer. + // Forwards any exceptional. + fn Scan(self)!: bool { + const LINE_DELIMITER = '\n' - self.reset() + self.reset() - let mut partBuff: bufferArray - mut part := unsafe::Slice(&partBuff[0], len(partBuff)) - for { - n := self.r.Read(part) else { error(error) } - if n == 0 { - break - } - if part[n-1] == LINE_DELIMITER { - self.b = append(self.b, part[:n-1]...) - break - } - self.b = append(self.b, part[:n]...) - } - self.b = clearCr(self.b) - ret len(self.b) > 0 - } + let mut partBuff: bufferArray + mut part := unsafe::Slice(&partBuff[0], len(partBuff)) + for { + n := self.r.Read(part) else { error(error) } + if n == 0 { + break + } + if part[n-1] == LINE_DELIMITER { + self.b = append(self.b, part[:n-1]...) + break + } + self.b = append(self.b, part[:n]...) + } + self.b = clearCr(self.b) + ret len(self.b) > 0 + } } // Clear last carriage return from buff if exist. fn clearCr(mut buf: []byte): []byte { - if len(buf) > 0 && buf[len(buf)-1] == '\r' { - ret buf[:len(buf)-1] - } - ret buf + if len(buf) > 0 && buf[len(buf)-1] == '\r' { + ret buf[:len(buf)-1] + } + ret buf } \ No newline at end of file diff --git a/std/io/stream.jule b/std/io/stream.jule index faa12e959..7562cda6b 100644 --- a/std/io/stream.jule +++ b/std/io/stream.jule @@ -4,22 +4,22 @@ // Reader trait mask for stream reader. trait Reader { - fn Read(mut self, mut buff: []byte)!: (n: int) + fn Read(mut self, mut buff: []byte)!: (n: int) } // Reader trait mask for stream writer. trait Writer { - fn Write(mut self, buff: []byte)!: (n: int) + fn Write(mut self, buff: []byte)!: (n: int) } // Reader and closer trait mask for read/close streams. trait WriterCloser { - Writer - fn Close(mut self)! + Writer + fn Close(mut self)! } // Stream trait mask for R/W streams. trait Stream { - Reader - Writer + Reader + Writer } \ No newline at end of file diff --git a/std/jule/ast/ast.jule b/std/jule/ast/ast.jule index 24c7537d8..7ab98353f 100644 --- a/std/jule/ast/ast.jule +++ b/std/jule/ast/ast.jule @@ -6,8 +6,8 @@ use std::jule::lex::{File} // Abstract syntax tree. struct Ast { - File: &File - TopDirectives: []&Directive - UseDecls: []&UseDecl - Nodes: []Node + File: &File + TopDirectives: []&Directive + UseDecls: []&UseDecl + Nodes: []Node } \ No newline at end of file diff --git a/std/jule/ast/node.jule b/std/jule/ast/node.jule index 422b2ccc8..7641babe5 100644 --- a/std/jule/ast/node.jule +++ b/std/jule/ast/node.jule @@ -6,40 +6,40 @@ use std::jule::lex::{Token, TokenId, TokenKind, Ident} // Type of AST Node's data. enum NodeData: type { - &EnumDecl, - &TypeEnumDecl, - &FnDecl, - &StructDecl, - &TraitDecl, - &TypeAliasDecl, - &VarDecl, - &Impl, + &EnumDecl, + &TypeEnumDecl, + &FnDecl, + &StructDecl, + &TraitDecl, + &TypeAliasDecl, + &VarDecl, + &Impl, } // AST Node. struct Node { - Token: &Token - Data: NodeData + Token: &Token + Data: NodeData } // Directive. struct Directive { - Tag: &Token - Args: []&Token + Tag: &Token + Args: []&Token } // Kind type of type declarations. enum TypeDeclKind: type { - &IdentTypeDecl, - &SubIdentTypeDecl, - &SptrTypeDecl, - &PtrTypeDecl, - &SlcTypeDecl, - &ArrTypeDecl, - &MapTypeDecl, - &TupleTypeDecl, - &FnDecl, - &NamespaceTypeDecl, + &IdentTypeDecl, + &SubIdentTypeDecl, + &SptrTypeDecl, + &PtrTypeDecl, + &SlcTypeDecl, + &ArrTypeDecl, + &MapTypeDecl, + &TupleTypeDecl, + &FnDecl, + &NamespaceTypeDecl, } // Type declaration. @@ -53,662 +53,662 @@ enum TypeDeclKind: type { // For function types: // - Function types represented by &FnDecl. struct TypeDecl { - Token: &Token - Kind: TypeDeclKind + Token: &Token + Kind: TypeDeclKind } // Identifier type. struct IdentTypeDecl { - Token: &Token - Ident: str - Binded: bool - Generics: []&TypeDecl + Token: &Token + Ident: str + Binded: bool + Generics: []&TypeDecl } // Sub-identifier type. struct SubIdentTypeDecl { - Idents: []&IdentTypeDecl + Idents: []&IdentTypeDecl } // Namespace chain type. struct NamespaceTypeDecl { - Idents: []&Token // Namespace chain with identifier tokens. - Kind: &TypeDecl // Type of identifier. + Idents: []&Token // Namespace chain with identifier tokens. + Kind: &TypeDecl // Type of identifier. } // Smart pointer type. struct SptrTypeDecl { - Elem: &TypeDecl + Elem: &TypeDecl } // Slice type. struct SlcTypeDecl { - Elem: &TypeDecl + Elem: &TypeDecl } // Tuple type. struct TupleTypeDecl { - Types: []&TypeDecl + Types: []&TypeDecl } // Pointer type. struct PtrTypeDecl { - Elem: &TypeDecl + Elem: &TypeDecl } impl PtrTypeDecl { - // Reports whether pointer is unsafe pointer (*unsafe). - fn IsUnsafe(self): bool { - ret self.Elem == nil - } + // Reports whether pointer is unsafe pointer (*unsafe). + fn IsUnsafe(self): bool { + ret self.Elem == nil + } } // Array type. // Size epxression is nil for auto-sized array. struct ArrTypeDecl { - Elem: &TypeDecl - Size: &Expr + Elem: &TypeDecl + Size: &Expr } impl ArrTypeDecl { - // Reports whether array is auto-sized. - fn AutoSized(self): bool { - ret self.Size == nil - } + // Reports whether array is auto-sized. + fn AutoSized(self): bool { + ret self.Size == nil + } } // Map type. struct MapTypeDecl { - Key: &TypeDecl - Val: &TypeDecl + Key: &TypeDecl + Val: &TypeDecl } // Return type. // Kind and Idents is nil for void type. struct RetTypeDecl { - Kind: &TypeDecl - Idents: []&Token + Kind: &TypeDecl + Idents: []&Token } // Type of Expr's data. enum ExprData: type { - &RangeExpr, - &TupleExpr, - &LitExpr, - &TypeDecl, - &IdentExpr, - &UnaryExpr, - &SubIdentExpr, - &NsSelectionExpr, - &VariadicExpr, - &CastExpr, - &FnCallExpr, - &StructLit, - &BraceLit, - &SlicingExpr, - &SliceExpr, - &BinaryExpr, - &UnsafeExpr, - &IndexingExpr, - &FnDecl, - &FieldExprPair, - &KeyValPair, + &RangeExpr, + &TupleExpr, + &LitExpr, + &TypeDecl, + &IdentExpr, + &UnaryExpr, + &SubIdentExpr, + &NsSelectionExpr, + &VariadicExpr, + &CastExpr, + &FnCallExpr, + &StructLit, + &BraceLit, + &SlicingExpr, + &SliceExpr, + &BinaryExpr, + &UnsafeExpr, + &IndexingExpr, + &FnDecl, + &FieldExprPair, + &KeyValPair, } // Expression. struct Expr { - Token: &Token - End: &Token - Kind: ExprData + Token: &Token + End: &Token + Kind: ExprData } // Range expression between parentheses. struct RangeExpr { - Expr: &Expr + Expr: &Expr } // Use expression. struct UseExpr { - Token: &Token - Expr: &Expr + Token: &Token + Expr: &Expr } // Tuple expression. struct TupleExpr { - Expr: []&Expr + Expr: []&Expr } // Literal expression. struct LitExpr { - Token: &Token - Value: str + Token: &Token + Value: str } // Unsafe expression. struct UnsafeExpr { - Token: &Token // Token of unsafe keyword. - Expr: &Expr + Token: &Token // Token of unsafe keyword. + Expr: &Expr } // Identifier expression. struct IdentExpr { - Token: &Token // Token of identifier. - Ident: str - Binded: bool + Token: &Token // Token of identifier. + Ident: str + Binded: bool } impl IdentExpr { - // Reports whether identifier is self keyword. - fn IsSelf(self): bool { - ret self.Ident == TokenKind.Self - } + // Reports whether identifier is self keyword. + fn IsSelf(self): bool { + ret self.Ident == TokenKind.Self + } } // Unary expression. struct UnaryExpr { - Op: &Token - Expr: &Expr + Op: &Token + Expr: &Expr } // Variadiced expression. struct VariadicExpr { - Token: &Token - Expr: &Expr + Token: &Token + Expr: &Expr } // Casting expression. struct CastExpr { - Kind: &TypeDecl - Expr: &Expr + Kind: &TypeDecl + Expr: &Expr } // Namespace identifier selection expression. struct NsSelectionExpr { - Ns: []&Token // Tokens of selected namespace identifier chain. - Ident: &Token // Token of selected identifier. + Ns: []&Token // Tokens of selected namespace identifier chain. + Ident: &Token // Token of selected identifier. } // Object sub identifier selection expression. struct SubIdentExpr { - Expr: &Expr // Selected object. - Ident: &Token // TOken of selected identifier. + Expr: &Expr // Selected object. + Ident: &Token // TOken of selected identifier. } // Binary operation. struct BinaryExpr { - Left: &Expr - Right: &Expr - Op: &Token + Left: &Expr + Right: &Expr + Op: &Token } // Function call expression kind. struct FnCallExpr { - Token: &Token - Expr: &Expr - Args: []&Expr - Exception: &ScopeTree // Exception handling scope. - IsCo: bool + Token: &Token + Expr: &Expr + Args: []&Expr + Exception: &ScopeTree // Exception handling scope. + IsCo: bool } impl FnCallExpr { - // Reports whether exception is not handled. - fn Unhandled(self): bool { - ret self.Exception == nil - } + // Reports whether exception is not handled. + fn Unhandled(self): bool { + ret self.Exception == nil + } - // Reports whether exception is ignored. - fn Ignored(self): bool { - // Return true if deferred field is true. - // Deferred field used mark for exception ignored calls like: x()! - ret self.Exception != nil && self.Exception.Deferred - } + // Reports whether exception is ignored. + fn Ignored(self): bool { + // Return true if deferred field is true. + // Deferred field used mark for exception ignored calls like: x()! + ret self.Exception != nil && self.Exception.Deferred + } } // Field-Expression pair. struct FieldExprPair { - Field: &Token // Field identifier token. - Expr: &Expr + Field: &Token // Field identifier token. + Expr: &Expr } impl FieldExprPair { - // Reports whether pair targeted field. - fn IsTargeted(self): bool { - ret self.Field != nil - } + // Reports whether pair targeted field. + fn IsTargeted(self): bool { + ret self.Field != nil + } } // Struct literal instiating expression. struct StructLit { - End: &Token - Kind: &TypeDecl - Exprs: []&Expr // Possible types: &FieldExprPair, and other expressions. + End: &Token + Kind: &TypeDecl + Exprs: []&Expr // Possible types: &FieldExprPair, and other expressions. } // Anonymous brace instiating expression. struct BraceLit { - Token: &Token - End: &Token - Exprs: []&Expr + Token: &Token + End: &Token + Exprs: []&Expr } impl BraceLit { - // Reports whether literal is empty ( {} ). - fn IsEmpty(self): bool { - ret len(self.Exprs) == 0 - } + // Reports whether literal is empty ( {} ). + fn IsEmpty(self): bool { + ret len(self.Exprs) == 0 + } } // Key-value pair expression. struct KeyValPair { - Key: &Expr - Val: &Expr - Colon: &Token + Key: &Expr + Val: &Expr + Colon: &Token } // Slice initiating expression. // Also represents array initiating expression. struct SliceExpr { - Token: &Token - End: &Token - Exprs: []&Expr + Token: &Token + End: &Token + Exprs: []&Expr } impl SliceExpr { - // Reports whether slice is empty. - fn IsEmpty(self): bool { - ret len(self.Exprs) == 0 - } + // Reports whether slice is empty. + fn IsEmpty(self): bool { + ret len(self.Exprs) == 0 + } } // Indexing expression. struct IndexingExpr { - Token: &Token - End: &Token - Expr: &Expr // Value expression to indexing. - Index: &Expr // Index value expression. + Token: &Token + End: &Token + Expr: &Expr // Value expression to indexing. + Index: &Expr // Index value expression. } // Slicing expression. struct SlicingExpr { - Token: &Token - End: &Token - Expr: &Expr // Value expression to slicing. - Start: &Expr // Start index value expression. - To: &Expr // To index value expression. + Token: &Token + End: &Token + Expr: &Expr // Value expression to slicing. + Start: &Expr // Start index value expression. + To: &Expr // To index value expression. } // Constraint. struct Constraint { - Mask: []&TypeDecl + Mask: []&TypeDecl } // Generic type declaration. struct GenericDecl { - Token: &Token - Ident: str - Constraint: &Constraint + Token: &Token + Ident: str + Constraint: &Constraint } // Label statement. struct LabelSt { - Token: &Token - Ident: str + Token: &Token + Ident: str } // Goto statement. struct GotoSt { - Token: &Token - Label: &Token + Token: &Token + Label: &Token } // Fall statement. struct FallSt { - Token: &Token + Token: &Token } // Left expression of assign statement. struct AssignLeft { - Token: &Token - Mutable: bool - Reference: bool - Ident: str - Expr: &Expr + Token: &Token + Mutable: bool + Reference: bool + Ident: str + Expr: &Expr } // Assign statement. struct AssignSt { - Declarative: bool - Setter: &Token - Left: []&AssignLeft - Right: &Expr + Declarative: bool + Setter: &Token + Left: []&AssignLeft + Right: &Expr } // Type of Stmt's data. enum StmtData: type { - &VarDecl, - &RetSt, - &GotoSt, - &BreakSt, - &ContSt, - &Expr, - &Conditional, - &MatchCase, - &Iter, - &AssignSt, - &FallSt, - &LabelSt, - &ScopeTree, - &TypeAliasDecl, - &UseExpr, + &VarDecl, + &RetSt, + &GotoSt, + &BreakSt, + &ContSt, + &Expr, + &Conditional, + &MatchCase, + &Iter, + &AssignSt, + &FallSt, + &LabelSt, + &ScopeTree, + &TypeAliasDecl, + &UseExpr, } // Statement. struct Stmt { - Token: &Token - Data: StmtData + Token: &Token + Data: StmtData } // Scope tree. struct ScopeTree { - Parent: &ScopeTree // Nil if scope is root. - Unsafety: bool - Deferred: bool - Stmts: []Stmt - End: &Token + Parent: &ScopeTree // Nil if scope is root. + Unsafety: bool + Deferred: bool + Stmts: []Stmt + End: &Token } // Parameter. struct ParamDecl { - Token: &Token - Mutable: bool - Variadic: bool - Reference: bool - Kind: &TypeDecl - Ident: str + Token: &Token + Mutable: bool + Variadic: bool + Reference: bool + Kind: &TypeDecl + Ident: str } impl ParamDecl { - // Reports whether parameter is self (receiver) parameter. - fn IsSelf(self): bool { - ret self.Ident == "&self" || self.Ident == "self" - } + // Reports whether parameter is self (receiver) parameter. + fn IsSelf(self): bool { + ret self.Ident == "&self" || self.Ident == "self" + } - // Reports whether self (receiver) parameter is reference. - fn IsRef(self): bool { - ret self.Ident != "" && self.Ident[0] == '&' - } + // Reports whether self (receiver) parameter is reference. + fn IsRef(self): bool { + ret self.Ident != "" && self.Ident[0] == '&' + } } // Function declaration. // Also represents anonymous function expression. struct FnDecl { - Token: &Token - Global: bool - Unsafety: bool - Public: bool - Binded: bool - Statically: bool - Exceptional: bool - Ident: str - Directives: []&Directive - Scope: &ScopeTree - Generics: []&GenericDecl - Result: &RetTypeDecl - Params: []&ParamDecl + Token: &Token + Global: bool + Unsafety: bool + Public: bool + Binded: bool + Statically: bool + Exceptional: bool + Ident: str + Directives: []&Directive + Scope: &ScopeTree + Generics: []&GenericDecl + Result: &RetTypeDecl + Params: []&ParamDecl } impl FnDecl { - // Reports whether function is anonymous. - fn IsAnon(self): bool { - ret self.Ident == Ident.Anon - } + // Reports whether function is anonymous. + fn IsAnon(self): bool { + ret self.Ident == Ident.Anon + } } // Variable declaration. struct VarDecl { - Scope: &ScopeTree // nil for global scopes - Token: &Token - Setter: &Token - Ident: str - Binded: bool - Public: bool - Mutable: bool - Constant: bool - Statically: bool - Reference: bool - Directives: []&Directive - Kind: &TypeDecl // nil for type inferred - Expr: &Expr + Scope: &ScopeTree // nil for global scopes + Token: &Token + Setter: &Token + Ident: str + Binded: bool + Public: bool + Mutable: bool + Constant: bool + Statically: bool + Reference: bool + Directives: []&Directive + Kind: &TypeDecl // nil for type inferred + Expr: &Expr } // Return statement. struct RetSt { - Token: &Token - Expr: &Expr + Token: &Token + Expr: &Expr } // Type of Iter's kind. enum IterKind: type { - &WhileKind, - &RangeKind, + &WhileKind, + &RangeKind, } // Iteration. struct Iter { - Comptime: bool - Token: &Token - Kind: IterKind - Scope: &ScopeTree + Comptime: bool + Token: &Token + Kind: IterKind + Scope: &ScopeTree } impl Iter { - // Reports whether iteration is infinity. - fn IsInf(self): bool { ret self.Kind == nil } + // Reports whether iteration is infinity. + fn IsInf(self): bool { ret self.Kind == nil } } // While iteration kind. struct WhileKind { - Expr: &Expr - Next: StmtData // Nil if kind is while-next iteration. - NextToken: &Token + Expr: &Expr + Next: StmtData // Nil if kind is while-next iteration. + NextToken: &Token } impl WhileKind { - // Reports whether kind is while-next iteration. - fn IsWhileNext(self): bool { - ret self.Next != nil - } + // Reports whether kind is while-next iteration. + fn IsWhileNext(self): bool { + ret self.Next != nil + } } // Range iteration kind. struct RangeKind { - InToken: &Token // Token of "in" keyword - Expr: &Expr - KeyA: &VarDecl // first key of range - KeyB: &VarDecl // second key of range + InToken: &Token // Token of "in" keyword + Expr: &Expr + KeyA: &VarDecl // first key of range + KeyB: &VarDecl // second key of range } // Break statement. struct BreakSt { - Token: &Token - Label: &Token + Token: &Token + Label: &Token } // Continue statement. struct ContSt { - Token: &Token - Label: &Token + Token: &Token + Label: &Token } // If condition. struct If { - Token: &Token - Expr: &Expr - Scope: &ScopeTree + Token: &Token + Expr: &Expr + Scope: &ScopeTree } // Else condition. struct Else { - Token: &Token - Scope: &ScopeTree + Token: &Token + Scope: &ScopeTree } // Condition chain. struct Conditional { - Head: &If - Tail: []&If - Default: &Else + Head: &If + Tail: []&If + Default: &Else } // Type alias declaration. struct TypeAliasDecl { - Scope: &ScopeTree - Public: bool - Binded: bool - Token: &Token - Ident: str - Kind: &TypeDecl + Scope: &ScopeTree + Public: bool + Binded: bool + Token: &Token + Ident: str + Kind: &TypeDecl } // Case of match-case. struct Case { - Token: &Token - Scope: &ScopeTree + Token: &Token + Scope: &ScopeTree - // Holds expression. - // Expressions holds *Type if If type matching. - Exprs: []&Expr + // Holds expression. + // Expressions holds *Type if If type matching. + Exprs: []&Expr } // Match-Case. struct MatchCase { - Comptime: bool - Token: &Token - End: &Token - TypeMatch: bool - Expr: &Expr - Cases: []&Case - Default: &Else + Comptime: bool + Token: &Token + End: &Token + TypeMatch: bool + Expr: &Expr + Cases: []&Case + Default: &Else } // Use declaration statement. struct UseDecl { - Token: &Token - LinkPath: str // Use declaration path string. - Alias: str - Full: bool // Full implicit import. - Selected: []&Token - Binded: bool // Bind use declaration. - Std: bool // Standard package use declaration. + Token: &Token + LinkPath: str // Use declaration path string. + Alias: str + Full: bool // Full implicit import. + Selected: []&Token + Binded: bool // Bind use declaration. + Std: bool // Standard package use declaration. } // Enum item. struct EnumItemDecl { - Token: &Token - Ident: str - Expr: &Expr // Nil for auto expression. + Token: &Token + Ident: str + Expr: &Expr // Nil for auto expression. } impl EnumItemDecl { - // Reports whether item has auto expression. - fn AutoExpr(self): bool { - ret self.Expr == nil - } + // Reports whether item has auto expression. + fn AutoExpr(self): bool { + ret self.Expr == nil + } } // Enum declaration. struct EnumDecl { - Token: &Token - Public: bool - Ident: str - Kind: &TypeDecl - Items: []&EnumItemDecl - End: &Token + Token: &Token + Public: bool + Ident: str + Kind: &TypeDecl + Items: []&EnumItemDecl + End: &Token } impl EnumDecl { - // Reports whether enum's type is default. - fn DefaultTyped(self): bool { - ret self.Kind == nil - } + // Reports whether enum's type is default. + fn DefaultTyped(self): bool { + ret self.Kind == nil + } } // TypeEnum item. struct TypeEnumItemDecl { - Token: &Token - Ident: str - Kind: &TypeDecl + Token: &Token + Ident: str + Kind: &TypeDecl } // TypeEnum declaration. struct TypeEnumDecl { - Token: &Token - Public: bool - Ident: str - Items: []&TypeEnumItemDecl - End: &Token + Token: &Token + Public: bool + Ident: str + Items: []&TypeEnumItemDecl + End: &Token } // Field declaration. struct FieldDecl { - Token: &Token - Public: bool - Mutable: bool // Interior mutability. - Ident: str - Kind: &TypeDecl - Default: &Expr // Nil if not given. + Token: &Token + Public: bool + Mutable: bool // Interior mutability. + Ident: str + Kind: &TypeDecl + Default: &Expr // Nil if not given. } // Structure declaration. struct StructDecl { - Token: &Token - End: &Token - Ident: str - Fields: []&FieldDecl - Public: bool - Binded: bool - Directives: []&Directive - Generics: []&GenericDecl + Token: &Token + End: &Token + Ident: str + Fields: []&FieldDecl + Public: bool + Binded: bool + Directives: []&Directive + Generics: []&GenericDecl } // Trait declaration. struct TraitDecl { - Token: &Token - End: &Token - Ident: str - Public: bool - Inherits: []&TypeDecl - Methods: []&FnDecl + Token: &Token + End: &Token + Ident: str + Public: bool + Inherits: []&TypeDecl + Methods: []&FnDecl } // Implementation. struct Impl { - End: &Token + End: &Token - // This token available for these cases: - // - Implementation trait to structure, represents trait's type. - Base: &TypeDecl + // This token available for these cases: + // - Implementation trait to structure, represents trait's type. + Base: &TypeDecl - // This token available for these cases: - // - Implementation trait to structure, represents structure's type. - // - Implementation to structure, represents structure's type. - Dest: &TypeDecl + // This token available for these cases: + // - Implementation trait to structure, represents structure's type. + // - Implementation to structure, represents structure's type. + Dest: &TypeDecl - // Given methods to implement. - Methods: []&FnDecl + // Given methods to implement. + Methods: []&FnDecl - // Static variables to implement. - Statics: []&VarDecl + // Static variables to implement. + Statics: []&VarDecl } impl Impl { - // Reports whether implementation type is trait to structure. - fn IsTraitImpl(self): bool { - ret self.Base != nil - } - - // Reports whether implementation type is append to destination structure. - fn IsStructImpl(self): bool { - ret self.Base == nil - } + // Reports whether implementation type is trait to structure. + fn IsTraitImpl(self): bool { + ret self.Base != nil + } + + // Reports whether implementation type is append to destination structure. + fn IsStructImpl(self): bool { + ret self.Base == nil + } } \ No newline at end of file diff --git a/std/jule/build/cpp.jule b/std/jule/build/cpp.jule index 9f00a94f8..3bd38c511 100644 --- a/std/jule/build/cpp.jule +++ b/std/jule/build/cpp.jule @@ -4,53 +4,53 @@ // Valid extensions of C++ headers. static CppHeaderExts: [...]str = [ - ".h", - ".hpp", - ".hxx", - ".hh", + ".h", + ".hpp", + ".hxx", + ".hh", ] // Valid extensions of C++ source files. static CppExts: [...]str = [ - ".cpp", - ".cc", - ".cxx", + ".cpp", + ".cc", + ".cxx", ] // Valid extensions of Objective-C++ source files. static ObjectiveCppExts: [...]str = [ - ".mm", + ".mm", ] // Reports whether path is C++ std library path. fn IsStdHeaderPath(p: str): bool { - ret p[0] == '<' && p[len(p)-1] == '>' + ret p[0] == '<' && p[len(p)-1] == '>' } // Reports whether C++ header extension is valid. fn IsValidHeaderExt(ext: str): bool { - for _, validExt in CppHeaderExts { - if ext == validExt { - ret true - } - } - ret false + for _, validExt in CppHeaderExts { + if ext == validExt { + ret true + } + } + ret false } // Reports whether C++ extension is valid. fn IsValidCppExt(ext: str): bool { - if ext == ".c" { - ret true - } - for _, e in CppExts { - if ext == e { - ret true - } - } - for _, e in ObjectiveCppExts { - if ext == e { - ret true - } - } - ret false + if ext == ".c" { + ret true + } + for _, e in CppExts { + if ext == e { + ret true + } + } + for _, e in ObjectiveCppExts { + if ext == e { + ret true + } + } + ret false } \ No newline at end of file diff --git a/std/jule/build/directive.jule b/std/jule/build/directive.jule index 703b07f62..85a097d31 100644 --- a/std/jule/build/directive.jule +++ b/std/jule/build/directive.jule @@ -9,17 +9,17 @@ const DIRECTIVEPREFIX = "jule:" // Compiler directives. enum Directive: str { - Cdef: "cdef", - Typedef: "typedef", - Pass: "pass", - Build: "build", - Namespace: "namespace", - Deprecated: "deprecated", - Test: "test", + Cdef: "cdef", + Typedef: "typedef", + Pass: "pass", + Build: "build", + Namespace: "namespace", + Deprecated: "deprecated", + Test: "test", } // Reports whether directive is top-directive. fn IsTopDirective(directive: str): bool { - ret directive == Directive.Pass || - directive == Directive.Build + ret directive == Directive.Pass || + directive == Directive.Build } \ No newline at end of file diff --git a/std/jule/build/env.jule b/std/jule/build/env.jule index 630b3a7cb..37df4e620 100644 --- a/std/jule/build/env.jule +++ b/std/jule/build/env.jule @@ -22,19 +22,19 @@ static mut Os = env::Os static mut Arch = env::Arch fn init() { - mut path := process::Executable() - if path == "" { - panic("std::jule::build: executable file cannot found") - } + mut path := process::Executable() + if path == "" { + panic("std::jule::build: executable file cannot found") + } - // Break immutability to assign paths. - unsafe { - *(&PathWd) = env::WorkingDir() else { - panic("std::jule::build: working directory path cannot found") - ret // To avoid assignment error. - } - *(&PathExec) = path::Dir(path) - *(&PathStdlib) = path::Join(PathExec, "..", Stdlib) - *(&PathApi) = path::Join(PathExec, "..", "api", "jule.hpp") - } + // Break immutability to assign paths. + unsafe { + *(&PathWd) = env::WorkingDir() else { + panic("std::jule::build: working directory path cannot found") + ret // To avoid assignment error. + } + *(&PathExec) = path::Dir(path) + *(&PathStdlib) = path::Join(PathExec, "..", Stdlib) + *(&PathApi) = path::Join(PathExec, "..", "api", "jule.hpp") + } } \ No newline at end of file diff --git a/std/jule/build/log.jule b/std/jule/build/log.jule index 3893f6ab0..13d884b98 100644 --- a/std/jule/build/log.jule +++ b/std/jule/build/log.jule @@ -6,357 +6,357 @@ use std::internal::strings::{StrBuilder} // Compiler log messages with formatting. enum LogMsg: str { - Empty: "", - StdlibNotExist: `standard library directory not found`, - FileNotUseable: `file is not useable for this operating system or architecture`, - FileNotJule: `this is not jule source file: @`, - NoEntryPoint: `missing entry point: entry point (main) function is not defined`, - DuplicatedIdent: `identifier "@" is duplicated for scope, used by another declaration`, - ExtraClosedParent: `extra closed parentheses`, - ExtraClosedBrace: `extra closed braces`, - ExtraClosedBracket: `extra closed brackets`, - WaitCloseParent: `parentheses waiting to close`, - WaitCloseBrace: `brace waiting to close`, - WaitCloseBracket: `bracket are waiting to close`, - ExpectedParentClose: `was expected parentheses close`, - ExpectedBraceClose: `was expected brace close`, - ExpectedBracketClose: `was expected bracket close`, - BodyNotExist: `body is not exist`, - OperatorOverflow: `operator overflow: repetitive operators`, - IncompatibleTypes: `mismatched types: @ and @`, - OperatorNotForJuleType: `operator @ is not defined for type @`, - OperatorNotForFloat: `operator @ is not defined for floating-point type(s)`, - OperatorNotForInt: `operator @ is not defined for integer type(s)`, - OperatorNotForUint: `operator @ is not defined for unsigned integer type(s)`, - IdentNotExist: `undefined identifier: @`, - NotFnCall: `value is not function`, - ArgumentOverflow: `argument overflow: passed more argument than expected to call @`, - FnHaveRet: `function @ cannot have return type`, - FnHaveParameters: `function @ cannot have parameter(s)`, - RequireRetExpr: `return statements of non-void functions should have return expression`, - VoidFnRetExpr: `void functions is cannot returns any value`, - BitShiftMustUnsigned: `bit shifting value is must be unsigned`, - LogicalNotBool: `logical expression is have only boolean type values`, - AssignConst: `constants is can't assign`, - AssignRequireLvalue: `invalid expression: expected lvalue for assignment`, - AssignTypeNotSupportValue: `type is not support assignment`, - InvalidToken: `undefined token: @`, - InvalidSyntax: `invalid syntax`, - InvalidType: `invalid type`, - InvalidNumericRange: `arithmetic value overflow: this value too big`, - InvalidExprForUnary: `unary operator @ is not defined for type @`, - InvalidEscapeSeq: `invalid escape sequence`, - InvalidTypeSource: `invalid type source`, - InvalidTypeForConst: `@ is invalid data-type for constant`, - InvalidExpr: `invalid expression`, - InvalidCppExt: `invalid C++ extension: @`, - InvalidLabel: `invalid label: @`, - InvalidExprForTypeInference: `invalid expression for type inference`, - MissingValueForTypeInference: `type inferred declarations should have a initializer expression`, - MissingType: `type missing`, - MissingExpr: `expression missing`, - MissingBlockCommentClose: `missing block comment close`, - MissingRuneEnd: `rune is not finished`, - MissingRet: `missing return at end of function`, - MissingStrEnd: `string is not finished`, - MissingMultiRet: `missing return expressions for multi-return`, - MissingMultiAssignIdents: `missing identifier(s) for multiple assignment`, - MissingUsePath: `missing path of use statement`, - MissingGotoLabel: `missing label identifier for goto statement`, - MissingExprFor: `missing expression for @`, - MissingGenerics: `missing generics`, - MissingReceiver: `missing receiver parameter`, - MissingFnParentheses: `missing function parentheses`, - ExprNotConst: `expressions is not constant expression`, - NilForTypeInference: `nil is cannot use with type inferred definitions`, - VoidForTypeInference: `void data is cannot use for type inferred definitions`, - RuneEmpty: `rune is cannot empty`, - RuneOverflow: `rune is should be single`, - NotSupportsIndexing: `type @ is not support indexing`, - NotSupportsSlicing: `type @ is not support slicing`, - AlreadyConst: `define is already constant`, - AlreadyVariadic: `define is already variadic`, - AlreadyReference: `define is already reference`, - StaticReference: `static variables cannot be reference`, - DuplicateUseDecl: `use declaration duplication: @ is already used above`, - IgnoreIdent: `ignore operator cannot use as identifier for this declaration`, - OverflowMultiAssignIdents: `overflow multi assignment identifers`, - OverflowRet: `overflow return expressions`, - BreakAtOutOfValidScope: `break keyword is cannot used at out of iteration and match cases`, - ContinueAtOutOfValidScope: `continue keyword is cannot used at out of iteration`, - IterWhileRequireBoolExpr: `while iterations must be have boolean expression`, - IterRangeRequireEnumerableExpr: `range iterations must be have enumerable expression`, - MuchRangeVars: `range variables can be maximum two`, - IfRequireBoolExpr: `if conditions must be have boolean expression`, - ElseHaveExpr: `else's cannot have any expression`, - VariadicParamNotLast: `variadic parameter can only be last parameter`, - VariadicWithNonVariadicable: `type @ is not variadicable`, - MoreArgsWithVariadiced: `variadic argument can't use with more argument`, - VariadicReference: `variadic storage cannot be reference`, - TypeNotSupportsCasting: `type @ not supports casting`, - TypeNotSupportsCastingTo: `type @ not supports casting to type @`, - UseAtContent: `use declaration must be start of source code`, - UseNotFound: `used directory path not found/access: @`, - DefNotSupportPub: `define is not supports modifier`, - ObjNotSupportSubFields: `object @ is not supports sub-defines`, - ObjHaveNotIdent: `undefined identifier: type @ has no field or method @`, - TypeNotSupportSubFields: `type @ is not supports sub-defines`, - TypeHaveNotIdent: `undefined identifier: type @ has no field or method @`, - DeclaredButNotUsed: `@ declared but not used`, - ExprNotFnCall: `statement must have function call expression`, - LabelExist: `label is already exist in this identifier: @`, - LabelNotExist: `not exist any label in this identifier: @`, - GotoJumpsDeclarations: `goto @ jumps over declaration(s)`, - FnNotHasParam: `function is not has parameter in this identifier: @`, - AlreadyHasExpr: `@ already has expression`, - ArgMustTargetToField: `argument must target to field`, - OverflowLimits: `overflow the limit of data-type`, - GenericsOverflow: `overflow generics`, - HasGenerics: `type has generics and used without instantiate`, - NotHasGenerics: `type have not generics but instantiate like generics`, - TypeNotSupportsGenerics: `type not supports generics`, - DivByZero: `divide by zero`, - TraitHaveNotIdent: `undefined identifier: trait @ has no define @`, - NotImplTraitDef: `trait @ derived but not implemented define @`, - DynamicTypeAnnotationFailed: `dynamic type annotation failed`, - FallthroughWrongUse: `fall keyword can only useable at end of the case scopes`, - FallthroughIntoFinalCase: `fall cannot useable at final case`, - UnsafeBehaviorAtOutOfUnsafeScope: `unsafe behaviors cannot available out of unsafe scopes`, - RefMethodUsedWithNotRefInstance: `reference method cannot use with non-reference instance`, - MethodAsAnonFn: `non-static methods cannot use as anonymous function`, - BindedFnAsAnonFn: `binded functions cannot use as anonymous function`, - GenericedFnAsAnonFn: `genericed functions cannot use as anonymous function`, - IllegalCycleRefersItself: `illegal cycle in declaration, @ refers to itself`, - IllegalCrossCycle: "illegal cross cycle in declarations;\n@", - AssignToNonMut: `cannot assign to immutable storage`, - AssignNonMutToMut: `immutable data cannot assign to mutable storage because of @ type which is mutable`, - RetWithMutTypedNonMut: `mutable typed return expressions should be mutable`, - MutOperationOnImmut: `mutable operation cannot used with immutable data`, - TraitHasRefParamFn: `trait has reference receiver parameter used method, cannot assign non-reference instance`, - EnumHaveNotField: `undefined identifier: enum @ has no field @`, - DuplicateMatchType: `duplicated pattern: type @ is already matched`, - BindedVarHasExpr: `binded variables cannot have expression`, - BindedVarIsConst: `binded variables cannot be constant`, - ConstVarNotHaveExpr: `missing expression for constant variable initialization`, - MissingExprForUnary: `missing expression for unary operator`, - InvalidOpForUnary: `invalid unary operator: @`, - UseDeclAtBody: `use declarations must declared top of source code`, - ArrayAutoSized: `array must have explicit size`, - NamespaceNotExist: `undefined namespace: @`, - ImplInvalidBase: `invalid base type for impl: @`, - ImplInvalidDest: `invalid destination type for impl: @`, - StructAlreadyHaveIdent: `identifier duplication: struct @ already have define @`, - UnsafePtrIndexing: `unsafe pointers are not supports indexing`, - MethodHasGenericWithSameIdent: `methods cannot have same generic identifier with owner same time`, - TupleAssignToSingle: `tuples cannot assign to single define in same time`, - MissingCompilePath: `missing compile path`, - ArraySizeIsNotInt: `array size must be integer`, - ArraySizeIsNeg: `array size must be positive integer`, - BuiltinAsNonFn: `builtin define cannot use as anonymous function`, - TypeCaseHasNotValidExpr: `type-match must be have , , or typed expression`, - IllegalImplOutOfPackage: `illegal implementation via definition from out of package`, - MethodNotInvoked: `methods should be invoked`, - BuiltinNotInvoked: `built-in functions should be invoked`, - DuplicatedUseSelection: `duplicated selection: @ is already selected`, - IdentIsNotAccessible: `inaccessible identifier: @ is private`, - InvalidStmtForNext: `invalid statement for while-next`, - ModuloWithNotInt: `module operator must be used with integer type`, - PkgIllegalCycleRefersItself: `illegal cycle in use declaration, package @ refers to itself`, - PkgIllegalCrossCycle: "illegal cross cycle in use declarations;\n@", - RefersTo: `@ refers to @`, - NoFileInEntryPackage: `there is no Jule source code in package: @`, - NoMemberInEnum: `enum @ have no field`, - InternalTypeNotSupportsClone: `type @ has internally types which is not supports cloning`, - InvalidExprForBinary: `invalid expression used for binary operation`, - BindedStructForRef: `binded structures cannot supports reference counting`, - TraitMethodHasGenerics: `trait methods cannot have generics`, - EnumAsMapVal: `maps do not support enums as map key type`, - GlobalNotStatic: `global variables must be static`, - StaticNotHaveExpr: `static variables must be have initialize expression`, - StaticFnHasReceiver: `static functions cannot have receiver parameter`, - RefAssignNonVar: `references requires variable based expression for assignment`, - MutRefPointsImmut: `mutable reference cannot point to immutable data`, - RefNotInited: `reference variables must be have lvalue initialize expression`, - ConstRef: `references cannot be constant`, - ConcurrentCallWithRefParam: `Safe Jule not allows to make concurrent calls with functions which is has reference parameter(s)`, - ConcurrentCallWithSelfParam: `Safe Jule not allows to make concurrent calls with methods which is has "self" receiver parameter`, - UsedRefInAnonFnFromParentScope: `anonymous functions cannot access to reference definition @ of parent scope`, - EnumCastedFromAny: `enum cannot casted from any type`, - DuplicatedUseAlias: `identifier duplication: @ is already used for another use declaration above`, - BuiltinUsedForRef: `built-in defines cannot pass to references`, - RefPointsToInvalidType: `references cannot points to type @`, - DefaultNotLast: `default case should be last case`, - TraitImplHasStatic: `trait implementations cannot implement static field`, - IncompatibleTypeForPtrArithmetic: `type @ is incompatible to use for pointer arithmetic`, - ComptimePanic: `compile-time panic: @`, - InvalidTypeForIndexing: `type @ is invalid for indexing`, - UnusedDirective: `this directive is out of scope, put it where it will be useful or delete it`, - UnsupportedDirective: `directive @ is not supported by define`, - PanicedWithNonStr: `panic function only accepts strings`, - ErrorWithNonExceptional: `error call can only useable for exceptional functions`, - BindedExceptional: `binded defines cannot be exceptional`, - HandledUnexceptional: `non-exceptionals cannot handled like exceptionals`, - UnhandledExceptional: `exceptionals must be handled`, - MissingAssignRet: `exceptional returns an expression, therefore else block should return expression`, - CoForExceptional: `concurrent calls not supports exceptionals`, - TypeCallWithExceptional: `exceptionals are not supported for type-cast call`, - RetInDeferred: `deferred scopes are not supports return statements`, - ErrorInDeferred: `deferred scopes are not supports error calls`, - NilError: `you cannot call error function with nil`, - UseExprOutOfScope: `use expressions cannot useable out of exceptional handler scopes`, - UseExprInDeferred: `use expressions cannot useable in deferred scopes`, - UseExprNotLast: `use expressions must be last statement of scope`, - ExceptionalEntryPoint: `entry point cannot be exceptional`, - ExceptionalInit: `initializer function cannot be exceptional`, - AutoSizedArrFilled: `auto-sized arrays cannot filled`, - AssignInExpr: `assignments not available for expressions`, - UsingDeprecated: `deprecated usage: @`, - TraitImplDeprecated: `trait implementations cannot have deprecated code`, - AssertNonBool: `assertion requires boolean expression`, - WrongTestFnDecl: `wrong test function declaration`, - TestMethod: `you cannot declare test methods`, - TestCalled: `you cannot call test functions`, - ModuleNotFound: `no module file found in current directory or any parent directory`, - UseDeclForInternal: `you cannot access to internal packages`, - PubTestFn: `test function cannot be public`, - BindedTypeNotAllowed: `binded definitions are not allowed in this scope`, - GenericsNotAllowed: `generics are not allowed in this scope`, - InitiationCycle: `type declaration causes initiation cycle`, - DeclFoundInsteadExpr: `expecting expression, found type declaration`, - CallingNonFn: `attempting to call a non-function`, - ExceptionalAtGlobalScope: `exceptionals are not allowed in global scope`, - StructureLitWithPrivFields: `structure cannot instantiating because it has non-public fields`, - AnyWithTypeEnum: `the type is not allowed for type-enum declarations`, - ConstraintFailed: "type @ is not matched with @'s constraint\n constraint: @", - SelectedImportExistInPackage: `selected identifier "@" is already exist in this package`, - CoForCastingCall: `concurrent calls are not allowed for type-cast calls`, - TypeIsNotComparable: `type @ is not comparable`, - AmperOpForEnum: `the @ enum type is not supports @ operator`, - MissingArgs: `missing arguments to call @`, - InheritedNonTrait: `trait @ cannot implement @, type should be trait`, - IncompatibleInherit: "trait @ inherits trait @, but same identifiers implemented different;\n @\n @", - ArraySizeOverflow: "array with size @ overflows limit (@) of the system", - InvalidTypeForTypeOf: "comptime::TypeOf is not supports type @", - ComptimeAsExpr: "compile-time evaluations cannot used as expression", - InvalidTypeForFn: `type @ is invalid for function @`, - ComptimeFallthrough: `the fall statement is not allowed for comptime-matching`, - CannotBeMut: `define @ cannot be mutable`, - AnonFn: `anonymous functions are not allowed in this scope`, - CopyWithMutableData: `struct @ cannot copied due to field which is stores mutable data`, - CalledOutOfScope: `you can call @ function in the scopes only`, - BlankIdentInUseDecl: `use declaration paths cannot contain blank identifier`, - ComptimeExprForRuntimeIteration: `comptime expressions cannot be iterated at runtime`, - InvalidTypeForComptimeIter: `type @ is not supports comptime iterations`, - InvalidComptimeIter: `comptime iterations can only be range iteration`, - InvalidComptimeTypeMatchExpr: `comptime type-match expressions can take only type declarations`, - WrongRetForward: "function return forwaring is wrong\n want (@)\n have (@)", + Empty: "", + StdlibNotExist: `standard library directory not found`, + FileNotUseable: `file is not useable for this operating system or architecture`, + FileNotJule: `this is not jule source file: @`, + NoEntryPoint: `missing entry point: entry point (main) function is not defined`, + DuplicatedIdent: `identifier "@" is duplicated for scope, used by another declaration`, + ExtraClosedParent: `extra closed parentheses`, + ExtraClosedBrace: `extra closed braces`, + ExtraClosedBracket: `extra closed brackets`, + WaitCloseParent: `parentheses waiting to close`, + WaitCloseBrace: `brace waiting to close`, + WaitCloseBracket: `bracket are waiting to close`, + ExpectedParentClose: `was expected parentheses close`, + ExpectedBraceClose: `was expected brace close`, + ExpectedBracketClose: `was expected bracket close`, + BodyNotExist: `body is not exist`, + OperatorOverflow: `operator overflow: repetitive operators`, + IncompatibleTypes: `mismatched types: @ and @`, + OperatorNotForJuleType: `operator @ is not defined for type @`, + OperatorNotForFloat: `operator @ is not defined for floating-point type(s)`, + OperatorNotForInt: `operator @ is not defined for integer type(s)`, + OperatorNotForUint: `operator @ is not defined for unsigned integer type(s)`, + IdentNotExist: `undefined identifier: @`, + NotFnCall: `value is not function`, + ArgumentOverflow: `argument overflow: passed more argument than expected to call @`, + FnHaveRet: `function @ cannot have return type`, + FnHaveParameters: `function @ cannot have parameter(s)`, + RequireRetExpr: `return statements of non-void functions should have return expression`, + VoidFnRetExpr: `void functions is cannot returns any value`, + BitShiftMustUnsigned: `bit shifting value is must be unsigned`, + LogicalNotBool: `logical expression is have only boolean type values`, + AssignConst: `constants is can't assign`, + AssignRequireLvalue: `invalid expression: expected lvalue for assignment`, + AssignTypeNotSupportValue: `type is not support assignment`, + InvalidToken: `undefined token: @`, + InvalidSyntax: `invalid syntax`, + InvalidType: `invalid type`, + InvalidNumericRange: `arithmetic value overflow: this value too big`, + InvalidExprForUnary: `unary operator @ is not defined for type @`, + InvalidEscapeSeq: `invalid escape sequence`, + InvalidTypeSource: `invalid type source`, + InvalidTypeForConst: `@ is invalid data-type for constant`, + InvalidExpr: `invalid expression`, + InvalidCppExt: `invalid C++ extension: @`, + InvalidLabel: `invalid label: @`, + InvalidExprForTypeInference: `invalid expression for type inference`, + MissingValueForTypeInference: `type inferred declarations should have a initializer expression`, + MissingType: `type missing`, + MissingExpr: `expression missing`, + MissingBlockCommentClose: `missing block comment close`, + MissingRuneEnd: `rune is not finished`, + MissingRet: `missing return at end of function`, + MissingStrEnd: `string is not finished`, + MissingMultiRet: `missing return expressions for multi-return`, + MissingMultiAssignIdents: `missing identifier(s) for multiple assignment`, + MissingUsePath: `missing path of use statement`, + MissingGotoLabel: `missing label identifier for goto statement`, + MissingExprFor: `missing expression for @`, + MissingGenerics: `missing generics`, + MissingReceiver: `missing receiver parameter`, + MissingFnParentheses: `missing function parentheses`, + ExprNotConst: `expressions is not constant expression`, + NilForTypeInference: `nil is cannot use with type inferred definitions`, + VoidForTypeInference: `void data is cannot use for type inferred definitions`, + RuneEmpty: `rune is cannot empty`, + RuneOverflow: `rune is should be single`, + NotSupportsIndexing: `type @ is not support indexing`, + NotSupportsSlicing: `type @ is not support slicing`, + AlreadyConst: `define is already constant`, + AlreadyVariadic: `define is already variadic`, + AlreadyReference: `define is already reference`, + StaticReference: `static variables cannot be reference`, + DuplicateUseDecl: `use declaration duplication: @ is already used above`, + IgnoreIdent: `ignore operator cannot use as identifier for this declaration`, + OverflowMultiAssignIdents: `overflow multi assignment identifers`, + OverflowRet: `overflow return expressions`, + BreakAtOutOfValidScope: `break keyword is cannot used at out of iteration and match cases`, + ContinueAtOutOfValidScope: `continue keyword is cannot used at out of iteration`, + IterWhileRequireBoolExpr: `while iterations must be have boolean expression`, + IterRangeRequireEnumerableExpr: `range iterations must be have enumerable expression`, + MuchRangeVars: `range variables can be maximum two`, + IfRequireBoolExpr: `if conditions must be have boolean expression`, + ElseHaveExpr: `else's cannot have any expression`, + VariadicParamNotLast: `variadic parameter can only be last parameter`, + VariadicWithNonVariadicable: `type @ is not variadicable`, + MoreArgsWithVariadiced: `variadic argument can't use with more argument`, + VariadicReference: `variadic storage cannot be reference`, + TypeNotSupportsCasting: `type @ not supports casting`, + TypeNotSupportsCastingTo: `type @ not supports casting to type @`, + UseAtContent: `use declaration must be start of source code`, + UseNotFound: `used directory path not found/access: @`, + DefNotSupportPub: `define is not supports modifier`, + ObjNotSupportSubFields: `object @ is not supports sub-defines`, + ObjHaveNotIdent: `undefined identifier: type @ has no field or method @`, + TypeNotSupportSubFields: `type @ is not supports sub-defines`, + TypeHaveNotIdent: `undefined identifier: type @ has no field or method @`, + DeclaredButNotUsed: `@ declared but not used`, + ExprNotFnCall: `statement must have function call expression`, + LabelExist: `label is already exist in this identifier: @`, + LabelNotExist: `not exist any label in this identifier: @`, + GotoJumpsDeclarations: `goto @ jumps over declaration(s)`, + FnNotHasParam: `function is not has parameter in this identifier: @`, + AlreadyHasExpr: `@ already has expression`, + ArgMustTargetToField: `argument must target to field`, + OverflowLimits: `overflow the limit of data-type`, + GenericsOverflow: `overflow generics`, + HasGenerics: `type has generics and used without instantiate`, + NotHasGenerics: `type have not generics but instantiate like generics`, + TypeNotSupportsGenerics: `type not supports generics`, + DivByZero: `divide by zero`, + TraitHaveNotIdent: `undefined identifier: trait @ has no define @`, + NotImplTraitDef: `trait @ derived but not implemented define @`, + DynamicTypeAnnotationFailed: `dynamic type annotation failed`, + FallthroughWrongUse: `fall keyword can only useable at end of the case scopes`, + FallthroughIntoFinalCase: `fall cannot useable at final case`, + UnsafeBehaviorAtOutOfUnsafeScope: `unsafe behaviors cannot available out of unsafe scopes`, + RefMethodUsedWithNotRefInstance: `reference method cannot use with non-reference instance`, + MethodAsAnonFn: `non-static methods cannot use as anonymous function`, + BindedFnAsAnonFn: `binded functions cannot use as anonymous function`, + GenericedFnAsAnonFn: `genericed functions cannot use as anonymous function`, + IllegalCycleRefersItself: `illegal cycle in declaration, @ refers to itself`, + IllegalCrossCycle: "illegal cross cycle in declarations;\n@", + AssignToNonMut: `cannot assign to immutable storage`, + AssignNonMutToMut: `immutable data cannot assign to mutable storage because of @ type which is mutable`, + RetWithMutTypedNonMut: `mutable typed return expressions should be mutable`, + MutOperationOnImmut: `mutable operation cannot used with immutable data`, + TraitHasRefParamFn: `trait has reference receiver parameter used method, cannot assign non-reference instance`, + EnumHaveNotField: `undefined identifier: enum @ has no field @`, + DuplicateMatchType: `duplicated pattern: type @ is already matched`, + BindedVarHasExpr: `binded variables cannot have expression`, + BindedVarIsConst: `binded variables cannot be constant`, + ConstVarNotHaveExpr: `missing expression for constant variable initialization`, + MissingExprForUnary: `missing expression for unary operator`, + InvalidOpForUnary: `invalid unary operator: @`, + UseDeclAtBody: `use declarations must declared top of source code`, + ArrayAutoSized: `array must have explicit size`, + NamespaceNotExist: `undefined namespace: @`, + ImplInvalidBase: `invalid base type for impl: @`, + ImplInvalidDest: `invalid destination type for impl: @`, + StructAlreadyHaveIdent: `identifier duplication: struct @ already have define @`, + UnsafePtrIndexing: `unsafe pointers are not supports indexing`, + MethodHasGenericWithSameIdent: `methods cannot have same generic identifier with owner same time`, + TupleAssignToSingle: `tuples cannot assign to single define in same time`, + MissingCompilePath: `missing compile path`, + ArraySizeIsNotInt: `array size must be integer`, + ArraySizeIsNeg: `array size must be positive integer`, + BuiltinAsNonFn: `builtin define cannot use as anonymous function`, + TypeCaseHasNotValidExpr: `type-match must be have , , or typed expression`, + IllegalImplOutOfPackage: `illegal implementation via definition from out of package`, + MethodNotInvoked: `methods should be invoked`, + BuiltinNotInvoked: `built-in functions should be invoked`, + DuplicatedUseSelection: `duplicated selection: @ is already selected`, + IdentIsNotAccessible: `inaccessible identifier: @ is private`, + InvalidStmtForNext: `invalid statement for while-next`, + ModuloWithNotInt: `module operator must be used with integer type`, + PkgIllegalCycleRefersItself: `illegal cycle in use declaration, package @ refers to itself`, + PkgIllegalCrossCycle: "illegal cross cycle in use declarations;\n@", + RefersTo: `@ refers to @`, + NoFileInEntryPackage: `there is no Jule source code in package: @`, + NoMemberInEnum: `enum @ have no field`, + InternalTypeNotSupportsClone: `type @ has internally types which is not supports cloning`, + InvalidExprForBinary: `invalid expression used for binary operation`, + BindedStructForRef: `binded structures cannot supports reference counting`, + TraitMethodHasGenerics: `trait methods cannot have generics`, + EnumAsMapVal: `maps do not support enums as map key type`, + GlobalNotStatic: `global variables must be static`, + StaticNotHaveExpr: `static variables must be have initialize expression`, + StaticFnHasReceiver: `static functions cannot have receiver parameter`, + RefAssignNonVar: `references requires variable based expression for assignment`, + MutRefPointsImmut: `mutable reference cannot point to immutable data`, + RefNotInited: `reference variables must be have lvalue initialize expression`, + ConstRef: `references cannot be constant`, + ConcurrentCallWithRefParam: `Safe Jule not allows to make concurrent calls with functions which is has reference parameter(s)`, + ConcurrentCallWithSelfParam: `Safe Jule not allows to make concurrent calls with methods which is has "self" receiver parameter`, + UsedRefInAnonFnFromParentScope: `anonymous functions cannot access to reference definition @ of parent scope`, + EnumCastedFromAny: `enum cannot casted from any type`, + DuplicatedUseAlias: `identifier duplication: @ is already used for another use declaration above`, + BuiltinUsedForRef: `built-in defines cannot pass to references`, + RefPointsToInvalidType: `references cannot points to type @`, + DefaultNotLast: `default case should be last case`, + TraitImplHasStatic: `trait implementations cannot implement static field`, + IncompatibleTypeForPtrArithmetic: `type @ is incompatible to use for pointer arithmetic`, + ComptimePanic: `compile-time panic: @`, + InvalidTypeForIndexing: `type @ is invalid for indexing`, + UnusedDirective: `this directive is out of scope, put it where it will be useful or delete it`, + UnsupportedDirective: `directive @ is not supported by define`, + PanicedWithNonStr: `panic function only accepts strings`, + ErrorWithNonExceptional: `error call can only useable for exceptional functions`, + BindedExceptional: `binded defines cannot be exceptional`, + HandledUnexceptional: `non-exceptionals cannot handled like exceptionals`, + UnhandledExceptional: `exceptionals must be handled`, + MissingAssignRet: `exceptional returns an expression, therefore else block should return expression`, + CoForExceptional: `concurrent calls not supports exceptionals`, + TypeCallWithExceptional: `exceptionals are not supported for type-cast call`, + RetInDeferred: `deferred scopes are not supports return statements`, + ErrorInDeferred: `deferred scopes are not supports error calls`, + NilError: `you cannot call error function with nil`, + UseExprOutOfScope: `use expressions cannot useable out of exceptional handler scopes`, + UseExprInDeferred: `use expressions cannot useable in deferred scopes`, + UseExprNotLast: `use expressions must be last statement of scope`, + ExceptionalEntryPoint: `entry point cannot be exceptional`, + ExceptionalInit: `initializer function cannot be exceptional`, + AutoSizedArrFilled: `auto-sized arrays cannot filled`, + AssignInExpr: `assignments not available for expressions`, + UsingDeprecated: `deprecated usage: @`, + TraitImplDeprecated: `trait implementations cannot have deprecated code`, + AssertNonBool: `assertion requires boolean expression`, + WrongTestFnDecl: `wrong test function declaration`, + TestMethod: `you cannot declare test methods`, + TestCalled: `you cannot call test functions`, + ModuleNotFound: `no module file found in current directory or any parent directory`, + UseDeclForInternal: `you cannot access to internal packages`, + PubTestFn: `test function cannot be public`, + BindedTypeNotAllowed: `binded definitions are not allowed in this scope`, + GenericsNotAllowed: `generics are not allowed in this scope`, + InitiationCycle: `type declaration causes initiation cycle`, + DeclFoundInsteadExpr: `expecting expression, found type declaration`, + CallingNonFn: `attempting to call a non-function`, + ExceptionalAtGlobalScope: `exceptionals are not allowed in global scope`, + StructureLitWithPrivFields: `structure cannot instantiating because it has non-public fields`, + AnyWithTypeEnum: `the type is not allowed for type-enum declarations`, + ConstraintFailed: "type @ is not matched with @'s constraint\n constraint: @", + SelectedImportExistInPackage: `selected identifier "@" is already exist in this package`, + CoForCastingCall: `concurrent calls are not allowed for type-cast calls`, + TypeIsNotComparable: `type @ is not comparable`, + AmperOpForEnum: `the @ enum type is not supports @ operator`, + MissingArgs: `missing arguments to call @`, + InheritedNonTrait: `trait @ cannot implement @, type should be trait`, + IncompatibleInherit: "trait @ inherits trait @, but same identifiers implemented different;\n @\n @", + ArraySizeOverflow: "array with size @ overflows limit (@) of the system", + InvalidTypeForTypeOf: "comptime::TypeOf is not supports type @", + ComptimeAsExpr: "compile-time evaluations cannot used as expression", + InvalidTypeForFn: `type @ is invalid for function @`, + ComptimeFallthrough: `the fall statement is not allowed for comptime-matching`, + CannotBeMut: `define @ cannot be mutable`, + AnonFn: `anonymous functions are not allowed in this scope`, + CopyWithMutableData: `struct @ cannot copied due to field which is stores mutable data`, + CalledOutOfScope: `you can call @ function in the scopes only`, + BlankIdentInUseDecl: `use declaration paths cannot contain blank identifier`, + ComptimeExprForRuntimeIteration: `comptime expressions cannot be iterated at runtime`, + InvalidTypeForComptimeIter: `type @ is not supports comptime iterations`, + InvalidComptimeIter: `comptime iterations can only be range iteration`, + InvalidComptimeTypeMatchExpr: `comptime type-match expressions can take only type declarations`, + WrongRetForward: "function return forwaring is wrong\n want (@)\n have (@)", - // Suggestions. - ExpectedIdentifier: `write an identifier because identifier expected`, - ExpectedLabelIdent: `write a label identifier because label expected`, - ExpectedDotForBind: `use dot (.) to access binded defines`, - ExpectedDblColon: `expected double colon "::"`, - EmptyParentNotValid: `empty parentheses are not valid expression, must include an expression in range`, - GiveExprToCast: `give an expression for casting`, - GiveTypeForCast: `type declaration expected for casting`, - ExpectedExpr: `an expression expected`, - ExpectedAnonFn: `anonymous function expected, remove identifier of function`, - ExpectedLeftOperand: `left operand expected for binary operator`, - ExpectedRightOperand: `right operand expected for binary operator`, - ExpectedColon: `expected colon ":"`, - ExpectedBody: `expected a body, bodies should start in same line with their definition and declared with braces "{ }"`, - ExpectedType: `expected type declaration`, - ExpectedPlainUseDecl: `expected plain use declaration for this package like: @`, - DeclareComptimeForeach: `declarate comptime iteration like: const for ...`, - MoveUseDeclToTopOfFile: `move this use declaration to top of source file`, - RenameForAvoidDuplication: `rename definition to avoid duplication`, - RemoveUseDeclAvoidDuplication: `remove this use declaration, already used, it is safe`, - RenameUseAliasAvoidDuplication: `rename alias for this use declaration to avoid duplication`, - RemoveUseSelectionAvoidDupliation: `remove this use selection, already selected, it is safe`, - RemoveConstToAssign: `remove constant qualifer if you need to assign`, - UseStaticKeywordToDef: `use "static" keyword to define`, - RemoveFallthroughFromFinalCase: `remove "fall" keyword`, - MakePubToAccess: `make public with capital letter identifier to access`, - ExpressionMustBeReferenceType: `expression must be reference type`, - CastToEnumTypeInsteadOfEnum: `try cast to type of enum fields instead of enum`, - TryFloatingPoint: `floating-point literals may solve your problem`, - ExpectedColonForAssign: `expected colon ":" for assignment`, - DeclareExceptional: `you can declare an exceptional function with "!" operator`, - HandleExceptional: `use "!" operator after exceptional to handle it`, - HandleInFn: `handle exceptional in a separate function or anonymous function`, - JustIgnoreOrHandle: `just ignore exceptional or handle it but you cannot do both at same time`, - UseImperative: `use clear imperative approach, comes relevant assignment statement before the expression`, - UseUnsafeForDeprecated: `use Unsafe Jule for deprecated codes or replace to successor`, - UseExpectedTestFnDecl: `use expected test function declaration: fn(t: &std::testing::T)`, - UseModInit: `use "julec mod init" command to initialize module`, - RemovePubModifier: `dont use identifier which is starts with capital letter to avoid define as public`, - ExpectedStruct: `expected structure, use a structure`, - ExpectedTrait: `expected trait, use a trait`, - UseTypeMatch: `you can use type-match if you want to match types`, - WrapExceptional: `wrap exceptional with a non-exceptional function`, - UseFieldPairToInstantiate: `use field:expression pairs to instantiate`, - InstantiateGenericFnToUseAsAnon: `instantiate generic function to use as anonymous function`, - UseUnsafeJuleToCallCo: `use Unsafe Jule with unsafe {} scope to make concurrent call`, - UseUnsafeJuleToCallCoSelf: `use "&self" receiver parameter instead, or Unsafe Jule with unsafe {} scope to make concurrent call`, - DefineZeroDefaultToUseAmper: `define default enum field (the first one is default) with zero value to use & operator`, - InvalidExprForConstMatch: `comptime-matching requires constant expression`, + // Suggestions. + ExpectedIdentifier: `write an identifier because identifier expected`, + ExpectedLabelIdent: `write a label identifier because label expected`, + ExpectedDotForBind: `use dot (.) to access binded defines`, + ExpectedDblColon: `expected double colon "::"`, + EmptyParentNotValid: `empty parentheses are not valid expression, must include an expression in range`, + GiveExprToCast: `give an expression for casting`, + GiveTypeForCast: `type declaration expected for casting`, + ExpectedExpr: `an expression expected`, + ExpectedAnonFn: `anonymous function expected, remove identifier of function`, + ExpectedLeftOperand: `left operand expected for binary operator`, + ExpectedRightOperand: `right operand expected for binary operator`, + ExpectedColon: `expected colon ":"`, + ExpectedBody: `expected a body, bodies should start in same line with their definition and declared with braces "{ }"`, + ExpectedType: `expected type declaration`, + ExpectedPlainUseDecl: `expected plain use declaration for this package like: @`, + DeclareComptimeForeach: `declarate comptime iteration like: const for ...`, + MoveUseDeclToTopOfFile: `move this use declaration to top of source file`, + RenameForAvoidDuplication: `rename definition to avoid duplication`, + RemoveUseDeclAvoidDuplication: `remove this use declaration, already used, it is safe`, + RenameUseAliasAvoidDuplication: `rename alias for this use declaration to avoid duplication`, + RemoveUseSelectionAvoidDupliation: `remove this use selection, already selected, it is safe`, + RemoveConstToAssign: `remove constant qualifer if you need to assign`, + UseStaticKeywordToDef: `use "static" keyword to define`, + RemoveFallthroughFromFinalCase: `remove "fall" keyword`, + MakePubToAccess: `make public with capital letter identifier to access`, + ExpressionMustBeReferenceType: `expression must be reference type`, + CastToEnumTypeInsteadOfEnum: `try cast to type of enum fields instead of enum`, + TryFloatingPoint: `floating-point literals may solve your problem`, + ExpectedColonForAssign: `expected colon ":" for assignment`, + DeclareExceptional: `you can declare an exceptional function with "!" operator`, + HandleExceptional: `use "!" operator after exceptional to handle it`, + HandleInFn: `handle exceptional in a separate function or anonymous function`, + JustIgnoreOrHandle: `just ignore exceptional or handle it but you cannot do both at same time`, + UseImperative: `use clear imperative approach, comes relevant assignment statement before the expression`, + UseUnsafeForDeprecated: `use Unsafe Jule for deprecated codes or replace to successor`, + UseExpectedTestFnDecl: `use expected test function declaration: fn(t: &std::testing::T)`, + UseModInit: `use "julec mod init" command to initialize module`, + RemovePubModifier: `dont use identifier which is starts with capital letter to avoid define as public`, + ExpectedStruct: `expected structure, use a structure`, + ExpectedTrait: `expected trait, use a trait`, + UseTypeMatch: `you can use type-match if you want to match types`, + WrapExceptional: `wrap exceptional with a non-exceptional function`, + UseFieldPairToInstantiate: `use field:expression pairs to instantiate`, + InstantiateGenericFnToUseAsAnon: `instantiate generic function to use as anonymous function`, + UseUnsafeJuleToCallCo: `use Unsafe Jule with unsafe {} scope to make concurrent call`, + UseUnsafeJuleToCallCoSelf: `use "&self" receiver parameter instead, or Unsafe Jule with unsafe {} scope to make concurrent call`, + DefineZeroDefaultToUseAmper: `define default enum field (the first one is default) with zero value to use & operator`, + InvalidExprForConstMatch: `comptime-matching requires constant expression`, } // Log kinds. enum LogKind { - Flat, // Just text. - Error, // Error message. + Flat, // Just text. + Error, // Error message. } // Compiler log. struct Log { - Kind: LogKind - Row: int - Column: int - Path: str - Text: str - Line: str - Suggestion: str + Kind: LogKind + Row: int + Column: int + Path: str + Text: str + Line: str + Suggestion: str } // Returns formatted error message by fmt and args. fn Logf(fmt: LogMsg, args: ...any): str { - ret applyFmt(fmt, args...) + ret applyFmt(fmt, args...) } fn argToStr(arg: any): str { - match type arg { - | str: - ret str(arg) - | byte: - ret str(byte(arg)) - | rune: - ret str(rune(arg)) - |: - ret "" - } + match type arg { + | str: + ret str(arg) + | byte: + ret str(byte(arg)) + | rune: + ret str(rune(arg)) + |: + ret "" + } } fn findNextFmt(fmt: str): int { - for i, b in fmt { - if b == '@' { - ret i - } - } - ret -1 + for i, b in fmt { + if b == '@' { + ret i + } + } + ret -1 } fn applyFmt(mut fmt: str, args: ...any): str { - mut s := StrBuilder.New(1 << 5) - for _, arg in args { - i := findNextFmt(fmt) - if i == -1 { - break - } - s.WriteStr(fmt[:i]) - s.WriteStr(argToStr(arg)) - fmt = fmt[i+1:] - } - s.WriteStr(fmt) - ret s.Str() + mut s := StrBuilder.New(1 << 5) + for _, arg in args { + i := findNextFmt(fmt) + if i == -1 { + break + } + s.WriteStr(fmt[:i]) + s.WriteStr(argToStr(arg)) + fmt = fmt[i+1:] + } + s.WriteStr(fmt) + ret s.Str() } \ No newline at end of file diff --git a/std/jule/build/platform.jule b/std/jule/build/platform.jule index 70df85989..a8c479f26 100644 --- a/std/jule/build/platform.jule +++ b/std/jule/build/platform.jule @@ -4,33 +4,33 @@ // List of all possible std::runtime::OS values: enum runtimeOs: str { - Windows: "windows", - Darwin: "darwin", - Linux: "linux", + Windows: "windows", + Darwin: "darwin", + Linux: "linux", } // List of all possible std::runtime::ARCH values: enum runtimeArch: str { - I386: "i386", - Amd64: "amd64", - Arm64: "arm64", + I386: "i386", + Amd64: "amd64", + Arm64: "arm64", } // Operating Systems for file annotation kind. enum DistOs: str { - Windows: "windows", - Linux: "linux", - Darwin: "darwin", - Unix: "unix", + Windows: "windows", + Linux: "linux", + Darwin: "darwin", + Unix: "unix", } // Architectures for file annotation kind. enum DistArch: str { - I386: "i386", - Arm64: "arm64", - Amd64: "amd64", - X32: "x32", - X64: "x64", + I386: "i386", + Arm64: "arm64", + Amd64: "amd64", + X32: "x32", + X64: "x64", } // Reports whether os is windows. diff --git a/std/jule/constant/const.jule b/std/jule/constant/const.jule index 043c11973..e19c2846f 100644 --- a/std/jule/constant/const.jule +++ b/std/jule/constant/const.jule @@ -7,594 +7,594 @@ use std::jule::types::{TypeKind} // Constant data. // Use Const.new_nil function istead of Const{} for nil literal. struct Const { - Kind: str - data: any + Kind: str + data: any } impl Const { - // Returns new constant value instance from 64-bit signed integer. - static fn NewI64(x: i64): &Const { ret &Const{data: x} } + // Returns new constant value instance from 64-bit signed integer. + static fn NewI64(x: i64): &Const { ret &Const{data: x} } - // Returns new constant value instance from 64-bit unsigned integer. - static fn NewU64(x: u64): &Const { ret &Const{data: x} } + // Returns new constant value instance from 64-bit unsigned integer. + static fn NewU64(x: u64): &Const { ret &Const{data: x} } - // Returns new constant value instance from boolean. - static fn NewBool(x: bool): &Const { ret &Const{data: x} } + // Returns new constant value instance from boolean. + static fn NewBool(x: bool): &Const { ret &Const{data: x} } - // Returns new constant value instance from string. - static fn NewStr(x: str): &Const { ret &Const{data: x} } + // Returns new constant value instance from string. + static fn NewStr(x: str): &Const { ret &Const{data: x} } - // Returns new constant value instance from 64-bit floating-point. - static fn NewF64(x: f64): &Const { ret &Const{data: x} } + // Returns new constant value instance from 64-bit floating-point. + static fn NewF64(x: f64): &Const { ret &Const{data: x} } - // Returns new constant value instance with nil. - static fn NewNil(): &Const { ret &Const{data: nil} } + // Returns new constant value instance with nil. + static fn NewNil(): &Const { ret &Const{data: nil} } } impl Const { - // - // Read - // - - // Reads 64-bit signed integer data. - // Returns 0 if data is not 64-bit signed integer. - fn ReadI64(self): i64 { - if !self.IsI64() { - ret 0 - } - ret i64(self.data) - } - - // Reads 64-bit unsigned integer data. - // Returns 0 if data is not 64-bit unsigned integer. - fn ReadU64(self): u64 { - if !self.IsU64() { - ret 0 - } - ret u64(self.data) - } - - // Reads boolean data. - // Returns false if data is not boolean. - fn ReadBool(self): bool { - if !self.IsBool() { - ret false - } - ret bool(self.data) - } - - // Reads string data. - // Returns empty string if data is not string. - fn ReadStr(self): str { - if !self.IsStr() { - ret "" - } - ret str(self.data) - } - - // Reads 64-bit floating-point data. - // Returns 0 if data is not 64-bit floating-point. - fn ReadF64(self): f64 { - if !self.IsF64() { - ret 0 - } - ret f64(self.data) - } - - // - // Castings - // - - // Reads data as 64-bit signed integer. - // Returns 0 if data is string, bool or which is not numeric. - fn AsI64(self): i64 { - match type self.data { - | i64: - ret i64(self.data) - | u64: - ret i64(u64(self.data)) - | f64: - ret i64(f64(self.data)) - |: - ret 0 - } - } - - // Reads data as 64-bit unsigned integer. - // Returns 0 if data is string, bool or which is not numeric. - fn AsU64(self): u64 { - match type self.data { - | u64: - ret u64(self.data) - | i64: - ret u64(i64(self.data)) - | f64: - ret u64(f64(self.data)) - |: - ret 0 - } - } - - // Reads data as 64-bit floating-point. - // Returns 0 if data is string, bool or which is not numeric. - fn AsF64(self): f64 { - match type self.data { - | f64: - ret f64(self.data) - | i64: - ret f64(i64(self.data)) - | u64: - ret f64(u64(self.data)) - |: - ret 0 - } - } - - // - // Set - // - - // Sets constant value from 64-bit signed integer. - fn SetI64(mut self, x: i64) { self.data = x } - - // Sets constant value from 64-bit unsigned integer. - fn SetU64(mut self, x: u64) { self.data = x } - - // Sets constant value from boolean. - fn SetBool(mut self, x: bool) { self.data = x } - - // Sets constant value from string. - fn SetStr(mut self, x: str) { self.data = x } - - // Sets constant value from 64-bit floating-point. - fn SetF64(mut self, x: f64) { self.data = x } - - // Sets constant value to nil. - fn SetNil(mut self) { self.data = nil } - - // - // Types - // - - // Reports whether data is 64-bit signed integer. - fn IsI64(self): bool { - match type self.data { - | i64: - ret true - |: - ret false - } - } - - // Reports whether data is 64-bit unsigned integer. - fn IsU64(self): bool { - match type self.data { - | u64: - ret true - |: - ret false - } - } - - // Reports whether data is boolean. - fn IsBool(self): bool { - match type self.data { - | bool: - ret true - |: - ret false - } - } - - // Reports whether data is string. - fn IsStr(self): bool { - match type self.data { - | str: - ret true - |: - ret false - } - } - - // Reports whether data is 64-bit floating-point. - fn IsF64(self): bool { - match type self.data { - | f64: - ret true - |: - ret false - } - } - - // Reports whether data is nil. - fn IsNil(self): bool { ret self.data == nil } - - // Reports whether self and x has same type. - fn AreSameTypes(self, x: Const): bool { - match { - | self.IsI64() == x.IsI64(): - ret true - | self.IsU64() == x.IsU64(): - ret true - | self.IsF64() == x.IsF64(): - ret true - | self.IsBool() == x.IsBool(): - ret true - | self.IsStr() == x.IsStr(): - ret true - | self.IsNil() == x.IsNil(): - ret true - |: - ret false - } - } - - // - // Logical - // - - // Reports whether self and x are true. - // Returns false if type is not supported. - fn And(self, x: Const): bool { - match { - | self.IsBool() && x.IsBool(): - ret self.ReadBool() && x.ReadBool() - |: - ret false - } - } - - // Reports whether self or x is true. - // Returns false if type is not supported. - fn Or(self, x: Const): bool { - match { - | self.IsBool() && x.IsBool(): - ret self.ReadBool() || x.ReadBool() - |: - ret false - } - } - - // Reports whether self and x are equals. - // Returns false if type is not supported. - fn Eq(self, x: Const): bool { - match { - | self.IsNil(): - ret x.IsNil() - | self.IsBool(): - ret x.IsBool() && self.ReadBool() == x.ReadBool() - | self.IsStr(): - ret x.IsStr() && self.ReadStr() == x.ReadStr() - | self.IsI64(): - ret self.ReadI64() == x.AsI64() - | self.IsU64(): - ret self.ReadU64() == x.AsU64() - | self.IsF64(): - ret self.ReadF64() == x.AsF64() - |: - ret false - } - } - - // Reports whether self less than x. - // Returns false if type is unsupported by operation. - // - // Supported types are: - // - strings - // - 64-bit signed integer - // - 64-bit unsigned integer - // - 64-bit floating-point - fn Lt(self, x: Const): bool { - match { - | self.IsStr(): - ret x.IsStr() && self.ReadStr() < x.ReadStr() - | self.IsI64(): - ret self.ReadI64() < x.AsI64() - | self.IsU64(): - ret self.ReadU64() < x.AsU64() - | self.IsF64(): - ret self.ReadF64() < x.AsF64() - |: - ret false - } - } - - // Reports whether self less than or equals to x. - // Returns false if type is unsupported by operation. - // - // Supported types are: - // - strings - // - 64-bit signed integer - // - 64-bit unsigned integer - // - 64-bit floating-point - fn LtEq(self, x: Const): bool { - match { - | self.IsStr(): - ret x.IsStr() && self.ReadStr() <= x.ReadStr() - | self.IsI64(): - ret self.ReadI64() <= x.AsI64() - | self.IsU64(): - ret self.ReadU64() <= x.AsU64() - | self.IsF64(): - ret self.ReadF64() <= x.AsF64() - |: - ret false - } - } - - // Reports whether self greater than x. - // Returns false if type is unsupported by operation. - // - // Supported types are: - // - strings - // - 64-bit signed integer - // - 64-bit unsigned integer - // - 64-bit floating-point - fn Gt(self, x: Const): bool { - match { - | self.IsStr(): - ret x.IsStr() && self.ReadStr() > x.ReadStr() - | self.IsI64(): - ret self.ReadI64() > x.AsI64() - | self.IsU64(): - ret self.ReadU64() > x.AsU64() - | self.IsF64(): - ret self.ReadF64() > x.AsF64() - |: - ret false - } - } - - // Reports whether self greater than or equals to x. - // Returns false if type is unsupported by operation. - // - // Supported types are: - // - strings - // - 64-bit signed integer - // - 64-bit unsigned integer - // - 64-bit floating-point - fn GtEq(self, x: Const): bool { - match { - | self.IsStr(): - ret x.IsStr() && self.ReadStr() >= x.ReadStr() - | self.IsI64(): - ret self.ReadI64() >= x.AsI64() - | self.IsU64(): - ret self.ReadU64() >= x.AsU64() - | self.IsF64(): - ret self.ReadF64() >= x.AsF64() - |: - ret false - } - } - - // - // Ops - // - - // Adds x's value to itself value. - // Reports whether operation is success. - fn Add(mut self, x: Const): bool { - match { - | self.IsStr(): - if !x.IsStr() { - ret false - } - self.SetStr(self.ReadStr() + x.ReadStr()) - | self.IsF64(): - self.SetF64(self.ReadF64() + x.AsF64()) - | self.IsI64(): - if x.IsF64() { - self.SetF64(self.AsF64() + x.ReadF64()) - } else { - self.SetI64(self.ReadI64() + x.AsI64()) - } - | self.IsU64(): - if x.IsF64() { - self.SetF64(self.AsF64() + x.ReadF64()) - } else { - self.SetU64(self.ReadU64() + x.AsU64()) - } - |: - ret false - } - ret true - } - - // Subs x's value from itself value. - // Reports whether operation is success. - fn Sub(mut self, x: Const): bool { - match { - | self.IsF64(): - self.SetF64(self.ReadF64() - x.AsF64()) - | self.IsI64(): - if x.IsF64() { - self.SetF64(self.AsF64() - x.ReadF64()) - } else { - self.SetI64(self.ReadI64() - x.AsI64()) - } - | self.IsU64(): - if x.IsF64() { - self.SetF64(self.AsF64() - x.ReadF64()) - } else { - self.SetU64(self.ReadU64() - x.AsU64()) - } - |: - ret false - } - ret true - } - - // Multiplies x's value to c's value. - // Reports whether operation is success. - fn Mul(mut self, x: Const): bool { - match { - | self.IsF64(): - self.SetF64(self.ReadF64() * x.AsF64()) - | self.IsI64(): - if x.IsF64() { - self.SetF64(self.AsF64() * x.ReadF64()) - } else { - self.SetI64(self.ReadI64() * x.AsI64()) - } - | self.IsU64(): - if x.IsF64() { - self.SetF64(self.AsF64() * x.ReadF64()) - } else { - self.SetU64(self.ReadU64() * x.AsU64()) - } - |: - ret false - } - ret true - } - - // Divides itself value to x's value. - // Reports whether operation is success. - // Reports false if divided-by-zero. - // - // NOTICE - // This operation makes constant value is floating-point. - fn Div(mut self, x: Const): bool { - match { - | self.IsF64(): - l := x.AsF64() - if l == 0 { - ret false - } - self.SetF64(self.ReadF64() / l) - | self.IsI64(): - l := x.AsF64() - if l == 0 { - ret false - } - self.SetF64(self.AsF64() / l) - | self.IsU64(): - l := x.AsF64() - if l == 0 { - ret false - } - self.SetF64(self.AsF64() / l) - |: - ret false - } - ret true - } - - // Mods itself value to x's value. - // Reports whether operation is success. - // Reports false if divided-by-zero. - fn Mod(mut self, x: Const): bool { - match { - | self.IsI64(): - l := x.AsI64() - if l == 0 { - ret false - } - self.SetI64(self.ReadI64() % l) - | self.IsU64(): - l := x.AsU64() - if l == 0 { - ret false - } - self.SetU64(self.ReadU64() % l) - |: - ret false - } - ret true - } - - // Bitwise and itself value to x's value. - // Reports whether operation is success. - fn BitwiseAnd(mut self, x: Const): bool { - match { - | self.IsI64(): - self.SetI64(self.ReadI64() & x.AsI64()) - | self.IsU64(): - self.SetU64(self.ReadU64() & x.AsU64()) - |: - ret false - } - ret true - } - - // Bitwise or itself value to x's value. - // Reports whether operation is success. - fn BitwiseOr(mut self, x: Const): bool { - match { - | self.IsI64(): - self.SetI64(self.ReadI64() | x.AsI64()) - | self.IsU64(): - self.SetU64(self.ReadU64() | x.AsU64()) - |: - ret false - } - ret true - } - - // Bitwise xor itself value to x's value. - // Reports whether operation is success. - fn Xor(mut self, x: Const): bool { - match { - | self.IsI64(): - self.SetI64(self.ReadI64() ^ x.AsI64()) - | self.IsU64(): - self.SetU64(self.ReadU64() ^ x.AsU64()) - |: - ret false - } - ret true - } - - // Left shifts itself value to x's value. - // Reports whether operation is success. - fn Lshift(mut self, x: Const): bool { - match { - | self.IsI64(): - l := self.AsI64() - if l < 0 { - r := x.AsU64() - self.SetI64(l << r) - } else { - lshiftUnsig(self, x) - } - | self.IsU64(): - lshiftUnsig(self, x) - |: - ret false - } - ret true - } - - // Right shifts itself value to x's value. - // Reports whether operation is success. - fn Rshift(mut self, x: Const): bool { - match { - | self.IsI64(): - l := self.AsI64() - if l < 0 { - r := x.AsU64() - self.SetI64(l >> r) - } else { - rshiftUnsig(self, x) - } - | self.IsU64(): - rshiftUnsig(self, x) - |: - ret false - } - ret true - } + // + // Read + // + + // Reads 64-bit signed integer data. + // Returns 0 if data is not 64-bit signed integer. + fn ReadI64(self): i64 { + if !self.IsI64() { + ret 0 + } + ret i64(self.data) + } + + // Reads 64-bit unsigned integer data. + // Returns 0 if data is not 64-bit unsigned integer. + fn ReadU64(self): u64 { + if !self.IsU64() { + ret 0 + } + ret u64(self.data) + } + + // Reads boolean data. + // Returns false if data is not boolean. + fn ReadBool(self): bool { + if !self.IsBool() { + ret false + } + ret bool(self.data) + } + + // Reads string data. + // Returns empty string if data is not string. + fn ReadStr(self): str { + if !self.IsStr() { + ret "" + } + ret str(self.data) + } + + // Reads 64-bit floating-point data. + // Returns 0 if data is not 64-bit floating-point. + fn ReadF64(self): f64 { + if !self.IsF64() { + ret 0 + } + ret f64(self.data) + } + + // + // Castings + // + + // Reads data as 64-bit signed integer. + // Returns 0 if data is string, bool or which is not numeric. + fn AsI64(self): i64 { + match type self.data { + | i64: + ret i64(self.data) + | u64: + ret i64(u64(self.data)) + | f64: + ret i64(f64(self.data)) + |: + ret 0 + } + } + + // Reads data as 64-bit unsigned integer. + // Returns 0 if data is string, bool or which is not numeric. + fn AsU64(self): u64 { + match type self.data { + | u64: + ret u64(self.data) + | i64: + ret u64(i64(self.data)) + | f64: + ret u64(f64(self.data)) + |: + ret 0 + } + } + + // Reads data as 64-bit floating-point. + // Returns 0 if data is string, bool or which is not numeric. + fn AsF64(self): f64 { + match type self.data { + | f64: + ret f64(self.data) + | i64: + ret f64(i64(self.data)) + | u64: + ret f64(u64(self.data)) + |: + ret 0 + } + } + + // + // Set + // + + // Sets constant value from 64-bit signed integer. + fn SetI64(mut self, x: i64) { self.data = x } + + // Sets constant value from 64-bit unsigned integer. + fn SetU64(mut self, x: u64) { self.data = x } + + // Sets constant value from boolean. + fn SetBool(mut self, x: bool) { self.data = x } + + // Sets constant value from string. + fn SetStr(mut self, x: str) { self.data = x } + + // Sets constant value from 64-bit floating-point. + fn SetF64(mut self, x: f64) { self.data = x } + + // Sets constant value to nil. + fn SetNil(mut self) { self.data = nil } + + // + // Types + // + + // Reports whether data is 64-bit signed integer. + fn IsI64(self): bool { + match type self.data { + | i64: + ret true + |: + ret false + } + } + + // Reports whether data is 64-bit unsigned integer. + fn IsU64(self): bool { + match type self.data { + | u64: + ret true + |: + ret false + } + } + + // Reports whether data is boolean. + fn IsBool(self): bool { + match type self.data { + | bool: + ret true + |: + ret false + } + } + + // Reports whether data is string. + fn IsStr(self): bool { + match type self.data { + | str: + ret true + |: + ret false + } + } + + // Reports whether data is 64-bit floating-point. + fn IsF64(self): bool { + match type self.data { + | f64: + ret true + |: + ret false + } + } + + // Reports whether data is nil. + fn IsNil(self): bool { ret self.data == nil } + + // Reports whether self and x has same type. + fn AreSameTypes(self, x: Const): bool { + match { + | self.IsI64() == x.IsI64(): + ret true + | self.IsU64() == x.IsU64(): + ret true + | self.IsF64() == x.IsF64(): + ret true + | self.IsBool() == x.IsBool(): + ret true + | self.IsStr() == x.IsStr(): + ret true + | self.IsNil() == x.IsNil(): + ret true + |: + ret false + } + } + + // + // Logical + // + + // Reports whether self and x are true. + // Returns false if type is not supported. + fn And(self, x: Const): bool { + match { + | self.IsBool() && x.IsBool(): + ret self.ReadBool() && x.ReadBool() + |: + ret false + } + } + + // Reports whether self or x is true. + // Returns false if type is not supported. + fn Or(self, x: Const): bool { + match { + | self.IsBool() && x.IsBool(): + ret self.ReadBool() || x.ReadBool() + |: + ret false + } + } + + // Reports whether self and x are equals. + // Returns false if type is not supported. + fn Eq(self, x: Const): bool { + match { + | self.IsNil(): + ret x.IsNil() + | self.IsBool(): + ret x.IsBool() && self.ReadBool() == x.ReadBool() + | self.IsStr(): + ret x.IsStr() && self.ReadStr() == x.ReadStr() + | self.IsI64(): + ret self.ReadI64() == x.AsI64() + | self.IsU64(): + ret self.ReadU64() == x.AsU64() + | self.IsF64(): + ret self.ReadF64() == x.AsF64() + |: + ret false + } + } + + // Reports whether self less than x. + // Returns false if type is unsupported by operation. + // + // Supported types are: + // - strings + // - 64-bit signed integer + // - 64-bit unsigned integer + // - 64-bit floating-point + fn Lt(self, x: Const): bool { + match { + | self.IsStr(): + ret x.IsStr() && self.ReadStr() < x.ReadStr() + | self.IsI64(): + ret self.ReadI64() < x.AsI64() + | self.IsU64(): + ret self.ReadU64() < x.AsU64() + | self.IsF64(): + ret self.ReadF64() < x.AsF64() + |: + ret false + } + } + + // Reports whether self less than or equals to x. + // Returns false if type is unsupported by operation. + // + // Supported types are: + // - strings + // - 64-bit signed integer + // - 64-bit unsigned integer + // - 64-bit floating-point + fn LtEq(self, x: Const): bool { + match { + | self.IsStr(): + ret x.IsStr() && self.ReadStr() <= x.ReadStr() + | self.IsI64(): + ret self.ReadI64() <= x.AsI64() + | self.IsU64(): + ret self.ReadU64() <= x.AsU64() + | self.IsF64(): + ret self.ReadF64() <= x.AsF64() + |: + ret false + } + } + + // Reports whether self greater than x. + // Returns false if type is unsupported by operation. + // + // Supported types are: + // - strings + // - 64-bit signed integer + // - 64-bit unsigned integer + // - 64-bit floating-point + fn Gt(self, x: Const): bool { + match { + | self.IsStr(): + ret x.IsStr() && self.ReadStr() > x.ReadStr() + | self.IsI64(): + ret self.ReadI64() > x.AsI64() + | self.IsU64(): + ret self.ReadU64() > x.AsU64() + | self.IsF64(): + ret self.ReadF64() > x.AsF64() + |: + ret false + } + } + + // Reports whether self greater than or equals to x. + // Returns false if type is unsupported by operation. + // + // Supported types are: + // - strings + // - 64-bit signed integer + // - 64-bit unsigned integer + // - 64-bit floating-point + fn GtEq(self, x: Const): bool { + match { + | self.IsStr(): + ret x.IsStr() && self.ReadStr() >= x.ReadStr() + | self.IsI64(): + ret self.ReadI64() >= x.AsI64() + | self.IsU64(): + ret self.ReadU64() >= x.AsU64() + | self.IsF64(): + ret self.ReadF64() >= x.AsF64() + |: + ret false + } + } + + // + // Ops + // + + // Adds x's value to itself value. + // Reports whether operation is success. + fn Add(mut self, x: Const): bool { + match { + | self.IsStr(): + if !x.IsStr() { + ret false + } + self.SetStr(self.ReadStr() + x.ReadStr()) + | self.IsF64(): + self.SetF64(self.ReadF64() + x.AsF64()) + | self.IsI64(): + if x.IsF64() { + self.SetF64(self.AsF64() + x.ReadF64()) + } else { + self.SetI64(self.ReadI64() + x.AsI64()) + } + | self.IsU64(): + if x.IsF64() { + self.SetF64(self.AsF64() + x.ReadF64()) + } else { + self.SetU64(self.ReadU64() + x.AsU64()) + } + |: + ret false + } + ret true + } + + // Subs x's value from itself value. + // Reports whether operation is success. + fn Sub(mut self, x: Const): bool { + match { + | self.IsF64(): + self.SetF64(self.ReadF64() - x.AsF64()) + | self.IsI64(): + if x.IsF64() { + self.SetF64(self.AsF64() - x.ReadF64()) + } else { + self.SetI64(self.ReadI64() - x.AsI64()) + } + | self.IsU64(): + if x.IsF64() { + self.SetF64(self.AsF64() - x.ReadF64()) + } else { + self.SetU64(self.ReadU64() - x.AsU64()) + } + |: + ret false + } + ret true + } + + // Multiplies x's value to c's value. + // Reports whether operation is success. + fn Mul(mut self, x: Const): bool { + match { + | self.IsF64(): + self.SetF64(self.ReadF64() * x.AsF64()) + | self.IsI64(): + if x.IsF64() { + self.SetF64(self.AsF64() * x.ReadF64()) + } else { + self.SetI64(self.ReadI64() * x.AsI64()) + } + | self.IsU64(): + if x.IsF64() { + self.SetF64(self.AsF64() * x.ReadF64()) + } else { + self.SetU64(self.ReadU64() * x.AsU64()) + } + |: + ret false + } + ret true + } + + // Divides itself value to x's value. + // Reports whether operation is success. + // Reports false if divided-by-zero. + // + // NOTICE + // This operation makes constant value is floating-point. + fn Div(mut self, x: Const): bool { + match { + | self.IsF64(): + l := x.AsF64() + if l == 0 { + ret false + } + self.SetF64(self.ReadF64() / l) + | self.IsI64(): + l := x.AsF64() + if l == 0 { + ret false + } + self.SetF64(self.AsF64() / l) + | self.IsU64(): + l := x.AsF64() + if l == 0 { + ret false + } + self.SetF64(self.AsF64() / l) + |: + ret false + } + ret true + } + + // Mods itself value to x's value. + // Reports whether operation is success. + // Reports false if divided-by-zero. + fn Mod(mut self, x: Const): bool { + match { + | self.IsI64(): + l := x.AsI64() + if l == 0 { + ret false + } + self.SetI64(self.ReadI64() % l) + | self.IsU64(): + l := x.AsU64() + if l == 0 { + ret false + } + self.SetU64(self.ReadU64() % l) + |: + ret false + } + ret true + } + + // Bitwise and itself value to x's value. + // Reports whether operation is success. + fn BitwiseAnd(mut self, x: Const): bool { + match { + | self.IsI64(): + self.SetI64(self.ReadI64() & x.AsI64()) + | self.IsU64(): + self.SetU64(self.ReadU64() & x.AsU64()) + |: + ret false + } + ret true + } + + // Bitwise or itself value to x's value. + // Reports whether operation is success. + fn BitwiseOr(mut self, x: Const): bool { + match { + | self.IsI64(): + self.SetI64(self.ReadI64() | x.AsI64()) + | self.IsU64(): + self.SetU64(self.ReadU64() | x.AsU64()) + |: + ret false + } + ret true + } + + // Bitwise xor itself value to x's value. + // Reports whether operation is success. + fn Xor(mut self, x: Const): bool { + match { + | self.IsI64(): + self.SetI64(self.ReadI64() ^ x.AsI64()) + | self.IsU64(): + self.SetU64(self.ReadU64() ^ x.AsU64()) + |: + ret false + } + ret true + } + + // Left shifts itself value to x's value. + // Reports whether operation is success. + fn Lshift(mut self, x: Const): bool { + match { + | self.IsI64(): + l := self.AsI64() + if l < 0 { + r := x.AsU64() + self.SetI64(l << r) + } else { + lshiftUnsig(self, x) + } + | self.IsU64(): + lshiftUnsig(self, x) + |: + ret false + } + ret true + } + + // Right shifts itself value to x's value. + // Reports whether operation is success. + fn Rshift(mut self, x: Const): bool { + match { + | self.IsI64(): + l := self.AsI64() + if l < 0 { + r := x.AsU64() + self.SetI64(l >> r) + } else { + rshiftUnsig(self, x) + } + | self.IsU64(): + rshiftUnsig(self, x) + |: + ret false + } + ret true + } } fn lshiftUnsig(mut &c: Const, &x: Const) { - l := c.AsU64() - r := x.AsU64() - c.SetU64(l << r) + l := c.AsU64() + r := x.AsU64() + c.SetU64(l << r) } fn rshiftUnsig(mut &c: Const, &x: Const) { - l := c.AsU64() - r := x.AsU64() - c.SetU64(l >> r) + l := c.AsU64() + r := x.AsU64() + c.SetU64(l >> r) } \ No newline at end of file diff --git a/std/jule/constant/lit/bytes.jule b/std/jule/constant/lit/bytes.jule index f8e7f1ae4..f177c2230 100644 --- a/std/jule/constant/lit/bytes.jule +++ b/std/jule/constant/lit/bytes.jule @@ -9,8 +9,8 @@ use utf8 for std::unicode::utf8 // Reports whether rune is byte actually. // In other words, whether rune is ACII. fn IsAscii(r: rune): bool { - const MaxAscii = 1 << 7 - 1 - ret r <= MaxAscii + const MaxAscii = 1 << 7 - 1 + ret r <= MaxAscii } // Returns rune value string from literal, includes quotes. @@ -18,15 +18,15 @@ fn IsAscii(r: rune): bool { // Returns zero rune if len(lit) == 0. // Assumes lit is syntaticaly and semantically correct. fn ToRune(mut lit: str): rune { - mut r := rune(0) - lit = lit[1:len(lit)-1] - if lit[0] == '\\' && len(lit) > 1 { - mut i := 0 - r = runeFromEsqSeq(lit, i) - } else { - r, _ = utf8::DecodeRuneStr(lit) - } - ret r + mut r := rune(0) + lit = lit[1:len(lit)-1] + if lit[0] == '\\' && len(lit) > 1 { + mut i := 0 + r = runeFromEsqSeq(lit, i) + } else { + r, _ = utf8::DecodeRuneStr(lit) + } + ret r } // Returns raw-string value string from literal, includes quotes. @@ -34,10 +34,10 @@ fn ToRune(mut lit: str): rune { // Returns empty string if len(lit) == 0. // Assumes lit is syntaticaly and semantically correct. fn ToRawStr(lit: str): str { - if len(lit) == 2 { - ret "" - } - ret lit[1:len(lit)-1] + if len(lit) == 2 { + ret "" + } + ret lit[1:len(lit)-1] } // Returns string value string from literal, includes quotes. @@ -45,108 +45,108 @@ fn ToRawStr(lit: str): str { // Returns empty string if len(lit) == 0. // Assumes lit is syntaticaly and semantically correct. fn ToStr(mut lit: str): str { - if len(lit) == 2 { - ret "" - } + if len(lit) == 2 { + ret "" + } - // Means string is just ASCII text without escape sequences. - mut isPure := true - for _, b in lit { - if b >= utf8::RuneSelf || b == '\\' { - isPure = false - break - } - } + // Means string is just ASCII text without escape sequences. + mut isPure := true + for _, b in lit { + if b >= utf8::RuneSelf || b == '\\' { + isPure = false + break + } + } - if isPure { - ret lit[1:len(lit)-1] - } + if isPure { + ret lit[1:len(lit)-1] + } - // String is not pure. - // Handle unicode characters and escape sequences. - lit = lit[1:len(lit)-1] - mut s := make([]byte, 0, len(lit)) - mut i := 0 - for i < len(lit) { - b := lit[i] - if b == '\\' { - strEsqSeq(s, lit, i) - } else { - r, size := utf8::DecodeRuneStr(lit[i:]) - i += size - s = utf8::AppendRune(s, r) - } - } - ret unsafe::StrFromBytes(s) + // String is not pure. + // Handle unicode characters and escape sequences. + lit = lit[1:len(lit)-1] + mut s := make([]byte, 0, len(lit)) + mut i := 0 + for i < len(lit) { + b := lit[i] + if b == '\\' { + strEsqSeq(s, lit, i) + } else { + r, size := utf8::DecodeRuneStr(lit[i:]) + i += size + s = utf8::AppendRune(s, r) + } + } + ret unsafe::StrFromBytes(s) } fn tryBtoaCommonEsq(s: str): (seq: byte, ok: bool) { - if len(s) < 2 || s[0] != '\\' { - ret - } - match s[1] { - | '\\': - seq = '\\' - | '\'': - seq = '\'' - | '"': - seq = '"' - | 'a': - seq = '\a' - | 'b': - seq = '\b' - | 'f': - seq = '\f' - | 'n': - seq = '\n' - | 'r': - seq = '\r' - | 't': - seq = '\t' - | 'v': - seq = '\v' - } - ok = seq != 0 - ret + if len(s) < 2 || s[0] != '\\' { + ret + } + match s[1] { + | '\\': + seq = '\\' + | '\'': + seq = '\'' + | '"': + seq = '"' + | 'a': + seq = '\a' + | 'b': + seq = '\b' + | 'f': + seq = '\f' + | 'n': + seq = '\n' + | 'r': + seq = '\r' + | 't': + seq = '\t' + | 'v': + seq = '\v' + } + ok = seq != 0 + ret } fn runeFromEsqSeq(s: str, mut &i: int): rune { - b, ok := tryBtoaCommonEsq(s[i:]) - i++ // Skip escape sequence solidus. - if ok { - i++ // Skip sequence specifier. - ret rune(b) - } + b, ok := tryBtoaCommonEsq(s[i:]) + i++ // Skip escape sequence solidus. + if ok { + i++ // Skip sequence specifier. + ret rune(b) + } - match s[i] { - | 'u': - const SeqLen = 5 - r := rune(conv::ParseUint(s[i+1 : i+SeqLen], 16, 64)!) - i += SeqLen - ret r - | 'U': - const SeqLen = 9 - r := rune(conv::ParseUint(s[i+1 : i+SeqLen], 16, 64)!) - i += SeqLen - ret r - | 'x': - const SeqLen = 3 - seq := s[i+1 : i+SeqLen] - i += SeqLen - ret rune(conv::ParseUint(seq, 16, 64)!) - |: - const SeqLen = 3 - seq := s[i:i+SeqLen] - i += SeqLen - ret rune(conv::ParseUint(seq[1:], 8, 64)!) - } + match s[i] { + | 'u': + const SeqLen = 5 + r := rune(conv::ParseUint(s[i+1 : i+SeqLen], 16, 64)!) + i += SeqLen + ret r + | 'U': + const SeqLen = 9 + r := rune(conv::ParseUint(s[i+1 : i+SeqLen], 16, 64)!) + i += SeqLen + ret r + | 'x': + const SeqLen = 3 + seq := s[i+1 : i+SeqLen] + i += SeqLen + ret rune(conv::ParseUint(seq, 16, 64)!) + |: + const SeqLen = 3 + seq := s[i:i+SeqLen] + i += SeqLen + ret rune(conv::ParseUint(seq[1:], 8, 64)!) + } } fn strEsqSeq(mut &buf: []byte, s: str, mut &i: int) { - r := runeFromEsqSeq(s, i) - if r <= 255 { - buf = append(buf, byte(r)) - ret - } - buf = utf8::AppendRune(buf, r) + r := runeFromEsqSeq(s, i) + if r <= 255 { + buf = append(buf, byte(r)) + ret + } + buf = utf8::AppendRune(buf, r) } \ No newline at end of file diff --git a/std/jule/importer/annotation.jule b/std/jule/importer/annotation.jule index c10a6034f..f4f95e4c2 100644 --- a/std/jule/importer/annotation.jule +++ b/std/jule/importer/annotation.jule @@ -7,103 +7,103 @@ use build for std::jule::build use strings for std::strings fn checkOs(arg: str): (ok: bool, exist: bool) { - ok = false - exist = true - match arg { - | build::DistOs.Windows: - ok = build::IsWindows(build::Os) - | build::DistOs.Darwin: - ok = build::IsDarwin(build::Os) - | build::DistOs.Linux: - ok = build::IsLinux(build::Os) - | build::DistOs.Unix: - ok = build::IsUnix(build::Os) - |: - ok = true - exist = false - } - ret + ok = false + exist = true + match arg { + | build::DistOs.Windows: + ok = build::IsWindows(build::Os) + | build::DistOs.Darwin: + ok = build::IsDarwin(build::Os) + | build::DistOs.Linux: + ok = build::IsLinux(build::Os) + | build::DistOs.Unix: + ok = build::IsUnix(build::Os) + |: + ok = true + exist = false + } + ret } fn checkArch(arg: str): (ok: bool, exist: bool) { - ok = false - exist = true - match arg { - | build::DistArch.I386: - ok = build::IsI386(build::Arch) - | build::DistArch.Amd64: - ok = build::IsAmd64(build::Arch) - | build::DistArch.Arm64: - ok = build::IsArm64(build::Arch) - | build::DistArch.X64: - ok = build::Is64Bit(build::Arch) - | build::DistArch.X32: - ok = build::Is32Bit(build::Arch) - |: - ok = true - exist = false - } - ret + ok = false + exist = true + match arg { + | build::DistArch.I386: + ok = build::IsI386(build::Arch) + | build::DistArch.Amd64: + ok = build::IsAmd64(build::Arch) + | build::DistArch.Arm64: + ok = build::IsArm64(build::Arch) + | build::DistArch.X64: + ok = build::Is64Bit(build::Arch) + | build::DistArch.X32: + ok = build::Is32Bit(build::Arch) + |: + ok = true + exist = false + } + ret } // Reports whether file path passes file annotation by current system. fn isPassFileAnnotation(mut p: str): bool { - p = path::Base(p) - n := len(p) - p = p[:n-len(path::Ext(p))] + p = path::Base(p) + n := len(p) + p = p[:n-len(path::Ext(p))] - // a1 is the second annotation. - // Should be architecture annotation if exist annotation 2 (aka a2), - // can operating system or architecture annotation if not. - mut a1 := "" - // a2 is first filter. - // Should be operating system filter if exist and valid annotation. - mut a2 := "" + // a1 is the second annotation. + // Should be architecture annotation if exist annotation 2 (aka a2), + // can operating system or architecture annotation if not. + mut a1 := "" + // a2 is first filter. + // Should be operating system filter if exist and valid annotation. + mut a2 := "" - // Annotation 1 - mut i := strings::FindLastByte(p, '_') - if i == -1 { - // Check file name directly if not exist any _ character. - mut ok, mut exist := checkOs(p) - if exist { - ret ok - } - ok, exist = checkArch(p) - ret !exist || ok - } - if i+1 >= n { - ret true - } - a1 = p[i+1:] + // Annotation 1 + mut i := strings::FindLastByte(p, '_') + if i == -1 { + // Check file name directly if not exist any _ character. + mut ok, mut exist := checkOs(p) + if exist { + ret ok + } + ok, exist = checkArch(p) + ret !exist || ok + } + if i+1 >= n { + ret true + } + a1 = p[i+1:] - p = p[:i] + p = p[:i] - // Annotation 2 - i = strings::FindLastByte(p, '_') - if i != -1 { - a2 = p[i+1:] - } + // Annotation 2 + i = strings::FindLastByte(p, '_') + if i != -1 { + a2 = p[i+1:] + } - if a2 == "" { - mut ok, mut exist := checkOs(a1) - if exist { - ret ok - } - ok, exist = checkArch(a1) - ret !exist || ok - } + if a2 == "" { + mut ok, mut exist := checkOs(a1) + if exist { + ret ok + } + ok, exist = checkArch(a1) + ret !exist || ok + } - mut ok, mut exist := checkArch(a1) - if exist { - if !ok { - ret false - } - ok, exist = checkOs(a2) - ret !exist || ok - } + mut ok, mut exist := checkArch(a1) + if exist { + if !ok { + ret false + } + ok, exist = checkOs(a2) + ret !exist || ok + } - // a1 is not architecture, for this reason bad couple pattern. - // Accept as one pattern, so a1 can be platform. - ok, exist = checkOs(a1) - ret !exist || ok + // a1 is not architecture, for this reason bad couple pattern. + // Accept as one pattern, so a1 can be platform. + ok, exist = checkOs(a1) + ret !exist || ok } \ No newline at end of file diff --git a/std/jule/importer/directive_eval.jule b/std/jule/importer/directive_eval.jule index 3dd117f22..f18e5ca5a 100644 --- a/std/jule/importer/directive_eval.jule +++ b/std/jule/importer/directive_eval.jule @@ -12,126 +12,126 @@ use std::jule::lex::{Token, TokenId, TokenKind} // Read manual for more information about syntax or etc: // https://manual.jule.dev/compiler/directives.html#directive-expressions struct directiveEval { - logs: []Log - d: &Directive - vars: []str + logs: []Log + d: &Directive + vars: []str } impl directiveEval { - fn pushErr(mut self, t: &Token, fmt: LogMsg, args: ...any) { - self.logs = append(self.logs, Log{ - Kind: LogKind.Error, - Row: t.Row, - Column: t.Column, - Path: t.File.Path, - Text: Logf(fmt, args...), - }) - } - - // Split operans by binary operators. - // Skips range of parentheses. - fn splitOperans(mut self, op: TokenId, mut &tokens: []&Token): [][]&Token { - mut parts := make([][]&Token, 0, 10) - mut i := 0 - mut rangeN := 0 - mut last := 0 - for i < len(tokens)-1; i++ { - b := tokens[i] - match b.Id { - | TokenId.LParent: - rangeN++ - continue - | TokenId.RParent: - rangeN-- - } - if rangeN > 0 || b.Id != op { - continue - } - parts = append(parts, tokens[last:i]) - last = i + 1 - } - if last < len(tokens) { - parts = append(parts, tokens[last:]) - } else { - // Missing operand. - self.pushErr(tokens[last-1], LogMsg.MissingExpr) - ret nil - } - ret parts - } - - // Eval directive variable. - fn evalDirectiveIdent(self, ident: str): bool { - if ident == "" { - ret false - } - for _, var in self.vars { - if var == ident { - ret true - } - } - ret false - } - - // Eval directive expression part. - // Accepts unary operators. - fn evalDirectivePart(mut self, mut part: []&Token): bool { - logicalNot := part[0].Id == TokenId.Excl - if logicalNot { - part = part[1:] - } - - if len(part) > 1 { - self.pushErr(part[1], LogMsg.InvalidSyntax) - ret false - } - - mut result := self.evalDirectiveIdent(part[0].Kind) - if logicalNot { - result = !result - } - ret result - } - - fn eval(mut self): bool { - if len(self.d.Args) == 0 { - self.pushErr(self.d.Tag, LogMsg.MissingExpr) - ret false - } - - mut result := false - - mut logicalOrParts := self.splitOperans(TokenId.DblVline, self.d.Args) - if logicalOrParts == nil { - ret false - } - - for (_, mut part) in logicalOrParts { - mut and := true - mut logicalAndParts := self.splitOperans(TokenId.DblAmper, part) - if logicalAndParts == nil { - ret false - } - - for (_, mut andPart) in logicalAndParts { - first := andPart[0] - if first.Id == TokenId.LParent { - end := andPart[len(andPart)-1] - - // Missing close. - if end.Id != TokenId.RParent { - self.pushErr(first, LogMsg.WaitCloseParent) - ret false - } - - andPart = andPart[1:len(andPart)-1] // Remove parentheses. - } - and = and && self.evalDirectivePart(andPart) - } - - result = result || and - } - - ret result - } + fn pushErr(mut self, t: &Token, fmt: LogMsg, args: ...any) { + self.logs = append(self.logs, Log{ + Kind: LogKind.Error, + Row: t.Row, + Column: t.Column, + Path: t.File.Path, + Text: Logf(fmt, args...), + }) + } + + // Split operans by binary operators. + // Skips range of parentheses. + fn splitOperans(mut self, op: TokenId, mut &tokens: []&Token): [][]&Token { + mut parts := make([][]&Token, 0, 10) + mut i := 0 + mut rangeN := 0 + mut last := 0 + for i < len(tokens)-1; i++ { + b := tokens[i] + match b.Id { + | TokenId.LParent: + rangeN++ + continue + | TokenId.RParent: + rangeN-- + } + if rangeN > 0 || b.Id != op { + continue + } + parts = append(parts, tokens[last:i]) + last = i + 1 + } + if last < len(tokens) { + parts = append(parts, tokens[last:]) + } else { + // Missing operand. + self.pushErr(tokens[last-1], LogMsg.MissingExpr) + ret nil + } + ret parts + } + + // Eval directive variable. + fn evalDirectiveIdent(self, ident: str): bool { + if ident == "" { + ret false + } + for _, var in self.vars { + if var == ident { + ret true + } + } + ret false + } + + // Eval directive expression part. + // Accepts unary operators. + fn evalDirectivePart(mut self, mut part: []&Token): bool { + logicalNot := part[0].Id == TokenId.Excl + if logicalNot { + part = part[1:] + } + + if len(part) > 1 { + self.pushErr(part[1], LogMsg.InvalidSyntax) + ret false + } + + mut result := self.evalDirectiveIdent(part[0].Kind) + if logicalNot { + result = !result + } + ret result + } + + fn eval(mut self): bool { + if len(self.d.Args) == 0 { + self.pushErr(self.d.Tag, LogMsg.MissingExpr) + ret false + } + + mut result := false + + mut logicalOrParts := self.splitOperans(TokenId.DblVline, self.d.Args) + if logicalOrParts == nil { + ret false + } + + for (_, mut part) in logicalOrParts { + mut and := true + mut logicalAndParts := self.splitOperans(TokenId.DblAmper, part) + if logicalAndParts == nil { + ret false + } + + for (_, mut andPart) in logicalAndParts { + first := andPart[0] + if first.Id == TokenId.LParent { + end := andPart[len(andPart)-1] + + // Missing close. + if end.Id != TokenId.RParent { + self.pushErr(first, LogMsg.WaitCloseParent) + ret false + } + + andPart = andPart[1:len(andPart)-1] // Remove parentheses. + } + and = and && self.evalDirectivePart(andPart) + } + + result = result || and + } + + ret result + } } \ No newline at end of file diff --git a/std/jule/importer/importer.jule b/std/jule/importer/importer.jule index e284f3ebd..e4f6de295 100644 --- a/std/jule/importer/importer.jule +++ b/std/jule/importer/importer.jule @@ -6,193 +6,193 @@ use std::fs::{OFlag, FsError, DirEntry, File, Directory} use path for std::fs::path use std::jule::ast::{Ast} use build for std::jule::build::{ - Directive, - LogKind, - Log, - Ext, + Directive, + LogKind, + Log, + Ext, } use mod for std::jule::internal::mod use std::jule::lex::{ - LexMode, - Token, - NewFileSet, - Lex, + LexMode, + Token, + NewFileSet, + Lex, } use std::jule::parser::{ParseFile} use std::jule::sema::{ - Importer, - ImportInfo, + Importer, + ImportInfo, } use process for std::process use strings for std::strings // Read buffer by file path. fn readBuff(path: str): []byte { - ret File.Read(path) else { - outln("error: file cannot read") - const ErrorExitCode = 1 - process::Exit(ErrorExitCode) - ret nil // Avoid error - } + ret File.Read(path) else { + outln("error: file cannot read") + const ErrorExitCode = 1 + process::Exit(ErrorExitCode) + ret nil // Avoid error + } } // Make compiler error, just text. // Not includes row, column, and etc. informations. fn flatCompilerErr(text: str): Log { - ret Log{ - Kind: LogKind.Error, - Text: text, - } + ret Log{ + Kind: LogKind.Error, + Text: text, + } } // Default importer for the reference Jule compiler. struct JuleImporter { - mods: []str - mod: str - pkgs: []&ImportInfo - vars: []str + mods: []str + mod: str + pkgs: []&ImportInfo + vars: []str } impl JuleImporter { - // Returns new importer instance by compile information. - static fn New(info: CompileInfo): &JuleImporter { - mut imp := &JuleImporter{ - mods: [build::PathStdlib], - } - initVars(imp.vars, info) - ret imp - } - - // Returns all imported packages. - // The return value is mutable reference to internal buffer. - // You should be care about using that copy. - fn AllPackages(mut self): []&ImportInfo { - ret self.pkgs - } + // Returns new importer instance by compile information. + static fn New(info: CompileInfo): &JuleImporter { + mut imp := &JuleImporter{ + mods: [build::PathStdlib], + } + initVars(imp.vars, info) + ret imp + } + + // Returns all imported packages. + // The return value is mutable reference to internal buffer. + // You should be care about using that copy. + fn AllPackages(mut self): []&ImportInfo { + ret self.pkgs + } } impl Importer for JuleImporter { - fn SetModPath(mut self, path: str) { - self.mod = path - } - - fn GetModPath(self): str { - ret self.mod - } - - fn ModById(self, id: int): str { - ret self.mods[id] - } - - fn GetImport(mut self, path: str): &ImportInfo { - for (_, mut p) in self.pkgs { - if p.Path == path { - ret p - } - } - ret nil - } - - fn ImportPackage(mut self, path: str, update_mod: bool): ([]&Ast, []Log) { - mut dirents := Directory.Read(path) else { - ret nil, [flatCompilerErr("connot read package directory: " + path)] - } - - if update_mod { - newMod := mod::FindModuleFileDeep(path) - if newMod != self.mod { - self.mod = newMod - mut errs := mod::CheckModuleFile(self.mod) - if len(errs) != 0 { - ret nil, errs - } - } - } - - mut asts := make([]&Ast, 0, len(dirents)) - for _, dirent in dirents { - // Skip directories, and non-jule files. - if dirent.Stat.IsDir() || !strings::HasSuffix(dirent.Name, build::Ext) { - continue - } - - _path := path::Join(path, dirent.Name) - mut file := NewFileSet(_path) - file.Fill(readBuff(file.Path)) - mut errors := Lex(file, LexMode.Standard) - if len(errors) > 0 { - ret nil, errors - } - - mut finfo := ParseFile(file) - if len(finfo.Errors) > 0 { - ret nil, finfo.Errors - } - - // Skip this source file if file annotation is failed. - if !isPassFileAnnotation(dirent.Name) { - continue - } - - r, mut logs := self.isPassBuildDirectives(finfo.Ast) - if len(logs) > 0 { - ret nil, logs - } - - // Skip file if can't pass build directives. - if !r { - continue - } - - asts = append(asts, finfo.Ast) - } - - ret asts, nil - } - - fn Imported(mut self, mut imp: &ImportInfo) { - // Already imported? - for _, p in self.pkgs { - if p.Binded == imp.Binded && p.LinkPath == imp.LinkPath { - ret - } - } - - if len(self.mod) != 0 { - for i, mod in self.mods { - if self.mod == mod { - imp.ModId = i - goto setted - } - } - imp.ModId = len(self.mods) - self.mods = append(self.mods, self.mod) - setted: - } - - self.pkgs = append(self.pkgs, imp) - } + fn SetModPath(mut self, path: str) { + self.mod = path + } + + fn GetModPath(self): str { + ret self.mod + } + + fn ModById(self, id: int): str { + ret self.mods[id] + } + + fn GetImport(mut self, path: str): &ImportInfo { + for (_, mut p) in self.pkgs { + if p.Path == path { + ret p + } + } + ret nil + } + + fn ImportPackage(mut self, path: str, update_mod: bool): ([]&Ast, []Log) { + mut dirents := Directory.Read(path) else { + ret nil, [flatCompilerErr("connot read package directory: " + path)] + } + + if update_mod { + newMod := mod::FindModuleFileDeep(path) + if newMod != self.mod { + self.mod = newMod + mut errs := mod::CheckModuleFile(self.mod) + if len(errs) != 0 { + ret nil, errs + } + } + } + + mut asts := make([]&Ast, 0, len(dirents)) + for _, dirent in dirents { + // Skip directories, and non-jule files. + if dirent.Stat.IsDir() || !strings::HasSuffix(dirent.Name, build::Ext) { + continue + } + + _path := path::Join(path, dirent.Name) + mut file := NewFileSet(_path) + file.Fill(readBuff(file.Path)) + mut errors := Lex(file, LexMode.Standard) + if len(errors) > 0 { + ret nil, errors + } + + mut finfo := ParseFile(file) + if len(finfo.Errors) > 0 { + ret nil, finfo.Errors + } + + // Skip this source file if file annotation is failed. + if !isPassFileAnnotation(dirent.Name) { + continue + } + + r, mut logs := self.isPassBuildDirectives(finfo.Ast) + if len(logs) > 0 { + ret nil, logs + } + + // Skip file if can't pass build directives. + if !r { + continue + } + + asts = append(asts, finfo.Ast) + } + + ret asts, nil + } + + fn Imported(mut self, mut imp: &ImportInfo) { + // Already imported? + for _, p in self.pkgs { + if p.Binded == imp.Binded && p.LinkPath == imp.LinkPath { + ret + } + } + + if len(self.mod) != 0 { + for i, mod in self.mods { + if self.mod == mod { + imp.ModId = i + goto setted + } + } + imp.ModId = len(self.mods) + self.mods = append(self.mods, self.mod) + setted: + } + + self.pkgs = append(self.pkgs, imp) + } } impl JuleImporter { - // Reports whether file passes build directives. - fn isPassBuildDirectives(mut self, mut &file: &Ast): (bool, []Log) { - for (_, mut td) in file.TopDirectives { - if td.Tag.Kind != Directive.Build { - continue - } - mut de := directiveEval{ - d: td, - vars: self.vars, - } - result := de.eval() - if len(de.logs) > 0 { - ret false, de.logs - } - if !result { - ret false, nil - } - } - ret true, nil - } + // Reports whether file passes build directives. + fn isPassBuildDirectives(mut self, mut &file: &Ast): (bool, []Log) { + for (_, mut td) in file.TopDirectives { + if td.Tag.Kind != Directive.Build { + continue + } + mut de := directiveEval{ + d: td, + vars: self.vars, + } + result := de.eval() + if len(de.logs) > 0 { + ret false, de.logs + } + if !result { + ret false, nil + } + } + ret true, nil + } } \ No newline at end of file diff --git a/std/jule/importer/var.jule b/std/jule/importer/var.jule index e4cab78ec..ed5f6211a 100644 --- a/std/jule/importer/var.jule +++ b/std/jule/importer/var.jule @@ -6,77 +6,77 @@ use build for std::jule::build // Standard back-end compilers. enum Compiler: str { - Clang: "clang", - GCC: "gcc", + Clang: "clang", + GCC: "gcc", } // Supported C++ standards. enum CppStd: str { - Cpp14: "cpp14", - Cpp17: "cpp17", - Cpp20: "cpp20", + Cpp14: "cpp14", + Cpp17: "cpp17", + Cpp20: "cpp20", } // Compile information. struct CompileInfo { - // Production compilation. - Prod: bool + // Production compilation. + Prod: bool - // Test compilation. - Test: bool + // Test compilation. + Test: bool - // Back-end compiler to use. - Compiler: Compiler + // Back-end compiler to use. + Compiler: Compiler - // C++ standard to use. - CppStd: CppStd + // C++ standard to use. + CppStd: CppStd } // Set operating system variables by native operating system. fn setOsVars(mut &vars: []str) { - vars = append(vars, build::Os) - if build::IsUnix(build::Os) { - vars = append(vars, "unix") - } + vars = append(vars, build::Os) + if build::IsUnix(build::Os) { + vars = append(vars, "unix") + } } // Set architecture variables by native architecture. fn setArchVars(mut &vars: []str) { - vars = append(vars, build::Arch) - if build::Is64Bit(build::Arch) { - vars = append(vars, "x64") - } - if build::Is32Bit(build::Arch) { - vars = append(vars, "x32") - } + vars = append(vars, build::Arch) + if build::Is64Bit(build::Arch) { + vars = append(vars, "x64") + } + if build::Is32Bit(build::Arch) { + vars = append(vars, "x32") + } } // Initialize directive eval variables by compile info. fn initVars(mut &vars: []str, &info: CompileInfo) { - setOsVars(vars) - setArchVars(vars) + setOsVars(vars) + setArchVars(vars) - if info.Prod { - vars = append(vars, "production") - } + if info.Prod { + vars = append(vars, "production") + } - if info.Test { - vars = append(vars, "test") - } + if info.Test { + vars = append(vars, "test") + } - match info.Compiler { - | Compiler.Clang: - vars = append(vars, "clang") - | Compiler.GCC: - vars = append(vars, "gcc") - } + match info.Compiler { + | Compiler.Clang: + vars = append(vars, "clang") + | Compiler.GCC: + vars = append(vars, "gcc") + } - match info.CppStd { - | CppStd.Cpp14: - vars = append(vars, "cpp14") - | CppStd.Cpp17: - vars = append(vars, "cpp17") - | CppStd.Cpp20: - vars = append(vars, "cpp20") - } + match info.CppStd { + | CppStd.Cpp14: + vars = append(vars, "cpp14") + | CppStd.Cpp17: + vars = append(vars, "cpp17") + | CppStd.Cpp20: + vars = append(vars, "cpp20") + } } \ No newline at end of file diff --git a/std/jule/integrated/conv.jule b/std/jule/integrated/conv.jule index bc537e9e9..9b7075601 100644 --- a/std/jule/integrated/conv.jule +++ b/std/jule/integrated/conv.jule @@ -12,93 +12,93 @@ use utf16 for std::unicode::utf16 // s, with a terminating NULL added. If s includes NULL // character at any location, ignores followed characters. fn UTF16FromStr(s: str): []u16 { - // In the worst case all characters require two u16. - // Also account for the terminating NULL character. - // See: C Strings and Windows UTF16. + // In the worst case all characters require two u16. + // Also account for the terminating NULL character. + // See: C Strings and Windows UTF16. - const NullTermination = 0 - runes := ([]rune)(s) - mut buff := make([]u16, 0, len(runes)) - for _, r in runes { - if r == NullTermination { - break - } - buff = utf16::AppendRune(buff, r) - } - ret utf16::AppendRune(buff, NullTermination) + const NullTermination = 0 + runes := ([]rune)(s) + mut buff := make([]u16, 0, len(runes)) + for _, r in runes { + if r == NullTermination { + break + } + buff = utf16::AppendRune(buff, r) + } + ret utf16::AppendRune(buff, NullTermination) } // Returns the UTF-8 encoding of the UTF-16 sequence s, // with a terminating NULL removed. Returns empty string // if s is nil. fn UTF16ToStr(s: []u16): str { - if s == nil { - ret "" - } - mut codePage := unsafe { *(&s) } - for i, v in s { - if v == 0 { - codePage = codePage[:i] - break - } - } - ret str(utf16::Decode(codePage)) + if s == nil { + ret "" + } + mut codePage := unsafe { *(&s) } + for i, v in s { + if v == 0 { + codePage = codePage[:i] + break + } + } + ret str(utf16::Decode(codePage)) } // Returns the UTF-8 encoding of the UTF-16 sequence s in *u16 form, // with a terminating NULL removed. Returns empty string if s is nil. unsafe fn U16PtrToStr(s: *u16): str { - if s == nil { - ret "" - } + if s == nil { + ret "" + } - let mut codePage: []u16 - mut i := 0 - for ; i++ { - r := s[i] - if r == 0 { - ret str(utf16::Decode(codePage)) - } - codePage = append(codePage, r) - } - ret "" + let mut codePage: []u16 + mut i := 0 + for ; i++ { + r := s[i] + if r == 0 { + ret str(utf16::Decode(codePage)) + } + codePage = append(codePage, r) + } + ret "" } // Returns the string of s, with a terminating NULL removed. // Returns empty string if pointer is nil. unsafe fn BytePtrToStr(s: *byte): str { - if s == nil { - ret "" - } - mut n := 0 - unsafe { - for s[n] != 0; n++ {} - } - if n == 0 { - ret "" - } - mut buf := make([]byte, n) - n = 0 - unsafe { - for s[n] != 0; n++ { - buf[n] = s[n] - } - } - ret str(buf) + if s == nil { + ret "" + } + mut n := 0 + unsafe { + for s[n] != 0; n++ {} + } + if n == 0 { + ret "" + } + mut buf := make([]byte, n) + n = 0 + unsafe { + for s[n] != 0; n++ { + buf[n] = s[n] + } + } + ret str(buf) } // Returns s as NULL terminated byte slice which is able to be used safely as // NULL terminated string pointer. If s contatins NULL termination at any location, // accepts NULL termination is the end of s and skips following bytes. fn StrToBytes(s: str): []byte { - for i, b in s { - if b == 0 { - mut bytes := make([]byte, i+1) - copy(bytes, s[:len(bytes)]) - ret bytes - } - } - mut bytes := make([]byte, len(s)+1) - copy(bytes, s) - ret bytes + for i, b in s { + if b == 0 { + mut bytes := make([]byte, i + 1) + copy(bytes, s[:len(bytes)]) + ret bytes + } + } + mut bytes := make([]byte, len(s) + 1) + copy(bytes, s) + ret bytes } \ No newline at end of file diff --git a/std/jule/integrated/mem.jule b/std/jule/integrated/mem.jule index d38cb69ed..91f767823 100644 --- a/std/jule/integrated/mem.jule +++ b/std/jule/integrated/mem.jule @@ -14,7 +14,7 @@ cpp unsafe fn free(mut ptr: *unsafe) // This function is part of the C-style memory management. // It can be very dangerous. fn Malloc(size: uint): *unsafe { - ret cpp.malloc(size) + ret cpp.malloc(size) } // Allocates n elements of size bytes each, all initialized to zero. @@ -23,7 +23,7 @@ fn Malloc(size: uint): *unsafe { // This function is part of the C-style memory management. // It can be very dangerous. fn Calloc(size: uint, n: uint): *unsafe { - ret cpp.calloc(size, n) + ret cpp.calloc(size, n) } // Re-allocates the previously allocated block in ptr, @@ -33,7 +33,7 @@ fn Calloc(size: uint, n: uint): *unsafe { // This function is part of the C-style memory management. // It can be very dangerous. unsafe fn Realloc(mut ptr: *unsafe, size: uint): *unsafe { - ret cpp.realloc(ptr, size) + ret cpp.realloc(ptr, size) } // Free a block allocated by malloc, realloc or calloc. @@ -43,33 +43,33 @@ unsafe fn Realloc(mut ptr: *unsafe, size: uint): *unsafe { // This function is part of the C-style memory management. // It can be very dangerous. unsafe fn Free(mut ptr: *unsafe) { - cpp.free(ptr) + cpp.free(ptr) } // Allocates new memory. // Equavalent to: new T in C++ fn New[T](): *T { - unsafe { - ret Emit[*T]("new (std::nothrow) {}", T) - } + unsafe { + ret Emit[*T]("new (std::nothrow) {}", T) + } } // Allocates new array memory. // Equavalent to: new T[size] in C++ fn NewArray[T](size: int): *T { - unsafe { - ret Emit[*T]("new (std::nothrow) {}[{}]", T, size) - } + unsafe { + ret Emit[*T]("new (std::nothrow) {}[{}]", T, size) + } } // Deallocates memory allocation. // Equavalent to: delete heap in C++ unsafe fn Delete[T](heap: *T) { - Emit("delete {}", heap) + Emit("delete {}", heap) } // Deallocates array memory allocation. // Equavalent to: delete[] heap in C++ unsafe fn DeleteArray[T](heap: *T) { - Emit("delete[] {}", heap) + Emit("delete[] {}", heap) } \ No newline at end of file diff --git a/std/jule/internal/mod/export.jule b/std/jule/internal/mod/export.jule index 7d5fa6f76..3b90c2652 100644 --- a/std/jule/internal/mod/export.jule +++ b/std/jule/internal/mod/export.jule @@ -7,10 +7,10 @@ use unicode for std::unicode // Reports whether identifier is public. fn IsPub(ident: str): bool { - if ident[0] < utf8::RuneSelf { // ASCII, fast way. - b := ident[0] - ret 'A' <= b && b <= 'Z' - } - r, _ := utf8::DecodeRuneStr(ident) - ret unicode::IsUpper(r) + if ident[0] < utf8::RuneSelf { // ASCII, fast way. + b := ident[0] + ret 'A' <= b && b <= 'Z' + } + r, _ := utf8::DecodeRuneStr(ident) + ret unicode::IsUpper(r) } \ No newline at end of file diff --git a/std/jule/internal/mod/mod.jule b/std/jule/internal/mod/mod.jule index 69f290fe3..95e0ca07f 100644 --- a/std/jule/internal/mod/mod.jule +++ b/std/jule/internal/mod/mod.jule @@ -11,52 +11,52 @@ use strings for std::strings // Searches module file in path. // Reports whether module file is exist in given directory. fn FindModuleFile(&dirents: []&DirEntry): bool { - for _, d in dirents { - if !d.Stat.IsDir() && d.Name == build::ModuleFile { - ret true - } - } - ret false + for _, d in dirents { + if !d.Stat.IsDir() && d.Name == build::ModuleFile { + ret true + } + } + ret false } // Searches module file in path, and their parent paths. // Returns empty string if any module file is not exist. // Returns directory path of module file if exist. fn FindModuleFileDeep(mut path: str): str { - for { - mut dirents := Directory.Read(path) else { - break - } + for { + mut dirents := Directory.Read(path) else { + break + } - exist := FindModuleFile(dirents) - if exist { - ret path - } + exist := FindModuleFile(dirents) + if exist { + ret path + } - n := len(path) - path = path::Dir(path) - if len(path) == n { // Same path, no difference. - break - } - } + n := len(path) + path = path::Dir(path) + if len(path) == n { // Same path, no difference. + break + } + } - ret "" + ret "" } // Checks module file of given directory. fn CheckModuleFile(&path: str): []Log { - bytes := File.Read(path::Join(path, build::ModuleFile)) else { - ret [{ - Kind: LogKind.Flat, - Text: "module file could not checked because of a problem", - }] - } - s := strings::Trim(unsafe::BytesStr(bytes), " \n\r\t\v") - if len(s) != 0 { - ret [{ - Kind: LogKind.Flat, - Text: "module file has syntax error(s)", - }] - } - ret nil + bytes := File.Read(path::Join(path, build::ModuleFile)) else { + ret [{ + Kind: LogKind.Flat, + Text: "module file could not checked because of a problem", + }] + } + s := strings::Trim(unsafe::BytesStr(bytes), " \n\r\t\v") + if len(s) != 0 { + ret [{ + Kind: LogKind.Flat, + Text: "module file has syntax error(s)", + }] + } + ret nil } \ No newline at end of file diff --git a/std/jule/lex/file.jule b/std/jule/lex/file.jule index 87938b086..8d79880c0 100644 --- a/std/jule/lex/file.jule +++ b/std/jule/lex/file.jule @@ -7,55 +7,55 @@ use path for std::fs::path // Fileset for lexing. struct File { - Path: str - Data: []byte - Tokens: []&Token + Path: str + Data: []byte + Tokens: []&Token } impl File { - // Fill data. - fn Fill(mut self, mut data: []byte) { - self.Data = data - } - - // Returns directory of file's path. - fn Dir(self): str { - ret path::Dir(self.Path) - } - - // Returns filename. - fn Name(self): str { - ret path::Base(self.Path) - } - - // Returns self as uintptr. - fn Addr(self): uintptr { - ret uintptr(&self) - } - - // Returns line (not include new-line char) by row. - // Returns empty string if line is not buffer. - fn GetRow(self, row: int): str { - mut n := 0 - mut lineStart := 0 - mut i := 0 - for i < len(self.Data); i++ { - if self.Data[i] != '\n' { - continue - } - n++ - if n == row { - ret str(self.Data[lineStart:i]) - } - lineStart = i + 1 - } - ret "" - } + // Fill data. + fn Fill(mut self, mut data: []byte) { + self.Data = data + } + + // Returns directory of file's path. + fn Dir(self): str { + ret path::Dir(self.Path) + } + + // Returns filename. + fn Name(self): str { + ret path::Base(self.Path) + } + + // Returns self as uintptr. + fn Addr(self): uintptr { + ret uintptr(&self) + } + + // Returns line (not include new-line char) by row. + // Returns empty string if line is not buffer. + fn GetRow(self, row: int): str { + mut n := 0 + mut lineStart := 0 + mut i := 0 + for i < len(self.Data); i++ { + if self.Data[i] != '\n' { + continue + } + n++ + if n == row { + ret str(self.Data[lineStart:i]) + } + lineStart = i + 1 + } + ret "" + } } // Returns new File points to Jule file. fn NewFileSet(path: str): &File { - ret &File{ - Path: path, - } + ret &File{ + Path: path, + } } \ No newline at end of file diff --git a/std/jule/lex/lex.jule b/std/jule/lex/lex.jule index 4f28c9af5..944f8c2bd 100644 --- a/std/jule/lex/lex.jule +++ b/std/jule/lex/lex.jule @@ -8,820 +8,820 @@ use utf8 for std::unicode::utf8 // Lexer mode. enum LexMode { - Standard: 0 << 0, // Standard mode. - Comment: 1 << 0, // Standard mode + comments. + Standard: 0 << 0, // Standard mode. + Comment: 1 << 0, // Standard mode + comments. } struct kindPair { - kind: TokenKind - id: TokenId + kind: TokenKind + id: TokenId } static keywords: [...]kindPair = [ - {TokenKind.Const, TokenId.Const}, - {TokenKind.Ret, TokenId.Ret}, - {TokenKind.Type, TokenId.Type}, - {TokenKind.For, TokenId.For}, - {TokenKind.Break, TokenId.Break}, - {TokenKind.Cont, TokenId.Cont}, - {TokenKind.In, TokenId.In}, - {TokenKind.If, TokenId.If}, - {TokenKind.Else, TokenId.Else}, - {TokenKind.Use, TokenId.Use}, - {TokenKind.Goto, TokenId.Goto}, - {TokenKind.Enum, TokenId.Enum}, - {TokenKind.Struct, TokenId.Struct}, - {TokenKind.Co, TokenId.Co}, - {TokenKind.Match, TokenId.Match}, - {TokenKind.Self, TokenId.Self}, - {TokenKind.Trait, TokenId.Trait}, - {TokenKind.Impl, TokenId.Impl}, - {TokenKind.Cpp, TokenId.Cpp}, - {TokenKind.Fall, TokenId.Fall}, - {TokenKind.Fn, TokenId.Fn}, - {TokenKind.Let, TokenId.Let}, - {TokenKind.Unsafe, TokenId.Unsafe}, - {TokenKind.Mut, TokenId.Mut}, - {TokenKind.Defer, TokenId.Defer}, - {TokenKind.Static, TokenId.Static}, - {TokenKind.Error, TokenId.Error}, - {TokenKind.Map, TokenId.Map}, + {TokenKind.Const, TokenId.Const}, + {TokenKind.Ret, TokenId.Ret}, + {TokenKind.Type, TokenId.Type}, + {TokenKind.For, TokenId.For}, + {TokenKind.Break, TokenId.Break}, + {TokenKind.Cont, TokenId.Cont}, + {TokenKind.In, TokenId.In}, + {TokenKind.If, TokenId.If}, + {TokenKind.Else, TokenId.Else}, + {TokenKind.Use, TokenId.Use}, + {TokenKind.Goto, TokenId.Goto}, + {TokenKind.Enum, TokenId.Enum}, + {TokenKind.Struct, TokenId.Struct}, + {TokenKind.Co, TokenId.Co}, + {TokenKind.Match, TokenId.Match}, + {TokenKind.Self, TokenId.Self}, + {TokenKind.Trait, TokenId.Trait}, + {TokenKind.Impl, TokenId.Impl}, + {TokenKind.Cpp, TokenId.Cpp}, + {TokenKind.Fall, TokenId.Fall}, + {TokenKind.Fn, TokenId.Fn}, + {TokenKind.Let, TokenId.Let}, + {TokenKind.Unsafe, TokenId.Unsafe}, + {TokenKind.Mut, TokenId.Mut}, + {TokenKind.Defer, TokenId.Defer}, + {TokenKind.Static, TokenId.Static}, + {TokenKind.Error, TokenId.Error}, + {TokenKind.Map, TokenId.Map}, ] static basicOps: [...]kindPair = [ - {TokenKind.DblColon, TokenId.DblColon}, - {TokenKind.ColonEq, TokenId.ColonEq}, - {TokenKind.Colon, TokenId.Colon}, - {TokenKind.Semicolon, TokenId.Semicolon}, - {TokenKind.Comma, TokenId.Comma}, - {TokenKind.TripleDot, TokenId.TripleDot}, - {TokenKind.Dot, TokenId.Dot}, - {TokenKind.PlusEq, TokenId.PlusEq}, - {TokenKind.MinusEq, TokenId.MinusEq}, - {TokenKind.StarEq, TokenId.StarEq}, - {TokenKind.SolidusEq, TokenId.SolidusEq}, - {TokenKind.PercentEq, TokenId.PercentEq}, - {TokenKind.ShlEq, TokenId.ShlEq}, - {TokenKind.ShrEq, TokenId.ShrEq}, - {TokenKind.CaretEq, TokenId.CaretEq}, - {TokenKind.AmperEq, TokenId.AmperEq}, - {TokenKind.VlineEq, TokenId.VlineEq}, - {TokenKind.Eqs, TokenId.Eqs}, - {TokenKind.NotEq, TokenId.NotEq}, - {TokenKind.GtEq, TokenId.GtEq}, - {TokenKind.LtEq, TokenId.LtEq}, - {TokenKind.DblAmper, TokenId.DblAmper}, - {TokenKind.DblVline, TokenId.DblVline}, - {TokenKind.Shl, TokenId.Shl}, - {TokenKind.Shr, TokenId.Shr}, - {TokenKind.DblPlus, TokenId.DblPlus}, - {TokenKind.DblMinus, TokenId.DblMinus}, - {TokenKind.Plus, TokenId.Plus}, - {TokenKind.Minus, TokenId.Minus}, - {TokenKind.Star, TokenId.Star}, - {TokenKind.Solidus, TokenId.Solidus}, - {TokenKind.Percent, TokenId.Percent}, - {TokenKind.Amper, TokenId.Amper}, - {TokenKind.Vline, TokenId.Vline}, - {TokenKind.Caret, TokenId.Caret}, - {TokenKind.Excl, TokenId.Excl}, - {TokenKind.Lt, TokenId.Lt}, - {TokenKind.Gt, TokenId.Gt}, - {TokenKind.Eq, TokenId.Eq}, - {TokenKind.Hash, TokenId.Hash}, - {TokenKind.LBrace, TokenId.LBrace}, - {TokenKind.RBrace, TokenId.RBrace}, - {TokenKind.LBracket, TokenId.LBracket}, - {TokenKind.RBracket, TokenId.RBracket}, - {TokenKind.LParent, TokenId.LParent}, - {TokenKind.RParent, TokenId.RParent}, + {TokenKind.DblColon, TokenId.DblColon}, + {TokenKind.ColonEq, TokenId.ColonEq}, + {TokenKind.Colon, TokenId.Colon}, + {TokenKind.Semicolon, TokenId.Semicolon}, + {TokenKind.Comma, TokenId.Comma}, + {TokenKind.TripleDot, TokenId.TripleDot}, + {TokenKind.Dot, TokenId.Dot}, + {TokenKind.PlusEq, TokenId.PlusEq}, + {TokenKind.MinusEq, TokenId.MinusEq}, + {TokenKind.StarEq, TokenId.StarEq}, + {TokenKind.SolidusEq, TokenId.SolidusEq}, + {TokenKind.PercentEq, TokenId.PercentEq}, + {TokenKind.ShlEq, TokenId.ShlEq}, + {TokenKind.ShrEq, TokenId.ShrEq}, + {TokenKind.CaretEq, TokenId.CaretEq}, + {TokenKind.AmperEq, TokenId.AmperEq}, + {TokenKind.VlineEq, TokenId.VlineEq}, + {TokenKind.Eqs, TokenId.Eqs}, + {TokenKind.NotEq, TokenId.NotEq}, + {TokenKind.GtEq, TokenId.GtEq}, + {TokenKind.LtEq, TokenId.LtEq}, + {TokenKind.DblAmper, TokenId.DblAmper}, + {TokenKind.DblVline, TokenId.DblVline}, + {TokenKind.Shl, TokenId.Shl}, + {TokenKind.Shr, TokenId.Shr}, + {TokenKind.DblPlus, TokenId.DblPlus}, + {TokenKind.DblMinus, TokenId.DblMinus}, + {TokenKind.Plus, TokenId.Plus}, + {TokenKind.Minus, TokenId.Minus}, + {TokenKind.Star, TokenId.Star}, + {TokenKind.Solidus, TokenId.Solidus}, + {TokenKind.Percent, TokenId.Percent}, + {TokenKind.Amper, TokenId.Amper}, + {TokenKind.Vline, TokenId.Vline}, + {TokenKind.Caret, TokenId.Caret}, + {TokenKind.Excl, TokenId.Excl}, + {TokenKind.Lt, TokenId.Lt}, + {TokenKind.Gt, TokenId.Gt}, + {TokenKind.Eq, TokenId.Eq}, + {TokenKind.Hash, TokenId.Hash}, + {TokenKind.LBrace, TokenId.LBrace}, + {TokenKind.RBrace, TokenId.RBrace}, + {TokenKind.LBracket, TokenId.LBracket}, + {TokenKind.RBracket, TokenId.RBracket}, + {TokenKind.LParent, TokenId.LParent}, + {TokenKind.RParent, TokenId.RParent}, ] fn makeErr(row: int, col: int, &f: &File, fmt: LogMsg, args: ...any): Log { - ret Log{ - Kind: LogKind.Error, - Row: row, - Column: col, - Path: f.Path, - Text: Logf(fmt, args...), - } + ret Log{ + Kind: LogKind.Error, + Row: row, + Column: col, + Path: f.Path, + Text: Logf(fmt, args...), + } } fn bytesHasPrefix(&bytes: []byte, prefix: str): bool { - if len(bytes) < len(prefix) { - ret false - } - for i in prefix { - if bytes[i] != prefix[i] { - ret false - } - } - ret true + if len(bytes) < len(prefix) { + ret false + } + for i in prefix { + if bytes[i] != prefix[i] { + ret false + } + } + ret true } fn floatFmtE(&txt: []byte, mut i: int): (lit: str) { - i++ // Skip E | e - if i >= len(txt) { - ret - } - - mut b := txt[i] - if b == '_' { - ret - } - if b == '+' || b == '-' { - i++ // Skip operator - if i >= len(txt) { - ret - } - if txt[i] == '_' { - ret - } - } - - first := i - for i < len(txt); i++ { - b = txt[i] - if b != '_' && !IsDecimal(b) { - break - } - } - - if i == first { - ret "" - } - ret str(txt[:i]) + i++ // Skip E | e + if i >= len(txt) { + ret + } + + mut b := txt[i] + if b == '_' { + ret + } + if b == '+' || b == '-' { + i++ // Skip operator + if i >= len(txt) { + ret + } + if txt[i] == '_' { + ret + } + } + + first := i + for i < len(txt); i++ { + b = txt[i] + if b != '_' && !IsDecimal(b) { + break + } + } + + if i == first { + ret "" + } + ret str(txt[:i]) } fn floatFmtP(&txt: []byte, i: int): str { - ret floatFmtE(txt, i) + ret floatFmtE(txt, i) } fn floatFmtDotnp(&txt: []byte, mut i: int): str { - if txt[i] != '.' { - ret "" - } + if txt[i] != '.' { + ret "" + } - i++ + i++ loop: - for i < len(txt); i++ { - b := txt[i] - match { - | b == '_' | IsDecimal(b): - continue - | isFloatFmtP(b, i): - ret floatFmtP(txt, i) - |: - break loop - } - } - ret "" + for i < len(txt); i++ { + b := txt[i] + match { + | b == '_' | IsDecimal(b): + continue + | isFloatFmtP(b, i): + ret floatFmtP(txt, i) + |: + break loop + } + } + ret "" } fn floatFmtDotfp(&txt: []byte, mut i: int): str { - i += 2 // skip .f - ret floatFmtE(txt, i) + i += 2 // skip .f + ret floatFmtE(txt, i) } fn floatFmtDotp(&txt: []byte, mut i: int): str { - i++ // skip . - ret floatFmtE(txt, i) + i++ // skip . + ret floatFmtE(txt, i) } fn floatNum(&txt: []byte, mut i: int): (lit: str) { - i++ // Skip dot - if i >= len(txt) { - ret str(txt) - } - if txt[i] == '_' { - i-- - ret str(txt[:i]) - } - for i < len(txt); i++ { - b := txt[i] - if i > 1 && (b == 'e' || b == 'E') { - ret floatFmtE(txt, i) - } - if b != '_' && !IsDecimal(b) { - break - } - } - - if i == 1 { // Just dot - ret - } - ret str(txt[:i]) + i++ // Skip dot + if i >= len(txt) { + ret str(txt) + } + if txt[i] == '_' { + i-- + ret str(txt[:i]) + } + for i < len(txt); i++ { + b := txt[i] + if i > 1 && (b == 'e' || b == 'E') { + ret floatFmtE(txt, i) + } + if b != '_' && !IsDecimal(b) { + break + } + } + + if i == 1 { // Just dot + ret + } + ret str(txt[:i]) } fn commonNum(&txt: []byte): (lit: str) { - mut i := 0 + mut i := 0 loop: - for i < len(txt); i++ { - b := txt[i] - match { - | b == '.': - ret floatNum(txt, i) - | b == '_': - continue - | isFloatFmtE(b, i): - ret floatFmtE(txt, i) - | !IsDecimal(b): - break loop - } - } - - if i == 0 { - ret - } - ret str(txt[:i]) + for i < len(txt); i++ { + b := txt[i] + match { + | b == '.': + ret floatNum(txt, i) + | b == '_': + continue + | isFloatFmtE(b, i): + ret floatFmtE(txt, i) + | !IsDecimal(b): + break loop + } + } + + if i == 0 { + ret + } + ret str(txt[:i]) } fn binaryNum(&txt: []byte): (lit: str) { - if !bytesHasPrefix(txt, "0b") { - ret "" - } - if len(txt) < 2 { - ret - } - - const BinaryStart = 2 - mut i := BinaryStart - for i < len(txt); i++ { - if txt[i] != '_' && !IsBinary(txt[i]) { - break - } - } - - if i == BinaryStart { - ret - } - ret str(txt[:i]) + if !bytesHasPrefix(txt, "0b") { + ret "" + } + if len(txt) < 2 { + ret + } + + const BinaryStart = 2 + mut i := BinaryStart + for i < len(txt); i++ { + if txt[i] != '_' && !IsBinary(txt[i]) { + break + } + } + + if i == BinaryStart { + ret + } + ret str(txt[:i]) } fn isFloatFmtE(b: byte, i: int): bool { - ret i > 0 && (b == 'e' || b == 'E') + ret i > 0 && (b == 'e' || b == 'E') } fn isFloatFmtP(b: byte, i: int): bool { - ret i > 0 && (b == 'p' || b == 'P') + ret i > 0 && (b == 'p' || b == 'P') } fn isFloatFmtDotnp(&txt: []byte, mut i: int): bool { - if txt[i] != '.' { - ret false - } - i++ + if txt[i] != '.' { + ret false + } + i++ loop: - for i < len(txt); i++ { - b := txt[i] - match { - | b == '_' | IsDecimal(b): - continue - | isFloatFmtP(b, i): - ret true - |: - break loop - } - } - - ret false + for i < len(txt); i++ { + b := txt[i] + match { + | b == '_' | IsDecimal(b): + continue + | isFloatFmtP(b, i): + ret true + |: + break loop + } + } + + ret false } fn isFloatFmtDotp(&txt: []byte, i: int): bool { - match { - | len(txt) < 3: - fall - | txt[i] != '.': - fall - | txt[i+1] != 'p' && txt[i+1] != 'P': - ret false - |: - ret true - } + match { + | len(txt) < 3: + fall + | txt[i] != '.': + fall + | txt[i+1] != 'p' && txt[i+1] != 'P': + ret false + |: + ret true + } } fn isFloatFmtDotfp(&txt: []byte, i: int): bool { - match { - | len(txt) < 4: - fall - | txt[i] != '.': - fall - | txt[i+1] != 'f' && txt[i+1] != 'F': - fall - | txt[i+2] != 'p' && txt[i+1] != 'P': - ret false - |: - ret true - } + match { + | len(txt) < 4: + fall + | txt[i] != '.': + fall + | txt[i+1] != 'f' && txt[i+1] != 'F': + fall + | txt[i+2] != 'p' && txt[i+1] != 'P': + ret false + |: + ret true + } } fn octalNum(&txt: []byte): (lit: str) { - if txt[0] != '0' { - ret "" - } - if len(txt) < 2 { - ret - } - - mut octalStart := 1 - - mut o := false - if txt[1] == 'o' { - if len(txt) < 3 { - ret - } - octalStart++ - o = true - } - - mut i := octalStart - for i < len(txt); i++ { - b := txt[i] - if b == '.' { - if o { - ret "" - } - ret floatNum(txt, i) - } - if isFloatFmtE(b, i) { - ret floatFmtE(txt, i) - } - if b != '_' && !IsOctal(b) { - break - } - } - - if i == octalStart { - ret - } - ret str(txt[:i]) + if txt[0] != '0' { + ret "" + } + if len(txt) < 2 { + ret + } + + mut octalStart := 1 + + mut o := false + if txt[1] == 'o' { + if len(txt) < 3 { + ret + } + octalStart++ + o = true + } + + mut i := octalStart + for i < len(txt); i++ { + b := txt[i] + if b == '.' { + if o { + ret "" + } + ret floatNum(txt, i) + } + if isFloatFmtE(b, i) { + ret floatFmtE(txt, i) + } + if b != '_' && !IsOctal(b) { + break + } + } + + if i == octalStart { + ret + } + ret str(txt[:i]) } fn hexNum(&txt: []byte): (lit: str) { - if len(txt) < 3 { - ret - } - if txt[0] != '0' || (txt[1] != 'x' && txt[1] != 'X') { - ret - } - - const HexStart = 2 - mut i := HexStart + if len(txt) < 3 { + ret + } + if txt[0] != '0' || (txt[1] != 'x' && txt[1] != 'X') { + ret + } + + const HexStart = 2 + mut i := HexStart loop: - for i < len(txt); i++ { - b := txt[i] - match { - | isFloatFmtDotp(txt, i): - ret floatFmtDotp(txt, i) - | isFloatFmtDotfp(txt, i): - ret floatFmtDotfp(txt, i) - | isFloatFmtP(b, i): - ret floatFmtP(txt, i) - | isFloatFmtDotnp(txt, i): - ret floatFmtDotnp(txt, i) - | b != '_' && !IsHex(b): - break loop - } - } - - if i == HexStart { - ret - } - ret str(txt[:i]) + for i < len(txt); i++ { + b := txt[i] + match { + | isFloatFmtDotp(txt, i): + ret floatFmtDotp(txt, i) + | isFloatFmtDotfp(txt, i): + ret floatFmtDotfp(txt, i) + | isFloatFmtP(b, i): + ret floatFmtP(txt, i) + | isFloatFmtDotnp(txt, i): + ret floatFmtDotnp(txt, i) + | b != '_' && !IsHex(b): + break loop + } + } + + if i == HexStart { + ret + } + ret str(txt[:i]) } fn hexEscape(&txt: []byte, n: int): (seq: str) { - if len(txt) < n { - ret - } - - const HexStart = 2 - mut i := HexStart - for i < n; i++ { - if !IsHex(txt[i]) { - ret - } - } - - seq = str(txt[:n]) - ret + if len(txt) < n { + ret + } + + const HexStart = 2 + mut i := HexStart + for i < n; i++ { + if !IsHex(txt[i]) { + ret + } + } + + seq = str(txt[:n]) + ret } // Pattern (RegEx): ^\\U.{8} fn bigUnicodePointEscape(&txt: []byte): str { - ret hexEscape(txt, 10) + ret hexEscape(txt, 10) } // Pattern (RegEx): ^\\u.{4} fn littleUnicodePointEscape(&txt: []byte): str { - ret hexEscape(txt, 6) + ret hexEscape(txt, 6) } // Pattern (RegEx): ^\\x.. fn hexByteEscape(&txt: []byte): str { - ret hexEscape(txt, 4) + ret hexEscape(txt, 4) } // Patter (RegEx): ^\\[0-7]{3} fn byteEscape(&txt: []byte): (seq: str) { - if len(txt) < 4 { - ret - } - if !IsOctal(txt[1]) || !IsOctal(txt[2]) || !IsOctal(txt[3]) { - ret - } - ret str(txt[:4]) + if len(txt) < 4 { + ret + } + if !IsOctal(txt[1]) || !IsOctal(txt[2]) || !IsOctal(txt[3]) { + ret + } + ret str(txt[:4]) } struct lex { - mode: LexMode - tokens: []&Token - file: &File - pos: int - column: int - row: int - errors: []Log + mode: LexMode + tokens: []&Token + file: &File + pos: int + column: int + row: int + errors: []Log } impl lex { - fn pushErr(mut self, fmt: LogMsg, args: ...any) { - self.errors = append(self.errors, - makeErr(self.row, self.column, self.file, fmt, args...)) - } - - fn pushErrTok(mut self, &token: &Token, fmt: LogMsg) { - self.errors = append(self.errors, - makeErr(token.Row, token.Column, self.file, fmt)) - } - - // Lexs all source content. - fn lex(mut self) { - self.errors = nil - self.newLine() - for self.pos < len(self.file.Data) { - mut token := self.token() - if token.Id != TokenId.Na { - self.tokens = append(self.tokens, token) - } - } - } - - // Returns identifer if next token is identifer, - // returns empty string if not. - fn id(mut self, &ln: []byte): str { - if len(ln) == 0 { - ret "" - } - r, mut i := utf8::DecodeRune(ln) - if r != '_' && !IsLetter(r) { - ret "" - } - - for i < len(ln) { - pr, n := utf8::DecodeRune(ln[i:]) - if pr != '_' && !IsDecimal(byte(pr)) && !IsLetter(pr) { - self.pos += i - ret str(ln[:i]) - } - i += n - } - - self.pos += len(ln) - ret str(ln) - } - - // Resume to lex from position. - fn resume(mut self): []byte { - // Skip spaces. - mut i := self.pos - for i < len(self.file.Data); i++ { - r := rune(self.file.Data[i]) - if IsSpace(r) { - self.pos++ - match r { - | '\n': - self.newLine() - |: - self.column++ - } - continue - } - - mut j := i - for j < len(self.file.Data); j++ { - if self.file.Data[j] == '\n' { - break - } - } - ret self.file.Data[i:j] - } - ret nil - } - - fn lexLineComment(mut self, mut &token: &Token) { - start := self.pos - self.pos += 2 - for self.pos < len(self.file.Data); self.pos++ { - r := self.file.Data[self.pos] - if r == '\n' || r == '\r' { - break - } - } - if self.mode&LexMode.Comment == LexMode.Comment { - token.Id = TokenId.Comment - token.Kind = str(self.file.Data[start:self.pos]) - } - } - - fn lexRangeComment(mut self, mut &token: &Token) { - start := self.pos - self.pos += 2 - for self.pos < len(self.file.Data); self.pos++ { - r := self.file.Data[self.pos] - if r == '\r' { - continue - } - if r == '\n' { - self.newLine() - continue - } - self.column += 1 - if self.pos+1 < len(self.file.Data) && r == '*' && - self.file.Data[self.pos+1] == '/' { - self.column += 2 - self.pos += 2 - if self.mode&LexMode.Comment == LexMode.Comment { - token.Id = TokenId.Comment - token.Kind = str(self.file.Data[start:self.pos]) - } - ret - } - } - self.pushErr(LogMsg.MissingBlockCommentClose) - } - - // Returns literal if next token is numeric, returns empty string if not. - fn num(mut self, &txt: []byte): (lit: str) { - if txt[0] == '_' { - ret "" - } - lit = hexNum(txt) - if lit != "" { - goto end - } - lit = octalNum(txt) - if lit != "" { - goto end - } - lit = binaryNum(txt) - if lit != "" { - goto end - } - lit = commonNum(txt) - end: - self.pos += len(lit) - ret - } - - fn escapeSeq(mut self, &txt: []byte): str { - mut seq := "" - if len(txt) < 2 { - goto end - } - - match txt[1] { - | '\\' | '\'' | '"' | 'a' | 'b' | 'f' | 'n' | 'r' | 't' | 'v': - self.pos += 2 - ret str(txt[:2]) - | 'U': - seq = bigUnicodePointEscape(txt) - | 'u': - seq = littleUnicodePointEscape(txt) - | 'x': - seq = hexByteEscape(txt) - |: - seq = byteEscape(txt) - } - - end: - if seq == "" { - self.pos++ - self.pushErr(LogMsg.InvalidEscapeSeq) - ret "" - } - self.pos += len(seq) - ret seq - } - - fn getRune(mut self, &txt: []byte, raw: bool): str { - if !raw && txt[0] == '\\' { - ret self.escapeSeq(txt) - } - r, n := utf8::DecodeRune(txt) - self.pos += n - ret str(r) - } - - fn lexRune(mut self, &txt: []byte): str { - mut run := StrBuilder.New(1 << 3) - run.WriteByte('\'') - self.column++ - mut n := 0 - mut i := 1 - for i < len(txt); i++ { - if txt[i] == '\r' { - continue - } - if txt[i] == '\n' { - self.pushErr(LogMsg.MissingRuneEnd) - self.pos++ - self.newLine() - ret "" - } - - part := txt[i:] - r := self.getRune(part, false) - run.WriteStr(r) - self.column += utf8::RuneCountStr(r) - if r == "'" { - self.pos++ - break - } - if len(r) > 1 { - i += len(r) - 1 - } - n++ - } - - if n == 0 { - self.pushErr(LogMsg.RuneEmpty) - } else if n > 1 { - self.pushErr(LogMsg.RuneOverflow) - } - - ret run.Str() - } - - fn lexStr(mut self): str { - mut s := StrBuilder.New(1 << 4) - mark := self.file.Data[self.pos] - self.pos++ // Skip mark - raw := mark == '`' - s.WriteByte(mark) - self.column++ - - for self.pos < len(self.file.Data) { - ch := self.file.Data[self.pos] - if ch == '\r' { - continue - } - if ch == '\n' { - self.newLine() - if !raw { - self.pushErr(LogMsg.MissingStrEnd) - self.pos++ - ret "" - } - } - mut part := self.file.Data[self.pos:] - r := self.getRune(part, raw) - s.WriteStr(r) - self.column += utf8::RuneCountStr(r) - if ch == mark { - break - } - } - - ret s.Str() - } - - fn isFirstTokenOfLine(self): bool { - ret self.column == 1 - } - - fn newLine(mut self) { - self.row++ - self.column = 1 - } - - fn isOp(mut self, &txt: []byte, kind: str, id: TokenId, mut &t: &Token): bool { - if !bytesHasPrefix(txt, kind) { - ret false - } - t.Kind = kind - t.Id = id - self.pos += len(kind) - ret true - } - - fn lexBasicOps(mut self, txt: []byte, mut &tok: &Token): bool { - for _, pair in basicOps { - if self.isOp(txt, pair.kind, pair.id, tok) { - ret true - } - } - ret false - } - - fn lexId(mut self, &txt: []byte, mut &t: &Token): bool { - lex := self.id(txt) - if lex == "" { - ret false - } - t.Kind = lex - t.Id = TokenId.Ident - ret true - } - - fn lexNum(mut self, &txt: []byte, mut &t: &Token): bool { - lex := self.num(txt) - if lex == "" { - ret false - } - t.Kind = lex - t.Id = TokenId.Lit - ret true - } - - // lex.Token generates next token from resume at position. - fn token(mut self): &Token { - mut t := &Token{ - File: self.file, - Id: TokenId.Na, - } - - txt := self.resume() - if txt == nil { - ret t - } - - // Set token values. - t.Column = self.column - t.Row = self.row - - //* lex.Tokenenize - match { - | self.lexNum(txt, t): - // Pass. - break - | txt[0] == '\'': - t.Kind = self.lexRune(txt) - t.Id = TokenId.Lit - ret t - | txt[0] == '"' || txt[0] == '`': - t.Kind = self.lexStr() - t.Id = TokenId.Lit - ret t - | bytesHasPrefix(txt, TokenKind.LnComment): - self.lexLineComment(t) - ret t - | bytesHasPrefix(txt, TokenKind.RangLComment): - self.lexRangeComment(t) - ret t - | self.lexBasicOps(txt, t): - // Pass. - break - | self.lexId(txt, t): - for _, pair in keywords { - if pair.kind == t.Kind { - t.Id = pair.id - break - } - } - |: - r, sz := utf8::DecodeRune(txt) - self.pushErr(LogMsg.InvalidToken, r) - self.column++ - self.pos += sz - ret t - } - self.column += utf8::RuneCountStr(t.Kind) - ret t - } + fn pushErr(mut self, fmt: LogMsg, args: ...any) { + self.errors = append(self.errors, + makeErr(self.row, self.column, self.file, fmt, args...)) + } + + fn pushErrTok(mut self, &token: &Token, fmt: LogMsg) { + self.errors = append(self.errors, + makeErr(token.Row, token.Column, self.file, fmt)) + } + + // Lexs all source content. + fn lex(mut self) { + self.errors = nil + self.newLine() + for self.pos < len(self.file.Data) { + mut token := self.token() + if token.Id != TokenId.Na { + self.tokens = append(self.tokens, token) + } + } + } + + // Returns identifer if next token is identifer, + // returns empty string if not. + fn id(mut self, &ln: []byte): str { + if len(ln) == 0 { + ret "" + } + r, mut i := utf8::DecodeRune(ln) + if r != '_' && !IsLetter(r) { + ret "" + } + + for i < len(ln) { + pr, n := utf8::DecodeRune(ln[i:]) + if pr != '_' && !IsDecimal(byte(pr)) && !IsLetter(pr) { + self.pos += i + ret str(ln[:i]) + } + i += n + } + + self.pos += len(ln) + ret str(ln) + } + + // Resume to lex from position. + fn resume(mut self): []byte { + // Skip spaces. + mut i := self.pos + for i < len(self.file.Data); i++ { + r := rune(self.file.Data[i]) + if IsSpace(r) { + self.pos++ + match r { + | '\n': + self.newLine() + |: + self.column++ + } + continue + } + + mut j := i + for j < len(self.file.Data); j++ { + if self.file.Data[j] == '\n' { + break + } + } + ret self.file.Data[i:j] + } + ret nil + } + + fn lexLineComment(mut self, mut &token: &Token) { + start := self.pos + self.pos += 2 + for self.pos < len(self.file.Data); self.pos++ { + r := self.file.Data[self.pos] + if r == '\n' || r == '\r' { + break + } + } + if self.mode&LexMode.Comment == LexMode.Comment { + token.Id = TokenId.Comment + token.Kind = str(self.file.Data[start:self.pos]) + } + } + + fn lexRangeComment(mut self, mut &token: &Token) { + start := self.pos + self.pos += 2 + for self.pos < len(self.file.Data); self.pos++ { + r := self.file.Data[self.pos] + if r == '\r' { + continue + } + if r == '\n' { + self.newLine() + continue + } + self.column += 1 + if self.pos+1 < len(self.file.Data) && r == '*' && + self.file.Data[self.pos+1] == '/' { + self.column += 2 + self.pos += 2 + if self.mode&LexMode.Comment == LexMode.Comment { + token.Id = TokenId.Comment + token.Kind = str(self.file.Data[start:self.pos]) + } + ret + } + } + self.pushErr(LogMsg.MissingBlockCommentClose) + } + + // Returns literal if next token is numeric, returns empty string if not. + fn num(mut self, &txt: []byte): (lit: str) { + if txt[0] == '_' { + ret "" + } + lit = hexNum(txt) + if lit != "" { + goto end + } + lit = octalNum(txt) + if lit != "" { + goto end + } + lit = binaryNum(txt) + if lit != "" { + goto end + } + lit = commonNum(txt) + end: + self.pos += len(lit) + ret + } + + fn escapeSeq(mut self, &txt: []byte): str { + mut seq := "" + if len(txt) < 2 { + goto end + } + + match txt[1] { + | '\\' | '\'' | '"' | 'a' | 'b' | 'f' | 'n' | 'r' | 't' | 'v': + self.pos += 2 + ret str(txt[:2]) + | 'U': + seq = bigUnicodePointEscape(txt) + | 'u': + seq = littleUnicodePointEscape(txt) + | 'x': + seq = hexByteEscape(txt) + |: + seq = byteEscape(txt) + } + + end: + if seq == "" { + self.pos++ + self.pushErr(LogMsg.InvalidEscapeSeq) + ret "" + } + self.pos += len(seq) + ret seq + } + + fn getRune(mut self, &txt: []byte, raw: bool): str { + if !raw && txt[0] == '\\' { + ret self.escapeSeq(txt) + } + r, n := utf8::DecodeRune(txt) + self.pos += n + ret str(r) + } + + fn lexRune(mut self, &txt: []byte): str { + mut run := StrBuilder.New(1 << 3) + run.WriteByte('\'') + self.column++ + mut n := 0 + mut i := 1 + for i < len(txt); i++ { + if txt[i] == '\r' { + continue + } + if txt[i] == '\n' { + self.pushErr(LogMsg.MissingRuneEnd) + self.pos++ + self.newLine() + ret "" + } + + part := txt[i:] + r := self.getRune(part, false) + run.WriteStr(r) + self.column += utf8::RuneCountStr(r) + if r == "'" { + self.pos++ + break + } + if len(r) > 1 { + i += len(r) - 1 + } + n++ + } + + if n == 0 { + self.pushErr(LogMsg.RuneEmpty) + } else if n > 1 { + self.pushErr(LogMsg.RuneOverflow) + } + + ret run.Str() + } + + fn lexStr(mut self): str { + mut s := StrBuilder.New(1 << 4) + mark := self.file.Data[self.pos] + self.pos++ // Skip mark + raw := mark == '`' + s.WriteByte(mark) + self.column++ + + for self.pos < len(self.file.Data) { + ch := self.file.Data[self.pos] + if ch == '\r' { + continue + } + if ch == '\n' { + self.newLine() + if !raw { + self.pushErr(LogMsg.MissingStrEnd) + self.pos++ + ret "" + } + } + mut part := self.file.Data[self.pos:] + r := self.getRune(part, raw) + s.WriteStr(r) + self.column += utf8::RuneCountStr(r) + if ch == mark { + break + } + } + + ret s.Str() + } + + fn isFirstTokenOfLine(self): bool { + ret self.column == 1 + } + + fn newLine(mut self) { + self.row++ + self.column = 1 + } + + fn isOp(mut self, &txt: []byte, kind: str, id: TokenId, mut &t: &Token): bool { + if !bytesHasPrefix(txt, kind) { + ret false + } + t.Kind = kind + t.Id = id + self.pos += len(kind) + ret true + } + + fn lexBasicOps(mut self, txt: []byte, mut &tok: &Token): bool { + for _, pair in basicOps { + if self.isOp(txt, pair.kind, pair.id, tok) { + ret true + } + } + ret false + } + + fn lexId(mut self, &txt: []byte, mut &t: &Token): bool { + lex := self.id(txt) + if lex == "" { + ret false + } + t.Kind = lex + t.Id = TokenId.Ident + ret true + } + + fn lexNum(mut self, &txt: []byte, mut &t: &Token): bool { + lex := self.num(txt) + if lex == "" { + ret false + } + t.Kind = lex + t.Id = TokenId.Lit + ret true + } + + // lex.Token generates next token from resume at position. + fn token(mut self): &Token { + mut t := &Token{ + File: self.file, + Id: TokenId.Na, + } + + txt := self.resume() + if txt == nil { + ret t + } + + // Set token values. + t.Column = self.column + t.Row = self.row + + //* lex.Tokenenize + match { + | self.lexNum(txt, t): + // Pass. + break + | txt[0] == '\'': + t.Kind = self.lexRune(txt) + t.Id = TokenId.Lit + ret t + | txt[0] == '"' || txt[0] == '`': + t.Kind = self.lexStr() + t.Id = TokenId.Lit + ret t + | bytesHasPrefix(txt, TokenKind.LnComment): + self.lexLineComment(t) + ret t + | bytesHasPrefix(txt, TokenKind.RangLComment): + self.lexRangeComment(t) + ret t + | self.lexBasicOps(txt, t): + // Pass. + break + | self.lexId(txt, t): + for _, pair in keywords { + if pair.kind == t.Kind { + t.Id = pair.id + break + } + } + |: + r, sz := utf8::DecodeRune(txt) + self.pushErr(LogMsg.InvalidToken, r) + self.column++ + self.pos += sz + ret t + } + self.column += utf8::RuneCountStr(t.Kind) + ret t + } } // Lex source code into fileset. // Returns nil if f == nil. // Returns nil slice for errors if no any error. fn Lex(mut f: &File, mode: LexMode): []Log { - if f == nil { - ret nil - } - - mut lex := lex{ - mode: mode, - file: f, - pos: 0, - row: -1, // For true row - } - - lex.newLine() - lex.lex() - - if len(lex.errors) > 0 { - ret lex.errors - } - - f.Tokens = lex.tokens - ret nil + if f == nil { + ret nil + } + + mut lex := lex{ + mode: mode, + file: f, + pos: 0, + row: -1, // For true row + } + + lex.newLine() + lex.lex() + + if len(lex.errors) > 0 { + ret lex.errors + } + + f.Tokens = lex.tokens + ret nil } \ No newline at end of file diff --git a/std/jule/lex/token.jule b/std/jule/lex/token.jule index 864e2ca8b..6850ecaf3 100644 --- a/std/jule/lex/token.jule +++ b/std/jule/lex/token.jule @@ -9,355 +9,355 @@ use strings for std::strings // Punctuations. static Puncts: [...]rune = [ - '!', - '#', - '$', - ',', - '.', - '\'', - '"', - ':', - ';', - '<', - '>', - '=', - '?', - '-', - '+', - '*', - '(', - ')', - '[', - ']', - '{', - '}', - '%', - '&', - '/', - '\\', - '@', - '^', - '_', - '`', - '|', - '~', - '¦', + '!', + '#', + '$', + ',', + '.', + '\'', + '"', + ':', + ';', + '<', + '>', + '=', + '?', + '-', + '+', + '*', + '(', + ')', + '[', + ']', + '{', + '}', + '%', + '&', + '/', + '\\', + '@', + '^', + '_', + '`', + '|', + '~', + '¦', ] // Space characters. static Spaces: [...]rune = [ - ' ', - '\t', - '\v', - '\r', - '\n', + ' ', + '\t', + '\v', + '\r', + '\n', ] // Kind list of unary operators. static UnaryOps: [...]TokenId = [ - TokenId.Minus, - TokenId.Plus, - TokenId.Caret, - TokenId.Excl, - TokenId.Star, - TokenId.Amper, + TokenId.Minus, + TokenId.Plus, + TokenId.Caret, + TokenId.Excl, + TokenId.Star, + TokenId.Amper, ] // Kind list of binary operators. static BinOps: [...]TokenId = [ - TokenId.Plus, - TokenId.Minus, - TokenId.Star, - TokenId.Solidus, - TokenId.Percent, - TokenId.Amper, - TokenId.Vline, - TokenId.Caret, - TokenId.Shl, - TokenId.Shr, - TokenId.Lt, - TokenId.Gt, - TokenId.LtEq, - TokenId.GtEq, - TokenId.DblAmper, - TokenId.DblVline, - TokenId.Eqs, - TokenId.NotEq, + TokenId.Plus, + TokenId.Minus, + TokenId.Star, + TokenId.Solidus, + TokenId.Percent, + TokenId.Amper, + TokenId.Vline, + TokenId.Caret, + TokenId.Shl, + TokenId.Shr, + TokenId.Lt, + TokenId.Gt, + TokenId.LtEq, + TokenId.GtEq, + TokenId.DblAmper, + TokenId.DblVline, + TokenId.Eqs, + TokenId.NotEq, ] // Kind list of weak operators. // These operators are weak, can used as part of expression. static WeakOps: [...]TokenId = [ - TokenId.TripleDot, - TokenId.Colon, + TokenId.TripleDot, + TokenId.Colon, ] // List of postfix operators. static PostfixOps: [...]TokenId = [ - TokenId.DblPlus, - TokenId.DblMinus, + TokenId.DblPlus, + TokenId.DblMinus, ] // List of assign operators. static AssignOps: [...]TokenId = [ - TokenId.Eq, - TokenId.PlusEq, - TokenId.MinusEq, - TokenId.SolidusEq, - TokenId.StarEq, - TokenId.PercentEq, - TokenId.ShrEq, - TokenId.ShlEq, - TokenId.VlineEq, - TokenId.AmperEq, - TokenId.CaretEq, + TokenId.Eq, + TokenId.PlusEq, + TokenId.MinusEq, + TokenId.SolidusEq, + TokenId.StarEq, + TokenId.PercentEq, + TokenId.ShrEq, + TokenId.ShlEq, + TokenId.VlineEq, + TokenId.AmperEq, + TokenId.CaretEq, ] // Special identifiers. enum Ident: str { - Ignore: "_", // Ignore - Anon: "", // Anonymous + Ignore: "_", // Ignore + Anon: "", // Anonymous } // Token identities. enum TokenId: uint { - Na, - Ident, - Ret, - Semicolon, - Lit, - Comma, - Const, - Type, - Colon, - For, - Break, - Cont, - In, - If, - Else, - Comment, - Use, - Dot, - Goto, - DblColon, - Enum, - Struct, - Co, - Match, - Self, - Trait, - Impl, - Cpp, - Fall, - Fn, - Let, - Unsafe, - Mut, - Defer, - Static, - Hash, - Error, - Map, - ColonEq, - TripleDot, - PlusEq, - MinusEq, - StarEq, - SolidusEq, - PercentEq, - ShlEq, - ShrEq, - CaretEq, - AmperEq, - VlineEq, - Eqs, - NotEq, - GtEq, - LtEq, - DblAmper, - DblVline, - Shl, - Shr, - DblPlus, - DblMinus, - Plus, - Minus, - Star, - Solidus, - Percent, - Amper, - Vline, - Caret, - Excl, - Lt, - Gt, - Eq, - LBrace, - RBrace, - LParent, - RParent, - LBracket, - RBracket, + Na, + Ident, + Ret, + Semicolon, + Lit, + Comma, + Const, + Type, + Colon, + For, + Break, + Cont, + In, + If, + Else, + Comment, + Use, + Dot, + Goto, + DblColon, + Enum, + Struct, + Co, + Match, + Self, + Trait, + Impl, + Cpp, + Fall, + Fn, + Let, + Unsafe, + Mut, + Defer, + Static, + Hash, + Error, + Map, + ColonEq, + TripleDot, + PlusEq, + MinusEq, + StarEq, + SolidusEq, + PercentEq, + ShlEq, + ShrEq, + CaretEq, + AmperEq, + VlineEq, + Eqs, + NotEq, + GtEq, + LtEq, + DblAmper, + DblVline, + Shl, + Shr, + DblPlus, + DblMinus, + Plus, + Minus, + Star, + Solidus, + Percent, + Amper, + Vline, + Caret, + Excl, + Lt, + Gt, + Eq, + LBrace, + RBrace, + LParent, + RParent, + LBracket, + RBracket, } // Token kinds. enum TokenKind: str { - DblColon: "::", - Colon: ":", - Semicolon: ";", - Comma: ",", - TripleDot: "...", - Dot: ".", - PlusEq: "+=", - MinusEq: "-=", - StarEq: "*=", - SolidusEq: "/=", - PercentEq: "%=", - ShlEq: "<<=", - ShrEq: ">>=", - CaretEq: "^=", - AmperEq: "&=", - VlineEq: "|=", - Eqs: "==", - NotEq: "!=", - GtEq: ">=", - LtEq: "<=", - DblAmper: "&&", - DblVline: "||", - Shl: "<<", - Shr: ">>", - DblPlus: "++", - DblMinus: "--", - Plus: "+", - Minus: "-", - Star: "*", - Solidus: "/", - Percent: "%", - Amper: "&", - Vline: "|", - Caret: "^", - Excl: "!", - Lt: "<", - Gt: ">", - Eq: "=", - ColonEq: ":=", - LnComment: "//", - RangLComment: "/*", - RangRComment: "*/", - LParent: "(", - RParent: ")", - LBracket: "[", - RBracket: "]", - LBrace: "{", - RBrace: "}", - Hash: "#", - Const: "const", - Ret: "ret", - Type: "type", - For: "for", - Break: "break", - Cont: "continue", - In: "in", - If: "if", - Else: "else", - Use: "use", - Goto: "goto", - Enum: "enum", - Struct: "struct", - Co: "co", - Match: "match", - Self: "self", - Trait: "trait", - Impl: "impl", - Cpp: "cpp", - Fall: "fall", - Fn: "fn", - Let: "let", - Unsafe: "unsafe", - Mut: "mut", - Defer: "defer", - Static: "static", - Error: "error", - Map: "map", + DblColon: "::", + Colon: ":", + Semicolon: ";", + Comma: ",", + TripleDot: "...", + Dot: ".", + PlusEq: "+=", + MinusEq: "-=", + StarEq: "*=", + SolidusEq: "/=", + PercentEq: "%=", + ShlEq: "<<=", + ShrEq: ">>=", + CaretEq: "^=", + AmperEq: "&=", + VlineEq: "|=", + Eqs: "==", + NotEq: "!=", + GtEq: ">=", + LtEq: "<=", + DblAmper: "&&", + DblVline: "||", + Shl: "<<", + Shr: ">>", + DblPlus: "++", + DblMinus: "--", + Plus: "+", + Minus: "-", + Star: "*", + Solidus: "/", + Percent: "%", + Amper: "&", + Vline: "|", + Caret: "^", + Excl: "!", + Lt: "<", + Gt: ">", + Eq: "=", + ColonEq: ":=", + LnComment: "//", + RangLComment: "/*", + RangRComment: "*/", + LParent: "(", + RParent: ")", + LBracket: "[", + RBracket: "]", + LBrace: "{", + RBrace: "}", + Hash: "#", + Const: "const", + Ret: "ret", + Type: "type", + For: "for", + Break: "break", + Cont: "continue", + In: "in", + If: "if", + Else: "else", + Use: "use", + Goto: "goto", + Enum: "enum", + Struct: "struct", + Co: "co", + Match: "match", + Self: "self", + Trait: "trait", + Impl: "impl", + Cpp: "cpp", + Fall: "fall", + Fn: "fn", + Let: "let", + Unsafe: "unsafe", + Mut: "mut", + Defer: "defer", + Static: "static", + Error: "error", + Map: "map", } // Token is lexer token. struct Token { - File: &File - Row: int - Column: int - Kind: str - Id: TokenId + File: &File + Row: int + Column: int + Kind: str + Id: TokenId } impl Token { - // Returns operator precedence of token. - // Returns 0 if token is not operator or - // invalid operator for operator precedence. - // - // Accepts assignment tokens (like equals [=]) as precedenced operator - // to handle expression assignments. - fn Prec(self): byte { - match self.Id { - | TokenId.Star - | TokenId.Percent - | TokenId.Solidus - | TokenId.Shr - | TokenId.Shl - | TokenId.Amper: - ret 5 - | TokenId.Plus - | TokenId.Minus - | TokenId.Vline - | TokenId.Caret: - ret 4 - | TokenId.Eqs - | TokenId.NotEq - | TokenId.Eq - | TokenId.Lt - | TokenId.LtEq - | TokenId.Gt - | TokenId.GtEq: - ret 3 - | TokenId.DblAmper: - ret 2 - | TokenId.DblVline: - ret 1 - |: - ret 0 - } - } + // Returns operator precedence of token. + // Returns 0 if token is not operator or + // invalid operator for operator precedence. + // + // Accepts assignment tokens (like equals [=]) as precedenced operator + // to handle expression assignments. + fn Prec(self): byte { + match self.Id { + | TokenId.Star + | TokenId.Percent + | TokenId.Solidus + | TokenId.Shr + | TokenId.Shl + | TokenId.Amper: + ret 5 + | TokenId.Plus + | TokenId.Minus + | TokenId.Vline + | TokenId.Caret: + ret 4 + | TokenId.Eqs + | TokenId.NotEq + | TokenId.Eq + | TokenId.Lt + | TokenId.LtEq + | TokenId.Gt + | TokenId.GtEq: + ret 3 + | TokenId.DblAmper: + ret 2 + | TokenId.DblVline: + ret 1 + |: + ret 0 + } + } } // Reports whether kind is unary operator. fn IsUnaryOp(id: TokenId): bool { - for _, op in UnaryOps { - if id == op { - ret true - } - } - ret false + for _, op in UnaryOps { + if id == op { + ret true + } + } + ret false } // Reports whether kind is binary operator. fn IsBinOp(id: TokenId): bool { - for _, op in BinOps { - if id == op { - ret true - } - } - ret false + for _, op in BinOps { + if id == op { + ret true + } + } + ret false } // Reports whether kind is weak operator. fn IsWeakOp(id: TokenId): bool { - for _, op in WeakOps { - if id == op { - ret true - } - } - ret false + for _, op in WeakOps { + if id == op { + ret true + } + } + ret false } // Reports whether kind is string literal. @@ -378,25 +378,25 @@ fn IsBool(k: str): bool { ret k == "true" || k == "false" } // Reports whether kind is float. fn IsFloat(k: str): bool { - if strings::HasPrefix(k, "0x") { - ret strings::ContainsAny(k, ".pP") - } - ret strings::ContainsAny(k, ".eE") + if strings::HasPrefix(k, "0x") { + ret strings::ContainsAny(k, ".pP") + } + ret strings::ContainsAny(k, ".eE") } // Reports whether kind is numeric. fn IsNum(k: str): bool { - if k == "" { - ret false - } + if k == "" { + ret false + } - b := k[0] - ret b == '.' || ('0' <= b && b <= '9') + b := k[0] + ret b == '.' || ('0' <= b && b <= '9') } // Reports whether kind is literal. fn IsLit(k: str): bool { - ret IsNum(k) || IsStr(k) || IsRune(k) || IsNil(k) || IsBool(k) + ret IsNum(k) || IsStr(k) || IsRune(k) || IsNil(k) || IsBool(k) } // Reports whether identifier is ignore. @@ -407,42 +407,42 @@ fn IsAnonIdent(ident: str): bool { ret ident == Ident.Anon } // Reports whether rune is punctuation. fn IsPunct(r: rune): bool { - for _, cr in Puncts { - if r == cr { - ret true - } - } - ret false + for _, cr in Puncts { + if r == cr { + ret true + } + } + ret false } // Reports wheter byte is whitespace. fn IsSpace(r: rune): bool { - for _, cr in Spaces { - if r == cr { - ret true - } - } - ret false + for _, cr in Spaces { + if r == cr { + ret true + } + } + ret false } // Reports whether rune is letter. fn IsLetter(r: rune): bool { - ret unicode::IsLetter(r) + ret unicode::IsLetter(r) } // Reports whether firs rune of string is allowed // to first rune for identifier. fn IsIdentRune(s: str): bool { - if s == "" { - ret false - } - if s[0] != '_' { - r, _ := utf8::DecodeRuneStr(s) - if !IsLetter(r) { - ret false - } - } - ret true + if s == "" { + ret false + } + if s[0] != '_' { + r, _ := utf8::DecodeRuneStr(s) + if !IsLetter(r) { + ret false + } + } + ret true } // Reports whether byte is decimal sequence. @@ -456,50 +456,50 @@ fn IsOctal(b: byte): bool { ret '0' <= b && b <= '7' } // Reports whether byte is hexadecimal sequence. fn IsHex(b: byte): bool { - match { - | '0' <= b && b <= '9': - ret true - | 'a' <= b && b <= 'f': - ret true - | 'A' <= b && b <= 'F': - ret true - |: - ret false - } + match { + | '0' <= b && b <= '9': + ret true + | 'a' <= b && b <= 'f': + ret true + | 'A' <= b && b <= 'F': + ret true + |: + ret false + } } // Reports given token id is allow for // assignment left-expression or not. fn IsAssign(id: TokenId): bool { - ret (id == TokenId.Ident || - id == TokenId.Cpp || - id == TokenId.Let || - id == TokenId.Mut || - id == TokenId.Self || - id == TokenId.LParent || - id == TokenId.Star || - id == TokenId.Amper) + ret (id == TokenId.Ident || + id == TokenId.Cpp || + id == TokenId.Let || + id == TokenId.Mut || + id == TokenId.Self || + id == TokenId.LParent || + id == TokenId.Star || + id == TokenId.Amper) } // Reports whether operator kind is postfix operator. fn IsPostfixOp(id: TokenId): bool { - for _, op in PostfixOps { - if id == op { - ret true - } - } - ret false + for _, op in PostfixOps { + if id == op { + ret true + } + } + ret false } // Reports whether operator kind is assignment operator. fn IsAssignOp(id: TokenId): bool { - if IsPostfixOp(id) { - ret true - } - for _, op in AssignOps { - if id == op { - ret true - } - } - ret false + if IsPostfixOp(id) { + ret true + } + for _, op in AssignOps { + if id == op { + ret true + } + } + ret false } \ No newline at end of file diff --git a/std/jule/parser/assign.jule b/std/jule/parser/assign.jule index ad47cda11..9309dd69b 100644 --- a/std/jule/parser/assign.jule +++ b/std/jule/parser/assign.jule @@ -6,37 +6,37 @@ use std::jule::lex::{Token, TokenId, TokenKind, IsAssign, IsAssignOp} // Assignment information. struct assignInfo { - l: []&Token - r: []&Token - setter: &Token - ok: bool + l: []&Token + r: []&Token + setter: &Token + ok: bool } // Checks assignment tokens and whether reports is ok or not. fn checkAssignTokens(&tokens: []&Token): bool { - if len(tokens) == 0 || !IsAssign(tokens[0].Id) { - ret false - } - mut braceN := 0 - for _, t in tokens { - match t.Id { - | TokenId.LBrace - | TokenId.LBracket - | TokenId.LParent: - braceN++ - | TokenId.RBrace - | TokenId.RBracket - | TokenId.RParent: - braceN-- - } - match { - | braceN < 0: - ret false - | braceN > 0: - continue - | IsAssignOp(t.Id) | t.Id == TokenId.ColonEq: - ret true - } - } - ret false + if len(tokens) == 0 || !IsAssign(tokens[0].Id) { + ret false + } + mut braceN := 0 + for _, t in tokens { + match t.Id { + | TokenId.LBrace + | TokenId.LBracket + | TokenId.LParent: + braceN++ + | TokenId.RBrace + | TokenId.RBracket + | TokenId.RParent: + braceN-- + } + match { + | braceN < 0: + ret false + | braceN > 0: + continue + | IsAssignOp(t.Id) | t.Id == TokenId.ColonEq: + ret true + } + } + ret false } \ No newline at end of file diff --git a/std/jule/parser/expr.jule b/std/jule/parser/expr.jule index bce2ac5ed..be770d21d 100644 --- a/std/jule/parser/expr.jule +++ b/std/jule/parser/expr.jule @@ -3,1113 +3,1113 @@ // license that can be found in the LICENSE file. use std::jule::ast::{ - IdentExpr, - TupleExpr, - ExprData, - LitExpr, - TypeDecl, - UnaryExpr, - SubIdentExpr, - NsSelectionExpr, - VariadicExpr, - CastExpr, - Expr, - FnCallExpr, - UnsafeExpr, - FnDecl, - FieldExprPair, - StructLit, - KeyValPair, - BraceLit, - SliceExpr, - IndexingExpr, - SlicingExpr, - BinaryExpr, - ScopeTree, - RangeExpr, + IdentExpr, + TupleExpr, + ExprData, + LitExpr, + TypeDecl, + UnaryExpr, + SubIdentExpr, + NsSelectionExpr, + VariadicExpr, + CastExpr, + Expr, + FnCallExpr, + UnsafeExpr, + FnDecl, + FieldExprPair, + StructLit, + KeyValPair, + BraceLit, + SliceExpr, + IndexingExpr, + SlicingExpr, + BinaryExpr, + ScopeTree, + RangeExpr, } use std::jule::build::{LogMsg} use std::jule::lex::{ - Token, - TokenId, - TokenKind, - IsUnaryOp, - IsBinOp, + Token, + TokenId, + TokenKind, + IsUnaryOp, + IsBinOp, } struct exprBuilder { - p: &parser + p: &parser } impl exprBuilder { - fn pushErr(mut self, token: &Token, fmt: LogMsg, args: ...any) { - self.p.pushErr(token, fmt, args...) - } - - // Push suggestion to last log. - fn pushSuggestion(mut self, fmt: LogMsg, args: ...any) { - self.p.pushSuggestion(fmt, args...) - } - - fn buildTuple(mut self, mut &parts: [][]&Token): &TupleExpr { - mut tuple := &TupleExpr{ - Expr: make([]&Expr, 0, len(parts)), - } - for (_, mut part) in parts { - tuple.Expr = append(tuple.Expr, self.buildFromTokens(part)) - } - ret tuple - } - - fn buildLit(self, mut token: &Token): &LitExpr { - ret &LitExpr{ - Token: token, - Value: token.Kind, - } - } - - fn buildPrimitiveType(self, mut &token: &Token): &TypeDecl { - ret buildPrimType(token) - } - - fn buildSingle(mut self, mut token: &Token): ExprData { - match token.Id { - | TokenId.Lit: - ret self.buildLit(token) - | TokenId.TripleDot: - ret &VariadicExpr{ - Token: token, - } - | TokenId.Ident - | TokenId.Self - | TokenId.Error: - ret buildIdentExpr(token) - } - self.pushErr(token, LogMsg.InvalidSyntax) - ret nil - } - - fn buildBindIdent(mut self, mut &tokens: []&Token): &IdentExpr { - if tokens[0].Id != TokenId.Cpp { - ret nil - } else if tokens[1].Id != TokenId.Dot { - self.pushErr(tokens[1], LogMsg.InvalidSyntax) - self.pushSuggestion(LogMsg.ExpectedDotForBind) - ret nil - } - mut token := tokens[2] - if token.Id != TokenId.Ident { - self.pushErr(tokens[2], LogMsg.InvalidSyntax) - self.pushSuggestion(LogMsg.ExpectedIdentifier) - ret nil - } - mut expr := buildIdentExpr(token) - expr.Binded = true - ret expr - } - - fn buildUnary(mut self, mut tokens: []&Token): &UnaryExpr { - mut op := tokens[0] - if len(tokens) == 1 { - self.pushErr(op, LogMsg.MissingExprForUnary) - ret nil - } else if !IsUnaryOp(op.Id) { - self.pushErr(op, LogMsg.InvalidOpForUnary, op.Kind) - ret nil - } - - // Length is 1 cause all length of operator tokens is 1. - // Change "1" with length of token's value - // if all operators length is not 1. - tokens = tokens[1:] - - ret &UnaryExpr{ - Op: op, - Expr: self.buildFromTokens(tokens), - } - } - - fn buildObjSubIdent(mut self, mut tokens: []&Token): &SubIdentExpr { - mut i := len(tokens) - 1 - mut identToken := tokens[i] - i-- // Set offset to delimiter token. - tokens = tokens[:i] // Remove dot token and selected identifier token. - if len(tokens) == 0 { - self.pushErr(identToken, LogMsg.InvalidSyntax) - ret nil - } - ret &SubIdentExpr{ - Ident: identToken, - Expr: self.buildFromTokens(tokens), - } - } - - fn buildNsSubIdent(mut self, mut &tokens: []&Token): &NsSelectionExpr { - mut ns := new(NsSelectionExpr) - if len(tokens) == 3 && tokens[0].Id == TokenId.Unsafe { - // Check unsafe scope selection. - ns.Ns = tokens[:1] - ns.Ident = tokens[2] - } else { - for (i, mut token) in tokens { - if i%2 == 0 { - if token.Id != TokenId.Ident { - self.pushErr(token, LogMsg.InvalidSyntax) - self.pushSuggestion(LogMsg.ExpectedIdentifier) - } - ns.Ns = append(ns.Ns, token) - } else if token.Id != TokenId.DblColon { - self.pushErr(token, LogMsg.InvalidSyntax) - self.pushSuggestion(LogMsg.ExpectedDblColon) - } - } - ns.Ident = ns.Ns[len(ns.Ns)-1] - ns.Ns = ns.Ns[:len(ns.Ns)-1] - } - ret ns - } - - fn buildType(mut self, mut &tokens: []&Token): &TypeDecl { - mut i := 0 - mut t, ok := unsafe { self.p.buildType(tokens, &i, false) } - if !ok { - self.pushErr(tokens[0], LogMsg.InvalidSyntax) - ret nil - } - - if i < len(tokens) { - self.pushErr(tokens[i], LogMsg.InvalidSyntax) - } - ret t - } - - fn buildSubIdent(mut self, mut &tokens: []&Token): ExprData { - i := len(tokens) - 2 // Set offset to delimiter token. - token := tokens[i] - match token.Id { - | TokenId.Dot: - ret self.buildObjSubIdent(tokens) - | TokenId.DblColon: - ret self.buildNsSubIdent(tokens) - | TokenId.RBracket: - // Catch slice, array, and map types. - ret self.buildType(tokens) - } - - // Caught anonymous functions. - if isAnonFnHead(tokens) { - ret self.buildType(tokens) - } - - self.pushErr(token, LogMsg.InvalidSyntax) - ret nil - } - - fn buildVariadic(mut self, mut tokens: []&Token): &VariadicExpr { - mut token := tokens[len(tokens)-1] // Variadic operator token. - tokens = tokens[:len(tokens)-1] // Remove variadic operator token. - ret &VariadicExpr{ - Token: token, - Expr: self.buildFromTokens(tokens), - } - } - - fn buildBetweenParentheses(mut self, mut tokens: []&Token): &RangeExpr { - if len(tokens) == 2 { - self.pushErr(tokens[0], LogMsg.MissingExpr) - self.pushSuggestion(LogMsg.EmptyParentNotValid) - ret nil - } - tokens = tokens[1:len(tokens)-1] // Remove parentheses. - ret &RangeExpr{ - Expr: self.buildFromTokens(tokens), - } - } - - fn tryBuildCast(mut self, mut &tokens: []&Token): &CastExpr { - mut rangeN := 0 - for i, token in tokens { - match token.Id { - | TokenId.LBrace - | TokenId.LBracket - | TokenId.LParent: - rangeN++ - continue - | TokenId.RBrace - | TokenId.RBracket - | TokenId.RParent: - rangeN-- - } - - if rangeN > 0 { - continue - } else if i+1 == len(tokens) { - ret nil - } - - mut typeTokens := tokens[:i+1] - mut exprTokens := tokens[i+1:] - - if len(exprTokens) == 0 { - // Expression is parentheses group. - ret nil - } - - tok := exprTokens[0] - if tok.Id != TokenId.LParent { - ret nil - } - - mut cast := &CastExpr{} - - // Expression tokens just parentheses. - if len(exprTokens) == 2 { - self.pushErr(exprTokens[0], LogMsg.MissingExpr) - self.pushSuggestion(LogMsg.GiveExprToCast) - } - - // Type tokens just parentheses. - if len(typeTokens) == 2 { - self.pushErr(typeTokens[0], LogMsg.MissingType) - self.pushSuggestion(LogMsg.GiveTypeForCast) - } else { - typeTokens = typeTokens[1:len(typeTokens)-1] // Remove parentheses. - mut typeIndex := 0 - mut t, ok := unsafe { self.p.buildType(typeTokens, &typeIndex, true) } - if ok && typeIndex < len(typeTokens) { - self.pushErr(typeTokens[typeIndex], LogMsg.InvalidSyntax) - } else if !ok { - ret cast - } - cast.Kind = t - - if len(exprTokens) > 2 { - // Remove parentheses. - mut j := 0 - _ = range(j, TokenId.LParent, TokenId.RParent, exprTokens) - if j < len(exprTokens) { - ret nil - } - exprTokens = exprTokens[:j] - cast.Expr = self.buildFromTokens(exprTokens) - } - } - ret cast - } - - ret nil - } - - fn pushArg(mut self, mut &args: []&Expr, mut tokens: []&Token, err_token: &Token) { - if len(tokens) == 0 { - self.pushErr(err_token, LogMsg.InvalidSyntax) - self.pushSuggestion(LogMsg.ExpectedExpr) - ret - } - args = append(args, self.buildFromTokens(tokens)) - } - - fn buildArgs(mut self, mut tokens: []&Token): []&Expr { - // No argument. - if len(tokens) < 2 { - ret nil - } - - let mut args: []&Expr = nil - mut last := 0 - mut rangeN := 0 - tokens = tokens[1:len(tokens)-1] // Remove parentheses. - for i, token in tokens { - match token.Id { - | TokenId.LBrace - | TokenId.LBracket - | TokenId.LParent: - rangeN++ - | TokenId.RBrace - | TokenId.RBracket - | TokenId.RParent: - rangeN-- - } - if rangeN > 0 || token.Id != TokenId.Comma { - continue - } - self.pushArg(args, tokens[last:i], token) - last = i + 1 - } - - if last < len(tokens) { - if last == 0 { - if len(tokens) > 0 { - self.pushArg(args, tokens[last:], tokens[last]) - } - } else { - self.pushArg(args, tokens[last:], tokens[last-1]) - } - } - - ret args - } - - // Tokens should include brackets. - fn buildCallGenerics(mut self, mut tokens: []&Token): []&TypeDecl { - if len(tokens) == 0 { - ret nil - } - - tokens = tokens[1:len(tokens)-1] // Remove brackets. - mut parts, errs := parts(tokens, TokenId.Comma, true) - mut generics := make([]&TypeDecl, 0, len(parts)) - self.p.errors = append(self.p.errors, errs...) - for (_, mut part) in parts { - if len(part) == 0 { - continue - } - mut j := 0 - mut generic, _ := unsafe { self.p.buildType(part, &j, true) } - if j < len(part) { - self.pushErr(part[j], LogMsg.InvalidSyntax) - } - generics = append(generics, generic) - } - - ret generics - } - - fn buildFnCall(mut self, mut &token: &Token, mut &expr: []&Token, mut &args: []&Token): &FnCallExpr { - ret &FnCallExpr{ - Token: token, - Expr: self.buildFromTokens(expr), - Args: self.buildArgs(args), - } - } - - fn buildParenthesesRange(mut self, mut &tokens: []&Token): ExprData { - mut token := tokens[0] - if token.Id == TokenId.LParent { - mut expr := self.tryBuildCast(tokens) - if expr != nil { - ret expr - } - } - mut exprTokens, mut argsTokens := rangeLast(tokens) - // Expression is parentheses group if data.exprTokens is zero. - // data.args_tokens holds tokens of parentheses range (include parentheses). - if len(exprTokens) == 0 { - ret self.buildBetweenParentheses(argsTokens) - } - - // Caught anonymous function types. - if isAnonFnHead(exprTokens) { - ret self.buildType(tokens) - } - ret self.buildFnCall(token, exprTokens, argsTokens) - } - - fn buildUnsafeExpr(mut self, mut tokens: []&Token): &UnsafeExpr { - mut token := tokens[0] - tokens = tokens[1:] // Remove unsafe keyword. - mut i := 0 - mut rangeTokens := range(i, TokenId.LBrace, TokenId.RBrace, tokens) - if len(rangeTokens) == 0 { - self.pushErr(tokens[0], LogMsg.MissingExpr) - ret nil - } - ret &UnsafeExpr{ - Token: token, - Expr: self.buildFromTokens(rangeTokens), - } - } - - fn buildAnonFn(mut self, mut &tokens: []&Token): &FnDecl { - mut f := self.p.buildFn(tokens, false, false) - if !f.IsAnon() { - self.pushErr(f.Token, LogMsg.InvalidSyntax) - self.pushSuggestion(LogMsg.ExpectedAnonFn) - } - ret f - } - - fn buildUnsafe(mut self, mut &tokens: []&Token): ExprData { - match tokens[1].Id { - | TokenId.Fn: - // Unsafe anonymous function. - ret self.buildAnonFn(tokens) - |: - ret self.buildUnsafeExpr(tokens) - } - } - - fn pushRangeLitPart(mut self, mut part: []&Token, - errorToken: &Token, mut &parts: [][]&Token) { - if len(part) == 0 { - self.pushErr(errorToken, LogMsg.InvalidSyntax) - self.pushSuggestion(LogMsg.ExpectedExpr) - ret - } - parts = append(parts, part) - } - - // Tokens should include brace tokens. - fn getBraceRangeLitExprParts(mut self, mut tokens: []&Token): [][]&Token { - // No part. - if len(tokens) < 2 { - ret nil - } - - let mut parts: [][]&Token = nil - - mut last := 0 - mut rangeN := 0 - tokens = tokens[1:len(tokens)-1] // Remove parentheses. - for i, token in tokens { - match token.Id { - | TokenId.LBrace - | TokenId.LBracket - | TokenId.LParent: - rangeN++ - | TokenId.RBrace - | TokenId.RBracket - | TokenId.RParent: - rangeN-- - } - if rangeN > 0 || token.Id != TokenId.Comma { - continue - } - self.pushRangeLitPart(tokens[last:i], token, parts) - last = i + 1 - } - - if last < len(tokens) { - if last == 0 { - if len(tokens) > 0 { - self.pushRangeLitPart(tokens[last:], tokens[last], parts) - } - } else { - self.pushRangeLitPart(tokens[last:], tokens[last-1], parts) - } - } - - ret parts - } - - fn buildFieldExprPair(mut self, mut tokens: []&Token): &FieldExprPair { - if len(tokens)-2 == 0 { - self.pushErr(tokens[1], LogMsg.MissingExpr) - ret nil - } - mut pair := &FieldExprPair{ - Field: tokens[0], - } - tokens = tokens[2:] // Remove field identifier and colon tokens. - pair.Expr = self.buildFromTokens(tokens) - ret pair - } - - fn buildStructLitExpr(mut self, mut &tokens: []&Token): &Expr { - mut token := tokens[0] - if token.Id == TokenId.Ident && len(tokens) > 1 { - token = tokens[1] - if token.Id == TokenId.Colon { - ret &Expr{ - Token: token, - End: tokens[len(tokens)-1], - Kind: self.buildFieldExprPair(tokens), - } - } - } - ret self.buildFromTokens(tokens) - } - - fn buildStructLitExprs(mut self, mut &tokens: []&Token): []&Expr { - mut parts := self.getBraceRangeLitExprParts(tokens) - if len(parts) == 0 { - ret nil - } - - mut pairs := make([]&Expr, 0, len(parts)) - for (_, mut part) in parts { - pairs = append(pairs, self.buildStructLitExpr(part)) - } - ret pairs - } - - fn buildTypedStructLiteral(mut self, mut tokens: []&Token): &StructLit { - mut i := 0 - mut t, ok := unsafe { self.p.buildType(tokens, &i, true) } - if !ok { - ret nil - } else if i >= len(tokens) { - self.pushErr(tokens[i], LogMsg.InvalidSyntax) - ret nil - } - - tokens = tokens[i:] // Remove type tokens. - token := tokens[0] - if token.Id != TokenId.LBrace { - self.pushErr(token, LogMsg.InvalidSyntax) - ret nil - } - - ret &StructLit{ - End: tokens[len(tokens)-1], - Kind: t, - Exprs: self.buildStructLitExprs(tokens), - } - } - - fn buildBraceLitPart(mut self, mut &tokens: []&Token): &Expr { - mut l, mut r := splitDelim(tokens, TokenId.Colon) - // If left is not nil, colon token found. - if l != nil { - ret &Expr{ - Token: tokens[0], - End: tokens[len(tokens)-1], - Kind: &KeyValPair{ - Colon: tokens[len(l)], - Key: self.buildFromTokens(l), - Val: self.buildFromTokens(r), - }, - } - } - ret self.buildFromTokens(tokens) - } - - fn buildBraceLit(mut self, mut &tokens: []&Token): &BraceLit { - mut lit := &BraceLit{ - Token: tokens[0], - End: tokens[len(tokens)-1], - } - - mut parts := self.getBraceRangeLitExprParts(tokens) - if parts == nil { - ret lit - } - - lit.Exprs = make([]&Expr, 0, len(parts)) - for (_, mut part) in parts { - lit.Exprs = append(lit.Exprs, self.buildBraceLitPart(part)) - } - - ret lit - } - - fn buildBraceRange(mut self, mut &tokens: []&Token): ExprData { - mut exprTokens, rangeN := getRangeExprTokens(tokens) - - match { - | len(exprTokens) == 0: - ret self.buildBraceLit(tokens) - | rangeN > 0: - self.pushErr(tokens[0], LogMsg.InvalidSyntax) - ret nil - } - - // Exceptional handling. - elseToken := exprTokens[len(exprTokens)-1] - if exprTokens[len(exprTokens)-1].Id == TokenId.Else { - exprTokens = exprTokens[:len(exprTokens)-1] // Ignore keyword "else" - mut d := self.build(exprTokens) - if d == nil { - ret nil - } - match type d { - | &FnCallExpr: - tokens = tokens[len(exprTokens)+1:] // Get range: {...} - mut i := 0 - mut rangeTokens := range(i, TokenId.LBrace, TokenId.RBrace, tokens) - mut model := (&FnCallExpr)(d) - if model.Ignored() { - self.pushErr(elseToken, LogMsg.InvalidSyntax) - self.pushSuggestion(LogMsg.JustIgnoreOrHandle) - } - model.Exception = self.p.buildScope(rangeTokens, tokens[i-1]) - ret d - |: - self.pushErr(exprTokens[0], LogMsg.InvalidSyntax) - ret nil - } - } - - match exprTokens[0].Id { - | TokenId.Unsafe: - ret self.buildUnsafe(tokens) - | TokenId.Fn: - ret self.buildAnonFn(tokens) - | TokenId.Ident - | TokenId.Cpp: - ret self.buildTypedStructLiteral(tokens) - |: - self.pushErr(exprTokens[0], LogMsg.InvalidSyntax) - ret nil - } - } - - // Tokens is should be store enumerable range tokens. - fn getEnumerableParts(mut self, mut tokens: []&Token): [][]&Token { - tokens = tokens[1:len(tokens)-1] // Remove range tokens. - mut parts, errors := parts(tokens, TokenId.Comma, true) - self.p.errors = append(self.p.errors, errors...) - ret parts - } - - fn buildSlice(mut self, mut tokens: []&Token): &SliceExpr { - mut slc := &SliceExpr{ - Token: tokens[0], - End: tokens[len(tokens)-1], - } - - mut parts := self.getEnumerableParts(tokens) - if len(parts) == 0 { - ret slc - } - - slc.Exprs = make([]&Expr, 0, len(parts)) - for (_, mut p) in parts { - if len(p) == 0 { - continue - } - slc.Exprs = append(slc.Exprs, self.buildFromTokens(p)) - } - - ret slc - } - - fn buildIndexing(mut self, mut exprTokens: []&Token, - mut tokens: []&Token, mut errorToken: &Token): &IndexingExpr { - mut end := tokens[len(tokens)-1] - tokens = tokens[1:len(tokens)-1] // Remove brackets. - if len(tokens) == 0 { - self.pushErr(errorToken, LogMsg.MissingExpr) - ret nil - } - mut expr := self.buildFromTokens(exprTokens) - if expr == nil { - ret nil - } - mut index := self.buildFromTokens(tokens) - if index == nil { - ret nil - } - ret &IndexingExpr{ - Token: errorToken, - End: end, - Expr: expr, - Index: index, - } - } - - fn buildSlicing(mut self, mut &exprTokens: []&Token, mut &start: []&Token, - mut &to: []&Token, mut &errorToken: &Token, mut end: &Token): &SlicingExpr { - mut slc := &SlicingExpr{ - Token: errorToken, - End: end, - Expr: self.buildFromTokens(exprTokens), - } - if len(start) > 0 { - slc.Start = self.buildFromTokens(start) - } - if len(to) > 0 { - slc.To = self.buildFromTokens(to) - } - ret slc - } - - fn buildBracketRange(mut self, mut tokens: []&Token): ExprData { - mut errorToken := tokens[0] - mut exprTokens, rangeN := getRangeExprTokens(tokens) - - if len(exprTokens) == 0 { - ret self.buildSlice(tokens) - } else if rangeN > 0 { - self.pushErr(errorToken, LogMsg.InvalidSyntax) - ret nil - } - - // Remove expression tokens. - // Holds only indexing tokens. - // Includes brackets. - tokens = tokens[len(exprTokens):] - - // Catch slicing expressions. - mut splitTokens := tokens[1:len(tokens)-1] // Remove brackets. - mut start, mut to := splitDelim(splitTokens, TokenId.Colon) - if start != nil || to != nil { - ret self.buildSlicing(exprTokens, start, to, errorToken, tokens[len(tokens)-1]) - } - ret self.buildIndexing(exprTokens, tokens, errorToken) - } - - fn buildExclRight(mut self, mut &tokens: []&Token): ExprData { - token := tokens[len(tokens)-1] - tokens = tokens[:len(tokens)-1] // Ignore "!" token. - mut d := self.build(tokens) - if d == nil { - ret nil - } - match type d { - | &FnCallExpr: - (&FnCallExpr)(d).Exception = &ScopeTree{ - Deferred: true, - } - ret d - } - self.pushErr(token, LogMsg.InvalidSyntax) - ret nil - } - - fn buildData(mut self, mut &tokens: []&Token): ExprData { - match len(tokens) { - | 0: - ret nil - | 1: - ret self.buildSingle(tokens[0]) - | 3: - if tokens[0].Id == TokenId.Cpp { - ret self.buildBindIdent(tokens) - } - } - - mut token := tokens[len(tokens)-1] - if token.Id == TokenId.TripleDot { - ret self.buildVariadic(tokens) - } - - token = tokens[0] - - // Unary operators. - if IsUnaryOp(token.Id) { - // Handle pointer to primitive type. - if len(tokens) > 1 { - token = tokens[1] - if token.Id == TokenId.Unsafe { - ret self.buildType(tokens) - } - } - ret self.buildUnary(tokens) - } - - if len(tokens) >= 3 { - match token.Id { - | TokenId.LParent - | TokenId.LBrace - | TokenId.LBracket: - // Catch type casting. - if len(tokens) > 3 { - t := tokens[len(tokens)-1] - if t.Id == TokenId.RParent { - break - } - } - - next := tokens[1] - if next.Id != TokenId.RBracket { - break - } - ret self.buildType(tokens) - } - } - - token = tokens[len(tokens)-1] - match token.Id { - | TokenId.Ident: - ret self.buildSubIdent(tokens) - | TokenId.Excl: - ret self.buildExclRight(tokens) - | TokenId.RParent: - ret self.buildParenthesesRange(tokens) - | TokenId.RBrace: - ret self.buildBraceRange(tokens) - | TokenId.RBracket: - ret self.buildBracketRange(tokens) - } - self.pushErr(token, LogMsg.InvalidSyntax) - ret nil - } - - fn buildBinary(mut self, mut &tokens: []&Token, i: int): ExprData { - mut op := tokens[i] - mut leftTokens := tokens[:i] - if isTypeOp(op.Id) && isTypeRange(leftTokens) { - // Catch slice and array types. - ret self.buildType(tokens) - } - mut rightTokens := tokens[i+1:] - if len(leftTokens) == 0 { - self.pushErr(tokens[i], LogMsg.InvalidSyntax) - self.pushSuggestion(LogMsg.ExpectedLeftOperand) - ret nil - } - if len(rightTokens) == 0 { - self.pushErr(tokens[i], LogMsg.InvalidSyntax) - self.pushSuggestion(LogMsg.ExpectedRightOperand) - ret nil - } - ret &BinaryExpr{ - Left: self.buildFromTokens(leftTokens), - Right: self.buildFromTokens(rightTokens), - Op: op, - } - } - - fn build(mut self, mut &tokens: []&Token): ExprData { - if tokens[0].Id == TokenId.Map { - ret self.buildType(tokens) - } - i := findLowestPrecOp(tokens) - if i == -1 { - ret self.buildData(tokens) - } - ret self.buildBinary(tokens, i) - } - - fn buildKind(mut self, mut &tokens: []&Token): ExprData { - mut parts, errors := parts(tokens, TokenId.Comma, true) - if errors != nil { - self.p.errors = append(self.p.errors, errors...) - ret nil - } else if len(parts) > 1 { - ret self.buildTuple(parts) - } - ret self.build(tokens) - } - - fn buildFromTokens(mut self, mut tokens: []&Token): &Expr { - if len(tokens) == 0 { - ret nil - } - mut kind := self.buildKind(tokens) - if kind == nil { - ret nil - } - ret &Expr{ - Token: tokens[0], - End: tokens[len(tokens)-1], - Kind: kind, - } - } + fn pushErr(mut self, token: &Token, fmt: LogMsg, args: ...any) { + self.p.pushErr(token, fmt, args...) + } + + // Push suggestion to last log. + fn pushSuggestion(mut self, fmt: LogMsg, args: ...any) { + self.p.pushSuggestion(fmt, args...) + } + + fn buildTuple(mut self, mut &parts: [][]&Token): &TupleExpr { + mut tuple := &TupleExpr{ + Expr: make([]&Expr, 0, len(parts)), + } + for (_, mut part) in parts { + tuple.Expr = append(tuple.Expr, self.buildFromTokens(part)) + } + ret tuple + } + + fn buildLit(self, mut token: &Token): &LitExpr { + ret &LitExpr{ + Token: token, + Value: token.Kind, + } + } + + fn buildPrimitiveType(self, mut &token: &Token): &TypeDecl { + ret buildPrimType(token) + } + + fn buildSingle(mut self, mut token: &Token): ExprData { + match token.Id { + | TokenId.Lit: + ret self.buildLit(token) + | TokenId.TripleDot: + ret &VariadicExpr{ + Token: token, + } + | TokenId.Ident + | TokenId.Self + | TokenId.Error: + ret buildIdentExpr(token) + } + self.pushErr(token, LogMsg.InvalidSyntax) + ret nil + } + + fn buildBindIdent(mut self, mut &tokens: []&Token): &IdentExpr { + if tokens[0].Id != TokenId.Cpp { + ret nil + } else if tokens[1].Id != TokenId.Dot { + self.pushErr(tokens[1], LogMsg.InvalidSyntax) + self.pushSuggestion(LogMsg.ExpectedDotForBind) + ret nil + } + mut token := tokens[2] + if token.Id != TokenId.Ident { + self.pushErr(tokens[2], LogMsg.InvalidSyntax) + self.pushSuggestion(LogMsg.ExpectedIdentifier) + ret nil + } + mut expr := buildIdentExpr(token) + expr.Binded = true + ret expr + } + + fn buildUnary(mut self, mut tokens: []&Token): &UnaryExpr { + mut op := tokens[0] + if len(tokens) == 1 { + self.pushErr(op, LogMsg.MissingExprForUnary) + ret nil + } else if !IsUnaryOp(op.Id) { + self.pushErr(op, LogMsg.InvalidOpForUnary, op.Kind) + ret nil + } + + // Length is 1 cause all length of operator tokens is 1. + // Change "1" with length of token's value + // if all operators length is not 1. + tokens = tokens[1:] + + ret &UnaryExpr{ + Op: op, + Expr: self.buildFromTokens(tokens), + } + } + + fn buildObjSubIdent(mut self, mut tokens: []&Token): &SubIdentExpr { + mut i := len(tokens) - 1 + mut identToken := tokens[i] + i-- // Set offset to delimiter token. + tokens = tokens[:i] // Remove dot token and selected identifier token. + if len(tokens) == 0 { + self.pushErr(identToken, LogMsg.InvalidSyntax) + ret nil + } + ret &SubIdentExpr{ + Ident: identToken, + Expr: self.buildFromTokens(tokens), + } + } + + fn buildNsSubIdent(mut self, mut &tokens: []&Token): &NsSelectionExpr { + mut ns := new(NsSelectionExpr) + if len(tokens) == 3 && tokens[0].Id == TokenId.Unsafe { + // Check unsafe scope selection. + ns.Ns = tokens[:1] + ns.Ident = tokens[2] + } else { + for (i, mut token) in tokens { + if i%2 == 0 { + if token.Id != TokenId.Ident { + self.pushErr(token, LogMsg.InvalidSyntax) + self.pushSuggestion(LogMsg.ExpectedIdentifier) + } + ns.Ns = append(ns.Ns, token) + } else if token.Id != TokenId.DblColon { + self.pushErr(token, LogMsg.InvalidSyntax) + self.pushSuggestion(LogMsg.ExpectedDblColon) + } + } + ns.Ident = ns.Ns[len(ns.Ns)-1] + ns.Ns = ns.Ns[:len(ns.Ns)-1] + } + ret ns + } + + fn buildType(mut self, mut &tokens: []&Token): &TypeDecl { + mut i := 0 + mut t, ok := unsafe { self.p.buildType(tokens, &i, false) } + if !ok { + self.pushErr(tokens[0], LogMsg.InvalidSyntax) + ret nil + } + + if i < len(tokens) { + self.pushErr(tokens[i], LogMsg.InvalidSyntax) + } + ret t + } + + fn buildSubIdent(mut self, mut &tokens: []&Token): ExprData { + i := len(tokens) - 2 // Set offset to delimiter token. + token := tokens[i] + match token.Id { + | TokenId.Dot: + ret self.buildObjSubIdent(tokens) + | TokenId.DblColon: + ret self.buildNsSubIdent(tokens) + | TokenId.RBracket: + // Catch slice, array, and map types. + ret self.buildType(tokens) + } + + // Caught anonymous functions. + if isAnonFnHead(tokens) { + ret self.buildType(tokens) + } + + self.pushErr(token, LogMsg.InvalidSyntax) + ret nil + } + + fn buildVariadic(mut self, mut tokens: []&Token): &VariadicExpr { + mut token := tokens[len(tokens)-1] // Variadic operator token. + tokens = tokens[:len(tokens)-1] // Remove variadic operator token. + ret &VariadicExpr{ + Token: token, + Expr: self.buildFromTokens(tokens), + } + } + + fn buildBetweenParentheses(mut self, mut tokens: []&Token): &RangeExpr { + if len(tokens) == 2 { + self.pushErr(tokens[0], LogMsg.MissingExpr) + self.pushSuggestion(LogMsg.EmptyParentNotValid) + ret nil + } + tokens = tokens[1:len(tokens)-1] // Remove parentheses. + ret &RangeExpr{ + Expr: self.buildFromTokens(tokens), + } + } + + fn tryBuildCast(mut self, mut &tokens: []&Token): &CastExpr { + mut rangeN := 0 + for i, token in tokens { + match token.Id { + | TokenId.LBrace + | TokenId.LBracket + | TokenId.LParent: + rangeN++ + continue + | TokenId.RBrace + | TokenId.RBracket + | TokenId.RParent: + rangeN-- + } + + if rangeN > 0 { + continue + } else if i+1 == len(tokens) { + ret nil + } + + mut typeTokens := tokens[:i+1] + mut exprTokens := tokens[i+1:] + + if len(exprTokens) == 0 { + // Expression is parentheses group. + ret nil + } + + tok := exprTokens[0] + if tok.Id != TokenId.LParent { + ret nil + } + + mut cast := &CastExpr{} + + // Expression tokens just parentheses. + if len(exprTokens) == 2 { + self.pushErr(exprTokens[0], LogMsg.MissingExpr) + self.pushSuggestion(LogMsg.GiveExprToCast) + } + + // Type tokens just parentheses. + if len(typeTokens) == 2 { + self.pushErr(typeTokens[0], LogMsg.MissingType) + self.pushSuggestion(LogMsg.GiveTypeForCast) + } else { + typeTokens = typeTokens[1:len(typeTokens)-1] // Remove parentheses. + mut typeIndex := 0 + mut t, ok := unsafe { self.p.buildType(typeTokens, &typeIndex, true) } + if ok && typeIndex < len(typeTokens) { + self.pushErr(typeTokens[typeIndex], LogMsg.InvalidSyntax) + } else if !ok { + ret cast + } + cast.Kind = t + + if len(exprTokens) > 2 { + // Remove parentheses. + mut j := 0 + _ = range(j, TokenId.LParent, TokenId.RParent, exprTokens) + if j < len(exprTokens) { + ret nil + } + exprTokens = exprTokens[:j] + cast.Expr = self.buildFromTokens(exprTokens) + } + } + ret cast + } + + ret nil + } + + fn pushArg(mut self, mut &args: []&Expr, mut tokens: []&Token, err_token: &Token) { + if len(tokens) == 0 { + self.pushErr(err_token, LogMsg.InvalidSyntax) + self.pushSuggestion(LogMsg.ExpectedExpr) + ret + } + args = append(args, self.buildFromTokens(tokens)) + } + + fn buildArgs(mut self, mut tokens: []&Token): []&Expr { + // No argument. + if len(tokens) < 2 { + ret nil + } + + let mut args: []&Expr = nil + mut last := 0 + mut rangeN := 0 + tokens = tokens[1:len(tokens)-1] // Remove parentheses. + for i, token in tokens { + match token.Id { + | TokenId.LBrace + | TokenId.LBracket + | TokenId.LParent: + rangeN++ + | TokenId.RBrace + | TokenId.RBracket + | TokenId.RParent: + rangeN-- + } + if rangeN > 0 || token.Id != TokenId.Comma { + continue + } + self.pushArg(args, tokens[last:i], token) + last = i + 1 + } + + if last < len(tokens) { + if last == 0 { + if len(tokens) > 0 { + self.pushArg(args, tokens[last:], tokens[last]) + } + } else { + self.pushArg(args, tokens[last:], tokens[last-1]) + } + } + + ret args + } + + // Tokens should include brackets. + fn buildCallGenerics(mut self, mut tokens: []&Token): []&TypeDecl { + if len(tokens) == 0 { + ret nil + } + + tokens = tokens[1:len(tokens)-1] // Remove brackets. + mut parts, errs := parts(tokens, TokenId.Comma, true) + mut generics := make([]&TypeDecl, 0, len(parts)) + self.p.errors = append(self.p.errors, errs...) + for (_, mut part) in parts { + if len(part) == 0 { + continue + } + mut j := 0 + mut generic, _ := unsafe { self.p.buildType(part, &j, true) } + if j < len(part) { + self.pushErr(part[j], LogMsg.InvalidSyntax) + } + generics = append(generics, generic) + } + + ret generics + } + + fn buildFnCall(mut self, mut &token: &Token, mut &expr: []&Token, mut &args: []&Token): &FnCallExpr { + ret &FnCallExpr{ + Token: token, + Expr: self.buildFromTokens(expr), + Args: self.buildArgs(args), + } + } + + fn buildParenthesesRange(mut self, mut &tokens: []&Token): ExprData { + mut token := tokens[0] + if token.Id == TokenId.LParent { + mut expr := self.tryBuildCast(tokens) + if expr != nil { + ret expr + } + } + mut exprTokens, mut argsTokens := rangeLast(tokens) + // Expression is parentheses group if data.exprTokens is zero. + // data.args_tokens holds tokens of parentheses range (include parentheses). + if len(exprTokens) == 0 { + ret self.buildBetweenParentheses(argsTokens) + } + + // Caught anonymous function types. + if isAnonFnHead(exprTokens) { + ret self.buildType(tokens) + } + ret self.buildFnCall(token, exprTokens, argsTokens) + } + + fn buildUnsafeExpr(mut self, mut tokens: []&Token): &UnsafeExpr { + mut token := tokens[0] + tokens = tokens[1:] // Remove unsafe keyword. + mut i := 0 + mut rangeTokens := range(i, TokenId.LBrace, TokenId.RBrace, tokens) + if len(rangeTokens) == 0 { + self.pushErr(tokens[0], LogMsg.MissingExpr) + ret nil + } + ret &UnsafeExpr{ + Token: token, + Expr: self.buildFromTokens(rangeTokens), + } + } + + fn buildAnonFn(mut self, mut &tokens: []&Token): &FnDecl { + mut f := self.p.buildFn(tokens, false, false) + if !f.IsAnon() { + self.pushErr(f.Token, LogMsg.InvalidSyntax) + self.pushSuggestion(LogMsg.ExpectedAnonFn) + } + ret f + } + + fn buildUnsafe(mut self, mut &tokens: []&Token): ExprData { + match tokens[1].Id { + | TokenId.Fn: + // Unsafe anonymous function. + ret self.buildAnonFn(tokens) + |: + ret self.buildUnsafeExpr(tokens) + } + } + + fn pushRangeLitPart(mut self, mut part: []&Token, + errorToken: &Token, mut &parts: [][]&Token) { + if len(part) == 0 { + self.pushErr(errorToken, LogMsg.InvalidSyntax) + self.pushSuggestion(LogMsg.ExpectedExpr) + ret + } + parts = append(parts, part) + } + + // Tokens should include brace tokens. + fn getBraceRangeLitExprParts(mut self, mut tokens: []&Token): [][]&Token { + // No part. + if len(tokens) < 2 { + ret nil + } + + let mut parts: [][]&Token = nil + + mut last := 0 + mut rangeN := 0 + tokens = tokens[1:len(tokens)-1] // Remove parentheses. + for i, token in tokens { + match token.Id { + | TokenId.LBrace + | TokenId.LBracket + | TokenId.LParent: + rangeN++ + | TokenId.RBrace + | TokenId.RBracket + | TokenId.RParent: + rangeN-- + } + if rangeN > 0 || token.Id != TokenId.Comma { + continue + } + self.pushRangeLitPart(tokens[last:i], token, parts) + last = i + 1 + } + + if last < len(tokens) { + if last == 0 { + if len(tokens) > 0 { + self.pushRangeLitPart(tokens[last:], tokens[last], parts) + } + } else { + self.pushRangeLitPart(tokens[last:], tokens[last-1], parts) + } + } + + ret parts + } + + fn buildFieldExprPair(mut self, mut tokens: []&Token): &FieldExprPair { + if len(tokens)-2 == 0 { + self.pushErr(tokens[1], LogMsg.MissingExpr) + ret nil + } + mut pair := &FieldExprPair{ + Field: tokens[0], + } + tokens = tokens[2:] // Remove field identifier and colon tokens. + pair.Expr = self.buildFromTokens(tokens) + ret pair + } + + fn buildStructLitExpr(mut self, mut &tokens: []&Token): &Expr { + mut token := tokens[0] + if token.Id == TokenId.Ident && len(tokens) > 1 { + token = tokens[1] + if token.Id == TokenId.Colon { + ret &Expr{ + Token: token, + End: tokens[len(tokens)-1], + Kind: self.buildFieldExprPair(tokens), + } + } + } + ret self.buildFromTokens(tokens) + } + + fn buildStructLitExprs(mut self, mut &tokens: []&Token): []&Expr { + mut parts := self.getBraceRangeLitExprParts(tokens) + if len(parts) == 0 { + ret nil + } + + mut pairs := make([]&Expr, 0, len(parts)) + for (_, mut part) in parts { + pairs = append(pairs, self.buildStructLitExpr(part)) + } + ret pairs + } + + fn buildTypedStructLiteral(mut self, mut tokens: []&Token): &StructLit { + mut i := 0 + mut t, ok := unsafe { self.p.buildType(tokens, &i, true) } + if !ok { + ret nil + } else if i >= len(tokens) { + self.pushErr(tokens[i], LogMsg.InvalidSyntax) + ret nil + } + + tokens = tokens[i:] // Remove type tokens. + token := tokens[0] + if token.Id != TokenId.LBrace { + self.pushErr(token, LogMsg.InvalidSyntax) + ret nil + } + + ret &StructLit{ + End: tokens[len(tokens)-1], + Kind: t, + Exprs: self.buildStructLitExprs(tokens), + } + } + + fn buildBraceLitPart(mut self, mut &tokens: []&Token): &Expr { + mut l, mut r := splitDelim(tokens, TokenId.Colon) + // If left is not nil, colon token found. + if l != nil { + ret &Expr{ + Token: tokens[0], + End: tokens[len(tokens)-1], + Kind: &KeyValPair{ + Colon: tokens[len(l)], + Key: self.buildFromTokens(l), + Val: self.buildFromTokens(r), + }, + } + } + ret self.buildFromTokens(tokens) + } + + fn buildBraceLit(mut self, mut &tokens: []&Token): &BraceLit { + mut lit := &BraceLit{ + Token: tokens[0], + End: tokens[len(tokens)-1], + } + + mut parts := self.getBraceRangeLitExprParts(tokens) + if parts == nil { + ret lit + } + + lit.Exprs = make([]&Expr, 0, len(parts)) + for (_, mut part) in parts { + lit.Exprs = append(lit.Exprs, self.buildBraceLitPart(part)) + } + + ret lit + } + + fn buildBraceRange(mut self, mut &tokens: []&Token): ExprData { + mut exprTokens, rangeN := getRangeExprTokens(tokens) + + match { + | len(exprTokens) == 0: + ret self.buildBraceLit(tokens) + | rangeN > 0: + self.pushErr(tokens[0], LogMsg.InvalidSyntax) + ret nil + } + + // Exceptional handling. + elseToken := exprTokens[len(exprTokens)-1] + if exprTokens[len(exprTokens)-1].Id == TokenId.Else { + exprTokens = exprTokens[:len(exprTokens)-1] // Ignore keyword "else" + mut d := self.build(exprTokens) + if d == nil { + ret nil + } + match type d { + | &FnCallExpr: + tokens = tokens[len(exprTokens)+1:] // Get range: {...} + mut i := 0 + mut rangeTokens := range(i, TokenId.LBrace, TokenId.RBrace, tokens) + mut model := (&FnCallExpr)(d) + if model.Ignored() { + self.pushErr(elseToken, LogMsg.InvalidSyntax) + self.pushSuggestion(LogMsg.JustIgnoreOrHandle) + } + model.Exception = self.p.buildScope(rangeTokens, tokens[i-1]) + ret d + |: + self.pushErr(exprTokens[0], LogMsg.InvalidSyntax) + ret nil + } + } + + match exprTokens[0].Id { + | TokenId.Unsafe: + ret self.buildUnsafe(tokens) + | TokenId.Fn: + ret self.buildAnonFn(tokens) + | TokenId.Ident + | TokenId.Cpp: + ret self.buildTypedStructLiteral(tokens) + |: + self.pushErr(exprTokens[0], LogMsg.InvalidSyntax) + ret nil + } + } + + // Tokens is should be store enumerable range tokens. + fn getEnumerableParts(mut self, mut tokens: []&Token): [][]&Token { + tokens = tokens[1:len(tokens)-1] // Remove range tokens. + mut parts, errors := parts(tokens, TokenId.Comma, true) + self.p.errors = append(self.p.errors, errors...) + ret parts + } + + fn buildSlice(mut self, mut tokens: []&Token): &SliceExpr { + mut slc := &SliceExpr{ + Token: tokens[0], + End: tokens[len(tokens)-1], + } + + mut parts := self.getEnumerableParts(tokens) + if len(parts) == 0 { + ret slc + } + + slc.Exprs = make([]&Expr, 0, len(parts)) + for (_, mut p) in parts { + if len(p) == 0 { + continue + } + slc.Exprs = append(slc.Exprs, self.buildFromTokens(p)) + } + + ret slc + } + + fn buildIndexing(mut self, mut exprTokens: []&Token, + mut tokens: []&Token, mut errorToken: &Token): &IndexingExpr { + mut end := tokens[len(tokens)-1] + tokens = tokens[1:len(tokens)-1] // Remove brackets. + if len(tokens) == 0 { + self.pushErr(errorToken, LogMsg.MissingExpr) + ret nil + } + mut expr := self.buildFromTokens(exprTokens) + if expr == nil { + ret nil + } + mut index := self.buildFromTokens(tokens) + if index == nil { + ret nil + } + ret &IndexingExpr{ + Token: errorToken, + End: end, + Expr: expr, + Index: index, + } + } + + fn buildSlicing(mut self, mut &exprTokens: []&Token, mut &start: []&Token, + mut &to: []&Token, mut &errorToken: &Token, mut end: &Token): &SlicingExpr { + mut slc := &SlicingExpr{ + Token: errorToken, + End: end, + Expr: self.buildFromTokens(exprTokens), + } + if len(start) > 0 { + slc.Start = self.buildFromTokens(start) + } + if len(to) > 0 { + slc.To = self.buildFromTokens(to) + } + ret slc + } + + fn buildBracketRange(mut self, mut tokens: []&Token): ExprData { + mut errorToken := tokens[0] + mut exprTokens, rangeN := getRangeExprTokens(tokens) + + if len(exprTokens) == 0 { + ret self.buildSlice(tokens) + } else if rangeN > 0 { + self.pushErr(errorToken, LogMsg.InvalidSyntax) + ret nil + } + + // Remove expression tokens. + // Holds only indexing tokens. + // Includes brackets. + tokens = tokens[len(exprTokens):] + + // Catch slicing expressions. + mut splitTokens := tokens[1:len(tokens)-1] // Remove brackets. + mut start, mut to := splitDelim(splitTokens, TokenId.Colon) + if start != nil || to != nil { + ret self.buildSlicing(exprTokens, start, to, errorToken, tokens[len(tokens)-1]) + } + ret self.buildIndexing(exprTokens, tokens, errorToken) + } + + fn buildExclRight(mut self, mut &tokens: []&Token): ExprData { + token := tokens[len(tokens)-1] + tokens = tokens[:len(tokens)-1] // Ignore "!" token. + mut d := self.build(tokens) + if d == nil { + ret nil + } + match type d { + | &FnCallExpr: + (&FnCallExpr)(d).Exception = &ScopeTree{ + Deferred: true, + } + ret d + } + self.pushErr(token, LogMsg.InvalidSyntax) + ret nil + } + + fn buildData(mut self, mut &tokens: []&Token): ExprData { + match len(tokens) { + | 0: + ret nil + | 1: + ret self.buildSingle(tokens[0]) + | 3: + if tokens[0].Id == TokenId.Cpp { + ret self.buildBindIdent(tokens) + } + } + + mut token := tokens[len(tokens)-1] + if token.Id == TokenId.TripleDot { + ret self.buildVariadic(tokens) + } + + token = tokens[0] + + // Unary operators. + if IsUnaryOp(token.Id) { + // Handle pointer to primitive type. + if len(tokens) > 1 { + token = tokens[1] + if token.Id == TokenId.Unsafe { + ret self.buildType(tokens) + } + } + ret self.buildUnary(tokens) + } + + if len(tokens) >= 3 { + match token.Id { + | TokenId.LParent + | TokenId.LBrace + | TokenId.LBracket: + // Catch type casting. + if len(tokens) > 3 { + t := tokens[len(tokens)-1] + if t.Id == TokenId.RParent { + break + } + } + + next := tokens[1] + if next.Id != TokenId.RBracket { + break + } + ret self.buildType(tokens) + } + } + + token = tokens[len(tokens)-1] + match token.Id { + | TokenId.Ident: + ret self.buildSubIdent(tokens) + | TokenId.Excl: + ret self.buildExclRight(tokens) + | TokenId.RParent: + ret self.buildParenthesesRange(tokens) + | TokenId.RBrace: + ret self.buildBraceRange(tokens) + | TokenId.RBracket: + ret self.buildBracketRange(tokens) + } + self.pushErr(token, LogMsg.InvalidSyntax) + ret nil + } + + fn buildBinary(mut self, mut &tokens: []&Token, i: int): ExprData { + mut op := tokens[i] + mut leftTokens := tokens[:i] + if isTypeOp(op.Id) && isTypeRange(leftTokens) { + // Catch slice and array types. + ret self.buildType(tokens) + } + mut rightTokens := tokens[i+1:] + if len(leftTokens) == 0 { + self.pushErr(tokens[i], LogMsg.InvalidSyntax) + self.pushSuggestion(LogMsg.ExpectedLeftOperand) + ret nil + } + if len(rightTokens) == 0 { + self.pushErr(tokens[i], LogMsg.InvalidSyntax) + self.pushSuggestion(LogMsg.ExpectedRightOperand) + ret nil + } + ret &BinaryExpr{ + Left: self.buildFromTokens(leftTokens), + Right: self.buildFromTokens(rightTokens), + Op: op, + } + } + + fn build(mut self, mut &tokens: []&Token): ExprData { + if tokens[0].Id == TokenId.Map { + ret self.buildType(tokens) + } + i := findLowestPrecOp(tokens) + if i == -1 { + ret self.buildData(tokens) + } + ret self.buildBinary(tokens, i) + } + + fn buildKind(mut self, mut &tokens: []&Token): ExprData { + mut parts, errors := parts(tokens, TokenId.Comma, true) + if errors != nil { + self.p.errors = append(self.p.errors, errors...) + ret nil + } else if len(parts) > 1 { + ret self.buildTuple(parts) + } + ret self.build(tokens) + } + + fn buildFromTokens(mut self, mut tokens: []&Token): &Expr { + if len(tokens) == 0 { + ret nil + } + mut kind := self.buildKind(tokens) + if kind == nil { + ret nil + } + ret &Expr{ + Token: tokens[0], + End: tokens[len(tokens)-1], + Kind: kind, + } + } } // Reports whether kind is potentially part of a type declaration. fn isTypeOp(&id: TokenId): bool { - ret id == TokenId.Amper || - id == TokenId.DblAmper || - id == TokenId.Star + ret id == TokenId.Amper || + id == TokenId.DblAmper || + id == TokenId.Star } // Reports whether range is potentially part of a type declaration. fn isTypeRange(mut &tokens: []&Token): bool { - mut op := false - for i, token in tokens { - if token.Id == TokenId.LBracket { - if op { - ret true - } - mut rangeN := 0 - mut lTokens := tokens[i:] - for _, lToken in lTokens { - match lToken.Id { - | TokenId.LBracket: - rangeN++ - continue - | TokenId.RBracket: - rangeN-- - continue - } - if rangeN == 0 { - ret isTypeOp(lToken.Id) - } - } - ret true - } - if !isTypeOp(token.Id) { - ret false - } - op = true - } - ret true + mut op := false + for i, token in tokens { + if token.Id == TokenId.LBracket { + if op { + ret true + } + mut rangeN := 0 + mut lTokens := tokens[i:] + for _, lToken in lTokens { + match lToken.Id { + | TokenId.LBracket: + rangeN++ + continue + | TokenId.RBracket: + rangeN-- + continue + } + if rangeN == 0 { + ret isTypeOp(lToken.Id) + } + } + ret true + } + if !isTypeOp(token.Id) { + ret false + } + op = true + } + ret true } // Returns expression tokens comes before block if exist, nil if not. fn getBlockExpr(mut &tokens: []&Token): []&Token { - mut braceN := 0 - mut skipToNextBraceClose := 0 - for i, tok in tokens { - match tok.Id { - | TokenId.Unsafe: - if len(tokens)-i > 1 && tokens[i+1].Id == TokenId.LBrace { - skipToNextBraceClose++ - } - | TokenId.LBrace: - if braceN > 0 || skipToNextBraceClose > 0 { - if skipToNextBraceClose > 0 { - skipToNextBraceClose-- - } - braceN++ - break - } - ret tokens[:i] - | TokenId.LBracket - | TokenId.LParent: - braceN++ - | TokenId.RBrace - | TokenId.RBracket - | TokenId.RParent: - braceN-- - } - } - ret nil + mut braceN := 0 + mut skipToNextBraceClose := 0 + for i, tok in tokens { + match tok.Id { + | TokenId.Unsafe: + if len(tokens)-i > 1 && tokens[i+1].Id == TokenId.LBrace { + skipToNextBraceClose++ + } + | TokenId.LBrace: + if braceN > 0 || skipToNextBraceClose > 0 { + if skipToNextBraceClose > 0 { + skipToNextBraceClose-- + } + braceN++ + break + } + ret tokens[:i] + | TokenId.LBracket + | TokenId.LParent: + braceN++ + | TokenId.RBrace + | TokenId.RBracket + | TokenId.RParent: + braceN-- + } + } + ret nil } // Returns delimiter index, left range and right range tokens. // Returns nil slice and -1 if not found. fn splitDelim(mut &tokens: []&Token, delim: TokenId): ([]&Token, []&Token) { - mut func := -1 - mut rangeN := 0 - mut i := 0 - for i < len(tokens); i++ { - token := tokens[i] - match token.Id { - | TokenId.Fn: - func = rangeN - | TokenId.LBrace - | TokenId.LBracket - | TokenId.LParent: - rangeN++ - continue - | TokenId.RParent: - rangeN-- - if func == rangeN { - func = -1 - // Skip colon token if function builded. - if len(tokens)-i > 1 && tokens[i+1].Id == TokenId.Colon { - i++ - continue - } - } - | TokenId.RBrace - | TokenId.RBracket: - rangeN-- - } - if token.Id == delim && rangeN == 0 { - mut l := tokens[:i] - mut r := tokens[i+1:] - ret l, r - } - } - ret nil, nil + mut func := -1 + mut rangeN := 0 + mut i := 0 + for i < len(tokens); i++ { + token := tokens[i] + match token.Id { + | TokenId.Fn: + func = rangeN + | TokenId.LBrace + | TokenId.LBracket + | TokenId.LParent: + rangeN++ + continue + | TokenId.RParent: + rangeN-- + if func == rangeN { + func = -1 + // Skip colon token if function builded. + if len(tokens)-i > 1 && tokens[i+1].Id == TokenId.Colon { + i++ + continue + } + } + | TokenId.RBrace + | TokenId.RBracket: + rangeN-- + } + if token.Id == delim && rangeN == 0 { + mut l := tokens[:i] + mut r := tokens[i+1:] + ret l, r + } + } + ret nil, nil } // Finds index of priority operator and returns index of operator // if found, returns -1 if not. fn findLowestPrecOp(&tokens: []&Token): int { - // Set to byte.Max, there is nothing for precedence byte.Max. - // It's provides optimization, avoid prec != -1 (if not setted) checking. - // Always greater than actual precedences. - // So, It's will initialized by first precedence without any checking that if not setted. - mut prec := byte.Max - mut precPos := -1 - - mut braceN := 0 - mut skipToNextBraceOpen := false - for i, token in tokens { - match token.Id { - | TokenId.LBrace: - skipToNextBraceOpen = false - fall - | TokenId.LParent - | TokenId.LBracket: - braceN++ - continue - | TokenId.RBrace - | TokenId.RParent - | TokenId.RBracket: - braceN-- - continue - | TokenId.If: - skipToNextBraceOpen = true - continue - } - match { - | skipToNextBraceOpen: - continue - | i == 0: - continue - | braceN > 0: - continue - | !IsBinOp(token.Id): - continue - } - - left := tokens[i-1] - - // Skip unary operator or type annotation. - if IsUnaryOp(left.Id) || left.Id == TokenId.Colon { - continue - } - - if i > 1 && left.Id == TokenId.RBracket { - lleft := tokens[i-2] - if lleft.Id == TokenId.LBracket { - // Skip potential type annotations. - if token.Id == TokenId.Amper || token.Id == TokenId.Star { - continue - } - } - } - - p := token.Prec() - if p != 0 && p <= prec { - prec = p - precPos = i - } - } - ret precPos + // Set to byte.Max, there is nothing for precedence byte.Max. + // It's provides optimization, avoid prec != -1 (if not setted) checking. + // Always greater than actual precedences. + // So, It's will initialized by first precedence without any checking that if not setted. + mut prec := byte.Max + mut precPos := -1 + + mut braceN := 0 + mut skipToNextBraceOpen := false + for i, token in tokens { + match token.Id { + | TokenId.LBrace: + skipToNextBraceOpen = false + fall + | TokenId.LParent + | TokenId.LBracket: + braceN++ + continue + | TokenId.RBrace + | TokenId.RParent + | TokenId.RBracket: + braceN-- + continue + | TokenId.If: + skipToNextBraceOpen = true + continue + } + match { + | skipToNextBraceOpen: + continue + | i == 0: + continue + | braceN > 0: + continue + | !IsBinOp(token.Id): + continue + } + + left := tokens[i-1] + + // Skip unary operator or type annotation. + if IsUnaryOp(left.Id) || left.Id == TokenId.Colon { + continue + } + + if i > 1 && left.Id == TokenId.RBracket { + lleft := tokens[i-2] + if lleft.Id == TokenId.LBracket { + // Skip potential type annotations. + if token.Id == TokenId.Amper || token.Id == TokenId.Star { + continue + } + } + } + + p := token.Prec() + if p != 0 && p <= prec { + prec = p + precPos = i + } + } + ret precPos } fn buildIdentExpr(mut &token: &Token): &IdentExpr { - ret &IdentExpr{ - Token: token, - Ident: token.Kind, - Binded: false, - } + ret &IdentExpr{ + Token: token, + Ident: token.Kind, + Binded: false, + } } fn getRangeExprTokens(mut &tokens: []&Token): ([]&Token, int) { - mut rangeN := 0 - mut i := len(tokens) - 1 - for i >= 0; i-- { - tok := tokens[i] - match tok.Id { - | TokenId.RBrace - | TokenId.RBracket - | TokenId.RParent: - rangeN++ - | TokenId.LBrace - | TokenId.LBracket - | TokenId.LParent: - rangeN-- - } - - if rangeN == 0 { - ret tokens[:i], rangeN - } - } - ret nil, rangeN + mut rangeN := 0 + mut i := len(tokens) - 1 + for i >= 0; i-- { + tok := tokens[i] + match tok.Id { + | TokenId.RBrace + | TokenId.RBracket + | TokenId.RParent: + rangeN++ + | TokenId.LBrace + | TokenId.LBracket + | TokenId.LParent: + rangeN-- + } + + if rangeN == 0 { + ret tokens[:i], rangeN + } + } + ret nil, rangeN } fn isAnonFnHead(&tokens: []&Token): bool { - match tokens[0].Id { - | TokenId.Unsafe: - if len(tokens) == 1 || tokens[1].Id != TokenId.Fn { - break - } - fall - | TokenId.Fn: - if tokens[len(tokens)-1].Id == TokenId.RBrace { - // Not function type declaration, anonymous function expression. - break - } - ret true - } - ret false + match tokens[0].Id { + | TokenId.Unsafe: + if len(tokens) == 1 || tokens[1].Id != TokenId.Fn { + break + } + fall + | TokenId.Fn: + if tokens[len(tokens)-1].Id == TokenId.RBrace { + // Not function type declaration, anonymous function expression. + break + } + ret true + } + ret false } \ No newline at end of file diff --git a/std/jule/parser/parse.jule b/std/jule/parser/parse.jule index 00487cb07..259a28a62 100644 --- a/std/jule/parser/parse.jule +++ b/std/jule/parser/parse.jule @@ -8,28 +8,28 @@ use std::jule::lex::{File} // Stores information about file parsing. struct FileInfo { - Ast: &Ast - Errors: []Log + Ast: &Ast + Errors: []Log } // Stores information about package parsing. struct PackageInfo { - Files: []&FileInfo + Files: []&FileInfo } // Parses fileset's tokens and builds AST. // Returns nil if f is not real. // File should not contain comment tokens. fn ParseFile(mut f: &File): &FileInfo { - if f == nil { - ret nil - } - mut finf := new(FileInfo) - finf.Ast, finf.Errors = parseFileset(f) - if len(finf.Errors) > 0 { - finf.Ast = nil - } - ret finf + if f == nil { + ret nil + } + mut finf := new(FileInfo) + finf.Ast, finf.Errors = parseFileset(f) + if len(finf.Errors) > 0 { + finf.Ast = nil + } + ret finf } // Parses fileset's tokens and builds AST. @@ -37,23 +37,23 @@ fn ParseFile(mut f: &File): &FileInfo { // Skip fileset if nil. // Files should not contain comment tokens. fn ParsePackage(mut filesets: []&File): &PackageInfo { - if filesets == nil { - ret nil - } - mut pinf := new(PackageInfo) - pinf.Files = make([]&FileInfo, 0, len(filesets)) - for (_, mut f) in filesets { - if f == nil { - continue - } - mut finfo := ParseFile(f) - pinf.Files = append(pinf.Files, finfo) - } - ret pinf + if filesets == nil { + ret nil + } + mut pinf := new(PackageInfo) + pinf.Files = make([]&FileInfo, 0, len(filesets)) + for (_, mut f) in filesets { + if f == nil { + continue + } + mut finfo := ParseFile(f) + pinf.Files = append(pinf.Files, finfo) + } + ret pinf } fn parseFileset(mut f: &File): (&Ast, []Log) { - mut p := new(parser) - p.parse(f) - ret p.ast, p.errors + mut p := new(parser) + p.parse(f) + ret p.ast, p.errors } \ No newline at end of file diff --git a/std/jule/parser/parser.jule b/std/jule/parser/parser.jule index c627fb7b7..c3752de46 100644 --- a/std/jule/parser/parser.jule +++ b/std/jule/parser/parser.jule @@ -4,58 +4,58 @@ use std::fs::path::{Join} use std::jule::ast::{ - Ast, - Constraint, - Directive, - Expr, - ScopeTree, - TypeDecl, - TypeAliasDecl, - VarDecl, - GenericDecl, - ParamDecl, - IdentTypeDecl, - RetTypeDecl, - TupleTypeDecl, - FnDecl, - UseDecl, - EnumItemDecl, - EnumDecl, - TypeEnumDecl, - TypeEnumItemDecl, - FieldDecl, - StructDecl, - TraitDecl, - NodeData, - Impl, - Node, + Ast, + Constraint, + Directive, + Expr, + ScopeTree, + TypeDecl, + TypeAliasDecl, + VarDecl, + GenericDecl, + ParamDecl, + IdentTypeDecl, + RetTypeDecl, + TupleTypeDecl, + FnDecl, + UseDecl, + EnumItemDecl, + EnumDecl, + TypeEnumDecl, + TypeEnumItemDecl, + FieldDecl, + StructDecl, + TraitDecl, + NodeData, + Impl, + Node, } use std::jule::lex::{ - File, - Token, - TokenId, - TokenKind, - Ident, - IsIgnoreIdent, + File, + Token, + TokenId, + TokenKind, + Ident, + IsIgnoreIdent, } use std::jule::build::{ - LogMsg, - Log, - LogKind, - Logf, - IsTopDirective, + LogMsg, + Log, + LogKind, + Logf, + IsTopDirective, } use mod for std::jule::internal::mod use strings for std::strings::{StrBuilder} fn makeErr(row: int, col: int, &f: &File, fmt: LogMsg, args: ...any): Log { - ret Log{ - Kind: LogKind.Error, - Row: row, - Column: col, - Path: f.Path, - Text: Logf(fmt, args...), - } + ret Log{ + Kind: LogKind.Error, + Row: row, + Column: col, + Path: f.Path, + Text: Logf(fmt, args...), + } } // Returns between of open and close ranges. @@ -67,26 +67,26 @@ fn makeErr(row: int, col: int, &f: &File, fmt: LogMsg, args: ...any): Log { // range(i, open, close, tokens) = nil if i > len(tokens) // range(i, open, close, tokens) = nil if tokens[i].Id != open fn range(mut &i: int, open: TokenId, close: TokenId, mut &tokens: []&Token): []&Token { - if i >= len(tokens) { - ret nil - } - tok := tokens[i] - if tok.Id != open { - ret nil - } - i++ - mut rangeN := 1 - start := i - for rangeN != 0 && i < len(tokens); i++ { - token := tokens[i] - match token.Id { - | open: - rangeN++ - | close: - rangeN-- - } - } - ret tokens[start:i-1] + if i >= len(tokens) { + ret nil + } + tok := tokens[i] + if tok.Id != open { + ret nil + } + i++ + mut rangeN := 1 + start := i + for rangeN != 0 && i < len(tokens); i++ { + token := tokens[i] + match token.Id { + | open: + rangeN++ + | close: + rangeN-- + } + } + ret tokens[start:i-1] } // rangeLast returns last range from tokens. @@ -97,35 +97,35 @@ fn range(mut &i: int, open: TokenId, close: TokenId, mut &tokens: []&Token): []& // rangeLast(tokens) = tokens, nil if len(tokens) == 0 // rangeLast(tokens) = tokens, nil if tokens is not has range at last fn rangeLast(mut &tokens: []&Token): (cutted: []&Token, cut: []&Token) { - if len(tokens) == 0 { - ret tokens, nil - } - first := tokens[len(tokens)-1].Id - if first != TokenId.RBrace && - first != TokenId.LBracket && - first != TokenId.RParent { - ret tokens, nil - } - mut braceN := 0 - mut i := len(tokens) - 1 - for i >= 0; i-- { - token := tokens[i] - match token.Id { - | TokenId.RBrace - | TokenId.RBracket - | TokenId.RParent: - braceN++ - continue - | TokenId.LBrace - | TokenId.LBracket - | TokenId.LParent: - braceN-- - } - if braceN == 0 { - ret tokens[:i], tokens[i:] - } - } - ret tokens, nil + if len(tokens) == 0 { + ret tokens, nil + } + first := tokens[len(tokens)-1].Id + if first != TokenId.RBrace && + first != TokenId.LBracket && + first != TokenId.RParent { + ret tokens, nil + } + mut braceN := 0 + mut i := len(tokens) - 1 + for i >= 0; i-- { + token := tokens[i] + match token.Id { + | TokenId.RBrace + | TokenId.RBracket + | TokenId.RParent: + braceN++ + continue + | TokenId.LBrace + | TokenId.LBracket + | TokenId.LParent: + braceN-- + } + if braceN == 0 { + ret tokens[:i], tokens[i:] + } + } + ret tokens, nil } // Returns parts separated by given token identifier. @@ -135,1803 +135,1803 @@ fn rangeLast(mut &tokens: []&Token): (cutted: []&Token, cut: []&Token) { // Special case is; // parts(tokens) = nil if len(tokens) == 0 fn parts(mut &tokens: []&Token, id: TokenId, exprMust: bool): (parts: [][]&Token, errors: []Log) { - if len(tokens) == 0 { - ret nil, nil - } - mut rangeN := 0 - mut last := 0 - for i, token in tokens { - match token.Id { - | TokenId.LBrace | TokenId.LBracket | TokenId.LParent: - rangeN++ - | TokenId.RBrace | TokenId.RBracket | TokenId.RParent: - rangeN-- - | id: - if rangeN > 0 { - continue - } - if exprMust && i-last <= 0 { - err := makeErr(token.Row, token.Column, token.File, LogMsg.MissingExpr) - errors = append(errors, err) - } - parts = append(parts, tokens[last:i]) - last = i + 1 - } - } - if last < len(tokens) { - parts = append(parts, tokens[last:]) - } - ret + if len(tokens) == 0 { + ret nil, nil + } + mut rangeN := 0 + mut last := 0 + for i, token in tokens { + match token.Id { + | TokenId.LBrace | TokenId.LBracket | TokenId.LParent: + rangeN++ + | TokenId.RBrace | TokenId.RBracket | TokenId.RParent: + rangeN-- + | id: + if rangeN > 0 { + continue + } + if exprMust && i-last <= 0 { + err := makeErr(token.Row, token.Column, token.File, LogMsg.MissingExpr) + errors = append(errors, err) + } + parts = append(parts, tokens[last:i]) + last = i + 1 + } + } + if last < len(tokens) { + parts = append(parts, tokens[last:]) + } + ret } fn getCloseOfBrace(left: TokenId): TokenId { - match left { - | TokenId.RParent: - ret TokenId.LParent - | TokenId.RBrace: - ret TokenId.LBrace - | TokenId.RBracket: - ret TokenId.LBracket - |: - ret left - } + match left { + | TokenId.RParent: + ret TokenId.LParent + | TokenId.RBrace: + ret TokenId.LBrace + | TokenId.RBracket: + ret TokenId.LBracket + |: + ret left + } } fn compilerErr(&token: &Token, &fmt: LogMsg, args: ...any): Log { - ret Log{ - Kind: LogKind.Error, - Row: token.Row, - Column: token.Column, - Path: token.File.Path, - Text: Logf(fmt, args...), - Line: token.File.GetRow(token.Row), - } + ret Log{ + Kind: LogKind.Error, + Row: token.Row, + Column: token.Column, + Path: token.File.Path, + Text: Logf(fmt, args...), + Line: token.File.GetRow(token.Row), + } } unsafe fn pushSuggestion(mut log: *Log, fmt: LogMsg, args: ...any) { - log.Suggestion = Logf(fmt, args...) + log.Suggestion = Logf(fmt, args...) } struct parser { - ast: &Ast - directives: []&Directive - errors: []Log + ast: &Ast + directives: []&Directive + errors: []Log - ep: &exprBuilder + ep: &exprBuilder } impl parser { - fn stop(mut self) { self.ast = nil } - fn stopped(self): bool { ret self.ast == nil } - - // Appends error by specified token, key and args. - fn pushErr(mut self, token: &Token, fmt: LogMsg, args: ...any) { - self.errors = append(self.errors, compilerErr(token, fmt, args...)) - } - - // Push suggestion to last log. - fn pushSuggestion(mut self, fmt: LogMsg, args: ...any) { - unsafe { pushSuggestion(&self.errors[len(self.errors)-1], fmt, args...) } - } - - fn buildExpr(mut &self, mut &tokens: []&Token): &Expr { - ret self.ep.buildFromTokens(tokens) - } - - fn buildDirective(mut self, mut tokens: []&Token): &Directive { - if len(tokens) == 1 { - self.pushErr(tokens[0], LogMsg.InvalidSyntax) - ret nil - } - if tokens[1].Column != tokens[0].Column+1 { - self.pushErr(tokens[0], LogMsg.InvalidSyntax) - ret nil - } - ret &Directive{ - Tag: tokens[1], - Args: tokens[2:], // Start 2 to skip '#', and tag tokens. - } - } - - fn pushDirective(mut self, mut d: &Directive) { - if d == nil { - ret - } - // Don't append if already added this directive. - for _, pd in self.directives { - if d.Tag.Kind == pd.Tag.Kind { - ret - } - } - self.directives = append(self.directives, d) - } - - fn buildScope(mut &self, mut &tokens: []&Token, mut end: &Token): &ScopeTree { - mut s := newScope() - s.End = end - mut sp := scopeParser{ - p: self, - } - sp.build(tokens, s) - ret s - } - - unsafe fn _buildType(mut &self, mut &tokens: []&Token, - mut i: *int, err: bool): (&TypeDecl, bool) { - mut tb := typeBuilder{ - p: self, - tokens: tokens, - i: i, - err: err, - } - ret tb.build() - } - - // Builds AST model of data-type. - unsafe fn buildType(mut &self, mut &tokens: []&Token, - mut i: *int, err: bool): (&TypeDecl, bool) { - token := tokens[*i] - mut t, ok := self._buildType(tokens, i, err) - if err && !ok { - self.pushErr(token, LogMsg.InvalidType) - } - ret t, ok - } - - fn buildTypeAliasDecl(mut &self, mut &tokens: []&Token): &TypeAliasDecl { - mut i := 1 // Skip "type" keyword. - if i >= len(tokens) { - self.pushErr(tokens[i-1], LogMsg.InvalidSyntax) - ret nil - } - mut tad := &TypeAliasDecl{ - Token: tokens[1], - Ident: tokens[1].Kind, - } - mut token := tokens[i] - if token.Id != TokenId.Ident { - self.pushErr(token, LogMsg.InvalidSyntax) - self.pushSuggestion(LogMsg.ExpectedIdentifier) - } - i++ - if i >= len(tokens) { - self.pushErr(tokens[i-1], LogMsg.InvalidSyntax) - ret tad - } - token = tokens[i] - if token.Id != TokenId.Colon { - self.pushErr(tokens[i-1], LogMsg.InvalidSyntax) - self.pushSuggestion(LogMsg.ExpectedColon) - ret tad - } - i++ - if i >= len(tokens) { - self.pushErr(tokens[i-1], LogMsg.MissingType) - ret tad - } - mut t, ok := unsafe { self.buildType(tokens, &i, true) } - tad.Kind = t - if ok && i < len(tokens) { - self.pushErr(tokens[i], LogMsg.InvalidSyntax) - } - tad.Public = mod::IsPub(tad.Ident) - ret tad - } - - fn buildVarTypeAndExpr(mut &self, mut &v: &VarDecl, mut &tokens: []&Token) { - mut i := 0 - mut tok := tokens[i] - if tok.Id == TokenId.Colon { - i++ // Skip type annotation operator (:) - if i >= len(tokens) || tokens[i].Id == TokenId.Eq { - self.pushErr(tok, LogMsg.MissingType) - ret - } - mut t, ok := unsafe { self.buildType(tokens, &i, true) } - if ok { - v.Kind = t - if i >= len(tokens) { - ret - } - tok = tokens[i] - } - } - - if tok.Id != TokenId.Eq { - self.pushErr(tok, LogMsg.InvalidSyntax) - ret - } - v.Setter = tok - - mut exprTokens := tokens[i+1:] - if len(exprTokens) == 0 { - self.pushErr(tok, LogMsg.MissingExpr) - ret - } - v.Expr = self.buildExpr(exprTokens) - } - - fn buildVarCommon(mut &self, mut &v: &VarDecl, mut tokens: []&Token) { - v.Token = tokens[0] - if v.Token.Id != TokenId.Ident { - self.pushErr(v.Token, LogMsg.InvalidSyntax) - self.pushSuggestion(LogMsg.ExpectedIdentifier) - ret - } - v.Ident = v.Token.Kind - v.Public = mod::IsPub(v.Ident) - v.Kind = nil // For auto-type. - if len(tokens) > 1 { - tokens = tokens[1:] // Remove identifier. - self.buildVarTypeAndExpr(v, tokens) - } - } - - fn buildVarBegin(mut self, mut &v: &VarDecl, mut &tokens: []&Token) { - tok := tokens[0] - match tok.Id { - | TokenId.Static: - v.Statically = true - fall - | TokenId.Let: - // Initialize 1 for skip the let keyword - if len(tokens) == 1 { - tokens = nil - self.pushErr(tok, LogMsg.InvalidSyntax) - ret - } - tokens = tokens[1:] - if tokens[0].Id == TokenId.Mut { - v.Mutable = true - // Skip the mut keyword - tokens = tokens[1:] - } - | TokenId.Const: - v.Constant = true - tokens = tokens[1:] - |: - tokens = nil - self.pushErr(tok, LogMsg.InvalidSyntax) - } - } - - fn buildVar(mut &self, mut tokens: []&Token): &VarDecl { - mut v := &VarDecl{ - Token: tokens[0], - } - self.buildVarBegin(v, tokens) - if len(tokens) == 0 { - ret nil - } - if tokens[0].Id == TokenId.Amper { - v.Reference = true - if len(tokens) == 1 { - ret nil - } - tokens = tokens[1:] - } - self.buildVarCommon(v, tokens) - ret v - } - - fn buildGeneric(mut &self, mut &tokens: []&Token): &GenericDecl { - mut g := &GenericDecl{ - Token: tokens[0], - } - if g.Token.Id != TokenId.Ident { - self.pushErr(g.Token, LogMsg.InvalidSyntax) - self.pushSuggestion(LogMsg.ExpectedIdentifier) - } - g.Ident = g.Token.Kind - if len(tokens) > 1 { - if tokens[1].Id != TokenId.Colon { - self.pushErr(tokens[1], LogMsg.InvalidSyntax) - ret nil - } - if len(tokens) == 2 { - self.pushErr(tokens[1], LogMsg.MissingExpr) - ret nil - } - mut constraintTokens := tokens[2:] - mut parts, errors := parts(constraintTokens, TokenId.Vline, true) - if len(errors) > 0 { - self.errors = append(self.errors, errors...) - ret nil - } - g.Constraint = &Constraint{Mask: make([]&TypeDecl, 0, len(parts))} - for (_, mut part) in parts { - mut i := 0 - mut kind, _ := unsafe { self.buildType(part, &i, true) } - g.Constraint.Mask = append(g.Constraint.Mask, kind) - if i < len(part) { - self.pushErr(part[i], LogMsg.InvalidSyntax) - } - } - } - ret g - } - - fn buildGenerics(mut &self, mut &tokens: []&Token, &errorToken: &Token): []&GenericDecl { - if len(tokens) == 0 { - self.pushErr(errorToken, LogMsg.MissingExpr) - ret nil - } - - mut parts, errors := parts(tokens, TokenId.Comma, true) - if len(errors) > 0 { - self.errors = append(self.errors, errors...) - ret nil - } - - mut generics := make([]&GenericDecl, 0, len(parts)) - for (_, mut part) in parts { - generics = append(generics, self.buildGeneric(part)) - } - - ret generics - } - - fn buildSelfParam(mut self, mut tokens: []&Token): &ParamDecl { - if len(tokens) == 0 { - ret nil - } - - mut param := new(ParamDecl) - - // Detects mut keyword. - if tokens[0].Id == TokenId.Mut { - param.Mutable = true - if len(tokens) == 1 { - self.pushErr(tokens[0], LogMsg.InvalidSyntax) - ret nil - } - tokens = tokens[1:] - } - - mut ident := StrBuilder.New(5) - - if tokens[0].Id == TokenId.Amper { - ident.WriteStr(TokenKind.Amper) - if len(tokens) == 1 { - self.pushErr(tokens[0], LogMsg.InvalidSyntax) - ret nil - } - tokens = tokens[1:] - } - - if tokens[0].Id == TokenId.Self { - ident.WriteStr(str(TokenKind.Self)) - param.Token = tokens[0] - if len(tokens) != 1 { - self.pushErr(tokens[1], LogMsg.InvalidSyntax) - } - } - - param.Ident = ident.Str() - ret param - } - - fn paramTypeBegin(mut self, mut ¶m: &ParamDecl, mut &i: int, &tokens: []&Token) { - for i < len(tokens); i++ { - token := tokens[i] - if token.Id != TokenId.TripleDot { - ret - } - - if param.Variadic { - self.pushErr(token, LogMsg.AlreadyVariadic) - continue - } - param.Variadic = true - } - } - - fn buildParamType(mut &self, mut ¶m: &ParamDecl, mut &tokens: []&Token) { - mut i := 0 - self.paramTypeBegin(param, i, tokens) - if i >= len(tokens) { - ret - } - - param.Kind, _ = unsafe { self.buildType(tokens, &i, true) } - if i < len(tokens) { - self.pushErr(tokens[i], LogMsg.InvalidSyntax) - } - } - - fn buildParamBody(mut &self, mut ¶m: &ParamDecl, mut tokens: []&Token) { - mut tok := tokens[0] - if len(tokens) == 1 { - // Just identifier token. - param.Ident = tok.Kind - ret - } else if len(tokens) < 3 { - self.pushErr(tok, LogMsg.MissingType) - ret - } - if tokens[1].Id != TokenId.Colon { - param.Ident = Ident.Anon - self.buildParamType(param, tokens) - ret - } - param.Ident = tok.Kind - tokens = tokens[2:] // Skip colon - self.buildParamType(param, tokens) - } - - fn buildParam(mut &self, mut tokens: []&Token): &ParamDecl { - mut param := &ParamDecl{ - Token: tokens[0], - } - - // Detects mut keyword. - if param.Token.Id == TokenId.Mut { - param.Mutable = true - if len(tokens) == 1 { - self.pushErr(tokens[0], LogMsg.InvalidSyntax) - ret nil - } - tokens = tokens[1:] - param.Token = tokens[0] - } - - // Catch reference parameters. - if len(tokens) >= 3 { - if param.Token.Id == TokenId.Amper { - if len(tokens) == 1 { - self.pushErr(tokens[0], LogMsg.InvalidSyntax) - ret nil - } - - if tokens[1].Id == TokenId.Ident && tokens[2].Id == TokenId.Colon { - param.Reference = true - tokens = tokens[1:] - param.Token = tokens[0] - } - } - } - - if param.Token.Id != TokenId.Ident { - // Just data type - param.Ident = Ident.Anon - self.buildParamType(param, tokens) - } else { - self.buildParamBody(param, tokens) - } - - ret param - } - - fn checkParams(mut self, mut ¶ms: []&ParamDecl) { - for (_, mut param) in params { - if param.IsSelf() || param.Kind != nil { - continue - } - if param.Token == nil { - self.pushErr(param.Token, LogMsg.MissingType) - } else { - param.Kind = &TypeDecl{ - Token: param.Token, - Kind: &IdentTypeDecl{ - Token: param.Token, - Ident: param.Token.Kind, - }, - } - param.Ident = Ident.Anon - } - } - } - - fn buildParams(mut &self, mut &tokens: []&Token, method: bool): []&ParamDecl { - mut parts, errs := parts(tokens, TokenId.Comma, true) - self.errors = append(self.errors, errs...) - if len(parts) == 0 { - ret nil - } - - let mut params: []&ParamDecl = nil - if method && len(parts) > 0 { - mut param := self.buildSelfParam(parts[0]) - if param != nil && param.IsSelf() { - params = append(params, param) - parts = parts[1:] - } - } - - for (_, mut part) in parts { - if len(part) == 0 { - continue - } - mut param := self.buildParam(part) - if param != nil { - params = append(params, param) - } - } - - self.checkParams(params) - ret params - } - - fn buildMultiRetType(mut &self, mut &tokens: []&Token, mut &i: int): (t: &RetTypeDecl, ok: bool) { - t = new(RetTypeDecl) - i++ - if i >= len(tokens) { - i-- - t.Kind, ok = unsafe { self.buildType(tokens, &i, false) } - ret - } - - i-- // For point to parentheses - ( - - mut rangeTokens := range(i, TokenId.LParent, TokenId.RParent, tokens) - - mut parts, errs := parts(rangeTokens, TokenId.Comma, true) - self.errors = append(self.errors, errs...) - if len(parts) == 0 { - ret - } - - mut types := make([]&TypeDecl, 0, len(parts)) - t.Idents = make([]&Token, 0, len(parts)) - for (_, mut part) in parts { - if len(part) == 0 { - continue - } - mut token := part[0] - mut offset := 0 - - // Check type annotation. - if len(part) > 1 { - token = part[1] - if token.Id == TokenId.Colon { - offset = 2 - if len(part) < 3 { - self.pushErr(token, LogMsg.MissingType) - continue - } - } - } - - token = part[0] - if offset != 2 { - mut newToken := new(Token, *token) - newToken.Kind = Ident.Anon - t.Idents = append(t.Idents, newToken) - } else { - t.Idents = append(t.Idents, token) - } - - mut tk, _ := unsafe { self.buildType(part, &offset, true) } - if offset < len(part) { - self.pushErr(part[offset], LogMsg.InvalidSyntax) - } - types = append(types, tk) - } - - if len(types) > 1 { - t.Kind = &TypeDecl{ - Token: tokens[0], - Kind: &TupleTypeDecl{ - Types: types, - }, - } - } else { - t.Kind = types[0] - } - - ok = true - ret - } - - // Builds function return type from tokens. - fn buildRetType(mut &self, mut &tokens: []&Token, mut &i: int): (t: &RetTypeDecl, ok: bool) { - t = new(RetTypeDecl) - if i >= len(tokens) { - ret - } - - mut token := tokens[i] - match token.Id { - | TokenId.LBrace: - ret - | TokenId.Eq: - ret - | TokenId.Colon: - if i+1 >= len(tokens) { - self.pushErr(token, LogMsg.MissingType) - ret - } - - i++ - token = tokens[i] - match token.Id { - | TokenId.LParent: - t, ok = self.buildMultiRetType(tokens, i) - ret - | TokenId.LBrace: - self.pushErr(token, LogMsg.MissingType) - ret - } - t.Kind, ok = unsafe { self.buildType(tokens, &i, true) } - ret - } - i++ - self.pushErr(token, LogMsg.InvalidSyntax) - ret - } - - // Build function prototype. - // Body is not necessary for successfull parsing. - // Just declration. - fn buildFnPrototype(mut &self, mut &tokens: []&Token, mut &i: int, method: bool): &FnDecl { - mut f := &FnDecl{ - Token: tokens[i], - } - - // Detect static keyword. - if f.Token.Id == TokenId.Static { - f.Statically = true - i++ - if i >= len(tokens) { - self.pushErr(f.Token, LogMsg.InvalidSyntax) - ret nil - } - f.Token = tokens[i] - } - - // Detect unsafe keyword. - if f.Token.Id == TokenId.Unsafe { - f.Unsafety = true - i++ - if i >= len(tokens) { - self.pushErr(f.Token, LogMsg.InvalidSyntax) - ret nil - } - f.Token = tokens[i] - } - - // Skips fn token. - i++ - if i >= len(tokens) { - self.pushErr(f.Token, LogMsg.InvalidSyntax) - ret nil - } - - tok := tokens[i] - if tok.Id == TokenId.Ident { - i++ - if i >= len(tokens) { - self.pushErr(f.Token, LogMsg.InvalidSyntax) - ret nil - } - f.Ident = tok.Kind - } else { - f.Ident = Ident.Anon - } - - errorToken := tokens[i] - mut genericsTokens := range(i, TokenId.LBracket, TokenId.RBracket, tokens) - if genericsTokens != nil { - f.Generics = self.buildGenerics(genericsTokens, errorToken) - } - - if tokens[i].Id != TokenId.LParent { - self.pushErr(tokens[i], LogMsg.MissingFnParentheses) - ret nil - } - - mut paramsToks := range(i, TokenId.LParent, TokenId.RParent, tokens) - if len(paramsToks) > 0 { - f.Params = self.buildParams(paramsToks, method) - } - - if i < len(tokens) { - token := tokens[i] - if token.Id == TokenId.Excl { - f.Exceptional = true - i++ - } - } - - f.Public = mod::IsPub(f.Ident) - f.Result, _ = self.buildRetType(tokens, i) - ret f - } - - // Parses function define. - // Prototype and body. - fn buildFn(mut &self, mut &tokens: []&Token, method: bool, prototype: bool): &FnDecl { - mut i := 0 - mut f := self.buildFnPrototype(tokens, i, method) - if prototype { - if i < len(tokens) { - self.pushErr(tokens[i+1], LogMsg.InvalidSyntax) - } - ret f - } else if f == nil { - ret f - } - - if i >= len(tokens) { - self.stop() - self.pushErr(f.Token, LogMsg.BodyNotExist) - self.pushSuggestion(LogMsg.ExpectedBody) - ret nil - } - mut blockTokens := range(i, TokenId.LBrace, TokenId.RBrace, tokens) - if blockTokens != nil { - f.Scope = self.buildScope(blockTokens, tokens[i-1]) - f.Scope.Unsafety = f.Unsafety - if i < len(tokens) { - self.pushErr(tokens[i], LogMsg.InvalidSyntax) - } - } else { - self.stop() - self.pushErr(f.Token, LogMsg.BodyNotExist) - self.pushSuggestion(LogMsg.ExpectedBody) - ret nil - } - ret f - } - - fn getUseDeclSelectors(mut self, mut tokens: []&Token): []&Token { - mut i := 0 - tokens = range(i, TokenId.LBrace, TokenId.RBrace, tokens) - mut parts, errs := parts(tokens, TokenId.Comma, true) - if len(errs) > 0 { - self.errors = append(self.errors, errs...) - ret nil - } - - mut selectors := make([]&Token, 0, len(parts)) - for (_, mut part) in parts { - if len(part) > 1 { - self.pushErr(part[1], LogMsg.InvalidSyntax) - } - mut tok := part[0] - if tok.Id != TokenId.Ident && tok.Id != TokenId.Self { - self.pushErr(tok, LogMsg.InvalidSyntax) - self.pushSuggestion(LogMsg.ExpectedIdentifier) - continue - } - selectors = append(selectors, tok) - } - ret selectors - } - - fn buildBindUseDecl(mut self, mut &decl: &UseDecl, &tokens: []&Token) { - if len(tokens) > 1 { - self.pushErr(tokens[1], LogMsg.InvalidSyntax) - } - token := tokens[0] - if token.Id != TokenId.Lit || (token.Kind[0] != '`' && token.Kind[0] != '"') { - self.pushErr(token, LogMsg.InvalidExpr) - ret - } - decl.Binded = true - decl.LinkPath = token.Kind[1:len(token.Kind)-1] - } - - fn useDeclTokstoa(mut self, &tokens: []&Token): str { - mut n := 0 - for _, token in tokens { - if token.Id != TokenId.Ident && token.Id != TokenId.DblColon { - self.pushErr(token, LogMsg.InvalidSyntax) - } - n += len(token.Kind) - } - mut s := StrBuilder.New(n) - for _, token in tokens { - s.WriteStr(token.Kind) - } - ret s.Str() - } - - fn buildStdUseDecl(mut self, mut &decl: &UseDecl, mut tokens: []&Token) { - decl.Std = true - - mut token := tokens[0] - if len(tokens) < 3 { - self.pushErr(token, LogMsg.InvalidSyntax) - ret - } - - tokens = tokens[2:] - token = tokens[len(tokens)-1] - match token.Id { - | TokenId.DblColon: - self.pushErr(token, LogMsg.InvalidSyntax) - ret - | TokenId.RBrace: - let mut selectors: []&Token = nil - tokens, selectors = rangeLast(tokens) - decl.Selected = self.getUseDeclSelectors(selectors) - if len(tokens) == 0 { - self.pushErr(token, LogMsg.InvalidSyntax) - ret - } - token = tokens[len(tokens)-1] - if token.Id != TokenId.DblColon { - self.pushErr(token, LogMsg.InvalidSyntax) - ret - } - tokens = tokens[:len(tokens)-1] - if len(tokens) == 0 { - self.pushErr(token, LogMsg.InvalidSyntax) - ret - } - | TokenId.Star: - tokens = tokens[:len(tokens)-1] - if len(tokens) == 0 { - self.pushErr(token, LogMsg.InvalidSyntax) - ret - } - token = tokens[len(tokens)-1] - if token.Id != TokenId.DblColon { - self.pushErr(token, LogMsg.InvalidSyntax) - ret - } - tokens = tokens[:len(tokens)-1] - if len(tokens) == 0 { - self.pushErr(token, LogMsg.InvalidSyntax) - ret - } - decl.Full = true - } - if len(tokens) == 1 && tokens[0].Id == TokenId.Unsafe { // Is std::unsafe? - decl.LinkPath = "std::unsafe" - } else { - decl.LinkPath = "std::" + self.useDeclTokstoa(tokens) - } - } - - fn buildIdentUseDecl(mut self, mut &decl: &UseDecl, mut tokens: []&Token) { - decl.Std = false - - mut token := tokens[len(tokens)-1] - match token.Id { - | TokenId.DblColon: - self.pushErr(token, LogMsg.InvalidSyntax) - ret - | TokenId.RBrace: - let mut selectors: []&Token = nil - tokens, selectors = rangeLast(tokens) - decl.Selected = self.getUseDeclSelectors(selectors) - if len(tokens) == 0 { - self.pushErr(token, LogMsg.InvalidSyntax) - ret - } - token = tokens[len(tokens)-1] - if token.Id != TokenId.DblColon { - self.pushErr(token, LogMsg.InvalidSyntax) - ret - } - tokens = tokens[:len(tokens)-1] - if len(tokens) == 0 { - self.pushErr(token, LogMsg.InvalidSyntax) - ret - } - | TokenId.Star: - tokens = tokens[:len(tokens)-1] - if len(tokens) == 0 { - self.pushErr(token, LogMsg.InvalidSyntax) - ret - } - token = tokens[len(tokens)-1] - if token.Id != TokenId.DblColon { - self.pushErr(token, LogMsg.InvalidSyntax) - ret - } - tokens = tokens[:len(tokens)-1] - if len(tokens) == 0 { - self.pushErr(token, LogMsg.InvalidSyntax) - ret - } - decl.Full = true - } - - decl.LinkPath = self.useDeclTokstoa(tokens) - } - - fn parseUseDecl(mut self, mut &decl: &UseDecl, mut tokens: []&Token) { - if decl.Binded { - self.buildBindUseDecl(decl, tokens) - ret - } - - mut token := tokens[0] - if token.Id != TokenId.Ident { - self.pushErr(token, LogMsg.InvalidSyntax) - self.pushSuggestion(LogMsg.ExpectedIdentifier) - ret - } - - if len(tokens) > 2 && tokens[1].Id == TokenId.For { - decl.Alias = token.Kind - if tokens[2].Id != TokenId.Ident { - self.pushErr(token, LogMsg.InvalidSyntax) - self.pushSuggestion(LogMsg.ExpectedIdentifier) - ret - } - tokens = tokens[2:] - token = tokens[0] - } - - const StdlibPrefix = "std" - - match { - | token.Kind == StdlibPrefix: - self.buildStdUseDecl(decl, tokens) - |: - self.buildIdentUseDecl(decl, tokens) - } - } - - fn buildUseDecl(mut self, mut tokens: []&Token, binded: bool): &UseDecl { - mut decl := &UseDecl{ - Token: tokens[0], - Binded: binded, - } - if len(tokens) < 2 { - self.pushErr(decl.Token, LogMsg.MissingUsePath) - ret nil - } - tokens = tokens[1:] // Skip "use" keyword. - self.parseUseDecl(decl, tokens) - ret decl - } - - fn buildTypeEnumItemKind(mut &self, mut &i: int, mut &tokens: []&Token): &TypeDecl { - mut braceN := 0 - exprStart := i - for i < len(tokens); i++ { - t := tokens[i] - match t.Id { - | TokenId.LBrace - | TokenId.LBracket - | TokenId.LParent: - braceN++ - continue - | TokenId.RBrace - | TokenId.RBracket - | TokenId.RParent: - braceN-- - } - if braceN > 0 { - continue - } - if t.Id == TokenId.Comma || i+1 >= len(tokens) { - let mut kindTokens: []&Token = nil - if t.Id == TokenId.Comma { - kindTokens = tokens[exprStart:i] - } else { - kindTokens = tokens[exprStart:] - } - mut j := 0 - mut kind, _ := unsafe { self.buildType(kindTokens, &j, true) } - if j < len(kindTokens) { - self.pushErr(kindTokens[j], LogMsg.InvalidSyntax) - } - ret kind - } - } - ret nil - } - - fn buildTypeEnumItems(mut &self, mut &tokens: []&Token): []&TypeEnumItemDecl { - mut items := make([]&TypeEnumItemDecl, 0, 1) - mut i := 0 - for i < len(tokens); i++ { - mut t := tokens[i] - mut item := new(TypeEnumItemDecl) - item.Token = t - if item.Token.Id == TokenId.Ident && len(tokens)-i > 2 { - t = tokens[i+1] - if t.Id == TokenId.Colon { - item.Ident = item.Token.Kind - i += 2 - if i >= len(tokens) || tokens[i].Id == TokenId.Comma { - self.pushErr(t, LogMsg.MissingType) - continue - } - } - } - item.Kind = self.buildTypeEnumItemKind(i, tokens) - items = append(items, item) - } - ret items - } - - fn buildTypeEnumDecl(mut &self, mut &tokens: []&Token): &TypeEnumDecl { - mut i := 1 - mut e := &TypeEnumDecl{ - // Skip "enum" tokens. - Token: tokens[i], - } - if e.Token.Id != TokenId.Ident { - self.pushErr(e.Token, LogMsg.InvalidSyntax) - self.pushSuggestion(LogMsg.ExpectedIdentifier) - } - e.Ident = e.Token.Kind - i += 3 // Skip "identifier: type" tokens. - mut itemTokens := range(i, TokenId.LBrace, TokenId.RBrace, tokens) - if itemTokens == nil { - self.stop() - self.pushErr(e.Token, LogMsg.BodyNotExist) - self.pushSuggestion(LogMsg.ExpectedBody) - ret e - } else if i < len(tokens) { - self.pushErr(tokens[i], LogMsg.InvalidSyntax) - } - e.Public = mod::IsPub(e.Ident) - e.End = tokens[i-1] - e.Items = self.buildTypeEnumItems(itemTokens) - ret e - } - - fn buildEnumItemExpr(mut &self, mut &i: int, mut &tokens: []&Token): &Expr { - mut braceN := 0 - exprStart := i - for i < len(tokens); i++ { - t := tokens[i] - match t.Id { - | TokenId.LBrace - | TokenId.LBracket - | TokenId.LParent: - braceN++ - continue - | TokenId.RBrace - | TokenId.RBracket - | TokenId.RParent: - braceN-- - } - if braceN > 0 { - continue - } - if t.Id == TokenId.Comma || i+1 >= len(tokens) { - let mut exprTokens: []&Token = nil - if t.Id == TokenId.Comma { - exprTokens = tokens[exprStart:i] - } else { - exprTokens = tokens[exprStart:] - } - ret self.buildExpr(exprTokens) - } - } - ret nil - } - - fn buildEnumItems(mut &self, mut &tokens: []&Token): []&EnumItemDecl { - mut items := make([]&EnumItemDecl, 0, 1) - mut i := 0 - for i < len(tokens); i++ { - mut t := tokens[i] - mut item := new(EnumItemDecl) - item.Token = t - if item.Token.Id != TokenId.Ident { - self.pushErr(item.Token, LogMsg.InvalidSyntax) - self.pushSuggestion(LogMsg.ExpectedIdentifier) - } - item.Ident = item.Token.Kind - if i+1 >= len(tokens) || tokens[i+1].Id == TokenId.Comma { - if i+1 < len(tokens) { - i++ - } - items = append(items, item) - continue - } - i++ - t = tokens[i] - i++ - if t.Id != TokenId.Colon { - self.pushErr(t, LogMsg.InvalidSyntax) - self.pushSuggestion(LogMsg.ExpectedColonForAssign) - continue - } - if i >= len(tokens) || tokens[i].Id == TokenId.Comma { - self.pushErr(t, LogMsg.MissingExpr) - continue - } - item.Expr = self.buildEnumItemExpr(i, tokens) - items = append(items, item) - } - ret items - } - - fn buildEnumDecl(mut &self, mut &tokens: []&Token): &EnumDecl { - if len(tokens) < 3 { - self.pushErr(tokens[0], LogMsg.InvalidSyntax) - ret nil - } - mut e := &EnumDecl{ - Token: tokens[1], - } - if e.Token.Id != TokenId.Ident { - self.pushErr(e.Token, LogMsg.InvalidSyntax) - self.pushSuggestion(LogMsg.ExpectedIdentifier) - } - e.Ident = e.Token.Kind - mut i := 2 - if tokens[i].Id == TokenId.Colon { - i++ - if i >= len(tokens) { - self.pushErr(tokens[i-1], LogMsg.InvalidSyntax) - ret e - } - e.Kind, _ = unsafe { self.buildType(tokens, &i, true) } - if i >= len(tokens) { - self.stop() - self.pushErr(e.Token, LogMsg.BodyNotExist) - self.pushSuggestion(LogMsg.ExpectedBody) - ret e - } - } else { - e.Kind = nil - } - mut itemTokens := range(i, TokenId.LBrace, TokenId.RBrace, tokens) - if itemTokens == nil { - self.stop() - self.pushErr(e.Token, LogMsg.BodyNotExist) - self.pushSuggestion(LogMsg.ExpectedBody) - ret e - } else if i < len(tokens) { - self.pushErr(tokens[i], LogMsg.InvalidSyntax) - } - e.Public = mod::IsPub(e.Ident) - e.End = tokens[i-1] - e.Items = self.buildEnumItems(itemTokens) - ret e - } - - fn buildNodeEnumDecl(mut &self, mut &tokens: []&Token): NodeData { - if len(tokens) > 3 && tokens[2].Id == TokenId.Colon { - if tokens[3].Id == TokenId.Type { - ret self.buildTypeEnumDecl(tokens) - } - } - ret self.buildEnumDecl(tokens) - } - - fn buildField(mut &self, mut tokens: []&Token): &FieldDecl { - mut f := new(FieldDecl) - - f.Mutable = tokens[0].Id == TokenId.Mut - if f.Mutable { - if len(tokens) == 1 { - self.pushErr(tokens[0], LogMsg.InvalidSyntax) - ret nil - } - tokens = tokens[1:] - } - - f.Token = tokens[0] - if f.Token.Id != TokenId.Ident { - self.pushErr(f.Token, LogMsg.InvalidSyntax) - self.pushSuggestion(LogMsg.ExpectedIdentifier) - ret nil - } - f.Ident = f.Token.Kind - - if len(tokens) == 1 { - self.pushErr(tokens[0], LogMsg.MissingType) - ret nil - } else if len(tokens) < 3 || tokens[1].Id != TokenId.Colon { - self.pushErr(tokens[1], LogMsg.MissingType) - ret nil - } - - tokens = tokens[2:] // Remove identifier and colon tokens. - mut i := 0 - f.Kind, _ = unsafe { self.buildType(tokens, &i, true) } - if i < len(tokens) { - token := tokens[i] - if token.Id != TokenId.Eq { - self.pushErr(tokens[i], LogMsg.InvalidSyntax) - ret nil - } - i++ - if i >= len(tokens) { - self.pushErr(token, LogMsg.MissingExpr) - ret nil - } - tokens = tokens[i:] - f.Default = self.buildExpr(tokens) - } - f.Public = mod::IsPub(f.Ident) - ret f - } - - fn buildStructDeclFields(mut &self, mut tokens: []&Token): []&FieldDecl { - let mut fields: []&FieldDecl = nil - mut stmts := splitStmts(tokens) - for (_, mut stmt) in stmts { - tokens = stmt.tokens - mut f := self.buildField(tokens) - fields = append(fields, f) - } - ret fields - } - - fn buildStructDecl(mut &self, mut &tokens: []&Token): &StructDecl { - if len(tokens) < 3 { - self.pushErr(tokens[0], LogMsg.InvalidSyntax) - ret nil - } - - mut i := 1 - mut s := &StructDecl{ - Token: tokens[i], - } - if s.Token.Id != TokenId.Ident { - self.pushErr(s.Token, LogMsg.InvalidSyntax) - self.pushSuggestion(LogMsg.ExpectedIdentifier) - } - i++ - if i >= len(tokens) { - self.pushErr(tokens[i], LogMsg.InvalidSyntax) - ret s - } - s.Ident = s.Token.Kind - - errorToken := tokens[i] - mut genericsTokens := range(i, TokenId.LBracket, TokenId.RBracket, tokens) - if genericsTokens != nil { - s.Generics = self.buildGenerics(genericsTokens, errorToken) - } - if i >= len(tokens) { - self.pushErr(tokens[i-1], LogMsg.BodyNotExist) - self.pushSuggestion(LogMsg.ExpectedBody) - ret s - } - - mut bodyTokens := range(i, TokenId.LBrace, TokenId.RBrace, tokens) - if bodyTokens == nil { - self.stop() - self.pushErr(s.Token, LogMsg.BodyNotExist) - self.pushSuggestion(LogMsg.ExpectedBody) - ret s - } - if i < len(tokens) { - self.pushErr(tokens[i], LogMsg.InvalidSyntax) - } - s.Public = mod::IsPub(s.Ident) - s.Fields = self.buildStructDeclFields(bodyTokens) - s.End = tokens[i-1] - ret s - } - - fn checkMethodReceiver(mut self, &f: &FnDecl) { - // Static methods cannot have receiver. - if f.Statically { - if len(f.Params) > 0 && f.Params[0].IsSelf() { - self.pushErr(f.Token, LogMsg.StaticFnHasReceiver) - } - ret - } - if len(f.Params) == 0 { - self.pushErr(f.Token, LogMsg.MissingReceiver) - ret - } - param := f.Params[0] - if !param.IsSelf() { - self.pushErr(f.Token, LogMsg.MissingReceiver) - ret - } - } - - fn buildTraitBody(mut &self, mut &t: &TraitDecl, mut tokens: []&Token) { - mut stmts := splitStmts(tokens) - for (_, mut stmt) in stmts { - tokens = stmt.tokens - if len(tokens) == 0 { - continue - } - match tokens[0].Id { - | TokenId.Fn: - mut f := self.buildFn(tokens, true, true) - if f == nil { - break - } - self.checkMethodReceiver(f) - if len(f.Generics) > 0 { - self.pushErr(f.Token, LogMsg.TraitMethodHasGenerics) - } - t.Methods = append(t.Methods, f) - |: - mut i := 0 - mut ti, ok := unsafe { self.buildType(tokens, &i, true) } - if !ok { - break - } - if i < len(tokens) { - self.pushErr(tokens[i], LogMsg.InvalidSyntax) - } - t.Inherits = append(t.Inherits, ti) - } - } - } - - fn buildTraitDecl(mut &self, mut &tokens: []&Token): &TraitDecl { - if len(tokens) < 3 { - self.pushErr(tokens[0], LogMsg.InvalidSyntax) - ret nil - } - mut t := &TraitDecl{ - Token: tokens[1], - } - if t.Token.Id != TokenId.Ident { - self.pushErr(t.Token, LogMsg.InvalidSyntax) - self.pushSuggestion(LogMsg.ExpectedIdentifier) - } - t.Ident = t.Token.Kind - mut i := 2 - mut bodyTokens := range(i, TokenId.LBrace, TokenId.RBrace, tokens) - if bodyTokens == nil { - self.stop() - self.pushErr(t.Token, LogMsg.BodyNotExist) - self.pushSuggestion(LogMsg.ExpectedBody) - ret nil - } - if i < len(tokens) { - self.pushErr(tokens[i], LogMsg.InvalidSyntax) - } - t.Public = mod::IsPub(t.Ident) - self.buildTraitBody(t, bodyTokens) - t.End = tokens[i-1] - ret t - } - - fn buildBindFn(mut &self, mut tokens: []&Token): &FnDecl { - tokens = tokens[1:] // Remove "cpp" keyword. - mut f := self.buildFn(tokens, false, true) - if f != nil { - f.Public = false - f.Binded = true - } - ret f - } - - fn buildBindVar(mut &self, mut tokens: []&Token): &VarDecl { - tokens = tokens[1:] // Remove "cpp" keyword. - mut v := self.buildVar(tokens) - if v != nil { - v.Public = false - v.Binded = true - if v.Expr != nil { - self.pushErr(v.Token, LogMsg.BindedVarHasExpr) - } - } - ret v - } - - fn buildBindStruct(mut &self, mut tokens: []&Token): &StructDecl { - tokens = tokens[1:] // Remove "cpp" keyword. - mut s := self.buildStructDecl(tokens) - if s != nil { - s.Public = false - for (_, mut f) in s.Fields { - // Binded structure's fields are always public by default. - f.Public = true - } - s.Binded = true - } - ret s - } - - fn buildBindTypeAlias(mut &self, mut tokens: []&Token): &TypeAliasDecl { - tokens = tokens[1:] // Remove "cpp" keyword. - mut t := self.buildTypeAliasDecl(tokens) - if t != nil { - t.Public = false - t.Binded = true - } - ret t - } - - fn buildBindUse(mut &self, mut tokens: []&Token): &UseDecl { - if len(tokens) == 1 { - self.pushErr(tokens[0], LogMsg.InvalidSyntax) - ret nil - } - tokens = tokens[1:] // Remove the bind keyword. - - const Binded = true - ret self.buildUseDecl(tokens, Binded) - } - - fn buildBind(mut &self, mut &tokens: []&Token): NodeData { - mut token := tokens[0] - if len(tokens) == 1 { - self.pushErr(token, LogMsg.InvalidSyntax) - ret nil - } - token = tokens[1] - match token.Id { - | TokenId.Fn - | TokenId.Unsafe: - ret self.buildBindFn(tokens) - | TokenId.Const - | TokenId.Let: - ret self.buildBindVar(tokens) - | TokenId.Struct: - ret self.buildBindStruct(tokens) - | TokenId.Type: - ret self.buildBindTypeAlias(tokens) - |: - self.pushErr(token, LogMsg.InvalidSyntax) - } - ret nil - } - - fn getMethod(mut &self, mut &tokens: []&Token): &FnDecl { - mut i := 0 - mut token := tokens[i] - if token.Id == TokenId.Static { - if i+1 >= len(tokens) { - self.pushErr(token, LogMsg.InvalidSyntax) - ret nil - } - i++ - token = tokens[i] - } - - if token.Id == TokenId.Unsafe { - if i+1 >= len(tokens) { - self.pushErr(token, LogMsg.InvalidSyntax) - ret nil - } - i++ - token = tokens[i] - } - - if token.Id != TokenId.Fn { - self.pushErr(token, LogMsg.InvalidSyntax) - ret nil - } - - ret self.buildFn(tokens, true, false) - } - - fn parseImplBody(mut &self, mut &ipl: &Impl, mut &tokens: []&Token) { - mut stmts := splitStmts(tokens) - for (_, mut stmt) in stmts { - tokens = stmt.tokens - mut token := tokens[0] - match token.Id { - | TokenId.Hash: - self.pushDirective(self.buildDirective(tokens)) - continue - } - - match token.Id { - | TokenId.Const: - mut v := self.buildVar(tokens) - if v != nil { - ipl.Statics = append(ipl.Statics, v) - } - | TokenId.Static - | TokenId.Fn - | TokenId.Unsafe: - mut f := self.getMethod(tokens) - if f != nil { - self.checkMethodReceiver(f) - self.applyFnMeta(f) - ipl.Methods = append(ipl.Methods, f) - } - |: - self.pushErr(token, LogMsg.InvalidSyntax) - continue - } - } - } - - fn buildImpl(mut &self, mut tokens: []&Token): &Impl { - mut token := tokens[0] - if len(tokens) < 2 { - self.pushErr(token, LogMsg.InvalidSyntax) - ret nil - } - - mut i := 1 - - mut base, mut ok := unsafe { self.buildType(tokens, &i, true) } - if !ok { - ret nil - } - if i >= len(tokens) { - self.pushErr(token, LogMsg.InvalidSyntax) - ret nil - } - - mut ipl := &Impl{ - Base: base, - } - - token = tokens[i] - if token.Id != TokenId.For { - if token.Id == TokenId.LBrace { - // This implementation is single. - // Just implements to destination. - // Therefore, swap Base and Dest tokens. - ipl.Base, ipl.Dest = ipl.Dest, ipl.Base - goto body - } - self.stop() - self.pushErr(token, LogMsg.BodyNotExist) - self.pushSuggestion(LogMsg.ExpectedBody) - ret nil - } - i++ - if i >= len(tokens) { - self.stop() - self.pushErr(token, LogMsg.BodyNotExist) - self.pushSuggestion(LogMsg.ExpectedBody) - ret nil - } - - ipl.Dest, ok = unsafe { self.buildType(tokens, &i, true) } - if !ok { - ret nil - } - if i >= len(tokens) { - self.stop() - self.pushErr(token, LogMsg.BodyNotExist) - self.pushSuggestion(LogMsg.ExpectedBody) - ret nil - } - - body: - mut bodyTokens := range(i, TokenId.LBrace, TokenId.RBrace, tokens) - if bodyTokens == nil { - self.stop() - self.pushErr(token, LogMsg.BodyNotExist) - self.pushSuggestion(LogMsg.ExpectedBody) - ret nil - } - if i < len(tokens) { - self.pushErr(tokens[i], LogMsg.InvalidSyntax) - } - ipl.End = tokens[i-1] - self.parseImplBody(ipl, bodyTokens) - ret ipl - } - - fn buildNodeData(mut &self, mut &tokens: []&Token): NodeData { - mut token := tokens[0] - match token.Id { - | TokenId.Fn - | TokenId.Unsafe: - mut f := self.buildFn(tokens, false, false) - if f != nil { - f.Global = true - } - ret f - | TokenId.Let - | TokenId.Const - | TokenId.Mut - | TokenId.Static: - ret self.buildVar(tokens) - | TokenId.Type: - ret self.buildTypeAliasDecl(tokens) - | TokenId.Enum: - ret self.buildNodeEnumDecl(tokens) - | TokenId.Struct: - ret self.buildStructDecl(tokens) - | TokenId.Trait: - ret self.buildTraitDecl(tokens) - | TokenId.Impl: - ret self.buildImpl(tokens) - | TokenId.Cpp: - ret self.buildBind(tokens) - |: - self.pushErr(token, LogMsg.InvalidSyntax) - ret nil - } - } - - fn applyFnMeta(mut self, mut &f: &FnDecl) { - f.Directives = self.directives - self.directives = nil - } - - fn applyMeta(mut self, mut &node: Node) { - match type node.Data { - | &VarDecl: - mut v := (&VarDecl)(node.Data) - if v == nil { - ret - } - v.Directives = self.directives - self.directives = nil - | &FnDecl: - mut f := (&FnDecl)(node.Data) - if f == nil { - ret - } - self.applyFnMeta(f) - | &StructDecl: - mut sd := (&StructDecl)(node.Data) - if sd == nil { - ret - } - sd.Directives = self.directives - self.directives = nil - } - } - - fn pushUseDecl(mut &self, mut &decl: &UseDecl) { - self.ast.UseDecls = append(self.ast.UseDecls, decl) - if len(self.ast.Nodes) > 0 { - self.pushErr(decl.Token, LogMsg.UseDeclAtBody) - self.pushSuggestion(LogMsg.MoveUseDeclToTopOfFile) - } - } - - fn pushMetaNodes(mut &self, mut &tokens: []&Token): bool { - match tokens[0].Id { - | TokenId.Use: - const Binded = false - mut decl := self.buildUseDecl(tokens, Binded) - self.pushUseDecl(decl) - ret true - | TokenId.Cpp: - if len(tokens) > 1 && tokens[1].Id == TokenId.Use { - mut decl := self.buildBindUse(tokens) - self.pushUseDecl(decl) - ret true - } - | TokenId.Hash: - self.pushDirective(self.buildDirective(tokens)) - ret true - } - ret false - } - - fn parseNode(mut &self, mut &st: []&Token): Node { - mut node := Node{ - Token: st[0], - } - - if self.pushMetaNodes(st) { - ret node - } - - mut data := self.buildNodeData(st) - if data == nil { - ret node - } - - node.Data = data - - self.applyMeta(node) - if len(self.directives) != 0 { - self.pushErr(self.directives[0].Tag, LogMsg.UnusedDirective) - } - self.directives = nil - ret node - } - - fn appendNode(mut &self, mut &st: []&Token) { - if len(st) == 0 { - ret - } - mut node := self.parseNode(st) - if node.Data != nil && !self.stopped() { - self.ast.Nodes = append(self.ast.Nodes, node) - } - } - - fn removeRange(self, mut i: int, id: TokenId, &tokens: []&Token, mut &ranges: []int) { - close := getCloseOfBrace(id) - for i >= 0; i-- { - tok := tokens[ranges[i]] - if tok.Id != close { - continue - } - ranges = append(ranges[:i], ranges[i+1:]...) - break - } - } - - fn pushWrongOrderCloseErr(mut self, &t: &Token, &tokens: []&Token, &ranges: []int) { - match tokens[ranges[len(ranges)-1]].Id { - | TokenId.LParent: - self.pushErr(t, LogMsg.ExpectedParentClose) - | TokenId.LBrace: - self.pushErr(t, LogMsg.ExpectedBraceClose) - | TokenId.LBracket: - self.pushErr(t, LogMsg.ExpectedBracketClose) - } - } - - fn pushRangeClose(mut self, t: &Token, left: TokenId, &tokens: []&Token, mut &ranges: []int) { - n := len(ranges) - if n == 0 { - match t.Id { - | TokenId.RBracket: - self.pushErr(t, LogMsg.ExtraClosedBracket) - | TokenId.RBrace: - self.pushErr(t, LogMsg.ExtraClosedBrace) - | TokenId.RParent: - self.pushErr(t, LogMsg.ExtraClosedParent) - } - ret - } else if tokens[ranges[n-1]].Id != left { - self.pushWrongOrderCloseErr(t, tokens, ranges) - } - self.removeRange(n - 1, t.Id, tokens, ranges) - } - - fn checkRanges(mut self, &tokens: []&Token) { - let mut ranges: []int = nil - - for i, token in tokens { - match token.Id { - | TokenId.LParent - | TokenId.LBrace - | TokenId.LBracket: - ranges = append(ranges, i) - | TokenId.RParent: - self.pushRangeClose(token, TokenId.LParent, tokens, ranges) - | TokenId.RBrace: - self.pushRangeClose(token, TokenId.LBrace, tokens, ranges) - | TokenId.RBracket: - self.pushRangeClose(token, TokenId.LBracket, tokens, ranges) - } - } - - for _, i in ranges { - token := tokens[i] - match token.Id { - | TokenId.LParent: - self.pushErr(token, LogMsg.WaitCloseParent) - | TokenId.LBrace: - self.pushErr(token, LogMsg.WaitCloseBrace) - | TokenId.LBracket: - self.pushErr(token, LogMsg.WaitCloseBracket) - } - } - } - - fn parse(mut &self, mut &f: &File) { - self.ast = &Ast{ - File: f, - } - self.ep = &exprBuilder{ - p: self, - } - - self.checkRanges(f.Tokens) - if len(self.errors) > 0 { - ret - } - - mut stmts := splitStmts(f.Tokens) - - // Get top directives. - mut i := 0 - for i < len(stmts); i++ { - mut stmt := stmts[i] - if len(stmt.tokens) < 2 { - ret - } - if stmt.tokens[0].Id != TokenId.Hash { - break - } - if !IsTopDirective(stmt.tokens[1].Kind) { - break - } - self.ast.TopDirectives = append(self.ast.TopDirectives, self.buildDirective(stmt.tokens)) - } - - // Remove all errors. - self.errors = nil - - for i < len(stmts) && !self.stopped(); i++ { - self.appendNode(stmts[i].tokens) - } - - if len(self.directives) != 0 { - self.pushErr(self.directives[0].Tag, LogMsg.UnusedDirective) - } - } + fn stop(mut self) { self.ast = nil } + fn stopped(self): bool { ret self.ast == nil } + + // Appends error by specified token, key and args. + fn pushErr(mut self, token: &Token, fmt: LogMsg, args: ...any) { + self.errors = append(self.errors, compilerErr(token, fmt, args...)) + } + + // Push suggestion to last log. + fn pushSuggestion(mut self, fmt: LogMsg, args: ...any) { + unsafe { pushSuggestion(&self.errors[len(self.errors)-1], fmt, args...) } + } + + fn buildExpr(mut &self, mut &tokens: []&Token): &Expr { + ret self.ep.buildFromTokens(tokens) + } + + fn buildDirective(mut self, mut tokens: []&Token): &Directive { + if len(tokens) == 1 { + self.pushErr(tokens[0], LogMsg.InvalidSyntax) + ret nil + } + if tokens[1].Column != tokens[0].Column+1 { + self.pushErr(tokens[0], LogMsg.InvalidSyntax) + ret nil + } + ret &Directive{ + Tag: tokens[1], + Args: tokens[2:], // Start 2 to skip '#', and tag tokens. + } + } + + fn pushDirective(mut self, mut d: &Directive) { + if d == nil { + ret + } + // Don't append if already added this directive. + for _, pd in self.directives { + if d.Tag.Kind == pd.Tag.Kind { + ret + } + } + self.directives = append(self.directives, d) + } + + fn buildScope(mut &self, mut &tokens: []&Token, mut end: &Token): &ScopeTree { + mut s := newScope() + s.End = end + mut sp := scopeParser{ + p: self, + } + sp.build(tokens, s) + ret s + } + + unsafe fn _buildType(mut &self, mut &tokens: []&Token, + mut i: *int, err: bool): (&TypeDecl, bool) { + mut tb := typeBuilder{ + p: self, + tokens: tokens, + i: i, + err: err, + } + ret tb.build() + } + + // Builds AST model of data-type. + unsafe fn buildType(mut &self, mut &tokens: []&Token, + mut i: *int, err: bool): (&TypeDecl, bool) { + token := tokens[*i] + mut t, ok := self._buildType(tokens, i, err) + if err && !ok { + self.pushErr(token, LogMsg.InvalidType) + } + ret t, ok + } + + fn buildTypeAliasDecl(mut &self, mut &tokens: []&Token): &TypeAliasDecl { + mut i := 1 // Skip "type" keyword. + if i >= len(tokens) { + self.pushErr(tokens[i-1], LogMsg.InvalidSyntax) + ret nil + } + mut tad := &TypeAliasDecl{ + Token: tokens[1], + Ident: tokens[1].Kind, + } + mut token := tokens[i] + if token.Id != TokenId.Ident { + self.pushErr(token, LogMsg.InvalidSyntax) + self.pushSuggestion(LogMsg.ExpectedIdentifier) + } + i++ + if i >= len(tokens) { + self.pushErr(tokens[i-1], LogMsg.InvalidSyntax) + ret tad + } + token = tokens[i] + if token.Id != TokenId.Colon { + self.pushErr(tokens[i-1], LogMsg.InvalidSyntax) + self.pushSuggestion(LogMsg.ExpectedColon) + ret tad + } + i++ + if i >= len(tokens) { + self.pushErr(tokens[i-1], LogMsg.MissingType) + ret tad + } + mut t, ok := unsafe { self.buildType(tokens, &i, true) } + tad.Kind = t + if ok && i < len(tokens) { + self.pushErr(tokens[i], LogMsg.InvalidSyntax) + } + tad.Public = mod::IsPub(tad.Ident) + ret tad + } + + fn buildVarTypeAndExpr(mut &self, mut &v: &VarDecl, mut &tokens: []&Token) { + mut i := 0 + mut tok := tokens[i] + if tok.Id == TokenId.Colon { + i++ // Skip type annotation operator (:) + if i >= len(tokens) || tokens[i].Id == TokenId.Eq { + self.pushErr(tok, LogMsg.MissingType) + ret + } + mut t, ok := unsafe { self.buildType(tokens, &i, true) } + if ok { + v.Kind = t + if i >= len(tokens) { + ret + } + tok = tokens[i] + } + } + + if tok.Id != TokenId.Eq { + self.pushErr(tok, LogMsg.InvalidSyntax) + ret + } + v.Setter = tok + + mut exprTokens := tokens[i+1:] + if len(exprTokens) == 0 { + self.pushErr(tok, LogMsg.MissingExpr) + ret + } + v.Expr = self.buildExpr(exprTokens) + } + + fn buildVarCommon(mut &self, mut &v: &VarDecl, mut tokens: []&Token) { + v.Token = tokens[0] + if v.Token.Id != TokenId.Ident { + self.pushErr(v.Token, LogMsg.InvalidSyntax) + self.pushSuggestion(LogMsg.ExpectedIdentifier) + ret + } + v.Ident = v.Token.Kind + v.Public = mod::IsPub(v.Ident) + v.Kind = nil // For auto-type. + if len(tokens) > 1 { + tokens = tokens[1:] // Remove identifier. + self.buildVarTypeAndExpr(v, tokens) + } + } + + fn buildVarBegin(mut self, mut &v: &VarDecl, mut &tokens: []&Token) { + tok := tokens[0] + match tok.Id { + | TokenId.Static: + v.Statically = true + fall + | TokenId.Let: + // Initialize 1 for skip the let keyword + if len(tokens) == 1 { + tokens = nil + self.pushErr(tok, LogMsg.InvalidSyntax) + ret + } + tokens = tokens[1:] + if tokens[0].Id == TokenId.Mut { + v.Mutable = true + // Skip the mut keyword + tokens = tokens[1:] + } + | TokenId.Const: + v.Constant = true + tokens = tokens[1:] + |: + tokens = nil + self.pushErr(tok, LogMsg.InvalidSyntax) + } + } + + fn buildVar(mut &self, mut tokens: []&Token): &VarDecl { + mut v := &VarDecl{ + Token: tokens[0], + } + self.buildVarBegin(v, tokens) + if len(tokens) == 0 { + ret nil + } + if tokens[0].Id == TokenId.Amper { + v.Reference = true + if len(tokens) == 1 { + ret nil + } + tokens = tokens[1:] + } + self.buildVarCommon(v, tokens) + ret v + } + + fn buildGeneric(mut &self, mut &tokens: []&Token): &GenericDecl { + mut g := &GenericDecl{ + Token: tokens[0], + } + if g.Token.Id != TokenId.Ident { + self.pushErr(g.Token, LogMsg.InvalidSyntax) + self.pushSuggestion(LogMsg.ExpectedIdentifier) + } + g.Ident = g.Token.Kind + if len(tokens) > 1 { + if tokens[1].Id != TokenId.Colon { + self.pushErr(tokens[1], LogMsg.InvalidSyntax) + ret nil + } + if len(tokens) == 2 { + self.pushErr(tokens[1], LogMsg.MissingExpr) + ret nil + } + mut constraintTokens := tokens[2:] + mut parts, errors := parts(constraintTokens, TokenId.Vline, true) + if len(errors) > 0 { + self.errors = append(self.errors, errors...) + ret nil + } + g.Constraint = &Constraint{Mask: make([]&TypeDecl, 0, len(parts))} + for (_, mut part) in parts { + mut i := 0 + mut kind, _ := unsafe { self.buildType(part, &i, true) } + g.Constraint.Mask = append(g.Constraint.Mask, kind) + if i < len(part) { + self.pushErr(part[i], LogMsg.InvalidSyntax) + } + } + } + ret g + } + + fn buildGenerics(mut &self, mut &tokens: []&Token, &errorToken: &Token): []&GenericDecl { + if len(tokens) == 0 { + self.pushErr(errorToken, LogMsg.MissingExpr) + ret nil + } + + mut parts, errors := parts(tokens, TokenId.Comma, true) + if len(errors) > 0 { + self.errors = append(self.errors, errors...) + ret nil + } + + mut generics := make([]&GenericDecl, 0, len(parts)) + for (_, mut part) in parts { + generics = append(generics, self.buildGeneric(part)) + } + + ret generics + } + + fn buildSelfParam(mut self, mut tokens: []&Token): &ParamDecl { + if len(tokens) == 0 { + ret nil + } + + mut param := new(ParamDecl) + + // Detects mut keyword. + if tokens[0].Id == TokenId.Mut { + param.Mutable = true + if len(tokens) == 1 { + self.pushErr(tokens[0], LogMsg.InvalidSyntax) + ret nil + } + tokens = tokens[1:] + } + + mut ident := StrBuilder.New(5) + + if tokens[0].Id == TokenId.Amper { + ident.WriteStr(TokenKind.Amper) + if len(tokens) == 1 { + self.pushErr(tokens[0], LogMsg.InvalidSyntax) + ret nil + } + tokens = tokens[1:] + } + + if tokens[0].Id == TokenId.Self { + ident.WriteStr(str(TokenKind.Self)) + param.Token = tokens[0] + if len(tokens) != 1 { + self.pushErr(tokens[1], LogMsg.InvalidSyntax) + } + } + + param.Ident = ident.Str() + ret param + } + + fn paramTypeBegin(mut self, mut ¶m: &ParamDecl, mut &i: int, &tokens: []&Token) { + for i < len(tokens); i++ { + token := tokens[i] + if token.Id != TokenId.TripleDot { + ret + } + + if param.Variadic { + self.pushErr(token, LogMsg.AlreadyVariadic) + continue + } + param.Variadic = true + } + } + + fn buildParamType(mut &self, mut ¶m: &ParamDecl, mut &tokens: []&Token) { + mut i := 0 + self.paramTypeBegin(param, i, tokens) + if i >= len(tokens) { + ret + } + + param.Kind, _ = unsafe { self.buildType(tokens, &i, true) } + if i < len(tokens) { + self.pushErr(tokens[i], LogMsg.InvalidSyntax) + } + } + + fn buildParamBody(mut &self, mut ¶m: &ParamDecl, mut tokens: []&Token) { + mut tok := tokens[0] + if len(tokens) == 1 { + // Just identifier token. + param.Ident = tok.Kind + ret + } else if len(tokens) < 3 { + self.pushErr(tok, LogMsg.MissingType) + ret + } + if tokens[1].Id != TokenId.Colon { + param.Ident = Ident.Anon + self.buildParamType(param, tokens) + ret + } + param.Ident = tok.Kind + tokens = tokens[2:] // Skip colon + self.buildParamType(param, tokens) + } + + fn buildParam(mut &self, mut tokens: []&Token): &ParamDecl { + mut param := &ParamDecl{ + Token: tokens[0], + } + + // Detects mut keyword. + if param.Token.Id == TokenId.Mut { + param.Mutable = true + if len(tokens) == 1 { + self.pushErr(tokens[0], LogMsg.InvalidSyntax) + ret nil + } + tokens = tokens[1:] + param.Token = tokens[0] + } + + // Catch reference parameters. + if len(tokens) >= 3 { + if param.Token.Id == TokenId.Amper { + if len(tokens) == 1 { + self.pushErr(tokens[0], LogMsg.InvalidSyntax) + ret nil + } + + if tokens[1].Id == TokenId.Ident && tokens[2].Id == TokenId.Colon { + param.Reference = true + tokens = tokens[1:] + param.Token = tokens[0] + } + } + } + + if param.Token.Id != TokenId.Ident { + // Just data type + param.Ident = Ident.Anon + self.buildParamType(param, tokens) + } else { + self.buildParamBody(param, tokens) + } + + ret param + } + + fn checkParams(mut self, mut ¶ms: []&ParamDecl) { + for (_, mut param) in params { + if param.IsSelf() || param.Kind != nil { + continue + } + if param.Token == nil { + self.pushErr(param.Token, LogMsg.MissingType) + } else { + param.Kind = &TypeDecl{ + Token: param.Token, + Kind: &IdentTypeDecl{ + Token: param.Token, + Ident: param.Token.Kind, + }, + } + param.Ident = Ident.Anon + } + } + } + + fn buildParams(mut &self, mut &tokens: []&Token, method: bool): []&ParamDecl { + mut parts, errs := parts(tokens, TokenId.Comma, true) + self.errors = append(self.errors, errs...) + if len(parts) == 0 { + ret nil + } + + let mut params: []&ParamDecl = nil + if method && len(parts) > 0 { + mut param := self.buildSelfParam(parts[0]) + if param != nil && param.IsSelf() { + params = append(params, param) + parts = parts[1:] + } + } + + for (_, mut part) in parts { + if len(part) == 0 { + continue + } + mut param := self.buildParam(part) + if param != nil { + params = append(params, param) + } + } + + self.checkParams(params) + ret params + } + + fn buildMultiRetType(mut &self, mut &tokens: []&Token, mut &i: int): (t: &RetTypeDecl, ok: bool) { + t = new(RetTypeDecl) + i++ + if i >= len(tokens) { + i-- + t.Kind, ok = unsafe { self.buildType(tokens, &i, false) } + ret + } + + i-- // For point to parentheses - ( - + mut rangeTokens := range(i, TokenId.LParent, TokenId.RParent, tokens) + + mut parts, errs := parts(rangeTokens, TokenId.Comma, true) + self.errors = append(self.errors, errs...) + if len(parts) == 0 { + ret + } + + mut types := make([]&TypeDecl, 0, len(parts)) + t.Idents = make([]&Token, 0, len(parts)) + for (_, mut part) in parts { + if len(part) == 0 { + continue + } + mut token := part[0] + mut offset := 0 + + // Check type annotation. + if len(part) > 1 { + token = part[1] + if token.Id == TokenId.Colon { + offset = 2 + if len(part) < 3 { + self.pushErr(token, LogMsg.MissingType) + continue + } + } + } + + token = part[0] + if offset != 2 { + mut newToken := new(Token, *token) + newToken.Kind = Ident.Anon + t.Idents = append(t.Idents, newToken) + } else { + t.Idents = append(t.Idents, token) + } + + mut tk, _ := unsafe { self.buildType(part, &offset, true) } + if offset < len(part) { + self.pushErr(part[offset], LogMsg.InvalidSyntax) + } + types = append(types, tk) + } + + if len(types) > 1 { + t.Kind = &TypeDecl{ + Token: tokens[0], + Kind: &TupleTypeDecl{ + Types: types, + }, + } + } else { + t.Kind = types[0] + } + + ok = true + ret + } + + // Builds function return type from tokens. + fn buildRetType(mut &self, mut &tokens: []&Token, mut &i: int): (t: &RetTypeDecl, ok: bool) { + t = new(RetTypeDecl) + if i >= len(tokens) { + ret + } + + mut token := tokens[i] + match token.Id { + | TokenId.LBrace: + ret + | TokenId.Eq: + ret + | TokenId.Colon: + if i+1 >= len(tokens) { + self.pushErr(token, LogMsg.MissingType) + ret + } + + i++ + token = tokens[i] + match token.Id { + | TokenId.LParent: + t, ok = self.buildMultiRetType(tokens, i) + ret + | TokenId.LBrace: + self.pushErr(token, LogMsg.MissingType) + ret + } + t.Kind, ok = unsafe { self.buildType(tokens, &i, true) } + ret + } + i++ + self.pushErr(token, LogMsg.InvalidSyntax) + ret + } + + // Build function prototype. + // Body is not necessary for successfull parsing. + // Just declration. + fn buildFnPrototype(mut &self, mut &tokens: []&Token, mut &i: int, method: bool): &FnDecl { + mut f := &FnDecl{ + Token: tokens[i], + } + + // Detect static keyword. + if f.Token.Id == TokenId.Static { + f.Statically = true + i++ + if i >= len(tokens) { + self.pushErr(f.Token, LogMsg.InvalidSyntax) + ret nil + } + f.Token = tokens[i] + } + + // Detect unsafe keyword. + if f.Token.Id == TokenId.Unsafe { + f.Unsafety = true + i++ + if i >= len(tokens) { + self.pushErr(f.Token, LogMsg.InvalidSyntax) + ret nil + } + f.Token = tokens[i] + } + + // Skips fn token. + i++ + if i >= len(tokens) { + self.pushErr(f.Token, LogMsg.InvalidSyntax) + ret nil + } + + tok := tokens[i] + if tok.Id == TokenId.Ident { + i++ + if i >= len(tokens) { + self.pushErr(f.Token, LogMsg.InvalidSyntax) + ret nil + } + f.Ident = tok.Kind + } else { + f.Ident = Ident.Anon + } + + errorToken := tokens[i] + mut genericsTokens := range(i, TokenId.LBracket, TokenId.RBracket, tokens) + if genericsTokens != nil { + f.Generics = self.buildGenerics(genericsTokens, errorToken) + } + + if tokens[i].Id != TokenId.LParent { + self.pushErr(tokens[i], LogMsg.MissingFnParentheses) + ret nil + } + + mut paramsToks := range(i, TokenId.LParent, TokenId.RParent, tokens) + if len(paramsToks) > 0 { + f.Params = self.buildParams(paramsToks, method) + } + + if i < len(tokens) { + token := tokens[i] + if token.Id == TokenId.Excl { + f.Exceptional = true + i++ + } + } + + f.Public = mod::IsPub(f.Ident) + f.Result, _ = self.buildRetType(tokens, i) + ret f + } + + // Parses function define. + // Prototype and body. + fn buildFn(mut &self, mut &tokens: []&Token, method: bool, prototype: bool): &FnDecl { + mut i := 0 + mut f := self.buildFnPrototype(tokens, i, method) + if prototype { + if i < len(tokens) { + self.pushErr(tokens[i+1], LogMsg.InvalidSyntax) + } + ret f + } else if f == nil { + ret f + } + + if i >= len(tokens) { + self.stop() + self.pushErr(f.Token, LogMsg.BodyNotExist) + self.pushSuggestion(LogMsg.ExpectedBody) + ret nil + } + mut blockTokens := range(i, TokenId.LBrace, TokenId.RBrace, tokens) + if blockTokens != nil { + f.Scope = self.buildScope(blockTokens, tokens[i-1]) + f.Scope.Unsafety = f.Unsafety + if i < len(tokens) { + self.pushErr(tokens[i], LogMsg.InvalidSyntax) + } + } else { + self.stop() + self.pushErr(f.Token, LogMsg.BodyNotExist) + self.pushSuggestion(LogMsg.ExpectedBody) + ret nil + } + ret f + } + + fn getUseDeclSelectors(mut self, mut tokens: []&Token): []&Token { + mut i := 0 + tokens = range(i, TokenId.LBrace, TokenId.RBrace, tokens) + mut parts, errs := parts(tokens, TokenId.Comma, true) + if len(errs) > 0 { + self.errors = append(self.errors, errs...) + ret nil + } + + mut selectors := make([]&Token, 0, len(parts)) + for (_, mut part) in parts { + if len(part) > 1 { + self.pushErr(part[1], LogMsg.InvalidSyntax) + } + mut tok := part[0] + if tok.Id != TokenId.Ident && tok.Id != TokenId.Self { + self.pushErr(tok, LogMsg.InvalidSyntax) + self.pushSuggestion(LogMsg.ExpectedIdentifier) + continue + } + selectors = append(selectors, tok) + } + ret selectors + } + + fn buildBindUseDecl(mut self, mut &decl: &UseDecl, &tokens: []&Token) { + if len(tokens) > 1 { + self.pushErr(tokens[1], LogMsg.InvalidSyntax) + } + token := tokens[0] + if token.Id != TokenId.Lit || (token.Kind[0] != '`' && token.Kind[0] != '"') { + self.pushErr(token, LogMsg.InvalidExpr) + ret + } + decl.Binded = true + decl.LinkPath = token.Kind[1:len(token.Kind)-1] + } + + fn useDeclTokstoa(mut self, &tokens: []&Token): str { + mut n := 0 + for _, token in tokens { + if token.Id != TokenId.Ident && token.Id != TokenId.DblColon { + self.pushErr(token, LogMsg.InvalidSyntax) + } + n += len(token.Kind) + } + mut s := StrBuilder.New(n) + for _, token in tokens { + s.WriteStr(token.Kind) + } + ret s.Str() + } + + fn buildStdUseDecl(mut self, mut &decl: &UseDecl, mut tokens: []&Token) { + decl.Std = true + + mut token := tokens[0] + if len(tokens) < 3 { + self.pushErr(token, LogMsg.InvalidSyntax) + ret + } + + tokens = tokens[2:] + token = tokens[len(tokens)-1] + match token.Id { + | TokenId.DblColon: + self.pushErr(token, LogMsg.InvalidSyntax) + ret + | TokenId.RBrace: + let mut selectors: []&Token = nil + tokens, selectors = rangeLast(tokens) + decl.Selected = self.getUseDeclSelectors(selectors) + if len(tokens) == 0 { + self.pushErr(token, LogMsg.InvalidSyntax) + ret + } + token = tokens[len(tokens)-1] + if token.Id != TokenId.DblColon { + self.pushErr(token, LogMsg.InvalidSyntax) + ret + } + tokens = tokens[:len(tokens)-1] + if len(tokens) == 0 { + self.pushErr(token, LogMsg.InvalidSyntax) + ret + } + | TokenId.Star: + tokens = tokens[:len(tokens)-1] + if len(tokens) == 0 { + self.pushErr(token, LogMsg.InvalidSyntax) + ret + } + token = tokens[len(tokens)-1] + if token.Id != TokenId.DblColon { + self.pushErr(token, LogMsg.InvalidSyntax) + ret + } + tokens = tokens[:len(tokens)-1] + if len(tokens) == 0 { + self.pushErr(token, LogMsg.InvalidSyntax) + ret + } + decl.Full = true + } + if len(tokens) == 1 && tokens[0].Id == TokenId.Unsafe { // Is std::unsafe? + decl.LinkPath = "std::unsafe" + } else { + decl.LinkPath = "std::" + self.useDeclTokstoa(tokens) + } + } + + fn buildIdentUseDecl(mut self, mut &decl: &UseDecl, mut tokens: []&Token) { + decl.Std = false + + mut token := tokens[len(tokens)-1] + match token.Id { + | TokenId.DblColon: + self.pushErr(token, LogMsg.InvalidSyntax) + ret + | TokenId.RBrace: + let mut selectors: []&Token = nil + tokens, selectors = rangeLast(tokens) + decl.Selected = self.getUseDeclSelectors(selectors) + if len(tokens) == 0 { + self.pushErr(token, LogMsg.InvalidSyntax) + ret + } + token = tokens[len(tokens)-1] + if token.Id != TokenId.DblColon { + self.pushErr(token, LogMsg.InvalidSyntax) + ret + } + tokens = tokens[:len(tokens)-1] + if len(tokens) == 0 { + self.pushErr(token, LogMsg.InvalidSyntax) + ret + } + | TokenId.Star: + tokens = tokens[:len(tokens)-1] + if len(tokens) == 0 { + self.pushErr(token, LogMsg.InvalidSyntax) + ret + } + token = tokens[len(tokens)-1] + if token.Id != TokenId.DblColon { + self.pushErr(token, LogMsg.InvalidSyntax) + ret + } + tokens = tokens[:len(tokens)-1] + if len(tokens) == 0 { + self.pushErr(token, LogMsg.InvalidSyntax) + ret + } + decl.Full = true + } + + decl.LinkPath = self.useDeclTokstoa(tokens) + } + + fn parseUseDecl(mut self, mut &decl: &UseDecl, mut tokens: []&Token) { + if decl.Binded { + self.buildBindUseDecl(decl, tokens) + ret + } + + mut token := tokens[0] + if token.Id != TokenId.Ident { + self.pushErr(token, LogMsg.InvalidSyntax) + self.pushSuggestion(LogMsg.ExpectedIdentifier) + ret + } + + if len(tokens) > 2 && tokens[1].Id == TokenId.For { + decl.Alias = token.Kind + if tokens[2].Id != TokenId.Ident { + self.pushErr(token, LogMsg.InvalidSyntax) + self.pushSuggestion(LogMsg.ExpectedIdentifier) + ret + } + tokens = tokens[2:] + token = tokens[0] + } + + const StdlibPrefix = "std" + + match { + | token.Kind == StdlibPrefix: + self.buildStdUseDecl(decl, tokens) + |: + self.buildIdentUseDecl(decl, tokens) + } + } + + fn buildUseDecl(mut self, mut tokens: []&Token, binded: bool): &UseDecl { + mut decl := &UseDecl{ + Token: tokens[0], + Binded: binded, + } + if len(tokens) < 2 { + self.pushErr(decl.Token, LogMsg.MissingUsePath) + ret nil + } + tokens = tokens[1:] // Skip "use" keyword. + self.parseUseDecl(decl, tokens) + ret decl + } + + fn buildTypeEnumItemKind(mut &self, mut &i: int, mut &tokens: []&Token): &TypeDecl { + mut braceN := 0 + exprStart := i + for i < len(tokens); i++ { + t := tokens[i] + match t.Id { + | TokenId.LBrace + | TokenId.LBracket + | TokenId.LParent: + braceN++ + continue + | TokenId.RBrace + | TokenId.RBracket + | TokenId.RParent: + braceN-- + } + if braceN > 0 { + continue + } + if t.Id == TokenId.Comma || i+1 >= len(tokens) { + let mut kindTokens: []&Token = nil + if t.Id == TokenId.Comma { + kindTokens = tokens[exprStart:i] + } else { + kindTokens = tokens[exprStart:] + } + mut j := 0 + mut kind, _ := unsafe { self.buildType(kindTokens, &j, true) } + if j < len(kindTokens) { + self.pushErr(kindTokens[j], LogMsg.InvalidSyntax) + } + ret kind + } + } + ret nil + } + + fn buildTypeEnumItems(mut &self, mut &tokens: []&Token): []&TypeEnumItemDecl { + mut items := make([]&TypeEnumItemDecl, 0, 1) + mut i := 0 + for i < len(tokens); i++ { + mut t := tokens[i] + mut item := new(TypeEnumItemDecl) + item.Token = t + if item.Token.Id == TokenId.Ident && len(tokens)-i > 2 { + t = tokens[i+1] + if t.Id == TokenId.Colon { + item.Ident = item.Token.Kind + i += 2 + if i >= len(tokens) || tokens[i].Id == TokenId.Comma { + self.pushErr(t, LogMsg.MissingType) + continue + } + } + } + item.Kind = self.buildTypeEnumItemKind(i, tokens) + items = append(items, item) + } + ret items + } + + fn buildTypeEnumDecl(mut &self, mut &tokens: []&Token): &TypeEnumDecl { + mut i := 1 + mut e := &TypeEnumDecl{ + // Skip "enum" tokens. + Token: tokens[i], + } + if e.Token.Id != TokenId.Ident { + self.pushErr(e.Token, LogMsg.InvalidSyntax) + self.pushSuggestion(LogMsg.ExpectedIdentifier) + } + e.Ident = e.Token.Kind + i += 3 // Skip "identifier: type" tokens. + mut itemTokens := range(i, TokenId.LBrace, TokenId.RBrace, tokens) + if itemTokens == nil { + self.stop() + self.pushErr(e.Token, LogMsg.BodyNotExist) + self.pushSuggestion(LogMsg.ExpectedBody) + ret e + } else if i < len(tokens) { + self.pushErr(tokens[i], LogMsg.InvalidSyntax) + } + e.Public = mod::IsPub(e.Ident) + e.End = tokens[i-1] + e.Items = self.buildTypeEnumItems(itemTokens) + ret e + } + + fn buildEnumItemExpr(mut &self, mut &i: int, mut &tokens: []&Token): &Expr { + mut braceN := 0 + exprStart := i + for i < len(tokens); i++ { + t := tokens[i] + match t.Id { + | TokenId.LBrace + | TokenId.LBracket + | TokenId.LParent: + braceN++ + continue + | TokenId.RBrace + | TokenId.RBracket + | TokenId.RParent: + braceN-- + } + if braceN > 0 { + continue + } + if t.Id == TokenId.Comma || i+1 >= len(tokens) { + let mut exprTokens: []&Token = nil + if t.Id == TokenId.Comma { + exprTokens = tokens[exprStart:i] + } else { + exprTokens = tokens[exprStart:] + } + ret self.buildExpr(exprTokens) + } + } + ret nil + } + + fn buildEnumItems(mut &self, mut &tokens: []&Token): []&EnumItemDecl { + mut items := make([]&EnumItemDecl, 0, 1) + mut i := 0 + for i < len(tokens); i++ { + mut t := tokens[i] + mut item := new(EnumItemDecl) + item.Token = t + if item.Token.Id != TokenId.Ident { + self.pushErr(item.Token, LogMsg.InvalidSyntax) + self.pushSuggestion(LogMsg.ExpectedIdentifier) + } + item.Ident = item.Token.Kind + if i+1 >= len(tokens) || tokens[i+1].Id == TokenId.Comma { + if i+1 < len(tokens) { + i++ + } + items = append(items, item) + continue + } + i++ + t = tokens[i] + i++ + if t.Id != TokenId.Colon { + self.pushErr(t, LogMsg.InvalidSyntax) + self.pushSuggestion(LogMsg.ExpectedColonForAssign) + continue + } + if i >= len(tokens) || tokens[i].Id == TokenId.Comma { + self.pushErr(t, LogMsg.MissingExpr) + continue + } + item.Expr = self.buildEnumItemExpr(i, tokens) + items = append(items, item) + } + ret items + } + + fn buildEnumDecl(mut &self, mut &tokens: []&Token): &EnumDecl { + if len(tokens) < 3 { + self.pushErr(tokens[0], LogMsg.InvalidSyntax) + ret nil + } + mut e := &EnumDecl{ + Token: tokens[1], + } + if e.Token.Id != TokenId.Ident { + self.pushErr(e.Token, LogMsg.InvalidSyntax) + self.pushSuggestion(LogMsg.ExpectedIdentifier) + } + e.Ident = e.Token.Kind + mut i := 2 + if tokens[i].Id == TokenId.Colon { + i++ + if i >= len(tokens) { + self.pushErr(tokens[i-1], LogMsg.InvalidSyntax) + ret e + } + e.Kind, _ = unsafe { self.buildType(tokens, &i, true) } + if i >= len(tokens) { + self.stop() + self.pushErr(e.Token, LogMsg.BodyNotExist) + self.pushSuggestion(LogMsg.ExpectedBody) + ret e + } + } else { + e.Kind = nil + } + mut itemTokens := range(i, TokenId.LBrace, TokenId.RBrace, tokens) + if itemTokens == nil { + self.stop() + self.pushErr(e.Token, LogMsg.BodyNotExist) + self.pushSuggestion(LogMsg.ExpectedBody) + ret e + } else if i < len(tokens) { + self.pushErr(tokens[i], LogMsg.InvalidSyntax) + } + e.Public = mod::IsPub(e.Ident) + e.End = tokens[i-1] + e.Items = self.buildEnumItems(itemTokens) + ret e + } + + fn buildNodeEnumDecl(mut &self, mut &tokens: []&Token): NodeData { + if len(tokens) > 3 && tokens[2].Id == TokenId.Colon { + if tokens[3].Id == TokenId.Type { + ret self.buildTypeEnumDecl(tokens) + } + } + ret self.buildEnumDecl(tokens) + } + + fn buildField(mut &self, mut tokens: []&Token): &FieldDecl { + mut f := new(FieldDecl) + + f.Mutable = tokens[0].Id == TokenId.Mut + if f.Mutable { + if len(tokens) == 1 { + self.pushErr(tokens[0], LogMsg.InvalidSyntax) + ret nil + } + tokens = tokens[1:] + } + + f.Token = tokens[0] + if f.Token.Id != TokenId.Ident { + self.pushErr(f.Token, LogMsg.InvalidSyntax) + self.pushSuggestion(LogMsg.ExpectedIdentifier) + ret nil + } + f.Ident = f.Token.Kind + + if len(tokens) == 1 { + self.pushErr(tokens[0], LogMsg.MissingType) + ret nil + } else if len(tokens) < 3 || tokens[1].Id != TokenId.Colon { + self.pushErr(tokens[1], LogMsg.MissingType) + ret nil + } + + tokens = tokens[2:] // Remove identifier and colon tokens. + mut i := 0 + f.Kind, _ = unsafe { self.buildType(tokens, &i, true) } + if i < len(tokens) { + token := tokens[i] + if token.Id != TokenId.Eq { + self.pushErr(tokens[i], LogMsg.InvalidSyntax) + ret nil + } + i++ + if i >= len(tokens) { + self.pushErr(token, LogMsg.MissingExpr) + ret nil + } + tokens = tokens[i:] + f.Default = self.buildExpr(tokens) + } + f.Public = mod::IsPub(f.Ident) + ret f + } + + fn buildStructDeclFields(mut &self, mut tokens: []&Token): []&FieldDecl { + let mut fields: []&FieldDecl = nil + mut stmts := splitStmts(tokens) + for (_, mut stmt) in stmts { + tokens = stmt.tokens + mut f := self.buildField(tokens) + fields = append(fields, f) + } + ret fields + } + + fn buildStructDecl(mut &self, mut &tokens: []&Token): &StructDecl { + if len(tokens) < 3 { + self.pushErr(tokens[0], LogMsg.InvalidSyntax) + ret nil + } + + mut i := 1 + mut s := &StructDecl{ + Token: tokens[i], + } + if s.Token.Id != TokenId.Ident { + self.pushErr(s.Token, LogMsg.InvalidSyntax) + self.pushSuggestion(LogMsg.ExpectedIdentifier) + } + i++ + if i >= len(tokens) { + self.pushErr(tokens[i], LogMsg.InvalidSyntax) + ret s + } + s.Ident = s.Token.Kind + + errorToken := tokens[i] + mut genericsTokens := range(i, TokenId.LBracket, TokenId.RBracket, tokens) + if genericsTokens != nil { + s.Generics = self.buildGenerics(genericsTokens, errorToken) + } + if i >= len(tokens) { + self.pushErr(tokens[i-1], LogMsg.BodyNotExist) + self.pushSuggestion(LogMsg.ExpectedBody) + ret s + } + + mut bodyTokens := range(i, TokenId.LBrace, TokenId.RBrace, tokens) + if bodyTokens == nil { + self.stop() + self.pushErr(s.Token, LogMsg.BodyNotExist) + self.pushSuggestion(LogMsg.ExpectedBody) + ret s + } + if i < len(tokens) { + self.pushErr(tokens[i], LogMsg.InvalidSyntax) + } + s.Public = mod::IsPub(s.Ident) + s.Fields = self.buildStructDeclFields(bodyTokens) + s.End = tokens[i-1] + ret s + } + + fn checkMethodReceiver(mut self, &f: &FnDecl) { + // Static methods cannot have receiver. + if f.Statically { + if len(f.Params) > 0 && f.Params[0].IsSelf() { + self.pushErr(f.Token, LogMsg.StaticFnHasReceiver) + } + ret + } + if len(f.Params) == 0 { + self.pushErr(f.Token, LogMsg.MissingReceiver) + ret + } + param := f.Params[0] + if !param.IsSelf() { + self.pushErr(f.Token, LogMsg.MissingReceiver) + ret + } + } + + fn buildTraitBody(mut &self, mut &t: &TraitDecl, mut tokens: []&Token) { + mut stmts := splitStmts(tokens) + for (_, mut stmt) in stmts { + tokens = stmt.tokens + if len(tokens) == 0 { + continue + } + match tokens[0].Id { + | TokenId.Fn: + mut f := self.buildFn(tokens, true, true) + if f == nil { + break + } + self.checkMethodReceiver(f) + if len(f.Generics) > 0 { + self.pushErr(f.Token, LogMsg.TraitMethodHasGenerics) + } + t.Methods = append(t.Methods, f) + |: + mut i := 0 + mut ti, ok := unsafe { self.buildType(tokens, &i, true) } + if !ok { + break + } + if i < len(tokens) { + self.pushErr(tokens[i], LogMsg.InvalidSyntax) + } + t.Inherits = append(t.Inherits, ti) + } + } + } + + fn buildTraitDecl(mut &self, mut &tokens: []&Token): &TraitDecl { + if len(tokens) < 3 { + self.pushErr(tokens[0], LogMsg.InvalidSyntax) + ret nil + } + mut t := &TraitDecl{ + Token: tokens[1], + } + if t.Token.Id != TokenId.Ident { + self.pushErr(t.Token, LogMsg.InvalidSyntax) + self.pushSuggestion(LogMsg.ExpectedIdentifier) + } + t.Ident = t.Token.Kind + mut i := 2 + mut bodyTokens := range(i, TokenId.LBrace, TokenId.RBrace, tokens) + if bodyTokens == nil { + self.stop() + self.pushErr(t.Token, LogMsg.BodyNotExist) + self.pushSuggestion(LogMsg.ExpectedBody) + ret nil + } + if i < len(tokens) { + self.pushErr(tokens[i], LogMsg.InvalidSyntax) + } + t.Public = mod::IsPub(t.Ident) + self.buildTraitBody(t, bodyTokens) + t.End = tokens[i-1] + ret t + } + + fn buildBindFn(mut &self, mut tokens: []&Token): &FnDecl { + tokens = tokens[1:] // Remove "cpp" keyword. + mut f := self.buildFn(tokens, false, true) + if f != nil { + f.Public = false + f.Binded = true + } + ret f + } + + fn buildBindVar(mut &self, mut tokens: []&Token): &VarDecl { + tokens = tokens[1:] // Remove "cpp" keyword. + mut v := self.buildVar(tokens) + if v != nil { + v.Public = false + v.Binded = true + if v.Expr != nil { + self.pushErr(v.Token, LogMsg.BindedVarHasExpr) + } + } + ret v + } + + fn buildBindStruct(mut &self, mut tokens: []&Token): &StructDecl { + tokens = tokens[1:] // Remove "cpp" keyword. + mut s := self.buildStructDecl(tokens) + if s != nil { + s.Public = false + for (_, mut f) in s.Fields { + // Binded structure's fields are always public by default. + f.Public = true + } + s.Binded = true + } + ret s + } + + fn buildBindTypeAlias(mut &self, mut tokens: []&Token): &TypeAliasDecl { + tokens = tokens[1:] // Remove "cpp" keyword. + mut t := self.buildTypeAliasDecl(tokens) + if t != nil { + t.Public = false + t.Binded = true + } + ret t + } + + fn buildBindUse(mut &self, mut tokens: []&Token): &UseDecl { + if len(tokens) == 1 { + self.pushErr(tokens[0], LogMsg.InvalidSyntax) + ret nil + } + tokens = tokens[1:] // Remove the bind keyword. + + const Binded = true + ret self.buildUseDecl(tokens, Binded) + } + + fn buildBind(mut &self, mut &tokens: []&Token): NodeData { + mut token := tokens[0] + if len(tokens) == 1 { + self.pushErr(token, LogMsg.InvalidSyntax) + ret nil + } + token = tokens[1] + match token.Id { + | TokenId.Fn + | TokenId.Unsafe: + ret self.buildBindFn(tokens) + | TokenId.Const + | TokenId.Let: + ret self.buildBindVar(tokens) + | TokenId.Struct: + ret self.buildBindStruct(tokens) + | TokenId.Type: + ret self.buildBindTypeAlias(tokens) + |: + self.pushErr(token, LogMsg.InvalidSyntax) + } + ret nil + } + + fn getMethod(mut &self, mut &tokens: []&Token): &FnDecl { + mut i := 0 + mut token := tokens[i] + if token.Id == TokenId.Static { + if i+1 >= len(tokens) { + self.pushErr(token, LogMsg.InvalidSyntax) + ret nil + } + i++ + token = tokens[i] + } + + if token.Id == TokenId.Unsafe { + if i+1 >= len(tokens) { + self.pushErr(token, LogMsg.InvalidSyntax) + ret nil + } + i++ + token = tokens[i] + } + + if token.Id != TokenId.Fn { + self.pushErr(token, LogMsg.InvalidSyntax) + ret nil + } + + ret self.buildFn(tokens, true, false) + } + + fn parseImplBody(mut &self, mut &ipl: &Impl, mut &tokens: []&Token) { + mut stmts := splitStmts(tokens) + for (_, mut stmt) in stmts { + tokens = stmt.tokens + mut token := tokens[0] + match token.Id { + | TokenId.Hash: + self.pushDirective(self.buildDirective(tokens)) + continue + } + + match token.Id { + | TokenId.Const: + mut v := self.buildVar(tokens) + if v != nil { + ipl.Statics = append(ipl.Statics, v) + } + | TokenId.Static + | TokenId.Fn + | TokenId.Unsafe: + mut f := self.getMethod(tokens) + if f != nil { + self.checkMethodReceiver(f) + self.applyFnMeta(f) + ipl.Methods = append(ipl.Methods, f) + } + |: + self.pushErr(token, LogMsg.InvalidSyntax) + continue + } + } + } + + fn buildImpl(mut &self, mut tokens: []&Token): &Impl { + mut token := tokens[0] + if len(tokens) < 2 { + self.pushErr(token, LogMsg.InvalidSyntax) + ret nil + } + + mut i := 1 + + mut base, mut ok := unsafe { self.buildType(tokens, &i, true) } + if !ok { + ret nil + } + if i >= len(tokens) { + self.pushErr(token, LogMsg.InvalidSyntax) + ret nil + } + + mut ipl := &Impl{ + Base: base, + } + + token = tokens[i] + if token.Id != TokenId.For { + if token.Id == TokenId.LBrace { + // This implementation is single. + // Just implements to destination. + // Therefore, swap Base and Dest tokens. + ipl.Base, ipl.Dest = ipl.Dest, ipl.Base + goto body + } + self.stop() + self.pushErr(token, LogMsg.BodyNotExist) + self.pushSuggestion(LogMsg.ExpectedBody) + ret nil + } + i++ + if i >= len(tokens) { + self.stop() + self.pushErr(token, LogMsg.BodyNotExist) + self.pushSuggestion(LogMsg.ExpectedBody) + ret nil + } + + ipl.Dest, ok = unsafe { self.buildType(tokens, &i, true) } + if !ok { + ret nil + } + if i >= len(tokens) { + self.stop() + self.pushErr(token, LogMsg.BodyNotExist) + self.pushSuggestion(LogMsg.ExpectedBody) + ret nil + } + + body: + mut bodyTokens := range(i, TokenId.LBrace, TokenId.RBrace, tokens) + if bodyTokens == nil { + self.stop() + self.pushErr(token, LogMsg.BodyNotExist) + self.pushSuggestion(LogMsg.ExpectedBody) + ret nil + } + if i < len(tokens) { + self.pushErr(tokens[i], LogMsg.InvalidSyntax) + } + ipl.End = tokens[i-1] + self.parseImplBody(ipl, bodyTokens) + ret ipl + } + + fn buildNodeData(mut &self, mut &tokens: []&Token): NodeData { + mut token := tokens[0] + match token.Id { + | TokenId.Fn + | TokenId.Unsafe: + mut f := self.buildFn(tokens, false, false) + if f != nil { + f.Global = true + } + ret f + | TokenId.Let + | TokenId.Const + | TokenId.Mut + | TokenId.Static: + ret self.buildVar(tokens) + | TokenId.Type: + ret self.buildTypeAliasDecl(tokens) + | TokenId.Enum: + ret self.buildNodeEnumDecl(tokens) + | TokenId.Struct: + ret self.buildStructDecl(tokens) + | TokenId.Trait: + ret self.buildTraitDecl(tokens) + | TokenId.Impl: + ret self.buildImpl(tokens) + | TokenId.Cpp: + ret self.buildBind(tokens) + |: + self.pushErr(token, LogMsg.InvalidSyntax) + ret nil + } + } + + fn applyFnMeta(mut self, mut &f: &FnDecl) { + f.Directives = self.directives + self.directives = nil + } + + fn applyMeta(mut self, mut &node: Node) { + match type node.Data { + | &VarDecl: + mut v := (&VarDecl)(node.Data) + if v == nil { + ret + } + v.Directives = self.directives + self.directives = nil + | &FnDecl: + mut f := (&FnDecl)(node.Data) + if f == nil { + ret + } + self.applyFnMeta(f) + | &StructDecl: + mut sd := (&StructDecl)(node.Data) + if sd == nil { + ret + } + sd.Directives = self.directives + self.directives = nil + } + } + + fn pushUseDecl(mut &self, mut &decl: &UseDecl) { + self.ast.UseDecls = append(self.ast.UseDecls, decl) + if len(self.ast.Nodes) > 0 { + self.pushErr(decl.Token, LogMsg.UseDeclAtBody) + self.pushSuggestion(LogMsg.MoveUseDeclToTopOfFile) + } + } + + fn pushMetaNodes(mut &self, mut &tokens: []&Token): bool { + match tokens[0].Id { + | TokenId.Use: + const Binded = false + mut decl := self.buildUseDecl(tokens, Binded) + self.pushUseDecl(decl) + ret true + | TokenId.Cpp: + if len(tokens) > 1 && tokens[1].Id == TokenId.Use { + mut decl := self.buildBindUse(tokens) + self.pushUseDecl(decl) + ret true + } + | TokenId.Hash: + self.pushDirective(self.buildDirective(tokens)) + ret true + } + ret false + } + + fn parseNode(mut &self, mut &st: []&Token): Node { + mut node := Node{ + Token: st[0], + } + + if self.pushMetaNodes(st) { + ret node + } + + mut data := self.buildNodeData(st) + if data == nil { + ret node + } + + node.Data = data + + self.applyMeta(node) + if len(self.directives) != 0 { + self.pushErr(self.directives[0].Tag, LogMsg.UnusedDirective) + } + self.directives = nil + ret node + } + + fn appendNode(mut &self, mut &st: []&Token) { + if len(st) == 0 { + ret + } + mut node := self.parseNode(st) + if node.Data != nil && !self.stopped() { + self.ast.Nodes = append(self.ast.Nodes, node) + } + } + + fn removeRange(self, mut i: int, id: TokenId, &tokens: []&Token, mut &ranges: []int) { + close := getCloseOfBrace(id) + for i >= 0; i-- { + tok := tokens[ranges[i]] + if tok.Id != close { + continue + } + ranges = append(ranges[:i], ranges[i+1:]...) + break + } + } + + fn pushWrongOrderCloseErr(mut self, &t: &Token, &tokens: []&Token, &ranges: []int) { + match tokens[ranges[len(ranges)-1]].Id { + | TokenId.LParent: + self.pushErr(t, LogMsg.ExpectedParentClose) + | TokenId.LBrace: + self.pushErr(t, LogMsg.ExpectedBraceClose) + | TokenId.LBracket: + self.pushErr(t, LogMsg.ExpectedBracketClose) + } + } + + fn pushRangeClose(mut self, t: &Token, left: TokenId, &tokens: []&Token, mut &ranges: []int) { + n := len(ranges) + if n == 0 { + match t.Id { + | TokenId.RBracket: + self.pushErr(t, LogMsg.ExtraClosedBracket) + | TokenId.RBrace: + self.pushErr(t, LogMsg.ExtraClosedBrace) + | TokenId.RParent: + self.pushErr(t, LogMsg.ExtraClosedParent) + } + ret + } else if tokens[ranges[n-1]].Id != left { + self.pushWrongOrderCloseErr(t, tokens, ranges) + } + self.removeRange(n - 1, t.Id, tokens, ranges) + } + + fn checkRanges(mut self, &tokens: []&Token) { + let mut ranges: []int = nil + + for i, token in tokens { + match token.Id { + | TokenId.LParent + | TokenId.LBrace + | TokenId.LBracket: + ranges = append(ranges, i) + | TokenId.RParent: + self.pushRangeClose(token, TokenId.LParent, tokens, ranges) + | TokenId.RBrace: + self.pushRangeClose(token, TokenId.LBrace, tokens, ranges) + | TokenId.RBracket: + self.pushRangeClose(token, TokenId.LBracket, tokens, ranges) + } + } + + for _, i in ranges { + token := tokens[i] + match token.Id { + | TokenId.LParent: + self.pushErr(token, LogMsg.WaitCloseParent) + | TokenId.LBrace: + self.pushErr(token, LogMsg.WaitCloseBrace) + | TokenId.LBracket: + self.pushErr(token, LogMsg.WaitCloseBracket) + } + } + } + + fn parse(mut &self, mut &f: &File) { + self.ast = &Ast{ + File: f, + } + self.ep = &exprBuilder{ + p: self, + } + + self.checkRanges(f.Tokens) + if len(self.errors) > 0 { + ret + } + + mut stmts := splitStmts(f.Tokens) + + // Get top directives. + mut i := 0 + for i < len(stmts); i++ { + mut stmt := stmts[i] + if len(stmt.tokens) < 2 { + ret + } + if stmt.tokens[0].Id != TokenId.Hash { + break + } + if !IsTopDirective(stmt.tokens[1].Kind) { + break + } + self.ast.TopDirectives = append(self.ast.TopDirectives, self.buildDirective(stmt.tokens)) + } + + // Remove all errors. + self.errors = nil + + for i < len(stmts) && !self.stopped(); i++ { + self.appendNode(stmts[i].tokens) + } + + if len(self.directives) != 0 { + self.pushErr(self.directives[0].Tag, LogMsg.UnusedDirective) + } + } } \ No newline at end of file diff --git a/std/jule/parser/scope.jule b/std/jule/parser/scope.jule index 798fe0957..655b9990d 100644 --- a/std/jule/parser/scope.jule +++ b/std/jule/parser/scope.jule @@ -3,1180 +3,1180 @@ // license that can be found in the LICENSE file. use std::jule::ast::{ - ScopeTree, - Node, - NodeData, - RetSt, - Iter, - WhileKind, - VarDecl, - RangeKind, - IterKind, - BreakSt, - ContSt, - If, - Else, - Conditional, - FnCallExpr, - Expr, - GotoSt, - FallSt, - Case, - MatchCase, - LabelSt, - AssignLeft, - AssignSt, - UseExpr, - Stmt, - StmtData, - TypeAliasDecl, + ScopeTree, + Node, + NodeData, + RetSt, + Iter, + WhileKind, + VarDecl, + RangeKind, + IterKind, + BreakSt, + ContSt, + If, + Else, + Conditional, + FnCallExpr, + Expr, + GotoSt, + FallSt, + Case, + MatchCase, + LabelSt, + AssignLeft, + AssignSt, + UseExpr, + Stmt, + StmtData, + TypeAliasDecl, } use std::jule::build::{LogMsg} use std::jule::lex::{ - Token, - TokenId, - TokenKind, - IsAssignOp, - IsPostfixOp, - IsBinOp, + Token, + TokenId, + TokenKind, + IsAssignOp, + IsPostfixOp, + IsBinOp, } fn newScope(): &ScopeTree { - ret new(ScopeTree) + ret new(ScopeTree) } // Reports whether token is statement finish point. fn isSt(current: &Token, prev: &Token): (ok: bool, terminated: bool) { - ok = current.Id == TokenId.Semicolon || prev.Row < current.Row - terminated = current.Id == TokenId.Semicolon - ret + ok = current.Id == TokenId.Semicolon || prev.Row < current.Row + terminated = current.Id == TokenId.Semicolon + ret } fn prevIsIncompleteExpr(&tokens: []&Token, &i: int): bool { - // Ignore namespaces. - if i > 1 && tokens[i-2].Id == TokenId.DblColon { - ret false - } - unsafe { - prev := tokens[i-1] - ret prev.Id == TokenId.Dot || - (IsBinOp(prev.Id) && prev.Row < tokens[i].Row) - } + // Ignore namespaces. + if i > 1 && tokens[i-2].Id == TokenId.DblColon { + ret false + } + unsafe { + prev := tokens[i-1] + ret prev.Id == TokenId.Dot || + (IsBinOp(prev.Id) && prev.Row < tokens[i].Row) + } } // Reports position of the next statement if exist, len(toks) if not. fn nextStPos(&tokens: []&Token, start: int): (int, bool) { - mut braceN := 0 - mut i := start - for i < len(tokens); i++ { - mut ok := false - mut terminated := false - tok := tokens[i] - match tok.Id { - | TokenId.LBrace - | TokenId.LBracket - | TokenId.LParent: - if braceN == 0 && i > start { - if !prevIsIncompleteExpr(tokens, i) { - ok, terminated = isSt(tok, tokens[i-1]) - if ok { - goto return - } - } - } - braceN++ - continue - | TokenId.RBrace - | TokenId.RBracket - | TokenId.RParent: - braceN-- - if braceN == 0 && i+1 < len(tokens) { - ok, terminated = isSt(tokens[i+1], tok) - if ok { - i++ - goto return - } - } - continue - } - - if braceN != 0 { - continue - } - - if i > start { - if prevIsIncompleteExpr(tokens, i) { - continue - } - ok, terminated = isSt(tok, tokens[i-1]) - } else { - ok, terminated = isSt(tok, tok) - } - if !ok { - continue - } - - return: - if terminated { - i++ - } - ret i, terminated - } - ret i, false + mut braceN := 0 + mut i := start + for i < len(tokens); i++ { + mut ok := false + mut terminated := false + tok := tokens[i] + match tok.Id { + | TokenId.LBrace + | TokenId.LBracket + | TokenId.LParent: + if braceN == 0 && i > start { + if !prevIsIncompleteExpr(tokens, i) { + ok, terminated = isSt(tok, tokens[i-1]) + if ok { + goto return + } + } + } + braceN++ + continue + | TokenId.RBrace + | TokenId.RBracket + | TokenId.RParent: + braceN-- + if braceN == 0 && i+1 < len(tokens) { + ok, terminated = isSt(tokens[i+1], tok) + if ok { + i++ + goto return + } + } + continue + } + + if braceN != 0 { + continue + } + + if i > start { + if prevIsIncompleteExpr(tokens, i) { + continue + } + ok, terminated = isSt(tok, tokens[i-1]) + } else { + ok, terminated = isSt(tok, tok) + } + if !ok { + continue + } + + return: + if terminated { + i++ + } + ret i, terminated + } + ret i, false } // Returns current statement tokens. // Starts selection at i. fn skipSt(mut &i: int, mut tokens: []&Token): ([]&Token, bool) { - start := i - mut terminated := false - i, terminated = nextStPos(tokens, start) - mut stTokens := tokens[start:i] - if terminated { - if len(stTokens) == 1 { - ret skipSt(i, tokens) - } - // -1 for eliminate statement terminator. - stTokens = stTokens[:len(stTokens)-1] - } - ret stTokens, terminated + start := i + mut terminated := false + i, terminated = nextStPos(tokens, start) + mut stTokens := tokens[start:i] + if terminated { + if len(stTokens) == 1 { + ret skipSt(i, tokens) + } + // -1 for eliminate statement terminator. + stTokens = stTokens[:len(stTokens)-1] + } + ret stTokens, terminated } struct stmt { - tokens: []&Token - terminated: bool + tokens: []&Token + terminated: bool } // Splits all statements. fn splitStmts(mut &tokens: []&Token): []&stmt { - mut stmts := make([]&stmt, 0, 20) - mut pos := 0 - for pos < len(tokens) { - mut stmt, terminated := skipSt(pos, tokens) - stmts = append(stmts, &stmt{ - tokens: stmt, - terminated: terminated, - }) - } - ret stmts + mut stmts := make([]&stmt, 0, 20) + mut pos := 0 + for pos < len(tokens) { + mut stmt, terminated := skipSt(pos, tokens) + stmts = append(stmts, &stmt{ + tokens: stmt, + terminated: terminated, + }) + } + ret stmts } struct scopeParser { - p: &parser - s: &ScopeTree - stmts: []&stmt - pos: int + p: &parser + s: &ScopeTree + stmts: []&stmt + pos: int } impl scopeParser { - fn stop(mut self) { - self.pos = -1 - } - - fn stopped(self): bool { - ret self.pos == -1 - } - - fn finished(self): bool { - ret self.pos >= len(self.stmts) - } - - fn isLastSt(self): bool { - ret self.pos+1 >= len(self.stmts) - } - - fn pushErr(mut self, token: &Token, fmt: LogMsg) { - self.p.pushErr(token, fmt) - } - - // Push suggestion to last log. - fn pushSuggestion(mut self, fmt: LogMsg, args: ...any) { - self.p.pushSuggestion(fmt, args...) - } - - fn insertAsNext(mut self, mut &tokens: []&Token) { - self.stmts = append(self.stmts[:self.pos+1], self.stmts[self.pos:]...) - self.stmts[self.pos+1] = &stmt{tokens: tokens} - } - - fn next(mut self): &stmt { - self.pos++ - ret self.stmts[self.pos] - } - - fn buildScope(mut self, mut &tokens: []&Token, mut end: &Token): &ScopeTree { - mut s := newScope() - s.Parent = self.s - s.End = end - mut ssp := scopeParser{ - p: self.p, - } - ssp.build(tokens, s) - ret s - } - - fn buildVarSt(mut self, mut &tokens: []&Token): &VarDecl { - mut v := self.p.buildVar(tokens) - v.Scope = self.s - ret v - } - - fn buildRetSt(mut self, mut tokens: []&Token): &RetSt { - mut st := &RetSt{ - Token: tokens[0], - } - if len(tokens) > 1 { - tokens = tokens[1:] // Remove ret keyword. - st.Expr = self.p.buildExpr(tokens) - } - ret st - } - - fn buildWhileNextIter(mut self, mut &s: &stmt): &Iter { - mut it := &Iter{ - Token: s.tokens[0], - } - mut tokens := s.tokens[1:] // Skip "iter" keyword. - mut kind := new(WhileKind) - - if len(tokens) > 0 { - kind.Expr = self.p.buildExpr(tokens) - } - - if self.isLastSt() { - self.pushErr(it.Token, LogMsg.InvalidSyntax) - ret nil - } - - tokens = self.next().tokens - mut stTokens := getBlockExpr(tokens) - if len(stTokens) > 0 { - mut stmt := &stmt{ - terminated: s.terminated, - tokens: stTokens, - } - kind.NextToken = stTokens[0] - kind.Next = self.buildSt(stmt) - } - - mut i := len(stTokens) - mut blockTokens := range(i, TokenId.LBrace, TokenId.RBrace, tokens) - if blockTokens == nil { - self.stop() - self.pushErr(it.Token, LogMsg.BodyNotExist) - self.pushSuggestion(LogMsg.ExpectedBody) - ret nil - } - if i < len(tokens) { - self.pushErr(tokens[i], LogMsg.InvalidSyntax) - } - - it.Scope = self.buildScope(blockTokens, tokens[i-1]) - it.Kind = kind - - ret it - } - - fn buildWhileIterKind(mut self, mut &tokens: []&Token): &WhileKind { - ret &WhileKind{ - Expr: self.p.buildExpr(tokens), - } - } - - fn getRangeKindKeysTokens(mut self, mut &toks: []&Token): [][]&Token { - mut vars, errs := parts(toks, TokenId.Comma, true) - self.p.errors = append(self.p.errors, errs...) - ret vars - } - - fn buildRangeKindKey(mut self, mut &tokens: []&Token): &VarDecl { - if len(tokens) == 0 { - ret nil - } - mut key := &VarDecl{ - Token: tokens[0], - Setter: tokens[0], - } - if key.Token.Id == TokenId.Mut { - key.Mutable = true - if len(tokens) == 1 { - self.pushErr(key.Token, LogMsg.InvalidSyntax) - } - key.Token = tokens[1] - } else if len(tokens) > 1 { - self.pushErr(tokens[1], LogMsg.InvalidSyntax) - } - if key.Token.Id != TokenId.Ident { - self.pushErr(key.Token, LogMsg.InvalidSyntax) - self.pushSuggestion(LogMsg.ExpectedIdentifier) - ret nil - } - key.Ident = key.Token.Kind - ret key - } - - fn buildRangeKindKeys(mut self, mut &parts: [][]&Token): []&VarDecl { - let mut keys: []&VarDecl = nil - for (_, mut tokens) in parts { - keys = append(keys, self.buildRangeKindKey(tokens)) - } - ret keys - } - - fn setupRangeKindKeysPlain(mut self, mut &rng: &RangeKind, mut &tokens: []&Token) { - mut keyTokens := self.getRangeKindKeysTokens(tokens) - if len(keyTokens) == 0 { - ret - } - if len(keyTokens) > 2 { - self.pushErr(rng.InToken, LogMsg.MuchRangeVars) - } - mut keys := self.buildRangeKindKeys(keyTokens) - rng.KeyA = keys[0] - if len(keys) > 1 { - rng.KeyB = keys[1] - } - } - - fn setupRangeKindKeysExplicit(mut self, mut &rng: &RangeKind, mut &tokens: []&Token) { - mut i := 0 - mut rang := range(i, TokenId.LParent, TokenId.RParent, tokens) - if i < len(tokens) { - self.pushErr(rng.InToken, LogMsg.InvalidSyntax) - } - self.setupRangeKindKeysPlain(rng, rang) - } - - fn setupRangeKindKeys(mut self, mut &rng: &RangeKind, mut &tokens: []&Token) { - if tokens[0].Id == TokenId.LParent { - self.setupRangeKindKeysExplicit(rng, tokens) - ret - } - self.setupRangeKindKeysPlain(rng, tokens) - } - - fn buildRangeIterKind(mut self, mut &var_tokens: []&Token, - mut &exprTokens: []&Token, mut &inToken: &Token): &RangeKind { - mut rng := &RangeKind{ - InToken: inToken, - } - if len(exprTokens) == 0 { - self.pushErr(rng.InToken, LogMsg.MissingExpr) - ret rng - } - rng.Expr = self.p.buildExpr(exprTokens) - if len(var_tokens) > 0 { - self.setupRangeKindKeys(rng, var_tokens) - } - ret rng - } - - fn buildCommonIterKind(mut self, mut &tokens: []&Token, &err_tok: &Token): IterKind { - mut braceN := 0 - for (i, mut tok) in tokens { - match tok.Id { - | TokenId.LBrace - | TokenId.LBracket - | TokenId.LParent: - braceN++ - continue - | TokenId.RBrace - | TokenId.RBracket - | TokenId.RParent: - braceN-- - } - if braceN != 0 { - continue - } - match tok.Id { - | TokenId.In: - mut declTokens := tokens[:i] - mut exprTokens := tokens[i+1:] - ret self.buildRangeIterKind(declTokens, exprTokens, tok) - } - } - ret self.buildWhileIterKind(tokens) - } - - fn buildCommonIter(mut self, mut tokens: []&Token): &Iter { - mut it := &Iter{ - Token: tokens[0], - } - tokens = tokens[1:] // Skip "iter" keyword. - if len(tokens) == 0 { - self.stop() - self.pushErr(it.Token, LogMsg.BodyNotExist) - self.pushSuggestion(LogMsg.ExpectedBody) - ret nil - } - mut exprTokens := getBlockExpr(tokens) - if len(exprTokens) > 0 { - it.Kind = self.buildCommonIterKind(exprTokens, it.Token) - } - mut i := len(exprTokens) - mut scopeTokens := range(i, TokenId.LBrace, TokenId.RBrace, tokens) - if scopeTokens == nil { - self.stop() - self.pushErr(it.Token, LogMsg.BodyNotExist) - self.pushSuggestion(LogMsg.ExpectedBody) - ret nil - } - if i < len(tokens) { - self.pushErr(tokens[i], LogMsg.InvalidSyntax) - } - it.Scope = self.buildScope(scopeTokens, tokens[i-1]) - ret it - } - - fn buildIterSt(mut self, mut &st: &stmt): &Iter { - if st.terminated { - ret self.buildWhileNextIter(st) - } - ret self.buildCommonIter(st.tokens) - } - - fn buildBreakSt(mut self, mut &tokens: []&Token): &BreakSt { - mut brk := &BreakSt{ - Token: tokens[0], - } - if len(tokens) > 1 { - if tokens[1].Id != TokenId.Ident { - self.pushErr(tokens[1], LogMsg.InvalidSyntax) - self.pushSuggestion(LogMsg.ExpectedLabelIdent) - } else { - brk.Label = tokens[1] - if len(tokens) > 2 { - self.pushErr(tokens[1], LogMsg.InvalidSyntax) - } - } - } - ret brk - } - - fn buildContSt(mut self, mut &tokens: []&Token): &ContSt { - mut cont := &ContSt{ - Token: tokens[0], - } - if len(tokens) > 1 { - if tokens[1].Id != TokenId.Ident { - self.pushErr(tokens[1], LogMsg.InvalidSyntax) - self.pushSuggestion(LogMsg.ExpectedLabelIdent) - } else { - cont.Label = tokens[1] - if len(tokens) > 2 { - self.pushErr(tokens[1], LogMsg.InvalidSyntax) - } - } - } - ret cont - } - - fn buildIf(mut self, mut &tokens: []&Token): &If { - mut model := &If{ - Token: tokens[0], - } - tokens = tokens[1:] - mut exprTokens := getBlockExpr(tokens) - mut i := 0 - if len(exprTokens) == 0 { - self.pushErr(model.Token, LogMsg.MissingExpr) - } else { - i = len(exprTokens) - } - mut scopeTokens := range(i, TokenId.LBrace, TokenId.RBrace, tokens) - if scopeTokens == nil { - self.stop() - self.pushErr(model.Token, LogMsg.BodyNotExist) - self.pushSuggestion(LogMsg.ExpectedBody) - ret nil - } - mut end := tokens[i-1] - if i < len(tokens) { - if tokens[i].Id == TokenId.Else { - tokens = tokens[i:] - } else { - self.pushErr(tokens[i], LogMsg.InvalidSyntax) - tokens = nil - } - } - model.Expr = self.p.buildExpr(exprTokens) - model.Scope = self.buildScope(scopeTokens, end) - ret model - } - - fn buildElse(mut self, mut &tokens: []&Token): &Else { - mut els := &Else{ - Token: tokens[0], - } - tokens = tokens[1:] // Remove "else" keyword. - mut i := 0 - mut scopeTokens := range(i, TokenId.LBrace, TokenId.RBrace, tokens) - if scopeTokens == nil { - if i < len(tokens) { - self.pushErr(els.Token, LogMsg.ElseHaveExpr) - } else { - self.stop() - self.pushErr(els.Token, LogMsg.BodyNotExist) - self.pushSuggestion(LogMsg.ExpectedBody) - } - ret nil - } - if i < len(tokens) { - self.pushErr(tokens[i], LogMsg.InvalidSyntax) - } - els.Scope = self.buildScope(scopeTokens, tokens[i-1]) - ret els - } - - fn buildIfElseChain(mut self, mut tokens: []&Token): &Conditional { - mut chain := &Conditional{ - Head: self.buildIf(tokens), - } - if chain.Head == nil { - ret nil - } - for len(tokens) != 0 { - if tokens[0].Id != TokenId.Else { - break - } - if len(tokens) > 1 && tokens[1].Id == TokenId.If { - tokens = tokens[1:] // Remove else token - mut elif := self.buildIf(tokens) - chain.Tail = append(chain.Tail, elif) - continue - } - chain.Default = self.buildElse(tokens) - break - } - ret chain - } - - fn buildCoCallSt(mut self, mut tokens: []&Token): &Expr { - token := tokens[0] - tokens = tokens[1:] // Start 1 to skip "co" token. - mut e := self.p.buildExpr(tokens) - if e == nil { - ret e - } - match type e.Kind { - | &FnCallExpr: - (&FnCallExpr)(e.Kind).IsCo = true - |: - self.pushErr(token, LogMsg.ExprNotFnCall) - } - ret e - } - - fn buildGotoSt(mut self, mut &tokens: []&Token): &GotoSt { - mut gt := &GotoSt{ - Token: tokens[0], - } - if len(tokens) == 1 { - self.pushErr(gt.Token, LogMsg.MissingGotoLabel) - ret nil - } else if len(tokens) > 2 { - self.pushErr(tokens[2], LogMsg.InvalidSyntax) - } - mut identToken := tokens[1] - if identToken.Id != TokenId.Ident { - self.pushErr(identToken, LogMsg.InvalidSyntax) - self.pushSuggestion(LogMsg.ExpectedIdentifier) - ret gt - } - gt.Label = identToken - ret gt - } - - fn buildFallSt(mut self, mut &tokens: []&Token): &FallSt { - mut fll := &FallSt{ - Token: tokens[0], - } - if len(tokens) > 1 { - self.pushErr(tokens[1], LogMsg.InvalidSyntax) - } - ret fll - } - - fn buildTypeAliasSt(mut self, mut &tokens: []&Token): &TypeAliasDecl { - mut tad := self.p.buildTypeAliasDecl(tokens) - tad.Scope = self.s - ret tad - } - - fn pushCaseExpr(mut self, mut tokens: []&Token, mut token: &Token, - typeMatch: bool, mut &exprs: []&Expr) { - if len(tokens) == 0 { - ret - } - if typeMatch { - mut i := 0 - mut t, ok := unsafe { self.p.buildType(tokens, &i, true) } - if ok { - exprs = append(exprs, &Expr{ - Token: tokens[0], - End: tokens[len(tokens)-1], - Kind: t, - }) - if i < len(tokens) { - self.pushErr(tokens[i], LogMsg.InvalidSyntax) - } - } - ret - } - exprs = append(exprs, self.p.buildExpr(tokens)) - } - - fn buildCaseExprs(mut self, mut &tokens: []&Token, mut &colon: &Token, typeMatch: bool): ([]&Expr, bool) { - mut exprs := make([]&Expr, 0, 1) - mut braceN := 0 - mut j := 0 - for (i, mut tok) in tokens { - match tok.Id { - | TokenId.LParent - | TokenId.LBrace - | TokenId.LBracket: - braceN++ - continue - | TokenId.RParent - | TokenId.RBrace - | TokenId.RBracket: - braceN-- - continue - } - - if braceN != 0 { - continue - } - match { - | tok.Id == TokenId.Vline: - exprTokens := tokens[j:i] - if len(exprTokens) == 0 { - self.pushErr(tok, LogMsg.MissingExpr) - } else { - self.pushCaseExpr(tokens[j:i], tok, typeMatch, exprs) - } - j = i + 1 - | tok.Id == TokenId.Colon: - colon = tok - self.pushCaseExpr(tokens[j:i], tok, typeMatch, exprs) - tokens = tokens[i+1:] - ret exprs, i-j == 0 || len(exprs) != 0 - } - } - self.pushErr(tokens[0], LogMsg.InvalidSyntax) - tokens = nil - ret nil, false - } - - fn buildCaseScope(mut self, mut &tokens: []&Token): &ScopeTree { - mut n := 0 - for { - mut i := 0 - mut next, _ := skipSt(i, tokens[n:]) - if len(next) == 0 { - break - } - tok := next[0] - if tok.Id != TokenId.Vline { - n += i - continue - } - mut scopeTokens := tokens[:n] - mut scope := self.buildScope(scopeTokens, tokens[n]) - tokens = tokens[n:] - ret scope - } - let mut end: &Token - if len(tokens) > 0 { - end = tokens[len(tokens)-1] - } - mut scope := self.buildScope(tokens, end) - tokens = nil - ret scope - } - - fn buildCase(mut self, mut &tokens: []&Token, typeMatch: bool): (&Case, bool) { - mut c := &Case{ - Token: tokens[0], - } - tokens = tokens[1:] // Remove case prefix. - let mut colon: &Token = nil - c.Exprs, ok := self.buildCaseExprs(tokens, colon, typeMatch) - c.Scope = self.buildCaseScope(tokens) - if c.Scope.End == nil { - c.Scope.End = colon - } - isDefault := ok && len(c.Exprs) == 0 - ret c, isDefault - } - - fn buildCases(mut self, mut tokens: []&Token, typeMatch: bool): ([]&Case, &Else) { - let mut cases: []&Case = nil - let mut def: &Else = nil - mut defNotLast := false - for len(tokens) > 0 { - mut tok := tokens[0] - if tok.Id != TokenId.Vline { - self.pushErr(tok, LogMsg.InvalidSyntax) - break - } - mut c, isDefault := self.buildCase(tokens, typeMatch) - if isDefault { - c.Token = tok - if def == nil { - def = &Else{ - Token: c.Token, - Scope: c.Scope, - } - } else { - self.pushErr(tok, LogMsg.InvalidSyntax) - } - } else { - defNotLast = defNotLast || def != nil - cases = append(cases, c) - } - } - - if defNotLast { - self.pushErr(def.Token, LogMsg.DefaultNotLast) - } - - ret cases, def - } - - fn buildMatchCase(mut self, mut tokens: []&Token): &MatchCase { - mut m := &MatchCase{ - Token: tokens[0], - } - tokens = tokens[1:] // Remove "match" keyword. - - if len(tokens) > 0 && tokens[0].Id == TokenId.Type { - m.TypeMatch = true - tokens = tokens[1:] // Skip "type" keyword - } - - mut exprTokens := getBlockExpr(tokens) - if len(exprTokens) > 0 { - m.Expr = self.p.buildExpr(exprTokens) - } else if m.TypeMatch { - self.pushErr(m.Token, LogMsg.MissingExpr) - } - - mut i := len(exprTokens) - mut blockToks := range(i, TokenId.LBrace, TokenId.RBrace, tokens) - if blockToks == nil { - self.stop() - self.pushErr(m.Token, LogMsg.BodyNotExist) - self.pushSuggestion(LogMsg.ExpectedBody) - ret nil - } else if i < len(tokens) { - self.pushErr(tokens[i], LogMsg.InvalidSyntax) - } - m.End = tokens[i-1] - m.Cases, m.Default = self.buildCases(blockToks, m.TypeMatch) - ret m - } - - fn buildScopeSt(mut self, mut tokens: []&Token): &ScopeTree { - mut isUnsafe := false - mut isDeferred := false - mut token := tokens[0] - if token.Id == TokenId.Unsafe { - isUnsafe = true - tokens = tokens[1:] - if len(tokens) == 0 { - self.pushErr(token, LogMsg.InvalidSyntax) - ret nil - } - token = tokens[0] - if token.Id == TokenId.Defer { - isDeferred = true - tokens = tokens[1:] - if len(tokens) == 0 { - self.pushErr(token, LogMsg.InvalidSyntax) - ret nil - } - } - } else if token.Id == TokenId.Defer { - isDeferred = true - tokens = tokens[1:] - if len(tokens) == 0 { - self.pushErr(token, LogMsg.InvalidSyntax) - ret nil - } - } - - mut i := 0 - mut scopeTokens := range(i, TokenId.LBrace, TokenId.RBrace, tokens) - if scopeTokens == nil { - self.pushErr(token, LogMsg.InvalidSyntax) - ret nil - } else if i < len(tokens) { - self.pushErr(tokens[i], LogMsg.InvalidSyntax) - } - mut scope := self.buildScope(scopeTokens, tokens[i-1]) - scope.Unsafety = isUnsafe - scope.Deferred = isDeferred - ret scope - } - - fn buildLabelSt(mut self, mut &tokens: []&Token): &LabelSt { - mut lbl := &LabelSt{ - Token: tokens[0], - Ident: tokens[0].Kind, - } - - // Save followed statement - if len(tokens) > 2 { - tokens = tokens[2:] // Remove goto keyword and label - self.insertAsNext(tokens) - } - - ret lbl - } - - fn buildIdSt(mut self, mut &tokens: []&Token): (StmtData, ok: bool) { - if len(tokens) == 1 { - ret - } - - mut token := tokens[1] - match token.Id { - | TokenId.Colon: - ret self.buildLabelSt(tokens), true - } - - ret - } - - fn buildAssignInfo(mut self, mut &tokens: []&Token): &assignInfo { - mut info := &assignInfo{ - ok: true, - } - mut braceN := 0 - for (i, mut token) in tokens { - match token.Id { - | TokenId.LBrace - | TokenId.LBracket - | TokenId.LParent: - braceN++ - | TokenId.RBrace - | TokenId.RBracket - | TokenId.RParent: - braceN-- - } - match { - | braceN > 0: - continue - | !IsAssignOp(token.Id) && token.Id != TokenId.ColonEq: - continue - } - - info.l = tokens[:i] - if len(info.l) == 0 { - info.ok = false - } - info.setter = token - if i+1 >= len(tokens) { - info.r = nil - info.ok = IsPostfixOp(info.setter.Id) - break - } - info.r = tokens[i+1:] - if IsPostfixOp(info.setter.Id) { - if len(info.r) > 0 { - self.pushErr(info.r[0], LogMsg.InvalidSyntax) - info.r = nil - } - } - break - } - ret info - } - - fn buildAssignL(mut self, mut &tokens: []&Token): &AssignLeft { - mut l := &AssignLeft{ - Token: tokens[0], - } - if tokens[0].Id == TokenId.Ident { - l.Ident = l.Token.Kind - } - l.Expr = self.p.buildExpr(tokens) - ret l - } - - fn buildAssignLs(mut self, mut &parts: [][]&Token): []&AssignLeft { - let mut lefts: []&AssignLeft = nil - for (_, mut part) in parts { - mut l := self.buildAssignL(part) - lefts = append(lefts, l) - } - ret lefts - } - - fn buildPlainAssign(mut self, mut &tokens: []&Token): (StmtData, bool) { - mut info := self.buildAssignInfo(tokens) - if !info.ok { - ret nil, false - } - - mut assign := &AssignSt{ - Setter: info.setter, - } - - // Caught declaration assignments. - if info.setter.Id == TokenId.ColonEq { - assign.Declarative = true - assign.Right = self.p.buildExpr(info.r) - ok := self.buildDeclAssign1(info.l, assign) - if !ok { - // Return with true to avoid duplicate error. - ret nil, true - } - if len(assign.Left) > 1 { - ret assign, true - } - // Single left, use &VarDecl intead. - mut left := assign.Left[0] - mut decl := &VarDecl{ - Token: left.Token, - Setter: assign.Setter, - Ident: left.Ident, - Mutable: left.Mutable, - Reference: left.Reference, - Scope: self.s, - Expr: assign.Right, - } - ret decl, true - } - - mut parts, errs := parts(info.l, TokenId.Comma, true) - if len(errs) > 0 { - self.p.errors = append(self.p.errors, errs...) - ret nil, false - } - - assign.Left = self.buildAssignLs(parts) - if info.r != nil { - assign.Right = self.p.buildExpr(info.r) - } - - ret assign, true - } - - fn buildDeclAssign1(mut self, mut &lefts: []&Token, mut &assign: &AssignSt): bool { - // Lefts - mut parts, errs := parts(lefts, TokenId.Comma, true) - if len(errs) > 0 { - self.p.errors = append(self.p.errors, errs...) - ret false - } - - for (_, mut part) in parts { - mut isMut := false - mut isRef := false - - token := part[0] - if token.Id == TokenId.Mut { - isMut = true - part = part[1:] - if len(part) == 0 { - self.pushErr(token, LogMsg.InvalidSyntax) - ret false - } - } - - if part[0].Id == TokenId.Amper { - isRef = true - part = part[1:] - if len(part) == 0 { - self.pushErr(token, LogMsg.InvalidSyntax) - ret false - } - } - - if part[0].Id != TokenId.Ident && part[0].Id != TokenId.LParent { - self.pushErr(token, LogMsg.InvalidSyntax) - ret false - } - - mut l := self.buildAssignL(part) - l.Mutable = isMut - l.Reference = isRef - assign.Left = append(assign.Left, l) - } - - ret true - } - - fn buildDeclAssign(mut self, mut tokens: []&Token): (&AssignSt, bool) { - if len(tokens) < 1 { - ret nil, false - } - - tokens = tokens[1:] // Skip "let" keyword - mut token := tokens[0] - if token.Id != TokenId.LParent { - ret nil, false - } - - mut assign := &AssignSt{ - Declarative: true, - } - - mut i := 0 - mut rang := range(i, TokenId.LParent, TokenId.RParent, tokens) - if rang == nil { - self.pushErr(token, LogMsg.InvalidSyntax) - ret nil, false - } else if i+1 < len(tokens) { - assign.Setter = tokens[i] - if assign.Setter.Id != TokenId.Eq { - self.pushErr(assign.Setter, LogMsg.InvalidSyntax) - } - i++ - mut exprTokens := tokens[i:] - assign.Right = self.p.buildExpr(exprTokens) - } - - ok := self.buildDeclAssign1(rang, assign) - ret assign, ok - } - - fn buildAssignSt(mut self, mut &tokens: []&Token): (st: StmtData, ok: bool) { - if !checkAssignTokens(tokens) { - ret nil, false - } - match tokens[0].Id { - | TokenId.Let: - st, ok = self.buildDeclAssign(tokens) - |: - st, ok = self.buildPlainAssign(tokens) - } - ret - } - - fn buildUseExpr(mut self, mut &tokens: []&Token): &UseExpr { - if len(tokens) == 1 { - self.pushErr(tokens[0], LogMsg.MissingExpr) - ret nil - } - mut ue := &UseExpr{ - Token: tokens[0], - } - tokens = tokens[1:] // Ignore "use" keyword. - ue.Expr = self.p.buildExpr(tokens) - ret ue - } - - fn buildConstSt(mut self, mut &st: &stmt): StmtData { - if len(st.tokens) == 1 { - self.pushErr(st.tokens[0], LogMsg.InvalidSyntax) - ret nil - } - match st.tokens[1].Id { - | TokenId.For: - st.tokens = st.tokens[1:] - mut iter := self.buildIterSt(st) - if iter != nil { - iter.Comptime = true - } - ret iter - | TokenId.Match: - st.tokens = st.tokens[1:] - mut mt := self.buildMatchCase(st.tokens) - if mt != nil { - mt.Comptime = true - } - ret mt - |: - ret self.buildVarSt(st.tokens) - } - } - - fn buildSt(mut self, mut &st: &stmt): StmtData { - mut token := st.tokens[0] - if token.Id == TokenId.Ident { - mut s, ok := self.buildIdSt(st.tokens) - if ok { - ret s - } - } - - mut s, ok := self.buildAssignSt(st.tokens) - if ok { - ret s - } - - match token.Id { - | TokenId.Use: - ret self.buildUseExpr(st.tokens) - | TokenId.Const: - ret self.buildConstSt(st) - | TokenId.Static - | TokenId.Let - | TokenId.Mut: - ret self.buildVarSt(st.tokens) - | TokenId.Ret: - ret self.buildRetSt(st.tokens) - | TokenId.For: - ret self.buildIterSt(st) - | TokenId.Break: - ret self.buildBreakSt(st.tokens) - | TokenId.Cont: - ret self.buildContSt(st.tokens) - | TokenId.If: - ret self.buildIfElseChain(st.tokens) - | TokenId.Co: - ret self.buildCoCallSt(st.tokens) - | TokenId.Goto: - ret self.buildGotoSt(st.tokens) - | TokenId.Fall: - ret self.buildFallSt(st.tokens) - | TokenId.Type: - ret self.buildTypeAliasSt(st.tokens) - | TokenId.Match: - ret self.buildMatchCase(st.tokens) - | TokenId.Unsafe: - if len(st.tokens) < 1 { - break - } - if st.tokens[1].Id == TokenId.Defer || - st.tokens[1].Id == TokenId.LBrace { // Scope. - ret self.buildScopeSt(st.tokens) - } - | TokenId.Defer: - ret self.buildScopeSt(st.tokens) - | TokenId.LBrace: - ret self.buildScopeSt(st.tokens) - } - mut expr := self.p.buildExpr(st.tokens) - if expr != nil { - ret expr - } - self.pushErr(token, LogMsg.InvalidSyntax) - ret nil - } - - fn build(mut self, mut &tokens: []&Token, mut &s: &ScopeTree) { - if s == nil { - ret - } - self.stmts = splitStmts(tokens) - self.pos = -1 // sp.next() first increase position - self.s = s - for !self.isLastSt() && !self.finished() { - mut st := self.next() - mut data := self.buildSt(st) - if data != nil { - self.s.Stmts = append(self.s.Stmts, Stmt{ - Token: st.tokens[0], - Data: data, - }) - } - if self.stopped() { - break - } - } - } + fn stop(mut self) { + self.pos = -1 + } + + fn stopped(self): bool { + ret self.pos == -1 + } + + fn finished(self): bool { + ret self.pos >= len(self.stmts) + } + + fn isLastSt(self): bool { + ret self.pos+1 >= len(self.stmts) + } + + fn pushErr(mut self, token: &Token, fmt: LogMsg) { + self.p.pushErr(token, fmt) + } + + // Push suggestion to last log. + fn pushSuggestion(mut self, fmt: LogMsg, args: ...any) { + self.p.pushSuggestion(fmt, args...) + } + + fn insertAsNext(mut self, mut &tokens: []&Token) { + self.stmts = append(self.stmts[:self.pos+1], self.stmts[self.pos:]...) + self.stmts[self.pos+1] = &stmt{tokens: tokens} + } + + fn next(mut self): &stmt { + self.pos++ + ret self.stmts[self.pos] + } + + fn buildScope(mut self, mut &tokens: []&Token, mut end: &Token): &ScopeTree { + mut s := newScope() + s.Parent = self.s + s.End = end + mut ssp := scopeParser{ + p: self.p, + } + ssp.build(tokens, s) + ret s + } + + fn buildVarSt(mut self, mut &tokens: []&Token): &VarDecl { + mut v := self.p.buildVar(tokens) + v.Scope = self.s + ret v + } + + fn buildRetSt(mut self, mut tokens: []&Token): &RetSt { + mut st := &RetSt{ + Token: tokens[0], + } + if len(tokens) > 1 { + tokens = tokens[1:] // Remove ret keyword. + st.Expr = self.p.buildExpr(tokens) + } + ret st + } + + fn buildWhileNextIter(mut self, mut &s: &stmt): &Iter { + mut it := &Iter{ + Token: s.tokens[0], + } + mut tokens := s.tokens[1:] // Skip "iter" keyword. + mut kind := new(WhileKind) + + if len(tokens) > 0 { + kind.Expr = self.p.buildExpr(tokens) + } + + if self.isLastSt() { + self.pushErr(it.Token, LogMsg.InvalidSyntax) + ret nil + } + + tokens = self.next().tokens + mut stTokens := getBlockExpr(tokens) + if len(stTokens) > 0 { + mut stmt := &stmt{ + terminated: s.terminated, + tokens: stTokens, + } + kind.NextToken = stTokens[0] + kind.Next = self.buildSt(stmt) + } + + mut i := len(stTokens) + mut blockTokens := range(i, TokenId.LBrace, TokenId.RBrace, tokens) + if blockTokens == nil { + self.stop() + self.pushErr(it.Token, LogMsg.BodyNotExist) + self.pushSuggestion(LogMsg.ExpectedBody) + ret nil + } + if i < len(tokens) { + self.pushErr(tokens[i], LogMsg.InvalidSyntax) + } + + it.Scope = self.buildScope(blockTokens, tokens[i-1]) + it.Kind = kind + + ret it + } + + fn buildWhileIterKind(mut self, mut &tokens: []&Token): &WhileKind { + ret &WhileKind{ + Expr: self.p.buildExpr(tokens), + } + } + + fn getRangeKindKeysTokens(mut self, mut &toks: []&Token): [][]&Token { + mut vars, errs := parts(toks, TokenId.Comma, true) + self.p.errors = append(self.p.errors, errs...) + ret vars + } + + fn buildRangeKindKey(mut self, mut &tokens: []&Token): &VarDecl { + if len(tokens) == 0 { + ret nil + } + mut key := &VarDecl{ + Token: tokens[0], + Setter: tokens[0], + } + if key.Token.Id == TokenId.Mut { + key.Mutable = true + if len(tokens) == 1 { + self.pushErr(key.Token, LogMsg.InvalidSyntax) + } + key.Token = tokens[1] + } else if len(tokens) > 1 { + self.pushErr(tokens[1], LogMsg.InvalidSyntax) + } + if key.Token.Id != TokenId.Ident { + self.pushErr(key.Token, LogMsg.InvalidSyntax) + self.pushSuggestion(LogMsg.ExpectedIdentifier) + ret nil + } + key.Ident = key.Token.Kind + ret key + } + + fn buildRangeKindKeys(mut self, mut &parts: [][]&Token): []&VarDecl { + let mut keys: []&VarDecl = nil + for (_, mut tokens) in parts { + keys = append(keys, self.buildRangeKindKey(tokens)) + } + ret keys + } + + fn setupRangeKindKeysPlain(mut self, mut &rng: &RangeKind, mut &tokens: []&Token) { + mut keyTokens := self.getRangeKindKeysTokens(tokens) + if len(keyTokens) == 0 { + ret + } + if len(keyTokens) > 2 { + self.pushErr(rng.InToken, LogMsg.MuchRangeVars) + } + mut keys := self.buildRangeKindKeys(keyTokens) + rng.KeyA = keys[0] + if len(keys) > 1 { + rng.KeyB = keys[1] + } + } + + fn setupRangeKindKeysExplicit(mut self, mut &rng: &RangeKind, mut &tokens: []&Token) { + mut i := 0 + mut rang := range(i, TokenId.LParent, TokenId.RParent, tokens) + if i < len(tokens) { + self.pushErr(rng.InToken, LogMsg.InvalidSyntax) + } + self.setupRangeKindKeysPlain(rng, rang) + } + + fn setupRangeKindKeys(mut self, mut &rng: &RangeKind, mut &tokens: []&Token) { + if tokens[0].Id == TokenId.LParent { + self.setupRangeKindKeysExplicit(rng, tokens) + ret + } + self.setupRangeKindKeysPlain(rng, tokens) + } + + fn buildRangeIterKind(mut self, mut &var_tokens: []&Token, + mut &exprTokens: []&Token, mut &inToken: &Token): &RangeKind { + mut rng := &RangeKind{ + InToken: inToken, + } + if len(exprTokens) == 0 { + self.pushErr(rng.InToken, LogMsg.MissingExpr) + ret rng + } + rng.Expr = self.p.buildExpr(exprTokens) + if len(var_tokens) > 0 { + self.setupRangeKindKeys(rng, var_tokens) + } + ret rng + } + + fn buildCommonIterKind(mut self, mut &tokens: []&Token, &err_tok: &Token): IterKind { + mut braceN := 0 + for (i, mut tok) in tokens { + match tok.Id { + | TokenId.LBrace + | TokenId.LBracket + | TokenId.LParent: + braceN++ + continue + | TokenId.RBrace + | TokenId.RBracket + | TokenId.RParent: + braceN-- + } + if braceN != 0 { + continue + } + match tok.Id { + | TokenId.In: + mut declTokens := tokens[:i] + mut exprTokens := tokens[i+1:] + ret self.buildRangeIterKind(declTokens, exprTokens, tok) + } + } + ret self.buildWhileIterKind(tokens) + } + + fn buildCommonIter(mut self, mut tokens: []&Token): &Iter { + mut it := &Iter{ + Token: tokens[0], + } + tokens = tokens[1:] // Skip "iter" keyword. + if len(tokens) == 0 { + self.stop() + self.pushErr(it.Token, LogMsg.BodyNotExist) + self.pushSuggestion(LogMsg.ExpectedBody) + ret nil + } + mut exprTokens := getBlockExpr(tokens) + if len(exprTokens) > 0 { + it.Kind = self.buildCommonIterKind(exprTokens, it.Token) + } + mut i := len(exprTokens) + mut scopeTokens := range(i, TokenId.LBrace, TokenId.RBrace, tokens) + if scopeTokens == nil { + self.stop() + self.pushErr(it.Token, LogMsg.BodyNotExist) + self.pushSuggestion(LogMsg.ExpectedBody) + ret nil + } + if i < len(tokens) { + self.pushErr(tokens[i], LogMsg.InvalidSyntax) + } + it.Scope = self.buildScope(scopeTokens, tokens[i-1]) + ret it + } + + fn buildIterSt(mut self, mut &st: &stmt): &Iter { + if st.terminated { + ret self.buildWhileNextIter(st) + } + ret self.buildCommonIter(st.tokens) + } + + fn buildBreakSt(mut self, mut &tokens: []&Token): &BreakSt { + mut brk := &BreakSt{ + Token: tokens[0], + } + if len(tokens) > 1 { + if tokens[1].Id != TokenId.Ident { + self.pushErr(tokens[1], LogMsg.InvalidSyntax) + self.pushSuggestion(LogMsg.ExpectedLabelIdent) + } else { + brk.Label = tokens[1] + if len(tokens) > 2 { + self.pushErr(tokens[1], LogMsg.InvalidSyntax) + } + } + } + ret brk + } + + fn buildContSt(mut self, mut &tokens: []&Token): &ContSt { + mut cont := &ContSt{ + Token: tokens[0], + } + if len(tokens) > 1 { + if tokens[1].Id != TokenId.Ident { + self.pushErr(tokens[1], LogMsg.InvalidSyntax) + self.pushSuggestion(LogMsg.ExpectedLabelIdent) + } else { + cont.Label = tokens[1] + if len(tokens) > 2 { + self.pushErr(tokens[1], LogMsg.InvalidSyntax) + } + } + } + ret cont + } + + fn buildIf(mut self, mut &tokens: []&Token): &If { + mut model := &If{ + Token: tokens[0], + } + tokens = tokens[1:] + mut exprTokens := getBlockExpr(tokens) + mut i := 0 + if len(exprTokens) == 0 { + self.pushErr(model.Token, LogMsg.MissingExpr) + } else { + i = len(exprTokens) + } + mut scopeTokens := range(i, TokenId.LBrace, TokenId.RBrace, tokens) + if scopeTokens == nil { + self.stop() + self.pushErr(model.Token, LogMsg.BodyNotExist) + self.pushSuggestion(LogMsg.ExpectedBody) + ret nil + } + mut end := tokens[i-1] + if i < len(tokens) { + if tokens[i].Id == TokenId.Else { + tokens = tokens[i:] + } else { + self.pushErr(tokens[i], LogMsg.InvalidSyntax) + tokens = nil + } + } + model.Expr = self.p.buildExpr(exprTokens) + model.Scope = self.buildScope(scopeTokens, end) + ret model + } + + fn buildElse(mut self, mut &tokens: []&Token): &Else { + mut els := &Else{ + Token: tokens[0], + } + tokens = tokens[1:] // Remove "else" keyword. + mut i := 0 + mut scopeTokens := range(i, TokenId.LBrace, TokenId.RBrace, tokens) + if scopeTokens == nil { + if i < len(tokens) { + self.pushErr(els.Token, LogMsg.ElseHaveExpr) + } else { + self.stop() + self.pushErr(els.Token, LogMsg.BodyNotExist) + self.pushSuggestion(LogMsg.ExpectedBody) + } + ret nil + } + if i < len(tokens) { + self.pushErr(tokens[i], LogMsg.InvalidSyntax) + } + els.Scope = self.buildScope(scopeTokens, tokens[i-1]) + ret els + } + + fn buildIfElseChain(mut self, mut tokens: []&Token): &Conditional { + mut chain := &Conditional{ + Head: self.buildIf(tokens), + } + if chain.Head == nil { + ret nil + } + for len(tokens) != 0 { + if tokens[0].Id != TokenId.Else { + break + } + if len(tokens) > 1 && tokens[1].Id == TokenId.If { + tokens = tokens[1:] // Remove else token + mut elif := self.buildIf(tokens) + chain.Tail = append(chain.Tail, elif) + continue + } + chain.Default = self.buildElse(tokens) + break + } + ret chain + } + + fn buildCoCallSt(mut self, mut tokens: []&Token): &Expr { + token := tokens[0] + tokens = tokens[1:] // Start 1 to skip "co" token. + mut e := self.p.buildExpr(tokens) + if e == nil { + ret e + } + match type e.Kind { + | &FnCallExpr: + (&FnCallExpr)(e.Kind).IsCo = true + |: + self.pushErr(token, LogMsg.ExprNotFnCall) + } + ret e + } + + fn buildGotoSt(mut self, mut &tokens: []&Token): &GotoSt { + mut gt := &GotoSt{ + Token: tokens[0], + } + if len(tokens) == 1 { + self.pushErr(gt.Token, LogMsg.MissingGotoLabel) + ret nil + } else if len(tokens) > 2 { + self.pushErr(tokens[2], LogMsg.InvalidSyntax) + } + mut identToken := tokens[1] + if identToken.Id != TokenId.Ident { + self.pushErr(identToken, LogMsg.InvalidSyntax) + self.pushSuggestion(LogMsg.ExpectedIdentifier) + ret gt + } + gt.Label = identToken + ret gt + } + + fn buildFallSt(mut self, mut &tokens: []&Token): &FallSt { + mut fll := &FallSt{ + Token: tokens[0], + } + if len(tokens) > 1 { + self.pushErr(tokens[1], LogMsg.InvalidSyntax) + } + ret fll + } + + fn buildTypeAliasSt(mut self, mut &tokens: []&Token): &TypeAliasDecl { + mut tad := self.p.buildTypeAliasDecl(tokens) + tad.Scope = self.s + ret tad + } + + fn pushCaseExpr(mut self, mut tokens: []&Token, mut token: &Token, + typeMatch: bool, mut &exprs: []&Expr) { + if len(tokens) == 0 { + ret + } + if typeMatch { + mut i := 0 + mut t, ok := unsafe { self.p.buildType(tokens, &i, true) } + if ok { + exprs = append(exprs, &Expr{ + Token: tokens[0], + End: tokens[len(tokens)-1], + Kind: t, + }) + if i < len(tokens) { + self.pushErr(tokens[i], LogMsg.InvalidSyntax) + } + } + ret + } + exprs = append(exprs, self.p.buildExpr(tokens)) + } + + fn buildCaseExprs(mut self, mut &tokens: []&Token, mut &colon: &Token, typeMatch: bool): ([]&Expr, bool) { + mut exprs := make([]&Expr, 0, 1) + mut braceN := 0 + mut j := 0 + for (i, mut tok) in tokens { + match tok.Id { + | TokenId.LParent + | TokenId.LBrace + | TokenId.LBracket: + braceN++ + continue + | TokenId.RParent + | TokenId.RBrace + | TokenId.RBracket: + braceN-- + continue + } + + if braceN != 0 { + continue + } + match { + | tok.Id == TokenId.Vline: + exprTokens := tokens[j:i] + if len(exprTokens) == 0 { + self.pushErr(tok, LogMsg.MissingExpr) + } else { + self.pushCaseExpr(tokens[j:i], tok, typeMatch, exprs) + } + j = i + 1 + | tok.Id == TokenId.Colon: + colon = tok + self.pushCaseExpr(tokens[j:i], tok, typeMatch, exprs) + tokens = tokens[i+1:] + ret exprs, i-j == 0 || len(exprs) != 0 + } + } + self.pushErr(tokens[0], LogMsg.InvalidSyntax) + tokens = nil + ret nil, false + } + + fn buildCaseScope(mut self, mut &tokens: []&Token): &ScopeTree { + mut n := 0 + for { + mut i := 0 + mut next, _ := skipSt(i, tokens[n:]) + if len(next) == 0 { + break + } + tok := next[0] + if tok.Id != TokenId.Vline { + n += i + continue + } + mut scopeTokens := tokens[:n] + mut scope := self.buildScope(scopeTokens, tokens[n]) + tokens = tokens[n:] + ret scope + } + let mut end: &Token + if len(tokens) > 0 { + end = tokens[len(tokens)-1] + } + mut scope := self.buildScope(tokens, end) + tokens = nil + ret scope + } + + fn buildCase(mut self, mut &tokens: []&Token, typeMatch: bool): (&Case, bool) { + mut c := &Case{ + Token: tokens[0], + } + tokens = tokens[1:] // Remove case prefix. + let mut colon: &Token = nil + c.Exprs, ok := self.buildCaseExprs(tokens, colon, typeMatch) + c.Scope = self.buildCaseScope(tokens) + if c.Scope.End == nil { + c.Scope.End = colon + } + isDefault := ok && len(c.Exprs) == 0 + ret c, isDefault + } + + fn buildCases(mut self, mut tokens: []&Token, typeMatch: bool): ([]&Case, &Else) { + let mut cases: []&Case = nil + let mut def: &Else = nil + mut defNotLast := false + for len(tokens) > 0 { + mut tok := tokens[0] + if tok.Id != TokenId.Vline { + self.pushErr(tok, LogMsg.InvalidSyntax) + break + } + mut c, isDefault := self.buildCase(tokens, typeMatch) + if isDefault { + c.Token = tok + if def == nil { + def = &Else{ + Token: c.Token, + Scope: c.Scope, + } + } else { + self.pushErr(tok, LogMsg.InvalidSyntax) + } + } else { + defNotLast = defNotLast || def != nil + cases = append(cases, c) + } + } + + if defNotLast { + self.pushErr(def.Token, LogMsg.DefaultNotLast) + } + + ret cases, def + } + + fn buildMatchCase(mut self, mut tokens: []&Token): &MatchCase { + mut m := &MatchCase{ + Token: tokens[0], + } + tokens = tokens[1:] // Remove "match" keyword. + + if len(tokens) > 0 && tokens[0].Id == TokenId.Type { + m.TypeMatch = true + tokens = tokens[1:] // Skip "type" keyword + } + + mut exprTokens := getBlockExpr(tokens) + if len(exprTokens) > 0 { + m.Expr = self.p.buildExpr(exprTokens) + } else if m.TypeMatch { + self.pushErr(m.Token, LogMsg.MissingExpr) + } + + mut i := len(exprTokens) + mut blockToks := range(i, TokenId.LBrace, TokenId.RBrace, tokens) + if blockToks == nil { + self.stop() + self.pushErr(m.Token, LogMsg.BodyNotExist) + self.pushSuggestion(LogMsg.ExpectedBody) + ret nil + } else if i < len(tokens) { + self.pushErr(tokens[i], LogMsg.InvalidSyntax) + } + m.End = tokens[i-1] + m.Cases, m.Default = self.buildCases(blockToks, m.TypeMatch) + ret m + } + + fn buildScopeSt(mut self, mut tokens: []&Token): &ScopeTree { + mut isUnsafe := false + mut isDeferred := false + mut token := tokens[0] + if token.Id == TokenId.Unsafe { + isUnsafe = true + tokens = tokens[1:] + if len(tokens) == 0 { + self.pushErr(token, LogMsg.InvalidSyntax) + ret nil + } + token = tokens[0] + if token.Id == TokenId.Defer { + isDeferred = true + tokens = tokens[1:] + if len(tokens) == 0 { + self.pushErr(token, LogMsg.InvalidSyntax) + ret nil + } + } + } else if token.Id == TokenId.Defer { + isDeferred = true + tokens = tokens[1:] + if len(tokens) == 0 { + self.pushErr(token, LogMsg.InvalidSyntax) + ret nil + } + } + + mut i := 0 + mut scopeTokens := range(i, TokenId.LBrace, TokenId.RBrace, tokens) + if scopeTokens == nil { + self.pushErr(token, LogMsg.InvalidSyntax) + ret nil + } else if i < len(tokens) { + self.pushErr(tokens[i], LogMsg.InvalidSyntax) + } + mut scope := self.buildScope(scopeTokens, tokens[i-1]) + scope.Unsafety = isUnsafe + scope.Deferred = isDeferred + ret scope + } + + fn buildLabelSt(mut self, mut &tokens: []&Token): &LabelSt { + mut lbl := &LabelSt{ + Token: tokens[0], + Ident: tokens[0].Kind, + } + + // Save followed statement + if len(tokens) > 2 { + tokens = tokens[2:] // Remove goto keyword and label + self.insertAsNext(tokens) + } + + ret lbl + } + + fn buildIdSt(mut self, mut &tokens: []&Token): (StmtData, ok: bool) { + if len(tokens) == 1 { + ret + } + + mut token := tokens[1] + match token.Id { + | TokenId.Colon: + ret self.buildLabelSt(tokens), true + } + + ret + } + + fn buildAssignInfo(mut self, mut &tokens: []&Token): &assignInfo { + mut info := &assignInfo{ + ok: true, + } + mut braceN := 0 + for (i, mut token) in tokens { + match token.Id { + | TokenId.LBrace + | TokenId.LBracket + | TokenId.LParent: + braceN++ + | TokenId.RBrace + | TokenId.RBracket + | TokenId.RParent: + braceN-- + } + match { + | braceN > 0: + continue + | !IsAssignOp(token.Id) && token.Id != TokenId.ColonEq: + continue + } + + info.l = tokens[:i] + if len(info.l) == 0 { + info.ok = false + } + info.setter = token + if i+1 >= len(tokens) { + info.r = nil + info.ok = IsPostfixOp(info.setter.Id) + break + } + info.r = tokens[i+1:] + if IsPostfixOp(info.setter.Id) { + if len(info.r) > 0 { + self.pushErr(info.r[0], LogMsg.InvalidSyntax) + info.r = nil + } + } + break + } + ret info + } + + fn buildAssignL(mut self, mut &tokens: []&Token): &AssignLeft { + mut l := &AssignLeft{ + Token: tokens[0], + } + if tokens[0].Id == TokenId.Ident { + l.Ident = l.Token.Kind + } + l.Expr = self.p.buildExpr(tokens) + ret l + } + + fn buildAssignLs(mut self, mut &parts: [][]&Token): []&AssignLeft { + let mut lefts: []&AssignLeft = nil + for (_, mut part) in parts { + mut l := self.buildAssignL(part) + lefts = append(lefts, l) + } + ret lefts + } + + fn buildPlainAssign(mut self, mut &tokens: []&Token): (StmtData, bool) { + mut info := self.buildAssignInfo(tokens) + if !info.ok { + ret nil, false + } + + mut assign := &AssignSt{ + Setter: info.setter, + } + + // Caught declaration assignments. + if info.setter.Id == TokenId.ColonEq { + assign.Declarative = true + assign.Right = self.p.buildExpr(info.r) + ok := self.buildDeclAssign1(info.l, assign) + if !ok { + // Return with true to avoid duplicate error. + ret nil, true + } + if len(assign.Left) > 1 { + ret assign, true + } + // Single left, use &VarDecl intead. + mut left := assign.Left[0] + mut decl := &VarDecl{ + Token: left.Token, + Setter: assign.Setter, + Ident: left.Ident, + Mutable: left.Mutable, + Reference: left.Reference, + Scope: self.s, + Expr: assign.Right, + } + ret decl, true + } + + mut parts, errs := parts(info.l, TokenId.Comma, true) + if len(errs) > 0 { + self.p.errors = append(self.p.errors, errs...) + ret nil, false + } + + assign.Left = self.buildAssignLs(parts) + if info.r != nil { + assign.Right = self.p.buildExpr(info.r) + } + + ret assign, true + } + + fn buildDeclAssign1(mut self, mut &lefts: []&Token, mut &assign: &AssignSt): bool { + // Lefts + mut parts, errs := parts(lefts, TokenId.Comma, true) + if len(errs) > 0 { + self.p.errors = append(self.p.errors, errs...) + ret false + } + + for (_, mut part) in parts { + mut isMut := false + mut isRef := false + + token := part[0] + if token.Id == TokenId.Mut { + isMut = true + part = part[1:] + if len(part) == 0 { + self.pushErr(token, LogMsg.InvalidSyntax) + ret false + } + } + + if part[0].Id == TokenId.Amper { + isRef = true + part = part[1:] + if len(part) == 0 { + self.pushErr(token, LogMsg.InvalidSyntax) + ret false + } + } + + if part[0].Id != TokenId.Ident && part[0].Id != TokenId.LParent { + self.pushErr(token, LogMsg.InvalidSyntax) + ret false + } + + mut l := self.buildAssignL(part) + l.Mutable = isMut + l.Reference = isRef + assign.Left = append(assign.Left, l) + } + + ret true + } + + fn buildDeclAssign(mut self, mut tokens: []&Token): (&AssignSt, bool) { + if len(tokens) < 1 { + ret nil, false + } + + tokens = tokens[1:] // Skip "let" keyword + mut token := tokens[0] + if token.Id != TokenId.LParent { + ret nil, false + } + + mut assign := &AssignSt{ + Declarative: true, + } + + mut i := 0 + mut rang := range(i, TokenId.LParent, TokenId.RParent, tokens) + if rang == nil { + self.pushErr(token, LogMsg.InvalidSyntax) + ret nil, false + } else if i+1 < len(tokens) { + assign.Setter = tokens[i] + if assign.Setter.Id != TokenId.Eq { + self.pushErr(assign.Setter, LogMsg.InvalidSyntax) + } + i++ + mut exprTokens := tokens[i:] + assign.Right = self.p.buildExpr(exprTokens) + } + + ok := self.buildDeclAssign1(rang, assign) + ret assign, ok + } + + fn buildAssignSt(mut self, mut &tokens: []&Token): (st: StmtData, ok: bool) { + if !checkAssignTokens(tokens) { + ret nil, false + } + match tokens[0].Id { + | TokenId.Let: + st, ok = self.buildDeclAssign(tokens) + |: + st, ok = self.buildPlainAssign(tokens) + } + ret + } + + fn buildUseExpr(mut self, mut &tokens: []&Token): &UseExpr { + if len(tokens) == 1 { + self.pushErr(tokens[0], LogMsg.MissingExpr) + ret nil + } + mut ue := &UseExpr{ + Token: tokens[0], + } + tokens = tokens[1:] // Ignore "use" keyword. + ue.Expr = self.p.buildExpr(tokens) + ret ue + } + + fn buildConstSt(mut self, mut &st: &stmt): StmtData { + if len(st.tokens) == 1 { + self.pushErr(st.tokens[0], LogMsg.InvalidSyntax) + ret nil + } + match st.tokens[1].Id { + | TokenId.For: + st.tokens = st.tokens[1:] + mut iter := self.buildIterSt(st) + if iter != nil { + iter.Comptime = true + } + ret iter + | TokenId.Match: + st.tokens = st.tokens[1:] + mut mt := self.buildMatchCase(st.tokens) + if mt != nil { + mt.Comptime = true + } + ret mt + |: + ret self.buildVarSt(st.tokens) + } + } + + fn buildSt(mut self, mut &st: &stmt): StmtData { + mut token := st.tokens[0] + if token.Id == TokenId.Ident { + mut s, ok := self.buildIdSt(st.tokens) + if ok { + ret s + } + } + + mut s, ok := self.buildAssignSt(st.tokens) + if ok { + ret s + } + + match token.Id { + | TokenId.Use: + ret self.buildUseExpr(st.tokens) + | TokenId.Const: + ret self.buildConstSt(st) + | TokenId.Static + | TokenId.Let + | TokenId.Mut: + ret self.buildVarSt(st.tokens) + | TokenId.Ret: + ret self.buildRetSt(st.tokens) + | TokenId.For: + ret self.buildIterSt(st) + | TokenId.Break: + ret self.buildBreakSt(st.tokens) + | TokenId.Cont: + ret self.buildContSt(st.tokens) + | TokenId.If: + ret self.buildIfElseChain(st.tokens) + | TokenId.Co: + ret self.buildCoCallSt(st.tokens) + | TokenId.Goto: + ret self.buildGotoSt(st.tokens) + | TokenId.Fall: + ret self.buildFallSt(st.tokens) + | TokenId.Type: + ret self.buildTypeAliasSt(st.tokens) + | TokenId.Match: + ret self.buildMatchCase(st.tokens) + | TokenId.Unsafe: + if len(st.tokens) < 1 { + break + } + if st.tokens[1].Id == TokenId.Defer || + st.tokens[1].Id == TokenId.LBrace { // Scope. + ret self.buildScopeSt(st.tokens) + } + | TokenId.Defer: + ret self.buildScopeSt(st.tokens) + | TokenId.LBrace: + ret self.buildScopeSt(st.tokens) + } + mut expr := self.p.buildExpr(st.tokens) + if expr != nil { + ret expr + } + self.pushErr(token, LogMsg.InvalidSyntax) + ret nil + } + + fn build(mut self, mut &tokens: []&Token, mut &s: &ScopeTree) { + if s == nil { + ret + } + self.stmts = splitStmts(tokens) + self.pos = -1 // sp.next() first increase position + self.s = s + for !self.isLastSt() && !self.finished() { + mut st := self.next() + mut data := self.buildSt(st) + if data != nil { + self.s.Stmts = append(self.s.Stmts, Stmt{ + Token: st.tokens[0], + Data: data, + }) + } + if self.stopped() { + break + } + } + } } \ No newline at end of file diff --git a/std/jule/parser/type.jule b/std/jule/parser/type.jule index c000a0da7..82dcd96c5 100644 --- a/std/jule/parser/type.jule +++ b/std/jule/parser/type.jule @@ -3,392 +3,392 @@ // license that can be found in the LICENSE file. use std::jule::ast::{ - TypeDecl, - SubIdentTypeDecl, - IdentTypeDecl, - NamespaceTypeDecl, - PtrTypeDecl, - SptrTypeDecl, - SlcTypeDecl, - ArrTypeDecl, - MapTypeDecl, + TypeDecl, + SubIdentTypeDecl, + IdentTypeDecl, + NamespaceTypeDecl, + PtrTypeDecl, + SptrTypeDecl, + SlcTypeDecl, + ArrTypeDecl, + MapTypeDecl, } use std::jule::build::{LogMsg} use std::jule::lex::{Token, TokenId, TokenKind} fn buildVoidType(): &TypeDecl { - ret new(TypeDecl) + ret new(TypeDecl) } fn buildPrimType(mut t: &Token): &TypeDecl { - ret &TypeDecl{ - Token: t, - Kind: &IdentTypeDecl{ - Token: t, - Ident: t.Kind, - }, - } + ret &TypeDecl{ + Token: t, + Kind: &IdentTypeDecl{ + Token: t, + Ident: t.Kind, + }, + } } struct typeBuilder { - p: &parser - tokens: []&Token - i: *int - err: bool + p: &parser + tokens: []&Token + i: *int + err: bool } impl typeBuilder { - fn pushErr(mut self, token: &Token, fmt: LogMsg) { - if self.err { - self.p.pushErr(token, fmt) - } - } - - // Push suggestion to last log. - fn pushSuggestion(mut self, fmt: LogMsg, args: ...any) { - if self.err { - self.p.pushSuggestion(fmt, args...) - } - } - - unsafe fn buildNamespace(mut self): &TypeDecl { - mut t := &TypeDecl{ - Token: self.tokens[*self.i], - } - - mut nst := new(NamespaceTypeDecl) - mut n := 0 - for *self.i < len(self.tokens); *self.i++ { - mut token := self.tokens[*self.i] - if n%2 == 0 { - if token.Id != TokenId.Ident { - self.pushErr(token, LogMsg.InvalidSyntax) - self.pushSuggestion(LogMsg.ExpectedIdentifier) - } - nst.Idents = append(nst.Idents, token) - } else if token.Id != TokenId.DblColon { - break - } - n++ - } - - // Remove selected identifier token. - nst.Idents = nst.Idents[:len(nst.Idents)-1] - - *self.i-- // Set offset to last identifier. - nst.Kind = self.buildIdent() - t.Kind = nst - ret t - } - - unsafe fn buildGenerics(mut self): []&TypeDecl { - if *self.i >= len(self.tokens) { - ret nil - } - token := self.tokens[*self.i] - if token.Id != TokenId.LBracket { - ret nil - } - - mut parts := self.identGenerics() - if len(parts) == 0 { - self.pushErr(token, LogMsg.InvalidSyntax) - ret nil - } - - mut types := make([]&TypeDecl, 0, len(parts)) - for (_, mut part) in parts { - mut j := 0 - mut t, _ := unsafe { self.p.buildType(part, &j, true) } - if j < len(part) { - self.pushErr(part[j], LogMsg.InvalidSyntax) - } - types = append(types, t) - } - ret types - } - - unsafe fn identGenerics(mut self): [][]&Token { - first := *self.i - mut rangeN := 0 - for *self.i < len(self.tokens); *self.i++ { - token := self.tokens[*self.i] - match token.Id { - | TokenId.LBracket: - rangeN++ - | TokenId.RBracket: - rangeN-- - } - if rangeN == 0 { - *self.i++ // Skip right bracket - break - } - } - mut tokens := self.tokens[first+1 : *self.i-1] // Take range of brackets. - mut parts, errors := parts(tokens, TokenId.Comma, true) - if self.err { - self.p.errors = append(self.p.errors, errors...) - } - ret parts - } - - unsafe fn buildIdent(mut self): &TypeDecl { - mut next := *self.i+1 < len(self.tokens) - if next && self.tokens[*self.i+1].Id == TokenId.DblColon { - ret self.buildNamespace() - } - mut token := self.tokens[*self.i] - mut it := &IdentTypeDecl{ - Token: token, - Ident: token.Kind, - Binded: false, - } - *self.i++ - mut itd := &TypeDecl{ - Token: token, - Kind: it, - } - if !next || self.tokens[*self.i].Id != TokenId.Dot { - it.Generics = self.buildGenerics() - ret itd - } - if len(self.tokens)-*self.i == 1 { - self.pushErr(token, LogMsg.InvalidSyntax) - ret itd - } - *self.i++ - if self.tokens[*self.i].Id != TokenId.Ident { - self.pushErr(self.tokens[*self.i-1], LogMsg.InvalidSyntax) - ret itd - } - mut sit := new(SubIdentTypeDecl) - sit.Idents = append(sit.Idents, it) - mut ident := self.buildIdent() - match type ident.Kind { - | &IdentTypeDecl: - sit.Idents = append(sit.Idents, (&IdentTypeDecl)(ident.Kind)) - | &SubIdentTypeDecl: - sit.Idents = append(sit.Idents, (&SubIdentTypeDecl)(ident.Kind).Idents...) - } - ret &TypeDecl{ - Token: token, - Kind: sit, - } - } - - unsafe fn buildCppLink(mut self): &TypeDecl { - if *self.i+1 >= len(self.tokens) || self.tokens[*self.i+1].Id != TokenId.Dot { - self.pushErr(self.tokens[*self.i], LogMsg.InvalidSyntax) - ret nil - } - *self.i += 2 // Skip the bind keyword and dot token. - mut t := self.buildIdent() - (&IdentTypeDecl)(t.Kind).Binded = true - ret t - } - - unsafe fn buildFn(mut self): &TypeDecl { - mut token := self.tokens[*self.i] - mut f := self.p.buildFnPrototype(self.tokens, *self.i, false) - if f == nil { - ret nil - } - if !f.IsAnon() { - self.pushErr(f.Token, LogMsg.InvalidSyntax) - } - ret &TypeDecl{ - Token: token, - Kind: f, - } - } - - unsafe fn buildPtr(mut self): &TypeDecl { - mut token := self.tokens[*self.i] - if *self.i+1 >= len(self.tokens) { - self.pushErr(token, LogMsg.InvalidSyntax) - ret nil - } - - *self.i++ - if self.tokens[*self.i].Id == TokenId.Unsafe { - *self.i++ - ret &TypeDecl{ - Token: token, - Kind: &PtrTypeDecl{ - Elem: nil, // Set Elem as nil for unsafe pointer (*unsafe) type. - }, - } - } - - mut elem := self.step() - if elem == nil { - ret nil - } - - ret &TypeDecl{ - Token: token, - Kind: &PtrTypeDecl{ - Elem: elem, - }, - } - } - - unsafe fn buildSptr(mut self): &TypeDecl { - mut token := self.tokens[*self.i] - if *self.i+1 >= len(self.tokens) { - self.pushErr(token, LogMsg.InvalidSyntax) - ret nil - } - - *self.i++ - mut elem := self.step() - if elem == nil { - ret nil - } - - ret &TypeDecl{ - Token: token, - Kind: &SptrTypeDecl{ - Elem: elem, - }, - } - } - - unsafe fn buildSlc(mut self): &TypeDecl { - mut token := self.tokens[*self.i] - *self.i++ // skip right bracket - mut elem := self.step() - if elem == nil { - ret nil - } - ret &TypeDecl{ - Token: token, - Kind: &SlcTypeDecl{ - Elem: elem, - }, - } - } - - unsafe fn buildArr(mut self): &TypeDecl { - mut exprTokens := range(*self.i, TokenId.LBracket, TokenId.RBracket, self.tokens) - if *self.i >= len(self.tokens) { - self.pushErr(self.tokens[*self.i-1], LogMsg.MissingType) - ret nil - } - - mut elem := self.step() - if elem == nil { - ret nil - } - - mut arrt := &ArrTypeDecl{ - Elem: elem, - } - - mut token := exprTokens[0] - if len(exprTokens) == 1 && token.Id == TokenId.TripleDot { - // Ignore. - } else { - arrt.Size = self.p.buildExpr(exprTokens) - } - - ret &TypeDecl{ - Token: token, - Kind: arrt, - } - } - - unsafe fn buildMap(mut self): &TypeDecl { - mut mapToken := self.tokens[*self.i] - *self.i++ // Skip map token. - if *self.i >= len(self.tokens) { - self.pushErr(mapToken, LogMsg.MissingType) - ret nil - } - - // Get key type tokens without brackets. - mut keyTokens := range(*self.i, TokenId.LBracket, TokenId.RBracket, self.tokens) - if *self.i >= len(self.tokens) { - self.pushErr(self.tokens[*self.i-1], LogMsg.MissingType) - ret nil - } else if len(keyTokens) == 0 { - self.pushErr(mapToken, LogMsg.MissingType) - ret nil - } - - mut mapt := new(MapTypeDecl) - mut j := 0 - mut keyt, mut ok := self.p.buildType(keyTokens, &j, self.err) - if !ok { - ret nil - } else if j < len(keyTokens) { - self.pushErr(keyTokens[j], LogMsg.InvalidSyntax) - } - mapt.Key = keyt - - mut valt, ok := self.p.buildType(self.tokens, self.i, self.err) - if !ok { - ret nil - } - mapt.Val = valt - ret &TypeDecl{ - Token: mapToken, - Kind: mapt, - } - } - - unsafe fn buildEnumerable(mut self): &TypeDecl { - mut token := self.tokens[*self.i] - if *self.i+2 >= len(self.tokens) { - self.pushErr(token, LogMsg.InvalidSyntax) - ret nil - } - *self.i++ - token = self.tokens[*self.i] - if token.Id == TokenId.RBracket { - ret self.buildSlc() - } - *self.i-- // Point to left bracket. - ret self.buildArr() - } - - unsafe fn step(mut self): &TypeDecl { - token := self.tokens[*self.i] - match token.Id { - | TokenId.Ident: - ret self.buildIdent() - | TokenId.Cpp: - ret self.buildCppLink() - | TokenId.Fn: - ret self.buildFn() - | TokenId.Star: - ret self.buildPtr() - | TokenId.Amper: - ret self.buildSptr() - | TokenId.DblAmper: - ret &TypeDecl{ - Kind: &SptrTypeDecl{ - Elem: self.buildSptr(), - }, - } - | TokenId.LBracket: - ret self.buildEnumerable() - | TokenId.Map: - ret self.buildMap() - |: - *self.i++ - self.pushErr(token, LogMsg.InvalidSyntax) - ret nil - } - } - - // Builds type. - // Returns void if error occurs. - unsafe fn build(mut self): (&TypeDecl, ok: bool) { - mut root := self.step() - if root == nil { - ret buildVoidType(), false - } - ret root, true - } + fn pushErr(mut self, token: &Token, fmt: LogMsg) { + if self.err { + self.p.pushErr(token, fmt) + } + } + + // Push suggestion to last log. + fn pushSuggestion(mut self, fmt: LogMsg, args: ...any) { + if self.err { + self.p.pushSuggestion(fmt, args...) + } + } + + unsafe fn buildNamespace(mut self): &TypeDecl { + mut t := &TypeDecl{ + Token: self.tokens[*self.i], + } + + mut nst := new(NamespaceTypeDecl) + mut n := 0 + for *self.i < len(self.tokens); *self.i++ { + mut token := self.tokens[*self.i] + if n%2 == 0 { + if token.Id != TokenId.Ident { + self.pushErr(token, LogMsg.InvalidSyntax) + self.pushSuggestion(LogMsg.ExpectedIdentifier) + } + nst.Idents = append(nst.Idents, token) + } else if token.Id != TokenId.DblColon { + break + } + n++ + } + + // Remove selected identifier token. + nst.Idents = nst.Idents[:len(nst.Idents)-1] + + *self.i-- // Set offset to last identifier. + nst.Kind = self.buildIdent() + t.Kind = nst + ret t + } + + unsafe fn buildGenerics(mut self): []&TypeDecl { + if *self.i >= len(self.tokens) { + ret nil + } + token := self.tokens[*self.i] + if token.Id != TokenId.LBracket { + ret nil + } + + mut parts := self.identGenerics() + if len(parts) == 0 { + self.pushErr(token, LogMsg.InvalidSyntax) + ret nil + } + + mut types := make([]&TypeDecl, 0, len(parts)) + for (_, mut part) in parts { + mut j := 0 + mut t, _ := unsafe { self.p.buildType(part, &j, true) } + if j < len(part) { + self.pushErr(part[j], LogMsg.InvalidSyntax) + } + types = append(types, t) + } + ret types + } + + unsafe fn identGenerics(mut self): [][]&Token { + first := *self.i + mut rangeN := 0 + for *self.i < len(self.tokens); *self.i++ { + token := self.tokens[*self.i] + match token.Id { + | TokenId.LBracket: + rangeN++ + | TokenId.RBracket: + rangeN-- + } + if rangeN == 0 { + *self.i++ // Skip right bracket + break + } + } + mut tokens := self.tokens[first+1 : *self.i-1] // Take range of brackets. + mut parts, errors := parts(tokens, TokenId.Comma, true) + if self.err { + self.p.errors = append(self.p.errors, errors...) + } + ret parts + } + + unsafe fn buildIdent(mut self): &TypeDecl { + mut next := *self.i+1 < len(self.tokens) + if next && self.tokens[*self.i+1].Id == TokenId.DblColon { + ret self.buildNamespace() + } + mut token := self.tokens[*self.i] + mut it := &IdentTypeDecl{ + Token: token, + Ident: token.Kind, + Binded: false, + } + *self.i++ + mut itd := &TypeDecl{ + Token: token, + Kind: it, + } + if !next || self.tokens[*self.i].Id != TokenId.Dot { + it.Generics = self.buildGenerics() + ret itd + } + if len(self.tokens)-*self.i == 1 { + self.pushErr(token, LogMsg.InvalidSyntax) + ret itd + } + *self.i++ + if self.tokens[*self.i].Id != TokenId.Ident { + self.pushErr(self.tokens[*self.i-1], LogMsg.InvalidSyntax) + ret itd + } + mut sit := new(SubIdentTypeDecl) + sit.Idents = append(sit.Idents, it) + mut ident := self.buildIdent() + match type ident.Kind { + | &IdentTypeDecl: + sit.Idents = append(sit.Idents, (&IdentTypeDecl)(ident.Kind)) + | &SubIdentTypeDecl: + sit.Idents = append(sit.Idents, (&SubIdentTypeDecl)(ident.Kind).Idents...) + } + ret &TypeDecl{ + Token: token, + Kind: sit, + } + } + + unsafe fn buildCppLink(mut self): &TypeDecl { + if *self.i+1 >= len(self.tokens) || self.tokens[*self.i+1].Id != TokenId.Dot { + self.pushErr(self.tokens[*self.i], LogMsg.InvalidSyntax) + ret nil + } + *self.i += 2 // Skip the bind keyword and dot token. + mut t := self.buildIdent() + (&IdentTypeDecl)(t.Kind).Binded = true + ret t + } + + unsafe fn buildFn(mut self): &TypeDecl { + mut token := self.tokens[*self.i] + mut f := self.p.buildFnPrototype(self.tokens, *self.i, false) + if f == nil { + ret nil + } + if !f.IsAnon() { + self.pushErr(f.Token, LogMsg.InvalidSyntax) + } + ret &TypeDecl{ + Token: token, + Kind: f, + } + } + + unsafe fn buildPtr(mut self): &TypeDecl { + mut token := self.tokens[*self.i] + if *self.i+1 >= len(self.tokens) { + self.pushErr(token, LogMsg.InvalidSyntax) + ret nil + } + + *self.i++ + if self.tokens[*self.i].Id == TokenId.Unsafe { + *self.i++ + ret &TypeDecl{ + Token: token, + Kind: &PtrTypeDecl{ + Elem: nil, // Set Elem as nil for unsafe pointer (*unsafe) type. + }, + } + } + + mut elem := self.step() + if elem == nil { + ret nil + } + + ret &TypeDecl{ + Token: token, + Kind: &PtrTypeDecl{ + Elem: elem, + }, + } + } + + unsafe fn buildSptr(mut self): &TypeDecl { + mut token := self.tokens[*self.i] + if *self.i+1 >= len(self.tokens) { + self.pushErr(token, LogMsg.InvalidSyntax) + ret nil + } + + *self.i++ + mut elem := self.step() + if elem == nil { + ret nil + } + + ret &TypeDecl{ + Token: token, + Kind: &SptrTypeDecl{ + Elem: elem, + }, + } + } + + unsafe fn buildSlc(mut self): &TypeDecl { + mut token := self.tokens[*self.i] + *self.i++ // skip right bracket + mut elem := self.step() + if elem == nil { + ret nil + } + ret &TypeDecl{ + Token: token, + Kind: &SlcTypeDecl{ + Elem: elem, + }, + } + } + + unsafe fn buildArr(mut self): &TypeDecl { + mut exprTokens := range(*self.i, TokenId.LBracket, TokenId.RBracket, self.tokens) + if *self.i >= len(self.tokens) { + self.pushErr(self.tokens[*self.i-1], LogMsg.MissingType) + ret nil + } + + mut elem := self.step() + if elem == nil { + ret nil + } + + mut arrt := &ArrTypeDecl{ + Elem: elem, + } + + mut token := exprTokens[0] + if len(exprTokens) == 1 && token.Id == TokenId.TripleDot { + // Ignore. + } else { + arrt.Size = self.p.buildExpr(exprTokens) + } + + ret &TypeDecl{ + Token: token, + Kind: arrt, + } + } + + unsafe fn buildMap(mut self): &TypeDecl { + mut mapToken := self.tokens[*self.i] + *self.i++ // Skip map token. + if *self.i >= len(self.tokens) { + self.pushErr(mapToken, LogMsg.MissingType) + ret nil + } + + // Get key type tokens without brackets. + mut keyTokens := range(*self.i, TokenId.LBracket, TokenId.RBracket, self.tokens) + if *self.i >= len(self.tokens) { + self.pushErr(self.tokens[*self.i-1], LogMsg.MissingType) + ret nil + } else if len(keyTokens) == 0 { + self.pushErr(mapToken, LogMsg.MissingType) + ret nil + } + + mut mapt := new(MapTypeDecl) + mut j := 0 + mut keyt, mut ok := self.p.buildType(keyTokens, &j, self.err) + if !ok { + ret nil + } else if j < len(keyTokens) { + self.pushErr(keyTokens[j], LogMsg.InvalidSyntax) + } + mapt.Key = keyt + + mut valt, ok := self.p.buildType(self.tokens, self.i, self.err) + if !ok { + ret nil + } + mapt.Val = valt + ret &TypeDecl{ + Token: mapToken, + Kind: mapt, + } + } + + unsafe fn buildEnumerable(mut self): &TypeDecl { + mut token := self.tokens[*self.i] + if *self.i+2 >= len(self.tokens) { + self.pushErr(token, LogMsg.InvalidSyntax) + ret nil + } + *self.i++ + token = self.tokens[*self.i] + if token.Id == TokenId.RBracket { + ret self.buildSlc() + } + *self.i-- // Point to left bracket. + ret self.buildArr() + } + + unsafe fn step(mut self): &TypeDecl { + token := self.tokens[*self.i] + match token.Id { + | TokenId.Ident: + ret self.buildIdent() + | TokenId.Cpp: + ret self.buildCppLink() + | TokenId.Fn: + ret self.buildFn() + | TokenId.Star: + ret self.buildPtr() + | TokenId.Amper: + ret self.buildSptr() + | TokenId.DblAmper: + ret &TypeDecl{ + Kind: &SptrTypeDecl{ + Elem: self.buildSptr(), + }, + } + | TokenId.LBracket: + ret self.buildEnumerable() + | TokenId.Map: + ret self.buildMap() + |: + *self.i++ + self.pushErr(token, LogMsg.InvalidSyntax) + ret nil + } + } + + // Builds type. + // Returns void if error occurs. + unsafe fn build(mut self): (&TypeDecl, ok: bool) { + mut root := self.step() + if root == nil { + ret buildVoidType(), false + } + ret root, true + } } \ No newline at end of file diff --git a/std/jule/sema/analysis.jule b/std/jule/sema/analysis.jule index 381f19b3e..001c338bc 100644 --- a/std/jule/sema/analysis.jule +++ b/std/jule/sema/analysis.jule @@ -8,50 +8,50 @@ use std::jule::build::{Log} // Flags for semantic analysis. enum SemaFlag { - Default: 0, // Default semantic analysis of Jule. - Shadowing: 1 << 0, // Default + enable shadowing. + Default: 0, // Default semantic analysis of Jule. + Shadowing: 1 << 0, // Default + enable shadowing. } // Builds symbol table of AST. fn buildSymbols(mut &ast: &Ast, mut &importer: Importer, mut owner: &symbolBuilder): (&SymbolTable, []Log) { - mut sb := &symbolBuilder{ - ast: ast, - importer: importer, - owner: owner, - } - sb.build() + mut sb := &symbolBuilder{ + ast: ast, + importer: importer, + owner: owner, + } + sb.build() - if len(sb.errors) == 0 { - ret sb.table, nil - } - ret nil, sb.errors + if len(sb.errors) == 0 { + ret sb.table, nil + } + ret nil, sb.errors } fn analyzePackage(mut &files: []&Ast, mut &importer: Importer, &flags: SemaFlag): (&Package, []Log) { - // Build symbol tables of files. - mut tables := make([]&SymbolTable, 0, len(files)) - for (_, mut f) in files { - mut table, mut errors := buildSymbols(f, importer, nil) - if len(errors) > 0 { - ret nil, errors - } - tables = append(tables, table) - } + // Build symbol tables of files. + mut tables := make([]&SymbolTable, 0, len(files)) + for (_, mut f) in files { + mut table, mut errors := buildSymbols(f, importer, nil) + if len(errors) > 0 { + ret nil, errors + } + tables = append(tables, table) + } - mut sema := &Sema{ - flags: flags, - meta: new(commonSemaMeta), - } - sema.check(tables) - if len(sema.errors) > 0 { - ret nil, sema.errors - } + mut sema := &Sema{ + flags: flags, + meta: new(commonSemaMeta), + } + sema.check(tables) + if len(sema.errors) > 0 { + ret nil, sema.errors + } - mut pkg := &Package{ - Files: sema.files, - } + mut pkg := &Package{ + Files: sema.files, + } - ret pkg, nil + ret pkg, nil } // Builds symbol table of package's ASTs. @@ -72,10 +72,10 @@ fn analyzePackage(mut &files: []&Ast, mut &importer: Importer, &flags: SemaFlag) // - You can pass nil to importer, but panics if importer is nil and // semantic analyzer used nil importer. fn AnalyzePackage(mut files: []&Ast, mut importer: Importer, flags: SemaFlag): (&Package, []Log) { - if len(files) == 0 { - ret nil, nil - } - ret analyzePackage(files, importer, flags) + if len(files) == 0 { + ret nil, nil + } + ret analyzePackage(files, importer, flags) } // Builds symbol table of AST. @@ -96,13 +96,13 @@ fn AnalyzePackage(mut files: []&Ast, mut importer: Importer, flags: SemaFlag): ( // - You can pass nil to importer, but panics if importer is nil and // semantic analyzer used nil importer. fn AnalyzeFile(mut f: &Ast, mut importer: Importer, flags: SemaFlag): (&SymbolTable, []Log) { - let mut files: [1]&Ast = [f] - mut pkg, mut errors := AnalyzePackage(unsafe::Slice(&files[0], len(files)), importer, flags) - if len(errors) > 0 { - ret nil, errors - } - // Select first table, because package has only one file. - // We give just one file. - mut table := pkg.Files[0] - ret table, nil + let mut files: [1]&Ast = [f] + mut pkg, mut errors := AnalyzePackage(unsafe::Slice(&files[0], len(files)), importer, flags) + if len(errors) > 0 { + ret nil, errors + } + // Select first table, because package has only one file. + // We give just one file. + mut table := pkg.Files[0] + ret table, nil } \ No newline at end of file diff --git a/std/jule/sema/builtin.jule b/std/jule/sema/builtin.jule index 554e5ea6b..ad8abd7e7 100644 --- a/std/jule/sema/builtin.jule +++ b/std/jule/sema/builtin.jule @@ -4,12 +4,12 @@ use fmt for std::fmt use std::jule::ast::{ - FnCallExpr, - TypeDecl, - IdentTypeDecl, - GenericDecl, - IdentExpr, - VariadicExpr, + FnCallExpr, + TypeDecl, + IdentTypeDecl, + GenericDecl, + IdentExpr, + VariadicExpr, } use mod for std::jule::internal::mod use std::jule::build::{LogMsg} @@ -24,52 +24,52 @@ use std::jule::constant::{Const} type builtinCaller: fn(mut &e: &Eval, mut &fc: &FnCallExpr, mut &d: &Data): &Data fn findBuiltinFunc(&ident: str): &FnIns { - match ident { - | "out": - static mut f = &FnIns{caller: builtinCallerOut} - ret f - | "outln": - static mut f = &FnIns{caller: builtinCallerOutln} - ret f - | "new": - static mut f = &FnIns{caller: builtinCallerNew} - ret f - | "panic": - static mut f = &FnIns{caller: builtinCallerPanic} - ret f - | "make": - static mut f = &FnIns{caller: builtinCallerMake} - ret f - | "append": - static mut f = &FnIns{caller: builtinCallerAppend} - ret f - | "copy": - static mut f = &FnIns{caller: builtinCallerCopy} - ret f - | "len": - static mut f = &FnIns{caller: builtinCallerLen} - ret f - | "cap": - static mut f = &FnIns{caller: builtinCallerCap} - ret f - | "delete": - static mut f = &FnIns{caller: builtinCallerDelete} - ret f - | "assert": - static mut f = &FnIns{caller: builtinCallerAssert} - ret f - |: - ret nil - } + match ident { + | "out": + static mut f = &FnIns{caller: builtinCallerOut} + ret f + | "outln": + static mut f = &FnIns{caller: builtinCallerOutln} + ret f + | "new": + static mut f = &FnIns{caller: builtinCallerNew} + ret f + | "panic": + static mut f = &FnIns{caller: builtinCallerPanic} + ret f + | "make": + static mut f = &FnIns{caller: builtinCallerMake} + ret f + | "append": + static mut f = &FnIns{caller: builtinCallerAppend} + ret f + | "copy": + static mut f = &FnIns{caller: builtinCallerCopy} + ret f + | "len": + static mut f = &FnIns{caller: builtinCallerLen} + ret f + | "cap": + static mut f = &FnIns{caller: builtinCallerCap} + ret f + | "delete": + static mut f = &FnIns{caller: builtinCallerDelete} + ret f + | "assert": + static mut f = &FnIns{caller: builtinCallerAssert} + ret f + |: + ret nil + } } fn primTypeAlias(mut &k: &TypeKind): &TypeAlias { - ret &TypeAlias{ - Public: true, - Kind: &TypeSymbol{ - Kind: k, - }, - } + ret &TypeAlias{ + Public: true, + Kind: &TypeSymbol{ + Kind: k, + }, + } } static mut primNil = &TypeKind{Kind: nil} @@ -92,1103 +92,1103 @@ static mut primF32 = &TypeKind{Kind: buildPrimType(PrimKind.F32)} static mut primF64 = &TypeKind{Kind: buildPrimType(PrimKind.F64)} fn findBuiltinVar(&ident: str): &Var { - match ident { - | "nil": - static mut v = &Var{ - Public: true, - Mutable: false, - Kind: &TypeSymbol{ - Kind: primNil, - }, - Constant: true, - Value: &Value{ - Data: &Data{ - Constant: Const.NewNil(), - }, - }, - } - ret v - | "true": - static mut v = &Var{ - Public: true, - Mutable: false, - Kind: findBuiltinTypeAlias("bool").Kind, - Constant: true, - Value: &Value{ - Data: &Data{ - Constant: Const.NewBool(true), - }, - }, - } - ret v - | "false": - static mut v = &Var{ - Public: true, - Mutable: false, - Kind: findBuiltinTypeAlias("bool").Kind, - Constant: true, - Value: &Value{ - Data: &Data{ - Constant: Const.NewBool(false), - }, - }, - } - ret v - |: - ret nil - } + match ident { + | "nil": + static mut v = &Var{ + Public: true, + Mutable: false, + Kind: &TypeSymbol{ + Kind: primNil, + }, + Constant: true, + Value: &Value{ + Data: &Data{ + Constant: Const.NewNil(), + }, + }, + } + ret v + | "true": + static mut v = &Var{ + Public: true, + Mutable: false, + Kind: findBuiltinTypeAlias("bool").Kind, + Constant: true, + Value: &Value{ + Data: &Data{ + Constant: Const.NewBool(true), + }, + }, + } + ret v + | "false": + static mut v = &Var{ + Public: true, + Mutable: false, + Kind: findBuiltinTypeAlias("bool").Kind, + Constant: true, + Value: &Value{ + Data: &Data{ + Constant: Const.NewBool(false), + }, + }, + } + ret v + |: + ret nil + } } fn findBuiltinTypeAlias(ident: str): &TypeAlias { - match ident { - | "any": - static mut t = primTypeAlias(primAny) - ret t - | "str": - static mut t = primTypeAlias(primStr) - ret t - | "bool": - static mut t = primTypeAlias(primBool) - ret t - | "uintptr": - static mut t = primTypeAlias(primUintptr) - ret t - | "uint": - static mut t = primTypeAlias(primUint) - ret t - | "int": - static mut t = primTypeAlias(primInt) - ret t - | "i8": - static mut t = primTypeAlias(primI8) - ret t - | "i16": - static mut t = primTypeAlias(primI16) - ret t - | "i64": - static mut t = primTypeAlias(primI64) - ret t - | "u16": - static mut t = primTypeAlias(primU16) - ret t - | "u32": - static mut t = primTypeAlias(primU32) - ret t - | "u64": - static mut t = primTypeAlias(primU64) - ret t - | "f32": - static mut t = primTypeAlias(primF32) - ret t - | "f64": - static mut t = primTypeAlias(primF64) - ret t - | "byte" | "u8": - static mut t = primTypeAlias(primU8) - ret t - | "rune" | "i32": - static mut t = primTypeAlias(primI32) - ret t - |: - ret nil - } + match ident { + | "any": + static mut t = primTypeAlias(primAny) + ret t + | "str": + static mut t = primTypeAlias(primStr) + ret t + | "bool": + static mut t = primTypeAlias(primBool) + ret t + | "uintptr": + static mut t = primTypeAlias(primUintptr) + ret t + | "uint": + static mut t = primTypeAlias(primUint) + ret t + | "int": + static mut t = primTypeAlias(primInt) + ret t + | "i8": + static mut t = primTypeAlias(primI8) + ret t + | "i16": + static mut t = primTypeAlias(primI16) + ret t + | "i64": + static mut t = primTypeAlias(primI64) + ret t + | "u16": + static mut t = primTypeAlias(primU16) + ret t + | "u32": + static mut t = primTypeAlias(primU32) + ret t + | "u64": + static mut t = primTypeAlias(primU64) + ret t + | "f32": + static mut t = primTypeAlias(primF32) + ret t + | "f64": + static mut t = primTypeAlias(primF64) + ret t + | "byte" | "u8": + static mut t = primTypeAlias(primU8) + ret t + | "rune" | "i32": + static mut t = primTypeAlias(primI32) + ret t + |: + ret nil + } } fn findBuiltinDef(&ident: str): any { - mut v := findBuiltinVar(ident) - if v != nil { - ret v - } - mut f := findBuiltinFunc(ident) - if f != nil { - ret f - } - mut ta := findBuiltinTypeAlias(ident) - if ta != nil { - ret ta - } - ret nil + mut v := findBuiltinVar(ident) + if v != nil { + ret v + } + mut f := findBuiltinFunc(ident) + if f != nil { + ret f + } + mut ta := findBuiltinTypeAlias(ident) + if ta != nil { + ret ta + } + ret nil } fn findBuiltinDefStdDebug(&ident: str): any { - match ident { - | "Out": - static mut f = &FnIns{caller: builtinCallerStdDebugOut} - ret f - | "Outln": - static mut f = &FnIns{caller: builtinCallerStdDebugOutln} - ret f - |: - ret nil - } + match ident { + | "Out": + static mut f = &FnIns{caller: builtinCallerStdDebugOut} + ret f + | "Outln": + static mut f = &FnIns{caller: builtinCallerStdDebugOutln} + ret f + |: + ret nil + } } fn findBuiltinDefStdMem(&ident: str): any { - match ident { - | "SizeOf": - static mut f = &FnIns{caller: builtinCallerStdMemSizeOf} - ret f - | "AlignOf": - static mut f = &FnIns{caller: builtinCallerStdMemAlignOf} - ret f - | "Free": - static mut f = &FnIns{caller: builtinCallerStdMemFree} - ret f - |: - ret nil - } + match ident { + | "SizeOf": + static mut f = &FnIns{caller: builtinCallerStdMemSizeOf} + ret f + | "AlignOf": + static mut f = &FnIns{caller: builtinCallerStdMemAlignOf} + ret f + | "Free": + static mut f = &FnIns{caller: builtinCallerStdMemFree} + ret f + |: + ret nil + } } fn findBuiltinDefStdComptime(&ident: str): any { - match ident { - | "TypeOf": - static mut f = &FnIns{caller: builtinCallerStdComptimeTypeOf} - ret f - | "ValueOf": - static mut f = &FnIns{caller: builtinCallerStdComptimeValueOf} - ret f - | "Line": - static mut f = &FnIns{caller: builtinCallerStdComptimeLine} - ret f - | "File": - static mut f = &FnIns{caller: builtinCallerStdComptimeFile} - ret f - | "Files": - static mut f = &FnIns{caller: builtinCallerStdComptimeFiles} - ret f - | "TypeAlias": - static mut f = &FnIns{caller: builtinCallerStdComptimeTypeAlias} - ret f - |: - ret nil - } + match ident { + | "TypeOf": + static mut f = &FnIns{caller: builtinCallerStdComptimeTypeOf} + ret f + | "ValueOf": + static mut f = &FnIns{caller: builtinCallerStdComptimeValueOf} + ret f + | "Line": + static mut f = &FnIns{caller: builtinCallerStdComptimeLine} + ret f + | "File": + static mut f = &FnIns{caller: builtinCallerStdComptimeFile} + ret f + | "Files": + static mut f = &FnIns{caller: builtinCallerStdComptimeFiles} + ret f + | "TypeAlias": + static mut f = &FnIns{caller: builtinCallerStdComptimeTypeAlias} + ret f + |: + ret nil + } } fn findBuiltinDefStdJuleIntegrated(&ident: str): any { - match ident { - | "ToStr": - static mut f = &FnIns{caller: builtinCallerStdJuleIntegratedToStr} - ret f - | "Emit": - static mut f = &FnIns{ - Decl: &Fn{ - Generics: make([]&GenericDecl, 1), - }, - caller: builtinCallerStdJuleIntegratedEmit, - } - ret f - |: - ret nil - } + match ident { + | "ToStr": + static mut f = &FnIns{caller: builtinCallerStdJuleIntegratedToStr} + ret f + | "Emit": + static mut f = &FnIns{ + Decl: &Fn{ + Generics: make([]&GenericDecl, 1), + }, + caller: builtinCallerStdJuleIntegratedEmit, + } + ret f + |: + ret nil + } } fn findPackageBuiltinDef(&linkPath: str, &ident: str): any { - match linkPath { - | "std::comptime": - ret findBuiltinDefStdComptime(ident) - | "std::debug": - ret findBuiltinDefStdDebug(ident) - | "std::mem": - ret findBuiltinDefStdMem(ident) - | "std::jule::integrated": - ret findBuiltinDefStdJuleIntegrated(ident) - |: - ret nil - } + match linkPath { + | "std::comptime": + ret findBuiltinDefStdComptime(ident) + | "std::debug": + ret findBuiltinDefStdDebug(ident) + | "std::mem": + ret findBuiltinDefStdMem(ident) + | "std::jule::integrated": + ret findBuiltinDefStdJuleIntegrated(ident) + |: + ret nil + } } fn builtinCallerError(mut &e: &Eval, mut &fc: &FnCallExpr): &Data { - if len(fc.Args) < 1 { - e.pushErr(fc.Token, LogMsg.MissingExprFor, "err") - ret nil - } - if len(fc.Args) > 1 { - e.pushErr(fc.Args[1].Token, LogMsg.ArgumentOverflow, "error") - } - mut expr := e.evalExpr(fc.Args[0]) - if expr == nil { - ret nil - } - - if expr.IsNil() { - e.pushErr(fc.Args[0].Token, LogMsg.NilError) - } - - mut d := buildVoidData() - d.Model = &BuiltinErrorCallExprModel{Err: expr} - ret d + if len(fc.Args) < 1 { + e.pushErr(fc.Token, LogMsg.MissingExprFor, "err") + ret nil + } + if len(fc.Args) > 1 { + e.pushErr(fc.Args[1].Token, LogMsg.ArgumentOverflow, "error") + } + mut expr := e.evalExpr(fc.Args[0]) + if expr == nil { + ret nil + } + + if expr.IsNil() { + e.pushErr(fc.Args[0].Token, LogMsg.NilError) + } + + mut d := buildVoidData() + d.Model = &BuiltinErrorCallExprModel{Err: expr} + ret d } fn builtinCallerOut(mut &e: &Eval, mut &fc: &FnCallExpr, mut &_: &Data): &Data { - if len(fc.Args) < 1 { - e.pushErr(fc.Token, LogMsg.MissingExprFor, "v") - ret nil - } - if len(fc.Args) > 1 { - e.pushErr(fc.Args[1].Token, LogMsg.ArgumentOverflow, "out") - } - - mut expr := e.evalExpr(fc.Args[0]) - if expr == nil { - ret nil - } - - if !isBuiltinStrConvertable(expr.Kind) { - e.pushErr(fc.Args[0].Token, LogMsg.InvalidExpr) - ret nil - } - - mut d := buildVoidData() - d.Model = &BuiltinOutCallExprModel{Expr: expr.Model} - ret d + if len(fc.Args) < 1 { + e.pushErr(fc.Token, LogMsg.MissingExprFor, "v") + ret nil + } + if len(fc.Args) > 1 { + e.pushErr(fc.Args[1].Token, LogMsg.ArgumentOverflow, "out") + } + + mut expr := e.evalExpr(fc.Args[0]) + if expr == nil { + ret nil + } + + if !isBuiltinStrConvertable(expr.Kind) { + e.pushErr(fc.Args[0].Token, LogMsg.InvalidExpr) + ret nil + } + + mut d := buildVoidData() + d.Model = &BuiltinOutCallExprModel{Expr: expr.Model} + ret d } fn builtinCallerOutln(mut &e: &Eval, mut &fc: &FnCallExpr, mut &d: &Data): &Data { - d = builtinCallerOut(e, fc, d) - if d == nil { - ret nil - } - - d.Model = &BuiltinOutlnCallExprModel{ - Expr: (&BuiltinOutCallExprModel)(d.Model).Expr, - } - ret d + d = builtinCallerOut(e, fc, d) + if d == nil { + ret nil + } + + d.Model = &BuiltinOutlnCallExprModel{ + Expr: (&BuiltinOutCallExprModel)(d.Model).Expr, + } + ret d } fn builtinCallerNew(mut &e: &Eval, mut &fc: &FnCallExpr, mut &d: &Data): &Data { - if len(fc.Args) < 1 { - e.pushErr(fc.Token, LogMsg.MissingExprFor, "type") - ret nil - } - if len(fc.Args) > 2 { - e.pushErr(fc.Args[2].Token, LogMsg.ArgumentOverflow, "new") - } - - mut t := e.evalExprKind(fc.Args[0].Kind) - if t == nil { - ret nil - } - - if !t.Decl { - e.pushErr(fc.Args[0].Token, LogMsg.InvalidType) - ret nil - } - - if !isValidForSptrType(t.Kind) { - mut s := t.Kind.Struct() - if s != nil && s.Decl != nil && s.Decl.Binded { - e.pushErr(fc.Args[0].Token, LogMsg.BindedStructForRef) - } - ret nil - } - - d.Kind = &TypeKind{ - Kind: &Sptr{ - Elem: t.Kind, - }, - } - - if len(fc.Args) == 2 { // Initialize expression. - mut old := e.prefix - e.prefix = t.Kind - - mut init := e.evalExpr(fc.Args[1]) - - e.prefix = old - - if init != nil { - mut token := fc.Args[1].Token - const Reference = false - e.s.checkValidityForInitExpr( - !e.immutable, Reference, t.Kind, init, token) - _ = e.s.checkAssignType(false, t.Kind, init, token) - - d.Model = &BuiltinNewCallExprModel{ - Kind: t.Kind, - Init: init.Model, - } - } - } else { - d.Model = &BuiltinNewCallExprModel{ - Kind: t.Kind, - } - } - - ret d + if len(fc.Args) < 1 { + e.pushErr(fc.Token, LogMsg.MissingExprFor, "type") + ret nil + } + if len(fc.Args) > 2 { + e.pushErr(fc.Args[2].Token, LogMsg.ArgumentOverflow, "new") + } + + mut t := e.evalExprKind(fc.Args[0].Kind) + if t == nil { + ret nil + } + + if !t.Decl { + e.pushErr(fc.Args[0].Token, LogMsg.InvalidType) + ret nil + } + + if !isValidForSptrType(t.Kind) { + mut s := t.Kind.Struct() + if s != nil && s.Decl != nil && s.Decl.Binded { + e.pushErr(fc.Args[0].Token, LogMsg.BindedStructForRef) + } + ret nil + } + + d.Kind = &TypeKind{ + Kind: &Sptr{ + Elem: t.Kind, + }, + } + + if len(fc.Args) == 2 { // Initialize expression. + mut old := e.prefix + e.prefix = t.Kind + + mut init := e.evalExpr(fc.Args[1]) + + e.prefix = old + + if init != nil { + mut token := fc.Args[1].Token + const Reference = false + e.s.checkValidityForInitExpr( + !e.immutable, Reference, t.Kind, init, token) + _ = e.s.checkAssignType(false, t.Kind, init, token) + + d.Model = &BuiltinNewCallExprModel{ + Kind: t.Kind, + Init: init.Model, + } + } + } else { + d.Model = &BuiltinNewCallExprModel{ + Kind: t.Kind, + } + } + + ret d } fn builtinCallerPanic(mut &e: &Eval, mut &fc: &FnCallExpr, mut &_: &Data): &Data { - if len(fc.Args) < 1 { - e.pushErr(fc.Token, LogMsg.MissingExprFor, "message") - ret nil - } - if len(fc.Args) > 1 { - e.pushErr(fc.Args[2].Token, LogMsg.ArgumentOverflow, "panic") - } - - mut expr := e.evalExpr(fc.Args[0]) - if expr == nil { - ret nil - } - - if expr.Kind.Prim() == nil || !expr.Kind.Prim().IsStr() { - e.pushErr(fc.Token, LogMsg.PanicedWithNonStr) - } - - mut d := buildVoidData() - d.Model = &BuiltinPanicCallExprModel{ - Token: fc.Token, - Expr: expr.Model, - } - ret d + if len(fc.Args) < 1 { + e.pushErr(fc.Token, LogMsg.MissingExprFor, "message") + ret nil + } + if len(fc.Args) > 1 { + e.pushErr(fc.Args[2].Token, LogMsg.ArgumentOverflow, "panic") + } + + mut expr := e.evalExpr(fc.Args[0]) + if expr == nil { + ret nil + } + + if expr.Kind.Prim() == nil || !expr.Kind.Prim().IsStr() { + e.pushErr(fc.Token, LogMsg.PanicedWithNonStr) + } + + mut d := buildVoidData() + d.Model = &BuiltinPanicCallExprModel{ + Token: fc.Token, + Expr: expr.Model, + } + ret d } fn builtinCallerMake(mut &e: &Eval, mut &fc: &FnCallExpr, mut &d: &Data): &Data { - if len(fc.Args) < 2 { - if len(fc.Args) == 1 { - e.pushErr(fc.Token, LogMsg.MissingExprFor, "size") - ret nil - } - e.pushErr(fc.Token, LogMsg.MissingExprFor, "type, size") - ret nil - } else if len(fc.Args) > 3 { - e.pushErr(fc.Args[3].Token, LogMsg.ArgumentOverflow, "make") - ret nil - } - - mut t := e.evalExprKind(fc.Args[0].Kind) - if t == nil { - ret nil - } - - if !t.Decl { - e.pushErr(fc.Args[0].Token, LogMsg.InvalidType) - ret nil - } else if t.Kind.Slc() == nil { - e.pushErr(fc.Args[0].Token, LogMsg.InvalidTypeForFn, t.Kind.Str(), "make") - ret nil - } - - d.Kind = t.Kind - - mut lenExpr := e.s.evalp(e.lookup, t.Kind).evalExpr(fc.Args[1]) - if lenExpr == nil { - ret nil - } - - e.checkIntegerIndexingByData(lenExpr, fc.Args[1].Token) - - mut model := &BuiltinMakeCallExprModel{ - Kind: t.Kind, - Len: lenExpr.Model, - } - d.Model = model - if len(fc.Args) == 3 { - mut capExpr := e.s.evalp(e.lookup, t.Kind).evalExpr(fc.Args[2]) - if capExpr == nil { - ret d - } - e.checkIntegerIndexingByData(capExpr, fc.Args[2].Token) - model.Cap = capExpr.Model - } - ret d + if len(fc.Args) < 2 { + if len(fc.Args) == 1 { + e.pushErr(fc.Token, LogMsg.MissingExprFor, "size") + ret nil + } + e.pushErr(fc.Token, LogMsg.MissingExprFor, "type, size") + ret nil + } else if len(fc.Args) > 3 { + e.pushErr(fc.Args[3].Token, LogMsg.ArgumentOverflow, "make") + ret nil + } + + mut t := e.evalExprKind(fc.Args[0].Kind) + if t == nil { + ret nil + } + + if !t.Decl { + e.pushErr(fc.Args[0].Token, LogMsg.InvalidType) + ret nil + } else if t.Kind.Slc() == nil { + e.pushErr(fc.Args[0].Token, LogMsg.InvalidTypeForFn, t.Kind.Str(), "make") + ret nil + } + + d.Kind = t.Kind + + mut lenExpr := e.s.evalp(e.lookup, t.Kind).evalExpr(fc.Args[1]) + if lenExpr == nil { + ret nil + } + + e.checkIntegerIndexingByData(lenExpr, fc.Args[1].Token) + + mut model := &BuiltinMakeCallExprModel{ + Kind: t.Kind, + Len: lenExpr.Model, + } + d.Model = model + if len(fc.Args) == 3 { + mut capExpr := e.s.evalp(e.lookup, t.Kind).evalExpr(fc.Args[2]) + if capExpr == nil { + ret d + } + e.checkIntegerIndexingByData(capExpr, fc.Args[2].Token) + model.Cap = capExpr.Model + } + ret d } fn builtinCallerAppend(mut &e: &Eval, mut &fc: &FnCallExpr, mut &d: &Data): &Data { - if len(fc.Args) < 2 { - if len(fc.Args) == 1 { - e.pushErr(fc.Token, LogMsg.MissingExprFor, "values") - ret nil - } - e.pushErr(fc.Token, LogMsg.MissingExprFor, "src, values") - ret nil - } - - mut t := e.evalExpr(fc.Args[0]) - if t == nil { - ret nil - } - - mut s := t.Kind.Slc() - if s == nil { - e.pushErr(fc.Args[0].Token, LogMsg.InvalidExpr) - ret nil - } - - const reference = false // Element parameter is not reference. - const mutable = true // Element parameter is mutable. - - if e.s.checkValidityForInitExpr(mutable, reference, t.Kind, t, fc.Args[0].Token) { - // Check type if validity is good. - // Helps to reduce error logs and duplicated logs. - _ = e.s.checkAssignType(reference, t.Kind, t, fc.Args[0].Token) - } - - mut prefix := e.prefix - e.prefix = t.Kind - defer { e.prefix = prefix } - - d = &Data{ - Mutable: true, - Kind: t.Kind, - } - match type fc.Args[1].Kind { - | &VariadicExpr: - if len(fc.Args) > 2 { - e.pushErr(fc.Args[2].Token, LogMsg.MoreArgsWithVariadiced) - } - - mut e1 := e.evalExpr((&VariadicExpr)(fc.Args[1].Kind).Expr) - if e1 == nil { - ret nil - } - if s.Elem.Prim() != nil && s.Elem.Prim().IsU8() { // []byte - if e1.Kind.Prim() != nil && e1.Kind.Prim().IsStr() { - // append([]byte, str...) - makeVariadic(e1, primU8) - d.Model = &BuiltinAppendCallExprModel{ - Dest: t.Model, - Elements: e1.Model, - } - ret d - } - } - - if !e1.Kind.Variadicable() { - e.pushErr(fc.Args[1].Token, LogMsg.VariadicWithNonVariadicable, e1.Kind.Str()) - ret nil - } - makeVariadic(e1, s.Elem) - - if e.s.checkValidityForInitExpr(mutable, reference, s.Elem, e1, fc.Args[1].Token) { - // Check type if validity is good. - // Helps to reduce error logs and duplicated logs. - _ = e.s.checkAssignType(reference, s.Elem, e1, fc.Args[1].Token) - } - d.Model = &BuiltinAppendCallExprModel{ - Dest: t.Model, - Elements: e1.Model, - } - ret d - } - - mut e1 := e.evalExpr(fc.Args[1]) - if e1 == nil { - ret nil - } - - mut slice := &SliceExprModel{ - ElemKind: s.Elem, - Elems: make([]ExprModel, 0, len(fc.Args)-1) - } - for (_, mut arg) in fc.Args[1:] { - e1 = e.evalExpr(arg) - if e1 == nil { - ret nil - } - if e1.Kind.Variadic { - e.pushErr(arg.Token, LogMsg.MoreArgsWithVariadiced) - } - if e.s.checkValidityForInitExpr(mutable, reference, s.Elem, e1, arg.Token) { - // Check type if validity is good. - // Helps to reduce error logs and duplicated logs. - _ = e.s.checkAssignType(reference, s.Elem, e1, arg.Token) - } - slice.Elems = append(slice.Elems, e1.Model) - } - d.Model = &BuiltinAppendCallExprModel{ - Dest: t.Model, - Elements: slice, - } - ret d + if len(fc.Args) < 2 { + if len(fc.Args) == 1 { + e.pushErr(fc.Token, LogMsg.MissingExprFor, "values") + ret nil + } + e.pushErr(fc.Token, LogMsg.MissingExprFor, "src, values") + ret nil + } + + mut t := e.evalExpr(fc.Args[0]) + if t == nil { + ret nil + } + + mut s := t.Kind.Slc() + if s == nil { + e.pushErr(fc.Args[0].Token, LogMsg.InvalidExpr) + ret nil + } + + const reference = false // Element parameter is not reference. + const mutable = true // Element parameter is mutable. + + if e.s.checkValidityForInitExpr(mutable, reference, t.Kind, t, fc.Args[0].Token) { + // Check type if validity is good. + // Helps to reduce error logs and duplicated logs. + _ = e.s.checkAssignType(reference, t.Kind, t, fc.Args[0].Token) + } + + mut prefix := e.prefix + e.prefix = t.Kind + defer { e.prefix = prefix } + + d = &Data{ + Mutable: true, + Kind: t.Kind, + } + match type fc.Args[1].Kind { + | &VariadicExpr: + if len(fc.Args) > 2 { + e.pushErr(fc.Args[2].Token, LogMsg.MoreArgsWithVariadiced) + } + + mut e1 := e.evalExpr((&VariadicExpr)(fc.Args[1].Kind).Expr) + if e1 == nil { + ret nil + } + if s.Elem.Prim() != nil && s.Elem.Prim().IsU8() { // []byte + if e1.Kind.Prim() != nil && e1.Kind.Prim().IsStr() { + // append([]byte, str...) + makeVariadic(e1, primU8) + d.Model = &BuiltinAppendCallExprModel{ + Dest: t.Model, + Elements: e1.Model, + } + ret d + } + } + + if !e1.Kind.Variadicable() { + e.pushErr(fc.Args[1].Token, LogMsg.VariadicWithNonVariadicable, e1.Kind.Str()) + ret nil + } + makeVariadic(e1, s.Elem) + + if e.s.checkValidityForInitExpr(mutable, reference, s.Elem, e1, fc.Args[1].Token) { + // Check type if validity is good. + // Helps to reduce error logs and duplicated logs. + _ = e.s.checkAssignType(reference, s.Elem, e1, fc.Args[1].Token) + } + d.Model = &BuiltinAppendCallExprModel{ + Dest: t.Model, + Elements: e1.Model, + } + ret d + } + + mut e1 := e.evalExpr(fc.Args[1]) + if e1 == nil { + ret nil + } + + mut slice := &SliceExprModel{ + ElemKind: s.Elem, + Elems: make([]ExprModel, 0, len(fc.Args) - 1), + } + for (_, mut arg) in fc.Args[1:] { + e1 = e.evalExpr(arg) + if e1 == nil { + ret nil + } + if e1.Kind.Variadic { + e.pushErr(arg.Token, LogMsg.MoreArgsWithVariadiced) + } + if e.s.checkValidityForInitExpr(mutable, reference, s.Elem, e1, arg.Token) { + // Check type if validity is good. + // Helps to reduce error logs and duplicated logs. + _ = e.s.checkAssignType(reference, s.Elem, e1, arg.Token) + } + slice.Elems = append(slice.Elems, e1.Model) + } + d.Model = &BuiltinAppendCallExprModel{ + Dest: t.Model, + Elements: slice, + } + ret d } fn callerCopySlice(mut &dest: &Data, mut &e: &Eval, mut &fc: &FnCallExpr, mut &d: &Data): &Data { - if !dest.Mutable { - e.pushErr(fc.Args[0].Token, LogMsg.MutOperationOnImmut) - } - - mut src := e.evalExpr(fc.Args[1]) - if src == nil { - ret nil - } - mut slc := src.Kind.Slc() - - if slc != nil { - if !src.Mutable && slc.Elem.Mutable() { - e.pushErr(fc.Args[1].Token, LogMsg.MutOperationOnImmut) - } - if !dest.Kind.Equal(src.Kind) { - e.pushErr(fc.Args[1].Token, LogMsg.IncompatibleTypes, dest.Kind.Str(), src.Kind.Str()) - } - } else { - destPrim := dest.Kind.Slc().Elem.Prim() - prim := src.Kind.Prim() - if destPrim == nil || prim == nil || !prim.IsStr() || !destPrim.IsU8() { - e.pushErr(fc.Args[1].Token, LogMsg.IncompatibleTypes, dest.Kind.Str(), src.Kind.Str()) - } - } - - d.Kind = lenKind() - d.Model = &BuiltinCopyCallExprModel{ - Dest: dest, - Src: src, - } - ret d + if !dest.Mutable { + e.pushErr(fc.Args[0].Token, LogMsg.MutOperationOnImmut) + } + + mut src := e.evalExpr(fc.Args[1]) + if src == nil { + ret nil + } + mut slc := src.Kind.Slc() + + if slc != nil { + if !src.Mutable && slc.Elem.Mutable() { + e.pushErr(fc.Args[1].Token, LogMsg.MutOperationOnImmut) + } + if !dest.Kind.Equal(src.Kind) { + e.pushErr(fc.Args[1].Token, LogMsg.IncompatibleTypes, dest.Kind.Str(), src.Kind.Str()) + } + } else { + destPrim := dest.Kind.Slc().Elem.Prim() + prim := src.Kind.Prim() + if destPrim == nil || prim == nil || !prim.IsStr() || !destPrim.IsU8() { + e.pushErr(fc.Args[1].Token, LogMsg.IncompatibleTypes, dest.Kind.Str(), src.Kind.Str()) + } + } + + d.Kind = lenKind() + d.Model = &BuiltinCopyCallExprModel{ + Dest: dest, + Src: src, + } + ret d } fn builtinCallerCopy(mut &e: &Eval, mut &fc: &FnCallExpr, mut &d: &Data): &Data { - if len(fc.Args) < 2 { - if len(fc.Args) == 1 { - e.pushErr(fc.Token, LogMsg.MissingExprFor, "src") - ret nil - } - e.pushErr(fc.Token, LogMsg.MissingExprFor, "src, values") - ret nil - } - if len(fc.Args) > 2 { - e.pushErr(fc.Args[2].Token, LogMsg.ArgumentOverflow, "copy") - } - - mut dest := e.evalExpr(fc.Args[0]) - match { - | dest == nil: - ret nil - | dest.Kind.Slc() != nil: - ret callerCopySlice(dest, e, fc, d) - |: - e.pushErr(fc.Args[0].Token, LogMsg.InvalidType) - ret nil - } + if len(fc.Args) < 2 { + if len(fc.Args) == 1 { + e.pushErr(fc.Token, LogMsg.MissingExprFor, "src") + ret nil + } + e.pushErr(fc.Token, LogMsg.MissingExprFor, "src, values") + ret nil + } + if len(fc.Args) > 2 { + e.pushErr(fc.Args[2].Token, LogMsg.ArgumentOverflow, "copy") + } + + mut dest := e.evalExpr(fc.Args[0]) + match { + | dest == nil: + ret nil + | dest.Kind.Slc() != nil: + ret callerCopySlice(dest, e, fc, d) + |: + e.pushErr(fc.Args[0].Token, LogMsg.InvalidType) + ret nil + } } fn callerLenSlice(mut &expr: &Data, mut &d: &Data): &Data { - d.Kind = lenKind() - d.Model = &BuiltinLenCallExprModel{ - Expr: expr, - } - ret d + d.Kind = lenKind() + d.Model = &BuiltinLenCallExprModel{ + Expr: expr, + } + ret d } fn callerLenMap(mut &expr: &Data, mut &d: &Data): &Data { - d.Kind = lenKind() - d.Model = &BuiltinLenCallExprModel{ - Expr: expr, - } - ret d + d.Kind = lenKind() + d.Model = &BuiltinLenCallExprModel{ + Expr: expr, + } + ret d } fn callerLenArr(mut &expr: &Data, mut &d: &Data): &Data { - d.Kind = lenKind() - d.Constant = Const.NewI64(i64(expr.Kind.Arr().N)) - d.Model = d.Constant - ret d + d.Kind = lenKind() + d.Constant = Const.NewI64(i64(expr.Kind.Arr().N)) + d.Model = d.Constant + ret d } fn callerLenStr(mut &expr: &Data, mut &d: &Data): &Data { - d.Kind = lenKind() - if expr.IsConst() { - d.Constant = Const.NewI64(i64(len(expr.Constant.ReadStr()))) - d.Model = d.Constant - } else { - d.Model = &BuiltinLenCallExprModel{ - Expr: expr, - } - } - ret d + d.Kind = lenKind() + if expr.IsConst() { + d.Constant = Const.NewI64(i64(len(expr.Constant.ReadStr()))) + d.Model = d.Constant + } else { + d.Model = &BuiltinLenCallExprModel{ + Expr: expr, + } + } + ret d } fn callerLenComptime(mut &d: &Data, n: int): &Data { - d.Kind = lenKind() - d.Constant = Const.NewI64(i64(n)) - d.Model = d.Constant - ret d + d.Kind = lenKind() + d.Constant = Const.NewI64(i64(n)) + d.Model = d.Constant + ret d } fn builtinCallerLen(mut &e: &Eval, mut &fc: &FnCallExpr, mut &d: &Data): &Data { - if len(fc.Args) < 1 { - e.pushErr(fc.Token, LogMsg.MissingExprFor, "obj") - ret nil - } - if len(fc.Args) > 1 { - e.pushErr(fc.Args[1].Token, LogMsg.ArgumentOverflow, "len") - } - mut dest := e.evalExpr1(fc.Args[0]) - match { - | dest == nil: - ret nil - | dest.Kind.Slc() != nil: - ret callerLenSlice(dest, d) - | dest.Kind.Arr() != nil: - ret callerLenArr(dest, d) - | dest.Kind.Map() != nil: - ret callerLenMap(dest, d) - | dest.Kind.Prim() != nil && dest.Kind.Prim().IsStr(): - ret callerLenStr(dest, d) - | dest.Kind.comptimeStructFields() != nil: - ret callerLenComptime(d, len(dest.Kind.comptimeStructFields().fields)) - | dest.Kind.comptimeEnumFields() != nil: - ret callerLenComptime(d, len(dest.Kind.comptimeEnumFields().fields)) - | dest.Kind.comptimeTypeInfos() != nil: - ret callerLenComptime(d, len(dest.Kind.comptimeTypeInfos().types)) - | dest.Kind.comptimeParams() != nil: - ret callerLenComptime(d, len(dest.Kind.comptimeParams().params)) - | dest.Kind.comptimeStatics() != nil: - ret callerLenComptime(d, len(dest.Kind.comptimeStatics().fields)) - | dest.Kind.comptimeFiles() != nil: - ret callerLenComptime(d, len(dest.Kind.comptimeFiles().files)) - |: - e.pushErr(fc.Args[0].Token, LogMsg.InvalidExpr) - ret nil - } + if len(fc.Args) < 1 { + e.pushErr(fc.Token, LogMsg.MissingExprFor, "obj") + ret nil + } + if len(fc.Args) > 1 { + e.pushErr(fc.Args[1].Token, LogMsg.ArgumentOverflow, "len") + } + mut dest := e.evalExpr1(fc.Args[0]) + match { + | dest == nil: + ret nil + | dest.Kind.Slc() != nil: + ret callerLenSlice(dest, d) + | dest.Kind.Arr() != nil: + ret callerLenArr(dest, d) + | dest.Kind.Map() != nil: + ret callerLenMap(dest, d) + | dest.Kind.Prim() != nil && dest.Kind.Prim().IsStr(): + ret callerLenStr(dest, d) + | dest.Kind.comptimeStructFields() != nil: + ret callerLenComptime(d, len(dest.Kind.comptimeStructFields().fields)) + | dest.Kind.comptimeEnumFields() != nil: + ret callerLenComptime(d, len(dest.Kind.comptimeEnumFields().fields)) + | dest.Kind.comptimeTypeInfos() != nil: + ret callerLenComptime(d, len(dest.Kind.comptimeTypeInfos().types)) + | dest.Kind.comptimeParams() != nil: + ret callerLenComptime(d, len(dest.Kind.comptimeParams().params)) + | dest.Kind.comptimeStatics() != nil: + ret callerLenComptime(d, len(dest.Kind.comptimeStatics().fields)) + | dest.Kind.comptimeFiles() != nil: + ret callerLenComptime(d, len(dest.Kind.comptimeFiles().files)) + |: + e.pushErr(fc.Args[0].Token, LogMsg.InvalidExpr) + ret nil + } } fn callerCapSlice(mut &expr: &Data, mut &d: &Data): &Data { - d.Kind = lenKind() - d.Model = &BuiltinCapCallExprModel{ - Expr: expr, - } - ret d + d.Kind = lenKind() + d.Model = &BuiltinCapCallExprModel{ + Expr: expr, + } + ret d } fn builtinCallerCap(mut &e: &Eval, mut &fc: &FnCallExpr, mut &d: &Data): &Data { - if len(fc.Args) < 1 { - e.pushErr(fc.Token, LogMsg.MissingExprFor, "obj") - ret nil - } - if len(fc.Args) > 1 { - e.pushErr(fc.Args[1].Token, LogMsg.ArgumentOverflow, "cap") - } - mut dest := e.evalExpr(fc.Args[0]) - match { - | dest == nil: - ret nil - | dest.Decl: - e.pushErr(fc.Args[0].Token, LogMsg.InvalidExpr) - ret nil - | dest.Kind.Slc() != nil: - ret callerCapSlice(dest, d) - |: - e.pushErr(fc.Args[0].Token, LogMsg.InvalidExpr) - ret nil - } + if len(fc.Args) < 1 { + e.pushErr(fc.Token, LogMsg.MissingExprFor, "obj") + ret nil + } + if len(fc.Args) > 1 { + e.pushErr(fc.Args[1].Token, LogMsg.ArgumentOverflow, "cap") + } + mut dest := e.evalExpr(fc.Args[0]) + match { + | dest == nil: + ret nil + | dest.Decl: + e.pushErr(fc.Args[0].Token, LogMsg.InvalidExpr) + ret nil + | dest.Kind.Slc() != nil: + ret callerCapSlice(dest, d) + |: + e.pushErr(fc.Args[0].Token, LogMsg.InvalidExpr) + ret nil + } } fn callerDeleteMap(mut &e: &Eval, mut &fc: &FnCallExpr, mut &expr: &Data, mut &d: &Data): &Data { - if !expr.Mutable { - e.pushErr(fc.Args[0].Token, LogMsg.MutOperationOnImmut) - } - d = buildVoidData() - mut model := &BuiltinDeleteCallExprModel{ - Dest: expr, - } - if len(fc.Args) == 2 { - mut key := e.evalExpr(fc.Args[1]) - match { - | key == nil: - ret nil - | key.Decl: - e.pushErr(fc.Args[1].Token, LogMsg.InvalidExpr) - ret nil - |: - const Reference = false - mut keyType := expr.Kind.Map().Key - if !e.s.checkAssignType(Reference, keyType, key, fc.Args[1].Token) { - ret nil - } - } - model.Key = key - } - d.Model = model - ret d + if !expr.Mutable { + e.pushErr(fc.Args[0].Token, LogMsg.MutOperationOnImmut) + } + d = buildVoidData() + mut model := &BuiltinDeleteCallExprModel{ + Dest: expr, + } + if len(fc.Args) == 2 { + mut key := e.evalExpr(fc.Args[1]) + match { + | key == nil: + ret nil + | key.Decl: + e.pushErr(fc.Args[1].Token, LogMsg.InvalidExpr) + ret nil + |: + const Reference = false + mut keyType := expr.Kind.Map().Key + if !e.s.checkAssignType(Reference, keyType, key, fc.Args[1].Token) { + ret nil + } + } + model.Key = key + } + d.Model = model + ret d } fn builtinCallerDelete(mut &e: &Eval, mut &fc: &FnCallExpr, mut &d: &Data): &Data { - if len(fc.Args) < 1 { - e.pushErr(fc.Token, LogMsg.MissingExprFor, "map") - ret nil - } - if len(fc.Args) > 2 { - e.pushErr(fc.Args[1].Token, LogMsg.ArgumentOverflow, "delete") - } - mut dest := e.evalExpr(fc.Args[0]) - match { - | dest == nil: - ret nil - | dest.Decl: - e.pushErr(fc.Args[0].Token, LogMsg.InvalidExpr) - ret nil - | dest.Kind.Map() != nil: - ret callerDeleteMap(e, fc, dest, d) - |: - e.pushErr(fc.Args[0].Token, LogMsg.InvalidExpr) - ret nil - } + if len(fc.Args) < 1 { + e.pushErr(fc.Token, LogMsg.MissingExprFor, "map") + ret nil + } + if len(fc.Args) > 2 { + e.pushErr(fc.Args[1].Token, LogMsg.ArgumentOverflow, "delete") + } + mut dest := e.evalExpr(fc.Args[0]) + match { + | dest == nil: + ret nil + | dest.Decl: + e.pushErr(fc.Args[0].Token, LogMsg.InvalidExpr) + ret nil + | dest.Kind.Map() != nil: + ret callerDeleteMap(e, fc, dest, d) + |: + e.pushErr(fc.Args[0].Token, LogMsg.InvalidExpr) + ret nil + } } fn builtinCallerAssert(mut &e: &Eval, mut &fc: &FnCallExpr, mut &_: &Data): &Data { - if len(fc.Args) < 1 { - e.pushErr(fc.Token, LogMsg.MissingExprFor, "expr") - ret nil - } - if len(fc.Args) > 2 { - e.pushErr(fc.Args[2].Token, LogMsg.ArgumentOverflow, "assert") - } - - mut expr := e.evalExpr(fc.Args[0]) - if expr == nil { - ret nil - } - - if expr.Kind.Prim() == nil || !expr.Kind.Prim().IsBool() { - e.pushErr(fc.Token, LogMsg.AssertNonBool) - } - - mut model := &BuiltinAssertCallExprModel{ - Token: fc.Token, - Expr: expr.Model, - Log: "assertion failed", // Default log message. - } - - // Custom log message is exist. - if len(fc.Args) == 2 { - mut log := e.evalExpr(fc.Args[1]) - if log == nil { - ret nil - } - - if !log.IsConst() || log.Kind.Prim() == nil || !log.Kind.Prim().IsStr() { - e.pushErr(fc.Args[1].Token, LogMsg.IncompatibleTypes, "const str", log.Kind.Str()) - ret nil - } - - model.Log = log.Constant.ReadStr() - } - - mut d := buildVoidData() - d.Model = model - ret d + if len(fc.Args) < 1 { + e.pushErr(fc.Token, LogMsg.MissingExprFor, "expr") + ret nil + } + if len(fc.Args) > 2 { + e.pushErr(fc.Args[2].Token, LogMsg.ArgumentOverflow, "assert") + } + + mut expr := e.evalExpr(fc.Args[0]) + if expr == nil { + ret nil + } + + if expr.Kind.Prim() == nil || !expr.Kind.Prim().IsBool() { + e.pushErr(fc.Token, LogMsg.AssertNonBool) + } + + mut model := &BuiltinAssertCallExprModel{ + Token: fc.Token, + Expr: expr.Model, + Log: "assertion failed", // Default log message. + } + + // Custom log message is exist. + if len(fc.Args) == 2 { + mut log := e.evalExpr(fc.Args[1]) + if log == nil { + ret nil + } + + if !log.IsConst() || log.Kind.Prim() == nil || !log.Kind.Prim().IsStr() { + e.pushErr(fc.Args[1].Token, LogMsg.IncompatibleTypes, "const str", log.Kind.Str()) + ret nil + } + + model.Log = log.Constant.ReadStr() + } + + mut d := buildVoidData() + d.Model = model + ret d } fn builtinCallerStdComptimeTypeOf(mut &e: &Eval, mut &fc: &FnCallExpr, mut &_: &Data): &Data { - if len(fc.Args) < 1 { - e.pushErr(fc.Token, LogMsg.MissingExprFor, "type|expr") - ret nil - } - if len(fc.Args) > 1 { - e.pushErr(fc.Args[1].Token, LogMsg.ArgumentOverflow, "TypeOf") - } - - mut d := e.evalExprKind(fc.Args[0].Kind) - if d == nil { - ret nil - } - f := d.Kind.Fn() - if f != nil { - if f.IsBuiltin() { - e.pushErr(fc.Args[0].Token, LogMsg.InvalidTypeForTypeOf, "") - ret nil - } - if len(f.Generics) != len(f.Decl.Generics) { - e.pushErr(fc.Args[0].Token, LogMsg.HasGenerics) - ret nil - } - } - s := d.Kind.Struct() - if s != nil && len(s.Generics) != len(s.Decl.Generics) { - e.pushErr(fc.Args[0].Token, LogMsg.HasGenerics) - ret nil - } - if d.Kind.comptime() { - e.pushErr(fc.Args[0].Token, LogMsg.InvalidTypeForTypeOf, d.Kind.Str()) - ret nil - } - ret buildComptimeTypeInfoData(e.s, d.Kind) + if len(fc.Args) < 1 { + e.pushErr(fc.Token, LogMsg.MissingExprFor, "type|expr") + ret nil + } + if len(fc.Args) > 1 { + e.pushErr(fc.Args[1].Token, LogMsg.ArgumentOverflow, "TypeOf") + } + + mut d := e.evalExprKind(fc.Args[0].Kind) + if d == nil { + ret nil + } + f := d.Kind.Fn() + if f != nil { + if f.IsBuiltin() { + e.pushErr(fc.Args[0].Token, LogMsg.InvalidTypeForTypeOf, "") + ret nil + } + if len(f.Generics) != len(f.Decl.Generics) { + e.pushErr(fc.Args[0].Token, LogMsg.HasGenerics) + ret nil + } + } + s := d.Kind.Struct() + if s != nil && len(s.Generics) != len(s.Decl.Generics) { + e.pushErr(fc.Args[0].Token, LogMsg.HasGenerics) + ret nil + } + if d.Kind.comptime() { + e.pushErr(fc.Args[0].Token, LogMsg.InvalidTypeForTypeOf, d.Kind.Str()) + ret nil + } + ret buildComptimeTypeInfoData(e.s, d.Kind) } fn builtinCallerStdComptimeValueOf(mut &e: &Eval, mut &fc: &FnCallExpr, mut &_: &Data): &Data { - if len(fc.Args) < 1 { - e.pushErr(fc.Token, LogMsg.MissingExprFor, "expr") - ret nil - } - if len(fc.Args) > 1 { - e.pushErr(fc.Args[1].Token, LogMsg.ArgumentOverflow, "ValueOf") - } - mut d := e.evalExpr(fc.Args[0]) - if d == nil { - ret nil - } - // Do not allow value if has unsupported type for type infer. - if !isGoodValueToInfer(d) { - e.pushErr(fc.Args[0].Token, LogMsg.InvalidTypeForFn, d.Kind.Str(), "ValueOf") - ret nil - } - ret buildComptimeValue(d) + if len(fc.Args) < 1 { + e.pushErr(fc.Token, LogMsg.MissingExprFor, "expr") + ret nil + } + if len(fc.Args) > 1 { + e.pushErr(fc.Args[1].Token, LogMsg.ArgumentOverflow, "ValueOf") + } + mut d := e.evalExpr(fc.Args[0]) + if d == nil { + ret nil + } + // Do not allow value if has unsupported type for type infer. + if !isGoodValueToInfer(d) { + e.pushErr(fc.Args[0].Token, LogMsg.InvalidTypeForFn, d.Kind.Str(), "ValueOf") + ret nil + } + ret buildComptimeValue(d) } fn builtinCallerStdComptimeLine(mut &e: &Eval, mut &fc: &FnCallExpr, mut &_: &Data): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[1].Token, LogMsg.ArgumentOverflow, "Line") - } - mut constant := Const.NewI64(i64(fc.Token.Row)) - ret &Data{ - Kind: primInt, - Constant: constant, - Model: constant, - } + if len(fc.Args) > 0 { + e.pushErr(fc.Args[1].Token, LogMsg.ArgumentOverflow, "Line") + } + mut constant := Const.NewI64(i64(fc.Token.Row)) + ret &Data{ + Kind: primInt, + Constant: constant, + Model: constant, + } } fn builtinCallerStdComptimeFile(mut &e: &Eval, mut &fc: &FnCallExpr, mut &_: &Data): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[1].Token, LogMsg.ArgumentOverflow, "File") - } - ret &Data{ - Kind: &TypeKind{ - Kind: &comptimeFile{ - file: e.s.file, - }, - }, - } + if len(fc.Args) > 0 { + e.pushErr(fc.Args[1].Token, LogMsg.ArgumentOverflow, "File") + } + ret &Data{ + Kind: &TypeKind{ + Kind: &comptimeFile{ + file: e.s.file, + }, + }, + } } fn builtinCallerStdComptimeFiles(mut &e: &Eval, mut &fc: &FnCallExpr, mut &_: &Data): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[1].Token, LogMsg.ArgumentOverflow, "Files") - } - ret &Data{ - Kind: &TypeKind{ - Kind: &comptimeFiles{ - files: e.s.files, - }, - }, - } + if len(fc.Args) > 0 { + e.pushErr(fc.Args[1].Token, LogMsg.ArgumentOverflow, "Files") + } + ret &Data{ + Kind: &TypeKind{ + Kind: &comptimeFiles{ + files: e.s.files, + }, + }, + } } fn builtinCallerStdComptimeTypeAlias(mut &e: &Eval, mut &fc: &FnCallExpr, mut &_: &Data): &Data { - if len(fc.Args) > 2 { - e.pushErr(fc.Args[1].Token, LogMsg.ArgumentOverflow, "TypeAlias") - ret nil - } - if len(fc.Args) == 0 { - e.pushErr(fc.Token, LogMsg.MissingExprFor, "ident, type") - ret nil - } - if len(fc.Args) == 1 { - e.pushErr(fc.Token, LogMsg.MissingExprFor, "type") - ret nil - } - match type fc.Args[0].Kind { - | &IdentExpr: - break - |: - e.pushErr(fc.Args[0].Token, LogMsg.InvalidSyntax) - e.pushSuggestion(LogMsg.ExpectedIdentifier) - ret nil - } - mut ident := (&IdentExpr)(fc.Args[0].Kind).Token - match type e.lookup { - | &scopeChecker: - break - |: - e.pushErr(fc.Token, LogMsg.CalledOutOfScope, "TypeAlias") - ret nil - } - - mut sc := (&scopeChecker)(e.lookup) - mut alias := &TypeAlias{ - Scope: sc.tree, - Public: mod::IsPub(ident.Kind), - Binded: false, - Used: false, - Generic: false, - Token: ident, - Ident: ident.Kind, - Kind: new(TypeSymbol), - } - mut t := e.eval1(fc.Args[1]) - if t == nil { - ret nil - } - if t.Decl { - alias.Kind.Kind = t.Kind - } else { - mut cti := t.Kind.comptimeTypeInfo() - if cti == nil { - e.pushErr(fc.Args[1].Token, LogMsg.InvalidSyntax) - e.pushSuggestion(LogMsg.ExpectedType) - ret nil - } - alias.Kind.Kind = cti.base - } - sc.checkTypeAlias(alias) - ret buildVoidData() + if len(fc.Args) > 2 { + e.pushErr(fc.Args[1].Token, LogMsg.ArgumentOverflow, "TypeAlias") + ret nil + } + if len(fc.Args) == 0 { + e.pushErr(fc.Token, LogMsg.MissingExprFor, "ident, type") + ret nil + } + if len(fc.Args) == 1 { + e.pushErr(fc.Token, LogMsg.MissingExprFor, "type") + ret nil + } + match type fc.Args[0].Kind { + | &IdentExpr: + break + |: + e.pushErr(fc.Args[0].Token, LogMsg.InvalidSyntax) + e.pushSuggestion(LogMsg.ExpectedIdentifier) + ret nil + } + mut ident := (&IdentExpr)(fc.Args[0].Kind).Token + match type e.lookup { + | &scopeChecker: + break + |: + e.pushErr(fc.Token, LogMsg.CalledOutOfScope, "TypeAlias") + ret nil + } + + mut sc := (&scopeChecker)(e.lookup) + mut alias := &TypeAlias{ + Scope: sc.tree, + Public: mod::IsPub(ident.Kind), + Binded: false, + Used: false, + Generic: false, + Token: ident, + Ident: ident.Kind, + Kind: new(TypeSymbol), + } + mut t := e.eval1(fc.Args[1]) + if t == nil { + ret nil + } + if t.Decl { + alias.Kind.Kind = t.Kind + } else { + mut cti := t.Kind.comptimeTypeInfo() + if cti == nil { + e.pushErr(fc.Args[1].Token, LogMsg.InvalidSyntax) + e.pushSuggestion(LogMsg.ExpectedType) + ret nil + } + alias.Kind.Kind = cti.base + } + sc.checkTypeAlias(alias) + ret buildVoidData() } fn builtinCallerStdMemSizeOf(mut &e: &Eval, mut &fc: &FnCallExpr, mut &_: &Data): &Data { - mut result := &Data{ - Kind: primUint, - } - - if len(fc.Args) < 1 { - e.pushErr(fc.Token, LogMsg.MissingExprFor, "type|expr") - ret result - } - if len(fc.Args) > 1 { - e.pushErr(fc.Args[1].Token, LogMsg.ArgumentOverflow, "SizeOf") - } - - mut d := e.evalExprKind(fc.Args[0].Kind) - if d == nil { - ret result - } - if !validTypeForXof(d.Kind) { - e.pushErr(fc.Args[0].Token, LogMsg.InvalidTypeForFn, d.Kind.Str(), "SizeOf") - } - - result.Model = &SizeofExprModel{Expr: d.Model} - ret result + mut result := &Data{ + Kind: primUint, + } + + if len(fc.Args) < 1 { + e.pushErr(fc.Token, LogMsg.MissingExprFor, "type|expr") + ret result + } + if len(fc.Args) > 1 { + e.pushErr(fc.Args[1].Token, LogMsg.ArgumentOverflow, "SizeOf") + } + + mut d := e.evalExprKind(fc.Args[0].Kind) + if d == nil { + ret result + } + if !validTypeForXof(d.Kind) { + e.pushErr(fc.Args[0].Token, LogMsg.InvalidTypeForFn, d.Kind.Str(), "SizeOf") + } + + result.Model = &SizeofExprModel{Expr: d.Model} + ret result } fn builtinCallerStdMemAlignOf(mut &e: &Eval, mut &fc: &FnCallExpr, mut &_: &Data): &Data { - mut result := &Data{ - Kind: primUint, - } - - if len(fc.Args) < 1 { - e.pushErr(fc.Token, LogMsg.MissingExprFor, "type|expr") - ret result - } - if len(fc.Args) > 1 { - e.pushErr(fc.Args[1].Token, LogMsg.ArgumentOverflow, "AlignOf") - } - - mut d := e.evalExprKind(fc.Args[0].Kind) - if d == nil { - ret result - } - if !validTypeForXof(d.Kind) { - e.pushErr(fc.Args[0].Token, LogMsg.InvalidTypeForFn, d.Kind.Str(), "AlignOf") - } - - result.Model = &AlignofExprModel{Expr: d.Model} - ret result + mut result := &Data{ + Kind: primUint, + } + + if len(fc.Args) < 1 { + e.pushErr(fc.Token, LogMsg.MissingExprFor, "type|expr") + ret result + } + if len(fc.Args) > 1 { + e.pushErr(fc.Args[1].Token, LogMsg.ArgumentOverflow, "AlignOf") + } + + mut d := e.evalExprKind(fc.Args[0].Kind) + if d == nil { + ret result + } + if !validTypeForXof(d.Kind) { + e.pushErr(fc.Args[0].Token, LogMsg.InvalidTypeForFn, d.Kind.Str(), "AlignOf") + } + + result.Model = &AlignofExprModel{Expr: d.Model} + ret result } fn builtinCallerStdMemFree(mut &e: &Eval, mut &fc: &FnCallExpr, mut &_: &Data): &Data { - if len(fc.Args) < 1 { - e.pushErr(fc.Token, LogMsg.MissingExprFor, "h") - ret nil - } - if len(fc.Args) > 1 { - e.pushErr(fc.Args[1].Token, LogMsg.ArgumentOverflow, "Free") - } - - mut d := e.evalExpr(fc.Args[0]) - if d == nil { - ret nil - } - - if !d.Kind.PerformsRC() { - e.pushErr(fc.Args[0].Token, LogMsg.InvalidExpr) - } - - mut result := buildVoidData() - result.Model = &FreeExprModel{Expr: d.Model} - ret result + if len(fc.Args) < 1 { + e.pushErr(fc.Token, LogMsg.MissingExprFor, "h") + ret nil + } + if len(fc.Args) > 1 { + e.pushErr(fc.Args[1].Token, LogMsg.ArgumentOverflow, "Free") + } + + mut d := e.evalExpr(fc.Args[0]) + if d == nil { + ret nil + } + + if !d.Kind.PerformsRC() { + e.pushErr(fc.Args[0].Token, LogMsg.InvalidExpr) + } + + mut result := buildVoidData() + result.Model = &FreeExprModel{Expr: d.Model} + ret result } fn builtinCallerStdJuleIntegratedToStr(mut &e: &Eval, mut &fc: &FnCallExpr, mut &_: &Data): &Data { - if len(fc.Args) < 1 { - e.pushErr(fc.Token, LogMsg.MissingExprFor, "expr") - ret nil - } - if len(fc.Args) > 1 { - e.pushErr(fc.Args[1].Token, LogMsg.ArgumentOverflow, "ToStr") - } - - mut d := e.evalExpr(fc.Args[0]) - if d == nil { - ret nil - } - - if !isBuiltinStrConvertable(d.Kind) { - e.pushErr(fc.Args[0].Token, LogMsg.InvalidExpr) - ret nil - } - - ret &Data{ - Kind: primStr, - Model: &IntegratedToStrExprModel{ - Expr: d.Model, - }, - } + if len(fc.Args) < 1 { + e.pushErr(fc.Token, LogMsg.MissingExprFor, "expr") + ret nil + } + if len(fc.Args) > 1 { + e.pushErr(fc.Args[1].Token, LogMsg.ArgumentOverflow, "ToStr") + } + + mut d := e.evalExpr(fc.Args[0]) + if d == nil { + ret nil + } + + if !isBuiltinStrConvertable(d.Kind) { + e.pushErr(fc.Args[0].Token, LogMsg.InvalidExpr) + ret nil + } + + ret &Data{ + Kind: primStr, + Model: &IntegratedToStrExprModel{ + Expr: d.Model, + }, + } } fn builtinCallerStdJuleIntegratedEmit(mut &e: &Eval, mut &fc: &FnCallExpr, mut &d: &Data): &Data { - if !e.isUnsafe() { - e.pushErr(fc.Token, LogMsg.UnsafeBehaviorAtOutOfUnsafeScope) - } - - if len(fc.Args) < 1 { - e.pushErr(fc.Token, LogMsg.MissingExprFor, "code") - ret nil - } - - mut argd := e.evalExpr(fc.Args[0]) - if argd == nil { - ret nil - } - - if argd.Kind.Prim() == nil || !argd.Kind.Prim().IsStr() { - e.pushErr(fc.Args[0].Token, LogMsg.IncompatibleTypes, PrimKind.Str, argd.Kind.Str()) - ret nil - } - - if !argd.IsConst() || !argd.Constant.IsStr() { - e.pushErr(fc.Args[0].Token, LogMsg.ExprNotConst) - ret nil - } - - mut r := buildVoidData() - - mut f := d.Kind.Fn() - if len(f.Generics) > 0 { - r.Kind = f.Generics[0].Kind - } - - mut model := &BackendEmitExprModel{ - Code: argd.Constant.ReadStr(), - } - - if len(fc.Args) > 1 { - model.Exprs = make([]ExprModel, 0, len(fc.Args) - 1) - for (_, mut arg) in fc.Args[1:] { - argd = e.eval1(arg) - if argd == nil { - ret nil - } - model.Exprs = append(model.Exprs, argd.Model) - } - } - - r.Model = model - ret r + if !e.isUnsafe() { + e.pushErr(fc.Token, LogMsg.UnsafeBehaviorAtOutOfUnsafeScope) + } + + if len(fc.Args) < 1 { + e.pushErr(fc.Token, LogMsg.MissingExprFor, "code") + ret nil + } + + mut argd := e.evalExpr(fc.Args[0]) + if argd == nil { + ret nil + } + + if argd.Kind.Prim() == nil || !argd.Kind.Prim().IsStr() { + e.pushErr(fc.Args[0].Token, LogMsg.IncompatibleTypes, PrimKind.Str, argd.Kind.Str()) + ret nil + } + + if !argd.IsConst() || !argd.Constant.IsStr() { + e.pushErr(fc.Args[0].Token, LogMsg.ExprNotConst) + ret nil + } + + mut r := buildVoidData() + + mut f := d.Kind.Fn() + if len(f.Generics) > 0 { + r.Kind = f.Generics[0].Kind + } + + mut model := &BackendEmitExprModel{ + Code: argd.Constant.ReadStr(), + } + + if len(fc.Args) > 1 { + model.Exprs = make([]ExprModel, 0, len(fc.Args) - 1) + for (_, mut arg) in fc.Args[1:] { + argd = e.eval1(arg) + if argd == nil { + ret nil + } + model.Exprs = append(model.Exprs, argd.Model) + } + } + + r.Model = model + ret r } fn builtinCallerStdDebugOut(mut &e: &Eval, mut &fc: &FnCallExpr, mut &d: &Data): &Data { - d = builtinCallerOut(e, fc, d) - if d == nil { - ret nil - } - (&BuiltinOutCallExprModel)(d.Model).Debug = true - ret d + d = builtinCallerOut(e, fc, d) + if d == nil { + ret nil + } + (&BuiltinOutCallExprModel)(d.Model).Debug = true + ret d } fn builtinCallerStdDebugOutln(mut &e: &Eval, mut &fc: &FnCallExpr, mut &d: &Data): &Data { - d = builtinCallerOutln(e, fc, d) - if d == nil { - ret nil - } - (&BuiltinOutlnCallExprModel)(d.Model).Debug = true - ret d + d = builtinCallerOutln(e, fc, d) + if d == nil { + ret nil + } + (&BuiltinOutlnCallExprModel)(d.Model).Debug = true + ret d } \ No newline at end of file diff --git a/std/jule/sema/comptime.jule b/std/jule/sema/comptime.jule index b7796735a..1ca3e9025 100644 --- a/std/jule/sema/comptime.jule +++ b/std/jule/sema/comptime.jule @@ -11,1441 +11,1441 @@ use types for std::jule::types // All comptime-structure methods starts with underscore (_). struct comptimeMatch { - data: &Data - exprToken: &Token + data: &Data + exprToken: &Token } impl Kind for comptimeMatch { - fn Str(self): str { ret "comptimeMatch" } - fn Equal(&self, other: &TypeKind): bool { ret false } + fn Str(self): str { ret "comptimeMatch" } + fn Equal(&self, other: &TypeKind): bool { ret false } } trait comptimeRangeKind { - fn ready(mut self, mut &keyA: &Var, mut &keyB: &Var) - fn step(mut self, i: int, mut &keyA: &Var, mut &keyB: &Var) - fn len(self): int + fn ready(mut self, mut &keyA: &Var, mut &keyB: &Var) + fn step(mut self, i: int, mut &keyA: &Var, mut &keyB: &Var) + fn len(self): int } // Compile-time ranges. struct comptimeRange { - kind: comptimeRangeKind + kind: comptimeRangeKind } impl Kind for comptimeRange { - fn Str(self): str { ret "comptimeRange" } - fn Equal(&self, other: &TypeKind): bool { ret false } + fn Str(self): str { ret "comptimeRange" } + fn Equal(&self, other: &TypeKind): bool { ret false } } // Compile-time field for structure. struct comptimeStructField { - field: &FieldIns + field: &FieldIns } impl Kind for comptimeStructField { - fn Str(self): str { ret "comptimeStructField" } - fn Equal(&self, other: &TypeKind): bool { ret false } + fn Str(self): str { ret "comptimeStructField" } + fn Equal(&self, other: &TypeKind): bool { ret false } } impl comptimeStructField { - fn _Name(&self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Name") - ret nil - } - mut constant := Const.NewStr(self.field.Decl.Ident) - ret &Data{ - Kind: primStr, - Constant: constant, - Model: constant, - } - } - - fn _Type(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Type") - ret nil - } - ret buildComptimeTypeInfoData(e.s, self.field.Kind) - } - - fn _Public(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Public") - ret nil - } - mut constant := Const.NewBool(self.field.Decl.Public) - ret &Data{ - Kind: primBool, - Constant: constant, - Model: constant, - } - } - - fn subIdent(mut &self, &ident: str): &Data { - match ident { - | "Name": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Name(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - | "Public": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Public(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - | "Type": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Type(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - |: - ret nil - } - } + fn _Name(&self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Name") + ret nil + } + mut constant := Const.NewStr(self.field.Decl.Ident) + ret &Data{ + Kind: primStr, + Constant: constant, + Model: constant, + } + } + + fn _Type(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Type") + ret nil + } + ret buildComptimeTypeInfoData(e.s, self.field.Kind) + } + + fn _Public(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Public") + ret nil + } + mut constant := Const.NewBool(self.field.Decl.Public) + ret &Data{ + Kind: primBool, + Constant: constant, + Model: constant, + } + } + + fn subIdent(mut &self, &ident: str): &Data { + match ident { + | "Name": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Name(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + | "Public": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Public(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + | "Type": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Type(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + |: + ret nil + } + } } // Compile-time fields range for structure. struct comptimeStructFields { - fields: []&FieldIns + fields: []&FieldIns } impl Kind for comptimeStructFields { - fn Str(self): str { ret "comptimeStructFields" } - fn Equal(&self, other: &TypeKind): bool { ret false } + fn Str(self): str { ret "comptimeStructFields" } + fn Equal(&self, other: &TypeKind): bool { ret false } } impl comptimeRangeKind for comptimeStructFields { - fn ready(mut self, mut &keyA: &Var, mut &keyB: &Var) { - if keyA != nil { - keyA.Constant = true - keyA.Value = &Value{ - Data: new(Data), - } - keyA.Kind = findBuiltinTypeAlias(PrimKind.Int).Kind - } - if keyB != nil { - keyB.Constant = true - keyB.Value = &Value{ - Data: new(Data), - } - keyB.Kind = &TypeSymbol{ - Kind: &TypeKind{ - Kind: new(comptimeStructField), - }, - } - } - } - - fn step(mut self, i: int, mut &keyA: &Var, mut &keyB: &Var) { - if keyA != nil { - // Kind should be assigned by caller. - keyA.Value.Data.Constant = Const.NewI64(i64(i)) - keyA.Value.Data.Model = keyA.Value.Data.Constant - } - if keyB != nil { - // Kind should be assigned by caller. - keyB.Kind.Kind.comptimeStructField().field = self.fields[i] - } - } - - fn len(self): int { - ret len(self.fields) - } + fn ready(mut self, mut &keyA: &Var, mut &keyB: &Var) { + if keyA != nil { + keyA.Constant = true + keyA.Value = &Value{ + Data: new(Data), + } + keyA.Kind = findBuiltinTypeAlias(PrimKind.Int).Kind + } + if keyB != nil { + keyB.Constant = true + keyB.Value = &Value{ + Data: new(Data), + } + keyB.Kind = &TypeSymbol{ + Kind: &TypeKind{ + Kind: new(comptimeStructField), + }, + } + } + } + + fn step(mut self, i: int, mut &keyA: &Var, mut &keyB: &Var) { + if keyA != nil { + // Kind should be assigned by caller. + keyA.Value.Data.Constant = Const.NewI64(i64(i)) + keyA.Value.Data.Model = keyA.Value.Data.Constant + } + if keyB != nil { + // Kind should be assigned by caller. + keyB.Kind.Kind.comptimeStructField().field = self.fields[i] + } + } + + fn len(self): int { + ret len(self.fields) + } } // Compile-time static field for structure. struct comptimeStatic { - field: &Var + field: &Var } impl Kind for comptimeStatic { - fn Str(self): str { ret "comptimeStatic" } - fn Equal(&self, other: &TypeKind): bool { ret false } + fn Str(self): str { ret "comptimeStatic" } + fn Equal(&self, other: &TypeKind): bool { ret false } } impl comptimeStatic { - fn _Name(&self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Name") - ret nil - } - mut constant := Const.NewStr(self.field.Ident) - ret &Data{ - Kind: primStr, - Constant: constant, - Model: constant, - } - } - - fn _Type(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Type") - ret nil - } - ret buildComptimeTypeInfoData(e.s, self.field.Kind.Kind) - } - - fn _Public(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Public") - ret nil - } - mut constant := Const.NewBool(self.field.Public) - ret &Data{ - Kind: primBool, - Constant: constant, - Model: constant, - } - } - - fn subIdent(mut &self, &ident: str): &Data { - match ident { - | "Name": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Name(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - | "Public": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Public(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - | "Type": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Type(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - |: - ret nil - } - } + fn _Name(&self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Name") + ret nil + } + mut constant := Const.NewStr(self.field.Ident) + ret &Data{ + Kind: primStr, + Constant: constant, + Model: constant, + } + } + + fn _Type(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Type") + ret nil + } + ret buildComptimeTypeInfoData(e.s, self.field.Kind.Kind) + } + + fn _Public(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Public") + ret nil + } + mut constant := Const.NewBool(self.field.Public) + ret &Data{ + Kind: primBool, + Constant: constant, + Model: constant, + } + } + + fn subIdent(mut &self, &ident: str): &Data { + match ident { + | "Name": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Name(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + | "Public": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Public(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + | "Type": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Type(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + |: + ret nil + } + } } // Compile-time static fields range for structure. struct comptimeStatics { - fields: []&Var + fields: []&Var } impl Kind for comptimeStatics { - fn Str(self): str { ret "comptimeStatics" } - fn Equal(&self, other: &TypeKind): bool { ret false } + fn Str(self): str { ret "comptimeStatics" } + fn Equal(&self, other: &TypeKind): bool { ret false } } impl comptimeRangeKind for comptimeStatics { - fn ready(mut self, mut &keyA: &Var, mut &keyB: &Var) { - if keyA != nil { - keyA.Constant = true - keyA.Value = &Value{ - Data: new(Data), - } - keyA.Kind = findBuiltinTypeAlias(PrimKind.Int).Kind - } - if keyB != nil { - keyB.Constant = true - keyB.Value = &Value{ - Data: new(Data), - } - keyB.Kind = &TypeSymbol{ - Kind: &TypeKind{ - Kind: new(comptimeStatic), - }, - } - } - } - - fn step(mut self, i: int, mut &keyA: &Var, mut &keyB: &Var) { - if keyA != nil { - // Kind should be assigned by caller. - keyA.Value.Data.Constant = Const.NewI64(i64(i)) - keyA.Value.Data.Model = keyA.Value.Data.Constant - } - if keyB != nil { - // Kind should be assigned by caller. - keyB.Kind.Kind.comptimeStatic().field = self.fields[i] - } - } - - fn len(self): int { - ret len(self.fields) - } + fn ready(mut self, mut &keyA: &Var, mut &keyB: &Var) { + if keyA != nil { + keyA.Constant = true + keyA.Value = &Value{ + Data: new(Data), + } + keyA.Kind = findBuiltinTypeAlias(PrimKind.Int).Kind + } + if keyB != nil { + keyB.Constant = true + keyB.Value = &Value{ + Data: new(Data), + } + keyB.Kind = &TypeSymbol{ + Kind: &TypeKind{ + Kind: new(comptimeStatic), + }, + } + } + } + + fn step(mut self, i: int, mut &keyA: &Var, mut &keyB: &Var) { + if keyA != nil { + // Kind should be assigned by caller. + keyA.Value.Data.Constant = Const.NewI64(i64(i)) + keyA.Value.Data.Model = keyA.Value.Data.Constant + } + if keyB != nil { + // Kind should be assigned by caller. + keyB.Kind.Kind.comptimeStatic().field = self.fields[i] + } + } + + fn len(self): int { + ret len(self.fields) + } } // Compile-time field for enum. struct comptimeEnumField { - field: &EnumItem + field: &EnumItem } impl Kind for comptimeEnumField { - fn Str(self): str { ret "comptimeEnumField" } - fn Equal(&self, other: &TypeKind): bool { ret false } + fn Str(self): str { ret "comptimeEnumField" } + fn Equal(&self, other: &TypeKind): bool { ret false } } impl comptimeEnumField { - fn _Name(&self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Name") - ret nil - } - mut constant := Const.NewStr(self.field.Ident) - ret &Data{ - Kind: primStr, - Constant: constant, - Model: constant, - } - } - - fn subIdent(mut &self, &ident: str): &Data { - match ident { - | "Name": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Name(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - |: - ret nil - } - } + fn _Name(&self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Name") + ret nil + } + mut constant := Const.NewStr(self.field.Ident) + ret &Data{ + Kind: primStr, + Constant: constant, + Model: constant, + } + } + + fn subIdent(mut &self, &ident: str): &Data { + match ident { + | "Name": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Name(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + |: + ret nil + } + } } // Compile-time fields range for enum. struct comptimeEnumFields { - fields: []&EnumItem + fields: []&EnumItem } impl Kind for comptimeEnumFields { - fn Str(self): str { ret "comptimeEnumFields" } - fn Equal(&self, other: &TypeKind): bool { ret false } + fn Str(self): str { ret "comptimeEnumFields" } + fn Equal(&self, other: &TypeKind): bool { ret false } } impl comptimeRangeKind for comptimeEnumFields { - fn ready(mut self, mut &keyA: &Var, mut &keyB: &Var) { - if keyA != nil { - keyA.Constant = true - keyA.Value = &Value{ - Data: new(Data), - } - keyA.Kind = findBuiltinTypeAlias(PrimKind.Int).Kind - } - if keyB != nil { - keyB.Constant = true - keyB.Value = &Value{ - Data: new(Data), - } - keyB.Kind = &TypeSymbol{ - Kind: &TypeKind{ - Kind: new(comptimeEnumField), - }, - } - } - } - - fn step(mut self, i: int, mut &keyA: &Var, mut &keyB: &Var) { - if keyA != nil { - // Kind should be assigned by caller. - keyA.Value.Data.Constant = Const.NewI64(i64(i)) - keyA.Value.Data.Model = keyA.Value.Data.Constant - } - if keyB != nil { - // Kind should be assigned by caller. - keyB.Kind.Kind.comptimeEnumField().field = self.fields[i] - } - } - - fn len(self): int { - ret len(self.fields) - } + fn ready(mut self, mut &keyA: &Var, mut &keyB: &Var) { + if keyA != nil { + keyA.Constant = true + keyA.Value = &Value{ + Data: new(Data), + } + keyA.Kind = findBuiltinTypeAlias(PrimKind.Int).Kind + } + if keyB != nil { + keyB.Constant = true + keyB.Value = &Value{ + Data: new(Data), + } + keyB.Kind = &TypeSymbol{ + Kind: &TypeKind{ + Kind: new(comptimeEnumField), + }, + } + } + } + + fn step(mut self, i: int, mut &keyA: &Var, mut &keyB: &Var) { + if keyA != nil { + // Kind should be assigned by caller. + keyA.Value.Data.Constant = Const.NewI64(i64(i)) + keyA.Value.Data.Model = keyA.Value.Data.Constant + } + if keyB != nil { + // Kind should be assigned by caller. + keyB.Kind.Kind.comptimeEnumField().field = self.fields[i] + } + } + + fn len(self): int { + ret len(self.fields) + } } // Compile-time parameter for functions. struct comptimeParam { - param: &ParamIns + param: &ParamIns } impl Kind for comptimeParam { - fn Str(self): str { ret "comptimeParam" } - fn Equal(&self, other: &TypeKind): bool { ret false } + fn Str(self): str { ret "comptimeParam" } + fn Equal(&self, other: &TypeKind): bool { ret false } } impl comptimeParam { - fn _Name(&self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Name") - ret nil - } - mut constant := Const.NewStr(self.param.Decl.Ident) - ret &Data{ - Kind: primStr, - Constant: constant, - Model: constant, - } - } - - fn _Type(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Type") - ret nil - } - ret buildComptimeTypeInfoData(e.s, self.param.Kind) - } - - fn _Variadic(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Variadic") - ret nil - } - mut constant := Const.NewBool(self.param.Decl.Variadic) - ret &Data{ - Kind: primBool, - Constant: constant, - Model: constant, - } - } - - fn _Reference(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Reference") - ret nil - } - mut constant := Const.NewBool(self.param.Decl.Reference) - ret &Data{ - Kind: primBool, - Constant: constant, - Model: constant, - } - } - - fn subIdent(mut &self, &ident: str): &Data { - match ident { - | "Name": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Name(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - | "Variadic": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Variadic(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - | "Reference": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Reference(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - | "Type": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Type(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - |: - ret nil - } - } + fn _Name(&self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Name") + ret nil + } + mut constant := Const.NewStr(self.param.Decl.Ident) + ret &Data{ + Kind: primStr, + Constant: constant, + Model: constant, + } + } + + fn _Type(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Type") + ret nil + } + ret buildComptimeTypeInfoData(e.s, self.param.Kind) + } + + fn _Variadic(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Variadic") + ret nil + } + mut constant := Const.NewBool(self.param.Decl.Variadic) + ret &Data{ + Kind: primBool, + Constant: constant, + Model: constant, + } + } + + fn _Reference(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Reference") + ret nil + } + mut constant := Const.NewBool(self.param.Decl.Reference) + ret &Data{ + Kind: primBool, + Constant: constant, + Model: constant, + } + } + + fn subIdent(mut &self, &ident: str): &Data { + match ident { + | "Name": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Name(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + | "Variadic": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Variadic(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + | "Reference": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Reference(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + | "Type": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Type(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + |: + ret nil + } + } } // Compile-time parameters range for function. struct comptimeParams { - params: []&ParamIns + params: []&ParamIns } impl Kind for comptimeParams { - fn Str(self): str { ret "comptimeParams" } - fn Equal(&self, other: &TypeKind): bool { ret false } + fn Str(self): str { ret "comptimeParams" } + fn Equal(&self, other: &TypeKind): bool { ret false } } impl comptimeRangeKind for comptimeParams { - fn ready(mut self, mut &keyA: &Var, mut &keyB: &Var) { - if keyA != nil { - keyA.Constant = true - keyA.Value = &Value{ - Data: new(Data), - } - keyA.Kind = findBuiltinTypeAlias(PrimKind.Int).Kind - } - if keyB != nil { - keyB.Constant = true - keyB.Value = &Value{ - Data: new(Data), - } - keyB.Kind = &TypeSymbol{ - Kind: &TypeKind{ - Kind: new(comptimeParam), - }, - } - } - } - - fn step(mut self, i: int, mut &keyA: &Var, mut &keyB: &Var) { - if keyA != nil { - // Kind should be assigned by caller. - keyA.Value.Data.Constant = Const.NewI64(i64(i)) - keyA.Value.Data.Model = keyA.Value.Data.Constant - } - if keyB != nil { - // Kind should be assigned by caller. - keyB.Kind.Kind.comptimeParam().param = self.params[i] - } - } - - fn len(self): int { - ret len(self.params) - } + fn ready(mut self, mut &keyA: &Var, mut &keyB: &Var) { + if keyA != nil { + keyA.Constant = true + keyA.Value = &Value{ + Data: new(Data), + } + keyA.Kind = findBuiltinTypeAlias(PrimKind.Int).Kind + } + if keyB != nil { + keyB.Constant = true + keyB.Value = &Value{ + Data: new(Data), + } + keyB.Kind = &TypeSymbol{ + Kind: &TypeKind{ + Kind: new(comptimeParam), + }, + } + } + } + + fn step(mut self, i: int, mut &keyA: &Var, mut &keyB: &Var) { + if keyA != nil { + // Kind should be assigned by caller. + keyA.Value.Data.Constant = Const.NewI64(i64(i)) + keyA.Value.Data.Model = keyA.Value.Data.Constant + } + if keyB != nil { + // Kind should be assigned by caller. + keyB.Kind.Kind.comptimeParam().param = self.params[i] + } + } + + fn len(self): int { + ret len(self.params) + } } // Compile-time type info range. struct comptimeTypeInfos { - types: []&comptimeTypeInfo + types: []&comptimeTypeInfo } impl Kind for comptimeTypeInfos { - fn Str(self): str { ret "comptimeTypeInfos" } - fn Equal(&self, other: &TypeKind): bool { ret false } + fn Str(self): str { ret "comptimeTypeInfos" } + fn Equal(&self, other: &TypeKind): bool { ret false } } impl comptimeRangeKind for comptimeTypeInfos { - fn ready(mut self, mut &keyA: &Var, mut &keyB: &Var) { - if keyA != nil { - keyA.Constant = true - keyA.Value = &Value{ - Data: new(Data), - } - keyA.Kind = findBuiltinTypeAlias(PrimKind.Int).Kind - } - if keyB != nil { - keyB.Constant = true - keyB.Value = &Value{ - Data: new(Data), - } - keyB.Kind = &TypeSymbol{ - Kind: &TypeKind{ - Kind: new(comptimeTypeInfo), - }, - } - } - } - - fn step(mut self, i: int, mut &keyA: &Var, mut &keyB: &Var) { - if keyA != nil { - // Kind should be assigned by caller. - keyA.Value.Data.Constant = Const.NewI64(i64(i)) - keyA.Value.Data.Model = keyA.Value.Data.Constant - } - if keyB != nil { - // Kind should be assigned by caller. - keyB.Kind.Kind.Kind = self.types[i] - } - } - - fn len(self): int { - ret len(self.types) - } + fn ready(mut self, mut &keyA: &Var, mut &keyB: &Var) { + if keyA != nil { + keyA.Constant = true + keyA.Value = &Value{ + Data: new(Data), + } + keyA.Kind = findBuiltinTypeAlias(PrimKind.Int).Kind + } + if keyB != nil { + keyB.Constant = true + keyB.Value = &Value{ + Data: new(Data), + } + keyB.Kind = &TypeSymbol{ + Kind: &TypeKind{ + Kind: new(comptimeTypeInfo), + }, + } + } + } + + fn step(mut self, i: int, mut &keyA: &Var, mut &keyB: &Var) { + if keyA != nil { + // Kind should be assigned by caller. + keyA.Value.Data.Constant = Const.NewI64(i64(i)) + keyA.Value.Data.Model = keyA.Value.Data.Constant + } + if keyB != nil { + // Kind should be assigned by caller. + keyB.Kind.Kind.Kind = self.types[i] + } + } + + fn len(self): int { + ret len(self.types) + } } // Compile-time type information data. struct comptimeTypeInfo { - base: &TypeKind + base: &TypeKind } impl Kind for comptimeTypeInfo { - fn Str(self): str { ret "comptimeTypeInfo[" + self.base.Str() + "]" } - fn Equal(&self, other: &TypeKind): bool { ret false } + fn Str(self): str { ret "comptimeTypeInfo[" + self.base.Str() + "]" } + fn Equal(&self, other: &TypeKind): bool { ret false } } impl comptimeTypeInfo { - fn _Str(&self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Str") - ret nil - } - mut constant := Const.NewStr(self.base.Str()) - ret &Data{ - Kind: primStr, - Constant: constant, - Model: constant, - } - } - - fn _Kind(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Kind") - ret nil - } - mut enm := findComptimePackage(e.s).FindEnum("Kind") - let mut item: &EnumItem = nil - match { - | self.base.Void(): - item = enm.FindItem("Void") - | self.base.Struct() != nil: - item = enm.FindItem("Struct") - | self.base.Trait() != nil: - item = enm.FindItem("Trait") - | self.base.Ptr() != nil: - if self.base.Ptr().IsUnsafe() { - item = enm.FindItem("UnsafePtr") - } else { - item = enm.FindItem("Ptr") - } - | self.base.Sptr() != nil: - item = enm.FindItem("SmartPtr") - | self.base.Enum() != nil: - item = enm.FindItem("Enum") - | self.base.Map() != nil: - item = enm.FindItem("Map") - | self.base.Slc() != nil: - item = enm.FindItem("Slice") - | self.base.Arr() != nil: - item = enm.FindItem("Array") - | self.base.Fn() != nil: - item = enm.FindItem("Func") - | self.base.Tup() != nil: - item = enm.FindItem("Tuple") - | self.base.Prim() != nil: - prim := self.base.Prim() - match { - | prim.IsAny(): - item = enm.FindItem("Any") - | prim.IsBool(): - item = enm.FindItem("Bool") - | prim.IsStr(): - item = enm.FindItem("Str") - | prim.IsF32(): - item = enm.FindItem("F32") - | prim.IsF64(): - item = enm.FindItem("F64") - | prim.IsI8(): - item = enm.FindItem("I8") - | prim.IsI16(): - item = enm.FindItem("I16") - | prim.IsI32(): - item = enm.FindItem("I32") - | prim.IsI64(): - item = enm.FindItem("I64") - | prim.IsU8(): - item = enm.FindItem("U8") - | prim.IsU16(): - item = enm.FindItem("U16") - | prim.IsU32(): - item = enm.FindItem("U32") - | prim.IsU64(): - item = enm.FindItem("U64") - | prim.IsInt(): - item = enm.FindItem("Int") - | prim.IsUint(): - item = enm.FindItem("Uint") - | prim.IsUintptr(): - item = enm.FindItem("Uintptr") - |: - panic("Kind(): unimplemented type for std::comptime: " + self.base.Str()) - } - |: - panic("Kind(): unimplemented type for std::comptime: " + self.base.Str()) - } - ret evalEnumStatic(enm, item, fc.Token) - } - - fn _Bits(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Bits") - ret nil - } - prim := self.base.Prim() - if prim == nil { - e.pushErr(fc.Token, LogMsg.InvalidTypeForFn, self.base.Str(), "Bits") - ret nil - } - n := types::BitsizeOf(prim.Kind) - if n == -1 { - e.pushErr(fc.Token, LogMsg.InvalidTypeForFn, self.base.Str(), "Bits") - ret nil - } - mut constant := Const.NewI64(i64(n)) - ret &Data{ - Kind: primStr, - Constant: constant, - Model: constant, - } - } - - fn _Elem(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Elem") - ret nil - } - mut ptr := self.base.Ptr() - if ptr != nil { - if ptr.IsUnsafe() { - e.pushErr(fc.Token, LogMsg.InvalidTypeForFn, self.base.Str(), "Elem") - ret nil - } - ret buildComptimeTypeInfoData(e.s, ptr.Elem) - } - mut sptr := self.base.Sptr() - if sptr != nil { - ret buildComptimeTypeInfoData(e.s, sptr.Elem) - } - mut slice := self.base.Slc() - if slice != nil { - ret buildComptimeTypeInfoData(e.s, slice.Elem) - } - mut array := self.base.Arr() - if array != nil { - ret buildComptimeTypeInfoData(e.s, array.Elem) - } - mut enm := self.base.Enum() - if enm != nil { - ret buildComptimeTypeInfoData(e.s, enm.Kind.Kind) - } - e.pushErr(fc.Token, LogMsg.InvalidTypeForFn, self.base.Str(), "Elem") - ret nil - } - - fn _Size(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Size") - ret nil - } - mut arr := self.base.Arr() - if arr == nil { - e.pushErr(fc.Token, LogMsg.InvalidTypeForFn, self.base.Str(), "Size") - ret nil - } - mut constant := Const.NewI64(i64(arr.N)) - ret &Data{ - Kind: primInt, - Constant: constant, - Model: constant, - } - } - - fn _Key(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Key") - ret nil - } - mut m := self.base.Map() - if m == nil { - e.pushErr(fc.Token, LogMsg.InvalidTypeForFn, self.base.Str(), "Key") - ret nil - } - ret buildComptimeTypeInfoData(e.s, m.Key) - } - - fn _Value(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Value") - ret nil - } - mut m := self.base.Map() - if m == nil { - e.pushErr(fc.Token, LogMsg.InvalidTypeForFn, self.base.Str(), "Value") - ret nil - } - ret buildComptimeTypeInfoData(e.s, m.Val) - } - - fn _Fields(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Fields") - ret nil - } - mut s := self.base.Struct() - if s != nil { - ret &Data{ - Kind: &TypeKind{ - Kind: &comptimeStructFields{ - fields: s.Fields, - }, - }, - } - } - mut enm := self.base.Enum() - if enm != nil { - ret &Data{ - Kind: &TypeKind{ - Kind: &comptimeEnumFields{ - fields: enm.Items, - }, - }, - } - } - e.pushErr(fc.Token, LogMsg.InvalidTypeForFn, self.base.Str(), "Fields") - ret nil - } - - fn _Statics(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Statics") - ret nil - } - mut s := self.base.Struct() - if s == nil { - e.pushErr(fc.Token, LogMsg.InvalidTypeForFn, self.base.Str(), "Fields") - ret nil - } - ret &Data{ - Kind: &TypeKind{ - Kind: &comptimeStatics{ - fields: s.Statics, - }, - }, - } - } - - fn _Public(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Public") - ret nil - } - mut public := false - match { - | self.base.Struct() != nil: - public = self.base.Struct().Decl.Public - | self.base.Trait() != nil: - public = self.base.Trait().Public - | self.base.Enum() != nil: - public = self.base.Enum().Public - | self.base.TypeEnum() != nil: - public = self.base.TypeEnum().Public - |: - e.pushErr(fc.Token, LogMsg.InvalidTypeForFn, self.base.Str(), "Public") - ret nil - } - mut constant := Const.NewBool(public) - ret &Data{ - Kind: primBool, - Constant: constant, - Model: constant, - } - } - - fn _Binded(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Binded") - ret nil - } - mut constant := Const.NewBool(self.base.Binded()) - ret &Data{ - Kind: primBool, - Constant: constant, - Model: constant, - } - } - - fn _Ordered(&self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Ordered") - ret nil - } - mut constant := Const.NewBool(self.base.Ordered()) - ret &Data{ - Kind: primStr, - Constant: constant, - Model: constant, - } - } - - fn _Comparable(&self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Comparable") - ret nil - } - mut constant := Const.NewBool(self.base.Comparable()) - ret &Data{ - Kind: primStr, - Constant: constant, - Model: constant, - } - } - - fn _Mutable(&self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Mutable") - ret nil - } - mut constant := Const.NewBool(self.base.Mutable()) - ret &Data{ - Kind: primBool, - Constant: constant, - Model: constant, - } - } - - fn _Types(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Types") - ret nil - } - mut tup := self.base.Tup() - if tup == nil { - e.pushErr(fc.Token, LogMsg.InvalidTypeForFn, self.base.Str(), "Types") - ret nil - } - mut infos := &comptimeTypeInfos{ - types: make([]&comptimeTypeInfo, 0, len(tup.Types)), - } - for (_, mut t) in tup.Types { - infos.types = append(infos.types, e.s.meta.pushComptimeTypeInfo(t)) - } - ret &Data{ - Kind: &TypeKind{ - Kind: infos, - }, - } - } - - fn _Exceptional(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Exceptional") - ret nil - } - mut f := self.base.Fn() - if f == nil { - e.pushErr(fc.Token, LogMsg.InvalidTypeForFn, self.base.Str(), "Exceptional") - ret nil - } - mut constant := Const.NewBool(f.Decl != nil && f.Decl.Exceptional) - ret &Data{ - Kind: primBool, - Constant: constant, - Model: constant, - } - } - - fn _CanNil(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "CanNil") - ret nil - } - mut constant := Const.NewBool(self.base.NilCompatible()) - ret &Data{ - Kind: primBool, - Constant: constant, - Model: constant, - } - } - - fn _RC(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "RC") - ret nil - } - mut constant := Const.NewBool(self.base.PerformsRC()) - ret &Data{ - Kind: primBool, - Constant: constant, - Model: constant, - } - } - - fn _Result(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Result") - ret nil - } - mut f := self.base.Fn() - if f == nil { - e.pushErr(fc.Token, LogMsg.InvalidTypeForFn, self.base.Str(), "Result") - ret nil - } - if f.Result == nil { - ret buildComptimeTypeInfoData(e.s, primVoid) - } - ret buildComptimeTypeInfoData(e.s, f.Result) - } - - fn _Params(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Params") - ret nil - } - mut f := self.base.Fn() - if f == nil { - e.pushErr(fc.Token, LogMsg.InvalidTypeForFn, self.base.Str(), "Params") - ret nil - } - ret &Data{ - Kind: &TypeKind{ - Kind: &comptimeParams{params: f.Params}, - }, - } - } - - fn subIdent(mut &self, &ident: str): &Data { - match ident { - | "Str": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Str(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - | "Bits": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Bits(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - | "Elem": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Elem(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - | "Size": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Size(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - | "Key": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Key(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - | "Value": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Value(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - | "Fields": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Fields(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - | "Statics": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Statics(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - | "Params": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Params(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - | "Types": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Types(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - | "Public": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Public(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - | "Binded": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Binded(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - | "Ordered": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Ordered(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - | "Comparable": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Comparable(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - | "Mutable": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Mutable(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - | "Exceptional": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Exceptional(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - | "CanNil": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._CanNil(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - | "RC": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._RC(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - | "Result": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Result(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - | "Kind": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Kind(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - |: - ret nil - } - } + fn _Str(&self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Str") + ret nil + } + mut constant := Const.NewStr(self.base.Str()) + ret &Data{ + Kind: primStr, + Constant: constant, + Model: constant, + } + } + + fn _Kind(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Kind") + ret nil + } + mut enm := findComptimePackage(e.s).FindEnum("Kind") + let mut item: &EnumItem = nil + match { + | self.base.Void(): + item = enm.FindItem("Void") + | self.base.Struct() != nil: + item = enm.FindItem("Struct") + | self.base.Trait() != nil: + item = enm.FindItem("Trait") + | self.base.Ptr() != nil: + if self.base.Ptr().IsUnsafe() { + item = enm.FindItem("UnsafePtr") + } else { + item = enm.FindItem("Ptr") + } + | self.base.Sptr() != nil: + item = enm.FindItem("SmartPtr") + | self.base.Enum() != nil: + item = enm.FindItem("Enum") + | self.base.Map() != nil: + item = enm.FindItem("Map") + | self.base.Slc() != nil: + item = enm.FindItem("Slice") + | self.base.Arr() != nil: + item = enm.FindItem("Array") + | self.base.Fn() != nil: + item = enm.FindItem("Func") + | self.base.Tup() != nil: + item = enm.FindItem("Tuple") + | self.base.Prim() != nil: + prim := self.base.Prim() + match { + | prim.IsAny(): + item = enm.FindItem("Any") + | prim.IsBool(): + item = enm.FindItem("Bool") + | prim.IsStr(): + item = enm.FindItem("Str") + | prim.IsF32(): + item = enm.FindItem("F32") + | prim.IsF64(): + item = enm.FindItem("F64") + | prim.IsI8(): + item = enm.FindItem("I8") + | prim.IsI16(): + item = enm.FindItem("I16") + | prim.IsI32(): + item = enm.FindItem("I32") + | prim.IsI64(): + item = enm.FindItem("I64") + | prim.IsU8(): + item = enm.FindItem("U8") + | prim.IsU16(): + item = enm.FindItem("U16") + | prim.IsU32(): + item = enm.FindItem("U32") + | prim.IsU64(): + item = enm.FindItem("U64") + | prim.IsInt(): + item = enm.FindItem("Int") + | prim.IsUint(): + item = enm.FindItem("Uint") + | prim.IsUintptr(): + item = enm.FindItem("Uintptr") + |: + panic("Kind(): unimplemented type for std::comptime: " + self.base.Str()) + } + |: + panic("Kind(): unimplemented type for std::comptime: " + self.base.Str()) + } + ret evalEnumStatic(enm, item, fc.Token) + } + + fn _Bits(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Bits") + ret nil + } + prim := self.base.Prim() + if prim == nil { + e.pushErr(fc.Token, LogMsg.InvalidTypeForFn, self.base.Str(), "Bits") + ret nil + } + n := types::BitsizeOf(prim.Kind) + if n == -1 { + e.pushErr(fc.Token, LogMsg.InvalidTypeForFn, self.base.Str(), "Bits") + ret nil + } + mut constant := Const.NewI64(i64(n)) + ret &Data{ + Kind: primStr, + Constant: constant, + Model: constant, + } + } + + fn _Elem(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Elem") + ret nil + } + mut ptr := self.base.Ptr() + if ptr != nil { + if ptr.IsUnsafe() { + e.pushErr(fc.Token, LogMsg.InvalidTypeForFn, self.base.Str(), "Elem") + ret nil + } + ret buildComptimeTypeInfoData(e.s, ptr.Elem) + } + mut sptr := self.base.Sptr() + if sptr != nil { + ret buildComptimeTypeInfoData(e.s, sptr.Elem) + } + mut slice := self.base.Slc() + if slice != nil { + ret buildComptimeTypeInfoData(e.s, slice.Elem) + } + mut array := self.base.Arr() + if array != nil { + ret buildComptimeTypeInfoData(e.s, array.Elem) + } + mut enm := self.base.Enum() + if enm != nil { + ret buildComptimeTypeInfoData(e.s, enm.Kind.Kind) + } + e.pushErr(fc.Token, LogMsg.InvalidTypeForFn, self.base.Str(), "Elem") + ret nil + } + + fn _Size(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Size") + ret nil + } + mut arr := self.base.Arr() + if arr == nil { + e.pushErr(fc.Token, LogMsg.InvalidTypeForFn, self.base.Str(), "Size") + ret nil + } + mut constant := Const.NewI64(i64(arr.N)) + ret &Data{ + Kind: primInt, + Constant: constant, + Model: constant, + } + } + + fn _Key(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Key") + ret nil + } + mut m := self.base.Map() + if m == nil { + e.pushErr(fc.Token, LogMsg.InvalidTypeForFn, self.base.Str(), "Key") + ret nil + } + ret buildComptimeTypeInfoData(e.s, m.Key) + } + + fn _Value(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Value") + ret nil + } + mut m := self.base.Map() + if m == nil { + e.pushErr(fc.Token, LogMsg.InvalidTypeForFn, self.base.Str(), "Value") + ret nil + } + ret buildComptimeTypeInfoData(e.s, m.Val) + } + + fn _Fields(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Fields") + ret nil + } + mut s := self.base.Struct() + if s != nil { + ret &Data{ + Kind: &TypeKind{ + Kind: &comptimeStructFields{ + fields: s.Fields, + }, + }, + } + } + mut enm := self.base.Enum() + if enm != nil { + ret &Data{ + Kind: &TypeKind{ + Kind: &comptimeEnumFields{ + fields: enm.Items, + }, + }, + } + } + e.pushErr(fc.Token, LogMsg.InvalidTypeForFn, self.base.Str(), "Fields") + ret nil + } + + fn _Statics(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Statics") + ret nil + } + mut s := self.base.Struct() + if s == nil { + e.pushErr(fc.Token, LogMsg.InvalidTypeForFn, self.base.Str(), "Fields") + ret nil + } + ret &Data{ + Kind: &TypeKind{ + Kind: &comptimeStatics{ + fields: s.Statics, + }, + }, + } + } + + fn _Public(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Public") + ret nil + } + mut public := false + match { + | self.base.Struct() != nil: + public = self.base.Struct().Decl.Public + | self.base.Trait() != nil: + public = self.base.Trait().Public + | self.base.Enum() != nil: + public = self.base.Enum().Public + | self.base.TypeEnum() != nil: + public = self.base.TypeEnum().Public + |: + e.pushErr(fc.Token, LogMsg.InvalidTypeForFn, self.base.Str(), "Public") + ret nil + } + mut constant := Const.NewBool(public) + ret &Data{ + Kind: primBool, + Constant: constant, + Model: constant, + } + } + + fn _Binded(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Binded") + ret nil + } + mut constant := Const.NewBool(self.base.Binded()) + ret &Data{ + Kind: primBool, + Constant: constant, + Model: constant, + } + } + + fn _Ordered(&self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Ordered") + ret nil + } + mut constant := Const.NewBool(self.base.Ordered()) + ret &Data{ + Kind: primStr, + Constant: constant, + Model: constant, + } + } + + fn _Comparable(&self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Comparable") + ret nil + } + mut constant := Const.NewBool(self.base.Comparable()) + ret &Data{ + Kind: primStr, + Constant: constant, + Model: constant, + } + } + + fn _Mutable(&self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Mutable") + ret nil + } + mut constant := Const.NewBool(self.base.Mutable()) + ret &Data{ + Kind: primBool, + Constant: constant, + Model: constant, + } + } + + fn _Types(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Types") + ret nil + } + mut tup := self.base.Tup() + if tup == nil { + e.pushErr(fc.Token, LogMsg.InvalidTypeForFn, self.base.Str(), "Types") + ret nil + } + mut infos := &comptimeTypeInfos{ + types: make([]&comptimeTypeInfo, 0, len(tup.Types)), + } + for (_, mut t) in tup.Types { + infos.types = append(infos.types, e.s.meta.pushComptimeTypeInfo(t)) + } + ret &Data{ + Kind: &TypeKind{ + Kind: infos, + }, + } + } + + fn _Exceptional(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Exceptional") + ret nil + } + mut f := self.base.Fn() + if f == nil { + e.pushErr(fc.Token, LogMsg.InvalidTypeForFn, self.base.Str(), "Exceptional") + ret nil + } + mut constant := Const.NewBool(f.Decl != nil && f.Decl.Exceptional) + ret &Data{ + Kind: primBool, + Constant: constant, + Model: constant, + } + } + + fn _CanNil(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "CanNil") + ret nil + } + mut constant := Const.NewBool(self.base.NilCompatible()) + ret &Data{ + Kind: primBool, + Constant: constant, + Model: constant, + } + } + + fn _RC(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "RC") + ret nil + } + mut constant := Const.NewBool(self.base.PerformsRC()) + ret &Data{ + Kind: primBool, + Constant: constant, + Model: constant, + } + } + + fn _Result(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Result") + ret nil + } + mut f := self.base.Fn() + if f == nil { + e.pushErr(fc.Token, LogMsg.InvalidTypeForFn, self.base.Str(), "Result") + ret nil + } + if f.Result == nil { + ret buildComptimeTypeInfoData(e.s, primVoid) + } + ret buildComptimeTypeInfoData(e.s, f.Result) + } + + fn _Params(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Params") + ret nil + } + mut f := self.base.Fn() + if f == nil { + e.pushErr(fc.Token, LogMsg.InvalidTypeForFn, self.base.Str(), "Params") + ret nil + } + ret &Data{ + Kind: &TypeKind{ + Kind: &comptimeParams{params: f.Params}, + }, + } + } + + fn subIdent(mut &self, &ident: str): &Data { + match ident { + | "Str": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Str(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + | "Bits": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Bits(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + | "Elem": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Elem(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + | "Size": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Size(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + | "Key": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Key(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + | "Value": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Value(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + | "Fields": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Fields(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + | "Statics": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Statics(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + | "Params": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Params(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + | "Types": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Types(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + | "Public": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Public(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + | "Binded": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Binded(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + | "Ordered": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Ordered(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + | "Comparable": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Comparable(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + | "Mutable": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Mutable(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + | "Exceptional": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Exceptional(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + | "CanNil": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._CanNil(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + | "RC": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._RC(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + | "Result": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Result(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + | "Kind": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Kind(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + |: + ret nil + } + } } // Compile-time value information data. struct comptimeValue { - data: &Data + data: &Data } impl Kind for comptimeValue { - fn Str(self): str { ret "comptimeValue" } - fn Equal(&self, other: &TypeKind): bool { ret false } + fn Str(self): str { ret "comptimeValue" } + fn Equal(&self, other: &TypeKind): bool { ret false } } impl comptimeValue { - fn _Unwrap(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Unwrap") - ret nil - } - ret self.data - } - - fn _Type(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Type") - ret nil - } - ret buildComptimeTypeInfoData(e.s, self.data.Kind) - } - - fn _Lvalue(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Lvalue") - ret nil - } - mut constant := Const.NewBool(self.data.Lvalue) - ret &Data{ - Kind: primBool, - Constant: constant, - Model: constant, - } - } - - fn _Mutable(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Mutable") - ret nil - } - mut constant := Const.NewBool(self.data.Mutable) - ret &Data{ - Kind: primBool, - Constant: constant, - Model: constant, - } - } - - fn _Const(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Const") - ret nil - } - mut constant := Const.NewBool(self.data.IsConst()) - ret &Data{ - Kind: primBool, - Constant: constant, - Model: constant, - } - } - - fn _Field(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 1 { - e.pushErr(fc.Args[1].Token, LogMsg.ArgumentOverflow, "Field") - ret nil - } - mut s := self.data.Kind.Struct() - if s == nil { - e.pushErr(fc.Token, LogMsg.InvalidTypeForFn, self.data.Kind.Str(), "Field") - ret nil - } - mut arg := fc.Args[0] - mut d := e.evalExpr(arg) - if d == nil { - ret nil - } - if !d.IsConst() { - e.pushErr(arg.Token, LogMsg.ExprNotConst) - ret nil - } - prim := d.Kind.Prim() - if prim == nil || !prim.IsStr() { - e.pushErr(arg.Token, LogMsg.IncompatibleTypes, PrimKind.Str, d.Kind.Str()) - ret nil - } - ident := d.Constant.ReadStr() - mut f := s.FindField(ident) - if f == nil { - e.pushErr(arg.Token, LogMsg.ObjHaveNotIdent, s.Decl.Ident, ident) - ret nil - } - d = new(Data, *self.data) - d = e.evalStructSubIdentField(d, s, arg.Token, f) - ret buildComptimeValue(d) - } - - fn subIdent(mut &self, &ident: str): &Data { - match ident { - | "Unwrap": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Unwrap(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - | "Type": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Type(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - | "Lvalue": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Lvalue(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - | "Mutable": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Mutable(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - | "Const": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Const(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - | "Field": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Field(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - |: - ret nil - } - } + fn _Unwrap(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Unwrap") + ret nil + } + ret self.data + } + + fn _Type(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Type") + ret nil + } + ret buildComptimeTypeInfoData(e.s, self.data.Kind) + } + + fn _Lvalue(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Lvalue") + ret nil + } + mut constant := Const.NewBool(self.data.Lvalue) + ret &Data{ + Kind: primBool, + Constant: constant, + Model: constant, + } + } + + fn _Mutable(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Mutable") + ret nil + } + mut constant := Const.NewBool(self.data.Mutable) + ret &Data{ + Kind: primBool, + Constant: constant, + Model: constant, + } + } + + fn _Const(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Const") + ret nil + } + mut constant := Const.NewBool(self.data.IsConst()) + ret &Data{ + Kind: primBool, + Constant: constant, + Model: constant, + } + } + + fn _Field(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 1 { + e.pushErr(fc.Args[1].Token, LogMsg.ArgumentOverflow, "Field") + ret nil + } + mut s := self.data.Kind.Struct() + if s == nil { + e.pushErr(fc.Token, LogMsg.InvalidTypeForFn, self.data.Kind.Str(), "Field") + ret nil + } + mut arg := fc.Args[0] + mut d := e.evalExpr(arg) + if d == nil { + ret nil + } + if !d.IsConst() { + e.pushErr(arg.Token, LogMsg.ExprNotConst) + ret nil + } + prim := d.Kind.Prim() + if prim == nil || !prim.IsStr() { + e.pushErr(arg.Token, LogMsg.IncompatibleTypes, PrimKind.Str, d.Kind.Str()) + ret nil + } + ident := d.Constant.ReadStr() + mut f := s.FindField(ident) + if f == nil { + e.pushErr(arg.Token, LogMsg.ObjHaveNotIdent, s.Decl.Ident, ident) + ret nil + } + d = new(Data, *self.data) + d = e.evalStructSubIdentField(d, s, arg.Token, f) + ret buildComptimeValue(d) + } + + fn subIdent(mut &self, &ident: str): &Data { + match ident { + | "Unwrap": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Unwrap(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + | "Type": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Type(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + | "Lvalue": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Lvalue(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + | "Mutable": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Mutable(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + | "Const": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Const(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + | "Field": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Field(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + |: + ret nil + } + } } // Compile-time file info range. struct comptimeFiles { - files: []&SymbolTable + files: []&SymbolTable } impl Kind for comptimeFiles { - fn Str(self): str { ret "comptimeFiles" } - fn Equal(&self, other: &TypeKind): bool { ret false } + fn Str(self): str { ret "comptimeFiles" } + fn Equal(&self, other: &TypeKind): bool { ret false } } impl comptimeRangeKind for comptimeFiles { - fn ready(mut self, mut &keyA: &Var, mut &keyB: &Var) { - if keyA != nil { - keyA.Constant = true - keyA.Value = &Value{ - Data: new(Data), - } - keyA.Kind = findBuiltinTypeAlias(PrimKind.Int).Kind - } - if keyB != nil { - keyB.Constant = true - keyB.Value = &Value{ - Data: new(Data), - } - keyB.Kind = &TypeSymbol{ - Kind: &TypeKind{ - Kind: new(comptimeFile), - }, - } - } - } - - fn step(mut self, i: int, mut &keyA: &Var, mut &keyB: &Var) { - if keyA != nil { - // Kind should be assigned by caller. - keyA.Value.Data.Constant = Const.NewI64(i64(i)) - keyA.Value.Data.Model = keyA.Value.Data.Constant - } - if keyB != nil { - // Kind should be assigned by caller. - (&comptimeFile)(keyB.Kind.Kind.Kind).file = self.files[i] - } - } - - fn len(self): int { - ret len(self.files) - } + fn ready(mut self, mut &keyA: &Var, mut &keyB: &Var) { + if keyA != nil { + keyA.Constant = true + keyA.Value = &Value{ + Data: new(Data), + } + keyA.Kind = findBuiltinTypeAlias(PrimKind.Int).Kind + } + if keyB != nil { + keyB.Constant = true + keyB.Value = &Value{ + Data: new(Data), + } + keyB.Kind = &TypeSymbol{ + Kind: &TypeKind{ + Kind: new(comptimeFile), + }, + } + } + } + + fn step(mut self, i: int, mut &keyA: &Var, mut &keyB: &Var) { + if keyA != nil { + // Kind should be assigned by caller. + keyA.Value.Data.Constant = Const.NewI64(i64(i)) + keyA.Value.Data.Model = keyA.Value.Data.Constant + } + if keyB != nil { + // Kind should be assigned by caller. + (&comptimeFile)(keyB.Kind.Kind.Kind).file = self.files[i] + } + } + + fn len(self): int { + ret len(self.files) + } } // Compile-time file information data. struct comptimeFile { - file: &SymbolTable + file: &SymbolTable } impl Kind for comptimeFile { - fn Str(self): str { ret "comptimeFile" } - fn Equal(&self, other: &TypeKind): bool { ret false } + fn Str(self): str { ret "comptimeFile" } + fn Equal(&self, other: &TypeKind): bool { ret false } } impl comptimeFile { - fn _Path(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Path") - ret nil - } - mut constant := Const.NewStr(self.file.File.Path) - ret &Data{ - Kind: primStr, - Constant: constant, - Model: constant, - } - } - - fn _Name(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Name") - ret nil - } - mut constant := Const.NewStr(self.file.File.Name()) - ret &Data{ - Kind: primStr, - Constant: constant, - Model: constant, - } - } - - fn _Dir(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { - if len(fc.Args) > 0 { - e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Dir") - ret nil - } - mut constant := Const.NewStr(self.file.File.Dir()) - ret &Data{ - Kind: primStr, - Constant: constant, - Model: constant, - } - } - - fn subIdent(mut &self, &ident: str): &Data { - match ident { - | "Path": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Path(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - | "Name": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Name(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - | "Dir": - mut method := &FnIns{ - caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { - ret self._Dir(e, fc) - }, - } - ret buildAsComptimeMethodData(method) - |: - ret nil - } - } + fn _Path(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Path") + ret nil + } + mut constant := Const.NewStr(self.file.File.Path) + ret &Data{ + Kind: primStr, + Constant: constant, + Model: constant, + } + } + + fn _Name(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Name") + ret nil + } + mut constant := Const.NewStr(self.file.File.Name()) + ret &Data{ + Kind: primStr, + Constant: constant, + Model: constant, + } + } + + fn _Dir(mut &self, mut &e: &Eval, mut &fc: &ast::FnCallExpr): &Data { + if len(fc.Args) > 0 { + e.pushErr(fc.Args[0].Token, LogMsg.ArgumentOverflow, "Dir") + ret nil + } + mut constant := Const.NewStr(self.file.File.Dir()) + ret &Data{ + Kind: primStr, + Constant: constant, + Model: constant, + } + } + + fn subIdent(mut &self, &ident: str): &Data { + match ident { + | "Path": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Path(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + | "Name": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Name(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + | "Dir": + mut method := &FnIns{ + caller: fn(mut &e: &Eval, mut &fc: &ast::FnCallExpr, mut &_: &Data): &Data { + ret self._Dir(e, fc) + }, + } + ret buildAsComptimeMethodData(method) + |: + ret nil + } + } } fn buildAsComptimeMethodData(mut &f: &FnIns): &Data { - ret &Data{ - Kind: &TypeKind{ - Kind: f, - }, - } + ret &Data{ + Kind: &TypeKind{ + Kind: f, + }, + } } fn findComptimePackage(mut &s: &Sema): &ImportInfo { - ret s.SelectPackage(fn(pkg: &ImportInfo): bool { - ret pkg.LinkPath == "std::comptime" - }) + ret s.SelectPackage(fn(pkg: &ImportInfo): bool { + ret pkg.LinkPath == "std::comptime" + }) } fn buildComptimeTypeInfoData(mut &s: &Sema, mut &t: &TypeKind): &Data { - ret &Data{ - Kind: &TypeKind{ - Kind: s.meta.pushComptimeTypeInfo(t), - }, - } + ret &Data{ + Kind: &TypeKind{ + Kind: s.meta.pushComptimeTypeInfo(t), + }, + } } fn buildComptimeValue(mut &d: &Data): &Data { - ret &Data{ - Kind: &TypeKind{ - Kind: &comptimeValue{ - data: d, - }, - }, - } + ret &Data{ + Kind: &TypeKind{ + Kind: &comptimeValue{ + data: d, + }, + }, + } } \ No newline at end of file diff --git a/std/jule/sema/constrait.jule b/std/jule/sema/constrait.jule index 8d16ca6ed..4fc4c5835 100644 --- a/std/jule/sema/constrait.jule +++ b/std/jule/sema/constrait.jule @@ -9,192 +9,192 @@ use types for std::jule::types use std::strings::{StrBuilder} enum builtinConstraint: str { - Signed: "signed", - Unsigned: "unsigned", - Float: "float", - Numeric: "numeric", - Immutable: "immutable", - Mutable: "mutable", - Ordered: "ordered", - Comparable: "comparable", + Signed: "signed", + Unsigned: "unsigned", + Float: "float", + Numeric: "numeric", + Immutable: "immutable", + Mutable: "mutable", + Ordered: "ordered", + Comparable: "comparable", } static builtinConstraints = [ - builtinConstraint.Signed, - builtinConstraint.Unsigned, - builtinConstraint.Float, - builtinConstraint.Numeric, - builtinConstraint.Mutable, - builtinConstraint.Immutable, - builtinConstraint.Ordered, - builtinConstraint.Comparable, + builtinConstraint.Signed, + builtinConstraint.Unsigned, + builtinConstraint.Float, + builtinConstraint.Numeric, + builtinConstraint.Mutable, + builtinConstraint.Immutable, + builtinConstraint.Ordered, + builtinConstraint.Comparable, ] struct constraintChecker { - mut s: &Sema + mut s: &Sema - // Declarations of generics. - mut genericsD: []&GenericDecl + // Declarations of generics. + mut genericsD: []&GenericDecl - // Generics of instance. - mut generics: []&InsGeneric + // Generics of instance. + mut generics: []&InsGeneric - // Type aliases for generics. - // It can be nil if environment is not guaranteed. - // It will be used for guaranteed environments. - mut genericsA: []&TypeAlias + // Type aliases for generics. + // It can be nil if environment is not guaranteed. + // It will be used for guaranteed environments. + mut genericsA: []&TypeAlias - // Functions instance. - // If this field is not nil, process will be executed by functions. - mut fi: &FnIns + // Functions instance. + // If this field is not nil, process will be executed by functions. + mut fi: &FnIns - // Structure instance. - // If this field is not nil, process will be executed by structures. - mut si: &StructIns + // Structure instance. + // If this field is not nil, process will be executed by structures. + mut si: &StructIns - // Error that will use as error token. - mut et: &Token + // Error that will use as error token. + mut et: &Token - // Whether instance is unique. - mut uniq: bool + // Whether instance is unique. + mut uniq: bool } impl constraintChecker { - fn readyFn(mut &self): fn(mut &sema: &Sema, mut &generics: []&TypeAlias): bool { - ret fn(mut &sema: &Sema, mut &generics: []&TypeAlias): bool { - for (i, mut g) in self.genericsD { - mut generic := self.generics[i] - if g.Constraint == nil || len(g.Constraint.Mask) == 0 { - continue - } - generic.Constraint = make([]&TypeKind, 0, len(g.Constraint.Mask)) - for (_, mut mask) in g.Constraint.Mask { - n := len(sema.errors) - mut kind := sema.buildTypeWithRefers(mask, sema, generics, nil) - if kind == nil { - match type mask.Kind { - | &IdentTypeDecl: - mut itd := (&IdentTypeDecl)(mask.Kind) - if len(itd.Generics) == 0 && isBuiltinConstraint(itd.Ident) { - kind = &TypeKind{Kind: buildPrimType(itd.Ident)} - sema.errors = sema.errors[:n] - goto success - } - } - ret false - } - success: - generic.Constraint = append(generic.Constraint, kind) - } - } - ret true - } - } - - // Functions will be checked in their environment, because environment is not guaranteed. - fn readyFi(mut &self): bool { - self.genericsD = self.fi.Decl.Generics - self.generics = self.fi.Generics - ret !self.uniq || self.s.fnEnvironment(self.fi, self.readyFn()) - } - - // Structure will be checked in current environment, because environment should be guaranteed. - fn readySi(mut &self): bool { - self.genericsD = self.si.Decl.Generics - self.generics = self.si.Generics - ret !self.uniq || self.readyFn()(self.s, self.genericsA) - } - - fn ready(mut &self): bool { - if self.fi != nil { - ret self.readyFi() - } - ret self.readySi() - } - - fn check(mut &self): bool { - if !self.ready() { - ret false - } - lookup: - for (i, mut g) in self.generics { - if g.Constraint == nil { - continue - } - for (_, mut c2) in g.Constraint { - mut prim := c2.Prim() - if prim != nil && prim.IsConstraint() { - if matchConstraint(prim.Kind, g.Kind) { - continue lookup - } - continue - } - if c2.Equal(g.Kind) { - continue lookup - } - } - self.s.pushErr(self.et, LogMsg.ConstraintFailed, g.Kind.Str(), self.genericsD[i].Ident, toStrConstraints(g)) - ret false - } - ret true - } + fn readyFn(mut &self): fn(mut &sema: &Sema, mut &generics: []&TypeAlias): bool { + ret fn(mut &sema: &Sema, mut &generics: []&TypeAlias): bool { + for (i, mut g) in self.genericsD { + mut generic := self.generics[i] + if g.Constraint == nil || len(g.Constraint.Mask) == 0 { + continue + } + generic.Constraint = make([]&TypeKind, 0, len(g.Constraint.Mask)) + for (_, mut mask) in g.Constraint.Mask { + n := len(sema.errors) + mut kind := sema.buildTypeWithRefers(mask, sema, generics, nil) + if kind == nil { + match type mask.Kind { + | &IdentTypeDecl: + mut itd := (&IdentTypeDecl)(mask.Kind) + if len(itd.Generics) == 0 && isBuiltinConstraint(itd.Ident) { + kind = &TypeKind{Kind: buildPrimType(itd.Ident)} + sema.errors = sema.errors[:n] + goto success + } + } + ret false + } + success: + generic.Constraint = append(generic.Constraint, kind) + } + } + ret true + } + } + + // Functions will be checked in their environment, because environment is not guaranteed. + fn readyFi(mut &self): bool { + self.genericsD = self.fi.Decl.Generics + self.generics = self.fi.Generics + ret !self.uniq || self.s.fnEnvironment(self.fi, self.readyFn()) + } + + // Structure will be checked in current environment, because environment should be guaranteed. + fn readySi(mut &self): bool { + self.genericsD = self.si.Decl.Generics + self.generics = self.si.Generics + ret !self.uniq || self.readyFn()(self.s, self.genericsA) + } + + fn ready(mut &self): bool { + if self.fi != nil { + ret self.readyFi() + } + ret self.readySi() + } + + fn check(mut &self): bool { + if !self.ready() { + ret false + } + lookup: + for (i, mut g) in self.generics { + if g.Constraint == nil { + continue + } + for (_, mut c2) in g.Constraint { + mut prim := c2.Prim() + if prim != nil && prim.IsConstraint() { + if matchConstraint(prim.Kind, g.Kind) { + continue lookup + } + continue + } + if c2.Equal(g.Kind) { + continue lookup + } + } + self.s.pushErr(self.et, LogMsg.ConstraintFailed, g.Kind.Str(), self.genericsD[i].Ident, toStrConstraints(g)) + ret false + } + ret true + } } fn toStrConstraints(g: &InsGeneric): str { - mut sb := StrBuilder.New(1 << 7) - for i, c in g.Constraint { - sb.WriteStr(c.Str()) - if len(g.Constraint)-i > 1 { - sb.WriteStr(" | ") - } - } - ret sb.Str() + mut sb := StrBuilder.New(1 << 7) + for i, c in g.Constraint { + sb.WriteStr(c.Str()) + if len(g.Constraint)-i > 1 { + sb.WriteStr(" | ") + } + } + ret sb.Str() } fn matchConstraint(&c: str, mut &g: &TypeKind): bool { - match c { - | builtinConstraint.Signed: - prim := g.Prim() - if prim == nil { - ret false - } - ret types::IsSigNum(prim.Kind) - | builtinConstraint.Unsigned: - prim := g.Prim() - if prim == nil { - ret false - } - ret types::IsUnsigInt(prim.Kind) - | builtinConstraint.Float: - prim := g.Prim() - if prim == nil { - ret false - } - ret types::IsFloat(prim.Kind) - | builtinConstraint.Numeric: - prim := g.Prim() - if prim == nil { - ret false - } - ret types::IsNum(prim.Kind) - | builtinConstraint.Mutable: - ret g.Mutable() - | builtinConstraint.Immutable: - ret !g.Mutable() - | builtinConstraint.Comparable: - ret g.Comparable() - | builtinConstraint.Ordered: - ret g.Ordered() - |: - ret false - } + match c { + | builtinConstraint.Signed: + prim := g.Prim() + if prim == nil { + ret false + } + ret types::IsSigNum(prim.Kind) + | builtinConstraint.Unsigned: + prim := g.Prim() + if prim == nil { + ret false + } + ret types::IsUnsigInt(prim.Kind) + | builtinConstraint.Float: + prim := g.Prim() + if prim == nil { + ret false + } + ret types::IsFloat(prim.Kind) + | builtinConstraint.Numeric: + prim := g.Prim() + if prim == nil { + ret false + } + ret types::IsNum(prim.Kind) + | builtinConstraint.Mutable: + ret g.Mutable() + | builtinConstraint.Immutable: + ret !g.Mutable() + | builtinConstraint.Comparable: + ret g.Comparable() + | builtinConstraint.Ordered: + ret g.Ordered() + |: + ret false + } } fn isBuiltinConstraint(&ident: str): bool { - for _, bc in builtinConstraints { - if ident == bc { - ret true - } - } - ret false + for _, bc in builtinConstraints { + if ident == bc { + ret true + } + } + ret false } \ No newline at end of file diff --git a/std/jule/sema/directive.jule b/std/jule/sema/directive.jule index 9112800b3..a0acec66a 100644 --- a/std/jule/sema/directive.jule +++ b/std/jule/sema/directive.jule @@ -7,179 +7,179 @@ use std::jule::build::{Directive, LogMsg} use std::jule::lex::{TokenId} struct directiveChecker { - s: &Sema - d: &[]&ast::Directive - o: any + s: &Sema + d: &[]&ast::Directive + o: any } impl directiveChecker { - fn checkCdef(mut self, &d: &ast::Directive) { - match type self.o { - | &Fn: - if (&Fn)(self.o).Binded { - break - } - fall - |: - self.s.pushErr(d.Tag, LogMsg.UnsupportedDirective, d.Tag.Kind) - } - - if len(d.Args) > 0 { - self.s.pushErr(d.Args[0], LogMsg.InvalidSyntax) - } - } - - fn checkTypedef(mut self, &d: &ast::Directive) { - match type self.o { - | &Struct: - if (&Struct)(self.o).Binded { - break - } - fall - |: - self.s.pushErr(d.Tag, LogMsg.UnsupportedDirective, d.Tag.Kind) - } - - if len(d.Args) > 0 { - self.s.pushErr(d.Args[0], LogMsg.InvalidSyntax) - } - } - - fn checkNamespace(mut self, mut &d: &ast::Directive) { - match type self.o { - | &Struct: - if !(&Struct)(self.o).Binded { - self.s.pushErr(d.Tag, LogMsg.UnsupportedDirective, d.Tag.Kind) - } - | &Fn: - if !(&Fn)(self.o).Binded { - self.s.pushErr(d.Tag, LogMsg.UnsupportedDirective, d.Tag.Kind) - } - | &Var: - if !(&Var)(self.o).Binded { - self.s.pushErr(d.Tag, LogMsg.UnsupportedDirective, d.Tag.Kind) - } - |: - self.s.pushErr(d.Tag, LogMsg.UnsupportedDirective, d.Tag.Kind) - } - - if len(d.Args) == 0 { - self.s.pushErr(d.Tag, LogMsg.MissingExpr) - ret - } else if len(d.Args) > 1 { - self.s.pushErr(d.Args[1], LogMsg.ArgumentOverflow, d.Tag.Kind) - } - - arg := d.Args[0] - if arg.Id != TokenId.Lit { - self.s.pushErr(arg, LogMsg.InvalidSyntax) - ret - } - - if arg.Kind[0] != '"' { - self.s.pushErr(arg, LogMsg.InvalidSyntax) - ret - } - - d.Args[0].Kind = arg.Kind[1:len(arg.Kind)-1] - - // Push relevant directives. - match type self.o { - | &Struct: - if findDirective(*self.d, Directive.Typedef) == nil { - mut typedef := &ast::Directive{ - Tag: d.Tag, - } - typedef.Tag.Kind = Directive.Typedef - *self.d = append(*self.d, typedef) - } - } - } - - fn checkDeprecated(mut self, mut &d: &ast::Directive) { - match type self.o { - | &Struct: - if (&Struct)(self.o).Binded { - self.s.pushErr(d.Tag, LogMsg.UnsupportedDirective, d.Tag.Kind) - } - | &Fn: - mut f := (&Fn)(self.o) - if f.Binded || f.IsEntryPoint() || f.IsInit() { - self.s.pushErr(d.Tag, LogMsg.UnsupportedDirective, d.Tag.Kind) - } - | &Var: - if (&Var)(self.o).Binded { - self.s.pushErr(d.Tag, LogMsg.UnsupportedDirective, d.Tag.Kind) - } - |: - self.s.pushErr(d.Tag, LogMsg.UnsupportedDirective, d.Tag.Kind) - } - - if len(d.Args) == 0 { - ret - } - if len(d.Args) > 1 { - self.s.pushErr(d.Args[1], LogMsg.ArgumentOverflow, d.Tag.Kind) - } - - arg := d.Args[0] - if arg.Id != TokenId.Lit { - self.s.pushErr(arg, LogMsg.InvalidSyntax) - ret - } - - if arg.Kind[0] != '"' { - self.s.pushErr(arg, LogMsg.InvalidSyntax) - ret - } - - d.Args[0].Kind = arg.Kind[1:len(arg.Kind)-1] - } - - fn checkTest(mut self, &d: &ast::Directive) { - match type self.o { - | &Fn: - f := (&Fn)(self.o) - if !f.Binded && !f.IsInit() && !f.IsEntryPoint() { - break - } - if f.IsMethod() { - self.s.pushErr(f.Token, LogMsg.TestMethod) - break - } - fall - |: - self.s.pushErr(d.Tag, LogMsg.UnsupportedDirective, d.Tag.Kind) - } - - if len(d.Args) > 0 { - self.s.pushErr(d.Args[0], LogMsg.InvalidSyntax) - } - } - - fn checkDirective(mut self, mut &d: &ast::Directive) { - match d.Tag.Kind { - | Directive.Cdef: - self.checkCdef(d) - | Directive.Typedef: - self.checkTypedef(d) - | Directive.Namespace: - self.checkNamespace(d) - | Directive.Deprecated: - self.checkDeprecated(d) - | Directive.Test: - self.checkTest(d) - | Directive.Build - | Directive.Pass: - self.s.pushErr(d.Tag, LogMsg.UnsupportedDirective, d.Tag.Kind) - |: - self.s.pushErr(d.Tag, LogMsg.InvalidLabel, d.Tag.Kind) - } - } - - fn check(mut self) { - for (_, mut d) in *self.d { - self.checkDirective(d) - } - } + fn checkCdef(mut self, &d: &ast::Directive) { + match type self.o { + | &Fn: + if (&Fn)(self.o).Binded { + break + } + fall + |: + self.s.pushErr(d.Tag, LogMsg.UnsupportedDirective, d.Tag.Kind) + } + + if len(d.Args) > 0 { + self.s.pushErr(d.Args[0], LogMsg.InvalidSyntax) + } + } + + fn checkTypedef(mut self, &d: &ast::Directive) { + match type self.o { + | &Struct: + if (&Struct)(self.o).Binded { + break + } + fall + |: + self.s.pushErr(d.Tag, LogMsg.UnsupportedDirective, d.Tag.Kind) + } + + if len(d.Args) > 0 { + self.s.pushErr(d.Args[0], LogMsg.InvalidSyntax) + } + } + + fn checkNamespace(mut self, mut &d: &ast::Directive) { + match type self.o { + | &Struct: + if !(&Struct)(self.o).Binded { + self.s.pushErr(d.Tag, LogMsg.UnsupportedDirective, d.Tag.Kind) + } + | &Fn: + if !(&Fn)(self.o).Binded { + self.s.pushErr(d.Tag, LogMsg.UnsupportedDirective, d.Tag.Kind) + } + | &Var: + if !(&Var)(self.o).Binded { + self.s.pushErr(d.Tag, LogMsg.UnsupportedDirective, d.Tag.Kind) + } + |: + self.s.pushErr(d.Tag, LogMsg.UnsupportedDirective, d.Tag.Kind) + } + + if len(d.Args) == 0 { + self.s.pushErr(d.Tag, LogMsg.MissingExpr) + ret + } else if len(d.Args) > 1 { + self.s.pushErr(d.Args[1], LogMsg.ArgumentOverflow, d.Tag.Kind) + } + + arg := d.Args[0] + if arg.Id != TokenId.Lit { + self.s.pushErr(arg, LogMsg.InvalidSyntax) + ret + } + + if arg.Kind[0] != '"' { + self.s.pushErr(arg, LogMsg.InvalidSyntax) + ret + } + + d.Args[0].Kind = arg.Kind[1:len(arg.Kind)-1] + + // Push relevant directives. + match type self.o { + | &Struct: + if findDirective(*self.d, Directive.Typedef) == nil { + mut typedef := &ast::Directive{ + Tag: d.Tag, + } + typedef.Tag.Kind = Directive.Typedef + *self.d = append(*self.d, typedef) + } + } + } + + fn checkDeprecated(mut self, mut &d: &ast::Directive) { + match type self.o { + | &Struct: + if (&Struct)(self.o).Binded { + self.s.pushErr(d.Tag, LogMsg.UnsupportedDirective, d.Tag.Kind) + } + | &Fn: + mut f := (&Fn)(self.o) + if f.Binded || f.IsEntryPoint() || f.IsInit() { + self.s.pushErr(d.Tag, LogMsg.UnsupportedDirective, d.Tag.Kind) + } + | &Var: + if (&Var)(self.o).Binded { + self.s.pushErr(d.Tag, LogMsg.UnsupportedDirective, d.Tag.Kind) + } + |: + self.s.pushErr(d.Tag, LogMsg.UnsupportedDirective, d.Tag.Kind) + } + + if len(d.Args) == 0 { + ret + } + if len(d.Args) > 1 { + self.s.pushErr(d.Args[1], LogMsg.ArgumentOverflow, d.Tag.Kind) + } + + arg := d.Args[0] + if arg.Id != TokenId.Lit { + self.s.pushErr(arg, LogMsg.InvalidSyntax) + ret + } + + if arg.Kind[0] != '"' { + self.s.pushErr(arg, LogMsg.InvalidSyntax) + ret + } + + d.Args[0].Kind = arg.Kind[1:len(arg.Kind)-1] + } + + fn checkTest(mut self, &d: &ast::Directive) { + match type self.o { + | &Fn: + f := (&Fn)(self.o) + if !f.Binded && !f.IsInit() && !f.IsEntryPoint() { + break + } + if f.IsMethod() { + self.s.pushErr(f.Token, LogMsg.TestMethod) + break + } + fall + |: + self.s.pushErr(d.Tag, LogMsg.UnsupportedDirective, d.Tag.Kind) + } + + if len(d.Args) > 0 { + self.s.pushErr(d.Args[0], LogMsg.InvalidSyntax) + } + } + + fn checkDirective(mut self, mut &d: &ast::Directive) { + match d.Tag.Kind { + | Directive.Cdef: + self.checkCdef(d) + | Directive.Typedef: + self.checkTypedef(d) + | Directive.Namespace: + self.checkNamespace(d) + | Directive.Deprecated: + self.checkDeprecated(d) + | Directive.Test: + self.checkTest(d) + | Directive.Build + | Directive.Pass: + self.s.pushErr(d.Tag, LogMsg.UnsupportedDirective, d.Tag.Kind) + |: + self.s.pushErr(d.Tag, LogMsg.InvalidLabel, d.Tag.Kind) + } + } + + fn check(mut self) { + for (_, mut d) in *self.d { + self.checkDirective(d) + } + } } \ No newline at end of file diff --git a/std/jule/sema/enum.jule b/std/jule/sema/enum.jule index 2d424e085..3f2b21027 100644 --- a/std/jule/sema/enum.jule +++ b/std/jule/sema/enum.jule @@ -6,92 +6,92 @@ use std::jule::lex::{Token} // Enum item. struct EnumItem { - Token: &Token - Ident: str - Value: &Value + Token: &Token + Ident: str + Value: &Value } impl EnumItem { - // Reports whether item has auto expression. - fn AutoExpr(self): bool { - ret self.Value == nil - } + // Reports whether item has auto expression. + fn AutoExpr(self): bool { + ret self.Value == nil + } } // Enum. struct Enum { - Token: &Token - Public: bool - Ident: str - Kind: &TypeSymbol - Items: []&EnumItem + Token: &Token + Public: bool + Ident: str + Kind: &TypeSymbol + Items: []&EnumItem } impl Kind for Enum { - // Implement: Kind - // Returns Enum's identifier. - fn Str(self): str { - ret self.Ident - } + // Implement: Kind + // Returns Enum's identifier. + fn Str(self): str { + ret self.Ident + } - // Reports whether types are same. - fn Equal(&self, other: &TypeKind): bool { - enm := unsafe { (*(&other)).Enum() } - ret self == enm - } + // Reports whether types are same. + fn Equal(&self, other: &TypeKind): bool { + enm := unsafe { (*(&other)).Enum() } + ret self == enm + } } impl Enum { - // Returns item by identifier. - // Returns nil reference if not exist any item in this identifier. - fn FindItem(mut self, ident: str): &EnumItem { - for (_, mut item) in self.Items { - if item.Ident == ident { - ret item - } - } - ret nil - } + // Returns item by identifier. + // Returns nil reference if not exist any item in this identifier. + fn FindItem(mut self, ident: str): &EnumItem { + for (_, mut item) in self.Items { + if item.Ident == ident { + ret item + } + } + ret nil + } } // TypeEnum item. struct TypeEnumItem { - Token: &Token - Ident: str - Kind: &TypeSymbol + Token: &Token + Ident: str + Kind: &TypeSymbol } // TypeEnum. struct TypeEnum { - Token: &Token - Public: bool - Ident: str - Items: []&TypeEnumItem + Token: &Token + Public: bool + Ident: str + Items: []&TypeEnumItem } impl Kind for TypeEnum { - // Implement: Kind - // Returns TypeEnum's identifier. - fn Str(self): str { - ret self.Ident - } + // Implement: Kind + // Returns TypeEnum's identifier. + fn Str(self): str { + ret self.Ident + } - // Reports whether types are same. - fn Equal(&self, other: &TypeKind): bool { - tenm := unsafe { (*(&other)).TypeEnum() } - ret self == tenm - } + // Reports whether types are same. + fn Equal(&self, other: &TypeKind): bool { + tenm := unsafe { (*(&other)).TypeEnum() } + ret self == tenm + } } impl TypeEnum { - // Returns item by identifier. - // Returns nil reference if not exist any item in this identifier. - fn FindItem(mut self, ident: str): &TypeEnumItem { - for (_, mut item) in self.Items { - if item.Ident == ident { - ret item - } - } - ret nil - } + // Returns item by identifier. + // Returns nil reference if not exist any item in this identifier. + fn FindItem(mut self, ident: str): &TypeEnumItem { + for (_, mut item) in self.Items { + if item.Ident == ident { + ret item + } + } + ret nil + } } \ No newline at end of file diff --git a/std/jule/sema/eval.jule b/std/jule/sema/eval.jule index 829627e6e..1a93d97ca 100644 --- a/std/jule/sema/eval.jule +++ b/std/jule/sema/eval.jule @@ -6,54 +6,54 @@ use std::unsafe use conv for std::conv use path for std::fs::path use ast for std::jule::ast::{ - Expr, - LitExpr, - IdentExpr, - VariadicExpr, - UnaryExpr, - UnsafeExpr, - SliceExpr, - ExprData, - FnDecl, - BinaryExpr, - BraceLit, - TupleExpr, - SubIdentExpr, - IndexingExpr, - NsSelectionExpr, - TypeDecl, - FnCallExpr, - SlicingExpr, - CastExpr, - StructLit, - KeyValPair, - IdentTypeDecl, - NamespaceTypeDecl, - SubIdentTypeDecl, - RangeExpr, - TypeDeclKind, - SptrTypeDecl, - PtrTypeDecl, + Expr, + LitExpr, + IdentExpr, + VariadicExpr, + UnaryExpr, + UnsafeExpr, + SliceExpr, + ExprData, + FnDecl, + BinaryExpr, + BraceLit, + TupleExpr, + SubIdentExpr, + IndexingExpr, + NsSelectionExpr, + TypeDecl, + FnCallExpr, + SlicingExpr, + CastExpr, + StructLit, + KeyValPair, + IdentTypeDecl, + NamespaceTypeDecl, + SubIdentTypeDecl, + RangeExpr, + TypeDeclKind, + SptrTypeDecl, + PtrTypeDecl, } use build for std::jule::build::{ - LogMsg, - Directive, - PathStdlib, - Logf, + LogMsg, + Directive, + PathStdlib, + Logf, } use std::jule::constant::{Const} use lit for std::jule::constant::lit use lex for std::jule::lex::{ - self, - Token, - TokenId, - TokenKind, - IsStr, - IsBool, - IsRune, - IsRawStr, - IsNil, - IsIgnoreIdent, + self, + Token, + TokenId, + TokenKind, + IsStr, + IsBool, + IsRune, + IsRawStr, + IsNil, + IsIgnoreIdent, } use types for std::jule::types use mod for std::jule::internal::mod @@ -61,4212 +61,4212 @@ use strings for std::strings::{StrBuilder} // Value data. struct Data { - // Means data is constant numeric and have not any exact type. - // Since data is constant numeric, it also implies kind is primitive. - untyped: bool - - Kind: &TypeKind - Mutable: bool - Reference: bool - Lvalue: bool - IsRune: bool - Model: ExprModel - - // True if kind is declaration such as: - // - &Enum - // - &Struct - // - int type - // - bool type - Decl: bool - - // Constant expression data. - Constant: &Const + // Means data is constant numeric and have not any exact type. + // Since data is constant numeric, it also implies kind is primitive. + untyped: bool + + Kind: &TypeKind + Mutable: bool + Reference: bool + Lvalue: bool + IsRune: bool + Model: ExprModel + + // True if kind is declaration such as: + // - &Enum + // - &Struct + // - int type + // - bool type + Decl: bool + + // Constant expression data. + Constant: &Const } impl Data { - // Reports whether Data is nil literal. - fn IsNil(self): bool { - ret self.Kind.IsNil() - } - - // Reports whether Data is void. - fn IsVoid(self): bool { - ret self.Kind.Void() - } - - // Reports whether Data is constant expression. - fn IsConst(self): bool { - ret self.Constant != nil - } - - // Reports left and right operand is good order. - // If reports false, left and right operand should be swapped. - // Accepts itself as left operand. - fn GoodOperand(self, mut &other: &Data): bool { - if other.Kind.TypeEnum() != nil { - ret false - } - ret (other.Kind.Prim() == nil || !other.Kind.Prim().IsAny()) && - other.Kind.Trait() == nil && - !self.Kind.IsNil() - } + // Reports whether Data is nil literal. + fn IsNil(self): bool { + ret self.Kind.IsNil() + } + + // Reports whether Data is void. + fn IsVoid(self): bool { + ret self.Kind.Void() + } + + // Reports whether Data is constant expression. + fn IsConst(self): bool { + ret self.Constant != nil + } + + // Reports left and right operand is good order. + // If reports false, left and right operand should be swapped. + // Accepts itself as left operand. + fn GoodOperand(self, mut &other: &Data): bool { + if other.Kind.TypeEnum() != nil { + ret false + } + ret (other.Kind.Prim() == nil || !other.Kind.Prim().IsAny()) && + other.Kind.Trait() == nil && + !self.Kind.IsNil() + } } // Value. struct Value { - Expr: &Expr - Data: &Data + Expr: &Expr + Data: &Data } // Evaluator. struct Eval { - s: &Sema // Used for error logging. - lookup: Lookup - prefix: &TypeKind - unsafety: bool - immutable: bool // This expression will assigned to immutable memory. - ignored: bool // Evaluated expression is not for assignment or something else. - disBuiltin: bool // Disallow/suppress Jule's built-in defines. - owner: &Var - field: &FieldIns // Field of this default expression. Used for checking cycles. - arg: bool // This expression evaluating for argument. + s: &Sema // Used for error logging. + lookup: Lookup + prefix: &TypeKind + unsafety: bool + immutable: bool // This expression will assigned to immutable memory. + ignored: bool // Evaluated expression is not for assignment or something else. + disBuiltin: bool // Disallow/suppress Jule's built-in defines. + owner: &Var + field: &FieldIns // Field of this default expression. Used for checking cycles. + arg: bool // This expression evaluating for argument. } impl Eval { - fn pushErr(mut self, token: &Token, fmt: LogMsg, args: ...any) { - self.s.pushErr(token, fmt, args...) - } - - // Push suggestion to last log. - fn pushSuggestion(mut self, fmt: LogMsg, args: ...any) { - self.s.pushSuggestion(fmt, args...) - } - - fn allowBuiltin(mut self) { - self.disBuiltin = false - } - - fn disallowBuiltin(mut self) { - self.disBuiltin = true - } - - // Reports whether evaluation in unsafe scope. - fn isUnsafe(self): bool { - ret self.unsafety - } - - // Reports whether evaluated expression is in global scope. - fn isGlobal(self): bool { - match type self.lookup { - | &Sema: - ret true - |: - ret false - } - } - - fn applyNumericPrefix(mut self, mut &d: &Data): bool { - if d == nil || - !d.IsConst() || - d.Kind.Prim() == nil || - self.prefix == nil { - ret false - } - prim := self.prefix.Prim() - if prim == nil { - ret false - } - - match { - | types::IsFloat(prim.Str()): - d.Kind = new(TypeKind, *self.prefix) - d.Constant.SetF64(d.Constant.AsF64()) - d.Constant.Kind = prim.Kind - | types::IsSigInt(prim.Str()): - if !sigAssignable(prim.Str(), d) { - ret false - } - d.Kind = new(TypeKind, *self.prefix) - d.Constant.SetI64(d.Constant.AsI64()) - d.Constant.Kind = prim.Kind - | types::IsUnsigInt(prim.Str()): - if !unsigAssignable(prim.Str(), d) { - ret false - } - d.Kind = new(TypeKind, *self.prefix) - d.Constant.SetU64(d.Constant.AsU64()) - d.Constant.Kind = prim.Kind - } - ret true - } - - fn litStr(self, &l: &LitExpr): &Data { - mut s := "" - if IsRawStr(l.Value) { - s = lit::ToRawStr(l.Value) - } else { - s = lit::ToStr(l.Value) - } - mut constant := Const.NewStr(s) - - ret &Data{ - Mutable: true, - Constant: constant, - Kind: primStr, - Model: constant, - } - } - - fn litRune(self, &l: &LitExpr): &Data { - r := lit::ToRune(l.Value) - mut data := &Data{ - Constant: Const.NewI64(i64(r)), - } - - if r <= 255 { - data.Kind = primU8 // Byte - } else { - data.Kind = primI32 // Rune - } - - data.Model = &RuneExprModel{Code: r} - data.Mutable = true - data.IsRune = true - data.untyped = true - ret data - } - - fn litFloat(self, &l: &LitExpr): &Data { - f := conv::ParseFloat(l.Value, 64) else { use f64.Max } - mut constant := Const.NewF64(f) - ret &Data{ - untyped: true, - Mutable: true, - Constant: constant, - Kind: primF64, - Model: constant, - } - } - - fn litInt(mut self, &l: &LitExpr): &Data { - const BitSize = 1 << 6 - - mut lit := l.Value - mut base := 0 - - match { - | strings::HasPrefix(lit, "0x"): // Hexadecimal - lit = lit[2:] - base = 1 << 4 - | strings::HasPrefix(lit, "0b"): // Binary - lit = lit[2:] - base = 1 << 1 - | strings::HasPrefix(lit, "0o"): // Ocatal - lit = lit[2:] - base = 1 << 3 - | lit[0] == '0' && len(lit) > 1: // Octal - lit = lit[1:] - base = 1 << 3 - |: - // Decimal - base = 1 << 3 + 2 - } - - mut d := new(Data) - - mut ok := true - sig := conv::ParseInt(lit, base, BitSize) else { - ok = false - use 0 - } - if ok { - d.Constant = Const.NewI64(sig) - d.Kind = primInt - } else { - unsig := conv::ParseUint(lit, base, BitSize) else { - self.pushErr(l.Token, LogMsg.InvalidNumericRange) - self.pushSuggestion(LogMsg.TryFloatingPoint) - use u64.Max - } - d.Constant = Const.NewU64(unsig) - d.Kind = primUint - } - - d.Model = d.Constant - d.untyped = true - if !self.applyNumericPrefix(d) { - // If prefix is not implemented, check constant bitsize. - // Arcihtecture bitsize type might be insufficient to store constant data. - // If this concern is true, set kind to minimum type that has enough bitsize. - fitBitsize(d) - } - ret d - } - - fn litNum(mut self, &l: &LitExpr): &Data { - match { - | lex::IsFloat(l.Value): - ret self.litFloat(l) - |: - ret self.litInt(l) - } - } - - fn evalLit(mut self, lit: &LitExpr): &Data { - match { - | IsStr(lit.Value): - ret self.litStr(lit) - | IsRune(lit.Value): - ret self.litRune(lit) - | lex::IsNum(lit.Value): - ret self.litNum(lit) - |: - ret nil - } - } - - fn findBuiltins(mut self, &ident: str): any { - if mod::IsPub(ident) { - match type self.lookup { - | &ImportInfo: - mut def := findBuiltinsImport(ident, (&ImportInfo)(self.lookup)) - if def != nil { - ret def - } - | &Sema: - mut def := findBuiltinsSema(ident, (&Sema)(self.lookup)) - if def != nil { - ret def - } - | &scopeChecker: - mut def := findBuiltinsSema(ident, (&scopeChecker)(self.lookup).s) - if def != nil { - ret def - } - } - ret nil - } - if self.disBuiltin { - ret nil - } - ret findBuiltinDef(ident) - } - - fn getDef(mut self, &ident: str, binded: bool): any { - // Find variables and type aliases first. - // Because self.lookup might be a scopeChecker, and shadowing may occurred. - // If any variable or type aliases is shadowing other declarations such us structure, - // it will result as wrong expression evaluation. - mut v := self.lookup.FindVar(ident, binded) - if v != nil { - ret v - } - - mut ta := self.lookup.FindTypeAlias(ident, binded) - if ta != nil { - ret ta - } - - if !binded { - mut enm := self.lookup.FindEnum(ident) - if enm != nil { - ret enm - } - - mut tenm := self.lookup.FindTypeEnum(ident) - if tenm != nil { - ret tenm - } - } - - mut f := self.lookup.FindFn(ident, binded) - if f != nil { - ret f - } - - mut s := self.lookup.FindStruct(ident, binded) - if s != nil { - ret s - } - - ret self.findBuiltins(ident) - } - - fn getOwnerRefers(mut self): &ReferenceStack { - match type self.lookup { - | &scopeChecker: - mut sc := (&scopeChecker)(self.lookup).getHardRoot() - ret sc.owner.Refers - |: - // Push reference to owner if global. - if self.owner != nil && - self.owner.Scope == nil { - ret self.owner.Refers - } - } - ret nil - } - - fn pushReference[T](mut self, mut &ref: T) { - mut refers := self.getOwnerRefers() - if refers != nil && !refers.Exist[T](ref) { - refers.Push(ref) - } - } - - fn _evalEnum(self, mut enm: &Enum): &Data { - ret &Data{ - Decl: true, - Kind: &TypeKind{ - Kind: enm, - }, - } - } - - fn evalEnum(mut self, mut enm: &Enum, errorToken: &Token): &Data { - if !self.s.isAccessibleDefine(enm.Public, enm.Token) { - self.pushErr(errorToken, LogMsg.IdentIsNotAccessible, enm.Ident) - self.pushSuggestion(LogMsg.MakePubToAccess) - ret nil - } - ret self._evalEnum(enm) - } - - fn _evalTypeEnum(self, mut enm: &TypeEnum): &Data { - ret &Data{ - Decl: true, - Kind: &TypeKind{ - Kind: enm, - }, - } - } - - fn evalTypeEnum(mut self, mut enm: &TypeEnum, errorToken: &Token): &Data { - if !self.s.isAccessibleDefine(enm.Public, enm.Token) { - self.pushErr(errorToken, LogMsg.IdentIsNotAccessible, enm.Ident) - self.pushSuggestion(LogMsg.MakePubToAccess) - ret nil - } - ret self._evalTypeEnum(enm) - } - - fn _evalStruct(self, mut s: &StructIns): &Data { - mut d := &Data{ - Decl: true, - Kind: &TypeKind{ - Kind: s, - }, - Model: s, - } - if s.Decl != nil && s.Decl.Binded { - d.Kind.BindIdent = s.Decl.Ident - } - ret d - } - - fn evalStruct(mut self, mut s: &StructIns, errorToken: &Token): &Data { - if !self.s.isAccessibleDefine(s.Decl.Public, s.Decl.Token) { - self.pushErr(errorToken, LogMsg.IdentIsNotAccessible, s.Decl.Ident) - self.pushSuggestion(LogMsg.MakePubToAccess) - ret nil - } - self.checkDeprecated(s.Decl.Directives, errorToken) - ret self._evalStruct(s) - } - - fn evalFnIns(self, mut f: &FnIns): &Data { - ret &Data{ - Kind: &TypeKind{ - Kind: f, - }, - Model: f, - } - } - - fn checkDeprecated(mut self, mut &directives: []&ast::Directive, tok: &Token) { - if self.isUnsafe() { - ret - } - - d := findDirective(directives, Directive.Deprecated) - if d != nil { - if len(d.Args) == 0 { - self.pushErr(tok, LogMsg.UsingDeprecated, "this code is deprecated") - } else { - self.pushErr(tok, LogMsg.UsingDeprecated, d.Args[0].Kind) - } - self.pushSuggestion(LogMsg.UseUnsafeForDeprecated) - } - } - - fn evalFn(mut self, mut f: &Fn, errorToken: &Token): &Data { - if !self.s.isAccessibleDefine(f.Public, f.Token) { - self.pushErr(errorToken, LogMsg.IdentIsNotAccessible, f.Ident) - self.pushSuggestion(LogMsg.MakePubToAccess) - ret nil - } - - self.checkDeprecated(f.Directives, errorToken) - - mut ins := f.instance() - self.pushReference[&FnIns](ins) - ret self.evalFnIns(ins) - } - - fn pushIllegalCycleError(mut self, &v1: &Var, &v2: &Var, mut &message: StrBuilder) { - const Padding = 7 - refers_to := Logf(LogMsg.RefersTo, v1.Ident, v2.Ident) - buf := unsafe { message.Buf() } - message.WriteStr(strings::Repeat(" ", Padding)) - message.WriteStr(refers_to) - message.WriteByte('\n') - message.Write(buf) - } - - fn checkCrossCycle(mut self, &v: &Var, mut &message: StrBuilder): bool { - for _, d in v.Depends { - if d == self.owner { - self.pushIllegalCycleError(v, d, message) - ret false - } - if !self.checkCrossCycle(d, message) { - self.pushIllegalCycleError(v, d, message) - ret false - } - } - ret true - } - - // Checks owner illegal cycles. - // Appends depend to depends if there is no illegal cycle. - // Returns true if e.owner is nil. - fn checkIllegalCycles(mut self, mut &v: &Var, declToken: &Token): (ok: bool) { - // Skip cycle checking if owner is nil or not global. - if self.owner == nil || self.owner.Scope != nil { - ret true - } - - // Check illegal cycle for itself. - // Because refers's owner is ta. - if self.owner == v { - self.pushErr(self.owner.Token, LogMsg.IllegalCycleRefersItself, self.owner.Ident) - ret false - } - - mut message := StrBuilder.New(1 << 5) - - if !self.checkCrossCycle(v, message) { - mut errMsg := message.Str() - message.Clear() - self.pushIllegalCycleError(self.owner, v, message) - errMsg += message.Str() - self.pushErr(declToken, LogMsg.IllegalCrossCycle, errMsg) - ret false - } - - self.owner.Depends = append(self.owner.Depends, v) - ret true - } - - fn evalVar(mut self, mut v: &Var, errorToken: &Token): &Data { - if !self.s.isAccessibleDefine(v.Public, v.Token) { - self.pushErr(errorToken, LogMsg.IdentIsNotAccessible, v.Ident) - self.pushSuggestion(LogMsg.MakePubToAccess) - ret nil - } - - self.checkDeprecated(v.Directives, errorToken) - - if v.Token == nil { - // Variable is built-in. - goto data - } - - v.Used = true - - match type self.lookup { - | &Sema: - // Check cycles for global scope. - ok := self.checkIllegalCycles(v, errorToken) - if !ok { - ret nil - } - | &scopeChecker: - mut s := (&scopeChecker)(self.lookup) - mut root := s.getRoot() - if root.captured != nil && isVarCaptured(root, s, v) { - root.pushCaptured(v) - } - if !v.Reference || self.isUnsafe() { - break - } - for s.owner == nil && s.parent != nil { - s = s.parent - } - if s.owner != nil && s.owner.Anon && v.Scope != s.owner.Scope { - self.pushErr(errorToken, LogMsg.UsedRefInAnonFnFromParentScope, v.Ident) - } - } - - // Push reference to global variable. - if v.Scope == nil { - self.pushReference[&Var](v) - } - - if !v.Binded && (v.Value == nil || v.Value.Data == nil) { - if v.Constant { - // Eval constant dependent variable. - self.s.checkVar(v, self.s) - if v.Value == nil || v.Value.Data == nil { - // Skip error. - ret nil - } - } - } - - // Kind is nil, no determined. - // In other word, not analyzed yet. - // But this variable is dependency, therefore check this for eval. - if v.Kind == nil || v.Kind.Kind == nil { - // Just necessary for global scope, therefore - // execute if only scope is nil aka variable is not in global scope. - if v.Scope != nil { - ret nil - } - - self.s.checkVar(v, self.lookup) - - // Ignore eval, because analyze is failed. - if v.Kind == nil || v.Kind.Kind == nil { - ret nil - } - } - - data: - mut d := &Data{ - Lvalue: !v.Constant, - Mutable: v.Mutable, - Reference: v.Reference, - Kind: v.Kind.Kind, - Model: v, - } - - if !v.Binded && v.IsInitialized() && v.Value.Data != nil { - d.IsRune = v.Value.Data.IsRune - } - - if v.Constant && v.Value.Data.Constant != nil { - d.Constant = new(Const, *v.Value.Data.Constant) - d.Model = d.Constant - if v.untypedConstant() { - self.applyNumericPrefix(d) - d.untyped = true - } - } - - ret d - } - - fn evalTypeAlias(mut self, mut ta: &TypeAlias, errorToken: &Token): &Data { - if !self.s.isAccessibleDefine(ta.Public, ta.Token) { - self.pushErr(errorToken, LogMsg.IdentIsNotAccessible, ta.Ident) - self.pushSuggestion(LogMsg.MakePubToAccess) - ret nil - } - - ta.Used = true - - mut kind := ta.Kind.Kind.Kind - let mut d: &Data = nil - match type kind { - | &StructIns: - d = self._evalStruct((&StructIns)(kind)) - | &Enum: - d = self._evalEnum((&Enum)(kind)) - | &TypeEnum: - d = self._evalTypeEnum((&TypeEnum)(kind)) - |: - d = &Data{ - Decl: true, - Kind: &TypeKind{ - Kind: ta.Kind.Kind.Kind, - }, - } - if ta.Binded { - d.Kind.BindIdent = ta.Ident - } else { - d.Kind.BindIdent = ta.Kind.Kind.BindIdent - } - d.Model = d.Kind - } - d.Kind.Generic = ta.Generic - ret d - } - - fn evalDef(mut self, mut &def: any, ident: &Token): &Data { - match type def { - | &Var: - ret self.evalVar((&Var)(def), ident) - | &Enum: - ret self.evalEnum((&Enum)(def), ident) - | &TypeEnum: - ret self.evalTypeEnum((&TypeEnum)(def), ident) - | &Struct: - ret self.evalStruct((&Struct)(def).instance(), ident) - | &Fn: - mut f := (&Fn)(def) - if f.Ident != build::InitFn { - ret self.evalFn(f, ident) - } - | &FnIns: - ret self.evalFnIns((&FnIns)(def)) - | &TypeAlias: - ret self.evalTypeAlias((&TypeAlias)(def), ident) - } - self.pushErr(ident, LogMsg.IdentNotExist, ident.Kind) - ret nil - } - - fn evalIdent(mut self, ident: &IdentExpr): &Data { - mut def := self.getDef(ident.Ident, ident.Binded) - ret self.evalDef(def, ident.Token) - } - - fn evalUnary(mut &self, mut u: &UnaryExpr): &Data { - mut unary := unaryEval.new(self) - ret unary.eval(u) - } - - fn evalVariadic(mut &self, mut v: &VariadicExpr): &Data { - if v.Expr == nil { - self.pushErr(v.Token, LogMsg.InvalidExpr) - ret nil - } - - mut prefix := self.prefix - self.prefix = nil - defer { self.prefix = prefix } - - mut d := self.evalExpr(v.Expr) - if d == nil { - ret nil - } - if !d.Kind.Variadicable() { - self.pushErr(v.Token, LogMsg.VariadicWithNonVariadicable, d.Kind.Str()) - ret nil - } - makeVariadic(d, d.Kind.Slc().Elem) - ret d - } - - fn evalUnsafe(mut &self, mut u: &UnsafeExpr): &Data { - unsafety := self.unsafety - self.unsafety = true - mut d := self.evalExpr(u.Expr) - self.unsafety = unsafety - ret d - } - - fn evalArr(mut &self, mut s: &SliceExpr): &Data { - // Arrays always has type prefixes. - mut pt := self.prefix.Arr() - - mut arr := &Arr{ - Auto: false, - N: 0, - Elem: pt.Elem, - } - - mut filled := false - - if len(s.Exprs) == 2 { - match type s.Exprs[1].Kind { - | &VariadicExpr: - if (&VariadicExpr)(s.Exprs[1].Kind).Expr != nil { - break - } - // Filled. - - if pt.Auto { - self.pushErr(s.Token, LogMsg.AutoSizedArrFilled) - ret nil - } - - filled = true - s.Exprs = s.Exprs[:1] - } - } - - arr.N = len(s.Exprs) - if !pt.Auto { - if arr.N > pt.N { - self.pushErr(s.Token, LogMsg.OverflowLimits) - } else if arr.N < pt.N { - arr.N = pt.N - } - } - - mut model := &ArrayExprModel{ - Kind: arr, - } - if filled { - model.Elems = make([]ExprModel, 0, 2) - } else { - model.Elems = make([]ExprModel, 0, len(s.Exprs)) - } - - mut prefix := self.prefix - self.prefix = arr.Elem - for (_, mut elem) in s.Exprs { - mut d := self.evalExpr(elem) - if d == nil { - continue - } - const destIsRef = false - if self.s.checkValidityForInitExpr(!self.immutable, destIsRef, arr.Elem, d, elem.Token) { - _ = self.s.checkAssignType(destIsRef, arr.Elem, d, elem.Token) - } - model.Elems = append(model.Elems, d.Model) - } - self.prefix = prefix - - if filled { - // Fill mark. - model.Elems = append(model.Elems, nil) - } - - ret &Data{ - Mutable: true, - Kind: &TypeKind{ - Kind: arr, - }, - Model: model, - } - } - - fn evalExpSlc(mut &self, mut s: &SliceExpr, mut t: &TypeKind, mut first: ExprModel): &Data { - mut slc := &Slc{ - Elem: t, - } - - mut i := 0 - mut model := &SliceExprModel{ - ElemKind: t, - Elems: make([]ExprModel, 0, len(s.Exprs)), - } - if first != nil { - model.Elems = append(model.Elems, first) - i = 1 - } - - mut prefix := self.prefix - self.prefix = slc.Elem - for (_, mut elem) in s.Exprs[i:] { - mut d := self.evalExpr(elem) - if d != nil { - const destIsRef = false - if self.s.checkValidityForInitExpr(!self.immutable, destIsRef, slc.Elem, d, elem.Token) { - _ = self.s.checkAssignType(destIsRef, slc.Elem, d, elem.Token) - } - model.Elems = append(model.Elems, d.Model) - } - } - self.prefix = prefix - - ret &Data{ - Mutable: true, - Kind: &TypeKind{ - Kind: slc, - }, - Model: model, - } - } - - fn evalSliceExpr(mut &self, mut s: &SliceExpr): &Data { - if self.prefix != nil { - match { - | self.prefix.Arr() != nil: - ret self.evalArr(s) - | self.prefix.Slc() != nil: - mut pt := self.prefix.Slc() - ret self.evalExpSlc(s, pt.Elem, nil) - } - } - - mut prefix := self.prefix - self.prefix = nil - - if len(s.Exprs) == 0 { - self.pushErr(s.Token, LogMsg.DynamicTypeAnnotationFailed) - ret nil - } - - mut firstElem := self.evalExpr(s.Exprs[0]) - if firstElem == nil { - ret nil - } - - // Check mutability for first element. - const destIsRef = false - self.s.checkValidityForInitExpr(!self.immutable, destIsRef, - firstElem.Kind, firstElem, s.Exprs[0].Token) - - mut d := self.evalExpSlc(s, firstElem.Kind, firstElem.Model) - - self.prefix = prefix - ret d - } - - fn checkIntegerIndexingByData(mut self, mut &d: &Data, mut token: &Token) { - errKey := checkDataForIntegerIndexing(d, token) - match errKey { - | LogMsg.Empty: - ret - | LogMsg.InvalidTypeForIndexing: - self.pushErr(token, errKey, d.Kind.Str()) - |: - self.pushErr(token, errKey) - } - } - - fn indexingPtr(mut self, mut &d: &Data, mut &index: &Data, mut &i: &IndexingExpr) { - self.checkIntegerIndexingByData(index, i.Token) - d.Lvalue = true - - mut ptr := d.Kind.Ptr() - match { - | ptr.IsUnsafe(): - self.pushErr(i.Token, LogMsg.UnsafePtrIndexing) - ret - | !self.isUnsafe(): - self.pushErr(i.Token, LogMsg.UnsafeBehaviorAtOutOfUnsafeScope) - } - - d.Kind = ptr.Elem - } - - fn indexingArr(mut self, mut &d: &Data, mut &index: &Data, mut &i: &IndexingExpr) { - mut arr := d.Kind.Arr() - d.Kind = arr.Elem - self.checkIntegerIndexingByData(index, i.Token) - d.Lvalue = true - if index.IsConst() && index.Constant.AsF64() >= f64(arr.N) { - self.pushErr(i.Token, LogMsg.OverflowLimits) - } - } - - fn indexingSlc(mut self, mut &d: &Data, mut &index: &Data, mut &i: &IndexingExpr) { - mut slc := d.Kind.Slc() - d.Kind = slc.Elem - self.checkIntegerIndexingByData(index, i.Token) - d.Lvalue = true - - // Check compile-time bounds. - if !index.IsConst() { - ret - } - match type d.Model { - | &SliceExprModel: - mut m := (&SliceExprModel)(d.Model) - indx := index.Constant.AsF64() - if indx >= f64(len(m.Elems)) { - self.pushErr(i.Token, LogMsg.OverflowLimits) - } else { - d.Model = m.Elems[u64(indx)] - d.Decl = true // Set Model: flag. - } - } - } - - fn indexingMap(mut self, mut &d: &Data, mut &index: &Data, mut &i: &IndexingExpr) { - d.Lvalue = true - if index == nil { - ret - } - mut m := d.Kind.Map() - mut atc := assignTypeChecker{ - s: self.s, - dest: m.Key, - d: index, - errorToken: i.Token, - } - _ = atc.check() - d.Kind = m.Val - } - - fn indexingStr(mut self, mut &d: &Data, mut &index: &Data, mut &i: &IndexingExpr) { - d.Kind = primU8 // Byte - d.Mutable = false - d.Lvalue = true - - if index == nil { - ret - } - - self.checkIntegerIndexingByData(index, i.Token) - - if !index.IsConst() { - d.Constant = nil - d.untyped = false - ret - } - - if d.IsConst() { - errorToken := i.Token - j := index.Constant.AsI64() - s := d.Constant.ReadStr() - if int(j) >= len(s) { - self.pushErr(errorToken, LogMsg.OverflowLimits) - } else { - d.Constant.SetU64(u64(s[j])) - } - } - } - - fn toIndexing(mut self, mut &d: &Data, mut &index: &Data, mut &i: &IndexingExpr) { - match { - | d.Kind.Ptr() != nil: - self.indexingPtr(d, index, i) - ret - | d.Kind.Arr() != nil: - self.indexingArr(d, index, i) - ret - | d.Kind.Slc() != nil: - self.indexingSlc(d, index, i) - ret - | d.Kind.Map() != nil: - self.indexingMap(d, index, i) - ret - | d.Kind.Prim() != nil: - prim := d.Kind.Prim() - match { - | prim.IsStr(): - self.indexingStr(d, index, i) - ret - } - } - self.pushErr(i.Token, LogMsg.NotSupportsIndexing, d.Kind.Str()) - } - - fn pushGenericsFromExprSubIdent(mut &self, mut &sexpr: &SubIdentExpr, - mut &generics: []&TypeDecl, mut &expr: &Expr): bool { - mut t := new(SubIdentTypeDecl) - if !pushSubIdentFromExpr(sexpr, t) { - self.pushErr(expr.Token, LogMsg.InvalidSyntax) - ret false - } - generics = append(generics, &TypeDecl{Kind: t}) - ret true - } - - fn pushGenericsFromData(mut &self, mut &generics: []&TypeDecl, mut &expr: &Expr): bool { - match type expr.Kind { - | &UnaryExpr: - mut u := (&UnaryExpr)(expr.Kind) - match u.Op.Id { - | TokenId.Star: - mut kind := new(PtrTypeDecl) - mut _generics := make([]&TypeDecl, 0, 1) - self.pushGenericsFromData(_generics, u.Expr) - kind.Elem = _generics[0] - generics = append(generics, &TypeDecl{ - Token: expr.Token, - Kind: kind, - }) - | TokenId.Amper: - mut kind := new(SptrTypeDecl) - mut _generics := make([]&TypeDecl, 0, 1) - self.pushGenericsFromData(_generics, u.Expr) - kind.Elem = _generics[0] - generics = append(generics, &TypeDecl{ - Token: expr.Token, - Kind: kind, - }) - |: - self.pushErr(u.Op, LogMsg.InvalidType) - ret false - } - | &TypeDecl: - generics = append(generics, (&TypeDecl)(expr.Kind)) - | &SubIdentExpr: - mut sexpr := (&SubIdentExpr)(expr.Kind) - ret self.pushGenericsFromExprSubIdent(sexpr, generics, expr) - | &IdentExpr: - mut ident := (&IdentExpr)(expr.Kind) - generics = append(generics, &TypeDecl{ - Kind: &IdentTypeDecl{ - Binded: ident.Binded, - Token: ident.Token, - Ident: ident.Ident, - }, - }) - | &TupleExpr: - for (_, mut texpr) in (&TupleExpr)(expr.Kind).Expr { - if !self.pushGenericsFromData(generics, texpr) { - ret false - } - } - | &NsSelectionExpr: - mut ns := (&NsSelectionExpr)(expr.Kind) - mut decl := &IdentTypeDecl{ - Token: ns.Ident, - Ident: ns.Ident.Kind, - } - generics = append(generics, &TypeDecl{ - Token: decl.Token, - Kind: &NamespaceTypeDecl{ - Idents: ns.Ns, - Kind: &TypeDecl{ - Token: decl.Token, - Kind: decl, - }, - }, - }) - |: - self.pushErr(expr.Token, LogMsg.InvalidSyntax) - ret false - } - ret true - } - - fn evalIdentDeclFromIndexing(mut &self, mut &d: &Data, mut &i: &IndexingExpr) { - mut s := d.Kind.Struct() - if s == nil { - self.pushErr(i.Expr.Token, LogMsg.TypeNotSupportsGenerics, d.Kind.Str()) - d = nil - ret - } - - let mut decl: &IdentTypeDecl = nil - match type i.Expr.Kind { - | &IdentExpr: - mut expr := (&IdentExpr)(i.Expr.Kind) - decl = &IdentTypeDecl{ - Binded: expr.Binded, - Token: expr.Token, - Ident: expr.Ident, - } - | &NsSelectionExpr: - mut expr := (&NsSelectionExpr)(i.Expr.Kind) - decl = &IdentTypeDecl{ - Token: expr.Ident, - Ident: expr.Ident.Kind, - } - |: - self.pushErr(i.Token, LogMsg.InvalidSyntax) - d = nil - ret - } - if !self.pushGenericsFromData(decl.Generics, i.Index) { - d = nil - ret - } - - s = self.typeChecker().fromStruct(decl, s.Decl) - if s == nil { - d = nil - ret - } - d.Kind.Kind = s - } - - // Checks new generics function instance. - // If instance is already exist, f will point to exist instantantiation. - fn checkGenericFn(mut &self, mut &f: &FnIns, mut &et: &Token, mut &model: ExprModel): bool { - ok := self.s.reloadFnInsTypes(f) - f.reloaded = true - if !ok { - ret false - } - mut existInstance := f.Decl.appendInstance(f) - // TODO: [check] is possible to optimize here using same environment with realoadFnInsTypes? - if !self.s.checkConstraintsFn(f, et, existInstance) { - ret false - } - if existInstance != nil { - // Update model and references by exist function instance. - // Generic functions returns always new instance, because might be - // generics are inferred. Therefore, always returns new instance for requests. - // So, if this absolute instance is already exist, update model. - // Otherwise, model's instance will be a dangling, because it never - // be appended into instances of function declaration since already exist. - updateModelToGenericIns(model, existInstance) - updateRefer(self.getOwnerRefers(), f, existInstance) - // Set f to exist one. - f = existInstance - } else { - // Check generic function instance instantly. - self.s.checkFnInsCaller(f, et) - } - ret true - } - - fn evalFnGenericFromIndexing(mut &self, mut &d: &Data, mut &i: &IndexingExpr) { - mut generics := make([]&TypeDecl, 0, 1 << 3) - if !self.pushGenericsFromData(generics, i.Index) { - d = nil - ret - } - - mut f := d.Kind.Fn() - mut genericsLen := 0 - if f.Decl != nil { - genericsLen = len(f.Decl.Generics) - } - if !self.s.checkGenericQuantity(genericsLen, len(generics), i.Expr.Token) { - d = nil - ret - } - - // Build real kinds of generic types. - f.Generics = make([]&InsGeneric, 0, len(f.Decl.Generics)) - for (_, mut g) in generics { - mut k := self.evalType(g) - if k == nil { - d = nil - ret - } - f.Generics = append(f.Generics, &InsGeneric{Kind: k.Kind}) - } - - if f.IsBuiltin() { - ret - } - - if self.checkGenericFn(f, i.Expr.Token, d.Model) { - d.Kind.Kind = f - } else { - d = nil - } - } - - fn evalIndexing(mut &self, mut i: &IndexingExpr): &Data { - mut prefix := self.prefix - self.prefix = nil - defer { self.prefix = prefix } - - mut d := self.evalExprKind(i.Expr.Kind) - if d == nil { - ret nil - } - - // Catch types. - if d.Decl { - self.evalIdentDeclFromIndexing(d, i) - ret d - } - - if d.Kind.Fn() != nil { - self.evalFnGenericFromIndexing(d, i) - ret d - } - - mut oldData := *d - - mut index := self.evalExpr(i.Index) - if index == nil { - ret nil - } - - // Set decl to true. It's a kind of flag. - // If decl is true after indexing eval, do not touch Model:. - // Setted by indexing eval. - d.Decl = false - - self.toIndexing(d, index, i) - if d.IsConst() { - d.Decl = false - d.Model = d.Constant - } else if d.Decl { - d.Decl = false - } else { - d.Model = &IndexingExprModel{ - Token: i.Token, - Expr: new(Data, oldData), - Index: index, - } - } - - ret d - } - - // Returns left and right index values. - // Returns zero integer expression if slicing have not left index. - // So, left index always represents an expression. - // Left data is nil if expression eval failed. - fn evalSlicingExprs(mut &self, mut &s: &SlicingExpr): (&Data, &Data) { - mut prefix := self.prefix - self.prefix = nil - defer { self.prefix = prefix } - - let mut l: &Data = nil - let mut r: &Data = nil - - if s.Start != nil { - l = self.evalExpr(s.Start) - if l != nil { - self.checkIntegerIndexingByData(l, s.Token) - } else { - ret nil, nil - } - } else { - l = &Data{ - Constant: Const.NewI64(0), - Kind: primInt, - } - l.Constant.Kind = PrimKind.Int - l.Model = l.Constant - } - - if s.To != nil { - r = self.evalExpr(s.To) - if r != nil { - self.checkIntegerIndexingByData(r, s.Token) - } else { - ret nil, nil - } - } - - ret l, r - } - - fn slicingArr(self, mut &d: &Data) { - mut elemType := d.Kind.Arr().Elem - d.Kind = &TypeKind{ - Kind: &Slc{ - Elem: elemType, - }, - } - - d.Lvalue = false - - // Keep mutability id already mutable. - // Be mutable, if element is not mutable-type. - d.Mutable = d.Mutable || !elemType.Mutable() - } - - fn slicingStr(self, mut &d: &Data, &l: &Data, &r: &Data) { - d.Lvalue = false - d.Mutable = true - if !d.IsConst() { - ret - } - - if l == nil || r == nil { - d.Constant = nil - d.untyped = false - ret - } - - if l.IsConst() && r.IsConst() { - left := l.Constant.AsI64() - if left < 0 { - ret - } - - s := d.Constant.ReadStr() - mut right := i64(0) - if r == nil { - right = i64(len(s)) - } else { - right = r.Constant.AsI64() - } - - if left > right { - ret - } - d.Constant.SetStr(s[left:right]) - d.Decl = true // Set Model: flag. - } else { - d.Constant = nil - d.untyped = false - } - } - - fn checkSlicing(mut self, mut &d: &Data, &l: &Data, &r: &Data, &s: &SlicingExpr) { - match { - | d.Kind.Arr() != nil: - self.slicingArr(d) - ret - | d.Kind.Slc() != nil: - ret - | d.Kind.Prim() != nil: - prim := d.Kind.Prim() - match { - | prim.IsStr(): - self.slicingStr(d, l, r) - ret - } - } - - self.pushErr(s.Token, LogMsg.NotSupportsSlicing, d.Kind.Str()) - } - - fn evalSlicing(mut &self, mut s: &SlicingExpr): &Data { - mut d := self.evalExpr(s.Expr) - if d == nil { - ret nil - } - - mut l, mut r := self.evalSlicingExprs(s) - if l == nil { - ret d - } - - // Set decl to true. It's a kind of flag. - // If decl is true after indexing eval, do not touch Model:. - // Setted by indexing eval. - d.Decl = false - - self.checkSlicing(d, l, r, s) - - if d.IsConst() { - d.Decl = false - d.Model = d.Constant - } else if d.Decl { - d.Decl = false - } else { - mut model := &SlicingExprModel{ - Token: s.Token, - Expr: d.Model, - Left: l.Model, - } - if r != nil { - model.Right = r.Model - } - d.Model = model - } - ret d - } - - fn castPtr(mut self, mut t: &TypeKind, mut d: &Data, errorToken: &Token) { - d.Constant = nil - d.untyped = false - sptr := d.Kind.Sptr() - if sptr != nil { - if !t.Ptr().Elem.Equal(sptr.Elem) { - self.pushErr(errorToken, LogMsg.TypeNotSupportsCastingTo, d.Kind.Str(), t.Str()) - } - ret - } - - if !self.isUnsafe() { - self.pushErr(errorToken, LogMsg.UnsafeBehaviorAtOutOfUnsafeScope) - ret - } - - prim := d.Kind.Prim() - if d.Kind.Ptr() == nil && (prim == nil || !types::IsInt(prim.Str())) { - self.pushErr(errorToken, LogMsg.TypeNotSupportsCastingTo, d.Kind.Str(), t.Str()) - } - } - - fn castStruct(mut self, mut t: &TypeKind, mut d: &Data, errorToken: &Token) { - d.Constant = nil - d.untyped = false - mut tr := d.Kind.Trait() - if tr == nil { - self.pushErr(errorToken, LogMsg.TypeNotSupportsCastingTo, d.Kind.Str(), t.Str()) - ret - } - - mut s := t.Struct() - self.pushReference[&StructIns](s) - - if !s.Decl.IsImplements(tr) { - self.pushErr(errorToken, LogMsg.TypeNotSupportsCastingTo, d.Kind.Str(), t.Str()) - } - } - - fn castRef(mut self, mut t: &TypeKind, mut d: &Data, errorToken: &Token) { - d.Constant = nil - d.untyped = false - mut sptr := t.Sptr() - - mut ptr := d.Kind.Ptr() - if ptr != nil && sptr.Elem.Equal(ptr.Elem) { - if !self.isUnsafe() { - self.pushErr(errorToken, LogMsg.UnsafeBehaviorAtOutOfUnsafeScope) - } - // Ok. - ret - } - - // For traits. - if sptr.Elem.Struct() != nil { - self.castStruct(sptr.Elem, d, errorToken) - ret - } - - self.pushErr(errorToken, LogMsg.TypeNotSupportsCastingTo, d.Kind.Str(), t.Str()) - } - - fn castSlc(mut self, mut t: &TypeKind, mut d: &Data, errorToken: &Token) { - c := d.Constant - d.Constant = nil - d.untyped = false - - if d.Kind.Enum() != nil { - if d.Kind.Enum().Kind.Kind.Prim() == nil || !d.Kind.Enum().Kind.Kind.Prim().IsStr() { - self.pushErr(errorToken, LogMsg.TypeNotSupportsCastingTo, d.Kind.Str(), t.Str()) - ret - } - } else if d.Kind.Prim() == nil || !d.Kind.Prim().IsStr() { - self.pushErr(errorToken, LogMsg.TypeNotSupportsCastingTo, d.Kind.Str(), t.Str()) - ret - } - - t = t.Slc().Elem - prim := t.Prim() - if prim == nil || (!prim.IsU8() && !prim.IsI32()) { - self.pushErr(errorToken, LogMsg.TypeNotSupportsCastingTo, d.Kind.Str(), t.Str()) - ret - } - - // Cast constant expressions. - if c != nil { - match { - | prim.IsU8(): - s := c.ReadStr() - mut model := &SliceExprModel{ - ElemKind: t, - Elems: make([]ExprModel, 0, len(s)), - } - for _, b in s { - mut bc := Const.NewU64(u64(b)) - bc.Kind = prim.Kind - model.Elems = append(model.Elems, bc) - } - d.Model = model - d.Decl = true // Prevent model changing. - | prim.IsI32(): - runes := []rune(c.ReadStr()) - mut model := &SliceExprModel{ - ElemKind: t, - Elems: make([]ExprModel, 0, len(runes)), - } - for _, r in runes { - mut rc := Const.NewI64(i64(r)) - rc.Kind = prim.Kind - model.Elems = append(model.Elems, rc) - } - d.Model = model - d.Decl = true // Prevent model changing. - } - } - } - - fn castStr(mut self, mut d: &Data, errorToken: &Token) { - if d.Kind.Enum() != nil { - mut e := d.Kind.Enum() - if e.Kind.Kind.Prim() != nil && e.Kind.Kind.Prim().IsStr() { - ret - } - } - - c := d.Constant - d.Constant = nil - d.untyped = false - if d.Kind.Prim() != nil { - prim := d.Kind.Prim() - if !prim.IsU8() && !prim.IsI32() { - self.pushErr(errorToken, LogMsg.TypeNotSupportsCastingTo, PrimKind.Str, d.Kind.Str()) - ret - } - // Cast constant expressions. - if c != nil { - match { - | prim.IsU8(): - d.Constant = Const.NewStr(str(byte(c.AsU64()))) - d.Model = d.Constant - d.Decl = true // Prevent model changing. - | prim.IsI32(): - d.Constant = Const.NewStr(str(rune(c.AsI64()))) - d.Model = d.Constant - d.Decl = true // Prevent model changing. - } - } - ret - } - - mut s := d.Kind.Slc() - if s == nil { - self.pushErr(errorToken, LogMsg.TypeNotSupportsCastingTo, PrimKind.Str, d.Kind.Str()) - ret - } - - mut t := s.Elem - prim := t.Prim() - if prim == nil || (!prim.IsU8() && !prim.IsI32()) { - self.pushErr(errorToken, LogMsg.TypeNotSupportsCastingTo, PrimKind.Str, d.Kind.Str()) - ret - } - } - - fn castInt(mut self, mut t: &TypeKind, mut d: &Data, errorToken: &Token) { - if d.IsConst() { - prim := t.Prim() - match { - | types::IsSigInt(prim.Kind): - d.Constant.SetI64(d.Constant.AsI64()) - | types::IsUnsigInt(prim.Kind): - d.Constant.SetU64(d.Constant.AsU64()) - } - } else { - d.Constant = nil - d.untyped = false - } - - if d.Kind.Enum() != nil { - e := d.Kind.Enum() - if types::IsNum(e.Kind.Kind.Str()) { - ret - } - } - - if d.Kind.Sptr() != nil { - prim := t.Prim() - if !prim.IsUintptr() { - self.pushErr(errorToken, LogMsg.TypeNotSupportsCastingTo, d.Kind.Str(), t.Str()) - } - ret - } - if d.Kind.Ptr() != nil { - prim := t.Prim() - if prim.IsUintptr() { - // Ignore case. - } else if !self.isUnsafe() { - self.pushErr(errorToken, LogMsg.UnsafeBehaviorAtOutOfUnsafeScope) - } - ret - } - - prim := d.Kind.Prim() - if prim != nil && types::IsNum(prim.Str()) { - ret - } - - self.pushErr(errorToken, LogMsg.TypeNotSupportsCastingTo, d.Kind.Str(), t.Str()) - } - - fn castNum(mut self, mut t: &TypeKind, mut d: &Data, errorToken: &Token) { - if d.IsConst() { - prim := t.Prim() - match { - | types::IsFloat(prim.Kind): - d.Constant.SetF64(d.Constant.AsF64()) - | types::IsSigInt(prim.Kind): - d.Constant.SetI64(d.Constant.AsI64()) - | types::IsUnsigInt(prim.Kind): - d.Constant.SetU64(d.Constant.AsU64()) - } - } else { - d.Constant = nil - d.untyped = false - } - - if d.Kind.Enum() != nil { - e := d.Kind.Enum() - if types::IsNum(e.Kind.Kind.Str()) { - ret - } - } - - prim := d.Kind.Prim() - if prim != nil && types::IsNum(prim.Str()) { - ret - } - - self.pushErr(errorToken, LogMsg.TypeNotSupportsCastingTo, d.Kind.Str(), t.Str()) - } - - fn castPrim(mut self, mut t: &TypeKind, mut d: &Data, errorToken: &Token) { - prim := t.Prim() - match { - | prim.IsAny(): - // The any type supports casting to any data type. - d.Constant = nil - d.untyped = false - | prim.IsStr(): - self.castStr(d, errorToken) - | types::IsInt(prim.Str()): - self.castInt(t, d, errorToken) - | types::IsNum(prim.Str()): - self.castNum(t, d, errorToken) - |: - self.pushErr(errorToken, LogMsg.TypeNotSupportsCasting, t.Str()) - } - } - - fn castConstant(mut self, mut &t: &TypeKind, mut &d: &Data) { - if d == nil || !d.IsConst() { - ret - } - prim := t.Prim() - castConstByType(prim.Kind, d) - d.Model = d.Constant - } - - fn castTypeEnum(mut self, mut &t: &TypeKind, mut &d: &Data, mut &errorToken: &Token) { - n := len(self.s.errors) - if !self.s.checkTypeCompatibility(d.Kind, t, errorToken) { - self.s.errors = self.s.errors[:n] - self.pushErr(errorToken, LogMsg.TypeNotSupportsCastingTo, d.Kind.Str(), t.Str()) - } - d.Constant = nil - d.untyped = false - } - - fn castTypeEnumT(mut self, mut &t: &TypeKind, mut &d: &Data, mut &errorToken: &Token) { - n := len(self.s.errors) - if !self.s.checkTypeCompatibility(t, d.Kind, errorToken) { - self.s.errors = self.s.errors[:n] - self.pushErr(errorToken, LogMsg.TypeNotSupportsCastingTo, d.Kind.Str(), t.Str()) - } - d.Constant = nil - d.untyped = false - } - - fn evalCastByTypeNData(mut self, mut t: &TypeKind, mut d: &Data, mut errorToken: &Token): &Data { - if d != nil && d.Decl { - self.pushErr(errorToken, LogMsg.InvalidExpr) - ret nil - } - - match { - | d.IsNil(): - if !t.NilCompatible() { - self.pushErr(errorToken, LogMsg.TypeNotSupportsCastingTo, "", t.Str()) - } - d.Constant = nil // Remove nil constant. - d.untyped = false - | d.Kind.Prim() != nil && d.Kind.Prim().IsAny(): - if t.Enum() != nil { - self.pushErr(errorToken, LogMsg.EnumCastedFromAny) - self.pushSuggestion(LogMsg.CastToEnumTypeInsteadOfEnum) - } else if t.TypeEnum() != nil { - self.pushErr(errorToken, LogMsg.EnumCastedFromAny) - } - d.Constant = nil - d.untyped = false - | d.Kind.TypeEnum() != nil: - self.castTypeEnum(t, d, errorToken) - | t.TypeEnum() != nil: - self.castTypeEnumT(t, d, errorToken) - | t.Ptr() != nil: - self.castPtr(t, d, errorToken) - | t.Sptr() != nil: - self.castRef(t, d, errorToken) - | t.Slc() != nil: - self.castSlc(t, d, errorToken) - | t.Struct() != nil: - self.castStruct(t, d, errorToken) - | t.Prim() != nil: - self.castPrim(t, d, errorToken) - self.castConstant(t, d) - |: - self.pushErr(errorToken, LogMsg.TypeNotSupportsCasting, t.Str()) - d = nil - } - - if d == nil { - ret nil - } - - // Keep mutability if data is already mutable. - // Even if the data is not mutable, set as mutable if the type is not mutable-type. - d.Mutable = d.Mutable || !d.Kind.Mutable() - - if !d.Decl && (d.Kind.Enum() == nil || !d.Kind.Enum().Kind.Kind.Equal(t)) { - applyCastKind(d, t, errorToken) - (&CastingExprModel)(d.Model).Token = errorToken - } else { - d.Kind = t - } - - // Remove flag. - // The variable d cannot be d.Decl true because of checked already. - // Therefore this field used as flag to say "do not touch to expression model". - // So, if d.Decl is true, model will not be changed. - d.Decl = false - - d.Lvalue = false - d.untyped = false - - if d.IsConst() { - d.Constant.Kind = t.Prim().Kind - } - - ret d - } - - fn evalCastT(mut &self, mut &t: &TypeKind, mut &e: &Expr, mut &et: &Token): &Data { - mut prefix := self.prefix - self.prefix = nil - defer { self.prefix = prefix } - if t.Slc() != nil { - match type e.Kind { - | &SliceExpr: - self.prefix = t - } - } - mut d := self.evalExpr(e) - if d == nil || self.prefix != nil { - ret d - } - ret self.evalCastByTypeNData(t, d, et) - } - - fn evalCast(mut &self, mut c: &CastExpr): &Data { - mut t := buildType(c.Kind) - ok := self.s.checkType(t, self.lookup) - if !ok { - ret nil - } - ret self.evalCastT(t.Kind, c.Expr, c.Kind.Token) - } - - fn evalNsSelection(mut self, s: &NsSelectionExpr): &Data { - path := buildLinkPathByTokens(s.Ns) - mut imp := self.lookup.SelectPackage(fn(imp: &ImportInfo): bool { - if len(s.Ns) == 1 && imp.Alias == path { - ret true - } - ret imp.LinkPath == path && imp.isAccessibleViaSelection() - }) - - if imp == nil { - self.pushErr(s.Ns[0], LogMsg.NamespaceNotExist, path) - ret nil - } - - mut lookup := self.lookup - self.lookup = imp - - const Binded = false - self.disallowBuiltin() - mut def := self.getDef(s.Ident.Kind, Binded) - self.allowBuiltin() - self.lookup = lookup - mut d := self.evalDef(def, s.Ident) - ret d - } - - fn evalStructLitExplicit(mut &self, mut s: &StructIns, - mut exprs: []&Expr, mut errorToken: &Token): &Data { - ok := self.s.checkGenericQuantity(len(s.Decl.Generics), len(s.Generics), errorToken) - if !ok { - ret nil - } - // NOTICE: Instance already checked (just fields) if generic quantity passes. - - if self.field != nil && self.field.Decl.Owner == s.Decl { - self.pushErr(errorToken, LogMsg.IllegalCycleRefersItself, s.Decl.Ident) - } - - self.pushReference[&StructIns](s) - self.checkDeprecated(s.Decl.Directives, errorToken) - - mut slc := structLitChecker{ - e: self, - errorToken: errorToken, - s: s, - } - slc.check(exprs) - - mut d := &Data{ - Mutable: !self.immutable, - Kind: &TypeKind{ - Kind: s, - }, - Model: &StructLitExprModel{ - Strct: s, - Args: slc.args, - }, - } - if s.Decl.Binded { - d.Kind.BindIdent = s.Decl.Ident - } - ret d - } - - fn evalStructLit(mut &self, mut lit: &StructLit): &Data { - mut t := buildType(lit.Kind) - ok := self.s.checkType(t, self.lookup) - if !ok { - ret nil - } - - mut s := t.Kind.Struct() - if s == nil { - if t.Kind.Sptr() != nil { - s = t.Kind.Sptr().Elem.Struct() - if s != nil { - goto eval - } - } - self.pushErr(lit.Kind.Token, LogMsg.InvalidSyntax) - ret nil - } - - eval: - mut d := self.evalStructLitExplicit(s, lit.Exprs, lit.Kind.Token) - if t.Kind.Sptr() != nil { - mut model := (&StructLitExprModel)(d.Model) - makeStructLitAlloc(d, model) - } - ret d - } - - fn typeChecker(mut self): typeChecker { - ret self.s.typeChecker(self.lookup, nil, nil) - } - - fn evalType(mut self, mut t: &TypeDecl): &Data { - mut tk := buildType(t) - ok := self.s.checkType(tk, self.lookup) - if !ok { - ret nil - } - ret &Data{ - Decl: true, - Kind: tk.Kind, - Model: tk.Kind, - } - } - - fn callTypeFn(mut &self, mut &fc: &FnCallExpr, mut &d: &Data) { - if len(fc.Args) < 1 { - self.pushErr(fc.Token, LogMsg.MissingExprFor, "v") - } else if len(fc.Args) > 1 { - self.pushErr(fc.Args[1].Token, LogMsg.ArgumentOverflow, d.Kind.Str()) - } else if fc.IsCo { - self.pushErr(fc.Token, LogMsg.CoForCastingCall) - d = nil - ret - } else if fc.Exception != nil { - self.pushErr(fc.Token, LogMsg.TypeCallWithExceptional) - d = nil - ret - } - - if len(fc.Args) > 0 { - mut arg := fc.Args[0] - d = self.evalCastT(d.Kind, arg, arg.Token) - ret - } - - if d != nil { - d.Decl = false - } - } - - fn callBuiltinFn(mut &self, mut &fc: &FnCallExpr, mut &d: &Data) { - if !fc.Unhandled() { // Exceptional handled? - // Built-in functions are not exceptional. - self.pushErr(fc.Token, LogMsg.HandledUnexceptional) - } - d = d.Kind.Fn().caller(self, fc, d) - if d == nil { - ret - } - d.Mutable = true - } - - fn checkFnOfConcurrentCall(mut self, &f: &FnIns, errorToken: &Token) { - if self.isUnsafe() { - ret - } - for _, p in f.Params { - if p.Decl.IsSelf() { - if !p.Decl.IsRef() { - self.pushErr(errorToken, LogMsg.ConcurrentCallWithSelfParam) - self.pushSuggestion(LogMsg.UseUnsafeJuleToCallCoSelf) - } - } - if p.Decl.Reference { - self.pushErr(errorToken, LogMsg.ConcurrentCallWithRefParam) - self.pushSuggestion(LogMsg.UseUnsafeJuleToCallCo) - ret - } - } - } - - fn processExceptionalHandler(mut self, mut &f: &FnIns, mut &fc: &FnCallExpr, mut &d: &Data) { - resultNeeded := !f.Decl.IsVoid() && (self.arg || !self.ignored) - let mut csc: &scopeChecker = nil - let mut ch: &Scope = nil - - mut model := (&FnCallExprModel)(d.Model) - - // self.lookup is always scopeChecker because exceptionals are - // not allowed in global scope. - mut sc := (&scopeChecker)(self.lookup) - csc = sc.newChildChecker() - if resultNeeded { - csc.result = f - } - ch = sc.getChild() - fc.Exception.Parent = sc.tree - csc.table.Vars = append(csc.table.Vars, buildErrorVar(ch, fc)) - sc.checkChildSsc(fc.Exception, ch, csc) - - model.Assigned = resultNeeded - model.Except = ch - - if resultNeeded && csc.result != nil { - self.pushErr(fc.Token, LogMsg.MissingAssignRet) - } - } - - fn callFn(mut &self, mut &fc: &FnCallExpr, mut &d: &Data) { - mut f := d.Kind.Fn() - if f.IsBuiltin() { - self.callBuiltinFn(fc, d) - ret - } - if self.isGlobal() && f.Decl.Exceptional { - self.pushErr(fc.Token, LogMsg.ExceptionalAtGlobalScope) - self.pushSuggestion(LogMsg.WrapExceptional) - d = nil - ret - } - - if !f.Decl.IsMethod() && hasDirective(f.Decl.Directives, Directive.Test) { - self.pushErr(fc.Token, LogMsg.TestCalled) - d = nil - ret - } - - if !d.Mutable && f.Decl.IsMethod() && !f.Decl.Statically && f.Decl.Params[0].Mutable { - if !self.immutable { - self.pushErr(fc.Token, LogMsg.MutOperationOnImmut) - } else { - // Caught mutability risk of immutable literals. - // Literal will not be assigned to immutable memory, - // used to call method with mutable receiver. - // Assume literal as mutable and check accordingly. - lit := isLitBased(d.Model) - if lit == nil { - // Expression is not literal based, so data is strictly immutable. - self.pushErr(fc.Token, LogMsg.MutOperationOnImmut) - } else { - checkMutRiskOfStructLit(self.s, lit) - } - } - } else if !self.isUnsafe() && f.Decl.Unsafety { - self.pushErr(fc.Token, LogMsg.UnsafeBehaviorAtOutOfUnsafeScope) - } - - mut dynamicAnnotation := len(f.Decl.Generics) > 0 && len(f.Generics) == 0 && len(f.Params) > 0 - if dynamicAnnotation { - f.Generics = make([]&InsGeneric, len(f.Decl.Generics)) - } else if len(f.Generics) != len(f.Decl.Generics) { - _ = self.s.checkGenericQuantity(len(f.Decl.Generics), len(f.Generics), fc.Token) - d = nil - ret - } - - mut old := self.s - if f.Decl.Owner != nil { - self.s = f.Decl.Owner.sema - } - - defer { - if old != self.s { - old.errors = append(old.errors, self.s.errors...) - self.s.errors = nil - } - self.s = old - } - - mut fcac := fnCallArgChecker{ - e: self, - args: fc.Args, - dynamicAnnotation: dynamicAnnotation, - errorToken: fc.Token, - } - - if !dynamicAnnotation { - if !f.reloaded { - ok := self.s.reloadFnInsTypes(f) - f.reloaded = true - if !ok { - d = nil - ret - } - } - mut existInstance := f.Decl.appendInstance(f) - if existInstance != nil { - f = existInstance - } - } else if !self.s.buildFnNonGenericTypeKinds(f, fcac.ignored) { - d = nil - ret - } - - fcac.f = f - - mut ok := false - if f.Decl.Owner != nil { - old, self.s = self.s, old // Save current Sema. - ok = fcac.check() - old, self.s = self.s, old // Save owner Sema. - } else { - ok = fcac.check() - } - - if dynamicAnnotation { - if !ok { - d = nil - ret - } - if !self.checkGenericFn(f, fc.Token, d.Model) { - d = nil - ret - } - } - - mut callModel := d.Model - - if f.Decl.IsVoid() { - d = buildVoidData() - } else { - d.Kind = f.Result - d.Lvalue = false - } - - mut model := &FnCallExprModel{ - Token: fc.Token, - Func: f, - Expr: callModel, - Args: fcac.argModels, - IsCo: fc.IsCo, - } - d.Model = model - d.Mutable = true - - if f.Decl.Exceptional { - if fc.IsCo { - self.s.pushErr(fc.Token, LogMsg.CoForExceptional) - self.s.pushSuggestion(LogMsg.HandleInFn) - } - match { - | fc.Unhandled(): - self.pushErr(fc.Token, LogMsg.UnhandledExceptional) - self.pushSuggestion(LogMsg.HandleExceptional) - | fc.Ignored(): - // Ok. - break - |: - // Handled with scope. - self.processExceptionalHandler(f, fc, d) - } - } else if !fc.Unhandled() { - self.pushErr(fc.Token, LogMsg.HandledUnexceptional) - } - - if fc.IsCo { - self.checkFnOfConcurrentCall(model.Func, fc.Token) - } - } - - fn evalFnCall(mut &self, mut fc: &FnCallExpr): &Data { - mut prefix := self.prefix - self.prefix = nil - defer { self.prefix = prefix } - - match type fc.Expr.Kind { - | &IdentExpr: - // Use fc.expr.Token.Kind instead of casting. - // Same thing, but more efficient and performant. - if fc.Expr.Token.Kind == TokenKind.Error { - ret builtinCallerError(self, fc) - } - } - - mut d := self.evalExprKind(fc.Expr.Kind) - if d == nil { - ret nil - } - - if d.Decl { - self.callTypeFn(fc, d) - ret d - } - - if d.Kind.Fn() == nil { - self.pushErr(fc.Token, LogMsg.CallingNonFn) - ret nil - } - - self.callFn(fc, d) - ret d - } - - fn evalEnumStatic(mut self, mut enm: &Enum, mut ident: &Token): &Data { - mut item := enm.FindItem(ident.Kind) - if item == nil { - self.pushErr(ident, LogMsg.ObjHaveNotIdent, enm.Ident, ident.Kind) - } - ret evalEnumStatic(enm, item, ident) - } - - fn evalTypeEnumStatic(mut self, mut enm: &TypeEnum, ident: &Token): &Data { - mut item := enm.FindItem(ident.Kind) - if item == nil { - self.pushErr(ident, LogMsg.ObjHaveNotIdent, enm.Ident, ident.Kind) - ret nil - } - match { - | item.Kind.Kind.Enum() != nil: - ret self._evalEnum(item.Kind.Kind.Enum()) - | item.Kind.Kind.TypeEnum() != nil: - ret self._evalTypeEnum(item.Kind.Kind.TypeEnum()) - | item.Kind.Kind.Struct() != nil: - ret self._evalStruct(item.Kind.Kind.Struct()) - |: - mut d := &Data{ - Decl: true, - Kind: item.Kind.Kind, - } - d.Model = d.Kind - ret d - } - } - - fn evalStructStatic(mut self, mut s: &StructIns, ident: &Token): &Data { - mut d := new(Data) - - // Method. - const Static = true - mut method := s.FindMethod(ident.Kind, Static) - if method != nil { - if !self.s.isAccessibleDefine(method.Public, method.Token) { - self.pushErr(ident, LogMsg.IdentIsNotAccessible, ident.Kind) - self.pushSuggestion(LogMsg.MakePubToAccess) - } - - mut ins := method.instance() - ins.Owner = s - self.pushReference[&FnIns](ins) - d.Model = &StructStaticIdentExprModel{ - Structure: s, - Expr: d.Model, - Method: ins, - } - d.Kind = &TypeKind{ - Kind: ins, - } - ret d - } - - mut sttc := s.FindStatic(ident.Kind) - if sttc != nil { - ret self.evalVar(sttc, ident) - } - - self.pushErr(ident, LogMsg.ObjHaveNotIdent, s.Decl.Ident, ident.Kind) - ret nil - } - - fn evalTraitSubIdent(mut self, mut d: &Data, mut trt: &Trait, mut ident: &Token): &Data { - mut f := trt.FindMethod(ident.Kind) - if f == nil { - self.pushErr(ident, LogMsg.ObjHaveNotIdent, trt.Ident, ident.Kind) - ret nil - } - ret &Data{ - Kind: &TypeKind{ - Kind: f.instance(), - }, - Model: &TraitSubIdentExprModel{ - Token: ident, - Expr: d.Model, - Method: f, - Trt: trt, - }, - } - } - - // This method evaluates expressions, will not check public availability. - fn evalStructSubIdentField(mut self, mut &d: &Data, mut &s: &StructIns, mut &tok: &Token, mut &f: &FieldIns): &Data { - mut model := &StructSubIdentExprModel{ - Token: tok, - Expr: new(Data, *d), - Field: f, - Owner: s, - } - d.Model = model - d.Kind = f.Kind - d.Lvalue = true - - if f.Decl.Mutable && !d.Mutable { - // Interior mutability. - match type self.lookup { - | &scopeChecker: - scope := (&scopeChecker)(self.lookup).getRoot() - d.Mutable = scope.owner != nil && scope.owner.Owner == s - } - } - - ret d - } - - fn evalStructSubIdent(mut self, mut d: &Data, mut s: &StructIns, mut si: &SubIdentExpr, ref: bool): &Data { - mut f := s.FindField(si.Ident.Kind) - if f != nil { - if !self.s.isAccessibleDefine(f.Decl.Public, f.Decl.Token) { - self.pushErr(si.Ident, LogMsg.IdentIsNotAccessible, f.Decl.Ident) - self.pushSuggestion(LogMsg.MakePubToAccess) - } - ret self.evalStructSubIdentField(d, s, si.Ident, f) - } - - const Static = false - mut m := s.FindMethod(si.Ident.Kind, Static) - if m == nil { - self.pushErr(si.Ident, LogMsg.ObjHaveNotIdent, s.Decl.Ident, si.Ident.Kind) - ret nil - } - if !self.s.isAccessibleDefine(m.Public, m.Token) { - self.pushErr(si.Ident, LogMsg.IdentIsNotAccessible, m.Ident) - self.pushSuggestion(LogMsg.MakePubToAccess) - } - - if m.Params[0].IsRef() && !ref { - self.pushErr(si.Ident, LogMsg.RefMethodUsedWithNotRefInstance) - } - - self.checkDeprecated(m.Directives, si.Ident) - - mut ins := m.instance() - ins.Owner = s - self.pushReference[&FnIns](ins) - mut model := new(Data, *d) - d.Model = &StructSubIdentExprModel{ - Token: si.Ident, - Expr: model, - Method: ins, - Owner: s, - } - d.Kind = &TypeKind{Kind: ins} - ret d - } - - fn evalIntTypeStatic(mut self, ident: &Token): &Data { - const kind: str = PrimKind.Int - match ident.Kind { - | "Max": - mut c := Const.NewI64(types::MaxI(kind)) - c.Kind = kind - ret &Data{ - Constant: c, - Model: c, - Kind: primInt, - untyped: true, - } - | "Min": - mut c := Const.NewI64(i64(types::Min(kind))) - c.Kind = kind - ret &Data{ - Constant: c, - Model: c, - Kind: primInt, - untyped: true, - } - |: - self.pushErr(ident, LogMsg.TypeHaveNotIdent, kind, ident.Kind) - ret nil - } - } - - fn evalUintTypeStatic(mut self, ident: &Token): &Data { - const kind: str = PrimKind.Uint - match ident.Kind { - | "Max": - mut c := Const.NewU64(types::MaxU(kind)) - c.Kind = kind - ret &Data{ - Constant: c, - Model: c, - Kind: primUint, - untyped: true, - } - |: - self.pushErr(ident, LogMsg.TypeHaveNotIdent, kind, ident.Kind) - ret nil - } - } - - fn evalI8TypeStatic(mut self, ident: &Token): &Data { - const kind: str = PrimKind.I8 - const min = types::MinI8 - const max = types::MaxI8 - match ident.Kind { - | "Max": - mut c := Const.NewI64(max) - c.Kind = kind - ret &Data{ - Constant: c, - Model: c, - Kind: primI8, - untyped: true, - } - | "Min": - mut c := Const.NewI64(min) - c.Kind = kind - ret &Data{ - Constant: c, - Model: c, - Kind: primI8, - untyped: true, - } - |: - self.pushErr(ident, LogMsg.TypeHaveNotIdent, kind, ident.Kind) - ret nil - } - } - - fn evalI16TypeStatic(mut self, ident: &Token): &Data { - const kind: str = PrimKind.I16 - const min = types::MinI16 - const max = types::MaxI16 - match ident.Kind { - | "Max": - mut c := Const.NewI64(max) - c.Kind = kind - ret &Data{ - Constant: c, - Model: c, - Kind: primI16, - untyped: true, - } - | "Min": - mut c := Const.NewI64(min) - c.Kind = kind - ret &Data{ - Constant: c, - Model: c, - Kind: primI16, - untyped: true, - } - |: - self.pushErr(ident, LogMsg.TypeHaveNotIdent, kind, ident.Kind) - ret nil - } - } - - fn evalI32TypeStatic(mut self, ident: &Token): &Data { - const kind: str = PrimKind.I32 - const min = types::MinI32 - const max = types::MaxI32 - match ident.Kind { - | "Max": - mut c := Const.NewI64(max) - c.Kind = kind - ret &Data{ - Constant: c, - Model: c, - Kind: primI32, - untyped: true, - } - | "Min": - mut c := Const.NewI64(min) - c.Kind = kind - ret &Data{ - Constant: c, - Model: c, - Kind: primI32, - untyped: true, - } - |: - self.pushErr(ident, LogMsg.TypeHaveNotIdent, kind, ident.Kind) - ret nil - } - } - - fn evalI64TypeStatic(mut self, ident: &Token): &Data { - const kind: str = PrimKind.I64 - const min = types::MinI64 - const max = types::MaxI64 - match ident.Kind { - | "Max": - mut c := Const.NewI64(max) - c.Kind = kind - ret &Data{ - Constant: c, - Model: c, - Kind: primI64, - untyped: true, - } - | "Min": - mut c := Const.NewI64(min) - c.Kind = kind - ret &Data{ - Constant: c, - Model: c, - Kind: primI64, - untyped: true, - } - |: - self.pushErr(ident, LogMsg.TypeHaveNotIdent, kind, ident.Kind) - ret nil - } - } - - fn evalU8TypeStatic(mut self, ident: &Token): &Data { - const kind: str = PrimKind.U8 - const max = types::MaxU8 - match ident.Kind { - | "Max": - mut c := Const.NewU64(max) - c.Kind = kind - ret &Data{ - Constant: c, - Model: c, - Kind: primU8, - untyped: true, - } - |: - self.pushErr(ident, LogMsg.TypeHaveNotIdent, kind, ident.Kind) - ret nil - } - } - - fn evalU16TypeStatic(mut self, ident: &Token): &Data { - const kind: str = PrimKind.U16 - const max = types::MaxU16 - match ident.Kind { - | "Max": - mut c := Const.NewU64(max) - c.Kind = kind - ret &Data{ - Constant: c, - Model: c, - Kind: primU16, - untyped: true, - } - |: - self.pushErr(ident, LogMsg.TypeHaveNotIdent, kind, ident.Kind) - ret nil - } - } - - fn evalU32TypeStatic(mut self, ident: &Token): &Data { - const kind: str = PrimKind.U32 - const max = types::MaxU32 - match ident.Kind { - | "Max": - mut c := Const.NewU64(max) - c.Kind = kind - ret &Data{ - Constant: c, - Model: c, - Kind: primU32, - untyped: true, - } - |: - self.pushErr(ident, LogMsg.TypeHaveNotIdent, kind, ident.Kind) - ret nil - } - } - - fn evalU64TypeStatic(mut self, ident: &Token): &Data { - const kind: str = PrimKind.U64 - const max = types::MaxU64 - match ident.Kind { - | "Max": - mut c := Const.NewU64(max) - c.Kind = kind - ret &Data{ - Constant: c, - Model: c, - Kind: primU64, - untyped: true, - } - |: - self.pushErr(ident, LogMsg.TypeHaveNotIdent, kind, ident.Kind) - ret nil - } - } - - fn evalF32TypeStatic(mut self, ident: &Token): &Data { - const kind = PrimKind.F32 - const max = types::MaxF32 - const min = types::MinF32 - const smallestNonZero = types::SmallestNonZeroF32 - match ident.Kind { - | "Max": - mut c := Const.NewF64(max) - c.Kind = kind - ret &Data{ - Constant: c, - Model: c, - Kind: primF32, - untyped: true, - } - | "Min": - mut c := Const.NewF64(min) - c.Kind = kind - ret &Data{ - Constant: c, - Model: c, - Kind: primF32, - untyped: true, - } - | "SmallestNonZero": - mut c := Const.NewF64(smallestNonZero) - c.Kind = kind - ret &Data{ - Constant: c, - Model: c, - Kind: primF32, - untyped: true, - } - |: - self.pushErr(ident, LogMsg.TypeHaveNotIdent, kind, ident.Kind) - ret nil - } - } - - fn evalF64TypeStatic(mut self, ident: &Token): &Data { - const kind = PrimKind.F64 - const max = types::MaxF64 - const min = types::MinF64 - const smallestNonZero = types::SmallestNonZeroF64 - match ident.Kind { - | "Max": - mut c := Const.NewF64(max) - c.Kind = kind - ret &Data{ - Constant: c, - Model: c, - Kind: primF64, - untyped: true, - } - | "Min": - mut c := Const.NewF64(min) - c.Kind = kind - ret &Data{ - Constant: c, - Model: c, - Kind: primF64, - untyped: true, - } - | "SmallestNonZero": - mut c := Const.NewF64(smallestNonZero) - c.Kind = kind - ret &Data{ - Constant: c, - Model: c, - Kind: primF64, - untyped: true, - } - |: - self.pushErr(ident, LogMsg.TypeHaveNotIdent, kind, ident.Kind) - ret nil - } - } - - fn evalPrimStatic(mut self, kind: str, ident: &Token): &Data { - match kind { - | PrimKind.Int: - ret self.evalIntTypeStatic(ident) - | PrimKind.Uint: - ret self.evalUintTypeStatic(ident) - | PrimKind.I8: - ret self.evalI8TypeStatic(ident) - | PrimKind.I16: - ret self.evalI16TypeStatic(ident) - | PrimKind.I32: - ret self.evalI32TypeStatic(ident) - | PrimKind.I64: - ret self.evalI64TypeStatic(ident) - | PrimKind.U8: - ret self.evalU8TypeStatic(ident) - | PrimKind.U16: - ret self.evalU16TypeStatic(ident) - | PrimKind.U32: - ret self.evalU32TypeStatic(ident) - | PrimKind.U64: - ret self.evalU64TypeStatic(ident) - | PrimKind.F32: - ret self.evalF32TypeStatic(ident) - | PrimKind.F64: - ret self.evalF64TypeStatic(ident) - |: - self.pushErr(ident, LogMsg.TypeHaveNotIdent, kind, ident.Kind) - ret nil - } - } - - fn evalTypeStatic(mut self, mut d: &Data, mut si: &SubIdentExpr): &Data { - match { - | d.Kind.Prim() != nil: - ret self.evalPrimStatic(d.Kind.Prim().Str(), si.Ident) - | d.Kind.Enum() != nil: - ret self.evalEnumStatic(d.Kind.Enum(), si.Ident) - | d.Kind.TypeEnum() != nil: - ret self.evalTypeEnumStatic(d.Kind.TypeEnum(), si.Ident) - | d.Kind.Struct() != nil: - ret self.evalStructStatic(d.Kind.Struct(), si.Ident) - |: - self.pushErr(si.Ident, LogMsg.TypeNotSupportSubFields, d.Kind.Str()) - ret nil - } - } - - fn comptimeObjSubIdent[ComptimeType](mut self, mut &ct: &ComptimeType, &d: &Data, &si: &SubIdentExpr): &Data { - mut cd := ct.subIdent(si.Ident.Kind) - if cd == nil { - self.pushErr(si.Ident, LogMsg.ObjHaveNotIdent, d.Kind.Str(), si.Ident.Kind) - } - ret cd - } - - fn tryComptimeObjSubIdent(mut self, mut &d: &Data, mut si: &SubIdentExpr): (&Data, bool) { - match { - | d.Kind.comptimeTypeInfo() != nil: - mut ct := d.Kind.comptimeTypeInfo() - ret self.comptimeObjSubIdent(ct, d, si), true - | d.Kind.comptimeStructField() != nil: - mut ct := d.Kind.comptimeStructField() - ret self.comptimeObjSubIdent(ct, d, si), true - | d.Kind.comptimeEnumField() != nil: - mut ct := d.Kind.comptimeEnumField() - ret self.comptimeObjSubIdent(ct, d, si), true - | d.Kind.comptimeParam() != nil: - mut ct := d.Kind.comptimeParam() - ret self.comptimeObjSubIdent(ct, d, si), true - | d.Kind.comptimeStatic() != nil: - mut ct := d.Kind.comptimeStatic() - ret self.comptimeObjSubIdent(ct, d, si), true - | d.Kind.comptimeValue() != nil: - mut ct := d.Kind.comptimeValue() - ret self.comptimeObjSubIdent(ct, d, si), true - | d.Kind.comptimeFile() != nil: - mut ct := d.Kind.comptimeFile() - ret self.comptimeObjSubIdent(ct, d, si), true - |: - ret nil, false - } - } - - fn evalObjSubIdent(mut self, mut d: &Data, mut si: &SubIdentExpr): &Data { - if IsIgnoreIdent(si.Ident.Kind) { - self.pushErr(si.Ident, LogMsg.InvalidSyntax) - ret nil - } - - { - mut compData, ok := self.tryComptimeObjSubIdent(d, si) - if ok { - ret compData - } - } - - mut kind := d.Kind - match { - | d.Kind.Ptr() != nil: - ptr := d.Kind.Ptr() - if ptr.IsUnsafe() { - break - } - if !self.isUnsafe() { - self.pushErr(si.Ident, LogMsg.UnsafeBehaviorAtOutOfUnsafeScope) - } - kind = d.Kind.Ptr().Elem - makeImplicitDeref(d, si.Ident) - | d.Kind.Sptr() != nil: - kind = d.Kind.Sptr().Elem - makeImplicitDeref(d, si.Ident) - } - - match { - | d.Kind.Trait() != nil: - ret self.evalTraitSubIdent(d, d.Kind.Trait(), si.Ident) - | kind.Struct() != nil: - s := kind.Struct() - if isInstancedStruct(s) { - mut usedReferenceElem := d.Kind.Sptr() != nil - ret self.evalStructSubIdent(d, kind.Struct(), si, usedReferenceElem) - } - } - self.pushErr(si.Ident, LogMsg.ObjNotSupportSubFields, d.Kind.Str()) - ret nil - } - - fn evalSubIdent(mut &self, mut si: &SubIdentExpr): &Data { - mut prefix := self.prefix - self.prefix = nil - defer { self.prefix = prefix } - mut d := self.evalExprKind(si.Expr.Kind) - if d == nil { - ret nil - } - if d.Decl { - ret self.evalTypeStatic(d, si) - } - ret self.evalObjSubIdent(d, si) - } - - fn evalTuple(mut &self, mut tup: &TupleExpr): &Data { - mut tupT := new(Tuple) - tupT.Types = make([]&TypeKind, 0, len(tup.Expr)) - - mut model := &TupleExprModel{ - Datas: make([]&Data, 0, len(tup.Expr)), - } - - mut ok := true - for (_, mut expr) in tup.Expr { - mut d := self.evalExpr(expr) - if d == nil { - ok = false - continue - } - tupT.Types = append(tupT.Types, d.Kind) - model.Datas = append(model.Datas, d) - } - - if !ok { - ret nil - } - - ret &Data{ - Kind: &TypeKind{Kind: tupT}, - Model: model, - } - } - - fn evalMap(mut &self, mut m: &Map, mut lit: &BraceLit): &Data { - mut model := &MapExprModel{ - KeyKind: m.Key, - ValKind: m.Val, - } - - for (_, mut expr) in lit.Exprs { - match type expr.Kind { - | &KeyValPair: - // Ok. - break - |: - self.pushErr(lit.Token, LogMsg.InvalidSyntax) - ret nil - } - - mut pair := (&KeyValPair)(expr.Kind) - - mut key := self.evalExpr(pair.Key) - if key == nil { - ret nil - } - - mut val := self.evalExpr(pair.Val) - if val == nil { - ret nil - } - - const destIsRef = false - if self.s.checkValidityForInitExpr(!self.immutable, destIsRef, m.Key, key, pair.Key.Token) { - _ = self.s.checkAssignType(destIsRef, m.Key, key, pair.Key.Token) - } - if self.s.checkValidityForInitExpr(!self.immutable, destIsRef, m.Val, val, pair.Val.Token) { - _ = self.s.checkAssignType(destIsRef, m.Val, val, pair.Val.Token) - } - - model.Entries = append(model.Entries, &KeyValPairExprModel{ - Key: key.Model, - Val: val.Model, - }) - } - - ret &Data{ - Mutable: true, - Kind: &TypeKind{Kind: m}, - Model: model, - } - } - - fn evalBraceLit(mut &self, mut lit: &BraceLit): &Data { - match { - | self.prefix == nil: - self.pushErr(lit.Token, LogMsg.InvalidSyntax) - ret nil - | self.prefix.Map() != nil: - ret self.evalMap(self.prefix.Map(), lit) - | self.prefix.Struct() != nil: - ret self.evalStructLitExplicit(self.prefix.Struct(), lit.Exprs, lit.Token) - |: - self.pushErr(lit.Token, LogMsg.InvalidSyntax) - ret nil - } - } - - fn evalAnonFunc(mut &self, mut decl: &FnDecl): &Data { - mut tc := typeChecker{ - s: self.s, - rootLookup: self.lookup, - lookup: self.lookup, - } - mut ins := tc.buildFunc(decl) - if ins == nil { - ret nil - } - ins.AsAnon = true - mut captured := make([]&Var, 0) - match type self.lookup { - | &scopeChecker: - mut sc := (&scopeChecker)(self.lookup) - mut scc := sc.newChildChecker() - scc.labels = new([]&scopeLabel, nil) - scc.gotos = new([]&scopeGoto, nil) - scc.owner = ins - scc.childIndex = 0 - scc.it = 0 - scc.cse = 0 - scc.captured = unsafe { (&[]&Var)(&captured) } - self.s.checkFnInsSc(ins, scc) - |: - self.s.checkFnIns(ins) - } - - ret &Data{ - Kind: &TypeKind{Kind: ins}, - Model: &AnonFnExprModel{ - Captured: captured, - Func: ins, - Global: self.isGlobal(), - }, - } - } - - fn evalBinary(mut &self, mut op: &BinaryExpr): &Data { - mut bs := binaryEval.newPlain(self) - // Apply prefix for just numericals. - if self.prefix != nil { - prim := self.prefix.Prim() - if prim == nil || !types::IsNum(prim.Str()) { - mut prefix := self.prefix - self.prefix = nil - defer { self.prefix = prefix } - ret bs.eval(op) - } - } - ret bs.eval(op) - } - - fn evalExprKind(mut &self, mut kind: ExprData): &Data { - match type kind { - | &RangeExpr: - mut e := (&RangeExpr)(kind) - ret self.evalExprKind(e.Expr.Kind) - | &LitExpr: - ret self.evalLit((&LitExpr)(kind)) - | &IdentExpr: - ret self.evalIdent((&IdentExpr)(kind)) - | &UnaryExpr: - ret self.evalUnary((&UnaryExpr)(kind)) - | &VariadicExpr: - ret self.evalVariadic((&VariadicExpr)(kind)) - | &UnsafeExpr: - ret self.evalUnsafe((&UnsafeExpr)(kind)) - | &SliceExpr: - ret self.evalSliceExpr((&SliceExpr)(kind)) - | &IndexingExpr: - ret self.evalIndexing((&IndexingExpr)(kind)) - | &SlicingExpr: - ret self.evalSlicing((&SlicingExpr)(kind)) - | &CastExpr: - ret self.evalCast((&CastExpr)(kind)) - | &NsSelectionExpr: - ret self.evalNsSelection((&NsSelectionExpr)(kind)) - | &StructLit: - ret self.evalStructLit((&StructLit)(kind)) - | &TypeDecl: - ret self.evalType((&TypeDecl)(kind)) - | &FnCallExpr: - ret self.evalFnCall((&FnCallExpr)(kind)) - | &SubIdentExpr: - ret self.evalSubIdent((&SubIdentExpr)(kind)) - | &TupleExpr: - ret self.evalTuple((&TupleExpr)(kind)) - | &BraceLit: - ret self.evalBraceLit((&BraceLit)(kind)) - | &FnDecl: - ret self.evalAnonFunc((&FnDecl)(kind)) - | &BinaryExpr: - ret self.evalBinary((&BinaryExpr)(kind)) - |: - ret nil - } - } - - // Returns value data of evaluated expression. - // Returns nil if error occurs. - fn eval1(mut &self, mut expr: &Expr): &Data { - mut d := self.evalExprKind(expr.Kind) - if d == nil || d.Kind == nil { - ret nil - } - - match { - | d.Kind.Fn() != nil: - mut f := d.Kind.Fn() - if f.IsBuiltin() { - self.s.pushErr(expr.Token, LogMsg.BuiltinNotInvoked) - break - } - if len(f.Generics) != len(f.Decl.Generics) { - self.s.pushErr(expr.Token, LogMsg.HasGenerics) - } else if !f.Decl.Statically && f.Decl.IsMethod() { - self.s.pushErr(expr.Token, LogMsg.MethodNotInvoked) - } else { - f.AsAnon = true - } - } - - ret d - } - - // Returns value data of evaluated expression. - // Returns nil if error occurs. - // Accepts comptime expressions as invalid. - fn eval(mut &self, mut expr: &Expr): &Data { - mut d := self.eval1(expr) - if d == nil { - ret nil - } - if (self.owner == nil || !self.owner.Constant) && d.Kind.comptime() { - self.s.pushErr(expr.Token, LogMsg.ComptimeAsExpr) - ret nil - } - ret d - } - - // Returns value data of evaluated expression. - // Returns nil if error occurs. - // Accepts decls as invalid expression. - fn evalExpr1(mut &self, mut expr: &Expr): &Data { - mut d := self.eval1(expr) - match { - | d == nil: - ret nil - | d.Decl: - self.pushErr(expr.Token, LogMsg.InvalidExpr) - ret nil - |: - ret d - } - } - - // Returns value data of evaluated expression. - // Returns nil if error occurs. - // Accepts decls as invalid expression. - fn evalExpr(mut &self, mut expr: &Expr): &Data { - mut d := self.eval(expr) - match { - | d == nil: - ret nil - | d.Decl: - self.pushErr(expr.Token, LogMsg.InvalidExpr) - ret nil - |: - ret d - } - } + fn pushErr(mut self, token: &Token, fmt: LogMsg, args: ...any) { + self.s.pushErr(token, fmt, args...) + } + + // Push suggestion to last log. + fn pushSuggestion(mut self, fmt: LogMsg, args: ...any) { + self.s.pushSuggestion(fmt, args...) + } + + fn allowBuiltin(mut self) { + self.disBuiltin = false + } + + fn disallowBuiltin(mut self) { + self.disBuiltin = true + } + + // Reports whether evaluation in unsafe scope. + fn isUnsafe(self): bool { + ret self.unsafety + } + + // Reports whether evaluated expression is in global scope. + fn isGlobal(self): bool { + match type self.lookup { + | &Sema: + ret true + |: + ret false + } + } + + fn applyNumericPrefix(mut self, mut &d: &Data): bool { + if d == nil || + !d.IsConst() || + d.Kind.Prim() == nil || + self.prefix == nil { + ret false + } + prim := self.prefix.Prim() + if prim == nil { + ret false + } + + match { + | types::IsFloat(prim.Str()): + d.Kind = new(TypeKind, *self.prefix) + d.Constant.SetF64(d.Constant.AsF64()) + d.Constant.Kind = prim.Kind + | types::IsSigInt(prim.Str()): + if !sigAssignable(prim.Str(), d) { + ret false + } + d.Kind = new(TypeKind, *self.prefix) + d.Constant.SetI64(d.Constant.AsI64()) + d.Constant.Kind = prim.Kind + | types::IsUnsigInt(prim.Str()): + if !unsigAssignable(prim.Str(), d) { + ret false + } + d.Kind = new(TypeKind, *self.prefix) + d.Constant.SetU64(d.Constant.AsU64()) + d.Constant.Kind = prim.Kind + } + ret true + } + + fn litStr(self, &l: &LitExpr): &Data { + mut s := "" + if IsRawStr(l.Value) { + s = lit::ToRawStr(l.Value) + } else { + s = lit::ToStr(l.Value) + } + mut constant := Const.NewStr(s) + + ret &Data{ + Mutable: true, + Constant: constant, + Kind: primStr, + Model: constant, + } + } + + fn litRune(self, &l: &LitExpr): &Data { + r := lit::ToRune(l.Value) + mut data := &Data{ + Constant: Const.NewI64(i64(r)), + } + + if r <= 255 { + data.Kind = primU8 // Byte + } else { + data.Kind = primI32 // Rune + } + + data.Model = &RuneExprModel{Code: r} + data.Mutable = true + data.IsRune = true + data.untyped = true + ret data + } + + fn litFloat(self, &l: &LitExpr): &Data { + f := conv::ParseFloat(l.Value, 64) else { use f64.Max } + mut constant := Const.NewF64(f) + ret &Data{ + untyped: true, + Mutable: true, + Constant: constant, + Kind: primF64, + Model: constant, + } + } + + fn litInt(mut self, &l: &LitExpr): &Data { + const BitSize = 1 << 6 + + mut lit := l.Value + mut base := 0 + + match { + | strings::HasPrefix(lit, "0x"): // Hexadecimal + lit = lit[2:] + base = 1 << 4 + | strings::HasPrefix(lit, "0b"): // Binary + lit = lit[2:] + base = 1 << 1 + | strings::HasPrefix(lit, "0o"): // Ocatal + lit = lit[2:] + base = 1 << 3 + | lit[0] == '0' && len(lit) > 1: // Octal + lit = lit[1:] + base = 1 << 3 + |: + // Decimal + base = 1 << 3 + 2 + } + + mut d := new(Data) + + mut ok := true + sig := conv::ParseInt(lit, base, BitSize) else { + ok = false + use 0 + } + if ok { + d.Constant = Const.NewI64(sig) + d.Kind = primInt + } else { + unsig := conv::ParseUint(lit, base, BitSize) else { + self.pushErr(l.Token, LogMsg.InvalidNumericRange) + self.pushSuggestion(LogMsg.TryFloatingPoint) + use u64.Max + } + d.Constant = Const.NewU64(unsig) + d.Kind = primUint + } + + d.Model = d.Constant + d.untyped = true + if !self.applyNumericPrefix(d) { + // If prefix is not implemented, check constant bitsize. + // Arcihtecture bitsize type might be insufficient to store constant data. + // If this concern is true, set kind to minimum type that has enough bitsize. + fitBitsize(d) + } + ret d + } + + fn litNum(mut self, &l: &LitExpr): &Data { + match { + | lex::IsFloat(l.Value): + ret self.litFloat(l) + |: + ret self.litInt(l) + } + } + + fn evalLit(mut self, lit: &LitExpr): &Data { + match { + | IsStr(lit.Value): + ret self.litStr(lit) + | IsRune(lit.Value): + ret self.litRune(lit) + | lex::IsNum(lit.Value): + ret self.litNum(lit) + |: + ret nil + } + } + + fn findBuiltins(mut self, &ident: str): any { + if mod::IsPub(ident) { + match type self.lookup { + | &ImportInfo: + mut def := findBuiltinsImport(ident, (&ImportInfo)(self.lookup)) + if def != nil { + ret def + } + | &Sema: + mut def := findBuiltinsSema(ident, (&Sema)(self.lookup)) + if def != nil { + ret def + } + | &scopeChecker: + mut def := findBuiltinsSema(ident, (&scopeChecker)(self.lookup).s) + if def != nil { + ret def + } + } + ret nil + } + if self.disBuiltin { + ret nil + } + ret findBuiltinDef(ident) + } + + fn getDef(mut self, &ident: str, binded: bool): any { + // Find variables and type aliases first. + // Because self.lookup might be a scopeChecker, and shadowing may occurred. + // If any variable or type aliases is shadowing other declarations such us structure, + // it will result as wrong expression evaluation. + mut v := self.lookup.FindVar(ident, binded) + if v != nil { + ret v + } + + mut ta := self.lookup.FindTypeAlias(ident, binded) + if ta != nil { + ret ta + } + + if !binded { + mut enm := self.lookup.FindEnum(ident) + if enm != nil { + ret enm + } + + mut tenm := self.lookup.FindTypeEnum(ident) + if tenm != nil { + ret tenm + } + } + + mut f := self.lookup.FindFn(ident, binded) + if f != nil { + ret f + } + + mut s := self.lookup.FindStruct(ident, binded) + if s != nil { + ret s + } + + ret self.findBuiltins(ident) + } + + fn getOwnerRefers(mut self): &ReferenceStack { + match type self.lookup { + | &scopeChecker: + mut sc := (&scopeChecker)(self.lookup).getHardRoot() + ret sc.owner.Refers + |: + // Push reference to owner if global. + if self.owner != nil && + self.owner.Scope == nil { + ret self.owner.Refers + } + } + ret nil + } + + fn pushReference[T](mut self, mut &ref: T) { + mut refers := self.getOwnerRefers() + if refers != nil && !refers.Exist[T](ref) { + refers.Push(ref) + } + } + + fn _evalEnum(self, mut enm: &Enum): &Data { + ret &Data{ + Decl: true, + Kind: &TypeKind{ + Kind: enm, + }, + } + } + + fn evalEnum(mut self, mut enm: &Enum, errorToken: &Token): &Data { + if !self.s.isAccessibleDefine(enm.Public, enm.Token) { + self.pushErr(errorToken, LogMsg.IdentIsNotAccessible, enm.Ident) + self.pushSuggestion(LogMsg.MakePubToAccess) + ret nil + } + ret self._evalEnum(enm) + } + + fn _evalTypeEnum(self, mut enm: &TypeEnum): &Data { + ret &Data{ + Decl: true, + Kind: &TypeKind{ + Kind: enm, + }, + } + } + + fn evalTypeEnum(mut self, mut enm: &TypeEnum, errorToken: &Token): &Data { + if !self.s.isAccessibleDefine(enm.Public, enm.Token) { + self.pushErr(errorToken, LogMsg.IdentIsNotAccessible, enm.Ident) + self.pushSuggestion(LogMsg.MakePubToAccess) + ret nil + } + ret self._evalTypeEnum(enm) + } + + fn _evalStruct(self, mut s: &StructIns): &Data { + mut d := &Data{ + Decl: true, + Kind: &TypeKind{ + Kind: s, + }, + Model: s, + } + if s.Decl != nil && s.Decl.Binded { + d.Kind.BindIdent = s.Decl.Ident + } + ret d + } + + fn evalStruct(mut self, mut s: &StructIns, errorToken: &Token): &Data { + if !self.s.isAccessibleDefine(s.Decl.Public, s.Decl.Token) { + self.pushErr(errorToken, LogMsg.IdentIsNotAccessible, s.Decl.Ident) + self.pushSuggestion(LogMsg.MakePubToAccess) + ret nil + } + self.checkDeprecated(s.Decl.Directives, errorToken) + ret self._evalStruct(s) + } + + fn evalFnIns(self, mut f: &FnIns): &Data { + ret &Data{ + Kind: &TypeKind{ + Kind: f, + }, + Model: f, + } + } + + fn checkDeprecated(mut self, mut &directives: []&ast::Directive, tok: &Token) { + if self.isUnsafe() { + ret + } + + d := findDirective(directives, Directive.Deprecated) + if d != nil { + if len(d.Args) == 0 { + self.pushErr(tok, LogMsg.UsingDeprecated, "this code is deprecated") + } else { + self.pushErr(tok, LogMsg.UsingDeprecated, d.Args[0].Kind) + } + self.pushSuggestion(LogMsg.UseUnsafeForDeprecated) + } + } + + fn evalFn(mut self, mut f: &Fn, errorToken: &Token): &Data { + if !self.s.isAccessibleDefine(f.Public, f.Token) { + self.pushErr(errorToken, LogMsg.IdentIsNotAccessible, f.Ident) + self.pushSuggestion(LogMsg.MakePubToAccess) + ret nil + } + + self.checkDeprecated(f.Directives, errorToken) + + mut ins := f.instance() + self.pushReference[&FnIns](ins) + ret self.evalFnIns(ins) + } + + fn pushIllegalCycleError(mut self, &v1: &Var, &v2: &Var, mut &message: StrBuilder) { + const Padding = 7 + refers_to := Logf(LogMsg.RefersTo, v1.Ident, v2.Ident) + buf := unsafe { message.Buf() } + message.WriteStr(strings::Repeat(" ", Padding)) + message.WriteStr(refers_to) + message.WriteByte('\n') + message.Write(buf) + } + + fn checkCrossCycle(mut self, &v: &Var, mut &message: StrBuilder): bool { + for _, d in v.Depends { + if d == self.owner { + self.pushIllegalCycleError(v, d, message) + ret false + } + if !self.checkCrossCycle(d, message) { + self.pushIllegalCycleError(v, d, message) + ret false + } + } + ret true + } + + // Checks owner illegal cycles. + // Appends depend to depends if there is no illegal cycle. + // Returns true if e.owner is nil. + fn checkIllegalCycles(mut self, mut &v: &Var, declToken: &Token): (ok: bool) { + // Skip cycle checking if owner is nil or not global. + if self.owner == nil || self.owner.Scope != nil { + ret true + } + + // Check illegal cycle for itself. + // Because refers's owner is ta. + if self.owner == v { + self.pushErr(self.owner.Token, LogMsg.IllegalCycleRefersItself, self.owner.Ident) + ret false + } + + mut message := StrBuilder.New(1 << 5) + + if !self.checkCrossCycle(v, message) { + mut errMsg := message.Str() + message.Clear() + self.pushIllegalCycleError(self.owner, v, message) + errMsg += message.Str() + self.pushErr(declToken, LogMsg.IllegalCrossCycle, errMsg) + ret false + } + + self.owner.Depends = append(self.owner.Depends, v) + ret true + } + + fn evalVar(mut self, mut v: &Var, errorToken: &Token): &Data { + if !self.s.isAccessibleDefine(v.Public, v.Token) { + self.pushErr(errorToken, LogMsg.IdentIsNotAccessible, v.Ident) + self.pushSuggestion(LogMsg.MakePubToAccess) + ret nil + } + + self.checkDeprecated(v.Directives, errorToken) + + if v.Token == nil { + // Variable is built-in. + goto data + } + + v.Used = true + + match type self.lookup { + | &Sema: + // Check cycles for global scope. + ok := self.checkIllegalCycles(v, errorToken) + if !ok { + ret nil + } + | &scopeChecker: + mut s := (&scopeChecker)(self.lookup) + mut root := s.getRoot() + if root.captured != nil && isVarCaptured(root, s, v) { + root.pushCaptured(v) + } + if !v.Reference || self.isUnsafe() { + break + } + for s.owner == nil && s.parent != nil { + s = s.parent + } + if s.owner != nil && s.owner.Anon && v.Scope != s.owner.Scope { + self.pushErr(errorToken, LogMsg.UsedRefInAnonFnFromParentScope, v.Ident) + } + } + + // Push reference to global variable. + if v.Scope == nil { + self.pushReference[&Var](v) + } + + if !v.Binded && (v.Value == nil || v.Value.Data == nil) { + if v.Constant { + // Eval constant dependent variable. + self.s.checkVar(v, self.s) + if v.Value == nil || v.Value.Data == nil { + // Skip error. + ret nil + } + } + } + + // Kind is nil, no determined. + // In other word, not analyzed yet. + // But this variable is dependency, therefore check this for eval. + if v.Kind == nil || v.Kind.Kind == nil { + // Just necessary for global scope, therefore + // execute if only scope is nil aka variable is not in global scope. + if v.Scope != nil { + ret nil + } + + self.s.checkVar(v, self.lookup) + + // Ignore eval, because analyze is failed. + if v.Kind == nil || v.Kind.Kind == nil { + ret nil + } + } + + data: + mut d := &Data{ + Lvalue: !v.Constant, + Mutable: v.Mutable, + Reference: v.Reference, + Kind: v.Kind.Kind, + Model: v, + } + + if !v.Binded && v.IsInitialized() && v.Value.Data != nil { + d.IsRune = v.Value.Data.IsRune + } + + if v.Constant && v.Value.Data.Constant != nil { + d.Constant = new(Const, *v.Value.Data.Constant) + d.Model = d.Constant + if v.untypedConstant() { + self.applyNumericPrefix(d) + d.untyped = true + } + } + + ret d + } + + fn evalTypeAlias(mut self, mut ta: &TypeAlias, errorToken: &Token): &Data { + if !self.s.isAccessibleDefine(ta.Public, ta.Token) { + self.pushErr(errorToken, LogMsg.IdentIsNotAccessible, ta.Ident) + self.pushSuggestion(LogMsg.MakePubToAccess) + ret nil + } + + ta.Used = true + + mut kind := ta.Kind.Kind.Kind + let mut d: &Data = nil + match type kind { + | &StructIns: + d = self._evalStruct((&StructIns)(kind)) + | &Enum: + d = self._evalEnum((&Enum)(kind)) + | &TypeEnum: + d = self._evalTypeEnum((&TypeEnum)(kind)) + |: + d = &Data{ + Decl: true, + Kind: &TypeKind{ + Kind: ta.Kind.Kind.Kind, + }, + } + if ta.Binded { + d.Kind.BindIdent = ta.Ident + } else { + d.Kind.BindIdent = ta.Kind.Kind.BindIdent + } + d.Model = d.Kind + } + d.Kind.Generic = ta.Generic + ret d + } + + fn evalDef(mut self, mut &def: any, ident: &Token): &Data { + match type def { + | &Var: + ret self.evalVar((&Var)(def), ident) + | &Enum: + ret self.evalEnum((&Enum)(def), ident) + | &TypeEnum: + ret self.evalTypeEnum((&TypeEnum)(def), ident) + | &Struct: + ret self.evalStruct((&Struct)(def).instance(), ident) + | &Fn: + mut f := (&Fn)(def) + if f.Ident != build::InitFn { + ret self.evalFn(f, ident) + } + | &FnIns: + ret self.evalFnIns((&FnIns)(def)) + | &TypeAlias: + ret self.evalTypeAlias((&TypeAlias)(def), ident) + } + self.pushErr(ident, LogMsg.IdentNotExist, ident.Kind) + ret nil + } + + fn evalIdent(mut self, ident: &IdentExpr): &Data { + mut def := self.getDef(ident.Ident, ident.Binded) + ret self.evalDef(def, ident.Token) + } + + fn evalUnary(mut &self, mut u: &UnaryExpr): &Data { + mut unary := unaryEval.new(self) + ret unary.eval(u) + } + + fn evalVariadic(mut &self, mut v: &VariadicExpr): &Data { + if v.Expr == nil { + self.pushErr(v.Token, LogMsg.InvalidExpr) + ret nil + } + + mut prefix := self.prefix + self.prefix = nil + defer { self.prefix = prefix } + + mut d := self.evalExpr(v.Expr) + if d == nil { + ret nil + } + if !d.Kind.Variadicable() { + self.pushErr(v.Token, LogMsg.VariadicWithNonVariadicable, d.Kind.Str()) + ret nil + } + makeVariadic(d, d.Kind.Slc().Elem) + ret d + } + + fn evalUnsafe(mut &self, mut u: &UnsafeExpr): &Data { + unsafety := self.unsafety + self.unsafety = true + mut d := self.evalExpr(u.Expr) + self.unsafety = unsafety + ret d + } + + fn evalArr(mut &self, mut s: &SliceExpr): &Data { + // Arrays always has type prefixes. + mut pt := self.prefix.Arr() + + mut arr := &Arr{ + Auto: false, + N: 0, + Elem: pt.Elem, + } + + mut filled := false + + if len(s.Exprs) == 2 { + match type s.Exprs[1].Kind { + | &VariadicExpr: + if (&VariadicExpr)(s.Exprs[1].Kind).Expr != nil { + break + } + // Filled. + + if pt.Auto { + self.pushErr(s.Token, LogMsg.AutoSizedArrFilled) + ret nil + } + + filled = true + s.Exprs = s.Exprs[:1] + } + } + + arr.N = len(s.Exprs) + if !pt.Auto { + if arr.N > pt.N { + self.pushErr(s.Token, LogMsg.OverflowLimits) + } else if arr.N < pt.N { + arr.N = pt.N + } + } + + mut model := &ArrayExprModel{ + Kind: arr, + } + if filled { + model.Elems = make([]ExprModel, 0, 2) + } else { + model.Elems = make([]ExprModel, 0, len(s.Exprs)) + } + + mut prefix := self.prefix + self.prefix = arr.Elem + for (_, mut elem) in s.Exprs { + mut d := self.evalExpr(elem) + if d == nil { + continue + } + const destIsRef = false + if self.s.checkValidityForInitExpr(!self.immutable, destIsRef, arr.Elem, d, elem.Token) { + _ = self.s.checkAssignType(destIsRef, arr.Elem, d, elem.Token) + } + model.Elems = append(model.Elems, d.Model) + } + self.prefix = prefix + + if filled { + // Fill mark. + model.Elems = append(model.Elems, nil) + } + + ret &Data{ + Mutable: true, + Kind: &TypeKind{ + Kind: arr, + }, + Model: model, + } + } + + fn evalExpSlc(mut &self, mut s: &SliceExpr, mut t: &TypeKind, mut first: ExprModel): &Data { + mut slc := &Slc{ + Elem: t, + } + + mut i := 0 + mut model := &SliceExprModel{ + ElemKind: t, + Elems: make([]ExprModel, 0, len(s.Exprs)), + } + if first != nil { + model.Elems = append(model.Elems, first) + i = 1 + } + + mut prefix := self.prefix + self.prefix = slc.Elem + for (_, mut elem) in s.Exprs[i:] { + mut d := self.evalExpr(elem) + if d != nil { + const destIsRef = false + if self.s.checkValidityForInitExpr(!self.immutable, destIsRef, slc.Elem, d, elem.Token) { + _ = self.s.checkAssignType(destIsRef, slc.Elem, d, elem.Token) + } + model.Elems = append(model.Elems, d.Model) + } + } + self.prefix = prefix + + ret &Data{ + Mutable: true, + Kind: &TypeKind{ + Kind: slc, + }, + Model: model, + } + } + + fn evalSliceExpr(mut &self, mut s: &SliceExpr): &Data { + if self.prefix != nil { + match { + | self.prefix.Arr() != nil: + ret self.evalArr(s) + | self.prefix.Slc() != nil: + mut pt := self.prefix.Slc() + ret self.evalExpSlc(s, pt.Elem, nil) + } + } + + mut prefix := self.prefix + self.prefix = nil + + if len(s.Exprs) == 0 { + self.pushErr(s.Token, LogMsg.DynamicTypeAnnotationFailed) + ret nil + } + + mut firstElem := self.evalExpr(s.Exprs[0]) + if firstElem == nil { + ret nil + } + + // Check mutability for first element. + const destIsRef = false + self.s.checkValidityForInitExpr(!self.immutable, destIsRef, + firstElem.Kind, firstElem, s.Exprs[0].Token) + + mut d := self.evalExpSlc(s, firstElem.Kind, firstElem.Model) + + self.prefix = prefix + ret d + } + + fn checkIntegerIndexingByData(mut self, mut &d: &Data, mut token: &Token) { + errKey := checkDataForIntegerIndexing(d, token) + match errKey { + | LogMsg.Empty: + ret + | LogMsg.InvalidTypeForIndexing: + self.pushErr(token, errKey, d.Kind.Str()) + |: + self.pushErr(token, errKey) + } + } + + fn indexingPtr(mut self, mut &d: &Data, mut &index: &Data, mut &i: &IndexingExpr) { + self.checkIntegerIndexingByData(index, i.Token) + d.Lvalue = true + + mut ptr := d.Kind.Ptr() + match { + | ptr.IsUnsafe(): + self.pushErr(i.Token, LogMsg.UnsafePtrIndexing) + ret + | !self.isUnsafe(): + self.pushErr(i.Token, LogMsg.UnsafeBehaviorAtOutOfUnsafeScope) + } + + d.Kind = ptr.Elem + } + + fn indexingArr(mut self, mut &d: &Data, mut &index: &Data, mut &i: &IndexingExpr) { + mut arr := d.Kind.Arr() + d.Kind = arr.Elem + self.checkIntegerIndexingByData(index, i.Token) + d.Lvalue = true + if index.IsConst() && index.Constant.AsF64() >= f64(arr.N) { + self.pushErr(i.Token, LogMsg.OverflowLimits) + } + } + + fn indexingSlc(mut self, mut &d: &Data, mut &index: &Data, mut &i: &IndexingExpr) { + mut slc := d.Kind.Slc() + d.Kind = slc.Elem + self.checkIntegerIndexingByData(index, i.Token) + d.Lvalue = true + + // Check compile-time bounds. + if !index.IsConst() { + ret + } + match type d.Model { + | &SliceExprModel: + mut m := (&SliceExprModel)(d.Model) + indx := index.Constant.AsF64() + if indx >= f64(len(m.Elems)) { + self.pushErr(i.Token, LogMsg.OverflowLimits) + } else { + d.Model = m.Elems[u64(indx)] + d.Decl = true // Set Model: flag. + } + } + } + + fn indexingMap(mut self, mut &d: &Data, mut &index: &Data, mut &i: &IndexingExpr) { + d.Lvalue = true + if index == nil { + ret + } + mut m := d.Kind.Map() + mut atc := assignTypeChecker{ + s: self.s, + dest: m.Key, + d: index, + errorToken: i.Token, + } + _ = atc.check() + d.Kind = m.Val + } + + fn indexingStr(mut self, mut &d: &Data, mut &index: &Data, mut &i: &IndexingExpr) { + d.Kind = primU8 // Byte + d.Mutable = false + d.Lvalue = true + + if index == nil { + ret + } + + self.checkIntegerIndexingByData(index, i.Token) + + if !index.IsConst() { + d.Constant = nil + d.untyped = false + ret + } + + if d.IsConst() { + errorToken := i.Token + j := index.Constant.AsI64() + s := d.Constant.ReadStr() + if int(j) >= len(s) { + self.pushErr(errorToken, LogMsg.OverflowLimits) + } else { + d.Constant.SetU64(u64(s[j])) + } + } + } + + fn toIndexing(mut self, mut &d: &Data, mut &index: &Data, mut &i: &IndexingExpr) { + match { + | d.Kind.Ptr() != nil: + self.indexingPtr(d, index, i) + ret + | d.Kind.Arr() != nil: + self.indexingArr(d, index, i) + ret + | d.Kind.Slc() != nil: + self.indexingSlc(d, index, i) + ret + | d.Kind.Map() != nil: + self.indexingMap(d, index, i) + ret + | d.Kind.Prim() != nil: + prim := d.Kind.Prim() + match { + | prim.IsStr(): + self.indexingStr(d, index, i) + ret + } + } + self.pushErr(i.Token, LogMsg.NotSupportsIndexing, d.Kind.Str()) + } + + fn pushGenericsFromExprSubIdent(mut &self, mut &sexpr: &SubIdentExpr, + mut &generics: []&TypeDecl, mut &expr: &Expr): bool { + mut t := new(SubIdentTypeDecl) + if !pushSubIdentFromExpr(sexpr, t) { + self.pushErr(expr.Token, LogMsg.InvalidSyntax) + ret false + } + generics = append(generics, &TypeDecl{Kind: t}) + ret true + } + + fn pushGenericsFromData(mut &self, mut &generics: []&TypeDecl, mut &expr: &Expr): bool { + match type expr.Kind { + | &UnaryExpr: + mut u := (&UnaryExpr)(expr.Kind) + match u.Op.Id { + | TokenId.Star: + mut kind := new(PtrTypeDecl) + mut _generics := make([]&TypeDecl, 0, 1) + self.pushGenericsFromData(_generics, u.Expr) + kind.Elem = _generics[0] + generics = append(generics, &TypeDecl{ + Token: expr.Token, + Kind: kind, + }) + | TokenId.Amper: + mut kind := new(SptrTypeDecl) + mut _generics := make([]&TypeDecl, 0, 1) + self.pushGenericsFromData(_generics, u.Expr) + kind.Elem = _generics[0] + generics = append(generics, &TypeDecl{ + Token: expr.Token, + Kind: kind, + }) + |: + self.pushErr(u.Op, LogMsg.InvalidType) + ret false + } + | &TypeDecl: + generics = append(generics, (&TypeDecl)(expr.Kind)) + | &SubIdentExpr: + mut sexpr := (&SubIdentExpr)(expr.Kind) + ret self.pushGenericsFromExprSubIdent(sexpr, generics, expr) + | &IdentExpr: + mut ident := (&IdentExpr)(expr.Kind) + generics = append(generics, &TypeDecl{ + Kind: &IdentTypeDecl{ + Binded: ident.Binded, + Token: ident.Token, + Ident: ident.Ident, + }, + }) + | &TupleExpr: + for (_, mut texpr) in (&TupleExpr)(expr.Kind).Expr { + if !self.pushGenericsFromData(generics, texpr) { + ret false + } + } + | &NsSelectionExpr: + mut ns := (&NsSelectionExpr)(expr.Kind) + mut decl := &IdentTypeDecl{ + Token: ns.Ident, + Ident: ns.Ident.Kind, + } + generics = append(generics, &TypeDecl{ + Token: decl.Token, + Kind: &NamespaceTypeDecl{ + Idents: ns.Ns, + Kind: &TypeDecl{ + Token: decl.Token, + Kind: decl, + }, + }, + }) + |: + self.pushErr(expr.Token, LogMsg.InvalidSyntax) + ret false + } + ret true + } + + fn evalIdentDeclFromIndexing(mut &self, mut &d: &Data, mut &i: &IndexingExpr) { + mut s := d.Kind.Struct() + if s == nil { + self.pushErr(i.Expr.Token, LogMsg.TypeNotSupportsGenerics, d.Kind.Str()) + d = nil + ret + } + + let mut decl: &IdentTypeDecl = nil + match type i.Expr.Kind { + | &IdentExpr: + mut expr := (&IdentExpr)(i.Expr.Kind) + decl = &IdentTypeDecl{ + Binded: expr.Binded, + Token: expr.Token, + Ident: expr.Ident, + } + | &NsSelectionExpr: + mut expr := (&NsSelectionExpr)(i.Expr.Kind) + decl = &IdentTypeDecl{ + Token: expr.Ident, + Ident: expr.Ident.Kind, + } + |: + self.pushErr(i.Token, LogMsg.InvalidSyntax) + d = nil + ret + } + if !self.pushGenericsFromData(decl.Generics, i.Index) { + d = nil + ret + } + + s = self.typeChecker().fromStruct(decl, s.Decl) + if s == nil { + d = nil + ret + } + d.Kind.Kind = s + } + + // Checks new generics function instance. + // If instance is already exist, f will point to exist instantantiation. + fn checkGenericFn(mut &self, mut &f: &FnIns, mut &et: &Token, mut &model: ExprModel): bool { + ok := self.s.reloadFnInsTypes(f) + f.reloaded = true + if !ok { + ret false + } + mut existInstance := f.Decl.appendInstance(f) + // TODO: [check] is possible to optimize here using same environment with realoadFnInsTypes? + if !self.s.checkConstraintsFn(f, et, existInstance) { + ret false + } + if existInstance != nil { + // Update model and references by exist function instance. + // Generic functions returns always new instance, because might be + // generics are inferred. Therefore, always returns new instance for requests. + // So, if this absolute instance is already exist, update model. + // Otherwise, model's instance will be a dangling, because it never + // be appended into instances of function declaration since already exist. + updateModelToGenericIns(model, existInstance) + updateRefer(self.getOwnerRefers(), f, existInstance) + // Set f to exist one. + f = existInstance + } else { + // Check generic function instance instantly. + self.s.checkFnInsCaller(f, et) + } + ret true + } + + fn evalFnGenericFromIndexing(mut &self, mut &d: &Data, mut &i: &IndexingExpr) { + mut generics := make([]&TypeDecl, 0, 1 << 3) + if !self.pushGenericsFromData(generics, i.Index) { + d = nil + ret + } + + mut f := d.Kind.Fn() + mut genericsLen := 0 + if f.Decl != nil { + genericsLen = len(f.Decl.Generics) + } + if !self.s.checkGenericQuantity(genericsLen, len(generics), i.Expr.Token) { + d = nil + ret + } + + // Build real kinds of generic types. + f.Generics = make([]&InsGeneric, 0, len(f.Decl.Generics)) + for (_, mut g) in generics { + mut k := self.evalType(g) + if k == nil { + d = nil + ret + } + f.Generics = append(f.Generics, &InsGeneric{Kind: k.Kind}) + } + + if f.IsBuiltin() { + ret + } + + if self.checkGenericFn(f, i.Expr.Token, d.Model) { + d.Kind.Kind = f + } else { + d = nil + } + } + + fn evalIndexing(mut &self, mut i: &IndexingExpr): &Data { + mut prefix := self.prefix + self.prefix = nil + defer { self.prefix = prefix } + + mut d := self.evalExprKind(i.Expr.Kind) + if d == nil { + ret nil + } + + // Catch types. + if d.Decl { + self.evalIdentDeclFromIndexing(d, i) + ret d + } + + if d.Kind.Fn() != nil { + self.evalFnGenericFromIndexing(d, i) + ret d + } + + mut oldData := *d + + mut index := self.evalExpr(i.Index) + if index == nil { + ret nil + } + + // Set decl to true. It's a kind of flag. + // If decl is true after indexing eval, do not touch Model:. + // Setted by indexing eval. + d.Decl = false + + self.toIndexing(d, index, i) + if d.IsConst() { + d.Decl = false + d.Model = d.Constant + } else if d.Decl { + d.Decl = false + } else { + d.Model = &IndexingExprModel{ + Token: i.Token, + Expr: new(Data, oldData), + Index: index, + } + } + + ret d + } + + // Returns left and right index values. + // Returns zero integer expression if slicing have not left index. + // So, left index always represents an expression. + // Left data is nil if expression eval failed. + fn evalSlicingExprs(mut &self, mut &s: &SlicingExpr): (&Data, &Data) { + mut prefix := self.prefix + self.prefix = nil + defer { self.prefix = prefix } + + let mut l: &Data = nil + let mut r: &Data = nil + + if s.Start != nil { + l = self.evalExpr(s.Start) + if l != nil { + self.checkIntegerIndexingByData(l, s.Token) + } else { + ret nil, nil + } + } else { + l = &Data{ + Constant: Const.NewI64(0), + Kind: primInt, + } + l.Constant.Kind = PrimKind.Int + l.Model = l.Constant + } + + if s.To != nil { + r = self.evalExpr(s.To) + if r != nil { + self.checkIntegerIndexingByData(r, s.Token) + } else { + ret nil, nil + } + } + + ret l, r + } + + fn slicingArr(self, mut &d: &Data) { + mut elemType := d.Kind.Arr().Elem + d.Kind = &TypeKind{ + Kind: &Slc{ + Elem: elemType, + }, + } + + d.Lvalue = false + + // Keep mutability id already mutable. + // Be mutable, if element is not mutable-type. + d.Mutable = d.Mutable || !elemType.Mutable() + } + + fn slicingStr(self, mut &d: &Data, &l: &Data, &r: &Data) { + d.Lvalue = false + d.Mutable = true + if !d.IsConst() { + ret + } + + if l == nil || r == nil { + d.Constant = nil + d.untyped = false + ret + } + + if l.IsConst() && r.IsConst() { + left := l.Constant.AsI64() + if left < 0 { + ret + } + + s := d.Constant.ReadStr() + mut right := i64(0) + if r == nil { + right = i64(len(s)) + } else { + right = r.Constant.AsI64() + } + + if left > right { + ret + } + d.Constant.SetStr(s[left:right]) + d.Decl = true // Set Model: flag. + } else { + d.Constant = nil + d.untyped = false + } + } + + fn checkSlicing(mut self, mut &d: &Data, &l: &Data, &r: &Data, &s: &SlicingExpr) { + match { + | d.Kind.Arr() != nil: + self.slicingArr(d) + ret + | d.Kind.Slc() != nil: + ret + | d.Kind.Prim() != nil: + prim := d.Kind.Prim() + match { + | prim.IsStr(): + self.slicingStr(d, l, r) + ret + } + } + + self.pushErr(s.Token, LogMsg.NotSupportsSlicing, d.Kind.Str()) + } + + fn evalSlicing(mut &self, mut s: &SlicingExpr): &Data { + mut d := self.evalExpr(s.Expr) + if d == nil { + ret nil + } + + mut l, mut r := self.evalSlicingExprs(s) + if l == nil { + ret d + } + + // Set decl to true. It's a kind of flag. + // If decl is true after indexing eval, do not touch Model:. + // Setted by indexing eval. + d.Decl = false + + self.checkSlicing(d, l, r, s) + + if d.IsConst() { + d.Decl = false + d.Model = d.Constant + } else if d.Decl { + d.Decl = false + } else { + mut model := &SlicingExprModel{ + Token: s.Token, + Expr: d.Model, + Left: l.Model, + } + if r != nil { + model.Right = r.Model + } + d.Model = model + } + ret d + } + + fn castPtr(mut self, mut t: &TypeKind, mut d: &Data, errorToken: &Token) { + d.Constant = nil + d.untyped = false + sptr := d.Kind.Sptr() + if sptr != nil { + if !t.Ptr().Elem.Equal(sptr.Elem) { + self.pushErr(errorToken, LogMsg.TypeNotSupportsCastingTo, d.Kind.Str(), t.Str()) + } + ret + } + + if !self.isUnsafe() { + self.pushErr(errorToken, LogMsg.UnsafeBehaviorAtOutOfUnsafeScope) + ret + } + + prim := d.Kind.Prim() + if d.Kind.Ptr() == nil && (prim == nil || !types::IsInt(prim.Str())) { + self.pushErr(errorToken, LogMsg.TypeNotSupportsCastingTo, d.Kind.Str(), t.Str()) + } + } + + fn castStruct(mut self, mut t: &TypeKind, mut d: &Data, errorToken: &Token) { + d.Constant = nil + d.untyped = false + mut tr := d.Kind.Trait() + if tr == nil { + self.pushErr(errorToken, LogMsg.TypeNotSupportsCastingTo, d.Kind.Str(), t.Str()) + ret + } + + mut s := t.Struct() + self.pushReference[&StructIns](s) + + if !s.Decl.IsImplements(tr) { + self.pushErr(errorToken, LogMsg.TypeNotSupportsCastingTo, d.Kind.Str(), t.Str()) + } + } + + fn castRef(mut self, mut t: &TypeKind, mut d: &Data, errorToken: &Token) { + d.Constant = nil + d.untyped = false + mut sptr := t.Sptr() + + mut ptr := d.Kind.Ptr() + if ptr != nil && sptr.Elem.Equal(ptr.Elem) { + if !self.isUnsafe() { + self.pushErr(errorToken, LogMsg.UnsafeBehaviorAtOutOfUnsafeScope) + } + // Ok. + ret + } + + // For traits. + if sptr.Elem.Struct() != nil { + self.castStruct(sptr.Elem, d, errorToken) + ret + } + + self.pushErr(errorToken, LogMsg.TypeNotSupportsCastingTo, d.Kind.Str(), t.Str()) + } + + fn castSlc(mut self, mut t: &TypeKind, mut d: &Data, errorToken: &Token) { + c := d.Constant + d.Constant = nil + d.untyped = false + + if d.Kind.Enum() != nil { + if d.Kind.Enum().Kind.Kind.Prim() == nil || !d.Kind.Enum().Kind.Kind.Prim().IsStr() { + self.pushErr(errorToken, LogMsg.TypeNotSupportsCastingTo, d.Kind.Str(), t.Str()) + ret + } + } else if d.Kind.Prim() == nil || !d.Kind.Prim().IsStr() { + self.pushErr(errorToken, LogMsg.TypeNotSupportsCastingTo, d.Kind.Str(), t.Str()) + ret + } + + t = t.Slc().Elem + prim := t.Prim() + if prim == nil || (!prim.IsU8() && !prim.IsI32()) { + self.pushErr(errorToken, LogMsg.TypeNotSupportsCastingTo, d.Kind.Str(), t.Str()) + ret + } + + // Cast constant expressions. + if c != nil { + match { + | prim.IsU8(): + s := c.ReadStr() + mut model := &SliceExprModel{ + ElemKind: t, + Elems: make([]ExprModel, 0, len(s)), + } + for _, b in s { + mut bc := Const.NewU64(u64(b)) + bc.Kind = prim.Kind + model.Elems = append(model.Elems, bc) + } + d.Model = model + d.Decl = true // Prevent model changing. + | prim.IsI32(): + runes := []rune(c.ReadStr()) + mut model := &SliceExprModel{ + ElemKind: t, + Elems: make([]ExprModel, 0, len(runes)), + } + for _, r in runes { + mut rc := Const.NewI64(i64(r)) + rc.Kind = prim.Kind + model.Elems = append(model.Elems, rc) + } + d.Model = model + d.Decl = true // Prevent model changing. + } + } + } + + fn castStr(mut self, mut d: &Data, errorToken: &Token) { + if d.Kind.Enum() != nil { + mut e := d.Kind.Enum() + if e.Kind.Kind.Prim() != nil && e.Kind.Kind.Prim().IsStr() { + ret + } + } + + c := d.Constant + d.Constant = nil + d.untyped = false + if d.Kind.Prim() != nil { + prim := d.Kind.Prim() + if !prim.IsU8() && !prim.IsI32() { + self.pushErr(errorToken, LogMsg.TypeNotSupportsCastingTo, PrimKind.Str, d.Kind.Str()) + ret + } + // Cast constant expressions. + if c != nil { + match { + | prim.IsU8(): + d.Constant = Const.NewStr(str(byte(c.AsU64()))) + d.Model = d.Constant + d.Decl = true // Prevent model changing. + | prim.IsI32(): + d.Constant = Const.NewStr(str(rune(c.AsI64()))) + d.Model = d.Constant + d.Decl = true // Prevent model changing. + } + } + ret + } + + mut s := d.Kind.Slc() + if s == nil { + self.pushErr(errorToken, LogMsg.TypeNotSupportsCastingTo, PrimKind.Str, d.Kind.Str()) + ret + } + + mut t := s.Elem + prim := t.Prim() + if prim == nil || (!prim.IsU8() && !prim.IsI32()) { + self.pushErr(errorToken, LogMsg.TypeNotSupportsCastingTo, PrimKind.Str, d.Kind.Str()) + ret + } + } + + fn castInt(mut self, mut t: &TypeKind, mut d: &Data, errorToken: &Token) { + if d.IsConst() { + prim := t.Prim() + match { + | types::IsSigInt(prim.Kind): + d.Constant.SetI64(d.Constant.AsI64()) + | types::IsUnsigInt(prim.Kind): + d.Constant.SetU64(d.Constant.AsU64()) + } + } else { + d.Constant = nil + d.untyped = false + } + + if d.Kind.Enum() != nil { + e := d.Kind.Enum() + if types::IsNum(e.Kind.Kind.Str()) { + ret + } + } + + if d.Kind.Sptr() != nil { + prim := t.Prim() + if !prim.IsUintptr() { + self.pushErr(errorToken, LogMsg.TypeNotSupportsCastingTo, d.Kind.Str(), t.Str()) + } + ret + } + if d.Kind.Ptr() != nil { + prim := t.Prim() + if prim.IsUintptr() { + // Ignore case. + } else if !self.isUnsafe() { + self.pushErr(errorToken, LogMsg.UnsafeBehaviorAtOutOfUnsafeScope) + } + ret + } + + prim := d.Kind.Prim() + if prim != nil && types::IsNum(prim.Str()) { + ret + } + + self.pushErr(errorToken, LogMsg.TypeNotSupportsCastingTo, d.Kind.Str(), t.Str()) + } + + fn castNum(mut self, mut t: &TypeKind, mut d: &Data, errorToken: &Token) { + if d.IsConst() { + prim := t.Prim() + match { + | types::IsFloat(prim.Kind): + d.Constant.SetF64(d.Constant.AsF64()) + | types::IsSigInt(prim.Kind): + d.Constant.SetI64(d.Constant.AsI64()) + | types::IsUnsigInt(prim.Kind): + d.Constant.SetU64(d.Constant.AsU64()) + } + } else { + d.Constant = nil + d.untyped = false + } + + if d.Kind.Enum() != nil { + e := d.Kind.Enum() + if types::IsNum(e.Kind.Kind.Str()) { + ret + } + } + + prim := d.Kind.Prim() + if prim != nil && types::IsNum(prim.Str()) { + ret + } + + self.pushErr(errorToken, LogMsg.TypeNotSupportsCastingTo, d.Kind.Str(), t.Str()) + } + + fn castPrim(mut self, mut t: &TypeKind, mut d: &Data, errorToken: &Token) { + prim := t.Prim() + match { + | prim.IsAny(): + // The any type supports casting to any data type. + d.Constant = nil + d.untyped = false + | prim.IsStr(): + self.castStr(d, errorToken) + | types::IsInt(prim.Str()): + self.castInt(t, d, errorToken) + | types::IsNum(prim.Str()): + self.castNum(t, d, errorToken) + |: + self.pushErr(errorToken, LogMsg.TypeNotSupportsCasting, t.Str()) + } + } + + fn castConstant(mut self, mut &t: &TypeKind, mut &d: &Data) { + if d == nil || !d.IsConst() { + ret + } + prim := t.Prim() + castConstByType(prim.Kind, d) + d.Model = d.Constant + } + + fn castTypeEnum(mut self, mut &t: &TypeKind, mut &d: &Data, mut &errorToken: &Token) { + n := len(self.s.errors) + if !self.s.checkTypeCompatibility(d.Kind, t, errorToken) { + self.s.errors = self.s.errors[:n] + self.pushErr(errorToken, LogMsg.TypeNotSupportsCastingTo, d.Kind.Str(), t.Str()) + } + d.Constant = nil + d.untyped = false + } + + fn castTypeEnumT(mut self, mut &t: &TypeKind, mut &d: &Data, mut &errorToken: &Token) { + n := len(self.s.errors) + if !self.s.checkTypeCompatibility(t, d.Kind, errorToken) { + self.s.errors = self.s.errors[:n] + self.pushErr(errorToken, LogMsg.TypeNotSupportsCastingTo, d.Kind.Str(), t.Str()) + } + d.Constant = nil + d.untyped = false + } + + fn evalCastByTypeNData(mut self, mut t: &TypeKind, mut d: &Data, mut errorToken: &Token): &Data { + if d != nil && d.Decl { + self.pushErr(errorToken, LogMsg.InvalidExpr) + ret nil + } + + match { + | d.IsNil(): + if !t.NilCompatible() { + self.pushErr(errorToken, LogMsg.TypeNotSupportsCastingTo, "", t.Str()) + } + d.Constant = nil // Remove nil constant. + d.untyped = false + | d.Kind.Prim() != nil && d.Kind.Prim().IsAny(): + if t.Enum() != nil { + self.pushErr(errorToken, LogMsg.EnumCastedFromAny) + self.pushSuggestion(LogMsg.CastToEnumTypeInsteadOfEnum) + } else if t.TypeEnum() != nil { + self.pushErr(errorToken, LogMsg.EnumCastedFromAny) + } + d.Constant = nil + d.untyped = false + | d.Kind.TypeEnum() != nil: + self.castTypeEnum(t, d, errorToken) + | t.TypeEnum() != nil: + self.castTypeEnumT(t, d, errorToken) + | t.Ptr() != nil: + self.castPtr(t, d, errorToken) + | t.Sptr() != nil: + self.castRef(t, d, errorToken) + | t.Slc() != nil: + self.castSlc(t, d, errorToken) + | t.Struct() != nil: + self.castStruct(t, d, errorToken) + | t.Prim() != nil: + self.castPrim(t, d, errorToken) + self.castConstant(t, d) + |: + self.pushErr(errorToken, LogMsg.TypeNotSupportsCasting, t.Str()) + d = nil + } + + if d == nil { + ret nil + } + + // Keep mutability if data is already mutable. + // Even if the data is not mutable, set as mutable if the type is not mutable-type. + d.Mutable = d.Mutable || !d.Kind.Mutable() + + if !d.Decl && (d.Kind.Enum() == nil || !d.Kind.Enum().Kind.Kind.Equal(t)) { + applyCastKind(d, t, errorToken) + (&CastingExprModel)(d.Model).Token = errorToken + } else { + d.Kind = t + } + + // Remove flag. + // The variable d cannot be d.Decl true because of checked already. + // Therefore this field used as flag to say "do not touch to expression model". + // So, if d.Decl is true, model will not be changed. + d.Decl = false + + d.Lvalue = false + d.untyped = false + + if d.IsConst() { + d.Constant.Kind = t.Prim().Kind + } + + ret d + } + + fn evalCastT(mut &self, mut &t: &TypeKind, mut &e: &Expr, mut &et: &Token): &Data { + mut prefix := self.prefix + self.prefix = nil + defer { self.prefix = prefix } + if t.Slc() != nil { + match type e.Kind { + | &SliceExpr: + self.prefix = t + } + } + mut d := self.evalExpr(e) + if d == nil || self.prefix != nil { + ret d + } + ret self.evalCastByTypeNData(t, d, et) + } + + fn evalCast(mut &self, mut c: &CastExpr): &Data { + mut t := buildType(c.Kind) + ok := self.s.checkType(t, self.lookup) + if !ok { + ret nil + } + ret self.evalCastT(t.Kind, c.Expr, c.Kind.Token) + } + + fn evalNsSelection(mut self, s: &NsSelectionExpr): &Data { + path := buildLinkPathByTokens(s.Ns) + mut imp := self.lookup.SelectPackage(fn(imp: &ImportInfo): bool { + if len(s.Ns) == 1 && imp.Alias == path { + ret true + } + ret imp.LinkPath == path && imp.isAccessibleViaSelection() + }) + + if imp == nil { + self.pushErr(s.Ns[0], LogMsg.NamespaceNotExist, path) + ret nil + } + + mut lookup := self.lookup + self.lookup = imp + + const Binded = false + self.disallowBuiltin() + mut def := self.getDef(s.Ident.Kind, Binded) + self.allowBuiltin() + self.lookup = lookup + mut d := self.evalDef(def, s.Ident) + ret d + } + + fn evalStructLitExplicit(mut &self, mut s: &StructIns, + mut exprs: []&Expr, mut errorToken: &Token): &Data { + ok := self.s.checkGenericQuantity(len(s.Decl.Generics), len(s.Generics), errorToken) + if !ok { + ret nil + } + // NOTICE: Instance already checked (just fields) if generic quantity passes. + + if self.field != nil && self.field.Decl.Owner == s.Decl { + self.pushErr(errorToken, LogMsg.IllegalCycleRefersItself, s.Decl.Ident) + } + + self.pushReference[&StructIns](s) + self.checkDeprecated(s.Decl.Directives, errorToken) + + mut slc := structLitChecker{ + e: self, + errorToken: errorToken, + s: s, + } + slc.check(exprs) + + mut d := &Data{ + Mutable: !self.immutable, + Kind: &TypeKind{ + Kind: s, + }, + Model: &StructLitExprModel{ + Strct: s, + Args: slc.args, + }, + } + if s.Decl.Binded { + d.Kind.BindIdent = s.Decl.Ident + } + ret d + } + + fn evalStructLit(mut &self, mut lit: &StructLit): &Data { + mut t := buildType(lit.Kind) + ok := self.s.checkType(t, self.lookup) + if !ok { + ret nil + } + + mut s := t.Kind.Struct() + if s == nil { + if t.Kind.Sptr() != nil { + s = t.Kind.Sptr().Elem.Struct() + if s != nil { + goto eval + } + } + self.pushErr(lit.Kind.Token, LogMsg.InvalidSyntax) + ret nil + } + + eval: + mut d := self.evalStructLitExplicit(s, lit.Exprs, lit.Kind.Token) + if t.Kind.Sptr() != nil { + mut model := (&StructLitExprModel)(d.Model) + makeStructLitAlloc(d, model) + } + ret d + } + + fn typeChecker(mut self): typeChecker { + ret self.s.typeChecker(self.lookup, nil, nil) + } + + fn evalType(mut self, mut t: &TypeDecl): &Data { + mut tk := buildType(t) + ok := self.s.checkType(tk, self.lookup) + if !ok { + ret nil + } + ret &Data{ + Decl: true, + Kind: tk.Kind, + Model: tk.Kind, + } + } + + fn callTypeFn(mut &self, mut &fc: &FnCallExpr, mut &d: &Data) { + if len(fc.Args) < 1 { + self.pushErr(fc.Token, LogMsg.MissingExprFor, "v") + } else if len(fc.Args) > 1 { + self.pushErr(fc.Args[1].Token, LogMsg.ArgumentOverflow, d.Kind.Str()) + } else if fc.IsCo { + self.pushErr(fc.Token, LogMsg.CoForCastingCall) + d = nil + ret + } else if fc.Exception != nil { + self.pushErr(fc.Token, LogMsg.TypeCallWithExceptional) + d = nil + ret + } + + if len(fc.Args) > 0 { + mut arg := fc.Args[0] + d = self.evalCastT(d.Kind, arg, arg.Token) + ret + } + + if d != nil { + d.Decl = false + } + } + + fn callBuiltinFn(mut &self, mut &fc: &FnCallExpr, mut &d: &Data) { + if !fc.Unhandled() { // Exceptional handled? + // Built-in functions are not exceptional. + self.pushErr(fc.Token, LogMsg.HandledUnexceptional) + } + d = d.Kind.Fn().caller(self, fc, d) + if d == nil { + ret + } + d.Mutable = true + } + + fn checkFnOfConcurrentCall(mut self, &f: &FnIns, errorToken: &Token) { + if self.isUnsafe() { + ret + } + for _, p in f.Params { + if p.Decl.IsSelf() { + if !p.Decl.IsRef() { + self.pushErr(errorToken, LogMsg.ConcurrentCallWithSelfParam) + self.pushSuggestion(LogMsg.UseUnsafeJuleToCallCoSelf) + } + } + if p.Decl.Reference { + self.pushErr(errorToken, LogMsg.ConcurrentCallWithRefParam) + self.pushSuggestion(LogMsg.UseUnsafeJuleToCallCo) + ret + } + } + } + + fn processExceptionalHandler(mut self, mut &f: &FnIns, mut &fc: &FnCallExpr, mut &d: &Data) { + resultNeeded := !f.Decl.IsVoid() && (self.arg || !self.ignored) + let mut csc: &scopeChecker = nil + let mut ch: &Scope = nil + + mut model := (&FnCallExprModel)(d.Model) + + // self.lookup is always scopeChecker because exceptionals are + // not allowed in global scope. + mut sc := (&scopeChecker)(self.lookup) + csc = sc.newChildChecker() + if resultNeeded { + csc.result = f + } + ch = sc.getChild() + fc.Exception.Parent = sc.tree + csc.table.Vars = append(csc.table.Vars, buildErrorVar(ch, fc)) + sc.checkChildSsc(fc.Exception, ch, csc) + + model.Assigned = resultNeeded + model.Except = ch + + if resultNeeded && csc.result != nil { + self.pushErr(fc.Token, LogMsg.MissingAssignRet) + } + } + + fn callFn(mut &self, mut &fc: &FnCallExpr, mut &d: &Data) { + mut f := d.Kind.Fn() + if f.IsBuiltin() { + self.callBuiltinFn(fc, d) + ret + } + if self.isGlobal() && f.Decl.Exceptional { + self.pushErr(fc.Token, LogMsg.ExceptionalAtGlobalScope) + self.pushSuggestion(LogMsg.WrapExceptional) + d = nil + ret + } + + if !f.Decl.IsMethod() && hasDirective(f.Decl.Directives, Directive.Test) { + self.pushErr(fc.Token, LogMsg.TestCalled) + d = nil + ret + } + + if !d.Mutable && f.Decl.IsMethod() && !f.Decl.Statically && f.Decl.Params[0].Mutable { + if !self.immutable { + self.pushErr(fc.Token, LogMsg.MutOperationOnImmut) + } else { + // Caught mutability risk of immutable literals. + // Literal will not be assigned to immutable memory, + // used to call method with mutable receiver. + // Assume literal as mutable and check accordingly. + lit := isLitBased(d.Model) + if lit == nil { + // Expression is not literal based, so data is strictly immutable. + self.pushErr(fc.Token, LogMsg.MutOperationOnImmut) + } else { + checkMutRiskOfStructLit(self.s, lit) + } + } + } else if !self.isUnsafe() && f.Decl.Unsafety { + self.pushErr(fc.Token, LogMsg.UnsafeBehaviorAtOutOfUnsafeScope) + } + + mut dynamicAnnotation := len(f.Decl.Generics) > 0 && len(f.Generics) == 0 && len(f.Params) > 0 + if dynamicAnnotation { + f.Generics = make([]&InsGeneric, len(f.Decl.Generics)) + } else if len(f.Generics) != len(f.Decl.Generics) { + _ = self.s.checkGenericQuantity(len(f.Decl.Generics), len(f.Generics), fc.Token) + d = nil + ret + } + + mut old := self.s + if f.Decl.Owner != nil { + self.s = f.Decl.Owner.sema + } + + defer { + if old != self.s { + old.errors = append(old.errors, self.s.errors...) + self.s.errors = nil + } + self.s = old + } + + mut fcac := fnCallArgChecker{ + e: self, + args: fc.Args, + dynamicAnnotation: dynamicAnnotation, + errorToken: fc.Token, + } + + if !dynamicAnnotation { + if !f.reloaded { + ok := self.s.reloadFnInsTypes(f) + f.reloaded = true + if !ok { + d = nil + ret + } + } + mut existInstance := f.Decl.appendInstance(f) + if existInstance != nil { + f = existInstance + } + } else if !self.s.buildFnNonGenericTypeKinds(f, fcac.ignored) { + d = nil + ret + } + + fcac.f = f + + mut ok := false + if f.Decl.Owner != nil { + old, self.s = self.s, old // Save current Sema. + ok = fcac.check() + old, self.s = self.s, old // Save owner Sema. + } else { + ok = fcac.check() + } + + if dynamicAnnotation { + if !ok { + d = nil + ret + } + if !self.checkGenericFn(f, fc.Token, d.Model) { + d = nil + ret + } + } + + mut callModel := d.Model + + if f.Decl.IsVoid() { + d = buildVoidData() + } else { + d.Kind = f.Result + d.Lvalue = false + } + + mut model := &FnCallExprModel{ + Token: fc.Token, + Func: f, + Expr: callModel, + Args: fcac.argModels, + IsCo: fc.IsCo, + } + d.Model = model + d.Mutable = true + + if f.Decl.Exceptional { + if fc.IsCo { + self.s.pushErr(fc.Token, LogMsg.CoForExceptional) + self.s.pushSuggestion(LogMsg.HandleInFn) + } + match { + | fc.Unhandled(): + self.pushErr(fc.Token, LogMsg.UnhandledExceptional) + self.pushSuggestion(LogMsg.HandleExceptional) + | fc.Ignored(): + // Ok. + break + |: + // Handled with scope. + self.processExceptionalHandler(f, fc, d) + } + } else if !fc.Unhandled() { + self.pushErr(fc.Token, LogMsg.HandledUnexceptional) + } + + if fc.IsCo { + self.checkFnOfConcurrentCall(model.Func, fc.Token) + } + } + + fn evalFnCall(mut &self, mut fc: &FnCallExpr): &Data { + mut prefix := self.prefix + self.prefix = nil + defer { self.prefix = prefix } + + match type fc.Expr.Kind { + | &IdentExpr: + // Use fc.expr.Token.Kind instead of casting. + // Same thing, but more efficient and performant. + if fc.Expr.Token.Kind == TokenKind.Error { + ret builtinCallerError(self, fc) + } + } + + mut d := self.evalExprKind(fc.Expr.Kind) + if d == nil { + ret nil + } + + if d.Decl { + self.callTypeFn(fc, d) + ret d + } + + if d.Kind.Fn() == nil { + self.pushErr(fc.Token, LogMsg.CallingNonFn) + ret nil + } + + self.callFn(fc, d) + ret d + } + + fn evalEnumStatic(mut self, mut enm: &Enum, mut ident: &Token): &Data { + mut item := enm.FindItem(ident.Kind) + if item == nil { + self.pushErr(ident, LogMsg.ObjHaveNotIdent, enm.Ident, ident.Kind) + } + ret evalEnumStatic(enm, item, ident) + } + + fn evalTypeEnumStatic(mut self, mut enm: &TypeEnum, ident: &Token): &Data { + mut item := enm.FindItem(ident.Kind) + if item == nil { + self.pushErr(ident, LogMsg.ObjHaveNotIdent, enm.Ident, ident.Kind) + ret nil + } + match { + | item.Kind.Kind.Enum() != nil: + ret self._evalEnum(item.Kind.Kind.Enum()) + | item.Kind.Kind.TypeEnum() != nil: + ret self._evalTypeEnum(item.Kind.Kind.TypeEnum()) + | item.Kind.Kind.Struct() != nil: + ret self._evalStruct(item.Kind.Kind.Struct()) + |: + mut d := &Data{ + Decl: true, + Kind: item.Kind.Kind, + } + d.Model = d.Kind + ret d + } + } + + fn evalStructStatic(mut self, mut s: &StructIns, ident: &Token): &Data { + mut d := new(Data) + + // Method. + const Static = true + mut method := s.FindMethod(ident.Kind, Static) + if method != nil { + if !self.s.isAccessibleDefine(method.Public, method.Token) { + self.pushErr(ident, LogMsg.IdentIsNotAccessible, ident.Kind) + self.pushSuggestion(LogMsg.MakePubToAccess) + } + + mut ins := method.instance() + ins.Owner = s + self.pushReference[&FnIns](ins) + d.Model = &StructStaticIdentExprModel{ + Structure: s, + Expr: d.Model, + Method: ins, + } + d.Kind = &TypeKind{ + Kind: ins, + } + ret d + } + + mut sttc := s.FindStatic(ident.Kind) + if sttc != nil { + ret self.evalVar(sttc, ident) + } + + self.pushErr(ident, LogMsg.ObjHaveNotIdent, s.Decl.Ident, ident.Kind) + ret nil + } + + fn evalTraitSubIdent(mut self, mut d: &Data, mut trt: &Trait, mut ident: &Token): &Data { + mut f := trt.FindMethod(ident.Kind) + if f == nil { + self.pushErr(ident, LogMsg.ObjHaveNotIdent, trt.Ident, ident.Kind) + ret nil + } + ret &Data{ + Kind: &TypeKind{ + Kind: f.instance(), + }, + Model: &TraitSubIdentExprModel{ + Token: ident, + Expr: d.Model, + Method: f, + Trt: trt, + }, + } + } + + // This method evaluates expressions, will not check public availability. + fn evalStructSubIdentField(mut self, mut &d: &Data, mut &s: &StructIns, mut &tok: &Token, mut &f: &FieldIns): &Data { + mut model := &StructSubIdentExprModel{ + Token: tok, + Expr: new(Data, *d), + Field: f, + Owner: s, + } + d.Model = model + d.Kind = f.Kind + d.Lvalue = true + + if f.Decl.Mutable && !d.Mutable { + // Interior mutability. + match type self.lookup { + | &scopeChecker: + scope := (&scopeChecker)(self.lookup).getRoot() + d.Mutable = scope.owner != nil && scope.owner.Owner == s + } + } + + ret d + } + + fn evalStructSubIdent(mut self, mut d: &Data, mut s: &StructIns, mut si: &SubIdentExpr, ref: bool): &Data { + mut f := s.FindField(si.Ident.Kind) + if f != nil { + if !self.s.isAccessibleDefine(f.Decl.Public, f.Decl.Token) { + self.pushErr(si.Ident, LogMsg.IdentIsNotAccessible, f.Decl.Ident) + self.pushSuggestion(LogMsg.MakePubToAccess) + } + ret self.evalStructSubIdentField(d, s, si.Ident, f) + } + + const Static = false + mut m := s.FindMethod(si.Ident.Kind, Static) + if m == nil { + self.pushErr(si.Ident, LogMsg.ObjHaveNotIdent, s.Decl.Ident, si.Ident.Kind) + ret nil + } + if !self.s.isAccessibleDefine(m.Public, m.Token) { + self.pushErr(si.Ident, LogMsg.IdentIsNotAccessible, m.Ident) + self.pushSuggestion(LogMsg.MakePubToAccess) + } + + if m.Params[0].IsRef() && !ref { + self.pushErr(si.Ident, LogMsg.RefMethodUsedWithNotRefInstance) + } + + self.checkDeprecated(m.Directives, si.Ident) + + mut ins := m.instance() + ins.Owner = s + self.pushReference[&FnIns](ins) + mut model := new(Data, *d) + d.Model = &StructSubIdentExprModel{ + Token: si.Ident, + Expr: model, + Method: ins, + Owner: s, + } + d.Kind = &TypeKind{Kind: ins} + ret d + } + + fn evalIntTypeStatic(mut self, ident: &Token): &Data { + const kind: str = PrimKind.Int + match ident.Kind { + | "Max": + mut c := Const.NewI64(types::MaxI(kind)) + c.Kind = kind + ret &Data{ + Constant: c, + Model: c, + Kind: primInt, + untyped: true, + } + | "Min": + mut c := Const.NewI64(i64(types::Min(kind))) + c.Kind = kind + ret &Data{ + Constant: c, + Model: c, + Kind: primInt, + untyped: true, + } + |: + self.pushErr(ident, LogMsg.TypeHaveNotIdent, kind, ident.Kind) + ret nil + } + } + + fn evalUintTypeStatic(mut self, ident: &Token): &Data { + const kind: str = PrimKind.Uint + match ident.Kind { + | "Max": + mut c := Const.NewU64(types::MaxU(kind)) + c.Kind = kind + ret &Data{ + Constant: c, + Model: c, + Kind: primUint, + untyped: true, + } + |: + self.pushErr(ident, LogMsg.TypeHaveNotIdent, kind, ident.Kind) + ret nil + } + } + + fn evalI8TypeStatic(mut self, ident: &Token): &Data { + const kind: str = PrimKind.I8 + const min = types::MinI8 + const max = types::MaxI8 + match ident.Kind { + | "Max": + mut c := Const.NewI64(max) + c.Kind = kind + ret &Data{ + Constant: c, + Model: c, + Kind: primI8, + untyped: true, + } + | "Min": + mut c := Const.NewI64(min) + c.Kind = kind + ret &Data{ + Constant: c, + Model: c, + Kind: primI8, + untyped: true, + } + |: + self.pushErr(ident, LogMsg.TypeHaveNotIdent, kind, ident.Kind) + ret nil + } + } + + fn evalI16TypeStatic(mut self, ident: &Token): &Data { + const kind: str = PrimKind.I16 + const min = types::MinI16 + const max = types::MaxI16 + match ident.Kind { + | "Max": + mut c := Const.NewI64(max) + c.Kind = kind + ret &Data{ + Constant: c, + Model: c, + Kind: primI16, + untyped: true, + } + | "Min": + mut c := Const.NewI64(min) + c.Kind = kind + ret &Data{ + Constant: c, + Model: c, + Kind: primI16, + untyped: true, + } + |: + self.pushErr(ident, LogMsg.TypeHaveNotIdent, kind, ident.Kind) + ret nil + } + } + + fn evalI32TypeStatic(mut self, ident: &Token): &Data { + const kind: str = PrimKind.I32 + const min = types::MinI32 + const max = types::MaxI32 + match ident.Kind { + | "Max": + mut c := Const.NewI64(max) + c.Kind = kind + ret &Data{ + Constant: c, + Model: c, + Kind: primI32, + untyped: true, + } + | "Min": + mut c := Const.NewI64(min) + c.Kind = kind + ret &Data{ + Constant: c, + Model: c, + Kind: primI32, + untyped: true, + } + |: + self.pushErr(ident, LogMsg.TypeHaveNotIdent, kind, ident.Kind) + ret nil + } + } + + fn evalI64TypeStatic(mut self, ident: &Token): &Data { + const kind: str = PrimKind.I64 + const min = types::MinI64 + const max = types::MaxI64 + match ident.Kind { + | "Max": + mut c := Const.NewI64(max) + c.Kind = kind + ret &Data{ + Constant: c, + Model: c, + Kind: primI64, + untyped: true, + } + | "Min": + mut c := Const.NewI64(min) + c.Kind = kind + ret &Data{ + Constant: c, + Model: c, + Kind: primI64, + untyped: true, + } + |: + self.pushErr(ident, LogMsg.TypeHaveNotIdent, kind, ident.Kind) + ret nil + } + } + + fn evalU8TypeStatic(mut self, ident: &Token): &Data { + const kind: str = PrimKind.U8 + const max = types::MaxU8 + match ident.Kind { + | "Max": + mut c := Const.NewU64(max) + c.Kind = kind + ret &Data{ + Constant: c, + Model: c, + Kind: primU8, + untyped: true, + } + |: + self.pushErr(ident, LogMsg.TypeHaveNotIdent, kind, ident.Kind) + ret nil + } + } + + fn evalU16TypeStatic(mut self, ident: &Token): &Data { + const kind: str = PrimKind.U16 + const max = types::MaxU16 + match ident.Kind { + | "Max": + mut c := Const.NewU64(max) + c.Kind = kind + ret &Data{ + Constant: c, + Model: c, + Kind: primU16, + untyped: true, + } + |: + self.pushErr(ident, LogMsg.TypeHaveNotIdent, kind, ident.Kind) + ret nil + } + } + + fn evalU32TypeStatic(mut self, ident: &Token): &Data { + const kind: str = PrimKind.U32 + const max = types::MaxU32 + match ident.Kind { + | "Max": + mut c := Const.NewU64(max) + c.Kind = kind + ret &Data{ + Constant: c, + Model: c, + Kind: primU32, + untyped: true, + } + |: + self.pushErr(ident, LogMsg.TypeHaveNotIdent, kind, ident.Kind) + ret nil + } + } + + fn evalU64TypeStatic(mut self, ident: &Token): &Data { + const kind: str = PrimKind.U64 + const max = types::MaxU64 + match ident.Kind { + | "Max": + mut c := Const.NewU64(max) + c.Kind = kind + ret &Data{ + Constant: c, + Model: c, + Kind: primU64, + untyped: true, + } + |: + self.pushErr(ident, LogMsg.TypeHaveNotIdent, kind, ident.Kind) + ret nil + } + } + + fn evalF32TypeStatic(mut self, ident: &Token): &Data { + const kind = PrimKind.F32 + const max = types::MaxF32 + const min = types::MinF32 + const smallestNonZero = types::SmallestNonZeroF32 + match ident.Kind { + | "Max": + mut c := Const.NewF64(max) + c.Kind = kind + ret &Data{ + Constant: c, + Model: c, + Kind: primF32, + untyped: true, + } + | "Min": + mut c := Const.NewF64(min) + c.Kind = kind + ret &Data{ + Constant: c, + Model: c, + Kind: primF32, + untyped: true, + } + | "SmallestNonZero": + mut c := Const.NewF64(smallestNonZero) + c.Kind = kind + ret &Data{ + Constant: c, + Model: c, + Kind: primF32, + untyped: true, + } + |: + self.pushErr(ident, LogMsg.TypeHaveNotIdent, kind, ident.Kind) + ret nil + } + } + + fn evalF64TypeStatic(mut self, ident: &Token): &Data { + const kind = PrimKind.F64 + const max = types::MaxF64 + const min = types::MinF64 + const smallestNonZero = types::SmallestNonZeroF64 + match ident.Kind { + | "Max": + mut c := Const.NewF64(max) + c.Kind = kind + ret &Data{ + Constant: c, + Model: c, + Kind: primF64, + untyped: true, + } + | "Min": + mut c := Const.NewF64(min) + c.Kind = kind + ret &Data{ + Constant: c, + Model: c, + Kind: primF64, + untyped: true, + } + | "SmallestNonZero": + mut c := Const.NewF64(smallestNonZero) + c.Kind = kind + ret &Data{ + Constant: c, + Model: c, + Kind: primF64, + untyped: true, + } + |: + self.pushErr(ident, LogMsg.TypeHaveNotIdent, kind, ident.Kind) + ret nil + } + } + + fn evalPrimStatic(mut self, kind: str, ident: &Token): &Data { + match kind { + | PrimKind.Int: + ret self.evalIntTypeStatic(ident) + | PrimKind.Uint: + ret self.evalUintTypeStatic(ident) + | PrimKind.I8: + ret self.evalI8TypeStatic(ident) + | PrimKind.I16: + ret self.evalI16TypeStatic(ident) + | PrimKind.I32: + ret self.evalI32TypeStatic(ident) + | PrimKind.I64: + ret self.evalI64TypeStatic(ident) + | PrimKind.U8: + ret self.evalU8TypeStatic(ident) + | PrimKind.U16: + ret self.evalU16TypeStatic(ident) + | PrimKind.U32: + ret self.evalU32TypeStatic(ident) + | PrimKind.U64: + ret self.evalU64TypeStatic(ident) + | PrimKind.F32: + ret self.evalF32TypeStatic(ident) + | PrimKind.F64: + ret self.evalF64TypeStatic(ident) + |: + self.pushErr(ident, LogMsg.TypeHaveNotIdent, kind, ident.Kind) + ret nil + } + } + + fn evalTypeStatic(mut self, mut d: &Data, mut si: &SubIdentExpr): &Data { + match { + | d.Kind.Prim() != nil: + ret self.evalPrimStatic(d.Kind.Prim().Str(), si.Ident) + | d.Kind.Enum() != nil: + ret self.evalEnumStatic(d.Kind.Enum(), si.Ident) + | d.Kind.TypeEnum() != nil: + ret self.evalTypeEnumStatic(d.Kind.TypeEnum(), si.Ident) + | d.Kind.Struct() != nil: + ret self.evalStructStatic(d.Kind.Struct(), si.Ident) + |: + self.pushErr(si.Ident, LogMsg.TypeNotSupportSubFields, d.Kind.Str()) + ret nil + } + } + + fn comptimeObjSubIdent[ComptimeType](mut self, mut &ct: &ComptimeType, &d: &Data, &si: &SubIdentExpr): &Data { + mut cd := ct.subIdent(si.Ident.Kind) + if cd == nil { + self.pushErr(si.Ident, LogMsg.ObjHaveNotIdent, d.Kind.Str(), si.Ident.Kind) + } + ret cd + } + + fn tryComptimeObjSubIdent(mut self, mut &d: &Data, mut si: &SubIdentExpr): (&Data, bool) { + match { + | d.Kind.comptimeTypeInfo() != nil: + mut ct := d.Kind.comptimeTypeInfo() + ret self.comptimeObjSubIdent(ct, d, si), true + | d.Kind.comptimeStructField() != nil: + mut ct := d.Kind.comptimeStructField() + ret self.comptimeObjSubIdent(ct, d, si), true + | d.Kind.comptimeEnumField() != nil: + mut ct := d.Kind.comptimeEnumField() + ret self.comptimeObjSubIdent(ct, d, si), true + | d.Kind.comptimeParam() != nil: + mut ct := d.Kind.comptimeParam() + ret self.comptimeObjSubIdent(ct, d, si), true + | d.Kind.comptimeStatic() != nil: + mut ct := d.Kind.comptimeStatic() + ret self.comptimeObjSubIdent(ct, d, si), true + | d.Kind.comptimeValue() != nil: + mut ct := d.Kind.comptimeValue() + ret self.comptimeObjSubIdent(ct, d, si), true + | d.Kind.comptimeFile() != nil: + mut ct := d.Kind.comptimeFile() + ret self.comptimeObjSubIdent(ct, d, si), true + |: + ret nil, false + } + } + + fn evalObjSubIdent(mut self, mut d: &Data, mut si: &SubIdentExpr): &Data { + if IsIgnoreIdent(si.Ident.Kind) { + self.pushErr(si.Ident, LogMsg.InvalidSyntax) + ret nil + } + + { + mut compData, ok := self.tryComptimeObjSubIdent(d, si) + if ok { + ret compData + } + } + + mut kind := d.Kind + match { + | d.Kind.Ptr() != nil: + ptr := d.Kind.Ptr() + if ptr.IsUnsafe() { + break + } + if !self.isUnsafe() { + self.pushErr(si.Ident, LogMsg.UnsafeBehaviorAtOutOfUnsafeScope) + } + kind = d.Kind.Ptr().Elem + makeImplicitDeref(d, si.Ident) + | d.Kind.Sptr() != nil: + kind = d.Kind.Sptr().Elem + makeImplicitDeref(d, si.Ident) + } + + match { + | d.Kind.Trait() != nil: + ret self.evalTraitSubIdent(d, d.Kind.Trait(), si.Ident) + | kind.Struct() != nil: + s := kind.Struct() + if isInstancedStruct(s) { + mut usedReferenceElem := d.Kind.Sptr() != nil + ret self.evalStructSubIdent(d, kind.Struct(), si, usedReferenceElem) + } + } + self.pushErr(si.Ident, LogMsg.ObjNotSupportSubFields, d.Kind.Str()) + ret nil + } + + fn evalSubIdent(mut &self, mut si: &SubIdentExpr): &Data { + mut prefix := self.prefix + self.prefix = nil + defer { self.prefix = prefix } + mut d := self.evalExprKind(si.Expr.Kind) + if d == nil { + ret nil + } + if d.Decl { + ret self.evalTypeStatic(d, si) + } + ret self.evalObjSubIdent(d, si) + } + + fn evalTuple(mut &self, mut tup: &TupleExpr): &Data { + mut tupT := new(Tuple) + tupT.Types = make([]&TypeKind, 0, len(tup.Expr)) + + mut model := &TupleExprModel{ + Datas: make([]&Data, 0, len(tup.Expr)), + } + + mut ok := true + for (_, mut expr) in tup.Expr { + mut d := self.evalExpr(expr) + if d == nil { + ok = false + continue + } + tupT.Types = append(tupT.Types, d.Kind) + model.Datas = append(model.Datas, d) + } + + if !ok { + ret nil + } + + ret &Data{ + Kind: &TypeKind{Kind: tupT}, + Model: model, + } + } + + fn evalMap(mut &self, mut m: &Map, mut lit: &BraceLit): &Data { + mut model := &MapExprModel{ + KeyKind: m.Key, + ValKind: m.Val, + } + + for (_, mut expr) in lit.Exprs { + match type expr.Kind { + | &KeyValPair: + // Ok. + break + |: + self.pushErr(lit.Token, LogMsg.InvalidSyntax) + ret nil + } + + mut pair := (&KeyValPair)(expr.Kind) + + mut key := self.evalExpr(pair.Key) + if key == nil { + ret nil + } + + mut val := self.evalExpr(pair.Val) + if val == nil { + ret nil + } + + const destIsRef = false + if self.s.checkValidityForInitExpr(!self.immutable, destIsRef, m.Key, key, pair.Key.Token) { + _ = self.s.checkAssignType(destIsRef, m.Key, key, pair.Key.Token) + } + if self.s.checkValidityForInitExpr(!self.immutable, destIsRef, m.Val, val, pair.Val.Token) { + _ = self.s.checkAssignType(destIsRef, m.Val, val, pair.Val.Token) + } + + model.Entries = append(model.Entries, &KeyValPairExprModel{ + Key: key.Model, + Val: val.Model, + }) + } + + ret &Data{ + Mutable: true, + Kind: &TypeKind{Kind: m}, + Model: model, + } + } + + fn evalBraceLit(mut &self, mut lit: &BraceLit): &Data { + match { + | self.prefix == nil: + self.pushErr(lit.Token, LogMsg.InvalidSyntax) + ret nil + | self.prefix.Map() != nil: + ret self.evalMap(self.prefix.Map(), lit) + | self.prefix.Struct() != nil: + ret self.evalStructLitExplicit(self.prefix.Struct(), lit.Exprs, lit.Token) + |: + self.pushErr(lit.Token, LogMsg.InvalidSyntax) + ret nil + } + } + + fn evalAnonFunc(mut &self, mut decl: &FnDecl): &Data { + mut tc := typeChecker{ + s: self.s, + rootLookup: self.lookup, + lookup: self.lookup, + } + mut ins := tc.buildFunc(decl) + if ins == nil { + ret nil + } + ins.AsAnon = true + mut captured := make([]&Var, 0) + match type self.lookup { + | &scopeChecker: + mut sc := (&scopeChecker)(self.lookup) + mut scc := sc.newChildChecker() + scc.labels = new([]&scopeLabel, nil) + scc.gotos = new([]&scopeGoto, nil) + scc.owner = ins + scc.childIndex = 0 + scc.it = 0 + scc.cse = 0 + scc.captured = unsafe { (&[]&Var)(&captured) } + self.s.checkFnInsSc(ins, scc) + |: + self.s.checkFnIns(ins) + } + + ret &Data{ + Kind: &TypeKind{Kind: ins}, + Model: &AnonFnExprModel{ + Captured: captured, + Func: ins, + Global: self.isGlobal(), + }, + } + } + + fn evalBinary(mut &self, mut op: &BinaryExpr): &Data { + mut bs := binaryEval.newPlain(self) + // Apply prefix for just numericals. + if self.prefix != nil { + prim := self.prefix.Prim() + if prim == nil || !types::IsNum(prim.Str()) { + mut prefix := self.prefix + self.prefix = nil + defer { self.prefix = prefix } + ret bs.eval(op) + } + } + ret bs.eval(op) + } + + fn evalExprKind(mut &self, mut kind: ExprData): &Data { + match type kind { + | &RangeExpr: + mut e := (&RangeExpr)(kind) + ret self.evalExprKind(e.Expr.Kind) + | &LitExpr: + ret self.evalLit((&LitExpr)(kind)) + | &IdentExpr: + ret self.evalIdent((&IdentExpr)(kind)) + | &UnaryExpr: + ret self.evalUnary((&UnaryExpr)(kind)) + | &VariadicExpr: + ret self.evalVariadic((&VariadicExpr)(kind)) + | &UnsafeExpr: + ret self.evalUnsafe((&UnsafeExpr)(kind)) + | &SliceExpr: + ret self.evalSliceExpr((&SliceExpr)(kind)) + | &IndexingExpr: + ret self.evalIndexing((&IndexingExpr)(kind)) + | &SlicingExpr: + ret self.evalSlicing((&SlicingExpr)(kind)) + | &CastExpr: + ret self.evalCast((&CastExpr)(kind)) + | &NsSelectionExpr: + ret self.evalNsSelection((&NsSelectionExpr)(kind)) + | &StructLit: + ret self.evalStructLit((&StructLit)(kind)) + | &TypeDecl: + ret self.evalType((&TypeDecl)(kind)) + | &FnCallExpr: + ret self.evalFnCall((&FnCallExpr)(kind)) + | &SubIdentExpr: + ret self.evalSubIdent((&SubIdentExpr)(kind)) + | &TupleExpr: + ret self.evalTuple((&TupleExpr)(kind)) + | &BraceLit: + ret self.evalBraceLit((&BraceLit)(kind)) + | &FnDecl: + ret self.evalAnonFunc((&FnDecl)(kind)) + | &BinaryExpr: + ret self.evalBinary((&BinaryExpr)(kind)) + |: + ret nil + } + } + + // Returns value data of evaluated expression. + // Returns nil if error occurs. + fn eval1(mut &self, mut expr: &Expr): &Data { + mut d := self.evalExprKind(expr.Kind) + if d == nil || d.Kind == nil { + ret nil + } + + match { + | d.Kind.Fn() != nil: + mut f := d.Kind.Fn() + if f.IsBuiltin() { + self.s.pushErr(expr.Token, LogMsg.BuiltinNotInvoked) + break + } + if len(f.Generics) != len(f.Decl.Generics) { + self.s.pushErr(expr.Token, LogMsg.HasGenerics) + } else if !f.Decl.Statically && f.Decl.IsMethod() { + self.s.pushErr(expr.Token, LogMsg.MethodNotInvoked) + } else { + f.AsAnon = true + } + } + + ret d + } + + // Returns value data of evaluated expression. + // Returns nil if error occurs. + // Accepts comptime expressions as invalid. + fn eval(mut &self, mut expr: &Expr): &Data { + mut d := self.eval1(expr) + if d == nil { + ret nil + } + if (self.owner == nil || !self.owner.Constant) && d.Kind.comptime() { + self.s.pushErr(expr.Token, LogMsg.ComptimeAsExpr) + ret nil + } + ret d + } + + // Returns value data of evaluated expression. + // Returns nil if error occurs. + // Accepts decls as invalid expression. + fn evalExpr1(mut &self, mut expr: &Expr): &Data { + mut d := self.eval1(expr) + match { + | d == nil: + ret nil + | d.Decl: + self.pushErr(expr.Token, LogMsg.InvalidExpr) + ret nil + |: + ret d + } + } + + // Returns value data of evaluated expression. + // Returns nil if error occurs. + // Accepts decls as invalid expression. + fn evalExpr(mut &self, mut expr: &Expr): &Data { + mut d := self.eval(expr) + match { + | d == nil: + ret nil + | d.Decl: + self.pushErr(expr.Token, LogMsg.InvalidExpr) + ret nil + |: + ret d + } + } } struct unaryEval { - e: &Eval - d: &Data - u: &UnaryExpr + e: &Eval + d: &Data + u: &UnaryExpr } impl unaryEval { - static fn new(mut e: &Eval): unaryEval { - ret unaryEval{ - e: e, - } - } - - fn minus(mut self) { - match { - | self.d.Kind == nil: - self.d = nil - ret - | self.d.Kind.Prim() != nil: - if !types::IsNum(self.d.Kind.Str()) { - self.d = nil - ret - } - | self.d.Kind.Struct() != nil: - if self.d.Kind.Struct().Operators.Neg == nil { - self.d = nil - ret - } - |: - self.d = nil - ret - } - - self.d.Lvalue = false - self.d.Mutable = true - - if self.d.IsConst() { - match { - | self.d.Constant.IsF64(): - self.d.Constant.SetF64(-self.d.Constant.ReadF64()) - | self.d.Constant.IsI64(): - self.d.Constant.SetI64(-self.d.Constant.ReadI64()) - | self.d.Constant.IsU64(): - self.d.Constant.SetI64(-self.d.Constant.AsI64()) - |: - panic("unimplemented constant type for unary.minus, this panic call should be unreachable") - } - // Do not self model for constant expressions. It's a overhead, - // because model will be changed to constant by following algorithm. - ret - } - - self.d.Model = &UnaryExprModel{ - Expr: new(Data, *self.d), - Op: self.u.Op, - } - } - - fn plus(mut self) { - match { - | self.d.Kind == nil: - self.d = nil - ret - | self.d.Kind.Prim() != nil: - if !types::IsNum(self.d.Kind.Str()) { - self.d = nil - ret - } - | self.d.Kind.Struct() != nil: - if self.d.Kind.Struct().Operators.Pos == nil { - self.d = nil - ret - } - |: - self.d = nil - ret - } - - self.d.Lvalue = false - self.d.Mutable = true - - if self.d.IsConst() { - match { - | self.d.Constant.IsF64(): - self.d.Constant.SetF64(+self.d.Constant.ReadF64()) - | self.d.Constant.IsI64(): - self.d.Constant.SetI64(+self.d.Constant.ReadI64()) - | self.d.Constant.IsU64(): - self.d.Constant.SetI64(+self.d.Constant.AsI64()) - |: - panic("unimplemented constant type for unary.plus, this panic call should be unreachable") - } - // Do not self model for constant expressions. It's a overhead, - // because model will be changed to constant by following algorithm. - ret - } - - self.d.Model = &UnaryExprModel{ - Expr: new(Data, *self.d), - Op: self.u.Op, - } - } - - fn caret(mut self) { - match { - | self.d.Kind == nil: - self.d = nil - ret - | self.d.Kind.Prim() != nil: - if !types::IsInt(self.d.Kind.Str()) { - self.d = nil - ret - } - | self.d.Kind.Struct() != nil: - if self.d.Kind.Struct().Operators.BitNot == nil { - self.d = nil - ret - } - |: - self.d = nil - ret - } - - self.d.Lvalue = false - self.d.Mutable = true - - if self.d.IsConst() { - match { - | self.d.Constant.IsI64(): - self.d.Constant.SetI64(^self.d.Constant.ReadI64()) - | self.d.Constant.IsU64(): - self.d.Constant.SetU64(^self.d.Constant.ReadU64()) - |: - panic("unimplemented constant type for unary.caret, this panic call should be unreachable") - } - // Do not self model for constant expressions. It's a overhead, - // because model will be changed to constant by following algorithm. - ret - } - - self.d.Model = &UnaryExprModel{ - Expr: new(Data, *self.d), - Op: self.u.Op, - } - } - - fn excl(mut self) { - t := self.d.Kind.Prim() - if t == nil || !t.IsBool() { - self.d = nil - ret - } - - self.d.Lvalue = false - self.d.Mutable = true - - if self.d.IsConst() { - match { - | self.d.Constant.IsBool(): - self.d.Constant.SetBool(!self.d.Constant.ReadBool()) - |: - panic("unimplemented constant type for unary.excl, this panic call should be unreachable") - } - // Do not self model for constant expressions. It's a overhead, - // because model will be changed to constant by following algorithm. - ret - } - - self.d.Model = &UnaryExprModel{ - Expr: new(Data, *self.d), - Op: self.u.Op, - } - } - - fn star(mut self) { - self.d.Model = &UnaryExprModel{ - Expr: new(Data, *self.d), - Op: self.u.Op, - } - - match { - | self.d.Kind.Ptr() != nil: - if !self.e.isUnsafe() { - self.e.pushErr(self.u.Op, LogMsg.UnsafeBehaviorAtOutOfUnsafeScope) - } - - mut t := self.d.Kind.Ptr() - if t.IsUnsafe() { - self.d = nil - ret - } - self.d.Kind = t.Elem - self.d.Mutable = true - | self.d.Kind.Sptr() != nil: - self.d.Kind = self.d.Kind.Sptr().Elem - |: - self.d = nil - ret - } - - self.d.Constant = nil - self.d.untyped = false - self.d.Lvalue = true - } - - fn amper(mut self) { - match type self.d.Model { - | &StructLitExprModel: - mut lit := (&StructLitExprModel)(self.d.Model) - makeStructLitAlloc(self.d, lit) - |: - match { - | canGetPtr(self.d): - self.d.Kind = &TypeKind{ - Kind: &Ptr{Elem: self.d.Kind}, - } - self.d.Model = &UnaryExprModel{ - Expr: new(Data, *self.d), - Op: self.u.Op, - } - |: - self.d = nil - ret - } - } - - self.d.Constant = nil - self.d.untyped = false - self.d.Lvalue = false - self.d.Mutable = true - } - - fn typeDecl(mut self) { - mut tc := typeChecker{ - s: self.e.s, - rootLookup: self.e.lookup, - lookup: self.e.lookup, - errorToken: self.u.Op, - } - match self.u.Op.Id { - | TokenId.Star: - self.d.Kind = &TypeKind{Kind: tc.buildPtrFromType(self.d.Kind)} - self.d.Model = self.d.Kind - | TokenId.Amper: - self.d.Kind = &TypeKind{Kind: tc.buildSptrFromType(self.d.Kind)} - self.d.Model = self.d.Kind - |: - self.e.pushErr(self.u.Op, LogMsg.InvalidExprForUnary, self.u.Op.Kind, self.d.Kind.Str()) - self.d = nil - ret - } - self.d.Decl = true - } - - fn evalData(mut self) { - match self.u.Op.Id { - | TokenId.Star - | TokenId.Amper: - mut prefix := self.e.prefix - self.e.prefix = nil - self.d = self.e.eval(self.u.Expr) - self.e.prefix = prefix - |: - self.d = self.e.eval(self.u.Expr) - } - } - - fn eval(mut self, mut u: &UnaryExpr): &Data { - self.u = u - self.evalData() - if self.d == nil { - ret nil - } - if self.d.Decl { - self.typeDecl() - ret self.d - } - - kind := self.d.Kind - match self.u.Op.Id { - | TokenId.Minus: - self.minus() - | TokenId.Plus: - self.plus() - | TokenId.Caret: - self.caret() - | TokenId.Excl: - self.excl() - | TokenId.Star: - self.star() - | TokenId.Amper: - self.amper() - |: - self.d = nil - } - - match { - | self.d == nil: - self.e.pushErr(self.u.Op, LogMsg.InvalidExprForUnary, self.u.Op.Kind, kind.Str()) - ret nil - | self.d.IsConst(): - self.d.Model = self.d.Constant - } - ret self.d - } + static fn new(mut e: &Eval): unaryEval { + ret unaryEval{ + e: e, + } + } + + fn minus(mut self) { + match { + | self.d.Kind == nil: + self.d = nil + ret + | self.d.Kind.Prim() != nil: + if !types::IsNum(self.d.Kind.Str()) { + self.d = nil + ret + } + | self.d.Kind.Struct() != nil: + if self.d.Kind.Struct().Operators.Neg == nil { + self.d = nil + ret + } + |: + self.d = nil + ret + } + + self.d.Lvalue = false + self.d.Mutable = true + + if self.d.IsConst() { + match { + | self.d.Constant.IsF64(): + self.d.Constant.SetF64(-self.d.Constant.ReadF64()) + | self.d.Constant.IsI64(): + self.d.Constant.SetI64(-self.d.Constant.ReadI64()) + | self.d.Constant.IsU64(): + self.d.Constant.SetI64(-self.d.Constant.AsI64()) + |: + panic("unimplemented constant type for unary.minus, this panic call should be unreachable") + } + // Do not self model for constant expressions. It's a overhead, + // because model will be changed to constant by following algorithm. + ret + } + + self.d.Model = &UnaryExprModel{ + Expr: new(Data, *self.d), + Op: self.u.Op, + } + } + + fn plus(mut self) { + match { + | self.d.Kind == nil: + self.d = nil + ret + | self.d.Kind.Prim() != nil: + if !types::IsNum(self.d.Kind.Str()) { + self.d = nil + ret + } + | self.d.Kind.Struct() != nil: + if self.d.Kind.Struct().Operators.Pos == nil { + self.d = nil + ret + } + |: + self.d = nil + ret + } + + self.d.Lvalue = false + self.d.Mutable = true + + if self.d.IsConst() { + match { + | self.d.Constant.IsF64(): + self.d.Constant.SetF64(+self.d.Constant.ReadF64()) + | self.d.Constant.IsI64(): + self.d.Constant.SetI64(+self.d.Constant.ReadI64()) + | self.d.Constant.IsU64(): + self.d.Constant.SetI64(+self.d.Constant.AsI64()) + |: + panic("unimplemented constant type for unary.plus, this panic call should be unreachable") + } + // Do not self model for constant expressions. It's a overhead, + // because model will be changed to constant by following algorithm. + ret + } + + self.d.Model = &UnaryExprModel{ + Expr: new(Data, *self.d), + Op: self.u.Op, + } + } + + fn caret(mut self) { + match { + | self.d.Kind == nil: + self.d = nil + ret + | self.d.Kind.Prim() != nil: + if !types::IsInt(self.d.Kind.Str()) { + self.d = nil + ret + } + | self.d.Kind.Struct() != nil: + if self.d.Kind.Struct().Operators.BitNot == nil { + self.d = nil + ret + } + |: + self.d = nil + ret + } + + self.d.Lvalue = false + self.d.Mutable = true + + if self.d.IsConst() { + match { + | self.d.Constant.IsI64(): + self.d.Constant.SetI64(^self.d.Constant.ReadI64()) + | self.d.Constant.IsU64(): + self.d.Constant.SetU64(^self.d.Constant.ReadU64()) + |: + panic("unimplemented constant type for unary.caret, this panic call should be unreachable") + } + // Do not self model for constant expressions. It's a overhead, + // because model will be changed to constant by following algorithm. + ret + } + + self.d.Model = &UnaryExprModel{ + Expr: new(Data, *self.d), + Op: self.u.Op, + } + } + + fn excl(mut self) { + t := self.d.Kind.Prim() + if t == nil || !t.IsBool() { + self.d = nil + ret + } + + self.d.Lvalue = false + self.d.Mutable = true + + if self.d.IsConst() { + match { + | self.d.Constant.IsBool(): + self.d.Constant.SetBool(!self.d.Constant.ReadBool()) + |: + panic("unimplemented constant type for unary.excl, this panic call should be unreachable") + } + // Do not self model for constant expressions. It's a overhead, + // because model will be changed to constant by following algorithm. + ret + } + + self.d.Model = &UnaryExprModel{ + Expr: new(Data, *self.d), + Op: self.u.Op, + } + } + + fn star(mut self) { + self.d.Model = &UnaryExprModel{ + Expr: new(Data, *self.d), + Op: self.u.Op, + } + + match { + | self.d.Kind.Ptr() != nil: + if !self.e.isUnsafe() { + self.e.pushErr(self.u.Op, LogMsg.UnsafeBehaviorAtOutOfUnsafeScope) + } + + mut t := self.d.Kind.Ptr() + if t.IsUnsafe() { + self.d = nil + ret + } + self.d.Kind = t.Elem + self.d.Mutable = true + | self.d.Kind.Sptr() != nil: + self.d.Kind = self.d.Kind.Sptr().Elem + |: + self.d = nil + ret + } + + self.d.Constant = nil + self.d.untyped = false + self.d.Lvalue = true + } + + fn amper(mut self) { + match type self.d.Model { + | &StructLitExprModel: + mut lit := (&StructLitExprModel)(self.d.Model) + makeStructLitAlloc(self.d, lit) + |: + match { + | canGetPtr(self.d): + self.d.Kind = &TypeKind{ + Kind: &Ptr{Elem: self.d.Kind}, + } + self.d.Model = &UnaryExprModel{ + Expr: new(Data, *self.d), + Op: self.u.Op, + } + |: + self.d = nil + ret + } + } + + self.d.Constant = nil + self.d.untyped = false + self.d.Lvalue = false + self.d.Mutable = true + } + + fn typeDecl(mut self) { + mut tc := typeChecker{ + s: self.e.s, + rootLookup: self.e.lookup, + lookup: self.e.lookup, + errorToken: self.u.Op, + } + match self.u.Op.Id { + | TokenId.Star: + self.d.Kind = &TypeKind{Kind: tc.buildPtrFromType(self.d.Kind)} + self.d.Model = self.d.Kind + | TokenId.Amper: + self.d.Kind = &TypeKind{Kind: tc.buildSptrFromType(self.d.Kind)} + self.d.Model = self.d.Kind + |: + self.e.pushErr(self.u.Op, LogMsg.InvalidExprForUnary, self.u.Op.Kind, self.d.Kind.Str()) + self.d = nil + ret + } + self.d.Decl = true + } + + fn evalData(mut self) { + match self.u.Op.Id { + | TokenId.Star + | TokenId.Amper: + mut prefix := self.e.prefix + self.e.prefix = nil + self.d = self.e.eval(self.u.Expr) + self.e.prefix = prefix + |: + self.d = self.e.eval(self.u.Expr) + } + } + + fn eval(mut self, mut u: &UnaryExpr): &Data { + self.u = u + self.evalData() + if self.d == nil { + ret nil + } + if self.d.Decl { + self.typeDecl() + ret self.d + } + + kind := self.d.Kind + match self.u.Op.Id { + | TokenId.Minus: + self.minus() + | TokenId.Plus: + self.plus() + | TokenId.Caret: + self.caret() + | TokenId.Excl: + self.excl() + | TokenId.Star: + self.star() + | TokenId.Amper: + self.amper() + |: + self.d = nil + } + + match { + | self.d == nil: + self.e.pushErr(self.u.Op, LogMsg.InvalidExprForUnary, self.u.Op.Kind, kind.Str()) + ret nil + | self.d.IsConst(): + self.d.Model = self.d.Constant + } + ret self.d + } } struct binaryEval { - e: &Eval - l: &Data - r: &Data - op: &Token + e: &Eval + l: &Data + r: &Data + op: &Token } impl binaryEval { - static fn newPlain(mut e: &Eval): binaryEval { - ret binaryEval{ - e: e, - } - } - - static fn new(mut e: &Eval, mut op: &Token): binaryEval { - ret binaryEval{ - e: e, - op: op, - } - } - - // Reports whether types are compatible. - // Also logs error message about incompatibility if types are incompatible. - fn checkTypeCompatibility(mut self): bool { - ret self.e.s.checkTypeCompatibility1(self.l.Kind, self.r, self.op) - } - - fn checkStructCommonOperatorCompatibility(mut self): bool { - let mut overload: &FnIns = nil - match self.op.Id { - | TokenId.Shl: - overload = self.l.Kind.Struct().Operators.Shl - | TokenId.Shr: - overload = self.l.Kind.Struct().Operators.Shr - | TokenId.Plus: - overload = self.l.Kind.Struct().Operators.Add - | TokenId.Minus: - overload = self.l.Kind.Struct().Operators.Sub - | TokenId.Solidus: - overload = self.l.Kind.Struct().Operators.Div - | TokenId.Star: - overload = self.l.Kind.Struct().Operators.Mul - | TokenId.Percent: - overload = self.l.Kind.Struct().Operators.Mod - | TokenId.Amper: - overload = self.l.Kind.Struct().Operators.BitAnd - | TokenId.Vline: - overload = self.l.Kind.Struct().Operators.BitOr - | TokenId.Caret: - overload = self.l.Kind.Struct().Operators.BitXor - |: - self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, self.l.Kind.Str()) - ret false - } - - if overload == nil { - self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, self.l.Kind.Str()) - ret false - } - - mut p := overload.Params[1] - ret self.e.s.checkAssignType(p.Decl.Reference, p.Kind, self.r, self.op) - } - - fn evalComptimeTypeInfo(mut self): &Data { - mut r := self.r.Kind.comptimeTypeInfo() - if r == nil { - self.e.pushErr(self.op, LogMsg.IncompatibleTypes, "comptimeTypeInfo", self.r.Kind.Str()) - ret nil - } - mut l := self.l.Kind.comptimeTypeInfo() - match self.op.Id { - | TokenId.Eqs: - mut constant := Const.NewBool(l.base.Equal(r.base)) - ret &Data{ - Kind: primBool, - Constant: constant, - Model: constant, - } - | TokenId.NotEq: - mut constant := Const.NewBool(!l.base.Equal(r.base)) - ret &Data{ - Kind: primBool, - Constant: constant, - Model: constant, - } - |: - self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, self.l.Kind.Str()) - ret nil - } - } - - fn evalNil(mut self): &Data { - if !self.r.Kind.NilCompatible() { - self.e.pushErr(self.op, LogMsg.IncompatibleTypes, "nil", self.r.Kind.Str()) - ret nil - } - - match self.op.Id { - | TokenId.Eqs - | TokenId.NotEq: - ret &Data{ - Kind: primBool, - } - |: - self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, "nil") - ret nil - } - } - - fn evalEnum(mut self): &Data { - mut enm := self.l.Kind.Enum() - match self.op.Id { - | TokenId.Eqs - | TokenId.NotEq: - mut rkind := self.r.Kind - if self.r.Kind.Enum() != nil { - rkind = self.r.Kind.Enum().Kind.Kind - } - if !self.e.s.checkTypeCompatibility(enm.Kind.Kind, rkind, self.op) { - ret nil - } - ret &Data{ - Kind: primBool, - } - } - - if self.r.Kind.Enum() == nil || enm != self.r.Kind.Enum() { - self.e.pushErr(self.op, LogMsg.IncompatibleTypes, enm.Ident, self.r.Kind.Str()) - ret nil - } - - match self.op.Id { - | TokenId.Gt - | TokenId.Lt - | TokenId.GtEq - | TokenId.LtEq: - if !types::IsNum(enm.Kind.Kind.Str()) { - self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, enm.Ident) - ret nil - } - ret &Data{ - Kind: primBool, - } - | TokenId.Amper: - first := enm.Items[0] - match { - | first.Value.Data.Constant.IsI64(): - if first.Value.Data.Constant.ReadI64() == 0 { - goto next - } - goto err - | first.Value.Data.Constant.IsU64(): - if first.Value.Data.Constant.ReadU64() == 0 { - goto next - } - goto err - |: - panic("unimplemented enum type, this panic call should be unreachable") - } - err: - self.e.pushErr(self.op, LogMsg.AmperOpForEnum, enm.Ident, self.op.Kind) - self.e.pushSuggestion(LogMsg.DefineZeroDefaultToUseAmper) - next: - fall - | TokenId.Vline - | TokenId.Caret: - if enm.Kind.Kind.Prim() == nil || !types::IsInt(enm.Kind.Kind.Prim().Str()) { - self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, enm.Ident) - } - ret self.l - |: - self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, enm.Ident) - ret nil - } - } - - fn evalTypeEnum(mut self): &Data { - mut enm := self.l.Kind.TypeEnum() - if !self.checkTypeCompatibility() { - ret nil - } - - match self.op.Id { - | TokenId.Eqs - | TokenId.NotEq: - ret &Data{ - Kind: primBool, - } - |: - self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, enm.Str()) - ret nil - } - } - - fn evalSptr(mut self): &Data { - if !self.checkTypeCompatibility() { - ret nil - } - - match self.op.Id { - | TokenId.Eqs - | TokenId.NotEq: - ret &Data{ - Kind: primBool, - } - |: - self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, self.l.Kind.Str()) - ret nil - } - } - - fn evalPtr(mut self): &Data { - match self.op.Id { - | TokenId.Eqs - | TokenId.NotEq - | TokenId.Lt - | TokenId.Gt - | TokenId.LtEq - | TokenId.GtEq: - if !self.checkTypeCompatibility() { - ret nil - } - ret &Data{ - Kind: primBool, - } - | TokenId.Plus - | TokenId.Minus: - if self.l.Kind.Ptr() == nil { - self.l, self.r = self.r, self.l - } - if self.l.Kind.Ptr().IsUnsafe() { - self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, self.l.Kind.Str()) - } - if !isPtrArithmeticCompatible(self.l, self.r) { - self.e.pushErr(self.op, LogMsg.IncompatibleTypeForPtrArithmetic, self.r.Kind.Str()) - ret nil - } - ret self.l - |: - self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, self.l.Kind.Str()) - ret nil - } - } - - fn evalArr(mut self): &Data { - if !self.checkTypeCompatibility() { - ret nil - } - - match self.op.Id { - | TokenId.Eqs - | TokenId.NotEq: - ret &Data{ - Kind: primBool, - } - |: - self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, self.l.Kind.Str()) - ret nil - } - } - - fn evalSlc(mut self): &Data { - if !self.checkTypeCompatibility() { - ret nil - } - - match self.op.Id { - | TokenId.Eqs - | TokenId.NotEq: - ret &Data{ - Kind: primBool, - } - |: - self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, self.l.Kind.Str()) - ret nil - } - } - - fn evalStruct(mut self): &Data { - match self.op.Id { - | TokenId.Gt: - if self.l.Kind.Struct().Operators.Gt == nil { - self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, self.l.Kind.Str()) - ret nil - } - ret &Data{ - Kind: primBool, - } - | TokenId.GtEq: - if self.l.Kind.Struct().Operators.GtEq == nil { - self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, self.l.Kind.Str()) - ret nil - } - ret &Data{ - Kind: primBool, - } - | TokenId.Lt: - if self.l.Kind.Struct().Operators.Lt == nil { - self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, self.l.Kind.Str()) - ret nil - } - ret &Data{ - Kind: primBool, - } - | TokenId.LtEq: - if self.l.Kind.Struct().Operators.LtEq == nil { - self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, self.l.Kind.Str()) - ret nil - } - ret &Data{ - Kind: primBool, - } - | TokenId.Eqs - | TokenId.NotEq: - if !self.checkTypeCompatibility() { - ret nil - } - ret &Data{ - Kind: primBool, - } - } - - if !self.checkStructCommonOperatorCompatibility() { - ret nil - } - ret self.l - } - - fn evalTrait(mut self): &Data { - if !self.checkTypeCompatibility() { - ret nil - } - - match self.op.Id { - | TokenId.Eqs - | TokenId.NotEq: - ret &Data{ - Kind: primBool, - } - |: - self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, self.l.Kind.Str()) - ret nil - } - } - - fn evalAny(mut self): &Data { - match self.op.Id { - | TokenId.Eqs - | TokenId.NotEq: - ret &Data{ - Kind: primBool, - } - |: - self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, PrimKind.Any) - ret nil - } - } - - fn evalBool(mut self): &Data { - if !self.checkTypeCompatibility() { - ret nil - } - - match self.op.Id { - | TokenId.Eqs - | TokenId.NotEq - | TokenId.DblAmper - | TokenId.DblVline: - ret self.l - |: - self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, self.l.Kind.Str()) - ret nil - } - } - - fn evalStr(mut self): &Data { - mut rk := self.r.Kind.Str() - if rk != PrimKind.Str { - self.e.pushErr(self.op, LogMsg.IncompatibleTypes, PrimKind.Str, rk) - ret nil - } - - match self.op.Id { - | TokenId.Plus: - ret self.l - | TokenId.Eqs - | TokenId.NotEq - | TokenId.Lt - | TokenId.Gt - | TokenId.GtEq - | TokenId.LtEq: - ret &Data{ - Kind: primBool, - } - |: - self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, PrimKind.Str) - ret nil - } - } - - fn setTypeToGreater(mut self) { - lp := self.l.Kind.Prim() - rp := self.r.Kind.Prim() - if self.l.IsConst() { - if !self.r.IsConst() { - self.l.Kind = self.r.Kind - self.l.Constant.Kind = rp.Kind - ret - } - goto set - } - if self.r.IsConst() { - self.r.Constant.Kind = lp.Kind - ret - } - set: - if self.l.untyped && !self.r.untyped { - self.l.Kind = self.r.Kind - if self.l.IsConst() { - self.l.Constant.Kind = rp.Kind - } - self.l.untyped = false - ret - } else if !self.l.untyped && self.r.untyped { - ret - } - if types::IsGreater(rp.Kind, lp.Kind) { - self.l.Kind = self.r.Kind - if self.l.IsConst() { - self.l.Constant.Kind = rp.Kind - } - } - } - - fn checkModData(mut self, mut &d: &Data) { - if !d.IsConst() { - if d.Kind.Prim() == nil || !types::IsInt(d.Kind.Prim().Kind) { - self.e.pushErr(self.op, LogMsg.ModuloWithNotInt) - } - ret - } - match { - | sigAssignable(PrimKind.I64, d): - d.Constant.SetI64(d.Constant.AsI64()) - | unsigAssignable(PrimKind.U64, d): - d.Constant.SetU64(d.Constant.AsU64()) - |: - self.e.pushErr(self.op, LogMsg.ModuloWithNotInt) - } - } - - fn mod(mut self) { - self.checkModData(self.l) - self.checkModData(self.r) - } - - fn numbersAreCompatibile(self, &lk: str, &rk: str): bool { - if !types::IsNum(rk) { - ret false - } - if self.l.IsConst() && self.l.untyped { - ret true - } - if lk == types::TypeKind.F32 { - if self.r.IsConst() && self.r.untyped { - ret floatAssignable(lk, self.r) - } - ret rk == types::TypeKind.F32 - } - if lk == types::TypeKind.F64 { - if self.r.IsConst() && self.r.untyped { - ret floatAssignable(lk, self.r) - } - ret rk == types::TypeKind.F64 - } - if self.r.IsConst() && self.r.untyped { - ret intAssignable(lk, self.r) - } - ret lk == rk - } - - fn evalFloat(mut self): &Data { - lk := self.l.Kind.Prim().Kind // Float guaranteed. - rk := self.r.Kind.Prim().Kind // Primitive guaranteed. - if !self.numbersAreCompatibile(lk, rk) { - self.e.s.pushCompatiblityError(self.l.Kind, self.r, self.op) - ret nil - } - - match self.op.Id { - | TokenId.Shl - | TokenId.Shr: - if !self.l.IsConst() || !intAssignable(PrimKind.I64, self.l) { - self.e.pushErr(self.op, LogMsg.IncompatibleTypes, lk, rk) - ret nil - } - if !self.r.IsConst() || !intAssignable(PrimKind.U64, self.r) { - self.e.pushErr(self.op, LogMsg.IncompatibleTypes, lk, rk) - ret nil - } - self.l.Constant.SetI64(self.l.Constant.AsI64()) - self.r.Constant.SetU64(self.r.Constant.AsU64()) - if !isOkForShifting(self.r) { - self.e.pushErr(self.op, LogMsg.BitShiftMustUnsigned) - ret nil - } - ret self.l - } - - // Logicals. - match self.op.Id { - | TokenId.Eqs - | TokenId.NotEq - | TokenId.Lt - | TokenId.Gt - | TokenId.GtEq - | TokenId.LtEq: - self.setTypeToGreater() - ret &Data{ - Kind: primBool, - } - } - - // Arithmetics. - match self.op.Id { - | TokenId.Plus - | TokenId.Minus - | TokenId.Star - | TokenId.Solidus: - self.setTypeToGreater() - ret self.l - | TokenId.Percent: - if !types::IsInt(rk) { - self.e.pushErr(self.op, LogMsg.IncompatibleTypes, lk, rk) - ret nil - } - self.mod() - self.setTypeToGreater() - ret self.r - |: - self.e.pushErr(self.op, LogMsg.OperatorNotForFloat, self.op.Kind) - ret nil - } - } - - fn evalInt(mut self): &Data { - lk := self.l.Kind.Prim().Kind // Integer guaranteed. - rk := self.r.Kind.Prim().Kind // Primitive guaranteed. - - match self.op.Id { - | TokenId.Shl - | TokenId.Shr: - if !types::IsInt(lk) || !types::IsInt(rk) { - self.e.pushErr(self.op, LogMsg.IncompatibleTypes, lk, rk) - ret nil - } - if !isOkForShifting(self.r) { - self.e.pushErr(self.op, LogMsg.BitShiftMustUnsigned) - ret nil - } - ret self.l - } - - if !self.numbersAreCompatibile(lk, rk) { - self.e.s.pushCompatiblityError(self.l.Kind, self.r, self.op) - ret nil - } - - // Logicals. - match self.op.Id { - | TokenId.Eqs - | TokenId.NotEq - | TokenId.Lt - | TokenId.Gt - | TokenId.GtEq - | TokenId.LtEq: - ret &Data{ - Kind: primBool, - } - } - - // Arithmetics. - match self.op.Id { - | TokenId.Plus - | TokenId.Minus - | TokenId.Star - | TokenId.Solidus - | TokenId.Amper - | TokenId.Vline - | TokenId.Caret: - self.setTypeToGreater() - ret self.l - | TokenId.Percent: - self.mod() - self.setTypeToGreater() - ret self.l - |: - self.e.pushErr(self.op, LogMsg.OperatorNotForInt, self.op.Kind) - ret nil - } - } - - fn evalPrim(mut self): &Data { - prim := self.l.Kind.Prim() - match { - | prim.IsBool(): - ret self.evalBool() - | prim.IsStr(): - ret self.evalStr() - } - - if self.r.Kind.Prim() == nil { - self.e.pushErr(self.op, LogMsg.IncompatibleTypes, prim.Str(), self.r.Kind.Str()) - ret nil - } - - match { - | types::IsFloat(prim.Kind): - ret self.evalFloat() - | types::IsInt(prim.Kind): - ret self.evalInt() - |: - ret nil - } - } - - fn checkSpecialCases(mut self) { - if !self.l.Kind.Comparable() && !self.r.Kind.IsNil() { - self.e.pushErr(self.op, LogMsg.TypeIsNotComparable, self.l.Kind.Str()) - } else if !self.r.Kind.Comparable() && !self.l.Kind.IsNil() { - self.e.pushErr(self.op, LogMsg.TypeIsNotComparable, self.r.Kind.Str()) - } - } - - fn evalOp(mut self): &Data { - self.checkSpecialCases() - match { - | self.l.Kind.Void(): - self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, "void") - ret nil - | self.r.Kind.comptimeTypeInfo() != nil: - self.l, self.r = self.r, self.l - fall - | self.l.Kind.comptimeTypeInfo() != nil: - ret self.evalComptimeTypeInfo() - | self.r.Kind.Prim() != nil && self.r.Kind.Prim().IsAny(): - self.l, self.r = self.r, self.l - fall - | self.r.Kind.IsNil(): - self.l, self.r = self.r, self.l - fall - | self.l.Kind.IsNil(): - ret self.evalNil() - | self.l.Kind.Prim() != nil && self.l.Kind.Prim().IsAny(): - ret self.evalAny() - | self.r.Kind.TypeEnum() != nil: - self.l, self.r = self.r, self.l - fall - | self.l.Kind.TypeEnum() != nil: - ret self.evalTypeEnum() - | self.r.Kind.Enum() != nil: - self.l, self.r = self.r, self.l - fall - | self.l.Kind.Enum() != nil: - ret self.evalEnum() - | self.r.Kind.Sptr() != nil: - self.l, self.r = self.r, self.l - fall - | self.l.Kind.Sptr() != nil: - ret self.evalSptr() - | self.r.Kind.Ptr() != nil: - self.l, self.r = self.r, self.l - fall - | self.l.Kind.Ptr() != nil: - ret self.evalPtr() - | self.l.Kind.Arr() != nil: - ret self.evalArr() - | self.l.Kind.Slc() != nil: - ret self.evalSlc() - | self.r.Kind.Trait() != nil: - self.l, self.r = self.r, self.l - fall - | self.l.Kind.Trait() != nil: - ret self.evalTrait() - | self.l.Kind.Struct() != nil: - ret self.evalStruct() - | self.l.Kind.Prim() != nil: - ret self.evalPrim() - |: - self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, self.l.Kind.Str()) - ret nil - } - } - - fn evalConst(mut self, mut &d: &Data) { - match { - | d == nil - | self.l.Model == nil - | self.r.Model == nil: - ret - | !self.l.IsConst() - | !self.r.IsConst(): - d.Constant = nil - d.untyped = false - ret - } - - match self.op.Id { - | TokenId.Eqs: - d.Constant = Const.NewBool(self.l.Constant.Eq(*self.r.Constant)) - | TokenId.NotEq: - d.Constant = Const.NewBool(!self.l.Constant.Eq(*self.r.Constant)) - | TokenId.DblVline: - d.Constant = Const.NewBool(self.l.Constant.Or(*self.r.Constant)) - | TokenId.DblAmper: - d.Constant = Const.NewBool(self.l.Constant.And(*self.r.Constant)) - | TokenId.Gt: - d.Constant = Const.NewBool(self.l.Constant.Gt(*self.r.Constant)) - | TokenId.Lt: - d.Constant = Const.NewBool(self.l.Constant.Lt(*self.r.Constant)) - | TokenId.GtEq: - d.Constant = Const.NewBool(self.l.Constant.GtEq(*self.r.Constant)) - | TokenId.LtEq: - d.Constant = Const.NewBool(self.l.Constant.LtEq(*self.r.Constant)) - | TokenId.Plus: - _ = self.l.Constant.Add(*self.r.Constant) - d.Constant = self.l.Constant - | TokenId.Minus: - _ = self.l.Constant.Sub(*self.r.Constant) - d.Constant = self.l.Constant - | TokenId.Star: - _ = self.l.Constant.Mul(*self.r.Constant) - d.Constant = self.l.Constant - | TokenId.Solidus: - ok := self.l.Constant.Div(*self.r.Constant) - if !ok && self.r.Constant.AsF64() == 0 { - self.e.pushErr(self.op, LogMsg.DivByZero) - } - d.Constant = self.l.Constant - mut prim := d.Kind.Prim() - match { - | types::IsSigInt(prim.Kind): - d.Constant.SetI64(d.Constant.AsI64()) - | types::IsUnsigInt(prim.Kind): - d.Constant.SetU64(d.Constant.AsU64()) - } - | TokenId.Percent: - ok := self.l.Constant.Mod(*self.r.Constant) - if !ok && self.r.Constant.AsF64() == 0 { - self.e.pushErr(self.op, LogMsg.DivByZero) - } - d.Constant = self.l.Constant - | TokenId.Vline: - _ = self.l.Constant.BitwiseOr(*self.r.Constant) - d.Constant = self.l.Constant - | TokenId.Amper: - _ = self.l.Constant.BitwiseAnd(*self.r.Constant) - d.Constant = self.l.Constant - | TokenId.Caret: - _ = self.l.Constant.Xor(*self.r.Constant) - d.Constant = self.l.Constant - | TokenId.Shl: - _ = self.l.Constant.Lshift(*self.r.Constant) - d.Constant = self.l.Constant - | TokenId.Shr: - _ = self.l.Constant.Rshift(*self.r.Constant) - d.Constant = self.l.Constant - } - d.Model = d.Constant - applyCastModelByEnum(d, d.Kind.Enum(), self.op) - } - - fn checkData(mut self, mut &d: &Data) { - f := d.Kind.Fn() - if f != nil && f.Decl != nil && f.Decl.IsMethod() { - self.e.pushErr(self.op, LogMsg.InvalidExprForBinary) - } - } - - fn checkDatas(mut self) { - self.checkData(self.l) - self.checkData(self.r) - } - - fn setModel(mut self, mut &d: &Data) { - if d.IsConst() { - if self.l.IsConst() && self.r.IsConst() || - self.l.Model == nil && self.r.Model == nil { - // Left and right are pure constant or comptime expression. - // Do not break this with changing Model. - ret - } - } - mut l, mut r := self.l, self.r - if !l.GoodOperand(r) { - l, r = r, l - } - - d.Model = &BinaryExprModel{ - Left: &OperandExprModel{ - Kind: l.Kind, - Model: l.Model, - }, - Right: &OperandExprModel{ - Kind: r.Kind, - Model: r.Model, - }, - Op: self.op, - } - } - - fn postEval(mut self, mut &d: &Data) { - d.Lvalue = false - self.setModel(d) - } - - fn solveExplicit(mut self, mut &l: &Data, mut &r: &Data): &Data { - self.l, self.r = l, r - - self.checkDatas() - - mut d := self.evalOp() - - // Save normal order - self.l, self.r = l, r - - self.evalConst(d) - - if d != nil { - d.Mutable = true - self.postEval(d) - } - - ret d - } - - fn eval(mut self, mut &op: &BinaryExpr): &Data { - if op.Op.Id == TokenId.Eq { - self.e.pushErr(op.Op, LogMsg.AssignInExpr) - self.e.pushSuggestion(LogMsg.UseImperative) - ret nil - } - - mut l := self.e.evalExpr1(op.Left) - if l == nil || l.Kind == nil { - ret nil - } - - mut prefix := self.e.prefix - self.e.prefix = l.Kind - defer { self.e.prefix = prefix } - mut r := self.e.evalExpr1(op.Right) - if r == nil || r.Kind == nil { - ret nil - } - - self.op = op.Op - - mut d := self.solveExplicit(l, r) - - // Save rune type. - if d != nil && l.IsRune && r.IsRune { - d.IsRune = true - } - - ret d - } + static fn newPlain(mut e: &Eval): binaryEval { + ret binaryEval{ + e: e, + } + } + + static fn new(mut e: &Eval, mut op: &Token): binaryEval { + ret binaryEval{ + e: e, + op: op, + } + } + + // Reports whether types are compatible. + // Also logs error message about incompatibility if types are incompatible. + fn checkTypeCompatibility(mut self): bool { + ret self.e.s.checkTypeCompatibility1(self.l.Kind, self.r, self.op) + } + + fn checkStructCommonOperatorCompatibility(mut self): bool { + let mut overload: &FnIns = nil + match self.op.Id { + | TokenId.Shl: + overload = self.l.Kind.Struct().Operators.Shl + | TokenId.Shr: + overload = self.l.Kind.Struct().Operators.Shr + | TokenId.Plus: + overload = self.l.Kind.Struct().Operators.Add + | TokenId.Minus: + overload = self.l.Kind.Struct().Operators.Sub + | TokenId.Solidus: + overload = self.l.Kind.Struct().Operators.Div + | TokenId.Star: + overload = self.l.Kind.Struct().Operators.Mul + | TokenId.Percent: + overload = self.l.Kind.Struct().Operators.Mod + | TokenId.Amper: + overload = self.l.Kind.Struct().Operators.BitAnd + | TokenId.Vline: + overload = self.l.Kind.Struct().Operators.BitOr + | TokenId.Caret: + overload = self.l.Kind.Struct().Operators.BitXor + |: + self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, self.l.Kind.Str()) + ret false + } + + if overload == nil { + self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, self.l.Kind.Str()) + ret false + } + + mut p := overload.Params[1] + ret self.e.s.checkAssignType(p.Decl.Reference, p.Kind, self.r, self.op) + } + + fn evalComptimeTypeInfo(mut self): &Data { + mut r := self.r.Kind.comptimeTypeInfo() + if r == nil { + self.e.pushErr(self.op, LogMsg.IncompatibleTypes, "comptimeTypeInfo", self.r.Kind.Str()) + ret nil + } + mut l := self.l.Kind.comptimeTypeInfo() + match self.op.Id { + | TokenId.Eqs: + mut constant := Const.NewBool(l.base.Equal(r.base)) + ret &Data{ + Kind: primBool, + Constant: constant, + Model: constant, + } + | TokenId.NotEq: + mut constant := Const.NewBool(!l.base.Equal(r.base)) + ret &Data{ + Kind: primBool, + Constant: constant, + Model: constant, + } + |: + self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, self.l.Kind.Str()) + ret nil + } + } + + fn evalNil(mut self): &Data { + if !self.r.Kind.NilCompatible() { + self.e.pushErr(self.op, LogMsg.IncompatibleTypes, "nil", self.r.Kind.Str()) + ret nil + } + + match self.op.Id { + | TokenId.Eqs + | TokenId.NotEq: + ret &Data{ + Kind: primBool, + } + |: + self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, "nil") + ret nil + } + } + + fn evalEnum(mut self): &Data { + mut enm := self.l.Kind.Enum() + match self.op.Id { + | TokenId.Eqs + | TokenId.NotEq: + mut rkind := self.r.Kind + if self.r.Kind.Enum() != nil { + rkind = self.r.Kind.Enum().Kind.Kind + } + if !self.e.s.checkTypeCompatibility(enm.Kind.Kind, rkind, self.op) { + ret nil + } + ret &Data{ + Kind: primBool, + } + } + + if self.r.Kind.Enum() == nil || enm != self.r.Kind.Enum() { + self.e.pushErr(self.op, LogMsg.IncompatibleTypes, enm.Ident, self.r.Kind.Str()) + ret nil + } + + match self.op.Id { + | TokenId.Gt + | TokenId.Lt + | TokenId.GtEq + | TokenId.LtEq: + if !types::IsNum(enm.Kind.Kind.Str()) { + self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, enm.Ident) + ret nil + } + ret &Data{ + Kind: primBool, + } + | TokenId.Amper: + first := enm.Items[0] + match { + | first.Value.Data.Constant.IsI64(): + if first.Value.Data.Constant.ReadI64() == 0 { + goto next + } + goto err + | first.Value.Data.Constant.IsU64(): + if first.Value.Data.Constant.ReadU64() == 0 { + goto next + } + goto err + |: + panic("unimplemented enum type, this panic call should be unreachable") + } + err: + self.e.pushErr(self.op, LogMsg.AmperOpForEnum, enm.Ident, self.op.Kind) + self.e.pushSuggestion(LogMsg.DefineZeroDefaultToUseAmper) + next: + fall + | TokenId.Vline + | TokenId.Caret: + if enm.Kind.Kind.Prim() == nil || !types::IsInt(enm.Kind.Kind.Prim().Str()) { + self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, enm.Ident) + } + ret self.l + |: + self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, enm.Ident) + ret nil + } + } + + fn evalTypeEnum(mut self): &Data { + mut enm := self.l.Kind.TypeEnum() + if !self.checkTypeCompatibility() { + ret nil + } + + match self.op.Id { + | TokenId.Eqs + | TokenId.NotEq: + ret &Data{ + Kind: primBool, + } + |: + self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, enm.Str()) + ret nil + } + } + + fn evalSptr(mut self): &Data { + if !self.checkTypeCompatibility() { + ret nil + } + + match self.op.Id { + | TokenId.Eqs + | TokenId.NotEq: + ret &Data{ + Kind: primBool, + } + |: + self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, self.l.Kind.Str()) + ret nil + } + } + + fn evalPtr(mut self): &Data { + match self.op.Id { + | TokenId.Eqs + | TokenId.NotEq + | TokenId.Lt + | TokenId.Gt + | TokenId.LtEq + | TokenId.GtEq: + if !self.checkTypeCompatibility() { + ret nil + } + ret &Data{ + Kind: primBool, + } + | TokenId.Plus + | TokenId.Minus: + if self.l.Kind.Ptr() == nil { + self.l, self.r = self.r, self.l + } + if self.l.Kind.Ptr().IsUnsafe() { + self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, self.l.Kind.Str()) + } + if !isPtrArithmeticCompatible(self.l, self.r) { + self.e.pushErr(self.op, LogMsg.IncompatibleTypeForPtrArithmetic, self.r.Kind.Str()) + ret nil + } + ret self.l + |: + self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, self.l.Kind.Str()) + ret nil + } + } + + fn evalArr(mut self): &Data { + if !self.checkTypeCompatibility() { + ret nil + } + + match self.op.Id { + | TokenId.Eqs + | TokenId.NotEq: + ret &Data{ + Kind: primBool, + } + |: + self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, self.l.Kind.Str()) + ret nil + } + } + + fn evalSlc(mut self): &Data { + if !self.checkTypeCompatibility() { + ret nil + } + + match self.op.Id { + | TokenId.Eqs + | TokenId.NotEq: + ret &Data{ + Kind: primBool, + } + |: + self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, self.l.Kind.Str()) + ret nil + } + } + + fn evalStruct(mut self): &Data { + match self.op.Id { + | TokenId.Gt: + if self.l.Kind.Struct().Operators.Gt == nil { + self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, self.l.Kind.Str()) + ret nil + } + ret &Data{ + Kind: primBool, + } + | TokenId.GtEq: + if self.l.Kind.Struct().Operators.GtEq == nil { + self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, self.l.Kind.Str()) + ret nil + } + ret &Data{ + Kind: primBool, + } + | TokenId.Lt: + if self.l.Kind.Struct().Operators.Lt == nil { + self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, self.l.Kind.Str()) + ret nil + } + ret &Data{ + Kind: primBool, + } + | TokenId.LtEq: + if self.l.Kind.Struct().Operators.LtEq == nil { + self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, self.l.Kind.Str()) + ret nil + } + ret &Data{ + Kind: primBool, + } + | TokenId.Eqs + | TokenId.NotEq: + if !self.checkTypeCompatibility() { + ret nil + } + ret &Data{ + Kind: primBool, + } + } + + if !self.checkStructCommonOperatorCompatibility() { + ret nil + } + ret self.l + } + + fn evalTrait(mut self): &Data { + if !self.checkTypeCompatibility() { + ret nil + } + + match self.op.Id { + | TokenId.Eqs + | TokenId.NotEq: + ret &Data{ + Kind: primBool, + } + |: + self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, self.l.Kind.Str()) + ret nil + } + } + + fn evalAny(mut self): &Data { + match self.op.Id { + | TokenId.Eqs + | TokenId.NotEq: + ret &Data{ + Kind: primBool, + } + |: + self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, PrimKind.Any) + ret nil + } + } + + fn evalBool(mut self): &Data { + if !self.checkTypeCompatibility() { + ret nil + } + + match self.op.Id { + | TokenId.Eqs + | TokenId.NotEq + | TokenId.DblAmper + | TokenId.DblVline: + ret self.l + |: + self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, self.l.Kind.Str()) + ret nil + } + } + + fn evalStr(mut self): &Data { + mut rk := self.r.Kind.Str() + if rk != PrimKind.Str { + self.e.pushErr(self.op, LogMsg.IncompatibleTypes, PrimKind.Str, rk) + ret nil + } + + match self.op.Id { + | TokenId.Plus: + ret self.l + | TokenId.Eqs + | TokenId.NotEq + | TokenId.Lt + | TokenId.Gt + | TokenId.GtEq + | TokenId.LtEq: + ret &Data{ + Kind: primBool, + } + |: + self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, PrimKind.Str) + ret nil + } + } + + fn setTypeToGreater(mut self) { + lp := self.l.Kind.Prim() + rp := self.r.Kind.Prim() + if self.l.IsConst() { + if !self.r.IsConst() { + self.l.Kind = self.r.Kind + self.l.Constant.Kind = rp.Kind + ret + } + goto set + } + if self.r.IsConst() { + self.r.Constant.Kind = lp.Kind + ret + } + set: + if self.l.untyped && !self.r.untyped { + self.l.Kind = self.r.Kind + if self.l.IsConst() { + self.l.Constant.Kind = rp.Kind + } + self.l.untyped = false + ret + } else if !self.l.untyped && self.r.untyped { + ret + } + if types::IsGreater(rp.Kind, lp.Kind) { + self.l.Kind = self.r.Kind + if self.l.IsConst() { + self.l.Constant.Kind = rp.Kind + } + } + } + + fn checkModData(mut self, mut &d: &Data) { + if !d.IsConst() { + if d.Kind.Prim() == nil || !types::IsInt(d.Kind.Prim().Kind) { + self.e.pushErr(self.op, LogMsg.ModuloWithNotInt) + } + ret + } + match { + | sigAssignable(PrimKind.I64, d): + d.Constant.SetI64(d.Constant.AsI64()) + | unsigAssignable(PrimKind.U64, d): + d.Constant.SetU64(d.Constant.AsU64()) + |: + self.e.pushErr(self.op, LogMsg.ModuloWithNotInt) + } + } + + fn mod(mut self) { + self.checkModData(self.l) + self.checkModData(self.r) + } + + fn numbersAreCompatibile(self, &lk: str, &rk: str): bool { + if !types::IsNum(rk) { + ret false + } + if self.l.IsConst() && self.l.untyped { + ret true + } + if lk == types::TypeKind.F32 { + if self.r.IsConst() && self.r.untyped { + ret floatAssignable(lk, self.r) + } + ret rk == types::TypeKind.F32 + } + if lk == types::TypeKind.F64 { + if self.r.IsConst() && self.r.untyped { + ret floatAssignable(lk, self.r) + } + ret rk == types::TypeKind.F64 + } + if self.r.IsConst() && self.r.untyped { + ret intAssignable(lk, self.r) + } + ret lk == rk + } + + fn evalFloat(mut self): &Data { + lk := self.l.Kind.Prim().Kind // Float guaranteed. + rk := self.r.Kind.Prim().Kind // Primitive guaranteed. + if !self.numbersAreCompatibile(lk, rk) { + self.e.s.pushCompatiblityError(self.l.Kind, self.r, self.op) + ret nil + } + + match self.op.Id { + | TokenId.Shl + | TokenId.Shr: + if !self.l.IsConst() || !intAssignable(PrimKind.I64, self.l) { + self.e.pushErr(self.op, LogMsg.IncompatibleTypes, lk, rk) + ret nil + } + if !self.r.IsConst() || !intAssignable(PrimKind.U64, self.r) { + self.e.pushErr(self.op, LogMsg.IncompatibleTypes, lk, rk) + ret nil + } + self.l.Constant.SetI64(self.l.Constant.AsI64()) + self.r.Constant.SetU64(self.r.Constant.AsU64()) + if !isOkForShifting(self.r) { + self.e.pushErr(self.op, LogMsg.BitShiftMustUnsigned) + ret nil + } + ret self.l + } + + // Logicals. + match self.op.Id { + | TokenId.Eqs + | TokenId.NotEq + | TokenId.Lt + | TokenId.Gt + | TokenId.GtEq + | TokenId.LtEq: + self.setTypeToGreater() + ret &Data{ + Kind: primBool, + } + } + + // Arithmetics. + match self.op.Id { + | TokenId.Plus + | TokenId.Minus + | TokenId.Star + | TokenId.Solidus: + self.setTypeToGreater() + ret self.l + | TokenId.Percent: + if !types::IsInt(rk) { + self.e.pushErr(self.op, LogMsg.IncompatibleTypes, lk, rk) + ret nil + } + self.mod() + self.setTypeToGreater() + ret self.r + |: + self.e.pushErr(self.op, LogMsg.OperatorNotForFloat, self.op.Kind) + ret nil + } + } + + fn evalInt(mut self): &Data { + lk := self.l.Kind.Prim().Kind // Integer guaranteed. + rk := self.r.Kind.Prim().Kind // Primitive guaranteed. + + match self.op.Id { + | TokenId.Shl + | TokenId.Shr: + if !types::IsInt(lk) || !types::IsInt(rk) { + self.e.pushErr(self.op, LogMsg.IncompatibleTypes, lk, rk) + ret nil + } + if !isOkForShifting(self.r) { + self.e.pushErr(self.op, LogMsg.BitShiftMustUnsigned) + ret nil + } + ret self.l + } + + if !self.numbersAreCompatibile(lk, rk) { + self.e.s.pushCompatiblityError(self.l.Kind, self.r, self.op) + ret nil + } + + // Logicals. + match self.op.Id { + | TokenId.Eqs + | TokenId.NotEq + | TokenId.Lt + | TokenId.Gt + | TokenId.GtEq + | TokenId.LtEq: + ret &Data{ + Kind: primBool, + } + } + + // Arithmetics. + match self.op.Id { + | TokenId.Plus + | TokenId.Minus + | TokenId.Star + | TokenId.Solidus + | TokenId.Amper + | TokenId.Vline + | TokenId.Caret: + self.setTypeToGreater() + ret self.l + | TokenId.Percent: + self.mod() + self.setTypeToGreater() + ret self.l + |: + self.e.pushErr(self.op, LogMsg.OperatorNotForInt, self.op.Kind) + ret nil + } + } + + fn evalPrim(mut self): &Data { + prim := self.l.Kind.Prim() + match { + | prim.IsBool(): + ret self.evalBool() + | prim.IsStr(): + ret self.evalStr() + } + + if self.r.Kind.Prim() == nil { + self.e.pushErr(self.op, LogMsg.IncompatibleTypes, prim.Str(), self.r.Kind.Str()) + ret nil + } + + match { + | types::IsFloat(prim.Kind): + ret self.evalFloat() + | types::IsInt(prim.Kind): + ret self.evalInt() + |: + ret nil + } + } + + fn checkSpecialCases(mut self) { + if !self.l.Kind.Comparable() && !self.r.Kind.IsNil() { + self.e.pushErr(self.op, LogMsg.TypeIsNotComparable, self.l.Kind.Str()) + } else if !self.r.Kind.Comparable() && !self.l.Kind.IsNil() { + self.e.pushErr(self.op, LogMsg.TypeIsNotComparable, self.r.Kind.Str()) + } + } + + fn evalOp(mut self): &Data { + self.checkSpecialCases() + match { + | self.l.Kind.Void(): + self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, "void") + ret nil + | self.r.Kind.comptimeTypeInfo() != nil: + self.l, self.r = self.r, self.l + fall + | self.l.Kind.comptimeTypeInfo() != nil: + ret self.evalComptimeTypeInfo() + | self.r.Kind.Prim() != nil && self.r.Kind.Prim().IsAny(): + self.l, self.r = self.r, self.l + fall + | self.r.Kind.IsNil(): + self.l, self.r = self.r, self.l + fall + | self.l.Kind.IsNil(): + ret self.evalNil() + | self.l.Kind.Prim() != nil && self.l.Kind.Prim().IsAny(): + ret self.evalAny() + | self.r.Kind.TypeEnum() != nil: + self.l, self.r = self.r, self.l + fall + | self.l.Kind.TypeEnum() != nil: + ret self.evalTypeEnum() + | self.r.Kind.Enum() != nil: + self.l, self.r = self.r, self.l + fall + | self.l.Kind.Enum() != nil: + ret self.evalEnum() + | self.r.Kind.Sptr() != nil: + self.l, self.r = self.r, self.l + fall + | self.l.Kind.Sptr() != nil: + ret self.evalSptr() + | self.r.Kind.Ptr() != nil: + self.l, self.r = self.r, self.l + fall + | self.l.Kind.Ptr() != nil: + ret self.evalPtr() + | self.l.Kind.Arr() != nil: + ret self.evalArr() + | self.l.Kind.Slc() != nil: + ret self.evalSlc() + | self.r.Kind.Trait() != nil: + self.l, self.r = self.r, self.l + fall + | self.l.Kind.Trait() != nil: + ret self.evalTrait() + | self.l.Kind.Struct() != nil: + ret self.evalStruct() + | self.l.Kind.Prim() != nil: + ret self.evalPrim() + |: + self.e.pushErr(self.op, LogMsg.OperatorNotForJuleType, self.op.Kind, self.l.Kind.Str()) + ret nil + } + } + + fn evalConst(mut self, mut &d: &Data) { + match { + | d == nil + | self.l.Model == nil + | self.r.Model == nil: + ret + | !self.l.IsConst() + | !self.r.IsConst(): + d.Constant = nil + d.untyped = false + ret + } + + match self.op.Id { + | TokenId.Eqs: + d.Constant = Const.NewBool(self.l.Constant.Eq(*self.r.Constant)) + | TokenId.NotEq: + d.Constant = Const.NewBool(!self.l.Constant.Eq(*self.r.Constant)) + | TokenId.DblVline: + d.Constant = Const.NewBool(self.l.Constant.Or(*self.r.Constant)) + | TokenId.DblAmper: + d.Constant = Const.NewBool(self.l.Constant.And(*self.r.Constant)) + | TokenId.Gt: + d.Constant = Const.NewBool(self.l.Constant.Gt(*self.r.Constant)) + | TokenId.Lt: + d.Constant = Const.NewBool(self.l.Constant.Lt(*self.r.Constant)) + | TokenId.GtEq: + d.Constant = Const.NewBool(self.l.Constant.GtEq(*self.r.Constant)) + | TokenId.LtEq: + d.Constant = Const.NewBool(self.l.Constant.LtEq(*self.r.Constant)) + | TokenId.Plus: + _ = self.l.Constant.Add(*self.r.Constant) + d.Constant = self.l.Constant + | TokenId.Minus: + _ = self.l.Constant.Sub(*self.r.Constant) + d.Constant = self.l.Constant + | TokenId.Star: + _ = self.l.Constant.Mul(*self.r.Constant) + d.Constant = self.l.Constant + | TokenId.Solidus: + ok := self.l.Constant.Div(*self.r.Constant) + if !ok && self.r.Constant.AsF64() == 0 { + self.e.pushErr(self.op, LogMsg.DivByZero) + } + d.Constant = self.l.Constant + mut prim := d.Kind.Prim() + match { + | types::IsSigInt(prim.Kind): + d.Constant.SetI64(d.Constant.AsI64()) + | types::IsUnsigInt(prim.Kind): + d.Constant.SetU64(d.Constant.AsU64()) + } + | TokenId.Percent: + ok := self.l.Constant.Mod(*self.r.Constant) + if !ok && self.r.Constant.AsF64() == 0 { + self.e.pushErr(self.op, LogMsg.DivByZero) + } + d.Constant = self.l.Constant + | TokenId.Vline: + _ = self.l.Constant.BitwiseOr(*self.r.Constant) + d.Constant = self.l.Constant + | TokenId.Amper: + _ = self.l.Constant.BitwiseAnd(*self.r.Constant) + d.Constant = self.l.Constant + | TokenId.Caret: + _ = self.l.Constant.Xor(*self.r.Constant) + d.Constant = self.l.Constant + | TokenId.Shl: + _ = self.l.Constant.Lshift(*self.r.Constant) + d.Constant = self.l.Constant + | TokenId.Shr: + _ = self.l.Constant.Rshift(*self.r.Constant) + d.Constant = self.l.Constant + } + d.Model = d.Constant + applyCastModelByEnum(d, d.Kind.Enum(), self.op) + } + + fn checkData(mut self, mut &d: &Data) { + f := d.Kind.Fn() + if f != nil && f.Decl != nil && f.Decl.IsMethod() { + self.e.pushErr(self.op, LogMsg.InvalidExprForBinary) + } + } + + fn checkDatas(mut self) { + self.checkData(self.l) + self.checkData(self.r) + } + + fn setModel(mut self, mut &d: &Data) { + if d.IsConst() { + if self.l.IsConst() && self.r.IsConst() || + self.l.Model == nil && self.r.Model == nil { + // Left and right are pure constant or comptime expression. + // Do not break this with changing Model. + ret + } + } + mut l, mut r := self.l, self.r + if !l.GoodOperand(r) { + l, r = r, l + } + + d.Model = &BinaryExprModel{ + Left: &OperandExprModel{ + Kind: l.Kind, + Model: l.Model, + }, + Right: &OperandExprModel{ + Kind: r.Kind, + Model: r.Model, + }, + Op: self.op, + } + } + + fn postEval(mut self, mut &d: &Data) { + d.Lvalue = false + self.setModel(d) + } + + fn solveExplicit(mut self, mut &l: &Data, mut &r: &Data): &Data { + self.l, self.r = l, r + + self.checkDatas() + + mut d := self.evalOp() + + // Save normal order + self.l, self.r = l, r + + self.evalConst(d) + + if d != nil { + d.Mutable = true + self.postEval(d) + } + + ret d + } + + fn eval(mut self, mut &op: &BinaryExpr): &Data { + if op.Op.Id == TokenId.Eq { + self.e.pushErr(op.Op, LogMsg.AssignInExpr) + self.e.pushSuggestion(LogMsg.UseImperative) + ret nil + } + + mut l := self.e.evalExpr1(op.Left) + if l == nil || l.Kind == nil { + ret nil + } + + mut prefix := self.e.prefix + self.e.prefix = l.Kind + defer { self.e.prefix = prefix } + mut r := self.e.evalExpr1(op.Right) + if r == nil || r.Kind == nil { + ret nil + } + + self.op = op.Op + + mut d := self.solveExplicit(l, r) + + // Save rune type. + if d != nil && l.IsRune && r.IsRune { + d.IsRune = true + } + + ret d + } } // Returns directive if exist. fn findDirective(mut &directives: []&ast::Directive, d: Directive): &ast::Directive { - for (_, mut dr) in directives { - if dr.Tag.Kind == d { - ret dr - } - } - ret nil + for (_, mut dr) in directives { + if dr.Tag.Kind == d { + ret dr + } + } + ret nil } fn findBuiltinsImport(&ident: str, imp: &ImportInfo): any { - ret findPackageBuiltinDef(imp.LinkPath, ident) + ret findPackageBuiltinDef(imp.LinkPath, ident) } // If current type is not enough to store constant data, update to minimum type @@ -4275,322 +4275,322 @@ fn findBuiltinsImport(&ident: str, imp: &ImportInfo): any { // If data is signed but kind is unsigned, type will be fit to signed and same // thing for unsigned data and signed kinds. fn fitBitsize(mut &d: &Data) { - mut prim := d.Kind.Prim() - z := types::BitsizeOf(prim.Str()) - match { - | d.Constant.IsI64(): - k := types::BitsizeOfInt(d.Constant.ReadI64()) - if k > z || types::IsUnsigInt(prim.Kind) { - d.Constant.Kind = types::IntFromBits(k) - d.Kind = findBuiltinTypeAlias(d.Constant.Kind).Kind.Kind - } - | d.Constant.IsU64(): - k := types::BitsizeOfUint(d.Constant.ReadU64()) - if k > z || types::IsSigInt(prim.Kind) { - d.Constant.Kind = types::UintFromBits(k) - d.Kind = findBuiltinTypeAlias(d.Constant.Kind).Kind.Kind - } - | d.Constant.IsF64(): - if z == 1<<6 { - // z is already equals to biggest bitsize. - ret - } - k := types::BitsizeOfFloat(d.Constant.ReadF64()) - if k > z { - d.Constant.Kind = types::FloatFromBits(k) - d.Kind = findBuiltinTypeAlias(d.Constant.Kind).Kind.Kind - } - } + mut prim := d.Kind.Prim() + z := types::BitsizeOf(prim.Str()) + match { + | d.Constant.IsI64(): + k := types::BitsizeOfInt(d.Constant.ReadI64()) + if k > z || types::IsUnsigInt(prim.Kind) { + d.Constant.Kind = types::IntFromBits(k) + d.Kind = findBuiltinTypeAlias(d.Constant.Kind).Kind.Kind + } + | d.Constant.IsU64(): + k := types::BitsizeOfUint(d.Constant.ReadU64()) + if k > z || types::IsSigInt(prim.Kind) { + d.Constant.Kind = types::UintFromBits(k) + d.Kind = findBuiltinTypeAlias(d.Constant.Kind).Kind.Kind + } + | d.Constant.IsF64(): + if z == 1<<6 { + // z is already equals to biggest bitsize. + ret + } + k := types::BitsizeOfFloat(d.Constant.ReadF64()) + if k > z { + d.Constant.Kind = types::FloatFromBits(k) + d.Kind = findBuiltinTypeAlias(d.Constant.Kind).Kind.Kind + } + } } fn makeStructLitAlloc(mut &d: &Data, mut &lit: &StructLitExprModel) { - d.Kind = &TypeKind{ - Kind: &Sptr{ - Elem: &TypeKind{Kind: lit.Strct}, - }, - } - d.Model = &AllocStructLitExprModel{ - Lit: lit, - } + d.Kind = &TypeKind{ + Kind: &Sptr{ + Elem: &TypeKind{Kind: lit.Strct}, + }, + } + d.Model = &AllocStructLitExprModel{ + Lit: lit, + } } fn buildErrorVar(mut &s: &Scope, mut &fc: &FnCallExpr): &Var { - ret &Var{ - Used: true, - Reference: false, - Mutable: true, - Ident: "error", - Token: fc.Token, - Kind: findBuiltinTypeAlias(PrimKind.Any).Kind, - Scope: s, - Value: &Value{ - Data: new(Data), - }, - } + ret &Var{ + Used: true, + Reference: false, + Mutable: true, + Ident: "error", + Token: fc.Token, + Kind: findBuiltinTypeAlias(PrimKind.Any).Kind, + Scope: s, + Value: &Value{ + Data: new(Data), + }, + } } fn findBuiltinsSema(&ident: str, mut s: &Sema): any { - for (_, mut imp) in s.file.Imports { - if imp.ImportAll || imp.existIdent(ident) { - mut def := findBuiltinsImport(ident, imp) - if def != nil { - ret def - } - } - } - - // If package is std, check for internal builtin defines. - mut ppath := s.file.File.Dir() - if strings::HasPrefix(ppath, PathStdlib) { - // Remove STDLIB directory path. - ppath = ppath[len(PathStdlib):] - // Add "std" to beginning without separator - // because path has separator at beginning. - ppath = "std" + strings::Replace(ppath, str(path::Separator), "::", -1) - - ret findPackageBuiltinDef(ppath, ident) - } - - ret nil + for (_, mut imp) in s.file.Imports { + if imp.ImportAll || imp.existIdent(ident) { + mut def := findBuiltinsImport(ident, imp) + if def != nil { + ret def + } + } + } + + // If package is std, check for internal builtin defines. + mut ppath := s.file.File.Dir() + if strings::HasPrefix(ppath, PathStdlib) { + // Remove STDLIB directory path. + ppath = ppath[len(PathStdlib):] + // Add "std" to beginning without separator + // because path has separator at beginning. + ppath = "std" + strings::Replace(ppath, str(path::Separator), "::", -1) + + ret findPackageBuiltinDef(ppath, ident) + } + + ret nil } fn isOkForShifting(mut &d: &Data): bool { - if d.IsConst() { - match { - | d.Constant.IsI64(): - ret d.Constant.ReadI64() >= 0 - | d.Constant.IsU64(): - ret true - | d.Constant.IsF64(): - ret d.Constant.ReadF64() >= 0 - |: - ret false - } - } - prim := d.Kind.Prim() - ret prim != nil && types::IsInt(prim.Str()) + if d.IsConst() { + match { + | d.Constant.IsI64(): + ret d.Constant.ReadI64() >= 0 + | d.Constant.IsU64(): + ret true + | d.Constant.IsF64(): + ret d.Constant.ReadF64() >= 0 + |: + ret false + } + } + prim := d.Kind.Prim() + ret prim != nil && types::IsInt(prim.Str()) } fn isInstancedStruct(s: &StructIns): bool { - ret len(s.Decl.Generics) == len(s.Generics) + ret len(s.Decl.Generics) == len(s.Generics) } fn isPtrArithmeticCompatible(mut &l: &Data, mut &r: &Data): bool { - ptr := r.Kind.Ptr() - if ptr != nil { - ret l.Kind.Ptr().Elem.Equal(ptr.Elem) - } - if r.IsConst() && r.untyped { - ret intAssignable(types::TypeKind.Int, r) || - intAssignable(types::TypeKind.Uint, r) - } - - mut tcc := typeCompatibilityChecker{ - dest: primInt, - src: r.Kind, - } - if tcc.check() { - ret true - } - tcc.dest = primUint - ret tcc.check() + ptr := r.Kind.Ptr() + if ptr != nil { + ret l.Kind.Ptr().Elem.Equal(ptr.Elem) + } + if r.IsConst() && r.untyped { + ret intAssignable(types::TypeKind.Int, r) || + intAssignable(types::TypeKind.Uint, r) + } + + mut tcc := typeCompatibilityChecker{ + dest: primInt, + src: r.Kind, + } + if tcc.check() { + ret true + } + tcc.dest = primUint + ret tcc.check() } fn applyCastKindModel(mut &d: &Data, mut &t: &TypeKind, mut &token: &Token) { - d.Model = &CastingExprModel{ - Token: token, - Expr: new(Data, *d), - Kind: t, - ExprKind: d.Kind, - } + d.Model = &CastingExprModel{ + Token: token, + Expr: new(Data, *d), + Kind: t, + ExprKind: d.Kind, + } } fn applyCastKind(mut &d: &Data, mut &t: &TypeKind, mut &token: &Token) { - applyCastKindModel(d, t, token) - d.Kind = t + applyCastKindModel(d, t, token) + d.Kind = t } fn buildVoidData(): &Data { - ret &Data{ - Kind: primVoid, - } + ret &Data{ + Kind: primVoid, + } } fn checkDataForIntegerIndexing(mut &d: &Data, mut &token: &Token): (errFmt: LogMsg) { - if d == nil { - ret LogMsg.Empty - } - - match { - | d.Kind.Prim() == nil: - ret LogMsg.InvalidTypeForIndexing - | !types::IsInt(d.Kind.Prim().Str()): - ret LogMsg.InvalidTypeForIndexing - | d.IsConst(): - if d.Constant.AsF64() < 0 { - ret LogMsg.OverflowLimits - } - | d.Kind.Prim() == nil - | d.IsConst() - | types::RealKindOf(d.Kind.Prim().Str()) != types::RealKindOf(PrimKind.Int): - applyCastKind(d, primInt, token) - } - ret LogMsg.Empty + if d == nil { + ret LogMsg.Empty + } + + match { + | d.Kind.Prim() == nil: + ret LogMsg.InvalidTypeForIndexing + | !types::IsInt(d.Kind.Prim().Str()): + ret LogMsg.InvalidTypeForIndexing + | d.IsConst(): + if d.Constant.AsF64() < 0 { + ret LogMsg.OverflowLimits + } + | d.Kind.Prim() == nil + | d.IsConst() + | types::RealKindOf(d.Kind.Prim().Str()) != types::RealKindOf(PrimKind.Int): + applyCastKind(d, primInt, token) + } + ret LogMsg.Empty } // Applies casting Model: to data by enum. // This is necessary to keep exact same type of enum's field type. // The parameter d should be constant data. fn applyCastModelByEnum(mut &d: &Data, mut e: &Enum, mut &token: &Token) { - if e == nil { - ret - } - p := e.Kind.Kind.Prim() - if p.IsStr() { - ret - } - applyCastKindModel(d, e.Kind.Kind, token) + if e == nil { + ret + } + p := e.Kind.Kind.Prim() + if p.IsStr() { + ret + } + applyCastKindModel(d, e.Kind.Kind, token) } fn castConstByType(&t: str, mut &d: &Data) { - match { - | types::IsSigInt(t): - match types::BitsizeOf(types::RealKindOf(t)) { - | 1 << 6: - d.Constant.SetI64(d.Constant.AsI64()) - | 1 << 5: - d.Constant.SetI64(i64(i32(d.Constant.AsI64()))) - | 1 << 4: - d.Constant.SetI64(i64(i16(d.Constant.AsI64()))) - | 1 << 3: - d.Constant.SetI64(i64(i8(d.Constant.AsI64()))) - } - | types::IsUnsigInt(t): - match types::BitsizeOf(types::RealKindOf(t)) { - | 1 << 6: - d.Constant.SetU64(d.Constant.AsU64()) - | 1 << 5: - d.Constant.SetU64(u64(u32(d.Constant.AsU64()))) - | 1 << 4: - d.Constant.SetU64(u64(u16(d.Constant.AsU64()))) - | 1 << 3: - d.Constant.SetU64(u64(u8(d.Constant.AsU64()))) - } - | types::IsFloat(t): - match types::BitsizeOf(types::RealKindOf(t)) { - | 1 << 6: - d.Constant.SetF64(d.Constant.AsF64()) - | 1 << 5: - d.Constant.SetF64(f64(f32(d.Constant.AsF64()))) - } - } + match { + | types::IsSigInt(t): + match types::BitsizeOf(types::RealKindOf(t)) { + | 1 << 6: + d.Constant.SetI64(d.Constant.AsI64()) + | 1 << 5: + d.Constant.SetI64(i64(i32(d.Constant.AsI64()))) + | 1 << 4: + d.Constant.SetI64(i64(i16(d.Constant.AsI64()))) + | 1 << 3: + d.Constant.SetI64(i64(i8(d.Constant.AsI64()))) + } + | types::IsUnsigInt(t): + match types::BitsizeOf(types::RealKindOf(t)) { + | 1 << 6: + d.Constant.SetU64(d.Constant.AsU64()) + | 1 << 5: + d.Constant.SetU64(u64(u32(d.Constant.AsU64()))) + | 1 << 4: + d.Constant.SetU64(u64(u16(d.Constant.AsU64()))) + | 1 << 3: + d.Constant.SetU64(u64(u8(d.Constant.AsU64()))) + } + | types::IsFloat(t): + match types::BitsizeOf(types::RealKindOf(t)) { + | 1 << 6: + d.Constant.SetF64(d.Constant.AsF64()) + | 1 << 5: + d.Constant.SetF64(f64(f32(d.Constant.AsF64()))) + } + } } fn updateModelToGenericIns(mut &m: ExprModel, mut &f: &FnIns) { - match type m { - | &FnIns: - m = f - | &StructSubIdentExprModel: - (&StructSubIdentExprModel)(m).Method = f - | &StructStaticIdentExprModel: - (&StructStaticIdentExprModel)(m).Method = f - } + match type m { + | &FnIns: + m = f + | &StructSubIdentExprModel: + (&StructSubIdentExprModel)(m).Method = f + | &StructStaticIdentExprModel: + (&StructStaticIdentExprModel)(m).Method = f + } } fn pushSubIdentFromExpr(mut expr: ExprData, mut &t: &SubIdentTypeDecl): bool { - match type expr { - | &IdentExpr: - mut e := (&IdentExpr)(expr) - t.Idents = append(t.Idents, &IdentTypeDecl{ - Token: e.Token, - Ident: e.Ident, - }) - | &SubIdentExpr: - mut e := (&SubIdentExpr)(expr) - if !pushSubIdentFromExpr(e.Expr.Kind, t) { - ret false - } - t.Idents = append(t.Idents, &IdentTypeDecl{ - Token: e.Ident, - Ident: e.Ident.Kind, - }) - |: - ret false - } - ret true + match type expr { + | &IdentExpr: + mut e := (&IdentExpr)(expr) + t.Idents = append(t.Idents, &IdentTypeDecl{ + Token: e.Token, + Ident: e.Ident, + }) + | &SubIdentExpr: + mut e := (&SubIdentExpr)(expr) + if !pushSubIdentFromExpr(e.Expr.Kind, t) { + ret false + } + t.Idents = append(t.Idents, &IdentTypeDecl{ + Token: e.Ident, + Ident: e.Ident.Kind, + }) + |: + ret false + } + ret true } fn constoa(&c: &Const): str { - match { - | c.IsI64(): - ret conv::FmtInt(c.ReadI64(), 10) - | c.IsU64(): - ret conv::FmtUint(c.ReadU64(), 10) - |: - ret "" - } + match { + | c.IsI64(): + ret conv::FmtInt(c.ReadI64(), 10) + | c.IsU64(): + ret conv::FmtUint(c.ReadU64(), 10) + |: + ret "" + } } fn evalEnumStatic(mut &enm: &Enum, mut &item: &EnumItem, mut &token: &Token): &Data { - mut d := &Data{ - Kind: &TypeKind{ - Kind: enm, - }, - } - if item != nil { - d.Constant = new(Const, *item.Value.Data.Constant) - d.Model = d.Constant - applyCastModelByEnum(d, enm, token) - } - ret d + mut d := &Data{ + Kind: &TypeKind{ + Kind: enm, + }, + } + if item != nil { + d.Constant = new(Const, *item.Value.Data.Constant) + d.Model = d.Constant + applyCastModelByEnum(d, enm, token) + } + ret d } // Reports whether expression model is literal-based. // Works for literals, sub-idents and castings. // Returns nil if not, otherwise returns the literal model. fn isLitBased(mut &m: ExprModel): &StructLitExprModel { - match type m { - | &StructLitExprModel: - ret (&StructLitExprModel)(m) - | &AllocStructLitExprModel: - ret (&AllocStructLitExprModel)(m).Lit - | &StructSubIdentExprModel: - mut ssi := (&StructSubIdentExprModel)(m) - ret isLitBased(ssi.Expr.Model) - | &CastingExprModel: - mut c := (&CastingExprModel)(m) - ret isLitBased(c.Expr.Model) - |: - ret nil - } + match type m { + | &StructLitExprModel: + ret (&StructLitExprModel)(m) + | &AllocStructLitExprModel: + ret (&AllocStructLitExprModel)(m).Lit + | &StructSubIdentExprModel: + mut ssi := (&StructSubIdentExprModel)(m) + ret isLitBased(ssi.Expr.Model) + | &CastingExprModel: + mut c := (&CastingExprModel)(m) + ret isLitBased(c.Expr.Model) + |: + ret nil + } } fn makeImplicitDeref(mut &d: &Data, mut baseToken: &Token) { - mut unary := &UnaryExprModel{ - Expr: new(Data, *d), - Op: new(Token, *baseToken), - } - unary.Op.Id = TokenId.Star - unary.Op.Kind = TokenKind.Star - d.Model = unary + mut unary := &UnaryExprModel{ + Expr: new(Data, *d), + Op: new(Token, *baseToken), + } + unary.Op.Id = TokenId.Star + unary.Op.Kind = TokenKind.Star + d.Model = unary } // Updates ref's old references to new. fn updateRefer[T](mut ref: &ReferenceStack, &old: T, mut &new: T) { - for i, sym in ref.buffer { - if sym == old { - ref.buffer[i] = new - } - } + for i, sym in ref.buffer { + if sym == old { + ref.buffer[i] = new + } + } } fn makeVariadic(mut &d: &Data, mut elem: &TypeKind) { - d.Kind = &TypeKind{ - Variadic: true, - Generic: elem.Generic, - BindIdent: elem.BindIdent, - Kind: elem.Kind, - } + d.Kind = &TypeKind{ + Variadic: true, + Generic: elem.Generic, + BindIdent: elem.BindIdent, + Kind: elem.Kind, + } } // Reports whether variable is captured from parent scope. @@ -4599,18 +4599,18 @@ fn makeVariadic(mut &d: &Data, mut elem: &TypeKind) { // - s: current scope which is v accessed from // - v: variable to check fn isVarCaptured(r: &scopeChecker, mut s: &scopeChecker, v: &Var): bool { - if v.Scope == nil { // Global scope variable. - ret false - } - for { - if s.scope == v.Scope { - ret false - } - // Break iteration if parent is not exist or scope already reached to root. - if s.parent == nil || s == r { - break - } - s = s.parent - } - ret true + if v.Scope == nil { // Global scope variable. + ret false + } + for { + if s.scope == v.Scope { + ret false + } + // Break iteration if parent is not exist or scope already reached to root. + if s.parent == nil || s == r { + break + } + s = s.parent + } + ret true } \ No newline at end of file diff --git a/std/jule/sema/fn.jule b/std/jule/sema/fn.jule index cc1669417..558abb98a 100644 --- a/std/jule/sema/fn.jule +++ b/std/jule/sema/fn.jule @@ -9,382 +9,382 @@ use std::internal::strings::{StrBuilder} // Return type. struct RetType { - Kind: &TypeSymbol - Idents: []&Token + Kind: &TypeSymbol + Idents: []&Token } // Parameter. struct Param { - Token: &Token - Mutable: bool - Variadic: bool - Reference: bool - Kind: &TypeSymbol - Ident: str + Token: &Token + Mutable: bool + Variadic: bool + Reference: bool + Kind: &TypeSymbol + Ident: str } impl Param { - fn instance(mut &self): &ParamIns { - ret &ParamIns{ - Decl: self, - } - } - - // Reports whether parameter is self (receiver) parameter. - fn IsSelf(self): bool { - ret self.Ident == "&self" || self.Ident == "self" - } - - // Reports whether self (receiver) parameter is reference. - fn IsRef(self): bool { - ret self.Ident != "" && self.Ident[0] == '&' - } + fn instance(mut &self): &ParamIns { + ret &ParamIns{ + Decl: self, + } + } + + // Reports whether parameter is self (receiver) parameter. + fn IsSelf(self): bool { + ret self.Ident == "&self" || self.Ident == "self" + } + + // Reports whether self (receiver) parameter is reference. + fn IsRef(self): bool { + ret self.Ident != "" && self.Ident[0] == '&' + } } // Function. struct Fn { - sema: &Sema - - Token: &Token - Global: bool - Unsafety: bool - Public: bool - Binded: bool - Statically: bool - Exceptional: bool - Ident: str - Directives: []&Directive - Scope: &ScopeTree - Generics: []&GenericDecl - Result: &RetType - Params: []&Param - Owner: &Struct - - // Function instances for each unique type combination of function call. - // Nil if function is never used. - Instances: []&FnIns + sema: &Sema + + Token: &Token + Global: bool + Unsafety: bool + Public: bool + Binded: bool + Statically: bool + Exceptional: bool + Ident: str + Directives: []&Directive + Scope: &ScopeTree + Generics: []&GenericDecl + Result: &RetType + Params: []&Param + Owner: &Struct + + // Function instances for each unique type combination of function call. + // Nil if function is never used. + Instances: []&FnIns } impl Fn { - // Reports whether return type is void. - fn IsVoid(self): bool { - ret self.Result == nil - } - - // Reports whether function is method. - fn IsMethod(self): bool { - ret self.Owner != nil - } - - // Reports whether function is entry point. - fn IsEntryPoint(self): bool { - ret self.Ident == EntryPoint - } - - // Reports whether function is initializer function. - fn IsInit(self): bool { - ret self.Ident == InitFn - } - - // Reports whether function is anonymous function. - fn IsAnon(self): bool { - ret IsAnonIdent(self.Ident) - } - - // Reports whether function has return variable(s). - fn AnyVar(self): bool { - ret self.Result != nil && len(self.Result.Idents) > 0 - } - - // Force to new instance. - fn instanceForce(mut &self): &FnIns { - mut ins := &FnIns{ - Decl: self, - Scope: new(Scope), - Refers: ReferenceStack.new(), - } - - ins.Params = make([]&ParamIns, 0, len(self.Params)) - for (_, mut p) in self.Params { - ins.Params = append(ins.Params, p.instance()) - } - - if ins.Decl.Result != nil { - ins.Result = ins.Decl.Result.Kind.Kind - } - - ret ins - } - - fn instance(mut &self): &FnIns { - // Returns already created instance for just one unique combination. - if len(self.Generics) == 0 && len(self.Instances) == 1 { - ret self.Instances[0] - } - ret self.instanceForce() - } - - // Appends function instance. - // Returns instance if already instance is already exist, nil if not. - fn appendInstance(mut self, mut &ins: &FnIns): &FnIns { - if len(self.Generics) == 0 { - // Skip already created instance for just one unique combination. - if len(self.Instances) == 1 { - ret self.Instances[0] - } - - self.Instances = append(self.Instances, ins) - ret nil - } - - if len(self.Instances) == 0 { - self.Instances = append(self.Instances, ins) - ret nil - } - - for (_, mut ains) in self.Instances { - if ains.Same(ins) { - // Instances are same. - ret ains - } - } - - self.Instances = append(self.Instances, ins) - ret nil - } + // Reports whether return type is void. + fn IsVoid(self): bool { + ret self.Result == nil + } + + // Reports whether function is method. + fn IsMethod(self): bool { + ret self.Owner != nil + } + + // Reports whether function is entry point. + fn IsEntryPoint(self): bool { + ret self.Ident == EntryPoint + } + + // Reports whether function is initializer function. + fn IsInit(self): bool { + ret self.Ident == InitFn + } + + // Reports whether function is anonymous function. + fn IsAnon(self): bool { + ret IsAnonIdent(self.Ident) + } + + // Reports whether function has return variable(s). + fn AnyVar(self): bool { + ret self.Result != nil && len(self.Result.Idents) > 0 + } + + // Force to new instance. + fn instanceForce(mut &self): &FnIns { + mut ins := &FnIns{ + Decl: self, + Scope: new(Scope), + Refers: ReferenceStack.new(), + } + + ins.Params = make([]&ParamIns, 0, len(self.Params)) + for (_, mut p) in self.Params { + ins.Params = append(ins.Params, p.instance()) + } + + if ins.Decl.Result != nil { + ins.Result = ins.Decl.Result.Kind.Kind + } + + ret ins + } + + fn instance(mut &self): &FnIns { + // Returns already created instance for just one unique combination. + if len(self.Generics) == 0 && len(self.Instances) == 1 { + ret self.Instances[0] + } + ret self.instanceForce() + } + + // Appends function instance. + // Returns instance if already instance is already exist, nil if not. + fn appendInstance(mut self, mut &ins: &FnIns): &FnIns { + if len(self.Generics) == 0 { + // Skip already created instance for just one unique combination. + if len(self.Instances) == 1 { + ret self.Instances[0] + } + + self.Instances = append(self.Instances, ins) + ret nil + } + + if len(self.Instances) == 0 { + self.Instances = append(self.Instances, ins) + ret nil + } + + for (_, mut ains) in self.Instances { + if ains.Same(ins) { + // Instances are same. + ret ains + } + } + + self.Instances = append(self.Instances, ins) + ret nil + } } // Parameter instance. struct ParamIns { - Decl: &Param - Kind: &TypeKind + Decl: &Param + Kind: &TypeKind } impl ParamIns { - // Implement: Kind - // Returns ParamIns's type kind as string. - fn Str(self): str { - mut s := StrBuilder.New(1 << 5) - if self.Decl.Mutable { - s.WriteStr("mut ") - } - - if self.Decl.Reference { - s.WriteStr("&_:") - } - - if self.Decl.IsSelf() { - if self.Decl.IsRef() { - s.WriteByte('&') - } - s.WriteStr("self") - ret s.Str() - } - - if self.Decl.Variadic { - s.WriteStr("...") - } - if self.Kind != nil { - s.WriteStr(self.Kind.Str()) - } - ret s.Str() - } + // Implement: Kind + // Returns ParamIns's type kind as string. + fn Str(self): str { + mut s := StrBuilder.New(1 << 5) + if self.Decl.Mutable { + s.WriteStr("mut ") + } + + if self.Decl.Reference { + s.WriteStr("&_:") + } + + if self.Decl.IsSelf() { + if self.Decl.IsRef() { + s.WriteByte('&') + } + s.WriteStr("self") + ret s.Str() + } + + if self.Decl.Variadic { + s.WriteStr("...") + } + if self.Kind != nil { + s.WriteStr(self.Kind.Str()) + } + ret s.Str() + } } // Function instance. struct FnIns { - Owner: &StructIns - Decl: &Fn - Generics: []&InsGeneric - Params: []&ParamIns - Result: &TypeKind - Scope: &Scope - Refers: &ReferenceStack - Anon: bool - AsAnon: bool // Whether this function instance used as anonymous function. - - caller: builtinCaller - reloaded: bool + Owner: &StructIns + Decl: &Fn + Generics: []&InsGeneric + Params: []&ParamIns + Result: &TypeKind + Scope: &Scope + Refers: &ReferenceStack + Anon: bool + AsAnon: bool // Whether this function instance used as anonymous function. + + caller: builtinCaller + reloaded: bool } impl Kind for FnIns { - // Implement: Kind - // Returns Fn's type kind as string. - fn Str(self): str { - const Ident = false - ret self.GetKindStr(Ident) - } - - // Reports whether types are same. - fn Equal(&self, other: &TypeKind): bool { - f := unsafe { (*(&other)).Fn() } - if f == nil { - ret false - } - ret self.EqualFn(f) - } + // Implement: Kind + // Returns Fn's type kind as string. + fn Str(self): str { + const Ident = false + ret self.GetKindStr(Ident) + } + + // Reports whether types are same. + fn Equal(&self, other: &TypeKind): bool { + f := unsafe { (*(&other)).Fn() } + if f == nil { + ret false + } + ret self.EqualFn(f) + } } impl FnIns { - // Reports whether functions are equals. - fn EqualFn(&self, &f: &FnIns): bool { - if self.Decl.Exceptional != f.Decl.Exceptional { - ret false - } - if self.Decl.Unsafety != f.Decl.Unsafety { - ret false - } - if self.Decl.IsVoid() != f.Decl.IsVoid() { - ret false - } - checkParams := fn(p1: &ParamIns, p2: &ParamIns): bool { - if p1.Decl.Mutable != p2.Decl.Mutable { - ret false - } - - if p1.Decl.IsSelf() { - if !p2.Decl.IsSelf() { - ret false - } - - if p1.Decl.IsRef() != p2.Decl.IsRef() { - ret false - } - - ret true - } - - if p1.Decl.Reference != p2.Decl.Reference { - ret false - } - - if p1.Decl.Variadic != p2.Decl.Variadic { - ret false - } - - ret p1.Kind.Equal(p2.Kind) - } - - if len(f.Params) != len(self.Params) { - ret false - } - - mut i := 0 - for i < len(self.Params); i++ { - if !checkParams(self.Params[i], f.Params[i]) { - ret false - } - } - - if !self.Decl.IsVoid() { - if !self.Result.Equal(f.Result) { - ret false - } - } - - ret true - } - - // Reports whether functions are equals by trait implementation rules. - fn equalTrait(&self, &other: &FnIns): bool { - if self.Decl.Public != other.Decl.Public { - ret false - } - if self.Decl.Ident != other.Decl.Ident { - ret false - } - if !self.EqualFn(other) { - ret false - } - if len(self.Decl.Generics) != len(other.Decl.Generics) { - ret false - } - ret true - } - - // Returns all types of result. - // Returns nil if result is nil. - // Returns mutable slice if returns internal slice. - fn Types(mut self): []&TypeKind { - match { - | self.Result == nil: - ret nil - | self.Result.Tup() == nil: - ret [self.Result] - |: - ret self.Result.Tup().Types - } - } - - // Reports whether instance is built-in. - fn IsBuiltin(self): bool { - ret self.caller != nil - } - - // Reports whether instance is anonymous function. - fn IsAnon(self): bool { - ret self.Anon || - self.Decl != nil && self.Decl.IsAnon() - } - - // Reports whether instances are same. - // Returns true if declarations and generics are same. - fn Same(self, f: &FnIns): bool { - if self.Decl != f.Decl || len(f.Generics) != len(self.Generics) { - ret false - } - - for i, g in self.Generics { - g2 := f.Generics[i] - if g.Kind.BindIdent != g2.Kind.BindIdent || !g.Kind.Equal(g2.Kind) { - ret false - } - } - ret true - } - - // Returns kind string of function instance. - // Appends identifier to kind of this instance. - // Does not appends identifier of this instance to kind if self.Decl is nil reference. - fn GetKindStr(self, ident: bool): str { - mut s := StrBuilder.New(1 << 5) - - if self.Decl.Unsafety { - s.WriteStr("unsafe ") - } - - s.WriteStr("fn") - - if ident && self.Decl != nil { - s.WriteByte(' ') - s.WriteStr(self.Decl.Ident) - } - - s.WriteByte('(') - n := len(self.Params) - if n > 0 { - for i, p in self.Params { - s.WriteStr(p.Str()) - if i < len(self.Params)-1 { - s.WriteByte(',') - } - } - } - s.WriteByte(')') - if self.Decl.Exceptional { - s.WriteByte('!') - } - if !self.Decl.IsVoid() { - s.WriteByte(':') - s.WriteStr(self.Result.Str()) - } - ret s.Str() - } + // Reports whether functions are equals. + fn EqualFn(&self, &f: &FnIns): bool { + if self.Decl.Exceptional != f.Decl.Exceptional { + ret false + } + if self.Decl.Unsafety != f.Decl.Unsafety { + ret false + } + if self.Decl.IsVoid() != f.Decl.IsVoid() { + ret false + } + checkParams := fn(p1: &ParamIns, p2: &ParamIns): bool { + if p1.Decl.Mutable != p2.Decl.Mutable { + ret false + } + + if p1.Decl.IsSelf() { + if !p2.Decl.IsSelf() { + ret false + } + + if p1.Decl.IsRef() != p2.Decl.IsRef() { + ret false + } + + ret true + } + + if p1.Decl.Reference != p2.Decl.Reference { + ret false + } + + if p1.Decl.Variadic != p2.Decl.Variadic { + ret false + } + + ret p1.Kind.Equal(p2.Kind) + } + + if len(f.Params) != len(self.Params) { + ret false + } + + mut i := 0 + for i < len(self.Params); i++ { + if !checkParams(self.Params[i], f.Params[i]) { + ret false + } + } + + if !self.Decl.IsVoid() { + if !self.Result.Equal(f.Result) { + ret false + } + } + + ret true + } + + // Reports whether functions are equals by trait implementation rules. + fn equalTrait(&self, &other: &FnIns): bool { + if self.Decl.Public != other.Decl.Public { + ret false + } + if self.Decl.Ident != other.Decl.Ident { + ret false + } + if !self.EqualFn(other) { + ret false + } + if len(self.Decl.Generics) != len(other.Decl.Generics) { + ret false + } + ret true + } + + // Returns all types of result. + // Returns nil if result is nil. + // Returns mutable slice if returns internal slice. + fn Types(mut self): []&TypeKind { + match { + | self.Result == nil: + ret nil + | self.Result.Tup() == nil: + ret [self.Result] + |: + ret self.Result.Tup().Types + } + } + + // Reports whether instance is built-in. + fn IsBuiltin(self): bool { + ret self.caller != nil + } + + // Reports whether instance is anonymous function. + fn IsAnon(self): bool { + ret self.Anon || + self.Decl != nil && self.Decl.IsAnon() + } + + // Reports whether instances are same. + // Returns true if declarations and generics are same. + fn Same(self, f: &FnIns): bool { + if self.Decl != f.Decl || len(f.Generics) != len(self.Generics) { + ret false + } + + for i, g in self.Generics { + g2 := f.Generics[i] + if g.Kind.BindIdent != g2.Kind.BindIdent || !g.Kind.Equal(g2.Kind) { + ret false + } + } + ret true + } + + // Returns kind string of function instance. + // Appends identifier to kind of this instance. + // Does not appends identifier of this instance to kind if self.Decl is nil reference. + fn GetKindStr(self, ident: bool): str { + mut s := StrBuilder.New(1 << 5) + + if self.Decl.Unsafety { + s.WriteStr("unsafe ") + } + + s.WriteStr("fn") + + if ident && self.Decl != nil { + s.WriteByte(' ') + s.WriteStr(self.Decl.Ident) + } + + s.WriteByte('(') + n := len(self.Params) + if n > 0 { + for i, p in self.Params { + s.WriteStr(p.Str()) + if i < len(self.Params)-1 { + s.WriteByte(',') + } + } + } + s.WriteByte(')') + if self.Decl.Exceptional { + s.WriteByte('!') + } + if !self.Decl.IsVoid() { + s.WriteByte(':') + s.WriteStr(self.Result.Str()) + } + ret s.Str() + } } fn parameterUsesGenerics(mut &p: &ParamIns, &generics: []&GenericDecl): bool { - if p.Decl.IsSelf() { - ret false - } - ret kindUsesGenerics(p.Kind, generics) + if p.Decl.IsSelf() { + ret false + } + ret kindUsesGenerics(p.Kind, generics) } \ No newline at end of file diff --git a/std/jule/sema/impl.jule b/std/jule/sema/impl.jule index 2973d66ac..38000d10f 100644 --- a/std/jule/sema/impl.jule +++ b/std/jule/sema/impl.jule @@ -6,23 +6,23 @@ use std::jule::ast::{TypeDecl} // Implementation. struct Impl { - // Equavalent to ast::Impl's base field. - Base: &TypeDecl + // Equavalent to ast::Impl's base field. + Base: &TypeDecl - // Equavalent to ast::Impl's dest field. - Dest: &TypeDecl + // Equavalent to ast::Impl's dest field. + Dest: &TypeDecl - // Equavalent to ast::Impl's methods field. - Methods: []&Fn + // Equavalent to ast::Impl's methods field. + Methods: []&Fn - // Equavalent to ast::Impl's statics field. - Statics: []&Var + // Equavalent to ast::Impl's statics field. + Statics: []&Var } impl Impl { - // Reports whether implementation type is trait to structure. - fn IsTraitImpl(self): bool { ret self.Base != nil } + // Reports whether implementation type is trait to structure. + fn IsTraitImpl(self): bool { ret self.Base != nil } - // Reports whether implementation type is append to destination structure. - fn IsStructImpl(self): bool { ret self.Base == nil } + // Reports whether implementation type is append to destination structure. + fn IsStructImpl(self): bool { ret self.Base == nil } } \ No newline at end of file diff --git a/std/jule/sema/lookup.jule b/std/jule/sema/lookup.jule index 1c2dce249..8190cdee0 100644 --- a/std/jule/sema/lookup.jule +++ b/std/jule/sema/lookup.jule @@ -4,35 +4,35 @@ // Lookup. trait Lookup { - // Select imported package. - // Returns nil reference if did not found any match. - fn SelectPackage(mut self, selector: fn(&ImportInfo): bool): &ImportInfo + // Select imported package. + // Returns nil reference if did not found any match. + fn SelectPackage(mut self, selector: fn(&ImportInfo): bool): &ImportInfo - // Find variable by identifier and binded state. - // Returns nil reference if did not found any match. - fn FindVar(mut self, ident: str, binded: bool): &Var + // Find variable by identifier and binded state. + // Returns nil reference if did not found any match. + fn FindVar(mut self, ident: str, binded: bool): &Var - // Find type alias by identifier and binded state. - // Returns nil reference if did not found any match. - fn FindTypeAlias(mut self, ident: str, binded: bool): &TypeAlias + // Find type alias by identifier and binded state. + // Returns nil reference if did not found any match. + fn FindTypeAlias(mut self, ident: str, binded: bool): &TypeAlias - // Find structure by identifier and binded state. - // Returns nil reference if did not found any match. - fn FindStruct(mut self, ident: str, binded: bool): &Struct + // Find structure by identifier and binded state. + // Returns nil reference if did not found any match. + fn FindStruct(mut self, ident: str, binded: bool): &Struct - // Find function by identifier and binded state. - // Returns nil reference if did not found any match. - fn FindFn(mut self, ident: str, binded: bool): &Fn + // Find function by identifier and binded state. + // Returns nil reference if did not found any match. + fn FindFn(mut self, ident: str, binded: bool): &Fn - // Find trait by identifier. - // Returns nil reference if did not found any match. - fn FindTrait(mut self, ident: str): &Trait + // Find trait by identifier. + // Returns nil reference if did not found any match. + fn FindTrait(mut self, ident: str): &Trait - // Find enum by identifier. - // Returns nil reference if did not found any match. - fn FindEnum(mut self, ident: str): &Enum + // Find enum by identifier. + // Returns nil reference if did not found any match. + fn FindEnum(mut self, ident: str): &Enum - // Find type enum by identifier. - // Returns nil reference if did not found any match. - fn FindTypeEnum(mut self, ident: str): &TypeEnum + // Find type enum by identifier. + // Returns nil reference if did not found any match. + fn FindTypeEnum(mut self, ident: str): &TypeEnum } \ No newline at end of file diff --git a/std/jule/sema/model.jule b/std/jule/sema/model.jule index 7e6f3ae70..000153a5c 100644 --- a/std/jule/sema/model.jule +++ b/std/jule/sema/model.jule @@ -7,307 +7,307 @@ use std::jule::constant::{Const} // Expression Model:. enum ExprModel: type { - &TypeKind, - &Const, - &Var, - &FnIns, - &StructIns, - &OperandExprModel, - &BinaryExprModel, - &UnaryExprModel, - &StructArgExprModel, - &StructLitExprModel, - &AllocStructLitExprModel, - &CastingExprModel, - &FnCallExprModel, - &SliceExprModel, - &IndexingExprModel, - &AnonFnExprModel, - &KeyValPairExprModel, - &MapExprModel, - &SlicingExprModel, - &TraitSubIdentExprModel, - &StructSubIdentExprModel, - &StructStaticIdentExprModel, - &ArrayExprModel, - &TupleExprModel, - &BuiltinOutCallExprModel, - &BuiltinOutlnCallExprModel, - &BuiltinNewCallExprModel, - &BuiltinPanicCallExprModel, - &BuiltinAssertCallExprModel, - &BuiltinMakeCallExprModel, - &BuiltinAppendCallExprModel, - &BuiltinCopyCallExprModel, - &BuiltinLenCallExprModel, - &BuiltinCapCallExprModel, - &BuiltinDeleteCallExprModel, - &BuiltinErrorCallExprModel, - &SizeofExprModel, - &AlignofExprModel, - &RuneExprModel, - &IntegratedToStrExprModel, - &BackendEmitExprModel, - &FreeExprModel, + &TypeKind, + &Const, + &Var, + &FnIns, + &StructIns, + &OperandExprModel, + &BinaryExprModel, + &UnaryExprModel, + &StructArgExprModel, + &StructLitExprModel, + &AllocStructLitExprModel, + &CastingExprModel, + &FnCallExprModel, + &SliceExprModel, + &IndexingExprModel, + &AnonFnExprModel, + &KeyValPairExprModel, + &MapExprModel, + &SlicingExprModel, + &TraitSubIdentExprModel, + &StructSubIdentExprModel, + &StructStaticIdentExprModel, + &ArrayExprModel, + &TupleExprModel, + &BuiltinOutCallExprModel, + &BuiltinOutlnCallExprModel, + &BuiltinNewCallExprModel, + &BuiltinPanicCallExprModel, + &BuiltinAssertCallExprModel, + &BuiltinMakeCallExprModel, + &BuiltinAppendCallExprModel, + &BuiltinCopyCallExprModel, + &BuiltinLenCallExprModel, + &BuiltinCapCallExprModel, + &BuiltinDeleteCallExprModel, + &BuiltinErrorCallExprModel, + &SizeofExprModel, + &AlignofExprModel, + &RuneExprModel, + &IntegratedToStrExprModel, + &BackendEmitExprModel, + &FreeExprModel, } // Operand expression Model:. struct OperandExprModel { - Kind: &TypeKind - Model: ExprModel + Kind: &TypeKind + Model: ExprModel } // Binary operation expression Model:. struct BinaryExprModel { - Left: &OperandExprModel - Right: &OperandExprModel - Op: &Token + Left: &OperandExprModel + Right: &OperandExprModel + Op: &Token } // Unary operation expression Model:. struct UnaryExprModel { - Expr: &Data - Op: &Token + Expr: &Data + Op: &Token } // Structure field argument expression Model: for constructors. // For example: &MyStruct{10, false, "-"} struct StructArgExprModel { - Token: &Token - Field: &FieldIns - Expr: &Data + Token: &Token + Field: &FieldIns + Expr: &Data } // Structure literal. struct StructLitExprModel { - Strct: &StructIns - Args: []&StructArgExprModel + Strct: &StructIns + Args: []&StructArgExprModel } // Heap allocated structure litral expression. // For example: &MyStruct{} struct AllocStructLitExprModel { - Lit: &StructLitExprModel + Lit: &StructLitExprModel } // Casting expression Model:. // For example: (int)(my_float) struct CastingExprModel { - Token: &Token - Expr: &Data - Kind: &TypeKind - ExprKind: &TypeKind + Token: &Token + Expr: &Data + Kind: &TypeKind + ExprKind: &TypeKind } // Function call expression Model:. struct FnCallExprModel { - Token: &Token - Func: &FnIns - IsCo: bool - Expr: ExprModel - Args: []ExprModel - Except: &Scope - Assigned: bool + Token: &Token + Func: &FnIns + IsCo: bool + Expr: ExprModel + Args: []ExprModel + Except: &Scope + Assigned: bool } // Slice expression Model:. // For example: [1, 2, 3, 4, 5, 6, 8, 9, 10] struct SliceExprModel { - ElemKind: &TypeKind - Elems: []ExprModel + ElemKind: &TypeKind + Elems: []ExprModel } // Indexing expression Model:. // For example: my_slice[my_index] struct IndexingExprModel { - Token: &Token - Expr: &Data - Index: &Data + Token: &Token + Expr: &Data + Index: &Data } // Anonymous function expression Model:. struct AnonFnExprModel { - Captured: []&Var - Func: &FnIns - Global: bool + Captured: []&Var + Func: &FnIns + Global: bool } // Key-value expression pair Model:. struct KeyValPairExprModel { - Key: ExprModel - Val: ExprModel + Key: ExprModel + Val: ExprModel } // Map expression Model:. // For example; {0: false, 1: true} struct MapExprModel { - KeyKind: &TypeKind - ValKind: &TypeKind - Entries: []&KeyValPairExprModel + KeyKind: &TypeKind + ValKind: &TypeKind + Entries: []&KeyValPairExprModel } // Slicing expression Model:. // For example: mySlice[2:len(mySlice)-5] struct SlicingExprModel { - Token: &Token + Token: &Token - // Expression to slicing. - Expr: ExprModel + // Expression to slicing. + Expr: ExprModel - // Left index expression. - // Zero integer if expression have not left index. - Left: ExprModel + // Left index expression. + // Zero integer if expression have not left index. + Left: ExprModel - // Right index expression. - // Nil if expression have not right index. - Right: ExprModel + // Right index expression. + // Nil if expression have not right index. + Right: ExprModel } // Trait sub-ident expression Model:. // For example: my_trait.my_sub_ident struct TraitSubIdentExprModel { - Token: &Token - Expr: ExprModel - Method: &Fn - Trt: &Trait + Token: &Token + Expr: ExprModel + Method: &Fn + Trt: &Trait } // Structure sub-ident expression Model:. // For example: my_struct.my_sub_ident struct StructSubIdentExprModel { - Token: &Token - Expr: &Data - Method: &FnIns - Field: &FieldIns - Owner: &StructIns + Token: &Token + Expr: &Data + Method: &FnIns + Field: &FieldIns + Owner: &StructIns } // Structure static ident expression Model:. // For example: MyStruct.my_sub_ident struct StructStaticIdentExprModel { - Structure: &StructIns - Expr: ExprModel - Method: &FnIns + Structure: &StructIns + Expr: ExprModel + Method: &FnIns } // Array expression Model:. // If array filled, elems field holds 2 data. // First data is expression, second is nil, kind of mark to that array filled. struct ArrayExprModel { - Kind: &Arr - Elems: []ExprModel + Kind: &Arr + Elems: []ExprModel } // Tuple expression Model:. struct TupleExprModel { - Datas: []&Data + Datas: []&Data } // Expression Model: for built-in out function calls. struct BuiltinOutCallExprModel { - Expr: ExprModel - Debug: bool + Expr: ExprModel + Debug: bool } // Expression Model: for built-in outln function calls. struct BuiltinOutlnCallExprModel { - Expr: ExprModel - Debug: bool + Expr: ExprModel + Debug: bool } // Expression Model: for built-in new function calls. struct BuiltinNewCallExprModel { - Kind: &TypeKind // Element type of reference. - Init: ExprModel // Nil for not initialized. + Kind: &TypeKind // Element type of reference. + Init: ExprModel // Nil for not initialized. } // Expression Model: for built-in panic function calls. struct BuiltinPanicCallExprModel { - Token: &Token - Expr: ExprModel + Token: &Token + Expr: ExprModel } // Expression Model: for built-in assert function calls. struct BuiltinAssertCallExprModel { - Token: &Token - Expr: ExprModel - Log: str + Token: &Token + Expr: ExprModel + Log: str } // Expression Model: for built-in make function calls. struct BuiltinMakeCallExprModel { - Kind: &TypeKind - Len: ExprModel - Cap: ExprModel + Kind: &TypeKind + Len: ExprModel + Cap: ExprModel } // Expression Model: for built-in append function calls. struct BuiltinAppendCallExprModel { - Dest: ExprModel - Elements: ExprModel + Dest: ExprModel + Elements: ExprModel } // Expression Model: for built-in len function calls. struct BuiltinLenCallExprModel { - Expr: &Data + Expr: &Data } // Expression Model: for built-in cap function calls. struct BuiltinCapCallExprModel { - Expr: &Data + Expr: &Data } // Expression Model: for built-in delete function calls. struct BuiltinDeleteCallExprModel { - Dest: &Data - Key: &Data + Dest: &Data + Key: &Data } // Expression Model: for built-in copy function calls. struct BuiltinCopyCallExprModel { - Dest: &Data - Src: &Data + Dest: &Data + Src: &Data } // Expression Model: for built-in error function calls. struct BuiltinErrorCallExprModel { - Func: &FnIns - Err: &Data + Func: &FnIns + Err: &Data } // Expression Model: for sizeof expressions. // For example, in C++: sizeof(int) struct SizeofExprModel { - Expr: ExprModel + Expr: ExprModel } // Expression Model: for alignof expressions. // For example, in C++: alignof(int) struct AlignofExprModel { - Expr: ExprModel + Expr: ExprModel } // Rune literal expression Model:. // For example: 'a' struct RuneExprModel { - Code: rune + Code: rune } // Expression Model: for to_str function of std::jule::integrated library. struct IntegratedToStrExprModel { - Expr: ExprModel + Expr: ExprModel } // Expression Model: for inline code emit to backend. struct BackendEmitExprModel { - Code: str + Code: str - // Expression Model: for expression or type emit to backend from Jule source code. - Exprs: []ExprModel + // Expression Model: for expression or type emit to backend from Jule source code. + Exprs: []ExprModel } // Expression Model: for free calls. // Function provided by: std::mem struct FreeExprModel { - Expr: ExprModel + Expr: ExprModel } \ No newline at end of file diff --git a/std/jule/sema/package.jule b/std/jule/sema/package.jule index a8731cc56..6da9a6d05 100644 --- a/std/jule/sema/package.jule +++ b/std/jule/sema/package.jule @@ -11,347 +11,347 @@ use strings for std::strings // Importer. // Used by semantic analyzer for import use declarations. trait Importer { - // Set current module path. - // Path should be valid directory. - // Set to empty string if module is not exist. - fn SetModPath(mut self, path: str) - - // Returns current module path. - // Path should be valid directory. - // Returns empty string if module is not exist. - fn GetModPath(self): str - - // Returns module path by identity. - fn ModById(self, id: int): str - - // Returns &ImportInfo by path. - // This function accepted as returns already imported and checked package. - // If returns not-nil value, will be used instead of ImportPackage - // if possible and package content is not checked by Sema. - fn GetImport(mut self, path: str): &ImportInfo - - // Path is the directory path of package to import. - // Should return abstract syntax tree of package files. - // Logs accepts as error. - // Updated module to package's module if exist when update_mod is true. - fn ImportPackage(mut self, path: str, update_mod: bool): ([]&Ast, []Log) - - // Invoked after the package is imported. - // Sets module identitity of imported package to current module. - fn Imported(mut self, mut &ImportInfo) + // Set current module path. + // Path should be valid directory. + // Set to empty string if module is not exist. + fn SetModPath(mut self, path: str) + + // Returns current module path. + // Path should be valid directory. + // Returns empty string if module is not exist. + fn GetModPath(self): str + + // Returns module path by identity. + fn ModById(self, id: int): str + + // Returns &ImportInfo by path. + // This function accepted as returns already imported and checked package. + // If returns not-nil value, will be used instead of ImportPackage + // if possible and package content is not checked by Sema. + fn GetImport(mut self, path: str): &ImportInfo + + // Path is the directory path of package to import. + // Should return abstract syntax tree of package files. + // Logs accepts as error. + // Updated module to package's module if exist when update_mod is true. + fn ImportPackage(mut self, path: str, update_mod: bool): ([]&Ast, []Log) + + // Invoked after the package is imported. + // Sets module identitity of imported package to current module. + fn Imported(mut self, mut &ImportInfo) } // Returns variable by identifier and binded state. // Returns nil if not exist any variable in this identifier. fn findVarInPackage(mut &files: []&SymbolTable, &ident: str, binded: bool): &Var { - for (_, mut f) in files { - mut v := f.FindVar(ident, binded) - if v != nil { - ret v - } - } - ret nil + for (_, mut f) in files { + mut v := f.FindVar(ident, binded) + if v != nil { + ret v + } + } + ret nil } // Returns type alias by identifier and binded state. // Returns nil if not exist any type alias in this identifier. fn findTypeAliasInPackage(mut &files: []&SymbolTable, &ident: str, binded: bool): &TypeAlias { - for (_, mut f) in files { - mut ta := f.FindTypeAlias(ident, binded) - if ta != nil { - ret ta - } - } - ret nil + for (_, mut f) in files { + mut ta := f.FindTypeAlias(ident, binded) + if ta != nil { + ret ta + } + } + ret nil } // Returns struct by identifier and binded state. // Returns nil if not exist any struct in this identifier. fn findStructInPackage(mut &files: []&SymbolTable, &ident: str, binded: bool): &Struct { - for (_, mut f) in files { - mut s := f.FindStruct(ident, binded) - if s != nil { - ret s - } - } - ret nil + for (_, mut f) in files { + mut s := f.FindStruct(ident, binded) + if s != nil { + ret s + } + } + ret nil } // Returns function by identifier and binded state. // Returns nil if not exist any function in this identifier. fn findFnInPackage(mut &files: []&SymbolTable, &ident: str, binded: bool): &Fn { - for (_, mut file) in files { - mut f := file.FindFn(ident, binded) - if f != nil { - ret f - } - } - ret nil + for (_, mut file) in files { + mut f := file.FindFn(ident, binded) + if f != nil { + ret f + } + } + ret nil } // Returns trait by identifier. // Returns nil if not exist any trait in this identifier. fn findTraitInPackage(mut &files: []&SymbolTable, &ident: str): &Trait { - for (_, mut f) in files { - mut t := f.FindTrait(ident) - if t != nil { - ret t - } - } - ret nil + for (_, mut f) in files { + mut t := f.FindTrait(ident) + if t != nil { + ret t + } + } + ret nil } // Returns enum by identifier. // Returns nil if not exist any enum in this identifier. fn findEnumInPackage(mut &files: []&SymbolTable, &ident: str): &Enum { - for (_, mut f) in files { - mut e := f.FindEnum(ident) - if e != nil { - ret e - } - } - ret nil + for (_, mut f) in files { + mut e := f.FindEnum(ident) + if e != nil { + ret e + } + } + ret nil } // Returns enum by identifier. // Returns nil if not exist any type enum in this identifier. fn findTypeEnumInPackage(mut &files: []&SymbolTable, &ident: str): &TypeEnum { - for (_, mut f) in files { - mut e := f.FindTypeEnum(ident) - if e != nil { - ret e - } - } - ret nil + for (_, mut f) in files { + mut e := f.FindTypeEnum(ident) + if e != nil { + ret e + } + } + ret nil } // Lookups tables with [SymbolTable.defByIdent] method. fn defByIdentPackage(mut &files: []&SymbolTable, &ident: str, binded: bool): any { - for (_, mut file) in files { - mut def := file.defByIdent(ident, binded) - if def != nil { - ret def - } - } - ret nil + for (_, mut file) in files { + mut def := file.defByIdent(ident, binded) + if def != nil { + ret def + } + } + ret nil } // Import information. // Represents imported package by use declaration. struct ImportInfo { - // Use declaration token. - Token: &Token + // Use declaration token. + Token: &Token - // Absolute path. - Path: str + // Absolute path. + Path: str - // Use declaration path string. - LinkPath: str + // Use declaration path string. + LinkPath: str - // Package identifier (aka package name). - // Empty if package is cpp header. - Ident: str + // Package identifier (aka package name). + // Empty if package is cpp header. + Ident: str - // Package alias identifier. - Alias: str + // Package alias identifier. + Alias: str - // True if imported with Importer.get_import function. - Duplicate: bool + // True if imported with Importer.get_import function. + Duplicate: bool - // Is binded use declaration. - Binded: bool + // Is binded use declaration. + Binded: bool - // Is standard library package. - Std: bool + // Is standard library package. + Std: bool - // Is imported all defines implicitly. - ImportAll: bool + // Is imported all defines implicitly. + ImportAll: bool - // Identifiers of selected definition. - Selected: []&Token + // Identifiers of selected definition. + Selected: []&Token - // Nil if package is cpp header. - Package: &Package + // Nil if package is cpp header. + Package: &Package - // Module identity. - ModId: int + // Module identity. + ModId: int } impl Lookup for ImportInfo { - // Returns always nil reference. - fn SelectPackage(mut self, fn(&ImportInfo): bool): &ImportInfo { ret nil } - - // Returns variable by identifier and binded state. - // Returns nil reference if not exist any variable in this identifier. - // - // Lookups by import way such as identifier selection. - // Just lookups non-binded defines. - fn FindVar(mut self, ident: str, _: bool): &Var { - if !self.isLookupable(ident) { - ret nil - } - ret findVarInPackage(self.Package.Files, ident, false) - } - - // Returns type alias by identifier. - // Returns nil reference if not exist any type alias in this identifier. - // - // Lookups by import way such as identifier selection. - // Just lookups non-binded defines. - fn FindTypeAlias(mut self, ident: str, _: bool): &TypeAlias { - if !self.isLookupable(ident) { - ret nil - } - ret findTypeAliasInPackage(self.Package.Files, ident, false) - } - - // Returns struct by identifier and binded state. - // Returns nil reference if not exist any struct in this identifier. - // - // Lookups by import way such as identifier selection. - // Just lookups non-binded defines. - fn FindStruct(mut self, ident: str, _: bool): &Struct { - if !self.isLookupable(ident) { - ret nil - } - ret findStructInPackage(self.Package.Files, ident, false) - } - - // Returns function by identifier and binded state. - // Returns nil reference if not exist any function in this identifier. - // - // Lookups by import way such as identifier selection. - // Just lookups non-binded defines. - fn FindFn(mut self, ident: str, _: bool): &Fn { - if !self.isLookupable(ident) { - ret nil - } - ret findFnInPackage(self.Package.Files, ident, false) - } - - // Returns trait by identifier. - // Returns nil reference if not exist any trait in this identifier. - // - // Lookups by import way such as identifier selection. - fn FindTrait(mut self, ident: str): &Trait { - if !self.isLookupable(ident) { - ret nil - } - ret findTraitInPackage(self.Package.Files, ident) - } - - // Returns enum by identifier. - // Returns nil reference if not exist any enum in this identifier. - // - // Lookups by import way such as identifier selection. - fn FindEnum(mut self, ident: str): &Enum { - if !self.isLookupable(ident) { - ret nil - } - ret findEnumInPackage(self.Package.Files, ident) - } - - // Returns type enum by identifier. - // Returns nil reference if not exist any type enum in this identifier. - // - // Lookups by import way such as identifier selection. - fn FindTypeEnum(mut self, ident: str): &TypeEnum { - if !self.isLookupable(ident) { - ret nil - } - ret findTypeEnumInPackage(self.Package.Files, ident) - } + // Returns always nil reference. + fn SelectPackage(mut self, fn(&ImportInfo): bool): &ImportInfo { ret nil } + + // Returns variable by identifier and binded state. + // Returns nil reference if not exist any variable in this identifier. + // + // Lookups by import way such as identifier selection. + // Just lookups non-binded defines. + fn FindVar(mut self, ident: str, _: bool): &Var { + if !self.isLookupable(ident) { + ret nil + } + ret findVarInPackage(self.Package.Files, ident, false) + } + + // Returns type alias by identifier. + // Returns nil reference if not exist any type alias in this identifier. + // + // Lookups by import way such as identifier selection. + // Just lookups non-binded defines. + fn FindTypeAlias(mut self, ident: str, _: bool): &TypeAlias { + if !self.isLookupable(ident) { + ret nil + } + ret findTypeAliasInPackage(self.Package.Files, ident, false) + } + + // Returns struct by identifier and binded state. + // Returns nil reference if not exist any struct in this identifier. + // + // Lookups by import way such as identifier selection. + // Just lookups non-binded defines. + fn FindStruct(mut self, ident: str, _: bool): &Struct { + if !self.isLookupable(ident) { + ret nil + } + ret findStructInPackage(self.Package.Files, ident, false) + } + + // Returns function by identifier and binded state. + // Returns nil reference if not exist any function in this identifier. + // + // Lookups by import way such as identifier selection. + // Just lookups non-binded defines. + fn FindFn(mut self, ident: str, _: bool): &Fn { + if !self.isLookupable(ident) { + ret nil + } + ret findFnInPackage(self.Package.Files, ident, false) + } + + // Returns trait by identifier. + // Returns nil reference if not exist any trait in this identifier. + // + // Lookups by import way such as identifier selection. + fn FindTrait(mut self, ident: str): &Trait { + if !self.isLookupable(ident) { + ret nil + } + ret findTraitInPackage(self.Package.Files, ident) + } + + // Returns enum by identifier. + // Returns nil reference if not exist any enum in this identifier. + // + // Lookups by import way such as identifier selection. + fn FindEnum(mut self, ident: str): &Enum { + if !self.isLookupable(ident) { + ret nil + } + ret findEnumInPackage(self.Package.Files, ident) + } + + // Returns type enum by identifier. + // Returns nil reference if not exist any type enum in this identifier. + // + // Lookups by import way such as identifier selection. + fn FindTypeEnum(mut self, ident: str): &TypeEnum { + if !self.isLookupable(ident) { + ret nil + } + ret findTypeEnumInPackage(self.Package.Files, ident) + } } impl ImportInfo { - fn isLookupable(self, &ident: str): bool { - if self.Binded { - ret false - } - - if !self.ImportAll { - if len(self.Alias) != 0 || self.existIdent(TokenKind.Self) { - ret true - } - - if len(self.Selected) > 0 { - if !self.existIdent(ident) { - ret false - } - } - } - ret true - } - - // Reports whether identifier is selected. - fn existIdent(self, ident: str): bool { - for _, sident in self.Selected { - if sident.Kind == ident { - ret true - } - } - - ret false - } - - fn isAccessibleViaSelection(self): bool { - ret self.ImportAll || len(self.Selected) == 0 || self.existIdent(TokenKind.Self) - } + fn isLookupable(self, &ident: str): bool { + if self.Binded { + ret false + } + + if !self.ImportAll { + if len(self.Alias) != 0 || self.existIdent(TokenKind.Self) { + ret true + } + + if len(self.Selected) > 0 { + if !self.existIdent(ident) { + ret false + } + } + } + ret true + } + + // Reports whether identifier is selected. + fn existIdent(self, ident: str): bool { + for _, sident in self.Selected { + if sident.Kind == ident { + ret true + } + } + + ret false + } + + fn isAccessibleViaSelection(self): bool { + ret self.ImportAll || len(self.Selected) == 0 || self.existIdent(TokenKind.Self) + } } // Package. struct Package { - // Symbol table for each package's file. - Files: []&SymbolTable + // Symbol table for each package's file. + Files: []&SymbolTable } impl Lookup for Package { - // Returns always nil reference. - fn SelectPackage(mut self, fn(&ImportInfo): bool): &ImportInfo { ret nil } - - // Returns variable by identifier and binded state. - // Returns nil reference if not exist any variable in this identifier. - fn FindVar(mut self, ident: str, binded: bool): &Var { - ret findVarInPackage(self.Files, ident, binded) - } - - // Returns type alias by identifier and binded state. - // Returns nil reference if not exist any type alias in this identifier. - fn FindTypeAlias(mut self, ident: str, binded: bool): &TypeAlias { - ret findTypeAliasInPackage(self.Files, ident, binded) - } - - // Returns struct by identifier and binded state. - // Returns nil reference if not exist any struct in this identifier. - fn FindStruct(mut self, ident: str, binded: bool): &Struct { - ret findStructInPackage(self.Files, ident, binded) - } - - // Returns function by identifier and binded state. - // Returns nil reference if not exist any function in this identifier. - fn FindFn(mut self, ident: str, binded: bool): &Fn { - ret findFnInPackage(self.Files, ident, binded) - } - - // Returns trait by identifier. - // Returns nil reference if not exist any trait in this identifier. - fn FindTrait(mut self, ident: str): &Trait { - ret findTraitInPackage(self.Files, ident) - } - - // Returns enum by identifier. - // Returns nil reference if not exist any enum in this identifier. - fn FindEnum(mut self, ident: str): &Enum { - ret findEnumInPackage(self.Files, ident) - } - - // Returns type enum by identifier. - // Returns nil reference if not exist any type enum in this identifier. - fn FindTypeEnum(mut self, ident: str): &TypeEnum { - ret findTypeEnumInPackage(self.Files, ident) - } + // Returns always nil reference. + fn SelectPackage(mut self, fn(&ImportInfo): bool): &ImportInfo { ret nil } + + // Returns variable by identifier and binded state. + // Returns nil reference if not exist any variable in this identifier. + fn FindVar(mut self, ident: str, binded: bool): &Var { + ret findVarInPackage(self.Files, ident, binded) + } + + // Returns type alias by identifier and binded state. + // Returns nil reference if not exist any type alias in this identifier. + fn FindTypeAlias(mut self, ident: str, binded: bool): &TypeAlias { + ret findTypeAliasInPackage(self.Files, ident, binded) + } + + // Returns struct by identifier and binded state. + // Returns nil reference if not exist any struct in this identifier. + fn FindStruct(mut self, ident: str, binded: bool): &Struct { + ret findStructInPackage(self.Files, ident, binded) + } + + // Returns function by identifier and binded state. + // Returns nil reference if not exist any function in this identifier. + fn FindFn(mut self, ident: str, binded: bool): &Fn { + ret findFnInPackage(self.Files, ident, binded) + } + + // Returns trait by identifier. + // Returns nil reference if not exist any trait in this identifier. + fn FindTrait(mut self, ident: str): &Trait { + ret findTraitInPackage(self.Files, ident) + } + + // Returns enum by identifier. + // Returns nil reference if not exist any enum in this identifier. + fn FindEnum(mut self, ident: str): &Enum { + ret findEnumInPackage(self.Files, ident) + } + + // Returns type enum by identifier. + // Returns nil reference if not exist any type enum in this identifier. + fn FindTypeEnum(mut self, ident: str): &TypeEnum { + ret findTypeEnumInPackage(self.Files, ident) + } } fn isStdPackage(&f: str, p: str): bool { - ret strings::HasPrefix(f, path::Join(PathStdlib, p)) + ret strings::HasPrefix(f, path::Join(PathStdlib, p)) } \ No newline at end of file diff --git a/std/jule/sema/pattern.jule b/std/jule/sema/pattern.jule index 2c6b61925..17abd0929 100644 --- a/std/jule/sema/pattern.jule +++ b/std/jule/sema/pattern.jule @@ -6,264 +6,264 @@ struct FuncPattern {} impl FuncPattern { - // Reports whether function is the reserved Dispose function. - static fn Dispose(f: &Fn): bool { - ret f != nil && - f.Owner != nil && - f.Ident == "Dispose" && - !f.Statically && - !f.Unsafety && - f.IsVoid() && - len(f.Generics) == 0 && - len(f.Params) == 1 && - f.Params[0].Mutable && - !f.Params[0].IsRef() - } - - // Reports whether function is the reserved Str function. - static fn Str(f: &Fn): bool { - if f == nil || - f.Owner == nil || - f.Ident != "Str" || - f.Statically || - f.Unsafety || - f.IsVoid() || - len(f.Generics) != 0 || - len(f.Params) != 1 || - f.Params[0].Mutable || - f.Params[0].IsRef() { - ret false - } - - mut ins := unsafe { *(&f.Instances[0]) } - prim := ins.Result.Prim() - if prim == nil { - ret false - } - ret prim.IsStr() - } - - static fn logical(&f: &Fn, ident: str): bool { - if f == nil || - f.Ident != ident || - f.Owner == nil || - len(f.Instances) == 0 || - f.Statically || - f.Unsafety || - f.IsVoid() || - len(f.Generics) != 0 || - len(f.Params) != 2 || - f.Params[0].Mutable || - f.Params[0].IsRef() || - f.Params[1].Mutable || - f.Params[1].Reference { - ret false - } - - mut ins := unsafe { *(&f.Instances[0]) } - prim := ins.Result.Prim() - if prim == nil || !prim.IsBool() { - ret false - } - ret ins.Owner == ins.Params[1].Kind.Struct() - } - - // Reports whether function is the reserved Eq function. - static fn Eq(f: &Fn): bool { - ret FuncPattern.logical(f, "Eq") - } - - // Reports whether function is the reserved Gt function. - static fn Gt(f: &Fn): bool { - ret FuncPattern.logical(f, "Gt") - } - - // Reports whether function is the reserved GtEq function. - static fn GtEq(f: &Fn): bool { - ret FuncPattern.logical(f, "GtEq") - } - - // Reports whether function is the reserved Lt function. - static fn Lt(f: &Fn): bool { - ret FuncPattern.logical(f, "Lt") - } - - // Reports whether function is the reserved LtEq function. - static fn LtEq(f: &Fn): bool { - ret FuncPattern.logical(f, "LtEq") - } - - static fn result(&f: &Fn, ident: str): bool { - if f == nil || - f.Ident != ident || - f.Owner == nil || - len(f.Instances) == 0 || - f.Statically || - f.Unsafety || - f.IsVoid() || - len(f.Generics) != 0 || - len(f.Params) != 2 || - f.Params[0].Mutable || - f.Params[0].IsRef() || - f.Params[1].Mutable || - f.Params[1].Reference { - ret false - } - - mut ins := unsafe { *(&f.Instances[0]) } - ret ins.Result.Struct() == ins.Owner - } - - // Reports whether function is the reserved Shl function. - static fn Shl(f: &Fn): bool { - ret FuncPattern.result(f, "Shl") - } - - // Reports whether function is the reserved Shr function. - static fn Shr(f: &Fn): bool { - ret FuncPattern.result(f, "Shr") - } - - // Reports whether function is the reserved Add function. - static fn Add(f: &Fn): bool { - ret FuncPattern.result(f, "Add") - } - - // Reports whether function is the reserved Sub function. - static fn Sub(f: &Fn): bool { - ret FuncPattern.result(f, "Sub") - } - - // Reports whether function is the reserved Div function. - static fn Div(f: &Fn): bool { - ret FuncPattern.result(f, "Div") - } - - // Reports whether function is the reserved Mul function. - static fn Mul(f: &Fn): bool { - ret FuncPattern.result(f, "Mul") - } - - // Reports whether function is the reserved Mod function. - static fn Mod(f: &Fn): bool { - ret FuncPattern.result(f, "Mod") - } - - // Reports whether function is the reserved BitAnd function. - static fn BitAnd(f: &Fn): bool { - ret FuncPattern.result(f, "BitAnd") - } - - // Reports whether function is the reserved BitOr function. - static fn BitOr(f: &Fn): bool { - ret FuncPattern.result(f, "BitOr") - } - - // Reports whether function is the reserved BitXor function. - static fn BitXor(f: &Fn): bool { - ret FuncPattern.result(f, "BitXor") - } - - static fn unary(&f: &Fn, ident: str): bool { - if f == nil || - f.Ident != ident || - f.Owner == nil || - len(f.Instances) == 0 || - f.Statically || - f.Unsafety || - f.IsVoid() || - len(f.Generics) != 0 || - len(f.Params) != 1 || - f.Params[0].Mutable || - f.Params[0].IsRef() { - ret false - } - - mut ins := unsafe { *(&f.Instances[0]) } - ret ins.Result.Struct() == ins.Owner - } - - // Reports whether function is the reserved Neg function. - static fn Neg(f: &Fn): bool { - ret FuncPattern.unary(f, "Neg") - } - - // Reports whether function is the reserved Pos function. - static fn Pos(f: &Fn): bool { - ret FuncPattern.unary(f, "Pos") - } - - // Reports whether function is the reserved BitNot function. - static fn BitNot(f: &Fn): bool { - ret FuncPattern.unary(f, "BitNot") - } - - static fn assign(&f: &Fn, ident: str): bool { - if f == nil || - f.Ident != ident || - f.Owner == nil || - len(f.Instances) == 0 || - f.Statically || - f.Unsafety || - !f.IsVoid() || - len(f.Generics) != 0 || - len(f.Params) != 2 || - !f.Params[0].Mutable || - f.Params[0].IsRef() || - f.Params[1].Mutable || - f.Params[1].Reference { - ret false - } - ret true - } - - // Reports whether function is the reserved AddAssign function. - static fn AddAssign(f: &Fn): bool { - ret FuncPattern.assign(f, "AddAssign") - } - - // Reports whether function is the reserved SubAssign function. - static fn SubAssign(f: &Fn): bool { - ret FuncPattern.assign(f, "SubAssign") - } - - // Reports whether function is the reserved DivAssign function. - static fn DivAssign(f: &Fn): bool { - ret FuncPattern.assign(f, "DivAssign") - } - - // Reports whether function is the reserved MulAssign function. - static fn MulAssign(f: &Fn): bool { - ret FuncPattern.assign(f, "MulAssign") - } - - // Reports whether function is the reserved ModAssign function. - static fn ModAssign(f: &Fn): bool { - ret FuncPattern.assign(f, "ModAssign") - } - - // Reports whether function is the reserved ShlAssign function. - static fn ShlAssign(f: &Fn): bool { - ret FuncPattern.assign(f, "ShlAssign") - } - - // Reports whether function is the reserved ShrAssign function. - static fn ShrAssign(f: &Fn): bool { - ret FuncPattern.assign(f, "ShrAssign") - } - - // Reports whether function is the reserved BitOrAssign function. - static fn BitOrAssign(f: &Fn): bool { - ret FuncPattern.assign(f, "BitOrAssign") - } - - // Reports whether function is the reserved BitAndAssign function. - static fn BitAndAssign(f: &Fn): bool { - ret FuncPattern.assign(f, "BitAndAssign") - } - - // Reports whether function is the reserved BitXorAssign function. - static fn BitXorAssign(f: &Fn): bool { - ret FuncPattern.assign(f, "BitXorAssign") - } + // Reports whether function is the reserved Dispose function. + static fn Dispose(f: &Fn): bool { + ret f != nil && + f.Owner != nil && + f.Ident == "Dispose" && + !f.Statically && + !f.Unsafety && + f.IsVoid() && + len(f.Generics) == 0 && + len(f.Params) == 1 && + f.Params[0].Mutable && + !f.Params[0].IsRef() + } + + // Reports whether function is the reserved Str function. + static fn Str(f: &Fn): bool { + if f == nil || + f.Owner == nil || + f.Ident != "Str" || + f.Statically || + f.Unsafety || + f.IsVoid() || + len(f.Generics) != 0 || + len(f.Params) != 1 || + f.Params[0].Mutable || + f.Params[0].IsRef() { + ret false + } + + mut ins := unsafe { *(&f.Instances[0]) } + prim := ins.Result.Prim() + if prim == nil { + ret false + } + ret prim.IsStr() + } + + static fn logical(&f: &Fn, ident: str): bool { + if f == nil || + f.Ident != ident || + f.Owner == nil || + len(f.Instances) == 0 || + f.Statically || + f.Unsafety || + f.IsVoid() || + len(f.Generics) != 0 || + len(f.Params) != 2 || + f.Params[0].Mutable || + f.Params[0].IsRef() || + f.Params[1].Mutable || + f.Params[1].Reference { + ret false + } + + mut ins := unsafe { *(&f.Instances[0]) } + prim := ins.Result.Prim() + if prim == nil || !prim.IsBool() { + ret false + } + ret ins.Owner == ins.Params[1].Kind.Struct() + } + + // Reports whether function is the reserved Eq function. + static fn Eq(f: &Fn): bool { + ret FuncPattern.logical(f, "Eq") + } + + // Reports whether function is the reserved Gt function. + static fn Gt(f: &Fn): bool { + ret FuncPattern.logical(f, "Gt") + } + + // Reports whether function is the reserved GtEq function. + static fn GtEq(f: &Fn): bool { + ret FuncPattern.logical(f, "GtEq") + } + + // Reports whether function is the reserved Lt function. + static fn Lt(f: &Fn): bool { + ret FuncPattern.logical(f, "Lt") + } + + // Reports whether function is the reserved LtEq function. + static fn LtEq(f: &Fn): bool { + ret FuncPattern.logical(f, "LtEq") + } + + static fn result(&f: &Fn, ident: str): bool { + if f == nil || + f.Ident != ident || + f.Owner == nil || + len(f.Instances) == 0 || + f.Statically || + f.Unsafety || + f.IsVoid() || + len(f.Generics) != 0 || + len(f.Params) != 2 || + f.Params[0].Mutable || + f.Params[0].IsRef() || + f.Params[1].Mutable || + f.Params[1].Reference { + ret false + } + + mut ins := unsafe { *(&f.Instances[0]) } + ret ins.Result.Struct() == ins.Owner + } + + // Reports whether function is the reserved Shl function. + static fn Shl(f: &Fn): bool { + ret FuncPattern.result(f, "Shl") + } + + // Reports whether function is the reserved Shr function. + static fn Shr(f: &Fn): bool { + ret FuncPattern.result(f, "Shr") + } + + // Reports whether function is the reserved Add function. + static fn Add(f: &Fn): bool { + ret FuncPattern.result(f, "Add") + } + + // Reports whether function is the reserved Sub function. + static fn Sub(f: &Fn): bool { + ret FuncPattern.result(f, "Sub") + } + + // Reports whether function is the reserved Div function. + static fn Div(f: &Fn): bool { + ret FuncPattern.result(f, "Div") + } + + // Reports whether function is the reserved Mul function. + static fn Mul(f: &Fn): bool { + ret FuncPattern.result(f, "Mul") + } + + // Reports whether function is the reserved Mod function. + static fn Mod(f: &Fn): bool { + ret FuncPattern.result(f, "Mod") + } + + // Reports whether function is the reserved BitAnd function. + static fn BitAnd(f: &Fn): bool { + ret FuncPattern.result(f, "BitAnd") + } + + // Reports whether function is the reserved BitOr function. + static fn BitOr(f: &Fn): bool { + ret FuncPattern.result(f, "BitOr") + } + + // Reports whether function is the reserved BitXor function. + static fn BitXor(f: &Fn): bool { + ret FuncPattern.result(f, "BitXor") + } + + static fn unary(&f: &Fn, ident: str): bool { + if f == nil || + f.Ident != ident || + f.Owner == nil || + len(f.Instances) == 0 || + f.Statically || + f.Unsafety || + f.IsVoid() || + len(f.Generics) != 0 || + len(f.Params) != 1 || + f.Params[0].Mutable || + f.Params[0].IsRef() { + ret false + } + + mut ins := unsafe { *(&f.Instances[0]) } + ret ins.Result.Struct() == ins.Owner + } + + // Reports whether function is the reserved Neg function. + static fn Neg(f: &Fn): bool { + ret FuncPattern.unary(f, "Neg") + } + + // Reports whether function is the reserved Pos function. + static fn Pos(f: &Fn): bool { + ret FuncPattern.unary(f, "Pos") + } + + // Reports whether function is the reserved BitNot function. + static fn BitNot(f: &Fn): bool { + ret FuncPattern.unary(f, "BitNot") + } + + static fn assign(&f: &Fn, ident: str): bool { + if f == nil || + f.Ident != ident || + f.Owner == nil || + len(f.Instances) == 0 || + f.Statically || + f.Unsafety || + !f.IsVoid() || + len(f.Generics) != 0 || + len(f.Params) != 2 || + !f.Params[0].Mutable || + f.Params[0].IsRef() || + f.Params[1].Mutable || + f.Params[1].Reference { + ret false + } + ret true + } + + // Reports whether function is the reserved AddAssign function. + static fn AddAssign(f: &Fn): bool { + ret FuncPattern.assign(f, "AddAssign") + } + + // Reports whether function is the reserved SubAssign function. + static fn SubAssign(f: &Fn): bool { + ret FuncPattern.assign(f, "SubAssign") + } + + // Reports whether function is the reserved DivAssign function. + static fn DivAssign(f: &Fn): bool { + ret FuncPattern.assign(f, "DivAssign") + } + + // Reports whether function is the reserved MulAssign function. + static fn MulAssign(f: &Fn): bool { + ret FuncPattern.assign(f, "MulAssign") + } + + // Reports whether function is the reserved ModAssign function. + static fn ModAssign(f: &Fn): bool { + ret FuncPattern.assign(f, "ModAssign") + } + + // Reports whether function is the reserved ShlAssign function. + static fn ShlAssign(f: &Fn): bool { + ret FuncPattern.assign(f, "ShlAssign") + } + + // Reports whether function is the reserved ShrAssign function. + static fn ShrAssign(f: &Fn): bool { + ret FuncPattern.assign(f, "ShrAssign") + } + + // Reports whether function is the reserved BitOrAssign function. + static fn BitOrAssign(f: &Fn): bool { + ret FuncPattern.assign(f, "BitOrAssign") + } + + // Reports whether function is the reserved BitAndAssign function. + static fn BitAndAssign(f: &Fn): bool { + ret FuncPattern.assign(f, "BitAndAssign") + } + + // Reports whether function is the reserved BitXorAssign function. + static fn BitXorAssign(f: &Fn): bool { + ret FuncPattern.assign(f, "BitXorAssign") + } } \ No newline at end of file diff --git a/std/jule/sema/scope.jule b/std/jule/sema/scope.jule index 95c3138b2..5e020673e 100644 --- a/std/jule/sema/scope.jule +++ b/std/jule/sema/scope.jule @@ -3,2255 +3,2255 @@ // license that can be found in the LICENSE file. use ast for std::jule::ast::{ - Expr, - ScopeTree, - TypeAliasDecl, - VarDecl, - NodeData, - AssignSt, - FnCallExpr, - WhileKind, - RangeKind, - Iter, - LabelSt, - TupleExpr, - UnsafeExpr, - AssignLeft, - MatchCase, - UseExpr, - ExprData, - StmtData, + Expr, + ScopeTree, + TypeAliasDecl, + VarDecl, + NodeData, + AssignSt, + FnCallExpr, + WhileKind, + RangeKind, + Iter, + LabelSt, + TupleExpr, + UnsafeExpr, + AssignLeft, + MatchCase, + UseExpr, + ExprData, + StmtData, } use std::jule::build::{LogMsg} use std::jule::constant::{Const} use std::jule::lex::{ - Token, - TokenId, - TokenKind, - IsIgnoreIdent, - IsAnonIdent, - IsPostfixOp, + Token, + TokenId, + TokenKind, + IsIgnoreIdent, + IsAnonIdent, + IsPostfixOp, } use types for std::jule::types // Statement type. enum Stmt: type { - &Scope, - &Var, - &Data, - &Conditional, - &InfIter, - &WhileIter, - &RangeIter, - &ContSt, - &Label, - &GotoSt, - &Postfix, - &Assign, - &MultiAssign, - &Match, - &FallSt, - &BreakSt, - &RetSt, + &Scope, + &Var, + &Data, + &Conditional, + &InfIter, + &WhileIter, + &RangeIter, + &ContSt, + &Label, + &GotoSt, + &Postfix, + &Assign, + &MultiAssign, + &Match, + &FallSt, + &BreakSt, + &RetSt, } fn newScopeCheckerBase(mut &s: &Sema, mut owner: &FnIns): &scopeChecker { - ret &scopeChecker{ - s: s, - owner: owner, - table: new(SymbolTable), - } + ret &scopeChecker{ + s: s, + owner: owner, + table: new(SymbolTable), + } } fn newScopeChecker(mut &s: &Sema, mut owner: &FnIns): &scopeChecker { - mut base := newScopeCheckerBase(s, owner) - base.labels = new([]&scopeLabel, nil) - base.gotos = new([]&scopeGoto, nil) - ret base + mut base := newScopeCheckerBase(s, owner) + base.labels = new([]&scopeLabel, nil) + base.gotos = new([]&scopeGoto, nil) + ret base } // Returns label by identifier. // Returns nil if not exist any label in this identifier. // Lookups given scope and parent scopes. fn findLabelParent(&ident: str, mut scope: &scopeChecker): &scopeLabel { - mut label := scope.findLabelScope(ident) - for label == nil { - if scope.parent == nil || scope.owner != nil { - ret nil - } + mut label := scope.findLabelScope(ident) + for label == nil { + if scope.parent == nil || scope.owner != nil { + ret nil + } - scope = scope.parent - label = scope.findLabelScope(ident) - } + scope = scope.parent + label = scope.findLabelScope(ident) + } - ret label + ret label } fn modelIsGotoScope(Model: any, &sc: &Scope): bool { - match type Model { - | &FnCallExprModel: - fcem := (&FnCallExprModel)(Model) - if fcem.Except == sc { - ret true - } - | &Data: - d := (&Data)(Model) - ret modelIsGotoScope(d.Model, sc) - } - ret false + match type Model { + | &FnCallExprModel: + fcem := (&FnCallExprModel)(Model) + if fcem.Except == sc { + ret true + } + | &Data: + d := (&Data)(Model) + ret modelIsGotoScope(d.Model, sc) + } + ret false } fn stmtIsGotoScope(&stmt: Stmt, &sc: &Scope): bool { - match type stmt { - | &Scope: - ret (&Scope)(stmt) == sc - | &InfIter: - ret (&InfIter)(stmt).Scope == sc - | &RangeIter: - it := (&RangeIter)(stmt) - ret it.Scope == sc || modelIsGotoScope(it.Expr.Model, sc) - | &WhileIter: - it := (&WhileIter)(stmt) - ret it.Scope == sc || - modelIsGotoScope(it.Expr, sc) || - modelIsGotoScope(it.Next, sc) - | &Match: - m := (&Match)(stmt) - for _, c in m.Cases { - if c.Scope == sc { - ret true - } - for _, expr in c.Exprs { - if modelIsGotoScope(expr.Model, sc) { - ret true - } - } - } - ret m.Default != nil && m.Default.Scope == sc - | &Conditional: - c := (&Conditional)(stmt) - for _, elif in c.Elifs { - if elif.Scope == sc || modelIsGotoScope(elif.Expr, sc) { - ret true - } - } - ret c.Default != nil && c.Default.Scope == sc - | &Data: - d := (&Data)(stmt) - ret modelIsGotoScope(d.Model, sc) - |: - ret false - } + match type stmt { + | &Scope: + ret (&Scope)(stmt) == sc + | &InfIter: + ret (&InfIter)(stmt).Scope == sc + | &RangeIter: + it := (&RangeIter)(stmt) + ret it.Scope == sc || modelIsGotoScope(it.Expr.Model, sc) + | &WhileIter: + it := (&WhileIter)(stmt) + ret it.Scope == sc || + modelIsGotoScope(it.Expr, sc) || + modelIsGotoScope(it.Next, sc) + | &Match: + m := (&Match)(stmt) + for _, c in m.Cases { + if c.Scope == sc { + ret true + } + for _, expr in c.Exprs { + if modelIsGotoScope(expr.Model, sc) { + ret true + } + } + } + ret m.Default != nil && m.Default.Scope == sc + | &Conditional: + c := (&Conditional)(stmt) + for _, elif in c.Elifs { + if elif.Scope == sc || modelIsGotoScope(elif.Expr, sc) { + ret true + } + } + ret c.Default != nil && c.Default.Scope == sc + | &Data: + d := (&Data)(stmt) + ret modelIsGotoScope(d.Model, sc) + |: + ret false + } } fn countMatchType(&m: &Match, &t: &TypeKind): int { - mut n := 0 - kind := t.Str() + mut n := 0 + kind := t.Str() loop: - for _, c in m.Cases { - if c == nil { - continue - } - - for _, expr in c.Exprs { - // Break loop because this expression is not parsed yet. - // So, parsed cases finished. - if expr == nil { - break loop - } - - if kind == (&TypeKind)(expr.Model).Str() { - n++ - } - } - } - ret n + for _, c in m.Cases { + if c == nil { + continue + } + + for _, expr in c.Exprs { + // Break loop because this expression is not parsed yet. + // So, parsed cases finished. + if expr == nil { + break loop + } + + if kind == (&TypeKind)(expr.Model).Str() { + n++ + } + } + } + ret n } fn getDatasFromTupleData(mut &d: &Data): []&Data { - if d.Kind.Tup() != nil { - match type d.Model { - | &TupleExprModel: - ret (&TupleExprModel)(d.Model).Datas - |: - mut t := d.Kind.Tup() - mut r := make([]&Data, 0, len(t.Types)) - for (_, mut kind) in t.Types { - r = append(r, &Data{ - Mutable: true, // Function return. - Kind: kind, - }) - } - ret r - } - } else { - ret [d] - } + if d.Kind.Tup() != nil { + match type d.Model { + | &TupleExprModel: + ret (&TupleExprModel)(d.Model).Datas + |: + mut t := d.Kind.Tup() + mut r := make([]&Data, 0, len(t.Types)) + for (_, mut kind) in t.Types { + r = append(r, &Data{ + Mutable: true, // Function return. + Kind: kind, + }) + } + ret r + } + } else { + ret [d] + } } fn getExprModels(mut &m: ExprData): []ExprData { - match type m { - | &TupleExpr: - mut tup := (&TupleExpr)(m) - mut models := make([]ExprData, 0, len(tup.Expr)) - for (_, mut expr) in tup.Expr { - models = append(models, expr.Kind) - } - ret models - |: - ret [m] - } + match type m { + | &TupleExpr: + mut tup := (&TupleExpr)(m) + mut models := make([]ExprData, 0, len(tup.Expr)) + for (_, mut expr) in tup.Expr { + models = append(models, expr.Kind) + } + ret models + |: + ret [m] + } } fn checkMut(mut &s: &Sema, &left: &Data, mut right: &Data, op: &Token): (ok: bool) { - match { - | !left.Mutable: - s.pushErr(op, LogMsg.AssignToNonMut) - ret false - | right != nil && !right.Mutable && right.Kind.Mutable(): - if op.Id != TokenId.Eq && right.Kind.Struct() != nil { - // If operator is not assignment, and kind is structure, allow. - // Operator overloading uses immutable copy of right operand. - // It's safe. - ret true - } - s.pushErr(op, LogMsg.AssignNonMutToMut, right.Kind.Str()) - ret false - |: - ret true - } + match { + | !left.Mutable: + s.pushErr(op, LogMsg.AssignToNonMut) + ret false + | right != nil && !right.Mutable && right.Kind.Mutable(): + if op.Id != TokenId.Eq && right.Kind.Struct() != nil { + // If operator is not assignment, and kind is structure, allow. + // Operator overloading uses immutable copy of right operand. + // It's safe. + ret true + } + s.pushErr(op, LogMsg.AssignNonMutToMut, right.Kind.Str()) + ret false + |: + ret true + } } fn checkAssign(mut &s: &Sema, mut &left: &Data, mut right: &Data, op: &Token): (ok: bool) { - f := left.Kind.Fn() - if f != nil && f.Decl != nil && f.Decl.Global { - s.pushErr(op, LogMsg.AssignTypeNotSupportValue) - ret false - } - - match { - | left.IsConst(): - s.pushErr(op, LogMsg.AssignConst) - s.pushSuggestion(LogMsg.RemoveConstToAssign) - ret false - | !left.Lvalue: - s.pushErr(op, LogMsg.AssignRequireLvalue) - ret false - | !checkMut(s, left, right, op): - ret false - |: - ret true - } + f := left.Kind.Fn() + if f != nil && f.Decl != nil && f.Decl.Global { + s.pushErr(op, LogMsg.AssignTypeNotSupportValue) + ret false + } + + match { + | left.IsConst(): + s.pushErr(op, LogMsg.AssignConst) + s.pushSuggestion(LogMsg.RemoveConstToAssign) + ret false + | !left.Lvalue: + s.pushErr(op, LogMsg.AssignRequireLvalue) + ret false + | !checkMut(s, left, right, op): + ret false + |: + ret true + } } fn isValidAstStForNextSt(mut &n: StmtData): bool { - match type n { - | &AssignSt: - ret !(&AssignSt)(n).Declarative - | &Expr: - ret true - |: - ret false - } + match type n { + | &AssignSt: + ret !(&AssignSt)(n).Declarative + | &Expr: + ret true + |: + ret false + } } fn isValidStForNextSt(&st: Stmt): bool { - match type st { - | &Postfix - | &Assign - | &MultiAssign: - ret true - | &Data: - match type (&Data)(st).Model { - | &FnCallExprModel: - ret true - |: - ret false - } - |: - ret false - } + match type st { + | &Postfix + | &Assign + | &MultiAssign: + ret true + | &Data: + match type (&Data)(st).Model { + | &FnCallExprModel: + ret true + |: + ret false + } + |: + ret false + } } fn stmtIsDef(&st: Stmt): bool { - match type st { - | &Var: - ret true - |: - ret false - } + match type st { + | &Var: + ret true + |: + ret false + } } // Scope. struct Scope { - Parent: &Scope - Unsafety: bool - Deferred: bool - Stmts: []Stmt + Parent: &Scope + Unsafety: bool + Deferred: bool + Stmts: []Stmt } // Chain conditional node. struct If { - Expr: ExprModel - Scope: &Scope + Expr: ExprModel + Scope: &Scope } // Default scope of conditional chain. struct Else { - Scope: &Scope + Scope: &Scope } // Conditional chain. struct Conditional { - Elifs: []&If // First not is root condition. - Default: &Else + Elifs: []&If // First not is root condition. + Default: &Else } // Infinity iteration. struct InfIter { - Scope: &Scope + Scope: &Scope } // While iteration. struct WhileIter { - Expr: ExprModel // Can be nil if iteration is while-next kind. - Next: Stmt // Nil if iteration is not while-next kind. - Scope: &Scope + Expr: ExprModel // Can be nil if iteration is while-next kind. + Next: Stmt // Nil if iteration is not while-next kind. + Scope: &Scope } impl WhileIter { - // Reports whether iteration is while-next kind. - fn IsWhileNext(self): bool { - ret self.Next != nil - } + // Reports whether iteration is while-next kind. + fn IsWhileNext(self): bool { + ret self.Next != nil + } } // Range iteration. struct RangeIter { - Expr: &Data - Scope: &Scope - KeyA: &Var - KeyB: &Var + Expr: &Data + Scope: &Scope + KeyA: &Var + KeyB: &Var } // Continue statement. struct ContSt { - It: uintptr + It: uintptr } // Break statement. struct BreakSt { - It: uintptr - Mtch: uintptr + It: uintptr + Mtch: uintptr } // Label. struct Label { - Ident: str + Ident: str } // Goto statement. struct GotoSt { - Ident: str - Label: &Label + Ident: str + Label: &Label } // Postfix assignment. struct Postfix { - Expr: ExprModel - Op: str + Expr: ExprModel + Op: str } // Assigment. struct Assign { - Left: &OperandExprModel - Right: &OperandExprModel - Op: &Token + Left: &OperandExprModel + Right: &OperandExprModel + Op: &Token } // Multi-declarative assignment. struct MultiAssign { - Decls: []&Var - Left: []&Data // Nil Model:s represents ingored expressions. - Right: ExprModel + Decls: []&Var + Left: []&Data // Nil Model:s represents ingored expressions. + Right: ExprModel } // Match-Case. struct Match { - Expr: &Data - TypeMatch: bool - Comptime: bool - Cases: []&Case - Default: &Case + Expr: &Data + TypeMatch: bool + Comptime: bool + Cases: []&Case + Default: &Case } impl Match { - // Reports whether match is type-match for generic type. - fn IsGenericTypeMatch(self): bool { - ret self.TypeMatch && self.Expr != nil && self.Expr.Kind.Generic - } + // Reports whether match is type-match for generic type. + fn IsGenericTypeMatch(self): bool { + ret self.TypeMatch && self.Expr != nil && self.Expr.Kind.Generic + } } // Match-Case case. struct Case { - Owner: &Match - Scope: &Scope - Exprs: []&Data - Next: &Case + Owner: &Match + Scope: &Scope + Exprs: []&Data + Next: &Case } impl Case { - // Reports whether case is default. - fn isDefault(self): bool { ret self.Exprs == nil } + // Reports whether case is default. + fn isDefault(self): bool { ret self.Exprs == nil } } // Fall statement. struct FallSt { - DestCase: uintptr + DestCase: uintptr } // Return statement. struct RetSt { - Func: &FnIns - Expr: ExprModel + Func: &FnIns + Expr: ExprModel } struct scopeLabel { - token: &Token - label: &Label - pos: int - scope: &scopeChecker - used: bool + token: &Token + label: &Label + pos: int + scope: &scopeChecker + used: bool } struct scopeGoto { - st: &GotoSt - gt: &ast::GotoSt - scope: &scopeChecker - pos: int + st: &GotoSt + gt: &ast::GotoSt + scope: &scopeChecker + pos: int } // Scope checker. struct scopeChecker { - calledFrom: &Token - s: &Sema - owner: &FnIns // See developer reference (1). - parent: &scopeChecker - childIndex: int // Index of child scope. - table: &SymbolTable - scope: &Scope - tree: &ScopeTree - result: &FnIns // Result type for last statement. - it: uintptr - cse: uintptr - captured: &[]&Var // Anonymous function's captured variables will be stored here. - labels: &[]&scopeLabel // All labels of all scopes. - gotos: &[]&scopeGoto // All gotos of all scopes. - i: int + calledFrom: &Token + s: &Sema + owner: &FnIns // See developer reference (1). + parent: &scopeChecker + childIndex: int // Index of child scope. + table: &SymbolTable + scope: &Scope + tree: &ScopeTree + result: &FnIns // Result type for last statement. + it: uintptr + cse: uintptr + captured: &[]&Var // Anonymous function's captured variables will be stored here. + labels: &[]&scopeLabel // All labels of all scopes. + gotos: &[]&scopeGoto // All gotos of all scopes. + i: int } impl Lookup for scopeChecker { - // Returns imported package by selector. - // Returns nil reference if selector returns false for all packages. - // Returns nil reference if selector is nil. - // - // Lookups: - // - Sema. - fn SelectPackage(mut self, selector: fn(&ImportInfo): bool): &ImportInfo { - ret self.s.SelectPackage(selector) - } - - // Returns variable by identifier and binded state. - // Returns nil reference if not exist any variable in this identifier. - // - // Lookups: - // - Current scope. - // - Parent scopes. - // - Sema. - fn FindVar(mut self, ident: str, binded: bool): &Var { - if !binded { // Local variables cannot be binded. - mut v := self.findVar(ident) - if v != nil { - ret v - } - } - ret self.s.FindVar(ident, binded) - } - - // Returns type alias by identifier and binded state. - // Returns nil reference if not exist any type alias in this identifier. - // - // Lookups: - // - Current scope. - // - Parent scopes. - // - Sema. - fn FindTypeAlias(mut self, ident: str, binded: bool): &TypeAlias { - // Search reverse for correct shadowing. - const Reverse = true - mut ta := self.table.findTypeAlias(ident, binded, Reverse) - if ta != nil { - ret ta - } - - mut parent := self.parent - for parent != nil { - ta = parent.table.findTypeAlias(ident, binded, Reverse) - if ta != nil { - ret ta - } - parent = parent.parent - } - - ret self.s.FindTypeAlias(ident, binded) - } - - // Returns struct by identifier and binded state. - // Returns nil reference if not exist any struct in this identifier. - // - // Lookups: - // - Sema. - fn FindStruct(mut self, ident: str, binded: bool): &Struct { - ret self.s.FindStruct(ident, binded) - } - - // Returns function by identifier and binded state. - // Returns nil reference if not exist any function in this identifier. - // - // Lookups: - // - Sema. - fn FindFn(mut self, ident: str, binded: bool): &Fn { - ret self.s.FindFn(ident, binded) - } - - // Returns trait by identifier. - // Returns nil reference if not exist any trait in this identifier. - // - // Lookups: - // - Sema. - fn FindTrait(mut self, ident: str): &Trait { - ret self.s.FindTrait(ident) - } - - // Returns enum by identifier. - // Returns nil reference if not exist any enum in this identifier. - // - // Lookups: - // - Sema. - fn FindEnum(mut self, ident: str): &Enum { - ret self.s.FindEnum(ident) - } - - // Returns type enum by identifier. - // Returns nil reference if not exist any type enum in this identifier. - // - // Lookups: - // - Sema. - fn FindTypeEnum(mut self, ident: str): &TypeEnum { - ret self.s.FindTypeEnum(ident) - } + // Returns imported package by selector. + // Returns nil reference if selector returns false for all packages. + // Returns nil reference if selector is nil. + // + // Lookups: + // - Sema. + fn SelectPackage(mut self, selector: fn(&ImportInfo): bool): &ImportInfo { + ret self.s.SelectPackage(selector) + } + + // Returns variable by identifier and binded state. + // Returns nil reference if not exist any variable in this identifier. + // + // Lookups: + // - Current scope. + // - Parent scopes. + // - Sema. + fn FindVar(mut self, ident: str, binded: bool): &Var { + if !binded { // Local variables cannot be binded. + mut v := self.findVar(ident) + if v != nil { + ret v + } + } + ret self.s.FindVar(ident, binded) + } + + // Returns type alias by identifier and binded state. + // Returns nil reference if not exist any type alias in this identifier. + // + // Lookups: + // - Current scope. + // - Parent scopes. + // - Sema. + fn FindTypeAlias(mut self, ident: str, binded: bool): &TypeAlias { + // Search reverse for correct shadowing. + const Reverse = true + mut ta := self.table.findTypeAlias(ident, binded, Reverse) + if ta != nil { + ret ta + } + + mut parent := self.parent + for parent != nil { + ta = parent.table.findTypeAlias(ident, binded, Reverse) + if ta != nil { + ret ta + } + parent = parent.parent + } + + ret self.s.FindTypeAlias(ident, binded) + } + + // Returns struct by identifier and binded state. + // Returns nil reference if not exist any struct in this identifier. + // + // Lookups: + // - Sema. + fn FindStruct(mut self, ident: str, binded: bool): &Struct { + ret self.s.FindStruct(ident, binded) + } + + // Returns function by identifier and binded state. + // Returns nil reference if not exist any function in this identifier. + // + // Lookups: + // - Sema. + fn FindFn(mut self, ident: str, binded: bool): &Fn { + ret self.s.FindFn(ident, binded) + } + + // Returns trait by identifier. + // Returns nil reference if not exist any trait in this identifier. + // + // Lookups: + // - Sema. + fn FindTrait(mut self, ident: str): &Trait { + ret self.s.FindTrait(ident) + } + + // Returns enum by identifier. + // Returns nil reference if not exist any enum in this identifier. + // + // Lookups: + // - Sema. + fn FindEnum(mut self, ident: str): &Enum { + ret self.s.FindEnum(ident) + } + + // Returns type enum by identifier. + // Returns nil reference if not exist any type enum in this identifier. + // + // Lookups: + // - Sema. + fn FindTypeEnum(mut self, ident: str): &TypeEnum { + ret self.s.FindTypeEnum(ident) + } } impl scopeChecker { - // Reports whether scope is unsafe. - fn isUnsafe(mut &self): bool { - mut scope := self - - iter: - if scope.scope.Unsafety { - ret true - } - - if scope.parent != nil { - scope = scope.parent - goto iter - } - - ret false - } - - // Reports scope is root. - // Accepts anonymous functions as root. - fn isRoot(self): bool { - ret self.parent == nil || self.owner != nil - } - - // Stop checking. - fn stop(mut self) { - self.i = -1 - } - - // Reports whether checking is stopped. - fn stopped(self): bool { - ret self.i == -1 - } - - // Reports scope is deferred. - fn isDeferred(mut &self): bool { - mut scope := self - - iter: - if scope.scope.Deferred { - ret true - } - - if scope.parent != nil { - scope = scope.parent - goto iter - } - - ret false - } - - // Push captured variable. - // It will append to all [captured] fields, - // because if child-scopes captures this variable, - // parent-scopes must be capture this variable too. - // Starts pushing from self to all parents. - // If any parent scope is not captures variable v, iteration will be break. - fn pushCaptured(mut &self, mut &v: &Var) { - mut sc := self - for { - if sc.captured != nil { - for _, cv in *sc.captured { - if cv == v { - goto exist - } - } - *sc.captured = append(*sc.captured, v) - exist: - } - if sc.parent == nil { - break - } - sc = sc.parent - if !isVarCaptured(sc, sc, v) { - break - } - } - } - - // Returns root scope. - // Accepts anonymous functions as root. - fn getRoot(mut &self): &scopeChecker { - mut root := self - for root.parent != nil && root.owner == nil { - root = root.parent - } - ret root - } - - // Returns hard root scope, owner always represents root function of this scope. - // Not accepts anonymous functions as root. - fn getHardRoot(mut &self): &scopeChecker { - mut root := self - for root.parent != nil { - root = root.parent - } - ret root - } - - // Like [Lookup.FindVar] but designed for local variables only. - fn findVar(mut self, ident: str): &Var { - const Reverse = true // Search reverse for correct shadowing. - const Binded = false // Local variables cannot be binded. - mut v := self.table.findVar(ident, Binded, Reverse) - if v != nil { - ret v - } - mut parent := self.parent - for parent != nil { - v = parent.table.findVar(ident, Binded, Reverse) - if v != nil { - ret v - } - parent = parent.parent - } - ret nil - } - - // Returns label by identifier. - // Returns nil if not exist any label in this identifier. - // Just lookups current scope. - fn findLabel(mut self, &ident: str): &Label { - for (_, mut st) in self.scope.Stmts { - match type st { - | &Label: - mut label := (&Label)(st) - if label.Ident == ident { - ret label - } - } - } - ret nil - } - - // Returns label by identifier. - // Returns nil if not exist any label in this identifier. - // Just lookups current scope. - fn findLabelScope(mut &self, &ident: str): &scopeLabel { - mut label := self.findLabelAll(ident) - if label != nil && label.scope == self { - ret label - } - - ret nil - } - - // Returns label by identifier. - // Returns nil if not exist any label in this identifier. - // Lookups all labels. - fn findLabelAll(mut self, &ident: str): &scopeLabel { - for (_, mut lbl) in *self.labels { - if lbl.label.Ident == ident { - ret lbl - } - } - ret nil - } - - // Reports this identifier duplicated in scope. - // The "self" parameter represents address of exception identifier. - // If founded identifier address equals to self, will be skipped. - fn isDuplicatedIdent(mut self, itself: uintptr, &ident: str): bool { - v := self.FindVar(ident, false) - if v != nil && uintptr(v) != itself { - if v.Scope == nil { // Ignore globals. - ret false - } - ret v.Scope == self.scope || !self.s.isFlag(SemaFlag.Shadowing) - } - - ta := self.FindTypeAlias(ident, false) - if ta != nil && uintptr(ta) != itself { - if ta.Scope == nil { // Ignore globals. - ret false - } - ret ta.Scope == self.tree || !self.s.isFlag(SemaFlag.Shadowing) - } - - ret false - } - - fn checkVarDecl(mut &self, mut decl: &VarDecl) { - mut v := buildVar(decl) - v.Scope = self.scope - - defer { - self.table.Vars = append(self.table.Vars, v) - self.scope.Stmts = append(self.scope.Stmts, v) - } - - if self.isDuplicatedIdent(uintptr(v), v.Ident) { - self.s.pushErr(v.Token, LogMsg.DuplicatedIdent, v.Ident) - self.s.pushSuggestion(LogMsg.RenameForAvoidDuplication) - self.stop() - ret - } - - self.s.checkVarDecl(v, self) - if !v.IsTypeInferred() && (v.Kind == nil || v.Kind.Kind == nil) { - ret - } - - self.s.evalVarValue(v, self) - if !v.IsInitialized() || v.Value.Data == nil { - // Skip checks if error ocurrs when evaluated expression, - // or unitiliazed variable. - ret - } - self.removeInteriorMutRisk(v.Value.Data) - self.s.checkVarValue(v) - } - - fn checkTypeAlias(mut &self, mut &ta: &TypeAlias) { - if self.isDuplicatedIdent(uintptr(ta), ta.Ident) { - self.s.pushErr(ta.Token, LogMsg.DuplicatedIdent, ta.Ident) - self.s.pushSuggestion(LogMsg.RenameForAvoidDuplication) - self.stop() - ret - } - self.s.checkTypeAliasDecl(ta, self) - self.table.TypeAliases = append(self.table.TypeAliases, ta) - - // Stop immediately if destination type is could not evaluated. - if ta.Kind.Kind == nil { - self.stop() - } - } - - fn checkTypeAliasDecl(mut &self, mut decl: &TypeAliasDecl) { - mut ta := buildTypeAlias(decl) - self.checkTypeAlias(ta) - } - - fn getChild(mut self): &Scope { - ret &Scope{ - Parent: self.scope, - } - } - - fn checkChildSsc(mut &self, mut &tree: &ScopeTree, mut &s: &Scope, mut &ssc: &scopeChecker) { - ssc.parent = self - ssc.check(tree, s) - } - - fn checkChildSc(mut &self, mut &tree: &ScopeTree, mut &ssc: &scopeChecker): &Scope { - mut s := self.getChild() - self.checkChildSsc(tree, s, ssc) - ret s - } - - fn checkChild(mut &self, mut &tree: &ScopeTree): &Scope { - mut ssc := self.newChildChecker() - ret self.checkChildSc(tree, ssc) - } - - fn checkAnonScope(mut &self, mut tree: &ScopeTree) { - mut s := self.checkChild(tree) - self.scope.Stmts = append(self.scope.Stmts, s) - } - - fn processErrorCall(mut &self, mut &m: &BuiltinErrorCallExprModel, err: &Token) { - if self.isDeferred() { - self.s.pushErr(err, LogMsg.ErrorInDeferred) - } - - mut root := self.getRoot() - if !root.owner.Decl.Exceptional { - self.s.pushErr(err, LogMsg.ErrorWithNonExceptional) - self.s.pushSuggestion(LogMsg.DeclareExceptional) - } - m.Func = root.owner - } - - fn checkExpr(mut &self, mut expr: &Expr) { - mut eval := self.s.eval(self) - eval.ignored = true - mut d := eval.evalExpr(expr) - if d == nil || d.Model == nil { - // Skip nil data, because evaluation failed and error documented (it should be) already. - // Skip nil modeled data, this return only caused by built-in functions and it should be safe. - ret - } - - match type d.Model { - | &BuiltinErrorCallExprModel: - mut m := (&BuiltinErrorCallExprModel)(d.Model) - self.processErrorCall(m, expr.Token) - self.scope.Stmts = append(self.scope.Stmts, d) - | &BackendEmitExprModel - | &BuiltinAppendCallExprModel - | &BuiltinOutCallExprModel - | &BuiltinOutlnCallExprModel - | &BuiltinPanicCallExprModel - | &BuiltinAssertCallExprModel - | &BuiltinCopyCallExprModel - | &BuiltinDeleteCallExprModel - | &FreeExprModel - | &FnCallExprModel: - self.scope.Stmts = append(self.scope.Stmts, d) - |: - self.s.pushErr(expr.Token, LogMsg.InvalidSyntax) - } - } - - fn checkIf(mut &self, mut i: &ast::If): &If { - mut s := self.checkChild(i.Scope) - - mut d := self.s.eval(self).evalExpr(i.Expr) - if d == nil { - ret nil - } - - mut prim := d.Kind.Prim() - if prim == nil || !prim.IsBool() { - self.s.pushErr(i.Expr.Token, LogMsg.IfRequireBoolExpr) - ret nil - } - - ret &If{ - Expr: d.Model, - Scope: s, - } - } - - fn checkElse(mut &self, mut e: &ast::Else): &Else { - ret &Else{ - Scope: self.checkChild(e.Scope), - } - } - - fn checkConditional(mut &self, mut conditional: &ast::Conditional) { - mut c := new(Conditional) - self.scope.Stmts = append(self.scope.Stmts, c) - - c.Elifs = make([]&If, 0, len(conditional.Tail) + 1) - - c.Elifs = append(c.Elifs, self.checkIf(conditional.Head)) - for (_, mut elif) in conditional.Tail { - c.Elifs = append(c.Elifs, self.checkIf(elif)) - } - - if conditional.Default != nil { - c.Default = self.checkElse(conditional.Default) - } - } - - fn checkIterScopeSsc(mut &self, it: uintptr, mut tree: &ScopeTree, mut &s: &Scope, mut ssc: &scopeChecker) { - ssc.it = it - self.checkChildSsc(tree, s, ssc) - } - - fn checkIterScopeSc(mut &self, it: uintptr, mut tree: &ScopeTree, mut ssc: &scopeChecker): &Scope { - mut scope := self.getChild() - self.checkIterScopeSsc(it, tree, scope, ssc) - ret scope - } - - fn checkIterScope(mut &self, it: uintptr, mut &tree: &ScopeTree): &Scope { - mut ssc := self.newChildChecker() - ret self.checkIterScopeSc(it, tree, ssc) - } - - fn checkInfIter(mut &self, mut &it: &Iter) { - mut kind := new(InfIter) - self.scope.Stmts = append(self.scope.Stmts, kind) - kind.Scope = self.checkIterScope(uintptr(kind), it.Scope) - } - - fn checkWhileIter(mut &self, mut &it: &Iter) { - mut wh := (&WhileKind)(it.Kind) - if wh.Expr == nil && wh.Next == nil { - self.checkInfIter(it) - ret - } - - mut kind := new(WhileIter) - self.scope.Stmts = append(self.scope.Stmts, kind) - kind.Scope = self.checkIterScope(uintptr(kind), it.Scope) - - if wh.Expr != nil { - mut d := self.s.eval(self).evalExpr(wh.Expr) - if d == nil { - ret - } - - prim := d.Kind.Prim() - if prim == nil { - self.s.pushErr(it.Token, LogMsg.IterWhileRequireBoolExpr) - ret - } - - if !prim.IsBool() { - self.s.pushErr(it.Token, LogMsg.IterWhileRequireBoolExpr) - ret - } - - kind.Expr = d.Model - } - - if wh.IsWhileNext() { - if !isValidAstStForNextSt(wh.Next) { - self.s.pushErr(wh.NextToken, LogMsg.InvalidStmtForNext) - ret - } - - n := len(self.scope.Stmts) - self.checkNode(wh.Next) - if n < len(self.scope.Stmts) { - mut st := self.scope.Stmts[n] - self.scope.Stmts = self.scope.Stmts[:n] // Remove trailing statements. - if !isValidStForNextSt(st) { - self.s.pushErr(wh.NextToken, LogMsg.InvalidStmtForNext) - } - kind.Next = st - } - } - } - - fn checkComptimeRangeIter(mut &self, mut &it: &Iter, mut &kind: &RangeIter, mut &d: &Data) { - if kind.KeyA != nil { - if !self.s.isFlag(SemaFlag.Shadowing) && self.isDuplicatedIdent(0, kind.KeyA.Ident) { - self.s.pushErr(kind.KeyA.Token, LogMsg.DuplicatedIdent, kind.KeyA.Ident) - self.s.pushSuggestion(LogMsg.RenameForAvoidDuplication) - } - } - if kind.KeyB != nil { - if !self.s.isFlag(SemaFlag.Shadowing) && self.isDuplicatedIdent(0, kind.KeyB.Ident) { - self.s.pushErr(kind.KeyB.Token, LogMsg.DuplicatedIdent, kind.KeyB.Ident) - self.s.pushSuggestion(LogMsg.RenameForAvoidDuplication) - } - } - - mut rang := (&RangeKind)(it.Kind) - makeComptimeRange(d) - if d.Decl { - self.s.pushErr(rang.Expr.Token, LogMsg.InvalidTypeForComptimeIter, d.Kind.Str()) - ret - } - - mut rc := rangeChecker{ - sc: self, - Kind: kind, - rang: rang, - d: d, - } - ok := rc.check() - if !ok { - ret - } - - mut comptime := d.Kind.comptimeRange() - comptime.kind.ready(kind.KeyA, kind.KeyB) - mut i := 0 - errors := len(self.s.errors) - for i < comptime.kind.len(); i++ { - mut ssc := self.newChildChecker() - mut scope := self.getChild() - if kind.KeyA != nil { - kind.KeyA.Scope = scope - ssc.table.Vars = append(ssc.table.Vars, kind.KeyA) - } - if kind.KeyB != nil { - kind.KeyB.Scope = scope - ssc.table.Vars = append(ssc.table.Vars, kind.KeyB) - } - comptime.kind.step(i, kind.KeyA, kind.KeyB) - self.checkChildSsc(it.Scope, scope, ssc) - if errors != len(self.s.errors) { - // Stop execution if new error occurred. - break - } - self.scope.Stmts = append(self.scope.Stmts, scope) - } - } - - fn checkRangeIter(mut &self, mut &it: &Iter) { - mut rang := (&RangeKind)(it.Kind) - - mut d := self.s.eval(self).evalExpr1(rang.Expr) - if d == nil { - ret - } - - mut kind := &RangeIter{ - Expr: d, - } - - if it.Comptime { - self.checkComptimeRangeIter(it, kind, d) - ret - } - if d.Kind.comptime() { - self.s.pushErr(rang.Expr.Token, LogMsg.ComptimeExprForRuntimeIteration) - self.s.pushSuggestion(LogMsg.DeclareComptimeForeach) - ret - } - - mut rc := rangeChecker{ - sc: self, - Kind: kind, - rang: rang, - d: d, - } - ok := rc.check() - if !ok { - ret - } - - self.scope.Stmts = append(self.scope.Stmts, kind) - - mut ssc := self.newChildChecker() - mut scope := self.getChild() - - if kind.KeyA != nil { - if !self.s.isFlag(SemaFlag.Shadowing) && self.isDuplicatedIdent(0, kind.KeyA.Ident) { - self.s.pushErr(kind.KeyA.Token, LogMsg.DuplicatedIdent, kind.KeyA.Ident) - self.s.pushSuggestion(LogMsg.RenameForAvoidDuplication) - } - kind.KeyA.Scope = scope - ssc.table.Vars = append(ssc.table.Vars, kind.KeyA) - } - - if kind.KeyB != nil { - if !self.s.isFlag(SemaFlag.Shadowing) && self.isDuplicatedIdent(0, kind.KeyB.Ident) { - self.s.pushErr(kind.KeyB.Token, LogMsg.DuplicatedIdent, kind.KeyB.Ident) - self.s.pushSuggestion(LogMsg.RenameForAvoidDuplication) - } - kind.KeyB.Scope = scope - ssc.table.Vars = append(ssc.table.Vars, kind.KeyB) - } - - self.checkIterScopeSsc(uintptr(kind), it.Scope, scope, ssc) - kind.Scope = scope - } - - fn checkIter(mut &self, mut it: &Iter) { - if it.IsInf() { - if it.Comptime { - self.s.pushErr(it.Token, LogMsg.InvalidComptimeIter) - ret - } - self.checkInfIter(it) - ret - } - - match type it.Kind { - | &WhileKind: - if it.Comptime { - self.s.pushErr(it.Token, LogMsg.InvalidComptimeIter) - ret - } - self.checkWhileIter(it) - | &RangeKind: - self.checkRangeIter(it) - |: - outln("error ") - } - } - - fn checkValidContLabel(mut &self, it: uintptr): bool { - mut scope := self - - iter: - if scope.it == it { - ret true - } - - if scope.parent != nil { - scope = scope.parent - goto iter - } - - ret false - } - - fn checkValidBreakLabel(mut &self, ptr: uintptr): bool { - mut scope := self - - iter: - if scope.it == ptr { - ret true - } - - if scope.cse != 0 { - mtch := unsafe { uintptr((*Case)(scope.cse).Owner) } - if mtch == ptr { - ret true - } - } - - if scope.parent != nil { - scope = scope.parent - goto iter - } - - ret false - } - - fn checkContValidScope(mut &self, c: &ast::ContSt): &ContSt { - if self.isDeferred() { - self.s.pushErr(c.Token, LogMsg.ContinueAtOutOfValidScope) - ret nil - } - - if c.Label != nil { - ret new(ContSt) - } - - mut scope := self - iter: - match { - | scope.it == 0 && scope.parent != nil && scope.owner == nil: - scope = scope.parent - goto iter - | scope.it != 0: - ret &ContSt{It: scope.it} - } - - self.s.pushErr(c.Token, LogMsg.ContinueAtOutOfValidScope) - ret nil - } - - fn checkCont(mut &self, c: &ast::ContSt) { - mut cont := self.checkContValidScope(c) - if cont == nil { - ret - } - - if c.Label != nil { // Label given. - mut label := findLabelParent(c.Label.Kind, self.parent) - if label == nil { - self.s.pushErr(c.Label, LogMsg.LabelNotExist, c.Label.Kind) - ret - } - - label.used = true - - if label.pos+1 >= len(label.scope.scope.Stmts) { - self.s.pushErr(c.Label, LogMsg.InvalidLabel, c.Label.Kind) - ret - } - - i := label.pos + 1 - if i >= len(label.scope.scope.Stmts) { - self.s.pushErr(c.Label, LogMsg.InvalidLabel) - } else { - mut st := label.scope.scope.Stmts[i] - match type st { - | &InfIter: - cont.It = uintptr((&InfIter)(st)) - | &RangeIter: - cont.It = uintptr((&RangeIter)(st)) - | &WhileIter: - cont.It = uintptr((&WhileIter)(st)) - |: - self.s.pushErr(c.Label, LogMsg.InvalidLabel, c.Label.Kind) - } - } - } - - if cont.It != 0 { - if !self.checkValidContLabel(cont.It) { - self.s.pushErr(c.Label, LogMsg.InvalidLabel, c.Label.Kind) - } - } - - self.scope.Stmts = append(self.scope.Stmts, cont) - } - - fn checkLabel(mut &self, mut l: &LabelSt) { - if self.findLabel(l.Ident) != nil { - self.s.pushErr(l.Token, LogMsg.LabelExist, l.Ident) - ret - } - - mut label := &Label{ - Ident: l.Ident, - } - - self.scope.Stmts = append(self.scope.Stmts, label) - *self.labels = append(*self.labels, &scopeLabel{ - token: l.Token, - label: label, - pos: len(self.scope.Stmts) - 1, - scope: self, - }) - } - - fn pushGoto(mut &self, mut gt: &ast::GotoSt) { - mut st := &GotoSt{ - Ident: gt.Label.Kind, - } - self.scope.Stmts = append(self.scope.Stmts, st) - - *self.gotos = append(*self.gotos, &scopeGoto{ - st: st, - gt: gt, - pos: len(self.scope.Stmts) - 1, - scope: self, - }) - } - - fn checkPostfix(mut &self, mut a: &AssignSt) { - if len(a.Left) > 1 { - self.s.pushErr(a.Setter, LogMsg.InvalidSyntax) - ret - } - - mut expr := a.Left[0].Expr - mut d := self.s.eval(self).evalExpr(expr) - if d == nil { - ret - } - - _ = checkAssign(self.s, d, nil, a.Setter) - - if d.Kind.Ptr() != nil { - mut ptr := d.Kind.Ptr() - if ptr.IsUnsafe() { - self.s.pushErr(a.Setter, LogMsg.OperatorNotForJuleType, a.Setter.Kind, d.Kind.Str()) - ret - } - } else { - if d.Kind.Prim() == nil || !types::IsNum(d.Kind.Prim().Kind) { - self.s.pushErr(a.Setter, LogMsg.OperatorNotForJuleType, a.Setter.Kind, d.Kind.Str()) - ret - } - } - - self.scope.Stmts = append(self.scope.Stmts, &Postfix{ - Expr: d.Model, - Op: a.Setter.Kind, - }) - } - - fn isNewAssignIdent(mut self, ident: str): bool { - if IsIgnoreIdent(ident) || ident == "" { - ret false - } - ret self.table.defByIdent(ident, false) == nil - } - - // Remove the interior mutability risk if the d represents a structure and - // this scope is owned by method which is owned by the relevant structure. - // In this case we should remove the interior mutability risk of data to allow copying. - // Otherwise assign analysis will complain and copy operation will not be allowed. - // - // See also documentation of the [sema.isMutRiskyStruct] method. - fn removeInteriorMutRisk(mut &self, mut &d: &Data) { - s := d.Kind.Struct() - if s == nil { - ret - } - root := self.getHardRoot() - if root.owner.Owner != s { - ret - } - // Mark data as mutable. - // Mutable data is not occurs mutability risk for analysis. - d.Mutable = true - } - - fn checkStructureAssignOp(mut &self, mut &s: &StructIns, mut &a: &AssignSt, mut &r: &Data): bool { - // This method adopted from [binaryEval.checkStructCommonOperatorCompatibility]. - // Should follow this method. - let mut overload: &FnIns = nil - match a.Setter.Id { - | TokenId.PlusEq: - overload = s.Operators.AddAssign - | TokenId.MinusEq: - overload = s.Operators.SubAssign - | TokenId.SolidusEq: - overload = s.Operators.DivAssign - | TokenId.StarEq: - overload = s.Operators.MulAssign - | TokenId.PercentEq: - overload = s.Operators.ModAssign - | TokenId.ShlEq: - overload = s.Operators.ShlAssign - | TokenId.ShrEq: - overload = s.Operators.ShrAssign - | TokenId.VlineEq: - overload = s.Operators.BitOrAssign - | TokenId.AmperEq: - overload = s.Operators.BitAndAssign - | TokenId.CaretEq: - overload = s.Operators.BitXorAssign - |: - self.s.pushErr(a.Setter, LogMsg.OperatorNotForJuleType, a.Setter.Kind, s.Str()) - ret false - } - - if overload == nil { - self.s.pushErr(a.Setter, LogMsg.OperatorNotForJuleType, a.Setter.Kind, s.Str()) - ret false - } - - mut p := overload.Params[1] - ret self.s.checkAssignType(p.Decl.Reference, p.Kind, r, a.Setter) - } - - fn checkSingleAssign(mut &self, mut &a: &AssignSt) { - let mut l: &Data = nil - - if !IsIgnoreIdent(a.Left[0].Ident) { - mut expr := a.Left[0].Expr - l = self.s.eval(self).evalExpr(expr) - if l == nil { - ret - } - } - - let mut eval: &Eval = nil - if l != nil { - eval = self.s.evalp(self, l.Kind) - } else { - eval = self.s.eval(self) - } - eval.unsafety = self.isUnsafe() - mut r := eval.evalExpr(a.Right) - if r == nil { - ret - } - - self.removeInteriorMutRisk(r) - - if l == nil { - if r.Kind.Void() { - self.s.pushErr(a.Right.Token, LogMsg.InvalidExpr) - } - self.scope.Stmts = append(self.scope.Stmts, r) - ret - } - - if !checkAssign(self.s, l, r, a.Setter) { - ret - } - - if r.Kind.Tup() != nil { - self.s.pushErr(a.Setter, LogMsg.MissingMultiAssignIdents) - ret - } - - mut lm := &OperandExprModel{ - Kind: l.Kind, - Model: l.Model, - } - mut rm := &OperandExprModel{ - Kind: r.Kind, - Model: r.Model, - } - self.scope.Stmts = append(self.scope.Stmts, &Assign{Left: lm, Right: rm, Op: a.Setter}) - - if a.Setter.Id == TokenId.Eq { - mut checker := assignTypeChecker{ - s: self.s, - dest: l.Kind, - d: r, - errorToken: a.Setter, - } - if checker.check() { - rm.Model = r.Model - lm.Model = l.Model - } - ret - } - mut strct := l.Kind.Struct() - if strct != nil { - self.checkStructureAssignOp(strct, a, r) - ret - } - id := a.Setter.Id - a.Setter.Id = removeEqFromOp(a.Setter.Id) - mut solver := binaryEval.new(eval, a.Setter) - solver.l, solver.r = l, r - _ = solver.evalOp() - a.Setter.Id = id - } - - fn processEndPartOfMultiAssign(mut self, mut &st: &MultiAssign, - mut &a: &AssignSt, mut &lexpr: &AssignLeft, mut &l: &Data, mut &r: &Data) { - if !lexpr.Reference && IsIgnoreIdent(lexpr.Ident) { - if r.Kind.Void() { - self.s.pushErr(a.Right.Token, LogMsg.InvalidExpr) - } - st.Left = append(st.Left, nil) - ret - } - - if a.Declarative && (lexpr.Reference || self.isNewAssignIdent(lexpr.Ident)) { - if self.isDuplicatedIdent(0, lexpr.Ident) { - self.s.pushErr(lexpr.Token, LogMsg.DuplicatedIdent, lexpr.Ident) - self.s.pushSuggestion(LogMsg.RenameForAvoidDuplication) - self.stop() - ret - } - if IsIgnoreIdent(lexpr.Ident) { - self.s.pushErr(lexpr.Token, LogMsg.IgnoreIdent) - } - - // Add new variable declaration statement. - mut v := &Var{ - Ident: lexpr.Ident, - Token: lexpr.Token, - Mutable: lexpr.Mutable, - Reference: lexpr.Reference, - Scope: self.scope, - Value: &Value{ - Expr: a.Right, - Data: r, - }, - } - self.s.checkVarValue(v) - st.Left = append(st.Left, &Data{ - Lvalue: !v.Constant, - Mutable: v.Mutable, - Reference: v.Reference, - Kind: v.Kind.Kind, - Model: v, - }) - st.Decls = append(st.Decls, v) - self.table.Vars = append(self.table.Vars, v) - ret - } - - if lexpr.Mutable || lexpr.Reference { - self.s.pushErr(lexpr.Token, LogMsg.DuplicatedIdent, lexpr.Ident) - self.s.pushSuggestion(LogMsg.RenameForAvoidDuplication) - } - - if !checkAssign(self.s, l, r, lexpr.Token) { - ret - } - - // Set reference false because this is normal assigment. - // So, we don't need to check reference assignment should using lvalue. - const Reference = false - self.s.checkValidityForInitExpr(l.Mutable, Reference, l.Kind, r, a.Setter) - - mut checker := assignTypeChecker{ - s: self.s, - dest: l.Kind, - d: r, - errorToken: a.Setter, - } - checker.check() - st.Left = append(st.Left, l) - } - - fn checkMultiAssign(mut &self, mut &a: &AssignSt) { - mut rd := self.s.eval(self).evalExpr(a.Right) - if rd == nil { - ret - } - mut right := getDatasFromTupleData(rd) - if len(right) == 1 { - match type right[0].Model { - | &IndexingExprModel: - mut iem := (&IndexingExprModel)(right[0].Model) - if iem.Expr.Kind.Map() != nil { // Is map lookup. - right = [ - &Data{Kind: iem.Expr.Kind.Map().Val}, - &Data{Kind: primBool}, - ] - } - } - } - - match { - | len(a.Left) > len(right): - self.s.pushErr(a.Setter, LogMsg.OverflowMultiAssignIdents) - ret - | len(a.Left) < len(right): - self.s.pushErr(a.Setter, LogMsg.MissingMultiAssignIdents) - ret - } - - mut st := &MultiAssign{ - Right: rd.Model, - } - for i in a.Left { - mut lexpr := a.Left[i] - let mut l: &Data = nil - if !IsIgnoreIdent(lexpr.Ident) && - (!a.Declarative || !self.isNewAssignIdent(lexpr.Ident)) { - l = self.s.eval(self).evalExpr(lexpr.Expr) - if l == nil { - continue - } - } - mut r := right[i] - self.removeInteriorMutRisk(r) - self.processEndPartOfMultiAssign(st, a, lexpr, l, r) - } - self.scope.Stmts = append(self.scope.Stmts, st) - } - - fn checkAssignSt(mut &self, mut a: &AssignSt) { - match { - | IsPostfixOp(a.Setter.Id): - self.checkPostfix(a) - | len(a.Left) == 1: - self.checkSingleAssign(a) - |: - self.checkMultiAssign(a) - } - } - - fn checkCaseScope(mut &self, &c: &Case, mut &tree: &ScopeTree): &Scope { - mut ssc := self.newChildChecker() - ssc.cse = uintptr(c) - ret self.checkChildSc(tree, ssc) - } - - fn checkCase(mut &self, mut m: &Match, i: int, mut c: &ast::Case, mut expr: &Data): &Case { - mut case := m.Cases[i] - case.Exprs = make([]&Data, 0, len(c.Exprs)) - mut constMatched := false - mut eval := self.s.eval(self) - for (_, mut e) in c.Exprs { - mut d := eval.evalExprKind(e.Kind) - if d == nil { - continue - } - - if m.TypeMatch { - // Match types. There is not need to check whether d.Decl is true. - // Parser always tries to build type declarations for type-match cases. - // So, d is should be type declaration already. - case.Exprs = append(case.Exprs, d) - if countMatchType(m, d.Kind) > 1 { - self.s.pushErr(e.Token, LogMsg.DuplicateMatchType, d.Kind.Str()) - } - if m.Comptime { - constMatched = constMatched || expr.Kind.Equal(d.Kind) - } else { - if expr.Kind.TypeEnum() != nil { - _ = self.s.checkTypeCompatibility(expr.Kind, d.Kind, e.Token) - } else { - trt := expr.Kind.Trait() - if trt != nil { - _ = self.s.checkTypeCompatibility(expr.Kind, d.Kind, e.Token) - } - } - } - continue - } - - if d.Decl { - self.s.pushErr(e.Token, LogMsg.DeclFoundInsteadExpr) - self.s.pushSuggestion(LogMsg.UseTypeMatch) - continue - } - - if m.Comptime { - if !d.IsConst() && d.Kind.comptimeTypeInfo() == nil { - self.s.pushErr(e.Token, LogMsg.ExprNotConst) - self.s.pushSuggestion(LogMsg.InvalidExprForConstMatch) - continue - } - if !constMatched { - if d.IsConst() { - constMatched = expr.IsConst() && d.Constant.Eq(*expr.Constant) - } else { - exprCti := expr.Kind.comptimeTypeInfo() - constMatched = exprCti != nil && d.Kind.comptimeTypeInfo().base.Equal(exprCti.base) - } - } - } - - case.Exprs = append(case.Exprs, d) - if !m.Comptime || - expr.Kind.comptimeTypeInfo() == nil || - d.Kind.comptimeTypeInfo() == nil { - mut checker := assignTypeChecker{ - s: self.s, - dest: expr.Kind, - d: d, - errorToken: e.Token, - } - checker.check() - } - } - if !m.Comptime || constMatched { - case.Scope = self.checkCaseScope(case, c.Scope) - } - ret case - } - - fn checkCases(mut &self, mut &m: &MatchCase, mut rm: &Match, mut expr: &Data) { - rm.Cases = make([]&Case, 0, len(m.Cases)) - for i in m.Cases { - mut case := &Case{ - Owner: rm, - } - if i > 0 { - rm.Cases[i-1].Next = case - } - rm.Cases = append(rm.Cases, case) - } - - if rm.Default != nil && len(m.Cases) > 0 { - rm.Cases[len(rm.Cases)-1].Next = rm.Default - } - - for (i, mut c) in m.Cases { - self.checkCase(rm, i, c, expr) - } - } - - fn checkDefault(mut &self, mut m: &Match, mut d: &ast::Else): &Case { - mut def := &Case{ - Owner: m, - } - def.Scope = self.checkCaseScope(def, d.Scope) - ret def - } - - fn checkComptimePanic(mut &self, mut callToken: &Token, &s: &Scope) { - if len(s.Stmts) != 1 { - ret - } - stmt := s.Stmts[0] - match type stmt { - | &Data: - d := (&Data)(stmt) - match type d.Model { - | &BuiltinPanicCallExprModel: - mut m := (&BuiltinPanicCallExprModel)(d.Model) - match type m.Expr { - | &Const: - c := (&Const)(m.Expr) - if !c.IsStr() { - break - } - if callToken == nil { - mut root := self.getHardRoot() - if root.calledFrom == nil { - callToken = m.Token - } else { - callToken = root.calledFrom - } - } - self.s.pushErr(callToken, LogMsg.ComptimePanic, c.ReadStr()) - self.stop() - } - } - } - } - - fn processConstMatch(mut &self, mut &tm: &Match, mut &m: &MatchCase) { - for (i, mut c) in tm.Cases { - if c.Scope != nil { - let mut token: &Token = nil - if !tm.TypeMatch && len(c.Scope.Stmts) > 0 { - token = m.Cases[i].Scope.Stmts[0].Token - } - self.checkComptimePanic(token, c.Scope) - tm.Default = c - tm.Cases = nil - ret - } - } - if m.Default != nil { - tm.Cases = nil - tm.Default = self.checkDefault(tm, m.Default) - if tm.Default != nil { - let mut token: &Token = nil - if !tm.TypeMatch { - token = m.Default.Scope.Stmts[0].Token - } - self.checkComptimePanic(token, tm.Default.Scope) - } - } else { - // Remove all cases, no success matching. - tm.Cases = nil - } - } - - fn checkTypeMatch(mut &self, mut &m: &MatchCase) { - mut d := self.s.eval(self).eval1(m.Expr) - if d == nil { - ret - } - - if m.Comptime { - mut cti := d.Kind.comptimeTypeInfo() - if cti == nil { - if !d.Decl { - self.s.pushErr(m.Expr.Token, LogMsg.InvalidComptimeTypeMatchExpr) - ret - } - } else { - d.Kind = cti.base - } - } else if d.Decl || !((d.Kind.Prim() != nil && d.Kind.Prim().IsAny()) || d.Kind.Trait() != nil || d.Kind.TypeEnum() != nil) { - self.s.pushErr(m.Expr.Token, LogMsg.TypeCaseHasNotValidExpr) - ret - } - - mut tm := &Match{ - TypeMatch: true, - Expr: d, - Comptime: m.Comptime, - } - - // Do not check default if comptime matching enabled. - // We do not know any case will be matched yet. - // The [self.processConstMatch] will check cases and if not exist - // any matching, will check default case if exist and handle it. - if !tm.Comptime && m.Default != nil { - tm.Default = self.checkDefault(tm, m.Default) - } - - self.checkCases(m, tm, d) - if tm.Comptime { - self.processConstMatch(tm, m) - } - self.scope.Stmts = append(self.scope.Stmts, tm) - } - - fn checkCommonMatch(mut &self, mut &m: &MatchCase) { - let mut d: &Data = nil - if m.Expr == nil { - d = &Data{ - Constant: Const.NewBool(true), - Kind: primBool, - } - d.Model = d.Constant - } else { - d = self.s.eval(self).evalExpr1(m.Expr) - if d == nil { - ret - } - } - - if m.Comptime { - if !canComptimeMatch(d) { - self.s.pushErr(m.Expr.Token, LogMsg.ExprNotConst) - self.s.pushSuggestion(LogMsg.InvalidExprForConstMatch) - ret - } - } else if d.Kind.comptime() { - self.s.pushErr(m.Expr.Token, LogMsg.ExprNotConst) - self.s.pushSuggestion(LogMsg.InvalidExprForConstMatch) - ret - } - - mut mc := &Match{ - Expr: d, - Comptime: m.Comptime, - } - - // Push into stmts here. Otherwise, labeled break statements and others - // will may log error(s) event semantic is good. - self.scope.Stmts = append(self.scope.Stmts, mc) - - // Do not check default if comptime matching enabled. - // We do not know any case will be matched yet. - // The [self.processConstMatch] will check cases and if not exist - // any matching, will check default case if exist and handle it. - if !mc.Comptime && m.Default != nil { - mc.Default = self.checkDefault(mc, m.Default) - } - - self.checkCases(m, mc, d) - if mc.Comptime { - self.processConstMatch(mc, m) - } - } - - fn checkMatch(mut &self, mut m: &MatchCase) { - if m.TypeMatch { - self.checkTypeMatch(m) - ret - } - self.checkCommonMatch(m) - } - - fn checkFall(mut &self, f: &ast::FallSt) { - if self.cse == 0 || - len(self.scope.Stmts)+1 < len(self.scope.Stmts) || - self.isDeferred() { - self.s.pushErr(f.Token, LogMsg.FallthroughWrongUse) - ret - } - - mut case := unsafe { (*Case)(self.cse) } - if unsafe { case.Owner.Comptime } { - self.s.pushErr(f.Token, LogMsg.ComptimeFallthrough) - ret - } else if unsafe { case.Next } == nil { - self.s.pushErr(f.Token, LogMsg.FallthroughIntoFinalCase) - self.s.pushSuggestion(LogMsg.RemoveFallthroughFromFinalCase) - ret - } - - self.scope.Stmts = append(self.scope.Stmts, &FallSt{ - DestCase: unsafe { uintptr(case.Next) }, - }) - } - - fn checkBreakWithLabel(mut &self, b: &ast::BreakSt): &BreakSt { - mut brk := self.checkPlainBreak(b) - if brk == nil { - ret nil - } - - // Set pointer to zero. - // Pointer will set by label. - brk.It = 0 - brk.Mtch = 0 - - mut label := findLabelParent(b.Label.Kind, self.parent) - if label == nil { - self.s.pushErr(b.Label, LogMsg.LabelNotExist, b.Label.Kind) - ret nil - } - - label.used = true - - if label.pos+1 >= len(label.scope.scope.Stmts) { - self.s.pushErr(b.Label, LogMsg.InvalidLabel, b.Label.Kind) - ret nil - } - - i := label.pos + 1 - if i >= len(label.scope.scope.Stmts) { - self.s.pushErr(b.Label, LogMsg.InvalidLabel, b.Label.Kind) - } else { - mut st := label.scope.scope.Stmts[i] - match type st { - | &InfIter: - brk.It = uintptr((&InfIter)(st)) - | &RangeIter: - brk.It = uintptr((&RangeIter)(st)) - | &WhileIter: - brk.It = uintptr((&WhileIter)(st)) - | &Match: - brk.Mtch = uintptr((&Match)(st)) - |: - self.s.pushErr(b.Label, LogMsg.InvalidLabel, b.Label.Kind) - } - } - - if brk.It != 0 { - if !self.checkValidBreakLabel(brk.It) { - self.s.pushErr(b.Label, LogMsg.InvalidLabel, b.Label.Kind) - } - } - - if brk.Mtch != 0 { - if !self.checkValidBreakLabel(brk.Mtch) { - self.s.pushErr(b.Label, LogMsg.InvalidLabel, b.Label.Kind) - } - } - - ret brk - } - - fn checkPlainBreak(mut &self, b: &ast::BreakSt): &BreakSt { - if self.isDeferred() { - self.s.pushErr(b.Token, LogMsg.BreakAtOutOfValidScope) - ret nil - } - - mut scope := self - iter: - match { - | scope.it == 0 && scope.cse == 0 && scope.parent != nil && scope.owner == nil: - scope = scope.parent - goto iter - | scope.it != 0: - ret &BreakSt{It: scope.it} - | scope.cse != 0: - ret &BreakSt{Mtch: unsafe { uintptr((*Case)(scope.cse).Owner) }} - } - - self.s.pushErr(b.Token, LogMsg.BreakAtOutOfValidScope) - ret nil - } - - fn checkBreak(mut &self, b: &ast::BreakSt) { - if b.Label != nil { // Label given. - mut brk := self.checkBreakWithLabel(b) - self.scope.Stmts = append(self.scope.Stmts, brk) - ret - } - - mut brk := self.checkPlainBreak(b) - self.scope.Stmts = append(self.scope.Stmts, brk) - } - - fn checkRet(mut &self, mut r: &ast::RetSt) { - if self.isDeferred() { - self.s.pushErr(r.Token, LogMsg.RetInDeferred) - } - - mut rt := &RetSt{ - Func: self.getRoot().owner, - } - self.scope.Stmts = append(self.scope.Stmts, rt) - - mut rtc := &retTypeChecker{ - sc: self, - f: rt.Func, - errorToken: r.Token, - } - ok := rtc.check(r.Expr) - if !ok { - ret - } - - if r.Expr != nil { - rt.Expr = rtc.model - } - } - - fn checkUseExpr(mut &self, ue: &UseExpr) { - if self.result == nil { - self.s.pushErr(ue.Token, LogMsg.UseExprOutOfScope) - ret - } - - if self.isDeferred() { - self.s.pushErr(ue.Token, LogMsg.UseExprInDeferred) - } - - if self.i+1 < len(self.tree.Stmts) { - self.s.pushErr(ue.Token, LogMsg.UseExprNotLast) - } - // Validated at end of scope's analysis. - } - - fn checkNode(mut &self, mut &node: StmtData) { - match type node { - | &ScopeTree: - self.checkAnonScope((&ScopeTree)(node)) - | &VarDecl: - self.checkVarDecl((&VarDecl)(node)) - | &TypeAliasDecl: - self.checkTypeAliasDecl((&TypeAliasDecl)(node)) - | &Expr: - self.checkExpr((&Expr)(node)) - | &ast::Conditional: - self.checkConditional((&ast::Conditional)(node)) - | &Iter: - self.checkIter((&Iter)(node)) - | &ast::ContSt: - self.checkCont((&ast::ContSt)(node)) - | &LabelSt: - self.checkLabel((&LabelSt)(node)) - | &ast::GotoSt: - self.pushGoto((&ast::GotoSt)(node)) - | &AssignSt: - self.checkAssignSt((&AssignSt)(node)) - | &MatchCase: - self.checkMatch((&MatchCase)(node)) - | &ast::FallSt: - self.checkFall((&ast::FallSt)(node)) - | &ast::BreakSt: - self.checkBreak((&ast::BreakSt)(node)) - | &ast::RetSt: - self.checkRet((&ast::RetSt)(node)) - | &UseExpr: - self.checkUseExpr((&UseExpr)(node)) - |: - outln("error ") - } - } - - fn checkResult(mut &self) { - mut stmt := self.tree.Stmts[len(self.tree.Stmts)-1] - match type stmt.Data { - | &UseExpr: - mut ue := (&UseExpr)(stmt.Data) - mut d := self.s.eval(self).evalExpr(ue.Expr) - if d == nil { - ret - } - self.scope.Stmts = append(self.scope.Stmts, d) - mut rtc := &retTypeChecker{ - sc: self, - errorToken: ue.Expr.Token, - types: self.result.Types(), - } - _ = rtc.check(ue.Expr) - | &Expr: - mut expr := (&Expr)(stmt.Data) - mut d := self.s.eval(self).evalExpr(expr) - if d == nil { - ret - } - match type d.Model { - | &BuiltinErrorCallExprModel: - mut m := (&BuiltinErrorCallExprModel)(d.Model) - self.processErrorCall(m, expr.Token) - self.scope.Stmts = append(self.scope.Stmts, d) - |: - ret - } - | &ast::GotoSt - | &ast::BreakSt - | &ast::ContSt - | &ast::RetSt: - self.checkNode(stmt.Data) - |: - self.checkNode(stmt.Data) - ret - } - - // Set result to nil, it is a mark for whether result is processed. - self.result = nil - } - - fn checkTree(mut &self) { - self.i = 0 - mut n := len(self.tree.Stmts) - if self.result != nil { - // Skip last statement if result is exist. - // Algorithm will check last statement for result. - // So, if you check last statement also here, it will duplicate. - n-- - } - for self.i < n; self.i++ { - mut stmt := self.tree.Stmts[self.i] - self.checkNode(stmt.Data) - if self.stopped() { - ret - } - } - if self.result != nil && len(self.tree.Stmts) != 0 { - self.checkResult() - } - } - - fn checkGoto(mut self, mut >: &scopeGoto, mut &label: &scopeLabel) { - mut gtsc := gt.scope - for gtsc.childIndex-1 > label.scope.childIndex { - gtsc = gtsc.parent - } - - mut n := 0 - - if gtsc.scope == label.scope.scope { - // Scopes are same and label at above, so safe. - if gt.pos > label.pos { - ret - } - - // Limit controlling to goto's position. - // Label and goto is in same scope. - n = gt.pos - } - - mut i := label.pos - 1 - - if n == 0 { - for j, stmt in label.scope.scope.Stmts { - // Break if position reached to goto's scope. - if stmtIsGotoScope(stmt, gtsc.scope) { - n = j - break - } - } - } - - for i >= n; i-- { - mut stmt := label.scope.scope.Stmts[i] - if stmtIsDef(stmt) { - self.s.pushErr(gt.gt.Token, LogMsg.GotoJumpsDeclarations, gt.gt.Label.Kind) - ret - } - } - } - - fn checkGotos(mut self) { - for (_, mut gt) in *self.gotos { - mut label := self.findLabelAll(gt.gt.Label.Kind) - if label == nil { - self.s.pushErr(gt.gt.Token, LogMsg.LabelNotExist, gt.gt.Label.Kind) - continue - } - gt.st.Label = label.label - label.used = true - self.checkGoto(gt, label) - } - } - - fn checkLabels(mut self) { - for _, l in *self.labels { - if !l.used { - self.s.pushErr(l.token, LogMsg.DeclaredButNotUsed, l.label.Ident) - } - } - } - - fn checkVars(mut self) { - for _, v in self.table.Vars { - if !v.Used && !v.Constant && !IsIgnoreIdent(v.Ident) && !IsAnonIdent(v.Ident) { - self.s.pushErr(v.Token, LogMsg.DeclaredButNotUsed, v.Ident) - } - } - } - - fn checkAliases(mut self) { - for _, a in self.table.TypeAliases { - if !a.Used && !IsIgnoreIdent(a.Ident) && !IsAnonIdent(a.Ident) { - self.s.pushErr(a.Token, LogMsg.DeclaredButNotUsed, a.Ident) - } - } - } - - // Checks scope tree. - fn check(mut &self, mut &tree: &ScopeTree, mut &s: &Scope) { - s.Deferred = tree.Deferred - s.Unsafety = tree.Unsafety - - errors := len(self.s.errors) - - self.tree = tree - self.scope = s - - self.checkTree() - - // If we have new errors, don't check unused declarations. - if errors == len(self.s.errors) { - self.checkVars() - self.checkAliases() - - if self.isRoot() { - self.checkGotos() - self.checkLabels() - } - } - } - - fn newChildChecker(mut &self): &scopeChecker { - mut base := newScopeCheckerBase(self.s, nil) - base.parent = self - base.labels = self.labels - base.gotos = self.gotos - base.childIndex = self.childIndex + 1 - ret base - } + // Reports whether scope is unsafe. + fn isUnsafe(mut &self): bool { + mut scope := self + + iter: + if scope.scope.Unsafety { + ret true + } + + if scope.parent != nil { + scope = scope.parent + goto iter + } + + ret false + } + + // Reports scope is root. + // Accepts anonymous functions as root. + fn isRoot(self): bool { + ret self.parent == nil || self.owner != nil + } + + // Stop checking. + fn stop(mut self) { + self.i = -1 + } + + // Reports whether checking is stopped. + fn stopped(self): bool { + ret self.i == -1 + } + + // Reports scope is deferred. + fn isDeferred(mut &self): bool { + mut scope := self + + iter: + if scope.scope.Deferred { + ret true + } + + if scope.parent != nil { + scope = scope.parent + goto iter + } + + ret false + } + + // Push captured variable. + // It will append to all [captured] fields, + // because if child-scopes captures this variable, + // parent-scopes must be capture this variable too. + // Starts pushing from self to all parents. + // If any parent scope is not captures variable v, iteration will be break. + fn pushCaptured(mut &self, mut &v: &Var) { + mut sc := self + for { + if sc.captured != nil { + for _, cv in *sc.captured { + if cv == v { + goto exist + } + } + *sc.captured = append(*sc.captured, v) + exist: + } + if sc.parent == nil { + break + } + sc = sc.parent + if !isVarCaptured(sc, sc, v) { + break + } + } + } + + // Returns root scope. + // Accepts anonymous functions as root. + fn getRoot(mut &self): &scopeChecker { + mut root := self + for root.parent != nil && root.owner == nil { + root = root.parent + } + ret root + } + + // Returns hard root scope, owner always represents root function of this scope. + // Not accepts anonymous functions as root. + fn getHardRoot(mut &self): &scopeChecker { + mut root := self + for root.parent != nil { + root = root.parent + } + ret root + } + + // Like [Lookup.FindVar] but designed for local variables only. + fn findVar(mut self, ident: str): &Var { + const Reverse = true // Search reverse for correct shadowing. + const Binded = false // Local variables cannot be binded. + mut v := self.table.findVar(ident, Binded, Reverse) + if v != nil { + ret v + } + mut parent := self.parent + for parent != nil { + v = parent.table.findVar(ident, Binded, Reverse) + if v != nil { + ret v + } + parent = parent.parent + } + ret nil + } + + // Returns label by identifier. + // Returns nil if not exist any label in this identifier. + // Just lookups current scope. + fn findLabel(mut self, &ident: str): &Label { + for (_, mut st) in self.scope.Stmts { + match type st { + | &Label: + mut label := (&Label)(st) + if label.Ident == ident { + ret label + } + } + } + ret nil + } + + // Returns label by identifier. + // Returns nil if not exist any label in this identifier. + // Just lookups current scope. + fn findLabelScope(mut &self, &ident: str): &scopeLabel { + mut label := self.findLabelAll(ident) + if label != nil && label.scope == self { + ret label + } + + ret nil + } + + // Returns label by identifier. + // Returns nil if not exist any label in this identifier. + // Lookups all labels. + fn findLabelAll(mut self, &ident: str): &scopeLabel { + for (_, mut lbl) in *self.labels { + if lbl.label.Ident == ident { + ret lbl + } + } + ret nil + } + + // Reports this identifier duplicated in scope. + // The "self" parameter represents address of exception identifier. + // If founded identifier address equals to self, will be skipped. + fn isDuplicatedIdent(mut self, itself: uintptr, &ident: str): bool { + v := self.FindVar(ident, false) + if v != nil && uintptr(v) != itself { + if v.Scope == nil { // Ignore globals. + ret false + } + ret v.Scope == self.scope || !self.s.isFlag(SemaFlag.Shadowing) + } + + ta := self.FindTypeAlias(ident, false) + if ta != nil && uintptr(ta) != itself { + if ta.Scope == nil { // Ignore globals. + ret false + } + ret ta.Scope == self.tree || !self.s.isFlag(SemaFlag.Shadowing) + } + + ret false + } + + fn checkVarDecl(mut &self, mut decl: &VarDecl) { + mut v := buildVar(decl) + v.Scope = self.scope + + defer { + self.table.Vars = append(self.table.Vars, v) + self.scope.Stmts = append(self.scope.Stmts, v) + } + + if self.isDuplicatedIdent(uintptr(v), v.Ident) { + self.s.pushErr(v.Token, LogMsg.DuplicatedIdent, v.Ident) + self.s.pushSuggestion(LogMsg.RenameForAvoidDuplication) + self.stop() + ret + } + + self.s.checkVarDecl(v, self) + if !v.IsTypeInferred() && (v.Kind == nil || v.Kind.Kind == nil) { + ret + } + + self.s.evalVarValue(v, self) + if !v.IsInitialized() || v.Value.Data == nil { + // Skip checks if error ocurrs when evaluated expression, + // or unitiliazed variable. + ret + } + self.removeInteriorMutRisk(v.Value.Data) + self.s.checkVarValue(v) + } + + fn checkTypeAlias(mut &self, mut &ta: &TypeAlias) { + if self.isDuplicatedIdent(uintptr(ta), ta.Ident) { + self.s.pushErr(ta.Token, LogMsg.DuplicatedIdent, ta.Ident) + self.s.pushSuggestion(LogMsg.RenameForAvoidDuplication) + self.stop() + ret + } + self.s.checkTypeAliasDecl(ta, self) + self.table.TypeAliases = append(self.table.TypeAliases, ta) + + // Stop immediately if destination type is could not evaluated. + if ta.Kind.Kind == nil { + self.stop() + } + } + + fn checkTypeAliasDecl(mut &self, mut decl: &TypeAliasDecl) { + mut ta := buildTypeAlias(decl) + self.checkTypeAlias(ta) + } + + fn getChild(mut self): &Scope { + ret &Scope{ + Parent: self.scope, + } + } + + fn checkChildSsc(mut &self, mut &tree: &ScopeTree, mut &s: &Scope, mut &ssc: &scopeChecker) { + ssc.parent = self + ssc.check(tree, s) + } + + fn checkChildSc(mut &self, mut &tree: &ScopeTree, mut &ssc: &scopeChecker): &Scope { + mut s := self.getChild() + self.checkChildSsc(tree, s, ssc) + ret s + } + + fn checkChild(mut &self, mut &tree: &ScopeTree): &Scope { + mut ssc := self.newChildChecker() + ret self.checkChildSc(tree, ssc) + } + + fn checkAnonScope(mut &self, mut tree: &ScopeTree) { + mut s := self.checkChild(tree) + self.scope.Stmts = append(self.scope.Stmts, s) + } + + fn processErrorCall(mut &self, mut &m: &BuiltinErrorCallExprModel, err: &Token) { + if self.isDeferred() { + self.s.pushErr(err, LogMsg.ErrorInDeferred) + } + + mut root := self.getRoot() + if !root.owner.Decl.Exceptional { + self.s.pushErr(err, LogMsg.ErrorWithNonExceptional) + self.s.pushSuggestion(LogMsg.DeclareExceptional) + } + m.Func = root.owner + } + + fn checkExpr(mut &self, mut expr: &Expr) { + mut eval := self.s.eval(self) + eval.ignored = true + mut d := eval.evalExpr(expr) + if d == nil || d.Model == nil { + // Skip nil data, because evaluation failed and error documented (it should be) already. + // Skip nil modeled data, this return only caused by built-in functions and it should be safe. + ret + } + + match type d.Model { + | &BuiltinErrorCallExprModel: + mut m := (&BuiltinErrorCallExprModel)(d.Model) + self.processErrorCall(m, expr.Token) + self.scope.Stmts = append(self.scope.Stmts, d) + | &BackendEmitExprModel + | &BuiltinAppendCallExprModel + | &BuiltinOutCallExprModel + | &BuiltinOutlnCallExprModel + | &BuiltinPanicCallExprModel + | &BuiltinAssertCallExprModel + | &BuiltinCopyCallExprModel + | &BuiltinDeleteCallExprModel + | &FreeExprModel + | &FnCallExprModel: + self.scope.Stmts = append(self.scope.Stmts, d) + |: + self.s.pushErr(expr.Token, LogMsg.InvalidSyntax) + } + } + + fn checkIf(mut &self, mut i: &ast::If): &If { + mut s := self.checkChild(i.Scope) + + mut d := self.s.eval(self).evalExpr(i.Expr) + if d == nil { + ret nil + } + + mut prim := d.Kind.Prim() + if prim == nil || !prim.IsBool() { + self.s.pushErr(i.Expr.Token, LogMsg.IfRequireBoolExpr) + ret nil + } + + ret &If{ + Expr: d.Model, + Scope: s, + } + } + + fn checkElse(mut &self, mut e: &ast::Else): &Else { + ret &Else{ + Scope: self.checkChild(e.Scope), + } + } + + fn checkConditional(mut &self, mut conditional: &ast::Conditional) { + mut c := new(Conditional) + self.scope.Stmts = append(self.scope.Stmts, c) + + c.Elifs = make([]&If, 0, len(conditional.Tail) + 1) + + c.Elifs = append(c.Elifs, self.checkIf(conditional.Head)) + for (_, mut elif) in conditional.Tail { + c.Elifs = append(c.Elifs, self.checkIf(elif)) + } + + if conditional.Default != nil { + c.Default = self.checkElse(conditional.Default) + } + } + + fn checkIterScopeSsc(mut &self, it: uintptr, mut tree: &ScopeTree, mut &s: &Scope, mut ssc: &scopeChecker) { + ssc.it = it + self.checkChildSsc(tree, s, ssc) + } + + fn checkIterScopeSc(mut &self, it: uintptr, mut tree: &ScopeTree, mut ssc: &scopeChecker): &Scope { + mut scope := self.getChild() + self.checkIterScopeSsc(it, tree, scope, ssc) + ret scope + } + + fn checkIterScope(mut &self, it: uintptr, mut &tree: &ScopeTree): &Scope { + mut ssc := self.newChildChecker() + ret self.checkIterScopeSc(it, tree, ssc) + } + + fn checkInfIter(mut &self, mut &it: &Iter) { + mut kind := new(InfIter) + self.scope.Stmts = append(self.scope.Stmts, kind) + kind.Scope = self.checkIterScope(uintptr(kind), it.Scope) + } + + fn checkWhileIter(mut &self, mut &it: &Iter) { + mut wh := (&WhileKind)(it.Kind) + if wh.Expr == nil && wh.Next == nil { + self.checkInfIter(it) + ret + } + + mut kind := new(WhileIter) + self.scope.Stmts = append(self.scope.Stmts, kind) + kind.Scope = self.checkIterScope(uintptr(kind), it.Scope) + + if wh.Expr != nil { + mut d := self.s.eval(self).evalExpr(wh.Expr) + if d == nil { + ret + } + + prim := d.Kind.Prim() + if prim == nil { + self.s.pushErr(it.Token, LogMsg.IterWhileRequireBoolExpr) + ret + } + + if !prim.IsBool() { + self.s.pushErr(it.Token, LogMsg.IterWhileRequireBoolExpr) + ret + } + + kind.Expr = d.Model + } + + if wh.IsWhileNext() { + if !isValidAstStForNextSt(wh.Next) { + self.s.pushErr(wh.NextToken, LogMsg.InvalidStmtForNext) + ret + } + + n := len(self.scope.Stmts) + self.checkNode(wh.Next) + if n < len(self.scope.Stmts) { + mut st := self.scope.Stmts[n] + self.scope.Stmts = self.scope.Stmts[:n] // Remove trailing statements. + if !isValidStForNextSt(st) { + self.s.pushErr(wh.NextToken, LogMsg.InvalidStmtForNext) + } + kind.Next = st + } + } + } + + fn checkComptimeRangeIter(mut &self, mut &it: &Iter, mut &kind: &RangeIter, mut &d: &Data) { + if kind.KeyA != nil { + if !self.s.isFlag(SemaFlag.Shadowing) && self.isDuplicatedIdent(0, kind.KeyA.Ident) { + self.s.pushErr(kind.KeyA.Token, LogMsg.DuplicatedIdent, kind.KeyA.Ident) + self.s.pushSuggestion(LogMsg.RenameForAvoidDuplication) + } + } + if kind.KeyB != nil { + if !self.s.isFlag(SemaFlag.Shadowing) && self.isDuplicatedIdent(0, kind.KeyB.Ident) { + self.s.pushErr(kind.KeyB.Token, LogMsg.DuplicatedIdent, kind.KeyB.Ident) + self.s.pushSuggestion(LogMsg.RenameForAvoidDuplication) + } + } + + mut rang := (&RangeKind)(it.Kind) + makeComptimeRange(d) + if d.Decl { + self.s.pushErr(rang.Expr.Token, LogMsg.InvalidTypeForComptimeIter, d.Kind.Str()) + ret + } + + mut rc := rangeChecker{ + sc: self, + Kind: kind, + rang: rang, + d: d, + } + ok := rc.check() + if !ok { + ret + } + + mut comptime := d.Kind.comptimeRange() + comptime.kind.ready(kind.KeyA, kind.KeyB) + mut i := 0 + errors := len(self.s.errors) + for i < comptime.kind.len(); i++ { + mut ssc := self.newChildChecker() + mut scope := self.getChild() + if kind.KeyA != nil { + kind.KeyA.Scope = scope + ssc.table.Vars = append(ssc.table.Vars, kind.KeyA) + } + if kind.KeyB != nil { + kind.KeyB.Scope = scope + ssc.table.Vars = append(ssc.table.Vars, kind.KeyB) + } + comptime.kind.step(i, kind.KeyA, kind.KeyB) + self.checkChildSsc(it.Scope, scope, ssc) + if errors != len(self.s.errors) { + // Stop execution if new error occurred. + break + } + self.scope.Stmts = append(self.scope.Stmts, scope) + } + } + + fn checkRangeIter(mut &self, mut &it: &Iter) { + mut rang := (&RangeKind)(it.Kind) + + mut d := self.s.eval(self).evalExpr1(rang.Expr) + if d == nil { + ret + } + + mut kind := &RangeIter{ + Expr: d, + } + + if it.Comptime { + self.checkComptimeRangeIter(it, kind, d) + ret + } + if d.Kind.comptime() { + self.s.pushErr(rang.Expr.Token, LogMsg.ComptimeExprForRuntimeIteration) + self.s.pushSuggestion(LogMsg.DeclareComptimeForeach) + ret + } + + mut rc := rangeChecker{ + sc: self, + Kind: kind, + rang: rang, + d: d, + } + ok := rc.check() + if !ok { + ret + } + + self.scope.Stmts = append(self.scope.Stmts, kind) + + mut ssc := self.newChildChecker() + mut scope := self.getChild() + + if kind.KeyA != nil { + if !self.s.isFlag(SemaFlag.Shadowing) && self.isDuplicatedIdent(0, kind.KeyA.Ident) { + self.s.pushErr(kind.KeyA.Token, LogMsg.DuplicatedIdent, kind.KeyA.Ident) + self.s.pushSuggestion(LogMsg.RenameForAvoidDuplication) + } + kind.KeyA.Scope = scope + ssc.table.Vars = append(ssc.table.Vars, kind.KeyA) + } + + if kind.KeyB != nil { + if !self.s.isFlag(SemaFlag.Shadowing) && self.isDuplicatedIdent(0, kind.KeyB.Ident) { + self.s.pushErr(kind.KeyB.Token, LogMsg.DuplicatedIdent, kind.KeyB.Ident) + self.s.pushSuggestion(LogMsg.RenameForAvoidDuplication) + } + kind.KeyB.Scope = scope + ssc.table.Vars = append(ssc.table.Vars, kind.KeyB) + } + + self.checkIterScopeSsc(uintptr(kind), it.Scope, scope, ssc) + kind.Scope = scope + } + + fn checkIter(mut &self, mut it: &Iter) { + if it.IsInf() { + if it.Comptime { + self.s.pushErr(it.Token, LogMsg.InvalidComptimeIter) + ret + } + self.checkInfIter(it) + ret + } + + match type it.Kind { + | &WhileKind: + if it.Comptime { + self.s.pushErr(it.Token, LogMsg.InvalidComptimeIter) + ret + } + self.checkWhileIter(it) + | &RangeKind: + self.checkRangeIter(it) + |: + outln("error ") + } + } + + fn checkValidContLabel(mut &self, it: uintptr): bool { + mut scope := self + + iter: + if scope.it == it { + ret true + } + + if scope.parent != nil { + scope = scope.parent + goto iter + } + + ret false + } + + fn checkValidBreakLabel(mut &self, ptr: uintptr): bool { + mut scope := self + + iter: + if scope.it == ptr { + ret true + } + + if scope.cse != 0 { + mtch := unsafe { uintptr((*Case)(scope.cse).Owner) } + if mtch == ptr { + ret true + } + } + + if scope.parent != nil { + scope = scope.parent + goto iter + } + + ret false + } + + fn checkContValidScope(mut &self, c: &ast::ContSt): &ContSt { + if self.isDeferred() { + self.s.pushErr(c.Token, LogMsg.ContinueAtOutOfValidScope) + ret nil + } + + if c.Label != nil { + ret new(ContSt) + } + + mut scope := self + iter: + match { + | scope.it == 0 && scope.parent != nil && scope.owner == nil: + scope = scope.parent + goto iter + | scope.it != 0: + ret &ContSt{It: scope.it} + } + + self.s.pushErr(c.Token, LogMsg.ContinueAtOutOfValidScope) + ret nil + } + + fn checkCont(mut &self, c: &ast::ContSt) { + mut cont := self.checkContValidScope(c) + if cont == nil { + ret + } + + if c.Label != nil { // Label given. + mut label := findLabelParent(c.Label.Kind, self.parent) + if label == nil { + self.s.pushErr(c.Label, LogMsg.LabelNotExist, c.Label.Kind) + ret + } + + label.used = true + + if label.pos+1 >= len(label.scope.scope.Stmts) { + self.s.pushErr(c.Label, LogMsg.InvalidLabel, c.Label.Kind) + ret + } + + i := label.pos + 1 + if i >= len(label.scope.scope.Stmts) { + self.s.pushErr(c.Label, LogMsg.InvalidLabel) + } else { + mut st := label.scope.scope.Stmts[i] + match type st { + | &InfIter: + cont.It = uintptr((&InfIter)(st)) + | &RangeIter: + cont.It = uintptr((&RangeIter)(st)) + | &WhileIter: + cont.It = uintptr((&WhileIter)(st)) + |: + self.s.pushErr(c.Label, LogMsg.InvalidLabel, c.Label.Kind) + } + } + } + + if cont.It != 0 { + if !self.checkValidContLabel(cont.It) { + self.s.pushErr(c.Label, LogMsg.InvalidLabel, c.Label.Kind) + } + } + + self.scope.Stmts = append(self.scope.Stmts, cont) + } + + fn checkLabel(mut &self, mut l: &LabelSt) { + if self.findLabel(l.Ident) != nil { + self.s.pushErr(l.Token, LogMsg.LabelExist, l.Ident) + ret + } + + mut label := &Label{ + Ident: l.Ident, + } + + self.scope.Stmts = append(self.scope.Stmts, label) + *self.labels = append(*self.labels, &scopeLabel{ + token: l.Token, + label: label, + pos: len(self.scope.Stmts) - 1, + scope: self, + }) + } + + fn pushGoto(mut &self, mut gt: &ast::GotoSt) { + mut st := &GotoSt{ + Ident: gt.Label.Kind, + } + self.scope.Stmts = append(self.scope.Stmts, st) + + *self.gotos = append(*self.gotos, &scopeGoto{ + st: st, + gt: gt, + pos: len(self.scope.Stmts) - 1, + scope: self, + }) + } + + fn checkPostfix(mut &self, mut a: &AssignSt) { + if len(a.Left) > 1 { + self.s.pushErr(a.Setter, LogMsg.InvalidSyntax) + ret + } + + mut expr := a.Left[0].Expr + mut d := self.s.eval(self).evalExpr(expr) + if d == nil { + ret + } + + _ = checkAssign(self.s, d, nil, a.Setter) + + if d.Kind.Ptr() != nil { + mut ptr := d.Kind.Ptr() + if ptr.IsUnsafe() { + self.s.pushErr(a.Setter, LogMsg.OperatorNotForJuleType, a.Setter.Kind, d.Kind.Str()) + ret + } + } else { + if d.Kind.Prim() == nil || !types::IsNum(d.Kind.Prim().Kind) { + self.s.pushErr(a.Setter, LogMsg.OperatorNotForJuleType, a.Setter.Kind, d.Kind.Str()) + ret + } + } + + self.scope.Stmts = append(self.scope.Stmts, &Postfix{ + Expr: d.Model, + Op: a.Setter.Kind, + }) + } + + fn isNewAssignIdent(mut self, ident: str): bool { + if IsIgnoreIdent(ident) || ident == "" { + ret false + } + ret self.table.defByIdent(ident, false) == nil + } + + // Remove the interior mutability risk if the d represents a structure and + // this scope is owned by method which is owned by the relevant structure. + // In this case we should remove the interior mutability risk of data to allow copying. + // Otherwise assign analysis will complain and copy operation will not be allowed. + // + // See also documentation of the [sema.isMutRiskyStruct] method. + fn removeInteriorMutRisk(mut &self, mut &d: &Data) { + s := d.Kind.Struct() + if s == nil { + ret + } + root := self.getHardRoot() + if root.owner.Owner != s { + ret + } + // Mark data as mutable. + // Mutable data is not occurs mutability risk for analysis. + d.Mutable = true + } + + fn checkStructureAssignOp(mut &self, mut &s: &StructIns, mut &a: &AssignSt, mut &r: &Data): bool { + // This method adopted from [binaryEval.checkStructCommonOperatorCompatibility]. + // Should follow this method. + let mut overload: &FnIns = nil + match a.Setter.Id { + | TokenId.PlusEq: + overload = s.Operators.AddAssign + | TokenId.MinusEq: + overload = s.Operators.SubAssign + | TokenId.SolidusEq: + overload = s.Operators.DivAssign + | TokenId.StarEq: + overload = s.Operators.MulAssign + | TokenId.PercentEq: + overload = s.Operators.ModAssign + | TokenId.ShlEq: + overload = s.Operators.ShlAssign + | TokenId.ShrEq: + overload = s.Operators.ShrAssign + | TokenId.VlineEq: + overload = s.Operators.BitOrAssign + | TokenId.AmperEq: + overload = s.Operators.BitAndAssign + | TokenId.CaretEq: + overload = s.Operators.BitXorAssign + |: + self.s.pushErr(a.Setter, LogMsg.OperatorNotForJuleType, a.Setter.Kind, s.Str()) + ret false + } + + if overload == nil { + self.s.pushErr(a.Setter, LogMsg.OperatorNotForJuleType, a.Setter.Kind, s.Str()) + ret false + } + + mut p := overload.Params[1] + ret self.s.checkAssignType(p.Decl.Reference, p.Kind, r, a.Setter) + } + + fn checkSingleAssign(mut &self, mut &a: &AssignSt) { + let mut l: &Data = nil + + if !IsIgnoreIdent(a.Left[0].Ident) { + mut expr := a.Left[0].Expr + l = self.s.eval(self).evalExpr(expr) + if l == nil { + ret + } + } + + let mut eval: &Eval = nil + if l != nil { + eval = self.s.evalp(self, l.Kind) + } else { + eval = self.s.eval(self) + } + eval.unsafety = self.isUnsafe() + mut r := eval.evalExpr(a.Right) + if r == nil { + ret + } + + self.removeInteriorMutRisk(r) + + if l == nil { + if r.Kind.Void() { + self.s.pushErr(a.Right.Token, LogMsg.InvalidExpr) + } + self.scope.Stmts = append(self.scope.Stmts, r) + ret + } + + if !checkAssign(self.s, l, r, a.Setter) { + ret + } + + if r.Kind.Tup() != nil { + self.s.pushErr(a.Setter, LogMsg.MissingMultiAssignIdents) + ret + } + + mut lm := &OperandExprModel{ + Kind: l.Kind, + Model: l.Model, + } + mut rm := &OperandExprModel{ + Kind: r.Kind, + Model: r.Model, + } + self.scope.Stmts = append(self.scope.Stmts, &Assign{Left: lm, Right: rm, Op: a.Setter}) + + if a.Setter.Id == TokenId.Eq { + mut checker := assignTypeChecker{ + s: self.s, + dest: l.Kind, + d: r, + errorToken: a.Setter, + } + if checker.check() { + rm.Model = r.Model + lm.Model = l.Model + } + ret + } + mut strct := l.Kind.Struct() + if strct != nil { + self.checkStructureAssignOp(strct, a, r) + ret + } + id := a.Setter.Id + a.Setter.Id = removeEqFromOp(a.Setter.Id) + mut solver := binaryEval.new(eval, a.Setter) + solver.l, solver.r = l, r + _ = solver.evalOp() + a.Setter.Id = id + } + + fn processEndPartOfMultiAssign(mut self, mut &st: &MultiAssign, + mut &a: &AssignSt, mut &lexpr: &AssignLeft, mut &l: &Data, mut &r: &Data) { + if !lexpr.Reference && IsIgnoreIdent(lexpr.Ident) { + if r.Kind.Void() { + self.s.pushErr(a.Right.Token, LogMsg.InvalidExpr) + } + st.Left = append(st.Left, nil) + ret + } + + if a.Declarative && (lexpr.Reference || self.isNewAssignIdent(lexpr.Ident)) { + if self.isDuplicatedIdent(0, lexpr.Ident) { + self.s.pushErr(lexpr.Token, LogMsg.DuplicatedIdent, lexpr.Ident) + self.s.pushSuggestion(LogMsg.RenameForAvoidDuplication) + self.stop() + ret + } + if IsIgnoreIdent(lexpr.Ident) { + self.s.pushErr(lexpr.Token, LogMsg.IgnoreIdent) + } + + // Add new variable declaration statement. + mut v := &Var{ + Ident: lexpr.Ident, + Token: lexpr.Token, + Mutable: lexpr.Mutable, + Reference: lexpr.Reference, + Scope: self.scope, + Value: &Value{ + Expr: a.Right, + Data: r, + }, + } + self.s.checkVarValue(v) + st.Left = append(st.Left, &Data{ + Lvalue: !v.Constant, + Mutable: v.Mutable, + Reference: v.Reference, + Kind: v.Kind.Kind, + Model: v, + }) + st.Decls = append(st.Decls, v) + self.table.Vars = append(self.table.Vars, v) + ret + } + + if lexpr.Mutable || lexpr.Reference { + self.s.pushErr(lexpr.Token, LogMsg.DuplicatedIdent, lexpr.Ident) + self.s.pushSuggestion(LogMsg.RenameForAvoidDuplication) + } + + if !checkAssign(self.s, l, r, lexpr.Token) { + ret + } + + // Set reference false because this is normal assigment. + // So, we don't need to check reference assignment should using lvalue. + const Reference = false + self.s.checkValidityForInitExpr(l.Mutable, Reference, l.Kind, r, a.Setter) + + mut checker := assignTypeChecker{ + s: self.s, + dest: l.Kind, + d: r, + errorToken: a.Setter, + } + checker.check() + st.Left = append(st.Left, l) + } + + fn checkMultiAssign(mut &self, mut &a: &AssignSt) { + mut rd := self.s.eval(self).evalExpr(a.Right) + if rd == nil { + ret + } + mut right := getDatasFromTupleData(rd) + if len(right) == 1 { + match type right[0].Model { + | &IndexingExprModel: + mut iem := (&IndexingExprModel)(right[0].Model) + if iem.Expr.Kind.Map() != nil { // Is map lookup. + right = [ + &Data{Kind: iem.Expr.Kind.Map().Val}, + &Data{Kind: primBool}, + ] + } + } + } + + match { + | len(a.Left) > len(right): + self.s.pushErr(a.Setter, LogMsg.OverflowMultiAssignIdents) + ret + | len(a.Left) < len(right): + self.s.pushErr(a.Setter, LogMsg.MissingMultiAssignIdents) + ret + } + + mut st := &MultiAssign{ + Right: rd.Model, + } + for i in a.Left { + mut lexpr := a.Left[i] + let mut l: &Data = nil + if !IsIgnoreIdent(lexpr.Ident) && + (!a.Declarative || !self.isNewAssignIdent(lexpr.Ident)) { + l = self.s.eval(self).evalExpr(lexpr.Expr) + if l == nil { + continue + } + } + mut r := right[i] + self.removeInteriorMutRisk(r) + self.processEndPartOfMultiAssign(st, a, lexpr, l, r) + } + self.scope.Stmts = append(self.scope.Stmts, st) + } + + fn checkAssignSt(mut &self, mut a: &AssignSt) { + match { + | IsPostfixOp(a.Setter.Id): + self.checkPostfix(a) + | len(a.Left) == 1: + self.checkSingleAssign(a) + |: + self.checkMultiAssign(a) + } + } + + fn checkCaseScope(mut &self, &c: &Case, mut &tree: &ScopeTree): &Scope { + mut ssc := self.newChildChecker() + ssc.cse = uintptr(c) + ret self.checkChildSc(tree, ssc) + } + + fn checkCase(mut &self, mut m: &Match, i: int, mut c: &ast::Case, mut expr: &Data): &Case { + mut case := m.Cases[i] + case.Exprs = make([]&Data, 0, len(c.Exprs)) + mut constMatched := false + mut eval := self.s.eval(self) + for (_, mut e) in c.Exprs { + mut d := eval.evalExprKind(e.Kind) + if d == nil { + continue + } + + if m.TypeMatch { + // Match types. There is not need to check whether d.Decl is true. + // Parser always tries to build type declarations for type-match cases. + // So, d is should be type declaration already. + case.Exprs = append(case.Exprs, d) + if countMatchType(m, d.Kind) > 1 { + self.s.pushErr(e.Token, LogMsg.DuplicateMatchType, d.Kind.Str()) + } + if m.Comptime { + constMatched = constMatched || expr.Kind.Equal(d.Kind) + } else { + if expr.Kind.TypeEnum() != nil { + _ = self.s.checkTypeCompatibility(expr.Kind, d.Kind, e.Token) + } else { + trt := expr.Kind.Trait() + if trt != nil { + _ = self.s.checkTypeCompatibility(expr.Kind, d.Kind, e.Token) + } + } + } + continue + } + + if d.Decl { + self.s.pushErr(e.Token, LogMsg.DeclFoundInsteadExpr) + self.s.pushSuggestion(LogMsg.UseTypeMatch) + continue + } + + if m.Comptime { + if !d.IsConst() && d.Kind.comptimeTypeInfo() == nil { + self.s.pushErr(e.Token, LogMsg.ExprNotConst) + self.s.pushSuggestion(LogMsg.InvalidExprForConstMatch) + continue + } + if !constMatched { + if d.IsConst() { + constMatched = expr.IsConst() && d.Constant.Eq(*expr.Constant) + } else { + exprCti := expr.Kind.comptimeTypeInfo() + constMatched = exprCti != nil && d.Kind.comptimeTypeInfo().base.Equal(exprCti.base) + } + } + } + + case.Exprs = append(case.Exprs, d) + if !m.Comptime || + expr.Kind.comptimeTypeInfo() == nil || + d.Kind.comptimeTypeInfo() == nil { + mut checker := assignTypeChecker{ + s: self.s, + dest: expr.Kind, + d: d, + errorToken: e.Token, + } + checker.check() + } + } + if !m.Comptime || constMatched { + case.Scope = self.checkCaseScope(case, c.Scope) + } + ret case + } + + fn checkCases(mut &self, mut &m: &MatchCase, mut rm: &Match, mut expr: &Data) { + rm.Cases = make([]&Case, 0, len(m.Cases)) + for i in m.Cases { + mut case := &Case{ + Owner: rm, + } + if i > 0 { + rm.Cases[i-1].Next = case + } + rm.Cases = append(rm.Cases, case) + } + + if rm.Default != nil && len(m.Cases) > 0 { + rm.Cases[len(rm.Cases)-1].Next = rm.Default + } + + for (i, mut c) in m.Cases { + self.checkCase(rm, i, c, expr) + } + } + + fn checkDefault(mut &self, mut m: &Match, mut d: &ast::Else): &Case { + mut def := &Case{ + Owner: m, + } + def.Scope = self.checkCaseScope(def, d.Scope) + ret def + } + + fn checkComptimePanic(mut &self, mut callToken: &Token, &s: &Scope) { + if len(s.Stmts) != 1 { + ret + } + stmt := s.Stmts[0] + match type stmt { + | &Data: + d := (&Data)(stmt) + match type d.Model { + | &BuiltinPanicCallExprModel: + mut m := (&BuiltinPanicCallExprModel)(d.Model) + match type m.Expr { + | &Const: + c := (&Const)(m.Expr) + if !c.IsStr() { + break + } + if callToken == nil { + mut root := self.getHardRoot() + if root.calledFrom == nil { + callToken = m.Token + } else { + callToken = root.calledFrom + } + } + self.s.pushErr(callToken, LogMsg.ComptimePanic, c.ReadStr()) + self.stop() + } + } + } + } + + fn processConstMatch(mut &self, mut &tm: &Match, mut &m: &MatchCase) { + for (i, mut c) in tm.Cases { + if c.Scope != nil { + let mut token: &Token = nil + if !tm.TypeMatch && len(c.Scope.Stmts) > 0 { + token = m.Cases[i].Scope.Stmts[0].Token + } + self.checkComptimePanic(token, c.Scope) + tm.Default = c + tm.Cases = nil + ret + } + } + if m.Default != nil { + tm.Cases = nil + tm.Default = self.checkDefault(tm, m.Default) + if tm.Default != nil { + let mut token: &Token = nil + if !tm.TypeMatch { + token = m.Default.Scope.Stmts[0].Token + } + self.checkComptimePanic(token, tm.Default.Scope) + } + } else { + // Remove all cases, no success matching. + tm.Cases = nil + } + } + + fn checkTypeMatch(mut &self, mut &m: &MatchCase) { + mut d := self.s.eval(self).eval1(m.Expr) + if d == nil { + ret + } + + if m.Comptime { + mut cti := d.Kind.comptimeTypeInfo() + if cti == nil { + if !d.Decl { + self.s.pushErr(m.Expr.Token, LogMsg.InvalidComptimeTypeMatchExpr) + ret + } + } else { + d.Kind = cti.base + } + } else if d.Decl || !((d.Kind.Prim() != nil && d.Kind.Prim().IsAny()) || d.Kind.Trait() != nil || d.Kind.TypeEnum() != nil) { + self.s.pushErr(m.Expr.Token, LogMsg.TypeCaseHasNotValidExpr) + ret + } + + mut tm := &Match{ + TypeMatch: true, + Expr: d, + Comptime: m.Comptime, + } + + // Do not check default if comptime matching enabled. + // We do not know any case will be matched yet. + // The [self.processConstMatch] will check cases and if not exist + // any matching, will check default case if exist and handle it. + if !tm.Comptime && m.Default != nil { + tm.Default = self.checkDefault(tm, m.Default) + } + + self.checkCases(m, tm, d) + if tm.Comptime { + self.processConstMatch(tm, m) + } + self.scope.Stmts = append(self.scope.Stmts, tm) + } + + fn checkCommonMatch(mut &self, mut &m: &MatchCase) { + let mut d: &Data = nil + if m.Expr == nil { + d = &Data{ + Constant: Const.NewBool(true), + Kind: primBool, + } + d.Model = d.Constant + } else { + d = self.s.eval(self).evalExpr1(m.Expr) + if d == nil { + ret + } + } + + if m.Comptime { + if !canComptimeMatch(d) { + self.s.pushErr(m.Expr.Token, LogMsg.ExprNotConst) + self.s.pushSuggestion(LogMsg.InvalidExprForConstMatch) + ret + } + } else if d.Kind.comptime() { + self.s.pushErr(m.Expr.Token, LogMsg.ExprNotConst) + self.s.pushSuggestion(LogMsg.InvalidExprForConstMatch) + ret + } + + mut mc := &Match{ + Expr: d, + Comptime: m.Comptime, + } + + // Push into stmts here. Otherwise, labeled break statements and others + // will may log error(s) event semantic is good. + self.scope.Stmts = append(self.scope.Stmts, mc) + + // Do not check default if comptime matching enabled. + // We do not know any case will be matched yet. + // The [self.processConstMatch] will check cases and if not exist + // any matching, will check default case if exist and handle it. + if !mc.Comptime && m.Default != nil { + mc.Default = self.checkDefault(mc, m.Default) + } + + self.checkCases(m, mc, d) + if mc.Comptime { + self.processConstMatch(mc, m) + } + } + + fn checkMatch(mut &self, mut m: &MatchCase) { + if m.TypeMatch { + self.checkTypeMatch(m) + ret + } + self.checkCommonMatch(m) + } + + fn checkFall(mut &self, f: &ast::FallSt) { + if self.cse == 0 || + len(self.scope.Stmts)+1 < len(self.scope.Stmts) || + self.isDeferred() { + self.s.pushErr(f.Token, LogMsg.FallthroughWrongUse) + ret + } + + mut case := unsafe { (*Case)(self.cse) } + if unsafe { case.Owner.Comptime } { + self.s.pushErr(f.Token, LogMsg.ComptimeFallthrough) + ret + } else if unsafe { case.Next } == nil { + self.s.pushErr(f.Token, LogMsg.FallthroughIntoFinalCase) + self.s.pushSuggestion(LogMsg.RemoveFallthroughFromFinalCase) + ret + } + + self.scope.Stmts = append(self.scope.Stmts, &FallSt{ + DestCase: unsafe { uintptr(case.Next) }, + }) + } + + fn checkBreakWithLabel(mut &self, b: &ast::BreakSt): &BreakSt { + mut brk := self.checkPlainBreak(b) + if brk == nil { + ret nil + } + + // Set pointer to zero. + // Pointer will set by label. + brk.It = 0 + brk.Mtch = 0 + + mut label := findLabelParent(b.Label.Kind, self.parent) + if label == nil { + self.s.pushErr(b.Label, LogMsg.LabelNotExist, b.Label.Kind) + ret nil + } + + label.used = true + + if label.pos+1 >= len(label.scope.scope.Stmts) { + self.s.pushErr(b.Label, LogMsg.InvalidLabel, b.Label.Kind) + ret nil + } + + i := label.pos + 1 + if i >= len(label.scope.scope.Stmts) { + self.s.pushErr(b.Label, LogMsg.InvalidLabel, b.Label.Kind) + } else { + mut st := label.scope.scope.Stmts[i] + match type st { + | &InfIter: + brk.It = uintptr((&InfIter)(st)) + | &RangeIter: + brk.It = uintptr((&RangeIter)(st)) + | &WhileIter: + brk.It = uintptr((&WhileIter)(st)) + | &Match: + brk.Mtch = uintptr((&Match)(st)) + |: + self.s.pushErr(b.Label, LogMsg.InvalidLabel, b.Label.Kind) + } + } + + if brk.It != 0 { + if !self.checkValidBreakLabel(brk.It) { + self.s.pushErr(b.Label, LogMsg.InvalidLabel, b.Label.Kind) + } + } + + if brk.Mtch != 0 { + if !self.checkValidBreakLabel(brk.Mtch) { + self.s.pushErr(b.Label, LogMsg.InvalidLabel, b.Label.Kind) + } + } + + ret brk + } + + fn checkPlainBreak(mut &self, b: &ast::BreakSt): &BreakSt { + if self.isDeferred() { + self.s.pushErr(b.Token, LogMsg.BreakAtOutOfValidScope) + ret nil + } + + mut scope := self + iter: + match { + | scope.it == 0 && scope.cse == 0 && scope.parent != nil && scope.owner == nil: + scope = scope.parent + goto iter + | scope.it != 0: + ret &BreakSt{It: scope.it} + | scope.cse != 0: + ret &BreakSt{Mtch: unsafe { uintptr((*Case)(scope.cse).Owner) }} + } + + self.s.pushErr(b.Token, LogMsg.BreakAtOutOfValidScope) + ret nil + } + + fn checkBreak(mut &self, b: &ast::BreakSt) { + if b.Label != nil { // Label given. + mut brk := self.checkBreakWithLabel(b) + self.scope.Stmts = append(self.scope.Stmts, brk) + ret + } + + mut brk := self.checkPlainBreak(b) + self.scope.Stmts = append(self.scope.Stmts, brk) + } + + fn checkRet(mut &self, mut r: &ast::RetSt) { + if self.isDeferred() { + self.s.pushErr(r.Token, LogMsg.RetInDeferred) + } + + mut rt := &RetSt{ + Func: self.getRoot().owner, + } + self.scope.Stmts = append(self.scope.Stmts, rt) + + mut rtc := &retTypeChecker{ + sc: self, + f: rt.Func, + errorToken: r.Token, + } + ok := rtc.check(r.Expr) + if !ok { + ret + } + + if r.Expr != nil { + rt.Expr = rtc.model + } + } + + fn checkUseExpr(mut &self, ue: &UseExpr) { + if self.result == nil { + self.s.pushErr(ue.Token, LogMsg.UseExprOutOfScope) + ret + } + + if self.isDeferred() { + self.s.pushErr(ue.Token, LogMsg.UseExprInDeferred) + } + + if self.i+1 < len(self.tree.Stmts) { + self.s.pushErr(ue.Token, LogMsg.UseExprNotLast) + } + // Validated at end of scope's analysis. + } + + fn checkNode(mut &self, mut &node: StmtData) { + match type node { + | &ScopeTree: + self.checkAnonScope((&ScopeTree)(node)) + | &VarDecl: + self.checkVarDecl((&VarDecl)(node)) + | &TypeAliasDecl: + self.checkTypeAliasDecl((&TypeAliasDecl)(node)) + | &Expr: + self.checkExpr((&Expr)(node)) + | &ast::Conditional: + self.checkConditional((&ast::Conditional)(node)) + | &Iter: + self.checkIter((&Iter)(node)) + | &ast::ContSt: + self.checkCont((&ast::ContSt)(node)) + | &LabelSt: + self.checkLabel((&LabelSt)(node)) + | &ast::GotoSt: + self.pushGoto((&ast::GotoSt)(node)) + | &AssignSt: + self.checkAssignSt((&AssignSt)(node)) + | &MatchCase: + self.checkMatch((&MatchCase)(node)) + | &ast::FallSt: + self.checkFall((&ast::FallSt)(node)) + | &ast::BreakSt: + self.checkBreak((&ast::BreakSt)(node)) + | &ast::RetSt: + self.checkRet((&ast::RetSt)(node)) + | &UseExpr: + self.checkUseExpr((&UseExpr)(node)) + |: + outln("error ") + } + } + + fn checkResult(mut &self) { + mut stmt := self.tree.Stmts[len(self.tree.Stmts)-1] + match type stmt.Data { + | &UseExpr: + mut ue := (&UseExpr)(stmt.Data) + mut d := self.s.eval(self).evalExpr(ue.Expr) + if d == nil { + ret + } + self.scope.Stmts = append(self.scope.Stmts, d) + mut rtc := &retTypeChecker{ + sc: self, + errorToken: ue.Expr.Token, + types: self.result.Types(), + } + _ = rtc.check(ue.Expr) + | &Expr: + mut expr := (&Expr)(stmt.Data) + mut d := self.s.eval(self).evalExpr(expr) + if d == nil { + ret + } + match type d.Model { + | &BuiltinErrorCallExprModel: + mut m := (&BuiltinErrorCallExprModel)(d.Model) + self.processErrorCall(m, expr.Token) + self.scope.Stmts = append(self.scope.Stmts, d) + |: + ret + } + | &ast::GotoSt + | &ast::BreakSt + | &ast::ContSt + | &ast::RetSt: + self.checkNode(stmt.Data) + |: + self.checkNode(stmt.Data) + ret + } + + // Set result to nil, it is a mark for whether result is processed. + self.result = nil + } + + fn checkTree(mut &self) { + self.i = 0 + mut n := len(self.tree.Stmts) + if self.result != nil { + // Skip last statement if result is exist. + // Algorithm will check last statement for result. + // So, if you check last statement also here, it will duplicate. + n-- + } + for self.i < n; self.i++ { + mut stmt := self.tree.Stmts[self.i] + self.checkNode(stmt.Data) + if self.stopped() { + ret + } + } + if self.result != nil && len(self.tree.Stmts) != 0 { + self.checkResult() + } + } + + fn checkGoto(mut self, mut >: &scopeGoto, mut &label: &scopeLabel) { + mut gtsc := gt.scope + for gtsc.childIndex-1 > label.scope.childIndex { + gtsc = gtsc.parent + } + + mut n := 0 + + if gtsc.scope == label.scope.scope { + // Scopes are same and label at above, so safe. + if gt.pos > label.pos { + ret + } + + // Limit controlling to goto's position. + // Label and goto is in same scope. + n = gt.pos + } + + mut i := label.pos - 1 + + if n == 0 { + for j, stmt in label.scope.scope.Stmts { + // Break if position reached to goto's scope. + if stmtIsGotoScope(stmt, gtsc.scope) { + n = j + break + } + } + } + + for i >= n; i-- { + mut stmt := label.scope.scope.Stmts[i] + if stmtIsDef(stmt) { + self.s.pushErr(gt.gt.Token, LogMsg.GotoJumpsDeclarations, gt.gt.Label.Kind) + ret + } + } + } + + fn checkGotos(mut self) { + for (_, mut gt) in *self.gotos { + mut label := self.findLabelAll(gt.gt.Label.Kind) + if label == nil { + self.s.pushErr(gt.gt.Token, LogMsg.LabelNotExist, gt.gt.Label.Kind) + continue + } + gt.st.Label = label.label + label.used = true + self.checkGoto(gt, label) + } + } + + fn checkLabels(mut self) { + for _, l in *self.labels { + if !l.used { + self.s.pushErr(l.token, LogMsg.DeclaredButNotUsed, l.label.Ident) + } + } + } + + fn checkVars(mut self) { + for _, v in self.table.Vars { + if !v.Used && !v.Constant && !IsIgnoreIdent(v.Ident) && !IsAnonIdent(v.Ident) { + self.s.pushErr(v.Token, LogMsg.DeclaredButNotUsed, v.Ident) + } + } + } + + fn checkAliases(mut self) { + for _, a in self.table.TypeAliases { + if !a.Used && !IsIgnoreIdent(a.Ident) && !IsAnonIdent(a.Ident) { + self.s.pushErr(a.Token, LogMsg.DeclaredButNotUsed, a.Ident) + } + } + } + + // Checks scope tree. + fn check(mut &self, mut &tree: &ScopeTree, mut &s: &Scope) { + s.Deferred = tree.Deferred + s.Unsafety = tree.Unsafety + + errors := len(self.s.errors) + + self.tree = tree + self.scope = s + + self.checkTree() + + // If we have new errors, don't check unused declarations. + if errors == len(self.s.errors) { + self.checkVars() + self.checkAliases() + + if self.isRoot() { + self.checkGotos() + self.checkLabels() + } + } + } + + fn newChildChecker(mut &self): &scopeChecker { + mut base := newScopeCheckerBase(self.s, nil) + base.parent = self + base.labels = self.labels + base.gotos = self.gotos + base.childIndex = self.childIndex + 1 + ret base + } } fn removeEqFromOp(op: TokenId): TokenId { - match op { - | TokenId.PlusEq: - ret TokenId.Plus - | TokenId.MinusEq: - ret TokenId.Minus - | TokenId.StarEq: - ret TokenId.Star - | TokenId.SolidusEq: - ret TokenId.Solidus - | TokenId.PercentEq: - ret TokenId.Percent - | TokenId.ShlEq: - ret TokenId.Shl - | TokenId.ShrEq: - ret TokenId.Shr - | TokenId.CaretEq: - ret TokenId.Caret - | TokenId.AmperEq: - ret TokenId.Amper - | TokenId.VlineEq: - ret TokenId.Vline - |: - ret op - } + match op { + | TokenId.PlusEq: + ret TokenId.Plus + | TokenId.MinusEq: + ret TokenId.Minus + | TokenId.StarEq: + ret TokenId.Star + | TokenId.SolidusEq: + ret TokenId.Solidus + | TokenId.PercentEq: + ret TokenId.Percent + | TokenId.ShlEq: + ret TokenId.Shl + | TokenId.ShrEq: + ret TokenId.Shr + | TokenId.CaretEq: + ret TokenId.Caret + | TokenId.AmperEq: + ret TokenId.Amper + | TokenId.VlineEq: + ret TokenId.Vline + |: + ret op + } } // Makes data d as comptimeRange. // If type is not supported, d.Decl will be true. fn makeComptimeRange(mut &d: &Data) { - match { - | d.Kind.comptimeStructFields() != nil: - d.Kind = &TypeKind{Kind: &comptimeRange{d.Kind.comptimeStructFields()}} - | d.Kind.comptimeEnumFields() != nil: - d.Kind = &TypeKind{Kind: &comptimeRange{d.Kind.comptimeEnumFields()}} - | d.Kind.comptimeTypeInfos() != nil: - d.Kind = &TypeKind{Kind: &comptimeRange{d.Kind.comptimeTypeInfos()}} - | d.Kind.comptimeParams() != nil: - d.Kind = &TypeKind{Kind: &comptimeRange{d.Kind.comptimeParams()}} - | d.Kind.comptimeStatics() != nil: - d.Kind = &TypeKind{Kind: &comptimeRange{d.Kind.comptimeStatics()}} - | d.Kind.comptimeFiles() != nil: - d.Kind = &TypeKind{Kind: &comptimeRange{d.Kind.comptimeFiles()}} - |: - // Flag for failure. - d.Decl = true - } + match { + | d.Kind.comptimeStructFields() != nil: + d.Kind = &TypeKind{Kind: &comptimeRange{d.Kind.comptimeStructFields()}} + | d.Kind.comptimeEnumFields() != nil: + d.Kind = &TypeKind{Kind: &comptimeRange{d.Kind.comptimeEnumFields()}} + | d.Kind.comptimeTypeInfos() != nil: + d.Kind = &TypeKind{Kind: &comptimeRange{d.Kind.comptimeTypeInfos()}} + | d.Kind.comptimeParams() != nil: + d.Kind = &TypeKind{Kind: &comptimeRange{d.Kind.comptimeParams()}} + | d.Kind.comptimeStatics() != nil: + d.Kind = &TypeKind{Kind: &comptimeRange{d.Kind.comptimeStatics()}} + | d.Kind.comptimeFiles() != nil: + d.Kind = &TypeKind{Kind: &comptimeRange{d.Kind.comptimeFiles()}} + |: + // Flag for failure. + d.Decl = true + } } // Reports whether d can match at comptime. fn canComptimeMatch(mut &d: &Data): bool { - // Do not allow value if has unsupported type for type infer. - if !isGoodValueToInfer(d) { - ret false - } - ret d.IsConst() || d.Kind.comptimeTypeInfo() != nil + // Do not allow value if has unsupported type for type infer. + if !isGoodValueToInfer(d) { + ret false + } + ret d.IsConst() || d.Kind.comptimeTypeInfo() != nil } \ No newline at end of file diff --git a/std/jule/sema/sema.jule b/std/jule/sema/sema.jule index 3d93d380e..39e413cd4 100644 --- a/std/jule/sema/sema.jule +++ b/std/jule/sema/sema.jule @@ -11,2906 +11,2906 @@ use types for std::jule::types use strings for std::strings::{StrBuilder} fn isValidModelForRef(mut &m: ExprModel): bool { - match type m { - | &Var: - ret true - | &StructSubIdentExprModel: - mut model := (&StructSubIdentExprModel)(m) - ret model.Field != nil && isValidModelForRef(model.Expr.Model) - | &UnaryExprModel: - mut unary := (&UnaryExprModel)(m) - if unary.Op.Id != TokenId.Star { - ret false - } - // Return true because of raw pointer dereferencing is an Unsafe Jule feature. - if unary.Expr.Kind.Ptr() != nil { - ret true - } - // Dereferencing should be smart pointer, otherwise return false. - if unary.Expr.Kind.Sptr() == nil { - ret false - } - ret isValidModelForRef(unary.Expr.Model) - | &IndexingExprModel: - mut indexing := (&IndexingExprModel)(m) - ret isValidModelForRef(indexing.Expr.Model) - |: - ret false - } + match type m { + | &Var: + ret true + | &StructSubIdentExprModel: + mut model := (&StructSubIdentExprModel)(m) + ret model.Field != nil && isValidModelForRef(model.Expr.Model) + | &UnaryExprModel: + mut unary := (&UnaryExprModel)(m) + if unary.Op.Id != TokenId.Star { + ret false + } + // Return true because of raw pointer dereferencing is an Unsafe Jule feature. + if unary.Expr.Kind.Ptr() != nil { + ret true + } + // Dereferencing should be smart pointer, otherwise return false. + if unary.Expr.Kind.Sptr() == nil { + ret false + } + ret isValidModelForRef(unary.Expr.Model) + | &IndexingExprModel: + mut indexing := (&IndexingExprModel)(m) + ret isValidModelForRef(indexing.Expr.Model) + |: + ret false + } } fn compilerErr(&token: &Token, line: bool, fmt: LogMsg, args: ...any): Log { - mut log := Log{ - Kind: LogKind.Error, - Row: token.Row, - Column: token.Column, - Path: token.File.Path, - Text: Logf(fmt, args...), - } - if line { - log.Line = token.File.GetRow(token.Row) - } - ret log + mut log := Log{ + Kind: LogKind.Error, + Row: token.Row, + Column: token.Column, + Path: token.File.Path, + Text: Logf(fmt, args...), + } + if line { + log.Line = token.File.GetRow(token.Row) + } + ret log } fn impIsLookupable(&i: &ImportInfo, &ident: str): bool { - if i.Binded { - ret false - } - if !i.ImportAll { - if len(i.Selected) > 0 { - ret i.existIdent(ident) - } - } - ret i.ImportAll + if i.Binded { + ret false + } + if !i.ImportAll { + if len(i.Selected) > 0 { + ret i.existIdent(ident) + } + } + ret i.ImportAll } fn appendRetVars(mut &dest: []&Var, mut &f: &FnIns) { - if f.Decl.IsVoid() || f.Result == nil { - ret - } - - mut types := f.Types() - for (i, mut ident) in f.Decl.Result.Idents { - if IsIgnoreIdent(ident.Kind) || IsAnonIdent(ident.Kind) { - continue - } - dest = append(dest, &Var{ - Used: true, - Mutable: true, - Ident: ident.Kind, - Token: ident, - Scope: f.Scope, - Kind: &TypeSymbol{ - Kind: types[i], - }, - Value: &Value{ - Data: new(Data), - }, - RetOrder: i, - }) - } - if len(f.Decl.Result.Idents) == 1 && len(dest) == 1 { - dest[len(dest)-1].RetOrder = -1 - } + if f.Decl.IsVoid() || f.Result == nil { + ret + } + + mut types := f.Types() + for (i, mut ident) in f.Decl.Result.Idents { + if IsIgnoreIdent(ident.Kind) || IsAnonIdent(ident.Kind) { + continue + } + dest = append(dest, &Var{ + Used: true, + Mutable: true, + Ident: ident.Kind, + Token: ident, + Scope: f.Scope, + Kind: &TypeSymbol{ + Kind: types[i], + }, + Value: &Value{ + Data: new(Data), + }, + RetOrder: i, + }) + } + if len(f.Decl.Result.Idents) == 1 && len(dest) == 1 { + dest[len(dest)-1].RetOrder = -1 + } } fn appendParamVars(mut &dest: []&Var, mut &f: &FnIns) { - if len(f.Params) == 0 { - ret - } - - for (_, mut p) in f.Params { - if IsIgnoreIdent(p.Decl.Ident) || IsAnonIdent(p.Decl.Ident) { - continue - } - - mut v := &Var{ - Used: true, - Reference: p.Decl.Reference, - Mutable: p.Decl.Mutable, - Ident: p.Decl.Ident, - Token: p.Decl.Token, - Kind: new(TypeSymbol), - Scope: f.Scope, - Value: &Value{ - Data: new(Data), - }, - } - - match { - | p.Decl.IsSelf(): - v.Kind.Kind = &TypeKind{ - Variadic: false, - Kind: f.Owner, - } - v.Reference = !p.Decl.IsRef() - - if p.Decl.IsRef() { - v.Ident = v.Ident[1:] // Remove reference sign. - v.Kind.Kind.Kind = &Sptr{ - Elem: &TypeKind{ - BindIdent: v.Kind.Kind.BindIdent, - Kind: v.Kind.Kind.Kind, - }, - } - } - | p.Decl.Variadic: - v.Kind.Kind = &TypeKind{ - Variadic: false, - Kind: &Slc{ - Elem: &TypeKind{ - BindIdent: p.Kind.BindIdent, - Kind: p.Kind.Kind, - }, - }, - } - |: - v.Kind.Kind = p.Kind - } - - dest = append(dest, v) - } + if len(f.Params) == 0 { + ret + } + + for (_, mut p) in f.Params { + if IsIgnoreIdent(p.Decl.Ident) || IsAnonIdent(p.Decl.Ident) { + continue + } + + mut v := &Var{ + Used: true, + Reference: p.Decl.Reference, + Mutable: p.Decl.Mutable, + Ident: p.Decl.Ident, + Token: p.Decl.Token, + Kind: new(TypeSymbol), + Scope: f.Scope, + Value: &Value{ + Data: new(Data), + }, + } + + match { + | p.Decl.IsSelf(): + v.Kind.Kind = &TypeKind{ + Variadic: false, + Kind: f.Owner, + } + v.Reference = !p.Decl.IsRef() + + if p.Decl.IsRef() { + v.Ident = v.Ident[1:] // Remove reference sign. + v.Kind.Kind.Kind = &Sptr{ + Elem: &TypeKind{ + BindIdent: v.Kind.Kind.BindIdent, + Kind: v.Kind.Kind.Kind, + }, + } + } + | p.Decl.Variadic: + v.Kind.Kind = &TypeKind{ + Variadic: false, + Kind: &Slc{ + Elem: &TypeKind{ + BindIdent: p.Kind.BindIdent, + Kind: p.Kind.Kind, + }, + }, + } + |: + v.Kind.Kind = p.Kind + } + + dest = append(dest, v) + } } // Builds type aliases for generic types of scope. // See developer reference (1), and (2). fn appendGenericTypeAliases(mut &dest: []&TypeAlias, mut &f: &FnIns) { - mut size := len(f.Generics) - if f.Decl.Owner != nil { - size += len(f.Decl.Owner.Generics) - } - - if size == 0 { - ret - } - - for (i, mut g) in f.Generics { - mut decl := f.Decl.Generics[i] - dest = append(dest, &TypeAlias{ - Used: true, - Generic: true, - Scope: f.Decl.Scope, - Ident: decl.Ident, - Token: decl.Token, - Kind: &TypeSymbol{Kind: g.Kind}, - }) - } - - if f.Decl.Owner != nil { - mut owner := f.Owner - for (i, mut g) in owner.Generics { - mut decl := owner.Decl.Generics[i] - dest = append(dest, &TypeAlias{ - Used: true, - Generic: true, - Scope: f.Decl.Scope, - Ident: decl.Ident, - Token: decl.Token, - Kind: &TypeSymbol{Kind: g.Kind}, - }) - } - } + mut size := len(f.Generics) + if f.Decl.Owner != nil { + size += len(f.Decl.Owner.Generics) + } + + if size == 0 { + ret + } + + for (i, mut g) in f.Generics { + mut decl := f.Decl.Generics[i] + dest = append(dest, &TypeAlias{ + Used: true, + Generic: true, + Scope: f.Decl.Scope, + Ident: decl.Ident, + Token: decl.Token, + Kind: &TypeSymbol{Kind: g.Kind}, + }) + } + + if f.Decl.Owner != nil { + mut owner := f.Owner + for (i, mut g) in owner.Generics { + mut decl := owner.Decl.Generics[i] + dest = append(dest, &TypeAlias{ + Used: true, + Generic: true, + Scope: f.Decl.Scope, + Ident: decl.Ident, + Token: decl.Token, + Kind: &TypeSymbol{Kind: g.Kind}, + }) + } + } } fn findFile(mut &files: []&SymbolTable, &handler: &File): &SymbolTable { - for (_, mut fl) in files { - if fl.File == handler { - ret fl - } - } - ret nil + for (_, mut fl) in files { + if fl.File == handler { + ret fl + } + } + ret nil } unsafe fn pushSuggestion(mut log: *Log, fmt: LogMsg, args: ...any) { - log.Suggestion = Logf(fmt, args...) + log.Suggestion = Logf(fmt, args...) } struct commonSemaMeta { - comptimeTypeInfos: []&comptimeTypeInfo + comptimeTypeInfos: []&comptimeTypeInfo } impl commonSemaMeta { - fn pushComptimeTypeInfo(mut self, mut &t: &TypeKind): &comptimeTypeInfo { - for (_, mut t2) in self.comptimeTypeInfos { - if t2.base.BindIdent == t.BindIdent && t2.base.Equal(t) { - ret t2 - } - } - mut t1 := &comptimeTypeInfo{base: t} - self.comptimeTypeInfos = append(self.comptimeTypeInfos, t1) - ret t1 - } + fn pushComptimeTypeInfo(mut self, mut &t: &TypeKind): &comptimeTypeInfo { + for (_, mut t2) in self.comptimeTypeInfos { + if t2.base.BindIdent == t.BindIdent && t2.base.Equal(t) { + ret t2 + } + } + mut t1 := &comptimeTypeInfo{base: t} + self.comptimeTypeInfos = append(self.comptimeTypeInfos, t1) + ret t1 + } } // Semantic analyzer for tables. // Accepts tables as files of package. struct Sema { - errors: []Log - files: []&SymbolTable // Package files. - file: &SymbolTable // Current package file. - flags: SemaFlag - meta: &commonSemaMeta + errors: []Log + files: []&SymbolTable // Package files. + file: &SymbolTable // Current package file. + flags: SemaFlag + meta: &commonSemaMeta } impl Lookup for Sema { - // Returns imported package by selector. - // Returns nil reference if selector returns false for all packages. - // Returns nil reference if selector is nil. - // - // Lookups: - // - Current file's imported packages. - fn SelectPackage(mut self, selector: fn(&ImportInfo): bool): &ImportInfo { - ret self.file.SelectPackage(selector) - } - - // Returns variable by identifier and binded state. - // Returns nil reference if not exist any variable in this identifier. - // - // Lookups: - // - Package file's symbol table. - // - Current file's public denifes of imported packages. - fn FindVar(mut self, ident: str, binded: bool): &Var { - // Lookup package files. - mut v := findVarInPackage(self.files, ident, binded) - if v != nil { - ret v - } - - // If identifier is not public, it should be built-in or package define. - if !mod::IsPub(ident) { - ret nil - } - - // Lookup current file's public denifes of imported packages. - for (_, mut imp) in self.file.Imports { - if !impIsLookupable(imp, ident) { - continue - } - v = imp.FindVar(ident, binded) - if v != nil && self.isAccessibleDefine(v.Public, v.Token) { - ret v - } - } - - ret nil - } - - // Returns type alias by identifier and binded state. - // Returns nil reference if not exist any type alias in this identifier. - // - // Lookups: - // - Package file's symbol table. - // - Current file's public denifes of imported packages. - fn FindTypeAlias(mut self, ident: str, binded: bool): &TypeAlias { - // Lookup package files. - mut ta := findTypeAliasInPackage(self.files, ident, binded) - if ta != nil { - ret ta - } - - // If identifier is not public, it should be built-in or package define. - if !mod::IsPub(ident) { - ret nil - } - - // Lookup current file's public denifes of imported packages. - for (_, mut imp) in self.file.Imports { - if !impIsLookupable(imp, ident) { - continue - } - ta = imp.FindTypeAlias(ident, binded) - if ta != nil && self.isAccessibleDefine(ta.Public, ta.Token) { - ret ta - } - } - - ret nil - } - - // Returns struct by identifier and binded state. - // Returns nil reference if not exist any struct in this identifier. - // - // Lookups: - // - Package file's symbol table. - // - Current file's public denifes of imported packages. - fn FindStruct(mut self, ident: str, binded: bool): &Struct { - // Lookup package files. - mut s := findStructInPackage(self.files, ident, binded) - if s != nil { - ret s - } - - // If identifier is not public, it should be built-in or package define. - if !mod::IsPub(ident) { - ret nil - } - - // Lookup current file's public denifes of imported packages. - for (_, mut imp) in self.file.Imports { - if !impIsLookupable(imp, ident) { - continue - } - s = imp.FindStruct(ident, binded) - if s != nil && self.isAccessibleDefine(s.Public, s.Token) { - ret s - } - } - ret nil - } - - // Returns function by identifier and binded state. - // Returns nil reference if not exist any function in this identifier. - // - // Lookups: - // - Package file's symbol table. - // - Current file's public denifes of imported packages. - fn FindFn(mut self, ident: str, binded: bool): &Fn { - // Lookup package files. - mut f := findFnInPackage(self.files, ident, binded) - if f != nil { - ret f - } - - // If identifier is not public, it should be built-in or package define. - if !mod::IsPub(ident) { - ret nil - } - - // Lookup current file's public denifes of imported packages. - for (_, mut imp) in self.file.Imports { - if !impIsLookupable(imp, ident) { - continue - } - f = imp.FindFn(ident, binded) - if f != nil && self.isAccessibleDefine(f.Public, f.Token) { - ret f - } - } - - ret nil - } - - // Returns trait by identifier. - // Returns nil reference if not exist any trait in this identifier. - // - // Lookups: - // - Package file's symbol table. - // - Current file's public denifes of imported packages. - fn FindTrait(mut self, ident: str): &Trait { - // Lookup package files. - mut t := findTraitInPackage(self.files, ident) - if t != nil { - ret t - } - - // If identifier is not public, it should be built-in or package define. - if !mod::IsPub(ident) { - ret nil - } - - // Lookup current file's public denifes of imported packages. - for (_, mut imp) in self.file.Imports { - if !impIsLookupable(imp, ident) { - continue - } - t = imp.FindTrait(ident) - if t != nil && self.isAccessibleDefine(t.Public, t.Token) { - ret t - } - } - - ret nil - } - - // Returns enum by identifier. - // Returns nil reference if not exist any enum in this identifier. - // - // Lookups: - // - Package file's symbol table. - // - Current file's public denifes of imported packages. - fn FindEnum(mut self, ident: str): &Enum { - // Lookup package files. - mut e := findEnumInPackage(self.files, ident) - if e != nil { - ret e - } - - // If identifier is not public, it should be built-in or package define. - if !mod::IsPub(ident) { - ret nil - } - - // Lookup current file's public denifes of imported packages. - for (_, mut imp) in self.file.Imports { - if !impIsLookupable(imp, ident) { - continue - } - e = imp.FindEnum(ident) - if e != nil && self.isAccessibleDefine(e.Public, e.Token) { - ret e - } - } - - ret nil - } - - // Returns type enum by identifier. - // Returns nil reference if not exist any type enum in this identifier. - // - // Lookups: - // - Package file's symbol table. - // - Current file's public denifes of imported packages. - fn FindTypeEnum(mut self, ident: str): &TypeEnum { - // Lookup package files. - mut e := findTypeEnumInPackage(self.files, ident) - if e != nil { - ret e - } - - // If identifier is not public, it should be built-in or package define. - if !mod::IsPub(ident) { - ret nil - } - - // Lookup current file's public denifes of imported packages. - for (_, mut imp) in self.file.Imports { - if !impIsLookupable(imp, ident) { - continue - } - e = imp.FindTypeEnum(ident) - if e != nil && self.isAccessibleDefine(e.Public, e.Token) { - ret e - } - } - - ret nil - } + // Returns imported package by selector. + // Returns nil reference if selector returns false for all packages. + // Returns nil reference if selector is nil. + // + // Lookups: + // - Current file's imported packages. + fn SelectPackage(mut self, selector: fn(&ImportInfo): bool): &ImportInfo { + ret self.file.SelectPackage(selector) + } + + // Returns variable by identifier and binded state. + // Returns nil reference if not exist any variable in this identifier. + // + // Lookups: + // - Package file's symbol table. + // - Current file's public denifes of imported packages. + fn FindVar(mut self, ident: str, binded: bool): &Var { + // Lookup package files. + mut v := findVarInPackage(self.files, ident, binded) + if v != nil { + ret v + } + + // If identifier is not public, it should be built-in or package define. + if !mod::IsPub(ident) { + ret nil + } + + // Lookup current file's public denifes of imported packages. + for (_, mut imp) in self.file.Imports { + if !impIsLookupable(imp, ident) { + continue + } + v = imp.FindVar(ident, binded) + if v != nil && self.isAccessibleDefine(v.Public, v.Token) { + ret v + } + } + + ret nil + } + + // Returns type alias by identifier and binded state. + // Returns nil reference if not exist any type alias in this identifier. + // + // Lookups: + // - Package file's symbol table. + // - Current file's public denifes of imported packages. + fn FindTypeAlias(mut self, ident: str, binded: bool): &TypeAlias { + // Lookup package files. + mut ta := findTypeAliasInPackage(self.files, ident, binded) + if ta != nil { + ret ta + } + + // If identifier is not public, it should be built-in or package define. + if !mod::IsPub(ident) { + ret nil + } + + // Lookup current file's public denifes of imported packages. + for (_, mut imp) in self.file.Imports { + if !impIsLookupable(imp, ident) { + continue + } + ta = imp.FindTypeAlias(ident, binded) + if ta != nil && self.isAccessibleDefine(ta.Public, ta.Token) { + ret ta + } + } + + ret nil + } + + // Returns struct by identifier and binded state. + // Returns nil reference if not exist any struct in this identifier. + // + // Lookups: + // - Package file's symbol table. + // - Current file's public denifes of imported packages. + fn FindStruct(mut self, ident: str, binded: bool): &Struct { + // Lookup package files. + mut s := findStructInPackage(self.files, ident, binded) + if s != nil { + ret s + } + + // If identifier is not public, it should be built-in or package define. + if !mod::IsPub(ident) { + ret nil + } + + // Lookup current file's public denifes of imported packages. + for (_, mut imp) in self.file.Imports { + if !impIsLookupable(imp, ident) { + continue + } + s = imp.FindStruct(ident, binded) + if s != nil && self.isAccessibleDefine(s.Public, s.Token) { + ret s + } + } + ret nil + } + + // Returns function by identifier and binded state. + // Returns nil reference if not exist any function in this identifier. + // + // Lookups: + // - Package file's symbol table. + // - Current file's public denifes of imported packages. + fn FindFn(mut self, ident: str, binded: bool): &Fn { + // Lookup package files. + mut f := findFnInPackage(self.files, ident, binded) + if f != nil { + ret f + } + + // If identifier is not public, it should be built-in or package define. + if !mod::IsPub(ident) { + ret nil + } + + // Lookup current file's public denifes of imported packages. + for (_, mut imp) in self.file.Imports { + if !impIsLookupable(imp, ident) { + continue + } + f = imp.FindFn(ident, binded) + if f != nil && self.isAccessibleDefine(f.Public, f.Token) { + ret f + } + } + + ret nil + } + + // Returns trait by identifier. + // Returns nil reference if not exist any trait in this identifier. + // + // Lookups: + // - Package file's symbol table. + // - Current file's public denifes of imported packages. + fn FindTrait(mut self, ident: str): &Trait { + // Lookup package files. + mut t := findTraitInPackage(self.files, ident) + if t != nil { + ret t + } + + // If identifier is not public, it should be built-in or package define. + if !mod::IsPub(ident) { + ret nil + } + + // Lookup current file's public denifes of imported packages. + for (_, mut imp) in self.file.Imports { + if !impIsLookupable(imp, ident) { + continue + } + t = imp.FindTrait(ident) + if t != nil && self.isAccessibleDefine(t.Public, t.Token) { + ret t + } + } + + ret nil + } + + // Returns enum by identifier. + // Returns nil reference if not exist any enum in this identifier. + // + // Lookups: + // - Package file's symbol table. + // - Current file's public denifes of imported packages. + fn FindEnum(mut self, ident: str): &Enum { + // Lookup package files. + mut e := findEnumInPackage(self.files, ident) + if e != nil { + ret e + } + + // If identifier is not public, it should be built-in or package define. + if !mod::IsPub(ident) { + ret nil + } + + // Lookup current file's public denifes of imported packages. + for (_, mut imp) in self.file.Imports { + if !impIsLookupable(imp, ident) { + continue + } + e = imp.FindEnum(ident) + if e != nil && self.isAccessibleDefine(e.Public, e.Token) { + ret e + } + } + + ret nil + } + + // Returns type enum by identifier. + // Returns nil reference if not exist any type enum in this identifier. + // + // Lookups: + // - Package file's symbol table. + // - Current file's public denifes of imported packages. + fn FindTypeEnum(mut self, ident: str): &TypeEnum { + // Lookup package files. + mut e := findTypeEnumInPackage(self.files, ident) + if e != nil { + ret e + } + + // If identifier is not public, it should be built-in or package define. + if !mod::IsPub(ident) { + ret nil + } + + // Lookup current file's public denifes of imported packages. + for (_, mut imp) in self.file.Imports { + if !impIsLookupable(imp, ident) { + continue + } + e = imp.FindTypeEnum(ident) + if e != nil && self.isAccessibleDefine(e.Public, e.Token) { + ret e + } + } + + ret nil + } } impl Sema { - // Reports whether flags has given flag. - fn isFlag(self, flags: SemaFlag): bool { ret self.flags&flags == flags } - - fn setCurrentFile(mut self, mut f: &SymbolTable) { self.file = f } - - fn pushErr(mut self, token: &Token, fmt: LogMsg, args: ...any) { - self.errors = append(self.errors, compilerErr(token, true, fmt, args...)) - } - - // Push suggestion to last log. - fn pushSuggestion(mut self, fmt: LogMsg, args: ...any) { - unsafe { pushSuggestion(&self.errors[len(self.errors)-1], fmt, args...) } - } - - // Reports whether define is accessible in the current package. - fn isAccessibleDefine(self, public: bool, token: &Token): bool { - ret public || token.File == nil || self.file.File.Dir() == token.File.Dir() - } - - // Reports this identifier duplicated in package's global scope. - // The "self" parameter represents address of exception identifier. - // If founded identifier address equals to self, will be skipped. - fn isDuplicatedIdent(self, itself: uintptr, &ident: str, binded: bool): bool { - for _, f in self.files { - if f.isDuplicatedIdent(itself, ident, binded) { - ret true - } - - for _, imp in f.Imports { - for _, selected in imp.Selected { - if selected.Kind == ident { - ret true - } - } - } - } - ret false - } - - fn checkDirectives(mut &self, mut &d: []&ast::Directive, mut o: any) { - mut dc := directiveChecker{ - s: self, - d: unsafe { (&[]&ast::Directive)(&d) }, - o: o, - } - dc.check() - } - - fn checkGenericQuantity(mut self, required: int, given: int, token: &Token): (ok: bool) { - match { - | required == 0 && given > 0: - self.pushErr(token, LogMsg.NotHasGenerics) - ret false - | required > 0 && given == 0: - self.pushErr(token, LogMsg.HasGenerics) - ret false - | required < given: - self.pushErr(token, LogMsg.GenericsOverflow) - ret false - | required > given: - self.pushErr(token, LogMsg.MissingGenerics) - ret false - |: - ret true - } - } - - fn isDuplicatedImportSelection(self, itself: uintptr, &ident: str): bool { - for _, imp in self.file.Imports { - if uintptr(imp) == itself { - // Don't scan trailing imports. - break - } - if imp.existIdent(ident) { - ret true - } - } - ret false - } - - fn getImportDef(self, &ident: str, mut &imp: &ImportInfo): any { - if findPackageBuiltinDef(imp.LinkPath, ident) != nil { - ret true - } - for (_, mut f) in imp.Package.Files { - // Binded defines can't export. - const Binded = false - mut def := f.defByIdent(ident, Binded) - if def != nil { - ret def - } - } - ret nil - } - - fn checkImportSelection[T](mut self, &ident: &Token, &s: T): bool { - if !self.isAccessibleDefine(s.Public, s.Token) { - self.pushErr(ident, LogMsg.IdentIsNotAccessible, ident.Kind) - self.pushSuggestion(LogMsg.MakePubToAccess) - ret false - } - const Binded = false // Exported defines cannot be binded. - if defByIdentPackage(self.files, s.Ident, Binded) != nil { - self.pushErr(ident, LogMsg.SelectedImportExistInPackage, s.Ident) - ret false - } - ret true - } - - fn checkImportSelectedSelections(mut self, mut &imp: &ImportInfo): (ok: bool) { - ok = true - for _, ident in imp.Selected { - if ident.Kind == TokenKind.Self { - continue - } - - if self.isDuplicatedImportSelection(uintptr(imp), ident.Kind) { - self.pushErr(ident, LogMsg.DuplicatedIdent, ident.Kind) - self.pushSuggestion(LogMsg.RenameForAvoidDuplication) - ok = false - continue - } - - mut def := self.getImportDef(ident.Kind, imp) - match type def { - | bool: - // Pass, built-in. - continue - | &Var: - mut v := (&Var)(def) - ok = self.checkImportSelection(ident, v) && ok - | &TypeAlias: - mut ta := (&TypeAlias)(def) - ok = self.checkImportSelection(ident, ta) && ok - | &Struct: - mut s := (&Struct)(def) - ok = self.checkImportSelection(ident, s) && ok - | &Trait: - mut t := (&Trait)(def) - ok = self.checkImportSelection(ident, t) && ok - | &Enum: - mut e := (&Enum)(def) - ok = self.checkImportSelection(ident, e) && ok - | &TypeEnum: - mut e := (&TypeEnum)(def) - ok = self.checkImportSelection(ident, e) && ok - | &Fn: - mut f := (&Fn)(def) - ok = self.checkImportSelection(ident, f) && ok - |: - self.pushErr(ident, LogMsg.IdentNotExist, ident.Kind) - ok = false - continue - } - } - ret - } - - fn checkImportsAllSelectionsFromCollection[T](mut self, &s: []T, &et: &Token): bool { - mut ok := true - for _, d in s { - if d.Public { - ok = self.checkImportSelection(et, d) && ok - } - } - ret ok - } - - fn checkImportAllSelections(mut self, &imp: &ImportInfo): (ok: bool) { - ok = true - for _, file in imp.Package.Files { - ok = self.checkImportsAllSelectionsFromCollection(file.Vars, imp.Token) && ok - ok = self.checkImportsAllSelectionsFromCollection(file.TypeAliases, imp.Token) && ok - ok = self.checkImportsAllSelectionsFromCollection(file.Structs, imp.Token) && ok - ok = self.checkImportsAllSelectionsFromCollection(file.Funcs, imp.Token) && ok - ok = self.checkImportsAllSelectionsFromCollection(file.Traits, imp.Token) && ok - ok = self.checkImportsAllSelectionsFromCollection(file.Enums, imp.Token) && ok - ok = self.checkImportsAllSelectionsFromCollection(file.TypeEnums, imp.Token) && ok - } - ret - } - - fn checkImportSelections(mut self, mut &imp: &ImportInfo): (ok: bool) { - if len(imp.Selected) > 0 { - ret self.checkImportSelectedSelections(imp) - } else if imp.ImportAll { - ret self.checkImportAllSelections(imp) - } - ret true - } - - fn isUseAliasDuplication(mut self, &imp: &ImportInfo): bool { - for (_, mut imp2) in self.file.Imports { - if imp2 == imp { - break - } - if imp2.Alias == imp.Alias { - ret true - } - // Catch identifiers of other use declarations. - if imp2.Ident == imp2.LinkPath && imp2.Ident == imp.Alias { - ret true - } - } - ret false - } - - fn checkImport(mut self, mut &imp: &ImportInfo): bool { - if imp.Binded || len(imp.Package.Files) == 0 { - ret true - } - - // Check special cases for std::unsafe. - if imp.LinkPath == "std::unsafe" { - if imp.ImportAll || imp.Alias != "" || len(imp.Selected) > 0 { - self.pushErr(imp.Token, LogMsg.ExpectedPlainUseDecl, "use std::unsafe") - ret false - } - } - - if len(imp.Alias) != 0 { - if IsIgnoreIdent(imp.Alias) { - self.pushErr(imp.Token, LogMsg.IgnoreIdent) - } else if self.isUseAliasDuplication(imp) { - self.pushErr(imp.Token, LogMsg.DuplicatedUseAlias, imp.Alias) - self.pushSuggestion(LogMsg.RenameUseAliasAvoidDuplication) - } - } - - if !imp.Duplicate { - mut sema := &Sema{ - flags: self.flags, - meta: self.meta, - } - sema.check(imp.Package.Files) - if len(sema.errors) != 0 { - self.errors = append(self.errors, sema.errors...) - sema.errors = nil - ret false - } - } - ret self.checkImportSelections(imp) - } - - fn checkImports(mut self) { - for (_, mut file) in self.files { - self.setCurrentFile(file) - for (_, mut imp) in file.Imports { - ok := self.checkImport(imp) - // Break checking if package has error. - if !ok { - ret - } - } - } - } - - fn implFileImpls(mut &self) { - for (_, mut imp) in self.file.Impls { - self.implImpl(imp) - } - } - - fn implImpls(mut &self) { - for (_, mut file) in self.files { - self.setCurrentFile(file) - self.implFileImpls() - } - } - - fn checkEnums(mut &self) { - for (_, mut file) in self.files { - self.setCurrentFile(file) - match { - | !self.checkEnumDecls(): - | !self.checkTypeEnumDecls(): - } - } - } - - fn checkFileInherits(mut &self) { - for (_, mut t) in self.file.Traits { - ok := self._checkTraitDeclInherits(t) - if !ok { - ret - } - } - } - - fn checkInherits(mut &self) { - for (_, mut file) in self.files { - self.setCurrentFile(file) - self.checkFileInherits() - } - } - - fn typeChecker(mut &self, mut l: Lookup, mut generics: []&TypeAlias, - mut referencer: &referencer): typeChecker { - mut tc := typeChecker{ - s: self, - rootLookup: l, - lookup: l, - referencer: referencer, - useGenerics: generics, - } - match type l { - | &scopeChecker: - mut hard := (&scopeChecker)(l).getHardRoot() - tc.refers = hard.owner.Refers - } - // referencer's refs field is not nil if owner is type alias. - if referencer != nil && referencer.refs != nil { - // Set owner alias field of TypeChecker to collect generic dependencies. - // See developer reference (4). - match type referencer.owner { - | &TypeAlias: - tc.ownerAlias = (&TypeAlias)(referencer.owner) - } - } - ret tc - } - - // Builds type, builds result as kind and collects referred type aliases. - fn buildTypeWithRefers(mut &self, mut &t: &ast::TypeDecl, mut l: Lookup, - mut generics: []&TypeAlias, mut referencer: &referencer): &TypeKind { - ret self.typeChecker(l, generics, referencer).checkDecl(t) - } - - // Checks type, builds result as kind and collects referred type aliases. - // Skips already checked types. - fn checkTypeWithRefers(mut &self, mut &t: &TypeSymbol, mut l: Lookup, - mut generics: []&TypeAlias, mut referencer: &referencer): (ok: bool) { - if t.checked() { - ret true - } - t.Kind = self.buildTypeWithRefers(t.Decl, l, generics, referencer) - ret t.checked() - } - - fn constraintChecker(mut &self): &constraintChecker { - ret &constraintChecker{s: self} - } - - // Checks type and builds result as kind. - // Skips already checked types. - fn checkType(mut &self, mut &t: &TypeSymbol, mut l: Lookup): bool { - ret self.checkTypeWithRefers(t, l, nil, nil) - } - - // Builds type with type aliases for generics. - // Returns nil if error occur or failed. - fn buildTypeWithGenerics(mut &self, mut &t: &ast::TypeDecl, - mut generics: []&TypeAlias, mut refers: &ReferenceStack): &TypeKind { - mut tc := &typeChecker{ - s: self, - rootLookup: self, - lookup: self, - useGenerics: generics, - refers: refers, - } - ret tc.checkDecl(t) - } - - // Same as self.buildTypeWithGenerics but not uses any generics. - fn buildType(mut &self, mut &t: &ast::TypeDecl): &TypeKind { - ret self.buildTypeWithGenerics(t, nil, nil) - } - - // Select type with name selection. - fn selectType(mut &self, mut &t: &ast::TypeDecl): &TypeKind { - mut tc := &typeChecker{ - s: self, - rootLookup: self, - lookup: self, - selection: true, - } - ret tc.checkDecl(t) - } - - // Returns Eval instance for configuration with - // type prefix and checks var dependencies. - fn evalpd(mut &self, mut l: Lookup, mut p: &TypeKind, mut owner: &Var): &Eval { - mut e := &Eval{ - s: self, - lookup: l, - owner: owner, - } - match type l { - | &scopeChecker: - e.unsafety = (&scopeChecker)(l).isUnsafe() - } - e.prefix = p - ret e - } - - // Returns Eval instance for configuration with type prefix. - fn evalp(mut &self, mut l: Lookup, mut p: &TypeKind): &Eval { - ret self.evalpd(l, p, nil) - } - - // Returns Eval instance for configuration. - fn eval(mut &self, mut l: Lookup): &Eval { - ret self.evalp(l, nil) - } - - fn checkAssignType(mut &self, destIsRef: bool, mut &dest: &TypeKind, - mut &d: &Data, mut errorToken: &Token): bool { - if d.Decl { - self.pushErr(errorToken, LogMsg.InvalidExpr) - ret false - } - if destIsRef { - if !dest.Equal(d.Kind) { - self.pushErr(errorToken, LogMsg.IncompatibleTypes, dest.Str(), d.Kind.Str()) - ret false - } - } else { - mut atc := &assignTypeChecker{ - s: self, - errorToken: errorToken, - dest: dest, - d: d, - } - ok := atc.check() - if !ok { - ret false - } - } - - if !d.IsConst() || dest.Prim() == nil { - ret true - } - - mut kind := dest.Prim().Kind - - match { - | types::IsSigInt(kind): - d.Constant.SetI64(d.Constant.AsI64()) - | types::IsUnsigInt(kind): - d.Constant.SetU64(d.Constant.AsU64()) - | types::IsFloat(kind): - d.Constant.SetF64(d.Constant.AsF64()) - } - - ret true - } - - fn _checkTypeCompatibility(mut &self, mut &dest: &TypeKind, mut &src: &TypeKind, - mut errorToken: &Token): bool { - if src == nil { - ret false - } - // Tuple to single type, always fails. - if src.Tup() != nil { - ret false - } - mut tcc := typeCompatibilityChecker{ - s: self, - errorToken: errorToken, - dest: dest, - src: src, - } - ret tcc.check() - } - - fn checkTypeCompatibility(mut &self, mut &dest: &TypeKind, - mut &src: &TypeKind, mut &errorToken: &Token): bool { - if self._checkTypeCompatibility(dest, src, errorToken) { - ret true - } - self.pushErr(errorToken, LogMsg.IncompatibleTypes, dest.Str(), src.Str()) - ret false - } - - fn pushCompatiblityError(mut self, mut &dest: &TypeKind, mut &src: &Data, - mut &errorToken: &Token) { - if src.untyped { - match { - | src.Constant.IsI64(): - self.pushErr(errorToken, LogMsg.IncompatibleTypes, dest.Str(), "untyped integer") - ret - | src.Constant.IsU64(): - self.pushErr(errorToken, LogMsg.IncompatibleTypes, dest.Str(), "untyped unsigned integer") - ret - | src.Constant.IsF64(): - self.pushErr(errorToken, LogMsg.IncompatibleTypes, dest.Str(), "untyped float") - ret - } - } - self.pushErr(errorToken, LogMsg.IncompatibleTypes, dest.Str(), src.Kind.Str()) - } - - fn checkTypeCompatibility1(mut &self, mut &dest: &TypeKind, mut &src: &Data, - mut &errorToken: &Token): bool { - if self._checkTypeCompatibility(dest, src.Kind, errorToken) { - ret true - } - self.pushCompatiblityError(dest, src, errorToken) - ret false - } - - // Builds non-generic types but skips generic types. - // Builds generic identifiers as primitive type. - // - // Useful: - // - For non-generic type parsed string type kinds. - // - For checking non-generic types. - fn buildNonGenericTypeKind(mut &self, mut &ast: &ast::TypeDecl, - mut &generics: []&ast::GenericDecl, mut &ignored: []&TypeKind): &TypeKind { - mut tc := &typeChecker{ - s: self, - rootLookup: self, - lookup: self, - ignoreGenerics: generics, - ignoredGenerics: &ignored, - } - ret tc.checkDecl(ast) - } - - fn buildFnNonGenericTypeKinds(mut &self, mut &f: &FnIns, mut &ignored: []&TypeKind): (ok: bool) { - ok = true - let mut generics: []&ast::GenericDecl = nil - if f.Decl.IsMethod() { - generics = append(f.Decl.Generics, f.Decl.Owner.Generics...) - } else { - generics = f.Decl.Generics - } - - for (_, mut p) in f.Params { - if !p.Decl.IsSelf() { - p.Kind = self.buildNonGenericTypeKind(p.Decl.Kind.Decl, generics, ignored) - ok = ok && p.Kind != nil - } - } - if !f.Decl.IsVoid() { - f.Result = self.buildNonGenericTypeKind(f.Decl.Result.Kind.Decl, generics, ignored) - ok = ok && f.Result != nil - } - ret - } - - fn getTraitCheckFnKind(mut &self, mut &f: &Fn): &FnIns { - if len(f.Instances) == 1 { - ret f.Instances[0] - } - mut ins := f.instanceForce() - - mut tc := &typeChecker{ - s: self, - rootLookup: self, - lookup: self, - } - for (_, mut p) in ins.Params { - if !p.Decl.IsSelf() { - p.Kind = tc.checkDecl(p.Decl.Kind.Decl) - } - } - if !f.IsVoid() { - ins.Result = tc.checkDecl(f.Result.Kind.Decl) - } - - ret ins - } - - fn checkConstraintsFn(mut &self, mut &f: &FnIns, mut &et: &Token, mut exist: &FnIns): bool { - mut cc := self.constraintChecker() - cc.et = et - cc.fi = f - if exist != nil { - for (i, mut g) in exist.Generics { - f.Generics[i].Constraint = g.Constraint - } - } else { - cc.uniq = true - } - ret cc.check() - } - - fn checkConstraintsStruct(mut &self, mut &s: &StructIns, mut &et: &Token, mut exist: &StructIns): bool { - mut cc := self.constraintChecker() - cc.et = et - cc.si = s - if exist != nil { - for (i, mut g) in exist.Generics { - s.Generics[i].Constraint = g.Constraint - } - } else { - cc.uniq = true - } - ret cc.check() - } - - // Call algo in the function's native environment. - // Errors will be handled. - // Returns result of algo. - fn fnEnvironment(mut &self, mut &f: &FnIns, algo: fn(mut &sema: &Sema, mut &generics: []&TypeAlias): bool): bool { - mut sema := f.Decl.sema - mut old := f.Decl.sema.file - defer { f.Decl.sema.setCurrentFile(old) } - mut file := findFile(f.Decl.sema.files, f.Decl.Token.File) - if file != nil { - f.Decl.sema.setCurrentFile(file) - } - - mut size := len(f.Generics) - if f.Decl != nil && f.Decl.Owner != nil { - size += len(f.Decl.Owner.Generics) - } - - mut generics := make([]&TypeAlias, 0, size) - appendGenericTypeAliases(generics, f) - - ok := algo(sema, generics) - - if sema != self { - self.errors = append(self.errors, sema.errors...) - sema.errors = nil - } - - ret ok - } - - fn checkFnParamKind(mut &self, mut &p: &ParamIns) { - p.Kind.Variadic = p.Decl.Variadic - if p.Decl.Reference && !isValidForRef(p.Kind) { - self.pushErr(p.Decl.Token, LogMsg.RefPointsToInvalidType, p.Kind.Str()) - } - } - - fn reloadFnInsTypes(mut &self, mut f: &FnIns): bool { - if f.IsBuiltin() || f.IsAnon() { - ret true - } - ret self.fnEnvironment(f, fn(mut &sema: &Sema, mut &generics: []&TypeAlias): bool { - mut ok := true - for (_, mut p) in f.Params { - if p.Decl.IsSelf() { - if p.Decl.IsRef() { - p.Kind = &TypeKind{ - Kind: &Sptr{ - Elem: &TypeKind{ - Kind: f.Owner, - }, - }, - } - } else { - p.Kind = &TypeKind{Kind: f.Owner} - } - } else { - p.Kind = sema.buildTypeWithGenerics(p.Decl.Kind.Decl, generics, f.Refers) - if p.Kind != nil { - self.checkFnParamKind(p) - } else { - ok = false - } - } - } - if !f.Decl.IsVoid() { - f.Result = sema.buildTypeWithGenerics(f.Decl.Result.Kind.Decl, generics, f.Refers) - ok = f.Result != nil && ok - } - ret ok - }) - } - - fn checkRefValidityForInitExpr(mut &self, leftMut: bool, mut &d: &Data, mut &errorToken: &Token): bool { - if !isValidModelForRef(d.Model) { - self.pushErr(errorToken, LogMsg.RefAssignNonVar) - ret false - } - if leftMut && !d.Mutable { - self.pushErr(errorToken, LogMsg.MutRefPointsImmut) - ret false - } - ret true - } - - // Reports whether struct is risky for mutability. - // Designed for copy assignments. - // It will not check mutability risk of the internal mutable data or etc. - // It will check interior mutability risk of the new copy. - // Assumes the assigned memory is mutable. - fn isMutRiskyStruct(self, &s: &StructIns): bool { - for _, f in s.Fields { - // Inerior mutability enables to copy internal mutable data with safety. - // If field is interior mutable and their kind is mutable, - // check whether the field accessible. If field is not accessible, - // there is no problem, because no risk for mutability. - // - // For example: - // We have a Foo struct. The Foo struct have the x field which is - // interior mutable with mutable kind. So the following code is risky: - // - // a := Foo{} - // mut b := a - // - // The example code above will create new copy of variable a, which is - // instance of struct Foo. If the field x is accessible, the variable - // b can mutate it, since it is mutable and can access to field x. - // Therefore, copying interior mutable fields with mutable kind - // must be disallowed if field is accessible for safety reasons. - if f.Decl.Mutable && f.Kind.Mutable() && - self.isAccessibleDefine(f.Decl.Public, f.Decl.Token) { - ret true - } - } - ret false - } - - fn checkValidityForInitExpr(mut &self, leftMut: bool, leftRef: bool, - &leftKind: &TypeKind, mut &d: &Data, mut &errorToken: &Token): bool { - if leftMut && !d.Mutable { - // Check classical assignment mutability. - if d.Kind.Mutable() { - self.pushErr(errorToken, LogMsg.AssignNonMutToMut, d.Kind.Str()) - ret false - } - // Check interior mutability risk for the struct copy. - s := d.Kind.Struct() - if s != nil && self.isMutRiskyStruct(s) { - self.pushErr(errorToken, LogMsg.CopyWithMutableData, d.Kind.Str()) - ret false - } - } - if leftRef { - if !self.checkRefValidityForInitExpr(leftMut, d, errorToken) { - ret false - } - } - mut atc := &assignTypeChecker{ - s: self, - d: d, - errorToken: errorToken, - } - ret atc.checkValidity() - } - - fn checkTypeAliasDeclKind(mut &self, mut &ta: &TypeAlias, mut l: Lookup): (ok: bool) { - mut old := self.file - defer { - self.setCurrentFile(old) - } - if ta.Token != nil { - mut file := findFile(self.files, ta.Token.File) - if file != nil { - self.setCurrentFile(file) - } - } - ok = self.checkTypeWithRefers(ta.Kind, l, nil, &referencer{ - ident: ta.Ident, - owner: ta, - refs: &ta.Refers, - }) - if ok && ta.Kind.Kind.Arr() != nil && ta.Kind.Kind.Arr().Auto { - self.pushErr(ta.Kind.Decl.Token, LogMsg.ArrayAutoSized) - ok = false - } - ret - } - - fn checkTypeAliasDecl(mut &self, mut &ta: &TypeAlias, mut l: Lookup) { - if IsIgnoreIdent(ta.Ident) { - self.pushErr(ta.Token, LogMsg.IgnoreIdent) - } - self.checkTypeAliasDeclKind(ta, l) - } - - // Checks type alias declaration with duplicated identifiers. - fn checkTypeAliasDeclDup(mut &self, mut &ta: &TypeAlias) { - if IsIgnoreIdent(ta.Ident) { - self.pushErr(ta.Token, LogMsg.IgnoreIdent) - } - if self.isDuplicatedIdent(uintptr(ta), ta.Ident, ta.Binded) { - self.pushErr(ta.Token, LogMsg.DuplicatedIdent, ta.Ident) - self.pushSuggestion(LogMsg.RenameForAvoidDuplication) - } - self.checkTypeAliasDeclKind(ta, self) - } - - // Checks current package file's type alias declarations. - fn checkTypeAliasDecls(mut &self): (ok: bool) { - for (_, mut ta) in self.file.TypeAliases { - self.checkTypeAliasDeclDup(ta) - - // Break checking if type alias has error. - if len(self.errors) > 0 { - ret false - } - } - ret true - } - - fn checkEnumItemsDup[T](mut self, items: []T) { - for _, item in items { - if item.Ident == "" { - continue - } else if IsIgnoreIdent(item.Ident) { - self.pushErr(item.Token, LogMsg.IgnoreIdent) - } else { - for _, citem in items { - if item == citem { - break - } else if item.Ident == citem.Ident { - self.pushErr(item.Token, LogMsg.DuplicatedIdent, item.Ident) - self.pushSuggestion(LogMsg.RenameForAvoidDuplication) - break - } - } - } - } - } - - fn checkEnumItemsStr(mut &self, mut &e: &Enum) { - mut eval := self.eval(self) - for (_, mut item) in e.Items { - if item.AutoExpr() { - item.Value = &Value{ - Data: &Data{ - Constant: Const.NewStr(item.Ident), - }, - } - item.Value.Data.Model = item.Value.Data.Constant - } else { - mut d := eval.evalExpr(item.Value.Expr) - if d == nil { - continue - } - - if !d.IsConst() { - self.pushErr(item.Value.Expr.Token, LogMsg.ExprNotConst) - } - - _ = self.checkAssignType(false, e.Kind.Kind, d, item.Token) - item.Value.Data = d - } - } - } - - fn checkEnumItemInt[Int](mut &self, mut &eval: &Eval, mut &e: &Enum, &prim: &Prim, mut &item: &EnumItem, mut &n: Int) { - if item.AutoExpr() { - item.Value = &Value{ - Data: new(Data), - } - const match type Int { - | i64: - item.Value.Data.Constant = Const.NewI64(n) - | u64: - item.Value.Data.Constant = Const.NewU64(n) - |: - panic("unimplemented enum int type, this panic call should be unreachable") - } - item.Value.Data.Model = item.Value.Data.Constant - } else { - mut d := eval.evalExpr(item.Value.Expr) - if d == nil { - ret - } - if !d.IsConst() { - self.pushErr(item.Value.Expr.Token, LogMsg.ExprNotConst) - } - _ = self.checkAssignType(false, e.Kind.Kind, d, item.Token) - item.Value.Data = d - const match type Int { - | i64: - n = item.Value.Data.Constant.ReadI64() - | u64: - n = item.Value.Data.Constant.ReadU64() - |: - panic("unimplemented enum int type, this panic call should be unreachable") - } - } - } - - fn checkEnumItemsInt1[Int](mut &self, &prim: &Prim, mut &e: &Enum) { - mut max := Int(0) - const match type Int { - | i64: - max = types::MaxI(prim.Str()) - | u64: - max = types::MaxU(prim.Str()) - |: - panic("unimplemented enum int type, this panic call should be unrechable") - } - - mut eval := self.eval(self) - mut n := Int(0) - mut first := e.Items[0] - self.checkEnumItemInt(eval, e, prim, first, n) - if first.Value.Data != nil { - const match type Int { - | i64: - n = first.Value.Data.Constant.AsI64() - | u64: - n = first.Value.Data.Constant.AsU64() - |: - panic("unimplemented enum int type, this panic call should be unreachable") - } - } - for (_, mut item) in e.Items[1:] { - if item.AutoExpr() && n > 0 && max-n <= 0 { - self.pushErr(item.Token, LogMsg.OverflowLimits) - break - } - n++ - self.checkEnumItemInt(eval, e, prim, item, n) - } - } - - fn checkEnumItemsInt(mut &self, mut &e: &Enum) { - prim := e.Kind.Kind.Prim() - match { - | types::IsSigInt(prim.Kind): - self.checkEnumItemsInt1[i64](prim, e) - |: - self.checkEnumItemsInt1[u64](prim, e) - } - } - - fn checkEnumDecl(mut &self, mut &e: &Enum) { - if IsIgnoreIdent(e.Ident) { - self.pushErr(e.Token, LogMsg.IgnoreIdent) - } else if self.isDuplicatedIdent(uintptr(e), e.Ident, false) { - self.pushErr(e.Token, LogMsg.DuplicatedIdent, e.Ident) - self.pushSuggestion(LogMsg.RenameForAvoidDuplication) - } - - if len(e.Items) == 0 { - self.pushErr(e.Token, LogMsg.NoMemberInEnum, e.Ident) - ret - } - - self.checkEnumItemsDup[&EnumItem](e.Items) - - if e.Kind != nil { - if !self.checkType(e.Kind, self) { - ret - } - } else { - // Set to default type. - e.Kind = findBuiltinTypeAlias(PrimKind.Int).Kind - } - - mut t := e.Kind.Kind.Prim() - if t == nil { - self.pushErr(e.Token, LogMsg.InvalidTypeSource) - ret - } - - // Check items. - match { - | t.IsStr(): - self.checkEnumItemsStr(e) - | types::IsInt(t.Str()): - self.checkEnumItemsInt(e) - |: - self.pushErr(e.Token, LogMsg.InvalidTypeSource) - } - } - - fn checkTypeEnumDecl(mut &self, mut &e: &TypeEnum) { - if IsIgnoreIdent(e.Ident) { - self.pushErr(e.Token, LogMsg.IgnoreIdent) - } else if self.isDuplicatedIdent(uintptr(e), e.Ident, false) { - self.pushErr(e.Token, LogMsg.DuplicatedIdent, e.Ident) - self.pushSuggestion(LogMsg.RenameForAvoidDuplication) - } - - if len(e.Items) == 0 { - self.pushErr(e.Token, LogMsg.NoMemberInEnum, e.Ident) - ret - } - - self.checkEnumItemsDup[&TypeEnumItem](e.Items) - for (_, mut item) in e.Items { - if item.Kind == nil { - self.pushErr(item.Token, LogMsg.MissingType) - continue - } - ok := self.checkType(item.Kind, self) - if !ok { - continue - } - p := item.Kind.Kind.Prim() - if p != nil && p.IsAny() { - self.pushErr(item.Token, LogMsg.AnyWithTypeEnum) - } - } - if len(e.Items) == 1 { - mut item := e.Items[0] - tk := TypeKind{ - Kind: e, - } - if item.Kind.Kind != nil && item.Kind.Kind.Equal(unsafe { (&TypeKind)(&tk) }) { - self.pushErr(item.Token, LogMsg.IllegalCycleRefersItself, e.Str()) - } - } - } - - // Checks current package file's enum declarations. - fn checkEnumDecls(mut &self): (ok: bool) { - for (_, mut e) in self.file.Enums { - self.checkEnumDecl(e) - // Break checking if type alias has error. - if len(self.errors) > 0 { - ret false - } - } - ret true - } - - // Checks current package file's type enum declarations. - fn checkTypeEnumDecls(mut &self): (ok: bool) { - for (_, mut e) in self.file.TypeEnums { - self.checkTypeEnumDecl(e) - // Break checking if type alias has error. - if len(self.errors) > 0 { - ret false - } - } - ret true - } - - fn checkDeclGenerics(mut self, &generics: []&ast::GenericDecl): (ok: bool) { - ok = true - for i, g in generics { - if IsIgnoreIdent(g.Ident) { - self.pushErr(g.Token, LogMsg.IgnoreIdent) - ok = false - continue - } - - // Check duplications. - duplicationLookup: - for j, ct in generics { - match { - | j >= i: - // Skip current and following generics. - break duplicationLookup - | g.Ident == ct.Ident: - self.pushErr(g.Token, LogMsg.DuplicatedIdent, g.Ident) - self.pushSuggestion(LogMsg.RenameForAvoidDuplication) - ok = false - break duplicationLookup - } - } - } - ret - } - - fn checkFnDeclParamsDup(mut self, &f: &Fn): (ok: bool) { - ok = true - check: - for i, p in f.Params { - // Lookup in generics. - for _, g in f.Generics { - if p.Ident == g.Ident { - ok = false - self.pushErr(p.Token, LogMsg.DuplicatedIdent, p.Ident) - self.pushSuggestion(LogMsg.RenameForAvoidDuplication) - continue check - } - } - - paramsLookup: - for j, jp in f.Params { - match { - | j >= i: - // Skip current and following parameters. - break paramsLookup - | IsIgnoreIdent(p.Ident) - | IsIgnoreIdent(jp.Ident) - | IsAnonIdent(p.Ident) - | IsAnonIdent(jp.Ident): - // Skip anonymous parameters. - break paramsLookup - | p.Ident == jp.Ident: - ok = false - self.pushErr(p.Token, LogMsg.DuplicatedIdent, p.Ident) - self.pushSuggestion(LogMsg.RenameForAvoidDuplication) - continue check - } - } - } - ret - } - - fn checkFnDeclResultDup(mut self, &f: &Fn): (ok: bool) { - ok = true - if f.IsVoid() { - ret - } - - // Check duplications. - for i, v in f.Result.Idents { - if IsIgnoreIdent(v.Kind) || IsAnonIdent(v.Kind) { - continue // Skip anonymous return variables. - } - // Lookup in generics. - for _, g in f.Generics { - if v.Kind == g.Ident { - goto exist - } - } - // Lookup in parameters. - for _, p in f.Params { - if v.Kind == p.Ident { - goto exist - } - } - - // Lookup in return identifiers. - itself_lookup: - for j, jv in f.Result.Idents { - match { - | j >= i: - // Skip current and following identifiers. - break itself_lookup - | jv.Kind == v.Kind: - goto exist - } - } - continue - exist: - self.pushErr(v, LogMsg.DuplicatedIdent, v.Kind) - self.pushSuggestion(LogMsg.RenameForAvoidDuplication) - ok = false - } - - ret - } - - fn checkFnVariadicParam(mut &self, mut &f: &Fn): bool { - if len(f.Params) == 0 { - ret false - } - mut param := f.Params[len(f.Params)-1] - if param.Variadic && param.Reference { - self.pushErr(param.Token, LogMsg.VariadicReference) - } - ret true - } - - // Checks generics, parameters and return type. - // Not checks scope, and other things. - fn checkFnDeclPrototype(mut &self, mut &f: &Fn) { - if f.Exceptional && f.Binded { - self.pushErr(f.Token, LogMsg.BindedExceptional) - ret - } - - if f.Exceptional { - if f.IsEntryPoint() { - self.pushErr(f.Token, LogMsg.ExceptionalEntryPoint) - } else if f.IsInit() { - self.pushErr(f.Token, LogMsg.ExceptionalInit) - } - } - - match { - | !self.checkDeclGenerics(f.Generics): - | !self.checkFnDeclParamsDup(f): - | !self.checkFnDeclResultDup(f): - | !self.checkFnVariadicParam(f): - } - } - - fn catchTraitInheritCycle(mut &self, t1: &Trait, mut t2: &Trait, mut &message: StrBuilder): (ok: bool) { - ok = true - for (_, mut i) in t2.Inherits { - if i.Kind == nil { - continue - } - mut t3 := i.Kind.Trait() - if t1 == t3 { - self.pushCycleError(t2.Ident, t3.Ident, message) - ret false - } - if !self.catchTraitInheritCycle(t1, t3, message) { - self.pushCycleError(t2.Ident, t3.Ident, message) - ret false - } - } - ret - } - - fn _checkTraitDeclInherits(mut &self, mut &t: &Trait): (ok: bool) { - ok = true - for (i, mut it) in t.Inherits { - if !self.checkType(it, self) { - ok = false - continue - } - mut t2 := it.Kind.Trait() - if t2 == nil { - self.pushErr(it.Decl.Token, LogMsg.InheritedNonTrait, t.Ident, it.Kind.Str()) - ok = false - continue - } - for j, it2 in t.Inherits { - if j >= i { - break - } - if it2.Kind != nil && it.Kind.Equal(it2.Kind) { - self.pushErr(it.Decl.Token, LogMsg.DuplicatedIdent, t2.Ident) - ok = false - break - } - } - if t == t2 { - self.pushErr(it.Decl.Token, LogMsg.IllegalCycleRefersItself, t.Ident) - ok = false - } else { - mut message := StrBuilder.New(1 << 6) - ok = ok && self.catchTraitInheritCycle(t, t2, message) - if message.Len() > 0 { - mut errMsg := message.Str() - message.Clear() - self.pushCycleError(t.Ident, t2.Ident, message) - errMsg += message.Str() - self.pushErr(it.Decl.Token, LogMsg.IllegalCrossCycle, errMsg) - } - } - } - ret ok - } - - fn checkTraitDeclInherits(mut &self, mut &t: &Trait) { - for (i, mut it) in t.Inherits { - mut t1 := it.Kind.Trait() - for (j, mut it2) in t.Inherits { - if j == i { - continue - } - mut t2 := it2.Kind.Trait() - for (_, mut t1m) in t1.Methods { - mut t2m := t2.FindMethod(t1m.Ident) - if t2m == nil { - continue - } - t1f := self.getTraitCheckFnKind(t1m) - t2f := self.getTraitCheckFnKind(t2m) - if !t1f.equalTrait(t2f) { - self.pushErr(it.Decl.Token, LogMsg.IncompatibleInherit, - t.Ident, t2.Ident, t1f.GetKindStr(true), t2f.GetKindStr(true)) - ret - } - } - } - } - } - - fn checkTraitDeclMethod(mut &self, mut &f: &Fn) { - if IsIgnoreIdent(f.Ident) { - self.pushErr(f.Token, LogMsg.IgnoreIdent) - } else if IsAnonIdent(f.Ident) { - self.pushErr(f.Token, LogMsg.AnonFn) - } - f.sema = self - self.checkFnDeclPrototype(f) - mut ins := f.instance() - _ = self.reloadFnInsTypes(ins) - ins.reloaded = true - f.appendInstance(ins) - } - - fn checkTraitDeclMethods(mut &self, mut &t: &Trait) { - for (i, mut f) in t.Methods { - self.checkTraitDeclMethod(f) - - // Break checking if type alias has error. - if len(self.errors) > 0 { - ret - } - - if t.findMethodInherit(f.Ident) != nil { - self.pushErr(f.Token, LogMsg.DuplicatedIdent, f.Ident) - self.pushSuggestion(LogMsg.RenameForAvoidDuplication) - continue - } - - // Check duplications. - duplicateLookup: - for j, jf in t.Methods { - // NOTE: - // Ignore identifier checking is unnecessary here. - // Because ignore identifiers logs error. - // Errors breaks checking, so here is unreachable code for - // ignore identified methods. - match { - | j >= i: - // Skip current and following methods. - break duplicateLookup - | f.Ident == jf.Ident: - self.pushErr(f.Token, LogMsg.DuplicatedIdent, f.Ident) - self.pushSuggestion(LogMsg.RenameForAvoidDuplication) - break duplicateLookup - } - } - } - } - - fn checkTraitDecl(mut &self, mut &t: &Trait) { - if IsIgnoreIdent(t.Ident) { - self.pushErr(t.Token, LogMsg.IgnoreIdent) - } else if self.isDuplicatedIdent(uintptr(t), t.Ident, false) { - self.pushErr(t.Token, LogMsg.DuplicatedIdent, t.Ident) - self.pushSuggestion(LogMsg.RenameForAvoidDuplication) - } - - self.checkTraitDeclInherits(t) - self.checkTraitDeclMethods(t) - } - - // Checks current package file's trait declarations. - fn checkTraitDecls(mut &self): (ok: bool) { - for (_, mut t) in self.file.Traits { - self.checkTraitDecl(t) - // Break checking if type alias has error. - if len(self.errors) > 0 { - ret false - } - } - ret true - } - - fn checkTraitImplMethods(mut self, mut &base: &Trait, &ipl: &Impl): (ok: bool) { - ok = true - for _, f in ipl.Methods { - if base.FindMethod(f.Ident) == nil { - self.pushErr(f.Token, LogMsg.TraitHaveNotIdent, base.Ident, f.Ident) - ok = false - } - } - ret - } - - fn implToStruct(mut &self, mut &dest: &Struct, mut &ipl: &Impl): (ok: bool) { - ok = true - - // Methods. - for (_, mut f) in ipl.Methods { - if dest.FindMethod(f.Ident, f.Statically) != nil || dest.FindField(f.Ident) != nil { - self.pushErr(f.Token, LogMsg.StructAlreadyHaveIdent, dest.Ident, f.Ident) - ok = false - continue - } - - if len(dest.Generics) > 0 && len(f.Generics) > 0 { - for _, fg in f.Generics { - for _, dg in dest.Generics { - if fg.Ident == dg.Ident { - self.pushErr(fg.Token, LogMsg.MethodHasGenericWithSameIdent) - ok = false - } - } - } - } - - self.checkDirectives(f.Directives, f) - - f.sema = self - f.Owner = dest - dest.Methods = append(dest.Methods, f) - } - - for (_, mut v) in ipl.Statics { - const Static = true - if dest.FindMethod(v.Ident, Static) != nil || dest.FindStatic(v.Ident) != nil { - self.pushErr(v.Token, LogMsg.StructAlreadyHaveIdent, dest.Ident, v.Ident) - ok = false - continue - } - dest.Statics = append(dest.Statics, v) - } - ret - } - - // Implement trait to destination. - fn implTrait(mut &self, mut &decl: &Impl) { - mut base_t := self.selectType(decl.Base) - if base_t == nil { - ret - } - mut base := base_t.Trait() - if base == nil { - self.pushErr(decl.Base.Token, LogMsg.ImplInvalidBase, base_t.Str()) - self.pushSuggestion(LogMsg.ExpectedTrait) - ret - } - - mut destT := self.selectType(decl.Dest) - if destT == nil { - ret - } - mut destS := destT.Struct() - if destS == nil { - self.pushErr(decl.Dest.Token, LogMsg.ImplInvalidDest, destT.Str()) - self.pushSuggestion(LogMsg.ExpectedStruct) - ret - } - - mut dest := destS.Decl - - if dest.Token.File.Dir() != self.file.File.Dir() { - self.pushErr(decl.Dest.Token, LogMsg.IllegalImplOutOfPackage) - ret - } - - pushImplemented(base, dest) - pushImplements(dest, base) - - if len(decl.Statics) > 0 { - self.pushErr(decl.Statics[0].Token, LogMsg.TraitImplHasStatic) - } - - match { - | !self.checkTraitImplMethods(base, decl): - | !self.implToStruct(dest, decl): - } - } - - fn implStruct(mut &self, mut &decl: &Impl) { - mut destT := self.selectType(decl.Dest) - if destT == nil { - ret - } - mut destS := destT.Struct() - if destS == nil { - self.pushErr(decl.Dest.Token, LogMsg.ImplInvalidDest, destT.Str()) - self.pushSuggestion(LogMsg.ExpectedStruct) - ret - } - - mut dest := destS.Decl - if dest.Token.File.Dir() != self.file.File.Dir() { - self.pushErr(decl.Dest.Token, LogMsg.IllegalImplOutOfPackage) - ret - } - - match { - | !self.implToStruct(dest, decl): - } - } - - // Implement implementation. - fn implImpl(mut &self, mut &decl: &Impl) { - match { - | decl.IsTraitImpl(): - self.implTrait(decl) - | decl.IsStructImpl(): - self.implStruct(decl) - } - } - - // Checks variable declaration. - // Will not check duplicated identifiers. - fn checkVarDecl(mut &self, mut &decl: &Var, mut l: Lookup) { - if IsIgnoreIdent(decl.Ident) { - self.pushErr(decl.Token, LogMsg.IgnoreIdent) - } - - if decl.IsTypeInferred() { - if !decl.IsInitialized() { - self.pushErr(decl.Token, LogMsg.MissingValueForTypeInference) - } - } else { - _ = self.checkType(decl.Kind, l) - } - - if decl.Reference { - if decl.Constant { - self.pushErr(decl.Token, LogMsg.ConstRef) - } - if decl.Statically { - self.pushErr(decl.Token, LogMsg.StaticReference) - } - } - - if !decl.IsInitialized() { - if decl.Constant { - self.pushErr(decl.Token, LogMsg.ConstVarNotHaveExpr) - } - if decl.Statically { - self.pushErr(decl.Token, LogMsg.StaticNotHaveExpr) - } - if decl.Reference { - self.pushErr(decl.Token, LogMsg.RefNotInited) - } - } - } - - // Checks variable declaration for global scope. - // Checks duplicated identifiers by Sema. - fn checkGlobalVarDecl(mut &self, mut &decl: &Var) { - if self.isDuplicatedIdent(uintptr(decl), decl.Ident, decl.Binded) { - self.pushErr(decl.Token, LogMsg.DuplicatedIdent, decl.Ident) - self.pushSuggestion(LogMsg.RenameForAvoidDuplication) - } - if decl.Binded && decl.Constant { - self.pushErr(decl.Token, LogMsg.BindedVarIsConst) - } - if !decl.Binded && !decl.Constant && !decl.Statically { - self.pushErr(decl.Token, LogMsg.GlobalNotStatic) - self.pushSuggestion(LogMsg.UseStaticKeywordToDef) - } - self.checkDirectives(decl.Directives, decl) - self.checkVarDecl(decl, self) - } - - // Checks current package file's global variable declarations. - fn checkGlobalDecls(mut &self): (ok: bool) { - for (_, mut decl) in self.file.Vars { - self.checkGlobalVarDecl(decl) - // Break checking if type alias has error. - if len(self.errors) > 0 { - ret false - } - } - ret true - } - - fn checkStructTraitImpl(mut &self, mut &strct: &Struct, mut &trt: &Trait): (ok: bool) { - for (_, mut tf) in trt.Methods { - mut exist := false - mut sf := strct.FindMethod(tf.Ident, tf.Statically) - tfK := self.getTraitCheckFnKind(tf) - if sf != nil { - mut sfK := self.getTraitCheckFnKind(sf) - exist = tfK.equalTrait(sfK) - } - if exist { - d := findDirective(sf.Directives, Directive.Deprecated) - if d != nil { - self.pushErr(d.Tag, LogMsg.TraitImplDeprecated) - } - ok = false - } else { - const Ident = true - self.pushErr(strct.Token, LogMsg.NotImplTraitDef, trt.Ident, tfK.GetKindStr(Ident)) - ok = false - } - } - ret - } - - fn checkStructImpls(mut &self, mut &s: &Struct): (ok: bool) { - ok = true - for (_, mut trt) in s.Implements { - ok = self.checkStructTraitImpl(s, trt) && ok - } - ret ok - } - - fn checkStructFields(mut &self, mut &st: &Struct): (ok: bool) { - ok = true - for (_, mut f) in st.Fields { - f.Owner = st - for _, cf in st.Fields { - if f == cf { - break - } else if f.Ident == cf.Ident { - self.pushErr(f.Token, LogMsg.DuplicatedIdent, f.Ident) - self.pushSuggestion(LogMsg.RenameForAvoidDuplication) - ok = false - } - } - } - ret ok - } - - fn checkStructDecl(mut &self, mut &s: &Struct) { - if IsIgnoreIdent(s.Ident) { - self.pushErr(s.Token, LogMsg.IgnoreIdent) - } else if self.isDuplicatedIdent(uintptr(s), s.Ident, s.Binded) { - self.pushErr(s.Token, LogMsg.DuplicatedIdent, s.Ident) - self.pushSuggestion(LogMsg.RenameForAvoidDuplication) - } - - self.checkDirectives(s.Directives, s) - - match { - | !self.checkDeclGenerics(s.Generics): - | !self.checkStructFields(s): - | !self.checkStructImpls(s): - | !self.checkFuncDeclsBy(s.Methods): - } - } - - // Checks current package file's structure declarations. - fn checkStructDecls(mut &self): (ok: bool) { - for (_, mut s) in self.file.Structs { - self.checkStructDecl(s) - // Break checking if type alias has error. - if len(self.errors) > 0 { - ret false - } - } - ret true - } - - fn checkAnonFuncDecl(mut &self, mut &f: &Fn) { - f.sema = self - self.checkFnDeclPrototype(f) - } - - fn checkFuncDecl(mut &self, mut &f: &Fn) { - if IsIgnoreIdent(f.Ident) { - self.pushErr(f.Token, LogMsg.IgnoreIdent) - } else if f.IsAnon() { - self.pushErr(f.Token, LogMsg.AnonFn) - } - - self.checkDirectives(f.Directives, f) - self.checkAnonFuncDecl(f) - - if f.Owner == nil && self.isDuplicatedIdent(uintptr(f), f.Ident, f.Binded) { - if f.Ident == build::InitFn { - init := self.FindFn(build::InitFn, false) - if init != nil { - ret - } - } - self.pushErr(f.Token, LogMsg.DuplicatedIdent, f.Ident) - self.pushSuggestion(LogMsg.RenameForAvoidDuplication) - } - } - - fn checkFuncDeclsBy(mut &self, mut &funcs: []&Fn): bool { - for (_, mut f) in funcs { - self.checkFuncDecl(f) - // Break checking if error occurs. - if len(self.errors) > 0 { - ret false - } - } - ret true - } - - // Checks current package file's function declarations. - fn checkFuncDecls(mut &self): (ok: bool) { - ret self.checkFuncDeclsBy(self.file.Funcs) - } - - fn pushCycleError(self, &st1: str, &st2: str, mut &message: StrBuilder) { - const Padding = 7 - refersTo := Logf(LogMsg.RefersTo, st1, st2) - m := message.Str() - message.WriteStr(strings::Repeat(" ", Padding)) - message.WriteStr(refersTo) - message.WriteByte('\n') - message.WriteStr(m) - } - - fn checkCrossCycle(self, &st1: &Struct, &st2: &Struct, mut &message: StrBuilder): bool { - for _, u in st2.Uses { - if u == st1 { - self.pushCycleError(st2.Ident, u.Ident, message) - ret false - } - if !self.checkCrossCycle(st1, u, message) { - self.pushCycleError(st2.Ident, u.Ident, message) - ret false - } - } - ret true - } - - // Checks declarations of all package files. - // Breaks checking if checked file failed. - fn checkPackageDecls(mut &self) { - for (_, mut f) in self.files { - self.setCurrentFile(f) - if !self.checkTypeAliasDecls() { - ret - } - } - - for (_, mut f) in self.files { - self.setCurrentFile(f) - if !self.checkTraitDecls() { - ret - } - } - - for (_, mut f) in self.files { - self.setCurrentFile(f) - if !self.checkGlobalDecls() { - ret - } - } - - for (_, mut f) in self.files { - self.setCurrentFile(f) - match { - | !self.checkFuncDecls(): - | !self.checkStructDecls(): - |: - continue - } - ret - } - } - - fn checkDataForTypeInference(mut self, &d: &Data, &err_token: &Token) { - match { - | d.IsNil(): - self.pushErr(err_token, LogMsg.NilForTypeInference) - | d.IsVoid(): - self.pushErr(err_token, LogMsg.VoidForTypeInference) - | d.Kind.Variadic: - self.pushErr(err_token, LogMsg.InvalidExprForTypeInference) - } - } - - // Checks value of variable. - fn checkVarValue(mut &self, mut &v: &Var) { - if v.IsTypeInferred() { - // Build new TypeSymbol because auto-type symbols are nil. - v.Kind = &TypeSymbol{Kind: v.Value.Data.Kind} - - self.checkDataForTypeInference(v.Value.Data, v.Value.Expr.Token) - self.checkValidityForInitExpr( - v.Mutable, - v.Reference, - v.Kind.Kind, - v.Value.Data, - v.Value.Expr.Token) - } else { - mut arr := v.Kind.Kind.Arr() - if arr != nil { - if arr.Auto { - dataArr := v.Value.Data.Kind.Arr() - if dataArr != nil { - arr.N = dataArr.N - } - } - } - - if self.checkAssignType(v.Reference, v.Kind.Kind, v.Value.Data, v.Value.Expr.Token) { - self.checkValidityForInitExpr( - v.Mutable, - v.Reference, - v.Kind.Kind, - v.Value.Data, - v.Value.Expr.Token) - } - } - - if v.Reference && !isValidForRef(v.Kind.Kind) { - self.pushErr(v.Token, LogMsg.RefPointsToInvalidType, v.Kind.Kind.Str()) - } - - if v.Constant { - if !v.Value.Data.IsConst() && !v.Value.Data.Kind.comptime() { - self.pushErr(v.Value.Expr.Token, LogMsg.ExprNotConst) - } - } else { - v.Value.Data.Constant = nil - v.Value.Data.untyped = false - } - - // Remove kind for avoid more tuple-type errors. - if v.Kind.Kind.Tup() != nil { - v.Kind.Kind = nil - } - } - - // Evaluates value of variable if initialized. - fn evalVarValue(mut &self, mut &decl: &Var, mut l: Lookup) { - if !decl.IsInitialized() { - ret - } - - let mut eval: &Eval = nil - if decl.Kind != nil { - eval = self.evalpd(l, decl.Kind.Kind, decl) - } else { - eval = self.evalpd(l, nil, decl) - } - eval.immutable = !decl.Mutable - decl.Value.Data = eval.evalExpr(decl.Value.Expr) - } - - // Evaluateds value of variable and checks. - // Assumes the variable is global. - fn checkVar(mut &self, mut &decl: &Var, mut l: Lookup) { - self.evalVarValue(decl, l) - if decl.Value.Data == nil { - ret // Skip checks if error ocurrs. - } - self.checkVarValue(decl) - } - - // Checks current package file's global variables. - fn checkGlobals(mut &self) { - for (_, mut decl) in self.file.Vars { - if decl.Binded { - continue - } - if decl.IsInitialized() && decl.Value.Data == nil || - decl.IsTypeInferred() && decl.Kind.Kind == nil { - self.checkVar(decl, self) - } - } - } - - // Returns new FnIns as ready-to-analysis. - // If function already has a instance, returns existing instance. - // Returns nil if have a problem. - fn readyToCheckFn(mut &self, mut &s: &StructIns, mut &f: &Fn): &FnIns { - mut ins := f.instance() - if len(f.Instances) != 0 { - ret ins - } - ins.Owner = s - f.appendInstance(ins) - ins.reloaded = true - if self.reloadFnInsTypes(ins) { - ret ins - } - ret nil - } - - fn checkTypeMethod(mut &self, mut &s: &StructIns, mut &f: &Fn) { - // Generic instances are checked instantly. - if len(f.Generics) > 0 { - ret - } - mut ins := f.Instances[0] - if len(ins.Scope.Stmts) > 0 { - // Checked - ret - } - self.checkFnIns(ins) - } - - fn checkStructInsOp(mut &self, mut &s: &StructIns, mut &f: &Fn, p: fn(f: &Fn): bool): &FnIns { - if f == nil || len(f.Generics) > 0 || !p(f) { - ret nil - } - ret f.Instances[0] - } - - // Checks environment-dependent parts of structure instance. - // Which is contains fields and generic-type constraints. - // If generic instance will be check, errorToken should be passed. - fn checkStructEnv(mut &self, mut &s: &StructIns, mut errorToken: &Token): (ok: bool) { - mut tc := typeChecker{ - s: s.Decl.sema, - rootLookup: s.Decl.sema, - lookup: s.Decl.sema, - referencer: &referencer{ - ident: s.Decl.Ident, - owner: s.Decl, - }, - refers: s.Refers, - } - - if len(s.Generics) > 0 { - tc.useGenerics = make([]&TypeAlias, 0, len(s.Generics)) - for (i, mut g) in s.Generics { - mut decl := s.Decl.Generics[i] - tc.useGenerics = append(tc.useGenerics, &TypeAlias{ - Ident: decl.Ident, - Token: decl.Token, - Kind: &TypeSymbol{Kind: g.Kind}, - }) - } - } - - mut oldFile := self.file - defer { self.setCurrentFile(oldFile) } - - if self.file.File != s.Decl.Token.File { - mut file := findFile(self.files, s.Decl.Token.File) - if file != nil { - self.setCurrentFile(file) - } - } - - if len(s.Generics) > 0 { - mut cc := self.constraintChecker() - cc.et = errorToken - cc.si = s - cc.genericsA = tc.useGenerics - cc.uniq = true - if !cc.check() { - ret - } - } - - ok = true - - if len(s.Statics) > 0 { - mut n := len(self.errors) - self.files[0].TypeAliases = append(tc.useGenerics, self.files[0].TypeAliases...) - for (_, mut v) in s.Statics { - self.checkVarDecl(v, self) - self.checkVar(v, self) - ok = len(self.errors)-n == 0 && ok - } - self.files[0].TypeAliases = self.files[0].TypeAliases[len(tc.useGenerics):] - if !ok { - ret false - } - } - - mut eval := self.eval(self) - s.Comparable = !s.Decl.Binded - for (_, mut f) in s.Fields { - mut kind := tc.checkDecl(f.Decl.Kind.Decl) - ok = kind != nil && ok - if kind == nil { - if self != s.Decl.sema && len(s.Decl.sema.errors) > 0 { - self.errors = append(self.errors, s.Decl.sema.errors...) - s.Decl.sema.errors = nil - } - continue - } - f.Kind = kind - s.Mutable = s.Mutable || (!f.Decl.Mutable && f.Kind.Mutable()) - s.Comparable = s.Comparable && f.Kind.Comparable() - - // Skip this field if not has default value. - if f.Decl.Default == nil { - continue - } - eval.prefix = f.Kind - eval.field = f - f.Default = eval.evalExpr(f.Decl.Default) - - // Skip if eval returned nil. - // Relevant error(s) logged by eval. - if f.Default == nil { - continue - } - - const Reference = false // Fields cannot be reference. - _ = self.checkAssignType(Reference, f.Kind, f.Default, f.Decl.Default.Token) - } - ret - } - - fn precheckStructIns(mut &self, mut &s: &StructIns, mut errorToken: &Token): (ok: bool) { - ok = self.checkStructEnv(s, errorToken) - if !ok { - ret false - } - for (_, mut f) in s.Methods { - if len(f.Generics) == 0 { - if self.readyToCheckFn(s, f) == nil { - ret false - } - } - } - ret true - } - - fn checkStructIns(mut &self, mut &s: &StructIns) { - for (_, mut f) in s.Methods { - self.checkTypeMethod(s, f) - } - } - - fn checkTypeStruct(mut &self, mut &s: &Struct) { - if s.Binded { - ret - } - - // Generic instances are checked instantly. - if len(s.Generics) > 0 { - ret - } - - // NOTICE: - // Do not check zero instance case, operator overloading - // checker will create an instance if not exist. - for (_, mut ins) in s.Instances { - self.checkStructIns(ins) - } - } - - fn checkStructTypes(mut &self) { - for (_, mut s) in self.file.Structs { - self.checkTypeStruct(s) - } - } - - fn checkStructInsOperators(mut &self, mut s: &StructIns) { - for (_, mut m) in s.Methods { - match m.Ident { - | "Eq": - s.Operators.Eq = self.checkStructInsOp(s, m, FuncPattern.Eq) - s.Comparable = s.Operators.Eq != nil - | "Gt": - s.Operators.Gt = self.checkStructInsOp(s, m, FuncPattern.Gt) - | "GtEq": - s.Operators.GtEq = self.checkStructInsOp(s, m, FuncPattern.GtEq) - | "Lt": - s.Operators.Lt = self.checkStructInsOp(s, m, FuncPattern.Lt) - | "LtEq": - s.Operators.LtEq = self.checkStructInsOp(s, m, FuncPattern.LtEq) - | "Shl": - s.Operators.Shl = self.checkStructInsOp(s, m, FuncPattern.Shl) - | "Shr": - s.Operators.Shr = self.checkStructInsOp(s, m, FuncPattern.Shr) - | "Add": - s.Operators.Add = self.checkStructInsOp(s, m, FuncPattern.Add) - | "Sub": - s.Operators.Sub = self.checkStructInsOp(s, m, FuncPattern.Sub) - | "Div": - s.Operators.Div = self.checkStructInsOp(s, m, FuncPattern.Div) - | "Mul": - s.Operators.Mul = self.checkStructInsOp(s, m, FuncPattern.Mul) - | "Mod": - s.Operators.Mod = self.checkStructInsOp(s, m, FuncPattern.Mod) - | "BitAnd": - s.Operators.BitAnd = self.checkStructInsOp(s, m, FuncPattern.BitAnd) - | "BitOr": - s.Operators.BitOr = self.checkStructInsOp(s, m, FuncPattern.BitOr) - | "BitXor": - s.Operators.BitXor = self.checkStructInsOp(s, m, FuncPattern.BitXor) - | "Neg": - s.Operators.Neg = self.checkStructInsOp(s, m, FuncPattern.Neg) - | "Pos": - s.Operators.Pos = self.checkStructInsOp(s, m, FuncPattern.Pos) - | "BitNot": - s.Operators.BitNot = self.checkStructInsOp(s, m, FuncPattern.BitNot) - | "AddAssign": - s.Operators.AddAssign = self.checkStructInsOp(s, m, FuncPattern.AddAssign) - | "SubAssign": - s.Operators.SubAssign = self.checkStructInsOp(s, m, FuncPattern.SubAssign) - | "DivAssign": - s.Operators.DivAssign = self.checkStructInsOp(s, m, FuncPattern.DivAssign) - | "MulAssign": - s.Operators.MulAssign = self.checkStructInsOp(s, m, FuncPattern.MulAssign) - | "ModAssign": - s.Operators.ModAssign = self.checkStructInsOp(s, m, FuncPattern.ModAssign) - | "ShlAssign": - s.Operators.ShlAssign = self.checkStructInsOp(s, m, FuncPattern.ShlAssign) - | "ShrAssign": - s.Operators.ShrAssign = self.checkStructInsOp(s, m, FuncPattern.ShrAssign) - | "BitOrAssign": - s.Operators.BitOrAssign = self.checkStructInsOp(s, m, FuncPattern.BitOrAssign) - | "BitAndAssign": - s.Operators.BitAndAssign = self.checkStructInsOp(s, m, FuncPattern.BitAndAssign) - | "BitXorAssign": - s.Operators.BitXorAssign = self.checkStructInsOp(s, m, FuncPattern.BitXorAssign) - } - } - } - - fn precheckStructType(mut &self, mut &s: &Struct) { - if s.Binded { - ret - } - - // Generic instances are checked instantly. - if len(s.Generics) > 0 { - ret - } - - if len(s.Instances) == 0 { - mut ins := s.instance() - ins.Checked = true - s.appendInstance(ins) // Append instance before precheck. - self.precheckStructIns(ins, nil) - } - - self.checkStructInsOperators(s.Instances[0]) - } - - fn precheckStructTypes(mut &self) { - for (_, mut s) in self.file.Structs { - self.precheckStructType(s) - } - } - - fn checkRets(mut self, mut &f: &FnIns) { - if f.Decl.IsVoid() { - ret - } - mrc := missingRetChecker.new() - ok := mrc.check(f.Scope) - if !ok { - self.pushErr(f.Decl.Token, LogMsg.MissingRet) - } - } - - fn checkFnInsSc(mut self, mut &f: &FnIns, mut &sc: &scopeChecker) { - appendRetVars(sc.table.Vars, f) - appendParamVars(sc.table.Vars, f) - appendGenericTypeAliases(sc.table.TypeAliases, f) - - sc.check(f.Decl.Scope, f.Scope) - - // Check return statements if scopeChecker not forced to stop. - if !sc.stopped() { - self.checkRets(f) - } - } - - fn checkFnInsCaller(mut &self, mut &f: &FnIns, mut caller: &Token) { - if f.Decl.Binded { - ret - } - - mut old := f.Decl.sema.file - defer { f.Decl.sema.setCurrentFile(old) } - mut file := findFile(f.Decl.sema.files, f.Decl.Token.File) - if file != nil { - f.Decl.sema.setCurrentFile(file) - } - - mut sc := newScopeChecker(f.Decl.sema, f) - sc.calledFrom = caller - self.checkFnInsSc(f, sc) - - if f.Decl.sema != self { - self.errors = append(self.errors, f.Decl.sema.errors...) - f.Decl.sema.errors = nil - } - } - - fn checkFnIns(mut &self, mut &f: &FnIns) { - self.checkFnInsCaller(f, nil) - } - - fn checkFunc(mut &self, mut &f: &Fn) { - if f.Binded { - ret - } - - // Generic instances are checked instantly. - if len(f.Generics) > 0 { - ret - } - - for (_, mut ins) in f.Instances { - self.checkFnIns(ins) - } - } - - fn checkTestFn(mut self, mut &f: &FnIns) { - if f.Decl.Public { - self.pushErr(f.Decl.Token, LogMsg.PubTestFn) - self.pushSuggestion(LogMsg.RemovePubModifier) - ret - } - - if f.Decl.Unsafety || - !f.Decl.IsVoid() || - len(f.Decl.Generics) != 0 || - len(f.Params) != 1 || - f.Decl.Params[0].Mutable || - f.Decl.Params[0].Reference { - self.pushErr(f.Decl.Token, LogMsg.WrongTestFnDecl) - self.pushSuggestion(LogMsg.UseExpectedTestFnDecl) - ret - } - - mut sptr := f.Params[0].Kind.Sptr() - if sptr == nil { - self.pushErr(f.Decl.Token, LogMsg.WrongTestFnDecl) - self.pushSuggestion(LogMsg.UseExpectedTestFnDecl) - ret - } - - s := sptr.Elem.Struct() - if s == nil || !isStdPackage(s.Decl.Token.File.Path, "testing") { - self.pushErr(f.Decl.Token, LogMsg.WrongTestFnDecl) - self.pushSuggestion(LogMsg.UseExpectedTestFnDecl) - ret - } - } - - fn precheckFunc(mut &self, mut &f: &Fn) { - if f.Binded { - ret - } - - // Generic instances are checked instantly. - if len(f.Generics) > 0 { - ret - } - - if len(f.Instances) == 0 { - mut ins := f.instanceForce() - f.Instances = append(f.Instances, ins) - ok := self.reloadFnInsTypes(ins) - ins.reloaded = true - - if ok && hasDirective(f.Directives, Directive.Test) { - self.checkTestFn(ins) - } - } - } - - // Prechecks types of current package file's functions. - fn precheckFuncs(mut &self) { - for (_, mut decl) in self.file.Traits { - for (_, mut m) in decl.Methods { - self.precheckFunc(m) - } - } - for (_, mut decl) in self.file.Funcs { - self.precheckFunc(decl) - } - } - - // Checks types of current package file's functions. - fn checkFuncs(mut &self) { - for (_, mut decl) in self.file.Funcs { - self.checkFunc(decl) - } - } - - // Checks all types of all package files. - // Breaks checking if checked file failed. - fn checkPackageTypes(mut &self) { - for (_, mut f) in self.files { - self.setCurrentFile(f) - self.checkGlobals() - self.precheckFuncs() - // Check structures first, see developer reference (7). - // Check operators first, see developer reference (7.1), and (7.2). - self.precheckStructTypes() - } - if len(self.errors) > 0 { - ret - } - for (_, mut f) in self.files { - self.setCurrentFile(f) - self.checkFuncs() - self.checkStructTypes() - } - } - - fn setFileSemaFields(mut &self) { - for (_, mut f) in self.file.Funcs { - f.sema = self - } - for (_, mut st) in self.file.Structs { - st.sema = self - } - } - - fn setSemaFields(mut &self) { - for (_, mut file) in self.files { - self.setCurrentFile(file) - self.setFileSemaFields() - } - } - - fn check(mut &self, mut &files: []&SymbolTable) { - self.files = files - - self.checkImports() - if len(self.errors) != 0 { - ret - } - - self.setSemaFields() - - self.checkInherits() - if len(self.errors) != 0 { - ret - } - - self.implImpls() - if len(self.errors) != 0 { - ret - } - - // Check enums here. - // See developer reference (8). - self.checkEnums() - if len(self.errors) != 0 { - ret - } - - self.checkPackageDecls() - if len(self.errors) != 0 { - ret - } - - self.checkPackageTypes() - } + // Reports whether flags has given flag. + fn isFlag(self, flags: SemaFlag): bool { ret self.flags&flags == flags } + + fn setCurrentFile(mut self, mut f: &SymbolTable) { self.file = f } + + fn pushErr(mut self, token: &Token, fmt: LogMsg, args: ...any) { + self.errors = append(self.errors, compilerErr(token, true, fmt, args...)) + } + + // Push suggestion to last log. + fn pushSuggestion(mut self, fmt: LogMsg, args: ...any) { + unsafe { pushSuggestion(&self.errors[len(self.errors)-1], fmt, args...) } + } + + // Reports whether define is accessible in the current package. + fn isAccessibleDefine(self, public: bool, token: &Token): bool { + ret public || token.File == nil || self.file.File.Dir() == token.File.Dir() + } + + // Reports this identifier duplicated in package's global scope. + // The "self" parameter represents address of exception identifier. + // If founded identifier address equals to self, will be skipped. + fn isDuplicatedIdent(self, itself: uintptr, &ident: str, binded: bool): bool { + for _, f in self.files { + if f.isDuplicatedIdent(itself, ident, binded) { + ret true + } + + for _, imp in f.Imports { + for _, selected in imp.Selected { + if selected.Kind == ident { + ret true + } + } + } + } + ret false + } + + fn checkDirectives(mut &self, mut &d: []&ast::Directive, mut o: any) { + mut dc := directiveChecker{ + s: self, + d: unsafe { (&[]&ast::Directive)(&d) }, + o: o, + } + dc.check() + } + + fn checkGenericQuantity(mut self, required: int, given: int, token: &Token): (ok: bool) { + match { + | required == 0 && given > 0: + self.pushErr(token, LogMsg.NotHasGenerics) + ret false + | required > 0 && given == 0: + self.pushErr(token, LogMsg.HasGenerics) + ret false + | required < given: + self.pushErr(token, LogMsg.GenericsOverflow) + ret false + | required > given: + self.pushErr(token, LogMsg.MissingGenerics) + ret false + |: + ret true + } + } + + fn isDuplicatedImportSelection(self, itself: uintptr, &ident: str): bool { + for _, imp in self.file.Imports { + if uintptr(imp) == itself { + // Don't scan trailing imports. + break + } + if imp.existIdent(ident) { + ret true + } + } + ret false + } + + fn getImportDef(self, &ident: str, mut &imp: &ImportInfo): any { + if findPackageBuiltinDef(imp.LinkPath, ident) != nil { + ret true + } + for (_, mut f) in imp.Package.Files { + // Binded defines can't export. + const Binded = false + mut def := f.defByIdent(ident, Binded) + if def != nil { + ret def + } + } + ret nil + } + + fn checkImportSelection[T](mut self, &ident: &Token, &s: T): bool { + if !self.isAccessibleDefine(s.Public, s.Token) { + self.pushErr(ident, LogMsg.IdentIsNotAccessible, ident.Kind) + self.pushSuggestion(LogMsg.MakePubToAccess) + ret false + } + const Binded = false // Exported defines cannot be binded. + if defByIdentPackage(self.files, s.Ident, Binded) != nil { + self.pushErr(ident, LogMsg.SelectedImportExistInPackage, s.Ident) + ret false + } + ret true + } + + fn checkImportSelectedSelections(mut self, mut &imp: &ImportInfo): (ok: bool) { + ok = true + for _, ident in imp.Selected { + if ident.Kind == TokenKind.Self { + continue + } + + if self.isDuplicatedImportSelection(uintptr(imp), ident.Kind) { + self.pushErr(ident, LogMsg.DuplicatedIdent, ident.Kind) + self.pushSuggestion(LogMsg.RenameForAvoidDuplication) + ok = false + continue + } + + mut def := self.getImportDef(ident.Kind, imp) + match type def { + | bool: + // Pass, built-in. + continue + | &Var: + mut v := (&Var)(def) + ok = self.checkImportSelection(ident, v) && ok + | &TypeAlias: + mut ta := (&TypeAlias)(def) + ok = self.checkImportSelection(ident, ta) && ok + | &Struct: + mut s := (&Struct)(def) + ok = self.checkImportSelection(ident, s) && ok + | &Trait: + mut t := (&Trait)(def) + ok = self.checkImportSelection(ident, t) && ok + | &Enum: + mut e := (&Enum)(def) + ok = self.checkImportSelection(ident, e) && ok + | &TypeEnum: + mut e := (&TypeEnum)(def) + ok = self.checkImportSelection(ident, e) && ok + | &Fn: + mut f := (&Fn)(def) + ok = self.checkImportSelection(ident, f) && ok + |: + self.pushErr(ident, LogMsg.IdentNotExist, ident.Kind) + ok = false + continue + } + } + ret + } + + fn checkImportsAllSelectionsFromCollection[T](mut self, &s: []T, &et: &Token): bool { + mut ok := true + for _, d in s { + if d.Public { + ok = self.checkImportSelection(et, d) && ok + } + } + ret ok + } + + fn checkImportAllSelections(mut self, &imp: &ImportInfo): (ok: bool) { + ok = true + for _, file in imp.Package.Files { + ok = self.checkImportsAllSelectionsFromCollection(file.Vars, imp.Token) && ok + ok = self.checkImportsAllSelectionsFromCollection(file.TypeAliases, imp.Token) && ok + ok = self.checkImportsAllSelectionsFromCollection(file.Structs, imp.Token) && ok + ok = self.checkImportsAllSelectionsFromCollection(file.Funcs, imp.Token) && ok + ok = self.checkImportsAllSelectionsFromCollection(file.Traits, imp.Token) && ok + ok = self.checkImportsAllSelectionsFromCollection(file.Enums, imp.Token) && ok + ok = self.checkImportsAllSelectionsFromCollection(file.TypeEnums, imp.Token) && ok + } + ret + } + + fn checkImportSelections(mut self, mut &imp: &ImportInfo): (ok: bool) { + if len(imp.Selected) > 0 { + ret self.checkImportSelectedSelections(imp) + } else if imp.ImportAll { + ret self.checkImportAllSelections(imp) + } + ret true + } + + fn isUseAliasDuplication(mut self, &imp: &ImportInfo): bool { + for (_, mut imp2) in self.file.Imports { + if imp2 == imp { + break + } + if imp2.Alias == imp.Alias { + ret true + } + // Catch identifiers of other use declarations. + if imp2.Ident == imp2.LinkPath && imp2.Ident == imp.Alias { + ret true + } + } + ret false + } + + fn checkImport(mut self, mut &imp: &ImportInfo): bool { + if imp.Binded || len(imp.Package.Files) == 0 { + ret true + } + + // Check special cases for std::unsafe. + if imp.LinkPath == "std::unsafe" { + if imp.ImportAll || imp.Alias != "" || len(imp.Selected) > 0 { + self.pushErr(imp.Token, LogMsg.ExpectedPlainUseDecl, "use std::unsafe") + ret false + } + } + + if len(imp.Alias) != 0 { + if IsIgnoreIdent(imp.Alias) { + self.pushErr(imp.Token, LogMsg.IgnoreIdent) + } else if self.isUseAliasDuplication(imp) { + self.pushErr(imp.Token, LogMsg.DuplicatedUseAlias, imp.Alias) + self.pushSuggestion(LogMsg.RenameUseAliasAvoidDuplication) + } + } + + if !imp.Duplicate { + mut sema := &Sema{ + flags: self.flags, + meta: self.meta, + } + sema.check(imp.Package.Files) + if len(sema.errors) != 0 { + self.errors = append(self.errors, sema.errors...) + sema.errors = nil + ret false + } + } + ret self.checkImportSelections(imp) + } + + fn checkImports(mut self) { + for (_, mut file) in self.files { + self.setCurrentFile(file) + for (_, mut imp) in file.Imports { + ok := self.checkImport(imp) + // Break checking if package has error. + if !ok { + ret + } + } + } + } + + fn implFileImpls(mut &self) { + for (_, mut imp) in self.file.Impls { + self.implImpl(imp) + } + } + + fn implImpls(mut &self) { + for (_, mut file) in self.files { + self.setCurrentFile(file) + self.implFileImpls() + } + } + + fn checkEnums(mut &self) { + for (_, mut file) in self.files { + self.setCurrentFile(file) + match { + | !self.checkEnumDecls(): + | !self.checkTypeEnumDecls(): + } + } + } + + fn checkFileInherits(mut &self) { + for (_, mut t) in self.file.Traits { + ok := self._checkTraitDeclInherits(t) + if !ok { + ret + } + } + } + + fn checkInherits(mut &self) { + for (_, mut file) in self.files { + self.setCurrentFile(file) + self.checkFileInherits() + } + } + + fn typeChecker(mut &self, mut l: Lookup, mut generics: []&TypeAlias, + mut referencer: &referencer): typeChecker { + mut tc := typeChecker{ + s: self, + rootLookup: l, + lookup: l, + referencer: referencer, + useGenerics: generics, + } + match type l { + | &scopeChecker: + mut hard := (&scopeChecker)(l).getHardRoot() + tc.refers = hard.owner.Refers + } + // referencer's refs field is not nil if owner is type alias. + if referencer != nil && referencer.refs != nil { + // Set owner alias field of TypeChecker to collect generic dependencies. + // See developer reference (4). + match type referencer.owner { + | &TypeAlias: + tc.ownerAlias = (&TypeAlias)(referencer.owner) + } + } + ret tc + } + + // Builds type, builds result as kind and collects referred type aliases. + fn buildTypeWithRefers(mut &self, mut &t: &ast::TypeDecl, mut l: Lookup, + mut generics: []&TypeAlias, mut referencer: &referencer): &TypeKind { + ret self.typeChecker(l, generics, referencer).checkDecl(t) + } + + // Checks type, builds result as kind and collects referred type aliases. + // Skips already checked types. + fn checkTypeWithRefers(mut &self, mut &t: &TypeSymbol, mut l: Lookup, + mut generics: []&TypeAlias, mut referencer: &referencer): (ok: bool) { + if t.checked() { + ret true + } + t.Kind = self.buildTypeWithRefers(t.Decl, l, generics, referencer) + ret t.checked() + } + + fn constraintChecker(mut &self): &constraintChecker { + ret &constraintChecker{s: self} + } + + // Checks type and builds result as kind. + // Skips already checked types. + fn checkType(mut &self, mut &t: &TypeSymbol, mut l: Lookup): bool { + ret self.checkTypeWithRefers(t, l, nil, nil) + } + + // Builds type with type aliases for generics. + // Returns nil if error occur or failed. + fn buildTypeWithGenerics(mut &self, mut &t: &ast::TypeDecl, + mut generics: []&TypeAlias, mut refers: &ReferenceStack): &TypeKind { + mut tc := &typeChecker{ + s: self, + rootLookup: self, + lookup: self, + useGenerics: generics, + refers: refers, + } + ret tc.checkDecl(t) + } + + // Same as self.buildTypeWithGenerics but not uses any generics. + fn buildType(mut &self, mut &t: &ast::TypeDecl): &TypeKind { + ret self.buildTypeWithGenerics(t, nil, nil) + } + + // Select type with name selection. + fn selectType(mut &self, mut &t: &ast::TypeDecl): &TypeKind { + mut tc := &typeChecker{ + s: self, + rootLookup: self, + lookup: self, + selection: true, + } + ret tc.checkDecl(t) + } + + // Returns Eval instance for configuration with + // type prefix and checks var dependencies. + fn evalpd(mut &self, mut l: Lookup, mut p: &TypeKind, mut owner: &Var): &Eval { + mut e := &Eval{ + s: self, + lookup: l, + owner: owner, + } + match type l { + | &scopeChecker: + e.unsafety = (&scopeChecker)(l).isUnsafe() + } + e.prefix = p + ret e + } + + // Returns Eval instance for configuration with type prefix. + fn evalp(mut &self, mut l: Lookup, mut p: &TypeKind): &Eval { + ret self.evalpd(l, p, nil) + } + + // Returns Eval instance for configuration. + fn eval(mut &self, mut l: Lookup): &Eval { + ret self.evalp(l, nil) + } + + fn checkAssignType(mut &self, destIsRef: bool, mut &dest: &TypeKind, + mut &d: &Data, mut errorToken: &Token): bool { + if d.Decl { + self.pushErr(errorToken, LogMsg.InvalidExpr) + ret false + } + if destIsRef { + if !dest.Equal(d.Kind) { + self.pushErr(errorToken, LogMsg.IncompatibleTypes, dest.Str(), d.Kind.Str()) + ret false + } + } else { + mut atc := &assignTypeChecker{ + s: self, + errorToken: errorToken, + dest: dest, + d: d, + } + ok := atc.check() + if !ok { + ret false + } + } + + if !d.IsConst() || dest.Prim() == nil { + ret true + } + + mut kind := dest.Prim().Kind + + match { + | types::IsSigInt(kind): + d.Constant.SetI64(d.Constant.AsI64()) + | types::IsUnsigInt(kind): + d.Constant.SetU64(d.Constant.AsU64()) + | types::IsFloat(kind): + d.Constant.SetF64(d.Constant.AsF64()) + } + + ret true + } + + fn _checkTypeCompatibility(mut &self, mut &dest: &TypeKind, mut &src: &TypeKind, + mut errorToken: &Token): bool { + if src == nil { + ret false + } + // Tuple to single type, always fails. + if src.Tup() != nil { + ret false + } + mut tcc := typeCompatibilityChecker{ + s: self, + errorToken: errorToken, + dest: dest, + src: src, + } + ret tcc.check() + } + + fn checkTypeCompatibility(mut &self, mut &dest: &TypeKind, + mut &src: &TypeKind, mut &errorToken: &Token): bool { + if self._checkTypeCompatibility(dest, src, errorToken) { + ret true + } + self.pushErr(errorToken, LogMsg.IncompatibleTypes, dest.Str(), src.Str()) + ret false + } + + fn pushCompatiblityError(mut self, mut &dest: &TypeKind, mut &src: &Data, + mut &errorToken: &Token) { + if src.untyped { + match { + | src.Constant.IsI64(): + self.pushErr(errorToken, LogMsg.IncompatibleTypes, dest.Str(), "untyped integer") + ret + | src.Constant.IsU64(): + self.pushErr(errorToken, LogMsg.IncompatibleTypes, dest.Str(), "untyped unsigned integer") + ret + | src.Constant.IsF64(): + self.pushErr(errorToken, LogMsg.IncompatibleTypes, dest.Str(), "untyped float") + ret + } + } + self.pushErr(errorToken, LogMsg.IncompatibleTypes, dest.Str(), src.Kind.Str()) + } + + fn checkTypeCompatibility1(mut &self, mut &dest: &TypeKind, mut &src: &Data, + mut &errorToken: &Token): bool { + if self._checkTypeCompatibility(dest, src.Kind, errorToken) { + ret true + } + self.pushCompatiblityError(dest, src, errorToken) + ret false + } + + // Builds non-generic types but skips generic types. + // Builds generic identifiers as primitive type. + // + // Useful: + // - For non-generic type parsed string type kinds. + // - For checking non-generic types. + fn buildNonGenericTypeKind(mut &self, mut &ast: &ast::TypeDecl, + mut &generics: []&ast::GenericDecl, mut &ignored: []&TypeKind): &TypeKind { + mut tc := &typeChecker{ + s: self, + rootLookup: self, + lookup: self, + ignoreGenerics: generics, + ignoredGenerics: &ignored, + } + ret tc.checkDecl(ast) + } + + fn buildFnNonGenericTypeKinds(mut &self, mut &f: &FnIns, mut &ignored: []&TypeKind): (ok: bool) { + ok = true + let mut generics: []&ast::GenericDecl = nil + if f.Decl.IsMethod() { + generics = append(f.Decl.Generics, f.Decl.Owner.Generics...) + } else { + generics = f.Decl.Generics + } + + for (_, mut p) in f.Params { + if !p.Decl.IsSelf() { + p.Kind = self.buildNonGenericTypeKind(p.Decl.Kind.Decl, generics, ignored) + ok = ok && p.Kind != nil + } + } + if !f.Decl.IsVoid() { + f.Result = self.buildNonGenericTypeKind(f.Decl.Result.Kind.Decl, generics, ignored) + ok = ok && f.Result != nil + } + ret + } + + fn getTraitCheckFnKind(mut &self, mut &f: &Fn): &FnIns { + if len(f.Instances) == 1 { + ret f.Instances[0] + } + mut ins := f.instanceForce() + + mut tc := &typeChecker{ + s: self, + rootLookup: self, + lookup: self, + } + for (_, mut p) in ins.Params { + if !p.Decl.IsSelf() { + p.Kind = tc.checkDecl(p.Decl.Kind.Decl) + } + } + if !f.IsVoid() { + ins.Result = tc.checkDecl(f.Result.Kind.Decl) + } + + ret ins + } + + fn checkConstraintsFn(mut &self, mut &f: &FnIns, mut &et: &Token, mut exist: &FnIns): bool { + mut cc := self.constraintChecker() + cc.et = et + cc.fi = f + if exist != nil { + for (i, mut g) in exist.Generics { + f.Generics[i].Constraint = g.Constraint + } + } else { + cc.uniq = true + } + ret cc.check() + } + + fn checkConstraintsStruct(mut &self, mut &s: &StructIns, mut &et: &Token, mut exist: &StructIns): bool { + mut cc := self.constraintChecker() + cc.et = et + cc.si = s + if exist != nil { + for (i, mut g) in exist.Generics { + s.Generics[i].Constraint = g.Constraint + } + } else { + cc.uniq = true + } + ret cc.check() + } + + // Call algo in the function's native environment. + // Errors will be handled. + // Returns result of algo. + fn fnEnvironment(mut &self, mut &f: &FnIns, algo: fn(mut &sema: &Sema, mut &generics: []&TypeAlias): bool): bool { + mut sema := f.Decl.sema + mut old := f.Decl.sema.file + defer { f.Decl.sema.setCurrentFile(old) } + mut file := findFile(f.Decl.sema.files, f.Decl.Token.File) + if file != nil { + f.Decl.sema.setCurrentFile(file) + } + + mut size := len(f.Generics) + if f.Decl != nil && f.Decl.Owner != nil { + size += len(f.Decl.Owner.Generics) + } + + mut generics := make([]&TypeAlias, 0, size) + appendGenericTypeAliases(generics, f) + + ok := algo(sema, generics) + + if sema != self { + self.errors = append(self.errors, sema.errors...) + sema.errors = nil + } + + ret ok + } + + fn checkFnParamKind(mut &self, mut &p: &ParamIns) { + p.Kind.Variadic = p.Decl.Variadic + if p.Decl.Reference && !isValidForRef(p.Kind) { + self.pushErr(p.Decl.Token, LogMsg.RefPointsToInvalidType, p.Kind.Str()) + } + } + + fn reloadFnInsTypes(mut &self, mut f: &FnIns): bool { + if f.IsBuiltin() || f.IsAnon() { + ret true + } + ret self.fnEnvironment(f, fn(mut &sema: &Sema, mut &generics: []&TypeAlias): bool { + mut ok := true + for (_, mut p) in f.Params { + if p.Decl.IsSelf() { + if p.Decl.IsRef() { + p.Kind = &TypeKind{ + Kind: &Sptr{ + Elem: &TypeKind{ + Kind: f.Owner, + }, + }, + } + } else { + p.Kind = &TypeKind{Kind: f.Owner} + } + } else { + p.Kind = sema.buildTypeWithGenerics(p.Decl.Kind.Decl, generics, f.Refers) + if p.Kind != nil { + self.checkFnParamKind(p) + } else { + ok = false + } + } + } + if !f.Decl.IsVoid() { + f.Result = sema.buildTypeWithGenerics(f.Decl.Result.Kind.Decl, generics, f.Refers) + ok = f.Result != nil && ok + } + ret ok + }) + } + + fn checkRefValidityForInitExpr(mut &self, leftMut: bool, mut &d: &Data, mut &errorToken: &Token): bool { + if !isValidModelForRef(d.Model) { + self.pushErr(errorToken, LogMsg.RefAssignNonVar) + ret false + } + if leftMut && !d.Mutable { + self.pushErr(errorToken, LogMsg.MutRefPointsImmut) + ret false + } + ret true + } + + // Reports whether struct is risky for mutability. + // Designed for copy assignments. + // It will not check mutability risk of the internal mutable data or etc. + // It will check interior mutability risk of the new copy. + // Assumes the assigned memory is mutable. + fn isMutRiskyStruct(self, &s: &StructIns): bool { + for _, f in s.Fields { + // Inerior mutability enables to copy internal mutable data with safety. + // If field is interior mutable and their kind is mutable, + // check whether the field accessible. If field is not accessible, + // there is no problem, because no risk for mutability. + // + // For example: + // We have a Foo struct. The Foo struct have the x field which is + // interior mutable with mutable kind. So the following code is risky: + // + // a := Foo{} + // mut b := a + // + // The example code above will create new copy of variable a, which is + // instance of struct Foo. If the field x is accessible, the variable + // b can mutate it, since it is mutable and can access to field x. + // Therefore, copying interior mutable fields with mutable kind + // must be disallowed if field is accessible for safety reasons. + if f.Decl.Mutable && f.Kind.Mutable() && + self.isAccessibleDefine(f.Decl.Public, f.Decl.Token) { + ret true + } + } + ret false + } + + fn checkValidityForInitExpr(mut &self, leftMut: bool, leftRef: bool, + &leftKind: &TypeKind, mut &d: &Data, mut &errorToken: &Token): bool { + if leftMut && !d.Mutable { + // Check classical assignment mutability. + if d.Kind.Mutable() { + self.pushErr(errorToken, LogMsg.AssignNonMutToMut, d.Kind.Str()) + ret false + } + // Check interior mutability risk for the struct copy. + s := d.Kind.Struct() + if s != nil && self.isMutRiskyStruct(s) { + self.pushErr(errorToken, LogMsg.CopyWithMutableData, d.Kind.Str()) + ret false + } + } + if leftRef { + if !self.checkRefValidityForInitExpr(leftMut, d, errorToken) { + ret false + } + } + mut atc := &assignTypeChecker{ + s: self, + d: d, + errorToken: errorToken, + } + ret atc.checkValidity() + } + + fn checkTypeAliasDeclKind(mut &self, mut &ta: &TypeAlias, mut l: Lookup): (ok: bool) { + mut old := self.file + defer { + self.setCurrentFile(old) + } + if ta.Token != nil { + mut file := findFile(self.files, ta.Token.File) + if file != nil { + self.setCurrentFile(file) + } + } + ok = self.checkTypeWithRefers(ta.Kind, l, nil, &referencer{ + ident: ta.Ident, + owner: ta, + refs: &ta.Refers, + }) + if ok && ta.Kind.Kind.Arr() != nil && ta.Kind.Kind.Arr().Auto { + self.pushErr(ta.Kind.Decl.Token, LogMsg.ArrayAutoSized) + ok = false + } + ret + } + + fn checkTypeAliasDecl(mut &self, mut &ta: &TypeAlias, mut l: Lookup) { + if IsIgnoreIdent(ta.Ident) { + self.pushErr(ta.Token, LogMsg.IgnoreIdent) + } + self.checkTypeAliasDeclKind(ta, l) + } + + // Checks type alias declaration with duplicated identifiers. + fn checkTypeAliasDeclDup(mut &self, mut &ta: &TypeAlias) { + if IsIgnoreIdent(ta.Ident) { + self.pushErr(ta.Token, LogMsg.IgnoreIdent) + } + if self.isDuplicatedIdent(uintptr(ta), ta.Ident, ta.Binded) { + self.pushErr(ta.Token, LogMsg.DuplicatedIdent, ta.Ident) + self.pushSuggestion(LogMsg.RenameForAvoidDuplication) + } + self.checkTypeAliasDeclKind(ta, self) + } + + // Checks current package file's type alias declarations. + fn checkTypeAliasDecls(mut &self): (ok: bool) { + for (_, mut ta) in self.file.TypeAliases { + self.checkTypeAliasDeclDup(ta) + + // Break checking if type alias has error. + if len(self.errors) > 0 { + ret false + } + } + ret true + } + + fn checkEnumItemsDup[T](mut self, items: []T) { + for _, item in items { + if item.Ident == "" { + continue + } else if IsIgnoreIdent(item.Ident) { + self.pushErr(item.Token, LogMsg.IgnoreIdent) + } else { + for _, citem in items { + if item == citem { + break + } else if item.Ident == citem.Ident { + self.pushErr(item.Token, LogMsg.DuplicatedIdent, item.Ident) + self.pushSuggestion(LogMsg.RenameForAvoidDuplication) + break + } + } + } + } + } + + fn checkEnumItemsStr(mut &self, mut &e: &Enum) { + mut eval := self.eval(self) + for (_, mut item) in e.Items { + if item.AutoExpr() { + item.Value = &Value{ + Data: &Data{ + Constant: Const.NewStr(item.Ident), + }, + } + item.Value.Data.Model = item.Value.Data.Constant + } else { + mut d := eval.evalExpr(item.Value.Expr) + if d == nil { + continue + } + + if !d.IsConst() { + self.pushErr(item.Value.Expr.Token, LogMsg.ExprNotConst) + } + + _ = self.checkAssignType(false, e.Kind.Kind, d, item.Token) + item.Value.Data = d + } + } + } + + fn checkEnumItemInt[Int](mut &self, mut &eval: &Eval, mut &e: &Enum, &prim: &Prim, mut &item: &EnumItem, mut &n: Int) { + if item.AutoExpr() { + item.Value = &Value{ + Data: new(Data), + } + const match type Int { + | i64: + item.Value.Data.Constant = Const.NewI64(n) + | u64: + item.Value.Data.Constant = Const.NewU64(n) + |: + panic("unimplemented enum int type, this panic call should be unreachable") + } + item.Value.Data.Model = item.Value.Data.Constant + } else { + mut d := eval.evalExpr(item.Value.Expr) + if d == nil { + ret + } + if !d.IsConst() { + self.pushErr(item.Value.Expr.Token, LogMsg.ExprNotConst) + } + _ = self.checkAssignType(false, e.Kind.Kind, d, item.Token) + item.Value.Data = d + const match type Int { + | i64: + n = item.Value.Data.Constant.ReadI64() + | u64: + n = item.Value.Data.Constant.ReadU64() + |: + panic("unimplemented enum int type, this panic call should be unreachable") + } + } + } + + fn checkEnumItemsInt1[Int](mut &self, &prim: &Prim, mut &e: &Enum) { + mut max := Int(0) + const match type Int { + | i64: + max = types::MaxI(prim.Str()) + | u64: + max = types::MaxU(prim.Str()) + |: + panic("unimplemented enum int type, this panic call should be unrechable") + } + + mut eval := self.eval(self) + mut n := Int(0) + mut first := e.Items[0] + self.checkEnumItemInt(eval, e, prim, first, n) + if first.Value.Data != nil { + const match type Int { + | i64: + n = first.Value.Data.Constant.AsI64() + | u64: + n = first.Value.Data.Constant.AsU64() + |: + panic("unimplemented enum int type, this panic call should be unreachable") + } + } + for (_, mut item) in e.Items[1:] { + if item.AutoExpr() && n > 0 && max-n <= 0 { + self.pushErr(item.Token, LogMsg.OverflowLimits) + break + } + n++ + self.checkEnumItemInt(eval, e, prim, item, n) + } + } + + fn checkEnumItemsInt(mut &self, mut &e: &Enum) { + prim := e.Kind.Kind.Prim() + match { + | types::IsSigInt(prim.Kind): + self.checkEnumItemsInt1[i64](prim, e) + |: + self.checkEnumItemsInt1[u64](prim, e) + } + } + + fn checkEnumDecl(mut &self, mut &e: &Enum) { + if IsIgnoreIdent(e.Ident) { + self.pushErr(e.Token, LogMsg.IgnoreIdent) + } else if self.isDuplicatedIdent(uintptr(e), e.Ident, false) { + self.pushErr(e.Token, LogMsg.DuplicatedIdent, e.Ident) + self.pushSuggestion(LogMsg.RenameForAvoidDuplication) + } + + if len(e.Items) == 0 { + self.pushErr(e.Token, LogMsg.NoMemberInEnum, e.Ident) + ret + } + + self.checkEnumItemsDup[&EnumItem](e.Items) + + if e.Kind != nil { + if !self.checkType(e.Kind, self) { + ret + } + } else { + // Set to default type. + e.Kind = findBuiltinTypeAlias(PrimKind.Int).Kind + } + + mut t := e.Kind.Kind.Prim() + if t == nil { + self.pushErr(e.Token, LogMsg.InvalidTypeSource) + ret + } + + // Check items. + match { + | t.IsStr(): + self.checkEnumItemsStr(e) + | types::IsInt(t.Str()): + self.checkEnumItemsInt(e) + |: + self.pushErr(e.Token, LogMsg.InvalidTypeSource) + } + } + + fn checkTypeEnumDecl(mut &self, mut &e: &TypeEnum) { + if IsIgnoreIdent(e.Ident) { + self.pushErr(e.Token, LogMsg.IgnoreIdent) + } else if self.isDuplicatedIdent(uintptr(e), e.Ident, false) { + self.pushErr(e.Token, LogMsg.DuplicatedIdent, e.Ident) + self.pushSuggestion(LogMsg.RenameForAvoidDuplication) + } + + if len(e.Items) == 0 { + self.pushErr(e.Token, LogMsg.NoMemberInEnum, e.Ident) + ret + } + + self.checkEnumItemsDup[&TypeEnumItem](e.Items) + for (_, mut item) in e.Items { + if item.Kind == nil { + self.pushErr(item.Token, LogMsg.MissingType) + continue + } + ok := self.checkType(item.Kind, self) + if !ok { + continue + } + p := item.Kind.Kind.Prim() + if p != nil && p.IsAny() { + self.pushErr(item.Token, LogMsg.AnyWithTypeEnum) + } + } + if len(e.Items) == 1 { + mut item := e.Items[0] + tk := TypeKind{ + Kind: e, + } + if item.Kind.Kind != nil && item.Kind.Kind.Equal(unsafe { (&TypeKind)(&tk) }) { + self.pushErr(item.Token, LogMsg.IllegalCycleRefersItself, e.Str()) + } + } + } + + // Checks current package file's enum declarations. + fn checkEnumDecls(mut &self): (ok: bool) { + for (_, mut e) in self.file.Enums { + self.checkEnumDecl(e) + // Break checking if type alias has error. + if len(self.errors) > 0 { + ret false + } + } + ret true + } + + // Checks current package file's type enum declarations. + fn checkTypeEnumDecls(mut &self): (ok: bool) { + for (_, mut e) in self.file.TypeEnums { + self.checkTypeEnumDecl(e) + // Break checking if type alias has error. + if len(self.errors) > 0 { + ret false + } + } + ret true + } + + fn checkDeclGenerics(mut self, &generics: []&ast::GenericDecl): (ok: bool) { + ok = true + for i, g in generics { + if IsIgnoreIdent(g.Ident) { + self.pushErr(g.Token, LogMsg.IgnoreIdent) + ok = false + continue + } + + // Check duplications. + duplicationLookup: + for j, ct in generics { + match { + | j >= i: + // Skip current and following generics. + break duplicationLookup + | g.Ident == ct.Ident: + self.pushErr(g.Token, LogMsg.DuplicatedIdent, g.Ident) + self.pushSuggestion(LogMsg.RenameForAvoidDuplication) + ok = false + break duplicationLookup + } + } + } + ret + } + + fn checkFnDeclParamsDup(mut self, &f: &Fn): (ok: bool) { + ok = true + check: + for i, p in f.Params { + // Lookup in generics. + for _, g in f.Generics { + if p.Ident == g.Ident { + ok = false + self.pushErr(p.Token, LogMsg.DuplicatedIdent, p.Ident) + self.pushSuggestion(LogMsg.RenameForAvoidDuplication) + continue check + } + } + + paramsLookup: + for j, jp in f.Params { + match { + | j >= i: + // Skip current and following parameters. + break paramsLookup + | IsIgnoreIdent(p.Ident) + | IsIgnoreIdent(jp.Ident) + | IsAnonIdent(p.Ident) + | IsAnonIdent(jp.Ident): + // Skip anonymous parameters. + break paramsLookup + | p.Ident == jp.Ident: + ok = false + self.pushErr(p.Token, LogMsg.DuplicatedIdent, p.Ident) + self.pushSuggestion(LogMsg.RenameForAvoidDuplication) + continue check + } + } + } + ret + } + + fn checkFnDeclResultDup(mut self, &f: &Fn): (ok: bool) { + ok = true + if f.IsVoid() { + ret + } + + // Check duplications. + for i, v in f.Result.Idents { + if IsIgnoreIdent(v.Kind) || IsAnonIdent(v.Kind) { + continue // Skip anonymous return variables. + } + // Lookup in generics. + for _, g in f.Generics { + if v.Kind == g.Ident { + goto exist + } + } + // Lookup in parameters. + for _, p in f.Params { + if v.Kind == p.Ident { + goto exist + } + } + + // Lookup in return identifiers. + itself_lookup: + for j, jv in f.Result.Idents { + match { + | j >= i: + // Skip current and following identifiers. + break itself_lookup + | jv.Kind == v.Kind: + goto exist + } + } + continue + exist: + self.pushErr(v, LogMsg.DuplicatedIdent, v.Kind) + self.pushSuggestion(LogMsg.RenameForAvoidDuplication) + ok = false + } + + ret + } + + fn checkFnVariadicParam(mut &self, mut &f: &Fn): bool { + if len(f.Params) == 0 { + ret false + } + mut param := f.Params[len(f.Params)-1] + if param.Variadic && param.Reference { + self.pushErr(param.Token, LogMsg.VariadicReference) + } + ret true + } + + // Checks generics, parameters and return type. + // Not checks scope, and other things. + fn checkFnDeclPrototype(mut &self, mut &f: &Fn) { + if f.Exceptional && f.Binded { + self.pushErr(f.Token, LogMsg.BindedExceptional) + ret + } + + if f.Exceptional { + if f.IsEntryPoint() { + self.pushErr(f.Token, LogMsg.ExceptionalEntryPoint) + } else if f.IsInit() { + self.pushErr(f.Token, LogMsg.ExceptionalInit) + } + } + + match { + | !self.checkDeclGenerics(f.Generics): + | !self.checkFnDeclParamsDup(f): + | !self.checkFnDeclResultDup(f): + | !self.checkFnVariadicParam(f): + } + } + + fn catchTraitInheritCycle(mut &self, t1: &Trait, mut t2: &Trait, mut &message: StrBuilder): (ok: bool) { + ok = true + for (_, mut i) in t2.Inherits { + if i.Kind == nil { + continue + } + mut t3 := i.Kind.Trait() + if t1 == t3 { + self.pushCycleError(t2.Ident, t3.Ident, message) + ret false + } + if !self.catchTraitInheritCycle(t1, t3, message) { + self.pushCycleError(t2.Ident, t3.Ident, message) + ret false + } + } + ret + } + + fn _checkTraitDeclInherits(mut &self, mut &t: &Trait): (ok: bool) { + ok = true + for (i, mut it) in t.Inherits { + if !self.checkType(it, self) { + ok = false + continue + } + mut t2 := it.Kind.Trait() + if t2 == nil { + self.pushErr(it.Decl.Token, LogMsg.InheritedNonTrait, t.Ident, it.Kind.Str()) + ok = false + continue + } + for j, it2 in t.Inherits { + if j >= i { + break + } + if it2.Kind != nil && it.Kind.Equal(it2.Kind) { + self.pushErr(it.Decl.Token, LogMsg.DuplicatedIdent, t2.Ident) + ok = false + break + } + } + if t == t2 { + self.pushErr(it.Decl.Token, LogMsg.IllegalCycleRefersItself, t.Ident) + ok = false + } else { + mut message := StrBuilder.New(1 << 6) + ok = ok && self.catchTraitInheritCycle(t, t2, message) + if message.Len() > 0 { + mut errMsg := message.Str() + message.Clear() + self.pushCycleError(t.Ident, t2.Ident, message) + errMsg += message.Str() + self.pushErr(it.Decl.Token, LogMsg.IllegalCrossCycle, errMsg) + } + } + } + ret ok + } + + fn checkTraitDeclInherits(mut &self, mut &t: &Trait) { + for (i, mut it) in t.Inherits { + mut t1 := it.Kind.Trait() + for (j, mut it2) in t.Inherits { + if j == i { + continue + } + mut t2 := it2.Kind.Trait() + for (_, mut t1m) in t1.Methods { + mut t2m := t2.FindMethod(t1m.Ident) + if t2m == nil { + continue + } + t1f := self.getTraitCheckFnKind(t1m) + t2f := self.getTraitCheckFnKind(t2m) + if !t1f.equalTrait(t2f) { + self.pushErr(it.Decl.Token, LogMsg.IncompatibleInherit, + t.Ident, t2.Ident, t1f.GetKindStr(true), t2f.GetKindStr(true)) + ret + } + } + } + } + } + + fn checkTraitDeclMethod(mut &self, mut &f: &Fn) { + if IsIgnoreIdent(f.Ident) { + self.pushErr(f.Token, LogMsg.IgnoreIdent) + } else if IsAnonIdent(f.Ident) { + self.pushErr(f.Token, LogMsg.AnonFn) + } + f.sema = self + self.checkFnDeclPrototype(f) + mut ins := f.instance() + _ = self.reloadFnInsTypes(ins) + ins.reloaded = true + f.appendInstance(ins) + } + + fn checkTraitDeclMethods(mut &self, mut &t: &Trait) { + for (i, mut f) in t.Methods { + self.checkTraitDeclMethod(f) + + // Break checking if type alias has error. + if len(self.errors) > 0 { + ret + } + + if t.findMethodInherit(f.Ident) != nil { + self.pushErr(f.Token, LogMsg.DuplicatedIdent, f.Ident) + self.pushSuggestion(LogMsg.RenameForAvoidDuplication) + continue + } + + // Check duplications. + duplicateLookup: + for j, jf in t.Methods { + // NOTE: + // Ignore identifier checking is unnecessary here. + // Because ignore identifiers logs error. + // Errors breaks checking, so here is unreachable code for + // ignore identified methods. + match { + | j >= i: + // Skip current and following methods. + break duplicateLookup + | f.Ident == jf.Ident: + self.pushErr(f.Token, LogMsg.DuplicatedIdent, f.Ident) + self.pushSuggestion(LogMsg.RenameForAvoidDuplication) + break duplicateLookup + } + } + } + } + + fn checkTraitDecl(mut &self, mut &t: &Trait) { + if IsIgnoreIdent(t.Ident) { + self.pushErr(t.Token, LogMsg.IgnoreIdent) + } else if self.isDuplicatedIdent(uintptr(t), t.Ident, false) { + self.pushErr(t.Token, LogMsg.DuplicatedIdent, t.Ident) + self.pushSuggestion(LogMsg.RenameForAvoidDuplication) + } + + self.checkTraitDeclInherits(t) + self.checkTraitDeclMethods(t) + } + + // Checks current package file's trait declarations. + fn checkTraitDecls(mut &self): (ok: bool) { + for (_, mut t) in self.file.Traits { + self.checkTraitDecl(t) + // Break checking if type alias has error. + if len(self.errors) > 0 { + ret false + } + } + ret true + } + + fn checkTraitImplMethods(mut self, mut &base: &Trait, &ipl: &Impl): (ok: bool) { + ok = true + for _, f in ipl.Methods { + if base.FindMethod(f.Ident) == nil { + self.pushErr(f.Token, LogMsg.TraitHaveNotIdent, base.Ident, f.Ident) + ok = false + } + } + ret + } + + fn implToStruct(mut &self, mut &dest: &Struct, mut &ipl: &Impl): (ok: bool) { + ok = true + + // Methods. + for (_, mut f) in ipl.Methods { + if dest.FindMethod(f.Ident, f.Statically) != nil || dest.FindField(f.Ident) != nil { + self.pushErr(f.Token, LogMsg.StructAlreadyHaveIdent, dest.Ident, f.Ident) + ok = false + continue + } + + if len(dest.Generics) > 0 && len(f.Generics) > 0 { + for _, fg in f.Generics { + for _, dg in dest.Generics { + if fg.Ident == dg.Ident { + self.pushErr(fg.Token, LogMsg.MethodHasGenericWithSameIdent) + ok = false + } + } + } + } + + self.checkDirectives(f.Directives, f) + + f.sema = self + f.Owner = dest + dest.Methods = append(dest.Methods, f) + } + + for (_, mut v) in ipl.Statics { + const Static = true + if dest.FindMethod(v.Ident, Static) != nil || dest.FindStatic(v.Ident) != nil { + self.pushErr(v.Token, LogMsg.StructAlreadyHaveIdent, dest.Ident, v.Ident) + ok = false + continue + } + dest.Statics = append(dest.Statics, v) + } + ret + } + + // Implement trait to destination. + fn implTrait(mut &self, mut &decl: &Impl) { + mut base_t := self.selectType(decl.Base) + if base_t == nil { + ret + } + mut base := base_t.Trait() + if base == nil { + self.pushErr(decl.Base.Token, LogMsg.ImplInvalidBase, base_t.Str()) + self.pushSuggestion(LogMsg.ExpectedTrait) + ret + } + + mut destT := self.selectType(decl.Dest) + if destT == nil { + ret + } + mut destS := destT.Struct() + if destS == nil { + self.pushErr(decl.Dest.Token, LogMsg.ImplInvalidDest, destT.Str()) + self.pushSuggestion(LogMsg.ExpectedStruct) + ret + } + + mut dest := destS.Decl + + if dest.Token.File.Dir() != self.file.File.Dir() { + self.pushErr(decl.Dest.Token, LogMsg.IllegalImplOutOfPackage) + ret + } + + pushImplemented(base, dest) + pushImplements(dest, base) + + if len(decl.Statics) > 0 { + self.pushErr(decl.Statics[0].Token, LogMsg.TraitImplHasStatic) + } + + match { + | !self.checkTraitImplMethods(base, decl): + | !self.implToStruct(dest, decl): + } + } + + fn implStruct(mut &self, mut &decl: &Impl) { + mut destT := self.selectType(decl.Dest) + if destT == nil { + ret + } + mut destS := destT.Struct() + if destS == nil { + self.pushErr(decl.Dest.Token, LogMsg.ImplInvalidDest, destT.Str()) + self.pushSuggestion(LogMsg.ExpectedStruct) + ret + } + + mut dest := destS.Decl + if dest.Token.File.Dir() != self.file.File.Dir() { + self.pushErr(decl.Dest.Token, LogMsg.IllegalImplOutOfPackage) + ret + } + + match { + | !self.implToStruct(dest, decl): + } + } + + // Implement implementation. + fn implImpl(mut &self, mut &decl: &Impl) { + match { + | decl.IsTraitImpl(): + self.implTrait(decl) + | decl.IsStructImpl(): + self.implStruct(decl) + } + } + + // Checks variable declaration. + // Will not check duplicated identifiers. + fn checkVarDecl(mut &self, mut &decl: &Var, mut l: Lookup) { + if IsIgnoreIdent(decl.Ident) { + self.pushErr(decl.Token, LogMsg.IgnoreIdent) + } + + if decl.IsTypeInferred() { + if !decl.IsInitialized() { + self.pushErr(decl.Token, LogMsg.MissingValueForTypeInference) + } + } else { + _ = self.checkType(decl.Kind, l) + } + + if decl.Reference { + if decl.Constant { + self.pushErr(decl.Token, LogMsg.ConstRef) + } + if decl.Statically { + self.pushErr(decl.Token, LogMsg.StaticReference) + } + } + + if !decl.IsInitialized() { + if decl.Constant { + self.pushErr(decl.Token, LogMsg.ConstVarNotHaveExpr) + } + if decl.Statically { + self.pushErr(decl.Token, LogMsg.StaticNotHaveExpr) + } + if decl.Reference { + self.pushErr(decl.Token, LogMsg.RefNotInited) + } + } + } + + // Checks variable declaration for global scope. + // Checks duplicated identifiers by Sema. + fn checkGlobalVarDecl(mut &self, mut &decl: &Var) { + if self.isDuplicatedIdent(uintptr(decl), decl.Ident, decl.Binded) { + self.pushErr(decl.Token, LogMsg.DuplicatedIdent, decl.Ident) + self.pushSuggestion(LogMsg.RenameForAvoidDuplication) + } + if decl.Binded && decl.Constant { + self.pushErr(decl.Token, LogMsg.BindedVarIsConst) + } + if !decl.Binded && !decl.Constant && !decl.Statically { + self.pushErr(decl.Token, LogMsg.GlobalNotStatic) + self.pushSuggestion(LogMsg.UseStaticKeywordToDef) + } + self.checkDirectives(decl.Directives, decl) + self.checkVarDecl(decl, self) + } + + // Checks current package file's global variable declarations. + fn checkGlobalDecls(mut &self): (ok: bool) { + for (_, mut decl) in self.file.Vars { + self.checkGlobalVarDecl(decl) + // Break checking if type alias has error. + if len(self.errors) > 0 { + ret false + } + } + ret true + } + + fn checkStructTraitImpl(mut &self, mut &strct: &Struct, mut &trt: &Trait): (ok: bool) { + for (_, mut tf) in trt.Methods { + mut exist := false + mut sf := strct.FindMethod(tf.Ident, tf.Statically) + tfK := self.getTraitCheckFnKind(tf) + if sf != nil { + mut sfK := self.getTraitCheckFnKind(sf) + exist = tfK.equalTrait(sfK) + } + if exist { + d := findDirective(sf.Directives, Directive.Deprecated) + if d != nil { + self.pushErr(d.Tag, LogMsg.TraitImplDeprecated) + } + ok = false + } else { + const Ident = true + self.pushErr(strct.Token, LogMsg.NotImplTraitDef, trt.Ident, tfK.GetKindStr(Ident)) + ok = false + } + } + ret + } + + fn checkStructImpls(mut &self, mut &s: &Struct): (ok: bool) { + ok = true + for (_, mut trt) in s.Implements { + ok = self.checkStructTraitImpl(s, trt) && ok + } + ret ok + } + + fn checkStructFields(mut &self, mut &st: &Struct): (ok: bool) { + ok = true + for (_, mut f) in st.Fields { + f.Owner = st + for _, cf in st.Fields { + if f == cf { + break + } else if f.Ident == cf.Ident { + self.pushErr(f.Token, LogMsg.DuplicatedIdent, f.Ident) + self.pushSuggestion(LogMsg.RenameForAvoidDuplication) + ok = false + } + } + } + ret ok + } + + fn checkStructDecl(mut &self, mut &s: &Struct) { + if IsIgnoreIdent(s.Ident) { + self.pushErr(s.Token, LogMsg.IgnoreIdent) + } else if self.isDuplicatedIdent(uintptr(s), s.Ident, s.Binded) { + self.pushErr(s.Token, LogMsg.DuplicatedIdent, s.Ident) + self.pushSuggestion(LogMsg.RenameForAvoidDuplication) + } + + self.checkDirectives(s.Directives, s) + + match { + | !self.checkDeclGenerics(s.Generics): + | !self.checkStructFields(s): + | !self.checkStructImpls(s): + | !self.checkFuncDeclsBy(s.Methods): + } + } + + // Checks current package file's structure declarations. + fn checkStructDecls(mut &self): (ok: bool) { + for (_, mut s) in self.file.Structs { + self.checkStructDecl(s) + // Break checking if type alias has error. + if len(self.errors) > 0 { + ret false + } + } + ret true + } + + fn checkAnonFuncDecl(mut &self, mut &f: &Fn) { + f.sema = self + self.checkFnDeclPrototype(f) + } + + fn checkFuncDecl(mut &self, mut &f: &Fn) { + if IsIgnoreIdent(f.Ident) { + self.pushErr(f.Token, LogMsg.IgnoreIdent) + } else if f.IsAnon() { + self.pushErr(f.Token, LogMsg.AnonFn) + } + + self.checkDirectives(f.Directives, f) + self.checkAnonFuncDecl(f) + + if f.Owner == nil && self.isDuplicatedIdent(uintptr(f), f.Ident, f.Binded) { + if f.Ident == build::InitFn { + init := self.FindFn(build::InitFn, false) + if init != nil { + ret + } + } + self.pushErr(f.Token, LogMsg.DuplicatedIdent, f.Ident) + self.pushSuggestion(LogMsg.RenameForAvoidDuplication) + } + } + + fn checkFuncDeclsBy(mut &self, mut &funcs: []&Fn): bool { + for (_, mut f) in funcs { + self.checkFuncDecl(f) + // Break checking if error occurs. + if len(self.errors) > 0 { + ret false + } + } + ret true + } + + // Checks current package file's function declarations. + fn checkFuncDecls(mut &self): (ok: bool) { + ret self.checkFuncDeclsBy(self.file.Funcs) + } + + fn pushCycleError(self, &st1: str, &st2: str, mut &message: StrBuilder) { + const Padding = 7 + refersTo := Logf(LogMsg.RefersTo, st1, st2) + m := message.Str() + message.WriteStr(strings::Repeat(" ", Padding)) + message.WriteStr(refersTo) + message.WriteByte('\n') + message.WriteStr(m) + } + + fn checkCrossCycle(self, &st1: &Struct, &st2: &Struct, mut &message: StrBuilder): bool { + for _, u in st2.Uses { + if u == st1 { + self.pushCycleError(st2.Ident, u.Ident, message) + ret false + } + if !self.checkCrossCycle(st1, u, message) { + self.pushCycleError(st2.Ident, u.Ident, message) + ret false + } + } + ret true + } + + // Checks declarations of all package files. + // Breaks checking if checked file failed. + fn checkPackageDecls(mut &self) { + for (_, mut f) in self.files { + self.setCurrentFile(f) + if !self.checkTypeAliasDecls() { + ret + } + } + + for (_, mut f) in self.files { + self.setCurrentFile(f) + if !self.checkTraitDecls() { + ret + } + } + + for (_, mut f) in self.files { + self.setCurrentFile(f) + if !self.checkGlobalDecls() { + ret + } + } + + for (_, mut f) in self.files { + self.setCurrentFile(f) + match { + | !self.checkFuncDecls(): + | !self.checkStructDecls(): + |: + continue + } + ret + } + } + + fn checkDataForTypeInference(mut self, &d: &Data, &err_token: &Token) { + match { + | d.IsNil(): + self.pushErr(err_token, LogMsg.NilForTypeInference) + | d.IsVoid(): + self.pushErr(err_token, LogMsg.VoidForTypeInference) + | d.Kind.Variadic: + self.pushErr(err_token, LogMsg.InvalidExprForTypeInference) + } + } + + // Checks value of variable. + fn checkVarValue(mut &self, mut &v: &Var) { + if v.IsTypeInferred() { + // Build new TypeSymbol because auto-type symbols are nil. + v.Kind = &TypeSymbol{Kind: v.Value.Data.Kind} + + self.checkDataForTypeInference(v.Value.Data, v.Value.Expr.Token) + self.checkValidityForInitExpr( + v.Mutable, + v.Reference, + v.Kind.Kind, + v.Value.Data, + v.Value.Expr.Token) + } else { + mut arr := v.Kind.Kind.Arr() + if arr != nil { + if arr.Auto { + dataArr := v.Value.Data.Kind.Arr() + if dataArr != nil { + arr.N = dataArr.N + } + } + } + + if self.checkAssignType(v.Reference, v.Kind.Kind, v.Value.Data, v.Value.Expr.Token) { + self.checkValidityForInitExpr( + v.Mutable, + v.Reference, + v.Kind.Kind, + v.Value.Data, + v.Value.Expr.Token) + } + } + + if v.Reference && !isValidForRef(v.Kind.Kind) { + self.pushErr(v.Token, LogMsg.RefPointsToInvalidType, v.Kind.Kind.Str()) + } + + if v.Constant { + if !v.Value.Data.IsConst() && !v.Value.Data.Kind.comptime() { + self.pushErr(v.Value.Expr.Token, LogMsg.ExprNotConst) + } + } else { + v.Value.Data.Constant = nil + v.Value.Data.untyped = false + } + + // Remove kind for avoid more tuple-type errors. + if v.Kind.Kind.Tup() != nil { + v.Kind.Kind = nil + } + } + + // Evaluates value of variable if initialized. + fn evalVarValue(mut &self, mut &decl: &Var, mut l: Lookup) { + if !decl.IsInitialized() { + ret + } + + let mut eval: &Eval = nil + if decl.Kind != nil { + eval = self.evalpd(l, decl.Kind.Kind, decl) + } else { + eval = self.evalpd(l, nil, decl) + } + eval.immutable = !decl.Mutable + decl.Value.Data = eval.evalExpr(decl.Value.Expr) + } + + // Evaluateds value of variable and checks. + // Assumes the variable is global. + fn checkVar(mut &self, mut &decl: &Var, mut l: Lookup) { + self.evalVarValue(decl, l) + if decl.Value.Data == nil { + ret // Skip checks if error ocurrs. + } + self.checkVarValue(decl) + } + + // Checks current package file's global variables. + fn checkGlobals(mut &self) { + for (_, mut decl) in self.file.Vars { + if decl.Binded { + continue + } + if decl.IsInitialized() && decl.Value.Data == nil || + decl.IsTypeInferred() && decl.Kind.Kind == nil { + self.checkVar(decl, self) + } + } + } + + // Returns new FnIns as ready-to-analysis. + // If function already has a instance, returns existing instance. + // Returns nil if have a problem. + fn readyToCheckFn(mut &self, mut &s: &StructIns, mut &f: &Fn): &FnIns { + mut ins := f.instance() + if len(f.Instances) != 0 { + ret ins + } + ins.Owner = s + f.appendInstance(ins) + ins.reloaded = true + if self.reloadFnInsTypes(ins) { + ret ins + } + ret nil + } + + fn checkTypeMethod(mut &self, mut &s: &StructIns, mut &f: &Fn) { + // Generic instances are checked instantly. + if len(f.Generics) > 0 { + ret + } + mut ins := f.Instances[0] + if len(ins.Scope.Stmts) > 0 { + // Checked + ret + } + self.checkFnIns(ins) + } + + fn checkStructInsOp(mut &self, mut &s: &StructIns, mut &f: &Fn, p: fn(f: &Fn): bool): &FnIns { + if f == nil || len(f.Generics) > 0 || !p(f) { + ret nil + } + ret f.Instances[0] + } + + // Checks environment-dependent parts of structure instance. + // Which is contains fields and generic-type constraints. + // If generic instance will be check, errorToken should be passed. + fn checkStructEnv(mut &self, mut &s: &StructIns, mut errorToken: &Token): (ok: bool) { + mut tc := typeChecker{ + s: s.Decl.sema, + rootLookup: s.Decl.sema, + lookup: s.Decl.sema, + referencer: &referencer{ + ident: s.Decl.Ident, + owner: s.Decl, + }, + refers: s.Refers, + } + + if len(s.Generics) > 0 { + tc.useGenerics = make([]&TypeAlias, 0, len(s.Generics)) + for (i, mut g) in s.Generics { + mut decl := s.Decl.Generics[i] + tc.useGenerics = append(tc.useGenerics, &TypeAlias{ + Ident: decl.Ident, + Token: decl.Token, + Kind: &TypeSymbol{Kind: g.Kind}, + }) + } + } + + mut oldFile := self.file + defer { self.setCurrentFile(oldFile) } + + if self.file.File != s.Decl.Token.File { + mut file := findFile(self.files, s.Decl.Token.File) + if file != nil { + self.setCurrentFile(file) + } + } + + if len(s.Generics) > 0 { + mut cc := self.constraintChecker() + cc.et = errorToken + cc.si = s + cc.genericsA = tc.useGenerics + cc.uniq = true + if !cc.check() { + ret + } + } + + ok = true + + if len(s.Statics) > 0 { + mut n := len(self.errors) + self.files[0].TypeAliases = append(tc.useGenerics, self.files[0].TypeAliases...) + for (_, mut v) in s.Statics { + self.checkVarDecl(v, self) + self.checkVar(v, self) + ok = len(self.errors)-n == 0 && ok + } + self.files[0].TypeAliases = self.files[0].TypeAliases[len(tc.useGenerics):] + if !ok { + ret false + } + } + + mut eval := self.eval(self) + s.Comparable = !s.Decl.Binded + for (_, mut f) in s.Fields { + mut kind := tc.checkDecl(f.Decl.Kind.Decl) + ok = kind != nil && ok + if kind == nil { + if self != s.Decl.sema && len(s.Decl.sema.errors) > 0 { + self.errors = append(self.errors, s.Decl.sema.errors...) + s.Decl.sema.errors = nil + } + continue + } + f.Kind = kind + s.Mutable = s.Mutable || (!f.Decl.Mutable && f.Kind.Mutable()) + s.Comparable = s.Comparable && f.Kind.Comparable() + + // Skip this field if not has default value. + if f.Decl.Default == nil { + continue + } + eval.prefix = f.Kind + eval.field = f + f.Default = eval.evalExpr(f.Decl.Default) + + // Skip if eval returned nil. + // Relevant error(s) logged by eval. + if f.Default == nil { + continue + } + + const Reference = false // Fields cannot be reference. + _ = self.checkAssignType(Reference, f.Kind, f.Default, f.Decl.Default.Token) + } + ret + } + + fn precheckStructIns(mut &self, mut &s: &StructIns, mut errorToken: &Token): (ok: bool) { + ok = self.checkStructEnv(s, errorToken) + if !ok { + ret false + } + for (_, mut f) in s.Methods { + if len(f.Generics) == 0 { + if self.readyToCheckFn(s, f) == nil { + ret false + } + } + } + ret true + } + + fn checkStructIns(mut &self, mut &s: &StructIns) { + for (_, mut f) in s.Methods { + self.checkTypeMethod(s, f) + } + } + + fn checkTypeStruct(mut &self, mut &s: &Struct) { + if s.Binded { + ret + } + + // Generic instances are checked instantly. + if len(s.Generics) > 0 { + ret + } + + // NOTICE: + // Do not check zero instance case, operator overloading + // checker will create an instance if not exist. + for (_, mut ins) in s.Instances { + self.checkStructIns(ins) + } + } + + fn checkStructTypes(mut &self) { + for (_, mut s) in self.file.Structs { + self.checkTypeStruct(s) + } + } + + fn checkStructInsOperators(mut &self, mut s: &StructIns) { + for (_, mut m) in s.Methods { + match m.Ident { + | "Eq": + s.Operators.Eq = self.checkStructInsOp(s, m, FuncPattern.Eq) + s.Comparable = s.Operators.Eq != nil + | "Gt": + s.Operators.Gt = self.checkStructInsOp(s, m, FuncPattern.Gt) + | "GtEq": + s.Operators.GtEq = self.checkStructInsOp(s, m, FuncPattern.GtEq) + | "Lt": + s.Operators.Lt = self.checkStructInsOp(s, m, FuncPattern.Lt) + | "LtEq": + s.Operators.LtEq = self.checkStructInsOp(s, m, FuncPattern.LtEq) + | "Shl": + s.Operators.Shl = self.checkStructInsOp(s, m, FuncPattern.Shl) + | "Shr": + s.Operators.Shr = self.checkStructInsOp(s, m, FuncPattern.Shr) + | "Add": + s.Operators.Add = self.checkStructInsOp(s, m, FuncPattern.Add) + | "Sub": + s.Operators.Sub = self.checkStructInsOp(s, m, FuncPattern.Sub) + | "Div": + s.Operators.Div = self.checkStructInsOp(s, m, FuncPattern.Div) + | "Mul": + s.Operators.Mul = self.checkStructInsOp(s, m, FuncPattern.Mul) + | "Mod": + s.Operators.Mod = self.checkStructInsOp(s, m, FuncPattern.Mod) + | "BitAnd": + s.Operators.BitAnd = self.checkStructInsOp(s, m, FuncPattern.BitAnd) + | "BitOr": + s.Operators.BitOr = self.checkStructInsOp(s, m, FuncPattern.BitOr) + | "BitXor": + s.Operators.BitXor = self.checkStructInsOp(s, m, FuncPattern.BitXor) + | "Neg": + s.Operators.Neg = self.checkStructInsOp(s, m, FuncPattern.Neg) + | "Pos": + s.Operators.Pos = self.checkStructInsOp(s, m, FuncPattern.Pos) + | "BitNot": + s.Operators.BitNot = self.checkStructInsOp(s, m, FuncPattern.BitNot) + | "AddAssign": + s.Operators.AddAssign = self.checkStructInsOp(s, m, FuncPattern.AddAssign) + | "SubAssign": + s.Operators.SubAssign = self.checkStructInsOp(s, m, FuncPattern.SubAssign) + | "DivAssign": + s.Operators.DivAssign = self.checkStructInsOp(s, m, FuncPattern.DivAssign) + | "MulAssign": + s.Operators.MulAssign = self.checkStructInsOp(s, m, FuncPattern.MulAssign) + | "ModAssign": + s.Operators.ModAssign = self.checkStructInsOp(s, m, FuncPattern.ModAssign) + | "ShlAssign": + s.Operators.ShlAssign = self.checkStructInsOp(s, m, FuncPattern.ShlAssign) + | "ShrAssign": + s.Operators.ShrAssign = self.checkStructInsOp(s, m, FuncPattern.ShrAssign) + | "BitOrAssign": + s.Operators.BitOrAssign = self.checkStructInsOp(s, m, FuncPattern.BitOrAssign) + | "BitAndAssign": + s.Operators.BitAndAssign = self.checkStructInsOp(s, m, FuncPattern.BitAndAssign) + | "BitXorAssign": + s.Operators.BitXorAssign = self.checkStructInsOp(s, m, FuncPattern.BitXorAssign) + } + } + } + + fn precheckStructType(mut &self, mut &s: &Struct) { + if s.Binded { + ret + } + + // Generic instances are checked instantly. + if len(s.Generics) > 0 { + ret + } + + if len(s.Instances) == 0 { + mut ins := s.instance() + ins.Checked = true + s.appendInstance(ins) // Append instance before precheck. + self.precheckStructIns(ins, nil) + } + + self.checkStructInsOperators(s.Instances[0]) + } + + fn precheckStructTypes(mut &self) { + for (_, mut s) in self.file.Structs { + self.precheckStructType(s) + } + } + + fn checkRets(mut self, mut &f: &FnIns) { + if f.Decl.IsVoid() { + ret + } + mrc := missingRetChecker.new() + ok := mrc.check(f.Scope) + if !ok { + self.pushErr(f.Decl.Token, LogMsg.MissingRet) + } + } + + fn checkFnInsSc(mut self, mut &f: &FnIns, mut &sc: &scopeChecker) { + appendRetVars(sc.table.Vars, f) + appendParamVars(sc.table.Vars, f) + appendGenericTypeAliases(sc.table.TypeAliases, f) + + sc.check(f.Decl.Scope, f.Scope) + + // Check return statements if scopeChecker not forced to stop. + if !sc.stopped() { + self.checkRets(f) + } + } + + fn checkFnInsCaller(mut &self, mut &f: &FnIns, mut caller: &Token) { + if f.Decl.Binded { + ret + } + + mut old := f.Decl.sema.file + defer { f.Decl.sema.setCurrentFile(old) } + mut file := findFile(f.Decl.sema.files, f.Decl.Token.File) + if file != nil { + f.Decl.sema.setCurrentFile(file) + } + + mut sc := newScopeChecker(f.Decl.sema, f) + sc.calledFrom = caller + self.checkFnInsSc(f, sc) + + if f.Decl.sema != self { + self.errors = append(self.errors, f.Decl.sema.errors...) + f.Decl.sema.errors = nil + } + } + + fn checkFnIns(mut &self, mut &f: &FnIns) { + self.checkFnInsCaller(f, nil) + } + + fn checkFunc(mut &self, mut &f: &Fn) { + if f.Binded { + ret + } + + // Generic instances are checked instantly. + if len(f.Generics) > 0 { + ret + } + + for (_, mut ins) in f.Instances { + self.checkFnIns(ins) + } + } + + fn checkTestFn(mut self, mut &f: &FnIns) { + if f.Decl.Public { + self.pushErr(f.Decl.Token, LogMsg.PubTestFn) + self.pushSuggestion(LogMsg.RemovePubModifier) + ret + } + + if f.Decl.Unsafety || + !f.Decl.IsVoid() || + len(f.Decl.Generics) != 0 || + len(f.Params) != 1 || + f.Decl.Params[0].Mutable || + f.Decl.Params[0].Reference { + self.pushErr(f.Decl.Token, LogMsg.WrongTestFnDecl) + self.pushSuggestion(LogMsg.UseExpectedTestFnDecl) + ret + } + + mut sptr := f.Params[0].Kind.Sptr() + if sptr == nil { + self.pushErr(f.Decl.Token, LogMsg.WrongTestFnDecl) + self.pushSuggestion(LogMsg.UseExpectedTestFnDecl) + ret + } + + s := sptr.Elem.Struct() + if s == nil || !isStdPackage(s.Decl.Token.File.Path, "testing") { + self.pushErr(f.Decl.Token, LogMsg.WrongTestFnDecl) + self.pushSuggestion(LogMsg.UseExpectedTestFnDecl) + ret + } + } + + fn precheckFunc(mut &self, mut &f: &Fn) { + if f.Binded { + ret + } + + // Generic instances are checked instantly. + if len(f.Generics) > 0 { + ret + } + + if len(f.Instances) == 0 { + mut ins := f.instanceForce() + f.Instances = append(f.Instances, ins) + ok := self.reloadFnInsTypes(ins) + ins.reloaded = true + + if ok && hasDirective(f.Directives, Directive.Test) { + self.checkTestFn(ins) + } + } + } + + // Prechecks types of current package file's functions. + fn precheckFuncs(mut &self) { + for (_, mut decl) in self.file.Traits { + for (_, mut m) in decl.Methods { + self.precheckFunc(m) + } + } + for (_, mut decl) in self.file.Funcs { + self.precheckFunc(decl) + } + } + + // Checks types of current package file's functions. + fn checkFuncs(mut &self) { + for (_, mut decl) in self.file.Funcs { + self.checkFunc(decl) + } + } + + // Checks all types of all package files. + // Breaks checking if checked file failed. + fn checkPackageTypes(mut &self) { + for (_, mut f) in self.files { + self.setCurrentFile(f) + self.checkGlobals() + self.precheckFuncs() + // Check structures first, see developer reference (7). + // Check operators first, see developer reference (7.1), and (7.2). + self.precheckStructTypes() + } + if len(self.errors) > 0 { + ret + } + for (_, mut f) in self.files { + self.setCurrentFile(f) + self.checkFuncs() + self.checkStructTypes() + } + } + + fn setFileSemaFields(mut &self) { + for (_, mut f) in self.file.Funcs { + f.sema = self + } + for (_, mut st) in self.file.Structs { + st.sema = self + } + } + + fn setSemaFields(mut &self) { + for (_, mut file) in self.files { + self.setCurrentFile(file) + self.setFileSemaFields() + } + } + + fn check(mut &self, mut &files: []&SymbolTable) { + self.files = files + + self.checkImports() + if len(self.errors) != 0 { + ret + } + + self.setSemaFields() + + self.checkInherits() + if len(self.errors) != 0 { + ret + } + + self.implImpls() + if len(self.errors) != 0 { + ret + } + + // Check enums here. + // See developer reference (8). + self.checkEnums() + if len(self.errors) != 0 { + ret + } + + self.checkPackageDecls() + if len(self.errors) != 0 { + ret + } + + self.checkPackageTypes() + } } struct missingRetChecker { - mut breaked: []uintptr - mut falled: bool + mut breaked: []uintptr + mut falled: bool } impl missingRetChecker { - static fn new(): missingRetChecker { - ret missingRetChecker{ - breaked: make([]uintptr, 1 << 4), - } - } - - fn checkConditional(self, mut c: &Conditional): bool { - for (_, mut elif) in c.Elifs { - if elif == nil { - ret false - } - if !self.checkScope(elif.Scope) { - ret false - } - } - ret c.Default != nil && self.checkScope(c.Default.Scope) - } - - fn checkMatch(self, mut m: &Match): bool { - for (_, mut c) in m.Cases { - if c == nil { - ret false - } - n := len(self.breaked) - ok := self.checkScope(c.Scope) - match { - | n != len(self.breaked): - ret false - | !ok: - if !self.falled { - ret false - } - fall - | self.falled: - self.falled = false - if c.Next == nil { - ret false - } - continue - } - } - ret m.Default != nil && self.checkScope(m.Default.Scope) - } - - fn checkInfIter(self, mut it: &InfIter): bool { - n := len(self.breaked) - if self.checkScope(it.Scope) { - self.breaked = self.breaked[:n] - ret true - } - if n != len(self.breaked) { - itaddr := uintptr(it) - for _, addr in self.breaked[n:] { - if itaddr == addr { - self.breaked = self.breaked[:n] - ret false - } - } - self.breaked = self.breaked[:n] - } - ret true - } - - fn checkScope(self, mut s: &Scope): bool { - if s == nil { - ret false - } - for (_, mut st) in s.Stmts { - match type st { - | &FallSt: - self.falled = true - ret false - | &BreakSt: - addr := (&BreakSt)(st).It - if addr != 0 { - self.breaked = append(self.breaked, addr) - } - ret false - | &ContSt: - ret false - | &InfIter: - if self.checkInfIter((&InfIter)(st)) { - ret true - } - | &RetSt: - ret true - | &Scope: - if self.checkScope((&Scope)(st)) { - ret true - } - | &Data: - match type (&Data)(st).Model { - | &BuiltinPanicCallExprModel - | &BuiltinErrorCallExprModel: - ret true - } - | &Conditional: - if self.checkConditional((&Conditional)(st)) { - ret true - } - | &Match: - if self.checkMatch((&Match)(st)) { - ret true - } - } - } - ret false - } - - fn check(self, mut s: &Scope): bool { - ret self.checkScope(s) - } + static fn new(): missingRetChecker { + ret missingRetChecker{ + breaked: make([]uintptr, 1 << 4), + } + } + + fn checkConditional(self, mut c: &Conditional): bool { + for (_, mut elif) in c.Elifs { + if elif == nil { + ret false + } + if !self.checkScope(elif.Scope) { + ret false + } + } + ret c.Default != nil && self.checkScope(c.Default.Scope) + } + + fn checkMatch(self, mut m: &Match): bool { + for (_, mut c) in m.Cases { + if c == nil { + ret false + } + n := len(self.breaked) + ok := self.checkScope(c.Scope) + match { + | n != len(self.breaked): + ret false + | !ok: + if !self.falled { + ret false + } + fall + | self.falled: + self.falled = false + if c.Next == nil { + ret false + } + continue + } + } + ret m.Default != nil && self.checkScope(m.Default.Scope) + } + + fn checkInfIter(self, mut it: &InfIter): bool { + n := len(self.breaked) + if self.checkScope(it.Scope) { + self.breaked = self.breaked[:n] + ret true + } + if n != len(self.breaked) { + itaddr := uintptr(it) + for _, addr in self.breaked[n:] { + if itaddr == addr { + self.breaked = self.breaked[:n] + ret false + } + } + self.breaked = self.breaked[:n] + } + ret true + } + + fn checkScope(self, mut s: &Scope): bool { + if s == nil { + ret false + } + for (_, mut st) in s.Stmts { + match type st { + | &FallSt: + self.falled = true + ret false + | &BreakSt: + addr := (&BreakSt)(st).It + if addr != 0 { + self.breaked = append(self.breaked, addr) + } + ret false + | &ContSt: + ret false + | &InfIter: + if self.checkInfIter((&InfIter)(st)) { + ret true + } + | &RetSt: + ret true + | &Scope: + if self.checkScope((&Scope)(st)) { + ret true + } + | &Data: + match type (&Data)(st).Model { + | &BuiltinPanicCallExprModel + | &BuiltinErrorCallExprModel: + ret true + } + | &Conditional: + if self.checkConditional((&Conditional)(st)) { + ret true + } + | &Match: + if self.checkMatch((&Match)(st)) { + ret true + } + } + } + ret false + } + + fn check(self, mut s: &Scope): bool { + ret self.checkScope(s) + } } fn pushImplemented(mut t: &Trait, mut &d: &Struct) { push: - match { - | len(t.Implemented) > 0: - for _, s in t.Implemented { - if s == d { - break push - } - } - fall - |: - t.Implemented = append(t.Implemented, d) - } - for (_, mut i) in t.Inherits { - pushImplemented(i.Kind.Trait(), d) - } + match { + | len(t.Implemented) > 0: + for _, s in t.Implemented { + if s == d { + break push + } + } + fall + |: + t.Implemented = append(t.Implemented, d) + } + for (_, mut i) in t.Inherits { + pushImplemented(i.Kind.Trait(), d) + } } fn pushImplements(mut &s: &Struct, mut t: &Trait) { push: - match { - | len(s.Implements) > 0: - for _, b in s.Implements { - if b == t { - break push - } - } - fall - |: - s.Implements = append(s.Implements, t) - } - for (_, mut i) in t.Inherits { - pushImplements(s, i.Kind.Trait()) - } + match { + | len(s.Implements) > 0: + for _, b in s.Implements { + if b == t { + break push + } + } + fall + |: + s.Implements = append(s.Implements, t) + } + for (_, mut i) in t.Inherits { + pushImplements(s, i.Kind.Trait()) + } } \ No newline at end of file diff --git a/std/jule/sema/struct.jule b/std/jule/sema/struct.jule index cbb4094eb..3e8577a72 100644 --- a/std/jule/sema/struct.jule +++ b/std/jule/sema/struct.jule @@ -9,320 +9,320 @@ use std::internal::strings::{StrBuilder} // Field. struct Field { - Owner: &Struct - Token: &Token - Public: bool - Mutable: bool // Interior mutability. - Ident: str - Kind: &TypeSymbol - Default: &Expr // Nil if not given. + Owner: &Struct + Token: &Token + Public: bool + Mutable: bool // Interior mutability. + Ident: str + Kind: &TypeSymbol + Default: &Expr // Nil if not given. } impl Field { - fn instance(mut &self): &FieldIns { - ret &FieldIns{ - Decl: self, - } - } + fn instance(mut &self): &FieldIns { + ret &FieldIns{ + Decl: self, + } + } } // Overloaded operators for instance. // Patterns are checked. struct Operators { - Eq: &FnIns - Gt: &FnIns - GtEq: &FnIns - Lt: &FnIns - LtEq: &FnIns - Shl: &FnIns - Shr: &FnIns - Add: &FnIns - Sub: &FnIns - Div: &FnIns - Mul: &FnIns - Mod: &FnIns - BitAnd: &FnIns - BitOr: &FnIns - BitXor: &FnIns - Neg: &FnIns - Pos: &FnIns - BitNot: &FnIns - AddAssign: &FnIns - SubAssign: &FnIns - DivAssign: &FnIns - MulAssign: &FnIns - ModAssign: &FnIns - ShlAssign: &FnIns - ShrAssign: &FnIns - BitOrAssign: &FnIns - BitAndAssign: &FnIns - BitXorAssign: &FnIns + Eq: &FnIns + Gt: &FnIns + GtEq: &FnIns + Lt: &FnIns + LtEq: &FnIns + Shl: &FnIns + Shr: &FnIns + Add: &FnIns + Sub: &FnIns + Div: &FnIns + Mul: &FnIns + Mod: &FnIns + BitAnd: &FnIns + BitOr: &FnIns + BitXor: &FnIns + Neg: &FnIns + Pos: &FnIns + BitNot: &FnIns + AddAssign: &FnIns + SubAssign: &FnIns + DivAssign: &FnIns + MulAssign: &FnIns + ModAssign: &FnIns + ShlAssign: &FnIns + ShrAssign: &FnIns + BitOrAssign: &FnIns + BitAndAssign: &FnIns + BitXorAssign: &FnIns } // Structure. struct Struct { - // Used for type parsing. - // Used declaration'sema sema for instance type checking. - sema: &Sema - - // This structure depended to these structures, except binded ones. - // Only stores plain identifier references such as A, B, and MyStruct. - // Not includes non-pain identifier references such as *A, &B, and []MyStruct. - Depends: []&Struct - - // This structures uses these structures. - // Stores all referred structures. - Uses: []&Struct - - Token: &Token - Ident: str - Fields: []&Field - Methods: []&Fn - Statics: []&Var - Public: bool - Binded: bool - Directives: []&Directive - Generics: []&GenericDecl - Implements: []&Trait - - // Structure instances for each unique type combination of structure. - // Nil if structure is never used. - Instances: []&StructIns + // Used for type parsing. + // Used declaration'sema sema for instance type checking. + sema: &Sema + + // This structure depended to these structures, except binded ones. + // Only stores plain identifier references such as A, B, and MyStruct. + // Not includes non-pain identifier references such as *A, &B, and []MyStruct. + Depends: []&Struct + + // This structures uses these structures. + // Stores all referred structures. + Uses: []&Struct + + Token: &Token + Ident: str + Fields: []&Field + Methods: []&Fn + Statics: []&Var + Public: bool + Binded: bool + Directives: []&Directive + Generics: []&GenericDecl + Implements: []&Trait + + // Structure instances for each unique type combination of structure. + // Nil if structure is never used. + Instances: []&StructIns } impl Struct { - fn instance(mut &self): &StructIns { - // Returns already created instance for just one unique combination. - if len(self.Generics) == 0 && len(self.Instances) == 1 { - ret self.Instances[0] - } - - mut ins := &StructIns{ - Decl: self, - Fields: make([]&FieldIns, 0, len(self.Fields)), - Statics: make([]&Var, 0, len(self.Statics)), - Refers: ReferenceStack.new(), - } - - for (_, mut s) in self.Statics { - ins.Statics = append(ins.Statics, new(Var, *s)) - } - - for (_, mut f) in self.Fields { - ins.Fields = append(ins.Fields, f.instance()) - if !f.Mutable && f.Kind.Kind != nil && f.Kind.Kind.Mutable() { - ins.Mutable = true - } - } - - if len(self.Generics) == 0 { - ins.Methods = self.Methods - } else { - ins.Methods = make([]&Fn, 0, len(self.Methods)) - for (_, mut f) in self.Methods { - mut fins := new(Fn, *f) - fins.Instances = nil - ins.Methods = append(ins.Methods, fins) - } - } - - ret ins - } - - // Appends instance if unique. - // Returns already exist instance if given insance is not unique. - fn appendInstance(mut self, mut &ins: &StructIns): &StructIns { - // Skip already created instance for just one unique combination. - if len(self.Generics) == 0 && len(self.Instances) == 1 { - ret self.Instances[0] - } - - for (_, mut ains) in self.Instances { - if ains.Same(ins) { - ret ains - } - } - - self.Instances = append(self.Instances, ins) - ret nil - } - - // Returns method by identifier. - // Returns nil reference if not exist any method in this identifier. - fn FindMethod(mut self, ident: str, statically: bool): &Fn { - for (_, mut f) in self.Methods { - if f.Statically == statically && f.Ident == ident { - ret f - } - } - ret nil - } - - // Returns static field by identifier. - // Returns nil reference if not exist any static field in this identifier. - fn FindStatic(mut self, ident: str): &Var { - for (_, mut v) in self.Statics { - if v.Ident == ident { - ret v - } - } - ret nil - } - - // Returns field by identifier. - // Returns nil reference if not exist any field in this identifier. - fn FindField(mut self, ident: str): &Field { - for (_, mut f) in self.Fields { - if f.Ident == ident { - ret f - } - } - ret nil - } - - // Reports whether structure implements given trait. - fn IsImplements(self, t: &Trait): bool { - for _, it in self.Implements { - if t == it { - ret true - } - } - ret false - } - - // Reports whether structure is uses given structure. - fn IsUses(self, s: &Struct): bool { - for _, u in self.Uses { - for s == u { - ret true - } - } - ret false - } - - // Reports whether structure has only reference-type-accessible defines. - fn HasRefAccessible(self): bool { - for _, m in self.Methods { - if len(m.Params) > 0 && m.Params[0].IsRef() { - ret true - } - } - ret false - } + fn instance(mut &self): &StructIns { + // Returns already created instance for just one unique combination. + if len(self.Generics) == 0 && len(self.Instances) == 1 { + ret self.Instances[0] + } + + mut ins := &StructIns{ + Decl: self, + Fields: make([]&FieldIns, 0, len(self.Fields)), + Statics: make([]&Var, 0, len(self.Statics)), + Refers: ReferenceStack.new(), + } + + for (_, mut s) in self.Statics { + ins.Statics = append(ins.Statics, new(Var, *s)) + } + + for (_, mut f) in self.Fields { + ins.Fields = append(ins.Fields, f.instance()) + if !f.Mutable && f.Kind.Kind != nil && f.Kind.Kind.Mutable() { + ins.Mutable = true + } + } + + if len(self.Generics) == 0 { + ins.Methods = self.Methods + } else { + ins.Methods = make([]&Fn, 0, len(self.Methods)) + for (_, mut f) in self.Methods { + mut fins := new(Fn, *f) + fins.Instances = nil + ins.Methods = append(ins.Methods, fins) + } + } + + ret ins + } + + // Appends instance if unique. + // Returns already exist instance if given insance is not unique. + fn appendInstance(mut self, mut &ins: &StructIns): &StructIns { + // Skip already created instance for just one unique combination. + if len(self.Generics) == 0 && len(self.Instances) == 1 { + ret self.Instances[0] + } + + for (_, mut ains) in self.Instances { + if ains.Same(ins) { + ret ains + } + } + + self.Instances = append(self.Instances, ins) + ret nil + } + + // Returns method by identifier. + // Returns nil reference if not exist any method in this identifier. + fn FindMethod(mut self, ident: str, statically: bool): &Fn { + for (_, mut f) in self.Methods { + if f.Statically == statically && f.Ident == ident { + ret f + } + } + ret nil + } + + // Returns static field by identifier. + // Returns nil reference if not exist any static field in this identifier. + fn FindStatic(mut self, ident: str): &Var { + for (_, mut v) in self.Statics { + if v.Ident == ident { + ret v + } + } + ret nil + } + + // Returns field by identifier. + // Returns nil reference if not exist any field in this identifier. + fn FindField(mut self, ident: str): &Field { + for (_, mut f) in self.Fields { + if f.Ident == ident { + ret f + } + } + ret nil + } + + // Reports whether structure implements given trait. + fn IsImplements(self, t: &Trait): bool { + for _, it in self.Implements { + if t == it { + ret true + } + } + ret false + } + + // Reports whether structure is uses given structure. + fn IsUses(self, s: &Struct): bool { + for _, u in self.Uses { + for s == u { + ret true + } + } + ret false + } + + // Reports whether structure has only reference-type-accessible defines. + fn HasRefAccessible(self): bool { + for _, m in self.Methods { + if len(m.Params) > 0 && m.Params[0].IsRef() { + ret true + } + } + ret false + } } // Field instance. struct FieldIns { - Decl: &Field - Kind: &TypeKind - Default: &Data // Nil if not given. + Decl: &Field + Kind: &TypeKind + Default: &Data // Nil if not given. } // Structure instance. struct StructIns { - Checked: bool - Decl: &Struct - Generics: []&InsGeneric - Fields: []&FieldIns - Statics: []&Var - Methods: []&Fn - Mutable: bool // This structure has mutable defines. - Comparable: bool - Refers: &ReferenceStack - Operators: Operators + Checked: bool + Decl: &Struct + Generics: []&InsGeneric + Fields: []&FieldIns + Statics: []&Var + Methods: []&Fn + Mutable: bool // This structure has mutable defines. + Comparable: bool + Refers: &ReferenceStack + Operators: Operators } impl Kind for StructIns { - // Implement: Kind - // Returns Struct's type kind as string. - fn Str(self): str { - mut kind := StrBuilder.New(1 << 5) - kind.WriteStr(self.Decl.Ident) - if len(self.Generics) > 0 { - kind.WriteByte('[') - for i, g in self.Generics { - kind.WriteStr(g.Kind.Str()) - if i < len(self.Generics)-1 { - kind.WriteByte(',') - } - } - kind.WriteByte(']') - } - ret kind.Str() - } - - // Reports whether types are same. - fn Equal(&self, other: &TypeKind): bool { - s := unsafe { (*(&other)).Struct() } - if s == nil { - ret false - } - - if self.Decl != s.Decl { - ret false - } - - if len(self.Generics) != len(s.Generics) { - ret false - } - - mut i := 0 - for i < len(self.Generics); i++ { - if !self.Generics[i].Kind.Equal(s.Generics[i].Kind) { - ret false - } - } - - ret true - } + // Implement: Kind + // Returns Struct's type kind as string. + fn Str(self): str { + mut kind := StrBuilder.New(1 << 5) + kind.WriteStr(self.Decl.Ident) + if len(self.Generics) > 0 { + kind.WriteByte('[') + for i, g in self.Generics { + kind.WriteStr(g.Kind.Str()) + if i < len(self.Generics)-1 { + kind.WriteByte(',') + } + } + kind.WriteByte(']') + } + ret kind.Str() + } + + // Reports whether types are same. + fn Equal(&self, other: &TypeKind): bool { + s := unsafe { (*(&other)).Struct() } + if s == nil { + ret false + } + + if self.Decl != s.Decl { + ret false + } + + if len(self.Generics) != len(s.Generics) { + ret false + } + + mut i := 0 + for i < len(self.Generics); i++ { + if !self.Generics[i].Kind.Equal(s.Generics[i].Kind) { + ret false + } + } + + ret true + } } impl StructIns { - // Reports whether instances are same. - // Returns true if declarations and generics are same. - fn Same(self, s: &StructIns): bool { - if self.Decl != s.Decl || len(s.Generics) != len(self.Generics) { - ret false - } - for i, g in self.Generics { - g2 := s.Generics[i] - if g.Kind.BindIdent != g2.Kind.BindIdent || !g.Kind.Equal(g2.Kind) { - ret false - } - } - ret true - } - - // Returns method by identifier. - // Returns nil reference if not exist any method in this identifier. - fn FindMethod(mut self, ident: str, statically: bool): &Fn { - for (_, mut f) in self.Methods { - if f.Statically == statically && f.Ident == ident { - ret f - } - } - ret nil - } - - // Returns field by identifier. - // Returns nil reference if not exist any field in this identifier. - fn FindField(mut self, ident: str): &FieldIns { - for (_, mut f) in self.Fields { - if f.Decl.Ident == ident { - ret f - } - } - ret nil - } - - // Returns static field by identifier. - // Returns nil reference if not exist any static field in this identifier. - fn FindStatic(mut self, ident: str): &Var { - for (_, mut v) in self.Statics { - if v.Ident == ident { - ret v - } - } - ret nil - } + // Reports whether instances are same. + // Returns true if declarations and generics are same. + fn Same(self, s: &StructIns): bool { + if self.Decl != s.Decl || len(s.Generics) != len(self.Generics) { + ret false + } + for i, g in self.Generics { + g2 := s.Generics[i] + if g.Kind.BindIdent != g2.Kind.BindIdent || !g.Kind.Equal(g2.Kind) { + ret false + } + } + ret true + } + + // Returns method by identifier. + // Returns nil reference if not exist any method in this identifier. + fn FindMethod(mut self, ident: str, statically: bool): &Fn { + for (_, mut f) in self.Methods { + if f.Statically == statically && f.Ident == ident { + ret f + } + } + ret nil + } + + // Returns field by identifier. + // Returns nil reference if not exist any field in this identifier. + fn FindField(mut self, ident: str): &FieldIns { + for (_, mut f) in self.Fields { + if f.Decl.Ident == ident { + ret f + } + } + ret nil + } + + // Returns static field by identifier. + // Returns nil reference if not exist any static field in this identifier. + fn FindStatic(mut self, ident: str): &Var { + for (_, mut v) in self.Statics { + if v.Ident == ident { + ret v + } + } + ret nil + } } \ No newline at end of file diff --git a/std/jule/sema/symbol.jule b/std/jule/sema/symbol.jule index bcc976428..cee98d321 100644 --- a/std/jule/sema/symbol.jule +++ b/std/jule/sema/symbol.jule @@ -5,34 +5,34 @@ use std::fs::{FsError, Status} use path for std::fs::path use ast for std::jule::ast::{ - Ast, - TypeDecl, - TypeAliasDecl, - FieldDecl, - TypeEnumDecl, - TypeEnumItemDecl, - EnumDecl, - EnumItemDecl, - VarDecl, - TraitDecl, - StructDecl, - ParamDecl, - FnDecl, - RetTypeDecl, - Node, - Expr, - UseDecl, + Ast, + TypeDecl, + TypeAliasDecl, + FieldDecl, + TypeEnumDecl, + TypeEnumItemDecl, + EnumDecl, + EnumItemDecl, + VarDecl, + TraitDecl, + StructDecl, + ParamDecl, + FnDecl, + RetTypeDecl, + Node, + Expr, + UseDecl, } use std::jule::build::{ - PathStdlib, - LogMsg, - Log, - LogKind, - Directive, - Logf, - IsStdHeaderPath, - IsValidHeaderExt, - IsValidCppExt, + PathStdlib, + LogMsg, + Log, + LogKind, + Directive, + Logf, + IsStdHeaderPath, + IsValidHeaderExt, + IsValidCppExt, } use std::jule::lex::{Token, TokenId, TokenKind} use strings for std::strings::{StrBuilder} @@ -46,737 +46,737 @@ use strings for std::strings::{StrBuilder} // - &Trait // - &Var -> Only global ones. struct ReferenceStack { - buffer: []any + buffer: []any } impl ReferenceStack { - // Returns new reference stack instance. - static fn new(): &ReferenceStack { - ret &ReferenceStack{ - buffer: make([]any, 0, 10), - } - } + // Returns new reference stack instance. + static fn new(): &ReferenceStack { + ret &ReferenceStack{ + buffer: make([]any, 0, 10), + } + } } impl ReferenceStack { - // Returns count of references. - fn Len(self): int { - ret len(self.buffer) - } - - // Returns reference by index. - fn At(mut self, i: int): any { - ret self.buffer[i] - } - - // Push new reference to stack. - fn Push(mut self, mut ref: any) { - self.buffer = append(self.buffer, ref) - } - - // Reports whether reference is exist. - fn Exist[T](self, t: T): bool { - for _, ref in self.buffer { - if ref == t { - ret true - } - } - ret false - } + // Returns count of references. + fn Len(self): int { + ret len(self.buffer) + } + + // Returns reference by index. + fn At(mut self, i: int): any { + ret self.buffer[i] + } + + // Push new reference to stack. + fn Push(mut self, mut ref: any) { + self.buffer = append(self.buffer, ref) + } + + // Reports whether reference is exist. + fn Exist[T](self, t: T): bool { + for _, ref in self.buffer { + if ref == t { + ret true + } + } + ret false + } } // Directive pass. struct Pass { - Token: &Token - Text: str + Token: &Token + Text: str } fn buildType(mut t: &TypeDecl): &TypeSymbol { - if t == nil { - ret nil - } - ret &TypeSymbol{ - Decl: t, - } + if t == nil { + ret nil + } + ret &TypeSymbol{ + Decl: t, + } } fn buildExpr(mut expr: &Expr): &Value { - if expr == nil { - ret nil - } - ret &Value{ - Expr: expr, - } + if expr == nil { + ret nil + } + ret &Value{ + Expr: expr, + } } fn buildTypeAlias(mut decl: &TypeAliasDecl): &TypeAlias { - ret &TypeAlias{ - Scope: decl.Scope, - Public: decl.Public, - Binded: decl.Binded, - Token: decl.Token, - Ident: decl.Ident, - Kind: buildType(decl.Kind), - } + ret &TypeAlias{ + Scope: decl.Scope, + Public: decl.Public, + Binded: decl.Binded, + Token: decl.Token, + Ident: decl.Ident, + Kind: buildType(decl.Kind), + } } fn buildField(mut decl: &FieldDecl): &Field { - ret &Field{ - Token: decl.Token, - Public: decl.Public, - Mutable: decl.Mutable, - Ident: decl.Ident, - Kind: buildType(decl.Kind), - Default: decl.Default, - } + ret &Field{ + Token: decl.Token, + Public: decl.Public, + Mutable: decl.Mutable, + Ident: decl.Ident, + Kind: buildType(decl.Kind), + Default: decl.Default, + } } fn buildFields(mut &decls: []&FieldDecl): []&Field { - mut fields := make([]&Field, 0, len(decls)) - for (_, mut decl) in decls { - fields = append(fields, buildField(decl)) - } - ret fields + mut fields := make([]&Field, 0, len(decls)) + for (_, mut decl) in decls { + fields = append(fields, buildField(decl)) + } + ret fields } fn buildStruct(mut decl: &StructDecl): &Struct { - ret &Struct{ - Token: decl.Token, - Ident: decl.Ident, - Fields: buildFields(decl.Fields), - Public: decl.Public, - Binded: decl.Binded, - Directives: decl.Directives, - Generics: decl.Generics, - } + ret &Struct{ + Token: decl.Token, + Ident: decl.Ident, + Fields: buildFields(decl.Fields), + Public: decl.Public, + Binded: decl.Binded, + Directives: decl.Directives, + Generics: decl.Generics, + } } fn buildParam(mut decl: &ParamDecl): &Param { - ret &Param{ - Token: decl.Token, - Mutable: decl.Mutable, - Variadic: decl.Variadic, - Reference: decl.Reference, - Kind: buildType(decl.Kind), - Ident: decl.Ident, - } + ret &Param{ + Token: decl.Token, + Mutable: decl.Mutable, + Variadic: decl.Variadic, + Reference: decl.Reference, + Kind: buildType(decl.Kind), + Ident: decl.Ident, + } } fn buildParams(mut &decls: []&ParamDecl): []&Param { - mut params := make([]&Param, 0, len(decls)) - for (_, mut decl) in decls { - params = append(params, buildParam(decl)) - } - ret params + mut params := make([]&Param, 0, len(decls)) + for (_, mut decl) in decls { + params = append(params, buildParam(decl)) + } + ret params } fn buildRetType(mut decl: &RetTypeDecl): &RetType { - if decl.Idents == nil && decl.Kind == nil { - ret nil // Void type. - } - ret &RetType{ - Kind: buildType(decl.Kind), - Idents: decl.Idents, - } + if decl.Idents == nil && decl.Kind == nil { + ret nil // Void type. + } + ret &RetType{ + Kind: buildType(decl.Kind), + Idents: decl.Idents, + } } fn buildFunc(mut decl: &FnDecl): &Fn { - ret &Fn{ - Token: decl.Token, - Global: decl.Global, - Unsafety: decl.Unsafety, - Public: decl.Public, - Binded: decl.Binded, - Statically: decl.Statically, - Exceptional: decl.Exceptional, - Ident: decl.Ident, - Directives: decl.Directives, - Scope: decl.Scope, - Generics: decl.Generics, - Result: buildRetType(decl.Result), - Params: buildParams(decl.Params), - } + ret &Fn{ + Token: decl.Token, + Global: decl.Global, + Unsafety: decl.Unsafety, + Public: decl.Public, + Binded: decl.Binded, + Statically: decl.Statically, + Exceptional: decl.Exceptional, + Ident: decl.Ident, + Directives: decl.Directives, + Scope: decl.Scope, + Generics: decl.Generics, + Result: buildRetType(decl.Result), + Params: buildParams(decl.Params), + } } fn buildMethods(mut &decls: []&FnDecl): []&Fn { - mut methods := make([]&Fn, 0, len(decls)) - for (_, mut decl) in decls { - methods = append(methods, buildFunc(decl)) - } - ret methods + mut methods := make([]&Fn, 0, len(decls)) + for (_, mut decl) in decls { + methods = append(methods, buildFunc(decl)) + } + ret methods } fn buildTraitInherits(mut &inherits: []&TypeDecl): []&TypeSymbol { - mut symbols := make([]&TypeSymbol, 0, len(inherits)) - for (_, mut it) in inherits { - symbols = append(symbols, buildType(it)) - } - ret symbols + mut symbols := make([]&TypeSymbol, 0, len(inherits)) + for (_, mut it) in inherits { + symbols = append(symbols, buildType(it)) + } + ret symbols } fn buildTrait(mut decl: &TraitDecl): &Trait { - ret &Trait{ - Token: decl.Token, - Ident: decl.Ident, - Public: decl.Public, - Methods: buildMethods(decl.Methods), - Inherits: buildTraitInherits(decl.Inherits), - } + ret &Trait{ + Token: decl.Token, + Ident: decl.Ident, + Public: decl.Public, + Methods: buildMethods(decl.Methods), + Inherits: buildTraitInherits(decl.Inherits), + } } fn buildEnumItem(mut decl: &EnumItemDecl): &EnumItem { - ret &EnumItem{ - Token: decl.Token, - Ident: decl.Ident, - Value: buildExpr(decl.Expr), - } + ret &EnumItem{ + Token: decl.Token, + Ident: decl.Ident, + Value: buildExpr(decl.Expr), + } } fn buildEnumItems(mut &decls: []&EnumItemDecl): []&EnumItem { - mut items := make([]&EnumItem, 0, len(decls)) - for (_, mut decl) in decls { - items = append(items, buildEnumItem(decl)) - } - ret items + mut items := make([]&EnumItem, 0, len(decls)) + for (_, mut decl) in decls { + items = append(items, buildEnumItem(decl)) + } + ret items } fn buildEnum(mut decl: &EnumDecl): &Enum { - ret &Enum{ - Token: decl.Token, - Public: decl.Public, - Ident: decl.Ident, - Kind: buildType(decl.Kind), - Items: buildEnumItems(decl.Items), - } + ret &Enum{ + Token: decl.Token, + Public: decl.Public, + Ident: decl.Ident, + Kind: buildType(decl.Kind), + Items: buildEnumItems(decl.Items), + } } fn buildTypeEnumItem(mut decl: &TypeEnumItemDecl): &TypeEnumItem { - ret &TypeEnumItem{ - Token: decl.Token, - Ident: decl.Ident, - Kind: buildType(decl.Kind), - } + ret &TypeEnumItem{ + Token: decl.Token, + Ident: decl.Ident, + Kind: buildType(decl.Kind), + } } fn buildTypeEnumItems(mut &decls: []&TypeEnumItemDecl): []&TypeEnumItem { - mut items := make([]&TypeEnumItem, 0, len(decls)) - for (_, mut decl) in decls { - items = append(items, buildTypeEnumItem(decl)) - } - ret items + mut items := make([]&TypeEnumItem, 0, len(decls)) + for (_, mut decl) in decls { + items = append(items, buildTypeEnumItem(decl)) + } + ret items } fn buildTypeEnum(mut decl: &TypeEnumDecl): &TypeEnum { - ret &TypeEnum{ - Token: decl.Token, - Public: decl.Public, - Ident: decl.Ident, - Items: buildTypeEnumItems(decl.Items), - } + ret &TypeEnum{ + Token: decl.Token, + Public: decl.Public, + Ident: decl.Ident, + Items: buildTypeEnumItems(decl.Items), + } } fn buildVar(mut decl: &VarDecl): &Var { - ret &Var{ - Token: decl.Token, - Ident: decl.Ident, - Binded: decl.Binded, - Constant: decl.Constant, - Mutable: decl.Mutable, - Public: decl.Public, - Statically: decl.Statically, - Reference: decl.Reference, - Directives: decl.Directives, - Refers: ReferenceStack.new(), - Kind: buildType(decl.Kind), - Value: buildExpr(decl.Expr), - } + ret &Var{ + Token: decl.Token, + Ident: decl.Ident, + Binded: decl.Binded, + Constant: decl.Constant, + Mutable: decl.Mutable, + Public: decl.Public, + Statically: decl.Statically, + Reference: decl.Reference, + Directives: decl.Directives, + Refers: ReferenceStack.new(), + Kind: buildType(decl.Kind), + Value: buildExpr(decl.Expr), + } } fn buildVars(mut decls: []&VarDecl): []&Var { - mut vars := make([]&Var, 0, len(decls)) - for (_, mut decl) in decls { - vars = append(vars, buildVar(decl)) - } - ret vars + mut vars := make([]&Var, 0, len(decls)) + for (_, mut decl) in decls { + vars = append(vars, buildVar(decl)) + } + ret vars } fn buildImpl(mut decl: &ast::Impl): &Impl { - ret &Impl{ - Base: decl.Base, - Dest: decl.Dest, - Methods: buildMethods(decl.Methods), - Statics: buildVars(decl.Statics), - } + ret &Impl{ + Base: decl.Base, + Dest: decl.Dest, + Methods: buildMethods(decl.Methods), + Statics: buildVars(decl.Statics), + } } // Symbol table builder. // Just builds symbols, not analyze metadatas // like struct's implemented traits. struct symbolBuilder { - owner: &symbolBuilder - importer: Importer - errors: []Log - ast: &Ast - table: &SymbolTable + owner: &symbolBuilder + importer: Importer + errors: []Log + ast: &Ast + table: &SymbolTable } impl symbolBuilder { - fn getRoot(mut &self): &symbolBuilder { - mut root := self - for root.owner != nil { - root = root.owner - } - ret root - } - - fn pushErr(mut self, &token: &Token, fmt: LogMsg, args: ...any) { - self.errors = append(self.errors, compilerErr(token, true, fmt, args...)) - } - - fn pushErrText(mut self, &token: &Token, fmt: LogMsg, args: ...any) { - self.errors = append(self.errors, compilerErr(token, false, fmt, args...)) - } - - // Push suggestion to last log. - fn pushSuggestion(mut self, fmt: LogMsg, args: ...any) { - unsafe { pushSuggestion(&self.errors[len(self.errors)-1], fmt, args...) } - } - - fn checkCppUseDeclPath(mut self, &decl: &UseDecl, &path: str): (ok: bool) { - ext := path::Ext(path) - if !IsValidHeaderExt(ext) && !IsValidCppExt(ext) { - self.pushErr(decl.Token, LogMsg.InvalidCppExt, ext) - ret false - } - - // Exist? - info := Status.Of(path) else { - self.pushErr(decl.Token, LogMsg.UseNotFound, decl.LinkPath) - ret false - } - if info.IsDir() { - self.pushErr(decl.Token, LogMsg.UseNotFound, decl.LinkPath) - ret false - } - - ret true - } - - fn buildCppHeaderImport(mut self, mut &decl: &UseDecl): &ImportInfo { - mut path := decl.LinkPath - - if !IsStdHeaderPath(decl.LinkPath) { - path = path::Join(decl.Token.File.Dir(), decl.LinkPath) - mut ok := self.checkCppUseDeclPath(decl, path) - if !ok { - ret nil - } - - // Set to absolute path for correct include path. - path, ok = path::Abs(path) - if !ok { - self.pushErr(decl.Token, LogMsg.UseNotFound, decl.LinkPath) - } - } - - ret &ImportInfo{ - Token: decl.Token, - Path: path, - LinkPath: decl.LinkPath, - Ident: "", // Cpp headers haven't identifiers. - Binded: true, - Std: false, - Package: nil, // Cpp headers haven't symbol table. - } - } - - fn buildStdImport(mut self, mut &decl: &UseDecl): &ImportInfo { - // No need to check blank identifiers for standart packages. - mut path := decl.LinkPath[len("std::"):] // Skip "std::" prefix. - path = strings::Replace(path, TokenKind.DblColon, str(path::Separator), -1) - path = path::Join(PathStdlib, path) - path, ok := path::Abs(path) - if !ok { - self.pushErr(decl.Token, LogMsg.UseNotFound, decl.LinkPath) - ret nil - } - - // Exist? - info := Status.Of(path) else { - self.pushErr(decl.Token, LogMsg.UseNotFound, decl.LinkPath) - ret nil - } - if !info.IsDir() { - self.pushErr(decl.Token, LogMsg.UseNotFound, decl.LinkPath) - ret nil - } - - // Select last identifier of namespace chain. - i := strings::FindLast(decl.LinkPath, TokenKind.DblColon) + 1 - ident := decl.LinkPath[i:] - - ret &ImportInfo{ - ImportAll: decl.Full, - Token: decl.Token, - Path: path, - LinkPath: decl.LinkPath, - Ident: ident, - Alias: decl.Alias, - Binded: false, - Std: true, - Package: &Package{ - Files: nil, // Appends by import algorithm. - }, - } - } - - fn buildIdentImport(mut &self, mut &decl: &UseDecl): &ImportInfo { - if decl.LinkPath == "_" || - strings::Find(decl.LinkPath, "::_::") != -1 || - strings::HasSuffix(decl.LinkPath, "::_") { - self.pushErr(decl.Token, LogMsg.BlankIdentInUseDecl) - ret nil - } - - modPath := self.importer.GetModPath() - if len(modPath) == 0 { - self.pushErr(decl.Token, LogMsg.ModuleNotFound) - self.pushSuggestion(LogMsg.UseModInit) - ret nil - } - - mut path := decl.LinkPath - path = strings::Replace(path, TokenKind.DblColon, str(path::Separator), -1) - path = path::Join(modPath, path) - - path, ok := path::Abs(path) - if !ok { - self.pushErr(decl.Token, LogMsg.UseNotFound, decl.LinkPath) - ret nil - } - - // Exist? - info := Status.Of(path) else { - self.pushErr(decl.Token, LogMsg.UseNotFound, decl.LinkPath) - ret nil - } - if !info.IsDir() { - self.pushErr(decl.Token, LogMsg.UseNotFound, decl.LinkPath) - ret nil - } - - // Select last identifier of namespace chain. - i := strings::FindLast(decl.LinkPath, TokenKind.DblColon) + 1 - ident := decl.LinkPath[i:] - - ret &ImportInfo{ - ImportAll: decl.Full, - Token: decl.Token, - Path: path, - LinkPath: decl.LinkPath, - Ident: ident, - Alias: decl.Alias, - Binded: false, - Std: false, - Package: &Package{ - Files: nil, // Appends by import algorithm. - }, - } - } - - fn buildImport(mut &self, mut &decl: &UseDecl): &ImportInfo { - match { - | decl.Binded: - ret self.buildCppHeaderImport(decl) - | decl.Std: - ret self.buildStdImport(decl) - |: - ret self.buildIdentImport(decl) - } - } - - fn checkDuplicateUseDecl(mut self, &pkg: &ImportInfo): (ok: bool) { - // Find package by path to detect cpp header imports. - lpkg := self.table.SelectPackage(fn(spkg: &ImportInfo): bool { - ret unsafe { pkg.Path == spkg.Path } - }) - if lpkg == nil { - ret true - } - - self.pushErr(pkg.Token, LogMsg.DuplicateUseDecl, pkg.LinkPath) - self.pushSuggestion(LogMsg.RemoveUseDeclAvoidDuplication) - ret false - } - - fn implImportSelections(mut self, mut &imp: &ImportInfo, mut &decl: &UseDecl) { - imp.Selected = decl.Selected - for _, item in imp.Selected { - for _, citem in imp.Selected { - if item == citem { - break - } else if item.Kind == citem.Kind { - self.pushErr(item, LogMsg.DuplicatedUseSelection, item.Kind) - self.pushSuggestion(LogMsg.RemoveUseSelectionAvoidDupliation) - break - } - } - } - } - - fn getAsLinkPath(mut &self, mut path: str): str { - if strings::HasPrefix(path, PathStdlib) { - path = path[len(PathStdlib):] - ret "std" + strings::Replace(path, str(path::Separator), TokenKind.DblColon, -1) - } - - root, _ := path::Abs(self.importer.GetModPath()) - path = path[len(root):] - if path[0] == path::Separator { - path = path[1:] - } - ret strings::Replace(path, str(path::Separator), TokenKind.DblColon, -1) - } - - fn pushCycleError(mut &self, &sb: &symbolBuilder, path: str, mut &message: StrBuilder) { - const Padding = 7 - refersTo := Logf( - LogMsg.RefersTo, - self.getAsLinkPath(sb.table.File.Dir()), - self.getAsLinkPath(path)) - m := message.Str() - message.WriteStr(strings::Repeat(" ", Padding)) - message.WriteStr(refersTo) - message.WriteByte('\n') - message.WriteStr(m) - } - - fn pushCrossCycleError(mut &self, &target: &symbolBuilder, &imp: &ImportInfo, &errorToken: &Token) { - mut message := StrBuilder.New(1 << 5) - - self.pushCycleError(self, imp.Path, message) - - mut owner := self.owner - mut old := self - - for owner.owner != nil { - self.pushCycleError(old.owner, old.table.File.Dir(), message) - - if owner.owner == target { - self.pushCycleError(target, owner.table.File.Dir(), message) - break - } - - old = owner - owner = owner.owner - } - - self.pushErr(errorToken, LogMsg.PkgIllegalCrossCycle, message.Str()) - } - - fn checkImportCycles(mut &self, imp: &ImportInfo, &decl: &UseDecl): bool { - if imp.Path == self.table.File.Dir() { - self.pushErr(decl.Token, LogMsg.PkgIllegalCycleRefersItself, self.getAsLinkPath(imp.Path)) - ret false - } - - if self.owner == nil { - ret true - } - - mut owner := self.owner - iter: - if owner.table.File.Dir() == imp.Path { - self.pushCrossCycleError(owner, imp, decl.Token) - ret false - } - - if owner.owner != nil { - owner = owner.owner - goto iter - } - - ret true - } - - // Checks internal packages or etc. for accessibility. - // - // Parameters: - // - decl: relevant use declaration. - // - mod: module that imports relevant package. - // - path: path of package that importing. - fn checkPackageAccessibility(mut self, &decl: &UseDecl, &mod: str, &path: str) { - if self.importer.GetModPath() != mod && strings::Contains(path, "internal") { - self.pushErr(decl.Token, LogMsg.UseDeclForInternal) - } - } - - fn importPackage(mut &self, mut &imp: &ImportInfo, mut &decl: &UseDecl): (ok: bool) { - if imp.Binded { - ret true - } - - mut port := self.importer.GetImport(imp.Path) - if port != nil { - imp.Package = port.Package - imp.Duplicate = true - - oldMod := self.importer.GetModPath() - self.importer.SetModPath(self.importer.ModById(imp.ModId)) - self.checkPackageAccessibility(decl, oldMod, port.Path) - self.importer.SetModPath(oldMod) - } else { - if !self.checkImportCycles(imp, decl) { - ret false - } - - oldMod := self.importer.GetModPath() - defer { self.importer.SetModPath(oldMod) } - if imp.Std { - self.importer.SetModPath(PathStdlib) - } - mut asts, mut errors := self.importer.ImportPackage(imp.Path, !imp.Std) - if len(errors) > 0 { - self.errors = append(self.errors, errors...) - ret false - } - - self.checkPackageAccessibility(decl, oldMod, imp.Path) - - for (_, mut ast) in asts { - let mut table: &SymbolTable = nil - table, errors = buildSymbols(ast, self.importer, self) - // Break import if file has error(s). - if len(errors) > 0 { - self.errors = append(self.errors, errors...) - ret false - } - imp.Package.Files = append(imp.Package.Files, table) - } - } - self.implImportSelections(imp, decl) - ret true - } - - fn importUseDecl(mut &self, mut &decl: &UseDecl): &ImportInfo { - mut imp := self.buildImport(decl) - // Break analysis if error occurs. - if imp == nil { - ret nil - } - - mut ok := self.checkDuplicateUseDecl(imp) - if !ok { - ret nil - } - - ok = self.importPackage(imp, decl) - self.table.Imports = append(self.table.Imports, imp) - if ok { - self.importer.Imported(imp) - ret imp - } - ret nil - } - - fn importUseDecls(mut &self) { - for (_, mut decl) in self.ast.UseDecls { - self.importUseDecl(decl) - // Break analysis if error occurs. - if len(self.errors) > 0 { - break - } - } - } - - fn appendNode(mut self, mut &node: Node) { - match type node.Data { - | &ast::Impl: - self.table.Impls = append(self.table.Impls, buildImpl((&ast::Impl)(node.Data))) - | &TypeAliasDecl: - mut ta := buildTypeAlias((&TypeAliasDecl)(node.Data)) - self.table.TypeAliases = append(self.table.TypeAliases, ta) - | &StructDecl: - mut srct := buildStruct((&StructDecl)(node.Data)) - self.table.Structs = append(self.table.Structs, srct) - | &FnDecl: - mut f := buildFunc((&FnDecl)(node.Data)) - self.table.Funcs = append(self.table.Funcs, f) - | &TraitDecl: - mut t := buildTrait((&TraitDecl)(node.Data)) - self.table.Traits = append(self.table.Traits, t) - | &VarDecl: - mut v := buildVar((&VarDecl)(node.Data)) - self.table.Vars = append(self.table.Vars, v) - | &EnumDecl: - mut e := buildEnum((&EnumDecl)(node.Data)) - self.table.Enums = append(self.table.Enums, e) - | &TypeEnumDecl: - mut e := buildTypeEnum((&TypeEnumDecl)(node.Data)) - self.table.TypeEnums = append(self.table.TypeEnums, e) - |: - self.pushErr(node.Token, LogMsg.InvalidSyntax) - } - } - - fn appendNodes(mut self) { - for (_, mut node) in self.ast.Nodes { - self.appendNode(node) - } - } - - fn pushDirectivePass(mut self, mut &d: &ast::Directive) { - if len(d.Args) == 0 { - self.pushErr(d.Tag, LogMsg.MissingExpr) - ret - } else if len(d.Args) > 1 { - arg := d.Args[1] - self.pushErr(arg, LogMsg.ArgumentOverflow, d.Tag.Kind) - } - - arg := d.Args[0] - if arg.Id != TokenId.Lit { - self.pushErr(arg, LogMsg.InvalidSyntax) - ret - } - - if arg.Kind[0] != '"' { - self.pushErr(arg, LogMsg.InvalidSyntax) - ret - } - - self.table.Passes = append(self.table.Passes, Pass{ - Token: d.Tag, - Text: arg.Kind[1:len(arg.Kind)-1], - }) - } - - fn appendTopDirectives(mut self) { - for (_, mut d) in self.ast.TopDirectives { - match d.Tag.Kind { - | Directive.Pass: - self.pushDirectivePass(d) - } - } - } - - fn build(mut &self) { - self.table = &SymbolTable{ - File: self.ast.File, - } - - self.appendTopDirectives() - - self.importUseDecls() - // Break analysis if use declarations has error. - if len(self.errors) > 0 { - ret - } - - self.appendNodes() - // Break analysis if declarations has error. - if len(self.errors) > 0 { - ret - } - } + fn getRoot(mut &self): &symbolBuilder { + mut root := self + for root.owner != nil { + root = root.owner + } + ret root + } + + fn pushErr(mut self, &token: &Token, fmt: LogMsg, args: ...any) { + self.errors = append(self.errors, compilerErr(token, true, fmt, args...)) + } + + fn pushErrText(mut self, &token: &Token, fmt: LogMsg, args: ...any) { + self.errors = append(self.errors, compilerErr(token, false, fmt, args...)) + } + + // Push suggestion to last log. + fn pushSuggestion(mut self, fmt: LogMsg, args: ...any) { + unsafe { pushSuggestion(&self.errors[len(self.errors)-1], fmt, args...) } + } + + fn checkCppUseDeclPath(mut self, &decl: &UseDecl, &path: str): (ok: bool) { + ext := path::Ext(path) + if !IsValidHeaderExt(ext) && !IsValidCppExt(ext) { + self.pushErr(decl.Token, LogMsg.InvalidCppExt, ext) + ret false + } + + // Exist? + info := Status.Of(path) else { + self.pushErr(decl.Token, LogMsg.UseNotFound, decl.LinkPath) + ret false + } + if info.IsDir() { + self.pushErr(decl.Token, LogMsg.UseNotFound, decl.LinkPath) + ret false + } + + ret true + } + + fn buildCppHeaderImport(mut self, mut &decl: &UseDecl): &ImportInfo { + mut path := decl.LinkPath + + if !IsStdHeaderPath(decl.LinkPath) { + path = path::Join(decl.Token.File.Dir(), decl.LinkPath) + mut ok := self.checkCppUseDeclPath(decl, path) + if !ok { + ret nil + } + + // Set to absolute path for correct include path. + path, ok = path::Abs(path) + if !ok { + self.pushErr(decl.Token, LogMsg.UseNotFound, decl.LinkPath) + } + } + + ret &ImportInfo{ + Token: decl.Token, + Path: path, + LinkPath: decl.LinkPath, + Ident: "", // Cpp headers haven't identifiers. + Binded: true, + Std: false, + Package: nil, // Cpp headers haven't symbol table. + } + } + + fn buildStdImport(mut self, mut &decl: &UseDecl): &ImportInfo { + // No need to check blank identifiers for standart packages. + mut path := decl.LinkPath[len("std::"):] // Skip "std::" prefix. + path = strings::Replace(path, TokenKind.DblColon, str(path::Separator), -1) + path = path::Join(PathStdlib, path) + path, ok := path::Abs(path) + if !ok { + self.pushErr(decl.Token, LogMsg.UseNotFound, decl.LinkPath) + ret nil + } + + // Exist? + info := Status.Of(path) else { + self.pushErr(decl.Token, LogMsg.UseNotFound, decl.LinkPath) + ret nil + } + if !info.IsDir() { + self.pushErr(decl.Token, LogMsg.UseNotFound, decl.LinkPath) + ret nil + } + + // Select last identifier of namespace chain. + i := strings::FindLast(decl.LinkPath, TokenKind.DblColon) + 1 + ident := decl.LinkPath[i:] + + ret &ImportInfo{ + ImportAll: decl.Full, + Token: decl.Token, + Path: path, + LinkPath: decl.LinkPath, + Ident: ident, + Alias: decl.Alias, + Binded: false, + Std: true, + Package: &Package{ + Files: nil, // Appends by import algorithm. + }, + } + } + + fn buildIdentImport(mut &self, mut &decl: &UseDecl): &ImportInfo { + if decl.LinkPath == "_" || + strings::Find(decl.LinkPath, "::_::") != -1 || + strings::HasSuffix(decl.LinkPath, "::_") { + self.pushErr(decl.Token, LogMsg.BlankIdentInUseDecl) + ret nil + } + + modPath := self.importer.GetModPath() + if len(modPath) == 0 { + self.pushErr(decl.Token, LogMsg.ModuleNotFound) + self.pushSuggestion(LogMsg.UseModInit) + ret nil + } + + mut path := decl.LinkPath + path = strings::Replace(path, TokenKind.DblColon, str(path::Separator), -1) + path = path::Join(modPath, path) + + path, ok := path::Abs(path) + if !ok { + self.pushErr(decl.Token, LogMsg.UseNotFound, decl.LinkPath) + ret nil + } + + // Exist? + info := Status.Of(path) else { + self.pushErr(decl.Token, LogMsg.UseNotFound, decl.LinkPath) + ret nil + } + if !info.IsDir() { + self.pushErr(decl.Token, LogMsg.UseNotFound, decl.LinkPath) + ret nil + } + + // Select last identifier of namespace chain. + i := strings::FindLast(decl.LinkPath, TokenKind.DblColon) + 1 + ident := decl.LinkPath[i:] + + ret &ImportInfo{ + ImportAll: decl.Full, + Token: decl.Token, + Path: path, + LinkPath: decl.LinkPath, + Ident: ident, + Alias: decl.Alias, + Binded: false, + Std: false, + Package: &Package{ + Files: nil, // Appends by import algorithm. + }, + } + } + + fn buildImport(mut &self, mut &decl: &UseDecl): &ImportInfo { + match { + | decl.Binded: + ret self.buildCppHeaderImport(decl) + | decl.Std: + ret self.buildStdImport(decl) + |: + ret self.buildIdentImport(decl) + } + } + + fn checkDuplicateUseDecl(mut self, &pkg: &ImportInfo): (ok: bool) { + // Find package by path to detect cpp header imports. + lpkg := self.table.SelectPackage(fn(spkg: &ImportInfo): bool { + ret unsafe { pkg.Path == spkg.Path } + }) + if lpkg == nil { + ret true + } + + self.pushErr(pkg.Token, LogMsg.DuplicateUseDecl, pkg.LinkPath) + self.pushSuggestion(LogMsg.RemoveUseDeclAvoidDuplication) + ret false + } + + fn implImportSelections(mut self, mut &imp: &ImportInfo, mut &decl: &UseDecl) { + imp.Selected = decl.Selected + for _, item in imp.Selected { + for _, citem in imp.Selected { + if item == citem { + break + } else if item.Kind == citem.Kind { + self.pushErr(item, LogMsg.DuplicatedUseSelection, item.Kind) + self.pushSuggestion(LogMsg.RemoveUseSelectionAvoidDupliation) + break + } + } + } + } + + fn getAsLinkPath(mut &self, mut path: str): str { + if strings::HasPrefix(path, PathStdlib) { + path = path[len(PathStdlib):] + ret "std" + strings::Replace(path, str(path::Separator), TokenKind.DblColon, -1) + } + + root, _ := path::Abs(self.importer.GetModPath()) + path = path[len(root):] + if path[0] == path::Separator { + path = path[1:] + } + ret strings::Replace(path, str(path::Separator), TokenKind.DblColon, -1) + } + + fn pushCycleError(mut &self, &sb: &symbolBuilder, path: str, mut &message: StrBuilder) { + const Padding = 7 + refersTo := Logf( + LogMsg.RefersTo, + self.getAsLinkPath(sb.table.File.Dir()), + self.getAsLinkPath(path)) + m := message.Str() + message.WriteStr(strings::Repeat(" ", Padding)) + message.WriteStr(refersTo) + message.WriteByte('\n') + message.WriteStr(m) + } + + fn pushCrossCycleError(mut &self, &target: &symbolBuilder, &imp: &ImportInfo, &errorToken: &Token) { + mut message := StrBuilder.New(1 << 5) + + self.pushCycleError(self, imp.Path, message) + + mut owner := self.owner + mut old := self + + for owner.owner != nil { + self.pushCycleError(old.owner, old.table.File.Dir(), message) + + if owner.owner == target { + self.pushCycleError(target, owner.table.File.Dir(), message) + break + } + + old = owner + owner = owner.owner + } + + self.pushErr(errorToken, LogMsg.PkgIllegalCrossCycle, message.Str()) + } + + fn checkImportCycles(mut &self, imp: &ImportInfo, &decl: &UseDecl): bool { + if imp.Path == self.table.File.Dir() { + self.pushErr(decl.Token, LogMsg.PkgIllegalCycleRefersItself, self.getAsLinkPath(imp.Path)) + ret false + } + + if self.owner == nil { + ret true + } + + mut owner := self.owner + iter: + if owner.table.File.Dir() == imp.Path { + self.pushCrossCycleError(owner, imp, decl.Token) + ret false + } + + if owner.owner != nil { + owner = owner.owner + goto iter + } + + ret true + } + + // Checks internal packages or etc. for accessibility. + // + // Parameters: + // - decl: relevant use declaration. + // - mod: module that imports relevant package. + // - path: path of package that importing. + fn checkPackageAccessibility(mut self, &decl: &UseDecl, &mod: str, &path: str) { + if self.importer.GetModPath() != mod && strings::Contains(path, "internal") { + self.pushErr(decl.Token, LogMsg.UseDeclForInternal) + } + } + + fn importPackage(mut &self, mut &imp: &ImportInfo, mut &decl: &UseDecl): (ok: bool) { + if imp.Binded { + ret true + } + + mut port := self.importer.GetImport(imp.Path) + if port != nil { + imp.Package = port.Package + imp.Duplicate = true + + oldMod := self.importer.GetModPath() + self.importer.SetModPath(self.importer.ModById(imp.ModId)) + self.checkPackageAccessibility(decl, oldMod, port.Path) + self.importer.SetModPath(oldMod) + } else { + if !self.checkImportCycles(imp, decl) { + ret false + } + + oldMod := self.importer.GetModPath() + defer { self.importer.SetModPath(oldMod) } + if imp.Std { + self.importer.SetModPath(PathStdlib) + } + mut asts, mut errors := self.importer.ImportPackage(imp.Path, !imp.Std) + if len(errors) > 0 { + self.errors = append(self.errors, errors...) + ret false + } + + self.checkPackageAccessibility(decl, oldMod, imp.Path) + + for (_, mut ast) in asts { + let mut table: &SymbolTable = nil + table, errors = buildSymbols(ast, self.importer, self) + // Break import if file has error(s). + if len(errors) > 0 { + self.errors = append(self.errors, errors...) + ret false + } + imp.Package.Files = append(imp.Package.Files, table) + } + } + self.implImportSelections(imp, decl) + ret true + } + + fn importUseDecl(mut &self, mut &decl: &UseDecl): &ImportInfo { + mut imp := self.buildImport(decl) + // Break analysis if error occurs. + if imp == nil { + ret nil + } + + mut ok := self.checkDuplicateUseDecl(imp) + if !ok { + ret nil + } + + ok = self.importPackage(imp, decl) + self.table.Imports = append(self.table.Imports, imp) + if ok { + self.importer.Imported(imp) + ret imp + } + ret nil + } + + fn importUseDecls(mut &self) { + for (_, mut decl) in self.ast.UseDecls { + self.importUseDecl(decl) + // Break analysis if error occurs. + if len(self.errors) > 0 { + break + } + } + } + + fn appendNode(mut self, mut &node: Node) { + match type node.Data { + | &ast::Impl: + self.table.Impls = append(self.table.Impls, buildImpl((&ast::Impl)(node.Data))) + | &TypeAliasDecl: + mut ta := buildTypeAlias((&TypeAliasDecl)(node.Data)) + self.table.TypeAliases = append(self.table.TypeAliases, ta) + | &StructDecl: + mut srct := buildStruct((&StructDecl)(node.Data)) + self.table.Structs = append(self.table.Structs, srct) + | &FnDecl: + mut f := buildFunc((&FnDecl)(node.Data)) + self.table.Funcs = append(self.table.Funcs, f) + | &TraitDecl: + mut t := buildTrait((&TraitDecl)(node.Data)) + self.table.Traits = append(self.table.Traits, t) + | &VarDecl: + mut v := buildVar((&VarDecl)(node.Data)) + self.table.Vars = append(self.table.Vars, v) + | &EnumDecl: + mut e := buildEnum((&EnumDecl)(node.Data)) + self.table.Enums = append(self.table.Enums, e) + | &TypeEnumDecl: + mut e := buildTypeEnum((&TypeEnumDecl)(node.Data)) + self.table.TypeEnums = append(self.table.TypeEnums, e) + |: + self.pushErr(node.Token, LogMsg.InvalidSyntax) + } + } + + fn appendNodes(mut self) { + for (_, mut node) in self.ast.Nodes { + self.appendNode(node) + } + } + + fn pushDirectivePass(mut self, mut &d: &ast::Directive) { + if len(d.Args) == 0 { + self.pushErr(d.Tag, LogMsg.MissingExpr) + ret + } else if len(d.Args) > 1 { + arg := d.Args[1] + self.pushErr(arg, LogMsg.ArgumentOverflow, d.Tag.Kind) + } + + arg := d.Args[0] + if arg.Id != TokenId.Lit { + self.pushErr(arg, LogMsg.InvalidSyntax) + ret + } + + if arg.Kind[0] != '"' { + self.pushErr(arg, LogMsg.InvalidSyntax) + ret + } + + self.table.Passes = append(self.table.Passes, Pass{ + Token: d.Tag, + Text: arg.Kind[1:len(arg.Kind)-1], + }) + } + + fn appendTopDirectives(mut self) { + for (_, mut d) in self.ast.TopDirectives { + match d.Tag.Kind { + | Directive.Pass: + self.pushDirectivePass(d) + } + } + } + + fn build(mut &self) { + self.table = &SymbolTable{ + File: self.ast.File, + } + + self.appendTopDirectives() + + self.importUseDecls() + // Break analysis if use declarations has error. + if len(self.errors) > 0 { + ret + } + + self.appendNodes() + // Break analysis if declarations has error. + if len(self.errors) > 0 { + ret + } + } } \ No newline at end of file diff --git a/std/jule/sema/table.jule b/std/jule/sema/table.jule index 7ad0c03fb..c1d2252d1 100644 --- a/std/jule/sema/table.jule +++ b/std/jule/sema/table.jule @@ -7,244 +7,244 @@ use std::jule::lex::{File} // Symbol table. // Builds by semantic analyzer. struct SymbolTable { - File: &File // Owner fileset of this symbol table. - Passes: []Pass // All passed flags with jule:pass directive. - Imports: []&ImportInfo // Imported packages. - Vars: []&Var // Variables. - TypeAliases: []&TypeAlias // Type aliases. - Structs: []&Struct // Structures. - Funcs: []&Fn // Functions. - Traits: []&Trait // Traits. - Enums: []&Enum // Enums. - TypeEnums: []&TypeEnum // Type enums. - Impls: []&Impl // Implementations. + File: &File // Owner fileset of this symbol table. + Passes: []Pass // All passed flags with jule:pass directive. + Imports: []&ImportInfo // Imported packages. + Vars: []&Var // Variables. + TypeAliases: []&TypeAlias // Type aliases. + Structs: []&Struct // Structures. + Funcs: []&Fn // Functions. + Traits: []&Trait // Traits. + Enums: []&Enum // Enums. + TypeEnums: []&TypeEnum // Type enums. + Impls: []&Impl // Implementations. } impl Lookup for SymbolTable { - // Returns imported package by selector. - // Returns nil reference if selector returns false for all packages. - // Returns nil reference if selector is nil. - fn SelectPackage(mut self, selector: fn(&ImportInfo): bool): &ImportInfo { - if selector == nil { - ret nil - } - for (_, mut pkg) in self.Imports { - if selector(pkg) { - ret pkg - } - } - ret nil - } - - // Returns variable by identifier and binded state. - // Returns nil if refenrece not exist any variable in this identifier. - fn FindVar(mut self, ident: str, binded: bool): &Var { - ret self.findVar(ident, binded, false) - } - - // Returns type alias by identifier and binded state. - // Returns nil reference if not exist any type alias in this identifier. - fn FindTypeAlias(mut self, ident: str, binded: bool): &TypeAlias { - ret self.findTypeAlias(ident, binded, false) - } - - // Returns struct by identifier and binded state. - // Returns nil reference if not exist any struct in this identifier. - fn FindStruct(mut self, ident: str, binded: bool): &Struct { - for (_, mut s) in self.Structs { - if s.Ident == ident && s.Binded == binded { - ret s - } - } - ret nil - } - - // Returns function by identifier and binded state. - // Returns nil reference if not exist any function in this identifier. - fn FindFn(mut self, ident: str, binded: bool): &Fn { - for (_, mut f) in self.Funcs { - if f.Ident == ident && f.Binded == binded { - ret f - } - } - ret nil - } - - // Returns trait by identifier. - // Returns nil reference if not exist any trait in this identifier. - fn FindTrait(mut self, ident: str): &Trait { - for (_, mut t) in self.Traits { - if t.Ident == ident { - ret t - } - } - ret nil - } - - // Returns enum by identifier. - // Returns nil reference if not exist any enum in this identifier. - fn FindEnum(mut self, ident: str): &Enum { - for (_, mut e) in self.Enums { - if e.Ident == ident { - ret e - } - } - ret nil - } - - // Returns type enum by identifier. - // Returns nil reference if not exist any type enum in this identifier. - fn FindTypeEnum(mut self, ident: str): &TypeEnum { - for (_, mut e) in self.TypeEnums { - if e.Ident == ident { - ret e - } - } - ret nil - } + // Returns imported package by selector. + // Returns nil reference if selector returns false for all packages. + // Returns nil reference if selector is nil. + fn SelectPackage(mut self, selector: fn(&ImportInfo): bool): &ImportInfo { + if selector == nil { + ret nil + } + for (_, mut pkg) in self.Imports { + if selector(pkg) { + ret pkg + } + } + ret nil + } + + // Returns variable by identifier and binded state. + // Returns nil if refenrece not exist any variable in this identifier. + fn FindVar(mut self, ident: str, binded: bool): &Var { + ret self.findVar(ident, binded, false) + } + + // Returns type alias by identifier and binded state. + // Returns nil reference if not exist any type alias in this identifier. + fn FindTypeAlias(mut self, ident: str, binded: bool): &TypeAlias { + ret self.findTypeAlias(ident, binded, false) + } + + // Returns struct by identifier and binded state. + // Returns nil reference if not exist any struct in this identifier. + fn FindStruct(mut self, ident: str, binded: bool): &Struct { + for (_, mut s) in self.Structs { + if s.Ident == ident && s.Binded == binded { + ret s + } + } + ret nil + } + + // Returns function by identifier and binded state. + // Returns nil reference if not exist any function in this identifier. + fn FindFn(mut self, ident: str, binded: bool): &Fn { + for (_, mut f) in self.Funcs { + if f.Ident == ident && f.Binded == binded { + ret f + } + } + ret nil + } + + // Returns trait by identifier. + // Returns nil reference if not exist any trait in this identifier. + fn FindTrait(mut self, ident: str): &Trait { + for (_, mut t) in self.Traits { + if t.Ident == ident { + ret t + } + } + ret nil + } + + // Returns enum by identifier. + // Returns nil reference if not exist any enum in this identifier. + fn FindEnum(mut self, ident: str): &Enum { + for (_, mut e) in self.Enums { + if e.Ident == ident { + ret e + } + } + ret nil + } + + // Returns type enum by identifier. + // Returns nil reference if not exist any type enum in this identifier. + fn FindTypeEnum(mut self, ident: str): &TypeEnum { + for (_, mut e) in self.TypeEnums { + if e.Ident == ident { + ret e + } + } + ret nil + } } impl SymbolTable { - fn findVar(mut self, &ident: str, binded: bool, reverse: bool): &Var { - if reverse { - mut i := len(self.Vars) - 1 - for i >= 0; i-- { - mut v := self.Vars[i] - if v.Ident == ident && v.Binded == binded { - ret v - } - } - } else { - for (_, mut v) in self.Vars { - if v.Ident == ident && v.Binded == binded { - ret v - } - } - } - ret nil - } - - fn findTypeAlias(mut self, &ident: str, binded: bool, reverse: bool): &TypeAlias { - if reverse { - mut i := len(self.TypeAliases) - 1 - for i >= 0; i-- { - mut ta := self.TypeAliases[i] - if ta.Ident == ident && ta.Binded == binded { - ret ta - } - } - } else { - for (_, mut ta) in self.TypeAliases { - if ta.Ident == ident && ta.Binded == binded { - ret ta - } - } - } - ret nil - } - - // Returns define by identifier. - // Returns nil reference if not exist any define in this identifier. - fn defByIdent(mut self, &ident: str, binded: bool): any { - for (_, mut v) in self.Vars { - if v.Ident == ident && v.Binded == binded { - ret v - } - } - - for (_, mut ta) in self.TypeAliases { - if ta.Ident == ident && ta.Binded == binded { - ret ta - } - } - - for (_, mut s) in self.Structs { - if s.Ident == ident && s.Binded == binded { - ret s - } - } - - for (_, mut f) in self.Funcs { - if f.Ident == ident && f.Binded == binded { - ret f - } - } - - if binded { - ret nil - } - - for (_, mut t) in self.Traits { - if t.Ident == ident { - ret t - } - } - - for (_, mut e) in self.Enums { - if e.Ident == ident { - ret e - } - } - - for (_, mut te) in self.TypeEnums { - if te.Ident == ident { - ret te - } - } - - ret nil - } - - // Reports this identifier duplicated in symbol table. - // The "self" parameter represents address of exception identifier. - // If founded identifier address equals to self, will be skipped. - fn isDuplicatedIdent(self, itself: uintptr, &ident: str, binded: bool): bool { - for _, v in self.Vars { - if uintptr(v) != itself && v.Ident == ident && v.Binded == binded { - ret true - } - } - - for _, ta in self.TypeAliases { - if uintptr(ta) != itself && ta.Ident == ident && ta.Binded == binded { - ret true - } - } - - for _, s in self.Structs { - if uintptr(s) != itself && s.Ident == ident && s.Binded == binded { - ret true - } - } - - for _, f in self.Funcs { - if uintptr(f) != itself && f.Ident == ident && f.Binded == binded { - ret true - } - } - - if binded { - ret false - } - - for _, t in self.Traits { - if uintptr(t) != itself && t.Ident == ident { - ret true - } - } - - for _, e in self.Enums { - if uintptr(e) != itself && e.Ident == ident { - ret true - } - } - - for _, te in self.TypeEnums { - if uintptr(te) != itself && te.Ident == ident { - ret true - } - } - - ret false - } + fn findVar(mut self, &ident: str, binded: bool, reverse: bool): &Var { + if reverse { + mut i := len(self.Vars) - 1 + for i >= 0; i-- { + mut v := self.Vars[i] + if v.Ident == ident && v.Binded == binded { + ret v + } + } + } else { + for (_, mut v) in self.Vars { + if v.Ident == ident && v.Binded == binded { + ret v + } + } + } + ret nil + } + + fn findTypeAlias(mut self, &ident: str, binded: bool, reverse: bool): &TypeAlias { + if reverse { + mut i := len(self.TypeAliases) - 1 + for i >= 0; i-- { + mut ta := self.TypeAliases[i] + if ta.Ident == ident && ta.Binded == binded { + ret ta + } + } + } else { + for (_, mut ta) in self.TypeAliases { + if ta.Ident == ident && ta.Binded == binded { + ret ta + } + } + } + ret nil + } + + // Returns define by identifier. + // Returns nil reference if not exist any define in this identifier. + fn defByIdent(mut self, &ident: str, binded: bool): any { + for (_, mut v) in self.Vars { + if v.Ident == ident && v.Binded == binded { + ret v + } + } + + for (_, mut ta) in self.TypeAliases { + if ta.Ident == ident && ta.Binded == binded { + ret ta + } + } + + for (_, mut s) in self.Structs { + if s.Ident == ident && s.Binded == binded { + ret s + } + } + + for (_, mut f) in self.Funcs { + if f.Ident == ident && f.Binded == binded { + ret f + } + } + + if binded { + ret nil + } + + for (_, mut t) in self.Traits { + if t.Ident == ident { + ret t + } + } + + for (_, mut e) in self.Enums { + if e.Ident == ident { + ret e + } + } + + for (_, mut te) in self.TypeEnums { + if te.Ident == ident { + ret te + } + } + + ret nil + } + + // Reports this identifier duplicated in symbol table. + // The "self" parameter represents address of exception identifier. + // If founded identifier address equals to self, will be skipped. + fn isDuplicatedIdent(self, itself: uintptr, &ident: str, binded: bool): bool { + for _, v in self.Vars { + if uintptr(v) != itself && v.Ident == ident && v.Binded == binded { + ret true + } + } + + for _, ta in self.TypeAliases { + if uintptr(ta) != itself && ta.Ident == ident && ta.Binded == binded { + ret true + } + } + + for _, s in self.Structs { + if uintptr(s) != itself && s.Ident == ident && s.Binded == binded { + ret true + } + } + + for _, f in self.Funcs { + if uintptr(f) != itself && f.Ident == ident && f.Binded == binded { + ret true + } + } + + if binded { + ret false + } + + for _, t in self.Traits { + if uintptr(t) != itself && t.Ident == ident { + ret true + } + } + + for _, e in self.Enums { + if uintptr(e) != itself && e.Ident == ident { + ret true + } + } + + for _, te in self.TypeEnums { + if uintptr(te) != itself && te.Ident == ident { + ret true + } + } + + ret false + } } \ No newline at end of file diff --git a/std/jule/sema/trait.jule b/std/jule/sema/trait.jule index 529f3e0f1..d5f50b799 100644 --- a/std/jule/sema/trait.jule +++ b/std/jule/sema/trait.jule @@ -6,65 +6,65 @@ use std::jule::lex::{Token, TokenId} // Trait. struct Trait { - Token: &Token - Ident: str - Public: bool - Inherits: []&TypeSymbol - Methods: []&Fn - Implemented: []&Struct + Token: &Token + Ident: str + Public: bool + Inherits: []&TypeSymbol + Methods: []&Fn + Implemented: []&Struct } impl Kind for Trait { - // Implement: Kind - // Returns Trait's identifier. - fn Str(self): str { - ret self.Ident - } + // Implement: Kind + // Returns Trait's identifier. + fn Str(self): str { + ret self.Ident + } - // Reports whether types are same. - fn Equal(&self, other: &TypeKind): bool { - trt := unsafe { (*(&other)).Trait() } - ret self == trt - } + // Reports whether types are same. + fn Equal(&self, other: &TypeKind): bool { + trt := unsafe { (*(&other)).Trait() } + ret self == trt + } } impl Trait { - // Returns method by identifier. - // Returns nil if not exist any method in this identifier. - fn FindMethod(mut self, ident: str): &Fn { - for (_, mut f) in self.Methods { - if f.Ident == ident { - ret f - } - } - ret self.findMethodInherit(ident) - } + // Returns method by identifier. + // Returns nil if not exist any method in this identifier. + fn FindMethod(mut self, ident: str): &Fn { + for (_, mut f) in self.Methods { + if f.Ident == ident { + ret f + } + } + ret self.findMethodInherit(ident) + } - fn inherits(mut &self, &t: &Trait): bool { - if self == t { - ret true - } - for (_, mut i) in self.Inherits { - if i.Kind.Trait().inherits(t) { - ret true - } - } - ret false - } + fn inherits(mut &self, &t: &Trait): bool { + if self == t { + ret true + } + for (_, mut i) in self.Inherits { + if i.Kind.Trait().inherits(t) { + ret true + } + } + ret false + } - fn findMethodInherit(mut self, &ident: str): &Fn { - for (_, mut i) in self.Inherits { - if i.Kind == nil { - continue - } - mut t := i.Kind.Trait() - if t != nil { - mut f2 := t.FindMethod(ident) - if f2 != nil { - ret f2 - } - } - } - ret nil - } + fn findMethodInherit(mut self, &ident: str): &Fn { + for (_, mut i) in self.Inherits { + if i.Kind == nil { + continue + } + mut t := i.Kind.Trait() + if t != nil { + mut f2 := t.FindMethod(ident) + if f2 != nil { + ret f2 + } + } + } + ret nil + } } \ No newline at end of file diff --git a/std/jule/sema/type.jule b/std/jule/sema/type.jule index 5dba6e18e..b134882eb 100644 --- a/std/jule/sema/type.jule +++ b/std/jule/sema/type.jule @@ -7,21 +7,21 @@ use conv for std::conv use ast for std::jule::ast::{ - Ast, - TypeDecl, - GenericDecl, - FnDecl, - MapTypeDecl, - PtrTypeDecl, - SlcTypeDecl, - ArrTypeDecl, - ScopeTree, - NamespaceTypeDecl, - TypeDeclKind, - TupleTypeDecl, - SptrTypeDecl, - IdentTypeDecl, - SubIdentTypeDecl, + Ast, + TypeDecl, + GenericDecl, + FnDecl, + MapTypeDecl, + PtrTypeDecl, + SlcTypeDecl, + ArrTypeDecl, + ScopeTree, + NamespaceTypeDecl, + TypeDeclKind, + TupleTypeDecl, + SptrTypeDecl, + IdentTypeDecl, + SubIdentTypeDecl, } use std::jule::build::{LogMsg, Logf} use std::jule::lex::{Token, TokenKind, TokenId} @@ -32,1724 +32,1724 @@ type PrimKind: types::TypeKind // Generic type for instance types. struct InsGeneric { - Kind: &TypeKind - Constraint: []&TypeKind + Kind: &TypeKind + Constraint: []&TypeKind } // Type alias. struct TypeAlias { - Scope: &ScopeTree - Public: bool - Binded: bool - Used: bool - Generic: bool - Token: &Token - Ident: str - Kind: &TypeSymbol - Refers: []any // Referred identifiers, except binded ones. - Generics: []&TypeAlias // See developer reference (1). + Scope: &ScopeTree + Public: bool + Binded: bool + Used: bool + Generic: bool + Token: &Token + Ident: str + Kind: &TypeSymbol + Refers: []any // Referred identifiers, except binded ones. + Generics: []&TypeAlias // See developer reference (1). } // Kind of type declaration. trait Kind { - fn Str(self): str - fn Equal(&self, other: &TypeKind): bool + fn Str(self): str + fn Equal(&self, other: &TypeKind): bool } // Evaluated type declaration. struct TypeKind { - BindIdent: str - Generic: bool - Variadic: bool - Kind: Kind + BindIdent: str + Generic: bool + Variadic: bool + Kind: Kind } impl Kind for TypeKind { - // Returns kind as string. - fn Str(self): str { - if self.IsNil() { - ret "nil" - } - - mut kind := StrBuilder.New(1 << 4) - - if self.Variadic { - kind.WriteStr("...") - } - - if self.Binded() { - kind.WriteStr("cpp.") - kind.WriteStr(self.BindIdent) - } else { - kind.WriteStr(self.Kind.Str()) - } - ret kind.Str() - } - - // Reports whether types are same. - fn Equal(&self, other: &TypeKind): bool { - if self.IsNil() { - ret other.IsNil() - } - if self.Binded() { - ret other.Binded() && self.BindIdent == other.BindIdent - } - ret self.Kind.Equal(other) - } + // Returns kind as string. + fn Str(self): str { + if self.IsNil() { + ret "nil" + } + + mut kind := StrBuilder.New(1 << 4) + + if self.Variadic { + kind.WriteStr("...") + } + + if self.Binded() { + kind.WriteStr("cpp.") + kind.WriteStr(self.BindIdent) + } else { + kind.WriteStr(self.Kind.Str()) + } + ret kind.Str() + } + + // Reports whether types are same. + fn Equal(&self, other: &TypeKind): bool { + if self.IsNil() { + ret other.IsNil() + } + if self.Binded() { + ret other.Binded() && self.BindIdent == other.BindIdent + } + ret self.Kind.Equal(other) + } } impl TypeKind { - // Reports whether type is binded kind. - fn Binded(self): bool { ret len(self.BindIdent) != 0 } - - // Reports whether kind is "nil". - fn IsNil(self): bool { ret self.Kind == nil } - - // Reports whether kind is "void". - fn Void(self): bool { - prim := unsafe { (*(&self)).Prim() } - ret prim != nil && prim.Kind == "void" - } - - // Reports whether kind is comparable. - fn Comparable(self): bool { - unsafe { - mut _self := &self - if _self.Struct() != nil { - ret _self.Struct().Comparable - } - ret _self.Map() == nil && _self.Slc() == nil && _self.Fn() == nil - } - } - - // Reports whether kind is mutable. - fn Mutable(self): bool { - unsafe { - mut _self := &self - if _self.Struct() != nil { - ret _self.Struct().Mutable - } - if _self.Trait() != nil { - ret true - } - if _self.Prim() != nil { - p := _self.Prim() - ret p.IsAny() - } - if _self.Arr() != nil { - ret _self.Arr().Elem.Mutable() - } - ret _self.Slc() != nil || - _self.Ptr() != nil || - _self.Sptr() != nil - } - } - - // Reports whether kind supports ordered constrait. - fn Ordered(self): bool { - unsafe { - mut _self := &self - prim := _self.Prim() - if prim != nil { - ret types::IsNum(prim.Kind) || prim.IsStr() - } - if _self.Ptr() != nil { - ret true - } - s := _self.Struct() - if s != nil { - ret s.Operators.Gt != nil && - s.Operators.GtEq != nil && - s.Operators.Lt != nil && - s.Operators.LtEq != nil - } - enm := _self.Enum() - if enm != nil { - ret types::IsNum(enm.Kind.Kind.Str()) - } - ret false - } - } - - // Reports whether kind is nil compatible. - fn NilCompatible(self): bool { - unsafe { - mut _self := &self - - prim := _self.Prim() - if prim != nil && prim.IsAny() { - ret true - } - - ret _self.IsNil() || - _self.Fn() != nil || - _self.Sptr() != nil || - _self.Ptr() != nil || - _self.Trait() != nil || - _self.Slc() != nil || - _self.Map() != nil || - _self.TypeEnum() != nil - } - } - - // Reports whether kind performs reference-counting. - fn PerformsRC(self): bool { - unsafe { - mut _self := &self - prim := _self.Prim() - if prim != nil { - ret prim.IsAny() || prim.IsStr() - } - ret _self.Sptr() != nil || _self.Slc() != nil || _self.Trait() != nil - } - } - - // Reports whether kind is variadicable. - fn Variadicable(self): bool { - unsafe { - mut _self := &self - ret _self.Slc() != nil - } - } - - // Returns primitive type if kind is primitive type, nil reference if not. - fn Prim(mut self): &Prim { - match type self.Kind { - | &Prim: - ret (&Prim)(self.Kind) - |: - ret nil - } - } - - // Returns reference type if kind is smart pointer, nil reference if not. - fn Sptr(mut self): &Sptr { - match type self.Kind { - | &Sptr: - ret (&Sptr)(self.Kind) - |: - ret nil - } - } - - // Returns pointer type if kind is pointer, nil reference if not. - fn Ptr(mut self): &Ptr { - match type self.Kind { - | &Ptr: - ret (&Ptr)(self.Kind) - |: - ret nil - } - } - - // Returns enum type if kind is enum, nil reference if not. - fn Enum(mut self): &Enum { - match type self.Kind { - | &Enum: - ret (&Enum)(self.Kind) - |: - ret nil - } - } - - // Returns type enum if kind is type enum, nil reference if not. - fn TypeEnum(mut self): &TypeEnum { - match type self.Kind { - | &TypeEnum: - ret (&TypeEnum)(self.Kind) - |: - ret nil - } - } - - // Returns array type if kind is array, nil reference if not. - fn Arr(mut self): &Arr { - match type self.Kind { - | &Arr: - ret (&Arr)(self.Kind) - |: - ret nil - } - } - - // Returns slice type if kind is slice, nil reference if not. - fn Slc(mut self): &Slc { - match type self.Kind { - | &Slc: - ret (&Slc)(self.Kind) - |: - ret nil - } - } - - // Returns fn type if kind is function, nil reference if not. - fn Fn(mut self): &FnIns { - match type self.Kind { - | &FnIns: - ret (&FnIns)(self.Kind) - |: - ret nil - } - } - - // Returns struct type if kind is structure, nil reference if not. - fn Struct(mut self): &StructIns { - match type self.Kind { - | &StructIns: - ret (&StructIns)(self.Kind) - |: - ret nil - } - } - - // Returns trait type if kind is trait, nil reference if not. - fn Trait(mut self): &Trait { - match type self.Kind { - | &Trait: - ret (&Trait)(self.Kind) - |: - ret nil - } - } - - // Returns map type if kind is map, nil reference if not. - fn Map(mut self): &Map { - match type self.Kind { - | &Map: - ret (&Map)(self.Kind) - |: - ret nil - } - } - - // Returns tuple type if kind is tuple, nil reference if not. - fn Tup(mut self): &Tuple { - match type self.Kind { - | &Tuple: - ret (&Tuple)(self.Kind) - |: - ret nil - } - } - - // Reports whether kind is comptime type. - // It will not check for the [comptimeRange]. - // Checks regular constant comptime expression types only. - fn comptime(mut self): bool { - ret self.comptimeTypeInfos() != nil || - self.comptimeTypeInfo() != nil || - self.comptimeStructFields() != nil || - self.comptimeStructField() != nil || - self.comptimeEnumFields() != nil || - self.comptimeEnumField() != nil || - self.comptimeStatics() != nil || - self.comptimeStatic() != nil || - self.comptimeParams() != nil || - self.comptimeParam() != nil || - self.comptimeValue() != nil || - self.comptimeFiles() != nil || - self.comptimeFile() != nil - } - - fn comptimeStructFields(mut self): &comptimeStructFields { - match type self.Kind { - | &comptimeStructFields: - ret (&comptimeStructFields)(self.Kind) - |: - ret nil - } - } - - fn comptimeStructField(mut self): &comptimeStructField { - match type self.Kind { - | &comptimeStructField: - ret (&comptimeStructField)(self.Kind) - |: - ret nil - } - } - - fn comptimeEnumFields(mut self): &comptimeEnumFields { - match type self.Kind { - | &comptimeEnumFields: - ret (&comptimeEnumFields)(self.Kind) - |: - ret nil - } - } - - fn comptimeEnumField(mut self): &comptimeEnumField { - match type self.Kind { - | &comptimeEnumField: - ret (&comptimeEnumField)(self.Kind) - |: - ret nil - } - } - - fn comptimeParams(mut self): &comptimeParams { - match type self.Kind { - | &comptimeParams: - ret (&comptimeParams)(self.Kind) - |: - ret nil - } - } - - fn comptimeParam(mut self): &comptimeParam { - match type self.Kind { - | &comptimeParam: - ret (&comptimeParam)(self.Kind) - |: - ret nil - } - } - - fn comptimeRange(mut self): &comptimeRange { - match type self.Kind { - | &comptimeRange: - ret (&comptimeRange)(self.Kind) - |: - ret nil - } - } - - fn comptimeTypeInfos(mut self): &comptimeTypeInfos { - match type self.Kind { - | &comptimeTypeInfos: - ret (&comptimeTypeInfos)(self.Kind) - |: - ret nil - } - } - - fn comptimeTypeInfo(mut self): &comptimeTypeInfo { - match type self.Kind { - | &comptimeTypeInfo: - ret (&comptimeTypeInfo)(self.Kind) - |: - ret nil - } - } - - fn comptimeStatics(mut self): &comptimeStatics { - match type self.Kind { - | &comptimeStatics: - ret (&comptimeStatics)(self.Kind) - |: - ret nil - } - } - - fn comptimeStatic(mut self): &comptimeStatic { - match type self.Kind { - | &comptimeStatic: - ret (&comptimeStatic)(self.Kind) - |: - ret nil - } - } - - fn comptimeValue(mut self): &comptimeValue { - match type self.Kind { - | &comptimeValue: - ret (&comptimeValue)(self.Kind) - |: - ret nil - } - } - - fn comptimeFile(mut self): &comptimeFile { - match type self.Kind { - | &comptimeFile: - ret (&comptimeFile)(self.Kind) - |: - ret nil - } - } - - fn comptimeFiles(mut self): &comptimeFiles { - match type self.Kind { - | &comptimeFiles: - ret (&comptimeFiles)(self.Kind) - |: - ret nil - } - } + // Reports whether type is binded kind. + fn Binded(self): bool { ret len(self.BindIdent) != 0 } + + // Reports whether kind is "nil". + fn IsNil(self): bool { ret self.Kind == nil } + + // Reports whether kind is "void". + fn Void(self): bool { + prim := unsafe { (*(&self)).Prim() } + ret prim != nil && prim.Kind == "void" + } + + // Reports whether kind is comparable. + fn Comparable(self): bool { + unsafe { + mut _self := &self + if _self.Struct() != nil { + ret _self.Struct().Comparable + } + ret _self.Map() == nil && _self.Slc() == nil && _self.Fn() == nil + } + } + + // Reports whether kind is mutable. + fn Mutable(self): bool { + unsafe { + mut _self := &self + if _self.Struct() != nil { + ret _self.Struct().Mutable + } + if _self.Trait() != nil { + ret true + } + if _self.Prim() != nil { + p := _self.Prim() + ret p.IsAny() + } + if _self.Arr() != nil { + ret _self.Arr().Elem.Mutable() + } + ret _self.Slc() != nil || + _self.Ptr() != nil || + _self.Sptr() != nil + } + } + + // Reports whether kind supports ordered constrait. + fn Ordered(self): bool { + unsafe { + mut _self := &self + prim := _self.Prim() + if prim != nil { + ret types::IsNum(prim.Kind) || prim.IsStr() + } + if _self.Ptr() != nil { + ret true + } + s := _self.Struct() + if s != nil { + ret s.Operators.Gt != nil && + s.Operators.GtEq != nil && + s.Operators.Lt != nil && + s.Operators.LtEq != nil + } + enm := _self.Enum() + if enm != nil { + ret types::IsNum(enm.Kind.Kind.Str()) + } + ret false + } + } + + // Reports whether kind is nil compatible. + fn NilCompatible(self): bool { + unsafe { + mut _self := &self + + prim := _self.Prim() + if prim != nil && prim.IsAny() { + ret true + } + + ret _self.IsNil() || + _self.Fn() != nil || + _self.Sptr() != nil || + _self.Ptr() != nil || + _self.Trait() != nil || + _self.Slc() != nil || + _self.Map() != nil || + _self.TypeEnum() != nil + } + } + + // Reports whether kind performs reference-counting. + fn PerformsRC(self): bool { + unsafe { + mut _self := &self + prim := _self.Prim() + if prim != nil { + ret prim.IsAny() || prim.IsStr() + } + ret _self.Sptr() != nil || _self.Slc() != nil || _self.Trait() != nil + } + } + + // Reports whether kind is variadicable. + fn Variadicable(self): bool { + unsafe { + mut _self := &self + ret _self.Slc() != nil + } + } + + // Returns primitive type if kind is primitive type, nil reference if not. + fn Prim(mut self): &Prim { + match type self.Kind { + | &Prim: + ret (&Prim)(self.Kind) + |: + ret nil + } + } + + // Returns reference type if kind is smart pointer, nil reference if not. + fn Sptr(mut self): &Sptr { + match type self.Kind { + | &Sptr: + ret (&Sptr)(self.Kind) + |: + ret nil + } + } + + // Returns pointer type if kind is pointer, nil reference if not. + fn Ptr(mut self): &Ptr { + match type self.Kind { + | &Ptr: + ret (&Ptr)(self.Kind) + |: + ret nil + } + } + + // Returns enum type if kind is enum, nil reference if not. + fn Enum(mut self): &Enum { + match type self.Kind { + | &Enum: + ret (&Enum)(self.Kind) + |: + ret nil + } + } + + // Returns type enum if kind is type enum, nil reference if not. + fn TypeEnum(mut self): &TypeEnum { + match type self.Kind { + | &TypeEnum: + ret (&TypeEnum)(self.Kind) + |: + ret nil + } + } + + // Returns array type if kind is array, nil reference if not. + fn Arr(mut self): &Arr { + match type self.Kind { + | &Arr: + ret (&Arr)(self.Kind) + |: + ret nil + } + } + + // Returns slice type if kind is slice, nil reference if not. + fn Slc(mut self): &Slc { + match type self.Kind { + | &Slc: + ret (&Slc)(self.Kind) + |: + ret nil + } + } + + // Returns fn type if kind is function, nil reference if not. + fn Fn(mut self): &FnIns { + match type self.Kind { + | &FnIns: + ret (&FnIns)(self.Kind) + |: + ret nil + } + } + + // Returns struct type if kind is structure, nil reference if not. + fn Struct(mut self): &StructIns { + match type self.Kind { + | &StructIns: + ret (&StructIns)(self.Kind) + |: + ret nil + } + } + + // Returns trait type if kind is trait, nil reference if not. + fn Trait(mut self): &Trait { + match type self.Kind { + | &Trait: + ret (&Trait)(self.Kind) + |: + ret nil + } + } + + // Returns map type if kind is map, nil reference if not. + fn Map(mut self): &Map { + match type self.Kind { + | &Map: + ret (&Map)(self.Kind) + |: + ret nil + } + } + + // Returns tuple type if kind is tuple, nil reference if not. + fn Tup(mut self): &Tuple { + match type self.Kind { + | &Tuple: + ret (&Tuple)(self.Kind) + |: + ret nil + } + } + + // Reports whether kind is comptime type. + // It will not check for the [comptimeRange]. + // Checks regular constant comptime expression types only. + fn comptime(mut self): bool { + ret self.comptimeTypeInfos() != nil || + self.comptimeTypeInfo() != nil || + self.comptimeStructFields() != nil || + self.comptimeStructField() != nil || + self.comptimeEnumFields() != nil || + self.comptimeEnumField() != nil || + self.comptimeStatics() != nil || + self.comptimeStatic() != nil || + self.comptimeParams() != nil || + self.comptimeParam() != nil || + self.comptimeValue() != nil || + self.comptimeFiles() != nil || + self.comptimeFile() != nil + } + + fn comptimeStructFields(mut self): &comptimeStructFields { + match type self.Kind { + | &comptimeStructFields: + ret (&comptimeStructFields)(self.Kind) + |: + ret nil + } + } + + fn comptimeStructField(mut self): &comptimeStructField { + match type self.Kind { + | &comptimeStructField: + ret (&comptimeStructField)(self.Kind) + |: + ret nil + } + } + + fn comptimeEnumFields(mut self): &comptimeEnumFields { + match type self.Kind { + | &comptimeEnumFields: + ret (&comptimeEnumFields)(self.Kind) + |: + ret nil + } + } + + fn comptimeEnumField(mut self): &comptimeEnumField { + match type self.Kind { + | &comptimeEnumField: + ret (&comptimeEnumField)(self.Kind) + |: + ret nil + } + } + + fn comptimeParams(mut self): &comptimeParams { + match type self.Kind { + | &comptimeParams: + ret (&comptimeParams)(self.Kind) + |: + ret nil + } + } + + fn comptimeParam(mut self): &comptimeParam { + match type self.Kind { + | &comptimeParam: + ret (&comptimeParam)(self.Kind) + |: + ret nil + } + } + + fn comptimeRange(mut self): &comptimeRange { + match type self.Kind { + | &comptimeRange: + ret (&comptimeRange)(self.Kind) + |: + ret nil + } + } + + fn comptimeTypeInfos(mut self): &comptimeTypeInfos { + match type self.Kind { + | &comptimeTypeInfos: + ret (&comptimeTypeInfos)(self.Kind) + |: + ret nil + } + } + + fn comptimeTypeInfo(mut self): &comptimeTypeInfo { + match type self.Kind { + | &comptimeTypeInfo: + ret (&comptimeTypeInfo)(self.Kind) + |: + ret nil + } + } + + fn comptimeStatics(mut self): &comptimeStatics { + match type self.Kind { + | &comptimeStatics: + ret (&comptimeStatics)(self.Kind) + |: + ret nil + } + } + + fn comptimeStatic(mut self): &comptimeStatic { + match type self.Kind { + | &comptimeStatic: + ret (&comptimeStatic)(self.Kind) + |: + ret nil + } + } + + fn comptimeValue(mut self): &comptimeValue { + match type self.Kind { + | &comptimeValue: + ret (&comptimeValue)(self.Kind) + |: + ret nil + } + } + + fn comptimeFile(mut self): &comptimeFile { + match type self.Kind { + | &comptimeFile: + ret (&comptimeFile)(self.Kind) + |: + ret nil + } + } + + fn comptimeFiles(mut self): &comptimeFiles { + match type self.Kind { + | &comptimeFiles: + ret (&comptimeFiles)(self.Kind) + |: + ret nil + } + } } // Type. struct TypeSymbol { - Decl: &TypeDecl // Never changed by semantic analyzer. - Kind: &TypeKind + Decl: &TypeDecl // Never changed by semantic analyzer. + Kind: &TypeKind } impl TypeSymbol { - // Reports whether type is checked already. - fn checked(self): bool { ret self.Kind != nil } + // Reports whether type is checked already. + fn checked(self): bool { ret self.Kind != nil } - // Removes kind and ready to check. - // checked() reports false after this function. - fn removeKind(mut self) { self.Kind = nil } + // Removes kind and ready to check. + // checked() reports false after this function. + fn removeKind(mut self) { self.Kind = nil } } // Primitive type. struct Prim { - Kind: str + Kind: str } impl Kind for Prim { - // Returns kind. - fn Str(self): str { - ret self.Kind - } - - // Reports whether types are same. - fn Equal(&self, other: &TypeKind): bool { - prim := unsafe { (*(&other)).Prim() } - if prim == nil { - ret false - } - ret self.Kind == prim.Kind - } + // Returns kind. + fn Str(self): str { + ret self.Kind + } + + // Reports whether types are same. + fn Equal(&self, other: &TypeKind): bool { + prim := unsafe { (*(&other)).Prim() } + if prim == nil { + ret false + } + ret self.Kind == prim.Kind + } } impl Prim { - // Reports whether type is built-in constraint. - fn IsConstraint(self): bool { - ret !self.IsStr() && - !self.IsAny() && - !self.IsBool() && - !types::IsNum(self.Kind) - } + // Reports whether type is built-in constraint. + fn IsConstraint(self): bool { + ret !self.IsStr() && + !self.IsAny() && + !self.IsBool() && + !types::IsNum(self.Kind) + } - // Reports whether type is primitive i8. - fn IsI8(self): bool { ret self.Kind == PrimKind.I8 } + // Reports whether type is primitive i8. + fn IsI8(self): bool { ret self.Kind == PrimKind.I8 } - // Reports whether type is primitive i16. - fn IsI16(self): bool { ret self.Kind == PrimKind.I16 } + // Reports whether type is primitive i16. + fn IsI16(self): bool { ret self.Kind == PrimKind.I16 } - // Reports whether type is primitive i32. - fn IsI32(self): bool { ret self.Kind == PrimKind.I32 } + // Reports whether type is primitive i32. + fn IsI32(self): bool { ret self.Kind == PrimKind.I32 } - // Reports whether type is primitive i64. - fn IsI64(self): bool { ret self.Kind == PrimKind.I64 } + // Reports whether type is primitive i64. + fn IsI64(self): bool { ret self.Kind == PrimKind.I64 } - // Reports whether type is primitive u8. - fn IsU8(self): bool { ret self.Kind == PrimKind.U8 } + // Reports whether type is primitive u8. + fn IsU8(self): bool { ret self.Kind == PrimKind.U8 } - // Reports whether type is primitive u16. - fn IsU16(self): bool { ret self.Kind == PrimKind.U16 } + // Reports whether type is primitive u16. + fn IsU16(self): bool { ret self.Kind == PrimKind.U16 } - // Reports whether type is primitive u32. - fn IsU32(self): bool { ret self.Kind == PrimKind.U32 } + // Reports whether type is primitive u32. + fn IsU32(self): bool { ret self.Kind == PrimKind.U32 } - // Reports whether type is primitive u64. - fn IsU64(self): bool { ret self.Kind == PrimKind.U64 } + // Reports whether type is primitive u64. + fn IsU64(self): bool { ret self.Kind == PrimKind.U64 } - // Reports whether type is primitive f32. - fn IsF32(self): bool { ret self.Kind == PrimKind.F32 } + // Reports whether type is primitive f32. + fn IsF32(self): bool { ret self.Kind == PrimKind.F32 } - // Reports whether type is primitive f64. - fn IsF64(self): bool { ret self.Kind == PrimKind.F64 } + // Reports whether type is primitive f64. + fn IsF64(self): bool { ret self.Kind == PrimKind.F64 } - // Reports whether type is primitive int. - fn IsInt(self): bool { ret self.Kind == PrimKind.Int } + // Reports whether type is primitive int. + fn IsInt(self): bool { ret self.Kind == PrimKind.Int } - // Reports whether type is primitive uint. - fn IsUint(self): bool { ret self.Kind == PrimKind.Uint } + // Reports whether type is primitive uint. + fn IsUint(self): bool { ret self.Kind == PrimKind.Uint } - // Reports whether type is primitive uintptr. - fn IsUintptr(self): bool { ret self.Kind == PrimKind.Uintptr } + // Reports whether type is primitive uintptr. + fn IsUintptr(self): bool { ret self.Kind == PrimKind.Uintptr } - // Reports whether type is primitive bool. - fn IsBool(self): bool { ret self.Kind == PrimKind.Bool } + // Reports whether type is primitive bool. + fn IsBool(self): bool { ret self.Kind == PrimKind.Bool } - // Reports whether type is primitive str. - fn IsStr(self): bool { ret self.Kind == PrimKind.Str } + // Reports whether type is primitive str. + fn IsStr(self): bool { ret self.Kind == PrimKind.Str } - // Reports whether type is primitive any. - fn IsAny(self): bool { ret self.Kind == PrimKind.Any } + // Reports whether type is primitive any. + fn IsAny(self): bool { ret self.Kind == PrimKind.Any } } // Smart pointer. struct Sptr { - Elem: &TypeKind + Elem: &TypeKind } impl Kind for Sptr { - // Returns smart pointer kind as string. - fn Str(self): str { ret "&" + self.Elem.Str() } - - // Reports whether types are same. - fn Equal(&self, other: &TypeKind): bool { - sptr := unsafe { (*(&other)).Sptr() } - if sptr == nil { - ret false - } - ret self.Elem.Equal(sptr.Elem) - } + // Returns smart pointer kind as string. + fn Str(self): str { ret "&" + self.Elem.Str() } + + // Reports whether types are same. + fn Equal(&self, other: &TypeKind): bool { + sptr := unsafe { (*(&other)).Sptr() } + if sptr == nil { + ret false + } + ret self.Elem.Equal(sptr.Elem) + } } // Slice type. struct Slc { - Elem: &TypeKind + Elem: &TypeKind } impl Kind for Slc { - // Returns slice kind as string. - fn Str(self): str { ret "[]" + self.Elem.Str() } - - // Reports whether types are same. - fn Equal(&self, other: &TypeKind): bool { - slc := unsafe { (*(&other)).Slc() } - if slc == nil { - ret false - } - ret self.Elem.Equal(slc.Elem) - } + // Returns slice kind as string. + fn Str(self): str { ret "[]" + self.Elem.Str() } + + // Reports whether types are same. + fn Equal(&self, other: &TypeKind): bool { + slc := unsafe { (*(&other)).Slc() } + if slc == nil { + ret false + } + ret self.Elem.Equal(slc.Elem) + } } // Tuple type. struct Tuple { - Types: []&TypeKind + Types: []&TypeKind } impl Kind for Tuple { - // Returns tuple kind as string. - fn Str(self): str { - mut s := StrBuilder.New(1 << 4) - s.WriteByte('(') - s.WriteStr(self.Types[0].Str()) - for _, t in self.Types[1:] { - s.WriteByte(',') - s.WriteStr(t.Str()) - } - s.WriteByte(')') - ret s.Str() - } - - // Reports whether types are same. - fn Equal(&self, other: &TypeKind): bool { - tup := unsafe { (*(&other)).Tup() } - if tup == nil { - ret false - } - if len(self.Types) != len(tup.Types) { - ret false - } - mut i := 0 - for i < len(self.Types); i++ { - if !self.Types[i].Equal(tup.Types[i]) { - ret false - } - } - - ret true - } + // Returns tuple kind as string. + fn Str(self): str { + mut s := StrBuilder.New(1 << 4) + s.WriteByte('(') + s.WriteStr(self.Types[0].Str()) + for _, t in self.Types[1:] { + s.WriteByte(',') + s.WriteStr(t.Str()) + } + s.WriteByte(')') + ret s.Str() + } + + // Reports whether types are same. + fn Equal(&self, other: &TypeKind): bool { + tup := unsafe { (*(&other)).Tup() } + if tup == nil { + ret false + } + if len(self.Types) != len(tup.Types) { + ret false + } + mut i := 0 + for i < len(self.Types); i++ { + if !self.Types[i].Equal(tup.Types[i]) { + ret false + } + } + + ret true + } } // Map type. struct Map { - Key: &TypeKind - Val: &TypeKind + Key: &TypeKind + Val: &TypeKind } impl Kind for Map { - // Returns map kind as string. - fn Str(self): str { - mut s := StrBuilder.New(1 << 4) - s.WriteStr("map[") - s.WriteStr(self.Key.Str()) - s.WriteByte(']') - s.WriteStr(self.Val.Str()) - ret s.Str() - } - - // Reports whether types are same. - fn Equal(&self, other: &TypeKind): bool { - m := unsafe { (*(&other)).Map() } - if m == nil { - ret false - } - ret self.Key.Equal(m.Key) && self.Val.Equal(m.Val) - } + // Returns map kind as string. + fn Str(self): str { + mut s := StrBuilder.New(1 << 4) + s.WriteStr("map[") + s.WriteStr(self.Key.Str()) + s.WriteByte(']') + s.WriteStr(self.Val.Str()) + ret s.Str() + } + + // Reports whether types are same. + fn Equal(&self, other: &TypeKind): bool { + m := unsafe { (*(&other)).Map() } + if m == nil { + ret false + } + ret self.Key.Equal(m.Key) && self.Val.Equal(m.Val) + } } // Array type. struct Arr { - Auto: bool // Auto-sized array. - N: int - Elem: &TypeKind + Auto: bool // Auto-sized array. + N: int + Elem: &TypeKind } impl Kind for Arr { - // Returns array kind as string. - fn Str(self): str { - mut s := StrBuilder.New(1 << 4) - s.WriteByte('[') - s.WriteStr(conv::Itoa(self.N)) - s.WriteByte(']') - s.WriteStr(self.Elem.Str()) - ret s.Str() - } - - // Reports whether types are same. - fn Equal(&self, other: &TypeKind): bool { - arr := unsafe { (*(&other)).Arr() } - if arr == nil { - ret false - } - ret self.N == arr.N && self.Elem.Equal(arr.Elem) - } + // Returns array kind as string. + fn Str(self): str { + mut s := StrBuilder.New(1 << 4) + s.WriteByte('[') + s.WriteStr(conv::Itoa(self.N)) + s.WriteByte(']') + s.WriteStr(self.Elem.Str()) + ret s.Str() + } + + // Reports whether types are same. + fn Equal(&self, other: &TypeKind): bool { + arr := unsafe { (*(&other)).Arr() } + if arr == nil { + ret false + } + ret self.N == arr.N && self.Elem.Equal(arr.Elem) + } } // Pointer type. struct Ptr { - Elem: &TypeKind + Elem: &TypeKind } impl Kind for Ptr { - // Returns pointer kind as string. - fn Str(self): str { - if self.IsUnsafe() { - ret "*unsafe" - } - ret "*" + self.Elem.Str() - } - - // Reports whether types are same. - fn Equal(&self, other: &TypeKind): bool { - ptr := unsafe { (*(&other)).Ptr() } - match { - | ptr == nil: - ret false - | ptr.IsUnsafe(): - ret self.IsUnsafe() - |: - ret self.Elem.Equal(ptr.Elem) - } - } + // Returns pointer kind as string. + fn Str(self): str { + if self.IsUnsafe() { + ret "*unsafe" + } + ret "*" + self.Elem.Str() + } + + // Reports whether types are same. + fn Equal(&self, other: &TypeKind): bool { + ptr := unsafe { (*(&other)).Ptr() } + match { + | ptr == nil: + ret false + | ptr.IsUnsafe(): + ret self.IsUnsafe() + |: + ret self.Elem.Equal(ptr.Elem) + } + } } impl Ptr { - // Reports whether pointer is unsafe pointer (*unsafe). - fn IsUnsafe(self): bool { ret self.Elem == nil } + // Reports whether pointer is unsafe pointer (*unsafe). + fn IsUnsafe(self): bool { ret self.Elem == nil } } struct referencer { - ident: str - owner: any - refs: *[]any + ident: str + owner: any + refs: *[]any } // Checks type and builds result as kind. // Removes kind if error occurs, // so type is not reports true for checked state. struct typeChecker { - // Uses Sema for: - // - Push errors. - s: &Sema + // Uses Sema for: + // - Push errors. + s: &Sema - // Uses Lookup for: - // - Lookup symbol tables for root specific. - rootLookup: Lookup + // Uses Lookup for: + // - Lookup symbol tables for root specific. + rootLookup: Lookup - // Uses Lookup for: - // - Lookup symbol tables for current. - // - It might be change when evaluation of namespace selection or etc. - lookup: Lookup + // Uses Lookup for: + // - Lookup symbol tables for current. + // - It might be change when evaluation of namespace selection or etc. + lookup: Lookup - // If this is not nil, appends referred ident types. - // Also used as checker owner. - referencer: &referencer + // If this is not nil, appends referred ident types. + // Also used as checker owner. + referencer: &referencer - // If this not nil, type dependencies will push into stack. - refers: &ReferenceStack + // If this not nil, type dependencies will push into stack. + refers: &ReferenceStack - errorToken: &Token + errorToken: &Token - // This identifiers ignored and - // appends as primitive type. - // - // Each dimension 2 array accepted as identifier group. - ignoreGenerics: []&GenericDecl + // This identifiers ignored and + // appends as primitive type. + // + // Each dimension 2 array accepted as identifier group. + ignoreGenerics: []&GenericDecl - // Relevant type kinds that contains an ignored generic type. - ignoredGenerics: *[]&TypeKind + // Relevant type kinds that contains an ignored generic type. + ignoredGenerics: *[]&TypeKind - // This generics used as type alias for real kind. - useGenerics: []&TypeAlias + // This generics used as type alias for real kind. + useGenerics: []&TypeAlias - // Current checked type is risky for cycles. - // If this field is true, cycle analysis will be executed for type. - cycleRisk: bool = true + // Current checked type is risky for cycles. + // If this field is true, cycle analysis will be executed for type. + cycleRisk: bool = true - // Disallow/suppress Jule's built-in defines. - disBuiltin: bool + // Disallow/suppress Jule's built-in defines. + disBuiltin: bool - // Name selection is enabled. - // No binded definitions, no generic type representation. - // Only typename selection. - // - // If selection is a struct, returns invalid instance that only has decl field. - selection: bool + // Name selection is enabled. + // No binded definitions, no generic type representation. + // Only typename selection. + // + // If selection is a struct, returns invalid instance that only has decl field. + selection: bool - // See developer reference (4). - ownerAlias: &TypeAlias + // See developer reference (4). + ownerAlias: &TypeAlias - // This generics are banned because of causes instantiation cycles. - // Usually stores structure generics and method generics. - // See developer reference (5). - bannedGenerics: []&TypeAlias + // This generics are banned because of causes instantiation cycles. + // Usually stores structure generics and method generics. + // See developer reference (5). + bannedGenerics: []&TypeAlias - // Enable/Disable status of instantiation catching. - // See developer reference (6). - inscatch: bool + // Enable/Disable status of instantiation catching. + // See developer reference (6). + inscatch: bool } impl typeChecker { - fn pushErr(mut self, token: &Token, fmt: LogMsg, args: ...any) { - self.s.pushErr(token, fmt, args...) - } - - fn allowBuiltin(mut self) { - self.disBuiltin = false - } - - fn disallowBuiltin(mut self) { - self.disBuiltin = true - } - - fn pushReference[T](mut self, mut &t: T) { - if self.refers == nil { - ret - } - if self.refers.Exist[T](t) { - ret - } - self.refers.Push(t) - } - - fn pushReferenceByKind(mut self, mut &k: &TypeKind) { - match { - | k.Struct() != nil: - mut t := k.Struct() - self.pushReference[&StructIns](t) - | k.Trait() != nil: - mut t := k.Trait() - self.pushReference[&Trait](t) - } - } - - fn pushCycleError(self, def1: any, def2: any, mut &message: StrBuilder) { - const Padding = 7 - getIdent := fn(&def: any): str { - match type def { - | &TypeAlias: - ret (&TypeAlias)(def).Ident - | &Struct: - ret (&Struct)(def).Ident - |: - ret "" - } - } - m := message.Str() - def1Ident := getIdent(def1) - def2Ident := getIdent(def2) - refersTo := Logf(LogMsg.RefersTo, def1Ident, def2Ident) - message.WriteStr(strings::Repeat(" ", Padding)) - message.WriteStr(refersTo) - message.WriteByte('\n') - message.WriteStr(m) - } - - fn checkCrossCycle(self, decl: any, mut &message: StrBuilder): bool { - match type decl { - | &TypeAlias: - ta := (&TypeAlias)(decl) - for _, d in ta.Refers { - match { - | self.referencer.owner == d: - self.pushCycleError(ta, d, message) - ret false - | !self.checkCrossCycle(d, message): - self.pushCycleError(ta, d, message) - ret false - } - } - | &Struct: - s := (&Struct)(decl) - for _, d in s.Depends { - match { - | self.referencer.owner == d: - self.pushCycleError(s, d, message) - ret false - | !self.checkCrossCycle(d, message): - self.pushCycleError(s, d, message) - ret false - } - } - } - ret true - } - - // Checks type alias illegal cycles. - // Appends reference to reference if there is no illegal cycle. - // Returns true if self.referencer is nil reference. - // Returns true if refers is nil. - fn checkIllegalCycles(mut self, &ident: &IdentTypeDecl, mut decl: any): (ok: bool) { - if self.referencer == nil || !self.cycleRisk { - ret true - } - - match type decl { - | &Struct: - if (&Struct)(decl).Binded { - ret true - } - | &TypeAlias: - if (&TypeAlias)(decl).Binded { - ret true - } - } - - // Check illegal cycle for itself. - // Because refers's owner is decl. - if self.referencer.owner == decl { - self.pushErr(ident.Token, LogMsg.IllegalCycleRefersItself, self.referencer.ident) - ret false - } - - mut message := StrBuilder.New(1 << 5) - - if !self.checkCrossCycle(decl, message) { - mut errMsg := message.Str() - message.Clear() - self.pushCycleError(self.referencer.owner, decl, message) - errMsg += message.Str() - self.pushErr(ident.Token, LogMsg.IllegalCrossCycle, errMsg) - ret false - } - - match type self.referencer.owner { - | &TypeAlias: - unsafe { - *self.referencer.refs = append(*self.referencer.refs, decl) - } - | &Struct: - match type decl { - | &Struct: - mut s := (&Struct)(self.referencer.owner) - s.Depends = append(s.Depends, (&Struct)(decl)) - } - } - - ret true - } - - fn fromTypeAlias(mut self, &decl: &IdentTypeDecl, mut &ta: &TypeAlias): Kind { - if !self.s.isAccessibleDefine(ta.Public, ta.Token) { - self.pushErr(decl.Token, LogMsg.IdentNotExist, decl.Ident) - ret nil - } - - ta.Used = true - - if len(decl.Generics) > 0 { - self.pushErr(decl.Token, LogMsg.TypeNotSupportsGenerics, decl.Ident) - ret nil - } - - // Enable instantiation cycle catching if type alias is - // one of the banned generics. - if !self.inscatch && self.bannedGenerics != nil { - self.inscatch = true - for _, bg in self.bannedGenerics { - if bg == ta || ta.Kind.Kind != nil && ta.Kind.Kind.Equal(bg.Kind.Kind) { - self.inscatch = false - break - } - } - } - - // Catch instantiation cycles. - // See developer reference (5). - if self.inscatch { - for _, bg in self.bannedGenerics { - if bg == ta { - self.pushErr(decl.Token, LogMsg.InitiationCycle, decl.Ident) - ret nil - } - for _, dg in ta.Generics { - if bg == dg { - self.pushErr(decl.Token, LogMsg.InitiationCycle, decl.Ident) - ret nil - } - } - } - } - - mut ok := self.checkIllegalCycles(decl, ta) - if !ok { - ret nil - } - - // Build kind if not builded already. - if ta.Kind.Kind == nil { - ok = self.s.checkTypeAliasDeclKind(ta, self.lookup) - if !ok { - ret nil - } - } - - // Push generic reference to owner type alias. - // See developer reference (3) and (4) for more information. - if ta.Generic && self.ownerAlias != nil { - self.ownerAlias.Generics = append(self.ownerAlias.Generics, ta) - } - - mut tk := &TypeKind{ - Generic: ta.Generic, - Kind: ta.Kind.Kind.Kind, - } - self.pushReferenceByKind(tk) - if ta.Binded { - tk.BindIdent = ta.Ident - } else { - tk.BindIdent = ta.Kind.Kind.BindIdent - } - ret tk - } - - fn fromEnum(mut self, &decl: &IdentTypeDecl, mut &e: &Enum): &Enum { - if !self.s.isAccessibleDefine(e.Public, e.Token) { - self.pushErr(decl.Token, LogMsg.IdentNotExist, decl.Ident) - ret nil - } - if len(decl.Generics) > 0 { - self.pushErr(decl.Token, LogMsg.TypeNotSupportsGenerics, decl.Ident) - ret nil - } - ret e - } - - fn fromTypeEnum(mut self, &decl: &IdentTypeDecl, mut &e: &TypeEnum): &TypeEnum { - if !self.s.isAccessibleDefine(e.Public, e.Token) { - self.pushErr(decl.Token, LogMsg.IdentNotExist, decl.Ident) - ret nil - } - if len(decl.Generics) > 0 { - self.pushErr(decl.Token, LogMsg.TypeNotSupportsGenerics, decl.Ident) - ret nil - } - ret e - } - - fn fromTrait(mut self, &decl: &IdentTypeDecl, mut &t: &Trait): &Trait { - if !self.s.isAccessibleDefine(t.Public, t.Token) { - self.pushErr(decl.Token, LogMsg.IdentNotExist, decl.Ident) - ret nil - } - if len(decl.Generics) > 0 { - self.pushErr(decl.Token, LogMsg.TypeNotSupportsGenerics, decl.Ident) - ret nil - } - self.pushReference[&Trait](t) - ret t - } - - fn checkStructIns(mut self, mut &ins: &StructIns, mut &errorToken: &Token): (ok: bool) { - if ins.Checked { - ret true - } - ins.Checked = true - - // Break algorithm cycle. - if self.referencer != nil && self.referencer.owner == ins.Decl { - ret true - } - - if !self.s.precheckStructIns(ins, errorToken) { - ret false - } - if len(ins.Generics) > 0 { - self.s.checkStructInsOperators(ins) - self.s.checkStructIns(ins) - } - ret true - } - - fn appendUsedStructReference(mut self, mut &s: &Struct) { - if self.referencer == nil { - ret - } - match type self.referencer.owner { - | &Struct: - mut refS := (&Struct)(self.referencer.owner) - if !refS.IsUses(s) { - refS.Uses = append(refS.Uses, s) - } - } - } - - fn buildStructInstance(mut self, mut &decl: &IdentTypeDecl, mut &s: &Struct): &StructIns { - // Save configuration. - mut referencer := self.referencer - self.referencer = nil - mut bannedGenerics := self.bannedGenerics - - // Set banned generics to catch initiation cycles. - // This just necessary for root, therefore avoid set each time. - if self.bannedGenerics == nil { - match type self.lookup { - | &scopeChecker: - mut sc := (&scopeChecker)(self.lookup) - mut hard := sc.getHardRoot() - if hard.owner.Owner == nil || hard.owner.Owner.Decl != s { - break - } - n := len(hard.owner.Generics) + len(hard.owner.Owner.Generics) - // Add scope generics to to catch instantiation cycles. - // See developer reference (5). - self.bannedGenerics = hard.table.TypeAliases[:n] - } - } else { - self.inscatch = true - } - - // Use rootLookup to parse generics with current current. - mut lookup := self.lookup - self.lookup = self.rootLookup - - // Build generics. - mut ins := s.instance() - ins.Generics = make([]&InsGeneric, 0, len(decl.Generics)) - for (_, mut g) in decl.Generics { - mut kind := self.build(g.Kind) - if kind == nil { - ret nil - } - ins.Generics = append(ins.Generics, &InsGeneric{Kind: kind}) - } - - // Restore configuration. - self.lookup = lookup - self.bannedGenerics = bannedGenerics - self.referencer = referencer - - ret ins - } - - fn fromStruct(mut self, mut &decl: &IdentTypeDecl, mut &s: &Struct): &StructIns { - if !self.s.isAccessibleDefine(s.Public, s.Token) { - self.pushErr(decl.Token, LogMsg.IdentNotExist, decl.Ident) - ret nil - } - - // Name selection. - // Return instance instantly. - if self.selection { - if len(decl.Generics) > 0 { - self.pushErr(decl.Token, LogMsg.GenericsNotAllowed) - ret nil - } - ret &StructIns{ - Decl: s, - } - } - - mut ok := self.checkIllegalCycles(decl, s) - if !ok { - ret nil - } - self.appendUsedStructReference(s) - - mut ins := self.buildStructInstance(decl, s) - if ins == nil { - ret nil - } - - ok = self.s.checkGenericQuantity(len(ins.Decl.Generics), len(ins.Generics), decl.Token) - if !ok { - ret nil - } - - mut existInstance := s.appendInstance(ins) - if existInstance != nil { - if !self.s.checkConstraintsStruct(ins, decl.Token, existInstance) { - ret nil - } - // Already checked instance, did not appended. - // So, this instance is not unique. - self.pushReference[&StructIns](existInstance) - ret existInstance - } - if !self.checkStructIns(ins, decl.Token) { - ret nil - } - self.pushReference[&StructIns](ins) - ret ins - } - - // Returns identifier if found. Also checks founded identifier. - // Uses internal lookup for all process except finding step of identifier. - // Will find identifier in [l], not internal lookup. - // Also finds in built-in lookup if allowed. - // If another lookup nedeed, uses internal lookup, so any generic type build - // process will use internal lookup. This might be useful for building - // genericed type from another package. - fn getDef(mut self, mut &decl: &IdentTypeDecl): Kind { - for _, g in self.ignoreGenerics { - if g.Ident == decl.Ident { - ret buildPrimType(g.Ident) - } - } - - for (_, mut g) in self.useGenerics { - if g.Ident == decl.Ident { - if len(decl.Generics) > 0 { - self.pushErr(decl.Token, LogMsg.TypeNotSupportsGenerics, decl.Ident) - ret nil - } - mut st := g.Kind.Kind.Struct() - if st != nil { - ok := self.checkIllegalCycles(decl, st.Decl) - if !ok { - ret nil - } - } - ret g.Kind.Kind.Kind - } - } - - if !decl.Binded { - mut e := self.lookup.FindEnum(decl.Ident) - if e != nil { - ret self.fromEnum(decl, e) - } - - mut te := self.lookup.FindTypeEnum(decl.Ident) - if te != nil { - ret self.fromTypeEnum(decl, te) - } - - mut t := self.lookup.FindTrait(decl.Ident) - if t != nil { - ret self.fromTrait(decl, t) - } - } else if self.selection { - self.pushErr(decl.Token, LogMsg.BindedTypeNotAllowed) - ret nil - } - - mut s := self.lookup.FindStruct(decl.Ident, decl.Binded) - if s != nil { - ret self.fromStruct(decl, s) - } - - mut ta := self.lookup.FindTypeAlias(decl.Ident, decl.Binded) - if ta == nil && !self.disBuiltin { - ta = findBuiltinTypeAlias(decl.Ident) - } - if ta != nil { - ret self.fromTypeAlias(decl, ta) - } - - self.pushErr(decl.Token, LogMsg.IdentNotExist, decl.Ident) - ret nil - } - - fn buildIdent(mut self, mut decl: &IdentTypeDecl): Kind { - ret self.getDef(decl) - } - - fn buildSubIdent(mut self, mut decl: &SubIdentTypeDecl): Kind { - mut ident := self.buildIdent(decl.Idents[0]) - if ident == nil { - ret nil - } - match type ident { - | &TypeEnum: - break - |: - self.pushErr(self.errorToken, LogMsg.InvalidSyntax) - ret nil - } - mut t := (&TypeEnum)(ident) - mut idents := decl.Idents[1:] - for i, id in idents { - mut item := t.FindItem(id.Ident) - if item == nil { - self.pushErr(id.Token, LogMsg.ObjHaveNotIdent, t.Ident, id.Ident) - ret nil - } - if len(idents)-i == 1 { - self.pushReferenceByKind(item.Kind.Kind) - ret item.Kind.Kind - } - t = item.Kind.Kind.TypeEnum() - if t == nil { - self.pushErr(self.errorToken, LogMsg.InvalidSyntax) - ret nil - } - } - // Should be unreachable. - ret nil - } - - fn buildSptrFromType(mut self, mut &elem: &TypeKind): &Sptr { - // Check special cases. - match { - | elem == nil: - ret nil - | elem.Struct() != nil: - s := elem.Struct() - if s.Decl != nil && s.Decl.Binded { - self.pushErr(self.errorToken, LogMsg.BindedStructForRef) - ret nil - } - | elem.Arr() != nil && elem.Arr().Auto: - self.pushErr(self.errorToken, LogMsg.ArrayAutoSized) - ret nil - } - ret &Sptr{ - Elem: elem, - } - } - - fn buildSptr(mut self, mut decl: &SptrTypeDecl): &Sptr { - cycleRisk := self.cycleRisk - self.cycleRisk = false - defer { self.cycleRisk = cycleRisk } - - mut elem := self.checkDecl(decl.Elem) - ret self.buildSptrFromType(elem) - } - - fn buildPtrFromType(mut self, mut &elem: &TypeKind): &Ptr { - // Check special cases. - match { - | elem == nil: - ret nil - | elem.Arr() != nil && elem.Arr().Auto: - self.pushErr(self.errorToken, LogMsg.ArrayAutoSized) - ret new(Ptr) - } - - ret &Ptr{ - Elem: elem, - } - } - - fn buildPtr(mut self, mut decl: &PtrTypeDecl): &Ptr { - cycleRisk := self.cycleRisk - self.cycleRisk = false - defer { self.cycleRisk = cycleRisk } - - let mut elem: &TypeKind = nil - - if !decl.IsUnsafe() { - elem = self.checkDecl(decl.Elem) - ret self.buildPtrFromType(elem) - } - - ret &Ptr{ - Elem: elem, - } - } - - fn buildSlc(mut self, mut decl: &SlcTypeDecl): &Slc { - cycleRisk := self.cycleRisk - self.cycleRisk = false - defer { self.cycleRisk = cycleRisk } - - mut elem := self.checkDecl(decl.Elem) - - // Check special cases. - match { - | elem == nil: - ret nil - | elem.Arr() != nil && elem.Arr().Auto: - self.pushErr(decl.Elem.Token, LogMsg.ArrayAutoSized) - ret nil - } - - ret &Slc{ - Elem: elem, - } - } - - fn buildArr(mut self, mut decl: &ArrTypeDecl): &Arr { - mut n := 0 - - if !decl.AutoSized() { - mut size := self.s.eval(self.lookup).evalExpr(decl.Size) - if size == nil { - ret nil - } - - if !size.IsConst() { - self.pushErr(decl.Size.Token, LogMsg.ExprNotConst) - ret nil - } else if size.Kind.Prim() == nil || !types::IsInt(size.Kind.Prim().Kind) { - self.pushErr(decl.Size.Token, LogMsg.ArraySizeIsNotInt) - ret nil - } - - n = int(size.Constant.AsI64()) - if n < 0 { - self.pushErr(decl.Elem.Token, LogMsg.ArraySizeIsNeg) - ret nil - } else { - max := types::MaxI(PrimKind.Int) - if types::BitSize != 64 && i64(n) > max { - self.pushErr(decl.Size.Token, LogMsg.ArraySizeOverflow, - constoa(size.Constant), conv::FmtInt(max, 10)) - ret nil - } - } - } - - mut elem := self.checkDecl(decl.Elem) - - // Check special cases. - match { - | elem == nil: - ret nil - | elem.Arr() != nil && elem.Arr().Auto: - self.pushErr(decl.Elem.Token, LogMsg.ArrayAutoSized) - ret nil - } - - ret &Arr{ - Auto: decl.AutoSized(), - N: n, - Elem: elem, - } - } - - fn buildMap(mut self, mut decl: &MapTypeDecl): &Map { - cycleRisk := self.cycleRisk - self.cycleRisk = false - defer { self.cycleRisk = cycleRisk } - - mut key := self.checkDecl(decl.Key) - if key == nil { - ret nil - } - - mut val := self.checkDecl(decl.Val) - if val == nil { - ret nil - } - if val.Enum() != nil { - self.pushErr(decl.Val.Token, LogMsg.EnumAsMapVal) - } - - ret &Map{ - Key: key, - Val: val, - } - } - - fn buildTuple(mut self, mut decl: &TupleTypeDecl): &Tuple { - mut types := make([]&TypeKind, 0, len(decl.Types)) - for (_, mut t) in decl.Types { - mut kind := self.checkDecl(t) - if kind == nil { - ret nil - } - types = append(types, kind) - } - - ret &Tuple{Types: types} - } - - fn checkFuncTypes(mut self, mut &f: &FnIns): (ok: bool) { - for (_, mut p) in f.Params { - p.Kind = self.build(p.Decl.Kind.Decl.Kind) - ok = p.Kind != nil - if !ok { - ret false - } - self.s.checkFnParamKind(p) - } - - if !f.Decl.IsVoid() { - f.Result = self.build(f.Decl.Result.Kind.Decl.Kind) - ret f.Result != nil - } - - ret true - } - - fn buildFunc(mut self, mut decl: &FnDecl): &FnIns { - cycleRisk := self.cycleRisk - self.cycleRisk = false - defer { self.cycleRisk = cycleRisk } - - if len(decl.Generics) > 0 { - self.pushErr(decl.Token, LogMsg.GenericedFnAsAnonFn) - ret nil - } - - mut f := buildFunc(decl) - - n := len(self.s.errors) - self.s.checkAnonFuncDecl(f) - if n != len(self.s.errors) { - ret nil - } - - mut ins := f.instanceForce() - ins.Anon = true - ins.AsAnon = true - - ok := self.checkFuncTypes(ins) - if !ok { - ret nil - } - - ret ins - } - - fn buildByNamespace(mut self, mut decl: &NamespaceTypeDecl): Kind { - path := buildLinkPathByTokens(decl.Idents) - mut imp := self.lookup.SelectPackage(fn(imp: &ImportInfo): bool { - if len(decl.Idents) == 1 && imp.Alias == path { - ret true - } - ret imp.LinkPath == path && imp.isAccessibleViaSelection() - }) - - selfIdent := str(TokenKind.Self) - if imp == nil || !imp.isLookupable(selfIdent) { - self.pushErr(decl.Idents[0], LogMsg.NamespaceNotExist, path) - ret nil - } - - self.disallowBuiltin() - mut lookup := self.lookup - self.lookup = imp - mut kind := self.checkDecl(decl.Kind) - self.lookup = lookup - self.allowBuiltin() - ret kind - } - - fn build(mut self, mut &declKind: TypeDeclKind): &TypeKind { - let mut kind: Kind = nil - match type declKind { - | &IdentTypeDecl: - mut t := self.buildIdent((&IdentTypeDecl)(declKind)) - if t != nil { - kind = t - } - | &SubIdentTypeDecl: - mut t := self.buildSubIdent((&SubIdentTypeDecl)(declKind)) - if t != nil { - kind = t - } - | &SptrTypeDecl: - self.inscatch = true - mut t := self.buildSptr((&SptrTypeDecl)(declKind)) - if t != nil { - kind = t - } - | &PtrTypeDecl: - self.inscatch = true - mut t := self.buildPtr((&PtrTypeDecl)(declKind)) - if t != nil { - kind = t - } - | &SlcTypeDecl: - self.inscatch = true - mut t := self.buildSlc((&SlcTypeDecl)(declKind)) - if t != nil { - kind = t - } - | &ArrTypeDecl: - self.inscatch = true - mut t := self.buildArr((&ArrTypeDecl)(declKind)) - if t != nil { - kind = t - } - | &MapTypeDecl: - self.inscatch = true - mut t := self.buildMap((&MapTypeDecl)(declKind)) - if t != nil { - kind = t - } - | &TupleTypeDecl: - self.inscatch = true - mut t := self.buildTuple((&TupleTypeDecl)(declKind)) - if t != nil { - kind = t - } - | &FnDecl: - self.inscatch = true - mut t := self.buildFunc((&FnDecl)(declKind)) - if t != nil { - kind = t - } - | &NamespaceTypeDecl: - self.inscatch = true - mut t := self.buildByNamespace((&NamespaceTypeDecl)(declKind)) - if t != nil { - kind = t - } - |: - self.pushErr(self.errorToken, LogMsg.InvalidType) - ret nil - } - if kind == nil { - ret nil - } - match type kind { - | &TypeKind: - ret (&TypeKind)(kind) - |: - mut tk := &TypeKind{Kind: kind} - match type kind { - | &Prim: - if self.ignoredGenerics != nil { - unsafe { *self.ignoredGenerics = append(*self.ignoredGenerics, tk) } - } - | &StructIns: - s := (&StructIns)(kind) - if s.Decl != nil && s.Decl.Binded { - tk.BindIdent = s.Decl.Ident - } - } - ret tk - } - } - - fn checkDecl(mut self, mut &decl: &TypeDecl): &TypeKind { - // Save current token. - mut errorToken := self.errorToken - - self.errorToken = decl.Token - mut kind := self.build(decl.Kind) - self.errorToken = errorToken - - ret kind - } - - fn check(mut self, mut &t: &TypeSymbol) { - if t.Decl == nil { - ret - } - mut kind := self.checkDecl(t.Decl) - if kind == nil { - t.removeKind() - ret - } - t.Kind = kind - } + fn pushErr(mut self, token: &Token, fmt: LogMsg, args: ...any) { + self.s.pushErr(token, fmt, args...) + } + + fn allowBuiltin(mut self) { + self.disBuiltin = false + } + + fn disallowBuiltin(mut self) { + self.disBuiltin = true + } + + fn pushReference[T](mut self, mut &t: T) { + if self.refers == nil { + ret + } + if self.refers.Exist[T](t) { + ret + } + self.refers.Push(t) + } + + fn pushReferenceByKind(mut self, mut &k: &TypeKind) { + match { + | k.Struct() != nil: + mut t := k.Struct() + self.pushReference[&StructIns](t) + | k.Trait() != nil: + mut t := k.Trait() + self.pushReference[&Trait](t) + } + } + + fn pushCycleError(self, def1: any, def2: any, mut &message: StrBuilder) { + const Padding = 7 + getIdent := fn(&def: any): str { + match type def { + | &TypeAlias: + ret (&TypeAlias)(def).Ident + | &Struct: + ret (&Struct)(def).Ident + |: + ret "" + } + } + m := message.Str() + def1Ident := getIdent(def1) + def2Ident := getIdent(def2) + refersTo := Logf(LogMsg.RefersTo, def1Ident, def2Ident) + message.WriteStr(strings::Repeat(" ", Padding)) + message.WriteStr(refersTo) + message.WriteByte('\n') + message.WriteStr(m) + } + + fn checkCrossCycle(self, decl: any, mut &message: StrBuilder): bool { + match type decl { + | &TypeAlias: + ta := (&TypeAlias)(decl) + for _, d in ta.Refers { + match { + | self.referencer.owner == d: + self.pushCycleError(ta, d, message) + ret false + | !self.checkCrossCycle(d, message): + self.pushCycleError(ta, d, message) + ret false + } + } + | &Struct: + s := (&Struct)(decl) + for _, d in s.Depends { + match { + | self.referencer.owner == d: + self.pushCycleError(s, d, message) + ret false + | !self.checkCrossCycle(d, message): + self.pushCycleError(s, d, message) + ret false + } + } + } + ret true + } + + // Checks type alias illegal cycles. + // Appends reference to reference if there is no illegal cycle. + // Returns true if self.referencer is nil reference. + // Returns true if refers is nil. + fn checkIllegalCycles(mut self, &ident: &IdentTypeDecl, mut decl: any): (ok: bool) { + if self.referencer == nil || !self.cycleRisk { + ret true + } + + match type decl { + | &Struct: + if (&Struct)(decl).Binded { + ret true + } + | &TypeAlias: + if (&TypeAlias)(decl).Binded { + ret true + } + } + + // Check illegal cycle for itself. + // Because refers's owner is decl. + if self.referencer.owner == decl { + self.pushErr(ident.Token, LogMsg.IllegalCycleRefersItself, self.referencer.ident) + ret false + } + + mut message := StrBuilder.New(1 << 5) + + if !self.checkCrossCycle(decl, message) { + mut errMsg := message.Str() + message.Clear() + self.pushCycleError(self.referencer.owner, decl, message) + errMsg += message.Str() + self.pushErr(ident.Token, LogMsg.IllegalCrossCycle, errMsg) + ret false + } + + match type self.referencer.owner { + | &TypeAlias: + unsafe { + *self.referencer.refs = append(*self.referencer.refs, decl) + } + | &Struct: + match type decl { + | &Struct: + mut s := (&Struct)(self.referencer.owner) + s.Depends = append(s.Depends, (&Struct)(decl)) + } + } + + ret true + } + + fn fromTypeAlias(mut self, &decl: &IdentTypeDecl, mut &ta: &TypeAlias): Kind { + if !self.s.isAccessibleDefine(ta.Public, ta.Token) { + self.pushErr(decl.Token, LogMsg.IdentNotExist, decl.Ident) + ret nil + } + + ta.Used = true + + if len(decl.Generics) > 0 { + self.pushErr(decl.Token, LogMsg.TypeNotSupportsGenerics, decl.Ident) + ret nil + } + + // Enable instantiation cycle catching if type alias is + // one of the banned generics. + if !self.inscatch && self.bannedGenerics != nil { + self.inscatch = true + for _, bg in self.bannedGenerics { + if bg == ta || ta.Kind.Kind != nil && ta.Kind.Kind.Equal(bg.Kind.Kind) { + self.inscatch = false + break + } + } + } + + // Catch instantiation cycles. + // See developer reference (5). + if self.inscatch { + for _, bg in self.bannedGenerics { + if bg == ta { + self.pushErr(decl.Token, LogMsg.InitiationCycle, decl.Ident) + ret nil + } + for _, dg in ta.Generics { + if bg == dg { + self.pushErr(decl.Token, LogMsg.InitiationCycle, decl.Ident) + ret nil + } + } + } + } + + mut ok := self.checkIllegalCycles(decl, ta) + if !ok { + ret nil + } + + // Build kind if not builded already. + if ta.Kind.Kind == nil { + ok = self.s.checkTypeAliasDeclKind(ta, self.lookup) + if !ok { + ret nil + } + } + + // Push generic reference to owner type alias. + // See developer reference (3) and (4) for more information. + if ta.Generic && self.ownerAlias != nil { + self.ownerAlias.Generics = append(self.ownerAlias.Generics, ta) + } + + mut tk := &TypeKind{ + Generic: ta.Generic, + Kind: ta.Kind.Kind.Kind, + } + self.pushReferenceByKind(tk) + if ta.Binded { + tk.BindIdent = ta.Ident + } else { + tk.BindIdent = ta.Kind.Kind.BindIdent + } + ret tk + } + + fn fromEnum(mut self, &decl: &IdentTypeDecl, mut &e: &Enum): &Enum { + if !self.s.isAccessibleDefine(e.Public, e.Token) { + self.pushErr(decl.Token, LogMsg.IdentNotExist, decl.Ident) + ret nil + } + if len(decl.Generics) > 0 { + self.pushErr(decl.Token, LogMsg.TypeNotSupportsGenerics, decl.Ident) + ret nil + } + ret e + } + + fn fromTypeEnum(mut self, &decl: &IdentTypeDecl, mut &e: &TypeEnum): &TypeEnum { + if !self.s.isAccessibleDefine(e.Public, e.Token) { + self.pushErr(decl.Token, LogMsg.IdentNotExist, decl.Ident) + ret nil + } + if len(decl.Generics) > 0 { + self.pushErr(decl.Token, LogMsg.TypeNotSupportsGenerics, decl.Ident) + ret nil + } + ret e + } + + fn fromTrait(mut self, &decl: &IdentTypeDecl, mut &t: &Trait): &Trait { + if !self.s.isAccessibleDefine(t.Public, t.Token) { + self.pushErr(decl.Token, LogMsg.IdentNotExist, decl.Ident) + ret nil + } + if len(decl.Generics) > 0 { + self.pushErr(decl.Token, LogMsg.TypeNotSupportsGenerics, decl.Ident) + ret nil + } + self.pushReference[&Trait](t) + ret t + } + + fn checkStructIns(mut self, mut &ins: &StructIns, mut &errorToken: &Token): (ok: bool) { + if ins.Checked { + ret true + } + ins.Checked = true + + // Break algorithm cycle. + if self.referencer != nil && self.referencer.owner == ins.Decl { + ret true + } + + if !self.s.precheckStructIns(ins, errorToken) { + ret false + } + if len(ins.Generics) > 0 { + self.s.checkStructInsOperators(ins) + self.s.checkStructIns(ins) + } + ret true + } + + fn appendUsedStructReference(mut self, mut &s: &Struct) { + if self.referencer == nil { + ret + } + match type self.referencer.owner { + | &Struct: + mut refS := (&Struct)(self.referencer.owner) + if !refS.IsUses(s) { + refS.Uses = append(refS.Uses, s) + } + } + } + + fn buildStructInstance(mut self, mut &decl: &IdentTypeDecl, mut &s: &Struct): &StructIns { + // Save configuration. + mut referencer := self.referencer + self.referencer = nil + mut bannedGenerics := self.bannedGenerics + + // Set banned generics to catch initiation cycles. + // This just necessary for root, therefore avoid set each time. + if self.bannedGenerics == nil { + match type self.lookup { + | &scopeChecker: + mut sc := (&scopeChecker)(self.lookup) + mut hard := sc.getHardRoot() + if hard.owner.Owner == nil || hard.owner.Owner.Decl != s { + break + } + n := len(hard.owner.Generics) + len(hard.owner.Owner.Generics) + // Add scope generics to to catch instantiation cycles. + // See developer reference (5). + self.bannedGenerics = hard.table.TypeAliases[:n] + } + } else { + self.inscatch = true + } + + // Use rootLookup to parse generics with current current. + mut lookup := self.lookup + self.lookup = self.rootLookup + + // Build generics. + mut ins := s.instance() + ins.Generics = make([]&InsGeneric, 0, len(decl.Generics)) + for (_, mut g) in decl.Generics { + mut kind := self.build(g.Kind) + if kind == nil { + ret nil + } + ins.Generics = append(ins.Generics, &InsGeneric{Kind: kind}) + } + + // Restore configuration. + self.lookup = lookup + self.bannedGenerics = bannedGenerics + self.referencer = referencer + + ret ins + } + + fn fromStruct(mut self, mut &decl: &IdentTypeDecl, mut &s: &Struct): &StructIns { + if !self.s.isAccessibleDefine(s.Public, s.Token) { + self.pushErr(decl.Token, LogMsg.IdentNotExist, decl.Ident) + ret nil + } + + // Name selection. + // Return instance instantly. + if self.selection { + if len(decl.Generics) > 0 { + self.pushErr(decl.Token, LogMsg.GenericsNotAllowed) + ret nil + } + ret &StructIns{ + Decl: s, + } + } + + mut ok := self.checkIllegalCycles(decl, s) + if !ok { + ret nil + } + self.appendUsedStructReference(s) + + mut ins := self.buildStructInstance(decl, s) + if ins == nil { + ret nil + } + + ok = self.s.checkGenericQuantity(len(ins.Decl.Generics), len(ins.Generics), decl.Token) + if !ok { + ret nil + } + + mut existInstance := s.appendInstance(ins) + if existInstance != nil { + if !self.s.checkConstraintsStruct(ins, decl.Token, existInstance) { + ret nil + } + // Already checked instance, did not appended. + // So, this instance is not unique. + self.pushReference[&StructIns](existInstance) + ret existInstance + } + if !self.checkStructIns(ins, decl.Token) { + ret nil + } + self.pushReference[&StructIns](ins) + ret ins + } + + // Returns identifier if found. Also checks founded identifier. + // Uses internal lookup for all process except finding step of identifier. + // Will find identifier in [l], not internal lookup. + // Also finds in built-in lookup if allowed. + // If another lookup nedeed, uses internal lookup, so any generic type build + // process will use internal lookup. This might be useful for building + // genericed type from another package. + fn getDef(mut self, mut &decl: &IdentTypeDecl): Kind { + for _, g in self.ignoreGenerics { + if g.Ident == decl.Ident { + ret buildPrimType(g.Ident) + } + } + + for (_, mut g) in self.useGenerics { + if g.Ident == decl.Ident { + if len(decl.Generics) > 0 { + self.pushErr(decl.Token, LogMsg.TypeNotSupportsGenerics, decl.Ident) + ret nil + } + mut st := g.Kind.Kind.Struct() + if st != nil { + ok := self.checkIllegalCycles(decl, st.Decl) + if !ok { + ret nil + } + } + ret g.Kind.Kind.Kind + } + } + + if !decl.Binded { + mut e := self.lookup.FindEnum(decl.Ident) + if e != nil { + ret self.fromEnum(decl, e) + } + + mut te := self.lookup.FindTypeEnum(decl.Ident) + if te != nil { + ret self.fromTypeEnum(decl, te) + } + + mut t := self.lookup.FindTrait(decl.Ident) + if t != nil { + ret self.fromTrait(decl, t) + } + } else if self.selection { + self.pushErr(decl.Token, LogMsg.BindedTypeNotAllowed) + ret nil + } + + mut s := self.lookup.FindStruct(decl.Ident, decl.Binded) + if s != nil { + ret self.fromStruct(decl, s) + } + + mut ta := self.lookup.FindTypeAlias(decl.Ident, decl.Binded) + if ta == nil && !self.disBuiltin { + ta = findBuiltinTypeAlias(decl.Ident) + } + if ta != nil { + ret self.fromTypeAlias(decl, ta) + } + + self.pushErr(decl.Token, LogMsg.IdentNotExist, decl.Ident) + ret nil + } + + fn buildIdent(mut self, mut decl: &IdentTypeDecl): Kind { + ret self.getDef(decl) + } + + fn buildSubIdent(mut self, mut decl: &SubIdentTypeDecl): Kind { + mut ident := self.buildIdent(decl.Idents[0]) + if ident == nil { + ret nil + } + match type ident { + | &TypeEnum: + break + |: + self.pushErr(self.errorToken, LogMsg.InvalidSyntax) + ret nil + } + mut t := (&TypeEnum)(ident) + mut idents := decl.Idents[1:] + for i, id in idents { + mut item := t.FindItem(id.Ident) + if item == nil { + self.pushErr(id.Token, LogMsg.ObjHaveNotIdent, t.Ident, id.Ident) + ret nil + } + if len(idents)-i == 1 { + self.pushReferenceByKind(item.Kind.Kind) + ret item.Kind.Kind + } + t = item.Kind.Kind.TypeEnum() + if t == nil { + self.pushErr(self.errorToken, LogMsg.InvalidSyntax) + ret nil + } + } + // Should be unreachable. + ret nil + } + + fn buildSptrFromType(mut self, mut &elem: &TypeKind): &Sptr { + // Check special cases. + match { + | elem == nil: + ret nil + | elem.Struct() != nil: + s := elem.Struct() + if s.Decl != nil && s.Decl.Binded { + self.pushErr(self.errorToken, LogMsg.BindedStructForRef) + ret nil + } + | elem.Arr() != nil && elem.Arr().Auto: + self.pushErr(self.errorToken, LogMsg.ArrayAutoSized) + ret nil + } + ret &Sptr{ + Elem: elem, + } + } + + fn buildSptr(mut self, mut decl: &SptrTypeDecl): &Sptr { + cycleRisk := self.cycleRisk + self.cycleRisk = false + defer { self.cycleRisk = cycleRisk } + + mut elem := self.checkDecl(decl.Elem) + ret self.buildSptrFromType(elem) + } + + fn buildPtrFromType(mut self, mut &elem: &TypeKind): &Ptr { + // Check special cases. + match { + | elem == nil: + ret nil + | elem.Arr() != nil && elem.Arr().Auto: + self.pushErr(self.errorToken, LogMsg.ArrayAutoSized) + ret new(Ptr) + } + + ret &Ptr{ + Elem: elem, + } + } + + fn buildPtr(mut self, mut decl: &PtrTypeDecl): &Ptr { + cycleRisk := self.cycleRisk + self.cycleRisk = false + defer { self.cycleRisk = cycleRisk } + + let mut elem: &TypeKind = nil + + if !decl.IsUnsafe() { + elem = self.checkDecl(decl.Elem) + ret self.buildPtrFromType(elem) + } + + ret &Ptr{ + Elem: elem, + } + } + + fn buildSlc(mut self, mut decl: &SlcTypeDecl): &Slc { + cycleRisk := self.cycleRisk + self.cycleRisk = false + defer { self.cycleRisk = cycleRisk } + + mut elem := self.checkDecl(decl.Elem) + + // Check special cases. + match { + | elem == nil: + ret nil + | elem.Arr() != nil && elem.Arr().Auto: + self.pushErr(decl.Elem.Token, LogMsg.ArrayAutoSized) + ret nil + } + + ret &Slc{ + Elem: elem, + } + } + + fn buildArr(mut self, mut decl: &ArrTypeDecl): &Arr { + mut n := 0 + + if !decl.AutoSized() { + mut size := self.s.eval(self.lookup).evalExpr(decl.Size) + if size == nil { + ret nil + } + + if !size.IsConst() { + self.pushErr(decl.Size.Token, LogMsg.ExprNotConst) + ret nil + } else if size.Kind.Prim() == nil || !types::IsInt(size.Kind.Prim().Kind) { + self.pushErr(decl.Size.Token, LogMsg.ArraySizeIsNotInt) + ret nil + } + + n = int(size.Constant.AsI64()) + if n < 0 { + self.pushErr(decl.Elem.Token, LogMsg.ArraySizeIsNeg) + ret nil + } else { + max := types::MaxI(PrimKind.Int) + if types::BitSize != 64 && i64(n) > max { + self.pushErr(decl.Size.Token, LogMsg.ArraySizeOverflow, + constoa(size.Constant), conv::FmtInt(max, 10)) + ret nil + } + } + } + + mut elem := self.checkDecl(decl.Elem) + + // Check special cases. + match { + | elem == nil: + ret nil + | elem.Arr() != nil && elem.Arr().Auto: + self.pushErr(decl.Elem.Token, LogMsg.ArrayAutoSized) + ret nil + } + + ret &Arr{ + Auto: decl.AutoSized(), + N: n, + Elem: elem, + } + } + + fn buildMap(mut self, mut decl: &MapTypeDecl): &Map { + cycleRisk := self.cycleRisk + self.cycleRisk = false + defer { self.cycleRisk = cycleRisk } + + mut key := self.checkDecl(decl.Key) + if key == nil { + ret nil + } + + mut val := self.checkDecl(decl.Val) + if val == nil { + ret nil + } + if val.Enum() != nil { + self.pushErr(decl.Val.Token, LogMsg.EnumAsMapVal) + } + + ret &Map{ + Key: key, + Val: val, + } + } + + fn buildTuple(mut self, mut decl: &TupleTypeDecl): &Tuple { + mut types := make([]&TypeKind, 0, len(decl.Types)) + for (_, mut t) in decl.Types { + mut kind := self.checkDecl(t) + if kind == nil { + ret nil + } + types = append(types, kind) + } + + ret &Tuple{Types: types} + } + + fn checkFuncTypes(mut self, mut &f: &FnIns): (ok: bool) { + for (_, mut p) in f.Params { + p.Kind = self.build(p.Decl.Kind.Decl.Kind) + ok = p.Kind != nil + if !ok { + ret false + } + self.s.checkFnParamKind(p) + } + + if !f.Decl.IsVoid() { + f.Result = self.build(f.Decl.Result.Kind.Decl.Kind) + ret f.Result != nil + } + + ret true + } + + fn buildFunc(mut self, mut decl: &FnDecl): &FnIns { + cycleRisk := self.cycleRisk + self.cycleRisk = false + defer { self.cycleRisk = cycleRisk } + + if len(decl.Generics) > 0 { + self.pushErr(decl.Token, LogMsg.GenericedFnAsAnonFn) + ret nil + } + + mut f := buildFunc(decl) + + n := len(self.s.errors) + self.s.checkAnonFuncDecl(f) + if n != len(self.s.errors) { + ret nil + } + + mut ins := f.instanceForce() + ins.Anon = true + ins.AsAnon = true + + ok := self.checkFuncTypes(ins) + if !ok { + ret nil + } + + ret ins + } + + fn buildByNamespace(mut self, mut decl: &NamespaceTypeDecl): Kind { + path := buildLinkPathByTokens(decl.Idents) + mut imp := self.lookup.SelectPackage(fn(imp: &ImportInfo): bool { + if len(decl.Idents) == 1 && imp.Alias == path { + ret true + } + ret imp.LinkPath == path && imp.isAccessibleViaSelection() + }) + + selfIdent := str(TokenKind.Self) + if imp == nil || !imp.isLookupable(selfIdent) { + self.pushErr(decl.Idents[0], LogMsg.NamespaceNotExist, path) + ret nil + } + + self.disallowBuiltin() + mut lookup := self.lookup + self.lookup = imp + mut kind := self.checkDecl(decl.Kind) + self.lookup = lookup + self.allowBuiltin() + ret kind + } + + fn build(mut self, mut &declKind: TypeDeclKind): &TypeKind { + let mut kind: Kind = nil + match type declKind { + | &IdentTypeDecl: + mut t := self.buildIdent((&IdentTypeDecl)(declKind)) + if t != nil { + kind = t + } + | &SubIdentTypeDecl: + mut t := self.buildSubIdent((&SubIdentTypeDecl)(declKind)) + if t != nil { + kind = t + } + | &SptrTypeDecl: + self.inscatch = true + mut t := self.buildSptr((&SptrTypeDecl)(declKind)) + if t != nil { + kind = t + } + | &PtrTypeDecl: + self.inscatch = true + mut t := self.buildPtr((&PtrTypeDecl)(declKind)) + if t != nil { + kind = t + } + | &SlcTypeDecl: + self.inscatch = true + mut t := self.buildSlc((&SlcTypeDecl)(declKind)) + if t != nil { + kind = t + } + | &ArrTypeDecl: + self.inscatch = true + mut t := self.buildArr((&ArrTypeDecl)(declKind)) + if t != nil { + kind = t + } + | &MapTypeDecl: + self.inscatch = true + mut t := self.buildMap((&MapTypeDecl)(declKind)) + if t != nil { + kind = t + } + | &TupleTypeDecl: + self.inscatch = true + mut t := self.buildTuple((&TupleTypeDecl)(declKind)) + if t != nil { + kind = t + } + | &FnDecl: + self.inscatch = true + mut t := self.buildFunc((&FnDecl)(declKind)) + if t != nil { + kind = t + } + | &NamespaceTypeDecl: + self.inscatch = true + mut t := self.buildByNamespace((&NamespaceTypeDecl)(declKind)) + if t != nil { + kind = t + } + |: + self.pushErr(self.errorToken, LogMsg.InvalidType) + ret nil + } + if kind == nil { + ret nil + } + match type kind { + | &TypeKind: + ret (&TypeKind)(kind) + |: + mut tk := &TypeKind{Kind: kind} + match type kind { + | &Prim: + if self.ignoredGenerics != nil { + unsafe { *self.ignoredGenerics = append(*self.ignoredGenerics, tk) } + } + | &StructIns: + s := (&StructIns)(kind) + if s.Decl != nil && s.Decl.Binded { + tk.BindIdent = s.Decl.Ident + } + } + ret tk + } + } + + fn checkDecl(mut self, mut &decl: &TypeDecl): &TypeKind { + // Save current token. + mut errorToken := self.errorToken + + self.errorToken = decl.Token + mut kind := self.build(decl.Kind) + self.errorToken = errorToken + + ret kind + } + + fn check(mut self, mut &t: &TypeSymbol) { + if t.Decl == nil { + ret + } + mut kind := self.checkDecl(t.Decl) + if kind == nil { + t.removeKind() + ret + } + t.Kind = kind + } } struct identTypeLookup {} impl identTypeLookup { - static fn prim(&ident: str, t: &Prim): bool { - ret t.Kind == ident - } - - static fn exist(&ident: str, mut &k: &TypeKind): bool { - match { - | k.Prim() != nil: - ret identTypeLookup.prim(ident, k.Prim()) - | k.Sptr() != nil: - mut sptr := k.Sptr() - ret identTypeLookup.exist(ident, sptr.Elem) - | k.Ptr() != nil: - mut ptr := k.Ptr() - ret identTypeLookup.exist(ident, ptr.Elem) - | k.Slc() != nil: - mut slc := k.Slc() - ret identTypeLookup.exist(ident, slc.Elem) - | k.Arr() != nil: - mut arr := k.Arr() - ret identTypeLookup.exist(ident, arr.Elem) - | k.Map() != nil: - mut m := k.Map() - ret identTypeLookup.exist(ident, m.Key) || - identTypeLookup.exist(ident, m.Val) - | k.Struct() != nil: - mut s := k.Struct() - for (_, mut g) in s.Generics { - if identTypeLookup.exist(ident, g.Kind) { - ret true - } - } - ret false - | k.Fn() != nil: - mut f := k.Fn() - for (_, mut p) in f.Params { - if p.Decl.IsSelf() { - continue - } - if identTypeLookup.exist(ident, p.Kind) { - ret true - } - } - if f.Result != nil { - ret identTypeLookup.exist(ident, f.Result) - } - ret false - | k.Tup() != nil: - mut tup := k.Tup() - for (_, mut t) in tup.Types { - if identTypeLookup.exist(ident, t) { - ret true - } - } - ret false - |: - ret false - } - } + static fn prim(&ident: str, t: &Prim): bool { + ret t.Kind == ident + } + + static fn exist(&ident: str, mut &k: &TypeKind): bool { + match { + | k.Prim() != nil: + ret identTypeLookup.prim(ident, k.Prim()) + | k.Sptr() != nil: + mut sptr := k.Sptr() + ret identTypeLookup.exist(ident, sptr.Elem) + | k.Ptr() != nil: + mut ptr := k.Ptr() + ret identTypeLookup.exist(ident, ptr.Elem) + | k.Slc() != nil: + mut slc := k.Slc() + ret identTypeLookup.exist(ident, slc.Elem) + | k.Arr() != nil: + mut arr := k.Arr() + ret identTypeLookup.exist(ident, arr.Elem) + | k.Map() != nil: + mut m := k.Map() + ret identTypeLookup.exist(ident, m.Key) || + identTypeLookup.exist(ident, m.Val) + | k.Struct() != nil: + mut s := k.Struct() + for (_, mut g) in s.Generics { + if identTypeLookup.exist(ident, g.Kind) { + ret true + } + } + ret false + | k.Fn() != nil: + mut f := k.Fn() + for (_, mut p) in f.Params { + if p.Decl.IsSelf() { + continue + } + if identTypeLookup.exist(ident, p.Kind) { + ret true + } + } + if f.Result != nil { + ret identTypeLookup.exist(ident, f.Result) + } + ret false + | k.Tup() != nil: + mut tup := k.Tup() + for (_, mut t) in tup.Types { + if identTypeLookup.exist(ident, t) { + ret true + } + } + ret false + |: + ret false + } + } } fn kindUsesGenerics(mut &k: &TypeKind, &generics: []&GenericDecl): bool { - for _, g in generics { - if identTypeLookup.exist(g.Ident, k) { - ret true - } - } - ret false + for _, g in generics { + if identTypeLookup.exist(g.Ident, k) { + ret true + } + } + ret false } // Reports whether directive is exist. fn hasDirective(mut &directives: []&ast::Directive, tag: str): bool { - for (_, mut dr) in directives { - if dr.Tag.Kind == tag { - ret true - } - } - ret false + for (_, mut dr) in directives { + if dr.Tag.Kind == tag { + ret true + } + } + ret false } fn canGetPtr(mut &d: &Data): bool { - match { - | !d.Lvalue | d.IsConst(): - ret false - | d.Kind.Fn() != nil | d.Kind.Enum() != nil: - ret false - |: - ret true - } + match { + | !d.Lvalue | d.IsConst(): + ret false + | d.Kind.Fn() != nil | d.Kind.Enum() != nil: + ret false + |: + ret true + } } // Reports kind is valid for smart pointer type such as &T. fn isValidForSptrType(mut &t: &TypeKind): bool { - mut s := t.Struct() - if s != nil && s.Decl != nil && s.Decl.Binded { - ret false - } - ret true + mut s := t.Struct() + if s != nil && s.Decl != nil && s.Decl.Binded { + ret false + } + ret true } // Reports kind is valid for reference such as reference variables. @@ -1757,84 +1757,84 @@ fn isValidForRef(mut &t: &TypeKind): bool { ret t.Fn() == nil } // Reports whether type has built-in string conversion support. fn isBuiltinStrConvertable(mut &t: &TypeKind): bool { - ret !t.Void() && t.Fn() == nil && t.Tup() == nil && !t.comptime() + ret !t.Void() && t.Fn() == nil && t.Tup() == nil && !t.comptime() } fn buildLinkPathByTokens(&tokens: []&Token): str { - if len(tokens) == 1 && tokens[0].Id == TokenId.Unsafe { - ret "std::unsafe" - } - mut n := 0 - for _, token in tokens { - n += len(token.Kind) - n += 2 - } - mut s := StrBuilder.New(n) - for i, token in tokens { - s.WriteStr(token.Kind) - if len(tokens)-i > 1 { - s.WriteStr("::") - } - } - ret s.Str() + if len(tokens) == 1 && tokens[0].Id == TokenId.Unsafe { + ret "std::unsafe" + } + mut n := 0 + for _, token in tokens { + n += len(token.Kind) + n += 2 + } + mut s := StrBuilder.New(n) + for i, token in tokens { + s.WriteStr(token.Kind) + if len(tokens)-i > 1 { + s.WriteStr("::") + } + } + ret s.Str() } fn buildPrimType(kind: str): &Prim { - ret &Prim{ - Kind: kind, - } + ret &Prim{ + Kind: kind, + } } fn getStructFromKind(mut k: &TypeKind): &Struct { - match { - | k == nil: - ret nil - | k.Struct() != nil: - ret k.Struct().Decl - | k.Sptr() != nil: - ret getStructFromKind(k.Sptr().Elem) - | k.Slc() != nil: - ret getStructFromKind(k.Slc().Elem) - | k.Arr() != nil: - ret getStructFromKind(k.Arr().Elem) - | k.Ptr() != nil: - // Pass pointers. - // Cloning just copies pointer address. - // There is no any illegal cycle risk. - ret nil - |: - ret nil - } + match { + | k == nil: + ret nil + | k.Struct() != nil: + ret k.Struct().Decl + | k.Sptr() != nil: + ret getStructFromKind(k.Sptr().Elem) + | k.Slc() != nil: + ret getStructFromKind(k.Slc().Elem) + | k.Arr() != nil: + ret getStructFromKind(k.Arr().Elem) + | k.Ptr() != nil: + // Pass pointers. + // Cloning just copies pointer address. + // There is no any illegal cycle risk. + ret nil + |: + ret nil + } } fn applyImplicitCast(mut &dest: &TypeKind, mut &d: &Data, mut &token: &Token) { - if d.Kind.IsNil() { - ret - } - destPrim := dest.Prim() - if destPrim != nil && destPrim.IsAny() { - prim := d.Kind.Prim() - if prim == nil || !prim.IsAny() { - applyCastKind(d, dest, token) - } - ret - } - - dt := dest.Trait() - if dt != nil { - bt := d.Kind.Trait() - if bt == nil || bt != dt { - applyCastKindModel(d, dest, token) - ret - } - } - - if dest.TypeEnum() != nil && d.Kind.TypeEnum() == nil { - applyCastKindModel(d, dest, token) - ret - } + if d.Kind.IsNil() { + ret + } + destPrim := dest.Prim() + if destPrim != nil && destPrim.IsAny() { + prim := d.Kind.Prim() + if prim == nil || !prim.IsAny() { + applyCastKind(d, dest, token) + } + ret + } + + dt := dest.Trait() + if dt != nil { + bt := d.Kind.Trait() + if bt == nil || bt != dt { + applyCastKindModel(d, dest, token) + ret + } + } + + if dest.TypeEnum() != nil && d.Kind.TypeEnum() == nil { + applyCastKindModel(d, dest, token) + ret + } } fn validTypeForXof(mut &t: &TypeKind): bool { - ret !t.Void() && t.Fn() == nil + ret !t.Void() && t.Fn() == nil } \ No newline at end of file diff --git a/std/jule/sema/type2.jule b/std/jule/sema/type2.jule index 29d905a56..1eb83e773 100644 --- a/std/jule/sema/type2.jule +++ b/std/jule/sema/type2.jule @@ -7,17 +7,17 @@ use conv for std::conv use math for std::math use ast for std::jule::ast::{ - Expr, - KeyValPair, - FieldExprPair, - RangeKind, - VarDecl, - ExprData, - IdentExpr, - SliceExpr, - VariadicExpr, - TupleExpr, - FnCallExpr, + Expr, + KeyValPair, + FieldExprPair, + RangeKind, + VarDecl, + ExprData, + IdentExpr, + SliceExpr, + VariadicExpr, + TupleExpr, + FnCallExpr, } use std::jule::build::{LogMsg, Logf} use lit for std::jule::constant::lit @@ -26,891 +26,891 @@ use std::internal::strings::{StrBuilder} use types for std::jule::types fn traitHasReferenceReceiver(&t: &Trait): bool { - for _, f in t.Methods { - // Skip static functions. - if f.Statically { - continue - } - - p := f.Params[0] - if p.IsRef() && p.IsSelf() { - ret true - } - } - ret false + for _, f in t.Methods { + // Skip static functions. + if f.Statically { + continue + } + + p := f.Params[0] + if p.IsRef() && p.IsSelf() { + ret true + } + } + ret false } fn floatAssignable(&kind: str, &d: &Data): bool { - value := conv::FmtFloat(d.Constant.AsF64(), 'g', -1, 64) - ret types::CheckBitFloat(value, types::BitsizeOf(kind)) + value := conv::FmtFloat(d.Constant.AsF64(), 'g', -1, 64) + ret types::CheckBitFloat(value, types::BitsizeOf(kind)) } fn sigAssignable(kind: str, &d: &Data): bool { - min := types::Min(kind) - max := types::Max(kind) - match { - | d.Constant.IsF64(): - x := d.Constant.ReadF64() - i, frac := math::Modf(x) - if frac != 0 { - ret false - } - ret i >= min && i <= max - | d.Constant.IsU64(): - x := d.Constant.AsF64() - if x <= max { - ret true - } - | d.Constant.IsI64(): - x := d.Constant.AsF64() - ret min <= x && x <= max - } - ret false + min := types::Min(kind) + max := types::Max(kind) + match { + | d.Constant.IsF64(): + x := d.Constant.ReadF64() + i, frac := math::Modf(x) + if frac != 0 { + ret false + } + ret i >= min && i <= max + | d.Constant.IsU64(): + x := d.Constant.AsF64() + if x <= max { + ret true + } + | d.Constant.IsI64(): + x := d.Constant.AsF64() + ret min <= x && x <= max + } + ret false } fn unsigAssignable(kind: str, &d: &Data): bool { - max := types::Max(kind) - if d.IsRune && kind == types::TypeKind.U8 { - ret lit::IsAscii(rune(d.Constant.ReadI64())) - } - - match { - | d.Constant.IsF64(): - x := d.Constant.ReadF64() - if x < 0 { - ret false - } - i, frac := math::Modf(x) - if frac != 0 { - ret false - } - ret i <= max - | d.Constant.IsU64(): - x := d.Constant.AsF64() - if x <= max { - ret true - } - | d.Constant.IsI64(): - x := d.Constant.AsF64() - ret 0 <= x && x <= max - } - ret false + max := types::Max(kind) + if d.IsRune && kind == types::TypeKind.U8 { + ret lit::IsAscii(rune(d.Constant.ReadI64())) + } + + match { + | d.Constant.IsF64(): + x := d.Constant.ReadF64() + if x < 0 { + ret false + } + i, frac := math::Modf(x) + if frac != 0 { + ret false + } + ret i <= max + | d.Constant.IsU64(): + x := d.Constant.AsF64() + if x <= max { + ret true + } + | d.Constant.IsI64(): + x := d.Constant.AsF64() + ret 0 <= x && x <= max + } + ret false } fn intAssignable(kind: str, &d: &Data): bool { - match { - | types::IsSigInt(kind): - ret sigAssignable(kind, d) - | types::IsUnsigInt(kind): - ret unsigAssignable(kind, d) - |: - ret false - } + match { + | types::IsSigInt(kind): + ret sigAssignable(kind, d) + | types::IsUnsigInt(kind): + ret unsigAssignable(kind, d) + |: + ret false + } } struct typeCompatibilityChecker { - s: &Sema // Used for error logging. - dest: &TypeKind - src: &TypeKind - errorToken: &Token + s: &Sema // Used for error logging. + dest: &TypeKind + src: &TypeKind + errorToken: &Token } impl typeCompatibilityChecker { - fn pushErr(mut self, fmt: LogMsg, args: ...any) { - self.s.pushErr(self.errorToken, fmt, args...) - } - - fn checkTrait(mut self): (ok: bool) { - if self.src.IsNil() { - ret true - } - mut trt := self.dest.Trait() - mut ref := false - match { - | self.src.Sptr() != nil: - ref = true - self.src = self.src.Sptr().Elem - if self.src.Struct() == nil { - ret false - } - fall - | self.src.Struct() != nil: - s := self.src.Struct() - if !s.Decl.IsImplements(trt) { - ret false - } - if !ref && traitHasReferenceReceiver(trt) { - self.pushErr(LogMsg.TraitHasRefParamFn) - ret false - } - ret true - | self.src.Trait() != nil: - mut base := self.src.Trait() - if trt == base { - ret true - } - lookup: - for _, s1 in base.Implemented { - for _, s2 in trt.Implemented { - if s1 == s2 { - continue lookup - } - } - ret false - } - for (_, mut m1) in trt.Methods { - mut m2 := base.FindMethod(m1.Ident) - if m2 == nil { - ret false - } - m1k := self.s.getTraitCheckFnKind(m1) - m2k := self.s.getTraitCheckFnKind(m2) - if !m1k.equalTrait(m2k) { - ret false - } - } - ret true - |: - ret false - } - } - - fn checkPtr(mut self): (ok: bool) { - if self.src.IsNil() { - ret true - } - mut dest := self.dest.Ptr() - if dest.IsUnsafe() { - ret true - } - ret self.dest.Equal(self.src) - } - - fn checkPrim(mut self): (ok: bool) { - if !self.dest.Variadic { - prim := self.dest.Prim() - if prim != nil && prim.IsAny() { - ret true - } - } - ret self.dest.Equal(self.src) - } - - fn typeEnum(self, mut &e: &TypeEnum, mut &t2: &TypeKind): (ok: bool) { - for (_, mut item) in e.Items { - if item.Kind.Kind.Equal(t2) { - ret true - } - mut ke := item.Kind.Kind.TypeEnum() - if ke == nil { - continue - } - if self.typeEnum(ke, t2) { - ret true - } - } - ret false - } - - fn checkTypeEnum(mut self): (ok: bool) { - if self.dest.Equal(self.src) { - ret true - } - mut e := self.dest.TypeEnum() - ret self.typeEnum(e, self.src) - } - - fn check(mut self): (ok: bool) { - if self.dest.Ptr() != nil { - ret self.checkPtr() - } - if self.dest.NilCompatible() { - if self.src.IsNil() { - ret true - } - } - - match { - | self.dest.Prim() != nil: - ret self.checkPrim() - | self.dest.TypeEnum() != nil: - ret self.checkTypeEnum() - | self.dest.Trait() != nil: - ret self.checkTrait() - |: - ret self.dest.Equal(self.src) - } - } + fn pushErr(mut self, fmt: LogMsg, args: ...any) { + self.s.pushErr(self.errorToken, fmt, args...) + } + + fn checkTrait(mut self): (ok: bool) { + if self.src.IsNil() { + ret true + } + mut trt := self.dest.Trait() + mut ref := false + match { + | self.src.Sptr() != nil: + ref = true + self.src = self.src.Sptr().Elem + if self.src.Struct() == nil { + ret false + } + fall + | self.src.Struct() != nil: + s := self.src.Struct() + if !s.Decl.IsImplements(trt) { + ret false + } + if !ref && traitHasReferenceReceiver(trt) { + self.pushErr(LogMsg.TraitHasRefParamFn) + ret false + } + ret true + | self.src.Trait() != nil: + mut base := self.src.Trait() + if trt == base { + ret true + } + lookup: + for _, s1 in base.Implemented { + for _, s2 in trt.Implemented { + if s1 == s2 { + continue lookup + } + } + ret false + } + for (_, mut m1) in trt.Methods { + mut m2 := base.FindMethod(m1.Ident) + if m2 == nil { + ret false + } + m1k := self.s.getTraitCheckFnKind(m1) + m2k := self.s.getTraitCheckFnKind(m2) + if !m1k.equalTrait(m2k) { + ret false + } + } + ret true + |: + ret false + } + } + + fn checkPtr(mut self): (ok: bool) { + if self.src.IsNil() { + ret true + } + mut dest := self.dest.Ptr() + if dest.IsUnsafe() { + ret true + } + ret self.dest.Equal(self.src) + } + + fn checkPrim(mut self): (ok: bool) { + if !self.dest.Variadic { + prim := self.dest.Prim() + if prim != nil && prim.IsAny() { + ret true + } + } + ret self.dest.Equal(self.src) + } + + fn typeEnum(self, mut &e: &TypeEnum, mut &t2: &TypeKind): (ok: bool) { + for (_, mut item) in e.Items { + if item.Kind.Kind.Equal(t2) { + ret true + } + mut ke := item.Kind.Kind.TypeEnum() + if ke == nil { + continue + } + if self.typeEnum(ke, t2) { + ret true + } + } + ret false + } + + fn checkTypeEnum(mut self): (ok: bool) { + if self.dest.Equal(self.src) { + ret true + } + mut e := self.dest.TypeEnum() + ret self.typeEnum(e, self.src) + } + + fn check(mut self): (ok: bool) { + if self.dest.Ptr() != nil { + ret self.checkPtr() + } + if self.dest.NilCompatible() { + if self.src.IsNil() { + ret true + } + } + + match { + | self.dest.Prim() != nil: + ret self.checkPrim() + | self.dest.TypeEnum() != nil: + ret self.checkTypeEnum() + | self.dest.Trait() != nil: + ret self.checkTrait() + |: + ret self.dest.Equal(self.src) + } + } } // Checks value and type compatibility for assignment. struct assignTypeChecker { - s: &Sema // Used for error logging and type checking. - dest: &TypeKind - d: &Data - errorToken: &Token + s: &Sema // Used for error logging and type checking. + dest: &TypeKind + d: &Data + errorToken: &Token } impl assignTypeChecker { - fn pushErr(mut self, fmt: LogMsg, args: ...any) { - self.s.pushErr(self.errorToken, fmt, args...) - } - - fn checkValidity(mut self): bool { - mut valid := true - match { - | self.d.Kind.Fn() != nil: - f := self.d.Kind.Fn() - match { - | f.IsBuiltin(): - self.pushErr(LogMsg.BuiltinAsNonFn) - valid = false - | f.Decl.Binded: - self.pushErr(LogMsg.BindedFnAsAnonFn) - valid = false - | !f.Decl.Statically && f.Decl.IsMethod(): - self.pushErr(LogMsg.MethodAsAnonFn) - valid = false - | len(f.Decl.Generics) > 0 && len(f.Generics) == 0: - self.pushErr(LogMsg.GenericedFnAsAnonFn) - self.s.pushSuggestion(LogMsg.InstantiateGenericFnToUseAsAnon) - valid = false - } - | self.d.Kind.Tup() != nil: - self.pushErr(LogMsg.TupleAssignToSingle) - valid = false - } - ret valid - } - - fn checkConst(mut self): bool { - // Since untyped literals only can be primitive numeric types and constants, - // do not check this cases, just check whether self.d is untyped literal. - if !self.d.untyped || self.dest.Prim() == nil { - ret false - } - kind := self.dest.Prim().Kind - match { - | types::IsFloat(kind): - if !floatAssignable(kind, self.d) { - ret false - } - self.d.Constant.Kind = kind - | types::IsInt(kind): - if !intAssignable(kind, self.d) { - ret false - } - self.d.Constant.Kind = kind - |: - ret false - } - ret true - } - - fn checkCompatibility(mut self): bool { - match { - | self.d == nil: - // Skip Data is nil. - ret false - | !self.checkValidity(): - // Data is invalid and error(s) logged about it. - ret false - | self.checkConst(): - ret true - | self.d.Kind.Enum() != nil: - mut dkind := self.dest - if self.dest.Enum() != nil { - dkind = self.dest.Enum().Kind.Kind - } - prim := self.dest.Prim() - if prim == nil || prim.IsAny() { - // Ignore direct comparison if prim is nil or any. - break - } - mut dest := self.d.Kind.Enum().Kind.Kind - ret self.s.checkTypeCompatibility(dest, dkind, self.errorToken) - } - ret self.s.checkTypeCompatibility1(self.dest, self.d, self.errorToken) - } - - fn check(mut self): bool { - ok := self.checkCompatibility() - if ok && !self.d.Kind.Variadic { - applyImplicitCast(self.dest, self.d, self.errorToken) - } - ret ok - } + fn pushErr(mut self, fmt: LogMsg, args: ...any) { + self.s.pushErr(self.errorToken, fmt, args...) + } + + fn checkValidity(mut self): bool { + mut valid := true + match { + | self.d.Kind.Fn() != nil: + f := self.d.Kind.Fn() + match { + | f.IsBuiltin(): + self.pushErr(LogMsg.BuiltinAsNonFn) + valid = false + | f.Decl.Binded: + self.pushErr(LogMsg.BindedFnAsAnonFn) + valid = false + | !f.Decl.Statically && f.Decl.IsMethod(): + self.pushErr(LogMsg.MethodAsAnonFn) + valid = false + | len(f.Decl.Generics) > 0 && len(f.Generics) == 0: + self.pushErr(LogMsg.GenericedFnAsAnonFn) + self.s.pushSuggestion(LogMsg.InstantiateGenericFnToUseAsAnon) + valid = false + } + | self.d.Kind.Tup() != nil: + self.pushErr(LogMsg.TupleAssignToSingle) + valid = false + } + ret valid + } + + fn checkConst(mut self): bool { + // Since untyped literals only can be primitive numeric types and constants, + // do not check this cases, just check whether self.d is untyped literal. + if !self.d.untyped || self.dest.Prim() == nil { + ret false + } + kind := self.dest.Prim().Kind + match { + | types::IsFloat(kind): + if !floatAssignable(kind, self.d) { + ret false + } + self.d.Constant.Kind = kind + | types::IsInt(kind): + if !intAssignable(kind, self.d) { + ret false + } + self.d.Constant.Kind = kind + |: + ret false + } + ret true + } + + fn checkCompatibility(mut self): bool { + match { + | self.d == nil: + // Skip Data is nil. + ret false + | !self.checkValidity(): + // Data is invalid and error(s) logged about it. + ret false + | self.checkConst(): + ret true + | self.d.Kind.Enum() != nil: + mut dkind := self.dest + if self.dest.Enum() != nil { + dkind = self.dest.Enum().Kind.Kind + } + prim := self.dest.Prim() + if prim == nil || prim.IsAny() { + // Ignore direct comparison if prim is nil or any. + break + } + mut dest := self.d.Kind.Enum().Kind.Kind + ret self.s.checkTypeCompatibility(dest, dkind, self.errorToken) + } + ret self.s.checkTypeCompatibility1(self.dest, self.d, self.errorToken) + } + + fn check(mut self): bool { + ok := self.checkCompatibility() + if ok && !self.d.Kind.Variadic { + applyImplicitCast(self.dest, self.d, self.errorToken) + } + ret ok + } } struct dynamicTypeAnnotation { - e: &Eval - f: &FnIns - p: &ParamIns - a: &Data - errorToken: &Token - k: *&TypeKind - c: &ast::TypeDecl - ignored: []&TypeKind // Ignored generics. + e: &Eval + f: &FnIns + p: &ParamIns + a: &Data + errorToken: &Token + k: *&TypeKind + c: &ast::TypeDecl + ignored: []&TypeKind // Ignored generics. } impl dynamicTypeAnnotation { - fn annotateConstraintElem[T](mut self, mut &k: &TypeKind): bool { - match type self.c.Kind { - | &T: - let mut elem: &TypeKind = nil - const match type T { - | ast::ArrTypeDecl: - elem = k.Arr().Elem - | ast::SlcTypeDecl: - elem = k.Slc().Elem - | ast::PtrTypeDecl: - elem = k.Ptr().Elem - | ast::SptrTypeDecl: - elem = k.Sptr().Elem - } - self.c = (&T)(self.c.Kind).Elem - ret self.annotateConstraint(elem) - } - ret false - } - - fn annotateConstraintMap(mut self, mut &k: &TypeKind): (ok: bool) { - match type self.c.Kind { - | &ast::MapTypeDecl: - mut m := k.Map() - mut m2 := (&ast::MapTypeDecl)(self.c.Kind) - self.c = m2.Key - if !self.annotateConstraint(m.Key) { - ret false - } - self.c = m2.Val - ret self.annotateConstraint(m.Val) - } - ret false - } - - fn annotateConstraintTup(mut self, mut &k: &TypeKind): (ok: bool) { - match type self.c.Kind { - | &ast::TupleTypeDecl: - mut tup := (&ast::TupleTypeDecl)(self.c.Kind) - mut tup2 := k.Tup() - for (_, mut t2) in tup2.Types { - for (_, mut t) in tup.Types { - self.c = t - if self.annotateConstraint(t2) { - ret true - } - } - } - } - ret false - } - - fn annotateConstraintFn(mut self, mut &k: &TypeKind): (ok: bool) { - match type self.c.Kind { - | &ast::FnDecl: - mut pf := (&ast::FnDecl)(self.c.Kind) - mut f := k.Fn() - for (i, mut fp) in f.Params { - self.c = pf.Params[i].Kind - if self.annotateConstraint(fp.Kind) { - ret true - } - } - if pf.Result != nil { - self.c = pf.Result.Kind - if self.annotateConstraint(f.Result) { - ret true - } - } - } - ret false - } - - fn annotateConstraintIdent(mut self, mut &k: &TypeKind): bool { - mut ident := (&ast::IdentTypeDecl)(self.c.Kind) - mut s := k.Struct() - for i, g in self.f.Decl.Generics { - if g.Ident == ident.Ident { - mut fg := self.f.Generics[i] - if fg != nil { - ret false - } - self.pushGeneric(k, i) - ret true - } - if s == nil { - continue - } - mut c := self.c - for (_, mut ig) in ident.Generics { - self.c = ig - for (_, mut sg) in s.Generics { - if self.annotateConstraint(sg.Kind) { - ret true - } - } - } - self.c = c - } - ret false - } - - fn annotateConstraint(mut self, mut &k: &TypeKind): bool { - match type self.c.Kind { - | &ast::IdentTypeDecl: - ret self.annotateConstraintIdent(k) - } - match { - | k.Arr() != nil: - ret self.annotateConstraintElem[ast::ArrTypeDecl](k) - | k.Slc() != nil: - ret self.annotateConstraintElem[ast::SlcTypeDecl](k) - | k.Ptr() != nil: - ret self.annotateConstraintElem[ast::PtrTypeDecl](k) - | k.Sptr() != nil: - ret self.annotateConstraintElem[ast::SptrTypeDecl](k) - | k.Map() != nil: - ret self.annotateConstraintMap(k) - | k.Fn() != nil: - ret self.annotateConstraintFn(k) - | k.Tup() != nil: - ret self.annotateConstraintTup(k) - |: - ret false - } - } - - fn pushGeneric(mut self, mut &k: &TypeKind, i: int) { - self.f.Generics[i] = &InsGeneric{Kind: k} - mut gd := self.f.Decl.Generics[i] - for (_, mut ignored) in self.ignored { - if gd.Ident == ignored.Str() { - ignored.Kind = k.Kind - } - } - if gd.Constraint == nil || len(gd.Constraint.Mask) != 1 { - ret - } - self.c = gd.Constraint.Mask[0] - self.annotateConstraint(k) - } - - unsafe fn annotatePrim(mut self, mut &k: &TypeKind): (ok: bool) { - ret self.annotateAny(k) - } - - unsafe fn annotateArr(mut self, mut &k: &TypeKind): (ok: bool) { - mut parr := (*self.k).Arr() - if parr == nil { - ret false - } - mut arr := k.Arr() - self.k = &parr.Elem - ret self.annotateKind(arr.Elem) - } - - unsafe fn annotateSlc(mut self, mut &k: &TypeKind): (ok: bool) { - mut pslc := (*self.k).Slc() - if pslc == nil { - ret false - } - mut slc := k.Slc() - self.k = &pslc.Elem - ret self.annotateKind(slc.Elem) - } - - unsafe fn checkMapKey(mut self, mut k: *&TypeKind, mut &ck: &TypeKind): (ok: bool) { - mut old := self.k - self.k = k - ok = self.annotateKind(ck) - self.k = old - ret ok - } - - unsafe fn annotateMap(mut self, mut &k: &TypeKind): (ok: bool) { - mut pmap := (*self.k).Map() - if pmap == nil { - ret false - } - mut m := k.Map() - ret self.checkMapKey(&pmap.Key, m.Key) && - self.checkMapKey(&pmap.Val, m.Val) - } - - unsafe fn annotateFn(mut self, mut &k: &TypeKind): (ok: bool) { - mut pf := (*self.k).Fn() - if pf == nil { - ret false - } - mut f := k.Fn() - match { - | len(pf.Params) != len(f.Params): - ret false - | pf.Decl.IsVoid() != f.Decl.IsVoid(): - ret false - } - - ok = true - mut old := self.k - for (i, mut fp) in f.Params { - self.k = &pf.Params[i].Kind - ok = self.annotateKind(fp.Kind) && ok - } - - if !pf.Decl.IsVoid() { - self.k = &pf.Result - ok = self.annotateKind(f.Result) && ok - } - - self.k = old - ret ok - } - - unsafe fn annotatePtr(mut self, mut &k: &TypeKind): (ok: bool) { - mut pptr := (*self.k).Ptr() - if pptr == nil { - ret false - } - mut ptr := k.Ptr() - self.k = &pptr.Elem - ret self.annotateKind(ptr.Elem) - } - - unsafe fn annotateSptr(mut self, mut &k: &TypeKind): (ok: bool) { - mut ssptr := (*self.k).Sptr() - if ssptr == nil { - ret false - } - mut sptr := k.Sptr() - self.k = &ssptr.Elem - ret self.annotateKind(sptr.Elem) - } - - unsafe fn annotateStruct(mut self, mut &k: &TypeKind): (ok: bool) { - mut s := (*self.k).Struct() - if s == nil { - ret false - } - mut s2 := k.Struct() - if len(s.Generics) != len(s2.Generics) { - ret false - } - for (i, mut g) in s.Generics { - mut g2 := s2.Generics[i] - if g.Kind.Equal(g2.Kind) { - continue - } - self.k = &g.Kind - if !self.annotateKind(g2.Kind) { - ret false - } - } - ret true - } - - unsafe fn annotateAny(mut self, mut &k: &TypeKind): (ok: bool) { - kind := (*self.k).Str() - for i, g in self.f.Decl.Generics { - if kind != g.Ident { - continue - } - t := self.f.Generics[i] - match { - | t == nil | t.Kind == nil: - self.pushGeneric(k, i) - | !t.Kind.Equal(k): - // Generic already pushed but generic type and current kind - // is different, so incompatible. - ret false - } - (*self.k).Kind = k.Kind - ret true - } - ret false - } - - unsafe fn annotateKind(mut self, mut &k: &TypeKind): (ok: bool) { - if self.k == nil || *self.k == nil { - ret - } - match { - | self.annotateAny(k): - ret true - | k.Prim() != nil: - ret self.annotatePrim(k) - | k.Arr() != nil: - ret self.annotateArr(k) - | k.Slc() != nil: - ret self.annotateSlc(k) - | k.Map() != nil: - ret self.annotateMap(k) - | k.Fn() != nil: - ret self.annotateFn(k) - | k.Ptr() != nil: - ret self.annotatePtr(k) - | k.Sptr() != nil: - ret self.annotateSptr(k) - | k.Struct() != nil: - ret self.annotateStruct(k) - |: - ret false - } - } - - unsafe fn annotate(mut self): (ok: bool) { - self.k = &self.p.Kind - ret self.annotateKind(self.a.Kind) - } + fn annotateConstraintElem[T](mut self, mut &k: &TypeKind): bool { + match type self.c.Kind { + | &T: + let mut elem: &TypeKind = nil + const match type T { + | ast::ArrTypeDecl: + elem = k.Arr().Elem + | ast::SlcTypeDecl: + elem = k.Slc().Elem + | ast::PtrTypeDecl: + elem = k.Ptr().Elem + | ast::SptrTypeDecl: + elem = k.Sptr().Elem + } + self.c = (&T)(self.c.Kind).Elem + ret self.annotateConstraint(elem) + } + ret false + } + + fn annotateConstraintMap(mut self, mut &k: &TypeKind): (ok: bool) { + match type self.c.Kind { + | &ast::MapTypeDecl: + mut m := k.Map() + mut m2 := (&ast::MapTypeDecl)(self.c.Kind) + self.c = m2.Key + if !self.annotateConstraint(m.Key) { + ret false + } + self.c = m2.Val + ret self.annotateConstraint(m.Val) + } + ret false + } + + fn annotateConstraintTup(mut self, mut &k: &TypeKind): (ok: bool) { + match type self.c.Kind { + | &ast::TupleTypeDecl: + mut tup := (&ast::TupleTypeDecl)(self.c.Kind) + mut tup2 := k.Tup() + for (_, mut t2) in tup2.Types { + for (_, mut t) in tup.Types { + self.c = t + if self.annotateConstraint(t2) { + ret true + } + } + } + } + ret false + } + + fn annotateConstraintFn(mut self, mut &k: &TypeKind): (ok: bool) { + match type self.c.Kind { + | &ast::FnDecl: + mut pf := (&ast::FnDecl)(self.c.Kind) + mut f := k.Fn() + for (i, mut fp) in f.Params { + self.c = pf.Params[i].Kind + if self.annotateConstraint(fp.Kind) { + ret true + } + } + if pf.Result != nil { + self.c = pf.Result.Kind + if self.annotateConstraint(f.Result) { + ret true + } + } + } + ret false + } + + fn annotateConstraintIdent(mut self, mut &k: &TypeKind): bool { + mut ident := (&ast::IdentTypeDecl)(self.c.Kind) + mut s := k.Struct() + for i, g in self.f.Decl.Generics { + if g.Ident == ident.Ident { + mut fg := self.f.Generics[i] + if fg != nil { + ret false + } + self.pushGeneric(k, i) + ret true + } + if s == nil { + continue + } + mut c := self.c + for (_, mut ig) in ident.Generics { + self.c = ig + for (_, mut sg) in s.Generics { + if self.annotateConstraint(sg.Kind) { + ret true + } + } + } + self.c = c + } + ret false + } + + fn annotateConstraint(mut self, mut &k: &TypeKind): bool { + match type self.c.Kind { + | &ast::IdentTypeDecl: + ret self.annotateConstraintIdent(k) + } + match { + | k.Arr() != nil: + ret self.annotateConstraintElem[ast::ArrTypeDecl](k) + | k.Slc() != nil: + ret self.annotateConstraintElem[ast::SlcTypeDecl](k) + | k.Ptr() != nil: + ret self.annotateConstraintElem[ast::PtrTypeDecl](k) + | k.Sptr() != nil: + ret self.annotateConstraintElem[ast::SptrTypeDecl](k) + | k.Map() != nil: + ret self.annotateConstraintMap(k) + | k.Fn() != nil: + ret self.annotateConstraintFn(k) + | k.Tup() != nil: + ret self.annotateConstraintTup(k) + |: + ret false + } + } + + fn pushGeneric(mut self, mut &k: &TypeKind, i: int) { + self.f.Generics[i] = &InsGeneric{Kind: k} + mut gd := self.f.Decl.Generics[i] + for (_, mut ignored) in self.ignored { + if gd.Ident == ignored.Str() { + ignored.Kind = k.Kind + } + } + if gd.Constraint == nil || len(gd.Constraint.Mask) != 1 { + ret + } + self.c = gd.Constraint.Mask[0] + self.annotateConstraint(k) + } + + unsafe fn annotatePrim(mut self, mut &k: &TypeKind): (ok: bool) { + ret self.annotateAny(k) + } + + unsafe fn annotateArr(mut self, mut &k: &TypeKind): (ok: bool) { + mut parr := (*self.k).Arr() + if parr == nil { + ret false + } + mut arr := k.Arr() + self.k = &parr.Elem + ret self.annotateKind(arr.Elem) + } + + unsafe fn annotateSlc(mut self, mut &k: &TypeKind): (ok: bool) { + mut pslc := (*self.k).Slc() + if pslc == nil { + ret false + } + mut slc := k.Slc() + self.k = &pslc.Elem + ret self.annotateKind(slc.Elem) + } + + unsafe fn checkMapKey(mut self, mut k: *&TypeKind, mut &ck: &TypeKind): (ok: bool) { + mut old := self.k + self.k = k + ok = self.annotateKind(ck) + self.k = old + ret ok + } + + unsafe fn annotateMap(mut self, mut &k: &TypeKind): (ok: bool) { + mut pmap := (*self.k).Map() + if pmap == nil { + ret false + } + mut m := k.Map() + ret self.checkMapKey(&pmap.Key, m.Key) && + self.checkMapKey(&pmap.Val, m.Val) + } + + unsafe fn annotateFn(mut self, mut &k: &TypeKind): (ok: bool) { + mut pf := (*self.k).Fn() + if pf == nil { + ret false + } + mut f := k.Fn() + match { + | len(pf.Params) != len(f.Params): + ret false + | pf.Decl.IsVoid() != f.Decl.IsVoid(): + ret false + } + + ok = true + mut old := self.k + for (i, mut fp) in f.Params { + self.k = &pf.Params[i].Kind + ok = self.annotateKind(fp.Kind) && ok + } + + if !pf.Decl.IsVoid() { + self.k = &pf.Result + ok = self.annotateKind(f.Result) && ok + } + + self.k = old + ret ok + } + + unsafe fn annotatePtr(mut self, mut &k: &TypeKind): (ok: bool) { + mut pptr := (*self.k).Ptr() + if pptr == nil { + ret false + } + mut ptr := k.Ptr() + self.k = &pptr.Elem + ret self.annotateKind(ptr.Elem) + } + + unsafe fn annotateSptr(mut self, mut &k: &TypeKind): (ok: bool) { + mut ssptr := (*self.k).Sptr() + if ssptr == nil { + ret false + } + mut sptr := k.Sptr() + self.k = &ssptr.Elem + ret self.annotateKind(sptr.Elem) + } + + unsafe fn annotateStruct(mut self, mut &k: &TypeKind): (ok: bool) { + mut s := (*self.k).Struct() + if s == nil { + ret false + } + mut s2 := k.Struct() + if len(s.Generics) != len(s2.Generics) { + ret false + } + for (i, mut g) in s.Generics { + mut g2 := s2.Generics[i] + if g.Kind.Equal(g2.Kind) { + continue + } + self.k = &g.Kind + if !self.annotateKind(g2.Kind) { + ret false + } + } + ret true + } + + unsafe fn annotateAny(mut self, mut &k: &TypeKind): (ok: bool) { + kind := (*self.k).Str() + for i, g in self.f.Decl.Generics { + if kind != g.Ident { + continue + } + t := self.f.Generics[i] + match { + | t == nil | t.Kind == nil: + self.pushGeneric(k, i) + | !t.Kind.Equal(k): + // Generic already pushed but generic type and current kind + // is different, so incompatible. + ret false + } + (*self.k).Kind = k.Kind + ret true + } + ret false + } + + unsafe fn annotateKind(mut self, mut &k: &TypeKind): (ok: bool) { + if self.k == nil || *self.k == nil { + ret + } + match { + | self.annotateAny(k): + ret true + | k.Prim() != nil: + ret self.annotatePrim(k) + | k.Arr() != nil: + ret self.annotateArr(k) + | k.Slc() != nil: + ret self.annotateSlc(k) + | k.Map() != nil: + ret self.annotateMap(k) + | k.Fn() != nil: + ret self.annotateFn(k) + | k.Ptr() != nil: + ret self.annotatePtr(k) + | k.Sptr() != nil: + ret self.annotateSptr(k) + | k.Struct() != nil: + ret self.annotateStruct(k) + |: + ret false + } + } + + unsafe fn annotate(mut self): (ok: bool) { + self.k = &self.p.Kind + ret self.annotateKind(self.a.Kind) + } } struct fnCallArgChecker { - e: &Eval - args: []&Expr - errorToken: &Token - f: &FnIns - dynamicAnnotation: bool - argModels: []ExprModel - ignored: []&TypeKind // Ignored generics. + e: &Eval + args: []&Expr + errorToken: &Token + f: &FnIns + dynamicAnnotation: bool + argModels: []ExprModel + ignored: []&TypeKind // Ignored generics. } impl fnCallArgChecker { - fn pushErrToken(mut self, token: &Token, fmt: LogMsg, args: ...any) { - self.e.s.pushErr(token, fmt, args...) - } - - fn pushErr(mut self, fmt: LogMsg, args: ...any) { - self.pushErrToken(self.errorToken, fmt, args...) - } - - fn getParams(mut self): []&ParamIns { - if len(self.f.Params) > 0 && - self.f.Params[0].Decl != nil && - self.f.Params[0].Decl.IsSelf() { - ret self.f.Params[1:] // Remove receiver parameter. - } - ret self.f.Params - } - - fn checkCounts(mut self, ¶ms: []&ParamIns): (ok: bool) { - mut n := len(params) - if n > 0 && params[0].Decl.IsSelf() { - n-- - } - - mut diff := n - len(self.args) - mut log := LogMsg.Empty - match { - | diff == 0: - ret true - | n > 0 && params[n-1].Decl.Variadic: - ret true - | diff < 0 || diff > len(params): - log = LogMsg.ArgumentOverflow - |: - log = LogMsg.MissingArgs - } - mut err := StrBuilder.New(1 << 5) - err.WriteStr(self.f.Decl.Ident) - err.WriteStr("\n want (") - for i, p in params { - err.WriteStr(p.Kind.Str()) - if len(params)-i > 1 { - err.WriteStr(", ") - } - } - err.WriteByte(')') - self.pushErr(log, err.Str()) - ret false - } - - fn checkArg(mut self, mut &p: &ParamIns, mut &arg: &Data, mut &errorToken: &Token): (ok: bool) { - if self.dynamicAnnotation && parameterUsesGenerics(p, self.f.Decl.Generics) { - // Accept as fail if parameter is variadic or expression is invalid. - ok = !p.Decl.Variadic && isGoodValueToInfer(arg) - if ok { - mut dta := dynamicTypeAnnotation{ - e: self.e, - f: self.f, - p: p, - a: arg, - errorToken: errorToken, - ignored: self.ignored, - } - ok = unsafe { dta.annotate() } - } - if !ok { - self.pushErrToken(errorToken, LogMsg.DynamicTypeAnnotationFailed) - ret false - } - } - - if self.e.s.checkValidityForInitExpr(p.Decl.Mutable, p.Decl.Reference, p.Kind, arg, errorToken) { - // Check type if validity is good. - // Helps to reduce error logs and duplicated logs. - ret self.e.s.checkAssignType(p.Decl.Reference, p.Kind, arg, errorToken) - } - ret false - } - - fn push(mut self, mut &p: &ParamIns, mut arg: &Expr): (ok: bool) { - mut old := self.e.prefix - oldImmut := self.e.immutable - - self.e.immutable = !p.Decl.Mutable - if !self.dynamicAnnotation && !p.Decl.Variadic { - self.e.prefix = p.Kind - } else { - self.e.prefix = nil - } - mut d := self.e.evalExpr(arg) - - self.e.prefix = old - self.e.immutable = oldImmut - - if d == nil { - ret false - } - - ok = self.checkArg(p, d, arg.Token) - self.argModels = append(self.argModels, d.Model) - ret - } - - fn pushVariadic(mut self, mut &p: &ParamIns, mut i: int): (ok: bool) { - ok = true - mut variadiced := false - more := i+1 < len(self.args) - mut model := &SliceExprModel{ - ElemKind: p.Kind, - } - - mut old := self.e.prefix - - // Save variadic status into separate variable. - // Because parameter might be variadic, but type might be not variadic. - // Some built-in functions passes non-variadic types. - // Also allocate new type based on [p.Kind] because type should be remain non-variadic. - // The [p.Kind] used as prefix and base type. - mut oldKind := p.Kind - p.Kind = new(TypeKind, *p.Kind) - p.Kind.Variadic = false - defer { - p.Kind.Variadic = false // Set actual type as non-variadic. - p.Kind = oldKind - } - - for i < len(self.args); i++ { - mut arg := self.args[i] - - match type arg.Kind { - | &VariadicExpr: - self.e.prefix = &TypeKind{ - Kind: &Slc{ - Elem: p.Kind, - }, - } - |: - self.e.prefix = p.Kind - } - - mut d := self.e.eval(arg) - if d == nil { - ok = false - continue - } - - if d.Kind.Variadic { - variadiced = true - p.Kind.Variadic = true - ok = ok && self.checkArg(p, d, arg.Token) - p.Kind.Variadic = false - match type d.Model { - | &SliceExprModel: - model = (&SliceExprModel)(d.Model) - model.ElemKind = p.Kind - |: - model = nil - self.argModels = append(self.argModels, d.Model) - } - // Break iteration early, this argument is variadic, so should be last. - // If this argument is not last, following algorithm will create error log for that. - // Increase variable i for point to following argument. - i++ - break - } - - ok = ok && self.checkArg(p, d, arg.Token) - model.Elems = append(model.Elems, d.Model) - } - self.e.prefix = old - - if variadiced && more { - // Use variable i because when variadic argument appears iteral will break. - // And it will increase variable i for point to following argument. - // Therefore, variable i always points to problematic argument. - self.pushErrToken(self.args[i].Token, LogMsg.MoreArgsWithVariadiced) - } - - if model != nil { - self.argModels = append(self.argModels, model) - } - ret ok - } - - fn checkArgs(mut self, mut ¶ms: []&ParamIns): (ok: bool) { - arg := self.e.arg - self.e.arg = true - - ok = true - mut i := 0 - if len(params) > 0 && params[0].Decl.IsSelf() { - // Ignore self. - i++ - } - iter: - for i < len(params) { - mut p := params[i] - match { - | p.Decl.Variadic: - ok = self.pushVariadic(p, i) && ok - // Variadiced parameters always last. - break iter - | len(self.args) <= i: - ok = false - break iter - |: - ok = self.push(p, self.args[i]) && ok - } - i++ - } - - self.e.arg = arg - ret ok - } - - fn checkDynamicTypeAnnotation(mut self): (ok: bool) { - for _, g in self.f.Generics { - if g == nil { - self.pushErr(LogMsg.DynamicTypeAnnotationFailed) - ret false - } - } - ret true - } - - fn check(mut self): (ok: bool) { - mut params := self.getParams() - ok = self.checkCounts(params) - if !ok { - ret false - } - ok = self.checkArgs(params) - if ok && self.dynamicAnnotation { - ok = self.checkDynamicTypeAnnotation() - } - ret ok - } + fn pushErrToken(mut self, token: &Token, fmt: LogMsg, args: ...any) { + self.e.s.pushErr(token, fmt, args...) + } + + fn pushErr(mut self, fmt: LogMsg, args: ...any) { + self.pushErrToken(self.errorToken, fmt, args...) + } + + fn getParams(mut self): []&ParamIns { + if len(self.f.Params) > 0 && + self.f.Params[0].Decl != nil && + self.f.Params[0].Decl.IsSelf() { + ret self.f.Params[1:] // Remove receiver parameter. + } + ret self.f.Params + } + + fn checkCounts(mut self, ¶ms: []&ParamIns): (ok: bool) { + mut n := len(params) + if n > 0 && params[0].Decl.IsSelf() { + n-- + } + + mut diff := n - len(self.args) + mut log := LogMsg.Empty + match { + | diff == 0: + ret true + | n > 0 && params[n-1].Decl.Variadic: + ret true + | diff < 0 || diff > len(params): + log = LogMsg.ArgumentOverflow + |: + log = LogMsg.MissingArgs + } + mut err := StrBuilder.New(1 << 5) + err.WriteStr(self.f.Decl.Ident) + err.WriteStr("\n want (") + for i, p in params { + err.WriteStr(p.Kind.Str()) + if len(params)-i > 1 { + err.WriteStr(", ") + } + } + err.WriteByte(')') + self.pushErr(log, err.Str()) + ret false + } + + fn checkArg(mut self, mut &p: &ParamIns, mut &arg: &Data, mut &errorToken: &Token): (ok: bool) { + if self.dynamicAnnotation && parameterUsesGenerics(p, self.f.Decl.Generics) { + // Accept as fail if parameter is variadic or expression is invalid. + ok = !p.Decl.Variadic && isGoodValueToInfer(arg) + if ok { + mut dta := dynamicTypeAnnotation{ + e: self.e, + f: self.f, + p: p, + a: arg, + errorToken: errorToken, + ignored: self.ignored, + } + ok = unsafe { dta.annotate() } + } + if !ok { + self.pushErrToken(errorToken, LogMsg.DynamicTypeAnnotationFailed) + ret false + } + } + + if self.e.s.checkValidityForInitExpr(p.Decl.Mutable, p.Decl.Reference, p.Kind, arg, errorToken) { + // Check type if validity is good. + // Helps to reduce error logs and duplicated logs. + ret self.e.s.checkAssignType(p.Decl.Reference, p.Kind, arg, errorToken) + } + ret false + } + + fn push(mut self, mut &p: &ParamIns, mut arg: &Expr): (ok: bool) { + mut old := self.e.prefix + oldImmut := self.e.immutable + + self.e.immutable = !p.Decl.Mutable + if !self.dynamicAnnotation && !p.Decl.Variadic { + self.e.prefix = p.Kind + } else { + self.e.prefix = nil + } + mut d := self.e.evalExpr(arg) + + self.e.prefix = old + self.e.immutable = oldImmut + + if d == nil { + ret false + } + + ok = self.checkArg(p, d, arg.Token) + self.argModels = append(self.argModels, d.Model) + ret + } + + fn pushVariadic(mut self, mut &p: &ParamIns, mut i: int): (ok: bool) { + ok = true + mut variadiced := false + more := i+1 < len(self.args) + mut model := &SliceExprModel{ + ElemKind: p.Kind, + } + + mut old := self.e.prefix + + // Save variadic status into separate variable. + // Because parameter might be variadic, but type might be not variadic. + // Some built-in functions passes non-variadic types. + // Also allocate new type based on [p.Kind] because type should be remain non-variadic. + // The [p.Kind] used as prefix and base type. + mut oldKind := p.Kind + p.Kind = new(TypeKind, *p.Kind) + p.Kind.Variadic = false + defer { + p.Kind.Variadic = false // Set actual type as non-variadic. + p.Kind = oldKind + } + + for i < len(self.args); i++ { + mut arg := self.args[i] + + match type arg.Kind { + | &VariadicExpr: + self.e.prefix = &TypeKind{ + Kind: &Slc{ + Elem: p.Kind, + }, + } + |: + self.e.prefix = p.Kind + } + + mut d := self.e.eval(arg) + if d == nil { + ok = false + continue + } + + if d.Kind.Variadic { + variadiced = true + p.Kind.Variadic = true + ok = ok && self.checkArg(p, d, arg.Token) + p.Kind.Variadic = false + match type d.Model { + | &SliceExprModel: + model = (&SliceExprModel)(d.Model) + model.ElemKind = p.Kind + |: + model = nil + self.argModels = append(self.argModels, d.Model) + } + // Break iteration early, this argument is variadic, so should be last. + // If this argument is not last, following algorithm will create error log for that. + // Increase variable i for point to following argument. + i++ + break + } + + ok = ok && self.checkArg(p, d, arg.Token) + model.Elems = append(model.Elems, d.Model) + } + self.e.prefix = old + + if variadiced && more { + // Use variable i because when variadic argument appears iteral will break. + // And it will increase variable i for point to following argument. + // Therefore, variable i always points to problematic argument. + self.pushErrToken(self.args[i].Token, LogMsg.MoreArgsWithVariadiced) + } + + if model != nil { + self.argModels = append(self.argModels, model) + } + ret ok + } + + fn checkArgs(mut self, mut ¶ms: []&ParamIns): (ok: bool) { + arg := self.e.arg + self.e.arg = true + + ok = true + mut i := 0 + if len(params) > 0 && params[0].Decl.IsSelf() { + // Ignore self. + i++ + } + iter: + for i < len(params) { + mut p := params[i] + match { + | p.Decl.Variadic: + ok = self.pushVariadic(p, i) && ok + // Variadiced parameters always last. + break iter + | len(self.args) <= i: + ok = false + break iter + |: + ok = self.push(p, self.args[i]) && ok + } + i++ + } + + self.e.arg = arg + ret ok + } + + fn checkDynamicTypeAnnotation(mut self): (ok: bool) { + for _, g in self.f.Generics { + if g == nil { + self.pushErr(LogMsg.DynamicTypeAnnotationFailed) + ret false + } + } + ret true + } + + fn check(mut self): (ok: bool) { + mut params := self.getParams() + ok = self.checkCounts(params) + if !ok { + ret false + } + ok = self.checkArgs(params) + if ok && self.dynamicAnnotation { + ok = self.checkDynamicTypeAnnotation() + } + ret ok + } } // Checks mutability risk of struct literals. @@ -918,506 +918,506 @@ impl fnCallArgChecker { // Therefore, it will not check interior mutability risks. // Assumes mutable structure literal and checks field assignments. fn checkMutRiskOfStructLit(mut &s: &Sema, &m: &StructLitExprModel) { - for _, arg in m.Args { - if arg.Field.Decl.Mutable { - // Skip this field. - // If there is a mutability risk, it will be logged by [structLitChecker]. - continue - } - if !arg.Expr.Mutable && arg.Expr.Kind.Mutable() { - s.pushErr(arg.Token, LogMsg.AssignNonMutToMut, arg.Expr.Kind.Str()) - } - } + for _, arg in m.Args { + if arg.Field.Decl.Mutable { + // Skip this field. + // If there is a mutability risk, it will be logged by [structLitChecker]. + continue + } + if !arg.Expr.Mutable && arg.Expr.Kind.Mutable() { + s.pushErr(arg.Token, LogMsg.AssignNonMutToMut, arg.Expr.Kind.Str()) + } + } } struct structLitChecker { - e: &Eval - errorToken: &Token - s: &StructIns - args: []&StructArgExprModel + e: &Eval + errorToken: &Token + s: &StructIns + args: []&StructArgExprModel } impl structLitChecker { - fn pushErr(mut self, token: &Token, fmt: LogMsg, args: ...any) { - self.e.pushErr(token, fmt, args...) - } - - // Push suggestion to last log. - fn pushSuggestion(mut self, fmt: LogMsg, args: ...any) { - self.e.pushSuggestion(fmt, args...) - } - - fn pushMatch(mut self, mut &f: &FieldIns, mut &d: &Data, mut &errorToken: &Token) { - const Reference = false - // If evaluated for the immutable memory, check as immutable. - // But if field in scope of the interior mutability, check as mutable. - // Do not accept as risky if structure is not have any method. - // Because if there is not method, no risk for interior mutability. - mutable := !self.e.immutable || (f.Decl.Mutable && len(self.s.Methods) > 0) - if self.e.s.checkValidityForInitExpr(mutable, Reference, f.Kind, d, errorToken) { - // Check type if validity is good. - // Helps to reduce error logs and duplicated logs. - _ = self.e.s.checkAssignType(false, f.Kind, d, errorToken) - } - self.args = append(self.args, &StructArgExprModel{ - Token: errorToken, - Field: f, - Expr: d, - }) - } - - fn checkPair(mut self, mut &pair: &FieldExprPair, mut &exprs: []&Expr) { - // Check existing. - mut f := self.s.FindField(pair.Field.Kind) - if f == nil { - self.pushErr(pair.Field, LogMsg.IdentNotExist, pair.Field.Kind) - ret - } - if !self.e.s.isAccessibleDefine(f.Decl.Public, f.Decl.Token) { - self.pushErr(pair.Field, LogMsg.IdentIsNotAccessible, pair.Field.Kind) - self.pushSuggestion(LogMsg.MakePubToAccess) - } - - // Check duplications. - dup_lookup: - for (_, mut expr) in exprs { - match type expr.Kind { - | &FieldExprPair: - mut dpair := (&FieldExprPair)(expr.Kind) - match { - | pair == dpair: - break dup_lookup - | pair.Field.Kind == dpair.Field.Kind: - self.pushErr(pair.Field, LogMsg.AlreadyHasExpr, pair.Field.Kind) - break dup_lookup - } - } - } - - mut prefix := self.e.prefix - defer { self.e.prefix = prefix } - self.e.prefix = f.Kind - - mut d := self.e.evalExpr(pair.Expr) - if d == nil { - ret - } - self.pushMatch(f, d, pair.Field) - } - - fn readyExprs(mut self, mut &exprs: []&Expr): bool { - mut ok := true - for (i, mut expr) in exprs { - match type expr.Kind { - | &KeyValPair: - mut pair := (&KeyValPair)(expr.Kind) - match type pair.Key.Kind { - | &IdentExpr: - // Ok - break - |: - self.pushErr(pair.Colon, LogMsg.InvalidSyntax) - ok = false - continue - } - exprs[i].Kind = &FieldExprPair{ - Field: pair.Key.Token, - Expr: pair.Val, - } - } - } - ret ok - } - - fn check(mut self, mut &exprs: []&Expr) { - if len(exprs) == 0 { - ret - } - if !self.readyExprs(exprs) { - ret - } - mut paired := false - for (i, mut expr) in exprs { - match type expr.Kind { - | &FieldExprPair: - mut pair := (&FieldExprPair)(expr.Kind) - if i > 0 && !paired { - self.pushErr(pair.Field, LogMsg.InvalidSyntax) - } - paired = true - self.checkPair(pair, exprs) - |: - if paired { - self.pushErr(expr.Token, LogMsg.ArgMustTargetToField) - } - if i >= len(self.s.Fields) { - self.pushErr(expr.Token, LogMsg.ArgumentOverflow) - continue - } - - mut field := self.s.Fields[i] - - if !self.e.s.isAccessibleDefine(field.Decl.Public, field.Decl.Token) { - self.pushErr(self.errorToken, LogMsg.StructureLitWithPrivFields) - self.pushSuggestion(LogMsg.UseFieldPairToInstantiate) - ret - } - - mut prefix := self.e.prefix - defer { self.e.prefix = prefix } - self.e.prefix = field.Kind - - mut d := self.e.evalExpr(expr) - if d == nil { - continue - } - - self.pushMatch(field, d, expr.Token) - } - } - - // Check missing arguments for fields. - if !paired { - n := len(self.s.Fields) - mut diff := n - len(exprs) - match { - | diff <= 0: - ret - } - - mut idents := StrBuilder.New(1 << 5) - for diff > 0; diff-- { - idents.WriteStr(", ") - idents.WriteStr(self.s.Fields[n-diff].Decl.Ident) - } - self.pushErr(self.errorToken, LogMsg.MissingExprFor, - str(unsafe { idents.Buf() }[2:])) /* Remove first separator. */ - } - } + fn pushErr(mut self, token: &Token, fmt: LogMsg, args: ...any) { + self.e.pushErr(token, fmt, args...) + } + + // Push suggestion to last log. + fn pushSuggestion(mut self, fmt: LogMsg, args: ...any) { + self.e.pushSuggestion(fmt, args...) + } + + fn pushMatch(mut self, mut &f: &FieldIns, mut &d: &Data, mut &errorToken: &Token) { + const Reference = false + // If evaluated for the immutable memory, check as immutable. + // But if field in scope of the interior mutability, check as mutable. + // Do not accept as risky if structure is not have any method. + // Because if there is not method, no risk for interior mutability. + mutable := !self.e.immutable || (f.Decl.Mutable && len(self.s.Methods) > 0) + if self.e.s.checkValidityForInitExpr(mutable, Reference, f.Kind, d, errorToken) { + // Check type if validity is good. + // Helps to reduce error logs and duplicated logs. + _ = self.e.s.checkAssignType(false, f.Kind, d, errorToken) + } + self.args = append(self.args, &StructArgExprModel{ + Token: errorToken, + Field: f, + Expr: d, + }) + } + + fn checkPair(mut self, mut &pair: &FieldExprPair, mut &exprs: []&Expr) { + // Check existing. + mut f := self.s.FindField(pair.Field.Kind) + if f == nil { + self.pushErr(pair.Field, LogMsg.IdentNotExist, pair.Field.Kind) + ret + } + if !self.e.s.isAccessibleDefine(f.Decl.Public, f.Decl.Token) { + self.pushErr(pair.Field, LogMsg.IdentIsNotAccessible, pair.Field.Kind) + self.pushSuggestion(LogMsg.MakePubToAccess) + } + + // Check duplications. + dup_lookup: + for (_, mut expr) in exprs { + match type expr.Kind { + | &FieldExprPair: + mut dpair := (&FieldExprPair)(expr.Kind) + match { + | pair == dpair: + break dup_lookup + | pair.Field.Kind == dpair.Field.Kind: + self.pushErr(pair.Field, LogMsg.AlreadyHasExpr, pair.Field.Kind) + break dup_lookup + } + } + } + + mut prefix := self.e.prefix + defer { self.e.prefix = prefix } + self.e.prefix = f.Kind + + mut d := self.e.evalExpr(pair.Expr) + if d == nil { + ret + } + self.pushMatch(f, d, pair.Field) + } + + fn readyExprs(mut self, mut &exprs: []&Expr): bool { + mut ok := true + for (i, mut expr) in exprs { + match type expr.Kind { + | &KeyValPair: + mut pair := (&KeyValPair)(expr.Kind) + match type pair.Key.Kind { + | &IdentExpr: + // Ok + break + |: + self.pushErr(pair.Colon, LogMsg.InvalidSyntax) + ok = false + continue + } + exprs[i].Kind = &FieldExprPair{ + Field: pair.Key.Token, + Expr: pair.Val, + } + } + } + ret ok + } + + fn check(mut self, mut &exprs: []&Expr) { + if len(exprs) == 0 { + ret + } + if !self.readyExprs(exprs) { + ret + } + mut paired := false + for (i, mut expr) in exprs { + match type expr.Kind { + | &FieldExprPair: + mut pair := (&FieldExprPair)(expr.Kind) + if i > 0 && !paired { + self.pushErr(pair.Field, LogMsg.InvalidSyntax) + } + paired = true + self.checkPair(pair, exprs) + |: + if paired { + self.pushErr(expr.Token, LogMsg.ArgMustTargetToField) + } + if i >= len(self.s.Fields) { + self.pushErr(expr.Token, LogMsg.ArgumentOverflow) + continue + } + + mut field := self.s.Fields[i] + + if !self.e.s.isAccessibleDefine(field.Decl.Public, field.Decl.Token) { + self.pushErr(self.errorToken, LogMsg.StructureLitWithPrivFields) + self.pushSuggestion(LogMsg.UseFieldPairToInstantiate) + ret + } + + mut prefix := self.e.prefix + defer { self.e.prefix = prefix } + self.e.prefix = field.Kind + + mut d := self.e.evalExpr(expr) + if d == nil { + continue + } + + self.pushMatch(field, d, expr.Token) + } + } + + // Check missing arguments for fields. + if !paired { + n := len(self.s.Fields) + mut diff := n - len(exprs) + match { + | diff <= 0: + ret + } + + mut idents := StrBuilder.New(1 << 5) + for diff > 0; diff-- { + idents.WriteStr(", ") + idents.WriteStr(self.s.Fields[n-diff].Decl.Ident) + } + self.pushErr(self.errorToken, LogMsg.MissingExprFor, + str(unsafe { idents.Buf() }[2:])) /* Remove first separator. */ + } + } } // Range checker and setter. struct rangeChecker { - sc: &scopeChecker - rang: &RangeKind - Kind: &RangeIter - d: &Data + sc: &scopeChecker + rang: &RangeKind + Kind: &RangeIter + d: &Data } impl rangeChecker { - fn buildVar(self, mut &decl: &VarDecl): &Var { - mut v := buildVar(decl) - ret v - } - - fn setSizeKey(mut self) { - if self.rang.KeyA == nil || IsIgnoreIdent(self.rang.KeyA.Ident) { - ret - } - self.Kind.KeyA = self.buildVar(self.rang.KeyA) - self.Kind.KeyA.Kind = findBuiltinTypeAlias(PrimKind.Int).Kind - } - - // Check range expression validity. - // It bypass mutability error if necessary. - // - // - d: data to check. - // - key: data passed to this key. - // - k: element kind of expression. - fn checkRangeExprValidity(mut self, mut &d: &Data, &key: &Var, mut &k: &TypeKind) { - mut _mut := key.Mutable - if _mut && !k.Mutable() { - // Bypass mutability error. - // Element kind is immutable. - // There is no mutation. - _mut = false - } - - self.sc.s.checkValidityForInitExpr( - _mut, key.Reference, key.Kind.Kind, d, self.rang.InToken) - } - - fn checkSlice(mut self) { - self.setSizeKey() - if self.rang.KeyB == nil || IsIgnoreIdent(self.rang.KeyB.Ident) { - ret - } - - mut slc := self.d.Kind.Slc() - self.Kind.KeyB = self.buildVar(self.rang.KeyB) - self.Kind.KeyB.Kind = &TypeSymbol{Kind: slc.Elem} - - self.checkRangeExprValidity(self.d, self.Kind.KeyB, slc.Elem) - } - - fn checkArray(mut self) { - self.setSizeKey() - if self.rang.KeyB == nil || IsIgnoreIdent(self.rang.KeyB.Ident) { - ret - } - - mut arr := self.d.Kind.Arr() - self.Kind.KeyB = self.buildVar(self.rang.KeyB) - self.Kind.KeyB.Kind = &TypeSymbol{Kind: arr.Elem} - - self.checkRangeExprValidity(self.d, self.Kind.KeyB, arr.Elem) - } - - fn checkMapKeyA(mut self) { - if self.rang.KeyA == nil || IsIgnoreIdent(self.rang.KeyA.Ident) { - ret - } - - mut m := self.d.Kind.Map() - self.Kind.KeyA = self.buildVar(self.rang.KeyA) - self.Kind.KeyA.Kind = &TypeSymbol{Kind: m.Key} - - mut d := new(Data, *self.d) - d.Kind = m.Key - - self.checkRangeExprValidity(d, self.Kind.KeyA, m.Key) - } - - fn checkMapKeyB(mut self) { - if self.rang.KeyB == nil || IsIgnoreIdent(self.rang.KeyB.Ident) { - ret - } - - mut m := self.d.Kind.Map() - self.Kind.KeyB = self.buildVar(self.rang.KeyB) - self.Kind.KeyB.Kind = &TypeSymbol{Kind: m.Val} - - mut d := new(Data, *self.d) - d.Kind = m.Val - - self.checkRangeExprValidity(d, self.Kind.KeyB, m.Val) - } - - fn checkMap(mut self) { - self.checkMapKeyA() - self.checkMapKeyB() - } - - fn checkStr(mut self) { - self.setSizeKey() - if self.rang.KeyB == nil || IsIgnoreIdent(self.rang.KeyB.Ident) { - ret - } - self.Kind.KeyB = self.buildVar(self.rang.KeyB) - self.Kind.KeyB.Kind = findBuiltinTypeAlias(PrimKind.U8).Kind - } - - fn checkComptime(mut self) { - self.setSizeKey() - if self.rang.KeyA != nil && self.rang.KeyA.Mutable { - self.sc.s.pushErr(self.rang.KeyA.Token, LogMsg.CannotBeMut, self.rang.KeyA.Ident) - } - if self.rang.KeyB != nil && self.rang.KeyB.Mutable { - self.sc.s.pushErr(self.rang.KeyB.Token, LogMsg.CannotBeMut, self.rang.KeyB.Ident) - } - if self.rang.KeyB == nil || IsIgnoreIdent(self.rang.KeyB.Ident) { - ret - } - self.Kind.KeyB = self.buildVar(self.rang.KeyB) - } - - fn checkComptimeRange(mut self): bool { - mut range := self.d.Kind.comptimeRange() - match type range.kind { - | &comptimeStructFields - | &comptimeEnumFields - | &comptimeParams - | &comptimeTypeInfos - | &comptimeStatics - | &comptimeFiles: - self.checkComptime() - ret true - |: - self.sc.s.pushErr(self.rang.InToken, LogMsg.IterRangeRequireEnumerableExpr) - ret false - } - } - - fn check(mut self): bool { - match { - | self.d.Kind.Variadic: - // Fail. - | self.d.Kind.Slc() != nil: - self.checkSlice() - ret true - | self.d.Kind.Arr() != nil: - self.checkArray() - ret true - | self.d.Kind.Map() != nil: - self.checkMap() - ret true - | self.d.Kind.comptimeRange() != nil: - ret self.checkComptimeRange() - |: - prim := self.d.Kind.Prim() - if prim != nil && prim.IsStr() { - self.checkStr() - ret true - } - } - self.sc.s.pushErr(self.rang.InToken, LogMsg.IterRangeRequireEnumerableExpr) - ret false - } + fn buildVar(self, mut &decl: &VarDecl): &Var { + mut v := buildVar(decl) + ret v + } + + fn setSizeKey(mut self) { + if self.rang.KeyA == nil || IsIgnoreIdent(self.rang.KeyA.Ident) { + ret + } + self.Kind.KeyA = self.buildVar(self.rang.KeyA) + self.Kind.KeyA.Kind = findBuiltinTypeAlias(PrimKind.Int).Kind + } + + // Check range expression validity. + // It bypass mutability error if necessary. + // + // - d: data to check. + // - key: data passed to this key. + // - k: element kind of expression. + fn checkRangeExprValidity(mut self, mut &d: &Data, &key: &Var, mut &k: &TypeKind) { + mut _mut := key.Mutable + if _mut && !k.Mutable() { + // Bypass mutability error. + // Element kind is immutable. + // There is no mutation. + _mut = false + } + + self.sc.s.checkValidityForInitExpr( + _mut, key.Reference, key.Kind.Kind, d, self.rang.InToken) + } + + fn checkSlice(mut self) { + self.setSizeKey() + if self.rang.KeyB == nil || IsIgnoreIdent(self.rang.KeyB.Ident) { + ret + } + + mut slc := self.d.Kind.Slc() + self.Kind.KeyB = self.buildVar(self.rang.KeyB) + self.Kind.KeyB.Kind = &TypeSymbol{Kind: slc.Elem} + + self.checkRangeExprValidity(self.d, self.Kind.KeyB, slc.Elem) + } + + fn checkArray(mut self) { + self.setSizeKey() + if self.rang.KeyB == nil || IsIgnoreIdent(self.rang.KeyB.Ident) { + ret + } + + mut arr := self.d.Kind.Arr() + self.Kind.KeyB = self.buildVar(self.rang.KeyB) + self.Kind.KeyB.Kind = &TypeSymbol{Kind: arr.Elem} + + self.checkRangeExprValidity(self.d, self.Kind.KeyB, arr.Elem) + } + + fn checkMapKeyA(mut self) { + if self.rang.KeyA == nil || IsIgnoreIdent(self.rang.KeyA.Ident) { + ret + } + + mut m := self.d.Kind.Map() + self.Kind.KeyA = self.buildVar(self.rang.KeyA) + self.Kind.KeyA.Kind = &TypeSymbol{Kind: m.Key} + + mut d := new(Data, *self.d) + d.Kind = m.Key + + self.checkRangeExprValidity(d, self.Kind.KeyA, m.Key) + } + + fn checkMapKeyB(mut self) { + if self.rang.KeyB == nil || IsIgnoreIdent(self.rang.KeyB.Ident) { + ret + } + + mut m := self.d.Kind.Map() + self.Kind.KeyB = self.buildVar(self.rang.KeyB) + self.Kind.KeyB.Kind = &TypeSymbol{Kind: m.Val} + + mut d := new(Data, *self.d) + d.Kind = m.Val + + self.checkRangeExprValidity(d, self.Kind.KeyB, m.Val) + } + + fn checkMap(mut self) { + self.checkMapKeyA() + self.checkMapKeyB() + } + + fn checkStr(mut self) { + self.setSizeKey() + if self.rang.KeyB == nil || IsIgnoreIdent(self.rang.KeyB.Ident) { + ret + } + self.Kind.KeyB = self.buildVar(self.rang.KeyB) + self.Kind.KeyB.Kind = findBuiltinTypeAlias(PrimKind.U8).Kind + } + + fn checkComptime(mut self) { + self.setSizeKey() + if self.rang.KeyA != nil && self.rang.KeyA.Mutable { + self.sc.s.pushErr(self.rang.KeyA.Token, LogMsg.CannotBeMut, self.rang.KeyA.Ident) + } + if self.rang.KeyB != nil && self.rang.KeyB.Mutable { + self.sc.s.pushErr(self.rang.KeyB.Token, LogMsg.CannotBeMut, self.rang.KeyB.Ident) + } + if self.rang.KeyB == nil || IsIgnoreIdent(self.rang.KeyB.Ident) { + ret + } + self.Kind.KeyB = self.buildVar(self.rang.KeyB) + } + + fn checkComptimeRange(mut self): bool { + mut range := self.d.Kind.comptimeRange() + match type range.kind { + | &comptimeStructFields + | &comptimeEnumFields + | &comptimeParams + | &comptimeTypeInfos + | &comptimeStatics + | &comptimeFiles: + self.checkComptime() + ret true + |: + self.sc.s.pushErr(self.rang.InToken, LogMsg.IterRangeRequireEnumerableExpr) + ret false + } + } + + fn check(mut self): bool { + match { + | self.d.Kind.Variadic: + // Fail. + | self.d.Kind.Slc() != nil: + self.checkSlice() + ret true + | self.d.Kind.Arr() != nil: + self.checkArray() + ret true + | self.d.Kind.Map() != nil: + self.checkMap() + ret true + | self.d.Kind.comptimeRange() != nil: + ret self.checkComptimeRange() + |: + prim := self.d.Kind.Prim() + if prim != nil && prim.IsStr() { + self.checkStr() + ret true + } + } + self.sc.s.pushErr(self.rang.InToken, LogMsg.IterRangeRequireEnumerableExpr) + ret false + } } // Return type checker for return statements. struct retTypeChecker { - sc: &scopeChecker - f: &FnIns - types: []&TypeKind // Return types. - exprs: []&Expr // Return expressions. - errorToken: &Token - model: ExprModel + sc: &scopeChecker + f: &FnIns + types: []&TypeKind // Return types. + exprs: []&Expr // Return expressions. + errorToken: &Token + model: ExprModel } impl retTypeChecker { - fn prepareTypes(mut self) { - if self.f != nil { - self.types = self.f.Types() - } - } - - fn prepareExprs(mut self, mut &e: &Expr) { - if e == nil { - ret - } - match type e.Kind { - | &TupleExpr: - self.exprs = (&TupleExpr)(e.Kind).Expr - |: - self.exprs = append(self.exprs, e) - } - } - - fn checkExprs(mut self) { - if len(self.exprs) == 0 { - ret - } - mut datas := make([]&Data, 0, len(self.exprs)) - mut eval := self.sc.s.eval(self.sc) - for (i, mut expr) in self.exprs { - if i >= len(self.types) { - break - } - - mut t := self.types[i] - - eval.prefix = t - mut d := eval.evalExpr(expr) - if d == nil { - continue - } - - datas = append(datas, d) - - if !d.Mutable && d.Kind.Mutable() { - self.sc.s.pushErr(self.errorToken, LogMsg.RetWithMutTypedNonMut) - ret - } - - mut ac := assignTypeChecker{ - s: self.sc.s, - dest: t, - d: d, - errorToken: self.errorToken, - } - ac.check() - } - - // Set Model. - if len(datas) > 1 { // Tuple - self.model = &TupleExprModel{ - Datas: datas, - } - } else if len(datas) == 1 { - self.model = datas[0].Model - } - } - - // Assumes len(self.exprs) == 0 and kind is [&FnCallExpr]. - fn tryFuncMultiRetForward(mut self): bool { - mut eval := self.sc.s.eval(self.sc) - mut d := eval.evalExpr(self.exprs[0]) - if d == nil { - // Return true to skip following "false" handling errors. - // Evaluation error is enough for developer for now. - ret true - } - mut tup := d.Kind.Tup() - if tup == nil { - ret false - } - if len(tup.Types) != len(self.types) { - goto err - } - self.model = d.Model - for i in self.types { - if !self.sc.s._checkTypeCompatibility(self.types[i], tup.Types[i], self.errorToken) { - goto err - } - } - ret true - err: - mut wanted := StrBuilder.New(1 << 5) - for i, t in self.types { - wanted.WriteStr(t.Str()) - if len(self.types)-i > 1 { - wanted.WriteStr(", ") - } - } - mut given := StrBuilder.New(1 << 5) - for i, t in tup.Types { - given.WriteStr(t.Str()) - if len(self.types)-i > 1 { - given.WriteStr(", ") - } - } - self.sc.s.pushErr(self.errorToken, LogMsg.WrongRetForward, wanted.Str(), given.Str()) - ret false - } - - fn check(mut self, mut &e: &Expr): bool { - self.prepareTypes() - self.prepareExprs(e) - match { - | len(self.exprs) == 0 && len(self.types) > 0: - if !self.f.Decl.AnyVar() { - self.sc.s.pushErr(self.errorToken, LogMsg.RequireRetExpr) - ret false - } - ret true - | len(self.exprs) > 0 && self.f != nil && self.f.Decl.IsVoid(): - self.sc.s.pushErr(self.errorToken, LogMsg.VoidFnRetExpr) - ret false - | len(self.exprs) == 1 && len(self.types) > 1: - match type self.exprs[0].Kind { - | &FnCallExpr: - if self.tryFuncMultiRetForward() { - ret true - } - } - self.sc.s.pushErr(self.errorToken, LogMsg.MissingMultiRet) - ret false - | len(self.exprs) < len(self.types): - self.sc.s.pushErr(self.errorToken, LogMsg.MissingMultiRet) - | len(self.exprs) > len(self.types): - self.sc.s.pushErr(self.errorToken, LogMsg.OverflowRet) - } - self.checkExprs() - ret true - } + fn prepareTypes(mut self) { + if self.f != nil { + self.types = self.f.Types() + } + } + + fn prepareExprs(mut self, mut &e: &Expr) { + if e == nil { + ret + } + match type e.Kind { + | &TupleExpr: + self.exprs = (&TupleExpr)(e.Kind).Expr + |: + self.exprs = append(self.exprs, e) + } + } + + fn checkExprs(mut self) { + if len(self.exprs) == 0 { + ret + } + mut datas := make([]&Data, 0, len(self.exprs)) + mut eval := self.sc.s.eval(self.sc) + for (i, mut expr) in self.exprs { + if i >= len(self.types) { + break + } + + mut t := self.types[i] + + eval.prefix = t + mut d := eval.evalExpr(expr) + if d == nil { + continue + } + + datas = append(datas, d) + + if !d.Mutable && d.Kind.Mutable() { + self.sc.s.pushErr(self.errorToken, LogMsg.RetWithMutTypedNonMut) + ret + } + + mut ac := assignTypeChecker{ + s: self.sc.s, + dest: t, + d: d, + errorToken: self.errorToken, + } + ac.check() + } + + // Set Model. + if len(datas) > 1 { // Tuple + self.model = &TupleExprModel{ + Datas: datas, + } + } else if len(datas) == 1 { + self.model = datas[0].Model + } + } + + // Assumes len(self.exprs) == 0 and kind is [&FnCallExpr]. + fn tryFuncMultiRetForward(mut self): bool { + mut eval := self.sc.s.eval(self.sc) + mut d := eval.evalExpr(self.exprs[0]) + if d == nil { + // Return true to skip following "false" handling errors. + // Evaluation error is enough for developer for now. + ret true + } + mut tup := d.Kind.Tup() + if tup == nil { + ret false + } + if len(tup.Types) != len(self.types) { + goto err + } + self.model = d.Model + for i in self.types { + if !self.sc.s._checkTypeCompatibility(self.types[i], tup.Types[i], self.errorToken) { + goto err + } + } + ret true + err: + mut wanted := StrBuilder.New(1 << 5) + for i, t in self.types { + wanted.WriteStr(t.Str()) + if len(self.types)-i > 1 { + wanted.WriteStr(", ") + } + } + mut given := StrBuilder.New(1 << 5) + for i, t in tup.Types { + given.WriteStr(t.Str()) + if len(self.types)-i > 1 { + given.WriteStr(", ") + } + } + self.sc.s.pushErr(self.errorToken, LogMsg.WrongRetForward, wanted.Str(), given.Str()) + ret false + } + + fn check(mut self, mut &e: &Expr): bool { + self.prepareTypes() + self.prepareExprs(e) + match { + | len(self.exprs) == 0 && len(self.types) > 0: + if !self.f.Decl.AnyVar() { + self.sc.s.pushErr(self.errorToken, LogMsg.RequireRetExpr) + ret false + } + ret true + | len(self.exprs) > 0 && self.f != nil && self.f.Decl.IsVoid(): + self.sc.s.pushErr(self.errorToken, LogMsg.VoidFnRetExpr) + ret false + | len(self.exprs) == 1 && len(self.types) > 1: + match type self.exprs[0].Kind { + | &FnCallExpr: + if self.tryFuncMultiRetForward() { + ret true + } + } + self.sc.s.pushErr(self.errorToken, LogMsg.MissingMultiRet) + ret false + | len(self.exprs) < len(self.types): + self.sc.s.pushErr(self.errorToken, LogMsg.MissingMultiRet) + | len(self.exprs) > len(self.types): + self.sc.s.pushErr(self.errorToken, LogMsg.OverflowRet) + } + self.checkExprs() + ret true + } } fn lenKind(): &TypeKind { - ret primInt + ret primInt } // Reports whether d is good for dynamic type infer. fn isGoodValueToInfer(&d: &Data): bool { - ret !d.IsNil() + ret !d.IsNil() } \ No newline at end of file diff --git a/std/jule/sema/var.jule b/std/jule/sema/var.jule index 4f9eeb592..95c51989f 100644 --- a/std/jule/sema/var.jule +++ b/std/jule/sema/var.jule @@ -7,45 +7,45 @@ use std::jule::lex::{Token} // Variable. struct Var { - Scope: &Scope - Token: &Token - Ident: str - Binded: bool - Constant: bool - Mutable: bool - Public: bool - Used: bool - Statically: bool - Reference: bool - Kind: &TypeSymbol - Value: &Value - Refers: &ReferenceStack - Directives: []&Directive + Scope: &Scope + Token: &Token + Ident: str + Binded: bool + Constant: bool + Mutable: bool + Public: bool + Used: bool + Statically: bool + Reference: bool + Kind: &TypeSymbol + Value: &Value + Refers: &ReferenceStack + Directives: []&Directive - // The -2 means this variable is not one of the return variables. - // The -1 means this variable is just the single return variable one. - // The 0..n means this variable is the nth variable of the return variables. - RetOrder: int = -2 + // The -2 means this variable is not one of the return variables. + // The -1 means this variable is just the single return variable one. + // The 0..n means this variable is the nth variable of the return variables. + RetOrder: int = -2 - // This variable depended to these variables for initialization expression. - // Nil if not global variable. - Depends: []&Var + // This variable depended to these variables for initialization expression. + // Nil if not global variable. + Depends: []&Var } impl Var { - // Reports whether variable is initialized explicitly. - fn IsInitialized(self): bool { - ret self.Value != nil - } + // Reports whether variable is initialized explicitly. + fn IsInitialized(self): bool { + ret self.Value != nil + } - // Reports whether variable is type inferred. - fn IsTypeInferred(self): bool { - ret self.Kind == nil || self.Kind.Decl == nil - } + // Reports whether variable is type inferred. + fn IsTypeInferred(self): bool { + ret self.Kind == nil || self.Kind.Decl == nil + } - // Reports whether variable is untyped constant. - // For true result, variable should type inferred and not include casting. - fn untypedConstant(self): bool { - ret self.IsTypeInferred() && self.Value.Data.untyped - } + // Reports whether variable is untyped constant. + // For true result, variable should type inferred and not include casting. + fn untypedConstant(self): bool { + ret self.IsTypeInferred() && self.Value.Data.untyped + } } \ No newline at end of file diff --git a/std/jule/types/bits.jule b/std/jule/types/bits.jule index d7da2e9d6..1ffeab248 100644 --- a/std/jule/types/bits.jule +++ b/std/jule/types/bits.jule @@ -21,136 +21,136 @@ static SysInt = "" static SysUint = "" fn checkBit(v: str, bit: int, checker: bitChecker): bool { - match { - | v == "": - ret false - | len(v) == 1: - ret true - | strings::HasPrefix(v, "0x"): - ret checker(v[2:], 1 << 4, bit) // Hexadecimal - | strings::HasPrefix(v, "0b"): - ret checker(v[2:], 1 << 1, bit) // Binary - | strings::HasPrefix(v, "0o"): - ret checker(v[2:], 1 << 3, bit) // Octal - | v[0] == '0': - ret checker(v[1:], 1 << 3, bit) // Octal - |: - ret checker(v, 1 << 3 + 2, bit) // Decimal - } + match { + | v == "": + ret false + | len(v) == 1: + ret true + | strings::HasPrefix(v, "0x"): + ret checker(v[2:], 1 << 4, bit) // Hexadecimal + | strings::HasPrefix(v, "0b"): + ret checker(v[2:], 1 << 1, bit) // Binary + | strings::HasPrefix(v, "0o"): + ret checker(v[2:], 1 << 3, bit) // Octal + | v[0] == '0': + ret checker(v[1:], 1 << 3, bit) // Octal + |: + ret checker(v, 1 << 3 + 2, bit) // Decimal + } } // Returns kind's bit-specific kind if bit-specific like int, uint, and uintptr. // Returns kind if not bit-specific. // Bit-size is determined by runtime. fn RealKindOf(kind: str): str { - match kind { - | TypeKind.Int: - ret SysInt - | TypeKind.Uint - | TypeKind.Uintptr: - ret SysUint - |: - ret kind - } + match kind { + | TypeKind.Int: + ret SysInt + | TypeKind.Uint + | TypeKind.Uintptr: + ret SysUint + |: + ret kind + } } // Returns kind's bit-size. // Returns -1 if kind is not numeric. fn BitsizeOf(k: str): int { - match k { - | TypeKind.I8 - | TypeKind.U8: - ret 1 << 3 - | TypeKind.I16 - | TypeKind.U16: - ret 1 << 4 - | TypeKind.I32 - | TypeKind.U32 - | TypeKind.F32: - ret 1 << 5 - | TypeKind.I64 - | TypeKind.U64 - | TypeKind.F64: - ret 1 << 6 - | TypeKind.Uint - | TypeKind.Int - | TypeKind.Uintptr: - ret BitSize - |: - ret -1 - } + match k { + | TypeKind.I8 + | TypeKind.U8: + ret 1 << 3 + | TypeKind.I16 + | TypeKind.U16: + ret 1 << 4 + | TypeKind.I32 + | TypeKind.U32 + | TypeKind.F32: + ret 1 << 5 + | TypeKind.I64 + | TypeKind.U64 + | TypeKind.F64: + ret 1 << 6 + | TypeKind.Uint + | TypeKind.Int + | TypeKind.Uintptr: + ret BitSize + |: + ret -1 + } } // Returns signed integer kind by bit-size. // Possible bit-sizes are: 8, 16, 32, and 64. // Returns empty string if bits is invalid. fn IntFromBits(bits: int): str { - match bits { - | 1 << 3: - ret TypeKind.I8 - | 1 << 4: - ret TypeKind.I16 - | 1 << 5: - ret TypeKind.I32 - | 1 << 6: - ret TypeKind.I64 - |: - ret "" - } + match bits { + | 1 << 3: + ret TypeKind.I8 + | 1 << 4: + ret TypeKind.I16 + | 1 << 5: + ret TypeKind.I32 + | 1 << 6: + ret TypeKind.I64 + |: + ret "" + } } // Returns unsigned integer kind by bit-size. // Possible bit-sizes are: 8, 16, 32, and 64. // Returns empty string if bits is invalid. fn UintFromBits(bits: int): str { - match bits { - | 1 << 3: - ret TypeKind.U8 - | 1 << 4: - ret TypeKind.U16 - | 1 << 5: - ret TypeKind.U32 - | 1 << 6: - ret TypeKind.U64 - |: - ret "" - } + match bits { + | 1 << 3: + ret TypeKind.U8 + | 1 << 4: + ret TypeKind.U16 + | 1 << 5: + ret TypeKind.U32 + | 1 << 6: + ret TypeKind.U64 + |: + ret "" + } } // Returns floating-point kind by bit-size. // Possible bit-sizes are: 32, and 64. // Returns empty string if bits is invalid. fn FloatFromBits(bits: int): str { - match bits { - | 1 << 5: - ret TypeKind.F32 - | 1 << 6: - ret TypeKind.F64 - |: - ret "" - } + match bits { + | 1 << 5: + ret TypeKind.F32 + | 1 << 6: + ret TypeKind.F64 + |: + ret "" + } } // Reports whether signed integer literal is compatible given bit-size. fn CheckBitInt(v: str, bit: int): bool { - ret checkBit(v, bit, fn(v: str, base: int, bit: int): bool { - _ = conv::ParseInt(v, base, bit) else { ret false } - ret true - }) + ret checkBit(v, bit, fn(v: str, base: int, bit: int): bool { + _ = conv::ParseInt(v, base, bit) else { ret false } + ret true + }) } // Reports whether unsigned integer literal is compatible given bit-size. fn CheckBitUint(v: str, bit: int): bool { - ret checkBit(v, bit, fn(v: str, base: int, bit: int): bool { - _ = conv::ParseUint(v, base, bit) else { ret false } - ret true - }) + ret checkBit(v, bit, fn(v: str, base: int, bit: int): bool { + _ = conv::ParseUint(v, base, bit) else { ret false } + ret true + }) } // Reports whether float literal is compatible given bit-size. fn CheckBitFloat(val: str, bit: int): bool { - _ = conv::ParseFloat(val, bit) else { ret false } - ret true + _ = conv::ParseFloat(val, bit) else { ret false } + ret true } // Reports minimum bit-size of given floating-point. @@ -159,12 +159,12 @@ fn CheckBitFloat(val: str, bit: int): bool { // - 32 for 32-bit // - 64 for 64-bit fn BitsizeOfFloat(x: f64): int { - match { - | MinF32 <= x && x <= MaxF32: - ret 1 << 5 - |: - ret 1 << 6 - } + match { + | MinF32 <= x && x <= MaxF32: + ret 1 << 5 + |: + ret 1 << 6 + } } // Reports minimum bit-size of given signed integer. @@ -175,16 +175,16 @@ fn BitsizeOfFloat(x: f64): int { // - 32 for 32-bit // - 64 for 64-bit fn BitsizeOfInt(x: i64): int { - match { - | MinI8 <= x && x <= MaxI8: - ret 1 << 3 - | MinI16 <= x && x <= MaxI16: - ret 1 << 4 - | MinI32 <= x && x <= MaxI32: - ret 1 << 5 - |: - ret 1 << 6 - } + match { + | MinI8 <= x && x <= MaxI8: + ret 1 << 3 + | MinI16 <= x && x <= MaxI16: + ret 1 << 4 + | MinI32 <= x && x <= MaxI32: + ret 1 << 5 + |: + ret 1 << 6 + } } // Reports minimum bit-size of given unsigned integer. @@ -195,36 +195,36 @@ fn BitsizeOfInt(x: i64): int { // - 32 for 32-bit // - 64 for 64-bit fn BitsizeOfUint(x: u64): int { - match { - | x <= MaxU8: - ret 1 << 3 - | x <= MaxU16: - ret 1 << 4 - | x <= MaxU32: - ret 1 << 5 - |: - ret 1 << 6 - } + match { + | x <= MaxU8: + ret 1 << 3 + | x <= MaxU16: + ret 1 << 4 + | x <= MaxU32: + ret 1 << 5 + |: + ret 1 << 6 + } } // Updates platform-specific informations by target. // If you will update target configuration, you should call this function. // In other words, new configurations is not applied for types. fn UpdateTarget() { - unsafe { - match build::Arch { - | "arm64" | "amd64": - *(&BitSize) = 1 << 6 - *(&SysInt) = TypeKind.I64 - *(&SysUint) = TypeKind.U64 - | "i386": - *(&BitSize) = 1 << 5 - *(&SysInt) = TypeKind.I32 - *(&SysUint) = TypeKind.U32 - } - } + unsafe { + match build::Arch { + | "arm64" | "amd64": + *(&BitSize) = 1 << 6 + *(&SysInt) = TypeKind.I64 + *(&SysUint) = TypeKind.U64 + | "i386": + *(&BitSize) = 1 << 5 + *(&SysInt) = TypeKind.I32 + *(&SysUint) = TypeKind.U32 + } + } } fn init() { - UpdateTarget() + UpdateTarget() } \ No newline at end of file diff --git a/std/jule/types/comp.jule b/std/jule/types/comp.jule index 2ac9e3f8f..46a198690 100644 --- a/std/jule/types/comp.jule +++ b/std/jule/types/comp.jule @@ -4,77 +4,77 @@ // Reports whether i16 is greater than given kind. fn IsI16Greater(mut k: str): bool { - ret k == TypeKind.I8 + ret k == TypeKind.I8 } // Reports whether i32 is greater than given kind. fn IsI32Greater(mut k: str): bool { - ret k == TypeKind.I8 || k == TypeKind.I16 + ret k == TypeKind.I8 || k == TypeKind.I16 } // Reports whether i64 is greater than given kind. fn IsI64Greater(mut k: str): bool { - ret k == TypeKind.I8 || - k == TypeKind.I16 || - k == TypeKind.I32 + ret k == TypeKind.I8 || + k == TypeKind.I16 || + k == TypeKind.I32 } // Reports whether u16 is greater than given kind. fn IsU16Greater(mut k: str): bool { - ret k == TypeKind.U8 + ret k == TypeKind.U8 } // Reports whether u32 is greater than given kind. fn IsU32Greater(mut k: str): bool { - ret k == TypeKind.U8 || - k == TypeKind.U16 + ret k == TypeKind.U8 || + k == TypeKind.U16 } // Reports whether u64 is greater than given kind. fn IsU64Greater(mut k: str): bool { - ret k == TypeKind.U8 || - k == TypeKind.U16 || - k == TypeKind.U32 + ret k == TypeKind.U8 || + k == TypeKind.U16 || + k == TypeKind.U32 } // Reports whether f32 is greater than given kind. fn IsF32Greater(k: str): bool { - ret k != TypeKind.F64 + ret k != TypeKind.F64 } // Reports whether f64 is greater than given kind. fn IsF64Greater(k: str): bool { - ret true + ret true } // Reports whether k1 kind greater than k2 kind. fn IsGreater(mut k1: str, k2: str): bool { - match k1 { - | TypeKind.Int: - ret IsSigInt(k2) - | TypeKind.Uint: - ret IsUnsigInt(k2) - | TypeKind.Uintptr: - ret IsUnsigInt(k2) - | TypeKind.I16: - ret IsI16Greater(k2) - | TypeKind.I32: - ret IsI32Greater(k2) - | TypeKind.I64: - ret IsI64Greater(k2) - | TypeKind.U16: - ret IsU16Greater(k2) - | TypeKind.U32: - ret IsU32Greater(k2) - | TypeKind.U64: - ret IsU64Greater(k2) - | TypeKind.F32: - ret IsF32Greater(k2) - | TypeKind.F64: - ret IsF64Greater(k2) - | TypeKind.Any: - ret true - |: - ret false - } + match k1 { + | TypeKind.Int: + ret IsSigInt(k2) + | TypeKind.Uint: + ret IsUnsigInt(k2) + | TypeKind.Uintptr: + ret IsUnsigInt(k2) + | TypeKind.I16: + ret IsI16Greater(k2) + | TypeKind.I32: + ret IsI32Greater(k2) + | TypeKind.I64: + ret IsI64Greater(k2) + | TypeKind.U16: + ret IsU16Greater(k2) + | TypeKind.U32: + ret IsU32Greater(k2) + | TypeKind.U64: + ret IsU64Greater(k2) + | TypeKind.F32: + ret IsF32Greater(k2) + | TypeKind.F64: + ret IsF64Greater(k2) + | TypeKind.Any: + ret true + |: + ret false + } } \ No newline at end of file diff --git a/std/jule/types/kind.jule b/std/jule/types/kind.jule index 0ce3f7e9a..0c2cbd90d 100644 --- a/std/jule/types/kind.jule +++ b/std/jule/types/kind.jule @@ -5,59 +5,59 @@ // Type kinds of primitive types. // These kinds are must match keyword form itself. enum TypeKind: str { - I8: "i8", // Kind of signed 8-bit integer - I16: "i16", // Kind of signed 16-bit integer - I32: "i32", // Kind of signed 32-bit integer - I64: "i64", // Kind of signed 64-bit integer - U8: "u8", // Kind of unsigned 8-bit integer - U16: "u16", // Kind of unsigned 16-bit integer - U32: "u32", // Kind of unsigned 32-bit integer - U64: "u64", // Kind of unsigned 64-bit integer - F32: "f32", // Kind of 32-bit floating-point - F64: "f64", // Kind of 64-bit floating-point - Uint: "uint", // Kind of system specific bit-size unsigned integer - Int: "int", // Kind of system specific bit-size signed integer - Uintptr: "uintptr", // Kind of system specific bit-size unsigned integer - Bool: "bool", // Kind of boolean - Str: "str", // Kind of string - Any: "any", // Kind of any type + I8: "i8", // Kind of signed 8-bit integer + I16: "i16", // Kind of signed 16-bit integer + I32: "i32", // Kind of signed 32-bit integer + I64: "i64", // Kind of signed 64-bit integer + U8: "u8", // Kind of unsigned 8-bit integer + U16: "u16", // Kind of unsigned 16-bit integer + U32: "u32", // Kind of unsigned 32-bit integer + U64: "u64", // Kind of unsigned 64-bit integer + F32: "f32", // Kind of 32-bit floating-point + F64: "f64", // Kind of 64-bit floating-point + Uint: "uint", // Kind of system specific bit-size unsigned integer + Int: "int", // Kind of system specific bit-size signed integer + Uintptr: "uintptr", // Kind of system specific bit-size unsigned integer + Bool: "bool", // Kind of boolean + Str: "str", // Kind of string + Any: "any", // Kind of any type } // Reports whether kind is signed integer. fn IsSigInt(mut k: str): bool { - ret k == TypeKind.I8 || - k == TypeKind.I16 || - k == TypeKind.I32 || - k == TypeKind.I64 || - k == TypeKind.Int + ret k == TypeKind.I8 || + k == TypeKind.I16 || + k == TypeKind.I32 || + k == TypeKind.I64 || + k == TypeKind.Int } // Reports kind is unsigned integer. fn IsUnsigInt(mut k: str): bool { - ret k == TypeKind.U8 || - k == TypeKind.U16 || - k == TypeKind.U32 || - k == TypeKind.U64 || - k == TypeKind.Uint || - k == TypeKind.Uintptr + ret k == TypeKind.U8 || + k == TypeKind.U16 || + k == TypeKind.U32 || + k == TypeKind.U64 || + k == TypeKind.Uint || + k == TypeKind.Uintptr } // Reports whether kind is signed/unsigned integer. fn IsInt(k: str): bool { - ret IsSigInt(k) || IsUnsigInt(k) + ret IsSigInt(k) || IsUnsigInt(k) } // Reports whether kind is float. fn IsFloat(k: str): bool { - ret k == TypeKind.F32 || k == TypeKind.F64 + ret k == TypeKind.F32 || k == TypeKind.F64 } // Reports whether kind is numeric. fn IsNum(k: str): bool { - ret IsInt(k) || IsFloat(k) + ret IsInt(k) || IsFloat(k) } // Reports whether kind is signed numeric. fn IsSigNum(k: str): bool { - ret IsSigInt(k) || IsFloat(k) + ret IsSigInt(k) || IsFloat(k) } \ No newline at end of file diff --git a/std/jule/types/limits.jule b/std/jule/types/limits.jule index 214b764d6..117c7fbf7 100644 --- a/std/jule/types/limits.jule +++ b/std/jule/types/limits.jule @@ -59,93 +59,93 @@ const MaxU64 = 18446744073709551615 // Returns minimum value of signed integer kinds. // Returns 0 if kind iss invalid. fn MinI(mut k: str): i64 { - k = RealKindOf(k) - match k { - | TypeKind.I8: - ret MinI8 - | TypeKind.I16: - ret MinI16 - | TypeKind.I32: - ret MinI32 - | TypeKind.I64: - ret MinI64 - |: - ret 0 - } + k = RealKindOf(k) + match k { + | TypeKind.I8: + ret MinI8 + | TypeKind.I16: + ret MinI16 + | TypeKind.I32: + ret MinI32 + | TypeKind.I64: + ret MinI64 + |: + ret 0 + } } // Returns minimum value of signed integer kinds. // Returns 0 if kind is invalid. fn MaxI(mut k: str): i64 { - k = RealKindOf(k) - match k { - | TypeKind.I8: - ret MaxI8 - | TypeKind.I16: - ret MaxI16 - | TypeKind.I32: - ret MaxI32 - | TypeKind.I64: - ret MaxI64 - |: - ret 0 - } + k = RealKindOf(k) + match k { + | TypeKind.I8: + ret MaxI8 + | TypeKind.I16: + ret MaxI16 + | TypeKind.I32: + ret MaxI32 + | TypeKind.I64: + ret MaxI64 + |: + ret 0 + } } // Returns maximum value of unsigned integer kinds. // Returns 0 if kind is invalid. fn MaxU(mut k: str): u64 { - k = RealKindOf(k) - match k { - | TypeKind.U8: - ret MaxU8 - | TypeKind.U16: - ret MaxU16 - | TypeKind.U32: - ret MaxU32 - | TypeKind.U64: - ret MaxU64 - |: - ret 0 - } + k = RealKindOf(k) + match k { + | TypeKind.U8: + ret MaxU8 + | TypeKind.U16: + ret MaxU16 + | TypeKind.U32: + ret MaxU32 + | TypeKind.U64: + ret MaxU64 + |: + ret 0 + } } // Returns minimum value of signed/unsigned integer and floating-point kinds. // Returns 0 if kind is invalid. fn Min(mut k: str): f64 { - k = RealKindOf(k) - i := MinI(k) - if i != 0 { - ret f64(i) - } - match k { - | TypeKind.F32: - ret MinF32 - | TypeKind.F64: - ret MinF64 - |: - ret 0 - } + k = RealKindOf(k) + i := MinI(k) + if i != 0 { + ret f64(i) + } + match k { + | TypeKind.F32: + ret MinF32 + | TypeKind.F64: + ret MinF64 + |: + ret 0 + } } // Returns maximum value of signed/unsigned integer and floating-point kinds. // Returns 0 if kind is invalid. fn Max(mut k: str): f64 { - k = RealKindOf(k) - i := MaxI(k) - if i != 0 { - ret f64(i) - } - u := MaxU(k) - if u != 0 { - ret f64(u) - } - match k { - | TypeKind.F32: - ret MaxF32 - | TypeKind.F64: - ret MaxF64 - |: - ret 0 - } + k = RealKindOf(k) + i := MaxI(k) + if i != 0 { + ret f64(i) + } + u := MaxU(k) + if u != 0 { + ret f64(u) + } + match k { + | TypeKind.F32: + ret MaxF32 + | TypeKind.F64: + ret MaxF64 + |: + ret 0 + } } \ No newline at end of file diff --git a/std/maps/maps.jule b/std/maps/maps.jule index 16727bee9..ee8f70381 100755 --- a/std/maps/maps.jule +++ b/std/maps/maps.jule @@ -6,40 +6,40 @@ // The nil maps considered as zero-length map. // The floating-point NaNs are not considered equal. fn Equal[M: map[K]V, K: comparable, V: comparable](m1: M, m2: M): bool { - if len(m1) != len(m2) { - ret false - } - for k, v1 in m1 { - v2, ok := m2[k] - if !ok || v1 != v2 { - ret false - } - } - ret true + if len(m1) != len(m2) { + ret false + } + for k, v1 in m1 { + v2, ok := m2[k] + if !ok || v1 != v2 { + ret false + } + } + ret true } // Returns all keys in a slice of map. // Returns nil if m == nil || len(m) == 0. fn Keys[M: map[K]V, K, V](mut m: M): []K { - if len(m) == 0 { - ret nil - } - mut s := make([]K, 0, len(m)) - for (mut k) in m { - s = append(s, k) - } - ret s + if len(m) == 0 { + ret nil + } + mut s := make([]K, 0, len(m)) + for (mut k) in m { + s = append(s, k) + } + ret s } // Returns all values in a slice of map. // Returns nil if m == nil || len(m) == 0. fn Values[M: map[K]V, K, V](mut m: M): []V { - if len(m) == 0 { - ret nil - } - mut s := make([]V, 0, len(m)) - for (_, mut v) in m { - s = append(s, v) - } - ret s + if len(m) == 0 { + ret nil + } + mut s := make([]V, 0, len(m)) + for (_, mut v) in m { + s = append(s, v) + } + ret s } \ No newline at end of file diff --git a/std/maps/maps_test.jule b/std/maps/maps_test.jule index 4763ab24b..22ffb6e57 100644 --- a/std/maps/maps_test.jule +++ b/std/maps/maps_test.jule @@ -7,131 +7,131 @@ use std::testing::{T} struct equalCase { - m1: map[int]str - m2: map[int]str - eq: bool + m1: map[int]str + m2: map[int]str + eq: bool } struct keysCase { - m: map[int]str - s: []int + m: map[int]str + s: []int } struct valuesCase { - m: map[int]str - s: []str + m: map[int]str + s: []str } static equalCases: []equalCase = [ - { - m1: {}, - m2: {}, - eq: true, - }, - { - m1: {}, - m2: nil, - eq: true, - }, - { - m1: nil, - m2: {}, - eq: true, - }, - { - m1: {0: "Hello", 1: ", ", 2: "World", 3: "!"}, - m2: {0: "Hello", 1: ", ", 2: "World", 3: "!"}, - eq: true, - }, - { - m1: {10: "Foo", 13: "Bar", 22: "Baz", 34: "..."}, - m2: {10: "Foo", 13: "Bar", 22: "Baz", 34: "..."}, - eq: true, - }, - { - m1: {0: "Hello", 1: ", ", 2: "World", 3: "!"}, - m2: {0: "Hello", 1: ", ", 2: "World", 3: "!!"}, - eq: false, - }, - { - m1: {10: "Foo", 13: "Bar", 22: "Baz"}, - m2: {10: "Foo", 13: "Bar", 22: "Baz", 34: "..."}, - eq: false, - }, - { - m1: {10: "Foo", 13: "Bar", 22: "Baz"}, - m2: {}, - eq: false, - }, - { - m1: {10: "Foo", 13: "Bar", 22: "Baz"}, - m2: nil, - eq: false, - }, + { + m1: {}, + m2: {}, + eq: true, + }, + { + m1: {}, + m2: nil, + eq: true, + }, + { + m1: nil, + m2: {}, + eq: true, + }, + { + m1: {0: "Hello", 1: ", ", 2: "World", 3: "!"}, + m2: {0: "Hello", 1: ", ", 2: "World", 3: "!"}, + eq: true, + }, + { + m1: {10: "Foo", 13: "Bar", 22: "Baz", 34: "..."}, + m2: {10: "Foo", 13: "Bar", 22: "Baz", 34: "..."}, + eq: true, + }, + { + m1: {0: "Hello", 1: ", ", 2: "World", 3: "!"}, + m2: {0: "Hello", 1: ", ", 2: "World", 3: "!!"}, + eq: false, + }, + { + m1: {10: "Foo", 13: "Bar", 22: "Baz"}, + m2: {10: "Foo", 13: "Bar", 22: "Baz", 34: "..."}, + eq: false, + }, + { + m1: {10: "Foo", 13: "Bar", 22: "Baz"}, + m2: {}, + eq: false, + }, + { + m1: {10: "Foo", 13: "Bar", 22: "Baz"}, + m2: nil, + eq: false, + }, ] static keysCases: []keysCase = [ - { - m: {0: "Hello", 1: ", ", 2: "World", 3: "!"}, - s: [0, 1, 2, 3], - }, - { - m: {10: "Foo", 13: "Bar", 22: "Baz", 34: "..."}, - s: [10, 13, 22, 34], - }, + { + m: {0: "Hello", 1: ", ", 2: "World", 3: "!"}, + s: [0, 1, 2, 3], + }, + { + m: {10: "Foo", 13: "Bar", 22: "Baz", 34: "..."}, + s: [10, 13, 22, 34], + }, ] static valuesCases: []valuesCase = [ - { - m: {0: "Hello", 1: ", ", 2: "World", 3: "!"}, - s: ["Hello", ", ", "World", "!"], - }, - { - m: {10: "Foo", 13: "Bar", 22: "Baz", 34: "..."}, - s: ["Foo", "Bar", "Baz", "..."], - }, + { + m: {0: "Hello", 1: ", ", 2: "World", 3: "!"}, + s: ["Hello", ", ", "World", "!"], + }, + { + m: {10: "Foo", 13: "Bar", 22: "Baz", 34: "..."}, + s: ["Foo", "Bar", "Baz", "..."], + }, ] #test fn equalKeys(t: &T) { - for i, case in equalCases { - eq := Equal(case.m1, case.m2) - if eq != case.eq { - t.Errorf("Equal test case {} failed, expected {} found {}", i, case.eq, eq) - } - } + for i, case in equalCases { + eq := Equal(case.m1, case.m2) + if eq != case.eq { + t.Errorf("Equal test case {} failed, expected {} found {}", i, case.eq, eq) + } + } } #test fn testKeys(t: &T) { - for i, case in keysCases { - keys := Keys(case.m) - lookup: - for _, key in keys { - for _, ckey in case.s { - if key == ckey { - continue lookup - } - } - t.Errorf("Keys test case {} failed", i) - break - } - } + for i, case in keysCases { + keys := Keys(case.m) + lookup: + for _, key in keys { + for _, ckey in case.s { + if key == ckey { + continue lookup + } + } + t.Errorf("Keys test case {} failed", i) + break + } + } } #test fn testValues(t: &T) { - for i, case in valuesCases { - values := Values(case.m) - lookup: - for _, value in values { - for _, cvalue in case.s { - if value == cvalue { - continue lookup - } - } - t.Errorf("Values test case {} failed", i) - break - } - } + for i, case in valuesCases { + values := Values(case.m) + lookup: + for _, value in values { + for _, cvalue in case.s { + if value == cvalue { + continue lookup + } + } + t.Errorf("Values test case {} failed", i) + break + } + } } \ No newline at end of file diff --git a/std/math/acosh.jule b/std/math/acosh.jule index 333d514b1..17bbe2fdd 100644 --- a/std/math/acosh.jule +++ b/std/math/acosh.jule @@ -71,18 +71,18 @@ // Acosh(x) = NaN if x < 1 // Acosh(NaN) = NaN fn Acosh(x: f64): f64 { - const Large = 1 << 28 // 2**28 - // first case is special case - match { - | x < 1 | IsNaN(x): - ret NaN() - | x == 1: - ret 0 - | x >= Large: - ret Log(x) + Ln2 // x > 2**28 - | x > 2: - ret Log(2 * x - 1 / (x + Sqrt(x * x - 1))) // 2**28 > x > 2 - } - t := x - 1 - ret Log1p(t + Sqrt(2 * t + t * t)) // 2 >= x > 1 + const Large = 1 << 28 // 2**28 + // first case is special case + match { + | x < 1 | IsNaN(x): + ret NaN() + | x == 1: + ret 0 + | x >= Large: + ret Log(x) + Ln2 // x > 2**28 + | x > 2: + ret Log(2 * x - 1 / (x + Sqrt(x * x - 1))) // 2**28 > x > 2 + } + t := x - 1 + ret Log1p(t + Sqrt(2 * t + t * t)) // 2 >= x > 1 } \ No newline at end of file diff --git a/std/math/asin.jule b/std/math/asin.jule index 155f95b96..e708affdf 100644 --- a/std/math/asin.jule +++ b/std/math/asin.jule @@ -48,29 +48,29 @@ // Asin(±0) = ±0 // Asin(x) = NaN if x < -1 or x > 1 fn Asin(mut x: f64): f64 { - if x == 0 { - ret x // special case - } - mut sign := false - if x < 0 { - x = -x - sign = true - } - if x > 1 { - ret NaN() // special case - } + if x == 0 { + ret x // special case + } + mut sign := false + if x < 0 { + x = -x + sign = true + } + if x > 1 { + ret NaN() // special case + } - mut temp := Sqrt(1 - x * x) - if x > 0.7 { - temp = Pi / 2 - satan(temp / x) - } else { - temp = satan(x / temp) - } + mut temp := Sqrt(1 - x * x) + if x > 0.7 { + temp = Pi / 2 - satan(temp / x) + } else { + temp = satan(x / temp) + } - if sign { - temp = -temp - } - ret temp + if sign { + temp = -temp + } + ret temp } // Returns the arccosine, in radians, of x. diff --git a/std/math/asinh.jule b/std/math/asinh.jule index b951e7eb2..266d94f89 100644 --- a/std/math/asinh.jule +++ b/std/math/asinh.jule @@ -68,32 +68,32 @@ // Asinh(±Inf) = ±Inf // Asinh(NaN) = NaN fn Asinh(mut x: f64): f64 { - const Ln2 = 6.93147180559945286227e-01 // 0x3FE62E42FEFA39EF - const NearZero = 1.0 / (1 << 28) // 2**-28 - const Large = 1 << 28 // 2**28 + const Ln2 = 6.93147180559945286227e-01 // 0x3FE62E42FEFA39EF + const NearZero = 1.0 / (1 << 28) // 2**-28 + const Large = 1 << 28 // 2**28 - // special cases - if IsNaN(x) || IsInf(x, 0) { - ret x - } - mut sign := false - if x < 0 { - x = -x - sign = true - } - mut temp := 0. - match { - | x > Large: - temp = Log(x) + Ln2 // |x| > 2**28 - | x > 2: - temp = Log(2 * x + 1 / (Sqrt(x * x + 1) + x)) // 2**28 > |x| > 2.0 - | x < NearZero: - temp = x // |x| < 2**-28 - |: - temp = Log1p(x + x * x / (1 + Sqrt(1 + x * x))) // 2.0 > |x| > 2**-28 - } - if sign { - temp = -temp - } - ret temp + // special cases + if IsNaN(x) || IsInf(x, 0) { + ret x + } + mut sign := false + if x < 0 { + x = -x + sign = true + } + mut temp := 0. + match { + | x > Large: + temp = Log(x) + Ln2 // |x| > 2**28 + | x > 2: + temp = Log(2 * x + 1 / (Sqrt(x * x + 1) + x)) // 2**28 > |x| > 2.0 + | x < NearZero: + temp = x // |x| < 2**-28 + |: + temp = Log1p(x + x * x / (1 + Sqrt(1 + x * x))) // 2.0 > |x| > 2**-28 + } + if sign { + temp = -temp + } + ret temp } \ No newline at end of file diff --git a/std/math/atan.jule b/std/math/atan.jule index 300212f93..5ea08fd24 100644 --- a/std/math/atan.jule +++ b/std/math/atan.jule @@ -84,36 +84,36 @@ // Evaluates a series valid in the range [0, 0.66]. fn xatan(x: f64): f64 { - const P0 = -8.750608600031904122785e-01 - const P1 = -1.615753718733365076637e+01 - const P2 = -7.500855792314704667340e+01 - const P3 = -1.228866684490136173410e+02 - const P4 = -6.485021904942025371773e+01 - const Q0 = +2.485846490142306297962e+01 - const Q1 = +1.650270098316988542046e+02 - const Q2 = +4.328810604912902668951e+02 - const Q3 = +4.853903996359136964868e+02 - const Q4 = +1.945506571482613964425e+02 + const P0 = -8.750608600031904122785e-01 + const P1 = -1.615753718733365076637e+01 + const P2 = -7.500855792314704667340e+01 + const P3 = -1.228866684490136173410e+02 + const P4 = -6.485021904942025371773e+01 + const Q0 = +2.485846490142306297962e+01 + const Q1 = +1.650270098316988542046e+02 + const Q2 = +4.328810604912902668951e+02 + const Q3 = +4.853903996359136964868e+02 + const Q4 = +1.945506571482613964425e+02 - mut z := x * x - z = z * ((((P0 * z + P1) * z + P2) * z + P3) * z + P4) / (((((z + Q0) * z + Q1) * z + Q2) * z + Q3) * z + Q4) - z = x * z + x - ret z + mut z := x * x + z = z * ((((P0 * z + P1) * z + P2) * z + P3) * z + P4) / (((((z + Q0) * z + Q1) * z + Q2) * z + Q3) * z + Q4) + z = x * z + x + ret z } // Reduces its argument (known to be positive) // to the range [0, 0.66] and calls xatan. fn satan(x: f64): f64 { - const morebits = 6.123233995736765886130e-17 // pi/2 = PIO2 + Morebits - const tan3pio8 = 2.41421356237309504880 // tan(3*pi/8) + const morebits = 6.123233995736765886130e-17 // pi/2 = PIO2 + Morebits + const tan3pio8 = 2.41421356237309504880 // tan(3*pi/8) - if x <= 0.66 { - ret xatan(x) - } - if x > tan3pio8 { - ret Pi / 2 - xatan(1 / x) + morebits - } - ret Pi / 4 + xatan((x - 1) / (x + 1)) + 0.5 * morebits + if x <= 0.66 { + ret xatan(x) + } + if x > tan3pio8 { + ret Pi / 2 - xatan(1 / x) + morebits + } + ret Pi / 4 + xatan((x - 1) / (x + 1)) + 0.5 * morebits } // Returns the arctangent, in radians, of x. @@ -122,11 +122,11 @@ fn satan(x: f64): f64 { // Atan(±0) = ±0 // Atan(±Inf) = ±Pi/2 fn Atan(x: f64): f64 { - if x == 0 { - ret x - } - if x > 0 { - ret satan(x) - } - ret -satan(-x) + if x == 0 { + ret x + } + if x > 0 { + ret satan(x) + } + ret -satan(-x) } \ No newline at end of file diff --git a/std/math/atan2.jule b/std/math/atan2.jule index f6d6ee091..6d7f0240d 100644 --- a/std/math/atan2.jule +++ b/std/math/atan2.jule @@ -58,43 +58,43 @@ // Atan2(+Inf, x) = +Pi/2 // Atan2(-Inf, x) = -Pi/2 fn Atan2(y: f64, x: f64): f64 { - // special cases - match { - | IsNaN(y) | IsNaN(x): - ret NaN() - | y == 0: - if x >= 0 && !Signbit(x) { - ret Copysign(0, y) - } - ret Copysign(Pi, y) - | x == 0: - ret Copysign(Pi / 2, y) - | IsInf(x, 0): - if IsInf(x, 1) { - match { - | IsInf(y, 0): - ret Copysign(Pi / 4, y) - |: - ret Copysign(0, y) - } - } - match { - | IsInf(y, 0): - ret Copysign(3 * Pi / 4, y) - |: - ret Copysign(Pi, y) - } - | IsInf(y, 0): - ret Copysign(Pi / 2, y) - } + // special cases + match { + | IsNaN(y) | IsNaN(x): + ret NaN() + | y == 0: + if x >= 0 && !Signbit(x) { + ret Copysign(0, y) + } + ret Copysign(Pi, y) + | x == 0: + ret Copysign(Pi / 2, y) + | IsInf(x, 0): + if IsInf(x, 1) { + match { + | IsInf(y, 0): + ret Copysign(Pi / 4, y) + |: + ret Copysign(0, y) + } + } + match { + | IsInf(y, 0): + ret Copysign(3 * Pi / 4, y) + |: + ret Copysign(Pi, y) + } + | IsInf(y, 0): + ret Copysign(Pi / 2, y) + } - // Call atan and determine the quadrant. - q := Atan(y / x) - if x < 0 { - if q <= 0 { - ret q + Pi - } - ret q - Pi - } - ret q + // Call atan and determine the quadrant. + q := Atan(y / x) + if x < 0 { + if q <= 0 { + ret q + Pi + } + ret q - Pi + } + ret q } \ No newline at end of file diff --git a/std/math/atanh.jule b/std/math/atanh.jule index 160278139..b3f03809f 100644 --- a/std/math/atanh.jule +++ b/std/math/atanh.jule @@ -76,33 +76,33 @@ // Atanh(x) = NaN if x < -1 or x > 1 // Atanh(NaN) = NaN fn Atanh(mut x: f64): f64 { - const NEAR_ZERO = 1.0 / (1 << 28) // 2**-28 - // special cases - match { - | x < -1 | x > 1 | IsNaN(x): - ret NaN() - | x == 1: - ret Inf(1) - | x == -1: - ret Inf(-1) - } - mut sign := false - if x < 0 { - x = -x - sign = true - } - mut temp := 0. - match { - | x < NEAR_ZERO: - temp = x - | x < 0.5: - temp = x + x - temp = 0.5 * Log1p(temp + temp * x / (1 - x)) - |: - temp = 0.5 * Log1p((x + x) / (1 - x)) - } - if sign { - temp = -temp - } - ret temp + const NEAR_ZERO = 1.0 / (1 << 28) // 2**-28 + // special cases + match { + | x < -1 | x > 1 | IsNaN(x): + ret NaN() + | x == 1: + ret Inf(1) + | x == -1: + ret Inf(-1) + } + mut sign := false + if x < 0 { + x = -x + sign = true + } + mut temp := 0. + match { + | x < NEAR_ZERO: + temp = x + | x < 0.5: + temp = x + x + temp = 0.5 * Log1p(temp + temp * x / (1 - x)) + |: + temp = 0.5 * Log1p((x + x) / (1 - x)) + } + if sign { + temp = -temp + } + ret temp } \ No newline at end of file diff --git a/std/math/big/bits.jule b/std/math/big/bits.jule index 72d6995de..4825fbc76 100644 --- a/std/math/big/bits.jule +++ b/std/math/big/bits.jule @@ -11,135 +11,135 @@ type bits: []bit const _INT_SIZE = 32 << (^uint(0) >> 63) fn u64FromBits(b: bits): u64 { - mut u := u64(0) - for i, bit in b { - u |= u64(bit) << i - } - ret u + mut u := u64(0) + for i, bit in b { + u |= u64(bit) << i + } + ret u } // Add one to bits. // Equals to x++ operator. fn addOne(mut &b: bits): (carry: bit) { - for i, x in b { - if x == 0 { - b[i] = 1 - ret 0b0 - } - b[i] = 0 - } - ret 0b1 + for i, x in b { + if x == 0 { + b[i] = 1 + ret 0b0 + } + b[i] = 0 + } + ret 0b1 } // Subrract one from bits. // Equals to x-- operator. fn subOne(mut &b: bits) { - mut j := 0 - for i, x in b { - if x == 0b1 { - b[i] = 0b0 - j = i - break - } - b[i] = 0 - } - for i in b[:j] { - b[i] = 0b1 - } + mut j := 0 + for i, x in b { + if x == 0b1 { + b[i] = 0b0 + j = i + break + } + b[i] = 0 + } + for i in b[:j] { + b[i] = 0b1 + } } fn reverse(mut &b: bits) { - mut i := 0 - for i < len(b)>>1; i++ { - b[i], b[len(b)-1-i] = b[len(b)-1-i], b[i] - } + mut i := 0 + for i < len(b)>>1; i++ { + b[i], b[len(b)-1-i] = b[len(b)-1-i], b[i] + } } // Add bits with size responsive. fn addRes(mut &x: bits, y: bits) { - mut carry := bit(0) - match { - | len(y) == 1: - carry = addOne(x) - | len(x) == len(y): - carry = addFast(x, y) - | len(x) > len(y): - carry = addRfast(x, y) - |: - x, carry = add(y, x) - } - if carry == 0b1 { - x = append(x, 0b1) - } + mut carry := bit(0) + match { + | len(y) == 1: + carry = addOne(x) + | len(x) == len(y): + carry = addFast(x, y) + | len(x) > len(y): + carry = addRfast(x, y) + |: + x, carry = add(y, x) + } + if carry == 0b1 { + x = append(x, 0b1) + } } // Subtract bits with size responsive. fn subRes(mut &x: bits, y: bits) { - mut carry := bit(0) - match { - | len(y) == 1: - twosComplement(x) - carry = addOne(x) - | len(x) == len(y): - twosComplement(x) - carry = addFast(x, y) - | len(x) > len(y): - twosComplement(x) - carry = addRfast(x, y) - |: - mut xn := make(bits, len(y)) - _ = copy(xn, x) - x = xn - twosComplement(x) - carry = addFast(x, y) - } - if carry == 0b0 { - twosComplement(x) - } + mut carry := bit(0) + match { + | len(y) == 1: + twosComplement(x) + carry = addOne(x) + | len(x) == len(y): + twosComplement(x) + carry = addFast(x, y) + | len(x) > len(y): + twosComplement(x) + carry = addRfast(x, y) + |: + mut xn := make(bits, len(y)) + _ = copy(xn, x) + x = xn + twosComplement(x) + carry = addFast(x, y) + } + if carry == 0b0 { + twosComplement(x) + } } // Bitwise or. // a's bitsize should be have same or greather than b's bitsize. fn or(mut &a: bits, &b: bits) { - for i in b { - a[i] |= b[i] - } + for i in b { + a[i] |= b[i] + } } // Bitwise xor. // a's bitsize should be have same or greather than b's bitsize. fn xor(mut &a: bits, &b: bits) { - for i in b { - a[i] ^= b[i] - } + for i in b { + a[i] ^= b[i] + } } // Bitwise and. // a's bitsize should be have same or greather than b's bitsize. fn and(mut &a: bits, &b: bits) { - for i in b { - a[i] &= b[i] - } - // Clean trailing bits. - if len(a) > len(b) { - mut trail := a[len(b):] - for i in trail { - trail[i] = 0b0 - } - } + for i in b { + a[i] &= b[i] + } + // Clean trailing bits. + if len(a) > len(b) { + mut trail := a[len(b):] + for i in trail { + trail[i] = 0b0 + } + } } // Update bits by 1's complement. fn onesComplement(mut &b: bits) { - for i, x in b { - b[i] = ^x & 0b1 - } + for i, x in b { + b[i] = ^x & 0b1 + } } // Update bits by 2's complement. fn twosComplement(mut &b: bits) { - onesComplement(b) - _ = addOne(b) + onesComplement(b) + _ = addOne(b) } // Addition operation on operand bits. @@ -148,12 +148,12 @@ fn twosComplement(mut &b: bits) { // Does not allocates new bits for result, updates elements of x. // x and y should be have same bitsize. fn addFast(mut &x: bits, &y: bits): (carry: bit) { - for i, xbit in x { - ybit := y[i] - x[i] = xbit ^ ybit ^ carry - carry = (xbit & ybit) | (xbit & carry) | (ybit & carry) - } - ret + for i, xbit in x { + ybit := y[i] + x[i] = xbit ^ ybit ^ carry + carry = (xbit & ybit) | (xbit & carry) | (ybit & carry) + } + ret } // Addition operation on operand bits. @@ -162,15 +162,15 @@ fn addFast(mut &x: bits, &y: bits): (carry: bit) { // Does not allocates new bits for result, updates elements of x. // y implies imaginary zero-bits for missing part if y.bit-size < x.bit-size. fn addRfast(mut &x: bits, &y: bits): (carry: bit) { - for i, xbit in x { - mut ybit := bit(0b0) - if i < len(y) { - ybit = y[i] - } - x[i] = xbit ^ ybit ^ carry - carry = (xbit & ybit) | (xbit & carry) | (ybit & carry) - } - ret + for i, xbit in x { + mut ybit := bit(0b0) + if i < len(y) { + ybit = y[i] + } + x[i] = xbit ^ ybit ^ carry + carry = (xbit & ybit) | (xbit & carry) | (ybit & carry) + } + ret } // Addition operation on operand bits. @@ -178,27 +178,27 @@ fn addRfast(mut &x: bits, &y: bits): (carry: bit) { // Carry is guaranteed to be 0b0 or 0b1. // y implies imaginary zero-bits for missing part if y.bit-size < x.bit-size. fn add(&x: bits, &y: bits): (r: bits, carry: bit) { - r = make(bits, 0, len(x)) - for i, xbit in x { - mut ybit := bit(0b0) - if i < len(y) { - ybit = y[i] - } - r = append(r, xbit ^ ybit ^ carry) - carry = (xbit & ybit) | (xbit & carry) | (ybit & carry) - } - ret + r = make(bits, 0, len(x)) + for i, xbit in x { + mut ybit := bit(0b0) + if i < len(y) { + ybit = y[i] + } + r = append(r, xbit ^ ybit ^ carry) + carry = (xbit & ybit) | (xbit & carry) | (ybit & carry) + } + ret } // Returns length of bits without trailing-zeros, normalizes bits. fn fitLen(mut &b: bits): int { - mut i := len(b) - 1 - for i >= 0; i-- { - if b[i] != 0b0 { - break - } - } - ret i+1 + mut i := len(b) - 1 + for i >= 0; i-- { + if b[i] != 0b0 { + break + } + } + ret i + 1 } // Eliminates trailing-zeros, normalizes bits. @@ -209,100 +209,100 @@ fn fit(mut &b: bits) { b = b[:fitLen(b)] } // Returns 0 if x == y. // Returns -1 if x < y. fn cmp(x: bits, &y: bits): int { - match { - | len(x) < len(y): - ret -1 - | len(x) > len(y): - ret +1 - } - mut i := len(x) - 1 - for i >= 0; i-- { - xbit := x[i] - ybit := y[i] - match { - | xbit > ybit: - ret +1 - | xbit < ybit: - ret -1 - } - } - ret 0 + match { + | len(x) < len(y): + ret -1 + | len(x) > len(y): + ret +1 + } + mut i := len(x) - 1 + for i >= 0; i-- { + xbit := x[i] + ybit := y[i] + match { + | xbit > ybit: + ret +1 + | xbit < ybit: + ret -1 + } + } + ret 0 } // Same as cmp, but designed for normal order bits. fn cmpRev(mut &x: bits, mut &y: bits): int { - match { - | len(x) < len(y): - ret -1 - | len(x) > len(y): - ret +1 - } - for i in x { - xbit := x[i] - ybit := y[i] - match { - | xbit > ybit: - ret +1 - | xbit < ybit: - ret -1 - } - } - ret 0 + match { + | len(x) < len(y): + ret -1 + | len(x) > len(y): + ret +1 + } + for i in x { + xbit := x[i] + ybit := y[i] + match { + | xbit > ybit: + ret +1 + | xbit < ybit: + ret -1 + } + } + ret 0 } // Reports whether number is odd that represented by bits. fn isOdd(&b: bits): bool { - ret len(b) > 0 && b[0] == 0b1 + ret len(b) > 0 && b[0] == 0b1 } // Reports whether number is even that represented by bits. fn isEven(&b: bits): bool { - ret len(b) > 0 && b[0] == 0b0 + ret len(b) > 0 && b[0] == 0b0 } // Basic multiplication algorithm for bits. fn basicMul(mut &x: bits, mut y: bits): bits { - if len(x) == 0 || len(y) == 0 { - ret nil - } - match 1 { - | len(x): - ret y - | len(y): - ret x - } - let mut r: bits = nil - mut m := make(bits, len(x), len(x) << 1) - _ = copy(m, x) - for len(y) > 0 { - if isOdd(y) { - addRes(r, m) - } - m = append(m[:1], m...) - m[0] = 0b0 - y = y[1:] - } - ret r + if len(x) == 0 || len(y) == 0 { + ret nil + } + match 1 { + | len(x): + ret y + | len(y): + ret x + } + let mut r: bits = nil + mut m := make(bits, len(x), len(x) << 1) + _ = copy(m, x) + for len(y) > 0 { + if isOdd(y) { + addRes(r, m) + } + m = append(m[:1], m...) + m[0] = 0b0 + y = y[1:] + } + ret r } fn cloneBits(x: bits): bits { - ret append(make(bits, 0, len(x)), x...) + ret append(make(bits, 0, len(x)), x...) } fn lsh(mut x: bits, y: int): bits { - if y > 0 && len(x) > 0 { - mut x2 := make(bits, len(x) + y) - _ = copy(x2[y:], x) - ret x2 - } - ret x + if y > 0 && len(x) > 0 { + mut x2 := make(bits, len(x) + y) + _ = copy(x2[y:], x) + ret x2 + } + ret x } fn rsh(mut x: bits, y: int): bits { - if y > len(x) { - ret nil - } - ret x[y:] + if y > len(x) { + ret nil + } + ret x[y:] } // This threshold is represents number of bits small numbers for karatsuba algorithm. @@ -310,29 +310,29 @@ fn rsh(mut x: bits, y: int): bits { const karatsubaThreshold = (1 << 5) + (1 << 4) fn karatsuba(mut x: bits, mut y: bits): bits { - fit(x) - fit(y) - if len(x) < karatsubaThreshold || len(y) < karatsubaThreshold { - ret basicMul(x, y) - } - m := max(len(x), len(y)) >> 1 - mut x1 := cloneBits(rsh(x, m)) - mut x0 := cloneBits(x) - subRes(x0, lsh(x1, m)) - mut y1 := cloneBits(rsh(y, m)) - mut y0 := cloneBits(y) - subRes(y0, lsh(y1, m)) - mut z2 := karatsuba(x1, y1) - mut z0 := karatsuba(x0, y0) - addRes(x1, x0) - addRes(y1, y0) - mut z1 := karatsuba(x1, y1) - subRes(z1, z2) - subRes(z1, z0) - mut r := lsh(z2, m << 1) - addRes(r, lsh(z1, m)) - addRes(r, z0) - ret r + fit(x) + fit(y) + if len(x) < karatsubaThreshold || len(y) < karatsubaThreshold { + ret basicMul(x, y) + } + m := max(len(x), len(y)) >> 1 + mut x1 := cloneBits(rsh(x, m)) + mut x0 := cloneBits(x) + subRes(x0, lsh(x1, m)) + mut y1 := cloneBits(rsh(y, m)) + mut y0 := cloneBits(y) + subRes(y0, lsh(y1, m)) + mut z2 := karatsuba(x1, y1) + mut z0 := karatsuba(x0, y0) + addRes(x1, x0) + addRes(y1, y0) + mut z1 := karatsuba(x1, y1) + subRes(z1, z2) + subRes(z1, z0) + mut r := lsh(z2, m << 1) + addRes(r, lsh(z1, m)) + addRes(r, z0) + ret r } // Recursion division algorithm. It will update left operand if necessary. @@ -427,29 +427,29 @@ fn karatsuba(mut x: bits, mut y: bits): bits { // 83976027694 // fn recursiveDiv(mut &x: bits, mut &y: bits, mut &s: bits, mut &q: bits) { - match cmp(x, y) { - | -1: - ret - | 0: - addOne(s) - ret - } - for cmp(q, x) == +1 { - q = q[1:] - } - if len(q) == len(y) { - addOne(s) - ret - } - subRes(x, q) - fit(x) - mut sq := q[:len(q)-len(y)+1] - mut &last := unsafe { *(&sq[len(sq)-1]) } - old := last - last = 0b1 - addRfast(s, sq) - last = old - recursiveDiv(x, y, s, q) + match cmp(x, y) { + | -1: + ret + | 0: + addOne(s) + ret + } + for cmp(q, x) == +1 { + q = q[1:] + } + if len(q) == len(y) { + addOne(s) + ret + } + subRes(x, q) + fit(x) + mut sq := q[:len(q)-len(y)+1] + mut &last := unsafe { *(&sq[len(sq)-1]) } + old := last + last = 0b1 + addRfast(s, sq) + last = old + recursiveDiv(x, y, s, q) } // Recursion modulo algorithm. It will update left operand if necessary. @@ -541,16 +541,16 @@ fn recursiveDiv(mut &x: bits, mut &y: bits, mut &s: bits, mut &q: bits) { // 55 = remainder, x < y // fn recursiveMod(mut &x: bits, &y: bits, mut &q: bits): bits { - match cmp(x, y) { - | 0: - ret nil - | -1: - ret x - } - for cmp(q, x) == +1 { - q = q[1:] - } - subRes(x, q) - fit(x) - ret recursiveMod(x, y, q) + match cmp(x, y) { + | 0: + ret nil + | -1: + ret x + } + for cmp(q, x) == +1 { + q = q[1:] + } + subRes(x, q) + fit(x) + ret recursiveMod(x, y, q) } \ No newline at end of file diff --git a/std/math/big/bits_test.jule b/std/math/big/bits_test.jule index ec2ec86ee..64f7798f4 100644 --- a/std/math/big/bits_test.jule +++ b/std/math/big/bits_test.jule @@ -7,31 +7,31 @@ use std::testing::{T} static casesTwosComplement: [][]bits = [ - [[0, 1, 0, 1, 1, 0, 1], [0, 1, 1, 0, 0, 1, 0]], - [[1, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1]], - [[1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0], [1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1]], - [[0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], [0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1]], - [[1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0], [1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1]], - [[0, 1, 0, 1, 0], [0, 1, 1, 0, 1]], - [[0, 0, 0, 1, 1, 0], [0, 0, 0, 1, 0, 1]], + [[0, 1, 0, 1, 1, 0, 1], [0, 1, 1, 0, 0, 1, 0]], + [[1, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1]], + [[1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0], [1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1]], + [[0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], [0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1]], + [[1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0], [1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1]], + [[0, 1, 0, 1, 0], [0, 1, 1, 0, 1]], + [[0, 0, 0, 1, 1, 0], [0, 0, 0, 1, 0, 1]], ] #test fn testU64FromBits(t: &T) { - t.Assert(u64FromBits([0, 1, 0, 1, 1, 0, 1]) == 90, "1) 1011010 != 90") - t.Assert(u64FromBits([0, 0, 0, 1, 1, 0, 1, 1, 1, 1]) == 984, "2) 1111011000 != 984") - t.Assert(u64FromBits([1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1]) == 9739573948397, "3) 10001101101110101011110110000110111111101101 != 9739573948397") - t.Assert(u64FromBits([0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1]) == 8984, "4) 10001100011000 != 8984") + t.Assert(u64FromBits([0, 1, 0, 1, 1, 0, 1]) == 90, "1) 1011010 != 90") + t.Assert(u64FromBits([0, 0, 0, 1, 1, 0, 1, 1, 1, 1]) == 984, "2) 1111011000 != 984") + t.Assert(u64FromBits([1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1]) == 9739573948397, "3) 10001101101110101011110110000110111111101101 != 9739573948397") + t.Assert(u64FromBits([0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1]) == 8984, "4) 10001100011000 != 8984") } #test fn testTwosComplement(t: &T) { - for _, case in casesTwosComplement { - mut x := cloneBits(case[0]) - y := case[1] - twosComplement(x) - if cmp(x, y) != 0 { - t.Errorf("{} != {}", case[0], y) - } - } + for _, case in casesTwosComplement { + mut x := cloneBits(case[0]) + y := case[1] + twosComplement(x) + if cmp(x, y) != 0 { + t.Errorf("{} != {}", case[0], y) + } + } } \ No newline at end of file diff --git a/std/math/big/conv.jule b/std/math/big/conv.jule index d980d651e..f564a2097 100644 --- a/std/math/big/conv.jule +++ b/std/math/big/conv.jule @@ -6,302 +6,302 @@ use std::unsafe // Parse bits from binary string. fn parseBinary(&s: str)!: bits { - // Eliminate initial-zeros to normalize and fit minimum mandatory bit-size. - mut j := 0 - for j < len(s); j++ { - if s[j] != '0' { - break - } - } - if len(s) == j { - // All bits are zero. - ret nil - } - mut r := make(bits, 0, len(s) - j) - mut k := len(s) - 1 - for k >= j; k-- { - match s[k] { - | '1': - r = append(r, 0b1) - | '0': - r = append(r, 0b0) - |: - error(BigError.Format) - } - } - ret r + // Eliminate initial-zeros to normalize and fit minimum mandatory bit-size. + mut j := 0 + for j < len(s); j++ { + if s[j] != '0' { + break + } + } + if len(s) == j { + // All bits are zero. + ret nil + } + mut r := make(bits, 0, len(s) - j) + mut k := len(s) - 1 + for k >= j; k-- { + match s[k] { + | '1': + r = append(r, 0b1) + | '0': + r = append(r, 0b0) + |: + error(BigError.Format) + } + } + ret r } // Parse bits from hexadecimal string. // Returns normalized bits. fn parseHex(&s: str)!: bits { - mut buf := make(bits, 0, len(s) * 4) - mut i := len(s) - 1 - for i >= 0; i-- { - h := s[i] - match h { - | '0': - buf = append(buf, 0b0, 0b0, 0b0, 0b0) - | '1': - buf = append(buf, 0b1, 0b0, 0b0, 0b0) - | '2': - buf = append(buf, 0b0, 0b1, 0b0, 0b0) - | '3': - buf = append(buf, 0b1, 0b1, 0b0, 0b0) - | '4': - buf = append(buf, 0b0, 0b0, 0b1, 0b0) - | '5': - buf = append(buf, 0b1, 0b0, 0b1, 0b0) - | '6': - buf = append(buf, 0b0, 0b1, 0b1, 0b0) - | '7': - buf = append(buf, 0b1, 0b1, 0b1, 0b0) - | '8': - buf = append(buf, 0b0, 0b0, 0b0, 0b1) - | '9': - buf = append(buf, 0b1, 0b0, 0b0, 0b1) - | 'A': - buf = append(buf, 0b0, 0b1, 0b0, 0b1) - | 'B': - buf = append(buf, 0b1, 0b1, 0b0, 0b1) - | 'C': - buf = append(buf, 0b0, 0b0, 0b1, 0b1) - | 'D': - buf = append(buf, 0b1, 0b0, 0b1, 0b1) - | 'E': - buf = append(buf, 0b0, 0b1, 0b1, 0b1) - | 'F': - buf = append(buf, 0b1, 0b1, 0b1, 0b1) - |: - error(BigError.Format) - } - } - fit(buf) - ret buf + mut buf := make(bits, 0, len(s) * 4) + mut i := len(s) - 1 + for i >= 0; i-- { + h := s[i] + match h { + | '0': + buf = append(buf, 0b0, 0b0, 0b0, 0b0) + | '1': + buf = append(buf, 0b1, 0b0, 0b0, 0b0) + | '2': + buf = append(buf, 0b0, 0b1, 0b0, 0b0) + | '3': + buf = append(buf, 0b1, 0b1, 0b0, 0b0) + | '4': + buf = append(buf, 0b0, 0b0, 0b1, 0b0) + | '5': + buf = append(buf, 0b1, 0b0, 0b1, 0b0) + | '6': + buf = append(buf, 0b0, 0b1, 0b1, 0b0) + | '7': + buf = append(buf, 0b1, 0b1, 0b1, 0b0) + | '8': + buf = append(buf, 0b0, 0b0, 0b0, 0b1) + | '9': + buf = append(buf, 0b1, 0b0, 0b0, 0b1) + | 'A': + buf = append(buf, 0b0, 0b1, 0b0, 0b1) + | 'B': + buf = append(buf, 0b1, 0b1, 0b0, 0b1) + | 'C': + buf = append(buf, 0b0, 0b0, 0b1, 0b1) + | 'D': + buf = append(buf, 0b1, 0b0, 0b1, 0b1) + | 'E': + buf = append(buf, 0b0, 0b1, 0b1, 0b1) + | 'F': + buf = append(buf, 0b1, 0b1, 0b1, 0b1) + |: + error(BigError.Format) + } + } + fit(buf) + ret buf } // Parse bits from octal string. // Returns normalized bits. fn parseOctal(&s: str)!: bits { - mut buf := make(bits, 0, len(s) * 3) - mut i := len(s) - 1 - for i >= 0; i-- { - match s[i] { - | '0': - buf = append(buf, 0b0, 0b0, 0b0) - | '1': - buf = append(buf, 0b1, 0b0, 0b0) - | '2': - buf = append(buf, 0b0, 0b1, 0b0) - | '3': - buf = append(buf, 0b1, 0b1, 0b0) - | '4': - buf = append(buf, 0b0, 0b0, 0b1) - | '5': - buf = append(buf, 0b1, 0b0, 0b1) - | '6': - buf = append(buf, 0b0, 0b1, 0b1) - | '7': - buf = append(buf, 0b1, 0b1, 0b1) - |: - error(BigError.Format) - } - } - fit(buf) - ret buf + mut buf := make(bits, 0, len(s) * 3) + mut i := len(s) - 1 + for i >= 0; i-- { + match s[i] { + | '0': + buf = append(buf, 0b0, 0b0, 0b0) + | '1': + buf = append(buf, 0b1, 0b0, 0b0) + | '2': + buf = append(buf, 0b0, 0b1, 0b0) + | '3': + buf = append(buf, 0b1, 0b1, 0b0) + | '4': + buf = append(buf, 0b0, 0b0, 0b1) + | '5': + buf = append(buf, 0b1, 0b0, 0b1) + | '6': + buf = append(buf, 0b0, 0b1, 0b1) + | '7': + buf = append(buf, 0b1, 0b1, 0b1) + |: + error(BigError.Format) + } + } + fit(buf) + ret buf } fn parseDecimal(&s: str)!: []byte { - mut sb := []byte(s) - for _, b in sb { - if b < '0' || '9' < b { - error(BigError.Format) - } - } - mut buf := make([]byte, 0, len(s) * 4) + mut sb := []byte(s) + for _, b in sb { + if b < '0' || '9' < b { + error(BigError.Format) + } + } + mut buf := make([]byte, 0, len(s) * 4) loop: - for { - d := sb[len(sb)-1] - '0' - buf = append(buf, d % 2) - mut carry := byte(0) - for i in sb { - t := carry * 10 + (sb[i] - '0') - sb[i] = '0' + (t >> 1) - carry = t & 0b1 - } - for i in sb { - if sb[i] != '0' { - sb = sb[i:] - continue loop - } - } - break - } - fit(buf) - ret buf + for { + d := sb[len(sb)-1] - '0' + buf = append(buf, d % 2) + mut carry := byte(0) + for i in sb { + t := carry * 10 + (sb[i] - '0') + sb[i] = '0' + (t >> 1) + carry = t & 0b1 + } + for i in sb { + if sb[i] != '0' { + sb = sb[i:] + continue loop + } + } + break + } + fit(buf) + ret buf } fn formatBinary(&b: bits): str { - if len(b) == 0 { - ret "0" - } - mut buf := make([]byte, len(b) + 1) - for i in b { - buf[i] = '0' + b[len(b)-i-1] - } - ret unsafe::StrFromBytes(buf[:len(buf)-1]) + if len(b) == 0 { + ret "0" + } + mut buf := make([]byte, len(b) + 1) + for i in b { + buf[i] = '0' + b[len(b)-i-1] + } + ret unsafe::StrFromBytes(buf[:len(buf)-1]) } fn appendNullTermination(mut &buf: []byte) { - if buf[len(buf)-1] != 0 { - buf = append(buf, 0) - } + if buf[len(buf)-1] != 0 { + buf = append(buf, 0) + } } fn formatDecimalPart(mut &buf: []byte, m: byte) { - mut carry := ^m & 0b1 - n := len(buf) - for in buf { - digit := buf[n-1] - '0' - value := (digit << m) + carry - buf = append(buf[:1], buf...) - buf[0] = '0' + (value % 10) - carry = value / 10 - } - buf = buf[:n] - if carry > 0 { - buf = append(buf[:1], buf...) - buf[0] = '0' + carry - } + mut carry := ^m & 0b1 + n := len(buf) + for in buf { + digit := buf[n-1] - '0' + value := (digit << m) + carry + buf = append(buf[:1], buf...) + buf[0] = '0' + (value % 10) + carry = value / 10 + } + buf = buf[:n] + if carry > 0 { + buf = append(buf[:1], buf...) + buf[0] = '0' + carry + } } fn formatDecimal(&b: bits): str { - mut buf := make([]byte, 1, len(b) >> 1 + 1) - buf[0] = '0' - for _, bit in formatBinary(b) { - formatDecimalPart(buf, 1) - if bit == '1' { - formatDecimalPart(buf, 0) - } - } - appendNullTermination(buf) - ret unsafe::StrFromBytes(buf[:len(buf)-1]) + mut buf := make([]byte, 1, len(b) >> 1 + 1) + buf[0] = '0' + for _, bit in formatBinary(b) { + formatDecimalPart(buf, 1) + if bit == '1' { + formatDecimalPart(buf, 0) + } + } + appendNullTermination(buf) + ret unsafe::StrFromBytes(buf[:len(buf)-1]) } fn formatOctal(&b: bits): str { - n := len(b) - len(b) % 3 - mut buf := make([]byte, 1, len(b) / 3 + 1) - mut i := 0 - for i < n; i += 3 { - buf = append(buf[:1], buf...) - c := b[i:i+3] - match { - | c[0] == 0b0 && c[1] == 0b0 && c[2] == 0b0: - buf[0] = '0' - | c[0] == 0b1 && c[1] == 0b0 && c[2] == 0b0: - buf[0] = '1' - | c[0] == 0b0 && c[1] == 0b1 && c[2] == 0b0: - buf[0] = '2' - | c[0] == 0b1 && c[1] == 0b1 && c[2] == 0b0: - buf[0] = '3' - | c[0] == 0b0 && c[1] == 0b0 && c[2] == 0b1: - buf[0] = '4' - | c[0] == 0b1 && c[1] == 0b0 && c[2] == 0b1: - buf[0] = '5' - | c[0] == 0b0 && c[1] == 0b1 && c[2] == 0b1: - buf[0] = '6' - | c[0] == 0b1 && c[1] == 0b1 && c[2] == 0b1: - buf[0] = '7' - } - } - c := b[n:] - match len(c) { - | 1: - buf = append(buf[:1], buf...) - buf[0] = '1' - | 2: - buf = append(buf[:1], buf...) - match { - | c[0] == 0b1 && c[1] == 0b0: - buf[0] = '1' - | c[0] == 0b0 && c[1] == 0b1: - buf[0] = '2' - | c[0] == 0b1 && c[1] == 0b1: - buf[0] = '3' - } - } - buf[len(buf)-1] = 0 - ret unsafe::StrFromBytes(buf[:len(buf)-1]) + n := len(b) - len(b) % 3 + mut buf := make([]byte, 1, len(b) / 3 + 1) + mut i := 0 + for i < n; i += 3 { + buf = append(buf[:1], buf...) + c := b[i:i+3] + match { + | c[0] == 0b0 && c[1] == 0b0 && c[2] == 0b0: + buf[0] = '0' + | c[0] == 0b1 && c[1] == 0b0 && c[2] == 0b0: + buf[0] = '1' + | c[0] == 0b0 && c[1] == 0b1 && c[2] == 0b0: + buf[0] = '2' + | c[0] == 0b1 && c[1] == 0b1 && c[2] == 0b0: + buf[0] = '3' + | c[0] == 0b0 && c[1] == 0b0 && c[2] == 0b1: + buf[0] = '4' + | c[0] == 0b1 && c[1] == 0b0 && c[2] == 0b1: + buf[0] = '5' + | c[0] == 0b0 && c[1] == 0b1 && c[2] == 0b1: + buf[0] = '6' + | c[0] == 0b1 && c[1] == 0b1 && c[2] == 0b1: + buf[0] = '7' + } + } + c := b[n:] + match len(c) { + | 1: + buf = append(buf[:1], buf...) + buf[0] = '1' + | 2: + buf = append(buf[:1], buf...) + match { + | c[0] == 0b1 && c[1] == 0b0: + buf[0] = '1' + | c[0] == 0b0 && c[1] == 0b1: + buf[0] = '2' + | c[0] == 0b1 && c[1] == 0b1: + buf[0] = '3' + } + } + buf[len(buf)-1] = 0 + ret unsafe::StrFromBytes(buf[:len(buf)-1]) } fn formatHex(&b: bits): str { - n := len(b) - len(b) % 4 - mut buf := make([]byte, 1, len(b) >> 2 + 1) - mut i := 0 - for i < n; i += 4 { - buf = append(buf[:1], buf...) - c := b[i:i+4] - match { - | c[0] == 0b0 && c[1] == 0b0 && c[2] == 0b0 && c[3] == 0b0: - buf[0] = '0' - | c[0] == 0b1 && c[1] == 0b0 && c[2] == 0b0 && c[3] == 0b0: - buf[0] = '1' - | c[0] == 0b0 && c[1] == 0b1 && c[2] == 0b0 && c[3] == 0b0: - buf[0] = '2' - | c[0] == 0b1 && c[1] == 0b1 && c[2] == 0b0 && c[3] == 0b0: - buf[0] = '3' - | c[0] == 0b0 && c[1] == 0b0 && c[2] == 0b1 && c[3] == 0b0: - buf[0] = '4' - | c[0] == 0b1 && c[1] == 0b0 && c[2] == 0b1 && c[3] == 0b0: - buf[0] = '5' - | c[0] == 0b0 && c[1] == 0b1 && c[2] == 0b1 && c[3] == 0b0: - buf[0] = '6' - | c[0] == 0b1 && c[1] == 0b1 && c[2] == 0b1 && c[3] == 0b0: - buf[0] = '7' - | c[0] == 0b0 && c[1] == 0b0 && c[2] == 0b0 && c[3] == 0b1: - buf[0] = '8' - | c[0] == 0b1 && c[1] == 0b0 && c[2] == 0b0 && c[3] == 0b1: - buf[0] = '9' - | c[0] == 0b0 && c[1] == 0b1 && c[2] == 0b0 && c[3] == 0b1: - buf[0] = 'A' - | c[0] == 0b1 && c[1] == 0b1 && c[2] == 0b0 && c[3] == 0b1: - buf[0] = 'B' - | c[0] == 0b0 && c[1] == 0b0 && c[2] == 0b1 && c[3] == 0b1: - buf[0] = 'C' - | c[0] == 0b1 && c[1] == 0b0 && c[2] == 0b1 && c[3] == 0b1: - buf[0] = 'D' - | c[0] == 0b0 && c[1] == 0b1 && c[2] == 0b1 && c[3] == 0b1: - buf[0] = 'E' - | c[0] == 0b1 && c[1] == 0b1 && c[2] == 0b1 && c[3] == 0b1: - buf[0] = 'F' - } - } - c := b[n:] - match len(c) { - | 1: - buf = append(buf[:1], buf...) - buf[0] = '1' - | 2: - buf = append(buf[:1], buf...) - match { - | c[0] == 0b0 && c[1] == 0b1: - buf[0] = '2' - | c[0] == 0b1 && c[1] == 0b1: - buf[0] = '3' - } - | 3: - buf = append(buf[:1], buf...) - match { - | c[0] == 0b0 && c[1] == 0b0 && c[2] == 0b1: - buf[0] = '4' - | c[0] == 0b1 && c[1] == 0b0 && c[2] == 0b1: - buf[0] = '5' - | c[0] == 0b0 && c[1] == 0b1 && c[2] == 0b1: - buf[0] = '6' - | c[0] == 0b1 && c[1] == 0b1 && c[2] == 0b1: - buf[0] = '7' - } - } - buf[len(buf)-1] = 0 - ret unsafe::StrFromBytes(buf[:len(buf)-1]) + n := len(b) - len(b) % 4 + mut buf := make([]byte, 1, len(b) >> 2 + 1) + mut i := 0 + for i < n; i += 4 { + buf = append(buf[:1], buf...) + c := b[i:i+4] + match { + | c[0] == 0b0 && c[1] == 0b0 && c[2] == 0b0 && c[3] == 0b0: + buf[0] = '0' + | c[0] == 0b1 && c[1] == 0b0 && c[2] == 0b0 && c[3] == 0b0: + buf[0] = '1' + | c[0] == 0b0 && c[1] == 0b1 && c[2] == 0b0 && c[3] == 0b0: + buf[0] = '2' + | c[0] == 0b1 && c[1] == 0b1 && c[2] == 0b0 && c[3] == 0b0: + buf[0] = '3' + | c[0] == 0b0 && c[1] == 0b0 && c[2] == 0b1 && c[3] == 0b0: + buf[0] = '4' + | c[0] == 0b1 && c[1] == 0b0 && c[2] == 0b1 && c[3] == 0b0: + buf[0] = '5' + | c[0] == 0b0 && c[1] == 0b1 && c[2] == 0b1 && c[3] == 0b0: + buf[0] = '6' + | c[0] == 0b1 && c[1] == 0b1 && c[2] == 0b1 && c[3] == 0b0: + buf[0] = '7' + | c[0] == 0b0 && c[1] == 0b0 && c[2] == 0b0 && c[3] == 0b1: + buf[0] = '8' + | c[0] == 0b1 && c[1] == 0b0 && c[2] == 0b0 && c[3] == 0b1: + buf[0] = '9' + | c[0] == 0b0 && c[1] == 0b1 && c[2] == 0b0 && c[3] == 0b1: + buf[0] = 'A' + | c[0] == 0b1 && c[1] == 0b1 && c[2] == 0b0 && c[3] == 0b1: + buf[0] = 'B' + | c[0] == 0b0 && c[1] == 0b0 && c[2] == 0b1 && c[3] == 0b1: + buf[0] = 'C' + | c[0] == 0b1 && c[1] == 0b0 && c[2] == 0b1 && c[3] == 0b1: + buf[0] = 'D' + | c[0] == 0b0 && c[1] == 0b1 && c[2] == 0b1 && c[3] == 0b1: + buf[0] = 'E' + | c[0] == 0b1 && c[1] == 0b1 && c[2] == 0b1 && c[3] == 0b1: + buf[0] = 'F' + } + } + c := b[n:] + match len(c) { + | 1: + buf = append(buf[:1], buf...) + buf[0] = '1' + | 2: + buf = append(buf[:1], buf...) + match { + | c[0] == 0b0 && c[1] == 0b1: + buf[0] = '2' + | c[0] == 0b1 && c[1] == 0b1: + buf[0] = '3' + } + | 3: + buf = append(buf[:1], buf...) + match { + | c[0] == 0b0 && c[1] == 0b0 && c[2] == 0b1: + buf[0] = '4' + | c[0] == 0b1 && c[1] == 0b0 && c[2] == 0b1: + buf[0] = '5' + | c[0] == 0b0 && c[1] == 0b1 && c[2] == 0b1: + buf[0] = '6' + | c[0] == 0b1 && c[1] == 0b1 && c[2] == 0b1: + buf[0] = '7' + } + } + buf[len(buf)-1] = 0 + ret unsafe::StrFromBytes(buf[:len(buf)-1]) } \ No newline at end of file diff --git a/std/math/big/conv_test.jule b/std/math/big/conv_test.jule index b17480483..df9a2cac6 100644 --- a/std/math/big/conv_test.jule +++ b/std/math/big/conv_test.jule @@ -7,65 +7,65 @@ use std::testing::{T} static casesParseHex = [ - [[]byte("0"), []], - [[]byte("A"), [0, 1, 0, 1]], - [[]byte("4A89BCE902F"), [1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1]], - [[]byte("564FF"), [1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1]], - [[]byte("564FFFFFAD89"), [1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1]], + [[]byte("0"), []], + [[]byte("A"), [0, 1, 0, 1]], + [[]byte("4A89BCE902F"), [1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1]], + [[]byte("564FF"), [1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1]], + [[]byte("564FFFFFAD89"), [1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1]], ] static casesParseOctal = [ - [[]byte("0"), []], - [[]byte("000"), []], - [[]byte("001"), [1]], - [[]byte("563"), [1, 1, 0, 0, 1, 1, 1, 0, 1]], - [[]byte("01234567"), [1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1]], - [[]byte("76543210"), [0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1]], - [[]byte("56323242425551121325623237"), [1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1]], + [[]byte("0"), []], + [[]byte("000"), []], + [[]byte("001"), [1]], + [[]byte("563"), [1, 1, 0, 0, 1, 1, 1, 0, 1]], + [[]byte("01234567"), [1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1]], + [[]byte("76543210"), [0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1]], + [[]byte("56323242425551121325623237"), [1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1]], ] static casesParseDecimal = [ - [[]byte("0"), []], - [[]byte("00000"), []], - [[]byte("010"), [0, 1, 0, 1]], - [[]byte("011"), [1, 1, 0, 1]], - [[]byte("11101293"), [1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1]], - [[]byte("77738310"), [0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1]], - [[]byte("52386786278527310725769899"), [1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1]], + [[]byte("0"), []], + [[]byte("00000"), []], + [[]byte("010"), [0, 1, 0, 1]], + [[]byte("011"), [1, 1, 0, 1]], + [[]byte("11101293"), [1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1]], + [[]byte("77738310"), [0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1]], + [[]byte("52386786278527310725769899"), [1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1]], ] #test fn testParseHex(t: &T) { - for _, c in casesParseHex { - c0 := str(c[0]) - bits := parseHex(c0)! - c1 := c[1] - if cmp(bits, c1) != 0 { - t.Errorf("0x{} != 0b{}", c0, c1) - } - } + for _, c in casesParseHex { + c0 := str(c[0]) + bits := parseHex(c0)! + c1 := c[1] + if cmp(bits, c1) != 0 { + t.Errorf("0x{} != 0b{}", c0, c1) + } + } } #test fn testParseOctal(t: &T) { - for _, c in casesParseOctal { - c0 := str(c[0]) - bits := parseOctal(c0)! - c1 := c[1] - if cmp(bits, c1) != 0 { - t.Errorf("0{} != 0b{}", c0, c1) - } - } + for _, c in casesParseOctal { + c0 := str(c[0]) + bits := parseOctal(c0)! + c1 := c[1] + if cmp(bits, c1) != 0 { + t.Errorf("0{} != 0b{}", c0, c1) + } + } } #test fn testParseDecimal(t: &T) { - for _, c in casesParseDecimal { - c0 := str(c[0]) - bits := parseDecimal(c0)! - c1 := c[1] - if cmp(bits, c1) != 0 { - t.Errorf("{} != {}", str(c[0]), c1) - } - } + for _, c in casesParseDecimal { + c0 := str(c[0]) + bits := parseDecimal(c0)! + c1 := c[1] + if cmp(bits, c1) != 0 { + t.Errorf("{} != {}", str(c[0]), c1) + } + } } \ No newline at end of file diff --git a/std/math/big/error.jule b/std/math/big/error.jule index e7ed3949e..911f8ecb2 100644 --- a/std/math/big/error.jule +++ b/std/math/big/error.jule @@ -4,5 +4,5 @@ // Error codes for big number algorithms. enum BigError { - Format, + Format, } \ No newline at end of file diff --git a/std/math/big/int.jule b/std/math/big/int.jule index bc646bdfe..e1cf35a0b 100644 --- a/std/math/big/int.jule +++ b/std/math/big/int.jule @@ -5,499 +5,499 @@ // Big arbitrary-precision signed integer. // Always in the normalized format, leading-zeros are eliminated. struct Int { - minus: bool - mut nat: nat + minus: bool + mut nat: nat } impl Int { - // Returns big integer that represents zero. - static fn Zero(): Int { - ret Int{ - nat: nat.zero(), - } - } - - // Returns big integer that represents one. - static fn One(): Int { - ret Int{ - nat: nat.one(), - } - } - - // Returns big integer that initialized by integer value. - // T can only be signed or unsigned integer types. - static fn New[T: Int | i8 | i16 | i32 | i64 | u8 | u16 | u32 | u64 | int | uint](i: T): Int { - const match type T { - | Int: - ret i - | i8 | i16 | i32 | i64 | u8 | u16 | u32 | u64 | int | uint: - ret Int{ - minus: i < 0, - nat: nat.new[T](i), - } - |: - panic("std::math::big: Int.new[T]: unimplemented type, this panic call should be unreachable") - } - } - - // Parse big integer from string. Fmt is the format of string. - // Results with exceptional if bits are not in the format or empty. - // Results with exceptional if fmt is not valid. - // Exceptional is always BigError.Format. - // - // Valid fmt values are; - // - 2 for binary. - // - 8 for octal. - // - 10 for decimal. - // - 16 for hexadecimal. - static fn Parse(mut s: str, fmt: int)!: Int { - mut r := Int{} - if len(s) > 0 { - match s[0] { - | '-': - r.minus = true - s = s[1:] - | '+': - s = s[1:] - } - } - r.nat = nat.parse(s, fmt) else { error(error) } - r.minus = r.minus && r.nat.len() != 0 - ret r - } - - // Returns count of bits except sign-bit. - // Return value also means the minimum number of bits that can represent the integer. - fn Len(self): int { - ret self.nat.len() - } - - // Adds two Int and returns result. - fn Add(self, y: Int): Int { - mut r := self - r += y - ret r - } - - // Adds Int. - fn AddAssign(mut self, y: Int) { - match { - | y.Len() == 0: - ret - | self.minus == y.minus: - self.nat += y.nat - |: - mut cmp := self.nat.cmp(y.nat) - if cmp == 0 { - self.minus = false - self.nat = nat.zero() - ret - } - if y.minus { - cmp = -cmp - } - if self.minus && cmp == +1 || - y.minus && cmp == -1 { - self.nat -= y.nat - } else { - self.nat = y.nat - self.nat - } - self.minus = cmp == +1 - } - } - - // Subtracts two Int and returns result. - fn Sub(self, y: Int): Int { - mut r := self - r -= y - ret r - } - - // Subtracts Int. - fn SubAssign(mut self, y: Int) { - if y.Len() == 0 { - ret - } - mut cmp := self.Cmp(y) - if cmp == 0 { - self.minus = false - self.nat = nat.zero() - ret - } - if self.minus == y.minus { - self.minus = cmp == -1 - if cmp == +1 { - self.nat -= y.nat - } else { - self.nat = y.nat - self.nat - } - ret - } - self.minus = false - self.nat += y.nat - ret - } - - // Multiplies two Int and returns result. - fn Mul(self, y: Int): Int { - mut r := self - r *= y - ret r - } - - // Multiplies Int. - fn MulAssign(mut self, y: Int) { - self.nat *= y.nat - self.minus = self.Len() > 0 && self.minus != y.minus - } - - // Divides two Int and returns result. - fn Div(self, y: Int): Int { - mut r := self - r /= y - ret r - } - - // Divides Int. - fn DivAssign(mut self, y: Int) { - self.nat /= y.nat - if self.Len() == 0 { - self.minus = false - } else { - self.minus = self.minus != y.minus - } - } - - // Modulo two Int and returns result. - fn Mod(self, y: Int): Int { - mut r := self - r %= y - ret r - } - - // Modulo Int. - fn ModAssign(mut self, y: Int) { - if self.minus == y.minus { - self.nat %= y.nat - self.minus = self.Len() > 0 && y.minus - ret - } - self.nat %= y.nat - if self.Len() == 0 { - self.minus = false - ret - } - self.nat -= y.nat - self.minus = self.Len() > 0 && y.minus - } - - // Bitwise left shift. - fn Shl(self, y: int): Int { - mut r := self - r <<= y - ret r - } - - // Bitwise left shift for assignment. - fn ShlAssign(mut self, y: int) { - self.nat <<= y - } - - // Bitwise right shift. - fn Shr(self, y: int): Int { - mut r := self - r >>= y - ret r - } - - // Bitwise right shift for assignment. - fn ShrAssign(mut self, y: int) { - self.nat >>= y - self.minus = self.minus && self.Len() > 0 - } - - // Bitwise or. - fn BitOr(self, y: Int): Int { - mut r := self - r |= y - ret r - } - - // Bitwise or for assignment. - fn BitOrAssign(mut self, y: Int) { - if self.Len() < y.Len() { - mut xb := make(bits, y.Len()) - _ = copy(xb, self.nat.bits) - self.nat.bits = xb - } - if self.minus { - twosComplement(self.nat.bits) - } - if y.minus { - twosComplement(y.nat.bits) - } - or(self.nat.bits, y.nat.bits) - if self.minus && self.Len() >= y.Len() { - twosComplement(self.nat.bits) - } - if y.minus { - twosComplement(y.nat.bits) - } - self.nat.fit() - } - - // Bitwise and. - fn BitAnd(self, y: Int): Int { - mut r := self - r &= y - ret r - } - - // Bitwise and for assignment. - fn BitAndAssign(mut self, y: Int) { - if self.Len() < y.Len() { - mut xb := make(bits, y.Len()) - _ = copy(xb, self.nat.bits) - self.nat.bits = xb - } - if self.minus { - twosComplement(self.nat.bits) - } - if y.minus { - twosComplement(y.nat.bits) - } - if !self.minus && y.minus && self.Len() > y.Len() { - mut x := self.nat.bits[:y.Len()] - and(x, y.nat.bits) - } else { - and(self.nat.bits, y.nat.bits) - } - if y.minus { - twosComplement(y.nat.bits) - if self.minus { - twosComplement(self.nat.bits) - } - } - self.minus = self.minus && y.minus - self.nat.fit() - } - - // Bitwise xor. - fn BitXor(self, y: Int): Int { - mut r := self - r ^= y - ret r - } - - // Bitwise xor for assignment. - fn BitXorAssign(mut self, y: Int) { - if !self.minus && y.minus { - self = y ^ self - ret - } - if self.Len() < y.Len() { - mut xb := make(bits, y.Len()) - _ = copy(xb, self.nat.bits) - self.nat.bits = xb - } - if self.minus { - twosComplement(self.nat.bits) - } - if y.minus { - twosComplement(y.nat.bits) - } - xor(self.nat.bits, y.nat.bits) - if self.minus && self.Len() >= y.Len() { - twosComplement(self.nat.bits) - } - if y.minus { - twosComplement(y.nat.bits) - } - self.minus = self.minus != y.minus - self.nat.fit() - } - - // Compares bits. - // Returns +1 if self > y. - // Returns 0 if self == y. - // Returns -1 if self < y. - fn Cmp(self, y: Int): int { - match { - | self.minus && !y.minus: - ret -1 - | !self.minus && y.minus: - ret +1 - } - cmp := self.nat.cmp(y.nat) - match { - | cmp == +1 && self.minus - | cmp == -1 && !self.minus: - ret -1 - | cmp == +1 && !self.minus - | cmp == -1 && self.minus: - ret +1 - |: - ret 0 - } - } - - // Reports whether integer less than other. - fn Lt(self, y: Int): bool { - ret self.Cmp(y) == -1 - } - - // Reports whether integer less than or equals to other. - fn LtEq(self, y: Int): bool { - ret self.Cmp(y) < +1 - } - - // Reports whether integer greater than other. - fn Gt(self, y: Int): bool { - ret self.Cmp(y) == +1 - } - - // Reports whether integer greater than or equals to other. - fn GtEq(self, y: Int): bool { - ret self.Cmp(y) > -1 - } - - // Reports whether integers are equals. - fn Eq(self, y: Int): bool { - ret self.Cmp(y) == 0 - } - - // Bitwise not. - fn BitNot(self): Int { - mut r := self.clone() - if r.minus { - subOne(r.nat.bits) - r.nat.fit() - } else { - carry := addOne(r.nat.bits) - if carry == 0b1 { - r.nat.bits = append(r.nat.bits, 0b1) - } - } - r.minus = !r.minus - ret r - } - - // Returns +1 if integer is positive or zero, -1 otherwise. - fn Sign(self): int { - if self.minus { - ret -1 - } - ret +1 - } - - // Unary minus. - fn Neg(self): Int { - mut r := self.clone() - r.minus = !r.minus - ret r - } - - // Unary plus. - fn Pos(self): Int { - ret self.clone() - } - - // Reports whether number is odd. - fn Odd(self): bool { - ret self.nat.odd() - } - - // Reports whether number is even. - fn Even(self): bool { - ret self.nat.even() - } - - // Returns bit by index. - // The index zero means first bit at right. - fn Bit(self, i: int): int { - ret self.nat.bit(i) - } - - // Returns immutable copy of internal little-endian bits. - fn Bits(self): []byte { - ret cloneBits(self.nat.bits) - } - - // Returns absolute value of integer. - fn Abs(self): Int { - mut r := self - r.minus = false - ret r - } - - // Returns count of absolute's trailing zeros. - fn TrailingZeros(self): int { - ret self.nat.trailingZeros() - } - - // Format number into string. Fmt is the format of number. - // Results with exceptional if fmt is not valid. - // Exceptional is always BigError.Format. - // - // Valid fmt values are; - // - 2 for binary. - // - 8 for octal. - // - 10 for decimal. - // - 16 for hexadecimal. - fn Format(self, fmt: int)!: str { - mut s := self.nat.format(fmt) else { error(error) } - if self.minus && s != "0" { - s = "-" + s - } - ret s - } - - // Returns integer in i64. - // Causes exception if nuber large than capacity of i64. - // Exception is equals to i64.Min constant if integer is negative, else i64.Max. - fn ToI64(self)!: i64 { - if self.Len() > 63 { - if self.minus { - error(i64.Min) - } - error(i64.Max) - } - x := i64(u64FromBits(self.nat.bits)) - if self.minus { - if x == 0 { - ret i64.Min - } - ret -x - } - ret x - } - - // Returns integer in u64. - // Causes exception if nuber large than capacity of u64. - // Exception is always equals to u64.Max constant. - fn ToU64(self)!: u64 { - x := self.nat.toU64() else { error(error) } - if self.minus { - ret -x - } - ret x - } - - // Formats number with self.Format(10) by default. - fn Str(self): str { - ret self.Format(10)! - } - - fn clone(self): Int { - mut r := self - r.nat = self.nat.clone() - ret r - } + // Returns big integer that represents zero. + static fn Zero(): Int { + ret Int{ + nat: nat.zero(), + } + } + + // Returns big integer that represents one. + static fn One(): Int { + ret Int{ + nat: nat.one(), + } + } + + // Returns big integer that initialized by integer value. + // T can only be signed or unsigned integer types. + static fn New[T: Int | i8 | i16 | i32 | i64 | u8 | u16 | u32 | u64 | int | uint](i: T): Int { + const match type T { + | Int: + ret i + | i8 | i16 | i32 | i64 | u8 | u16 | u32 | u64 | int | uint: + ret Int{ + minus: i < 0, + nat: nat.new[T](i), + } + |: + panic("std::math::big: Int.new[T]: unimplemented type, this panic call should be unreachable") + } + } + + // Parse big integer from string. Fmt is the format of string. + // Results with exceptional if bits are not in the format or empty. + // Results with exceptional if fmt is not valid. + // Exceptional is always BigError.Format. + // + // Valid fmt values are; + // - 2 for binary. + // - 8 for octal. + // - 10 for decimal. + // - 16 for hexadecimal. + static fn Parse(mut s: str, fmt: int)!: Int { + mut r := Int{} + if len(s) > 0 { + match s[0] { + | '-': + r.minus = true + s = s[1:] + | '+': + s = s[1:] + } + } + r.nat = nat.parse(s, fmt) else { error(error) } + r.minus = r.minus && r.nat.len() != 0 + ret r + } + + // Returns count of bits except sign-bit. + // Return value also means the minimum number of bits that can represent the integer. + fn Len(self): int { + ret self.nat.len() + } + + // Adds two Int and returns result. + fn Add(self, y: Int): Int { + mut r := self + r += y + ret r + } + + // Adds Int. + fn AddAssign(mut self, y: Int) { + match { + | y.Len() == 0: + ret + | self.minus == y.minus: + self.nat += y.nat + |: + mut cmp := self.nat.cmp(y.nat) + if cmp == 0 { + self.minus = false + self.nat = nat.zero() + ret + } + if y.minus { + cmp = -cmp + } + if self.minus && cmp == +1 || + y.minus && cmp == -1 { + self.nat -= y.nat + } else { + self.nat = y.nat - self.nat + } + self.minus = cmp == +1 + } + } + + // Subtracts two Int and returns result. + fn Sub(self, y: Int): Int { + mut r := self + r -= y + ret r + } + + // Subtracts Int. + fn SubAssign(mut self, y: Int) { + if y.Len() == 0 { + ret + } + mut cmp := self.Cmp(y) + if cmp == 0 { + self.minus = false + self.nat = nat.zero() + ret + } + if self.minus == y.minus { + self.minus = cmp == -1 + if cmp == +1 { + self.nat -= y.nat + } else { + self.nat = y.nat - self.nat + } + ret + } + self.minus = false + self.nat += y.nat + ret + } + + // Multiplies two Int and returns result. + fn Mul(self, y: Int): Int { + mut r := self + r *= y + ret r + } + + // Multiplies Int. + fn MulAssign(mut self, y: Int) { + self.nat *= y.nat + self.minus = self.Len() > 0 && self.minus != y.minus + } + + // Divides two Int and returns result. + fn Div(self, y: Int): Int { + mut r := self + r /= y + ret r + } + + // Divides Int. + fn DivAssign(mut self, y: Int) { + self.nat /= y.nat + if self.Len() == 0 { + self.minus = false + } else { + self.minus = self.minus != y.minus + } + } + + // Modulo two Int and returns result. + fn Mod(self, y: Int): Int { + mut r := self + r %= y + ret r + } + + // Modulo Int. + fn ModAssign(mut self, y: Int) { + if self.minus == y.minus { + self.nat %= y.nat + self.minus = self.Len() > 0 && y.minus + ret + } + self.nat %= y.nat + if self.Len() == 0 { + self.minus = false + ret + } + self.nat -= y.nat + self.minus = self.Len() > 0 && y.minus + } + + // Bitwise left shift. + fn Shl(self, y: int): Int { + mut r := self + r <<= y + ret r + } + + // Bitwise left shift for assignment. + fn ShlAssign(mut self, y: int) { + self.nat <<= y + } + + // Bitwise right shift. + fn Shr(self, y: int): Int { + mut r := self + r >>= y + ret r + } + + // Bitwise right shift for assignment. + fn ShrAssign(mut self, y: int) { + self.nat >>= y + self.minus = self.minus && self.Len() > 0 + } + + // Bitwise or. + fn BitOr(self, y: Int): Int { + mut r := self + r |= y + ret r + } + + // Bitwise or for assignment. + fn BitOrAssign(mut self, y: Int) { + if self.Len() < y.Len() { + mut xb := make(bits, y.Len()) + _ = copy(xb, self.nat.bits) + self.nat.bits = xb + } + if self.minus { + twosComplement(self.nat.bits) + } + if y.minus { + twosComplement(y.nat.bits) + } + or(self.nat.bits, y.nat.bits) + if self.minus && self.Len() >= y.Len() { + twosComplement(self.nat.bits) + } + if y.minus { + twosComplement(y.nat.bits) + } + self.nat.fit() + } + + // Bitwise and. + fn BitAnd(self, y: Int): Int { + mut r := self + r &= y + ret r + } + + // Bitwise and for assignment. + fn BitAndAssign(mut self, y: Int) { + if self.Len() < y.Len() { + mut xb := make(bits, y.Len()) + _ = copy(xb, self.nat.bits) + self.nat.bits = xb + } + if self.minus { + twosComplement(self.nat.bits) + } + if y.minus { + twosComplement(y.nat.bits) + } + if !self.minus && y.minus && self.Len() > y.Len() { + mut x := self.nat.bits[:y.Len()] + and(x, y.nat.bits) + } else { + and(self.nat.bits, y.nat.bits) + } + if y.minus { + twosComplement(y.nat.bits) + if self.minus { + twosComplement(self.nat.bits) + } + } + self.minus = self.minus && y.minus + self.nat.fit() + } + + // Bitwise xor. + fn BitXor(self, y: Int): Int { + mut r := self + r ^= y + ret r + } + + // Bitwise xor for assignment. + fn BitXorAssign(mut self, y: Int) { + if !self.minus && y.minus { + self = y ^ self + ret + } + if self.Len() < y.Len() { + mut xb := make(bits, y.Len()) + _ = copy(xb, self.nat.bits) + self.nat.bits = xb + } + if self.minus { + twosComplement(self.nat.bits) + } + if y.minus { + twosComplement(y.nat.bits) + } + xor(self.nat.bits, y.nat.bits) + if self.minus && self.Len() >= y.Len() { + twosComplement(self.nat.bits) + } + if y.minus { + twosComplement(y.nat.bits) + } + self.minus = self.minus != y.minus + self.nat.fit() + } + + // Compares bits. + // Returns +1 if self > y. + // Returns 0 if self == y. + // Returns -1 if self < y. + fn Cmp(self, y: Int): int { + match { + | self.minus && !y.minus: + ret -1 + | !self.minus && y.minus: + ret +1 + } + cmp := self.nat.cmp(y.nat) + match { + | cmp == +1 && self.minus + | cmp == -1 && !self.minus: + ret -1 + | cmp == +1 && !self.minus + | cmp == -1 && self.minus: + ret +1 + |: + ret 0 + } + } + + // Reports whether integer less than other. + fn Lt(self, y: Int): bool { + ret self.Cmp(y) == -1 + } + + // Reports whether integer less than or equals to other. + fn LtEq(self, y: Int): bool { + ret self.Cmp(y) < +1 + } + + // Reports whether integer greater than other. + fn Gt(self, y: Int): bool { + ret self.Cmp(y) == +1 + } + + // Reports whether integer greater than or equals to other. + fn GtEq(self, y: Int): bool { + ret self.Cmp(y) > -1 + } + + // Reports whether integers are equals. + fn Eq(self, y: Int): bool { + ret self.Cmp(y) == 0 + } + + // Bitwise not. + fn BitNot(self): Int { + mut r := self.clone() + if r.minus { + subOne(r.nat.bits) + r.nat.fit() + } else { + carry := addOne(r.nat.bits) + if carry == 0b1 { + r.nat.bits = append(r.nat.bits, 0b1) + } + } + r.minus = !r.minus + ret r + } + + // Returns +1 if integer is positive or zero, -1 otherwise. + fn Sign(self): int { + if self.minus { + ret -1 + } + ret +1 + } + + // Unary minus. + fn Neg(self): Int { + mut r := self.clone() + r.minus = !r.minus + ret r + } + + // Unary plus. + fn Pos(self): Int { + ret self.clone() + } + + // Reports whether number is odd. + fn Odd(self): bool { + ret self.nat.odd() + } + + // Reports whether number is even. + fn Even(self): bool { + ret self.nat.even() + } + + // Returns bit by index. + // The index zero means first bit at right. + fn Bit(self, i: int): int { + ret self.nat.bit(i) + } + + // Returns immutable copy of internal little-endian bits. + fn Bits(self): []byte { + ret cloneBits(self.nat.bits) + } + + // Returns absolute value of integer. + fn Abs(self): Int { + mut r := self + r.minus = false + ret r + } + + // Returns count of absolute's trailing zeros. + fn TrailingZeros(self): int { + ret self.nat.trailingZeros() + } + + // Format number into string. Fmt is the format of number. + // Results with exceptional if fmt is not valid. + // Exceptional is always BigError.Format. + // + // Valid fmt values are; + // - 2 for binary. + // - 8 for octal. + // - 10 for decimal. + // - 16 for hexadecimal. + fn Format(self, fmt: int)!: str { + mut s := self.nat.format(fmt) else { error(error) } + if self.minus && s != "0" { + s = "-" + s + } + ret s + } + + // Returns integer in i64. + // Causes exception if nuber large than capacity of i64. + // Exception is equals to i64.Min constant if integer is negative, else i64.Max. + fn ToI64(self)!: i64 { + if self.Len() > 63 { + if self.minus { + error(i64.Min) + } + error(i64.Max) + } + x := i64(u64FromBits(self.nat.bits)) + if self.minus { + if x == 0 { + ret i64.Min + } + ret -x + } + ret x + } + + // Returns integer in u64. + // Causes exception if nuber large than capacity of u64. + // Exception is always equals to u64.Max constant. + fn ToU64(self)!: u64 { + x := self.nat.toU64() else { error(error) } + if self.minus { + ret -x + } + ret x + } + + // Formats number with self.Format(10) by default. + fn Str(self): str { + ret self.Format(10)! + } + + fn clone(self): Int { + mut r := self + r.nat = self.nat.clone() + ret r + } } fn max(a: int, b: int): int { - if a > b { - ret a - } - ret b + if a > b { + ret a + } + ret b } \ No newline at end of file diff --git a/std/math/big/int_test.jule b/std/math/big/int_test.jule index 3e9f96e1c..e5cda75ed 100644 --- a/std/math/big/int_test.jule +++ b/std/math/big/int_test.jule @@ -7,324 +7,324 @@ use std::testing::{T} static casesIntAdd = [ - ["+10000100100001", "+10011001101010", "+100011110001011"], - ["+10000100100001", "-10011001101010", "-10101001001"], - ["+10011001101010", "-10000100100001", "+10101001001"], - ["-10011001101010", "+10000100100001", "-10101001001"], - ["-10000100100001", "+10011001101010", "+10101001001"], - ["-100011", "-1110100110", "-1111001001"], - ["+11000", "+101011", "+1000011"], + ["+10000100100001", "+10011001101010", "+100011110001011"], + ["+10000100100001", "-10011001101010", "-10101001001"], + ["+10011001101010", "-10000100100001", "+10101001001"], + ["-10011001101010", "+10000100100001", "-10101001001"], + ["-10000100100001", "+10011001101010", "+10101001001"], + ["-100011", "-1110100110", "-1111001001"], + ["+11000", "+101011", "+1000011"], ] static casesIntSub = [ - ["+1010", "+10100", "-1010"], - ["+10000100100001", "+10011001101010", "-10101001001"], - ["+10000100100001", "-10011001101010", "+100011110001011"], - ["+10011001101010", "-10000100100001", "+100011110001011"], - ["-10011001101010", "+10000100100001", "+100011110001011"], - ["-10000100100001", "+10011001101010", "+100011110001011"], - ["-100011", "-1110100110", "+1110000011"], - ["+11000", "+101011", "-10011"], + ["+1010", "+10100", "-1010"], + ["+10000100100001", "+10011001101010", "-10101001001"], + ["+10000100100001", "-10011001101010", "+100011110001011"], + ["+10011001101010", "-10000100100001", "+100011110001011"], + ["-10011001101010", "+10000100100001", "+100011110001011"], + ["-10000100100001", "+10011001101010", "+100011110001011"], + ["-100011", "-1110100110", "+1110000011"], + ["+11000", "+101011", "-10011"], ] static casesIntMul = [ - ["+1011010", "-1011010", "-1111110100100"], - ["+1011010", "-1", "-1011010"], - ["+1100010", "+100", "+110001000"], - ["+100", "+1100010", "+110001000"], - ["+10001101101110101011110110000110111111101101", "+10001101101110101011110110000110111111101101", "+100111001110111001111001111111010101001001011000000000110101110110111110110000101101001"], - ["-100111001110111001111001111111010101001001011000000000110101110110111110110000101101001", "+100111001110111001111001111111010101001001011000000000110101110110111110110000101101001", "-11000000011001110000010110100111100100110000001110100100100001110010010011011011110100000111000000011100100101001011101010001010001100010011110010101111111101011110100010001"], + ["+1011010", "-1011010", "-1111110100100"], + ["+1011010", "-1", "-1011010"], + ["+1100010", "+100", "+110001000"], + ["+100", "+1100010", "+110001000"], + ["+10001101101110101011110110000110111111101101", "+10001101101110101011110110000110111111101101", "+100111001110111001111001111111010101001001011000000000110101110110111110110000101101001"], + ["-100111001110111001111001111111010101001001011000000000110101110110111110110000101101001", "+100111001110111001111001111111010101001001011000000000110101110110111110110000101101001", "-11000000011001110000010110100111100100110000001110100100100001110010010011011011110100000111000000011100100101001011101010001010001100010011110010101111111101011110100010001"], ] static casesIntDiv = [ - ["+1010", "-1", "-1010"], - ["+1010", "+10", "+101"], - ["-1000000", "-110", "+1010"], - ["+1001100", "+11", "+11001"], - ["+1000000", "+100", "+10000"], - ["-11111011", "+1101", "-10011"], - ["+10011011001110001", "+111", "+10110001011001"], - ["-10011001101010", "-10", "+1001100110101"], - ["+1010101010101010101010101010101010101010101010", "-10", "-101010101010101010101010101010101010101010101"], - ["+100111001110111001111001111111010101001001011000000000110101110110111110110000101101001", "+10", "+10011100111011100111100111111101010100100101100000000011010111011011111011000010110100"], + ["+1010", "-1", "-1010"], + ["+1010", "+10", "+101"], + ["-1000000", "-110", "+1010"], + ["+1001100", "+11", "+11001"], + ["+1000000", "+100", "+10000"], + ["-11111011", "+1101", "-10011"], + ["+10011011001110001", "+111", "+10110001011001"], + ["-10011001101010", "-10", "+1001100110101"], + ["+1010101010101010101010101010101010101010101010", "-10", "-101010101010101010101010101010101010101010101"], + ["+100111001110111001111001111111010101001001011000000000110101110110111110110000101101001", "+10", "+10011100111011100111100111111101010100100101100000000011010111011011111011000010110100"], ] static casesIntMod = [ - ["-1010", "+11", "+10"], - ["-1011110110110101010101010101010011001111010101101011100", "+1101101", "+111011"], - ["+1010", "-11", "-10"], - ["+1010", "+11", "+1"], - ["+1011110110110101010101010101010011001111010101101011100", "-1101101", "-111011"], - ["+1010", "+10000000000", "+1010"], - ["+10111101", "+10111111", "+10111101"], - ["+10001110000010", "-11000011010100000", "-10110001100011110"], - ["+1110101011011101", "-1000000000000000000000", "-111110001010100100011"], - ["-1110101011011101", "-1000000000000000000000", "-1110101011011101"], - ["-1000000000", "-1101", "-101"], - ["-1010", "+10000000000", "+1111110110"], - ["+1010", "-10000000000", "-1111110110"], + ["-1010", "+11", "+10"], + ["-1011110110110101010101010101010011001111010101101011100", "+1101101", "+111011"], + ["+1010", "-11", "-10"], + ["+1010", "+11", "+1"], + ["+1011110110110101010101010101010011001111010101101011100", "-1101101", "-111011"], + ["+1010", "+10000000000", "+1010"], + ["+10111101", "+10111111", "+10111101"], + ["+10001110000010", "-11000011010100000", "-10110001100011110"], + ["+1110101011011101", "-1000000000000000000000", "-111110001010100100011"], + ["-1110101011011101", "-1000000000000000000000", "-1110101011011101"], + ["-1000000000", "-1101", "-101"], + ["-1010", "+10000000000", "+1111110110"], + ["+1010", "-10000000000", "-1111110110"], ] static casesIntBitNot: [][]i64 = [ - [-20, 19], - [-90, 89], - [20, -21], - [90, -91], + [-20, 19], + [-90, 89], + [20, -21], + [90, -91], ] static casesIntBitOr: [][]i64 = [ - [20, 4, 20], - [4, 20, 20], - [345, 2, 347], - [908474739, 747688553334, 748259113847], - [97799739579632223, 1234567890, 97799739731806943], - [-20, 4, -20], - [-4, 20, -4], - [-345, 2, -345], - [-908474739, 747688553334, -570560513], - [-97799739579632223, 1234567890, -97799738497239053], + [20, 4, 20], + [4, 20, 20], + [345, 2, 347], + [908474739, 747688553334, 748259113847], + [97799739579632223, 1234567890, 97799739731806943], + [-20, 4, -20], + [-4, 20, -4], + [-345, 2, -345], + [-908474739, 747688553334, -570560513], + [-97799739579632223, 1234567890, -97799738497239053], ] static casesIntBitAnd: [][]i64 = [ - [902984, 24, 8], - [24, 902984, 8], - [902984, 2434, 256], - [2434, 902984, 256], - [77786486463864864, 97774749933, 19360907296], - [123456789, 987654321, 39471121], - [5, -3, 5], - [-5, 3, 3], - [-8884973, 88893, 18705], - [88893, -8884973, 18705], - [13452, -12345, 1156], - [-13452, -12345, -13500], - [-12345, -13452, -13500], + [902984, 24, 8], + [24, 902984, 8], + [902984, 2434, 256], + [2434, 902984, 256], + [77786486463864864, 97774749933, 19360907296], + [123456789, 987654321, 39471121], + [5, -3, 5], + [-5, 3, 3], + [-8884973, 88893, 18705], + [88893, -8884973, 18705], + [13452, -12345, 1156], + [-13452, -12345, -13500], + [-12345, -13452, -13500], ] static casesIntBitXor: [][]i64 = [ - [10, 11, 1], - [87793, 5, 87796], - [5, 87793, 87796], - [10, 1, 11], - [1, 10, 11], - [12345, 54321, 58376], - [123, 321, 314], - [1234567890, 9876543210, 8676316216], - [-10, -1, 9], - [-1, 10, -11], - [10, -1, -11], - [12345, -54321, -58378], - [123, -321, -316], - [-1234567890, 9876543210, -8676316220], - [9876543210, -1234567890, -8676316220], + [10, 11, 1], + [87793, 5, 87796], + [5, 87793, 87796], + [10, 1, 11], + [1, 10, 11], + [12345, 54321, 58376], + [123, 321, 314], + [1234567890, 9876543210, 8676316216], + [-10, -1, 9], + [-1, 10, -11], + [10, -1, -11], + [12345, -54321, -58378], + [123, -321, -316], + [-1234567890, 9876543210, -8676316220], + [9876543210, -1234567890, -8676316220], ] fn testCommonIntOp(&t: &T, op: str, &cases: [][]str) { - for _, c in cases { - mut n1 := Int.Parse(c[0], 2) else { - t.Errorf("exception occurs: {}", error) - continue - } - n2 := Int.Parse(c[1], 2) else { - t.Errorf("exception occurs: {}", error) - continue - } - match op { - | "+": - n1 += n2 - | "-": - n1 -= n2 - | "*": - n1 *= n2 - | "/": - n1 /= n2 - | "%": - n1 %= n2 - } - cr := c[2] - if n1.Len() != len(cr)-1 || - n1.minus && c[2][0] != '-' || - !n1.minus && c[2][0] != '+' { - t.Errorf("{} {} {} != {}", c[0], op, c[1], c[2]) - continue - } - for i, b in n1.nat.bits { - cb := cr[len(cr)-1-i] - if b == 0b1 && cb != '1' || - b == 0b0 && cb != '0' { - t.Errorf("{} {} {} != {}", c[0], op, c[1], c[2]) - break - } - } - } + for _, c in cases { + mut n1 := Int.Parse(c[0], 2) else { + t.Errorf("exception occurs: {}", error) + continue + } + n2 := Int.Parse(c[1], 2) else { + t.Errorf("exception occurs: {}", error) + continue + } + match op { + | "+": + n1 += n2 + | "-": + n1 -= n2 + | "*": + n1 *= n2 + | "/": + n1 /= n2 + | "%": + n1 %= n2 + } + cr := c[2] + if n1.Len() != len(cr)-1 || + n1.minus && c[2][0] != '-' || + !n1.minus && c[2][0] != '+' { + t.Errorf("{} {} {} != {}", c[0], op, c[1], c[2]) + continue + } + for i, b in n1.nat.bits { + cb := cr[len(cr)-1-i] + if b == 0b1 && cb != '1' || + b == 0b0 && cb != '0' { + t.Errorf("{} {} {} != {}", c[0], op, c[1], c[2]) + break + } + } + } } #test fn testIntAdd(t: &T) { - testCommonIntOp(t, "+", casesIntAdd) + testCommonIntOp(t, "+", casesIntAdd) } #test fn testIntSub(t: &T) { - testCommonIntOp(t, "-", casesIntSub) + testCommonIntOp(t, "-", casesIntSub) } #test fn testIntMul(t: &T) { - testCommonIntOp(t, "*", casesIntMul) + testCommonIntOp(t, "*", casesIntMul) } #test fn testIntDiv(t: &T) { - testCommonIntOp(t, "/", casesIntDiv) + testCommonIntOp(t, "/", casesIntDiv) } #test fn testIntMod(t: &T) { - testCommonIntOp(t, "%", casesIntMod) + testCommonIntOp(t, "%", casesIntMod) } #test fn testIntBitNot(t: &T) { - for _, c in casesIntBitNot { - i := Int.New(c[0]) - r := ^i - if (r.ToI64()!) != c[1] { - t.Errorf("^{} != {}", c[0], c[1]) - } - } + for _, c in casesIntBitNot { + i := Int.New(c[0]) + r := ^i + if (r.ToI64()!) != c[1] { + t.Errorf("^{} != {}", c[0], c[1]) + } + } } fn testIntBitBinary(t: &T, op: str, &cases: [][]i64) { - for _, c in cases { - mut n1 := Int.New(c[0]) - n2 := Int.New(c[1]) - match op { - | "|": - n1 |= n2 - | "&": - n1 &= n2 - | "^": - n1 ^= n2 - } - i := n1.ToI64()! - if i != c[2] { - t.Errorf("{} {} {} != {}", c[0], op, c[1], c[2]) - } - } + for _, c in cases { + mut n1 := Int.New(c[0]) + n2 := Int.New(c[1]) + match op { + | "|": + n1 |= n2 + | "&": + n1 &= n2 + | "^": + n1 ^= n2 + } + i := n1.ToI64()! + if i != c[2] { + t.Errorf("{} {} {} != {}", c[0], op, c[1], c[2]) + } + } } #test fn testIntBitOr(t: &T) { - testIntBitBinary(t, "|", casesIntBitOr) + testIntBitBinary(t, "|", casesIntBitOr) } #test fn testIntBitAnd(t: &T) { - testIntBitBinary(t, "&", casesIntBitAnd) + testIntBitBinary(t, "&", casesIntBitAnd) } #test fn testIntBitXor(t: &T) { - testIntBitBinary(t, "^", casesIntBitXor) + testIntBitBinary(t, "^", casesIntBitXor) } #test fn testIntLt(t: &T) { - t.Assert(!Int.Parse("1011010", 2)!.Lt(Int.Parse("00001011010", 2)!), "1) 1011010 < 00001011010") - t.Assert(!Int.Parse("1111011000", 2)!.Lt(Int.Parse("000000000001111011000", 2)!), "2) 1111011000 < 000000000001111011000") - t.Assert(!Int.Parse("10001100011000", 2)!.Lt(Int.Parse("100011", 2)!), "3) 10001100011000 < 100011") - t.Assert(!Int.Parse("10001101101110101011110110000110111111101111", 2)!.Lt(Int.Parse("10001101101110101011110110000110111111101101", 2)!), "4) 10001101101110101011110110000110111111101111 < 10001101101110101011110110000110111111101101") - - // - - - t.Assert(!Int.Parse("-1011010", 2)!.Lt(Int.Parse("-00001011010", 2)!), "4) -1011010 <= -00001011010") - t.Assert(!Int.Parse("-1111011000", 2)!.Lt(Int.Parse("-000000000001111011000", 2)!), "5) -1111011000 <= -000000000001111011000") - t.Assert(!Int.Parse("-10001100011000", 2)!.Lt(Int.Parse("-10001100011000", 2)!), "6) -10001100011000 >= -10001100011000") - t.Assert(!Int.Parse("-10001101101110101011110110000110111111101101", 2)!.Lt(Int.Parse("-10001101101110101011110110000110111111101101", 2)!), "7) -10001101101110101011110110000110111111101101 >= -10001101101110101011110110000110111111101101") - t.Assert(Int.Parse("-1011010", 2)!.Lt(Int.Parse("-00001", 2)!), "4) -1011010 <= -00001") - - // - + - t.Assert(Int.Parse("-1011010", 2)!.Lt(Int.Parse("00001011010", 2)!), "8) -1011010 >= 00001011010") - t.Assert(Int.Parse("-1111011000", 2)!.Lt(Int.Parse("000000000001111011000", 2)!), "9) -1111011000 >= 000000000001111011000") - t.Assert(Int.Parse("-10001100011000", 2)!.Lt(Int.Parse("10001100011000", 2)!), "10) -10001100011000 >= 10001100011000") - t.Assert(Int.Parse("-10001101101110101011110110000110111111101101", 2)!.Lt(Int.Parse("10001101101110101011110110000110111111101101", 2)!), "11) -10001101101110101011110110000110111111101101 >= 10001101101110101011110110000110111111101101") + t.Assert(!Int.Parse("1011010", 2)!.Lt(Int.Parse("00001011010", 2)!), "1) 1011010 < 00001011010") + t.Assert(!Int.Parse("1111011000", 2)!.Lt(Int.Parse("000000000001111011000", 2)!), "2) 1111011000 < 000000000001111011000") + t.Assert(!Int.Parse("10001100011000", 2)!.Lt(Int.Parse("100011", 2)!), "3) 10001100011000 < 100011") + t.Assert(!Int.Parse("10001101101110101011110110000110111111101111", 2)!.Lt(Int.Parse("10001101101110101011110110000110111111101101", 2)!), "4) 10001101101110101011110110000110111111101111 < 10001101101110101011110110000110111111101101") + + // - - + t.Assert(!Int.Parse("-1011010", 2)!.Lt(Int.Parse("-00001011010", 2)!), "4) -1011010 <= -00001011010") + t.Assert(!Int.Parse("-1111011000", 2)!.Lt(Int.Parse("-000000000001111011000", 2)!), "5) -1111011000 <= -000000000001111011000") + t.Assert(!Int.Parse("-10001100011000", 2)!.Lt(Int.Parse("-10001100011000", 2)!), "6) -10001100011000 >= -10001100011000") + t.Assert(!Int.Parse("-10001101101110101011110110000110111111101101", 2)!.Lt(Int.Parse("-10001101101110101011110110000110111111101101", 2)!), "7) -10001101101110101011110110000110111111101101 >= -10001101101110101011110110000110111111101101") + t.Assert(Int.Parse("-1011010", 2)!.Lt(Int.Parse("-00001", 2)!), "4) -1011010 <= -00001") + + // - + + t.Assert(Int.Parse("-1011010", 2)!.Lt(Int.Parse("00001011010", 2)!), "8) -1011010 >= 00001011010") + t.Assert(Int.Parse("-1111011000", 2)!.Lt(Int.Parse("000000000001111011000", 2)!), "9) -1111011000 >= 000000000001111011000") + t.Assert(Int.Parse("-10001100011000", 2)!.Lt(Int.Parse("10001100011000", 2)!), "10) -10001100011000 >= 10001100011000") + t.Assert(Int.Parse("-10001101101110101011110110000110111111101101", 2)!.Lt(Int.Parse("10001101101110101011110110000110111111101101", 2)!), "11) -10001101101110101011110110000110111111101101 >= 10001101101110101011110110000110111111101101") } #test fn testIntGt(t: &T) { - // + + - t.Assert(!Int.Parse("+1011010", 2)!.Gt(Int.Parse("+00001011010", 2)!), "1) 1011010 > 00001011010") - t.Assert(!Int.Parse("+1111011000", 2)!.Gt(Int.Parse("+000000000001111011000", 2)!), "2) 1111011000 > 000000000001111011000") - t.Assert(Int.Parse("+10001100011000", 2)!.Gt(Int.Parse("+100011", 2)!), "3) 10001100011000 <= 100011") - t.Assert(Int.Parse("+10001101101110101011110110000110111111101111", 2)!.Gt(Int.Parse("+10001101101110101011110110000110111111101101", 2)!), "4) 10001101101110101011110110000110111111101111 <= 10001101101110101011110110000110111111101101") - - // - - - t.Assert(!Int.Parse("-1011010", 2)!.Gt(Int.Parse("-00001011010", 2)!), "4) -1011010 <= -00001011010") - t.Assert(!Int.Parse("-1111011000", 2)!.Gt(Int.Parse("-000000000001111011000", 2)!), "5) -1111011000 <= -000000000001111011000") - t.Assert(!Int.Parse("-10001100011000", 2)!.Gt(Int.Parse("-10001100011000", 2)!), "6) -10001100011000 >= -10001100011000") - t.Assert(!Int.Parse("-10001101101110101011110110000110111111101101", 2)!.Gt(Int.Parse("-10001101101110101011110110000110111111101101", 2)!), "7) -10001101101110101011110110000110111111101101 >= -10001101101110101011110110000110111111101101") - - // + - - t.Assert(Int.Parse("+1011010", 2)!.Gt(Int.Parse("-00001011010", 2)!), "8) 1011010 <= -00001011010") - t.Assert(Int.Parse("+1111011000", 2)!.Gt(Int.Parse("-000000000001111011000", 2)!), "9) 1111011000 <= -000000000001111011000") - t.Assert(Int.Parse("+10001100011000", 2)!.Gt(Int.Parse("-10001100011000", 2)!), "10) 10001100011000 <= -10001100011000") - t.Assert(Int.Parse("+10001101101110101011110110000110111111101101", 2)!.Gt(Int.Parse("-10001101101110101011110110000110111111101101", 2)!), "11) 10001101101110101011110110000110111111101101 <= -10001101101110101011110110000110111111101101") + // + + + t.Assert(!Int.Parse("+1011010", 2)!.Gt(Int.Parse("+00001011010", 2)!), "1) 1011010 > 00001011010") + t.Assert(!Int.Parse("+1111011000", 2)!.Gt(Int.Parse("+000000000001111011000", 2)!), "2) 1111011000 > 000000000001111011000") + t.Assert(Int.Parse("+10001100011000", 2)!.Gt(Int.Parse("+100011", 2)!), "3) 10001100011000 <= 100011") + t.Assert(Int.Parse("+10001101101110101011110110000110111111101111", 2)!.Gt(Int.Parse("+10001101101110101011110110000110111111101101", 2)!), "4) 10001101101110101011110110000110111111101111 <= 10001101101110101011110110000110111111101101") + + // - - + t.Assert(!Int.Parse("-1011010", 2)!.Gt(Int.Parse("-00001011010", 2)!), "4) -1011010 <= -00001011010") + t.Assert(!Int.Parse("-1111011000", 2)!.Gt(Int.Parse("-000000000001111011000", 2)!), "5) -1111011000 <= -000000000001111011000") + t.Assert(!Int.Parse("-10001100011000", 2)!.Gt(Int.Parse("-10001100011000", 2)!), "6) -10001100011000 >= -10001100011000") + t.Assert(!Int.Parse("-10001101101110101011110110000110111111101101", 2)!.Gt(Int.Parse("-10001101101110101011110110000110111111101101", 2)!), "7) -10001101101110101011110110000110111111101101 >= -10001101101110101011110110000110111111101101") + + // + - + t.Assert(Int.Parse("+1011010", 2)!.Gt(Int.Parse("-00001011010", 2)!), "8) 1011010 <= -00001011010") + t.Assert(Int.Parse("+1111011000", 2)!.Gt(Int.Parse("-000000000001111011000", 2)!), "9) 1111011000 <= -000000000001111011000") + t.Assert(Int.Parse("+10001100011000", 2)!.Gt(Int.Parse("-10001100011000", 2)!), "10) 10001100011000 <= -10001100011000") + t.Assert(Int.Parse("+10001101101110101011110110000110111111101101", 2)!.Gt(Int.Parse("-10001101101110101011110110000110111111101101", 2)!), "11) 10001101101110101011110110000110111111101101 <= -10001101101110101011110110000110111111101101") } #test fn testIntEq(t: &T) { - // + + - t.Assert(Int.Parse("+1011010", 2)!.Eq(Int.Parse("+00001011010", 2)!), "1) 1011010 != 00001011010") - t.Assert(Int.Parse("+1111011000", 2)!.Eq(Int.Parse("+000000000001111011000", 2)!), "2) 1111011000 != 000000000001111011000") - t.Assert(Int.Parse("+10001100011000", 2)!.Eq(Int.Parse("+10001100011000", 2)!), "3) 10001100011000 != 10001100011000") - t.Assert(Int.Parse("+10001101101110101011110110000110111111101101", 2)!.Eq(Int.Parse("+10001101101110101011110110000110111111101101", 2)!), "4) 10001101101110101011110110000110111111101101 != 10001101101110101011110110000110111111101101") - - // - - - t.Assert(Int.Parse("-1011010", 2)!.Eq(Int.Parse("-00001011010", 2)!), "5) -1011010 != -00001011010") - t.Assert(Int.Parse("-1111011000", 2)!.Eq(Int.Parse("-000000000001111011000", 2)!), "6) -1111011000 != -000000000001111011000") - t.Assert(Int.Parse("-10001100011000", 2)!.Eq(Int.Parse("-10001100011000", 2)!), "7) -10001100011000 != -10001100011000") - t.Assert(Int.Parse("-10001101101110101011110110000110111111101101", 2)!.Eq(Int.Parse("-10001101101110101011110110000110111111101101", 2)!), "8) -10001101101110101011110110000110111111101101 != -10001101101110101011110110000110111111101101") - - // + - - t.Assert(!Int.Parse("+1011010", 2)!.Eq(Int.Parse("-00001011010", 2)!), "9) 1011010 != -00001011010") - t.Assert(!Int.Parse("+1111011000", 2)!.Eq(Int.Parse("-000000000001111011000", 2)!), "10) 1111011000 != -000000000001111011000") - t.Assert(!Int.Parse("+10001100011000", 2)!.Eq(Int.Parse("-10001100011000", 2)!), "11) 10001100011000 != -10001100011000") - t.Assert(!Int.Parse("+10001101101110101011110110000110111111101101", 2)!.Eq(Int.Parse("-10001101101110101011110110000110111111101101", 2)!), "12) 10001101101110101011110110000110111111101101 != -10001101101110101011110110000110111111101101") + // + + + t.Assert(Int.Parse("+1011010", 2)!.Eq(Int.Parse("+00001011010", 2)!), "1) 1011010 != 00001011010") + t.Assert(Int.Parse("+1111011000", 2)!.Eq(Int.Parse("+000000000001111011000", 2)!), "2) 1111011000 != 000000000001111011000") + t.Assert(Int.Parse("+10001100011000", 2)!.Eq(Int.Parse("+10001100011000", 2)!), "3) 10001100011000 != 10001100011000") + t.Assert(Int.Parse("+10001101101110101011110110000110111111101101", 2)!.Eq(Int.Parse("+10001101101110101011110110000110111111101101", 2)!), "4) 10001101101110101011110110000110111111101101 != 10001101101110101011110110000110111111101101") + + // - - + t.Assert(Int.Parse("-1011010", 2)!.Eq(Int.Parse("-00001011010", 2)!), "5) -1011010 != -00001011010") + t.Assert(Int.Parse("-1111011000", 2)!.Eq(Int.Parse("-000000000001111011000", 2)!), "6) -1111011000 != -000000000001111011000") + t.Assert(Int.Parse("-10001100011000", 2)!.Eq(Int.Parse("-10001100011000", 2)!), "7) -10001100011000 != -10001100011000") + t.Assert(Int.Parse("-10001101101110101011110110000110111111101101", 2)!.Eq(Int.Parse("-10001101101110101011110110000110111111101101", 2)!), "8) -10001101101110101011110110000110111111101101 != -10001101101110101011110110000110111111101101") + + // + - + t.Assert(!Int.Parse("+1011010", 2)!.Eq(Int.Parse("-00001011010", 2)!), "9) 1011010 != -00001011010") + t.Assert(!Int.Parse("+1111011000", 2)!.Eq(Int.Parse("-000000000001111011000", 2)!), "10) 1111011000 != -000000000001111011000") + t.Assert(!Int.Parse("+10001100011000", 2)!.Eq(Int.Parse("-10001100011000", 2)!), "11) 10001100011000 != -10001100011000") + t.Assert(!Int.Parse("+10001101101110101011110110000110111111101101", 2)!.Eq(Int.Parse("-10001101101110101011110110000110111111101101", 2)!), "12) 10001101101110101011110110000110111111101101 != -10001101101110101011110110000110111111101101") } #test fn testIntFormat(t: &T) { - // Binary - t.Assert((Int.Parse("11101110101", 2)!.Format(2)!) == "11101110101", "1) 11101110101 != 11101110101") - t.Assert((Int.Parse("-000000", 2)!.Format(2)!) == "0", "2) -000000 != 0") - t.Assert((Int.Parse("000000", 2)!.Format(2)!) == "0", "3) 000000 != 0") - t.Assert((Int.Parse("-00111", 2)!.Format(2)!) == "-111", "4) 00111 != -111") - t.Assert((Int.Parse("1010", 2)!.Format(2)!) == "1010", "5) 1010 != 1010") - - // Octal - t.Assert((Int.Parse("1010", 2)!.Format(8)!) == "12", "6) 1010 != 12") - t.Assert((Int.Parse("101", 2)!.Format(8)!) == "5", "7) 101 != 5") - t.Assert((Int.Parse("-1010", 2)!.Format(8)!) == "-12", "8) -1010 != -12") - t.Assert((Int.Parse("-101", 2)!.Format(8)!) == "-5", "9) -101 != -5") - t.Assert((Int.Parse("1111010101", 2)!.Format(8)!) == "1725", "10) 1111010101 != 1725") - t.Assert((Int.Parse("-10001101101110101011110110000110111111101101", 2)!.Format(8)!) == "-215565366067755", "11) -10001101101110101011110110000110111111101101 != -215565366067755") - t.Assert((Int.Parse("100111001110111001111001111111010101001001011000000000110101110110111110110000101101001", 2)!.Format(8)!) == "47167171772511300065667660551", "12) 100111001110111001111001111111010101001001011000000000110101110110111110110000101101001 != 47167171772511300065667660551") - - // Decimal - t.Assert((Int.Parse("1010", 2)!.Format(10)!) == "10", "13) 1010 != 10") - t.Assert((Int.Parse("101", 2)!.Format(10)!) == "5", "14) 101 != 5") - t.Assert((Int.Parse("-1010", 2)!.Format(10)!) == "-10", "15) -1010 != -10") - t.Assert((Int.Parse("-101", 2)!.Format(10)!) == "-5", "16) -101 != -5") - t.Assert((Int.Parse("1111010101", 2)!.Format(10)!) == "981", "17) 1111010101 != 981") - t.Assert((Int.Parse("-10001101101110101011110110000110111111101101", 2)!.Format(10)!) == "-9739573948397", "18) -10001101101110101011110110000110111111101101 != -9739573948397") - t.Assert((Int.Parse("100111001110111001111001111111010101001001011000000000110101110110111110110000101101001", 2)!.Format(10)!) == "94859300696293528418869609", "19) 100111001110111001111001111111010101001001011000000000110101110110111110110000101101001 != 94859300696293528418869609") - - // Hexadecimal - t.Assert((Int.Parse("1010", 2)!.Format(16)!) == "A", "20) 1010 != A") - t.Assert((Int.Parse("101", 2)!.Format(16)!) == "5", "21) 101 != 5") - t.Assert((Int.Parse("-1010", 2)!.Format(16)!) == "-A", "22) -1010 != -A") - t.Assert((Int.Parse("-101", 2)!.Format(16)!) == "-5", "23) -101 != -5") - t.Assert((Int.Parse("1111010101", 2)!.Format(16)!) == "3D5", "24) 1111010101 != 3D5") - t.Assert((Int.Parse("-10001101101110101011110110000110111111101101", 2)!.Format(16)!) == "-8DBABD86FED", "25) -10001101101110101011110110000110111111101101 != -8DBABD86FED") - t.Assert((Int.Parse("100111001110111001111001111111010101001001011000000000110101110110111110110000101101001", 2)!.Format(16)!) == "4E773CFEA92C01AEDF6169", "26) 100111001110111001111001111111010101001001011000000000110101110110111110110000101101001 != 4E773CFEA92C01AEDF6169") + // Binary + t.Assert((Int.Parse("11101110101", 2)!.Format(2)!) == "11101110101", "1) 11101110101 != 11101110101") + t.Assert((Int.Parse("-000000", 2)!.Format(2)!) == "0", "2) -000000 != 0") + t.Assert((Int.Parse("000000", 2)!.Format(2)!) == "0", "3) 000000 != 0") + t.Assert((Int.Parse("-00111", 2)!.Format(2)!) == "-111", "4) 00111 != -111") + t.Assert((Int.Parse("1010", 2)!.Format(2)!) == "1010", "5) 1010 != 1010") + + // Octal + t.Assert((Int.Parse("1010", 2)!.Format(8)!) == "12", "6) 1010 != 12") + t.Assert((Int.Parse("101", 2)!.Format(8)!) == "5", "7) 101 != 5") + t.Assert((Int.Parse("-1010", 2)!.Format(8)!) == "-12", "8) -1010 != -12") + t.Assert((Int.Parse("-101", 2)!.Format(8)!) == "-5", "9) -101 != -5") + t.Assert((Int.Parse("1111010101", 2)!.Format(8)!) == "1725", "10) 1111010101 != 1725") + t.Assert((Int.Parse("-10001101101110101011110110000110111111101101", 2)!.Format(8)!) == "-215565366067755", "11) -10001101101110101011110110000110111111101101 != -215565366067755") + t.Assert((Int.Parse("100111001110111001111001111111010101001001011000000000110101110110111110110000101101001", 2)!.Format(8)!) == "47167171772511300065667660551", "12) 100111001110111001111001111111010101001001011000000000110101110110111110110000101101001 != 47167171772511300065667660551") + + // Decimal + t.Assert((Int.Parse("1010", 2)!.Format(10)!) == "10", "13) 1010 != 10") + t.Assert((Int.Parse("101", 2)!.Format(10)!) == "5", "14) 101 != 5") + t.Assert((Int.Parse("-1010", 2)!.Format(10)!) == "-10", "15) -1010 != -10") + t.Assert((Int.Parse("-101", 2)!.Format(10)!) == "-5", "16) -101 != -5") + t.Assert((Int.Parse("1111010101", 2)!.Format(10)!) == "981", "17) 1111010101 != 981") + t.Assert((Int.Parse("-10001101101110101011110110000110111111101101", 2)!.Format(10)!) == "-9739573948397", "18) -10001101101110101011110110000110111111101101 != -9739573948397") + t.Assert((Int.Parse("100111001110111001111001111111010101001001011000000000110101110110111110110000101101001", 2)!.Format(10)!) == "94859300696293528418869609", "19) 100111001110111001111001111111010101001001011000000000110101110110111110110000101101001 != 94859300696293528418869609") + + // Hexadecimal + t.Assert((Int.Parse("1010", 2)!.Format(16)!) == "A", "20) 1010 != A") + t.Assert((Int.Parse("101", 2)!.Format(16)!) == "5", "21) 101 != 5") + t.Assert((Int.Parse("-1010", 2)!.Format(16)!) == "-A", "22) -1010 != -A") + t.Assert((Int.Parse("-101", 2)!.Format(16)!) == "-5", "23) -101 != -5") + t.Assert((Int.Parse("1111010101", 2)!.Format(16)!) == "3D5", "24) 1111010101 != 3D5") + t.Assert((Int.Parse("-10001101101110101011110110000110111111101101", 2)!.Format(16)!) == "-8DBABD86FED", "25) -10001101101110101011110110000110111111101101 != -8DBABD86FED") + t.Assert((Int.Parse("100111001110111001111001111111010101001001011000000000110101110110111110110000101101001", 2)!.Format(16)!) == "4E773CFEA92C01AEDF6169", "26) 100111001110111001111001111111010101001001011000000000110101110110111110110000101101001 != 4E773CFEA92C01AEDF6169") } \ No newline at end of file diff --git a/std/math/big/nat.jule b/std/math/big/nat.jule index 89fe20eb4..6ff57c14a 100644 --- a/std/math/big/nat.jule +++ b/std/math/big/nat.jule @@ -6,446 +6,446 @@ use std::unsafe // An arbitrary-precision natural number. struct nat { - mut bits: bits + mut bits: bits } impl nat { - // Returns nat that represents zero. - static fn zero(): nat { - ret nat{} - } - - // Returns nat that represents one. - static fn one(): nat { - ret nat{ - bits: [1], - } - } - - // Returns nat that initialized by integer value. - // T can only be signed or unsigned integer types. - static fn new[T](mut i: T): nat { - const match type T { - | nat: - ret i - } - mut nat := nat.zero() - const match type T { - | i8: - nat.bits = make(bits, 1 << 3 - 1) - | u8: - nat.bits = make(bits, 1 << 3) - | i16: - nat.bits = make(bits, 1 << 4 - 1) - | u16: - nat.bits = make(bits, 1 << 4) - | i32: - nat.bits = make(bits, 1 << 5 - 1) - | u32: - nat.bits = make(bits, 1 << 5) - | i64: - nat.bits = make(bits, 1 << 6 - 1) - | u64: - nat.bits = make(bits, 1 << 6) - | int: - nat.bits = make(bits, _INT_SIZE - 1) - | uint: - nat.bits = make(bits, _INT_SIZE) - |: - panic("std::math::big: nat.new[T]: T is should be signed or unsigned integer type except uintptr") - } - if i < 0 { - i = -i - } - for j in nat.bits { - nat.bits[j] = bit((i >> j) & 0b1) - } - nat.fit() - ret nat - } - - // Parse nat from string. Fmt is the format of string. - // Results with exceptional if bits are not in the format or empty. - // Results with exceptional if fmt is not valid. - // Exceptional is always BigError.Format. - // - // Valid fmt values are; - // - 2 for binary. - // - 8 for octal. - // - 10 for decimal. - // - 16 for hexadecimal. - static fn parse(s: str, fmt: int)!: nat { - if s == "" { - error(BigError.Format) - } - mut r := nat{} - match fmt { - | 2: - r.bits = parseBinary(s) else { error(error) } - | 8: - r.bits = parseOctal(s) else { error(error) } - | 10: - r.bits = parseDecimal(s) else { error(error) } - | 16: - r.bits = parseHex(s) else { error(error) } - |: - error(BigError.Format) - } - ret r - } - - // Returns count of bits. - // Return value also means the minimum number of bits that can represent the integer. - fn len(self): int { - ret len(self.bits) - } - - // Eliminates initial-zeros, normalizes bits. - fn fit(mut self) { - fit(self.bits) - } - - // Adds two nat and returns result. - fn Add(self, y: nat): nat { - mut r := self - r += y - ret r - } - - // Adds nat. - fn AddAssign(mut self, y: nat) { - if y.len() == 0 { - ret - } - self.bits = cloneBits(self.bits) - addRes(self.bits, y.bits) - } - - // Subtracts two nat and returns result. - fn Sub(self, y: nat): nat { - mut r := self - r -= y - ret r - } - - // Subtracts nat. - fn SubAssign(mut self, y: nat) { - if y.len() == 0 { - ret - } - self.bits = cloneBits(self.bits) - subRes(self.bits, y.bits) - self.fit() - } - - // Multiplies two nat and returns result. - fn Mul(self, y: nat): nat { - mut r := self - r *= y - ret r - } - - // Multiplies nat. - fn MulAssign(mut self, y: nat) { - match y.len() { - | 1: - ret - | 0: - // Right operand is zero, result is always zero. - self.bits = nil - ret - } - if self.len() == 0 { - // Right operand is zero, result is always zero. - self.bits = nil - ret - } - - // The opeand y is small number. - // Use basic algorithm instead of karatsuba. - if y.len() < karatsubaThreshold { - self.bits = basicMul(self.bits, y.bits) - } else { - self.bits = karatsuba(self.bits, y.bits) - } - self.fit() - } - - // Divides two nat and returns result. - fn Div(self, y: nat): nat { - mut r := self - r /= y - ret r - } - - // Divides nat. - fn DivAssign(mut self, y: nat) { - if self.len() == 0 { - // Left operans is zero, remainder is always zero. - ret - } - match y.len() { - | 1: - // Right operand is 1, quotient is always equals to left operand. - ret - | 0: - panic("std::math::big: division by zero") - } - match self.cmp(y) { - | -1: - // Left operand is less than right oprand. - // Quotient is always equals to zero. - self.bits = nil - ret - | 0: - // Left oprand and right operand are equal. - // Quotient is always zero. - self.bits = [1] - ret - } - mut xb := cloneBits(self.bits) - mut q := make(bits, len(xb)) - _ = copy(q[len(q)-len(y.bits):], y.bits) - mut s := make(bits, len(xb)) - recursiveDiv(xb, y.bits, s, q) - self.bits = s - self.fit() - } - - // Modulo two nat and returns result. - fn Mod(self, y: nat): nat { - mut r := self - r %= y - ret r - } - - // Modulo nat. - fn ModAssign(mut self, y: nat) { - if self.len() == 0 { - // Left operans is zero, remainder is always zero. - ret - } - match { - | y.len() == 1: - // Right operand is 1, remainder is always zero. - self.bits = nil - ret - | y.len() == 2 && y.bits[0] == 0b0: - // Right operand is 2. - // If left opeand is even, remainder is always zero. - // If left operand is odd, remainder is always one. - if self.even() { - self.bits = nil - } else { - self.bits = [1] - } - ret - | y.len() == 0: - panic("std::math::big: division by zero") - } - match self.cmp(y) { - | -1: - // Left operand less than right operand. - // Remainder always equals to left operand. - ret - | 0: - // Left oprand and right operand are equal. - // Remainder is always zero. - self.bits = nil - ret - } - mut xb := cloneBits(self.bits) - mut q := make(bits, len(xb)) - _ = copy(q[len(q)-len(y.bits):], y.bits) - self.bits = recursiveMod(xb, y.bits, q) - self.fit() - } - - // Bitwise left shift. - fn Shl(self, y: int): nat { - mut r := self - r <<= y - ret r - } - - // Bitwise left shift for assignment. - fn ShlAssign(mut self, y: int) { - self.bits = lsh(self.bits, y) - } - - // Bitwise right shift. - fn Shr(self, y: int): nat { - mut r := self - r >>= y - ret r - } - - // Bitwise right shift for assignment. - fn ShrAssign(mut self, y: int) { - self.bits = rsh(self.bits, y) - } - - // Bitwise or. - fn BitOr(self, y: nat): nat { - mut r := self - r |= y - ret r - } - - // Bitwise or for assignment. - fn BitOrAssign(mut self, y: nat) { - if self.len() < y.len() { - self = y | self - ret - } - self.bits = cloneBits(self.bits) - or(self.bits, y.bits) - self.fit() - } - - // Bitwise and. - fn BitAnd(self, y: nat): nat { - mut r := self - r &= y - ret r - } - - // Bitwise and for assignment. - fn BitAndAssign(mut self, y: nat) { - if self.len() < y.len() { - self = y & self - ret - } - self.bits = cloneBits(self.bits) - and(self.bits, y.bits) - self.fit() - } - - // Bitwise and. - fn BitXor(self, y: nat): nat { - mut r := self - r ^= y - ret r - } - - // Bitwise xor for assignment. - fn BitXorAssign(mut self, y: nat) { - if self.len() < y.len() { - self = y ^ self - ret - } - self.bits = cloneBits(self.bits) - xor(self.bits, y.bits) - self.fit() - } - - // Compares bits. - // Returns +1 if self > y. - // Returns 0 if self == y. - // Returns -1 if self < y. - fn cmp(self, y: nat): int { - ret cmp(self.bits, y.bits) - } - - // Reports whether integer less than other. - fn Lt(self, y: nat): bool { - ret self.cmp(y) == -1 - } - - // Reports whether integer less than or equals to other. - fn LtEq(self, y: nat): bool { - ret self.cmp(y) < +1 - } - - // Reports whether integer greater than other. - fn Gt(self, y: nat): bool { - ret self.cmp(y) == +1 - } - - // Reports whether integer greater than or equals to other. - fn GtEq(self, y: nat): bool { - ret self.cmp(y) > -1 - } - - // Reports whether bits are equals. - fn Eq(self, y: nat): bool { - ret self.cmp(y) == 0 - } - - // Reports whether number is odd. - fn odd(self): bool { - ret isOdd(self.bits) - } - - // Reports whether number is even. - fn even(self): bool { - ret isEven(self.bits) - } - - // Returns bit by index. - // The index zero means first bit at right. - fn bit(self, i: int): int { - if i < 0 { - panic("std::math::big: negative bit index") - } - if i >= self.len() { - ret 0 - } - ret int(self.bits[i]) - } - - // Returns count of trailing zeros. - fn trailingZeros(self): int { - for i, b in self.bits { - if b != 0b0 { - ret i - } - } - ret 0 - } - - // Format number into string. Fmt is the format of number. - // Results with exceptional if fmt is not valid. - // Exceptional is always BigError.Format. - // - // Valid fmt values are; - // - 2 for binary. - // - 8 for octal. - /// - 10 for decimal. - /// - 16 for hexadecimal. - fn format(self, fmt: int)!: str { - match fmt { - | 2: - ret formatBinary(self.bits) - | 8: - ret formatOctal(self.bits) - | 10: - ret formatDecimal(self.bits) - | 16: - ret formatHex(self.bits) - |: - error(BigError.Format) - } - } - - // Returns integer in u64. - // Causes exception if nuber large than capacity of u64. - // Exception is always equals to u64.Max constant. - fn toU64(self)!: u64 { - if self.len() > 64 { - error(u64.Max) - } - ret u64FromBits(self.bits) - } - - // Formats number with self.format(10) by default. - fn toStr(self): str { - ret self.format(10)! - } - - fn clone(self): nat { - ret nat{ - bits: cloneBits(self.bits), - } - } + // Returns nat that represents zero. + static fn zero(): nat { + ret nat{} + } + + // Returns nat that represents one. + static fn one(): nat { + ret nat{ + bits: [1], + } + } + + // Returns nat that initialized by integer value. + // T can only be signed or unsigned integer types. + static fn new[T](mut i: T): nat { + const match type T { + | nat: + ret i + } + mut nat := nat.zero() + const match type T { + | i8: + nat.bits = make(bits, 1 << 3 - 1) + | u8: + nat.bits = make(bits, 1 << 3) + | i16: + nat.bits = make(bits, 1 << 4 - 1) + | u16: + nat.bits = make(bits, 1 << 4) + | i32: + nat.bits = make(bits, 1 << 5 - 1) + | u32: + nat.bits = make(bits, 1 << 5) + | i64: + nat.bits = make(bits, 1 << 6 - 1) + | u64: + nat.bits = make(bits, 1 << 6) + | int: + nat.bits = make(bits, _INT_SIZE - 1) + | uint: + nat.bits = make(bits, _INT_SIZE) + |: + panic("std::math::big: nat.new[T]: T is should be signed or unsigned integer type except uintptr") + } + if i < 0 { + i = -i + } + for j in nat.bits { + nat.bits[j] = bit((i >> j) & 0b1) + } + nat.fit() + ret nat + } + + // Parse nat from string. Fmt is the format of string. + // Results with exceptional if bits are not in the format or empty. + // Results with exceptional if fmt is not valid. + // Exceptional is always BigError.Format. + // + // Valid fmt values are; + // - 2 for binary. + // - 8 for octal. + // - 10 for decimal. + // - 16 for hexadecimal. + static fn parse(s: str, fmt: int)!: nat { + if s == "" { + error(BigError.Format) + } + mut r := nat{} + match fmt { + | 2: + r.bits = parseBinary(s) else { error(error) } + | 8: + r.bits = parseOctal(s) else { error(error) } + | 10: + r.bits = parseDecimal(s) else { error(error) } + | 16: + r.bits = parseHex(s) else { error(error) } + |: + error(BigError.Format) + } + ret r + } + + // Returns count of bits. + // Return value also means the minimum number of bits that can represent the integer. + fn len(self): int { + ret len(self.bits) + } + + // Eliminates initial-zeros, normalizes bits. + fn fit(mut self) { + fit(self.bits) + } + + // Adds two nat and returns result. + fn Add(self, y: nat): nat { + mut r := self + r += y + ret r + } + + // Adds nat. + fn AddAssign(mut self, y: nat) { + if y.len() == 0 { + ret + } + self.bits = cloneBits(self.bits) + addRes(self.bits, y.bits) + } + + // Subtracts two nat and returns result. + fn Sub(self, y: nat): nat { + mut r := self + r -= y + ret r + } + + // Subtracts nat. + fn SubAssign(mut self, y: nat) { + if y.len() == 0 { + ret + } + self.bits = cloneBits(self.bits) + subRes(self.bits, y.bits) + self.fit() + } + + // Multiplies two nat and returns result. + fn Mul(self, y: nat): nat { + mut r := self + r *= y + ret r + } + + // Multiplies nat. + fn MulAssign(mut self, y: nat) { + match y.len() { + | 1: + ret + | 0: + // Right operand is zero, result is always zero. + self.bits = nil + ret + } + if self.len() == 0 { + // Right operand is zero, result is always zero. + self.bits = nil + ret + } + + // The opeand y is small number. + // Use basic algorithm instead of karatsuba. + if y.len() < karatsubaThreshold { + self.bits = basicMul(self.bits, y.bits) + } else { + self.bits = karatsuba(self.bits, y.bits) + } + self.fit() + } + + // Divides two nat and returns result. + fn Div(self, y: nat): nat { + mut r := self + r /= y + ret r + } + + // Divides nat. + fn DivAssign(mut self, y: nat) { + if self.len() == 0 { + // Left operans is zero, remainder is always zero. + ret + } + match y.len() { + | 1: + // Right operand is 1, quotient is always equals to left operand. + ret + | 0: + panic("std::math::big: division by zero") + } + match self.cmp(y) { + | -1: + // Left operand is less than right oprand. + // Quotient is always equals to zero. + self.bits = nil + ret + | 0: + // Left oprand and right operand are equal. + // Quotient is always zero. + self.bits = [1] + ret + } + mut xb := cloneBits(self.bits) + mut q := make(bits, len(xb)) + _ = copy(q[len(q)-len(y.bits):], y.bits) + mut s := make(bits, len(xb)) + recursiveDiv(xb, y.bits, s, q) + self.bits = s + self.fit() + } + + // Modulo two nat and returns result. + fn Mod(self, y: nat): nat { + mut r := self + r %= y + ret r + } + + // Modulo nat. + fn ModAssign(mut self, y: nat) { + if self.len() == 0 { + // Left operans is zero, remainder is always zero. + ret + } + match { + | y.len() == 1: + // Right operand is 1, remainder is always zero. + self.bits = nil + ret + | y.len() == 2 && y.bits[0] == 0b0: + // Right operand is 2. + // If left opeand is even, remainder is always zero. + // If left operand is odd, remainder is always one. + if self.even() { + self.bits = nil + } else { + self.bits = [1] + } + ret + | y.len() == 0: + panic("std::math::big: division by zero") + } + match self.cmp(y) { + | -1: + // Left operand less than right operand. + // Remainder always equals to left operand. + ret + | 0: + // Left oprand and right operand are equal. + // Remainder is always zero. + self.bits = nil + ret + } + mut xb := cloneBits(self.bits) + mut q := make(bits, len(xb)) + _ = copy(q[len(q)-len(y.bits):], y.bits) + self.bits = recursiveMod(xb, y.bits, q) + self.fit() + } + + // Bitwise left shift. + fn Shl(self, y: int): nat { + mut r := self + r <<= y + ret r + } + + // Bitwise left shift for assignment. + fn ShlAssign(mut self, y: int) { + self.bits = lsh(self.bits, y) + } + + // Bitwise right shift. + fn Shr(self, y: int): nat { + mut r := self + r >>= y + ret r + } + + // Bitwise right shift for assignment. + fn ShrAssign(mut self, y: int) { + self.bits = rsh(self.bits, y) + } + + // Bitwise or. + fn BitOr(self, y: nat): nat { + mut r := self + r |= y + ret r + } + + // Bitwise or for assignment. + fn BitOrAssign(mut self, y: nat) { + if self.len() < y.len() { + self = y | self + ret + } + self.bits = cloneBits(self.bits) + or(self.bits, y.bits) + self.fit() + } + + // Bitwise and. + fn BitAnd(self, y: nat): nat { + mut r := self + r &= y + ret r + } + + // Bitwise and for assignment. + fn BitAndAssign(mut self, y: nat) { + if self.len() < y.len() { + self = y & self + ret + } + self.bits = cloneBits(self.bits) + and(self.bits, y.bits) + self.fit() + } + + // Bitwise and. + fn BitXor(self, y: nat): nat { + mut r := self + r ^= y + ret r + } + + // Bitwise xor for assignment. + fn BitXorAssign(mut self, y: nat) { + if self.len() < y.len() { + self = y ^ self + ret + } + self.bits = cloneBits(self.bits) + xor(self.bits, y.bits) + self.fit() + } + + // Compares bits. + // Returns +1 if self > y. + // Returns 0 if self == y. + // Returns -1 if self < y. + fn cmp(self, y: nat): int { + ret cmp(self.bits, y.bits) + } + + // Reports whether integer less than other. + fn Lt(self, y: nat): bool { + ret self.cmp(y) == -1 + } + + // Reports whether integer less than or equals to other. + fn LtEq(self, y: nat): bool { + ret self.cmp(y) < +1 + } + + // Reports whether integer greater than other. + fn Gt(self, y: nat): bool { + ret self.cmp(y) == +1 + } + + // Reports whether integer greater than or equals to other. + fn GtEq(self, y: nat): bool { + ret self.cmp(y) > -1 + } + + // Reports whether bits are equals. + fn Eq(self, y: nat): bool { + ret self.cmp(y) == 0 + } + + // Reports whether number is odd. + fn odd(self): bool { + ret isOdd(self.bits) + } + + // Reports whether number is even. + fn even(self): bool { + ret isEven(self.bits) + } + + // Returns bit by index. + // The index zero means first bit at right. + fn bit(self, i: int): int { + if i < 0 { + panic("std::math::big: negative bit index") + } + if i >= self.len() { + ret 0 + } + ret int(self.bits[i]) + } + + // Returns count of trailing zeros. + fn trailingZeros(self): int { + for i, b in self.bits { + if b != 0b0 { + ret i + } + } + ret 0 + } + + // Format number into string. Fmt is the format of number. + // Results with exceptional if fmt is not valid. + // Exceptional is always BigError.Format. + // + // Valid fmt values are; + // - 2 for binary. + // - 8 for octal. + /// - 10 for decimal. + /// - 16 for hexadecimal. + fn format(self, fmt: int)!: str { + match fmt { + | 2: + ret formatBinary(self.bits) + | 8: + ret formatOctal(self.bits) + | 10: + ret formatDecimal(self.bits) + | 16: + ret formatHex(self.bits) + |: + error(BigError.Format) + } + } + + // Returns integer in u64. + // Causes exception if nuber large than capacity of u64. + // Exception is always equals to u64.Max constant. + fn toU64(self)!: u64 { + if self.len() > 64 { + error(u64.Max) + } + ret u64FromBits(self.bits) + } + + // Formats number with self.format(10) by default. + fn toStr(self): str { + ret self.format(10)! + } + + fn clone(self): nat { + ret nat{ + bits: cloneBits(self.bits), + } + } } \ No newline at end of file diff --git a/std/math/big/nat_test.jule b/std/math/big/nat_test.jule index 91c1f13df..8c3005495 100644 --- a/std/math/big/nat_test.jule +++ b/std/math/big/nat_test.jule @@ -7,309 +7,309 @@ use std::testing::{T} static casesNatFromBits = [ - "1011010", - "1111011000", - "10001100011000", - "10001101101110101011110110000110111111101101", - "10001100011111", - "11111111111111111111111110011", + "1011010", + "1111011000", + "10001100011000", + "10001101101110101011110110000110111111101101", + "10001100011111", + "11111111111111111111111110011", ] static casesNatAdd = [ - ["1011010", "1011010", "10110100"], - ["1011010", "0000001", "1011011"], - ["10011000000111", "100000101011101000", "100011000011101111"], - ["00000000000000", "00000000001", "1"], - ["100000101011101000", "111101100111111001", "1011110010011100001"], + ["1011010", "1011010", "10110100"], + ["1011010", "0000001", "1011011"], + ["10011000000111", "100000101011101000", "100011000011101111"], + ["00000000000000", "00000000001", "1"], + ["100000101011101000", "111101100111111001", "1011110010011100001"], ] static casesNatSub = [ - ["1011010", "1011010", ""], - ["1011010", "0000001", "1011001"], - ["100000101011101000", "10011000000111", "11110010011100001"], - ["100010", "110111001110", "110110101100"], - ["10001100001110", "111101101", "10000100100001"], - ["1010", "10100", "1010"], - ["101011", "11000", "10011"], - ["11101110111011111111111011110101010010101101111010101101010101010101011110011010010110010101110110010101101011001011", "11101110111011111111111011110101010010101101111010101101010101010101011110011010010110010101110110010101101011001010", "1"], + ["1011010", "1011010", ""], + ["1011010", "0000001", "1011001"], + ["100000101011101000", "10011000000111", "11110010011100001"], + ["100010", "110111001110", "110110101100"], + ["10001100001110", "111101101", "10000100100001"], + ["1010", "10100", "1010"], + ["101011", "11000", "10011"], + ["11101110111011111111111011110101010010101101111010101101010101010101011110011010010110010101110110010101101011001011", "11101110111011111111111011110101010010101101111010101101010101010101011110011010010110010101110110010101101011001010", "1"], ] static casesNatMul = [ - ["1011010", "1011010", "1111110100100"], - ["1011010", "1", "1011010"], - ["1011010", "0", ""], - ["1100010", "100", "110001000"], - ["100", "1100010", "110001000"], - ["10001101101110101011110110000110111111101101", "10001101101110101011110110000110111111101101", "100111001110111001111001111111010101001001011000000000110101110110111110110000101101001"], - ["100111001110111001111001111111010101001001011000000000110101110110111110110000101101001", "100111001110111001111001111111010101001001011000000000110101110110111110110000101101001", "11000000011001110000010110100111100100110000001110100100100001110010010011011011110100000111000000011100100101001011101010001010001100010011110010101111111101011110100010001"], - ["1010", "10", "10100"], - ["10", "1010", "10100"], - ["1010101010101010101010101010101010101010101010", "10", "10101010101010101010101010101010101010101010100"], - ["10", "1010101010101010101010101010101010101010101010", "10101010101010101010101010101010101010101010100"], - ["1011", "101", "110111"], - ["100110111011001001000001111000001111101010110110011010001111110011111001011101001001011011110100101011000100000110110100001010010101000000111111101010000101011010111011110101110111100000010100100100111110010101100111101110011001100110100000101000011100101010010001010111011001000001100010001101011000010011010100011011111011111001100010100000000000100001001011110111100011000000001100000110110001001000000100110100100110010011110100010100000010011110101000001010110010110001010001110000010111110001111111001011000110110010110110011001110011000110100001101001001101001111110101111000011111000000100101101011111010001001100011001100110010001110100000111110001010001011001101001011101100001001101011001100001101001010010111011000101110010101111101010000110101111110110101010111011010000100001011011010000011000110100100000011010011111011110010000111110001011011111100010000100000101100100101001011101111101011000011011001111111100101010100101001001111100001001000111000111000101101101011010001001110000010100001011110010011110000101010111010100011010101110010111111011010111101110010001100111010011011101101010110000010001101100111010010000110011111001100", "1001110110010001000000010110100001101000011010010110010001101100110011111001100", "101111111010100100000110011100101111100010111010000100000001001011001110001101110100000110010010011110110001101010010100100100110011010011010001101011001010011111000000000101110010110100111100010101001000110111010111000011010101001101010001011001111101011110010110110101000010010011010000100110110001100111011110001100011110111100011100010001011011111011101111000011011010110100011000111111011111110010001011111101111111011001010001110110000110101111010100000011111110111111101101011101000110010100101000111110000111010000110001001101101010111101001110101010000000000110101110011001000110000100010100111000110010111111010111100001110010110110001110010000001010000110100111000001011110101110011111010110010111111001010010111100101101111111100011100110001111010110100000111101110101100111100110101111101101000101101011010101110111011110011101000100000101010000101010100001010101011110011100011000110110100100111001110100101110011100111000111100011010100001011000111110000101111011011010010000011101100001110111111000111000111001111101111011100101000110110011000101000110000110010011111000111111000101011110101101101011101011110010011000010010101000111100110001000001100110010000011011001000011010011000101100011111011100101010010000"], - ["100110111011001001000001111000001111101010110110011010001111110011111001011101001001011011110100101011000100000110110100001010010101000000111111101010000101011010111011110101110111100000010100100100111110010101100111101110011001100110100000101000011100101010010001010111011001000001100010001101011000010011010100011011111011111001100010100000000000100001001011110111100011000000001100000110110001001000000100110100100110010011110100010100000010011110101000001010110010110001010001110000010111110001111111001011000110110010110110011001110011000110100001101001001101001111110101111000011111000000100101101011111010001001100011001100110010001110100000111110001010001011001101001011101100001001101011001100001101001010010111011000101110010101111101010000110101111110110101010111011010000100001011011010000011000110100100000011010011111011110010000111110001011011111100010000100000101100100101001011101111101011000011011001111111100101010100101001001111100001001000111000111000101101101011010001001110000010100001011110010011110000101010111010100011010101110010111111011010111101110010001100111010011011101101010110000010001101100111010010000110011111001100", "10101011110000001101101110000010111111100010001110001001110111110101111000110110010011001011111100010001011000010100100100001000011001001111101010101110010101101100000000110100100110110100100101110111111110010111010011000100010001011011101010111011001000100010010111000100010001000000100101111101010100011011010101100001101110110000001111010000010000111101001011111011100111011100001001011011101001001101000011110100000010011001100", "1101000011101010101110100110011110110011010010101000110001111111000111000100110001110001101110100001111101110010111101001110100100100101010101111111110001001100011011010110001111001100101011110000111001101010000101110100000111110101101111001001110000111011000001101010110010100010011110110111110011001001001111010100011000100010000101110101011000011010101000100111111111011111001001010110100101111100111101000110101001000001101010010100100011101011110101101001111001111101000010011111010000111001010010001001010010001111001010000000110000111100110101110010110010010010111010101110101011001110010111100010010011100111111011001000000101101000111101110011010101101000100011101101011001111111001001110000110101100000011000010000111010000010101100101010100011000001000111100000100100111111100101010100001010101001110001111111111110110101001001110110001001010011101111011111110001001010111011101010000100001100011001000110001100000101100011110101011000100111010000011111110001111001000111101110110000100001011001100011010010110111101101101011010101111010100001101011100000110010100001110010000101011110111010111011001000000101000000101010001000010110010101101010010010110100010100101101100000000111100101100111011000110110010101110000110001100110011110000101010101001100010111000000100100010101111001111100001001000101010000001111111100101001101101001001000111100000000110101011001000000110001101001100001010001100110101110001011011001010101001111001101010000110000110101010011010000001010100011111111000111110110011101001101111001101000111011011011101011111000110100010011110011010010000"], + ["1011010", "1011010", "1111110100100"], + ["1011010", "1", "1011010"], + ["1011010", "0", ""], + ["1100010", "100", "110001000"], + ["100", "1100010", "110001000"], + ["10001101101110101011110110000110111111101101", "10001101101110101011110110000110111111101101", "100111001110111001111001111111010101001001011000000000110101110110111110110000101101001"], + ["100111001110111001111001111111010101001001011000000000110101110110111110110000101101001", "100111001110111001111001111111010101001001011000000000110101110110111110110000101101001", "11000000011001110000010110100111100100110000001110100100100001110010010011011011110100000111000000011100100101001011101010001010001100010011110010101111111101011110100010001"], + ["1010", "10", "10100"], + ["10", "1010", "10100"], + ["1010101010101010101010101010101010101010101010", "10", "10101010101010101010101010101010101010101010100"], + ["10", "1010101010101010101010101010101010101010101010", "10101010101010101010101010101010101010101010100"], + ["1011", "101", "110111"], + ["100110111011001001000001111000001111101010110110011010001111110011111001011101001001011011110100101011000100000110110100001010010101000000111111101010000101011010111011110101110111100000010100100100111110010101100111101110011001100110100000101000011100101010010001010111011001000001100010001101011000010011010100011011111011111001100010100000000000100001001011110111100011000000001100000110110001001000000100110100100110010011110100010100000010011110101000001010110010110001010001110000010111110001111111001011000110110010110110011001110011000110100001101001001101001111110101111000011111000000100101101011111010001001100011001100110010001110100000111110001010001011001101001011101100001001101011001100001101001010010111011000101110010101111101010000110101111110110101010111011010000100001011011010000011000110100100000011010011111011110010000111110001011011111100010000100000101100100101001011101111101011000011011001111111100101010100101001001111100001001000111000111000101101101011010001001110000010100001011110010011110000101010111010100011010101110010111111011010111101110010001100111010011011101101010110000010001101100111010010000110011111001100", "1001110110010001000000010110100001101000011010010110010001101100110011111001100", "101111111010100100000110011100101111100010111010000100000001001011001110001101110100000110010010011110110001101010010100100100110011010011010001101011001010011111000000000101110010110100111100010101001000110111010111000011010101001101010001011001111101011110010110110101000010010011010000100110110001100111011110001100011110111100011100010001011011111011101111000011011010110100011000111111011111110010001011111101111111011001010001110110000110101111010100000011111110111111101101011101000110010100101000111110000111010000110001001101101010111101001110101010000000000110101110011001000110000100010100111000110010111111010111100001110010110110001110010000001010000110100111000001011110101110011111010110010111111001010010111100101101111111100011100110001111010110100000111101110101100111100110101111101101000101101011010101110111011110011101000100000101010000101010100001010101011110011100011000110110100100111001110100101110011100111000111100011010100001011000111110000101111011011010010000011101100001110111111000111000111001111101111011100101000110110011000101000110000110010011111000111111000101011110101101101011101011110010011000010010101000111100110001000001100110010000011011001000011010011000101100011111011100101010010000"], + ["100110111011001001000001111000001111101010110110011010001111110011111001011101001001011011110100101011000100000110110100001010010101000000111111101010000101011010111011110101110111100000010100100100111110010101100111101110011001100110100000101000011100101010010001010111011001000001100010001101011000010011010100011011111011111001100010100000000000100001001011110111100011000000001100000110110001001000000100110100100110010011110100010100000010011110101000001010110010110001010001110000010111110001111111001011000110110010110110011001110011000110100001101001001101001111110101111000011111000000100101101011111010001001100011001100110010001110100000111110001010001011001101001011101100001001101011001100001101001010010111011000101110010101111101010000110101111110110101010111011010000100001011011010000011000110100100000011010011111011110010000111110001011011111100010000100000101100100101001011101111101011000011011001111111100101010100101001001111100001001000111000111000101101101011010001001110000010100001011110010011110000101010111010100011010101110010111111011010111101110010001100111010011011101101010110000010001101100111010010000110011111001100", "10101011110000001101101110000010111111100010001110001001110111110101111000110110010011001011111100010001011000010100100100001000011001001111101010101110010101101100000000110100100110110100100101110111111110010111010011000100010001011011101010111011001000100010010111000100010001000000100101111101010100011011010101100001101110110000001111010000010000111101001011111011100111011100001001011011101001001101000011110100000010011001100", "1101000011101010101110100110011110110011010010101000110001111111000111000100110001110001101110100001111101110010111101001110100100100101010101111111110001001100011011010110001111001100101011110000111001101010000101110100000111110101101111001001110000111011000001101010110010100010011110110111110011001001001111010100011000100010000101110101011000011010101000100111111111011111001001010110100101111100111101000110101001000001101010010100100011101011110101101001111001111101000010011111010000111001010010001001010010001111001010000000110000111100110101110010110010010010111010101110101011001110010111100010010011100111111011001000000101101000111101110011010101101000100011101101011001111111001001110000110101100000011000010000111010000010101100101010100011000001000111100000100100111111100101010100001010101001110001111111111110110101001001110110001001010011101111011111110001001010111011101010000100001100011001000110001100000101100011110101011000100111010000011111110001111001000111101110110000100001011001100011010010110111101101101011010101111010100001101011100000110010100001110010000101011110111010111011001000000101000000101010001000010110010101101010010010110100010100101101100000000111100101100111011000110110010101110000110001100110011110000101010101001100010111000000100100010101111001111100001001000101010000001111111100101001101101001001000111100000000110101011001000000110001101001100001010001100110101110001011011001010101001111001101010000110000110101010011010000001010100011111111000111110110011101001101111001101000111011011011101011111000110100010011110011010010000"], ] static casesNatDiv = [ - ["1010", "1", "1010"], - ["1010", "10", "101"], - ["1000000", "110", "1010"], - ["1001100", "11", "11001"], - ["1000000", "100", "10000"], - ["11111011", "1101", "10011"], - ["10", "11", ""], - ["10011011001110001", "111", "10110001011001"], - ["10011001101010", "10", "1001100110101"], - ["1010101010101010101010101010101010101010101010", "10", "101010101010101010101010101010101010101010101"], - ["100111001110111001111001111111010101001001011000000000110101110110111110110000101101001", "10", "10011100111011100111100111111101010100100101100000000011010111011011111011000010110100"], - ["110101101011110101010100111", "110100", "1000010000100101101111"], - ["110101101011110101010100111", "11011001", "1111110101010101010"], + ["1010", "1", "1010"], + ["1010", "10", "101"], + ["1000000", "110", "1010"], + ["1001100", "11", "11001"], + ["1000000", "100", "10000"], + ["11111011", "1101", "10011"], + ["10", "11", ""], + ["10011011001110001", "111", "10110001011001"], + ["10011001101010", "10", "1001100110101"], + ["1010101010101010101010101010101010101010101010", "10", "101010101010101010101010101010101010101010101"], + ["100111001110111001111001111111010101001001011000000000110101110110111110110000101101001", "10", "10011100111011100111100111111101010100100101100000000011010111011011111011000010110100"], + ["110101101011110101010100111", "110100", "1000010000100101101111"], + ["110101101011110101010100111", "11011001", "1111110101010101010"], ] static casesNatMod = [ - ["1010", "1010", ""], - ["1010", "1", ""], - ["111001010111011001", "1110110", "11111"], - ["11101110111011111111111011110101010010101101111010101101010101010101011110011010010110010101110110010101101011001011", "1110101", "1011001"], - ["11110110110101010101010101111111111011010101010101010101001111111001010101001010101010110000000011111101101001010111001111", "1110101", "1100001"], - ["0", "11100111", ""], - ["0", "0", ""], - ["110101101011110101010100111", "110100", "11011"], - ["1010", "11", "1"], + ["1010", "1010", ""], + ["1010", "1", ""], + ["111001010111011001", "1110110", "11111"], + ["11101110111011111111111011110101010010101101111010101101010101010101011110011010010110010101110110010101101011001011", "1110101", "1011001"], + ["11110110110101010101010101111111111011010101010101010101001111111001010101001010101010110000000011111101101001010111001111", "1110101", "1100001"], + ["0", "11100111", ""], + ["0", "0", ""], + ["110101101011110101010100111", "110100", "11011"], + ["1010", "11", "1"], ] static casesNatShl: [][]u64 = [ - [1, 8, 256], - [9834, 32, 42236708388864], - [9383, 0, 9383], - [9383, 1, 18766], - [0, 20, 0], - [0, 0, 0], - [123456789, 8, 31604937984], + [1, 8, 256], + [9834, 32, 42236708388864], + [9383, 0, 9383], + [9383, 1, 18766], + [0, 20, 0], + [0, 0, 0], + [123456789, 8, 31604937984], ] static casesNatShr: [][]u64 = [ - [64, 2, 16], - [256, 8, 1], - [89357, 9, 174], - [3759375747438473473, 49, 6677], - [0, 90, 0], - [2, 90, 0], + [64, 2, 16], + [256, 8, 1], + [89357, 9, 174], + [3759375747438473473, 49, 6677], + [0, 90, 0], + [2, 90, 0], ] static casesNatBitOr: [][]u64 = [ - [20, 4, 20], - [4, 20, 20], - [345, 2, 347], - [908474739, 747688553334, 748259113847], - [97799739579632223, 1234567890, 97799739731806943], + [20, 4, 20], + [4, 20, 20], + [345, 2, 347], + [908474739, 747688553334, 748259113847], + [97799739579632223, 1234567890, 97799739731806943], ] static casesNatBitAnd: [][]u64 = [ - [902984, 24, 8], - [24, 902984, 8], - [902984, 2434, 256], - [2434, 902984, 256], - [77786486463864864, 97774749933, 19360907296], - [123456789, 987654321, 39471121], + [902984, 24, 8], + [24, 902984, 8], + [902984, 2434, 256], + [2434, 902984, 256], + [77786486463864864, 97774749933, 19360907296], + [123456789, 987654321, 39471121], ] static casesNatBitXor: [][]u64 = [ - [10, 11, 1], - [87793, 5, 87796], - [5, 87793, 87796], - [10, 1, 11], - [1, 10, 11], - [12345, 54321, 58376], - [123, 321, 314], - [1234567890, 9876543210, 8676316216], + [10, 11, 1], + [87793, 5, 87796], + [5, 87793, 87796], + [10, 1, 11], + [1, 10, 11], + [12345, 54321, 58376], + [123, 321, 314], + [1234567890, 9876543210, 8676316216], ] static casesNatTrailingZeros = [ - [0b111010101010111101010110000000, 7], - [0b111111111111111111111110000000, 7], - [0, 0], - [1, 0], - [0b10, 1], - [0b101101000, 3], + [0b111010101010111101010110000000, 7], + [0b111111111111111111111110000000, 7], + [0, 0], + [1, 0], + [0b10, 1], + [0b101101000, 3], ] #test fn testNatFromBits(t: &T) { - for _, c in casesNatFromBits { - n := nat.parse(c, 2) else { - t.Errorf("exceptional occurs: {}", error) - continue - } - if len(n.bits) != len(c) { - t.Errorf("{} != {}", c, c) - continue - } - for i, b in n.bits { - cb := c[len(c)-1-i] - if b == 0b1 && cb != '1' || - b == 0b0 && cb != '0' { - t.Errorf("{} != {}", c, c) - break - } - } - } + for _, c in casesNatFromBits { + n := nat.parse(c, 2) else { + t.Errorf("exceptional occurs: {}", error) + continue + } + if len(n.bits) != len(c) { + t.Errorf("{} != {}", c, c) + continue + } + for i, b in n.bits { + cb := c[len(c)-1-i] + if b == 0b1 && cb != '1' || + b == 0b0 && cb != '0' { + t.Errorf("{} != {}", c, c) + break + } + } + } } fn testCommonNatOp(&t: &T, op: str, &cases: [][]str) { - for _, c in cases { - mut n1 := nat.parse(c[0], 2) else { - t.Errorf("exception occurs: {}", error) - continue - } - n2 := nat.parse(c[1], 2) else { - t.Errorf("exception occurs: {}", error) - continue - } - match op { - | "+": - n1 += n2 - | "-": - n1 -= n2 - | "*": - n1 *= n2 - | "/": - n1 /= n2 - | "%": - n1 %= n2 - } - cr := c[2] - if n1.len() != len(cr) { - t.Errorf("{} {} {} != {}", c[0], op, c[1], cr) - continue - } - for i, b in n1.bits { - cb := cr[len(cr)-1-i] - if b == 0b1 && cb != '1' || - b == 0b0 && cb != '0' { - t.Errorf("{} {} {} != {}", c[0], op, c[1], cr) - break - } - } - } + for _, c in cases { + mut n1 := nat.parse(c[0], 2) else { + t.Errorf("exception occurs: {}", error) + continue + } + n2 := nat.parse(c[1], 2) else { + t.Errorf("exception occurs: {}", error) + continue + } + match op { + | "+": + n1 += n2 + | "-": + n1 -= n2 + | "*": + n1 *= n2 + | "/": + n1 /= n2 + | "%": + n1 %= n2 + } + cr := c[2] + if n1.len() != len(cr) { + t.Errorf("{} {} {} != {}", c[0], op, c[1], cr) + continue + } + for i, b in n1.bits { + cb := cr[len(cr)-1-i] + if b == 0b1 && cb != '1' || + b == 0b0 && cb != '0' { + t.Errorf("{} {} {} != {}", c[0], op, c[1], cr) + break + } + } + } } #test fn testNatAdd(t: &T) { - testCommonNatOp(t, "+", casesNatAdd) + testCommonNatOp(t, "+", casesNatAdd) } #test fn testNatSub(t: &T) { - testCommonNatOp(t, "-", casesNatSub) + testCommonNatOp(t, "-", casesNatSub) } #test fn testNatMul(t: &T) { - testCommonNatOp(t, "*", casesNatMul) + testCommonNatOp(t, "*", casesNatMul) } #test fn testNatDiv(t: &T) { - testCommonNatOp(t, "/", casesNatDiv) + testCommonNatOp(t, "/", casesNatDiv) } #test fn testNatMod(t: &T) { - testCommonNatOp(t, "%", casesNatMod) + testCommonNatOp(t, "%", casesNatMod) } fn testNatBitBinary(&t: &T, op: str, &cases: [][]u64) { - for _, c in cases { - mut n1 := nat.new(c[0]) - n2 := nat.new(c[1]) - match op { - | "|": - n1 |= n2 - | "&": - n1 &= n2 - | "^": - n1 ^= n2 - } - u := n1.toU64()! - if u != c[2] { - t.Errorf("{} {} {} != {}", c[0], op, c[1], c[2]) - } - } + for _, c in cases { + mut n1 := nat.new(c[0]) + n2 := nat.new(c[1]) + match op { + | "|": + n1 |= n2 + | "&": + n1 &= n2 + | "^": + n1 ^= n2 + } + u := n1.toU64()! + if u != c[2] { + t.Errorf("{} {} {} != {}", c[0], op, c[1], c[2]) + } + } } #test fn testNatBitOr(t: &T) { - testNatBitBinary(t, "|", casesNatBitOr) + testNatBitBinary(t, "|", casesNatBitOr) } #test fn testNatBitAnd(t: &T) { - testNatBitBinary(t, "&", casesNatBitAnd) + testNatBitBinary(t, "&", casesNatBitAnd) } #test fn testNatBitXor(t: &T) { - testNatBitBinary(t, "^", casesNatBitXor) + testNatBitBinary(t, "^", casesNatBitXor) } #test fn testNatShl(t: &T) { - for _, c in casesNatShl { - n := nat.new(c[0]) - mut r := n << int(c[1]) - u := r.toU64()! - if u != c[2] { - t.Errorf("{} << {} != {}", c[0], c[1], c[2]) - } - } + for _, c in casesNatShl { + n := nat.new(c[0]) + mut r := n << int(c[1]) + u := r.toU64()! + if u != c[2] { + t.Errorf("{} << {} != {}", c[0], c[1], c[2]) + } + } } #test fn testNatShr(t: &T) { - for _, c in casesNatShr { - n := nat.new(c[0]) - mut r := n >> int(c[1]) - u := r.toU64()! - if u != c[2] { - t.Errorf("{} >> {} != {}", c[0], c[1], c[2]) - } - } + for _, c in casesNatShr { + n := nat.new(c[0]) + mut r := n >> int(c[1]) + u := r.toU64()! + if u != c[2] { + t.Errorf("{} >> {} != {}", c[0], c[1], c[2]) + } + } } #test fn testNatTrailingBits(t: &T) { - for _, c in casesNatTrailingZeros { - n := nat.new(c[0]) - zeros := n.trailingZeros() - if zeros != c[1] { - t.Errorf("expected {}, found {}, for input {}", c[1], zeros, c[0]) - } - } + for _, c in casesNatTrailingZeros { + n := nat.new(c[0]) + zeros := n.trailingZeros() + if zeros != c[1] { + t.Errorf("expected {}, found {}, for input {}", c[1], zeros, c[0]) + } + } } #test fn testNatLt(t: &T) { - t.Assert(!nat.parse("1011010", 2)!.Lt(nat.parse("00001011010", 2)!), "1) 1011010 < 00001011010") - t.Assert(!nat.parse("1111011000", 2)!.Lt(nat.parse("000000000001111011000", 2)!), "2) 1111011000 < 000000000001111011000") - t.Assert(!nat.parse("10001100011000", 2)!.Lt(nat.parse("100011", 2)!), "3) 10001100011000 < 100011") - t.Assert(!nat.parse("10001101101110101011110110000110111111101111", 2)!.Lt(nat.parse("10001101101110101011110110000110111111101101", 2)!), "4) 10001101101110101011110110000110111111101111 < 10001101101110101011110110000110111111101101") + t.Assert(!nat.parse("1011010", 2)!.Lt(nat.parse("00001011010", 2)!), "1) 1011010 < 00001011010") + t.Assert(!nat.parse("1111011000", 2)!.Lt(nat.parse("000000000001111011000", 2)!), "2) 1111011000 < 000000000001111011000") + t.Assert(!nat.parse("10001100011000", 2)!.Lt(nat.parse("100011", 2)!), "3) 10001100011000 < 100011") + t.Assert(!nat.parse("10001101101110101011110110000110111111101111", 2)!.Lt(nat.parse("10001101101110101011110110000110111111101101", 2)!), "4) 10001101101110101011110110000110111111101111 < 10001101101110101011110110000110111111101101") } #test fn testNatGt(t: &T) { - t.Assert(!nat.parse("1011010", 2)!.Gt(nat.parse("00001011010", 2)!), "1) 1011010 > 00001011010") - t.Assert(!nat.parse("1111011000", 2)!.Gt(nat.parse("000000000001111011000", 2)!), "2) 1111011000 > 000000000001111011000") - t.Assert(nat.parse("10001100011000", 2)!.Gt(nat.parse("100011", 2)!), "3) 10001100011000 <= 100011") - t.Assert(nat.parse("10001101101110101011110110000110111111101111", 2)!.Gt(nat.parse("10001101101110101011110110000110111111101101", 2)!), "4) 10001101101110101011110110000110111111101111 <= 10001101101110101011110110000110111111101101") - t.Assert(!nat.parse("10000100100001", 2)!.Gt(nat.parse("10011001101010", 2)!), "5) 10000100100001 >= 10011001101010") + t.Assert(!nat.parse("1011010", 2)!.Gt(nat.parse("00001011010", 2)!), "1) 1011010 > 00001011010") + t.Assert(!nat.parse("1111011000", 2)!.Gt(nat.parse("000000000001111011000", 2)!), "2) 1111011000 > 000000000001111011000") + t.Assert(nat.parse("10001100011000", 2)!.Gt(nat.parse("100011", 2)!), "3) 10001100011000 <= 100011") + t.Assert(nat.parse("10001101101110101011110110000110111111101111", 2)!.Gt(nat.parse("10001101101110101011110110000110111111101101", 2)!), "4) 10001101101110101011110110000110111111101111 <= 10001101101110101011110110000110111111101101") + t.Assert(!nat.parse("10000100100001", 2)!.Gt(nat.parse("10011001101010", 2)!), "5) 10000100100001 >= 10011001101010") } #test fn testNatEq(t: &T) { - t.Assert(nat.parse("1011010", 2)!.Eq(nat.parse("00001011010", 2)!), "1) 1011010 != 00001011010") - t.Assert(nat.parse("1111011000", 2)!.Eq(nat.parse("000000000001111011000", 2)!), "2) 1111011000 != 000000000001111011000") - t.Assert(nat.parse("10001100011000", 2)!.Eq(nat.parse("10001100011000", 2)!), "3) 10001100011000 != 10001100011000") - t.Assert(nat.parse("10001101101110101011110110000110111111101101", 2)!.Eq(nat.parse("10001101101110101011110110000110111111101101", 2)!), "4) 10001101101110101011110110000110111111101101 != 10001101101110101011110110000110111111101101") + t.Assert(nat.parse("1011010", 2)!.Eq(nat.parse("00001011010", 2)!), "1) 1011010 != 00001011010") + t.Assert(nat.parse("1111011000", 2)!.Eq(nat.parse("000000000001111011000", 2)!), "2) 1111011000 != 000000000001111011000") + t.Assert(nat.parse("10001100011000", 2)!.Eq(nat.parse("10001100011000", 2)!), "3) 10001100011000 != 10001100011000") + t.Assert(nat.parse("10001101101110101011110110000110111111101101", 2)!.Eq(nat.parse("10001101101110101011110110000110111111101101", 2)!), "4) 10001101101110101011110110000110111111101101 != 10001101101110101011110110000110111111101101") } \ No newline at end of file diff --git a/std/math/bits.jule b/std/math/bits.jule index e1fa4951c..6f69a8ba1 100644 --- a/std/math/bits.jule +++ b/std/math/bits.jule @@ -50,19 +50,19 @@ fn NaN(): f64 { ret F64FromBits(uvNaN) } // Reports whether f is an IEEE 754 “not-a-number” value. fn IsNaN(f: f64): bool { - // IEEE 754 says that only NaNs satisfy f != f. - // To avoid the floating-point hardware, could use: - // x: = f64_bits(f); - // ret u32(x>>shift)&mask == mask && x != uvinf && x != uvneginf - ret f != f + // IEEE 754 says that only NaNs satisfy f != f. + // To avoid the floating-point hardware, could use: + // x: = f64_bits(f); + // ret u32(x>>shift)&mask == mask && x != uvinf && x != uvneginf + ret f != f } // Returns positive infinity if sign >= 0, negative infinity if !sign < 0. fn Inf(sign: int): f64 { - if sign >= 0 { - ret F64FromBits(uvinf) - } - ret F64FromBits(uvneginf) + if sign >= 0 { + ret F64FromBits(uvinf) + } + ret F64FromBits(uvneginf) } // Reports whether f is an infinity, according to sign. @@ -70,19 +70,19 @@ fn Inf(sign: int): f64 { // If sign < 0, IsInf reports whether f is negative infinity. // If sign == 0, IsInf reports whether f is either infinity. fn IsInf(f: f64, sign: int): bool { - // Test for infinity by comparing against maximum float. - // To avoid the floating-point hardware, could use: - // x: = f64_bits(f); - // ret sign >= 0 && x == uvinf || sign <= 0 && x == uvneginf; - ret sign >= 0 && f > f64.Max || sign <= 0 && f < -f64.Max + // Test for infinity by comparing against maximum float. + // To avoid the floating-point hardware, could use: + // x: = f64_bits(f); + // ret sign >= 0 && x == uvinf || sign <= 0 && x == uvneginf; + ret sign >= 0 && f > f64.Max || sign <= 0 && f < -f64.Max } // Returns a normal number y and exponent exp // satisfying x == y × 2**exp. It assumes x is finite and non-zero. fn normalize(x: f64): (y: f64, exp: int) { - const SmallestNormal = 2.2250738585072014e-308 // 2**-1022 - if Abs(x) < SmallestNormal { - ret x * (1 << 52), -52 - } - ret x, 0 + const SmallestNormal = 2.2250738585072014e-308 // 2**-1022 + if Abs(x) < SmallestNormal { + ret x * (1 << 52), -52 + } + ret x, 0 } \ No newline at end of file diff --git a/std/math/bits/bits.jule b/std/math/bits/bits.jule index 3479af405..e62e0a7fe 100644 --- a/std/math/bits/bits.jule +++ b/std/math/bits/bits.jule @@ -66,67 +66,67 @@ fn LeadingZeros64(x: u64): int { ret 64 - Len64(x) } const _DE_BRUIJN32 = 0x077CB531 static _DE_BRUIJN32_TAB: [32]byte = [ - 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, - 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9, + 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, + 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9, ] const _DE_BRUIJN64 = 0x03f79d71b4ca8b09 static _DE_BRUIJN64_TAB: [64]byte = [ - 0, 1, 56, 2, 57, 49, 28, 3, 61, 58, 42, 50, 38, 29, 17, 4, - 62, 47, 59, 36, 45, 43, 51, 22, 53, 39, 33, 30, 24, 18, 12, 5, - 63, 55, 48, 27, 60, 41, 37, 16, 46, 35, 44, 21, 52, 32, 23, 11, - 54, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6, + 0, 1, 56, 2, 57, 49, 28, 3, 61, 58, 42, 50, 38, 29, 17, 4, + 62, 47, 59, 36, 45, 43, 51, 22, 53, 39, 33, 30, 24, 18, 12, 5, + 63, 55, 48, 27, 60, 41, 37, 16, 46, 35, 44, 21, 52, 32, 23, 11, + 54, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6, ] // Returns the number of trailing zero bits in x; the result is UintSize for x == 0. fn TrailingZeros(x: uint): int { - if UintSize == 32 { - ret TrailingZeros32(u32(x)) - } - ret TrailingZeros64(u64(x)) + if UintSize == 32 { + ret TrailingZeros32(u32(x)) + } + ret TrailingZeros64(u64(x)) } // Returns the number of trailing zero bits in x; the result is 8 for x == 0. fn TrailingZeros8(x: u8): int { - ret int(ntz8tab[x]) + ret int(ntz8tab[x]) } // Returns the number of trailing zero bits in x; the result is 16 for x == 0. fn TrailingZeros16(x: u16): int { - if x == 0 { - ret 16 - } - // see comment in trailing_zeros64 - ret int(_DE_BRUIJN32_TAB[u32(x&-x)*_DE_BRUIJN32>>(32-5)]) + if x == 0 { + ret 16 + } + // see comment in trailing_zeros64 + ret int(_DE_BRUIJN32_TAB[u32(x&-x)*_DE_BRUIJN32>>(32-5)]) } // Returns the number of trailing zero bits in x; the result is 32 for x == 0. fn TrailingZeros32(x: u32): int { - if x == 0 { - ret 32 - } - // see comment in trailing_zeros64 - ret int(_DE_BRUIJN32_TAB[(x&-x)*_DE_BRUIJN32>>(32-5)]) + if x == 0 { + ret 32 + } + // see comment in trailing_zeros64 + ret int(_DE_BRUIJN32_TAB[(x&-x)*_DE_BRUIJN32>>(32-5)]) } // Returns the number of trailing zero bits in x; the result is 64 for x == 0. fn TrailingZeros64(x: u64): int { - if x == 0 { - ret 64 - } - // If popcount is fast, replace code below with return popcount(^x & (x - 1)). - // - // x & -x leaves only the right-most bit set in the word. Let k be the - // index of that bit. Since only a single bit is set, the value is two - // to the power of k. Multiplying by a power of two is equivalent to - // left shifting, in this case by k bits. The de Bruijn (64 bit) constant - // is such that all six bit, consecutive substrings are distinct. - // Therefore, if we have a left shifted version of this constant we can - // find by how many bits it was shifted by looking at which six bit - // substring ended up at the top of the word. - // (Knuth, volume 4, section 7.3.1) - ret int(_DE_BRUIJN64_TAB[(x&-x)*_DE_BRUIJN64>>(64-6)]) + if x == 0 { + ret 64 + } + // If popcount is fast, replace code below with return popcount(^x & (x - 1)). + // + // x & -x leaves only the right-most bit set in the word. Let k be the + // index of that bit. Since only a single bit is set, the value is two + // to the power of k. Multiplying by a power of two is equivalent to + // left shifting, in this case by k bits. The de Bruijn (64 bit) constant + // is such that all six bit, consecutive substrings are distinct. + // Therefore, if we have a left shifted version of this constant we can + // find by how many bits it was shifted by looking at which six bit + // substring ended up at the top of the word. + // (Knuth, volume 4, section 7.3.1) + ret int(_DE_BRUIJN64_TAB[(x&-x)*_DE_BRUIJN64>>(64-6)]) } // --- ones_count --- @@ -139,56 +139,56 @@ const m4 = 0x0000ffff0000ffff // Returns the number of one bits ("population count") in x. fn OnesCount(x: uint): int { - if UintSize == 32 { - ret OnesCount32(u32(x)) - } - ret OnesCount64(u64(x)) + if UintSize == 32 { + ret OnesCount32(u32(x)) + } + ret OnesCount64(u64(x)) } // Returns the number of one bits ("population count") in x. fn OnesCount8(x: u8): int { - ret int(pop8tab[x]) + ret int(pop8tab[x]) } // Returns the number of one bits ("population count") in x. fn OnesCount16(x: u16): int { - ret int(pop8tab[x>>8] + pop8tab[x&0xff]) + ret int(pop8tab[x>>8] + pop8tab[x&0xff]) } // Returns the number of one bits ("population count") in x. fn OnesCount32(x: u32): int { - ret int(pop8tab[x>>24] + pop8tab[x>>16&0xff] + pop8tab[x>>8&0xff] + pop8tab[x&0xff]) + ret int(pop8tab[x>>24] + pop8tab[x>>16&0xff] + pop8tab[x>>8&0xff] + pop8tab[x&0xff]) } // Returns the number of one bits ("population count") in x. fn OnesCount64(mut x: u64): int { - // Implementation: Parallel summing of adjacent bits. - // See "Hacker's Delight", Chap. 5: Counting Bits. - // The following pattern shows the general approach: - // - // x = x>>1&(m0&m) + x&(m0&m) - // x = x>>2&(m1&m) + x&(m1&m) - // x = x>>4&(m2&m) + x&(m2&m) - // x = x>>8&(m3&m) + x&(m3&m) - // x = x>>16&(m4&m) + x&(m4&m) - // x = x>>32&(m5&m) + x&(m5&m) - // ret int(x) - // - // Masking (& operations) can be left away when there's no - // danger that a field's sum will carry over into the next - // field: Since the result cannot be > 64, 8 bits is enough - // and we can ignore the masks for the shifts by 8 and up. - // Per "Hacker's Delight", the first line can be simplified - // more, but it saves at best one instruction, so we leave - // it alone for clarity. - const m = 18446744073709551615 // 1<<64 - 1 - x = x >> 1 & (m0 & m) + x & (m0 & m) - x = x >> 2 & (m1 & m) + x & (m1 & m) - x = (x >> 4 + x) & (m2 & m) - x += x >> 8 - x += x >> 16 - x += x >> 32 - ret int(x) & (1 << 7 - 1) + // Implementation: Parallel summing of adjacent bits. + // See "Hacker's Delight", Chap. 5: Counting Bits. + // The following pattern shows the general approach: + // + // x = x>>1&(m0&m) + x&(m0&m) + // x = x>>2&(m1&m) + x&(m1&m) + // x = x>>4&(m2&m) + x&(m2&m) + // x = x>>8&(m3&m) + x&(m3&m) + // x = x>>16&(m4&m) + x&(m4&m) + // x = x>>32&(m5&m) + x&(m5&m) + // ret int(x) + // + // Masking (& operations) can be left away when there's no + // danger that a field's sum will carry over into the next + // field: Since the result cannot be > 64, 8 bits is enough + // and we can ignore the masks for the shifts by 8 and up. + // Per "Hacker's Delight", the first line can be simplified + // more, but it saves at best one instruction, so we leave + // it alone for clarity. + const m = 18446744073709551615 // 1<<64 - 1 + x = x >> 1 & (m0 & m) + x & (m0 & m) + x = x >> 2 & (m1 & m) + x & (m1 & m) + x = (x >> 4 + x) & (m2 & m) + x += x >> 8 + x += x >> 16 + x += x >> 32 + ret int(x) & (1 << 7 - 1) } // --- rotate_left --- @@ -198,10 +198,10 @@ fn OnesCount64(mut x: u64): int { // // This function's execution time does not depend on the inputs. fn RotateLeft(x: uint, k: int): uint { - if UintSize == 32 { - ret uint(RotateLeft32(u32(x), k)) - } - ret uint(RotateLeft64(u64(x), k)) + if UintSize == 32 { + ret uint(RotateLeft32(u32(x), k)) + } + ret uint(RotateLeft64(u64(x), k)) } // Returns the value of x rotated left by (k mod 8) bits. @@ -209,9 +209,9 @@ fn RotateLeft(x: uint, k: int): uint { // // This function's execution time does not depend on the inputs. fn RotateLeft8(x: u8, k: int): u8 { - const n = 8 - s := uint(k) & (n - 1) - ret x << s | x >> (n - s) + const n = 8 + s := uint(k) & (n - 1) + ret x << s | x >> (n - s) } // Returns the value of x rotated left by (k mod 16) bits. @@ -219,9 +219,9 @@ fn RotateLeft8(x: u8, k: int): u8 { // // This function's execution time does not depend on the inputs. fn RotateLeft16(x: u16, k: int): u16 { - const n = 16 - s := uint(k) & (n - 1) - ret x << s | x >> (n - s) + const n = 16 + s := uint(k) & (n - 1) + ret x << s | x >> (n - s) } // Returns the value of x rotated left by (k mod 32) bits. @@ -229,9 +229,9 @@ fn RotateLeft16(x: u16, k: int): u16 { // // This function's execution time does not depend on the inputs. fn RotateLeft32(x: u32, k: int): u32 { - const n = 32 - s := uint(k) & (n - 1) - ret x << s | x >> (n - s) + const n = 32 + s := uint(k) & (n - 1) + ret x << s | x >> (n - s) } // Returns the value of x rotated left by (k mod 64) bits. @@ -239,47 +239,47 @@ fn RotateLeft32(x: u32, k: int): u32 { // // This function's execution time does not depend on the inputs. fn RotateLeft64(x: u64, k: int): u64 { - const n = 64 - s := uint(k) & (n - 1) - ret x << s | x >> (n - s) + const n = 64 + s := uint(k) & (n - 1) + ret x << s | x >> (n - s) } // --- reverse --- // Returns the value of x with its bits in reversed order. fn Reverse(x: uint): uint { - if UintSize == 32 { - ret uint(Reverse32(u32(x))) - } - ret uint(Reverse64(u64(x))) + if UintSize == 32 { + ret uint(Reverse32(u32(x))) + } + ret uint(Reverse64(u64(x))) } // Returns the value of x with its bits in reversed order. fn Reverse8(x: u8): u8 { - ret rev8tab[x] + ret rev8tab[x] } // Returns the value of x with its bits in reversed order. fn Reverse16(x: u16): u16 { - ret u16(rev8tab[x>>8]) | u16(rev8tab[x&0xff]) << 8 + ret u16(rev8tab[x>>8]) | u16(rev8tab[x&0xff]) << 8 } // Returns the value of x with its bits in reversed order. fn Reverse32(mut x: u32): u32 { - const m = 1 << 32 - 1 - x = x >> 1 & (m0 & m) | x & (m0 & m) << 1 - x = x >> 2 & (m1 & m) | x & (m1 & m) << 2 - x = x >> 4 & (m2 & m) | x & (m2 & m) << 4 - ret ReverseBytes32(x) + const m = 1 << 32 - 1 + x = x >> 1 & (m0 & m) | x & (m0 & m) << 1 + x = x >> 2 & (m1 & m) | x & (m1 & m) << 2 + x = x >> 4 & (m2 & m) | x & (m2 & m) << 4 + ret ReverseBytes32(x) } // Returns the value of x with its bits in reversed order. fn Reverse64(mut x: u64): u64 { - const m = 18446744073709551615 // 1<<64 - 1 - x = x >> 1 & (m0 & m) | x & (m0 & m) << 1 - x = x >> 2 & (m1 & m) | x & (m1 & m) << 2 - x = x >> 4 & (m2 & m) | x & (m2 & m) << 4 - ret ReverseBytes64(x) + const m = 18446744073709551615 // 1<<64 - 1 + x = x >> 1 & (m0 & m) | x & (m0 & m) << 1 + x = x >> 2 & (m1 & m) | x & (m1 & m) << 2 + x = x >> 4 & (m2 & m) | x & (m2 & m) << 4 + ret ReverseBytes64(x) } // --- reverse_bytes --- @@ -288,36 +288,36 @@ fn Reverse64(mut x: u64): u64 { // // This function's execution time does not depend on the inputs. fn ReverseBytes(x: uint): uint { - if UintSize == 32 { - ret uint(ReverseBytes32(u32(x))) - } - ret uint(ReverseBytes64(u64(x))) + if UintSize == 32 { + ret uint(ReverseBytes32(u32(x))) + } + ret uint(ReverseBytes64(u64(x))) } // Returns the value of x with its bytes in reversed order. // // This function's execution time does not depend on the inputs. fn ReverseBytes16(x: u16): u16 { - ret x >> 8 | x << 8 + ret x >> 8 | x << 8 } // Returns the value of x with its bytes in reversed order. // // This function's execution time does not depend on the inputs. fn ReverseBytes32(mut x: u32): u32 { - const m = 1 << 32 - 1 - x = x >> 8 & (m3 & m) | x & (m3 & m) << 8 - ret x >> 16 | x << 16 + const m = 1 << 32 - 1 + x = x >> 8 & (m3 & m) | x & (m3 & m) << 8 + ret x >> 16 | x << 16 } // Returns the value of x with its bytes in reversed order. // // This function's execution time does not depend on the inputs. fn ReverseBytes64(mut x: u64): u64 { - const m = 18446744073709551615 // 1<<64 - 1 - x = x >> 8 & (m3 & m) | x & (m3 & m) << 8 - x = x >> 16 & (m4 & m) | x & (m4 & m) << 16 - ret x >> 32 | x << 32 + const m = 18446744073709551615 // 1<<64 - 1 + x = x >> 8 & (m3 & m) | x & (m3 & m) << 8 + x = x >> 16 & (m4 & m) | x & (m4 & m) << 16 + ret x >> 32 | x << 32 } // --- len --- @@ -325,58 +325,58 @@ fn ReverseBytes64(mut x: u64): u64 { // Returns the minimum number of bits required to represent x; // the result is 0 for x == 0. fn Len(x: uint): int { - if UintSize == 32 { - ret Len32(u32(x)) - } - ret Len64(u64(x)) + if UintSize == 32 { + ret Len32(u32(x)) + } + ret Len64(u64(x)) } // Returns the minimum number of bits required to represent x; // the result is 0 for x == 0. fn Len8(x: u8): int { - ret int(len8tab[x]) + ret int(len8tab[x]) } // Returns the minimum number of bits required to represent x; // the result is 0 for x == 0. fn Len16(mut x: u16): (n: int) { - if x >= 1<<8 { - x >>= 8 - n = 8 - } - ret n + int(len8tab[x]) + if x >= 1<<8 { + x >>= 8 + n = 8 + } + ret n + int(len8tab[x]) } // Returns the minimum number of bits required to represent x; // the result is 0 for x == 0. fn Len32(mut x: u32): (n: int) { - if x >= 1<<16 { - x >>= 16 - n = 16 - } - if x >= 1<<8 { - x >>= 8 - n += 8 - } - ret n + int(len8tab[x]) + if x >= 1<<16 { + x >>= 16 + n = 16 + } + if x >= 1<<8 { + x >>= 8 + n += 8 + } + ret n + int(len8tab[x]) } // Returns the minimum number of bits required to represent x; // the result is 0 for x == 0. fn Len64(mut x: u64): (n: int) { - if x >= 1<<32 { - x >>= 32 - n = 32 - } - if x >= 1<<16 { - x >>= 16 - n += 16 - } - if x >= 1<<8 { - x >>= 8 - n += 8 - } - ret n + int(len8tab[x]) + if x >= 1<<32 { + x >>= 32 + n = 32 + } + if x >= 1<<16 { + x >>= 16 + n += 16 + } + if x >= 1<<8 { + x >>= 8 + n += 8 + } + ret n + int(len8tab[x]) } // --- Add with carry --- @@ -387,12 +387,12 @@ fn Len64(mut x: u64): (n: int) { // // This function's execution time does not depend on the inputs. fn Add(x: uint, y: uint, carry: uint): (sum: uint, carry_out: uint) { - if UintSize == 32 { - s32, c32 := Add32(u32(x), u32(y), u32(carry)) - ret uint(s32), uint(c32) - } - s64, c64 := Add64(u64(x), u64(y), u64(carry)) - ret uint(s64), uint(c64) + if UintSize == 32 { + s32, c32 := Add32(u32(x), u32(y), u32(carry)) + ret uint(s32), uint(c32) + } + s64, c64 := Add64(u64(x), u64(y), u64(carry)) + ret uint(s64), uint(c64) } // Returns the sum with carry of x, y and carry: sum = x + y + carry. @@ -401,10 +401,10 @@ fn Add(x: uint, y: uint, carry: uint): (sum: uint, carry_out: uint) { // // This function's execution time does not depend on the inputs. fn Add32(x: u32, y: u32, carry: u32): (sum: u32, carryout: u32) { - sum64 := u64(x) + u64(y) + u64(carry) - sum = u32(sum64) - carryout = u32(sum64 >> 32) - ret + sum64 := u64(x) + u64(y) + u64(carry) + sum = u32(sum64) + carryout = u32(sum64 >> 32) + ret } // Returns the sum with carry of x, y and carry: sum = x + y + carry. @@ -413,12 +413,12 @@ fn Add32(x: u32, y: u32, carry: u32): (sum: u32, carryout: u32) { // // This function's execution time does not depend on the inputs. fn Add64(x: u64, y: u64, carry: u64): (sum: u64, carryout: u64) { - sum = x + y + carry - // The sum will overflow if both top bits are set (x & y) or if one of them - // is (x | y), and a carry from the lower place happened. If such a carry - // happens, the top bit will be 1 + 0 + 1 = 0 (& ^sum). - carryout = ((x & y) | ((x | y) & ^sum)) >> 63 - ret + sum = x + y + carry + // The sum will overflow if both top bits are set (x & y) or if one of them + // is (x | y), and a carry from the lower place happened. If such a carry + // happens, the top bit will be 1 + 0 + 1 = 0 (& ^sum). + carryout = ((x & y) | ((x | y) & ^sum)) >> 63 + ret } // --- Subtract with borrow --- @@ -429,12 +429,12 @@ fn Add64(x: u64, y: u64, carry: u64): (sum: u64, carryout: u64) { // // This function's execution time does not depend on the inputs. fn Sub(x: uint, y: uint, borrow: uint): (diff: uint, borrow_out: uint) { - if UintSize == 32 { - d32, b32 := Sub32(u32(x), u32(y), u32(borrow)) - ret uint(d32), uint(b32) - } - d64, b64 := Sub64(u64(x), u64(y), u64(borrow)) - ret uint(d64), uint(b64) + if UintSize == 32 { + d32, b32 := Sub32(u32(x), u32(y), u32(borrow)) + ret uint(d32), uint(b32) + } + d64, b64 := Sub64(u64(x), u64(y), u64(borrow)) + ret uint(d64), uint(b64) } // Returns the difference of x, y and borrow, diff = x - y - borrow. @@ -443,13 +443,13 @@ fn Sub(x: uint, y: uint, borrow: uint): (diff: uint, borrow_out: uint) { // // This function's execution time does not depend on the inputs. fn Sub32(x: u32, y: u32, borrow: u32): (diff: u32, borrowout: u32) { - diff = x - y - borrow - // The difference will underflow if the top bit of x is not set and the top - // bit of y is set (^x & y) or if they are the same (^(x ^ y)) and a borrow - // from the lower place happens. If that borrow happens, the result will be - // 1 - 1 - 1 = 0 - 0 - 1 = 1 (& diff). - borrowout = ((^x & y) | (^(x ^ y) & diff)) >> 31 - ret + diff = x - y - borrow + // The difference will underflow if the top bit of x is not set and the top + // bit of y is set (^x & y) or if they are the same (^(x ^ y)) and a borrow + // from the lower place happens. If that borrow happens, the result will be + // 1 - 1 - 1 = 0 - 0 - 1 = 1 (& diff). + borrowout = ((^x & y) | (^(x ^ y) & diff)) >> 31 + ret } // Returns the difference of x, y and borrow: diff = x - y - borrow. @@ -458,10 +458,10 @@ fn Sub32(x: u32, y: u32, borrow: u32): (diff: u32, borrowout: u32) { // // This function's execution time does not depend on the inputs. fn Sub64(x: u64, y: u64, borrow: u64): (diff: u64, borrowout: u64) { - diff = x - y - borrow - // See sub32 for the bit logic. - borrowout = ((^x & y) | (^(x ^ y) & diff)) >> 63 - ret + diff = x - y - borrow + // See sub32 for the bit logic. + borrowout = ((^x & y) | (^(x ^ y) & diff)) >> 63 + ret } // --- Full-width multiply --- @@ -472,12 +472,12 @@ fn Sub64(x: u64, y: u64, borrow: u64): (diff: u64, borrowout: u64) { // // This function's execution time does not depend on the inputs. fn Mul(x: uint, y: uint): (hi: uint, lo: uint) { - if UintSize == 32 { - h, l := Mul32(u32(x), u32(y)) - ret uint(h), uint(l) - } - h, l := Mul64(u64(x), u64(y)) - ret uint(h), uint(l) + if UintSize == 32 { + h, l := Mul32(u32(x), u32(y)) + ret uint(h), uint(l) + } + h, l := Mul64(u64(x), u64(y)) + ret uint(h), uint(l) } // Returns the 64-bit product of x and y: (hi, lo) = x * y @@ -486,9 +486,9 @@ fn Mul(x: uint, y: uint): (hi: uint, lo: uint) { // // This function's execution time does not depend on the inputs. fn Mul32(x: u32, y: u32): (hi: u32, lo: u32) { - tmp := u64(x) * u64(y) - hi, lo = u32(tmp >> 32), u32(tmp) - ret + tmp := u64(x) * u64(y) + hi, lo = u32(tmp >> 32), u32(tmp) + ret } // Returns the 128-bit product of x and y: (hi, lo) = x * y @@ -497,19 +497,19 @@ fn Mul32(x: u32, y: u32): (hi: u32, lo: u32) { // // This function's execution time does not depend on the inputs. fn Mul64(x: u64, y: u64): (hi: u64, lo: u64) { - const mask32 = 1 << 32 - 1 - x0 := x & mask32 - x1 := x >> 32 - y0 := y & mask32 - y1 := y >> 32 - w0 := x0 * y0 - t := x1 * y0 + w0 >> 32 - mut w1 := t & mask32 - w2 := t >> 32 - w1 += x0 * y1 - hi = x1 * y1 + w2 + w1 >> 32 - lo = x * y - ret + const mask32 = 1 << 32 - 1 + x0 := x & mask32 + x1 := x >> 32 + y0 := y & mask32 + y1 := y >> 32 + w0 := x0 * y0 + t := x1 * y0 + w0 >> 32 + mut w1 := t & mask32 + w2 := t >> 32 + w1 += x0 * y1 + hi = x1 * y1 + w2 + w1 >> 32 + lo = x * y + ret } // --- Full-width divide --- @@ -519,12 +519,12 @@ fn Mul64(x: u64, y: u64): (hi: u64, lo: u64) { // half in parameter hi and the lower half in parameter lo. // div panics for y == 0 (division by zero) or y <= hi (quotient overflow). fn Div(hi: uint, lo: uint, y: uint): (quo: uint, rem: uint) { - if UintSize == 32 { - q, r := Div32(u32(hi), u32(lo), u32(y)) - ret uint(q), uint(r) - } - q, r := Div64(u64(hi), u64(lo), u64(y)) - ret uint(q), uint(r) + if UintSize == 32 { + q, r := Div32(u32(hi), u32(lo), u32(y)) + ret uint(q), uint(r) + } + q, r := Div64(u64(hi), u64(lo), u64(y)) + ret uint(q), uint(r) } // Returns the quotient and remainder of (hi, lo) divided by y: @@ -532,15 +532,15 @@ fn Div(hi: uint, lo: uint, y: uint): (quo: uint, rem: uint) { // half in parameter hi and the lower half in parameter lo. // div32 panics for y == 0 (division by zero) or y <= hi (quotient overflow). fn Div32(hi: u32, lo: u32, y: u32): (quo: u32, rem: u32) { - if y == 0 { - panic(divideError) - } - if y != 0 && y <= hi { - panic(overflowError) - } - z := u64(hi) << 32 | u64(lo) - quo, rem = u32(z / u64(y)), u32(z % u64(y)) - ret + if y == 0 { + panic(divideError) + } + if y != 0 && y <= hi { + panic(overflowError) + } + z := u64(hi) << 32 | u64(lo) + quo, rem = u32(z / u64(y)), u32(z % u64(y)) + ret } // Returns the quotient and remainder of (hi, lo) divided by y: @@ -548,77 +548,77 @@ fn Div32(hi: u32, lo: u32, y: u32): (quo: u32, rem: u32) { // half in parameter hi and the lower half in parameter lo. // div64 panics for y == 0 (division by zero) or y <= hi (quotient overflow). fn Div64(hi: u64, lo: u64, mut y: u64): (quo: u64, rem: u64) { - const two32 = 1 << 32 - const mask32 = two32 - 1 - if y == 0 { - panic(divideError) - } - if y <= hi { - panic(overflowError) - } - - s := uint(LeadingZeros64(y)) - y <<= s - - yn1 := y >> 32 - yn0 := y & mask32 - un32 := hi << s | lo >> (64 - s) - un10 := lo << s - un1 := un10 >> 32 - un0 := un10 & mask32 - mut q1 := un32 / yn1 - mut rhat := un32 - q1 * yn1 - - for q1 >= two32 || q1*yn0 > two32*rhat+un1 { - q1-- - rhat += yn1 - if rhat >= two32 { - break - } - } - - un21 := un32 * two32 + un1 - q1 * y - mut q0 := un21 / yn1 - rhat = un21 - q0 * yn1 - - for q0 >= two32 || q0*yn0 > two32*rhat+un0 { - q0-- - rhat += yn1 - if rhat >= two32 { - break - } - } - - ret q1 * two32 + q0, (un21 * two32 + un0 - q0 * y) >> s + const two32 = 1 << 32 + const mask32 = two32 - 1 + if y == 0 { + panic(divideError) + } + if y <= hi { + panic(overflowError) + } + + s := uint(LeadingZeros64(y)) + y <<= s + + yn1 := y >> 32 + yn0 := y & mask32 + un32 := hi << s | lo >> (64 - s) + un10 := lo << s + un1 := un10 >> 32 + un0 := un10 & mask32 + mut q1 := un32 / yn1 + mut rhat := un32 - q1 * yn1 + + for q1 >= two32 || q1*yn0 > two32*rhat+un1 { + q1-- + rhat += yn1 + if rhat >= two32 { + break + } + } + + un21 := un32 * two32 + un1 - q1 * y + mut q0 := un21 / yn1 + rhat = un21 - q0 * yn1 + + for q0 >= two32 || q0*yn0 > two32*rhat+un0 { + q0-- + rhat += yn1 + if rhat >= two32 { + break + } + } + + ret q1 * two32 + q0, (un21 * two32 + un0 - q0 * y) >> s } // Returns the remainder of (hi, lo) divided by y. rem panics for // y == 0 (division by zero) but, unlike div, it doesn't panic on a // quotient overflow. fn Rem(hi: uint, lo: uint, y: uint): uint { - if UintSize == 32 { - ret uint(Rem32(u32(hi), u32(lo), u32(y))) - } - ret uint(Rem64(u64(hi), u64(lo), u64(y))) + if UintSize == 32 { + ret uint(Rem32(u32(hi), u32(lo), u32(y))) + } + ret uint(Rem64(u64(hi), u64(lo), u64(y))) } // Returns the remainder of (hi, lo) divided by y. rem32 panics // for y == 0 (division by zero) but, unlike div32, it doesn't panic // on a quotient overflow. fn Rem32(hi: u32, lo: u32, y: u32): u32 { - ret u32((u64(hi) << 32 | u64(lo)) % u64(y)) + ret u32((u64(hi) << 32 | u64(lo)) % u64(y)) } // Returns the remainder of (hi, lo) divided by y. rem64 panics // for y == 0 (division by zero) but, unlike div64, it doesn't panic // on a quotient overflow. fn Rem64(hi: u64, lo: u64, y: u64): u64 { - // We scale down hi so that hi < y, then use div64 to compute the - // rem with the guarantee that it won't panic on quotient overflow. - // Given that - // hi ≡ hi%y (mod y) - // we have - // hi<<64 + lo ≡ (hi%y)<<64 + lo (mod y) - _, rem := Div64(hi % y, lo, y) - ret rem + // We scale down hi so that hi < y, then use div64 to compute the + // rem with the guarantee that it won't panic on quotient overflow. + // Given that + // hi ≡ hi%y (mod y) + // we have + // hi<<64 + lo ≡ (hi%y)<<64 + lo (mod y) + _, rem := Div64(hi % y, lo, y) + ret rem } \ No newline at end of file diff --git a/std/math/bits/bits_tables.jule b/std/math/bits/bits_tables.jule index 63701fcc5..aa9595df7 100644 --- a/std/math/bits/bits_tables.jule +++ b/std/math/bits/bits_tables.jule @@ -36,69 +36,69 @@ // ==================================================== const ntz8tab = ("\x08\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + - "\x04\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + - "\x05\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + - "\x04\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + - "\x06\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + - "\x04\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + - "\x05\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + - "\x04\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + - "\x07\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + - "\x04\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + - "\x05\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + - "\x04\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + - "\x06\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + - "\x04\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + - "\x05\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + - "\x04\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00") + "\x04\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + + "\x05\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + + "\x04\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + + "\x06\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + + "\x04\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + + "\x05\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + + "\x04\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + + "\x07\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + + "\x04\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + + "\x05\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + + "\x04\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + + "\x06\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + + "\x04\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + + "\x05\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + + "\x04\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00") const pop8tab = ("\x00\x01\x01\x02\x01\x02\x02\x03\x01\x02\x02\x03\x02\x03\x03\x04" + - "\x01\x02\x02\x03\x02\x03\x03\x04\x02\x03\x03\x04\x03\x04\x04\x05" + - "\x01\x02\x02\x03\x02\x03\x03\x04\x02\x03\x03\x04\x03\x04\x04\x05" + - "\x02\x03\x03\x04\x03\x04\x04\x05\x03\x04\x04\x05\x04\x05\x05\x06" + - "\x01\x02\x02\x03\x02\x03\x03\x04\x02\x03\x03\x04\x03\x04\x04\x05" + - "\x02\x03\x03\x04\x03\x04\x04\x05\x03\x04\x04\x05\x04\x05\x05\x06" + - "\x02\x03\x03\x04\x03\x04\x04\x05\x03\x04\x04\x05\x04\x05\x05\x06" + - "\x03\x04\x04\x05\x04\x05\x05\x06\x04\x05\x05\x06\x05\x06\x06\x07" + - "\x01\x02\x02\x03\x02\x03\x03\x04\x02\x03\x03\x04\x03\x04\x04\x05" + - "\x02\x03\x03\x04\x03\x04\x04\x05\x03\x04\x04\x05\x04\x05\x05\x06" + - "\x02\x03\x03\x04\x03\x04\x04\x05\x03\x04\x04\x05\x04\x05\x05\x06" + - "\x03\x04\x04\x05\x04\x05\x05\x06\x04\x05\x05\x06\x05\x06\x06\x07" + - "\x02\x03\x03\x04\x03\x04\x04\x05\x03\x04\x04\x05\x04\x05\x05\x06" + - "\x03\x04\x04\x05\x04\x05\x05\x06\x04\x05\x05\x06\x05\x06\x06\x07" + - "\x03\x04\x04\x05\x04\x05\x05\x06\x04\x05\x05\x06\x05\x06\x06\x07" + - "\x04\x05\x05\x06\x05\x06\x06\x07\x05\x06\x06\x07\x06\x07\x07\x08") + "\x01\x02\x02\x03\x02\x03\x03\x04\x02\x03\x03\x04\x03\x04\x04\x05" + + "\x01\x02\x02\x03\x02\x03\x03\x04\x02\x03\x03\x04\x03\x04\x04\x05" + + "\x02\x03\x03\x04\x03\x04\x04\x05\x03\x04\x04\x05\x04\x05\x05\x06" + + "\x01\x02\x02\x03\x02\x03\x03\x04\x02\x03\x03\x04\x03\x04\x04\x05" + + "\x02\x03\x03\x04\x03\x04\x04\x05\x03\x04\x04\x05\x04\x05\x05\x06" + + "\x02\x03\x03\x04\x03\x04\x04\x05\x03\x04\x04\x05\x04\x05\x05\x06" + + "\x03\x04\x04\x05\x04\x05\x05\x06\x04\x05\x05\x06\x05\x06\x06\x07" + + "\x01\x02\x02\x03\x02\x03\x03\x04\x02\x03\x03\x04\x03\x04\x04\x05" + + "\x02\x03\x03\x04\x03\x04\x04\x05\x03\x04\x04\x05\x04\x05\x05\x06" + + "\x02\x03\x03\x04\x03\x04\x04\x05\x03\x04\x04\x05\x04\x05\x05\x06" + + "\x03\x04\x04\x05\x04\x05\x05\x06\x04\x05\x05\x06\x05\x06\x06\x07" + + "\x02\x03\x03\x04\x03\x04\x04\x05\x03\x04\x04\x05\x04\x05\x05\x06" + + "\x03\x04\x04\x05\x04\x05\x05\x06\x04\x05\x05\x06\x05\x06\x06\x07" + + "\x03\x04\x04\x05\x04\x05\x05\x06\x04\x05\x05\x06\x05\x06\x06\x07" + + "\x04\x05\x05\x06\x05\x06\x06\x07\x05\x06\x06\x07\x06\x07\x07\x08") const rev8tab = ("\x00\x80\x40\xc0\x20\xa0\x60\xe0\x10\x90\x50\xd0\x30\xb0\x70\xf0" + - "\x08\x88\x48\xc8\x28\xa8\x68\xe8\x18\x98\x58\xd8\x38\xb8\x78\xf8" + - "\x04\x84\x44\xc4\x24\xa4\x64\xe4\x14\x94\x54\xd4\x34\xb4\x74\xf4" + - "\x0c\x8c\x4c\xcc\x2c\xac\x6c\xec\x1c\x9c\x5c\xdc\x3c\xbc\x7c\xfc" + - "\x02\x82\x42\xc2\x22\xa2\x62\xe2\x12\x92\x52\xd2\x32\xb2\x72\xf2" + - "\x0a\x8a\x4a\xca\x2a\xaa\x6a\xea\x1a\x9a\x5a\xda\x3a\xba\x7a\xfa" + - "\x06\x86\x46\xc6\x26\xa6\x66\xe6\x16\x96\x56\xd6\x36\xb6\x76\xf6" + - "\x0e\x8e\x4e\xce\x2e\xae\x6e\xee\x1e\x9e\x5e\xde\x3e\xbe\x7e\xfe" + - "\x01\x81\x41\xc1\x21\xa1\x61\xe1\x11\x91\x51\xd1\x31\xb1\x71\xf1" + - "\x09\x89\x49\xc9\x29\xa9\x69\xe9\x19\x99\x59\xd9\x39\xb9\x79\xf9" + - "\x05\x85\x45\xc5\x25\xa5\x65\xe5\x15\x95\x55\xd5\x35\xb5\x75\xf5" + - "\x0d\x8d\x4d\xcd\x2d\xad\x6d\xed\x1d\x9d\x5d\xdd\x3d\xbd\x7d\xfd" + - "\x03\x83\x43\xc3\x23\xa3\x63\xe3\x13\x93\x53\xd3\x33\xb3\x73\xf3" + - "\x0b\x8b\x4b\xcb\x2b\xab\x6b\xeb\x1b\x9b\x5b\xdb\x3b\xbb\x7b\xfb" + - "\x07\x87\x47\xc7\x27\xa7\x67\xe7\x17\x97\x57\xd7\x37\xb7\x77\xf7" + - "\x0f\x8f\x4f\xcf\x2f\xaf\x6f\xef\x1f\x9f\x5f\xdf\x3f\xbf\x7f\xff") + "\x08\x88\x48\xc8\x28\xa8\x68\xe8\x18\x98\x58\xd8\x38\xb8\x78\xf8" + + "\x04\x84\x44\xc4\x24\xa4\x64\xe4\x14\x94\x54\xd4\x34\xb4\x74\xf4" + + "\x0c\x8c\x4c\xcc\x2c\xac\x6c\xec\x1c\x9c\x5c\xdc\x3c\xbc\x7c\xfc" + + "\x02\x82\x42\xc2\x22\xa2\x62\xe2\x12\x92\x52\xd2\x32\xb2\x72\xf2" + + "\x0a\x8a\x4a\xca\x2a\xaa\x6a\xea\x1a\x9a\x5a\xda\x3a\xba\x7a\xfa" + + "\x06\x86\x46\xc6\x26\xa6\x66\xe6\x16\x96\x56\xd6\x36\xb6\x76\xf6" + + "\x0e\x8e\x4e\xce\x2e\xae\x6e\xee\x1e\x9e\x5e\xde\x3e\xbe\x7e\xfe" + + "\x01\x81\x41\xc1\x21\xa1\x61\xe1\x11\x91\x51\xd1\x31\xb1\x71\xf1" + + "\x09\x89\x49\xc9\x29\xa9\x69\xe9\x19\x99\x59\xd9\x39\xb9\x79\xf9" + + "\x05\x85\x45\xc5\x25\xa5\x65\xe5\x15\x95\x55\xd5\x35\xb5\x75\xf5" + + "\x0d\x8d\x4d\xcd\x2d\xad\x6d\xed\x1d\x9d\x5d\xdd\x3d\xbd\x7d\xfd" + + "\x03\x83\x43\xc3\x23\xa3\x63\xe3\x13\x93\x53\xd3\x33\xb3\x73\xf3" + + "\x0b\x8b\x4b\xcb\x2b\xab\x6b\xeb\x1b\x9b\x5b\xdb\x3b\xbb\x7b\xfb" + + "\x07\x87\x47\xc7\x27\xa7\x67\xe7\x17\x97\x57\xd7\x37\xb7\x77\xf7" + + "\x0f\x8f\x4f\xcf\x2f\xaf\x6f\xef\x1f\x9f\x5f\xdf\x3f\xbf\x7f\xff") const len8tab = ("\x00\x01\x02\x02\x03\x03\x03\x03\x04\x04\x04\x04\x04\x04\x04\x04" + - "\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05" + - "\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06" + - "\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06" + - "\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07" + - "\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07" + - "\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07" + - "\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07" + - "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08" + - "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08" + - "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08" + - "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08" + - "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08" + - "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08" + - "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08" + - "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08") \ No newline at end of file + "\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05" + + "\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06" + + "\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06" + + "\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07" + + "\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07" + + "\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07" + + "\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07" + + "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08" + + "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08" + + "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08" + + "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08" + + "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08" + + "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08" + + "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08" + + "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08") \ No newline at end of file diff --git a/std/math/cbrt.jule b/std/math/cbrt.jule index 9d62c6526..943ccd496 100644 --- a/std/math/cbrt.jule +++ b/std/math/cbrt.jule @@ -54,53 +54,53 @@ // Cbrt(±Inf) = ±Inf // Cbrt(NaN) = NaN fn Cbrt(mut x: f64): f64 { - const B1 = 715094163 // (682-0.03306235651)*2**20 - const B2 = 696219795 // (664-0.03306235651)*2**20 - const C = 5.42857142857142815906e-01 // 19/35 = 0x3FE15F15F15F15F1 - const D = -7.05306122448979611050e-01 // -864/1225 = 0xBFE691DE2532C834 - const E = 1.41428571428571436819e+00 // 99/70 = 0x3FF6A0EA0EA0EA0F - const F = 1.60714285714285720630e+00 // 45/28 = 0x3FF9B6DB6DB6DB6E - const G = 3.57142857142857150787e-01 // 5/14 = 0x3FD6DB6DB6DB6DB7 - const SmallestNormal = 2.22507385850720138309e-308 // 2**-1022 = 0x0010000000000000 + const B1 = 715094163 // (682-0.03306235651)*2**20 + const B2 = 696219795 // (664-0.03306235651)*2**20 + const C = 5.42857142857142815906e-01 // 19/35 = 0x3FE15F15F15F15F1 + const D = -7.05306122448979611050e-01 // -864/1225 = 0xBFE691DE2532C834 + const E = 1.41428571428571436819e+00 // 99/70 = 0x3FF6A0EA0EA0EA0F + const F = 1.60714285714285720630e+00 // 45/28 = 0x3FF9B6DB6DB6DB6E + const G = 3.57142857142857150787e-01 // 5/14 = 0x3FD6DB6DB6DB6DB7 + const SmallestNormal = 2.22507385850720138309e-308 // 2**-1022 = 0x0010000000000000 - // special cases - if x == 0 || IsNaN(x) || IsInf(x, 0) { - ret x - } + // special cases + if x == 0 || IsNaN(x) || IsInf(x, 0) { + ret x + } - mut sign := false - if x < 0 { - x = -x - sign = true - } + mut sign := false + if x < 0 { + x = -x + sign = true + } - // rough cbrt to 5 bits - mut t := F64FromBits(F64Bits(x) / 3 + B1 << 32) - if x < SmallestNormal { - // subnormal number - t = f64(1 << 54) // set t= 2**54 - t *= x - t = F64FromBits(F64Bits(t) / 3 + B2 << 32) - } + // rough cbrt to 5 bits + mut t := F64FromBits(F64Bits(x) / 3 + B1 << 32) + if x < SmallestNormal { + // subnormal number + t = f64(1 << 54) // set t= 2**54 + t *= x + t = F64FromBits(F64Bits(t) / 3 + B2 << 32) + } - // new cbrt to 23 bits - mut r := t * t / x - mut s := C + r * t - t *= G + F / (s + E + D / s) + // new cbrt to 23 bits + mut r := t * t / x + mut s := C + r * t + t *= G + F / (s + E + D / s) - // chop to 22 bits, make larger than cbrt(x) - t = F64FromBits(F64Bits(t) & (0xFFFFFFFFC << 28) + 1 << 30) + // chop to 22 bits, make larger than cbrt(x) + t = F64FromBits(F64Bits(t) & (0xFFFFFFFFC << 28) + 1 << 30) - // one step newton iteration to 53 bits with error less than 0.667ulps - s = t * t // t*t is exact - r = x / s - w := t + t - r = (r - t) / (w + r) // r-s is exact - t = t + t * r + // one step newton iteration to 53 bits with error less than 0.667ulps + s = t * t // t*t is exact + r = x / s + w := t + t + r = (r - t) / (w + r) // r-s is exact + t = t + t * r - // restore the sign bit - if sign { - t = -t - } - ret t + // restore the sign bit + if sign { + t = -t + } + ret t } \ No newline at end of file diff --git a/std/math/cmplx/abs.jule b/std/math/cmplx/abs.jule index c5f2c2010..082a3de5f 100644 --- a/std/math/cmplx/abs.jule +++ b/std/math/cmplx/abs.jule @@ -8,8 +8,8 @@ use math for std::math // https://github.com/golang/go/blob/go1.20/src/math/cmplx/abs.go impl Cmplx { - // Returns the absolute value (also called the modulus) of x. - fn Abs(self): f64 { - ret math::Hypot(self.Real(), self.Imag()) - } + // Returns the absolute value (also called the modulus) of x. + fn Abs(self): f64 { + ret math::Hypot(self.Real(), self.Imag()) + } } \ No newline at end of file diff --git a/std/math/cmplx/asin.jule b/std/math/cmplx/asin.jule index 583f40a9c..d5be2952d 100644 --- a/std/math/cmplx/asin.jule +++ b/std/math/cmplx/asin.jule @@ -31,194 +31,194 @@ use math for std::math // moshier@na-net.ornl.gov impl Cmplx { - // Complex circular arc sine - // - // DESCRIPTION: - // - // Inverse complex sine: - // 2 - // w = -i clog( iz + csqrt( 1 - z ) ). - // - // casin(z) = -i casinh(iz) - // - // ACCURACY: - // - // Relative error: - // arithmetic domain # trials peak rms - // DEC -10,+10 10100 2.1e-15 3.4e-16 - // IEEE -10,+10 30000 2.2e-14 2.7e-15 - // Larger relative error can be observed for z near zero. - // Also tested by csin(casin(z)) = z. + // Complex circular arc sine + // + // DESCRIPTION: + // + // Inverse complex sine: + // 2 + // w = -i clog( iz + csqrt( 1 - z ) ). + // + // casin(z) = -i casinh(iz) + // + // ACCURACY: + // + // Relative error: + // arithmetic domain # trials peak rms + // DEC -10,+10 10100 2.1e-15 3.4e-16 + // IEEE -10,+10 30000 2.2e-14 2.7e-15 + // Larger relative error can be observed for z near zero. + // Also tested by csin(casin(z)) = z. - // Returns the inverse sine of complex number. - fn Asin(self): Cmplx { - match { - | self.Imag() == 0 && math::Abs(self.Real()) <= 1: - ret Cmplx.New(math::Asin(self.Real()), self.Imag()) - | self.Real() == 0 && math::Abs(self.Imag()) <= 1: - ret Cmplx.New(self.Real(), math::Asinh(self.Imag())) - | math::IsNaN(self.Imag()): - match { - | self.Real() == 0: - ret Cmplx.New(self.Real(), math::NaN()) - | math::IsInf(self.Real(), 0): - ret Cmplx.New(math::NaN(), self.Real()) - |: - ret Cmplx.NaN() - } - | math::IsInf(self.Imag(), 0): - match { - | math::IsNaN(self.Real()): - ret self - | math::IsInf(self.Real(), 0): - ret Cmplx.New(math::Copysign(math::Pi / 4, self.Real()), self.Imag()) - |: - ret Cmplx.New(math::Copysign(0, self.Real()), self.Imag()) - } - | math::IsInf(self.Real(), 0): - ret Cmplx.New(math::Copysign(math::Pi / 2, self.Real()), math::Copysign(self.Real(), self.Imag())) - } - ct := Cmplx.New(-self.Imag(), self.Real()) // i * x - xx := self.Mul(self) - x1 := Cmplx.New(1 - xx.Real(), -xx.Imag()) // 1 - x*x - x2 := x1.Sqrt() // x2 = sqrt(1 - x*x) - w := ct.Add(x2).Log() - ret Cmplx.New(w.Imag(), -w.Real()) // -i * w - } + // Returns the inverse sine of complex number. + fn Asin(self): Cmplx { + match { + | self.Imag() == 0 && math::Abs(self.Real()) <= 1: + ret Cmplx.New(math::Asin(self.Real()), self.Imag()) + | self.Real() == 0 && math::Abs(self.Imag()) <= 1: + ret Cmplx.New(self.Real(), math::Asinh(self.Imag())) + | math::IsNaN(self.Imag()): + match { + | self.Real() == 0: + ret Cmplx.New(self.Real(), math::NaN()) + | math::IsInf(self.Real(), 0): + ret Cmplx.New(math::NaN(), self.Real()) + |: + ret Cmplx.NaN() + } + | math::IsInf(self.Imag(), 0): + match { + | math::IsNaN(self.Real()): + ret self + | math::IsInf(self.Real(), 0): + ret Cmplx.New(math::Copysign(math::Pi / 4, self.Real()), self.Imag()) + |: + ret Cmplx.New(math::Copysign(0, self.Real()), self.Imag()) + } + | math::IsInf(self.Real(), 0): + ret Cmplx.New(math::Copysign(math::Pi / 2, self.Real()), math::Copysign(self.Real(), self.Imag())) + } + ct := Cmplx.New(-self.Imag(), self.Real()) // i * x + xx := self.Mul(self) + x1 := Cmplx.New(1 - xx.Real(), -xx.Imag()) // 1 - x*x + x2 := x1.Sqrt() // x2 = sqrt(1 - x*x) + w := ct.Add(x2).Log() + ret Cmplx.New(w.Imag(), -w.Real()) // -i * w + } - // Returns the inverse hyperbolic sine of complex number. - fn Asinh(self): Cmplx { - match { - | self.Imag() == 0 && math::Abs(self.Real()) <= 1: - ret Cmplx.New(math::Asinh(self.Real()), self.Imag()) - | self.Real() == 0 && math::Abs(self.Imag()) <= 1: - ret Cmplx.New(self.Real(), math::Asin(self.Imag())) - | math::IsInf(self.Real(), 0): - match { - | math::IsInf(self.Imag(), 0): - ret Cmplx.New(self.Real(), math::Copysign(math::Pi / 4, self.Imag())) - | math::IsNaN(self.Imag()): - ret self - |: - ret Cmplx.New(self.Real(), math::Copysign(0.0, self.Imag())) - } - | math::IsNaN(self.Real()): - match { - | self.Imag() == 0: - ret self - | math::IsInf(self.Imag(), 0): - ret Cmplx.New(self.Imag(), self.Real()) - |: - ret Cmplx.NaN() - } - | math::IsInf(self.Imag(), 0): - ret Cmplx.New(math::Copysign(self.Imag(), self.Real()), math::Copysign(math::Pi / 2, self.Imag())) - } - xx := self.Mul(self) - x1 := Cmplx.New(1 + xx.Real(), xx.Imag()) // 1 + x*x - ret self.Add(x1.Sqrt()).Log() // log(x + sqrt(1 + x*x)) - } + // Returns the inverse hyperbolic sine of complex number. + fn Asinh(self): Cmplx { + match { + | self.Imag() == 0 && math::Abs(self.Real()) <= 1: + ret Cmplx.New(math::Asinh(self.Real()), self.Imag()) + | self.Real() == 0 && math::Abs(self.Imag()) <= 1: + ret Cmplx.New(self.Real(), math::Asin(self.Imag())) + | math::IsInf(self.Real(), 0): + match { + | math::IsInf(self.Imag(), 0): + ret Cmplx.New(self.Real(), math::Copysign(math::Pi / 4, self.Imag())) + | math::IsNaN(self.Imag()): + ret self + |: + ret Cmplx.New(self.Real(), math::Copysign(0.0, self.Imag())) + } + | math::IsNaN(self.Real()): + match { + | self.Imag() == 0: + ret self + | math::IsInf(self.Imag(), 0): + ret Cmplx.New(self.Imag(), self.Real()) + |: + ret Cmplx.NaN() + } + | math::IsInf(self.Imag(), 0): + ret Cmplx.New(math::Copysign(self.Imag(), self.Real()), math::Copysign(math::Pi / 2, self.Imag())) + } + xx := self.Mul(self) + x1 := Cmplx.New(1 + xx.Real(), xx.Imag()) // 1 + x*x + ret self.Add(x1.Sqrt()).Log() // log(x + sqrt(1 + x*x)) + } - // Complex circular arc cosine - // - // DESCRIPTION: - // - // w = arccos z = PI/2 - arcsin z. - // - // ACCURACY: - // - // Relative error: - // arithmetic domain # trials peak rms - // DEC -10,+10 5200 1.6e-15 2.8e-16 - // IEEE -10,+10 30000 1.8e-14 2.2e-15 + // Complex circular arc cosine + // + // DESCRIPTION: + // + // w = arccos z = PI/2 - arcsin z. + // + // ACCURACY: + // + // Relative error: + // arithmetic domain # trials peak rms + // DEC -10,+10 5200 1.6e-15 2.8e-16 + // IEEE -10,+10 30000 1.8e-14 2.2e-15 - // Returns the inverse cosine of complex number. - fn Acos(self): Cmplx { - w := self.Asin() - ret Cmplx.New(math::Pi / 2 - w.Real(), -w.Imag()) - } + // Returns the inverse cosine of complex number. + fn Acos(self): Cmplx { + w := self.Asin() + ret Cmplx.New(math::Pi / 2 - w.Real(), -w.Imag()) + } - // Returns the inverse hyperbolic cosine of complex number. - fn Acosh(self): Cmplx { - if self.IsZero() { - ret Cmplx.New(0, math::Copysign(math::Pi / 2, self.Imag())) - } - w := self.Acos() - if w.Imag() <= 0 { - ret Cmplx.New(-w.Imag(), w.Real()) // i * w - } - ret Cmplx.New(w.Imag(), -w.Real()) // -i * w - } + // Returns the inverse hyperbolic cosine of complex number. + fn Acosh(self): Cmplx { + if self.IsZero() { + ret Cmplx.New(0, math::Copysign(math::Pi / 2, self.Imag())) + } + w := self.Acos() + if w.Imag() <= 0 { + ret Cmplx.New(-w.Imag(), w.Real()) // i * w + } + ret Cmplx.New(w.Imag(), -w.Real()) // -i * w + } - // Complex circular arc tangent - // - // DESCRIPTION: - // - // If - // z = x + iy, - // - // then - // 1 ( 2x ) - // Re w = - arctan(-----------) + k PI - // 2 ( 2 2) - // (1 - x - y ) - // - // ( 2 2) - // 1 (x + (y+1) ) - // Im w = - log(------------) - // 4 ( 2 2) - // (x + (y-1) ) - // - // Where k is an arbitrary integer. - // - // catan(z) = -i catanh(iz). - // - // ACCURACY: - // - // Relative error: - // arithmetic domain # trials peak rms - // DEC -10,+10 5900 1.3e-16 7.8e-18 - // IEEE -10,+10 30000 2.3e-15 8.5e-17 - // The check catan( ctan(z) ) = z, with |x| and |y| < PI/2, - // had peak relative error 1.5e-16, rms relative error - // 2.9e-17. See also clog(). + // Complex circular arc tangent + // + // DESCRIPTION: + // + // If + // z = x + iy, + // + // then + // 1 ( 2x ) + // Re w = - arctan(-----------) + k PI + // 2 ( 2 2) + // (1 - x - y ) + // + // ( 2 2) + // 1 (x + (y+1) ) + // Im w = - log(------------) + // 4 ( 2 2) + // (x + (y-1) ) + // + // Where k is an arbitrary integer. + // + // catan(z) = -i catanh(iz). + // + // ACCURACY: + // + // Relative error: + // arithmetic domain # trials peak rms + // DEC -10,+10 5900 1.3e-16 7.8e-18 + // IEEE -10,+10 30000 2.3e-15 8.5e-17 + // The check catan( ctan(z) ) = z, with |x| and |y| < PI/2, + // had peak relative error 1.5e-16, rms relative error + // 2.9e-17. See also clog(). - // Returns the inverse tangent of complex number. - fn Atan(self): Cmplx { - match { - | self.Imag() == 0: - ret Cmplx.New(math::Atan(self.Real()), self.Imag()) - | self.Real() == 0 && math::Abs(self.Imag()) <= 1: - ret Cmplx.New(self.Real(), math::Atanh(self.Imag())) - | math::IsInf(self.Imag(), 0) | math::IsInf(self.Real(), 0): - if math::IsNaN(self.Real()) { - ret Cmplx.New(math::NaN(), math::Copysign(0, self.Imag())) - } - ret Cmplx.New(math::Copysign(math::Pi / 2, self.Real()), math::Copysign(0, self.Imag())) - | math::IsNaN(self.Real()) | math::IsNaN(self.Imag()): - ret Cmplx.NaN() - } - x2 := self.Real() * self.Real() - a := 1 - x2 - self.Imag() * self.Imag() - if a == 0 { - ret Cmplx.NaN() - } - mut t := 0.5 * math::Atan2(2 * self.Real(), a) - w := reducePi(t) + // Returns the inverse tangent of complex number. + fn Atan(self): Cmplx { + match { + | self.Imag() == 0: + ret Cmplx.New(math::Atan(self.Real()), self.Imag()) + | self.Real() == 0 && math::Abs(self.Imag()) <= 1: + ret Cmplx.New(self.Real(), math::Atanh(self.Imag())) + | math::IsInf(self.Imag(), 0) | math::IsInf(self.Real(), 0): + if math::IsNaN(self.Real()) { + ret Cmplx.New(math::NaN(), math::Copysign(0, self.Imag())) + } + ret Cmplx.New(math::Copysign(math::Pi / 2, self.Real()), math::Copysign(0, self.Imag())) + | math::IsNaN(self.Real()) | math::IsNaN(self.Imag()): + ret Cmplx.NaN() + } + x2 := self.Real() * self.Real() + a := 1 - x2 - self.Imag() * self.Imag() + if a == 0 { + ret Cmplx.NaN() + } + mut t := 0.5 * math::Atan2(2 * self.Real(), a) + w := reducePi(t) - t = self.Imag() - 1 - b := x2 + t * t - if b == 0 { - ret Cmplx.NaN() - } - t = self.Imag() + 1 - c := (x2 + t * t) / b - ret Cmplx.New(w, 0.25 * math::Log(c)) - } + t = self.Imag() - 1 + b := x2 + t * t + if b == 0 { + ret Cmplx.NaN() + } + t = self.Imag() + 1 + c := (x2 + t * t) / b + ret Cmplx.New(w, 0.25 * math::Log(c)) + } - // Returns the inverse hyperbolic tangent of complex number. - fn Atanh(self): Cmplx { - z := Cmplx.New(-self.Imag(), self.Real()).Atan() // z = atan(i * x) - ret Cmplx.New(z.Imag(), -z.Real()) // z = -i * z - } + // Returns the inverse hyperbolic tangent of complex number. + fn Atanh(self): Cmplx { + z := Cmplx.New(-self.Imag(), self.Real()).Atan() // z = atan(i * x) + ret Cmplx.New(z.Imag(), -z.Real()) // z = -i * z + } } \ No newline at end of file diff --git a/std/math/cmplx/cmplx.jule b/std/math/cmplx/cmplx.jule index fd7bb9974..bd77d6ea5 100644 --- a/std/math/cmplx/cmplx.jule +++ b/std/math/cmplx/cmplx.jule @@ -6,148 +6,148 @@ use math for std::math // Complex number. struct Cmplx { - real: f64 - imag: f64 + real: f64 + imag: f64 } impl Cmplx { - // Returns new complex number. - static fn New(real: f64, imag: f64): Cmplx { - ret Cmplx{ - real: real, - imag: imag, - } - } - - // Returns NaN complex number. - static fn NaN(): Cmplx { - ret Cmplx{ - real: math::NaN(), - imag: math::NaN(), - } - } - - // Returns Inf complex number. - // Uses positive infinity if sign >= 0, negative infinity if !sign < 0. - static fn Inf(sign: int): Cmplx { - ret Cmplx{ - real: math::Inf(sign), - imag: math::Inf(sign), - } - } - - // Returns zero complex number. - static fn Zero(): Cmplx { - ret Cmplx.New(0, 0) - } - - // Returns real part of complex number. - fn Real(self): f64 { - ret self.real - } - - // Returns imaginary part of complex number. - fn Imag(self): f64 { - ret self.imag - } - - // Returns conjugate of complex number. - fn Conj(self): Cmplx { - ret Cmplx.New(self.Real(), -self.Imag()) - } - - // Returns addition of complex numbers. - fn Add(self, c: Cmplx): Cmplx { - mut r := self - r += c - ret r - } - - // Add to complex number. - fn AddAssign(mut self, c: Cmplx) { - self.real += c.Real() - self.imag += c.Imag() - } - - // Returns subtraction of complex numbers. - fn Sub(self, c: Cmplx): Cmplx { - mut r := self - r -= c - ret r - } - - // Subtract from complex number. - fn SubAssign(mut self, c: Cmplx) { - self.real -= c.Real() - self.imag -= c.Imag() - } - - // Returns multiplication of complex numbers. - fn Mul(self, c: Cmplx): Cmplx { - mut r := self - r *= c - ret r - } - - // Multiply complex numbers. - fn MulAssign(mut self, c: Cmplx) { - real := self.Real() * c.Real() + self.Imag() * c.Imag() * -1 - imag := self.Real() * c.Imag() + self.Imag() * c.Real() - self.real = real - self.imag = imag - } - - // Returns division of complex numbers. - // Returns NaN complex number if denominator is zero. - fn Div(self, c: Cmplx): Cmplx { - mut r := self - r /= c - ret r - } - - // Divide complex numbers. - // Assigns NaN complex number if denominator is zero. - fn DivAssign(mut self, c: Cmplx) { - denominator := c.Real() * c.Real() + c.Imag() * c.Imag() - if denominator == 0 { - self.imag = math::NaN() - self.real = math::NaN() - ret - } - numerator := self.Real() * c.Real() + self.Imag() * c.Imag() - self.imag = (self.Imag() * c.Real() - self.Real() * c.Imag()) / denominator - self.real = numerator / denominator - } - - // Unary plus operator. - fn Pos(self): Cmplx { - ret Cmplx.New(+self.Real(), +self.Imag()) - } - - // Unary minus operator. - fn Neg(self): Cmplx { - ret Cmplx.New(-self.Real(), -self.Imag()) - } - - // Reports whether either real or imag is an infinity. - fn IsInf(self): bool { - ret math::IsInf(self.Real(), 0) || math::IsInf(self.Imag(), 0) - } - - // Reports whether either real or imag is NaN and neither is an infinity. - fn IsNaN(self): bool { - match { - | math::IsInf(self.Real(), 0) | math::IsInf(self.Imag(), 0): - ret false - | math::IsNaN(self.Real()) | math::IsNaN(self.Imag()): - ret true - |: - ret false - } - } - - // Reports whether real and imag is zero. - fn IsZero(self): bool { - ret self.Real() == 0 && self.Imag() == 0 - } + // Returns new complex number. + static fn New(real: f64, imag: f64): Cmplx { + ret Cmplx{ + real: real, + imag: imag, + } + } + + // Returns NaN complex number. + static fn NaN(): Cmplx { + ret Cmplx{ + real: math::NaN(), + imag: math::NaN(), + } + } + + // Returns Inf complex number. + // Uses positive infinity if sign >= 0, negative infinity if !sign < 0. + static fn Inf(sign: int): Cmplx { + ret Cmplx{ + real: math::Inf(sign), + imag: math::Inf(sign), + } + } + + // Returns zero complex number. + static fn Zero(): Cmplx { + ret Cmplx.New(0, 0) + } + + // Returns real part of complex number. + fn Real(self): f64 { + ret self.real + } + + // Returns imaginary part of complex number. + fn Imag(self): f64 { + ret self.imag + } + + // Returns conjugate of complex number. + fn Conj(self): Cmplx { + ret Cmplx.New(self.Real(), -self.Imag()) + } + + // Returns addition of complex numbers. + fn Add(self, c: Cmplx): Cmplx { + mut r := self + r += c + ret r + } + + // Add to complex number. + fn AddAssign(mut self, c: Cmplx) { + self.real += c.Real() + self.imag += c.Imag() + } + + // Returns subtraction of complex numbers. + fn Sub(self, c: Cmplx): Cmplx { + mut r := self + r -= c + ret r + } + + // Subtract from complex number. + fn SubAssign(mut self, c: Cmplx) { + self.real -= c.Real() + self.imag -= c.Imag() + } + + // Returns multiplication of complex numbers. + fn Mul(self, c: Cmplx): Cmplx { + mut r := self + r *= c + ret r + } + + // Multiply complex numbers. + fn MulAssign(mut self, c: Cmplx) { + real := self.Real() * c.Real() + self.Imag() * c.Imag() * -1 + imag := self.Real() * c.Imag() + self.Imag() * c.Real() + self.real = real + self.imag = imag + } + + // Returns division of complex numbers. + // Returns NaN complex number if denominator is zero. + fn Div(self, c: Cmplx): Cmplx { + mut r := self + r /= c + ret r + } + + // Divide complex numbers. + // Assigns NaN complex number if denominator is zero. + fn DivAssign(mut self, c: Cmplx) { + denominator := c.Real() * c.Real() + c.Imag() * c.Imag() + if denominator == 0 { + self.imag = math::NaN() + self.real = math::NaN() + ret + } + numerator := self.Real() * c.Real() + self.Imag() * c.Imag() + self.imag = (self.Imag() * c.Real() - self.Real() * c.Imag()) / denominator + self.real = numerator / denominator + } + + // Unary plus operator. + fn Pos(self): Cmplx { + ret Cmplx.New(+self.Real(), +self.Imag()) + } + + // Unary minus operator. + fn Neg(self): Cmplx { + ret Cmplx.New(-self.Real(), -self.Imag()) + } + + // Reports whether either real or imag is an infinity. + fn IsInf(self): bool { + ret math::IsInf(self.Real(), 0) || math::IsInf(self.Imag(), 0) + } + + // Reports whether either real or imag is NaN and neither is an infinity. + fn IsNaN(self): bool { + match { + | math::IsInf(self.Real(), 0) | math::IsInf(self.Imag(), 0): + ret false + | math::IsNaN(self.Real()) | math::IsNaN(self.Imag()): + ret true + |: + ret false + } + } + + // Reports whether real and imag is zero. + fn IsZero(self): bool { + ret self.Real() == 0 && self.Imag() == 0 + } } \ No newline at end of file diff --git a/std/math/cmplx/exp.jule b/std/math/cmplx/exp.jule index 01da23760..1f45b5709 100644 --- a/std/math/cmplx/exp.jule +++ b/std/math/cmplx/exp.jule @@ -50,26 +50,26 @@ use math for std::math // IEEE -10,+10 30000 3.0e-16 8.7e-17 impl Cmplx { - // Returns e**x, the base-e exponential of x. - fn Exp(self): Cmplx { - match { - | math::IsInf(self.Real(), 0): - match { - | self.Real() > 0 && self.Imag() == 0: - ret self - | math::IsInf(self.Imag(), 0) | math::IsNaN(self.Imag()): - if self.Real() < 0 { - ret Cmplx.New(0, math::Copysign(0, self.Imag())) - } - ret Cmplx.New(math::Inf(1.0), math::NaN()) - } - | math::IsNaN(self.Real()): - if self.Imag() == 0 { - ret Cmplx.New(math::NaN(), self.Imag()) - } - } - r := math::Exp(self.Real()) - s, c := math::Sincos(self.Imag()) - ret Cmplx.New(r * c, r * s) - } + // Returns e**x, the base-e exponential of x. + fn Exp(self): Cmplx { + match { + | math::IsInf(self.Real(), 0): + match { + | self.Real() > 0 && self.Imag() == 0: + ret self + | math::IsInf(self.Imag(), 0) | math::IsNaN(self.Imag()): + if self.Real() < 0 { + ret Cmplx.New(0, math::Copysign(0, self.Imag())) + } + ret Cmplx.New(math::Inf(1.0), math::NaN()) + } + | math::IsNaN(self.Real()): + if self.Imag() == 0 { + ret Cmplx.New(math::NaN(), self.Imag()) + } + } + r := math::Exp(self.Real()) + s, c := math::Sincos(self.Imag()) + ret Cmplx.New(r * c, r * s) + } } \ No newline at end of file diff --git a/std/math/cmplx/log.jule b/std/math/cmplx/log.jule index 0ed59feca..d87da60ab 100644 --- a/std/math/cmplx/log.jule +++ b/std/math/cmplx/log.jule @@ -56,14 +56,14 @@ use math for std::math // absolute error 1.0e-16. impl Cmplx { - // Returns the natural logarithm of complex number. - fn Log(self): Cmplx { - ret Cmplx.New(math::Log(self.Abs()), self.Phase()) - } + // Returns the natural logarithm of complex number. + fn Log(self): Cmplx { + ret Cmplx.New(math::Log(self.Abs()), self.Phase()) + } - // Returns the decimal logarithm of complex number. - fn Log10(self): Cmplx { - z := self.Log() - ret Cmplx.New(math::Log10E * z.Real(), math::Log10E * z.Imag()) - } + // Returns the decimal logarithm of complex number. + fn Log10(self): Cmplx { + z := self.Log() + ret Cmplx.New(math::Log10E * z.Real(), math::Log10E * z.Imag()) + } } \ No newline at end of file diff --git a/std/math/cmplx/phase.jule b/std/math/cmplx/phase.jule index 25dd78002..708a1d1d2 100644 --- a/std/math/cmplx/phase.jule +++ b/std/math/cmplx/phase.jule @@ -8,9 +8,9 @@ use math for std::math // https://github.com/golang/go/blob/go1.20/src/math/cmplx/phase.go impl Cmplx { - // Phase returns the phase (also called the argument) of x. - // The returned value is in the range [-PI, PI]. - fn Phase(self): f64 { - ret math::Atan2(self.Imag(), self.Real()) - } + // Phase returns the phase (also called the argument) of x. + // The returned value is in the range [-PI, PI]. + fn Phase(self): f64 { + ret math::Atan2(self.Imag(), self.Real()) + } } \ No newline at end of file diff --git a/std/math/cmplx/polar.jule b/std/math/cmplx/polar.jule index 4e3901a0b..a16457cf2 100644 --- a/std/math/cmplx/polar.jule +++ b/std/math/cmplx/polar.jule @@ -8,10 +8,10 @@ use math for std::math // https://github.com/golang/go/blob/go1.20/src/math/cmplx/polar.go impl Cmplx { - // Polar returns the absolute value r and phase θ of x, - // such that x = r * e**θi. - // The phase is in the range [-PI, PI]. - fn Polar(self): (r: f64, theta: f64) { - ret self.Abs(), self.Phase() - } + // Polar returns the absolute value r and phase θ of x, + // such that x = r * e**θi. + // The phase is in the range [-PI, PI]. + fn Polar(self): (r: f64, theta: f64) { + ret self.Abs(), self.Phase() + } } \ No newline at end of file diff --git a/std/math/cmplx/pow.jule b/std/math/cmplx/pow.jule index 450a55f52..a8d71341f 100644 --- a/std/math/cmplx/pow.jule +++ b/std/math/cmplx/pow.jule @@ -45,41 +45,41 @@ use math for std::math // IEEE -10,+10 30000 9.4e-15 1.5e-15 impl Cmplx { - // Returns x**y, the base-x (self) exponential of y. - // For generalized compatibility with [math::pow]: - // - // Pow(0, ±0) returns 1+0i - // Pow(0, c) for c.real()<0 returns inf+0i if c.imag() is zero, otherwise inf+inf i. - fn Pow(self, y: Cmplx): Cmplx { - if self.IsZero() { // Guaranteed also true for x == -0. - if y.IsNaN() { - ret Cmplx.NaN() - } - match { - | y.Real() == 0: - ret Cmplx.New(1, 0) - | y.Real() < 0: - if y.Imag() == 0 { - ret Cmplx.New(math::Inf(1), 0) - } - ret Cmplx.Inf(1) - | y.Real() > 0: - ret Cmplx.Zero() - } - panic("not reached") - } - modulus := self.Abs() - if modulus == 0 { - ret Cmplx.Zero() - } - mut r := math::Pow(modulus, y.Real()) - arg := self.Phase() - mut theta := y.Real() * arg - if y.Imag() != 0 { - r *= math::Exp(-y.Imag() * arg) - theta += y.Imag() * math::Log(modulus) - } - s, c := math::Sincos(theta) - ret Cmplx.New(r * c, r * s) - } + // Returns x**y, the base-x (self) exponential of y. + // For generalized compatibility with [math::pow]: + // + // Pow(0, ±0) returns 1+0i + // Pow(0, c) for c.real()<0 returns inf+0i if c.imag() is zero, otherwise inf+inf i. + fn Pow(self, y: Cmplx): Cmplx { + if self.IsZero() { // Guaranteed also true for x == -0. + if y.IsNaN() { + ret Cmplx.NaN() + } + match { + | y.Real() == 0: + ret Cmplx.New(1, 0) + | y.Real() < 0: + if y.Imag() == 0 { + ret Cmplx.New(math::Inf(1), 0) + } + ret Cmplx.Inf(1) + | y.Real() > 0: + ret Cmplx.Zero() + } + panic("not reached") + } + modulus := self.Abs() + if modulus == 0 { + ret Cmplx.Zero() + } + mut r := math::Pow(modulus, y.Real()) + arg := self.Phase() + mut theta := y.Real() * arg + if y.Imag() != 0 { + r *= math::Exp(-y.Imag() * arg) + theta += y.Imag() * math::Log(modulus) + } + s, c := math::Sincos(theta) + ret Cmplx.New(r * c, r * s) + } } \ No newline at end of file diff --git a/std/math/cmplx/rect.jule b/std/math/cmplx/rect.jule index 5dbb6ba16..6d4e4c703 100644 --- a/std/math/cmplx/rect.jule +++ b/std/math/cmplx/rect.jule @@ -8,9 +8,9 @@ use math for std::math // https://github.com/golang/go/blob/go1.20/src/math/cmplx/rect.go impl Cmplx { - // Returns the complex number with polar coordinates r, θ. - static fn Rect(r: f64, theta: f64): Cmplx { - s, c := math::Sincos(theta) - ret Cmplx.New(r * c, r * s) - } + // Returns the complex number with polar coordinates r, θ. + static fn Rect(r: f64, theta: f64): Cmplx { + s, c := math::Sincos(theta) + ret Cmplx.New(r * c, r * s) + } } \ No newline at end of file diff --git a/std/math/cmplx/sin.jule b/std/math/cmplx/sin.jule index 9a1bc7f66..9e491cd0d 100644 --- a/std/math/cmplx/sin.jule +++ b/std/math/cmplx/sin.jule @@ -31,158 +31,158 @@ use math for std::math // moshier@na-net.ornl.gov impl Cmplx { - // Complex circular sine - // - // DESCRIPTION: - // - // If - // z = x + iy, - // - // then - // - // w = sin x cosh y + i cos x sinh y. - // - // csin(z) = -i csinh(iz). - // - // ACCURACY: - // - // Relative error: - // arithmetic domain # trials peak rms - // DEC -10,+10 8400 5.3e-17 1.3e-17 - // IEEE -10,+10 30000 3.8e-16 1.0e-16 - // Also tested by csin(casin(z)) = z. + // Complex circular sine + // + // DESCRIPTION: + // + // If + // z = x + iy, + // + // then + // + // w = sin x cosh y + i cos x sinh y. + // + // csin(z) = -i csinh(iz). + // + // ACCURACY: + // + // Relative error: + // arithmetic domain # trials peak rms + // DEC -10,+10 8400 5.3e-17 1.3e-17 + // IEEE -10,+10 30000 3.8e-16 1.0e-16 + // Also tested by csin(casin(z)) = z. - // Returns the sine of complex number. - fn Sin(self): Cmplx { - match { - | self.Imag() == 0 && (math::IsInf(self.Real(), 0) || math::IsNaN(self.Real())): - ret Cmplx.New(math::NaN(), self.Imag()) - | math::IsInf(self.Imag(), 0): - match { - | self.Real() == 0: - ret self - | math::IsInf(self.Real(), 0) | math::IsNaN(self.Real()): - ret Cmplx.New(math::NaN(), self.Imag()) - } - | self.Real() == 0 && math::IsNaN(self.Imag()): - ret self - } - s, c := math::Sincos(self.Real()) - sh, ch := sinhcosh(self.Imag()) - ret Cmplx.New(s * ch, c * sh) - } + // Returns the sine of complex number. + fn Sin(self): Cmplx { + match { + | self.Imag() == 0 && (math::IsInf(self.Real(), 0) || math::IsNaN(self.Real())): + ret Cmplx.New(math::NaN(), self.Imag()) + | math::IsInf(self.Imag(), 0): + match { + | self.Real() == 0: + ret self + | math::IsInf(self.Real(), 0) | math::IsNaN(self.Real()): + ret Cmplx.New(math::NaN(), self.Imag()) + } + | self.Real() == 0 && math::IsNaN(self.Imag()): + ret self + } + s, c := math::Sincos(self.Real()) + sh, ch := sinhcosh(self.Imag()) + ret Cmplx.New(s * ch, c * sh) + } - // Complex hyperbolic sine - // - // DESCRIPTION: - // - // csinh z = (cexp(z) - cexp(-z))/2 - // = sinh x * cos y + i cosh x * sin y . - // - // ACCURACY: - // - // Relative error: - // arithmetic domain # trials peak rms - // IEEE -10,+10 30000 3.1e-16 8.2e-17 + // Complex hyperbolic sine + // + // DESCRIPTION: + // + // csinh z = (cexp(z) - cexp(-z))/2 + // = sinh x * cos y + i cosh x * sin y . + // + // ACCURACY: + // + // Relative error: + // arithmetic domain # trials peak rms + // IEEE -10,+10 30000 3.1e-16 8.2e-17 - // Returns the hyperbolic sine of complex number. - fn Sinh(self): Cmplx { - match { - | self.Real() == 0 && (math::IsInf(self.Imag(), 0) || math::IsNaN(self.Imag())): - ret Cmplx.New(self.Real(), math::NaN()) - | math::IsInf(self.Real(), 0): - match { - | self.Imag() == 0: - ret Cmplx.New(self.Real(), self.Imag()) - | math::IsInf(self.Imag(), 0) | math::IsNaN(self.Imag()): - ret Cmplx.New(self.Real(), math::NaN()) - } - | self.Imag() == 0 && math::IsNaN(self.Real()): - ret Cmplx.New(math::NaN(), self.Imag()) - } - s, c := math::Sincos(self.Imag()) - sh, ch := sinhcosh(self.Real()) - ret Cmplx.New(c * sh, s * ch) - } + // Returns the hyperbolic sine of complex number. + fn Sinh(self): Cmplx { + match { + | self.Real() == 0 && (math::IsInf(self.Imag(), 0) || math::IsNaN(self.Imag())): + ret Cmplx.New(self.Real(), math::NaN()) + | math::IsInf(self.Real(), 0): + match { + | self.Imag() == 0: + ret Cmplx.New(self.Real(), self.Imag()) + | math::IsInf(self.Imag(), 0) | math::IsNaN(self.Imag()): + ret Cmplx.New(self.Real(), math::NaN()) + } + | self.Imag() == 0 && math::IsNaN(self.Real()): + ret Cmplx.New(math::NaN(), self.Imag()) + } + s, c := math::Sincos(self.Imag()) + sh, ch := sinhcosh(self.Real()) + ret Cmplx.New(c * sh, s * ch) + } - // Complex circular cosine - // - // DESCRIPTION: - // - // If - // z = x + iy, - // - // then - // - // w = cos x cosh y - i sin x sinh y. - // - // ACCURACY: - // - // Relative error: - // arithmetic domain # trials peak rms - // DEC -10,+10 8400 4.5e-17 1.3e-17 - // IEEE -10,+10 30000 3.8e-16 1.0e-16 + // Complex circular cosine + // + // DESCRIPTION: + // + // If + // z = x + iy, + // + // then + // + // w = cos x cosh y - i sin x sinh y. + // + // ACCURACY: + // + // Relative error: + // arithmetic domain # trials peak rms + // DEC -10,+10 8400 4.5e-17 1.3e-17 + // IEEE -10,+10 30000 3.8e-16 1.0e-16 - // Returns the cosine of complex number. - fn Cos(self): Cmplx { - match { - | self.Imag() == 0 && (math::IsInf(self.Real(), 0) || math::IsNaN(self.Real())): - ret Cmplx.New(math::NaN(), -self.Imag() * math::Copysign(0, self.Real())) - | math::IsInf(self.Imag(), 0): - match { - | self.Real() == 0: - ret Cmplx.New(math::Inf(1), -self.Real() * math::Copysign(0, self.Imag())) - | math::IsInf(self.Real(), 0) | math::IsNaN(self.Real()): - ret Cmplx.New(math::Inf(1), math::NaN()) - } - | self.Real() == 0 && math::IsNaN(self.Imag()): - ret Cmplx.New(math::NaN(), 0) - } - s, c := math::Sincos(self.Real()) - sh, ch := sinhcosh(self.Imag()) - ret Cmplx.New(c * ch, -s * sh) - } + // Returns the cosine of complex number. + fn Cos(self): Cmplx { + match { + | self.Imag() == 0 && (math::IsInf(self.Real(), 0) || math::IsNaN(self.Real())): + ret Cmplx.New(math::NaN(), -self.Imag() * math::Copysign(0, self.Real())) + | math::IsInf(self.Imag(), 0): + match { + | self.Real() == 0: + ret Cmplx.New(math::Inf(1), -self.Real() * math::Copysign(0, self.Imag())) + | math::IsInf(self.Real(), 0) | math::IsNaN(self.Real()): + ret Cmplx.New(math::Inf(1), math::NaN()) + } + | self.Real() == 0 && math::IsNaN(self.Imag()): + ret Cmplx.New(math::NaN(), 0) + } + s, c := math::Sincos(self.Real()) + sh, ch := sinhcosh(self.Imag()) + ret Cmplx.New(c * ch, -s * sh) + } - // Complex hyperbolic cosine - // - // DESCRIPTION: - // - // ccosh(z) = cosh x cos y + i sinh x sin y . - // - // ACCURACY: - // - // Relative error: - // arithmetic domain # trials peak rms - // IEEE -10,+10 30000 2.9e-16 8.1e-17 + // Complex hyperbolic cosine + // + // DESCRIPTION: + // + // ccosh(z) = cosh x cos y + i sinh x sin y . + // + // ACCURACY: + // + // Relative error: + // arithmetic domain # trials peak rms + // IEEE -10,+10 30000 2.9e-16 8.1e-17 - // Returns the hyperbolic cosine of complex number. - fn Cosh(self): Cmplx { - match { - | self.Real() == 0 && (math::IsInf(self.Imag(), 0) || math::IsNaN(self.Imag())): - ret Cmplx.New(math::NaN(), self.Real() * math::Copysign(0, self.Imag())) - | math::IsInf(self.Real(), 0): - match { - | self.Imag() == 0: - ret Cmplx.New(math::Inf(1), self.Imag() * math::Copysign(0, self.Real())) - | math::IsInf(self.Imag(), 0) || math::IsNaN(self.Imag()): - ret Cmplx.New(math::Inf(1), math::NaN()) - } - | self.Imag() == 0 && math::IsNaN(self.Real()): - ret Cmplx.New(math::NaN(), self.Imag()) - } - s, c := math::Sincos(self.Imag()) - sh, ch := sinhcosh(self.Real()) - ret Cmplx.New(c * ch, s * sh) - } + // Returns the hyperbolic cosine of complex number. + fn Cosh(self): Cmplx { + match { + | self.Real() == 0 && (math::IsInf(self.Imag(), 0) || math::IsNaN(self.Imag())): + ret Cmplx.New(math::NaN(), self.Real() * math::Copysign(0, self.Imag())) + | math::IsInf(self.Real(), 0): + match { + | self.Imag() == 0: + ret Cmplx.New(math::Inf(1), self.Imag() * math::Copysign(0, self.Real())) + | math::IsInf(self.Imag(), 0) || math::IsNaN(self.Imag()): + ret Cmplx.New(math::Inf(1), math::NaN()) + } + | self.Imag() == 0 && math::IsNaN(self.Real()): + ret Cmplx.New(math::NaN(), self.Imag()) + } + s, c := math::Sincos(self.Imag()) + sh, ch := sinhcosh(self.Real()) + ret Cmplx.New(c * ch, s * sh) + } } // calculate sinh and cosh. fn sinhcosh(x: f64): (sh: f64, ch: f64) { - if math::Abs(x) <= 0.5 { - ret math::Sinh(x), math::Cosh(x) - } - mut e := math::Exp(x) - ei := 0.5 / e - e *= 0.5 - ret e - ei, e + ei + if math::Abs(x) <= 0.5 { + ret math::Sinh(x), math::Cosh(x) + } + mut e := math::Exp(x) + ei := 0.5 / e + e *= 0.5 + ret e - ei, e + ei } \ No newline at end of file diff --git a/std/math/cmplx/sqrt.jule b/std/math/cmplx/sqrt.jule index 7e64bd1ff..63153892b 100644 --- a/std/math/cmplx/sqrt.jule +++ b/std/math/cmplx/sqrt.jule @@ -56,56 +56,56 @@ use math for std::math // IEEE -10,+10 1,000,000 2.9e-16 6.1e-17 impl Cmplx { - // Returns the square root of complex number. - // The result r is chosen so that r.real() ≥ 0 and r.imag() has the same sign as self.imag(). - fn Sqrt(self): Cmplx { - if self.Imag() == 0 { - // Ensure that imag(r) has the same sign as imag(x) for imag(x) == signed zero. - if self.Real() == 0 { - ret Cmplx.New(0, self.Imag()) - } - if self.Real() < 0 { - ret Cmplx.New(0, math::Copysign(math::Sqrt(-self.Real()), self.Imag())) - } - ret Cmplx.New(math::Sqrt(self.Real()), self.Imag()) - } else if math::IsInf(self.Imag(), 0) { - ret Cmplx.New(math::Inf(1.0), self.Imag()) - } - if self.Real() == 0 { - if self.Imag() < 0 { - r := math::Sqrt(-0.5 * self.Imag()) - ret Cmplx.New(r, -r) - } - r := math::Sqrt(0.5 * self.Imag()) - ret Cmplx.New(r, r) - } - mut a := self.Real() - mut b := self.Imag() - mut scale := 0. - // Rescale to avoid internal overflow or underflow. - if math::Abs(a) > 4 || math::Abs(b) > 4 { - a *= 0.25 - b *= 0.25 - scale = 2 - } else { - a *= 1.8014398509481984e16 // 2**54 - b *= 1.8014398509481984e16 - scale = 7.450580596923828125e-9 // 2**-27 - } - mut r := math::Hypot(a, b) - mut t := 0. - if a > 0 { - t = math::Sqrt(0.5 * r + 0.5 * a) - r = scale * math::Abs((0.5 * b) / t) - t *= scale - } else { - r = math::Sqrt(0.5 * r - 0.5 * a) - t = scale * math::Abs((0.5 * b) / r) - r *= scale - } - if b < 0 { - ret Cmplx.New(t, -r) - } - ret Cmplx.New(t, r) - } + // Returns the square root of complex number. + // The result r is chosen so that r.real() ≥ 0 and r.imag() has the same sign as self.imag(). + fn Sqrt(self): Cmplx { + if self.Imag() == 0 { + // Ensure that imag(r) has the same sign as imag(x) for imag(x) == signed zero. + if self.Real() == 0 { + ret Cmplx.New(0, self.Imag()) + } + if self.Real() < 0 { + ret Cmplx.New(0, math::Copysign(math::Sqrt(-self.Real()), self.Imag())) + } + ret Cmplx.New(math::Sqrt(self.Real()), self.Imag()) + } else if math::IsInf(self.Imag(), 0) { + ret Cmplx.New(math::Inf(1.0), self.Imag()) + } + if self.Real() == 0 { + if self.Imag() < 0 { + r := math::Sqrt(-0.5 * self.Imag()) + ret Cmplx.New(r, -r) + } + r := math::Sqrt(0.5 * self.Imag()) + ret Cmplx.New(r, r) + } + mut a := self.Real() + mut b := self.Imag() + mut scale := 0. + // Rescale to avoid internal overflow or underflow. + if math::Abs(a) > 4 || math::Abs(b) > 4 { + a *= 0.25 + b *= 0.25 + scale = 2 + } else { + a *= 1.8014398509481984e16 // 2**54 + b *= 1.8014398509481984e16 + scale = 7.450580596923828125e-9 // 2**-27 + } + mut r := math::Hypot(a, b) + mut t := 0. + if a > 0 { + t = math::Sqrt(0.5 * r + 0.5 * a) + r = scale * math::Abs((0.5 * b) / t) + t *= scale + } else { + r = math::Sqrt(0.5 * r - 0.5 * a) + t = scale * math::Abs((0.5 * b) / r) + r *= scale + } + if b < 0 { + ret Cmplx.New(t, -r) + } + ret Cmplx.New(t, r) + } } \ No newline at end of file diff --git a/std/math/cmplx/tan.jule b/std/math/cmplx/tan.jule index fdfca6df1..f86d4041f 100644 --- a/std/math/cmplx/tan.jule +++ b/std/math/cmplx/tan.jule @@ -32,122 +32,122 @@ use bits for std::math::bits // moshier@na-net.ornl.gov impl Cmplx { - // Complex circular tangent - // - // DESCRIPTION: - // - // If - // z = x + iy, - // - // then - // - // sin 2x + i sinh 2y - // w = --------------------. - // cos 2x + cosh 2y - // - // On the real axis the denominator is zero at odd multiples - // of PI/2. The denominator is evaluated by its Taylor - // series near these points. - // - // ctan(z) = -i ctanh(iz). - // - // ACCURACY: - // - // Relative error: - // arithmetic domain # trials peak rms - // DEC -10,+10 5200 7.1e-17 1.6e-17 - // IEEE -10,+10 30000 7.2e-16 1.2e-16 - // Also tested by ctan * ccot = 1 and catan(ctan(z)) = z. + // Complex circular tangent + // + // DESCRIPTION: + // + // If + // z = x + iy, + // + // then + // + // sin 2x + i sinh 2y + // w = --------------------. + // cos 2x + cosh 2y + // + // On the real axis the denominator is zero at odd multiples + // of PI/2. The denominator is evaluated by its Taylor + // series near these points. + // + // ctan(z) = -i ctanh(iz). + // + // ACCURACY: + // + // Relative error: + // arithmetic domain # trials peak rms + // DEC -10,+10 5200 7.1e-17 1.6e-17 + // IEEE -10,+10 30000 7.2e-16 1.2e-16 + // Also tested by ctan * ccot = 1 and catan(ctan(z)) = z. - // Returns the tangent of complex number. - fn Tan(self): Cmplx { - match { - | math::IsInf(self.Imag(), 0): - match { - | math::IsInf(self.Real(), 0) | math::IsNaN(self.Real()): - ret Cmplx.New(math::Copysign(0, self.Real()), math::Copysign(1, self.Imag())) - } - ret Cmplx.New(math::Copysign(0, math::Sin(2 * self.Real())), math::Copysign(1, self.Imag())) - | self.Real() == 0 && math::IsNaN(self.Imag()): - ret self - } - mut d := math::Cos(2 * self.Real()) + math::Cosh(2 * self.Imag()) - if math::Abs(d) < 0.25 { - d = tanSeries(self) - } - if d == 0 { - ret Cmplx.Inf(1) - } - ret Cmplx.New(math::Sin(2 * self.Real()) / d, math::Sinh(2 * self.Imag()) / d) - } + // Returns the tangent of complex number. + fn Tan(self): Cmplx { + match { + | math::IsInf(self.Imag(), 0): + match { + | math::IsInf(self.Real(), 0) | math::IsNaN(self.Real()): + ret Cmplx.New(math::Copysign(0, self.Real()), math::Copysign(1, self.Imag())) + } + ret Cmplx.New(math::Copysign(0, math::Sin(2 * self.Real())), math::Copysign(1, self.Imag())) + | self.Real() == 0 && math::IsNaN(self.Imag()): + ret self + } + mut d := math::Cos(2 * self.Real()) + math::Cosh(2 * self.Imag()) + if math::Abs(d) < 0.25 { + d = tanSeries(self) + } + if d == 0 { + ret Cmplx.Inf(1) + } + ret Cmplx.New(math::Sin(2 * self.Real()) / d, math::Sinh(2 * self.Imag()) / d) + } - // Complex hyperbolic tangent - // - // DESCRIPTION: - // - // tanh z = (sinh 2x + i sin 2y) / (cosh 2x + cos 2y) . - // - // ACCURACY: - // - // Relative error: - // arithmetic domain # trials peak rms - // IEEE -10,+10 30000 1.7e-14 2.4e-16 + // Complex hyperbolic tangent + // + // DESCRIPTION: + // + // tanh z = (sinh 2x + i sin 2y) / (cosh 2x + cos 2y) . + // + // ACCURACY: + // + // Relative error: + // arithmetic domain # trials peak rms + // IEEE -10,+10 30000 1.7e-14 2.4e-16 - // Returns the hyperbolic tangent of complex number. - fn Tanh(self): Cmplx { - match { - | math::IsInf(self.Real(), 0): - match { - | math::IsInf(self.Imag(), 0) | math::IsNaN(self.Imag()): - ret Cmplx.New(math::Copysign(1, self.Real()), math::Copysign(0, self.Imag())) - } - ret Cmplx.New(math::Copysign(1, self.Real()), math::Copysign(0, math::Sin(2 * self.Imag()))) - | self.Imag() == 0 && math::IsNaN(self.Real()): - ret self - } - d := math::Cosh(2 * self.Real()) + math::Cos(2 * self.Imag()) - if d == 0 { - ret Cmplx.Inf(1) - } - ret Cmplx.New(math::Sinh(2 * self.Real()) / d, math::Sin(2 * self.Imag()) / d) - } + // Returns the hyperbolic tangent of complex number. + fn Tanh(self): Cmplx { + match { + | math::IsInf(self.Real(), 0): + match { + | math::IsInf(self.Imag(), 0) | math::IsNaN(self.Imag()): + ret Cmplx.New(math::Copysign(1, self.Real()), math::Copysign(0, self.Imag())) + } + ret Cmplx.New(math::Copysign(1, self.Real()), math::Copysign(0, math::Sin(2 * self.Imag()))) + | self.Imag() == 0 && math::IsNaN(self.Real()): + ret self + } + d := math::Cosh(2 * self.Real()) + math::Cos(2 * self.Imag()) + if d == 0 { + ret Cmplx.Inf(1) + } + ret Cmplx.New(math::Sinh(2 * self.Real()) / d, math::Sin(2 * self.Imag()) / d) + } - // Complex circular cotangent - // - // DESCRIPTION: - // - // If - // z = x + iy, - // - // then - // - // sin 2x - i sinh 2y - // w = --------------------. - // cosh 2y - cos 2x - // - // On the real axis, the denominator has zeros at even - // multiples of PI/2. Near these points it is evaluated - // by a Taylor series. - // - // ACCURACY: - // - // Relative error: - // arithmetic domain # trials peak rms - // DEC -10,+10 3000 6.5e-17 1.6e-17 - // IEEE -10,+10 30000 9.2e-16 1.2e-16 - // Also tested by ctan * ccot = 1 + i0. + // Complex circular cotangent + // + // DESCRIPTION: + // + // If + // z = x + iy, + // + // then + // + // sin 2x - i sinh 2y + // w = --------------------. + // cosh 2y - cos 2x + // + // On the real axis, the denominator has zeros at even + // multiples of PI/2. Near these points it is evaluated + // by a Taylor series. + // + // ACCURACY: + // + // Relative error: + // arithmetic domain # trials peak rms + // DEC -10,+10 3000 6.5e-17 1.6e-17 + // IEEE -10,+10 30000 9.2e-16 1.2e-16 + // Also tested by ctan * ccot = 1 + i0. - // Returns the cotangent of complex number. - fn Cot(self): Cmplx { - mut d := math::Cosh(2 * self.Imag()) - math::Cos(2 * self.Real()) - if math::Abs(d) < 0.25 { - d = tanSeries(self) - } - if d == 0 { - ret Cmplx.Inf(1) - } - ret Cmplx.New(math::Sin(2 * self.Real()) / d, -math::Sinh(2 * self.Imag()) / d) - } + // Returns the cotangent of complex number. + fn Cot(self): Cmplx { + mut d := math::Cosh(2 * self.Imag()) - math::Cos(2 * self.Real()) + if math::Abs(d) < 0.25 { + d = tanSeries(self) + } + if d == 0 { + ret Cmplx.Inf(1) + } + ret Cmplx.New(math::Sin(2 * self.Real()) / d, -math::Sinh(2 * self.Imag()) / d) + } } // Reduces the input argument x to the range (-PI/2, PI/2]. @@ -159,141 +159,141 @@ impl Cmplx { // "ARGUMENT REDUCTION FOR HUGE ARGUMENTS: Good to the Last Bit" // K. C. Ng et al, March 24, 1992. fn reducePi(mut x: f64): f64 { - // reduce_threshold is the maximum value of x where the reduction using - // Cody-Waite reduction still gives accurate results. This threshold - // is set by t*PIn being representable as a float64 without error - // where t is given by t = floor(x * (1 / PI)) and PIn are the leading partial - // terms of PI. Since the leading terms, PI1 and PI2 below, have 30 and 32 - // trailing zero bits respectively, t should have less than 30 significant bits. - // t < 1<<30 -> floor(x*(1/PI)+0.5) < 1<<30 -> x < (1<<30-1) * PI - 0.5 - // So, conservatively we can take x < 1<<30. - const REDUCE_THRESHOLD: f64 = 1 << 30 + // reduce_threshold is the maximum value of x where the reduction using + // Cody-Waite reduction still gives accurate results. This threshold + // is set by t*PIn being representable as a float64 without error + // where t is given by t = floor(x * (1 / PI)) and PIn are the leading partial + // terms of PI. Since the leading terms, PI1 and PI2 below, have 30 and 32 + // trailing zero bits respectively, t should have less than 30 significant bits. + // t < 1<<30 -> floor(x*(1/PI)+0.5) < 1<<30 -> x < (1<<30-1) * PI - 0.5 + // So, conservatively we can take x < 1<<30. + const REDUCE_THRESHOLD: f64 = 1 << 30 - if math::Abs(x) < REDUCE_THRESHOLD { - // Use Cody-Waite reduction in three parts. + if math::Abs(x) < REDUCE_THRESHOLD { + // Use Cody-Waite reduction in three parts. - // PI1, PI2 and PI3 comprise an extended precision value of PI - // such that PI ~= PI1 + PI2 + PI3. The parts are chosen so - // that PI1 and PI2 have an approximately equal number of trailing - // zero bits. This ensures that t*PI1 and t*PI2 are exact for - // large integer values of t. The full precision PI3 ensures the - // approximation of PI is accurate to 102 bits to handle cancellation - // during subtraction. - const PI1 = 3.141592502593994 // 0x400921fb40000000 - const PI2 = 1.5099578831723193e-07 // 0x3e84442d00000000 - const PI3 = 1.0780605716316238e-14 // 0x3d08469898cc5170 + // PI1, PI2 and PI3 comprise an extended precision value of PI + // such that PI ~= PI1 + PI2 + PI3. The parts are chosen so + // that PI1 and PI2 have an approximately equal number of trailing + // zero bits. This ensures that t*PI1 and t*PI2 are exact for + // large integer values of t. The full precision PI3 ensures the + // approximation of PI is accurate to 102 bits to handle cancellation + // during subtraction. + const PI1 = 3.141592502593994 // 0x400921fb40000000 + const PI2 = 1.5099578831723193e-07 // 0x3e84442d00000000 + const PI3 = 1.0780605716316238e-14 // 0x3d08469898cc5170 - mut t := x / math::Pi - t += 0.5 - t = f64(i64(t)) // i64(t) = the multiple - ret ((x - t * PI1) - t * PI2) - t * PI3 - } - // Must apply Payne-Hanek range reduction - const MASK = 0x7FF - const SHIFT = 64 - 11 - 1 - const BIAS = 1023 - const FRAC_MASK = 1 << SHIFT - 1 + mut t := x / math::Pi + t += 0.5 + t = f64(i64(t)) // i64(t) = the multiple + ret ((x - t * PI1) - t * PI2) - t * PI3 + } + // Must apply Payne-Hanek range reduction + const MASK = 0x7FF + const SHIFT = 64 - 11 - 1 + const BIAS = 1023 + const FRAC_MASK = 1 << SHIFT - 1 - // Extract out the integer and exponent such that, - // x = ix * 2 ** exp. - mut ix := math::F64Bits(x) - exp := int(ix >> SHIFT & MASK) - BIAS - SHIFT - ix &= FRAC_MASK - ix |= 1 << SHIFT + // Extract out the integer and exponent such that, + // x = ix * 2 ** exp. + mut ix := math::F64Bits(x) + exp := int(ix >> SHIFT & MASK) - BIAS - SHIFT + ix &= FRAC_MASK + ix |= 1 << SHIFT - // m_pi is the binary digits of 1/PI as a u64 array, - // that is, 1/PI = Sum mPI[i]*2^(-64*i). - // 19 64-bit digits give 1216 bits of precision - // to handle the largest possible f64 exponent. - let mPi: [...]u64 = [ - 0x0000000000000000, - 0x517cc1b727220a94, - 0xfe13abe8fa9a6ee0, - 0x6db14acc9e21c820, - 0xff28b1d5ef5de2b0, - 0xdb92371d2126e970, - 0x0324977504e8c90e, - 0x7f0ef58e5894d39f, - 0x74411afa975da242, - 0x74ce38135a2fbf20, - 0x9cc8eb1cc1a99cfa, - 0x4e422fc5defc941d, - 0x8ffc4bffef02cc07, - 0xf79788c5ad05368f, - 0xb69b3f6793e584db, - 0xa7a31fb34f2ff516, - 0xba93dd63f5f2f8bd, - 0x9e839cfbc5294975, - 0x35fdafd88fc6ae84, - 0x2b0198237e3db5d5, - ] - // Use the exponent to extract the 3 appropriate u64 digits from mPi, - // B ~ (z0, z1, z2), such that the product leading digit has the exponent -64. - // Note, exp >= 50 since x >= REDUCE_THRESHOLD and exp < 971 for maximum f64. - digit, bitshift := uint(exp + 64) / 64, uint(exp + 64) % 64 - z0 := (mPi[digit] << bitshift) | (mPi[digit+1] >> (64 - bitshift)) - z1 := (mPi[digit+1] << bitshift) | (mPi[digit+2] >> (64 - bitshift)) - z2 := (mPi[digit+2] << bitshift) | (mPi[digit+3] >> (64 - bitshift)) - // Multiply mantissa by the digits and extract the upper two digits (hi, lo). - z2hi, _ := bits::Mul64(z2, ix) - z1hi, z1lo := bits::Mul64(z1, ix) - z0lo := z0 * ix - lo, c := bits::Add64(z1lo, z2hi, 0) - mut hi, _ := bits::Add64(z0lo, z1hi, c) - // Find the magnitude of the fraction. - lz := uint(bits::LeadingZeros64(hi)) - e := u64(BIAS - (lz + 1)) - // Clear implicit mantissa bit and shift into place. - hi = (hi << (lz + 1)) | (lo >> (64 - (lz + 1))) - hi >>= 64 - SHIFT - // Include the exponent and convert to a float. - hi |= e << SHIFT - x = math::F64FromBits(hi) - // map to (-PI/2, PI/2] - if x > 0.5 { - x-- - } - ret math::Pi * x + // m_pi is the binary digits of 1/PI as a u64 array, + // that is, 1/PI = Sum mPI[i]*2^(-64*i). + // 19 64-bit digits give 1216 bits of precision + // to handle the largest possible f64 exponent. + let mPi: [...]u64 = [ + 0x0000000000000000, + 0x517cc1b727220a94, + 0xfe13abe8fa9a6ee0, + 0x6db14acc9e21c820, + 0xff28b1d5ef5de2b0, + 0xdb92371d2126e970, + 0x0324977504e8c90e, + 0x7f0ef58e5894d39f, + 0x74411afa975da242, + 0x74ce38135a2fbf20, + 0x9cc8eb1cc1a99cfa, + 0x4e422fc5defc941d, + 0x8ffc4bffef02cc07, + 0xf79788c5ad05368f, + 0xb69b3f6793e584db, + 0xa7a31fb34f2ff516, + 0xba93dd63f5f2f8bd, + 0x9e839cfbc5294975, + 0x35fdafd88fc6ae84, + 0x2b0198237e3db5d5, + ] + // Use the exponent to extract the 3 appropriate u64 digits from mPi, + // B ~ (z0, z1, z2), such that the product leading digit has the exponent -64. + // Note, exp >= 50 since x >= REDUCE_THRESHOLD and exp < 971 for maximum f64. + digit, bitshift := uint(exp + 64) / 64, uint(exp + 64) % 64 + z0 := (mPi[digit] << bitshift) | (mPi[digit+1] >> (64 - bitshift)) + z1 := (mPi[digit+1] << bitshift) | (mPi[digit+2] >> (64 - bitshift)) + z2 := (mPi[digit+2] << bitshift) | (mPi[digit+3] >> (64 - bitshift)) + // Multiply mantissa by the digits and extract the upper two digits (hi, lo). + z2hi, _ := bits::Mul64(z2, ix) + z1hi, z1lo := bits::Mul64(z1, ix) + z0lo := z0 * ix + lo, c := bits::Add64(z1lo, z2hi, 0) + mut hi, _ := bits::Add64(z0lo, z1hi, c) + // Find the magnitude of the fraction. + lz := uint(bits::LeadingZeros64(hi)) + e := u64(BIAS - (lz + 1)) + // Clear implicit mantissa bit and shift into place. + hi = (hi << (lz + 1)) | (lo >> (64 - (lz + 1))) + hi >>= 64 - SHIFT + // Include the exponent and convert to a float. + hi |= e << SHIFT + x = math::F64FromBits(hi) + // map to (-PI/2, PI/2] + if x > 0.5 { + x-- + } + ret math::Pi * x } // Taylor series expansion for cosh(2y) - cos(2x) fn tanSeries(z: Cmplx): f64 { - const MACHEP = 1.0 / (1 << 53) + const MACHEP = 1.0 / (1 << 53) - mut x := reducePi(math::Abs(2 * z.Real())) - x = x * x - mut y := math::Abs(2 * z.Imag()) - y = y * y - mut x2 := 1.0 - mut y2 := 1.0 - mut f := 1.0 - mut rn := 0.0 - mut d := 0.0 - for { - rn++ - f *= rn - rn++ - f *= rn - x2 *= x - y2 *= y - mut t := y2 + x2 - t /= f - d += t + mut x := reducePi(math::Abs(2 * z.Real())) + x = x * x + mut y := math::Abs(2 * z.Imag()) + y = y * y + mut x2 := 1.0 + mut y2 := 1.0 + mut f := 1.0 + mut rn := 0.0 + mut d := 0.0 + for { + rn++ + f *= rn + rn++ + f *= rn + x2 *= x + y2 *= y + mut t := y2 + x2 + t /= f + d += t - rn++ - f *= rn - rn++ - f *= rn - x2 *= x - y2 *= y - t = y2 - x2 - t /= f - d += t - if !(math::Abs(t/d) > MACHEP) { - // Caution: Use ! and > instead of <= for correct behavior if t/d is NaN. - // See issue 17577 of Go project. - break - } - } - ret d + rn++ + f *= rn + rn++ + f *= rn + x2 *= x + y2 *= y + t = y2 - x2 + t /= f + d += t + if !(math::Abs(t/d) > MACHEP) { + // Caution: Use ! and > instead of <= for correct behavior if t/d is NaN. + // See issue 17577 of Go project. + break + } + } + ret d } \ No newline at end of file diff --git a/std/math/copysign.jule b/std/math/copysign.jule index f24aedb05..61fcbda0d 100644 --- a/std/math/copysign.jule +++ b/std/math/copysign.jule @@ -37,6 +37,6 @@ // Returns a value with the magnitude of f and the sign of sign. fn Copysign(f: f64, sign: f64): f64 { - const SIGN_BIT = 1 << 63 - ret F64FromBits(F64Bits(f) & ^SIGN_BIT | F64Bits(sign) & SIGN_BIT) + const SIGN_BIT = 1 << 63 + ret F64FromBits(F64Bits(f) & ^SIGN_BIT | F64Bits(sign) & SIGN_BIT) } \ No newline at end of file diff --git a/std/math/dim.jule b/std/math/dim.jule index c88b9ac7a..ceac98285 100644 --- a/std/math/dim.jule +++ b/std/math/dim.jule @@ -42,18 +42,18 @@ // Dim(-Inf, -Inf) = NaN // Dim(x, NaN) = Dim(NaN, x) = NaN fn Dim(x: f64, y: f64): f64 { - // The special cases result in NaN after the subtraction: - // +inf - +inf = NaN - // -inf - -inf = NaN - // NaN - y = NaN - // x - NaN = NaN - v := x - y - if v <= 0 { - // v is negative or 0 - ret 0 - } - // v is positive or NaN - ret v + // The special cases result in NaN after the subtraction: + // +inf - +inf = NaN + // -inf - -inf = NaN + // NaN - y = NaN + // x - NaN = NaN + v := x - y + if v <= 0 { + // v is negative or 0 + ret 0 + } + // v is positive or NaN + ret v } // Returns the larger of x or y. @@ -64,23 +64,23 @@ fn Dim(x: f64, y: f64): f64 { // Max(+0, ±0) = Max(±0, +0) = +0 // Max(-0, -0) = -0 fn Max(x: f64, y: f64): f64 { - // special cases - match { - | IsInf(x, 1) | IsInf(y, 1): - ret Inf(1) - | IsNaN(x) | IsNaN(y): - ret NaN() - | x == 0 && x == y: - if Signbit(x) { - ret y - } - ret x - } + // special cases + match { + | IsInf(x, 1) | IsInf(y, 1): + ret Inf(1) + | IsNaN(x) | IsNaN(y): + ret NaN() + | x == 0 && x == y: + if Signbit(x) { + ret y + } + ret x + } - if x > y { - ret x - } - ret y + if x > y { + ret x + } + ret y } // Returns the smaller of x or y. @@ -90,21 +90,21 @@ fn Max(x: f64, y: f64): f64 { // Min(x, NaN) = Min(NaN, x) = NaN // Min(-0, ±0) = Min(±0, -0) = -0 fn Min(x: f64, y: f64): f64 { - // special cases - match { - | IsInf(x, -1) | IsInf(y, -1): - ret Inf(-1) - | IsNaN(x) | IsNaN(y): - ret NaN() - | x == 0 && x == y: - if Signbit(x) { - ret x - } - ret y - } + // special cases + match { + | IsInf(x, -1) | IsInf(y, -1): + ret Inf(-1) + | IsNaN(x) | IsNaN(y): + ret NaN() + | x == 0 && x == y: + if Signbit(x) { + ret x + } + ret y + } - if x < y { - ret x - } - ret y + if x < y { + ret x + } + ret y } \ No newline at end of file diff --git a/std/math/erf.jule b/std/math/erf.jule index bee342574..a6bb9e090 100644 --- a/std/math/erf.jule +++ b/std/math/erf.jule @@ -219,73 +219,73 @@ const sb7 = -2.24409524465858183362e+01 // 0xC03670E242712D62 // Erf(-Inf) = -1 // Erf(NaN) = NaN fn Erf(mut x: f64): f64 { - const VeryTiny = 2.848094538889218e-306 // 0x0080000000000000 - const Small = 1.0 / (1 << 28) // 2**-28 - // special cases - match { - | IsNaN(x): - ret NaN() - | IsInf(x, 1): - ret 1 - | IsInf(x, -1): - ret -1 - } - mut sign := false - if x < 0 { - x = -x - sign = true - } - if x < 0.84375 { // |x| < 0.84375 - mut temp := 0. - if x < Small { // |x| < 2**-28 - if x < VeryTiny { - temp = 0.125 * (8.0 * x + efx8 * x) // avoid underflow - } else { - temp = x + efx * x - } - } else { - z := x * x - r := pp0 + z * (pp1 + z * (pp2 + z * (pp3 + z * pp4))) - s := 1 + z * (qq1 + z * (qq2 + z * (qq3 + z * (qq4 + z * qq5)))) - y := r / s - temp = x + x * y - } - if sign { - ret -temp - } - ret temp - } - if x < 1.25 { // 0.84375 <= |x| < 1.25 - s := x - 1 - P := pa0 + s * (pa1 + s * (pa2 + s * (pa3 + s * (pa4 + s * (pa5 + s * pa6))))) - Q := 1 + s * (qa1 + s * (qa2 + s * (qa3 + s * (qa4 + s * (qa5 + s * qa6))))) - if sign { - ret -erx - P / Q - } - ret erx + P / Q - } - if x >= 6 { // inf > |x| >= 6 - if sign { - ret -1 - } - ret 1 - } - s := 1 / (x * x) - mut R := 0. - mut S := 0. - if x < 1/0.35 { // |x| < 1 / 0.35 ~ 2.857143 - R = ra0 + s * (ra1 + s * (ra2 + s * (ra3 + s * (ra4 + s * (ra5 + s * (ra6 + s * ra7)))))) - S = 1 + s * (sa1 + s * (sa2 + s * (sa3 + s * (sa4 + s * (sa5 + s * (sa6 + s * (sa7 + s * sa8))))))) - } else { // |x| >= 1 / 0.35 ~ 2.857143 - R = ra0 + s * (rb1 + s * (rb2 + s * (rb3 + s * (rb4 + s * (rb5 + s * rb6))))) - S = 1 + s * (sb1 + s * (sb2 + s * (sb3 + s * (sb4 + s * (sb5 + s * (sb6 + s * sb7)))))) - } - z := F64FromBits(F64Bits(x) & 0xffffffff00000000) // pseudo-single (20-bit) precision x - r := Exp(-z * z - 0.5625) * Exp((z - x) * (z + x) + R / S) - if sign { - ret r / x - 1 - } - ret 1 - r / x + const VeryTiny = 2.848094538889218e-306 // 0x0080000000000000 + const Small = 1.0 / (1 << 28) // 2**-28 + // special cases + match { + | IsNaN(x): + ret NaN() + | IsInf(x, 1): + ret 1 + | IsInf(x, -1): + ret -1 + } + mut sign := false + if x < 0 { + x = -x + sign = true + } + if x < 0.84375 { // |x| < 0.84375 + mut temp := 0. + if x < Small { // |x| < 2**-28 + if x < VeryTiny { + temp = 0.125 * (8.0 * x + efx8 * x) // avoid underflow + } else { + temp = x + efx * x + } + } else { + z := x * x + r := pp0 + z * (pp1 + z * (pp2 + z * (pp3 + z * pp4))) + s := 1 + z * (qq1 + z * (qq2 + z * (qq3 + z * (qq4 + z * qq5)))) + y := r / s + temp = x + x * y + } + if sign { + ret -temp + } + ret temp + } + if x < 1.25 { // 0.84375 <= |x| < 1.25 + s := x - 1 + P := pa0 + s * (pa1 + s * (pa2 + s * (pa3 + s * (pa4 + s * (pa5 + s * pa6))))) + Q := 1 + s * (qa1 + s * (qa2 + s * (qa3 + s * (qa4 + s * (qa5 + s * qa6))))) + if sign { + ret -erx - P / Q + } + ret erx + P / Q + } + if x >= 6 { // inf > |x| >= 6 + if sign { + ret -1 + } + ret 1 + } + s := 1 / (x * x) + mut R := 0. + mut S := 0. + if x < 1/0.35 { // |x| < 1 / 0.35 ~ 2.857143 + R = ra0 + s * (ra1 + s * (ra2 + s * (ra3 + s * (ra4 + s * (ra5 + s * (ra6 + s * ra7)))))) + S = 1 + s * (sa1 + s * (sa2 + s * (sa3 + s * (sa4 + s * (sa5 + s * (sa6 + s * (sa7 + s * sa8))))))) + } else { // |x| >= 1 / 0.35 ~ 2.857143 + R = ra0 + s * (rb1 + s * (rb2 + s * (rb3 + s * (rb4 + s * (rb5 + s * rb6))))) + S = 1 + s * (sb1 + s * (sb2 + s * (sb3 + s * (sb4 + s * (sb5 + s * (sb6 + s * sb7)))))) + } + z := F64FromBits(F64Bits(x) & 0xffffffff00000000) // pseudo-single (20-bit) precision x + r := Exp(-z * z - 0.5625) * Exp((z - x) * (z + x) + R / S) + if sign { + ret r / x - 1 + } + ret 1 - r / x } // Returns the complementary error function of x. @@ -295,73 +295,73 @@ fn Erf(mut x: f64): f64 { // Erfc(-Inf) = 2 // Erfc(NaN) = NaN fn Erfc(mut x: f64): f64 { - const Tiny = 1.0 / (1 << 56) // 2**-56 - // special cases - match { - | IsNaN(x): - ret NaN() - | IsInf(x, 1): - ret 0 - | IsInf(x, -1): - ret 2 - } - mut sign := false - if x < 0 { - x = -x - sign = true - } - if x < 0.84375 { // |x| < 0.84375 - mut temp := 0. - if x < Tiny { // |x| < 2**-56 - temp = x - } else { - z := x * x - r := pp0 + z * (pp1 + z * (pp2 + z * (pp3 + z * pp4))) - s := 1 + z * (qq1 + z * (qq2 + z * (qq3 + z * (qq4 + z * qq5)))) - y := r / s - if x < 0.25 { // |x| < 1/4 - temp = x + x * y - } else { - temp = 0.5 + (x * y + (x - 0.5)) - } - } - if sign { - ret 1 + temp - } - ret 1 - temp - } - if x < 1.25 { // 0.84375 <= |x| < 1.25 - s := x - 1 - P := pa0 + s * (pa1 + s * (pa2 + s * (pa3 + s * (pa4 + s * (pa5 + s * pa6))))) - Q := 1 + s * (qa1 + s * (qa2 + s * (qa3 + s * (qa4 + s * (qa5 + s * qa6))))) - if sign { - ret 1 + erx + Q / P - } - ret 1 - erx - Q / P - } - if x < 28 { // |x| < 28 - s := 1 / (x * x) - mut R := 0. - mut S := 0. - if x < 1/0.35 { // |x| < 1 / 0.35 ~ 2.857143 - R = ra0 + s * (ra1 + s * (ra2 + s * (ra3 + s * (ra4 + s * (ra5 + s * (ra6 + s * ra7)))))) - S = 1 + s * (sa1 + s * (sa2 + s * (sa3 + s * (sa4 + s * (sa5 + s * (sa6 + s * (sa7 + s * sa8))))))) - } else { // |x| >= 1 / 0.35 ~ 2.857143 - if sign && x > 6 { - ret 2 // x < -6 - } - R = rb0 + s * (rb1 + s * (rb2 + s * (rb3 + s * (rb4 + s * (rb5 + s * rb6))))) - S = 1 + s * (sb1 + s * (sb2 + s * (sb3 + s * (sb4 + s * (sb5 + s * (sb6 + s * sb7)))))) - } - z := F64FromBits(F64Bits(x) & 0xffffffff00000000) // pseudo-single (20-bit) precision x - r := Exp(-z * z - 0.5625) * Exp((z - x) * (z + x) + R / S) - if sign { - ret 2 - r / x - } - ret r / x - } - if sign { - ret 2 - } - ret 0 + const Tiny = 1.0 / (1 << 56) // 2**-56 + // special cases + match { + | IsNaN(x): + ret NaN() + | IsInf(x, 1): + ret 0 + | IsInf(x, -1): + ret 2 + } + mut sign := false + if x < 0 { + x = -x + sign = true + } + if x < 0.84375 { // |x| < 0.84375 + mut temp := 0. + if x < Tiny { // |x| < 2**-56 + temp = x + } else { + z := x * x + r := pp0 + z * (pp1 + z * (pp2 + z * (pp3 + z * pp4))) + s := 1 + z * (qq1 + z * (qq2 + z * (qq3 + z * (qq4 + z * qq5)))) + y := r / s + if x < 0.25 { // |x| < 1/4 + temp = x + x * y + } else { + temp = 0.5 + (x * y + (x - 0.5)) + } + } + if sign { + ret 1 + temp + } + ret 1 - temp + } + if x < 1.25 { // 0.84375 <= |x| < 1.25 + s := x - 1 + P := pa0 + s * (pa1 + s * (pa2 + s * (pa3 + s * (pa4 + s * (pa5 + s * pa6))))) + Q := 1 + s * (qa1 + s * (qa2 + s * (qa3 + s * (qa4 + s * (qa5 + s * qa6))))) + if sign { + ret 1 + erx + Q / P + } + ret 1 - erx - Q / P + } + if x < 28 { // |x| < 28 + s := 1 / (x * x) + mut R := 0. + mut S := 0. + if x < 1/0.35 { // |x| < 1 / 0.35 ~ 2.857143 + R = ra0 + s * (ra1 + s * (ra2 + s * (ra3 + s * (ra4 + s * (ra5 + s * (ra6 + s * ra7)))))) + S = 1 + s * (sa1 + s * (sa2 + s * (sa3 + s * (sa4 + s * (sa5 + s * (sa6 + s * (sa7 + s * sa8))))))) + } else { // |x| >= 1 / 0.35 ~ 2.857143 + if sign && x > 6 { + ret 2 // x < -6 + } + R = rb0 + s * (rb1 + s * (rb2 + s * (rb3 + s * (rb4 + s * (rb5 + s * rb6))))) + S = 1 + s * (sb1 + s * (sb2 + s * (sb3 + s * (sb4 + s * (sb5 + s * (sb6 + s * sb7)))))) + } + z := F64FromBits(F64Bits(x) & 0xffffffff00000000) // pseudo-single (20-bit) precision x + r := Exp(-z * z - 0.5625) * Exp((z - x) * (z + x) + R / S) + if sign { + ret 2 - r / x + } + ret r / x + } + if sign { + ret 2 + } + ret 0 } \ No newline at end of file diff --git a/std/math/erfinv.jule b/std/math/erfinv.jule index cd39eb34e..4673485e2 100644 --- a/std/math/erfinv.jule +++ b/std/math/erfinv.jule @@ -105,46 +105,46 @@ const f7 = 2.891024605872965461538222e-15 // Erfinv(x) = NaN if x < -1 or x > 1 // Erfinv(NaN) = NaN fn Erfinv(mut x: f64): f64 { - // special cases - if IsNaN(x) || x <= -1 || x >= 1 { - if x == -1 || x == 1 { - ret Inf(int(x)) - } - ret NaN() - } + // special cases + if IsNaN(x) || x <= -1 || x >= 1 { + if x == -1 || x == 1 { + ret Inf(int(x)) + } + ret NaN() + } - mut sign := false - if x < 0 { - x = -x - sign = true - } + mut sign := false + if x < 0 { + x = -x + sign = true + } - mut ans := 0. - if x <= 0.85 { // |x| <= 0.85 - r := 0.180625 - 0.25 * x * x - z1 := ((((((a7 * r + a6) * r + a5) * r + a4) * r + a3) * r + a2) * r + a1) * r + a0 - z2 := ((((((b7 * r + b6) * r + b5) * r + b4) * r + b3) * r + b2) * r + b1) * r + b0 - ans = (x * z1) / z2 - } else { - mut z1 := 0. - mut z2 := 0. - mut r := Sqrt(Ln2 - Log(1.0 - x)) - if r <= 5.0 { - r -= 1.6 - z1 = ((((((c7 * r + c6) * r + c5) * r + c4) * r + c3) * r + c2) * r + c1) * r + c0 - z2 = ((((((d7 * r + d6) * r + d5) * r + d4) * r + d3) * r + d2) * r + d1) * r + d0 - } else { - r -= 5.0 - z1 = ((((((e7 * r + e6) * r + e5) * r + e4) * r + e3) * r + e2) * r + e1) * r + e0 - z2 = ((((((f7 * r + f6) * r + f5) * r + f4) * r + f3) * r + f2) * r + f1) * r + f0 - } - ans = z1 / z2 - } + mut ans := 0. + if x <= 0.85 { // |x| <= 0.85 + r := 0.180625 - 0.25 * x * x + z1 := ((((((a7 * r + a6) * r + a5) * r + a4) * r + a3) * r + a2) * r + a1) * r + a0 + z2 := ((((((b7 * r + b6) * r + b5) * r + b4) * r + b3) * r + b2) * r + b1) * r + b0 + ans = (x * z1) / z2 + } else { + mut z1 := 0. + mut z2 := 0. + mut r := Sqrt(Ln2 - Log(1.0 - x)) + if r <= 5.0 { + r -= 1.6 + z1 = ((((((c7 * r + c6) * r + c5) * r + c4) * r + c3) * r + c2) * r + c1) * r + c0 + z2 = ((((((d7 * r + d6) * r + d5) * r + d4) * r + d3) * r + d2) * r + d1) * r + d0 + } else { + r -= 5.0 + z1 = ((((((e7 * r + e6) * r + e5) * r + e4) * r + e3) * r + e2) * r + e1) * r + e0 + z2 = ((((((f7 * r + f6) * r + f5) * r + f4) * r + f3) * r + f2) * r + f1) * r + f0 + } + ans = z1 / z2 + } - if sign { - ret -ans - } - ret ans + if sign { + ret -ans + } + ret ans } // Returns the inverse of erfc(x). diff --git a/std/math/exp.jule b/std/math/exp.jule index 8002a87ee..4e04354e9 100644 --- a/std/math/exp.jule +++ b/std/math/exp.jule @@ -120,93 +120,93 @@ // Very large values overflow to 0 or Inf. // Very small values underflow to 1. fn Exp(x: f64): f64 { - const Ln2Hi = 6.93147180369123816490e-01 - const Ln2Lo = 1.90821492927058770002e-10 - const Log2E = 1.44269504088896338700e+00 + const Ln2Hi = 6.93147180369123816490e-01 + const Ln2Lo = 1.90821492927058770002e-10 + const Log2E = 1.44269504088896338700e+00 - const Overflow = 7.09782712893383973096e+02 - const Underflow = -7.45133219101941108420e+02 - const NearZero = 1.0 / (1 << 28) // 2**-28 + const Overflow = 7.09782712893383973096e+02 + const Underflow = -7.45133219101941108420e+02 + const NearZero = 1.0 / (1 << 28) // 2**-28 - // special cases - match { - | IsNaN(x) | IsInf(x, 1): - ret x - | IsInf(x, -1): - ret 0 - | x > Overflow: - ret Inf(1) - | x < Underflow: - ret 0 - | -NearZero < x && x < NearZero: - ret 1 + x - } + // special cases + match { + | IsNaN(x) | IsInf(x, 1): + ret x + | IsInf(x, -1): + ret 0 + | x > Overflow: + ret Inf(1) + | x < Underflow: + ret 0 + | -NearZero < x && x < NearZero: + ret 1 + x + } - // reduce; computed as r = hi - lo for extra precision. - mut k := 0 - match { - | x < 0: - k = int(Log2E * x - 0.5) - | x > 0: - k = int(Log2E * x + 0.5) - } - hi := x - f64(k) * Ln2Hi - lo := f64(k) * Ln2Lo + // reduce; computed as r = hi - lo for extra precision. + mut k := 0 + match { + | x < 0: + k = int(Log2E * x - 0.5) + | x > 0: + k = int(Log2E * x + 0.5) + } + hi := x - f64(k) * Ln2Hi + lo := f64(k) * Ln2Lo - // compute - ret expmulti(hi, lo, k) + // compute + ret expmulti(hi, lo, k) } // Returns 2**x, the base-2 exponential of x. // Special cases are the same as Exp. fn Exp2(x: f64): f64 { - const Ln2Hi = 6.93147180369123816490e-01 - const Ln2Lo = 1.90821492927058770002e-10 + const Ln2Hi = 6.93147180369123816490e-01 + const Ln2Lo = 1.90821492927058770002e-10 - const Overflow = 1.0239999999999999e+03 - const Underflow = -1.0740e+03 + const Overflow = 1.0239999999999999e+03 + const Underflow = -1.0740e+03 - // special cases - match { - | IsNaN(x) | IsInf(x, 1): - ret x - | IsInf(x, -1): - ret 0 - | x > Overflow: - ret Inf(1) - | x < Underflow: - ret 0 - } + // special cases + match { + | IsNaN(x) | IsInf(x, 1): + ret x + | IsInf(x, -1): + ret 0 + | x > Overflow: + ret Inf(1) + | x < Underflow: + ret 0 + } - // argument reduction; x = r×lg(e) + k with |r| ≤ ln(2)/2. - // computed as r = hi - lo for extra precision. - mut k := 0 - match { - | x > 0: - k = int(x + 0.5) - | x < 0: - k = int(x - 0.5) - } - t := x - f64(k) - hi := t * Ln2Hi - lo := -t * Ln2Lo + // argument reduction; x = r×lg(e) + k with |r| ≤ ln(2)/2. + // computed as r = hi - lo for extra precision. + mut k := 0 + match { + | x > 0: + k = int(x + 0.5) + | x < 0: + k = int(x - 0.5) + } + t := x - f64(k) + hi := t * Ln2Hi + lo := -t * Ln2Lo - // compute - ret expmulti(hi, lo, k) + // compute + ret expmulti(hi, lo, k) } // Returns e**r × 2**k where r = hi - lo and |r| ≤ ln(2)/2. fn expmulti(hi: f64, lo: f64, k: int): f64 { - const p1 = 1.66666666666666657415e-01 /* 0x3FC55555; 0x55555555 */ - const p2 = -2.77777777770155933842e-03 /* 0xBF66C16C; 0x16BEBD93 */ - const p3 = 6.61375632143793436117e-05 /* 0x3F11566A; 0xAF25DE2C */ - const p4 = -1.65339022054652515390e-06 /* 0xBEBBBD41; 0xC5D26BF1 */ - const p5 = 4.13813679705723846039e-08 /* 0x3E663769; 0x72BEA4D0 */ + const p1 = 1.66666666666666657415e-01 /* 0x3FC55555; 0x55555555 */ + const p2 = -2.77777777770155933842e-03 /* 0xBF66C16C; 0x16BEBD93 */ + const p3 = 6.61375632143793436117e-05 /* 0x3F11566A; 0xAF25DE2C */ + const p4 = -1.65339022054652515390e-06 /* 0xBEBBBD41; 0xC5D26BF1 */ + const p5 = 4.13813679705723846039e-08 /* 0x3E663769; 0x72BEA4D0 */ - r := hi - lo - t := r * r - c := r - t * (p1 + t * (p2 + t * (p3 + t * (p4 + t * p5)))) - y := 1 - ((lo - (r * c) / (2 - c)) - hi) - // TODO(rsc): make sure ldexp can handle boundary k - ret Ldexp(y, k) + r := hi - lo + t := r * r + c := r - t * (p1 + t * (p2 + t * (p3 + t * (p4 + t * p5)))) + y := 1 - ((lo - (r * c) / (2 - c)) - hi) + // TODO(rsc): make sure ldexp can handle boundary k + ret Ldexp(y, k) } \ No newline at end of file diff --git a/std/math/expm1.jule b/std/math/expm1.jule index dcc577d21..c8506904f 100644 --- a/std/math/expm1.jule +++ b/std/math/expm1.jule @@ -154,113 +154,113 @@ // // Very large values overflow to -1 or +Inf. fn Expm1(mut x: f64): f64 { - const OTHRESHOLD = 7.09782712893383973096e+02 // 0x40862E42FEFA39EF - const LN2_X56 = 3.88162421113569373274e+01 // 0x4043687a9f1af2b1 - const LN2_HALF_X3 = 1.03972077083991796413e+00 // 0x3ff0a2b23f3bab73 - const LN2_HALF = 3.46573590279972654709e-01 // 0x3fd62e42fefa39ef - const LN2_HI = 6.93147180369123816490e-01 // 0x3fe62e42fee00000 - const LN2_LO = 1.90821492927058770002e-10 // 0x3dea39ef35793c76 - const INV_LN2 = 1.44269504088896338700e+00 // 0x3ff71547652b82fe - const TINY = 1.0 / (1 << 54) // 2**-54 = 0x3c90000000000000 - // scaled coefficients related to expm1 - const Q1 = -3.33333333333331316428e-02 // 0xBFA11111111110F4 - const Q2 = 1.58730158725481460165e-03 // 0x3F5A01A019FE5585 - const Q3 = -7.93650757867487942473e-05 // 0xBF14CE199EAADBB7 - const Q4 = 4.00821782732936239552e-06 // 0x3ED0CFCA86E65239 - const Q5 = -2.01099218183624371326e-07 // 0xBE8AFDB76E09C32D + const OTHRESHOLD = 7.09782712893383973096e+02 // 0x40862E42FEFA39EF + const LN2_X56 = 3.88162421113569373274e+01 // 0x4043687a9f1af2b1 + const LN2_HALF_X3 = 1.03972077083991796413e+00 // 0x3ff0a2b23f3bab73 + const LN2_HALF = 3.46573590279972654709e-01 // 0x3fd62e42fefa39ef + const LN2_HI = 6.93147180369123816490e-01 // 0x3fe62e42fee00000 + const LN2_LO = 1.90821492927058770002e-10 // 0x3dea39ef35793c76 + const INV_LN2 = 1.44269504088896338700e+00 // 0x3ff71547652b82fe + const TINY = 1.0 / (1 << 54) // 2**-54 = 0x3c90000000000000 + // scaled coefficients related to expm1 + const Q1 = -3.33333333333331316428e-02 // 0xBFA11111111110F4 + const Q2 = 1.58730158725481460165e-03 // 0x3F5A01A019FE5585 + const Q3 = -7.93650757867487942473e-05 // 0xBF14CE199EAADBB7 + const Q4 = 4.00821782732936239552e-06 // 0x3ED0CFCA86E65239 + const Q5 = -2.01099218183624371326e-07 // 0xBE8AFDB76E09C32D - // special cases - match { - | IsInf(x, 1) | IsNaN(x): - ret x - | IsInf(x, -1): - ret -1 - } + // special cases + match { + | IsInf(x, 1) | IsNaN(x): + ret x + | IsInf(x, -1): + ret -1 + } - mut absx := x - mut sign := false - if x < 0 { - absx = -absx - sign = true - } + mut absx := x + mut sign := false + if x < 0 { + absx = -absx + sign = true + } - // filter out huge argument - if absx >= LN2_X56 { // if |x| >= 56 * ln2 - if sign { - ret -1 // x < -56*ln2, return -1 - } - if absx >= OTHRESHOLD { // if |x| >= 709.78... - ret Inf(1) - } - } + // filter out huge argument + if absx >= LN2_X56 { // if |x| >= 56 * ln2 + if sign { + ret -1 // x < -56*ln2, return -1 + } + if absx >= OTHRESHOLD { // if |x| >= 709.78... + ret Inf(1) + } + } - // argument reduction - mut c := 0. - mut k := 0 - if absx > LN2_HALF { // if |x| > 0.5 * ln2 - mut hi := 0. - mut lo := 0. - if absx < LN2_HALF_X3 { // and |x| < 1.5 * ln2 - if !sign { - hi = x - LN2_HI - lo = LN2_LO - k = 1 - } else { - hi = x + LN2_HI - lo = -LN2_LO - k = -1 - } - } else { - if !sign { - k = int(INV_LN2 * x + 0.5) - } else { - k = int(INV_LN2 * x - 0.5) - } - t := f64(k) - hi = x - t * LN2_HI // t * LN2_HI is exact here - lo = t * LN2_LO - } - x = hi - lo - c = (hi - x) - lo - } else if absx < TINY { // when |x| < 2**-54, return x - ret x - } else { - k = 0 - } + // argument reduction + mut c := 0. + mut k := 0 + if absx > LN2_HALF { // if |x| > 0.5 * ln2 + mut hi := 0. + mut lo := 0. + if absx < LN2_HALF_X3 { // and |x| < 1.5 * ln2 + if !sign { + hi = x - LN2_HI + lo = LN2_LO + k = 1 + } else { + hi = x + LN2_HI + lo = -LN2_LO + k = -1 + } + } else { + if !sign { + k = int(INV_LN2 * x + 0.5) + } else { + k = int(INV_LN2 * x - 0.5) + } + t := f64(k) + hi = x - t * LN2_HI // t * LN2_HI is exact here + lo = t * LN2_LO + } + x = hi - lo + c = (hi - x) - lo + } else if absx < TINY { // when |x| < 2**-54, return x + ret x + } else { + k = 0 + } - // x is now in primary range - hfx := 0.5 * x - hxs := x * hfx - r1 := 1 + hxs * (Q1 + hxs * (Q2 + hxs * (Q3 + hxs * (Q4 + hxs * Q5)))) - mut t := 3 - r1 * hfx - mut e := hxs * ((r1 - t) / (6.0 - x * t)) - if k == 0 { - ret x - (x * e - hxs) // c is 0 - } - e = (x * (e - c) - c) - e -= hxs - match { - | k == -1: - ret 0.5 * (x - e) - 0.5 - | k == 1: - if x < -0.25 { - ret -2 * (e - (x + 0.5)) - } - ret 1 + 2 * (x - e) - | k <= -2 | k > 56: // suffice to return exp(x)-1 - mut y := 1 - (e - x) - y = F64FromBits(F64Bits(y) + u64(k) << 52) // add k to y's exponent - ret y - 1 - } - if k < 20 { - t = F64FromBits(u64(0x3ff0000000000000 - (0x20000000000000 >> uint(k)))) // t=1-2**-k - mut y := t - (e - x) - y = F64FromBits(F64Bits(y) + u64(k) << 52) // add k to y's exponent - ret y - } - t = F64FromBits(u64(0x3ff - k) << 52) // 2**-k - mut y := x - (e + t) - y++ - y = F64FromBits(F64Bits(y) + u64(k) << 52) // add k to y's exponent - ret y + // x is now in primary range + hfx := 0.5 * x + hxs := x * hfx + r1 := 1 + hxs * (Q1 + hxs * (Q2 + hxs * (Q3 + hxs * (Q4 + hxs * Q5)))) + mut t := 3 - r1 * hfx + mut e := hxs * ((r1 - t) / (6.0 - x * t)) + if k == 0 { + ret x - (x * e - hxs) // c is 0 + } + e = (x * (e - c) - c) + e -= hxs + match { + | k == -1: + ret 0.5 * (x - e) - 0.5 + | k == 1: + if x < -0.25 { + ret -2 * (e - (x + 0.5)) + } + ret 1 + 2 * (x - e) + | k <= -2 | k > 56: // suffice to return exp(x)-1 + mut y := 1 - (e - x) + y = F64FromBits(F64Bits(y) + u64(k) << 52) // add k to y's exponent + ret y - 1 + } + if k < 20 { + t = F64FromBits(u64(0x3ff0000000000000 - (0x20000000000000 >> uint(k)))) // t=1-2**-k + mut y := t - (e - x) + y = F64FromBits(F64Bits(y) + u64(k) << 52) // add k to y's exponent + ret y + } + t = F64FromBits(u64(0x3ff - k) << 52) // 2**-k + mut y := x - (e + t) + y++ + y = F64FromBits(F64Bits(y) + u64(k) << 52) // add k to y's exponent + ret y } \ No newline at end of file diff --git a/std/math/floor.jule b/std/math/floor.jule index e588b9424..74516d9d6 100644 --- a/std/math/floor.jule +++ b/std/math/floor.jule @@ -42,18 +42,18 @@ // Floor(±Inf) = ±Inf // Floor(NaN) = NaN fn Floor(x: f64): f64 { - if x == 0 || IsNaN(x) || IsInf(x, 0) { - ret x - } - if x < 0 { - mut d, fract := Modf(-x) - if fract != 0.0 { - d = d + 1 - } - ret -d - } - d, _ := Modf(x) - ret d + if x == 0 || IsNaN(x) || IsInf(x, 0) { + ret x + } + if x < 0 { + mut d, fract := Modf(-x) + if fract != 0.0 { + d = d + 1 + } + ret -d + } + d, _ := Modf(x) + ret d } // Returns the least integer value greater than or equal to x. @@ -71,11 +71,11 @@ fn Ceil(x: f64): f64 { ret -Floor(-x) } // Trunc(±Inf) = ±Inf // Trunc(NaN) = NaN fn Trunc(x: f64): f64 { - if x == 0 || IsNaN(x) || IsInf(x, 0) { - ret x - } - d, _ := Modf(x) - ret d + if x == 0 || IsNaN(x) || IsInf(x, 0) { + ret x + } + d, _ := Modf(x) + ret d } // Returns the nearest integer, rounding half away from zero. @@ -85,34 +85,34 @@ fn Trunc(x: f64): f64 { // Round(±Inf) = ±Inf // Round(NaN) = NaN fn Round(x: f64): f64 { - // round is a faster implementation of: - // - // round(x f64) f64 { - // t: = trunc(x) - // if abs(x-t) >= 0.5 { - // ret t + copysign(1, x) - // } - // ret t - // } - mut bits := F64Bits(x) - mut e := uint(bits >> shift) & mask - if e < bias { - // Round abs(x) < 1 including denormals. - bits &= signMask // +-0 - if e == bias-1 { - bits |= uvone // +-1 - } - } else if e < bias+shift { - // Round any abs(x) >= 1 containing a fractional component [0,1). - // - // Numbers with larger exponents are returned unchanged since they - // must be either an integer, infinity, or NaN. - const HALF = 1 << (shift - 1) - e -= bias - bits += HALF >> e - bits &= ^(fracMask >> e) - } - ret F64FromBits(bits) + // round is a faster implementation of: + // + // round(x f64) f64 { + // t: = trunc(x) + // if abs(x-t) >= 0.5 { + // ret t + copysign(1, x) + // } + // ret t + // } + mut bits := F64Bits(x) + mut e := uint(bits >> shift) & mask + if e < bias { + // Round abs(x) < 1 including denormals. + bits &= signMask // +-0 + if e == bias-1 { + bits |= uvone // +-1 + } + } else if e < bias+shift { + // Round any abs(x) >= 1 containing a fractional component [0,1). + // + // Numbers with larger exponents are returned unchanged since they + // must be either an integer, infinity, or NaN. + const HALF = 1 << (shift - 1) + e -= bias + bits += HALF >> e + bits &= ^(fracMask >> e) + } + ret F64FromBits(bits) } // Returns the nearest integer, rounding ties to even. @@ -122,34 +122,34 @@ fn Round(x: f64): f64 { // RoundEven(±Inf) = ±Inf // RoundEven(NaN) = NaN fn RoundEven(x: f64): f64 { - // round_even is a faster implementation of: - // - // round_even(x f64) f64 { - // t: = trunc(x) - // odd: = remainder(t, 2) != 0 - // d: = abs(x - t) - // if d > 0.5 || (d == 0.5 && odd) { - // ret t + copysign(1, x) - // } - // ret t - // } - mut bits := F64Bits(x) - mut e := uint(bits >> shift) & mask - if e >= bias { - // Round abs(x) >= 1. - // - Large numbers without fractional components, infinity, and NaN are unchanged. - // - Add 0.499.. or 0.5 before truncating depending on whether the truncated - // number is even or odd (respectively). - const halfMinusUlp = (1 << (shift - 1)) - 1 - e -= bias - bits += (halfMinusUlp + (bits >> (shift - e)) & 1) >> e - bits &= ^(fracMask >> e) - } else if e == bias-1 && bits&fracMask != 0 { - // Round 0.5 < abs(x) < 1. - bits = bits & signMask | uvone // +-1 - } else { - // Round abs(x) <= 0.5 including denormals. - bits &= signMask // +-0 - } - ret F64FromBits(bits) + // round_even is a faster implementation of: + // + // round_even(x f64) f64 { + // t: = trunc(x) + // odd: = remainder(t, 2) != 0 + // d: = abs(x - t) + // if d > 0.5 || (d == 0.5 && odd) { + // ret t + copysign(1, x) + // } + // ret t + // } + mut bits := F64Bits(x) + mut e := uint(bits >> shift) & mask + if e >= bias { + // Round abs(x) >= 1. + // - Large numbers without fractional components, infinity, and NaN are unchanged. + // - Add 0.499.. or 0.5 before truncating depending on whether the truncated + // number is even or odd (respectively). + const halfMinusUlp = (1 << (shift - 1)) - 1 + e -= bias + bits += (halfMinusUlp + (bits >> (shift - e)) & 1) >> e + bits &= ^(fracMask >> e) + } else if e == bias-1 && bits&fracMask != 0 { + // Round 0.5 < abs(x) < 1. + bits = bits & signMask | uvone // +-1 + } else { + // Round abs(x) <= 0.5 including denormals. + bits &= signMask // +-0 + } + ret F64FromBits(bits) } \ No newline at end of file diff --git a/std/math/fma.jule b/std/math/fma.jule index 81c1cf4d7..80cb67dc0 100644 --- a/std/math/fma.jule +++ b/std/math/fma.jule @@ -38,38 +38,38 @@ use bits for std::math::bits fn zero(x: u64): u64 { - if x == 0 { - ret 1 - } - ret 0 - // branchless: - // ret ((x>>1 | x&1) - 1) >> 63 + if x == 0 { + ret 1 + } + ret 0 + // branchless: + // ret ((x>>1 | x&1) - 1) >> 63 } fn nonzero(x: u64): u64 { - if x != 0 { - ret 1 - } - ret 0 - // branchless: - // ret 1 - ((x>>1|x&1)-1)>>63 + if x != 0 { + ret 1 + } + ret 0 + // branchless: + // ret 1 - ((x>>1|x&1)-1)>>63 } fn shl(u1: u64, u2: u64, n: uint): (r1: u64, r2: u64) { - r1 = u1 << n | u2 >> (64 - n) | u2 << (n - 64) - r2 = u2 << n - ret + r1 = u1 << n | u2 >> (64 - n) | u2 << (n - 64) + r2 = u2 << n + ret } fn shr(u1: u64, u2: u64, n: uint): (r1: u64, r2: u64) { - r2 = u2 >> n | u1 << (64 - n) - // Avoid overflow value of: u1>>(n-64) - shift := n - 64 - if shift < 64 { - r2 |= u1 >> shift - } - r1 = u1 >> n - ret + r2 = u2 >> n | u1 << (64 - n) + // Avoid overflow value of: u1>>(n-64) + shift := n - 64 + if shift < 64 { + r2 |= u1 >> shift + } + r1 = u1 >> n + ret } // Compresses the bottom n+1 bits of the two-word @@ -77,126 +77,126 @@ fn shr(u1: u64, u2: u64, n: uint): (r1: u64, r2: u64) { // shifted to the right by n, except the result's 0th bit is // set to the bitwise OR of the bottom n+1 bits. fn shrcompress(u1: u64, u2: u64, n: uint): (r1: u64, r2: u64) { - match { - | n == 0: - ret u1, u2 - | n == 64: - ret 0, u1 | nonzero(u2) - | n >= 128: - ret 0, nonzero(u1 | u2) - | n < 64: - r1, r2 = shr(u1, u2, n) - r2 |= nonzero(u2 & (1 << n - 1)) - | n < 128: - r1, r2 = shr(u1, u2, n) - r2 |= nonzero(u1 & (1 << (n - 64) - 1) | u2) - } - ret + match { + | n == 0: + ret u1, u2 + | n == 64: + ret 0, u1 | nonzero(u2) + | n >= 128: + ret 0, nonzero(u1 | u2) + | n < 64: + r1, r2 = shr(u1, u2, n) + r2 |= nonzero(u2 & (1 << n - 1)) + | n < 128: + r1, r2 = shr(u1, u2, n) + r2 |= nonzero(u1 & (1 << (n - 64) - 1) | u2) + } + ret } fn lz(u1: u64, u2: u64): (l: i32) { - l = i32(bits::LeadingZeros64(u1)) - if l == 64 { - l += i32(bits::LeadingZeros64(u2)) - } - ret l + l = i32(bits::LeadingZeros64(u1)) + if l == 64 { + l += i32(bits::LeadingZeros64(u2)) + } + ret l } // Splits b into sign, biased exponent, and mantissa. // It adds the implicit 1 bit to the mantissa for normal values, // and normalizes subnormal values. fn split(b: u64): (sign: u32, exp: i32, mantissa: u64) { - sign = u32(b >> 63) - exp = i32(b >> 52) & mask - mantissa = b & fracMask - - if exp == 0 { - // Normalize value if subnormal. - shift := uint(bits::LeadingZeros64(mantissa) - 11) - mantissa <<= shift - exp = 1 - i32(shift) - } else { - // Add implicit 1 bit - mantissa |= 1 << 52 - } - ret + sign = u32(b >> 63) + exp = i32(b >> 52) & mask + mantissa = b & fracMask + + if exp == 0 { + // Normalize value if subnormal. + shift := uint(bits::LeadingZeros64(mantissa) - 11) + mantissa <<= shift + exp = 1 - i32(shift) + } else { + // Add implicit 1 bit + mantissa |= 1 << 52 + } + ret } // Returns x * y + z, computed with only one rounding. // (That is, FMA returns the fused multiply-add of x, y, and z.) fn FMA(x: f64, y: f64, z: f64): f64 { - bx, by, bz := F64Bits(x), F64Bits(y), F64Bits(z) - - // inf or NaN or zero involved. At most one rounding will occur. - if x == 0.0 || y == 0.0 || z == 0.0 || bx&uvinf == uvinf || by&uvinf == uvinf { - ret x * y + z - } - // Handle non-finite z separately. Evaluating x*y+z where - // x and y are finite, but z is infinite, should always result in z. - if bz&uvinf == uvinf { - ret z - } - - // Inputs are (sub)normal. - // Split x, y, z into sign, exponent, mantissa. - xs, xe, xm := split(bx) - ys, ye, ym := split(by) - mut zs, mut ze, zm := split(bz) - - // Compute product p = x*y as sign, exponent, two-word mantissa. - // Start with exponent. "is normal" bit isn't subtracted yet. - mut pe := xe + ye - bias + 1 - - // pm1:pm2 is the double-word mantissa for the product p. - // Shift left to leave top bit in product. Effectively - // shifts the 106-bit product to the left by 21. - mut pm1, mut pm2 := bits::Mul64(xm << 10, ym << 11) - mut zm1, mut zm2 := zm << 10, u64(0) - mut ps := xs ^ ys // product sign - - // normalize to 62nd bit - is62zero := uint((^pm1 >> 62) & 1) - pm1, pm2 = shl(pm1, pm2, is62zero) - pe -= i32(is62zero) - - // Swap addition operands so |p| >= |z| - if pe < ze || pe == ze && pm1 < zm1 { - ps, pe, pm1, pm2, zs, ze, zm1, zm2 = zs, ze, zm1, zm2, ps, i32(pe), pm1, pm2 - } - - // Align significands - zm1, zm2 = shrcompress(zm1, zm2, uint(pe - ze)) - - // Compute resulting significands, normalizing if necessary. - mut m := u64(0) - mut c := u64(0) - if ps == zs { - // Adding (pm1:pm2) + (zm1:zm2) - pm2, c = bits::Add64(pm2, zm2, 0) - pm1, _ = bits::Add64(pm1, zm1, c) - pe -= i32(^pm1 >> 63) - pm1, m = shrcompress(pm1, pm2, uint(64 + pm1 >> 63)) - } else { - // Subtracting (pm1:pm2) - (zm1:zm2) - pm2, c = bits::Sub64(pm2, zm2, 0) - pm1, _ = bits::Sub64(pm1, zm1, c) - nz := lz(pm1, pm2) - pe -= nz - m, pm2 = shl(pm1, pm2, uint(nz - 1)) - m |= nonzero(pm2) - } - - // Round and break ties to even - if pe > 1022+bias || pe == 1022+bias && (m+1<<9)>>63 == 1 { - // rounded value overflows exponent range - ret F64FromBits(u64(ps) << 63 | uvinf) - } - if pe < 0 { - n := uint(-pe) - m = m >> n | nonzero(m & (1 << n - 1)) - pe = 0 - } - m = ((m + 1 << 9) >> 10) & ^zero((m & (1 << 10 - 1)) ^ 1 << 9) - pe &= -i32(nonzero(m)) - ret F64FromBits(u64(ps) << 63 + u64(pe) << 52 + m) + bx, by, bz := F64Bits(x), F64Bits(y), F64Bits(z) + + // inf or NaN or zero involved. At most one rounding will occur. + if x == 0.0 || y == 0.0 || z == 0.0 || bx&uvinf == uvinf || by&uvinf == uvinf { + ret x * y + z + } + // Handle non-finite z separately. Evaluating x*y+z where + // x and y are finite, but z is infinite, should always result in z. + if bz&uvinf == uvinf { + ret z + } + + // Inputs are (sub)normal. + // Split x, y, z into sign, exponent, mantissa. + xs, xe, xm := split(bx) + ys, ye, ym := split(by) + mut zs, mut ze, zm := split(bz) + + // Compute product p = x*y as sign, exponent, two-word mantissa. + // Start with exponent. "is normal" bit isn't subtracted yet. + mut pe := xe + ye - bias + 1 + + // pm1:pm2 is the double-word mantissa for the product p. + // Shift left to leave top bit in product. Effectively + // shifts the 106-bit product to the left by 21. + mut pm1, mut pm2 := bits::Mul64(xm << 10, ym << 11) + mut zm1, mut zm2 := zm << 10, u64(0) + mut ps := xs ^ ys // product sign + + // normalize to 62nd bit + is62zero := uint((^pm1 >> 62) & 1) + pm1, pm2 = shl(pm1, pm2, is62zero) + pe -= i32(is62zero) + + // Swap addition operands so |p| >= |z| + if pe < ze || pe == ze && pm1 < zm1 { + ps, pe, pm1, pm2, zs, ze, zm1, zm2 = zs, ze, zm1, zm2, ps, i32(pe), pm1, pm2 + } + + // Align significands + zm1, zm2 = shrcompress(zm1, zm2, uint(pe - ze)) + + // Compute resulting significands, normalizing if necessary. + mut m := u64(0) + mut c := u64(0) + if ps == zs { + // Adding (pm1:pm2) + (zm1:zm2) + pm2, c = bits::Add64(pm2, zm2, 0) + pm1, _ = bits::Add64(pm1, zm1, c) + pe -= i32(^pm1 >> 63) + pm1, m = shrcompress(pm1, pm2, uint(64 + pm1 >> 63)) + } else { + // Subtracting (pm1:pm2) - (zm1:zm2) + pm2, c = bits::Sub64(pm2, zm2, 0) + pm1, _ = bits::Sub64(pm1, zm1, c) + nz := lz(pm1, pm2) + pe -= nz + m, pm2 = shl(pm1, pm2, uint(nz - 1)) + m |= nonzero(pm2) + } + + // Round and break ties to even + if pe > 1022+bias || pe == 1022+bias && (m+1<<9)>>63 == 1 { + // rounded value overflows exponent range + ret F64FromBits(u64(ps) << 63 | uvinf) + } + if pe < 0 { + n := uint(-pe) + m = m >> n | nonzero(m & (1 << n - 1)) + pe = 0 + } + m = ((m + 1 << 9) >> 10) & ^zero((m & (1 << 10 - 1)) ^ 1 << 9) + pe &= -i32(nonzero(m)) + ret F64FromBits(u64(ps) << 63 + u64(pe) << 52 + m) } \ No newline at end of file diff --git a/std/math/frexp.jule b/std/math/frexp.jule index 5c446f90a..1ab03b8dc 100644 --- a/std/math/frexp.jule +++ b/std/math/frexp.jule @@ -45,18 +45,18 @@ // Frexp(±Inf) = ±Inf, 0 // Frexp(NaN) = NaN, 0 fn Frexp(mut f: f64): (frac: f64, exp: int) { - // special cases - match { - | f == 0: - ret f, 0 // correctly return -0 - | IsInf(f, 0) | IsNaN(f): - ret f, 0 - } - f, exp = normalize(f) - mut x := F64Bits(f) - exp += int((x >> shift) & mask) - bias + 1 - x = x & ^(mask << shift) - x |= (-1 + bias) << shift - frac = F64FromBits(x) - ret + // special cases + match { + | f == 0: + ret f, 0 // correctly return -0 + | IsInf(f, 0) | IsNaN(f): + ret f, 0 + } + f, exp = normalize(f) + mut x := F64Bits(f) + exp += int((x >> shift) & mask) - bias + 1 + x = x & ^(mask << shift) + x |= (-1 + bias) << shift + frac = F64FromBits(x) + ret } \ No newline at end of file diff --git a/std/math/gamma.jule b/std/math/gamma.jule index 9ce6f2c87..b73d21cf8 100644 --- a/std/math/gamma.jule +++ b/std/math/gamma.jule @@ -95,30 +95,30 @@ // moshier@na-net.ornl.gov static gamp: [...]f64 = [ - 1.60119522476751861407e-04, - 1.19135147006586384913e-03, - 1.04213797561761569935e-02, - 4.76367800457137231464e-02, - 2.07448227648435975150e-01, - 4.94214826801497100753e-01, - 9.99999999999999996796e-01, + 1.60119522476751861407e-04, + 1.19135147006586384913e-03, + 1.04213797561761569935e-02, + 4.76367800457137231464e-02, + 2.07448227648435975150e-01, + 4.94214826801497100753e-01, + 9.99999999999999996796e-01, ] static gamq: [...]f64 = [ - -2.31581873324120129819e-05, - 5.39605580493303397842e-04, - -4.45641913851797240494e-03, - 1.18139785222060435552e-02, - 3.58236398605498653373e-02, - -2.34591795718243348568e-01, - 7.14304917030273074085e-02, - 1.00000000000000000320e+00, + -2.31581873324120129819e-05, + 5.39605580493303397842e-04, + -4.45641913851797240494e-03, + 1.18139785222060435552e-02, + 3.58236398605498653373e-02, + -2.34591795718243348568e-01, + 7.14304917030273074085e-02, + 1.00000000000000000320e+00, ] static gams: [...]f64 = [ - 7.87311395793093628397e-04, - -2.29549961613378126380e-04, - -2.68132617805781232825e-03, - 3.47222221605458667310e-03, - 8.33333333333482257126e-02, + 7.87311395793093628397e-04, + -2.29549961613378126380e-04, + -2.68132617805781232825e-03, + 3.47222221605458667310e-03, + 8.33333333333482257126e-02, ] // Gamma function computed by Stirling's formula. @@ -129,22 +129,22 @@ static gams: [...]f64 = [ // in reciprocal and produce denormalized floats. The lower precision there // masks any imprecision in the polynomial. fn stirling(x: f64): (f64, f64) { - if x > 200 { - ret Inf(1), 1 - } - const SqrtTwoPi = 2.506628274631000502417 - const MaxStirling = 143.01608 - mut w := 1 / x - w = 1 + w * ((((gams[0] * w + gams[1]) * w + gams[2]) * w + gams[3]) * w + gams[4]) - mut y1 := Exp(x) - mut y2 := 1.0 - if x > MaxStirling { // avoid Pow() overflow - v := Pow(x, 0.5 * x - 0.25) - y1, y2 = v, v / y1 - } else { - y1 = Pow(x, x - 0.5) / y1 - } - ret y1, SqrtTwoPi * w * y2 + if x > 200 { + ret Inf(1), 1 + } + const SqrtTwoPi = 2.506628274631000502417 + const MaxStirling = 143.01608 + mut w := 1 / x + w = 1 + w * ((((gams[0] * w + gams[1]) * w + gams[2]) * w + gams[3]) * w + gams[4]) + mut y1 := Exp(x) + mut y2 := 1.0 + if x > MaxStirling { // avoid Pow() overflow + v := Pow(x, 0.5 * x - 0.25) + y1, y2 = v, v / y1 + } else { + y1 = Pow(x, x - 0.5) / y1 + } + ret y1, SqrtTwoPi * w * y2 } // Returns the Gamma function of x. @@ -157,95 +157,95 @@ fn stirling(x: f64): (f64, f64) { // Gamma(-Inf) = NaN // Gamma(NaN) = NaN fn Gamma(mut x: f64): f64 { - const euler = 0.57721566490153286060651209008240243104215933593992 // A001620 - // special cases - match { - | isNegInt(x) | IsInf(x, -1) | IsNaN(x): - ret NaN() - | IsInf(x, 1): - ret Inf(1) - | x == 0: - if Signbit(x) { - ret Inf(-1) - } - ret Inf(1) - } - mut q := Abs(x) - mut p := Floor(q) - if q > 33 { - if x >= 0 { - y1, y2 := stirling(x) - ret y1 * y2 - } - // Note: x is negative but (checked above) not a negative integer, - // so x must be small enough to be in range for conversion to int64. - // If |x| were >= 2⁶³ it would have to be an integer. - mut signgam := 1 - ip := i64(p) - if ip&1 == 0 { - signgam = -1 - } - mut z := q - p - if z > 0.5 { - p = p + 1 - z = q - p - } - z = q * Sin(Pi * z) - if z == 0 { - ret Inf(signgam) - } - sq1, sq2 := stirling(q) - absz := Abs(z) - d := absz * sq1 * sq2 - if IsInf(d, 0) { - z = Pi / absz / sq1 / sq2 - } else { - z = Pi / d - } - ret f64(signgam) * z - } + const euler = 0.57721566490153286060651209008240243104215933593992 // A001620 + // special cases + match { + | isNegInt(x) | IsInf(x, -1) | IsNaN(x): + ret NaN() + | IsInf(x, 1): + ret Inf(1) + | x == 0: + if Signbit(x) { + ret Inf(-1) + } + ret Inf(1) + } + mut q := Abs(x) + mut p := Floor(q) + if q > 33 { + if x >= 0 { + y1, y2 := stirling(x) + ret y1 * y2 + } + // Note: x is negative but (checked above) not a negative integer, + // so x must be small enough to be in range for conversion to int64. + // If |x| were >= 2⁶³ it would have to be an integer. + mut signgam := 1 + ip := i64(p) + if ip&1 == 0 { + signgam = -1 + } + mut z := q - p + if z > 0.5 { + p = p + 1 + z = q - p + } + z = q * Sin(Pi * z) + if z == 0 { + ret Inf(signgam) + } + sq1, sq2 := stirling(q) + absz := Abs(z) + d := absz * sq1 * sq2 + if IsInf(d, 0) { + z = Pi / absz / sq1 / sq2 + } else { + z = Pi / d + } + ret f64(signgam) * z + } - // Reduce argument - mut z := 1.0 - for x >= 3 { - x = x - 1 - z = z * x - } - for x < 0 { - if x > -1e-09 { - goto small - } - z = z / x - x = x + 1 - } - for x < 2 { - if x < 1e-09 { - goto small - } - z = z / x - x = x + 1 - } + // Reduce argument + mut z := 1.0 + for x >= 3 { + x = x - 1 + z = z * x + } + for x < 0 { + if x > -1e-09 { + goto small + } + z = z / x + x = x + 1 + } + for x < 2 { + if x < 1e-09 { + goto small + } + z = z / x + x = x + 1 + } - if x == 2 { - ret z - } + if x == 2 { + ret z + } - x = x - 2 - p = (((((x * gamp[0] + gamp[1]) * x + gamp[2]) * x + gamp[3]) * x + gamp[4]) * x + gamp[5]) * x + gamp[6] - q = ((((((x * gamq[0] + gamq[1]) * x + gamq[2]) * x + gamq[3]) * x + gamq[4]) * x + gamq[5]) * x + gamq[6]) * x + gamq[7] - ret z * p / q + x = x - 2 + p = (((((x * gamp[0] + gamp[1]) * x + gamp[2]) * x + gamp[3]) * x + gamp[4]) * x + gamp[5]) * x + gamp[6] + q = ((((((x * gamq[0] + gamq[1]) * x + gamq[2]) * x + gamq[3]) * x + gamq[4]) * x + gamq[5]) * x + gamq[6]) * x + gamq[7] + ret z * p / q small: - if x == 0 { - ret Inf(1) - } - ret z / ((1 + euler * x) * x) + if x == 0 { + ret Inf(1) + } + ret z / ((1 + euler * x) * x) } fn isNegInt(x: f64): bool { - if x < 0 { - _, xf := Modf(x) - ret xf == 0 - } - ret false + if x < 0 { + _, xf := Modf(x) + ret xf == 0 + } + ret false } \ No newline at end of file diff --git a/std/math/hypot.jule b/std/math/hypot.jule index 50cbbefea..a91df26e3 100644 --- a/std/math/hypot.jule +++ b/std/math/hypot.jule @@ -48,20 +48,20 @@ // Hypot(NaN, q) = NaN // Hypot(p, NaN) = NaN fn Hypot(mut p: f64, mut q: f64): f64 { - // special cases - match { - | IsInf(p, 0) | IsInf(q, 0): - ret Inf(1) - | IsNaN(p) | IsNaN(q): - ret NaN() - } - p, q = Abs(p), Abs(q) - if p < q { - p, q = q, p - } - if p == 0 { - ret 0 - } - q = q / p - ret p * Sqrt(1 + q * q) + // special cases + match { + | IsInf(p, 0) | IsInf(q, 0): + ret Inf(1) + | IsNaN(p) | IsNaN(q): + ret NaN() + } + p, q = Abs(p), Abs(q) + if p < q { + p, q = q, p + } + if p == 0 { + ret 0 + } + q = q / p + ret p * Sqrt(1 + q * q) } \ No newline at end of file diff --git a/std/math/j0.jule b/std/math/j0.jule index 14ed9013a..b33da7013 100644 --- a/std/math/j0.jule +++ b/std/math/j0.jule @@ -105,71 +105,71 @@ // J0(0) = 1 // J0(NaN) = NaN fn J0(mut x: f64): f64 { - const TWO_M27 = 1.0 / (1 << 27) // 2**-27 0x3e40000000000000 - const TWO_M13 = 1.0 / (1 << 13) // 2**-13 0x3f20000000000000 - const TWO129 = 0x4800000000000000 // 1 << 129 // 2**129 0x4800000000000000 - // R0/S0 on [0, 2] - const R02 = 1.56249999999999947958e-02 // 0x3F8FFFFFFFFFFFFD - const R03 = -1.89979294238854721751e-04 // 0xBF28E6A5B61AC6E9 - const R04 = 1.82954049532700665670e-06 // 0x3EBEB1D10C503919 - const R05 = -4.61832688532103189199e-09 // 0xBE33D5E773D63FCE - const S01 = 1.56191029464890010492e-02 // 0x3F8FFCE882C8C2A4 - const S02 = 1.16926784663337450260e-04 // 0x3F1EA6D2DD57DBF4 - const S03 = 5.13546550207318111446e-07 // 0x3EA13B54CE84D5A9 - const S04 = 1.16614003333790000205e-09 // 0x3E1408BCF4745D8F - // special cases - match { - | IsNaN(x): - ret x - | IsInf(x, 0): - ret 0 - | x == 0: - ret 1 - } + const TWO_M27 = 1.0 / (1 << 27) // 2**-27 0x3e40000000000000 + const TWO_M13 = 1.0 / (1 << 13) // 2**-13 0x3f20000000000000 + const TWO129 = 0x4800000000000000 // 1 << 129 // 2**129 0x4800000000000000 + // R0/S0 on [0, 2] + const R02 = 1.56249999999999947958e-02 // 0x3F8FFFFFFFFFFFFD + const R03 = -1.89979294238854721751e-04 // 0xBF28E6A5B61AC6E9 + const R04 = 1.82954049532700665670e-06 // 0x3EBEB1D10C503919 + const R05 = -4.61832688532103189199e-09 // 0xBE33D5E773D63FCE + const S01 = 1.56191029464890010492e-02 // 0x3F8FFCE882C8C2A4 + const S02 = 1.16926784663337450260e-04 // 0x3F1EA6D2DD57DBF4 + const S03 = 5.13546550207318111446e-07 // 0x3EA13B54CE84D5A9 + const S04 = 1.16614003333790000205e-09 // 0x3E1408BCF4745D8F + // special cases + match { + | IsNaN(x): + ret x + | IsInf(x, 0): + ret 0 + | x == 0: + ret 1 + } - x = Abs(x) - if x >= 2 { - s, c := Sincos(x) - mut ss := s - c - mut cc := s + c + x = Abs(x) + if x >= 2 { + s, c := Sincos(x) + mut ss := s - c + mut cc := s + c - // make sure x+x does not overflow - if x < f64.Max/2 { - z := -Cos(x + x) - if s*c < 0 { - cc = z / ss - } else { - ss = z / cc - } - } + // make sure x+x does not overflow + if x < f64.Max/2 { + z := -Cos(x + x) + if s*c < 0 { + cc = z / ss + } else { + ss = z / cc + } + } - // j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x) - // y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x) + // j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x) + // y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x) - mut z := 0. - if x > TWO129 { // |x| > ~6.8056e+38 - z = (1 / SqrtPi) * cc / Sqrt(x) - } else { - u := pzero(x) - v := qzero(x) - z = (1 / SqrtPi) * (u * cc - v * ss) / Sqrt(x) - } - ret z // |x| >= 2.0 - } - if x < TWO_M13 { // |x| < ~1.2207e-4 - if x < TWO_M27 { - ret 1 // |x| < ~7.4506e-9 - } - ret 1 - 0.25 * x * x // ~7.4506e-9 < |x| < ~1.2207e-4 - } - z := x * x - r := z * (R02 + z * (R03 + z * (R04 + z * R05))) - s := 1 + z * (S01 + z * (S02 + z * (S03 + z * S04))) - if x < 1 { - ret 1 + z * (-0.25 + (r / s)) // |x| < 1.00 - } - u := 0.5 * x - ret (1 + u) * (1 - u) + z * (r / s) // 1.0 < |x| < 2.0 + mut z := 0. + if x > TWO129 { // |x| > ~6.8056e+38 + z = (1 / SqrtPi) * cc / Sqrt(x) + } else { + u := pzero(x) + v := qzero(x) + z = (1 / SqrtPi) * (u * cc - v * ss) / Sqrt(x) + } + ret z // |x| >= 2.0 + } + if x < TWO_M13 { // |x| < ~1.2207e-4 + if x < TWO_M27 { + ret 1 // |x| < ~7.4506e-9 + } + ret 1 - 0.25 * x * x // ~7.4506e-9 < |x| < ~1.2207e-4 + } + z := x * x + r := z * (R02 + z * (R03 + z * (R04 + z * R05))) + s := 1 + z * (S01 + z * (S02 + z * (S03 + z * S04))) + if x < 1 { + ret 1 + z * (-0.25 + (r / s)) // |x| < 1.00 + } + u := 0.5 * x + ret (1 + u) * (1 - u) + z * (r / s) // 1.0 < |x| < 2.0 } // Returns the order-zero Bessel function of the second kind. @@ -180,74 +180,74 @@ fn J0(mut x: f64): f64 { // Y0(x < 0) = NaN // Y0(NaN) = NaN fn Y0(x: f64): f64 { - const TWO_M27 = 1.0 / (1 << 27) // 2**-27 0x3e40000000000000 - const TWO129 = 0x4800000000000000 // 1 << 129 // 2**129 0x4800000000000000 - const U00 = -7.38042951086872317523e-02 // 0xBFB2E4D699CBD01F - const U01 = 1.76666452509181115538e-01 // 0x3FC69D019DE9E3FC - const U02 = -1.38185671945596898896e-02 // 0xBF8C4CE8B16CFA97 - const U03 = 3.47453432093683650238e-04 // 0x3F36C54D20B29B6B - const U04 = -3.81407053724364161125e-06 // 0xBECFFEA773D25CAD - const U05 = 1.95590137035022920206e-08 // 0x3E5500573B4EABD4 - const U06 = -3.98205194132103398453e-11 // 0xBDC5E43D693FB3C8 - const V01 = 1.27304834834123699328e-02 // 0x3F8A127091C9C71A - const V02 = 7.60068627350353253702e-05 // 0x3F13ECBBF578C6C1 - const V03 = 2.59150851840457805467e-07 // 0x3E91642D7FF202FD - const V04 = 4.41110311332675467403e-10 // 0x3DFE50183BD6D9EF - // special cases - match { - | x < 0 | IsNaN(x): - ret NaN() - | IsInf(x, 1): - ret 0 - | x == 0: - ret Inf(-1) - } + const TWO_M27 = 1.0 / (1 << 27) // 2**-27 0x3e40000000000000 + const TWO129 = 0x4800000000000000 // 1 << 129 // 2**129 0x4800000000000000 + const U00 = -7.38042951086872317523e-02 // 0xBFB2E4D699CBD01F + const U01 = 1.76666452509181115538e-01 // 0x3FC69D019DE9E3FC + const U02 = -1.38185671945596898896e-02 // 0xBF8C4CE8B16CFA97 + const U03 = 3.47453432093683650238e-04 // 0x3F36C54D20B29B6B + const U04 = -3.81407053724364161125e-06 // 0xBECFFEA773D25CAD + const U05 = 1.95590137035022920206e-08 // 0x3E5500573B4EABD4 + const U06 = -3.98205194132103398453e-11 // 0xBDC5E43D693FB3C8 + const V01 = 1.27304834834123699328e-02 // 0x3F8A127091C9C71A + const V02 = 7.60068627350353253702e-05 // 0x3F13ECBBF578C6C1 + const V03 = 2.59150851840457805467e-07 // 0x3E91642D7FF202FD + const V04 = 4.41110311332675467403e-10 // 0x3DFE50183BD6D9EF + // special cases + match { + | x < 0 | IsNaN(x): + ret NaN() + | IsInf(x, 1): + ret 0 + | x == 0: + ret Inf(-1) + } - if x >= 2 { // |x| >= 2.0 - // y0(x) = sqrt(2/(pi*x))*(p0(x)*sin(x0)+q0(x)*cos(x0)) - // where x0 = x-pi/4 - // Better formula: - // cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4) - // = 1/sqrt(2) * (sin(x) + cos(x)) - // sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4) - // = 1/sqrt(2) * (sin(x) - cos(x)) - // To avoid cancellation, use - // sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) - // to compute the worse one. + if x >= 2 { // |x| >= 2.0 + // y0(x) = sqrt(2/(pi*x))*(p0(x)*sin(x0)+q0(x)*cos(x0)) + // where x0 = x-pi/4 + // Better formula: + // cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4) + // = 1/sqrt(2) * (sin(x) + cos(x)) + // sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4) + // = 1/sqrt(2) * (sin(x) - cos(x)) + // To avoid cancellation, use + // sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + // to compute the worse one. - s, c := Sincos(x) - mut ss := s - c - mut cc := s + c + s, c := Sincos(x) + mut ss := s - c + mut cc := s + c - // j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x) - // y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x) + // j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x) + // y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x) - // make sure x+x does not overflow - if x < f64.Max/2 { - z := -Cos(x + x) - if s*c < 0 { - cc = z / ss - } else { - ss = z / cc - } - } - mut z := 0. - if x > TWO129 { // |x| > ~6.8056e+38 - z = (1 / SqrtPi) * ss / Sqrt(x) - } else { - u := pzero(x) - v := qzero(x) - z = (1 / SqrtPi) * (u * ss + v * cc) / Sqrt(x) - } - ret z // |x| >= 2.0 - } - if x <= TWO_M27 { - ret U00 + (2 / Pi) * Log(x) // |x| < ~7.4506e-9 - } - z := x * x - u := U00 + z * (U01 + z * (U02 + z * (U03 + z * (U04 + z * (U05 + z * U06))))) - v := 1 + z * (V01 + z * (V02 + z * (V03 + z * V04))) - ret u / v + (2 / Pi) * J0(x) * Log(x) // ~7.4506e-9 < |x| < 2.0 + // make sure x+x does not overflow + if x < f64.Max/2 { + z := -Cos(x + x) + if s*c < 0 { + cc = z / ss + } else { + ss = z / cc + } + } + mut z := 0. + if x > TWO129 { // |x| > ~6.8056e+38 + z = (1 / SqrtPi) * ss / Sqrt(x) + } else { + u := pzero(x) + v := qzero(x) + z = (1 / SqrtPi) * (u * ss + v * cc) / Sqrt(x) + } + ret z // |x| >= 2.0 + } + if x <= TWO_M27 { + ret U00 + (2 / Pi) * Log(x) // |x| < ~7.4506e-9 + } + z := x * x + u := U00 + z * (U01 + z * (U02 + z * (U03 + z * (U04 + z * (U05 + z * U06))))) + v := 1 + z * (V01 + z * (V02 + z * (V03 + z * V04))) + ret u / v + (2 / Pi) * J0(x) * Log(x) // ~7.4506e-9 < |x| < 2.0 } // The asymptotic expansions of pzero is @@ -261,94 +261,94 @@ fn Y0(x: f64): f64 { // for x in [+inf, 8]=1/[0,0.125] static p0r8: [6]f64 = [ - 0.00000000000000000000e+00, // 0x0000000000000000 - -7.03124999999900357484e-02, // 0xBFB1FFFFFFFFFD32 - -8.08167041275349795626e+00, // 0xC02029D0B44FA779 - -2.57063105679704847262e+02, // 0xC07011027B19E863 - -2.48521641009428822144e+03, // 0xC0A36A6ECD4DCAFC - -5.25304380490729545272e+03, // 0xC0B4850B36CC643D + 0.00000000000000000000e+00, // 0x0000000000000000 + -7.03124999999900357484e-02, // 0xBFB1FFFFFFFFFD32 + -8.08167041275349795626e+00, // 0xC02029D0B44FA779 + -2.57063105679704847262e+02, // 0xC07011027B19E863 + -2.48521641009428822144e+03, // 0xC0A36A6ECD4DCAFC + -5.25304380490729545272e+03, // 0xC0B4850B36CC643D ] static p0s8: [5]f64 = [ - 1.16534364619668181717e+02, // 0x405D223307A96751 - 3.83374475364121826715e+03, // 0x40ADF37D50596938 - 4.05978572648472545552e+04, // 0x40E3D2BB6EB6B05F - 1.16752972564375915681e+05, // 0x40FC810F8F9FA9BD - 4.76277284146730962675e+04, // 0x40E741774F2C49DC + 1.16534364619668181717e+02, // 0x405D223307A96751 + 3.83374475364121826715e+03, // 0x40ADF37D50596938 + 4.05978572648472545552e+04, // 0x40E3D2BB6EB6B05F + 1.16752972564375915681e+05, // 0x40FC810F8F9FA9BD + 4.76277284146730962675e+04, // 0x40E741774F2C49DC ] // for x in [8,4.5454]=1/[0.125,0.22001] static p0r5: [6]f64 = [ - -1.14125464691894502584e-11, // 0xBDA918B147E495CC - -7.03124940873599280078e-02, // 0xBFB1FFFFE69AFBC6 - -4.15961064470587782438e+00, // 0xC010A370F90C6BBF - -6.76747652265167261021e+01, // 0xC050EB2F5A7D1783 - -3.31231299649172967747e+02, // 0xC074B3B36742CC63 - -3.46433388365604912451e+02, // 0xC075A6EF28A38BD7 + -1.14125464691894502584e-11, // 0xBDA918B147E495CC + -7.03124940873599280078e-02, // 0xBFB1FFFFE69AFBC6 + -4.15961064470587782438e+00, // 0xC010A370F90C6BBF + -6.76747652265167261021e+01, // 0xC050EB2F5A7D1783 + -3.31231299649172967747e+02, // 0xC074B3B36742CC63 + -3.46433388365604912451e+02, // 0xC075A6EF28A38BD7 ] static p0s5: [5]f64 = [ - 6.07539382692300335975e+01, // 0x404E60810C98C5DE - 1.05125230595704579173e+03, // 0x40906D025C7E2864 - 5.97897094333855784498e+03, // 0x40B75AF88FBE1D60 - 9.62544514357774460223e+03, // 0x40C2CCB8FA76FA38 - 2.40605815922939109441e+03, // 0x40A2CC1DC70BE864 + 6.07539382692300335975e+01, // 0x404E60810C98C5DE + 1.05125230595704579173e+03, // 0x40906D025C7E2864 + 5.97897094333855784498e+03, // 0x40B75AF88FBE1D60 + 9.62544514357774460223e+03, // 0x40C2CCB8FA76FA38 + 2.40605815922939109441e+03, // 0x40A2CC1DC70BE864 ] // for x in [4.547,2.8571]=1/[0.2199,0.35001] static p0r3: [6]f64 = [ - -2.54704601771951915620e-09, // 0xBE25E1036FE1AA86 - -7.03119616381481654654e-02, // 0xBFB1FFF6F7C0E24B - -2.40903221549529611423e+00, // 0xC00345B2AEA48074 - -2.19659774734883086467e+01, // 0xC035F74A4CB94E14 - -5.80791704701737572236e+01, // 0xC04D0A22420A1A45 - -3.14479470594888503854e+01, // 0xC03F72ACA892D80F + -2.54704601771951915620e-09, // 0xBE25E1036FE1AA86 + -7.03119616381481654654e-02, // 0xBFB1FFF6F7C0E24B + -2.40903221549529611423e+00, // 0xC00345B2AEA48074 + -2.19659774734883086467e+01, // 0xC035F74A4CB94E14 + -5.80791704701737572236e+01, // 0xC04D0A22420A1A45 + -3.14479470594888503854e+01, // 0xC03F72ACA892D80F ] static p0s3: [5]f64 = [ - 3.58560338055209726349e+01, // 0x4041ED9284077DD3 - 3.61513983050303863820e+02, // 0x40769839464A7C0E - 1.19360783792111533330e+03, // 0x4092A66E6D1061D6 - 1.12799679856907414432e+03, // 0x40919FFCB8C39B7E - 1.73580930813335754692e+02, // 0x4065B296FC379081 + 3.58560338055209726349e+01, // 0x4041ED9284077DD3 + 3.61513983050303863820e+02, // 0x40769839464A7C0E + 1.19360783792111533330e+03, // 0x4092A66E6D1061D6 + 1.12799679856907414432e+03, // 0x40919FFCB8C39B7E + 1.73580930813335754692e+02, // 0x4065B296FC379081 ] // for x in [2.8570,2]=1/[0.3499,0.5] static p0r2: [6]f64 = [ - -8.87534333032526411254e-08, // 0xBE77D316E927026D - -7.03030995483624743247e-02, // 0xBFB1FF62495E1E42 - -1.45073846780952986357e+00, // 0xBFF736398A24A843 - -7.63569613823527770791e+00, // 0xC01E8AF3EDAFA7F3 - -1.11931668860356747786e+01, // 0xC02662E6C5246303 - -3.23364579351335335033e+00, // 0xC009DE81AF8FE70F + -8.87534333032526411254e-08, // 0xBE77D316E927026D + -7.03030995483624743247e-02, // 0xBFB1FF62495E1E42 + -1.45073846780952986357e+00, // 0xBFF736398A24A843 + -7.63569613823527770791e+00, // 0xC01E8AF3EDAFA7F3 + -1.11931668860356747786e+01, // 0xC02662E6C5246303 + -3.23364579351335335033e+00, // 0xC009DE81AF8FE70F ] static p0s2: [5]f64 = [ - 2.22202997532088808441e+01, // 0x40363865908B5959 - 1.36206794218215208048e+02, // 0x4061069E0EE8878F - 2.70470278658083486789e+02, // 0x4070E78642EA079B - 1.53875394208320329881e+02, // 0x40633C033AB6FAFF - 1.46576176948256193810e+01, // 0x402D50B344391809 + 2.22202997532088808441e+01, // 0x40363865908B5959 + 1.36206794218215208048e+02, // 0x4061069E0EE8878F + 2.70470278658083486789e+02, // 0x4070E78642EA079B + 1.53875394208320329881e+02, // 0x40633C033AB6FAFF + 1.46576176948256193810e+01, // 0x402D50B344391809 ] fn pzero(x: f64): f64 { - let mut p: *[6]f64 = nil - let mut q: *[5]f64 = nil - if x >= 8 { - p = &p0r8 - q = &p0s8 - } else if x >= 4.5454 { - p = &p0r5 - q = &p0s5 - } else if x >= 2.8571 { - p = &p0r3 - q = &p0s3 - } else if x >= 2 { - p = &p0r2 - q = &p0s2 - } - unsafe { - z := 1 / (x * x) - r := (*p)[0] + z * ((*p)[1] + z * ((*p)[2] + z * ((*p)[3] + z * ((*p)[4] + z * (*p)[5])))) - s := 1 + z * ((*q)[0] + z * ((*q)[1] + z * ((*q)[2] + z * ((*q)[3] + z * (*q)[4])))) - ret 1 + r / s - } + let mut p: *[6]f64 = nil + let mut q: *[5]f64 = nil + if x >= 8 { + p = &p0r8 + q = &p0s8 + } else if x >= 4.5454 { + p = &p0r5 + q = &p0s5 + } else if x >= 2.8571 { + p = &p0r3 + q = &p0s3 + } else if x >= 2 { + p = &p0r2 + q = &p0s2 + } + unsafe { + z := 1 / (x * x) + r := (*p)[0] + z * ((*p)[1] + z * ((*p)[2] + z * ((*p)[3] + z * ((*p)[4] + z * (*p)[5])))) + s := 1 + z * ((*q)[0] + z * ((*q)[1] + z * ((*q)[2] + z * ((*q)[3] + z * (*q)[4])))) + ret 1 + r / s + } } // For x >= 8, the asymptotic expansions of qzero is @@ -362,96 +362,96 @@ fn pzero(x: f64): f64 { // for x in [+inf, 8]=1/[0,0.125] static q0r8: [6]f64 = [ - 0.00000000000000000000e+00, // 0x0000000000000000 - 7.32421874999935051953e-02, // 0x3FB2BFFFFFFFFE2C - 1.17682064682252693899e+01, // 0x402789525BB334D6 - 5.57673380256401856059e+02, // 0x40816D6315301825 - 8.85919720756468632317e+03, // 0x40C14D993E18F46D - 3.70146267776887834771e+04, // 0x40E212D40E901566 + 0.00000000000000000000e+00, // 0x0000000000000000 + 7.32421874999935051953e-02, // 0x3FB2BFFFFFFFFE2C + 1.17682064682252693899e+01, // 0x402789525BB334D6 + 5.57673380256401856059e+02, // 0x40816D6315301825 + 8.85919720756468632317e+03, // 0x40C14D993E18F46D + 3.70146267776887834771e+04, // 0x40E212D40E901566 ] static q0s8: [6]f64 = [ - 1.63776026895689824414e+02, // 0x406478D5365B39BC - 8.09834494656449805916e+03, // 0x40BFA2584E6B0563 - 1.42538291419120476348e+05, // 0x4101665254D38C3F - 8.03309257119514397345e+05, // 0x412883DA83A52B43 - 8.40501579819060512818e+05, // 0x4129A66B28DE0B3D - -3.43899293537866615225e+05, // 0xC114FD6D2C9530C5 + 1.63776026895689824414e+02, // 0x406478D5365B39BC + 8.09834494656449805916e+03, // 0x40BFA2584E6B0563 + 1.42538291419120476348e+05, // 0x4101665254D38C3F + 8.03309257119514397345e+05, // 0x412883DA83A52B43 + 8.40501579819060512818e+05, // 0x4129A66B28DE0B3D + -3.43899293537866615225e+05, // 0xC114FD6D2C9530C5 ] // for x in [8,4.5454]=1/[0.125,0.22001] static q0r5: [6]f64 = [ - 1.84085963594515531381e-11, // 0x3DB43D8F29CC8CD9 - 7.32421766612684765896e-02, // 0x3FB2BFFFD172B04C - 5.83563508962056953777e+00, // 0x401757B0B9953DD3 - 1.35111577286449829671e+02, // 0x4060E3920A8788E9 - 1.02724376596164097464e+03, // 0x40900CF99DC8C481 - 1.98997785864605384631e+03, // 0x409F17E953C6E3A6 + 1.84085963594515531381e-11, // 0x3DB43D8F29CC8CD9 + 7.32421766612684765896e-02, // 0x3FB2BFFFD172B04C + 5.83563508962056953777e+00, // 0x401757B0B9953DD3 + 1.35111577286449829671e+02, // 0x4060E3920A8788E9 + 1.02724376596164097464e+03, // 0x40900CF99DC8C481 + 1.98997785864605384631e+03, // 0x409F17E953C6E3A6 ] static q0s5: [6]f64 = [ - 8.27766102236537761883e+01, // 0x4054B1B3FB5E1543 - 2.07781416421392987104e+03, // 0x40A03BA0DA21C0CE - 1.88472887785718085070e+04, // 0x40D267D27B591E6D - 5.67511122894947329769e+04, // 0x40EBB5E397E02372 - 3.59767538425114471465e+04, // 0x40E191181F7A54A0 - -5.35434275601944773371e+03, // 0xC0B4EA57BEDBC609 + 8.27766102236537761883e+01, // 0x4054B1B3FB5E1543 + 2.07781416421392987104e+03, // 0x40A03BA0DA21C0CE + 1.88472887785718085070e+04, // 0x40D267D27B591E6D + 5.67511122894947329769e+04, // 0x40EBB5E397E02372 + 3.59767538425114471465e+04, // 0x40E191181F7A54A0 + -5.35434275601944773371e+03, // 0xC0B4EA57BEDBC609 ] // for x in [4.547,2.8571]=1/[0.2199,0.35001] static q0r3: [6]f64 = [ - 4.37741014089738620906e-09, // 0x3E32CD036ADECB82 - 7.32411180042911447163e-02, // 0x3FB2BFEE0E8D0842 - 3.34423137516170720929e+00, // 0x400AC0FC61149CF5 - 4.26218440745412650017e+01, // 0x40454F98962DAEDD - 1.70808091340565596283e+02, // 0x406559DBE25EFD1F - 1.66733948696651168575e+02, // 0x4064D77C81FA21E0 + 4.37741014089738620906e-09, // 0x3E32CD036ADECB82 + 7.32411180042911447163e-02, // 0x3FB2BFEE0E8D0842 + 3.34423137516170720929e+00, // 0x400AC0FC61149CF5 + 4.26218440745412650017e+01, // 0x40454F98962DAEDD + 1.70808091340565596283e+02, // 0x406559DBE25EFD1F + 1.66733948696651168575e+02, // 0x4064D77C81FA21E0 ] static q0s3: [6]f64 = [ - 4.87588729724587182091e+01, // 0x40486122BFE343A6 - 7.09689221056606015736e+02, // 0x40862D8386544EB3 - 3.70414822620111362994e+03, // 0x40ACF04BE44DFC63 - 6.46042516752568917582e+03, // 0x40B93C6CD7C76A28 - 2.51633368920368957333e+03, // 0x40A3A8AAD94FB1C0 - -1.49247451836156386662e+02, // 0xC062A7EB201CF40F + 4.87588729724587182091e+01, // 0x40486122BFE343A6 + 7.09689221056606015736e+02, // 0x40862D8386544EB3 + 3.70414822620111362994e+03, // 0x40ACF04BE44DFC63 + 6.46042516752568917582e+03, // 0x40B93C6CD7C76A28 + 2.51633368920368957333e+03, // 0x40A3A8AAD94FB1C0 + -1.49247451836156386662e+02, // 0xC062A7EB201CF40F ] // for x in [2.8570,2]=1/[0.3499,0.5] static q0r2: [6]f64 = [ - 1.50444444886983272379e-07, // 0x3E84313B54F76BDB - 7.32234265963079278272e-02, // 0x3FB2BEC53E883E34 - 1.99819174093815998816e+00, // 0x3FFFF897E727779C - 1.44956029347885735348e+01, // 0x402CFDBFAAF96FE5 - 3.16662317504781540833e+01, // 0x403FAA8E29FBDC4A - 1.62527075710929267416e+01, // 0x403040B171814BB4 + 1.50444444886983272379e-07, // 0x3E84313B54F76BDB + 7.32234265963079278272e-02, // 0x3FB2BEC53E883E34 + 1.99819174093815998816e+00, // 0x3FFFF897E727779C + 1.44956029347885735348e+01, // 0x402CFDBFAAF96FE5 + 3.16662317504781540833e+01, // 0x403FAA8E29FBDC4A + 1.62527075710929267416e+01, // 0x403040B171814BB4 ] static q0s2: [6]f64 = [ - 3.03655848355219184498e+01, // 0x403E5D96F7C07AED - 2.69348118608049844624e+02, // 0x4070D591E4D14B40 - 8.44783757595320139444e+02, // 0x408A664522B3BF22 - 8.82935845112488550512e+02, // 0x408B977C9C5CC214 - 2.12666388511798828631e+02, // 0x406A95530E001365 - -5.31095493882666946917e+00, // 0xC0153E6AF8B32931 + 3.03655848355219184498e+01, // 0x403E5D96F7C07AED + 2.69348118608049844624e+02, // 0x4070D591E4D14B40 + 8.44783757595320139444e+02, // 0x408A664522B3BF22 + 8.82935845112488550512e+02, // 0x408B977C9C5CC214 + 2.12666388511798828631e+02, // 0x406A95530E001365 + -5.31095493882666946917e+00, // 0xC0153E6AF8B32931 ] fn qzero(x: f64): f64 { - let mut p: *[6]f64 = nil - let mut q: *[6]f64 = nil - if x >= 8 { - p = &q0r8 - q = &q0s8 - } else if x >= 4.5454 { - p = &q0r5 - q = &q0s5 - } else if x >= 2.8571 { - p = &q0r3 - q = &q0s3 - } else if x >= 2 { - p = &q0r2 - q = &q0s2 - } - unsafe { - z := 1 / (x * x) - r := (*p)[0] + z * ((*p)[1] + z * ((*p)[2] + z * ((*p)[3] + z * ((*p)[4] + z * (*p)[5])))) - s := 1 + z * ((*q)[0] + z * ((*q)[1] + z * ((*q)[2] + z * ((*q)[3] + z * ((*q)[4] + z * (*q)[5]))))) - ret (-0.125 + r / s) / x - } + let mut p: *[6]f64 = nil + let mut q: *[6]f64 = nil + if x >= 8 { + p = &q0r8 + q = &q0s8 + } else if x >= 4.5454 { + p = &q0r5 + q = &q0s5 + } else if x >= 2.8571 { + p = &q0r3 + q = &q0s3 + } else if x >= 2 { + p = &q0r2 + q = &q0s2 + } + unsafe { + z := 1 / (x * x) + r := (*p)[0] + z * ((*p)[1] + z * ((*p)[2] + z * ((*p)[3] + z * ((*p)[4] + z * (*p)[5])))) + s := 1 + z * ((*q)[0] + z * ((*q)[1] + z * ((*q)[2] + z * ((*q)[3] + z * ((*q)[4] + z * (*q)[5]))))) + ret (-0.125 + r / s) / x + } } \ No newline at end of file diff --git a/std/math/j1.jule b/std/math/j1.jule index 79b6322a7..d57cfac6e 100644 --- a/std/math/j1.jule +++ b/std/math/j1.jule @@ -103,75 +103,75 @@ // J1(±Inf) = 0 // J1(NaN) = NaN fn J1(mut x: f64): f64 { - const TWO_M27 = 1.0 / (1 << 27) // 2**-27 0x3e40000000000000 - const TWO129 = 0x4800000000000000 // 1 << 129 // 2**129 0x4800000000000000 - // R0/S0 on [0, 2] - const R00 = -6.25000000000000000000e-02 // 0xBFB0000000000000 - const R01 = 1.40705666955189706048e-03 // 0x3F570D9F98472C61 - const R02 = -1.59955631084035597520e-05 // 0xBEF0C5C6BA169668 - const R03 = 4.96727999609584448412e-08 // 0x3E6AAAFA46CA0BD9 - const S01 = 1.91537599538363460805e-02 // 0x3F939D0B12637E53 - const S02 = 1.85946785588630915560e-04 // 0x3F285F56B9CDF664 - const S03 = 1.17718464042623683263e-06 // 0x3EB3BFF8333F8498 - const S04 = 5.04636257076217042715e-09 // 0x3E35AC88C97DFF2C - const S05 = 1.23542274426137913908e-11 // 0x3DAB2ACFCFB97ED8 - // special cases - match { - | IsNaN(x): - ret x - | IsInf(x, 0) | x == 0: - ret 0 - } + const TWO_M27 = 1.0 / (1 << 27) // 2**-27 0x3e40000000000000 + const TWO129 = 0x4800000000000000 // 1 << 129 // 2**129 0x4800000000000000 + // R0/S0 on [0, 2] + const R00 = -6.25000000000000000000e-02 // 0xBFB0000000000000 + const R01 = 1.40705666955189706048e-03 // 0x3F570D9F98472C61 + const R02 = -1.59955631084035597520e-05 // 0xBEF0C5C6BA169668 + const R03 = 4.96727999609584448412e-08 // 0x3E6AAAFA46CA0BD9 + const S01 = 1.91537599538363460805e-02 // 0x3F939D0B12637E53 + const S02 = 1.85946785588630915560e-04 // 0x3F285F56B9CDF664 + const S03 = 1.17718464042623683263e-06 // 0x3EB3BFF8333F8498 + const S04 = 5.04636257076217042715e-09 // 0x3E35AC88C97DFF2C + const S05 = 1.23542274426137913908e-11 // 0x3DAB2ACFCFB97ED8 + // special cases + match { + | IsNaN(x): + ret x + | IsInf(x, 0) | x == 0: + ret 0 + } - mut sign := false - if x < 0 { - x = -x - sign = true - } - if x >= 2 { - s, c := Sincos(x) - mut ss := -s - c - mut cc := s - c + mut sign := false + if x < 0 { + x = -x + sign = true + } + if x >= 2 { + s, c := Sincos(x) + mut ss := -s - c + mut cc := s - c - // make sure x+x does not overflow - if x < f64.Max/2 { - z := Cos(x + x) - if s*c > 0 { - cc = z / ss - } else { - ss = z / cc - } - } + // make sure x+x does not overflow + if x < f64.Max/2 { + z := Cos(x + x) + if s*c > 0 { + cc = z / ss + } else { + ss = z / cc + } + } - // j1(x) = 1/sqrt(pi) * (P(1,x)*cc - Q(1,x)*ss) / sqrt(x) - // y1(x) = 1/sqrt(pi) * (P(1,x)*ss + Q(1,x)*cc) / sqrt(x) + // j1(x) = 1/sqrt(pi) * (P(1,x)*cc - Q(1,x)*ss) / sqrt(x) + // y1(x) = 1/sqrt(pi) * (P(1,x)*ss + Q(1,x)*cc) / sqrt(x) - mut z := 0. - if x > TWO129 { - z = (1 / SqrtPi) * cc / Sqrt(x) - } else { - u := pone(x) - v := qone(x) - z = (1 / SqrtPi) * (u * cc - v * ss) / Sqrt(x) - } - if sign { - ret -z - } - ret z - } + mut z := 0. + if x > TWO129 { + z = (1 / SqrtPi) * cc / Sqrt(x) + } else { + u := pone(x) + v := qone(x) + z = (1 / SqrtPi) * (u * cc - v * ss) / Sqrt(x) + } + if sign { + ret -z + } + ret z + } - if x < TWO_M27 { // |x|<2**-27 - ret 0.5 * x // inexact if x!=0 necessary - } - mut z := x * x - mut r := z * (R00 + z * (R01 + z * (R02 + z * R03))) - s := 1.0 + z * (S01 + z * (S02 + z * (S03 + z * (S04 + z * S05)))) - r *= x - z = 0.5 * x + r / s - if sign { - ret -z - } - ret z + if x < TWO_M27 { // |x|<2**-27 + ret 0.5 * x // inexact if x!=0 necessary + } + mut z := x * x + mut r := z * (R00 + z * (R01 + z * (R02 + z * R03))) + s := 1.0 + z * (S01 + z * (S02 + z * (S03 + z * (S04 + z * S05)))) + r *= x + z = 0.5 * x + r / s + if sign { + ret -z + } + ret z } // Returns the order-one Bessel function of the second kind. @@ -182,70 +182,70 @@ fn J1(mut x: f64): f64 { // Y1(x < 0) = NaN // Y1(NaN) = NaN fn Y1(x: f64): f64 { - const TWO_M54 = 1.0 / (1 << 54) // 2**-54 0x3c90000000000000 - const TWO129 = 0x4800000000000000 // 1 << 129 // 2**129 0x4800000000000000 - const U00 = -1.96057090646238940668e-01 // 0xBFC91866143CBC8A - const U01 = 5.04438716639811282616e-02 // 0x3FA9D3C776292CD1 - const U02 = -1.91256895875763547298e-03 // 0xBF5F55E54844F50F - const U03 = 2.35252600561610495928e-05 // 0x3EF8AB038FA6B88E - const U04 = -9.19099158039878874504e-08 // 0xBE78AC00569105B8 - const V00 = 1.99167318236649903973e-02 // 0x3F94650D3F4DA9F0 - const V01 = 2.02552581025135171496e-04 // 0x3F2A8C896C257764 - const V02 = 1.35608801097516229404e-06 // 0x3EB6C05A894E8CA6 - const V03 = 6.22741452364621501295e-09 // 0x3E3ABF1D5BA69A86 - const V04 = 1.66559246207992079114e-11 // 0x3DB25039DACA772A - // special cases - match { - | x < 0 | IsNaN(x): - ret NaN() - | IsInf(x, 1): - ret 0 - | x == 0: - ret Inf(-1) - } + const TWO_M54 = 1.0 / (1 << 54) // 2**-54 0x3c90000000000000 + const TWO129 = 0x4800000000000000 // 1 << 129 // 2**129 0x4800000000000000 + const U00 = -1.96057090646238940668e-01 // 0xBFC91866143CBC8A + const U01 = 5.04438716639811282616e-02 // 0x3FA9D3C776292CD1 + const U02 = -1.91256895875763547298e-03 // 0xBF5F55E54844F50F + const U03 = 2.35252600561610495928e-05 // 0x3EF8AB038FA6B88E + const U04 = -9.19099158039878874504e-08 // 0xBE78AC00569105B8 + const V00 = 1.99167318236649903973e-02 // 0x3F94650D3F4DA9F0 + const V01 = 2.02552581025135171496e-04 // 0x3F2A8C896C257764 + const V02 = 1.35608801097516229404e-06 // 0x3EB6C05A894E8CA6 + const V03 = 6.22741452364621501295e-09 // 0x3E3ABF1D5BA69A86 + const V04 = 1.66559246207992079114e-11 // 0x3DB25039DACA772A + // special cases + match { + | x < 0 | IsNaN(x): + ret NaN() + | IsInf(x, 1): + ret 0 + | x == 0: + ret Inf(-1) + } - if x >= 2 { - s, c := Sincos(x) - mut ss := -s - c - mut cc := s - c + if x >= 2 { + s, c := Sincos(x) + mut ss := -s - c + mut cc := s - c - // make sure x+x does not overflow - if x < f64.Max/2 { - z := Cos(x + x) - if s*c > 0 { - cc = z / ss - } else { - ss = z / cc - } - } - // y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x0)+q1(x)*cos(x0)) - // where x0 = x-3pi/4 - // Better formula: - // cos(x0) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4) - // = 1/sqrt(2) * (sin(x) - cos(x)) - // sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4) - // = -1/sqrt(2) * (cos(x) + sin(x)) - // To avoid cancellation, use - // sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) - // to compute the worse one. + // make sure x+x does not overflow + if x < f64.Max/2 { + z := Cos(x + x) + if s*c > 0 { + cc = z / ss + } else { + ss = z / cc + } + } + // y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x0)+q1(x)*cos(x0)) + // where x0 = x-3pi/4 + // Better formula: + // cos(x0) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4) + // = 1/sqrt(2) * (sin(x) - cos(x)) + // sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4) + // = -1/sqrt(2) * (cos(x) + sin(x)) + // To avoid cancellation, use + // sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + // to compute the worse one. - mut z := 0. - if x > TWO129 { - z = (1 / SqrtPi) * ss / Sqrt(x) - } else { - u := pone(x) - v := qone(x) - z = (1 / SqrtPi) * (u * ss + v * cc) / Sqrt(x) - } - ret z - } - if x <= TWO_M54 { // x < 2**-54 - ret -(2 / Pi) / x - } - z := x * x - u := U00 + z * (U01 + z * (U02 + z * (U03 + z * U04))) - v := 1 + z * (V00 + z * (V01 + z * (V02 + z * (V03 + z * V04)))) - ret x * (u / v) + (2 / Pi) * (J1(x) * Log(x) - 1 / x) + mut z := 0. + if x > TWO129 { + z = (1 / SqrtPi) * ss / Sqrt(x) + } else { + u := pone(x) + v := qone(x) + z = (1 / SqrtPi) * (u * ss + v * cc) / Sqrt(x) + } + ret z + } + if x <= TWO_M54 { // x < 2**-54 + ret -(2 / Pi) / x + } + z := x * x + u := U00 + z * (U01 + z * (U02 + z * (U03 + z * U04))) + v := 1 + z * (V00 + z * (V01 + z * (V02 + z * (V03 + z * V04)))) + ret x * (u / v) + (2 / Pi) * (J1(x) * Log(x) - 1 / x) } // For x >= 8, the asymptotic expansions of pone is @@ -259,94 +259,94 @@ fn Y1(x: f64): f64 { // for x in [+inf, 8]=1/[0,0.125] static p1r8: [6]f64 = [ - 0.00000000000000000000e+00, // 0x0000000000000000 - 1.17187499999988647970e-01, // 0x3FBDFFFFFFFFFCCE - 1.32394806593073575129e+01, // 0x402A7A9D357F7FCE - 4.12051854307378562225e+02, // 0x4079C0D4652EA590 - 3.87474538913960532227e+03, // 0x40AE457DA3A532CC - 7.91447954031891731574e+03, // 0x40BEEA7AC32782DD + 0.00000000000000000000e+00, // 0x0000000000000000 + 1.17187499999988647970e-01, // 0x3FBDFFFFFFFFFCCE + 1.32394806593073575129e+01, // 0x402A7A9D357F7FCE + 4.12051854307378562225e+02, // 0x4079C0D4652EA590 + 3.87474538913960532227e+03, // 0x40AE457DA3A532CC + 7.91447954031891731574e+03, // 0x40BEEA7AC32782DD ] static p1s8: [5]f64 = [ - 1.14207370375678408436e+02, // 0x405C8D458E656CAC - 3.65093083420853463394e+03, // 0x40AC85DC964D274F - 3.69562060269033463555e+04, // 0x40E20B8697C5BB7F - 9.76027935934950801311e+04, // 0x40F7D42CB28F17BB - 3.08042720627888811578e+04, // 0x40DE1511697A0B2D + 1.14207370375678408436e+02, // 0x405C8D458E656CAC + 3.65093083420853463394e+03, // 0x40AC85DC964D274F + 3.69562060269033463555e+04, // 0x40E20B8697C5BB7F + 9.76027935934950801311e+04, // 0x40F7D42CB28F17BB + 3.08042720627888811578e+04, // 0x40DE1511697A0B2D ] // for x in [8,4.5454] = 1/[0.125,0.22001] static p1r5: [6]f64 = [ - 1.31990519556243522749e-11, // 0x3DAD0667DAE1CA7D - 1.17187493190614097638e-01, // 0x3FBDFFFFE2C10043 - 6.80275127868432871736e+00, // 0x401B36046E6315E3 - 1.08308182990189109773e+02, // 0x405B13B9452602ED - 5.17636139533199752805e+02, // 0x40802D16D052D649 - 5.28715201363337541807e+02, // 0x408085B8BB7E0CB7 + 1.31990519556243522749e-11, // 0x3DAD0667DAE1CA7D + 1.17187493190614097638e-01, // 0x3FBDFFFFE2C10043 + 6.80275127868432871736e+00, // 0x401B36046E6315E3 + 1.08308182990189109773e+02, // 0x405B13B9452602ED + 5.17636139533199752805e+02, // 0x40802D16D052D649 + 5.28715201363337541807e+02, // 0x408085B8BB7E0CB7 ] static p1s5: [5]f64 = [ - 5.92805987221131331921e+01, // 0x404DA3EAA8AF633D - 9.91401418733614377743e+02, // 0x408EFB361B066701 - 5.35326695291487976647e+03, // 0x40B4E9445706B6FB - 7.84469031749551231769e+03, // 0x40BEA4B0B8A5BB15 - 1.50404688810361062679e+03, // 0x40978030036F5E51 + 5.92805987221131331921e+01, // 0x404DA3EAA8AF633D + 9.91401418733614377743e+02, // 0x408EFB361B066701 + 5.35326695291487976647e+03, // 0x40B4E9445706B6FB + 7.84469031749551231769e+03, // 0x40BEA4B0B8A5BB15 + 1.50404688810361062679e+03, // 0x40978030036F5E51 ] // for x in[4.5453,2.8571] = 1/[0.2199,0.35001] static p1r3: [6]f64 = [ - 3.02503916137373618024e-09, // 0x3E29FC21A7AD9EDD - 1.17186865567253592491e-01, // 0x3FBDFFF55B21D17B - 3.93297750033315640650e+00, // 0x400F76BCE85EAD8A - 3.51194035591636932736e+01, // 0x40418F489DA6D129 - 9.10550110750781271918e+01, // 0x4056C3854D2C1837 - 4.85590685197364919645e+01, // 0x4048478F8EA83EE5 + 3.02503916137373618024e-09, // 0x3E29FC21A7AD9EDD + 1.17186865567253592491e-01, // 0x3FBDFFF55B21D17B + 3.93297750033315640650e+00, // 0x400F76BCE85EAD8A + 3.51194035591636932736e+01, // 0x40418F489DA6D129 + 9.10550110750781271918e+01, // 0x4056C3854D2C1837 + 4.85590685197364919645e+01, // 0x4048478F8EA83EE5 ] static p1s3: [5]f64 = [ - 3.47913095001251519989e+01, // 0x40416549A134069C - 3.36762458747825746741e+02, // 0x40750C3307F1A75F - 1.04687139975775130551e+03, // 0x40905B7C5037D523 - 8.90811346398256432622e+02, // 0x408BD67DA32E31E9 - 1.03787932439639277504e+02, // 0x4059F26D7C2EED53 + 3.47913095001251519989e+01, // 0x40416549A134069C + 3.36762458747825746741e+02, // 0x40750C3307F1A75F + 1.04687139975775130551e+03, // 0x40905B7C5037D523 + 8.90811346398256432622e+02, // 0x408BD67DA32E31E9 + 1.03787932439639277504e+02, // 0x4059F26D7C2EED53 ] // for x in [2.8570,2] = 1/[0.3499,0.5] static p1r2: [6]f64 = [ - 1.07710830106873743082e-07, // 0x3E7CE9D4F65544F4 - 1.17176219462683348094e-01, // 0x3FBDFF42BE760D83 - 2.36851496667608785174e+00, // 0x4002F2B7F98FAEC0 - 1.22426109148261232917e+01, // 0x40287C377F71A964 - 1.76939711271687727390e+01, // 0x4031B1A8177F8EE2 - 5.07352312588818499250e+00, // 0x40144B49A574C1FE + 1.07710830106873743082e-07, // 0x3E7CE9D4F65544F4 + 1.17176219462683348094e-01, // 0x3FBDFF42BE760D83 + 2.36851496667608785174e+00, // 0x4002F2B7F98FAEC0 + 1.22426109148261232917e+01, // 0x40287C377F71A964 + 1.76939711271687727390e+01, // 0x4031B1A8177F8EE2 + 5.07352312588818499250e+00, // 0x40144B49A574C1FE ] static p1s2: [5]f64 = [ - 2.14364859363821409488e+01, // 0x40356FBD8AD5ECDC - 1.25290227168402751090e+02, // 0x405F529314F92CD5 - 2.32276469057162813669e+02, // 0x406D08D8D5A2DBD9 - 1.17679373287147100768e+02, // 0x405D6B7ADA1884A9 - 8.36463893371618283368e+00, // 0x4020BAB1F44E5192 + 2.14364859363821409488e+01, // 0x40356FBD8AD5ECDC + 1.25290227168402751090e+02, // 0x405F529314F92CD5 + 2.32276469057162813669e+02, // 0x406D08D8D5A2DBD9 + 1.17679373287147100768e+02, // 0x405D6B7ADA1884A9 + 8.36463893371618283368e+00, // 0x4020BAB1F44E5192 ] fn pone(x: f64): f64 { - let mut p: *[6]f64 = nil - let mut q: *[5]f64 = nil - if x >= 8 { - p = &p1r8 - q = &p1s8 - } else if x >= 4.5454 { - p = &p1r5 - q = &p1s5 - } else if x >= 2.8571 { - p = &p1r3 - q = &p1s3 - } else if x >= 2 { - p = &p1r2 - q = &p1s2 - } - unsafe { - z := 1 / (x * x) - r := (*p)[0] + z * ((*p)[1] + z * ((*p)[2] + z * ((*p)[3] + z * ((*p)[4] + z * (*p)[5])))) - s := 1.0 + z * ((*q)[0] + z * ((*q)[1] + z * ((*q)[2] + z * ((*q)[3] + z * (*q)[4])))) - ret 1 + r / s - } + let mut p: *[6]f64 = nil + let mut q: *[5]f64 = nil + if x >= 8 { + p = &p1r8 + q = &p1s8 + } else if x >= 4.5454 { + p = &p1r5 + q = &p1s5 + } else if x >= 2.8571 { + p = &p1r3 + q = &p1s3 + } else if x >= 2 { + p = &p1r2 + q = &p1s2 + } + unsafe { + z := 1 / (x * x) + r := (*p)[0] + z * ((*p)[1] + z * ((*p)[2] + z * ((*p)[3] + z * ((*p)[4] + z * (*p)[5])))) + s := 1.0 + z * ((*q)[0] + z * ((*q)[1] + z * ((*q)[2] + z * ((*q)[3] + z * (*q)[4])))) + ret 1 + r / s + } } // For x >= 8, the asymptotic expansions of qone is @@ -360,96 +360,96 @@ fn pone(x: f64): f64 { // for x in [+inf, 8] = 1/[0,0.125] static q1r8: [6]f64 = [ - 0.00000000000000000000e+00, // 0x0000000000000000 - -1.02539062499992714161e-01, // 0xBFBA3FFFFFFFFDF3 - -1.62717534544589987888e+01, // 0xC0304591A26779F7 - -7.59601722513950107896e+02, // 0xC087BCD053E4B576 - -1.18498066702429587167e+04, // 0xC0C724E740F87415 - -4.84385124285750353010e+04, // 0xC0E7A6D065D09C6A + 0.00000000000000000000e+00, // 0x0000000000000000 + -1.02539062499992714161e-01, // 0xBFBA3FFFFFFFFDF3 + -1.62717534544589987888e+01, // 0xC0304591A26779F7 + -7.59601722513950107896e+02, // 0xC087BCD053E4B576 + -1.18498066702429587167e+04, // 0xC0C724E740F87415 + -4.84385124285750353010e+04, // 0xC0E7A6D065D09C6A ] static q1s8: [6]f64 = [ - 1.61395369700722909556e+02, // 0x40642CA6DE5BCDE5 - 7.82538599923348465381e+03, // 0x40BE9162D0D88419 - 1.33875336287249578163e+05, // 0x4100579AB0B75E98 - 7.19657723683240939863e+05, // 0x4125F65372869C19 - 6.66601232617776375264e+05, // 0x412457D27719AD5C - -2.94490264303834643215e+05, // 0xC111F9690EA5AA18 + 1.61395369700722909556e+02, // 0x40642CA6DE5BCDE5 + 7.82538599923348465381e+03, // 0x40BE9162D0D88419 + 1.33875336287249578163e+05, // 0x4100579AB0B75E98 + 7.19657723683240939863e+05, // 0x4125F65372869C19 + 6.66601232617776375264e+05, // 0x412457D27719AD5C + -2.94490264303834643215e+05, // 0xC111F9690EA5AA18 ] // for x in [8,4.5454] = 1/[0.125,0.22001] static q1r5: [6]f64 = [ - -2.08979931141764104297e-11, // 0xBDB6FA431AA1A098 - -1.02539050241375426231e-01, // 0xBFBA3FFFCB597FEF - -8.05644828123936029840e+00, // 0xC0201CE6CA03AD4B - -1.83669607474888380239e+02, // 0xC066F56D6CA7B9B0 - -1.37319376065508163265e+03, // 0xC09574C66931734F - -2.61244440453215656817e+03, // 0xC0A468E388FDA79D + -2.08979931141764104297e-11, // 0xBDB6FA431AA1A098 + -1.02539050241375426231e-01, // 0xBFBA3FFFCB597FEF + -8.05644828123936029840e+00, // 0xC0201CE6CA03AD4B + -1.83669607474888380239e+02, // 0xC066F56D6CA7B9B0 + -1.37319376065508163265e+03, // 0xC09574C66931734F + -2.61244440453215656817e+03, // 0xC0A468E388FDA79D ] static q1s5: [6]f64 = [ - 8.12765501384335777857e+01, // 0x405451B2FF5A11B2 - 1.99179873460485964642e+03, // 0x409F1F31E77BF839 - 1.74684851924908907677e+04, // 0x40D10F1F0D64CE29 - 4.98514270910352279316e+04, // 0x40E8576DAABAD197 - 2.79480751638918118260e+04, // 0x40DB4B04CF7C364B - -4.71918354795128470869e+03, // 0xC0B26F2EFCFFA004 + 8.12765501384335777857e+01, // 0x405451B2FF5A11B2 + 1.99179873460485964642e+03, // 0x409F1F31E77BF839 + 1.74684851924908907677e+04, // 0x40D10F1F0D64CE29 + 4.98514270910352279316e+04, // 0x40E8576DAABAD197 + 2.79480751638918118260e+04, // 0x40DB4B04CF7C364B + -4.71918354795128470869e+03, // 0xC0B26F2EFCFFA004 ] // for x in [4.5454,2.8571] = 1/[0.2199,0.35001] ??? static q1r3: [6]f64 = [ - -5.07831226461766561369e-09, // 0xBE35CFA9D38FC84F - -1.02537829820837089745e-01, // 0xBFBA3FEB51AEED54 - -4.61011581139473403113e+00, // 0xC01270C23302D9FF - -5.78472216562783643212e+01, // 0xC04CEC71C25D16DA - -2.28244540737631695038e+02, // 0xC06C87D34718D55F - -2.19210128478909325622e+02, // 0xC06B66B95F5C1BF6 + -5.07831226461766561369e-09, // 0xBE35CFA9D38FC84F + -1.02537829820837089745e-01, // 0xBFBA3FEB51AEED54 + -4.61011581139473403113e+00, // 0xC01270C23302D9FF + -5.78472216562783643212e+01, // 0xC04CEC71C25D16DA + -2.28244540737631695038e+02, // 0xC06C87D34718D55F + -2.19210128478909325622e+02, // 0xC06B66B95F5C1BF6 ] static q1s3: [6]f64 = [ - 4.76651550323729509273e+01, // 0x4047D523CCD367E4 - 6.73865112676699709482e+02, // 0x40850EEBC031EE3E - 3.38015286679526343505e+03, // 0x40AA684E448E7C9A - 5.54772909720722782367e+03, // 0x40B5ABBAA61D54A6 - 1.90311919338810798763e+03, // 0x409DBC7A0DD4DF4B - -1.35201191444307340817e+02, // 0xC060E670290A311F + 4.76651550323729509273e+01, // 0x4047D523CCD367E4 + 6.73865112676699709482e+02, // 0x40850EEBC031EE3E + 3.38015286679526343505e+03, // 0x40AA684E448E7C9A + 5.54772909720722782367e+03, // 0x40B5ABBAA61D54A6 + 1.90311919338810798763e+03, // 0x409DBC7A0DD4DF4B + -1.35201191444307340817e+02, // 0xC060E670290A311F ] // for x in [2.8570,2] = 1/[0.3499,0.5] static q1r2: [6]f64 = [ - -1.78381727510958865572e-07, // 0xBE87F12644C626D2 - -1.02517042607985553460e-01, // 0xBFBA3E8E9148B010 - -2.75220568278187460720e+00, // 0xC006048469BB4EDA - -1.96636162643703720221e+01, // 0xC033A9E2C168907F - -4.23253133372830490089e+01, // 0xC04529A3DE104AAA - -2.13719211703704061733e+01, // 0xC0355F3639CF6E52 + -1.78381727510958865572e-07, // 0xBE87F12644C626D2 + -1.02517042607985553460e-01, // 0xBFBA3E8E9148B010 + -2.75220568278187460720e+00, // 0xC006048469BB4EDA + -1.96636162643703720221e+01, // 0xC033A9E2C168907F + -4.23253133372830490089e+01, // 0xC04529A3DE104AAA + -2.13719211703704061733e+01, // 0xC0355F3639CF6E52 ] static q1s2: [6]f64 = [ - 2.95333629060523854548e+01, // 0x403D888A78AE64FF - 2.52981549982190529136e+02, // 0x406F9F68DB821CBA - 7.57502834868645436472e+02, // 0x4087AC05CE49A0F7 - 7.39393205320467245656e+02, // 0x40871B2548D4C029 - 1.55949003336666123687e+02, // 0x40637E5E3C3ED8D4 - -4.95949898822628210127e+00, // 0xC013D686E71BE86B + 2.95333629060523854548e+01, // 0x403D888A78AE64FF + 2.52981549982190529136e+02, // 0x406F9F68DB821CBA + 7.57502834868645436472e+02, // 0x4087AC05CE49A0F7 + 7.39393205320467245656e+02, // 0x40871B2548D4C029 + 1.55949003336666123687e+02, // 0x40637E5E3C3ED8D4 + -4.95949898822628210127e+00, // 0xC013D686E71BE86B ] fn qone(x: f64): f64 { - let mut p: *[6]f64 = nil - let mut q: *[6]f64 = nil - if x >= 8 { - p = &q1r8 - q = &q1s8 - } else if x >= 4.5454 { - p = &q1r5 - q = &q1s5 - } else if x >= 2.8571 { - p = &q1r3 - q = &q1s3 - } else if x >= 2 { - p = &q1r2 - q = &q1s2 - } - unsafe { - z := 1 / (x * x) - r := (*p)[0] + z * ((*p)[1] + z * ((*p)[2] + z * ((*p)[3] + z * ((*p)[4] + z * (*p)[5])))) - s := 1 + z * ((*q)[0] + z * ((*q)[1] + z * ((*q)[2] + z * ((*q)[3] + z * ((*q)[4] + z * (*q)[5]))))) - ret (0.375 + r / s) / x - } + let mut p: *[6]f64 = nil + let mut q: *[6]f64 = nil + if x >= 8 { + p = &q1r8 + q = &q1s8 + } else if x >= 4.5454 { + p = &q1r5 + q = &q1s5 + } else if x >= 2.8571 { + p = &q1r3 + q = &q1s3 + } else if x >= 2 { + p = &q1r2 + q = &q1s2 + } + unsafe { + z := 1 / (x * x) + r := (*p)[0] + z * ((*p)[1] + z * ((*p)[2] + z * ((*p)[3] + z * ((*p)[4] + z * (*p)[5])))) + s := 1 + z * ((*q)[0] + z * ((*q)[1] + z * ((*q)[2] + z * ((*q)[3] + z * ((*q)[4] + z * (*q)[5]))))) + ret (0.375 + r / s) / x + } } \ No newline at end of file diff --git a/std/math/jn.jule b/std/math/jn.jule index 5f87e04d2..dbb50bfd4 100644 --- a/std/math/jn.jule +++ b/std/math/jn.jule @@ -82,178 +82,178 @@ // Jn(n, ±Inf) = 0 // Jn(n, NaN) = NaN fn Jn(mut n: int, mut x: f64): f64 { - const twoM29 = 1.0 / (1 << 29) // 2**-29 0x3e10000000000000 - const two302 = 0x52D0000000000000 //1 << 302 // 2**302 0x52D0000000000000 - // special cases - match { - | IsNaN(x): - ret x - | IsInf(x, 0): - ret 0 - } - // J(-n, x) = (-1)**n * J(n, x), J(n, -x) = (-1)**n * J(n, x) - // Thus, J(-n, x) = J(n, -x) + const twoM29 = 1.0 / (1 << 29) // 2**-29 0x3e10000000000000 + const two302 = 0x52D0000000000000 //1 << 302 // 2**302 0x52D0000000000000 + // special cases + match { + | IsNaN(x): + ret x + | IsInf(x, 0): + ret 0 + } + // J(-n, x) = (-1)**n * J(n, x), J(n, -x) = (-1)**n * J(n, x) + // Thus, J(-n, x) = J(n, -x) - if n == 0 { - ret J0(x) - } - if x == 0 { - ret 0 - } - if n < 0 { - n, x = -n, -x - } - if n == 1 { - ret J1(x) - } - mut sign := false - if x < 0 { - x = -x - if n&1 == 1 { - sign = true // odd n and negative x - } - } - mut b := 0. - if f64(n) <= x { - // Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) - if x >= two302 { // x > 2**302 - // (x >> n**2) - // Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) - // Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) - // Let s=sin(x), c=cos(x), - // xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then - // - // n sin(xn)*sqt2 cos(xn)*sqt2 - // ---------------------------------- - // 0 s-c c+s - // 1 -s-c -c+s - // 2 -s+c -c-s - // 3 s+c c-s + if n == 0 { + ret J0(x) + } + if x == 0 { + ret 0 + } + if n < 0 { + n, x = -n, -x + } + if n == 1 { + ret J1(x) + } + mut sign := false + if x < 0 { + x = -x + if n&1 == 1 { + sign = true // odd n and negative x + } + } + mut b := 0. + if f64(n) <= x { + // Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) + if x >= two302 { // x > 2**302 + // (x >> n**2) + // Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) + // Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) + // Let s=sin(x), c=cos(x), + // xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then + // + // n sin(xn)*sqt2 cos(xn)*sqt2 + // ---------------------------------- + // 0 s-c c+s + // 1 -s-c -c+s + // 2 -s+c -c-s + // 3 s+c c-s - mut temp := 0. - s, c := Sincos(x) - match n & 3 { - | 0: - temp = c + s - | 1: - temp = -c + s - | 2: - temp = -c - s - | 3: - temp = c - s - } - b = (1 / SqrtPi) * temp / Sqrt(x) - } else { - b = J1(x) - mut i, mut a := 1, J0(x) - for i < n; i++ { - a, b = b, b * (f64(i + i) / x) - a // avoid underflow - } - } - } else { - if x < twoM29 { // x < 2**-29 - // x is tiny, return the first Taylor expansion of J(n,x) - // J(n,x) = 1/n!*(x/2)**n - ... + mut temp := 0. + s, c := Sincos(x) + match n & 3 { + | 0: + temp = c + s + | 1: + temp = -c + s + | 2: + temp = -c - s + | 3: + temp = c - s + } + b = (1 / SqrtPi) * temp / Sqrt(x) + } else { + b = J1(x) + mut i, mut a := 1, J0(x) + for i < n; i++ { + a, b = b, b * (f64(i + i) / x) - a // avoid underflow + } + } + } else { + if x < twoM29 { // x < 2**-29 + // x is tiny, return the first Taylor expansion of J(n,x) + // J(n,x) = 1/n!*(x/2)**n - ... - if n > 33 { // underflow - b = 0 - } else { - temp := x * 0.5 - b = temp - mut a := 1.0 - mut i := 2 - for i <= n; i++ { - a *= f64(i) // a = n! - b *= temp // b = (x/2)**n - } - b /= a - } - } else { - // use backward recurrence - // x x**2 x**2 - // J(n,x)/J(n-1,x) = ---- ------ ------ ..... - // 2n - 2(n+1) - 2(n+2) - // - // 1 1 1 - // (for large x) = ---- ------ ------ ..... - // 2n 2(n+1) 2(n+2) - // -- - ------ - ------ - - // x x x - // - // Let w = 2n/x and h=2/x, then the above quotient - // is equal to the continued fraction: - // 1 - // = ----------------------- - // 1 - // w - ----------------- - // 1 - // w+h - --------- - // w+2h - ... - // - // To determine how many terms needed, let - // Q(0) = w, Q(1) = w(w+h) - 1, - // Q(k) = (w+k*h)*Q(k-1) - Q(k-2), - // When Q(k) > 1e4 good for single - // When Q(k) > 1e9 good for double - // When Q(k) > 1e17 good for quadruple + if n > 33 { // underflow + b = 0 + } else { + temp := x * 0.5 + b = temp + mut a := 1.0 + mut i := 2 + for i <= n; i++ { + a *= f64(i) // a = n! + b *= temp // b = (x/2)**n + } + b /= a + } + } else { + // use backward recurrence + // x x**2 x**2 + // J(n,x)/J(n-1,x) = ---- ------ ------ ..... + // 2n - 2(n+1) - 2(n+2) + // + // 1 1 1 + // (for large x) = ---- ------ ------ ..... + // 2n 2(n+1) 2(n+2) + // -- - ------ - ------ - + // x x x + // + // Let w = 2n/x and h=2/x, then the above quotient + // is equal to the continued fraction: + // 1 + // = ----------------------- + // 1 + // w - ----------------- + // 1 + // w+h - --------- + // w+2h - ... + // + // To determine how many terms needed, let + // Q(0) = w, Q(1) = w(w+h) - 1, + // Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + // When Q(k) > 1e4 good for single + // When Q(k) > 1e9 good for double + // When Q(k) > 1e17 good for quadruple - // determine k - w := f64(n + n) / x - h := 2 / x - mut q0 := w - mut z := w + h - mut q1 := w * z - 1 - mut k := 1 - for q1 < 1e9 { - k++ - z += h - q0, q1 = q1, z * q1 - q0 - } - m := n + n - mut t := 0.0 - mut i := 2 * (n + k) - for i >= m; i -= 2 { - t = 1 / (f64(i) / x - t) - } - mut a := t - b = 1 - // estimate log((2/x)**n*n!) = n*log(2/x)+n*ln(n) - // Hence, if n*(log(2n/x)) > ... - // single 8.8722839355e+01 - // double 7.09782712893383973096e+02 - // long double 1.1356523406294143949491931077970765006170e+04 - // then recurrent value may overflow and the result is - // likely underflow to zero + // determine k + w := f64(n + n) / x + h := 2 / x + mut q0 := w + mut z := w + h + mut q1 := w * z - 1 + mut k := 1 + for q1 < 1e9 { + k++ + z += h + q0, q1 = q1, z * q1 - q0 + } + m := n + n + mut t := 0.0 + mut i := 2 * (n + k) + for i >= m; i -= 2 { + t = 1 / (f64(i) / x - t) + } + mut a := t + b = 1 + // estimate log((2/x)**n*n!) = n*log(2/x)+n*ln(n) + // Hence, if n*(log(2n/x)) > ... + // single 8.8722839355e+01 + // double 7.09782712893383973096e+02 + // long double 1.1356523406294143949491931077970765006170e+04 + // then recurrent value may overflow and the result is + // likely underflow to zero - mut tmp := f64(n) - v := 2 / x - tmp = tmp * Log(Abs(v * tmp)) - if tmp < 7.09782712893383973096e+02 { - i = n - 1 - for i > 0; i-- { - di := f64(i + i) - a, b = b, b * di / x - a - } - } else { - i = n - 1 - for i > 0; i-- { - di := f64(i + i) - a, b = b, b * di / x - a - // scale b to avoid spurious overflow - if b > 1e100 { - a /= b - t /= b - b = 1 - } - } - } - b = t * J0(x) / b - } - } - if sign { - ret -b - } - ret b + mut tmp := f64(n) + v := 2 / x + tmp = tmp * Log(Abs(v * tmp)) + if tmp < 7.09782712893383973096e+02 { + i = n - 1 + for i > 0; i-- { + di := f64(i + i) + a, b = b, b * di / x - a + } + } else { + i = n - 1 + for i > 0; i-- { + di := f64(i + i) + a, b = b, b * di / x - a + // scale b to avoid spurious overflow + if b > 1e100 { + a /= b + t /= b + b = 1 + } + } + } + b = t * J0(x) / b + } + } + if sign { + ret -b + } + ret b } // Returns the order-n Bessel function of the second kind. @@ -265,76 +265,76 @@ fn Jn(mut n: int, mut x: f64): f64 { // Yn(n, x < 0) = NaN // Yn(n, NaN) = NaN fn Yn(mut n: int, x: f64): f64 { - const two302 = 0x52D0000000000000 // 1 << 302 // 2**302 0x52D0000000000000 - // special cases - match { - | x < 0 | IsNaN(x): - ret NaN() - | IsInf(x, 1): - ret 0 - } + const two302 = 0x52D0000000000000 // 1 << 302 // 2**302 0x52D0000000000000 + // special cases + match { + | x < 0 | IsNaN(x): + ret NaN() + | IsInf(x, 1): + ret 0 + } - if n == 0 { - ret Y0(x) - } - if x == 0 { - if n < 0 && n&1 == 1 { - ret Inf(1) - } - ret Inf(-1) - } - mut sign := false - if n < 0 { - n = -n - if n&1 == 1 { - sign = true // sign true if n < 0 && |n| odd - } - } - if n == 1 { - if sign { - ret -Y1(x) - } - ret Y1(x) - } - mut b := 0. - if x >= two302 { // x > 2**302 - // (x >> n**2) - // Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) - // Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) - // Let s=sin(x), c=cos(x), - // xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then - // - // n sin(xn)*sqt2 cos(xn)*sqt2 - // ---------------------------------- - // 0 s-c c+s - // 1 -s-c -c+s - // 2 -s+c -c-s - // 3 s+c c-s + if n == 0 { + ret Y0(x) + } + if x == 0 { + if n < 0 && n&1 == 1 { + ret Inf(1) + } + ret Inf(-1) + } + mut sign := false + if n < 0 { + n = -n + if n&1 == 1 { + sign = true // sign true if n < 0 && |n| odd + } + } + if n == 1 { + if sign { + ret -Y1(x) + } + ret Y1(x) + } + mut b := 0. + if x >= two302 { // x > 2**302 + // (x >> n**2) + // Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) + // Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) + // Let s=sin(x), c=cos(x), + // xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then + // + // n sin(xn)*sqt2 cos(xn)*sqt2 + // ---------------------------------- + // 0 s-c c+s + // 1 -s-c -c+s + // 2 -s+c -c-s + // 3 s+c c-s - mut temp := 0. - s, c := Sincos(x) - match n & 3 { - | 0: - temp = s - c - | 1: - temp = -s - c - | 2: - temp = -s + c - | 3: - temp = s + c - } - b = (1 / SqrtPi) * temp / Sqrt(x) - } else { - mut a := Y0(x) - b = Y1(x) - // quit if b is -inf - mut i := 1 - for i < n && !IsInf(b, -1); i++ { - a, b = b, (f64(i + i) / x) * b - a - } - } - if sign { - ret -b - } - ret b + mut temp := 0. + s, c := Sincos(x) + match n & 3 { + | 0: + temp = s - c + | 1: + temp = -s - c + | 2: + temp = -s + c + | 3: + temp = s + c + } + b = (1 / SqrtPi) * temp / Sqrt(x) + } else { + mut a := Y0(x) + b = Y1(x) + // quit if b is -inf + mut i := 1 + for i < n && !IsInf(b, -1); i++ { + a, b = b, (f64(i + i) / x) * b - a + } + } + if sign { + ret -b + } + ret b } \ No newline at end of file diff --git a/std/math/ldexp.jule b/std/math/ldexp.jule index 1600e6979..721d17019 100644 --- a/std/math/ldexp.jule +++ b/std/math/ldexp.jule @@ -43,33 +43,33 @@ // Ldexp(±Inf, exp) = ±Inf // Ldexp(NaN, exp) = NaN fn Ldexp(mut frac: f64, mut exp: int): f64 { - // special cases - match { - | frac == 0: - ret frac // correctly return -0 - | IsInf(frac, 0) | IsNaN(frac): - ret frac - } - mut e := 0 - frac, e = normalize(frac) - exp += e - mut x := F64Bits(frac) - exp += int(x >> shift) & mask - bias - if exp < -1075 { - ret Copysign(0, frac) // underflow - } - if exp > 1023 { // overflow - if frac < 0 { - ret Inf(-1) - } - ret Inf(1) - } - mut m := 1. - if exp < -1022 { // denormal - exp += 53 - m = 1.0 / (1 << 53) // 2**-53 - } - x = x & ^(mask << shift) - x |= u64(exp + bias) << shift - ret m * F64FromBits(x) + // special cases + match { + | frac == 0: + ret frac // correctly return -0 + | IsInf(frac, 0) | IsNaN(frac): + ret frac + } + mut e := 0 + frac, e = normalize(frac) + exp += e + mut x := F64Bits(frac) + exp += int(x >> shift) & mask - bias + if exp < -1075 { + ret Copysign(0, frac) // underflow + } + if exp > 1023 { // overflow + if frac < 0 { + ret Inf(-1) + } + ret Inf(1) + } + mut m := 1. + if exp < -1022 { // denormal + exp += 53 + m = 1.0 / (1 << 53) // 2**-53 + } + x = x & ^(mask << shift) + x |= u64(exp + bias) << shift + ret m * F64FromBits(x) } \ No newline at end of file diff --git a/std/math/lgamma.jule b/std/math/lgamma.jule index 6ee2ff198..4cd357179 100644 --- a/std/math/lgamma.jule +++ b/std/math/lgamma.jule @@ -120,78 +120,78 @@ // static _LGAM_A: [...]f64 = [ - 7.72156649015328655494e-02, // 0x3FB3C467E37DB0C8 - 3.22467033424113591611e-01, // 0x3FD4A34CC4A60FAD - 6.73523010531292681824e-02, // 0x3FB13E001A5562A7 - 2.05808084325167332806e-02, // 0x3F951322AC92547B - 7.38555086081402883957e-03, // 0x3F7E404FB68FEFE8 - 2.89051383673415629091e-03, // 0x3F67ADD8CCB7926B - 1.19270763183362067845e-03, // 0x3F538A94116F3F5D - 5.10069792153511336608e-04, // 0x3F40B6C689B99C00 - 2.20862790713908385557e-04, // 0x3F2CF2ECED10E54D - 1.08011567247583939954e-04, // 0x3F1C5088987DFB07 - 2.52144565451257326939e-05, // 0x3EFA7074428CFA52 - 4.48640949618915160150e-05, // 0x3F07858E90A45837 + 7.72156649015328655494e-02, // 0x3FB3C467E37DB0C8 + 3.22467033424113591611e-01, // 0x3FD4A34CC4A60FAD + 6.73523010531292681824e-02, // 0x3FB13E001A5562A7 + 2.05808084325167332806e-02, // 0x3F951322AC92547B + 7.38555086081402883957e-03, // 0x3F7E404FB68FEFE8 + 2.89051383673415629091e-03, // 0x3F67ADD8CCB7926B + 1.19270763183362067845e-03, // 0x3F538A94116F3F5D + 5.10069792153511336608e-04, // 0x3F40B6C689B99C00 + 2.20862790713908385557e-04, // 0x3F2CF2ECED10E54D + 1.08011567247583939954e-04, // 0x3F1C5088987DFB07 + 2.52144565451257326939e-05, // 0x3EFA7074428CFA52 + 4.48640949618915160150e-05, // 0x3F07858E90A45837 ] static _LGAM_R: [...]f64 = [ - 1.0, // placeholder - 1.39200533467621045958e+00, // 0x3FF645A762C4AB74 - 7.21935547567138069525e-01, // 0x3FE71A1893D3DCDC - 1.71933865632803078993e-01, // 0x3FC601EDCCFBDF27 - 1.86459191715652901344e-02, // 0x3F9317EA742ED475 - 7.77942496381893596434e-04, // 0x3F497DDACA41A95B - 7.32668430744625636189e-06, // 0x3EDEBAF7A5B38140 + 1.0, // placeholder + 1.39200533467621045958e+00, // 0x3FF645A762C4AB74 + 7.21935547567138069525e-01, // 0x3FE71A1893D3DCDC + 1.71933865632803078993e-01, // 0x3FC601EDCCFBDF27 + 1.86459191715652901344e-02, // 0x3F9317EA742ED475 + 7.77942496381893596434e-04, // 0x3F497DDACA41A95B + 7.32668430744625636189e-06, // 0x3EDEBAF7A5B38140 ] static _LGAM_S: [...]f64 = [ - -7.72156649015328655494e-02, // 0xBFB3C467E37DB0C8 - 2.14982415960608852501e-01, // 0x3FCB848B36E20878 - 3.25778796408930981787e-01, // 0x3FD4D98F4F139F59 - 1.46350472652464452805e-01, // 0x3FC2BB9CBEE5F2F7 - 2.66422703033638609560e-02, // 0x3F9B481C7E939961 - 1.84028451407337715652e-03, // 0x3F5E26B67368F239 - 3.19475326584100867617e-05, // 0x3F00BFECDD17E945 + -7.72156649015328655494e-02, // 0xBFB3C467E37DB0C8 + 2.14982415960608852501e-01, // 0x3FCB848B36E20878 + 3.25778796408930981787e-01, // 0x3FD4D98F4F139F59 + 1.46350472652464452805e-01, // 0x3FC2BB9CBEE5F2F7 + 2.66422703033638609560e-02, // 0x3F9B481C7E939961 + 1.84028451407337715652e-03, // 0x3F5E26B67368F239 + 3.19475326584100867617e-05, // 0x3F00BFECDD17E945 ] static _LGAM_T: [...]f64 = [ - 4.83836122723810047042e-01, // 0x3FDEF72BC8EE38A2 - -1.47587722994593911752e-01, // 0xBFC2E4278DC6C509 - 6.46249402391333854778e-02, // 0x3FB08B4294D5419B - -3.27885410759859649565e-02, // 0xBFA0C9A8DF35B713 - 1.79706750811820387126e-02, // 0x3F9266E7970AF9EC - -1.03142241298341437450e-02, // 0xBF851F9FBA91EC6A - 6.10053870246291332635e-03, // 0x3F78FCE0E370E344 - -3.68452016781138256760e-03, // 0xBF6E2EFFB3E914D7 - 2.25964780900612472250e-03, // 0x3F6282D32E15C915 - -1.40346469989232843813e-03, // 0xBF56FE8EBF2D1AF1 - 8.81081882437654011382e-04, // 0x3F4CDF0CEF61A8E9 - -5.38595305356740546715e-04, // 0xBF41A6109C73E0EC - 3.15632070903625950361e-04, // 0x3F34AF6D6C0EBBF7 - -3.12754168375120860518e-04, // 0xBF347F24ECC38C38 - 3.35529192635519073543e-04, // 0x3F35FD3EE8C2D3F4 + 4.83836122723810047042e-01, // 0x3FDEF72BC8EE38A2 + -1.47587722994593911752e-01, // 0xBFC2E4278DC6C509 + 6.46249402391333854778e-02, // 0x3FB08B4294D5419B + -3.27885410759859649565e-02, // 0xBFA0C9A8DF35B713 + 1.79706750811820387126e-02, // 0x3F9266E7970AF9EC + -1.03142241298341437450e-02, // 0xBF851F9FBA91EC6A + 6.10053870246291332635e-03, // 0x3F78FCE0E370E344 + -3.68452016781138256760e-03, // 0xBF6E2EFFB3E914D7 + 2.25964780900612472250e-03, // 0x3F6282D32E15C915 + -1.40346469989232843813e-03, // 0xBF56FE8EBF2D1AF1 + 8.81081882437654011382e-04, // 0x3F4CDF0CEF61A8E9 + -5.38595305356740546715e-04, // 0xBF41A6109C73E0EC + 3.15632070903625950361e-04, // 0x3F34AF6D6C0EBBF7 + -3.12754168375120860518e-04, // 0xBF347F24ECC38C38 + 3.35529192635519073543e-04, // 0x3F35FD3EE8C2D3F4 ] static _LGAM_U: [...]f64 = [ - -7.72156649015328655494e-02, // 0xBFB3C467E37DB0C8 - 6.32827064025093366517e-01, // 0x3FE4401E8B005DFF - 1.45492250137234768737e+00, // 0x3FF7475CD119BD6F - 9.77717527963372745603e-01, // 0x3FEF497644EA8450 - 2.28963728064692451092e-01, // 0x3FCD4EAEF6010924 - 1.33810918536787660377e-02, // 0x3F8B678BBF2BAB09 + -7.72156649015328655494e-02, // 0xBFB3C467E37DB0C8 + 6.32827064025093366517e-01, // 0x3FE4401E8B005DFF + 1.45492250137234768737e+00, // 0x3FF7475CD119BD6F + 9.77717527963372745603e-01, // 0x3FEF497644EA8450 + 2.28963728064692451092e-01, // 0x3FCD4EAEF6010924 + 1.33810918536787660377e-02, // 0x3F8B678BBF2BAB09 ] static _LGAM_V: [...]f64 = [ - 1.0, - 2.45597793713041134822e+00, // 0x4003A5D7C2BD619C - 2.12848976379893395361e+00, // 0x40010725A42B18F5 - 7.69285150456672783825e-01, // 0x3FE89DFBE45050AF - 1.04222645593369134254e-01, // 0x3FBAAE55D6537C88 - 3.21709242282423911810e-03, // 0x3F6A5ABB57D0CF61 + 1.0, + 2.45597793713041134822e+00, // 0x4003A5D7C2BD619C + 2.12848976379893395361e+00, // 0x40010725A42B18F5 + 7.69285150456672783825e-01, // 0x3FE89DFBE45050AF + 1.04222645593369134254e-01, // 0x3FBAAE55D6537C88 + 3.21709242282423911810e-03, // 0x3F6A5ABB57D0CF61 ] static _LGAM_W: [...]f64 = [ - 4.18938533204672725052e-01, // 0x3FDACFE390C97D69 - 8.33333333333329678849e-02, // 0x3FB555555555553B - -2.77777777728775536470e-03, // 0xBF66C16C16B02E5C - 7.93650558643019558500e-04, // 0x3F4A019F98CF38B6 - -5.95187557450339963135e-04, // 0xBF4380CB8C0FE741 - 8.36339918996282139126e-04, // 0x3F4B67BA4CDAD5D1 - -1.63092934096575273989e-03, // 0xBF5AB89D0B9E43E4 + 4.18938533204672725052e-01, // 0x3FDACFE390C97D69 + 8.33333333333329678849e-02, // 0x3FB555555555553B + -2.77777777728775536470e-03, // 0xBF66C16C16B02E5C + 7.93650558643019558500e-04, // 0x3F4A019F98CF38B6 + -5.95187557450339963135e-04, // 0xBF4380CB8C0FE741 + 8.36339918996282139126e-04, // 0x3F4B67BA4CDAD5D1 + -1.63092934096575273989e-03, // 0xBF5AB89D0B9E43E4 ] // Returns the natural logarithm and sign (-1 or +1) of Gamma(x). @@ -203,192 +203,192 @@ static _LGAM_W: [...]f64 = [ // Lgamma(-Inf) = -Inf // Lgamma(NaN) = NaN fn Lgamma(mut x: f64): (lgamma: f64, sign: int) { - const YMIN = 1.461632144968362245 - const TWO52 = 1 << 52 // 0x4330000000000000 ~4.5036e+15 - const TWO58 = 1 << 58 // 0x4390000000000000 ~2.8823e+17 - const TINY = 8.47033e-22 // 1.0 / (1 << 70) // 0x3b90000000000000 ~8.47033e-22 - const TC = 1.46163214496836224576e+00 // 0x3FF762D86356BE3F - const TF = -1.21486290535849611461e-01 // 0xBFBF19B9BCC38A42 - // TT = -(tail of TF) - const TT = -3.63867699703950536541e-18 // 0xBC50C7CAA48A971F - // special cases - sign = 1 - match { - | IsNaN(x): - lgamma = x - ret - | IsInf(x, 0): - lgamma = x - ret - | x == 0: - lgamma = Inf(1) - ret - } + const YMIN = 1.461632144968362245 + const TWO52 = 1 << 52 // 0x4330000000000000 ~4.5036e+15 + const TWO58 = 1 << 58 // 0x4390000000000000 ~2.8823e+17 + const TINY = 8.47033e-22 // 1.0 / (1 << 70) // 0x3b90000000000000 ~8.47033e-22 + const TC = 1.46163214496836224576e+00 // 0x3FF762D86356BE3F + const TF = -1.21486290535849611461e-01 // 0xBFBF19B9BCC38A42 + // TT = -(tail of TF) + const TT = -3.63867699703950536541e-18 // 0xBC50C7CAA48A971F + // special cases + sign = 1 + match { + | IsNaN(x): + lgamma = x + ret + | IsInf(x, 0): + lgamma = x + ret + | x == 0: + lgamma = Inf(1) + ret + } - mut neg := false - if x < 0 { - x = -x - neg = true - } + mut neg := false + if x < 0 { + x = -x + neg = true + } - if x < TINY { // if |x| < 2**-70, ret -log(|x|) - if neg { - sign = -1 - } - lgamma = -Log(x) - ret - } - mut nadj := 0. - if neg { - if x >= TWO52 { // |x| >= 2**52, must be -integer - lgamma = Inf(1) - ret - } - t := sinPi(x) - if t == 0 { - lgamma = Inf(1) // -integer - ret - } - nadj = Log(Pi / Abs(t * x)) - if t < 0 { - sign = -1 - } - } + if x < TINY { // if |x| < 2**-70, ret -log(|x|) + if neg { + sign = -1 + } + lgamma = -Log(x) + ret + } + mut nadj := 0. + if neg { + if x >= TWO52 { // |x| >= 2**52, must be -integer + lgamma = Inf(1) + ret + } + t := sinPi(x) + if t == 0 { + lgamma = Inf(1) // -integer + ret + } + nadj = Log(Pi / Abs(t * x)) + if t < 0 { + sign = -1 + } + } - match { - | x == 1 | x == 2: // purge off 1 and 2 - lgamma = 0 - ret - | x < 2: // use lgamma(x) = lgamma(x+1) - log(x) - mut y := 0. - mut i := 0 - if x <= 0.9 { - lgamma = -Log(x) - match { - | x >= (YMIN - 1 + 0.27): // 0.7316 <= x <= 0.9 - y = 1 - x - i = 0 - | x >= (YMIN - 1 - 0.27): // 0.2316 <= x < 0.7316 - y = x - (TC - 1) - i = 1 - |: - // 0 < x < 0.2316 - y = x - i = 2 - } - } else { - lgamma = 0 - match { - | x >= (YMIN + 0.27): // 1.7316 <= x < 2 - y = 2 - x - i = 0 - | x >= (YMIN - 0.27): // 1.2316 <= x < 1.7316 - y = x - TC - i = 1 - |: - // 0.9 < x < 1.2316 - y = x - 1 - i = 2 - } - } - match i { - | 0: - z := y * y - p1 := _LGAM_A[0] + z * (_LGAM_A[2] + z * (_LGAM_A[4] + z * (_LGAM_A[6] + z * (_LGAM_A[8] + z * _LGAM_A[10])))) - p2 := z * (_LGAM_A[1] + z * (+_LGAM_A[3] + z * (_LGAM_A[5] + z * (_LGAM_A[7] + z * (_LGAM_A[9] + z * _LGAM_A[11]))))) - p := y * p1 + p2 - lgamma += (p - 0.5 * y) - | 1: - z := y * y - w := z * y - p1 := _LGAM_T[0] + w * (_LGAM_T[3] + w * (_LGAM_T[6] + w * (_LGAM_T[9] + w * _LGAM_T[12]))) // parallel comp - p2 := _LGAM_T[1] + w * (_LGAM_T[4] + w * (_LGAM_T[7] + w * (_LGAM_T[10] + w * _LGAM_T[13]))) - p3 := _LGAM_T[2] + w * (_LGAM_T[5] + w * (_LGAM_T[8] + w * (_LGAM_T[11] + w * _LGAM_T[14]))) - p := z * p1 - (TT - w * (p2 + y * p3)) - lgamma += (TF + p) - | 2: - p1 := y * (_LGAM_U[0] + y * (_LGAM_U[1] + y * (_LGAM_U[2] + y * (_LGAM_U[3] + y * (_LGAM_U[4] + y * _LGAM_U[5]))))) - p2 := 1 + y * (_LGAM_V[1] + y * (_LGAM_V[2] + y * (_LGAM_V[3] + y * (_LGAM_V[4] + y * _LGAM_V[5])))) - lgamma += (-0.5 * y + p1 / p2) - } - | x < 8: // 2 <= x < 8 - i := int(x) - y := x - f64(i) - p := y * (_LGAM_S[0] + y * (_LGAM_S[1] + y * (_LGAM_S[2] + y * (_LGAM_S[3] + y * (_LGAM_S[4] + y * (_LGAM_S[5] + y * _LGAM_S[6])))))) - q := 1 + y * (_LGAM_R[1] + y * (_LGAM_R[2] + y * (_LGAM_R[3] + y * (_LGAM_R[4] + y * (_LGAM_R[5] + y * _LGAM_R[6]))))) - lgamma = 0.5 * y + p / q - mut z := 1.0 // lgamma(1+s) = log(s) + lgamma(s) - match i { - | 7: - z *= (y + 6) - fall - | 6: - z *= (y + 5) - fall - | 5: - z *= (y + 4) - fall - | 4: - z *= (y + 3) - fall - | 3: - z *= (y + 2) - lgamma += Log(z) - } - | x < TWO58: // 8 <= x < 2**58 - t := Log(x) - z := 1 / x - y := z * z - w := _LGAM_W[0] + z * (_LGAM_W[1] + y * (_LGAM_W[2] + y * (_LGAM_W[3] + y * (_LGAM_W[4] + y * (_LGAM_W[5] + y * _LGAM_W[6]))))) - lgamma = (x - 0.5) * (t - 1) + w - |: - // 2**58 <= x <= inf - lgamma = x * (Log(x) - 1) - } - if neg { - lgamma = nadj - lgamma - } - ret + match { + | x == 1 | x == 2: // purge off 1 and 2 + lgamma = 0 + ret + | x < 2: // use lgamma(x) = lgamma(x+1) - log(x) + mut y := 0. + mut i := 0 + if x <= 0.9 { + lgamma = -Log(x) + match { + | x >= (YMIN - 1 + 0.27): // 0.7316 <= x <= 0.9 + y = 1 - x + i = 0 + | x >= (YMIN - 1 - 0.27): // 0.2316 <= x < 0.7316 + y = x - (TC - 1) + i = 1 + |: + // 0 < x < 0.2316 + y = x + i = 2 + } + } else { + lgamma = 0 + match { + | x >= (YMIN + 0.27): // 1.7316 <= x < 2 + y = 2 - x + i = 0 + | x >= (YMIN - 0.27): // 1.2316 <= x < 1.7316 + y = x - TC + i = 1 + |: + // 0.9 < x < 1.2316 + y = x - 1 + i = 2 + } + } + match i { + | 0: + z := y * y + p1 := _LGAM_A[0] + z * (_LGAM_A[2] + z * (_LGAM_A[4] + z * (_LGAM_A[6] + z * (_LGAM_A[8] + z * _LGAM_A[10])))) + p2 := z * (_LGAM_A[1] + z * (+_LGAM_A[3] + z * (_LGAM_A[5] + z * (_LGAM_A[7] + z * (_LGAM_A[9] + z * _LGAM_A[11]))))) + p := y * p1 + p2 + lgamma += (p - 0.5 * y) + | 1: + z := y * y + w := z * y + p1 := _LGAM_T[0] + w * (_LGAM_T[3] + w * (_LGAM_T[6] + w * (_LGAM_T[9] + w * _LGAM_T[12]))) // parallel comp + p2 := _LGAM_T[1] + w * (_LGAM_T[4] + w * (_LGAM_T[7] + w * (_LGAM_T[10] + w * _LGAM_T[13]))) + p3 := _LGAM_T[2] + w * (_LGAM_T[5] + w * (_LGAM_T[8] + w * (_LGAM_T[11] + w * _LGAM_T[14]))) + p := z * p1 - (TT - w * (p2 + y * p3)) + lgamma += (TF + p) + | 2: + p1 := y * (_LGAM_U[0] + y * (_LGAM_U[1] + y * (_LGAM_U[2] + y * (_LGAM_U[3] + y * (_LGAM_U[4] + y * _LGAM_U[5]))))) + p2 := 1 + y * (_LGAM_V[1] + y * (_LGAM_V[2] + y * (_LGAM_V[3] + y * (_LGAM_V[4] + y * _LGAM_V[5])))) + lgamma += (-0.5 * y + p1 / p2) + } + | x < 8: // 2 <= x < 8 + i := int(x) + y := x - f64(i) + p := y * (_LGAM_S[0] + y * (_LGAM_S[1] + y * (_LGAM_S[2] + y * (_LGAM_S[3] + y * (_LGAM_S[4] + y * (_LGAM_S[5] + y * _LGAM_S[6])))))) + q := 1 + y * (_LGAM_R[1] + y * (_LGAM_R[2] + y * (_LGAM_R[3] + y * (_LGAM_R[4] + y * (_LGAM_R[5] + y * _LGAM_R[6]))))) + lgamma = 0.5 * y + p / q + mut z := 1.0 // lgamma(1+s) = log(s) + lgamma(s) + match i { + | 7: + z *= (y + 6) + fall + | 6: + z *= (y + 5) + fall + | 5: + z *= (y + 4) + fall + | 4: + z *= (y + 3) + fall + | 3: + z *= (y + 2) + lgamma += Log(z) + } + | x < TWO58: // 8 <= x < 2**58 + t := Log(x) + z := 1 / x + y := z * z + w := _LGAM_W[0] + z * (_LGAM_W[1] + y * (_LGAM_W[2] + y * (_LGAM_W[3] + y * (_LGAM_W[4] + y * (_LGAM_W[5] + y * _LGAM_W[6]))))) + lgamma = (x - 0.5) * (t - 1) + w + |: + // 2**58 <= x <= inf + lgamma = x * (Log(x) - 1) + } + if neg { + lgamma = nadj - lgamma + } + ret } // Is a helper function for negative x fn sinPi(mut x: f64): f64 { - const Two52 = 1 << 52 // 0x4330000000000000 ~4.5036e+15 - const Two53 = 1 << 53 // 0x4340000000000000 ~9.0072e+15 - if x < 0.25 { - ret -Sin(Pi * x) - } + const Two52 = 1 << 52 // 0x4330000000000000 ~4.5036e+15 + const Two53 = 1 << 53 // 0x4340000000000000 ~9.0072e+15 + if x < 0.25 { + ret -Sin(Pi * x) + } - // argument reduction - mut z := Floor(x) - mut n := 0 - if z != x { // inexact - x = Mod(x, 2) - n = int(x * 4) - } else { - if x >= Two53 { // x must be even - x = 0 - n = 0 - } else { - if x < Two52 { - z = x + Two52 // exact - } - n = int(1 & F64Bits(z)) - x = f64(n) - n <<= 2 - } - } - match n { - | 0: - x = Sin(Pi * x) - | 1 | 2: - x = Cos(Pi * (0.5 - x)) - | 3 | 4: - x = Sin(Pi * (1 - x)) - | 5 | 6: - x = -Cos(Pi * (x - 1.5)) - |: - x = Sin(Pi * (x - 2)) - } - ret -x + // argument reduction + mut z := Floor(x) + mut n := 0 + if z != x { // inexact + x = Mod(x, 2) + n = int(x * 4) + } else { + if x >= Two53 { // x must be even + x = 0 + n = 0 + } else { + if x < Two52 { + z = x + Two52 // exact + } + n = int(1 & F64Bits(z)) + x = f64(n) + n <<= 2 + } + } + match n { + | 0: + x = Sin(Pi * x) + | 1 | 2: + x = Cos(Pi * (0.5 - x)) + | 3 | 4: + x = Sin(Pi * (1 - x)) + | 5 | 6: + x = -Cos(Pi * (x - 1.5)) + |: + x = Sin(Pi * (x - 2)) + } + ret -x } \ No newline at end of file diff --git a/std/math/log.jule b/std/math/log.jule index 400b60bd7..ea4e0314e 100644 --- a/std/math/log.jule +++ b/std/math/log.jule @@ -109,42 +109,42 @@ // Log(x < 0) = NaN // Log(NaN) = NaN fn Log(x: f64): f64 { - const LN2_HI = 6.93147180369123816490e-01 /* 3fe62e42 fee00000 */ - const LN2_LO = 1.90821492927058770002e-10 /* 3dea39ef 35793c76 */ - const L1 = 6.666666666666735130e-01 /* 3FE55555 55555593 */ - const L2 = 3.999999999940941908e-01 /* 3FD99999 9997FA04 */ - const L3 = 2.857142874366239149e-01 /* 3FD24924 94229359 */ - const L4 = 2.222219843214978396e-01 /* 3FCC71C5 1D8E78AF */ - const L5 = 1.818357216161805012e-01 /* 3FC74664 96CB03DE */ - const L6 = 1.531383769920937332e-01 /* 3FC39A09 D078C69F */ - const L7 = 1.479819860511658591e-01 /* 3FC2F112 DF3E5244 */ + const LN2_HI = 6.93147180369123816490e-01 /* 3fe62e42 fee00000 */ + const LN2_LO = 1.90821492927058770002e-10 /* 3dea39ef 35793c76 */ + const L1 = 6.666666666666735130e-01 /* 3FE55555 55555593 */ + const L2 = 3.999999999940941908e-01 /* 3FD99999 9997FA04 */ + const L3 = 2.857142874366239149e-01 /* 3FD24924 94229359 */ + const L4 = 2.222219843214978396e-01 /* 3FCC71C5 1D8E78AF */ + const L5 = 1.818357216161805012e-01 /* 3FC74664 96CB03DE */ + const L6 = 1.531383769920937332e-01 /* 3FC39A09 D078C69F */ + const L7 = 1.479819860511658591e-01 /* 3FC2F112 DF3E5244 */ - // special cases - match { - | IsNaN(x) | IsInf(x, 1): - ret x - | x < 0: - ret NaN() - | x == 0: - ret Inf(-1) - } + // special cases + match { + | IsNaN(x) | IsInf(x, 1): + ret x + | x < 0: + ret NaN() + | x == 0: + ret Inf(-1) + } - // reduce - mut f1, mut ki := Frexp(x) - if f1 < Sqrt2/2 { - f1 *= 2 - ki-- - } - f := f1 - 1 - k := f64(ki) + // reduce + mut f1, mut ki := Frexp(x) + if f1 < Sqrt2/2 { + f1 *= 2 + ki-- + } + f := f1 - 1 + k := f64(ki) - // compute - s := f / (2 + f) - s2 := s * s - s4 := s2 * s2 - t1 := s2 * (L1 + s4 * (L3 + s4 * (L5 + s4 * L7))) - t2 := s4 * (L2 + s4 * (L4 + s4 * L6)) - R := t1 + t2 - hfsq := 0.5 * f * f - ret k * LN2_HI - ((hfsq - (s * (hfsq + R) + k * LN2_LO)) - f) + // compute + s := f / (2 + f) + s2 := s * s + s4 := s2 * s2 + t1 := s2 * (L1 + s4 * (L3 + s4 * (L5 + s4 * L7))) + t2 := s4 * (L2 + s4 * (L4 + s4 * L6)) + R := t1 + t2 + hfsq := 0.5 * f * f + ret k * LN2_HI - ((hfsq - (s * (hfsq + R) + k * LN2_LO)) - f) } \ No newline at end of file diff --git a/std/math/log10.jule b/std/math/log10.jule index 2a6ed46f3..96c2fa3ec 100644 --- a/std/math/log10.jule +++ b/std/math/log10.jule @@ -42,11 +42,11 @@ fn Log10(x: f64): f64 { ret Log(x) * (1 / Ln10) } // Returns the binary logarithm of x. // The special cases are the same as for log. fn Log2(x: f64): f64 { - frac, exp := Frexp(x) - // Make sure exact powers of two give an exact answer. - // Don't depend on Log(0.5)*(1/LN2)+exp being exactly exp-1. - if frac == 0.5 { - ret f64(exp - 1) - } - ret Log(frac) * (1 / Ln2) + f64(exp) + frac, exp := Frexp(x) + // Make sure exact powers of two give an exact answer. + // Don't depend on Log(0.5)*(1/LN2)+exp being exactly exp-1. + if frac == 0.5 { + ret f64(exp - 1) + } + ret Log(frac) * (1 / Ln2) + f64(exp) } \ No newline at end of file diff --git a/std/math/log1p.jule b/std/math/log1p.jule index 2ddea75ba..13f76c35b 100644 --- a/std/math/log1p.jule +++ b/std/math/log1p.jule @@ -124,104 +124,104 @@ // Log1p(x < -1) = NaN // Log1p(NaN) = NaN fn Log1p(x: f64): f64 { - const Sqrt2m1 = 4.142135623730950488017e-01 // sqrt(2)-1 = 0x3fda827999fcef34 - const Sqrt2Halfm1 = -2.928932188134524755992e-01 // sqrt(2)/2-1 = 0xbfd2bec333018866 - const Small = 1.0 / (1 << 29) // 2**-29 = 0x3e20000000000000 - const Tiny = 1.0 / (1 << 54) // 2**-54 - const Two53 = 1 << 53 // 2**53 - const Ln2Hi = 6.93147180369123816490e-01 // 3fe62e42fee00000 - const Ln2Lo = 1.90821492927058770002e-10 // 3dea39ef35793c76 - const LP1 = 6.666666666666735130e-01 // 3FE5555555555593 - const LP2 = 3.999999999940941908e-01 // 3FD999999997FA04 - const LP3 = 2.857142874366239149e-01 // 3FD2492494229359 - const LP4 = 2.222219843214978396e-01 // 3FCC71C51D8E78AF - const LP5 = 1.818357216161805012e-01 // 3FC7466496CB03DE - const LP6 = 1.531383769920937332e-01 // 3FC39A09D078C69F - const LP7 = 1.479819860511658591e-01 // 3FC2F112DF3E5244 + const Sqrt2m1 = 4.142135623730950488017e-01 // sqrt(2)-1 = 0x3fda827999fcef34 + const Sqrt2Halfm1 = -2.928932188134524755992e-01 // sqrt(2)/2-1 = 0xbfd2bec333018866 + const Small = 1.0 / (1 << 29) // 2**-29 = 0x3e20000000000000 + const Tiny = 1.0 / (1 << 54) // 2**-54 + const Two53 = 1 << 53 // 2**53 + const Ln2Hi = 6.93147180369123816490e-01 // 3fe62e42fee00000 + const Ln2Lo = 1.90821492927058770002e-10 // 3dea39ef35793c76 + const LP1 = 6.666666666666735130e-01 // 3FE5555555555593 + const LP2 = 3.999999999940941908e-01 // 3FD999999997FA04 + const LP3 = 2.857142874366239149e-01 // 3FD2492494229359 + const LP4 = 2.222219843214978396e-01 // 3FCC71C51D8E78AF + const LP5 = 1.818357216161805012e-01 // 3FC7466496CB03DE + const LP6 = 1.531383769920937332e-01 // 3FC39A09D078C69F + const LP7 = 1.479819860511658591e-01 // 3FC2F112DF3E5244 - // special cases - match { - | x < -1 | IsNaN(x): // includes -inf - ret NaN() - | x == -1: - ret Inf(-1) - | IsInf(x, 1): - ret Inf(1) - } + // special cases + match { + | x < -1 | IsNaN(x): // includes -inf + ret NaN() + | x == -1: + ret Inf(-1) + | IsInf(x, 1): + ret Inf(1) + } - absx := Abs(x) + absx := Abs(x) - mut f := 0. - mut iu := u64(0) - mut k := 1 - if absx < Sqrt2m1 { // |x| < sqrt(2)-1 - if absx < Small { // |x| < 2**-29 - if absx < Tiny { // |x| < 2**-54 - ret x - } - ret x - x * x * 0.5 - } - if x > Sqrt2Halfm1 { // sqrt(2)/2-1 < x - // (sqrt(2)/2-1) < x < (sqrt(2)-1) - k = 0 - f = x - iu = 1 - } - } - mut c := 0. - if k != 0 { - mut u := 0. - if absx < Two53 { // 1<<53 - u = 1.0 + x - iu = F64Bits(u) - k = int((iu >> 52) - 1023) - // correction term - if k > 0 { - c = 1.0 - (u - x) - } else { - c = x - (u - 1.0) - } - c /= u - } else { - u = x - iu = F64Bits(u) - k = int((iu >> 52) - 1023) - c = 0 - } - iu &= 0x000fffffffffffff + mut f := 0. + mut iu := u64(0) + mut k := 1 + if absx < Sqrt2m1 { // |x| < sqrt(2)-1 + if absx < Small { // |x| < 2**-29 + if absx < Tiny { // |x| < 2**-54 + ret x + } + ret x - x * x * 0.5 + } + if x > Sqrt2Halfm1 { // sqrt(2)/2-1 < x + // (sqrt(2)/2-1) < x < (sqrt(2)-1) + k = 0 + f = x + iu = 1 + } + } + mut c := 0. + if k != 0 { + mut u := 0. + if absx < Two53 { // 1<<53 + u = 1.0 + x + iu = F64Bits(u) + k = int((iu >> 52) - 1023) + // correction term + if k > 0 { + c = 1.0 - (u - x) + } else { + c = x - (u - 1.0) + } + c /= u + } else { + u = x + iu = F64Bits(u) + k = int((iu >> 52) - 1023) + c = 0 + } + iu &= 0x000fffffffffffff - if iu < 0x0006a09e667f3bcd { // mantissa of sqrt(2) - u = F64FromBits(iu | 0x3ff0000000000000) // normalize u - } else { - k++ - u = F64FromBits(iu | 0x3fe0000000000000) // normalize u/2 - iu = (0x0010000000000000 - iu) >> 2 - } - f = u - 1.0 // sqrt(2)/2 < u < sqrt(2) - } - hfsq := 0.5 * f * f - mut s := 0. - mut R := 0. - mut z := 0. - if iu == 0 { // |f| < 2**-20 - if f == 0 { - if k == 0 { - ret 0 - } - c += f64(k) * Ln2Lo - ret f64(k) * Ln2Hi + c - } - R = hfsq * (1.0 - 0.66666666666666666 * f) // avoid division - if k == 0 { - ret f - R - } - ret f64(k) * Ln2Hi - ((R - (f64(k) * Ln2Lo + 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 { - ret f - (hfsq - s * (hfsq + R)) - } - ret f64(k) * Ln2Hi - ((hfsq - (s * (hfsq + R) + (f64(k) * Ln2Lo + c))) - f) + if iu < 0x0006a09e667f3bcd { // mantissa of sqrt(2) + u = F64FromBits(iu | 0x3ff0000000000000) // normalize u + } else { + k++ + u = F64FromBits(iu | 0x3fe0000000000000) // normalize u/2 + iu = (0x0010000000000000 - iu) >> 2 + } + f = u - 1.0 // sqrt(2)/2 < u < sqrt(2) + } + hfsq := 0.5 * f * f + mut s := 0. + mut R := 0. + mut z := 0. + if iu == 0 { // |f| < 2**-20 + if f == 0 { + if k == 0 { + ret 0 + } + c += f64(k) * Ln2Lo + ret f64(k) * Ln2Hi + c + } + R = hfsq * (1.0 - 0.66666666666666666 * f) // avoid division + if k == 0 { + ret f - R + } + ret f64(k) * Ln2Hi - ((R - (f64(k) * Ln2Lo + 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 { + ret f - (hfsq - s * (hfsq + R)) + } + ret f64(k) * Ln2Hi - ((hfsq - (s * (hfsq + R) + (f64(k) * Ln2Lo + c))) - f) } \ No newline at end of file diff --git a/std/math/logb.jule b/std/math/logb.jule index daadee417..e31b4e253 100644 --- a/std/math/logb.jule +++ b/std/math/logb.jule @@ -42,16 +42,16 @@ // Logb(0) = -Inf // Logb(NaN) = NaN fn Logb(x: f64): f64 { - // special cases - match { - | x == 0: - ret Inf(-1) - | IsInf(x, 0): - ret Inf(1) - | IsNaN(x): - ret x - } - ret f64(ilogb(x)) + // special cases + match { + | x == 0: + ret Inf(-1) + | IsInf(x, 0): + ret Inf(1) + | IsNaN(x): + ret x + } + ret f64(ilogb(x)) } // Returns the binary exponent of x as an integer. @@ -61,20 +61,20 @@ fn Logb(x: f64): f64 { // Ilogb(0) = i32.Min // Ilogb(NaN) = i32.Max fn Ilogb(x: f64): int { - // special cases - match { - | x == 0: - ret i32.Min - | IsNaN(x): - ret i32.Max - | IsInf(x, 0): - ret i32.Max - } - ret ilogb(x) + // special cases + match { + | x == 0: + ret i32.Min + | IsNaN(x): + ret i32.Max + | IsInf(x, 0): + ret i32.Max + } + ret ilogb(x) } // Returns the binary exponent of x. It assumes x is finite and non-zero. fn ilogb(mut x: f64): int { - x, exp := normalize(x) - ret int((F64Bits(x) >> shift) & mask) - bias + exp + x, exp := normalize(x) + ret int((F64Bits(x) >> shift) & mask) - bias + exp } \ No newline at end of file diff --git a/std/math/mod.jule b/std/math/mod.jule index 060f26193..9ec611ddf 100644 --- a/std/math/mod.jule +++ b/std/math/mod.jule @@ -50,26 +50,26 @@ // Mod(x, ±Inf) = x // Mod(x, NaN) = NaN fn Mod(x: f64, mut y: f64): f64 { - if y == 0 || IsInf(x, 0) || IsNaN(x) || IsNaN(y) { - ret NaN() - } - y = Abs(y) + if y == 0 || IsInf(x, 0) || IsNaN(x) || IsNaN(y) { + ret NaN() + } + y = Abs(y) - yfr, yexp := Frexp(y) - mut r := x - if x < 0 { - r = -x - } + yfr, yexp := Frexp(y) + mut r := x + if x < 0 { + r = -x + } - for r >= y { - rfr, mut rexp := Frexp(r) - if rfr < yfr { - rexp = rexp - 1 - } - r = r - Ldexp(y, rexp - yexp) - } - if x < 0 { - r = -r - } - ret r + for r >= y { + rfr, mut rexp := Frexp(r) + if rfr < yfr { + rexp = rexp - 1 + } + r = r - Ldexp(y, rexp - yexp) + } + if x < 0 { + r = -r + } + ret r } \ No newline at end of file diff --git a/std/math/modf.jule b/std/math/modf.jule index 7add65af1..1ea54c003 100644 --- a/std/math/modf.jule +++ b/std/math/modf.jule @@ -42,20 +42,20 @@ // Modf(±Inf) = ±Inf, NaN // Modf(NaN) = NaN, NaN fn Modf(f: f64): (integer: f64, frac: f64) { - const ModfMaxPowTwo = 4.503599627370496000e+15 - absF := Abs(f) - mut i := 0.0 - if absF > ModfMaxPowTwo { - i = f - } else { - i = absF + ModfMaxPowTwo - i -= ModfMaxPowTwo - for i > absF { - i-- - } - if f < 0.0 { - i = -i - } - } - ret i, f - i + const ModfMaxPowTwo = 4.503599627370496000e+15 + absF := Abs(f) + mut i := 0.0 + if absF > ModfMaxPowTwo { + i = f + } else { + i = absF + ModfMaxPowTwo + i -= ModfMaxPowTwo + for i > absF { + i-- + } + if f < 0.0 { + i = -i + } + } + ret i, f - i } \ No newline at end of file diff --git a/std/math/nextafter.jule b/std/math/nextafter.jule index 0a089ae9b..889458f2f 100644 --- a/std/math/nextafter.jule +++ b/std/math/nextafter.jule @@ -42,19 +42,19 @@ // NextAfter32(NaN, y) = NaN // NextAfter32(x, NaN) = NaN fn NextAfter32(x: f32, y: f32): (r: f32) { - match { - | IsNaN(f64(x)) | IsNaN(f64(y)): // special case - r = f32(NaN()) - | x == y: - r = x - | x == 0: - r = f32(Copysign(f64(F32FromBits(1)), f64(y))) - | (y > x) == (x > 0): - r = F32FromBits(F32Bits(x) + 1) - |: - r = F32FromBits(F32Bits(x) - 1) - } - ret + match { + | IsNaN(f64(x)) | IsNaN(f64(y)): // special case + r = f32(NaN()) + | x == y: + r = x + | x == 0: + r = f32(Copysign(f64(F32FromBits(1)), f64(y))) + | (y > x) == (x > 0): + r = F32FromBits(F32Bits(x) + 1) + |: + r = F32FromBits(F32Bits(x) - 1) + } + ret } // Returns the next representable f64 value after x towards y. @@ -64,17 +64,17 @@ fn NextAfter32(x: f32, y: f32): (r: f32) { // NextAfter(NaN, y) = NaN // NextAfter(x, NaN) = NaN fn NextAfter(x: f64, y: f64): (r: f64) { - match { - | IsNaN(x) | IsNaN(y): // special case - r = NaN() - | x == y: - r = x - | x == 0: - r = Copysign(F64FromBits(1), y) - | (y > x) == (x > 0): - r = F64FromBits(F64Bits(x) + 1) - |: - r = F64FromBits(F64Bits(x) - 1) - } - ret + match { + | IsNaN(x) | IsNaN(y): // special case + r = NaN() + | x == y: + r = x + | x == 0: + r = Copysign(F64FromBits(1), y) + | (y > x) == (x > 0): + r = F64FromBits(F64Bits(x) + 1) + |: + r = F64FromBits(F64Bits(x) - 1) + } + ret } \ No newline at end of file diff --git a/std/math/pow.jule b/std/math/pow.jule index b494b21c7..97e01ce61 100644 --- a/std/math/pow.jule +++ b/std/math/pow.jule @@ -62,120 +62,120 @@ // Pow(-Inf, y) = Pow(-0, -y) // Pow(x, y) = NaN for finite x < 0 and finite non-integer y fn Pow(x: f64, y: f64): f64 { - match { - | y == 0 | x == 1: - ret 1 - | y == 1: - ret x - | IsNaN(x) | IsNaN(y): - ret NaN() - | x == 0: - match { - | y < 0: - if isOddInt(y) { - ret Copysign(Inf(1), x) - } - ret Inf(1) - | y > 0: - if isOddInt(y) { - ret x - } - ret 0 - } - | IsInf(y, 0): - match { - | x == -1: - ret 1 - | (Abs(x) < 1) == IsInf(y, 1): - ret 0 - |: - ret Inf(1) - } - | IsInf(x, 0): - if IsInf(x, -1) { - ret Pow(1 / x, -y) // Pow(-0, -y) - } - match { - | y < 0: - ret 0 - | y > 0: - ret Inf(1) - } - | y == 0.5: - ret Sqrt(x) - | y == -0.5: - ret 1 / Sqrt(x) - } + match { + | y == 0 | x == 1: + ret 1 + | y == 1: + ret x + | IsNaN(x) | IsNaN(y): + ret NaN() + | x == 0: + match { + | y < 0: + if isOddInt(y) { + ret Copysign(Inf(1), x) + } + ret Inf(1) + | y > 0: + if isOddInt(y) { + ret x + } + ret 0 + } + | IsInf(y, 0): + match { + | x == -1: + ret 1 + | (Abs(x) < 1) == IsInf(y, 1): + ret 0 + |: + ret Inf(1) + } + | IsInf(x, 0): + if IsInf(x, -1) { + ret Pow(1 / x, -y) // Pow(-0, -y) + } + match { + | y < 0: + ret 0 + | y > 0: + ret Inf(1) + } + | y == 0.5: + ret Sqrt(x) + | y == -0.5: + ret 1 / Sqrt(x) + } - mut yi, mut yf := Modf(Abs(y)) - if yf != 0 && x < 0 { - ret NaN() - } - if yi >= 1<<63 { - // yi is a large even int that will lead to overflow (or underflow to 0) - // for all x except -1 (x == 1 was handled earlier) - match { - | x == -1: - ret 1 - | (Abs(x) < 1) == (y > 0): - ret 0 - |: - ret Inf(1) - } - } + mut yi, mut yf := Modf(Abs(y)) + if yf != 0 && x < 0 { + ret NaN() + } + if yi >= 1<<63 { + // yi is a large even int that will lead to overflow (or underflow to 0) + // for all x except -1 (x == 1 was handled earlier) + match { + | x == -1: + ret 1 + | (Abs(x) < 1) == (y > 0): + ret 0 + |: + ret Inf(1) + } + } - // ans = a1 * 2**ae (= 1 for now). - mut a1 := 1.0 - mut ae := 0 + // ans = a1 * 2**ae (= 1 for now). + mut a1 := 1.0 + mut ae := 0 - // ans *= x**yf - if yf != 0 { - if yf > 0.5 { - yf-- - yi++ - } - a1 = Exp(yf * Log(x)) - } + // ans *= x**yf + if yf != 0 { + if yf > 0.5 { + yf-- + yi++ + } + a1 = Exp(yf * Log(x)) + } - // ans *= x**yi - // by multiplying in successive squarings - // of x according to bits of yi. - // accumulate powers of two into exp. - mut x1, mut xe := Frexp(x) - mut i := i64(yi) - for i != 0; i >>= 1 { - if xe < -1<<12 || 1<<12 < xe { - // catch xe before it overflows the left shift below - // Since i !=0 it has at least one bit still set, so ae will accumulate xe - // on at least one more iteration, ae += xe is a lower bound on ae - // the lower bound on ae exceeds the size of a float64 exp - // so the final call to Ldexp will produce under/overflow (0/Inf) - ae += xe - break - } - if i&1 == 1 { - a1 *= x1 - ae += xe - } - x1 *= x1 - xe <<= 1 - if x1 < 0.5 { - x1 += x1 - xe-- - } - } + // ans *= x**yi + // by multiplying in successive squarings + // of x according to bits of yi. + // accumulate powers of two into exp. + mut x1, mut xe := Frexp(x) + mut i := i64(yi) + for i != 0; i >>= 1 { + if xe < -1<<12 || 1<<12 < xe { + // catch xe before it overflows the left shift below + // Since i !=0 it has at least one bit still set, so ae will accumulate xe + // on at least one more iteration, ae += xe is a lower bound on ae + // the lower bound on ae exceeds the size of a float64 exp + // so the final call to Ldexp will produce under/overflow (0/Inf) + ae += xe + break + } + if i&1 == 1 { + a1 *= x1 + ae += xe + } + x1 *= x1 + xe <<= 1 + if x1 < 0.5 { + x1 += x1 + xe-- + } + } - // ans = a1*2**ae - // if y < 0 { ans = 1 / ans } - // but in the opposite order - if y < 0 { - a1 = 1 / a1 - ae = -ae - } - ret Ldexp(a1, ae) + // ans = a1*2**ae + // if y < 0 { ans = 1 / ans } + // but in the opposite order + if y < 0 { + a1 = 1 / a1 + ae = -ae + } + ret Ldexp(a1, ae) } fn isOddInt(x: f64): bool { - xi, xf := Modf(x) - ret xf == 0 && i64(xi)&1 == 1 + xi, xf := Modf(x) + ret xf == 0 && i64(xi)&1 == 1 } \ No newline at end of file diff --git a/std/math/pow10.jule b/std/math/pow10.jule index e06d994e9..300de9c56 100644 --- a/std/math/pow10.jule +++ b/std/math/pow10.jule @@ -37,20 +37,20 @@ // Stores the pre-computed values 10**i for i < 32. static pow10tab: [...]f64 = [ - 1e00, 1e01, 1e02, 1e03, 1e04, 1e05, 1e06, 1e07, 1e08, 1e09, - 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, - 1e20, 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29, - 1e30, 1e31, + 1e00, 1e01, 1e02, 1e03, 1e04, 1e05, 1e06, 1e07, 1e08, 1e09, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, + 1e20, 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29, + 1e30, 1e31, ] // Stores the pre-computed value for 10**(i*32) at index i. static pow10postab32: [...]f64 = [ - 1e00, 1e32, 1e64, 1e96, 1e128, 1e160, 1e192, 1e224, 1e256, 1e288, + 1e00, 1e32, 1e64, 1e96, 1e128, 1e160, 1e192, 1e224, 1e256, 1e288, ] // Stores the pre-computed value for 10**(-i*32) at index i. static pow10negtab32: [...]f64 = [ - 1e-00, 1e-32, 1e-64, 1e-96, 1e-128, 1e-160, 1e-192, 1e-224, 1e-256, 1e-288, 1e-320, + 1e-00, 1e-32, 1e-64, 1e-96, 1e-128, 1e-160, 1e-192, 1e-224, 1e-256, 1e-288, 1e-320, ] // Returns 10**n, the base-10 exponential of n. @@ -59,19 +59,19 @@ static pow10negtab32: [...]f64 = [ // Pow10(n) = 0 for n < -323 // Pow10(n) = Inf for n > 308 fn Pow10(n: int): f64 { - if 0 <= n && n <= 308 { - ret pow10postab32[uint(n)/32] * pow10tab[uint(n)%32] - } + if 0 <= n && n <= 308 { + ret pow10postab32[uint(n)/32] * pow10tab[uint(n)%32] + } - if -323 <= n && n <= 0 { - ret pow10negtab32[uint(-n)/32] / pow10tab[uint(-n)%32] - } + if -323 <= n && n <= 0 { + ret pow10negtab32[uint(-n)/32] / pow10tab[uint(-n)%32] + } - // n < -323 || 308 < n - if n > 0 { - ret Inf(1) - } + // n < -323 || 308 < n + if n > 0 { + ret Inf(1) + } - // n < -323 - ret 0 + // n < -323 + ret 0 } \ No newline at end of file diff --git a/std/math/rand/rand.jule b/std/math/rand/rand.jule index 72f9ae1fb..2031a48c0 100644 --- a/std/math/rand/rand.jule +++ b/std/math/rand/rand.jule @@ -26,121 +26,121 @@ type Seed: u64 // // With this formula, randomness can be made in the [min, max) range. struct Rand { - mut seed: Seed + mut seed: Seed } impl Rand { - const seedMask = 1 << 63 - 1 + const seedMask = 1 << 63 - 1 - // Returns new PRNG for seed. - static fn New(seed: Seed): &Rand { - mut rand := new(Rand) - rand.setSeed(seed) - ret rand - } + // Returns new PRNG for seed. + static fn New(seed: Seed): &Rand { + mut rand := new(Rand) + rand.setSeed(seed) + ret rand + } } impl Rand { - // Sets seed. - fn setSeed(self, seed: Seed) { - self.seed = seed & Rand.seedMask - self.seed += self.seed * (seed >> (1 << 3)) - } + // Sets seed. + fn setSeed(self, seed: Seed) { + self.seed = seed & Rand.seedMask + self.seed += self.seed * (seed >> (1 << 3)) + } - // Processes, sets, and returns new seed. - fn snext(self): Seed { - const NextMask = 0x41C64E6D - self.setSeed((self.seed * NextMask + 0x3039) & Rand.seedMask) - ret self.seed - } + // Processes, sets, and returns new seed. + fn snext(self): Seed { + const NextMask = 0x41C64E6D + self.setSeed((self.seed * NextMask + 0x3039) & Rand.seedMask) + ret self.seed + } - // Returns a non-genative pseudo-random - // 63-bit signed integer as an 64-bit signed integer. - fn Next63(self): i64 { - const RngMax = 1 << 63 - const RngMask = RngMax - 1 - ret i64(self.snext() & RngMask) - } + // Returns a non-genative pseudo-random + // 63-bit signed integer as an 64-bit signed integer. + fn Next63(self): i64 { + const RngMax = 1 << 63 + const RngMask = RngMax - 1 + ret i64(self.snext() & RngMask) + } - // Returns a non-genative pseudo-random - // 31-bit signed integer as an 31-bit signed integer. - fn Next31(self): i32 { - ret i32(self.Next63() >> 32) - } + // Returns a non-genative pseudo-random + // 31-bit signed integer as an 31-bit signed integer. + fn Next31(self): i32 { + ret i32(self.Next63() >> 32) + } - // Returns a non-genative pseudo-random int. - fn Next(self): int { - u := uint(self.Next63()) - ret int(u << 1 >> 1) // clear sign bit if int == int32 - } + // Returns a non-genative pseudo-random int. + fn Next(self): int { + u := uint(self.Next63()) + ret int(u << 1 >> 1) // clear sign bit if int == int32 + } - // Returns a non-genative pseudo-random in [0, n) range - // 63-bit signed integer as an 64-bit signed integer. - // If n <= 0, it panics. - fn Nextn63(self, n: i64): i64 { - if n <= 0 { - panic("Rand.Nextn63: invalid argument") - } - if n&(n - 1) == 0 { - ret self.Next63() & (n - 1) - } - max := i64(1 << 63 - 1 - (1 << 63) % u64(n)) - mut v := self.Next63() - for v > max { - v = self.Next63() - } - ret v % n - } + // Returns a non-genative pseudo-random in [0, n) range + // 63-bit signed integer as an 64-bit signed integer. + // If n <= 0, it panics. + fn Nextn63(self, n: i64): i64 { + if n <= 0 { + panic("Rand.Nextn63: invalid argument") + } + if n&(n - 1) == 0 { + ret self.Next63() & (n - 1) + } + max := i64(1 << 63 - 1 - (1 << 63) % u64(n)) + mut v := self.Next63() + for v > max { + v = self.Next63() + } + ret v % n + } - // Returns a non-genative pseudo-random in [0, n) range - // 31-bit signed integer as an 31-bit signed integer. - // If n <= 0, it panics. - fn Nextn31(self, n: i32): i32 { - if n <= 0 { - panic("Rand.nextn31: invalid argument") - } - if n&(n - 1) == 0 { - ret self.Next31() & (n - 1) - } - max := i32(1 << 31 - 1 - (1 << 31) % u32(n)) - mut v := self.Next31() - for v > max { - v = self.Next31() - } - ret v % n - } + // Returns a non-genative pseudo-random in [0, n) range + // 31-bit signed integer as an 31-bit signed integer. + // If n <= 0, it panics. + fn Nextn31(self, n: i32): i32 { + if n <= 0 { + panic("Rand.nextn31: invalid argument") + } + if n&(n - 1) == 0 { + ret self.Next31() & (n - 1) + } + max := i32(1 << 31 - 1 - (1 << 31) % u32(n)) + mut v := self.Next31() + for v > max { + v = self.Next31() + } + ret v % n + } - // Returns a non-genative pseudo-random in [0, n) range as int. - // If n <= 0, it panics. - fn Nextn(self, n: int): int { - if n <= 0 { - panic("Rand.nextn: invalid argument") - } - if n <= 1<<31-1 { - ret int(self.Nextn31(i32(n))) - } - ret int(self.Nextn63(i64(n))) - } + // Returns a non-genative pseudo-random in [0, n) range as int. + // If n <= 0, it panics. + fn Nextn(self, n: int): int { + if n <= 0 { + panic("Rand.nextn: invalid argument") + } + if n <= 1<<31-1 { + ret int(self.Nextn31(i32(n))) + } + ret int(self.Nextn63(i64(n))) + } - // Returns a non-genative pseudo-random in [0.0, 1.0) range - // as f64 floating-point. - fn Fnext64(self): f64 { - sample: - f := f64(self.Next63()) / (1 << 63) - if f == 1 { - goto sample - } - ret f - } + // Returns a non-genative pseudo-random in [0.0, 1.0) range + // as f64 floating-point. + fn Fnext64(self): f64 { + sample: + f := f64(self.Next63()) / (1 << 63) + if f == 1 { + goto sample + } + ret f + } - // Returns a non-genative pseudo-random in [0.0, 1.0) range - // as f32 floating-point. - fn Fnext32(self): f32 { - sample: - f := f32(self.Fnext64()) - if f == 1 { - goto sample - } - ret f - } + // Returns a non-genative pseudo-random in [0.0, 1.0) range + // as f32 floating-point. + fn Fnext32(self): f32 { + sample: + f := f32(self.Fnext64()) + if f == 1 { + goto sample + } + ret f + } } \ No newline at end of file diff --git a/std/math/remainder.jule b/std/math/remainder.jule index 9d16ed2f4..fd6e88dac 100644 --- a/std/math/remainder.jule +++ b/std/math/remainder.jule @@ -66,52 +66,52 @@ // Remainder(x, ±Inf) = x // Remainder(x, NaN) = NaN fn Remainder(mut x: f64, mut y: f64): f64 { - const Tiny = 4.45014771701440276618e-308 // 0x0020000000000000 - const HalfMax = f64.Max / 2 + const Tiny = 4.45014771701440276618e-308 // 0x0020000000000000 + const HalfMax = f64.Max / 2 - // special cases - match { - | IsNaN(x) | IsNaN(y) | IsInf(x, 0) | y == 0: - ret NaN() - | IsInf(y, 0): - ret x - } - mut sign := false - if x < 0 { - x = -x - sign = true - } - if y < 0 { - y = -y - } - if x == y { - if sign { - zero := 0.0 - ret -zero - } - ret 0 - } - if y <= HalfMax { - x = Mod(x, y + y) // now x < 2y - } - if y < Tiny { - if x+x > y { - x -= y - if x+x >= y { - x -= y - } - } - } else { - yHalf := 0.5 * y - if x > yHalf { - x -= y - if x >= yHalf { - x -= y - } - } - } - if sign { - x = -x - } - ret x + // special cases + match { + | IsNaN(x) | IsNaN(y) | IsInf(x, 0) | y == 0: + ret NaN() + | IsInf(y, 0): + ret x + } + mut sign := false + if x < 0 { + x = -x + sign = true + } + if y < 0 { + y = -y + } + if x == y { + if sign { + zero := 0.0 + ret -zero + } + ret 0 + } + if y <= HalfMax { + x = Mod(x, y + y) // now x < 2y + } + if y < Tiny { + if x+x > y { + x -= y + if x+x >= y { + x -= y + } + } + } else { + yHalf := 0.5 * y + if x > yHalf { + x -= y + if x >= yHalf { + x -= y + } + } + } + if sign { + x = -x + } + ret x } \ No newline at end of file diff --git a/std/math/sin.jule b/std/math/sin.jule index e58f052a8..499409678 100644 --- a/std/math/sin.jule +++ b/std/math/sin.jule @@ -122,22 +122,22 @@ // sin coefficients static _SIN: [...]f64 = [ - 1.58962301576546568060e-10, // 0x3de5d8fd1fd19ccd - -2.50507477628578072866e-8, // 0xbe5ae5e5a9291f5d - 2.75573136213857245213e-6, // 0x3ec71de3567d48a1 - -1.98412698295895385996e-4, // 0xbf2a01a019bfdf03 - 8.33333333332211858878e-3, // 0x3f8111111110f7d0 - -1.66666666666666307295e-1, // 0xbfc5555555555548 + 1.58962301576546568060e-10, // 0x3de5d8fd1fd19ccd + -2.50507477628578072866e-8, // 0xbe5ae5e5a9291f5d + 2.75573136213857245213e-6, // 0x3ec71de3567d48a1 + -1.98412698295895385996e-4, // 0xbf2a01a019bfdf03 + 8.33333333332211858878e-3, // 0x3f8111111110f7d0 + -1.66666666666666307295e-1, // 0xbfc5555555555548 ] // cos coefficients static _COS: [...]f64 = [ - -1.13585365213876817300e-11, // 0xbda8fa49a0861a9b - 2.08757008419747316778e-9, // 0x3e21ee9d7b4e3f05 - -2.75573141792967388112e-7, // 0xbe927e4f7eac4bc6 - 2.48015872888517045348e-5, // 0x3efa01a019c844f5 - -1.38888888888730564116e-3, // 0xbf56c16c16c14f91 - 4.16666666666665929218e-2, // 0x3fa555555555554b + -1.13585365213876817300e-11, // 0xbda8fa49a0861a9b + 2.08757008419747316778e-9, // 0x3e21ee9d7b4e3f05 + -2.75573141792967388112e-7, // 0xbe927e4f7eac4bc6 + 2.48015872888517045348e-5, // 0x3efa01a019c844f5 + -1.38888888888730564116e-3, // 0xbf56c16c16c14f91 + 4.16666666666665929218e-2, // 0x3fa555555555554b ] // Returns the cosine of the radian argument x. @@ -146,54 +146,54 @@ static _COS: [...]f64 = [ // Cos(±Inf) = NaN // Cos(NaN) = NaN fn Cos(mut x: f64): f64 { - const PI4A = 7.85398125648498535156e-1 // 0x3fe921fb40000000, PI/4 split into three parts - const PI4B = 3.77489470793079817668e-8 // 0x3e64442d00000000, - const PI4C = 2.69515142907905952645e-15 // 0x3ce8469898cc5170, - // special cases - if IsNaN(x) || IsInf(x, 0) { - ret NaN() - } + const PI4A = 7.85398125648498535156e-1 // 0x3fe921fb40000000, PI/4 split into three parts + const PI4B = 3.77489470793079817668e-8 // 0x3e64442d00000000, + const PI4C = 2.69515142907905952645e-15 // 0x3ce8469898cc5170, + // special cases + if IsNaN(x) || IsInf(x, 0) { + ret NaN() + } - // make argument positive - mut sign := false - x = Abs(x) + // make argument positive + mut sign := false + x = Abs(x) - mut j := u64(0) - mut y := 0. - mut z := 0. - if x >= reduceThreshold { - j, z = trigReduce(x) - } else { - j = u64(x * (4 / Pi)) // integer part of x/(PI/4), as integer for tests on the phase angle - y = f64(j) // integer part of x/(PI/4), as float + mut j := u64(0) + mut y := 0. + mut z := 0. + if x >= reduceThreshold { + j, z = trigReduce(x) + } else { + j = u64(x * (4 / Pi)) // integer part of x/(PI/4), as integer for tests on the phase angle + y = f64(j) // integer part of x/(PI/4), as float - // map zeros to origin - if j&1 == 1 { - j++ - y++ - } - j &= 7 // octant modulo 2Pi radians (360 degrees) - z = ((x - y * PI4A) - y * PI4B) - y * PI4C // Extended precision modular arithmetic - } + // map zeros to origin + if j&1 == 1 { + j++ + y++ + } + j &= 7 // octant modulo 2Pi radians (360 degrees) + z = ((x - y * PI4A) - y * PI4B) - y * PI4C // Extended precision modular arithmetic + } - if j > 3 { - j -= 4 - sign = !sign - } - if j > 1 { - sign = !sign - } + if j > 3 { + j -= 4 + sign = !sign + } + if j > 1 { + sign = !sign + } - zz := z * z - if j == 1 || j == 2 { - y = z + z * zz * ((((((_SIN[0] * zz) + _SIN[1]) * zz + _SIN[2]) * zz + _SIN[3]) * zz + _SIN[4]) * zz + _SIN[5]) - } else { - y = 1.0 - 0.5 * zz + zz * zz * ((((((_COS[0] * zz) + _COS[1]) * zz + _COS[2]) * zz + _COS[3]) * zz + _COS[4]) * zz + _COS[5]) - } - if sign { - y = -y - } - ret y + zz := z * z + if j == 1 || j == 2 { + y = z + z * zz * ((((((_SIN[0] * zz) + _SIN[1]) * zz + _SIN[2]) * zz + _SIN[3]) * zz + _SIN[4]) * zz + _SIN[5]) + } else { + y = 1.0 - 0.5 * zz + zz * zz * ((((((_COS[0] * zz) + _COS[1]) * zz + _COS[2]) * zz + _COS[3]) * zz + _COS[4]) * zz + _COS[5]) + } + if sign { + y = -y + } + ret y } // Returns the sine of the radian argument x. @@ -203,54 +203,54 @@ fn Cos(mut x: f64): f64 { // Sin(±Inf) = NaN // Sin(NaN) = NaN fn Sin(mut x: f64): f64 { - const PI4A = 7.85398125648498535156e-1 // 0x3fe921fb40000000, PI/4 split into three parts - const PI4B = 3.77489470793079817668e-8 // 0x3e64442d00000000, - const PI4C = 2.69515142907905952645e-15 // 0x3ce8469898cc5170, - // special cases - match { - | x == 0 | IsNaN(x): - ret x // ret ±0 || NaN() - | IsInf(x, 0): - ret NaN() - } + const PI4A = 7.85398125648498535156e-1 // 0x3fe921fb40000000, PI/4 split into three parts + const PI4B = 3.77489470793079817668e-8 // 0x3e64442d00000000, + const PI4C = 2.69515142907905952645e-15 // 0x3ce8469898cc5170, + // special cases + match { + | x == 0 | IsNaN(x): + ret x // ret ±0 || NaN() + | IsInf(x, 0): + ret NaN() + } - // make argument positive but save the sign - mut sign := false - if x < 0 { - x = -x - sign = true - } + // make argument positive but save the sign + mut sign := false + if x < 0 { + x = -x + sign = true + } - mut j := u64(0) - mut y := 0. - mut z := 0. - if x >= reduceThreshold { - j, z = trigReduce(x) - } else { - j = u64(x * (4 / Pi)) // integer part of x/(PI/4), as integer for tests on the phase angle - y = f64(j) // integer part of x/(PI/4), as float + mut j := u64(0) + mut y := 0. + mut z := 0. + if x >= reduceThreshold { + j, z = trigReduce(x) + } else { + j = u64(x * (4 / Pi)) // integer part of x/(PI/4), as integer for tests on the phase angle + y = f64(j) // integer part of x/(PI/4), as float - // map zeros to origin - if j&1 == 1 { - j++ - y++ - } - j &= 7 // octant modulo 2Pi radians (360 degrees) - z = ((x - y * PI4A) - y * PI4B) - y * PI4C // Extended precision modular arithmetic - } - // reflect in x axis - if j > 3 { - sign = !sign - j -= 4 - } - zz := z * z - if j == 1 || j == 2 { - y = 1.0 - 0.5 * zz + zz * zz * ((((((_COS[0] * zz) + _COS[1]) * zz + _COS[2]) * zz + _COS[3]) * zz + _COS[4]) * zz + _COS[5]) - } else { - y = z + z * zz * ((((((_SIN[0] * zz) + _SIN[1]) * zz + _SIN[2]) * zz + _SIN[3]) * zz + _SIN[4]) * zz + _SIN[5]) - } - if sign { - y = -y - } - ret y + // map zeros to origin + if j&1 == 1 { + j++ + y++ + } + j &= 7 // octant modulo 2Pi radians (360 degrees) + z = ((x - y * PI4A) - y * PI4B) - y * PI4C // Extended precision modular arithmetic + } + // reflect in x axis + if j > 3 { + sign = !sign + j -= 4 + } + zz := z * z + if j == 1 || j == 2 { + y = 1.0 - 0.5 * zz + zz * zz * ((((((_COS[0] * zz) + _COS[1]) * zz + _COS[2]) * zz + _COS[3]) * zz + _COS[4]) * zz + _COS[5]) + } else { + y = z + z * zz * ((((((_SIN[0] * zz) + _SIN[1]) * zz + _SIN[2]) * zz + _SIN[3]) * zz + _SIN[4]) * zz + _SIN[5]) + } + if sign { + y = -y + } + ret y } \ No newline at end of file diff --git a/std/math/sincos.jule b/std/math/sincos.jule index cfd970f22..d5f0409ce 100644 --- a/std/math/sincos.jule +++ b/std/math/sincos.jule @@ -44,59 +44,59 @@ // Sincos(±Inf) = NaN, NaN // Sincos(NaN) = NaN, NaN fn Sincos(mut x: f64): (sin: f64, cos: f64) { - const PI4A = 7.85398125648498535156e-1 // 0x3fe921fb40000000, Pi/4 split into three parts - const PI4B = 3.77489470793079817668e-8 // 0x3e64442d00000000, - const PI4C = 2.69515142907905952645e-15 // 0x3ce8469898cc5170, - // special cases - match { - | x == 0: - ret x, 1 // ret ±0.0, 1.0 - | IsNaN(x) | IsInf(x, 0): - ret NaN(), NaN() - } + const PI4A = 7.85398125648498535156e-1 // 0x3fe921fb40000000, Pi/4 split into three parts + const PI4B = 3.77489470793079817668e-8 // 0x3e64442d00000000, + const PI4C = 2.69515142907905952645e-15 // 0x3ce8469898cc5170, + // special cases + match { + | x == 0: + ret x, 1 // ret ±0.0, 1.0 + | IsNaN(x) | IsInf(x, 0): + ret NaN(), NaN() + } - // make argument positive - mut sinSign, mut cosSign := false, false - if x < 0 { - x = -x - sinSign = true - } + // make argument positive + mut sinSign, mut cosSign := false, false + if x < 0 { + x = -x + sinSign = true + } - mut j := u64(0) - mut y := 0. - mut z := 0. - if x >= reduceThreshold { - j, z = trigReduce(x) - } else { - j = u64(x * (4 / Pi)) // integer part of x/(PI/4), as integer for tests on the phase angle - y = f64(j) // integer part of x/(PI/4), as float + mut j := u64(0) + mut y := 0. + mut z := 0. + if x >= reduceThreshold { + j, z = trigReduce(x) + } else { + j = u64(x * (4 / Pi)) // integer part of x/(PI/4), as integer for tests on the phase angle + y = f64(j) // integer part of x/(PI/4), as float - if j&1 == 1 { // map zeros to origin - j++ - y++ - } - j &= 7 // octant modulo 2Pi radians (360 degrees) - z = ((x - y * PI4A) - y * PI4B) - y * PI4C // Extended precision modular arithmetic - } - if j > 3 { // reflect in x axis - j -= 4 - sinSign, cosSign = !sinSign, !cosSign - } - if j > 1 { - cosSign = !cosSign - } + if j&1 == 1 { // map zeros to origin + j++ + y++ + } + j &= 7 // octant modulo 2Pi radians (360 degrees) + z = ((x - y * PI4A) - y * PI4B) - y * PI4C // Extended precision modular arithmetic + } + if j > 3 { // reflect in x axis + j -= 4 + sinSign, cosSign = !sinSign, !cosSign + } + if j > 1 { + cosSign = !cosSign + } - zz := z * z - cos = 1.0 - 0.5 * zz + zz * zz * ((((((_COS[0] * zz) + _COS[1]) * zz + _COS[2]) * zz + _COS[3]) * zz + _COS[4]) * zz + _COS[5]) - sin = z + z * zz * ((((((_SIN[0] * zz) + _SIN[1]) * zz + _SIN[2]) * zz + _SIN[3]) * zz + _SIN[4]) * zz + _SIN[5]) - if j == 1 || j == 2 { - sin, cos = cos, sin - } - if cosSign { - cos = -cos - } - if sinSign { - sin = -sin - } - ret + zz := z * z + cos = 1.0 - 0.5 * zz + zz * zz * ((((((_COS[0] * zz) + _COS[1]) * zz + _COS[2]) * zz + _COS[3]) * zz + _COS[4]) * zz + _COS[5]) + sin = z + z * zz * ((((((_SIN[0] * zz) + _SIN[1]) * zz + _SIN[2]) * zz + _SIN[3]) * zz + _SIN[4]) * zz + _SIN[5]) + if j == 1 || j == 2 { + sin, cos = cos, sin + } + if cosSign { + cos = -cos + } + if sinSign { + sin = -sin + } + ret } \ No newline at end of file diff --git a/std/math/sinh.jule b/std/math/sinh.jule index 3119f5182..6ce6053df 100644 --- a/std/math/sinh.jule +++ b/std/math/sinh.jule @@ -54,38 +54,38 @@ // Sinh(±Inf) = ±Inf // Sinh(NaN) = NaN fn Sinh(mut x: f64): f64 { - // The coefficients are #2029 from Hart & Cheney. (20.36D) - const P0 = -0.6307673640497716991184787251e+6 - const P1 = -0.8991272022039509355398013511e+5 - const P2 = -0.2894211355989563807284660366e+4 - const P3 = -0.2630563213397497062819489e+2 - const Q0 = -0.6307673640497716991212077277e+6 - const Q1 = 0.1521517378790019070696485176e+5 - const Q2 = -0.173678953558233699533450911e+3 + // The coefficients are #2029 from Hart & Cheney. (20.36D) + const P0 = -0.6307673640497716991184787251e+6 + const P1 = -0.8991272022039509355398013511e+5 + const P2 = -0.2894211355989563807284660366e+4 + const P3 = -0.2630563213397497062819489e+2 + const Q0 = -0.6307673640497716991212077277e+6 + const Q1 = 0.1521517378790019070696485176e+5 + const Q2 = -0.173678953558233699533450911e+3 - mut sign := false - if x < 0 { - x = -x - sign = true - } + mut sign := false + if x < 0 { + x = -x + sign = true + } - mut temp := 0. - match { - | x > 21: - temp = Exp(x) * 0.5 - | x > 0.5: - ex := Exp(x) - temp = (ex - 1 / ex) * 0.5 - |: - sq := x * x - temp = (((P3 * sq + P2) * sq + P1) * sq + P0) * x - temp = temp / (((sq + Q2) * sq + Q1) * sq + Q0) - } + mut temp := 0. + match { + | x > 21: + temp = Exp(x) * 0.5 + | x > 0.5: + ex := Exp(x) + temp = (ex - 1 / ex) * 0.5 + |: + sq := x * x + temp = (((P3 * sq + P2) * sq + P1) * sq + P0) * x + temp = temp / (((sq + Q2) * sq + Q1) * sq + Q0) + } - if sign { - temp = -temp - } - ret temp + if sign { + temp = -temp + } + ret temp } // Returns the hyperbolic cosine of x. @@ -95,10 +95,10 @@ fn Sinh(mut x: f64): f64 { // Cosh(±Inf) = +Inf // Cosh(NaN) = NaN fn Cosh(mut x: f64): f64 { - x = Abs(x) - if x > 21 { - ret Exp(x) * 0.5 - } - ex := Exp(x) - ret (ex + 1 / ex) * 0.5 + x = Abs(x) + if x > 21 { + ret Exp(x) * 0.5 + } + ex := Exp(x) + ret (ex + 1 / ex) * 0.5 } \ No newline at end of file diff --git a/std/math/sqrt.jule b/std/math/sqrt.jule index 8950f0077..18ec09635 100644 --- a/std/math/sqrt.jule +++ b/std/math/sqrt.jule @@ -121,49 +121,49 @@ // Sqrt(x < 0) = NaN // Sqrt(NaN) = NaN fn Sqrt(x: f64): f64 { - // special cases - match { - | x == 0 | IsNaN(x) | IsInf(x, 1): - ret x - | x < 0: - ret NaN() - } - mut ix := F64Bits(x) - // normalize x - mut exp := int((ix >> shift) & mask) - if exp == 0 { // subnormal x - for ix&(1 << shift) == 0 { - ix <<= 1 - exp-- - } - exp++ - } - exp -= bias // unbias exponent - ix = ix & ^(mask << shift) - ix |= 1 << shift - if exp&1 == 1 { // odd exp, double x to make it even - ix <<= 1 - } - exp >>= 1 // exp = exp/2, exponent of square root - // generate sqrt(x) bit by bit - ix <<= 1 - mut q := u64(0) // q = sqrt(x) - mut s := u64(0) - mut r := u64(1 << (shift + 1)) // r = moving bit from MSB to LSB - for r != 0 { - t := s + r - if t <= ix { - s = t + r - ix -= t - q += r - } - ix <<= 1 - r >>= 1 - } - // final rounding - if ix != 0 { // remainder, result not exact - q += q & 1 // round according to extra bit - } - ix = q >> 1 + u64(exp - 1 + bias) << shift // significand + biased exponent - ret F64FromBits(ix) + // special cases + match { + | x == 0 | IsNaN(x) | IsInf(x, 1): + ret x + | x < 0: + ret NaN() + } + mut ix := F64Bits(x) + // normalize x + mut exp := int((ix >> shift) & mask) + if exp == 0 { // subnormal x + for ix&(1 << shift) == 0 { + ix <<= 1 + exp-- + } + exp++ + } + exp -= bias // unbias exponent + ix = ix & ^(mask << shift) + ix |= 1 << shift + if exp&1 == 1 { // odd exp, double x to make it even + ix <<= 1 + } + exp >>= 1 // exp = exp/2, exponent of square root + // generate sqrt(x) bit by bit + ix <<= 1 + mut q := u64(0) // q = sqrt(x) + mut s := u64(0) + mut r := u64(1 << (shift + 1)) // r = moving bit from MSB to LSB + for r != 0 { + t := s + r + if t <= ix { + s = t + r + ix -= t + q += r + } + ix <<= 1 + r >>= 1 + } + // final rounding + if ix != 0 { // remainder, result not exact + q += q & 1 // round according to extra bit + } + ix = q >> 1 + u64(exp - 1 + bias) << shift // significand + biased exponent + ret F64FromBits(ix) } \ No newline at end of file diff --git a/std/math/tan.jule b/std/math/tan.jule index f000284cd..e286541ab 100644 --- a/std/math/tan.jule +++ b/std/math/tan.jule @@ -92,16 +92,16 @@ // tan coefficients static _TAN_P: [...]f64 = [ - -1.30936939181383777646e4, // 0xc0c992d8d24f3f38 - 1.15351664838587416140e6, // 0x413199eca5fc9ddd - -1.79565251976484877988e7, // 0xc1711fead3299176 + -1.30936939181383777646e4, // 0xc0c992d8d24f3f38 + 1.15351664838587416140e6, // 0x413199eca5fc9ddd + -1.79565251976484877988e7, // 0xc1711fead3299176 ] static _TAN_Q: [...]f64 = [ - 1.00000000000000000000e0, - 1.36812963470692954678e4, // 0x40cab8a5eeb36572 - -1.32089234440210967447e6, // 0xc13427bc582abc96 - 2.50083801823357915839e7, // 0x4177d98fc2ead8ef - -5.38695755929454629881e7, // 0xc189afe03cbe5a31 + 1.00000000000000000000e0, + 1.36812963470692954678e4, // 0x40cab8a5eeb36572 + -1.32089234440210967447e6, // 0xc13427bc582abc96 + 2.50083801823357915839e7, // 0x4177d98fc2ead8ef + -5.38695755929454629881e7, // 0xc189afe03cbe5a31 ] // Returns the tangent of the radian argument x. @@ -111,52 +111,52 @@ static _TAN_Q: [...]f64 = [ // Tan(±Inf) = NaN // Tan(NaN) = NaN fn Tan(mut x: f64): f64 { - const PI4A = 7.85398125648498535156e-1 // 0x3fe921fb40000000, PI/4 split into three parts - const PI4B = 3.77489470793079817668e-8 // 0x3e64442d00000000, - const PI4C = 2.69515142907905952645e-15 // 0x3ce8469898cc5170, - // special cases - match { - | x == 0 | IsNaN(x): - ret x // ret ±0 || NaN() - | IsInf(x, 0): - ret NaN() - } + const PI4A = 7.85398125648498535156e-1 // 0x3fe921fb40000000, PI/4 split into three parts + const PI4B = 3.77489470793079817668e-8 // 0x3e64442d00000000, + const PI4C = 2.69515142907905952645e-15 // 0x3ce8469898cc5170, + // special cases + match { + | x == 0 | IsNaN(x): + ret x // ret ±0 || NaN() + | IsInf(x, 0): + ret NaN() + } - // make argument positive but save the sign - mut sign := false - if x < 0 { - x = -x - sign = true - } - mut j := u64(0) - mut y := 0. - mut z := 0. - if x >= reduceThreshold { - j, z = trigReduce(x) - } else { - j = u64(x * (4 / Pi)) // integer part of x/(PI/4), as integer for tests on the phase angle - y = f64(j) // integer part of x/(PI/4), as float + // make argument positive but save the sign + mut sign := false + if x < 0 { + x = -x + sign = true + } + mut j := u64(0) + mut y := 0. + mut z := 0. + if x >= reduceThreshold { + j, z = trigReduce(x) + } else { + j = u64(x * (4 / Pi)) // integer part of x/(PI/4), as integer for tests on the phase angle + y = f64(j) // integer part of x/(PI/4), as float - /* map zeros and singularities to origin */ - if j&1 == 1 { - j++ - y++ - } + /* map zeros and singularities to origin */ + if j&1 == 1 { + j++ + y++ + } - z = ((x - y * PI4A) - y * PI4B) - y * PI4C - } - zz := z * z + z = ((x - y * PI4A) - y * PI4B) - y * PI4C + } + zz := z * z - if zz > 1e-14 { - y = z + z * (zz * (((_TAN_P[0] * zz) + _TAN_P[1]) * zz + _TAN_P[2]) / ((((zz + _TAN_Q[1]) * zz + _TAN_Q[2]) * zz + _TAN_Q[3]) * zz + _TAN_Q[4])) - } else { - y = z - } - if j&2 == 2 { - y = -1 / y - } - if sign { - y = -y - } - ret y + if zz > 1e-14 { + y = z + z * (zz * (((_TAN_P[0] * zz) + _TAN_P[1]) * zz + _TAN_P[2]) / ((((zz + _TAN_Q[1]) * zz + _TAN_Q[2]) * zz + _TAN_Q[3]) * zz + _TAN_Q[4])) + } else { + y = z + } + if j&2 == 2 { + y = -1 / y + } + if sign { + y = -y + } + ret y } \ No newline at end of file diff --git a/std/math/tanh.jule b/std/math/tanh.jule index 649b1ac59..b5455b02d 100644 --- a/std/math/tanh.jule +++ b/std/math/tanh.jule @@ -86,15 +86,15 @@ // static tanhp: [...]f64 = [ - -9.64399179425052238628e-1, - -9.92877231001918586564e1, - -1.61468768441708447952e3, + -9.64399179425052238628e-1, + -9.92877231001918586564e1, + -1.61468768441708447952e3, ] static tanhq: [...]f64 = [ - 1.12811678491632931402e2, - 2.23548839060100448583e3, - 4.84406305325125486048e3, + 1.12811678491632931402e2, + 2.23548839060100448583e3, + 4.84406305325125486048e3, ] // Returns the hyperbolic tangent of x. @@ -104,26 +104,26 @@ static tanhq: [...]f64 = [ // Tanh(±Inf) = ±1 // Tanh(NaN) = NaN fn Tanh(x: f64): f64 { - const majulelog = 8.8029691931113054295988e+01 // log(2**127) - mut z := Abs(x) - match { - | z > 0.5*majulelog: - if x < 0 { - ret -1 - } - ret 1 - | z >= 0.625: - s := Exp(2 * z) - z = 1 - 2 / (s + 1) - if x < 0 { - z = -z - } - |: - if x == 0 { - ret x - } - s := x * x - z = x + x * s * ((tanhp[0] * s + tanhp[1]) * s + tanhp[2]) / (((s + tanhq[0]) * s + tanhq[1]) * s + tanhq[2]) - } - ret z + const majulelog = 8.8029691931113054295988e+01 // log(2**127) + mut z := Abs(x) + match { + | z > 0.5*majulelog: + if x < 0 { + ret -1 + } + ret 1 + | z >= 0.625: + s := Exp(2 * z) + z = 1 - 2 / (s + 1) + if x < 0 { + z = -z + } + |: + if x == 0 { + ret x + } + s := x * x + z = x + x * s * ((tanhp[0] * s + tanhp[1]) * s + tanhp[2]) / (((s + tanhq[0]) * s + tanhq[1]) * s + tanhq[2]) + } + ret z } \ No newline at end of file diff --git a/std/math/trig_reduce.jule b/std/math/trig_reduce.jule index ec2a17200..f26be10a1 100644 --- a/std/math/trig_reduce.jule +++ b/std/math/trig_reduce.jule @@ -58,49 +58,49 @@ const reduceThreshold = 1 << 29 // K. C. Ng et al, March 24, 1992 // The simulated multi-precision calculation of x*B uses 64-bit integer arithmetic. fn trigReduce(mut x: f64): (j: u64, z: f64) { - const PI4 = Pi / 4 - if x < PI4 { - ret 0, x - } - // Extract out the integer and exponent such that, - // x = ix * 2 ** exp. - mut ix := F64Bits(x) - exp := int(ix >> shift & mask) - bias - shift - ix = ix & ^(mask << shift) - ix |= 1 << shift - // Use the exponent to extract the 3 appropriate uint64 digits from M_PI4, - // B ~ (z0, z1, z2), such that the product leading digit has the exponent -61. - // Note, exp >= -53 since x >= PI4 and exp < 971 for maximum f64. - digit, bitshift := uint(exp + 61) / 64, uint(exp + 61) % 64 - z0 := (M_PI4[digit] << bitshift) | (M_PI4[digit+1] >> (64 - bitshift)) - z1 := (M_PI4[digit+1] << bitshift) | (M_PI4[digit+2] >> (64 - bitshift)) - z2 := (M_PI4[digit+2] << bitshift) | (M_PI4[digit+3] >> (64 - bitshift)) - // Multiply mantissa by the digits and extract the upper two digits (hi, lo). - z2hi, _ := bits::Mul64(z2, ix) - z1hi, z1lo := bits::Mul64(z1, ix) - z0lo := z0 * ix - lo, c := bits::Add64(z1lo, z2hi, 0) - mut hi, _ := bits::Add64(z0lo, z1hi, c) - // The top 3 bits are j. - j = hi >> 61 - // Extract the fraction and find its magnitude. - hi = hi << 3 | lo >> 61 - lz := uint(bits::LeadingZeros64(hi)) - e := u64(bias - (lz + 1)) - // Clear implicit mantissa bit and shift into place. - hi = (hi << (lz + 1)) | (lo >> (64 - (lz + 1))) - hi >>= 64 - shift - // Include the exponent and convert to a float. - hi |= e << shift - z = F64FromBits(hi) - // Map zeros to origin. - if j&1 == 1 { - j++ - j &= 7 - z-- - } - // Multiply the fractional part by pi/4. - ret j, z * PI4 + const PI4 = Pi / 4 + if x < PI4 { + ret 0, x + } + // Extract out the integer and exponent such that, + // x = ix * 2 ** exp. + mut ix := F64Bits(x) + exp := int(ix >> shift & mask) - bias - shift + ix = ix & ^(mask << shift) + ix |= 1 << shift + // Use the exponent to extract the 3 appropriate uint64 digits from M_PI4, + // B ~ (z0, z1, z2), such that the product leading digit has the exponent -61. + // Note, exp >= -53 since x >= PI4 and exp < 971 for maximum f64. + digit, bitshift := uint(exp + 61) / 64, uint(exp + 61) % 64 + z0 := (M_PI4[digit] << bitshift) | (M_PI4[digit+1] >> (64 - bitshift)) + z1 := (M_PI4[digit+1] << bitshift) | (M_PI4[digit+2] >> (64 - bitshift)) + z2 := (M_PI4[digit+2] << bitshift) | (M_PI4[digit+3] >> (64 - bitshift)) + // Multiply mantissa by the digits and extract the upper two digits (hi, lo). + z2hi, _ := bits::Mul64(z2, ix) + z1hi, z1lo := bits::Mul64(z1, ix) + z0lo := z0 * ix + lo, c := bits::Add64(z1lo, z2hi, 0) + mut hi, _ := bits::Add64(z0lo, z1hi, c) + // The top 3 bits are j. + j = hi >> 61 + // Extract the fraction and find its magnitude. + hi = hi << 3 | lo >> 61 + lz := uint(bits::LeadingZeros64(hi)) + e := u64(bias - (lz + 1)) + // Clear implicit mantissa bit and shift into place. + hi = (hi << (lz + 1)) | (lo >> (64 - (lz + 1))) + hi >>= 64 - shift + // Include the exponent and convert to a float. + hi |= e << shift + z = F64FromBits(hi) + // Map zeros to origin. + if j&1 == 1 { + j++ + j &= 7 + z-- + } + // Multiply the fractional part by pi/4. + ret j, z * PI4 } // Is the binary digits of 4/pi as a u64 array, @@ -108,24 +108,24 @@ fn trigReduce(mut x: f64): (j: u64, z: f64) { // 19 64-bit digits and the leading one bit give 1217 bits // of precision to handle the largest possible f64 exponent. static M_PI4: [...]u64 = [ - 0x0000000000000001, - 0x45f306dc9c882a53, - 0xf84eafa3ea69bb81, - 0xb6c52b3278872083, - 0xfca2c757bd778ac3, - 0x6e48dc74849ba5c0, - 0x0c925dd413a32439, - 0xfc3bd63962534e7d, - 0xd1046bea5d768909, - 0xd338e04d68befc82, - 0x7323ac7306a673e9, - 0x3908bf177bf25076, - 0x3ff12fffbc0b301f, - 0xde5e2316b414da3e, - 0xda6cfd9e4f96136e, - 0x9e8c7ecd3cbfd45a, - 0xea4f758fd7cbe2f6, - 0x7a0e73ef14a525d4, - 0xd7f6bf623f1aba10, - 0xac06608df8f6d757, + 0x0000000000000001, + 0x45f306dc9c882a53, + 0xf84eafa3ea69bb81, + 0xb6c52b3278872083, + 0xfca2c757bd778ac3, + 0x6e48dc74849ba5c0, + 0x0c925dd413a32439, + 0xfc3bd63962534e7d, + 0xd1046bea5d768909, + 0xd338e04d68befc82, + 0x7323ac7306a673e9, + 0x3908bf177bf25076, + 0x3ff12fffbc0b301f, + 0xde5e2316b414da3e, + 0xda6cfd9e4f96136e, + 0x9e8c7ecd3cbfd45a, + 0xea4f758fd7cbe2f6, + 0x7a0e73ef14a525d4, + 0xd7f6bf623f1aba10, + 0xac06608df8f6d757, ] \ No newline at end of file diff --git a/std/mem/builtin_test.jule b/std/mem/builtin_test.jule index d654d2a38..c36f3be49 100644 --- a/std/mem/builtin_test.jule +++ b/std/mem/builtin_test.jule @@ -10,18 +10,18 @@ trait testTrait {} #test fn testFree(t: &T) { - mut sptr := new(int) - Free(sptr) + mut sptr := new(int) + Free(sptr) - let mut trt: testTrait = nil - Free(trt) + let mut trt: testTrait = nil + Free(trt) - mut an := any(0) - Free(an) + mut an := any(0) + Free(an) - mut slice := make([]byte, 10) - Free(slice) + mut slice := make([]byte, 10) + Free(slice) - mut s := []byte("hello world") // Allocate for free operation. - Free(s) + mut s := []byte("hello world") // Allocate for free operation. + Free(s) } \ No newline at end of file diff --git a/std/mem/heap.jule b/std/mem/heap.jule index c57c2c59b..a48b14ed4 100644 --- a/std/mem/heap.jule +++ b/std/mem/heap.jule @@ -7,50 +7,50 @@ use integ for std::jule::integrated // Wrapper for heap allocation. // Should be freed, occurs memory leak if did not. struct Heap[T] { - heap: *T + heap: *T } impl Heap { - // Allocates new T on heap, and returns &Heap[T] instance - // that points relevant allocation. - // Returns nil reference if allocation failed. - static fn New(): &Heap[T] { - mut heap := integ::new[T]() - if heap == nil { - ret nil - } - ret &Heap[T]{ - heap: heap, - } - } + // Allocates new T on heap, and returns &Heap[T] instance + // that points relevant allocation. + // Returns nil reference if allocation failed. + static fn New(): &Heap[T] { + mut heap := integ::new[T]() + if heap == nil { + ret nil + } + ret &Heap[T]{ + heap: heap, + } + } } impl Heap { - // Returns address of allocation. - // Returns 0 if internal pointer is nil. - fn Addr(self): uintptr { ret uintptr(self.heap) } + // Returns address of allocation. + // Returns 0 if internal pointer is nil. + fn Addr(self): uintptr { ret uintptr(self.heap) } - // Frees allocation and sets address as 0 (aka nil). - fn Free(mut self) { - unsafe { integ::delete[T](self.heap) } - self.heap = nil - } + // Frees allocation and sets address as 0 (aka nil). + fn Free(mut self) { + unsafe { integ::delete[T](self.heap) } + self.heap = nil + } - // Dereferences and returns value of internal pointer. - // Panics if internal pointer is nil. - fn Get(mut self): T { - if self.heap == nil { - panic("std::mem: Heap.get: nil pointer dereference") - } - ret unsafe { *self.heap } - } + // Dereferences and returns value of internal pointer. + // Panics if internal pointer is nil. + fn Get(mut self): T { + if self.heap == nil { + panic("std::mem: Heap.get: nil pointer dereference") + } + ret unsafe { *self.heap } + } - // Sets value of internal pointer. - // Panics if internal pointer is nil. - fn Set(mut self, mut val: T) { - if self.heap == nil { - panic("std::mem: Heap.set: nil pointer dereference") - } - unsafe { *self.heap = val } - } + // Sets value of internal pointer. + // Panics if internal pointer is nil. + fn Set(mut self, mut val: T) { + if self.heap == nil { + panic("std::mem: Heap.set: nil pointer dereference") + } + unsafe { *self.heap = val } + } } \ No newline at end of file diff --git a/std/net/addr.jule b/std/net/addr.jule index a4cf2663b..9a4934b6b 100644 --- a/std/net/addr.jule +++ b/std/net/addr.jule @@ -7,36 +7,36 @@ use conv for std::internal::conv // Address errors. enum AddrError { - NoSuitable, // No suitable address. - Unable, // Unable to parse address. - MissingIPv6, // IPv6 address is missing. - UnexpectedToken, // Address have unexpected token(s). - TooShort, // Address is too short. - TooLong, // Address is too long. - IPv4FieldValueOverflow, // IPv4 address field has value > 255. - EmptyField, // IPv4 address field must have at least one digit. - IPv4FieldOctetWithLeadingZero, // IPv4 field has octet with leading zero. - EmptyZone, // Zone must be a non-empty string. - IPv6FieldValueOverflow, // Each group must have 4 or less digits or field has value >=2^16. - IPv6ShortColon, // Colon must be followed by more characters. - MissingPort, // Port is missing. - InvalidPort, // Port is invalid. - TooManyColons, // There is too many colons. - MissingRBracket, // There is missing right bracket "]". - UnexpectedLBracket, // Address have unexpected left bracket "[". - UnexpectedRBracket, // Address have unexpected right bracket "]". - UnknownNetwork, // Unknown network name. + NoSuitable, // No suitable address. + Unable, // Unable to parse address. + MissingIPv6, // IPv6 address is missing. + UnexpectedToken, // Address have unexpected token(s). + TooShort, // Address is too short. + TooLong, // Address is too long. + IPv4FieldValueOverflow, // IPv4 address field has value > 255. + EmptyField, // IPv4 address field must have at least one digit. + IPv4FieldOctetWithLeadingZero, // IPv4 field has octet with leading zero. + EmptyZone, // Zone must be a non-empty string. + IPv6FieldValueOverflow, // Each group must have 4 or less digits or field has value >=2^16. + IPv6ShortColon, // Colon must be followed by more characters. + MissingPort, // Port is missing. + InvalidPort, // Port is invalid. + TooManyColons, // There is too many colons. + MissingRBracket, // There is missing right bracket "]". + UnexpectedLBracket, // Address have unexpected left bracket "[". + UnexpectedRBracket, // Address have unexpected right bracket "]". + UnknownNetwork, // Unknown network name. } const localhost = "localhost" // Represents a network end point address. trait Addr { - // Returns name of the network. - fn Network(self): str + // Returns name of the network. + fn Network(self): str - // String form of address. - fn Str(self): str + // String form of address. + fn Str(self): str } // Combines host and port into a network address of the @@ -45,11 +45,11 @@ trait Addr { // // See the [Connect] function for a description of the host and port parameters. fn JoinHostPort(host: str, port: str): str { - // We assume that host is a literal IPv6 address if host has colons. - if fastbytes::FindByteStr(host, ':') >= 0 { - ret "[" + host + "]:" + port - } - ret host + ":" + port + // We assume that host is a literal IPv6 address if host has colons. + if fastbytes::FindByteStr(host, ':') >= 0 { + ret "[" + host + "]:" + port + } + ret host + ":" + port } // Splits a network address of the form "host:port", @@ -64,62 +64,62 @@ fn JoinHostPort(host: str, port: str): str { // // Exceptionals are always will be AddrError. fn SplitHostPort(hostport: str)!: (host: str, port: str) { - mut j, mut k := 0, 0 - i := fastbytes::FindLastByteStr(hostport, ':') - if i == -1 { - error(AddrError.MissingPort) - } - if hostport[0] == '[' { - // Expect the first ']' just before the last ':'. - end := fastbytes::FindByteStr(hostport, ']') - if end == -1 { - error(AddrError.MissingRBracket) - } - match end + 1 { - | len(hostport): - error(AddrError.MissingPort) - | i: - // Expected result, it's fine. - |: - // Either ']' isn't followed by a colon, or it is - // followed by a colon that is not the last one. - if hostport[end+1] == ':' { - error(AddrError.TooManyColons) - } - error(AddrError.MissingPort) - } - host = hostport[1:end] - j, k = 1, end + 1 // There can't be a '[' resp. ']' before these positions. - } else { - host = hostport[:i] - if fastbytes::FindByteStr(host, ':') != -1 { - error(AddrError.TooManyColons) - } - } - if fastbytes::FindByteStr(hostport[j:], '[') != -1 { - error(AddrError.UnexpectedLBracket) - } - if fastbytes::FindByteStr(hostport[k:], ']') != -1 { - error(AddrError.UnexpectedRBracket) - } - port = hostport[i+1:] - ret + mut j, mut k := 0, 0 + i := fastbytes::FindLastByteStr(hostport, ':') + if i == -1 { + error(AddrError.MissingPort) + } + if hostport[0] == '[' { + // Expect the first ']' just before the last ':'. + end := fastbytes::FindByteStr(hostport, ']') + if end == -1 { + error(AddrError.MissingRBracket) + } + match end + 1 { + | len(hostport): + error(AddrError.MissingPort) + | i: + // Expected result, it's fine. + |: + // Either ']' isn't followed by a colon, or it is + // followed by a colon that is not the last one. + if hostport[end+1] == ':' { + error(AddrError.TooManyColons) + } + error(AddrError.MissingPort) + } + host = hostport[1:end] + j, k = 1, end + 1 // There can't be a '[' resp. ']' before these positions. + } else { + host = hostport[:i] + if fastbytes::FindByteStr(host, ':') != -1 { + error(AddrError.TooManyColons) + } + } + if fastbytes::FindByteStr(hostport[j:], '[') != -1 { + error(AddrError.UnexpectedLBracket) + } + if fastbytes::FindByteStr(hostport[k:], ']') != -1 { + error(AddrError.UnexpectedRBracket) + } + port = hostport[i+1:] + ret } fn internetAddr(&net: Network, mut ip: Ip, port: int, zone: str): Addr { - match net { - | Network.Tcp | Network.Tcp4 | Network.Tcp6: - ret &TcpAddr{Ip: ip, Port: port, Zone: zone} - | Network.Udp | Network.Udp4 | Network.Udp6: - ret &UdpAddr{Ip: ip, Port: port, Zone: zone} - |: - panic("unexpected network: " + str(net)) - } + match net { + | Network.Tcp | Network.Tcp4 | Network.Tcp6: + ret &TcpAddr{Ip: ip, Port: port, Zone: zone} + | Network.Udp | Network.Udp4 | Network.Udp6: + ret &UdpAddr{Ip: ip, Port: port, Zone: zone} + |: + panic("unexpected network: " + str(net)) + } } enum ipAddr: type { - Ip, - TcpAddr, + Ip, + TcpAddr, } // Parses addr as an IP address, returning the result. The string @@ -128,19 +128,19 @@ enum ipAddr: type { // // Exceptionals are always will be AddrError. fn parseAddr(addr: str)!: ipAddr { - for _, b in addr { - match b { - | '.': - ret parseIPv4(addr) else { error(error) } - | ':': - ret parseIPv6(addr) else { error(error) } - | '%': - // Assume that this was trying to be an IPv6 address with - // a zone specifier, but the address is missing. - error(AddrError.MissingIPv6) - } - } - error(AddrError.Unable) + for _, b in addr { + match b { + | '.': + ret parseIPv4(addr) else { error(error) } + | ':': + ret parseIPv6(addr) else { error(error) } + | '%': + // Assume that this was trying to be an IPv6 address with + // a zone specifier, but the address is missing. + error(AddrError.MissingIPv6) + } + } + error(AddrError.Unable) } // Resolvers addr which may be aliteral IP address and @@ -148,119 +148,119 @@ fn parseAddr(addr: str)!: ipAddr { // // Forwards any exceptional from used methods. fn resolveInternetAddr(&net: Network, &addr: str)!: Addr { - if addr == "" { - error(AddrError.MissingPort) - } - mut host, mut port := "", "" - mut portnum := 0 - match net { - | Network.Tcp | Network.Tcp4 | Network.Tcp6 - | Network.Udp | Network.Udp4 | Network.Udp6: - host, port = SplitHostPort(addr) else { error(error) } - (portnum), ok := conv::Atoi(port) - if !ok { - error(AddrError.InvalidPort) - } - |: - error(AddrError.UnknownNetwork) - } - if host == "" { - ret internetAddr(net, Ip.Empty(), portnum, "") - } - if host == localhost { - ret buildLocalhostAddr(net, portnum) - } - mut ip := parseAddr(host) else { error(error) } - match type ip { - | Ip: - match net { - | Network.Tcp6 | Network.Udp6: - ret nil - | Network.Tcp | Network.Tcp4: - ret &TcpAddr{ - Ip: (Ip)(ip), - Port: portnum, - } - | Network.Udp | Network.Udp4: - ret &UdpAddr{ - Ip: (Ip)(ip), - Port: portnum, - } - |: - panic("implementation bug, this panic should be unreachable") - } - | TcpAddr: - mut ipAddr := (TcpAddr)(ip) - match net { - | Network.Tcp: - ipAddr.Port = portnum - ret new(TcpAddr, ipAddr) - | Network.Udp: - ret &UdpAddr{ - Ip: ipAddr.Ip, - Zone: ipAddr.Zone, - Port: portnum, - } - | Network.Tcp4: - if !ipAddr.Ip.To4().Empty() { - ipAddr.Port = portnum - ret new(TcpAddr, ipAddr) - } - | Network.Udp4: - if !ipAddr.Ip.To4().Empty() { - ret &UdpAddr{ - Ip: ipAddr.Ip, - Zone: ipAddr.Zone, - Port: portnum, - } - } - | Network.Tcp6: - if len(ipAddr.Ip.Addr) == Ipv6.Len && ipAddr.Ip.To4().Empty() { - ipAddr.Port = portnum - ret new(TcpAddr, ipAddr) - } - | Network.Udp6: - if len(ipAddr.Ip.Addr) == Ipv6.Len && ipAddr.Ip.To4().Empty() { - ret &UdpAddr{ - Ip: ipAddr.Ip, - Zone: ipAddr.Zone, - Port: portnum, - } - } - } - } - ret nil + if addr == "" { + error(AddrError.MissingPort) + } + mut host, mut port := "", "" + mut portnum := 0 + match net { + | Network.Tcp | Network.Tcp4 | Network.Tcp6 + | Network.Udp | Network.Udp4 | Network.Udp6: + host, port = SplitHostPort(addr) else { error(error) } + (portnum), ok := conv::Atoi(port) + if !ok { + error(AddrError.InvalidPort) + } + |: + error(AddrError.UnknownNetwork) + } + if host == "" { + ret internetAddr(net, Ip.Empty(), portnum, "") + } + if host == localhost { + ret buildLocalhostAddr(net, portnum) + } + mut ip := parseAddr(host) else { error(error) } + match type ip { + | Ip: + match net { + | Network.Tcp6 | Network.Udp6: + ret nil + | Network.Tcp | Network.Tcp4: + ret &TcpAddr{ + Ip: (Ip)(ip), + Port: portnum, + } + | Network.Udp | Network.Udp4: + ret &UdpAddr{ + Ip: (Ip)(ip), + Port: portnum, + } + |: + panic("implementation bug, this panic should be unreachable") + } + | TcpAddr: + mut ipAddr := (TcpAddr)(ip) + match net { + | Network.Tcp: + ipAddr.Port = portnum + ret new(TcpAddr, ipAddr) + | Network.Udp: + ret &UdpAddr{ + Ip: ipAddr.Ip, + Zone: ipAddr.Zone, + Port: portnum, + } + | Network.Tcp4: + if !ipAddr.Ip.To4().Empty() { + ipAddr.Port = portnum + ret new(TcpAddr, ipAddr) + } + | Network.Udp4: + if !ipAddr.Ip.To4().Empty() { + ret &UdpAddr{ + Ip: ipAddr.Ip, + Zone: ipAddr.Zone, + Port: portnum, + } + } + | Network.Tcp6: + if len(ipAddr.Ip.Addr) == Ipv6.Len && ipAddr.Ip.To4().Empty() { + ipAddr.Port = portnum + ret new(TcpAddr, ipAddr) + } + | Network.Udp6: + if len(ipAddr.Ip.Addr) == Ipv6.Len && ipAddr.Ip.To4().Empty() { + ret &UdpAddr{ + Ip: ipAddr.Ip, + Zone: ipAddr.Zone, + Port: portnum, + } + } + } + } + ret nil } fn buildLocalhostAddr(&net: Network, port: int): Addr { - match net { - | Network.Tcp | Network.Tcp4: - ret &TcpAddr{ - Ip: Ipv4.Addr(127, 0, 0, 1), - Port: port, - } - | Network.Udp | Network.Udp4: - ret &UdpAddr{ - Ip: Ipv4.Addr(127, 0, 0, 1), - Port: port, - } - } - match net { - | Network.Tcp6: - mut addr := make([]byte, Ipv6.Len) - addr[len(addr)-1] = 1 - ret &TcpAddr{ - Ip: Ip{Addr: addr}, - Port: port, - } - | Network.Udp6: - mut addr := make([]byte, Ipv6.Len) - addr[len(addr)-1] = 1 - ret &UdpAddr{ - Ip: Ip{Addr: addr}, - Port: port, - } - |: - panic("implementation bug, this panic should be unreachable") - } + match net { + | Network.Tcp | Network.Tcp4: + ret &TcpAddr{ + Ip: Ipv4.Addr(127, 0, 0, 1), + Port: port, + } + | Network.Udp | Network.Udp4: + ret &UdpAddr{ + Ip: Ipv4.Addr(127, 0, 0, 1), + Port: port, + } + } + match net { + | Network.Tcp6: + mut addr := make([]byte, Ipv6.Len) + addr[len(addr)-1] = 1 + ret &TcpAddr{ + Ip: Ip{Addr: addr}, + Port: port, + } + | Network.Udp6: + mut addr := make([]byte, Ipv6.Len) + addr[len(addr)-1] = 1 + ret &UdpAddr{ + Ip: Ip{Addr: addr}, + Port: port, + } + |: + panic("implementation bug, this panic should be unreachable") + } } \ No newline at end of file diff --git a/std/net/conv.jule b/std/net/conv.jule index a07908e1d..3702a8afe 100644 --- a/std/net/conv.jule +++ b/std/net/conv.jule @@ -9,9 +9,9 @@ use conv for std::internal::conv // If the first two bytes of s are not hex digits or the third byte // does not match e, false is returned. fn xtoi(s: []byte, e: byte): (byte, bool) { - if len(s) > 2 && s[2] != e { - ret 0, false - } - n, ei, ok := conv::Xbtoi(s) - ret byte(n), ok && ei == 2 + if len(s) > 2 && s[2] != e { + ret 0, false + } + n, ei, ok := conv::Xbtoi(s) + ret byte(n), ok && ei == 2 } \ No newline at end of file diff --git a/std/net/ip.jule b/std/net/ip.jule index 2d1ba0373..5df4819ba 100644 --- a/std/net/ip.jule +++ b/std/net/ip.jule @@ -18,125 +18,125 @@ use fastbytes for std::internal::fastbytes // Some methods might return mutable data. // There is no immutability promises. struct Ip { - Addr: []byte + Addr: []byte } impl Ip { - // Returns empty IP address. - static fn Empty(): Ip { - ret Ip{Addr: nil} - } + // Returns empty IP address. + static fn Empty(): Ip { + ret Ip{Addr: nil} + } - // Like self.Str except that it returns and empty string when IP is empty. - fn ipEmptyStr(self): str { - if self.Empty() { - ret "" - } - ret self.Str() - } + // Like self.Str except that it returns and empty string when IP is empty. + fn ipEmptyStr(self): str { + if self.Empty() { + ret "" + } + ret self.Str() + } - // Reports whether IP is empty. - fn Empty(self): bool { - ret len(self.Addr) == 0 - } + // Reports whether IP is empty. + fn Empty(self): bool { + ret len(self.Addr) == 0 + } - // Reports wherher IPs are points to the same address. - // An IPv4 address and that same address in IPv6 from are considered to be equal. - fn Eq(self, other: Ip): bool { - match { - | len(self.Addr) == len(other.Addr): - ret fastbytes::Equal(self.Addr, other.Addr) - | len(self.Addr) == Ipv4.Len && len(other.Addr) == Ipv6.Len: - ret fastbytes::Equal(other.Addr[:12], v4InV6Prefix) && fastbytes::Equal(self.Addr, other.Addr[12:]) - | len(self.Addr) == Ipv6.Len && len(other.Addr) == Ipv4.Len: - ret fastbytes::Equal(self.Addr[:12], v4InV6Prefix) && fastbytes::Equal(self.Addr[12:], other.Addr) - |: - ret false - } - } + // Reports wherher IPs are points to the same address. + // An IPv4 address and that same address in IPv6 from are considered to be equal. + fn Eq(self, other: Ip): bool { + match { + | len(self.Addr) == len(other.Addr): + ret fastbytes::Equal(self.Addr, other.Addr) + | len(self.Addr) == Ipv4.Len && len(other.Addr) == Ipv6.Len: + ret fastbytes::Equal(other.Addr[:12], v4InV6Prefix) && fastbytes::Equal(self.Addr, other.Addr[12:]) + | len(self.Addr) == Ipv6.Len && len(other.Addr) == Ipv4.Len: + ret fastbytes::Equal(self.Addr[:12], v4InV6Prefix) && fastbytes::Equal(self.Addr[12:], other.Addr) + |: + ret false + } + } - // Reports whether IP is an unspecified address, - // which is "0.0.0.0" in IPv4 or "::" in IPv6. - fn IsUnspecified(self): bool { - ret self == Ipv4.Zero() || self == Ipv6.Unspecified() - } + // Reports whether IP is an unspecified address, + // which is "0.0.0.0" in IPv4 or "::" in IPv6. + fn IsUnspecified(self): bool { + ret self == Ipv4.Zero() || self == Ipv6.Unspecified() + } - // Reports whether IP is a loopback address. - fn IsLoopback(self): bool { - ip4 := unsafe { (*(&self)).To4() } - if !ip4.Empty() { - ret ip4.Addr[0] == 127 - } - ret self == Ipv6.Loopback() - } + // Reports whether IP is a loopback address. + fn IsLoopback(self): bool { + ip4 := unsafe { (*(&self)).To4() } + if !ip4.Empty() { + ret ip4.Addr[0] == 127 + } + ret self == Ipv6.Loopback() + } - // Reports whether IP is a private address according to - // RFC 1918 (for IPv4) and RFC 4193 (for IPv6). - fn IsPrivate(self): bool { - ip4 := unsafe { (*(&self)).To4() } - if !ip4.Empty() { - // Following RFC 1918, Section 3. Private Address Space which says: - // The Internet Assigned Numbers Authority (IANA) has reserved the - // following three blocks of the IP address space for private internets: - // 10.0.0.0 - 10.255.255.255 (10/8 prefix) - // 172.16.0.0 - 172.31.255.255 (172.16/12 prefix) - // 192.168.0.0 - 192.168.255.255 (192.168/16 prefix) - ret ip4.Addr[0] == 10 || - (ip4.Addr[0] == 172 && ip4.Addr[1]&0xF0 == 16) || - (ip4.Addr[0] == 192 && ip4.Addr[1] == 168) - } - // Following RFC 4193, Section 8. IANA Considerations which says: - // The IANA has assigned the FC00::/7 prefix to "Unique Local Unicast". - ret len(self.Addr) == Ipv6.Len && self.Addr[0]&0xFE == 0xFC - } + // Reports whether IP is a private address according to + // RFC 1918 (for IPv4) and RFC 4193 (for IPv6). + fn IsPrivate(self): bool { + ip4 := unsafe { (*(&self)).To4() } + if !ip4.Empty() { + // Following RFC 1918, Section 3. Private Address Space which says: + // The Internet Assigned Numbers Authority (IANA) has reserved the + // following three blocks of the IP address space for private internets: + // 10.0.0.0 - 10.255.255.255 (10/8 prefix) + // 172.16.0.0 - 172.31.255.255 (172.16/12 prefix) + // 192.168.0.0 - 192.168.255.255 (192.168/16 prefix) + ret ip4.Addr[0] == 10 || + (ip4.Addr[0] == 172 && ip4.Addr[1]&0xF0 == 16) || + (ip4.Addr[0] == 192 && ip4.Addr[1] == 168) + } + // Following RFC 4193, Section 8. IANA Considerations which says: + // The IANA has assigned the FC00::/7 prefix to "Unique Local Unicast". + ret len(self.Addr) == Ipv6.Len && self.Addr[0]&0xFE == 0xFC + } - // Converts the IPv4 address to a 4-byte representation. - // Returns empty if UP is not an Ipv4 address. - fn To4(mut self): Ip { - if len(self.Addr) == Ipv4.Len { - ret self - } - if len(self.Addr) == Ipv6.Len && - isZeros(self.Addr[:10]) && - self.Addr[10] == 0xFF && - self.Addr[11] == 0xFF { - ret Ip{Addr: self.Addr[12:16]} - } - ret Ip.Empty() - } + // Converts the IPv4 address to a 4-byte representation. + // Returns empty if UP is not an Ipv4 address. + fn To4(mut self): Ip { + if len(self.Addr) == Ipv4.Len { + ret self + } + if len(self.Addr) == Ipv6.Len && + isZeros(self.Addr[:10]) && + self.Addr[10] == 0xFF && + self.Addr[11] == 0xFF { + ret Ip{Addr: self.Addr[12:16]} + } + ret Ip.Empty() + } - // Converts the IP address to a 16-byte representation. - // Returns empty if address is not an IP address (it is the wrong length). - fn To16(mut self): Ip { - match { - | len(self.Addr) == Ipv4.Len: - ret Ipv4.Addr(self.Addr[0], self.Addr[1], self.Addr[2], self.Addr[3]) - | len(self.Addr) == Ipv6.Len: - ret self - |: - ret Ip.Empty() - } - } + // Converts the IP address to a 16-byte representation. + // Returns empty if address is not an IP address (it is the wrong length). + fn To16(mut self): Ip { + match { + | len(self.Addr) == Ipv4.Len: + ret Ipv4.Addr(self.Addr[0], self.Addr[1], self.Addr[2], self.Addr[3]) + | len(self.Addr) == Ipv6.Len: + ret self + |: + ret Ip.Empty() + } + } - // Returns string form of the IP address. - // It returns one of 4 forms: - // - "", if ip is empty - // - dotted decimal ("192.0.2.1"), if ip is an IPv4 or IP4-mapped IPv6 address - // - IPv6 conforming to RFC 5952 ("2001:db8::1"), if ip is a valid IPv6 address - // - the hexadecimal form of ip, without punctuation, if no other cases apply - fn Str(self): str { - if self.Empty() { - ret "" - } - if len(self.Addr) != Ipv4.Len && len(self.Addr) != Ipv6.Len { - ret "?" + hexStr(self.Addr) - } - ip4 := unsafe { (*(&self)).To4() } - if len(ip4.Addr) == Ipv4.Len { - ret str4(ipAddrFrom4(ip4.Addr)) - } - ret str16(ipAddrFrom16(self.Addr)) - } + // Returns string form of the IP address. + // It returns one of 4 forms: + // - "", if ip is empty + // - dotted decimal ("192.0.2.1"), if ip is an IPv4 or IP4-mapped IPv6 address + // - IPv6 conforming to RFC 5952 ("2001:db8::1"), if ip is a valid IPv6 address + // - the hexadecimal form of ip, without punctuation, if no other cases apply + fn Str(self): str { + if self.Empty() { + ret "" + } + if len(self.Addr) != Ipv4.Len && len(self.Addr) != Ipv6.Len { + ret "?" + hexStr(self.Addr) + } + ip4 := unsafe { (*(&self)).To4() } + if len(ip4.Addr) == Ipv4.Len { + ret str4(ipAddrFrom4(ip4.Addr)) + } + ret str16(ipAddrFrom16(self.Addr)) + } } static v4InV6Prefix: []byte = [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xFF, 0xFF] @@ -145,114 +145,114 @@ static v4InV6Prefix: []byte = [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, struct Ipv4 {} impl Ipv4 { - // Length of IPv4 address in bytes. - const Len = 1 << 2 + // Length of IPv4 address in bytes. + const Len = 1 << 2 - // Returns IPv4 address known as limited broadcast. - // The IP that returned is statically allocated and mutable. - static fn Broadcast(): Ip { - static mut addr = Ipv4.Addr(255, 255, 255, 255) - ret addr - } + // Returns IPv4 address known as limited broadcast. + // The IP that returned is statically allocated and mutable. + static fn Broadcast(): Ip { + static mut addr = Ipv4.Addr(255, 255, 255, 255) + ret addr + } - // Returns IPv4 address known as all systems. - // The IP that returned is statically allocated and mutable. - static fn AllSystems(): Ip { - static mut addr = Ipv4.Addr(224, 0, 0, 1) - ret addr - } + // Returns IPv4 address known as all systems. + // The IP that returned is statically allocated and mutable. + static fn AllSystems(): Ip { + static mut addr = Ipv4.Addr(224, 0, 0, 1) + ret addr + } - // Returns IPv4 address known as all routers. - // The IP that returned is statically allocated and mutable. - static fn AllRouters(): Ip { - static mut addr = Ipv4.Addr(224, 0, 0, 2) - ret addr - } + // Returns IPv4 address known as all routers. + // The IP that returned is statically allocated and mutable. + static fn AllRouters(): Ip { + static mut addr = Ipv4.Addr(224, 0, 0, 2) + ret addr + } - // Returns IPv4 address known as all zeros. - // The IP that returned is statically allocated and mutable. - static fn Zero(): Ip { - static mut addr = Ipv4.Addr(0, 0, 0, 0) - ret addr - } + // Returns IPv4 address known as all zeros. + // The IP that returned is statically allocated and mutable. + static fn Zero(): Ip { + static mut addr = Ipv4.Addr(0, 0, 0, 0) + ret addr + } - // Returns the IP address (in 16-byte form) of the - // IPv4 address a.b.c.d. - static fn Addr(a: byte, b: byte, c: byte, d: byte): Ip { - mut addr := make([]byte, Ipv6.Len) - copy(addr, v4InV6Prefix) - addr[12] = a - addr[13] = b - addr[14] = c - addr[15] = d - ret Ip{Addr: addr} - } + // Returns the IP address (in 16-byte form) of the + // IPv4 address a.b.c.d. + static fn Addr(a: byte, b: byte, c: byte, d: byte): Ip { + mut addr := make([]byte, Ipv6.Len) + copy(addr, v4InV6Prefix) + addr[12] = a + addr[13] = b + addr[14] = c + addr[15] = d + ret Ip{Addr: addr} + } } // IPv6 functionalities. struct Ipv6 {} impl Ipv6 { - // Length of IPv6 address in bytes. - const Len = 1 << 4 + // Length of IPv6 address in bytes. + const Len = 1 << 4 - // Returns IPv6 address known as all zeros. - // The IP that returned is statically allocated and mutable. - static fn Zero(): Ip { - static mut addr = Ip{Addr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]} - ret addr - } + // Returns IPv6 address known as all zeros. + // The IP that returned is statically allocated and mutable. + static fn Zero(): Ip { + static mut addr = Ip{Addr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]} + ret addr + } - // Returns IPv6 address known as unspecified. - // The IP that returned is statically allocated and mutable. - static fn Unspecified(): Ip { - static mut addr = Ip{Addr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]} - ret addr - } + // Returns IPv6 address known as unspecified. + // The IP that returned is statically allocated and mutable. + static fn Unspecified(): Ip { + static mut addr = Ip{Addr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]} + ret addr + } - // Returns IPv6 address known as loopback. - // The IP that returned is statically allocated and mutable. - static fn Loopback(): Ip { - static mut addr = Ip{Addr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]} - ret addr - } + // Returns IPv6 address known as loopback. + // The IP that returned is statically allocated and mutable. + static fn Loopback(): Ip { + static mut addr = Ip{Addr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]} + ret addr + } - // Returns IPv6 address known as interterface local all nodes. - // The IP that returned is statically allocated and mutable. - static fn InterfaceLocalAllNodes(): Ip { - static mut addr = Ip{Addr: [0xFF, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01]} - ret addr - } + // Returns IPv6 address known as interterface local all nodes. + // The IP that returned is statically allocated and mutable. + static fn InterfaceLocalAllNodes(): Ip { + static mut addr = Ip{Addr: [0xFF, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01]} + ret addr + } - // Returns IPv6 address known as link local all nodes. - // The IP that returned is statically allocated and mutable. - static fn LinkLocalAllNodes(): Ip { - static mut addr = Ip{Addr: [0xFF, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01]} - ret addr - } + // Returns IPv6 address known as link local all nodes. + // The IP that returned is statically allocated and mutable. + static fn LinkLocalAllNodes(): Ip { + static mut addr = Ip{Addr: [0xFF, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01]} + ret addr + } - // Returns IPv6 address known as link local all routers. - // The IP that returned is statically allocated and mutable. - static fn LinkLocalAllRouters(): Ip { - static mut addr = Ip{Addr: [0xFF, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x02]} - ret addr - } + // Returns IPv6 address known as link local all routers. + // The IP that returned is statically allocated and mutable. + static fn LinkLocalAllRouters(): Ip { + static mut addr = Ip{Addr: [0xFF, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x02]} + ret addr + } } // Reports whether addr is just all-zeros. fn isZeros(addr: []byte): bool { - for _, b in addr { - if b != 0 { - ret false - } - } - ret true + for _, b in addr { + if b != 0 { + ret false + } + } + ret true } fn hexStr(b: []byte): str { - mut s := make([]byte, (len(b) << 1) + 1) - for i, tn in b { - s[i<<1], s[i<<1+1] = hexDigit[tn>>4], hexDigit[tn&0xF] - } - ret unsafe::StrFromBytes(s[:len(s)-1]) + mut s := make([]byte, (len(b) << 1) + 1) + for i, tn in b { + s[i<<1], s[i<<1+1] = hexDigit[tn>>4], hexDigit[tn&0xF] + } + ret unsafe::StrFromBytes(s[:len(s)-1]) } \ No newline at end of file diff --git a/std/net/ip_addr.jule b/std/net/ip_addr.jule index b777b678f..544a3e3d2 100644 --- a/std/net/ip_addr.jule +++ b/std/net/ip_addr.jule @@ -8,63 +8,63 @@ use fastbytes for std::internal::fastbytes // Returns the address of the IPv4 address given by the 4-bytes representation. fn ipAddrFrom4(addr: []byte): u128 { - ret u128{ - hi: 0, - lo: 0xFFFF00000000 | u64(addr[0]) << 24 | u64(addr[1]) << 16 | u64(addr[2]) << 8 | u64(addr[3]), - } + ret u128{ + hi: 0, + lo: 0xFFFF00000000 | u64(addr[0]) << 24 | u64(addr[1]) << 16 | u64(addr[2]) << 8 | u64(addr[3]), + } } // Returns the address of the IPv6 address given by the 16-bytes representation. fn ipAddrFrom16(addr: []byte): u128 { - ret u128{ - hi: beU64(addr[:8]), - lo: beU64(addr[8:]), - } + ret u128{ + hi: beU64(addr[:8]), + lo: beU64(addr[8:]), + } } fn beU64(b: []byte): u64 { - ret u64(b[7]) | u64(b[6]) << 8 | u64(b[5]) << 16 | u64(b[4]) << 24 | - u64(b[3]) << 32 | u64(b[2]) << 40 | u64(b[1]) << 48 | u64(b[0]) << 56 + ret u64(b[7]) | u64(b[6]) << 8 | u64(b[5]) << 16 | u64(b[4]) << 24 | + u64(b[3]) << 32 | u64(b[2]) << 40 | u64(b[1]) << 48 | u64(b[0]) << 56 } fn beU64v4(b: []byte): u64 { - ret u64(b[3]) << 24 | u64(b[2]) << 16 | u64(b[1]) << 8 | u64(b[0]) + ret u64(b[3]) << 24 | u64(b[2]) << 16 | u64(b[1]) << 8 | u64(b[0]) } fn bePutU64v4(mut b: []byte, v: u64) { - b[3] = byte(v >> 24) - b[2] = byte(v >> 16) - b[1] = byte(v >> 8) - b[0] = byte(v) + b[3] = byte(v >> 24) + b[2] = byte(v >> 16) + b[1] = byte(v >> 8) + b[0] = byte(v) } fn bePutU64(mut b: []byte, v: u64) { - b[7] = byte(v) - b[6] = byte(v >> 8) - b[5] = byte(v >> 16) - b[4] = byte(v >> 24) - b[3] = byte(v >> 32) - b[2] = byte(v >> 40) - b[1] = byte(v >> 48) - b[0] = byte(v >> 56) + b[7] = byte(v) + b[6] = byte(v >> 8) + b[5] = byte(v >> 16) + b[4] = byte(v >> 24) + b[3] = byte(v >> 32) + b[2] = byte(v >> 40) + b[1] = byte(v >> 48) + b[0] = byte(v >> 56) } // Returns the i'th byte of ip. If ip is not an IPv4, v4 returns // unspecified garbage. fn v4(ip: u128, i: int): byte { - ret byte(ip.lo >> ((3 - i) << 3)) + ret byte(ip.lo >> ((3 - i) << 3)) } // Returns the i'th 16-bit word of ip. If ip is an IPv4 address, // this accesses the IPv4-mapped IPv6 address form of the IP. fn v6u16(ip: u128, i: byte): u16 { - mut p := u64((i / 4) % 2) - if p == 0 { - p = ip.hi - } else { - p = ip.lo - } - ret u16(p >> ((3 - i % 4) << 4)) + mut p := u64((i / 4) % 2) + if p == 0 { + p = ip.hi + } else { + p = ip.lo + } + ret u16(p >> ((3 - i % 4) << 4)) } // String of the hex digits from 0 to f. It's used in @@ -72,272 +72,272 @@ fn v6u16(ip: u128, i: byte): u16 { const digits = "0123456789abcdef" fn appendDecimal(mut &s: StrBuilder, x: u8) { - if x >= 100 { - s.WriteByte(digits[x/100]) - } - if x >= 10 { - s.WriteByte(digits[x/10%10]) - } - s.WriteByte(digits[x%10]) + if x >= 100 { + s.WriteByte(digits[x/100]) + } + if x >= 10 { + s.WriteByte(digits[x/10%10]) + } + s.WriteByte(digits[x%10]) } fn appendHex(mut &s: StrBuilder, x: u16) { - if x >= 0x1000 { - s.WriteByte(digits[x>>12]) - } - if x >= 0x100 { - s.WriteByte(digits[x>>8&0xF]) - } - if x >= 0x10 { - s.WriteByte(digits[x>>4&0xF]) - } - s.WriteByte(digits[x&0xF]) + if x >= 0x1000 { + s.WriteByte(digits[x>>12]) + } + if x >= 0x100 { + s.WriteByte(digits[x>>8&0xF]) + } + if x >= 0x10 { + s.WriteByte(digits[x>>4&0xF]) + } + s.WriteByte(digits[x&0xF]) } fn str4(ip: u128): str { - const Max = len("255.255.255.255") - mut s := StrBuilder.New(Max) - appendDecimal(s, v4(ip, 0)) - s.WriteByte('.') - appendDecimal(s, v4(ip, 1)) - s.WriteByte('.') - appendDecimal(s, v4(ip, 2)) - s.WriteByte('.') - appendDecimal(s, v4(ip, 3)) - ret s.Str() + const Max = len("255.255.255.255") + mut s := StrBuilder.New(Max) + appendDecimal(s, v4(ip, 0)) + s.WriteByte('.') + appendDecimal(s, v4(ip, 1)) + s.WriteByte('.') + appendDecimal(s, v4(ip, 2)) + s.WriteByte('.') + appendDecimal(s, v4(ip, 3)) + ret s.Str() } fn str16(ip: u128): str { - const Max = len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%enp5s0") - mut s := StrBuilder.New(Max) - - mut zeroStart, mut zeroEnd := byte(255), byte(255) - mut i := byte(0) - for i < 8; i++ { - mut j := i - for j < 8 && v6u16(ip, j) == 0 { - j++ - } - mut l := j - i - if l >= 2 && l > zeroEnd-zeroStart { - zeroStart, zeroEnd = i, j - } - } - - i = 0 - for i < 8; i++ { - if i == zeroStart { - s.WriteStr("::") - i = zeroEnd - if i >= 8 { - break - } - } else if i > 0 { - s.WriteByte(':') - } - appendHex(s, v6u16(ip, i)) - } - - ret s.Str() + const Max = len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%enp5s0") + mut s := StrBuilder.New(Max) + + mut zeroStart, mut zeroEnd := byte(255), byte(255) + mut i := byte(0) + for i < 8; i++ { + mut j := i + for j < 8 && v6u16(ip, j) == 0 { + j++ + } + mut l := j - i + if l >= 2 && l > zeroEnd-zeroStart { + zeroStart, zeroEnd = i, j + } + } + + i = 0 + for i < 8; i++ { + if i == zeroStart { + s.WriteStr("::") + i = zeroEnd + if i >= 8 { + break + } + } else if i > 0 { + s.WriteByte(':') + } + appendHex(s, v6u16(ip, i)) + } + + ret s.Str() } fn parseIPv4Fields(&addr: str, off: int, end: int, mut fields: []byte)! { - mut val, mut pos := 0, 0 - mut digLen := 0 // number of digits in current octet - s := unsafe::StrBytes(addr)[off:end] - mut i := 0 - for i < len(s); i++ { - if s[i] >= '0' && s[i] <= '9' { - if digLen == 1 && val == 0 { - error(AddrError.IPv4FieldOctetWithLeadingZero) - } - val = val * 10 + int(s[i]) - '0' - digLen++ - if val > 255 { - error(AddrError.IPv4FieldValueOverflow) - } - } else if s[i] == '.' { - // .1.2.3 - // 1.2.3. - // 1..2.3 - if i == 0 || i == len(s)-1 || s[i-1] == '.' { - error(AddrError.EmptyField) - } - // 1.2.3.4.5 - if pos == 3 { - error(AddrError.TooLong) - } - fields[pos] = byte(val) - pos++ - val = 0 - digLen = 0 - } else { - error(AddrError.UnexpectedToken) - } - } - if pos < 3 { - error(AddrError.TooShort) - } - fields[3] = byte(val) + mut val, mut pos := 0, 0 + mut digLen := 0 // number of digits in current octet + s := unsafe::StrBytes(addr)[off:end] + mut i := 0 + for i < len(s); i++ { + if s[i] >= '0' && s[i] <= '9' { + if digLen == 1 && val == 0 { + error(AddrError.IPv4FieldOctetWithLeadingZero) + } + val = val * 10 + int(s[i]) - '0' + digLen++ + if val > 255 { + error(AddrError.IPv4FieldValueOverflow) + } + } else if s[i] == '.' { + // .1.2.3 + // 1.2.3. + // 1..2.3 + if i == 0 || i == len(s)-1 || s[i-1] == '.' { + error(AddrError.EmptyField) + } + // 1.2.3.4.5 + if pos == 3 { + error(AddrError.TooLong) + } + fields[pos] = byte(val) + pos++ + val = 0 + digLen = 0 + } else { + error(AddrError.UnexpectedToken) + } + } + if pos < 3 { + error(AddrError.TooShort) + } + fields[3] = byte(val) } fn parseIPv4(&addr: str)!: Ip { - mut fields := make([]byte, 4) - parseIPv4Fields(addr, 0, len(addr), fields) else { error(error) } - ret Ip{Addr: fields} + mut fields := make([]byte, 4) + parseIPv4Fields(addr, 0, len(addr), fields) else { error(error) } + ret Ip{Addr: fields} } // Parses addr as an IPv6 address (in form "2001:db8::68"). fn parseIPv6(&addr: str)!: TcpAddr { - mut s := unsafe::StrBytes(addr) - - // Split off the zone right from the start. Yes it's a second scan - // of the string, but trying to handle it inline makes a bunch of - // other inner loop conditionals more expensive, and it ends up - // being slower. - let mut zone: []byte = nil - mut i := fastbytes::FindByte(s, '%') - if i != -1 { - s, zone = s[:i], s[i+1:] - if len(zone) == 0 { - // Not allowed to have an empty zone if explicitly specified. - error(AddrError.EmptyZone) - } - } - - mut ip := make([]byte, 16) - mut ellipsis := -1 // Position of ellipsis in IP. - - // Might have leading ellipsis. - if len(s) >= 2 && s[0] == ':' && s[1] == ':' { - ellipsis = 0 - s = s[2:] - // Might be only ellipsis. - if len(s) == 0 { - mut tcpAddr := TcpAddr{ - Ip: Ipv6.Unspecified().To16(), - Zone: str(zone), - } - ret tcpAddr - } - } - - // Loop, parsing hex numbers followed by colon. - i = 0 - for i < 16 { - // Hex number. Similar to parseIPv4, inlining the hex number - // parsing yields a significant performance increase. - mut off := 0 - mut acc := u32(0) - for off < len(s); off++ { - c := s[off] - if c >= '0' && c <= '9' { - acc = (acc << 4) + u32(c - '0') - } else if c >= 'a' && c <= 'f' { - acc = (acc << 4) + u32(c - 'a' + 10) - } else if c >= 'A' && c <= 'F' { - acc = (acc << 4) + u32(c - 'A' + 10) - } else { - break - } - if off > 3 { - // More than 4 digits in group, fail. - error(AddrError.IPv6FieldValueOverflow) - } - if acc > u32(u16.Max) { - // Overflow, fail. - error(AddrError.IPv6FieldValueOverflow) - } - } - if off == 0 { - // No digits found, fail. - error(AddrError.EmptyField) - } - - // If followed by dot, might be in trailing IPv4. - if off < len(s) && s[off] == '.' { - if ellipsis < 0 && i != 12 { - // Not the right place. - error(AddrError.UnexpectedToken) - } - if i+4 > 16 { - // Not enough room. - error(AddrError.TooLong) - } - - mut end := len(addr) - if len(zone) > 0 { - end -= len(zone) + 1 - } - parseIPv4Fields(addr, end - len(s), end, ip[i:i+4]) else { error(error) } - s = s[:0] - i += 4 - break - } - - // Save this 16-bit chunk. - ip[i] = byte(acc >> 8) - ip[i+1] = byte(acc) - i += 2 - - // Stop at end of string. - s = s[off:] - if len(s) == 0 { - break - } - - // Otherwise must be followed by colon and more. - if s[0] != ':' { - error(AddrError.UnexpectedToken) - } else if len(s) == 1 { - error(AddrError.IPv6ShortColon) - } - s = s[1:] - - // Look for ellipsis. - if s[0] == ':' { - if ellipsis >= 0 { // already have one - error(AddrError.UnexpectedToken) - } - ellipsis = i - s = s[1:] - if len(s) == 0 { // can be at end - break - } - } - } - // Must have used entire string. - if len(s) != 0 { - error(AddrError.UnexpectedToken) - } - - // If didn't parse enough, expand ellipsis. - if i < 16 { - if ellipsis < 0 { - error(AddrError.TooShort) - } - n := 16 - i - mut j := i - 1 - for j >= ellipsis; j-- { - ip[j+n] = ip[j] - } - j = ellipsis - for j < ellipsis+n; j++ { - ip[j] = 0 - } - } else if ellipsis >= 0 { - // Ellipsis must represent at least one 0 group. - error(AddrError.TooShort) - } - - // Parse IP address. - u128addr := ipAddrFrom16(ip) - bePutU64(ip[:8], u128addr.hi) - bePutU64(ip[8:], u128addr.lo) - mut tcpAddr := TcpAddr{ - Ip: Ip{Addr: ip}, - Zone: str(zone), - } - tcpAddr.Ip = tcpAddr.Ip.To16() - ret tcpAddr + mut s := unsafe::StrBytes(addr) + + // Split off the zone right from the start. Yes it's a second scan + // of the string, but trying to handle it inline makes a bunch of + // other inner loop conditionals more expensive, and it ends up + // being slower. + let mut zone: []byte = nil + mut i := fastbytes::FindByte(s, '%') + if i != -1 { + s, zone = s[:i], s[i+1:] + if len(zone) == 0 { + // Not allowed to have an empty zone if explicitly specified. + error(AddrError.EmptyZone) + } + } + + mut ip := make([]byte, 16) + mut ellipsis := -1 // Position of ellipsis in IP. + + // Might have leading ellipsis. + if len(s) >= 2 && s[0] == ':' && s[1] == ':' { + ellipsis = 0 + s = s[2:] + // Might be only ellipsis. + if len(s) == 0 { + mut tcpAddr := TcpAddr{ + Ip: Ipv6.Unspecified().To16(), + Zone: str(zone), + } + ret tcpAddr + } + } + + // Loop, parsing hex numbers followed by colon. + i = 0 + for i < 16 { + // Hex number. Similar to parseIPv4, inlining the hex number + // parsing yields a significant performance increase. + mut off := 0 + mut acc := u32(0) + for off < len(s); off++ { + c := s[off] + if c >= '0' && c <= '9' { + acc = (acc << 4) + u32(c - '0') + } else if c >= 'a' && c <= 'f' { + acc = (acc << 4) + u32(c - 'a' + 10) + } else if c >= 'A' && c <= 'F' { + acc = (acc << 4) + u32(c - 'A' + 10) + } else { + break + } + if off > 3 { + // More than 4 digits in group, fail. + error(AddrError.IPv6FieldValueOverflow) + } + if acc > u32(u16.Max) { + // Overflow, fail. + error(AddrError.IPv6FieldValueOverflow) + } + } + if off == 0 { + // No digits found, fail. + error(AddrError.EmptyField) + } + + // If followed by dot, might be in trailing IPv4. + if off < len(s) && s[off] == '.' { + if ellipsis < 0 && i != 12 { + // Not the right place. + error(AddrError.UnexpectedToken) + } + if i+4 > 16 { + // Not enough room. + error(AddrError.TooLong) + } + + mut end := len(addr) + if len(zone) > 0 { + end -= len(zone) + 1 + } + parseIPv4Fields(addr, end - len(s), end, ip[i:i+4]) else { error(error) } + s = s[:0] + i += 4 + break + } + + // Save this 16-bit chunk. + ip[i] = byte(acc >> 8) + ip[i+1] = byte(acc) + i += 2 + + // Stop at end of string. + s = s[off:] + if len(s) == 0 { + break + } + + // Otherwise must be followed by colon and more. + if s[0] != ':' { + error(AddrError.UnexpectedToken) + } else if len(s) == 1 { + error(AddrError.IPv6ShortColon) + } + s = s[1:] + + // Look for ellipsis. + if s[0] == ':' { + if ellipsis >= 0 { // already have one + error(AddrError.UnexpectedToken) + } + ellipsis = i + s = s[1:] + if len(s) == 0 { // can be at end + break + } + } + } + // Must have used entire string. + if len(s) != 0 { + error(AddrError.UnexpectedToken) + } + + // If didn't parse enough, expand ellipsis. + if i < 16 { + if ellipsis < 0 { + error(AddrError.TooShort) + } + n := 16 - i + mut j := i - 1 + for j >= ellipsis; j-- { + ip[j+n] = ip[j] + } + j = ellipsis + for j < ellipsis+n; j++ { + ip[j] = 0 + } + } else if ellipsis >= 0 { + // Ellipsis must represent at least one 0 group. + error(AddrError.TooShort) + } + + // Parse IP address. + u128addr := ipAddrFrom16(ip) + bePutU64(ip[:8], u128addr.hi) + bePutU64(ip[8:], u128addr.lo) + mut tcpAddr := TcpAddr{ + Ip: Ip{Addr: ip}, + Zone: str(zone), + } + tcpAddr.Ip = tcpAddr.Ip.To16() + ret tcpAddr } \ No newline at end of file diff --git a/std/net/mac.jule b/std/net/mac.jule index 191e36b43..0571fa504 100644 --- a/std/net/mac.jule +++ b/std/net/mac.jule @@ -9,91 +9,91 @@ const hexDigit = "0123456789abcdef" // Physical hardware address. struct HardwareAddr { - Addr: []byte + Addr: []byte } impl HardwareAddr { - // Parses s as an IEEE 802 MAC-48, EUI-48, EUI-64, or a 20-octet - // IP over InfiniBand link-layer address using one of the following formats: - // 00:00:5e:00:53:01 - // 02:00:5e:10:00:00:00:01 - // 00:00:00:00:fe:80:00:00:00:00:00:00:02:00:5e:10:00:00:00:01 - // 00-00-5e-00-53-01 - // 02-00-5e-10-00-00-00-01 - // 00-00-00-00-fe-80-00-00-00-00-00-00-02-00-5e-10-00-00-00-01 - // 0000.5e00.5301 - // 0200.5e10.0000.0001 - // 0000.0000.fe80.0000.0000.0000.0200.5e10.0000.0001 - // - // Exceptional is always will be AddrError.Unable. - static fn Parse(addr: str)!: HardwareAddr { - if len(addr) < 14 { - error(AddrError.Unable) - } - mut addrB := unsafe::StrBytes(addr) - if addr[2] == ':' || addr[2] == '-' { - if (len(addr) + 1)%3 != 0 { - error(AddrError.Unable) - } - n := (len(addr) + 1) / 3 - if n != 6 && n != 8 && n != 20 { - error(AddrError.Unable) - } - mut hAddr := make([]byte, n) - mut x, mut i := 0, 0 - for i < n { - (hAddr[i]), ok := xtoi(addrB[x:], addr[2]) - if !ok { - error(AddrError.Unable) - } - i++ - x += 3 - } - ret HardwareAddr{ - Addr: hAddr, - } - } else if addr[4] == '.' { - if (len(addr) + 1)%5 != 0 { - error(AddrError.Unable) - } - n := ((len(addr) + 1) << 1) / 5 - if n != 6 && n != 8 && n != 20 { - error(AddrError.Unable) - } - mut hAddr := make([]byte, n) - mut x, mut i := 0, 0 - for i < n { - (hAddr[i]), mut ok := xtoi(addrB[x:x+2], 0) - if !ok { - error(AddrError.Unable) - } - hAddr[i+1], ok = xtoi(addrB[x+2:], addr[4]) - if !ok { - error(AddrError.Unable) - } - i += 2 - x += 5 - } - ret HardwareAddr{ - Addr: hAddr, - } - } - error(AddrError.Unable) - } + // Parses s as an IEEE 802 MAC-48, EUI-48, EUI-64, or a 20-octet + // IP over InfiniBand link-layer address using one of the following formats: + // 00:00:5e:00:53:01 + // 02:00:5e:10:00:00:00:01 + // 00:00:00:00:fe:80:00:00:00:00:00:00:02:00:5e:10:00:00:00:01 + // 00-00-5e-00-53-01 + // 02-00-5e-10-00-00-00-01 + // 00-00-00-00-fe-80-00-00-00-00-00-00-02-00-5e-10-00-00-00-01 + // 0000.5e00.5301 + // 0200.5e10.0000.0001 + // 0000.0000.fe80.0000.0000.0000.0200.5e10.0000.0001 + // + // Exceptional is always will be AddrError.Unable. + static fn Parse(addr: str)!: HardwareAddr { + if len(addr) < 14 { + error(AddrError.Unable) + } + mut addrB := unsafe::StrBytes(addr) + if addr[2] == ':' || addr[2] == '-' { + if (len(addr) + 1)%3 != 0 { + error(AddrError.Unable) + } + n := (len(addr) + 1) / 3 + if n != 6 && n != 8 && n != 20 { + error(AddrError.Unable) + } + mut hAddr := make([]byte, n) + mut x, mut i := 0, 0 + for i < n { + (hAddr[i]), ok := xtoi(addrB[x:], addr[2]) + if !ok { + error(AddrError.Unable) + } + i++ + x += 3 + } + ret HardwareAddr{ + Addr: hAddr, + } + } else if addr[4] == '.' { + if (len(addr) + 1)%5 != 0 { + error(AddrError.Unable) + } + n := ((len(addr) + 1) << 1) / 5 + if n != 6 && n != 8 && n != 20 { + error(AddrError.Unable) + } + mut hAddr := make([]byte, n) + mut x, mut i := 0, 0 + for i < n { + (hAddr[i]), mut ok := xtoi(addrB[x:x+2], 0) + if !ok { + error(AddrError.Unable) + } + hAddr[i+1], ok = xtoi(addrB[x+2:], addr[4]) + if !ok { + error(AddrError.Unable) + } + i += 2 + x += 5 + } + ret HardwareAddr{ + Addr: hAddr, + } + } + error(AddrError.Unable) + } - // Returns address in string form. - fn Str(self): str { - if len(self.Addr) == 0 { - ret "" - } - mut buf := StrBuilder.New(len(self.Addr) * 3 - 1) - for i, b in self.Addr { - if i > 0 { - buf.WriteByte(':') - } - buf.WriteByte(hexDigit[b>>4]) - buf.WriteByte(hexDigit[b&0xF]) - } - ret buf.Str() - } + // Returns address in string form. + fn Str(self): str { + if len(self.Addr) == 0 { + ret "" + } + mut buf := StrBuilder.New(len(self.Addr) * 3 - 1) + for i, b in self.Addr { + if i > 0 { + buf.WriteByte(':') + } + buf.WriteByte(hexDigit[b>>4]) + buf.WriteByte(hexDigit[b&0xF]) + } + ret buf.Str() + } } \ No newline at end of file diff --git a/std/net/mac_test.jule b/std/net/mac_test.jule index 2fad56034..fde1633ba 100644 --- a/std/net/mac_test.jule +++ b/std/net/mac_test.jule @@ -8,96 +8,96 @@ use std::testing::{T} use strings for std::strings struct caseMacParse { - s: str - addr: HardwareAddr - ok: bool + s: str + addr: HardwareAddr + ok: bool } static casesMacParse: []caseMacParse = [ - // See RFC 7042, Section 2.1.1. - {"00:00:5e:00:53:01", {Addr: [0x00, 0x00, 0x5e, 0x00, 0x53, 0x01]}, true}, - {"00-00-5e-00-53-01", {Addr: [0x00, 0x00, 0x5e, 0x00, 0x53, 0x01]}, true}, - {"0000.5e00.5301", {Addr: [0x00, 0x00, 0x5e, 0x00, 0x53, 0x01]}, true}, + // See RFC 7042, Section 2.1.1. + {"00:00:5e:00:53:01", {Addr: [0x00, 0x00, 0x5e, 0x00, 0x53, 0x01]}, true}, + {"00-00-5e-00-53-01", {Addr: [0x00, 0x00, 0x5e, 0x00, 0x53, 0x01]}, true}, + {"0000.5e00.5301", {Addr: [0x00, 0x00, 0x5e, 0x00, 0x53, 0x01]}, true}, - // See RFC 7042, Section 2.2.2. - {"02:00:5e:10:00:00:00:01", {Addr: [0x02, 0x00, 0x5e, 0x10, 0x00, 0x00, 0x00, 0x01]}, true}, - {"02-00-5e-10-00-00-00-01", {Addr: [0x02, 0x00, 0x5e, 0x10, 0x00, 0x00, 0x00, 0x01]}, true}, - {"0200.5e10.0000.0001", {Addr: [0x02, 0x00, 0x5e, 0x10, 0x00, 0x00, 0x00, 0x01]}, true}, + // See RFC 7042, Section 2.2.2. + {"02:00:5e:10:00:00:00:01", {Addr: [0x02, 0x00, 0x5e, 0x10, 0x00, 0x00, 0x00, 0x01]}, true}, + {"02-00-5e-10-00-00-00-01", {Addr: [0x02, 0x00, 0x5e, 0x10, 0x00, 0x00, 0x00, 0x01]}, true}, + {"0200.5e10.0000.0001", {Addr: [0x02, 0x00, 0x5e, 0x10, 0x00, 0x00, 0x00, 0x01]}, true}, - // See RFC 4391, Section 9.1.1. - { - "00:00:00:00:fe:80:00:00:00:00:00:00:02:00:5e:10:00:00:00:01", - { - Addr: [ - 0x00, 0x00, 0x00, 0x00, - 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x5e, 0x10, 0x00, 0x00, 0x00, 0x01, - ], - }, - true, - }, - { - "00-00-00-00-fe-80-00-00-00-00-00-00-02-00-5e-10-00-00-00-01", - { - Addr: [ - 0x00, 0x00, 0x00, 0x00, - 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x5e, 0x10, 0x00, 0x00, 0x00, 0x01, - ], - }, - true, - }, - { - "0000.0000.fe80.0000.0000.0000.0200.5e10.0000.0001", - { - Addr: [ - 0x00, 0x00, 0x00, 0x00, - 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x5e, 0x10, 0x00, 0x00, 0x00, 0x01, - ], - }, - true, - }, - {"ab:cd:ef:AB:CD:EF", {Addr: [0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef]}, true}, - {"ab:cd:ef:AB:CD:EF:ab:cd", {Addr: [0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0xab, 0xcd]}, true}, - { - "ab:cd:ef:AB:CD:EF:ab:cd:ef:AB:CD:EF:ab:cd:ef:AB:CD:EF:ab:cd", - { - Addr: [ - 0xab, 0xcd, 0xef, 0xab, - 0xcd, 0xef, 0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, - 0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0xab, 0xcd, - ], - }, - true, - }, + // See RFC 4391, Section 9.1.1. + { + "00:00:00:00:fe:80:00:00:00:00:00:00:02:00:5e:10:00:00:00:01", + { + Addr: [ + 0x00, 0x00, 0x00, 0x00, + 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x5e, 0x10, 0x00, 0x00, 0x00, 0x01, + ], + }, + true, + }, + { + "00-00-00-00-fe-80-00-00-00-00-00-00-02-00-5e-10-00-00-00-01", + { + Addr: [ + 0x00, 0x00, 0x00, 0x00, + 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x5e, 0x10, 0x00, 0x00, 0x00, 0x01, + ], + }, + true, + }, + { + "0000.0000.fe80.0000.0000.0000.0200.5e10.0000.0001", + { + Addr: [ + 0x00, 0x00, 0x00, 0x00, + 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x5e, 0x10, 0x00, 0x00, 0x00, 0x01, + ], + }, + true, + }, + {"ab:cd:ef:AB:CD:EF", {Addr: [0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef]}, true}, + {"ab:cd:ef:AB:CD:EF:ab:cd", {Addr: [0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0xab, 0xcd]}, true}, + { + "ab:cd:ef:AB:CD:EF:ab:cd:ef:AB:CD:EF:ab:cd:ef:AB:CD:EF:ab:cd", + { + Addr: [ + 0xab, 0xcd, 0xef, 0xab, + 0xcd, 0xef, 0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, + 0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0xab, 0xcd, + ], + }, + true, + }, - // Unsuccessful cases. - {"01.02.03.04.05.06", {}, false}, - {"01:02:03:04:05:06:", {}, false}, - {"x1:02:03:04:05:06", {}, false}, - {"01002:03:04:05:06", {}, false}, - {"01:02003:04:05:06", {}, false}, - {"01:02:03004:05:06", {}, false}, - {"01:02:03:04005:06", {}, false}, - {"01:02:03:04:05006", {}, false}, - {"01-02:03:04:05:06", {}, false}, - {"01:02-03-04-05-06", {}, false}, - {"0123:4567:89AF", {}, false}, - {"0123-4567-89AF", {}, false}, + // Unsuccessful cases. + {"01.02.03.04.05.06", {}, false}, + {"01:02:03:04:05:06:", {}, false}, + {"x1:02:03:04:05:06", {}, false}, + {"01002:03:04:05:06", {}, false}, + {"01:02003:04:05:06", {}, false}, + {"01:02:03004:05:06", {}, false}, + {"01:02:03:04005:06", {}, false}, + {"01:02:03:04:05006", {}, false}, + {"01-02:03:04:05:06", {}, false}, + {"01:02-03-04-05-06", {}, false}, + {"0123:4567:89AF", {}, false}, + {"0123-4567-89AF", {}, false}, ] #test fn testParseMac(t: &T) { - for _, case in casesMacParse { - HardwareAddr.Parse(case.s) else { - if case.ok { - t.Errorf("expected success parsing for {}, but failed", case.s) - } - continue - } - if !case.ok { - t.Errorf("expected fail parsing for {}, but success", case.s) - } - } + for _, case in casesMacParse { + HardwareAddr.Parse(case.s) else { + if case.ok { + t.Errorf("expected success parsing for {}, but failed", case.s) + } + continue + } + if !case.ok { + t.Errorf("expected fail parsing for {}, but success", case.s) + } + } } \ No newline at end of file diff --git a/std/net/net.jule b/std/net/net.jule index 847ef3d5f..d5617809b 100644 --- a/std/net/net.jule +++ b/std/net/net.jule @@ -6,27 +6,27 @@ use time for std::time // Network names. enum Network: str { - Tcp: "tcp", - Tcp4: "tcp4", - Tcp6: "tcp6", - Udp: "udp", - Udp4: "udp4", - Udp6: "udp6", + Tcp: "tcp", + Tcp4: "tcp4", + Tcp6: "tcp6", + Udp: "udp", + Udp4: "udp4", + Udp6: "udp6", } // Common connection behavior. trait Conn { - fn Read(mut self, mut buf: []byte)!: int - fn Write(mut self, buf: []byte)!: int - fn SetReadTimeout(mut self, timeout: time::DurInt)! - fn SetWriteTimeout(mut self, timeout: time::DurInt)! - fn Network(self): Network - fn Close(mut self)! + fn Read(mut self, mut buf: []byte)!: int + fn Write(mut self, buf: []byte)!: int + fn SetReadTimeout(mut self, timeout: time::DurInt)! + fn SetWriteTimeout(mut self, timeout: time::DurInt)! + fn Network(self): Network + fn Close(mut self)! } // Common listener behavior. trait Listener { - fn Accept(self)!: Conn - fn Network(self): Network - fn Close(self)! + fn Accept(self)!: Conn + fn Network(self): Network + fn Close(self)! } \ No newline at end of file diff --git a/std/net/sock.jule b/std/net/sock.jule index e0eeab6f2..f379702a8 100644 --- a/std/net/sock.jule +++ b/std/net/sock.jule @@ -13,12 +13,12 @@ use sys for std::sys // // See the [Connect] function for a description of the network and addr parameters. fn Listen(network: Network, addr: str)!: Listener { - match network { - | Network.Tcp | Network.Tcp4 | Network.Tcp6: - ret tcpBind(network, addr) else { error(error) } - |: - error(AddrError.UnknownNetwork) - } + match network { + | Network.Tcp | Network.Tcp4 | Network.Tcp6: + ret tcpBind(network, addr) else { error(error) } + |: + error(AddrError.UnknownNetwork) + } } // Listens the address on the named network. @@ -27,7 +27,7 @@ fn Listen(network: Network, addr: str)!: Listener { // // See the [Connect] function for a description of the network and addr parameters. fn ListenUDP(network: Network, addr: str)!: &UdpConn { - ret udpBind(network, addr) else { error(error) } + ret udpBind(network, addr) else { error(error) } } // Connects to the address on the named network. @@ -70,7 +70,7 @@ fn ListenUDP(network: Network, addr: str)!: &UdpConn { // // It will forward any exceptional from network connectors. fn Connect(network: Network, addr: str)!: Conn { - ret ConnectTimeout(network, addr, 0) else { error(error) } + ret ConnectTimeout(network, addr, 0) else { error(error) } } // Same as Connect, but uses timeout. @@ -78,32 +78,32 @@ fn Connect(network: Network, addr: str)!: Conn { // Timeout precision is microseconds. // If the timeout is below one microsecond it will be ignored. fn ConnectTimeout(network: Network, addr: str, timeout: time::DurInt)!: Conn { - match network { - | Network.Tcp | Network.Tcp4 | Network.Tcp6: - ret tcpConnect(network, addr, timeout) else { error(error) } - | Network.Udp | Network.Udp4 | Network.Udp6: - ret udpConnect(network, addr) else { error(error) } - |: - error(AddrError.UnknownNetwork) - } + match network { + | Network.Tcp | Network.Tcp4 | Network.Tcp6: + ret tcpConnect(network, addr, timeout) else { error(error) } + | Network.Udp | Network.Udp4 | Network.Udp6: + ret udpConnect(network, addr) else { error(error) } + |: + error(AddrError.UnknownNetwork) + } } unsafe fn getSocketAddr(handle: netHandle, addr: *sys::Sockaddr, len: addrLen)! { - if sys::Getsockname(handle, addr, &len) < 0 { - error(lastErrorCode()) - } + if sys::Getsockname(handle, addr, &len) < 0 { + error(lastErrorCode()) + } } unsafe fn connectSocketNoTimeout(handle: netHandle, sockAddr: *sys::Sockaddr, sockLen: uint)! { - if sys::Connect(handle, sockAddr, sockLen) < 0 { - error(lastErrorCode()) - } + if sys::Connect(handle, sockAddr, sockLen) < 0 { + error(lastErrorCode()) + } } fn timevalFromDuration(timeout: time::DurInt): sys::Timeval { - sec := i64(time::Duration.Seconds(timeout)) - mut tv := sys::Timeval{} - tv.tv_sec = sec - tv.tv_usec = time::Duration.Microseconds(timeout - (time::Duration.Second * sec)) - ret tv + sec := i64(time::Duration.Seconds(timeout)) + mut tv := sys::Timeval{} + tv.tv_sec = sec + tv.tv_usec = time::Duration.Microseconds(timeout - (time::Duration.Second * sec)) + ret tv } \ No newline at end of file diff --git a/std/net/sock_unix.jule b/std/net/sock_unix.jule index 17c4a186b..8b3babcd8 100644 --- a/std/net/sock_unix.jule +++ b/std/net/sock_unix.jule @@ -12,124 +12,124 @@ type netHandle: int type addrLen: u32 fn lastErrorCode(): int { - ret sys::GetLastErrno() + ret sys::GetLastErrno() } fn closeSocket(handle: netHandle): bool { - ret sys::Close(handle) >= 0 + ret sys::Close(handle) >= 0 } fn closeSocketBlockingMode(handle: netHandle)! { - mut arg := sys::Fcntl(handle, sys::F_GETFL, 0) - if arg < 0 { - error(lastErrorCode()) - } - arg |= sys::O_NONBLOCK - if sys::Fcntl(handle, sys::F_SETFL, arg) < 0 { - error(lastErrorCode()) - } + mut arg := sys::Fcntl(handle, sys::F_GETFL, 0) + if arg < 0 { + error(lastErrorCode()) + } + arg |= sys::O_NONBLOCK + if sys::Fcntl(handle, sys::F_SETFL, arg) < 0 { + error(lastErrorCode()) + } } fn openSocketBlockingMode(handle: netHandle)! { - mut arg := sys::Fcntl(handle, sys::F_GETFL, 0) - if arg < 0 { - error(lastErrorCode()) - } - arg &= ^sys::O_NONBLOCK - if sys::Fcntl(handle, sys::F_SETFL, arg) < 0 { - error(lastErrorCode()) - } + mut arg := sys::Fcntl(handle, sys::F_GETFL, 0) + if arg < 0 { + error(lastErrorCode()) + } + arg &= ^sys::O_NONBLOCK + if sys::Fcntl(handle, sys::F_SETFL, arg) < 0 { + error(lastErrorCode()) + } } unsafe fn connectSocket(handle: netHandle, sockAddr: *sys::Sockaddr, sockLen: uint, timeout: time::DurInt)! { - if timeout == 0 { - connectSocketNoTimeout(handle, sockAddr, sockLen) else { error(error) } - ret - } - tv := timevalFromDuration(timeout) - if tv.tv_sec == 0 && tv.tv_usec == 0 { - connectSocketNoTimeout(handle, sockAddr, sockLen) else { error(error) } - ret - } - closeSocketBlockingMode(handle) else { error(error) } - mut res := sys::Connect(handle, sockAddr, sockLen) - if res < 0 { - err := lastErrorCode() - if err != sys::EINPROGRESS { - error(err) - } - } else { - ret - } - mut fd := sys::Fd{} - sys::FdZero(&fd) - sys::FdSet(handle, &fd) + if timeout == 0 { + connectSocketNoTimeout(handle, sockAddr, sockLen) else { error(error) } + ret + } + tv := timevalFromDuration(timeout) + if tv.tv_sec == 0 && tv.tv_usec == 0 { + connectSocketNoTimeout(handle, sockAddr, sockLen) else { error(error) } + ret + } + closeSocketBlockingMode(handle) else { error(error) } + mut res := sys::Connect(handle, sockAddr, sockLen) + if res < 0 { + err := lastErrorCode() + if err != sys::EINPROGRESS { + error(err) + } + } else { + ret + } + mut fd := sys::Fd{} + sys::FdZero(&fd) + sys::FdSet(handle, &fd) lookup: - for { - res = sys::Select(handle + 1, nil, &fd, nil, &tv) - err := lastErrorCode() - match { - | res < 0 && err != sys::EINTR: - error(err) - | res > 0: - len2 := UnsignedInt(mem::SizeOf(int)) - opt := 0 - if sys::Getsockopt(handle, sys::SOL_SOCKET, sys::SO_ERROR, &opt, &len2) < 0 { - error(lastErrorCode()) - } - if opt != 0 { - error(opt) - } - break lookup - |: - // Timeout. - error(-1) - } - } - openSocketBlockingMode(handle) else { error(error) } + for { + res = sys::Select(handle + 1, nil, &fd, nil, &tv) + err := lastErrorCode() + match { + | res < 0 && err != sys::EINTR: + error(err) + | res > 0: + len2 := UnsignedInt(mem::SizeOf(int)) + opt := 0 + if sys::Getsockopt(handle, sys::SOL_SOCKET, sys::SO_ERROR, &opt, &len2) < 0 { + error(lastErrorCode()) + } + if opt != 0 { + error(opt) + } + break lookup + |: + // Timeout. + error(-1) + } + } + openSocketBlockingMode(handle) else { error(error) } } fn recvfrom(&conn: UdpConn, mut &buf: []byte)!: int { - zsys::HandleRW(buf) - if conn.v6 { - addrLen := addrLen(mem::SizeOf(conn.sockaddr6)) - n := unsafe { sys::Recvfrom(conn.handle, &buf[0], uint(len(buf)), 0, (*sys::Sockaddr)(&conn.sockaddr6), &addrLen) } - if n >= 0 { - ret int(n) - } - } else { - addrLen := addrLen(mem::SizeOf(conn.sockaddr4)) - n := unsafe { sys::Recvfrom(conn.handle, &buf[0], uint(len(buf)), 0, (*sys::Sockaddr)(&conn.sockaddr4), &addrLen) } - if n >= 0 { - ret int(n) - } - } - error(lastErrorCode()) + zsys::HandleRW(buf) + if conn.v6 { + addrLen := addrLen(mem::SizeOf(conn.sockaddr6)) + n := unsafe { sys::Recvfrom(conn.handle, &buf[0], uint(len(buf)), 0, (*sys::Sockaddr)(&conn.sockaddr6), &addrLen) } + if n >= 0 { + ret int(n) + } + } else { + addrLen := addrLen(mem::SizeOf(conn.sockaddr4)) + n := unsafe { sys::Recvfrom(conn.handle, &buf[0], uint(len(buf)), 0, (*sys::Sockaddr)(&conn.sockaddr4), &addrLen) } + if n >= 0 { + ret int(n) + } + } + error(lastErrorCode()) } fn sendto(&conn: UdpConn, &buf: []byte)!: int { - zsys::HandleRW(buf) - if conn.v6 { - addrLen := addrLen(mem::SizeOf(conn.sockaddr6)) - n := unsafe { sys::Sendto(conn.handle, &buf[0], uint(len(buf)), 0, (*sys::Sockaddr)(&conn.sockaddr6), addrLen) } - if n >= 0 { - ret int(n) - } - } else { - addrLen := addrLen(mem::SizeOf(conn.sockaddr4)) - n := unsafe { sys::Sendto(conn.handle, &buf[0], uint(len(buf)), 0, (*sys::Sockaddr)(&conn.sockaddr4), addrLen) } - if n >= 0 { - ret int(n) - } - } - error(lastErrorCode()) + zsys::HandleRW(buf) + if conn.v6 { + addrLen := addrLen(mem::SizeOf(conn.sockaddr6)) + n := unsafe { sys::Sendto(conn.handle, &buf[0], uint(len(buf)), 0, (*sys::Sockaddr)(&conn.sockaddr6), addrLen) } + if n >= 0 { + ret int(n) + } + } else { + addrLen := addrLen(mem::SizeOf(conn.sockaddr4)) + n := unsafe { sys::Sendto(conn.handle, &buf[0], uint(len(buf)), 0, (*sys::Sockaddr)(&conn.sockaddr4), addrLen) } + if n >= 0 { + ret int(n) + } + } + error(lastErrorCode()) } fn setSocketTimeout(handle: netHandle, scope: int, timeout: time::DurInt)! { - tv := timevalFromDuration(timeout) - unsafe { - if sys::Setsockopt(handle, sys::SOL_SOCKET, scope, &tv, mem::SizeOf(tv)) < 0 { - error(lastErrorCode()) - } - } + tv := timevalFromDuration(timeout) + unsafe { + if sys::Setsockopt(handle, sys::SOL_SOCKET, scope, &tv, mem::SizeOf(tv)) < 0 { + error(lastErrorCode()) + } + } } \ No newline at end of file diff --git a/std/net/sock_windows.jule b/std/net/sock_windows.jule index 7ea46bff9..6318d71a3 100644 --- a/std/net/sock_windows.jule +++ b/std/net/sock_windows.jule @@ -12,121 +12,121 @@ type netHandle: uint type addrLen: Int fn lastErrorCode(): int { - ret sys::WSAGetLastError() + ret sys::WSAGetLastError() } fn closeSocket(handle: netHandle): bool { - ret sys::CloseSocket(handle) >= 0 + ret sys::CloseSocket(handle) >= 0 } fn setSocketBlockingMode(handle: netHandle, mode: UnsignedLong)! { - FIONBIO := 0x80000000 | (Long(mem::SizeOf(UnsignedLong) & 0x7F) << 16) | ('f' << 8) | 126 - unsafe { - if sys::Ioctlsocket(handle, FIONBIO, &mode) == sys::SOCKET_ERROR { - error(lastErrorCode()) - } - } + FIONBIO := 0x80000000 | (Long(mem::SizeOf(UnsignedLong) & 0x7F) << 16) | ('f' << 8) | 126 + unsafe { + if sys::Ioctlsocket(handle, FIONBIO, &mode) == sys::SOCKET_ERROR { + error(lastErrorCode()) + } + } } fn closeSocketBlockingMode(handle: netHandle)! { - setSocketBlockingMode(handle, 1) else { error(error) } + setSocketBlockingMode(handle, 1) else { error(error) } } fn openSocketBlockingMode(handle: netHandle)! { - setSocketBlockingMode(handle, 0) else { error(error) } + setSocketBlockingMode(handle, 0) else { error(error) } } unsafe fn connectSocket(handle: netHandle, sockAddr: *sys::Sockaddr, sockLen: uint, timeout: time::DurInt)! { - if timeout == 0 { - connectSocketNoTimeout(handle, sockAddr, sockLen) else { error(error) } - ret - } - tv := timevalFromDuration(timeout) - if tv.tv_sec == 0 && tv.tv_usec == 0 { - connectSocketNoTimeout(handle, sockAddr, sockLen) else { error(error) } - ret - } - closeSocketBlockingMode(handle) else { error(error) } - if sys::Connect(handle, sockAddr, sockLen) != sys::SOCKET_ERROR { - ret - } - err := lastErrorCode() - if err != sys::WSAEWOULDBLOCK { - error(err) - } - fdW := sys::Fd{} - mut fdE := sys::Fd{} - sys::FdZero(&fdW) - sys::FdSet(handle, &fdW) - sys::FdZero(&fdE) - sys::FdSet(handle, &fdE) - res := sys::Select(0, nil, &fdW, &fdE, &tv) - if res <= 0 { - if res == 0 { - // Timeout. - error(-1) - } - error(lastErrorCode()) - } - if sys::FdIsset(handle, &fdE) != 0 { - mut opt := Int(0) - mut optLen := Int(mem::SizeOf(opt)) - sys::Getsockopt(handle, sys::SOL_SOCKET, sys::SO_ERROR, (*Char)(&opt), &optLen) - error(int(opt)) - } - openSocketBlockingMode(handle) else { error(error) } + if timeout == 0 { + connectSocketNoTimeout(handle, sockAddr, sockLen) else { error(error) } + ret + } + tv := timevalFromDuration(timeout) + if tv.tv_sec == 0 && tv.tv_usec == 0 { + connectSocketNoTimeout(handle, sockAddr, sockLen) else { error(error) } + ret + } + closeSocketBlockingMode(handle) else { error(error) } + if sys::Connect(handle, sockAddr, sockLen) != sys::SOCKET_ERROR { + ret + } + err := lastErrorCode() + if err != sys::WSAEWOULDBLOCK { + error(err) + } + fdW := sys::Fd{} + mut fdE := sys::Fd{} + sys::FdZero(&fdW) + sys::FdSet(handle, &fdW) + sys::FdZero(&fdE) + sys::FdSet(handle, &fdE) + res := sys::Select(0, nil, &fdW, &fdE, &tv) + if res <= 0 { + if res == 0 { + // Timeout. + error(-1) + } + error(lastErrorCode()) + } + if sys::FdIsset(handle, &fdE) != 0 { + mut opt := Int(0) + mut optLen := Int(mem::SizeOf(opt)) + sys::Getsockopt(handle, sys::SOL_SOCKET, sys::SO_ERROR, (*Char)(&opt), &optLen) + error(int(opt)) + } + openSocketBlockingMode(handle) else { error(error) } } fn recvfrom(&conn: UdpConn, mut &buf: []byte)!: int { - zsys::HandleRW(buf) - if conn.v6 { - addrLen := addrLen(mem::SizeOf(conn.sockaddr6)) - n := unsafe { sys::Recvfrom(conn.handle, &buf[0], len(buf), 0, (*sys::Sockaddr)(&conn.sockaddr6), &addrLen) } - if n >= 0 { - ret int(n) - } - } else { - addrLen := addrLen(mem::SizeOf(conn.sockaddr4)) - n := unsafe { sys::Recvfrom(conn.handle, &buf[0], len(buf), 0, (*sys::Sockaddr)(&conn.sockaddr4), &addrLen) } - if n >= 0 { - ret int(n) - } - } - error(lastErrorCode()) + zsys::HandleRW(buf) + if conn.v6 { + addrLen := addrLen(mem::SizeOf(conn.sockaddr6)) + n := unsafe { sys::Recvfrom(conn.handle, &buf[0], len(buf), 0, (*sys::Sockaddr)(&conn.sockaddr6), &addrLen) } + if n >= 0 { + ret int(n) + } + } else { + addrLen := addrLen(mem::SizeOf(conn.sockaddr4)) + n := unsafe { sys::Recvfrom(conn.handle, &buf[0], len(buf), 0, (*sys::Sockaddr)(&conn.sockaddr4), &addrLen) } + if n >= 0 { + ret int(n) + } + } + error(lastErrorCode()) } fn sendto(&conn: UdpConn, &buf: []byte)!: int { - zsys::HandleRW(buf) - if conn.v6 { - addrLen := addrLen(mem::SizeOf(conn.sockaddr6)) - n := unsafe { sys::Sendto(conn.handle, &buf[0], len(buf), 0, (*sys::Sockaddr)(&conn.sockaddr6), addrLen) } - if n >= 0 { - ret int(n) - } - } else { - addrLen := addrLen(mem::SizeOf(conn.sockaddr4)) - n := unsafe { sys::Sendto(conn.handle, &buf[0], len(buf), 0, (*sys::Sockaddr)(&conn.sockaddr4), addrLen) } - if n >= 0 { - ret int(n) - } - } - error(lastErrorCode()) + zsys::HandleRW(buf) + if conn.v6 { + addrLen := addrLen(mem::SizeOf(conn.sockaddr6)) + n := unsafe { sys::Sendto(conn.handle, &buf[0], len(buf), 0, (*sys::Sockaddr)(&conn.sockaddr6), addrLen) } + if n >= 0 { + ret int(n) + } + } else { + addrLen := addrLen(mem::SizeOf(conn.sockaddr4)) + n := unsafe { sys::Sendto(conn.handle, &buf[0], len(buf), 0, (*sys::Sockaddr)(&conn.sockaddr4), addrLen) } + if n >= 0 { + ret int(n) + } + } + error(lastErrorCode()) } fn setSocketTimeout(handle: netHandle, scope: int, timeout: time::DurInt)! { - tv := timevalFromDuration(timeout) - unsafe { - if sys::Setsockopt(handle, sys::SOL_SOCKET, scope, (*Char)(&tv), int(mem::SizeOf(tv))) < 0 { - error(lastErrorCode()) - } - } + tv := timevalFromDuration(timeout) + unsafe { + if sys::Setsockopt(handle, sys::SOL_SOCKET, scope, (*Char)(&tv), int(mem::SizeOf(tv))) < 0 { + error(lastErrorCode()) + } + } } fn init() { - mut wsaData := sys::WsaData{} - verReq := sys::MakeWord(2, 2) - r := unsafe { sys::WSAStartup(verReq, &wsaData) } - if r != 0 { - panic("syd::net [windows specific]: WSAStartup failed") - } + mut wsaData := sys::WsaData{} + verReq := sys::MakeWord(2, 2) + r := unsafe { sys::WSAStartup(verReq, &wsaData) } + if r != 0 { + panic("syd::net [windows specific]: WSAStartup failed") + } } \ No newline at end of file diff --git a/std/net/tcp.jule b/std/net/tcp.jule index 5cce4a056..5ce0a058f 100644 --- a/std/net/tcp.jule +++ b/std/net/tcp.jule @@ -6,45 +6,45 @@ use conv for std::internal::conv // Represents the address of a TCP end point. struct TcpAddr { - Ip: Ip - Port: int - Zone: str // IPv6 scoped addressing zone. + Ip: Ip + Port: int + Zone: str // IPv6 scoped addressing zone. } impl Addr for TcpAddr { - // Returns the address's network name. - fn Network(self): str { - ret "tcp" - } + // Returns the address's network name. + fn Network(self): str { + ret "tcp" + } - // Returns string form of address. - fn Str(self): str { - ip := self.Ip.ipEmptyStr() - if self.Zone != "" { - ret JoinHostPort(ip + "%" + self.Zone, conv::Itoa(self.Port)) - } - ret JoinHostPort(ip, conv::Itoa(self.Port)) - } + // Returns string form of address. + fn Str(self): str { + ip := self.Ip.ipEmptyStr() + if self.Zone != "" { + ret JoinHostPort(ip + "%" + self.Zone, conv::Itoa(self.Port)) + } + ret JoinHostPort(ip, conv::Itoa(self.Port)) + } } impl TcpAddr { - // Returns an address of TCP end point. - // The network must be a TCP network name. - // - // See the [Connect] function for a description of the network and addr parameters. - // - // Exceptionals are always will be AddrError. - static fn Resolve(mut network: Network, addr: str)!: &TcpAddr { - match network { - | Network.Tcp | Network.Tcp4 | Network.Tcp6: - break - |: - error(AddrError.UnknownNetwork) - } - mut intAddr := resolveInternetAddr(network, addr) else { error(error) } - if intAddr == nil { - error(AddrError.NoSuitable) - } - ret (&TcpAddr)(intAddr) - } + // Returns an address of TCP end point. + // The network must be a TCP network name. + // + // See the [Connect] function for a description of the network and addr parameters. + // + // Exceptionals are always will be AddrError. + static fn Resolve(mut network: Network, addr: str)!: &TcpAddr { + match network { + | Network.Tcp | Network.Tcp4 | Network.Tcp6: + break + |: + error(AddrError.UnknownNetwork) + } + mut intAddr := resolveInternetAddr(network, addr) else { error(error) } + if intAddr == nil { + error(AddrError.NoSuitable) + } + ret (&TcpAddr)(intAddr) + } } \ No newline at end of file diff --git a/std/net/tcp_conn.jule b/std/net/tcp_conn.jule index 17c26c2d1..9b9fe267f 100644 --- a/std/net/tcp_conn.jule +++ b/std/net/tcp_conn.jule @@ -10,9 +10,9 @@ use zsys for std::internal::zsys // TCP connection. // In most cases, represents TCP client. struct TcpConn { - mut handle: netHandle = sys::INVALID_SOCKET - v6: bool - Addr: &TcpAddr + mut handle: netHandle = sys::INVALID_SOCKET + v6: bool + Addr: &TcpAddr } impl Conn for TcpConn {} @@ -22,98 +22,98 @@ impl io::Stream for TcpConn {} impl io::WriterCloser for TcpConn {} impl TcpConn { - // Read bytes to buffer from connection and returns readed byte count. - // The number of bytes readed can never exceed the length of the buffer. - // If the buffer is larger than the number of bytes that can be read, - // the buffer will not cause an overflow. - // It will panic if connection is closed. - // If connection is closed by server, it returns zero and sets connection - // state as closed. So if you try read again, function will panic because of - // connection state is closed. - // All exceptionals are error code of implementation. - fn Read(mut self, mut buf: []byte)!: int { - if self.handle == sys::INVALID_SOCKET { - panic("std::net: TcpConn.Read: connection is closed") - } - if len(buf) == 0 { - ret 0 - } - zsys::HandleRW(buf) - n := unsafe { sys::Recv(self.handle, &buf[0], uint(len(buf)), 0) } - if n > 0 { - ret n - } else if n == 0 { - self.Close()! - ret 0 - } - error(lastErrorCode()) - } + // Read bytes to buffer from connection and returns readed byte count. + // The number of bytes readed can never exceed the length of the buffer. + // If the buffer is larger than the number of bytes that can be read, + // the buffer will not cause an overflow. + // It will panic if connection is closed. + // If connection is closed by server, it returns zero and sets connection + // state as closed. So if you try read again, function will panic because of + // connection state is closed. + // All exceptionals are error code of implementation. + fn Read(mut self, mut buf: []byte)!: int { + if self.handle == sys::INVALID_SOCKET { + panic("std::net: TcpConn.Read: connection is closed") + } + if len(buf) == 0 { + ret 0 + } + zsys::HandleRW(buf) + n := unsafe { sys::Recv(self.handle, &buf[0], uint(len(buf)), 0) } + if n > 0 { + ret n + } else if n == 0 { + self.Close()! + ret 0 + } + error(lastErrorCode()) + } - // Writes bytes to connection and returns writed byte count. - // The number of bytes written can never exceed the length of the buffer. - // All exceptionals are error code of implementation. - fn Write(mut self, buf: []byte)!: int { - if self.handle == sys::INVALID_SOCKET { - panic("std::net: TcpConn.Write: connection is closed") - } - if len(buf) == 0 { - ret 0 - } - zsys::HandleRW(buf) - n := unsafe { sys::Send(self.handle, &buf[0], uint(len(buf)), 0) } - if n < 0 { - error(lastErrorCode()) - } - ret n - } + // Writes bytes to connection and returns writed byte count. + // The number of bytes written can never exceed the length of the buffer. + // All exceptionals are error code of implementation. + fn Write(mut self, buf: []byte)!: int { + if self.handle == sys::INVALID_SOCKET { + panic("std::net: TcpConn.Write: connection is closed") + } + if len(buf) == 0 { + ret 0 + } + zsys::HandleRW(buf) + n := unsafe { sys::Send(self.handle, &buf[0], uint(len(buf)), 0) } + if n < 0 { + error(lastErrorCode()) + } + ret n + } - // Sets read timeout for connection. - // Timeout precision is microseconds. - // If the timeout is below one microsecond it will be accepted as zero. - // The zero timeout, clears current timeout if exist. - // All exceptionals are error code of implementation. - fn SetReadTimeout(mut self, timeout: time::DurInt)! { - if self.handle == sys::INVALID_SOCKET { - panic("std::net: TcpConn.SetReadTimeout: connection is closed") - } - setSocketTimeout(self.handle, sys::SO_RCVTIMEO, timeout) else { error(error) } - } + // Sets read timeout for connection. + // Timeout precision is microseconds. + // If the timeout is below one microsecond it will be accepted as zero. + // The zero timeout, clears current timeout if exist. + // All exceptionals are error code of implementation. + fn SetReadTimeout(mut self, timeout: time::DurInt)! { + if self.handle == sys::INVALID_SOCKET { + panic("std::net: TcpConn.SetReadTimeout: connection is closed") + } + setSocketTimeout(self.handle, sys::SO_RCVTIMEO, timeout) else { error(error) } + } - // Sets write timeout for connection. - // Timeout precision is microseconds. - // If the timeout is below one microsecond it will be accepted as zero. - // The zero timeout, clears current timeout if exist. - // All exceptionals are error code of implementation. - fn SetWriteTimeout(mut self, timeout: time::DurInt)! { - if self.handle == sys::INVALID_SOCKET { - panic("std::net: TcpConn.SetReadTimeout: connection is closed") - } - setSocketTimeout(self.handle, sys::SO_SNDTIMEO, timeout) else { error(error) } - } + // Sets write timeout for connection. + // Timeout precision is microseconds. + // If the timeout is below one microsecond it will be accepted as zero. + // The zero timeout, clears current timeout if exist. + // All exceptionals are error code of implementation. + fn SetWriteTimeout(mut self, timeout: time::DurInt)! { + if self.handle == sys::INVALID_SOCKET { + panic("std::net: TcpConn.SetReadTimeout: connection is closed") + } + setSocketTimeout(self.handle, sys::SO_SNDTIMEO, timeout) else { error(error) } + } - // Returns network name which is connected. - // If connection closed, returns Network.Tcp as a general network. - fn Network(self): Network { - match { - | self.handle == sys::INVALID_SOCKET: - ret Network.Tcp - | self.v6: - ret Network.Tcp6 - |: - ret Network.Tcp4 - } - } + // Returns network name which is connected. + // If connection closed, returns Network.Tcp as a general network. + fn Network(self): Network { + match { + | self.handle == sys::INVALID_SOCKET: + ret Network.Tcp + | self.v6: + ret Network.Tcp6 + |: + ret Network.Tcp4 + } + } - // Closes connection. - // All exceptionals are error code of implementation. - fn Close(mut self)! { - if self.handle == sys::INVALID_SOCKET { - ret - } - if !closeSocket(self.handle) { - error(lastErrorCode()) - } - self.handle = sys::INVALID_SOCKET - self.v6 = false - } + // Closes connection. + // All exceptionals are error code of implementation. + fn Close(mut self)! { + if self.handle == sys::INVALID_SOCKET { + ret + } + if !closeSocket(self.handle) { + error(lastErrorCode()) + } + self.handle = sys::INVALID_SOCKET + self.v6 = false + } } \ No newline at end of file diff --git a/std/net/tcp_listener.jule b/std/net/tcp_listener.jule index 52d23c639..ed85556e6 100644 --- a/std/net/tcp_listener.jule +++ b/std/net/tcp_listener.jule @@ -9,301 +9,301 @@ use time for std::time // TCP listener. // In most cases, represents TCP server. struct TcpListener { - addr: &TcpAddr - mut v6: bool - mut handle: netHandle = sys::INVALID_SOCKET + addr: &TcpAddr + mut v6: bool + mut handle: netHandle = sys::INVALID_SOCKET } impl Listener for TcpListener {} impl TcpListener { - // Binds new TCP listener and starts listening given address. - // Returns relevant created &TcpListener if success. - // If addr is not a valid address, it will forward relevant parse exceptionals. - // In addition, any bind and listening error will be return as exceptional. - // - // See the [Connect] function for a description of the addr parameter. - static fn Bind(addr: str)!: &TcpListener { - ret tcpBind(Network.Tcp, addr) else { error(error) } - } + // Binds new TCP listener and starts listening given address. + // Returns relevant created &TcpListener if success. + // If addr is not a valid address, it will forward relevant parse exceptionals. + // In addition, any bind and listening error will be return as exceptional. + // + // See the [Connect] function for a description of the addr parameter. + static fn Bind(addr: str)!: &TcpListener { + ret tcpBind(Network.Tcp, addr) else { error(error) } + } - // Connects to TCP listener by given address. - // Returns relevant created &TcpConn if success. - // If addr is not a valid address, it will forward relevant parse exceptionals. - // In addition, any bind and listening error will be return as exceptional. - // - // See the [Connect] function for a description of the addr parameter. - static fn Connect(addr: str)!: &TcpConn { - ret tcpConnect(Network.Tcp, addr, 0) else { error(error) } - } + // Connects to TCP listener by given address. + // Returns relevant created &TcpConn if success. + // If addr is not a valid address, it will forward relevant parse exceptionals. + // In addition, any bind and listening error will be return as exceptional. + // + // See the [Connect] function for a description of the addr parameter. + static fn Connect(addr: str)!: &TcpConn { + ret tcpConnect(Network.Tcp, addr, 0) else { error(error) } + } - // Same as TcpListener.Connect, but uses timeout. - static fn ConnectTimeout(addr: str, timeout: time::DurInt)!: &TcpConn { - ret tcpConnect(Network.Tcp, addr, timeout) else { error(error) } - } + // Same as TcpListener.Connect, but uses timeout. + static fn ConnectTimeout(addr: str, timeout: time::DurInt)!: &TcpConn { + ret tcpConnect(Network.Tcp, addr, timeout) else { error(error) } + } - // Accepts incoming connection, returns &TcpConn. - // All exceptionals are error code of implementation. - // Panics if connection is closed. - fn Accept(self)!: Conn { - if self.handle == sys::INVALID_SOCKET { - panic("std::net: TcpListener.Accept: connection is not open") - } - if self.v6 { // IPv6 - mut clientAddr := sys::SockaddrIn6{} - clientAddrLen := addrLen(mem::SizeOf(clientAddr)) - handle := unsafe { sys::Accept(self.handle, (*sys::Sockaddr)(&clientAddr), &clientAddrLen) } - if handle < 0 { - error(lastErrorCode()) - } - mut ip := Ip{ - Addr: make([]byte, Ipv6.Len), - } - unsafe { - getSocketAddr(handle, (*sys::Sockaddr)(&clientAddr), clientAddrLen) else { error(error) } - } - for i in ip.Addr { - ip.Addr[i] = clientAddr.sin6_addr.s6_addr[i] - } - ret &TcpConn{ - Addr: &TcpAddr{ - Ip: ip, - Port: int(sys::Ntohs(int(clientAddr.sin6_port))), - }, - handle: handle, - v6: true, - } - } else { // IPv4 - mut clientAddr := sys::SockaddrIn{} - clientAddrLen := addrLen(mem::SizeOf(clientAddr)) - handle := unsafe { sys::Accept(self.handle, (*sys::Sockaddr)(&clientAddr), &clientAddrLen) } - if handle < 0 { - error(lastErrorCode()) - } - mut ip := Ip{ - Addr: make([]byte, Ipv4.Len), - } - unsafe { - getSocketAddr(handle, (*sys::Sockaddr)(&clientAddr), clientAddrLen) else { error(error) } - } - bePutU64v4(ip.Addr, u64(clientAddr.sin_addr.s_addr)) - ret &TcpConn{ - Addr: &TcpAddr{ - Ip: ip, - Port: int(sys::Ntohs(int(clientAddr.sin_port))), - }, - handle: handle, - } - } - } + // Accepts incoming connection, returns &TcpConn. + // All exceptionals are error code of implementation. + // Panics if connection is closed. + fn Accept(self)!: Conn { + if self.handle == sys::INVALID_SOCKET { + panic("std::net: TcpListener.Accept: connection is not open") + } + if self.v6 { // IPv6 + mut clientAddr := sys::SockaddrIn6{} + clientAddrLen := addrLen(mem::SizeOf(clientAddr)) + handle := unsafe { sys::Accept(self.handle, (*sys::Sockaddr)(&clientAddr), &clientAddrLen) } + if handle < 0 { + error(lastErrorCode()) + } + mut ip := Ip{ + Addr: make([]byte, Ipv6.Len), + } + unsafe { + getSocketAddr(handle, (*sys::Sockaddr)(&clientAddr), clientAddrLen) else { error(error) } + } + for i in ip.Addr { + ip.Addr[i] = clientAddr.sin6_addr.s6_addr[i] + } + ret &TcpConn{ + Addr: &TcpAddr{ + Ip: ip, + Port: int(sys::Ntohs(int(clientAddr.sin6_port))), + }, + handle: handle, + v6: true, + } + } else { // IPv4 + mut clientAddr := sys::SockaddrIn{} + clientAddrLen := addrLen(mem::SizeOf(clientAddr)) + handle := unsafe { sys::Accept(self.handle, (*sys::Sockaddr)(&clientAddr), &clientAddrLen) } + if handle < 0 { + error(lastErrorCode()) + } + mut ip := Ip{ + Addr: make([]byte, Ipv4.Len), + } + unsafe { + getSocketAddr(handle, (*sys::Sockaddr)(&clientAddr), clientAddrLen) else { error(error) } + } + bePutU64v4(ip.Addr, u64(clientAddr.sin_addr.s_addr)) + ret &TcpConn{ + Addr: &TcpAddr{ + Ip: ip, + Port: int(sys::Ntohs(int(clientAddr.sin_port))), + }, + handle: handle, + } + } + } - // Returns network name which is listening. - // If connection closed, returns Network.Tcp as a general network. - fn Network(self): Network { - match { - | self.handle == sys::INVALID_SOCKET: - ret Network.Tcp - | self.v6: - ret Network.Tcp6 - |: - ret Network.Tcp4 - } - } + // Returns network name which is listening. + // If connection closed, returns Network.Tcp as a general network. + fn Network(self): Network { + match { + | self.handle == sys::INVALID_SOCKET: + ret Network.Tcp + | self.v6: + ret Network.Tcp6 + |: + ret Network.Tcp4 + } + } - // Closes connection. - // All exceptionals are error code of implementation. - fn Close(self)! { - if self.handle == sys::INVALID_SOCKET { - ret - } - if !closeSocket(self.handle) { - error(lastErrorCode()) - } - self.handle = sys::INVALID_SOCKET - self.v6 = false - } + // Closes connection. + // All exceptionals are error code of implementation. + fn Close(self)! { + if self.handle == sys::INVALID_SOCKET { + ret + } + if !closeSocket(self.handle) { + error(lastErrorCode()) + } + self.handle = sys::INVALID_SOCKET + self.v6 = false + } } fn tcpBind(network: Network, &addr: str)!: &TcpListener { - mut tcpAddr := TcpAddr.Resolve(network, addr) else { error(error) } - mut handle := netHandle(sys::INVALID_SOCKET) - mut v6 := false - if tcpAddr.Ip.Empty() { - handle = sys::Socket(sys::AF_INET, sys::SOCK_STREAM, sys::IPPROTO_TCP) - if handle < 0 { - error(lastErrorCode()) - } - match network { - | Network.Tcp | Network.Tcp4: - mut sockAddr := sys::SockaddrIn{} - sockAddr.sin_family = sys::AF_INET - sockAddr.sin_port = sys::Htons(tcpAddr.Port) - sockAddr.sin_addr.s_addr = sys::INADDR_ANY - unsafe { - if sys::Bind(handle, (*sys::Sockaddr)(&sockAddr), mem::SizeOf(sockAddr)) != 0 { - closeSocket(handle) - error(lastErrorCode()) - } - } - | Network.Tcp6: - v6 = true - handle = sys::Socket(sys::AF_INET6, sys::SOCK_STREAM, sys::IPPROTO_TCP) - if handle < 0 { - error(lastErrorCode()) - } - mut sockAddr := sys::SockaddrIn6{} - sockAddr.sin6_family = sys::AF_INET6 - sockAddr.sin6_port = sys::Htons(tcpAddr.Port) - unsafe { - if sys::Bind(handle, (*sys::Sockaddr)(&sockAddr), mem::SizeOf(sockAddr)) != 0 { - closeSocket(handle) - error(lastErrorCode()) - } - } - |: - error(AddrError.UnknownNetwork) - } - } else { - mut ipv4 := tcpAddr.Ip.To4() - if ipv4.Empty() { - if network == Network.Tcp4 { - error(AddrError.NoSuitable) - } - v6 = true - handle = sys::Socket(sys::AF_INET6, sys::SOCK_STREAM, sys::IPPROTO_TCP) - if handle < 0 { - error(lastErrorCode()) - } - mut sockAddr := sys::SockaddrIn6{} - sockAddr.sin6_family = sys::AF_INET6 - for i, b in tcpAddr.Ip.Addr { - sockAddr.sin6_addr.s6_addr[i] = b - } - sockAddr.sin6_port = sys::Htons(tcpAddr.Port) - unsafe { - if sys::Bind(handle, (*sys::Sockaddr)(&sockAddr), mem::SizeOf(sockAddr)) != 0 { - closeSocket(handle) - error(lastErrorCode()) - } - } - } else { - if network == Network.Tcp6 { - error(AddrError.NoSuitable) - } - tcpAddr.Ip = ipv4 - handle = sys::Socket(sys::AF_INET, sys::SOCK_STREAM, sys::IPPROTO_TCP) - if handle < 0 { - error(lastErrorCode()) - } - mut sockAddr := sys::SockaddrIn{} - sockAddr.sin_family = sys::AF_INET - sockAddr.sin_port = sys::Htons(tcpAddr.Port) - sockAddr.sin_addr.s_addr = u32(beU64v4(tcpAddr.Ip.Addr)) - unsafe { - if sys::Bind(handle, (*sys::Sockaddr)(&sockAddr), mem::SizeOf(sockAddr)) != 0 { - closeSocket(handle) - error(lastErrorCode()) - } - } - } - } - const MaxQueueLength = 10 // Length of maximum connection waiters. - if sys::Listen(handle, MaxQueueLength) < 0 { - closeSocket(handle) - error(lastErrorCode()) - } - ret &TcpListener{ - v6: v6, - addr: tcpAddr, - handle: handle, - } + mut tcpAddr := TcpAddr.Resolve(network, addr) else { error(error) } + mut handle := netHandle(sys::INVALID_SOCKET) + mut v6 := false + if tcpAddr.Ip.Empty() { + handle = sys::Socket(sys::AF_INET, sys::SOCK_STREAM, sys::IPPROTO_TCP) + if handle < 0 { + error(lastErrorCode()) + } + match network { + | Network.Tcp | Network.Tcp4: + mut sockAddr := sys::SockaddrIn{} + sockAddr.sin_family = sys::AF_INET + sockAddr.sin_port = sys::Htons(tcpAddr.Port) + sockAddr.sin_addr.s_addr = sys::INADDR_ANY + unsafe { + if sys::Bind(handle, (*sys::Sockaddr)(&sockAddr), mem::SizeOf(sockAddr)) != 0 { + closeSocket(handle) + error(lastErrorCode()) + } + } + | Network.Tcp6: + v6 = true + handle = sys::Socket(sys::AF_INET6, sys::SOCK_STREAM, sys::IPPROTO_TCP) + if handle < 0 { + error(lastErrorCode()) + } + mut sockAddr := sys::SockaddrIn6{} + sockAddr.sin6_family = sys::AF_INET6 + sockAddr.sin6_port = sys::Htons(tcpAddr.Port) + unsafe { + if sys::Bind(handle, (*sys::Sockaddr)(&sockAddr), mem::SizeOf(sockAddr)) != 0 { + closeSocket(handle) + error(lastErrorCode()) + } + } + |: + error(AddrError.UnknownNetwork) + } + } else { + mut ipv4 := tcpAddr.Ip.To4() + if ipv4.Empty() { + if network == Network.Tcp4 { + error(AddrError.NoSuitable) + } + v6 = true + handle = sys::Socket(sys::AF_INET6, sys::SOCK_STREAM, sys::IPPROTO_TCP) + if handle < 0 { + error(lastErrorCode()) + } + mut sockAddr := sys::SockaddrIn6{} + sockAddr.sin6_family = sys::AF_INET6 + for i, b in tcpAddr.Ip.Addr { + sockAddr.sin6_addr.s6_addr[i] = b + } + sockAddr.sin6_port = sys::Htons(tcpAddr.Port) + unsafe { + if sys::Bind(handle, (*sys::Sockaddr)(&sockAddr), mem::SizeOf(sockAddr)) != 0 { + closeSocket(handle) + error(lastErrorCode()) + } + } + } else { + if network == Network.Tcp6 { + error(AddrError.NoSuitable) + } + tcpAddr.Ip = ipv4 + handle = sys::Socket(sys::AF_INET, sys::SOCK_STREAM, sys::IPPROTO_TCP) + if handle < 0 { + error(lastErrorCode()) + } + mut sockAddr := sys::SockaddrIn{} + sockAddr.sin_family = sys::AF_INET + sockAddr.sin_port = sys::Htons(tcpAddr.Port) + sockAddr.sin_addr.s_addr = u32(beU64v4(tcpAddr.Ip.Addr)) + unsafe { + if sys::Bind(handle, (*sys::Sockaddr)(&sockAddr), mem::SizeOf(sockAddr)) != 0 { + closeSocket(handle) + error(lastErrorCode()) + } + } + } + } + const MaxQueueLength = 10 // Length of maximum connection waiters. + if sys::Listen(handle, MaxQueueLength) < 0 { + closeSocket(handle) + error(lastErrorCode()) + } + ret &TcpListener{ + v6: v6, + addr: tcpAddr, + handle: handle, + } } fn tcpConnect(network: Network, &addr: str, timeout: time::DurInt)!: &TcpConn { - mut tcpAddr := TcpAddr.Resolve(network, addr) else { error(error) } - mut handle := netHandle(sys::INVALID_SOCKET) - mut v6 := false - if tcpAddr.Ip.Empty() { - handle = sys::Socket(sys::AF_INET, sys::SOCK_STREAM, sys::IPPROTO_TCP) - if handle < 0 { - error(lastErrorCode()) - } - match network { - | Network.Tcp | Network.Tcp4: - mut sockAddr := sys::SockaddrIn{} - sockAddr.sin_family = sys::AF_INET - sockAddr.sin_port = sys::Htons(tcpAddr.Port) - sockAddr.sin_addr.s_addr = sys::INADDR_ANY - unsafe { - connectSocket(handle, (*sys::Sockaddr)(&sockAddr), mem::SizeOf(sockAddr), timeout) else { - closeSocket(handle) - error(error) - } - } - | Network.Tcp6: - handle = sys::Socket(sys::AF_INET6, sys::SOCK_STREAM, sys::IPPROTO_TCP) - if handle < 0 { - error(lastErrorCode()) - } - mut sockAddr := sys::SockaddrIn6{} - sockAddr.sin6_family = sys::AF_INET6 - sockAddr.sin6_port = sys::Htons(tcpAddr.Port) - unsafe { - connectSocket(handle, (*sys::Sockaddr)(&sockAddr), mem::SizeOf(sockAddr), timeout) else { - closeSocket(handle) - error(error) - } - } - |: - error(AddrError.UnknownNetwork) - } - } else { - mut ipv4 := tcpAddr.Ip.To4() - if ipv4.Empty() { - if network == Network.Tcp4 { - error(AddrError.NoSuitable) - } - v6 = true - handle = sys::Socket(sys::AF_INET6, sys::SOCK_STREAM, sys::IPPROTO_TCP) - if handle < 0 { - error(lastErrorCode()) - } - mut sockAddr := sys::SockaddrIn6{} - sockAddr.sin6_family = sys::AF_INET6 - for i, b in tcpAddr.Ip.Addr { - sockAddr.sin6_addr.s6_addr[i] = b - } - sockAddr.sin6_port = sys::Htons(tcpAddr.Port) - unsafe { - connectSocket(handle, (*sys::Sockaddr)(&sockAddr), mem::SizeOf(sockAddr), timeout) else { - closeSocket(handle) - error(error) - } - } - } else { - if network == Network.Tcp6 { - error(AddrError.NoSuitable) - } - tcpAddr.Ip = ipv4 - handle = sys::Socket(sys::AF_INET, sys::SOCK_STREAM, sys::IPPROTO_TCP) - if handle < 0 { - error(lastErrorCode()) - } - mut sockAddr := sys::SockaddrIn{} - sockAddr.sin_family = sys::AF_INET - sockAddr.sin_port = sys::Htons(tcpAddr.Port) - sockAddr.sin_addr.s_addr = u32(beU64v4(tcpAddr.Ip.Addr)) - unsafe { - connectSocket(handle, (*sys::Sockaddr)(&sockAddr), mem::SizeOf(sockAddr), timeout) else { - closeSocket(handle) - error(error) - } - } - } - } - ret &TcpConn{ - Addr: tcpAddr, - handle: handle, - v6: v6, - } + mut tcpAddr := TcpAddr.Resolve(network, addr) else { error(error) } + mut handle := netHandle(sys::INVALID_SOCKET) + mut v6 := false + if tcpAddr.Ip.Empty() { + handle = sys::Socket(sys::AF_INET, sys::SOCK_STREAM, sys::IPPROTO_TCP) + if handle < 0 { + error(lastErrorCode()) + } + match network { + | Network.Tcp | Network.Tcp4: + mut sockAddr := sys::SockaddrIn{} + sockAddr.sin_family = sys::AF_INET + sockAddr.sin_port = sys::Htons(tcpAddr.Port) + sockAddr.sin_addr.s_addr = sys::INADDR_ANY + unsafe { + connectSocket(handle, (*sys::Sockaddr)(&sockAddr), mem::SizeOf(sockAddr), timeout) else { + closeSocket(handle) + error(error) + } + } + | Network.Tcp6: + handle = sys::Socket(sys::AF_INET6, sys::SOCK_STREAM, sys::IPPROTO_TCP) + if handle < 0 { + error(lastErrorCode()) + } + mut sockAddr := sys::SockaddrIn6{} + sockAddr.sin6_family = sys::AF_INET6 + sockAddr.sin6_port = sys::Htons(tcpAddr.Port) + unsafe { + connectSocket(handle, (*sys::Sockaddr)(&sockAddr), mem::SizeOf(sockAddr), timeout) else { + closeSocket(handle) + error(error) + } + } + |: + error(AddrError.UnknownNetwork) + } + } else { + mut ipv4 := tcpAddr.Ip.To4() + if ipv4.Empty() { + if network == Network.Tcp4 { + error(AddrError.NoSuitable) + } + v6 = true + handle = sys::Socket(sys::AF_INET6, sys::SOCK_STREAM, sys::IPPROTO_TCP) + if handle < 0 { + error(lastErrorCode()) + } + mut sockAddr := sys::SockaddrIn6{} + sockAddr.sin6_family = sys::AF_INET6 + for i, b in tcpAddr.Ip.Addr { + sockAddr.sin6_addr.s6_addr[i] = b + } + sockAddr.sin6_port = sys::Htons(tcpAddr.Port) + unsafe { + connectSocket(handle, (*sys::Sockaddr)(&sockAddr), mem::SizeOf(sockAddr), timeout) else { + closeSocket(handle) + error(error) + } + } + } else { + if network == Network.Tcp6 { + error(AddrError.NoSuitable) + } + tcpAddr.Ip = ipv4 + handle = sys::Socket(sys::AF_INET, sys::SOCK_STREAM, sys::IPPROTO_TCP) + if handle < 0 { + error(lastErrorCode()) + } + mut sockAddr := sys::SockaddrIn{} + sockAddr.sin_family = sys::AF_INET + sockAddr.sin_port = sys::Htons(tcpAddr.Port) + sockAddr.sin_addr.s_addr = u32(beU64v4(tcpAddr.Ip.Addr)) + unsafe { + connectSocket(handle, (*sys::Sockaddr)(&sockAddr), mem::SizeOf(sockAddr), timeout) else { + closeSocket(handle) + error(error) + } + } + } + } + ret &TcpConn{ + Addr: tcpAddr, + handle: handle, + v6: v6, + } } \ No newline at end of file diff --git a/std/net/u128.jule b/std/net/u128.jule index aa9a37a9f..d4a112f1e 100644 --- a/std/net/u128.jule +++ b/std/net/u128.jule @@ -2,6 +2,6 @@ // Use of this source code is governed by a BSD 3-Clause // license that can be found in the LICENSE file. struct u128 { - hi: u64 - lo: u64 + hi: u64 + lo: u64 } \ No newline at end of file diff --git a/std/net/udp.jule b/std/net/udp.jule index 592ef6cbe..afab0c292 100644 --- a/std/net/udp.jule +++ b/std/net/udp.jule @@ -6,45 +6,45 @@ use conv for std::internal::conv // Represents the address of a UDP end point. struct UdpAddr { - Ip: Ip - Port: int - Zone: str // IPv6 scoped addressing zone. + Ip: Ip + Port: int + Zone: str // IPv6 scoped addressing zone. } impl Addr for UdpAddr { - // Returns the address's network name. - fn Network(self): str { - ret "udp" - } + // Returns the address's network name. + fn Network(self): str { + ret "udp" + } - // Returns string form of address. - fn Str(self): str { - ip := self.Ip.ipEmptyStr() - if self.Zone != "" { - ret JoinHostPort(ip + "%" + self.Zone, conv::Itoa(self.Port)) - } - ret JoinHostPort(ip, conv::Itoa(self.Port)) - } + // Returns string form of address. + fn Str(self): str { + ip := self.Ip.ipEmptyStr() + if self.Zone != "" { + ret JoinHostPort(ip + "%" + self.Zone, conv::Itoa(self.Port)) + } + ret JoinHostPort(ip, conv::Itoa(self.Port)) + } } impl UdpAddr { - // Returns an address of UDP end point. - // The network must be a UDP network name. - // - // See the [Connect] function for a description of the network and addr parameters. - // - // Exceptionals are always will be AddrError. - static fn Resolve(mut network: Network, addr: str)!: &UdpAddr { - match network { - | Network.Udp | Network.Udp4 | Network.Udp6: - break - |: - error(AddrError.UnknownNetwork) - } - mut intAddr := resolveInternetAddr(network, addr) else { error(error) } - if intAddr == nil { - error(AddrError.NoSuitable) - } - ret (&UdpAddr)(intAddr) - } + // Returns an address of UDP end point. + // The network must be a UDP network name. + // + // See the [Connect] function for a description of the network and addr parameters. + // + // Exceptionals are always will be AddrError. + static fn Resolve(mut network: Network, addr: str)!: &UdpAddr { + match network { + | Network.Udp | Network.Udp4 | Network.Udp6: + break + |: + error(AddrError.UnknownNetwork) + } + mut intAddr := resolveInternetAddr(network, addr) else { error(error) } + if intAddr == nil { + error(AddrError.NoSuitable) + } + ret (&UdpAddr)(intAddr) + } } \ No newline at end of file diff --git a/std/net/udp_conn.jule b/std/net/udp_conn.jule index 5ccdffc6a..7d592e2a4 100644 --- a/std/net/udp_conn.jule +++ b/std/net/udp_conn.jule @@ -10,11 +10,11 @@ use sys for std::sys // UDP connection. // This structure represents server and client connections. struct UdpConn { - mut sockaddr4: sys::SockaddrIn - mut sockaddr6: sys::SockaddrIn6 - mut handle: netHandle = sys::INVALID_SOCKET - Addr: &UdpAddr - v6: bool + mut sockaddr4: sys::SockaddrIn + mut sockaddr6: sys::SockaddrIn6 + mut handle: netHandle = sys::INVALID_SOCKET + Addr: &UdpAddr + v6: bool } impl Conn for UdpConn {} @@ -24,251 +24,251 @@ impl io::Stream for UdpConn {} impl io::WriterCloser for UdpConn {} impl UdpConn { - // Binds new UDP listener and starts listening given address. - // Returns relevant created &UdpConn if success. - // If addr is not a valid address, it will forward relevant parse exceptionals. - // In addition, any bind and listening error will be return as exceptional. - // - // See the [Connect] function for a description of the addr parameter. - static fn Bind(addr: str)!: &UdpConn { - ret udpBind(Network.Udp, addr) else { error(error) } - } + // Binds new UDP listener and starts listening given address. + // Returns relevant created &UdpConn if success. + // If addr is not a valid address, it will forward relevant parse exceptionals. + // In addition, any bind and listening error will be return as exceptional. + // + // See the [Connect] function for a description of the addr parameter. + static fn Bind(addr: str)!: &UdpConn { + ret udpBind(Network.Udp, addr) else { error(error) } + } - // Connects to UDP listener by given address. - // Returns relevant created &UdpConn if success. - // If addr is not a valid address, it will forward relevant parse exceptionals. - // In addition, any bind and listening error will be return as exceptional. - // - // See the [Connect] function for a description of the addr parameter. - static fn Connect(addr: str)!: &UdpConn { - ret udpConnect(Network.Udp, addr) else { error(error) } - } + // Connects to UDP listener by given address. + // Returns relevant created &UdpConn if success. + // If addr is not a valid address, it will forward relevant parse exceptionals. + // In addition, any bind and listening error will be return as exceptional. + // + // See the [Connect] function for a description of the addr parameter. + static fn Connect(addr: str)!: &UdpConn { + ret udpConnect(Network.Udp, addr) else { error(error) } + } - // Read bytes to buffer from connection and returns readed byte count. - // The number of bytes readed can never exceed the length of the buffer. - // If the buffer is larger than the number of bytes that can be read, - // the buffer will not cause an overflow. - // It will panic if connection is closed. - // All exceptionals are error code of implementation. - fn Read(mut self, mut buf: []byte)!: int { - if self.handle == sys::INVALID_SOCKET { - panic("std::net: UdpConn.Read: connection is closed") - } - if len(buf) == 0 { - ret 0 - } - ret recvfrom(self, buf) else { error(error) } - } + // Read bytes to buffer from connection and returns readed byte count. + // The number of bytes readed can never exceed the length of the buffer. + // If the buffer is larger than the number of bytes that can be read, + // the buffer will not cause an overflow. + // It will panic if connection is closed. + // All exceptionals are error code of implementation. + fn Read(mut self, mut buf: []byte)!: int { + if self.handle == sys::INVALID_SOCKET { + panic("std::net: UdpConn.Read: connection is closed") + } + if len(buf) == 0 { + ret 0 + } + ret recvfrom(self, buf) else { error(error) } + } - // Writes bytes to connection and returns writed byte count. - // The number of bytes written can never exceed the length of the buffer. - // All exceptionals are error code of implementation. - fn Write(mut self, buf: []byte)!: int { - if self.handle == sys::INVALID_SOCKET { - panic("std::net: UdpConn.Write: connection is closed") - } - if len(buf) == 0 { - ret 0 - } - ret sendto(self, buf) else { error(error) } - } + // Writes bytes to connection and returns writed byte count. + // The number of bytes written can never exceed the length of the buffer. + // All exceptionals are error code of implementation. + fn Write(mut self, buf: []byte)!: int { + if self.handle == sys::INVALID_SOCKET { + panic("std::net: UdpConn.Write: connection is closed") + } + if len(buf) == 0 { + ret 0 + } + ret sendto(self, buf) else { error(error) } + } - // Sets read timeout for connection. - // Timeout precision is microseconds. - // If the timeout is below one microsecond it will be accepted as zero. - // The zero timeout, clears current timeout if exist. - // All exceptionals are error code of implementation. - fn SetReadTimeout(mut self, timeout: time::DurInt)! { - if self.handle == sys::INVALID_SOCKET { - panic("std::net: TcpConn.SetReadTimeout: connection is closed") - } - setSocketTimeout(self.handle, sys::SO_RCVTIMEO, timeout) else { error(error) } - } + // Sets read timeout for connection. + // Timeout precision is microseconds. + // If the timeout is below one microsecond it will be accepted as zero. + // The zero timeout, clears current timeout if exist. + // All exceptionals are error code of implementation. + fn SetReadTimeout(mut self, timeout: time::DurInt)! { + if self.handle == sys::INVALID_SOCKET { + panic("std::net: TcpConn.SetReadTimeout: connection is closed") + } + setSocketTimeout(self.handle, sys::SO_RCVTIMEO, timeout) else { error(error) } + } - // Sets write timeout for connection. - // Timeout precision is microseconds. - // If the timeout is below one microsecond it will be accepted as zero. - // The zero timeout, clears current timeout if exist. - // All exceptionals are error code of implementation. - fn SetWriteTimeout(mut self, timeout: time::DurInt)! { - if self.handle == sys::INVALID_SOCKET { - panic("std::net: TcpConn.SetReadTimeout: connection is closed") - } - setSocketTimeout(self.handle, sys::SO_SNDTIMEO, timeout) else { error(error) } - } + // Sets write timeout for connection. + // Timeout precision is microseconds. + // If the timeout is below one microsecond it will be accepted as zero. + // The zero timeout, clears current timeout if exist. + // All exceptionals are error code of implementation. + fn SetWriteTimeout(mut self, timeout: time::DurInt)! { + if self.handle == sys::INVALID_SOCKET { + panic("std::net: TcpConn.SetReadTimeout: connection is closed") + } + setSocketTimeout(self.handle, sys::SO_SNDTIMEO, timeout) else { error(error) } + } - // Returns network name which is connected or listening. - // If connection closed, returns Network.Udp as a general network. - fn Network(self): Network { - match { - | self.handle == sys::INVALID_SOCKET: - ret Network.Udp - | self.v6: - ret Network.Udp6 - |: - ret Network.Udp4 - } - } + // Returns network name which is connected or listening. + // If connection closed, returns Network.Udp as a general network. + fn Network(self): Network { + match { + | self.handle == sys::INVALID_SOCKET: + ret Network.Udp + | self.v6: + ret Network.Udp6 + |: + ret Network.Udp4 + } + } - // Closes connection. - // All exceptionals are error code of implementation. - fn Close(mut self)! { - if self.handle == sys::INVALID_SOCKET { - ret - } - if !closeSocket(self.handle) { - error(lastErrorCode()) - } - self.handle = sys::INVALID_SOCKET - self.v6 = false - } + // Closes connection. + // All exceptionals are error code of implementation. + fn Close(mut self)! { + if self.handle == sys::INVALID_SOCKET { + ret + } + if !closeSocket(self.handle) { + error(lastErrorCode()) + } + self.handle = sys::INVALID_SOCKET + self.v6 = false + } } fn udpBind(network: Network, &addr: str)!: &UdpConn { - mut conn := UdpConn{ - handle: netHandle(sys::INVALID_SOCKET), - Addr: UdpAddr.Resolve(network, addr) else { error(error) }, - } - if conn.Addr.Ip.Empty() { - conn.handle = sys::Socket(sys::AF_INET, sys::SOCK_DGRAM, sys::IPPROTO_UDP) - if conn.handle < 0 { - error(lastErrorCode()) - } - match network { - | Network.Udp | Network.Udp4: - conn.sockaddr4 = sys::SockaddrIn{} - conn.sockaddr4.sin_family = sys::AF_INET - conn.sockaddr4.sin_port = sys::Htons(conn.Addr.Port) - conn.sockaddr4.sin_addr.s_addr = sys::INADDR_ANY - unsafe { - if sys::Bind(conn.handle, (*sys::Sockaddr)(&conn.sockaddr4), mem::SizeOf(conn.sockaddr4)) != 0 { - closeSocket(conn.handle) - error(lastErrorCode()) - } - } - | Network.Udp6: - conn.v6 = true - conn.handle = sys::Socket(sys::AF_INET6, sys::SOCK_DGRAM, sys::IPPROTO_UDP) - if conn.handle < 0 { - error(lastErrorCode()) - } - mut sockAddr := sys::SockaddrIn6{} - sockAddr.sin6_family = sys::AF_INET6 - sockAddr.sin6_port = sys::Htons(conn.Addr.Port) - unsafe { - if sys::Bind(conn.handle, (*sys::Sockaddr)(&sockAddr), mem::SizeOf(sockAddr)) != 0 { - closeSocket(conn.handle) - error(lastErrorCode()) - } - } - |: - error(AddrError.UnknownNetwork) - } - } else { - mut ipv4 := conn.Addr.Ip.To4() - if ipv4.Empty() { - if network == Network.Udp4 { - error(AddrError.NoSuitable) - } - conn.v6 = true - conn.handle = sys::Socket(sys::AF_INET6, sys::SOCK_DGRAM, sys::IPPROTO_UDP) - if conn.handle < 0 { - error(lastErrorCode()) - } - conn.sockaddr6 = sys::SockaddrIn6{} - conn.sockaddr6.sin6_family = sys::AF_INET6 - for i, b in conn.Addr.Ip.Addr { - conn.sockaddr6.sin6_addr.s6_addr[i] = b - } - conn.sockaddr6.sin6_port = sys::Htons(conn.Addr.Port) - unsafe { - if sys::Bind(conn.handle, (*sys::Sockaddr)(&conn.sockaddr6), mem::SizeOf(conn.sockaddr6)) != 0 { - closeSocket(conn.handle) - error(lastErrorCode()) - } - } - } else { - if network == Network.Udp6 { - error(AddrError.NoSuitable) - } - conn.Addr.Ip = ipv4 - conn.handle = sys::Socket(sys::AF_INET, sys::SOCK_DGRAM, sys::IPPROTO_UDP) - if conn.handle < 0 { - error(lastErrorCode()) - } - conn.sockaddr4 = sys::SockaddrIn{} - conn.sockaddr4.sin_family = sys::AF_INET - conn.sockaddr4.sin_port = sys::Htons(conn.Addr.Port) - conn.sockaddr4.sin_addr.s_addr = u32(beU64v4(conn.Addr.Ip.Addr)) - unsafe { - if sys::Bind(conn.handle, (*sys::Sockaddr)(&conn.sockaddr4), mem::SizeOf(conn.sockaddr4)) != 0 { - closeSocket(conn.handle) - error(lastErrorCode()) - } - } - } - } - ret new(UdpConn, conn) + mut conn := UdpConn{ + handle: netHandle(sys::INVALID_SOCKET), + Addr: UdpAddr.Resolve(network, addr) else { error(error) }, + } + if conn.Addr.Ip.Empty() { + conn.handle = sys::Socket(sys::AF_INET, sys::SOCK_DGRAM, sys::IPPROTO_UDP) + if conn.handle < 0 { + error(lastErrorCode()) + } + match network { + | Network.Udp | Network.Udp4: + conn.sockaddr4 = sys::SockaddrIn{} + conn.sockaddr4.sin_family = sys::AF_INET + conn.sockaddr4.sin_port = sys::Htons(conn.Addr.Port) + conn.sockaddr4.sin_addr.s_addr = sys::INADDR_ANY + unsafe { + if sys::Bind(conn.handle, (*sys::Sockaddr)(&conn.sockaddr4), mem::SizeOf(conn.sockaddr4)) != 0 { + closeSocket(conn.handle) + error(lastErrorCode()) + } + } + | Network.Udp6: + conn.v6 = true + conn.handle = sys::Socket(sys::AF_INET6, sys::SOCK_DGRAM, sys::IPPROTO_UDP) + if conn.handle < 0 { + error(lastErrorCode()) + } + mut sockAddr := sys::SockaddrIn6{} + sockAddr.sin6_family = sys::AF_INET6 + sockAddr.sin6_port = sys::Htons(conn.Addr.Port) + unsafe { + if sys::Bind(conn.handle, (*sys::Sockaddr)(&sockAddr), mem::SizeOf(sockAddr)) != 0 { + closeSocket(conn.handle) + error(lastErrorCode()) + } + } + |: + error(AddrError.UnknownNetwork) + } + } else { + mut ipv4 := conn.Addr.Ip.To4() + if ipv4.Empty() { + if network == Network.Udp4 { + error(AddrError.NoSuitable) + } + conn.v6 = true + conn.handle = sys::Socket(sys::AF_INET6, sys::SOCK_DGRAM, sys::IPPROTO_UDP) + if conn.handle < 0 { + error(lastErrorCode()) + } + conn.sockaddr6 = sys::SockaddrIn6{} + conn.sockaddr6.sin6_family = sys::AF_INET6 + for i, b in conn.Addr.Ip.Addr { + conn.sockaddr6.sin6_addr.s6_addr[i] = b + } + conn.sockaddr6.sin6_port = sys::Htons(conn.Addr.Port) + unsafe { + if sys::Bind(conn.handle, (*sys::Sockaddr)(&conn.sockaddr6), mem::SizeOf(conn.sockaddr6)) != 0 { + closeSocket(conn.handle) + error(lastErrorCode()) + } + } + } else { + if network == Network.Udp6 { + error(AddrError.NoSuitable) + } + conn.Addr.Ip = ipv4 + conn.handle = sys::Socket(sys::AF_INET, sys::SOCK_DGRAM, sys::IPPROTO_UDP) + if conn.handle < 0 { + error(lastErrorCode()) + } + conn.sockaddr4 = sys::SockaddrIn{} + conn.sockaddr4.sin_family = sys::AF_INET + conn.sockaddr4.sin_port = sys::Htons(conn.Addr.Port) + conn.sockaddr4.sin_addr.s_addr = u32(beU64v4(conn.Addr.Ip.Addr)) + unsafe { + if sys::Bind(conn.handle, (*sys::Sockaddr)(&conn.sockaddr4), mem::SizeOf(conn.sockaddr4)) != 0 { + closeSocket(conn.handle) + error(lastErrorCode()) + } + } + } + } + ret new(UdpConn, conn) } fn udpConnect(network: Network, &addr: str)!: &UdpConn { - mut conn := UdpConn{ - handle: netHandle(sys::INVALID_SOCKET), - Addr: UdpAddr.Resolve(network, addr) else { error(error) }, - } - if conn.Addr.Ip.Empty() { - conn.handle = sys::Socket(sys::AF_INET, sys::SOCK_DGRAM, sys::IPPROTO_UDP) - if conn.handle < 0 { - error(lastErrorCode()) - } - match network { - | Network.Udp | Network.Udp4: - conn.sockaddr4 = sys::SockaddrIn{} - conn.sockaddr4.sin_family = sys::AF_INET - conn.sockaddr4.sin_port = sys::Htons(conn.Addr.Port) - conn.sockaddr4.sin_addr.s_addr = sys::INADDR_ANY - | Network.Udp6: - conn.handle = sys::Socket(sys::AF_INET6, sys::SOCK_DGRAM, sys::IPPROTO_UDP) - if conn.handle < 0 { - error(lastErrorCode()) - } - conn.sockaddr6 = sys::SockaddrIn6{} - conn.sockaddr6.sin6_family = sys::AF_INET6 - conn.sockaddr6.sin6_port = sys::Htons(conn.Addr.Port) - |: - error(AddrError.UnknownNetwork) - } - } else { - mut ipv4 := conn.Addr.Ip.To4() - if ipv4.Empty() { - if network == Network.Udp4 { - error(AddrError.NoSuitable) - } - conn.v6 = true - conn.handle = sys::Socket(sys::AF_INET6, sys::SOCK_DGRAM, sys::IPPROTO_UDP) - if conn.handle < 0 { - error(lastErrorCode()) - } - conn.sockaddr6 = sys::SockaddrIn6{} - conn.sockaddr6.sin6_family = sys::AF_INET6 - for i, b in conn.Addr.Ip.Addr { - conn.sockaddr6.sin6_addr.s6_addr[i] = b - } - conn.sockaddr6.sin6_port = sys::Htons(conn.Addr.Port) - } else { - if network == Network.Udp6 { - error(AddrError.NoSuitable) - } - conn.Addr.Ip = ipv4 - conn.handle = sys::Socket(sys::AF_INET, sys::SOCK_DGRAM, sys::IPPROTO_UDP) - if conn.handle < 0 { - error(lastErrorCode()) - } - conn.sockaddr4 = sys::SockaddrIn{} - conn.sockaddr4.sin_family = sys::AF_INET - conn.sockaddr4.sin_port = sys::Htons(conn.Addr.Port) - conn.sockaddr4.sin_addr.s_addr = u32(beU64v4(conn.Addr.Ip.Addr)) - } - } - ret new(UdpConn, conn) + mut conn := UdpConn{ + handle: netHandle(sys::INVALID_SOCKET), + Addr: UdpAddr.Resolve(network, addr) else { error(error) }, + } + if conn.Addr.Ip.Empty() { + conn.handle = sys::Socket(sys::AF_INET, sys::SOCK_DGRAM, sys::IPPROTO_UDP) + if conn.handle < 0 { + error(lastErrorCode()) + } + match network { + | Network.Udp | Network.Udp4: + conn.sockaddr4 = sys::SockaddrIn{} + conn.sockaddr4.sin_family = sys::AF_INET + conn.sockaddr4.sin_port = sys::Htons(conn.Addr.Port) + conn.sockaddr4.sin_addr.s_addr = sys::INADDR_ANY + | Network.Udp6: + conn.handle = sys::Socket(sys::AF_INET6, sys::SOCK_DGRAM, sys::IPPROTO_UDP) + if conn.handle < 0 { + error(lastErrorCode()) + } + conn.sockaddr6 = sys::SockaddrIn6{} + conn.sockaddr6.sin6_family = sys::AF_INET6 + conn.sockaddr6.sin6_port = sys::Htons(conn.Addr.Port) + |: + error(AddrError.UnknownNetwork) + } + } else { + mut ipv4 := conn.Addr.Ip.To4() + if ipv4.Empty() { + if network == Network.Udp4 { + error(AddrError.NoSuitable) + } + conn.v6 = true + conn.handle = sys::Socket(sys::AF_INET6, sys::SOCK_DGRAM, sys::IPPROTO_UDP) + if conn.handle < 0 { + error(lastErrorCode()) + } + conn.sockaddr6 = sys::SockaddrIn6{} + conn.sockaddr6.sin6_family = sys::AF_INET6 + for i, b in conn.Addr.Ip.Addr { + conn.sockaddr6.sin6_addr.s6_addr[i] = b + } + conn.sockaddr6.sin6_port = sys::Htons(conn.Addr.Port) + } else { + if network == Network.Udp6 { + error(AddrError.NoSuitable) + } + conn.Addr.Ip = ipv4 + conn.handle = sys::Socket(sys::AF_INET, sys::SOCK_DGRAM, sys::IPPROTO_UDP) + if conn.handle < 0 { + error(lastErrorCode()) + } + conn.sockaddr4 = sys::SockaddrIn{} + conn.sockaddr4.sin_family = sys::AF_INET + conn.sockaddr4.sin_port = sys::Htons(conn.Addr.Port) + conn.sockaddr4.sin_addr.s_addr = u32(beU64v4(conn.Addr.Ip.Addr)) + } + } + ret new(UdpConn, conn) } \ No newline at end of file diff --git a/std/process/cmd.jule b/std/process/cmd.jule index d934a5873..718eb12ea 100644 --- a/std/process/cmd.jule +++ b/std/process/cmd.jule @@ -13,40 +13,40 @@ // will use copy of the parent process's environment variables. Environment variables // should be in the "KEY=value" format. struct Cmd { - mut attrs: cmdAttrs + mut attrs: cmdAttrs - path: str + path: str - Args: []str - Env: []str + Args: []str + Env: []str } impl Cmd { - // Returns Cmd instance for path. - static fn New(path: str): &Cmd { - ret &Cmd{ - path: path, - } - } + // Returns Cmd instance for path. + static fn New(path: str): &Cmd { + ret &Cmd{ + path: path, + } + } - // Spawns new child-process and executes command. - // Panics if command is already spawned. - // Use the [Wait] or [Kill] method to make respawnable. - fn Spawn(self)! { - self.spawn() else { error(error) } - } + // Spawns new child-process and executes command. + // Panics if command is already spawned. + // Use the [Wait] or [Kill] method to make respawnable. + fn Spawn(self)! { + self.spawn() else { error(error) } + } - // Kills process. - // Fails if process is not alive. - // Panics if command is not spawned. - fn Kill(self)! { - self.kill() else { error(error) } - } + // Kills process. + // Fails if process is not alive. + // Panics if command is not spawned. + fn Kill(self)! { + self.kill() else { error(error) } + } - // Waits complete for running of process. - // Returns exit code of process. - // Panics if command is not spawned. - fn Wait(self)!: int { - ret self.wait() else { error(error) } - } + // Waits complete for running of process. + // Returns exit code of process. + // Panics if command is not spawned. + fn Wait(self)!: int { + ret self.wait() else { error(error) } + } } \ No newline at end of file diff --git a/std/process/cmd_unix.jule b/std/process/cmd_unix.jule index 044612494..9622e8e48 100644 --- a/std/process/cmd_unix.jule +++ b/std/process/cmd_unix.jule @@ -29,118 +29,118 @@ type pid: int const invalidPid = -1 struct cmdAttrs { - pid: pid = invalidPid + pid: pid = invalidPid } fn strSliceToCstrSlice(&s: []str, mut &bargs: [][]byte): []*integ::Char { - mut cs := make([]*integ::Char, len(s) + 1) - bargs = make([][]byte, len(s)) - for i, arg in s { - mut barg := integ::StrToBytes(arg) - bargs[i] = barg - cs[i] = unsafe { (*integ::Char)(&barg[0]) } - } - cs[len(cs)-1] = nil - ret cs + mut cs := make([]*integ::Char, len(s) + 1) + bargs = make([][]byte, len(s)) + for i, arg in s { + mut barg := integ::StrToBytes(arg) + bargs[i] = barg + cs[i] = unsafe { (*integ::Char)(&barg[0]) } + } + cs[len(cs)-1] = nil + ret cs } fn execvp(&file: str, &argv: []str): int { - mut bargs := [][]byte(nil) // Avoid deallocation of converted args for safety. - cargv := strSliceToCstrSlice(argv, bargs) - s := integ::StrToBytes(file) - unsafe { - ret integ::Emit[int]("execvp({}, (char*const*){})", (*integ::Char)(&s[0]), &cargv[0]) - } + mut bargs := [][]byte(nil) // Avoid deallocation of converted args for safety. + cargv := strSliceToCstrSlice(argv, bargs) + s := integ::StrToBytes(file) + unsafe { + ret integ::Emit[int]("execvp({}, (char*const*){})", (*integ::Char)(&s[0]), &cargv[0]) + } } fn setenv(&envv: []str)! { - const Overwrite = 1 - for _, env in envv { - i := fastbytes::FindByteStr(env, '=') - if i == -1 { - error(ProcessError.Env) - } - unsafe { - key := integ::StrToBytes(env[:i]) - if len(env)-i == 1 { - val := "\x00" - if cpp.setenv((*integ::Char)(&key[0]), (*integ::Char)(&val[0]), Overwrite) == -1 { - error(ProcessError.Env) - } - } else { - val := integ::StrToBytes(env[i+1:]) - if cpp.setenv((*integ::Char)(&key[0]), (*integ::Char)(&val[0]), Overwrite) == -1 { - error(ProcessError.Env) - } - } - } - } + const Overwrite = 1 + for _, env in envv { + i := fastbytes::FindByteStr(env, '=') + if i == -1 { + error(ProcessError.Env) + } + unsafe { + key := integ::StrToBytes(env[:i]) + if len(env)-i == 1 { + val := "\x00" + if cpp.setenv((*integ::Char)(&key[0]), (*integ::Char)(&val[0]), Overwrite) == -1 { + error(ProcessError.Env) + } + } else { + val := integ::StrToBytes(env[i+1:]) + if cpp.setenv((*integ::Char)(&key[0]), (*integ::Char)(&val[0]), Overwrite) == -1 { + error(ProcessError.Env) + } + } + } + } } impl Cmd { - fn spawn(self)! { - if self.attrs.pid != invalidPid { - panic("command is already spawned") - } - path := self.path - let pipe: [2]integ::Int - if unsafe { cpp.pipe(&pipe[0]) } == -1 { - error(ProcessError.Spawn) - } - if sys::Fcntl(int(pipe[1]), cpp.F_SETFD, cpp.fcntl(int(pipe[1]), cpp.F_GETFD)|cpp.FD_CLOEXEC) == -1 { - sys::Close(int(pipe[0])) - sys::Close(int(pipe[1])) - error(ProcessError.Spawn) - } - self.attrs.pid = cpp.fork() - match self.attrs.pid { - | -1: - error(ProcessError.Spawn) - | 0: - sys::Close(int(pipe[0])) - mut args := make([]str, 1, 1 + len(self.Args)) - args[0] = path - args = append(args, self.Args...) - setenv(self.Env) else { error(error) } - execvp(path, args) - code := conv::Itoa(sys::GetLastErrno()) - unsafe { sys::Write(int(pipe[1]), &code[0], uint(len(code))) } - sys::Close(int(pipe[1])) - Exit(1) - |: - sys::Close(int(pipe[1])) - let mut buf: [16]byte - n := unsafe { sys::Read(int(pipe[0]), &buf[0], uint(len(buf))) } - sys::Close(int(pipe[0])) - if n != 0 { - self.attrs.pid = invalidPid - code, _ := unsafe { conv::AtoiBp(&buf[0], n) } - error(processErrorFromCode(code)) - } - } - } + fn spawn(self)! { + if self.attrs.pid != invalidPid { + panic("command is already spawned") + } + path := self.path + let pipe: [2]integ::Int + if unsafe { cpp.pipe(&pipe[0]) } == -1 { + error(ProcessError.Spawn) + } + if sys::Fcntl(int(pipe[1]), cpp.F_SETFD, cpp.fcntl(int(pipe[1]), cpp.F_GETFD)|cpp.FD_CLOEXEC) == -1 { + sys::Close(int(pipe[0])) + sys::Close(int(pipe[1])) + error(ProcessError.Spawn) + } + self.attrs.pid = cpp.fork() + match self.attrs.pid { + | -1: + error(ProcessError.Spawn) + | 0: + sys::Close(int(pipe[0])) + mut args := make([]str, 1, 1 + len(self.Args)) + args[0] = path + args = append(args, self.Args...) + setenv(self.Env) else { error(error) } + execvp(path, args) + code := conv::Itoa(sys::GetLastErrno()) + unsafe { sys::Write(int(pipe[1]), &code[0], uint(len(code))) } + sys::Close(int(pipe[1])) + Exit(1) + |: + sys::Close(int(pipe[1])) + let mut buf: [16]byte + n := unsafe { sys::Read(int(pipe[0]), &buf[0], uint(len(buf))) } + sys::Close(int(pipe[0])) + if n != 0 { + self.attrs.pid = invalidPid + code, _ := unsafe { conv::AtoiBp(&buf[0], n) } + error(processErrorFromCode(code)) + } + } + } - fn kill(self)! { - if self.attrs.pid == invalidPid { - panic("command is not spawned") - } - if cpp.kill(self.attrs.pid, 1) != 0 { - error(getLastProcessError()) - } - self.attrs.pid = invalidPid - } + fn kill(self)! { + if self.attrs.pid == invalidPid { + panic("command is not spawned") + } + if cpp.kill(self.attrs.pid, 1) != 0 { + error(getLastProcessError()) + } + self.attrs.pid = invalidPid + } - fn wait(self)!: int { - if self.attrs.pid == invalidPid { - panic("command is not spawned") - } - mut stat := 0 - unsafe { - if cpp.waitpid(self.attrs.pid, (*integ::Int)(&stat), 0) == -1 { - error(getLastProcessError()) - } - } - self.attrs.pid = invalidPid - ret cpp.WEXITSTATUS(stat) - } + fn wait(self)!: int { + if self.attrs.pid == invalidPid { + panic("command is not spawned") + } + mut stat := 0 + unsafe { + if cpp.waitpid(self.attrs.pid, (*integ::Int)(&stat), 0) == -1 { + error(getLastProcessError()) + } + } + self.attrs.pid = invalidPid + ret cpp.WEXITSTATUS(stat) + } } \ No newline at end of file diff --git a/std/process/cmd_windows.jule b/std/process/cmd_windows.jule index 0aafbe10c..e120e692e 100644 --- a/std/process/cmd_windows.jule +++ b/std/process/cmd_windows.jule @@ -15,13 +15,13 @@ cpp let INFINITE: int #typedef cpp struct STARTUPINFOW { - cb: uint + cb: uint } #typedef cpp struct PROCESS_INFORMATION { - hProcess: cpp.HANDLE - hThread: cpp.HANDLE + hProcess: cpp.HANDLE + hThread: cpp.HANDLE } cpp unsafe fn CreateProcessW(*u16, *u16, *unsafe, *unsafe, int, integ: integ::LongLong, *unsafe, *u16, *cpp.STARTUPINFOW, *cpp.PROCESS_INFORMATION): int @@ -33,142 +33,142 @@ cpp unsafe fn WaitForSingleObject(cpp.HANDLE, int) const _CREATE_UNICODE_ENVIRONMENT = 0x00000400 struct cmdAttrs { - hProcess: cpp.HANDLE - hThread: cpp.HANDLE + hProcess: cpp.HANDLE + hThread: cpp.HANDLE } impl Cmd { - fn spawn(self)! { - if self.attrs.hProcess != nil { - panic("command is already spawned") - } - mut startupInfo := cpp.STARTUPINFOW{} - mut processInfo := cpp.PROCESS_INFORMATION{} - unsafe { - cpp.ZeroMemory(&startupInfo, mem::SizeOf(startupInfo)) - cpp.ZeroMemory(&processInfo, mem::SizeOf(processInfo)) - } - startupInfo.cb = mem::SizeOf(startupInfo) - mut args := make([]str, 1, 1 + len(self.Args)) - args[0] = self.path - args = append(args, self.Args...) - argv := integ::UTF16FromStr(makeCmdLine(args)) - env := createEnvBlock(self.Env) else { error(error) } - mut envp := &env[0] - if len(self.Env) == 0 { - envp = nil - } - const flags = _CREATE_UNICODE_ENVIRONMENT - unsafe { - if cpp.CreateProcessW(nil, (*integ::Wchar)(&argv[0]), nil, nil, 0, - flags, envp, nil, &startupInfo, &processInfo) == 0 { - error(getLastProcessError()) - } - } - self.attrs.hProcess = processInfo.hProcess - self.attrs.hThread = processInfo.hThread - } - - fn kill(self)! { - if self.attrs.hProcess == nil { - panic("command is not spawned") - } - if unsafe { cpp.TerminateProcess(self.attrs.hProcess, 0) } { - self.attrs.hProcess = nil - self.attrs.hThread = nil - ret - } - error(-1) - } - - fn wait(self)!: int { - if self.attrs.hProcess == nil { - panic("command is not spawned") - } - unsafe { cpp.WaitForSingleObject(self.attrs.hProcess, cpp.INFINITE) } - mut exitCode := integ::LongLong(-1) - unsafe { - cpp.GetExitCodeProcess(self.attrs.hProcess, &exitCode) - sys::CloseHandle(uintptr(self.attrs.hProcess)) - sys::CloseHandle(uintptr(self.attrs.hThread)) - } - self.attrs.hProcess = nil - self.attrs.hThread = nil - ret int(exitCode) - } + fn spawn(self)! { + if self.attrs.hProcess != nil { + panic("command is already spawned") + } + mut startupInfo := cpp.STARTUPINFOW{} + mut processInfo := cpp.PROCESS_INFORMATION{} + unsafe { + cpp.ZeroMemory(&startupInfo, mem::SizeOf(startupInfo)) + cpp.ZeroMemory(&processInfo, mem::SizeOf(processInfo)) + } + startupInfo.cb = mem::SizeOf(startupInfo) + mut args := make([]str, 1, 1 + len(self.Args)) + args[0] = self.path + args = append(args, self.Args...) + argv := integ::UTF16FromStr(makeCmdLine(args)) + env := createEnvBlock(self.Env) else { error(error) } + mut envp := &env[0] + if len(self.Env) == 0 { + envp = nil + } + const flags = _CREATE_UNICODE_ENVIRONMENT + unsafe { + if cpp.CreateProcessW(nil, (*integ::Wchar)(&argv[0]), nil, nil, 0, + flags, envp, nil, &startupInfo, &processInfo) == 0 { + error(getLastProcessError()) + } + } + self.attrs.hProcess = processInfo.hProcess + self.attrs.hThread = processInfo.hThread + } + + fn kill(self)! { + if self.attrs.hProcess == nil { + panic("command is not spawned") + } + if unsafe { cpp.TerminateProcess(self.attrs.hProcess, 0) } { + self.attrs.hProcess = nil + self.attrs.hThread = nil + ret + } + error(-1) + } + + fn wait(self)!: int { + if self.attrs.hProcess == nil { + panic("command is not spawned") + } + unsafe { cpp.WaitForSingleObject(self.attrs.hProcess, cpp.INFINITE) } + mut exitCode := integ::LongLong(-1) + unsafe { + cpp.GetExitCodeProcess(self.attrs.hProcess, &exitCode) + sys::CloseHandle(uintptr(self.attrs.hProcess)) + sys::CloseHandle(uintptr(self.attrs.hThread)) + } + self.attrs.hProcess = nil + self.attrs.hThread = nil + ret int(exitCode) + } } // Escapes the string s, as per escapeArg, appends the result to s. fn appendEscapeArg(mut &s: StrBuilder, arg: str) { - if len(arg) == 0 { - s.WriteStr(`""`) - ret - } - - mut needsBackslash := false - mut hasSpace := false - mut i := 0 - for i < len(arg); i++ { - match arg[i] { - | '"' | '\\': - needsBackslash = true - | ' ' | '\t': - hasSpace = true - } - } - - if !needsBackslash && !hasSpace { - // No special handling required; normal case. - s.WriteStr(arg) - ret - } - if !needsBackslash { - // hasSpace is true, so we need to quote the string. - s.WriteByte('"') - s.WriteStr(arg) - s.WriteByte('"') - ret - } - - if hasSpace { - s.WriteByte('"') - } - mut slashes := 0 - i = 0 - for i < len(arg); i++ { - c := arg[i] - match c { - | '\\': - slashes++ - | '"': - for slashes > 0; slashes-- { - s.WriteByte('\\') - } - s.WriteByte('\\') - |: - slashes = 0 - } - s.WriteByte(c) - } - if hasSpace { - for slashes > 0; slashes-- { - s.WriteByte('\\') - } - s.WriteByte('"') - } + if len(arg) == 0 { + s.WriteStr(`""`) + ret + } + + mut needsBackslash := false + mut hasSpace := false + mut i := 0 + for i < len(arg); i++ { + match arg[i] { + | '"' | '\\': + needsBackslash = true + | ' ' | '\t': + hasSpace = true + } + } + + if !needsBackslash && !hasSpace { + // No special handling required; normal case. + s.WriteStr(arg) + ret + } + if !needsBackslash { + // hasSpace is true, so we need to quote the string. + s.WriteByte('"') + s.WriteStr(arg) + s.WriteByte('"') + ret + } + + if hasSpace { + s.WriteByte('"') + } + mut slashes := 0 + i = 0 + for i < len(arg); i++ { + c := arg[i] + match c { + | '\\': + slashes++ + | '"': + for slashes > 0; slashes-- { + s.WriteByte('\\') + } + s.WriteByte('\\') + |: + slashes = 0 + } + s.WriteByte(c) + } + if hasSpace { + for slashes > 0; slashes-- { + s.WriteByte('\\') + } + s.WriteByte('"') + } } // Builds a command line out of args by escaping "special" // characters and joining the arguments with spaces. fn makeCmdLine(args: []str): str { - mut s := StrBuilder.New(1 << 4) - for _, arg in args { - if s.Len() > 0 { - s.WriteByte(' ') - } - appendEscapeArg(s, arg) - } - ret s.Str() + mut s := StrBuilder.New(1 << 4) + for _, arg in args { + if s.Len() > 0 { + s.WriteByte(' ') + } + appendEscapeArg(s, arg) + } + ret s.Str() } // Converts an array of environment strings into @@ -177,24 +177,24 @@ fn makeCmdLine(args: []str): str { // Last bytes are two UCS-2 NULLs, or four NULL bytes. // If any string contains a NULL, it returns (nil, EINVAL). fn createEnvBlock(env: []str)!: []u16 { - if len(env) == 0 { - ret utf16::Encode([]rune("\x00\x00")) - } - mut n := 0 - for _, s in env { - if fastbytes::FindByteStr(s, 0) != -1 { - error(ProcessError.Env) - } - n += len(s) + 1 - } - n++ - mut b := make([]u16, 0, n) - for _, s in env { - for _, c in []rune(s) { - b = utf16::AppendRune(b, c) - } - b = utf16::AppendRune(b, 0) - } - b = utf16::AppendRune(b, 0) - ret b + if len(env) == 0 { + ret utf16::Encode([]rune("\x00\x00")) + } + mut n := 0 + for _, s in env { + if fastbytes::FindByteStr(s, 0) != -1 { + error(ProcessError.Env) + } + n += len(s) + 1 + } + n++ + mut b := make([]u16, 0, n) + for _, s in env { + for _, c in []rune(s) { + b = utf16::AppendRune(b, c) + } + b = utf16::AppendRune(b, 0) + } + b = utf16::AppendRune(b, 0) + ret b } \ No newline at end of file diff --git a/std/process/error.jule b/std/process/error.jule index e4b5abbe5..ffc0b8512 100644 --- a/std/process/error.jule +++ b/std/process/error.jule @@ -4,9 +4,9 @@ // Process error codes. enum ProcessError { - Denied, // Permission is not enough. - NotExist, // One or more components of the new process path name of the file do not exist or is a null pathname. - Env, // Environment variables are represented in wrong format or an error occurred when assigning. - Spawn, // An error occurred spawning. - Other, // Other system error. + Denied, // Permission is not enough. + NotExist, // One or more components of the new process path name of the file do not exist or is a null pathname. + Env, // Environment variables are represented in wrong format or an error occurred when assigning. + Spawn, // An error occurred spawning. + Other, // Other system error. } \ No newline at end of file diff --git a/std/process/error_unix.jule b/std/process/error_unix.jule index 2692b8b4f..004627081 100644 --- a/std/process/error_unix.jule +++ b/std/process/error_unix.jule @@ -3,23 +3,23 @@ // license that can be found in the LICENSE file. use std::sys::{ - GetLastErrno, - EACCES, - ENOENT, + GetLastErrno, + EACCES, + ENOENT, } fn processErrorFromCode(code: int): ProcessError { - match code { - | EACCES: - ret ProcessError.Denied - | ENOENT: - ret ProcessError.NotExist - |: - ret ProcessError.Other - } + match code { + | EACCES: + ret ProcessError.Denied + | ENOENT: + ret ProcessError.NotExist + |: + ret ProcessError.Other + } } // Returns last process error by errno. fn getLastProcessError(): ProcessError { - ret processErrorFromCode(GetLastErrno()) + ret processErrorFromCode(GetLastErrno()) } \ No newline at end of file diff --git a/std/process/error_windows.jule b/std/process/error_windows.jule index 284a70b2f..8032176b4 100644 --- a/std/process/error_windows.jule +++ b/std/process/error_windows.jule @@ -9,18 +9,18 @@ const _ERROR_PATH_NOT_FOUND = 0x3 const _ERROR_ACCESS_DENIED = 0x5 fn processErrorFromCode(code: int): ProcessError { - match code { - | _ERROR_ACCESS_DENIED: - ret ProcessError.Denied - | _ERROR_FILE_NOT_FOUND - | _ERROR_PATH_NOT_FOUND: - ret ProcessError.NotExist - |: - ret ProcessError.Other - } + match code { + | _ERROR_ACCESS_DENIED: + ret ProcessError.Denied + | _ERROR_FILE_NOT_FOUND + | _ERROR_PATH_NOT_FOUND: + ret ProcessError.NotExist + |: + ret ProcessError.Other + } } // Returns last process error by error. fn getLastProcessError(): ProcessError { - ret processErrorFromCode(int(sys::GetLastError())) + ret processErrorFromCode(int(sys::GetLastError())) } \ No newline at end of file diff --git a/std/queue/queue.jule b/std/queue/queue.jule index 518792373..af534b419 100644 --- a/std/queue/queue.jule +++ b/std/queue/queue.jule @@ -13,115 +13,115 @@ const growFactor = 2 // Queues aren't use shared allocation between themselves. // Allocates new space and copies (not deep copy) items into space. struct Queue[T] { - mem: dynar::Dynar[T] + mem: dynar::Dynar[T] } impl Queue { - // Returns new queue instance with capacity. - static fn New(cap: int): Queue[T] { - mut queue := Queue[T]{ - mem: dynar::Dynar[T].New(), - } - if cap > 0 { - queue.resize(cap) - } - ret queue - } + // Returns new queue instance with capacity. + static fn New(cap: int): Queue[T] { + mut queue := Queue[T]{ + mem: dynar::Dynar[T].New(), + } + if cap > 0 { + queue.resize(cap) + } + ret queue + } - fn resize(mut self, n: int) { - ok := self.mem.Resize(n) - if !ok { - panic("Queue[T]: heap reallocation failed") - } - } + fn resize(mut self, n: int) { + ok := self.mem.Resize(n) + if !ok { + panic("Queue[T]: heap reallocation failed") + } + } - // Deallocate heap. - fn Dispose(mut self) { - self.mem.Dispose() - } + // Deallocate heap. + fn Dispose(mut self) { + self.mem.Dispose() + } - // Set capacity to length. - // Removes additional capacity that waiting to use. - // Allocates new memory to cut additional capacity. - fn Fit(mut self) { - if self.Len() != self.Cap() { - self.resize(self.Len()) - } - } + // Set capacity to length. + // Removes additional capacity that waiting to use. + // Allocates new memory to cut additional capacity. + fn Fit(mut self) { + if self.Len() != self.Cap() { + self.resize(self.Len()) + } + } - // Returns length of queue. - // Another meaning is count of elements. - fn Len(self): int { - ret self.mem.Buff.len - } + // Returns length of queue. + // Another meaning is count of elements. + fn Len(self): int { + ret self.mem.Buff.len + } - // Returns capacity of queue. - // Another meaning is additional redy-to-use allocation size. - fn Cap(self): int { - ret self.mem.Buff.cap - } + // Returns capacity of queue. + // Another meaning is additional redy-to-use allocation size. + fn Cap(self): int { + ret self.mem.Buff.cap + } - // Reports whether queue is empty. - fn Empty(self): bool { - ret self.Len() == 0 - } + // Reports whether queue is empty. + fn Empty(self): bool { + ret self.Len() == 0 + } - // Removes all elements. - // Does not deallocates buffer, keeps capacity. - fn Clear(mut self) { - self.mem.Buff.len = 0 - } + // Removes all elements. + // Does not deallocates buffer, keeps capacity. + fn Clear(mut self) { + self.mem.Buff.len = 0 + } - // Pushes element to rear of the queue. - fn Push(mut self, mut t: T) { - if self.Len() >= self.Cap() { - self.resize((self.Cap() * growFactor) + 1) - } - unsafe { - self.mem.Buff.heap[self.Len()] = t - } - self.mem.Buff.len++ - } + // Pushes element to rear of the queue. + fn Push(mut self, mut t: T) { + if self.Len() >= self.Cap() { + self.resize((self.Cap() * growFactor) + 1) + } + unsafe { + self.mem.Buff.heap[self.Len()] = t + } + self.mem.Buff.len++ + } - // Returns element front of the queue, then removes front element. - // Panics if queue is empty. - fn Pop(mut self): T { - if self.Empty() { - panic("Queue[T]: pop with zero-length queue") - } - mut t := unsafe { self.mem.Buff.heap[0] } - if self.Len() != 1 { - self.mem.ShiftLeft(1, self.Len(), 1) - } - self.mem.Buff.len-- - ret t - } + // Returns element front of the queue, then removes front element. + // Panics if queue is empty. + fn Pop(mut self): T { + if self.Empty() { + panic("Queue[T]: pop with zero-length queue") + } + mut t := unsafe { self.mem.Buff.heap[0] } + if self.Len() != 1 { + self.mem.ShiftLeft(1, self.Len(), 1) + } + self.mem.Buff.len-- + ret t + } - // Returns front element of the queue. - // Panics if queue is empty. - fn Front(mut self): T { - if self.Empty() { - panic("Queue[T]: front with zero-length queue") - } - unsafe { - ret self.mem.Buff.heap[0] - } - } + // Returns front element of the queue. + // Panics if queue is empty. + fn Front(mut self): T { + if self.Empty() { + panic("Queue[T]: front with zero-length queue") + } + unsafe { + ret self.mem.Buff.heap[0] + } + } - // Returns slice that contains elements of queue. - // Slice is not mutable reference to internal buffer, but can effect internal - // buffer if T is mutable type. - // Appends elements in front-to-rear order. - fn Slice(mut self): []T { - if self.Empty() { - ret nil - } - mut s := make([]T, 0, self.Len()) - mut i := self.mem.Buff.heap - j := self.mem.Buff.heap + self.Len() - for i < j; i++ { - s = append(s, unsafe { *i }) - } - ret s - } + // Returns slice that contains elements of queue. + // Slice is not mutable reference to internal buffer, but can effect internal + // buffer if T is mutable type. + // Appends elements in front-to-rear order. + fn Slice(mut self): []T { + if self.Empty() { + ret nil + } + mut s := make([]T, 0, self.Len()) + mut i := self.mem.Buff.heap + j := self.mem.Buff.heap + self.Len() + for i < j; i++ { + s = append(s, unsafe { *i }) + } + ret s + } } \ No newline at end of file diff --git a/std/slices/slices.jule b/std/slices/slices.jule index f4a245356..769029c58 100644 --- a/std/slices/slices.jule +++ b/std/slices/slices.jule @@ -6,72 +6,72 @@ // The nil slices considered as zero-length slices. // The floating-point NaNs are not considered equal. fn Equal[S: []E, E: comparable](s1: S, s2: S): bool { - if len(s1) != len(s2) { - ret false - } - for i, e in s1 { - if e != s2[i] { - ret false - } - } - ret true + if len(s1) != len(s2) { + ret false + } + for i, e in s1 { + if e != s2[i] { + ret false + } + } + ret true } // Returns index of first matched element with specified element, // returns -1 if not exist any match. Starts searching at left // of slice to right. fn Find[S: []E, E: comparable](s: S, e: E): int { - for i, e2 in s { - if e == e2 { - ret i - } - } - ret -1 + for i, e2 in s { + if e == e2 { + ret i + } + } + ret -1 } // Returns index of first matched element with specified element, // returns -1 if not exist any match. Starts searching at right // of slice to left. fn FindLast[S: []E, E: comparable](s: S, e: E): int { - mut i := len(s) - 1 - for i >= 0; i-- { - if s[i] == e { - ret i - } - } - ret -1 + mut i := len(s) - 1 + for i >= 0; i-- { + if s[i] == e { + ret i + } + } + ret -1 } // Reports whether slice includes e. fn Contains[S: []E, E: comparable](s: S, e: E): bool { - ret Find[S, E](s, e) >= 0 + ret Find[S, E](s, e) >= 0 } // Counts the number of matched elements with e in s. fn Count[S: []E, E: comparable](s: S, e: E): (n: int) { - for _, e2 in s { - if e2 == e { - n++ - } - } - ret + for _, e2 in s { + if e2 == e { + n++ + } + } + ret } // Replaces matched slice elements with old to new. // Returns count of replacements. fn Replace[S: []E, E: comparable](mut s: S, old: E, mut new: E): (n: int) { - for i, e in s { - if e == old { - s[i] = new - n++ - } - } - ret + for i, e in s { + if e == old { + s[i] = new + n++ + } + } + ret } // Reverses elements of the slice. fn Reverse[S: []E, E](mut s: S) { - for i in s[:len(s)>>1] { - s[i], s[len(s)-i-1] = s[len(s)-i-1], s[i] - } + for i in s[:len(s)>>1] { + s[i], s[len(s)-i-1] = s[len(s)-i-1], s[i] + } } \ No newline at end of file diff --git a/std/slices/slices_test.jule b/std/slices/slices_test.jule index ee595e1ac..7a15ff401 100644 --- a/std/slices/slices_test.jule +++ b/std/slices/slices_test.jule @@ -8,94 +8,94 @@ use std::testing::{T} #test fn testEqual(t: &T) { - t.Assert(Equal([1, 2, 3], [1, 2, 3]), "Equal([1, 2, 3], [1, 2, 3]) != true") - t.Assert(Equal([0], [0]), "Equal([0], [0]) != true") - t.Assert(Equal[[]byte, byte]([], nil), "Equal([], nil) != true") - t.Assert(Equal[[]byte, byte](nil, []), "Equal(nil, []) != true") - t.Assert(!Equal[[]byte, byte]([0], nil), "Equal([0], nil) != false") - t.Assert(!Equal([1, 2, 3], [1, 2]), "Equal([1, 2, 3], [1, 2]) != false") - t.Assert(!Equal([1, 2], [1, 2, 3]), "Equal([1, 2], [1, 2, 3]) != false") + t.Assert(Equal([1, 2, 3], [1, 2, 3]), "Equal([1, 2, 3], [1, 2, 3]) != true") + t.Assert(Equal([0], [0]), "Equal([0], [0]) != true") + t.Assert(Equal[[]byte, byte]([], nil), "Equal([], nil) != true") + t.Assert(Equal[[]byte, byte](nil, []), "Equal(nil, []) != true") + t.Assert(!Equal[[]byte, byte]([0], nil), "Equal([0], nil) != false") + t.Assert(!Equal([1, 2, 3], [1, 2]), "Equal([1, 2, 3], [1, 2]) != false") + t.Assert(!Equal([1, 2], [1, 2, 3]), "Equal([1, 2], [1, 2, 3]) != false") } #test fn testFind(t: &T) { - s := [1, 2, 3, 4, 6, 5, 6] - t.Assert(Find(s, 20) == -1, "Find(s, 20) != -1") - t.Assert(Find(s, 1) == 0, "Find(s, 1) != 0") - t.Assert(Find(s, 2) == 1, "Find(s, 2) != 1") - t.Assert(Find(s, 3) == 2, "Find(s, 3) != 2") - t.Assert(Find(s, 4) == 3, "Find(s, 4) != 3") - t.Assert(Find(s, 5) == 5, "Find(s, 5) != 5") - t.Assert(Find(s, 6) == 4, "Find(s, 6) != 4") + s := [1, 2, 3, 4, 6, 5, 6] + t.Assert(Find(s, 20) == -1, "Find(s, 20) != -1") + t.Assert(Find(s, 1) == 0, "Find(s, 1) != 0") + t.Assert(Find(s, 2) == 1, "Find(s, 2) != 1") + t.Assert(Find(s, 3) == 2, "Find(s, 3) != 2") + t.Assert(Find(s, 4) == 3, "Find(s, 4) != 3") + t.Assert(Find(s, 5) == 5, "Find(s, 5) != 5") + t.Assert(Find(s, 6) == 4, "Find(s, 6) != 4") } #test fn testFindLast(t: &T) { - s := [1, 2, 3, 4, 6, 5, 6] - t.Assert(FindLast(s, 20) == -1, "FindLast(s, 20) != -1") - t.Assert(FindLast(s, 1) == 0, "FindLast(s, 1) != 0") - t.Assert(FindLast(s, 2) == 1, "FindLast(s, 2) != 1") - t.Assert(FindLast(s, 3) == 2, "FindLast(s, 3) != 2") - t.Assert(FindLast(s, 4) == 3, "FindLast(s, 4) != 3") - t.Assert(FindLast(s, 5) == 5, "FindLast(s, 5) != 5") - t.Assert(FindLast(s, 6) == 6, "FindLast(s, 6) != 6") + s := [1, 2, 3, 4, 6, 5, 6] + t.Assert(FindLast(s, 20) == -1, "FindLast(s, 20) != -1") + t.Assert(FindLast(s, 1) == 0, "FindLast(s, 1) != 0") + t.Assert(FindLast(s, 2) == 1, "FindLast(s, 2) != 1") + t.Assert(FindLast(s, 3) == 2, "FindLast(s, 3) != 2") + t.Assert(FindLast(s, 4) == 3, "FindLast(s, 4) != 3") + t.Assert(FindLast(s, 5) == 5, "FindLast(s, 5) != 5") + t.Assert(FindLast(s, 6) == 6, "FindLast(s, 6) != 6") } #test fn testContains(t: &T) { - s := [1, 2, 3, 4, 6, 5, 6] - t.Assert(!Contains(s, 20), "Contains(s, 20)") - t.Assert(Contains(s, 1), "!Contains(s, 1)") - t.Assert(Contains(s, 2), "!Contains(s, 2)") - t.Assert(Contains(s, 3), "!Contains(s, 3)") - t.Assert(Contains(s, 4), "!Contains(s, 4)") - t.Assert(Contains(s, 5), "!Contains(s, 5)") - t.Assert(Contains(s, 6), "!Contains(s, 6)") + s := [1, 2, 3, 4, 6, 5, 6] + t.Assert(!Contains(s, 20), "Contains(s, 20)") + t.Assert(Contains(s, 1), "!Contains(s, 1)") + t.Assert(Contains(s, 2), "!Contains(s, 2)") + t.Assert(Contains(s, 3), "!Contains(s, 3)") + t.Assert(Contains(s, 4), "!Contains(s, 4)") + t.Assert(Contains(s, 5), "!Contains(s, 5)") + t.Assert(Contains(s, 6), "!Contains(s, 6)") } #test fn testCount(t: &T) { - mut s := [1, 2, 3, 4, 6, 5, 6] - t.Assert(Count(s, 6) == 2, "Count(s, 6) != 2") + mut s := [1, 2, 3, 4, 6, 5, 6] + t.Assert(Count(s, 6) == 2, "Count(s, 6) != 2") - mut s2 := ["hello", "world", "!", "!", "!"] - t.Assert(Count(s2, "!") == 3, "Count(s2, \"!\") != 3") + mut s2 := ["hello", "world", "!", "!", "!"] + t.Assert(Count(s2, "!") == 3, "Count(s2, \"!\") != 3") - let mut s3: []int = [] - t.Assert(Count(s3, 2) == 0, "Count(s3, 2) != 0") + let mut s3: []int = [] + t.Assert(Count(s3, 2) == 0, "Count(s3, 2) != 0") } #test fn test_replace(t: &T) { - mut s := [1, 2, 3, 4, 6, 5, 6] - rs := [1, 2, 3, 4, 10, 5, 10] - t.Assert(Replace(s, 6, 10) == 2, "Replace(s, 6, 10) != 2") - t.Assert(Equal(s, rs), "Replace(s, 6, 10) != rs") + mut s := [1, 2, 3, 4, 6, 5, 6] + rs := [1, 2, 3, 4, 10, 5, 10] + t.Assert(Replace(s, 6, 10) == 2, "Replace(s, 6, 10) != 2") + t.Assert(Equal(s, rs), "Replace(s, 6, 10) != rs") - mut s2 := ["hello", "world", "!"] - rs2 := ["hi", "world", "!"] - t.Assert(Replace(s2, "hello", "hi") == 1, "Replace(s2, \"hello\", \"hi\") != 1") - t.Assert(Equal(s2, rs2), "Replace(s2, \"hello\", \"hi\") != rs2") + mut s2 := ["hello", "world", "!"] + rs2 := ["hi", "world", "!"] + t.Assert(Replace(s2, "hello", "hi") == 1, "Replace(s2, \"hello\", \"hi\") != 1") + t.Assert(Equal(s2, rs2), "Replace(s2, \"hello\", \"hi\") != rs2") - mut s3 := [0, 1, 1, 2] - t.Assert(Replace(s3, 3, 1) == 0, "Replace(s3, 3, 1) != 0") - t.Assert(Equal(s3, s3), "Replace(s3, 3, 1) != s3") + mut s3 := [0, 1, 1, 2] + t.Assert(Replace(s3, 3, 1) == 0, "Replace(s3, 3, 1) != 0") + t.Assert(Equal(s3, s3), "Replace(s3, 3, 1) != s3") } #test fn testReverse(t: &T) { - mut s := [1, 2, 3, 4, 6, 5, 6] - rs := [6, 5, 6, 4, 3, 2, 1] - Reverse(s) - t.Assert(Equal(s, rs), "s != rs") + mut s := [1, 2, 3, 4, 6, 5, 6] + rs := [6, 5, 6, 4, 3, 2, 1] + Reverse(s) + t.Assert(Equal(s, rs), "s != rs") - mut s2 := ["hello", "world", "!"] - rs2 := ["!", "world", "hello"] - Reverse(s2) - t.Assert(Equal(s2, rs2), "s2 != rs2") + mut s2 := ["hello", "world", "!"] + rs2 := ["!", "world", "hello"] + Reverse(s2) + t.Assert(Equal(s2, rs2), "s2 != rs2") - mut s3 := [1, 2] - rs3 := [2, 1] - Reverse(s3) - t.Assert(Equal(s3, rs3), "s3 != rs3") + mut s3 := [1, 2] + rs3 := [2, 1] + Reverse(s3) + t.Assert(Equal(s3, rs3), "s3 != rs3") } \ No newline at end of file diff --git a/std/slices/sort.jule b/std/slices/sort.jule index 8bcf98af5..d64aad3fe 100644 --- a/std/slices/sort.jule +++ b/std/slices/sort.jule @@ -41,19 +41,19 @@ use cmp for std::internal::cmp // Sorts a slice of any ordered type in ascending order. // When sorting floating-point numbers, NaNs are ordered before other values. fn Sort[S: []E, E: ordered](mut s: S) { - n := len(s) - pdqsort(s, 0, n, bits::Len(uint(n))) + n := len(s) + pdqsort(s, 0, n, bits::Len(uint(n))) } // Reports whether x is sorted in ascending order. fn IsSorted[S: []E, E: ordered](mut s: S): bool { - mut i := len(s) - 1 - for i > 0; i-- { - if cmp::Less(s[i], s[i-1]) { - ret false - } - } - ret true + mut i := len(s) - 1 + for i > 0; i-- { + if cmp::Less(s[i], s[i-1]) { + ret false + } + } + ret true } // Sorts the slice s in ascending order as determined by the cmp @@ -64,21 +64,21 @@ fn IsSorted[S: []E, E: ordered](mut s: S): bool { // SortFunc requires that cmp is a strict weak ordering. // See https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings. fn SortFunc[S: []E, E](mut s: S, cmp: fn(a: E, b: E): int) { - n := len(s) - pdqsortFunc(s, 0, n, bits::Len(uint(n)), cmp) + n := len(s) + pdqsortFunc(s, 0, n, bits::Len(uint(n)), cmp) } fn nextPowerOfTwo(length: int): uint { - shift := uint(bits::Len(uint(length))) - ret uint(1 << shift) + shift := uint(bits::Len(uint(length))) + ret uint(1 << shift) } // xorshift paper: https://www.jstatsoft.org/article/view/v008i14/xorshift.pdf type xorshift: u64 fn xorshiftNext(mut &r: xorshift): u64 { - r ^= r << 13 - r ^= r >> 17 - r ^= r << 5 - ret u64(r) + r ^= r << 13 + r ^= r >> 17 + r ^= r << 5 + ret u64(r) } \ No newline at end of file diff --git a/std/slices/sort_test.jule b/std/slices/sort_test.jule index a444e7285..1896e0b37 100644 --- a/std/slices/sort_test.jule +++ b/std/slices/sort_test.jule @@ -13,86 +13,86 @@ static caseF64sWithNaNs = [74.3, 59.0, math::Inf(1), 238.2, -784.0, 2.3, math::N static caseStrs = ["", "Hello", "foo", "bar", "foo", "f00", "%*&^*&^&", "***"] fn cloneSlice[T](s: T): T { - ret append(make(T, 0, len(s)), s...) + ret append(make(T, 0, len(s)), s...) } #test fn testInts(t: &T) { - mut case := cloneSlice(caseInts) - Sort(case) - if !IsSorted(case) { - t.Errorf("sorted: {}", caseInts) - t.Errorf(" got: {}", case) - } + mut case := cloneSlice(caseInts) + Sort(case) + if !IsSorted(case) { + t.Errorf("sorted: {}", caseInts) + t.Errorf(" got: {}", case) + } } #test fn testF64s(t: &T) { - mut case := cloneSlice(caseF64s) - Sort(case) - if !IsSorted(case) { - t.Errorf("sorted: {}", caseF64s) - t.Errorf(" got: {}", case) - } + mut case := cloneSlice(caseF64s) + Sort(case) + if !IsSorted(case) { + t.Errorf("sorted: {}", caseF64s) + t.Errorf(" got: {}", case) + } } #test fn testF64sWithNaNs(t: &T) { - mut case := cloneSlice(caseF64sWithNaNs) - Sort(case) - if !IsSorted(case) { - t.Errorf("sorted: {}", caseF64sWithNaNs) - t.Errorf(" got: {}", case) - } + mut case := cloneSlice(caseF64sWithNaNs) + Sort(case) + if !IsSorted(case) { + t.Errorf("sorted: {}", caseF64sWithNaNs) + t.Errorf(" got: {}", case) + } } #test fn testStrs(t: &T) { - mut case := cloneSlice(caseStrs) - Sort(case) - if !IsSorted(case) { - t.Errorf("sorted: {}", caseStrs) - t.Errorf(" got: {}", case) - } + mut case := cloneSlice(caseStrs) + Sort(case) + if !IsSorted(case) { + t.Errorf("sorted: {}", caseStrs) + t.Errorf(" got: {}", case) + } } #test fn testIntsFunc(t: &T) { - mut case := cloneSlice(caseInts) - SortFunc(case, fn(a: int, b: int): int { ret compare(a, b) }) - if !IsSorted(case) { - t.Errorf("sorted: {}", caseInts) - t.Errorf(" got: {}", case) - } + mut case := cloneSlice(caseInts) + SortFunc(case, fn(a: int, b: int): int { ret compare(a, b) }) + if !IsSorted(case) { + t.Errorf("sorted: {}", caseInts) + t.Errorf(" got: {}", case) + } } #test fn testF64sFunc(t: &T) { - mut case := cloneSlice(caseF64s) - SortFunc(case, fn(a: f64, b: f64): int { ret compare(a, b) }) - if !IsSorted(case) { - t.Errorf("sorted: {}", caseF64s) - t.Errorf(" got: {}", case) - } + mut case := cloneSlice(caseF64s) + SortFunc(case, fn(a: f64, b: f64): int { ret compare(a, b) }) + if !IsSorted(case) { + t.Errorf("sorted: {}", caseF64s) + t.Errorf(" got: {}", case) + } } #test fn testStrsFunc(t: &T) { - mut case := cloneSlice(caseStrs) - SortFunc(case, fn(a: str, b: str): int { ret compare(a, b) }) - if !IsSorted(case) { - t.Errorf("sorted: {}", caseStrs) - t.Errorf(" got: {}", case) - } + mut case := cloneSlice(caseStrs) + SortFunc(case, fn(a: str, b: str): int { ret compare(a, b) }) + if !IsSorted(case) { + t.Errorf("sorted: {}", caseStrs) + t.Errorf(" got: {}", case) + } } fn compare[T](a: T, b: T): int { - match { - | a < b: - ret -1 - | a > b: - ret +1 - |: - ret 0 - } + match { + | a < b: + ret -1 + | a > b: + ret +1 + |: + ret 0 + } } \ No newline at end of file diff --git a/std/slices/sortfunc.jule b/std/slices/sortfunc.jule index fc4307d92..b351a0cab 100644 --- a/std/slices/sortfunc.jule +++ b/std/slices/sortfunc.jule @@ -37,93 +37,93 @@ // Sorts data[a:b] using insertion sort. fn insertionSortFunc[S: []E, E](mut data: S, a: int, b: int, cmp: fn(a: E, b: E): int) { - mut i := a + 1 - for i < b; i++ { - mut j := i - for j > a && (cmp(data[j], data[j-1]) < 0); j-- { - data[j], data[j-1] = data[j-1], data[j] - } - } + mut i := a + 1 + for i < b; i++ { + mut j := i + for j > a && (cmp(data[j], data[j-1]) < 0); j-- { + data[j], data[j-1] = data[j-1], data[j] + } + } } // Implements the heap property on data[lo:hi]. // first is an offset into the array where the root of the heap lies. fn siftDownFunc[S: []E, E](mut data: S, lo: int, hi: int, first: int, cmp: fn(a: E, b: E): int) { - mut root := lo - for { - mut child := 2 * root + 1 - if child >= hi { - break - } - if child+1 < hi && (cmp(data[first+child], data[first+child+1]) < 0) { - child++ - } - if !(cmp(data[first+root], data[first+child]) < 0) { - ret - } - data[first+root], data[first+child] = data[first+child], data[first+root] - root = child - } + mut root := lo + for { + mut child := 2 * root + 1 + if child >= hi { + break + } + if child+1 < hi && (cmp(data[first+child], data[first+child+1]) < 0) { + child++ + } + if !(cmp(data[first+root], data[first+child]) < 0) { + ret + } + data[first+root], data[first+child] = data[first+child], data[first+root] + root = child + } } fn heapSortFunc[S: []E, E](mut data: S, a: int, b: int, cmp: fn(a: E, b: E): int) { - first := a - lo := 0 - hi := b - a - - // Build heap with greatest element at top. - mut i := (hi - 1) >> 1 - for i >= 0; i-- { - siftDownFunc(data, i, hi, first, cmp) - } - - // Pop elements, largest first, into end of data. - i = hi - 1 - for i >= 0; i-- { - data[first], data[first+i] = data[first+i], data[first] - siftDownFunc(data, lo, i, first, cmp) - } + first := a + lo := 0 + hi := b - a + + // Build heap with greatest element at top. + mut i := (hi - 1) >> 1 + for i >= 0; i-- { + siftDownFunc(data, i, hi, first, cmp) + } + + // Pop elements, largest first, into end of data. + i = hi - 1 + for i >= 0; i-- { + data[first], data[first+i] = data[first+i], data[first] + siftDownFunc(data, lo, i, first, cmp) + } } // Scatters some elements around in an attempt to break some patterns // that might cause imbalanced partitions in quicksort. fn breakPatternsFunc[S: []E, E](mut data: S, a: int, b: int, cmp: fn(a: E, b: E): int) { - length := b - a - if length >= 8 { - mut random := xorshift(length) - modulus := nextPowerOfTwo(length) - - mut idx := a + (length >> 2) << 1 - 1 - for idx <= a+(length >> 2)<<1+1; idx++ { - mut other := int(uint(xorshiftNext(random)) & (modulus - 1)) - if other >= length { - other -= length - } - data[idx], data[a+other] = data[a+other], data[idx] - } - } + length := b - a + if length >= 8 { + mut random := xorshift(length) + modulus := nextPowerOfTwo(length) + + mut idx := a + (length >> 2) << 1 - 1 + for idx <= a+(length >> 2)<<1+1; idx++ { + mut other := int(uint(xorshiftNext(random)) & (modulus - 1)) + if other >= length { + other -= length + } + data[idx], data[a+other] = data[a+other], data[idx] + } + } } // Returns x,y where data[x] <= data[y], where x,y=a,b or x,y=b,a. fn order2Func[S: []E, E](data: S, a: int, b: int, mut &swaps: int, cmp: fn(a: E, b: E): int): (int, int) { - if cmp(data[b], data[a]) < 0 { - swaps++ - ret b, a - } - ret a, b + if cmp(data[b], data[a]) < 0 { + swaps++ + ret b, a + } + ret a, b } // Returns x where data[x] is the median of data[a],data[b],data[c], where x is a, b, or c. fn medianFunc[S: []E, E](data: S, mut a: int, mut b: int, mut c: int, mut &swaps: int, cmp: fn(a: E, b: E): int): int { - a, b = order2Func(data, a, b, swaps, cmp) - b, c = order2Func(data, b, c, swaps, cmp) - a, b = order2Func(data, a, b, swaps, cmp) - ret b + a, b = order2Func(data, a, b, swaps, cmp) + b, c = order2Func(data, b, c, swaps, cmp) + a, b = order2Func(data, a, b, swaps, cmp) + ret b } // Finds the median of data[a - 1], data[a], data[a + 1] and stores the index into a. fn medianAdjacentFunc[S: []E, E](mut data: S, a: int, mut &swaps: int, cmp: fn(a: E, b: E): int): int { - ret medianFunc(data, a - 1, a, a + 1, swaps, cmp) + ret medianFunc(data, a - 1, a, a + 1, swaps, cmp) } // Chooses a pivot in data[a:b]. @@ -132,114 +132,114 @@ fn medianAdjacentFunc[S: []E, E](mut data: S, a: int, mut &swaps: int, cmp: fn(a // [8,shortestNinther): uses the simple median-of-three method. // [shortestNinther,∞): uses the Tukey ninther method. fn choosePivotFunc[S: []E, E](mut data: S, a: int, b: int, cmp: fn(a: E, b: E): int): (pivot: int, hint: sortedHint) { - const shortestNinther = 50 - const maxSwaps = 4 * 3 - - l := b - a - - mut swaps := 0 - mut i := a + l >> 2 * 1 - mut j := a + l >> 2 * 2 - mut k := a + l >> 2 * 3 - - if l >= 8 { - if l >= shortestNinther { - // Tukey ninther method, the idea came from Rust's implementation. - i = medianAdjacentFunc(data, i, swaps, cmp) - j = medianAdjacentFunc(data, j, swaps, cmp) - k = medianAdjacentFunc(data, k, swaps, cmp) - } - // Find the median among i, j, k and stores it into j. - j = medianFunc(data, i, j, k, swaps, cmp) - } - - match swaps { - | 0: - ret j, sortedHint.Increasing - | maxSwaps: - ret j, sortedHint.Decreasing - |: - ret j, sortedHint.Unknown - } + const shortestNinther = 50 + const maxSwaps = 4 * 3 + + l := b - a + + mut swaps := 0 + mut i := a + l >> 2 * 1 + mut j := a + l >> 2 * 2 + mut k := a + l >> 2 * 3 + + if l >= 8 { + if l >= shortestNinther { + // Tukey ninther method, the idea came from Rust's implementation. + i = medianAdjacentFunc(data, i, swaps, cmp) + j = medianAdjacentFunc(data, j, swaps, cmp) + k = medianAdjacentFunc(data, k, swaps, cmp) + } + // Find the median among i, j, k and stores it into j. + j = medianFunc(data, i, j, k, swaps, cmp) + } + + match swaps { + | 0: + ret j, sortedHint.Increasing + | maxSwaps: + ret j, sortedHint.Decreasing + |: + ret j, sortedHint.Unknown + } } fn reverseRangeFunc[S: []E, E](mut data: S, a: int, b: int, cmp: fn(a: E, b: E): int) { - mut i := a - mut j := b - 1 - for i < j { - data[i], data[j] = data[j], data[i] - i++ - j-- - } + mut i := a + mut j := b - 1 + for i < j { + data[i], data[j] = data[j], data[i] + i++ + j-- + } } // Partially sorts a slice, returns true if the slice is sorted at the end. fn partialInsertionSortFunc[S: []E, E](mut data: S, a: int, b: int, cmp: fn(a: E, b: E): int): bool { - const maxSteps = 5 // maximum number of adjacent out-of-order pairs that will get shifted - const shortestShifting = 50 // don't shift any elements on short arrays - - mut i := a + 1 - mut j := 0 - for j < maxSteps; j++ { - for i < b && !(cmp(data[i], data[i-1]) < 0) { - i++ - } - - if i == b { - ret true - } - - if b-a < shortestShifting { - ret false - } - - data[i], data[i-1] = data[i-1], data[i] - - // Shift the smaller one to the left. - if i-a >= 2 { - j = i - 1 - for j >= 1; j-- { - if !(cmp(data[j], data[j-1]) < 0) { - break - } - data[j], data[j-1] = data[j-1], data[j] - } - } - // Shift the greater one to the right. - if b-i >= 2 { - j = i + 1 - for j < b; j++ { - if !(cmp(data[j], data[j-1]) < 0) { - break - } - data[j], data[j-1] = data[j-1], data[j] - } - } - } - ret false + const maxSteps = 5 // maximum number of adjacent out-of-order pairs that will get shifted + const shortestShifting = 50 // don't shift any elements on short arrays + + mut i := a + 1 + mut j := 0 + for j < maxSteps; j++ { + for i < b && !(cmp(data[i], data[i-1]) < 0) { + i++ + } + + if i == b { + ret true + } + + if b-a < shortestShifting { + ret false + } + + data[i], data[i-1] = data[i-1], data[i] + + // Shift the smaller one to the left. + if i-a >= 2 { + j = i - 1 + for j >= 1; j-- { + if !(cmp(data[j], data[j-1]) < 0) { + break + } + data[j], data[j-1] = data[j-1], data[j] + } + } + // Shift the greater one to the right. + if b-i >= 2 { + j = i + 1 + for j < b; j++ { + if !(cmp(data[j], data[j-1]) < 0) { + break + } + data[j], data[j-1] = data[j-1], data[j] + } + } + } + ret false } // Partitions data[a:b] into elements equal to data[pivot] followed by elements greater than data[pivot]. // It assumed that data[a:b] does not contain elements smaller than the data[pivot]. fn partitionEqualFunc[S: []E, E](mut data: S, a: int, b: int, pivot: int, cmp: fn(a: E, b: E): int): (newpivot: int) { - data[a], data[pivot] = data[pivot], data[a] - mut i, mut j := a + 1, b - 1 // i and j are inclusive of the elements remaining to be partitioned - - for { - for i <= j && !(cmp(data[a], data[i]) < 0) { - i++ - } - for i <= j && (cmp(data[a], data[j]) < 0) { - j-- - } - if i > j { - break - } - data[i], data[j] = data[j], data[i] - i++ - j-- - } - ret i + data[a], data[pivot] = data[pivot], data[a] + mut i, mut j := a + 1, b - 1 // i and j are inclusive of the elements remaining to be partitioned + + for { + for i <= j && !(cmp(data[a], data[i]) < 0) { + i++ + } + for i <= j && (cmp(data[a], data[j]) < 0) { + j-- + } + if i > j { + break + } + data[i], data[j] = data[j], data[i] + i++ + j-- + } + ret i } // Does one quicksort partition. @@ -247,39 +247,39 @@ fn partitionEqualFunc[S: []E, E](mut data: S, a: int, b: int, pivot: int, cmp: f // Moves elements in data[a:b] around, so that data[i]

=p for inewpivot. // On return, data[newpivot] = p fn partitionFunc[S: []E, E](mut data: S, a: int, b: int, pivot: int, cmp: fn(a: E, b: E): int): (newpivot: int, alreadyPartitioned: bool) { - data[a], data[pivot] = data[pivot], data[a] - mut i, mut j := a + 1, b - 1 // i and j are inclusive of the elements remaining to be partitioned - - for i <= j && (cmp(data[i], data[a]) < 0) { - i++ - } - for i <= j && !(cmp(data[j], data[a]) < 0) { - j-- - } - if i > j { - data[j], data[a] = data[a], data[j] - ret j, true - } - data[i], data[j] = data[j], data[i] - i++ - j-- - - for { - for i <= j && (cmp(data[i], data[a]) < 0) { - i++ - } - for i <= j && !(cmp(data[j], data[a]) < 0) { - j-- - } - if i > j { - break - } - data[i], data[j] = data[j], data[i] - i++ - j-- - } - data[j], data[a] = data[a], data[j] - ret j, false + data[a], data[pivot] = data[pivot], data[a] + mut i, mut j := a + 1, b - 1 // i and j are inclusive of the elements remaining to be partitioned + + for i <= j && (cmp(data[i], data[a]) < 0) { + i++ + } + for i <= j && !(cmp(data[j], data[a]) < 0) { + j-- + } + if i > j { + data[j], data[a] = data[a], data[j] + ret j, true + } + data[i], data[j] = data[j], data[i] + i++ + j-- + + for { + for i <= j && (cmp(data[i], data[a]) < 0) { + i++ + } + for i <= j && !(cmp(data[j], data[a]) < 0) { + j-- + } + if i > j { + break + } + data[i], data[j] = data[j], data[i] + i++ + j-- + } + data[j], data[a] = data[a], data[j] + ret j, false } // Sorts data[a:b]. @@ -289,69 +289,69 @@ fn partitionFunc[S: []E, E](mut data: S, a: int, b: int, pivot: int, cmp: fn(a: // Rust implementation: https://docs.rs/pdqsort/latest/pdqsort/ // limit is the number of allowed bad (very unbalanced) pivots before falling back to heapsort. fn pdqsortFunc[S: []E, E](mut data: S, mut a: int, mut b: int, mut limit: int, cmp: fn(a: E, b: E): int) { - const maxInsertion = 12 - - mut wasBalanced := true // whether the last partitioning was reasonably balanced - mut wasPartitioned := true // whether the slice was already partitioned - - for { - length := b - a - - if length <= maxInsertion { - insertionSortFunc(data, a, b, cmp) - ret - } - - // Fall back to heapsort if too many bad choices were made. - if limit == 0 { - heapSortFunc(data, a, b, cmp) - ret - } - - // If the last partitioning was imbalanced, we need to breaking patterns. - if !wasBalanced { - breakPatternsFunc(data, a, b, cmp) - limit-- - } - - mut pivot, mut hint := choosePivotFunc(data, a, b, cmp) - if hint == sortedHint.Decreasing { - reverseRangeFunc(data, a, b, cmp) - // The chosen pivot was pivot-a elements after the start of the array. - // After reversing it is pivot-a elements before the end of the array. - // The idea came from Rust's implementation. - pivot = (b - 1) - (pivot - a) - hint = sortedHint.Increasing - } - - // The slice is likely already sorted. - if wasBalanced && wasPartitioned && hint == sortedHint.Increasing { - if partialInsertionSortFunc(data, a, b, cmp) { - ret - } - } - - // Probably the slice contains many duplicate elements, partition the slice into - // elements equal to and elements greater than the pivot. - if a > 0 && !(cmp(data[a-1], data[pivot]) < 0) { - mid := partitionEqualFunc(data, a, b, pivot, cmp) - a = mid - continue - } - - mid, alreadyPartitioned := partitionFunc(data, a, b, pivot, cmp) - wasPartitioned = alreadyPartitioned - - leftLen, rightLen := mid - a, b - mid - balanceThreshold := length >> 3 - if leftLen < rightLen { - wasBalanced = leftLen >= balanceThreshold - pdqsortFunc(data, a, mid, limit, cmp) - a = mid + 1 - } else { - wasBalanced = rightLen >= balanceThreshold - pdqsortFunc(data, mid + 1, b, limit, cmp) - b = mid - } - } + const maxInsertion = 12 + + mut wasBalanced := true // whether the last partitioning was reasonably balanced + mut wasPartitioned := true // whether the slice was already partitioned + + for { + length := b - a + + if length <= maxInsertion { + insertionSortFunc(data, a, b, cmp) + ret + } + + // Fall back to heapsort if too many bad choices were made. + if limit == 0 { + heapSortFunc(data, a, b, cmp) + ret + } + + // If the last partitioning was imbalanced, we need to breaking patterns. + if !wasBalanced { + breakPatternsFunc(data, a, b, cmp) + limit-- + } + + mut pivot, mut hint := choosePivotFunc(data, a, b, cmp) + if hint == sortedHint.Decreasing { + reverseRangeFunc(data, a, b, cmp) + // The chosen pivot was pivot-a elements after the start of the array. + // After reversing it is pivot-a elements before the end of the array. + // The idea came from Rust's implementation. + pivot = (b - 1) - (pivot - a) + hint = sortedHint.Increasing + } + + // The slice is likely already sorted. + if wasBalanced && wasPartitioned && hint == sortedHint.Increasing { + if partialInsertionSortFunc(data, a, b, cmp) { + ret + } + } + + // Probably the slice contains many duplicate elements, partition the slice into + // elements equal to and elements greater than the pivot. + if a > 0 && !(cmp(data[a-1], data[pivot]) < 0) { + mid := partitionEqualFunc(data, a, b, pivot, cmp) + a = mid + continue + } + + mid, alreadyPartitioned := partitionFunc(data, a, b, pivot, cmp) + wasPartitioned = alreadyPartitioned + + leftLen, rightLen := mid - a, b - mid + balanceThreshold := length >> 3 + if leftLen < rightLen { + wasBalanced = leftLen >= balanceThreshold + pdqsortFunc(data, a, mid, limit, cmp) + a = mid + 1 + } else { + wasBalanced = rightLen >= balanceThreshold + pdqsortFunc(data, mid + 1, b, limit, cmp) + b = mid + } + } } \ No newline at end of file diff --git a/std/slices/sortordered.jule b/std/slices/sortordered.jule index 8011a6e74..fff3ce635 100644 --- a/std/slices/sortordered.jule +++ b/std/slices/sortordered.jule @@ -39,100 +39,100 @@ use bits for std::math::bits use cmp for std::internal::cmp enum sortedHint { - Unknown, - Increasing, - Decreasing, + Unknown, + Increasing, + Decreasing, } // Sorts data[a:b] using insertion sort. fn insertionSort[E: ordered](mut &data: []E, a: int, b: int) { - mut i := a + 1 - for i < b; i++ { - mut j := i - for j > a && cmp::Less(data[j], data[j-1]); j-- { - data[j], data[j-1] = data[j-1], data[j] - } - } + mut i := a + 1 + for i < b; i++ { + mut j := i + for j > a && cmp::Less(data[j], data[j-1]); j-- { + data[j], data[j-1] = data[j-1], data[j] + } + } } // Implements the heap property on data[lo:hi]. // first is an offset into the array where the root of the heap lies. fn siftDown[E: ordered](mut &data: []E, lo: int, hi: int, first: int) { - mut root := lo - for { - mut child := 2 * root + 1 - if child >= hi { - break - } - if child+1 < hi && cmp::Less(data[first+child], data[first+child+1]) { - child++ - } - if !cmp::Less(data[first+root], data[first+child]) { - ret - } - data[first+root], data[first+child] = data[first+child], data[first+root] - root = child - } + mut root := lo + for { + mut child := 2 * root + 1 + if child >= hi { + break + } + if child+1 < hi && cmp::Less(data[first+child], data[first+child+1]) { + child++ + } + if !cmp::Less(data[first+root], data[first+child]) { + ret + } + data[first+root], data[first+child] = data[first+child], data[first+root] + root = child + } } fn heapSort[E: ordered](mut &data: []E, a: int, b: int) { - first := a - lo := 0 - hi := b - a - - // Build heap with greatest element at top. - mut i := (hi - 1) >> 1 - for i >= 0; i-- { - siftDown(data, i, hi, first) - } - - // Pop elements, largest first, into end of data. - i = hi - 1 - for i >= 0; i-- { - data[first], data[first+1] = data[first+1], data[first] - siftDown(data, lo, i, first) - } + first := a + lo := 0 + hi := b - a + + // Build heap with greatest element at top. + mut i := (hi - 1) >> 1 + for i >= 0; i-- { + siftDown(data, i, hi, first) + } + + // Pop elements, largest first, into end of data. + i = hi - 1 + for i >= 0; i-- { + data[first], data[first+1] = data[first+1], data[first] + siftDown(data, lo, i, first) + } } // breakPatternsOrdered scatters some elements around in an attempt to break some patterns // that might cause imbalanced partitions in quicksort. fn breakPatterns[E: ordered](mut &data: []E, a: int, b: int) { - length := b - a - if length >= 8 { - mut random := xorshift(length) - modulus := nextPowerOfTwo(length) - - mut idx := a + (length / 4) * 2 - 1 - for idx <= a+(length / 4)*2+1; idx++ { - mut other := int(uint(xorshiftNext(random)) & (modulus - 1)) - if other >= length { - other -= length - } - data[idx], data[a+other] = data[a+other], data[idx] - } - } + length := b - a + if length >= 8 { + mut random := xorshift(length) + modulus := nextPowerOfTwo(length) + + mut idx := a + (length / 4) * 2 - 1 + for idx <= a+(length / 4)*2+1; idx++ { + mut other := int(uint(xorshiftNext(random)) & (modulus - 1)) + if other >= length { + other -= length + } + data[idx], data[a+other] = data[a+other], data[idx] + } + } } // Returns x,y where data[x] <= data[y], where x,y=a,b or x,y=b,a. fn order2O[E: ordered](data: []E, a: int, b: int, mut &swaps: int): (int, int) { - if cmp::Less(data[b], data[a]) { - swaps++ - ret b, a - } - ret a, b + if cmp::Less(data[b], data[a]) { + swaps++ + ret b, a + } + ret a, b } // Returns x where data[x] is the median of data[a],data[b],data[c], where x is a, b, or c. fn median[E: ordered](data: []E, mut a: int, mut b: int, mut c: int, mut &swaps: int): int { - a, b = order2O(data, a, b, swaps) - b, c = order2O(data, b, c, swaps) - a, b = order2O(data, a, b, swaps) - ret b + a, b = order2O(data, a, b, swaps) + b, c = order2O(data, b, c, swaps) + a, b = order2O(data, a, b, swaps) + ret b } // Finds the median of data[a - 1], data[a], data[a + 1] and stores the index into a. fn medianAdjacent[E: ordered](data: []E, a: int, mut &swaps: int): int { - ret median(data, a - 1, a, a + 1, swaps) + ret median(data, a - 1, a, a + 1, swaps) } // Chooses a pivot in data[a:b]. @@ -141,113 +141,113 @@ fn medianAdjacent[E: ordered](data: []E, a: int, mut &swaps: int): int { // [8,shortestNinther): uses the simple median-of-three method. // [shortestNinther,∞): uses the Tukey ninther method. fn choosePivot[E: ordered](mut &data: []E, a: int, b: int): (pivot: int, hint: sortedHint) { - const shortestNinther = 50 - const maxSwaps = 4 * 3 - - l := b - a - - mut swaps := 0 - mut i := a + l / 4 * 1 - mut j := a + l / 4 * 2 - mut k := a + l / 4 * 3 - - if l >= 8 { - if l >= shortestNinther { - // Tukey ninther method, the idea came from Rust's implementation. - i = medianAdjacent(data, i, swaps) - j = medianAdjacent(data, j, swaps) - k = medianAdjacent(data, k, swaps) - } - // Find the median among i, j, k and stores it into j. - j = median(data, i, j, k, swaps) - } - - match swaps { - | 0: - ret j, sortedHint.Increasing - | maxSwaps: - ret j, sortedHint.Decreasing - |: - ret j, sortedHint.Unknown - } + const shortestNinther = 50 + const maxSwaps = 4 * 3 + + l := b - a + + mut swaps := 0 + mut i := a + l / 4 * 1 + mut j := a + l / 4 * 2 + mut k := a + l / 4 * 3 + + if l >= 8 { + if l >= shortestNinther { + // Tukey ninther method, the idea came from Rust's implementation. + i = medianAdjacent(data, i, swaps) + j = medianAdjacent(data, j, swaps) + k = medianAdjacent(data, k, swaps) + } + // Find the median among i, j, k and stores it into j. + j = median(data, i, j, k, swaps) + } + + match swaps { + | 0: + ret j, sortedHint.Increasing + | maxSwaps: + ret j, sortedHint.Decreasing + |: + ret j, sortedHint.Unknown + } } fn reverseRange[E: ordered](mut &data: []E, a: int, b: int) { - mut i := a - mut j := b - 1 - for i < j { - data[i], data[j] = data[j], data[i] - i++ - j-- - } + mut i := a + mut j := b - 1 + for i < j { + data[i], data[j] = data[j], data[i] + i++ + j-- + } } // Partially sorts a slice, returns true if the slice is sorted at the end. fn partialInsertionSort[E: ordered](mut &data: []E, a: int, b: int): bool { - const maxSteps = 5 // maximum number of adjacent out-of-order pairs that will get shifted - const shortestShifting = 50 // don't shift any elements on short arrays - mut i := a + 1 - mut j := 0 - for j < maxSteps; j++ { - for i < b && !cmp::Less(data[i], data[i-1]) { - i++ - } - - if i == b { - ret true - } - - if b-a < shortestShifting { - ret false - } - - data[i], data[i-1] = data[i-1], data[i] - - // Shift the smaller one to the left. - if i-a >= 2 { - mut z := i - 1 - for z >= 1; j-- { - if !cmp::Less(data[z], data[z-1]) { - break - } - data[z], data[z-1] = data[z-1], data[z] - } - } - // Shift the greater one to the right. - if b-i >= 2 { - mut z := i + 1 - for z < b; z++ { - if !cmp::Less(data[z], data[z-1]) { - break - } - data[z], data[z-1] = data[z-1], data[z] - } - } - } - ret false + const maxSteps = 5 // maximum number of adjacent out-of-order pairs that will get shifted + const shortestShifting = 50 // don't shift any elements on short arrays + mut i := a + 1 + mut j := 0 + for j < maxSteps; j++ { + for i < b && !cmp::Less(data[i], data[i-1]) { + i++ + } + + if i == b { + ret true + } + + if b-a < shortestShifting { + ret false + } + + data[i], data[i-1] = data[i-1], data[i] + + // Shift the smaller one to the left. + if i-a >= 2 { + mut z := i - 1 + for z >= 1; j-- { + if !cmp::Less(data[z], data[z-1]) { + break + } + data[z], data[z-1] = data[z-1], data[z] + } + } + // Shift the greater one to the right. + if b-i >= 2 { + mut z := i + 1 + for z < b; z++ { + if !cmp::Less(data[z], data[z-1]) { + break + } + data[z], data[z-1] = data[z-1], data[z] + } + } + } + ret false } // Partitions data[a:b] into elements equal to data[pivot] followed by elements greater than data[pivot]. // It assumed that data[a:b] does not contain elements smaller than the data[pivot]. fn partitionEqual[E: ordered](mut &data: []E, a: int, b: int, pivot: int): (newpivot: int) { - data[a], data[pivot] = data[pivot], data[a] - mut i, mut j := a + 1, b - 1 // i and j are inclusive of the elements remaining to be partitioned - - for { - for i <= j && !cmp::Less(data[a], data[i]) { - i++ - } - for i <= j && cmp::Less(data[a], data[j]) { - j-- - } - if i > j { - break - } - data[i], data[j] = data[j], data[i] - i++ - j-- - } - ret i + data[a], data[pivot] = data[pivot], data[a] + mut i, mut j := a + 1, b - 1 // i and j are inclusive of the elements remaining to be partitioned + + for { + for i <= j && !cmp::Less(data[a], data[i]) { + i++ + } + for i <= j && cmp::Less(data[a], data[j]) { + j-- + } + if i > j { + break + } + data[i], data[j] = data[j], data[i] + i++ + j-- + } + ret i } // Does one quicksort partition. @@ -255,39 +255,39 @@ fn partitionEqual[E: ordered](mut &data: []E, a: int, b: int, pivot: int): (newp // Moves elements in data[a:b] around, so that data[i]

=p for inewpivot. // On return, data[newpivot] = p fn partition[E: ordered](mut &data: []E, a: int, b: int, pivot: int): (newpivot: int, alreadyPartitioned: bool) { - data[a], data[pivot] = data[pivot], data[a] - mut i, mut j := a + 1, b - 1 // i and j are inclusive of the elements remaining to be partitioned - - for i <= j && cmp::Less(data[i], data[a]) { - i++ - } - for i <= j && !cmp::Less(data[j], data[a]) { - j-- - } - if i > j { - data[j], data[a] = data[a], data[j] - ret j, true - } - data[i], data[j] = data[j], data[i] - i++ - j-- - - for { - for i <= j && cmp::Less(data[i], data[a]) { - i++ - } - for i <= j && !cmp::Less(data[j], data[a]) { - j-- - } - if i > j { - break - } - data[i], data[j] = data[j], data[i] - i++ - j-- - } - data[j], data[a] = data[a], data[j] - ret j, false + data[a], data[pivot] = data[pivot], data[a] + mut i, mut j := a + 1, b - 1 // i and j are inclusive of the elements remaining to be partitioned + + for i <= j && cmp::Less(data[i], data[a]) { + i++ + } + for i <= j && !cmp::Less(data[j], data[a]) { + j-- + } + if i > j { + data[j], data[a] = data[a], data[j] + ret j, true + } + data[i], data[j] = data[j], data[i] + i++ + j-- + + for { + for i <= j && cmp::Less(data[i], data[a]) { + i++ + } + for i <= j && !cmp::Less(data[j], data[a]) { + j-- + } + if i > j { + break + } + data[i], data[j] = data[j], data[i] + i++ + j-- + } + data[j], data[a] = data[a], data[j] + ret j, false } // Sorts data[a:b]. @@ -297,69 +297,69 @@ fn partition[E: ordered](mut &data: []E, a: int, b: int, pivot: int): (newpivot: // Rust implementation: https://docs.rs/pdqsort/latest/pdqsort/ // limit is the number of allowed bad (very unbalanced) pivots before falling back to heapsort. fn pdqsort[E: ordered](mut &data: []E, mut a: int, mut b: int, mut limit: int) { - const maxInsertion = 12 - - mut wasBalanced := true // whether the last partitioning was reasonably balanced - mut wasPartitioned := true // whether the slice was already partitioned - - for { - length := b - a - - if length <= maxInsertion { - insertionSort(data, a, b) - ret - } - - // Fall back to heapsort if too many bad choices were made. - if limit == 0 { - heapSort(data, a, b) - ret - } - - // If the last partitioning was imbalanced, we need to breaking patterns. - if !wasBalanced { - breakPatterns(data, a, b) - limit-- - } - - mut pivot, mut hint := choosePivot(data, a, b) - if hint == sortedHint.Decreasing { - reverseRange(data, a, b) - // The chosen pivot was pivot-a elements after the start of the array. - // After reversing it is pivot-a elements before the end of the array. - // The idea came from Rust's implementation. - pivot = (b - 1) - (pivot - a) - hint = sortedHint.Increasing - } - - // The slice is likely already sorted. - if wasBalanced && wasPartitioned && hint == sortedHint.Increasing { - if partialInsertionSort(data, a, b) { - ret - } - } - - // Probably the slice contains many duplicate elements, partition the slice into - // elements equal to and elements greater than the pivot. - if a > 0 && !cmp::Less(data[a-1], data[pivot]) { - mid := partitionEqual(data, a, b, pivot) - a = mid - continue - } - - mid, alreadyPartitioned := partition(data, a, b, pivot) - wasPartitioned = alreadyPartitioned - - leftLen, rightLen := mid - a, b - mid - balanceThreshold := length / 8 - if leftLen < rightLen { - wasBalanced = leftLen >= balanceThreshold - pdqsort(data, a, mid, limit) - a = mid + 1 - } else { - wasBalanced = rightLen >= balanceThreshold - pdqsort(data, mid + 1, b, limit) - b = mid - } - } + const maxInsertion = 12 + + mut wasBalanced := true // whether the last partitioning was reasonably balanced + mut wasPartitioned := true // whether the slice was already partitioned + + for { + length := b - a + + if length <= maxInsertion { + insertionSort(data, a, b) + ret + } + + // Fall back to heapsort if too many bad choices were made. + if limit == 0 { + heapSort(data, a, b) + ret + } + + // If the last partitioning was imbalanced, we need to breaking patterns. + if !wasBalanced { + breakPatterns(data, a, b) + limit-- + } + + mut pivot, mut hint := choosePivot(data, a, b) + if hint == sortedHint.Decreasing { + reverseRange(data, a, b) + // The chosen pivot was pivot-a elements after the start of the array. + // After reversing it is pivot-a elements before the end of the array. + // The idea came from Rust's implementation. + pivot = (b - 1) - (pivot - a) + hint = sortedHint.Increasing + } + + // The slice is likely already sorted. + if wasBalanced && wasPartitioned && hint == sortedHint.Increasing { + if partialInsertionSort(data, a, b) { + ret + } + } + + // Probably the slice contains many duplicate elements, partition the slice into + // elements equal to and elements greater than the pivot. + if a > 0 && !cmp::Less(data[a-1], data[pivot]) { + mid := partitionEqual(data, a, b, pivot) + a = mid + continue + } + + mid, alreadyPartitioned := partition(data, a, b, pivot) + wasPartitioned = alreadyPartitioned + + leftLen, rightLen := mid - a, b - mid + balanceThreshold := length / 8 + if leftLen < rightLen { + wasBalanced = leftLen >= balanceThreshold + pdqsort(data, a, mid, limit) + a = mid + 1 + } else { + wasBalanced = rightLen >= balanceThreshold + pdqsort(data, mid + 1, b, limit) + b = mid + } + } } \ No newline at end of file diff --git a/std/stack/stack.jule b/std/stack/stack.jule index c4b3e14b9..2ba6433f8 100644 --- a/std/stack/stack.jule +++ b/std/stack/stack.jule @@ -13,113 +13,113 @@ const growFactor = 2 // Stacks aren't use shared allocation between themselves. // Allocates new space and copies (not deep copy) items into space. struct Stack[T] { - mem: dynar::Dynar[T] + mem: dynar::Dynar[T] } impl Stack { - // Returns new stack instance with capacity. - static fn New(cap: int): Stack[T] { - mut stack := Stack[T]{ - mem: dynar::Dynar[T].New(), - } - if cap > 0 { - stack.resize(cap) - } - ret stack - } + // Returns new stack instance with capacity. + static fn New(cap: int): Stack[T] { + mut stack := Stack[T]{ + mem: dynar::Dynar[T].New(), + } + if cap > 0 { + stack.resize(cap) + } + ret stack + } - fn resize(mut self, n: int) { - ok := self.mem.Resize(n) - if !ok { - panic("Stack[T]: heap reallocation failed") - } - } + fn resize(mut self, n: int) { + ok := self.mem.Resize(n) + if !ok { + panic("Stack[T]: heap reallocation failed") + } + } - // Deallocate heap. - fn Dispose(mut self) { - self.mem.Dispose() - } + // Deallocate heap. + fn Dispose(mut self) { + self.mem.Dispose() + } - // Set capacity to length. - // Removes additional capacity that waiting to use. - // Allocates new memory to cut additional capacity. - fn Fit(mut self) { - if self.Len() != self.Cap() { - self.resize(self.Len()) - } - } + // Set capacity to length. + // Removes additional capacity that waiting to use. + // Allocates new memory to cut additional capacity. + fn Fit(mut self) { + if self.Len() != self.Cap() { + self.resize(self.Len()) + } + } - // Returns length of stack. - // Another meaning is count of elements. - fn Len(self): int { - ret self.mem.Buff.len - } + // Returns length of stack. + // Another meaning is count of elements. + fn Len(self): int { + ret self.mem.Buff.len + } - // Returns capacity of stack. - // Another meaning is additional redy-to-use allocation size. - fn Cap(self): int { - ret self.mem.Buff.cap - } + // Returns capacity of stack. + // Another meaning is additional redy-to-use allocation size. + fn Cap(self): int { + ret self.mem.Buff.cap + } - // Reports whether stack is empty. - fn Empty(self): bool { - ret self.Len() == 0 - } + // Reports whether stack is empty. + fn Empty(self): bool { + ret self.Len() == 0 + } - // Removes all elements. - // Does not deallocates buffer, keeps capacity. - fn Clear(mut self) { - self.mem.Buff.len = 0 - } + // Removes all elements. + // Does not deallocates buffer, keeps capacity. + fn Clear(mut self) { + self.mem.Buff.len = 0 + } - // Pushes element to top of the stack. - fn Push(mut self, mut t: T) { - if self.Len() >= self.Cap() { - self.resize((self.Cap() * growFactor) + 1) - } - unsafe { - self.mem.Buff.heap[self.Len()] = t - } - self.mem.Buff.len++ - } + // Pushes element to top of the stack. + fn Push(mut self, mut t: T) { + if self.Len() >= self.Cap() { + self.resize((self.Cap() * growFactor) + 1) + } + unsafe { + self.mem.Buff.heap[self.Len()] = t + } + self.mem.Buff.len++ + } - // Returns top element of stack, then removes top element. - // Panics if stack is empty. - fn Pop(mut self): T { - if self.Empty() { - panic("Stack[T]: pop with zero-length stack") - } - self.mem.Buff.len-- - unsafe { - ret self.mem.Buff.heap[self.Len()] - } - } + // Returns top element of stack, then removes top element. + // Panics if stack is empty. + fn Pop(mut self): T { + if self.Empty() { + panic("Stack[T]: pop with zero-length stack") + } + self.mem.Buff.len-- + unsafe { + ret self.mem.Buff.heap[self.Len()] + } + } - // Returns top element of stack. - // Panics if stack is empty. - fn Top(mut self): T { - if self.Empty() { - panic("Stack[T]: top with zero-length stack") - } - unsafe { - ret self.mem.Buff.heap[self.Len()-1] - } - } + // Returns top element of stack. + // Panics if stack is empty. + fn Top(mut self): T { + if self.Empty() { + panic("Stack[T]: top with zero-length stack") + } + unsafe { + ret self.mem.Buff.heap[self.Len()-1] + } + } - // Returns slice that contains elements of stack. - // Slice is not mutable reference to internal buffer, but can effect internal - // buffer if T is mutable type. - // Appends elements in top-to-bottom order. - fn Slice(mut self): []T { - if self.Empty() { - ret nil - } - mut s := make([]T, 0, self.Len()) - mut i := self.mem.Buff.heap + self.Len() - 1 - j := self.mem.Buff.heap - for i >= j; i-- { - s = append(s, unsafe { *i }) - } - ret s - } + // Returns slice that contains elements of stack. + // Slice is not mutable reference to internal buffer, but can effect internal + // buffer if T is mutable type. + // Appends elements in top-to-bottom order. + fn Slice(mut self): []T { + if self.Empty() { + ret nil + } + mut s := make([]T, 0, self.Len()) + mut i := self.mem.Buff.heap + self.Len() - 1 + j := self.mem.Buff.heap + for i >= j; i-- { + s = append(s, unsafe { *i }) + } + ret s + } } \ No newline at end of file diff --git a/std/strings/compare.jule b/std/strings/compare.jule index 82342e227..54e853aff 100644 --- a/std/strings/compare.jule +++ b/std/strings/compare.jule @@ -9,25 +9,25 @@ // [slices::SortFunc], for example). It is usually clearer and always faster // to use the built-in string comparison operators ==, <, >, and so on. fn Compare(a: str, b: str): int { - mut l := len(a) - if len(b) < l { - l = len(b) - } - mut i := 0 - for i < l; i++ { - c1, c2 := a[i], b[i] - if c1 < c2 { - ret -1 - } - if c1 > c2 { - ret +1 - } - } - if len(a) < len(b) { - ret -1 - } - if len(a) > len(b) { - ret +1 - } - ret 0 + mut l := len(a) + if len(b) < l { + l = len(b) + } + mut i := 0 + for i < l; i++ { + c1, c2 := a[i], b[i] + if c1 < c2 { + ret -1 + } + if c1 > c2 { + ret +1 + } + } + if len(a) < len(b) { + ret -1 + } + if len(a) > len(b) { + ret +1 + } + ret 0 } \ No newline at end of file diff --git a/std/strings/strings.jule b/std/strings/strings.jule index ec989d635..e6d54719b 100644 --- a/std/strings/strings.jule +++ b/std/strings/strings.jule @@ -9,27 +9,27 @@ use fastbytes for std::internal::fastbytes // Returns string that equals to concatenation of n-count s. // Returns empty string is n <= 0. fn Repeat(s: str, mut n: int): str { - if n <= 0 { - ret "" - } - if len(s) > int.Max/n { - panic("std::strings: repeat: integer buffer size overflow") - } - mut ss := StrBuilder.New(len(s) * n) - for n > 0; n-- { - ss.WriteStr(s) - } - ret ss.Str() + if n <= 0 { + ret "" + } + if len(s) > int.Max/n { + panic("std::strings: repeat: integer buffer size overflow") + } + mut ss := StrBuilder.New(len(s) * n) + for n > 0; n-- { + ss.WriteStr(s) + } + ret ss.Str() } // Reports string has prefix as specified substring or not. fn HasPrefix(s: str, sub: str): bool { - ret len(s) >= len(sub) && s[:len(sub)] == sub + ret len(s) >= len(sub) && s[:len(sub)] == sub } // Reports string has suffix as specified substring or not. fn HasSuffix(s: str, sub: str): bool { - ret len(s) >= len(sub) && s[len(s)-len(sub):] == sub + ret len(s) >= len(sub) && s[len(s)-len(sub):] == sub } // Returns index of first matched item with specified substring, @@ -37,22 +37,22 @@ fn HasSuffix(s: str, sub: str): bool { // of string to right. Starts searching s at given index. // Returns -1, if i < 0 || i >= len(s). fn FindAt(s: str, sub: str, mut i: int): int { - if i < 0 || len(s) < len(sub) || len(sub) == 0 { - ret -1 - } - for i < len(s); i++ { - if HasPrefix(s[i:], sub) { - ret i - } - } - ret -1 + if i < 0 || len(s) < len(sub) || len(sub) == 0 { + ret -1 + } + for i < len(s); i++ { + if HasPrefix(s[i:], sub) { + ret i + } + } + ret -1 } // Returns index of first matched item with specified substring, // returns -1 if not exist any match. Starts searching at left // of string to right. fn Find(s: str, sub: str): int { - ret FindAt(s, sub, 0) + ret FindAt(s, sub, 0) } // Returns index of first matched item with specified substring, @@ -60,29 +60,29 @@ fn Find(s: str, sub: str): int { // of string to left. Starts searching s at given index. // Returns -1, if i < 0 || i >= len(s). fn FindLastAt(s: str, sub: str, i: int): int { - mut j := i - len(sub) + 1 - if len(sub) == 0 || i < 0 || i >= len(s) || j < 0 { - ret -1 - } + mut j := i - len(sub) + 1 + if len(sub) == 0 || i < 0 || i >= len(s) || j < 0 { + ret -1 + } loop: - for j >= 0; j-- { - mut k := j - mut z := 0 - for z < len(sub); k, z = k + 1, z + 1 { - if s[k] != sub[z] { - continue loop - } - } - ret j - } - ret -1 + for j >= 0; j-- { + mut k := j + mut z := 0 + for z < len(sub); k, z = k + 1, z + 1 { + if s[k] != sub[z] { + continue loop + } + } + ret j + } + ret -1 } // Returns index of first matched item with specified substring, // returns -1 if not exist any match. Starts searching at right // of string to left. fn FindLast(s: str, sub: str): int { - ret FindLastAt(s, sub, len(s) - 1) + ret FindLastAt(s, sub, len(s) - 1) } // Returns index of first matched item with finder function, @@ -90,24 +90,24 @@ fn FindLast(s: str, sub: str): int { // of string to right. Starts searching s at given index. // Returns -1, if i < 0. fn FindFnAt(s: str, mut i: int, f: fn(mut rune): bool): int { - if i < 0 { - ret -1 - } - for i < len(s) { - r, n := utf8::DecodeRuneStr(s[i:]) - if f(r) { - ret i - } - i += n - } - ret -1 + if i < 0 { + ret -1 + } + for i < len(s) { + r, n := utf8::DecodeRuneStr(s[i:]) + if f(r) { + ret i + } + i += n + } + ret -1 } // Returns index of first matched item with finder function, // returns -1 if not exist any match. Starts searching at left // of string to right. fn FindFn(s: str, f: fn(mut rune): bool): int { - ret FindFnAt(s, 0, f) + ret FindFnAt(s, 0, f) } // Returns index of first matched item with finder function, @@ -115,282 +115,282 @@ fn FindFn(s: str, f: fn(mut rune): bool): int { // of string to left. Starts searching s at given index. // Returns -1, if i < 0 || i >= len(s). fn FindFnLastAt(s: str, mut i: int, f: fn(mut rune): bool): int { - if i < 0 || i >= len(s) { - ret -1 - } - for i > 0 { - r, n := utf8::DecodeRuneStr(s[i:]) - if f(r) { - ret i - } - i -= n - } - ret -1 + if i < 0 || i >= len(s) { + ret -1 + } + for i > 0 { + r, n := utf8::DecodeRuneStr(s[i:]) + if f(r) { + ret i + } + i -= n + } + ret -1 } // Returns index of first matched item with finder function, // returns -1 if not exist any match. Starts searching at right // of string to left. fn FindFnLast(s: str, f: fn(mut rune): bool): int { - ret FindFnLastAt(s, len(s) - 1, f) + ret FindFnLastAt(s, len(s) - 1, f) } // Returns index of first matched item with specified byte, // returns -1 if not exist any match. Starts searching at left // of string to right. fn FindByte(s: str, b: byte): int { - ret fastbytes::FindByteStr(s, b) + ret fastbytes::FindByteStr(s, b) } // Returns index of first matched item with specified byte, // returns -1 if not exist any match. Starts searching at right // of string to left. fn FindLastByte(s: str, b: byte): int { - ret fastbytes::FindLastByteStr(s, b) + ret fastbytes::FindLastByteStr(s, b) } // Returns index of first matched item with specified rune, // returns -1 if not exist any match. Starts searching at left // of string to right. fn FindRune(s: str, r: rune): int { - mut i := 0 - for i < len(s) { - br, n := utf8::DecodeRuneStr(s[i:]) - if r == br { - ret i - } - i += n - } - ret -1 + mut i := 0 + for i < len(s) { + br, n := utf8::DecodeRuneStr(s[i:]) + if r == br { + ret i + } + i += n + } + ret -1 } // Returns index of first matched item with specified rune, // returns -1 if not exist any match. Starts searching at right // of string to left. fn FindLastRune(s: str, r: rune): int { - mut i := len(s) - for i > 0 { - br, n := utf8::DecodeLastRuneStr(s[:i]) - if r == br { - ret i - 1 - } - i -= n - } - ret -1 + mut i := len(s) + for i > 0 { + br, n := utf8::DecodeLastRuneStr(s[:i]) + if r == br { + ret i - 1 + } + i -= n + } + ret -1 } // Returns index of first matched item with any of runes, // returns -1 if not exist any match. Starts searching at left // of string to right. fn FindAny(s: str, runes: str): int { - mut i := 0 - for i < len(s) { - r, n := utf8::DecodeRuneStr(s[i:]) - if FindRune(runes, r) != -1 { - ret i - } - i += n - } - ret -1 + mut i := 0 + for i < len(s) { + r, n := utf8::DecodeRuneStr(s[i:]) + if FindRune(runes, r) != -1 { + ret i + } + i += n + } + ret -1 } // Returns index of first matched item with any of runes, // returns -1 if not exist any match. Starts searching at right // of string to left. fn FindLastAny(s: str, runes: str): int { - mut i := len(s) - for i > 0 { - r, n := utf8::DecodeLastRuneStr(s[:i]) - if FindRune(runes, r) != -1 { - ret i - 1 - } - i -= n - } - ret -1 + mut i := len(s) + for i > 0 { + r, n := utf8::DecodeLastRuneStr(s[:i]) + if FindRune(runes, r) != -1 { + ret i - 1 + } + i -= n + } + ret -1 } // Splits the string into the specified number of parts to the specified substring. // Returns empty slice if n is equals to zero. // Returns all parts if n less than zero. fn Split(s: str, sub: str, mut n: int): []str { - mut cap := n - if n < 0 { - cap = 1 << 4 - } - mut parts := make([]str, 0, cap) - if n == 0 { - ret parts - } - if n < 0 { - n = len(s) - } - mut i := 0 - for n > 0; n-- { - j := FindAt(s, sub, i) - if j == -1 { - break - } - parts = append(parts, s[i:j]) - i = j + len(sub) - } - if n > 0 && i < len(s) { - parts = append(parts, s[i:]) - } - ret parts + mut cap := n + if n < 0 { + cap = 1 << 4 + } + mut parts := make([]str, 0, cap) + if n == 0 { + ret parts + } + if n < 0 { + n = len(s) + } + mut i := 0 + for n > 0; n-- { + j := FindAt(s, sub, i) + if j == -1 { + break + } + parts = append(parts, s[i:j]) + i = j + len(sub) + } + if n > 0 && i < len(s) { + parts = append(parts, s[i:]) + } + ret parts } // Reports whether string includes substring. fn Contains(s: str, sub: str): bool { - ret FindAt(s, sub, 0) != -1 + ret FindAt(s, sub, 0) != -1 } // Reports whether string includes byte. fn ContainsByte(s: str, b: byte): bool { - ret FindByte(s, b) != -1 + ret FindByte(s, b) != -1 } // Reports whether string includes rune. fn ContainsRune(s: str, r: rune): bool { - ret FindRune(s, r) != -1 + ret FindRune(s, r) != -1 } // Reports whether string includes any of runes. fn ContainsAny(s: str, runes: str): bool { - ret FindAny(s, runes) != -1 + ret FindAny(s, runes) != -1 } // Counts the number of non-overlapping instances of substring in s. // Returns zero if substring is empty. fn Count(s: str, sub: str): int { - if len(sub) == 0 { - ret 0 - } - mut n := 0 - mut i := 0 - for { - j := FindAt(s, sub, i) - if j == -1 { - break - } - n++ - i = j + len(sub) - } - ret n + if len(sub) == 0 { + ret 0 + } + mut n := 0 + mut i := 0 + for { + j := FindAt(s, sub, i) + if j == -1 { + break + } + n++ + i = j + len(sub) + } + ret n } // Replaces all substrings matching sub in the string with new. // Returns same string if n is equals to zero. // Replaces all matches if n less than zero. fn Replace(s: str, sub: str, new: str, mut n: int): str { - if n == 0 || sub == new { - ret s - } - - m := Count(s, sub) - if m == 0 { - ret s - } - if n < 0 || m < n { - n = m - } - - mut ss := StrBuilder.New((len(s) + n * (len(new) - len(sub))) + 1) - mut i := 0 - for n > 0; n-- { - j := FindAt(s, sub, i) - if j == -1 { - break - } - ss.WriteStr(s[i:j]) - ss.WriteStr(new) - i = j + len(sub) - } - ss.WriteStr(s[i:]) - ret ss.Str() + if n == 0 || sub == new { + ret s + } + + m := Count(s, sub) + if m == 0 { + ret s + } + if n < 0 || m < n { + n = m + } + + mut ss := StrBuilder.New((len(s) + n * (len(new) - len(sub))) + 1) + mut i := 0 + for n > 0; n-- { + j := FindAt(s, sub, i) + if j == -1 { + break + } + ss.WriteStr(s[i:j]) + ss.WriteStr(new) + i = j + len(sub) + } + ss.WriteStr(s[i:]) + ret ss.Str() } // Returns a copy of the string s with all its characters modified // according to the mapping function. If mapping returns a negative value, // the character is dropped from the string with no replacement. fn Map(s: str, mapping: fn(mut rune): rune): str { - mut ss := StrBuilder.New(len(s) + 1) - mut i := 0 - for i < len(s) { - mut r, n := utf8::DecodeRuneStr(s[i:]) - i += n - r = mapping(r) - if r >= 0 { - ss.WriteRune(r) - } - } - ret ss.Str() + mut ss := StrBuilder.New(len(s) + 1) + mut i := 0 + for i < len(s) { + mut r, n := utf8::DecodeRuneStr(s[i:]) + i += n + r = mapping(r) + if r >= 0 { + ss.WriteRune(r) + } + } + ret ss.Str() } // Returns s with all Unicode letters mapped to their lower case. fn ToLower(s: str): str { - ret Map(s, unicode::ToLower) + ret Map(s, unicode::ToLower) } // Returns s with all Unicode letters mapped to their upper case. fn ToUpper(s: str): str { - ret Map(s, unicode::ToUpper) + ret Map(s, unicode::ToUpper) } // Trims string by specified runes at left. // Cutset should include runes to trim. fn TrimLeft(mut s: str, cutset: str): str { - mut i := 0 - for i < len(s) { - r, n := utf8::DecodeRuneStr(s[i:]) - if FindRune(cutset, r) == -1 { - ret s[i:] - } - i += n - } - ret "" + mut i := 0 + for i < len(s) { + r, n := utf8::DecodeRuneStr(s[i:]) + if FindRune(cutset, r) == -1 { + ret s[i:] + } + i += n + } + ret "" } // Trims string by specified runes at right. // Cutset should include runes to trim. fn TrimRight(s: str, cutset: str): str { - mut i := len(s) - for i > 0 { - r, n := utf8::DecodeLastRuneStr(s[:i]) - if FindRune(cutset, r) == -1 { - ret s[:i] - } - i -= n - } - ret "" + mut i := len(s) + for i > 0 { + r, n := utf8::DecodeLastRuneStr(s[:i]) + if FindRune(cutset, r) == -1 { + ret s[:i] + } + i -= n + } + ret "" } // Trims string by specified runes at left and right. // Cutset should include runes to trim. fn Trim(s: str, cutset: str): str { - ret TrimLeft(TrimRight(s, cutset), cutset) + ret TrimLeft(TrimRight(s, cutset), cutset) } // Concatenates the parts of its first argument to create a single string. // The separator sep is placed between parts in the resulting string. fn Join(parts: []str, sep: str): str { - match len(parts) { - | 0: - ret "" - | 1: - ret parts[0] - } - mut n := 0 - for _, part in parts { - n += len(part) - n++ - } - mut s := StrBuilder.New(n + 1) - s.WriteStr(parts[0]) - for _, part in parts[1:] { - s.WriteStr(sep) - s.WriteStr(part) - } - ret s.Str() + match len(parts) { + | 0: + ret "" + | 1: + ret parts[0] + } + mut n := 0 + for _, part in parts { + n += len(part) + n++ + } + mut s := StrBuilder.New(n + 1) + s.WriteStr(parts[0]) + for _, part in parts[1:] { + s.WriteStr(sep) + s.WriteStr(part) + } + ret s.Str() } // Cut slices s around the first instance of sep, @@ -398,9 +398,9 @@ fn Join(parts: []str, sep: str): str { // The found result reports whether sep appears in s. // If sep does not appear in s, cut returns s, "", false. fn Cut(s: str, sep: str): (before: str, after: str, found: bool) { - i := Find(s, sep) - if i >= 0 { - ret s[:i], s[i+len(sep):], true - } - ret s, "", false + i := Find(s, sep) + if i >= 0 { + ret s[:i], s[i+len(sep):], true + } + ret s, "", false } \ No newline at end of file diff --git a/std/sync/atomic/atomic.jule b/std/sync/atomic/atomic.jule index 8b77f4284..9e045111a 100644 --- a/std/sync/atomic/atomic.jule +++ b/std/sync/atomic/atomic.jule @@ -4,93 +4,93 @@ #cdef cpp unsafe fn __jule_atomic_swap_explicit[T]( - mut addr: *T, new: T, order: MemoryOrder): (old: T) + mut addr: *T, new: T, order: MemoryOrder): (old: T) #cdef cpp unsafe fn __jule_atomic_compare_swap_explicit[T](mut addr: *T, old: *T, - new: T, suc: MemoryOrder, fail: MemoryOrder): (swapped: bool) + new: T, suc: MemoryOrder, fail: MemoryOrder): (swapped: bool) #cdef cpp unsafe fn __jule_atomic_add_explicit[T]( - mut addr: *T, delta: T, order: MemoryOrder): (old: T) + mut addr: *T, delta: T, order: MemoryOrder): (old: T) #cdef cpp unsafe fn __jule_atomic_load_explicit[T](addr: *T, order: MemoryOrder): T #cdef cpp unsafe fn __jule_atomic_store_explicit[T]( - mut addr: *T, val: T, order: MemoryOrder) + mut addr: *T, val: T, order: MemoryOrder) // Memory order for atomic operations. // Specifies how memory accesses. enum MemoryOrder { - // The weakest memory order. - // There no synchronization or ordering on read/write access. - // Only the operation is guaranteed to be atomic. - // Usually performs fastest atomicity performance. - Relaxed: 0, - - // Combined with a load, if the loaded value was written - // by a store operation with a Release or stronger order, - // all subsequent operations are ordered after that store. - // Especially all subsequent uploads will see the data - // written before the repository. - Acquire: 2, - - // When combined with a store, all previous operations are - // ordered with the Acquire or stronger order before any load - // of that value. In particular, all previous writes become - // visible to all threads that perform an Acquire or stronger - // load of this value. - Release: 3, - - // Acquire and Release combined. - // Aka acquire/release. - // For loads it uses Acquire, for stores it uses Release ordering. - AcqRel: 4, - - // Default memory order for most things. - // Aka sequentially consistent. - // Operations are sequenced consistently. - SeqCst: 5, + // The weakest memory order. + // There no synchronization or ordering on read/write access. + // Only the operation is guaranteed to be atomic. + // Usually performs fastest atomicity performance. + Relaxed: 0, + + // Combined with a load, if the loaded value was written + // by a store operation with a Release or stronger order, + // all subsequent operations are ordered after that store. + // Especially all subsequent uploads will see the data + // written before the repository. + Acquire: 2, + + // When combined with a store, all previous operations are + // ordered with the Acquire or stronger order before any load + // of that value. In particular, all previous writes become + // visible to all threads that perform an Acquire or stronger + // load of this value. + Release: 3, + + // Acquire and Release combined. + // Aka acquire/release. + // For loads it uses Acquire, for stores it uses Release ordering. + AcqRel: 4, + + // Default memory order for most things. + // Aka sequentially consistent. + // Operations are sequenced consistently. + SeqCst: 5, } struct atomicNumber[T] { - n: T + n: T } impl atomicNumber { - // Atomically stores new value and returns the previous value. - fn Swap(mut self, new: T, order: MemoryOrder): (old: T) { - ret unsafe { cpp.__jule_atomic_swap_explicit[T](&self.n, new, order) } - } - - // Executes the compare-and-swap operation. - fn CompareSwap(mut self, old: T, new: T, order: MemoryOrder): (swapped: bool) { - ret unsafe { cpp.__jule_atomic_compare_swap_explicit[T](&self.n, &old, new, order, order) } - } - - // Atomically adds delta to value and returns the previous value. - fn Add(mut self, delta: T, order: MemoryOrder): (old: T) { - ret unsafe { cpp.__jule_atomic_add_explicit[T](&self.n, delta, order) } - } - - // Atomically reads and returns value. - fn Load(self, order: MemoryOrder): T { - ret unsafe { cpp.__jule_atomic_load_explicit[T](&self.n, order) } - } - - // Atomically assigns to value. - fn Store(mut self, val: T, order: MemoryOrder) { - unsafe { cpp.__jule_atomic_store_explicit[T](&self.n, val, order) } - } + // Atomically stores new value and returns the previous value. + fn Swap(mut self, new: T, order: MemoryOrder): (old: T) { + ret unsafe { cpp.__jule_atomic_swap_explicit[T](&self.n, new, order) } + } + + // Executes the compare-and-swap operation. + fn CompareSwap(mut self, old: T, new: T, order: MemoryOrder): (swapped: bool) { + ret unsafe { cpp.__jule_atomic_compare_swap_explicit[T](&self.n, &old, new, order, order) } + } + + // Atomically adds delta to value and returns the previous value. + fn Add(mut self, delta: T, order: MemoryOrder): (old: T) { + ret unsafe { cpp.__jule_atomic_add_explicit[T](&self.n, delta, order) } + } + + // Atomically reads and returns value. + fn Load(self, order: MemoryOrder): T { + ret unsafe { cpp.__jule_atomic_load_explicit[T](&self.n, order) } + } + + // Atomically assigns to value. + fn Store(mut self, val: T, order: MemoryOrder) { + unsafe { cpp.__jule_atomic_store_explicit[T](&self.n, val, order) } + } } impl atomicNumber { - // Returns new atomic instance for type with initializer value. - static fn New(n: T): atomicNumber[T] { - ret atomicNumber[T]{n: n} - } + // Returns new atomic instance for type with initializer value. + static fn New(n: T): atomicNumber[T] { + ret atomicNumber[T]{n: n} + } } // Type alias for private wrapper structure for i8 type. @@ -129,54 +129,54 @@ type AtomicUintptr: atomicNumber[uintptr] // Atomically stores new into addr and returns the previous addr value. // Only integer types are supported. fn Swap[T](mut &addr: T, new: T, order: MemoryOrder): (old: T) { - match type T { - | int | uint | i8 | i16 | i32 | i64 | u8 | u16 | u32 | u64 | uintptr: - ret unsafe { cpp.__jule_atomic_swap_explicit[T](&addr, new, order) } - |: - panic("std::sync::atomic: swap: T is unsupported type, only integer types are supported") - } + match type T { + | int | uint | i8 | i16 | i32 | i64 | u8 | u16 | u32 | u64 | uintptr: + ret unsafe { cpp.__jule_atomic_swap_explicit[T](&addr, new, order) } + |: + panic("std::sync::atomic: swap: T is unsupported type, only integer types are supported") + } } // Executes the compare-and-swap operation for value. // Only integer types are supported. fn CompareSwap[T](mut &addr: T, old: T, new: T, order: MemoryOrder): (swapped: bool) { - match type T { - | int | uint | i8 | i16 | i32 | i64 | u8 | u16 | u32 | u64 | uintptr: - ret unsafe { cpp.__jule_atomic_compare_swap_explicit[T](&addr, &old, new, order, order) } - |: - panic("std::sync::atomic: compare_swap: T is unsupported type, only integer types are supported") - } + match type T { + | int | uint | i8 | i16 | i32 | i64 | u8 | u16 | u32 | u64 | uintptr: + ret unsafe { cpp.__jule_atomic_compare_swap_explicit[T](&addr, &old, new, order, order) } + |: + panic("std::sync::atomic: compare_swap: T is unsupported type, only integer types are supported") + } } // Atomically adds delta to addr and returns the previous addr value. // Only integer types are supported. fn Add[T](mut &addr: T, delta: T, order: MemoryOrder): (old: T) { - match type T { - | int | uint | i8 | i16 | i32 | i64 | u8 | u16 | u32 | u64 | uintptr: - ret unsafe { cpp.__jule_atomic_add_explicit[T](&addr, delta, order) } - |: - panic("std::sync::atomic: add: T is unsupported type, only integer types are supported") - } + match type T { + | int | uint | i8 | i16 | i32 | i64 | u8 | u16 | u32 | u64 | uintptr: + ret unsafe { cpp.__jule_atomic_add_explicit[T](&addr, delta, order) } + |: + panic("std::sync::atomic: add: T is unsupported type, only integer types are supported") + } } // Atomically loads addr. // Only integer types are supported. fn Load[T](&addr: T, order: MemoryOrder): T { - match type T { - | int | uint | i8 | i16 | i32 | i64 | u8 | u16 | u32 | u64 | uintptr: - ret unsafe { cpp.__jule_atomic_load_explicit[T](&addr, order) } - |: - panic("std::sync::atomic: load: T is unsupported type, only integer types are supported") - } + match type T { + | int | uint | i8 | i16 | i32 | i64 | u8 | u16 | u32 | u64 | uintptr: + ret unsafe { cpp.__jule_atomic_load_explicit[T](&addr, order) } + |: + panic("std::sync::atomic: load: T is unsupported type, only integer types are supported") + } } // Atomically stores val into addr. // Only integer types are supported. fn Store[T](mut &addr: T, val: T, order: MemoryOrder) { - match type T { - | int | uint | i8 | i16 | i32 | i64 | u8 | u16 | u32 | u64 | uintptr: - unsafe { cpp.__jule_atomic_store_explicit[T](&addr, val, order) } - |: - panic("std::sync::atomic: store: T is unsupported type, only integer types are supported") - } + match type T { + | int | uint | i8 | i16 | i32 | i64 | u8 | u16 | u32 | u64 | uintptr: + unsafe { cpp.__jule_atomic_store_explicit[T](&addr, val, order) } + |: + panic("std::sync::atomic: store: T is unsupported type, only integer types are supported") + } } \ No newline at end of file diff --git a/std/sync/mutex.jule b/std/sync/mutex.jule index 6fb57cd55..3f34c9f99 100644 --- a/std/sync/mutex.jule +++ b/std/sync/mutex.jule @@ -8,29 +8,29 @@ cpp use "" #namespace "std" #typedef cpp struct mutex { - lock: fn() - unlock: fn() - try_lock: fn(): bool + lock: fn() + unlock: fn() + try_lock: fn(): bool } struct mutex { - p: *cpp.mutex + p: *cpp.mutex } impl mutex { - static fn new(): &mutex { - mut mtx := &mutex{ - p: integ::New[cpp.mutex](), - } - if mtx.p == nil { - panic("std::sync: mutex: allocation failed") - } - ret mtx - } + static fn new(): &mutex { + mut mtx := &mutex{ + p: integ::New[cpp.mutex](), + } + if mtx.p == nil { + panic("std::sync: mutex: allocation failed") + } + ret mtx + } - fn Dispose(mut self) { - unsafe { integ::Delete[cpp.mutex](self.p) } - } + fn Dispose(mut self) { + unsafe { integ::Delete[cpp.mutex](self.p) } + } } // Muxtex is a primitive used to protect memory in @@ -45,35 +45,35 @@ impl mutex { // Mutex suitable for using without smart pointers thanks to internal allocations. // The internal allocation automatically deallocated by smart pointer. struct Mutex { - mtx: &mutex = mutex.new() + mtx: &mutex = mutex.new() } impl Mutex { - // Returns new initialized ready-for-use Mutex. - static fn New(): Mutex { - ret Mutex{} - } + // Returns new initialized ready-for-use Mutex. + static fn New(): Mutex { + ret Mutex{} + } } impl Mutex { - // Locks the mutex. If the mutex is locked by - // another thread, it stops the execution of the - // algorithm to seize it and waits to lock the mutex. - fn Lock(self) { - unsafe { self.mtx.p.lock() } - } + // Locks the mutex. If the mutex is locked by + // another thread, it stops the execution of the + // algorithm to seize it and waits to lock the mutex. + fn Lock(self) { + unsafe { self.mtx.p.lock() } + } - // Unlock the mutex you locked and make it open - // to locking by the thread. - fn Unlock(self) { - unsafe { self.mtx.p.unlock() } - } + // Unlock the mutex you locked and make it open + // to locking by the thread. + fn Unlock(self) { + unsafe { self.mtx.p.unlock() } + } - // Try locking the mutex. But unlike the lock - // method, it just tries to lock instead of waiting - // to lock. Returns true if the locking was - // successful, false otherwise. - fn TryLock(self): bool { - ret unsafe { self.mtx.p.try_lock() } - } + // Try locking the mutex. But unlike the lock + // method, it just tries to lock instead of waiting + // to lock. Returns true if the locking was + // successful, false otherwise. + fn TryLock(self): bool { + ret unsafe { self.mtx.p.try_lock() } + } } \ No newline at end of file diff --git a/std/sync/once.jule b/std/sync/once.jule index 4a35cd993..358ffa0d8 100644 --- a/std/sync/once.jule +++ b/std/sync/once.jule @@ -40,68 +40,68 @@ use std::sync::atomic::{MemoryOrder, AtomicU8} // Once is an object that will perform exactly one action. // A Once must not be copied after first use. struct Once { - // done indicates whether the action has been performed. - // It is first in the struct because it is used in the hot path. - // The hot path is inlined at every call site. - // Placing done first allows more compact instructions on some architectures (amd64/i386), - // and fewer instructions (to calculate offset) on other architectures. - mut done: AtomicU8 - mut m: Mutex + // done indicates whether the action has been performed. + // It is first in the struct because it is used in the hot path. + // The hot path is inlined at every call site. + // Placing done first allows more compact instructions on some architectures (amd64/i386), + // and fewer instructions (to calculate offset) on other architectures. + mut done: AtomicU8 + mut m: Mutex } impl Once { - // Returns new instance for Once. - static fn New(): Once { - ret Once{} - } + // Returns new instance for Once. + static fn New(): Once { + ret Once{} + } - // Calls the function f if and only if do is being called for the - // first time for this instance of Once. In other words, given - // - // let once = Once{} - // - // if once.do(f) is called multiple times, only the first call will invoke f, - // even if f has a different value in each invocation. A new instance of - // Once is required for each function to execute. - // - // do is intended for initialization that must be run exactly once. Since f - // is niladic, it may be necessary to use a function literal to capture the - // arguments to a function to be invoked by do: - // - // config.once.do(func() { config.init(filename) }) - // - // Because no call to do returns until the one call to f returns, if f causes - // do to be called, it will deadlock. - // - // If f panics, do considers it to have returned; future calls of do return - // without calling f. - fn Do(self, f: fn()) { - // Note: Here is an incorrect implementation of do: - // - // if self.done.compare_swap(0, 1) { - // f() - // } - // - // do guarantees that when it returns, f has finished. - // This implementation would not implement that guarantee: - // given two simultaneous calls, the winner of the cas would - // call f, and the second would return immediately, without - // waiting for the first's call to f to complete. - // This is why the slow path falls back to a mutex, and why - // the self.done.store must be delayed until after f returns. + // Calls the function f if and only if do is being called for the + // first time for this instance of Once. In other words, given + // + // let once = Once{} + // + // if once.do(f) is called multiple times, only the first call will invoke f, + // even if f has a different value in each invocation. A new instance of + // Once is required for each function to execute. + // + // do is intended for initialization that must be run exactly once. Since f + // is niladic, it may be necessary to use a function literal to capture the + // arguments to a function to be invoked by do: + // + // config.once.do(func() { config.init(filename) }) + // + // Because no call to do returns until the one call to f returns, if f causes + // do to be called, it will deadlock. + // + // If f panics, do considers it to have returned; future calls of do return + // without calling f. + fn Do(self, f: fn()) { + // Note: Here is an incorrect implementation of do: + // + // if self.done.compare_swap(0, 1) { + // f() + // } + // + // do guarantees that when it returns, f has finished. + // This implementation would not implement that guarantee: + // given two simultaneous calls, the winner of the cas would + // call f, and the second would return immediately, without + // waiting for the first's call to f to complete. + // This is why the slow path falls back to a mutex, and why + // the self.done.store must be delayed until after f returns. - if self.done.Load(MemoryOrder.Relaxed) == 0 { - // Outlined slow-path to allow inlining of the fast-path. - self.doSlow(f) - } - } + if self.done.Load(MemoryOrder.Relaxed) == 0 { + // Outlined slow-path to allow inlining of the fast-path. + self.doSlow(f) + } + } - fn doSlow(self, f: fn()) { - self.m.Lock() - if self.done.Load(MemoryOrder.Relaxed) == 0 { - f() - self.done.Store(1, MemoryOrder.Relaxed) - } - self.m.Unlock() - } + fn doSlow(self, f: fn()) { + self.m.Lock() + if self.done.Load(MemoryOrder.Relaxed) == 0 { + f() + self.done.Store(1, MemoryOrder.Relaxed) + } + self.m.Unlock() + } } \ No newline at end of file diff --git a/std/sync/waitgroup.jule b/std/sync/waitgroup.jule index 96015196d..3f7bd82cb 100644 --- a/std/sync/waitgroup.jule +++ b/std/sync/waitgroup.jule @@ -14,60 +14,60 @@ use std::sync::atomic::{MemoryOrder, AtomicU32} // in each parallel job: // `wg.done()` when finished struct WaitGroup { - taskN: AtomicU32 // current task count - reading/writing should be atomic - waitN: AtomicU32 // current wait count - reading/writing should be atomic + taskN: AtomicU32 // current task count - reading/writing should be atomic + waitN: AtomicU32 // current wait count - reading/writing should be atomic } impl WaitGroup { - // Returns new WaitGroup instance. - static fn New(): &WaitGroup { - ret new(WaitGroup) - } + // Returns new WaitGroup instance. + static fn New(): &WaitGroup { + ret new(WaitGroup) + } - // Increments (+delta) or decrements (-delta) task count by delta - // and unblocks any wait() calls if task count becomes zero. - // Panics if task count reaches below zero. - fn Add(mut self, delta: int) { - oldTask := int(self.taskN.Add(u32(delta), MemoryOrder.Relaxed)) - nTask := oldTask + delta - if nTask < 0 { - panic("std:sync: WaitGroup.Add: negative number of tasks") - } + // Increments (+delta) or decrements (-delta) task count by delta + // and unblocks any wait() calls if task count becomes zero. + // Panics if task count reaches below zero. + fn Add(mut self, delta: int) { + oldTask := int(self.taskN.Add(u32(delta), MemoryOrder.Relaxed)) + nTask := oldTask + delta + if nTask < 0 { + panic("std:sync: WaitGroup.Add: negative number of tasks") + } - // Number of tasks still greater than zero. - // No need to clear waiters. - if nTask != 0 { - ret - } + // Number of tasks still greater than zero. + // No need to clear waiters. + if nTask != 0 { + ret + } - // Number of tasks reaches to zero, therefore clear waiters. - for { - nWaiters := self.waitN.Load(MemoryOrder.Relaxed) - if nWaiters == 0 { - ret - } + // Number of tasks reaches to zero, therefore clear waiters. + for { + nWaiters := self.waitN.Load(MemoryOrder.Relaxed) + if nWaiters == 0 { + ret + } - if self.waitN.CompareSwap(nWaiters, 0, MemoryOrder.Relaxed) { - ret - } - } - } + if self.waitN.CompareSwap(nWaiters, 0, MemoryOrder.Relaxed) { + ret + } + } + } - // Decrements the WaitGroup counter by one. - fn Done(mut self) { self.Add(-1) } + // Decrements the WaitGroup counter by one. + fn Done(mut self) { self.Add(-1) } - // Blocks until all tasks are done (task count becomes zero) - fn Wait(mut self) { - nTask := self.taskN.Load(MemoryOrder.Relaxed) - if nTask == 0 { - // No task, no need to wait. - ret - } + // Blocks until all tasks are done (task count becomes zero) + fn Wait(mut self) { + nTask := self.taskN.Load(MemoryOrder.Relaxed) + if nTask == 0 { + // No task, no need to wait. + ret + } - // Register this wait call to waiters. - self.waitN.Add(1, MemoryOrder.Relaxed) + // Register this wait call to waiters. + self.waitN.Add(1, MemoryOrder.Relaxed) - // Wait for clearing waiters. - for self.waitN.Load(MemoryOrder.Relaxed) != 0 {} - } + // Wait for clearing waiters. + for self.waitN.Load(MemoryOrder.Relaxed) != 0 {} + } } \ No newline at end of file diff --git a/std/sys/net.jule b/std/sys/net.jule index 885d89bd5..d68e9c6c7 100755 --- a/std/sys/net.jule +++ b/std/sys/net.jule @@ -9,33 +9,33 @@ cpp struct fd_set {} #typedef cpp struct timeval { - tv_sec: i64 // Seconds. - tv_usec: i64 // Microseconds. + tv_sec: i64 // Seconds. + tv_usec: i64 // Microseconds. } cpp struct in_addr { - s_addr: u32 + s_addr: u32 } cpp struct in6_addr { - s6_addr: [16]byte + s6_addr: [16]byte } cpp struct sockaddr {} cpp struct sockaddr_in { - sin_len: byte - sin_family: byte - sin_port: u16 - sin_addr: cpp.in_addr - sin_zero: [8]Char + sin_len: byte + sin_family: byte + sin_port: u16 + sin_addr: cpp.in_addr + sin_zero: [8]Char } cpp struct sockaddr_in6 { - sin6_len: byte - sin6_family: byte - sin6_port: u16 - sin6_addr: cpp.in6_addr + sin6_len: byte + sin6_family: byte + sin6_port: u16 + sin6_addr: cpp.in6_addr } #cdef @@ -63,15 +63,15 @@ type Fd: cpp.fd_set // C's htons macro. fn Htons(x: int): u16 { - ret cpp.htons(x) + ret cpp.htons(x) } // C's ntohs macro. fn Ntohs(x: int): u16 { - ret cpp.ntohs(x) + ret cpp.ntohs(x) } // C's select function. unsafe fn Select(nfds: int, mut read: *Fd, mut write: *Fd, mut err: *Fd, mut timeout: *Timeval): int { - ret cpp.select(nfds, read, write, err, timeout) + ret cpp.select(nfds, read, write, err, timeout) } \ No newline at end of file diff --git a/std/sys/net_unix.jule b/std/sys/net_unix.jule index 51ba5b58c..a44febe90 100755 --- a/std/sys/net_unix.jule +++ b/std/sys/net_unix.jule @@ -31,70 +31,70 @@ const INVALID_SOCKET = -1 // C's FD_ZERO macro. unsafe fn FdZero(mut fd: *Fd) { - cpp.FD_ZERO(fd) + cpp.FD_ZERO(fd) } // C's FD_SET macro. unsafe fn FdSet(handle: int, mut fd: *Fd) { - cpp.FD_SET(handle, fd) + cpp.FD_SET(handle, fd) } // C's socket function. fn Socket(domain: int, t: int, protocol: int): int { - ret cpp.socket(domain, t, protocol) + ret cpp.socket(domain, t, protocol) } // C's bind function. unsafe fn Bind(handle: int, addr: *Sockaddr, len: uint): int { - ret cpp.bind(handle, addr, len) + ret cpp.bind(handle, addr, len) } // C's connect function. unsafe fn Connect(handle: int, addr: *Sockaddr, len: uint): int { - ret cpp.connect(handle, addr, len) + ret cpp.connect(handle, addr, len) } // C's listen function. fn Listen(handle: int, backlog: int): int { - ret cpp.listen(handle, backlog) + ret cpp.listen(handle, backlog) } // C's accept function. unsafe fn Accept(handle: int, addr: *Sockaddr, len: *u32): int { - ret cpp.accept(handle, addr, len) + ret cpp.accept(handle, addr, len) } // C's recv function. unsafe fn Recv(handle: int, mut buf: *unsafe, len: uint, flags: int): int { - ret cpp.recv(handle, buf, len, flags) + ret cpp.recv(handle, buf, len, flags) } // C's recvfrom function. unsafe fn Recvfrom(handle: int, mut buf: *unsafe, len: uint, flags: int, srcAddr: *Sockaddr, addrLen: *u32): uint { - ret cpp.recvfrom(handle, buf, len, flags, srcAddr, addrLen) + ret cpp.recvfrom(handle, buf, len, flags, srcAddr, addrLen) } // C's send function. unsafe fn Send(handle: int, mut buf: *unsafe, len: uint, flags: int): int { - ret cpp.send(handle, buf, len, flags) + ret cpp.send(handle, buf, len, flags) } // C's recvfrom function. unsafe fn Sendto(handle: int, mut buf: *unsafe, len: uint, flags: int, srcAddr: *Sockaddr, addrLen: u32): uint { - ret cpp.sendto(handle, buf, len, flags, srcAddr, addrLen) + ret cpp.sendto(handle, buf, len, flags, srcAddr, addrLen) } // C's getsockopt function. unsafe fn Getsockopt(handle: int, level: int, option: int, buf: *unsafe, len: *UnsignedInt): int { - ret cpp.getsockopt(handle, level, option, buf, len) + ret cpp.getsockopt(handle, level, option, buf, len) } // C's setsockopt function. unsafe fn Setsockopt(handle: int, level: int, option: int, buf: *unsafe, len: uint): int { - ret cpp.setsockopt(handle, level, option, buf, len) + ret cpp.setsockopt(handle, level, option, buf, len) } // C's getsockname function. unsafe fn Getsockname(handle: int, addr: *Sockaddr, len: *u32): int { - ret cpp.getsockname(handle, addr, len) + ret cpp.getsockname(handle, addr, len) } \ No newline at end of file diff --git a/std/sys/net_windows.jule b/std/sys/net_windows.jule index 852da42ee..27a350b28 100755 --- a/std/sys/net_windows.jule +++ b/std/sys/net_windows.jule @@ -77,95 +77,95 @@ const SO_SNDTIMEO = 0x1005 // C's FD_ZERO macro. unsafe fn FdZero(mut fd: *Fd) { - cpp.FD_ZERO(fd) + cpp.FD_ZERO(fd) } // C's FD_SET macro. unsafe fn FdSet(handle: uint, mut fd: *Fd) { - cpp.FD_SET(handle, fd) + cpp.FD_SET(handle, fd) } // C's FD_ISSET macro. unsafe fn FdIsset(handle: uint, mut fd: *Fd): int { - ret cpp.FD_ISSET(handle, fd) + ret cpp.FD_ISSET(handle, fd) } // C's socket function. fn Socket(domain: int, t: int, protocol: int): uint { - ret cpp.socket(domain, t, protocol) + ret cpp.socket(domain, t, protocol) } // C's bind function. unsafe fn Bind(handle: uint, addr: *Sockaddr, len: uint): int { - ret cpp.bind(handle, addr, len) + ret cpp.bind(handle, addr, len) } // C's connect function. unsafe fn Connect(handle: uint, addr: *Sockaddr, len: uint): int { - ret cpp.connect(handle, addr, len) + ret cpp.connect(handle, addr, len) } // C's listen function. fn Listen(handle: uint, backlog: int): int { - ret cpp.listen(handle, backlog) + ret cpp.listen(handle, backlog) } // C's accept function. unsafe fn Accept(handle: uint, addr: *Sockaddr, len: *Int): uint { - ret cpp.accept(handle, addr, len) + ret cpp.accept(handle, addr, len) } // C's recv function. unsafe fn Recv(handle: uint, mut buf: *byte, len: uint, flags: int): int { - ret cpp.recv(handle, (*Char)(buf), len, flags) + ret cpp.recv(handle, (*Char)(buf), len, flags) } // C's recvfrom function. unsafe fn Recvfrom(handle: uint, mut buf: *byte, len: int, flags: int, from: *Sockaddr, fromLen: *Int): int { - ret cpp.recvfrom(handle, (*Char)(buf), len, flags, from, fromLen) + ret cpp.recvfrom(handle, (*Char)(buf), len, flags, from, fromLen) } // C's send function. unsafe fn Send(handle: uint, mut buf: *byte, len: uint, flags: int): int { - ret cpp.send(handle, (*Char)(buf), len, flags) + ret cpp.send(handle, (*Char)(buf), len, flags) } // C's sendto function. unsafe fn Sendto(handle: uint, mut buf: *byte, len: int, flags: int, to: *Sockaddr, toLen: Int): int { - ret cpp.sendto(handle, (*Char)(buf), len, flags, to, toLen) + ret cpp.sendto(handle, (*Char)(buf), len, flags, to, toLen) } // C's closesocket function. fn CloseSocket(handle: uint): int { - ret cpp.closesocket(handle) + ret cpp.closesocket(handle) } // C's WSAStartup function. unsafe fn WSAStartup(verReq: u16, mut data: *WsaData): int { - ret cpp.WSAStartup(verReq, data) + ret cpp.WSAStartup(verReq, data) } // C's MAKEWORD macro. fn MakeWord(a: int, b: int): u16 { - ret cpp.MAKEWORD(a, b) + ret cpp.MAKEWORD(a, b) } // C's getsockopt function. unsafe fn Getsockopt(handle: uint, level: int, option: int, buf: *Char, len: *Int): int { - ret cpp.getsockopt(handle, level, option, buf, len) + ret cpp.getsockopt(handle, level, option, buf, len) } // C's setsockopt function. unsafe fn Setsockopt(handle: uint, level: int, option: int, buf: *Char, len: int): int { - ret cpp.setsockopt(handle, level, option, buf, len) + ret cpp.setsockopt(handle, level, option, buf, len) } // C's ioctlsocket function. unsafe fn Ioctlsocket(handle: uint, cmd: Long, arg: *UnsignedLong): int { - ret cpp.ioctlsocket(handle, cmd, arg) + ret cpp.ioctlsocket(handle, cmd, arg) } // C's getsockname function. unsafe fn Getsockname(handle: uint, addr: *Sockaddr, len: *Int): int { - ret cpp.getsockname(handle, addr, len) + ret cpp.getsockname(handle, addr, len) } \ No newline at end of file diff --git a/std/sys/syscall.jule b/std/sys/syscall.jule index 846cc864a..85a6eaf13 100644 --- a/std/sys/syscall.jule +++ b/std/sys/syscall.jule @@ -13,12 +13,12 @@ cpp unsafe fn write(handle: int, buff: *unsafe, n: uint): int // Wrapper for C's lseek function. fn Seek(handle: int, offset: int, origin: int): int { - ret cpp.lseek(handle, offset, origin) + ret cpp.lseek(handle, offset, origin) } // Wrapper for C's read function. unsafe fn Read(handle: int, mut buff: *unsafe, n: uint): int { - ret cpp.read(handle, buff, n) + ret cpp.read(handle, buff, n) } // Wrapper for C's close function. @@ -26,7 +26,7 @@ fn Close(handle: int): int { ret cpp.close(handle) } // Wrapper for C's write function. unsafe fn Write(handle: int, buff: *unsafe, n: uint): int { - ret cpp.write(handle, buff, n) + ret cpp.write(handle, buff, n) } // Wrapper for C's exit. diff --git a/std/sys/syscall_unix.jule b/std/sys/syscall_unix.jule index b5c061033..52ce83165 100644 --- a/std/sys/syscall_unix.jule +++ b/std/sys/syscall_unix.jule @@ -11,15 +11,15 @@ cpp use "" cpp struct DIR {} cpp struct dirent { - d_name: *Char + d_name: *Char } cpp type _mode_t: uint cpp type _off_t: uint cpp struct stat { - st_mode: cpp._mode_t - st_size: cpp._off_t + st_mode: cpp._mode_t + st_size: cpp._off_t } cpp fn fcntl(int, int, int): int @@ -52,23 +52,23 @@ const F_SETFL = 4 // Calls C's fcntl function. fn Fcntl(handle: int, cmd: int, arg: int): int { - ret cpp.fcntl(handle, cmd, arg) + ret cpp.fcntl(handle, cmd, arg) } // Calls C's stat function. unsafe fn Stat(path: *byte, mut stat: *SysStat): int { - ret integ::Emit[int]("stat({}, {})", (*Char)(path), stat) + ret integ::Emit[int]("stat({}, {})", (*Char)(path), stat) } // Wrapper for C's open function. unsafe fn Open(path: *byte, flag: int, mode: int): int { - ret cpp.open((*Char)(path), flag, mode) + ret cpp.open((*Char)(path), flag, mode) } // Reads current working directory into buff. // Returns pointer to buff if success, nil pointer if error occurs. unsafe fn Getcwd(buff: *byte, bufflen: uint): *byte { - ret (*byte)(cpp.getcwd((*Char)(buff), bufflen)) + ret (*byte)(cpp.getcwd((*Char)(buff), bufflen)) } // Calls C's opendir function. @@ -88,7 +88,7 @@ unsafe fn Remove(path: *byte): int { ret cpp.remove((*Char)(path)) } // Wrapper for C's mkdir function. unsafe fn Mkdir(path: *byte, mode: int): int { - ret cpp.mkdir((*Char)(path), mode) + ret cpp.mkdir((*Char)(path), mode) } // Wrapper for C's rmdir function. diff --git a/std/sys/syscall_windows.jule b/std/sys/syscall_windows.jule index e94b54722..7b9bcd6f0 100644 --- a/std/sys/syscall_windows.jule +++ b/std/sys/syscall_windows.jule @@ -16,13 +16,13 @@ cpp type _mode_t: uint cpp type _off_t: uint cpp struct _stat { - st_mode: cpp._mode_t - st_size: cpp._off_t + st_mode: cpp._mode_t + st_size: cpp._off_t } #typedef cpp struct WIN32_FIND_DATAW { - cFileName: *Wchar + cFileName: *Wchar } cpp fn GetStdHandle(stdh: uintptr): *unsafe @@ -39,9 +39,9 @@ cpp unsafe fn RemoveDirectoryW(path: *Wchar): bool cpp unsafe fn GetConsoleMode(handle: cpp.HANDLE, mut mode: *cpp.DWORD): bool cpp unsafe fn SetConsoleMode(handle: cpp.HANDLE, mode: cpp.DWORD): bool cpp unsafe fn WriteConsoleW(handle: cpp.HANDLE, buffer: *unsafe, - toWrite: cpp.DWORD, written: *cpp.DWORD, reserved: *unsafe): bool + toWrite: cpp.DWORD, written: *cpp.DWORD, reserved: *unsafe): bool cpp unsafe fn ReadConsoleW(handle: cpp.HANDLE, mut buffer: *unsafe, - toRead: cpp.DWORD, readed: *cpp.DWORD, inputControl: *unsafe): bool + toRead: cpp.DWORD, readed: *cpp.DWORD, inputControl: *unsafe): bool cpp fn WSAGetLastError(): int cpp unsafe fn FindFirstFileW(*Wchar, *cpp.WIN32_FIND_DATAW): cpp.HANDLE cpp unsafe fn FindNextFileW(cpp.HANDLE, *cpp.WIN32_FIND_DATAW): int @@ -66,12 +66,12 @@ unsafe fn CloseHandle(stdh: Handle): bool { ret cpp.CloseHandle(unsafe { (*unsaf // Calls C's _wstat function. unsafe fn Wstat(path: *u16, mut stat: *SysStat): int { - ret cpp._wstat((*Wchar)(path), stat) + ret cpp._wstat((*Wchar)(path), stat) } // Wrapper for C's _wopen function. unsafe fn Wopen(path: *u16, flag: int, mode: int): int { - ret cpp._wopen((*Wchar)(&path[0]), flag, mode) + ret cpp._wopen((*Wchar)(&path[0]), flag, mode) } // Returns last Windows error. @@ -80,77 +80,77 @@ fn GetLastError(): u32 { ret cpp.GetLastError() } // Reads working directory into buff and returns readed // rune count of current process. Returns 0 if fail. unsafe fn GetCurrentDirectory(bufflen: u32, mut buff: *u16): u32 { - ret cpp.GetCurrentDirectoryW(bufflen, (*Wchar)(buff)) + ret cpp.GetCurrentDirectoryW(bufflen, (*Wchar)(buff)) } // Sets working directory to path. // Reports operation is success. unsafe fn SetCurrentDirectory(path: *u16): bool { - ret cpp.SetCurrentDirectoryW((*Wchar)(path)) + ret cpp.SetCurrentDirectoryW((*Wchar)(path)) } // Delete file. unsafe fn DeleteFile(path: *u16): bool { - ret cpp.DeleteFileW((*Wchar)(path)) + ret cpp.DeleteFileW((*Wchar)(path)) } // Creates directory. unsafe fn CreateDirectory(path: *u16): bool { - ret cpp.CreateDirectoryW((*Wchar)(path), nil) + ret cpp.CreateDirectoryW((*Wchar)(path), nil) } // Removes empty directory. unsafe fn RemoveDirectory(path: *u16): bool { - ret cpp.RemoveDirectoryW((*Wchar)(path)) + ret cpp.RemoveDirectoryW((*Wchar)(path)) } // Calls Windows's GetFullPathNameW function. unsafe fn GetFullPathName(path: *u16, bufflen: u32, - buff: *u16, fname: **u16): u32 { - ret cpp.GetFullPathNameW((*Wchar)(path), bufflen, (*Wchar)(buff), (**Wchar)(fname)) + buff: *u16, fname: **u16): u32 { + ret cpp.GetFullPathNameW((*Wchar)(path), bufflen, (*Wchar)(buff), (**Wchar)(fname)) } // Calls Windows's GetConsoleMode function. fn GetConsoleMode(handle: Handle, mut &mode: int): bool { - ret unsafe { cpp.GetConsoleMode(cpp.HANDLE(handle), (*cpp.DWORD)(&mode)) } + ret unsafe { cpp.GetConsoleMode(cpp.HANDLE(handle), (*cpp.DWORD)(&mode)) } } // Calls Windows's SetConsoleMode function. fn SetConsoleMode(handle: Handle, mode: int): bool { - ret unsafe { cpp.SetConsoleMode(cpp.HANDLE(handle), cpp.DWORD(mode)) } + ret unsafe { cpp.SetConsoleMode(cpp.HANDLE(handle), cpp.DWORD(mode)) } } // Calls Windows's WriteConsoleW function. unsafe fn WriteConsole(handle: Handle, buffer: *u16, toWrite: int, - mut &written: int, reserved: *unsafe): bool { - ret cpp.WriteConsoleW(cpp.HANDLE(handle), (*unsafe)(buffer), - cpp.DWORD(toWrite), (*cpp.DWORD)(written), reserved) + mut &written: int, reserved: *unsafe): bool { + ret cpp.WriteConsoleW(cpp.HANDLE(handle), (*unsafe)(buffer), + cpp.DWORD(toWrite), (*cpp.DWORD)(written), reserved) } // Calls Windows's ReadConsoleW function. // Passes nil pointer for input control. unsafe fn ReadConsole(handle: Handle, mut buffer: *u16, toRead: int, - mut &readed: int): bool { - ret cpp.ReadConsoleW(cpp.HANDLE(handle), (*unsafe)(buffer), - cpp.DWORD(toRead), (*cpp.DWORD)(&readed), nil) + mut &readed: int): bool { + ret cpp.ReadConsoleW(cpp.HANDLE(handle), (*unsafe)(buffer), + cpp.DWORD(toRead), (*cpp.DWORD)(&readed), nil) } // Calls Windows's WSAGetLastError function. fn WSAGetLastError(): int { - ret cpp.WSAGetLastError() + ret cpp.WSAGetLastError() } // Call's Windows FindFirstFileW function. unsafe fn FindFirstFile(path: *u16, mut data: *Win32FindData): Handle { - ret Handle(cpp.FindFirstFileW((*Wchar)(path), data)) + ret Handle(cpp.FindFirstFileW((*Wchar)(path), data)) } // Call's Windows FindNextFileW function. unsafe fn FindNextFile(h: Handle, mut data: *Win32FindData): int { - ret cpp.FindNextFileW(cpp.HANDLE(h), data) + ret cpp.FindNextFileW(cpp.HANDLE(h), data) } // Call's Windows FindClose function. fn FindClose(h: Handle): int { - ret unsafe { cpp.FindClose(cpp.HANDLE(h)) } + ret unsafe { cpp.FindClose(cpp.HANDLE(h)) } } \ No newline at end of file diff --git a/std/testing/t.jule b/std/testing/t.jule index 4f2a635ab..c58bac71b 100644 --- a/std/testing/t.jule +++ b/std/testing/t.jule @@ -6,73 +6,73 @@ use std::unsafe use fmt for std::internal::fmt enum status: byte { - Na: 0x0, - Skip: 0x1 << 0, - Fail: 0x1 << 1, + Na: 0x0, + Skip: 0x1 << 0, + Fail: 0x1 << 1, } // A test utility also used by the Jule runtime. // It provides functionalities that facilitate the // management and development of tests. struct T { - mut s: status + mut s: status } impl T { - // Used by runtime. - // Reset all data. - fn reset(self) { - self.s = status.Na - } + // Used by runtime. + // Reset all data. + fn reset(self) { + self.s = status.Na + } - // Wrapper for internal logs. - fn println(self, msg: str) { - out(" ") - outln(msg) - } + // Wrapper for internal logs. + fn println(self, msg: str) { + out(" ") + outln(msg) + } - // Fails test. - // Does not breaks scope execution. - fn Fail(self) { - if self.s == status.Skip { - panic("std::testing: T.fail: failed test that already skipped") - } - self.s = status.Fail - } + // Fails test. + // Does not breaks scope execution. + fn Fail(self) { + if self.s == status.Skip { + panic("std::testing: T.fail: failed test that already skipped") + } + self.s = status.Fail + } - // Reports whether test is failed. - fn Failed(self): bool { - ret self.s == status.Fail - } + // Reports whether test is failed. + fn Failed(self): bool { + ret self.s == status.Fail + } - // Skip test. - // Does not breaks scope execution. - fn Skip(self) { - if self.s == status.Skip { - panic("std::testing: T.skip: skipped test that already failed") - } - self.s = status.Skip - } + // Skip test. + // Does not breaks scope execution. + fn Skip(self) { + if self.s == status.Skip { + panic("std::testing: T.skip: skipped test that already failed") + } + self.s = status.Skip + } - // Reports whether test is skipped. - fn Skipped(self): bool { - ret self.s == status.Skip - } + // Reports whether test is skipped. + fn Skipped(self): bool { + ret self.s == status.Skip + } - // Set status of test as failure if expression is evaluated false at runtime. - fn Assert(self, expr: bool, message: str): bool { - if !expr { - self.println(message) - self.Fail() - } - ret expr - } + // Set status of test as failure if expression is evaluated false at runtime. + fn Assert(self, expr: bool, message: str): bool { + if !expr { + self.println(message) + self.Fail() + } + ret expr + } - // Set status of test as failure and print message by formatting. - // Prints new-line after formatted text. - // Uses std::fmt internally. - fn Errorf(self, fmt: str, args: ...any) { - self.println(unsafe::BytesStr(fmt::Format(fmt, args...))) - self.Fail() - } + // Set status of test as failure and print message by formatting. + // Prints new-line after formatted text. + // Uses std::fmt internally. + fn Errorf(self, fmt: str, args: ...any) { + self.println(unsafe::BytesStr(fmt::Format(fmt, args...))) + self.Fail() + } } \ No newline at end of file diff --git a/std/thread/thread.jule b/std/thread/thread.jule index 25f031a3e..eb7d2cf29 100644 --- a/std/thread/thread.jule +++ b/std/thread/thread.jule @@ -7,16 +7,16 @@ cpp use "thread.hpp" #namespace "std" #typedef cpp struct thread { - detach: fn() - join: fn() - joinable: fn(): bool + detach: fn() + join: fn() + joinable: fn(): bool } #typedef cpp struct __jule_thread_handle { - thread: fn(): *cpp.thread - ref_count: fn(): uint - drop: fn() + thread: fn(): *cpp.thread + ref_count: fn(): uint + drop: fn() } cpp fn __jule_spawn_thread(routine: fn()): cpp.__jule_thread_handle @@ -31,61 +31,61 @@ cpp fn __jule_spawn_thread(routine: fn()): cpp.__jule_thread_handle // // It is experimental. struct Thread { - handle: cpp.__jule_thread_handle + handle: cpp.__jule_thread_handle } impl Thread { - // Spawns new thread by routine. - // Panics if routine is nil. - // Thread starts execution of routine when spawned. - static fn Spawn(routine: fn()): &Thread { - if routine == nil { - panic("std::thread Thread.Spawn: routine is nil") - } - ret &Thread{ - handle: cpp.__jule_spawn_thread(routine), - } - } + // Spawns new thread by routine. + // Panics if routine is nil. + // Thread starts execution of routine when spawned. + static fn Spawn(routine: fn()): &Thread { + if routine == nil { + panic("std::thread Thread.Spawn: routine is nil") + } + ret &Thread{ + handle: cpp.__jule_spawn_thread(routine), + } + } } impl Thread { - // Wait for complete execution of thread if active. - // Returns when the thread execution has completed. - // So program stops execution until thread's execution has completed. - // - // Panics if thread is not active. - fn Wait(self) { - if !self.Active() { - panic("std::thread Thread.Wait: thread is not active") - } - unsafe { self.handle.thread().join() } - self.handle.drop() - } + // Wait for complete execution of thread if active. + // Returns when the thread execution has completed. + // So program stops execution until thread's execution has completed. + // + // Panics if thread is not active. + fn Wait(self) { + if !self.Active() { + panic("std::thread Thread.Wait: thread is not active") + } + unsafe { self.handle.thread().join() } + self.handle.drop() + } - // Detach thread and make it independent. - // After this, this thread object can no longer identify thread. - fn Detach(self) { - if !self.Active() { - panic("std::thread Thread.Detach: thread is not active") - } - unsafe { self.handle.thread().detach() } - self.handle.drop() - } + // Detach thread and make it independent. + // After this, this thread object can no longer identify thread. + fn Detach(self) { + if !self.Active() { + panic("std::thread Thread.Detach: thread is not active") + } + unsafe { self.handle.thread().detach() } + self.handle.drop() + } - // Reports whether thread object identifies an active - // thread of execution. - fn Active(self): bool { - if self.handle.thread() == nil { - ret false - } - ret unsafe { self.handle.thread().joinable() } - } + // Reports whether thread object identifies an active + // thread of execution. + fn Active(self): bool { + if self.handle.thread() == nil { + ret false + } + ret unsafe { self.handle.thread().joinable() } + } - // Detaches thread if thread is still executing. - fn Dispose(mut self) { - if self.Active() && self.handle.ref_count() == 1 { - unsafe { self.handle.thread().detach() } - } - self.handle.drop() - } + // Detaches thread if thread is still executing. + fn Dispose(mut self) { + if self.Active() && self.handle.ref_count() == 1 { + unsafe { self.handle.thread().detach() } + } + self.handle.drop() + } } \ No newline at end of file diff --git a/std/time/duration.jule b/std/time/duration.jule index c7f3fca23..6842089f2 100644 --- a/std/time/duration.jule +++ b/std/time/duration.jule @@ -9,166 +9,166 @@ type DurInt: i64 struct Duration {} impl Duration { - const min = DurInt.Min - const max = DurInt.Max - - // A nanosecond. - const Nanosecond: DurInt = 1 - - // Nanoseconds in microsecond. - // How many nanoseconds are in microsecond. - const Microsecond: DurInt = 1000 * Duration.Nanosecond - - // Nanoseconds in millisecond. - // How many nanoseconds are in millisecond. - const Millisecond: DurInt = 1000 * Duration.Microsecond - - // Nanoseconds in second. - // How many nanoseconds are in second. - const Second: DurInt = 1000 * Duration.Millisecond - - // Nanoseconds in minute. - // How many nanoseconds are in minute. - const Minute: DurInt = 60 * Duration.Second - - // Nanoseconds in hour. - // How many nanoseconds are in hour. - const Hour: DurInt = 60 * Duration.Minute - - // Returns duration as nanoseconds. - static fn Nanoseconds(d: DurInt): DurInt { - ret d - } - - // Returns duration as microseconds. - static fn Microseconds(d: DurInt): DurInt { - ret d / Duration.Microsecond - } - - // Returns duration as milliseconds. - static fn Milliseconds(d: DurInt): DurInt { - ret d / Duration.Millisecond - } - - // Returns duration as floating-point seconds. - static fn Seconds(d: DurInt): f64 { - sec := d / Duration.Second - nsec := d % Duration.Second - ret f64(sec) + f64(nsec) / 1e9 - } - - // Returns duration as floating-point minutes. - static fn Minutes(d: DurInt): f64 { - min := d / Duration.Minute - nsec := d % Duration.Minute - ret f64(min) + f64(nsec) / (60 * 1e9) - } - - // Returns duration as floating-point hours. - static fn Hours(d: DurInt): f64 { - hour := d / Duration.Hour - nsec := d % Duration.Hour - ret f64(hour) + f64(nsec) / (60 * 60 * 1e9) - } - - // Returns absolute value of duration. - static fn Abs(d: DurInt): DurInt { - match { - | d >= 0: - ret d - | d == Duration.min: - ret Duration.max - |: - ret -d - } - } - - // Returns a string representing the duration in the form "72h3m0.5s". - // Leading zero units are omitted. As a special case, durations less than one - // second format use a smaller unit (milli-, micro-, or nanoseconds) to ensure - // that the leading digit is non-zero. The zero duration formats as 0s. - static fn Str(d: DurInt): str { - mut buf := make([]byte, 1 << 5) - n := formatDuration(d, buf) - buf = buf[n:] - ret str(buf) - } + const min = DurInt.Min + const max = DurInt.Max + + // A nanosecond. + const Nanosecond: DurInt = 1 + + // Nanoseconds in microsecond. + // How many nanoseconds are in microsecond. + const Microsecond: DurInt = 1000 * Duration.Nanosecond + + // Nanoseconds in millisecond. + // How many nanoseconds are in millisecond. + const Millisecond: DurInt = 1000 * Duration.Microsecond + + // Nanoseconds in second. + // How many nanoseconds are in second. + const Second: DurInt = 1000 * Duration.Millisecond + + // Nanoseconds in minute. + // How many nanoseconds are in minute. + const Minute: DurInt = 60 * Duration.Second + + // Nanoseconds in hour. + // How many nanoseconds are in hour. + const Hour: DurInt = 60 * Duration.Minute + + // Returns duration as nanoseconds. + static fn Nanoseconds(d: DurInt): DurInt { + ret d + } + + // Returns duration as microseconds. + static fn Microseconds(d: DurInt): DurInt { + ret d / Duration.Microsecond + } + + // Returns duration as milliseconds. + static fn Milliseconds(d: DurInt): DurInt { + ret d / Duration.Millisecond + } + + // Returns duration as floating-point seconds. + static fn Seconds(d: DurInt): f64 { + sec := d / Duration.Second + nsec := d % Duration.Second + ret f64(sec) + f64(nsec) / 1e9 + } + + // Returns duration as floating-point minutes. + static fn Minutes(d: DurInt): f64 { + min := d / Duration.Minute + nsec := d % Duration.Minute + ret f64(min) + f64(nsec) / (60 * 1e9) + } + + // Returns duration as floating-point hours. + static fn Hours(d: DurInt): f64 { + hour := d / Duration.Hour + nsec := d % Duration.Hour + ret f64(hour) + f64(nsec) / (60 * 60 * 1e9) + } + + // Returns absolute value of duration. + static fn Abs(d: DurInt): DurInt { + match { + | d >= 0: + ret d + | d == Duration.min: + ret Duration.max + |: + ret -d + } + } + + // Returns a string representing the duration in the form "72h3m0.5s". + // Leading zero units are omitted. As a special case, durations less than one + // second format use a smaller unit (milli-, micro-, or nanoseconds) to ensure + // that the leading digit is non-zero. The zero duration formats as 0s. + static fn Str(d: DurInt): str { + mut buf := make([]byte, 1 << 5) + n := formatDuration(d, buf) + buf = buf[n:] + ret str(buf) + } } // Formats the representation of d into the end of buf and // returns the offset of the first character. fn formatDuration(d: DurInt, mut buf: []byte): int { - // Largest time is 2540400h10m10.000000000s - mut w := len(buf) - - mut u := u64(d) - neg := d < 0 - if neg { - u = -u - } - - if u < u64(Duration.Second) { - // Special case: if duration is smaller than a second, - // use smaller units, like 1.2ms - mut prec := 0 - w-- - buf[w] = 's' - w-- - match { - | u == 0: - buf[w] = '0' - ret w - | u < u64(Duration.Microsecond): - // print nanoseconds - prec = 0 - buf[w] = 'n' - | u < u64(Duration.Millisecond): - // print microseconds - prec = 3 - // U+00B5 'µ' micro sign == 0xC2 0xB5 - w-- // Need room for two bytes. - buf[w] = 194 - buf[w+1] = 181 - |: - // print milliseconds - prec = 6 - buf[w] = 'm' - } - w, u = fmtFrac(buf[:w], u, prec) - w = fmtInt(buf[:w], u) - } else { - w-- - buf[w] = 's' - - w, u = fmtFrac(buf[:w], u, 9) - - // u is now integer seconds - w = fmtInt(buf[:w], u % 60) - u /= 60 - - // u is now integer minutes - if u > 0 { - w-- - buf[w] = 'm' - w = fmtInt(buf[:w], u % 60) - u /= 60 - - // u is now integer hours - // Stop at hours because days can be different lengths. - if u > 0 { - w-- - buf[w] = 'h' - w = fmtInt(buf[:w], u) - } - } - } - - if neg { - w-- - buf[w] = '-' - } - - ret w + // Largest time is 2540400h10m10.000000000s + mut w := len(buf) + + mut u := u64(d) + neg := d < 0 + if neg { + u = -u + } + + if u < u64(Duration.Second) { + // Special case: if duration is smaller than a second, + // use smaller units, like 1.2ms + mut prec := 0 + w-- + buf[w] = 's' + w-- + match { + | u == 0: + buf[w] = '0' + ret w + | u < u64(Duration.Microsecond): + // print nanoseconds + prec = 0 + buf[w] = 'n' + | u < u64(Duration.Millisecond): + // print microseconds + prec = 3 + // U+00B5 'µ' micro sign == 0xC2 0xB5 + w-- // Need room for two bytes. + buf[w] = 194 + buf[w+1] = 181 + |: + // print milliseconds + prec = 6 + buf[w] = 'm' + } + w, u = fmtFrac(buf[:w], u, prec) + w = fmtInt(buf[:w], u) + } else { + w-- + buf[w] = 's' + + w, u = fmtFrac(buf[:w], u, 9) + + // u is now integer seconds + w = fmtInt(buf[:w], u % 60) + u /= 60 + + // u is now integer minutes + if u > 0 { + w-- + buf[w] = 'm' + w = fmtInt(buf[:w], u % 60) + u /= 60 + + // u is now integer hours + // Stop at hours because days can be different lengths. + if u > 0 { + w-- + buf[w] = 'h' + w = fmtInt(buf[:w], u) + } + } + } + + if neg { + w-- + buf[w] = '-' + } + + ret w } // Formats the fraction of v/10**prec (e.g., ".12345") into the @@ -176,39 +176,39 @@ fn formatDuration(d: DurInt, mut buf: []byte): int { // point too when the fraction is 0. It returns the index where the // output bytes begin and the value v/10**prec. fn fmtFrac(mut buf: []byte, mut v: u64, prec: int): (nw: int, nv: u64) { - // Omit trailing zeros up to and including decimal point. - mut w := len(buf) - mut print := false - mut i := 0 - for i < prec; i++ { - digit := v % 10 - print = print || digit != 0 - if print { - w-- - buf[w] = byte(digit) + '0' - } - v /= 10 - } - if print { - w-- - buf[w] = '.' - } - ret w, v + // Omit trailing zeros up to and including decimal point. + mut w := len(buf) + mut print := false + mut i := 0 + for i < prec; i++ { + digit := v % 10 + print = print || digit != 0 + if print { + w-- + buf[w] = byte(digit) + '0' + } + v /= 10 + } + if print { + w-- + buf[w] = '.' + } + ret w, v } // Formats v into the tail of buf. // It returns the index where the output begins. fn fmtInt(mut buf: []byte, mut v: u64): int { - mut w := len(buf) - if v == 0 { - w-- - buf[w] = '0' - } else { - for v > 0 { - w-- - buf[w] = byte(v % 10) + '0' - v /= 10 - } - } - ret w + mut w := len(buf) + if v == 0 { + w-- + buf[w] = '0' + } else { + for v > 0 { + w-- + buf[w] = byte(v % 10) + '0' + v /= 10 + } + } + ret w } \ No newline at end of file diff --git a/std/time/thread.jule b/std/time/thread.jule index acdea512d..347ea8edf 100644 --- a/std/time/thread.jule +++ b/std/time/thread.jule @@ -19,7 +19,7 @@ cpp fn sleep_for(x: cpp.chrono_ns) // Stops execution of caller thread by absolute duration. // This function only affects execution of caller thread, not process. fn Sleep(mut dur: DurInt) { - dur = Duration.Abs(dur) - ns := u64(Duration.Nanoseconds(dur)) - cpp.sleep_for(cpp.nanoseconds(ns)) + dur = Duration.Abs(dur) + ns := u64(Duration.Nanoseconds(dur)) + cpp.sleep_for(cpp.nanoseconds(ns)) } \ No newline at end of file diff --git a/std/time/time.jule b/std/time/time.jule index 7962a3bfd..49e2fec57 100644 --- a/std/time/time.jule +++ b/std/time/time.jule @@ -40,39 +40,39 @@ type TimeData: u64 // Abstract time. struct AbsTime { - Day: TimeData - WeekDay: TimeData - YearDay: TimeData - Month: TimeData - Year: TimeData - Second: TimeData - Minute: TimeData - Hour: TimeData + Day: TimeData + WeekDay: TimeData + YearDay: TimeData + Month: TimeData + Year: TimeData + Second: TimeData + Minute: TimeData + Hour: TimeData } impl AbsTime { - // Returns abstract time as unix-time seconds. - fn Unix(self): UnixTime { - mut leap := false - mut y := self.Year - unixYearOffset - mut m := self.Month - unixMonthOffset - if m >= 12 || m < 0 { - mut adj := m / 12 - m %= 12 - if m < 0 { - adj-- - m += 12 - } - y += adj - } - mut t := unixYearToSeconds(y, leap) - t += unixMonthToSeconds(m, leap) - t += day * (self.Day - 1) - t += hour * self.Hour - t += 60 * self.Minute - t += self.Second - ret t - } + // Returns abstract time as unix-time seconds. + fn Unix(self): UnixTime { + mut leap := false + mut y := self.Year - unixYearOffset + mut m := self.Month - unixMonthOffset + if m >= 12 || m < 0 { + mut adj := m / 12 + m %= 12 + if m < 0 { + adj-- + m += 12 + } + y += adj + } + mut t := unixYearToSeconds(y, leap) + t += unixMonthToSeconds(m, leap) + t += day * (self.Day - 1) + t += hour * self.Hour + t += 60 * self.Minute + t += self.Second + ret t + } } // Timestamp. @@ -83,207 +83,207 @@ impl AbsTime { // call in the background. Back-to-back calls may cause you // to make the same calculation over and over again. struct Time { - sec: UnixTime + sec: UnixTime } impl Time { - // Returns new time instance from unix-time. - static fn Unix(sec: UnixTime): Time { - ret Time{ - sec: sec, - } - } - - // Returns time instance of the moment. - static fn Now(): Time { - ret Time.Unix(unix()) - } + // Returns new time instance from unix-time. + static fn Unix(sec: UnixTime): Time { + ret Time{ + sec: sec, + } + } + + // Returns time instance of the moment. + static fn Now(): Time { + ret Time.Unix(unix()) + } } impl Time { - // Returns time as unix-time. - fn Unix(self): UnixTime { ret self.sec } - - // Returns day of month. - fn Day(self): TimeData { ret self.Abs().Day } - - // Returns month. - fn Month(self): TimeData { ret self.Abs().Month } - - // Returns year. - fn Year(self): TimeData { ret self.Abs().Year } - - // Returns second. - fn Second(self): TimeData { ret self.Abs().Second } - - // Returns minute. - fn Minute(self): TimeData { ret self.Abs().Minute } - - // Returns hour. - fn Hour(self): TimeData { ret self.Abs().Hour } - - // Returns time as abstract time. - fn Abs(self): AbsTime { - secs := self.sec - modApoch - mut days := secs / day - mut remSecs := secs % day - if remSecs < 0 { - remSecs += day - days-- - } - - mut qcCycles := days / daysPer400Y - mut remDays := days % daysPer400Y - if remDays < 0 { - remDays += daysPer400Y - qcCycles-- - } - - mut cCycles := remDays / daysPer100Y - if cCycles == 4 { - cCycles-- - } - remDays -= cCycles * daysPer100Y - - mut qCycles := remDays / daysPer4Y - if qCycles == 25 { - qCycles-- - } - remDays -= qCycles * daysPer4Y - - mut remYears := remDays / daysPerY - if remYears == 4 { - remYears-- - } - remDays -= remYears * daysPerY - - mut leap := u64(0) - if remYears == 0 && (qCycles > 0 || cCycles == 0) { - leap = 1 - } - mut yDay := remDays + 31 + 28 + leap - if yDay >= daysPerY+leap { - yDay -= daysPerY + leap - } - - mut months := u64(0) - for mdays[months] <= remDays; months++ { - remDays -= mdays[months] - } - - mut t := AbsTime{} - t.Year = remYears + 4 * qCycles + 100 * cCycles + 400 * qcCycles + 100 - t.Month = months + 2 - if t.Month >= 12 { - t.Month -= 12 - t.Year++ - } - t.Month += unixMonthOffset - t.Year += unixYearOffset - t.Day = remDays + 1 - t.WeekDay = (3 + days) % 7 - if t.WeekDay < 0 { - t.WeekDay += 7 - } - t.YearDay = yDay - t.Hour = remSecs / hour - t.Minute = remSecs / 60 % 60 - t.Second = remSecs % 60 - ret t - } + // Returns time as unix-time. + fn Unix(self): UnixTime { ret self.sec } + + // Returns day of month. + fn Day(self): TimeData { ret self.Abs().Day } + + // Returns month. + fn Month(self): TimeData { ret self.Abs().Month } + + // Returns year. + fn Year(self): TimeData { ret self.Abs().Year } + + // Returns second. + fn Second(self): TimeData { ret self.Abs().Second } + + // Returns minute. + fn Minute(self): TimeData { ret self.Abs().Minute } + + // Returns hour. + fn Hour(self): TimeData { ret self.Abs().Hour } + + // Returns time as abstract time. + fn Abs(self): AbsTime { + secs := self.sec - modApoch + mut days := secs / day + mut remSecs := secs % day + if remSecs < 0 { + remSecs += day + days-- + } + + mut qcCycles := days / daysPer400Y + mut remDays := days % daysPer400Y + if remDays < 0 { + remDays += daysPer400Y + qcCycles-- + } + + mut cCycles := remDays / daysPer100Y + if cCycles == 4 { + cCycles-- + } + remDays -= cCycles * daysPer100Y + + mut qCycles := remDays / daysPer4Y + if qCycles == 25 { + qCycles-- + } + remDays -= qCycles * daysPer4Y + + mut remYears := remDays / daysPerY + if remYears == 4 { + remYears-- + } + remDays -= remYears * daysPerY + + mut leap := u64(0) + if remYears == 0 && (qCycles > 0 || cCycles == 0) { + leap = 1 + } + mut yDay := remDays + 31 + 28 + leap + if yDay >= daysPerY+leap { + yDay -= daysPerY + leap + } + + mut months := u64(0) + for mdays[months] <= remDays; months++ { + remDays -= mdays[months] + } + + mut t := AbsTime{} + t.Year = remYears + 4 * qCycles + 100 * cCycles + 400 * qcCycles + 100 + t.Month = months + 2 + if t.Month >= 12 { + t.Month -= 12 + t.Year++ + } + t.Month += unixMonthOffset + t.Year += unixYearOffset + t.Day = remDays + 1 + t.WeekDay = (3 + days) % 7 + if t.WeekDay < 0 { + t.WeekDay += 7 + } + t.YearDay = yDay + t.Hour = remSecs / hour + t.Minute = remSecs / 60 % 60 + t.Second = remSecs % 60 + ret t + } } // Returns current unix time UTC. fn unix(): UnixTime { - ret UnixTime(unsafe { cpp.time(nil) }) + ret UnixTime(unsafe { cpp.time(nil) }) } fn unixYearToSeconds(y: TimeData, mut &leap: bool): UnixTime { - if y-2 <= 136 { - mut leaps := (y - 68) >> 2 - leap = (y - 68)&3 == 0 - if leap { - leaps-- - } - ret 31536000 * (y - 70) + day * leaps - } - - mut leaps := TimeData(0) - mut centuries := TimeData(0) - mut cycles := (y - 100) / 400 - mut rem := (y - 100) % 400 - if rem < 0 { - cycles-- - rem += 400 - } - if rem == 0 { - leap = true - centuries = 0 - leaps = 0 - } else { - if rem >= 200 { - if rem >= 300 { - centuries = 3 - rem -= 300 - } else { - centuries = 2 - rem -= 200 - } - } else { - if rem >= 100 { - centuries = 1 - rem -= 100 - } else { - centuries = 0 - } - } - if rem == 0 { - leap = false - leaps = 0 - } else { - leaps = rem / 4 - rem %= 4 - leap = rem == 0 - } - } - - leaps += 97 * cycles + 24 * centuries - if leap { - leaps++ - } - - ret (y - 100) * 31536000 + leaps * day + 946684800 + day + if y-2 <= 136 { + mut leaps := (y - 68) >> 2 + leap = (y - 68)&3 == 0 + if leap { + leaps-- + } + ret 31536000 * (y - 70) + day * leaps + } + + mut leaps := TimeData(0) + mut centuries := TimeData(0) + mut cycles := (y - 100) / 400 + mut rem := (y - 100) % 400 + if rem < 0 { + cycles-- + rem += 400 + } + if rem == 0 { + leap = true + centuries = 0 + leaps = 0 + } else { + if rem >= 200 { + if rem >= 300 { + centuries = 3 + rem -= 300 + } else { + centuries = 2 + rem -= 200 + } + } else { + if rem >= 100 { + centuries = 1 + rem -= 100 + } else { + centuries = 0 + } + } + if rem == 0 { + leap = false + leaps = 0 + } else { + leaps = rem / 4 + rem %= 4 + leap = rem == 0 + } + } + + leaps += 97 * cycles + 24 * centuries + if leap { + leaps++ + } + + ret (y - 100) * 31536000 + leaps * day + 946684800 + day } fn unixMonthToSeconds(m: TimeData, leap: bool): UnixTime { - // Set seconds through month. - mut t := UnixTime(0) - match m { - | 1: - t = 31 * day - | 2: - t = 59 * day - | 3: - t = 90 * day - | 4: - t = 120 * day - | 5: - t = 151 * day - | 6: - t = 181 * day - | 7: - t = 212 * day - | 8: - t = 243 * day - | 9: - t = 273 * day - | 10: - t = 304 * day - | 11: - t = 334 * day - } - if leap && m >= 2 { - t += day - } - ret t + // Set seconds through month. + mut t := UnixTime(0) + match m { + | 1: + t = 31 * day + | 2: + t = 59 * day + | 3: + t = 90 * day + | 4: + t = 120 * day + | 5: + t = 151 * day + | 6: + t = 181 * day + | 7: + t = 212 * day + | 8: + t = 243 * day + | 9: + t = 273 * day + | 10: + t = 304 * day + | 11: + t = 334 * day + } + if leap && m >= 2 { + t += day + } + ret t } \ No newline at end of file diff --git a/std/unicode/digit.jule b/std/unicode/digit.jule index b33eb6466..71653a129 100644 --- a/std/unicode/digit.jule +++ b/std/unicode/digit.jule @@ -37,8 +37,8 @@ // Reports whether the rune is a decimal digit. fn IsDigit(r: rune): bool { - if r <= MaxLatin1 { - ret '0' <= r && r <= '9' - } - ret isExcludingLatin(Digit, r) + if r <= MaxLatin1 { + ret '0' <= r && r <= '9' + } + ret isExcludingLatin(Digit, r) } \ No newline at end of file diff --git a/std/unicode/graphic.jule b/std/unicode/graphic.jule index e8c110662..079e045aa 100644 --- a/std/unicode/graphic.jule +++ b/std/unicode/graphic.jule @@ -54,46 +54,46 @@ static GraphicRanges = [L, M, N, P, S, ZS] // Such characters include letters, marks, numbers, punctuation, symbols, and // spaces, from categories L, M, N, P, S, ZS. fn IsGraphic(r: rune): bool { - // We convert to u32 to avoid the extra test for negative, - // and in the index we convert to uint8 to avoid the range check. - if u32(r) <= MaxLatin1 { - ret _PROPERTIES[u8(r)]&__PG != 0 - } - ret IsIn(r, GraphicRanges...) + // We convert to u32 to avoid the extra test for negative, + // and in the index we convert to uint8 to avoid the range check. + if u32(r) <= MaxLatin1 { + ret _PROPERTIES[u8(r)]&__PG != 0 + } + ret IsIn(r, GraphicRanges...) } // Reports whether the rune is a member of one of the ranges. fn IsIn(r: rune, ranges: ...&RangeTable): bool { - for _, inside in ranges { - if Is(inside, r) { - ret true - } - } - ret false + for _, inside in ranges { + if Is(inside, r) { + ret true + } + } + ret false } // Reports whether the rune is a letter (category L). fn IsLetter(r: rune): bool { - if u32(r) <= MaxLatin1 { - ret _PROPERTIES[u8(r)]&(__P_L_MASK) != 0 - } - ret isExcludingLatin(Letter, r) + if u32(r) <= MaxLatin1 { + ret _PROPERTIES[u8(r)]&(__P_L_MASK) != 0 + } + ret isExcludingLatin(Letter, r) } // Reports whether the rune is a number (category N). fn IsNumber(r: rune): bool { - if u32(r) <= MaxLatin1 { - ret _PROPERTIES[u8(r)]&__P_N != 0 - } - ret isExcludingLatin(Number, r) + if u32(r) <= MaxLatin1 { + ret _PROPERTIES[u8(r)]&__P_N != 0 + } + ret isExcludingLatin(Number, r) } // Reports whether the rune is a Unicode punctuation character (category P). fn IsPunct(r: rune): bool { - if u32(r) <= MaxLatin1 { - ret _PROPERTIES[u8(r)]&__P_P != 0 - } - ret Is(Punct, r) + if u32(r) <= MaxLatin1 { + ret _PROPERTIES[u8(r)]&__P_P != 0 + } + ret Is(Punct, r) } // Reports whether the rune is a space character as defined @@ -105,13 +105,13 @@ fn IsPunct(r: rune): bool { // Other definitions of spacing characters are set by category // Z and property Pattern_White_Space. fn IsSpace(r: rune): bool { - // This property isn't the same as Z; special-case it. - if u32(r) <= MaxLatin1 { - match r { - | '\t' | '\n' | '\v' | '\f' | '\r' | ' ' | 0x85 | 0xA0: - ret true - } - ret false - } - ret isExcludingLatin(WhiteSpace, r) + // This property isn't the same as Z; special-case it. + if u32(r) <= MaxLatin1 { + match r { + | '\t' | '\n' | '\v' | '\f' | '\r' | ' ' | 0x85 | 0xA0: + ret true + } + ret false + } + ret isExcludingLatin(WhiteSpace, r) } \ No newline at end of file diff --git a/std/unicode/letter.jule b/std/unicode/letter.jule index 9567ad760..e775b2225 100644 --- a/std/unicode/letter.jule +++ b/std/unicode/letter.jule @@ -70,8 +70,8 @@ type d: [MaxCase]rune // will fail (the constants in the composite literal will not fit in u16) // and the types here can change to u32. struct foldPair { - from: u16 - to: u16 + from: u16 + to: u16 } // Represents a range of Unicode code points for simple (one @@ -87,26 +87,26 @@ struct foldPair { // // The constant UPPER_LOWER has an otherwise impossible delta value. struct caseRange { - lo: u32 - hi: u32 - delta: d + lo: u32 + hi: u32 + delta: d } // Represents of a range of 16-bit Unicode code points. The range runs from lo to hi // inclusive and has the specified stride. struct Range16 { - Lo: u16 - Hi: u16 - Stride: u16 + Lo: u16 + Hi: u16 + Stride: u16 } // Represents of a range of Unicode code points and is used when one or // more of the values will not fit in 16 bits. The range runs from lo to hi // inclusive and has the specified stride. lo and hi must always be >= 1<<16. struct Range32 { - Lo: u32 - Hi: u32 - Stride: u32 + Lo: u32 + Hi: u32 + Stride: u32 } // Defines a set of Unicode code points by listing the ranges of @@ -115,196 +115,196 @@ struct Range32 { // The two slices must be in sorted order and non-overlapping. // Also, R32 should contain only values >= 0x10000 (1<<16). struct RangeTable { - R16: []Range16 - R32: []Range32 - LatinOffset: int // number of entries in R16 with Hi <= MaxLatin1 + R16: []Range16 + R32: []Range32 + LatinOffset: int // number of entries in R16 with Hi <= MaxLatin1 } // to maps the rune using the specified case mapping. // It additionally reports whether caseRange contained a mapping for r. fn to(case: int, r: rune, caseRange: []caseRange): (mappedRune: rune, foundMapping: bool) { - if case < 0 || MaxCase <= case { - ret ReplacementChar, false // as reasonable an error as any - } + if case < 0 || MaxCase <= case { + ret ReplacementChar, false // as reasonable an error as any + } - // binary search over ranges - mut lo := 0 - mut hi := len(caseRange) - for lo < hi { - m := lo + (hi - lo) / 2 - cr := caseRange[m] - if rune(cr.lo) <= r && r <= rune(cr.hi) { - delta := cr.delta[case] - if delta > MaxRune { - // In an Upper-Lower sequence, which always starts with - // an UpperCase letter, the real deltas always look like: - // {0, 1, 0} UpperCase (Lower is next) - // {-1, 0, -1} LowerCase (Upper, Title are previous) - // The characters at even offsets from the beginning of the - // sequence are upper case; the ones at odd offsets are lower. - // The correct mapping can be done by clearing or setting the low - // bit in the sequence offset. - // The constants UpperCase and TitleCase are even while LowerCase - // is odd so we take the low bit from case. - ret rune(cr.lo) + ((r - rune(cr.lo)) & ^1 | rune(case & 1)), true - } - ret r + delta, true - } - if r < rune(cr.lo) { - hi = m - } else { - lo = m + 1 - } - } - ret r, false + // binary search over ranges + mut lo := 0 + mut hi := len(caseRange) + for lo < hi { + m := lo + (hi - lo) / 2 + cr := caseRange[m] + if rune(cr.lo) <= r && r <= rune(cr.hi) { + delta := cr.delta[case] + if delta > MaxRune { + // In an Upper-Lower sequence, which always starts with + // an UpperCase letter, the real deltas always look like: + // {0, 1, 0} UpperCase (Lower is next) + // {-1, 0, -1} LowerCase (Upper, Title are previous) + // The characters at even offsets from the beginning of the + // sequence are upper case; the ones at odd offsets are lower. + // The correct mapping can be done by clearing or setting the low + // bit in the sequence offset. + // The constants UpperCase and TitleCase are even while LowerCase + // is odd so we take the low bit from case. + ret rune(cr.lo) + ((r - rune(cr.lo)) & ^1 | rune(case & 1)), true + } + ret r + delta, true + } + if r < rune(cr.lo) { + hi = m + } else { + lo = m + 1 + } + } + ret r, false } // Maps the rune to the specified case: UpperCase, LowerCase, or TitleCase. fn To(case: int, mut r: rune): rune { - r, _ = to(case, r, CASE_RANGES) - ret r + r, _ = to(case, r, CASE_RANGES) + ret r } // Maps the rune to upper case. fn ToUpper(mut r: rune): rune { - if r <= MaxASCII { - if 'a' <= r && r <= 'z' { - r -= 'a' - 'A' - } - ret r - } - ret To(UpperCase, r) + if r <= MaxASCII { + if 'a' <= r && r <= 'z' { + r -= 'a' - 'A' + } + ret r + } + ret To(UpperCase, r) } // Maps the rune to lower case. fn ToLower(mut r: rune): rune { - if r <= MaxASCII { - if 'A' <= r && r <= 'Z' { - r += 'a' - 'A' - } - ret r - } - ret To(LowerCase, r) + if r <= MaxASCII { + if 'A' <= r && r <= 'Z' { + r += 'a' - 'A' + } + ret r + } + ret To(LowerCase, r) } // Reports whether r is in the sorted slice of 16-bit ranges. fn is16(ranges: []Range16, r: u16): bool { - if len(ranges) <= linearMax || r <= MaxLatin1 { - for i in ranges { - range := &ranges[i] - unsafe { - if r < range.Lo { - ret false - } - if r <= range.Hi { - ret range.Stride == 1 || (r-range.Lo)%range.Stride == 0 - } - } - } - ret false - } + if len(ranges) <= linearMax || r <= MaxLatin1 { + for i in ranges { + range := &ranges[i] + unsafe { + if r < range.Lo { + ret false + } + if r <= range.Hi { + ret range.Stride == 1 || (r-range.Lo)%range.Stride == 0 + } + } + } + ret false + } - // binary search over ranges - mut lo := 0 - mut hi := len(ranges) - for lo < hi { - m := lo + (hi - lo) / 2 - range := &ranges[m] - unsafe { - if range.Lo <= r && r <= range.Hi { - ret range.Stride == 1 || (r-range.Lo)%range.Stride == 0 - } - if r < range.Lo { - hi = m - } else { - lo = m + 1 - } - } - } - ret false + // binary search over ranges + mut lo := 0 + mut hi := len(ranges) + for lo < hi { + m := lo + (hi - lo) / 2 + range := &ranges[m] + unsafe { + if range.Lo <= r && r <= range.Hi { + ret range.Stride == 1 || (r-range.Lo)%range.Stride == 0 + } + if r < range.Lo { + hi = m + } else { + lo = m + 1 + } + } + } + ret false } // Reports whether r is in the sorted slice of 32-bit ranges. fn is32(ranges: []Range32, r: u32): bool { - if len(ranges) <= linearMax { - for i in ranges { - range := &ranges[i] - unsafe { - if r < range.Lo { - ret false - } - if r <= range.Hi { - ret range.Stride == 1 || (r-range.Lo)%range.Stride == 0 - } - } - } - ret false - } + if len(ranges) <= linearMax { + for i in ranges { + range := &ranges[i] + unsafe { + if r < range.Lo { + ret false + } + if r <= range.Hi { + ret range.Stride == 1 || (r-range.Lo)%range.Stride == 0 + } + } + } + ret false + } - // binary search over ranges - mut lo := 0 - mut hi := len(ranges) - for lo < hi { - m := lo + (hi - lo) / 2 - range := &ranges[m] - unsafe { - if range.Lo <= r && r <= range.Hi { - ret range.Stride == 1 || (r-range.Lo)%range.Stride == 0 - } - if r < range.Lo { - hi = m - } else { - lo = m + 1 - } - } - } - ret false + // binary search over ranges + mut lo := 0 + mut hi := len(ranges) + for lo < hi { + m := lo + (hi - lo) / 2 + range := &ranges[m] + unsafe { + if range.Lo <= r && r <= range.Hi { + ret range.Stride == 1 || (r-range.Lo)%range.Stride == 0 + } + if r < range.Lo { + hi = m + } else { + lo = m + 1 + } + } + } + ret false } // Reports whether the rune is in the specified table of ranges. fn Is(rangeTab: &RangeTable, r: rune): bool { - &R16 := rangeTab.R16 - // Compare as u32 to correctly handle negative runes. - if len(R16) > 0 && u32(r) <= u32(R16[len(R16)-1].Hi) { - ret is16(R16, u16(r)) - } - &R32 := rangeTab.R32 - if len(R32) > 0 && r >= rune(R32[0].Lo) { - ret is32(R32, u32(r)) - } - ret false + &R16 := rangeTab.R16 + // Compare as u32 to correctly handle negative runes. + if len(R16) > 0 && u32(r) <= u32(R16[len(R16)-1].Hi) { + ret is16(R16, u16(r)) + } + &R32 := rangeTab.R32 + if len(R32) > 0 && r >= rune(R32[0].Lo) { + ret is32(R32, u32(r)) + } + ret false } fn isExcludingLatin(rangeTab: &RangeTable, r: rune): bool { - { - &R16 := rangeTab.R16 - // Compare as u32 to correctly handle negative runes. - off := rangeTab.LatinOffset - if len(R16) > off && u32(r) <= u32(R16[len(R16)-1].Hi) { - ret is16(R16[off:], u16(r)) - } - } - &R32 := rangeTab.R32 - if len(R32) > 0 && r >= rune(R32[0].Lo) { - ret is32(R32, u32(r)) - } - ret false + { + &R16 := rangeTab.R16 + // Compare as u32 to correctly handle negative runes. + off := rangeTab.LatinOffset + if len(R16) > off && u32(r) <= u32(R16[len(R16)-1].Hi) { + ret is16(R16[off:], u16(r)) + } + } + &R32 := rangeTab.R32 + if len(R32) > 0 && r >= rune(R32[0].Lo) { + ret is32(R32, u32(r)) + } + ret false } // Reports whether the rune is an upper case letter. fn IsUpper(r: rune): bool { - // See comment in is_graphic. - if u32(r) <= MaxLatin1 { - ret _PROPERTIES[u8(r)]&__P_L_MASK == __P_LU - } - ret isExcludingLatin(Upper, r) + // See comment in is_graphic. + if u32(r) <= MaxLatin1 { + ret _PROPERTIES[u8(r)]&__P_L_MASK == __P_LU + } + ret isExcludingLatin(Upper, r) } // Reports whether the rune is a lower case letter. fn IsLower(r: rune): bool { - // See comment in is_graphic. - if u32(r) <= MaxLatin1 { - ret _PROPERTIES[u8(r)]&__P_L_MASK == __P_LL - } - ret isExcludingLatin(Lower, r) + // See comment in is_graphic. + if u32(r) <= MaxLatin1 { + ret _PROPERTIES[u8(r)]&__P_L_MASK == __P_LL + } + ret isExcludingLatin(Lower, r) } \ No newline at end of file diff --git a/std/unicode/tables.jule b/std/unicode/tables.jule index 161a0570b..bf6283059 100644 --- a/std/unicode/tables.jule +++ b/std/unicode/tables.jule @@ -37,3744 +37,3744 @@ // The set of Unicode category tables. static Categories: map[str]&RangeTable = { - "C": C, - "CC": CC, - "CF": CF, - "CO": CO, - "CS": CS, - "L": L, - "LL": LL, - "LM": LM, - "LO": LO, - "LT": LT, - "LU": LU, - "M": M, - "MC": MC, - "ME": ME, - "MN": MN, - "N": N, - "ND": ND, - "NL": NL, - "NO": NO, - "P": P, - "PC": PC, - "PD": PD, - "PE": PE, - "PF": PF, - "PI": PI, - "PO": PO, - "PS": PS, - "S": S, - "SC": SC, - "SK": SK, - "SM": SM, - "SO": SO, - "Z": Z, - "ZL": ZL, - "ZP": ZP, - "ZS": ZS, + "C": C, + "CC": CC, + "CF": CF, + "CO": CO, + "CS": CS, + "L": L, + "LL": LL, + "LM": LM, + "LO": LO, + "LT": LT, + "LU": LU, + "M": M, + "MC": MC, + "ME": ME, + "MN": MN, + "N": N, + "ND": ND, + "NL": NL, + "NO": NO, + "P": P, + "PC": PC, + "PD": PD, + "PE": PE, + "PF": PF, + "PI": PI, + "PO": PO, + "PS": PS, + "S": S, + "SC": SC, + "SK": SK, + "SM": SM, + "SO": SO, + "Z": Z, + "ZL": ZL, + "ZP": ZP, + "ZS": ZS, } static _C = &RangeTable{ - R16: [ - {0x0000, 0x001f, 1}, - {0x007f, 0x009f, 1}, - {0x00ad, 0x0600, 1363}, - {0x0601, 0x0605, 1}, - {0x061c, 0x06dd, 193}, - {0x070f, 0x0890, 385}, - {0x0891, 0x08e2, 81}, - {0x180e, 0x200b, 2045}, - {0x200c, 0x200f, 1}, - {0x202a, 0x202e, 1}, - {0x2060, 0x2064, 1}, - {0x2066, 0x206f, 1}, - {0xd800, 0xf8ff, 1}, - {0xfeff, 0xfff9, 250}, - {0xfffa, 0xfffb, 1}, - ], - R32: [ - {0x110bd, 0x110cd, 16}, - {0x13430, 0x1343f, 1}, - {0x1bca0, 0x1bca3, 1}, - {0x1d173, 0x1d17a, 1}, - {0xe0001, 0xe0020, 31}, - {0xe0021, 0xe007f, 1}, - {0xf0000, 0xffffd, 1}, - {0x100000, 0x10fffd, 1}, - ], - LatinOffset: 2, + R16: [ + {0x0000, 0x001f, 1}, + {0x007f, 0x009f, 1}, + {0x00ad, 0x0600, 1363}, + {0x0601, 0x0605, 1}, + {0x061c, 0x06dd, 193}, + {0x070f, 0x0890, 385}, + {0x0891, 0x08e2, 81}, + {0x180e, 0x200b, 2045}, + {0x200c, 0x200f, 1}, + {0x202a, 0x202e, 1}, + {0x2060, 0x2064, 1}, + {0x2066, 0x206f, 1}, + {0xd800, 0xf8ff, 1}, + {0xfeff, 0xfff9, 250}, + {0xfffa, 0xfffb, 1}, + ], + R32: [ + {0x110bd, 0x110cd, 16}, + {0x13430, 0x1343f, 1}, + {0x1bca0, 0x1bca3, 1}, + {0x1d173, 0x1d17a, 1}, + {0xe0001, 0xe0020, 31}, + {0xe0021, 0xe007f, 1}, + {0xf0000, 0xffffd, 1}, + {0x100000, 0x10fffd, 1}, + ], + LatinOffset: 2, } static _CC = &RangeTable{ - R16: [ - {0x0000, 0x001f, 1}, - {0x007f, 0x009f, 1}, - ], - LatinOffset: 2, + R16: [ + {0x0000, 0x001f, 1}, + {0x007f, 0x009f, 1}, + ], + LatinOffset: 2, } static _CF = &RangeTable{ - R16: [ - {0x00ad, 0x0600, 1363}, - {0x0601, 0x0605, 1}, - {0x061c, 0x06dd, 193}, - {0x070f, 0x0890, 385}, - {0x0891, 0x08e2, 81}, - {0x180e, 0x200b, 2045}, - {0x200c, 0x200f, 1}, - {0x202a, 0x202e, 1}, - {0x2060, 0x2064, 1}, - {0x2066, 0x206f, 1}, - {0xfeff, 0xfff9, 250}, - {0xfffa, 0xfffb, 1}, - ], - R32: [ - {0x110bd, 0x110cd, 16}, - {0x13430, 0x1343f, 1}, - {0x1bca0, 0x1bca3, 1}, - {0x1d173, 0x1d17a, 1}, - {0xe0001, 0xe0020, 31}, - {0xe0021, 0xe007f, 1}, - ], + R16: [ + {0x00ad, 0x0600, 1363}, + {0x0601, 0x0605, 1}, + {0x061c, 0x06dd, 193}, + {0x070f, 0x0890, 385}, + {0x0891, 0x08e2, 81}, + {0x180e, 0x200b, 2045}, + {0x200c, 0x200f, 1}, + {0x202a, 0x202e, 1}, + {0x2060, 0x2064, 1}, + {0x2066, 0x206f, 1}, + {0xfeff, 0xfff9, 250}, + {0xfffa, 0xfffb, 1}, + ], + R32: [ + {0x110bd, 0x110cd, 16}, + {0x13430, 0x1343f, 1}, + {0x1bca0, 0x1bca3, 1}, + {0x1d173, 0x1d17a, 1}, + {0xe0001, 0xe0020, 31}, + {0xe0021, 0xe007f, 1}, + ], } static _CO = &RangeTable{ - R16: [ - {0xe000, 0xf8ff, 1}, - ], - R32: [ - {0xf0000, 0xffffd, 1}, - {0x100000, 0x10fffd, 1}, - ], + R16: [ + {0xe000, 0xf8ff, 1}, + ], + R32: [ + {0xf0000, 0xffffd, 1}, + {0x100000, 0x10fffd, 1}, + ], } static _CS = &RangeTable{ - R16: [ - {0xd800, 0xdfff, 1}, - ], + R16: [ + {0xd800, 0xdfff, 1}, + ], } static _L = &RangeTable{ - R16: [ - {0x0041, 0x005a, 1}, - {0x0061, 0x007a, 1}, - {0x00aa, 0x00b5, 11}, - {0x00ba, 0x00c0, 6}, - {0x00c1, 0x00d6, 1}, - {0x00d8, 0x00f6, 1}, - {0x00f8, 0x02c1, 1}, - {0x02c6, 0x02d1, 1}, - {0x02e0, 0x02e4, 1}, - {0x02ec, 0x02ee, 2}, - {0x0370, 0x0374, 1}, - {0x0376, 0x0377, 1}, - {0x037a, 0x037d, 1}, - {0x037f, 0x0386, 7}, - {0x0388, 0x038a, 1}, - {0x038c, 0x038e, 2}, - {0x038f, 0x03a1, 1}, - {0x03a3, 0x03f5, 1}, - {0x03f7, 0x0481, 1}, - {0x048a, 0x052f, 1}, - {0x0531, 0x0556, 1}, - {0x0559, 0x0560, 7}, - {0x0561, 0x0588, 1}, - {0x05d0, 0x05ea, 1}, - {0x05ef, 0x05f2, 1}, - {0x0620, 0x064a, 1}, - {0x066e, 0x066f, 1}, - {0x0671, 0x06d3, 1}, - {0x06d5, 0x06e5, 16}, - {0x06e6, 0x06ee, 8}, - {0x06ef, 0x06fa, 11}, - {0x06fb, 0x06fc, 1}, - {0x06ff, 0x0710, 17}, - {0x0712, 0x072f, 1}, - {0x074d, 0x07a5, 1}, - {0x07b1, 0x07ca, 25}, - {0x07cb, 0x07ea, 1}, - {0x07f4, 0x07f5, 1}, - {0x07fa, 0x0800, 6}, - {0x0801, 0x0815, 1}, - {0x081a, 0x0824, 10}, - {0x0828, 0x0840, 24}, - {0x0841, 0x0858, 1}, - {0x0860, 0x086a, 1}, - {0x0870, 0x0887, 1}, - {0x0889, 0x088e, 1}, - {0x08a0, 0x08c9, 1}, - {0x0904, 0x0939, 1}, - {0x093d, 0x0950, 19}, - {0x0958, 0x0961, 1}, - {0x0971, 0x0980, 1}, - {0x0985, 0x098c, 1}, - {0x098f, 0x0990, 1}, - {0x0993, 0x09a8, 1}, - {0x09aa, 0x09b0, 1}, - {0x09b2, 0x09b6, 4}, - {0x09b7, 0x09b9, 1}, - {0x09bd, 0x09ce, 17}, - {0x09dc, 0x09dd, 1}, - {0x09df, 0x09e1, 1}, - {0x09f0, 0x09f1, 1}, - {0x09fc, 0x0a05, 9}, - {0x0a06, 0x0a0a, 1}, - {0x0a0f, 0x0a10, 1}, - {0x0a13, 0x0a28, 1}, - {0x0a2a, 0x0a30, 1}, - {0x0a32, 0x0a33, 1}, - {0x0a35, 0x0a36, 1}, - {0x0a38, 0x0a39, 1}, - {0x0a59, 0x0a5c, 1}, - {0x0a5e, 0x0a72, 20}, - {0x0a73, 0x0a74, 1}, - {0x0a85, 0x0a8d, 1}, - {0x0a8f, 0x0a91, 1}, - {0x0a93, 0x0aa8, 1}, - {0x0aaa, 0x0ab0, 1}, - {0x0ab2, 0x0ab3, 1}, - {0x0ab5, 0x0ab9, 1}, - {0x0abd, 0x0ad0, 19}, - {0x0ae0, 0x0ae1, 1}, - {0x0af9, 0x0b05, 12}, - {0x0b06, 0x0b0c, 1}, - {0x0b0f, 0x0b10, 1}, - {0x0b13, 0x0b28, 1}, - {0x0b2a, 0x0b30, 1}, - {0x0b32, 0x0b33, 1}, - {0x0b35, 0x0b39, 1}, - {0x0b3d, 0x0b5c, 31}, - {0x0b5d, 0x0b5f, 2}, - {0x0b60, 0x0b61, 1}, - {0x0b71, 0x0b83, 18}, - {0x0b85, 0x0b8a, 1}, - {0x0b8e, 0x0b90, 1}, - {0x0b92, 0x0b95, 1}, - {0x0b99, 0x0b9a, 1}, - {0x0b9c, 0x0b9e, 2}, - {0x0b9f, 0x0ba3, 4}, - {0x0ba4, 0x0ba8, 4}, - {0x0ba9, 0x0baa, 1}, - {0x0bae, 0x0bb9, 1}, - {0x0bd0, 0x0c05, 53}, - {0x0c06, 0x0c0c, 1}, - {0x0c0e, 0x0c10, 1}, - {0x0c12, 0x0c28, 1}, - {0x0c2a, 0x0c39, 1}, - {0x0c3d, 0x0c58, 27}, - {0x0c59, 0x0c5a, 1}, - {0x0c5d, 0x0c60, 3}, - {0x0c61, 0x0c80, 31}, - {0x0c85, 0x0c8c, 1}, - {0x0c8e, 0x0c90, 1}, - {0x0c92, 0x0ca8, 1}, - {0x0caa, 0x0cb3, 1}, - {0x0cb5, 0x0cb9, 1}, - {0x0cbd, 0x0cdd, 32}, - {0x0cde, 0x0ce0, 2}, - {0x0ce1, 0x0cf1, 16}, - {0x0cf2, 0x0d04, 18}, - {0x0d05, 0x0d0c, 1}, - {0x0d0e, 0x0d10, 1}, - {0x0d12, 0x0d3a, 1}, - {0x0d3d, 0x0d4e, 17}, - {0x0d54, 0x0d56, 1}, - {0x0d5f, 0x0d61, 1}, - {0x0d7a, 0x0d7f, 1}, - {0x0d85, 0x0d96, 1}, - {0x0d9a, 0x0db1, 1}, - {0x0db3, 0x0dbb, 1}, - {0x0dbd, 0x0dc0, 3}, - {0x0dc1, 0x0dc6, 1}, - {0x0e01, 0x0e30, 1}, - {0x0e32, 0x0e33, 1}, - {0x0e40, 0x0e46, 1}, - {0x0e81, 0x0e82, 1}, - {0x0e84, 0x0e86, 2}, - {0x0e87, 0x0e8a, 1}, - {0x0e8c, 0x0ea3, 1}, - {0x0ea5, 0x0ea7, 2}, - {0x0ea8, 0x0eb0, 1}, - {0x0eb2, 0x0eb3, 1}, - {0x0ebd, 0x0ec0, 3}, - {0x0ec1, 0x0ec4, 1}, - {0x0ec6, 0x0edc, 22}, - {0x0edd, 0x0edf, 1}, - {0x0f00, 0x0f40, 64}, - {0x0f41, 0x0f47, 1}, - {0x0f49, 0x0f6c, 1}, - {0x0f88, 0x0f8c, 1}, - {0x1000, 0x102a, 1}, - {0x103f, 0x1050, 17}, - {0x1051, 0x1055, 1}, - {0x105a, 0x105d, 1}, - {0x1061, 0x1065, 4}, - {0x1066, 0x106e, 8}, - {0x106f, 0x1070, 1}, - {0x1075, 0x1081, 1}, - {0x108e, 0x10a0, 18}, - {0x10a1, 0x10c5, 1}, - {0x10c7, 0x10cd, 6}, - {0x10d0, 0x10fa, 1}, - {0x10fc, 0x1248, 1}, - {0x124a, 0x124d, 1}, - {0x1250, 0x1256, 1}, - {0x1258, 0x125a, 2}, - {0x125b, 0x125d, 1}, - {0x1260, 0x1288, 1}, - {0x128a, 0x128d, 1}, - {0x1290, 0x12b0, 1}, - {0x12b2, 0x12b5, 1}, - {0x12b8, 0x12be, 1}, - {0x12c0, 0x12c2, 2}, - {0x12c3, 0x12c5, 1}, - {0x12c8, 0x12d6, 1}, - {0x12d8, 0x1310, 1}, - {0x1312, 0x1315, 1}, - {0x1318, 0x135a, 1}, - {0x1380, 0x138f, 1}, - {0x13a0, 0x13f5, 1}, - {0x13f8, 0x13fd, 1}, - {0x1401, 0x166c, 1}, - {0x166f, 0x167f, 1}, - {0x1681, 0x169a, 1}, - {0x16a0, 0x16ea, 1}, - {0x16f1, 0x16f8, 1}, - {0x1700, 0x1711, 1}, - {0x171f, 0x1731, 1}, - {0x1740, 0x1751, 1}, - {0x1760, 0x176c, 1}, - {0x176e, 0x1770, 1}, - {0x1780, 0x17b3, 1}, - {0x17d7, 0x17dc, 5}, - {0x1820, 0x1878, 1}, - {0x1880, 0x1884, 1}, - {0x1887, 0x18a8, 1}, - {0x18aa, 0x18b0, 6}, - {0x18b1, 0x18f5, 1}, - {0x1900, 0x191e, 1}, - {0x1950, 0x196d, 1}, - {0x1970, 0x1974, 1}, - {0x1980, 0x19ab, 1}, - {0x19b0, 0x19c9, 1}, - {0x1a00, 0x1a16, 1}, - {0x1a20, 0x1a54, 1}, - {0x1aa7, 0x1b05, 94}, - {0x1b06, 0x1b33, 1}, - {0x1b45, 0x1b4c, 1}, - {0x1b83, 0x1ba0, 1}, - {0x1bae, 0x1baf, 1}, - {0x1bba, 0x1be5, 1}, - {0x1c00, 0x1c23, 1}, - {0x1c4d, 0x1c4f, 1}, - {0x1c5a, 0x1c7d, 1}, - {0x1c80, 0x1c88, 1}, - {0x1c90, 0x1cba, 1}, - {0x1cbd, 0x1cbf, 1}, - {0x1ce9, 0x1cec, 1}, - {0x1cee, 0x1cf3, 1}, - {0x1cf5, 0x1cf6, 1}, - {0x1cfa, 0x1d00, 6}, - {0x1d01, 0x1dbf, 1}, - {0x1e00, 0x1f15, 1}, - {0x1f18, 0x1f1d, 1}, - {0x1f20, 0x1f45, 1}, - {0x1f48, 0x1f4d, 1}, - {0x1f50, 0x1f57, 1}, - {0x1f59, 0x1f5f, 2}, - {0x1f60, 0x1f7d, 1}, - {0x1f80, 0x1fb4, 1}, - {0x1fb6, 0x1fbc, 1}, - {0x1fbe, 0x1fc2, 4}, - {0x1fc3, 0x1fc4, 1}, - {0x1fc6, 0x1fcc, 1}, - {0x1fd0, 0x1fd3, 1}, - {0x1fd6, 0x1fdb, 1}, - {0x1fe0, 0x1fec, 1}, - {0x1ff2, 0x1ff4, 1}, - {0x1ff6, 0x1ffc, 1}, - {0x2071, 0x207f, 14}, - {0x2090, 0x209c, 1}, - {0x2102, 0x2107, 5}, - {0x210a, 0x2113, 1}, - {0x2115, 0x2119, 4}, - {0x211a, 0x211d, 1}, - {0x2124, 0x212a, 2}, - {0x212b, 0x212d, 1}, - {0x212f, 0x2139, 1}, - {0x213c, 0x213f, 1}, - {0x2145, 0x2149, 1}, - {0x214e, 0x2183, 53}, - {0x2184, 0x2c00, 2684}, - {0x2c01, 0x2ce4, 1}, - {0x2ceb, 0x2cee, 1}, - {0x2cf2, 0x2cf3, 1}, - {0x2d00, 0x2d25, 1}, - {0x2d27, 0x2d2d, 6}, - {0x2d30, 0x2d67, 1}, - {0x2d6f, 0x2d80, 17}, - {0x2d81, 0x2d96, 1}, - {0x2da0, 0x2da6, 1}, - {0x2da8, 0x2dae, 1}, - {0x2db0, 0x2db6, 1}, - {0x2db8, 0x2dbe, 1}, - {0x2dc0, 0x2dc6, 1}, - {0x2dc8, 0x2dce, 1}, - {0x2dd0, 0x2dd6, 1}, - {0x2dd8, 0x2dde, 1}, - {0x2e2f, 0x3005, 470}, - {0x3006, 0x3031, 43}, - {0x3032, 0x3035, 1}, - {0x303b, 0x303c, 1}, - {0x3041, 0x3096, 1}, - {0x309d, 0x309f, 1}, - {0x30a1, 0x30fa, 1}, - {0x30fc, 0x30ff, 1}, - {0x3105, 0x312f, 1}, - {0x3131, 0x318e, 1}, - {0x31a0, 0x31bf, 1}, - {0x31f0, 0x31ff, 1}, - {0x3400, 0x4dbf, 1}, - {0x4e00, 0xa48c, 1}, - {0xa4d0, 0xa4fd, 1}, - {0xa500, 0xa60c, 1}, - {0xa610, 0xa61f, 1}, - {0xa62a, 0xa62b, 1}, - {0xa640, 0xa66e, 1}, - {0xa67f, 0xa69d, 1}, - {0xa6a0, 0xa6e5, 1}, - {0xa717, 0xa71f, 1}, - {0xa722, 0xa788, 1}, - {0xa78b, 0xa7ca, 1}, - {0xa7d0, 0xa7d1, 1}, - {0xa7d3, 0xa7d5, 2}, - {0xa7d6, 0xa7d9, 1}, - {0xa7f2, 0xa801, 1}, - {0xa803, 0xa805, 1}, - {0xa807, 0xa80a, 1}, - {0xa80c, 0xa822, 1}, - {0xa840, 0xa873, 1}, - {0xa882, 0xa8b3, 1}, - {0xa8f2, 0xa8f7, 1}, - {0xa8fb, 0xa8fd, 2}, - {0xa8fe, 0xa90a, 12}, - {0xa90b, 0xa925, 1}, - {0xa930, 0xa946, 1}, - {0xa960, 0xa97c, 1}, - {0xa984, 0xa9b2, 1}, - {0xa9cf, 0xa9e0, 17}, - {0xa9e1, 0xa9e4, 1}, - {0xa9e6, 0xa9ef, 1}, - {0xa9fa, 0xa9fe, 1}, - {0xaa00, 0xaa28, 1}, - {0xaa40, 0xaa42, 1}, - {0xaa44, 0xaa4b, 1}, - {0xaa60, 0xaa76, 1}, - {0xaa7a, 0xaa7e, 4}, - {0xaa7f, 0xaaaf, 1}, - {0xaab1, 0xaab5, 4}, - {0xaab6, 0xaab9, 3}, - {0xaaba, 0xaabd, 1}, - {0xaac0, 0xaac2, 2}, - {0xaadb, 0xaadd, 1}, - {0xaae0, 0xaaea, 1}, - {0xaaf2, 0xaaf4, 1}, - {0xab01, 0xab06, 1}, - {0xab09, 0xab0e, 1}, - {0xab11, 0xab16, 1}, - {0xab20, 0xab26, 1}, - {0xab28, 0xab2e, 1}, - {0xab30, 0xab5a, 1}, - {0xab5c, 0xab69, 1}, - {0xab70, 0xabe2, 1}, - {0xac00, 0xd7a3, 1}, - {0xd7b0, 0xd7c6, 1}, - {0xd7cb, 0xd7fb, 1}, - {0xf900, 0xfa6d, 1}, - {0xfa70, 0xfad9, 1}, - {0xfb00, 0xfb06, 1}, - {0xfb13, 0xfb17, 1}, - {0xfb1d, 0xfb1f, 2}, - {0xfb20, 0xfb28, 1}, - {0xfb2a, 0xfb36, 1}, - {0xfb38, 0xfb3c, 1}, - {0xfb3e, 0xfb40, 2}, - {0xfb41, 0xfb43, 2}, - {0xfb44, 0xfb46, 2}, - {0xfb47, 0xfbb1, 1}, - {0xfbd3, 0xfd3d, 1}, - {0xfd50, 0xfd8f, 1}, - {0xfd92, 0xfdc7, 1}, - {0xfdf0, 0xfdfb, 1}, - {0xfe70, 0xfe74, 1}, - {0xfe76, 0xfefc, 1}, - {0xff21, 0xff3a, 1}, - {0xff41, 0xff5a, 1}, - {0xff66, 0xffbe, 1}, - {0xffc2, 0xffc7, 1}, - {0xffca, 0xffcf, 1}, - {0xffd2, 0xffd7, 1}, - {0xffda, 0xffdc, 1}, - ], - R32: [ - {0x10000, 0x1000b, 1}, - {0x1000d, 0x10026, 1}, - {0x10028, 0x1003a, 1}, - {0x1003c, 0x1003d, 1}, - {0x1003f, 0x1004d, 1}, - {0x10050, 0x1005d, 1}, - {0x10080, 0x100fa, 1}, - {0x10280, 0x1029c, 1}, - {0x102a0, 0x102d0, 1}, - {0x10300, 0x1031f, 1}, - {0x1032d, 0x10340, 1}, - {0x10342, 0x10349, 1}, - {0x10350, 0x10375, 1}, - {0x10380, 0x1039d, 1}, - {0x103a0, 0x103c3, 1}, - {0x103c8, 0x103cf, 1}, - {0x10400, 0x1049d, 1}, - {0x104b0, 0x104d3, 1}, - {0x104d8, 0x104fb, 1}, - {0x10500, 0x10527, 1}, - {0x10530, 0x10563, 1}, - {0x10570, 0x1057a, 1}, - {0x1057c, 0x1058a, 1}, - {0x1058c, 0x10592, 1}, - {0x10594, 0x10595, 1}, - {0x10597, 0x105a1, 1}, - {0x105a3, 0x105b1, 1}, - {0x105b3, 0x105b9, 1}, - {0x105bb, 0x105bc, 1}, - {0x10600, 0x10736, 1}, - {0x10740, 0x10755, 1}, - {0x10760, 0x10767, 1}, - {0x10780, 0x10785, 1}, - {0x10787, 0x107b0, 1}, - {0x107b2, 0x107ba, 1}, - {0x10800, 0x10805, 1}, - {0x10808, 0x1080a, 2}, - {0x1080b, 0x10835, 1}, - {0x10837, 0x10838, 1}, - {0x1083c, 0x1083f, 3}, - {0x10840, 0x10855, 1}, - {0x10860, 0x10876, 1}, - {0x10880, 0x1089e, 1}, - {0x108e0, 0x108f2, 1}, - {0x108f4, 0x108f5, 1}, - {0x10900, 0x10915, 1}, - {0x10920, 0x10939, 1}, - {0x10980, 0x109b7, 1}, - {0x109be, 0x109bf, 1}, - {0x10a00, 0x10a10, 16}, - {0x10a11, 0x10a13, 1}, - {0x10a15, 0x10a17, 1}, - {0x10a19, 0x10a35, 1}, - {0x10a60, 0x10a7c, 1}, - {0x10a80, 0x10a9c, 1}, - {0x10ac0, 0x10ac7, 1}, - {0x10ac9, 0x10ae4, 1}, - {0x10b00, 0x10b35, 1}, - {0x10b40, 0x10b55, 1}, - {0x10b60, 0x10b72, 1}, - {0x10b80, 0x10b91, 1}, - {0x10c00, 0x10c48, 1}, - {0x10c80, 0x10cb2, 1}, - {0x10cc0, 0x10cf2, 1}, - {0x10d00, 0x10d23, 1}, - {0x10e80, 0x10ea9, 1}, - {0x10eb0, 0x10eb1, 1}, - {0x10f00, 0x10f1c, 1}, - {0x10f27, 0x10f30, 9}, - {0x10f31, 0x10f45, 1}, - {0x10f70, 0x10f81, 1}, - {0x10fb0, 0x10fc4, 1}, - {0x10fe0, 0x10ff6, 1}, - {0x11003, 0x11037, 1}, - {0x11071, 0x11072, 1}, - {0x11075, 0x11083, 14}, - {0x11084, 0x110af, 1}, - {0x110d0, 0x110e8, 1}, - {0x11103, 0x11126, 1}, - {0x11144, 0x11147, 3}, - {0x11150, 0x11172, 1}, - {0x11176, 0x11183, 13}, - {0x11184, 0x111b2, 1}, - {0x111c1, 0x111c4, 1}, - {0x111da, 0x111dc, 2}, - {0x11200, 0x11211, 1}, - {0x11213, 0x1122b, 1}, - {0x1123f, 0x11240, 1}, - {0x11280, 0x11286, 1}, - {0x11288, 0x1128a, 2}, - {0x1128b, 0x1128d, 1}, - {0x1128f, 0x1129d, 1}, - {0x1129f, 0x112a8, 1}, - {0x112b0, 0x112de, 1}, - {0x11305, 0x1130c, 1}, - {0x1130f, 0x11310, 1}, - {0x11313, 0x11328, 1}, - {0x1132a, 0x11330, 1}, - {0x11332, 0x11333, 1}, - {0x11335, 0x11339, 1}, - {0x1133d, 0x11350, 19}, - {0x1135d, 0x11361, 1}, - {0x11400, 0x11434, 1}, - {0x11447, 0x1144a, 1}, - {0x1145f, 0x11461, 1}, - {0x11480, 0x114af, 1}, - {0x114c4, 0x114c5, 1}, - {0x114c7, 0x11580, 185}, - {0x11581, 0x115ae, 1}, - {0x115d8, 0x115db, 1}, - {0x11600, 0x1162f, 1}, - {0x11644, 0x11680, 60}, - {0x11681, 0x116aa, 1}, - {0x116b8, 0x11700, 72}, - {0x11701, 0x1171a, 1}, - {0x11740, 0x11746, 1}, - {0x11800, 0x1182b, 1}, - {0x118a0, 0x118df, 1}, - {0x118ff, 0x11906, 1}, - {0x11909, 0x1190c, 3}, - {0x1190d, 0x11913, 1}, - {0x11915, 0x11916, 1}, - {0x11918, 0x1192f, 1}, - {0x1193f, 0x11941, 2}, - {0x119a0, 0x119a7, 1}, - {0x119aa, 0x119d0, 1}, - {0x119e1, 0x119e3, 2}, - {0x11a00, 0x11a0b, 11}, - {0x11a0c, 0x11a32, 1}, - {0x11a3a, 0x11a50, 22}, - {0x11a5c, 0x11a89, 1}, - {0x11a9d, 0x11ab0, 19}, - {0x11ab1, 0x11af8, 1}, - {0x11c00, 0x11c08, 1}, - {0x11c0a, 0x11c2e, 1}, - {0x11c40, 0x11c72, 50}, - {0x11c73, 0x11c8f, 1}, - {0x11d00, 0x11d06, 1}, - {0x11d08, 0x11d09, 1}, - {0x11d0b, 0x11d30, 1}, - {0x11d46, 0x11d60, 26}, - {0x11d61, 0x11d65, 1}, - {0x11d67, 0x11d68, 1}, - {0x11d6a, 0x11d89, 1}, - {0x11d98, 0x11ee0, 328}, - {0x11ee1, 0x11ef2, 1}, - {0x11f02, 0x11f04, 2}, - {0x11f05, 0x11f10, 1}, - {0x11f12, 0x11f33, 1}, - {0x11fb0, 0x12000, 80}, - {0x12001, 0x12399, 1}, - {0x12480, 0x12543, 1}, - {0x12f90, 0x12ff0, 1}, - {0x13000, 0x1342f, 1}, - {0x13441, 0x13446, 1}, - {0x14400, 0x14646, 1}, - {0x16800, 0x16a38, 1}, - {0x16a40, 0x16a5e, 1}, - {0x16a70, 0x16abe, 1}, - {0x16ad0, 0x16aed, 1}, - {0x16b00, 0x16b2f, 1}, - {0x16b40, 0x16b43, 1}, - {0x16b63, 0x16b77, 1}, - {0x16b7d, 0x16b8f, 1}, - {0x16e40, 0x16e7f, 1}, - {0x16f00, 0x16f4a, 1}, - {0x16f50, 0x16f93, 67}, - {0x16f94, 0x16f9f, 1}, - {0x16fe0, 0x16fe1, 1}, - {0x16fe3, 0x17000, 29}, - {0x17001, 0x187f7, 1}, - {0x18800, 0x18cd5, 1}, - {0x18d00, 0x18d08, 1}, - {0x1aff0, 0x1aff3, 1}, - {0x1aff5, 0x1affb, 1}, - {0x1affd, 0x1affe, 1}, - {0x1b000, 0x1b122, 1}, - {0x1b132, 0x1b150, 30}, - {0x1b151, 0x1b152, 1}, - {0x1b155, 0x1b164, 15}, - {0x1b165, 0x1b167, 1}, - {0x1b170, 0x1b2fb, 1}, - {0x1bc00, 0x1bc6a, 1}, - {0x1bc70, 0x1bc7c, 1}, - {0x1bc80, 0x1bc88, 1}, - {0x1bc90, 0x1bc99, 1}, - {0x1d400, 0x1d454, 1}, - {0x1d456, 0x1d49c, 1}, - {0x1d49e, 0x1d49f, 1}, - {0x1d4a2, 0x1d4a5, 3}, - {0x1d4a6, 0x1d4a9, 3}, - {0x1d4aa, 0x1d4ac, 1}, - {0x1d4ae, 0x1d4b9, 1}, - {0x1d4bb, 0x1d4bd, 2}, - {0x1d4be, 0x1d4c3, 1}, - {0x1d4c5, 0x1d505, 1}, - {0x1d507, 0x1d50a, 1}, - {0x1d50d, 0x1d514, 1}, - {0x1d516, 0x1d51c, 1}, - {0x1d51e, 0x1d539, 1}, - {0x1d53b, 0x1d53e, 1}, - {0x1d540, 0x1d544, 1}, - {0x1d546, 0x1d54a, 4}, - {0x1d54b, 0x1d550, 1}, - {0x1d552, 0x1d6a5, 1}, - {0x1d6a8, 0x1d6c0, 1}, - {0x1d6c2, 0x1d6da, 1}, - {0x1d6dc, 0x1d6fa, 1}, - {0x1d6fc, 0x1d714, 1}, - {0x1d716, 0x1d734, 1}, - {0x1d736, 0x1d74e, 1}, - {0x1d750, 0x1d76e, 1}, - {0x1d770, 0x1d788, 1}, - {0x1d78a, 0x1d7a8, 1}, - {0x1d7aa, 0x1d7c2, 1}, - {0x1d7c4, 0x1d7cb, 1}, - {0x1df00, 0x1df1e, 1}, - {0x1df25, 0x1df2a, 1}, - {0x1e030, 0x1e06d, 1}, - {0x1e100, 0x1e12c, 1}, - {0x1e137, 0x1e13d, 1}, - {0x1e14e, 0x1e290, 322}, - {0x1e291, 0x1e2ad, 1}, - {0x1e2c0, 0x1e2eb, 1}, - {0x1e4d0, 0x1e4eb, 1}, - {0x1e7e0, 0x1e7e6, 1}, - {0x1e7e8, 0x1e7eb, 1}, - {0x1e7ed, 0x1e7ee, 1}, - {0x1e7f0, 0x1e7fe, 1}, - {0x1e800, 0x1e8c4, 1}, - {0x1e900, 0x1e943, 1}, - {0x1e94b, 0x1ee00, 1205}, - {0x1ee01, 0x1ee03, 1}, - {0x1ee05, 0x1ee1f, 1}, - {0x1ee21, 0x1ee22, 1}, - {0x1ee24, 0x1ee27, 3}, - {0x1ee29, 0x1ee32, 1}, - {0x1ee34, 0x1ee37, 1}, - {0x1ee39, 0x1ee3b, 2}, - {0x1ee42, 0x1ee47, 5}, - {0x1ee49, 0x1ee4d, 2}, - {0x1ee4e, 0x1ee4f, 1}, - {0x1ee51, 0x1ee52, 1}, - {0x1ee54, 0x1ee57, 3}, - {0x1ee59, 0x1ee61, 2}, - {0x1ee62, 0x1ee64, 2}, - {0x1ee67, 0x1ee6a, 1}, - {0x1ee6c, 0x1ee72, 1}, - {0x1ee74, 0x1ee77, 1}, - {0x1ee79, 0x1ee7c, 1}, - {0x1ee7e, 0x1ee80, 2}, - {0x1ee81, 0x1ee89, 1}, - {0x1ee8b, 0x1ee9b, 1}, - {0x1eea1, 0x1eea3, 1}, - {0x1eea5, 0x1eea9, 1}, - {0x1eeab, 0x1eebb, 1}, - {0x20000, 0x2a6df, 1}, - {0x2a700, 0x2b739, 1}, - {0x2b740, 0x2b81d, 1}, - {0x2b820, 0x2cea1, 1}, - {0x2ceb0, 0x2ebe0, 1}, - {0x2f800, 0x2fa1d, 1}, - {0x30000, 0x3134a, 1}, - {0x31350, 0x323af, 1}, - ], - LatinOffset: 6, + R16: [ + {0x0041, 0x005a, 1}, + {0x0061, 0x007a, 1}, + {0x00aa, 0x00b5, 11}, + {0x00ba, 0x00c0, 6}, + {0x00c1, 0x00d6, 1}, + {0x00d8, 0x00f6, 1}, + {0x00f8, 0x02c1, 1}, + {0x02c6, 0x02d1, 1}, + {0x02e0, 0x02e4, 1}, + {0x02ec, 0x02ee, 2}, + {0x0370, 0x0374, 1}, + {0x0376, 0x0377, 1}, + {0x037a, 0x037d, 1}, + {0x037f, 0x0386, 7}, + {0x0388, 0x038a, 1}, + {0x038c, 0x038e, 2}, + {0x038f, 0x03a1, 1}, + {0x03a3, 0x03f5, 1}, + {0x03f7, 0x0481, 1}, + {0x048a, 0x052f, 1}, + {0x0531, 0x0556, 1}, + {0x0559, 0x0560, 7}, + {0x0561, 0x0588, 1}, + {0x05d0, 0x05ea, 1}, + {0x05ef, 0x05f2, 1}, + {0x0620, 0x064a, 1}, + {0x066e, 0x066f, 1}, + {0x0671, 0x06d3, 1}, + {0x06d5, 0x06e5, 16}, + {0x06e6, 0x06ee, 8}, + {0x06ef, 0x06fa, 11}, + {0x06fb, 0x06fc, 1}, + {0x06ff, 0x0710, 17}, + {0x0712, 0x072f, 1}, + {0x074d, 0x07a5, 1}, + {0x07b1, 0x07ca, 25}, + {0x07cb, 0x07ea, 1}, + {0x07f4, 0x07f5, 1}, + {0x07fa, 0x0800, 6}, + {0x0801, 0x0815, 1}, + {0x081a, 0x0824, 10}, + {0x0828, 0x0840, 24}, + {0x0841, 0x0858, 1}, + {0x0860, 0x086a, 1}, + {0x0870, 0x0887, 1}, + {0x0889, 0x088e, 1}, + {0x08a0, 0x08c9, 1}, + {0x0904, 0x0939, 1}, + {0x093d, 0x0950, 19}, + {0x0958, 0x0961, 1}, + {0x0971, 0x0980, 1}, + {0x0985, 0x098c, 1}, + {0x098f, 0x0990, 1}, + {0x0993, 0x09a8, 1}, + {0x09aa, 0x09b0, 1}, + {0x09b2, 0x09b6, 4}, + {0x09b7, 0x09b9, 1}, + {0x09bd, 0x09ce, 17}, + {0x09dc, 0x09dd, 1}, + {0x09df, 0x09e1, 1}, + {0x09f0, 0x09f1, 1}, + {0x09fc, 0x0a05, 9}, + {0x0a06, 0x0a0a, 1}, + {0x0a0f, 0x0a10, 1}, + {0x0a13, 0x0a28, 1}, + {0x0a2a, 0x0a30, 1}, + {0x0a32, 0x0a33, 1}, + {0x0a35, 0x0a36, 1}, + {0x0a38, 0x0a39, 1}, + {0x0a59, 0x0a5c, 1}, + {0x0a5e, 0x0a72, 20}, + {0x0a73, 0x0a74, 1}, + {0x0a85, 0x0a8d, 1}, + {0x0a8f, 0x0a91, 1}, + {0x0a93, 0x0aa8, 1}, + {0x0aaa, 0x0ab0, 1}, + {0x0ab2, 0x0ab3, 1}, + {0x0ab5, 0x0ab9, 1}, + {0x0abd, 0x0ad0, 19}, + {0x0ae0, 0x0ae1, 1}, + {0x0af9, 0x0b05, 12}, + {0x0b06, 0x0b0c, 1}, + {0x0b0f, 0x0b10, 1}, + {0x0b13, 0x0b28, 1}, + {0x0b2a, 0x0b30, 1}, + {0x0b32, 0x0b33, 1}, + {0x0b35, 0x0b39, 1}, + {0x0b3d, 0x0b5c, 31}, + {0x0b5d, 0x0b5f, 2}, + {0x0b60, 0x0b61, 1}, + {0x0b71, 0x0b83, 18}, + {0x0b85, 0x0b8a, 1}, + {0x0b8e, 0x0b90, 1}, + {0x0b92, 0x0b95, 1}, + {0x0b99, 0x0b9a, 1}, + {0x0b9c, 0x0b9e, 2}, + {0x0b9f, 0x0ba3, 4}, + {0x0ba4, 0x0ba8, 4}, + {0x0ba9, 0x0baa, 1}, + {0x0bae, 0x0bb9, 1}, + {0x0bd0, 0x0c05, 53}, + {0x0c06, 0x0c0c, 1}, + {0x0c0e, 0x0c10, 1}, + {0x0c12, 0x0c28, 1}, + {0x0c2a, 0x0c39, 1}, + {0x0c3d, 0x0c58, 27}, + {0x0c59, 0x0c5a, 1}, + {0x0c5d, 0x0c60, 3}, + {0x0c61, 0x0c80, 31}, + {0x0c85, 0x0c8c, 1}, + {0x0c8e, 0x0c90, 1}, + {0x0c92, 0x0ca8, 1}, + {0x0caa, 0x0cb3, 1}, + {0x0cb5, 0x0cb9, 1}, + {0x0cbd, 0x0cdd, 32}, + {0x0cde, 0x0ce0, 2}, + {0x0ce1, 0x0cf1, 16}, + {0x0cf2, 0x0d04, 18}, + {0x0d05, 0x0d0c, 1}, + {0x0d0e, 0x0d10, 1}, + {0x0d12, 0x0d3a, 1}, + {0x0d3d, 0x0d4e, 17}, + {0x0d54, 0x0d56, 1}, + {0x0d5f, 0x0d61, 1}, + {0x0d7a, 0x0d7f, 1}, + {0x0d85, 0x0d96, 1}, + {0x0d9a, 0x0db1, 1}, + {0x0db3, 0x0dbb, 1}, + {0x0dbd, 0x0dc0, 3}, + {0x0dc1, 0x0dc6, 1}, + {0x0e01, 0x0e30, 1}, + {0x0e32, 0x0e33, 1}, + {0x0e40, 0x0e46, 1}, + {0x0e81, 0x0e82, 1}, + {0x0e84, 0x0e86, 2}, + {0x0e87, 0x0e8a, 1}, + {0x0e8c, 0x0ea3, 1}, + {0x0ea5, 0x0ea7, 2}, + {0x0ea8, 0x0eb0, 1}, + {0x0eb2, 0x0eb3, 1}, + {0x0ebd, 0x0ec0, 3}, + {0x0ec1, 0x0ec4, 1}, + {0x0ec6, 0x0edc, 22}, + {0x0edd, 0x0edf, 1}, + {0x0f00, 0x0f40, 64}, + {0x0f41, 0x0f47, 1}, + {0x0f49, 0x0f6c, 1}, + {0x0f88, 0x0f8c, 1}, + {0x1000, 0x102a, 1}, + {0x103f, 0x1050, 17}, + {0x1051, 0x1055, 1}, + {0x105a, 0x105d, 1}, + {0x1061, 0x1065, 4}, + {0x1066, 0x106e, 8}, + {0x106f, 0x1070, 1}, + {0x1075, 0x1081, 1}, + {0x108e, 0x10a0, 18}, + {0x10a1, 0x10c5, 1}, + {0x10c7, 0x10cd, 6}, + {0x10d0, 0x10fa, 1}, + {0x10fc, 0x1248, 1}, + {0x124a, 0x124d, 1}, + {0x1250, 0x1256, 1}, + {0x1258, 0x125a, 2}, + {0x125b, 0x125d, 1}, + {0x1260, 0x1288, 1}, + {0x128a, 0x128d, 1}, + {0x1290, 0x12b0, 1}, + {0x12b2, 0x12b5, 1}, + {0x12b8, 0x12be, 1}, + {0x12c0, 0x12c2, 2}, + {0x12c3, 0x12c5, 1}, + {0x12c8, 0x12d6, 1}, + {0x12d8, 0x1310, 1}, + {0x1312, 0x1315, 1}, + {0x1318, 0x135a, 1}, + {0x1380, 0x138f, 1}, + {0x13a0, 0x13f5, 1}, + {0x13f8, 0x13fd, 1}, + {0x1401, 0x166c, 1}, + {0x166f, 0x167f, 1}, + {0x1681, 0x169a, 1}, + {0x16a0, 0x16ea, 1}, + {0x16f1, 0x16f8, 1}, + {0x1700, 0x1711, 1}, + {0x171f, 0x1731, 1}, + {0x1740, 0x1751, 1}, + {0x1760, 0x176c, 1}, + {0x176e, 0x1770, 1}, + {0x1780, 0x17b3, 1}, + {0x17d7, 0x17dc, 5}, + {0x1820, 0x1878, 1}, + {0x1880, 0x1884, 1}, + {0x1887, 0x18a8, 1}, + {0x18aa, 0x18b0, 6}, + {0x18b1, 0x18f5, 1}, + {0x1900, 0x191e, 1}, + {0x1950, 0x196d, 1}, + {0x1970, 0x1974, 1}, + {0x1980, 0x19ab, 1}, + {0x19b0, 0x19c9, 1}, + {0x1a00, 0x1a16, 1}, + {0x1a20, 0x1a54, 1}, + {0x1aa7, 0x1b05, 94}, + {0x1b06, 0x1b33, 1}, + {0x1b45, 0x1b4c, 1}, + {0x1b83, 0x1ba0, 1}, + {0x1bae, 0x1baf, 1}, + {0x1bba, 0x1be5, 1}, + {0x1c00, 0x1c23, 1}, + {0x1c4d, 0x1c4f, 1}, + {0x1c5a, 0x1c7d, 1}, + {0x1c80, 0x1c88, 1}, + {0x1c90, 0x1cba, 1}, + {0x1cbd, 0x1cbf, 1}, + {0x1ce9, 0x1cec, 1}, + {0x1cee, 0x1cf3, 1}, + {0x1cf5, 0x1cf6, 1}, + {0x1cfa, 0x1d00, 6}, + {0x1d01, 0x1dbf, 1}, + {0x1e00, 0x1f15, 1}, + {0x1f18, 0x1f1d, 1}, + {0x1f20, 0x1f45, 1}, + {0x1f48, 0x1f4d, 1}, + {0x1f50, 0x1f57, 1}, + {0x1f59, 0x1f5f, 2}, + {0x1f60, 0x1f7d, 1}, + {0x1f80, 0x1fb4, 1}, + {0x1fb6, 0x1fbc, 1}, + {0x1fbe, 0x1fc2, 4}, + {0x1fc3, 0x1fc4, 1}, + {0x1fc6, 0x1fcc, 1}, + {0x1fd0, 0x1fd3, 1}, + {0x1fd6, 0x1fdb, 1}, + {0x1fe0, 0x1fec, 1}, + {0x1ff2, 0x1ff4, 1}, + {0x1ff6, 0x1ffc, 1}, + {0x2071, 0x207f, 14}, + {0x2090, 0x209c, 1}, + {0x2102, 0x2107, 5}, + {0x210a, 0x2113, 1}, + {0x2115, 0x2119, 4}, + {0x211a, 0x211d, 1}, + {0x2124, 0x212a, 2}, + {0x212b, 0x212d, 1}, + {0x212f, 0x2139, 1}, + {0x213c, 0x213f, 1}, + {0x2145, 0x2149, 1}, + {0x214e, 0x2183, 53}, + {0x2184, 0x2c00, 2684}, + {0x2c01, 0x2ce4, 1}, + {0x2ceb, 0x2cee, 1}, + {0x2cf2, 0x2cf3, 1}, + {0x2d00, 0x2d25, 1}, + {0x2d27, 0x2d2d, 6}, + {0x2d30, 0x2d67, 1}, + {0x2d6f, 0x2d80, 17}, + {0x2d81, 0x2d96, 1}, + {0x2da0, 0x2da6, 1}, + {0x2da8, 0x2dae, 1}, + {0x2db0, 0x2db6, 1}, + {0x2db8, 0x2dbe, 1}, + {0x2dc0, 0x2dc6, 1}, + {0x2dc8, 0x2dce, 1}, + {0x2dd0, 0x2dd6, 1}, + {0x2dd8, 0x2dde, 1}, + {0x2e2f, 0x3005, 470}, + {0x3006, 0x3031, 43}, + {0x3032, 0x3035, 1}, + {0x303b, 0x303c, 1}, + {0x3041, 0x3096, 1}, + {0x309d, 0x309f, 1}, + {0x30a1, 0x30fa, 1}, + {0x30fc, 0x30ff, 1}, + {0x3105, 0x312f, 1}, + {0x3131, 0x318e, 1}, + {0x31a0, 0x31bf, 1}, + {0x31f0, 0x31ff, 1}, + {0x3400, 0x4dbf, 1}, + {0x4e00, 0xa48c, 1}, + {0xa4d0, 0xa4fd, 1}, + {0xa500, 0xa60c, 1}, + {0xa610, 0xa61f, 1}, + {0xa62a, 0xa62b, 1}, + {0xa640, 0xa66e, 1}, + {0xa67f, 0xa69d, 1}, + {0xa6a0, 0xa6e5, 1}, + {0xa717, 0xa71f, 1}, + {0xa722, 0xa788, 1}, + {0xa78b, 0xa7ca, 1}, + {0xa7d0, 0xa7d1, 1}, + {0xa7d3, 0xa7d5, 2}, + {0xa7d6, 0xa7d9, 1}, + {0xa7f2, 0xa801, 1}, + {0xa803, 0xa805, 1}, + {0xa807, 0xa80a, 1}, + {0xa80c, 0xa822, 1}, + {0xa840, 0xa873, 1}, + {0xa882, 0xa8b3, 1}, + {0xa8f2, 0xa8f7, 1}, + {0xa8fb, 0xa8fd, 2}, + {0xa8fe, 0xa90a, 12}, + {0xa90b, 0xa925, 1}, + {0xa930, 0xa946, 1}, + {0xa960, 0xa97c, 1}, + {0xa984, 0xa9b2, 1}, + {0xa9cf, 0xa9e0, 17}, + {0xa9e1, 0xa9e4, 1}, + {0xa9e6, 0xa9ef, 1}, + {0xa9fa, 0xa9fe, 1}, + {0xaa00, 0xaa28, 1}, + {0xaa40, 0xaa42, 1}, + {0xaa44, 0xaa4b, 1}, + {0xaa60, 0xaa76, 1}, + {0xaa7a, 0xaa7e, 4}, + {0xaa7f, 0xaaaf, 1}, + {0xaab1, 0xaab5, 4}, + {0xaab6, 0xaab9, 3}, + {0xaaba, 0xaabd, 1}, + {0xaac0, 0xaac2, 2}, + {0xaadb, 0xaadd, 1}, + {0xaae0, 0xaaea, 1}, + {0xaaf2, 0xaaf4, 1}, + {0xab01, 0xab06, 1}, + {0xab09, 0xab0e, 1}, + {0xab11, 0xab16, 1}, + {0xab20, 0xab26, 1}, + {0xab28, 0xab2e, 1}, + {0xab30, 0xab5a, 1}, + {0xab5c, 0xab69, 1}, + {0xab70, 0xabe2, 1}, + {0xac00, 0xd7a3, 1}, + {0xd7b0, 0xd7c6, 1}, + {0xd7cb, 0xd7fb, 1}, + {0xf900, 0xfa6d, 1}, + {0xfa70, 0xfad9, 1}, + {0xfb00, 0xfb06, 1}, + {0xfb13, 0xfb17, 1}, + {0xfb1d, 0xfb1f, 2}, + {0xfb20, 0xfb28, 1}, + {0xfb2a, 0xfb36, 1}, + {0xfb38, 0xfb3c, 1}, + {0xfb3e, 0xfb40, 2}, + {0xfb41, 0xfb43, 2}, + {0xfb44, 0xfb46, 2}, + {0xfb47, 0xfbb1, 1}, + {0xfbd3, 0xfd3d, 1}, + {0xfd50, 0xfd8f, 1}, + {0xfd92, 0xfdc7, 1}, + {0xfdf0, 0xfdfb, 1}, + {0xfe70, 0xfe74, 1}, + {0xfe76, 0xfefc, 1}, + {0xff21, 0xff3a, 1}, + {0xff41, 0xff5a, 1}, + {0xff66, 0xffbe, 1}, + {0xffc2, 0xffc7, 1}, + {0xffca, 0xffcf, 1}, + {0xffd2, 0xffd7, 1}, + {0xffda, 0xffdc, 1}, + ], + R32: [ + {0x10000, 0x1000b, 1}, + {0x1000d, 0x10026, 1}, + {0x10028, 0x1003a, 1}, + {0x1003c, 0x1003d, 1}, + {0x1003f, 0x1004d, 1}, + {0x10050, 0x1005d, 1}, + {0x10080, 0x100fa, 1}, + {0x10280, 0x1029c, 1}, + {0x102a0, 0x102d0, 1}, + {0x10300, 0x1031f, 1}, + {0x1032d, 0x10340, 1}, + {0x10342, 0x10349, 1}, + {0x10350, 0x10375, 1}, + {0x10380, 0x1039d, 1}, + {0x103a0, 0x103c3, 1}, + {0x103c8, 0x103cf, 1}, + {0x10400, 0x1049d, 1}, + {0x104b0, 0x104d3, 1}, + {0x104d8, 0x104fb, 1}, + {0x10500, 0x10527, 1}, + {0x10530, 0x10563, 1}, + {0x10570, 0x1057a, 1}, + {0x1057c, 0x1058a, 1}, + {0x1058c, 0x10592, 1}, + {0x10594, 0x10595, 1}, + {0x10597, 0x105a1, 1}, + {0x105a3, 0x105b1, 1}, + {0x105b3, 0x105b9, 1}, + {0x105bb, 0x105bc, 1}, + {0x10600, 0x10736, 1}, + {0x10740, 0x10755, 1}, + {0x10760, 0x10767, 1}, + {0x10780, 0x10785, 1}, + {0x10787, 0x107b0, 1}, + {0x107b2, 0x107ba, 1}, + {0x10800, 0x10805, 1}, + {0x10808, 0x1080a, 2}, + {0x1080b, 0x10835, 1}, + {0x10837, 0x10838, 1}, + {0x1083c, 0x1083f, 3}, + {0x10840, 0x10855, 1}, + {0x10860, 0x10876, 1}, + {0x10880, 0x1089e, 1}, + {0x108e0, 0x108f2, 1}, + {0x108f4, 0x108f5, 1}, + {0x10900, 0x10915, 1}, + {0x10920, 0x10939, 1}, + {0x10980, 0x109b7, 1}, + {0x109be, 0x109bf, 1}, + {0x10a00, 0x10a10, 16}, + {0x10a11, 0x10a13, 1}, + {0x10a15, 0x10a17, 1}, + {0x10a19, 0x10a35, 1}, + {0x10a60, 0x10a7c, 1}, + {0x10a80, 0x10a9c, 1}, + {0x10ac0, 0x10ac7, 1}, + {0x10ac9, 0x10ae4, 1}, + {0x10b00, 0x10b35, 1}, + {0x10b40, 0x10b55, 1}, + {0x10b60, 0x10b72, 1}, + {0x10b80, 0x10b91, 1}, + {0x10c00, 0x10c48, 1}, + {0x10c80, 0x10cb2, 1}, + {0x10cc0, 0x10cf2, 1}, + {0x10d00, 0x10d23, 1}, + {0x10e80, 0x10ea9, 1}, + {0x10eb0, 0x10eb1, 1}, + {0x10f00, 0x10f1c, 1}, + {0x10f27, 0x10f30, 9}, + {0x10f31, 0x10f45, 1}, + {0x10f70, 0x10f81, 1}, + {0x10fb0, 0x10fc4, 1}, + {0x10fe0, 0x10ff6, 1}, + {0x11003, 0x11037, 1}, + {0x11071, 0x11072, 1}, + {0x11075, 0x11083, 14}, + {0x11084, 0x110af, 1}, + {0x110d0, 0x110e8, 1}, + {0x11103, 0x11126, 1}, + {0x11144, 0x11147, 3}, + {0x11150, 0x11172, 1}, + {0x11176, 0x11183, 13}, + {0x11184, 0x111b2, 1}, + {0x111c1, 0x111c4, 1}, + {0x111da, 0x111dc, 2}, + {0x11200, 0x11211, 1}, + {0x11213, 0x1122b, 1}, + {0x1123f, 0x11240, 1}, + {0x11280, 0x11286, 1}, + {0x11288, 0x1128a, 2}, + {0x1128b, 0x1128d, 1}, + {0x1128f, 0x1129d, 1}, + {0x1129f, 0x112a8, 1}, + {0x112b0, 0x112de, 1}, + {0x11305, 0x1130c, 1}, + {0x1130f, 0x11310, 1}, + {0x11313, 0x11328, 1}, + {0x1132a, 0x11330, 1}, + {0x11332, 0x11333, 1}, + {0x11335, 0x11339, 1}, + {0x1133d, 0x11350, 19}, + {0x1135d, 0x11361, 1}, + {0x11400, 0x11434, 1}, + {0x11447, 0x1144a, 1}, + {0x1145f, 0x11461, 1}, + {0x11480, 0x114af, 1}, + {0x114c4, 0x114c5, 1}, + {0x114c7, 0x11580, 185}, + {0x11581, 0x115ae, 1}, + {0x115d8, 0x115db, 1}, + {0x11600, 0x1162f, 1}, + {0x11644, 0x11680, 60}, + {0x11681, 0x116aa, 1}, + {0x116b8, 0x11700, 72}, + {0x11701, 0x1171a, 1}, + {0x11740, 0x11746, 1}, + {0x11800, 0x1182b, 1}, + {0x118a0, 0x118df, 1}, + {0x118ff, 0x11906, 1}, + {0x11909, 0x1190c, 3}, + {0x1190d, 0x11913, 1}, + {0x11915, 0x11916, 1}, + {0x11918, 0x1192f, 1}, + {0x1193f, 0x11941, 2}, + {0x119a0, 0x119a7, 1}, + {0x119aa, 0x119d0, 1}, + {0x119e1, 0x119e3, 2}, + {0x11a00, 0x11a0b, 11}, + {0x11a0c, 0x11a32, 1}, + {0x11a3a, 0x11a50, 22}, + {0x11a5c, 0x11a89, 1}, + {0x11a9d, 0x11ab0, 19}, + {0x11ab1, 0x11af8, 1}, + {0x11c00, 0x11c08, 1}, + {0x11c0a, 0x11c2e, 1}, + {0x11c40, 0x11c72, 50}, + {0x11c73, 0x11c8f, 1}, + {0x11d00, 0x11d06, 1}, + {0x11d08, 0x11d09, 1}, + {0x11d0b, 0x11d30, 1}, + {0x11d46, 0x11d60, 26}, + {0x11d61, 0x11d65, 1}, + {0x11d67, 0x11d68, 1}, + {0x11d6a, 0x11d89, 1}, + {0x11d98, 0x11ee0, 328}, + {0x11ee1, 0x11ef2, 1}, + {0x11f02, 0x11f04, 2}, + {0x11f05, 0x11f10, 1}, + {0x11f12, 0x11f33, 1}, + {0x11fb0, 0x12000, 80}, + {0x12001, 0x12399, 1}, + {0x12480, 0x12543, 1}, + {0x12f90, 0x12ff0, 1}, + {0x13000, 0x1342f, 1}, + {0x13441, 0x13446, 1}, + {0x14400, 0x14646, 1}, + {0x16800, 0x16a38, 1}, + {0x16a40, 0x16a5e, 1}, + {0x16a70, 0x16abe, 1}, + {0x16ad0, 0x16aed, 1}, + {0x16b00, 0x16b2f, 1}, + {0x16b40, 0x16b43, 1}, + {0x16b63, 0x16b77, 1}, + {0x16b7d, 0x16b8f, 1}, + {0x16e40, 0x16e7f, 1}, + {0x16f00, 0x16f4a, 1}, + {0x16f50, 0x16f93, 67}, + {0x16f94, 0x16f9f, 1}, + {0x16fe0, 0x16fe1, 1}, + {0x16fe3, 0x17000, 29}, + {0x17001, 0x187f7, 1}, + {0x18800, 0x18cd5, 1}, + {0x18d00, 0x18d08, 1}, + {0x1aff0, 0x1aff3, 1}, + {0x1aff5, 0x1affb, 1}, + {0x1affd, 0x1affe, 1}, + {0x1b000, 0x1b122, 1}, + {0x1b132, 0x1b150, 30}, + {0x1b151, 0x1b152, 1}, + {0x1b155, 0x1b164, 15}, + {0x1b165, 0x1b167, 1}, + {0x1b170, 0x1b2fb, 1}, + {0x1bc00, 0x1bc6a, 1}, + {0x1bc70, 0x1bc7c, 1}, + {0x1bc80, 0x1bc88, 1}, + {0x1bc90, 0x1bc99, 1}, + {0x1d400, 0x1d454, 1}, + {0x1d456, 0x1d49c, 1}, + {0x1d49e, 0x1d49f, 1}, + {0x1d4a2, 0x1d4a5, 3}, + {0x1d4a6, 0x1d4a9, 3}, + {0x1d4aa, 0x1d4ac, 1}, + {0x1d4ae, 0x1d4b9, 1}, + {0x1d4bb, 0x1d4bd, 2}, + {0x1d4be, 0x1d4c3, 1}, + {0x1d4c5, 0x1d505, 1}, + {0x1d507, 0x1d50a, 1}, + {0x1d50d, 0x1d514, 1}, + {0x1d516, 0x1d51c, 1}, + {0x1d51e, 0x1d539, 1}, + {0x1d53b, 0x1d53e, 1}, + {0x1d540, 0x1d544, 1}, + {0x1d546, 0x1d54a, 4}, + {0x1d54b, 0x1d550, 1}, + {0x1d552, 0x1d6a5, 1}, + {0x1d6a8, 0x1d6c0, 1}, + {0x1d6c2, 0x1d6da, 1}, + {0x1d6dc, 0x1d6fa, 1}, + {0x1d6fc, 0x1d714, 1}, + {0x1d716, 0x1d734, 1}, + {0x1d736, 0x1d74e, 1}, + {0x1d750, 0x1d76e, 1}, + {0x1d770, 0x1d788, 1}, + {0x1d78a, 0x1d7a8, 1}, + {0x1d7aa, 0x1d7c2, 1}, + {0x1d7c4, 0x1d7cb, 1}, + {0x1df00, 0x1df1e, 1}, + {0x1df25, 0x1df2a, 1}, + {0x1e030, 0x1e06d, 1}, + {0x1e100, 0x1e12c, 1}, + {0x1e137, 0x1e13d, 1}, + {0x1e14e, 0x1e290, 322}, + {0x1e291, 0x1e2ad, 1}, + {0x1e2c0, 0x1e2eb, 1}, + {0x1e4d0, 0x1e4eb, 1}, + {0x1e7e0, 0x1e7e6, 1}, + {0x1e7e8, 0x1e7eb, 1}, + {0x1e7ed, 0x1e7ee, 1}, + {0x1e7f0, 0x1e7fe, 1}, + {0x1e800, 0x1e8c4, 1}, + {0x1e900, 0x1e943, 1}, + {0x1e94b, 0x1ee00, 1205}, + {0x1ee01, 0x1ee03, 1}, + {0x1ee05, 0x1ee1f, 1}, + {0x1ee21, 0x1ee22, 1}, + {0x1ee24, 0x1ee27, 3}, + {0x1ee29, 0x1ee32, 1}, + {0x1ee34, 0x1ee37, 1}, + {0x1ee39, 0x1ee3b, 2}, + {0x1ee42, 0x1ee47, 5}, + {0x1ee49, 0x1ee4d, 2}, + {0x1ee4e, 0x1ee4f, 1}, + {0x1ee51, 0x1ee52, 1}, + {0x1ee54, 0x1ee57, 3}, + {0x1ee59, 0x1ee61, 2}, + {0x1ee62, 0x1ee64, 2}, + {0x1ee67, 0x1ee6a, 1}, + {0x1ee6c, 0x1ee72, 1}, + {0x1ee74, 0x1ee77, 1}, + {0x1ee79, 0x1ee7c, 1}, + {0x1ee7e, 0x1ee80, 2}, + {0x1ee81, 0x1ee89, 1}, + {0x1ee8b, 0x1ee9b, 1}, + {0x1eea1, 0x1eea3, 1}, + {0x1eea5, 0x1eea9, 1}, + {0x1eeab, 0x1eebb, 1}, + {0x20000, 0x2a6df, 1}, + {0x2a700, 0x2b739, 1}, + {0x2b740, 0x2b81d, 1}, + {0x2b820, 0x2cea1, 1}, + {0x2ceb0, 0x2ebe0, 1}, + {0x2f800, 0x2fa1d, 1}, + {0x30000, 0x3134a, 1}, + {0x31350, 0x323af, 1}, + ], + LatinOffset: 6, } static _LL = &RangeTable{ - R16: [ - {0x0061, 0x007a, 1}, - {0x00b5, 0x00df, 42}, - {0x00e0, 0x00f6, 1}, - {0x00f8, 0x00ff, 1}, - {0x0101, 0x0137, 2}, - {0x0138, 0x0148, 2}, - {0x0149, 0x0177, 2}, - {0x017a, 0x017e, 2}, - {0x017f, 0x0180, 1}, - {0x0183, 0x0185, 2}, - {0x0188, 0x018c, 4}, - {0x018d, 0x0192, 5}, - {0x0195, 0x0199, 4}, - {0x019a, 0x019b, 1}, - {0x019e, 0x01a1, 3}, - {0x01a3, 0x01a5, 2}, - {0x01a8, 0x01aa, 2}, - {0x01ab, 0x01ad, 2}, - {0x01b0, 0x01b4, 4}, - {0x01b6, 0x01b9, 3}, - {0x01ba, 0x01bd, 3}, - {0x01be, 0x01bf, 1}, - {0x01c6, 0x01cc, 3}, - {0x01ce, 0x01dc, 2}, - {0x01dd, 0x01ef, 2}, - {0x01f0, 0x01f3, 3}, - {0x01f5, 0x01f9, 4}, - {0x01fb, 0x0233, 2}, - {0x0234, 0x0239, 1}, - {0x023c, 0x023f, 3}, - {0x0240, 0x0242, 2}, - {0x0247, 0x024f, 2}, - {0x0250, 0x0293, 1}, - {0x0295, 0x02af, 1}, - {0x0371, 0x0373, 2}, - {0x0377, 0x037b, 4}, - {0x037c, 0x037d, 1}, - {0x0390, 0x03ac, 28}, - {0x03ad, 0x03ce, 1}, - {0x03d0, 0x03d1, 1}, - {0x03d5, 0x03d7, 1}, - {0x03d9, 0x03ef, 2}, - {0x03f0, 0x03f3, 1}, - {0x03f5, 0x03fb, 3}, - {0x03fc, 0x0430, 52}, - {0x0431, 0x045f, 1}, - {0x0461, 0x0481, 2}, - {0x048b, 0x04bf, 2}, - {0x04c2, 0x04ce, 2}, - {0x04cf, 0x052f, 2}, - {0x0560, 0x0588, 1}, - {0x10d0, 0x10fa, 1}, - {0x10fd, 0x10ff, 1}, - {0x13f8, 0x13fd, 1}, - {0x1c80, 0x1c88, 1}, - {0x1d00, 0x1d2b, 1}, - {0x1d6b, 0x1d77, 1}, - {0x1d79, 0x1d9a, 1}, - {0x1e01, 0x1e95, 2}, - {0x1e96, 0x1e9d, 1}, - {0x1e9f, 0x1eff, 2}, - {0x1f00, 0x1f07, 1}, - {0x1f10, 0x1f15, 1}, - {0x1f20, 0x1f27, 1}, - {0x1f30, 0x1f37, 1}, - {0x1f40, 0x1f45, 1}, - {0x1f50, 0x1f57, 1}, - {0x1f60, 0x1f67, 1}, - {0x1f70, 0x1f7d, 1}, - {0x1f80, 0x1f87, 1}, - {0x1f90, 0x1f97, 1}, - {0x1fa0, 0x1fa7, 1}, - {0x1fb0, 0x1fb4, 1}, - {0x1fb6, 0x1fb7, 1}, - {0x1fbe, 0x1fc2, 4}, - {0x1fc3, 0x1fc4, 1}, - {0x1fc6, 0x1fc7, 1}, - {0x1fd0, 0x1fd3, 1}, - {0x1fd6, 0x1fd7, 1}, - {0x1fe0, 0x1fe7, 1}, - {0x1ff2, 0x1ff4, 1}, - {0x1ff6, 0x1ff7, 1}, - {0x210a, 0x210e, 4}, - {0x210f, 0x2113, 4}, - {0x212f, 0x2139, 5}, - {0x213c, 0x213d, 1}, - {0x2146, 0x2149, 1}, - {0x214e, 0x2184, 54}, - {0x2c30, 0x2c5f, 1}, - {0x2c61, 0x2c65, 4}, - {0x2c66, 0x2c6c, 2}, - {0x2c71, 0x2c73, 2}, - {0x2c74, 0x2c76, 2}, - {0x2c77, 0x2c7b, 1}, - {0x2c81, 0x2ce3, 2}, - {0x2ce4, 0x2cec, 8}, - {0x2cee, 0x2cf3, 5}, - {0x2d00, 0x2d25, 1}, - {0x2d27, 0x2d2d, 6}, - {0xa641, 0xa66d, 2}, - {0xa681, 0xa69b, 2}, - {0xa723, 0xa72f, 2}, - {0xa730, 0xa731, 1}, - {0xa733, 0xa771, 2}, - {0xa772, 0xa778, 1}, - {0xa77a, 0xa77c, 2}, - {0xa77f, 0xa787, 2}, - {0xa78c, 0xa78e, 2}, - {0xa791, 0xa793, 2}, - {0xa794, 0xa795, 1}, - {0xa797, 0xa7a9, 2}, - {0xa7af, 0xa7b5, 6}, - {0xa7b7, 0xa7c3, 2}, - {0xa7c8, 0xa7ca, 2}, - {0xa7d1, 0xa7d9, 2}, - {0xa7f6, 0xa7fa, 4}, - {0xab30, 0xab5a, 1}, - {0xab60, 0xab68, 1}, - {0xab70, 0xabbf, 1}, - {0xfb00, 0xfb06, 1}, - {0xfb13, 0xfb17, 1}, - {0xff41, 0xff5a, 1}, - ], - R32: [ - {0x10428, 0x1044f, 1}, - {0x104d8, 0x104fb, 1}, - {0x10597, 0x105a1, 1}, - {0x105a3, 0x105b1, 1}, - {0x105b3, 0x105b9, 1}, - {0x105bb, 0x105bc, 1}, - {0x10cc0, 0x10cf2, 1}, - {0x118c0, 0x118df, 1}, - {0x16e60, 0x16e7f, 1}, - {0x1d41a, 0x1d433, 1}, - {0x1d44e, 0x1d454, 1}, - {0x1d456, 0x1d467, 1}, - {0x1d482, 0x1d49b, 1}, - {0x1d4b6, 0x1d4b9, 1}, - {0x1d4bb, 0x1d4bd, 2}, - {0x1d4be, 0x1d4c3, 1}, - {0x1d4c5, 0x1d4cf, 1}, - {0x1d4ea, 0x1d503, 1}, - {0x1d51e, 0x1d537, 1}, - {0x1d552, 0x1d56b, 1}, - {0x1d586, 0x1d59f, 1}, - {0x1d5ba, 0x1d5d3, 1}, - {0x1d5ee, 0x1d607, 1}, - {0x1d622, 0x1d63b, 1}, - {0x1d656, 0x1d66f, 1}, - {0x1d68a, 0x1d6a5, 1}, - {0x1d6c2, 0x1d6da, 1}, - {0x1d6dc, 0x1d6e1, 1}, - {0x1d6fc, 0x1d714, 1}, - {0x1d716, 0x1d71b, 1}, - {0x1d736, 0x1d74e, 1}, - {0x1d750, 0x1d755, 1}, - {0x1d770, 0x1d788, 1}, - {0x1d78a, 0x1d78f, 1}, - {0x1d7aa, 0x1d7c2, 1}, - {0x1d7c4, 0x1d7c9, 1}, - {0x1d7cb, 0x1df00, 1845}, - {0x1df01, 0x1df09, 1}, - {0x1df0b, 0x1df1e, 1}, - {0x1df25, 0x1df2a, 1}, - {0x1e922, 0x1e943, 1}, - ], - LatinOffset: 4, + R16: [ + {0x0061, 0x007a, 1}, + {0x00b5, 0x00df, 42}, + {0x00e0, 0x00f6, 1}, + {0x00f8, 0x00ff, 1}, + {0x0101, 0x0137, 2}, + {0x0138, 0x0148, 2}, + {0x0149, 0x0177, 2}, + {0x017a, 0x017e, 2}, + {0x017f, 0x0180, 1}, + {0x0183, 0x0185, 2}, + {0x0188, 0x018c, 4}, + {0x018d, 0x0192, 5}, + {0x0195, 0x0199, 4}, + {0x019a, 0x019b, 1}, + {0x019e, 0x01a1, 3}, + {0x01a3, 0x01a5, 2}, + {0x01a8, 0x01aa, 2}, + {0x01ab, 0x01ad, 2}, + {0x01b0, 0x01b4, 4}, + {0x01b6, 0x01b9, 3}, + {0x01ba, 0x01bd, 3}, + {0x01be, 0x01bf, 1}, + {0x01c6, 0x01cc, 3}, + {0x01ce, 0x01dc, 2}, + {0x01dd, 0x01ef, 2}, + {0x01f0, 0x01f3, 3}, + {0x01f5, 0x01f9, 4}, + {0x01fb, 0x0233, 2}, + {0x0234, 0x0239, 1}, + {0x023c, 0x023f, 3}, + {0x0240, 0x0242, 2}, + {0x0247, 0x024f, 2}, + {0x0250, 0x0293, 1}, + {0x0295, 0x02af, 1}, + {0x0371, 0x0373, 2}, + {0x0377, 0x037b, 4}, + {0x037c, 0x037d, 1}, + {0x0390, 0x03ac, 28}, + {0x03ad, 0x03ce, 1}, + {0x03d0, 0x03d1, 1}, + {0x03d5, 0x03d7, 1}, + {0x03d9, 0x03ef, 2}, + {0x03f0, 0x03f3, 1}, + {0x03f5, 0x03fb, 3}, + {0x03fc, 0x0430, 52}, + {0x0431, 0x045f, 1}, + {0x0461, 0x0481, 2}, + {0x048b, 0x04bf, 2}, + {0x04c2, 0x04ce, 2}, + {0x04cf, 0x052f, 2}, + {0x0560, 0x0588, 1}, + {0x10d0, 0x10fa, 1}, + {0x10fd, 0x10ff, 1}, + {0x13f8, 0x13fd, 1}, + {0x1c80, 0x1c88, 1}, + {0x1d00, 0x1d2b, 1}, + {0x1d6b, 0x1d77, 1}, + {0x1d79, 0x1d9a, 1}, + {0x1e01, 0x1e95, 2}, + {0x1e96, 0x1e9d, 1}, + {0x1e9f, 0x1eff, 2}, + {0x1f00, 0x1f07, 1}, + {0x1f10, 0x1f15, 1}, + {0x1f20, 0x1f27, 1}, + {0x1f30, 0x1f37, 1}, + {0x1f40, 0x1f45, 1}, + {0x1f50, 0x1f57, 1}, + {0x1f60, 0x1f67, 1}, + {0x1f70, 0x1f7d, 1}, + {0x1f80, 0x1f87, 1}, + {0x1f90, 0x1f97, 1}, + {0x1fa0, 0x1fa7, 1}, + {0x1fb0, 0x1fb4, 1}, + {0x1fb6, 0x1fb7, 1}, + {0x1fbe, 0x1fc2, 4}, + {0x1fc3, 0x1fc4, 1}, + {0x1fc6, 0x1fc7, 1}, + {0x1fd0, 0x1fd3, 1}, + {0x1fd6, 0x1fd7, 1}, + {0x1fe0, 0x1fe7, 1}, + {0x1ff2, 0x1ff4, 1}, + {0x1ff6, 0x1ff7, 1}, + {0x210a, 0x210e, 4}, + {0x210f, 0x2113, 4}, + {0x212f, 0x2139, 5}, + {0x213c, 0x213d, 1}, + {0x2146, 0x2149, 1}, + {0x214e, 0x2184, 54}, + {0x2c30, 0x2c5f, 1}, + {0x2c61, 0x2c65, 4}, + {0x2c66, 0x2c6c, 2}, + {0x2c71, 0x2c73, 2}, + {0x2c74, 0x2c76, 2}, + {0x2c77, 0x2c7b, 1}, + {0x2c81, 0x2ce3, 2}, + {0x2ce4, 0x2cec, 8}, + {0x2cee, 0x2cf3, 5}, + {0x2d00, 0x2d25, 1}, + {0x2d27, 0x2d2d, 6}, + {0xa641, 0xa66d, 2}, + {0xa681, 0xa69b, 2}, + {0xa723, 0xa72f, 2}, + {0xa730, 0xa731, 1}, + {0xa733, 0xa771, 2}, + {0xa772, 0xa778, 1}, + {0xa77a, 0xa77c, 2}, + {0xa77f, 0xa787, 2}, + {0xa78c, 0xa78e, 2}, + {0xa791, 0xa793, 2}, + {0xa794, 0xa795, 1}, + {0xa797, 0xa7a9, 2}, + {0xa7af, 0xa7b5, 6}, + {0xa7b7, 0xa7c3, 2}, + {0xa7c8, 0xa7ca, 2}, + {0xa7d1, 0xa7d9, 2}, + {0xa7f6, 0xa7fa, 4}, + {0xab30, 0xab5a, 1}, + {0xab60, 0xab68, 1}, + {0xab70, 0xabbf, 1}, + {0xfb00, 0xfb06, 1}, + {0xfb13, 0xfb17, 1}, + {0xff41, 0xff5a, 1}, + ], + R32: [ + {0x10428, 0x1044f, 1}, + {0x104d8, 0x104fb, 1}, + {0x10597, 0x105a1, 1}, + {0x105a3, 0x105b1, 1}, + {0x105b3, 0x105b9, 1}, + {0x105bb, 0x105bc, 1}, + {0x10cc0, 0x10cf2, 1}, + {0x118c0, 0x118df, 1}, + {0x16e60, 0x16e7f, 1}, + {0x1d41a, 0x1d433, 1}, + {0x1d44e, 0x1d454, 1}, + {0x1d456, 0x1d467, 1}, + {0x1d482, 0x1d49b, 1}, + {0x1d4b6, 0x1d4b9, 1}, + {0x1d4bb, 0x1d4bd, 2}, + {0x1d4be, 0x1d4c3, 1}, + {0x1d4c5, 0x1d4cf, 1}, + {0x1d4ea, 0x1d503, 1}, + {0x1d51e, 0x1d537, 1}, + {0x1d552, 0x1d56b, 1}, + {0x1d586, 0x1d59f, 1}, + {0x1d5ba, 0x1d5d3, 1}, + {0x1d5ee, 0x1d607, 1}, + {0x1d622, 0x1d63b, 1}, + {0x1d656, 0x1d66f, 1}, + {0x1d68a, 0x1d6a5, 1}, + {0x1d6c2, 0x1d6da, 1}, + {0x1d6dc, 0x1d6e1, 1}, + {0x1d6fc, 0x1d714, 1}, + {0x1d716, 0x1d71b, 1}, + {0x1d736, 0x1d74e, 1}, + {0x1d750, 0x1d755, 1}, + {0x1d770, 0x1d788, 1}, + {0x1d78a, 0x1d78f, 1}, + {0x1d7aa, 0x1d7c2, 1}, + {0x1d7c4, 0x1d7c9, 1}, + {0x1d7cb, 0x1df00, 1845}, + {0x1df01, 0x1df09, 1}, + {0x1df0b, 0x1df1e, 1}, + {0x1df25, 0x1df2a, 1}, + {0x1e922, 0x1e943, 1}, + ], + LatinOffset: 4, } static _LM = &RangeTable{ - R16: [ - {0x02b0, 0x02c1, 1}, - {0x02c6, 0x02d1, 1}, - {0x02e0, 0x02e4, 1}, - {0x02ec, 0x02ee, 2}, - {0x0374, 0x037a, 6}, - {0x0559, 0x0640, 231}, - {0x06e5, 0x06e6, 1}, - {0x07f4, 0x07f5, 1}, - {0x07fa, 0x081a, 32}, - {0x0824, 0x0828, 4}, - {0x08c9, 0x0971, 168}, - {0x0e46, 0x0ec6, 128}, - {0x10fc, 0x17d7, 1755}, - {0x1843, 0x1aa7, 612}, - {0x1c78, 0x1c7d, 1}, - {0x1d2c, 0x1d6a, 1}, - {0x1d78, 0x1d9b, 35}, - {0x1d9c, 0x1dbf, 1}, - {0x2071, 0x207f, 14}, - {0x2090, 0x209c, 1}, - {0x2c7c, 0x2c7d, 1}, - {0x2d6f, 0x2e2f, 192}, - {0x3005, 0x3031, 44}, - {0x3032, 0x3035, 1}, - {0x303b, 0x309d, 98}, - {0x309e, 0x30fc, 94}, - {0x30fd, 0x30fe, 1}, - {0xa015, 0xa4f8, 1251}, - {0xa4f9, 0xa4fd, 1}, - {0xa60c, 0xa67f, 115}, - {0xa69c, 0xa69d, 1}, - {0xa717, 0xa71f, 1}, - {0xa770, 0xa788, 24}, - {0xa7f2, 0xa7f4, 1}, - {0xa7f8, 0xa7f9, 1}, - {0xa9cf, 0xa9e6, 23}, - {0xaa70, 0xaadd, 109}, - {0xaaf3, 0xaaf4, 1}, - {0xab5c, 0xab5f, 1}, - {0xab69, 0xff70, 21511}, - {0xff9e, 0xff9f, 1}, - ], - R32: [ - {0x10780, 0x10785, 1}, - {0x10787, 0x107b0, 1}, - {0x107b2, 0x107ba, 1}, - {0x16b40, 0x16b43, 1}, - {0x16f93, 0x16f9f, 1}, - {0x16fe0, 0x16fe1, 1}, - {0x16fe3, 0x1aff0, 16397}, - {0x1aff1, 0x1aff3, 1}, - {0x1aff5, 0x1affb, 1}, - {0x1affd, 0x1affe, 1}, - {0x1e030, 0x1e06d, 1}, - {0x1e137, 0x1e13d, 1}, - {0x1e4eb, 0x1e94b, 1120}, - ], + R16: [ + {0x02b0, 0x02c1, 1}, + {0x02c6, 0x02d1, 1}, + {0x02e0, 0x02e4, 1}, + {0x02ec, 0x02ee, 2}, + {0x0374, 0x037a, 6}, + {0x0559, 0x0640, 231}, + {0x06e5, 0x06e6, 1}, + {0x07f4, 0x07f5, 1}, + {0x07fa, 0x081a, 32}, + {0x0824, 0x0828, 4}, + {0x08c9, 0x0971, 168}, + {0x0e46, 0x0ec6, 128}, + {0x10fc, 0x17d7, 1755}, + {0x1843, 0x1aa7, 612}, + {0x1c78, 0x1c7d, 1}, + {0x1d2c, 0x1d6a, 1}, + {0x1d78, 0x1d9b, 35}, + {0x1d9c, 0x1dbf, 1}, + {0x2071, 0x207f, 14}, + {0x2090, 0x209c, 1}, + {0x2c7c, 0x2c7d, 1}, + {0x2d6f, 0x2e2f, 192}, + {0x3005, 0x3031, 44}, + {0x3032, 0x3035, 1}, + {0x303b, 0x309d, 98}, + {0x309e, 0x30fc, 94}, + {0x30fd, 0x30fe, 1}, + {0xa015, 0xa4f8, 1251}, + {0xa4f9, 0xa4fd, 1}, + {0xa60c, 0xa67f, 115}, + {0xa69c, 0xa69d, 1}, + {0xa717, 0xa71f, 1}, + {0xa770, 0xa788, 24}, + {0xa7f2, 0xa7f4, 1}, + {0xa7f8, 0xa7f9, 1}, + {0xa9cf, 0xa9e6, 23}, + {0xaa70, 0xaadd, 109}, + {0xaaf3, 0xaaf4, 1}, + {0xab5c, 0xab5f, 1}, + {0xab69, 0xff70, 21511}, + {0xff9e, 0xff9f, 1}, + ], + R32: [ + {0x10780, 0x10785, 1}, + {0x10787, 0x107b0, 1}, + {0x107b2, 0x107ba, 1}, + {0x16b40, 0x16b43, 1}, + {0x16f93, 0x16f9f, 1}, + {0x16fe0, 0x16fe1, 1}, + {0x16fe3, 0x1aff0, 16397}, + {0x1aff1, 0x1aff3, 1}, + {0x1aff5, 0x1affb, 1}, + {0x1affd, 0x1affe, 1}, + {0x1e030, 0x1e06d, 1}, + {0x1e137, 0x1e13d, 1}, + {0x1e4eb, 0x1e94b, 1120}, + ], } static _LO = &RangeTable{ - R16: [ - {0x00aa, 0x00ba, 16}, - {0x01bb, 0x01c0, 5}, - {0x01c1, 0x01c3, 1}, - {0x0294, 0x05d0, 828}, - {0x05d1, 0x05ea, 1}, - {0x05ef, 0x05f2, 1}, - {0x0620, 0x063f, 1}, - {0x0641, 0x064a, 1}, - {0x066e, 0x066f, 1}, - {0x0671, 0x06d3, 1}, - {0x06d5, 0x06ee, 25}, - {0x06ef, 0x06fa, 11}, - {0x06fb, 0x06fc, 1}, - {0x06ff, 0x0710, 17}, - {0x0712, 0x072f, 1}, - {0x074d, 0x07a5, 1}, - {0x07b1, 0x07ca, 25}, - {0x07cb, 0x07ea, 1}, - {0x0800, 0x0815, 1}, - {0x0840, 0x0858, 1}, - {0x0860, 0x086a, 1}, - {0x0870, 0x0887, 1}, - {0x0889, 0x088e, 1}, - {0x08a0, 0x08c8, 1}, - {0x0904, 0x0939, 1}, - {0x093d, 0x0950, 19}, - {0x0958, 0x0961, 1}, - {0x0972, 0x0980, 1}, - {0x0985, 0x098c, 1}, - {0x098f, 0x0990, 1}, - {0x0993, 0x09a8, 1}, - {0x09aa, 0x09b0, 1}, - {0x09b2, 0x09b6, 4}, - {0x09b7, 0x09b9, 1}, - {0x09bd, 0x09ce, 17}, - {0x09dc, 0x09dd, 1}, - {0x09df, 0x09e1, 1}, - {0x09f0, 0x09f1, 1}, - {0x09fc, 0x0a05, 9}, - {0x0a06, 0x0a0a, 1}, - {0x0a0f, 0x0a10, 1}, - {0x0a13, 0x0a28, 1}, - {0x0a2a, 0x0a30, 1}, - {0x0a32, 0x0a33, 1}, - {0x0a35, 0x0a36, 1}, - {0x0a38, 0x0a39, 1}, - {0x0a59, 0x0a5c, 1}, - {0x0a5e, 0x0a72, 20}, - {0x0a73, 0x0a74, 1}, - {0x0a85, 0x0a8d, 1}, - {0x0a8f, 0x0a91, 1}, - {0x0a93, 0x0aa8, 1}, - {0x0aaa, 0x0ab0, 1}, - {0x0ab2, 0x0ab3, 1}, - {0x0ab5, 0x0ab9, 1}, - {0x0abd, 0x0ad0, 19}, - {0x0ae0, 0x0ae1, 1}, - {0x0af9, 0x0b05, 12}, - {0x0b06, 0x0b0c, 1}, - {0x0b0f, 0x0b10, 1}, - {0x0b13, 0x0b28, 1}, - {0x0b2a, 0x0b30, 1}, - {0x0b32, 0x0b33, 1}, - {0x0b35, 0x0b39, 1}, - {0x0b3d, 0x0b5c, 31}, - {0x0b5d, 0x0b5f, 2}, - {0x0b60, 0x0b61, 1}, - {0x0b71, 0x0b83, 18}, - {0x0b85, 0x0b8a, 1}, - {0x0b8e, 0x0b90, 1}, - {0x0b92, 0x0b95, 1}, - {0x0b99, 0x0b9a, 1}, - {0x0b9c, 0x0b9e, 2}, - {0x0b9f, 0x0ba3, 4}, - {0x0ba4, 0x0ba8, 4}, - {0x0ba9, 0x0baa, 1}, - {0x0bae, 0x0bb9, 1}, - {0x0bd0, 0x0c05, 53}, - {0x0c06, 0x0c0c, 1}, - {0x0c0e, 0x0c10, 1}, - {0x0c12, 0x0c28, 1}, - {0x0c2a, 0x0c39, 1}, - {0x0c3d, 0x0c58, 27}, - {0x0c59, 0x0c5a, 1}, - {0x0c5d, 0x0c60, 3}, - {0x0c61, 0x0c80, 31}, - {0x0c85, 0x0c8c, 1}, - {0x0c8e, 0x0c90, 1}, - {0x0c92, 0x0ca8, 1}, - {0x0caa, 0x0cb3, 1}, - {0x0cb5, 0x0cb9, 1}, - {0x0cbd, 0x0cdd, 32}, - {0x0cde, 0x0ce0, 2}, - {0x0ce1, 0x0cf1, 16}, - {0x0cf2, 0x0d04, 18}, - {0x0d05, 0x0d0c, 1}, - {0x0d0e, 0x0d10, 1}, - {0x0d12, 0x0d3a, 1}, - {0x0d3d, 0x0d4e, 17}, - {0x0d54, 0x0d56, 1}, - {0x0d5f, 0x0d61, 1}, - {0x0d7a, 0x0d7f, 1}, - {0x0d85, 0x0d96, 1}, - {0x0d9a, 0x0db1, 1}, - {0x0db3, 0x0dbb, 1}, - {0x0dbd, 0x0dc0, 3}, - {0x0dc1, 0x0dc6, 1}, - {0x0e01, 0x0e30, 1}, - {0x0e32, 0x0e33, 1}, - {0x0e40, 0x0e45, 1}, - {0x0e81, 0x0e82, 1}, - {0x0e84, 0x0e86, 2}, - {0x0e87, 0x0e8a, 1}, - {0x0e8c, 0x0ea3, 1}, - {0x0ea5, 0x0ea7, 2}, - {0x0ea8, 0x0eb0, 1}, - {0x0eb2, 0x0eb3, 1}, - {0x0ebd, 0x0ec0, 3}, - {0x0ec1, 0x0ec4, 1}, - {0x0edc, 0x0edf, 1}, - {0x0f00, 0x0f40, 64}, - {0x0f41, 0x0f47, 1}, - {0x0f49, 0x0f6c, 1}, - {0x0f88, 0x0f8c, 1}, - {0x1000, 0x102a, 1}, - {0x103f, 0x1050, 17}, - {0x1051, 0x1055, 1}, - {0x105a, 0x105d, 1}, - {0x1061, 0x1065, 4}, - {0x1066, 0x106e, 8}, - {0x106f, 0x1070, 1}, - {0x1075, 0x1081, 1}, - {0x108e, 0x1100, 114}, - {0x1101, 0x1248, 1}, - {0x124a, 0x124d, 1}, - {0x1250, 0x1256, 1}, - {0x1258, 0x125a, 2}, - {0x125b, 0x125d, 1}, - {0x1260, 0x1288, 1}, - {0x128a, 0x128d, 1}, - {0x1290, 0x12b0, 1}, - {0x12b2, 0x12b5, 1}, - {0x12b8, 0x12be, 1}, - {0x12c0, 0x12c2, 2}, - {0x12c3, 0x12c5, 1}, - {0x12c8, 0x12d6, 1}, - {0x12d8, 0x1310, 1}, - {0x1312, 0x1315, 1}, - {0x1318, 0x135a, 1}, - {0x1380, 0x138f, 1}, - {0x1401, 0x166c, 1}, - {0x166f, 0x167f, 1}, - {0x1681, 0x169a, 1}, - {0x16a0, 0x16ea, 1}, - {0x16f1, 0x16f8, 1}, - {0x1700, 0x1711, 1}, - {0x171f, 0x1731, 1}, - {0x1740, 0x1751, 1}, - {0x1760, 0x176c, 1}, - {0x176e, 0x1770, 1}, - {0x1780, 0x17b3, 1}, - {0x17dc, 0x1820, 68}, - {0x1821, 0x1842, 1}, - {0x1844, 0x1878, 1}, - {0x1880, 0x1884, 1}, - {0x1887, 0x18a8, 1}, - {0x18aa, 0x18b0, 6}, - {0x18b1, 0x18f5, 1}, - {0x1900, 0x191e, 1}, - {0x1950, 0x196d, 1}, - {0x1970, 0x1974, 1}, - {0x1980, 0x19ab, 1}, - {0x19b0, 0x19c9, 1}, - {0x1a00, 0x1a16, 1}, - {0x1a20, 0x1a54, 1}, - {0x1b05, 0x1b33, 1}, - {0x1b45, 0x1b4c, 1}, - {0x1b83, 0x1ba0, 1}, - {0x1bae, 0x1baf, 1}, - {0x1bba, 0x1be5, 1}, - {0x1c00, 0x1c23, 1}, - {0x1c4d, 0x1c4f, 1}, - {0x1c5a, 0x1c77, 1}, - {0x1ce9, 0x1cec, 1}, - {0x1cee, 0x1cf3, 1}, - {0x1cf5, 0x1cf6, 1}, - {0x1cfa, 0x2135, 1083}, - {0x2136, 0x2138, 1}, - {0x2d30, 0x2d67, 1}, - {0x2d80, 0x2d96, 1}, - {0x2da0, 0x2da6, 1}, - {0x2da8, 0x2dae, 1}, - {0x2db0, 0x2db6, 1}, - {0x2db8, 0x2dbe, 1}, - {0x2dc0, 0x2dc6, 1}, - {0x2dc8, 0x2dce, 1}, - {0x2dd0, 0x2dd6, 1}, - {0x2dd8, 0x2dde, 1}, - {0x3006, 0x303c, 54}, - {0x3041, 0x3096, 1}, - {0x309f, 0x30a1, 2}, - {0x30a2, 0x30fa, 1}, - {0x30ff, 0x3105, 6}, - {0x3106, 0x312f, 1}, - {0x3131, 0x318e, 1}, - {0x31a0, 0x31bf, 1}, - {0x31f0, 0x31ff, 1}, - {0x3400, 0x4dbf, 1}, - {0x4e00, 0xa014, 1}, - {0xa016, 0xa48c, 1}, - {0xa4d0, 0xa4f7, 1}, - {0xa500, 0xa60b, 1}, - {0xa610, 0xa61f, 1}, - {0xa62a, 0xa62b, 1}, - {0xa66e, 0xa6a0, 50}, - {0xa6a1, 0xa6e5, 1}, - {0xa78f, 0xa7f7, 104}, - {0xa7fb, 0xa801, 1}, - {0xa803, 0xa805, 1}, - {0xa807, 0xa80a, 1}, - {0xa80c, 0xa822, 1}, - {0xa840, 0xa873, 1}, - {0xa882, 0xa8b3, 1}, - {0xa8f2, 0xa8f7, 1}, - {0xa8fb, 0xa8fd, 2}, - {0xa8fe, 0xa90a, 12}, - {0xa90b, 0xa925, 1}, - {0xa930, 0xa946, 1}, - {0xa960, 0xa97c, 1}, - {0xa984, 0xa9b2, 1}, - {0xa9e0, 0xa9e4, 1}, - {0xa9e7, 0xa9ef, 1}, - {0xa9fa, 0xa9fe, 1}, - {0xaa00, 0xaa28, 1}, - {0xaa40, 0xaa42, 1}, - {0xaa44, 0xaa4b, 1}, - {0xaa60, 0xaa6f, 1}, - {0xaa71, 0xaa76, 1}, - {0xaa7a, 0xaa7e, 4}, - {0xaa7f, 0xaaaf, 1}, - {0xaab1, 0xaab5, 4}, - {0xaab6, 0xaab9, 3}, - {0xaaba, 0xaabd, 1}, - {0xaac0, 0xaac2, 2}, - {0xaadb, 0xaadc, 1}, - {0xaae0, 0xaaea, 1}, - {0xaaf2, 0xab01, 15}, - {0xab02, 0xab06, 1}, - {0xab09, 0xab0e, 1}, - {0xab11, 0xab16, 1}, - {0xab20, 0xab26, 1}, - {0xab28, 0xab2e, 1}, - {0xabc0, 0xabe2, 1}, - {0xac00, 0xd7a3, 1}, - {0xd7b0, 0xd7c6, 1}, - {0xd7cb, 0xd7fb, 1}, - {0xf900, 0xfa6d, 1}, - {0xfa70, 0xfad9, 1}, - {0xfb1d, 0xfb1f, 2}, - {0xfb20, 0xfb28, 1}, - {0xfb2a, 0xfb36, 1}, - {0xfb38, 0xfb3c, 1}, - {0xfb3e, 0xfb40, 2}, - {0xfb41, 0xfb43, 2}, - {0xfb44, 0xfb46, 2}, - {0xfb47, 0xfbb1, 1}, - {0xfbd3, 0xfd3d, 1}, - {0xfd50, 0xfd8f, 1}, - {0xfd92, 0xfdc7, 1}, - {0xfdf0, 0xfdfb, 1}, - {0xfe70, 0xfe74, 1}, - {0xfe76, 0xfefc, 1}, - {0xff66, 0xff6f, 1}, - {0xff71, 0xff9d, 1}, - {0xffa0, 0xffbe, 1}, - {0xffc2, 0xffc7, 1}, - {0xffca, 0xffcf, 1}, - {0xffd2, 0xffd7, 1}, - {0xffda, 0xffdc, 1}, - ], - R32: [ - {0x10000, 0x1000b, 1}, - {0x1000d, 0x10026, 1}, - {0x10028, 0x1003a, 1}, - {0x1003c, 0x1003d, 1}, - {0x1003f, 0x1004d, 1}, - {0x10050, 0x1005d, 1}, - {0x10080, 0x100fa, 1}, - {0x10280, 0x1029c, 1}, - {0x102a0, 0x102d0, 1}, - {0x10300, 0x1031f, 1}, - {0x1032d, 0x10340, 1}, - {0x10342, 0x10349, 1}, - {0x10350, 0x10375, 1}, - {0x10380, 0x1039d, 1}, - {0x103a0, 0x103c3, 1}, - {0x103c8, 0x103cf, 1}, - {0x10450, 0x1049d, 1}, - {0x10500, 0x10527, 1}, - {0x10530, 0x10563, 1}, - {0x10600, 0x10736, 1}, - {0x10740, 0x10755, 1}, - {0x10760, 0x10767, 1}, - {0x10800, 0x10805, 1}, - {0x10808, 0x1080a, 2}, - {0x1080b, 0x10835, 1}, - {0x10837, 0x10838, 1}, - {0x1083c, 0x1083f, 3}, - {0x10840, 0x10855, 1}, - {0x10860, 0x10876, 1}, - {0x10880, 0x1089e, 1}, - {0x108e0, 0x108f2, 1}, - {0x108f4, 0x108f5, 1}, - {0x10900, 0x10915, 1}, - {0x10920, 0x10939, 1}, - {0x10980, 0x109b7, 1}, - {0x109be, 0x109bf, 1}, - {0x10a00, 0x10a10, 16}, - {0x10a11, 0x10a13, 1}, - {0x10a15, 0x10a17, 1}, - {0x10a19, 0x10a35, 1}, - {0x10a60, 0x10a7c, 1}, - {0x10a80, 0x10a9c, 1}, - {0x10ac0, 0x10ac7, 1}, - {0x10ac9, 0x10ae4, 1}, - {0x10b00, 0x10b35, 1}, - {0x10b40, 0x10b55, 1}, - {0x10b60, 0x10b72, 1}, - {0x10b80, 0x10b91, 1}, - {0x10c00, 0x10c48, 1}, - {0x10d00, 0x10d23, 1}, - {0x10e80, 0x10ea9, 1}, - {0x10eb0, 0x10eb1, 1}, - {0x10f00, 0x10f1c, 1}, - {0x10f27, 0x10f30, 9}, - {0x10f31, 0x10f45, 1}, - {0x10f70, 0x10f81, 1}, - {0x10fb0, 0x10fc4, 1}, - {0x10fe0, 0x10ff6, 1}, - {0x11003, 0x11037, 1}, - {0x11071, 0x11072, 1}, - {0x11075, 0x11083, 14}, - {0x11084, 0x110af, 1}, - {0x110d0, 0x110e8, 1}, - {0x11103, 0x11126, 1}, - {0x11144, 0x11147, 3}, - {0x11150, 0x11172, 1}, - {0x11176, 0x11183, 13}, - {0x11184, 0x111b2, 1}, - {0x111c1, 0x111c4, 1}, - {0x111da, 0x111dc, 2}, - {0x11200, 0x11211, 1}, - {0x11213, 0x1122b, 1}, - {0x1123f, 0x11240, 1}, - {0x11280, 0x11286, 1}, - {0x11288, 0x1128a, 2}, - {0x1128b, 0x1128d, 1}, - {0x1128f, 0x1129d, 1}, - {0x1129f, 0x112a8, 1}, - {0x112b0, 0x112de, 1}, - {0x11305, 0x1130c, 1}, - {0x1130f, 0x11310, 1}, - {0x11313, 0x11328, 1}, - {0x1132a, 0x11330, 1}, - {0x11332, 0x11333, 1}, - {0x11335, 0x11339, 1}, - {0x1133d, 0x11350, 19}, - {0x1135d, 0x11361, 1}, - {0x11400, 0x11434, 1}, - {0x11447, 0x1144a, 1}, - {0x1145f, 0x11461, 1}, - {0x11480, 0x114af, 1}, - {0x114c4, 0x114c5, 1}, - {0x114c7, 0x11580, 185}, - {0x11581, 0x115ae, 1}, - {0x115d8, 0x115db, 1}, - {0x11600, 0x1162f, 1}, - {0x11644, 0x11680, 60}, - {0x11681, 0x116aa, 1}, - {0x116b8, 0x11700, 72}, - {0x11701, 0x1171a, 1}, - {0x11740, 0x11746, 1}, - {0x11800, 0x1182b, 1}, - {0x118ff, 0x11906, 1}, - {0x11909, 0x1190c, 3}, - {0x1190d, 0x11913, 1}, - {0x11915, 0x11916, 1}, - {0x11918, 0x1192f, 1}, - {0x1193f, 0x11941, 2}, - {0x119a0, 0x119a7, 1}, - {0x119aa, 0x119d0, 1}, - {0x119e1, 0x119e3, 2}, - {0x11a00, 0x11a0b, 11}, - {0x11a0c, 0x11a32, 1}, - {0x11a3a, 0x11a50, 22}, - {0x11a5c, 0x11a89, 1}, - {0x11a9d, 0x11ab0, 19}, - {0x11ab1, 0x11af8, 1}, - {0x11c00, 0x11c08, 1}, - {0x11c0a, 0x11c2e, 1}, - {0x11c40, 0x11c72, 50}, - {0x11c73, 0x11c8f, 1}, - {0x11d00, 0x11d06, 1}, - {0x11d08, 0x11d09, 1}, - {0x11d0b, 0x11d30, 1}, - {0x11d46, 0x11d60, 26}, - {0x11d61, 0x11d65, 1}, - {0x11d67, 0x11d68, 1}, - {0x11d6a, 0x11d89, 1}, - {0x11d98, 0x11ee0, 328}, - {0x11ee1, 0x11ef2, 1}, - {0x11f02, 0x11f04, 2}, - {0x11f05, 0x11f10, 1}, - {0x11f12, 0x11f33, 1}, - {0x11fb0, 0x12000, 80}, - {0x12001, 0x12399, 1}, - {0x12480, 0x12543, 1}, - {0x12f90, 0x12ff0, 1}, - {0x13000, 0x1342f, 1}, - {0x13441, 0x13446, 1}, - {0x14400, 0x14646, 1}, - {0x16800, 0x16a38, 1}, - {0x16a40, 0x16a5e, 1}, - {0x16a70, 0x16abe, 1}, - {0x16ad0, 0x16aed, 1}, - {0x16b00, 0x16b2f, 1}, - {0x16b63, 0x16b77, 1}, - {0x16b7d, 0x16b8f, 1}, - {0x16f00, 0x16f4a, 1}, - {0x16f50, 0x17000, 176}, - {0x17001, 0x187f7, 1}, - {0x18800, 0x18cd5, 1}, - {0x18d00, 0x18d08, 1}, - {0x1b000, 0x1b122, 1}, - {0x1b132, 0x1b150, 30}, - {0x1b151, 0x1b152, 1}, - {0x1b155, 0x1b164, 15}, - {0x1b165, 0x1b167, 1}, - {0x1b170, 0x1b2fb, 1}, - {0x1bc00, 0x1bc6a, 1}, - {0x1bc70, 0x1bc7c, 1}, - {0x1bc80, 0x1bc88, 1}, - {0x1bc90, 0x1bc99, 1}, - {0x1df0a, 0x1e100, 502}, - {0x1e101, 0x1e12c, 1}, - {0x1e14e, 0x1e290, 322}, - {0x1e291, 0x1e2ad, 1}, - {0x1e2c0, 0x1e2eb, 1}, - {0x1e4d0, 0x1e4ea, 1}, - {0x1e7e0, 0x1e7e6, 1}, - {0x1e7e8, 0x1e7eb, 1}, - {0x1e7ed, 0x1e7ee, 1}, - {0x1e7f0, 0x1e7fe, 1}, - {0x1e800, 0x1e8c4, 1}, - {0x1ee00, 0x1ee03, 1}, - {0x1ee05, 0x1ee1f, 1}, - {0x1ee21, 0x1ee22, 1}, - {0x1ee24, 0x1ee27, 3}, - {0x1ee29, 0x1ee32, 1}, - {0x1ee34, 0x1ee37, 1}, - {0x1ee39, 0x1ee3b, 2}, - {0x1ee42, 0x1ee47, 5}, - {0x1ee49, 0x1ee4d, 2}, - {0x1ee4e, 0x1ee4f, 1}, - {0x1ee51, 0x1ee52, 1}, - {0x1ee54, 0x1ee57, 3}, - {0x1ee59, 0x1ee61, 2}, - {0x1ee62, 0x1ee64, 2}, - {0x1ee67, 0x1ee6a, 1}, - {0x1ee6c, 0x1ee72, 1}, - {0x1ee74, 0x1ee77, 1}, - {0x1ee79, 0x1ee7c, 1}, - {0x1ee7e, 0x1ee80, 2}, - {0x1ee81, 0x1ee89, 1}, - {0x1ee8b, 0x1ee9b, 1}, - {0x1eea1, 0x1eea3, 1}, - {0x1eea5, 0x1eea9, 1}, - {0x1eeab, 0x1eebb, 1}, - {0x20000, 0x2a6df, 1}, - {0x2a700, 0x2b739, 1}, - {0x2b740, 0x2b81d, 1}, - {0x2b820, 0x2cea1, 1}, - {0x2ceb0, 0x2ebe0, 1}, - {0x2f800, 0x2fa1d, 1}, - {0x30000, 0x3134a, 1}, - {0x31350, 0x323af, 1}, - ], - LatinOffset: 1, + R16: [ + {0x00aa, 0x00ba, 16}, + {0x01bb, 0x01c0, 5}, + {0x01c1, 0x01c3, 1}, + {0x0294, 0x05d0, 828}, + {0x05d1, 0x05ea, 1}, + {0x05ef, 0x05f2, 1}, + {0x0620, 0x063f, 1}, + {0x0641, 0x064a, 1}, + {0x066e, 0x066f, 1}, + {0x0671, 0x06d3, 1}, + {0x06d5, 0x06ee, 25}, + {0x06ef, 0x06fa, 11}, + {0x06fb, 0x06fc, 1}, + {0x06ff, 0x0710, 17}, + {0x0712, 0x072f, 1}, + {0x074d, 0x07a5, 1}, + {0x07b1, 0x07ca, 25}, + {0x07cb, 0x07ea, 1}, + {0x0800, 0x0815, 1}, + {0x0840, 0x0858, 1}, + {0x0860, 0x086a, 1}, + {0x0870, 0x0887, 1}, + {0x0889, 0x088e, 1}, + {0x08a0, 0x08c8, 1}, + {0x0904, 0x0939, 1}, + {0x093d, 0x0950, 19}, + {0x0958, 0x0961, 1}, + {0x0972, 0x0980, 1}, + {0x0985, 0x098c, 1}, + {0x098f, 0x0990, 1}, + {0x0993, 0x09a8, 1}, + {0x09aa, 0x09b0, 1}, + {0x09b2, 0x09b6, 4}, + {0x09b7, 0x09b9, 1}, + {0x09bd, 0x09ce, 17}, + {0x09dc, 0x09dd, 1}, + {0x09df, 0x09e1, 1}, + {0x09f0, 0x09f1, 1}, + {0x09fc, 0x0a05, 9}, + {0x0a06, 0x0a0a, 1}, + {0x0a0f, 0x0a10, 1}, + {0x0a13, 0x0a28, 1}, + {0x0a2a, 0x0a30, 1}, + {0x0a32, 0x0a33, 1}, + {0x0a35, 0x0a36, 1}, + {0x0a38, 0x0a39, 1}, + {0x0a59, 0x0a5c, 1}, + {0x0a5e, 0x0a72, 20}, + {0x0a73, 0x0a74, 1}, + {0x0a85, 0x0a8d, 1}, + {0x0a8f, 0x0a91, 1}, + {0x0a93, 0x0aa8, 1}, + {0x0aaa, 0x0ab0, 1}, + {0x0ab2, 0x0ab3, 1}, + {0x0ab5, 0x0ab9, 1}, + {0x0abd, 0x0ad0, 19}, + {0x0ae0, 0x0ae1, 1}, + {0x0af9, 0x0b05, 12}, + {0x0b06, 0x0b0c, 1}, + {0x0b0f, 0x0b10, 1}, + {0x0b13, 0x0b28, 1}, + {0x0b2a, 0x0b30, 1}, + {0x0b32, 0x0b33, 1}, + {0x0b35, 0x0b39, 1}, + {0x0b3d, 0x0b5c, 31}, + {0x0b5d, 0x0b5f, 2}, + {0x0b60, 0x0b61, 1}, + {0x0b71, 0x0b83, 18}, + {0x0b85, 0x0b8a, 1}, + {0x0b8e, 0x0b90, 1}, + {0x0b92, 0x0b95, 1}, + {0x0b99, 0x0b9a, 1}, + {0x0b9c, 0x0b9e, 2}, + {0x0b9f, 0x0ba3, 4}, + {0x0ba4, 0x0ba8, 4}, + {0x0ba9, 0x0baa, 1}, + {0x0bae, 0x0bb9, 1}, + {0x0bd0, 0x0c05, 53}, + {0x0c06, 0x0c0c, 1}, + {0x0c0e, 0x0c10, 1}, + {0x0c12, 0x0c28, 1}, + {0x0c2a, 0x0c39, 1}, + {0x0c3d, 0x0c58, 27}, + {0x0c59, 0x0c5a, 1}, + {0x0c5d, 0x0c60, 3}, + {0x0c61, 0x0c80, 31}, + {0x0c85, 0x0c8c, 1}, + {0x0c8e, 0x0c90, 1}, + {0x0c92, 0x0ca8, 1}, + {0x0caa, 0x0cb3, 1}, + {0x0cb5, 0x0cb9, 1}, + {0x0cbd, 0x0cdd, 32}, + {0x0cde, 0x0ce0, 2}, + {0x0ce1, 0x0cf1, 16}, + {0x0cf2, 0x0d04, 18}, + {0x0d05, 0x0d0c, 1}, + {0x0d0e, 0x0d10, 1}, + {0x0d12, 0x0d3a, 1}, + {0x0d3d, 0x0d4e, 17}, + {0x0d54, 0x0d56, 1}, + {0x0d5f, 0x0d61, 1}, + {0x0d7a, 0x0d7f, 1}, + {0x0d85, 0x0d96, 1}, + {0x0d9a, 0x0db1, 1}, + {0x0db3, 0x0dbb, 1}, + {0x0dbd, 0x0dc0, 3}, + {0x0dc1, 0x0dc6, 1}, + {0x0e01, 0x0e30, 1}, + {0x0e32, 0x0e33, 1}, + {0x0e40, 0x0e45, 1}, + {0x0e81, 0x0e82, 1}, + {0x0e84, 0x0e86, 2}, + {0x0e87, 0x0e8a, 1}, + {0x0e8c, 0x0ea3, 1}, + {0x0ea5, 0x0ea7, 2}, + {0x0ea8, 0x0eb0, 1}, + {0x0eb2, 0x0eb3, 1}, + {0x0ebd, 0x0ec0, 3}, + {0x0ec1, 0x0ec4, 1}, + {0x0edc, 0x0edf, 1}, + {0x0f00, 0x0f40, 64}, + {0x0f41, 0x0f47, 1}, + {0x0f49, 0x0f6c, 1}, + {0x0f88, 0x0f8c, 1}, + {0x1000, 0x102a, 1}, + {0x103f, 0x1050, 17}, + {0x1051, 0x1055, 1}, + {0x105a, 0x105d, 1}, + {0x1061, 0x1065, 4}, + {0x1066, 0x106e, 8}, + {0x106f, 0x1070, 1}, + {0x1075, 0x1081, 1}, + {0x108e, 0x1100, 114}, + {0x1101, 0x1248, 1}, + {0x124a, 0x124d, 1}, + {0x1250, 0x1256, 1}, + {0x1258, 0x125a, 2}, + {0x125b, 0x125d, 1}, + {0x1260, 0x1288, 1}, + {0x128a, 0x128d, 1}, + {0x1290, 0x12b0, 1}, + {0x12b2, 0x12b5, 1}, + {0x12b8, 0x12be, 1}, + {0x12c0, 0x12c2, 2}, + {0x12c3, 0x12c5, 1}, + {0x12c8, 0x12d6, 1}, + {0x12d8, 0x1310, 1}, + {0x1312, 0x1315, 1}, + {0x1318, 0x135a, 1}, + {0x1380, 0x138f, 1}, + {0x1401, 0x166c, 1}, + {0x166f, 0x167f, 1}, + {0x1681, 0x169a, 1}, + {0x16a0, 0x16ea, 1}, + {0x16f1, 0x16f8, 1}, + {0x1700, 0x1711, 1}, + {0x171f, 0x1731, 1}, + {0x1740, 0x1751, 1}, + {0x1760, 0x176c, 1}, + {0x176e, 0x1770, 1}, + {0x1780, 0x17b3, 1}, + {0x17dc, 0x1820, 68}, + {0x1821, 0x1842, 1}, + {0x1844, 0x1878, 1}, + {0x1880, 0x1884, 1}, + {0x1887, 0x18a8, 1}, + {0x18aa, 0x18b0, 6}, + {0x18b1, 0x18f5, 1}, + {0x1900, 0x191e, 1}, + {0x1950, 0x196d, 1}, + {0x1970, 0x1974, 1}, + {0x1980, 0x19ab, 1}, + {0x19b0, 0x19c9, 1}, + {0x1a00, 0x1a16, 1}, + {0x1a20, 0x1a54, 1}, + {0x1b05, 0x1b33, 1}, + {0x1b45, 0x1b4c, 1}, + {0x1b83, 0x1ba0, 1}, + {0x1bae, 0x1baf, 1}, + {0x1bba, 0x1be5, 1}, + {0x1c00, 0x1c23, 1}, + {0x1c4d, 0x1c4f, 1}, + {0x1c5a, 0x1c77, 1}, + {0x1ce9, 0x1cec, 1}, + {0x1cee, 0x1cf3, 1}, + {0x1cf5, 0x1cf6, 1}, + {0x1cfa, 0x2135, 1083}, + {0x2136, 0x2138, 1}, + {0x2d30, 0x2d67, 1}, + {0x2d80, 0x2d96, 1}, + {0x2da0, 0x2da6, 1}, + {0x2da8, 0x2dae, 1}, + {0x2db0, 0x2db6, 1}, + {0x2db8, 0x2dbe, 1}, + {0x2dc0, 0x2dc6, 1}, + {0x2dc8, 0x2dce, 1}, + {0x2dd0, 0x2dd6, 1}, + {0x2dd8, 0x2dde, 1}, + {0x3006, 0x303c, 54}, + {0x3041, 0x3096, 1}, + {0x309f, 0x30a1, 2}, + {0x30a2, 0x30fa, 1}, + {0x30ff, 0x3105, 6}, + {0x3106, 0x312f, 1}, + {0x3131, 0x318e, 1}, + {0x31a0, 0x31bf, 1}, + {0x31f0, 0x31ff, 1}, + {0x3400, 0x4dbf, 1}, + {0x4e00, 0xa014, 1}, + {0xa016, 0xa48c, 1}, + {0xa4d0, 0xa4f7, 1}, + {0xa500, 0xa60b, 1}, + {0xa610, 0xa61f, 1}, + {0xa62a, 0xa62b, 1}, + {0xa66e, 0xa6a0, 50}, + {0xa6a1, 0xa6e5, 1}, + {0xa78f, 0xa7f7, 104}, + {0xa7fb, 0xa801, 1}, + {0xa803, 0xa805, 1}, + {0xa807, 0xa80a, 1}, + {0xa80c, 0xa822, 1}, + {0xa840, 0xa873, 1}, + {0xa882, 0xa8b3, 1}, + {0xa8f2, 0xa8f7, 1}, + {0xa8fb, 0xa8fd, 2}, + {0xa8fe, 0xa90a, 12}, + {0xa90b, 0xa925, 1}, + {0xa930, 0xa946, 1}, + {0xa960, 0xa97c, 1}, + {0xa984, 0xa9b2, 1}, + {0xa9e0, 0xa9e4, 1}, + {0xa9e7, 0xa9ef, 1}, + {0xa9fa, 0xa9fe, 1}, + {0xaa00, 0xaa28, 1}, + {0xaa40, 0xaa42, 1}, + {0xaa44, 0xaa4b, 1}, + {0xaa60, 0xaa6f, 1}, + {0xaa71, 0xaa76, 1}, + {0xaa7a, 0xaa7e, 4}, + {0xaa7f, 0xaaaf, 1}, + {0xaab1, 0xaab5, 4}, + {0xaab6, 0xaab9, 3}, + {0xaaba, 0xaabd, 1}, + {0xaac0, 0xaac2, 2}, + {0xaadb, 0xaadc, 1}, + {0xaae0, 0xaaea, 1}, + {0xaaf2, 0xab01, 15}, + {0xab02, 0xab06, 1}, + {0xab09, 0xab0e, 1}, + {0xab11, 0xab16, 1}, + {0xab20, 0xab26, 1}, + {0xab28, 0xab2e, 1}, + {0xabc0, 0xabe2, 1}, + {0xac00, 0xd7a3, 1}, + {0xd7b0, 0xd7c6, 1}, + {0xd7cb, 0xd7fb, 1}, + {0xf900, 0xfa6d, 1}, + {0xfa70, 0xfad9, 1}, + {0xfb1d, 0xfb1f, 2}, + {0xfb20, 0xfb28, 1}, + {0xfb2a, 0xfb36, 1}, + {0xfb38, 0xfb3c, 1}, + {0xfb3e, 0xfb40, 2}, + {0xfb41, 0xfb43, 2}, + {0xfb44, 0xfb46, 2}, + {0xfb47, 0xfbb1, 1}, + {0xfbd3, 0xfd3d, 1}, + {0xfd50, 0xfd8f, 1}, + {0xfd92, 0xfdc7, 1}, + {0xfdf0, 0xfdfb, 1}, + {0xfe70, 0xfe74, 1}, + {0xfe76, 0xfefc, 1}, + {0xff66, 0xff6f, 1}, + {0xff71, 0xff9d, 1}, + {0xffa0, 0xffbe, 1}, + {0xffc2, 0xffc7, 1}, + {0xffca, 0xffcf, 1}, + {0xffd2, 0xffd7, 1}, + {0xffda, 0xffdc, 1}, + ], + R32: [ + {0x10000, 0x1000b, 1}, + {0x1000d, 0x10026, 1}, + {0x10028, 0x1003a, 1}, + {0x1003c, 0x1003d, 1}, + {0x1003f, 0x1004d, 1}, + {0x10050, 0x1005d, 1}, + {0x10080, 0x100fa, 1}, + {0x10280, 0x1029c, 1}, + {0x102a0, 0x102d0, 1}, + {0x10300, 0x1031f, 1}, + {0x1032d, 0x10340, 1}, + {0x10342, 0x10349, 1}, + {0x10350, 0x10375, 1}, + {0x10380, 0x1039d, 1}, + {0x103a0, 0x103c3, 1}, + {0x103c8, 0x103cf, 1}, + {0x10450, 0x1049d, 1}, + {0x10500, 0x10527, 1}, + {0x10530, 0x10563, 1}, + {0x10600, 0x10736, 1}, + {0x10740, 0x10755, 1}, + {0x10760, 0x10767, 1}, + {0x10800, 0x10805, 1}, + {0x10808, 0x1080a, 2}, + {0x1080b, 0x10835, 1}, + {0x10837, 0x10838, 1}, + {0x1083c, 0x1083f, 3}, + {0x10840, 0x10855, 1}, + {0x10860, 0x10876, 1}, + {0x10880, 0x1089e, 1}, + {0x108e0, 0x108f2, 1}, + {0x108f4, 0x108f5, 1}, + {0x10900, 0x10915, 1}, + {0x10920, 0x10939, 1}, + {0x10980, 0x109b7, 1}, + {0x109be, 0x109bf, 1}, + {0x10a00, 0x10a10, 16}, + {0x10a11, 0x10a13, 1}, + {0x10a15, 0x10a17, 1}, + {0x10a19, 0x10a35, 1}, + {0x10a60, 0x10a7c, 1}, + {0x10a80, 0x10a9c, 1}, + {0x10ac0, 0x10ac7, 1}, + {0x10ac9, 0x10ae4, 1}, + {0x10b00, 0x10b35, 1}, + {0x10b40, 0x10b55, 1}, + {0x10b60, 0x10b72, 1}, + {0x10b80, 0x10b91, 1}, + {0x10c00, 0x10c48, 1}, + {0x10d00, 0x10d23, 1}, + {0x10e80, 0x10ea9, 1}, + {0x10eb0, 0x10eb1, 1}, + {0x10f00, 0x10f1c, 1}, + {0x10f27, 0x10f30, 9}, + {0x10f31, 0x10f45, 1}, + {0x10f70, 0x10f81, 1}, + {0x10fb0, 0x10fc4, 1}, + {0x10fe0, 0x10ff6, 1}, + {0x11003, 0x11037, 1}, + {0x11071, 0x11072, 1}, + {0x11075, 0x11083, 14}, + {0x11084, 0x110af, 1}, + {0x110d0, 0x110e8, 1}, + {0x11103, 0x11126, 1}, + {0x11144, 0x11147, 3}, + {0x11150, 0x11172, 1}, + {0x11176, 0x11183, 13}, + {0x11184, 0x111b2, 1}, + {0x111c1, 0x111c4, 1}, + {0x111da, 0x111dc, 2}, + {0x11200, 0x11211, 1}, + {0x11213, 0x1122b, 1}, + {0x1123f, 0x11240, 1}, + {0x11280, 0x11286, 1}, + {0x11288, 0x1128a, 2}, + {0x1128b, 0x1128d, 1}, + {0x1128f, 0x1129d, 1}, + {0x1129f, 0x112a8, 1}, + {0x112b0, 0x112de, 1}, + {0x11305, 0x1130c, 1}, + {0x1130f, 0x11310, 1}, + {0x11313, 0x11328, 1}, + {0x1132a, 0x11330, 1}, + {0x11332, 0x11333, 1}, + {0x11335, 0x11339, 1}, + {0x1133d, 0x11350, 19}, + {0x1135d, 0x11361, 1}, + {0x11400, 0x11434, 1}, + {0x11447, 0x1144a, 1}, + {0x1145f, 0x11461, 1}, + {0x11480, 0x114af, 1}, + {0x114c4, 0x114c5, 1}, + {0x114c7, 0x11580, 185}, + {0x11581, 0x115ae, 1}, + {0x115d8, 0x115db, 1}, + {0x11600, 0x1162f, 1}, + {0x11644, 0x11680, 60}, + {0x11681, 0x116aa, 1}, + {0x116b8, 0x11700, 72}, + {0x11701, 0x1171a, 1}, + {0x11740, 0x11746, 1}, + {0x11800, 0x1182b, 1}, + {0x118ff, 0x11906, 1}, + {0x11909, 0x1190c, 3}, + {0x1190d, 0x11913, 1}, + {0x11915, 0x11916, 1}, + {0x11918, 0x1192f, 1}, + {0x1193f, 0x11941, 2}, + {0x119a0, 0x119a7, 1}, + {0x119aa, 0x119d0, 1}, + {0x119e1, 0x119e3, 2}, + {0x11a00, 0x11a0b, 11}, + {0x11a0c, 0x11a32, 1}, + {0x11a3a, 0x11a50, 22}, + {0x11a5c, 0x11a89, 1}, + {0x11a9d, 0x11ab0, 19}, + {0x11ab1, 0x11af8, 1}, + {0x11c00, 0x11c08, 1}, + {0x11c0a, 0x11c2e, 1}, + {0x11c40, 0x11c72, 50}, + {0x11c73, 0x11c8f, 1}, + {0x11d00, 0x11d06, 1}, + {0x11d08, 0x11d09, 1}, + {0x11d0b, 0x11d30, 1}, + {0x11d46, 0x11d60, 26}, + {0x11d61, 0x11d65, 1}, + {0x11d67, 0x11d68, 1}, + {0x11d6a, 0x11d89, 1}, + {0x11d98, 0x11ee0, 328}, + {0x11ee1, 0x11ef2, 1}, + {0x11f02, 0x11f04, 2}, + {0x11f05, 0x11f10, 1}, + {0x11f12, 0x11f33, 1}, + {0x11fb0, 0x12000, 80}, + {0x12001, 0x12399, 1}, + {0x12480, 0x12543, 1}, + {0x12f90, 0x12ff0, 1}, + {0x13000, 0x1342f, 1}, + {0x13441, 0x13446, 1}, + {0x14400, 0x14646, 1}, + {0x16800, 0x16a38, 1}, + {0x16a40, 0x16a5e, 1}, + {0x16a70, 0x16abe, 1}, + {0x16ad0, 0x16aed, 1}, + {0x16b00, 0x16b2f, 1}, + {0x16b63, 0x16b77, 1}, + {0x16b7d, 0x16b8f, 1}, + {0x16f00, 0x16f4a, 1}, + {0x16f50, 0x17000, 176}, + {0x17001, 0x187f7, 1}, + {0x18800, 0x18cd5, 1}, + {0x18d00, 0x18d08, 1}, + {0x1b000, 0x1b122, 1}, + {0x1b132, 0x1b150, 30}, + {0x1b151, 0x1b152, 1}, + {0x1b155, 0x1b164, 15}, + {0x1b165, 0x1b167, 1}, + {0x1b170, 0x1b2fb, 1}, + {0x1bc00, 0x1bc6a, 1}, + {0x1bc70, 0x1bc7c, 1}, + {0x1bc80, 0x1bc88, 1}, + {0x1bc90, 0x1bc99, 1}, + {0x1df0a, 0x1e100, 502}, + {0x1e101, 0x1e12c, 1}, + {0x1e14e, 0x1e290, 322}, + {0x1e291, 0x1e2ad, 1}, + {0x1e2c0, 0x1e2eb, 1}, + {0x1e4d0, 0x1e4ea, 1}, + {0x1e7e0, 0x1e7e6, 1}, + {0x1e7e8, 0x1e7eb, 1}, + {0x1e7ed, 0x1e7ee, 1}, + {0x1e7f0, 0x1e7fe, 1}, + {0x1e800, 0x1e8c4, 1}, + {0x1ee00, 0x1ee03, 1}, + {0x1ee05, 0x1ee1f, 1}, + {0x1ee21, 0x1ee22, 1}, + {0x1ee24, 0x1ee27, 3}, + {0x1ee29, 0x1ee32, 1}, + {0x1ee34, 0x1ee37, 1}, + {0x1ee39, 0x1ee3b, 2}, + {0x1ee42, 0x1ee47, 5}, + {0x1ee49, 0x1ee4d, 2}, + {0x1ee4e, 0x1ee4f, 1}, + {0x1ee51, 0x1ee52, 1}, + {0x1ee54, 0x1ee57, 3}, + {0x1ee59, 0x1ee61, 2}, + {0x1ee62, 0x1ee64, 2}, + {0x1ee67, 0x1ee6a, 1}, + {0x1ee6c, 0x1ee72, 1}, + {0x1ee74, 0x1ee77, 1}, + {0x1ee79, 0x1ee7c, 1}, + {0x1ee7e, 0x1ee80, 2}, + {0x1ee81, 0x1ee89, 1}, + {0x1ee8b, 0x1ee9b, 1}, + {0x1eea1, 0x1eea3, 1}, + {0x1eea5, 0x1eea9, 1}, + {0x1eeab, 0x1eebb, 1}, + {0x20000, 0x2a6df, 1}, + {0x2a700, 0x2b739, 1}, + {0x2b740, 0x2b81d, 1}, + {0x2b820, 0x2cea1, 1}, + {0x2ceb0, 0x2ebe0, 1}, + {0x2f800, 0x2fa1d, 1}, + {0x30000, 0x3134a, 1}, + {0x31350, 0x323af, 1}, + ], + LatinOffset: 1, } static _LT = &RangeTable{ - R16: [ - {0x01c5, 0x01cb, 3}, - {0x01f2, 0x1f88, 7574}, - {0x1f89, 0x1f8f, 1}, - {0x1f98, 0x1f9f, 1}, - {0x1fa8, 0x1faf, 1}, - {0x1fbc, 0x1fcc, 16}, - {0x1ffc, 0x1ffc, 1}, - ], + R16: [ + {0x01c5, 0x01cb, 3}, + {0x01f2, 0x1f88, 7574}, + {0x1f89, 0x1f8f, 1}, + {0x1f98, 0x1f9f, 1}, + {0x1fa8, 0x1faf, 1}, + {0x1fbc, 0x1fcc, 16}, + {0x1ffc, 0x1ffc, 1}, + ], } static _LU = &RangeTable{ - R16: [ - {0x0041, 0x005a, 1}, - {0x00c0, 0x00d6, 1}, - {0x00d8, 0x00de, 1}, - {0x0100, 0x0136, 2}, - {0x0139, 0x0147, 2}, - {0x014a, 0x0178, 2}, - {0x0179, 0x017d, 2}, - {0x0181, 0x0182, 1}, - {0x0184, 0x0186, 2}, - {0x0187, 0x0189, 2}, - {0x018a, 0x018b, 1}, - {0x018e, 0x0191, 1}, - {0x0193, 0x0194, 1}, - {0x0196, 0x0198, 1}, - {0x019c, 0x019d, 1}, - {0x019f, 0x01a0, 1}, - {0x01a2, 0x01a6, 2}, - {0x01a7, 0x01a9, 2}, - {0x01ac, 0x01ae, 2}, - {0x01af, 0x01b1, 2}, - {0x01b2, 0x01b3, 1}, - {0x01b5, 0x01b7, 2}, - {0x01b8, 0x01bc, 4}, - {0x01c4, 0x01cd, 3}, - {0x01cf, 0x01db, 2}, - {0x01de, 0x01ee, 2}, - {0x01f1, 0x01f4, 3}, - {0x01f6, 0x01f8, 1}, - {0x01fa, 0x0232, 2}, - {0x023a, 0x023b, 1}, - {0x023d, 0x023e, 1}, - {0x0241, 0x0243, 2}, - {0x0244, 0x0246, 1}, - {0x0248, 0x024e, 2}, - {0x0370, 0x0372, 2}, - {0x0376, 0x037f, 9}, - {0x0386, 0x0388, 2}, - {0x0389, 0x038a, 1}, - {0x038c, 0x038e, 2}, - {0x038f, 0x0391, 2}, - {0x0392, 0x03a1, 1}, - {0x03a3, 0x03ab, 1}, - {0x03cf, 0x03d2, 3}, - {0x03d3, 0x03d4, 1}, - {0x03d8, 0x03ee, 2}, - {0x03f4, 0x03f7, 3}, - {0x03f9, 0x03fa, 1}, - {0x03fd, 0x042f, 1}, - {0x0460, 0x0480, 2}, - {0x048a, 0x04c0, 2}, - {0x04c1, 0x04cd, 2}, - {0x04d0, 0x052e, 2}, - {0x0531, 0x0556, 1}, - {0x10a0, 0x10c5, 1}, - {0x10c7, 0x10cd, 6}, - {0x13a0, 0x13f5, 1}, - {0x1c90, 0x1cba, 1}, - {0x1cbd, 0x1cbf, 1}, - {0x1e00, 0x1e94, 2}, - {0x1e9e, 0x1efe, 2}, - {0x1f08, 0x1f0f, 1}, - {0x1f18, 0x1f1d, 1}, - {0x1f28, 0x1f2f, 1}, - {0x1f38, 0x1f3f, 1}, - {0x1f48, 0x1f4d, 1}, - {0x1f59, 0x1f5f, 2}, - {0x1f68, 0x1f6f, 1}, - {0x1fb8, 0x1fbb, 1}, - {0x1fc8, 0x1fcb, 1}, - {0x1fd8, 0x1fdb, 1}, - {0x1fe8, 0x1fec, 1}, - {0x1ff8, 0x1ffb, 1}, - {0x2102, 0x2107, 5}, - {0x210b, 0x210d, 1}, - {0x2110, 0x2112, 1}, - {0x2115, 0x2119, 4}, - {0x211a, 0x211d, 1}, - {0x2124, 0x212a, 2}, - {0x212b, 0x212d, 1}, - {0x2130, 0x2133, 1}, - {0x213e, 0x213f, 1}, - {0x2145, 0x2183, 62}, - {0x2c00, 0x2c2f, 1}, - {0x2c60, 0x2c62, 2}, - {0x2c63, 0x2c64, 1}, - {0x2c67, 0x2c6d, 2}, - {0x2c6e, 0x2c70, 1}, - {0x2c72, 0x2c75, 3}, - {0x2c7e, 0x2c80, 1}, - {0x2c82, 0x2ce2, 2}, - {0x2ceb, 0x2ced, 2}, - {0x2cf2, 0xa640, 31054}, - {0xa642, 0xa66c, 2}, - {0xa680, 0xa69a, 2}, - {0xa722, 0xa72e, 2}, - {0xa732, 0xa76e, 2}, - {0xa779, 0xa77d, 2}, - {0xa77e, 0xa786, 2}, - {0xa78b, 0xa78d, 2}, - {0xa790, 0xa792, 2}, - {0xa796, 0xa7aa, 2}, - {0xa7ab, 0xa7ae, 1}, - {0xa7b0, 0xa7b4, 1}, - {0xa7b6, 0xa7c4, 2}, - {0xa7c5, 0xa7c7, 1}, - {0xa7c9, 0xa7d0, 7}, - {0xa7d6, 0xa7d8, 2}, - {0xa7f5, 0xff21, 22316}, - {0xff22, 0xff3a, 1}, - ], - R32: [ - {0x10400, 0x10427, 1}, - {0x104b0, 0x104d3, 1}, - {0x10570, 0x1057a, 1}, - {0x1057c, 0x1058a, 1}, - {0x1058c, 0x10592, 1}, - {0x10594, 0x10595, 1}, - {0x10c80, 0x10cb2, 1}, - {0x118a0, 0x118bf, 1}, - {0x16e40, 0x16e5f, 1}, - {0x1d400, 0x1d419, 1}, - {0x1d434, 0x1d44d, 1}, - {0x1d468, 0x1d481, 1}, - {0x1d49c, 0x1d49e, 2}, - {0x1d49f, 0x1d4a5, 3}, - {0x1d4a6, 0x1d4a9, 3}, - {0x1d4aa, 0x1d4ac, 1}, - {0x1d4ae, 0x1d4b5, 1}, - {0x1d4d0, 0x1d4e9, 1}, - {0x1d504, 0x1d505, 1}, - {0x1d507, 0x1d50a, 1}, - {0x1d50d, 0x1d514, 1}, - {0x1d516, 0x1d51c, 1}, - {0x1d538, 0x1d539, 1}, - {0x1d53b, 0x1d53e, 1}, - {0x1d540, 0x1d544, 1}, - {0x1d546, 0x1d54a, 4}, - {0x1d54b, 0x1d550, 1}, - {0x1d56c, 0x1d585, 1}, - {0x1d5a0, 0x1d5b9, 1}, - {0x1d5d4, 0x1d5ed, 1}, - {0x1d608, 0x1d621, 1}, - {0x1d63c, 0x1d655, 1}, - {0x1d670, 0x1d689, 1}, - {0x1d6a8, 0x1d6c0, 1}, - {0x1d6e2, 0x1d6fa, 1}, - {0x1d71c, 0x1d734, 1}, - {0x1d756, 0x1d76e, 1}, - {0x1d790, 0x1d7a8, 1}, - {0x1d7ca, 0x1e900, 4406}, - {0x1e901, 0x1e921, 1}, - ], - LatinOffset: 3, + R16: [ + {0x0041, 0x005a, 1}, + {0x00c0, 0x00d6, 1}, + {0x00d8, 0x00de, 1}, + {0x0100, 0x0136, 2}, + {0x0139, 0x0147, 2}, + {0x014a, 0x0178, 2}, + {0x0179, 0x017d, 2}, + {0x0181, 0x0182, 1}, + {0x0184, 0x0186, 2}, + {0x0187, 0x0189, 2}, + {0x018a, 0x018b, 1}, + {0x018e, 0x0191, 1}, + {0x0193, 0x0194, 1}, + {0x0196, 0x0198, 1}, + {0x019c, 0x019d, 1}, + {0x019f, 0x01a0, 1}, + {0x01a2, 0x01a6, 2}, + {0x01a7, 0x01a9, 2}, + {0x01ac, 0x01ae, 2}, + {0x01af, 0x01b1, 2}, + {0x01b2, 0x01b3, 1}, + {0x01b5, 0x01b7, 2}, + {0x01b8, 0x01bc, 4}, + {0x01c4, 0x01cd, 3}, + {0x01cf, 0x01db, 2}, + {0x01de, 0x01ee, 2}, + {0x01f1, 0x01f4, 3}, + {0x01f6, 0x01f8, 1}, + {0x01fa, 0x0232, 2}, + {0x023a, 0x023b, 1}, + {0x023d, 0x023e, 1}, + {0x0241, 0x0243, 2}, + {0x0244, 0x0246, 1}, + {0x0248, 0x024e, 2}, + {0x0370, 0x0372, 2}, + {0x0376, 0x037f, 9}, + {0x0386, 0x0388, 2}, + {0x0389, 0x038a, 1}, + {0x038c, 0x038e, 2}, + {0x038f, 0x0391, 2}, + {0x0392, 0x03a1, 1}, + {0x03a3, 0x03ab, 1}, + {0x03cf, 0x03d2, 3}, + {0x03d3, 0x03d4, 1}, + {0x03d8, 0x03ee, 2}, + {0x03f4, 0x03f7, 3}, + {0x03f9, 0x03fa, 1}, + {0x03fd, 0x042f, 1}, + {0x0460, 0x0480, 2}, + {0x048a, 0x04c0, 2}, + {0x04c1, 0x04cd, 2}, + {0x04d0, 0x052e, 2}, + {0x0531, 0x0556, 1}, + {0x10a0, 0x10c5, 1}, + {0x10c7, 0x10cd, 6}, + {0x13a0, 0x13f5, 1}, + {0x1c90, 0x1cba, 1}, + {0x1cbd, 0x1cbf, 1}, + {0x1e00, 0x1e94, 2}, + {0x1e9e, 0x1efe, 2}, + {0x1f08, 0x1f0f, 1}, + {0x1f18, 0x1f1d, 1}, + {0x1f28, 0x1f2f, 1}, + {0x1f38, 0x1f3f, 1}, + {0x1f48, 0x1f4d, 1}, + {0x1f59, 0x1f5f, 2}, + {0x1f68, 0x1f6f, 1}, + {0x1fb8, 0x1fbb, 1}, + {0x1fc8, 0x1fcb, 1}, + {0x1fd8, 0x1fdb, 1}, + {0x1fe8, 0x1fec, 1}, + {0x1ff8, 0x1ffb, 1}, + {0x2102, 0x2107, 5}, + {0x210b, 0x210d, 1}, + {0x2110, 0x2112, 1}, + {0x2115, 0x2119, 4}, + {0x211a, 0x211d, 1}, + {0x2124, 0x212a, 2}, + {0x212b, 0x212d, 1}, + {0x2130, 0x2133, 1}, + {0x213e, 0x213f, 1}, + {0x2145, 0x2183, 62}, + {0x2c00, 0x2c2f, 1}, + {0x2c60, 0x2c62, 2}, + {0x2c63, 0x2c64, 1}, + {0x2c67, 0x2c6d, 2}, + {0x2c6e, 0x2c70, 1}, + {0x2c72, 0x2c75, 3}, + {0x2c7e, 0x2c80, 1}, + {0x2c82, 0x2ce2, 2}, + {0x2ceb, 0x2ced, 2}, + {0x2cf2, 0xa640, 31054}, + {0xa642, 0xa66c, 2}, + {0xa680, 0xa69a, 2}, + {0xa722, 0xa72e, 2}, + {0xa732, 0xa76e, 2}, + {0xa779, 0xa77d, 2}, + {0xa77e, 0xa786, 2}, + {0xa78b, 0xa78d, 2}, + {0xa790, 0xa792, 2}, + {0xa796, 0xa7aa, 2}, + {0xa7ab, 0xa7ae, 1}, + {0xa7b0, 0xa7b4, 1}, + {0xa7b6, 0xa7c4, 2}, + {0xa7c5, 0xa7c7, 1}, + {0xa7c9, 0xa7d0, 7}, + {0xa7d6, 0xa7d8, 2}, + {0xa7f5, 0xff21, 22316}, + {0xff22, 0xff3a, 1}, + ], + R32: [ + {0x10400, 0x10427, 1}, + {0x104b0, 0x104d3, 1}, + {0x10570, 0x1057a, 1}, + {0x1057c, 0x1058a, 1}, + {0x1058c, 0x10592, 1}, + {0x10594, 0x10595, 1}, + {0x10c80, 0x10cb2, 1}, + {0x118a0, 0x118bf, 1}, + {0x16e40, 0x16e5f, 1}, + {0x1d400, 0x1d419, 1}, + {0x1d434, 0x1d44d, 1}, + {0x1d468, 0x1d481, 1}, + {0x1d49c, 0x1d49e, 2}, + {0x1d49f, 0x1d4a5, 3}, + {0x1d4a6, 0x1d4a9, 3}, + {0x1d4aa, 0x1d4ac, 1}, + {0x1d4ae, 0x1d4b5, 1}, + {0x1d4d0, 0x1d4e9, 1}, + {0x1d504, 0x1d505, 1}, + {0x1d507, 0x1d50a, 1}, + {0x1d50d, 0x1d514, 1}, + {0x1d516, 0x1d51c, 1}, + {0x1d538, 0x1d539, 1}, + {0x1d53b, 0x1d53e, 1}, + {0x1d540, 0x1d544, 1}, + {0x1d546, 0x1d54a, 4}, + {0x1d54b, 0x1d550, 1}, + {0x1d56c, 0x1d585, 1}, + {0x1d5a0, 0x1d5b9, 1}, + {0x1d5d4, 0x1d5ed, 1}, + {0x1d608, 0x1d621, 1}, + {0x1d63c, 0x1d655, 1}, + {0x1d670, 0x1d689, 1}, + {0x1d6a8, 0x1d6c0, 1}, + {0x1d6e2, 0x1d6fa, 1}, + {0x1d71c, 0x1d734, 1}, + {0x1d756, 0x1d76e, 1}, + {0x1d790, 0x1d7a8, 1}, + {0x1d7ca, 0x1e900, 4406}, + {0x1e901, 0x1e921, 1}, + ], + LatinOffset: 3, } static _M = &RangeTable{ - R16: [ - {0x0300, 0x036f, 1}, - {0x0483, 0x0489, 1}, - {0x0591, 0x05bd, 1}, - {0x05bf, 0x05c1, 2}, - {0x05c2, 0x05c4, 2}, - {0x05c5, 0x05c7, 2}, - {0x0610, 0x061a, 1}, - {0x064b, 0x065f, 1}, - {0x0670, 0x06d6, 102}, - {0x06d7, 0x06dc, 1}, - {0x06df, 0x06e4, 1}, - {0x06e7, 0x06e8, 1}, - {0x06ea, 0x06ed, 1}, - {0x0711, 0x0730, 31}, - {0x0731, 0x074a, 1}, - {0x07a6, 0x07b0, 1}, - {0x07eb, 0x07f3, 1}, - {0x07fd, 0x0816, 25}, - {0x0817, 0x0819, 1}, - {0x081b, 0x0823, 1}, - {0x0825, 0x0827, 1}, - {0x0829, 0x082d, 1}, - {0x0859, 0x085b, 1}, - {0x0898, 0x089f, 1}, - {0x08ca, 0x08e1, 1}, - {0x08e3, 0x0903, 1}, - {0x093a, 0x093c, 1}, - {0x093e, 0x094f, 1}, - {0x0951, 0x0957, 1}, - {0x0962, 0x0963, 1}, - {0x0981, 0x0983, 1}, - {0x09bc, 0x09be, 2}, - {0x09bf, 0x09c4, 1}, - {0x09c7, 0x09c8, 1}, - {0x09cb, 0x09cd, 1}, - {0x09d7, 0x09e2, 11}, - {0x09e3, 0x09fe, 27}, - {0x0a01, 0x0a03, 1}, - {0x0a3c, 0x0a3e, 2}, - {0x0a3f, 0x0a42, 1}, - {0x0a47, 0x0a48, 1}, - {0x0a4b, 0x0a4d, 1}, - {0x0a51, 0x0a70, 31}, - {0x0a71, 0x0a75, 4}, - {0x0a81, 0x0a83, 1}, - {0x0abc, 0x0abe, 2}, - {0x0abf, 0x0ac5, 1}, - {0x0ac7, 0x0ac9, 1}, - {0x0acb, 0x0acd, 1}, - {0x0ae2, 0x0ae3, 1}, - {0x0afa, 0x0aff, 1}, - {0x0b01, 0x0b03, 1}, - {0x0b3c, 0x0b3e, 2}, - {0x0b3f, 0x0b44, 1}, - {0x0b47, 0x0b48, 1}, - {0x0b4b, 0x0b4d, 1}, - {0x0b55, 0x0b57, 1}, - {0x0b62, 0x0b63, 1}, - {0x0b82, 0x0bbe, 60}, - {0x0bbf, 0x0bc2, 1}, - {0x0bc6, 0x0bc8, 1}, - {0x0bca, 0x0bcd, 1}, - {0x0bd7, 0x0c00, 41}, - {0x0c01, 0x0c04, 1}, - {0x0c3c, 0x0c3e, 2}, - {0x0c3f, 0x0c44, 1}, - {0x0c46, 0x0c48, 1}, - {0x0c4a, 0x0c4d, 1}, - {0x0c55, 0x0c56, 1}, - {0x0c62, 0x0c63, 1}, - {0x0c81, 0x0c83, 1}, - {0x0cbc, 0x0cbe, 2}, - {0x0cbf, 0x0cc4, 1}, - {0x0cc6, 0x0cc8, 1}, - {0x0cca, 0x0ccd, 1}, - {0x0cd5, 0x0cd6, 1}, - {0x0ce2, 0x0ce3, 1}, - {0x0cf3, 0x0d00, 13}, - {0x0d01, 0x0d03, 1}, - {0x0d3b, 0x0d3c, 1}, - {0x0d3e, 0x0d44, 1}, - {0x0d46, 0x0d48, 1}, - {0x0d4a, 0x0d4d, 1}, - {0x0d57, 0x0d62, 11}, - {0x0d63, 0x0d81, 30}, - {0x0d82, 0x0d83, 1}, - {0x0dca, 0x0dcf, 5}, - {0x0dd0, 0x0dd4, 1}, - {0x0dd6, 0x0dd8, 2}, - {0x0dd9, 0x0ddf, 1}, - {0x0df2, 0x0df3, 1}, - {0x0e31, 0x0e34, 3}, - {0x0e35, 0x0e3a, 1}, - {0x0e47, 0x0e4e, 1}, - {0x0eb1, 0x0eb4, 3}, - {0x0eb5, 0x0ebc, 1}, - {0x0ec8, 0x0ece, 1}, - {0x0f18, 0x0f19, 1}, - {0x0f35, 0x0f39, 2}, - {0x0f3e, 0x0f3f, 1}, - {0x0f71, 0x0f84, 1}, - {0x0f86, 0x0f87, 1}, - {0x0f8d, 0x0f97, 1}, - {0x0f99, 0x0fbc, 1}, - {0x0fc6, 0x102b, 101}, - {0x102c, 0x103e, 1}, - {0x1056, 0x1059, 1}, - {0x105e, 0x1060, 1}, - {0x1062, 0x1064, 1}, - {0x1067, 0x106d, 1}, - {0x1071, 0x1074, 1}, - {0x1082, 0x108d, 1}, - {0x108f, 0x109a, 11}, - {0x109b, 0x109d, 1}, - {0x135d, 0x135f, 1}, - {0x1712, 0x1715, 1}, - {0x1732, 0x1734, 1}, - {0x1752, 0x1753, 1}, - {0x1772, 0x1773, 1}, - {0x17b4, 0x17d3, 1}, - {0x17dd, 0x180b, 46}, - {0x180c, 0x180d, 1}, - {0x180f, 0x1885, 118}, - {0x1886, 0x18a9, 35}, - {0x1920, 0x192b, 1}, - {0x1930, 0x193b, 1}, - {0x1a17, 0x1a1b, 1}, - {0x1a55, 0x1a5e, 1}, - {0x1a60, 0x1a7c, 1}, - {0x1a7f, 0x1ab0, 49}, - {0x1ab1, 0x1ace, 1}, - {0x1b00, 0x1b04, 1}, - {0x1b34, 0x1b44, 1}, - {0x1b6b, 0x1b73, 1}, - {0x1b80, 0x1b82, 1}, - {0x1ba1, 0x1bad, 1}, - {0x1be6, 0x1bf3, 1}, - {0x1c24, 0x1c37, 1}, - {0x1cd0, 0x1cd2, 1}, - {0x1cd4, 0x1ce8, 1}, - {0x1ced, 0x1cf4, 7}, - {0x1cf7, 0x1cf9, 1}, - {0x1dc0, 0x1dff, 1}, - {0x20d0, 0x20f0, 1}, - {0x2cef, 0x2cf1, 1}, - {0x2d7f, 0x2de0, 97}, - {0x2de1, 0x2dff, 1}, - {0x302a, 0x302f, 1}, - {0x3099, 0x309a, 1}, - {0xa66f, 0xa672, 1}, - {0xa674, 0xa67d, 1}, - {0xa69e, 0xa69f, 1}, - {0xa6f0, 0xa6f1, 1}, - {0xa802, 0xa806, 4}, - {0xa80b, 0xa823, 24}, - {0xa824, 0xa827, 1}, - {0xa82c, 0xa880, 84}, - {0xa881, 0xa8b4, 51}, - {0xa8b5, 0xa8c5, 1}, - {0xa8e0, 0xa8f1, 1}, - {0xa8ff, 0xa926, 39}, - {0xa927, 0xa92d, 1}, - {0xa947, 0xa953, 1}, - {0xa980, 0xa983, 1}, - {0xa9b3, 0xa9c0, 1}, - {0xa9e5, 0xaa29, 68}, - {0xaa2a, 0xaa36, 1}, - {0xaa43, 0xaa4c, 9}, - {0xaa4d, 0xaa7b, 46}, - {0xaa7c, 0xaa7d, 1}, - {0xaab0, 0xaab2, 2}, - {0xaab3, 0xaab4, 1}, - {0xaab7, 0xaab8, 1}, - {0xaabe, 0xaabf, 1}, - {0xaac1, 0xaaeb, 42}, - {0xaaec, 0xaaef, 1}, - {0xaaf5, 0xaaf6, 1}, - {0xabe3, 0xabea, 1}, - {0xabec, 0xabed, 1}, - {0xfb1e, 0xfe00, 738}, - {0xfe01, 0xfe0f, 1}, - {0xfe20, 0xfe2f, 1}, - ], - R32: [ - {0x101fd, 0x102e0, 227}, - {0x10376, 0x1037a, 1}, - {0x10a01, 0x10a03, 1}, - {0x10a05, 0x10a06, 1}, - {0x10a0c, 0x10a0f, 1}, - {0x10a38, 0x10a3a, 1}, - {0x10a3f, 0x10ae5, 166}, - {0x10ae6, 0x10d24, 574}, - {0x10d25, 0x10d27, 1}, - {0x10eab, 0x10eac, 1}, - {0x10efd, 0x10eff, 1}, - {0x10f46, 0x10f50, 1}, - {0x10f82, 0x10f85, 1}, - {0x11000, 0x11002, 1}, - {0x11038, 0x11046, 1}, - {0x11070, 0x11073, 3}, - {0x11074, 0x1107f, 11}, - {0x11080, 0x11082, 1}, - {0x110b0, 0x110ba, 1}, - {0x110c2, 0x11100, 62}, - {0x11101, 0x11102, 1}, - {0x11127, 0x11134, 1}, - {0x11145, 0x11146, 1}, - {0x11173, 0x11180, 13}, - {0x11181, 0x11182, 1}, - {0x111b3, 0x111c0, 1}, - {0x111c9, 0x111cc, 1}, - {0x111ce, 0x111cf, 1}, - {0x1122c, 0x11237, 1}, - {0x1123e, 0x11241, 3}, - {0x112df, 0x112ea, 1}, - {0x11300, 0x11303, 1}, - {0x1133b, 0x1133c, 1}, - {0x1133e, 0x11344, 1}, - {0x11347, 0x11348, 1}, - {0x1134b, 0x1134d, 1}, - {0x11357, 0x11362, 11}, - {0x11363, 0x11366, 3}, - {0x11367, 0x1136c, 1}, - {0x11370, 0x11374, 1}, - {0x11435, 0x11446, 1}, - {0x1145e, 0x114b0, 82}, - {0x114b1, 0x114c3, 1}, - {0x115af, 0x115b5, 1}, - {0x115b8, 0x115c0, 1}, - {0x115dc, 0x115dd, 1}, - {0x11630, 0x11640, 1}, - {0x116ab, 0x116b7, 1}, - {0x1171d, 0x1172b, 1}, - {0x1182c, 0x1183a, 1}, - {0x11930, 0x11935, 1}, - {0x11937, 0x11938, 1}, - {0x1193b, 0x1193e, 1}, - {0x11940, 0x11942, 2}, - {0x11943, 0x119d1, 142}, - {0x119d2, 0x119d7, 1}, - {0x119da, 0x119e0, 1}, - {0x119e4, 0x11a01, 29}, - {0x11a02, 0x11a0a, 1}, - {0x11a33, 0x11a39, 1}, - {0x11a3b, 0x11a3e, 1}, - {0x11a47, 0x11a51, 10}, - {0x11a52, 0x11a5b, 1}, - {0x11a8a, 0x11a99, 1}, - {0x11c2f, 0x11c36, 1}, - {0x11c38, 0x11c3f, 1}, - {0x11c92, 0x11ca7, 1}, - {0x11ca9, 0x11cb6, 1}, - {0x11d31, 0x11d36, 1}, - {0x11d3a, 0x11d3c, 2}, - {0x11d3d, 0x11d3f, 2}, - {0x11d40, 0x11d45, 1}, - {0x11d47, 0x11d8a, 67}, - {0x11d8b, 0x11d8e, 1}, - {0x11d90, 0x11d91, 1}, - {0x11d93, 0x11d97, 1}, - {0x11ef3, 0x11ef6, 1}, - {0x11f00, 0x11f01, 1}, - {0x11f03, 0x11f34, 49}, - {0x11f35, 0x11f3a, 1}, - {0x11f3e, 0x11f42, 1}, - {0x13440, 0x13447, 7}, - {0x13448, 0x13455, 1}, - {0x16af0, 0x16af4, 1}, - {0x16b30, 0x16b36, 1}, - {0x16f4f, 0x16f51, 2}, - {0x16f52, 0x16f87, 1}, - {0x16f8f, 0x16f92, 1}, - {0x16fe4, 0x16ff0, 12}, - {0x16ff1, 0x1bc9d, 19628}, - {0x1bc9e, 0x1cf00, 4706}, - {0x1cf01, 0x1cf2d, 1}, - {0x1cf30, 0x1cf46, 1}, - {0x1d165, 0x1d169, 1}, - {0x1d16d, 0x1d172, 1}, - {0x1d17b, 0x1d182, 1}, - {0x1d185, 0x1d18b, 1}, - {0x1d1aa, 0x1d1ad, 1}, - {0x1d242, 0x1d244, 1}, - {0x1da00, 0x1da36, 1}, - {0x1da3b, 0x1da6c, 1}, - {0x1da75, 0x1da84, 15}, - {0x1da9b, 0x1da9f, 1}, - {0x1daa1, 0x1daaf, 1}, - {0x1e000, 0x1e006, 1}, - {0x1e008, 0x1e018, 1}, - {0x1e01b, 0x1e021, 1}, - {0x1e023, 0x1e024, 1}, - {0x1e026, 0x1e02a, 1}, - {0x1e08f, 0x1e130, 161}, - {0x1e131, 0x1e136, 1}, - {0x1e2ae, 0x1e2ec, 62}, - {0x1e2ed, 0x1e2ef, 1}, - {0x1e4ec, 0x1e4ef, 1}, - {0x1e8d0, 0x1e8d6, 1}, - {0x1e944, 0x1e94a, 1}, - {0xe0100, 0xe01ef, 1}, - ], + R16: [ + {0x0300, 0x036f, 1}, + {0x0483, 0x0489, 1}, + {0x0591, 0x05bd, 1}, + {0x05bf, 0x05c1, 2}, + {0x05c2, 0x05c4, 2}, + {0x05c5, 0x05c7, 2}, + {0x0610, 0x061a, 1}, + {0x064b, 0x065f, 1}, + {0x0670, 0x06d6, 102}, + {0x06d7, 0x06dc, 1}, + {0x06df, 0x06e4, 1}, + {0x06e7, 0x06e8, 1}, + {0x06ea, 0x06ed, 1}, + {0x0711, 0x0730, 31}, + {0x0731, 0x074a, 1}, + {0x07a6, 0x07b0, 1}, + {0x07eb, 0x07f3, 1}, + {0x07fd, 0x0816, 25}, + {0x0817, 0x0819, 1}, + {0x081b, 0x0823, 1}, + {0x0825, 0x0827, 1}, + {0x0829, 0x082d, 1}, + {0x0859, 0x085b, 1}, + {0x0898, 0x089f, 1}, + {0x08ca, 0x08e1, 1}, + {0x08e3, 0x0903, 1}, + {0x093a, 0x093c, 1}, + {0x093e, 0x094f, 1}, + {0x0951, 0x0957, 1}, + {0x0962, 0x0963, 1}, + {0x0981, 0x0983, 1}, + {0x09bc, 0x09be, 2}, + {0x09bf, 0x09c4, 1}, + {0x09c7, 0x09c8, 1}, + {0x09cb, 0x09cd, 1}, + {0x09d7, 0x09e2, 11}, + {0x09e3, 0x09fe, 27}, + {0x0a01, 0x0a03, 1}, + {0x0a3c, 0x0a3e, 2}, + {0x0a3f, 0x0a42, 1}, + {0x0a47, 0x0a48, 1}, + {0x0a4b, 0x0a4d, 1}, + {0x0a51, 0x0a70, 31}, + {0x0a71, 0x0a75, 4}, + {0x0a81, 0x0a83, 1}, + {0x0abc, 0x0abe, 2}, + {0x0abf, 0x0ac5, 1}, + {0x0ac7, 0x0ac9, 1}, + {0x0acb, 0x0acd, 1}, + {0x0ae2, 0x0ae3, 1}, + {0x0afa, 0x0aff, 1}, + {0x0b01, 0x0b03, 1}, + {0x0b3c, 0x0b3e, 2}, + {0x0b3f, 0x0b44, 1}, + {0x0b47, 0x0b48, 1}, + {0x0b4b, 0x0b4d, 1}, + {0x0b55, 0x0b57, 1}, + {0x0b62, 0x0b63, 1}, + {0x0b82, 0x0bbe, 60}, + {0x0bbf, 0x0bc2, 1}, + {0x0bc6, 0x0bc8, 1}, + {0x0bca, 0x0bcd, 1}, + {0x0bd7, 0x0c00, 41}, + {0x0c01, 0x0c04, 1}, + {0x0c3c, 0x0c3e, 2}, + {0x0c3f, 0x0c44, 1}, + {0x0c46, 0x0c48, 1}, + {0x0c4a, 0x0c4d, 1}, + {0x0c55, 0x0c56, 1}, + {0x0c62, 0x0c63, 1}, + {0x0c81, 0x0c83, 1}, + {0x0cbc, 0x0cbe, 2}, + {0x0cbf, 0x0cc4, 1}, + {0x0cc6, 0x0cc8, 1}, + {0x0cca, 0x0ccd, 1}, + {0x0cd5, 0x0cd6, 1}, + {0x0ce2, 0x0ce3, 1}, + {0x0cf3, 0x0d00, 13}, + {0x0d01, 0x0d03, 1}, + {0x0d3b, 0x0d3c, 1}, + {0x0d3e, 0x0d44, 1}, + {0x0d46, 0x0d48, 1}, + {0x0d4a, 0x0d4d, 1}, + {0x0d57, 0x0d62, 11}, + {0x0d63, 0x0d81, 30}, + {0x0d82, 0x0d83, 1}, + {0x0dca, 0x0dcf, 5}, + {0x0dd0, 0x0dd4, 1}, + {0x0dd6, 0x0dd8, 2}, + {0x0dd9, 0x0ddf, 1}, + {0x0df2, 0x0df3, 1}, + {0x0e31, 0x0e34, 3}, + {0x0e35, 0x0e3a, 1}, + {0x0e47, 0x0e4e, 1}, + {0x0eb1, 0x0eb4, 3}, + {0x0eb5, 0x0ebc, 1}, + {0x0ec8, 0x0ece, 1}, + {0x0f18, 0x0f19, 1}, + {0x0f35, 0x0f39, 2}, + {0x0f3e, 0x0f3f, 1}, + {0x0f71, 0x0f84, 1}, + {0x0f86, 0x0f87, 1}, + {0x0f8d, 0x0f97, 1}, + {0x0f99, 0x0fbc, 1}, + {0x0fc6, 0x102b, 101}, + {0x102c, 0x103e, 1}, + {0x1056, 0x1059, 1}, + {0x105e, 0x1060, 1}, + {0x1062, 0x1064, 1}, + {0x1067, 0x106d, 1}, + {0x1071, 0x1074, 1}, + {0x1082, 0x108d, 1}, + {0x108f, 0x109a, 11}, + {0x109b, 0x109d, 1}, + {0x135d, 0x135f, 1}, + {0x1712, 0x1715, 1}, + {0x1732, 0x1734, 1}, + {0x1752, 0x1753, 1}, + {0x1772, 0x1773, 1}, + {0x17b4, 0x17d3, 1}, + {0x17dd, 0x180b, 46}, + {0x180c, 0x180d, 1}, + {0x180f, 0x1885, 118}, + {0x1886, 0x18a9, 35}, + {0x1920, 0x192b, 1}, + {0x1930, 0x193b, 1}, + {0x1a17, 0x1a1b, 1}, + {0x1a55, 0x1a5e, 1}, + {0x1a60, 0x1a7c, 1}, + {0x1a7f, 0x1ab0, 49}, + {0x1ab1, 0x1ace, 1}, + {0x1b00, 0x1b04, 1}, + {0x1b34, 0x1b44, 1}, + {0x1b6b, 0x1b73, 1}, + {0x1b80, 0x1b82, 1}, + {0x1ba1, 0x1bad, 1}, + {0x1be6, 0x1bf3, 1}, + {0x1c24, 0x1c37, 1}, + {0x1cd0, 0x1cd2, 1}, + {0x1cd4, 0x1ce8, 1}, + {0x1ced, 0x1cf4, 7}, + {0x1cf7, 0x1cf9, 1}, + {0x1dc0, 0x1dff, 1}, + {0x20d0, 0x20f0, 1}, + {0x2cef, 0x2cf1, 1}, + {0x2d7f, 0x2de0, 97}, + {0x2de1, 0x2dff, 1}, + {0x302a, 0x302f, 1}, + {0x3099, 0x309a, 1}, + {0xa66f, 0xa672, 1}, + {0xa674, 0xa67d, 1}, + {0xa69e, 0xa69f, 1}, + {0xa6f0, 0xa6f1, 1}, + {0xa802, 0xa806, 4}, + {0xa80b, 0xa823, 24}, + {0xa824, 0xa827, 1}, + {0xa82c, 0xa880, 84}, + {0xa881, 0xa8b4, 51}, + {0xa8b5, 0xa8c5, 1}, + {0xa8e0, 0xa8f1, 1}, + {0xa8ff, 0xa926, 39}, + {0xa927, 0xa92d, 1}, + {0xa947, 0xa953, 1}, + {0xa980, 0xa983, 1}, + {0xa9b3, 0xa9c0, 1}, + {0xa9e5, 0xaa29, 68}, + {0xaa2a, 0xaa36, 1}, + {0xaa43, 0xaa4c, 9}, + {0xaa4d, 0xaa7b, 46}, + {0xaa7c, 0xaa7d, 1}, + {0xaab0, 0xaab2, 2}, + {0xaab3, 0xaab4, 1}, + {0xaab7, 0xaab8, 1}, + {0xaabe, 0xaabf, 1}, + {0xaac1, 0xaaeb, 42}, + {0xaaec, 0xaaef, 1}, + {0xaaf5, 0xaaf6, 1}, + {0xabe3, 0xabea, 1}, + {0xabec, 0xabed, 1}, + {0xfb1e, 0xfe00, 738}, + {0xfe01, 0xfe0f, 1}, + {0xfe20, 0xfe2f, 1}, + ], + R32: [ + {0x101fd, 0x102e0, 227}, + {0x10376, 0x1037a, 1}, + {0x10a01, 0x10a03, 1}, + {0x10a05, 0x10a06, 1}, + {0x10a0c, 0x10a0f, 1}, + {0x10a38, 0x10a3a, 1}, + {0x10a3f, 0x10ae5, 166}, + {0x10ae6, 0x10d24, 574}, + {0x10d25, 0x10d27, 1}, + {0x10eab, 0x10eac, 1}, + {0x10efd, 0x10eff, 1}, + {0x10f46, 0x10f50, 1}, + {0x10f82, 0x10f85, 1}, + {0x11000, 0x11002, 1}, + {0x11038, 0x11046, 1}, + {0x11070, 0x11073, 3}, + {0x11074, 0x1107f, 11}, + {0x11080, 0x11082, 1}, + {0x110b0, 0x110ba, 1}, + {0x110c2, 0x11100, 62}, + {0x11101, 0x11102, 1}, + {0x11127, 0x11134, 1}, + {0x11145, 0x11146, 1}, + {0x11173, 0x11180, 13}, + {0x11181, 0x11182, 1}, + {0x111b3, 0x111c0, 1}, + {0x111c9, 0x111cc, 1}, + {0x111ce, 0x111cf, 1}, + {0x1122c, 0x11237, 1}, + {0x1123e, 0x11241, 3}, + {0x112df, 0x112ea, 1}, + {0x11300, 0x11303, 1}, + {0x1133b, 0x1133c, 1}, + {0x1133e, 0x11344, 1}, + {0x11347, 0x11348, 1}, + {0x1134b, 0x1134d, 1}, + {0x11357, 0x11362, 11}, + {0x11363, 0x11366, 3}, + {0x11367, 0x1136c, 1}, + {0x11370, 0x11374, 1}, + {0x11435, 0x11446, 1}, + {0x1145e, 0x114b0, 82}, + {0x114b1, 0x114c3, 1}, + {0x115af, 0x115b5, 1}, + {0x115b8, 0x115c0, 1}, + {0x115dc, 0x115dd, 1}, + {0x11630, 0x11640, 1}, + {0x116ab, 0x116b7, 1}, + {0x1171d, 0x1172b, 1}, + {0x1182c, 0x1183a, 1}, + {0x11930, 0x11935, 1}, + {0x11937, 0x11938, 1}, + {0x1193b, 0x1193e, 1}, + {0x11940, 0x11942, 2}, + {0x11943, 0x119d1, 142}, + {0x119d2, 0x119d7, 1}, + {0x119da, 0x119e0, 1}, + {0x119e4, 0x11a01, 29}, + {0x11a02, 0x11a0a, 1}, + {0x11a33, 0x11a39, 1}, + {0x11a3b, 0x11a3e, 1}, + {0x11a47, 0x11a51, 10}, + {0x11a52, 0x11a5b, 1}, + {0x11a8a, 0x11a99, 1}, + {0x11c2f, 0x11c36, 1}, + {0x11c38, 0x11c3f, 1}, + {0x11c92, 0x11ca7, 1}, + {0x11ca9, 0x11cb6, 1}, + {0x11d31, 0x11d36, 1}, + {0x11d3a, 0x11d3c, 2}, + {0x11d3d, 0x11d3f, 2}, + {0x11d40, 0x11d45, 1}, + {0x11d47, 0x11d8a, 67}, + {0x11d8b, 0x11d8e, 1}, + {0x11d90, 0x11d91, 1}, + {0x11d93, 0x11d97, 1}, + {0x11ef3, 0x11ef6, 1}, + {0x11f00, 0x11f01, 1}, + {0x11f03, 0x11f34, 49}, + {0x11f35, 0x11f3a, 1}, + {0x11f3e, 0x11f42, 1}, + {0x13440, 0x13447, 7}, + {0x13448, 0x13455, 1}, + {0x16af0, 0x16af4, 1}, + {0x16b30, 0x16b36, 1}, + {0x16f4f, 0x16f51, 2}, + {0x16f52, 0x16f87, 1}, + {0x16f8f, 0x16f92, 1}, + {0x16fe4, 0x16ff0, 12}, + {0x16ff1, 0x1bc9d, 19628}, + {0x1bc9e, 0x1cf00, 4706}, + {0x1cf01, 0x1cf2d, 1}, + {0x1cf30, 0x1cf46, 1}, + {0x1d165, 0x1d169, 1}, + {0x1d16d, 0x1d172, 1}, + {0x1d17b, 0x1d182, 1}, + {0x1d185, 0x1d18b, 1}, + {0x1d1aa, 0x1d1ad, 1}, + {0x1d242, 0x1d244, 1}, + {0x1da00, 0x1da36, 1}, + {0x1da3b, 0x1da6c, 1}, + {0x1da75, 0x1da84, 15}, + {0x1da9b, 0x1da9f, 1}, + {0x1daa1, 0x1daaf, 1}, + {0x1e000, 0x1e006, 1}, + {0x1e008, 0x1e018, 1}, + {0x1e01b, 0x1e021, 1}, + {0x1e023, 0x1e024, 1}, + {0x1e026, 0x1e02a, 1}, + {0x1e08f, 0x1e130, 161}, + {0x1e131, 0x1e136, 1}, + {0x1e2ae, 0x1e2ec, 62}, + {0x1e2ed, 0x1e2ef, 1}, + {0x1e4ec, 0x1e4ef, 1}, + {0x1e8d0, 0x1e8d6, 1}, + {0x1e944, 0x1e94a, 1}, + {0xe0100, 0xe01ef, 1}, + ], } static _MC = &RangeTable{ - R16: [ - {0x0903, 0x093b, 56}, - {0x093e, 0x0940, 1}, - {0x0949, 0x094c, 1}, - {0x094e, 0x094f, 1}, - {0x0982, 0x0983, 1}, - {0x09be, 0x09c0, 1}, - {0x09c7, 0x09c8, 1}, - {0x09cb, 0x09cc, 1}, - {0x09d7, 0x0a03, 44}, - {0x0a3e, 0x0a40, 1}, - {0x0a83, 0x0abe, 59}, - {0x0abf, 0x0ac0, 1}, - {0x0ac9, 0x0acb, 2}, - {0x0acc, 0x0b02, 54}, - {0x0b03, 0x0b3e, 59}, - {0x0b40, 0x0b47, 7}, - {0x0b48, 0x0b4b, 3}, - {0x0b4c, 0x0b57, 11}, - {0x0bbe, 0x0bbf, 1}, - {0x0bc1, 0x0bc2, 1}, - {0x0bc6, 0x0bc8, 1}, - {0x0bca, 0x0bcc, 1}, - {0x0bd7, 0x0c01, 42}, - {0x0c02, 0x0c03, 1}, - {0x0c41, 0x0c44, 1}, - {0x0c82, 0x0c83, 1}, - {0x0cbe, 0x0cc0, 2}, - {0x0cc1, 0x0cc4, 1}, - {0x0cc7, 0x0cc8, 1}, - {0x0cca, 0x0ccb, 1}, - {0x0cd5, 0x0cd6, 1}, - {0x0cf3, 0x0d02, 15}, - {0x0d03, 0x0d3e, 59}, - {0x0d3f, 0x0d40, 1}, - {0x0d46, 0x0d48, 1}, - {0x0d4a, 0x0d4c, 1}, - {0x0d57, 0x0d82, 43}, - {0x0d83, 0x0dcf, 76}, - {0x0dd0, 0x0dd1, 1}, - {0x0dd8, 0x0ddf, 1}, - {0x0df2, 0x0df3, 1}, - {0x0f3e, 0x0f3f, 1}, - {0x0f7f, 0x102b, 172}, - {0x102c, 0x1031, 5}, - {0x1038, 0x103b, 3}, - {0x103c, 0x1056, 26}, - {0x1057, 0x1062, 11}, - {0x1063, 0x1064, 1}, - {0x1067, 0x106d, 1}, - {0x1083, 0x1084, 1}, - {0x1087, 0x108c, 1}, - {0x108f, 0x109a, 11}, - {0x109b, 0x109c, 1}, - {0x1715, 0x1734, 31}, - {0x17b6, 0x17be, 8}, - {0x17bf, 0x17c5, 1}, - {0x17c7, 0x17c8, 1}, - {0x1923, 0x1926, 1}, - {0x1929, 0x192b, 1}, - {0x1930, 0x1931, 1}, - {0x1933, 0x1938, 1}, - {0x1a19, 0x1a1a, 1}, - {0x1a55, 0x1a57, 2}, - {0x1a61, 0x1a63, 2}, - {0x1a64, 0x1a6d, 9}, - {0x1a6e, 0x1a72, 1}, - {0x1b04, 0x1b35, 49}, - {0x1b3b, 0x1b3d, 2}, - {0x1b3e, 0x1b41, 1}, - {0x1b43, 0x1b44, 1}, - {0x1b82, 0x1ba1, 31}, - {0x1ba6, 0x1ba7, 1}, - {0x1baa, 0x1be7, 61}, - {0x1bea, 0x1bec, 1}, - {0x1bee, 0x1bf2, 4}, - {0x1bf3, 0x1c24, 49}, - {0x1c25, 0x1c2b, 1}, - {0x1c34, 0x1c35, 1}, - {0x1ce1, 0x1cf7, 22}, - {0x302e, 0x302f, 1}, - {0xa823, 0xa824, 1}, - {0xa827, 0xa880, 89}, - {0xa881, 0xa8b4, 51}, - {0xa8b5, 0xa8c3, 1}, - {0xa952, 0xa953, 1}, - {0xa983, 0xa9b4, 49}, - {0xa9b5, 0xa9ba, 5}, - {0xa9bb, 0xa9be, 3}, - {0xa9bf, 0xa9c0, 1}, - {0xaa2f, 0xaa30, 1}, - {0xaa33, 0xaa34, 1}, - {0xaa4d, 0xaa7b, 46}, - {0xaa7d, 0xaaeb, 110}, - {0xaaee, 0xaaef, 1}, - {0xaaf5, 0xabe3, 238}, - {0xabe4, 0xabe6, 2}, - {0xabe7, 0xabe9, 2}, - {0xabea, 0xabec, 2}, - ], - R32: [ - {0x11000, 0x11002, 2}, - {0x11082, 0x110b0, 46}, - {0x110b1, 0x110b2, 1}, - {0x110b7, 0x110b8, 1}, - {0x1112c, 0x11145, 25}, - {0x11146, 0x11182, 60}, - {0x111b3, 0x111b5, 1}, - {0x111bf, 0x111c0, 1}, - {0x111ce, 0x1122c, 94}, - {0x1122d, 0x1122e, 1}, - {0x11232, 0x11233, 1}, - {0x11235, 0x112e0, 171}, - {0x112e1, 0x112e2, 1}, - {0x11302, 0x11303, 1}, - {0x1133e, 0x1133f, 1}, - {0x11341, 0x11344, 1}, - {0x11347, 0x11348, 1}, - {0x1134b, 0x1134d, 1}, - {0x11357, 0x11362, 11}, - {0x11363, 0x11435, 210}, - {0x11436, 0x11437, 1}, - {0x11440, 0x11441, 1}, - {0x11445, 0x114b0, 107}, - {0x114b1, 0x114b2, 1}, - {0x114b9, 0x114bb, 2}, - {0x114bc, 0x114be, 1}, - {0x114c1, 0x115af, 238}, - {0x115b0, 0x115b1, 1}, - {0x115b8, 0x115bb, 1}, - {0x115be, 0x11630, 114}, - {0x11631, 0x11632, 1}, - {0x1163b, 0x1163c, 1}, - {0x1163e, 0x116ac, 110}, - {0x116ae, 0x116af, 1}, - {0x116b6, 0x11720, 106}, - {0x11721, 0x11726, 5}, - {0x1182c, 0x1182e, 1}, - {0x11838, 0x11930, 248}, - {0x11931, 0x11935, 1}, - {0x11937, 0x11938, 1}, - {0x1193d, 0x11940, 3}, - {0x11942, 0x119d1, 143}, - {0x119d2, 0x119d3, 1}, - {0x119dc, 0x119df, 1}, - {0x119e4, 0x11a39, 85}, - {0x11a57, 0x11a58, 1}, - {0x11a97, 0x11c2f, 408}, - {0x11c3e, 0x11ca9, 107}, - {0x11cb1, 0x11cb4, 3}, - {0x11d8a, 0x11d8e, 1}, - {0x11d93, 0x11d94, 1}, - {0x11d96, 0x11ef5, 351}, - {0x11ef6, 0x11f03, 13}, - {0x11f34, 0x11f35, 1}, - {0x11f3e, 0x11f3f, 1}, - {0x11f41, 0x16f51, 20496}, - {0x16f52, 0x16f87, 1}, - {0x16ff0, 0x16ff1, 1}, - {0x1d165, 0x1d166, 1}, - {0x1d16d, 0x1d172, 1}, - ], + R16: [ + {0x0903, 0x093b, 56}, + {0x093e, 0x0940, 1}, + {0x0949, 0x094c, 1}, + {0x094e, 0x094f, 1}, + {0x0982, 0x0983, 1}, + {0x09be, 0x09c0, 1}, + {0x09c7, 0x09c8, 1}, + {0x09cb, 0x09cc, 1}, + {0x09d7, 0x0a03, 44}, + {0x0a3e, 0x0a40, 1}, + {0x0a83, 0x0abe, 59}, + {0x0abf, 0x0ac0, 1}, + {0x0ac9, 0x0acb, 2}, + {0x0acc, 0x0b02, 54}, + {0x0b03, 0x0b3e, 59}, + {0x0b40, 0x0b47, 7}, + {0x0b48, 0x0b4b, 3}, + {0x0b4c, 0x0b57, 11}, + {0x0bbe, 0x0bbf, 1}, + {0x0bc1, 0x0bc2, 1}, + {0x0bc6, 0x0bc8, 1}, + {0x0bca, 0x0bcc, 1}, + {0x0bd7, 0x0c01, 42}, + {0x0c02, 0x0c03, 1}, + {0x0c41, 0x0c44, 1}, + {0x0c82, 0x0c83, 1}, + {0x0cbe, 0x0cc0, 2}, + {0x0cc1, 0x0cc4, 1}, + {0x0cc7, 0x0cc8, 1}, + {0x0cca, 0x0ccb, 1}, + {0x0cd5, 0x0cd6, 1}, + {0x0cf3, 0x0d02, 15}, + {0x0d03, 0x0d3e, 59}, + {0x0d3f, 0x0d40, 1}, + {0x0d46, 0x0d48, 1}, + {0x0d4a, 0x0d4c, 1}, + {0x0d57, 0x0d82, 43}, + {0x0d83, 0x0dcf, 76}, + {0x0dd0, 0x0dd1, 1}, + {0x0dd8, 0x0ddf, 1}, + {0x0df2, 0x0df3, 1}, + {0x0f3e, 0x0f3f, 1}, + {0x0f7f, 0x102b, 172}, + {0x102c, 0x1031, 5}, + {0x1038, 0x103b, 3}, + {0x103c, 0x1056, 26}, + {0x1057, 0x1062, 11}, + {0x1063, 0x1064, 1}, + {0x1067, 0x106d, 1}, + {0x1083, 0x1084, 1}, + {0x1087, 0x108c, 1}, + {0x108f, 0x109a, 11}, + {0x109b, 0x109c, 1}, + {0x1715, 0x1734, 31}, + {0x17b6, 0x17be, 8}, + {0x17bf, 0x17c5, 1}, + {0x17c7, 0x17c8, 1}, + {0x1923, 0x1926, 1}, + {0x1929, 0x192b, 1}, + {0x1930, 0x1931, 1}, + {0x1933, 0x1938, 1}, + {0x1a19, 0x1a1a, 1}, + {0x1a55, 0x1a57, 2}, + {0x1a61, 0x1a63, 2}, + {0x1a64, 0x1a6d, 9}, + {0x1a6e, 0x1a72, 1}, + {0x1b04, 0x1b35, 49}, + {0x1b3b, 0x1b3d, 2}, + {0x1b3e, 0x1b41, 1}, + {0x1b43, 0x1b44, 1}, + {0x1b82, 0x1ba1, 31}, + {0x1ba6, 0x1ba7, 1}, + {0x1baa, 0x1be7, 61}, + {0x1bea, 0x1bec, 1}, + {0x1bee, 0x1bf2, 4}, + {0x1bf3, 0x1c24, 49}, + {0x1c25, 0x1c2b, 1}, + {0x1c34, 0x1c35, 1}, + {0x1ce1, 0x1cf7, 22}, + {0x302e, 0x302f, 1}, + {0xa823, 0xa824, 1}, + {0xa827, 0xa880, 89}, + {0xa881, 0xa8b4, 51}, + {0xa8b5, 0xa8c3, 1}, + {0xa952, 0xa953, 1}, + {0xa983, 0xa9b4, 49}, + {0xa9b5, 0xa9ba, 5}, + {0xa9bb, 0xa9be, 3}, + {0xa9bf, 0xa9c0, 1}, + {0xaa2f, 0xaa30, 1}, + {0xaa33, 0xaa34, 1}, + {0xaa4d, 0xaa7b, 46}, + {0xaa7d, 0xaaeb, 110}, + {0xaaee, 0xaaef, 1}, + {0xaaf5, 0xabe3, 238}, + {0xabe4, 0xabe6, 2}, + {0xabe7, 0xabe9, 2}, + {0xabea, 0xabec, 2}, + ], + R32: [ + {0x11000, 0x11002, 2}, + {0x11082, 0x110b0, 46}, + {0x110b1, 0x110b2, 1}, + {0x110b7, 0x110b8, 1}, + {0x1112c, 0x11145, 25}, + {0x11146, 0x11182, 60}, + {0x111b3, 0x111b5, 1}, + {0x111bf, 0x111c0, 1}, + {0x111ce, 0x1122c, 94}, + {0x1122d, 0x1122e, 1}, + {0x11232, 0x11233, 1}, + {0x11235, 0x112e0, 171}, + {0x112e1, 0x112e2, 1}, + {0x11302, 0x11303, 1}, + {0x1133e, 0x1133f, 1}, + {0x11341, 0x11344, 1}, + {0x11347, 0x11348, 1}, + {0x1134b, 0x1134d, 1}, + {0x11357, 0x11362, 11}, + {0x11363, 0x11435, 210}, + {0x11436, 0x11437, 1}, + {0x11440, 0x11441, 1}, + {0x11445, 0x114b0, 107}, + {0x114b1, 0x114b2, 1}, + {0x114b9, 0x114bb, 2}, + {0x114bc, 0x114be, 1}, + {0x114c1, 0x115af, 238}, + {0x115b0, 0x115b1, 1}, + {0x115b8, 0x115bb, 1}, + {0x115be, 0x11630, 114}, + {0x11631, 0x11632, 1}, + {0x1163b, 0x1163c, 1}, + {0x1163e, 0x116ac, 110}, + {0x116ae, 0x116af, 1}, + {0x116b6, 0x11720, 106}, + {0x11721, 0x11726, 5}, + {0x1182c, 0x1182e, 1}, + {0x11838, 0x11930, 248}, + {0x11931, 0x11935, 1}, + {0x11937, 0x11938, 1}, + {0x1193d, 0x11940, 3}, + {0x11942, 0x119d1, 143}, + {0x119d2, 0x119d3, 1}, + {0x119dc, 0x119df, 1}, + {0x119e4, 0x11a39, 85}, + {0x11a57, 0x11a58, 1}, + {0x11a97, 0x11c2f, 408}, + {0x11c3e, 0x11ca9, 107}, + {0x11cb1, 0x11cb4, 3}, + {0x11d8a, 0x11d8e, 1}, + {0x11d93, 0x11d94, 1}, + {0x11d96, 0x11ef5, 351}, + {0x11ef6, 0x11f03, 13}, + {0x11f34, 0x11f35, 1}, + {0x11f3e, 0x11f3f, 1}, + {0x11f41, 0x16f51, 20496}, + {0x16f52, 0x16f87, 1}, + {0x16ff0, 0x16ff1, 1}, + {0x1d165, 0x1d166, 1}, + {0x1d16d, 0x1d172, 1}, + ], } static _ME = &RangeTable{ - R16: [ - {0x0488, 0x0489, 1}, - {0x1abe, 0x20dd, 1567}, - {0x20de, 0x20e0, 1}, - {0x20e2, 0x20e4, 1}, - {0xa670, 0xa672, 1}, - ], + R16: [ + {0x0488, 0x0489, 1}, + {0x1abe, 0x20dd, 1567}, + {0x20de, 0x20e0, 1}, + {0x20e2, 0x20e4, 1}, + {0xa670, 0xa672, 1}, + ], } static _MN = &RangeTable{ - R16: [ - {0x0300, 0x036f, 1}, - {0x0483, 0x0487, 1}, - {0x0591, 0x05bd, 1}, - {0x05bf, 0x05c1, 2}, - {0x05c2, 0x05c4, 2}, - {0x05c5, 0x05c7, 2}, - {0x0610, 0x061a, 1}, - {0x064b, 0x065f, 1}, - {0x0670, 0x06d6, 102}, - {0x06d7, 0x06dc, 1}, - {0x06df, 0x06e4, 1}, - {0x06e7, 0x06e8, 1}, - {0x06ea, 0x06ed, 1}, - {0x0711, 0x0730, 31}, - {0x0731, 0x074a, 1}, - {0x07a6, 0x07b0, 1}, - {0x07eb, 0x07f3, 1}, - {0x07fd, 0x0816, 25}, - {0x0817, 0x0819, 1}, - {0x081b, 0x0823, 1}, - {0x0825, 0x0827, 1}, - {0x0829, 0x082d, 1}, - {0x0859, 0x085b, 1}, - {0x0898, 0x089f, 1}, - {0x08ca, 0x08e1, 1}, - {0x08e3, 0x0902, 1}, - {0x093a, 0x093c, 2}, - {0x0941, 0x0948, 1}, - {0x094d, 0x0951, 4}, - {0x0952, 0x0957, 1}, - {0x0962, 0x0963, 1}, - {0x0981, 0x09bc, 59}, - {0x09c1, 0x09c4, 1}, - {0x09cd, 0x09e2, 21}, - {0x09e3, 0x09fe, 27}, - {0x0a01, 0x0a02, 1}, - {0x0a3c, 0x0a41, 5}, - {0x0a42, 0x0a47, 5}, - {0x0a48, 0x0a4b, 3}, - {0x0a4c, 0x0a4d, 1}, - {0x0a51, 0x0a70, 31}, - {0x0a71, 0x0a75, 4}, - {0x0a81, 0x0a82, 1}, - {0x0abc, 0x0ac1, 5}, - {0x0ac2, 0x0ac5, 1}, - {0x0ac7, 0x0ac8, 1}, - {0x0acd, 0x0ae2, 21}, - {0x0ae3, 0x0afa, 23}, - {0x0afb, 0x0aff, 1}, - {0x0b01, 0x0b3c, 59}, - {0x0b3f, 0x0b41, 2}, - {0x0b42, 0x0b44, 1}, - {0x0b4d, 0x0b55, 8}, - {0x0b56, 0x0b62, 12}, - {0x0b63, 0x0b82, 31}, - {0x0bc0, 0x0bcd, 13}, - {0x0c00, 0x0c04, 4}, - {0x0c3c, 0x0c3e, 2}, - {0x0c3f, 0x0c40, 1}, - {0x0c46, 0x0c48, 1}, - {0x0c4a, 0x0c4d, 1}, - {0x0c55, 0x0c56, 1}, - {0x0c62, 0x0c63, 1}, - {0x0c81, 0x0cbc, 59}, - {0x0cbf, 0x0cc6, 7}, - {0x0ccc, 0x0ccd, 1}, - {0x0ce2, 0x0ce3, 1}, - {0x0d00, 0x0d01, 1}, - {0x0d3b, 0x0d3c, 1}, - {0x0d41, 0x0d44, 1}, - {0x0d4d, 0x0d62, 21}, - {0x0d63, 0x0d81, 30}, - {0x0dca, 0x0dd2, 8}, - {0x0dd3, 0x0dd4, 1}, - {0x0dd6, 0x0e31, 91}, - {0x0e34, 0x0e3a, 1}, - {0x0e47, 0x0e4e, 1}, - {0x0eb1, 0x0eb4, 3}, - {0x0eb5, 0x0ebc, 1}, - {0x0ec8, 0x0ece, 1}, - {0x0f18, 0x0f19, 1}, - {0x0f35, 0x0f39, 2}, - {0x0f71, 0x0f7e, 1}, - {0x0f80, 0x0f84, 1}, - {0x0f86, 0x0f87, 1}, - {0x0f8d, 0x0f97, 1}, - {0x0f99, 0x0fbc, 1}, - {0x0fc6, 0x102d, 103}, - {0x102e, 0x1030, 1}, - {0x1032, 0x1037, 1}, - {0x1039, 0x103a, 1}, - {0x103d, 0x103e, 1}, - {0x1058, 0x1059, 1}, - {0x105e, 0x1060, 1}, - {0x1071, 0x1074, 1}, - {0x1082, 0x1085, 3}, - {0x1086, 0x108d, 7}, - {0x109d, 0x135d, 704}, - {0x135e, 0x135f, 1}, - {0x1712, 0x1714, 1}, - {0x1732, 0x1733, 1}, - {0x1752, 0x1753, 1}, - {0x1772, 0x1773, 1}, - {0x17b4, 0x17b5, 1}, - {0x17b7, 0x17bd, 1}, - {0x17c6, 0x17c9, 3}, - {0x17ca, 0x17d3, 1}, - {0x17dd, 0x180b, 46}, - {0x180c, 0x180d, 1}, - {0x180f, 0x1885, 118}, - {0x1886, 0x18a9, 35}, - {0x1920, 0x1922, 1}, - {0x1927, 0x1928, 1}, - {0x1932, 0x1939, 7}, - {0x193a, 0x193b, 1}, - {0x1a17, 0x1a18, 1}, - {0x1a1b, 0x1a56, 59}, - {0x1a58, 0x1a5e, 1}, - {0x1a60, 0x1a62, 2}, - {0x1a65, 0x1a6c, 1}, - {0x1a73, 0x1a7c, 1}, - {0x1a7f, 0x1ab0, 49}, - {0x1ab1, 0x1abd, 1}, - {0x1abf, 0x1ace, 1}, - {0x1b00, 0x1b03, 1}, - {0x1b34, 0x1b36, 2}, - {0x1b37, 0x1b3a, 1}, - {0x1b3c, 0x1b42, 6}, - {0x1b6b, 0x1b73, 1}, - {0x1b80, 0x1b81, 1}, - {0x1ba2, 0x1ba5, 1}, - {0x1ba8, 0x1ba9, 1}, - {0x1bab, 0x1bad, 1}, - {0x1be6, 0x1be8, 2}, - {0x1be9, 0x1bed, 4}, - {0x1bef, 0x1bf1, 1}, - {0x1c2c, 0x1c33, 1}, - {0x1c36, 0x1c37, 1}, - {0x1cd0, 0x1cd2, 1}, - {0x1cd4, 0x1ce0, 1}, - {0x1ce2, 0x1ce8, 1}, - {0x1ced, 0x1cf4, 7}, - {0x1cf8, 0x1cf9, 1}, - {0x1dc0, 0x1dff, 1}, - {0x20d0, 0x20dc, 1}, - {0x20e1, 0x20e5, 4}, - {0x20e6, 0x20f0, 1}, - {0x2cef, 0x2cf1, 1}, - {0x2d7f, 0x2de0, 97}, - {0x2de1, 0x2dff, 1}, - {0x302a, 0x302d, 1}, - {0x3099, 0x309a, 1}, - {0xa66f, 0xa674, 5}, - {0xa675, 0xa67d, 1}, - {0xa69e, 0xa69f, 1}, - {0xa6f0, 0xa6f1, 1}, - {0xa802, 0xa806, 4}, - {0xa80b, 0xa825, 26}, - {0xa826, 0xa82c, 6}, - {0xa8c4, 0xa8c5, 1}, - {0xa8e0, 0xa8f1, 1}, - {0xa8ff, 0xa926, 39}, - {0xa927, 0xa92d, 1}, - {0xa947, 0xa951, 1}, - {0xa980, 0xa982, 1}, - {0xa9b3, 0xa9b6, 3}, - {0xa9b7, 0xa9b9, 1}, - {0xa9bc, 0xa9bd, 1}, - {0xa9e5, 0xaa29, 68}, - {0xaa2a, 0xaa2e, 1}, - {0xaa31, 0xaa32, 1}, - {0xaa35, 0xaa36, 1}, - {0xaa43, 0xaa4c, 9}, - {0xaa7c, 0xaab0, 52}, - {0xaab2, 0xaab4, 1}, - {0xaab7, 0xaab8, 1}, - {0xaabe, 0xaabf, 1}, - {0xaac1, 0xaaec, 43}, - {0xaaed, 0xaaf6, 9}, - {0xabe5, 0xabe8, 3}, - {0xabed, 0xfb1e, 20273}, - {0xfe00, 0xfe0f, 1}, - {0xfe20, 0xfe2f, 1}, - ], - R32: [ - {0x101fd, 0x102e0, 227}, - {0x10376, 0x1037a, 1}, - {0x10a01, 0x10a03, 1}, - {0x10a05, 0x10a06, 1}, - {0x10a0c, 0x10a0f, 1}, - {0x10a38, 0x10a3a, 1}, - {0x10a3f, 0x10ae5, 166}, - {0x10ae6, 0x10d24, 574}, - {0x10d25, 0x10d27, 1}, - {0x10eab, 0x10eac, 1}, - {0x10efd, 0x10eff, 1}, - {0x10f46, 0x10f50, 1}, - {0x10f82, 0x10f85, 1}, - {0x11001, 0x11038, 55}, - {0x11039, 0x11046, 1}, - {0x11070, 0x11073, 3}, - {0x11074, 0x1107f, 11}, - {0x11080, 0x11081, 1}, - {0x110b3, 0x110b6, 1}, - {0x110b9, 0x110ba, 1}, - {0x110c2, 0x11100, 62}, - {0x11101, 0x11102, 1}, - {0x11127, 0x1112b, 1}, - {0x1112d, 0x11134, 1}, - {0x11173, 0x11180, 13}, - {0x11181, 0x111b6, 53}, - {0x111b7, 0x111be, 1}, - {0x111c9, 0x111cc, 1}, - {0x111cf, 0x1122f, 96}, - {0x11230, 0x11231, 1}, - {0x11234, 0x11236, 2}, - {0x11237, 0x1123e, 7}, - {0x11241, 0x112df, 158}, - {0x112e3, 0x112ea, 1}, - {0x11300, 0x11301, 1}, - {0x1133b, 0x1133c, 1}, - {0x11340, 0x11366, 38}, - {0x11367, 0x1136c, 1}, - {0x11370, 0x11374, 1}, - {0x11438, 0x1143f, 1}, - {0x11442, 0x11444, 1}, - {0x11446, 0x1145e, 24}, - {0x114b3, 0x114b8, 1}, - {0x114ba, 0x114bf, 5}, - {0x114c0, 0x114c2, 2}, - {0x114c3, 0x115b2, 239}, - {0x115b3, 0x115b5, 1}, - {0x115bc, 0x115bd, 1}, - {0x115bf, 0x115c0, 1}, - {0x115dc, 0x115dd, 1}, - {0x11633, 0x1163a, 1}, - {0x1163d, 0x1163f, 2}, - {0x11640, 0x116ab, 107}, - {0x116ad, 0x116b0, 3}, - {0x116b1, 0x116b5, 1}, - {0x116b7, 0x1171d, 102}, - {0x1171e, 0x1171f, 1}, - {0x11722, 0x11725, 1}, - {0x11727, 0x1172b, 1}, - {0x1182f, 0x11837, 1}, - {0x11839, 0x1183a, 1}, - {0x1193b, 0x1193c, 1}, - {0x1193e, 0x11943, 5}, - {0x119d4, 0x119d7, 1}, - {0x119da, 0x119db, 1}, - {0x119e0, 0x11a01, 33}, - {0x11a02, 0x11a0a, 1}, - {0x11a33, 0x11a38, 1}, - {0x11a3b, 0x11a3e, 1}, - {0x11a47, 0x11a51, 10}, - {0x11a52, 0x11a56, 1}, - {0x11a59, 0x11a5b, 1}, - {0x11a8a, 0x11a96, 1}, - {0x11a98, 0x11a99, 1}, - {0x11c30, 0x11c36, 1}, - {0x11c38, 0x11c3d, 1}, - {0x11c3f, 0x11c92, 83}, - {0x11c93, 0x11ca7, 1}, - {0x11caa, 0x11cb0, 1}, - {0x11cb2, 0x11cb3, 1}, - {0x11cb5, 0x11cb6, 1}, - {0x11d31, 0x11d36, 1}, - {0x11d3a, 0x11d3c, 2}, - {0x11d3d, 0x11d3f, 2}, - {0x11d40, 0x11d45, 1}, - {0x11d47, 0x11d90, 73}, - {0x11d91, 0x11d95, 4}, - {0x11d97, 0x11ef3, 348}, - {0x11ef4, 0x11f00, 12}, - {0x11f01, 0x11f36, 53}, - {0x11f37, 0x11f3a, 1}, - {0x11f40, 0x11f42, 2}, - {0x13440, 0x13447, 7}, - {0x13448, 0x13455, 1}, - {0x16af0, 0x16af4, 1}, - {0x16b30, 0x16b36, 1}, - {0x16f4f, 0x16f8f, 64}, - {0x16f90, 0x16f92, 1}, - {0x16fe4, 0x1bc9d, 19641}, - {0x1bc9e, 0x1cf00, 4706}, - {0x1cf01, 0x1cf2d, 1}, - {0x1cf30, 0x1cf46, 1}, - {0x1d167, 0x1d169, 1}, - {0x1d17b, 0x1d182, 1}, - {0x1d185, 0x1d18b, 1}, - {0x1d1aa, 0x1d1ad, 1}, - {0x1d242, 0x1d244, 1}, - {0x1da00, 0x1da36, 1}, - {0x1da3b, 0x1da6c, 1}, - {0x1da75, 0x1da84, 15}, - {0x1da9b, 0x1da9f, 1}, - {0x1daa1, 0x1daaf, 1}, - {0x1e000, 0x1e006, 1}, - {0x1e008, 0x1e018, 1}, - {0x1e01b, 0x1e021, 1}, - {0x1e023, 0x1e024, 1}, - {0x1e026, 0x1e02a, 1}, - {0x1e08f, 0x1e130, 161}, - {0x1e131, 0x1e136, 1}, - {0x1e2ae, 0x1e2ec, 62}, - {0x1e2ed, 0x1e2ef, 1}, - {0x1e4ec, 0x1e4ef, 1}, - {0x1e8d0, 0x1e8d6, 1}, - {0x1e944, 0x1e94a, 1}, - {0xe0100, 0xe01ef, 1}, - ], + R16: [ + {0x0300, 0x036f, 1}, + {0x0483, 0x0487, 1}, + {0x0591, 0x05bd, 1}, + {0x05bf, 0x05c1, 2}, + {0x05c2, 0x05c4, 2}, + {0x05c5, 0x05c7, 2}, + {0x0610, 0x061a, 1}, + {0x064b, 0x065f, 1}, + {0x0670, 0x06d6, 102}, + {0x06d7, 0x06dc, 1}, + {0x06df, 0x06e4, 1}, + {0x06e7, 0x06e8, 1}, + {0x06ea, 0x06ed, 1}, + {0x0711, 0x0730, 31}, + {0x0731, 0x074a, 1}, + {0x07a6, 0x07b0, 1}, + {0x07eb, 0x07f3, 1}, + {0x07fd, 0x0816, 25}, + {0x0817, 0x0819, 1}, + {0x081b, 0x0823, 1}, + {0x0825, 0x0827, 1}, + {0x0829, 0x082d, 1}, + {0x0859, 0x085b, 1}, + {0x0898, 0x089f, 1}, + {0x08ca, 0x08e1, 1}, + {0x08e3, 0x0902, 1}, + {0x093a, 0x093c, 2}, + {0x0941, 0x0948, 1}, + {0x094d, 0x0951, 4}, + {0x0952, 0x0957, 1}, + {0x0962, 0x0963, 1}, + {0x0981, 0x09bc, 59}, + {0x09c1, 0x09c4, 1}, + {0x09cd, 0x09e2, 21}, + {0x09e3, 0x09fe, 27}, + {0x0a01, 0x0a02, 1}, + {0x0a3c, 0x0a41, 5}, + {0x0a42, 0x0a47, 5}, + {0x0a48, 0x0a4b, 3}, + {0x0a4c, 0x0a4d, 1}, + {0x0a51, 0x0a70, 31}, + {0x0a71, 0x0a75, 4}, + {0x0a81, 0x0a82, 1}, + {0x0abc, 0x0ac1, 5}, + {0x0ac2, 0x0ac5, 1}, + {0x0ac7, 0x0ac8, 1}, + {0x0acd, 0x0ae2, 21}, + {0x0ae3, 0x0afa, 23}, + {0x0afb, 0x0aff, 1}, + {0x0b01, 0x0b3c, 59}, + {0x0b3f, 0x0b41, 2}, + {0x0b42, 0x0b44, 1}, + {0x0b4d, 0x0b55, 8}, + {0x0b56, 0x0b62, 12}, + {0x0b63, 0x0b82, 31}, + {0x0bc0, 0x0bcd, 13}, + {0x0c00, 0x0c04, 4}, + {0x0c3c, 0x0c3e, 2}, + {0x0c3f, 0x0c40, 1}, + {0x0c46, 0x0c48, 1}, + {0x0c4a, 0x0c4d, 1}, + {0x0c55, 0x0c56, 1}, + {0x0c62, 0x0c63, 1}, + {0x0c81, 0x0cbc, 59}, + {0x0cbf, 0x0cc6, 7}, + {0x0ccc, 0x0ccd, 1}, + {0x0ce2, 0x0ce3, 1}, + {0x0d00, 0x0d01, 1}, + {0x0d3b, 0x0d3c, 1}, + {0x0d41, 0x0d44, 1}, + {0x0d4d, 0x0d62, 21}, + {0x0d63, 0x0d81, 30}, + {0x0dca, 0x0dd2, 8}, + {0x0dd3, 0x0dd4, 1}, + {0x0dd6, 0x0e31, 91}, + {0x0e34, 0x0e3a, 1}, + {0x0e47, 0x0e4e, 1}, + {0x0eb1, 0x0eb4, 3}, + {0x0eb5, 0x0ebc, 1}, + {0x0ec8, 0x0ece, 1}, + {0x0f18, 0x0f19, 1}, + {0x0f35, 0x0f39, 2}, + {0x0f71, 0x0f7e, 1}, + {0x0f80, 0x0f84, 1}, + {0x0f86, 0x0f87, 1}, + {0x0f8d, 0x0f97, 1}, + {0x0f99, 0x0fbc, 1}, + {0x0fc6, 0x102d, 103}, + {0x102e, 0x1030, 1}, + {0x1032, 0x1037, 1}, + {0x1039, 0x103a, 1}, + {0x103d, 0x103e, 1}, + {0x1058, 0x1059, 1}, + {0x105e, 0x1060, 1}, + {0x1071, 0x1074, 1}, + {0x1082, 0x1085, 3}, + {0x1086, 0x108d, 7}, + {0x109d, 0x135d, 704}, + {0x135e, 0x135f, 1}, + {0x1712, 0x1714, 1}, + {0x1732, 0x1733, 1}, + {0x1752, 0x1753, 1}, + {0x1772, 0x1773, 1}, + {0x17b4, 0x17b5, 1}, + {0x17b7, 0x17bd, 1}, + {0x17c6, 0x17c9, 3}, + {0x17ca, 0x17d3, 1}, + {0x17dd, 0x180b, 46}, + {0x180c, 0x180d, 1}, + {0x180f, 0x1885, 118}, + {0x1886, 0x18a9, 35}, + {0x1920, 0x1922, 1}, + {0x1927, 0x1928, 1}, + {0x1932, 0x1939, 7}, + {0x193a, 0x193b, 1}, + {0x1a17, 0x1a18, 1}, + {0x1a1b, 0x1a56, 59}, + {0x1a58, 0x1a5e, 1}, + {0x1a60, 0x1a62, 2}, + {0x1a65, 0x1a6c, 1}, + {0x1a73, 0x1a7c, 1}, + {0x1a7f, 0x1ab0, 49}, + {0x1ab1, 0x1abd, 1}, + {0x1abf, 0x1ace, 1}, + {0x1b00, 0x1b03, 1}, + {0x1b34, 0x1b36, 2}, + {0x1b37, 0x1b3a, 1}, + {0x1b3c, 0x1b42, 6}, + {0x1b6b, 0x1b73, 1}, + {0x1b80, 0x1b81, 1}, + {0x1ba2, 0x1ba5, 1}, + {0x1ba8, 0x1ba9, 1}, + {0x1bab, 0x1bad, 1}, + {0x1be6, 0x1be8, 2}, + {0x1be9, 0x1bed, 4}, + {0x1bef, 0x1bf1, 1}, + {0x1c2c, 0x1c33, 1}, + {0x1c36, 0x1c37, 1}, + {0x1cd0, 0x1cd2, 1}, + {0x1cd4, 0x1ce0, 1}, + {0x1ce2, 0x1ce8, 1}, + {0x1ced, 0x1cf4, 7}, + {0x1cf8, 0x1cf9, 1}, + {0x1dc0, 0x1dff, 1}, + {0x20d0, 0x20dc, 1}, + {0x20e1, 0x20e5, 4}, + {0x20e6, 0x20f0, 1}, + {0x2cef, 0x2cf1, 1}, + {0x2d7f, 0x2de0, 97}, + {0x2de1, 0x2dff, 1}, + {0x302a, 0x302d, 1}, + {0x3099, 0x309a, 1}, + {0xa66f, 0xa674, 5}, + {0xa675, 0xa67d, 1}, + {0xa69e, 0xa69f, 1}, + {0xa6f0, 0xa6f1, 1}, + {0xa802, 0xa806, 4}, + {0xa80b, 0xa825, 26}, + {0xa826, 0xa82c, 6}, + {0xa8c4, 0xa8c5, 1}, + {0xa8e0, 0xa8f1, 1}, + {0xa8ff, 0xa926, 39}, + {0xa927, 0xa92d, 1}, + {0xa947, 0xa951, 1}, + {0xa980, 0xa982, 1}, + {0xa9b3, 0xa9b6, 3}, + {0xa9b7, 0xa9b9, 1}, + {0xa9bc, 0xa9bd, 1}, + {0xa9e5, 0xaa29, 68}, + {0xaa2a, 0xaa2e, 1}, + {0xaa31, 0xaa32, 1}, + {0xaa35, 0xaa36, 1}, + {0xaa43, 0xaa4c, 9}, + {0xaa7c, 0xaab0, 52}, + {0xaab2, 0xaab4, 1}, + {0xaab7, 0xaab8, 1}, + {0xaabe, 0xaabf, 1}, + {0xaac1, 0xaaec, 43}, + {0xaaed, 0xaaf6, 9}, + {0xabe5, 0xabe8, 3}, + {0xabed, 0xfb1e, 20273}, + {0xfe00, 0xfe0f, 1}, + {0xfe20, 0xfe2f, 1}, + ], + R32: [ + {0x101fd, 0x102e0, 227}, + {0x10376, 0x1037a, 1}, + {0x10a01, 0x10a03, 1}, + {0x10a05, 0x10a06, 1}, + {0x10a0c, 0x10a0f, 1}, + {0x10a38, 0x10a3a, 1}, + {0x10a3f, 0x10ae5, 166}, + {0x10ae6, 0x10d24, 574}, + {0x10d25, 0x10d27, 1}, + {0x10eab, 0x10eac, 1}, + {0x10efd, 0x10eff, 1}, + {0x10f46, 0x10f50, 1}, + {0x10f82, 0x10f85, 1}, + {0x11001, 0x11038, 55}, + {0x11039, 0x11046, 1}, + {0x11070, 0x11073, 3}, + {0x11074, 0x1107f, 11}, + {0x11080, 0x11081, 1}, + {0x110b3, 0x110b6, 1}, + {0x110b9, 0x110ba, 1}, + {0x110c2, 0x11100, 62}, + {0x11101, 0x11102, 1}, + {0x11127, 0x1112b, 1}, + {0x1112d, 0x11134, 1}, + {0x11173, 0x11180, 13}, + {0x11181, 0x111b6, 53}, + {0x111b7, 0x111be, 1}, + {0x111c9, 0x111cc, 1}, + {0x111cf, 0x1122f, 96}, + {0x11230, 0x11231, 1}, + {0x11234, 0x11236, 2}, + {0x11237, 0x1123e, 7}, + {0x11241, 0x112df, 158}, + {0x112e3, 0x112ea, 1}, + {0x11300, 0x11301, 1}, + {0x1133b, 0x1133c, 1}, + {0x11340, 0x11366, 38}, + {0x11367, 0x1136c, 1}, + {0x11370, 0x11374, 1}, + {0x11438, 0x1143f, 1}, + {0x11442, 0x11444, 1}, + {0x11446, 0x1145e, 24}, + {0x114b3, 0x114b8, 1}, + {0x114ba, 0x114bf, 5}, + {0x114c0, 0x114c2, 2}, + {0x114c3, 0x115b2, 239}, + {0x115b3, 0x115b5, 1}, + {0x115bc, 0x115bd, 1}, + {0x115bf, 0x115c0, 1}, + {0x115dc, 0x115dd, 1}, + {0x11633, 0x1163a, 1}, + {0x1163d, 0x1163f, 2}, + {0x11640, 0x116ab, 107}, + {0x116ad, 0x116b0, 3}, + {0x116b1, 0x116b5, 1}, + {0x116b7, 0x1171d, 102}, + {0x1171e, 0x1171f, 1}, + {0x11722, 0x11725, 1}, + {0x11727, 0x1172b, 1}, + {0x1182f, 0x11837, 1}, + {0x11839, 0x1183a, 1}, + {0x1193b, 0x1193c, 1}, + {0x1193e, 0x11943, 5}, + {0x119d4, 0x119d7, 1}, + {0x119da, 0x119db, 1}, + {0x119e0, 0x11a01, 33}, + {0x11a02, 0x11a0a, 1}, + {0x11a33, 0x11a38, 1}, + {0x11a3b, 0x11a3e, 1}, + {0x11a47, 0x11a51, 10}, + {0x11a52, 0x11a56, 1}, + {0x11a59, 0x11a5b, 1}, + {0x11a8a, 0x11a96, 1}, + {0x11a98, 0x11a99, 1}, + {0x11c30, 0x11c36, 1}, + {0x11c38, 0x11c3d, 1}, + {0x11c3f, 0x11c92, 83}, + {0x11c93, 0x11ca7, 1}, + {0x11caa, 0x11cb0, 1}, + {0x11cb2, 0x11cb3, 1}, + {0x11cb5, 0x11cb6, 1}, + {0x11d31, 0x11d36, 1}, + {0x11d3a, 0x11d3c, 2}, + {0x11d3d, 0x11d3f, 2}, + {0x11d40, 0x11d45, 1}, + {0x11d47, 0x11d90, 73}, + {0x11d91, 0x11d95, 4}, + {0x11d97, 0x11ef3, 348}, + {0x11ef4, 0x11f00, 12}, + {0x11f01, 0x11f36, 53}, + {0x11f37, 0x11f3a, 1}, + {0x11f40, 0x11f42, 2}, + {0x13440, 0x13447, 7}, + {0x13448, 0x13455, 1}, + {0x16af0, 0x16af4, 1}, + {0x16b30, 0x16b36, 1}, + {0x16f4f, 0x16f8f, 64}, + {0x16f90, 0x16f92, 1}, + {0x16fe4, 0x1bc9d, 19641}, + {0x1bc9e, 0x1cf00, 4706}, + {0x1cf01, 0x1cf2d, 1}, + {0x1cf30, 0x1cf46, 1}, + {0x1d167, 0x1d169, 1}, + {0x1d17b, 0x1d182, 1}, + {0x1d185, 0x1d18b, 1}, + {0x1d1aa, 0x1d1ad, 1}, + {0x1d242, 0x1d244, 1}, + {0x1da00, 0x1da36, 1}, + {0x1da3b, 0x1da6c, 1}, + {0x1da75, 0x1da84, 15}, + {0x1da9b, 0x1da9f, 1}, + {0x1daa1, 0x1daaf, 1}, + {0x1e000, 0x1e006, 1}, + {0x1e008, 0x1e018, 1}, + {0x1e01b, 0x1e021, 1}, + {0x1e023, 0x1e024, 1}, + {0x1e026, 0x1e02a, 1}, + {0x1e08f, 0x1e130, 161}, + {0x1e131, 0x1e136, 1}, + {0x1e2ae, 0x1e2ec, 62}, + {0x1e2ed, 0x1e2ef, 1}, + {0x1e4ec, 0x1e4ef, 1}, + {0x1e8d0, 0x1e8d6, 1}, + {0x1e944, 0x1e94a, 1}, + {0xe0100, 0xe01ef, 1}, + ], } static _N = &RangeTable{ - R16: [ - {0x0030, 0x0039, 1}, - {0x00b2, 0x00b3, 1}, - {0x00b9, 0x00bc, 3}, - {0x00bd, 0x00be, 1}, - {0x0660, 0x0669, 1}, - {0x06f0, 0x06f9, 1}, - {0x07c0, 0x07c9, 1}, - {0x0966, 0x096f, 1}, - {0x09e6, 0x09ef, 1}, - {0x09f4, 0x09f9, 1}, - {0x0a66, 0x0a6f, 1}, - {0x0ae6, 0x0aef, 1}, - {0x0b66, 0x0b6f, 1}, - {0x0b72, 0x0b77, 1}, - {0x0be6, 0x0bf2, 1}, - {0x0c66, 0x0c6f, 1}, - {0x0c78, 0x0c7e, 1}, - {0x0ce6, 0x0cef, 1}, - {0x0d58, 0x0d5e, 1}, - {0x0d66, 0x0d78, 1}, - {0x0de6, 0x0def, 1}, - {0x0e50, 0x0e59, 1}, - {0x0ed0, 0x0ed9, 1}, - {0x0f20, 0x0f33, 1}, - {0x1040, 0x1049, 1}, - {0x1090, 0x1099, 1}, - {0x1369, 0x137c, 1}, - {0x16ee, 0x16f0, 1}, - {0x17e0, 0x17e9, 1}, - {0x17f0, 0x17f9, 1}, - {0x1810, 0x1819, 1}, - {0x1946, 0x194f, 1}, - {0x19d0, 0x19da, 1}, - {0x1a80, 0x1a89, 1}, - {0x1a90, 0x1a99, 1}, - {0x1b50, 0x1b59, 1}, - {0x1bb0, 0x1bb9, 1}, - {0x1c40, 0x1c49, 1}, - {0x1c50, 0x1c59, 1}, - {0x2070, 0x2074, 4}, - {0x2075, 0x2079, 1}, - {0x2080, 0x2089, 1}, - {0x2150, 0x2182, 1}, - {0x2185, 0x2189, 1}, - {0x2460, 0x249b, 1}, - {0x24ea, 0x24ff, 1}, - {0x2776, 0x2793, 1}, - {0x2cfd, 0x3007, 778}, - {0x3021, 0x3029, 1}, - {0x3038, 0x303a, 1}, - {0x3192, 0x3195, 1}, - {0x3220, 0x3229, 1}, - {0x3248, 0x324f, 1}, - {0x3251, 0x325f, 1}, - {0x3280, 0x3289, 1}, - {0x32b1, 0x32bf, 1}, - {0xa620, 0xa629, 1}, - {0xa6e6, 0xa6ef, 1}, - {0xa830, 0xa835, 1}, - {0xa8d0, 0xa8d9, 1}, - {0xa900, 0xa909, 1}, - {0xa9d0, 0xa9d9, 1}, - {0xa9f0, 0xa9f9, 1}, - {0xaa50, 0xaa59, 1}, - {0xabf0, 0xabf9, 1}, - {0xff10, 0xff19, 1}, - ], - R32: [ - {0x10107, 0x10133, 1}, - {0x10140, 0x10178, 1}, - {0x1018a, 0x1018b, 1}, - {0x102e1, 0x102fb, 1}, - {0x10320, 0x10323, 1}, - {0x10341, 0x1034a, 9}, - {0x103d1, 0x103d5, 1}, - {0x104a0, 0x104a9, 1}, - {0x10858, 0x1085f, 1}, - {0x10879, 0x1087f, 1}, - {0x108a7, 0x108af, 1}, - {0x108fb, 0x108ff, 1}, - {0x10916, 0x1091b, 1}, - {0x109bc, 0x109bd, 1}, - {0x109c0, 0x109cf, 1}, - {0x109d2, 0x109ff, 1}, - {0x10a40, 0x10a48, 1}, - {0x10a7d, 0x10a7e, 1}, - {0x10a9d, 0x10a9f, 1}, - {0x10aeb, 0x10aef, 1}, - {0x10b58, 0x10b5f, 1}, - {0x10b78, 0x10b7f, 1}, - {0x10ba9, 0x10baf, 1}, - {0x10cfa, 0x10cff, 1}, - {0x10d30, 0x10d39, 1}, - {0x10e60, 0x10e7e, 1}, - {0x10f1d, 0x10f26, 1}, - {0x10f51, 0x10f54, 1}, - {0x10fc5, 0x10fcb, 1}, - {0x11052, 0x1106f, 1}, - {0x110f0, 0x110f9, 1}, - {0x11136, 0x1113f, 1}, - {0x111d0, 0x111d9, 1}, - {0x111e1, 0x111f4, 1}, - {0x112f0, 0x112f9, 1}, - {0x11450, 0x11459, 1}, - {0x114d0, 0x114d9, 1}, - {0x11650, 0x11659, 1}, - {0x116c0, 0x116c9, 1}, - {0x11730, 0x1173b, 1}, - {0x118e0, 0x118f2, 1}, - {0x11950, 0x11959, 1}, - {0x11c50, 0x11c6c, 1}, - {0x11d50, 0x11d59, 1}, - {0x11da0, 0x11da9, 1}, - {0x11f50, 0x11f59, 1}, - {0x11fc0, 0x11fd4, 1}, - {0x12400, 0x1246e, 1}, - {0x16a60, 0x16a69, 1}, - {0x16ac0, 0x16ac9, 1}, - {0x16b50, 0x16b59, 1}, - {0x16b5b, 0x16b61, 1}, - {0x16e80, 0x16e96, 1}, - {0x1d2c0, 0x1d2d3, 1}, - {0x1d2e0, 0x1d2f3, 1}, - {0x1d360, 0x1d378, 1}, - {0x1d7ce, 0x1d7ff, 1}, - {0x1e140, 0x1e149, 1}, - {0x1e2f0, 0x1e2f9, 1}, - {0x1e4f0, 0x1e4f9, 1}, - {0x1e8c7, 0x1e8cf, 1}, - {0x1e950, 0x1e959, 1}, - {0x1ec71, 0x1ecab, 1}, - {0x1ecad, 0x1ecaf, 1}, - {0x1ecb1, 0x1ecb4, 1}, - {0x1ed01, 0x1ed2d, 1}, - {0x1ed2f, 0x1ed3d, 1}, - {0x1f100, 0x1f10c, 1}, - {0x1fbf0, 0x1fbf9, 1}, - ], - LatinOffset: 4, + R16: [ + {0x0030, 0x0039, 1}, + {0x00b2, 0x00b3, 1}, + {0x00b9, 0x00bc, 3}, + {0x00bd, 0x00be, 1}, + {0x0660, 0x0669, 1}, + {0x06f0, 0x06f9, 1}, + {0x07c0, 0x07c9, 1}, + {0x0966, 0x096f, 1}, + {0x09e6, 0x09ef, 1}, + {0x09f4, 0x09f9, 1}, + {0x0a66, 0x0a6f, 1}, + {0x0ae6, 0x0aef, 1}, + {0x0b66, 0x0b6f, 1}, + {0x0b72, 0x0b77, 1}, + {0x0be6, 0x0bf2, 1}, + {0x0c66, 0x0c6f, 1}, + {0x0c78, 0x0c7e, 1}, + {0x0ce6, 0x0cef, 1}, + {0x0d58, 0x0d5e, 1}, + {0x0d66, 0x0d78, 1}, + {0x0de6, 0x0def, 1}, + {0x0e50, 0x0e59, 1}, + {0x0ed0, 0x0ed9, 1}, + {0x0f20, 0x0f33, 1}, + {0x1040, 0x1049, 1}, + {0x1090, 0x1099, 1}, + {0x1369, 0x137c, 1}, + {0x16ee, 0x16f0, 1}, + {0x17e0, 0x17e9, 1}, + {0x17f0, 0x17f9, 1}, + {0x1810, 0x1819, 1}, + {0x1946, 0x194f, 1}, + {0x19d0, 0x19da, 1}, + {0x1a80, 0x1a89, 1}, + {0x1a90, 0x1a99, 1}, + {0x1b50, 0x1b59, 1}, + {0x1bb0, 0x1bb9, 1}, + {0x1c40, 0x1c49, 1}, + {0x1c50, 0x1c59, 1}, + {0x2070, 0x2074, 4}, + {0x2075, 0x2079, 1}, + {0x2080, 0x2089, 1}, + {0x2150, 0x2182, 1}, + {0x2185, 0x2189, 1}, + {0x2460, 0x249b, 1}, + {0x24ea, 0x24ff, 1}, + {0x2776, 0x2793, 1}, + {0x2cfd, 0x3007, 778}, + {0x3021, 0x3029, 1}, + {0x3038, 0x303a, 1}, + {0x3192, 0x3195, 1}, + {0x3220, 0x3229, 1}, + {0x3248, 0x324f, 1}, + {0x3251, 0x325f, 1}, + {0x3280, 0x3289, 1}, + {0x32b1, 0x32bf, 1}, + {0xa620, 0xa629, 1}, + {0xa6e6, 0xa6ef, 1}, + {0xa830, 0xa835, 1}, + {0xa8d0, 0xa8d9, 1}, + {0xa900, 0xa909, 1}, + {0xa9d0, 0xa9d9, 1}, + {0xa9f0, 0xa9f9, 1}, + {0xaa50, 0xaa59, 1}, + {0xabf0, 0xabf9, 1}, + {0xff10, 0xff19, 1}, + ], + R32: [ + {0x10107, 0x10133, 1}, + {0x10140, 0x10178, 1}, + {0x1018a, 0x1018b, 1}, + {0x102e1, 0x102fb, 1}, + {0x10320, 0x10323, 1}, + {0x10341, 0x1034a, 9}, + {0x103d1, 0x103d5, 1}, + {0x104a0, 0x104a9, 1}, + {0x10858, 0x1085f, 1}, + {0x10879, 0x1087f, 1}, + {0x108a7, 0x108af, 1}, + {0x108fb, 0x108ff, 1}, + {0x10916, 0x1091b, 1}, + {0x109bc, 0x109bd, 1}, + {0x109c0, 0x109cf, 1}, + {0x109d2, 0x109ff, 1}, + {0x10a40, 0x10a48, 1}, + {0x10a7d, 0x10a7e, 1}, + {0x10a9d, 0x10a9f, 1}, + {0x10aeb, 0x10aef, 1}, + {0x10b58, 0x10b5f, 1}, + {0x10b78, 0x10b7f, 1}, + {0x10ba9, 0x10baf, 1}, + {0x10cfa, 0x10cff, 1}, + {0x10d30, 0x10d39, 1}, + {0x10e60, 0x10e7e, 1}, + {0x10f1d, 0x10f26, 1}, + {0x10f51, 0x10f54, 1}, + {0x10fc5, 0x10fcb, 1}, + {0x11052, 0x1106f, 1}, + {0x110f0, 0x110f9, 1}, + {0x11136, 0x1113f, 1}, + {0x111d0, 0x111d9, 1}, + {0x111e1, 0x111f4, 1}, + {0x112f0, 0x112f9, 1}, + {0x11450, 0x11459, 1}, + {0x114d0, 0x114d9, 1}, + {0x11650, 0x11659, 1}, + {0x116c0, 0x116c9, 1}, + {0x11730, 0x1173b, 1}, + {0x118e0, 0x118f2, 1}, + {0x11950, 0x11959, 1}, + {0x11c50, 0x11c6c, 1}, + {0x11d50, 0x11d59, 1}, + {0x11da0, 0x11da9, 1}, + {0x11f50, 0x11f59, 1}, + {0x11fc0, 0x11fd4, 1}, + {0x12400, 0x1246e, 1}, + {0x16a60, 0x16a69, 1}, + {0x16ac0, 0x16ac9, 1}, + {0x16b50, 0x16b59, 1}, + {0x16b5b, 0x16b61, 1}, + {0x16e80, 0x16e96, 1}, + {0x1d2c0, 0x1d2d3, 1}, + {0x1d2e0, 0x1d2f3, 1}, + {0x1d360, 0x1d378, 1}, + {0x1d7ce, 0x1d7ff, 1}, + {0x1e140, 0x1e149, 1}, + {0x1e2f0, 0x1e2f9, 1}, + {0x1e4f0, 0x1e4f9, 1}, + {0x1e8c7, 0x1e8cf, 1}, + {0x1e950, 0x1e959, 1}, + {0x1ec71, 0x1ecab, 1}, + {0x1ecad, 0x1ecaf, 1}, + {0x1ecb1, 0x1ecb4, 1}, + {0x1ed01, 0x1ed2d, 1}, + {0x1ed2f, 0x1ed3d, 1}, + {0x1f100, 0x1f10c, 1}, + {0x1fbf0, 0x1fbf9, 1}, + ], + LatinOffset: 4, } static _ND = &RangeTable{ - R16: [ - {0x0030, 0x0039, 1}, - {0x0660, 0x0669, 1}, - {0x06f0, 0x06f9, 1}, - {0x07c0, 0x07c9, 1}, - {0x0966, 0x096f, 1}, - {0x09e6, 0x09ef, 1}, - {0x0a66, 0x0a6f, 1}, - {0x0ae6, 0x0aef, 1}, - {0x0b66, 0x0b6f, 1}, - {0x0be6, 0x0bef, 1}, - {0x0c66, 0x0c6f, 1}, - {0x0ce6, 0x0cef, 1}, - {0x0d66, 0x0d6f, 1}, - {0x0de6, 0x0def, 1}, - {0x0e50, 0x0e59, 1}, - {0x0ed0, 0x0ed9, 1}, - {0x0f20, 0x0f29, 1}, - {0x1040, 0x1049, 1}, - {0x1090, 0x1099, 1}, - {0x17e0, 0x17e9, 1}, - {0x1810, 0x1819, 1}, - {0x1946, 0x194f, 1}, - {0x19d0, 0x19d9, 1}, - {0x1a80, 0x1a89, 1}, - {0x1a90, 0x1a99, 1}, - {0x1b50, 0x1b59, 1}, - {0x1bb0, 0x1bb9, 1}, - {0x1c40, 0x1c49, 1}, - {0x1c50, 0x1c59, 1}, - {0xa620, 0xa629, 1}, - {0xa8d0, 0xa8d9, 1}, - {0xa900, 0xa909, 1}, - {0xa9d0, 0xa9d9, 1}, - {0xa9f0, 0xa9f9, 1}, - {0xaa50, 0xaa59, 1}, - {0xabf0, 0xabf9, 1}, - {0xff10, 0xff19, 1}, - ], - R32: [ - {0x104a0, 0x104a9, 1}, - {0x10d30, 0x10d39, 1}, - {0x11066, 0x1106f, 1}, - {0x110f0, 0x110f9, 1}, - {0x11136, 0x1113f, 1}, - {0x111d0, 0x111d9, 1}, - {0x112f0, 0x112f9, 1}, - {0x11450, 0x11459, 1}, - {0x114d0, 0x114d9, 1}, - {0x11650, 0x11659, 1}, - {0x116c0, 0x116c9, 1}, - {0x11730, 0x11739, 1}, - {0x118e0, 0x118e9, 1}, - {0x11950, 0x11959, 1}, - {0x11c50, 0x11c59, 1}, - {0x11d50, 0x11d59, 1}, - {0x11da0, 0x11da9, 1}, - {0x11f50, 0x11f59, 1}, - {0x16a60, 0x16a69, 1}, - {0x16ac0, 0x16ac9, 1}, - {0x16b50, 0x16b59, 1}, - {0x1d7ce, 0x1d7ff, 1}, - {0x1e140, 0x1e149, 1}, - {0x1e2f0, 0x1e2f9, 1}, - {0x1e4f0, 0x1e4f9, 1}, - {0x1e950, 0x1e959, 1}, - {0x1fbf0, 0x1fbf9, 1}, - ], - LatinOffset: 1, + R16: [ + {0x0030, 0x0039, 1}, + {0x0660, 0x0669, 1}, + {0x06f0, 0x06f9, 1}, + {0x07c0, 0x07c9, 1}, + {0x0966, 0x096f, 1}, + {0x09e6, 0x09ef, 1}, + {0x0a66, 0x0a6f, 1}, + {0x0ae6, 0x0aef, 1}, + {0x0b66, 0x0b6f, 1}, + {0x0be6, 0x0bef, 1}, + {0x0c66, 0x0c6f, 1}, + {0x0ce6, 0x0cef, 1}, + {0x0d66, 0x0d6f, 1}, + {0x0de6, 0x0def, 1}, + {0x0e50, 0x0e59, 1}, + {0x0ed0, 0x0ed9, 1}, + {0x0f20, 0x0f29, 1}, + {0x1040, 0x1049, 1}, + {0x1090, 0x1099, 1}, + {0x17e0, 0x17e9, 1}, + {0x1810, 0x1819, 1}, + {0x1946, 0x194f, 1}, + {0x19d0, 0x19d9, 1}, + {0x1a80, 0x1a89, 1}, + {0x1a90, 0x1a99, 1}, + {0x1b50, 0x1b59, 1}, + {0x1bb0, 0x1bb9, 1}, + {0x1c40, 0x1c49, 1}, + {0x1c50, 0x1c59, 1}, + {0xa620, 0xa629, 1}, + {0xa8d0, 0xa8d9, 1}, + {0xa900, 0xa909, 1}, + {0xa9d0, 0xa9d9, 1}, + {0xa9f0, 0xa9f9, 1}, + {0xaa50, 0xaa59, 1}, + {0xabf0, 0xabf9, 1}, + {0xff10, 0xff19, 1}, + ], + R32: [ + {0x104a0, 0x104a9, 1}, + {0x10d30, 0x10d39, 1}, + {0x11066, 0x1106f, 1}, + {0x110f0, 0x110f9, 1}, + {0x11136, 0x1113f, 1}, + {0x111d0, 0x111d9, 1}, + {0x112f0, 0x112f9, 1}, + {0x11450, 0x11459, 1}, + {0x114d0, 0x114d9, 1}, + {0x11650, 0x11659, 1}, + {0x116c0, 0x116c9, 1}, + {0x11730, 0x11739, 1}, + {0x118e0, 0x118e9, 1}, + {0x11950, 0x11959, 1}, + {0x11c50, 0x11c59, 1}, + {0x11d50, 0x11d59, 1}, + {0x11da0, 0x11da9, 1}, + {0x11f50, 0x11f59, 1}, + {0x16a60, 0x16a69, 1}, + {0x16ac0, 0x16ac9, 1}, + {0x16b50, 0x16b59, 1}, + {0x1d7ce, 0x1d7ff, 1}, + {0x1e140, 0x1e149, 1}, + {0x1e2f0, 0x1e2f9, 1}, + {0x1e4f0, 0x1e4f9, 1}, + {0x1e950, 0x1e959, 1}, + {0x1fbf0, 0x1fbf9, 1}, + ], + LatinOffset: 1, } static _NL = &RangeTable{ - R16: [ - {0x16ee, 0x16f0, 1}, - {0x2160, 0x2182, 1}, - {0x2185, 0x2188, 1}, - {0x3007, 0x3021, 26}, - {0x3022, 0x3029, 1}, - {0x3038, 0x303a, 1}, - {0xa6e6, 0xa6ef, 1}, - ], - R32: [ - {0x10140, 0x10174, 1}, - {0x10341, 0x1034a, 9}, - {0x103d1, 0x103d5, 1}, - {0x12400, 0x1246e, 1}, - ], + R16: [ + {0x16ee, 0x16f0, 1}, + {0x2160, 0x2182, 1}, + {0x2185, 0x2188, 1}, + {0x3007, 0x3021, 26}, + {0x3022, 0x3029, 1}, + {0x3038, 0x303a, 1}, + {0xa6e6, 0xa6ef, 1}, + ], + R32: [ + {0x10140, 0x10174, 1}, + {0x10341, 0x1034a, 9}, + {0x103d1, 0x103d5, 1}, + {0x12400, 0x1246e, 1}, + ], } static _NO = &RangeTable{ - R16: [ - {0x00b2, 0x00b3, 1}, - {0x00b9, 0x00bc, 3}, - {0x00bd, 0x00be, 1}, - {0x09f4, 0x09f9, 1}, - {0x0b72, 0x0b77, 1}, - {0x0bf0, 0x0bf2, 1}, - {0x0c78, 0x0c7e, 1}, - {0x0d58, 0x0d5e, 1}, - {0x0d70, 0x0d78, 1}, - {0x0f2a, 0x0f33, 1}, - {0x1369, 0x137c, 1}, - {0x17f0, 0x17f9, 1}, - {0x19da, 0x2070, 1686}, - {0x2074, 0x2079, 1}, - {0x2080, 0x2089, 1}, - {0x2150, 0x215f, 1}, - {0x2189, 0x2460, 727}, - {0x2461, 0x249b, 1}, - {0x24ea, 0x24ff, 1}, - {0x2776, 0x2793, 1}, - {0x2cfd, 0x3192, 1173}, - {0x3193, 0x3195, 1}, - {0x3220, 0x3229, 1}, - {0x3248, 0x324f, 1}, - {0x3251, 0x325f, 1}, - {0x3280, 0x3289, 1}, - {0x32b1, 0x32bf, 1}, - {0xa830, 0xa835, 1}, - ], - R32: [ - {0x10107, 0x10133, 1}, - {0x10175, 0x10178, 1}, - {0x1018a, 0x1018b, 1}, - {0x102e1, 0x102fb, 1}, - {0x10320, 0x10323, 1}, - {0x10858, 0x1085f, 1}, - {0x10879, 0x1087f, 1}, - {0x108a7, 0x108af, 1}, - {0x108fb, 0x108ff, 1}, - {0x10916, 0x1091b, 1}, - {0x109bc, 0x109bd, 1}, - {0x109c0, 0x109cf, 1}, - {0x109d2, 0x109ff, 1}, - {0x10a40, 0x10a48, 1}, - {0x10a7d, 0x10a7e, 1}, - {0x10a9d, 0x10a9f, 1}, - {0x10aeb, 0x10aef, 1}, - {0x10b58, 0x10b5f, 1}, - {0x10b78, 0x10b7f, 1}, - {0x10ba9, 0x10baf, 1}, - {0x10cfa, 0x10cff, 1}, - {0x10e60, 0x10e7e, 1}, - {0x10f1d, 0x10f26, 1}, - {0x10f51, 0x10f54, 1}, - {0x10fc5, 0x10fcb, 1}, - {0x11052, 0x11065, 1}, - {0x111e1, 0x111f4, 1}, - {0x1173a, 0x1173b, 1}, - {0x118ea, 0x118f2, 1}, - {0x11c5a, 0x11c6c, 1}, - {0x11fc0, 0x11fd4, 1}, - {0x16b5b, 0x16b61, 1}, - {0x16e80, 0x16e96, 1}, - {0x1d2c0, 0x1d2d3, 1}, - {0x1d2e0, 0x1d2f3, 1}, - {0x1d360, 0x1d378, 1}, - {0x1e8c7, 0x1e8cf, 1}, - {0x1ec71, 0x1ecab, 1}, - {0x1ecad, 0x1ecaf, 1}, - {0x1ecb1, 0x1ecb4, 1}, - {0x1ed01, 0x1ed2d, 1}, - {0x1ed2f, 0x1ed3d, 1}, - {0x1f100, 0x1f10c, 1}, - ], - LatinOffset: 3, + R16: [ + {0x00b2, 0x00b3, 1}, + {0x00b9, 0x00bc, 3}, + {0x00bd, 0x00be, 1}, + {0x09f4, 0x09f9, 1}, + {0x0b72, 0x0b77, 1}, + {0x0bf0, 0x0bf2, 1}, + {0x0c78, 0x0c7e, 1}, + {0x0d58, 0x0d5e, 1}, + {0x0d70, 0x0d78, 1}, + {0x0f2a, 0x0f33, 1}, + {0x1369, 0x137c, 1}, + {0x17f0, 0x17f9, 1}, + {0x19da, 0x2070, 1686}, + {0x2074, 0x2079, 1}, + {0x2080, 0x2089, 1}, + {0x2150, 0x215f, 1}, + {0x2189, 0x2460, 727}, + {0x2461, 0x249b, 1}, + {0x24ea, 0x24ff, 1}, + {0x2776, 0x2793, 1}, + {0x2cfd, 0x3192, 1173}, + {0x3193, 0x3195, 1}, + {0x3220, 0x3229, 1}, + {0x3248, 0x324f, 1}, + {0x3251, 0x325f, 1}, + {0x3280, 0x3289, 1}, + {0x32b1, 0x32bf, 1}, + {0xa830, 0xa835, 1}, + ], + R32: [ + {0x10107, 0x10133, 1}, + {0x10175, 0x10178, 1}, + {0x1018a, 0x1018b, 1}, + {0x102e1, 0x102fb, 1}, + {0x10320, 0x10323, 1}, + {0x10858, 0x1085f, 1}, + {0x10879, 0x1087f, 1}, + {0x108a7, 0x108af, 1}, + {0x108fb, 0x108ff, 1}, + {0x10916, 0x1091b, 1}, + {0x109bc, 0x109bd, 1}, + {0x109c0, 0x109cf, 1}, + {0x109d2, 0x109ff, 1}, + {0x10a40, 0x10a48, 1}, + {0x10a7d, 0x10a7e, 1}, + {0x10a9d, 0x10a9f, 1}, + {0x10aeb, 0x10aef, 1}, + {0x10b58, 0x10b5f, 1}, + {0x10b78, 0x10b7f, 1}, + {0x10ba9, 0x10baf, 1}, + {0x10cfa, 0x10cff, 1}, + {0x10e60, 0x10e7e, 1}, + {0x10f1d, 0x10f26, 1}, + {0x10f51, 0x10f54, 1}, + {0x10fc5, 0x10fcb, 1}, + {0x11052, 0x11065, 1}, + {0x111e1, 0x111f4, 1}, + {0x1173a, 0x1173b, 1}, + {0x118ea, 0x118f2, 1}, + {0x11c5a, 0x11c6c, 1}, + {0x11fc0, 0x11fd4, 1}, + {0x16b5b, 0x16b61, 1}, + {0x16e80, 0x16e96, 1}, + {0x1d2c0, 0x1d2d3, 1}, + {0x1d2e0, 0x1d2f3, 1}, + {0x1d360, 0x1d378, 1}, + {0x1e8c7, 0x1e8cf, 1}, + {0x1ec71, 0x1ecab, 1}, + {0x1ecad, 0x1ecaf, 1}, + {0x1ecb1, 0x1ecb4, 1}, + {0x1ed01, 0x1ed2d, 1}, + {0x1ed2f, 0x1ed3d, 1}, + {0x1f100, 0x1f10c, 1}, + ], + LatinOffset: 3, } static _P = &RangeTable{ - R16: [ - {0x0021, 0x0023, 1}, - {0x0025, 0x002a, 1}, - {0x002c, 0x002f, 1}, - {0x003a, 0x003b, 1}, - {0x003f, 0x0040, 1}, - {0x005b, 0x005d, 1}, - {0x005f, 0x007b, 28}, - {0x007d, 0x00a1, 36}, - {0x00a7, 0x00ab, 4}, - {0x00b6, 0x00b7, 1}, - {0x00bb, 0x00bf, 4}, - {0x037e, 0x0387, 9}, - {0x055a, 0x055f, 1}, - {0x0589, 0x058a, 1}, - {0x05be, 0x05c0, 2}, - {0x05c3, 0x05c6, 3}, - {0x05f3, 0x05f4, 1}, - {0x0609, 0x060a, 1}, - {0x060c, 0x060d, 1}, - {0x061b, 0x061d, 2}, - {0x061e, 0x061f, 1}, - {0x066a, 0x066d, 1}, - {0x06d4, 0x0700, 44}, - {0x0701, 0x070d, 1}, - {0x07f7, 0x07f9, 1}, - {0x0830, 0x083e, 1}, - {0x085e, 0x0964, 262}, - {0x0965, 0x0970, 11}, - {0x09fd, 0x0a76, 121}, - {0x0af0, 0x0c77, 391}, - {0x0c84, 0x0df4, 368}, - {0x0e4f, 0x0e5a, 11}, - {0x0e5b, 0x0f04, 169}, - {0x0f05, 0x0f12, 1}, - {0x0f14, 0x0f3a, 38}, - {0x0f3b, 0x0f3d, 1}, - {0x0f85, 0x0fd0, 75}, - {0x0fd1, 0x0fd4, 1}, - {0x0fd9, 0x0fda, 1}, - {0x104a, 0x104f, 1}, - {0x10fb, 0x1360, 613}, - {0x1361, 0x1368, 1}, - {0x1400, 0x166e, 622}, - {0x169b, 0x169c, 1}, - {0x16eb, 0x16ed, 1}, - {0x1735, 0x1736, 1}, - {0x17d4, 0x17d6, 1}, - {0x17d8, 0x17da, 1}, - {0x1800, 0x180a, 1}, - {0x1944, 0x1945, 1}, - {0x1a1e, 0x1a1f, 1}, - {0x1aa0, 0x1aa6, 1}, - {0x1aa8, 0x1aad, 1}, - {0x1b5a, 0x1b60, 1}, - {0x1b7d, 0x1b7e, 1}, - {0x1bfc, 0x1bff, 1}, - {0x1c3b, 0x1c3f, 1}, - {0x1c7e, 0x1c7f, 1}, - {0x1cc0, 0x1cc7, 1}, - {0x1cd3, 0x2010, 829}, - {0x2011, 0x2027, 1}, - {0x2030, 0x2043, 1}, - {0x2045, 0x2051, 1}, - {0x2053, 0x205e, 1}, - {0x207d, 0x207e, 1}, - {0x208d, 0x208e, 1}, - {0x2308, 0x230b, 1}, - {0x2329, 0x232a, 1}, - {0x2768, 0x2775, 1}, - {0x27c5, 0x27c6, 1}, - {0x27e6, 0x27ef, 1}, - {0x2983, 0x2998, 1}, - {0x29d8, 0x29db, 1}, - {0x29fc, 0x29fd, 1}, - {0x2cf9, 0x2cfc, 1}, - {0x2cfe, 0x2cff, 1}, - {0x2d70, 0x2e00, 144}, - {0x2e01, 0x2e2e, 1}, - {0x2e30, 0x2e4f, 1}, - {0x2e52, 0x2e5d, 1}, - {0x3001, 0x3003, 1}, - {0x3008, 0x3011, 1}, - {0x3014, 0x301f, 1}, - {0x3030, 0x303d, 13}, - {0x30a0, 0x30fb, 91}, - {0xa4fe, 0xa4ff, 1}, - {0xa60d, 0xa60f, 1}, - {0xa673, 0xa67e, 11}, - {0xa6f2, 0xa6f7, 1}, - {0xa874, 0xa877, 1}, - {0xa8ce, 0xa8cf, 1}, - {0xa8f8, 0xa8fa, 1}, - {0xa8fc, 0xa92e, 50}, - {0xa92f, 0xa95f, 48}, - {0xa9c1, 0xa9cd, 1}, - {0xa9de, 0xa9df, 1}, - {0xaa5c, 0xaa5f, 1}, - {0xaade, 0xaadf, 1}, - {0xaaf0, 0xaaf1, 1}, - {0xabeb, 0xfd3e, 20819}, - {0xfd3f, 0xfe10, 209}, - {0xfe11, 0xfe19, 1}, - {0xfe30, 0xfe52, 1}, - {0xfe54, 0xfe61, 1}, - {0xfe63, 0xfe68, 5}, - {0xfe6a, 0xfe6b, 1}, - {0xff01, 0xff03, 1}, - {0xff05, 0xff0a, 1}, - {0xff0c, 0xff0f, 1}, - {0xff1a, 0xff1b, 1}, - {0xff1f, 0xff20, 1}, - {0xff3b, 0xff3d, 1}, - {0xff3f, 0xff5b, 28}, - {0xff5d, 0xff5f, 2}, - {0xff60, 0xff65, 1}, - ], - R32: [ - {0x10100, 0x10102, 1}, - {0x1039f, 0x103d0, 49}, - {0x1056f, 0x10857, 744}, - {0x1091f, 0x1093f, 32}, - {0x10a50, 0x10a58, 1}, - {0x10a7f, 0x10af0, 113}, - {0x10af1, 0x10af6, 1}, - {0x10b39, 0x10b3f, 1}, - {0x10b99, 0x10b9c, 1}, - {0x10ead, 0x10f55, 168}, - {0x10f56, 0x10f59, 1}, - {0x10f86, 0x10f89, 1}, - {0x11047, 0x1104d, 1}, - {0x110bb, 0x110bc, 1}, - {0x110be, 0x110c1, 1}, - {0x11140, 0x11143, 1}, - {0x11174, 0x11175, 1}, - {0x111c5, 0x111c8, 1}, - {0x111cd, 0x111db, 14}, - {0x111dd, 0x111df, 1}, - {0x11238, 0x1123d, 1}, - {0x112a9, 0x1144b, 418}, - {0x1144c, 0x1144f, 1}, - {0x1145a, 0x1145b, 1}, - {0x1145d, 0x114c6, 105}, - {0x115c1, 0x115d7, 1}, - {0x11641, 0x11643, 1}, - {0x11660, 0x1166c, 1}, - {0x116b9, 0x1173c, 131}, - {0x1173d, 0x1173e, 1}, - {0x1183b, 0x11944, 265}, - {0x11945, 0x11946, 1}, - {0x119e2, 0x11a3f, 93}, - {0x11a40, 0x11a46, 1}, - {0x11a9a, 0x11a9c, 1}, - {0x11a9e, 0x11aa2, 1}, - {0x11b00, 0x11b09, 1}, - {0x11c41, 0x11c45, 1}, - {0x11c70, 0x11c71, 1}, - {0x11ef7, 0x11ef8, 1}, - {0x11f43, 0x11f4f, 1}, - {0x11fff, 0x12470, 1137}, - {0x12471, 0x12474, 1}, - {0x12ff1, 0x12ff2, 1}, - {0x16a6e, 0x16a6f, 1}, - {0x16af5, 0x16b37, 66}, - {0x16b38, 0x16b3b, 1}, - {0x16b44, 0x16e97, 851}, - {0x16e98, 0x16e9a, 1}, - {0x16fe2, 0x1bc9f, 19645}, - {0x1da87, 0x1da8b, 1}, - {0x1e95e, 0x1e95f, 1}, - ], - LatinOffset: 11, + R16: [ + {0x0021, 0x0023, 1}, + {0x0025, 0x002a, 1}, + {0x002c, 0x002f, 1}, + {0x003a, 0x003b, 1}, + {0x003f, 0x0040, 1}, + {0x005b, 0x005d, 1}, + {0x005f, 0x007b, 28}, + {0x007d, 0x00a1, 36}, + {0x00a7, 0x00ab, 4}, + {0x00b6, 0x00b7, 1}, + {0x00bb, 0x00bf, 4}, + {0x037e, 0x0387, 9}, + {0x055a, 0x055f, 1}, + {0x0589, 0x058a, 1}, + {0x05be, 0x05c0, 2}, + {0x05c3, 0x05c6, 3}, + {0x05f3, 0x05f4, 1}, + {0x0609, 0x060a, 1}, + {0x060c, 0x060d, 1}, + {0x061b, 0x061d, 2}, + {0x061e, 0x061f, 1}, + {0x066a, 0x066d, 1}, + {0x06d4, 0x0700, 44}, + {0x0701, 0x070d, 1}, + {0x07f7, 0x07f9, 1}, + {0x0830, 0x083e, 1}, + {0x085e, 0x0964, 262}, + {0x0965, 0x0970, 11}, + {0x09fd, 0x0a76, 121}, + {0x0af0, 0x0c77, 391}, + {0x0c84, 0x0df4, 368}, + {0x0e4f, 0x0e5a, 11}, + {0x0e5b, 0x0f04, 169}, + {0x0f05, 0x0f12, 1}, + {0x0f14, 0x0f3a, 38}, + {0x0f3b, 0x0f3d, 1}, + {0x0f85, 0x0fd0, 75}, + {0x0fd1, 0x0fd4, 1}, + {0x0fd9, 0x0fda, 1}, + {0x104a, 0x104f, 1}, + {0x10fb, 0x1360, 613}, + {0x1361, 0x1368, 1}, + {0x1400, 0x166e, 622}, + {0x169b, 0x169c, 1}, + {0x16eb, 0x16ed, 1}, + {0x1735, 0x1736, 1}, + {0x17d4, 0x17d6, 1}, + {0x17d8, 0x17da, 1}, + {0x1800, 0x180a, 1}, + {0x1944, 0x1945, 1}, + {0x1a1e, 0x1a1f, 1}, + {0x1aa0, 0x1aa6, 1}, + {0x1aa8, 0x1aad, 1}, + {0x1b5a, 0x1b60, 1}, + {0x1b7d, 0x1b7e, 1}, + {0x1bfc, 0x1bff, 1}, + {0x1c3b, 0x1c3f, 1}, + {0x1c7e, 0x1c7f, 1}, + {0x1cc0, 0x1cc7, 1}, + {0x1cd3, 0x2010, 829}, + {0x2011, 0x2027, 1}, + {0x2030, 0x2043, 1}, + {0x2045, 0x2051, 1}, + {0x2053, 0x205e, 1}, + {0x207d, 0x207e, 1}, + {0x208d, 0x208e, 1}, + {0x2308, 0x230b, 1}, + {0x2329, 0x232a, 1}, + {0x2768, 0x2775, 1}, + {0x27c5, 0x27c6, 1}, + {0x27e6, 0x27ef, 1}, + {0x2983, 0x2998, 1}, + {0x29d8, 0x29db, 1}, + {0x29fc, 0x29fd, 1}, + {0x2cf9, 0x2cfc, 1}, + {0x2cfe, 0x2cff, 1}, + {0x2d70, 0x2e00, 144}, + {0x2e01, 0x2e2e, 1}, + {0x2e30, 0x2e4f, 1}, + {0x2e52, 0x2e5d, 1}, + {0x3001, 0x3003, 1}, + {0x3008, 0x3011, 1}, + {0x3014, 0x301f, 1}, + {0x3030, 0x303d, 13}, + {0x30a0, 0x30fb, 91}, + {0xa4fe, 0xa4ff, 1}, + {0xa60d, 0xa60f, 1}, + {0xa673, 0xa67e, 11}, + {0xa6f2, 0xa6f7, 1}, + {0xa874, 0xa877, 1}, + {0xa8ce, 0xa8cf, 1}, + {0xa8f8, 0xa8fa, 1}, + {0xa8fc, 0xa92e, 50}, + {0xa92f, 0xa95f, 48}, + {0xa9c1, 0xa9cd, 1}, + {0xa9de, 0xa9df, 1}, + {0xaa5c, 0xaa5f, 1}, + {0xaade, 0xaadf, 1}, + {0xaaf0, 0xaaf1, 1}, + {0xabeb, 0xfd3e, 20819}, + {0xfd3f, 0xfe10, 209}, + {0xfe11, 0xfe19, 1}, + {0xfe30, 0xfe52, 1}, + {0xfe54, 0xfe61, 1}, + {0xfe63, 0xfe68, 5}, + {0xfe6a, 0xfe6b, 1}, + {0xff01, 0xff03, 1}, + {0xff05, 0xff0a, 1}, + {0xff0c, 0xff0f, 1}, + {0xff1a, 0xff1b, 1}, + {0xff1f, 0xff20, 1}, + {0xff3b, 0xff3d, 1}, + {0xff3f, 0xff5b, 28}, + {0xff5d, 0xff5f, 2}, + {0xff60, 0xff65, 1}, + ], + R32: [ + {0x10100, 0x10102, 1}, + {0x1039f, 0x103d0, 49}, + {0x1056f, 0x10857, 744}, + {0x1091f, 0x1093f, 32}, + {0x10a50, 0x10a58, 1}, + {0x10a7f, 0x10af0, 113}, + {0x10af1, 0x10af6, 1}, + {0x10b39, 0x10b3f, 1}, + {0x10b99, 0x10b9c, 1}, + {0x10ead, 0x10f55, 168}, + {0x10f56, 0x10f59, 1}, + {0x10f86, 0x10f89, 1}, + {0x11047, 0x1104d, 1}, + {0x110bb, 0x110bc, 1}, + {0x110be, 0x110c1, 1}, + {0x11140, 0x11143, 1}, + {0x11174, 0x11175, 1}, + {0x111c5, 0x111c8, 1}, + {0x111cd, 0x111db, 14}, + {0x111dd, 0x111df, 1}, + {0x11238, 0x1123d, 1}, + {0x112a9, 0x1144b, 418}, + {0x1144c, 0x1144f, 1}, + {0x1145a, 0x1145b, 1}, + {0x1145d, 0x114c6, 105}, + {0x115c1, 0x115d7, 1}, + {0x11641, 0x11643, 1}, + {0x11660, 0x1166c, 1}, + {0x116b9, 0x1173c, 131}, + {0x1173d, 0x1173e, 1}, + {0x1183b, 0x11944, 265}, + {0x11945, 0x11946, 1}, + {0x119e2, 0x11a3f, 93}, + {0x11a40, 0x11a46, 1}, + {0x11a9a, 0x11a9c, 1}, + {0x11a9e, 0x11aa2, 1}, + {0x11b00, 0x11b09, 1}, + {0x11c41, 0x11c45, 1}, + {0x11c70, 0x11c71, 1}, + {0x11ef7, 0x11ef8, 1}, + {0x11f43, 0x11f4f, 1}, + {0x11fff, 0x12470, 1137}, + {0x12471, 0x12474, 1}, + {0x12ff1, 0x12ff2, 1}, + {0x16a6e, 0x16a6f, 1}, + {0x16af5, 0x16b37, 66}, + {0x16b38, 0x16b3b, 1}, + {0x16b44, 0x16e97, 851}, + {0x16e98, 0x16e9a, 1}, + {0x16fe2, 0x1bc9f, 19645}, + {0x1da87, 0x1da8b, 1}, + {0x1e95e, 0x1e95f, 1}, + ], + LatinOffset: 11, } static _PC = &RangeTable{ - R16: [ - {0x005f, 0x203f, 8160}, - {0x2040, 0x2054, 20}, - {0xfe33, 0xfe34, 1}, - {0xfe4d, 0xfe4f, 1}, - {0xff3f, 0xff3f, 1}, - ], + R16: [ + {0x005f, 0x203f, 8160}, + {0x2040, 0x2054, 20}, + {0xfe33, 0xfe34, 1}, + {0xfe4d, 0xfe4f, 1}, + {0xff3f, 0xff3f, 1}, + ], } static _PD = &RangeTable{ - R16: [ - {0x002d, 0x058a, 1373}, - {0x05be, 0x1400, 3650}, - {0x1806, 0x2010, 2058}, - {0x2011, 0x2015, 1}, - {0x2e17, 0x2e1a, 3}, - {0x2e3a, 0x2e3b, 1}, - {0x2e40, 0x2e5d, 29}, - {0x301c, 0x3030, 20}, - {0x30a0, 0xfe31, 52625}, - {0xfe32, 0xfe58, 38}, - {0xfe63, 0xff0d, 170}, - ], - R32: [ - {0x10ead, 0x10ead, 1}, - ], + R16: [ + {0x002d, 0x058a, 1373}, + {0x05be, 0x1400, 3650}, + {0x1806, 0x2010, 2058}, + {0x2011, 0x2015, 1}, + {0x2e17, 0x2e1a, 3}, + {0x2e3a, 0x2e3b, 1}, + {0x2e40, 0x2e5d, 29}, + {0x301c, 0x3030, 20}, + {0x30a0, 0xfe31, 52625}, + {0xfe32, 0xfe58, 38}, + {0xfe63, 0xff0d, 170}, + ], + R32: [ + {0x10ead, 0x10ead, 1}, + ], } static _PE = &RangeTable{ - R16: [ - {0x0029, 0x005d, 52}, - {0x007d, 0x0f3b, 3774}, - {0x0f3d, 0x169c, 1887}, - {0x2046, 0x207e, 56}, - {0x208e, 0x2309, 635}, - {0x230b, 0x232a, 31}, - {0x2769, 0x2775, 2}, - {0x27c6, 0x27e7, 33}, - {0x27e9, 0x27ef, 2}, - {0x2984, 0x2998, 2}, - {0x29d9, 0x29db, 2}, - {0x29fd, 0x2e23, 1062}, - {0x2e25, 0x2e29, 2}, - {0x2e56, 0x2e5c, 2}, - {0x3009, 0x3011, 2}, - {0x3015, 0x301b, 2}, - {0x301e, 0x301f, 1}, - {0xfd3e, 0xfe18, 218}, - {0xfe36, 0xfe44, 2}, - {0xfe48, 0xfe5a, 18}, - {0xfe5c, 0xfe5e, 2}, - {0xff09, 0xff3d, 52}, - {0xff5d, 0xff63, 3}, - ], - LatinOffset: 1, + R16: [ + {0x0029, 0x005d, 52}, + {0x007d, 0x0f3b, 3774}, + {0x0f3d, 0x169c, 1887}, + {0x2046, 0x207e, 56}, + {0x208e, 0x2309, 635}, + {0x230b, 0x232a, 31}, + {0x2769, 0x2775, 2}, + {0x27c6, 0x27e7, 33}, + {0x27e9, 0x27ef, 2}, + {0x2984, 0x2998, 2}, + {0x29d9, 0x29db, 2}, + {0x29fd, 0x2e23, 1062}, + {0x2e25, 0x2e29, 2}, + {0x2e56, 0x2e5c, 2}, + {0x3009, 0x3011, 2}, + {0x3015, 0x301b, 2}, + {0x301e, 0x301f, 1}, + {0xfd3e, 0xfe18, 218}, + {0xfe36, 0xfe44, 2}, + {0xfe48, 0xfe5a, 18}, + {0xfe5c, 0xfe5e, 2}, + {0xff09, 0xff3d, 52}, + {0xff5d, 0xff63, 3}, + ], + LatinOffset: 1, } static _PF = &RangeTable{ - R16: [ - {0x00bb, 0x2019, 8030}, - {0x201d, 0x203a, 29}, - {0x2e03, 0x2e05, 2}, - {0x2e0a, 0x2e0d, 3}, - {0x2e1d, 0x2e21, 4}, - ], + R16: [ + {0x00bb, 0x2019, 8030}, + {0x201d, 0x203a, 29}, + {0x2e03, 0x2e05, 2}, + {0x2e0a, 0x2e0d, 3}, + {0x2e1d, 0x2e21, 4}, + ], } static _PI = &RangeTable{ - R16: [ - {0x00ab, 0x2018, 8045}, - {0x201b, 0x201c, 1}, - {0x201f, 0x2039, 26}, - {0x2e02, 0x2e04, 2}, - {0x2e09, 0x2e0c, 3}, - {0x2e1c, 0x2e20, 4}, - ], + R16: [ + {0x00ab, 0x2018, 8045}, + {0x201b, 0x201c, 1}, + {0x201f, 0x2039, 26}, + {0x2e02, 0x2e04, 2}, + {0x2e09, 0x2e0c, 3}, + {0x2e1c, 0x2e20, 4}, + ], } static _PO = &RangeTable{ - R16: [ - {0x0021, 0x0023, 1}, - {0x0025, 0x0027, 1}, - {0x002a, 0x002e, 2}, - {0x002f, 0x003a, 11}, - {0x003b, 0x003f, 4}, - {0x0040, 0x005c, 28}, - {0x00a1, 0x00a7, 6}, - {0x00b6, 0x00b7, 1}, - {0x00bf, 0x037e, 703}, - {0x0387, 0x055a, 467}, - {0x055b, 0x055f, 1}, - {0x0589, 0x05c0, 55}, - {0x05c3, 0x05c6, 3}, - {0x05f3, 0x05f4, 1}, - {0x0609, 0x060a, 1}, - {0x060c, 0x060d, 1}, - {0x061b, 0x061d, 2}, - {0x061e, 0x061f, 1}, - {0x066a, 0x066d, 1}, - {0x06d4, 0x0700, 44}, - {0x0701, 0x070d, 1}, - {0x07f7, 0x07f9, 1}, - {0x0830, 0x083e, 1}, - {0x085e, 0x0964, 262}, - {0x0965, 0x0970, 11}, - {0x09fd, 0x0a76, 121}, - {0x0af0, 0x0c77, 391}, - {0x0c84, 0x0df4, 368}, - {0x0e4f, 0x0e5a, 11}, - {0x0e5b, 0x0f04, 169}, - {0x0f05, 0x0f12, 1}, - {0x0f14, 0x0f85, 113}, - {0x0fd0, 0x0fd4, 1}, - {0x0fd9, 0x0fda, 1}, - {0x104a, 0x104f, 1}, - {0x10fb, 0x1360, 613}, - {0x1361, 0x1368, 1}, - {0x166e, 0x16eb, 125}, - {0x16ec, 0x16ed, 1}, - {0x1735, 0x1736, 1}, - {0x17d4, 0x17d6, 1}, - {0x17d8, 0x17da, 1}, - {0x1800, 0x1805, 1}, - {0x1807, 0x180a, 1}, - {0x1944, 0x1945, 1}, - {0x1a1e, 0x1a1f, 1}, - {0x1aa0, 0x1aa6, 1}, - {0x1aa8, 0x1aad, 1}, - {0x1b5a, 0x1b60, 1}, - {0x1b7d, 0x1b7e, 1}, - {0x1bfc, 0x1bff, 1}, - {0x1c3b, 0x1c3f, 1}, - {0x1c7e, 0x1c7f, 1}, - {0x1cc0, 0x1cc7, 1}, - {0x1cd3, 0x2016, 835}, - {0x2017, 0x2020, 9}, - {0x2021, 0x2027, 1}, - {0x2030, 0x2038, 1}, - {0x203b, 0x203e, 1}, - {0x2041, 0x2043, 1}, - {0x2047, 0x2051, 1}, - {0x2053, 0x2055, 2}, - {0x2056, 0x205e, 1}, - {0x2cf9, 0x2cfc, 1}, - {0x2cfe, 0x2cff, 1}, - {0x2d70, 0x2e00, 144}, - {0x2e01, 0x2e06, 5}, - {0x2e07, 0x2e08, 1}, - {0x2e0b, 0x2e0e, 3}, - {0x2e0f, 0x2e16, 1}, - {0x2e18, 0x2e19, 1}, - {0x2e1b, 0x2e1e, 3}, - {0x2e1f, 0x2e2a, 11}, - {0x2e2b, 0x2e2e, 1}, - {0x2e30, 0x2e39, 1}, - {0x2e3c, 0x2e3f, 1}, - {0x2e41, 0x2e43, 2}, - {0x2e44, 0x2e4f, 1}, - {0x2e52, 0x2e54, 1}, - {0x3001, 0x3003, 1}, - {0x303d, 0x30fb, 190}, - {0xa4fe, 0xa4ff, 1}, - {0xa60d, 0xa60f, 1}, - {0xa673, 0xa67e, 11}, - {0xa6f2, 0xa6f7, 1}, - {0xa874, 0xa877, 1}, - {0xa8ce, 0xa8cf, 1}, - {0xa8f8, 0xa8fa, 1}, - {0xa8fc, 0xa92e, 50}, - {0xa92f, 0xa95f, 48}, - {0xa9c1, 0xa9cd, 1}, - {0xa9de, 0xa9df, 1}, - {0xaa5c, 0xaa5f, 1}, - {0xaade, 0xaadf, 1}, - {0xaaf0, 0xaaf1, 1}, - {0xabeb, 0xfe10, 21029}, - {0xfe11, 0xfe16, 1}, - {0xfe19, 0xfe30, 23}, - {0xfe45, 0xfe46, 1}, - {0xfe49, 0xfe4c, 1}, - {0xfe50, 0xfe52, 1}, - {0xfe54, 0xfe57, 1}, - {0xfe5f, 0xfe61, 1}, - {0xfe68, 0xfe6a, 2}, - {0xfe6b, 0xff01, 150}, - {0xff02, 0xff03, 1}, - {0xff05, 0xff07, 1}, - {0xff0a, 0xff0e, 2}, - {0xff0f, 0xff1a, 11}, - {0xff1b, 0xff1f, 4}, - {0xff20, 0xff3c, 28}, - {0xff61, 0xff64, 3}, - {0xff65, 0xff65, 1}, - ], - R32: [ - {0x10100, 0x10102, 1}, - {0x1039f, 0x103d0, 49}, - {0x1056f, 0x10857, 744}, - {0x1091f, 0x1093f, 32}, - {0x10a50, 0x10a58, 1}, - {0x10a7f, 0x10af0, 113}, - {0x10af1, 0x10af6, 1}, - {0x10b39, 0x10b3f, 1}, - {0x10b99, 0x10b9c, 1}, - {0x10f55, 0x10f59, 1}, - {0x10f86, 0x10f89, 1}, - {0x11047, 0x1104d, 1}, - {0x110bb, 0x110bc, 1}, - {0x110be, 0x110c1, 1}, - {0x11140, 0x11143, 1}, - {0x11174, 0x11175, 1}, - {0x111c5, 0x111c8, 1}, - {0x111cd, 0x111db, 14}, - {0x111dd, 0x111df, 1}, - {0x11238, 0x1123d, 1}, - {0x112a9, 0x1144b, 418}, - {0x1144c, 0x1144f, 1}, - {0x1145a, 0x1145b, 1}, - {0x1145d, 0x114c6, 105}, - {0x115c1, 0x115d7, 1}, - {0x11641, 0x11643, 1}, - {0x11660, 0x1166c, 1}, - {0x116b9, 0x1173c, 131}, - {0x1173d, 0x1173e, 1}, - {0x1183b, 0x11944, 265}, - {0x11945, 0x11946, 1}, - {0x119e2, 0x11a3f, 93}, - {0x11a40, 0x11a46, 1}, - {0x11a9a, 0x11a9c, 1}, - {0x11a9e, 0x11aa2, 1}, - {0x11b00, 0x11b09, 1}, - {0x11c41, 0x11c45, 1}, - {0x11c70, 0x11c71, 1}, - {0x11ef7, 0x11ef8, 1}, - {0x11f43, 0x11f4f, 1}, - {0x11fff, 0x12470, 1137}, - {0x12471, 0x12474, 1}, - {0x12ff1, 0x12ff2, 1}, - {0x16a6e, 0x16a6f, 1}, - {0x16af5, 0x16b37, 66}, - {0x16b38, 0x16b3b, 1}, - {0x16b44, 0x16e97, 851}, - {0x16e98, 0x16e9a, 1}, - {0x16fe2, 0x1bc9f, 19645}, - {0x1da87, 0x1da8b, 1}, - {0x1e95e, 0x1e95f, 1}, - ], - LatinOffset: 8, + R16: [ + {0x0021, 0x0023, 1}, + {0x0025, 0x0027, 1}, + {0x002a, 0x002e, 2}, + {0x002f, 0x003a, 11}, + {0x003b, 0x003f, 4}, + {0x0040, 0x005c, 28}, + {0x00a1, 0x00a7, 6}, + {0x00b6, 0x00b7, 1}, + {0x00bf, 0x037e, 703}, + {0x0387, 0x055a, 467}, + {0x055b, 0x055f, 1}, + {0x0589, 0x05c0, 55}, + {0x05c3, 0x05c6, 3}, + {0x05f3, 0x05f4, 1}, + {0x0609, 0x060a, 1}, + {0x060c, 0x060d, 1}, + {0x061b, 0x061d, 2}, + {0x061e, 0x061f, 1}, + {0x066a, 0x066d, 1}, + {0x06d4, 0x0700, 44}, + {0x0701, 0x070d, 1}, + {0x07f7, 0x07f9, 1}, + {0x0830, 0x083e, 1}, + {0x085e, 0x0964, 262}, + {0x0965, 0x0970, 11}, + {0x09fd, 0x0a76, 121}, + {0x0af0, 0x0c77, 391}, + {0x0c84, 0x0df4, 368}, + {0x0e4f, 0x0e5a, 11}, + {0x0e5b, 0x0f04, 169}, + {0x0f05, 0x0f12, 1}, + {0x0f14, 0x0f85, 113}, + {0x0fd0, 0x0fd4, 1}, + {0x0fd9, 0x0fda, 1}, + {0x104a, 0x104f, 1}, + {0x10fb, 0x1360, 613}, + {0x1361, 0x1368, 1}, + {0x166e, 0x16eb, 125}, + {0x16ec, 0x16ed, 1}, + {0x1735, 0x1736, 1}, + {0x17d4, 0x17d6, 1}, + {0x17d8, 0x17da, 1}, + {0x1800, 0x1805, 1}, + {0x1807, 0x180a, 1}, + {0x1944, 0x1945, 1}, + {0x1a1e, 0x1a1f, 1}, + {0x1aa0, 0x1aa6, 1}, + {0x1aa8, 0x1aad, 1}, + {0x1b5a, 0x1b60, 1}, + {0x1b7d, 0x1b7e, 1}, + {0x1bfc, 0x1bff, 1}, + {0x1c3b, 0x1c3f, 1}, + {0x1c7e, 0x1c7f, 1}, + {0x1cc0, 0x1cc7, 1}, + {0x1cd3, 0x2016, 835}, + {0x2017, 0x2020, 9}, + {0x2021, 0x2027, 1}, + {0x2030, 0x2038, 1}, + {0x203b, 0x203e, 1}, + {0x2041, 0x2043, 1}, + {0x2047, 0x2051, 1}, + {0x2053, 0x2055, 2}, + {0x2056, 0x205e, 1}, + {0x2cf9, 0x2cfc, 1}, + {0x2cfe, 0x2cff, 1}, + {0x2d70, 0x2e00, 144}, + {0x2e01, 0x2e06, 5}, + {0x2e07, 0x2e08, 1}, + {0x2e0b, 0x2e0e, 3}, + {0x2e0f, 0x2e16, 1}, + {0x2e18, 0x2e19, 1}, + {0x2e1b, 0x2e1e, 3}, + {0x2e1f, 0x2e2a, 11}, + {0x2e2b, 0x2e2e, 1}, + {0x2e30, 0x2e39, 1}, + {0x2e3c, 0x2e3f, 1}, + {0x2e41, 0x2e43, 2}, + {0x2e44, 0x2e4f, 1}, + {0x2e52, 0x2e54, 1}, + {0x3001, 0x3003, 1}, + {0x303d, 0x30fb, 190}, + {0xa4fe, 0xa4ff, 1}, + {0xa60d, 0xa60f, 1}, + {0xa673, 0xa67e, 11}, + {0xa6f2, 0xa6f7, 1}, + {0xa874, 0xa877, 1}, + {0xa8ce, 0xa8cf, 1}, + {0xa8f8, 0xa8fa, 1}, + {0xa8fc, 0xa92e, 50}, + {0xa92f, 0xa95f, 48}, + {0xa9c1, 0xa9cd, 1}, + {0xa9de, 0xa9df, 1}, + {0xaa5c, 0xaa5f, 1}, + {0xaade, 0xaadf, 1}, + {0xaaf0, 0xaaf1, 1}, + {0xabeb, 0xfe10, 21029}, + {0xfe11, 0xfe16, 1}, + {0xfe19, 0xfe30, 23}, + {0xfe45, 0xfe46, 1}, + {0xfe49, 0xfe4c, 1}, + {0xfe50, 0xfe52, 1}, + {0xfe54, 0xfe57, 1}, + {0xfe5f, 0xfe61, 1}, + {0xfe68, 0xfe6a, 2}, + {0xfe6b, 0xff01, 150}, + {0xff02, 0xff03, 1}, + {0xff05, 0xff07, 1}, + {0xff0a, 0xff0e, 2}, + {0xff0f, 0xff1a, 11}, + {0xff1b, 0xff1f, 4}, + {0xff20, 0xff3c, 28}, + {0xff61, 0xff64, 3}, + {0xff65, 0xff65, 1}, + ], + R32: [ + {0x10100, 0x10102, 1}, + {0x1039f, 0x103d0, 49}, + {0x1056f, 0x10857, 744}, + {0x1091f, 0x1093f, 32}, + {0x10a50, 0x10a58, 1}, + {0x10a7f, 0x10af0, 113}, + {0x10af1, 0x10af6, 1}, + {0x10b39, 0x10b3f, 1}, + {0x10b99, 0x10b9c, 1}, + {0x10f55, 0x10f59, 1}, + {0x10f86, 0x10f89, 1}, + {0x11047, 0x1104d, 1}, + {0x110bb, 0x110bc, 1}, + {0x110be, 0x110c1, 1}, + {0x11140, 0x11143, 1}, + {0x11174, 0x11175, 1}, + {0x111c5, 0x111c8, 1}, + {0x111cd, 0x111db, 14}, + {0x111dd, 0x111df, 1}, + {0x11238, 0x1123d, 1}, + {0x112a9, 0x1144b, 418}, + {0x1144c, 0x1144f, 1}, + {0x1145a, 0x1145b, 1}, + {0x1145d, 0x114c6, 105}, + {0x115c1, 0x115d7, 1}, + {0x11641, 0x11643, 1}, + {0x11660, 0x1166c, 1}, + {0x116b9, 0x1173c, 131}, + {0x1173d, 0x1173e, 1}, + {0x1183b, 0x11944, 265}, + {0x11945, 0x11946, 1}, + {0x119e2, 0x11a3f, 93}, + {0x11a40, 0x11a46, 1}, + {0x11a9a, 0x11a9c, 1}, + {0x11a9e, 0x11aa2, 1}, + {0x11b00, 0x11b09, 1}, + {0x11c41, 0x11c45, 1}, + {0x11c70, 0x11c71, 1}, + {0x11ef7, 0x11ef8, 1}, + {0x11f43, 0x11f4f, 1}, + {0x11fff, 0x12470, 1137}, + {0x12471, 0x12474, 1}, + {0x12ff1, 0x12ff2, 1}, + {0x16a6e, 0x16a6f, 1}, + {0x16af5, 0x16b37, 66}, + {0x16b38, 0x16b3b, 1}, + {0x16b44, 0x16e97, 851}, + {0x16e98, 0x16e9a, 1}, + {0x16fe2, 0x1bc9f, 19645}, + {0x1da87, 0x1da8b, 1}, + {0x1e95e, 0x1e95f, 1}, + ], + LatinOffset: 8, } static _PS = &RangeTable{ - R16: [ - {0x0028, 0x005b, 51}, - {0x007b, 0x0f3a, 3775}, - {0x0f3c, 0x169b, 1887}, - {0x201a, 0x201e, 4}, - {0x2045, 0x207d, 56}, - {0x208d, 0x2308, 635}, - {0x230a, 0x2329, 31}, - {0x2768, 0x2774, 2}, - {0x27c5, 0x27e6, 33}, - {0x27e8, 0x27ee, 2}, - {0x2983, 0x2997, 2}, - {0x29d8, 0x29da, 2}, - {0x29fc, 0x2e22, 1062}, - {0x2e24, 0x2e28, 2}, - {0x2e42, 0x2e55, 19}, - {0x2e57, 0x2e5b, 2}, - {0x3008, 0x3010, 2}, - {0x3014, 0x301a, 2}, - {0x301d, 0xfd3f, 52514}, - {0xfe17, 0xfe35, 30}, - {0xfe37, 0xfe43, 2}, - {0xfe47, 0xfe59, 18}, - {0xfe5b, 0xfe5d, 2}, - {0xff08, 0xff3b, 51}, - {0xff5b, 0xff5f, 4}, - {0xff62, 0xff62, 1}, - ], - LatinOffset: 1, + R16: [ + {0x0028, 0x005b, 51}, + {0x007b, 0x0f3a, 3775}, + {0x0f3c, 0x169b, 1887}, + {0x201a, 0x201e, 4}, + {0x2045, 0x207d, 56}, + {0x208d, 0x2308, 635}, + {0x230a, 0x2329, 31}, + {0x2768, 0x2774, 2}, + {0x27c5, 0x27e6, 33}, + {0x27e8, 0x27ee, 2}, + {0x2983, 0x2997, 2}, + {0x29d8, 0x29da, 2}, + {0x29fc, 0x2e22, 1062}, + {0x2e24, 0x2e28, 2}, + {0x2e42, 0x2e55, 19}, + {0x2e57, 0x2e5b, 2}, + {0x3008, 0x3010, 2}, + {0x3014, 0x301a, 2}, + {0x301d, 0xfd3f, 52514}, + {0xfe17, 0xfe35, 30}, + {0xfe37, 0xfe43, 2}, + {0xfe47, 0xfe59, 18}, + {0xfe5b, 0xfe5d, 2}, + {0xff08, 0xff3b, 51}, + {0xff5b, 0xff5f, 4}, + {0xff62, 0xff62, 1}, + ], + LatinOffset: 1, } static _S = &RangeTable{ - R16: [ - {0x0024, 0x002b, 7}, - {0x003c, 0x003e, 1}, - {0x005e, 0x0060, 2}, - {0x007c, 0x007e, 2}, - {0x00a2, 0x00a6, 1}, - {0x00a8, 0x00a9, 1}, - {0x00ac, 0x00ae, 2}, - {0x00af, 0x00b1, 1}, - {0x00b4, 0x00b8, 4}, - {0x00d7, 0x00f7, 32}, - {0x02c2, 0x02c5, 1}, - {0x02d2, 0x02df, 1}, - {0x02e5, 0x02eb, 1}, - {0x02ed, 0x02ef, 2}, - {0x02f0, 0x02ff, 1}, - {0x0375, 0x0384, 15}, - {0x0385, 0x03f6, 113}, - {0x0482, 0x058d, 267}, - {0x058e, 0x058f, 1}, - {0x0606, 0x0608, 1}, - {0x060b, 0x060e, 3}, - {0x060f, 0x06de, 207}, - {0x06e9, 0x06fd, 20}, - {0x06fe, 0x07f6, 248}, - {0x07fe, 0x07ff, 1}, - {0x0888, 0x09f2, 362}, - {0x09f3, 0x09fa, 7}, - {0x09fb, 0x0af1, 246}, - {0x0b70, 0x0bf3, 131}, - {0x0bf4, 0x0bfa, 1}, - {0x0c7f, 0x0d4f, 208}, - {0x0d79, 0x0e3f, 198}, - {0x0f01, 0x0f03, 1}, - {0x0f13, 0x0f15, 2}, - {0x0f16, 0x0f17, 1}, - {0x0f1a, 0x0f1f, 1}, - {0x0f34, 0x0f38, 2}, - {0x0fbe, 0x0fc5, 1}, - {0x0fc7, 0x0fcc, 1}, - {0x0fce, 0x0fcf, 1}, - {0x0fd5, 0x0fd8, 1}, - {0x109e, 0x109f, 1}, - {0x1390, 0x1399, 1}, - {0x166d, 0x17db, 366}, - {0x1940, 0x19de, 158}, - {0x19df, 0x19ff, 1}, - {0x1b61, 0x1b6a, 1}, - {0x1b74, 0x1b7c, 1}, - {0x1fbd, 0x1fbf, 2}, - {0x1fc0, 0x1fc1, 1}, - {0x1fcd, 0x1fcf, 1}, - {0x1fdd, 0x1fdf, 1}, - {0x1fed, 0x1fef, 1}, - {0x1ffd, 0x1ffe, 1}, - {0x2044, 0x2052, 14}, - {0x207a, 0x207c, 1}, - {0x208a, 0x208c, 1}, - {0x20a0, 0x20c0, 1}, - {0x2100, 0x2101, 1}, - {0x2103, 0x2106, 1}, - {0x2108, 0x2109, 1}, - {0x2114, 0x2116, 2}, - {0x2117, 0x2118, 1}, - {0x211e, 0x2123, 1}, - {0x2125, 0x2129, 2}, - {0x212e, 0x213a, 12}, - {0x213b, 0x2140, 5}, - {0x2141, 0x2144, 1}, - {0x214a, 0x214d, 1}, - {0x214f, 0x218a, 59}, - {0x218b, 0x2190, 5}, - {0x2191, 0x2307, 1}, - {0x230c, 0x2328, 1}, - {0x232b, 0x2426, 1}, - {0x2440, 0x244a, 1}, - {0x249c, 0x24e9, 1}, - {0x2500, 0x2767, 1}, - {0x2794, 0x27c4, 1}, - {0x27c7, 0x27e5, 1}, - {0x27f0, 0x2982, 1}, - {0x2999, 0x29d7, 1}, - {0x29dc, 0x29fb, 1}, - {0x29fe, 0x2b73, 1}, - {0x2b76, 0x2b95, 1}, - {0x2b97, 0x2bff, 1}, - {0x2ce5, 0x2cea, 1}, - {0x2e50, 0x2e51, 1}, - {0x2e80, 0x2e99, 1}, - {0x2e9b, 0x2ef3, 1}, - {0x2f00, 0x2fd5, 1}, - {0x2ff0, 0x2ffb, 1}, - {0x3004, 0x3012, 14}, - {0x3013, 0x3020, 13}, - {0x3036, 0x3037, 1}, - {0x303e, 0x303f, 1}, - {0x309b, 0x309c, 1}, - {0x3190, 0x3191, 1}, - {0x3196, 0x319f, 1}, - {0x31c0, 0x31e3, 1}, - {0x3200, 0x321e, 1}, - {0x322a, 0x3247, 1}, - {0x3250, 0x3260, 16}, - {0x3261, 0x327f, 1}, - {0x328a, 0x32b0, 1}, - {0x32c0, 0x33ff, 1}, - {0x4dc0, 0x4dff, 1}, - {0xa490, 0xa4c6, 1}, - {0xa700, 0xa716, 1}, - {0xa720, 0xa721, 1}, - {0xa789, 0xa78a, 1}, - {0xa828, 0xa82b, 1}, - {0xa836, 0xa839, 1}, - {0xaa77, 0xaa79, 1}, - {0xab5b, 0xab6a, 15}, - {0xab6b, 0xfb29, 20414}, - {0xfbb2, 0xfbc2, 1}, - {0xfd40, 0xfd4f, 1}, - {0xfdcf, 0xfdfc, 45}, - {0xfdfd, 0xfdff, 1}, - {0xfe62, 0xfe64, 2}, - {0xfe65, 0xfe66, 1}, - {0xfe69, 0xff04, 155}, - {0xff0b, 0xff1c, 17}, - {0xff1d, 0xff1e, 1}, - {0xff3e, 0xff40, 2}, - {0xff5c, 0xff5e, 2}, - {0xffe0, 0xffe6, 1}, - {0xffe8, 0xffee, 1}, - {0xfffc, 0xfffd, 1}, - ], - R32: [ - {0x10137, 0x1013f, 1}, - {0x10179, 0x10189, 1}, - {0x1018c, 0x1018e, 1}, - {0x10190, 0x1019c, 1}, - {0x101a0, 0x101d0, 48}, - {0x101d1, 0x101fc, 1}, - {0x10877, 0x10878, 1}, - {0x10ac8, 0x1173f, 3191}, - {0x11fd5, 0x11ff1, 1}, - {0x16b3c, 0x16b3f, 1}, - {0x16b45, 0x1bc9c, 20823}, - {0x1cf50, 0x1cfc3, 1}, - {0x1d000, 0x1d0f5, 1}, - {0x1d100, 0x1d126, 1}, - {0x1d129, 0x1d164, 1}, - {0x1d16a, 0x1d16c, 1}, - {0x1d183, 0x1d184, 1}, - {0x1d18c, 0x1d1a9, 1}, - {0x1d1ae, 0x1d1ea, 1}, - {0x1d200, 0x1d241, 1}, - {0x1d245, 0x1d300, 187}, - {0x1d301, 0x1d356, 1}, - {0x1d6c1, 0x1d6db, 26}, - {0x1d6fb, 0x1d715, 26}, - {0x1d735, 0x1d74f, 26}, - {0x1d76f, 0x1d789, 26}, - {0x1d7a9, 0x1d7c3, 26}, - {0x1d800, 0x1d9ff, 1}, - {0x1da37, 0x1da3a, 1}, - {0x1da6d, 0x1da74, 1}, - {0x1da76, 0x1da83, 1}, - {0x1da85, 0x1da86, 1}, - {0x1e14f, 0x1e2ff, 432}, - {0x1ecac, 0x1ecb0, 4}, - {0x1ed2e, 0x1eef0, 450}, - {0x1eef1, 0x1f000, 271}, - {0x1f001, 0x1f02b, 1}, - {0x1f030, 0x1f093, 1}, - {0x1f0a0, 0x1f0ae, 1}, - {0x1f0b1, 0x1f0bf, 1}, - {0x1f0c1, 0x1f0cf, 1}, - {0x1f0d1, 0x1f0f5, 1}, - {0x1f10d, 0x1f1ad, 1}, - {0x1f1e6, 0x1f202, 1}, - {0x1f210, 0x1f23b, 1}, - {0x1f240, 0x1f248, 1}, - {0x1f250, 0x1f251, 1}, - {0x1f260, 0x1f265, 1}, - {0x1f300, 0x1f6d7, 1}, - {0x1f6dc, 0x1f6ec, 1}, - {0x1f6f0, 0x1f6fc, 1}, - {0x1f700, 0x1f776, 1}, - {0x1f77b, 0x1f7d9, 1}, - {0x1f7e0, 0x1f7eb, 1}, - {0x1f7f0, 0x1f800, 16}, - {0x1f801, 0x1f80b, 1}, - {0x1f810, 0x1f847, 1}, - {0x1f850, 0x1f859, 1}, - {0x1f860, 0x1f887, 1}, - {0x1f890, 0x1f8ad, 1}, - {0x1f8b0, 0x1f8b1, 1}, - {0x1f900, 0x1fa53, 1}, - {0x1fa60, 0x1fa6d, 1}, - {0x1fa70, 0x1fa7c, 1}, - {0x1fa80, 0x1fa88, 1}, - {0x1fa90, 0x1fabd, 1}, - {0x1fabf, 0x1fac5, 1}, - {0x1face, 0x1fadb, 1}, - {0x1fae0, 0x1fae8, 1}, - {0x1faf0, 0x1faf8, 1}, - {0x1fb00, 0x1fb92, 1}, - {0x1fb94, 0x1fbca, 1}, - ], - LatinOffset: 10, + R16: [ + {0x0024, 0x002b, 7}, + {0x003c, 0x003e, 1}, + {0x005e, 0x0060, 2}, + {0x007c, 0x007e, 2}, + {0x00a2, 0x00a6, 1}, + {0x00a8, 0x00a9, 1}, + {0x00ac, 0x00ae, 2}, + {0x00af, 0x00b1, 1}, + {0x00b4, 0x00b8, 4}, + {0x00d7, 0x00f7, 32}, + {0x02c2, 0x02c5, 1}, + {0x02d2, 0x02df, 1}, + {0x02e5, 0x02eb, 1}, + {0x02ed, 0x02ef, 2}, + {0x02f0, 0x02ff, 1}, + {0x0375, 0x0384, 15}, + {0x0385, 0x03f6, 113}, + {0x0482, 0x058d, 267}, + {0x058e, 0x058f, 1}, + {0x0606, 0x0608, 1}, + {0x060b, 0x060e, 3}, + {0x060f, 0x06de, 207}, + {0x06e9, 0x06fd, 20}, + {0x06fe, 0x07f6, 248}, + {0x07fe, 0x07ff, 1}, + {0x0888, 0x09f2, 362}, + {0x09f3, 0x09fa, 7}, + {0x09fb, 0x0af1, 246}, + {0x0b70, 0x0bf3, 131}, + {0x0bf4, 0x0bfa, 1}, + {0x0c7f, 0x0d4f, 208}, + {0x0d79, 0x0e3f, 198}, + {0x0f01, 0x0f03, 1}, + {0x0f13, 0x0f15, 2}, + {0x0f16, 0x0f17, 1}, + {0x0f1a, 0x0f1f, 1}, + {0x0f34, 0x0f38, 2}, + {0x0fbe, 0x0fc5, 1}, + {0x0fc7, 0x0fcc, 1}, + {0x0fce, 0x0fcf, 1}, + {0x0fd5, 0x0fd8, 1}, + {0x109e, 0x109f, 1}, + {0x1390, 0x1399, 1}, + {0x166d, 0x17db, 366}, + {0x1940, 0x19de, 158}, + {0x19df, 0x19ff, 1}, + {0x1b61, 0x1b6a, 1}, + {0x1b74, 0x1b7c, 1}, + {0x1fbd, 0x1fbf, 2}, + {0x1fc0, 0x1fc1, 1}, + {0x1fcd, 0x1fcf, 1}, + {0x1fdd, 0x1fdf, 1}, + {0x1fed, 0x1fef, 1}, + {0x1ffd, 0x1ffe, 1}, + {0x2044, 0x2052, 14}, + {0x207a, 0x207c, 1}, + {0x208a, 0x208c, 1}, + {0x20a0, 0x20c0, 1}, + {0x2100, 0x2101, 1}, + {0x2103, 0x2106, 1}, + {0x2108, 0x2109, 1}, + {0x2114, 0x2116, 2}, + {0x2117, 0x2118, 1}, + {0x211e, 0x2123, 1}, + {0x2125, 0x2129, 2}, + {0x212e, 0x213a, 12}, + {0x213b, 0x2140, 5}, + {0x2141, 0x2144, 1}, + {0x214a, 0x214d, 1}, + {0x214f, 0x218a, 59}, + {0x218b, 0x2190, 5}, + {0x2191, 0x2307, 1}, + {0x230c, 0x2328, 1}, + {0x232b, 0x2426, 1}, + {0x2440, 0x244a, 1}, + {0x249c, 0x24e9, 1}, + {0x2500, 0x2767, 1}, + {0x2794, 0x27c4, 1}, + {0x27c7, 0x27e5, 1}, + {0x27f0, 0x2982, 1}, + {0x2999, 0x29d7, 1}, + {0x29dc, 0x29fb, 1}, + {0x29fe, 0x2b73, 1}, + {0x2b76, 0x2b95, 1}, + {0x2b97, 0x2bff, 1}, + {0x2ce5, 0x2cea, 1}, + {0x2e50, 0x2e51, 1}, + {0x2e80, 0x2e99, 1}, + {0x2e9b, 0x2ef3, 1}, + {0x2f00, 0x2fd5, 1}, + {0x2ff0, 0x2ffb, 1}, + {0x3004, 0x3012, 14}, + {0x3013, 0x3020, 13}, + {0x3036, 0x3037, 1}, + {0x303e, 0x303f, 1}, + {0x309b, 0x309c, 1}, + {0x3190, 0x3191, 1}, + {0x3196, 0x319f, 1}, + {0x31c0, 0x31e3, 1}, + {0x3200, 0x321e, 1}, + {0x322a, 0x3247, 1}, + {0x3250, 0x3260, 16}, + {0x3261, 0x327f, 1}, + {0x328a, 0x32b0, 1}, + {0x32c0, 0x33ff, 1}, + {0x4dc0, 0x4dff, 1}, + {0xa490, 0xa4c6, 1}, + {0xa700, 0xa716, 1}, + {0xa720, 0xa721, 1}, + {0xa789, 0xa78a, 1}, + {0xa828, 0xa82b, 1}, + {0xa836, 0xa839, 1}, + {0xaa77, 0xaa79, 1}, + {0xab5b, 0xab6a, 15}, + {0xab6b, 0xfb29, 20414}, + {0xfbb2, 0xfbc2, 1}, + {0xfd40, 0xfd4f, 1}, + {0xfdcf, 0xfdfc, 45}, + {0xfdfd, 0xfdff, 1}, + {0xfe62, 0xfe64, 2}, + {0xfe65, 0xfe66, 1}, + {0xfe69, 0xff04, 155}, + {0xff0b, 0xff1c, 17}, + {0xff1d, 0xff1e, 1}, + {0xff3e, 0xff40, 2}, + {0xff5c, 0xff5e, 2}, + {0xffe0, 0xffe6, 1}, + {0xffe8, 0xffee, 1}, + {0xfffc, 0xfffd, 1}, + ], + R32: [ + {0x10137, 0x1013f, 1}, + {0x10179, 0x10189, 1}, + {0x1018c, 0x1018e, 1}, + {0x10190, 0x1019c, 1}, + {0x101a0, 0x101d0, 48}, + {0x101d1, 0x101fc, 1}, + {0x10877, 0x10878, 1}, + {0x10ac8, 0x1173f, 3191}, + {0x11fd5, 0x11ff1, 1}, + {0x16b3c, 0x16b3f, 1}, + {0x16b45, 0x1bc9c, 20823}, + {0x1cf50, 0x1cfc3, 1}, + {0x1d000, 0x1d0f5, 1}, + {0x1d100, 0x1d126, 1}, + {0x1d129, 0x1d164, 1}, + {0x1d16a, 0x1d16c, 1}, + {0x1d183, 0x1d184, 1}, + {0x1d18c, 0x1d1a9, 1}, + {0x1d1ae, 0x1d1ea, 1}, + {0x1d200, 0x1d241, 1}, + {0x1d245, 0x1d300, 187}, + {0x1d301, 0x1d356, 1}, + {0x1d6c1, 0x1d6db, 26}, + {0x1d6fb, 0x1d715, 26}, + {0x1d735, 0x1d74f, 26}, + {0x1d76f, 0x1d789, 26}, + {0x1d7a9, 0x1d7c3, 26}, + {0x1d800, 0x1d9ff, 1}, + {0x1da37, 0x1da3a, 1}, + {0x1da6d, 0x1da74, 1}, + {0x1da76, 0x1da83, 1}, + {0x1da85, 0x1da86, 1}, + {0x1e14f, 0x1e2ff, 432}, + {0x1ecac, 0x1ecb0, 4}, + {0x1ed2e, 0x1eef0, 450}, + {0x1eef1, 0x1f000, 271}, + {0x1f001, 0x1f02b, 1}, + {0x1f030, 0x1f093, 1}, + {0x1f0a0, 0x1f0ae, 1}, + {0x1f0b1, 0x1f0bf, 1}, + {0x1f0c1, 0x1f0cf, 1}, + {0x1f0d1, 0x1f0f5, 1}, + {0x1f10d, 0x1f1ad, 1}, + {0x1f1e6, 0x1f202, 1}, + {0x1f210, 0x1f23b, 1}, + {0x1f240, 0x1f248, 1}, + {0x1f250, 0x1f251, 1}, + {0x1f260, 0x1f265, 1}, + {0x1f300, 0x1f6d7, 1}, + {0x1f6dc, 0x1f6ec, 1}, + {0x1f6f0, 0x1f6fc, 1}, + {0x1f700, 0x1f776, 1}, + {0x1f77b, 0x1f7d9, 1}, + {0x1f7e0, 0x1f7eb, 1}, + {0x1f7f0, 0x1f800, 16}, + {0x1f801, 0x1f80b, 1}, + {0x1f810, 0x1f847, 1}, + {0x1f850, 0x1f859, 1}, + {0x1f860, 0x1f887, 1}, + {0x1f890, 0x1f8ad, 1}, + {0x1f8b0, 0x1f8b1, 1}, + {0x1f900, 0x1fa53, 1}, + {0x1fa60, 0x1fa6d, 1}, + {0x1fa70, 0x1fa7c, 1}, + {0x1fa80, 0x1fa88, 1}, + {0x1fa90, 0x1fabd, 1}, + {0x1fabf, 0x1fac5, 1}, + {0x1face, 0x1fadb, 1}, + {0x1fae0, 0x1fae8, 1}, + {0x1faf0, 0x1faf8, 1}, + {0x1fb00, 0x1fb92, 1}, + {0x1fb94, 0x1fbca, 1}, + ], + LatinOffset: 10, } static _SC = &RangeTable{ - R16: [ - {0x0024, 0x00a2, 126}, - {0x00a3, 0x00a5, 1}, - {0x058f, 0x060b, 124}, - {0x07fe, 0x07ff, 1}, - {0x09f2, 0x09f3, 1}, - {0x09fb, 0x0af1, 246}, - {0x0bf9, 0x0e3f, 582}, - {0x17db, 0x20a0, 2245}, - {0x20a1, 0x20c0, 1}, - {0xa838, 0xfdfc, 21956}, - {0xfe69, 0xff04, 155}, - {0xffe0, 0xffe1, 1}, - {0xffe5, 0xffe6, 1}, - ], - R32: [ - {0x11fdd, 0x11fe0, 1}, - {0x1e2ff, 0x1ecb0, 2481}, - ], - LatinOffset: 2, + R16: [ + {0x0024, 0x00a2, 126}, + {0x00a3, 0x00a5, 1}, + {0x058f, 0x060b, 124}, + {0x07fe, 0x07ff, 1}, + {0x09f2, 0x09f3, 1}, + {0x09fb, 0x0af1, 246}, + {0x0bf9, 0x0e3f, 582}, + {0x17db, 0x20a0, 2245}, + {0x20a1, 0x20c0, 1}, + {0xa838, 0xfdfc, 21956}, + {0xfe69, 0xff04, 155}, + {0xffe0, 0xffe1, 1}, + {0xffe5, 0xffe6, 1}, + ], + R32: [ + {0x11fdd, 0x11fe0, 1}, + {0x1e2ff, 0x1ecb0, 2481}, + ], + LatinOffset: 2, } static _SK = &RangeTable{ - R16: [ - {0x005e, 0x0060, 2}, - {0x00a8, 0x00af, 7}, - {0x00b4, 0x00b8, 4}, - {0x02c2, 0x02c5, 1}, - {0x02d2, 0x02df, 1}, - {0x02e5, 0x02eb, 1}, - {0x02ed, 0x02ef, 2}, - {0x02f0, 0x02ff, 1}, - {0x0375, 0x0384, 15}, - {0x0385, 0x0888, 1283}, - {0x1fbd, 0x1fbf, 2}, - {0x1fc0, 0x1fc1, 1}, - {0x1fcd, 0x1fcf, 1}, - {0x1fdd, 0x1fdf, 1}, - {0x1fed, 0x1fef, 1}, - {0x1ffd, 0x1ffe, 1}, - {0x309b, 0x309c, 1}, - {0xa700, 0xa716, 1}, - {0xa720, 0xa721, 1}, - {0xa789, 0xa78a, 1}, - {0xab5b, 0xab6a, 15}, - {0xab6b, 0xfbb2, 20551}, - {0xfbb3, 0xfbc2, 1}, - {0xff3e, 0xff40, 2}, - {0xffe3, 0xffe3, 1}, - ], - R32: [ - {0x1f3fb, 0x1f3ff, 1}, - ], - LatinOffset: 3, + R16: [ + {0x005e, 0x0060, 2}, + {0x00a8, 0x00af, 7}, + {0x00b4, 0x00b8, 4}, + {0x02c2, 0x02c5, 1}, + {0x02d2, 0x02df, 1}, + {0x02e5, 0x02eb, 1}, + {0x02ed, 0x02ef, 2}, + {0x02f0, 0x02ff, 1}, + {0x0375, 0x0384, 15}, + {0x0385, 0x0888, 1283}, + {0x1fbd, 0x1fbf, 2}, + {0x1fc0, 0x1fc1, 1}, + {0x1fcd, 0x1fcf, 1}, + {0x1fdd, 0x1fdf, 1}, + {0x1fed, 0x1fef, 1}, + {0x1ffd, 0x1ffe, 1}, + {0x309b, 0x309c, 1}, + {0xa700, 0xa716, 1}, + {0xa720, 0xa721, 1}, + {0xa789, 0xa78a, 1}, + {0xab5b, 0xab6a, 15}, + {0xab6b, 0xfbb2, 20551}, + {0xfbb3, 0xfbc2, 1}, + {0xff3e, 0xff40, 2}, + {0xffe3, 0xffe3, 1}, + ], + R32: [ + {0x1f3fb, 0x1f3ff, 1}, + ], + LatinOffset: 3, } static _SM = &RangeTable{ - R16: [ - {0x002b, 0x003c, 17}, - {0x003d, 0x003e, 1}, - {0x007c, 0x007e, 2}, - {0x00ac, 0x00b1, 5}, - {0x00d7, 0x00f7, 32}, - {0x03f6, 0x0606, 528}, - {0x0607, 0x0608, 1}, - {0x2044, 0x2052, 14}, - {0x207a, 0x207c, 1}, - {0x208a, 0x208c, 1}, - {0x2118, 0x2140, 40}, - {0x2141, 0x2144, 1}, - {0x214b, 0x2190, 69}, - {0x2191, 0x2194, 1}, - {0x219a, 0x219b, 1}, - {0x21a0, 0x21a6, 3}, - {0x21ae, 0x21ce, 32}, - {0x21cf, 0x21d2, 3}, - {0x21d4, 0x21f4, 32}, - {0x21f5, 0x22ff, 1}, - {0x2320, 0x2321, 1}, - {0x237c, 0x239b, 31}, - {0x239c, 0x23b3, 1}, - {0x23dc, 0x23e1, 1}, - {0x25b7, 0x25c1, 10}, - {0x25f8, 0x25ff, 1}, - {0x266f, 0x27c0, 337}, - {0x27c1, 0x27c4, 1}, - {0x27c7, 0x27e5, 1}, - {0x27f0, 0x27ff, 1}, - {0x2900, 0x2982, 1}, - {0x2999, 0x29d7, 1}, - {0x29dc, 0x29fb, 1}, - {0x29fe, 0x2aff, 1}, - {0x2b30, 0x2b44, 1}, - {0x2b47, 0x2b4c, 1}, - {0xfb29, 0xfe62, 825}, - {0xfe64, 0xfe66, 1}, - {0xff0b, 0xff1c, 17}, - {0xff1d, 0xff1e, 1}, - {0xff5c, 0xff5e, 2}, - {0xffe2, 0xffe9, 7}, - {0xffea, 0xffec, 1}, - ], - R32: [ - {0x1d6c1, 0x1d6db, 26}, - {0x1d6fb, 0x1d715, 26}, - {0x1d735, 0x1d74f, 26}, - {0x1d76f, 0x1d789, 26}, - {0x1d7a9, 0x1d7c3, 26}, - {0x1eef0, 0x1eef1, 1}, - ], - LatinOffset: 5, + R16: [ + {0x002b, 0x003c, 17}, + {0x003d, 0x003e, 1}, + {0x007c, 0x007e, 2}, + {0x00ac, 0x00b1, 5}, + {0x00d7, 0x00f7, 32}, + {0x03f6, 0x0606, 528}, + {0x0607, 0x0608, 1}, + {0x2044, 0x2052, 14}, + {0x207a, 0x207c, 1}, + {0x208a, 0x208c, 1}, + {0x2118, 0x2140, 40}, + {0x2141, 0x2144, 1}, + {0x214b, 0x2190, 69}, + {0x2191, 0x2194, 1}, + {0x219a, 0x219b, 1}, + {0x21a0, 0x21a6, 3}, + {0x21ae, 0x21ce, 32}, + {0x21cf, 0x21d2, 3}, + {0x21d4, 0x21f4, 32}, + {0x21f5, 0x22ff, 1}, + {0x2320, 0x2321, 1}, + {0x237c, 0x239b, 31}, + {0x239c, 0x23b3, 1}, + {0x23dc, 0x23e1, 1}, + {0x25b7, 0x25c1, 10}, + {0x25f8, 0x25ff, 1}, + {0x266f, 0x27c0, 337}, + {0x27c1, 0x27c4, 1}, + {0x27c7, 0x27e5, 1}, + {0x27f0, 0x27ff, 1}, + {0x2900, 0x2982, 1}, + {0x2999, 0x29d7, 1}, + {0x29dc, 0x29fb, 1}, + {0x29fe, 0x2aff, 1}, + {0x2b30, 0x2b44, 1}, + {0x2b47, 0x2b4c, 1}, + {0xfb29, 0xfe62, 825}, + {0xfe64, 0xfe66, 1}, + {0xff0b, 0xff1c, 17}, + {0xff1d, 0xff1e, 1}, + {0xff5c, 0xff5e, 2}, + {0xffe2, 0xffe9, 7}, + {0xffea, 0xffec, 1}, + ], + R32: [ + {0x1d6c1, 0x1d6db, 26}, + {0x1d6fb, 0x1d715, 26}, + {0x1d735, 0x1d74f, 26}, + {0x1d76f, 0x1d789, 26}, + {0x1d7a9, 0x1d7c3, 26}, + {0x1eef0, 0x1eef1, 1}, + ], + LatinOffset: 5, } static _SO = &RangeTable{ - R16: [ - {0x00a6, 0x00a9, 3}, - {0x00ae, 0x00b0, 2}, - {0x0482, 0x058d, 267}, - {0x058e, 0x060e, 128}, - {0x060f, 0x06de, 207}, - {0x06e9, 0x06fd, 20}, - {0x06fe, 0x07f6, 248}, - {0x09fa, 0x0b70, 374}, - {0x0bf3, 0x0bf8, 1}, - {0x0bfa, 0x0c7f, 133}, - {0x0d4f, 0x0d79, 42}, - {0x0f01, 0x0f03, 1}, - {0x0f13, 0x0f15, 2}, - {0x0f16, 0x0f17, 1}, - {0x0f1a, 0x0f1f, 1}, - {0x0f34, 0x0f38, 2}, - {0x0fbe, 0x0fc5, 1}, - {0x0fc7, 0x0fcc, 1}, - {0x0fce, 0x0fcf, 1}, - {0x0fd5, 0x0fd8, 1}, - {0x109e, 0x109f, 1}, - {0x1390, 0x1399, 1}, - {0x166d, 0x1940, 723}, - {0x19de, 0x19ff, 1}, - {0x1b61, 0x1b6a, 1}, - {0x1b74, 0x1b7c, 1}, - {0x2100, 0x2101, 1}, - {0x2103, 0x2106, 1}, - {0x2108, 0x2109, 1}, - {0x2114, 0x2116, 2}, - {0x2117, 0x211e, 7}, - {0x211f, 0x2123, 1}, - {0x2125, 0x2129, 2}, - {0x212e, 0x213a, 12}, - {0x213b, 0x214a, 15}, - {0x214c, 0x214d, 1}, - {0x214f, 0x218a, 59}, - {0x218b, 0x2195, 10}, - {0x2196, 0x2199, 1}, - {0x219c, 0x219f, 1}, - {0x21a1, 0x21a2, 1}, - {0x21a4, 0x21a5, 1}, - {0x21a7, 0x21ad, 1}, - {0x21af, 0x21cd, 1}, - {0x21d0, 0x21d1, 1}, - {0x21d3, 0x21d5, 2}, - {0x21d6, 0x21f3, 1}, - {0x2300, 0x2307, 1}, - {0x230c, 0x231f, 1}, - {0x2322, 0x2328, 1}, - {0x232b, 0x237b, 1}, - {0x237d, 0x239a, 1}, - {0x23b4, 0x23db, 1}, - {0x23e2, 0x2426, 1}, - {0x2440, 0x244a, 1}, - {0x249c, 0x24e9, 1}, - {0x2500, 0x25b6, 1}, - {0x25b8, 0x25c0, 1}, - {0x25c2, 0x25f7, 1}, - {0x2600, 0x266e, 1}, - {0x2670, 0x2767, 1}, - {0x2794, 0x27bf, 1}, - {0x2800, 0x28ff, 1}, - {0x2b00, 0x2b2f, 1}, - {0x2b45, 0x2b46, 1}, - {0x2b4d, 0x2b73, 1}, - {0x2b76, 0x2b95, 1}, - {0x2b97, 0x2bff, 1}, - {0x2ce5, 0x2cea, 1}, - {0x2e50, 0x2e51, 1}, - {0x2e80, 0x2e99, 1}, - {0x2e9b, 0x2ef3, 1}, - {0x2f00, 0x2fd5, 1}, - {0x2ff0, 0x2ffb, 1}, - {0x3004, 0x3012, 14}, - {0x3013, 0x3020, 13}, - {0x3036, 0x3037, 1}, - {0x303e, 0x303f, 1}, - {0x3190, 0x3191, 1}, - {0x3196, 0x319f, 1}, - {0x31c0, 0x31e3, 1}, - {0x3200, 0x321e, 1}, - {0x322a, 0x3247, 1}, - {0x3250, 0x3260, 16}, - {0x3261, 0x327f, 1}, - {0x328a, 0x32b0, 1}, - {0x32c0, 0x33ff, 1}, - {0x4dc0, 0x4dff, 1}, - {0xa490, 0xa4c6, 1}, - {0xa828, 0xa82b, 1}, - {0xa836, 0xa837, 1}, - {0xa839, 0xaa77, 574}, - {0xaa78, 0xaa79, 1}, - {0xfd40, 0xfd4f, 1}, - {0xfdcf, 0xfdfd, 46}, - {0xfdfe, 0xfdff, 1}, - {0xffe4, 0xffe8, 4}, - {0xffed, 0xffee, 1}, - {0xfffc, 0xfffd, 1}, - ], - R32: [ - {0x10137, 0x1013f, 1}, - {0x10179, 0x10189, 1}, - {0x1018c, 0x1018e, 1}, - {0x10190, 0x1019c, 1}, - {0x101a0, 0x101d0, 48}, - {0x101d1, 0x101fc, 1}, - {0x10877, 0x10878, 1}, - {0x10ac8, 0x1173f, 3191}, - {0x11fd5, 0x11fdc, 1}, - {0x11fe1, 0x11ff1, 1}, - {0x16b3c, 0x16b3f, 1}, - {0x16b45, 0x1bc9c, 20823}, - {0x1cf50, 0x1cfc3, 1}, - {0x1d000, 0x1d0f5, 1}, - {0x1d100, 0x1d126, 1}, - {0x1d129, 0x1d164, 1}, - {0x1d16a, 0x1d16c, 1}, - {0x1d183, 0x1d184, 1}, - {0x1d18c, 0x1d1a9, 1}, - {0x1d1ae, 0x1d1ea, 1}, - {0x1d200, 0x1d241, 1}, - {0x1d245, 0x1d300, 187}, - {0x1d301, 0x1d356, 1}, - {0x1d800, 0x1d9ff, 1}, - {0x1da37, 0x1da3a, 1}, - {0x1da6d, 0x1da74, 1}, - {0x1da76, 0x1da83, 1}, - {0x1da85, 0x1da86, 1}, - {0x1e14f, 0x1ecac, 2909}, - {0x1ed2e, 0x1f000, 722}, - {0x1f001, 0x1f02b, 1}, - {0x1f030, 0x1f093, 1}, - {0x1f0a0, 0x1f0ae, 1}, - {0x1f0b1, 0x1f0bf, 1}, - {0x1f0c1, 0x1f0cf, 1}, - {0x1f0d1, 0x1f0f5, 1}, - {0x1f10d, 0x1f1ad, 1}, - {0x1f1e6, 0x1f202, 1}, - {0x1f210, 0x1f23b, 1}, - {0x1f240, 0x1f248, 1}, - {0x1f250, 0x1f251, 1}, - {0x1f260, 0x1f265, 1}, - {0x1f300, 0x1f3fa, 1}, - {0x1f400, 0x1f6d7, 1}, - {0x1f6dc, 0x1f6ec, 1}, - {0x1f6f0, 0x1f6fc, 1}, - {0x1f700, 0x1f776, 1}, - {0x1f77b, 0x1f7d9, 1}, - {0x1f7e0, 0x1f7eb, 1}, - {0x1f7f0, 0x1f800, 16}, - {0x1f801, 0x1f80b, 1}, - {0x1f810, 0x1f847, 1}, - {0x1f850, 0x1f859, 1}, - {0x1f860, 0x1f887, 1}, - {0x1f890, 0x1f8ad, 1}, - {0x1f8b0, 0x1f8b1, 1}, - {0x1f900, 0x1fa53, 1}, - {0x1fa60, 0x1fa6d, 1}, - {0x1fa70, 0x1fa7c, 1}, - {0x1fa80, 0x1fa88, 1}, - {0x1fa90, 0x1fabd, 1}, - {0x1fabf, 0x1fac5, 1}, - {0x1face, 0x1fadb, 1}, - {0x1fae0, 0x1fae8, 1}, - {0x1faf0, 0x1faf8, 1}, - {0x1fb00, 0x1fb92, 1}, - {0x1fb94, 0x1fbca, 1}, - ], - LatinOffset: 2, + R16: [ + {0x00a6, 0x00a9, 3}, + {0x00ae, 0x00b0, 2}, + {0x0482, 0x058d, 267}, + {0x058e, 0x060e, 128}, + {0x060f, 0x06de, 207}, + {0x06e9, 0x06fd, 20}, + {0x06fe, 0x07f6, 248}, + {0x09fa, 0x0b70, 374}, + {0x0bf3, 0x0bf8, 1}, + {0x0bfa, 0x0c7f, 133}, + {0x0d4f, 0x0d79, 42}, + {0x0f01, 0x0f03, 1}, + {0x0f13, 0x0f15, 2}, + {0x0f16, 0x0f17, 1}, + {0x0f1a, 0x0f1f, 1}, + {0x0f34, 0x0f38, 2}, + {0x0fbe, 0x0fc5, 1}, + {0x0fc7, 0x0fcc, 1}, + {0x0fce, 0x0fcf, 1}, + {0x0fd5, 0x0fd8, 1}, + {0x109e, 0x109f, 1}, + {0x1390, 0x1399, 1}, + {0x166d, 0x1940, 723}, + {0x19de, 0x19ff, 1}, + {0x1b61, 0x1b6a, 1}, + {0x1b74, 0x1b7c, 1}, + {0x2100, 0x2101, 1}, + {0x2103, 0x2106, 1}, + {0x2108, 0x2109, 1}, + {0x2114, 0x2116, 2}, + {0x2117, 0x211e, 7}, + {0x211f, 0x2123, 1}, + {0x2125, 0x2129, 2}, + {0x212e, 0x213a, 12}, + {0x213b, 0x214a, 15}, + {0x214c, 0x214d, 1}, + {0x214f, 0x218a, 59}, + {0x218b, 0x2195, 10}, + {0x2196, 0x2199, 1}, + {0x219c, 0x219f, 1}, + {0x21a1, 0x21a2, 1}, + {0x21a4, 0x21a5, 1}, + {0x21a7, 0x21ad, 1}, + {0x21af, 0x21cd, 1}, + {0x21d0, 0x21d1, 1}, + {0x21d3, 0x21d5, 2}, + {0x21d6, 0x21f3, 1}, + {0x2300, 0x2307, 1}, + {0x230c, 0x231f, 1}, + {0x2322, 0x2328, 1}, + {0x232b, 0x237b, 1}, + {0x237d, 0x239a, 1}, + {0x23b4, 0x23db, 1}, + {0x23e2, 0x2426, 1}, + {0x2440, 0x244a, 1}, + {0x249c, 0x24e9, 1}, + {0x2500, 0x25b6, 1}, + {0x25b8, 0x25c0, 1}, + {0x25c2, 0x25f7, 1}, + {0x2600, 0x266e, 1}, + {0x2670, 0x2767, 1}, + {0x2794, 0x27bf, 1}, + {0x2800, 0x28ff, 1}, + {0x2b00, 0x2b2f, 1}, + {0x2b45, 0x2b46, 1}, + {0x2b4d, 0x2b73, 1}, + {0x2b76, 0x2b95, 1}, + {0x2b97, 0x2bff, 1}, + {0x2ce5, 0x2cea, 1}, + {0x2e50, 0x2e51, 1}, + {0x2e80, 0x2e99, 1}, + {0x2e9b, 0x2ef3, 1}, + {0x2f00, 0x2fd5, 1}, + {0x2ff0, 0x2ffb, 1}, + {0x3004, 0x3012, 14}, + {0x3013, 0x3020, 13}, + {0x3036, 0x3037, 1}, + {0x303e, 0x303f, 1}, + {0x3190, 0x3191, 1}, + {0x3196, 0x319f, 1}, + {0x31c0, 0x31e3, 1}, + {0x3200, 0x321e, 1}, + {0x322a, 0x3247, 1}, + {0x3250, 0x3260, 16}, + {0x3261, 0x327f, 1}, + {0x328a, 0x32b0, 1}, + {0x32c0, 0x33ff, 1}, + {0x4dc0, 0x4dff, 1}, + {0xa490, 0xa4c6, 1}, + {0xa828, 0xa82b, 1}, + {0xa836, 0xa837, 1}, + {0xa839, 0xaa77, 574}, + {0xaa78, 0xaa79, 1}, + {0xfd40, 0xfd4f, 1}, + {0xfdcf, 0xfdfd, 46}, + {0xfdfe, 0xfdff, 1}, + {0xffe4, 0xffe8, 4}, + {0xffed, 0xffee, 1}, + {0xfffc, 0xfffd, 1}, + ], + R32: [ + {0x10137, 0x1013f, 1}, + {0x10179, 0x10189, 1}, + {0x1018c, 0x1018e, 1}, + {0x10190, 0x1019c, 1}, + {0x101a0, 0x101d0, 48}, + {0x101d1, 0x101fc, 1}, + {0x10877, 0x10878, 1}, + {0x10ac8, 0x1173f, 3191}, + {0x11fd5, 0x11fdc, 1}, + {0x11fe1, 0x11ff1, 1}, + {0x16b3c, 0x16b3f, 1}, + {0x16b45, 0x1bc9c, 20823}, + {0x1cf50, 0x1cfc3, 1}, + {0x1d000, 0x1d0f5, 1}, + {0x1d100, 0x1d126, 1}, + {0x1d129, 0x1d164, 1}, + {0x1d16a, 0x1d16c, 1}, + {0x1d183, 0x1d184, 1}, + {0x1d18c, 0x1d1a9, 1}, + {0x1d1ae, 0x1d1ea, 1}, + {0x1d200, 0x1d241, 1}, + {0x1d245, 0x1d300, 187}, + {0x1d301, 0x1d356, 1}, + {0x1d800, 0x1d9ff, 1}, + {0x1da37, 0x1da3a, 1}, + {0x1da6d, 0x1da74, 1}, + {0x1da76, 0x1da83, 1}, + {0x1da85, 0x1da86, 1}, + {0x1e14f, 0x1ecac, 2909}, + {0x1ed2e, 0x1f000, 722}, + {0x1f001, 0x1f02b, 1}, + {0x1f030, 0x1f093, 1}, + {0x1f0a0, 0x1f0ae, 1}, + {0x1f0b1, 0x1f0bf, 1}, + {0x1f0c1, 0x1f0cf, 1}, + {0x1f0d1, 0x1f0f5, 1}, + {0x1f10d, 0x1f1ad, 1}, + {0x1f1e6, 0x1f202, 1}, + {0x1f210, 0x1f23b, 1}, + {0x1f240, 0x1f248, 1}, + {0x1f250, 0x1f251, 1}, + {0x1f260, 0x1f265, 1}, + {0x1f300, 0x1f3fa, 1}, + {0x1f400, 0x1f6d7, 1}, + {0x1f6dc, 0x1f6ec, 1}, + {0x1f6f0, 0x1f6fc, 1}, + {0x1f700, 0x1f776, 1}, + {0x1f77b, 0x1f7d9, 1}, + {0x1f7e0, 0x1f7eb, 1}, + {0x1f7f0, 0x1f800, 16}, + {0x1f801, 0x1f80b, 1}, + {0x1f810, 0x1f847, 1}, + {0x1f850, 0x1f859, 1}, + {0x1f860, 0x1f887, 1}, + {0x1f890, 0x1f8ad, 1}, + {0x1f8b0, 0x1f8b1, 1}, + {0x1f900, 0x1fa53, 1}, + {0x1fa60, 0x1fa6d, 1}, + {0x1fa70, 0x1fa7c, 1}, + {0x1fa80, 0x1fa88, 1}, + {0x1fa90, 0x1fabd, 1}, + {0x1fabf, 0x1fac5, 1}, + {0x1face, 0x1fadb, 1}, + {0x1fae0, 0x1fae8, 1}, + {0x1faf0, 0x1faf8, 1}, + {0x1fb00, 0x1fb92, 1}, + {0x1fb94, 0x1fbca, 1}, + ], + LatinOffset: 2, } static _Z = &RangeTable{ - R16: [ - {0x0020, 0x00a0, 128}, - {0x1680, 0x2000, 2432}, - {0x2001, 0x200a, 1}, - {0x2028, 0x2029, 1}, - {0x202f, 0x205f, 48}, - {0x3000, 0x3000, 1}, - ], - LatinOffset: 1, + R16: [ + {0x0020, 0x00a0, 128}, + {0x1680, 0x2000, 2432}, + {0x2001, 0x200a, 1}, + {0x2028, 0x2029, 1}, + {0x202f, 0x205f, 48}, + {0x3000, 0x3000, 1}, + ], + LatinOffset: 1, } static _ZL = &RangeTable{ - R16: [ - {0x2028, 0x2028, 1}, - ], + R16: [ + {0x2028, 0x2028, 1}, + ], } static _ZP = &RangeTable{ - R16: [ - {0x2029, 0x2029, 1}, - ], + R16: [ + {0x2029, 0x2029, 1}, + ], } static _ZS = &RangeTable{ - R16: [ - {0x0020, 0x00a0, 128}, - {0x1680, 0x2000, 2432}, - {0x2001, 0x200a, 1}, - {0x202f, 0x205f, 48}, - {0x3000, 0x3000, 1}, - ], - LatinOffset: 1, + R16: [ + {0x0020, 0x00a0, 128}, + {0x1680, 0x2000, 2432}, + {0x2001, 0x200a, 1}, + {0x202f, 0x205f, 48}, + {0x3000, 0x3000, 1}, + ], + LatinOffset: 1, } // These variables have type &RangeTable. @@ -3828,2032 +3828,2032 @@ static ZS = _ZS // The set of Unicode characters in category ZS (Separator, S // The set of Unicode script tables. static Scripts: map[str]&RangeTable = { - "Adlam": Adlam, - "Ahom": Ahom, - "Anatolian_Hieroglyphs": AnatolianHieroglyphs, - "Arabic": Arabic, - "Armenian": Armenian, - "Avestan": Avestan, - "Balinese": Balinese, - "Bamum": Bamum, - "Bassa_Vah": BassaVah, - "Batak": Batak, - "Bengali": Bengali, - "Bhaiksuki": Bhaiksuki, - "Bopomofo": Bopomofo, - "Brahmi": Brahmi, - "Braille": Braille, - "Buginese": Buginese, - "Buhid": Buhid, - "Canadian_Aboriginal": CanadianAboriginal, - "Carian": Carian, - "Caucasian_Albanian": CaucasianAlbanian, - "Chakma": Chakma, - "Cham": Cham, - "Cherokee": Cherokee, - "Chorasmian": Chorasmian, - "Common": Common, - "Coptic": Coptic, - "Cuneiform": Cuneiform, - "Cypriot": Cypriot, - "Cypro_Minoan": CyproMinoan, - "Cyrillic": Cyrillic, - "Deseret": Deseret, - "Devanagari": Devanagari, - "Dives_Akuru": DivesAkuru, - "Dogra": Dogra, - "Duployan": Duployan, - "Egyptian_Hieroglyphs": EgyptianHieroglyphs, - "Elbasan": Elbasan, - "Elymaic": Elymaic, - "Ethiopic": Ethiopic, - "Georgian": Georgian, - "Glagolitic": Glagolitic, - "Gothic": Gothic, - "Grantha": Grantha, - "Greek": Greek, - "Gujarati": Gujarati, - "Gunjala_Gondi": GunjalaGondi, - "Gurmukhi": Gurmukhi, - "Han": Han, - "Hangul": Hangul, - "Hanifi_Rohingya": HanifiRohingya, - "Hanunoo": Hanunoo, - "Hatran": Hatran, - "Hebrew": Hebrew, - "Hiragana": Hiragana, - "Imperial_Aramaic": ImperialAramaic, - "Inherited": Inherited, - "Inscriptional_Pahlavi": InscriptionalPahlavi, - "Inscriptional_Parthian": InscriptionalParthian, - "Javanese": Javanese, - "Kaithi": Kaithi, - "Kannada": Kannada, - "Katakana": Katakana, - "Kawi": Kawi, - "Kayah_Li": KayahLi, - "Kharoshthi": Kharoshthi, - "Khitan_Small_Script": KhitanSmallScript, - "Khmer": Khmer, - "Khojki": Khojki, - "Khudawadi": Khudawadi, - "Lao": Lao, - "Latin": Latin, - "Lepcha": Lepcha, - "Limbu": Limbu, - "Linear_A": LinearA, - "Linear_B": LinearB, - "Lisu": Lisu, - "Lycian": Lycian, - "Lydian": Lydian, - "Mahajani": Mahajani, - "Makasar": Makasar, - "Malayalam": Malayalam, - "Mandaic": Mandaic, - "Manichaean": Manichaean, - "Marchen": Marchen, - "Masaram_Gondi": MasaramGondi, - "Medefaidrin": Medefaidrin, - "Meetei_Mayek": MeeteiMayek, - "Mende_Kikakui": MendeKikakui, - "Meroitic_Cursive": MeroiticCursive, - "Meroitic_Hieroglyphs": MeroiticHieroglyphs, - "Miao": Miao, - "Modi": Modi, - "Mongolian": Mongolian, - "Mro": Mro, - "Multani": Multani, - "Myanmar": Myanmar, - "Nabataean": Nabataean, - "Nag_Mundari": NagMundari, - "Nandinagari": Nandinagari, - "New_Tai_Lue": NewTaiLue, - "Newa": Newa, - "Nko": Nko, - "Nushu": Nushu, - "Nyiakeng_Puachue_Hmong": NyiakengPuachueHmong, - "Ogham": Ogham, - "Ol_Chiki": OlChiki, - "Old_Hungarian": OldHungarian, - "Old_Italic": OldItalic, - "Old_North_Arabian": OldNorthArabian, - "Old_Permic": OldPermic, - "Old_Persian": OldPersian, - "Old_Sogdian": OldSogdian, - "Old_South_Arabian": OldSouthArabian, - "Old_Turkic": OldTurkic, - "Old_Uyghur": OldUyghur, - "Oriya": Oriya, - "Osage": Osage, - "Osmanya": Osmanya, - "Pahawh_Hmong": PahawhHmong, - "Palmyrene": Palmyrene, - "Pau_Cin_Hau": PauCinHau, - "Phags_Pa": PhagsPa, - "Phoenician": Phoenician, - "Psalter_Pahlavi": PsalterPahlavi, - "Rejang": Rejang, - "Runic": Runic, - "Samaritan": Samaritan, - "Saurashtra": Saurashtra, - "Sharada": Sharada, - "Shavian": Shavian, - "Siddham": Siddham, - "SignWriting": SignWriting, - "Sinhala": Sinhala, - "Sogdian": Sogdian, - "Sora_Sompeng": SoraSompeng, - "Soyombo": Soyombo, - "Sundanese": Sundanese, - "Syloti_Nagri": SylotiNagri, - "Syriac": Syriac, - "Tagalog": Tagalog, - "Tagbanwa": Tagbanwa, - "Tai_Le": TaiLe, - "Tai_Tham": TaiTham, - "Tai_Viet": TaiViet, - "Takri": Takri, - "Tamil": Tamil, - "Tangsa": Tangsa, - "Tangut": Tangut, - "Telugu": Telugu, - "Thaana": Thaana, - "Thai": Thai, - "Tibetan": Tibetan, - "Tifinagh": Tifinagh, - "Tirhuta": Tirhuta, - "Toto": Toto, - "Ugaritic": Ugaritic, - "Vai": Vai, - "Vithkuqi": Vithkuqi, - "Wancho": Wancho, - "Warang_Citi": WarangCiti, - "Yezidi": Yezidi, - "Yi": Yi, - "Zanabazar_Square": ZanabazarSquare, + "Adlam": Adlam, + "Ahom": Ahom, + "Anatolian_Hieroglyphs": AnatolianHieroglyphs, + "Arabic": Arabic, + "Armenian": Armenian, + "Avestan": Avestan, + "Balinese": Balinese, + "Bamum": Bamum, + "Bassa_Vah": BassaVah, + "Batak": Batak, + "Bengali": Bengali, + "Bhaiksuki": Bhaiksuki, + "Bopomofo": Bopomofo, + "Brahmi": Brahmi, + "Braille": Braille, + "Buginese": Buginese, + "Buhid": Buhid, + "Canadian_Aboriginal": CanadianAboriginal, + "Carian": Carian, + "Caucasian_Albanian": CaucasianAlbanian, + "Chakma": Chakma, + "Cham": Cham, + "Cherokee": Cherokee, + "Chorasmian": Chorasmian, + "Common": Common, + "Coptic": Coptic, + "Cuneiform": Cuneiform, + "Cypriot": Cypriot, + "Cypro_Minoan": CyproMinoan, + "Cyrillic": Cyrillic, + "Deseret": Deseret, + "Devanagari": Devanagari, + "Dives_Akuru": DivesAkuru, + "Dogra": Dogra, + "Duployan": Duployan, + "Egyptian_Hieroglyphs": EgyptianHieroglyphs, + "Elbasan": Elbasan, + "Elymaic": Elymaic, + "Ethiopic": Ethiopic, + "Georgian": Georgian, + "Glagolitic": Glagolitic, + "Gothic": Gothic, + "Grantha": Grantha, + "Greek": Greek, + "Gujarati": Gujarati, + "Gunjala_Gondi": GunjalaGondi, + "Gurmukhi": Gurmukhi, + "Han": Han, + "Hangul": Hangul, + "Hanifi_Rohingya": HanifiRohingya, + "Hanunoo": Hanunoo, + "Hatran": Hatran, + "Hebrew": Hebrew, + "Hiragana": Hiragana, + "Imperial_Aramaic": ImperialAramaic, + "Inherited": Inherited, + "Inscriptional_Pahlavi": InscriptionalPahlavi, + "Inscriptional_Parthian": InscriptionalParthian, + "Javanese": Javanese, + "Kaithi": Kaithi, + "Kannada": Kannada, + "Katakana": Katakana, + "Kawi": Kawi, + "Kayah_Li": KayahLi, + "Kharoshthi": Kharoshthi, + "Khitan_Small_Script": KhitanSmallScript, + "Khmer": Khmer, + "Khojki": Khojki, + "Khudawadi": Khudawadi, + "Lao": Lao, + "Latin": Latin, + "Lepcha": Lepcha, + "Limbu": Limbu, + "Linear_A": LinearA, + "Linear_B": LinearB, + "Lisu": Lisu, + "Lycian": Lycian, + "Lydian": Lydian, + "Mahajani": Mahajani, + "Makasar": Makasar, + "Malayalam": Malayalam, + "Mandaic": Mandaic, + "Manichaean": Manichaean, + "Marchen": Marchen, + "Masaram_Gondi": MasaramGondi, + "Medefaidrin": Medefaidrin, + "Meetei_Mayek": MeeteiMayek, + "Mende_Kikakui": MendeKikakui, + "Meroitic_Cursive": MeroiticCursive, + "Meroitic_Hieroglyphs": MeroiticHieroglyphs, + "Miao": Miao, + "Modi": Modi, + "Mongolian": Mongolian, + "Mro": Mro, + "Multani": Multani, + "Myanmar": Myanmar, + "Nabataean": Nabataean, + "Nag_Mundari": NagMundari, + "Nandinagari": Nandinagari, + "New_Tai_Lue": NewTaiLue, + "Newa": Newa, + "Nko": Nko, + "Nushu": Nushu, + "Nyiakeng_Puachue_Hmong": NyiakengPuachueHmong, + "Ogham": Ogham, + "Ol_Chiki": OlChiki, + "Old_Hungarian": OldHungarian, + "Old_Italic": OldItalic, + "Old_North_Arabian": OldNorthArabian, + "Old_Permic": OldPermic, + "Old_Persian": OldPersian, + "Old_Sogdian": OldSogdian, + "Old_South_Arabian": OldSouthArabian, + "Old_Turkic": OldTurkic, + "Old_Uyghur": OldUyghur, + "Oriya": Oriya, + "Osage": Osage, + "Osmanya": Osmanya, + "Pahawh_Hmong": PahawhHmong, + "Palmyrene": Palmyrene, + "Pau_Cin_Hau": PauCinHau, + "Phags_Pa": PhagsPa, + "Phoenician": Phoenician, + "Psalter_Pahlavi": PsalterPahlavi, + "Rejang": Rejang, + "Runic": Runic, + "Samaritan": Samaritan, + "Saurashtra": Saurashtra, + "Sharada": Sharada, + "Shavian": Shavian, + "Siddham": Siddham, + "SignWriting": SignWriting, + "Sinhala": Sinhala, + "Sogdian": Sogdian, + "Sora_Sompeng": SoraSompeng, + "Soyombo": Soyombo, + "Sundanese": Sundanese, + "Syloti_Nagri": SylotiNagri, + "Syriac": Syriac, + "Tagalog": Tagalog, + "Tagbanwa": Tagbanwa, + "Tai_Le": TaiLe, + "Tai_Tham": TaiTham, + "Tai_Viet": TaiViet, + "Takri": Takri, + "Tamil": Tamil, + "Tangsa": Tangsa, + "Tangut": Tangut, + "Telugu": Telugu, + "Thaana": Thaana, + "Thai": Thai, + "Tibetan": Tibetan, + "Tifinagh": Tifinagh, + "Tirhuta": Tirhuta, + "Toto": Toto, + "Ugaritic": Ugaritic, + "Vai": Vai, + "Vithkuqi": Vithkuqi, + "Wancho": Wancho, + "Warang_Citi": WarangCiti, + "Yezidi": Yezidi, + "Yi": Yi, + "Zanabazar_Square": ZanabazarSquare, } static _ADLAM = &RangeTable{ - R16: [], - R32: [ - {0x1e900, 0x1e94b, 1}, - {0x1e950, 0x1e959, 1}, - {0x1e95e, 0x1e95f, 1}, - ], + R16: [], + R32: [ + {0x1e900, 0x1e94b, 1}, + {0x1e950, 0x1e959, 1}, + {0x1e95e, 0x1e95f, 1}, + ], } static _AHOM = &RangeTable{ - R16: [], - R32: [ - {0x11700, 0x1171a, 1}, - {0x1171d, 0x1172b, 1}, - {0x11730, 0x11746, 1}, - ], + R16: [], + R32: [ + {0x11700, 0x1171a, 1}, + {0x1171d, 0x1172b, 1}, + {0x11730, 0x11746, 1}, + ], } static _ANATOLIAN_HIEROGLYPHS = &RangeTable{ - R16: [], - R32: [ - {0x14400, 0x14646, 1}, - ], + R16: [], + R32: [ + {0x14400, 0x14646, 1}, + ], } static _ARABIC = &RangeTable{ - R16: [ - {0x0600, 0x0604, 1}, - {0x0606, 0x060b, 1}, - {0x060d, 0x061a, 1}, - {0x061c, 0x061e, 1}, - {0x0620, 0x063f, 1}, - {0x0641, 0x064a, 1}, - {0x0656, 0x066f, 1}, - {0x0671, 0x06dc, 1}, - {0x06de, 0x06ff, 1}, - {0x0750, 0x077f, 1}, - {0x0870, 0x088e, 1}, - {0x0890, 0x0891, 1}, - {0x0898, 0x08e1, 1}, - {0x08e3, 0x08ff, 1}, - {0xfb50, 0xfbc2, 1}, - {0xfbd3, 0xfd3d, 1}, - {0xfd40, 0xfd8f, 1}, - {0xfd92, 0xfdc7, 1}, - {0xfdcf, 0xfdf0, 33}, - {0xfdf1, 0xfdff, 1}, - {0xfe70, 0xfe74, 1}, - {0xfe76, 0xfefc, 1}, - ], - R32: [ - {0x10e60, 0x10e7e, 1}, - {0x10efd, 0x10eff, 1}, - {0x1ee00, 0x1ee03, 1}, - {0x1ee05, 0x1ee1f, 1}, - {0x1ee21, 0x1ee22, 1}, - {0x1ee24, 0x1ee27, 3}, - {0x1ee29, 0x1ee32, 1}, - {0x1ee34, 0x1ee37, 1}, - {0x1ee39, 0x1ee3b, 2}, - {0x1ee42, 0x1ee47, 5}, - {0x1ee49, 0x1ee4d, 2}, - {0x1ee4e, 0x1ee4f, 1}, - {0x1ee51, 0x1ee52, 1}, - {0x1ee54, 0x1ee57, 3}, - {0x1ee59, 0x1ee61, 2}, - {0x1ee62, 0x1ee64, 2}, - {0x1ee67, 0x1ee6a, 1}, - {0x1ee6c, 0x1ee72, 1}, - {0x1ee74, 0x1ee77, 1}, - {0x1ee79, 0x1ee7c, 1}, - {0x1ee7e, 0x1ee80, 2}, - {0x1ee81, 0x1ee89, 1}, - {0x1ee8b, 0x1ee9b, 1}, - {0x1eea1, 0x1eea3, 1}, - {0x1eea5, 0x1eea9, 1}, - {0x1eeab, 0x1eebb, 1}, - {0x1eef0, 0x1eef1, 1}, - ], + R16: [ + {0x0600, 0x0604, 1}, + {0x0606, 0x060b, 1}, + {0x060d, 0x061a, 1}, + {0x061c, 0x061e, 1}, + {0x0620, 0x063f, 1}, + {0x0641, 0x064a, 1}, + {0x0656, 0x066f, 1}, + {0x0671, 0x06dc, 1}, + {0x06de, 0x06ff, 1}, + {0x0750, 0x077f, 1}, + {0x0870, 0x088e, 1}, + {0x0890, 0x0891, 1}, + {0x0898, 0x08e1, 1}, + {0x08e3, 0x08ff, 1}, + {0xfb50, 0xfbc2, 1}, + {0xfbd3, 0xfd3d, 1}, + {0xfd40, 0xfd8f, 1}, + {0xfd92, 0xfdc7, 1}, + {0xfdcf, 0xfdf0, 33}, + {0xfdf1, 0xfdff, 1}, + {0xfe70, 0xfe74, 1}, + {0xfe76, 0xfefc, 1}, + ], + R32: [ + {0x10e60, 0x10e7e, 1}, + {0x10efd, 0x10eff, 1}, + {0x1ee00, 0x1ee03, 1}, + {0x1ee05, 0x1ee1f, 1}, + {0x1ee21, 0x1ee22, 1}, + {0x1ee24, 0x1ee27, 3}, + {0x1ee29, 0x1ee32, 1}, + {0x1ee34, 0x1ee37, 1}, + {0x1ee39, 0x1ee3b, 2}, + {0x1ee42, 0x1ee47, 5}, + {0x1ee49, 0x1ee4d, 2}, + {0x1ee4e, 0x1ee4f, 1}, + {0x1ee51, 0x1ee52, 1}, + {0x1ee54, 0x1ee57, 3}, + {0x1ee59, 0x1ee61, 2}, + {0x1ee62, 0x1ee64, 2}, + {0x1ee67, 0x1ee6a, 1}, + {0x1ee6c, 0x1ee72, 1}, + {0x1ee74, 0x1ee77, 1}, + {0x1ee79, 0x1ee7c, 1}, + {0x1ee7e, 0x1ee80, 2}, + {0x1ee81, 0x1ee89, 1}, + {0x1ee8b, 0x1ee9b, 1}, + {0x1eea1, 0x1eea3, 1}, + {0x1eea5, 0x1eea9, 1}, + {0x1eeab, 0x1eebb, 1}, + {0x1eef0, 0x1eef1, 1}, + ], } static _ARMENIAN = &RangeTable{ - R16: [ - {0x0531, 0x0556, 1}, - {0x0559, 0x058a, 1}, - {0x058d, 0x058f, 1}, - {0xfb13, 0xfb17, 1}, - ], + R16: [ + {0x0531, 0x0556, 1}, + {0x0559, 0x058a, 1}, + {0x058d, 0x058f, 1}, + {0xfb13, 0xfb17, 1}, + ], } static _AVESTAN = &RangeTable{ - R16: [], - R32: [ - {0x10b00, 0x10b35, 1}, - {0x10b39, 0x10b3f, 1}, - ], + R16: [], + R32: [ + {0x10b00, 0x10b35, 1}, + {0x10b39, 0x10b3f, 1}, + ], } static _BALINESE = &RangeTable{ - R16: [ - {0x1b00, 0x1b4c, 1}, - {0x1b50, 0x1b7e, 1}, - ], + R16: [ + {0x1b00, 0x1b4c, 1}, + {0x1b50, 0x1b7e, 1}, + ], } static _BAMUM = &RangeTable{ - R16: [ - {0xa6a0, 0xa6f7, 1}, - ], - R32: [ - {0x16800, 0x16a38, 1}, - ], + R16: [ + {0xa6a0, 0xa6f7, 1}, + ], + R32: [ + {0x16800, 0x16a38, 1}, + ], } static _BASSA_VAH = &RangeTable{ - R16: [], - R32: [ - {0x16ad0, 0x16aed, 1}, - {0x16af0, 0x16af5, 1}, - ], + R16: [], + R32: [ + {0x16ad0, 0x16aed, 1}, + {0x16af0, 0x16af5, 1}, + ], } static _BATAK = &RangeTable{ - R16: [ - {0x1bc0, 0x1bf3, 1}, - {0x1bfc, 0x1bff, 1}, - ], + R16: [ + {0x1bc0, 0x1bf3, 1}, + {0x1bfc, 0x1bff, 1}, + ], } static _BENGALI = &RangeTable{ - R16: [ - {0x0980, 0x0983, 1}, - {0x0985, 0x098c, 1}, - {0x098f, 0x0990, 1}, - {0x0993, 0x09a8, 1}, - {0x09aa, 0x09b0, 1}, - {0x09b2, 0x09b6, 4}, - {0x09b7, 0x09b9, 1}, - {0x09bc, 0x09c4, 1}, - {0x09c7, 0x09c8, 1}, - {0x09cb, 0x09ce, 1}, - {0x09d7, 0x09dc, 5}, - {0x09dd, 0x09df, 2}, - {0x09e0, 0x09e3, 1}, - {0x09e6, 0x09fe, 1}, - ], + R16: [ + {0x0980, 0x0983, 1}, + {0x0985, 0x098c, 1}, + {0x098f, 0x0990, 1}, + {0x0993, 0x09a8, 1}, + {0x09aa, 0x09b0, 1}, + {0x09b2, 0x09b6, 4}, + {0x09b7, 0x09b9, 1}, + {0x09bc, 0x09c4, 1}, + {0x09c7, 0x09c8, 1}, + {0x09cb, 0x09ce, 1}, + {0x09d7, 0x09dc, 5}, + {0x09dd, 0x09df, 2}, + {0x09e0, 0x09e3, 1}, + {0x09e6, 0x09fe, 1}, + ], } static _BHAIKSUKI = &RangeTable{ - R16: [], - R32: [ - {0x11c00, 0x11c08, 1}, - {0x11c0a, 0x11c36, 1}, - {0x11c38, 0x11c45, 1}, - {0x11c50, 0x11c6c, 1}, - ], + R16: [], + R32: [ + {0x11c00, 0x11c08, 1}, + {0x11c0a, 0x11c36, 1}, + {0x11c38, 0x11c45, 1}, + {0x11c50, 0x11c6c, 1}, + ], } static _BOPOMOFO = &RangeTable{ - R16: [ - {0x02ea, 0x02eb, 1}, - {0x3105, 0x312f, 1}, - {0x31a0, 0x31bf, 1}, - ], + R16: [ + {0x02ea, 0x02eb, 1}, + {0x3105, 0x312f, 1}, + {0x31a0, 0x31bf, 1}, + ], } static _BRAHMI = &RangeTable{ - R16: [], - R32: [ - {0x11000, 0x1104d, 1}, - {0x11052, 0x11075, 1}, - {0x1107f, 0x1107f, 1}, - ], + R16: [], + R32: [ + {0x11000, 0x1104d, 1}, + {0x11052, 0x11075, 1}, + {0x1107f, 0x1107f, 1}, + ], } static _BRAILLE = &RangeTable{ - R16: [ - {0x2800, 0x28ff, 1}, - ], + R16: [ + {0x2800, 0x28ff, 1}, + ], } static _BUGINESE = &RangeTable{ - R16: [ - {0x1a00, 0x1a1b, 1}, - {0x1a1e, 0x1a1f, 1}, - ], + R16: [ + {0x1a00, 0x1a1b, 1}, + {0x1a1e, 0x1a1f, 1}, + ], } static _BUHID = &RangeTable{ - R16: [ - {0x1740, 0x1753, 1}, - ], + R16: [ + {0x1740, 0x1753, 1}, + ], } static _CANADIAN_ABORIGINAL = &RangeTable{ - R16: [ - {0x1400, 0x167f, 1}, - {0x18b0, 0x18f5, 1}, - ], - R32: [ - {0x11ab0, 0x11abf, 1}, - ], + R16: [ + {0x1400, 0x167f, 1}, + {0x18b0, 0x18f5, 1}, + ], + R32: [ + {0x11ab0, 0x11abf, 1}, + ], } static _CARIAN = &RangeTable{ - R16: [], - R32: [ - {0x102a0, 0x102d0, 1}, - ], + R16: [], + R32: [ + {0x102a0, 0x102d0, 1}, + ], } static _CAUCASIAN_ALBANIAN = &RangeTable{ - R16: [], - R32: [ - {0x10530, 0x10563, 1}, - {0x1056f, 0x1056f, 1}, - ], + R16: [], + R32: [ + {0x10530, 0x10563, 1}, + {0x1056f, 0x1056f, 1}, + ], } static _CHAKMA = &RangeTable{ - R16: [], - R32: [ - {0x11100, 0x11134, 1}, - {0x11136, 0x11147, 1}, - ], + R16: [], + R32: [ + {0x11100, 0x11134, 1}, + {0x11136, 0x11147, 1}, + ], } static _CHAM = &RangeTable{ - R16: [ - {0xaa00, 0xaa36, 1}, - {0xaa40, 0xaa4d, 1}, - {0xaa50, 0xaa59, 1}, - {0xaa5c, 0xaa5f, 1}, - ], + R16: [ + {0xaa00, 0xaa36, 1}, + {0xaa40, 0xaa4d, 1}, + {0xaa50, 0xaa59, 1}, + {0xaa5c, 0xaa5f, 1}, + ], } static _CHEROKEE = &RangeTable{ - R16: [ - {0x13a0, 0x13f5, 1}, - {0x13f8, 0x13fd, 1}, - {0xab70, 0xabbf, 1}, - ], + R16: [ + {0x13a0, 0x13f5, 1}, + {0x13f8, 0x13fd, 1}, + {0xab70, 0xabbf, 1}, + ], } static _CHORASMIAN = &RangeTable{ - R16: [], - R32: [ - {0x10fb0, 0x10fcb, 1}, - ], + R16: [], + R32: [ + {0x10fb0, 0x10fcb, 1}, + ], } static _COMMON = &RangeTable{ - R16: [ - {0x0000, 0x0040, 1}, - {0x005b, 0x0060, 1}, - {0x007b, 0x00a9, 1}, - {0x00ab, 0x00b9, 1}, - {0x00bb, 0x00bf, 1}, - {0x00d7, 0x00f7, 32}, - {0x02b9, 0x02df, 1}, - {0x02e5, 0x02e9, 1}, - {0x02ec, 0x02ff, 1}, - {0x0374, 0x037e, 10}, - {0x0385, 0x0387, 2}, - {0x0605, 0x060c, 7}, - {0x061b, 0x061f, 4}, - {0x0640, 0x06dd, 157}, - {0x08e2, 0x0964, 130}, - {0x0965, 0x0e3f, 1242}, - {0x0fd5, 0x0fd8, 1}, - {0x10fb, 0x16eb, 1520}, - {0x16ec, 0x16ed, 1}, - {0x1735, 0x1736, 1}, - {0x1802, 0x1803, 1}, - {0x1805, 0x1cd3, 1230}, - {0x1ce1, 0x1ce9, 8}, - {0x1cea, 0x1cec, 1}, - {0x1cee, 0x1cf3, 1}, - {0x1cf5, 0x1cf7, 1}, - {0x1cfa, 0x2000, 774}, - {0x2001, 0x200b, 1}, - {0x200e, 0x2064, 1}, - {0x2066, 0x2070, 1}, - {0x2074, 0x207e, 1}, - {0x2080, 0x208e, 1}, - {0x20a0, 0x20c0, 1}, - {0x2100, 0x2125, 1}, - {0x2127, 0x2129, 1}, - {0x212c, 0x2131, 1}, - {0x2133, 0x214d, 1}, - {0x214f, 0x215f, 1}, - {0x2189, 0x218b, 1}, - {0x2190, 0x2426, 1}, - {0x2440, 0x244a, 1}, - {0x2460, 0x27ff, 1}, - {0x2900, 0x2b73, 1}, - {0x2b76, 0x2b95, 1}, - {0x2b97, 0x2bff, 1}, - {0x2e00, 0x2e5d, 1}, - {0x2ff0, 0x2ffb, 1}, - {0x3000, 0x3004, 1}, - {0x3006, 0x3008, 2}, - {0x3009, 0x3020, 1}, - {0x3030, 0x3037, 1}, - {0x303c, 0x303f, 1}, - {0x309b, 0x309c, 1}, - {0x30a0, 0x30fb, 91}, - {0x30fc, 0x3190, 148}, - {0x3191, 0x319f, 1}, - {0x31c0, 0x31e3, 1}, - {0x3220, 0x325f, 1}, - {0x327f, 0x32cf, 1}, - {0x32ff, 0x3358, 89}, - {0x3359, 0x33ff, 1}, - {0x4dc0, 0x4dff, 1}, - {0xa700, 0xa721, 1}, - {0xa788, 0xa78a, 1}, - {0xa830, 0xa839, 1}, - {0xa92e, 0xa9cf, 161}, - {0xab5b, 0xab6a, 15}, - {0xab6b, 0xfd3e, 20947}, - {0xfd3f, 0xfe10, 209}, - {0xfe11, 0xfe19, 1}, - {0xfe30, 0xfe52, 1}, - {0xfe54, 0xfe66, 1}, - {0xfe68, 0xfe6b, 1}, - {0xfeff, 0xff01, 2}, - {0xff02, 0xff20, 1}, - {0xff3b, 0xff40, 1}, - {0xff5b, 0xff65, 1}, - {0xff70, 0xff9e, 46}, - {0xff9f, 0xffe0, 65}, - {0xffe1, 0xffe6, 1}, - {0xffe8, 0xffee, 1}, - {0xfff9, 0xfffd, 1}, - ], - R32: [ - {0x10100, 0x10102, 1}, - {0x10107, 0x10133, 1}, - {0x10137, 0x1013f, 1}, - {0x10190, 0x1019c, 1}, - {0x101d0, 0x101fc, 1}, - {0x102e1, 0x102fb, 1}, - {0x1bca0, 0x1bca3, 1}, - {0x1cf50, 0x1cfc3, 1}, - {0x1d000, 0x1d0f5, 1}, - {0x1d100, 0x1d126, 1}, - {0x1d129, 0x1d166, 1}, - {0x1d16a, 0x1d17a, 1}, - {0x1d183, 0x1d184, 1}, - {0x1d18c, 0x1d1a9, 1}, - {0x1d1ae, 0x1d1ea, 1}, - {0x1d2c0, 0x1d2d3, 1}, - {0x1d2e0, 0x1d2f3, 1}, - {0x1d300, 0x1d356, 1}, - {0x1d360, 0x1d378, 1}, - {0x1d400, 0x1d454, 1}, - {0x1d456, 0x1d49c, 1}, - {0x1d49e, 0x1d49f, 1}, - {0x1d4a2, 0x1d4a5, 3}, - {0x1d4a6, 0x1d4a9, 3}, - {0x1d4aa, 0x1d4ac, 1}, - {0x1d4ae, 0x1d4b9, 1}, - {0x1d4bb, 0x1d4bd, 2}, - {0x1d4be, 0x1d4c3, 1}, - {0x1d4c5, 0x1d505, 1}, - {0x1d507, 0x1d50a, 1}, - {0x1d50d, 0x1d514, 1}, - {0x1d516, 0x1d51c, 1}, - {0x1d51e, 0x1d539, 1}, - {0x1d53b, 0x1d53e, 1}, - {0x1d540, 0x1d544, 1}, - {0x1d546, 0x1d54a, 4}, - {0x1d54b, 0x1d550, 1}, - {0x1d552, 0x1d6a5, 1}, - {0x1d6a8, 0x1d7cb, 1}, - {0x1d7ce, 0x1d7ff, 1}, - {0x1ec71, 0x1ecb4, 1}, - {0x1ed01, 0x1ed3d, 1}, - {0x1f000, 0x1f02b, 1}, - {0x1f030, 0x1f093, 1}, - {0x1f0a0, 0x1f0ae, 1}, - {0x1f0b1, 0x1f0bf, 1}, - {0x1f0c1, 0x1f0cf, 1}, - {0x1f0d1, 0x1f0f5, 1}, - {0x1f100, 0x1f1ad, 1}, - {0x1f1e6, 0x1f1ff, 1}, - {0x1f201, 0x1f202, 1}, - {0x1f210, 0x1f23b, 1}, - {0x1f240, 0x1f248, 1}, - {0x1f250, 0x1f251, 1}, - {0x1f260, 0x1f265, 1}, - {0x1f300, 0x1f6d7, 1}, - {0x1f6dc, 0x1f6ec, 1}, - {0x1f6f0, 0x1f6fc, 1}, - {0x1f700, 0x1f776, 1}, - {0x1f77b, 0x1f7d9, 1}, - {0x1f7e0, 0x1f7eb, 1}, - {0x1f7f0, 0x1f800, 16}, - {0x1f801, 0x1f80b, 1}, - {0x1f810, 0x1f847, 1}, - {0x1f850, 0x1f859, 1}, - {0x1f860, 0x1f887, 1}, - {0x1f890, 0x1f8ad, 1}, - {0x1f8b0, 0x1f8b1, 1}, - {0x1f900, 0x1fa53, 1}, - {0x1fa60, 0x1fa6d, 1}, - {0x1fa70, 0x1fa7c, 1}, - {0x1fa80, 0x1fa88, 1}, - {0x1fa90, 0x1fabd, 1}, - {0x1fabf, 0x1fac5, 1}, - {0x1face, 0x1fadb, 1}, - {0x1fae0, 0x1fae8, 1}, - {0x1faf0, 0x1faf8, 1}, - {0x1fb00, 0x1fb92, 1}, - {0x1fb94, 0x1fbca, 1}, - {0x1fbf0, 0x1fbf9, 1}, - {0xe0001, 0xe0020, 31}, - {0xe0021, 0xe007f, 1}, - ], - LatinOffset: 6, + R16: [ + {0x0000, 0x0040, 1}, + {0x005b, 0x0060, 1}, + {0x007b, 0x00a9, 1}, + {0x00ab, 0x00b9, 1}, + {0x00bb, 0x00bf, 1}, + {0x00d7, 0x00f7, 32}, + {0x02b9, 0x02df, 1}, + {0x02e5, 0x02e9, 1}, + {0x02ec, 0x02ff, 1}, + {0x0374, 0x037e, 10}, + {0x0385, 0x0387, 2}, + {0x0605, 0x060c, 7}, + {0x061b, 0x061f, 4}, + {0x0640, 0x06dd, 157}, + {0x08e2, 0x0964, 130}, + {0x0965, 0x0e3f, 1242}, + {0x0fd5, 0x0fd8, 1}, + {0x10fb, 0x16eb, 1520}, + {0x16ec, 0x16ed, 1}, + {0x1735, 0x1736, 1}, + {0x1802, 0x1803, 1}, + {0x1805, 0x1cd3, 1230}, + {0x1ce1, 0x1ce9, 8}, + {0x1cea, 0x1cec, 1}, + {0x1cee, 0x1cf3, 1}, + {0x1cf5, 0x1cf7, 1}, + {0x1cfa, 0x2000, 774}, + {0x2001, 0x200b, 1}, + {0x200e, 0x2064, 1}, + {0x2066, 0x2070, 1}, + {0x2074, 0x207e, 1}, + {0x2080, 0x208e, 1}, + {0x20a0, 0x20c0, 1}, + {0x2100, 0x2125, 1}, + {0x2127, 0x2129, 1}, + {0x212c, 0x2131, 1}, + {0x2133, 0x214d, 1}, + {0x214f, 0x215f, 1}, + {0x2189, 0x218b, 1}, + {0x2190, 0x2426, 1}, + {0x2440, 0x244a, 1}, + {0x2460, 0x27ff, 1}, + {0x2900, 0x2b73, 1}, + {0x2b76, 0x2b95, 1}, + {0x2b97, 0x2bff, 1}, + {0x2e00, 0x2e5d, 1}, + {0x2ff0, 0x2ffb, 1}, + {0x3000, 0x3004, 1}, + {0x3006, 0x3008, 2}, + {0x3009, 0x3020, 1}, + {0x3030, 0x3037, 1}, + {0x303c, 0x303f, 1}, + {0x309b, 0x309c, 1}, + {0x30a0, 0x30fb, 91}, + {0x30fc, 0x3190, 148}, + {0x3191, 0x319f, 1}, + {0x31c0, 0x31e3, 1}, + {0x3220, 0x325f, 1}, + {0x327f, 0x32cf, 1}, + {0x32ff, 0x3358, 89}, + {0x3359, 0x33ff, 1}, + {0x4dc0, 0x4dff, 1}, + {0xa700, 0xa721, 1}, + {0xa788, 0xa78a, 1}, + {0xa830, 0xa839, 1}, + {0xa92e, 0xa9cf, 161}, + {0xab5b, 0xab6a, 15}, + {0xab6b, 0xfd3e, 20947}, + {0xfd3f, 0xfe10, 209}, + {0xfe11, 0xfe19, 1}, + {0xfe30, 0xfe52, 1}, + {0xfe54, 0xfe66, 1}, + {0xfe68, 0xfe6b, 1}, + {0xfeff, 0xff01, 2}, + {0xff02, 0xff20, 1}, + {0xff3b, 0xff40, 1}, + {0xff5b, 0xff65, 1}, + {0xff70, 0xff9e, 46}, + {0xff9f, 0xffe0, 65}, + {0xffe1, 0xffe6, 1}, + {0xffe8, 0xffee, 1}, + {0xfff9, 0xfffd, 1}, + ], + R32: [ + {0x10100, 0x10102, 1}, + {0x10107, 0x10133, 1}, + {0x10137, 0x1013f, 1}, + {0x10190, 0x1019c, 1}, + {0x101d0, 0x101fc, 1}, + {0x102e1, 0x102fb, 1}, + {0x1bca0, 0x1bca3, 1}, + {0x1cf50, 0x1cfc3, 1}, + {0x1d000, 0x1d0f5, 1}, + {0x1d100, 0x1d126, 1}, + {0x1d129, 0x1d166, 1}, + {0x1d16a, 0x1d17a, 1}, + {0x1d183, 0x1d184, 1}, + {0x1d18c, 0x1d1a9, 1}, + {0x1d1ae, 0x1d1ea, 1}, + {0x1d2c0, 0x1d2d3, 1}, + {0x1d2e0, 0x1d2f3, 1}, + {0x1d300, 0x1d356, 1}, + {0x1d360, 0x1d378, 1}, + {0x1d400, 0x1d454, 1}, + {0x1d456, 0x1d49c, 1}, + {0x1d49e, 0x1d49f, 1}, + {0x1d4a2, 0x1d4a5, 3}, + {0x1d4a6, 0x1d4a9, 3}, + {0x1d4aa, 0x1d4ac, 1}, + {0x1d4ae, 0x1d4b9, 1}, + {0x1d4bb, 0x1d4bd, 2}, + {0x1d4be, 0x1d4c3, 1}, + {0x1d4c5, 0x1d505, 1}, + {0x1d507, 0x1d50a, 1}, + {0x1d50d, 0x1d514, 1}, + {0x1d516, 0x1d51c, 1}, + {0x1d51e, 0x1d539, 1}, + {0x1d53b, 0x1d53e, 1}, + {0x1d540, 0x1d544, 1}, + {0x1d546, 0x1d54a, 4}, + {0x1d54b, 0x1d550, 1}, + {0x1d552, 0x1d6a5, 1}, + {0x1d6a8, 0x1d7cb, 1}, + {0x1d7ce, 0x1d7ff, 1}, + {0x1ec71, 0x1ecb4, 1}, + {0x1ed01, 0x1ed3d, 1}, + {0x1f000, 0x1f02b, 1}, + {0x1f030, 0x1f093, 1}, + {0x1f0a0, 0x1f0ae, 1}, + {0x1f0b1, 0x1f0bf, 1}, + {0x1f0c1, 0x1f0cf, 1}, + {0x1f0d1, 0x1f0f5, 1}, + {0x1f100, 0x1f1ad, 1}, + {0x1f1e6, 0x1f1ff, 1}, + {0x1f201, 0x1f202, 1}, + {0x1f210, 0x1f23b, 1}, + {0x1f240, 0x1f248, 1}, + {0x1f250, 0x1f251, 1}, + {0x1f260, 0x1f265, 1}, + {0x1f300, 0x1f6d7, 1}, + {0x1f6dc, 0x1f6ec, 1}, + {0x1f6f0, 0x1f6fc, 1}, + {0x1f700, 0x1f776, 1}, + {0x1f77b, 0x1f7d9, 1}, + {0x1f7e0, 0x1f7eb, 1}, + {0x1f7f0, 0x1f800, 16}, + {0x1f801, 0x1f80b, 1}, + {0x1f810, 0x1f847, 1}, + {0x1f850, 0x1f859, 1}, + {0x1f860, 0x1f887, 1}, + {0x1f890, 0x1f8ad, 1}, + {0x1f8b0, 0x1f8b1, 1}, + {0x1f900, 0x1fa53, 1}, + {0x1fa60, 0x1fa6d, 1}, + {0x1fa70, 0x1fa7c, 1}, + {0x1fa80, 0x1fa88, 1}, + {0x1fa90, 0x1fabd, 1}, + {0x1fabf, 0x1fac5, 1}, + {0x1face, 0x1fadb, 1}, + {0x1fae0, 0x1fae8, 1}, + {0x1faf0, 0x1faf8, 1}, + {0x1fb00, 0x1fb92, 1}, + {0x1fb94, 0x1fbca, 1}, + {0x1fbf0, 0x1fbf9, 1}, + {0xe0001, 0xe0020, 31}, + {0xe0021, 0xe007f, 1}, + ], + LatinOffset: 6, } static _COPTIC = &RangeTable{ - R16: [ - {0x03e2, 0x03ef, 1}, - {0x2c80, 0x2cf3, 1}, - {0x2cf9, 0x2cff, 1}, - ], + R16: [ + {0x03e2, 0x03ef, 1}, + {0x2c80, 0x2cf3, 1}, + {0x2cf9, 0x2cff, 1}, + ], } static _CUNEIFORM = &RangeTable{ - R16: [], - R32: [ - {0x12000, 0x12399, 1}, - {0x12400, 0x1246e, 1}, - {0x12470, 0x12474, 1}, - {0x12480, 0x12543, 1}, - ], + R16: [], + R32: [ + {0x12000, 0x12399, 1}, + {0x12400, 0x1246e, 1}, + {0x12470, 0x12474, 1}, + {0x12480, 0x12543, 1}, + ], } static _CYPRIOT = &RangeTable{ - R16: [], - R32: [ - {0x10800, 0x10805, 1}, - {0x10808, 0x1080a, 2}, - {0x1080b, 0x10835, 1}, - {0x10837, 0x10838, 1}, - {0x1083c, 0x1083f, 3}, - ], + R16: [], + R32: [ + {0x10800, 0x10805, 1}, + {0x10808, 0x1080a, 2}, + {0x1080b, 0x10835, 1}, + {0x10837, 0x10838, 1}, + {0x1083c, 0x1083f, 3}, + ], } static _CYPRO_MINOAN = &RangeTable{ - R16: [], - R32: [ - {0x12f90, 0x12ff2, 1}, - ], + R16: [], + R32: [ + {0x12f90, 0x12ff2, 1}, + ], } static _CYRILLIC = &RangeTable{ - R16: [ - {0x0400, 0x0484, 1}, - {0x0487, 0x052f, 1}, - {0x1c80, 0x1c88, 1}, - {0x1d2b, 0x1d78, 77}, - {0x2de0, 0x2dff, 1}, - {0xa640, 0xa69f, 1}, - {0xfe2e, 0xfe2f, 1}, - ], - R32: [ - {0x1e030, 0x1e06d, 1}, - {0x1e08f, 0x1e08f, 1}, - ], + R16: [ + {0x0400, 0x0484, 1}, + {0x0487, 0x052f, 1}, + {0x1c80, 0x1c88, 1}, + {0x1d2b, 0x1d78, 77}, + {0x2de0, 0x2dff, 1}, + {0xa640, 0xa69f, 1}, + {0xfe2e, 0xfe2f, 1}, + ], + R32: [ + {0x1e030, 0x1e06d, 1}, + {0x1e08f, 0x1e08f, 1}, + ], } static _DESERET = &RangeTable{ - R16: [], - R32: [ - {0x10400, 0x1044f, 1}, - ], + R16: [], + R32: [ + {0x10400, 0x1044f, 1}, + ], } static _DEVANAGARI = &RangeTable{ - R16: [ - {0x0900, 0x0950, 1}, - {0x0955, 0x0963, 1}, - {0x0966, 0x097f, 1}, - {0xa8e0, 0xa8ff, 1}, - ], - R32: [ - {0x11b00, 0x11b09, 1}, - ], + R16: [ + {0x0900, 0x0950, 1}, + {0x0955, 0x0963, 1}, + {0x0966, 0x097f, 1}, + {0xa8e0, 0xa8ff, 1}, + ], + R32: [ + {0x11b00, 0x11b09, 1}, + ], } static _DIVES_AKURU = &RangeTable{ - R16: [], - R32: [ - {0x11900, 0x11906, 1}, - {0x11909, 0x1190c, 3}, - {0x1190d, 0x11913, 1}, - {0x11915, 0x11916, 1}, - {0x11918, 0x11935, 1}, - {0x11937, 0x11938, 1}, - {0x1193b, 0x11946, 1}, - {0x11950, 0x11959, 1}, - ], + R16: [], + R32: [ + {0x11900, 0x11906, 1}, + {0x11909, 0x1190c, 3}, + {0x1190d, 0x11913, 1}, + {0x11915, 0x11916, 1}, + {0x11918, 0x11935, 1}, + {0x11937, 0x11938, 1}, + {0x1193b, 0x11946, 1}, + {0x11950, 0x11959, 1}, + ], } static _DOGRA = &RangeTable{ - R16: [], - R32: [ - {0x11800, 0x1183b, 1}, - ], + R16: [], + R32: [ + {0x11800, 0x1183b, 1}, + ], } static _DUPLOYAN = &RangeTable{ - R16: [], - R32: [ - {0x1bc00, 0x1bc6a, 1}, - {0x1bc70, 0x1bc7c, 1}, - {0x1bc80, 0x1bc88, 1}, - {0x1bc90, 0x1bc99, 1}, - {0x1bc9c, 0x1bc9f, 1}, - ], + R16: [], + R32: [ + {0x1bc00, 0x1bc6a, 1}, + {0x1bc70, 0x1bc7c, 1}, + {0x1bc80, 0x1bc88, 1}, + {0x1bc90, 0x1bc99, 1}, + {0x1bc9c, 0x1bc9f, 1}, + ], } static _EGYPTIAN_HIEROGLYPHS = &RangeTable{ - R16: [], - R32: [ - {0x13000, 0x13455, 1}, - ], + R16: [], + R32: [ + {0x13000, 0x13455, 1}, + ], } static _ELBASAN = &RangeTable{ - R16: [], - R32: [ - {0x10500, 0x10527, 1}, - ], + R16: [], + R32: [ + {0x10500, 0x10527, 1}, + ], } static _ELYMAIC = &RangeTable{ - R16: [], - R32: [ - {0x10fe0, 0x10ff6, 1}, - ], + R16: [], + R32: [ + {0x10fe0, 0x10ff6, 1}, + ], } static _ETHIOPIC = &RangeTable{ - R16: [ - {0x1200, 0x1248, 1}, - {0x124a, 0x124d, 1}, - {0x1250, 0x1256, 1}, - {0x1258, 0x125a, 2}, - {0x125b, 0x125d, 1}, - {0x1260, 0x1288, 1}, - {0x128a, 0x128d, 1}, - {0x1290, 0x12b0, 1}, - {0x12b2, 0x12b5, 1}, - {0x12b8, 0x12be, 1}, - {0x12c0, 0x12c2, 2}, - {0x12c3, 0x12c5, 1}, - {0x12c8, 0x12d6, 1}, - {0x12d8, 0x1310, 1}, - {0x1312, 0x1315, 1}, - {0x1318, 0x135a, 1}, - {0x135d, 0x137c, 1}, - {0x1380, 0x1399, 1}, - {0x2d80, 0x2d96, 1}, - {0x2da0, 0x2da6, 1}, - {0x2da8, 0x2dae, 1}, - {0x2db0, 0x2db6, 1}, - {0x2db8, 0x2dbe, 1}, - {0x2dc0, 0x2dc6, 1}, - {0x2dc8, 0x2dce, 1}, - {0x2dd0, 0x2dd6, 1}, - {0x2dd8, 0x2dde, 1}, - {0xab01, 0xab06, 1}, - {0xab09, 0xab0e, 1}, - {0xab11, 0xab16, 1}, - {0xab20, 0xab26, 1}, - {0xab28, 0xab2e, 1}, - ], - R32: [ - {0x1e7e0, 0x1e7e6, 1}, - {0x1e7e8, 0x1e7eb, 1}, - {0x1e7ed, 0x1e7ee, 1}, - {0x1e7f0, 0x1e7fe, 1}, - ], + R16: [ + {0x1200, 0x1248, 1}, + {0x124a, 0x124d, 1}, + {0x1250, 0x1256, 1}, + {0x1258, 0x125a, 2}, + {0x125b, 0x125d, 1}, + {0x1260, 0x1288, 1}, + {0x128a, 0x128d, 1}, + {0x1290, 0x12b0, 1}, + {0x12b2, 0x12b5, 1}, + {0x12b8, 0x12be, 1}, + {0x12c0, 0x12c2, 2}, + {0x12c3, 0x12c5, 1}, + {0x12c8, 0x12d6, 1}, + {0x12d8, 0x1310, 1}, + {0x1312, 0x1315, 1}, + {0x1318, 0x135a, 1}, + {0x135d, 0x137c, 1}, + {0x1380, 0x1399, 1}, + {0x2d80, 0x2d96, 1}, + {0x2da0, 0x2da6, 1}, + {0x2da8, 0x2dae, 1}, + {0x2db0, 0x2db6, 1}, + {0x2db8, 0x2dbe, 1}, + {0x2dc0, 0x2dc6, 1}, + {0x2dc8, 0x2dce, 1}, + {0x2dd0, 0x2dd6, 1}, + {0x2dd8, 0x2dde, 1}, + {0xab01, 0xab06, 1}, + {0xab09, 0xab0e, 1}, + {0xab11, 0xab16, 1}, + {0xab20, 0xab26, 1}, + {0xab28, 0xab2e, 1}, + ], + R32: [ + {0x1e7e0, 0x1e7e6, 1}, + {0x1e7e8, 0x1e7eb, 1}, + {0x1e7ed, 0x1e7ee, 1}, + {0x1e7f0, 0x1e7fe, 1}, + ], } static _GEORGIAN = &RangeTable{ - R16: [ - {0x10a0, 0x10c5, 1}, - {0x10c7, 0x10cd, 6}, - {0x10d0, 0x10fa, 1}, - {0x10fc, 0x10ff, 1}, - {0x1c90, 0x1cba, 1}, - {0x1cbd, 0x1cbf, 1}, - {0x2d00, 0x2d25, 1}, - {0x2d27, 0x2d2d, 6}, - ], + R16: [ + {0x10a0, 0x10c5, 1}, + {0x10c7, 0x10cd, 6}, + {0x10d0, 0x10fa, 1}, + {0x10fc, 0x10ff, 1}, + {0x1c90, 0x1cba, 1}, + {0x1cbd, 0x1cbf, 1}, + {0x2d00, 0x2d25, 1}, + {0x2d27, 0x2d2d, 6}, + ], } static _GLAGOLITIC = &RangeTable{ - R16: [ - {0x2c00, 0x2c5f, 1}, - ], - R32: [ - {0x1e000, 0x1e006, 1}, - {0x1e008, 0x1e018, 1}, - {0x1e01b, 0x1e021, 1}, - {0x1e023, 0x1e024, 1}, - {0x1e026, 0x1e02a, 1}, - ], + R16: [ + {0x2c00, 0x2c5f, 1}, + ], + R32: [ + {0x1e000, 0x1e006, 1}, + {0x1e008, 0x1e018, 1}, + {0x1e01b, 0x1e021, 1}, + {0x1e023, 0x1e024, 1}, + {0x1e026, 0x1e02a, 1}, + ], } static _GOTHIC = &RangeTable{ - R16: [], - R32: [ - {0x10330, 0x1034a, 1}, - ], + R16: [], + R32: [ + {0x10330, 0x1034a, 1}, + ], } static _GRANTHA = &RangeTable{ - R16: [], - R32: [ - {0x11300, 0x11303, 1}, - {0x11305, 0x1130c, 1}, - {0x1130f, 0x11310, 1}, - {0x11313, 0x11328, 1}, - {0x1132a, 0x11330, 1}, - {0x11332, 0x11333, 1}, - {0x11335, 0x11339, 1}, - {0x1133c, 0x11344, 1}, - {0x11347, 0x11348, 1}, - {0x1134b, 0x1134d, 1}, - {0x11350, 0x11357, 7}, - {0x1135d, 0x11363, 1}, - {0x11366, 0x1136c, 1}, - {0x11370, 0x11374, 1}, - ], + R16: [], + R32: [ + {0x11300, 0x11303, 1}, + {0x11305, 0x1130c, 1}, + {0x1130f, 0x11310, 1}, + {0x11313, 0x11328, 1}, + {0x1132a, 0x11330, 1}, + {0x11332, 0x11333, 1}, + {0x11335, 0x11339, 1}, + {0x1133c, 0x11344, 1}, + {0x11347, 0x11348, 1}, + {0x1134b, 0x1134d, 1}, + {0x11350, 0x11357, 7}, + {0x1135d, 0x11363, 1}, + {0x11366, 0x1136c, 1}, + {0x11370, 0x11374, 1}, + ], } static _GREEK = &RangeTable{ - R16: [ - {0x0370, 0x0373, 1}, - {0x0375, 0x0377, 1}, - {0x037a, 0x037d, 1}, - {0x037f, 0x0384, 5}, - {0x0386, 0x0388, 2}, - {0x0389, 0x038a, 1}, - {0x038c, 0x038e, 2}, - {0x038f, 0x03a1, 1}, - {0x03a3, 0x03e1, 1}, - {0x03f0, 0x03ff, 1}, - {0x1d26, 0x1d2a, 1}, - {0x1d5d, 0x1d61, 1}, - {0x1d66, 0x1d6a, 1}, - {0x1dbf, 0x1f00, 321}, - {0x1f01, 0x1f15, 1}, - {0x1f18, 0x1f1d, 1}, - {0x1f20, 0x1f45, 1}, - {0x1f48, 0x1f4d, 1}, - {0x1f50, 0x1f57, 1}, - {0x1f59, 0x1f5f, 2}, - {0x1f60, 0x1f7d, 1}, - {0x1f80, 0x1fb4, 1}, - {0x1fb6, 0x1fc4, 1}, - {0x1fc6, 0x1fd3, 1}, - {0x1fd6, 0x1fdb, 1}, - {0x1fdd, 0x1fef, 1}, - {0x1ff2, 0x1ff4, 1}, - {0x1ff6, 0x1ffe, 1}, - {0x2126, 0xab65, 35391}, - ], - R32: [ - {0x10140, 0x1018e, 1}, - {0x101a0, 0x1d200, 53344}, - {0x1d201, 0x1d245, 1}, - ], + R16: [ + {0x0370, 0x0373, 1}, + {0x0375, 0x0377, 1}, + {0x037a, 0x037d, 1}, + {0x037f, 0x0384, 5}, + {0x0386, 0x0388, 2}, + {0x0389, 0x038a, 1}, + {0x038c, 0x038e, 2}, + {0x038f, 0x03a1, 1}, + {0x03a3, 0x03e1, 1}, + {0x03f0, 0x03ff, 1}, + {0x1d26, 0x1d2a, 1}, + {0x1d5d, 0x1d61, 1}, + {0x1d66, 0x1d6a, 1}, + {0x1dbf, 0x1f00, 321}, + {0x1f01, 0x1f15, 1}, + {0x1f18, 0x1f1d, 1}, + {0x1f20, 0x1f45, 1}, + {0x1f48, 0x1f4d, 1}, + {0x1f50, 0x1f57, 1}, + {0x1f59, 0x1f5f, 2}, + {0x1f60, 0x1f7d, 1}, + {0x1f80, 0x1fb4, 1}, + {0x1fb6, 0x1fc4, 1}, + {0x1fc6, 0x1fd3, 1}, + {0x1fd6, 0x1fdb, 1}, + {0x1fdd, 0x1fef, 1}, + {0x1ff2, 0x1ff4, 1}, + {0x1ff6, 0x1ffe, 1}, + {0x2126, 0xab65, 35391}, + ], + R32: [ + {0x10140, 0x1018e, 1}, + {0x101a0, 0x1d200, 53344}, + {0x1d201, 0x1d245, 1}, + ], } static _GUJARATI = &RangeTable{ - R16: [ - {0x0a81, 0x0a83, 1}, - {0x0a85, 0x0a8d, 1}, - {0x0a8f, 0x0a91, 1}, - {0x0a93, 0x0aa8, 1}, - {0x0aaa, 0x0ab0, 1}, - {0x0ab2, 0x0ab3, 1}, - {0x0ab5, 0x0ab9, 1}, - {0x0abc, 0x0ac5, 1}, - {0x0ac7, 0x0ac9, 1}, - {0x0acb, 0x0acd, 1}, - {0x0ad0, 0x0ae0, 16}, - {0x0ae1, 0x0ae3, 1}, - {0x0ae6, 0x0af1, 1}, - {0x0af9, 0x0aff, 1}, - ], + R16: [ + {0x0a81, 0x0a83, 1}, + {0x0a85, 0x0a8d, 1}, + {0x0a8f, 0x0a91, 1}, + {0x0a93, 0x0aa8, 1}, + {0x0aaa, 0x0ab0, 1}, + {0x0ab2, 0x0ab3, 1}, + {0x0ab5, 0x0ab9, 1}, + {0x0abc, 0x0ac5, 1}, + {0x0ac7, 0x0ac9, 1}, + {0x0acb, 0x0acd, 1}, + {0x0ad0, 0x0ae0, 16}, + {0x0ae1, 0x0ae3, 1}, + {0x0ae6, 0x0af1, 1}, + {0x0af9, 0x0aff, 1}, + ], } static _GUNJALA_GONDI = &RangeTable{ - R16: [], - R32: [ - {0x11d60, 0x11d65, 1}, - {0x11d67, 0x11d68, 1}, - {0x11d6a, 0x11d8e, 1}, - {0x11d90, 0x11d91, 1}, - {0x11d93, 0x11d98, 1}, - {0x11da0, 0x11da9, 1}, - ], + R16: [], + R32: [ + {0x11d60, 0x11d65, 1}, + {0x11d67, 0x11d68, 1}, + {0x11d6a, 0x11d8e, 1}, + {0x11d90, 0x11d91, 1}, + {0x11d93, 0x11d98, 1}, + {0x11da0, 0x11da9, 1}, + ], } static _GURMUKHI = &RangeTable{ - R16: [ - {0x0a01, 0x0a03, 1}, - {0x0a05, 0x0a0a, 1}, - {0x0a0f, 0x0a10, 1}, - {0x0a13, 0x0a28, 1}, - {0x0a2a, 0x0a30, 1}, - {0x0a32, 0x0a33, 1}, - {0x0a35, 0x0a36, 1}, - {0x0a38, 0x0a39, 1}, - {0x0a3c, 0x0a3e, 2}, - {0x0a3f, 0x0a42, 1}, - {0x0a47, 0x0a48, 1}, - {0x0a4b, 0x0a4d, 1}, - {0x0a51, 0x0a59, 8}, - {0x0a5a, 0x0a5c, 1}, - {0x0a5e, 0x0a66, 8}, - {0x0a67, 0x0a76, 1}, - ], + R16: [ + {0x0a01, 0x0a03, 1}, + {0x0a05, 0x0a0a, 1}, + {0x0a0f, 0x0a10, 1}, + {0x0a13, 0x0a28, 1}, + {0x0a2a, 0x0a30, 1}, + {0x0a32, 0x0a33, 1}, + {0x0a35, 0x0a36, 1}, + {0x0a38, 0x0a39, 1}, + {0x0a3c, 0x0a3e, 2}, + {0x0a3f, 0x0a42, 1}, + {0x0a47, 0x0a48, 1}, + {0x0a4b, 0x0a4d, 1}, + {0x0a51, 0x0a59, 8}, + {0x0a5a, 0x0a5c, 1}, + {0x0a5e, 0x0a66, 8}, + {0x0a67, 0x0a76, 1}, + ], } static _HAN = &RangeTable{ - R16: [ - {0x2e80, 0x2e99, 1}, - {0x2e9b, 0x2ef3, 1}, - {0x2f00, 0x2fd5, 1}, - {0x3005, 0x3007, 2}, - {0x3021, 0x3029, 1}, - {0x3038, 0x303b, 1}, - {0x3400, 0x4dbf, 1}, - {0x4e00, 0x9fff, 1}, - {0xf900, 0xfa6d, 1}, - {0xfa70, 0xfad9, 1}, - ], - R32: [ - {0x16fe2, 0x16fe3, 1}, - {0x16ff0, 0x16ff1, 1}, - {0x20000, 0x2a6df, 1}, - {0x2a700, 0x2b739, 1}, - {0x2b740, 0x2b81d, 1}, - {0x2b820, 0x2cea1, 1}, - {0x2ceb0, 0x2ebe0, 1}, - {0x2f800, 0x2fa1d, 1}, - {0x30000, 0x3134a, 1}, - {0x31350, 0x323af, 1}, - ], + R16: [ + {0x2e80, 0x2e99, 1}, + {0x2e9b, 0x2ef3, 1}, + {0x2f00, 0x2fd5, 1}, + {0x3005, 0x3007, 2}, + {0x3021, 0x3029, 1}, + {0x3038, 0x303b, 1}, + {0x3400, 0x4dbf, 1}, + {0x4e00, 0x9fff, 1}, + {0xf900, 0xfa6d, 1}, + {0xfa70, 0xfad9, 1}, + ], + R32: [ + {0x16fe2, 0x16fe3, 1}, + {0x16ff0, 0x16ff1, 1}, + {0x20000, 0x2a6df, 1}, + {0x2a700, 0x2b739, 1}, + {0x2b740, 0x2b81d, 1}, + {0x2b820, 0x2cea1, 1}, + {0x2ceb0, 0x2ebe0, 1}, + {0x2f800, 0x2fa1d, 1}, + {0x30000, 0x3134a, 1}, + {0x31350, 0x323af, 1}, + ], } static _HANGUL = &RangeTable{ - R16: [ - {0x1100, 0x11ff, 1}, - {0x302e, 0x302f, 1}, - {0x3131, 0x318e, 1}, - {0x3200, 0x321e, 1}, - {0x3260, 0x327e, 1}, - {0xa960, 0xa97c, 1}, - {0xac00, 0xd7a3, 1}, - {0xd7b0, 0xd7c6, 1}, - {0xd7cb, 0xd7fb, 1}, - {0xffa0, 0xffbe, 1}, - {0xffc2, 0xffc7, 1}, - {0xffca, 0xffcf, 1}, - {0xffd2, 0xffd7, 1}, - {0xffda, 0xffdc, 1}, - ], + R16: [ + {0x1100, 0x11ff, 1}, + {0x302e, 0x302f, 1}, + {0x3131, 0x318e, 1}, + {0x3200, 0x321e, 1}, + {0x3260, 0x327e, 1}, + {0xa960, 0xa97c, 1}, + {0xac00, 0xd7a3, 1}, + {0xd7b0, 0xd7c6, 1}, + {0xd7cb, 0xd7fb, 1}, + {0xffa0, 0xffbe, 1}, + {0xffc2, 0xffc7, 1}, + {0xffca, 0xffcf, 1}, + {0xffd2, 0xffd7, 1}, + {0xffda, 0xffdc, 1}, + ], } static _HANIFI_ROHINGYA = &RangeTable{ - R16: [], - R32: [ - {0x10d00, 0x10d27, 1}, - {0x10d30, 0x10d39, 1}, - ], + R16: [], + R32: [ + {0x10d00, 0x10d27, 1}, + {0x10d30, 0x10d39, 1}, + ], } static _HANUNOO = &RangeTable{ - R16: [ - {0x1720, 0x1734, 1}, - ], + R16: [ + {0x1720, 0x1734, 1}, + ], } static _HATRAN = &RangeTable{ - R16: [], - R32: [ - {0x108e0, 0x108f2, 1}, - {0x108f4, 0x108f5, 1}, - {0x108fb, 0x108ff, 1}, - ], + R16: [], + R32: [ + {0x108e0, 0x108f2, 1}, + {0x108f4, 0x108f5, 1}, + {0x108fb, 0x108ff, 1}, + ], } static _HEBREW = &RangeTable{ - R16: [ - {0x0591, 0x05c7, 1}, - {0x05d0, 0x05ea, 1}, - {0x05ef, 0x05f4, 1}, - {0xfb1d, 0xfb36, 1}, - {0xfb38, 0xfb3c, 1}, - {0xfb3e, 0xfb40, 2}, - {0xfb41, 0xfb43, 2}, - {0xfb44, 0xfb46, 2}, - {0xfb47, 0xfb4f, 1}, - ], + R16: [ + {0x0591, 0x05c7, 1}, + {0x05d0, 0x05ea, 1}, + {0x05ef, 0x05f4, 1}, + {0xfb1d, 0xfb36, 1}, + {0xfb38, 0xfb3c, 1}, + {0xfb3e, 0xfb40, 2}, + {0xfb41, 0xfb43, 2}, + {0xfb44, 0xfb46, 2}, + {0xfb47, 0xfb4f, 1}, + ], } static _HIRAGANA = &RangeTable{ - R16: [ - {0x3041, 0x3096, 1}, - {0x309d, 0x309f, 1}, - ], - R32: [ - {0x1b001, 0x1b11f, 1}, - {0x1b132, 0x1b150, 30}, - {0x1b151, 0x1b152, 1}, - {0x1f200, 0x1f200, 1}, - ], + R16: [ + {0x3041, 0x3096, 1}, + {0x309d, 0x309f, 1}, + ], + R32: [ + {0x1b001, 0x1b11f, 1}, + {0x1b132, 0x1b150, 30}, + {0x1b151, 0x1b152, 1}, + {0x1f200, 0x1f200, 1}, + ], } static _IMPERIAL_ARAMAIC = &RangeTable{ - R16: [], - R32: [ - {0x10840, 0x10855, 1}, - {0x10857, 0x1085f, 1}, - ], + R16: [], + R32: [ + {0x10840, 0x10855, 1}, + {0x10857, 0x1085f, 1}, + ], } static _INHERITED = &RangeTable{ - R16: [ - {0x0300, 0x036f, 1}, - {0x0485, 0x0486, 1}, - {0x064b, 0x0655, 1}, - {0x0670, 0x0951, 737}, - {0x0952, 0x0954, 1}, - {0x1ab0, 0x1ace, 1}, - {0x1cd0, 0x1cd2, 1}, - {0x1cd4, 0x1ce0, 1}, - {0x1ce2, 0x1ce8, 1}, - {0x1ced, 0x1cf4, 7}, - {0x1cf8, 0x1cf9, 1}, - {0x1dc0, 0x1dff, 1}, - {0x200c, 0x200d, 1}, - {0x20d0, 0x20f0, 1}, - {0x302a, 0x302d, 1}, - {0x3099, 0x309a, 1}, - {0xfe00, 0xfe0f, 1}, - {0xfe20, 0xfe2d, 1}, - ], - R32: [ - {0x101fd, 0x102e0, 227}, - {0x1133b, 0x1cf00, 48069}, - {0x1cf01, 0x1cf2d, 1}, - {0x1cf30, 0x1cf46, 1}, - {0x1d167, 0x1d169, 1}, - {0x1d17b, 0x1d182, 1}, - {0x1d185, 0x1d18b, 1}, - {0x1d1aa, 0x1d1ad, 1}, - {0xe0100, 0xe01ef, 1}, - ], + R16: [ + {0x0300, 0x036f, 1}, + {0x0485, 0x0486, 1}, + {0x064b, 0x0655, 1}, + {0x0670, 0x0951, 737}, + {0x0952, 0x0954, 1}, + {0x1ab0, 0x1ace, 1}, + {0x1cd0, 0x1cd2, 1}, + {0x1cd4, 0x1ce0, 1}, + {0x1ce2, 0x1ce8, 1}, + {0x1ced, 0x1cf4, 7}, + {0x1cf8, 0x1cf9, 1}, + {0x1dc0, 0x1dff, 1}, + {0x200c, 0x200d, 1}, + {0x20d0, 0x20f0, 1}, + {0x302a, 0x302d, 1}, + {0x3099, 0x309a, 1}, + {0xfe00, 0xfe0f, 1}, + {0xfe20, 0xfe2d, 1}, + ], + R32: [ + {0x101fd, 0x102e0, 227}, + {0x1133b, 0x1cf00, 48069}, + {0x1cf01, 0x1cf2d, 1}, + {0x1cf30, 0x1cf46, 1}, + {0x1d167, 0x1d169, 1}, + {0x1d17b, 0x1d182, 1}, + {0x1d185, 0x1d18b, 1}, + {0x1d1aa, 0x1d1ad, 1}, + {0xe0100, 0xe01ef, 1}, + ], } static _INSCRIPTIONAL_PAHLAVI = &RangeTable{ - R16: [], - R32: [ - {0x10b60, 0x10b72, 1}, - {0x10b78, 0x10b7f, 1}, - ], + R16: [], + R32: [ + {0x10b60, 0x10b72, 1}, + {0x10b78, 0x10b7f, 1}, + ], } static _INSCRIPTIONAL_PARTHIAN = &RangeTable{ - R16: [], - R32: [ - {0x10b40, 0x10b55, 1}, - {0x10b58, 0x10b5f, 1}, - ], + R16: [], + R32: [ + {0x10b40, 0x10b55, 1}, + {0x10b58, 0x10b5f, 1}, + ], } static _JAVANESE = &RangeTable{ - R16: [ - {0xa980, 0xa9cd, 1}, - {0xa9d0, 0xa9d9, 1}, - {0xa9de, 0xa9df, 1}, - ], + R16: [ + {0xa980, 0xa9cd, 1}, + {0xa9d0, 0xa9d9, 1}, + {0xa9de, 0xa9df, 1}, + ], } static _KAITHI = &RangeTable{ - R16: [], - R32: [ - {0x11080, 0x110c2, 1}, - {0x110cd, 0x110cd, 1}, - ], + R16: [], + R32: [ + {0x11080, 0x110c2, 1}, + {0x110cd, 0x110cd, 1}, + ], } static _KANNADA = &RangeTable{ - R16: [ - {0x0c80, 0x0c8c, 1}, - {0x0c8e, 0x0c90, 1}, - {0x0c92, 0x0ca8, 1}, - {0x0caa, 0x0cb3, 1}, - {0x0cb5, 0x0cb9, 1}, - {0x0cbc, 0x0cc4, 1}, - {0x0cc6, 0x0cc8, 1}, - {0x0cca, 0x0ccd, 1}, - {0x0cd5, 0x0cd6, 1}, - {0x0cdd, 0x0cde, 1}, - {0x0ce0, 0x0ce3, 1}, - {0x0ce6, 0x0cef, 1}, - {0x0cf1, 0x0cf3, 1}, - ], + R16: [ + {0x0c80, 0x0c8c, 1}, + {0x0c8e, 0x0c90, 1}, + {0x0c92, 0x0ca8, 1}, + {0x0caa, 0x0cb3, 1}, + {0x0cb5, 0x0cb9, 1}, + {0x0cbc, 0x0cc4, 1}, + {0x0cc6, 0x0cc8, 1}, + {0x0cca, 0x0ccd, 1}, + {0x0cd5, 0x0cd6, 1}, + {0x0cdd, 0x0cde, 1}, + {0x0ce0, 0x0ce3, 1}, + {0x0ce6, 0x0cef, 1}, + {0x0cf1, 0x0cf3, 1}, + ], } static _KATAKANA = &RangeTable{ - R16: [ - {0x30a1, 0x30fa, 1}, - {0x30fd, 0x30ff, 1}, - {0x31f0, 0x31ff, 1}, - {0x32d0, 0x32fe, 1}, - {0x3300, 0x3357, 1}, - {0xff66, 0xff6f, 1}, - {0xff71, 0xff9d, 1}, - ], - R32: [ - {0x1aff0, 0x1aff3, 1}, - {0x1aff5, 0x1affb, 1}, - {0x1affd, 0x1affe, 1}, - {0x1b000, 0x1b120, 288}, - {0x1b121, 0x1b122, 1}, - {0x1b155, 0x1b164, 15}, - {0x1b165, 0x1b167, 1}, - ], + R16: [ + {0x30a1, 0x30fa, 1}, + {0x30fd, 0x30ff, 1}, + {0x31f0, 0x31ff, 1}, + {0x32d0, 0x32fe, 1}, + {0x3300, 0x3357, 1}, + {0xff66, 0xff6f, 1}, + {0xff71, 0xff9d, 1}, + ], + R32: [ + {0x1aff0, 0x1aff3, 1}, + {0x1aff5, 0x1affb, 1}, + {0x1affd, 0x1affe, 1}, + {0x1b000, 0x1b120, 288}, + {0x1b121, 0x1b122, 1}, + {0x1b155, 0x1b164, 15}, + {0x1b165, 0x1b167, 1}, + ], } static _KAWI = &RangeTable{ - R16: [], - R32: [ - {0x11f00, 0x11f10, 1}, - {0x11f12, 0x11f3a, 1}, - {0x11f3e, 0x11f59, 1}, - ], + R16: [], + R32: [ + {0x11f00, 0x11f10, 1}, + {0x11f12, 0x11f3a, 1}, + {0x11f3e, 0x11f59, 1}, + ], } static _KAYAH_LI = &RangeTable{ - R16: [ - {0xa900, 0xa92d, 1}, - {0xa92f, 0xa92f, 1}, - ], + R16: [ + {0xa900, 0xa92d, 1}, + {0xa92f, 0xa92f, 1}, + ], } static _KHAROSHTHI = &RangeTable{ - R16: [], - R32: [ - {0x10a00, 0x10a03, 1}, - {0x10a05, 0x10a06, 1}, - {0x10a0c, 0x10a13, 1}, - {0x10a15, 0x10a17, 1}, - {0x10a19, 0x10a35, 1}, - {0x10a38, 0x10a3a, 1}, - {0x10a3f, 0x10a48, 1}, - {0x10a50, 0x10a58, 1}, - ], + R16: [], + R32: [ + {0x10a00, 0x10a03, 1}, + {0x10a05, 0x10a06, 1}, + {0x10a0c, 0x10a13, 1}, + {0x10a15, 0x10a17, 1}, + {0x10a19, 0x10a35, 1}, + {0x10a38, 0x10a3a, 1}, + {0x10a3f, 0x10a48, 1}, + {0x10a50, 0x10a58, 1}, + ], } static _KHITAN_SMALL_SCRIPT = &RangeTable{ - R16: [], - R32: [ - {0x16fe4, 0x18b00, 6940}, - {0x18b01, 0x18cd5, 1}, - ], + R16: [], + R32: [ + {0x16fe4, 0x18b00, 6940}, + {0x18b01, 0x18cd5, 1}, + ], } static _KHMER = &RangeTable{ - R16: [ - {0x1780, 0x17dd, 1}, - {0x17e0, 0x17e9, 1}, - {0x17f0, 0x17f9, 1}, - {0x19e0, 0x19ff, 1}, - ], + R16: [ + {0x1780, 0x17dd, 1}, + {0x17e0, 0x17e9, 1}, + {0x17f0, 0x17f9, 1}, + {0x19e0, 0x19ff, 1}, + ], } static _KHOJKI = &RangeTable{ - R16: [], - R32: [ - {0x11200, 0x11211, 1}, - {0x11213, 0x11241, 1}, - ], + R16: [], + R32: [ + {0x11200, 0x11211, 1}, + {0x11213, 0x11241, 1}, + ], } static _KHUDAWADI = &RangeTable{ - R16: [], - R32: [ - {0x112b0, 0x112ea, 1}, - {0x112f0, 0x112f9, 1}, - ], + R16: [], + R32: [ + {0x112b0, 0x112ea, 1}, + {0x112f0, 0x112f9, 1}, + ], } static _LAO = &RangeTable{ - R16: [ - {0x0e81, 0x0e82, 1}, - {0x0e84, 0x0e86, 2}, - {0x0e87, 0x0e8a, 1}, - {0x0e8c, 0x0ea3, 1}, - {0x0ea5, 0x0ea7, 2}, - {0x0ea8, 0x0ebd, 1}, - {0x0ec0, 0x0ec4, 1}, - {0x0ec6, 0x0ec8, 2}, - {0x0ec9, 0x0ece, 1}, - {0x0ed0, 0x0ed9, 1}, - {0x0edc, 0x0edf, 1}, - ], + R16: [ + {0x0e81, 0x0e82, 1}, + {0x0e84, 0x0e86, 2}, + {0x0e87, 0x0e8a, 1}, + {0x0e8c, 0x0ea3, 1}, + {0x0ea5, 0x0ea7, 2}, + {0x0ea8, 0x0ebd, 1}, + {0x0ec0, 0x0ec4, 1}, + {0x0ec6, 0x0ec8, 2}, + {0x0ec9, 0x0ece, 1}, + {0x0ed0, 0x0ed9, 1}, + {0x0edc, 0x0edf, 1}, + ], } static _LATIN = &RangeTable{ - R16: [ - {0x0041, 0x005a, 1}, - {0x0061, 0x007a, 1}, - {0x00aa, 0x00ba, 16}, - {0x00c0, 0x00d6, 1}, - {0x00d8, 0x00f6, 1}, - {0x00f8, 0x02b8, 1}, - {0x02e0, 0x02e4, 1}, - {0x1d00, 0x1d25, 1}, - {0x1d2c, 0x1d5c, 1}, - {0x1d62, 0x1d65, 1}, - {0x1d6b, 0x1d77, 1}, - {0x1d79, 0x1dbe, 1}, - {0x1e00, 0x1eff, 1}, - {0x2071, 0x207f, 14}, - {0x2090, 0x209c, 1}, - {0x212a, 0x212b, 1}, - {0x2132, 0x214e, 28}, - {0x2160, 0x2188, 1}, - {0x2c60, 0x2c7f, 1}, - {0xa722, 0xa787, 1}, - {0xa78b, 0xa7ca, 1}, - {0xa7d0, 0xa7d1, 1}, - {0xa7d3, 0xa7d5, 2}, - {0xa7d6, 0xa7d9, 1}, - {0xa7f2, 0xa7ff, 1}, - {0xab30, 0xab5a, 1}, - {0xab5c, 0xab64, 1}, - {0xab66, 0xab69, 1}, - {0xfb00, 0xfb06, 1}, - {0xff21, 0xff3a, 1}, - {0xff41, 0xff5a, 1}, - ], - R32: [ - {0x10780, 0x10785, 1}, - {0x10787, 0x107b0, 1}, - {0x107b2, 0x107ba, 1}, - {0x1df00, 0x1df1e, 1}, - {0x1df25, 0x1df2a, 1}, - ], - LatinOffset: 5, + R16: [ + {0x0041, 0x005a, 1}, + {0x0061, 0x007a, 1}, + {0x00aa, 0x00ba, 16}, + {0x00c0, 0x00d6, 1}, + {0x00d8, 0x00f6, 1}, + {0x00f8, 0x02b8, 1}, + {0x02e0, 0x02e4, 1}, + {0x1d00, 0x1d25, 1}, + {0x1d2c, 0x1d5c, 1}, + {0x1d62, 0x1d65, 1}, + {0x1d6b, 0x1d77, 1}, + {0x1d79, 0x1dbe, 1}, + {0x1e00, 0x1eff, 1}, + {0x2071, 0x207f, 14}, + {0x2090, 0x209c, 1}, + {0x212a, 0x212b, 1}, + {0x2132, 0x214e, 28}, + {0x2160, 0x2188, 1}, + {0x2c60, 0x2c7f, 1}, + {0xa722, 0xa787, 1}, + {0xa78b, 0xa7ca, 1}, + {0xa7d0, 0xa7d1, 1}, + {0xa7d3, 0xa7d5, 2}, + {0xa7d6, 0xa7d9, 1}, + {0xa7f2, 0xa7ff, 1}, + {0xab30, 0xab5a, 1}, + {0xab5c, 0xab64, 1}, + {0xab66, 0xab69, 1}, + {0xfb00, 0xfb06, 1}, + {0xff21, 0xff3a, 1}, + {0xff41, 0xff5a, 1}, + ], + R32: [ + {0x10780, 0x10785, 1}, + {0x10787, 0x107b0, 1}, + {0x107b2, 0x107ba, 1}, + {0x1df00, 0x1df1e, 1}, + {0x1df25, 0x1df2a, 1}, + ], + LatinOffset: 5, } static _LEPCHA = &RangeTable{ - R16: [ - {0x1c00, 0x1c37, 1}, - {0x1c3b, 0x1c49, 1}, - {0x1c4d, 0x1c4f, 1}, - ], + R16: [ + {0x1c00, 0x1c37, 1}, + {0x1c3b, 0x1c49, 1}, + {0x1c4d, 0x1c4f, 1}, + ], } static _LIMBU = &RangeTable{ - R16: [ - {0x1900, 0x191e, 1}, - {0x1920, 0x192b, 1}, - {0x1930, 0x193b, 1}, - {0x1940, 0x1944, 4}, - {0x1945, 0x194f, 1}, - ], + R16: [ + {0x1900, 0x191e, 1}, + {0x1920, 0x192b, 1}, + {0x1930, 0x193b, 1}, + {0x1940, 0x1944, 4}, + {0x1945, 0x194f, 1}, + ], } static _LINEAR_A = &RangeTable{ - R16: [], - R32: [ - {0x10600, 0x10736, 1}, - {0x10740, 0x10755, 1}, - {0x10760, 0x10767, 1}, - ], + R16: [], + R32: [ + {0x10600, 0x10736, 1}, + {0x10740, 0x10755, 1}, + {0x10760, 0x10767, 1}, + ], } static _LINEAR_B = &RangeTable{ - R16: [], - R32: [ - {0x10000, 0x1000b, 1}, - {0x1000d, 0x10026, 1}, - {0x10028, 0x1003a, 1}, - {0x1003c, 0x1003d, 1}, - {0x1003f, 0x1004d, 1}, - {0x10050, 0x1005d, 1}, - {0x10080, 0x100fa, 1}, - ], + R16: [], + R32: [ + {0x10000, 0x1000b, 1}, + {0x1000d, 0x10026, 1}, + {0x10028, 0x1003a, 1}, + {0x1003c, 0x1003d, 1}, + {0x1003f, 0x1004d, 1}, + {0x10050, 0x1005d, 1}, + {0x10080, 0x100fa, 1}, + ], } static _LISU = &RangeTable{ - R16: [ - {0xa4d0, 0xa4ff, 1}, - ], - R32: [ - {0x11fb0, 0x11fb0, 1}, - ], + R16: [ + {0xa4d0, 0xa4ff, 1}, + ], + R32: [ + {0x11fb0, 0x11fb0, 1}, + ], } static _LYCIAN = &RangeTable{ - R16: [], - R32: [ - {0x10280, 0x1029c, 1}, - ], + R16: [], + R32: [ + {0x10280, 0x1029c, 1}, + ], } static _LYDIAN = &RangeTable{ - R16: [], - R32: [ - {0x10920, 0x10939, 1}, - {0x1093f, 0x1093f, 1}, - ], + R16: [], + R32: [ + {0x10920, 0x10939, 1}, + {0x1093f, 0x1093f, 1}, + ], } static _MAHAJANI = &RangeTable{ - R16: [], - R32: [ - {0x11150, 0x11176, 1}, - ], + R16: [], + R32: [ + {0x11150, 0x11176, 1}, + ], } static _MAKASAR = &RangeTable{ - R16: [], - R32: [ - {0x11ee0, 0x11ef8, 1}, - ], + R16: [], + R32: [ + {0x11ee0, 0x11ef8, 1}, + ], } static _MALAYALAM = &RangeTable{ - R16: [ - {0x0d00, 0x0d0c, 1}, - {0x0d0e, 0x0d10, 1}, - {0x0d12, 0x0d44, 1}, - {0x0d46, 0x0d48, 1}, - {0x0d4a, 0x0d4f, 1}, - {0x0d54, 0x0d63, 1}, - {0x0d66, 0x0d7f, 1}, - ], + R16: [ + {0x0d00, 0x0d0c, 1}, + {0x0d0e, 0x0d10, 1}, + {0x0d12, 0x0d44, 1}, + {0x0d46, 0x0d48, 1}, + {0x0d4a, 0x0d4f, 1}, + {0x0d54, 0x0d63, 1}, + {0x0d66, 0x0d7f, 1}, + ], } static _MANDAIC = &RangeTable{ - R16: [ - {0x0840, 0x085b, 1}, - {0x085e, 0x085e, 1}, - ], + R16: [ + {0x0840, 0x085b, 1}, + {0x085e, 0x085e, 1}, + ], } static _MANICHAEAN = &RangeTable{ - R16: [], - R32: [ - {0x10ac0, 0x10ae6, 1}, - {0x10aeb, 0x10af6, 1}, - ], + R16: [], + R32: [ + {0x10ac0, 0x10ae6, 1}, + {0x10aeb, 0x10af6, 1}, + ], } static _MARCHEN = &RangeTable{ - R16: [], - R32: [ - {0x11c70, 0x11c8f, 1}, - {0x11c92, 0x11ca7, 1}, - {0x11ca9, 0x11cb6, 1}, - ], + R16: [], + R32: [ + {0x11c70, 0x11c8f, 1}, + {0x11c92, 0x11ca7, 1}, + {0x11ca9, 0x11cb6, 1}, + ], } static _MASARAM_GONDI = &RangeTable{ - R16: [], - R32: [ - {0x11d00, 0x11d06, 1}, - {0x11d08, 0x11d09, 1}, - {0x11d0b, 0x11d36, 1}, - {0x11d3a, 0x11d3c, 2}, - {0x11d3d, 0x11d3f, 2}, - {0x11d40, 0x11d47, 1}, - {0x11d50, 0x11d59, 1}, - ], + R16: [], + R32: [ + {0x11d00, 0x11d06, 1}, + {0x11d08, 0x11d09, 1}, + {0x11d0b, 0x11d36, 1}, + {0x11d3a, 0x11d3c, 2}, + {0x11d3d, 0x11d3f, 2}, + {0x11d40, 0x11d47, 1}, + {0x11d50, 0x11d59, 1}, + ], } static _MEDEFAIDRIN = &RangeTable{ - R16: [], - R32: [ - {0x16e40, 0x16e9a, 1}, - ], + R16: [], + R32: [ + {0x16e40, 0x16e9a, 1}, + ], } static _MEETEI_MAYEK = &RangeTable{ - R16: [ - {0xaae0, 0xaaf6, 1}, - {0xabc0, 0xabed, 1}, - {0xabf0, 0xabf9, 1}, - ], + R16: [ + {0xaae0, 0xaaf6, 1}, + {0xabc0, 0xabed, 1}, + {0xabf0, 0xabf9, 1}, + ], } static _MENDE_KIKAKUI = &RangeTable{ - R16: [], - R32: [ - {0x1e800, 0x1e8c4, 1}, - {0x1e8c7, 0x1e8d6, 1}, - ], + R16: [], + R32: [ + {0x1e800, 0x1e8c4, 1}, + {0x1e8c7, 0x1e8d6, 1}, + ], } static _MEROITIC_CURSIVE = &RangeTable{ - R16: [], - R32: [ - {0x109a0, 0x109b7, 1}, - {0x109bc, 0x109cf, 1}, - {0x109d2, 0x109ff, 1}, - ], + R16: [], + R32: [ + {0x109a0, 0x109b7, 1}, + {0x109bc, 0x109cf, 1}, + {0x109d2, 0x109ff, 1}, + ], } static _MEROITIC_HIEROGLYPHS = &RangeTable{ - R16: [], - R32: [ - {0x10980, 0x1099f, 1}, - ], + R16: [], + R32: [ + {0x10980, 0x1099f, 1}, + ], } static _MIAO = &RangeTable{ - R16: [], - R32: [ - {0x16f00, 0x16f4a, 1}, - {0x16f4f, 0x16f87, 1}, - {0x16f8f, 0x16f9f, 1}, - ], + R16: [], + R32: [ + {0x16f00, 0x16f4a, 1}, + {0x16f4f, 0x16f87, 1}, + {0x16f8f, 0x16f9f, 1}, + ], } static _MODI = &RangeTable{ - R16: [], - R32: [ - {0x11600, 0x11644, 1}, - {0x11650, 0x11659, 1}, - ], + R16: [], + R32: [ + {0x11600, 0x11644, 1}, + {0x11650, 0x11659, 1}, + ], } static _MONGOLIAN = &RangeTable{ - R16: [ - {0x1800, 0x1801, 1}, - {0x1804, 0x1806, 2}, - {0x1807, 0x1819, 1}, - {0x1820, 0x1878, 1}, - {0x1880, 0x18aa, 1}, - ], - R32: [ - {0x11660, 0x1166c, 1}, - ], + R16: [ + {0x1800, 0x1801, 1}, + {0x1804, 0x1806, 2}, + {0x1807, 0x1819, 1}, + {0x1820, 0x1878, 1}, + {0x1880, 0x18aa, 1}, + ], + R32: [ + {0x11660, 0x1166c, 1}, + ], } static _MRO = &RangeTable{ - R16: [], - R32: [ - {0x16a40, 0x16a5e, 1}, - {0x16a60, 0x16a69, 1}, - {0x16a6e, 0x16a6f, 1}, - ], + R16: [], + R32: [ + {0x16a40, 0x16a5e, 1}, + {0x16a60, 0x16a69, 1}, + {0x16a6e, 0x16a6f, 1}, + ], } static _MULTANI = &RangeTable{ - R16: [], - R32: [ - {0x11280, 0x11286, 1}, - {0x11288, 0x1128a, 2}, - {0x1128b, 0x1128d, 1}, - {0x1128f, 0x1129d, 1}, - {0x1129f, 0x112a9, 1}, - ], + R16: [], + R32: [ + {0x11280, 0x11286, 1}, + {0x11288, 0x1128a, 2}, + {0x1128b, 0x1128d, 1}, + {0x1128f, 0x1129d, 1}, + {0x1129f, 0x112a9, 1}, + ], } static _MYANMAR = &RangeTable{ - R16: [ - {0x1000, 0x109f, 1}, - {0xa9e0, 0xa9fe, 1}, - {0xaa60, 0xaa7f, 1}, - ], + R16: [ + {0x1000, 0x109f, 1}, + {0xa9e0, 0xa9fe, 1}, + {0xaa60, 0xaa7f, 1}, + ], } static _NABATAEAN = &RangeTable{ - R16: [], - R32: [ - {0x10880, 0x1089e, 1}, - {0x108a7, 0x108af, 1}, - ], + R16: [], + R32: [ + {0x10880, 0x1089e, 1}, + {0x108a7, 0x108af, 1}, + ], } static _NAG_MUNDARI = &RangeTable{ - R16: [], - R32: [ - {0x1e4d0, 0x1e4f9, 1}, - ], + R16: [], + R32: [ + {0x1e4d0, 0x1e4f9, 1}, + ], } static _NANDINAGARI = &RangeTable{ - R16: [], - R32: [ - {0x119a0, 0x119a7, 1}, - {0x119aa, 0x119d7, 1}, - {0x119da, 0x119e4, 1}, - ], + R16: [], + R32: [ + {0x119a0, 0x119a7, 1}, + {0x119aa, 0x119d7, 1}, + {0x119da, 0x119e4, 1}, + ], } static _NEW_TAI_LUE = &RangeTable{ - R16: [ - {0x1980, 0x19ab, 1}, - {0x19b0, 0x19c9, 1}, - {0x19d0, 0x19da, 1}, - {0x19de, 0x19df, 1}, - ], + R16: [ + {0x1980, 0x19ab, 1}, + {0x19b0, 0x19c9, 1}, + {0x19d0, 0x19da, 1}, + {0x19de, 0x19df, 1}, + ], } static _NEWA = &RangeTable{ - R16: [], - R32: [ - {0x11400, 0x1145b, 1}, - {0x1145d, 0x11461, 1}, - ], + R16: [], + R32: [ + {0x11400, 0x1145b, 1}, + {0x1145d, 0x11461, 1}, + ], } static _NKO = &RangeTable{ - R16: [ - {0x07c0, 0x07fa, 1}, - {0x07fd, 0x07ff, 1}, - ], + R16: [ + {0x07c0, 0x07fa, 1}, + {0x07fd, 0x07ff, 1}, + ], } static _NUSHU = &RangeTable{ - R16: [], - R32: [ - {0x16fe1, 0x1b170, 16783}, - {0x1b171, 0x1b2fb, 1}, - ], + R16: [], + R32: [ + {0x16fe1, 0x1b170, 16783}, + {0x1b171, 0x1b2fb, 1}, + ], } static _NYIAKENG_PUACHUE_HMONG = &RangeTable{ - R16: [], - R32: [ - {0x1e100, 0x1e12c, 1}, - {0x1e130, 0x1e13d, 1}, - {0x1e140, 0x1e149, 1}, - {0x1e14e, 0x1e14f, 1}, - ], + R16: [], + R32: [ + {0x1e100, 0x1e12c, 1}, + {0x1e130, 0x1e13d, 1}, + {0x1e140, 0x1e149, 1}, + {0x1e14e, 0x1e14f, 1}, + ], } static _OGHAM = &RangeTable{ - R16: [ - {0x1680, 0x169c, 1}, - ], + R16: [ + {0x1680, 0x169c, 1}, + ], } static _OL_CHIKI = &RangeTable{ - R16: [ - {0x1c50, 0x1c7f, 1}, - ], + R16: [ + {0x1c50, 0x1c7f, 1}, + ], } static _OLD_HUNGARIAN = &RangeTable{ - R16: [], - R32: [ - {0x10c80, 0x10cb2, 1}, - {0x10cc0, 0x10cf2, 1}, - {0x10cfa, 0x10cff, 1}, - ], + R16: [], + R32: [ + {0x10c80, 0x10cb2, 1}, + {0x10cc0, 0x10cf2, 1}, + {0x10cfa, 0x10cff, 1}, + ], } static _OLD_ITALIC = &RangeTable{ - R16: [], - R32: [ - {0x10300, 0x10323, 1}, - {0x1032d, 0x1032f, 1}, - ], + R16: [], + R32: [ + {0x10300, 0x10323, 1}, + {0x1032d, 0x1032f, 1}, + ], } static _OLD_NORTH_ARABIAN = &RangeTable{ - R16: [], - R32: [ - {0x10a80, 0x10a9f, 1}, - ], + R16: [], + R32: [ + {0x10a80, 0x10a9f, 1}, + ], } static _OLD_PERMIC = &RangeTable{ - R16: [], - R32: [ - {0x10350, 0x1037a, 1}, - ], + R16: [], + R32: [ + {0x10350, 0x1037a, 1}, + ], } static _OLD_PERSIAN = &RangeTable{ - R16: [], - R32: [ - {0x103a0, 0x103c3, 1}, - {0x103c8, 0x103d5, 1}, - ], + R16: [], + R32: [ + {0x103a0, 0x103c3, 1}, + {0x103c8, 0x103d5, 1}, + ], } static _OLD_SOGDIAN = &RangeTable{ - R16: [], - R32: [ - {0x10f00, 0x10f27, 1}, - ], + R16: [], + R32: [ + {0x10f00, 0x10f27, 1}, + ], } static _OLD_SOUTH_ARABIAN = &RangeTable{ - R16: [], - R32: [ - {0x10a60, 0x10a7f, 1}, - ], + R16: [], + R32: [ + {0x10a60, 0x10a7f, 1}, + ], } static _OLD_TURKIC = &RangeTable{ - R16: [], - R32: [ - {0x10c00, 0x10c48, 1}, - ], + R16: [], + R32: [ + {0x10c00, 0x10c48, 1}, + ], } static _OLD_UYGHUR = &RangeTable{ - R16: [], - R32: [ - {0x10f70, 0x10f89, 1}, - ], + R16: [], + R32: [ + {0x10f70, 0x10f89, 1}, + ], } static _ORIYA = &RangeTable{ - R16: [ - {0x0b01, 0x0b03, 1}, - {0x0b05, 0x0b0c, 1}, - {0x0b0f, 0x0b10, 1}, - {0x0b13, 0x0b28, 1}, - {0x0b2a, 0x0b30, 1}, - {0x0b32, 0x0b33, 1}, - {0x0b35, 0x0b39, 1}, - {0x0b3c, 0x0b44, 1}, - {0x0b47, 0x0b48, 1}, - {0x0b4b, 0x0b4d, 1}, - {0x0b55, 0x0b57, 1}, - {0x0b5c, 0x0b5d, 1}, - {0x0b5f, 0x0b63, 1}, - {0x0b66, 0x0b77, 1}, - ], + R16: [ + {0x0b01, 0x0b03, 1}, + {0x0b05, 0x0b0c, 1}, + {0x0b0f, 0x0b10, 1}, + {0x0b13, 0x0b28, 1}, + {0x0b2a, 0x0b30, 1}, + {0x0b32, 0x0b33, 1}, + {0x0b35, 0x0b39, 1}, + {0x0b3c, 0x0b44, 1}, + {0x0b47, 0x0b48, 1}, + {0x0b4b, 0x0b4d, 1}, + {0x0b55, 0x0b57, 1}, + {0x0b5c, 0x0b5d, 1}, + {0x0b5f, 0x0b63, 1}, + {0x0b66, 0x0b77, 1}, + ], } static _OSAGE = &RangeTable{ - R16: [], - R32: [ - {0x104b0, 0x104d3, 1}, - {0x104d8, 0x104fb, 1}, - ], + R16: [], + R32: [ + {0x104b0, 0x104d3, 1}, + {0x104d8, 0x104fb, 1}, + ], } static _OSMANYA = &RangeTable{ - R16: [], - R32: [ - {0x10480, 0x1049d, 1}, - {0x104a0, 0x104a9, 1}, - ], + R16: [], + R32: [ + {0x10480, 0x1049d, 1}, + {0x104a0, 0x104a9, 1}, + ], } static _PAHAWH_HMONG = &RangeTable{ - R16: [], - R32: [ - {0x16b00, 0x16b45, 1}, - {0x16b50, 0x16b59, 1}, - {0x16b5b, 0x16b61, 1}, - {0x16b63, 0x16b77, 1}, - {0x16b7d, 0x16b8f, 1}, - ], + R16: [], + R32: [ + {0x16b00, 0x16b45, 1}, + {0x16b50, 0x16b59, 1}, + {0x16b5b, 0x16b61, 1}, + {0x16b63, 0x16b77, 1}, + {0x16b7d, 0x16b8f, 1}, + ], } static _PALMYRENE = &RangeTable{ - R16: [], - R32: [ - {0x10860, 0x1087f, 1}, - ], + R16: [], + R32: [ + {0x10860, 0x1087f, 1}, + ], } static _PAU_CIN_HAU = &RangeTable{ - R16: [], - R32: [ - {0x11ac0, 0x11af8, 1}, - ], + R16: [], + R32: [ + {0x11ac0, 0x11af8, 1}, + ], } static _PHAGS_PA = &RangeTable{ - R16: [ - {0xa840, 0xa877, 1}, - ], + R16: [ + {0xa840, 0xa877, 1}, + ], } static _PHOENICIAN = &RangeTable{ - R16: [], - R32: [ - {0x10900, 0x1091b, 1}, - {0x1091f, 0x1091f, 1}, - ], + R16: [], + R32: [ + {0x10900, 0x1091b, 1}, + {0x1091f, 0x1091f, 1}, + ], } static _PSALTER_PAHLAVI = &RangeTable{ - R16: [], - R32: [ - {0x10b80, 0x10b91, 1}, - {0x10b99, 0x10b9c, 1}, - {0x10ba9, 0x10baf, 1}, - ], + R16: [], + R32: [ + {0x10b80, 0x10b91, 1}, + {0x10b99, 0x10b9c, 1}, + {0x10ba9, 0x10baf, 1}, + ], } static _REJANG = &RangeTable{ - R16: [ - {0xa930, 0xa953, 1}, - {0xa95f, 0xa95f, 1}, - ], + R16: [ + {0xa930, 0xa953, 1}, + {0xa95f, 0xa95f, 1}, + ], } static _RUNIC = &RangeTable{ - R16: [ - {0x16a0, 0x16ea, 1}, - {0x16ee, 0x16f8, 1}, - ], + R16: [ + {0x16a0, 0x16ea, 1}, + {0x16ee, 0x16f8, 1}, + ], } static _SAMARITAN = &RangeTable{ - R16: [ - {0x0800, 0x082d, 1}, - {0x0830, 0x083e, 1}, - ], + R16: [ + {0x0800, 0x082d, 1}, + {0x0830, 0x083e, 1}, + ], } static _SAURASHTRA = &RangeTable{ - R16: [ - {0xa880, 0xa8c5, 1}, - {0xa8ce, 0xa8d9, 1}, - ], + R16: [ + {0xa880, 0xa8c5, 1}, + {0xa8ce, 0xa8d9, 1}, + ], } static _SHARADA = &RangeTable{ - R16: [], - R32: [ - {0x11180, 0x111df, 1}, - ], + R16: [], + R32: [ + {0x11180, 0x111df, 1}, + ], } static _SHAVIAN = &RangeTable{ - R16: [], - R32: [ - {0x10450, 0x1047f, 1}, - ], + R16: [], + R32: [ + {0x10450, 0x1047f, 1}, + ], } static _SIDDHAM = &RangeTable{ - R16: [], - R32: [ - {0x11580, 0x115b5, 1}, - {0x115b8, 0x115dd, 1}, - ], + R16: [], + R32: [ + {0x11580, 0x115b5, 1}, + {0x115b8, 0x115dd, 1}, + ], } static _SIGN_WRITING = &RangeTable{ - R16: [], - R32: [ - {0x1d800, 0x1da8b, 1}, - {0x1da9b, 0x1da9f, 1}, - {0x1daa1, 0x1daaf, 1}, - ], + R16: [], + R32: [ + {0x1d800, 0x1da8b, 1}, + {0x1da9b, 0x1da9f, 1}, + {0x1daa1, 0x1daaf, 1}, + ], } static _SINHALA = &RangeTable{ - R16: [ - {0x0d81, 0x0d83, 1}, - {0x0d85, 0x0d96, 1}, - {0x0d9a, 0x0db1, 1}, - {0x0db3, 0x0dbb, 1}, - {0x0dbd, 0x0dc0, 3}, - {0x0dc1, 0x0dc6, 1}, - {0x0dca, 0x0dcf, 5}, - {0x0dd0, 0x0dd4, 1}, - {0x0dd6, 0x0dd8, 2}, - {0x0dd9, 0x0ddf, 1}, - {0x0de6, 0x0def, 1}, - {0x0df2, 0x0df4, 1}, - ], - R32: [ - {0x111e1, 0x111f4, 1}, - ], + R16: [ + {0x0d81, 0x0d83, 1}, + {0x0d85, 0x0d96, 1}, + {0x0d9a, 0x0db1, 1}, + {0x0db3, 0x0dbb, 1}, + {0x0dbd, 0x0dc0, 3}, + {0x0dc1, 0x0dc6, 1}, + {0x0dca, 0x0dcf, 5}, + {0x0dd0, 0x0dd4, 1}, + {0x0dd6, 0x0dd8, 2}, + {0x0dd9, 0x0ddf, 1}, + {0x0de6, 0x0def, 1}, + {0x0df2, 0x0df4, 1}, + ], + R32: [ + {0x111e1, 0x111f4, 1}, + ], } static _SOGDIAN = &RangeTable{ - R16: [], - R32: [ - {0x10f30, 0x10f59, 1}, - ], + R16: [], + R32: [ + {0x10f30, 0x10f59, 1}, + ], } static _SORA_SOMPENG = &RangeTable{ - R16: [], - R32: [ - {0x110d0, 0x110e8, 1}, - {0x110f0, 0x110f9, 1}, - ], + R16: [], + R32: [ + {0x110d0, 0x110e8, 1}, + {0x110f0, 0x110f9, 1}, + ], } static _SOYOMBO = &RangeTable{ - R16: [], - R32: [ - {0x11a50, 0x11aa2, 1}, - ], + R16: [], + R32: [ + {0x11a50, 0x11aa2, 1}, + ], } static _SUNDANESE = &RangeTable{ - R16: [ - {0x1b80, 0x1bbf, 1}, - {0x1cc0, 0x1cc7, 1}, - ], + R16: [ + {0x1b80, 0x1bbf, 1}, + {0x1cc0, 0x1cc7, 1}, + ], } static _SYLOTI_NAGRI = &RangeTable{ - R16: [ - {0xa800, 0xa82c, 1}, - ], + R16: [ + {0xa800, 0xa82c, 1}, + ], } static _SYRIAC = &RangeTable{ - R16: [ - {0x0700, 0x070d, 1}, - {0x070f, 0x074a, 1}, - {0x074d, 0x074f, 1}, - {0x0860, 0x086a, 1}, - ], + R16: [ + {0x0700, 0x070d, 1}, + {0x070f, 0x074a, 1}, + {0x074d, 0x074f, 1}, + {0x0860, 0x086a, 1}, + ], } static _TAGALOG = &RangeTable{ - R16: [ - {0x1700, 0x1715, 1}, - {0x171f, 0x171f, 1}, - ], + R16: [ + {0x1700, 0x1715, 1}, + {0x171f, 0x171f, 1}, + ], } static _TAGBANWA = &RangeTable{ - R16: [ - {0x1760, 0x176c, 1}, - {0x176e, 0x1770, 1}, - {0x1772, 0x1773, 1}, - ], + R16: [ + {0x1760, 0x176c, 1}, + {0x176e, 0x1770, 1}, + {0x1772, 0x1773, 1}, + ], } static _TAI_LE = &RangeTable{ - R16: [ - {0x1950, 0x196d, 1}, - {0x1970, 0x1974, 1}, - ], + R16: [ + {0x1950, 0x196d, 1}, + {0x1970, 0x1974, 1}, + ], } static _TAI_THAM = &RangeTable{ - R16: [ - {0x1a20, 0x1a5e, 1}, - {0x1a60, 0x1a7c, 1}, - {0x1a7f, 0x1a89, 1}, - {0x1a90, 0x1a99, 1}, - {0x1aa0, 0x1aad, 1}, - ], + R16: [ + {0x1a20, 0x1a5e, 1}, + {0x1a60, 0x1a7c, 1}, + {0x1a7f, 0x1a89, 1}, + {0x1a90, 0x1a99, 1}, + {0x1aa0, 0x1aad, 1}, + ], } static _TAI_VIET = &RangeTable{ - R16: [ - {0xaa80, 0xaac2, 1}, - {0xaadb, 0xaadf, 1}, - ], + R16: [ + {0xaa80, 0xaac2, 1}, + {0xaadb, 0xaadf, 1}, + ], } static _TAKRI = &RangeTable{ - R16: [], - R32: [ - {0x11680, 0x116b9, 1}, - {0x116c0, 0x116c9, 1}, - ], + R16: [], + R32: [ + {0x11680, 0x116b9, 1}, + {0x116c0, 0x116c9, 1}, + ], } static _TAMIL = &RangeTable{ - R16: [ - {0x0b82, 0x0b83, 1}, - {0x0b85, 0x0b8a, 1}, - {0x0b8e, 0x0b90, 1}, - {0x0b92, 0x0b95, 1}, - {0x0b99, 0x0b9a, 1}, - {0x0b9c, 0x0b9e, 2}, - {0x0b9f, 0x0ba3, 4}, - {0x0ba4, 0x0ba8, 4}, - {0x0ba9, 0x0baa, 1}, - {0x0bae, 0x0bb9, 1}, - {0x0bbe, 0x0bc2, 1}, - {0x0bc6, 0x0bc8, 1}, - {0x0bca, 0x0bcd, 1}, - {0x0bd0, 0x0bd7, 7}, - {0x0be6, 0x0bfa, 1}, - ], - R32: [ - {0x11fc0, 0x11ff1, 1}, - {0x11fff, 0x11fff, 1}, - ], + R16: [ + {0x0b82, 0x0b83, 1}, + {0x0b85, 0x0b8a, 1}, + {0x0b8e, 0x0b90, 1}, + {0x0b92, 0x0b95, 1}, + {0x0b99, 0x0b9a, 1}, + {0x0b9c, 0x0b9e, 2}, + {0x0b9f, 0x0ba3, 4}, + {0x0ba4, 0x0ba8, 4}, + {0x0ba9, 0x0baa, 1}, + {0x0bae, 0x0bb9, 1}, + {0x0bbe, 0x0bc2, 1}, + {0x0bc6, 0x0bc8, 1}, + {0x0bca, 0x0bcd, 1}, + {0x0bd0, 0x0bd7, 7}, + {0x0be6, 0x0bfa, 1}, + ], + R32: [ + {0x11fc0, 0x11ff1, 1}, + {0x11fff, 0x11fff, 1}, + ], } static _TANGSA = &RangeTable{ - R16: [], - R32: [ - {0x16a70, 0x16abe, 1}, - {0x16ac0, 0x16ac9, 1}, - ], + R16: [], + R32: [ + {0x16a70, 0x16abe, 1}, + {0x16ac0, 0x16ac9, 1}, + ], } static _TANGUT = &RangeTable{ - R16: [], - R32: [ - {0x16fe0, 0x17000, 32}, - {0x17001, 0x187f7, 1}, - {0x18800, 0x18aff, 1}, - {0x18d00, 0x18d08, 1}, - ], + R16: [], + R32: [ + {0x16fe0, 0x17000, 32}, + {0x17001, 0x187f7, 1}, + {0x18800, 0x18aff, 1}, + {0x18d00, 0x18d08, 1}, + ], } static _TELUGU = &RangeTable{ - R16: [ - {0x0c00, 0x0c0c, 1}, - {0x0c0e, 0x0c10, 1}, - {0x0c12, 0x0c28, 1}, - {0x0c2a, 0x0c39, 1}, - {0x0c3c, 0x0c44, 1}, - {0x0c46, 0x0c48, 1}, - {0x0c4a, 0x0c4d, 1}, - {0x0c55, 0x0c56, 1}, - {0x0c58, 0x0c5a, 1}, - {0x0c5d, 0x0c60, 3}, - {0x0c61, 0x0c63, 1}, - {0x0c66, 0x0c6f, 1}, - {0x0c77, 0x0c7f, 1}, - ], + R16: [ + {0x0c00, 0x0c0c, 1}, + {0x0c0e, 0x0c10, 1}, + {0x0c12, 0x0c28, 1}, + {0x0c2a, 0x0c39, 1}, + {0x0c3c, 0x0c44, 1}, + {0x0c46, 0x0c48, 1}, + {0x0c4a, 0x0c4d, 1}, + {0x0c55, 0x0c56, 1}, + {0x0c58, 0x0c5a, 1}, + {0x0c5d, 0x0c60, 3}, + {0x0c61, 0x0c63, 1}, + {0x0c66, 0x0c6f, 1}, + {0x0c77, 0x0c7f, 1}, + ], } static _THAANA = &RangeTable{ - R16: [ - {0x0780, 0x07b1, 1}, - ], + R16: [ + {0x0780, 0x07b1, 1}, + ], } static _THAI = &RangeTable{ - R16: [ - {0x0e01, 0x0e3a, 1}, - {0x0e40, 0x0e5b, 1}, - ], + R16: [ + {0x0e01, 0x0e3a, 1}, + {0x0e40, 0x0e5b, 1}, + ], } static _TIBETAN = &RangeTable{ - R16: [ - {0x0f00, 0x0f47, 1}, - {0x0f49, 0x0f6c, 1}, - {0x0f71, 0x0f97, 1}, - {0x0f99, 0x0fbc, 1}, - {0x0fbe, 0x0fcc, 1}, - {0x0fce, 0x0fd4, 1}, - {0x0fd9, 0x0fda, 1}, - ], + R16: [ + {0x0f00, 0x0f47, 1}, + {0x0f49, 0x0f6c, 1}, + {0x0f71, 0x0f97, 1}, + {0x0f99, 0x0fbc, 1}, + {0x0fbe, 0x0fcc, 1}, + {0x0fce, 0x0fd4, 1}, + {0x0fd9, 0x0fda, 1}, + ], } static _TIFINAGH = &RangeTable{ - R16: [ - {0x2d30, 0x2d67, 1}, - {0x2d6f, 0x2d70, 1}, - {0x2d7f, 0x2d7f, 1}, - ], + R16: [ + {0x2d30, 0x2d67, 1}, + {0x2d6f, 0x2d70, 1}, + {0x2d7f, 0x2d7f, 1}, + ], } static _TIRHUTA = &RangeTable{ - R16: [], - R32: [ - {0x11480, 0x114c7, 1}, - {0x114d0, 0x114d9, 1}, - ], + R16: [], + R32: [ + {0x11480, 0x114c7, 1}, + {0x114d0, 0x114d9, 1}, + ], } static _TOTO = &RangeTable{ - R16: [], - R32: [ - {0x1e290, 0x1e2ae, 1}, - ], + R16: [], + R32: [ + {0x1e290, 0x1e2ae, 1}, + ], } static _UGARITIC = &RangeTable{ - R16: [], - R32: [ - {0x10380, 0x1039d, 1}, - {0x1039f, 0x1039f, 1}, - ], + R16: [], + R32: [ + {0x10380, 0x1039d, 1}, + {0x1039f, 0x1039f, 1}, + ], } static _VAI = &RangeTable{ - R16: [ - {0xa500, 0xa62b, 1}, - ], + R16: [ + {0xa500, 0xa62b, 1}, + ], } static _VITHKUQI = &RangeTable{ - R16: [], - R32: [ - {0x10570, 0x1057a, 1}, - {0x1057c, 0x1058a, 1}, - {0x1058c, 0x10592, 1}, - {0x10594, 0x10595, 1}, - {0x10597, 0x105a1, 1}, - {0x105a3, 0x105b1, 1}, - {0x105b3, 0x105b9, 1}, - {0x105bb, 0x105bc, 1}, - ], + R16: [], + R32: [ + {0x10570, 0x1057a, 1}, + {0x1057c, 0x1058a, 1}, + {0x1058c, 0x10592, 1}, + {0x10594, 0x10595, 1}, + {0x10597, 0x105a1, 1}, + {0x105a3, 0x105b1, 1}, + {0x105b3, 0x105b9, 1}, + {0x105bb, 0x105bc, 1}, + ], } static _WANCHO = &RangeTable{ - R16: [], - R32: [ - {0x1e2c0, 0x1e2f9, 1}, - {0x1e2ff, 0x1e2ff, 1}, - ], + R16: [], + R32: [ + {0x1e2c0, 0x1e2f9, 1}, + {0x1e2ff, 0x1e2ff, 1}, + ], } static _WARANG_CITI = &RangeTable{ - R16: [], - R32: [ - {0x118a0, 0x118f2, 1}, - {0x118ff, 0x118ff, 1}, - ], + R16: [], + R32: [ + {0x118a0, 0x118f2, 1}, + {0x118ff, 0x118ff, 1}, + ], } static _YEZIDI = &RangeTable{ - R16: [], - R32: [ - {0x10e80, 0x10ea9, 1}, - {0x10eab, 0x10ead, 1}, - {0x10eb0, 0x10eb1, 1}, - ], + R16: [], + R32: [ + {0x10e80, 0x10ea9, 1}, + {0x10eab, 0x10ead, 1}, + {0x10eb0, 0x10eb1, 1}, + ], } static _YI = &RangeTable{ - R16: [ - {0xa000, 0xa48c, 1}, - {0xa490, 0xa4c6, 1}, - ], + R16: [ + {0xa000, 0xa48c, 1}, + {0xa490, 0xa4c6, 1}, + ], } static _ZANABAZAR_SQUARE = &RangeTable{ - R16: [], - R32: [ - {0x11a00, 0x11a47, 1}, - ], + R16: [], + R32: [ + {0x11a00, 0x11a47, 1}, + ], } // These variables have type &RangeTable. @@ -6023,1196 +6023,1196 @@ static ZanabazarSquare = _ZANABAZAR_SQUARE // The set of Unicode cha // The set of Unicode property tables. static Properties: map[str]&RangeTable = { - "AsciiHexDigit": AsciiHexDigit, - "BidiControl": BidiControl, - "Dash": Dash, - "Deprecated": Deprecated, - "Diacritic": Diacritic, - "Extender": Extender, - "HexDigit": HexDigit, - "Hyphen": Hyphen, - "IdsBinaryOperator": IdsBinaryOperator, - "IdsTrinaryOperator": IdsTrinaryOperator, - "Ideographic": Ideographic, - "JoinControl": JoinControl, - "LogicalOrderException": LogicalOrderException, - "NoncharacterCodePoint": NoncharacterCodePoint, - "OtherAlphabetic": OtherAlphabetic, - "OtherDefaultIgnorableCodePoint": OtherDefaultIgnorableCodePoint, - "OtherGraphemeExtend": OtherGraphemeExtend, - "OtherIdContinue": OtherIdContinue, - "OtherIdStart": OtherIdStart, - "OtherLowercase": OtherLowercase, - "OtherMath": OtherMath, - "OtherUppercase": OtherUppercase, - "PatternSyntax": PatternSyntax, - "PatternWhiteSpace": PatternWhiteSpace, - "PrependedConcatenationMark": PrependedConcatenationMark, - "QuotationMark": QuotationMark, - "Radical": Radical, - "RegionalIndicator": RegionalIndicator, - "SentenceTerminal": SentenceTerminal, - "SoftDotted": SoftDotted, - "TerminalPunctuation": TerminalPunctuation, - "UnifiedIdeograph": UnifiedIdeograph, - "VariationSelector": VariationSelector, - "WhiteSpace": WhiteSpace, + "AsciiHexDigit": AsciiHexDigit, + "BidiControl": BidiControl, + "Dash": Dash, + "Deprecated": Deprecated, + "Diacritic": Diacritic, + "Extender": Extender, + "HexDigit": HexDigit, + "Hyphen": Hyphen, + "IdsBinaryOperator": IdsBinaryOperator, + "IdsTrinaryOperator": IdsTrinaryOperator, + "Ideographic": Ideographic, + "JoinControl": JoinControl, + "LogicalOrderException": LogicalOrderException, + "NoncharacterCodePoint": NoncharacterCodePoint, + "OtherAlphabetic": OtherAlphabetic, + "OtherDefaultIgnorableCodePoint": OtherDefaultIgnorableCodePoint, + "OtherGraphemeExtend": OtherGraphemeExtend, + "OtherIdContinue": OtherIdContinue, + "OtherIdStart": OtherIdStart, + "OtherLowercase": OtherLowercase, + "OtherMath": OtherMath, + "OtherUppercase": OtherUppercase, + "PatternSyntax": PatternSyntax, + "PatternWhiteSpace": PatternWhiteSpace, + "PrependedConcatenationMark": PrependedConcatenationMark, + "QuotationMark": QuotationMark, + "Radical": Radical, + "RegionalIndicator": RegionalIndicator, + "SentenceTerminal": SentenceTerminal, + "SoftDotted": SoftDotted, + "TerminalPunctuation": TerminalPunctuation, + "UnifiedIdeograph": UnifiedIdeograph, + "VariationSelector": VariationSelector, + "WhiteSpace": WhiteSpace, } static _ASCII_HEX_DIGIT = &RangeTable{ - R16: [ - {0x0030, 0x0039, 1}, - {0x0041, 0x0046, 1}, - {0x0061, 0x0066, 1}, - ], - LatinOffset: 3, + R16: [ + {0x0030, 0x0039, 1}, + {0x0041, 0x0046, 1}, + {0x0061, 0x0066, 1}, + ], + LatinOffset: 3, } static _BIDI_CONTROL = &RangeTable{ - R16: [ - {0x061c, 0x200e, 6642}, - {0x200f, 0x202a, 27}, - {0x202b, 0x202e, 1}, - {0x2066, 0x2069, 1}, - ], + R16: [ + {0x061c, 0x200e, 6642}, + {0x200f, 0x202a, 27}, + {0x202b, 0x202e, 1}, + {0x2066, 0x2069, 1}, + ], } static _DASH = &RangeTable{ - R16: [ - {0x002d, 0x058a, 1373}, - {0x05be, 0x1400, 3650}, - {0x1806, 0x2010, 2058}, - {0x2011, 0x2015, 1}, - {0x2053, 0x207b, 40}, - {0x208b, 0x2212, 391}, - {0x2e17, 0x2e1a, 3}, - {0x2e3a, 0x2e3b, 1}, - {0x2e40, 0x2e5d, 29}, - {0x301c, 0x3030, 20}, - {0x30a0, 0xfe31, 52625}, - {0xfe32, 0xfe58, 38}, - {0xfe63, 0xff0d, 170}, - ], - R32: [ - {0x10ead, 0x10ead, 1}, - ], + R16: [ + {0x002d, 0x058a, 1373}, + {0x05be, 0x1400, 3650}, + {0x1806, 0x2010, 2058}, + {0x2011, 0x2015, 1}, + {0x2053, 0x207b, 40}, + {0x208b, 0x2212, 391}, + {0x2e17, 0x2e1a, 3}, + {0x2e3a, 0x2e3b, 1}, + {0x2e40, 0x2e5d, 29}, + {0x301c, 0x3030, 20}, + {0x30a0, 0xfe31, 52625}, + {0xfe32, 0xfe58, 38}, + {0xfe63, 0xff0d, 170}, + ], + R32: [ + {0x10ead, 0x10ead, 1}, + ], } static _DEPRECATED = &RangeTable{ - R16: [ - {0x0149, 0x0673, 1322}, - {0x0f77, 0x0f79, 2}, - {0x17a3, 0x17a4, 1}, - {0x206a, 0x206f, 1}, - {0x2329, 0x232a, 1}, - ], - R32: [ - {0xe0001, 0xe0001, 1}, - ], + R16: [ + {0x0149, 0x0673, 1322}, + {0x0f77, 0x0f79, 2}, + {0x17a3, 0x17a4, 1}, + {0x206a, 0x206f, 1}, + {0x2329, 0x232a, 1}, + ], + R32: [ + {0xe0001, 0xe0001, 1}, + ], } static _DIACRITIC = &RangeTable{ - R16: [ - {0x005e, 0x0060, 2}, - {0x00a8, 0x00af, 7}, - {0x00b4, 0x00b7, 3}, - {0x00b8, 0x02b0, 504}, - {0x02b1, 0x034e, 1}, - {0x0350, 0x0357, 1}, - {0x035d, 0x0362, 1}, - {0x0374, 0x0375, 1}, - {0x037a, 0x0384, 10}, - {0x0385, 0x0483, 254}, - {0x0484, 0x0487, 1}, - {0x0559, 0x0591, 56}, - {0x0592, 0x05a1, 1}, - {0x05a3, 0x05bd, 1}, - {0x05bf, 0x05c1, 2}, - {0x05c2, 0x05c4, 2}, - {0x064b, 0x0652, 1}, - {0x0657, 0x0658, 1}, - {0x06df, 0x06e0, 1}, - {0x06e5, 0x06e6, 1}, - {0x06ea, 0x06ec, 1}, - {0x0730, 0x074a, 1}, - {0x07a6, 0x07b0, 1}, - {0x07eb, 0x07f5, 1}, - {0x0818, 0x0819, 1}, - {0x0898, 0x089f, 1}, - {0x08c9, 0x08d2, 1}, - {0x08e3, 0x08fe, 1}, - {0x093c, 0x094d, 17}, - {0x0951, 0x0954, 1}, - {0x0971, 0x09bc, 75}, - {0x09cd, 0x0a3c, 111}, - {0x0a4d, 0x0abc, 111}, - {0x0acd, 0x0afd, 48}, - {0x0afe, 0x0aff, 1}, - {0x0b3c, 0x0b4d, 17}, - {0x0b55, 0x0bcd, 120}, - {0x0c3c, 0x0c4d, 17}, - {0x0cbc, 0x0ccd, 17}, - {0x0d3b, 0x0d3c, 1}, - {0x0d4d, 0x0e47, 125}, - {0x0e48, 0x0e4c, 1}, - {0x0e4e, 0x0eba, 108}, - {0x0ec8, 0x0ecc, 1}, - {0x0f18, 0x0f19, 1}, - {0x0f35, 0x0f39, 2}, - {0x0f3e, 0x0f3f, 1}, - {0x0f82, 0x0f84, 1}, - {0x0f86, 0x0f87, 1}, - {0x0fc6, 0x1037, 113}, - {0x1039, 0x103a, 1}, - {0x1063, 0x1064, 1}, - {0x1069, 0x106d, 1}, - {0x1087, 0x108d, 1}, - {0x108f, 0x109a, 11}, - {0x109b, 0x135d, 706}, - {0x135e, 0x135f, 1}, - {0x1714, 0x1715, 1}, - {0x17c9, 0x17d3, 1}, - {0x17dd, 0x1939, 348}, - {0x193a, 0x193b, 1}, - {0x1a75, 0x1a7c, 1}, - {0x1a7f, 0x1ab0, 49}, - {0x1ab1, 0x1abe, 1}, - {0x1ac1, 0x1acb, 1}, - {0x1b34, 0x1b44, 16}, - {0x1b6b, 0x1b73, 1}, - {0x1baa, 0x1bab, 1}, - {0x1c36, 0x1c37, 1}, - {0x1c78, 0x1c7d, 1}, - {0x1cd0, 0x1ce8, 1}, - {0x1ced, 0x1cf4, 7}, - {0x1cf7, 0x1cf9, 1}, - {0x1d2c, 0x1d6a, 1}, - {0x1dc4, 0x1dcf, 1}, - {0x1df5, 0x1dff, 1}, - {0x1fbd, 0x1fbf, 2}, - {0x1fc0, 0x1fc1, 1}, - {0x1fcd, 0x1fcf, 1}, - {0x1fdd, 0x1fdf, 1}, - {0x1fed, 0x1fef, 1}, - {0x1ffd, 0x1ffe, 1}, - {0x2cef, 0x2cf1, 1}, - {0x2e2f, 0x302a, 507}, - {0x302b, 0x302f, 1}, - {0x3099, 0x309c, 1}, - {0x30fc, 0xa66f, 30067}, - {0xa67c, 0xa67d, 1}, - {0xa67f, 0xa69c, 29}, - {0xa69d, 0xa6f0, 83}, - {0xa6f1, 0xa700, 15}, - {0xa701, 0xa721, 1}, - {0xa788, 0xa78a, 1}, - {0xa7f8, 0xa7f9, 1}, - {0xa8c4, 0xa8e0, 28}, - {0xa8e1, 0xa8f1, 1}, - {0xa92b, 0xa92e, 1}, - {0xa953, 0xa9b3, 96}, - {0xa9c0, 0xa9e5, 37}, - {0xaa7b, 0xaa7d, 1}, - {0xaabf, 0xaac2, 1}, - {0xaaf6, 0xab5b, 101}, - {0xab5c, 0xab5f, 1}, - {0xab69, 0xab6b, 1}, - {0xabec, 0xabed, 1}, - {0xfb1e, 0xfe20, 770}, - {0xfe21, 0xfe2f, 1}, - {0xff3e, 0xff40, 2}, - {0xff70, 0xff9e, 46}, - {0xff9f, 0xffe3, 68}, - ], - R32: [ - {0x102e0, 0x10780, 1184}, - {0x10781, 0x10785, 1}, - {0x10787, 0x107b0, 1}, - {0x107b2, 0x107ba, 1}, - {0x10ae5, 0x10ae6, 1}, - {0x10d22, 0x10d27, 1}, - {0x10efd, 0x10eff, 1}, - {0x10f46, 0x10f50, 1}, - {0x10f82, 0x10f85, 1}, - {0x11046, 0x11070, 42}, - {0x110b9, 0x110ba, 1}, - {0x11133, 0x11134, 1}, - {0x11173, 0x111c0, 77}, - {0x111ca, 0x111cc, 1}, - {0x11235, 0x11236, 1}, - {0x112e9, 0x112ea, 1}, - {0x1133c, 0x1134d, 17}, - {0x11366, 0x1136c, 1}, - {0x11370, 0x11374, 1}, - {0x11442, 0x11446, 4}, - {0x114c2, 0x114c3, 1}, - {0x115bf, 0x115c0, 1}, - {0x1163f, 0x116b6, 119}, - {0x116b7, 0x1172b, 116}, - {0x11839, 0x1183a, 1}, - {0x1193d, 0x1193e, 1}, - {0x11943, 0x119e0, 157}, - {0x11a34, 0x11a47, 19}, - {0x11a99, 0x11c3f, 422}, - {0x11d42, 0x11d44, 2}, - {0x11d45, 0x11d97, 82}, - {0x13447, 0x13455, 1}, - {0x16af0, 0x16af4, 1}, - {0x16b30, 0x16b36, 1}, - {0x16f8f, 0x16f9f, 1}, - {0x16ff0, 0x16ff1, 1}, - {0x1aff0, 0x1aff3, 1}, - {0x1aff5, 0x1affb, 1}, - {0x1affd, 0x1affe, 1}, - {0x1cf00, 0x1cf2d, 1}, - {0x1cf30, 0x1cf46, 1}, - {0x1d167, 0x1d169, 1}, - {0x1d16d, 0x1d172, 1}, - {0x1d17b, 0x1d182, 1}, - {0x1d185, 0x1d18b, 1}, - {0x1d1aa, 0x1d1ad, 1}, - {0x1e030, 0x1e06d, 1}, - {0x1e130, 0x1e136, 1}, - {0x1e2ae, 0x1e2ec, 62}, - {0x1e2ed, 0x1e2ef, 1}, - {0x1e8d0, 0x1e8d6, 1}, - {0x1e944, 0x1e946, 1}, - {0x1e948, 0x1e94a, 1}, - ], - LatinOffset: 3, + R16: [ + {0x005e, 0x0060, 2}, + {0x00a8, 0x00af, 7}, + {0x00b4, 0x00b7, 3}, + {0x00b8, 0x02b0, 504}, + {0x02b1, 0x034e, 1}, + {0x0350, 0x0357, 1}, + {0x035d, 0x0362, 1}, + {0x0374, 0x0375, 1}, + {0x037a, 0x0384, 10}, + {0x0385, 0x0483, 254}, + {0x0484, 0x0487, 1}, + {0x0559, 0x0591, 56}, + {0x0592, 0x05a1, 1}, + {0x05a3, 0x05bd, 1}, + {0x05bf, 0x05c1, 2}, + {0x05c2, 0x05c4, 2}, + {0x064b, 0x0652, 1}, + {0x0657, 0x0658, 1}, + {0x06df, 0x06e0, 1}, + {0x06e5, 0x06e6, 1}, + {0x06ea, 0x06ec, 1}, + {0x0730, 0x074a, 1}, + {0x07a6, 0x07b0, 1}, + {0x07eb, 0x07f5, 1}, + {0x0818, 0x0819, 1}, + {0x0898, 0x089f, 1}, + {0x08c9, 0x08d2, 1}, + {0x08e3, 0x08fe, 1}, + {0x093c, 0x094d, 17}, + {0x0951, 0x0954, 1}, + {0x0971, 0x09bc, 75}, + {0x09cd, 0x0a3c, 111}, + {0x0a4d, 0x0abc, 111}, + {0x0acd, 0x0afd, 48}, + {0x0afe, 0x0aff, 1}, + {0x0b3c, 0x0b4d, 17}, + {0x0b55, 0x0bcd, 120}, + {0x0c3c, 0x0c4d, 17}, + {0x0cbc, 0x0ccd, 17}, + {0x0d3b, 0x0d3c, 1}, + {0x0d4d, 0x0e47, 125}, + {0x0e48, 0x0e4c, 1}, + {0x0e4e, 0x0eba, 108}, + {0x0ec8, 0x0ecc, 1}, + {0x0f18, 0x0f19, 1}, + {0x0f35, 0x0f39, 2}, + {0x0f3e, 0x0f3f, 1}, + {0x0f82, 0x0f84, 1}, + {0x0f86, 0x0f87, 1}, + {0x0fc6, 0x1037, 113}, + {0x1039, 0x103a, 1}, + {0x1063, 0x1064, 1}, + {0x1069, 0x106d, 1}, + {0x1087, 0x108d, 1}, + {0x108f, 0x109a, 11}, + {0x109b, 0x135d, 706}, + {0x135e, 0x135f, 1}, + {0x1714, 0x1715, 1}, + {0x17c9, 0x17d3, 1}, + {0x17dd, 0x1939, 348}, + {0x193a, 0x193b, 1}, + {0x1a75, 0x1a7c, 1}, + {0x1a7f, 0x1ab0, 49}, + {0x1ab1, 0x1abe, 1}, + {0x1ac1, 0x1acb, 1}, + {0x1b34, 0x1b44, 16}, + {0x1b6b, 0x1b73, 1}, + {0x1baa, 0x1bab, 1}, + {0x1c36, 0x1c37, 1}, + {0x1c78, 0x1c7d, 1}, + {0x1cd0, 0x1ce8, 1}, + {0x1ced, 0x1cf4, 7}, + {0x1cf7, 0x1cf9, 1}, + {0x1d2c, 0x1d6a, 1}, + {0x1dc4, 0x1dcf, 1}, + {0x1df5, 0x1dff, 1}, + {0x1fbd, 0x1fbf, 2}, + {0x1fc0, 0x1fc1, 1}, + {0x1fcd, 0x1fcf, 1}, + {0x1fdd, 0x1fdf, 1}, + {0x1fed, 0x1fef, 1}, + {0x1ffd, 0x1ffe, 1}, + {0x2cef, 0x2cf1, 1}, + {0x2e2f, 0x302a, 507}, + {0x302b, 0x302f, 1}, + {0x3099, 0x309c, 1}, + {0x30fc, 0xa66f, 30067}, + {0xa67c, 0xa67d, 1}, + {0xa67f, 0xa69c, 29}, + {0xa69d, 0xa6f0, 83}, + {0xa6f1, 0xa700, 15}, + {0xa701, 0xa721, 1}, + {0xa788, 0xa78a, 1}, + {0xa7f8, 0xa7f9, 1}, + {0xa8c4, 0xa8e0, 28}, + {0xa8e1, 0xa8f1, 1}, + {0xa92b, 0xa92e, 1}, + {0xa953, 0xa9b3, 96}, + {0xa9c0, 0xa9e5, 37}, + {0xaa7b, 0xaa7d, 1}, + {0xaabf, 0xaac2, 1}, + {0xaaf6, 0xab5b, 101}, + {0xab5c, 0xab5f, 1}, + {0xab69, 0xab6b, 1}, + {0xabec, 0xabed, 1}, + {0xfb1e, 0xfe20, 770}, + {0xfe21, 0xfe2f, 1}, + {0xff3e, 0xff40, 2}, + {0xff70, 0xff9e, 46}, + {0xff9f, 0xffe3, 68}, + ], + R32: [ + {0x102e0, 0x10780, 1184}, + {0x10781, 0x10785, 1}, + {0x10787, 0x107b0, 1}, + {0x107b2, 0x107ba, 1}, + {0x10ae5, 0x10ae6, 1}, + {0x10d22, 0x10d27, 1}, + {0x10efd, 0x10eff, 1}, + {0x10f46, 0x10f50, 1}, + {0x10f82, 0x10f85, 1}, + {0x11046, 0x11070, 42}, + {0x110b9, 0x110ba, 1}, + {0x11133, 0x11134, 1}, + {0x11173, 0x111c0, 77}, + {0x111ca, 0x111cc, 1}, + {0x11235, 0x11236, 1}, + {0x112e9, 0x112ea, 1}, + {0x1133c, 0x1134d, 17}, + {0x11366, 0x1136c, 1}, + {0x11370, 0x11374, 1}, + {0x11442, 0x11446, 4}, + {0x114c2, 0x114c3, 1}, + {0x115bf, 0x115c0, 1}, + {0x1163f, 0x116b6, 119}, + {0x116b7, 0x1172b, 116}, + {0x11839, 0x1183a, 1}, + {0x1193d, 0x1193e, 1}, + {0x11943, 0x119e0, 157}, + {0x11a34, 0x11a47, 19}, + {0x11a99, 0x11c3f, 422}, + {0x11d42, 0x11d44, 2}, + {0x11d45, 0x11d97, 82}, + {0x13447, 0x13455, 1}, + {0x16af0, 0x16af4, 1}, + {0x16b30, 0x16b36, 1}, + {0x16f8f, 0x16f9f, 1}, + {0x16ff0, 0x16ff1, 1}, + {0x1aff0, 0x1aff3, 1}, + {0x1aff5, 0x1affb, 1}, + {0x1affd, 0x1affe, 1}, + {0x1cf00, 0x1cf2d, 1}, + {0x1cf30, 0x1cf46, 1}, + {0x1d167, 0x1d169, 1}, + {0x1d16d, 0x1d172, 1}, + {0x1d17b, 0x1d182, 1}, + {0x1d185, 0x1d18b, 1}, + {0x1d1aa, 0x1d1ad, 1}, + {0x1e030, 0x1e06d, 1}, + {0x1e130, 0x1e136, 1}, + {0x1e2ae, 0x1e2ec, 62}, + {0x1e2ed, 0x1e2ef, 1}, + {0x1e8d0, 0x1e8d6, 1}, + {0x1e944, 0x1e946, 1}, + {0x1e948, 0x1e94a, 1}, + ], + LatinOffset: 3, } static _EXTENDER = &RangeTable{ - R16: [ - {0x00b7, 0x02d0, 537}, - {0x02d1, 0x0640, 879}, - {0x07fa, 0x0b55, 859}, - {0x0e46, 0x0ec6, 128}, - {0x180a, 0x1843, 57}, - {0x1aa7, 0x1c36, 399}, - {0x1c7b, 0x3005, 5002}, - {0x3031, 0x3035, 1}, - {0x309d, 0x309e, 1}, - {0x30fc, 0x30fe, 1}, - {0xa015, 0xa60c, 1527}, - {0xa9cf, 0xa9e6, 23}, - {0xaa70, 0xaadd, 109}, - {0xaaf3, 0xaaf4, 1}, - {0xff70, 0xff70, 1}, - ], - R32: [ - {0x10781, 0x10782, 1}, - {0x1135d, 0x115c6, 617}, - {0x115c7, 0x115c8, 1}, - {0x11a98, 0x16b42, 20650}, - {0x16b43, 0x16fe0, 1181}, - {0x16fe1, 0x16fe3, 2}, - {0x1e13c, 0x1e13d, 1}, - {0x1e944, 0x1e946, 1}, - ], + R16: [ + {0x00b7, 0x02d0, 537}, + {0x02d1, 0x0640, 879}, + {0x07fa, 0x0b55, 859}, + {0x0e46, 0x0ec6, 128}, + {0x180a, 0x1843, 57}, + {0x1aa7, 0x1c36, 399}, + {0x1c7b, 0x3005, 5002}, + {0x3031, 0x3035, 1}, + {0x309d, 0x309e, 1}, + {0x30fc, 0x30fe, 1}, + {0xa015, 0xa60c, 1527}, + {0xa9cf, 0xa9e6, 23}, + {0xaa70, 0xaadd, 109}, + {0xaaf3, 0xaaf4, 1}, + {0xff70, 0xff70, 1}, + ], + R32: [ + {0x10781, 0x10782, 1}, + {0x1135d, 0x115c6, 617}, + {0x115c7, 0x115c8, 1}, + {0x11a98, 0x16b42, 20650}, + {0x16b43, 0x16fe0, 1181}, + {0x16fe1, 0x16fe3, 2}, + {0x1e13c, 0x1e13d, 1}, + {0x1e944, 0x1e946, 1}, + ], } static _HEX_DIGIT = &RangeTable{ - R16: [ - {0x0030, 0x0039, 1}, - {0x0041, 0x0046, 1}, - {0x0061, 0x0066, 1}, - {0xff10, 0xff19, 1}, - {0xff21, 0xff26, 1}, - {0xff41, 0xff46, 1}, - ], - LatinOffset: 3, + R16: [ + {0x0030, 0x0039, 1}, + {0x0041, 0x0046, 1}, + {0x0061, 0x0066, 1}, + {0xff10, 0xff19, 1}, + {0xff21, 0xff26, 1}, + {0xff41, 0xff46, 1}, + ], + LatinOffset: 3, } static _HYPHEN = &RangeTable{ - R16: [ - {0x002d, 0x00ad, 128}, - {0x058a, 0x1806, 4732}, - {0x2010, 0x2011, 1}, - {0x2e17, 0x30fb, 740}, - {0xfe63, 0xff0d, 170}, - {0xff65, 0xff65, 1}, - ], - LatinOffset: 1, + R16: [ + {0x002d, 0x00ad, 128}, + {0x058a, 0x1806, 4732}, + {0x2010, 0x2011, 1}, + {0x2e17, 0x30fb, 740}, + {0xfe63, 0xff0d, 170}, + {0xff65, 0xff65, 1}, + ], + LatinOffset: 1, } static _IDS_BINARY_OPERATOR = &RangeTable{ - R16: [ - {0x2ff0, 0x2ff1, 1}, - {0x2ff4, 0x2ffb, 1}, - ], + R16: [ + {0x2ff0, 0x2ff1, 1}, + {0x2ff4, 0x2ffb, 1}, + ], } static _IDS_TRINARY_OPERATOR = &RangeTable{ - R16: [ - {0x2ff2, 0x2ff3, 1}, - ], + R16: [ + {0x2ff2, 0x2ff3, 1}, + ], } static _IDEOGRAPHIC = &RangeTable{ - R16: [ - {0x3006, 0x3007, 1}, - {0x3021, 0x3029, 1}, - {0x3038, 0x303a, 1}, - {0x3400, 0x4dbf, 1}, - {0x4e00, 0x9fff, 1}, - {0xf900, 0xfa6d, 1}, - {0xfa70, 0xfad9, 1}, - ], - R32: [ - {0x16fe4, 0x17000, 28}, - {0x17001, 0x187f7, 1}, - {0x18800, 0x18cd5, 1}, - {0x18d00, 0x18d08, 1}, - {0x1b170, 0x1b2fb, 1}, - {0x20000, 0x2a6df, 1}, - {0x2a700, 0x2b739, 1}, - {0x2b740, 0x2b81d, 1}, - {0x2b820, 0x2cea1, 1}, - {0x2ceb0, 0x2ebe0, 1}, - {0x2f800, 0x2fa1d, 1}, - {0x30000, 0x3134a, 1}, - {0x31350, 0x323af, 1}, - ], + R16: [ + {0x3006, 0x3007, 1}, + {0x3021, 0x3029, 1}, + {0x3038, 0x303a, 1}, + {0x3400, 0x4dbf, 1}, + {0x4e00, 0x9fff, 1}, + {0xf900, 0xfa6d, 1}, + {0xfa70, 0xfad9, 1}, + ], + R32: [ + {0x16fe4, 0x17000, 28}, + {0x17001, 0x187f7, 1}, + {0x18800, 0x18cd5, 1}, + {0x18d00, 0x18d08, 1}, + {0x1b170, 0x1b2fb, 1}, + {0x20000, 0x2a6df, 1}, + {0x2a700, 0x2b739, 1}, + {0x2b740, 0x2b81d, 1}, + {0x2b820, 0x2cea1, 1}, + {0x2ceb0, 0x2ebe0, 1}, + {0x2f800, 0x2fa1d, 1}, + {0x30000, 0x3134a, 1}, + {0x31350, 0x323af, 1}, + ], } static _JOIN_CONTROL = &RangeTable{ - R16: [ - {0x200c, 0x200d, 1}, - ], + R16: [ + {0x200c, 0x200d, 1}, + ], } static _LOGICAL_ORDER_EXCEPTION = &RangeTable{ - R16: [ - {0x0e40, 0x0e44, 1}, - {0x0ec0, 0x0ec4, 1}, - {0x19b5, 0x19b7, 1}, - {0x19ba, 0xaab5, 37115}, - {0xaab6, 0xaab9, 3}, - {0xaabb, 0xaabc, 1}, - ], + R16: [ + {0x0e40, 0x0e44, 1}, + {0x0ec0, 0x0ec4, 1}, + {0x19b5, 0x19b7, 1}, + {0x19ba, 0xaab5, 37115}, + {0xaab6, 0xaab9, 3}, + {0xaabb, 0xaabc, 1}, + ], } static _NONCHARACTER_CODE_POINT = &RangeTable{ - R16: [ - {0xfdd0, 0xfdef, 1}, - {0xfffe, 0xffff, 1}, - ], - R32: [ - {0x1fffe, 0x1ffff, 1}, - {0x2fffe, 0x2ffff, 1}, - {0x3fffe, 0x3ffff, 1}, - {0x4fffe, 0x4ffff, 1}, - {0x5fffe, 0x5ffff, 1}, - {0x6fffe, 0x6ffff, 1}, - {0x7fffe, 0x7ffff, 1}, - {0x8fffe, 0x8ffff, 1}, - {0x9fffe, 0x9ffff, 1}, - {0xafffe, 0xaffff, 1}, - {0xbfffe, 0xbffff, 1}, - {0xcfffe, 0xcffff, 1}, - {0xdfffe, 0xdffff, 1}, - {0xefffe, 0xeffff, 1}, - {0xffffe, 0xfffff, 1}, - {0x10fffe, 0x10ffff, 1}, - ], + R16: [ + {0xfdd0, 0xfdef, 1}, + {0xfffe, 0xffff, 1}, + ], + R32: [ + {0x1fffe, 0x1ffff, 1}, + {0x2fffe, 0x2ffff, 1}, + {0x3fffe, 0x3ffff, 1}, + {0x4fffe, 0x4ffff, 1}, + {0x5fffe, 0x5ffff, 1}, + {0x6fffe, 0x6ffff, 1}, + {0x7fffe, 0x7ffff, 1}, + {0x8fffe, 0x8ffff, 1}, + {0x9fffe, 0x9ffff, 1}, + {0xafffe, 0xaffff, 1}, + {0xbfffe, 0xbffff, 1}, + {0xcfffe, 0xcffff, 1}, + {0xdfffe, 0xdffff, 1}, + {0xefffe, 0xeffff, 1}, + {0xffffe, 0xfffff, 1}, + {0x10fffe, 0x10ffff, 1}, + ], } static _OTHER_ALPHABETIC = &RangeTable{ - R16: [ - {0x0345, 0x05b0, 619}, - {0x05b1, 0x05bd, 1}, - {0x05bf, 0x05c1, 2}, - {0x05c2, 0x05c4, 2}, - {0x05c5, 0x05c7, 2}, - {0x0610, 0x061a, 1}, - {0x064b, 0x0657, 1}, - {0x0659, 0x065f, 1}, - {0x0670, 0x06d6, 102}, - {0x06d7, 0x06dc, 1}, - {0x06e1, 0x06e4, 1}, - {0x06e7, 0x06e8, 1}, - {0x06ed, 0x0711, 36}, - {0x0730, 0x073f, 1}, - {0x07a6, 0x07b0, 1}, - {0x0816, 0x0817, 1}, - {0x081b, 0x0823, 1}, - {0x0825, 0x0827, 1}, - {0x0829, 0x082c, 1}, - {0x08d4, 0x08df, 1}, - {0x08e3, 0x08e9, 1}, - {0x08f0, 0x0903, 1}, - {0x093a, 0x093b, 1}, - {0x093e, 0x094c, 1}, - {0x094e, 0x094f, 1}, - {0x0955, 0x0957, 1}, - {0x0962, 0x0963, 1}, - {0x0981, 0x0983, 1}, - {0x09be, 0x09c4, 1}, - {0x09c7, 0x09c8, 1}, - {0x09cb, 0x09cc, 1}, - {0x09d7, 0x09e2, 11}, - {0x09e3, 0x0a01, 30}, - {0x0a02, 0x0a03, 1}, - {0x0a3e, 0x0a42, 1}, - {0x0a47, 0x0a48, 1}, - {0x0a4b, 0x0a4c, 1}, - {0x0a51, 0x0a70, 31}, - {0x0a71, 0x0a75, 4}, - {0x0a81, 0x0a83, 1}, - {0x0abe, 0x0ac5, 1}, - {0x0ac7, 0x0ac9, 1}, - {0x0acb, 0x0acc, 1}, - {0x0ae2, 0x0ae3, 1}, - {0x0afa, 0x0afc, 1}, - {0x0b01, 0x0b03, 1}, - {0x0b3e, 0x0b44, 1}, - {0x0b47, 0x0b48, 1}, - {0x0b4b, 0x0b4c, 1}, - {0x0b56, 0x0b57, 1}, - {0x0b62, 0x0b63, 1}, - {0x0b82, 0x0bbe, 60}, - {0x0bbf, 0x0bc2, 1}, - {0x0bc6, 0x0bc8, 1}, - {0x0bca, 0x0bcc, 1}, - {0x0bd7, 0x0c00, 41}, - {0x0c01, 0x0c04, 1}, - {0x0c3e, 0x0c44, 1}, - {0x0c46, 0x0c48, 1}, - {0x0c4a, 0x0c4c, 1}, - {0x0c55, 0x0c56, 1}, - {0x0c62, 0x0c63, 1}, - {0x0c81, 0x0c83, 1}, - {0x0cbe, 0x0cc4, 1}, - {0x0cc6, 0x0cc8, 1}, - {0x0cca, 0x0ccc, 1}, - {0x0cd5, 0x0cd6, 1}, - {0x0ce2, 0x0ce3, 1}, - {0x0cf3, 0x0d00, 13}, - {0x0d01, 0x0d03, 1}, - {0x0d3e, 0x0d44, 1}, - {0x0d46, 0x0d48, 1}, - {0x0d4a, 0x0d4c, 1}, - {0x0d57, 0x0d62, 11}, - {0x0d63, 0x0d81, 30}, - {0x0d82, 0x0d83, 1}, - {0x0dcf, 0x0dd4, 1}, - {0x0dd6, 0x0dd8, 2}, - {0x0dd9, 0x0ddf, 1}, - {0x0df2, 0x0df3, 1}, - {0x0e31, 0x0e34, 3}, - {0x0e35, 0x0e3a, 1}, - {0x0e4d, 0x0eb1, 100}, - {0x0eb4, 0x0eb9, 1}, - {0x0ebb, 0x0ebc, 1}, - {0x0ecd, 0x0f71, 164}, - {0x0f72, 0x0f83, 1}, - {0x0f8d, 0x0f97, 1}, - {0x0f99, 0x0fbc, 1}, - {0x102b, 0x1036, 1}, - {0x1038, 0x103b, 3}, - {0x103c, 0x103e, 1}, - {0x1056, 0x1059, 1}, - {0x105e, 0x1060, 1}, - {0x1062, 0x1064, 1}, - {0x1067, 0x106d, 1}, - {0x1071, 0x1074, 1}, - {0x1082, 0x108d, 1}, - {0x108f, 0x109a, 11}, - {0x109b, 0x109d, 1}, - {0x1712, 0x1713, 1}, - {0x1732, 0x1733, 1}, - {0x1752, 0x1753, 1}, - {0x1772, 0x1773, 1}, - {0x17b6, 0x17c8, 1}, - {0x1885, 0x1886, 1}, - {0x18a9, 0x1920, 119}, - {0x1921, 0x192b, 1}, - {0x1930, 0x1938, 1}, - {0x1a17, 0x1a1b, 1}, - {0x1a55, 0x1a5e, 1}, - {0x1a61, 0x1a74, 1}, - {0x1abf, 0x1ac0, 1}, - {0x1acc, 0x1ace, 1}, - {0x1b00, 0x1b04, 1}, - {0x1b35, 0x1b43, 1}, - {0x1b80, 0x1b82, 1}, - {0x1ba1, 0x1ba9, 1}, - {0x1bac, 0x1bad, 1}, - {0x1be7, 0x1bf1, 1}, - {0x1c24, 0x1c36, 1}, - {0x1de7, 0x1df4, 1}, - {0x24b6, 0x24e9, 1}, - {0x2de0, 0x2dff, 1}, - {0xa674, 0xa67b, 1}, - {0xa69e, 0xa69f, 1}, - {0xa802, 0xa80b, 9}, - {0xa823, 0xa827, 1}, - {0xa880, 0xa881, 1}, - {0xa8b4, 0xa8c3, 1}, - {0xa8c5, 0xa8ff, 58}, - {0xa926, 0xa92a, 1}, - {0xa947, 0xa952, 1}, - {0xa980, 0xa983, 1}, - {0xa9b4, 0xa9bf, 1}, - {0xa9e5, 0xaa29, 68}, - {0xaa2a, 0xaa36, 1}, - {0xaa43, 0xaa4c, 9}, - {0xaa4d, 0xaa7b, 46}, - {0xaa7c, 0xaa7d, 1}, - {0xaab0, 0xaab2, 2}, - {0xaab3, 0xaab4, 1}, - {0xaab7, 0xaab8, 1}, - {0xaabe, 0xaaeb, 45}, - {0xaaec, 0xaaef, 1}, - {0xaaf5, 0xabe3, 238}, - {0xabe4, 0xabea, 1}, - {0xfb1e, 0xfb1e, 1}, - ], - R32: [ - {0x10376, 0x1037a, 1}, - {0x10a01, 0x10a03, 1}, - {0x10a05, 0x10a06, 1}, - {0x10a0c, 0x10a0f, 1}, - {0x10d24, 0x10d27, 1}, - {0x10eab, 0x10eac, 1}, - {0x11000, 0x11002, 1}, - {0x11038, 0x11045, 1}, - {0x11073, 0x11074, 1}, - {0x11080, 0x11082, 1}, - {0x110b0, 0x110b8, 1}, - {0x110c2, 0x11100, 62}, - {0x11101, 0x11102, 1}, - {0x11127, 0x11132, 1}, - {0x11145, 0x11146, 1}, - {0x11180, 0x11182, 1}, - {0x111b3, 0x111bf, 1}, - {0x111ce, 0x111cf, 1}, - {0x1122c, 0x11234, 1}, - {0x11237, 0x1123e, 7}, - {0x11241, 0x112df, 158}, - {0x112e0, 0x112e8, 1}, - {0x11300, 0x11303, 1}, - {0x1133e, 0x11344, 1}, - {0x11347, 0x11348, 1}, - {0x1134b, 0x1134c, 1}, - {0x11357, 0x11362, 11}, - {0x11363, 0x11435, 210}, - {0x11436, 0x11441, 1}, - {0x11443, 0x11445, 1}, - {0x114b0, 0x114c1, 1}, - {0x115af, 0x115b5, 1}, - {0x115b8, 0x115be, 1}, - {0x115dc, 0x115dd, 1}, - {0x11630, 0x1163e, 1}, - {0x11640, 0x116ab, 107}, - {0x116ac, 0x116b5, 1}, - {0x1171d, 0x1172a, 1}, - {0x1182c, 0x11838, 1}, - {0x11930, 0x11935, 1}, - {0x11937, 0x11938, 1}, - {0x1193b, 0x1193c, 1}, - {0x11940, 0x11942, 2}, - {0x119d1, 0x119d7, 1}, - {0x119da, 0x119df, 1}, - {0x119e4, 0x11a01, 29}, - {0x11a02, 0x11a0a, 1}, - {0x11a35, 0x11a39, 1}, - {0x11a3b, 0x11a3e, 1}, - {0x11a51, 0x11a5b, 1}, - {0x11a8a, 0x11a97, 1}, - {0x11c2f, 0x11c36, 1}, - {0x11c38, 0x11c3e, 1}, - {0x11c92, 0x11ca7, 1}, - {0x11ca9, 0x11cb6, 1}, - {0x11d31, 0x11d36, 1}, - {0x11d3a, 0x11d3c, 2}, - {0x11d3d, 0x11d3f, 2}, - {0x11d40, 0x11d41, 1}, - {0x11d43, 0x11d47, 4}, - {0x11d8a, 0x11d8e, 1}, - {0x11d90, 0x11d91, 1}, - {0x11d93, 0x11d96, 1}, - {0x11ef3, 0x11ef6, 1}, - {0x11f00, 0x11f01, 1}, - {0x11f03, 0x11f34, 49}, - {0x11f35, 0x11f3a, 1}, - {0x11f3e, 0x11f40, 1}, - {0x16f4f, 0x16f51, 2}, - {0x16f52, 0x16f87, 1}, - {0x16f8f, 0x16f92, 1}, - {0x16ff0, 0x16ff1, 1}, - {0x1bc9e, 0x1e000, 9058}, - {0x1e001, 0x1e006, 1}, - {0x1e008, 0x1e018, 1}, - {0x1e01b, 0x1e021, 1}, - {0x1e023, 0x1e024, 1}, - {0x1e026, 0x1e02a, 1}, - {0x1e08f, 0x1e947, 2232}, - {0x1f130, 0x1f149, 1}, - {0x1f150, 0x1f169, 1}, - {0x1f170, 0x1f189, 1}, - ], + R16: [ + {0x0345, 0x05b0, 619}, + {0x05b1, 0x05bd, 1}, + {0x05bf, 0x05c1, 2}, + {0x05c2, 0x05c4, 2}, + {0x05c5, 0x05c7, 2}, + {0x0610, 0x061a, 1}, + {0x064b, 0x0657, 1}, + {0x0659, 0x065f, 1}, + {0x0670, 0x06d6, 102}, + {0x06d7, 0x06dc, 1}, + {0x06e1, 0x06e4, 1}, + {0x06e7, 0x06e8, 1}, + {0x06ed, 0x0711, 36}, + {0x0730, 0x073f, 1}, + {0x07a6, 0x07b0, 1}, + {0x0816, 0x0817, 1}, + {0x081b, 0x0823, 1}, + {0x0825, 0x0827, 1}, + {0x0829, 0x082c, 1}, + {0x08d4, 0x08df, 1}, + {0x08e3, 0x08e9, 1}, + {0x08f0, 0x0903, 1}, + {0x093a, 0x093b, 1}, + {0x093e, 0x094c, 1}, + {0x094e, 0x094f, 1}, + {0x0955, 0x0957, 1}, + {0x0962, 0x0963, 1}, + {0x0981, 0x0983, 1}, + {0x09be, 0x09c4, 1}, + {0x09c7, 0x09c8, 1}, + {0x09cb, 0x09cc, 1}, + {0x09d7, 0x09e2, 11}, + {0x09e3, 0x0a01, 30}, + {0x0a02, 0x0a03, 1}, + {0x0a3e, 0x0a42, 1}, + {0x0a47, 0x0a48, 1}, + {0x0a4b, 0x0a4c, 1}, + {0x0a51, 0x0a70, 31}, + {0x0a71, 0x0a75, 4}, + {0x0a81, 0x0a83, 1}, + {0x0abe, 0x0ac5, 1}, + {0x0ac7, 0x0ac9, 1}, + {0x0acb, 0x0acc, 1}, + {0x0ae2, 0x0ae3, 1}, + {0x0afa, 0x0afc, 1}, + {0x0b01, 0x0b03, 1}, + {0x0b3e, 0x0b44, 1}, + {0x0b47, 0x0b48, 1}, + {0x0b4b, 0x0b4c, 1}, + {0x0b56, 0x0b57, 1}, + {0x0b62, 0x0b63, 1}, + {0x0b82, 0x0bbe, 60}, + {0x0bbf, 0x0bc2, 1}, + {0x0bc6, 0x0bc8, 1}, + {0x0bca, 0x0bcc, 1}, + {0x0bd7, 0x0c00, 41}, + {0x0c01, 0x0c04, 1}, + {0x0c3e, 0x0c44, 1}, + {0x0c46, 0x0c48, 1}, + {0x0c4a, 0x0c4c, 1}, + {0x0c55, 0x0c56, 1}, + {0x0c62, 0x0c63, 1}, + {0x0c81, 0x0c83, 1}, + {0x0cbe, 0x0cc4, 1}, + {0x0cc6, 0x0cc8, 1}, + {0x0cca, 0x0ccc, 1}, + {0x0cd5, 0x0cd6, 1}, + {0x0ce2, 0x0ce3, 1}, + {0x0cf3, 0x0d00, 13}, + {0x0d01, 0x0d03, 1}, + {0x0d3e, 0x0d44, 1}, + {0x0d46, 0x0d48, 1}, + {0x0d4a, 0x0d4c, 1}, + {0x0d57, 0x0d62, 11}, + {0x0d63, 0x0d81, 30}, + {0x0d82, 0x0d83, 1}, + {0x0dcf, 0x0dd4, 1}, + {0x0dd6, 0x0dd8, 2}, + {0x0dd9, 0x0ddf, 1}, + {0x0df2, 0x0df3, 1}, + {0x0e31, 0x0e34, 3}, + {0x0e35, 0x0e3a, 1}, + {0x0e4d, 0x0eb1, 100}, + {0x0eb4, 0x0eb9, 1}, + {0x0ebb, 0x0ebc, 1}, + {0x0ecd, 0x0f71, 164}, + {0x0f72, 0x0f83, 1}, + {0x0f8d, 0x0f97, 1}, + {0x0f99, 0x0fbc, 1}, + {0x102b, 0x1036, 1}, + {0x1038, 0x103b, 3}, + {0x103c, 0x103e, 1}, + {0x1056, 0x1059, 1}, + {0x105e, 0x1060, 1}, + {0x1062, 0x1064, 1}, + {0x1067, 0x106d, 1}, + {0x1071, 0x1074, 1}, + {0x1082, 0x108d, 1}, + {0x108f, 0x109a, 11}, + {0x109b, 0x109d, 1}, + {0x1712, 0x1713, 1}, + {0x1732, 0x1733, 1}, + {0x1752, 0x1753, 1}, + {0x1772, 0x1773, 1}, + {0x17b6, 0x17c8, 1}, + {0x1885, 0x1886, 1}, + {0x18a9, 0x1920, 119}, + {0x1921, 0x192b, 1}, + {0x1930, 0x1938, 1}, + {0x1a17, 0x1a1b, 1}, + {0x1a55, 0x1a5e, 1}, + {0x1a61, 0x1a74, 1}, + {0x1abf, 0x1ac0, 1}, + {0x1acc, 0x1ace, 1}, + {0x1b00, 0x1b04, 1}, + {0x1b35, 0x1b43, 1}, + {0x1b80, 0x1b82, 1}, + {0x1ba1, 0x1ba9, 1}, + {0x1bac, 0x1bad, 1}, + {0x1be7, 0x1bf1, 1}, + {0x1c24, 0x1c36, 1}, + {0x1de7, 0x1df4, 1}, + {0x24b6, 0x24e9, 1}, + {0x2de0, 0x2dff, 1}, + {0xa674, 0xa67b, 1}, + {0xa69e, 0xa69f, 1}, + {0xa802, 0xa80b, 9}, + {0xa823, 0xa827, 1}, + {0xa880, 0xa881, 1}, + {0xa8b4, 0xa8c3, 1}, + {0xa8c5, 0xa8ff, 58}, + {0xa926, 0xa92a, 1}, + {0xa947, 0xa952, 1}, + {0xa980, 0xa983, 1}, + {0xa9b4, 0xa9bf, 1}, + {0xa9e5, 0xaa29, 68}, + {0xaa2a, 0xaa36, 1}, + {0xaa43, 0xaa4c, 9}, + {0xaa4d, 0xaa7b, 46}, + {0xaa7c, 0xaa7d, 1}, + {0xaab0, 0xaab2, 2}, + {0xaab3, 0xaab4, 1}, + {0xaab7, 0xaab8, 1}, + {0xaabe, 0xaaeb, 45}, + {0xaaec, 0xaaef, 1}, + {0xaaf5, 0xabe3, 238}, + {0xabe4, 0xabea, 1}, + {0xfb1e, 0xfb1e, 1}, + ], + R32: [ + {0x10376, 0x1037a, 1}, + {0x10a01, 0x10a03, 1}, + {0x10a05, 0x10a06, 1}, + {0x10a0c, 0x10a0f, 1}, + {0x10d24, 0x10d27, 1}, + {0x10eab, 0x10eac, 1}, + {0x11000, 0x11002, 1}, + {0x11038, 0x11045, 1}, + {0x11073, 0x11074, 1}, + {0x11080, 0x11082, 1}, + {0x110b0, 0x110b8, 1}, + {0x110c2, 0x11100, 62}, + {0x11101, 0x11102, 1}, + {0x11127, 0x11132, 1}, + {0x11145, 0x11146, 1}, + {0x11180, 0x11182, 1}, + {0x111b3, 0x111bf, 1}, + {0x111ce, 0x111cf, 1}, + {0x1122c, 0x11234, 1}, + {0x11237, 0x1123e, 7}, + {0x11241, 0x112df, 158}, + {0x112e0, 0x112e8, 1}, + {0x11300, 0x11303, 1}, + {0x1133e, 0x11344, 1}, + {0x11347, 0x11348, 1}, + {0x1134b, 0x1134c, 1}, + {0x11357, 0x11362, 11}, + {0x11363, 0x11435, 210}, + {0x11436, 0x11441, 1}, + {0x11443, 0x11445, 1}, + {0x114b0, 0x114c1, 1}, + {0x115af, 0x115b5, 1}, + {0x115b8, 0x115be, 1}, + {0x115dc, 0x115dd, 1}, + {0x11630, 0x1163e, 1}, + {0x11640, 0x116ab, 107}, + {0x116ac, 0x116b5, 1}, + {0x1171d, 0x1172a, 1}, + {0x1182c, 0x11838, 1}, + {0x11930, 0x11935, 1}, + {0x11937, 0x11938, 1}, + {0x1193b, 0x1193c, 1}, + {0x11940, 0x11942, 2}, + {0x119d1, 0x119d7, 1}, + {0x119da, 0x119df, 1}, + {0x119e4, 0x11a01, 29}, + {0x11a02, 0x11a0a, 1}, + {0x11a35, 0x11a39, 1}, + {0x11a3b, 0x11a3e, 1}, + {0x11a51, 0x11a5b, 1}, + {0x11a8a, 0x11a97, 1}, + {0x11c2f, 0x11c36, 1}, + {0x11c38, 0x11c3e, 1}, + {0x11c92, 0x11ca7, 1}, + {0x11ca9, 0x11cb6, 1}, + {0x11d31, 0x11d36, 1}, + {0x11d3a, 0x11d3c, 2}, + {0x11d3d, 0x11d3f, 2}, + {0x11d40, 0x11d41, 1}, + {0x11d43, 0x11d47, 4}, + {0x11d8a, 0x11d8e, 1}, + {0x11d90, 0x11d91, 1}, + {0x11d93, 0x11d96, 1}, + {0x11ef3, 0x11ef6, 1}, + {0x11f00, 0x11f01, 1}, + {0x11f03, 0x11f34, 49}, + {0x11f35, 0x11f3a, 1}, + {0x11f3e, 0x11f40, 1}, + {0x16f4f, 0x16f51, 2}, + {0x16f52, 0x16f87, 1}, + {0x16f8f, 0x16f92, 1}, + {0x16ff0, 0x16ff1, 1}, + {0x1bc9e, 0x1e000, 9058}, + {0x1e001, 0x1e006, 1}, + {0x1e008, 0x1e018, 1}, + {0x1e01b, 0x1e021, 1}, + {0x1e023, 0x1e024, 1}, + {0x1e026, 0x1e02a, 1}, + {0x1e08f, 0x1e947, 2232}, + {0x1f130, 0x1f149, 1}, + {0x1f150, 0x1f169, 1}, + {0x1f170, 0x1f189, 1}, + ], } static _OTHER_DEFAULT_IGNORABLE_CODE_POINT = &RangeTable{ - R16: [ - {0x034f, 0x115f, 3600}, - {0x1160, 0x17b4, 1620}, - {0x17b5, 0x2065, 2224}, - {0x3164, 0xffa0, 52796}, - {0xfff0, 0xfff8, 1}, - ], - R32: [ - {0xe0000, 0xe0002, 2}, - {0xe0003, 0xe001f, 1}, - {0xe0080, 0xe00ff, 1}, - {0xe01f0, 0xe0fff, 1}, - ], + R16: [ + {0x034f, 0x115f, 3600}, + {0x1160, 0x17b4, 1620}, + {0x17b5, 0x2065, 2224}, + {0x3164, 0xffa0, 52796}, + {0xfff0, 0xfff8, 1}, + ], + R32: [ + {0xe0000, 0xe0002, 2}, + {0xe0003, 0xe001f, 1}, + {0xe0080, 0xe00ff, 1}, + {0xe01f0, 0xe0fff, 1}, + ], } static _OTHER_GRAPHEME_EXTEND = &RangeTable{ - R16: [ - {0x09be, 0x09d7, 25}, - {0x0b3e, 0x0b57, 25}, - {0x0bbe, 0x0bd7, 25}, - {0x0cc2, 0x0cd5, 19}, - {0x0cd6, 0x0d3e, 104}, - {0x0d57, 0x0dcf, 120}, - {0x0ddf, 0x1b35, 3414}, - {0x200c, 0x302e, 4130}, - {0x302f, 0xff9e, 53103}, - {0xff9f, 0xff9f, 1}, - ], - R32: [ - {0x1133e, 0x11357, 25}, - {0x114b0, 0x114bd, 13}, - {0x115af, 0x11930, 897}, - {0x1d165, 0x1d16e, 9}, - {0x1d16f, 0x1d172, 1}, - {0xe0020, 0xe007f, 1}, - ], + R16: [ + {0x09be, 0x09d7, 25}, + {0x0b3e, 0x0b57, 25}, + {0x0bbe, 0x0bd7, 25}, + {0x0cc2, 0x0cd5, 19}, + {0x0cd6, 0x0d3e, 104}, + {0x0d57, 0x0dcf, 120}, + {0x0ddf, 0x1b35, 3414}, + {0x200c, 0x302e, 4130}, + {0x302f, 0xff9e, 53103}, + {0xff9f, 0xff9f, 1}, + ], + R32: [ + {0x1133e, 0x11357, 25}, + {0x114b0, 0x114bd, 13}, + {0x115af, 0x11930, 897}, + {0x1d165, 0x1d16e, 9}, + {0x1d16f, 0x1d172, 1}, + {0xe0020, 0xe007f, 1}, + ], } static _OTHER_ID_CONTINUE = &RangeTable{ - R16: [ - {0x00b7, 0x0387, 720}, - {0x1369, 0x1371, 1}, - {0x19da, 0x19da, 1}, - ], + R16: [ + {0x00b7, 0x0387, 720}, + {0x1369, 0x1371, 1}, + {0x19da, 0x19da, 1}, + ], } static _OTHER_ID_START = &RangeTable{ - R16: [ - {0x1885, 0x1886, 1}, - {0x2118, 0x212e, 22}, - {0x309b, 0x309c, 1}, - ], + R16: [ + {0x1885, 0x1886, 1}, + {0x2118, 0x212e, 22}, + {0x309b, 0x309c, 1}, + ], } static _OTHER_LOWERCASE = &RangeTable{ - R16: [ - {0x00aa, 0x00ba, 16}, - {0x02b0, 0x02b8, 1}, - {0x02c0, 0x02c1, 1}, - {0x02e0, 0x02e4, 1}, - {0x0345, 0x037a, 53}, - {0x10fc, 0x1d2c, 3120}, - {0x1d2d, 0x1d6a, 1}, - {0x1d78, 0x1d9b, 35}, - {0x1d9c, 0x1dbf, 1}, - {0x2071, 0x207f, 14}, - {0x2090, 0x209c, 1}, - {0x2170, 0x217f, 1}, - {0x24d0, 0x24e9, 1}, - {0x2c7c, 0x2c7d, 1}, - {0xa69c, 0xa69d, 1}, - {0xa770, 0xa7f2, 130}, - {0xa7f3, 0xa7f4, 1}, - {0xa7f8, 0xa7f9, 1}, - {0xab5c, 0xab5f, 1}, - {0xab69, 0xab69, 1}, - ], - R32: [ - {0x10780, 0x10783, 3}, - {0x10784, 0x10785, 1}, - {0x10787, 0x107b0, 1}, - {0x107b2, 0x107ba, 1}, - {0x1e030, 0x1e06d, 1}, - ], - LatinOffset: 1, + R16: [ + {0x00aa, 0x00ba, 16}, + {0x02b0, 0x02b8, 1}, + {0x02c0, 0x02c1, 1}, + {0x02e0, 0x02e4, 1}, + {0x0345, 0x037a, 53}, + {0x10fc, 0x1d2c, 3120}, + {0x1d2d, 0x1d6a, 1}, + {0x1d78, 0x1d9b, 35}, + {0x1d9c, 0x1dbf, 1}, + {0x2071, 0x207f, 14}, + {0x2090, 0x209c, 1}, + {0x2170, 0x217f, 1}, + {0x24d0, 0x24e9, 1}, + {0x2c7c, 0x2c7d, 1}, + {0xa69c, 0xa69d, 1}, + {0xa770, 0xa7f2, 130}, + {0xa7f3, 0xa7f4, 1}, + {0xa7f8, 0xa7f9, 1}, + {0xab5c, 0xab5f, 1}, + {0xab69, 0xab69, 1}, + ], + R32: [ + {0x10780, 0x10783, 3}, + {0x10784, 0x10785, 1}, + {0x10787, 0x107b0, 1}, + {0x107b2, 0x107ba, 1}, + {0x1e030, 0x1e06d, 1}, + ], + LatinOffset: 1, } static _OTHER_MATH = &RangeTable{ - R16: [ - {0x005e, 0x03d0, 882}, - {0x03d1, 0x03d2, 1}, - {0x03d5, 0x03f0, 27}, - {0x03f1, 0x03f4, 3}, - {0x03f5, 0x2016, 7201}, - {0x2032, 0x2034, 1}, - {0x2040, 0x2061, 33}, - {0x2062, 0x2064, 1}, - {0x207d, 0x207e, 1}, - {0x208d, 0x208e, 1}, - {0x20d0, 0x20dc, 1}, - {0x20e1, 0x20e5, 4}, - {0x20e6, 0x20eb, 5}, - {0x20ec, 0x20ef, 1}, - {0x2102, 0x2107, 5}, - {0x210a, 0x2113, 1}, - {0x2115, 0x2119, 4}, - {0x211a, 0x211d, 1}, - {0x2124, 0x2128, 4}, - {0x2129, 0x212c, 3}, - {0x212d, 0x212f, 2}, - {0x2130, 0x2131, 1}, - {0x2133, 0x2138, 1}, - {0x213c, 0x213f, 1}, - {0x2145, 0x2149, 1}, - {0x2195, 0x2199, 1}, - {0x219c, 0x219f, 1}, - {0x21a1, 0x21a2, 1}, - {0x21a4, 0x21a5, 1}, - {0x21a7, 0x21a9, 2}, - {0x21aa, 0x21ad, 1}, - {0x21b0, 0x21b1, 1}, - {0x21b6, 0x21b7, 1}, - {0x21bc, 0x21cd, 1}, - {0x21d0, 0x21d1, 1}, - {0x21d3, 0x21d5, 2}, - {0x21d6, 0x21db, 1}, - {0x21dd, 0x21e4, 7}, - {0x21e5, 0x2308, 291}, - {0x2309, 0x230b, 1}, - {0x23b4, 0x23b5, 1}, - {0x23b7, 0x23d0, 25}, - {0x23e2, 0x25a0, 446}, - {0x25a1, 0x25ae, 13}, - {0x25af, 0x25b6, 1}, - {0x25bc, 0x25c0, 1}, - {0x25c6, 0x25c7, 1}, - {0x25ca, 0x25cb, 1}, - {0x25cf, 0x25d3, 1}, - {0x25e2, 0x25e4, 2}, - {0x25e7, 0x25ec, 1}, - {0x2605, 0x2606, 1}, - {0x2640, 0x2642, 2}, - {0x2660, 0x2663, 1}, - {0x266d, 0x266e, 1}, - {0x27c5, 0x27c6, 1}, - {0x27e6, 0x27ef, 1}, - {0x2983, 0x2998, 1}, - {0x29d8, 0x29db, 1}, - {0x29fc, 0x29fd, 1}, - {0xfe61, 0xfe63, 2}, - {0xfe68, 0xff3c, 212}, - {0xff3e, 0xff3e, 1}, - ], - R32: [ - {0x1d400, 0x1d454, 1}, - {0x1d456, 0x1d49c, 1}, - {0x1d49e, 0x1d49f, 1}, - {0x1d4a2, 0x1d4a5, 3}, - {0x1d4a6, 0x1d4a9, 3}, - {0x1d4aa, 0x1d4ac, 1}, - {0x1d4ae, 0x1d4b9, 1}, - {0x1d4bb, 0x1d4bd, 2}, - {0x1d4be, 0x1d4c3, 1}, - {0x1d4c5, 0x1d505, 1}, - {0x1d507, 0x1d50a, 1}, - {0x1d50d, 0x1d514, 1}, - {0x1d516, 0x1d51c, 1}, - {0x1d51e, 0x1d539, 1}, - {0x1d53b, 0x1d53e, 1}, - {0x1d540, 0x1d544, 1}, - {0x1d546, 0x1d54a, 4}, - {0x1d54b, 0x1d550, 1}, - {0x1d552, 0x1d6a5, 1}, - {0x1d6a8, 0x1d6c0, 1}, - {0x1d6c2, 0x1d6da, 1}, - {0x1d6dc, 0x1d6fa, 1}, - {0x1d6fc, 0x1d714, 1}, - {0x1d716, 0x1d734, 1}, - {0x1d736, 0x1d74e, 1}, - {0x1d750, 0x1d76e, 1}, - {0x1d770, 0x1d788, 1}, - {0x1d78a, 0x1d7a8, 1}, - {0x1d7aa, 0x1d7c2, 1}, - {0x1d7c4, 0x1d7cb, 1}, - {0x1d7ce, 0x1d7ff, 1}, - {0x1ee00, 0x1ee03, 1}, - {0x1ee05, 0x1ee1f, 1}, - {0x1ee21, 0x1ee22, 1}, - {0x1ee24, 0x1ee27, 3}, - {0x1ee29, 0x1ee32, 1}, - {0x1ee34, 0x1ee37, 1}, - {0x1ee39, 0x1ee3b, 2}, - {0x1ee42, 0x1ee47, 5}, - {0x1ee49, 0x1ee4d, 2}, - {0x1ee4e, 0x1ee4f, 1}, - {0x1ee51, 0x1ee52, 1}, - {0x1ee54, 0x1ee57, 3}, - {0x1ee59, 0x1ee61, 2}, - {0x1ee62, 0x1ee64, 2}, - {0x1ee67, 0x1ee6a, 1}, - {0x1ee6c, 0x1ee72, 1}, - {0x1ee74, 0x1ee77, 1}, - {0x1ee79, 0x1ee7c, 1}, - {0x1ee7e, 0x1ee80, 2}, - {0x1ee81, 0x1ee89, 1}, - {0x1ee8b, 0x1ee9b, 1}, - {0x1eea1, 0x1eea3, 1}, - {0x1eea5, 0x1eea9, 1}, - {0x1eeab, 0x1eebb, 1}, - ], + R16: [ + {0x005e, 0x03d0, 882}, + {0x03d1, 0x03d2, 1}, + {0x03d5, 0x03f0, 27}, + {0x03f1, 0x03f4, 3}, + {0x03f5, 0x2016, 7201}, + {0x2032, 0x2034, 1}, + {0x2040, 0x2061, 33}, + {0x2062, 0x2064, 1}, + {0x207d, 0x207e, 1}, + {0x208d, 0x208e, 1}, + {0x20d0, 0x20dc, 1}, + {0x20e1, 0x20e5, 4}, + {0x20e6, 0x20eb, 5}, + {0x20ec, 0x20ef, 1}, + {0x2102, 0x2107, 5}, + {0x210a, 0x2113, 1}, + {0x2115, 0x2119, 4}, + {0x211a, 0x211d, 1}, + {0x2124, 0x2128, 4}, + {0x2129, 0x212c, 3}, + {0x212d, 0x212f, 2}, + {0x2130, 0x2131, 1}, + {0x2133, 0x2138, 1}, + {0x213c, 0x213f, 1}, + {0x2145, 0x2149, 1}, + {0x2195, 0x2199, 1}, + {0x219c, 0x219f, 1}, + {0x21a1, 0x21a2, 1}, + {0x21a4, 0x21a5, 1}, + {0x21a7, 0x21a9, 2}, + {0x21aa, 0x21ad, 1}, + {0x21b0, 0x21b1, 1}, + {0x21b6, 0x21b7, 1}, + {0x21bc, 0x21cd, 1}, + {0x21d0, 0x21d1, 1}, + {0x21d3, 0x21d5, 2}, + {0x21d6, 0x21db, 1}, + {0x21dd, 0x21e4, 7}, + {0x21e5, 0x2308, 291}, + {0x2309, 0x230b, 1}, + {0x23b4, 0x23b5, 1}, + {0x23b7, 0x23d0, 25}, + {0x23e2, 0x25a0, 446}, + {0x25a1, 0x25ae, 13}, + {0x25af, 0x25b6, 1}, + {0x25bc, 0x25c0, 1}, + {0x25c6, 0x25c7, 1}, + {0x25ca, 0x25cb, 1}, + {0x25cf, 0x25d3, 1}, + {0x25e2, 0x25e4, 2}, + {0x25e7, 0x25ec, 1}, + {0x2605, 0x2606, 1}, + {0x2640, 0x2642, 2}, + {0x2660, 0x2663, 1}, + {0x266d, 0x266e, 1}, + {0x27c5, 0x27c6, 1}, + {0x27e6, 0x27ef, 1}, + {0x2983, 0x2998, 1}, + {0x29d8, 0x29db, 1}, + {0x29fc, 0x29fd, 1}, + {0xfe61, 0xfe63, 2}, + {0xfe68, 0xff3c, 212}, + {0xff3e, 0xff3e, 1}, + ], + R32: [ + {0x1d400, 0x1d454, 1}, + {0x1d456, 0x1d49c, 1}, + {0x1d49e, 0x1d49f, 1}, + {0x1d4a2, 0x1d4a5, 3}, + {0x1d4a6, 0x1d4a9, 3}, + {0x1d4aa, 0x1d4ac, 1}, + {0x1d4ae, 0x1d4b9, 1}, + {0x1d4bb, 0x1d4bd, 2}, + {0x1d4be, 0x1d4c3, 1}, + {0x1d4c5, 0x1d505, 1}, + {0x1d507, 0x1d50a, 1}, + {0x1d50d, 0x1d514, 1}, + {0x1d516, 0x1d51c, 1}, + {0x1d51e, 0x1d539, 1}, + {0x1d53b, 0x1d53e, 1}, + {0x1d540, 0x1d544, 1}, + {0x1d546, 0x1d54a, 4}, + {0x1d54b, 0x1d550, 1}, + {0x1d552, 0x1d6a5, 1}, + {0x1d6a8, 0x1d6c0, 1}, + {0x1d6c2, 0x1d6da, 1}, + {0x1d6dc, 0x1d6fa, 1}, + {0x1d6fc, 0x1d714, 1}, + {0x1d716, 0x1d734, 1}, + {0x1d736, 0x1d74e, 1}, + {0x1d750, 0x1d76e, 1}, + {0x1d770, 0x1d788, 1}, + {0x1d78a, 0x1d7a8, 1}, + {0x1d7aa, 0x1d7c2, 1}, + {0x1d7c4, 0x1d7cb, 1}, + {0x1d7ce, 0x1d7ff, 1}, + {0x1ee00, 0x1ee03, 1}, + {0x1ee05, 0x1ee1f, 1}, + {0x1ee21, 0x1ee22, 1}, + {0x1ee24, 0x1ee27, 3}, + {0x1ee29, 0x1ee32, 1}, + {0x1ee34, 0x1ee37, 1}, + {0x1ee39, 0x1ee3b, 2}, + {0x1ee42, 0x1ee47, 5}, + {0x1ee49, 0x1ee4d, 2}, + {0x1ee4e, 0x1ee4f, 1}, + {0x1ee51, 0x1ee52, 1}, + {0x1ee54, 0x1ee57, 3}, + {0x1ee59, 0x1ee61, 2}, + {0x1ee62, 0x1ee64, 2}, + {0x1ee67, 0x1ee6a, 1}, + {0x1ee6c, 0x1ee72, 1}, + {0x1ee74, 0x1ee77, 1}, + {0x1ee79, 0x1ee7c, 1}, + {0x1ee7e, 0x1ee80, 2}, + {0x1ee81, 0x1ee89, 1}, + {0x1ee8b, 0x1ee9b, 1}, + {0x1eea1, 0x1eea3, 1}, + {0x1eea5, 0x1eea9, 1}, + {0x1eeab, 0x1eebb, 1}, + ], } static _OTHER_UPPERCASE = &RangeTable{ - R16: [ - {0x2160, 0x216f, 1}, - {0x24b6, 0x24cf, 1}, - ], - R32: [ - {0x1f130, 0x1f149, 1}, - {0x1f150, 0x1f169, 1}, - {0x1f170, 0x1f189, 1}, - ], + R16: [ + {0x2160, 0x216f, 1}, + {0x24b6, 0x24cf, 1}, + ], + R32: [ + {0x1f130, 0x1f149, 1}, + {0x1f150, 0x1f169, 1}, + {0x1f170, 0x1f189, 1}, + ], } static _PATTERN_SYNTAX = &RangeTable{ - R16: [ - {0x0021, 0x002f, 1}, - {0x003a, 0x0040, 1}, - {0x005b, 0x005e, 1}, - {0x0060, 0x007b, 27}, - {0x007c, 0x007e, 1}, - {0x00a1, 0x00a7, 1}, - {0x00a9, 0x00ab, 2}, - {0x00ac, 0x00b0, 2}, - {0x00b1, 0x00bb, 5}, - {0x00bf, 0x00d7, 24}, - {0x00f7, 0x2010, 7961}, - {0x2011, 0x2027, 1}, - {0x2030, 0x203e, 1}, - {0x2041, 0x2053, 1}, - {0x2055, 0x205e, 1}, - {0x2190, 0x245f, 1}, - {0x2500, 0x2775, 1}, - {0x2794, 0x2bff, 1}, - {0x2e00, 0x2e7f, 1}, - {0x3001, 0x3003, 1}, - {0x3008, 0x3020, 1}, - {0x3030, 0xfd3e, 52494}, - {0xfd3f, 0xfe45, 262}, - {0xfe46, 0xfe46, 1}, - ], - LatinOffset: 10, + R16: [ + {0x0021, 0x002f, 1}, + {0x003a, 0x0040, 1}, + {0x005b, 0x005e, 1}, + {0x0060, 0x007b, 27}, + {0x007c, 0x007e, 1}, + {0x00a1, 0x00a7, 1}, + {0x00a9, 0x00ab, 2}, + {0x00ac, 0x00b0, 2}, + {0x00b1, 0x00bb, 5}, + {0x00bf, 0x00d7, 24}, + {0x00f7, 0x2010, 7961}, + {0x2011, 0x2027, 1}, + {0x2030, 0x203e, 1}, + {0x2041, 0x2053, 1}, + {0x2055, 0x205e, 1}, + {0x2190, 0x245f, 1}, + {0x2500, 0x2775, 1}, + {0x2794, 0x2bff, 1}, + {0x2e00, 0x2e7f, 1}, + {0x3001, 0x3003, 1}, + {0x3008, 0x3020, 1}, + {0x3030, 0xfd3e, 52494}, + {0xfd3f, 0xfe45, 262}, + {0xfe46, 0xfe46, 1}, + ], + LatinOffset: 10, } static _PATTERN_WHITE_SPACE = &RangeTable{ - R16: [ - {0x0009, 0x000d, 1}, - {0x0020, 0x0085, 101}, - {0x200e, 0x200f, 1}, - {0x2028, 0x2029, 1}, - ], - LatinOffset: 2, + R16: [ + {0x0009, 0x000d, 1}, + {0x0020, 0x0085, 101}, + {0x200e, 0x200f, 1}, + {0x2028, 0x2029, 1}, + ], + LatinOffset: 2, } static _PREPENDED_CONCATENATION_MARK = &RangeTable{ - R16: [ - {0x0600, 0x0605, 1}, - {0x06dd, 0x070f, 50}, - {0x0890, 0x0891, 1}, - {0x08e2, 0x08e2, 1}, - ], - R32: [ - {0x110bd, 0x110cd, 16}, - ], + R16: [ + {0x0600, 0x0605, 1}, + {0x06dd, 0x070f, 50}, + {0x0890, 0x0891, 1}, + {0x08e2, 0x08e2, 1}, + ], + R32: [ + {0x110bd, 0x110cd, 16}, + ], } static _QUOTATION_MARK = &RangeTable{ - R16: [ - {0x0022, 0x0027, 5}, - {0x00ab, 0x00bb, 16}, - {0x2018, 0x201f, 1}, - {0x2039, 0x203a, 1}, - {0x2e42, 0x300c, 458}, - {0x300d, 0x300f, 1}, - {0x301d, 0x301f, 1}, - {0xfe41, 0xfe44, 1}, - {0xff02, 0xff07, 5}, - {0xff62, 0xff63, 1}, - ], - LatinOffset: 2, + R16: [ + {0x0022, 0x0027, 5}, + {0x00ab, 0x00bb, 16}, + {0x2018, 0x201f, 1}, + {0x2039, 0x203a, 1}, + {0x2e42, 0x300c, 458}, + {0x300d, 0x300f, 1}, + {0x301d, 0x301f, 1}, + {0xfe41, 0xfe44, 1}, + {0xff02, 0xff07, 5}, + {0xff62, 0xff63, 1}, + ], + LatinOffset: 2, } static _RADICAL = &RangeTable{ - R16: [ - {0x2e80, 0x2e99, 1}, - {0x2e9b, 0x2ef3, 1}, - {0x2f00, 0x2fd5, 1}, - ], + R16: [ + {0x2e80, 0x2e99, 1}, + {0x2e9b, 0x2ef3, 1}, + {0x2f00, 0x2fd5, 1}, + ], } static _REGIONAL_INDICATOR = &RangeTable{ - R16: [], - R32: [ - {0x1f1e6, 0x1f1ff, 1}, - ], + R16: [], + R32: [ + {0x1f1e6, 0x1f1ff, 1}, + ], } static _SENTENCE_TERMINAL = &RangeTable{ - R16: [ - {0x0021, 0x002e, 13}, - {0x003f, 0x0589, 1354}, - {0x061d, 0x061f, 1}, - {0x06d4, 0x0700, 44}, - {0x0701, 0x0702, 1}, - {0x07f9, 0x0837, 62}, - {0x0839, 0x083d, 4}, - {0x083e, 0x0964, 294}, - {0x0965, 0x104a, 1765}, - {0x104b, 0x1362, 791}, - {0x1367, 0x1368, 1}, - {0x166e, 0x1735, 199}, - {0x1736, 0x1803, 205}, - {0x1809, 0x1944, 315}, - {0x1945, 0x1aa8, 355}, - {0x1aa9, 0x1aab, 1}, - {0x1b5a, 0x1b5b, 1}, - {0x1b5e, 0x1b5f, 1}, - {0x1b7d, 0x1b7e, 1}, - {0x1c3b, 0x1c3c, 1}, - {0x1c7e, 0x1c7f, 1}, - {0x203c, 0x203d, 1}, - {0x2047, 0x2049, 1}, - {0x2e2e, 0x2e3c, 14}, - {0x2e53, 0x2e54, 1}, - {0x3002, 0xa4ff, 29949}, - {0xa60e, 0xa60f, 1}, - {0xa6f3, 0xa6f7, 4}, - {0xa876, 0xa877, 1}, - {0xa8ce, 0xa8cf, 1}, - {0xa92f, 0xa9c8, 153}, - {0xa9c9, 0xaa5d, 148}, - {0xaa5e, 0xaa5f, 1}, - {0xaaf0, 0xaaf1, 1}, - {0xabeb, 0xfe52, 21095}, - {0xfe56, 0xfe57, 1}, - {0xff01, 0xff0e, 13}, - {0xff1f, 0xff61, 66}, - ], - R32: [ - {0x10a56, 0x10a57, 1}, - {0x10f55, 0x10f59, 1}, - {0x10f86, 0x10f89, 1}, - {0x11047, 0x11048, 1}, - {0x110be, 0x110c1, 1}, - {0x11141, 0x11143, 1}, - {0x111c5, 0x111c6, 1}, - {0x111cd, 0x111de, 17}, - {0x111df, 0x11238, 89}, - {0x11239, 0x1123b, 2}, - {0x1123c, 0x112a9, 109}, - {0x1144b, 0x1144c, 1}, - {0x115c2, 0x115c3, 1}, - {0x115c9, 0x115d7, 1}, - {0x11641, 0x11642, 1}, - {0x1173c, 0x1173e, 1}, - {0x11944, 0x11946, 2}, - {0x11a42, 0x11a43, 1}, - {0x11a9b, 0x11a9c, 1}, - {0x11c41, 0x11c42, 1}, - {0x11ef7, 0x11ef8, 1}, - {0x11f43, 0x11f44, 1}, - {0x16a6e, 0x16a6f, 1}, - {0x16af5, 0x16b37, 66}, - {0x16b38, 0x16b44, 12}, - {0x16e98, 0x1bc9f, 19975}, - {0x1da88, 0x1da88, 1}, - ], - LatinOffset: 1, + R16: [ + {0x0021, 0x002e, 13}, + {0x003f, 0x0589, 1354}, + {0x061d, 0x061f, 1}, + {0x06d4, 0x0700, 44}, + {0x0701, 0x0702, 1}, + {0x07f9, 0x0837, 62}, + {0x0839, 0x083d, 4}, + {0x083e, 0x0964, 294}, + {0x0965, 0x104a, 1765}, + {0x104b, 0x1362, 791}, + {0x1367, 0x1368, 1}, + {0x166e, 0x1735, 199}, + {0x1736, 0x1803, 205}, + {0x1809, 0x1944, 315}, + {0x1945, 0x1aa8, 355}, + {0x1aa9, 0x1aab, 1}, + {0x1b5a, 0x1b5b, 1}, + {0x1b5e, 0x1b5f, 1}, + {0x1b7d, 0x1b7e, 1}, + {0x1c3b, 0x1c3c, 1}, + {0x1c7e, 0x1c7f, 1}, + {0x203c, 0x203d, 1}, + {0x2047, 0x2049, 1}, + {0x2e2e, 0x2e3c, 14}, + {0x2e53, 0x2e54, 1}, + {0x3002, 0xa4ff, 29949}, + {0xa60e, 0xa60f, 1}, + {0xa6f3, 0xa6f7, 4}, + {0xa876, 0xa877, 1}, + {0xa8ce, 0xa8cf, 1}, + {0xa92f, 0xa9c8, 153}, + {0xa9c9, 0xaa5d, 148}, + {0xaa5e, 0xaa5f, 1}, + {0xaaf0, 0xaaf1, 1}, + {0xabeb, 0xfe52, 21095}, + {0xfe56, 0xfe57, 1}, + {0xff01, 0xff0e, 13}, + {0xff1f, 0xff61, 66}, + ], + R32: [ + {0x10a56, 0x10a57, 1}, + {0x10f55, 0x10f59, 1}, + {0x10f86, 0x10f89, 1}, + {0x11047, 0x11048, 1}, + {0x110be, 0x110c1, 1}, + {0x11141, 0x11143, 1}, + {0x111c5, 0x111c6, 1}, + {0x111cd, 0x111de, 17}, + {0x111df, 0x11238, 89}, + {0x11239, 0x1123b, 2}, + {0x1123c, 0x112a9, 109}, + {0x1144b, 0x1144c, 1}, + {0x115c2, 0x115c3, 1}, + {0x115c9, 0x115d7, 1}, + {0x11641, 0x11642, 1}, + {0x1173c, 0x1173e, 1}, + {0x11944, 0x11946, 2}, + {0x11a42, 0x11a43, 1}, + {0x11a9b, 0x11a9c, 1}, + {0x11c41, 0x11c42, 1}, + {0x11ef7, 0x11ef8, 1}, + {0x11f43, 0x11f44, 1}, + {0x16a6e, 0x16a6f, 1}, + {0x16af5, 0x16b37, 66}, + {0x16b38, 0x16b44, 12}, + {0x16e98, 0x1bc9f, 19975}, + {0x1da88, 0x1da88, 1}, + ], + LatinOffset: 1, } static _SOFT_DOTTED = &RangeTable{ - R16: [ - {0x0069, 0x006a, 1}, - {0x012f, 0x0249, 282}, - {0x0268, 0x029d, 53}, - {0x02b2, 0x03f3, 321}, - {0x0456, 0x0458, 2}, - {0x1d62, 0x1d96, 52}, - {0x1da4, 0x1da8, 4}, - {0x1e2d, 0x1ecb, 158}, - {0x2071, 0x2148, 215}, - {0x2149, 0x2c7c, 2867}, - ], - R32: [ - {0x1d422, 0x1d423, 1}, - {0x1d456, 0x1d457, 1}, - {0x1d48a, 0x1d48b, 1}, - {0x1d4be, 0x1d4bf, 1}, - {0x1d4f2, 0x1d4f3, 1}, - {0x1d526, 0x1d527, 1}, - {0x1d55a, 0x1d55b, 1}, - {0x1d58e, 0x1d58f, 1}, - {0x1d5c2, 0x1d5c3, 1}, - {0x1d5f6, 0x1d5f7, 1}, - {0x1d62a, 0x1d62b, 1}, - {0x1d65e, 0x1d65f, 1}, - {0x1d692, 0x1d693, 1}, - {0x1df1a, 0x1e04c, 306}, - {0x1e04d, 0x1e068, 27}, - ], - LatinOffset: 1, + R16: [ + {0x0069, 0x006a, 1}, + {0x012f, 0x0249, 282}, + {0x0268, 0x029d, 53}, + {0x02b2, 0x03f3, 321}, + {0x0456, 0x0458, 2}, + {0x1d62, 0x1d96, 52}, + {0x1da4, 0x1da8, 4}, + {0x1e2d, 0x1ecb, 158}, + {0x2071, 0x2148, 215}, + {0x2149, 0x2c7c, 2867}, + ], + R32: [ + {0x1d422, 0x1d423, 1}, + {0x1d456, 0x1d457, 1}, + {0x1d48a, 0x1d48b, 1}, + {0x1d4be, 0x1d4bf, 1}, + {0x1d4f2, 0x1d4f3, 1}, + {0x1d526, 0x1d527, 1}, + {0x1d55a, 0x1d55b, 1}, + {0x1d58e, 0x1d58f, 1}, + {0x1d5c2, 0x1d5c3, 1}, + {0x1d5f6, 0x1d5f7, 1}, + {0x1d62a, 0x1d62b, 1}, + {0x1d65e, 0x1d65f, 1}, + {0x1d692, 0x1d693, 1}, + {0x1df1a, 0x1e04c, 306}, + {0x1e04d, 0x1e068, 27}, + ], + LatinOffset: 1, } static _TERMINAL_PUNCTUATION = &RangeTable{ - R16: [ - {0x0021, 0x002c, 11}, - {0x002e, 0x003a, 12}, - {0x003b, 0x003f, 4}, - {0x037e, 0x0387, 9}, - {0x0589, 0x05c3, 58}, - {0x060c, 0x061b, 15}, - {0x061d, 0x061f, 1}, - {0x06d4, 0x0700, 44}, - {0x0701, 0x070a, 1}, - {0x070c, 0x07f8, 236}, - {0x07f9, 0x0830, 55}, - {0x0831, 0x083e, 1}, - {0x085e, 0x0964, 262}, - {0x0965, 0x0e5a, 1269}, - {0x0e5b, 0x0f08, 173}, - {0x0f0d, 0x0f12, 1}, - {0x104a, 0x104b, 1}, - {0x1361, 0x1368, 1}, - {0x166e, 0x16eb, 125}, - {0x16ec, 0x16ed, 1}, - {0x1735, 0x1736, 1}, - {0x17d4, 0x17d6, 1}, - {0x17da, 0x1802, 40}, - {0x1803, 0x1805, 1}, - {0x1808, 0x1809, 1}, - {0x1944, 0x1945, 1}, - {0x1aa8, 0x1aab, 1}, - {0x1b5a, 0x1b5b, 1}, - {0x1b5d, 0x1b5f, 1}, - {0x1b7d, 0x1b7e, 1}, - {0x1c3b, 0x1c3f, 1}, - {0x1c7e, 0x1c7f, 1}, - {0x203c, 0x203d, 1}, - {0x2047, 0x2049, 1}, - {0x2e2e, 0x2e3c, 14}, - {0x2e41, 0x2e4c, 11}, - {0x2e4e, 0x2e4f, 1}, - {0x2e53, 0x2e54, 1}, - {0x3001, 0x3002, 1}, - {0xa4fe, 0xa4ff, 1}, - {0xa60d, 0xa60f, 1}, - {0xa6f3, 0xa6f7, 1}, - {0xa876, 0xa877, 1}, - {0xa8ce, 0xa8cf, 1}, - {0xa92f, 0xa9c7, 152}, - {0xa9c8, 0xa9c9, 1}, - {0xaa5d, 0xaa5f, 1}, - {0xaadf, 0xaaf0, 17}, - {0xaaf1, 0xabeb, 250}, - {0xfe50, 0xfe52, 1}, - {0xfe54, 0xfe57, 1}, - {0xff01, 0xff0c, 11}, - {0xff0e, 0xff1a, 12}, - {0xff1b, 0xff1f, 4}, - {0xff61, 0xff64, 3}, - ], - R32: [ - {0x1039f, 0x103d0, 49}, - {0x10857, 0x1091f, 200}, - {0x10a56, 0x10a57, 1}, - {0x10af0, 0x10af5, 1}, - {0x10b3a, 0x10b3f, 1}, - {0x10b99, 0x10b9c, 1}, - {0x10f55, 0x10f59, 1}, - {0x10f86, 0x10f89, 1}, - {0x11047, 0x1104d, 1}, - {0x110be, 0x110c1, 1}, - {0x11141, 0x11143, 1}, - {0x111c5, 0x111c6, 1}, - {0x111cd, 0x111de, 17}, - {0x111df, 0x11238, 89}, - {0x11239, 0x1123c, 1}, - {0x112a9, 0x1144b, 418}, - {0x1144c, 0x1144d, 1}, - {0x1145a, 0x1145b, 1}, - {0x115c2, 0x115c5, 1}, - {0x115c9, 0x115d7, 1}, - {0x11641, 0x11642, 1}, - {0x1173c, 0x1173e, 1}, - {0x11944, 0x11946, 2}, - {0x11a42, 0x11a43, 1}, - {0x11a9b, 0x11a9c, 1}, - {0x11aa1, 0x11aa2, 1}, - {0x11c41, 0x11c43, 1}, - {0x11c71, 0x11ef7, 646}, - {0x11ef8, 0x11f43, 75}, - {0x11f44, 0x12470, 1324}, - {0x12471, 0x12474, 1}, - {0x16a6e, 0x16a6f, 1}, - {0x16af5, 0x16b37, 66}, - {0x16b38, 0x16b39, 1}, - {0x16b44, 0x16e97, 851}, - {0x16e98, 0x1bc9f, 19975}, - {0x1da87, 0x1da8a, 1}, - ], - LatinOffset: 3, + R16: [ + {0x0021, 0x002c, 11}, + {0x002e, 0x003a, 12}, + {0x003b, 0x003f, 4}, + {0x037e, 0x0387, 9}, + {0x0589, 0x05c3, 58}, + {0x060c, 0x061b, 15}, + {0x061d, 0x061f, 1}, + {0x06d4, 0x0700, 44}, + {0x0701, 0x070a, 1}, + {0x070c, 0x07f8, 236}, + {0x07f9, 0x0830, 55}, + {0x0831, 0x083e, 1}, + {0x085e, 0x0964, 262}, + {0x0965, 0x0e5a, 1269}, + {0x0e5b, 0x0f08, 173}, + {0x0f0d, 0x0f12, 1}, + {0x104a, 0x104b, 1}, + {0x1361, 0x1368, 1}, + {0x166e, 0x16eb, 125}, + {0x16ec, 0x16ed, 1}, + {0x1735, 0x1736, 1}, + {0x17d4, 0x17d6, 1}, + {0x17da, 0x1802, 40}, + {0x1803, 0x1805, 1}, + {0x1808, 0x1809, 1}, + {0x1944, 0x1945, 1}, + {0x1aa8, 0x1aab, 1}, + {0x1b5a, 0x1b5b, 1}, + {0x1b5d, 0x1b5f, 1}, + {0x1b7d, 0x1b7e, 1}, + {0x1c3b, 0x1c3f, 1}, + {0x1c7e, 0x1c7f, 1}, + {0x203c, 0x203d, 1}, + {0x2047, 0x2049, 1}, + {0x2e2e, 0x2e3c, 14}, + {0x2e41, 0x2e4c, 11}, + {0x2e4e, 0x2e4f, 1}, + {0x2e53, 0x2e54, 1}, + {0x3001, 0x3002, 1}, + {0xa4fe, 0xa4ff, 1}, + {0xa60d, 0xa60f, 1}, + {0xa6f3, 0xa6f7, 1}, + {0xa876, 0xa877, 1}, + {0xa8ce, 0xa8cf, 1}, + {0xa92f, 0xa9c7, 152}, + {0xa9c8, 0xa9c9, 1}, + {0xaa5d, 0xaa5f, 1}, + {0xaadf, 0xaaf0, 17}, + {0xaaf1, 0xabeb, 250}, + {0xfe50, 0xfe52, 1}, + {0xfe54, 0xfe57, 1}, + {0xff01, 0xff0c, 11}, + {0xff0e, 0xff1a, 12}, + {0xff1b, 0xff1f, 4}, + {0xff61, 0xff64, 3}, + ], + R32: [ + {0x1039f, 0x103d0, 49}, + {0x10857, 0x1091f, 200}, + {0x10a56, 0x10a57, 1}, + {0x10af0, 0x10af5, 1}, + {0x10b3a, 0x10b3f, 1}, + {0x10b99, 0x10b9c, 1}, + {0x10f55, 0x10f59, 1}, + {0x10f86, 0x10f89, 1}, + {0x11047, 0x1104d, 1}, + {0x110be, 0x110c1, 1}, + {0x11141, 0x11143, 1}, + {0x111c5, 0x111c6, 1}, + {0x111cd, 0x111de, 17}, + {0x111df, 0x11238, 89}, + {0x11239, 0x1123c, 1}, + {0x112a9, 0x1144b, 418}, + {0x1144c, 0x1144d, 1}, + {0x1145a, 0x1145b, 1}, + {0x115c2, 0x115c5, 1}, + {0x115c9, 0x115d7, 1}, + {0x11641, 0x11642, 1}, + {0x1173c, 0x1173e, 1}, + {0x11944, 0x11946, 2}, + {0x11a42, 0x11a43, 1}, + {0x11a9b, 0x11a9c, 1}, + {0x11aa1, 0x11aa2, 1}, + {0x11c41, 0x11c43, 1}, + {0x11c71, 0x11ef7, 646}, + {0x11ef8, 0x11f43, 75}, + {0x11f44, 0x12470, 1324}, + {0x12471, 0x12474, 1}, + {0x16a6e, 0x16a6f, 1}, + {0x16af5, 0x16b37, 66}, + {0x16b38, 0x16b39, 1}, + {0x16b44, 0x16e97, 851}, + {0x16e98, 0x1bc9f, 19975}, + {0x1da87, 0x1da8a, 1}, + ], + LatinOffset: 3, } static _UNIFIED_IDEOGRAPH = &RangeTable{ - R16: [ - {0x3400, 0x4dbf, 1}, - {0x4e00, 0x9fff, 1}, - {0xfa0e, 0xfa0f, 1}, - {0xfa11, 0xfa13, 2}, - {0xfa14, 0xfa1f, 11}, - {0xfa21, 0xfa23, 2}, - {0xfa24, 0xfa27, 3}, - {0xfa28, 0xfa29, 1}, - ], - R32: [ - {0x20000, 0x2a6df, 1}, - {0x2a700, 0x2b739, 1}, - {0x2b740, 0x2b81d, 1}, - {0x2b820, 0x2cea1, 1}, - {0x2ceb0, 0x2ebe0, 1}, - {0x30000, 0x3134a, 1}, - {0x31350, 0x323af, 1}, - ], + R16: [ + {0x3400, 0x4dbf, 1}, + {0x4e00, 0x9fff, 1}, + {0xfa0e, 0xfa0f, 1}, + {0xfa11, 0xfa13, 2}, + {0xfa14, 0xfa1f, 11}, + {0xfa21, 0xfa23, 2}, + {0xfa24, 0xfa27, 3}, + {0xfa28, 0xfa29, 1}, + ], + R32: [ + {0x20000, 0x2a6df, 1}, + {0x2a700, 0x2b739, 1}, + {0x2b740, 0x2b81d, 1}, + {0x2b820, 0x2cea1, 1}, + {0x2ceb0, 0x2ebe0, 1}, + {0x30000, 0x3134a, 1}, + {0x31350, 0x323af, 1}, + ], } static _VARIATION_SELECTOR = &RangeTable{ - R16: [ - {0x180b, 0x180d, 1}, - {0x180f, 0xfe00, 58865}, - {0xfe01, 0xfe0f, 1}, - ], - R32: [ - {0xe0100, 0xe01ef, 1}, - ], + R16: [ + {0x180b, 0x180d, 1}, + {0x180f, 0xfe00, 58865}, + {0xfe01, 0xfe0f, 1}, + ], + R32: [ + {0xe0100, 0xe01ef, 1}, + ], } static _WHITE_SPACE = &RangeTable{ - R16: [ - {0x0009, 0x000d, 1}, - {0x0020, 0x0085, 101}, - {0x00a0, 0x1680, 5600}, - {0x2000, 0x200a, 1}, - {0x2028, 0x2029, 1}, - {0x202f, 0x205f, 48}, - {0x3000, 0x3000, 1}, - ], - LatinOffset: 2, + R16: [ + {0x0009, 0x000d, 1}, + {0x0020, 0x0085, 101}, + {0x00a0, 0x1680, 5600}, + {0x2000, 0x200a, 1}, + {0x2028, 0x2029, 1}, + {0x202f, 0x205f, 48}, + {0x3000, 0x3000, 1}, + ], + LatinOffset: 2, } // These variables have type &RangeTable. @@ -7254,815 +7254,815 @@ static WhiteSpace = _WHITE_SPACE // T // The table describing case mappings for all letters with non-self mappings. static CASE_RANGES = _CASE_RANGES static _CASE_RANGES: []caseRange = [ - {0x0041, 0x005A, [0, 32, 0]}, - {0x0061, 0x007A, [-32, 0, -32]}, - {0x00B5, 0x00B5, [743, 0, 743]}, - {0x00C0, 0x00D6, [0, 32, 0]}, - {0x00D8, 0x00DE, [0, 32, 0]}, - {0x00E0, 0x00F6, [-32, 0, -32]}, - {0x00F8, 0x00FE, [-32, 0, -32]}, - {0x00FF, 0x00FF, [121, 0, 121]}, - {0x0100, 0x012F, [upperLower, upperLower, upperLower]}, - {0x0130, 0x0130, [0, -199, 0]}, - {0x0131, 0x0131, [-232, 0, -232]}, - {0x0132, 0x0137, [upperLower, upperLower, upperLower]}, - {0x0139, 0x0148, [upperLower, upperLower, upperLower]}, - {0x014A, 0x0177, [upperLower, upperLower, upperLower]}, - {0x0178, 0x0178, [0, -121, 0]}, - {0x0179, 0x017E, [upperLower, upperLower, upperLower]}, - {0x017F, 0x017F, [-300, 0, -300]}, - {0x0180, 0x0180, [195, 0, 195]}, - {0x0181, 0x0181, [0, 210, 0]}, - {0x0182, 0x0185, [upperLower, upperLower, upperLower]}, - {0x0186, 0x0186, [0, 206, 0]}, - {0x0187, 0x0188, [upperLower, upperLower, upperLower]}, - {0x0189, 0x018A, [0, 205, 0]}, - {0x018B, 0x018C, [upperLower, upperLower, upperLower]}, - {0x018E, 0x018E, [0, 79, 0]}, - {0x018F, 0x018F, [0, 202, 0]}, - {0x0190, 0x0190, [0, 203, 0]}, - {0x0191, 0x0192, [upperLower, upperLower, upperLower]}, - {0x0193, 0x0193, [0, 205, 0]}, - {0x0194, 0x0194, [0, 207, 0]}, - {0x0195, 0x0195, [97, 0, 97]}, - {0x0196, 0x0196, [0, 211, 0]}, - {0x0197, 0x0197, [0, 209, 0]}, - {0x0198, 0x0199, [upperLower, upperLower, upperLower]}, - {0x019A, 0x019A, [163, 0, 163]}, - {0x019C, 0x019C, [0, 211, 0]}, - {0x019D, 0x019D, [0, 213, 0]}, - {0x019E, 0x019E, [130, 0, 130]}, - {0x019F, 0x019F, [0, 214, 0]}, - {0x01A0, 0x01A5, [upperLower, upperLower, upperLower]}, - {0x01A6, 0x01A6, [0, 218, 0]}, - {0x01A7, 0x01A8, [upperLower, upperLower, upperLower]}, - {0x01A9, 0x01A9, [0, 218, 0]}, - {0x01AC, 0x01AD, [upperLower, upperLower, upperLower]}, - {0x01AE, 0x01AE, [0, 218, 0]}, - {0x01AF, 0x01B0, [upperLower, upperLower, upperLower]}, - {0x01B1, 0x01B2, [0, 217, 0]}, - {0x01B3, 0x01B6, [upperLower, upperLower, upperLower]}, - {0x01B7, 0x01B7, [0, 219, 0]}, - {0x01B8, 0x01B9, [upperLower, upperLower, upperLower]}, - {0x01BC, 0x01BD, [upperLower, upperLower, upperLower]}, - {0x01BF, 0x01BF, [56, 0, 56]}, - {0x01C4, 0x01C4, [0, 2, 1]}, - {0x01C5, 0x01C5, [-1, 1, 0]}, - {0x01C6, 0x01C6, [-2, 0, -1]}, - {0x01C7, 0x01C7, [0, 2, 1]}, - {0x01C8, 0x01C8, [-1, 1, 0]}, - {0x01C9, 0x01C9, [-2, 0, -1]}, - {0x01CA, 0x01CA, [0, 2, 1]}, - {0x01CB, 0x01CB, [-1, 1, 0]}, - {0x01CC, 0x01CC, [-2, 0, -1]}, - {0x01CD, 0x01DC, [upperLower, upperLower, upperLower]}, - {0x01DD, 0x01DD, [-79, 0, -79]}, - {0x01DE, 0x01EF, [upperLower, upperLower, upperLower]}, - {0x01F1, 0x01F1, [0, 2, 1]}, - {0x01F2, 0x01F2, [-1, 1, 0]}, - {0x01F3, 0x01F3, [-2, 0, -1]}, - {0x01F4, 0x01F5, [upperLower, upperLower, upperLower]}, - {0x01F6, 0x01F6, [0, -97, 0]}, - {0x01F7, 0x01F7, [0, -56, 0]}, - {0x01F8, 0x021F, [upperLower, upperLower, upperLower]}, - {0x0220, 0x0220, [0, -130, 0]}, - {0x0222, 0x0233, [upperLower, upperLower, upperLower]}, - {0x023A, 0x023A, [0, 10795, 0]}, - {0x023B, 0x023C, [upperLower, upperLower, upperLower]}, - {0x023D, 0x023D, [0, -163, 0]}, - {0x023E, 0x023E, [0, 10792, 0]}, - {0x023F, 0x0240, [10815, 0, 10815]}, - {0x0241, 0x0242, [upperLower, upperLower, upperLower]}, - {0x0243, 0x0243, [0, -195, 0]}, - {0x0244, 0x0244, [0, 69, 0]}, - {0x0245, 0x0245, [0, 71, 0]}, - {0x0246, 0x024F, [upperLower, upperLower, upperLower]}, - {0x0250, 0x0250, [10783, 0, 10783]}, - {0x0251, 0x0251, [10780, 0, 10780]}, - {0x0252, 0x0252, [10782, 0, 10782]}, - {0x0253, 0x0253, [-210, 0, -210]}, - {0x0254, 0x0254, [-206, 0, -206]}, - {0x0256, 0x0257, [-205, 0, -205]}, - {0x0259, 0x0259, [-202, 0, -202]}, - {0x025B, 0x025B, [-203, 0, -203]}, - {0x025C, 0x025C, [42319, 0, 42319]}, - {0x0260, 0x0260, [-205, 0, -205]}, - {0x0261, 0x0261, [42315, 0, 42315]}, - {0x0263, 0x0263, [-207, 0, -207]}, - {0x0265, 0x0265, [42280, 0, 42280]}, - {0x0266, 0x0266, [42308, 0, 42308]}, - {0x0268, 0x0268, [-209, 0, -209]}, - {0x0269, 0x0269, [-211, 0, -211]}, - {0x026A, 0x026A, [42308, 0, 42308]}, - {0x026B, 0x026B, [10743, 0, 10743]}, - {0x026C, 0x026C, [42305, 0, 42305]}, - {0x026F, 0x026F, [-211, 0, -211]}, - {0x0271, 0x0271, [10749, 0, 10749]}, - {0x0272, 0x0272, [-213, 0, -213]}, - {0x0275, 0x0275, [-214, 0, -214]}, - {0x027D, 0x027D, [10727, 0, 10727]}, - {0x0280, 0x0280, [-218, 0, -218]}, - {0x0282, 0x0282, [42307, 0, 42307]}, - {0x0283, 0x0283, [-218, 0, -218]}, - {0x0287, 0x0287, [42282, 0, 42282]}, - {0x0288, 0x0288, [-218, 0, -218]}, - {0x0289, 0x0289, [-69, 0, -69]}, - {0x028A, 0x028B, [-217, 0, -217]}, - {0x028C, 0x028C, [-71, 0, -71]}, - {0x0292, 0x0292, [-219, 0, -219]}, - {0x029D, 0x029D, [42261, 0, 42261]}, - {0x029E, 0x029E, [42258, 0, 42258]}, - {0x0345, 0x0345, [84, 0, 84]}, - {0x0370, 0x0373, [upperLower, upperLower, upperLower]}, - {0x0376, 0x0377, [upperLower, upperLower, upperLower]}, - {0x037B, 0x037D, [130, 0, 130]}, - {0x037F, 0x037F, [0, 116, 0]}, - {0x0386, 0x0386, [0, 38, 0]}, - {0x0388, 0x038A, [0, 37, 0]}, - {0x038C, 0x038C, [0, 64, 0]}, - {0x038E, 0x038F, [0, 63, 0]}, - {0x0391, 0x03A1, [0, 32, 0]}, - {0x03A3, 0x03AB, [0, 32, 0]}, - {0x03AC, 0x03AC, [-38, 0, -38]}, - {0x03AD, 0x03AF, [-37, 0, -37]}, - {0x03B1, 0x03C1, [-32, 0, -32]}, - {0x03C2, 0x03C2, [-31, 0, -31]}, - {0x03C3, 0x03CB, [-32, 0, -32]}, - {0x03CC, 0x03CC, [-64, 0, -64]}, - {0x03CD, 0x03CE, [-63, 0, -63]}, - {0x03CF, 0x03CF, [0, 8, 0]}, - {0x03D0, 0x03D0, [-62, 0, -62]}, - {0x03D1, 0x03D1, [-57, 0, -57]}, - {0x03D5, 0x03D5, [-47, 0, -47]}, - {0x03D6, 0x03D6, [-54, 0, -54]}, - {0x03D7, 0x03D7, [-8, 0, -8]}, - {0x03D8, 0x03EF, [upperLower, upperLower, upperLower]}, - {0x03F0, 0x03F0, [-86, 0, -86]}, - {0x03F1, 0x03F1, [-80, 0, -80]}, - {0x03F2, 0x03F2, [7, 0, 7]}, - {0x03F3, 0x03F3, [-116, 0, -116]}, - {0x03F4, 0x03F4, [0, -60, 0]}, - {0x03F5, 0x03F5, [-96, 0, -96]}, - {0x03F7, 0x03F8, [upperLower, upperLower, upperLower]}, - {0x03F9, 0x03F9, [0, -7, 0]}, - {0x03FA, 0x03FB, [upperLower, upperLower, upperLower]}, - {0x03FD, 0x03FF, [0, -130, 0]}, - {0x0400, 0x040F, [0, 80, 0]}, - {0x0410, 0x042F, [0, 32, 0]}, - {0x0430, 0x044F, [-32, 0, -32]}, - {0x0450, 0x045F, [-80, 0, -80]}, - {0x0460, 0x0481, [upperLower, upperLower, upperLower]}, - {0x048A, 0x04BF, [upperLower, upperLower, upperLower]}, - {0x04C0, 0x04C0, [0, 15, 0]}, - {0x04C1, 0x04CE, [upperLower, upperLower, upperLower]}, - {0x04CF, 0x04CF, [-15, 0, -15]}, - {0x04D0, 0x052F, [upperLower, upperLower, upperLower]}, - {0x0531, 0x0556, [0, 48, 0]}, - {0x0561, 0x0586, [-48, 0, -48]}, - {0x10A0, 0x10C5, [0, 7264, 0]}, - {0x10C7, 0x10C7, [0, 7264, 0]}, - {0x10CD, 0x10CD, [0, 7264, 0]}, - {0x10D0, 0x10FA, [3008, 0, 0]}, - {0x10FD, 0x10FF, [3008, 0, 0]}, - {0x13A0, 0x13EF, [0, 38864, 0]}, - {0x13F0, 0x13F5, [0, 8, 0]}, - {0x13F8, 0x13FD, [-8, 0, -8]}, - {0x1C80, 0x1C80, [-6254, 0, -6254]}, - {0x1C81, 0x1C81, [-6253, 0, -6253]}, - {0x1C82, 0x1C82, [-6244, 0, -6244]}, - {0x1C83, 0x1C84, [-6242, 0, -6242]}, - {0x1C85, 0x1C85, [-6243, 0, -6243]}, - {0x1C86, 0x1C86, [-6236, 0, -6236]}, - {0x1C87, 0x1C87, [-6181, 0, -6181]}, - {0x1C88, 0x1C88, [35266, 0, 35266]}, - {0x1C90, 0x1CBA, [0, -3008, 0]}, - {0x1CBD, 0x1CBF, [0, -3008, 0]}, - {0x1D79, 0x1D79, [35332, 0, 35332]}, - {0x1D7D, 0x1D7D, [3814, 0, 3814]}, - {0x1D8E, 0x1D8E, [35384, 0, 35384]}, - {0x1E00, 0x1E95, [upperLower, upperLower, upperLower]}, - {0x1E9B, 0x1E9B, [-59, 0, -59]}, - {0x1E9E, 0x1E9E, [0, -7615, 0]}, - {0x1EA0, 0x1EFF, [upperLower, upperLower, upperLower]}, - {0x1F00, 0x1F07, [8, 0, 8]}, - {0x1F08, 0x1F0F, [0, -8, 0]}, - {0x1F10, 0x1F15, [8, 0, 8]}, - {0x1F18, 0x1F1D, [0, -8, 0]}, - {0x1F20, 0x1F27, [8, 0, 8]}, - {0x1F28, 0x1F2F, [0, -8, 0]}, - {0x1F30, 0x1F37, [8, 0, 8]}, - {0x1F38, 0x1F3F, [0, -8, 0]}, - {0x1F40, 0x1F45, [8, 0, 8]}, - {0x1F48, 0x1F4D, [0, -8, 0]}, - {0x1F51, 0x1F51, [8, 0, 8]}, - {0x1F53, 0x1F53, [8, 0, 8]}, - {0x1F55, 0x1F55, [8, 0, 8]}, - {0x1F57, 0x1F57, [8, 0, 8]}, - {0x1F59, 0x1F59, [0, -8, 0]}, - {0x1F5B, 0x1F5B, [0, -8, 0]}, - {0x1F5D, 0x1F5D, [0, -8, 0]}, - {0x1F5F, 0x1F5F, [0, -8, 0]}, - {0x1F60, 0x1F67, [8, 0, 8]}, - {0x1F68, 0x1F6F, [0, -8, 0]}, - {0x1F70, 0x1F71, [74, 0, 74]}, - {0x1F72, 0x1F75, [86, 0, 86]}, - {0x1F76, 0x1F77, [100, 0, 100]}, - {0x1F78, 0x1F79, [128, 0, 128]}, - {0x1F7A, 0x1F7B, [112, 0, 112]}, - {0x1F7C, 0x1F7D, [126, 0, 126]}, - {0x1F80, 0x1F87, [8, 0, 8]}, - {0x1F88, 0x1F8F, [0, -8, 0]}, - {0x1F90, 0x1F97, [8, 0, 8]}, - {0x1F98, 0x1F9F, [0, -8, 0]}, - {0x1FA0, 0x1FA7, [8, 0, 8]}, - {0x1FA8, 0x1FAF, [0, -8, 0]}, - {0x1FB0, 0x1FB1, [8, 0, 8]}, - {0x1FB3, 0x1FB3, [9, 0, 9]}, - {0x1FB8, 0x1FB9, [0, -8, 0]}, - {0x1FBA, 0x1FBB, [0, -74, 0]}, - {0x1FBC, 0x1FBC, [0, -9, 0]}, - {0x1FBE, 0x1FBE, [-7205, 0, -7205]}, - {0x1FC3, 0x1FC3, [9, 0, 9]}, - {0x1FC8, 0x1FCB, [0, -86, 0]}, - {0x1FCC, 0x1FCC, [0, -9, 0]}, - {0x1FD0, 0x1FD1, [8, 0, 8]}, - {0x1FD8, 0x1FD9, [0, -8, 0]}, - {0x1FDA, 0x1FDB, [0, -100, 0]}, - {0x1FE0, 0x1FE1, [8, 0, 8]}, - {0x1FE5, 0x1FE5, [7, 0, 7]}, - {0x1FE8, 0x1FE9, [0, -8, 0]}, - {0x1FEA, 0x1FEB, [0, -112, 0]}, - {0x1FEC, 0x1FEC, [0, -7, 0]}, - {0x1FF3, 0x1FF3, [9, 0, 9]}, - {0x1FF8, 0x1FF9, [0, -128, 0]}, - {0x1FFA, 0x1FFB, [0, -126, 0]}, - {0x1FFC, 0x1FFC, [0, -9, 0]}, - {0x2126, 0x2126, [0, -7517, 0]}, - {0x212A, 0x212A, [0, -8383, 0]}, - {0x212B, 0x212B, [0, -8262, 0]}, - {0x2132, 0x2132, [0, 28, 0]}, - {0x214E, 0x214E, [-28, 0, -28]}, - {0x2160, 0x216F, [0, 16, 0]}, - {0x2170, 0x217F, [-16, 0, -16]}, - {0x2183, 0x2184, [upperLower, upperLower, upperLower]}, - {0x24B6, 0x24CF, [0, 26, 0]}, - {0x24D0, 0x24E9, [-26, 0, -26]}, - {0x2C00, 0x2C2F, [0, 48, 0]}, - {0x2C30, 0x2C5F, [-48, 0, -48]}, - {0x2C60, 0x2C61, [upperLower, upperLower, upperLower]}, - {0x2C62, 0x2C62, [0, -10743, 0]}, - {0x2C63, 0x2C63, [0, -3814, 0]}, - {0x2C64, 0x2C64, [0, -10727, 0]}, - {0x2C65, 0x2C65, [-10795, 0, -10795]}, - {0x2C66, 0x2C66, [-10792, 0, -10792]}, - {0x2C67, 0x2C6C, [upperLower, upperLower, upperLower]}, - {0x2C6D, 0x2C6D, [0, -10780, 0]}, - {0x2C6E, 0x2C6E, [0, -10749, 0]}, - {0x2C6F, 0x2C6F, [0, -10783, 0]}, - {0x2C70, 0x2C70, [0, -10782, 0]}, - {0x2C72, 0x2C73, [upperLower, upperLower, upperLower]}, - {0x2C75, 0x2C76, [upperLower, upperLower, upperLower]}, - {0x2C7E, 0x2C7F, [0, -10815, 0]}, - {0x2C80, 0x2CE3, [upperLower, upperLower, upperLower]}, - {0x2CEB, 0x2CEE, [upperLower, upperLower, upperLower]}, - {0x2CF2, 0x2CF3, [upperLower, upperLower, upperLower]}, - {0x2D00, 0x2D25, [-7264, 0, -7264]}, - {0x2D27, 0x2D27, [-7264, 0, -7264]}, - {0x2D2D, 0x2D2D, [-7264, 0, -7264]}, - {0xA640, 0xA66D, [upperLower, upperLower, upperLower]}, - {0xA680, 0xA69B, [upperLower, upperLower, upperLower]}, - {0xA722, 0xA72F, [upperLower, upperLower, upperLower]}, - {0xA732, 0xA76F, [upperLower, upperLower, upperLower]}, - {0xA779, 0xA77C, [upperLower, upperLower, upperLower]}, - {0xA77D, 0xA77D, [0, -35332, 0]}, - {0xA77E, 0xA787, [upperLower, upperLower, upperLower]}, - {0xA78B, 0xA78C, [upperLower, upperLower, upperLower]}, - {0xA78D, 0xA78D, [0, -42280, 0]}, - {0xA790, 0xA793, [upperLower, upperLower, upperLower]}, - {0xA794, 0xA794, [48, 0, 48]}, - {0xA796, 0xA7A9, [upperLower, upperLower, upperLower]}, - {0xA7AA, 0xA7AA, [0, -42308, 0]}, - {0xA7AB, 0xA7AB, [0, -42319, 0]}, - {0xA7AC, 0xA7AC, [0, -42315, 0]}, - {0xA7AD, 0xA7AD, [0, -42305, 0]}, - {0xA7AE, 0xA7AE, [0, -42308, 0]}, - {0xA7B0, 0xA7B0, [0, -42258, 0]}, - {0xA7B1, 0xA7B1, [0, -42282, 0]}, - {0xA7B2, 0xA7B2, [0, -42261, 0]}, - {0xA7B3, 0xA7B3, [0, 928, 0]}, - {0xA7B4, 0xA7C3, [upperLower, upperLower, upperLower]}, - {0xA7C4, 0xA7C4, [0, -48, 0]}, - {0xA7C5, 0xA7C5, [0, -42307, 0]}, - {0xA7C6, 0xA7C6, [0, -35384, 0]}, - {0xA7C7, 0xA7CA, [upperLower, upperLower, upperLower]}, - {0xA7D0, 0xA7D1, [upperLower, upperLower, upperLower]}, - {0xA7D6, 0xA7D9, [upperLower, upperLower, upperLower]}, - {0xA7F5, 0xA7F6, [upperLower, upperLower, upperLower]}, - {0xAB53, 0xAB53, [-928, 0, -928]}, - {0xAB70, 0xABBF, [-38864, 0, -38864]}, - {0xFF21, 0xFF3A, [0, 32, 0]}, - {0xFF41, 0xFF5A, [-32, 0, -32]}, - {0x10400, 0x10427, [0, 40, 0]}, - {0x10428, 0x1044F, [-40, 0, -40]}, - {0x104B0, 0x104D3, [0, 40, 0]}, - {0x104D8, 0x104FB, [-40, 0, -40]}, - {0x10570, 0x1057A, [0, 39, 0]}, - {0x1057C, 0x1058A, [0, 39, 0]}, - {0x1058C, 0x10592, [0, 39, 0]}, - {0x10594, 0x10595, [0, 39, 0]}, - {0x10597, 0x105A1, [-39, 0, -39]}, - {0x105A3, 0x105B1, [-39, 0, -39]}, - {0x105B3, 0x105B9, [-39, 0, -39]}, - {0x105BB, 0x105BC, [-39, 0, -39]}, - {0x10C80, 0x10CB2, [0, 64, 0]}, - {0x10CC0, 0x10CF2, [-64, 0, -64]}, - {0x118A0, 0x118BF, [0, 32, 0]}, - {0x118C0, 0x118DF, [-32, 0, -32]}, - {0x16E40, 0x16E5F, [0, 32, 0]}, - {0x16E60, 0x16E7F, [-32, 0, -32]}, - {0x1E900, 0x1E921, [0, 34, 0]}, - {0x1E922, 0x1E943, [-34, 0, -34]}, + {0x0041, 0x005A, [0, 32, 0]}, + {0x0061, 0x007A, [-32, 0, -32]}, + {0x00B5, 0x00B5, [743, 0, 743]}, + {0x00C0, 0x00D6, [0, 32, 0]}, + {0x00D8, 0x00DE, [0, 32, 0]}, + {0x00E0, 0x00F6, [-32, 0, -32]}, + {0x00F8, 0x00FE, [-32, 0, -32]}, + {0x00FF, 0x00FF, [121, 0, 121]}, + {0x0100, 0x012F, [upperLower, upperLower, upperLower]}, + {0x0130, 0x0130, [0, -199, 0]}, + {0x0131, 0x0131, [-232, 0, -232]}, + {0x0132, 0x0137, [upperLower, upperLower, upperLower]}, + {0x0139, 0x0148, [upperLower, upperLower, upperLower]}, + {0x014A, 0x0177, [upperLower, upperLower, upperLower]}, + {0x0178, 0x0178, [0, -121, 0]}, + {0x0179, 0x017E, [upperLower, upperLower, upperLower]}, + {0x017F, 0x017F, [-300, 0, -300]}, + {0x0180, 0x0180, [195, 0, 195]}, + {0x0181, 0x0181, [0, 210, 0]}, + {0x0182, 0x0185, [upperLower, upperLower, upperLower]}, + {0x0186, 0x0186, [0, 206, 0]}, + {0x0187, 0x0188, [upperLower, upperLower, upperLower]}, + {0x0189, 0x018A, [0, 205, 0]}, + {0x018B, 0x018C, [upperLower, upperLower, upperLower]}, + {0x018E, 0x018E, [0, 79, 0]}, + {0x018F, 0x018F, [0, 202, 0]}, + {0x0190, 0x0190, [0, 203, 0]}, + {0x0191, 0x0192, [upperLower, upperLower, upperLower]}, + {0x0193, 0x0193, [0, 205, 0]}, + {0x0194, 0x0194, [0, 207, 0]}, + {0x0195, 0x0195, [97, 0, 97]}, + {0x0196, 0x0196, [0, 211, 0]}, + {0x0197, 0x0197, [0, 209, 0]}, + {0x0198, 0x0199, [upperLower, upperLower, upperLower]}, + {0x019A, 0x019A, [163, 0, 163]}, + {0x019C, 0x019C, [0, 211, 0]}, + {0x019D, 0x019D, [0, 213, 0]}, + {0x019E, 0x019E, [130, 0, 130]}, + {0x019F, 0x019F, [0, 214, 0]}, + {0x01A0, 0x01A5, [upperLower, upperLower, upperLower]}, + {0x01A6, 0x01A6, [0, 218, 0]}, + {0x01A7, 0x01A8, [upperLower, upperLower, upperLower]}, + {0x01A9, 0x01A9, [0, 218, 0]}, + {0x01AC, 0x01AD, [upperLower, upperLower, upperLower]}, + {0x01AE, 0x01AE, [0, 218, 0]}, + {0x01AF, 0x01B0, [upperLower, upperLower, upperLower]}, + {0x01B1, 0x01B2, [0, 217, 0]}, + {0x01B3, 0x01B6, [upperLower, upperLower, upperLower]}, + {0x01B7, 0x01B7, [0, 219, 0]}, + {0x01B8, 0x01B9, [upperLower, upperLower, upperLower]}, + {0x01BC, 0x01BD, [upperLower, upperLower, upperLower]}, + {0x01BF, 0x01BF, [56, 0, 56]}, + {0x01C4, 0x01C4, [0, 2, 1]}, + {0x01C5, 0x01C5, [-1, 1, 0]}, + {0x01C6, 0x01C6, [-2, 0, -1]}, + {0x01C7, 0x01C7, [0, 2, 1]}, + {0x01C8, 0x01C8, [-1, 1, 0]}, + {0x01C9, 0x01C9, [-2, 0, -1]}, + {0x01CA, 0x01CA, [0, 2, 1]}, + {0x01CB, 0x01CB, [-1, 1, 0]}, + {0x01CC, 0x01CC, [-2, 0, -1]}, + {0x01CD, 0x01DC, [upperLower, upperLower, upperLower]}, + {0x01DD, 0x01DD, [-79, 0, -79]}, + {0x01DE, 0x01EF, [upperLower, upperLower, upperLower]}, + {0x01F1, 0x01F1, [0, 2, 1]}, + {0x01F2, 0x01F2, [-1, 1, 0]}, + {0x01F3, 0x01F3, [-2, 0, -1]}, + {0x01F4, 0x01F5, [upperLower, upperLower, upperLower]}, + {0x01F6, 0x01F6, [0, -97, 0]}, + {0x01F7, 0x01F7, [0, -56, 0]}, + {0x01F8, 0x021F, [upperLower, upperLower, upperLower]}, + {0x0220, 0x0220, [0, -130, 0]}, + {0x0222, 0x0233, [upperLower, upperLower, upperLower]}, + {0x023A, 0x023A, [0, 10795, 0]}, + {0x023B, 0x023C, [upperLower, upperLower, upperLower]}, + {0x023D, 0x023D, [0, -163, 0]}, + {0x023E, 0x023E, [0, 10792, 0]}, + {0x023F, 0x0240, [10815, 0, 10815]}, + {0x0241, 0x0242, [upperLower, upperLower, upperLower]}, + {0x0243, 0x0243, [0, -195, 0]}, + {0x0244, 0x0244, [0, 69, 0]}, + {0x0245, 0x0245, [0, 71, 0]}, + {0x0246, 0x024F, [upperLower, upperLower, upperLower]}, + {0x0250, 0x0250, [10783, 0, 10783]}, + {0x0251, 0x0251, [10780, 0, 10780]}, + {0x0252, 0x0252, [10782, 0, 10782]}, + {0x0253, 0x0253, [-210, 0, -210]}, + {0x0254, 0x0254, [-206, 0, -206]}, + {0x0256, 0x0257, [-205, 0, -205]}, + {0x0259, 0x0259, [-202, 0, -202]}, + {0x025B, 0x025B, [-203, 0, -203]}, + {0x025C, 0x025C, [42319, 0, 42319]}, + {0x0260, 0x0260, [-205, 0, -205]}, + {0x0261, 0x0261, [42315, 0, 42315]}, + {0x0263, 0x0263, [-207, 0, -207]}, + {0x0265, 0x0265, [42280, 0, 42280]}, + {0x0266, 0x0266, [42308, 0, 42308]}, + {0x0268, 0x0268, [-209, 0, -209]}, + {0x0269, 0x0269, [-211, 0, -211]}, + {0x026A, 0x026A, [42308, 0, 42308]}, + {0x026B, 0x026B, [10743, 0, 10743]}, + {0x026C, 0x026C, [42305, 0, 42305]}, + {0x026F, 0x026F, [-211, 0, -211]}, + {0x0271, 0x0271, [10749, 0, 10749]}, + {0x0272, 0x0272, [-213, 0, -213]}, + {0x0275, 0x0275, [-214, 0, -214]}, + {0x027D, 0x027D, [10727, 0, 10727]}, + {0x0280, 0x0280, [-218, 0, -218]}, + {0x0282, 0x0282, [42307, 0, 42307]}, + {0x0283, 0x0283, [-218, 0, -218]}, + {0x0287, 0x0287, [42282, 0, 42282]}, + {0x0288, 0x0288, [-218, 0, -218]}, + {0x0289, 0x0289, [-69, 0, -69]}, + {0x028A, 0x028B, [-217, 0, -217]}, + {0x028C, 0x028C, [-71, 0, -71]}, + {0x0292, 0x0292, [-219, 0, -219]}, + {0x029D, 0x029D, [42261, 0, 42261]}, + {0x029E, 0x029E, [42258, 0, 42258]}, + {0x0345, 0x0345, [84, 0, 84]}, + {0x0370, 0x0373, [upperLower, upperLower, upperLower]}, + {0x0376, 0x0377, [upperLower, upperLower, upperLower]}, + {0x037B, 0x037D, [130, 0, 130]}, + {0x037F, 0x037F, [0, 116, 0]}, + {0x0386, 0x0386, [0, 38, 0]}, + {0x0388, 0x038A, [0, 37, 0]}, + {0x038C, 0x038C, [0, 64, 0]}, + {0x038E, 0x038F, [0, 63, 0]}, + {0x0391, 0x03A1, [0, 32, 0]}, + {0x03A3, 0x03AB, [0, 32, 0]}, + {0x03AC, 0x03AC, [-38, 0, -38]}, + {0x03AD, 0x03AF, [-37, 0, -37]}, + {0x03B1, 0x03C1, [-32, 0, -32]}, + {0x03C2, 0x03C2, [-31, 0, -31]}, + {0x03C3, 0x03CB, [-32, 0, -32]}, + {0x03CC, 0x03CC, [-64, 0, -64]}, + {0x03CD, 0x03CE, [-63, 0, -63]}, + {0x03CF, 0x03CF, [0, 8, 0]}, + {0x03D0, 0x03D0, [-62, 0, -62]}, + {0x03D1, 0x03D1, [-57, 0, -57]}, + {0x03D5, 0x03D5, [-47, 0, -47]}, + {0x03D6, 0x03D6, [-54, 0, -54]}, + {0x03D7, 0x03D7, [-8, 0, -8]}, + {0x03D8, 0x03EF, [upperLower, upperLower, upperLower]}, + {0x03F0, 0x03F0, [-86, 0, -86]}, + {0x03F1, 0x03F1, [-80, 0, -80]}, + {0x03F2, 0x03F2, [7, 0, 7]}, + {0x03F3, 0x03F3, [-116, 0, -116]}, + {0x03F4, 0x03F4, [0, -60, 0]}, + {0x03F5, 0x03F5, [-96, 0, -96]}, + {0x03F7, 0x03F8, [upperLower, upperLower, upperLower]}, + {0x03F9, 0x03F9, [0, -7, 0]}, + {0x03FA, 0x03FB, [upperLower, upperLower, upperLower]}, + {0x03FD, 0x03FF, [0, -130, 0]}, + {0x0400, 0x040F, [0, 80, 0]}, + {0x0410, 0x042F, [0, 32, 0]}, + {0x0430, 0x044F, [-32, 0, -32]}, + {0x0450, 0x045F, [-80, 0, -80]}, + {0x0460, 0x0481, [upperLower, upperLower, upperLower]}, + {0x048A, 0x04BF, [upperLower, upperLower, upperLower]}, + {0x04C0, 0x04C0, [0, 15, 0]}, + {0x04C1, 0x04CE, [upperLower, upperLower, upperLower]}, + {0x04CF, 0x04CF, [-15, 0, -15]}, + {0x04D0, 0x052F, [upperLower, upperLower, upperLower]}, + {0x0531, 0x0556, [0, 48, 0]}, + {0x0561, 0x0586, [-48, 0, -48]}, + {0x10A0, 0x10C5, [0, 7264, 0]}, + {0x10C7, 0x10C7, [0, 7264, 0]}, + {0x10CD, 0x10CD, [0, 7264, 0]}, + {0x10D0, 0x10FA, [3008, 0, 0]}, + {0x10FD, 0x10FF, [3008, 0, 0]}, + {0x13A0, 0x13EF, [0, 38864, 0]}, + {0x13F0, 0x13F5, [0, 8, 0]}, + {0x13F8, 0x13FD, [-8, 0, -8]}, + {0x1C80, 0x1C80, [-6254, 0, -6254]}, + {0x1C81, 0x1C81, [-6253, 0, -6253]}, + {0x1C82, 0x1C82, [-6244, 0, -6244]}, + {0x1C83, 0x1C84, [-6242, 0, -6242]}, + {0x1C85, 0x1C85, [-6243, 0, -6243]}, + {0x1C86, 0x1C86, [-6236, 0, -6236]}, + {0x1C87, 0x1C87, [-6181, 0, -6181]}, + {0x1C88, 0x1C88, [35266, 0, 35266]}, + {0x1C90, 0x1CBA, [0, -3008, 0]}, + {0x1CBD, 0x1CBF, [0, -3008, 0]}, + {0x1D79, 0x1D79, [35332, 0, 35332]}, + {0x1D7D, 0x1D7D, [3814, 0, 3814]}, + {0x1D8E, 0x1D8E, [35384, 0, 35384]}, + {0x1E00, 0x1E95, [upperLower, upperLower, upperLower]}, + {0x1E9B, 0x1E9B, [-59, 0, -59]}, + {0x1E9E, 0x1E9E, [0, -7615, 0]}, + {0x1EA0, 0x1EFF, [upperLower, upperLower, upperLower]}, + {0x1F00, 0x1F07, [8, 0, 8]}, + {0x1F08, 0x1F0F, [0, -8, 0]}, + {0x1F10, 0x1F15, [8, 0, 8]}, + {0x1F18, 0x1F1D, [0, -8, 0]}, + {0x1F20, 0x1F27, [8, 0, 8]}, + {0x1F28, 0x1F2F, [0, -8, 0]}, + {0x1F30, 0x1F37, [8, 0, 8]}, + {0x1F38, 0x1F3F, [0, -8, 0]}, + {0x1F40, 0x1F45, [8, 0, 8]}, + {0x1F48, 0x1F4D, [0, -8, 0]}, + {0x1F51, 0x1F51, [8, 0, 8]}, + {0x1F53, 0x1F53, [8, 0, 8]}, + {0x1F55, 0x1F55, [8, 0, 8]}, + {0x1F57, 0x1F57, [8, 0, 8]}, + {0x1F59, 0x1F59, [0, -8, 0]}, + {0x1F5B, 0x1F5B, [0, -8, 0]}, + {0x1F5D, 0x1F5D, [0, -8, 0]}, + {0x1F5F, 0x1F5F, [0, -8, 0]}, + {0x1F60, 0x1F67, [8, 0, 8]}, + {0x1F68, 0x1F6F, [0, -8, 0]}, + {0x1F70, 0x1F71, [74, 0, 74]}, + {0x1F72, 0x1F75, [86, 0, 86]}, + {0x1F76, 0x1F77, [100, 0, 100]}, + {0x1F78, 0x1F79, [128, 0, 128]}, + {0x1F7A, 0x1F7B, [112, 0, 112]}, + {0x1F7C, 0x1F7D, [126, 0, 126]}, + {0x1F80, 0x1F87, [8, 0, 8]}, + {0x1F88, 0x1F8F, [0, -8, 0]}, + {0x1F90, 0x1F97, [8, 0, 8]}, + {0x1F98, 0x1F9F, [0, -8, 0]}, + {0x1FA0, 0x1FA7, [8, 0, 8]}, + {0x1FA8, 0x1FAF, [0, -8, 0]}, + {0x1FB0, 0x1FB1, [8, 0, 8]}, + {0x1FB3, 0x1FB3, [9, 0, 9]}, + {0x1FB8, 0x1FB9, [0, -8, 0]}, + {0x1FBA, 0x1FBB, [0, -74, 0]}, + {0x1FBC, 0x1FBC, [0, -9, 0]}, + {0x1FBE, 0x1FBE, [-7205, 0, -7205]}, + {0x1FC3, 0x1FC3, [9, 0, 9]}, + {0x1FC8, 0x1FCB, [0, -86, 0]}, + {0x1FCC, 0x1FCC, [0, -9, 0]}, + {0x1FD0, 0x1FD1, [8, 0, 8]}, + {0x1FD8, 0x1FD9, [0, -8, 0]}, + {0x1FDA, 0x1FDB, [0, -100, 0]}, + {0x1FE0, 0x1FE1, [8, 0, 8]}, + {0x1FE5, 0x1FE5, [7, 0, 7]}, + {0x1FE8, 0x1FE9, [0, -8, 0]}, + {0x1FEA, 0x1FEB, [0, -112, 0]}, + {0x1FEC, 0x1FEC, [0, -7, 0]}, + {0x1FF3, 0x1FF3, [9, 0, 9]}, + {0x1FF8, 0x1FF9, [0, -128, 0]}, + {0x1FFA, 0x1FFB, [0, -126, 0]}, + {0x1FFC, 0x1FFC, [0, -9, 0]}, + {0x2126, 0x2126, [0, -7517, 0]}, + {0x212A, 0x212A, [0, -8383, 0]}, + {0x212B, 0x212B, [0, -8262, 0]}, + {0x2132, 0x2132, [0, 28, 0]}, + {0x214E, 0x214E, [-28, 0, -28]}, + {0x2160, 0x216F, [0, 16, 0]}, + {0x2170, 0x217F, [-16, 0, -16]}, + {0x2183, 0x2184, [upperLower, upperLower, upperLower]}, + {0x24B6, 0x24CF, [0, 26, 0]}, + {0x24D0, 0x24E9, [-26, 0, -26]}, + {0x2C00, 0x2C2F, [0, 48, 0]}, + {0x2C30, 0x2C5F, [-48, 0, -48]}, + {0x2C60, 0x2C61, [upperLower, upperLower, upperLower]}, + {0x2C62, 0x2C62, [0, -10743, 0]}, + {0x2C63, 0x2C63, [0, -3814, 0]}, + {0x2C64, 0x2C64, [0, -10727, 0]}, + {0x2C65, 0x2C65, [-10795, 0, -10795]}, + {0x2C66, 0x2C66, [-10792, 0, -10792]}, + {0x2C67, 0x2C6C, [upperLower, upperLower, upperLower]}, + {0x2C6D, 0x2C6D, [0, -10780, 0]}, + {0x2C6E, 0x2C6E, [0, -10749, 0]}, + {0x2C6F, 0x2C6F, [0, -10783, 0]}, + {0x2C70, 0x2C70, [0, -10782, 0]}, + {0x2C72, 0x2C73, [upperLower, upperLower, upperLower]}, + {0x2C75, 0x2C76, [upperLower, upperLower, upperLower]}, + {0x2C7E, 0x2C7F, [0, -10815, 0]}, + {0x2C80, 0x2CE3, [upperLower, upperLower, upperLower]}, + {0x2CEB, 0x2CEE, [upperLower, upperLower, upperLower]}, + {0x2CF2, 0x2CF3, [upperLower, upperLower, upperLower]}, + {0x2D00, 0x2D25, [-7264, 0, -7264]}, + {0x2D27, 0x2D27, [-7264, 0, -7264]}, + {0x2D2D, 0x2D2D, [-7264, 0, -7264]}, + {0xA640, 0xA66D, [upperLower, upperLower, upperLower]}, + {0xA680, 0xA69B, [upperLower, upperLower, upperLower]}, + {0xA722, 0xA72F, [upperLower, upperLower, upperLower]}, + {0xA732, 0xA76F, [upperLower, upperLower, upperLower]}, + {0xA779, 0xA77C, [upperLower, upperLower, upperLower]}, + {0xA77D, 0xA77D, [0, -35332, 0]}, + {0xA77E, 0xA787, [upperLower, upperLower, upperLower]}, + {0xA78B, 0xA78C, [upperLower, upperLower, upperLower]}, + {0xA78D, 0xA78D, [0, -42280, 0]}, + {0xA790, 0xA793, [upperLower, upperLower, upperLower]}, + {0xA794, 0xA794, [48, 0, 48]}, + {0xA796, 0xA7A9, [upperLower, upperLower, upperLower]}, + {0xA7AA, 0xA7AA, [0, -42308, 0]}, + {0xA7AB, 0xA7AB, [0, -42319, 0]}, + {0xA7AC, 0xA7AC, [0, -42315, 0]}, + {0xA7AD, 0xA7AD, [0, -42305, 0]}, + {0xA7AE, 0xA7AE, [0, -42308, 0]}, + {0xA7B0, 0xA7B0, [0, -42258, 0]}, + {0xA7B1, 0xA7B1, [0, -42282, 0]}, + {0xA7B2, 0xA7B2, [0, -42261, 0]}, + {0xA7B3, 0xA7B3, [0, 928, 0]}, + {0xA7B4, 0xA7C3, [upperLower, upperLower, upperLower]}, + {0xA7C4, 0xA7C4, [0, -48, 0]}, + {0xA7C5, 0xA7C5, [0, -42307, 0]}, + {0xA7C6, 0xA7C6, [0, -35384, 0]}, + {0xA7C7, 0xA7CA, [upperLower, upperLower, upperLower]}, + {0xA7D0, 0xA7D1, [upperLower, upperLower, upperLower]}, + {0xA7D6, 0xA7D9, [upperLower, upperLower, upperLower]}, + {0xA7F5, 0xA7F6, [upperLower, upperLower, upperLower]}, + {0xAB53, 0xAB53, [-928, 0, -928]}, + {0xAB70, 0xABBF, [-38864, 0, -38864]}, + {0xFF21, 0xFF3A, [0, 32, 0]}, + {0xFF41, 0xFF5A, [-32, 0, -32]}, + {0x10400, 0x10427, [0, 40, 0]}, + {0x10428, 0x1044F, [-40, 0, -40]}, + {0x104B0, 0x104D3, [0, 40, 0]}, + {0x104D8, 0x104FB, [-40, 0, -40]}, + {0x10570, 0x1057A, [0, 39, 0]}, + {0x1057C, 0x1058A, [0, 39, 0]}, + {0x1058C, 0x10592, [0, 39, 0]}, + {0x10594, 0x10595, [0, 39, 0]}, + {0x10597, 0x105A1, [-39, 0, -39]}, + {0x105A3, 0x105B1, [-39, 0, -39]}, + {0x105B3, 0x105B9, [-39, 0, -39]}, + {0x105BB, 0x105BC, [-39, 0, -39]}, + {0x10C80, 0x10CB2, [0, 64, 0]}, + {0x10CC0, 0x10CF2, [-64, 0, -64]}, + {0x118A0, 0x118BF, [0, 32, 0]}, + {0x118C0, 0x118DF, [-32, 0, -32]}, + {0x16E40, 0x16E5F, [0, 32, 0]}, + {0x16E60, 0x16E7F, [-32, 0, -32]}, + {0x1E900, 0x1E921, [0, 34, 0]}, + {0x1E922, 0x1E943, [-34, 0, -34]}, ] static _PROPERTIES: [MaxLatin1 + 1]u8 = [ - __P_C, // '\x00' - __P_C, // '\x01' - __P_C, // '\x02' - __P_C, // '\x03' - __P_C, // '\x04' - __P_C, // '\x05' - __P_C, // '\x06' - __P_C, // '\a' - __P_C, // '\b' - __P_C, // '\t' - __P_C, // '\n' - __P_C, // '\v' - __P_C, // '\f' - __P_C, // '\r' - __P_C, // '\x0e' - __P_C, // '\x0f' - __P_C, // '\x10' - __P_C, // '\x11' - __P_C, // '\x12' - __P_C, // '\x13' - __P_C, // '\x14' - __P_C, // '\x15' - __P_C, // '\x16' - __P_C, // '\x17' - __P_C, // '\x18' - __P_C, // '\x19' - __P_C, // '\x1a' - __P_C, // '\x1b' - __P_C, // '\x1c' - __P_C, // '\x1d' - __P_C, // '\x1e' - __P_C, // '\x1f' - __P_Z | __PP, // ' ' - __P_P | __PP, // '!' - __P_P | __PP, // '"' - __P_P | __PP, // '#' - __P_S | __PP, // '$' - __P_P | __PP, // '%' - __P_P | __PP, // '&' - __P_P | __PP, // '\'' - __P_P | __PP, // '(' - __P_P | __PP, // ')' - __P_P | __PP, // '*' - __P_S | __PP, // '+' - __P_P | __PP, // ',' - __P_P | __PP, // '-' - __P_P | __PP, // '.' - __P_P | __PP, // '/' - __P_N | __PP, // '0' - __P_N | __PP, // '1' - __P_N | __PP, // '2' - __P_N | __PP, // '3' - __P_N | __PP, // '4' - __P_N | __PP, // '5' - __P_N | __PP, // '6' - __P_N | __PP, // '7' - __P_N | __PP, // '8' - __P_N | __PP, // '9' - __P_P | __PP, // ':' - __P_P | __PP, // ';' - __P_S | __PP, // '<' - __P_S | __PP, // '=' - __P_S | __PP, // '>' - __P_P | __PP, // '?' - __P_P | __PP, // '@' - __P_LU | __PP, // 'A' - __P_LU | __PP, // 'B' - __P_LU | __PP, // 'C' - __P_LU | __PP, // 'D' - __P_LU | __PP, // 'E' - __P_LU | __PP, // 'F' - __P_LU | __PP, // 'G' - __P_LU | __PP, // 'H' - __P_LU | __PP, // 'I' - __P_LU | __PP, // 'J' - __P_LU | __PP, // 'K' - __P_LU | __PP, // 'L' - __P_LU | __PP, // 'M' - __P_LU | __PP, // 'N' - __P_LU | __PP, // 'O' - __P_LU | __PP, // 'P' - __P_LU | __PP, // 'Q' - __P_LU | __PP, // 'R' - __P_LU | __PP, // 'S' - __P_LU | __PP, // 'T' - __P_LU | __PP, // 'U' - __P_LU | __PP, // 'V' - __P_LU | __PP, // 'W' - __P_LU | __PP, // 'X' - __P_LU | __PP, // 'Y' - __P_LU | __PP, // 'Z' - __P_P | __PP, // '[' - __P_P | __PP, // '\\' - __P_P | __PP, // ']' - __P_S | __PP, // '^' - __P_P | __PP, // '_' - __P_S | __PP, // '`' - __P_LL | __PP, // 'a' - __P_LL | __PP, // 'b' - __P_LL | __PP, // 'c' - __P_LL | __PP, // 'd' - __P_LL | __PP, // 'e' - __P_LL | __PP, // 'f' - __P_LL | __PP, // 'g' - __P_LL | __PP, // 'h' - __P_LL | __PP, // 'i' - __P_LL | __PP, // 'j' - __P_LL | __PP, // 'k' - __P_LL | __PP, // 'l' - __P_LL | __PP, // 'm' - __P_LL | __PP, // 'n' - __P_LL | __PP, // 'o' - __P_LL | __PP, // 'p' - __P_LL | __PP, // 'q' - __P_LL | __PP, // 'r' - __P_LL | __PP, // 's' - __P_LL | __PP, // 't' - __P_LL | __PP, // 'u' - __P_LL | __PP, // 'v' - __P_LL | __PP, // 'w' - __P_LL | __PP, // 'x' - __P_LL | __PP, // 'y' - __P_LL | __PP, // 'z' - __P_P | __PP, // '{' - __P_S | __PP, // '|' - __P_P | __PP, // '}' - __P_S | __PP, // '~' - __P_C, // '\x7f' - __P_C, // '\u0080' - __P_C, // '\u0081' - __P_C, // '\u0082' - __P_C, // '\u0083' - __P_C, // '\u0084' - __P_C, // '\u0085' - __P_C, // '\u0086' - __P_C, // '\u0087' - __P_C, // '\u0088' - __P_C, // '\u0089' - __P_C, // '\u008a' - __P_C, // '\u008b' - __P_C, // '\u008c' - __P_C, // '\u008d' - __P_C, // '\u008e' - __P_C, // '\u008f' - __P_C, // '\u0090' - __P_C, // '\u0091' - __P_C, // '\u0092' - __P_C, // '\u0093' - __P_C, // '\u0094' - __P_C, // '\u0095' - __P_C, // '\u0096' - __P_C, // '\u0097' - __P_C, // '\u0098' - __P_C, // '\u0099' - __P_C, // '\u009a' - __P_C, // '\u009b' - __P_C, // '\u009c' - __P_C, // '\u009d' - __P_C, // '\u009e' - __P_C, // '\u009f' - __P_Z, // '\u00a0' - __P_P | __PP, // '¡' - __P_S | __PP, // '¢' - __P_S | __PP, // '£' - __P_S | __PP, // '¤' - __P_S | __PP, // '¥' - __P_S | __PP, // '¦' - __P_P | __PP, // '§' - __P_S | __PP, // '¨' - __P_S | __PP, // '©' - __P_LO | __PP, // 'ª' - __P_P | __PP, // '«' - __P_S | __PP, // '¬' - 0, // '\u00ad' - __P_S | __PP, // '®' - __P_S | __PP, // '¯' - __P_S | __PP, // '°' - __P_S | __PP, // '±' - __P_N | __PP, // '²' - __P_N | __PP, // '³' - __P_S | __PP, // '´' - __P_LL | __PP, // 'µ' - __P_P | __PP, // '¶' - __P_P | __PP, // '·' - __P_S | __PP, // '¸' - __P_N | __PP, // '¹' - __P_LO | __PP, // 'º' - __P_P | __PP, // '»' - __P_N | __PP, // '¼' - __P_N | __PP, // '½' - __P_N | __PP, // '¾' - __P_P | __PP, // '¿' - __P_LU | __PP, // 'À' - __P_LU | __PP, // 'Á' - __P_LU | __PP, // 'Â' - __P_LU | __PP, // 'Ã' - __P_LU | __PP, // 'Ä' - __P_LU | __PP, // 'Å' - __P_LU | __PP, // 'Æ' - __P_LU | __PP, // 'Ç' - __P_LU | __PP, // 'È' - __P_LU | __PP, // 'É' - __P_LU | __PP, // 'Ê' - __P_LU | __PP, // 'Ë' - __P_LU | __PP, // 'Ì' - __P_LU | __PP, // 'Í' - __P_LU | __PP, // 'Î' - __P_LU | __PP, // 'Ï' - __P_LU | __PP, // 'Ð' - __P_LU | __PP, // 'Ñ' - __P_LU | __PP, // 'Ò' - __P_LU | __PP, // 'Ó' - __P_LU | __PP, // 'Ô' - __P_LU | __PP, // 'Õ' - __P_LU | __PP, // 'Ö' - __P_S | __PP, // '×' - __P_LU | __PP, // 'Ø' - __P_LU | __PP, // 'Ù' - __P_LU | __PP, // 'Ú' - __P_LU | __PP, // 'Û' - __P_LU | __PP, // 'Ü' - __P_LU | __PP, // 'Ý' - __P_LU | __PP, // 'Þ' - __P_LL | __PP, // 'ß' - __P_LL | __PP, // 'à' - __P_LL | __PP, // 'á' - __P_LL | __PP, // 'â' - __P_LL | __PP, // 'ã' - __P_LL | __PP, // 'ä' - __P_LL | __PP, // 'å' - __P_LL | __PP, // 'æ' - __P_LL | __PP, // 'ç' - __P_LL | __PP, // 'è' - __P_LL | __PP, // 'é' - __P_LL | __PP, // 'ê' - __P_LL | __PP, // 'ë' - __P_LL | __PP, // 'ì' - __P_LL | __PP, // 'í' - __P_LL | __PP, // 'î' - __P_LL | __PP, // 'ï' - __P_LL | __PP, // 'ð' - __P_LL | __PP, // 'ñ' - __P_LL | __PP, // 'ò' - __P_LL | __PP, // 'ó' - __P_LL | __PP, // 'ô' - __P_LL | __PP, // 'õ' - __P_LL | __PP, // 'ö' - __P_S | __PP, // '÷' - __P_LL | __PP, // 'ø' - __P_LL | __PP, // 'ù' - __P_LL | __PP, // 'ú' - __P_LL | __PP, // 'û' - __P_LL | __PP, // 'ü' - __P_LL | __PP, // 'ý' - __P_LL | __PP, // 'þ' - __P_LL | __PP, // 'ÿ' + __P_C, // '\x00' + __P_C, // '\x01' + __P_C, // '\x02' + __P_C, // '\x03' + __P_C, // '\x04' + __P_C, // '\x05' + __P_C, // '\x06' + __P_C, // '\a' + __P_C, // '\b' + __P_C, // '\t' + __P_C, // '\n' + __P_C, // '\v' + __P_C, // '\f' + __P_C, // '\r' + __P_C, // '\x0e' + __P_C, // '\x0f' + __P_C, // '\x10' + __P_C, // '\x11' + __P_C, // '\x12' + __P_C, // '\x13' + __P_C, // '\x14' + __P_C, // '\x15' + __P_C, // '\x16' + __P_C, // '\x17' + __P_C, // '\x18' + __P_C, // '\x19' + __P_C, // '\x1a' + __P_C, // '\x1b' + __P_C, // '\x1c' + __P_C, // '\x1d' + __P_C, // '\x1e' + __P_C, // '\x1f' + __P_Z | __PP, // ' ' + __P_P | __PP, // '!' + __P_P | __PP, // '"' + __P_P | __PP, // '#' + __P_S | __PP, // '$' + __P_P | __PP, // '%' + __P_P | __PP, // '&' + __P_P | __PP, // '\'' + __P_P | __PP, // '(' + __P_P | __PP, // ')' + __P_P | __PP, // '*' + __P_S | __PP, // '+' + __P_P | __PP, // ',' + __P_P | __PP, // '-' + __P_P | __PP, // '.' + __P_P | __PP, // '/' + __P_N | __PP, // '0' + __P_N | __PP, // '1' + __P_N | __PP, // '2' + __P_N | __PP, // '3' + __P_N | __PP, // '4' + __P_N | __PP, // '5' + __P_N | __PP, // '6' + __P_N | __PP, // '7' + __P_N | __PP, // '8' + __P_N | __PP, // '9' + __P_P | __PP, // ':' + __P_P | __PP, // ';' + __P_S | __PP, // '<' + __P_S | __PP, // '=' + __P_S | __PP, // '>' + __P_P | __PP, // '?' + __P_P | __PP, // '@' + __P_LU | __PP, // 'A' + __P_LU | __PP, // 'B' + __P_LU | __PP, // 'C' + __P_LU | __PP, // 'D' + __P_LU | __PP, // 'E' + __P_LU | __PP, // 'F' + __P_LU | __PP, // 'G' + __P_LU | __PP, // 'H' + __P_LU | __PP, // 'I' + __P_LU | __PP, // 'J' + __P_LU | __PP, // 'K' + __P_LU | __PP, // 'L' + __P_LU | __PP, // 'M' + __P_LU | __PP, // 'N' + __P_LU | __PP, // 'O' + __P_LU | __PP, // 'P' + __P_LU | __PP, // 'Q' + __P_LU | __PP, // 'R' + __P_LU | __PP, // 'S' + __P_LU | __PP, // 'T' + __P_LU | __PP, // 'U' + __P_LU | __PP, // 'V' + __P_LU | __PP, // 'W' + __P_LU | __PP, // 'X' + __P_LU | __PP, // 'Y' + __P_LU | __PP, // 'Z' + __P_P | __PP, // '[' + __P_P | __PP, // '\\' + __P_P | __PP, // ']' + __P_S | __PP, // '^' + __P_P | __PP, // '_' + __P_S | __PP, // '`' + __P_LL | __PP, // 'a' + __P_LL | __PP, // 'b' + __P_LL | __PP, // 'c' + __P_LL | __PP, // 'd' + __P_LL | __PP, // 'e' + __P_LL | __PP, // 'f' + __P_LL | __PP, // 'g' + __P_LL | __PP, // 'h' + __P_LL | __PP, // 'i' + __P_LL | __PP, // 'j' + __P_LL | __PP, // 'k' + __P_LL | __PP, // 'l' + __P_LL | __PP, // 'm' + __P_LL | __PP, // 'n' + __P_LL | __PP, // 'o' + __P_LL | __PP, // 'p' + __P_LL | __PP, // 'q' + __P_LL | __PP, // 'r' + __P_LL | __PP, // 's' + __P_LL | __PP, // 't' + __P_LL | __PP, // 'u' + __P_LL | __PP, // 'v' + __P_LL | __PP, // 'w' + __P_LL | __PP, // 'x' + __P_LL | __PP, // 'y' + __P_LL | __PP, // 'z' + __P_P | __PP, // '{' + __P_S | __PP, // '|' + __P_P | __PP, // '}' + __P_S | __PP, // '~' + __P_C, // '\x7f' + __P_C, // '\u0080' + __P_C, // '\u0081' + __P_C, // '\u0082' + __P_C, // '\u0083' + __P_C, // '\u0084' + __P_C, // '\u0085' + __P_C, // '\u0086' + __P_C, // '\u0087' + __P_C, // '\u0088' + __P_C, // '\u0089' + __P_C, // '\u008a' + __P_C, // '\u008b' + __P_C, // '\u008c' + __P_C, // '\u008d' + __P_C, // '\u008e' + __P_C, // '\u008f' + __P_C, // '\u0090' + __P_C, // '\u0091' + __P_C, // '\u0092' + __P_C, // '\u0093' + __P_C, // '\u0094' + __P_C, // '\u0095' + __P_C, // '\u0096' + __P_C, // '\u0097' + __P_C, // '\u0098' + __P_C, // '\u0099' + __P_C, // '\u009a' + __P_C, // '\u009b' + __P_C, // '\u009c' + __P_C, // '\u009d' + __P_C, // '\u009e' + __P_C, // '\u009f' + __P_Z, // '\u00a0' + __P_P | __PP, // '¡' + __P_S | __PP, // '¢' + __P_S | __PP, // '£' + __P_S | __PP, // '¤' + __P_S | __PP, // '¥' + __P_S | __PP, // '¦' + __P_P | __PP, // '§' + __P_S | __PP, // '¨' + __P_S | __PP, // '©' + __P_LO | __PP, // 'ª' + __P_P | __PP, // '«' + __P_S | __PP, // '¬' + 0, // '\u00ad' + __P_S | __PP, // '®' + __P_S | __PP, // '¯' + __P_S | __PP, // '°' + __P_S | __PP, // '±' + __P_N | __PP, // '²' + __P_N | __PP, // '³' + __P_S | __PP, // '´' + __P_LL | __PP, // 'µ' + __P_P | __PP, // '¶' + __P_P | __PP, // '·' + __P_S | __PP, // '¸' + __P_N | __PP, // '¹' + __P_LO | __PP, // 'º' + __P_P | __PP, // '»' + __P_N | __PP, // '¼' + __P_N | __PP, // '½' + __P_N | __PP, // '¾' + __P_P | __PP, // '¿' + __P_LU | __PP, // 'À' + __P_LU | __PP, // 'Á' + __P_LU | __PP, // 'Â' + __P_LU | __PP, // 'Ã' + __P_LU | __PP, // 'Ä' + __P_LU | __PP, // 'Å' + __P_LU | __PP, // 'Æ' + __P_LU | __PP, // 'Ç' + __P_LU | __PP, // 'È' + __P_LU | __PP, // 'É' + __P_LU | __PP, // 'Ê' + __P_LU | __PP, // 'Ë' + __P_LU | __PP, // 'Ì' + __P_LU | __PP, // 'Í' + __P_LU | __PP, // 'Î' + __P_LU | __PP, // 'Ï' + __P_LU | __PP, // 'Ð' + __P_LU | __PP, // 'Ñ' + __P_LU | __PP, // 'Ò' + __P_LU | __PP, // 'Ó' + __P_LU | __PP, // 'Ô' + __P_LU | __PP, // 'Õ' + __P_LU | __PP, // 'Ö' + __P_S | __PP, // '×' + __P_LU | __PP, // 'Ø' + __P_LU | __PP, // 'Ù' + __P_LU | __PP, // 'Ú' + __P_LU | __PP, // 'Û' + __P_LU | __PP, // 'Ü' + __P_LU | __PP, // 'Ý' + __P_LU | __PP, // 'Þ' + __P_LL | __PP, // 'ß' + __P_LL | __PP, // 'à' + __P_LL | __PP, // 'á' + __P_LL | __PP, // 'â' + __P_LL | __PP, // 'ã' + __P_LL | __PP, // 'ä' + __P_LL | __PP, // 'å' + __P_LL | __PP, // 'æ' + __P_LL | __PP, // 'ç' + __P_LL | __PP, // 'è' + __P_LL | __PP, // 'é' + __P_LL | __PP, // 'ê' + __P_LL | __PP, // 'ë' + __P_LL | __PP, // 'ì' + __P_LL | __PP, // 'í' + __P_LL | __PP, // 'î' + __P_LL | __PP, // 'ï' + __P_LL | __PP, // 'ð' + __P_LL | __PP, // 'ñ' + __P_LL | __PP, // 'ò' + __P_LL | __PP, // 'ó' + __P_LL | __PP, // 'ô' + __P_LL | __PP, // 'õ' + __P_LL | __PP, // 'ö' + __P_S | __PP, // '÷' + __P_LL | __PP, // 'ø' + __P_LL | __PP, // 'ù' + __P_LL | __PP, // 'ú' + __P_LL | __PP, // 'û' + __P_LL | __PP, // 'ü' + __P_LL | __PP, // 'ý' + __P_LL | __PP, // 'þ' + __P_LL | __PP, // 'ÿ' ] static ASCII_FOLD: [MaxASCII + 1]u16 = [ - 0x0000, - 0x0001, - 0x0002, - 0x0003, - 0x0004, - 0x0005, - 0x0006, - 0x0007, - 0x0008, - 0x0009, - 0x000A, - 0x000B, - 0x000C, - 0x000D, - 0x000E, - 0x000F, - 0x0010, - 0x0011, - 0x0012, - 0x0013, - 0x0014, - 0x0015, - 0x0016, - 0x0017, - 0x0018, - 0x0019, - 0x001A, - 0x001B, - 0x001C, - 0x001D, - 0x001E, - 0x001F, - 0x0020, - 0x0021, - 0x0022, - 0x0023, - 0x0024, - 0x0025, - 0x0026, - 0x0027, - 0x0028, - 0x0029, - 0x002A, - 0x002B, - 0x002C, - 0x002D, - 0x002E, - 0x002F, - 0x0030, - 0x0031, - 0x0032, - 0x0033, - 0x0034, - 0x0035, - 0x0036, - 0x0037, - 0x0038, - 0x0039, - 0x003A, - 0x003B, - 0x003C, - 0x003D, - 0x003E, - 0x003F, - 0x0040, - 0x0061, - 0x0062, - 0x0063, - 0x0064, - 0x0065, - 0x0066, - 0x0067, - 0x0068, - 0x0069, - 0x006A, - 0x006B, - 0x006C, - 0x006D, - 0x006E, - 0x006F, - 0x0070, - 0x0071, - 0x0072, - 0x0073, - 0x0074, - 0x0075, - 0x0076, - 0x0077, - 0x0078, - 0x0079, - 0x007A, - 0x005B, - 0x005C, - 0x005D, - 0x005E, - 0x005F, - 0x0060, - 0x0041, - 0x0042, - 0x0043, - 0x0044, - 0x0045, - 0x0046, - 0x0047, - 0x0048, - 0x0049, - 0x004A, - 0x212A, - 0x004C, - 0x004D, - 0x004E, - 0x004F, - 0x0050, - 0x0051, - 0x0052, - 0x017F, - 0x0054, - 0x0055, - 0x0056, - 0x0057, - 0x0058, - 0x0059, - 0x005A, - 0x007B, - 0x007C, - 0x007D, - 0x007E, - 0x007F, + 0x0000, + 0x0001, + 0x0002, + 0x0003, + 0x0004, + 0x0005, + 0x0006, + 0x0007, + 0x0008, + 0x0009, + 0x000A, + 0x000B, + 0x000C, + 0x000D, + 0x000E, + 0x000F, + 0x0010, + 0x0011, + 0x0012, + 0x0013, + 0x0014, + 0x0015, + 0x0016, + 0x0017, + 0x0018, + 0x0019, + 0x001A, + 0x001B, + 0x001C, + 0x001D, + 0x001E, + 0x001F, + 0x0020, + 0x0021, + 0x0022, + 0x0023, + 0x0024, + 0x0025, + 0x0026, + 0x0027, + 0x0028, + 0x0029, + 0x002A, + 0x002B, + 0x002C, + 0x002D, + 0x002E, + 0x002F, + 0x0030, + 0x0031, + 0x0032, + 0x0033, + 0x0034, + 0x0035, + 0x0036, + 0x0037, + 0x0038, + 0x0039, + 0x003A, + 0x003B, + 0x003C, + 0x003D, + 0x003E, + 0x003F, + 0x0040, + 0x0061, + 0x0062, + 0x0063, + 0x0064, + 0x0065, + 0x0066, + 0x0067, + 0x0068, + 0x0069, + 0x006A, + 0x006B, + 0x006C, + 0x006D, + 0x006E, + 0x006F, + 0x0070, + 0x0071, + 0x0072, + 0x0073, + 0x0074, + 0x0075, + 0x0076, + 0x0077, + 0x0078, + 0x0079, + 0x007A, + 0x005B, + 0x005C, + 0x005D, + 0x005E, + 0x005F, + 0x0060, + 0x0041, + 0x0042, + 0x0043, + 0x0044, + 0x0045, + 0x0046, + 0x0047, + 0x0048, + 0x0049, + 0x004A, + 0x212A, + 0x004C, + 0x004D, + 0x004E, + 0x004F, + 0x0050, + 0x0051, + 0x0052, + 0x017F, + 0x0054, + 0x0055, + 0x0056, + 0x0057, + 0x0058, + 0x0059, + 0x005A, + 0x007B, + 0x007C, + 0x007D, + 0x007E, + 0x007F, ] static CASE_ORBIT: []foldPair = [ - {0x004B, 0x006B}, - {0x0053, 0x0073}, - {0x006B, 0x212A}, - {0x0073, 0x017F}, - {0x00B5, 0x039C}, - {0x00C5, 0x00E5}, - {0x00DF, 0x1E9E}, - {0x00E5, 0x212B}, - {0x0130, 0x0130}, - {0x0131, 0x0131}, - {0x017F, 0x0053}, - {0x01C4, 0x01C5}, - {0x01C5, 0x01C6}, - {0x01C6, 0x01C4}, - {0x01C7, 0x01C8}, - {0x01C8, 0x01C9}, - {0x01C9, 0x01C7}, - {0x01CA, 0x01CB}, - {0x01CB, 0x01CC}, - {0x01CC, 0x01CA}, - {0x01F1, 0x01F2}, - {0x01F2, 0x01F3}, - {0x01F3, 0x01F1}, - {0x0345, 0x0399}, - {0x0392, 0x03B2}, - {0x0395, 0x03B5}, - {0x0398, 0x03B8}, - {0x0399, 0x03B9}, - {0x039A, 0x03BA}, - {0x039C, 0x03BC}, - {0x03A0, 0x03C0}, - {0x03A1, 0x03C1}, - {0x03A3, 0x03C2}, - {0x03A6, 0x03C6}, - {0x03A9, 0x03C9}, - {0x03B2, 0x03D0}, - {0x03B5, 0x03F5}, - {0x03B8, 0x03D1}, - {0x03B9, 0x1FBE}, - {0x03BA, 0x03F0}, - {0x03BC, 0x00B5}, - {0x03C0, 0x03D6}, - {0x03C1, 0x03F1}, - {0x03C2, 0x03C3}, - {0x03C3, 0x03A3}, - {0x03C6, 0x03D5}, - {0x03C9, 0x2126}, - {0x03D0, 0x0392}, - {0x03D1, 0x03F4}, - {0x03D5, 0x03A6}, - {0x03D6, 0x03A0}, - {0x03F0, 0x039A}, - {0x03F1, 0x03A1}, - {0x03F4, 0x0398}, - {0x03F5, 0x0395}, - {0x0412, 0x0432}, - {0x0414, 0x0434}, - {0x041E, 0x043E}, - {0x0421, 0x0441}, - {0x0422, 0x0442}, - {0x042A, 0x044A}, - {0x0432, 0x1C80}, - {0x0434, 0x1C81}, - {0x043E, 0x1C82}, - {0x0441, 0x1C83}, - {0x0442, 0x1C84}, - {0x044A, 0x1C86}, - {0x0462, 0x0463}, - {0x0463, 0x1C87}, - {0x1C80, 0x0412}, - {0x1C81, 0x0414}, - {0x1C82, 0x041E}, - {0x1C83, 0x0421}, - {0x1C84, 0x1C85}, - {0x1C85, 0x0422}, - {0x1C86, 0x042A}, - {0x1C87, 0x0462}, - {0x1C88, 0xA64A}, - {0x1E60, 0x1E61}, - {0x1E61, 0x1E9B}, - {0x1E9B, 0x1E60}, - {0x1E9E, 0x00DF}, - {0x1FBE, 0x0345}, - {0x2126, 0x03A9}, - {0x212A, 0x004B}, - {0x212B, 0x00C5}, - {0xA64A, 0xA64B}, - {0xA64B, 0x1C88}, + {0x004B, 0x006B}, + {0x0053, 0x0073}, + {0x006B, 0x212A}, + {0x0073, 0x017F}, + {0x00B5, 0x039C}, + {0x00C5, 0x00E5}, + {0x00DF, 0x1E9E}, + {0x00E5, 0x212B}, + {0x0130, 0x0130}, + {0x0131, 0x0131}, + {0x017F, 0x0053}, + {0x01C4, 0x01C5}, + {0x01C5, 0x01C6}, + {0x01C6, 0x01C4}, + {0x01C7, 0x01C8}, + {0x01C8, 0x01C9}, + {0x01C9, 0x01C7}, + {0x01CA, 0x01CB}, + {0x01CB, 0x01CC}, + {0x01CC, 0x01CA}, + {0x01F1, 0x01F2}, + {0x01F2, 0x01F3}, + {0x01F3, 0x01F1}, + {0x0345, 0x0399}, + {0x0392, 0x03B2}, + {0x0395, 0x03B5}, + {0x0398, 0x03B8}, + {0x0399, 0x03B9}, + {0x039A, 0x03BA}, + {0x039C, 0x03BC}, + {0x03A0, 0x03C0}, + {0x03A1, 0x03C1}, + {0x03A3, 0x03C2}, + {0x03A6, 0x03C6}, + {0x03A9, 0x03C9}, + {0x03B2, 0x03D0}, + {0x03B5, 0x03F5}, + {0x03B8, 0x03D1}, + {0x03B9, 0x1FBE}, + {0x03BA, 0x03F0}, + {0x03BC, 0x00B5}, + {0x03C0, 0x03D6}, + {0x03C1, 0x03F1}, + {0x03C2, 0x03C3}, + {0x03C3, 0x03A3}, + {0x03C6, 0x03D5}, + {0x03C9, 0x2126}, + {0x03D0, 0x0392}, + {0x03D1, 0x03F4}, + {0x03D5, 0x03A6}, + {0x03D6, 0x03A0}, + {0x03F0, 0x039A}, + {0x03F1, 0x03A1}, + {0x03F4, 0x0398}, + {0x03F5, 0x0395}, + {0x0412, 0x0432}, + {0x0414, 0x0434}, + {0x041E, 0x043E}, + {0x0421, 0x0441}, + {0x0422, 0x0442}, + {0x042A, 0x044A}, + {0x0432, 0x1C80}, + {0x0434, 0x1C81}, + {0x043E, 0x1C82}, + {0x0441, 0x1C83}, + {0x0442, 0x1C84}, + {0x044A, 0x1C86}, + {0x0462, 0x0463}, + {0x0463, 0x1C87}, + {0x1C80, 0x0412}, + {0x1C81, 0x0414}, + {0x1C82, 0x041E}, + {0x1C83, 0x0421}, + {0x1C84, 0x1C85}, + {0x1C85, 0x0422}, + {0x1C86, 0x042A}, + {0x1C87, 0x0462}, + {0x1C88, 0xA64A}, + {0x1E60, 0x1E61}, + {0x1E61, 0x1E9B}, + {0x1E9B, 0x1E60}, + {0x1E9E, 0x00DF}, + {0x1FBE, 0x0345}, + {0x2126, 0x03A9}, + {0x212A, 0x004B}, + {0x212B, 0x00C5}, + {0xA64A, 0xA64B}, + {0xA64B, 0x1C88}, ] // Maps a category name to a table of @@ -8070,299 +8070,299 @@ static CASE_ORBIT: []foldPair = [ // simple case folding to code points inside the category. // If there is NO entry for a category name, there are NO such points. static FoldCategory: map[str]&RangeTable = { - "L": FOLD_L, - "LL": FOLD_LL, - "LT": FOLD_LT, - "LU": FOLD_LU, - "M": FOLD_M, - "MN": FOLD_MN, + "L": FOLD_L, + "LL": FOLD_LL, + "LT": FOLD_LT, + "LU": FOLD_LU, + "M": FOLD_M, + "MN": FOLD_MN, } static FOLD_L = &RangeTable{ - R16: [ - {0x0345, 0x0345, 1}, - ], + R16: [ + {0x0345, 0x0345, 1}, + ], } static FOLD_LL = &RangeTable{ - R16: [ - {0x0041, 0x005a, 1}, - {0x00c0, 0x00d6, 1}, - {0x00d8, 0x00de, 1}, - {0x0100, 0x012e, 2}, - {0x0132, 0x0136, 2}, - {0x0139, 0x0147, 2}, - {0x014a, 0x0178, 2}, - {0x0179, 0x017d, 2}, - {0x0181, 0x0182, 1}, - {0x0184, 0x0186, 2}, - {0x0187, 0x0189, 2}, - {0x018a, 0x018b, 1}, - {0x018e, 0x0191, 1}, - {0x0193, 0x0194, 1}, - {0x0196, 0x0198, 1}, - {0x019c, 0x019d, 1}, - {0x019f, 0x01a0, 1}, - {0x01a2, 0x01a6, 2}, - {0x01a7, 0x01a9, 2}, - {0x01ac, 0x01ae, 2}, - {0x01af, 0x01b1, 2}, - {0x01b2, 0x01b3, 1}, - {0x01b5, 0x01b7, 2}, - {0x01b8, 0x01bc, 4}, - {0x01c4, 0x01c5, 1}, - {0x01c7, 0x01c8, 1}, - {0x01ca, 0x01cb, 1}, - {0x01cd, 0x01db, 2}, - {0x01de, 0x01ee, 2}, - {0x01f1, 0x01f2, 1}, - {0x01f4, 0x01f6, 2}, - {0x01f7, 0x01f8, 1}, - {0x01fa, 0x0232, 2}, - {0x023a, 0x023b, 1}, - {0x023d, 0x023e, 1}, - {0x0241, 0x0243, 2}, - {0x0244, 0x0246, 1}, - {0x0248, 0x024e, 2}, - {0x0345, 0x0370, 43}, - {0x0372, 0x0376, 4}, - {0x037f, 0x0386, 7}, - {0x0388, 0x038a, 1}, - {0x038c, 0x038e, 2}, - {0x038f, 0x0391, 2}, - {0x0392, 0x03a1, 1}, - {0x03a3, 0x03ab, 1}, - {0x03cf, 0x03d8, 9}, - {0x03da, 0x03ee, 2}, - {0x03f4, 0x03f7, 3}, - {0x03f9, 0x03fa, 1}, - {0x03fd, 0x042f, 1}, - {0x0460, 0x0480, 2}, - {0x048a, 0x04c0, 2}, - {0x04c1, 0x04cd, 2}, - {0x04d0, 0x052e, 2}, - {0x0531, 0x0556, 1}, - {0x10a0, 0x10c5, 1}, - {0x10c7, 0x10cd, 6}, - {0x13a0, 0x13f5, 1}, - {0x1c90, 0x1cba, 1}, - {0x1cbd, 0x1cbf, 1}, - {0x1e00, 0x1e94, 2}, - {0x1e9e, 0x1efe, 2}, - {0x1f08, 0x1f0f, 1}, - {0x1f18, 0x1f1d, 1}, - {0x1f28, 0x1f2f, 1}, - {0x1f38, 0x1f3f, 1}, - {0x1f48, 0x1f4d, 1}, - {0x1f59, 0x1f5f, 2}, - {0x1f68, 0x1f6f, 1}, - {0x1f88, 0x1f8f, 1}, - {0x1f98, 0x1f9f, 1}, - {0x1fa8, 0x1faf, 1}, - {0x1fb8, 0x1fbc, 1}, - {0x1fc8, 0x1fcc, 1}, - {0x1fd8, 0x1fdb, 1}, - {0x1fe8, 0x1fec, 1}, - {0x1ff8, 0x1ffc, 1}, - {0x2126, 0x212a, 4}, - {0x212b, 0x2132, 7}, - {0x2183, 0x2c00, 2685}, - {0x2c01, 0x2c2f, 1}, - {0x2c60, 0x2c62, 2}, - {0x2c63, 0x2c64, 1}, - {0x2c67, 0x2c6d, 2}, - {0x2c6e, 0x2c70, 1}, - {0x2c72, 0x2c75, 3}, - {0x2c7e, 0x2c80, 1}, - {0x2c82, 0x2ce2, 2}, - {0x2ceb, 0x2ced, 2}, - {0x2cf2, 0xa640, 31054}, - {0xa642, 0xa66c, 2}, - {0xa680, 0xa69a, 2}, - {0xa722, 0xa72e, 2}, - {0xa732, 0xa76e, 2}, - {0xa779, 0xa77d, 2}, - {0xa77e, 0xa786, 2}, - {0xa78b, 0xa78d, 2}, - {0xa790, 0xa792, 2}, - {0xa796, 0xa7aa, 2}, - {0xa7ab, 0xa7ae, 1}, - {0xa7b0, 0xa7b4, 1}, - {0xa7b6, 0xa7c4, 2}, - {0xa7c5, 0xa7c7, 1}, - {0xa7c9, 0xa7d0, 7}, - {0xa7d6, 0xa7d8, 2}, - {0xa7f5, 0xff21, 22316}, - {0xff22, 0xff3a, 1}, - ], - R32: [ - {0x10400, 0x10427, 1}, - {0x104b0, 0x104d3, 1}, - {0x10570, 0x1057a, 1}, - {0x1057c, 0x1058a, 1}, - {0x1058c, 0x10592, 1}, - {0x10594, 0x10595, 1}, - {0x10c80, 0x10cb2, 1}, - {0x118a0, 0x118bf, 1}, - {0x16e40, 0x16e5f, 1}, - {0x1e900, 0x1e921, 1}, - ], - LatinOffset: 3, + R16: [ + {0x0041, 0x005a, 1}, + {0x00c0, 0x00d6, 1}, + {0x00d8, 0x00de, 1}, + {0x0100, 0x012e, 2}, + {0x0132, 0x0136, 2}, + {0x0139, 0x0147, 2}, + {0x014a, 0x0178, 2}, + {0x0179, 0x017d, 2}, + {0x0181, 0x0182, 1}, + {0x0184, 0x0186, 2}, + {0x0187, 0x0189, 2}, + {0x018a, 0x018b, 1}, + {0x018e, 0x0191, 1}, + {0x0193, 0x0194, 1}, + {0x0196, 0x0198, 1}, + {0x019c, 0x019d, 1}, + {0x019f, 0x01a0, 1}, + {0x01a2, 0x01a6, 2}, + {0x01a7, 0x01a9, 2}, + {0x01ac, 0x01ae, 2}, + {0x01af, 0x01b1, 2}, + {0x01b2, 0x01b3, 1}, + {0x01b5, 0x01b7, 2}, + {0x01b8, 0x01bc, 4}, + {0x01c4, 0x01c5, 1}, + {0x01c7, 0x01c8, 1}, + {0x01ca, 0x01cb, 1}, + {0x01cd, 0x01db, 2}, + {0x01de, 0x01ee, 2}, + {0x01f1, 0x01f2, 1}, + {0x01f4, 0x01f6, 2}, + {0x01f7, 0x01f8, 1}, + {0x01fa, 0x0232, 2}, + {0x023a, 0x023b, 1}, + {0x023d, 0x023e, 1}, + {0x0241, 0x0243, 2}, + {0x0244, 0x0246, 1}, + {0x0248, 0x024e, 2}, + {0x0345, 0x0370, 43}, + {0x0372, 0x0376, 4}, + {0x037f, 0x0386, 7}, + {0x0388, 0x038a, 1}, + {0x038c, 0x038e, 2}, + {0x038f, 0x0391, 2}, + {0x0392, 0x03a1, 1}, + {0x03a3, 0x03ab, 1}, + {0x03cf, 0x03d8, 9}, + {0x03da, 0x03ee, 2}, + {0x03f4, 0x03f7, 3}, + {0x03f9, 0x03fa, 1}, + {0x03fd, 0x042f, 1}, + {0x0460, 0x0480, 2}, + {0x048a, 0x04c0, 2}, + {0x04c1, 0x04cd, 2}, + {0x04d0, 0x052e, 2}, + {0x0531, 0x0556, 1}, + {0x10a0, 0x10c5, 1}, + {0x10c7, 0x10cd, 6}, + {0x13a0, 0x13f5, 1}, + {0x1c90, 0x1cba, 1}, + {0x1cbd, 0x1cbf, 1}, + {0x1e00, 0x1e94, 2}, + {0x1e9e, 0x1efe, 2}, + {0x1f08, 0x1f0f, 1}, + {0x1f18, 0x1f1d, 1}, + {0x1f28, 0x1f2f, 1}, + {0x1f38, 0x1f3f, 1}, + {0x1f48, 0x1f4d, 1}, + {0x1f59, 0x1f5f, 2}, + {0x1f68, 0x1f6f, 1}, + {0x1f88, 0x1f8f, 1}, + {0x1f98, 0x1f9f, 1}, + {0x1fa8, 0x1faf, 1}, + {0x1fb8, 0x1fbc, 1}, + {0x1fc8, 0x1fcc, 1}, + {0x1fd8, 0x1fdb, 1}, + {0x1fe8, 0x1fec, 1}, + {0x1ff8, 0x1ffc, 1}, + {0x2126, 0x212a, 4}, + {0x212b, 0x2132, 7}, + {0x2183, 0x2c00, 2685}, + {0x2c01, 0x2c2f, 1}, + {0x2c60, 0x2c62, 2}, + {0x2c63, 0x2c64, 1}, + {0x2c67, 0x2c6d, 2}, + {0x2c6e, 0x2c70, 1}, + {0x2c72, 0x2c75, 3}, + {0x2c7e, 0x2c80, 1}, + {0x2c82, 0x2ce2, 2}, + {0x2ceb, 0x2ced, 2}, + {0x2cf2, 0xa640, 31054}, + {0xa642, 0xa66c, 2}, + {0xa680, 0xa69a, 2}, + {0xa722, 0xa72e, 2}, + {0xa732, 0xa76e, 2}, + {0xa779, 0xa77d, 2}, + {0xa77e, 0xa786, 2}, + {0xa78b, 0xa78d, 2}, + {0xa790, 0xa792, 2}, + {0xa796, 0xa7aa, 2}, + {0xa7ab, 0xa7ae, 1}, + {0xa7b0, 0xa7b4, 1}, + {0xa7b6, 0xa7c4, 2}, + {0xa7c5, 0xa7c7, 1}, + {0xa7c9, 0xa7d0, 7}, + {0xa7d6, 0xa7d8, 2}, + {0xa7f5, 0xff21, 22316}, + {0xff22, 0xff3a, 1}, + ], + R32: [ + {0x10400, 0x10427, 1}, + {0x104b0, 0x104d3, 1}, + {0x10570, 0x1057a, 1}, + {0x1057c, 0x1058a, 1}, + {0x1058c, 0x10592, 1}, + {0x10594, 0x10595, 1}, + {0x10c80, 0x10cb2, 1}, + {0x118a0, 0x118bf, 1}, + {0x16e40, 0x16e5f, 1}, + {0x1e900, 0x1e921, 1}, + ], + LatinOffset: 3, } static FOLD_LT = &RangeTable{ - R16: [ - {0x01c4, 0x01c6, 2}, - {0x01c7, 0x01c9, 2}, - {0x01ca, 0x01cc, 2}, - {0x01f1, 0x01f3, 2}, - {0x1f80, 0x1f87, 1}, - {0x1f90, 0x1f97, 1}, - {0x1fa0, 0x1fa7, 1}, - {0x1fb3, 0x1fc3, 16}, - {0x1ff3, 0x1ff3, 1}, - ], + R16: [ + {0x01c4, 0x01c6, 2}, + {0x01c7, 0x01c9, 2}, + {0x01ca, 0x01cc, 2}, + {0x01f1, 0x01f3, 2}, + {0x1f80, 0x1f87, 1}, + {0x1f90, 0x1f97, 1}, + {0x1fa0, 0x1fa7, 1}, + {0x1fb3, 0x1fc3, 16}, + {0x1ff3, 0x1ff3, 1}, + ], } static FOLD_LU = &RangeTable{ - R16: [ - {0x0061, 0x007a, 1}, - {0x00b5, 0x00df, 42}, - {0x00e0, 0x00f6, 1}, - {0x00f8, 0x00ff, 1}, - {0x0101, 0x012f, 2}, - {0x0133, 0x0137, 2}, - {0x013a, 0x0148, 2}, - {0x014b, 0x0177, 2}, - {0x017a, 0x017e, 2}, - {0x017f, 0x0180, 1}, - {0x0183, 0x0185, 2}, - {0x0188, 0x018c, 4}, - {0x0192, 0x0195, 3}, - {0x0199, 0x019a, 1}, - {0x019e, 0x01a1, 3}, - {0x01a3, 0x01a5, 2}, - {0x01a8, 0x01ad, 5}, - {0x01b0, 0x01b4, 4}, - {0x01b6, 0x01b9, 3}, - {0x01bd, 0x01bf, 2}, - {0x01c5, 0x01c6, 1}, - {0x01c8, 0x01c9, 1}, - {0x01cb, 0x01cc, 1}, - {0x01ce, 0x01dc, 2}, - {0x01dd, 0x01ef, 2}, - {0x01f2, 0x01f3, 1}, - {0x01f5, 0x01f9, 4}, - {0x01fb, 0x021f, 2}, - {0x0223, 0x0233, 2}, - {0x023c, 0x023f, 3}, - {0x0240, 0x0242, 2}, - {0x0247, 0x024f, 2}, - {0x0250, 0x0254, 1}, - {0x0256, 0x0257, 1}, - {0x0259, 0x025b, 2}, - {0x025c, 0x0260, 4}, - {0x0261, 0x0265, 2}, - {0x0266, 0x0268, 2}, - {0x0269, 0x026c, 1}, - {0x026f, 0x0271, 2}, - {0x0272, 0x0275, 3}, - {0x027d, 0x0280, 3}, - {0x0282, 0x0283, 1}, - {0x0287, 0x028c, 1}, - {0x0292, 0x029d, 11}, - {0x029e, 0x0345, 167}, - {0x0371, 0x0373, 2}, - {0x0377, 0x037b, 4}, - {0x037c, 0x037d, 1}, - {0x03ac, 0x03af, 1}, - {0x03b1, 0x03ce, 1}, - {0x03d0, 0x03d1, 1}, - {0x03d5, 0x03d7, 1}, - {0x03d9, 0x03ef, 2}, - {0x03f0, 0x03f3, 1}, - {0x03f5, 0x03fb, 3}, - {0x0430, 0x045f, 1}, - {0x0461, 0x0481, 2}, - {0x048b, 0x04bf, 2}, - {0x04c2, 0x04ce, 2}, - {0x04cf, 0x052f, 2}, - {0x0561, 0x0586, 1}, - {0x10d0, 0x10fa, 1}, - {0x10fd, 0x10ff, 1}, - {0x13f8, 0x13fd, 1}, - {0x1c80, 0x1c88, 1}, - {0x1d79, 0x1d7d, 4}, - {0x1d8e, 0x1e01, 115}, - {0x1e03, 0x1e95, 2}, - {0x1e9b, 0x1ea1, 6}, - {0x1ea3, 0x1eff, 2}, - {0x1f00, 0x1f07, 1}, - {0x1f10, 0x1f15, 1}, - {0x1f20, 0x1f27, 1}, - {0x1f30, 0x1f37, 1}, - {0x1f40, 0x1f45, 1}, - {0x1f51, 0x1f57, 2}, - {0x1f60, 0x1f67, 1}, - {0x1f70, 0x1f7d, 1}, - {0x1fb0, 0x1fb1, 1}, - {0x1fbe, 0x1fd0, 18}, - {0x1fd1, 0x1fe0, 15}, - {0x1fe1, 0x1fe5, 4}, - {0x214e, 0x2184, 54}, - {0x2c30, 0x2c5f, 1}, - {0x2c61, 0x2c65, 4}, - {0x2c66, 0x2c6c, 2}, - {0x2c73, 0x2c76, 3}, - {0x2c81, 0x2ce3, 2}, - {0x2cec, 0x2cee, 2}, - {0x2cf3, 0x2d00, 13}, - {0x2d01, 0x2d25, 1}, - {0x2d27, 0x2d2d, 6}, - {0xa641, 0xa66d, 2}, - {0xa681, 0xa69b, 2}, - {0xa723, 0xa72f, 2}, - {0xa733, 0xa76f, 2}, - {0xa77a, 0xa77c, 2}, - {0xa77f, 0xa787, 2}, - {0xa78c, 0xa791, 5}, - {0xa793, 0xa794, 1}, - {0xa797, 0xa7a9, 2}, - {0xa7b5, 0xa7c3, 2}, - {0xa7c8, 0xa7ca, 2}, - {0xa7d1, 0xa7d7, 6}, - {0xa7d9, 0xa7f6, 29}, - {0xab53, 0xab70, 29}, - {0xab71, 0xabbf, 1}, - {0xff41, 0xff5a, 1}, - ], - R32: [ - {0x10428, 0x1044f, 1}, - {0x104d8, 0x104fb, 1}, - {0x10597, 0x105a1, 1}, - {0x105a3, 0x105b1, 1}, - {0x105b3, 0x105b9, 1}, - {0x105bb, 0x105bc, 1}, - {0x10cc0, 0x10cf2, 1}, - {0x118c0, 0x118df, 1}, - {0x16e60, 0x16e7f, 1}, - {0x1e922, 0x1e943, 1}, - ], - LatinOffset: 4, + R16: [ + {0x0061, 0x007a, 1}, + {0x00b5, 0x00df, 42}, + {0x00e0, 0x00f6, 1}, + {0x00f8, 0x00ff, 1}, + {0x0101, 0x012f, 2}, + {0x0133, 0x0137, 2}, + {0x013a, 0x0148, 2}, + {0x014b, 0x0177, 2}, + {0x017a, 0x017e, 2}, + {0x017f, 0x0180, 1}, + {0x0183, 0x0185, 2}, + {0x0188, 0x018c, 4}, + {0x0192, 0x0195, 3}, + {0x0199, 0x019a, 1}, + {0x019e, 0x01a1, 3}, + {0x01a3, 0x01a5, 2}, + {0x01a8, 0x01ad, 5}, + {0x01b0, 0x01b4, 4}, + {0x01b6, 0x01b9, 3}, + {0x01bd, 0x01bf, 2}, + {0x01c5, 0x01c6, 1}, + {0x01c8, 0x01c9, 1}, + {0x01cb, 0x01cc, 1}, + {0x01ce, 0x01dc, 2}, + {0x01dd, 0x01ef, 2}, + {0x01f2, 0x01f3, 1}, + {0x01f5, 0x01f9, 4}, + {0x01fb, 0x021f, 2}, + {0x0223, 0x0233, 2}, + {0x023c, 0x023f, 3}, + {0x0240, 0x0242, 2}, + {0x0247, 0x024f, 2}, + {0x0250, 0x0254, 1}, + {0x0256, 0x0257, 1}, + {0x0259, 0x025b, 2}, + {0x025c, 0x0260, 4}, + {0x0261, 0x0265, 2}, + {0x0266, 0x0268, 2}, + {0x0269, 0x026c, 1}, + {0x026f, 0x0271, 2}, + {0x0272, 0x0275, 3}, + {0x027d, 0x0280, 3}, + {0x0282, 0x0283, 1}, + {0x0287, 0x028c, 1}, + {0x0292, 0x029d, 11}, + {0x029e, 0x0345, 167}, + {0x0371, 0x0373, 2}, + {0x0377, 0x037b, 4}, + {0x037c, 0x037d, 1}, + {0x03ac, 0x03af, 1}, + {0x03b1, 0x03ce, 1}, + {0x03d0, 0x03d1, 1}, + {0x03d5, 0x03d7, 1}, + {0x03d9, 0x03ef, 2}, + {0x03f0, 0x03f3, 1}, + {0x03f5, 0x03fb, 3}, + {0x0430, 0x045f, 1}, + {0x0461, 0x0481, 2}, + {0x048b, 0x04bf, 2}, + {0x04c2, 0x04ce, 2}, + {0x04cf, 0x052f, 2}, + {0x0561, 0x0586, 1}, + {0x10d0, 0x10fa, 1}, + {0x10fd, 0x10ff, 1}, + {0x13f8, 0x13fd, 1}, + {0x1c80, 0x1c88, 1}, + {0x1d79, 0x1d7d, 4}, + {0x1d8e, 0x1e01, 115}, + {0x1e03, 0x1e95, 2}, + {0x1e9b, 0x1ea1, 6}, + {0x1ea3, 0x1eff, 2}, + {0x1f00, 0x1f07, 1}, + {0x1f10, 0x1f15, 1}, + {0x1f20, 0x1f27, 1}, + {0x1f30, 0x1f37, 1}, + {0x1f40, 0x1f45, 1}, + {0x1f51, 0x1f57, 2}, + {0x1f60, 0x1f67, 1}, + {0x1f70, 0x1f7d, 1}, + {0x1fb0, 0x1fb1, 1}, + {0x1fbe, 0x1fd0, 18}, + {0x1fd1, 0x1fe0, 15}, + {0x1fe1, 0x1fe5, 4}, + {0x214e, 0x2184, 54}, + {0x2c30, 0x2c5f, 1}, + {0x2c61, 0x2c65, 4}, + {0x2c66, 0x2c6c, 2}, + {0x2c73, 0x2c76, 3}, + {0x2c81, 0x2ce3, 2}, + {0x2cec, 0x2cee, 2}, + {0x2cf3, 0x2d00, 13}, + {0x2d01, 0x2d25, 1}, + {0x2d27, 0x2d2d, 6}, + {0xa641, 0xa66d, 2}, + {0xa681, 0xa69b, 2}, + {0xa723, 0xa72f, 2}, + {0xa733, 0xa76f, 2}, + {0xa77a, 0xa77c, 2}, + {0xa77f, 0xa787, 2}, + {0xa78c, 0xa791, 5}, + {0xa793, 0xa794, 1}, + {0xa797, 0xa7a9, 2}, + {0xa7b5, 0xa7c3, 2}, + {0xa7c8, 0xa7ca, 2}, + {0xa7d1, 0xa7d7, 6}, + {0xa7d9, 0xa7f6, 29}, + {0xab53, 0xab70, 29}, + {0xab71, 0xabbf, 1}, + {0xff41, 0xff5a, 1}, + ], + R32: [ + {0x10428, 0x1044f, 1}, + {0x104d8, 0x104fb, 1}, + {0x10597, 0x105a1, 1}, + {0x105a3, 0x105b1, 1}, + {0x105b3, 0x105b9, 1}, + {0x105bb, 0x105bc, 1}, + {0x10cc0, 0x10cf2, 1}, + {0x118c0, 0x118df, 1}, + {0x16e60, 0x16e7f, 1}, + {0x1e922, 0x1e943, 1}, + ], + LatinOffset: 4, } static FOLD_M = &RangeTable{ - R16: [ - {0x0399, 0x03b9, 32}, - {0x1fbe, 0x1fbe, 1}, - ], + R16: [ + {0x0399, 0x03b9, 32}, + {0x1fbe, 0x1fbe, 1}, + ], } static FOLD_MN = &RangeTable{ - R16: [ - {0x0399, 0x03b9, 32}, - {0x1fbe, 0x1fbe, 1}, - ], + R16: [ + {0x0399, 0x03b9, 32}, + {0x1fbe, 0x1fbe, 1}, + ], } // Maps a script name to a table of @@ -8370,26 +8370,26 @@ static FOLD_MN = &RangeTable{ // simple case folding to code points inside the script. // If there is NO entry for a script name, there are NO such points. static FoldScript: map[str]&RangeTable = { - "Common": FOLD_COMMON, - "Greek": FOLD_GREEK, - "Inherited": FOLD_INHERITED, + "Common": FOLD_COMMON, + "Greek": FOLD_GREEK, + "Inherited": FOLD_INHERITED, } static FOLD_COMMON = &RangeTable{ - R16: [ - {0x039c, 0x03bc, 32}, - ], + R16: [ + {0x039c, 0x03bc, 32}, + ], } static FOLD_GREEK = &RangeTable{ - R16: [ - {0x00b5, 0x0345, 656}, - ], + R16: [ + {0x00b5, 0x0345, 656}, + ], } static FOLD_INHERITED = &RangeTable{ - R16: [ - {0x0399, 0x03b9, 32}, - {0x1fbe, 0x1fbe, 1}, - ], + R16: [ + {0x0399, 0x03b9, 32}, + {0x1fbe, 0x1fbe, 1}, + ], } \ No newline at end of file diff --git a/std/unicode/utf16/utf16.jule b/std/unicode/utf16/utf16.jule index f89616a6a..11daad8db 100644 --- a/std/unicode/utf16/utf16.jule +++ b/std/unicode/utf16/utf16.jule @@ -59,102 +59,102 @@ const surrSelf = 0x10000 // Reports whether the specified Unicode code point // can appear in a surrogate pair. fn IsSurrogate(r: rune): bool { - ret surr1 <= r && r < surr3 + ret surr1 <= r && r < surr3 } // Returns the UTF-16 decoding of a surrogate pair. // If the pair is not a valid UTF-16 surrogate pair, DecodeRune returns // the Unicode replacement code point U+FFFD. fn DecodeRune(r1: rune, r2: rune): rune { - if surr1 <= r1 && r1 < surr2 && surr2 <= r2 && r2 < surr3 { - ret (r1 - surr1) << 10 | (r2 - surr2) + surrSelf - } - ret replacementChar + if surr1 <= r1 && r1 < surr2 && surr2 <= r2 && r2 < surr3 { + ret (r1 - surr1) << 10 | (r2 - surr2) + surrSelf + } + ret replacementChar } // Returns the UTF-16 surrogate pair r1, r2 for the given rune. // If the rune is not a valid Unicode code point or does not need encoding, // encode_rune returns U+FFFD, U+FFFD. fn EncodeRune(mut r: rune): (r1: rune, r2: rune) { - if r < surrSelf || r > MaxRune { - ret replacementChar, replacementChar - } - r -= surrSelf - ret surr1 + (r >> 10) & 0x3ff, surr2 + r & 0x3ff + if r < surrSelf || r > MaxRune { + ret replacementChar, replacementChar + } + r -= surrSelf + ret surr1 + (r >> 10) & 0x3ff, surr2 + r & 0x3ff } // Returns the UTF-16 encoding of the Unicode code point sequence s. fn Encode(s: []rune): []u16 { - mut n := len(s) - for _, v in s { - if v >= surrSelf { - n++ - } - } + mut n := len(s) + for _, v in s { + if v >= surrSelf { + n++ + } + } - mut a := make([]u16, n) - n = 0 - for _, v in s { - match { - | 0 <= v && v < surr1 | surr3 <= v && v < surrSelf: - // normal rune - a[n] = u16(v) - n++ - | surrSelf <= v && v <= MaxRune: - // needs surrogate sequence - r1, r2 := EncodeRune(v) - a[n] = u16(r1) - a[n+1] = u16(r2) - n += 2 - |: - a[n] = u16(replacementChar) - n++ - } - } - ret a[:n] + mut a := make([]u16, n) + n = 0 + for _, v in s { + match { + | 0 <= v && v < surr1 | surr3 <= v && v < surrSelf: + // normal rune + a[n] = u16(v) + n++ + | surrSelf <= v && v <= MaxRune: + // needs surrogate sequence + r1, r2 := EncodeRune(v) + a[n] = u16(r1) + a[n+1] = u16(r2) + n += 2 + |: + a[n] = u16(replacementChar) + n++ + } + } + ret a[:n] } // Returns the Unicode code point sequence // represented by the UTF-16 encoding s. fn Decode(s: []u16): []rune { - mut a := make([]rune, len(s)) - mut n := 0 - mut i := 0 - for i < len(s); i++ { - r := s[i] - match { - | r < surr1 | surr3 <= r: - // normal rune - a[n] = rune(r) - | r < surr2 && i+1 < len(s) && surr2 <= s[i+1] && s[i+1] < surr3: - // This case requires r >= SURR1 condition is true. - // Previous case checks this condition already. - // Therefore this case will not check this. + mut a := make([]rune, len(s)) + mut n := 0 + mut i := 0 + for i < len(s); i++ { + r := s[i] + match { + | r < surr1 | surr3 <= r: + // normal rune + a[n] = rune(r) + | r < surr2 && i+1 < len(s) && surr2 <= s[i+1] && s[i+1] < surr3: + // This case requires r >= SURR1 condition is true. + // Previous case checks this condition already. + // Therefore this case will not check this. - // valid surrogate sequence - a[n] = DecodeRune(rune(r), rune(s[i+1])) - i++ - |: - // invalid surrogate sequence - a[n] = replacementChar - } - n++ - } - ret a[:n] + // valid surrogate sequence + a[n] = DecodeRune(rune(r), rune(s[i+1])) + i++ + |: + // invalid surrogate sequence + a[n] = replacementChar + } + n++ + } + ret a[:n] } // Appends the UTF-16 encoding of the Unicode code point r // to the end of p and returns the extended buffer. If the rune is not // a valid Unicode code point, it appends the encoding of U+FFFD. fn AppendRune(mut a: []u16, r: rune): []u16 { - match { - | 0 <= r && r < surr1 | surr3 <= r && r < surrSelf: - // normal rune - ret append(a, u16(r)) - | surrSelf <= r && r <= MaxRune: - // needs surrogate sequence - r1, r2 := EncodeRune(r) - ret append(a, u16(r1), u16(r2)) - } - ret append(a, replacementChar) + match { + | 0 <= r && r < surr1 | surr3 <= r && r < surrSelf: + // normal rune + ret append(a, u16(r)) + | surrSelf <= r && r <= MaxRune: + // needs surrogate sequence + r1, r2 := EncodeRune(r) + ret append(a, u16(r1), u16(r2)) + } + ret append(a, replacementChar) } \ No newline at end of file diff --git a/std/unicode/utf8/utf8.jule b/std/unicode/utf8/utf8.jule index 19beda259..176a6dc3f 100644 --- a/std/unicode/utf8/utf8.jule +++ b/std/unicode/utf8/utf8.jule @@ -97,78 +97,78 @@ const s7 = 0x44 // accept 4, size 4 // Is information about the first byte in a UTF-8 sequence. static first: [256]byte = [ - // 1 2 3 4 5 6 7 8 9 A B C D E F - as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x00-0x0F - as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x10-0x1F - as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x20-0x2F - as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x30-0x3F - as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x40-0x4F - as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x50-0x5F - as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x60-0x6F - as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x70-0x7F - // 1 2 3 4 5 6 7 8 9 A B C D E F - xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0x80-0x8F - xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0x90-0x9F - xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0xA0-0xAF - xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0xB0-0xBF - xx, xx, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, // 0xC0-0xCF - s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, // 0xD0-0xDF - s2, s3, s3, s3, s3, s3, s3, s3, s3, s3, s3, s3, s3, s4, s3, s3, // 0xE0-0xEF - s5, s6, s6, s6, s7, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0xF0-0xFF + // 1 2 3 4 5 6 7 8 9 A B C D E F + as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x00-0x0F + as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x10-0x1F + as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x20-0x2F + as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x30-0x3F + as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x40-0x4F + as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x50-0x5F + as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x60-0x6F + as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x70-0x7F + // 1 2 3 4 5 6 7 8 9 A B C D E F + xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0x80-0x8F + xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0x90-0x9F + xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0xA0-0xAF + xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0xB0-0xBF + xx, xx, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, // 0xC0-0xCF + s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, // 0xD0-0xDF + s2, s3, s3, s3, s3, s3, s3, s3, s3, s3, s3, s3, s3, s4, s3, s3, // 0xE0-0xEF + s5, s6, s6, s6, s7, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0xF0-0xFF ] // Gives the range of valid values for the second byte in a UTF-8 sequence. struct acceptRange { - lo: byte // lowest value for second byte. - hi: byte // highest value for second byte. + lo: byte // lowest value for second byte. + hi: byte // highest value for second byte. } // Has size 16 to avoid bounds checks in the code that uses it. static acceptRanges: [16]acceptRange = [ - {locb, hicb}, - {0xA0, hicb}, - {locb, 0x9F}, - {0x90, hicb}, - {locb, 0x8F}, + {locb, hicb}, + {0xA0, hicb}, + {locb, 0x9F}, + {0x90, hicb}, + {locb, 0x8F}, ] // Reports whether the bytes in p begin with a full UTF-8 encoding of a rune. // An invalid encoding is considered a full Rune since it will convert as a width-1 error rune. fn FullRune(p: []byte): bool { - if len(p) == 0 { - ret false - } - x := first[p[0]] - if len(p) >= int(x&7) { - ret true // ASCII, invalid or valid. - } - // Must be short or invalid. - accept := acceptRanges[x>>4] - if len(p) > 1 && (p[1] < accept.lo || accept.hi < p[1]) { - ret true - } else if len(p) > 2 && (p[2] < locb || hicb < p[2]) { - ret true - } - ret false + if len(p) == 0 { + ret false + } + x := first[p[0]] + if len(p) >= int(x&7) { + ret true // ASCII, invalid or valid. + } + // Must be short or invalid. + accept := acceptRanges[x>>4] + if len(p) > 1 && (p[1] < accept.lo || accept.hi < p[1]) { + ret true + } else if len(p) > 2 && (p[2] < locb || hicb < p[2]) { + ret true + } + ret false } // Is like FullRune but its input is a string. fn FullRuneStr(s: str): bool { - if len(s) == 0 { - ret false - } - x := first[s[0]] - if len(s) >= int(x&7) { - ret true // ASCII, invalid, or valid. - } - // Must be short or invalid. - accept := acceptRanges[x>>4] - if len(s) > 1 && (s[1] < accept.lo || accept.hi < s[1]) { - ret true - } else if len(s) > 2 && (s[2] < locb || hicb < s[2]) { - ret true - } - ret false + if len(s) == 0 { + ret false + } + x := first[s[0]] + if len(s) >= int(x&7) { + ret true // ASCII, invalid, or valid. + } + // Must be short or invalid. + accept := acceptRanges[x>>4] + if len(s) > 1 && (s[1] < accept.lo || accept.hi < s[1]) { + ret true + } else if len(s) > 2 && (s[2] < locb || hicb < s[2]) { + ret true + } + ret false } // Unpacks the first UTF-8 encoding in p and returns the rune and @@ -180,42 +180,42 @@ fn FullRuneStr(s: str): bool { // out of range, or is not the shortest possible UTF-8 encoding for the // value. No other validation is performed. fn DecodeRune(p: []byte): (r: rune, size: int) { - if len(p) < 1 { - ret RuneError, 0 - } - p0 := p[0] - x := first[p0] - if x >= as { - // The following code simulates an additional check for x == XX and - // handling the ASCII and invalid cases accordingly. This mask-and-or - // approach prevents an additional branch. - mask := rune(x << 31 >> 31) // Create 0x0000 or 0xFFFF. - ret rune(p[0]) & ^mask | RuneError & mask, 1 - } - sz := int(x & 7) - accept := acceptRanges[x>>4] - if len(p) < sz { - ret RuneError, 1 - } - b1 := p[1] - if b1 < accept.lo || accept.hi < b1 { - ret RuneError, 1 - } - if sz <= 2 { // <= instead of == to help the compiler eliminate some bounds checks - ret rune(p0 & mask2) << 6 | rune(b1 & maskX), 2 - } - b2 := p[2] - if b2 < locb || hicb < b2 { - ret RuneError, 1 - } - if sz <= 3 { - ret rune(p0 & mask3) << 12 | rune(b1 & maskX) << 6 | rune(b2 & maskX), 3 - } - b3 := p[3] - if b3 < locb || hicb < b3 { - ret RuneError, 1 - } - ret rune(p0 & mask4) << 18 | rune(b1 & maskX) << 12 | rune(b2 & maskX) << 6 | rune(b3 & maskX), 4 + if len(p) < 1 { + ret RuneError, 0 + } + p0 := p[0] + x := first[p0] + if x >= as { + // The following code simulates an additional check for x == XX and + // handling the ASCII and invalid cases accordingly. This mask-and-or + // approach prevents an additional branch. + mask := rune(x << 31 >> 31) // Create 0x0000 or 0xFFFF. + ret rune(p[0]) & ^mask | RuneError & mask, 1 + } + sz := int(x & 7) + accept := acceptRanges[x>>4] + if len(p) < sz { + ret RuneError, 1 + } + b1 := p[1] + if b1 < accept.lo || accept.hi < b1 { + ret RuneError, 1 + } + if sz <= 2 { // <= instead of == to help the compiler eliminate some bounds checks + ret rune(p0 & mask2) << 6 | rune(b1 & maskX), 2 + } + b2 := p[2] + if b2 < locb || hicb < b2 { + ret RuneError, 1 + } + if sz <= 3 { + ret rune(p0 & mask3) << 12 | rune(b1 & maskX) << 6 | rune(b2 & maskX), 3 + } + b3 := p[3] + if b3 < locb || hicb < b3 { + ret RuneError, 1 + } + ret rune(p0 & mask4) << 18 | rune(b1 & maskX) << 12 | rune(b2 & maskX) << 6 | rune(b3 & maskX), 4 } // Is like DecodeRune but its input is a string. If s is empty @@ -227,42 +227,42 @@ fn DecodeRune(p: []byte): (r: rune, size: int) { // out of range, or is not the shortest possible UTF-8 encoding for the // value. No other validation is performed. fn DecodeRuneStr(s: str): (r: rune, size: int) { - if len(s) < 1 { - ret RuneError, 0 - } - s0 := s[0] - x := first[s0] - if x >= as { - // The following code simulates an additional check for x == xx and - // handling the ASCII and invalid cases accordingly. This mask-and-or - // approach prevents an additional branch. - mask := rune(x << 31 >> 31) // Create 0x0000 or 0xFFFF. - ret rune(s[0]) & ^mask | RuneError & mask, 1 - } - sz := int(x & 7) - accept := acceptRanges[x>>4] - if len(s) < sz { - ret RuneError, 1 - } - s1 := s[1] - if s1 < accept.lo || accept.hi < s1 { - ret RuneError, 1 - } - if sz <= 2 { // <= instead of == to help the compiler eliminate some bounds checks - ret rune(s0 & mask2) << 6 | rune(s1 & maskX), 2 - } - s2 := s[2] - if s2 < locb || hicb < s2 { - ret RuneError, 1 - } - if sz <= 3 { - ret rune(s0 & mask3) << 12 | rune(s1 & maskX) << 6 | rune(s2 & maskX), 3 - } - s3 := s[3] - if s3 < locb || hicb < s3 { - ret RuneError, 1 - } - ret rune(s0 & mask4) << 18 | rune(s1 & maskX) << 12 | rune(s2 & maskX) << 6 | rune(s3 & maskX), 4 + if len(s) < 1 { + ret RuneError, 0 + } + s0 := s[0] + x := first[s0] + if x >= as { + // The following code simulates an additional check for x == xx and + // handling the ASCII and invalid cases accordingly. This mask-and-or + // approach prevents an additional branch. + mask := rune(x << 31 >> 31) // Create 0x0000 or 0xFFFF. + ret rune(s[0]) & ^mask | RuneError & mask, 1 + } + sz := int(x & 7) + accept := acceptRanges[x>>4] + if len(s) < sz { + ret RuneError, 1 + } + s1 := s[1] + if s1 < accept.lo || accept.hi < s1 { + ret RuneError, 1 + } + if sz <= 2 { // <= instead of == to help the compiler eliminate some bounds checks + ret rune(s0 & mask2) << 6 | rune(s1 & maskX), 2 + } + s2 := s[2] + if s2 < locb || hicb < s2 { + ret RuneError, 1 + } + if sz <= 3 { + ret rune(s0 & mask3) << 12 | rune(s1 & maskX) << 6 | rune(s2 & maskX), 3 + } + s3 := s[3] + if s3 < locb || hicb < s3 { + ret RuneError, 1 + } + ret rune(s0 & mask4) << 18 | rune(s1 & maskX) << 12 | rune(s2 & maskX) << 6 | rune(s3 & maskX), 4 } // Unpacks the last UTF-8 encoding in p and returns the rune and @@ -274,36 +274,36 @@ fn DecodeRuneStr(s: str): (r: rune, size: int) { // out of range, or is not the shortest possible UTF-8 encoding for the // value. No other validation is performed. fn DecodeLastRune(p: []byte): (r: rune, size: int) { - if len(p) == 0 { - ret RuneError, 0 - } - end := len(p) - mut start := end - 1 - r = rune(p[start]) - if r < RuneSelf { - ret r, 1 - } - // guard against O(n^2) behavior when traversing - // backwards through strings with long sequences of - // invalid UTF-8. - mut lim := end - UTFMax - if lim < 0 { - lim = 0 - } - start-- - for start >= lim; start-- { - if RuneStart(p[start]) { - break - } - } - if start < 0 { - start = 0 - } - r, size = DecodeRune(p[start:end]) - if start+size != end { - ret RuneError, 1 - } - ret r, size + if len(p) == 0 { + ret RuneError, 0 + } + end := len(p) + mut start := end - 1 + r = rune(p[start]) + if r < RuneSelf { + ret r, 1 + } + // guard against O(n^2) behavior when traversing + // backwards through strings with long sequences of + // invalid UTF-8. + mut lim := end - UTFMax + if lim < 0 { + lim = 0 + } + start-- + for start >= lim; start-- { + if RuneStart(p[start]) { + break + } + } + if start < 0 { + start = 0 + } + r, size = DecodeRune(p[start:end]) + if start+size != end { + ret RuneError, 1 + } + ret r, size } // Is like DecodeLastRune but its input is a string. If @@ -315,200 +315,200 @@ fn DecodeLastRune(p: []byte): (r: rune, size: int) { // out of range, or is not the shortest possible UTF-8 encoding for the // value. No other validation is performed. fn DecodeLastRuneStr(s: str): (r: rune, size: int) { - if len(s) == 0 { - ret RuneError, 0 - } - end := len(s) - mut start := end - 1 - r = rune(s[start]) - if r < RuneSelf { - ret r, 1 - } - // guard against O(n^2) behavior when traversing - // backwards through strings with long sequences of - // invalid UTF-8. - mut lim := end - UTFMax - if lim < 0 { - lim = 0 - } - start-- - for start >= lim; start-- { - if RuneStart(s[start]) { - break - } - } - if start < 0 { - start = 0 - } - r, size = DecodeRuneStr(s[start:end]) - if start+size != end { - ret RuneError, 1 - } - ret r, size + if len(s) == 0 { + ret RuneError, 0 + } + end := len(s) + mut start := end - 1 + r = rune(s[start]) + if r < RuneSelf { + ret r, 1 + } + // guard against O(n^2) behavior when traversing + // backwards through strings with long sequences of + // invalid UTF-8. + mut lim := end - UTFMax + if lim < 0 { + lim = 0 + } + start-- + for start >= lim; start-- { + if RuneStart(s[start]) { + break + } + } + if start < 0 { + start = 0 + } + r, size = DecodeRuneStr(s[start:end]) + if start+size != end { + ret RuneError, 1 + } + ret r, size } // Returns the number of bytes required to encode the rune. // It returns -1 if the rune is not a valid value to encode in UTF-8. fn RuneLen(r: rune): int { - match { - | r < 0: - ret -1 - | r <= rune1max: - ret 1 - | r <= rune2max: - ret 2 - | surrogateMin <= r && r <= surrogateMax: - ret -1 - | r <= rune3max: - ret 3 - | r <= MaxRune: - ret 4 - |: - ret -1 - } + match { + | r < 0: + ret -1 + | r <= rune1max: + ret 1 + | r <= rune2max: + ret 2 + | surrogateMin <= r && r <= surrogateMax: + ret -1 + | r <= rune3max: + ret 3 + | r <= MaxRune: + ret 4 + |: + ret -1 + } } // Writes into p (which must be large enough) the UTF-8 encoding of the rune. // If the rune is out of range, it writes the encoding of RuneError. // It returns the number of bytes written. fn EncodeRune(mut p: []byte, mut r: rune): int { - // Negative values are erroneous. Making it unsigned addresses the problem. - i := u32(r) - match { - | i <= rune1max: - p[0] = byte(r) - ret 1 - | i <= rune2max: - p[0] = t2 | byte(r >> 6) - p[1] = tx | byte(r) & maskX - ret 2 - | i > MaxRune | surrogateMin <= i && i <= surrogateMax: - r = RuneError - fall - | i <= rune3max: - p[0] = t3 | byte(r >> 12) - p[1] = tx | byte(r >> 6) & maskX - p[2] = tx | byte(r) & maskX - ret 3 - |: - p[0] = t4 | byte(r >> 18) - p[1] = tx | byte(r >> 12) & maskX - p[2] = tx | byte(r >> 6) & maskX - p[3] = tx | byte(r) & maskX - ret 4 - } + // Negative values are erroneous. Making it unsigned addresses the problem. + i := u32(r) + match { + | i <= rune1max: + p[0] = byte(r) + ret 1 + | i <= rune2max: + p[0] = t2 | byte(r >> 6) + p[1] = tx | byte(r) & maskX + ret 2 + | i > MaxRune | surrogateMin <= i && i <= surrogateMax: + r = RuneError + fall + | i <= rune3max: + p[0] = t3 | byte(r >> 12) + p[1] = tx | byte(r >> 6) & maskX + p[2] = tx | byte(r) & maskX + ret 3 + |: + p[0] = t4 | byte(r >> 18) + p[1] = tx | byte(r >> 12) & maskX + p[2] = tx | byte(r >> 6) & maskX + p[3] = tx | byte(r) & maskX + ret 4 + } } // Appends the UTF-8 encoding of r to the end of p and // returns the extended buffer. If the rune is out of range, // it appends the encoding of RuneError. fn AppendRune(mut p: []byte, r: rune): []byte { - if r <= rune1max { - ret append(p, byte(r)) - } - ret appendRuneNonASCII(p, r) + if r <= rune1max { + ret append(p, byte(r)) + } + ret appendRuneNonASCII(p, r) } fn appendRuneNonASCII(mut p: []byte, mut r: rune): []byte { - // Negative values are erroneous. Making it unsigned addresses the problem. - i := u32(r) - match { - | i <= rune2max: - ret append(p, t2 | byte(r >> 6), tx | byte(r) & maskX) - | i > MaxRune | surrogateMin <= i && i <= surrogateMax: - r = RuneSelf - fall - | i <= rune3max: - ret append(p, t3 | byte(r >> 12), tx | byte(r >> 6) & maskX, tx | byte(r) & maskX) - |: - ret append(p, t4 | byte(r >> 18), tx | byte(r >> 12) & maskX, tx | byte(r >> 6) & maskX, tx | byte(r) & maskX) - } + // Negative values are erroneous. Making it unsigned addresses the problem. + i := u32(r) + match { + | i <= rune2max: + ret append(p, t2 | byte(r >> 6), tx | byte(r) & maskX) + | i > MaxRune | surrogateMin <= i && i <= surrogateMax: + r = RuneSelf + fall + | i <= rune3max: + ret append(p, t3 | byte(r >> 12), tx | byte(r >> 6) & maskX, tx | byte(r) & maskX) + |: + ret append(p, t4 | byte(r >> 18), tx | byte(r >> 12) & maskX, tx | byte(r >> 6) & maskX, tx | byte(r) & maskX) + } } // Returns the number of runes in p. Erroneous and short // encodings are treated as single runes of width 1 byte. fn RuneCount(p: []byte): (n: int) { - mut i := 0 - for i < len(p) { - n++ - mut c := p[i] - if c < RuneSelf { - // ASCII fast path - i++ - continue - } - x := first[c] - if x == xx { - i++ // invalid. - continue - } - mut size := int(x & 7) - if i+size > len(p) { - i++ // Short or invalid. - continue - } - accept := acceptRanges[x>>4] - c = p[i+1] - if c < accept.lo || accept.hi < c { - size = 1 - } else if size == 2 { - } else { - c = p[i+2] - if c < locb || hicb < c { - size = 1 - } else if size == 3 { - } else { - c = p[i+3] - if c < locb || hicb < c { - size = 1 - } - } - } - i += size - } - ret n + mut i := 0 + for i < len(p) { + n++ + mut c := p[i] + if c < RuneSelf { + // ASCII fast path + i++ + continue + } + x := first[c] + if x == xx { + i++ // invalid. + continue + } + mut size := int(x & 7) + if i+size > len(p) { + i++ // Short or invalid. + continue + } + accept := acceptRanges[x>>4] + c = p[i+1] + if c < accept.lo || accept.hi < c { + size = 1 + } else if size == 2 { + } else { + c = p[i+2] + if c < locb || hicb < c { + size = 1 + } else if size == 3 { + } else { + c = p[i+3] + if c < locb || hicb < c { + size = 1 + } + } + } + i += size + } + ret n } // Is like RuneCount but its input is a string. fn RuneCountStr(s: str): (n: int) { - mut i := 0 - for i < len(s); n++ { - mut c := s[i] - if c < RuneSelf { - // ASCII fast path - i++ - continue - } - x := first[c] - if x == xx { - i++ // invalid. - continue - } - mut size := int(x & 7) - if i+size > len(s) { - i++ // Short or invalid. - continue - } - accept := acceptRanges[x>>4] - c = s[i+1] - if c < accept.lo || accept.hi < c { - size = 1 - } else if size == 2 { - } else { - c = s[i+2] - if c < locb || hicb < c { - size = 1 - } else if size == 3 { - } else { - c = s[i+3] - if c < locb || hicb < c { - size = 1 - } - } - } - i += size - } - ret n + mut i := 0 + for i < len(s); n++ { + mut c := s[i] + if c < RuneSelf { + // ASCII fast path + i++ + continue + } + x := first[c] + if x == xx { + i++ // invalid. + continue + } + mut size := int(x & 7) + if i+size > len(s) { + i++ // Short or invalid. + continue + } + accept := acceptRanges[x>>4] + c = s[i+1] + if c < accept.lo || accept.hi < c { + size = 1 + } else if size == 2 { + } else { + c = s[i+2] + if c < locb || hicb < c { + size = 1 + } else if size == 3 { + } else { + c = s[i+3] + if c < locb || hicb < c { + size = 1 + } + } + } + i += size + } + ret n } // Reports whether the byte could be the first byte of an encoded, @@ -518,119 +518,119 @@ fn RuneStart(b: byte): bool { ret b&0xC0 != 0x80 } // Reports whether p consists entirely of valid UTF-8-encoded runes. fn Valid(p: []byte): bool { - // Break immutability, it is safe because - // p's content is not changed by this function. - mut cp := unsafe { *(&p) } - - // Fast path. Check for and skip 8 bytes of ASCII characters per iteration. - for len(cp) >= 8 { - // Combining two 32 bit loads allows the same code to be used - // for 32 and 64 bit platforms. - first32 := u32(cp[0]) | u32(cp[1]) << 8 | u32(cp[2]) << 16 | u32(cp[3]) << 24 - second32 := u32(cp[4]) | u32(cp[5]) << 8 | u32(cp[6]) << 16 | u32(cp[7]) << 24 - if (first32 | second32)&0x80808080 != 0 { - // Found a non ASCII byte (>= RneSelf). - break - } - cp = cp[8:] - } - mut i := 0 - for i < len(cp) { - pi := cp[i] - if pi < RuneSelf { - i++ - continue - } - x := first[pi] - if x == xx { - ret false // Illegal starter byte. - } - size := int(x & 7) - if i+size > len(cp) { - ret false // Short or invalid. - } - accept := acceptRanges[x>>4] - mut c := cp[i+1] - if c < accept.lo || accept.hi < c { - ret false - } else if size == 2 { - } else { - c = cp[i+2] - if c < locb || hicb < c { - ret false - } else if size == 3 { - } else { - c = cp[i+3] - if c < locb || hicb < c { - ret false - } - } - } - i += size - } - ret true + // Break immutability, it is safe because + // p's content is not changed by this function. + mut cp := unsafe { *(&p) } + + // Fast path. Check for and skip 8 bytes of ASCII characters per iteration. + for len(cp) >= 8 { + // Combining two 32 bit loads allows the same code to be used + // for 32 and 64 bit platforms. + first32 := u32(cp[0]) | u32(cp[1]) << 8 | u32(cp[2]) << 16 | u32(cp[3]) << 24 + second32 := u32(cp[4]) | u32(cp[5]) << 8 | u32(cp[6]) << 16 | u32(cp[7]) << 24 + if (first32 | second32)&0x80808080 != 0 { + // Found a non ASCII byte (>= RneSelf). + break + } + cp = cp[8:] + } + mut i := 0 + for i < len(cp) { + pi := cp[i] + if pi < RuneSelf { + i++ + continue + } + x := first[pi] + if x == xx { + ret false // Illegal starter byte. + } + size := int(x & 7) + if i+size > len(cp) { + ret false // Short or invalid. + } + accept := acceptRanges[x>>4] + mut c := cp[i+1] + if c < accept.lo || accept.hi < c { + ret false + } else if size == 2 { + } else { + c = cp[i+2] + if c < locb || hicb < c { + ret false + } else if size == 3 { + } else { + c = cp[i+3] + if c < locb || hicb < c { + ret false + } + } + } + i += size + } + ret true } // Reports whether s consists entirely of valid UTF-8-encoded runes. fn ValidStr(mut s: str): bool { - // Fast path. Check for and skip 8 bytes of ASCII characters per iteration. - for len(s) >= 8 { - // Combining two 32 bit loads allows the same code to be used - // for 32 and 64 bit platforms. - first32 := u32(s[0]) | u32(s[1]) << 8 | u32(s[2]) << 16 | u32(s[3]) << 24 - second32 := u32(s[4]) | u32(s[5]) << 8 | u32(s[6]) << 16 | u32(s[7]) << 24 - if (first32 | second32)&0x80808080 != 0 { - // Found a non ASCII byte (>= RuneSelf). - break - } - s = s[8:] - } - mut i := 0 - for i < len(s) { - si := s[i] - if si < RuneSelf { - i++ - continue - } - x := first[si] - if x == xx { - ret false // Illegal starter byte. - } - size := int(x & 7) - if i+size > len(s) { - ret false // Short or invalid. - } - accept := acceptRanges[x>>4] - mut c := s[i+1] - if c < accept.lo || accept.hi < c { - ret false - } else if size == 2 { - } else { - c = s[i+2] - if c < locb || hicb < c { - ret false - } else if size == 3 { - } else { - c = s[i+3] - if c < locb || hicb < c { - ret false - } - } - } - i += size - } - ret true + // Fast path. Check for and skip 8 bytes of ASCII characters per iteration. + for len(s) >= 8 { + // Combining two 32 bit loads allows the same code to be used + // for 32 and 64 bit platforms. + first32 := u32(s[0]) | u32(s[1]) << 8 | u32(s[2]) << 16 | u32(s[3]) << 24 + second32 := u32(s[4]) | u32(s[5]) << 8 | u32(s[6]) << 16 | u32(s[7]) << 24 + if (first32 | second32)&0x80808080 != 0 { + // Found a non ASCII byte (>= RuneSelf). + break + } + s = s[8:] + } + mut i := 0 + for i < len(s) { + si := s[i] + if si < RuneSelf { + i++ + continue + } + x := first[si] + if x == xx { + ret false // Illegal starter byte. + } + size := int(x & 7) + if i+size > len(s) { + ret false // Short or invalid. + } + accept := acceptRanges[x>>4] + mut c := s[i+1] + if c < accept.lo || accept.hi < c { + ret false + } else if size == 2 { + } else { + c = s[i+2] + if c < locb || hicb < c { + ret false + } else if size == 3 { + } else { + c = s[i+3] + if c < locb || hicb < c { + ret false + } + } + } + i += size + } + ret true } // Reports whether r can be legally encoded as UTF-8. // Code points that are out of range or a surrogate half are illegal. fn ValidRune(r: rune): bool { - match { - | 0 <= r && r < surrogateMin: - ret true - | surrogateMax < r && r <= MaxRune: - ret true - |: - ret false - } + match { + | 0 <= r && r < surrogateMin: + ret true + | surrogateMax < r && r <= MaxRune: + ret true + |: + ret false + } } \ No newline at end of file diff --git a/std/unsafe/conv.jule b/std/unsafe/conv.jule index 46c3be226..2531dfac7 100644 --- a/std/unsafe/conv.jule +++ b/std/unsafe/conv.jule @@ -8,50 +8,50 @@ use integ for std::jule::integrated // The returned string uses n as length. // Will not perform garbage collection. fn Str(b: *byte, n: int): str { - mut s := "" - unsafe { - integ::Emit("{}.buffer = {}::make({}, {})", s, &byte, b, nil) - integ::Emit("{}._len = {}", s, n) - integ::Emit("{}._slice = {}", s, b) - } - ret s + mut s := "" + unsafe { + integ::Emit("{}.buffer = {}::make({}, {})", s, &byte, b, nil) + integ::Emit("{}._len = {}", s, n) + integ::Emit("{}._slice = {}", s, b) + } + ret s } // Returns slice based on e, the parameter e means first element of slice. // The returned slice uses n as length and capacity. // Will not perform garbage collection. fn Slice[Elem](e: *Elem, n: int): []Elem { - mut buf := []Elem(nil) - unsafe { - integ::Emit("{}.data = {}::make({}, {})", buf, &Elem, e, nil) - integ::Emit("{}._len = {}", buf, n) - integ::Emit("{}._cap = {}", buf, n) - integ::Emit("{}._slice = {}", buf, e) - } - ret buf + mut buf := []Elem(nil) + unsafe { + integ::Emit("{}.data = {}::make({}, {})", buf, &Elem, e, nil) + integ::Emit("{}._len = {}", buf, n) + integ::Emit("{}._cap = {}", buf, n) + integ::Emit("{}._slice = {}", buf, e) + } + ret buf } // Alias for Slice(b, n). fn Bytes(b: *byte, n: int): []byte { - ret Slice(b, n) + ret Slice(b, n) } // Alias for Slice(&s[0], len(s)). // Returns nil if len(s) == 0. fn StrBytes(s: str): []byte { - if len(s) == 0 { - ret nil - } - ret Slice(&s[0], len(s)) + if len(s) == 0 { + ret nil + } + ret Slice(&s[0], len(s)) } // Alias for Str(&b[0], len(b)). // Returns empty string if len(b) == 0. fn BytesStr(b: []byte): str { - if len(b) == 0 { - ret "" - } - ret Str(&b[0], len(b)) + if len(b) == 0 { + ret "" + } + ret Str(&b[0], len(b)) } // Same as [BytesStr] but keeps garbage collection. @@ -59,12 +59,12 @@ fn StrFromBytes(b: []byte): str { ret unsafe { *(*str)(&b) } } // Same as [StrBytes] but keeps garbage collection. fn BytesFromStr(s: str): []byte { - mut b := StrBytes(s) - unsafe { - if integ::Emit[bool]("{}.buffer.ref != {}", s, nil) { - integ::Emit("{}.data.ref = {}.buffer.ref", b, s) - integ::Emit("{}.data.add_ref()", b) - } - } - ret b + mut b := StrBytes(s) + unsafe { + if integ::Emit[bool]("{}.buffer.ref != {}", s, nil) { + integ::Emit("{}.data.ref = {}.buffer.ref", b, s) + integ::Emit("{}.data.add_ref()", b) + } + } + ret b } \ No newline at end of file diff --git a/std/vec/vec.jule b/std/vec/vec.jule index bb60ae006..a9b327093 100644 --- a/std/vec/vec.jule +++ b/std/vec/vec.jule @@ -17,218 +17,218 @@ const growFactor = 2 // Vectors aren't use shared allocation between themselves. // Allocates new space and copies (not deep copy) items into space. struct Vec[T] { - mem: Dynar[T] + mem: Dynar[T] } impl Vec { - // Allocate new vector with capacity. - static fn New(cap: int): Vec[T] { - mut vec := Vec[T]{ - mem: Dynar[T].New(), - } - if cap > 0 { - vec.resize(cap) - } - ret vec - } - - fn resize(mut self, n: int) { - ok := self.mem.Resize(n) - if !ok { - panic("Vec[T]: heap reallocation failed") - } - } - - fn calcGrow(self, delta: int): int { - t := self.Len() + delta - ret t * growFactor - } - - fn reviewSize(mut self, delta: int) { - if self.Len()+delta > self.Cap() { - self.resize(self.calcGrow(delta)) - } - } - - // Deallocate heap. - fn Dispose(mut self) { - self.mem.Dispose() - } - - // Set capacity to length. - // Removes additional capacity that waiting to use. - // Allocates new memory to cut additional capacity. - fn Fit(mut self) { - if self.Len() != self.Cap() { - self.resize(self.Len()) - } - } - - // Returns length. - fn Len(self): int { - ret self.mem.Buff.len - } - - // Returns capacity. - fn Cap(self): int { - ret self.mem.Buff.cap - } - - // Sets length. - // Sets length to zero if n < 0. - // Don't set length if n >= length of vector. - fn SetLen(mut self, n: int) { - if n < 0 { - self.mem.Buff.len = 0 - ret - } - if n >= self.Len() { - ret - } - self.mem.Buff.len = n - } - - // Returns item by index. - fn At(mut self, i: int): T { - if i < 0 || i >= self.Len() { - panic("Vec[T].At: out of range") - } - unsafe { - ret self.mem.Buff.heap[i] - } - } - - // Set element by index. - fn Set(mut self, i: int, mut item: T) { - if i < 0 || i >= self.Len() { - panic("Vec[T].Set: out of range") - } - unsafe { - self.mem.Buff.heap[i] = item - } - } - - // Removes all elements. - // Does not deallocates buffer, keeps capacity. - fn Clear(mut self) { - self.mem.Buff.len = 0 - } - - // Push item to end of heap. - fn Push(mut self, mut item: T) { - if self.Len() >= self.Cap() { - self.resize((self.Cap() * growFactor) + 1) - } - unsafe { - self.mem.Buff.heap[self.Len()] = item - } - self.mem.Buff.len++ - } - - // Push item to front of heap. - fn PushFront(mut self, mut item: T) { - if self.Len() >= self.Cap() { - self.resize((self.Cap() * growFactor) + 1) - } - self.mem.ShiftRight(0, 1) - unsafe { - self.mem.Buff.heap[0] = item - } - self.mem.Buff.len++ - } - - // Push items to end of heap. - fn Append(mut self, mut items: ...T) { - if len(items) == 0 { - ret - } - self.reviewSize(len(items)) - self.mem.Set(self.Len(), &items[0], len(items)) - self.mem.Buff.len += len(items) - } - - // Merge items to end of heap. - fn Merge(mut self, mut vec: Vec[T]) { - if vec.Len() == 0 { - ret - } - self.reviewSize(vec.Len()) - self.mem.Set(self.Len(), vec.mem.Begin(), vec.Len()) - self.mem.Buff.len += vec.Len() - } - - // Merge items to front of heap. - fn MergeFront(mut self, mut vec: Vec[T]) { - if vec.Len() == 0 { - ret - } - self.reviewSize(vec.Len()) - self.mem.ShiftRight(0, vec.Len()) - self.mem.Set(0, vec.mem.Begin(), vec.Len()) - self.mem.Buff.len += vec.Len() - } - - // Remove range from heap. - fn RemoveRange(mut self, start: int, n: int) { - if n < 1 { - ret - } - if start < -1 { - panic("Vec[T].RemoveRange: removing starts at negative index") - } - if start >= self.Len() { - panic("Vec[T].RemoveRange: removing starts at out of range") - } - if self.Len()-start-n < 0 { - panic("Vec[T].RemoveRange: removing continues at out of range") - } - self.mem.ShiftLeft(start + n, self.Len(), n) - self.mem.Buff.len -= n - } - - // Insert item by index. - fn Insert(mut self, i: int, mut item: T) { - if i < 0 { - panic("Vec[T].Insert: insertion starts at negative index") - } - if i > self.Len() { - panic("Vec[T].Insert: insertion starts at out of range") - } - if self.Len() >= self.Cap() { - self.resize((self.Cap() * growFactor) + 1) - } - self.mem.ShiftRight(i, 1) - unsafe { - self.mem.Buff.heap[i] = item - } - self.mem.Buff.len++ - } - - // Slice between indexes except end position. - // Not clones internal buffer, so slice vector can effect - // to internal buffer if type is mutable. - fn Slice(mut self, start: int, end: int): Vec[T] { - if start < 0 { - panic("Vec[T].Slice: slicing starts at negative index") - } - if start > self.Len() { - panic("Vec[T].Slice: slicing starts at out of range") - } - if end > self.Len() { - panic("Vec[T].Slice: slicing ends at out of range") - } - if end < 0 { - panic("Vec[T].Slice: slicing ends at negative index") - } - if start > end { - panic("Vec[T].Slice: start point < end point") - } - if start == end { - ret Vec[T].New(0) - } - mut vec := Vec[T].New(end - start) - vec.mem.Set(0, self.mem.Begin() + start, vec.Cap()) - vec.mem.Buff.len = vec.Cap() - ret vec - } + // Allocate new vector with capacity. + static fn New(cap: int): Vec[T] { + mut vec := Vec[T]{ + mem: Dynar[T].New(), + } + if cap > 0 { + vec.resize(cap) + } + ret vec + } + + fn resize(mut self, n: int) { + ok := self.mem.Resize(n) + if !ok { + panic("Vec[T]: heap reallocation failed") + } + } + + fn calcGrow(self, delta: int): int { + t := self.Len() + delta + ret t * growFactor + } + + fn reviewSize(mut self, delta: int) { + if self.Len()+delta > self.Cap() { + self.resize(self.calcGrow(delta)) + } + } + + // Deallocate heap. + fn Dispose(mut self) { + self.mem.Dispose() + } + + // Set capacity to length. + // Removes additional capacity that waiting to use. + // Allocates new memory to cut additional capacity. + fn Fit(mut self) { + if self.Len() != self.Cap() { + self.resize(self.Len()) + } + } + + // Returns length. + fn Len(self): int { + ret self.mem.Buff.len + } + + // Returns capacity. + fn Cap(self): int { + ret self.mem.Buff.cap + } + + // Sets length. + // Sets length to zero if n < 0. + // Don't set length if n >= length of vector. + fn SetLen(mut self, n: int) { + if n < 0 { + self.mem.Buff.len = 0 + ret + } + if n >= self.Len() { + ret + } + self.mem.Buff.len = n + } + + // Returns item by index. + fn At(mut self, i: int): T { + if i < 0 || i >= self.Len() { + panic("Vec[T].At: out of range") + } + unsafe { + ret self.mem.Buff.heap[i] + } + } + + // Set element by index. + fn Set(mut self, i: int, mut item: T) { + if i < 0 || i >= self.Len() { + panic("Vec[T].Set: out of range") + } + unsafe { + self.mem.Buff.heap[i] = item + } + } + + // Removes all elements. + // Does not deallocates buffer, keeps capacity. + fn Clear(mut self) { + self.mem.Buff.len = 0 + } + + // Push item to end of heap. + fn Push(mut self, mut item: T) { + if self.Len() >= self.Cap() { + self.resize((self.Cap() * growFactor) + 1) + } + unsafe { + self.mem.Buff.heap[self.Len()] = item + } + self.mem.Buff.len++ + } + + // Push item to front of heap. + fn PushFront(mut self, mut item: T) { + if self.Len() >= self.Cap() { + self.resize((self.Cap() * growFactor) + 1) + } + self.mem.ShiftRight(0, 1) + unsafe { + self.mem.Buff.heap[0] = item + } + self.mem.Buff.len++ + } + + // Push items to end of heap. + fn Append(mut self, mut items: ...T) { + if len(items) == 0 { + ret + } + self.reviewSize(len(items)) + self.mem.Set(self.Len(), &items[0], len(items)) + self.mem.Buff.len += len(items) + } + + // Merge items to end of heap. + fn Merge(mut self, mut vec: Vec[T]) { + if vec.Len() == 0 { + ret + } + self.reviewSize(vec.Len()) + self.mem.Set(self.Len(), vec.mem.Begin(), vec.Len()) + self.mem.Buff.len += vec.Len() + } + + // Merge items to front of heap. + fn MergeFront(mut self, mut vec: Vec[T]) { + if vec.Len() == 0 { + ret + } + self.reviewSize(vec.Len()) + self.mem.ShiftRight(0, vec.Len()) + self.mem.Set(0, vec.mem.Begin(), vec.Len()) + self.mem.Buff.len += vec.Len() + } + + // Remove range from heap. + fn RemoveRange(mut self, start: int, n: int) { + if n < 1 { + ret + } + if start < -1 { + panic("Vec[T].RemoveRange: removing starts at negative index") + } + if start >= self.Len() { + panic("Vec[T].RemoveRange: removing starts at out of range") + } + if self.Len()-start-n < 0 { + panic("Vec[T].RemoveRange: removing continues at out of range") + } + self.mem.ShiftLeft(start + n, self.Len(), n) + self.mem.Buff.len -= n + } + + // Insert item by index. + fn Insert(mut self, i: int, mut item: T) { + if i < 0 { + panic("Vec[T].Insert: insertion starts at negative index") + } + if i > self.Len() { + panic("Vec[T].Insert: insertion starts at out of range") + } + if self.Len() >= self.Cap() { + self.resize((self.Cap() * growFactor) + 1) + } + self.mem.ShiftRight(i, 1) + unsafe { + self.mem.Buff.heap[i] = item + } + self.mem.Buff.len++ + } + + // Slice between indexes except end position. + // Not clones internal buffer, so slice vector can effect + // to internal buffer if type is mutable. + fn Slice(mut self, start: int, end: int): Vec[T] { + if start < 0 { + panic("Vec[T].Slice: slicing starts at negative index") + } + if start > self.Len() { + panic("Vec[T].Slice: slicing starts at out of range") + } + if end > self.Len() { + panic("Vec[T].Slice: slicing ends at out of range") + } + if end < 0 { + panic("Vec[T].Slice: slicing ends at negative index") + } + if start > end { + panic("Vec[T].Slice: start point < end point") + } + if start == end { + ret Vec[T].New(0) + } + mut vec := Vec[T].New(end - start) + vec.mem.Set(0, self.mem.Begin() + start, vec.Cap()) + vec.mem.Buff.len = vec.Cap() + ret vec + } } \ No newline at end of file diff --git a/tests/arrays/main.jule b/tests/arrays/main.jule index 094e0d164..c98305c2e 100644 --- a/tests/arrays/main.jule +++ b/tests/arrays/main.jule @@ -3,10 +3,10 @@ // license that can be found in the LICENSE file. fn main() { - let arr0: [5]i32 = [0, 0, 0, 0, 0] - let arr1: [6]i32 = [9, 16, 32, 64, 128, 256] - assert(len(arr0) == 5) - assert(len((arr1)) == 6) - outln(len(arr0)) - outln(len((arr1))) + let arr0: [5]i32 = [0, 0, 0, 0, 0] + let arr1: [6]i32 = [9, 16, 32, 64, 128, 256] + assert(len(arr0) == 5) + assert(len((arr1)) == 6) + outln(len(arr0)) + outln(len((arr1))) } \ No newline at end of file diff --git a/tests/assertion/main.jule b/tests/assertion/main.jule index e86bdf8ea..91834c7af 100644 --- a/tests/assertion/main.jule +++ b/tests/assertion/main.jule @@ -3,7 +3,7 @@ // license that can be found in the LICENSE file. fn main() { - let s: []int = nil - assert(len(s) == 0) - assert(s == nil) + let s: []int = nil + assert(len(s) == 0) + assert(s == nil) } \ No newline at end of file diff --git a/tests/basic_calculator/main.jule b/tests/basic_calculator/main.jule index f33fb3f06..f33010ff4 100644 --- a/tests/basic_calculator/main.jule +++ b/tests/basic_calculator/main.jule @@ -7,42 +7,42 @@ use conv for std::conv use io for std::io fn readln(): str { - let scanner = io::Scanner.New(io::Stdin()) - if (scanner.Scan() else { use false }) { - ret scanner.Text() - } - ret "" + let scanner = io::Scanner.New(io::Stdin()) + if (scanner.Scan() else { use false }) { + ret scanner.Text() + } + ret "" } fn numericInput(msg: str)!: f64 { - fmt::Print(msg) - let input = readln() - ret conv::ParseFloat(input, 64) else { error(false) } + fmt::Print(msg) + let input = readln() + ret conv::ParseFloat(input, 64) else { error(false) } } fn main() { - for { - let l = numericInput("Input left: ") else { - fmt::Println("Invalid left!") - continue - } - let r = numericInput("Input right: ") else { - fmt::Println("Invalid right!") - continue - } - fmt::Print("Choose your op: + - / *\nYour op: ") - let input = readln() - match input { - | "+": - fmt::Println(l + r) - | "-": - fmt::Println(l - r) - | "*": - fmt::Println(l * r) - | "/": - fmt::Println(l / r) - |: - fmt::Println("Invalid operation!") - } - } + for { + let l = numericInput("Input left: ") else { + fmt::Println("Invalid left!") + continue + } + let r = numericInput("Input right: ") else { + fmt::Println("Invalid right!") + continue + } + fmt::Print("Choose your op: + - / *\nYour op: ") + let input = readln() + match input { + | "+": + fmt::Println(l + r) + | "-": + fmt::Println(l - r) + | "*": + fmt::Println(l * r) + | "/": + fmt::Println(l / r) + |: + fmt::Println("Invalid operation!") + } + } } \ No newline at end of file diff --git a/tests/comptime/match.jule b/tests/comptime/match.jule index 8752a3991..72339d24b 100644 --- a/tests/comptime/match.jule +++ b/tests/comptime/match.jule @@ -5,58 +5,58 @@ use comptime for std::comptime fn match1() { - const match comptime::TypeOf(int) { - | comptime::TypeOf(&int): - outln("foo") - | comptime::TypeOf(bool): - outln("bar") - |: - outln("baz") - } + const match comptime::TypeOf(int) { + | comptime::TypeOf(&int): + outln("foo") + | comptime::TypeOf(bool): + outln("bar") + |: + outln("baz") + } } fn match2() { - const match 20 { - | 20: - outln("foo") - | 40: - outln("bar") - |: - outln("baz") - } + const match 20 { + | 20: + outln("foo") + | 40: + outln("bar") + |: + outln("baz") + } } fn match3() { - const match { - | false | false: - outln("foo") - | true | false: - outln("bar") - |: - outln("baz") - } + const match { + | false | false: + outln("foo") + | true | false: + outln("bar") + |: + outln("baz") + } } fn typeMatch1() { - const match type int { - | int: - outln("foo") - | bool: - outln("bar") - |: - outln("baz") - } + const match type int { + | int: + outln("foo") + | bool: + outln("bar") + |: + outln("baz") + } } fn typeMatch2() { - const match type comptime::TypeOf(int) { - | *int: - outln("foo") - | bool: - outln("bar") - |: - outln("baz") - } + const match type comptime::TypeOf(int) { + | *int: + outln("foo") + | bool: + outln("bar") + |: + outln("baz") + } } fn main() {} \ No newline at end of file diff --git a/tests/concurrency/main.jule b/tests/concurrency/main.jule index 46c44923b..e072cd804 100644 --- a/tests/concurrency/main.jule +++ b/tests/concurrency/main.jule @@ -8,20 +8,20 @@ use std::sync::atomic::{AtomicInt, MemoryOrder} static mut n: AtomicInt = AtomicInt.New(0) fn addToN(mut wg: *WaitGroup) { - unsafe defer { wg.Done() } - n.Add(1, MemoryOrder.Relaxed) + unsafe defer { wg.Done() } + n.Add(1, MemoryOrder.Relaxed) } fn main() { - let mut wg = WaitGroup{} + let mut wg = WaitGroup{} - let mut j = 0 - for j < 100; j++ { - wg.Add(1) - co addToN(&wg) - } + let mut j = 0 + for j < 100; j++ { + wg.Add(1) + co addToN(&wg) + } - wg.Wait() + wg.Wait() - outln(n.Load(MemoryOrder.Relaxed)) + outln(n.Load(MemoryOrder.Relaxed)) } \ No newline at end of file diff --git a/tests/exceptionals/main.jule b/tests/exceptionals/main.jule index 745f994cf..8ad3143a6 100644 --- a/tests/exceptionals/main.jule +++ b/tests/exceptionals/main.jule @@ -3,66 +3,66 @@ // license that can be found in the LICENSE file. fn successVoid()! { - outln("success void") + outln("success void") } fn failVoid()! { - error("not implemented") + error("not implemented") } fn successRet()!: int { - ret 20 + ret 20 } fn failRet()!: int { - error("not implemented") + error("not implemented") } fn successRet1()!: (a: int) { - a = 40 - ret + a = 40 + ret } fn failRet1()!: (a: int) { - error("not implemented") + error("not implemented") } fn successRet2()!: (a: int, b: int) { - a = 40 - b = 50 - ret + a = 40 + b = 50 + ret } fn failRet2()!: (a: int, b: int) { - error("not implemented") + error("not implemented") } fn main() { - successVoid() else { - panic("successVoid failed, should be success") - } - failVoid() else { - outln("handled error of failVoid") - } + successVoid() else { + panic("successVoid failed, should be success") + } + failVoid() else { + outln("handled error of failVoid") + } - successRet() else { - panic("successRet failed, should be success") - } - failRet() else { - outln("handled error of failRet") - } + successRet() else { + panic("successRet failed, should be success") + } + failRet() else { + outln("handled error of failRet") + } - successRet1() else { - panic("successRet1 failed, should be success") - } - failRet1() else { - outln("handled error of failRet1") - } + successRet1() else { + panic("successRet1 failed, should be success") + } + failRet1() else { + outln("handled error of failRet1") + } - successRet2() else { - panic("success_ret2 failed, should be success") - } - failRet2() else { - outln("handled error of failRet2") - } + successRet2() else { + panic("success_ret2 failed, should be success") + } + failRet2() else { + outln("handled error of failRet2") + } } \ No newline at end of file diff --git a/tests/generics/main.jule b/tests/generics/main.jule index 2323774d5..d929dc93a 100644 --- a/tests/generics/main.jule +++ b/tests/generics/main.jule @@ -5,42 +5,42 @@ // Reports index of x in s. // Returns -1 if x is not exist in s. fn find[T](s: []T, x: T): int { - for i, y in s { - if y == x { - ret i - } - } - ret -1 + for i, y in s { + if y == x { + ret i + } + } + ret -1 } // Reports whether x exist in s. fn exist[T](s: []T, x: T): bool { - ret find[T](s, x) != -1 + ret find[T](s, x) != -1 } // Utils for slices. struct Slice[T] {} impl Slice { - // Forwards to exist function. - static fn exist(s: []T, x: T): bool { - ret exist[T](s, x) - } + // Forwards to exist function. + static fn exist(s: []T, x: T): bool { + ret exist[T](s, x) + } - // Forwats to find function. - static fn find(s: []T, x: T): int { - ret find[T](s, x) - } + // Forwats to find function. + static fn find(s: []T, x: T): int { + ret find[T](s, x) + } } fn main() { - let s = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - outln(exist(s, 20)) - outln(exist[int](s, 4)) - outln(Slice[int].exist(s, 20)) - outln(Slice[int].exist(s, 4)) - outln(find(s, 20)) - outln(find[int](s, 4)) - outln(Slice[int].find(s, 20)) - outln(Slice[int].find(s, 4)) + let s = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + outln(exist(s, 20)) + outln(exist[int](s, 4)) + outln(Slice[int].exist(s, 20)) + outln(Slice[int].exist(s, 4)) + outln(find(s, 20)) + outln(find[int](s, 4)) + outln(Slice[int].find(s, 20)) + outln(Slice[int].find(s, 4)) } \ No newline at end of file diff --git a/tests/levenshtein_distance/main.jule b/tests/levenshtein_distance/main.jule index 3dc2ec9a1..5efa6fdbf 100644 --- a/tests/levenshtein_distance/main.jule +++ b/tests/levenshtein_distance/main.jule @@ -3,52 +3,52 @@ // license that can be found in the LICENSE file. fn min(values: ...int): int { - if len(values) == 0 { - ret 0 - } - let mut min = values[0] - for _, x in values[1:] { - if min > x { - min = x - } - } - ret min + if len(values) == 0 { + ret 0 + } + let mut min = values[0] + for _, x in values[1:] { + if min > x { + min = x + } + } + ret min } fn levenshteinDistance(s1: str, s2: str): int { - if s1 == s2 { - ret 0 - } - if len(s1) == 0 { - ret len(s2) - } - if len(s2) == 0 { - ret len(s1) - } - let v_len = len(s2) + 1 - let mut v0 = make([]int, v_len) - let mut v1 = make([]int, v_len) - let mut i = 0 - for i < v_len; i++ { - v0[i] = i - } - i = 0 - for i < len(s1); i++ { - v1[0] = i + 1 - let mut j = 0 - for j < len(s2); j++ { - let mut cost = 1 - if s1[i] == s2[j] { - cost = 0 - } - v1[j+1] = min(v1[j] + 1, v0[j+1] + 1, v0[j] + cost) - } - v0, v1 = v1, v0 - } - ret v0[len(s2)] + if s1 == s2 { + ret 0 + } + if len(s1) == 0 { + ret len(s2) + } + if len(s2) == 0 { + ret len(s1) + } + let v_len = len(s2) + 1 + let mut v0 = make([]int, v_len) + let mut v1 = make([]int, v_len) + let mut i = 0 + for i < v_len; i++ { + v0[i] = i + } + i = 0 + for i < len(s1); i++ { + v1[0] = i + 1 + let mut j = 0 + for j < len(s2); j++ { + let mut cost = 1 + if s1[i] == s2[j] { + cost = 0 + } + v1[j+1] = min(v1[j] + 1, v0[j+1] + 1, v0[j] + cost) + } + v0, v1 = v1, v0 + } + ret v0[len(s2)] } fn main() { - let mut d = levenshteinDistance("Levenshtein", "Distance") - outln(d) + let mut d = levenshteinDistance("Levenshtein", "Distance") + outln(d) } \ No newline at end of file diff --git a/tests/maps/main.jule b/tests/maps/main.jule index 2ddd51098..3324140a5 100644 --- a/tests/maps/main.jule +++ b/tests/maps/main.jule @@ -3,24 +3,24 @@ // license that can be found in the LICENSE file. fn main() { - let mut m: map[i32]str = { - 0: "The", - 1: "Jule", - 2: "Programming", - 3: "Language", - } - for key, value in m { - out(key) - out(": ") - outln(value) - } - outln(len(m)) - let mut ok = false - _, ok = m[0] - outln(ok) - _, ok = m[10] - outln(ok) - delete(m, 3) - delete(m) - outln(len(m)) + let mut m: map[i32]str = { + 0: "The", + 1: "Jule", + 2: "Programming", + 3: "Language", + } + for key, value in m { + out(key) + out(": ") + outln(value) + } + outln(len(m)) + let mut ok = false + _, ok = m[0] + outln(ok) + _, ok = m[10] + outln(ok) + delete(m, 3) + delete(m) + outln(len(m)) } \ No newline at end of file diff --git a/tests/operator_overloading/main.jule b/tests/operator_overloading/main.jule index 4f3ff01f1..e245fcbc3 100644 --- a/tests/operator_overloading/main.jule +++ b/tests/operator_overloading/main.jule @@ -2,193 +2,193 @@ // Use of this source code is governed by a BSD 3-Clause // license that can be found in the LICENSE file. struct Int { - x: int + x: int } impl Int { - fn Add(self, y: Int): Int { - ret Int{self.x + y.x} - } + fn Add(self, y: Int): Int { + ret Int{self.x + y.x} + } - fn AddAssign(mut self, y: Int) { - self.x += y.x - } + fn AddAssign(mut self, y: Int) { + self.x += y.x + } - fn Sub(self, y: Int): Int { - ret Int{self.x - y.x} - } + fn Sub(self, y: Int): Int { + ret Int{self.x - y.x} + } - fn SubAssign(mut self, y: Int) { - self.x -= y.x - } + fn SubAssign(mut self, y: Int) { + self.x -= y.x + } - fn Mul(self, y: Int): Int { - ret Int{self.x * y.x} - } + fn Mul(self, y: Int): Int { + ret Int{self.x * y.x} + } - fn MulAssign(mut self, y: Int) { - self.x *= y.x - } + fn MulAssign(mut self, y: Int) { + self.x *= y.x + } - fn Div(self, y: Int): Int { - ret Int{self.x / y.x} - } + fn Div(self, y: Int): Int { + ret Int{self.x / y.x} + } - fn DivAssign(mut self, y: Int) { - self.x /= y.x - } + fn DivAssign(mut self, y: Int) { + self.x /= y.x + } - fn Mod(self, y: Int): Int { - ret Int{self.x % y.x} - } + fn Mod(self, y: Int): Int { + ret Int{self.x % y.x} + } - fn ModAssign(mut self, y: Int) { - self.x %= y.x - } + fn ModAssign(mut self, y: Int) { + self.x %= y.x + } - fn Shl(self, y: Int): Int { - ret Int{self.x << y.x} - } + fn Shl(self, y: Int): Int { + ret Int{self.x << y.x} + } - fn ShlAssign(mut self, y: Int) { - self.x <<= y.x - } + fn ShlAssign(mut self, y: Int) { + self.x <<= y.x + } - fn Shr(self, y: Int): Int { - ret Int{self.x >> y.x} - } + fn Shr(self, y: Int): Int { + ret Int{self.x >> y.x} + } - fn ShrAssign(mut self, y: Int) { - self.x >>= y.x - } + fn ShrAssign(mut self, y: Int) { + self.x >>= y.x + } - fn BitOr(self, y: Int): Int { - ret Int{self.x | y.x} - } + fn BitOr(self, y: Int): Int { + ret Int{self.x | y.x} + } - fn BitOrAssign(mut self, y: Int) { - self.x |= y.x - } + fn BitOrAssign(mut self, y: Int) { + self.x |= y.x + } - fn BitAnd(self, y: Int): Int { - ret Int{self.x & y.x} - } + fn BitAnd(self, y: Int): Int { + ret Int{self.x & y.x} + } - fn BitAndAssign(mut self, y: Int) { - self.x &= y.x - } + fn BitAndAssign(mut self, y: Int) { + self.x &= y.x + } - fn BitXor(self, y: Int): Int { - ret Int{self.x ^ y.x} - } + fn BitXor(self, y: Int): Int { + ret Int{self.x ^ y.x} + } - fn BitXorAssign(mut self, y: Int) { - self.x ^= y.x - } + fn BitXorAssign(mut self, y: Int) { + self.x ^= y.x + } - fn BitNot(self): Int { - ret Int{^self.x} - } + fn BitNot(self): Int { + ret Int{^self.x} + } - fn Neg(self): Int { - ret Int{-self.x} - } + fn Neg(self): Int { + ret Int{-self.x} + } - fn Pos(self): Int { - ret Int{+self.x} - } + fn Pos(self): Int { + ret Int{+self.x} + } } struct Number[T] { - x: T + x: T } impl Number { - fn Add(self, y: Number[T]): Number[T] { - ret Number[T]{self.x + y.x} - } + fn Add(self, y: Number[T]): Number[T] { + ret Number[T]{self.x + y.x} + } - fn AddAssign(mut self, y: Number[T]) { - self.x += y.x - } + fn AddAssign(mut self, y: Number[T]) { + self.x += y.x + } - fn Sub(self, y: Number[T]): Number[T] { - ret Number[T]{self.x - y.x} - } + fn Sub(self, y: Number[T]): Number[T] { + ret Number[T]{self.x - y.x} + } - fn SubAssign(mut self, y: Number[T]) { - self.x -= y.x - } + fn SubAssign(mut self, y: Number[T]) { + self.x -= y.x + } - fn Mul(self, y: Number[T]): Number[T] { - ret Number[T]{self.x * y.x} - } + fn Mul(self, y: Number[T]): Number[T] { + ret Number[T]{self.x * y.x} + } - fn MulAssign(mut self, y: Number[T]) { - self.x *= y.x - } + fn MulAssign(mut self, y: Number[T]) { + self.x *= y.x + } - fn Div(self, y: Number[T]): Number[T] { - ret Number[T]{self.x / y.x} - } + fn Div(self, y: Number[T]): Number[T] { + ret Number[T]{self.x / y.x} + } - fn DivAssign(mut self, y: Number[T]) { - self.x /= y.x - } + fn DivAssign(mut self, y: Number[T]) { + self.x /= y.x + } - fn Neg(self): Number[T] { - ret Number[T]{-self.x} - } + fn Neg(self): Number[T] { + ret Number[T]{-self.x} + } - fn Pos(self): Number[T] { - ret Number[T]{+self.x} - } + fn Pos(self): Number[T] { + ret Number[T]{+self.x} + } } fn testInt() { - let mut x = Int{10} - let y = Int{20} - _ = x + y - x += y - _ = x - y - x -= y - _ = x * y - x *= y - _ = x / y - x /= y - _ = x % y - x %= y - _ = x << y - x <<= y - _ = x >> y - x >>= y - _ = x | y - x |= y - _ = x & y - x &= y - _ = x ^ y - x ^= y - _ = ^x - _ = -x - _ = +x + let mut x = Int{10} + let y = Int{20} + _ = x + y + x += y + _ = x - y + x -= y + _ = x * y + x *= y + _ = x / y + x /= y + _ = x % y + x %= y + _ = x << y + x <<= y + _ = x >> y + x >>= y + _ = x | y + x |= y + _ = x & y + x &= y + _ = x ^ y + x ^= y + _ = ^x + _ = -x + _ = +x } fn testNumber() { - let mut x = Number[f64]{10} - let y = Number[f64]{20} - _ = x + y - x += y - _ = x - y - x -= y - _ = x * y - x *= y - _ = x / y - x /= y - _ = -x - _ = +x + let mut x = Number[f64]{10} + let y = Number[f64]{20} + _ = x + y + x += y + _ = x - y + x -= y + _ = x * y + x *= y + _ = x / y + x /= y + _ = -x + _ = +x } fn main() { - testInt() - testNumber() + testInt() + testNumber() } \ No newline at end of file diff --git a/tests/quicksort/main.jule b/tests/quicksort/main.jule index b3e40abe6..b411c10ca 100644 --- a/tests/quicksort/main.jule +++ b/tests/quicksort/main.jule @@ -3,28 +3,28 @@ // license that can be found in the LICENSE file. fn quicksort(mut s: []int) { - if len(s) <= 1 { - ret - } + if len(s) <= 1 { + ret + } - let mut i = -1 - let last = s[len(s)-1] - for j in s { - let mut x = &s[j] - if (unsafe { *x <= last }) { - i++ - let mut y = &s[i] - unsafe { *x, *y = *y, *x } - } - } + let mut i = -1 + let last = s[len(s)-1] + for j in s { + let mut x = &s[j] + if (unsafe { *x <= last }) { + i++ + let mut y = &s[i] + unsafe { *x, *y = *y, *x } + } + } - quicksort(s[:i]) - quicksort(s[i+1:]) + quicksort(s[:i]) + quicksort(s[i+1:]) } fn main() { - let mut my_slice = [1, 9, -2, 25, -24, 4623, 0, -1, 0xFD2] - outln(my_slice) - quicksort(my_slice) - outln(my_slice) + let mut my_slice = [1, 9, -2, 25, -24, 4623, 0, -1, 0xFD2] + outln(my_slice) + quicksort(my_slice) + outln(my_slice) } \ No newline at end of file diff --git a/tests/sleep/main.jule b/tests/sleep/main.jule index fffb54cf0..48f1473c5 100644 --- a/tests/sleep/main.jule +++ b/tests/sleep/main.jule @@ -6,14 +6,14 @@ use std::math::rand::{Rand} use time for std::time::{Time, Duration} fn main() { - let mut rand = Rand.New(Time.Now().Unix()) - let mut i = 0 - for i < 10; i++ { - let dur = Duration.Millisecond * rand.Nextn63(1000) - out("Sleeping for ") - out(Duration.Milliseconds(dur)) - outln("ms") - time::Sleep(dur) - } - outln("Done!") + let mut rand = Rand.New(Time.Now().Unix()) + let mut i = 0 + for i < 10; i++ { + let dur = Duration.Millisecond * rand.Nextn63(1000) + out("Sleeping for ") + out(Duration.Milliseconds(dur)) + outln("ms") + time::Sleep(dur) + } + outln("Done!") } \ No newline at end of file diff --git a/tests/syntax/main.jule b/tests/syntax/main.jule index 7a1de974e..9f344fad8 100644 --- a/tests/syntax/main.jule +++ b/tests/syntax/main.jule @@ -13,136 +13,136 @@ fn testPlainTypeParameters1(_: integ::Int, _: integ::Int) {} fn testPlainTypeParameters2(&_: integ::Int, &_: integ::Int) {} fn testStringConcat() { - _ = "Hello" + " " + "World!" + _ = "Hello" + " " + "World!" } fn testIntergers() { - _ = 13e+1 - _ = 3536 - _ = 0x0FDDA24 - _ = 05353 + _ = 13e+1 + _ = 3536 + _ = 0x0FDDA24 + _ = 05353 } fn testVariable() { - let a: int = 0 - _ = a - let mut x = 10 - x = 100 - outln(x) - b := 20 - &c := a - mut z := 20 - mut &k := x - _ = b, c, z, k + let a: int = 0 + _ = a + let mut x = 10 + x = 100 + outln(x) + b := 20 + &c := a + mut z := 20 + mut &k := x + _ = b, c, z, k } fn testAssignment() { - let mut x = 10 - x += 100 + let mut x = 10 + x += 100 } fn testSlice() { - let my_slice = [ - ["Apple", "Banana"], - ["Bred", "Cheese"], - ] - outln( - my_slice[0]) + let my_slice = [ + ["Apple", "Banana"], + ["Bred", "Cheese"], + ] + outln( + my_slice[0]) } fn testArray() { - let my_array: [2][3]str = [ - ["Apple", "Banana", "TEST"], - ["Bred", "Cheese", "BLA"], - ] - outln( - my_array[0]) + let my_array: [2][3]str = [ + ["Apple", "Banana", "TEST"], + ["Bred", "Cheese", "BLA"], + ] + outln( + my_array[0]) } fn testAnonymousFunction() { - let myFunc: fn() = fn() { - outln("Hello World!") - } - myFunc() - let rf = fn(): i32 { - ret 90 - }() - _ = rf - fn() { - outln("Anonymous Outln") - }() - let a = 0 - _ = a + let myFunc: fn() = fn() { + outln("Hello World!") + } + myFunc() + let rf = fn(): i32 { + ret 90 + }() + _ = rf + fn() { + outln("Anonymous Outln") + }() + let a = 0 + _ = a } fn testMultipleVariable() { - let (mut a, mut b, _, c) = 100, 200, nil, false - _ = c - a, b = 10, 20 - a, b = b, a - outln(a) - outln(b) - a, b, _ = testMultipleReturn() + let (mut a, mut b, _, c) = 100, 200, nil, false + _ = c + a, b = 10, 20 + a, b = b, a + outln(a) + outln(b) + a, b, _ = testMultipleReturn() } fn testMultipleReturn(): (int, int, bool) { ret 5, 5, false } fn testIter() { - // Infinity iteration - for { - break - continue - } - - // While iteration - for !false { - break - } - - // Foreach iteration - for in "Hello" { - outln("Jule") - } - - for index in "Hello" { - outln(index) - } - - for _, c in "Hello" { - outln(c) - } - - for _, element in ["The", "Jule", "Programming", "Language"] { - outln(element) - } - - for index in "TEST" { - _ = index - } - - for { break } - - let mut a = 0 - for a <= 3; a++ { - outln(a) - } + // Infinity iteration + for { + break + continue + } + + // While iteration + for !false { + break + } + + // Foreach iteration + for in "Hello" { + outln("Jule") + } + + for index in "Hello" { + outln(index) + } + + for _, c in "Hello" { + outln(c) + } + + for _, element in ["The", "Jule", "Programming", "Language"] { + outln(element) + } + + for index in "TEST" { + _ = index + } + + for { break } + + let mut a = 0 + for a <= 3; a++ { + outln(a) + } } fn testIfExpressions() { - if true { - outln("IF") - } else if true { - outln("ELSE_IF0") - } else if false { - outln("ELSE_IF_1") - if true == true { - outln("ELSE_IF_1_IF") - } else { - outln("ELSE") - } - } else { - outln("ELSE") - } + if true { + outln("IF") + } else if true { + outln("ELSE_IF0") + } else if false { + outln("ELSE_IF_1") + if true == true { + outln("ELSE_IF_1_IF") + } else { + outln("ELSE") + } + } else { + outln("ELSE") + } } fn testParameters(a: i32, b: bool) {} @@ -150,107 +150,107 @@ fn testParameters(a: i32, b: bool) {} fn testParameters2(a: i32, b: i32, c: bool, d: bool) {} fn testVariadicParameters(lnEvery: bool, values: ...i32) { - for _, i in values { - if lnEvery { - outln(i) - } else { - out(i) - } - } + for _, i in values { + if lnEvery { + outln(i) + } else { + out(i) + } + } } fn testVariadicParameters2(...str) {} fn testCasting() { - let a: *int = nil - _ = uintptr(a) - _ = f32(5000) - let bytes = []byte("Hello Bytes") - outln(bytes) - outln(str(bytes)) + let a: *int = nil + _ = uintptr(a) + _ = f32(5000) + let bytes = []byte("Hello Bytes") + outln(bytes) + outln(str(bytes)) } fn testRawString() { - _ = `Hello + _ = `Hello raw` - _ = ` + _ = ` strings` } fn testMap() { - let mut m: map[int]str = { - 0: "The", - 1: "Jule", - 2: "Programming", - 3: "Language", - } - m[4] = "Maps" - outln(m) - for key, value in m { - out(key) - out(": ") - outln(value) - } + let mut m: map[int]str = { + 0: "The", + 1: "Jule", + 2: "Programming", + 3: "Language", + } + m[4] = "Maps" + outln(m) + for key, value in m { + out(key) + out(": ") + outln(value) + } } fn testInblockTypeAlias() { - type integer: i32 - let x: integer = 10 - _ = x + type integer: i32 + let x: integer = 10 + _ = x } fn testInblockBlock() { - { - outln("INBLOCK_BLOCK") - } + { + outln("INBLOCK_BLOCK") + } } fn testGoto() { - let s = "Hello World" - { - let mut ok = false - { - if !ok { - ok = true - goto bla - } - goto test - } - bla: - outln(ok) - } + let s = "Hello World" + { + let mut ok = false + { + if !ok { + ok = true + goto bla + } + goto test + } + bla: + outln(ok) + } test: - { - outln("TEST") - goto end - } - outln(s) + { + outln("TEST") + goto end + } + outln(s) end: } enum testEnum { - item1, - item2, - item3: 369, - item4, + item1, + item2, + item3: 369, + item4, } struct testStruct { - a: str - b: i32 - c: byte - d: bool + a: str + b: i32 + c: byte + d: bool } impl testStruct { - fn func1(mut self) { - self.a = "test" - } + fn func1(mut self) { + self.a = "test" + } - fn func2[T1](mut self) { - self.d = !self.d - } + fn func2[T1](mut self) { + self.d = !self.d + } } fn testGenericFunc[T](a: T, b: T): T { ret a + b } @@ -258,65 +258,65 @@ fn testGenericFunc[T](a: T, b: T): T { ret a + b } fn testRetVars(): (x: int) { ret } fn testPostfix() { - let mut a = 10 - a++ - a-- + let mut a = 10 + a++ + a-- } fn testMatchCase() { - match 10 { - | 1: - outln("one") - | 2: - outln("two") - |: - outln("default") - } - - match { - | false: - outln("false") - | !true: - outln("!true") - | false | true: - outln("false, true") - |: - outln("default") - } + match 10 { + | 1: + outln("one") + | 2: + outln("two") + |: + outln("default") + } + + match { + | false: + outln("false") + | !true: + outln("!true") + | false | true: + outln("false, true") + |: + outln("default") + } } fn init() { - outln("Syntax Test") + outln("Syntax Test") } // Entry point function of program. fn main() { - testIntergers() - testStringConcat() - testVariable() - testAssignment() - testSlice() - testArray() - testAnonymousFunction() - testMultipleVariable() - testIter() - testIfExpressions() - testParameters(24, false) - testParameters2(24, 52, true, false) - testVariadicParameters(true) - testVariadicParameters(true, 10, 20) - testVariadicParameters(!false, [i32(1), 2, 3, 4, 5]...) - testVariadicParameters2() - testVariadicParameters2("TEST", "TEST_1") - testCasting() - testRawString() - testMap() - testInblockTypeAlias() - testInblockBlock() - testGoto() - outln(testEnum.item3) - testGenericFunc[int](2, -30) - testGenericFunc[uint](6, 2) - testGenericFunc[f64](4.2, 35.23) - testMatchCase() + testIntergers() + testStringConcat() + testVariable() + testAssignment() + testSlice() + testArray() + testAnonymousFunction() + testMultipleVariable() + testIter() + testIfExpressions() + testParameters(24, false) + testParameters2(24, 52, true, false) + testVariadicParameters(true) + testVariadicParameters(true, 10, 20) + testVariadicParameters(!false, [i32(1), 2, 3, 4, 5]...) + testVariadicParameters2() + testVariadicParameters2("TEST", "TEST_1") + testCasting() + testRawString() + testMap() + testInblockTypeAlias() + testInblockBlock() + testGoto() + outln(testEnum.item3) + testGenericFunc[int](2, -30) + testGenericFunc[uint](6, 2) + testGenericFunc[f64](4.2, 35.23) + testMatchCase() } \ No newline at end of file diff --git a/tests/traits/main.jule b/tests/traits/main.jule index 363383f47..1df17eb02 100644 --- a/tests/traits/main.jule +++ b/tests/traits/main.jule @@ -1,37 +1,37 @@ -// Copyright 2022-2024 The Jule Programming Language. -// Use of this source code is governed by a BSD 3-Clause -// license that can be found in the LICENSE file. - -use std::math::{Pi} - -trait Shape { - fn area(self): f32 -} - -struct Rectangle { - width: int - height: int -} - -impl Shape for Rectangle { - fn area(self): f32 { - ret f32(self.width * self.height) - } -} - -struct Circle { - r: f32 -} - -impl Shape for Circle { - fn area(self): f32 { - ret Pi * self.r * self.r - } -} - -fn main() { - let rect: Shape = Rectangle{90, 5} - let circ: Shape = Circle{90.5} - outln(rect.area()) - outln(circ.area()) -} +// Copyright 2022-2024 The Jule Programming Language. +// Use of this source code is governed by a BSD 3-Clause +// license that can be found in the LICENSE file. + +use std::math::{Pi} + +trait Shape { + fn area(self): f32 +} + +struct Rectangle { + width: int + height: int +} + +impl Shape for Rectangle { + fn area(self): f32 { + ret f32(self.width * self.height) + } +} + +struct Circle { + r: f32 +} + +impl Shape for Circle { + fn area(self): f32 { + ret Pi * self.r * self.r + } +} + +fn main() { + let rect: Shape = Rectangle{90, 5} + let circ: Shape = Circle{90.5} + outln(rect.area()) + outln(circ.area()) +} \ No newline at end of file