From f3d6dd04c465cce710f60f4618b9ae61c7bbcc10 Mon Sep 17 00:00:00 2001 From: mertcandav Date: Tue, 5 Mar 2024 16:05:24 +0300 Subject: [PATCH] std::conv: use exceptionals instead of returning error code --- std/conv/atob.jule | 10 +++---- std/conv/atof.jule | 15 ++++++---- std/conv/atoi.jule | 49 ++++++++++++++++---------------- std/conv/error.jule | 2 +- std/conv/itoa.jule | 2 +- std/flag/flag.jule | 17 ++--------- std/jule/constant/lit/bytes.jule | 15 +++------- std/jule/sema/eval.jule | 18 ++++++------ std/jule/types/bits.jule | 12 ++++---- tests/basic_calculator/main.jule | 12 ++++++-- 10 files changed, 71 insertions(+), 81 deletions(-) diff --git a/std/conv/atob.jule b/std/conv/atob.jule index b500212c6..daa02ca47 100644 --- a/std/conv/atob.jule +++ b/std/conv/atob.jule @@ -37,15 +37,15 @@ // Returns the boolean value represented by the string. // It accepts 1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False. -// Any other value returns an error. -pub fn conv_bool(s: str): (bool, ConvError) { +// Any other value throws exception. +pub fn conv_bool(s: str)!: bool { match s { | "1" | "t" | "T" | "true" | "TRUE" | "True": - ret true, ConvError.Ok + ret true | "0" | "f" | "F" | "false" | "FALSE" | "False": - ret false, ConvError.Ok + ret false |: - ret false, ConvError.InvalidSyntax + error(ConvError.InvalidSyntax) } } diff --git a/std/conv/atof.jule b/std/conv/atof.jule index b005d46f9..6b91c43d0 100644 --- a/std/conv/atof.jule +++ b/std/conv/atof.jule @@ -753,20 +753,23 @@ fn parse_float_prefix(s: str, bit_size: int): (f64, int, ConvError) { // there are more bits in the hexadecimal representation than // will fit in the mantissa.) // -// The errors that returns have concrete type ConvError. +// The exceptional errors that have concrete type ConvError. // -// If s is not syntactically well-formed, returns err = ConvError.InvalidSyntax. +// If s is not syntactically well-formed, throws exception = ConvError.InvalidSyntax. // // If s is syntactically well-formed but is more than 1/2 ULP // away from the largest floating point number of the given size, -// Returns f = ±inf, err = ConvError.OutOfRange. +// Exceptional = ConvError.OutOfRange. // // Recognizes the string "nan", and the (possibly signed) strings "inf" and "infinity" // as their respective special floating point values. It ignores case when matching. -pub fn parse_float(s: str, bit_size: int): (f64, ConvError) { +pub fn parse_float(s: str, bit_size: int)!: f64 { let (f, n, err) = parse_float_prefix(s, bit_size) if n != s.len && (err == ConvError.Ok || err != ConvError.InvalidSyntax) { - ret 0, ConvError.InvalidSyntax + error(ConvError.InvalidSyntax) } - ret f, err + if err != ConvError.Ok { + error(err) + } + ret f } diff --git a/std/conv/atoi.jule b/std/conv/atoi.jule index a769feadc..b62494b1d 100644 --- a/std/conv/atoi.jule +++ b/std/conv/atoi.jule @@ -48,10 +48,7 @@ fn lower(c: byte): byte { ret c | ('x' - 'X') } -// Is like parse_int but for unsigned numbers. -// -// A sign prefix is not permitted. -pub fn parse_uint(mut s: str, mut base: int, mut bit_size: int): (u64, ConvError) { +fn __parse_uint(mut s: str, mut base: int, mut bit_size: int): (u64, ConvError) { if s == "" { ret 0, ConvError.InvalidSyntax } @@ -107,12 +104,6 @@ pub fn parse_uint(mut s: str, mut base: int, mut bit_size: int): (u64, ConvError | 64: max_val = u64.MAX } - /* - let mut prec = 1 - if bit_size == 64 { - prec = 2 - } - let max_val = u64(1)<= cutoff { - ret i64(cutoff - 1), ConvError.OutOfRange + error(ConvError.OutOfRange) } if neg && un > cutoff { - ret -i64(cutoff), ConvError.OutOfRange + error(ConvError.OutOfRange) } let mut n = i64(un) if neg { n = -n } - ret n, ConvError.Ok + ret n } diff --git a/std/conv/error.jule b/std/conv/error.jule index 86346b58e..7f947da9c 100644 --- a/std/conv/error.jule +++ b/std/conv/error.jule @@ -4,7 +4,7 @@ // Error codes of conv package. pub enum ConvError { - Ok, // No problem. + 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. diff --git a/std/conv/itoa.jule b/std/conv/itoa.jule index 52dc890c9..440398928 100644 --- a/std/conv/itoa.jule +++ b/std/conv/itoa.jule @@ -173,7 +173,7 @@ fn fmt_bits(mut dst: []byte, mut u: u64, base: int, neg: bool, append_: bool): ( // 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. - let shift = uint(bits::trailing_zeros(uint(base))) & 7 + let shift = uint(bits::trailing_zeros(uint(base))) & 0b111 let b = u64(base) let m = uint(base) - 1 // == 1<= b { diff --git a/std/flag/flag.jule b/std/flag/flag.jule index dd265786a..8ebcb2a18 100644 --- a/std/flag/flag.jule +++ b/std/flag/flag.jule @@ -187,19 +187,14 @@ impl ArgParser { match { | s == "": ret 0, false - | strings::has_prefix(s, "0x"): // Hexadecimal x, ok = parser(s[2:], 0b00010000) - | strings::has_prefix(s, "0b"): // Binary x, ok = parser(s[2:], 0b10) - | strings::has_prefix(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) } @@ -231,30 +226,24 @@ impl ArgParser { | IntFlag: let mut intf = IntFlag(flag) let ((*intf._data), ok) = self.parse_integer[i64](data, fn(s: str, base: int): (i64, bool) { - let (x, err) = conv::parse_int(s, base, BIT64) - ret x, err == conv::ConvError.Ok + ret conv::parse_int(s, base, BIT64) else { ret 0, false }, true }) if !ok { error("--" + flag.name() + ": expression must be valid signed integer") } - | UintFlag: let mut uintf = UintFlag(flag) let ((*uintf._data), ok) = self.parse_integer[u64](data, fn(s: str, base: int): (u64, bool) { - let (x, err) = conv::parse_uint(s, base, BIT64) - ret x, err == conv::ConvError.Ok + ret conv::parse_uint(s, base, BIT64) else { ret 0, false }, true }) if !ok { error("--" + flag.name() + ": expression must be valid unsigned integer") } - | FloatFlag: let mut ff = FloatFlag(flag) - let ((*ff._data), err) = conv::parse_float(data, BIT64) - if err != conv::ConvError.Ok { + *ff._data = conv::parse_float(data, BIT64) else { error("--" + flag.name() + ": expression must be valid floating-point") } - | StrFlag: *StrFlag(flag)._data = data } diff --git a/std/jule/constant/lit/bytes.jule b/std/jule/constant/lit/bytes.jule index a5b35daed..774110b4b 100644 --- a/std/jule/constant/lit/bytes.jule +++ b/std/jule/constant/lit/bytes.jule @@ -92,31 +92,24 @@ fn rune_from_esq_seq(bytes: []byte, mut &i: int): rune { match bytes[i] { | 'u': const SEQ_LEN = 5 - let (rc, _) = conv::parse_uint(str(bytes[i+1:i+SEQ_LEN]), 16, 64) + let r = rune(conv::parse_uint(str(bytes[i+1:i+SEQ_LEN]), 16, 64)!) i += SEQ_LEN - let r = rune(rc) ret r - | 'U': const SEQ_LEN = 9 - let (rc, _) = conv::parse_uint(str(bytes[i+1:i+SEQ_LEN]), 16, 64) + let r = rune(conv::parse_uint(str(bytes[i+1:i+SEQ_LEN]), 16, 64)!) i += SEQ_LEN - let r = rune(rc) ret r - | 'x': const SEQ_LEN = 3 let seq = bytes[i+1:i+SEQ_LEN] i += SEQ_LEN - let (b, _) = conv::parse_uint(str(seq), 16, 64) - ret rune(b) - + ret rune(conv::parse_uint(str(seq), 16, 64)!) |: const SEQ_LEN = 3 let seq = bytes[i : i+SEQ_LEN] i += SEQ_LEN - let (b, _) = conv::parse_uint(str(seq[1:]), 8, 64) - ret rune(b) + ret rune(conv::parse_uint(str(seq[1:]), 8, 64)!) } } diff --git a/std/jule/sema/eval.jule b/std/jule/sema/eval.jule index c15603749..da387e52d 100644 --- a/std/jule/sema/eval.jule +++ b/std/jule/sema/eval.jule @@ -464,7 +464,7 @@ impl Eval { fn lit_float(self, &l: &LitExpr): &Data { const FLOAT_KIND: str = PrimKind.F64 - let (f, _) = parse_float(l.value, 64) + let f = parse_float(l.value, 64) else { use f64.MAX } let mut constant = Const.new_f64(f) ret &Data{ @@ -489,19 +489,15 @@ impl Eval { | strings::has_prefix(lit, "0x"): // Hexadecimal lit = lit[2:] base = 0b00010000 - | strings::has_prefix(lit, "0b"): // Binary lit = lit[2:] base = 0b10 - | strings::has_prefix(lit, "0o"): // Ocatal lit = lit[2:] base = 0b1000 - | lit[0] == '0' && lit.len > 1: // Octal lit = lit[1:] base = 0b1000 - |: // Decimal base = 0b1010 } @@ -512,17 +508,21 @@ impl Eval { decl: false, } - let (sig, err) = parse_int(lit, base, BIT_SIZE) - if err == ConvError.Ok { + let mut ok = true + let sig = parse_int(lit, base, BIT_SIZE) else { + ok = false + use 0 + } + if ok { d.constant = Const.new_i64(sig) d.kind = &TypeKind{ kind: build_prim_type(PrimKind.Int), } } else { - let (unsig, err) = parse_uint(lit, base, BIT_SIZE) - if err != ConvError.Ok { + let unsig = parse_uint(lit, base, BIT_SIZE) else { self.push_err(l.token, LogMsg.InvalidNumericRange) self.push_suggestion(LogMsg.TryFloatingPoint) + use u64.MAX } d.constant = Const.new_u64(unsig) d.kind = &TypeKind{ diff --git a/std/jule/types/bits.jule b/std/jule/types/bits.jule index 0bb96ddde..2897ab79b 100644 --- a/std/jule/types/bits.jule +++ b/std/jule/types/bits.jule @@ -100,23 +100,23 @@ pub fn float_from_bits(bits: u64): str { // Reports whether signed integer literal is compatible given bit-size. pub fn check_bit_int(v: str, bit: int): bool { ret check_bit(v, bit, fn(v: str, base: int, bit: int): bool { - let (_, err) = conv::parse_int(v, base, bit) - ret err == conv::ConvError.Ok + _ = conv::parse_int(v, base, bit) else { ret false } + ret true }) } // Reports whether unsigned integer literal is compatible given bit-size. pub fn check_bit_uint(v: str, bit: int): bool { ret check_bit(v, bit, fn(v: str, base: int, bit: int): bool { - let (_, err) = conv::parse_uint(v, base, bit) - ret err == conv::ConvError.Ok + _ = conv::parse_uint(v, base, bit) else { ret false } + ret true }) } // Reports whether float literal is compatible given bit-size. pub fn check_bit_float(val: str, bit: int): bool { - let (_, err) = conv::parse_float(val, bit) - ret err == conv::ConvError.Ok + _ = conv::parse_float(val, bit) else { ret false } + ret true } // Reports minimum bit-size of given floating-point. diff --git a/tests/basic_calculator/main.jule b/tests/basic_calculator/main.jule index 614f63d36..6c27fb3bb 100644 --- a/tests/basic_calculator/main.jule +++ b/tests/basic_calculator/main.jule @@ -8,14 +8,20 @@ use io for std::io fn readln(): str { let scanner = io::Scanner.newf(io::stdin()) - ret if (scanner.scan() else { use false }) { scanner.text() } else { "" } + if (scanner.scan() else { use false }) { + ret scanner.text() + } + ret "" } fn numeric_input(msg: str): (f64, ok: bool) { fmt::print(msg) + ok = true let input = readln() - let (flt, err) = conv::parse_float(input, 64) - ok = err == conv::ConvError.Ok + let flt = conv::parse_float(input, 64) else { + ok = false + use 0 + } ret flt, ok }