aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2024-05-18 16:31:34 -0400
committerBruce Hill <bruce@bruce-hill.com>2024-05-18 16:31:34 -0400
commit1df26851d73e50407a3b7c79bcdb5b0cc053fe67 (patch)
treec2e3c393b30ab34d782fd6839100c6854abd7e91
parente439fcd1e2090ff797b46c80c6264f08ea9e9cfb (diff)
Add syntax for "inline C(...)"
-rw-r--r--ast.h1
-rw-r--r--builtins/files.c38
-rw-r--r--builtins/files.h3
-rw-r--r--builtins/functions.c22
-rw-r--r--builtins/functions.h5
-rw-r--r--builtins/util.h1
-rw-r--r--compile.c8
-rw-r--r--environment.c2
-rw-r--r--parse.c35
-rw-r--r--repl.c2
-rw-r--r--typecheck.c5
11 files changed, 68 insertions, 54 deletions
diff --git a/ast.h b/ast.h
index 4307532b..e9e4dc32 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 a500687e..2375fc8a 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 024cd6d1..f650f78e 100644
--- a/builtins/files.h
+++ b/builtins/files.h
@@ -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
diff --git a/builtins/functions.c b/builtins/functions.c
index eedcc9fb..b2808c5a 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 e62fc441..f1a2867e 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 1b5664d7..dc42d570 100644
--- a/builtins/util.h
+++ b/builtins/util.h
@@ -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>
diff --git a/compile.c b/compile.c
index 99e7d77b..0e73eaa1 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 d5ece261..5799cedb 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 868c8bb9..b2c4f170 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 9f01c247..c687f378 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 d60a84ea..34d62aad 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);