summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2019-11-02 23:30:16 -0400
committerLeo Tenenbaum <pommicket@gmail.com>2019-11-02 23:30:16 -0400
commit575ff90da3be49ac5b478d5cbb1765bbda27a80e (patch)
treebc1ec79b5c7f0f5c5209ca153732ac92fde8fa01
parent456ff7743aeed28a6837a7dbc9cc0ab28331931d (diff)
did part of #sizeof/alignof directives for compile-time size and aligns of types
realizing that the current user type system has bugs; will need to switch to one which isn't identifier based after resolving.
-rw-r--r--cgen.c34
-rw-r--r--decls_cgen.c4
-rw-r--r--eval.c28
-rw-r--r--main.c1
-rw-r--r--parse.c70
-rw-r--r--test.toc3
-rw-r--r--tokenizer.c3
-rw-r--r--typedefs_cgen.c4
-rw-r--r--types.c50
-rw-r--r--types.h22
10 files changed, 142 insertions, 77 deletions
diff --git a/cgen.c b/cgen.c
index c28342f..8d31ece 100644
--- a/cgen.c
+++ b/cgen.c
@@ -520,7 +520,9 @@ static bool cgen_set_tuple(CGenerator *g, Expression *exprs, Identifier *idents,
case EXPR_FN:
case EXPR_CAST:
case EXPR_NEW:
- case EXPR_DIRECT:
+ case EXPR_C:
+ case EXPR_DSIZEOF:
+ case EXPR_DALIGNOF:
case EXPR_TYPE:
assert(0);
return false;
@@ -756,7 +758,9 @@ static bool cgen_expr_pre(CGenerator *g, Expression *e) {
case EXPR_LITERAL_STR:
case EXPR_IDENT:
case EXPR_FN:
- case EXPR_DIRECT:
+ case EXPR_C:
+ case EXPR_DSIZEOF:
+ case EXPR_DALIGNOF:
case EXPR_TYPE:
break;
case EXPR_TUPLE:
@@ -973,18 +977,20 @@ static bool cgen_expr(CGenerator *g, Expression *e) {
cgen_write(g, "))");
}
break;
- case EXPR_DIRECT:
- switch (e->direct.which) {
- case DIRECT_C: {
- Value val;
- if (!eval_expr(g->evalr, &e->direct.args[0], &val))
- return false;
- cgen_indent(g);
- fwrite(val.slice.data, 1, (size_t)val.slice.n, cgen_writing_to(g));
- } break;
- case DIRECT_COUNT: assert(0); break;
- }
- break;
+ case EXPR_C: {
+ Value val;
+ if (!eval_expr(g->evalr, e->c.code, &val))
+ return false;
+ cgen_indent(g);
+ fwrite(val.slice.data, 1, (size_t)val.slice.n, cgen_writing_to(g));
+ } break;
+ case EXPR_DSIZEOF:
+ case EXPR_DALIGNOF: {
+ Value val;
+ if (!eval_expr(g->evalr, e, &val))
+ return false;
+ cgen_write(g, "%"PRId64, val.i64);
+ } break;
case EXPR_CAST: {
Type *from = &e->cast.expr->type;
Type *to = &e->cast.type;
diff --git a/decls_cgen.c b/decls_cgen.c
index 0a7a521..6a3a635 100644
--- a/decls_cgen.c
+++ b/decls_cgen.c
@@ -70,7 +70,9 @@ static bool cgen_decls_expr(CGenerator *g, Expression *e) {
fn_exit(&e->fn);
break;
case EXPR_TYPE:
- case EXPR_DIRECT:
+ case EXPR_C:
+ case EXPR_DSIZEOF:
+ case EXPR_DALIGNOF:
case EXPR_NEW:
case EXPR_IDENT:
case EXPR_LITERAL_BOOL:
diff --git a/eval.c b/eval.c
index ebebf64..43cb309 100644
--- a/eval.c
+++ b/eval.c
@@ -1,5 +1,6 @@
static bool types_block(Typer *tr, Block *b);
static bool types_decl(Typer *tr, Declaration *d);
+static bool type_resolve(Typer *tr, Type *t, Location where);
static size_t compiler_sizeof(Type *t);
static bool eval_block(Evaluator *ev, Block *b, Type *t, Value *v);
static bool eval_expr(Evaluator *ev, Expression *e, Value *v);
@@ -1110,14 +1111,27 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) {
return false;
}
} break;
- case EXPR_DIRECT: {
- DirectExpr *d = &e->direct;
- switch (d->which) {
- case DIRECT_C:
- err_print(e->where, "Cannot run C code at compile time.");
- return false;
- case DIRECT_COUNT: assert(0); return false;
+ case EXPR_C:
+ err_print(e->where, "Cannot run C code at compile time.");
+ return false;
+ case EXPR_DSIZEOF:
+ case EXPR_DALIGNOF: {
+ Expression *of = e->kind == EXPR_DSIZEOF ? e->dsizeof.of : e->dalignof.of;
+ Type *type;
+ if (of->type.kind == TYPE_TYPE) {
+ /* it's a type, return the size/align of it */
+ Value typeval;
+ if (!eval_expr(ev, of, &typeval)) return false;
+ type = typeval.type;
+ if (!type_resolve(ev->typer, type, e->where)) return false;
+ } else {
+ /* it's an expression, return the size/align of its type */
+ type = &of->type;
}
+ if (e->kind == EXPR_DSIZEOF)
+ v->i64 = (I64)compiler_sizeof(type);
+ else
+ v->i64 = (I64)compiler_alignof(type);
} break;
case EXPR_NEW:
/* it's not strictly necessary to do the if here */
diff --git a/main.c b/main.c
index 3033d24..cbd93b8 100644
--- a/main.c
+++ b/main.c
@@ -1,6 +1,5 @@
/*
TODO:
-verify size of struct, align of fields
pointers to futurely-declared types
for
+=, -=, *=, /=
diff --git a/parse.c b/parse.c
index 4d38609..a01dce8 100644
--- a/parse.c
+++ b/parse.c
@@ -13,7 +13,9 @@ static const char *expr_kind_to_str(ExprKind k) {
case EXPR_IF: return "if expression";
case EXPR_WHILE: return "while expression";
case EXPR_CALL: return "function call";
- case EXPR_DIRECT: return "directive";
+ case EXPR_C: return "c code";
+ case EXPR_DSIZEOF: return "#sizeof";
+ case EXPR_DALIGNOF: return "#alignof";
case EXPR_NEW: return "new expression";
case EXPR_CAST: return "cast expression";
case EXPR_UNARY_OP: return "unary operator";
@@ -1481,25 +1483,37 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) {
if (t->token->kind == TOKEN_DIRECT) {
/* it's a directive */
- e->kind = EXPR_DIRECT;
- e->direct.which = t->token->direct;
- e->direct.args = NULL;
- if (token_is_kw(&t->token[1], KW_LPAREN)) {
- Argument *args = NULL;
- /* has args (but maybe it's just "#foo()") */
- t->token++; /* move to ( */
- if (!parse_args(p, &args)) return false;
- arr_foreach(args, Argument, arg) {
- if (arg->name != NULL) {
- err_print(arg->where, "Directives cannot have named arguments.");
- return false;
- }
- *(Expression *)parser_arr_add(p, &e->direct.args) = arg->val;
+ Expression *single_arg = NULL; /* points to an expr if this is a directive with one expression argument */
+
+ switch (t->token->direct) {
+ case DIRECT_C:
+ e->kind = EXPR_C;
+ single_arg = e->c.code = parser_new_expr(p);
+ break;
+ case DIRECT_SIZEOF:
+ e->kind = EXPR_DSIZEOF;
+ single_arg = e->dsizeof.of = parser_new_expr(p);
+ break;
+ case DIRECT_ALIGNOF:
+ e->kind = EXPR_DALIGNOF;
+ single_arg = e->dalignof.of = parser_new_expr(p);
+ break;
+ case DIRECT_COUNT: assert(0); break;
+ }
+ if (single_arg) {
+ t->token++;
+ if (!token_is_kw(t->token, KW_LPAREN)) {
+ err_print(t->token->where, "Expected ( to follow #%s.", directives[t->token->direct]);
+ return false;
}
- return true;
- } else {
- /* no args */
- e->direct.args = NULL;
+ t->token++;
+ Token *arg_end = expr_find_end(p, 0, NULL);
+ if (!token_is_kw(arg_end, KW_RPAREN)) {
+ err_print(end->where, "Expected ) at end of #%s directive.", directives[t->token->direct]);
+ return false;
+ }
+ if (!parse_expr(p, single_arg, arg_end))
+ return false;
t->token++;
return true;
}
@@ -1902,10 +1916,20 @@ static void fprint_expr(FILE *out, Expression *e) {
}
fprintf(out, ")");
break;
- case EXPR_DIRECT:
- fprintf(out, "#");
- fprintf(out, "%s", directives[e->direct.which]);
- fprint_arg_exprs(out, e->direct.args);
+ case EXPR_C:
+ fprintf(out, "#C(");
+ fprint_expr(out, e->c.code);
+ fprintf(out, ")");
+ break;
+ case EXPR_DSIZEOF:
+ fprintf(out, "#sizeof(");
+ fprint_expr(out, e->dsizeof.of);
+ fprintf(out, ")");
+ break;
+ case EXPR_DALIGNOF:
+ fprintf(out, "#alignof(");
+ fprint_expr(out, e->dalignof.of);
+ fprintf(out, ")");
break;
case EXPR_SLICE: {
SliceExpr *s = &e->slice;
diff --git a/test.toc b/test.toc
index c7659d8..99c5235 100644
--- a/test.toc
+++ b/test.toc
@@ -26,4 +26,7 @@ main @= fn() {
puti(total());
X @= total();
puti(X);
+ puti(#sizeof(int));
+ puti(#alignof(int));
+ puti(#sizeof({ Foo @= struct { x: i64; y: char; } ; f: Foo; f }));
};
diff --git a/tokenizer.c b/tokenizer.c
index aa9dd83..a5eb3ce 100644
--- a/tokenizer.c
+++ b/tokenizer.c
@@ -11,8 +11,7 @@ static const char *keywords[KW_COUNT] =
static inline const char *kw_to_str(Keyword k) { return keywords[k]; }
static const char *directives[DIRECT_COUNT] =
- {"C"};
-
+ {"C", "sizeof", "alignof"};
/* Returns KW_COUNT if it's not a keyword */
/* OPTIM: don't use strncmp so much */
diff --git a/typedefs_cgen.c b/typedefs_cgen.c
index 47122e0..d34514a 100644
--- a/typedefs_cgen.c
+++ b/typedefs_cgen.c
@@ -73,7 +73,9 @@ static bool typedefs_expr(CGenerator *g, Expression *e) {
fn_exit(&e->fn);
break;
case EXPR_TYPE:
- case EXPR_DIRECT:
+ case EXPR_C:
+ case EXPR_DSIZEOF:
+ case EXPR_DALIGNOF:
case EXPR_NEW:
case EXPR_IDENT:
case EXPR_LITERAL_BOOL:
diff --git a/types.c b/types.c
index dde2193..1c0bf9c 100644
--- a/types.c
+++ b/types.c
@@ -111,6 +111,7 @@ static bool expr_arr_must_mut(Expression *e) {
case EXPR_CALL:
case EXPR_NEW:
case EXPR_UNARY_OP:
+ case EXPR_C:
return true;
case EXPR_SLICE:
return expr_arr_must_mut(e->slice.of);
@@ -137,8 +138,9 @@ static bool expr_arr_must_mut(Expression *e) {
case EXPR_LITERAL_CHAR:
case EXPR_LITERAL_INT:
case EXPR_BINARY_OP:
- case EXPR_DIRECT:
case EXPR_TYPE:
+ case EXPR_DALIGNOF:
+ case EXPR_DSIZEOF:
break;
}
assert(0);
@@ -201,7 +203,9 @@ static bool expr_must_lval(Expression *e) {
case EXPR_IF:
case EXPR_WHILE:
case EXPR_CALL:
- case EXPR_DIRECT:
+ case EXPR_C:
+ case EXPR_DALIGNOF:
+ case EXPR_DSIZEOF:
case EXPR_BLOCK:
case EXPR_SLICE:
case EXPR_TYPE: {
@@ -869,25 +873,31 @@ static bool types_expr(Typer *tr, Expression *e) {
t->kind = TYPE_VOID;
}
} break;
- case EXPR_DIRECT:
- arr_foreach(e->direct.args, Expression, arg) {
- if (!types_expr(tr, arg))
- return false;
- }
- switch (e->direct.which) {
- case DIRECT_C: {
- size_t n_args = arr_len(e->direct.args);
- if (n_args != 1) {
- err_print(e->where, "#C call should have one string argument (got %lu arguments).", (unsigned long)n_args);
- return false;
- }
- /* type automatically set to unknown */
-
- /* TODO: when string types are added, check */
- } break;
- case DIRECT_COUNT: assert(0); return false;
+ case EXPR_C: {
+ Expression *code = e->c.code;
+ if (!types_expr(tr, code))
+ return false;
+ if (code->type.kind != TYPE_SLICE
+ || !type_is_builtin(code->type.slice, BUILTIN_CHAR)) {
+ char *s = type_to_str(&code->type);
+ err_print(e->where, "Argument to #C directive must be a string, but got type %s.");
+ free(s);
+ return false;
}
- break;
+ t->kind = TYPE_UNKNOWN;
+ } break;
+ case EXPR_DSIZEOF: {
+ if (!types_expr(tr, e->dsizeof.of))
+ return false;
+ t->kind = TYPE_BUILTIN;
+ t->builtin = BUILTIN_I64;
+ } break;
+ case EXPR_DALIGNOF: {
+ if (!types_expr(tr, e->dalignof.of))
+ return false;
+ t->kind = TYPE_BUILTIN;
+ t->builtin = BUILTIN_I64;
+ } break;
case EXPR_UNARY_OP: {
Expression *of = e->unary.of;
Type *of_type = &of->type;
diff --git a/types.h b/types.h
index d1c5bf5..2358f45 100644
--- a/types.h
+++ b/types.h
@@ -138,6 +138,8 @@ typedef enum {
typedef enum {
DIRECT_C,
+ DIRECT_SIZEOF,
+ DIRECT_ALIGNOF,
DIRECT_COUNT
} Directive;
@@ -337,7 +339,9 @@ typedef enum {
EXPR_CALL,
EXPR_BLOCK,
EXPR_TUPLE,
- EXPR_DIRECT,
+ EXPR_C,
+ EXPR_DSIZEOF,
+ EXPR_DALIGNOF,
EXPR_SLICE,
EXPR_TYPE
} ExprKind;
@@ -368,12 +372,6 @@ typedef enum {
} BinaryOp;
typedef struct {
- Directive which;
- struct Expression *args;
-} DirectExpr;
-
-
-typedef struct {
struct Expression *fn;
union {
struct Argument *args;
@@ -457,7 +455,15 @@ typedef struct Expression {
Field *field; /* for . only */
} binary;
CallExpr call;
- DirectExpr direct;
+ struct {
+ struct Expression *code;
+ } c;
+ struct {
+ struct Expression *of;
+ } dsizeof; /* #sizeof directive */
+ struct {
+ struct Expression *of;
+ } dalignof; /* #alignof directive */
Identifier ident;
NewExpr new;
struct {