-RELEASE=1
+RELEASE=0
OBJ_FILES=\
build/onyxlex.o \
- Checking which things are allowed to cast to/from should be checked in the checker,
not in the wasm generatation
- [ ] Start work on evaluating compile time known values.
+ [X] Start work on evaluating compile time known values.
- An expression marked COMPTIME will be reduced to its value in the parse tree.
[ ] All code paths return correct value
// NOTE: Useful not inlined functions
+AstTyped* ast_reduce(bh_allocator a, AstTyped* node);
void promote_numlit_to_larger(AstNumLit* num);
// NOTE: Useful inlined functions
b32 type_is_array(Type* tyoe);
b32 type_is_struct(Type* type);
b32 type_is_bool(Type* type);
+b32 type_is_small_integer(Type* type);
b32 type_is_integer(Type* type);
b32 type_is_numeric(Type* type);
b32 type_is_compound(Type* type);
typedef union {
struct {
- u32 i1, i2;
+ i32 i1, i2;
};
i64 l;
float f;
z = v.z + u.z;
}
-some_value := #char "A";
+some_value := 20 + 30 * 4 + 15 / 5;
start :: proc #export {
heap_init();
print_bin(42l);
print_hex(42l);
+ print(cast(u32) (#char "a" + #char "0"));
+
for i: #char "a", #char "f" do print_hex(cast(u64) i);
a := 12345;
CHECK(while, AstWhile* whilenode);
CHECK(for, AstFor* fornode);
CHECK(call, AstCall* call);
-CHECK(binaryop, AstBinaryOp* binop, b32 assignment_is_ok);
+CHECK(binaryop, AstBinaryOp** pbinop, b32 assignment_is_ok);
+CHECK(unaryop, AstUnaryOp** punop);
CHECK(expression, AstTyped** expr);
CHECK(address_of, AstAddressOf* aof);
CHECK(dereference, AstDereference* deref);
binop->right = (AstTyped *) binop_node;
binop->operation = Binary_Op_Assign;
- if (check_binaryop(binop_node, 0)) return 1;
+ if (check_binaryop(&binop_node, 0)) return 1;
}
if (!types_are_compatible(binop->left->type, binop->right->type)) {
return 0;
}
-CHECK(binaryop_compare, AstBinaryOp* binop) {
+CHECK(binaryop_compare, AstBinaryOp** pbinop) {
+ AstBinaryOp* binop = *pbinop;
+
if (binop->left->type == NULL) {
onyx_message_add(Msg_Type_Unresolved_Type,
binop->token->pos,
return 0;
}
-CHECK(binaryop_bool, AstBinaryOp* binop) {
+CHECK(binaryop_bool, AstBinaryOp** pbinop) {
+ AstBinaryOp* binop = *pbinop;
+
if (binop->left->type == NULL) {
onyx_message_add(Msg_Type_Unresolved_Type,
binop->token->pos,
return 0;
}
-CHECK(binaryop, AstBinaryOp* binop, b32 assignment_is_ok) {
+CHECK(binaryop, AstBinaryOp** pbinop, b32 assignment_is_ok) {
+ AstBinaryOp* binop = *pbinop;
+
if (check_expression(&binop->left)) return 1;
if (check_expression(&binop->right)) return 1;
+ if ((binop->left->flags & Ast_Flag_Comptime) && (binop->right->flags & Ast_Flag_Comptime)) {
+ binop->flags |= Ast_Flag_Comptime;
+ }
+
if (binop_is_assignment(binop)) return check_binop_assignment(binop, assignment_is_ok);
- if (binop_is_compare(binop)) return check_binaryop_compare(binop);
+ if (binop_is_compare(binop)) return check_binaryop_compare(pbinop);
if (binop->operation == Binary_Op_Bool_And
|| binop->operation == Binary_Op_Bool_Or)
- return check_binaryop_bool(binop);
+ return check_binaryop_bool(pbinop);
if (binop->left->type == NULL) {
onyx_message_add(Msg_Type_Unresolved_Type,
binop_node->type = binop->right->type;
binop_node->operation = Binary_Op_Multiply;
- if (check_binaryop(binop_node, 0)) return 1;
+ if (check_binaryop(&binop_node, 0)) return 1;
binop->right = (AstTyped *) binop_node;
binop->type = binop->left->type;
}
binop->type = binop->left->type;
+
+ if (binop->flags & Ast_Flag_Comptime) {
+ // NOTE: Not a binary op
+ *pbinop = (AstBinaryOp *) ast_reduce(semstate.node_allocator, (AstTyped *) binop);
+ }
+
+ return 0;
+}
+
+CHECK(unaryop, AstUnaryOp** punop) {
+ AstUnaryOp* unaryop = *punop;
+
+ if (check_expression(&unaryop->expr)) return 1;
+
+ if (unaryop->operation != Unary_Op_Cast) {
+ unaryop->type = unaryop->expr->type;
+ }
+
+ if (unaryop->expr->flags & Ast_Flag_Comptime) {
+ unaryop->flags |= Ast_Flag_Comptime;
+ // NOTE: Not a unary op
+ *punop = (AstUnaryOp *) ast_reduce(semstate.node_allocator, (AstTyped *) unaryop);
+ }
+
return 0;
}
i32 retval = 0;
switch (expr->kind) {
- case Ast_Kind_Binary_Op: retval = check_binaryop((AstBinaryOp *) expr, 0); break;
-
- case Ast_Kind_Unary_Op:
- retval = check_expression(&((AstUnaryOp *) expr)->expr);
-
- if (((AstUnaryOp *) expr)->operation != Unary_Op_Cast) {
- expr->type = ((AstUnaryOp *) expr)->expr->type;
- }
- break;
+ case Ast_Kind_Binary_Op: retval = check_binaryop((AstBinaryOp **) pexpr, 0); break;
+ case Ast_Kind_Unary_Op: retval = check_unaryop((AstUnaryOp **) pexpr); break;
case Ast_Kind_Call: retval = check_call((AstCall *) expr); break;
case Ast_Kind_Block: retval = check_block((AstBlock *) expr); break;
case Ast_Kind_Binary_Op:
stmt->flags |= Ast_Flag_Expr_Ignored;
- return check_binaryop((AstBinaryOp *) stmt, 1);
+ return check_binaryop((AstBinaryOp **) &stmt, 1);
default:
stmt->flags |= Ast_Flag_Expr_Ignored;
if (memres->initial_value != NULL) {
fill_in_type(memres->initial_value);
+ check_expression(&memres->initial_value);
+
+ if ((memres->initial_value->flags & Ast_Flag_Comptime) == 0) {
+ onyx_message_add(Msg_Type_Literal,
+ memres->initial_value->token->pos,
+ "top level expressions must be compile time known");
+ return 1;
+ }
Type* memres_type = memres->type;
if (!type_is_compound(memres_type)) memres_type = memres_type->Pointer.elem;
case Ast_Kind_If: return check_if((AstIf *) node);
case Ast_Kind_While: return check_while((AstWhile *) node);
case Ast_Kind_Call: return check_call((AstCall *) node);
- case Ast_Kind_Binary_Op: return check_binaryop((AstBinaryOp *) node, 1);
+ case Ast_Kind_Binary_Op: return check_binaryop((AstBinaryOp **) &node, 1);
default: return check_expression((AstTyped **) &node);
}
}
}
symres_expression(&(*unaryop)->expr);
+
+ if ((*unaryop)->type_node == NULL)
+ (*unaryop)->type_node = ((AstUnaryOp *)(*unaryop))->expr->type_node;
}
static void symres_expression(AstTyped** expr) {
case Ast_Kind_Binary_Op:
symres_expression(&((AstBinaryOp *)(*expr))->left);
symres_expression(&((AstBinaryOp *)(*expr))->right);
+
+ (*expr)->type_node = ((AstBinaryOp *)(*expr))->left->type_node;
break;
case Ast_Kind_Unary_Op: symres_unaryop((AstUnaryOp **) expr); break;
if ((*memres)->initial_value != NULL) {
symres_expression(&(*memres)->initial_value);
- if (((*memres)->initial_value->flags & Ast_Flag_Comptime) == 0) {
- onyx_message_add(Msg_Type_Literal,
- (*memres)->initial_value->token->pos,
- "top level expressions must be compile time known");
- return;
- }
-
if ((*memres)->type_node == NULL)
(*memres)->type_node = (*memres)->initial_value->type_node;
return type != NULL && type->kind == Type_Kind_Basic && type->Basic.kind == Basic_Kind_Bool;
}
+b32 type_is_small_integer(Type* type) {
+ if (type->kind != Type_Kind_Basic) return 0;
+
+ return type->Basic.kind >= Basic_Kind_I8 && type->Basic.kind <= Basic_Kind_U32;
+}
+
b32 type_is_integer(Type* type) {
if (type->kind != Type_Kind_Basic) return 0;
#include "onyxlex.h"
#include "onyxastnodes.h"
#include "onyxmsgs.h"
+#include "onyxparser.h"
bh_scratch global_scratch;
bh_allocator global_scratch_allocator;
return res;
}
+#define REDUCE_BINOP_ALL(op) \
+ if (type_is_small_integer(res->type) || type_is_bool(res->type)) { \
+ res->value.i = left->value.i op right->value.i; \
+ } else if (type_is_integer(res->type)) { \
+ res->value.l = left->value.l op right->value.l; \
+ } else if (res->type->Basic.kind == Basic_Kind_F32) { \
+ res->value.f = left->value.f op right->value.f; \
+ } else if (res->type->Basic.kind == Basic_Kind_F64) { \
+ res->value.d = left->value.d op right->value.d; \
+ } \
+ break;
+
+#define REDUCE_BINOP_INT(op) \
+ if (type_is_small_integer(res->type) || type_is_bool(res->type)) { \
+ res->value.i = left->value.i op right->value.i; \
+ } else if (type_is_integer(res->type)) { \
+ res->value.l = left->value.l op right->value.l; \
+ } \
+ break;
+
+#define REDUCE_BINOP_BOOL(op) \
+ if (type_is_bool(res->type)) { \
+ res->value.i = left->value.i op right->value.i; \
+ } \
+ break;
+
+
+AstTyped* ast_reduce(bh_allocator a, AstTyped* node);
+
+AstNumLit* ast_reduce_binop(bh_allocator a, AstBinaryOp* node) {
+ AstNumLit* left = (AstNumLit *) ast_reduce(a, node->left);
+ AstNumLit* right = (AstNumLit *) ast_reduce(a, node->right);
+
+ if (left->kind != Ast_Kind_NumLit || right->kind != Ast_Kind_NumLit) {
+ node->left = (AstTyped *) left;
+ node->right = (AstTyped *) right;
+ return (AstNumLit *) node;
+ }
+
+ AstNumLit* res = onyx_ast_node_new(a, sizeof(AstNumLit), Ast_Kind_NumLit);
+ res->token = node->token;
+ res->flags |= Ast_Flag_Comptime;
+ res->type_node = node->type_node;
+ res->type = node->type;
+
+ switch (node->operation) {
+ case Binary_Op_Add: REDUCE_BINOP_ALL(+);
+ case Binary_Op_Minus: REDUCE_BINOP_ALL(-);
+ case Binary_Op_Multiply: REDUCE_BINOP_ALL(*);
+ case Binary_Op_Divide: REDUCE_BINOP_ALL(/);
+ case Binary_Op_Modulus: REDUCE_BINOP_INT(%);
+
+ case Binary_Op_Equal: REDUCE_BINOP_ALL(==);
+ case Binary_Op_Not_Equal: REDUCE_BINOP_ALL(!=);
+ case Binary_Op_Less: REDUCE_BINOP_ALL(<);
+ case Binary_Op_Less_Equal: REDUCE_BINOP_ALL(<=);
+ case Binary_Op_Greater: REDUCE_BINOP_ALL(>);
+ case Binary_Op_Greater_Equal: REDUCE_BINOP_ALL(>=);
+
+ case Binary_Op_And: REDUCE_BINOP_INT(&);
+ case Binary_Op_Or: REDUCE_BINOP_INT(|);
+ case Binary_Op_Xor: REDUCE_BINOP_INT(^);
+ case Binary_Op_Shl: REDUCE_BINOP_INT(<<);
+ case Binary_Op_Shr: REDUCE_BINOP_INT(>>);
+ case Binary_Op_Sar: REDUCE_BINOP_INT(>>);
+
+ case Binary_Op_Bool_And: REDUCE_BINOP_BOOL(&&);
+ case Binary_Op_Bool_Or: REDUCE_BINOP_BOOL(||);
+
+ default: break;
+ }
+
+ return res;
+}
+#define REDUCE_UNOP(op) \
+ if (type_is_small_integer(unop->type) || type_is_bool(unop->type)) { \
+ res->value.i = op ((AstNumLit *) unop->expr)->value.i; \
+ } else if (type_is_integer(unop->type)) { \
+ res->value.l = op ((AstNumLit *) unop->expr)->value.l; \
+ } else if (unop->type->Basic.kind == Basic_Kind_F32) { \
+ res->value.f = op ((AstNumLit *) unop->expr)->value.f; \
+ } else if (unop->type->Basic.kind == Basic_Kind_F64) { \
+ res->value.d = op ((AstNumLit *) unop->expr)->value.d; \
+ } \
+ break;
+
+AstTyped* ast_reduce_unaryop(bh_allocator a, AstUnaryOp* unop) {
+ unop->expr = ast_reduce(a, unop->expr);
+
+ if (unop->expr->kind != Ast_Kind_NumLit) {
+ return (AstTyped *) unop;
+ }
+ AstNumLit* res = onyx_ast_node_new(a, sizeof(AstNumLit), Ast_Kind_NumLit);
+ res->token = unop->token;
+ res->flags |= Ast_Flag_Comptime;
+ res->type_node = unop->type_node;
+ res->type = unop->type;
+
+ switch (unop->operation) {
+ case Unary_Op_Negate: REDUCE_UNOP(-);
+ case Unary_Op_Not: {
+ if (type_is_bool(res->type)) res->value.i = ! ((AstNumLit *) unop->expr)->value.i;
+ break;
+ }
+ default: return (AstTyped *) unop;
+ }
+
+ return (AstTyped *) res;
+}
+
+AstTyped* ast_reduce(bh_allocator a, AstTyped* node) {
+ assert(node->flags & Ast_Flag_Comptime);
+
+ switch (node->kind) {
+ case Ast_Kind_Binary_Op: return (AstTyped *) ast_reduce_binop(a, (AstBinaryOp *) node);
+ case Ast_Kind_Unary_Op: return (AstTyped *) ast_reduce_unaryop(a, (AstUnaryOp *) node);
+ case Ast_Kind_NumLit: return node;
+ default: return NULL;
+ }
+}
void promote_numlit_to_larger(AstNumLit* num) {
assert(num->type != NULL);