diff --git a/new_types.kl b/new_types.kl index dc5b981..fb0f549 100644 --- a/new_types.kl +++ b/new_types.kl @@ -12,6 +12,11 @@ unary_test :: () // var := -true // var := +true +binary_test :: () + int_val :: 1000 + add :: int_val + 10 + 2.242 + + basic_type_assignment :: () custom_data: Custom_Data diff --git a/typecheck.cpp b/typecheck.cpp index 67b0328..eb62c9f 100644 --- a/typecheck.cpp +++ b/typecheck.cpp @@ -1,7 +1,8 @@ #define CASE(kind,type) case AST_##kind: { Ast_##type *node = (Ast_##type *)ast; #define BREAK() } break - - +//----------------------------------------------------------------------------- +// Evaluating constant expressions +//----------------------------------------------------------------------------- #define CASE_CONVERT(pos, int_val, kind_val, new_val, TYPE, min, max) \ case TYPE:{ \ if(int_val > max) parsing_error(pos, "Overflow when converting from %s constant to %s, value out of range: %d, max is: %d", type_names[kind_val], type_names[TYPE], int_val, max); \ @@ -10,13 +11,14 @@ }break; function Value -from_untyped_to_typed(Token *pos, Value a, Ast_Resolved_Type *new_type){ +convert_untyped(Token *pos, Value a, Ast_Resolved_Type *new_type){ assert(is_untyped(a.type)); assert(new_type); if(is_int(a.type) && is_int(new_type)){ assert(a.type == untyped_int); switch(new_type->kind){ + case TYPE_UNTYPED_INT: break; CASE_CONVERT(pos, a.int_val, a.type->kind, a.s64_val, TYPE_INT, TYPE_INT_MIN, TYPE_INT_MAX) CASE_CONVERT(pos, a.int_val, a.type->kind, a.u64_val, TYPE_UINT, TYPE_UINT_MIN, TYPE_INT_MAX) CASE_CONVERT(pos, a.int_val, a.type->kind, a.s8_val , TYPE_S8 , S8MIN, S8MAX) @@ -53,15 +55,112 @@ from_untyped_to_typed(Token *pos, Value a, Ast_Resolved_Type *new_type){ return a; } +function S64 +value_get_int(Value value){ + assert(is_float(value.type) || is_int(value.type)); + S64 result = 0; + switch(value.type->kind){ + case TYPE_UNTYPED_FLOAT: result = (S64)value.f64_val; break; + case TYPE_F64: result = (S64)value.f64_val; break; + case TYPE_F32: result = (S64)value.f32_val; break; + case TYPE_UNTYPED_INT: result = value.int_val; break; + case TYPE_INT: result = value.s64_val; break; + case TYPE_S64:result = value.s64_val; break; + case TYPE_S32:result = value.s32_val; break; + case TYPE_S16:result = value.s16_val; break; + case TYPE_S8:result = value.s8_val; break; + case TYPE_U64:result = value.u64_val; break;// @todo Need big int + case TYPE_U32:result = value.u32_val; break; + case TYPE_U16:result = value.u16_val; break; + case TYPE_U8:result = value.u8_val; break; + case TYPE_UINT:result = value.u64_val; break; + default: invalid_codepath; + } + return result; +} + +function F64 +value_get_float(Value value){ + assert(is_float(value.type) || is_int(value.type)); + F64 result = value.f64_val; + if(is_int(value.type)) + result = (F64)value_get_int(value); + else if(value.type == type_f32) + result = value.f32_val; + return result; +} + +#include +function Value +eval_binary(Token *pos, Token_Kind op, Value a, Value b){ + if(!(is_numeric(a.type) && is_numeric(b.type))) parsing_error(pos, "Constant application of binary %s on values of type %s is not allowed", token_kind_string(op).str, docname(a.type)); + + S64 left_int = value_get_int(a); + S64 right_int = value_get_int(b); + F64 left_float = value_get_float(a); + F64 right_float = value_get_float(b); + + switch(op){ + case TK_Add: { + left_int = left_int + right_int; + left_float = left_float + right_float; + } break; + case TK_Sub: { + left_int = left_int - right_int; + left_float = left_float - right_float; + } break; + case TK_Mul: { + left_int = left_int * right_int; + left_float = left_float * right_float; + } break; + case TK_Div: { + left_int = left_int / right_int; + left_float = left_float / right_float; + } break; + case TK_Mod: { + left_int = left_int % right_int; + left_float = fmod(left_float, right_float); + } break; + invalid_default_case; + } + + Ast_Resolved_Type *final_type = 0; + Value before_conversion; + if(is_int(a.type) && is_int(b.type)) { + before_conversion.type = untyped_int; + before_conversion.int_val = left_int; + final_type = untyped_int; + } + else{ + before_conversion.type = untyped_float; + before_conversion.f64_val = left_float; + final_type = untyped_float; + } + + if(is_typed(a.type) && is_typed(b.type)){ + if(a.type != b.type) parsing_error(pos, "Type mismatch in binary operation %s - left: %s right: %s", token_kind_string(op).str, docname(a.type), docname(b.type)); + else final_type = a.type; + } + + else if(is_typed(a.type) || is_typed(b.type)){ + not_implemented; + } + + Value result = convert_untyped(pos, before_conversion, final_type); + return result; +} + function Value eval_unary(Token *pos, Token_Kind op, Value v){ switch(op){ case TK_Sub:{ switch(v.type->kind){ + // @todo: Bounds checking for conversion from negative to positive + // it's, positive is 2147483647 negative is -2147483648 case TYPE_UNTYPED_INT: v.int_val = -v.int_val;break; case TYPE_UNTYPED_FLOAT: v.f64_val = -v.f64_val;break; - case TYPE_INT: v.int_val = -v.int_val;break; - case TYPE_S64: v.s64_val = -v.s64_val;break; // @todo Check bounds + case TYPE_INT: v.s64_val = -v.int_val;break; + case TYPE_S64: v.s64_val = -v.s64_val;break; case TYPE_S32: v.s32_val = -v.s32_val;break; case TYPE_S16: v.s16_val = -v.s16_val;break; case TYPE_S8: v.s8_val = -v.s8_val; break; @@ -79,11 +178,11 @@ eval_unary(Token *pos, Token_Kind op, Value v){ switch(v.type->kind){ case TYPE_UNTYPED_INT: v.int_val = +v.int_val;break; case TYPE_UNTYPED_FLOAT: v.f64_val = +v.f64_val;break; - case TYPE_INT: v.int_val = +v.int_val;break; - case TYPE_S64: v.int_val = +v.int_val;break; // @todo Check bounds - case TYPE_S32: v.int_val = +v.int_val;break; - case TYPE_S16: v.int_val = +v.int_val;break; - case TYPE_S8: v.int_val = +v.int_val;break; + case TYPE_INT: v.s64_val = +v.int_val;break; + case TYPE_S64: v.s64_val = +v.int_val;break; + case TYPE_S32: v.s32_val = +v.int_val;break; + case TYPE_S16: v.s16_val = +v.int_val;break; + case TYPE_S8: v.s8_val = +v.int_val;break; case TYPE_F32: v.f32_val = +v.f32_val;break; case TYPE_F64: v.f64_val = +v.f64_val;break; case TYPE_U64: v.u64_val = +v.u64_val;break; @@ -100,6 +199,21 @@ eval_unary(Token *pos, Token_Kind op, Value v){ return v; } +#define rewrite_into_const(ast,T,s) _rewrite_into_const(ast,sizeof(T),s) +function void +_rewrite_into_const(Ast *node, U64 ast_size, Value value){ + auto ast = (Ast_Atom *)node; + assert(ast_size >= sizeof(Ast_Atom)); + ast->flags = set_flag(ast->flags, AST_ATOM); + ast->kind = AST_VALUE; + ast->value = value; +} + +function void +_rewrite_into_const(Ast *node, U64 ast_size, Sym *sym){ + _rewrite_into_const(node, ast_size, sym->value); +} + function Ast_Resolved_Type * resolve_typespec(Ast_Expr *ast, B32 ast_can_be_null){ if(ast_can_be_null && ast == 0) return 0; @@ -207,21 +321,6 @@ require_const_int(Ast_Expr *expr, B32 ast_can_be_null){ return op; } -#define rewrite_into_const(ast,T,s) _rewrite_into_const(ast,sizeof(T),s) -function void -_rewrite_into_const(Ast *node, U64 ast_size, Value value){ - auto ast = (Ast_Atom *)node; - assert(ast_size >= sizeof(Ast_Atom)); - ast->flags = set_flag(ast->flags, AST_ATOM); - ast->kind = AST_VALUE; - ast->value = value; -} - -function void -_rewrite_into_const(Ast *node, U64 ast_size, Sym *sym){ - _rewrite_into_const(node, ast_size, sym->value); -} - function Operand resolve_lambda(Ast_Lambda *lambda, Sym *sym = 0){ @@ -275,7 +374,7 @@ resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *expected_type, Sym *lambda_to_res switch(ast->kind){ CASE(VALUE, Atom){ - return operand_rvalue(node->value); + return operand_const_rvalue(node->value); BREAK(); } CASE(IDENT, Atom){ @@ -480,16 +579,18 @@ resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *expected_type, Sym *lambda_to_res if(!is_numeric(op.type)) parsing_error(node->pos, "Unary [-] cant be applied to value of type %s", docname(op.type)); if(op.is_const){ rewrite_into_const(node, Ast_Unary, eval_unary(node->pos, node->op, op.value)); + return operand_const_rvalue(op.value); } - return op; + return operand_rvalue(op.value.type); }break; case TK_Add:{ Operand op = resolve_expr(node->expr); if(!is_numeric(op.type)) parsing_error(node->pos, "Unary [+] cant be applied to value of type %s", docname(op.type)); if(op.is_const){ rewrite_into_const(node, Ast_Unary, eval_unary(node->pos, node->op, op.value)); + return operand_const_rvalue(op.value); } - return op; + return operand_rvalue(op.type); }break; invalid_default_case; return {}; } @@ -604,8 +705,8 @@ resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *expected_type, Sym *lambda_to_res else if(token_is_compare(node->op)){ Operand left = resolve_expr(node->left); Operand right = resolve_expr(node->right); - result = resolve_operand_pair(node->pos, left, right); - if(result.is_const){ + + if(left.is_const && right.is_const){ if(result.type == type_int){ switch(node->op){ case TK_GreaterThen : result.bool_val = left.int_val > right.int_val; break; @@ -619,6 +720,12 @@ resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *expected_type, Sym *lambda_to_res } else parsing_error(node->pos, "Arithmetic on type [%s] is not supported", type_names[result.type->kind]); } + else if(left.type != right.type) { + parsing_error(node->pos, "Type mismatch in binary operation %s - left: %s right: %s", token_kind_string(node->op).str, docname(left.type), docname(right.type)); + } + else{ + result = operand_rvalue(left.type); + } } //----------------------------------------------------------------------------- @@ -627,18 +734,16 @@ resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *expected_type, Sym *lambda_to_res else{ Operand left = resolve_expr(node->left); Operand right = resolve_expr(node->right); - result = resolve_operand_pair(node->pos, left, right); - if(result.is_const){ - if(result.type == type_int){ - switch(node->op){ - case TK_Add: result.int_val = left.int_val + right.int_val; break; - case TK_Sub: result.int_val = left.int_val - right.int_val; break; - case TK_Mul: result.int_val = left.int_val * right.int_val; break; - case TK_Div: result.int_val = left.int_val / right.int_val; break; - invalid_default_case; - } - } - else parsing_error(node->pos, "Arithmetic on type [%s] is not supported", type_names[result.type->kind]); + if(left.is_const && right.is_const){ + Value value = eval_binary(node->pos, node->op, left.value, right.value); + rewrite_into_const(node, Ast_Binary, value); + result = operand_const_rvalue(value); + } + else if(left.type != right.type){ + parsing_error(node->pos, "Type mismatch in binary operation %s - left: %s right: %s", token_kind_string(node->op).str, docname(left.type), docname(right.type)); + } + else{ + result = operand_rvalue(left.type); } } //----------------------------------------------------------------------------- @@ -700,13 +805,13 @@ resolve_binding(Ast *ast, Sym *sym){ CASE(VAR, Var){ Ast_Resolved_Type *type = resolve_typespec(node->typespec, AST_CAN_BE_NULL); Operand expr = resolve_expr(node->expr, type); + assert(expr.type != 0 || type != 0); if(!type) expr.type = if_untyped_get_default_conversion(expr.type); else if(!expr.type) expr.type = type; else if(type == expr.type); - else if(is_untyped(expr.type)){ - expr.value = from_untyped_to_typed(node->pos, expr.value, type); - } + else if(is_untyped(expr.type)) expr.value = convert_untyped(node->pos, expr.value, type); + else invalid_codepath; type_complete(expr.type); return expr; diff --git a/typecheck.h b/typecheck.h index bdcfffb..91eb657 100644 --- a/typecheck.h +++ b/typecheck.h @@ -233,7 +233,7 @@ operand_lambda(Ast_Resolved_Type *type){ } function Operand -operand_rvalue(Value value){ +operand_const_rvalue(Value value){ Operand result = {}; result.is_const = true; result.value = value;