diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2024-11-03 12:20:53 -0500 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2024-11-03 12:20:53 -0500 |
| commit | 078b4431854895c64d9b55bc3e1a9122cc911f48 (patch) | |
| tree | aead6d835d0b9227059dd90bc2c626003e807ea9 | |
| parent | d905fa4888876eddc7716e88ffa158ed657bcf37 (diff) | |
Add a `repeat` keyword
| -rw-r--r-- | ast.c | 1 | ||||
| -rw-r--r-- | ast.h | 5 | ||||
| -rw-r--r-- | compile.c | 19 | ||||
| -rw-r--r-- | docs/threads.md | 2 | ||||
| -rw-r--r-- | parse.c | 10 | ||||
| -rw-r--r-- | test/threads.tm | 2 | ||||
| -rw-r--r-- | typecheck.c | 2 |
7 files changed, 36 insertions, 5 deletions
@@ -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), @@ -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 { @@ -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 ) @@ -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) |
