Add syntax for "inline C(...)"
This commit is contained in:
parent
e439fcd1e2
commit
1df26851d7
1
ast.h
1
ast.h
@ -275,6 +275,7 @@ struct ast_s {
|
||||
} LinkerDirective;
|
||||
struct {
|
||||
CORD code;
|
||||
type_ast_t *type;
|
||||
} InlineCCode;
|
||||
} __data;
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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");
|
||||
|
@ -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
35
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;
|
||||
|
2
repl.c
2
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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user