summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2019-09-21 16:08:55 -0400
committerLeo Tenenbaum <pommicket@gmail.com>2019-09-21 16:08:55 -0400
commitfc35d3e7cb55c90bf04d93eed584db0868db13bc (patch)
tree0f2d0fa5f24a520ae859b74e5b808f03452e564d
parentbf72f1b8fd0546fb4794e3d36ffa7cc38b79e6c5 (diff)
deref; improved eval, decls
-rw-r--r--abbrevs.txt19
-rw-r--r--eval.c135
-rw-r--r--main.c1
-rw-r--r--parse.c259
-rw-r--r--test.toc7
-rw-r--r--types.c19
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
diff --git a/eval.c b/eval.c
index 7033367..8a78dd0 100644
--- a/eval.c
+++ b/eval.c
@@ -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;
diff --git a/main.c b/main.c
index 83b6541..6b97098 100644
--- a/main.c
+++ b/main.c
@@ -1,6 +1,7 @@
/*
TODO:
pointers
+float => f32
don't allow nested functions to capture outer variables (constants are allowed though)
re-do cgen
*/
diff --git a/parse.c b/parse.c
index 9ac94a9..9f9849c 100644
--- a/parse.c
+++ b/parse.c
@@ -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;
diff --git a/test.toc b/test.toc
index 8d572ac..6868061 100644
--- a/test.toc
+++ b/test.toc
@@ -1,6 +1,5 @@
main @= fn() {
- x : int;
- y : *i64 = &x;
- N @= 12.3;
- z := &N;
+ Q @= 8;
+ P @= 7;
+ x : [P+Q]f32;
};
diff --git a/types.c b/types.c
index d0e147e..f4d8f0a 100644
--- a/types.c
+++ b/types.c
@@ -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;