From c4479e4bd61fb2c68fdac2637a20d6d99f7b9552 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Thu, 13 Feb 2025 15:21:00 -0500 Subject: [PATCH] Add Int:onward() iterator --- compile.c | 14 ++++++++++++++ docs/integers.md | 31 +++++++++++++++++++++++++++++++ environment.c | 17 +++++++++++------ stdlib/integers.c | 15 +++++++++++++++ stdlib/integers.h | 2 ++ 5 files changed, 73 insertions(+), 6 deletions(-) diff --git a/compile.c b/compile.c index 04ec9e0..dc00d01 100644 --- a/compile.c +++ b/compile.c @@ -1543,6 +1543,7 @@ static CORD _compile_statement(env_t *env, ast_t *ast) // 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) { + // TODO: support other integer types arg_ast_t *args = Match(for_->iter, MethodCall)->args; if (!args) code_err(for_->iter, "to() needs at least one argument"); @@ -1587,6 +1588,19 @@ static CORD _compile_statement(env_t *env, ast_t *ast) "\t", naked_body, "}", stop); + } else if (for_->iter->tag == MethodCall && streq(Match(for_->iter, MethodCall)->name, "onward") && + get_type(env, Match(for_->iter, MethodCall)->self)->tag == BigIntType) { + // Special case for Int:onward() + arg_ast_t *args = Match(for_->iter, MethodCall)->args; + arg_t *arg_spec = new(arg_t, .name="step", .type=INT_TYPE, .default_val=FakeAST(Int, .str="1"), .next=NULL); + CORD step = compile_arguments(env, for_->iter, arg_spec, args); + CORD value = for_->vars ? compile(body_scope, for_->vars->ast) : "i"; + return CORD_all( + "for (Int_t ", value, " = ", compile(env, Match(for_->iter, MethodCall)->self), ", ", + "step = ", step, "; ; ", value, " = Int$plus(", value, ", step)) {\n" + "\t", naked_body, + "}", + stop); } type_t *iter_t = value_type(get_type(env, for_->iter)); diff --git a/docs/integers.md b/docs/integers.md index b660031..84f3341 100644 --- a/docs/integers.md +++ b/docs/integers.md @@ -257,6 +257,37 @@ The octal string representation of the integer. --- +### `onward` + +**Description:** +Return an iterator that counts infinitely from the starting integer (with an +optional step size). + +**Signature:** +```tomo +func onward(first: Int, step: Int = 1 -> Text) +``` + +**Parameters:** + +- `first`: The starting integer. +- `step`: The increment step size (default: 1). + +**Returns:** +An iterator function that counts onward from the starting integer. + +**Example:** +```tomo +nums := &[:Int] +for i in 5:onward(): + nums:insert(i) + stop if i == 10 +>> nums[] += [5, 6, 7, 8, 9, 10] +``` + +--- + ### `parse` **Description:** diff --git a/environment.c b/environment.c index 1427e9e..1354999 100644 --- a/environment.c +++ b/environment.c @@ -115,7 +115,6 @@ env_t *new_compilation_unit(CORD libname) {"factorial", "Int$factorial", "func(x:Int -> Int)"}, {"format", "Int$format", "func(i:Int, digits=0 -> Text)"}, {"gcd", "Int$gcd", "func(x,y:Int -> Int)"}, - {"parse", "Int$parse", "func(text:Text -> Int?)"}, {"hex", "Int$hex", "func(i:Int, digits=0, uppercase=yes, prefix=yes -> Text)"}, {"is_prime", "Int$is_prime", "func(x:Int,reps=50 -> Bool)"}, {"left_shifted", "Int$left_shifted", "func(x,y:Int -> Int)"}, @@ -126,13 +125,15 @@ env_t *new_compilation_unit(CORD libname) {"negative", "Int$negative", "func(x:Int -> Int)"}, {"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?)"}, {"plus", "Int$plus", "func(x,y:Int -> Int)"}, {"power", "Int$power", "func(base:Int,exponent:Int -> Int)"}, {"prev_prime", "Int$prev_prime", "func(x:Int -> Int)"}, {"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,step=none:Int -> func(->Int?))"}, + {"to", "Int$to", "func(first:Int,last: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)"}, @@ -148,7 +149,8 @@ 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,step=none:Int64 -> func(->Int?))"}, + {"onward", "Int64$onward", "func(first:Int64,step=Int64(1) -> func(->Int?))"}, + {"to", "Int64$to", "func(first:Int64,last: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)"}, @@ -168,7 +170,8 @@ 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,step=none:Int32 -> func(->Int?))"}, + {"onward", "Int32$onward", "func(first:Int32,step=Int32(1) -> func(->Int?))"}, + {"to", "Int32$to", "func(first:Int32,last: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)"}, @@ -188,7 +191,8 @@ 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,step=none:Int16 -> func(->Int?))"}, + {"onward", "Int16$onward", "func(first:Int16,step=Int16(1) -> func(->Int?))"}, + {"to", "Int16$to", "func(first:Int16,last: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)"}, @@ -208,7 +212,8 @@ 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,step=none:Int8 -> func(->Int?))"}, + {"onward", "Int8$onward", "func(first:Int8,step=Int8(1) -> func(->Int?))"}, + {"to", "Int8$to", "func(first:Int8,last: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)"}, diff --git a/stdlib/integers.c b/stdlib/integers.c index 858025f..835da97 100644 --- a/stdlib/integers.c +++ b/stdlib/integers.c @@ -362,6 +362,14 @@ public PUREFUNC Closure_t Int$to(Int_t first, Int_t last, OptionalInt_t step) { return (Closure_t){.fn=_next_int, .userdata=range}; } +public PUREFUNC Closure_t Int$onward(Int_t first, Int_t step) { + IntRange_t *range = GC_MALLOC(sizeof(IntRange_t)); + range->current = first; + range->last = NONE_INT; + range->step = step; + return (Closure_t){.fn=_next_int, .userdata=range}; +} + public Int_t Int$from_str(const char *str) { mpz_t i; int result; @@ -575,6 +583,13 @@ public void Int32$deserialize(FILE *in, void *outval, Array_t*, const TypeInfo_t 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 to_attr Closure_t KindOfInt ## $onward(c_type first, c_type step) { \ + IntRange_t *range = GC_MALLOC(sizeof(IntRange_t)); \ + range->current = KindOfInt##_to_Int(first); \ + range->last = NONE_INT; \ + range->step = KindOfInt##_to_Int(step); \ + 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); \ if (full_int.small == 0) return (Optional ## KindOfInt ## _t){.is_none=true}; \ diff --git a/stdlib/integers.h b/stdlib/integers.h index fce243a..7bed455 100644 --- a/stdlib/integers.h +++ b/stdlib/integers.h @@ -35,6 +35,7 @@ Text_t type_name ## $octal(c_type i, Int_t digits, bool prefix); \ Array_t type_name ## $bits(c_type x); \ 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); \ MACROLIKE PUREFUNC c_type type_name ## $clamped(c_type x, c_type min, c_type max) { \ return x < min ? min : (x > max ? max : x); \ @@ -102,6 +103,7 @@ 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 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); Int_t Int$abs(Int_t x);