diff options
author | Leo Tenenbaum <pommicket@gmail.com> | 2019-09-21 16:08:55 -0400 |
---|---|---|
committer | Leo Tenenbaum <pommicket@gmail.com> | 2019-09-21 16:08:55 -0400 |
commit | fc35d3e7cb55c90bf04d93eed584db0868db13bc (patch) | |
tree | 0f2d0fa5f24a520ae859b74e5b808f03452e564d | |
parent | bf72f1b8fd0546fb4794e3d36ffa7cc38b79e6c5 (diff) |
deref; improved eval, decls
-rw-r--r-- | abbrevs.txt | 19 | ||||
-rw-r--r-- | eval.c | 135 | ||||
-rw-r--r-- | main.c | 1 | ||||
-rw-r--r-- | parse.c | 259 | ||||
-rw-r--r-- | test.toc | 7 | ||||
-rw-r--r-- | types.c | 19 |
6 files changed, 259 insertions, 181 deletions
diff --git a/abbrevs.txt b/abbrevs.txt index f75f05b..77176ff 100644 --- a/abbrevs.txt +++ b/abbrevs.txt @@ -1,13 +1,14 @@ -kw - keyword -ident - identifier -direct - directive decl - declaration -stmt - statement +deref - dereference +direct - directive +eof - end of file expr - expression -op - operator -tokr - tokenizer -str - string -num - number fn - function +ident - identifier +kw - keyword +num - number +op - operator ptr - pointer -eof - end of file +stmt - statement +str - string +tokr - tokenizer @@ -1,74 +1,98 @@ -/* static bool eval_expr_as_float(Expression *e, FloatLiteral *f) { */ -/* switch (e->kind) { */ -/* case EXPR_FLOAT_LITERAL: */ -/* *f = e->floatl; */ -/* return true; */ -/* case EXPR_INT_LITERAL: */ -/* *f = (FloatLiteral)e->intl; */ -/* return true; */ -/* } */ -/* err_print(e->where, "Not implemented yet"); */ -/* return false; */ -/* } */ +typedef struct Value { + union { + Integer intv; + Floating floatv; + struct Value *points_to; + FnExpr fn; + }; +} Value; -static bool eval_expr_as_int(Expression *e, Integer *i) { - /* OPTIM: cache eval'd expression values? (probably only for declarations) */ +/* NOTE: expr must be typed before it can be evaluated */ +static bool eval_expr(Expression *e, Value *v) { + /* TODO: cache eval'd expression values (probably only needed for declarations) */ switch (e->kind) { case EXPR_LITERAL_FLOAT: - err_print(e->where, "Expected integer, but found floating-point literal."); + v->floatv = e->floatl; return false; case EXPR_LITERAL_INT: if (e->intl > (UInteger)INTEGER_MAX) { /* TODO: FIXME */ err_print(e->where, "Overflow when evaluating integer."); return false; } - *i = (Integer)e->intl; + v->intv = (Integer)e->intl; return true; case EXPR_LITERAL_STR: - err_print(e->where, "Expected integer, but found string literal."); + err_print(e->where, "not implemented yet"); /* TODO */ return false; - case EXPR_UNARY_OP: + case EXPR_UNARY_OP: { + Expression *of_expr = e->unary.of; switch (e->unary.op) { case UNARY_MINUS: { - Integer of; - if (!eval_expr_as_int(e->unary.of, &of)) return false; - *i = -of; + Value of; + if (!eval_expr(of_expr, &of)) return false; + assert(e->type.kind != TYPE_BUILTIN); + if (type_builtin_is_integer(e->type.builtin)) { + v->intv = -of.intv; + } else if (type_builtin_is_floating(e->type.builtin)) { + v->floatv = -of.floatv; + } else { + err_print(e->where, "negation of non-numerical types not supported in evaluator yet."); + return false; + } return true; } case UNARY_ADDRESS: - err_print(e->where, "Use of pointer as integer constant."); - return false; + v->points_to = malloc(sizeof *v->points_to); /* OPTIM */ + return eval_expr(e->unary.of, v->points_to); + case UNARY_DEREF: { + Value ptr; + if (!eval_expr(of_expr, &ptr)) return false; + *v = *ptr.points_to; + return true; + } break; } - break; + } break; case EXPR_BINARY_OP: { - + Value lhs, rhs; + /* NOTE: this will need to change for short-circuiting */ + if (!eval_expr(e->binary.lhs, &lhs)) return false; + if (!eval_expr(e->binary.rhs, &rhs)) return false; + bool is_int = type_builtin_is_integer(e->type.builtin); + bool is_float = type_builtin_is_floating(e->type.builtin); switch (e->binary.op) { case BINARY_PLUS: + if (is_int) { + v->intv = lhs.intv + rhs.intv; + } else if (is_float) { + v->floatv = lhs.floatv + rhs.floatv; + } else assert(0); + return true; case BINARY_MINUS: + if (is_int) { + v->intv = lhs.intv - rhs.intv; + } else if (is_float) { + v->floatv = lhs.floatv - rhs.floatv; + } else assert(0); + return true; case BINARY_MUL: - case BINARY_DIV: { - Integer lhs, rhs; - if (!eval_expr_as_int(e->binary.lhs, &lhs)) return false; - if (!eval_expr_as_int(e->binary.rhs, &rhs)) return false; - switch (e->binary.op) { - case BINARY_PLUS: - *i = lhs + rhs; - return true; - case BINARY_MINUS: - *i = lhs - rhs; - return true; - case BINARY_MUL: - *i = lhs * rhs; - return true; - case BINARY_DIV: - *i = lhs / rhs; - return true; - default: assert(0); return false; - } - } + if (is_int) { + v->intv = lhs.intv * rhs.intv; + } else if (is_float) { + v->floatv = lhs.floatv * rhs.floatv; + } else assert(0); + return true; + case BINARY_DIV: + /* TODO(eventually): check div by 0 */ + if (is_int) { + v->intv = lhs.intv / rhs.intv; + } else if (is_float) { + v->floatv = lhs.floatv / rhs.floatv; + } else assert(0); + return true; case BINARY_SET: + return true; case BINARY_COMMA: - err_print(e->where, "Expected operator which returns an integer, but got %s", binary_op_to_str(e->binary.op)); + err_print(e->where, "tuples not supported at compile time yet."); return false; case BINARY_AT_INDEX: err_print(e->where, "Cannot get index of array at compile time yet."); @@ -95,21 +119,18 @@ static bool eval_expr_as_int(Expression *e, Integer *i) { info_print(d->where, "Declaration was here."); return false; } - if (d->type.kind != TYPE_BUILTIN || !type_builtin_is_integer(d->type.builtin)) { - char *type_str = type_to_str(&d->type); - err_print(e->where, "Expected integer, but identifier has type %s.", type_str); - info_print(d->where, "Declaration was here."); - free(type_str); - return false; - } /* TODO: tuples */ - eval_expr_as_int(&d->expr, i); - + if (!d->val) { + d->val = err_malloc(sizeof *d->val); /* OPTIM */ + if (!eval_expr(&d->expr, d->val)) + return false; + } + *v = *d->val; return true; } break; case EXPR_FN: - err_print(e->where, "Expected integer, but found function."); - return false; + v->fn = *e->fn; + return true; case EXPR_CALL: err_print(e->where, "Compile time function calling not supported yet."); /* TODO */ break; @@ -1,6 +1,7 @@ /* TODO: pointers +float => f32 don't allow nested functions to capture outer variables (constants are allowed though) re-do cgen */ @@ -71,7 +71,8 @@ typedef enum { typedef enum { UNARY_MINUS, - UNARY_ADDRESS /* &x */ + UNARY_ADDRESS, /* &x */ + UNARY_DEREF } UnaryOp; typedef enum { @@ -92,7 +93,6 @@ typedef struct { typedef struct { struct Expression *fn; Array args; /* of Expression */ - unsigned long out_var; /* which out variable is used for this call (used by cgen) */ } CallExpr; #define EXPR_FLAG_FOUND_TYPE 0x01 @@ -135,14 +135,13 @@ typedef struct Declaration { Type type; unsigned short flags; Expression expr; + struct Value *val; /* only for constant decls. set to NULL here, and to actual value by types.c. */ } Declaration; typedef struct FnExpr { Declaration params; /* declaration of the parameters to this function */ Type ret_type; Block body; - Identifier name; /* NULL if the function is anonymous (set to NULL by parse.c, set to actual value by types_cgen.c) */ - unsigned long id; /* this is used to keep track of local vs global/other local functions (there might be multiple functions called "foo") */ } FnExpr; /* an expression such as fn(x: int) int {return 2 * x;} */ typedef enum { @@ -177,12 +176,15 @@ typedef enum { } DeclEndType; static bool parse_expr(Parser *p, Expression *e, Token *end); -static bool parse_decl(Parser *p, Declaration *d, DeclEndType ends_with); + +#define PARSE_DECL_ALLOW_CONST_WITH_NO_EXPR 0x01 +static bool parse_decl(Parser *p, Declaration *d, DeclEndType ends_with, uint16_t flags); static const char *unary_op_to_str(UnaryOp u) { switch (u) { case UNARY_MINUS: return "-"; case UNARY_ADDRESS: return "&"; + case UNARY_DEREF: return "*"; } assert(0); return ""; @@ -596,14 +598,13 @@ static bool parse_fn_expr(Parser *p, FnExpr *f) { Tokenizer *t = p->tokr; /* only called when token is fn */ assert(token_is_kw(t->token, KW_FN)); - f->name = 0; t->token++; if (!token_is_kw(t->token, KW_LPAREN)) { tokr_err(t, "Expected '(' after 'fn'."); return false; } t->token++; - parse_decl(p, &f->params, DECL_END_RPAREN); + parse_decl(p, &f->params, DECL_END_RPAREN, PARSE_DECL_ALLOW_CONST_WITH_NO_EXPR); if (token_is_kw(t->token, KW_LBRACE)) { /* void function */ @@ -928,9 +929,13 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) { op = UNARY_MINUS; break; case KW_AMPERSAND: - is_unary= true; + is_unary = true; op = UNARY_ADDRESS; break; + case KW_ASTERISK: + is_unary = true; + op = UNARY_DEREF; + break; default: is_unary = false; break; @@ -1004,127 +1009,163 @@ static inline bool ends_decl(Token *t, DeclEndType ends_with) { || (token_is_kw(t, KW_RPAREN) && ends_with == DECL_END_RPAREN); } -static bool parse_single_type_in_decl(Parser *p, Declaration *d, DeclEndType ends_with) { +static bool parse_decl(Parser *p, Declaration *d, DeclEndType ends_with, uint16_t flags) { + d->val = NULL; + d->type.kind = TYPE_VOID; + d->where = p->tokr->token->where; + arr_create(&d->idents, sizeof(Identifier)); Tokenizer *t = p->tokr; + d->flags = 0; + if (ends_decl(t->token, ends_with)) { + t->token++; + return true; + } + /* OPTIM: Maybe don't use a dynamic array or use parser allocator. */ size_t n_idents_with_this_type = 1; - while (1) { - Identifier *ident = arr_add(&d->idents); - if (t->token->kind != TOKEN_IDENT) { - tokr_err(t, "Cannot declare non-identifier (that's a %s).", token_kind_to_str(t->token->kind)); /* TODO(eventually): an */ - return false; - } - *ident = t->token->ident; - t->token++; - if (token_is_kw(t->token, KW_COMMA)) { + bool ret = true; + for (size_t type_no = 0; ; type_no++) { + /* parse a single type in this decl */ + while (1) { + Identifier *ident = arr_add(&d->idents); + if (t->token->kind != TOKEN_IDENT) { + tokr_err(t, "Cannot declare non-identifier (that's a %s).", token_kind_to_str(t->token->kind)); /* TODO(eventually): an */ + ret = false; + break; + } + *ident = t->token->ident; t->token++; - n_idents_with_this_type++; - continue; + if (token_is_kw(t->token, KW_COMMA)) { + t->token++; + n_idents_with_this_type++; + continue; + } + if (token_is_kw(t->token, KW_COLON)) { + if (d->flags & DECL_FLAG_CONST) { + tokr_err(t, "Either everything or nothing must be constant in a declaration."); + ret = false; + break; + } + t->token++; + break; + } + if (token_is_kw(t->token, KW_AT)) { + if (type_no == 0) { + d->flags |= DECL_FLAG_CONST; + } else if (!(d->flags & DECL_FLAG_CONST)) { + tokr_err(t, "Either everything or nothing must be constant in a declaration."); + ret = false; + break; + } + t->token++; + break; + } + tokr_err(t, "Expected ',' to continue listing variables or ':' / '@' to indicate type."); + ret = false; + break; } - if (token_is_kw(t->token, KW_COLON)) { - t->token++; + if (!ret) break; + + if (token_is_kw(t->token, KW_SEMICOLON) || token_is_kw(t->token, KW_RPAREN)) { + /* e.g. foo :; */ + tokr_err(t, "Cannot infer type without expression."); + ret = false; break; } - if (token_is_kw(t->token, KW_AT)) { - d->flags |= DECL_FLAG_CONST; - t->token++; + + bool annotates_type = !token_is_kw(t->token, KW_EQ) && !token_is_kw(t->token, KW_COMMA); + if (d->type.kind != TYPE_VOID /* multiple types in one declaration */ + && (!!(d->flags & DECL_FLAG_ANNOTATES_TYPE)) != annotates_type) { /* annotation on one decl but not the other */ + /* e.g. x: int, y := 3, 5;*/ + tokr_err(t, "You must specify either all types or no types in a single declaration."); + ret = false; break; } - tokr_err(t, "Expected ',' to continue listing variables or ':' / '@' to indicate type."); - return false; - } - - - if (token_is_kw(t->token, KW_SEMICOLON) || token_is_kw(t->token, KW_RPAREN)) { - /* e.g. foo :; */ - tokr_err(t, "Cannot infer type without expression."); - return false; - } + if (annotates_type) { + d->flags |= DECL_FLAG_ANNOTATES_TYPE; + Type type; + if (!parse_type(p, &type)) { + ret = false; + break; + } + if (n_idents_with_this_type == 1 && d->type.kind == TYPE_VOID) { + d->type = type; + } else if (d->type.kind == TYPE_TUPLE) { + /* add to tuple */ + for (size_t i = 0; i < n_idents_with_this_type; i++) { + *(Type*)arr_add(&d->type.tuple) = type; + } + } else { + /* construct tuple */ + Array tup_arr; + arr_create(&tup_arr, sizeof(Type)); + if (d->type.kind != TYPE_VOID) { + *(Type*)arr_add(&tup_arr) = d->type; /* add current type */ + } + d->type.flags = 0; + d->type.kind = TYPE_TUPLE; + d->type.tuple = tup_arr; + for (size_t i = 0; i < n_idents_with_this_type; i++) { + *(Type*)arr_add(&d->type.tuple) = type; + } + } + } - bool annotates_type = !token_is_kw(t->token, KW_EQ) && !token_is_kw(t->token, KW_COMMA); - if (d->type.kind != TYPE_VOID /* multiple types in one declaration */ - && (!!(d->flags & DECL_FLAG_ANNOTATES_TYPE)) != annotates_type) { /* annotation on one decl but not the other */ - /* e.g. x: int, y := 3, 5;*/ - tokr_err(t, "You must specify either all types or no types in a single declaration."); - return false; - } - if (annotates_type) { - d->flags |= DECL_FLAG_ANNOTATES_TYPE; - Type type; - if (!parse_type(p, &type)) { - return false; + if (token_is_kw(t->token, KW_COMMA)) { + /* next type in declaration */ + t->token++; /* move past , */ + continue; } - if (n_idents_with_this_type == 1 && d->type.kind == TYPE_VOID) { - d->type = type; - } else if (d->type.kind == TYPE_TUPLE) { - /* add to tuple */ - for (size_t i = 0; i < n_idents_with_this_type; i++) { - *(Type*)arr_add(&d->type.tuple) = type; + + /* OPTIM: switch t->token->kw ? */ + if (token_is_kw(t->token, KW_EQ)) { + t->token++; + Token *end = expr_find_end(p, 0); + if (!token_is_kw(end, KW_SEMICOLON)) { + tokr_err(t, "Expected ';' at end of declaration."); + ret = false; + break; } - } else { - /* construct tuple */ - Array tup_arr; - arr_create(&tup_arr, sizeof(Type)); - if (d->type.kind != TYPE_VOID) { - *(Type*)arr_add(&tup_arr) = d->type; /* add current type */ + d->flags |= DECL_FLAG_HAS_EXPR; + if (!parse_expr(p, &d->expr, end)) { + t->token = end + 1; /* move past ; */ + ret = false; + break; } - d->type.flags = 0; - d->type.kind = TYPE_TUPLE; - d->type.tuple = tup_arr; - for (size_t i = 0; i < n_idents_with_this_type; i++) { - *(Type*)arr_add(&d->type.tuple) = type; + if (ends_decl(t->token, ends_with)) { + t->token++; + break; } + tokr_err(t, "Expected '%c' at end of declaration.", + ends_with == DECL_END_SEMICOLON ? ';' : ')'); + ret = false; + } else if (ends_decl(t->token, ends_with)) { + t->token++; + } else { + tokr_err(t, "Expected '%c' or '=' at end of delaration.", + ends_with == DECL_END_SEMICOLON ? ';' : ')'); + ret = false; } + break; } - - if (token_is_kw(t->token, KW_COMMA)) { - /* next type in declaration */ - t->token++; /* move past , */ - return parse_single_type_in_decl(p, d, ends_with); + + if ((d->flags & DECL_FLAG_CONST) && !(d->flags & DECL_FLAG_HAS_EXPR) && !(flags & PARSE_DECL_ALLOW_CONST_WITH_NO_EXPR)) { + t->token--; + /* disallowed constant without an expression, e.g. x @ int; */ + tokr_err(t, "You must have an expression at the end of this constant declaration."); + ret = false; } - /* OPTIM: switch t->token->kw ? */ - if (token_is_kw(t->token, KW_EQ)) { - t->token++; - Token *end = expr_find_end(p, 0); - if (!token_is_kw(end, KW_SEMICOLON)) { - tokr_err(t, "Expected ';' at end of declaration."); - return false; - } - if (!parse_expr(p, &d->expr, end)) { - t->token = end + 1; /* move past ; */ - return false; - } - d->flags |= DECL_FLAG_HAS_EXPR; - if (ends_decl(t->token, ends_with)) { + if (!ret) { + /* move past end of decl */ + while (t->token->kind != TOKEN_EOF && !token_is_kw(t->token, KW_SEMICOLON)) { t->token++; - return true; } - tokr_err(t, "Expected '%c' at end of declaration.", - ends_with == DECL_END_SEMICOLON ? ';' : ')'); - return false; - - } else if (ends_decl(t->token, ends_with)) { - t->token++; - return true; - } else { - tokr_err(t, "Expected '%c' or '=' at end of delaration.", - ends_with == DECL_END_SEMICOLON ? ';' : ')'); - return false; - } -} - -static bool parse_decl(Parser *p, Declaration *d, DeclEndType ends_with) { - d->type.kind = TYPE_VOID; - d->where = p->tokr->token->where; - arr_create(&d->idents, sizeof(Identifier)); - Tokenizer *t = p->tokr; - d->flags = 0; - if (ends_decl(t->token, ends_with)) { - t->token++; - return true; + if (token_is_kw(t->token, KW_SEMICOLON)) { + t->token++; /* move past ; */ + } } - return parse_single_type_in_decl(p, d, ends_with); /* recursively calls itself to parse all types */ + return ret; } static bool parse_stmt(Parser *p, Statement *s) { @@ -1139,7 +1180,7 @@ static bool parse_stmt(Parser *p, Statement *s) { if (token_is_kw(t->token + 1, KW_COLON) || token_is_kw(t->token + 1, KW_COMMA) || token_is_kw(t->token + 1, KW_AT)) { s->kind = STMT_DECL; - if (!parse_decl(p, &s->decl, DECL_END_SEMICOLON)) { + if (!parse_decl(p, &s->decl, DECL_END_SEMICOLON, 0)) { return false; } return true; @@ -1,6 +1,5 @@ main @= fn() { - x : int; - y : *i64 = &x; - N @= 12.3; - z := &N; + Q @= 8; + P @= 7; + x : [P+Q]f32; }; @@ -202,8 +202,14 @@ static bool type_resolve(Type *t) { case TYPE_ARR: { /* it's an array */ if (!type_resolve(t->arr.of)) return false; /* resolve inner type */ - Integer size; - if (!eval_expr_as_int(t->arr.n_expr, &size)) return false; /* resolve N */ + Value val; + Expression *n_expr = t->arr.n_expr; + if (!type_of_expr(n_expr)) return false; + if (n_expr->type.kind != TYPE_BUILTIN || !type_builtin_is_integer(n_expr->type.builtin)) + return false; + + if (!eval_expr(n_expr, &val)) return false; /* resolve N */ + Integer size = val.intv; if (size < 0) err_print(t->arr.n_expr->where, "Negative array length (" INTEGER_FMT ")", size); t->arr.n = (UInteger)size; @@ -353,6 +359,8 @@ static bool type_of_expr(Expression *e) { t->ptr.of = malloc(sizeof *t->ptr.of); /* OPTIM */ *t->ptr.of = *of_type; break; + case UNARY_DEREF: + *t = *of_type->ptr.of; } } break; case EXPR_BINARY_OP: { @@ -531,6 +539,13 @@ static bool types_decl(Declaration *d) { } d->type = d->expr.type; } + if (d->flags & DECL_FLAG_CONST) { + if (!d->val) { + d->val = err_malloc(sizeof *d->val); /* OPTIM */ + if (!eval_expr(&d->expr, d->val)) + return false; + } + } } d->flags |= DECL_FLAG_FOUND_TYPE; return true; |