aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compile.c4
-rw-r--r--src/environment.c23
-rw-r--r--src/stdlib/bools.c39
-rw-r--r--src/stdlib/bools.h2
-rw-r--r--src/stdlib/bytes.c13
-rw-r--r--src/stdlib/bytes.h1
-rw-r--r--src/stdlib/integers.c36
-rw-r--r--src/stdlib/integers.h4
-rw-r--r--src/stdlib/nums.c23
-rw-r--r--src/stdlib/nums.h4
-rw-r--r--src/stdlib/paths.c4
-rw-r--r--src/stdlib/stdlib.c14
-rw-r--r--src/stdlib/text.c24
-rw-r--r--src/stdlib/text.h4
-rw-r--r--src/tomo.c4
-rw-r--r--src/typecheck.c2
16 files changed, 140 insertions, 61 deletions
diff --git a/src/compile.c b/src/compile.c
index 1795bb38..eb250d74 100644
--- a/src/compile.c
+++ b/src/compile.c
@@ -1513,7 +1513,7 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
struct { const char *name; binding_t *b; } *entry = closed_vars.entries.data + closed_vars.entries.stride*i;
if (entry->b->type->tag == ModuleType)
continue;
- if (Text$starts_with(entry->b->code, Text("userdata->"))) {
+ if (Text$starts_with(entry->b->code, Text("userdata->"), NULL)) {
Table$str_set(defer_env->locals, entry->name, entry->b);
} else {
Text_t defer_name = Texts("defer$", String(++defer_id), "$", entry->name);
@@ -4254,7 +4254,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));
+ OptionalInt64_t cache_size = Int64$parse(Text$from_str(Match(cache, Int)->str), NULL);
Text_t pop_code = EMPTY_TEXT;
if (cache->tag == Int && !cache_size.is_none && cache_size.value > 0) {
// FIXME: this currently just deletes the first entry, but this should be more like a
diff --git a/src/environment.c b/src/environment.c
index 93b5a16c..3faad24d 100644
--- a/src/environment.c
+++ b/src/environment.c
@@ -85,14 +85,15 @@ env_t *global_env(bool source_mapping)
{"Abort", Type(AbortType), Text("void"), Text("Abort$info"), {}},
{"Memory", Type(MemoryType), Text("Memory_t"), Text("Memory$info"), {}},
{"Bool", Type(BoolType), Text("Bool_t"), Text("Bool$info"), TypedList(ns_entry_t,
- {"parse", "Bool$parse", "func(text:Text -> Bool?)"},
+ {"parse", "Bool$parse", "func(text:Text, remainder:&Text? = none -> Bool?)"},
)},
{"Byte", Type(ByteType), Text("Byte_t"), Text("Byte$info"), TypedList(ns_entry_t,
- {"max", "Byte$max", "Byte"},
{"get_bit", "Byte$get_bit", "func(x:Byte, bit_index:Int -> Bool)"},
{"hex", "Byte$hex", "func(byte:Byte, uppercase=yes, prefix=no -> Text)"},
{"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?)"},
{"to", "Byte$to", "func(first:Byte, last:Byte, step:Int8?=none -> func(->Byte?))"},
)},
{"Int", Type(BigIntType), Text("Int_t"), Text("Int$info"), TypedList(ns_entry_t,
@@ -118,7 +119,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 -> Int?)"},
+ {"parse", "Int$parse", "func(text:Text, 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
@@ -137,7 +138,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 -> Int64?)"},
+ {"parse", "Int64$parse", "func(text:Text, 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)"},
@@ -159,7 +160,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 -> Int32?)"},
+ {"parse", "Int32$parse", "func(text:Text, 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)"},
@@ -181,7 +182,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 -> Int16?)"},
+ {"parse", "Int16$parse", "func(text:Text, 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)"},
@@ -203,7 +204,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 -> Int8?)"},
+ {"parse", "Int8$parse", "func(text:Text, 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)"},
@@ -238,7 +239,7 @@ env_t *global_env(bool source_mapping)
{"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 -> 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),
@@ -268,7 +269,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 -> 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)"},
@@ -345,7 +346,7 @@ env_t *global_env(bool source_mapping)
{"bytes", "Text$utf8_bytes", "func(text:Text -> [Byte])"},
{"caseless_equals", "Text$equal_ignoring_case", "func(a,b:Text, language='C' -> Bool)"},
{"codepoint_names", "Text$codepoint_names", "func(text:Text -> [Text])"},
- {"ends_with", "Text$ends_with", "func(text,suffix:Text -> Bool)"},
+ {"ends_with", "Text$ends_with", "func(text,suffix:Text, remainder:&Text? = none -> Bool)"},
{"from", "Text$from", "func(text:Text, first:Int -> Text)"},
{"from_bytes", "Text$from_bytes", "func(bytes:[Byte] -> Text?)"},
{"from_c_string", "Text$from_str", "func(str:CString -> Text?)"},
@@ -368,7 +369,7 @@ env_t *global_env(bool source_mapping)
{"slice", "Text$slice", "func(text:Text, from=1, to=-1 -> Text)"},
{"split", "Text$split", "func(text:Text, delimiter='' -> [Text])"},
{"split_any", "Text$split_any", "func(text:Text, delimiters=' \\t\\r\\n' -> [Text])"},
- {"starts_with", "Text$starts_with", "func(text,prefix:Text -> Bool)"},
+ {"starts_with", "Text$starts_with", "func(text,prefix:Text, remainder:&Text? = none -> Bool)"},
{"title", "Text$title", "func(text:Text, language='C' -> Text)"},
{"to", "Text$to", "func(text:Text, last:Int -> Text)"},
{"translate", "Text$translate", "func(text:Text, translations:{Text=Text} -> Text)"},
diff --git a/src/stdlib/bools.c b/src/stdlib/bools.c
index 66b7e209..85de0621 100644
--- a/src/stdlib/bools.c
+++ b/src/stdlib/bools.c
@@ -22,24 +22,37 @@ PUREFUNC public Text_t Bool$as_text(const void *b, bool colorize, const TypeInfo
return *(Bool_t*)b ? Text("yes") : Text("no");
}
-PUREFUNC public OptionalBool_t Bool$parse(Text_t text)
+static bool try_parse(Text_t text, Text_t target, bool target_value, Text_t *remainder, bool *result)
{
- Text_t lang = Text("C");
- if (Text$equal_ignoring_case(text, Text("yes"), lang)
- || Text$equal_ignoring_case(text, Text("on"), lang)
- || Text$equal_ignoring_case(text, Text("true"), lang)
- || Text$equal_ignoring_case(text, Text("1"), lang)) {
- return yes;
- } else if (Text$equal_ignoring_case(text, Text("no"), lang)
- || Text$equal_ignoring_case(text, Text("off"), lang)
- || Text$equal_ignoring_case(text, Text("false"), lang)
- || Text$equal_ignoring_case(text, Text("0"), lang)) {
- return no;
+ static const Text_t lang = Text("C");
+ if (text.length < target.length) return false;
+ Text_t prefix = Text$to(text, Int$from_int64(target.length));
+ if (Text$equal_ignoring_case(prefix, target, lang)) {
+ if (remainder) *remainder = Text$from(text, Int$from_int64(target.length + 1));
+ else if (text.length > target.length) return false;
+ *result = target_value;
+ return true;
} else {
- return NONE_BOOL;
+ return false;
}
}
+PUREFUNC public OptionalBool_t Bool$parse(Text_t text, Text_t *remainder)
+{
+ bool result;
+ if (try_parse(text, Text("yes"), true, remainder, &result)
+ || try_parse(text, Text("true"), true, remainder, &result)
+ || try_parse(text, Text("on"), true, remainder, &result)
+ || try_parse(text, Text("1"), true, remainder, &result)
+ || try_parse(text, Text("no"), false, remainder, &result)
+ || try_parse(text, Text("false"), false, remainder, &result)
+ || try_parse(text, Text("off"), false, remainder, &result)
+ || try_parse(text, Text("0"), false, remainder, &result))
+ return result;
+ else
+ return NONE_BOOL;
+}
+
static bool Bool$is_none(const void *b, const TypeInfo_t *info)
{
(void)info;
diff --git a/src/stdlib/bools.h b/src/stdlib/bools.h
index 6d0300d5..ae6c5feb 100644
--- a/src/stdlib/bools.h
+++ b/src/stdlib/bools.h
@@ -13,7 +13,7 @@
#define no (Bool_t)false
PUREFUNC Text_t Bool$as_text(const void *b, bool colorize, const TypeInfo_t *type);
-OptionalBool_t Bool$parse(Text_t text);
+OptionalBool_t Bool$parse(Text_t text, Text_t *remainder);
MACROLIKE Bool_t Bool$from_int(Int_t i) { return (i.small != 0); }
MACROLIKE Bool_t Bool$from_int64(Int64_t i) { return (i != 0); }
MACROLIKE Bool_t Bool$from_int32(Int32_t i) { return (i != 0); }
diff --git a/src/stdlib/bytes.c b/src/stdlib/bytes.c
index 48c8b93b..130a645f 100644
--- a/src/stdlib/bytes.c
+++ b/src/stdlib/bytes.c
@@ -3,6 +3,7 @@
#include <stdint.h>
#include "bytes.h"
+#include "integers.h"
#include "stdlib.h"
#include "text.h"
#include "util.h"
@@ -29,6 +30,18 @@ public CONSTFUNC bool Byte$is_between(const Byte_t x, const Byte_t low, const By
return low <= x && x <= high;
}
+public OptionalByte_t Byte$parse(Text_t text, Text_t *remainder)
+{
+ OptionalInt_t full_int = Int$parse(text, 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){.value=Byte$from_int(full_int, true)};
+ } else {
+ return NONE_BYTE;
+ }
+}
+
public Text_t Byte$hex(Byte_t byte, bool uppercase, bool prefix) {
struct Text_s text = {.tag=TEXT_ASCII};
text.ascii = GC_MALLOC_ATOMIC(8);
diff --git a/src/stdlib/bytes.h b/src/stdlib/bytes.h
index e733c274..ab88b5bc 100644
--- a/src/stdlib/bytes.h
+++ b/src/stdlib/bytes.h
@@ -19,6 +19,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);
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; }
MACROLIKE Byte_t Byte$from_bool(bool b) { return (Byte_t)b; }
diff --git a/src/stdlib/integers.c b/src/stdlib/integers.c
index 018798ec..86be790d 100644
--- a/src/stdlib/integers.c
+++ b/src/stdlib/integers.c
@@ -424,8 +424,36 @@ public Int_t Int$from_str(const char *str) {
return Int$from_mpz(i);
}
-public OptionalInt_t Int$parse(Text_t text) {
- return Int$from_str(Text$as_c_string(text));
+public OptionalInt_t Int$parse(Text_t text, Text_t *remainder) {
+ const char *str = Text$as_c_string(text);
+ mpz_t i;
+ int result;
+ if (strncmp(str, "0x", 2) == 0) {
+ const char *end = str + 2 + strcspn(str + 2, "0123456789abcdefABCDEF");
+ if (remainder) *remainder = Text$from_str(end);
+ else if (*end != '\0') return NONE_INT;
+ result = mpz_init_set_str(i, str + 2, 16);
+ } else if (strncmp(str, "0o", 2) == 0) {
+ const char *end = str + 2 + strcspn(str + 2, "01234567");
+ if (remainder) *remainder = Text$from_str(end);
+ else if (*end != '\0') return NONE_INT;
+ result = mpz_init_set_str(i, str + 2, 8);
+ } else if (strncmp(str, "0b", 2) == 0) {
+ const char *end = str + 2 + strcspn(str + 2, "01");
+ if (remainder) *remainder = Text$from_str(end);
+ else if (*end != '\0') return NONE_INT;
+ result = mpz_init_set_str(i, str + 2, 2);
+ } else {
+ const char *end = str + 2 + strcspn(str + 2, "0123456789");
+ if (remainder) *remainder = Text$from_str(end);
+ else if (*end != '\0') return NONE_INT;
+ result = mpz_init_set_str(i, str, 10);
+ }
+ if (result != 0) {
+ if (remainder) *remainder = text;
+ return NONE_INT;
+ }
+ return Int$from_mpz(i);
}
public bool Int$is_prime(Int_t x, Int_t reps)
@@ -670,8 +698,8 @@ public void Int32$deserialize(FILE *in, void *outval, List_t *pointers, const Ty
range->step = step; \
return (Closure_t){.fn=_next_##KindOfInt, .userdata=range}; \
} \
- public PUREFUNC Optional ## KindOfInt ## _t KindOfInt ## $parse(Text_t text) { \
- OptionalInt_t full_int = Int$parse(text); \
+ public PUREFUNC Optional ## KindOfInt ## _t KindOfInt ## $parse(Text_t text, Text_t *remainder) { \
+ OptionalInt_t full_int = Int$parse(text, remainder); \
if (full_int.small == 0L) return (Optional ## KindOfInt ## _t){.is_none=true}; \
if (Int$compare_value(full_int, I(min_val)) < 0) { \
return (Optional ## KindOfInt ## _t){.is_none=true}; \
diff --git a/src/stdlib/integers.h b/src/stdlib/integers.h
index beb26bd6..50ca485f 100644
--- a/src/stdlib/integers.h
+++ b/src/stdlib/integers.h
@@ -32,7 +32,7 @@
bool type_name ## $get_bit(c_type x, Int_t bit_index); \
Closure_t type_name ## $to(c_type first, c_type last, Optional ## type_name ## _t step); \
Closure_t type_name ## $onward(c_type first, c_type step); \
- PUREFUNC Optional ## type_name ## _t type_name ## $parse(Text_t text); \
+ PUREFUNC Optional ## type_name ## _t type_name ## $parse(Text_t text, Text_t *remainder); \
CONSTFUNC bool type_name ## $is_between(const c_type x, const c_type low, const c_type high); \
CONSTFUNC c_type type_name ## $clamped(c_type x, c_type min, c_type max); \
MACROLIKE CONSTFUNC c_type type_name ## $from_byte(Byte_t b) { return (c_type)b; } \
@@ -101,7 +101,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);
+OptionalInt_t Int$parse(Text_t text, 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/nums.c b/src/stdlib/nums.c
index 34fbb162..3775c8f4 100644
--- a/src/stdlib/nums.c
+++ b/src/stdlib/nums.c
@@ -98,14 +98,20 @@ public CONSTFUNC double Num$clamped(double x, double low, double high) {
return (x <= low) ? low : (x >= high ? high : x);
}
-public OptionalNum_t Num$parse(Text_t text) {
+public OptionalNum_t Num$parse(Text_t text, Text_t *remainder) {
const char *str = Text$as_c_string(text);
char *end = NULL;
double d = strtod(str, &end);
- if (end > str && end[0] == '\0')
+ if (end > str) {
+ if (remainder)
+ *remainder = Text$from_str(end);
+ else if (*end != '\0')
+ return nan("none");
return d;
- else
+ } else {
+ if (remainder) *remainder = text;
return nan("none");
+ }
}
static bool Num$is_none(const void *n, const TypeInfo_t *info)
@@ -203,14 +209,19 @@ public CONSTFUNC float Num32$clamped(float x, float low, float high) {
return (x <= low) ? low : (x >= high ? high : x);
}
-public OptionalNum32_t Num32$parse(Text_t text) {
+public OptionalNum32_t Num32$parse(Text_t text, Text_t *remainder) {
const char *str = Text$as_c_string(text);
char *end = NULL;
double d = strtod(str, &end);
- if (end > str && end[0] == '\0')
+ if (end > str && end[0] == '\0') {
+ if (remainder) *remainder = Text$from_str(end);
+ else if (*end != '\0')
+ return nan("none");
return d;
- else
+ } else {
+ if (remainder) *remainder = text;
return nan("none");
+ }
}
static bool Num32$is_none(const void *n, const TypeInfo_t *info)
diff --git a/src/stdlib/nums.h b/src/stdlib/nums.h
index fdd9e227..fe76d1c3 100644
--- a/src/stdlib/nums.h
+++ b/src/stdlib/nums.h
@@ -30,7 +30,7 @@ CONSTFUNC bool Num$finite(double n);
CONSTFUNC bool Num$isnan(double n);
double Num$nan(Text_t tag);
CONSTFUNC double Num$mix(double amount, double x, double y);
-OptionalNum_t Num$parse(Text_t text);
+OptionalNum_t Num$parse(Text_t text, Text_t *remainder);
CONSTFUNC bool Num$is_between(const double x, const double low, const double high);
CONSTFUNC double Num$clamped(double x, double low, double high);
MACROLIKE CONSTFUNC double Num$from_num32(Num32_t n) { return (double)n; }
@@ -83,7 +83,7 @@ CONSTFUNC bool Num32$isinf(float n);
CONSTFUNC bool Num32$finite(float n);
CONSTFUNC bool Num32$isnan(float n);
CONSTFUNC float Num32$mix(float amount, float x, float y);
-OptionalNum32_t Num32$parse(Text_t text);
+OptionalNum32_t Num32$parse(Text_t text, Text_t *remainder);
float Num32$nan(Text_t tag);
CONSTFUNC bool Num32$is_between(const float x, const float low, const float high);
CONSTFUNC float Num32$clamped(float x, float low, float high);
diff --git a/src/stdlib/paths.c b/src/stdlib/paths.c
index 94baf995..58702ec7 100644
--- a/src/stdlib/paths.c
+++ b/src/stdlib/paths.c
@@ -619,10 +619,10 @@ public bool Path$has_extension(Path_t path, Text_t extension)
if (extension.length == 0)
return !Text$has(Text$from(last, I(2)), Text(".")) || Text$equal_values(last, Text(".."));
- if (!Text$starts_with(extension, Text(".")))
+ if (!Text$starts_with(extension, Text("."), NULL))
extension = Texts(Text("."), extension);
- return Text$ends_with(Text$from(last, I(2)), extension);
+ return Text$ends_with(Text$from(last, I(2)), extension, NULL);
}
public Path_t Path$child(Path_t path, Text_t name)
diff --git a/src/stdlib/stdlib.c b/src/stdlib/stdlib.c
index 2b4bd99c..02ccd710 100644
--- a/src/stdlib/stdlib.c
+++ b/src/stdlib/stdlib.c
@@ -90,37 +90,37 @@ static bool parse_single_arg(const TypeInfo_t *info, char *arg, void *dest)
*(OptionalInt_t*)dest = parsed;
return parsed.small != 0;
} else if (info == &Int64$info) {
- OptionalInt64_t parsed = Int64$parse(Text$from_str(arg));
+ OptionalInt64_t parsed = Int64$parse(Text$from_str(arg), NULL);
if (!parsed.is_none)
*(OptionalInt64_t*)dest = parsed;
return !parsed.is_none;
} else if (info == &Int32$info) {
- OptionalInt32_t parsed = Int32$parse(Text$from_str(arg));
+ OptionalInt32_t parsed = Int32$parse(Text$from_str(arg), NULL);
if (!parsed.is_none)
*(OptionalInt32_t*)dest = parsed;
return !parsed.is_none;
} else if (info == &Int16$info) {
- OptionalInt16_t parsed = Int16$parse(Text$from_str(arg));
+ OptionalInt16_t parsed = Int16$parse(Text$from_str(arg), NULL);
if (!parsed.is_none)
*(OptionalInt16_t*)dest = parsed;
return !parsed.is_none;
} else if (info == &Int8$info) {
- OptionalInt8_t parsed = Int8$parse(Text$from_str(arg));
+ OptionalInt8_t parsed = Int8$parse(Text$from_str(arg), NULL);
if (!parsed.is_none)
*(OptionalInt8_t*)dest = parsed;
return !parsed.is_none;
} else if (info == &Bool$info) {
- OptionalBool_t parsed = Bool$parse(Text$from_str(arg));
+ OptionalBool_t parsed = Bool$parse(Text$from_str(arg), NULL);
if (parsed != NONE_BOOL)
*(OptionalBool_t*)dest = parsed;
return parsed != NONE_BOOL;
} else if (info == &Num$info) {
- OptionalNum_t parsed = Num$parse(Text$from_str(arg));
+ OptionalNum_t parsed = Num$parse(Text$from_str(arg), NULL);
if (!isnan(parsed))
*(OptionalNum_t*)dest = parsed;
return !isnan(parsed);
} else if (info == &Num32$info) {
- OptionalNum32_t parsed = Num32$parse(Text$from_str(arg));
+ OptionalNum32_t parsed = Num32$parse(Text$from_str(arg), NULL);
if (!isnan(parsed))
*(OptionalNum32_t*)dest = parsed;
return !isnan(parsed);
diff --git a/src/stdlib/text.c b/src/stdlib/text.c
index 80c267ed..8ef0874e 100644
--- a/src/stdlib/text.c
+++ b/src/stdlib/text.c
@@ -1102,30 +1102,42 @@ bool _matches(TextIter_t *text_state, TextIter_t *target_state, int64_t pos)
return true;
}
-PUREFUNC public bool Text$starts_with(Text_t text, Text_t prefix)
+PUREFUNC public bool Text$starts_with(Text_t text, Text_t prefix, Text_t *remainder)
{
if (text.length < prefix.length)
return false;
TextIter_t text_state = NEW_TEXT_ITER_STATE(text), prefix_state = NEW_TEXT_ITER_STATE(prefix);
- return _matches(&text_state, &prefix_state, 0);
+ if (_matches(&text_state, &prefix_state, 0)) {
+ if (remainder) *remainder = Text$from(text, Int$from_int64(prefix.length + 1));
+ return true;
+ } else {
+ if (remainder) *remainder = text;
+ return false;
+ }
}
-PUREFUNC public bool Text$ends_with(Text_t text, Text_t suffix)
+PUREFUNC public bool Text$ends_with(Text_t text, Text_t suffix, Text_t *remainder)
{
if (text.length < suffix.length)
return false;
TextIter_t text_state = NEW_TEXT_ITER_STATE(text), suffix_state = NEW_TEXT_ITER_STATE(suffix);
- return _matches(&text_state, &suffix_state, text.length - suffix.length);
+ if (_matches(&text_state, &suffix_state, text.length - suffix.length)) {
+ if (remainder) *remainder = Text$to(text, Int$from_int64(text.length - suffix.length));
+ return true;
+ } else {
+ if (remainder) *remainder = text;
+ return false;
+ }
}
public Text_t Text$without_prefix(Text_t text, Text_t prefix)
{
- return Text$starts_with(text, prefix) ? Text$slice(text, I(prefix.length + 1), I(text.length)) : text;
+ return Text$starts_with(text, prefix, false) ? Text$slice(text, I(prefix.length + 1), I(text.length)) : text;
}
public Text_t Text$without_suffix(Text_t text, Text_t suffix)
{
- return Text$ends_with(text, suffix) ? Text$slice(text, I(1), I(text.length - suffix.length)) : text;
+ return Text$ends_with(text, suffix, false) ? Text$slice(text, I(1), I(text.length - suffix.length)) : text;
}
static bool _has_grapheme(TextIter_t *text, int32_t g)
diff --git a/src/stdlib/text.h b/src/stdlib/text.h
index 642a74b6..637a3db7 100644
--- a/src/stdlib/text.h
+++ b/src/stdlib/text.h
@@ -59,8 +59,8 @@ Text_t Text$lower(Text_t text, Text_t language);
Text_t Text$title(Text_t text, Text_t language);
Text_t Text$as_text(const void *text, bool colorize, const TypeInfo_t *info);
Text_t Text$quoted(Text_t str, bool colorize, Text_t quotation_mark);
-PUREFUNC bool Text$starts_with(Text_t text, Text_t prefix);
-PUREFUNC bool Text$ends_with(Text_t text, Text_t suffix);
+PUREFUNC bool Text$starts_with(Text_t text, Text_t prefix, Text_t *remainder);
+PUREFUNC bool Text$ends_with(Text_t text, Text_t suffix, Text_t *remainder);
Text_t Text$without_prefix(Text_t text, Text_t prefix);
Text_t Text$without_suffix(Text_t text, Text_t suffix);
Text_t Text$replace(Text_t text, Text_t target, Text_t replacement);
diff --git a/src/tomo.c b/src/tomo.c
index f60e7427..e105cb7a 100644
--- a/src/tomo.c
+++ b/src/tomo.c
@@ -709,11 +709,11 @@ time_t latest_included_modification_time(Path_t path)
bool allow_dot_include = Path$has_extension(path, Text("s")) || Path$has_extension(path, Text("S"));
for (Text_t line; (line=next_line(by_line.userdata)).length >= 0; ) {
line = Text$trim(line, Text(" \t"), true, false);
- if (!Text$starts_with(line, Text("#include")) && !(allow_dot_include && Text$starts_with(line, Text(".include"))))
+ if (!Text$starts_with(line, Text("#include"), NULL) && !(allow_dot_include && Text$starts_with(line, Text(".include"), NULL)))
continue;
// Check for `"` after `#include` or `.include` and some spaces:
- if (!Text$starts_with(Text$trim(Text$from(line, I(9)), Text(" \t"), true, false), Text("\"")))
+ if (!Text$starts_with(Text$trim(Text$from(line, I(9)), Text(" \t"), true, false), Text("\""), NULL))
continue;
List_t chunks = Text$split(line, Text("\""));
diff --git a/src/typecheck.c b/src/typecheck.c
index 494c73d8..0ed2328f 100644
--- a/src/typecheck.c
+++ b/src/typecheck.c
@@ -1686,7 +1686,7 @@ PUREFUNC bool is_constant(env_t *env, ast_t *ast)
case Bool: case Num: case None: return true;
case Int: {
DeclareMatch(info, ast, Int);
- Int_t int_val = Int$parse(Text$from_str(info->str));
+ Int_t int_val = Int$parse(Text$from_str(info->str), NULL);
if (int_val.small == 0) return false; // Failed to parse
return (Int$compare_value(int_val, I(BIGGEST_SMALL_INT)) <= 0);
}