mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Compare commits
1 Commits
v0.6.2
...
overload_t
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3348f4dc7d |
@@ -636,7 +636,7 @@ typedef struct Decl_
|
||||
bool obfuscate : 1;
|
||||
bool is_dynamic : 1;
|
||||
bool is_synthetic : 1;
|
||||
OperatorOverload operator : 4;
|
||||
OperatorOverload operator : 5;
|
||||
union
|
||||
{
|
||||
void *backend_ref;
|
||||
@@ -1781,7 +1781,7 @@ extern const char *kw_max;
|
||||
extern const char *kw_min;
|
||||
extern const char *kw_elements;
|
||||
extern const char *kw_align;
|
||||
|
||||
extern const char *kw_add;
|
||||
extern const char *kw_nameof;
|
||||
extern const char *kw_names;
|
||||
extern const char *kw_sizeof;
|
||||
@@ -1790,6 +1790,7 @@ extern const char *kw_out;
|
||||
extern const char *kw_inout;
|
||||
extern const char *kw_deprecated;
|
||||
extern const char *kw_distinct;
|
||||
extern const char *kw_div;
|
||||
extern const char *kw_intvec;
|
||||
extern const char *kw_floatvec;
|
||||
extern const char *kw_inline;
|
||||
@@ -1800,17 +1801,21 @@ extern const char *kw_elementat;
|
||||
extern const char *kw_elementref;
|
||||
extern const char *kw_elementset;
|
||||
extern const char *kw_len;
|
||||
extern const char *kw_nan;
|
||||
extern const char *kw_noinline;
|
||||
extern const char *kw_main;
|
||||
extern const char *kw_max;
|
||||
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_pure;
|
||||
extern const char *kw_ptr;
|
||||
extern const char *kw_values;
|
||||
extern const char *kw_rem;
|
||||
extern const char *kw_return;
|
||||
extern const char *kw_sub;
|
||||
extern const char *kw_type;
|
||||
extern const char *kw_values;
|
||||
extern const char *kw_FILE;
|
||||
extern const char *kw_FUNC;
|
||||
extern const char *kw_LINE;
|
||||
|
||||
@@ -722,6 +722,12 @@ typedef enum
|
||||
OVERLOAD_ELEMENT_REF,
|
||||
OVERLOAD_ELEMENT_SET,
|
||||
OVERLOAD_LEN,
|
||||
OVERLOAD_ADD,
|
||||
OVERLOAD_SUB,
|
||||
OVERLOAD_MULT,
|
||||
OVERLOAD_DIV,
|
||||
OVERLOAD_REM,
|
||||
OVERLOAD_NEG,
|
||||
} OperatorOverload;
|
||||
|
||||
typedef enum
|
||||
|
||||
@@ -1274,6 +1274,34 @@ static inline bool sema_analyse_operator_len(Decl *method)
|
||||
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)
|
||||
{
|
||||
switch (method->operator)
|
||||
@@ -1285,6 +1313,14 @@ static bool sema_check_operator_method_validity(Decl *method)
|
||||
return sema_analyse_operator_element_at(method);
|
||||
case OVERLOAD_LEN:
|
||||
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
|
||||
}
|
||||
@@ -1402,6 +1438,21 @@ static const char *attribute_domain_to_string(AttributeDomain domain)
|
||||
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)
|
||||
{
|
||||
AttributeType type = attr->attr_kind;
|
||||
@@ -1538,6 +1589,36 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
|
||||
}
|
||||
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)
|
||||
{
|
||||
if (decl->decl_kind != DECL_MACRO)
|
||||
|
||||
@@ -838,6 +838,31 @@ bool sema_expr_check_assign(SemaContext *c, Expr *expr)
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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 *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 *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;
|
||||
// 2. Perform promotion to a common type.
|
||||
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;
|
||||
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.
|
||||
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
|
||||
* @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;
|
||||
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);
|
||||
// 4. Do a binary arithmetic promotion
|
||||
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
|
||||
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.
|
||||
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)
|
||||
{
|
||||
// 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.
|
||||
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)
|
||||
{
|
||||
// 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.
|
||||
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.
|
||||
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.
|
||||
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);
|
||||
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));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ const char *kw_FILE;
|
||||
const char *kw_FUNC;
|
||||
const char *kw_LINEREAL;
|
||||
const char *kw_LINE;
|
||||
const char *kw_add;
|
||||
const char *kw_align;
|
||||
const char *kw_argc;
|
||||
const char *kw_argv;
|
||||
@@ -56,6 +57,7 @@ const char *kw_at_return;
|
||||
const char *kw_check_assign;
|
||||
const char *kw_deprecated;
|
||||
const char *kw_distinct;
|
||||
const char *kw_div;
|
||||
const char *kw_elementat;
|
||||
const char *kw_elementref;
|
||||
const char *kw_elementset;
|
||||
@@ -74,19 +76,23 @@ const char *kw_mainstub;
|
||||
const char *kw_main;
|
||||
const char *kw_max;
|
||||
const char *kw_min;
|
||||
const char *kw_mult;
|
||||
const char *kw_nameof;
|
||||
const char *kw_names;
|
||||
const char *kw_nan;
|
||||
const char *kw_neg;
|
||||
const char *kw_noinline;
|
||||
const char *kw_ordinal;
|
||||
const char *kw_out;
|
||||
const char *kw_ptr;
|
||||
const char *kw_pure;
|
||||
const char *kw_rem;
|
||||
const char *kw_return;
|
||||
const char *kw_sizeof;
|
||||
const char *kw_std;
|
||||
const char *kw_std__core;
|
||||
const char *kw_std__core__types;
|
||||
const char *kw_sub;
|
||||
const char *kw_typekind;
|
||||
const char *kw_type;
|
||||
const char *kw_values;
|
||||
@@ -140,11 +146,13 @@ void symtab_init(uint32_t capacity)
|
||||
|
||||
type = TOKEN_IDENT;
|
||||
|
||||
kw_add = KW_DEF("add");
|
||||
kw_align = KW_DEF("align");
|
||||
kw_argc = KW_DEF("_$argc");
|
||||
kw_argv = KW_DEF("_$argv");
|
||||
kw_check_assign = KW_DEF("check_assign");
|
||||
kw_deprecated = KW_DEF("deprecated");
|
||||
kw_div = KW_DEF("div");
|
||||
kw_distinct = KW_DEF("distinct");
|
||||
kw_elementat = KW_DEF("elementat");
|
||||
kw_elementref = KW_DEF("elementref");
|
||||
@@ -164,18 +172,22 @@ void symtab_init(uint32_t capacity)
|
||||
kw_main = KW_DEF("main");
|
||||
kw_max = KW_DEF("max");
|
||||
kw_min = KW_DEF("min");
|
||||
kw_mult = KW_DEF("mult");
|
||||
kw_nameof = KW_DEF("nameof");
|
||||
kw_names = KW_DEF("names");
|
||||
kw_nan = KW_DEF("nan");
|
||||
kw_neg = KW_DEF("neg");
|
||||
kw_noinline = KW_DEF("noinline");
|
||||
kw_ordinal = KW_DEF("ordinal");
|
||||
kw_out = KW_DEF("out");
|
||||
kw_ptr = KW_DEF("ptr");
|
||||
kw_pure = KW_DEF("pure");
|
||||
kw_rem = KW_DEF("rem");
|
||||
kw_sizeof = KW_DEF("sizeof");
|
||||
kw_std = KW_DEF("std");
|
||||
kw_std__core = KW_DEF("std::core");
|
||||
kw_std__core__types = KW_DEF("std::core::types");
|
||||
kw_sub = KW_DEF("sub");
|
||||
kw_type = KW_DEF("type");
|
||||
kw_values = KW_DEF("values");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user