From 9d9fe12987bc8e7c3266ec320d04a97a37c3fb1b Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Thu, 4 Jul 2024 16:23:05 -0400 Subject: Add `!!` statement for printing text --- parse.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) (limited to 'parse.c') diff --git a/parse.c b/parse.c index 73c65d46..fd757444 100644 --- a/parse.c +++ b/parse.c @@ -97,6 +97,7 @@ static PARSER(parse_extern); static PARSER(parse_inline_c); static PARSER(parse_declaration); static PARSER(parse_doctest); +static PARSER(parse_say); static PARSER(parse_use); static PARSER(parse_import); static PARSER(parse_linker); @@ -1527,7 +1528,8 @@ PARSER(parse_assignment) { PARSER(parse_statement) { ast_t *stmt = NULL; if ((stmt=parse_declaration(ctx, pos)) - || (stmt=parse_doctest(ctx, pos))) + || (stmt=parse_doctest(ctx, pos)) + || (stmt=parse_say(ctx, pos))) return stmt; if (!(false @@ -2014,6 +2016,55 @@ PARSER(parse_doctest) { return NewAST(ctx->file, start, pos, DocTest, .expr=expr, .output=output); } +PARSER(parse_say) { + const char *start = pos; + if (!match(&pos, "!!")) return NULL; + spaces(&pos); + + ast_list_t *chunks = NULL; + CORD chunk = CORD_EMPTY; + const char *chunk_start = pos; + const char open_interp = '{', close_interp = '}'; + while (pos < ctx->file->text + ctx->file->len) { + if (*pos == open_interp) { // Interpolation + const char *interp_start = pos; + if (chunk) { + ast_t *literal = NewAST(ctx->file, chunk_start, pos, TextLiteral, .cord=chunk); + chunks = new(ast_list_t, .ast=literal, .next=chunks); + chunk = NULL; + } + ++pos; + ast_t *interp; + if (close_interp) { + whitespace(&pos); + interp = expect(ctx, interp_start, &pos, parse_expr, "I expected an interpolation expression here"); + whitespace(&pos); + expect_closing(ctx, &pos, (char[]){close_interp, 0}, "I was expecting a '%c' to finish this interpolation", close_interp); + } else { + if (*pos == ' ' || *pos == '\t') + parser_err(ctx, pos, pos+1, "Whitespace is not allowed before an interpolation here"); + interp = expect(ctx, interp_start, &pos, parse_term, "I expected an interpolation term here"); + } + chunks = new(ast_list_t, .ast=interp, .next=chunks); + chunk_start = pos; + } else if (*pos == '\r' || *pos == '\n') { // Newline + break; + } else { // Plain character + chunk = CORD_cat_char(chunk, *pos); + ++pos; + } + } + + if (chunk) { + ast_t *literal = NewAST(ctx->file, chunk_start, pos, TextLiteral, .cord=chunk); + chunks = new(ast_list_t, .ast=literal, .next=chunks); + chunk = NULL; + } + + REVERSE_LIST(chunks); + return NewAST(ctx->file, start, pos, PrintStatement, .to_print=chunks); +} + PARSER(parse_use) { const char *start = pos; if (!match_word(&pos, "use")) return NULL; -- cgit v1.2.3