aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2024-11-03 12:20:53 -0500
committerBruce Hill <bruce@bruce-hill.com>2024-11-03 12:20:53 -0500
commit078b4431854895c64d9b55bc3e1a9122cc911f48 (patch)
treeaead6d835d0b9227059dd90bc2c626003e807ea9
parentd905fa4888876eddc7716e88ffa158ed657bcf37 (diff)
Add a `repeat` keyword
-rw-r--r--ast.c1
-rw-r--r--ast.h5
-rw-r--r--compile.c19
-rw-r--r--docs/threads.md2
-rw-r--r--parse.c10
-rw-r--r--test/threads.tm2
-rw-r--r--typecheck.c2
7 files changed, 36 insertions, 5 deletions
diff --git a/ast.c b/ast.c
index 8eca3147..65a8f405 100644
--- a/ast.c
+++ b/ast.c
@@ -137,6 +137,7 @@ CORD ast_to_xml(ast_t *ast)
T(For, "<For>%r%r%r%r%r</For>", ast_list_to_xml(data.vars), optional_tagged("iterable", data.iter),
optional_tagged("body", data.body), optional_tagged("empty", data.empty))
T(While, "<While>%r%r</While>", optional_tagged("condition", data.condition), optional_tagged("body", data.body))
+ T(Repeat, "<Repeat>%r</Repeat>", optional_tagged("body", data.body))
T(If, "<If>%r%r%r</If>", optional_tagged("condition", data.condition), optional_tagged("body", data.body), optional_tagged("else", data.else_body))
T(When, "<When><subject>%r</subject>%r%r</When>", ast_to_xml(data.subject), when_clauses_to_xml(data.clauses), optional_tagged("else", data.else_body))
T(Reduction, "<Reduction>%r%r</Reduction>", optional_tagged("iterable", data.iter),
diff --git a/ast.h b/ast.h
index 5d7f87d2..6546dd2d 100644
--- a/ast.h
+++ b/ast.h
@@ -133,7 +133,7 @@ typedef enum {
FunctionDef, Lambda,
FunctionCall, MethodCall,
Block,
- For, While, If, When,
+ For, While, If, When, Repeat,
Reduction,
Skip, Stop, Pass,
Defer,
@@ -256,6 +256,9 @@ struct ast_s {
ast_t *condition, *body;
} While;
struct {
+ ast_t *body;
+ } Repeat;
+ struct {
ast_t *condition, *body, *else_body;
} If;
struct {
diff --git a/compile.c b/compile.c
index 0ab4fa41..91abbef8 100644
--- a/compile.c
+++ b/compile.c
@@ -1056,6 +1056,23 @@ CORD compile_statement(env_t *env, ast_t *ast)
loop = CORD_all(loop, "\n", loop_ctx.stop_label, ":;");
return loop;
}
+ case Repeat: {
+ ast_t *body = Match(ast, Repeat)->body;
+ env_t *scope = fresh_scope(env);
+ loop_ctx_t loop_ctx = (loop_ctx_t){
+ .loop_name="repeat",
+ .deferred=scope->deferred,
+ .next=env->loop_ctx,
+ };
+ scope->loop_ctx = &loop_ctx;
+ CORD body_code = compile_statement(scope, body);
+ if (loop_ctx.skip_label)
+ body_code = CORD_all(body_code, "\n", loop_ctx.skip_label, ": continue;");
+ CORD loop = CORD_all("for (;;) {\n\t", body_code, "\n}");
+ if (loop_ctx.stop_label)
+ loop = CORD_all(loop, "\n", loop_ctx.stop_label, ":;");
+ return loop;
+ }
case For: {
auto for_ = Match(ast, For);
@@ -3385,7 +3402,7 @@ CORD compile(env_t *env, ast_t *ast)
case Defer: code_err(ast, "Compiling 'defer' as expression!");
case Extern: code_err(ast, "Externs are not supported as expressions");
case TableEntry: code_err(ast, "Table entries should not be compiled directly");
- case Declare: case Assign: case UpdateAssign: case For: case While: case StructDef: case LangDef:
+ case Declare: case Assign: case UpdateAssign: case For: case While: case Repeat: case StructDef: case LangDef:
case EnumDef: case FunctionDef: case Skip: case Stop: case Pass: case Return: case DocTest: case PrintStatement:
code_err(ast, "This is not a valid expression");
default: case Unknown: code_err(ast, "Unknown AST");
diff --git a/docs/threads.md b/docs/threads.md
index ab0ce399..68fdf7d7 100644
--- a/docs/threads.md
+++ b/docs/threads.md
@@ -28,7 +28,7 @@ A new `Thread` object representing the created thread.
>> jobs := |Int|
>> results := |Int|
>> thread := Thread.new(func():
- while yes:
+ repeat:
input := jobs:get()
results:give(input + 10
)
diff --git a/parse.c b/parse.c
index 2ea8cd78..7af03a16 100644
--- a/parse.c
+++ b/parse.c
@@ -122,6 +122,7 @@ static PARSER(parse_parens);
static PARSER(parse_pass);
static PARSER(parse_path);
static PARSER(parse_reduction);
+static PARSER(parse_repeat);
static PARSER(parse_return);
static PARSER(parse_say);
static PARSER(parse_set);
@@ -1222,6 +1223,14 @@ PARSER(parse_while) {
return NewAST(ctx->file, start, pos, While, .condition=condition, .body=body);
}
+PARSER(parse_repeat) {
+ // repeat: [<indent>] body
+ const char *start = pos;
+ if (!match_word(&pos, "repeat")) return NULL;
+ ast_t *body = expect(ctx, start, &pos, parse_block, "I expected a body for this 'repeat'");
+ return NewAST(ctx->file, start, pos, Repeat, .body=body);
+}
+
PARSER(parse_heap_alloc) {
const char *start = pos;
if (!match(&pos, "@")) return NULL;
@@ -1874,6 +1883,7 @@ PARSER(parse_extended_expr) {
|| (expr=optional(ctx, &pos, parse_while))
|| (expr=optional(ctx, &pos, parse_if))
|| (expr=optional(ctx, &pos, parse_when))
+ || (expr=optional(ctx, &pos, parse_repeat))
|| (expr=optional(ctx, &pos, parse_do))
)
return expr;
diff --git a/test/threads.tm b/test/threads.tm
index 2ac2b679..8fa61778 100644
--- a/test/threads.tm
+++ b/test/threads.tm
@@ -27,7 +27,7 @@ func main():
results := |:Int; max_size|
>> thread := Thread.new(func():
!! In another thread!
- while yes:
+ repeat:
>> got := jobs:get()
when got is Increment(x):
>> results:give(x+1)
diff --git a/typecheck.c b/typecheck.c
index bff7d080..7cc081de 100644
--- a/typecheck.c
+++ b/typecheck.c
@@ -1229,7 +1229,7 @@ type_t *get_type(env_t *env, ast_t *ast)
}
}
- case While: case For: return Type(VoidType);
+ case While: case Repeat: case For: return Type(VoidType);
case InlineCCode: {
auto inline_code = Match(ast, InlineCCode);
if (inline_code->type)