summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--base_cgen.c10
-rw-r--r--cgen.c55
-rw-r--r--eval.c11
-rw-r--r--main.c4
-rw-r--r--out.c6
-rw-r--r--out.h2
-rw-r--r--parse.c129
-rw-r--r--test.toc7
-rw-r--r--types.c20
-rw-r--r--util/err.c1
10 files changed, 182 insertions, 63 deletions
diff --git a/base_cgen.c b/base_cgen.c
index 817354f..64d96d0 100644
--- a/base_cgen.c
+++ b/base_cgen.c
@@ -154,6 +154,9 @@ static void cgen_type_pre(CGenerator *g, Type *t) {
case TYPE_TUPLE:
assert(0);
return;
+ case TYPE_UNKNOWN:
+ err_print(t->where, "Type of unknown-typed expression required (x := #C(\"...\") will not work; you need to annotate the type of x).");
+ abort();
case TYPE_ARR:
cgen_type_pre(g, t->arr.of);
break;
@@ -226,6 +229,9 @@ static void cgen_type_post(CGenerator *g, Type *t) {
cgen_write(g, "[%lu]", t->arr.n);
cgen_type_post(g, t->arr.of);
break;
+ case TYPE_UNKNOWN: /* we should always do pre first */
+ assert(0);
+ break;
}
}
@@ -269,12 +275,12 @@ static bool cgen_fn_header(CGenerator *g, FnExpr *f) {
static bool cgen_block_enter(CGenerator *g, Block *b) {
g->block = b;
- return block_enter(b);
+ return block_enter(b, &b->stmts);
}
static bool cgen_block_exit(CGenerator *g, Block *into) {
Block *b = g->block;
g->block = into;
- return block_exit(b);
+ return block_exit(b, &b->stmts);
}
diff --git a/cgen.c b/cgen.c
index 9353084..f1eea25 100644
--- a/cgen.c
+++ b/cgen.c
@@ -16,6 +16,27 @@ static void cgen_create(CGenerator *g, Identifiers *ids, FILE *c_out, FILE *h_ou
cgen_writeln(g, ""); /* extra newline between includes and code */
}
+static bool cgen_direct(CGenerator *g, DirectExpr *direct, Location where) {
+ switch (direct->which) {
+ case DIRECT_C: {
+ Expression *args = direct->args.data;
+ size_t nargs = direct->args.len;
+ if (nargs != 1) {
+ err_print(where, "Expected 1 argument to #C directive, but got %lu.", nargs);
+ }
+ /* TODO: compile-time constants */
+ if (args[0].kind != EXPR_STR_LITERAL) {
+ err_print(args[0].where, "Argument to #C directive must be a string literal.");
+ }
+ cgen_write(g, "%s", args[0].strl.str);
+ } break;
+ case DIRECT_COUNT:
+ assert(0);
+ return false;
+ }
+ return true;
+}
+
static bool cgen_expr(CGenerator *g, Expression *e) {
switch (e->kind) {
case EXPR_INT_LITERAL:
@@ -88,6 +109,9 @@ static bool cgen_expr(CGenerator *g, Expression *e) {
}
cgen_write(g, ")");
break;
+ case EXPR_DIRECT:
+ if (!cgen_direct(g, &e->direct, e->where)) return false;
+ break;
}
return true;
}
@@ -117,6 +141,9 @@ static void cgen_zero_value(CGenerator *g, Type *t) {
assert(0);
}
break;
+ case TYPE_UNKNOWN:
+ assert(0);
+ break;
}
}
@@ -245,12 +272,38 @@ static bool cgen_fns_in_stmt(CGenerator *g, Statement *s) {
return true;
}
+/* generate a statement at top level, including any functions in it. */
+static bool cgen_stmt_top(CGenerator *g, Statement *s) {
+ if (!cgen_fns_in_stmt(g, s)) return false;
+ switch (s->kind) {
+ case STMT_EXPR: {
+ Expression *e = &s->expr;
+ bool ignored = true;
+ switch (e->kind) {
+ case EXPR_DIRECT:
+ switch (e->direct.which) {
+ case DIRECT_C:
+ ignored = false;
+ cgen_direct(g, &e->direct, e->where);
+ break;
+ case DIRECT_COUNT: assert(0); break;
+ }
+ default: break;
+ }
+ if (ignored)
+ warn_print(e->where, "Expression at top level currently ignored."); /* TODO */
+ } break;
+ case STMT_DECL: break;
+ }
+ return true;
+}
+
static bool cgen_file(CGenerator *g, ParsedFile *f) {
cgen_write_line_comment(g, "toc");
bool ret = true;
if (!cgen_decls_file(g, f)) return false;
arr_foreach(&f->stmts, Statement, s) {
- if (!cgen_fns_in_stmt(g, s)) return false;
+ if (!cgen_stmt_top(g, s)) return false;
}
g->writing_to = CGEN_WRITING_TO_C;
/* write actual main function */
diff --git a/eval.c b/eval.c
index a131c03..c619fab 100644
--- a/eval.c
+++ b/eval.c
@@ -94,6 +94,17 @@ static bool eval_expr_as_int(Expression *e, Integer *i) {
case EXPR_FN:
err_print(e->where, "Expected integer, but found function.");
return false;
+ case EXPR_CALL:
+ err_print(e->where, "Compile time function calling not supported yet."); /* TODO */
+ break;
+ case EXPR_DIRECT:
+ switch (e->direct.which) {
+ case DIRECT_C:
+ err_print(e->where, "Can't run C code at compile time.");
+ return false;
+ case DIRECT_COUNT: assert(0); break;
+ }
+ break;
}
err_print(e->where, "Not implemented yet");
return false;
diff --git a/main.c b/main.c
index 1721269..c875f4b 100644
--- a/main.c
+++ b/main.c
@@ -62,6 +62,9 @@ int main(int argc, char **argv) {
fprint_parsed_file(stdout, &f);
tokr_free(&t);
+
+
+ block_enter(NULL, &f.stmts); /* enter global scope */
if (!types_file(&f)) {
err_fprint(TEXT_IMPORTANT("Errors occured while determining types.\n"));
return EXIT_FAILURE;
@@ -79,6 +82,7 @@ int main(int argc, char **argv) {
return EXIT_FAILURE;
}
+ block_exit(NULL, &f.stmts); /* exit global scope */
free(contents);
fclose(c_out);
diff --git a/out.c b/out.c
index fdcede3..22c285e 100644
--- a/out.c
+++ b/out.c
@@ -1,10 +1,12 @@
#include "out.h"
/* toc */
-void x__c5x__b3x__c5x__84x__c4x__a8x__f0x__9fx__90x__9f(void) {
+#include <stdio.h>
+void x__c5x__b3x__c5x__84x__c4x__a8(void) {
+ printf("Hello, World!\n");
}
void main__(void) {
- x__c5x__b3x__c5x__84x__c4x__a8x__f0x__9fx__90x__9f();
+ x__c5x__b3x__c5x__84x__c4x__a8();
}
int main(void) {
diff --git a/out.h b/out.h
index bd89a1f..57b86cd 100644
--- a/out.h
+++ b/out.h
@@ -1,4 +1,4 @@
#include <stddef.h>
#include <stdint.h>
-void x__c5x__b3x__c5x__84x__c4x__a8x__f0x__9fx__90x__9f(void);
+void x__c5x__b3x__c5x__84x__c4x__a8(void);
void main__(void);
diff --git a/parse.c b/parse.c
index e7f1016..101d003 100644
--- a/parse.c
+++ b/parse.c
@@ -1,6 +1,7 @@
/* TODO: stmt_parse -> parse_stmt, etc. */
typedef enum {
TYPE_VOID,
+ TYPE_UNKNOWN,
TYPE_BUILTIN,
TYPE_FN,
TYPE_TUPLE,
@@ -69,7 +70,8 @@ typedef enum {
EXPR_BINARY_OP,
EXPR_UNARY_OP,
EXPR_FN,
- EXPR_CALL
+ EXPR_CALL,
+ EXPR_DIRECT
} ExprKind;
typedef enum {
@@ -84,6 +86,12 @@ typedef enum {
BINARY_AT_INDEX /* e.g. x[i] */
} BinaryOp;
+typedef struct {
+ Directive which;
+ Array args; /* of Expression */
+} DirectExpr;
+
+
#define EXPR_FLAG_FLEXIBLE 0x01 /* e.g. 4 => float/i32/etc. */
typedef struct Expression {
@@ -105,8 +113,9 @@ typedef struct Expression {
} binary;
struct {
struct Expression *fn;
- Array args; /* of expression */
+ Array args; /* of Expression */
} call;
+ DirectExpr direct;
Identifier ident;
FnExpr fn;
};
@@ -232,6 +241,8 @@ static size_t type_to_str(Type *t, char *buffer, size_t bufsize) {
switch (t->kind) {
case TYPE_VOID:
return str_copy(buffer, bufsize, "void");
+ case TYPE_UNKNOWN:
+ return str_copy(buffer, bufsize, "???");
case TYPE_BUILTIN: {
const char *s = keywords[builtin_type_to_kw(t->builtin)];
return str_copy(buffer, bufsize, s);
@@ -600,6 +611,35 @@ static bool parse_fn_expr(Parser *p, FnExpr *f) {
return parse_block(p, &f->body);
}
+/* parses, e.g. "(3, 5, foo)" */
+static bool parse_args(Parser *p, Array *args) {
+ Tokenizer *t = p->tokr;
+ Token *start = t->token;
+ assert(token_is_kw(start, KW_LPAREN));
+ arr_create(args, sizeof(Expression));
+ t->token++; /* move past ( */
+ if (!token_is_kw(t->token, KW_RPAREN)) {
+ /* non-empty arg list */
+ while (1) {
+ if (t->token->kind == TOKEN_EOF) {
+ tokr_err(t, "Expected argument list to continue.");
+ info_print(start->where, "This is where the argument list starts.");
+ return false;
+ }
+ Expression *arg = arr_add(args);
+ if (!parse_expr(p, arg, expr_find_end(p, EXPR_END_RPAREN_OR_COMMA))) {
+ return false;
+ }
+ if (token_is_kw(t->token, KW_RPAREN))
+ break;
+ assert(token_is_kw(t->token, KW_COMMA));
+ t->token++; /* move past , */
+ }
+ }
+ t->token++; /* move past ) */
+ return true;
+}
+
static bool parse_expr(Parser *p, Expression *e, Token *end) {
Tokenizer *t = p->tokr;
if (end == NULL) return false;
@@ -750,6 +790,7 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) {
/* try a function call or array access */
Token *token = t->token;
+
/* currently unnecessary: paren_level = square_level = 0; */
/*
can't call at start, e.g. in (fn() {})(), it is not the empty function ""
@@ -765,7 +806,8 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) {
if (token->kind == TOKEN_KW) {
switch (token->kw) {
case KW_LPAREN:
- if (square_level == 0 && paren_level == 0)
+ if (square_level == 0 && paren_level == 0 && token != t->tokens.data
+ && token[-1].kind != TOKEN_DIRECT /* don't include directives */)
opening_bracket = token; /* maybe this left parenthesis opens the function call */
paren_level++;
break;
@@ -804,26 +846,8 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) {
if (!parse_expr(p, e->call.fn, opening_bracket)) { /* parse up to ( as function */
return false;
}
- arr_create(&e->call.args, sizeof(Expression));
- t->token = opening_bracket + 1; /* move past ( */
- if (!token_is_kw(t->token, KW_RPAREN)) {
- /* non-empty arg list */
- while (1) {
- if (t->token->kind == TOKEN_EOF) {
- tokr_err(t, "Expected argument list to continue.");
- return false;
- }
- Expression *arg = arr_add(&e->call.args);
- if (!parse_expr(p, arg, expr_find_end(p, EXPR_END_RPAREN_OR_COMMA))) {
- return false;
- }
- if (token_is_kw(t->token, KW_RPAREN))
- break;
- t->token++; /* move past , */
- }
- }
- t->token++; /* move past ) */
- return true;
+ t->token = opening_bracket;
+ return parse_args(p, &e->call.args);
}
case KW_LSQUARE: {
/* it's an array access */
@@ -846,6 +870,22 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) {
return false;
}
}
+
+ if (t->token->kind == TOKEN_DIRECT) {
+ /* it's a directive */
+ e->kind = EXPR_DIRECT;
+ e->direct.which = t->token->direct;
+ if (token_is_kw(&t->token[1], KW_LPAREN)) {
+ /* has args (but maybe it's just "#foo()") */
+ t->token++; /* move to ( */
+ return parse_args(p, &e->direct.args);
+ } else {
+ /* no args */
+ arr_create(&e->direct.args, sizeof(Expression));
+ t->token++;
+ return true;
+ }
+ }
tokr_err(t, "Not implemented yet.");
return false;
}
@@ -943,25 +983,6 @@ static bool parse_single_type_in_decl(Parser *p, Declaration *d) {
return false;
}
*ident = t->token->ident;
- /*
- only keep track of file scoped declarations---
- block enter/exit code will handle the rest
- */
- IdentTree *ident_info = *ident;
- if (p->block == NULL) {
- if (ident_info->decls.len) {
- /* this was already declared! */
- IdentDecl *prev = ident_info->decls.data;
- tokr_err(t, "Re-declaration of identifier in global scope.");
- info_print(prev->decl->where, "Previous declaration was here.");
- return false;
- }
- assert(!ident_info->decls.item_sz); /* we shouldn't have created this array already */
- arr_create(&ident_info->decls, sizeof(IdentDecl));
- IdentDecl *ident_decl = arr_add(&ident_info->decls);
- ident_decl->decl = d;
- ident_decl->scope = NULL;
- }
t->token++;
if (token_is_kw(t->token, KW_COMMA)) {
t->token++;
@@ -1139,6 +1160,9 @@ static void fprint_type(FILE *out, Type *t) {
case TYPE_VOID:
fprintf(out, "void");
break;
+ case TYPE_UNKNOWN:
+ fprintf(out, "???");
+ break;
case TYPE_FN: {
Type *types = t->fn.types.data;
fprintf(out, "fn (");
@@ -1202,6 +1226,15 @@ static void fprint_fn_expr(FILE *out, FnExpr *f) {
fprint_block(out, &f->body);
}
+static void fprint_args(FILE *out, Array *args) {
+ fprintf(out, "(");
+ arr_foreach(args, Expression, arg) {
+ if (arg != args->data) fprintf(out, ", ");
+ fprint_expr(out, arg);
+ }
+ fprintf(out, ")");
+}
+
static void fprint_expr(FILE *out, Expression *e) {
PARSE_PRINT_LOCATION(e->where);
switch (e->kind) {
@@ -1256,12 +1289,12 @@ static void fprint_expr(FILE *out, Expression *e) {
break;
case EXPR_CALL:
fprint_expr(out, e->call.fn);
- fprintf(out, "(");
- arr_foreach(&e->call.args, Expression, arg) {
- if (arg != e->call.args.data) fprintf(out, ", ");
- fprint_expr(out, arg);
- }
- fprintf(out, ")");
+ fprint_args(out, &e->call.args);
+ break;
+ case EXPR_DIRECT:
+ fprintf(out, "#");
+ fprintf(out, directives[e->direct.which]);
+ fprint_args(out, &e->direct.args);
break;
}
}
diff --git a/test.toc b/test.toc
index 54f217e..86d8961 100644
--- a/test.toc
+++ b/test.toc
@@ -1,6 +1,9 @@
-ųńĨ🐟 @= fn() {
+#C("#include <stdio.h>\n");
+
+ųńĨ @= fn() {
+ #C("printf(\"Hello, World!\\n\")");
};
main @= fn() {
- ųńĨ🐟();
+ ųńĨ();
};
diff --git a/types.c b/types.c
index 0bfc3ff..7b90299 100644
--- a/types.c
+++ b/types.c
@@ -1,6 +1,7 @@
-static bool block_enter(Block *b) {
+/* pass NULL for block for global scope */
+static bool block_enter(Block *b, Array *stmts) {
bool ret = true;
- arr_foreach(&b->stmts, Statement, stmt) {
+ arr_foreach(stmts, Statement, stmt) {
if (stmt->kind == STMT_DECL) {
Declaration *decl = &stmt->decl;
arr_foreach(&decl->idents, Identifier, ident) {
@@ -29,10 +30,10 @@ static bool block_enter(Block *b) {
return ret;
}
-static bool block_exit(Block *b) {
+static bool block_exit(Block *b, Array *stmts) {
/* OPTIM: figure out some way of not re-iterating over everything */
bool ret = true;
- arr_foreach(&b->stmts, Statement, stmt) {
+ arr_foreach(stmts, Statement, stmt) {
if (stmt->kind == STMT_DECL) {
Declaration *decl = &stmt->decl;
arr_foreach(&decl->idents, Identifier, ident) {
@@ -50,6 +51,8 @@ static bool block_exit(Block *b) {
}
static bool type_eq(Type *a, Type *b) {
+ if (a->kind == TYPE_UNKNOWN || b->kind == TYPE_UNKNOWN)
+ return true; /* allow things such as 3 + #C("5") */
if (a->kind != b->kind) return false;
if (a->flags & TYPE_FLAG_FLEXIBLE) {
if (b->flags & TYPE_FLAG_FLEXIBLE) return true;
@@ -66,6 +69,7 @@ static bool type_eq(Type *a, Type *b) {
}
switch (a->kind) {
case TYPE_VOID: return true;
+ case TYPE_UNKNOWN: assert(0); return false;
case TYPE_BUILTIN:
return a->builtin == b->builtin;
case TYPE_FN: {
@@ -244,7 +248,6 @@ static bool type_of_expr(Expression *e, Type *t) {
break;
case EXPR_IDENT: {
if (!type_of_ident(e->where, e->ident, t, false)) return false;
-
} break;
case EXPR_CALL: {
Expression *f = e->call.fn;
@@ -265,6 +268,9 @@ static bool type_of_expr(Expression *e, Type *t) {
*t = *(Type*)fn_type.fn.types.data;
break;
}
+ case EXPR_DIRECT:
+ t->kind = TYPE_UNKNOWN;
+ break;
case EXPR_UNARY_OP: {
Type *of_type = &e->unary.of->type;
if (!type_of_expr(e->unary.of, of_type)) return false;
@@ -380,11 +386,11 @@ static bool types_stmt(Statement *s);
static bool types_block(Block *b) {
bool ret = true;
- if (!block_enter(b)) return false;
+ if (!block_enter(b, &b->stmts)) return false;
arr_foreach(&b->stmts, Statement, s) {
if (!types_stmt(s)) ret = false;
}
- if (!block_exit(b)) return false;
+ if (!block_exit(b, &b->stmts)) return false;
return ret;
}
diff --git a/util/err.c b/util/err.c
index 72e94be..3fe3b53 100644
--- a/util/err.c
+++ b/util/err.c
@@ -57,6 +57,7 @@ static void err_print_footer_(const char *context) {
if (!has_newline)
end = strchr(context, '\0');
assert(end);
+ err_fprint("\n\there: --> ");
err_fwrite(context, 1, (size_t)(end - context));
if (!has_newline)
err_fprint("<end of file>");