aboutsummaryrefslogtreecommitdiff
path: root/parse.c
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2024-07-04 16:23:05 -0400
committerBruce Hill <bruce@bruce-hill.com>2024-07-04 16:23:05 -0400
commit9d9fe12987bc8e7c3266ec320d04a97a37c3fb1b (patch)
tree8a79d864f60d81f08a0776b6f85dbab242ecc89a /parse.c
parentd073c10137a1aa8a3d3f5e3a71b22cbb4725b47c (diff)
Add `!!` statement for printing text
Diffstat (limited to 'parse.c')
-rw-r--r--parse.c53
1 files changed, 52 insertions, 1 deletions
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;