[qfcc] Support references in expressions

While a reference var can't be initialized yet, using them seems to work
in that they get dereferenced when the value needs to be read or written
(though I haven't seen any generated code for them yet).
This commit is contained in:
Bill Currie 2024-10-26 13:30:59 +09:00
parent 164c949796
commit af42b8e221
5 changed files with 60 additions and 19 deletions

View file

@ -979,6 +979,7 @@ const expr_t *conditional_expr (const expr_t *cond, const expr_t *e1,
const expr_t *incop_expr (int op, const expr_t *e, int postop);
const expr_t *array_expr (const expr_t *array, const expr_t *index);
const expr_t *deref_pointer_expr (const expr_t *pointer);
const expr_t *pointer_deref (const expr_t *pointer);
const expr_t *offset_pointer_expr (const expr_t *pointer, const expr_t *offset);
const expr_t *address_expr (const expr_t *e1, const type_t *t);
const expr_t *build_if_statement (int not, const expr_t *test, const expr_t *s1,

View file

@ -254,6 +254,13 @@ param_mismatch (const expr_t *e, int param, const char *fn,
get_type_string (t2));
}
static const expr_t *
reference_error (const expr_t *e, const type_t *dst, const type_t *src)
{
return error (e, "cannot bind reference of type %s to %s",
get_type_string (dst), get_type_string (src));
}
const expr_t *
test_error (const expr_t *e, const type_t *t)
{
@ -1988,7 +1995,8 @@ vararg_integer (const expr_t *e)
}
const expr_t *
build_function_call (const expr_t *fexpr, const type_t *ftype, const expr_t *params)
build_function_call (const expr_t *fexpr, const type_t *ftype,
const expr_t *params)
{
int param_count = 0;
expr_t *call;
@ -2010,7 +2018,6 @@ build_function_call (const expr_t *fexpr, const type_t *ftype, const expr_t *par
}
}
if (ftype->func.num_params < -1) {
if (options.code.max_params >= 0
&& arg_count > options.code.max_params) {
@ -2066,15 +2073,24 @@ build_function_call (const expr_t *fexpr, const type_t *ftype, const expr_t *par
}
if (i < param_count) {
auto param_type = ftype->func.param_types[i];
if (e->type == ex_nil)
e = convert_nil (e, t = param_type);
if (e->type == ex_bool)
e = convert_from_bool (e, param_type);
if (e->type == ex_error) {
err = e;
continue;
}
auto param_qual = ftype->func.param_quals[i];
if (is_reference (param_type) && param_qual != pq_in) {
internal_error (e, "qualified reference param (not yet)");
}
if (is_reference (param_type) && !is_reference (t)) {
if (!is_lvalue (e)) {
err = error (e, "cannot pass non-lvalue by reference");
}
if (!err && dereference_type (param_type) != t) {
err = reference_error (e, param_type, t);
}
} else if (!is_reference (param_type) && is_reference (t)) {
t = dereference_type (t);
}
if (e->type == ex_nil) {
t = param_type;
}
if (param_qual == pq_out || param_qual == pq_inout) {
//FIXME should be able to use something like *foo() as
//an out or inout arg
@ -2102,13 +2118,9 @@ build_function_call (const expr_t *fexpr, const type_t *ftype, const expr_t *par
}
t = param_type;
} else {
if (e->type == ex_nil)
e = convert_nil (e, t = type_nil);
if (e->type == ex_bool)
e = convert_from_bool (e, get_type (e));
if (is_int_val (e)
&& options.code.progsversion == PROG_ID_VERSION)
e = cast_expr (&type_float, e);
if (e->type == ex_nil) {
t = type_nil;
}
if (options.code.promote_float) {
if (is_scalar (get_type (e)) && is_float (get_type (e))) {
t = &type_double;
@ -2180,7 +2192,18 @@ build_function_call (const expr_t *fexpr, const type_t *ftype, const expr_t *par
inout->inout.out = e;
e = inout;
} else {
e = cast_expr (arg_types[i], e);
if (is_reference (arg_types[i])) {
if (is_reference (get_type (e))) {
// just copy the param, so no op
} else {
e = address_expr (e, nullptr);
}
} else {
if (is_reference (get_type (e))) {
e = pointer_deref (e);
}
e = cast_expr (arg_types[i], e);
}
}
expr_prepend_expr (args, e);
}

View file

@ -320,6 +320,9 @@ assign_expr (const expr_t *dst, const expr_t *src)
if ((expr = check_valid_lvalue (dst))) {
return expr;
}
if (is_reference (get_type (dst))) {
dst = pointer_deref (dst);
}
dst_type = get_type (dst);
if (!dst_type) {
internal_error (dst, "dst_type broke in assign_expr");
@ -347,6 +350,9 @@ assign_expr (const expr_t *dst, const expr_t *src)
return src;
}
}
if (is_reference (get_type (src))) {
src = pointer_deref (src);
}
src_type = get_type (src);
if (!src_type) {
internal_error (src, "src_type broke in assign_expr");

View file

@ -1333,6 +1333,13 @@ binary_expr (int op, const expr_t *e1, const expr_t *e2)
if ((e = check_precedence (op, e1, e2)))
return e;
if (is_reference (get_type (e1))) {
e1 = pointer_deref (e1);
}
if (is_reference (get_type (e2))) {
e2 = pointer_deref (e2);
}
auto t1 = get_type (e1);
auto t2 = get_type (e2);
if (!t1 || !t2)

View file

@ -119,7 +119,7 @@ quat_negate (const expr_t *e)
return new_vector_expr (q);
}
static const expr_t *
const expr_t *
pointer_deref (const expr_t *e)
{
scoped_src_loc (e);
@ -440,6 +440,10 @@ unary_expr (int op, const expr_t *e)
return e;
}
if (is_reference (get_type (e))) {
e = pointer_deref (e);
}
unary_type_t *unary_type = nullptr;
auto t = get_type (e);