diff --git a/builtins/integers.c b/builtins/integers.c index bf55d0a..d9361cf 100644 --- a/builtins/integers.c +++ b/builtins/integers.c @@ -92,7 +92,7 @@ public Text_t Int$format(Int_t i, Int_t digits_int) } public Text_t Int$hex(Int_t i, Int_t digits_int, bool uppercase, bool prefix) { - if (Int$compare(&i, (Int_t[1]){I_small(0)}, &$Int) < 0) + if (Int$is_negative(i)) return Text$concat(Text("-"), Int$hex(Int$negative(i), digits_int, uppercase, prefix)); int64_t digits = Int_to_Int64(digits_int, false); @@ -119,8 +119,7 @@ public Text_t Int$hex(Int_t i, Int_t digits_int, bool uppercase, bool prefix) { } public Text_t Int$octal(Int_t i, Int_t digits_int, bool prefix) { - Int_t zero = I_small(0); - if (Int$compare(&i, &zero, &$Int) < 0) + if (Int$is_negative(i)) return Text$concat(Text("-"), Int$octal(Int$negative(i), digits_int, prefix)); int64_t digits = Int_to_Int64(digits_int, false); @@ -317,7 +316,7 @@ public Int_t Int$sqrt(Int_t i) } public Int_t Int$random(Int_t min, Int_t max) { - int32_t cmp = Int$compare(&min, &max, &$Int); + int32_t cmp = Int$compare_value(min, max); if (cmp > 0) { Text_t min_text = Int$as_text(&min, false, &$Int), max_text = Int$as_text(&max, false, &$Int); fail("Random minimum value (%k) is larger than the maximum value (%k)", @@ -342,7 +341,7 @@ public Int_t Int$random(Int_t min, Int_t max) { } public Range_t Int$to(Int_t from, Int_t to) { - return (Range_t){from, to, Int$compare(&to, &from, &$Int) >= 0 ? (Int_t){.small=(1<<2)|1} : (Int_t){.small=(-1>>2)|1}}; + return (Range_t){from, to, Int$compare_value(to, from) >= 0 ? (Int_t){.small=(1<<2)|1} : (Int_t){.small=(-1>>2)|1}}; } public Int_t Int$from_str(const char *str, bool *success) { @@ -369,7 +368,7 @@ public bool Int$is_prime(Int_t x, Int_t reps) { mpz_t p; mpz_init_set_int(p, x); - if (Int$compare(&reps, (Int_t[1]){I_small(9999)}, &$Int) > 0) + if (Int$compare_value(reps, I(9999)) > 0) fail("Number of prime-test repetitions should not be above 9999"); int reps_int = Int_to_Int32(reps, false); return (mpz_probab_prime_p(p, reps_int) != 0); @@ -464,11 +463,11 @@ public const TypeInfo $Int = { bool parsed_int = false; \ Int_t full_int = Int$from_text(text, &parsed_int); \ if (!parsed_int && success) *success = false; \ - if (Int$compare(&full_int, (Int_t[1]){I(min_val)}, &$Int) < 0) { \ + if (Int$compare_value(full_int, I(min_val)) < 0) { \ if (success) *success = false; \ return min_val; \ } \ - if (Int$compare(&full_int, (Int_t[1]){I(max_val)}, &$Int) > 0) { \ + if (Int$compare_value(full_int, I(max_val)) > 0) { \ if (success) *success = false; \ return max_val; \ } \ diff --git a/builtins/integers.h b/builtins/integers.h index e24b786..4ff862f 100644 --- a/builtins/integers.h +++ b/builtins/integers.h @@ -257,6 +257,13 @@ static inline Int_t Int$negative(Int_t x) return Int$slow_negative(x); } +static inline bool Int$is_negative(Int_t x) +{ + if (__builtin_expect((x.small & 1), 1)) + return x.small < 0; + return Int$compare_value(x, I_small(0)) < 0; +} + // Conversion functions: static inline Int_t Int64_to_Int(int64_t i) diff --git a/builtins/text.c b/builtins/text.c index 97b50a4..b3fe25e 100644 --- a/builtins/text.c +++ b/builtins/text.c @@ -268,6 +268,42 @@ public Text_t Text$_concat(int n, Text_t items[n]) return ret; } +public Text_t Text$repeat(Text_t text, Int_t count) +{ + if (text.length == 0 || Int$is_negative(count)) + return Text(""); + + Int_t result_len = Int$times(count, I(text.length)); + if (Int$compare_value(result_len, I(1l<<40)) > 0) + fail("Text repeating would produce too big of an result!"); + + int64_t count64 = Int_to_Int64(count, false); + if (text.tag == TEXT_SUBTEXT) { + int64_t subtexts = num_subtexts(text); + Text_t ret = { + .length=text.length * count64, + .tag=TEXT_SUBTEXT, + .subtexts=GC_MALLOC(sizeof(Text_t[subtexts * count64])), + }; + for (int64_t c = 0; c < count64; c++) { + for (int64_t i = 0; i < subtexts; i++) { + if (text.subtexts[i].length > 0) + ret.subtexts[c*subtexts + i] = text.subtexts[i]; + } + } + return ret; + } else { + Text_t ret = { + .length=text.length * count64, + .tag=TEXT_SUBTEXT, + .subtexts=GC_MALLOC(sizeof(Text_t[count64])), + }; + for (int64_t i = 0; i < count64; i++) + ret.subtexts[i] = text; + return ret; + } +} + public Text_t Text$slice(Text_t text, Int_t first_int, Int_t last_int) { int64_t first = Int_to_Int64(first_int, false); diff --git a/builtins/text.h b/builtins/text.h index c93c626..747f82a 100644 --- a/builtins/text.h +++ b/builtins/text.h @@ -52,6 +52,7 @@ Text_t Text$from_bytes(array_t bytes); array_t Text$lines(Text_t text); Text_t Text$join(Text_t glue, array_t pieces); Text_t Text$map(Text_t text, Pattern_t pattern, closure_t fn); +Text_t Text$repeat(Text_t text, Int_t count); extern const TypeInfo $Text; diff --git a/docs/text.md b/docs/text.md index 7039043..3849f84 100644 --- a/docs/text.md +++ b/docs/text.md @@ -895,6 +895,32 @@ The text formatted as a quoted string. --- +## `repeat` + +**Description:** +Repeat some text multiple times. + +**Usage:** +```tomo +repeat(text: Text, count:Int) -> Text +``` + +**Parameters:** + +- `text`: The text to repeat. +- `count`: The number of times to repeat it. (Negative numbers are equivalent to zero). + +**Returns:** +The text repeated the given number of times. + +**Example:** +```tomo +>> "Abc":repeat(3) += "AbcAbcAbc" +``` + +--- + ## `replace` **Description:** diff --git a/environment.c b/environment.c index 2c1a3f7..21cd04f 100644 --- a/environment.c +++ b/environment.c @@ -259,6 +259,7 @@ env_t *new_compilation_unit(CORD *libname) {"map", "Text$map", "func(text:Text, pattern:Pattern, fn:func(text:Text)->Text)->Text"}, {"matches", "Text$matches", "func(text:Text, pattern:Pattern)->Bool"}, {"quoted", "Text$quoted", "func(text:Text, color=no)->Text"}, + {"repeat", "Text$repeat", "func(text:Text, count:Int)->Text"}, {"replace", "Text$replace", "func(text:Text, pattern:Pattern, replacement:Text, backref=$/\\/, recursive=yes)->Text"}, {"replace_all", "Text$replace_all", "func(text:Text, replacements:{Pattern:Text}, backref=$/\\/, recursive=yes)->Text"}, {"split", "Text$split", "func(text:Text, pattern=$Pattern'')->[Text]"}, diff --git a/test/text.tm b/test/text.tm index 74a5341..0a34e2a 100644 --- a/test/text.tm +++ b/test/text.tm @@ -253,3 +253,6 @@ func main(): >> "hello world":map($/world/, Text.upper) = "hello WORLD" + + >> "Abc":repeat(3) + = "AbcAbcAbc"