More work on typechecking and type conversions

This commit is contained in:
Krzosa Karol
2022-06-03 14:03:01 +02:00
parent 7e4b9777e6
commit e200a006a2
3 changed files with 156 additions and 46 deletions

View File

@@ -12,6 +12,11 @@ unary_test :: ()
// var := -true // var := -true
// var := +true // var := +true
binary_test :: ()
int_val :: 1000
add :: int_val + 10 + 2.242
basic_type_assignment :: () basic_type_assignment :: ()
custom_data: Custom_Data custom_data: Custom_Data

View File

@@ -1,7 +1,8 @@
#define CASE(kind,type) case AST_##kind: { Ast_##type *node = (Ast_##type *)ast; #define CASE(kind,type) case AST_##kind: { Ast_##type *node = (Ast_##type *)ast;
#define BREAK() } break #define BREAK() } break
//-----------------------------------------------------------------------------
// Evaluating constant expressions
//-----------------------------------------------------------------------------
#define CASE_CONVERT(pos, int_val, kind_val, new_val, TYPE, min, max) \ #define CASE_CONVERT(pos, int_val, kind_val, new_val, TYPE, min, max) \
case TYPE:{ \ 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); \ 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; }break;
function Value 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(is_untyped(a.type));
assert(new_type); assert(new_type);
if(is_int(a.type) && is_int(new_type)){ if(is_int(a.type) && is_int(new_type)){
assert(a.type == untyped_int); assert(a.type == untyped_int);
switch(new_type->kind){ 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.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.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) 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; 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 <math.h>
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 function Value
eval_unary(Token *pos, Token_Kind op, Value v){ eval_unary(Token *pos, Token_Kind op, Value v){
switch(op){ switch(op){
case TK_Sub:{ case TK_Sub:{
switch(v.type->kind){ 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_INT: v.int_val = -v.int_val;break;
case TYPE_UNTYPED_FLOAT: v.f64_val = -v.f64_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_INT: v.s64_val = -v.int_val;break;
case TYPE_S64: v.s64_val = -v.s64_val;break; // @todo Check bounds case TYPE_S64: v.s64_val = -v.s64_val;break;
case TYPE_S32: v.s32_val = -v.s32_val;break; case TYPE_S32: v.s32_val = -v.s32_val;break;
case TYPE_S16: v.s16_val = -v.s16_val;break; case TYPE_S16: v.s16_val = -v.s16_val;break;
case TYPE_S8: v.s8_val = -v.s8_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){ switch(v.type->kind){
case TYPE_UNTYPED_INT: v.int_val = +v.int_val;break; case TYPE_UNTYPED_INT: v.int_val = +v.int_val;break;
case TYPE_UNTYPED_FLOAT: v.f64_val = +v.f64_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_INT: v.s64_val = +v.int_val;break;
case TYPE_S64: v.int_val = +v.int_val;break; // @todo Check bounds case TYPE_S64: v.s64_val = +v.int_val;break;
case TYPE_S32: v.int_val = +v.int_val;break; case TYPE_S32: v.s32_val = +v.int_val;break;
case TYPE_S16: v.int_val = +v.int_val;break; case TYPE_S16: v.s16_val = +v.int_val;break;
case TYPE_S8: v.int_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_F32: v.f32_val = +v.f32_val;break;
case TYPE_F64: v.f64_val = +v.f64_val;break; case TYPE_F64: v.f64_val = +v.f64_val;break;
case TYPE_U64: v.u64_val = +v.u64_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; 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 * function Ast_Resolved_Type *
resolve_typespec(Ast_Expr *ast, B32 ast_can_be_null){ resolve_typespec(Ast_Expr *ast, B32 ast_can_be_null){
if(ast_can_be_null && ast == 0) return 0; 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; 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 function Operand
resolve_lambda(Ast_Lambda *lambda, Sym *sym = 0){ 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){ switch(ast->kind){
CASE(VALUE, Atom){ CASE(VALUE, Atom){
return operand_rvalue(node->value); return operand_const_rvalue(node->value);
BREAK(); BREAK();
} }
CASE(IDENT, Atom){ 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(!is_numeric(op.type)) parsing_error(node->pos, "Unary [-] cant be applied to value of type %s", docname(op.type));
if(op.is_const){ if(op.is_const){
rewrite_into_const(node, Ast_Unary, eval_unary(node->pos, node->op, op.value)); 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; }break;
case TK_Add:{ case TK_Add:{
Operand op = resolve_expr(node->expr); 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(!is_numeric(op.type)) parsing_error(node->pos, "Unary [+] cant be applied to value of type %s", docname(op.type));
if(op.is_const){ if(op.is_const){
rewrite_into_const(node, Ast_Unary, eval_unary(node->pos, node->op, op.value)); 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; }break;
invalid_default_case; return {}; 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)){ else if(token_is_compare(node->op)){
Operand left = resolve_expr(node->left); Operand left = resolve_expr(node->left);
Operand right = resolve_expr(node->right); 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){ if(result.type == type_int){
switch(node->op){ switch(node->op){
case TK_GreaterThen : result.bool_val = left.int_val > right.int_val; break; 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 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{ else{
Operand left = resolve_expr(node->left); Operand left = resolve_expr(node->left);
Operand right = resolve_expr(node->right); Operand right = resolve_expr(node->right);
result = resolve_operand_pair(node->pos, left, right); if(left.is_const && right.is_const){
if(result.is_const){ Value value = eval_binary(node->pos, node->op, left.value, right.value);
if(result.type == type_int){ rewrite_into_const(node, Ast_Binary, value);
switch(node->op){ result = operand_const_rvalue(value);
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 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 parsing_error(node->pos, "Arithmetic on type [%s] is not supported", type_names[result.type->kind]); else{
result = operand_rvalue(left.type);
} }
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@@ -700,13 +805,13 @@ resolve_binding(Ast *ast, Sym *sym){
CASE(VAR, Var){ CASE(VAR, Var){
Ast_Resolved_Type *type = resolve_typespec(node->typespec, AST_CAN_BE_NULL); Ast_Resolved_Type *type = resolve_typespec(node->typespec, AST_CAN_BE_NULL);
Operand expr = resolve_expr(node->expr, type); Operand expr = resolve_expr(node->expr, type);
assert(expr.type != 0 || type != 0);
if(!type) expr.type = if_untyped_get_default_conversion(expr.type); if(!type) expr.type = if_untyped_get_default_conversion(expr.type);
else if(!expr.type) expr.type = type; else if(!expr.type) expr.type = type;
else if(type == expr.type); else if(type == expr.type);
else if(is_untyped(expr.type)){ else if(is_untyped(expr.type)) expr.value = convert_untyped(node->pos, expr.value, type);
expr.value = from_untyped_to_typed(node->pos, expr.value, type); else invalid_codepath;
}
type_complete(expr.type); type_complete(expr.type);
return expr; return expr;

View File

@@ -233,7 +233,7 @@ operand_lambda(Ast_Resolved_Type *type){
} }
function Operand function Operand
operand_rvalue(Value value){ operand_const_rvalue(Value value){
Operand result = {}; Operand result = {};
result.is_const = true; result.is_const = true;
result.value = value; result.value = value;