Deprecate Range datatype in favor of using iterator methods
This commit is contained in:
parent
8e0f1fa227
commit
5be9559046
2
Makefile
2
Makefile
@ -32,7 +32,7 @@ CFLAGS_PLACEHOLDER="$$(echo -e '\033[2m<flags...>\033[m')"
|
||||
LDLIBS=-lgc -lcord -lm -lunistring -lgmp -ldl
|
||||
BUILTIN_OBJS=stdlib/siphash.o stdlib/arrays.o stdlib/bools.o stdlib/bytes.o stdlib/nums.o stdlib/integers.o \
|
||||
stdlib/pointers.o stdlib/memory.o stdlib/text.o stdlib/threads.o stdlib/c_strings.o stdlib/tables.o \
|
||||
stdlib/types.o stdlib/util.o stdlib/files.o stdlib/ranges.o stdlib/shell.o stdlib/paths.o stdlib/rng.o \
|
||||
stdlib/types.o stdlib/util.o stdlib/files.o stdlib/shell.o stdlib/paths.o stdlib/rng.o \
|
||||
stdlib/optionals.o stdlib/patterns.o stdlib/metamethods.o stdlib/functiontype.o stdlib/stdlib.o \
|
||||
stdlib/structs.o stdlib/enums.o stdlib/moments.o stdlib/mutexeddata.o
|
||||
TESTS=$(patsubst %.tm,%.tm.testresult,$(wildcard test/*.tm))
|
||||
|
70
compile.c
70
compile.c
@ -500,7 +500,6 @@ PUREFUNC CORD compile_unsigned_type(type_t *t)
|
||||
CORD compile_type(type_t *t)
|
||||
{
|
||||
if (t == THREAD_TYPE) return "Thread_t";
|
||||
else if (t == RANGE_TYPE) return "Range_t";
|
||||
else if (t == RNG_TYPE) return "RNG_t";
|
||||
else if (t == MATCH_TYPE) return "Match_t";
|
||||
|
||||
@ -1541,26 +1540,58 @@ static CORD _compile_statement(env_t *env, ast_t *ast)
|
||||
naked_body = CORD_all(naked_body, "\n", loop_ctx.skip_label, ": continue;");
|
||||
CORD stop = loop_ctx.stop_label ? CORD_all("\n", loop_ctx.stop_label, ":;") : CORD_EMPTY;
|
||||
|
||||
// Special case for improving performance for numeric iteration:
|
||||
if (for_->iter->tag == MethodCall && streq(Match(for_->iter, MethodCall)->name, "to") &&
|
||||
get_type(env, Match(for_->iter, MethodCall)->self)->tag == BigIntType) {
|
||||
arg_ast_t *args = Match(for_->iter, MethodCall)->args;
|
||||
if (!args) code_err(for_->iter, "to() needs at least one argument");
|
||||
|
||||
CORD last = CORD_EMPTY, step = CORD_EMPTY, optional_step = CORD_EMPTY;
|
||||
if (!args->name || streq(args->name, "last")) {
|
||||
last = compile_to_type(env, args->value, INT_TYPE);
|
||||
if (args->next) {
|
||||
if (args->next->name && !streq(args->next->name, "step"))
|
||||
code_err(args->next->value, "Invalid argument name: %s", args->next->name);
|
||||
if (get_type(env, args->next->value)->tag == OptionalType)
|
||||
optional_step = compile_to_type(env, args->next->value, Type(OptionalType, .type=INT_TYPE));
|
||||
else
|
||||
step = compile_to_type(env, args->next->value, INT_TYPE);
|
||||
}
|
||||
} else if (streq(args->name, "step")) {
|
||||
if (get_type(env, args->value)->tag == OptionalType)
|
||||
optional_step = compile_to_type(env, args->value, Type(OptionalType, .type=INT_TYPE));
|
||||
else
|
||||
step = compile_to_type(env, args->value, INT_TYPE);
|
||||
if (args->next) {
|
||||
if (args->next->name && !streq(args->next->name, "last"))
|
||||
code_err(args->next->value, "Invalid argument name: %s", args->next->name);
|
||||
last = compile_to_type(env, args->next->value, INT_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
if (!last)
|
||||
code_err(for_->iter, "No `last` argument was given");
|
||||
|
||||
if (step && optional_step)
|
||||
step = CORD_all("({ OptionalInt_t maybe_step = ", optional_step, "; maybe_step->small == 0 ? (Int$compare_value(last, first) >= 0 ? I_small(1) : I_small(-1)) : (Int_t)maybe_step; })");
|
||||
else if (!step)
|
||||
step = "Int$compare_value(last, first) >= 0 ? I_small(1) : I_small(-1)";
|
||||
|
||||
CORD value = for_->vars ? compile(body_scope, for_->vars->ast) : "i";
|
||||
return CORD_all(
|
||||
"for (Int_t first = ", compile(env, Match(for_->iter, MethodCall)->self), ", ",
|
||||
value, " = first, "
|
||||
"last = ", last, ", "
|
||||
"step = ", step, "; "
|
||||
"Int$compare_value(", value, ", last) != Int$compare_value(step, I_small(0)); ", value, " = Int$plus(", value, ", step)) {\n"
|
||||
"\t", naked_body,
|
||||
"}",
|
||||
stop);
|
||||
}
|
||||
|
||||
type_t *iter_t = value_type(get_type(env, for_->iter));
|
||||
type_t *iter_value_t = value_type(iter_t);
|
||||
|
||||
if (iter_value_t == RANGE_TYPE) {
|
||||
CORD range = compile_to_pointer_depth(env, for_->iter, 0, false);
|
||||
CORD value = for_->vars ? compile(body_scope, for_->vars->ast) : "i";
|
||||
if (for_->empty)
|
||||
code_err(ast, "Ranges are never empty, they always contain at least their starting element");
|
||||
return CORD_all(
|
||||
"{\n"
|
||||
"const Range_t range = ", range, ";\n"
|
||||
"if (range.step.small == 0) fail(\"This range has a 'step' of zero and will loop infinitely!\");\n"
|
||||
"bool negative = (Int$compare_value(range.step, I(0)) < 0);\n"
|
||||
"for (Int_t ", value, " = range.first; ({ int32_t cmp = Int$compare_value(", value, ", range.last); negative ? cmp >= 0 : cmp <= 0;}) ; ", value, " = Int$plus(", value, ", range.step)) {\n"
|
||||
"\t", naked_body,
|
||||
"\n}",
|
||||
stop,
|
||||
"\n}");
|
||||
}
|
||||
|
||||
switch (iter_value_t->tag) {
|
||||
case ArrayType: {
|
||||
type_t *item_t = Match(iter_value_t, ArrayType)->item_type;
|
||||
@ -3848,7 +3879,7 @@ CORD compile(env_t *env, ast_t *ast)
|
||||
case StructType: {
|
||||
for (arg_t *field = Match(value_t, StructType)->fields; field; field = field->next) {
|
||||
if (streq(field->name, f->field)) {
|
||||
const char *prefix = (value_t == RANGE_TYPE || value_t == MATCH_TYPE) ? "" : "$";
|
||||
const char *prefix = (value_t == MATCH_TYPE) ? "" : "$";
|
||||
if (fielded_t->tag == PointerType) {
|
||||
CORD fielded = compile_to_pointer_depth(env, f->fielded, 1, false);
|
||||
return CORD_asprintf("(%r)->%s%s", fielded, prefix, f->field);
|
||||
@ -4086,7 +4117,6 @@ void compile_namespace(env_t *env, const char *ns_name, ast_t *block)
|
||||
CORD compile_type_info(env_t *env, type_t *t)
|
||||
{
|
||||
if (t == THREAD_TYPE) return "&Thread$info";
|
||||
else if (t == RANGE_TYPE) return "&Range$info";
|
||||
else if (t == MATCH_TYPE) return "&Match$info";
|
||||
else if (t == RNG_TYPE) return "&RNG$info";
|
||||
|
||||
|
@ -24,7 +24,6 @@ Information about Tomo's built-in types can be found here:
|
||||
- [Moment](moments.md)
|
||||
- [Enums](enums.md)
|
||||
- [Floating point numbers](nums.md)
|
||||
- [Integer Ranges](ranges.md)
|
||||
- [Integers](integers.md)
|
||||
- [Languages](langs.md)
|
||||
- [Mutexed Data](mutexed.md)
|
||||
|
@ -297,25 +297,34 @@ of the representable range or if the entire text can't be parsed as an integer,
|
||||
### `to`
|
||||
|
||||
**Description:**
|
||||
Creates an inclusive range of integers between the specified start and end values.
|
||||
Returns an iterator function that iterates over the range of numbers specified.
|
||||
Iteration is assumed to be nonempty and
|
||||
|
||||
**Signature:**
|
||||
```tomo
|
||||
func to(from: Int, to: Int -> Range)
|
||||
func to(first: Int, last: Int, step : Int? = none:Int -> func(->Int?))
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
|
||||
- `from`: The starting value of the range.
|
||||
- `to`: The ending value of the range.
|
||||
- `first`: The starting value of the range.
|
||||
- `last`: The ending value of the range.
|
||||
- `step`: An optional step size to use. If unspecified or `none`, the step will be inferred to be `+1` if `last >= first`, otherwise `-1`.
|
||||
|
||||
**Returns:**
|
||||
A range object representing all integers from `from` to `to` (inclusive).
|
||||
An iterator function that returns each integer in the given range (inclusive).
|
||||
|
||||
**Example:**
|
||||
```tomo
|
||||
>> 1:to(5)
|
||||
= Range(first=1, last=5, step=1)
|
||||
>> 2:to(5)
|
||||
= func(->Int?)
|
||||
>> [x for x in 2:to(5)]
|
||||
= [2, 3, 4, 5]
|
||||
>> [x for x in 5:to(2)]
|
||||
= [5, 4, 3, 2]
|
||||
|
||||
>> [x for x in 2:to(5, step=2)]
|
||||
= [2, 4]
|
||||
```
|
||||
|
||||
---
|
||||
|
@ -1,65 +0,0 @@
|
||||
# Ranges
|
||||
|
||||
Ranges are Tomo's way to do iteration over numeric ranges. Ranges are typically
|
||||
created using the `Int.to()` method like so: `5:to(10)`. Ranges are
|
||||
*inclusive*.
|
||||
|
||||
```tomo
|
||||
>> [i for i in 3:to(5)]
|
||||
= [3, 4, 5]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Range Methods
|
||||
|
||||
### `reversed`
|
||||
|
||||
**Description:**
|
||||
Returns a reversed copy of the range.
|
||||
|
||||
**Signature:**
|
||||
```tomo
|
||||
func reversed(range: Range -> Range)
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
|
||||
- `range`: The range to be reversed.
|
||||
|
||||
**Returns:**
|
||||
A new `Range` with the order of elements reversed.
|
||||
|
||||
**Example:**
|
||||
```tomo
|
||||
>> 1:to(5):reversed()
|
||||
= Range(first=5, last=1, step=-1)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `by`
|
||||
|
||||
**Description:**
|
||||
Creates a new range with a specified step value.
|
||||
|
||||
**Signature:**
|
||||
```tomo
|
||||
func by(range: Range, step: Int -> Range)
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
|
||||
- `range`: The original range.
|
||||
- `step`: The step value to be used in the new range.
|
||||
|
||||
**Returns:**
|
||||
A new `Range` that increments by the specified step value.
|
||||
|
||||
**Example:**
|
||||
```tomo
|
||||
>> 1:to(5):by(2)
|
||||
= Range(first=1, last=5, step=2)
|
||||
```
|
||||
|
||||
---
|
@ -13,7 +13,6 @@
|
||||
|
||||
type_t *TEXT_TYPE = NULL;
|
||||
type_t *MATCH_TYPE = NULL;
|
||||
type_t *RANGE_TYPE = NULL;
|
||||
type_t *RNG_TYPE = NULL;
|
||||
public type_t *THREAD_TYPE = NULL;
|
||||
|
||||
@ -67,15 +66,6 @@ env_t *new_compilation_unit(CORD libname)
|
||||
const char *name, *code, *type_str;
|
||||
} ns_entry_t;
|
||||
|
||||
{
|
||||
env_t *range_env = namespace_env(env, "Range");
|
||||
RANGE_TYPE = Type(
|
||||
StructType, .name="Range", .env=range_env,
|
||||
.fields=new(arg_t, .name="first", .type=INT_TYPE,
|
||||
.next=new(arg_t, .name="last", .type=INT_TYPE,
|
||||
.next=new(arg_t, .name="step", .type=INT_TYPE, .default_val=FakeAST(Int, .str="1")))));
|
||||
}
|
||||
|
||||
{
|
||||
env_t *match_env = namespace_env(env, "Match");
|
||||
MATCH_TYPE = Type(
|
||||
@ -142,7 +132,7 @@ env_t *new_compilation_unit(CORD libname)
|
||||
{"right_shifted", "Int$right_shifted", "func(x,y:Int -> Int)"},
|
||||
{"sqrt", "Int$sqrt", "func(x:Int -> Int?)"},
|
||||
{"times", "Int$times", "func(x,y:Int -> Int)"},
|
||||
{"to", "Int$to", "func(from:Int,to:Int -> Range)"},
|
||||
{"to", "Int$to", "func(from:Int,to:Int,step=none:Int -> func(->Int?))"},
|
||||
)},
|
||||
{"Int64", Type(IntType, .bits=TYPE_IBITS64), "Int64_t", "Int64$info", TypedArray(ns_entry_t,
|
||||
{"abs", "labs", "func(i:Int64 -> Int64)"},
|
||||
@ -158,7 +148,7 @@ env_t *new_compilation_unit(CORD libname)
|
||||
{"modulo", "Int64$modulo", "func(x,y:Int64 -> Int64)"},
|
||||
{"modulo1", "Int64$modulo1", "func(x,y:Int64 -> Int64)"},
|
||||
{"octal", "Int64$octal", "func(i:Int64, digits=0, prefix=yes -> Text)"},
|
||||
{"to", "Int64$to", "func(from:Int64,to:Int64 -> Range)"},
|
||||
{"to", "Int64$to", "func(from:Int64,to:Int64,step=none:Int64 -> func(->Int?))"},
|
||||
{"unsigned_left_shifted", "Int64$unsigned_left_shifted", "func(x:Int64,y:Int64 -> Int64)"},
|
||||
{"unsigned_right_shifted", "Int64$unsigned_right_shifted", "func(x:Int64,y:Int64 -> Int64)"},
|
||||
{"wrapping_minus", "Int64$wrapping_minus", "func(x:Int64,y:Int64 -> Int64)"},
|
||||
@ -178,7 +168,7 @@ env_t *new_compilation_unit(CORD libname)
|
||||
{"modulo", "Int32$modulo", "func(x,y:Int32 -> Int32)"},
|
||||
{"modulo1", "Int32$modulo1", "func(x,y:Int32 -> Int32)"},
|
||||
{"octal", "Int32$octal", "func(i:Int32, digits=0, prefix=yes -> Text)"},
|
||||
{"to", "Int32$to", "func(from:Int32,to:Int32 -> Range)"},
|
||||
{"to", "Int32$to", "func(from:Int32,to:Int32,step=none:Int32 -> func(->Int?))"},
|
||||
{"unsigned_left_shifted", "Int32$unsigned_left_shifted", "func(x:Int32,y:Int32 -> Int32)"},
|
||||
{"unsigned_right_shifted", "Int32$unsigned_right_shifted", "func(x:Int32,y:Int32 -> Int32)"},
|
||||
{"wrapping_minus", "Int32$wrapping_minus", "func(x:Int32,y:Int32 -> Int32)"},
|
||||
@ -198,7 +188,7 @@ env_t *new_compilation_unit(CORD libname)
|
||||
{"modulo", "Int16$modulo", "func(x,y:Int16 -> Int16)"},
|
||||
{"modulo1", "Int16$modulo1", "func(x,y:Int16 -> Int16)"},
|
||||
{"octal", "Int16$octal", "func(i:Int16, digits=0, prefix=yes -> Text)"},
|
||||
{"to", "Int16$to", "func(from:Int16,to:Int16 -> Range)"},
|
||||
{"to", "Int16$to", "func(from:Int16,to:Int16,step=none:Int16 -> func(->Int?))"},
|
||||
{"unsigned_left_shifted", "Int16$unsigned_left_shifted", "func(x:Int16,y:Int16 -> Int16)"},
|
||||
{"unsigned_right_shifted", "Int16$unsigned_right_shifted", "func(x:Int16,y:Int16 -> Int16)"},
|
||||
{"wrapping_minus", "Int16$wrapping_minus", "func(x:Int16,y:Int16 -> Int16)"},
|
||||
@ -218,7 +208,7 @@ env_t *new_compilation_unit(CORD libname)
|
||||
{"modulo", "Int8$modulo", "func(x,y:Int8 -> Int8)"},
|
||||
{"modulo1", "Int8$modulo1", "func(x,y:Int8 -> Int8)"},
|
||||
{"octal", "Int8$octal", "func(i:Int8, digits=0, prefix=yes -> Text)"},
|
||||
{"to", "Int8$to", "func(from:Int8,to:Int8 -> Range)"},
|
||||
{"to", "Int8$to", "func(from:Int8,to:Int8,step=none:Int8 -> func(->Int?))"},
|
||||
{"unsigned_left_shifted", "Int8$unsigned_left_shifted", "func(x:Int8,y:Int8 -> Int8)"},
|
||||
{"unsigned_right_shifted", "Int8$unsigned_right_shifted", "func(x:Int8,y:Int8 -> Int8)"},
|
||||
{"wrapping_minus", "Int8$wrapping_minus", "func(x:Int8,y:Int8 -> Int8)"},
|
||||
@ -285,10 +275,6 @@ env_t *new_compilation_unit(CORD libname)
|
||||
#undef F_opt
|
||||
#undef F
|
||||
#undef C
|
||||
{"Range", RANGE_TYPE, "Range_t", "Range", TypedArray(ns_entry_t,
|
||||
{"reversed", "Range$reversed", "func(range:Range -> Range)"},
|
||||
{"by", "Range$by", "func(range:Range, step:Int -> Range)"},
|
||||
)},
|
||||
{"Match", MATCH_TYPE, "Match_t", "Match", TypedArray(ns_entry_t,
|
||||
// No methods
|
||||
)},
|
||||
@ -547,16 +533,6 @@ env_t *for_scope(env_t *env, ast_t *ast)
|
||||
type_t *iter_t = value_type(get_type(env, for_->iter));
|
||||
env_t *scope = fresh_scope(env);
|
||||
|
||||
if (iter_t == RANGE_TYPE) {
|
||||
if (for_->vars) {
|
||||
if (for_->vars->next)
|
||||
code_err(for_->vars->next->ast, "This is too many variables for this loop");
|
||||
const char *var = Match(for_->vars->ast, Var)->name;
|
||||
set_binding(scope, var, INT_TYPE, CORD_cat("_$", var));
|
||||
}
|
||||
return scope;
|
||||
}
|
||||
|
||||
switch (iter_t->tag) {
|
||||
case ArrayType: {
|
||||
type_t *item_t = Match(iter_t, ArrayType)->item_type;
|
||||
|
@ -71,7 +71,6 @@ binding_t *get_namespace_binding(env_t *env, ast_t *self, const char *name);
|
||||
#define code_err(ast, ...) compiler_err((ast)->file, (ast)->start, (ast)->end, __VA_ARGS__)
|
||||
extern type_t *TEXT_TYPE;
|
||||
extern type_t *MATCH_TYPE;
|
||||
extern type_t *RANGE_TYPE;
|
||||
extern type_t *RNG_TYPE;
|
||||
extern type_t *THREAD_TYPE;
|
||||
|
||||
|
@ -29,7 +29,6 @@ some common functionality.
|
||||
- Paths: [header](stdlib/paths.h), [implementation](stdlib/paths.c)
|
||||
- Patterns: [header](stdlib/patterns.h), [implementation](stdlib/patterns.c)
|
||||
- Pointers: [header](stdlib/pointers.h), [implementation](stdlib/pointers.c)
|
||||
- Ranges: [header](stdlib/ranges.h), [implementation](stdlib/ranges.c)
|
||||
- Shell: [header](stdlib/shell.h), [implementation](stdlib/shell.c)
|
||||
- Tables: [header](stdlib/tables.h), [implementation](stdlib/tables.c)
|
||||
- Text: [header](stdlib/text.h), [implementation](stdlib/text.c)
|
||||
|
@ -62,10 +62,6 @@ typedef struct {
|
||||
void *fn, *userdata;
|
||||
} Closure_t;
|
||||
|
||||
typedef struct Range_s {
|
||||
Int_t first, last, step;
|
||||
} Range_t;
|
||||
|
||||
enum text_type { TEXT_ASCII, TEXT_GRAPHEMES, TEXT_CONCAT };
|
||||
|
||||
typedef struct Text_s {
|
||||
|
@ -32,6 +32,11 @@ public Text_t Int$as_text(const void *i, bool colorize, const TypeInfo_t*) {
|
||||
return text;
|
||||
}
|
||||
|
||||
static bool Int$is_none(const void *i, const TypeInfo_t*)
|
||||
{
|
||||
return ((Int_t*)i)->small == 0;
|
||||
}
|
||||
|
||||
public PUREFUNC int32_t Int$compare_value(const Int_t x, const Int_t y) {
|
||||
if (likely(x.small & y.small & 1))
|
||||
return (x.small > y.small) - (x.small < y.small);
|
||||
@ -330,8 +335,31 @@ public OptionalInt_t Int$sqrt(Int_t i)
|
||||
return Int$from_mpz(result);
|
||||
}
|
||||
|
||||
public PUREFUNC Range_t Int$to(Int_t from, Int_t to) {
|
||||
return (Range_t){from, to, Int$compare_value(to, from) >= 0 ? (Int_t){.small=(1<<2)|1} : (Int_t){.small=(-1>>2)|1}};
|
||||
typedef struct {
|
||||
OptionalInt_t current, last;
|
||||
Int_t step;
|
||||
} IntRange_t;
|
||||
|
||||
static OptionalInt_t _next_int(IntRange_t *info)
|
||||
{
|
||||
OptionalInt_t i = info->current;
|
||||
if (!Int$is_none(&i, &Int$info)) {
|
||||
Int_t next = Int$plus(i, info->step);
|
||||
if (!Int$is_none(&info->last, &Int$info) && Int$compare_value(next, info->last) == Int$compare_value(info->step, I(0)))
|
||||
next = NONE_INT;
|
||||
info->current = next;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
public PUREFUNC Closure_t Int$to(Int_t first, Int_t last, OptionalInt_t step) {
|
||||
IntRange_t *range = GC_MALLOC(sizeof(IntRange_t));
|
||||
range->current = first;
|
||||
range->last = last;
|
||||
range->step = Int$is_none(&step, &Int$info) ?
|
||||
Int$compare_value(last, first) >= 0 ? (Int_t){.small=(1<<2)|1} : (Int_t){.small=(-1>>2)|1}
|
||||
: step;
|
||||
return (Closure_t){.fn=_next_int, .userdata=range};
|
||||
}
|
||||
|
||||
public Int_t Int$from_str(const char *str) {
|
||||
@ -415,11 +443,6 @@ public Int_t Int$factorial(Int_t n)
|
||||
return Int$from_mpz(ret);
|
||||
}
|
||||
|
||||
static bool Int$is_none(const void *i, const TypeInfo_t*)
|
||||
{
|
||||
return ((Int_t*)i)->small == 0;
|
||||
}
|
||||
|
||||
static void Int$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t*)
|
||||
{
|
||||
Int_t i = *(Int_t*)obj;
|
||||
@ -545,8 +568,12 @@ public void Int32$deserialize(FILE *in, void *outval, Array_t*, const TypeInfo_t
|
||||
} \
|
||||
return bit_array; \
|
||||
} \
|
||||
public to_attr Range_t KindOfInt ## $to(c_type from, c_type to) { \
|
||||
return (Range_t){Int64_to_Int(from), Int64_to_Int(to), to >= from ? I_small(1): I_small(-1)}; \
|
||||
public to_attr Closure_t KindOfInt ## $to(c_type first, c_type last, Optional ## KindOfInt ## _t step) { \
|
||||
IntRange_t *range = GC_MALLOC(sizeof(IntRange_t)); \
|
||||
range->current = KindOfInt##_to_Int(first); \
|
||||
range->last = KindOfInt##_to_Int(last); \
|
||||
range->step = step.is_none ? (last >= first ? I_small(1) : I_small(-1)) : KindOfInt##_to_Int(step.i); \
|
||||
return (Closure_t){.fn=_next_int, .userdata=range}; \
|
||||
} \
|
||||
public PUREFUNC Optional ## KindOfInt ## _t KindOfInt ## $parse(Text_t text) { \
|
||||
OptionalInt_t full_int = Int$parse(text); \
|
||||
|
@ -22,7 +22,7 @@
|
||||
#define I16(x) ((int16_t)x)
|
||||
#define I8(x) ((int8_t)x)
|
||||
|
||||
#define DEFINE_INT_TYPE(c_type, type_name, to_attr) \
|
||||
#define DEFINE_INT_TYPE(c_type, type_name) \
|
||||
typedef struct { \
|
||||
c_type i; \
|
||||
bool is_none:1; \
|
||||
@ -34,7 +34,7 @@
|
||||
Text_t type_name ## $hex(c_type i, Int_t digits, bool uppercase, bool prefix); \
|
||||
Text_t type_name ## $octal(c_type i, Int_t digits, bool prefix); \
|
||||
Array_t type_name ## $bits(c_type x); \
|
||||
to_attr Range_t type_name ## $to(c_type from, c_type to); \
|
||||
Closure_t type_name ## $to(c_type first, c_type last, Optional ## type_name ## _t step); \
|
||||
PUREFUNC Optional ## type_name ## _t type_name ## $parse(Text_t text); \
|
||||
MACROLIKE PUREFUNC c_type type_name ## $clamped(c_type x, c_type min, c_type max) { \
|
||||
return x < min ? min : (x > max ? max : x); \
|
||||
@ -68,10 +68,10 @@
|
||||
return (c_type)((u##c_type)x >> y); \
|
||||
}
|
||||
|
||||
DEFINE_INT_TYPE(int64_t, Int64, __attribute__(()))
|
||||
DEFINE_INT_TYPE(int32_t, Int32, CONSTFUNC)
|
||||
DEFINE_INT_TYPE(int16_t, Int16, CONSTFUNC)
|
||||
DEFINE_INT_TYPE(int8_t, Int8, CONSTFUNC)
|
||||
DEFINE_INT_TYPE(int64_t, Int64)
|
||||
DEFINE_INT_TYPE(int32_t, Int32)
|
||||
DEFINE_INT_TYPE(int16_t, Int16)
|
||||
DEFINE_INT_TYPE(int8_t, Int8)
|
||||
#undef DEFINE_INT_TYPE
|
||||
|
||||
#define NONE_INT64 ((OptionalInt64_t){.is_none=true})
|
||||
@ -101,7 +101,7 @@ PUREFUNC bool Int$equal_value(const Int_t x, const Int_t y);
|
||||
Text_t Int$format(Int_t i, Int_t digits);
|
||||
Text_t Int$hex(Int_t i, Int_t digits, bool uppercase, bool prefix);
|
||||
Text_t Int$octal(Int_t i, Int_t digits, bool prefix);
|
||||
PUREFUNC Range_t Int$to(Int_t from, Int_t to);
|
||||
PUREFUNC Closure_t Int$to(Int_t first, Int_t last, OptionalInt_t step);
|
||||
OptionalInt_t Int$from_str(const char *str);
|
||||
OptionalInt_t Int$parse(Text_t text);
|
||||
Int_t Int$abs(Int_t x);
|
||||
|
@ -1,74 +0,0 @@
|
||||
// Functions that operate on numeric ranges
|
||||
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <gc.h>
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include "integers.h"
|
||||
#include "text.h"
|
||||
#include "types.h"
|
||||
#include "util.h"
|
||||
|
||||
|
||||
PUREFUNC static int32_t Range$compare(const void *vx, const void *vy, const TypeInfo_t *)
|
||||
{
|
||||
if (vx == vy) return 0;
|
||||
Range_t *x = (Range_t*)vx, *y = (Range_t*)vy;
|
||||
int32_t diff = Int$compare(&x->first, &y->first, &Int$info);
|
||||
if (diff != 0) return diff;
|
||||
diff = Int$compare(&x->last, &y->last, &Int$info);
|
||||
if (diff != 0) return diff;
|
||||
return Int$compare(&x->step, &y->step, &Int$info);
|
||||
}
|
||||
|
||||
PUREFUNC static bool Range$equal(const void *vx, const void *vy, const TypeInfo_t*)
|
||||
{
|
||||
if (vx == vy) return true;
|
||||
Range_t *x = (Range_t*)vx, *y = (Range_t*)vy;
|
||||
return Int$equal(&x->first, &y->first, &Int$info) && Int$equal(&x->last, &y->last, &Int$info) && Int$equal(&x->step, &y->step, &Int$info);
|
||||
}
|
||||
|
||||
static Text_t Range$as_text(const void *obj, bool use_color, const TypeInfo_t *)
|
||||
{
|
||||
if (!obj) return Text("Range");
|
||||
|
||||
Range_t *r = (Range_t*)obj;
|
||||
Text_t first = Int$as_text(&r->first, use_color, &Int$info);
|
||||
Text_t last = Int$as_text(&r->last, use_color, &Int$info);
|
||||
Text_t step = Int$as_text(&r->step, use_color, &Int$info);
|
||||
return Text$format(use_color ? "\x1b[0;1mRange\x1b[m(first=%k, last=%k, step=%k)"
|
||||
: "Range(first=%k, last=%k, step=%k)", &first, &last, &step);
|
||||
}
|
||||
|
||||
PUREFUNC public Range_t Range$reversed(Range_t r)
|
||||
{
|
||||
return (Range_t){r.last, r.first, Int$negative(r.step)};
|
||||
}
|
||||
|
||||
PUREFUNC public Range_t Range$by(Range_t r, Int_t step)
|
||||
{
|
||||
return (Range_t){r.first, r.last, Int$times(step, r.step)};
|
||||
}
|
||||
|
||||
static bool Range$is_none(const void *obj, const TypeInfo_t*)
|
||||
{
|
||||
return ((Range_t*)obj)->step.small == 0x1;
|
||||
}
|
||||
|
||||
public const TypeInfo_t Range$info = {
|
||||
.size=sizeof(Range_t),
|
||||
.align=__alignof(Range_t),
|
||||
.metamethods={
|
||||
.as_text=Range$as_text,
|
||||
.compare=Range$compare,
|
||||
.equal=Range$equal,
|
||||
.is_none=Range$is_none,
|
||||
},
|
||||
};
|
||||
|
||||
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
|
@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// Ranges represent numeric ranges
|
||||
|
||||
PUREFUNC Range_t Range$reversed(Range_t r);
|
||||
PUREFUNC Range_t Range$by(Range_t r, Int_t step);
|
||||
|
||||
extern const TypeInfo_t Range$info;
|
||||
|
||||
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1
|
@ -24,7 +24,6 @@
|
||||
#include "paths.h"
|
||||
#include "patterns.h"
|
||||
#include "pointers.h"
|
||||
#include "ranges.h"
|
||||
#include "rng.h"
|
||||
#include "shell.h"
|
||||
#include "siphash.h"
|
||||
|
@ -1,31 +0,0 @@
|
||||
|
||||
func main():
|
||||
>> r := 5:to(10):by(2)
|
||||
= Range(first=5, last=10, step=2)
|
||||
>> r.first
|
||||
= 5
|
||||
>> r.last
|
||||
= 10
|
||||
>> r.step
|
||||
= 2
|
||||
|
||||
>> Range(1, 5) == 1:to(5)
|
||||
= yes
|
||||
|
||||
>> 1:to(5) == 5:to(1):reversed()
|
||||
= yes
|
||||
|
||||
>> Range(1, 5) == Range(5, 10)
|
||||
= no
|
||||
|
||||
>> [i for i in 3:to(5)]
|
||||
= [3, 4, 5]
|
||||
|
||||
>> [i for i in 3:to(10):by(2)]
|
||||
= [3, 5, 7, 9]
|
||||
|
||||
>> [i for i in 3:to(10):reversed():by(2)]
|
||||
= [10, 8, 6, 4]
|
||||
|
||||
>> [i for i in (2:to(10):by(2)):by(2)]
|
||||
= [2, 6, 10]
|
Loading…
Reference in New Issue
Block a user