aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compile/functions.c3
-rw-r--r--src/environment.c18
-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
-rw-r--r--src/typecheck.c3
10 files changed, 106 insertions, 61 deletions
diff --git a/src/compile/functions.c b/src/compile/functions.c
index cce93e3d..63d7d23d 100644
--- a/src/compile/functions.c
+++ b/src/compile/functions.c
@@ -6,6 +6,7 @@
#include "../stdlib/datatypes.h"
#include "../stdlib/integers.h"
#include "../stdlib/nums.h"
+#include "../stdlib/optionals.h"
#include "../stdlib/tables.h"
#include "../stdlib/text.h"
#include "../stdlib/util.h"
@@ -703,7 +704,7 @@ Text_t compile_function(env_t *env, Text_t name_code, ast_t *ast, Text_t *static
definition = Texts(definition, wrapper);
} else if (cache && cache->tag == Int) {
assert(args);
- OptionalInt64_t cache_size = Int64$parse(Text$from_str(Match(cache, Int)->str), NULL);
+ OptionalInt64_t cache_size = Int64$parse(Text$from_str(Match(cache, Int)->str), NONE_INT, NULL);
Text_t pop_code = EMPTY_TEXT;
if (cache->tag == Int && cache_size.has_value && cache_size.value > 0) {
// FIXME: this currently just deletes the first entry, but this
diff --git a/src/environment.c b/src/environment.c
index 43d22c3d..7e04fe79 100644
--- a/src/environment.c
+++ b/src/environment.c
@@ -93,7 +93,7 @@ env_t *global_env(bool source_mapping) {
MAKE_TYPE("Empty", EMPTY_TYPE, Text("Empty$$type"), Text("Empty$$info")),
MAKE_TYPE( //
"Bool", Type(BoolType), Text("Bool_t"), Text("Bool$info"),
- {"parse", "Bool$parse", "func(text:Text, remainder:&Text? = none -> Bool?)"}),
+ {"parse", "Bool$parse", "func(text:Text, remainder:&Text?=none -> Bool?)"}),
MAKE_TYPE( //
"Byte", Type(ByteType), Text("Byte_t"), Text("Byte$info"),
{"get_bit", "Byte$get_bit", "func(x:Byte, bit_index:Int -> Bool)"}, //
@@ -101,7 +101,7 @@ env_t *global_env(bool source_mapping) {
{"is_between", "Byte$is_between", "func(x:Byte, low:Byte, high:Byte -> Bool)"}, //
{"max", "Byte$max", "Byte"}, //
{"min", "Byte$min", "Byte"}, //
- {"parse", "Byte$parse", "func(text:Text, remainder:&Text? = none -> Byte?)"}, //
+ {"parse", "Byte$parse", "func(text:Text, base:Int?=none, remainder:&Text?=none -> Byte?)"}, //
{"to", "Byte$to", "func(first:Byte, last:Byte, step:Int8?=none -> func(->Byte?))"}),
MAKE_TYPE( //
"Int", Type(BigIntType), Text("Int_t"), Text("Int$info"), {"abs", "Int$abs", "func(x:Int -> Int)"}, //
@@ -126,7 +126,7 @@ env_t *global_env(bool source_mapping) {
{"next_prime", "Int$next_prime", "func(x:Int -> Int)"}, //
{"octal", "Int$octal", "func(i:Int, digits=0, prefix=yes -> Text)"}, //
{"onward", "Int$onward", "func(first:Int,step=1 -> func(->Int?))"}, //
- {"parse", "Int$parse", "func(text:Text, remainder:&Text? = none -> Int?)"}, //
+ {"parse", "Int$parse", "func(text:Text, base:Int?=none, remainder:&Text?=none -> Int?)"}, //
{"plus", "Int$plus", "func(x,y:Int -> Int)"}, //
{"power", "Int$power", "func(base:Int,exponent:Int -> Int)"}, //
#if __GNU_MP_VERSION >= 6
@@ -145,7 +145,7 @@ env_t *global_env(bool source_mapping) {
{"clamped", "Int64$clamped", "func(x,low,high:Int64 -> Int64)"}, //
{"divided_by", "Int64$divided_by", "func(x,y:Int64 -> Int64)"}, //
{"gcd", "Int64$gcd", "func(x,y:Int64 -> Int64)"}, //
- {"parse", "Int64$parse", "func(text:Text, remainder:&Text? = none -> Int64?)"}, //
+ {"parse", "Int64$parse", "func(text:Text, base:Int?=none, remainder:&Text?=none -> Int64?)"}, //
{"get_bit", "Int64$get_bit", "func(x:Int64, bit_index:Int -> Bool)"}, //
{"hex", "Int64$hex", "func(i:Int64, digits=0, uppercase=yes, prefix=yes -> Text)"}, //
{"is_between", "Int64$is_between", "func(x:Int64,low:Int64,high:Int64 -> Bool)"}, //
@@ -167,7 +167,7 @@ env_t *global_env(bool source_mapping) {
{"clamped", "Int32$clamped", "func(x,low,high:Int32 -> Int32)"}, //
{"divided_by", "Int32$divided_by", "func(x,y:Int32 -> Int32)"}, //
{"gcd", "Int32$gcd", "func(x,y:Int32 -> Int32)"}, //
- {"parse", "Int32$parse", "func(text:Text, remainder:&Text? = none -> Int32?)"}, //
+ {"parse", "Int32$parse", "func(text:Text, base:Int?=none, remainder:&Text?=none -> Int32?)"}, //
{"get_bit", "Int32$get_bit", "func(x:Int32, bit_index:Int -> Bool)"}, //
{"hex", "Int32$hex", "func(i:Int32, digits=0, uppercase=yes, prefix=yes -> Text)"}, //
{"is_between", "Int32$is_between", "func(x:Int32,low:Int32,high:Int32 -> Bool)"}, //
@@ -189,7 +189,7 @@ env_t *global_env(bool source_mapping) {
{"clamped", "Int16$clamped", "func(x,low,high:Int16 -> Int16)"}, //
{"divided_by", "Int16$divided_by", "func(x,y:Int16 -> Int16)"}, //
{"gcd", "Int16$gcd", "func(x,y:Int16 -> Int16)"}, //
- {"parse", "Int16$parse", "func(text:Text, remainder:&Text? = none -> Int16?)"}, //
+ {"parse", "Int16$parse", "func(text:Text, base:Int?=none, remainder:&Text?=none -> Int16?)"}, //
{"get_bit", "Int16$get_bit", "func(x:Int16, bit_index:Int -> Bool)"}, //
{"hex", "Int16$hex", "func(i:Int16, digits=0, uppercase=yes, prefix=yes -> Text)"}, //
{"is_between", "Int16$is_between", "func(x:Int16,low:Int16,high:Int16 -> Bool)"}, //
@@ -211,7 +211,7 @@ env_t *global_env(bool source_mapping) {
{"clamped", "Int8$clamped", "func(x,low,high:Int8 -> Int8)"}, //
{"divided_by", "Int8$divided_by", "func(x,y:Int8 -> Int8)"}, //
{"gcd", "Int8$gcd", "func(x,y:Int8 -> Int8)"}, //
- {"parse", "Int8$parse", "func(text:Text, remainder:&Text? = none -> Int8?)"}, //
+ {"parse", "Int8$parse", "func(text:Text, base:Int?=none, remainder:&Text?=none -> Int8?)"}, //
{"get_bit", "Int8$get_bit", "func(x:Int8, bit_index:Int -> Bool)"}, //
{"hex", "Int8$hex", "func(i:Int8, digits=0, uppercase=yes, prefix=yes -> Text)"}, //
{"is_between", "Int8$is_between", "func(x:Int8,low:Int8,high:Int8 -> Bool)"}, //
@@ -245,7 +245,7 @@ env_t *global_env(bool source_mapping) {
C(SQRT1_2), {"INF", "(Num_t)(INFINITY)", "Num"}, //
{"TAU", "(Num_t)(2.*M_PI)", "Num"}, //
{"mix", "Num$mix", "func(amount,x,y:Num -> Num)"}, //
- {"parse", "Num$parse", "func(text:Text, remainder:&Text? = none -> Num?)"}, //
+ {"parse", "Num$parse", "func(text:Text, remainder:&Text?=none -> Num?)"}, //
{"abs", "fabs", "func(n:Num -> Num)"}, //
F_opt(acos), F_opt(acosh), F_opt(asin), F(asinh), F(atan), F_opt(atanh), F(cbrt), F(ceil), F_opt(cos),
F(cosh), F(erf), F(erfc), F(exp), F(exp2), F(expm1), F(floor), F(j0), F(j1), F_opt(log), F_opt(log10),
@@ -274,7 +274,7 @@ env_t *global_env(bool source_mapping) {
{"INF", "(Num32_t)(INFINITY)", "Num32"}, //
{"TAU", "(Num32_t)(2.f*M_PI)", "Num32"}, //
{"mix", "Num32$mix", "func(amount,x,y:Num32 -> Num32)"}, //
- {"parse", "Num32$parse", "func(text:Text, remainder:&Text? = none -> Num32?)"}, //
+ {"parse", "Num32$parse", "func(text:Text, remainder:&Text?=none -> Num32?)"}, //
{"abs", "fabsf", "func(n:Num32 -> Num32)"}, //
{"modulo", "Num32$mod", "func(x,y:Num32 -> Num32)"}, //
{"modulo1", "Num32$mod1", "func(x,y:Num32 -> Num32)"}, //
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; }
diff --git a/src/typecheck.c b/src/typecheck.c
index 37f4fcab..e432759b 100644
--- a/src/typecheck.c
+++ b/src/typecheck.c
@@ -14,6 +14,7 @@
#include "naming.h"
#include "parse/files.h"
#include "parse/types.h"
+#include "stdlib/optionals.h"
#include "stdlib/paths.h"
#include "stdlib/tables.h"
#include "stdlib/text.h"
@@ -1659,7 +1660,7 @@ PUREFUNC bool is_constant(env_t *env, ast_t *ast) {
case None: return true;
case Int: {
DeclareMatch(info, ast, Int);
- Int_t int_val = Int$parse(Text$from_str(info->str), NULL);
+ Int_t int_val = Int$parse(Text$from_str(info->str), NONE_INT, NULL);
if (int_val.small == 0) return false; // Failed to parse
return (Int$compare_value(int_val, I(BIGGEST_SMALL_INT)) <= 0);
}