From 1df26851d73e50407a3b7c79bcdb5b0cc053fe67 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Sat, 18 May 2024 16:31:34 -0400 Subject: [PATCH] Add syntax for "inline C(...)" --- ast.h | 1 + builtins/files.c | 38 +++++++++++++++++++------------------- builtins/files.h | 3 +-- builtins/functions.c | 22 +--------------------- builtins/functions.h | 5 ----- builtins/util.h | 1 - compile.c | 8 +++++++- environment.c | 2 +- parse.c | 35 +++++++++++++++++++++++++++++++++-- repl.c | 2 +- typecheck.c | 5 ++++- 11 files changed, 68 insertions(+), 54 deletions(-) diff --git a/ast.h b/ast.h index 4307532..e9e4dc3 100644 --- a/ast.h +++ b/ast.h @@ -275,6 +275,7 @@ struct ast_s { } LinkerDirective; struct { CORD code; + type_ast_t *type; } InlineCCode; } __data; }; diff --git a/builtins/files.c b/builtins/files.c index a500687..2375fc8 100644 --- a/builtins/files.c +++ b/builtins/files.c @@ -209,7 +209,7 @@ static int fputc_column(FILE *out, char c, char print_char, int *column) // // Print a span from a file // -public int fprint_span(FILE *out, file_t *file, const char *start, const char *end, const char *hl_color, int64_t context_lines, bool use_color) +public int highlight_error(file_t *file, const char *start, const char *end, const char *hl_color, int64_t context_lines, bool use_color) { if (!file) return 0; @@ -229,18 +229,18 @@ public int fprint_span(FILE *out, file_t *file, const char *start, const char *e lineno_fmt = "\x1b[0;2m%*lu\x1b(0\x78\x1b(B\x1b[m "; normal_color = "\x1b[m"; empty_marker = "\x1b(0\x61\x1b(B"; - printed += fprintf(out, "\x1b[33;4;1m%s\x1b[m\n", file->relative_filename); + printed += fprintf(stderr, "\x1b[33;4;1m%s\x1b[m\n", file->relative_filename); } else { lineno_fmt = "%*lu| "; hl_color = ""; normal_color = ""; empty_marker = " "; print_carets = true; - printed += fprintf(out, "%s\n", file->relative_filename); + printed += fprintf(stderr, "%s\n", file->relative_filename); } if (context_lines == 0) - return fprintf(out, "%s%.*s%s", hl_color, (int)(end - start), start, normal_color); + return fprintf(stderr, "%s%.*s%s", hl_color, (int)(end - start), start, normal_color); int64_t start_line = get_line_number(file, start), end_line = get_line_number(file, end); @@ -257,14 +257,14 @@ public int fprint_span(FILE *out, file_t *file, const char *start, const char *e for (int64_t line_no = first_line; line_no <= last_line; ++line_no) { if (line_no > first_line + 5 && line_no < last_line - 5) { if (use_color) - printed += fprintf(out, "\x1b[0;2;3;4m ... %ld lines omitted ... \x1b[m\n", (last_line - first_line) - 11); + printed += fprintf(stderr, "\x1b[0;2;3;4m ... %ld lines omitted ... \x1b[m\n", (last_line - first_line) - 11); else - printed += fprintf(out, " ... %ld lines omitted ...\n", (last_line - first_line) - 11); + printed += fprintf(stderr, " ... %ld lines omitted ...\n", (last_line - first_line) - 11); line_no = last_line - 6; continue; } - printed += fprintf(out, lineno_fmt, digits, line_no); + printed += fprintf(stderr, lineno_fmt, digits, line_no); const char *line = get_line(file, line_no); if (!line) break; @@ -272,33 +272,33 @@ public int fprint_span(FILE *out, file_t *file, const char *start, const char *e const char *p = line; // Before match for (; *p && *p != '\r' && *p != '\n' && p < start; ++p) - printed += fputc_column(out, *p, *p, &column); + printed += fputc_column(stderr, *p, *p, &column); // Zero-width matches if (p == start && start == end) { - printed += fprintf(out, "%s%s%s", hl_color, empty_marker, normal_color); + printed += fprintf(stderr, "%s%s%s", hl_color, empty_marker, normal_color); column += 1; } // Inside match if (start <= p && p < end) { - printed += fputs(hl_color, out); + printed += fputs(hl_color, stderr); for (; *p && *p != '\r' && *p != '\n' && p < end; ++p) - printed += fputc_column(out, *p, *p, &column); - printed += fputs(normal_color, out); + printed += fputc_column(stderr, *p, *p, &column); + printed += fputs(normal_color, stderr); } // After match for (; *p && *p != '\r' && *p != '\n'; ++p) - printed += fputc_column(out, *p, *p, &column); + printed += fputc_column(stderr, *p, *p, &column); - printed += fprintf(out, "\n"); + printed += fprintf(stderr, "\n"); const char *eol = strchrnul(line, '\n'); if (print_carets && start >= line && start < eol && line <= start) { for (int num = 0; num < digits; num++) - printed += fputc(' ', out); - printed += fputs(": ", out); + printed += fputc(' ', stderr); + printed += fputs(": ", stderr); int col = 0; for (const char *sp = line; *sp && *sp != '\n'; ++sp) { char print_char; @@ -310,12 +310,12 @@ public int fprint_span(FILE *out, file_t *file, const char *start, const char *e print_char = '-'; else print_char = ' '; - printed += fputc_column(out, *sp, print_char, &col); + printed += fputc_column(stderr, *sp, print_char, &col); } - printed += fputs("\n", out); + printed += fputs("\n", stderr); } } - fflush(out); + fflush(stderr); return printed; } diff --git a/builtins/files.h b/builtins/files.h index 024cd6d..f650f78 100644 --- a/builtins/files.h +++ b/builtins/files.h @@ -5,7 +5,6 @@ #include #include -#include #include typedef struct { @@ -31,6 +30,6 @@ __attribute__((pure, nonnull)) const char *get_line(file_t *f, int64_t line_number); __attribute__((pure, nonnull)) const char *get_file_pos(file_t *f, const char *p); -int fprint_span(FILE *out, file_t *file, const char *start, const char *end, const char *hl_color, int64_t context_lines, bool use_color); +int highlight_error(file_t *file, const char *start, const char *end, const char *hl_color, int64_t context_lines, bool use_color); // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/builtins/functions.c b/builtins/functions.c index eedcc9f..b2808c5 100644 --- a/builtins/functions.c +++ b/builtins/functions.c @@ -68,7 +68,7 @@ public void fail_source(const char *filename, int64_t start, int64_t end, CORD f file_t *file = filename ? load_file(filename) : NULL; if (filename && file) { fputs("\n", stderr); - fprint_span(stderr, file, file->text+start, file->text+end, "\x1b[31;1m", 2, USE_COLOR); + highlight_error(file, file->text+start, file->text+end, "\x1b[31;1m", 2, USE_COLOR); } raise(SIGABRT); @@ -240,24 +240,4 @@ public bool pop_flag(char **argv, int *i, const char *flag, CORD *result) } } -public void *xfopen(CORD path, CORD flags) -{ - return fopen(CORD_to_const_char_star(path), CORD_to_const_char_star(flags)); -} - -public CORD xfread_all(void *fp) -{ - return CORD_from_file_eager(fp); -} - -public void xfputs(CORD text, void *fp) -{ - CORD_put(text, fp); -} - -public void xfclose(void *fp) -{ - fclose(fp); -} - // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/builtins/functions.h b/builtins/functions.h index e62fc44..f1a2867 100644 --- a/builtins/functions.h +++ b/builtins/functions.h @@ -26,9 +26,4 @@ bool generic_equal(const void *x, const void *y, const TypeInfo *type); CORD generic_as_text(const void *obj, bool colorize, const TypeInfo *type); bool pop_flag(char **argv, int *i, const char *flag, CORD *result); -void *xfopen(CORD path, CORD flags); -CORD xfread_all(void *fp); -void xfputs(CORD text, void *fp); -void xfclose(void *fp); - // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/builtins/util.h b/builtins/util.h index 1b5664d..dc42d57 100644 --- a/builtins/util.h +++ b/builtins/util.h @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include diff --git a/compile.c b/compile.c index 99e7d77..0e73eaa 100644 --- a/compile.c +++ b/compile.c @@ -1940,7 +1940,13 @@ CORD compile(env_t *env, ast_t *ast) default: code_err(ast, "Indexing is not supported for type: %T", container_t); } } - case InlineCCode: return Match(ast, InlineCCode)->code; + case InlineCCode: { + type_t *t = get_type(env, ast); + if (t->tag == VoidType) + return CORD_all("{\n", Match(ast, InlineCCode)->code, "\n}"); + else + return Match(ast, InlineCCode)->code; + } case Use: return CORD_EMPTY; case LinkerDirective: code_err(ast, "Linker directives are not supported yet"); case Extern: code_err(ast, "Externs are not supported as expressions"); diff --git a/environment.c b/environment.c index d5ece26..5799ced 100644 --- a/environment.c +++ b/environment.c @@ -360,7 +360,7 @@ void compiler_err(file_t *f, const char *start, const char *end, const char *fmt fputs(" \x1b[m", stderr); fputs("\n\n", stderr); if (f && start && end) - fprint_span(stderr, f, start, end, "\x1b[31;1m", 2, isatty(STDERR_FILENO) && !getenv("NO_COLOR")); + highlight_error(f, start, end, "\x1b[31;1m", 2, isatty(STDERR_FILENO) && !getenv("NO_COLOR")); raise(SIGABRT); exit(1); diff --git a/parse.c b/parse.c index 868c8bb..b2c4f17 100644 --- a/parse.c +++ b/parse.c @@ -47,7 +47,7 @@ int op_tightness[] = { static const char *keywords[] = { "yes", "xor", "while", "when", "use", "then", "struct", "stop", "skip", "return", - "or", "not", "no", "mod1", "mod", "pass", "lang", "in", "if", "func", "for", "extern", + "or", "not", "no", "mod1", "mod", "pass", "lang", "inline", "in", "if", "func", "for", "extern", "enum", "else", "do", "and", "_min_", "_max_", NULL, }; @@ -94,6 +94,7 @@ static PARSER(parse_lang_def); static PARSER(parse_text); static PARSER(parse_func_def); static PARSER(parse_extern); +static PARSER(parse_inline_c); static PARSER(parse_declaration); static PARSER(parse_doctest); static PARSER(parse_use); @@ -117,7 +118,7 @@ static void vparser_err(parse_ctx_t *ctx, const char *start, const char *end, co fputs(" \x1b[m", stderr); fputs("\n\n", stderr); - fprint_span(stderr, ctx->file, start, end, "\x1b[31;1;7m", 2, isatty(STDERR_FILENO) && !getenv("NO_COLOR")); + highlight_error(ctx->file, start, end, "\x1b[31;1;7m", 2, isatty(STDERR_FILENO) && !getenv("NO_COLOR")); fputs("\n", stderr); if (ctx->on_err) @@ -1254,6 +1255,7 @@ PARSER(parse_term_no_suffix) { || (term=parse_return(ctx, pos)) || (term=parse_not(ctx, pos)) || (term=parse_extern(ctx, pos)) + || (term=parse_inline_c(ctx, pos)) ); return term; } @@ -1602,6 +1604,7 @@ PARSER(parse_namespace) { ||(stmt=optional(ctx, &pos, parse_use)) ||(stmt=optional(ctx, &pos, parse_linker)) ||(stmt=optional(ctx, &pos, parse_extern)) + ||(stmt=optional(ctx, &pos, parse_inline_c)) ||(stmt=optional(ctx, &pos, parse_declaration))) { statements = new(ast_list_t, .ast=stmt, .next=statements); @@ -1637,6 +1640,7 @@ PARSER(parse_file_body) { ||(stmt=optional(ctx, &pos, parse_use)) ||(stmt=optional(ctx, &pos, parse_linker)) ||(stmt=optional(ctx, &pos, parse_extern)) + ||(stmt=optional(ctx, &pos, parse_inline_c)) ||(stmt=optional(ctx, &pos, parse_declaration))) { statements = new(ast_list_t, .ast=stmt, .next=statements); @@ -1924,6 +1928,33 @@ PARSER(parse_extern) { return NewAST(ctx->file, start, pos, Extern, .name=name, .type=type); } +PARSER(parse_inline_c) { + const char *start = pos; + if (!match_word(&pos, "inline")) return NULL; + spaces(&pos); + if (!match_word(&pos, "C")) return NULL; + spaces(&pos); + if (!match(&pos, "(")) + parser_err(ctx, start, pos, "I expected a '(' here"); + + int64_t indent = get_indent(ctx, pos); + whitespace(&pos); + // Block: + CORD c_code = CORD_EMPTY; + while (get_indent(ctx, pos) > indent) { + size_t line_len = strcspn(pos, "\r\n"); + c_code = CORD_all(c_code, heap_strn(pos, line_len), "\n"); + pos += line_len; + if (whitespace(&pos) == 0) break; + } + expect_closing(ctx, &pos, ")", "I wasn't able to parse the rest of this inline C"); + spaces(&pos); + type_ast_t *type = NULL; + if (match(&pos, ":")) + type = expect(ctx, start, &pos, parse_type, "I couldn't parse the type for this extern"); + return NewAST(ctx->file, start, pos, InlineCCode, .code=c_code, .type=type); +} + PARSER(parse_doctest) { const char *start = pos; if (!match(&pos, ">>")) return NULL; diff --git a/repl.c b/repl.c index 9f01c24..c687f37 100644 --- a/repl.c +++ b/repl.c @@ -90,7 +90,7 @@ static void repl_err(ast_t *node, const char *fmt, ...) fputs(" \x1b[m", stderr); fputs("\n\n", stderr); if (node) - fprint_span(stderr, node->file, node->start, node->end, "\x1b[31;1m", 2, color); + highlight_error(node->file, node->start, node->end, "\x1b[31;1m", 2, color); longjmp(on_err, 1); } diff --git a/typecheck.c b/typecheck.c index d60a84e..34d62aa 100644 --- a/typecheck.c +++ b/typecheck.c @@ -986,7 +986,10 @@ type_t *get_type(env_t *env, ast_t *ast) } case While: case For: return Type(VoidType); - case InlineCCode: return Type(VoidType); + case InlineCCode: { + type_ast_t *type_ast = Match(ast, InlineCCode)->type; + return type_ast ? parse_type_ast(env, type_ast) : Type(VoidType); + } case Unknown: code_err(ast, "I can't figure out the type of: %W", ast); } code_err(ast, "I can't figure out the type of: %W", ast);