Add syntax for "inline C(...)"

This commit is contained in:
Bruce Hill 2024-05-18 16:31:34 -04:00
parent e439fcd1e2
commit 1df26851d7
11 changed files with 68 additions and 54 deletions

1
ast.h
View File

@ -275,6 +275,7 @@ struct ast_s {
} LinkerDirective;
struct {
CORD code;
type_ast_t *type;
} InlineCCode;
} __data;
};

View File

@ -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;
}

View File

@ -5,7 +5,6 @@
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
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

View File

@ -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

View File

@ -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

View File

@ -5,7 +5,6 @@
#include <assert.h>
#include <gc.h>
#include <gc/cord.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <err.h>

View File

@ -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");

View File

@ -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);

35
parse.c
View File

@ -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;

2
repl.c
View File

@ -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);
}

View File

@ -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);