diff --git a/typecheck.cpp b/typecheck.cpp index a827014..f1b1c99 100644 --- a/typecheck.cpp +++ b/typecheck.cpp @@ -31,37 +31,6 @@ type_error(Token *token, Ast_Resolved_Type *expected, Ast_Resolved_Type *actual, //----------------------------------------------------------------------------- // Evaluating constant expressions //----------------------------------------------------------------------------- -function Value -convert_untyped(Token *pos, Value a, Ast_Resolved_Type *new_type){ - // assert(a.type); - assert(new_type); - if(a.type == 0) return a; - if(is_typed(a.type)) return a; - - if(is_int(a.type) && is_int(new_type)){ - assert(a.type == untyped_int); - if(!bigint_fits_in_bits(&a.big_int_val, new_type->size*8, is_signed_int(new_type))){ - parsing_error(pos, "Doesn't fit"); - } - } - - else if(is_int(a.type) && is_float(new_type)){ - a.f64_val = bigint_as_float(&a.big_int_val); // @leak bigint - } - else if(is_float(a.type) && is_float(new_type)){ - // nothing to do - } - else if(is_bool(a.type) && is_bool(new_type)) - ; // nothing to do - else if(is_string(a.type) && is_string(new_type)) - ; // nothing to do - else parsing_error(pos, "Type mismatch when converting from %s to %s", docname(a.type), docname(new_type)); - - a.type = new_type; - return a; -} - - function Value value_bool(B32 v){ Value value; @@ -102,14 +71,41 @@ value_float(BigInt a){ return value; } +function Value +convert_untyped(Token *pos, Value a, Ast_Resolved_Type *new_type){ + assert(new_type); + if(a.type == 0) return a; + if(is_typed(a.type)) return a; + + if(is_int(a.type) && is_int(new_type)){ + assert(a.type == untyped_int); + if(!bigint_fits_in_bits(&a.big_int_val, new_type->size*8, is_signed_int(new_type))){ + Scratch scratch; + const char *string = bigint_to_error_string(scratch, &a.big_int_val, 10); + parsing_error(pos, "Value %s doesn't fit in type %s", string, docname(new_type)); + } + } + + else if(is_int(a.type) && is_float(new_type)) + a.f64_val = bigint_as_float(&a.big_int_val); // @leak bigint + else if(is_float(a.type) && is_float(new_type)) + ; // nothing to do + else if(is_bool(a.type) && is_bool(new_type)) + ; // nothing to do + else if(is_string(a.type) && is_string(new_type)) + ; // nothing to do + else parsing_error(pos, "Type mismatch when converting from %s to %s", docname(a.type), docname(new_type)); + + a.type = new_type; + return a; +} + function void match_values(Value *a, Value *b){ - if(is_int(a->type) && is_float(b->type)){ + if(is_int(a->type) && is_float(b->type)) *a = value_float(a->big_int_val); - } - else if(is_float(a->type) && is_int(b->type)){ + else if(is_float(a->type) && is_int(b->type)) *b = value_float(b->big_int_val); - } } function Value @@ -119,42 +115,37 @@ compare_values(Token *pos, Token_Kind op, Value a, Value b){ B32 result = 0; switch(a.type->kind){ - case TYPE_UNTYPED_INT: - case TYPE_S8:case TYPE_S16:case TYPE_S32:case TYPE_S64: - case TYPE_U8:case TYPE_U16:case TYPE_U32:case TYPE_U64:{ + CASE_INT:{ CmpRes cmp = bigint_cmp(&a.big_int_val, &b.big_int_val); switch(op){ - case TK_LesserThenOrEqual: result = (cmp == CMP_LT) || (cmp == CMP_EQ); break; + case TK_LesserThenOrEqual: result = (cmp == CMP_LT) || (cmp == CMP_EQ); break; case TK_GreaterThenOrEqual: result = (cmp == CMP_GT) || (cmp == CMP_EQ); break; - case TK_GreaterThen: result = cmp == CMP_GT; break; - case TK_LesserThen: result = cmp == CMP_LT; break; - case TK_Equals: result = cmp == CMP_EQ; break; - case TK_NotEquals: result = cmp != CMP_EQ; break; + case TK_GreaterThen: result = cmp == CMP_GT; break; + case TK_LesserThen: result = cmp == CMP_LT; break; + case TK_Equals: result = cmp == CMP_EQ; break; + case TK_NotEquals: result = cmp != CMP_EQ; break; invalid_default_case; } }break; - case TYPE_UNTYPED_BOOL: - case TYPE_BOOL:{ + CASE_BOOL:{ switch(op){ - case TK_Equals: result = a.bool_val == b.bool_val; break; - case TK_NotEquals: result = a.bool_val != b.bool_val; break; + case TK_Equals: result = a.bool_val == b.bool_val; break; + case TK_NotEquals: result = a.bool_val != b.bool_val; break; invalid_default_case; } }break; - case TYPE_UNTYPED_FLOAT: - case TYPE_F32: case TYPE_F64:{ + CASE_FLOAT:{ switch(op){ - case TK_LesserThenOrEqual: result = a.f64_val <= b.f64_val; break; + case TK_LesserThenOrEqual: result = a.f64_val <= b.f64_val; break; case TK_GreaterThenOrEqual: result = a.f64_val >= b.f64_val; break; - case TK_GreaterThen: result = a.f64_val > b.f64_val; break; - case TK_LesserThen: result = a.f64_val < b.f64_val; break; - case TK_Equals: result = a.f64_val == b.f64_val; break; - case TK_NotEquals: result = a.f64_val != b.f64_val; break; + case TK_GreaterThen: result = a.f64_val > b.f64_val; break; + case TK_LesserThen: result = a.f64_val < b.f64_val; break; + case TK_Equals: result = a.f64_val == b.f64_val; break; + case TK_NotEquals: result = a.f64_val != b.f64_val; break; invalid_default_case; } }break; - case TYPE_UNTYPED_STRING: - case TYPE_STRING:{ + CASE_STRING:{ invalid_codepath; }break; invalid_default_case; @@ -175,9 +166,7 @@ eval_binary(Token *pos, Token_Kind op, Value a, Value b){ Value result = {}; result.type = a.type; switch(a.type->kind){ - case TYPE_UNTYPED_INT: - case TYPE_S8:case TYPE_S16:case TYPE_S32:case TYPE_S64: - case TYPE_U8:case TYPE_U16:case TYPE_U32:case TYPE_U64:{ + CASE_INT:{ switch(op){ case TK_BitXor: bigint_xor(&result.big_int_val, &a.big_int_val, &b.big_int_val); break; case TK_BitAnd: bigint_and(&result.big_int_val, &a.big_int_val, &b.big_int_val); break; @@ -192,8 +181,7 @@ eval_binary(Token *pos, Token_Kind op, Value a, Value b){ invalid_default_case; } }break; - case TYPE_UNTYPED_BOOL: - case TYPE_BOOL:{ + CASE_BOOL:{ switch(op){ case TK_And: result.bool_val = a.bool_val && b.bool_val; break; case TK_Or: result.bool_val = a.bool_val || b.bool_val; break; @@ -203,8 +191,7 @@ eval_binary(Token *pos, Token_Kind op, Value a, Value b){ invalid_default_case; } }break; - case TYPE_UNTYPED_FLOAT: - case TYPE_F32: case TYPE_F64:{ + CASE_FLOAT:{ switch(op){ case TK_Add: result.f64_val = a.f64_val + b.f64_val; break; case TK_Sub: result.f64_val = a.f64_val - b.f64_val; break; @@ -213,8 +200,7 @@ eval_binary(Token *pos, Token_Kind op, Value a, Value b){ invalid_default_case; } }break; - case TYPE_UNTYPED_STRING: - case TYPE_STRING:{ + CASE_STRING:{ invalid_codepath; }break; invalid_default_case; @@ -225,41 +211,57 @@ eval_binary(Token *pos, Token_Kind op, Value a, Value b){ function Value eval_unary(Token *pos, Token_Kind op, Value a){ - if(!is_numeric(a.type)) parsing_error(pos, "Constant application of binary %s on values of type %s is not allowed", name(op), docname(a.type)); - BigInt result = {}; switch(op){ case TK_Add:{ return a; } break; case TK_Sub:{ - if(is_int(a.type)){ - bigint_negate(&result, &a.big_int_val); - return value_int(result); - } else if(is_float(a.type)){ - return value_float(-a.f64_val); - } else invalid_codepath; - } break; - case TK_Neg:{ - if(is_int(a.type)){ - bigint_not(&result, &a.big_int_val, 64, 1); // Invalid - return value_int(result); - } else invalid_codepath; - } break; - case TK_Not:{ - if(is_int(a.type)){ - if(CMP_EQ == bigint_cmp_zero(&a.big_int_val)){ - return value_bool(1); - } else return value_bool(0); - } else if(is_float(a.type)){ - return value_bool(!a.f64_val); - } else if(is_bool(a.type)){ - a.bool_val = !a.bool_val; - return a; + switch(a.type->kind){ + CASE_INT:{ + bigint_negate(&result, &a.big_int_val); + return value_int(result); + }break; + CASE_FLOAT:{ + return value_float(-a.f64_val); + }break; + default:goto failure; } } break; - default: invalid_codepath; + case TK_Neg:{ + switch(a.type->kind){ + CASE_SINT: case TYPE_UNTYPED_INT:{ + bigint_not(&result, &a.big_int_val, a.big_int_val.digit_count*64, 1); + return value_int(result); + }break; + CASE_UINT:{ + bigint_not(&result, &a.big_int_val, a.big_int_val.digit_count*64, 0); + return value_int(result); + } + default:goto failure; + } + } break; + case TK_Not:{ + switch(a.type->kind){ + CASE_INT: { + if(CMP_EQ == bigint_cmp_zero(&a.big_int_val)) + return value_bool(1); + return value_bool(0); + }break; + CASE_FLOAT:{ + return value_bool(!a.f64_val); + }break; + CASE_BOOL:{ + a.bool_val = !a.bool_val; + return a; + }break; + default:goto failure; + } + } break; + default:goto failure; } + + failure: parsing_error(pos, "Constant application of binary %s on values of type %s is not allowed", name(op), docname(a.type)); invalid_return; } @@ -433,9 +435,11 @@ field_access_string(Ast_Expr *right){ auto a = (Ast_Atom *)right; if(a->intern_val == pctx->intern("len"_s)){ return operand_lvalue(type_s64); - } else if(a->intern_val == pctx->intern("str"_s)){ + } + else if(a->intern_val == pctx->intern("str"_s)){ return operand_lvalue(type_pointer(type_u8)); - } else invalid_return; + } + else invalid_return; } function Operand diff --git a/types.h b/types.h index 89b9acb..e4a6db7 100644 --- a/types.h +++ b/types.h @@ -46,6 +46,13 @@ enum Ast_Resolved_Type_Kind{ TYPE_LAST_NUMERIC = TYPE_BOOL, }; +#define CASE_SINT case TYPE_S8:case TYPE_S16:case TYPE_S32:case TYPE_S64 +#define CASE_UINT case TYPE_U8:case TYPE_U16:case TYPE_U32:case TYPE_U64 +#define CASE_INT case TYPE_UNTYPED_INT: CASE_SINT: CASE_UINT +#define CASE_BOOL case TYPE_UNTYPED_BOOL: case TYPE_BOOL +#define CASE_FLOAT case TYPE_UNTYPED_FLOAT: case TYPE_F32: case TYPE_F64 +#define CASE_STRING case TYPE_UNTYPED_STRING: case TYPE_STRING + const char *type_names[] = { "[Invalid Ast_Resolved_Type]", "[Completing]",