From 575ff90da3be49ac5b478d5cbb1765bbda27a80e Mon Sep 17 00:00:00 2001 From: Leo Tenenbaum Date: Sat, 2 Nov 2019 23:30:16 -0400 Subject: 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. --- cgen.c | 34 ++++++++++++++++------------ decls_cgen.c | 4 +++- eval.c | 28 +++++++++++++++++------ main.c | 1 - parse.c | 70 ++++++++++++++++++++++++++++++++++++++------------------- test.toc | 3 +++ tokenizer.c | 3 +-- typedefs_cgen.c | 4 +++- types.c | 50 ++++++++++++++++++++++++----------------- types.h | 22 +++++++++++------- 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; @@ -367,12 +371,6 @@ typedef enum { BINARY_DOT } BinaryOp; -typedef struct { - Directive which; - struct Expression *args; -} DirectExpr; - - typedef struct { struct Expression *fn; union { @@ -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 { -- cgit v1.2.3