Compare commits

...

1 Commits

Author SHA1 Message Date
Christoffer Lerno
3348f4dc7d Test of overloading. 2022-09-15 22:31:31 +02:00
5 changed files with 174 additions and 11 deletions

View File

@@ -636,7 +636,7 @@ typedef struct Decl_
bool obfuscate : 1; bool obfuscate : 1;
bool is_dynamic : 1; bool is_dynamic : 1;
bool is_synthetic : 1; bool is_synthetic : 1;
OperatorOverload operator : 4; OperatorOverload operator : 5;
union union
{ {
void *backend_ref; void *backend_ref;
@@ -1781,7 +1781,7 @@ extern const char *kw_max;
extern const char *kw_min; extern const char *kw_min;
extern const char *kw_elements; extern const char *kw_elements;
extern const char *kw_align; extern const char *kw_align;
extern const char *kw_add;
extern const char *kw_nameof; extern const char *kw_nameof;
extern const char *kw_names; extern const char *kw_names;
extern const char *kw_sizeof; extern const char *kw_sizeof;
@@ -1790,6 +1790,7 @@ extern const char *kw_out;
extern const char *kw_inout; extern const char *kw_inout;
extern const char *kw_deprecated; extern const char *kw_deprecated;
extern const char *kw_distinct; extern const char *kw_distinct;
extern const char *kw_div;
extern const char *kw_intvec; extern const char *kw_intvec;
extern const char *kw_floatvec; extern const char *kw_floatvec;
extern const char *kw_inline; extern const char *kw_inline;
@@ -1800,17 +1801,21 @@ extern const char *kw_elementat;
extern const char *kw_elementref; extern const char *kw_elementref;
extern const char *kw_elementset; extern const char *kw_elementset;
extern const char *kw_len; extern const char *kw_len;
extern const char *kw_nan;
extern const char *kw_noinline;
extern const char *kw_main; extern const char *kw_main;
extern const char *kw_max; extern const char *kw_max;
extern const char *kw_min; extern const char *kw_min;
extern const char *kw_mult;
extern const char *kw_nan;
extern const char *kw_neg;
extern const char *kw_noinline;
extern const char *kw_ordinal; extern const char *kw_ordinal;
extern const char *kw_pure; extern const char *kw_pure;
extern const char *kw_ptr; extern const char *kw_ptr;
extern const char *kw_values; extern const char *kw_rem;
extern const char *kw_return; extern const char *kw_return;
extern const char *kw_sub;
extern const char *kw_type; extern const char *kw_type;
extern const char *kw_values;
extern const char *kw_FILE; extern const char *kw_FILE;
extern const char *kw_FUNC; extern const char *kw_FUNC;
extern const char *kw_LINE; extern const char *kw_LINE;

View File

@@ -722,6 +722,12 @@ typedef enum
OVERLOAD_ELEMENT_REF, OVERLOAD_ELEMENT_REF,
OVERLOAD_ELEMENT_SET, OVERLOAD_ELEMENT_SET,
OVERLOAD_LEN, OVERLOAD_LEN,
OVERLOAD_ADD,
OVERLOAD_SUB,
OVERLOAD_MULT,
OVERLOAD_DIV,
OVERLOAD_REM,
OVERLOAD_NEG,
} OperatorOverload; } OperatorOverload;
typedef enum typedef enum

View File

@@ -1274,6 +1274,34 @@ static inline bool sema_analyse_operator_len(Decl *method)
return true; return true;
} }
static inline bool sema_analyse_operator_binary_arithmetics(Decl *method)
{
TypeInfo *rtype;
Signature *signature = &method->func_decl.signature;
Decl **params = signature->params;
uint32_t param_count = vec_size(params);
if (param_count != 2)
{
SEMA_ERROR(method, "Expected two elements for this operation.");
return false;
}
return true;
}
static inline bool sema_analyse_operator_unary_arithmetics(Decl *method)
{
TypeInfo *rtype;
Signature *signature = &method->func_decl.signature;
Decl **params = signature->params;
uint32_t param_count = vec_size(params);
if (param_count != 1)
{
SEMA_ERROR(method, "Too many parameters for this operation.");
return false;
}
return true;
}
static bool sema_check_operator_method_validity(Decl *method) static bool sema_check_operator_method_validity(Decl *method)
{ {
switch (method->operator) switch (method->operator)
@@ -1285,6 +1313,14 @@ static bool sema_check_operator_method_validity(Decl *method)
return sema_analyse_operator_element_at(method); return sema_analyse_operator_element_at(method);
case OVERLOAD_LEN: case OVERLOAD_LEN:
return sema_analyse_operator_len(method); return sema_analyse_operator_len(method);
case OVERLOAD_ADD:
case OVERLOAD_DIV:
case OVERLOAD_MULT:
case OVERLOAD_REM:
case OVERLOAD_SUB:
return sema_analyse_operator_binary_arithmetics(method);
case OVERLOAD_NEG:
return sema_analyse_operator_unary_arithmetics(method);
} }
UNREACHABLE UNREACHABLE
} }
@@ -1402,6 +1438,21 @@ static const char *attribute_domain_to_string(AttributeDomain domain)
UNREACHABLE UNREACHABLE
} }
INLINE bool check_operator_overload(Expr *expr, Decl *decl, const char *kw)
{
if (decl->decl_kind != DECL_MACRO)
{
SEMA_ERROR(expr, "@operator(%s) can only be used with macros.", kw);
return false;
}
if (!decl->func_decl.type_parent)
{
SEMA_ERROR(expr, "@operator(%s) can only be used with method-like macros.", kw);
return false;
}
return true;
}
static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr, AttributeDomain domain) static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr, AttributeDomain domain)
{ {
AttributeType type = attr->attr_kind; AttributeType type = attr->attr_kind;
@@ -1538,6 +1589,36 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
} }
decl->operator = OVERLOAD_LEN; decl->operator = OVERLOAD_LEN;
} }
else if (kw == kw_add)
{
if (!check_operator_overload(expr, decl, kw)) return false;
decl->operator = OVERLOAD_ADD;
}
else if (kw == kw_sub)
{
if (!check_operator_overload(expr, decl, kw)) return false;
decl->operator = OVERLOAD_SUB;
}
else if (kw == kw_mult)
{
if (!check_operator_overload(expr, decl, kw)) return false;
decl->operator = OVERLOAD_MULT;
}
else if (kw == kw_div)
{
if (!check_operator_overload(expr, decl, kw)) return false;
decl->operator = OVERLOAD_DIV;
}
else if (kw == kw_rem)
{
if (!check_operator_overload(expr, decl, kw)) return false;
decl->operator = OVERLOAD_REM;
}
else if (kw == kw_neg)
{
if (!check_operator_overload(expr, decl, kw)) return false;
decl->operator = OVERLOAD_NEG;
}
else if (kw == kw_floatvec) else if (kw == kw_floatvec)
{ {
if (decl->decl_kind != DECL_MACRO) if (decl->decl_kind != DECL_MACRO)

View File

@@ -838,6 +838,31 @@ bool sema_expr_check_assign(SemaContext *c, Expr *expr)
return false; return false;
} }
static Decl *sema_type_get_overload_method(Type *a, OperatorOverload overload)
{
if (!overload) return NULL;
assert(a->canonical == a);
if (!type_may_have_sub_elements(a))
{
return NULL;
}
FOREACH_BEGIN(Decl *method, a->decl->methods)
if (method->operator == overload) return method;
FOREACH_END();
return NULL;
}
INLINE bool sema_rewrite_analyze_overload(SemaContext *context, Expr *expr, Decl *decl, Expr *left, Expr *right)
{
expr->expr_kind = EXPR_CALL;
Expr **args = VECNEW(Expr*, 2);
vec_add(args, right);
expr->call_expr = (ExprCall){ .arguments = args, .func_ref = declid(decl) };
return sema_expr_analyse_general_call(context, expr, decl, left, false);
}
static inline bool sema_cast_ident_rvalue(SemaContext *context, Expr *expr) static inline bool sema_cast_ident_rvalue(SemaContext *context, Expr *expr)
{ {
Decl *decl = expr->identifier_expr.decl; Decl *decl = expr->identifier_expr.decl;
@@ -1325,7 +1350,7 @@ static inline bool sema_expr_analyse_binary_subexpr(SemaContext *context, Expr *
return (int)sema_analyse_expr(context, left) & (int)sema_analyse_expr(context, right); return (int)sema_analyse_expr(context, left) & (int)sema_analyse_expr(context, right);
} }
static inline bool sema_expr_analyse_binary_arithmetic_subexpr(SemaContext *context, Expr *expr, const char *error, bool bool_is_allowed) static inline bool sema_expr_analyse_binary_arithmetic_subexpr(SemaContext *context, Expr *expr, const char *error, bool bool_is_allowed, OperatorOverload *overload)
{ {
Expr *left = exprptr(expr->binary_expr.left); Expr *left = exprptr(expr->binary_expr.left);
Expr *right = exprptr(expr->binary_expr.right); Expr *right = exprptr(expr->binary_expr.right);
@@ -1338,6 +1363,14 @@ static inline bool sema_expr_analyse_binary_arithmetic_subexpr(SemaContext *cont
Type *left_type = type_no_optional(left->type)->canonical; Type *left_type = type_no_optional(left->type)->canonical;
Type *right_type = type_no_optional(right->type)->canonical; Type *right_type = type_no_optional(right->type)->canonical;
Decl *possible_overload = sema_type_get_overload_method(left_type, *overload);
if (possible_overload)
{
if (!sema_rewrite_analyze_overload(context, expr, possible_overload, left, right)) return false;
return true;
}
*overload = 0;
if (bool_is_allowed && left_type == type_bool && right_type == type_bool) return true; if (bool_is_allowed && left_type == type_bool && right_type == type_bool) return true;
// 2. Perform promotion to a common type. // 2. Perform promotion to a common type.
return binary_arithmetic_promotion(context, left, right, left_type, right_type, expr, error); return binary_arithmetic_promotion(context, left, right, left_type, right_type, expr, error);
@@ -5879,6 +5912,12 @@ static bool sema_expr_analyse_sub(SemaContext *context, Expr *expr, Expr *left,
left_type = type_no_optional(left->type)->canonical; left_type = type_no_optional(left->type)->canonical;
right_type = type_no_optional(right->type)->canonical; right_type = type_no_optional(right->type)->canonical;
Decl *possible_overload = sema_type_get_overload_method(left_type, OVERLOAD_SUB);
if (possible_overload)
{
return sema_rewrite_analyze_overload(context, expr, possible_overload, left, right);
}
// 7. Attempt arithmetic promotion, to promote both to a common type. // 7. Attempt arithmetic promotion, to promote both to a common type.
if (!binary_arithmetic_promotion(context, left, right, left_type, right_type, expr, "The subtraction %s - %s is not possible.")) if (!binary_arithmetic_promotion(context, left, right, left_type, right_type, expr, "The subtraction %s - %s is not possible."))
{ {
@@ -5910,6 +5949,7 @@ static bool sema_expr_analyse_sub(SemaContext *context, Expr *expr, Expr *left,
} }
/** /**
* Analyse a + b * Analyse a + b
* @return true if it succeeds. * @return true if it succeeds.
@@ -6003,6 +6043,12 @@ static bool sema_expr_analyse_add(SemaContext *context, Expr *expr, Expr *left,
left_type = type_no_optional(left->type)->canonical; left_type = type_no_optional(left->type)->canonical;
right_type = type_no_optional(right->type)->canonical; right_type = type_no_optional(right->type)->canonical;
Decl *possible_overload = sema_type_get_overload_method(left_type, OVERLOAD_ADD);
if (possible_overload)
{
return sema_rewrite_analyze_overload(context, expr, possible_overload, left, right);
}
assert(!cast_to_iptr); assert(!cast_to_iptr);
// 4. Do a binary arithmetic promotion // 4. Do a binary arithmetic promotion
if (!binary_arithmetic_promotion(context, left, right, left_type, right_type, expr, "Cannot do the addition %s + %s.")) if (!binary_arithmetic_promotion(context, left, right, left_type, right_type, expr, "Cannot do the addition %s + %s."))
@@ -6046,8 +6092,9 @@ static bool sema_expr_analyse_mult(SemaContext *context, Expr *expr, Expr *left,
{ {
// 1. Analyse the sub expressions and promote to a common type // 1. Analyse the sub expressions and promote to a common type
if (!sema_expr_analyse_binary_arithmetic_subexpr(context, expr, "It is not possible to multiply %s by %s.", false)) return false; OperatorOverload overload = OVERLOAD_MULT;
if (!sema_expr_analyse_binary_arithmetic_subexpr(context, expr, "It is not possible to multiply %s by %s.", false, &overload)) return false;
if (overload) return true;
// 2. Handle constant folding. // 2. Handle constant folding.
if (expr_both_const(left, right)) if (expr_both_const(left, right))
@@ -6079,7 +6126,9 @@ static bool sema_expr_analyse_mult(SemaContext *context, Expr *expr, Expr *left,
static bool sema_expr_analyse_div(SemaContext *context, Expr *expr, Expr *left, Expr *right) static bool sema_expr_analyse_div(SemaContext *context, Expr *expr, Expr *left, Expr *right)
{ {
// 1. Analyse sub expressions and promote to a common type // 1. Analyse sub expressions and promote to a common type
if (!sema_expr_analyse_binary_arithmetic_subexpr(context, expr, "Cannot divide %s by %s.", false)) return false; OperatorOverload overload = OVERLOAD_DIV;
if (!sema_expr_analyse_binary_arithmetic_subexpr(context, expr, "Cannot divide %s by %s.", false, &overload)) return false;
if (overload) return true;
// 2. Check for a constant 0 on the rhs. // 2. Check for a constant 0 on the rhs.
if (IS_CONST(right)) if (IS_CONST(right))
@@ -6131,7 +6180,9 @@ static bool sema_expr_analyse_div(SemaContext *context, Expr *expr, Expr *left,
static bool sema_expr_analyse_mod(SemaContext *context, Expr *expr, Expr *left, Expr *right) static bool sema_expr_analyse_mod(SemaContext *context, Expr *expr, Expr *left, Expr *right)
{ {
// 1. Analyse both sides and promote to a common type // 1. Analyse both sides and promote to a common type
if (!sema_expr_analyse_binary_arithmetic_subexpr(context, expr, NULL, false)) return false; OperatorOverload overload = OVERLOAD_REM;
if (!sema_expr_analyse_binary_arithmetic_subexpr(context, expr, NULL, false, &overload)) return false;
if (overload) return true;
// 3. a % 0 is not valid, so detect it. // 3. a % 0 is not valid, so detect it.
if (IS_CONST(right) && int_is_zero(right->const_expr.ixx)) if (IS_CONST(right) && int_is_zero(right->const_expr.ixx))
@@ -6160,7 +6211,8 @@ static bool sema_expr_analyse_bit(SemaContext *context, Expr *expr, Expr *left,
{ {
// 1. Convert to common type if possible. // 1. Convert to common type if possible.
if (!sema_expr_analyse_binary_arithmetic_subexpr(context, expr, NULL, true)) return false; OperatorOverload overload = 0;
if (!sema_expr_analyse_binary_arithmetic_subexpr(context, expr, NULL, true, &overload)) return false;
// 2. Check that both are integers or bools. // 2. Check that both are integers or bools.
bool is_bool = left->type->canonical == type_bool; bool is_bool = left->type->canonical == type_bool;
@@ -6730,6 +6782,13 @@ static bool sema_expr_analyse_neg(SemaContext *context, Expr *expr)
Type *no_fail = type_no_optional(inner->type); Type *no_fail = type_no_optional(inner->type);
if (!type_may_negate(no_fail)) if (!type_may_negate(no_fail))
{ {
Decl *decl = sema_type_get_overload_method(no_fail->canonical, OVERLOAD_NEG);
if (decl)
{
expr->expr_kind = EXPR_CALL;
expr->call_expr = (ExprCall){ .func_ref = declid(decl) };
return sema_expr_analyse_general_call(context, expr, decl, inner, false);
}
SEMA_ERROR(expr, "Cannot negate an expression of type %s.", type_quoted_error_string(no_fail)); SEMA_ERROR(expr, "Cannot negate an expression of type %s.", type_quoted_error_string(no_fail));
return false; return false;
} }

View File

@@ -43,6 +43,7 @@ const char *kw_FILE;
const char *kw_FUNC; const char *kw_FUNC;
const char *kw_LINEREAL; const char *kw_LINEREAL;
const char *kw_LINE; const char *kw_LINE;
const char *kw_add;
const char *kw_align; const char *kw_align;
const char *kw_argc; const char *kw_argc;
const char *kw_argv; const char *kw_argv;
@@ -56,6 +57,7 @@ const char *kw_at_return;
const char *kw_check_assign; const char *kw_check_assign;
const char *kw_deprecated; const char *kw_deprecated;
const char *kw_distinct; const char *kw_distinct;
const char *kw_div;
const char *kw_elementat; const char *kw_elementat;
const char *kw_elementref; const char *kw_elementref;
const char *kw_elementset; const char *kw_elementset;
@@ -74,19 +76,23 @@ const char *kw_mainstub;
const char *kw_main; const char *kw_main;
const char *kw_max; const char *kw_max;
const char *kw_min; const char *kw_min;
const char *kw_mult;
const char *kw_nameof; const char *kw_nameof;
const char *kw_names; const char *kw_names;
const char *kw_nan; const char *kw_nan;
const char *kw_neg;
const char *kw_noinline; const char *kw_noinline;
const char *kw_ordinal; const char *kw_ordinal;
const char *kw_out; const char *kw_out;
const char *kw_ptr; const char *kw_ptr;
const char *kw_pure; const char *kw_pure;
const char *kw_rem;
const char *kw_return; const char *kw_return;
const char *kw_sizeof; const char *kw_sizeof;
const char *kw_std; const char *kw_std;
const char *kw_std__core; const char *kw_std__core;
const char *kw_std__core__types; const char *kw_std__core__types;
const char *kw_sub;
const char *kw_typekind; const char *kw_typekind;
const char *kw_type; const char *kw_type;
const char *kw_values; const char *kw_values;
@@ -140,11 +146,13 @@ void symtab_init(uint32_t capacity)
type = TOKEN_IDENT; type = TOKEN_IDENT;
kw_add = KW_DEF("add");
kw_align = KW_DEF("align"); kw_align = KW_DEF("align");
kw_argc = KW_DEF("_$argc"); kw_argc = KW_DEF("_$argc");
kw_argv = KW_DEF("_$argv"); kw_argv = KW_DEF("_$argv");
kw_check_assign = KW_DEF("check_assign"); kw_check_assign = KW_DEF("check_assign");
kw_deprecated = KW_DEF("deprecated"); kw_deprecated = KW_DEF("deprecated");
kw_div = KW_DEF("div");
kw_distinct = KW_DEF("distinct"); kw_distinct = KW_DEF("distinct");
kw_elementat = KW_DEF("elementat"); kw_elementat = KW_DEF("elementat");
kw_elementref = KW_DEF("elementref"); kw_elementref = KW_DEF("elementref");
@@ -164,18 +172,22 @@ void symtab_init(uint32_t capacity)
kw_main = KW_DEF("main"); kw_main = KW_DEF("main");
kw_max = KW_DEF("max"); kw_max = KW_DEF("max");
kw_min = KW_DEF("min"); kw_min = KW_DEF("min");
kw_mult = KW_DEF("mult");
kw_nameof = KW_DEF("nameof"); kw_nameof = KW_DEF("nameof");
kw_names = KW_DEF("names"); kw_names = KW_DEF("names");
kw_nan = KW_DEF("nan"); kw_nan = KW_DEF("nan");
kw_neg = KW_DEF("neg");
kw_noinline = KW_DEF("noinline"); kw_noinline = KW_DEF("noinline");
kw_ordinal = KW_DEF("ordinal"); kw_ordinal = KW_DEF("ordinal");
kw_out = KW_DEF("out"); kw_out = KW_DEF("out");
kw_ptr = KW_DEF("ptr"); kw_ptr = KW_DEF("ptr");
kw_pure = KW_DEF("pure"); kw_pure = KW_DEF("pure");
kw_rem = KW_DEF("rem");
kw_sizeof = KW_DEF("sizeof"); kw_sizeof = KW_DEF("sizeof");
kw_std = KW_DEF("std"); kw_std = KW_DEF("std");
kw_std__core = KW_DEF("std::core"); kw_std__core = KW_DEF("std::core");
kw_std__core__types = KW_DEF("std::core::types"); kw_std__core__types = KW_DEF("std::core::types");
kw_sub = KW_DEF("sub");
kw_type = KW_DEF("type"); kw_type = KW_DEF("type");
kw_values = KW_DEF("values"); kw_values = KW_DEF("values");