summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--eval.c13
-rw-r--r--main.c2
-rw-r--r--parse.c298
-rw-r--r--test.toc8
-rw-r--r--tokenizer.c3
-rw-r--r--types.c12
6 files changed, 191 insertions, 145 deletions
diff --git a/eval.c b/eval.c
index 0d2e140..6ab901a 100644
--- a/eval.c
+++ b/eval.c
@@ -195,16 +195,13 @@ static bool eval_expr(Expression *e, Value *v) {
case EXPR_FN:
v->fn = e->fn;
return true;
+ case EXPR_CAST:
case EXPR_IF:
- case EXPR_WHILE: {
- err_print(e->where, "compile time if/while not supported yet."); /* TODO */
- } break;
+ case EXPR_WHILE:
case EXPR_CALL:
- err_print(e->where, "Compile time function calling not supported yet."); /* TODO */
- break;
- case EXPR_BLOCK:
- err_print(e->where, "Block eval not supported yet."); /* TODO */
- break;
+ case EXPR_BLOCK: {
+ err_print(e->where, "operation not supported at compile time yet."); /* TODO */
+ } break;
case EXPR_DIRECT:
switch (e->direct.which) {
case DIRECT_C:
diff --git a/main.c b/main.c
index 77c4208..b4bf517 100644
--- a/main.c
+++ b/main.c
@@ -1,7 +1,7 @@
/*
TODO:
-get rid of multiple types in one decl (no a, b := twofn();)
casting
+named return values
re-do cgen
*/
#include "toc.c"
diff --git a/parse.c b/parse.c
index 499ed78..ff6c8d2 100644
--- a/parse.c
+++ b/parse.c
@@ -72,6 +72,7 @@ typedef enum {
EXPR_IF,
EXPR_WHILE,
EXPR_FN,
+ EXPR_CAST,
EXPR_CALL,
EXPR_BLOCK,
EXPR_DIRECT
@@ -121,12 +122,17 @@ typedef struct {
Block body;
} WhileExpr;
-typedef struct FnExpr {
+typedef struct {
Array params; /* declarations of the parameters to this function */
Type ret_type;
Block body;
} FnExpr; /* an expression such as fn(x: int) int { 2 * x } */
+typedef struct {
+ Type type;
+ struct Expression *expr;
+} CastExpr;
+
#define EXPR_FLAG_FOUND_TYPE 0x01
typedef struct Expression {
@@ -154,6 +160,7 @@ typedef struct Expression {
IfExpr if_;
WhileExpr while_;
FnExpr fn;
+ CastExpr cast;
Block block;
};
} Expression;
@@ -394,26 +401,6 @@ static Expression *parser_new_expr(Parser *p) {
return block_arr_add(&p->exprs);
}
-#define NOT_AN_OP -1
-static int op_precedence(Keyword op) {
- switch (op) {
- case KW_EQ: return 0;
- case KW_LT: return 3;
- case KW_GT: return 3;
- case KW_LE: return 3;
- case KW_GE: return 3;
- case KW_EQEQ: return 3;
- case KW_NE: return 3;
- case KW_COMMA: return 5;
- case KW_PLUS: return 10;
- case KW_MINUS: return 20;
- case KW_AMPERSAND: return 25;
- case KW_ASTERISK: return 30;
- case KW_SLASH: return 40;
- case KW_EXCLAMATION: return 50;
- default: return NOT_AN_OP;
- }
-}
/* TODO: check that we check which thing ends it everywhere */
@@ -732,6 +719,29 @@ static bool parse_args(Parser *p, Array *args) {
static void fprint_expr(FILE *out, Expression *e);
+
+#define NOT_AN_OP -1
+#define CAST_PRECEDENCE 1
+static int op_precedence(Keyword op) {
+ switch (op) {
+ case KW_EQ: return 0;
+ case KW_LT: return 3;
+ case KW_GT: return 3;
+ case KW_LE: return 3;
+ case KW_GE: return 3;
+ case KW_EQEQ: return 3;
+ case KW_NE: return 3;
+ case KW_COMMA: return 5;
+ case KW_PLUS: return 10;
+ case KW_MINUS: return 20;
+ case KW_AMPERSAND: return 25;
+ case KW_ASTERISK: return 30;
+ case KW_SLASH: return 40;
+ case KW_EXCLAMATION: return 50;
+ default: return NOT_AN_OP;
+ }
+}
+
static bool parse_expr(Parser *p, Expression *e, Token *end) {
Tokenizer *t = p->tokr;
e->flags = 0;
@@ -927,7 +937,8 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) {
break;
default: { /* OPTIM: use individual cases for each op */
if (paren_level == 0 && brace_level == 0 && square_level == 0) {
- int precedence = op_precedence(token->kw);
+ int precedence = token->kw == KW_AS ? CAST_PRECEDENCE
+ : op_precedence(token->kw);
if (precedence == NOT_AN_OP) break; /* nvm it's not an operator */
if (lowest_precedence == NOT_AN_OP || precedence <= lowest_precedence) {
lowest_precedence = precedence;
@@ -970,7 +981,133 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) {
return true;
}
- if (lowest_precedence == NOT_AN_OP) {
+ if (lowest_precedence != NOT_AN_OP) {
+
+ /* Check if this is a unary op not a binary one (e.g. +-3 => +(-3), not (+)-(3)). */
+ while (lowest_precedence_op != t->token
+ && lowest_precedence_op[-1].kind == TOKEN_KW
+ && op_precedence(lowest_precedence_op[-1].kw) != NOT_AN_OP) {
+ lowest_precedence_op--;
+ }
+
+ if (lowest_precedence_op == t->token) {
+ /* Unary */
+ UnaryOp op;
+ bool is_unary = true;
+ switch (lowest_precedence_op->kw) {
+ case KW_PLUS:
+ /* unary + is ignored entirely */
+ t->token++;
+ /* re-parse this expression without + */
+ return parse_expr(p, e, end);
+ case KW_MINUS:
+ op = UNARY_MINUS;
+ break;
+ case KW_AMPERSAND:
+ op = UNARY_ADDRESS;
+ break;
+ case KW_ASTERISK:
+ op = UNARY_DEREF;
+ break;
+ case KW_EXCLAMATION:
+ op = UNARY_NOT;
+ break;
+ default:
+ is_unary = false;
+ break;
+ }
+ if (!is_unary) {
+ tokr_err(t, "%s is not a unary operator.", keywords[lowest_precedence_op->kw]);
+ return false;
+ }
+ e->unary.op = op;
+ e->kind = EXPR_UNARY_OP;
+ t->token++;
+ Expression *of = parser_new_expr(p);
+ e->unary.of = of;
+ return parse_expr(p, of, end);
+ }
+
+ if (lowest_precedence_op->kw == KW_AS) {
+ /* cast */
+ Expression *casted = parser_new_expr(p);
+ e->kind = EXPR_CAST;
+ e->cast.expr = casted;
+ if (!parse_expr(p, casted, lowest_precedence_op))
+ return false;
+ t->token = lowest_precedence_op + 1;
+ if (!parse_type(p, &e->cast.type))
+ return false;
+ if (t->token != end) {
+ tokr_err(t, "Cast expression continues after type");
+ return false;
+ }
+ return true;
+ }
+
+
+ BinaryOp op;
+ switch (lowest_precedence_op->kw) {
+ case KW_PLUS:
+ op = BINARY_PLUS;
+ break;
+ case KW_MINUS:
+ op = BINARY_MINUS;
+ break;
+ case KW_EQEQ:
+ op = BINARY_EQ;
+ break;
+ case KW_NE:
+ op = BINARY_NE;
+ break;
+ case KW_LT:
+ op = BINARY_LT;
+ break;
+ case KW_LE:
+ op = BINARY_LE;
+ break;
+ case KW_GT:
+ op = BINARY_GT;
+ break;
+ case KW_GE:
+ op = BINARY_GE;
+ break;
+ case KW_EQ:
+ op = BINARY_SET;
+ break;
+ case KW_COMMA:
+ op = BINARY_COMMA;
+ break;
+ case KW_ASTERISK:
+ op = BINARY_MUL;
+ break;
+ case KW_SLASH:
+ op = BINARY_DIV;
+ break;
+ case KW_AMPERSAND:
+ case KW_EXCLAMATION:
+ err_print(lowest_precedence_op->where, "Unary operator '%s' being used as a binary operator!", kw_to_str(lowest_precedence_op->kw));
+ return false;
+ default: assert(0); return false;
+ }
+ e->binary.op = op;
+ e->kind = EXPR_BINARY_OP;
+
+ Expression *lhs = parser_new_expr(p);
+ e->binary.lhs = lhs;
+ if (!parse_expr(p, lhs, lowest_precedence_op)) {
+ return false;
+ }
+
+ Expression *rhs = parser_new_expr(p);
+ t->token = lowest_precedence_op + 1;
+ e->binary.rhs = rhs;
+ if (!parse_expr(p, rhs, end)) {
+ return false;
+ }
+
+ return true;
+ } else {
/* function calls, array accesses, etc. */
/* try a function call or array access */
@@ -1093,114 +1230,6 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) {
t->token = end + 1;
return false;
}
-
- /* Check if his is a unary op not a binary one (e.g. +-3 => +(-3), not (+)-(3)). */
- while (lowest_precedence_op != t->token
- && lowest_precedence_op[-1].kind == TOKEN_KW
- && op_precedence(lowest_precedence_op[-1].kw) != NOT_AN_OP) {
- lowest_precedence_op--;
- }
-
- if (lowest_precedence_op == t->token) {
- /* Unary */
- UnaryOp op;
- bool is_unary = true;
- switch (lowest_precedence_op->kw) {
- case KW_PLUS:
- /* unary + is ignored entirely */
- t->token++;
- /* re-parse this expression without + */
- return parse_expr(p, e, end);
- case KW_MINUS:
- op = UNARY_MINUS;
- break;
- case KW_AMPERSAND:
- op = UNARY_ADDRESS;
- break;
- case KW_ASTERISK:
- op = UNARY_DEREF;
- break;
- case KW_EXCLAMATION:
- op = UNARY_NOT;
- break;
- default:
- is_unary = false;
- break;
- }
- if (!is_unary) {
- tokr_err(t, "%s is not a unary operator.", keywords[lowest_precedence_op->kw]);
- return false;
- }
- e->unary.op = op;
- e->kind = EXPR_UNARY_OP;
- t->token++;
- Expression *of = parser_new_expr(p);
- e->unary.of = of;
- return parse_expr(p, of, end);
- }
-
-
- BinaryOp op;
- switch (lowest_precedence_op->kw) {
- case KW_PLUS:
- op = BINARY_PLUS;
- break;
- case KW_MINUS:
- op = BINARY_MINUS;
- break;
- case KW_EQEQ:
- op = BINARY_EQ;
- break;
- case KW_NE:
- op = BINARY_NE;
- break;
- case KW_LT:
- op = BINARY_LT;
- break;
- case KW_LE:
- op = BINARY_LE;
- break;
- case KW_GT:
- op = BINARY_GT;
- break;
- case KW_GE:
- op = BINARY_GE;
- break;
- case KW_EQ:
- op = BINARY_SET;
- break;
- case KW_COMMA:
- op = BINARY_COMMA;
- break;
- case KW_ASTERISK:
- op = BINARY_MUL;
- break;
- case KW_SLASH:
- op = BINARY_DIV;
- break;
- case KW_AMPERSAND:
- case KW_EXCLAMATION:
- err_print(lowest_precedence_op->where, "Unary operator '%s' being used as a binary operator!", kw_to_str(lowest_precedence_op->kw));
- return false;
- default: assert(0); return false;
- }
- e->binary.op = op;
- e->kind = EXPR_BINARY_OP;
-
- Expression *lhs = parser_new_expr(p);
- e->binary.lhs = lhs;
- if (!parse_expr(p, lhs, lowest_precedence_op)) {
- return false;
- }
-
- Expression *rhs = parser_new_expr(p);
- t->token = lowest_precedence_op + 1;
- e->binary.rhs = rhs;
- if (!parse_expr(p, rhs, end)) {
- return false;
- }
-
- return true;
}
static inline bool ends_decl(Token *t, DeclEndType ends_with) {
@@ -1486,6 +1515,13 @@ static void fprint_expr(FILE *out, Expression *e) {
case EXPR_FN:
fprint_fn_expr(out, &e->fn);
break;
+ case EXPR_CAST:
+ fprintf(out, "cast(");
+ fprint_expr(out, e->cast.expr);
+ fprintf(out, ", ");
+ fprint_type(out, &e->cast.type);
+ fprintf(out, ")");
+ break;
case EXPR_IF:
if (e->if_.cond) {
fprintf(out, "(else)? if ");
diff --git a/test.toc b/test.toc
index e582078..d041aa3 100644
--- a/test.toc
+++ b/test.toc
@@ -1,8 +1,8 @@
main @= fn() {
// b := !(5 > 3 && 4 <= 3 && 3 >= 2 || 0 == 1 || 5 != 3);
- N @= 2;
- foo : [N+1]int;
- x : float;
- x, foo[0], foo[1] = 1.3, 3, 5;
+ N, M @= 2;
+ foo := 3;
+ bar : float = foo as float;
+
};
diff --git a/tokenizer.c b/tokenizer.c
index dc46cd5..02194c5 100644
--- a/tokenizer.c
+++ b/tokenizer.c
@@ -44,6 +44,7 @@ typedef enum {
KW_WHILE,
KW_RETURN,
KW_FN,
+ KW_AS,
KW_BOOL,
KW_TRUE,
KW_FALSE,
@@ -66,7 +67,7 @@ static const char *keywords[KW_COUNT] =
{";", ":", "@", ",", "(", ")", "{", "}", "[", "]", "==", "!=", "<", "<=", ">", ">=",
"+", "-", "*", "!", "&", "/",
"=",
- "if", "elif", "else", "while", "return", "fn",
+ "if", "elif", "else", "while", "return", "fn", "as",
"bool", "true", "false",
"int", "i8", "i16", "i32", "i64",
"u8", "u16", "u32", "u64", "float", "f32", "f64"};
diff --git a/types.c b/types.c
index 86247e8..5c1ed9d 100644
--- a/types.c
+++ b/types.c
@@ -389,6 +389,13 @@ static bool types_expr(Typer *tr, Expression *e) {
case EXPR_IDENT: {
if (!type_of_ident(tr, e->where, e->ident, t)) return false;
} break;
+ case EXPR_CAST: {
+ /* TODO: forbid certain casts */
+ CastExpr *c = &e->cast;
+ if (!types_expr(tr, c->expr))
+ return false;
+ *t = c->type;
+ } break;
case EXPR_IF: {
IfExpr *i = &e->if_;
IfExpr *curr = i;
@@ -741,6 +748,11 @@ static bool types_decl(Typer *tr, Declaration *d) {
}
}
d->flags |= DECL_FLAG_FOUND_TYPE;
+ if (d->type.kind == TYPE_TUPLE) {
+ /* TODO(eventually): Should this be allowed? */
+ err_print(d->where, "Declaring a tuple is not allowed.");
+ return false;
+ }
ret:
arr_remove_last(&tr->in_decls);
return success;