aboutsummaryrefslogtreecommitdiff
path: root/src/stdlib
diff options
context:
space:
mode:
Diffstat (limited to 'src/stdlib')
-rw-r--r--src/stdlib/bigint.c119
-rw-r--r--src/stdlib/bigint.h2
-rw-r--r--src/stdlib/bytes.c4
-rw-r--r--src/stdlib/bytes.h2
-rw-r--r--src/stdlib/cli.c10
-rw-r--r--src/stdlib/intX.c.h4
-rw-r--r--src/stdlib/intX.h2
7 files changed, 93 insertions, 50 deletions
diff --git a/src/stdlib/bigint.c b/src/stdlib/bigint.c
index 46957c2d..2d145bd5 100644
--- a/src/stdlib/bigint.c
+++ b/src/stdlib/bigint.c
@@ -393,55 +393,98 @@ PUREFUNC Closure_t Int$onward(Int_t first, Int_t step) {
}
public
-Int_t Int$from_str(const char *str) {
- mpz_t i;
- int result;
- if (strncmp(str, "0x", 2) == 0) {
- result = mpz_init_set_str(i, str + 2, 16);
- } else if (strncmp(str, "0o", 2) == 0) {
- result = mpz_init_set_str(i, str + 2, 8);
- } else if (strncmp(str, "0b", 2) == 0) {
- result = mpz_init_set_str(i, str + 2, 2);
- } else {
- result = mpz_init_set_str(i, str, 10);
- }
- if (result != 0) return NONE_INT;
- return Int$from_mpz(i);
-}
+Int_t Int$from_str(const char *str) { return Int$parse(Text$from_str(str), NONE_INT, NULL); }
public
-OptionalInt_t Int$parse(Text_t text, Text_t *remainder) {
+OptionalInt_t Int$parse(Text_t text, OptionalInt_t base, Text_t *remainder) {
const char *str = Text$as_c_string(text);
- mpz_t i;
- int result;
- if (strncmp(str, "0x", 2) == 0) {
- str += 2;
- const char *end = str + strspn(str, "0123456789abcdefABCDEF");
- if (remainder) *remainder = Text$from_str(end);
- else if (*end != '\0') return NONE_INT;
- result = mpz_init_set_str(i, String(string_slice(str, (size_t)(end - str))), 16);
+ bool negative = (*str == '-');
+ if (negative || *str == '+') str += 1;
+ const char *end = str;
+ int32_t base32;
+ if (base.small != 0) {
+ base32 = Int32$from_int(base, false);
+ switch (base32) {
+ case 16:
+ if (strncmp(str, "0x", 2) == 0) {
+ base16_prefix:
+ str += 2;
+ }
+ end = str + strspn(str, "0123456789abcdefABCDEF");
+ break;
+ case 10:
+ base10:
+ end = str + strspn(str, "0123456789");
+ break;
+ case 8:
+ if (strncmp(str, "0o", 2) == 0) {
+ base8_prefix:
+ str += 2;
+ }
+ end = str + strspn(str, "01234567");
+ break;
+ case 2:
+ if (strncmp(str, "0b", 2) == 0) {
+ base2_prefix:
+ str += 2;
+ }
+ end = str + strspn(str, "01");
+ break;
+ case 1: {
+ str += strspn(str, "0");
+ size_t n = strspn(str, "1");
+ end = str + n;
+ if (remainder) *remainder = Text$from_str(end);
+ else if (*end != '\0') return NONE_INT;
+ return Int$from_int64((int64_t)n);
+ }
+ default: {
+ if (base32 < 1 || base32 > 36) {
+ if (remainder) *remainder = text;
+ return NONE_INT;
+ }
+ for (; *end; end++) {
+ char c = *end;
+ int32_t digit;
+ if ('0' <= c && c <= '9') {
+ digit = (c - (int)'0');
+ } else if ('a' <= c && c <= 'z') {
+ digit = (c - (int)'a');
+ } else if ('A' <= c && c <= 'Z') {
+ digit = (c - (int)'A');
+ } else {
+ break;
+ }
+ if (digit >= base32) break;
+ }
+ }
+ }
+ } else if (strncmp(str, "0x", 2) == 0) {
+ base32 = 16;
+ goto base16_prefix;
} else if (strncmp(str, "0o", 2) == 0) {
- str += 2;
- const char *end = str + strspn(str, "01234567");
- if (remainder) *remainder = Text$from_str(end);
- else if (*end != '\0') return NONE_INT;
- result = mpz_init_set_str(i, String(string_slice(str, (size_t)(end - str))), 8);
+ base32 = 8;
+ goto base8_prefix;
} else if (strncmp(str, "0b", 2) == 0) {
- str += 2;
- const char *end = str + strspn(str, "01");
- if (remainder) *remainder = Text$from_str(end);
- else if (*end != '\0') return NONE_INT;
- result = mpz_init_set_str(i, String(string_slice(str, (size_t)(end - str))), 2);
+ base32 = 2;
+ goto base2_prefix;
} else {
- const char *end = str + strspn(str, "0123456789");
- if (remainder) *remainder = Text$from_str(end);
- else if (*end != '\0') return NONE_INT;
- result = mpz_init_set_str(i, String(string_slice(str, (size_t)(end - str))), 10);
+ base32 = 10;
+ goto base10;
}
+
+ if (remainder) *remainder = Text$from_str(end);
+ else if (*end != '\0') return NONE_INT;
+
+ mpz_t i;
+ int result = mpz_init_set_str(i, String(string_slice(str, (size_t)(end - str))), base32);
if (result != 0) {
if (remainder) *remainder = text;
return NONE_INT;
}
+ if (negative) {
+ mpz_neg(i, i);
+ }
return Int$from_mpz(i);
}
diff --git a/src/stdlib/bigint.h b/src/stdlib/bigint.h
index a00bdf2f..9ce4c800 100644
--- a/src/stdlib/bigint.h
+++ b/src/stdlib/bigint.h
@@ -23,7 +23,7 @@ Text_t Int$octal(Int_t i, Int_t digits, bool prefix);
PUREFUNC Closure_t Int$to(Int_t first, Int_t last, OptionalInt_t step);
PUREFUNC Closure_t Int$onward(Int_t first, Int_t step);
OptionalInt_t Int$from_str(const char *str);
-OptionalInt_t Int$parse(Text_t text, Text_t *remainder);
+OptionalInt_t Int$parse(Text_t text, OptionalInt_t base, Text_t *remainder);
Int_t Int$abs(Int_t x);
Int_t Int$power(Int_t base, Int_t exponent);
Int_t Int$gcd(Int_t x, Int_t y);
diff --git a/src/stdlib/bytes.c b/src/stdlib/bytes.c
index ab689ae4..4416d804 100644
--- a/src/stdlib/bytes.c
+++ b/src/stdlib/bytes.c
@@ -33,8 +33,8 @@ public
CONSTFUNC bool Byte$is_between(const Byte_t x, const Byte_t low, const Byte_t high) { return low <= x && x <= high; }
public
-OptionalByte_t Byte$parse(Text_t text, Text_t *remainder) {
- OptionalInt_t full_int = Int$parse(text, remainder);
+OptionalByte_t Byte$parse(Text_t text, OptionalInt_t base, Text_t *remainder) {
+ OptionalInt_t full_int = Int$parse(text, base, remainder);
if (full_int.small != 0L && Int$compare_value(full_int, I(0)) >= 0 && Int$compare_value(full_int, I(255)) <= 0) {
return (OptionalByte_t){.has_value = true, .value = Byte$from_int(full_int, true)};
} else {
diff --git a/src/stdlib/bytes.h b/src/stdlib/bytes.h
index 2f948177..6581f300 100644
--- a/src/stdlib/bytes.h
+++ b/src/stdlib/bytes.h
@@ -18,7 +18,7 @@ Byte_t Byte$from_int(Int_t i, bool truncate);
Byte_t Byte$from_int64(int64_t i, bool truncate);
Byte_t Byte$from_int32(int32_t i, bool truncate);
Byte_t Byte$from_int16(int16_t i, bool truncate);
-OptionalByte_t Byte$parse(Text_t text, Text_t *remainder);
+OptionalByte_t Byte$parse(Text_t text, OptionalInt_t base, Text_t *remainder);
Closure_t Byte$to(Byte_t first, Byte_t last, OptionalInt8_t step);
MACROLIKE Byte_t Byte$from_int8(int8_t i) { return (Byte_t)i; }
diff --git a/src/stdlib/cli.c b/src/stdlib/cli.c
index 04538796..18da5c5e 100644
--- a/src/stdlib/cli.c
+++ b/src/stdlib/cli.c
@@ -238,23 +238,23 @@ static List_t parse_arg_list(List_t args, const char *flag, void *dest, const Ty
if (parsed.small == 0) print_err("Could not parse argument for ", flag, ": ", arg);
*(Int_t *)dest = parsed;
} else if (type == &Int64$info) {
- OptionalInt64_t parsed = Int64$parse(Text$from_str(arg), NULL);
+ OptionalInt64_t parsed = Int64$parse(Text$from_str(arg), NONE_INT, NULL);
if (!parsed.has_value) print_err("Could not parse argument for ", flag, ": ", arg);
*(Int64_t *)dest = parsed.value;
} else if (type == &Int32$info) {
- OptionalInt32_t parsed = Int32$parse(Text$from_str(arg), NULL);
+ OptionalInt32_t parsed = Int32$parse(Text$from_str(arg), NONE_INT, NULL);
if (!parsed.has_value) print_err("Could not parse argument for ", flag, ": ", arg);
*(Int32_t *)dest = parsed.value;
} else if (type == &Int16$info) {
- OptionalInt16_t parsed = Int16$parse(Text$from_str(arg), NULL);
+ OptionalInt16_t parsed = Int16$parse(Text$from_str(arg), NONE_INT, NULL);
if (!parsed.has_value) print_err("Could not parse argument for ", flag, ": ", arg);
*(Int16_t *)dest = parsed.value;
} else if (type == &Int8$info) {
- OptionalInt8_t parsed = Int8$parse(Text$from_str(arg), NULL);
+ OptionalInt8_t parsed = Int8$parse(Text$from_str(arg), NONE_INT, NULL);
if (!parsed.has_value) print_err("Could not parse argument for ", flag, ": ", arg);
*(Int8_t *)dest = parsed.value;
} else if (type == &Byte$info) {
- OptionalByte_t parsed = Byte$parse(Text$from_str(arg), NULL);
+ OptionalByte_t parsed = Byte$parse(Text$from_str(arg), NONE_INT, NULL);
if (!parsed.has_value) print_err("Could not parse argument for ", flag, ": ", arg);
*(Byte_t *)dest = parsed.value;
} else if (type == &Bool$info) {
diff --git a/src/stdlib/intX.c.h b/src/stdlib/intX.c.h
index 0e665591..0910c7f1 100644
--- a/src/stdlib/intX.c.h
+++ b/src/stdlib/intX.c.h
@@ -188,8 +188,8 @@ Closure_t NAMESPACED(onward)(INT_T first, INT_T step) {
return (Closure_t){.fn = _next_int, .userdata = range};
}
public
-PUREFUNC OPT_T NAMESPACED(parse)(Text_t text, Text_t *remainder) {
- OptionalInt_t full_int = Int$parse(text, remainder);
+PUREFUNC OPT_T NAMESPACED(parse)(Text_t text, OptionalInt_t base, Text_t *remainder) {
+ OptionalInt_t full_int = Int$parse(text, base, remainder);
if (full_int.small == 0L) return (OPT_T){.has_value = false};
if (Int$compare_value(full_int, I(NAMESPACED(min))) < 0) {
return (OPT_T){.has_value = false};
diff --git a/src/stdlib/intX.h b/src/stdlib/intX.h
index 0f4632c2..1c8b4a05 100644
--- a/src/stdlib/intX.h
+++ b/src/stdlib/intX.h
@@ -46,7 +46,7 @@ List_t NAMESPACED(bits)(INTX_T x);
bool NAMESPACED(get_bit)(INTX_T x, Int_t bit_index);
Closure_t NAMESPACED(to)(INTX_T first, INTX_T last, OPT_T step);
Closure_t NAMESPACED(onward)(INTX_T first, INTX_T step);
-PUREFUNC OPT_T NAMESPACED(parse)(Text_t text, Text_t *remainder);
+PUREFUNC OPT_T NAMESPACED(parse)(Text_t text, OptionalInt_t base, Text_t *remainder);
CONSTFUNC bool NAMESPACED(is_between)(const INTX_T x, const INTX_T low, const INTX_T high);
CONSTFUNC INTX_T NAMESPACED(clamped)(INTX_T x, INTX_T min, INTX_T max);
MACROLIKE CONSTFUNC INTX_T NAMESPACED(from_byte)(Byte_t b) { return (INTX_T)b; }