aboutsummaryrefslogtreecommitdiff
path: root/src/check_expr.c
diff options
context:
space:
mode:
authorGinger Bill <bill@gingerbill.org>2017-04-01 12:07:41 +0100
committerGinger Bill <bill@gingerbill.org>2017-04-01 12:07:41 +0100
commitdc303cde21d23b1b57a4cb4f667b2cfbe2a39ffd (patch)
tree9ea225d705d2123b818415f6306373eae9d3cd0c /src/check_expr.c
parenta75ccb6fbc529d2fee00f9b456ca7c0c830548ee (diff)
Complex numbers: complex64 complex128
Diffstat (limited to 'src/check_expr.c')
-rw-r--r--src/check_expr.c153
1 files changed, 150 insertions, 3 deletions
diff --git a/src/check_expr.c b/src/check_expr.c
index db1bbd135..8c162e034 100644
--- a/src/check_expr.c
+++ b/src/check_expr.c
@@ -1754,18 +1754,37 @@ bool check_representable_as_constant(Checker *c, ExactValue in_value, Type *type
if (v.kind != ExactValue_Float) {
return false;
}
+ if (out_value) *out_value = v;
+
switch (type->Basic.kind) {
- // case Basic_f16:
case Basic_f32:
case Basic_f64:
- // case Basic_f128:
- if (out_value) *out_value = v;
return true;
case Basic_UntypedFloat:
return true;
}
+ } else if (is_type_complex(type)) {
+ ExactValue v = exact_value_to_complex(in_value);
+ if (v.kind != ExactValue_Complex) {
+ return false;
+ }
+
+ switch (type->Basic.kind) {
+ case Basic_complex64:
+ case Basic_complex128: {
+ ExactValue real = exact_value_real(v);
+ ExactValue imag = exact_value_imag(v);
+ if (real.kind != ExactValue_Invalid &&
+ imag.kind != ExactValue_Invalid) {
+ if (out_value) *out_value = exact_binary_operator_value(Token_Add, real, exact_value_make_imag(imag));
+ return true;
+ }
+ } break;
+ }
+
+ return false;
} else if (is_type_pointer(type)) {
if (in_value.kind == ExactValue_Pointer) {
return true;
@@ -2190,6 +2209,10 @@ bool check_is_castable_to(Checker *c, Operand *operand, Type *y) {
}
}
+ if (is_type_complex(src) && is_type_complex(dst)) {
+ return true;
+ }
+
// Cast between pointers
if (is_type_pointer(src) && is_type_pointer(dst)) {
Type *s = base_type(type_deref(src));
@@ -3568,6 +3591,129 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
operand->mode = Addressing_Value;
} break;
+ case BuiltinProc_complex: {
+ // complex :: proc(real, imag: float_type) -> complex_type
+ Operand x = *operand;
+ Operand y = {0};
+
+ // NOTE(bill): Invalid will be the default till fixed
+ operand->type = t_invalid;
+ operand->mode = Addressing_Invalid;
+
+ check_expr(c, &y, ce->args.e[1]);
+ if (y.mode == Addressing_Invalid) {
+ return false;
+ }
+
+ u32 flag = 0;
+ if (is_type_untyped(x.type)) {
+ flag |= 1;
+ }
+ if (is_type_untyped(y.type)) {
+ flag |= 2;
+ }
+ switch (flag) {
+ case 0: break;
+ case 1: convert_to_typed(c, &x, y.type, 0); break;
+ case 2: convert_to_typed(c, &y, x.type, 0); break;
+ case 3: {
+ if (x.mode == Addressing_Constant && y.mode == Addressing_Constant) {
+ if (is_type_numeric(x.type) && exact_value_imag(x.value).value_float == 0) {
+ x.type = t_untyped_float;
+ }
+ if (is_type_numeric(y.type) && exact_value_imag(y.value).value_float == 0) {
+ y.type = t_untyped_float;
+ }
+ } else {
+ convert_to_typed(c, &x, t_f64, 0);
+ convert_to_typed(c, &y, t_f64, 0);
+ }
+ } break;
+ }
+
+ if (x.mode == Addressing_Invalid || y.mode == Addressing_Invalid) {
+ return false;
+ }
+
+ if (!are_types_identical(x.type, y.type)) {
+ gbString type_x = type_to_string(x.type);
+ gbString type_y = type_to_string(y.type);
+ error_node(call,
+ "Mismatched types to `complex`, `%s` vs `%s`",
+ type_x, type_y);
+ gb_string_free(type_y);
+ gb_string_free(type_x);
+ return false;
+ }
+
+ if (!is_type_float(x.type)) {
+ gbString s = type_to_string(x.type);
+ error_node(call, "Arguments have type `%s`, expected a floating point", s);
+ gb_string_free(s);
+ return false;
+ }
+
+ if (x.mode == Addressing_Constant && y.mode == Addressing_Constant) {
+ operand->value = exact_binary_operator_value(Token_Add, x.value, y.value);
+ operand->mode = Addressing_Constant;
+ } else {
+ operand->mode = Addressing_Value;
+ }
+
+ BasicKind kind = core_type(x.type)->Basic.kind;
+ switch (kind) {
+ case Basic_f32: operand->type = t_complex64; break;
+ case Basic_f64: operand->type = t_complex128; break;
+ case Basic_UntypedFloat: operand->type = t_untyped_complex; break;
+ default: GB_PANIC("Invalid type"); break;
+ }
+ } break;
+
+ case BuiltinProc_real:
+ case BuiltinProc_imag: {
+ // real :: proc(c: complex_type) -> float_type
+ // imag :: proc(c: complex_type) -> float_type
+
+ Operand *x = operand;
+ if (is_type_untyped(x->type)) {
+ if (x->mode == Addressing_Constant) {
+ if (is_type_numeric(x->type)) {
+ x->type = t_untyped_complex;
+ }
+ } else {
+ convert_to_typed(c, x, t_complex128, 0);
+ if (x->mode == Addressing_Invalid) {
+ return false;
+ }
+ }
+ }
+
+ if (!is_type_complex(x->type)) {
+ gbString s = type_to_string(x->type);
+ error_node(call, "Argument has type `%s`, expected a complex type", s);
+ gb_string_free(s);
+ return false;
+ }
+
+ if (x->mode == Addressing_Constant) {
+ if (id == BuiltinProc_real) {
+ x->value = exact_value_real(x->value);
+ } else {
+ x->value = exact_value_imag(x->value);
+ }
+ } else {
+ x->mode = Addressing_Value;
+ }
+
+ BasicKind kind = core_type(x->type)->Basic.kind;
+ switch (kind) {
+ case Basic_complex64: x->type = t_f32; break;
+ case Basic_complex128: x->type = t_f64; break;
+ case Basic_UntypedComplex: x->type = t_untyped_float; break;
+ default: GB_PANIC("Invalid type"); break;
+ }
+ } break;
+
case BuiltinProc_slice_ptr: {
// slice_ptr :: proc(a: ^T, len: int) -> []T
// slice_ptr :: proc(a: ^T, len, cap: int) -> []T
@@ -4405,6 +4551,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
switch (bl->kind) {
case Token_Integer: t = t_untyped_integer; break;
case Token_Float: t = t_untyped_float; break;
+ case Token_Imag: t = t_untyped_complex; break;
case Token_String: t = t_untyped_string; break;
case Token_Rune: t = t_untyped_rune; break;
default: GB_PANIC("Unknown literal"); break;