From ab3e064c6f90ec94daad99b5a4c56e0abbcc79bb Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Sat, 9 Apr 2022 08:22:31 -0300 Subject: Add more type rules and numeric type coercion --- src/errors.c | 2 + src/errors.h | 2 + src/parser.c | 183 ++++++++++++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 167 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/errors.c b/src/errors.c index b987b34..3974281 100644 --- a/src/errors.c +++ b/src/errors.c @@ -22,6 +22,8 @@ static const char* error_msgs[] = { [ERR_WRONG_RET_TYPE] = "error: return type don't match type signature", [ERR_WRONG_COND_TYPE] = "error: conditional expression is not boolean", [ERR_WRONG_TYPE_T_F] = "error: unmatched types between true and false expression", + [ERR_WRONG_TYPE_NUM] = "error: non numeric argument types", + [ERR_WRONG_TYPE_BOOL] = "error: non bool argument types", }; static Error current_error = {.value = ERR_OK}; diff --git a/src/errors.h b/src/errors.h index a84305b..3c85307 100644 --- a/src/errors.h +++ b/src/errors.h @@ -30,6 +30,8 @@ typedef enum ErrorValue { ERR_WRONG_RET_TYPE, ERR_WRONG_COND_TYPE, ERR_WRONG_TYPE_T_F, + ERR_WRONG_TYPE_NUM, + ERR_WRONG_TYPE_BOOL, ERR_OK, } ErrorValue; diff --git a/src/parser.c b/src/parser.c index ddcee56..252ceaa 100644 --- a/src/parser.c +++ b/src/parser.c @@ -684,6 +684,107 @@ symbol_check(Parser *parser, Node *node) { return true; } +Type * +coerce_numeric_types(Type *a, Type *b) { + if (a == &default_types[TYPE_U8]) { + if (b == &default_types[TYPE_U16] || + b == &default_types[TYPE_U32] || + b == &default_types[TYPE_U64] || + b == &default_types[TYPE_S8] || + b == &default_types[TYPE_S16] || + b == &default_types[TYPE_S32] || + b == &default_types[TYPE_S64] || + b == &default_types[TYPE_F32] || + b == &default_types[TYPE_F64]) { + return b; + } + } else if (a == &default_types[TYPE_U16]) { + if (b == &default_types[TYPE_U32] || + b == &default_types[TYPE_S16] || + b == &default_types[TYPE_S32] || + b == &default_types[TYPE_S64] || + b == &default_types[TYPE_U64] || + b == &default_types[TYPE_F32] || + b == &default_types[TYPE_F64]) { + return b; + } + if (b == &default_types[TYPE_S8]) { + return &default_types[TYPE_S16]; + } + } else if (a == &default_types[TYPE_U32]) { + if (b == &default_types[TYPE_U64] || + b == &default_types[TYPE_S32] || + b == &default_types[TYPE_S64] || + b == &default_types[TYPE_F32] || + b == &default_types[TYPE_F64]) { + return b; + } + if (b == &default_types[TYPE_S8] || + b == &default_types[TYPE_S16]) { + return &default_types[TYPE_S32]; + } + } else if (a == &default_types[TYPE_U64]) { + if (b == &default_types[TYPE_S64] || + b == &default_types[TYPE_F32] || + b == &default_types[TYPE_F64]) { + return b; + } + if (b == &default_types[TYPE_S8] || + b == &default_types[TYPE_S16] || + b == &default_types[TYPE_S32]) { + return &default_types[TYPE_S64]; + } + } else if (a == &default_types[TYPE_S8]) { + if (b == &default_types[TYPE_S16] || + b == &default_types[TYPE_S32] || + b == &default_types[TYPE_S64] || + b == &default_types[TYPE_F32] || + b == &default_types[TYPE_F64]) { + return b; + } + } else if (a == &default_types[TYPE_S16]) { + if (b == &default_types[TYPE_S32] || + b == &default_types[TYPE_S64] || + b == &default_types[TYPE_F32] || + b == &default_types[TYPE_F64]) { + return b; + } + } else if (a == &default_types[TYPE_S32]) { + if (b == &default_types[TYPE_S64] || + b == &default_types[TYPE_F32] || + b == &default_types[TYPE_F64]) { + return b; + } + } else if (a == &default_types[TYPE_S64]) { + if (b == &default_types[TYPE_F32] || + b == &default_types[TYPE_F64]) { + return b; + } + } else if (a == &default_types[TYPE_F32]) { + if (b == &default_types[TYPE_F64]) { + return b; + } + } + return a; +} + +bool +type_is_numeric(Type *t) { + if (t == &default_types[TYPE_U8] || + t == &default_types[TYPE_U16] || + t == &default_types[TYPE_U32] || + t == &default_types[TYPE_U64] || + t == &default_types[TYPE_S8] || + t == &default_types[TYPE_S16] || + t == &default_types[TYPE_S32] || + t == &default_types[TYPE_S64] || + t == &default_types[TYPE_F32] || + t == &default_types[TYPE_F64]) { + return true; + } + return false; +} + bool resolve_type(Parser *parser, Node *node) { if (node->expr_type != NULL) { @@ -696,6 +797,10 @@ resolve_type(Parser *parser, Node *node) { } switch (node->type) { case NODE_BUILTIN: { + for (size_t i = 0; i < array_size(node->builtin.args); ++i) { + Node *arg = node->builtin.args[i]; + resolve_type(parser, arg); + } switch (node->builtin.type) { // Numbers. case TOKEN_ADD: @@ -703,35 +808,67 @@ resolve_type(Parser *parser, Node *node) { case TOKEN_MUL: case TOKEN_DIV: case TOKEN_MOD: { - // TODO: Properly resolve this - node->expr_type = &default_types[TYPE_U64]; + Type *type = NULL; + for (size_t i = 0; i < array_size(node->builtin.args); ++i) { + Node *arg = node->builtin.args[i]; + + // Check that all arguments are nums. + if (!type_is_numeric(arg->expr_type)) { + push_error(ERR_TYPE_PARSER, ERR_WRONG_TYPE_NUM, + arg->line, arg->col); + return false; + } + + if (type == NULL) { + type = arg->expr_type; + } else if (type != arg->expr_type) { + type = coerce_numeric_types(type, arg->expr_type); + } + } + node->expr_type = type; } break; // Bools. case TOKEN_NOT: case TOKEN_AND: - case TOKEN_OR: + case TOKEN_OR: { + // Check that all arguments are boolean. + for (size_t i = 0; i < array_size(node->builtin.args); ++i) { + Node *arg = node->builtin.args[i]; + if (arg->expr_type != &default_types[TYPE_BOOL]) { + push_error(ERR_TYPE_PARSER, ERR_WRONG_TYPE_BOOL, + arg->line, arg->col); + return false; + } + } + node->expr_type = &default_types[TYPE_BOOL]; + } break; case TOKEN_EQ: case TOKEN_LT: case TOKEN_GT: case TOKEN_LE: case TOKEN_GE: { + // Check that all arguments are nums. + for (size_t i = 0; i < array_size(node->builtin.args); ++i) { + Node *arg = node->builtin.args[i]; + if (!type_is_numeric(arg->expr_type)) { + push_error(ERR_TYPE_PARSER, ERR_WRONG_TYPE_NUM, + arg->line, arg->col); + return false; + } + } node->expr_type = &default_types[TYPE_BOOL]; } break; default: break; } - for (size_t i = 0; i < array_size(node->builtin.args); ++i) { - Node *arg = node->builtin.args[i]; - resolve_type(parser, arg); - } } break; case NODE_SYMBOL: { node->expr_type = find_symbol(parser, node); } break; case NODE_FUN: { resolve_type(parser, node->fun.body); + // Check that the type of body matches the return type. StringView *type_body = &node->fun.body->expr_type->name; StringView *return_type = &node->fun.return_type->string; - // Check that the type of body matches the return type. if (!sv_equal(type_body, return_type)) { push_error(ERR_TYPE_PARSER, ERR_WRONG_RET_TYPE, node->line, node->col); return false; @@ -747,22 +884,32 @@ resolve_type(Parser *parser, Node *node) { } break; case NODE_IF: { resolve_type(parser, node->ifexpr.cond); + resolve_type(parser, node->ifexpr.expr_true); + Type *type_true = node->ifexpr.expr_true->expr_type; + node->expr_type = type_true; + if (node->ifexpr.expr_false != NULL) { + resolve_type(parser, node->ifexpr.expr_false); + } + // Check ifexpr.cond is a bool. - if (!sv_equal(&node->ifexpr.cond->expr_type->name, &default_types[TYPE_BOOL].name)) { - push_error(ERR_TYPE_PARSER, ERR_WRONG_COND_TYPE, node->line, node->col); + Type *type_cond = node->ifexpr.cond->expr_type; + if (!sv_equal(&type_cond->name, &default_types[TYPE_BOOL].name)) { + push_error(ERR_TYPE_PARSER, ERR_WRONG_COND_TYPE, + node->line, node->col); return false; } - resolve_type(parser, node->ifexpr.expr_true); + // Check if types of expr_true and expr_false match if (node->ifexpr.expr_false != NULL) { - resolve_type(parser, node->ifexpr.expr_false); - // Check if types of expr_true and expr_false match - if (!sv_equal(&node->ifexpr.expr_true->expr_type->name, &node->ifexpr.expr_false->expr_type->name)) { - push_error(ERR_TYPE_PARSER, ERR_WRONG_TYPE_T_F, node->line, node->col); + Type *type_false = node->ifexpr.expr_false->expr_type; + if (type_is_numeric(type_true) && type_is_numeric(type_false)) { + node->expr_type = coerce_numeric_types(type_true, type_false); + } else if (!sv_equal(&type_true->name, &type_false->name)) { + push_error(ERR_TYPE_PARSER, ERR_WRONG_TYPE_T_F, + node->line, node->col); return false; } } - node->expr_type = node->ifexpr.expr_true->expr_type; } break; case NODE_SET: { node->expr_type = &default_types[TYPE_VOID]; @@ -773,10 +920,6 @@ resolve_type(Parser *parser, Node *node) { resolve_type(parser, node->def.value); } break; case NODE_NUMBER: { - // TODO: Is this the best way of doing it? We probably need a more - // sophisticated way of approaching this. For example: - // `(if (< 1 2) 1 -2)` will currently fail with this approach, since - // 1:u64 and -2:s64 if (node->number.fractional != 0) { node->expr_type = &default_types[TYPE_F64]; } else if (node->number.negative) { -- cgit v1.2.1