[qfcc] Rework function/pointer/array declarations

They should now work in generic contexts, but the pressing need to work
on arrays was due to constant expressions for element counts breaking.
As a side effect, function pointers are now a thing (and seem to work
like they do in C)
This commit is contained in:
Bill Currie 2025-01-03 02:54:30 +09:00
parent fd836e74e1
commit 99632ddb03
18 changed files with 358 additions and 199 deletions

View file

@ -6,10 +6,10 @@
#include <script.h>
#include <string.h>
typedef void () void_function;
typedef void (*void_function)();
int PR_SetField (entity ent, string field, string value) = #0;
@function(void) PR_FindFunction (string func) = #0;
void_function PR_FindFunction (string func) = #0;
@static void ParseEntities (string ent_data);
@ -80,7 +80,7 @@ int PR_SetField (entity ent, string field, string value) = #0;
local int count;
local string field, value;
local plitem_t *keys;
local @function(void) func;
local void_function func;
local Entity *e;
classname = PL_String (PL_ObjectForKey (dict, "classname"));

View file

@ -78,7 +78,7 @@ BOOL (id object) object_is_meta_class = #0;
@end
typedef void arIMP(id, SEL, id);
typedef void (*arIMP)(id, SEL, id);
@static BOOL allocDebug;
@static Class autoreleaseClass;

View file

@ -108,6 +108,7 @@ typedef struct element_chain_s {
element_t *head;
element_t **tail;
const type_t *type; ///< inferred if null
const expr_t *type_expr;
} element_chain_t;
typedef struct ex_listitem_s {
@ -1045,6 +1046,7 @@ expr_t *new_memset_expr (const expr_t *dst, const expr_t *val,
const expr_t *count);
expr_t *new_type_expr (const type_t *type);
expr_t *new_type_function (int op, const expr_t *params);
const expr_t *type_function (int op, const expr_t *params);
symbol_t *type_parameter (symbol_t *sym, const expr_t *type);
const type_t *resolve_type (const expr_t *te, rua_ctx_t *ctx);
@ -1156,6 +1158,7 @@ const expr_t *gather_factors (const type_t *type, int op,
typedef struct rua_ctx_s rua_ctx_t;
const expr_t *expr_process (const expr_t *expr, rua_ctx_t *ctx);
specifier_t spec_process (specifier_t spec, rua_ctx_t *ctx);
bool can_inline (const expr_t *expr, symbol_t *fsym);
///@}

View file

@ -61,6 +61,7 @@ extern const char *storage_class_names[sc_count];
typedef struct specifier_s {
const type_t *type;
const expr_t *type_expr;
expr_t *type_list;
attribute_t *attributes;
param_t *params;
symbol_t *sym;
@ -80,7 +81,6 @@ typedef struct specifier_s {
bool is_overload:1;
bool is_generic:1;
bool is_generic_block:1;
bool is_function:1;//FIXME do proper void(*)() -> ev_func
bool is_far:1;
};
unsigned spec_bits;

View file

@ -285,7 +285,8 @@ symbol_t *make_symbol (const char *name, const struct type_s *type,
struct specifier_s;
symbol_t *declare_symbol (struct specifier_s spec, const expr_t *init,
symtab_t *symtab, expr_t *block, rua_ctx_t *ctx);
symbol_t *declare_field (struct specifier_s spec, symtab_t *symtab);
symbol_t *declare_field (struct specifier_s spec, symtab_t *symtab,
rua_ctx_t *ctx);
///@}

View file

@ -86,9 +86,8 @@ type_t type_SEL = {
};
const type_t *IMP_params[] = { &type_id, &type_SEL };
param_qual_t IMP_quals[] = { pq_in, pq_in };
type_t type_IMP = {
type_t type_IMP_func = {
.type = ev_func,
.name = "IMP",
.alignment = 1,
.width = 1,
.columns = 1,
@ -101,6 +100,17 @@ type_t type_IMP = {
.no_va_list = 1,
},
};
type_t type_IMP = {
.type = ev_ptr,
.name = "IMP",
.alignment = 1,
.width = 1,
.columns = 1,
.meta = ty_basic,
.fldptr = {
.type = &type_IMP_func,
},
};
type_t type_super = {
.type = ev_invalid,
};
@ -1983,6 +1993,7 @@ init_objective_structs (void)
make_structure ("obj_selector", 's', sel_struct, &type_selector);
chain_type (&type_selector);
chain_type (&type_SEL);
chain_type (&type_IMP_func);
chain_type (&type_IMP);
make_structure ("obj_method", 's', method_struct, &type_method);
@ -2009,8 +2020,8 @@ init_objective_structs (void)
static void
init_classes (void)
{
make_structure ("obj_class", 's', class_struct, &type_class);
chain_type (&type_class);
make_structure ("obj_class", 's', class_struct, &type_class);
chain_type (&type_Class);
make_structure ("obj_object", 's', object_struct, &type_object);
chain_type (&type_object);

View file

@ -106,6 +106,7 @@ get_op_string (int op)
case QC_REVERSE: return "@reverse";
case QC_DUAL: return "@dual";
case QC_UNDUAL: return "@undual";
case QC_AT_FUNCTION:return "@function";
case QC_AT_FIELD: return "@field";
case QC_AT_POINTER: return "@pointer";
case QC_AT_ARRAY: return "@array";
@ -342,7 +343,10 @@ print_type_expr (dstring_t *dstr, const expr_t *e, int level, int id,
dasprintf (dstr, "%*se_%p -> e_%p;\n", indent, "", e, e->typ.params);
str = get_op_string (e->typ.op);
} else if (e->typ.type) {
str = e->typ.type->encoding;
str = e->typ.type->encoding;
if (!str) {
str = type_get_encoding (e->typ.type);
}
} else if (e->typ.sym) {
str = e->typ.sym->name;
}

View file

@ -459,7 +459,10 @@ function_expr (const expr_t *fexpr, const expr_t *args)
}
auto ftype = get_type (fexpr);
if (ftype->type != ev_func) {
if (is_ptr (ftype) && is_func (dereference_type (ftype))) {
ftype = dereference_type (ftype);
}
if (!is_func (ftype)) {
if (fexpr->type == ex_symbol)
return error (fexpr, "Called object \"%s\" is not a function",
fexpr->symbol->name);

View file

@ -108,8 +108,12 @@ cast_expr (const type_t *dstType, const expr_t *e)
}
if ((dstType == type_default && is_enum (srcType))
|| (is_enum (dstType) && srcType == type_default))
|| (is_enum (dstType) && srcType == type_default)) {
return e;
}
if ((is_pointer (dstType) && is_func (srcType))) {
return new_alias_expr (dstType, e);
}
if ((is_pointer (dstType) && is_string (srcType))
|| (is_string (dstType) && is_pointer (srcType))) {
return new_alias_expr (dstType, e);

View file

@ -50,14 +50,27 @@
typedef const expr_t *(*process_f) (const expr_t *expr, rua_ctx_t *ctx);
static const type_t *
proc_decl_type (const expr_t *decl, rua_ctx_t *ctx)
{
if (decl->type != ex_decl) {
internal_error (decl, "not a decl expression");
}
if (decl->decl.list.head) {
internal_error (decl, "non-empty cast decl");
}
auto spec = spec_process (decl->decl.spec, ctx);
return spec.type;
}
static const expr_t *
proc_expr (const expr_t *expr, rua_ctx_t *ctx)
{
scoped_src_loc (expr);
if (expr->expr.op == 'C') {
auto type = resolve_type (expr->expr.e1, ctx);
expr = expr_process (expr->expr.e2, ctx);
return cast_expr (type, expr);
auto type = proc_decl_type (expr->expr.e1, ctx);
auto e = expr_process (expr->expr.e2, ctx);
return cast_expr (type, e);
}
auto e1 = expr_process (expr->expr.e1, ctx);
auto e2 = expr_process (expr->expr.e2, ctx);
@ -447,6 +460,9 @@ proc_compound (const expr_t *expr, rua_ctx_t *ctx)
{
scoped_src_loc (expr);
auto comp = new_compound_init ();
if (expr->compound.type_expr) {
comp->compound.type = proc_decl_type (expr->compound.type_expr, ctx);
}
for (auto ele = expr->compound.head; ele; ele = ele->next) {
append_element (comp, new_element (expr_process (ele->expr, ctx),
ele->designator));
@ -593,18 +609,132 @@ proc_cond (const expr_t *expr, rua_ctx_t *ctx)
return new_cond_expr (test, true_expr, false_expr);
}
static const type_t *
decl_function (const type_t *type, const expr_t *t, const symbol_t *sym,
rua_ctx_t *ctx)
{
scoped_src_loc (t);
if (type && is_func (type)) {
error (t, "'%s' declared as a function returning a function",
sym->name);
} else if (type && is_array (type)) {
error (t, "'%s' declared as function returning an array", sym->name);
}
// FIXME not sure I like this setup for @function
auto params = t->typ.params;
auto ftype = params->typ.type;
if (type) {
ftype = append_type (ftype, type);
ftype = find_type (ftype);
}
return ftype;
}
static const type_t *
decl_array (const type_t *type, const expr_t *t, const symbol_t *sym,
rua_ctx_t *ctx)
{
scoped_src_loc (t);
if (type && is_func (type)) {
error (t, "declaration of '%s' as array of functions", sym->name);
}
auto params = new_list_expr (nullptr);
if (!proc_do_list (&params->list, &t->typ.params->list, ctx)) {
return type;
}
expr_prepend_expr (params, new_type_expr (type));
auto type_expr = type_function (QC_AT_ARRAY, params);
return resolve_type (type_expr, ctx);
}
static const type_t *
decl_pointer (const type_t *type, const expr_t *t, const symbol_t *sym,
rua_ctx_t *ctx)
{
scoped_src_loc (t);
auto params = new_list_expr (new_type_expr (type));
auto type_expr = type_function (QC_AT_POINTER, params);
return resolve_type (type_expr, ctx);
}
static const type_t *
decl_field (const type_t *type, const expr_t *t, const symbol_t *sym,
rua_ctx_t *ctx)
{
scoped_src_loc (t);
auto params = new_list_expr (new_type_expr (type));
auto type_expr = type_function (QC_AT_FIELD, params);
return resolve_type (type_expr, ctx);
}
specifier_t
spec_process (specifier_t spec, rua_ctx_t *ctx)
{
if (spec.type && spec.type_expr) {
internal_error (0, "both type and type_expr set");
}
if (!spec.type_expr) {
spec = default_type (spec, spec.sym);
}
if (!spec.type_list) {
return spec;
}
if (spec.type_list->type != ex_list) {
internal_error (spec.type_list, "not a list");
}
int num_types = list_count (&spec.type_list->list);
const expr_t *type_list[num_types];
auto type = spec.type; // core type (int etc)
if (spec.type_expr) {
type = resolve_type (spec.type_expr, ctx);
}
//const type_t *type = nullptr;
// other than fields, the type list is built up by appending types
// to the list, but it's the final type in the list that takes the
// core type, so extract them in reverse for a forward loop
list_scatter_rev (&spec.type_list->list, type_list);
for (int i = 0; i < num_types; i++) {
auto t = type_list[i];
if (t->type != ex_type) {
internal_error (t, "not a type expr");
}
switch (t->typ.op) {
case QC_AT_FUNCTION:
type = decl_function (type, t, spec.sym, ctx);
break;
case QC_AT_ARRAY:
type = decl_array (type, t, spec.sym, ctx);
break;
case QC_AT_POINTER:
type = decl_pointer (type, t, spec.sym, ctx);
break;
case QC_AT_FIELD:
type = decl_field (type, t, spec.sym, ctx);
break;
default:
internal_error (t, "unexpected type op: %d", t->typ.op);
}
}
spec.type_list = nullptr;
spec.type = type;
return spec;
}
static const expr_t *
proc_decl (const expr_t *expr, rua_ctx_t *ctx)
{
scoped_src_loc (expr);
expr_t *block = nullptr;
auto decl_spec = expr->decl.spec;
if (decl_spec.type && decl_spec.type_expr) {
internal_error (0, "both type and type_expr set");
}
if (decl_spec.storage == sc_local) {
scoped_src_loc (expr);
block = new_block_expr (nullptr);
}
int count = list_count (&expr->decl.list);
const expr_t *decls[count + 1];
const expr_t *decls[count];
list_scatter (&expr->decl.list, decls);
for (int i = 0; i < count; i++) {
auto decl = decls[i];
@ -628,6 +758,12 @@ proc_decl (const expr_t *expr, rua_ctx_t *ctx)
internal_error (decl, "not a symbol");
}
auto spec = decl_spec;
spec.sym = sym;
if (spec.type_list) {
// to get here, a concrete declaration is being made
spec.is_generic = false;
spec = spec_process (spec, ctx);
}
if (sym && !spec.type_expr) {
spec.type = append_type (sym->type, spec.type);
spec.type = find_type (spec.type);

View file

@ -161,6 +161,7 @@ single_type_opt_int_pair (int arg_count, const expr_t **args)
static const expr_t *
evaluate_int (const expr_t *expr, rua_ctx_t *ctx)
{
expr = expr_process (expr, ctx);
if (expr->type == ex_expr || expr->type == ex_uexpr) {
auto e = new_expr ();
*e = *expr;
@ -203,7 +204,7 @@ resolve_function (int arg_count, const expr_t **args, rua_ctx_t *ctx)
return &type_func;//FIXME
auto type = resolve_type (args[0], ctx);
if (type) {
type = field_type (type);
type = field_type (type);//FIXME wrong type
type = find_type (type);
}
return type;
@ -224,10 +225,7 @@ static const type_t *
resolve_pointer (int arg_count, const expr_t **args, rua_ctx_t *ctx)
{
auto type = resolve_type (args[0], ctx);
if (type) {
type = pointer_type (type);
type = find_type (type);
}
type = pointer_type (type);
return type;
}
@ -235,17 +233,15 @@ static const type_t *
resolve_array (int arg_count, const expr_t **args, rua_ctx_t *ctx)
{
auto type = resolve_type (args[0], ctx);
if (type) {
int count = 0;
if (arg_count > 1) {
auto count_expr = evaluate_int (args[1], ctx);
if (is_error (count_expr)) {
return nullptr;
}
count = expr_int (count_expr);
int count = 0;
if (arg_count > 1) {
auto count_expr = evaluate_int (args[1], ctx);
if (is_error (count_expr)) {
return nullptr;
}
type = array_type (type, count);
count = expr_integral (count_expr);
}
type = array_type (type, count);
return type;
}
@ -671,6 +667,19 @@ static type_func_t type_funcs[] = {
},
};
expr_t *
new_type_function (int op, const expr_t *params)
{
auto te = new_expr ();
te->type = ex_type;
te->nodag = true;
te->typ = (ex_type_t) {
.op = op,
.params = params,
};
return te;
}
const expr_t *
type_function (int op, const expr_t *params)
{
@ -686,14 +695,7 @@ type_function (int op, const expr_t *params)
if (msg) {
return error (params, "%s for %s", msg, type_funcs[ind].name);
}
auto te = new_expr ();
te->type = ex_type;
te->nodag = true;
te->typ = (ex_type_t) {
.op = op,
.params = params,
};
return te;
return new_type_function (op, params);
}
symbol_t *
@ -725,9 +727,9 @@ resolve_type (const expr_t *te, rua_ctx_t *ctx)
internal_error (te, "not a type expression");
}
if (!te->typ.op) {
if (!te->typ.type) {
internal_error (te, "no type in reference");
}
//if (!te->typ.type) {
// internal_error (te, "no type in reference");
//}
return te->typ.type;
}
int op = te->typ.op;

View file

@ -755,11 +755,11 @@ create_generic_sym (genfunc_t *g, const expr_t *fexpr, calltype_t *calltype,
}
static metafunc_t *
get_function (const char *name, specifier_t spec)
get_function (const char *name, specifier_t spec, rua_ctx_t *ctx)
{
if (!spec.sym->type || !spec.sym->type->encoding) {
spec = default_type (spec, spec.sym);
spec.sym->type = append_type (spec.sym->type, spec.type);
spec = spec_process (spec, ctx);
spec.sym->type = spec.type;
set_func_attrs (spec.sym->type, spec.attributes);
spec.sym->type = find_type (spec.sym->type);
}
@ -850,6 +850,7 @@ symbol_t *
function_symbol (specifier_t spec, rua_ctx_t *ctx)
{
symbol_t *sym = spec.sym;
sym->params = spec.params;
const char *name = sym->name;
metafunc_t *func = Hash_Find (function_map, name);
@ -879,7 +880,7 @@ function_symbol (specifier_t spec, rua_ctx_t *ctx)
Hash_Add (metafuncs, func);
Hash_Add (function_map, func);
} else {
func = get_function (name, spec);
func = get_function (name, spec, ctx);
}
if (func && func->meta_type == mf_overload)

View file

@ -108,6 +108,6 @@ void
glsl_declare_field (specifier_t spec, symtab_t *symtab, rua_ctx_t *ctx)
{
auto attributes = glsl_optimize_attributes (spec.attributes);
spec.sym = declare_field (spec, symtab);
spec.sym = declare_field (spec, symtab, ctx);
glsl_apply_attributes (attributes, spec);
}

View file

@ -359,7 +359,7 @@ send_message (int super, rua_ctx_t *ctx)
{
symbol_t *sym;
const char *sm_name = "obj_msgSend";
type_t *sm_type = &type_IMP;
const type_t *sm_type = type_IMP.fldptr.type;
if (super) {
sm_name = "obj_msgSend_super";

View file

@ -199,7 +199,7 @@ int yylex (YYSTYPE *yylval, YYLTYPE *yylloc);
%type <spec> enum_specifier algebra_specifier
%type <symbol> optional_enum_list enum_list enumerator_list enumerator
%type <symbol> enum_init
%type <size> array_decl
%type <expr> array_decl
%type <expr> const string
@ -213,7 +213,7 @@ int yylex (YYSTYPE *yylval, YYLTYPE *yylloc);
%type <expr> opt_init_semi opt_expr comma_expr
%type <expr> expr
%type <expr> compound_init
%type <spec> opt_cast
%type <expr> opt_cast
%type <mut_expr> element_list expr_list
%type <designator> designator designator_spec
%type <element> element
@ -353,6 +353,7 @@ spec_merge (specifier_t spec, specifier_t new)
spec.multi_type = true;
}
}
spec.type_list = new.type_list;
if (new.is_typedef || !storage_auto (new)) {
if ((spec.is_typedef || !storage_auto (spec)) && !spec.multi_store) {
error (0, "multiple storage classes in declaration specifiers");
@ -391,50 +392,40 @@ spec_merge (specifier_t spec, specifier_t new)
return spec;
}
static const type_t *
static specifier_t
resolve_type_spec (specifier_t spec, rua_ctx_t *ctx)
{
spec = spec_process (spec, ctx);
auto type = spec.type;
if (spec.type_expr) {
type = resolve_type (spec.type_expr, ctx);
spec.type_expr = nullptr;
}
return find_type (type);
}
static specifier_t
typename_spec (specifier_t spec)
{
spec = default_type (spec, 0);
spec.sym->type = find_type (append_type (spec.sym->type, spec.type));
spec.type = spec.sym->type;
spec.type = find_type (type);
return spec;
}
static specifier_t
function_spec (specifier_t spec, param_t *params)
typename_spec (specifier_t spec, rua_ctx_t *ctx)
{
// empty param list in an abstract decl does not create a symbol
if (!spec.sym) {
spec.sym = new_symbol (0);
spec = default_type (spec, 0);
return spec;
}
static specifier_t
function_spec (specifier_t spec, param_t *parameters)
{
// return type will be filled in when building the final type
// FIXME not sure I like this setup for @function
auto params = new_type_expr (parse_params (0, parameters));
auto type_expr = new_type_function (QC_AT_FUNCTION, params);
if (spec.type_list) {
expr_append_expr (spec.type_list, type_expr);
} else {
spec.type_list = new_list_expr (type_expr);
}
if (!spec.type_expr) {
spec = default_type (spec, spec.sym);
}
spec.sym->params = params;
if (spec.sym->type) {
if (is_func (spec.sym->type)) {
error (0, "'%s' declared as a function returning a function",
spec.sym->name);
} else if (is_array (spec.sym->type)) {
error (0, "declaration of '%s' as array of functions",
spec.sym->name);
} else if (!is_pointer (spec.sym->type)
&& !is_field (spec.sym->type)) {
internal_error (0, "unexpected type");
}
}
spec.is_function = !spec.sym->type; //FIXME do proper void(*)() -> ev_func
spec.sym->type = append_type (spec.sym->type, parse_params (0, params));
spec.params = parameters;
spec.is_generic = generic_scope;
spec.is_generic_block = generic_block;
spec.symtab = generic_symtab;
@ -442,41 +433,50 @@ function_spec (specifier_t spec, param_t *params)
}
static specifier_t
array_spec (specifier_t spec, unsigned size)
array_spec (specifier_t spec, const expr_t *size)
{
spec = default_type (spec, spec.sym);
if (spec.sym->type) {
if (is_func (spec.sym->type)) {
error (0, "'%s' declared as function returning an array",
spec.sym->name);
} else if (!is_pointer (spec.sym->type)
&& !is_array (spec.sym->type)
&& !is_field (spec.sym->type)) {
internal_error (0, "unexpected type");
}
// element type will be filled in when building the final type
auto params = new_list_expr (size);
auto type_expr = new_type_function (QC_AT_ARRAY, params);
if (spec.type_list) {
expr_append_expr (spec.type_list, type_expr);
} else {
spec.type_list = new_list_expr (type_expr);
}
spec.sym->type = append_type (spec.sym->type, array_type (0, size));
return spec;
}
static specifier_t
pointer_spec (specifier_t quals, specifier_t spec)
{
if (spec.sym->type) {
if (!is_func (spec.sym->type)
&& !is_pointer (spec.sym->type)
&& !is_array (spec.sym->type)
&& !is_field (spec.sym->type)) {
internal_error (0, "unexpected type");
}
// referenced type will be filled in when building the final type
auto type_expr = new_type_function (QC_AT_POINTER, nullptr);
if (spec.type_list) {
expr_append_expr (spec.type_list, type_expr);
} else {
spec.type_list = new_list_expr (type_expr);
}
return spec;
}
static specifier_t
field_spec (specifier_t spec)
{
// referenced type will be filled in when building the final type
auto type_expr = new_type_function (QC_AT_FIELD, nullptr);
if (spec.type_list) {
expr_prepend_expr (spec.type_list, type_expr);
} else {
spec.type_list = new_list_expr (type_expr);
}
spec.sym->type = append_type (spec.sym->type, pointer_type (0));
return spec;
}
static specifier_t
qc_function_spec (specifier_t spec, param_t *params)
{
#if 0
//FIXME this is borked
// .float () foo; is a field holding a function variable rather
// than a function that returns a float field.
// FIXME I think this breaks fields holding functions that return fields
@ -494,19 +494,17 @@ qc_function_spec (specifier_t spec, param_t *params)
spec.sym = new_symbol (0);
spec.sym->type = field_chain;
spec.type = ret_type;
#endif
spec = function_spec (spec, params);
return spec;
}
static specifier_t
qc_set_symbol (specifier_t spec, symbol_t *sym)
qc_set_symbol (specifier_t spec, symbol_t *sym, rua_ctx_t *ctx)
{
// qc-style function declarations don't know the symbol name until the
// declaration is fully parsed, so spec.sym's name is null but its type
// carries any extra type information (field, pointer, array)
sym->params = spec.sym->params;
sym->type = spec.sym->type;
spec = spec_process (spec, ctx);
sym->type = spec.type;
spec.sym = sym;
return spec;
}
@ -518,20 +516,25 @@ make_ellipsis (void)
}
static param_t *
make_param (specifier_t spec)
make_param (specifier_t spec, rua_ctx_t *ctx)
{
//FIXME should not be sc_global
if (spec.storage == sc_global) {
spec.storage = sc_param;
}
spec = spec_process (spec, ctx);
param_t *param;
if (spec.type_expr) {
param = new_generic_param (spec.type_expr, spec.sym->name);
} else {
} else if (spec.sym) {
spec = default_type (spec, spec.sym);
spec.type = find_type (append_type (spec.sym->type, spec.type));
param = new_param (0, spec.type, spec.sym->name);
param = new_param (nullptr, spec.type, spec.sym->name);
} else {
spec = default_type (spec, spec.sym);
param = new_param (nullptr, spec.type, nullptr);
}
if (spec.is_const) {
if (spec.storage == sc_out) {
@ -569,19 +572,20 @@ make_selector (const char *selector, const type_t *type, const char *name)
}
static param_t *
make_qc_param (specifier_t spec, symbol_t *sym)
make_qc_param (specifier_t spec, symbol_t *sym, rua_ctx_t *ctx)
{
sym->type = nullptr;
spec.sym = sym;
return make_param (spec);
return make_param (spec, ctx);
}
static param_t *
make_qc_func_param (specifier_t spec, param_t *params, symbol_t *sym)
make_qc_func_param (specifier_t spec, param_t *params, symbol_t *sym,
rua_ctx_t *ctx)
{
spec = qc_function_spec (spec, params);
sym->type = append_type (spec.sym->type, spec.type);
param_t *param = new_param (0, sym->type, sym->name);
spec = spec_process (spec, ctx);
param_t *param = new_param (0, spec.type, sym->name);
return param;
}
@ -795,11 +799,11 @@ qc_param_list
qc_first_param
: typespec identifier
{
$$ = make_qc_param ($1, $2);
$$ = make_qc_param ($1, $2, ctx);
}
| typespec_reserved qc_func_params identifier
{
$$ = make_qc_func_param ($1, $2, $3);
$$ = make_qc_func_param ($1, $2, $3, ctx);
}
| ELLIPSIS
{
@ -813,11 +817,11 @@ qc_first_param
qc_param
: typespec identifier
{
$$ = make_qc_param ($1, $2);
$$ = make_qc_param ($1, $2, ctx);
}
| typespec qc_func_params identifier
{
$$ = make_qc_func_param ($1, $2, $3);
$$ = make_qc_func_param ($1, $2, $3, ctx);
}
| ELLIPSIS
{
@ -859,7 +863,7 @@ qc_func_decl
qc_nocode_func
: identifier '=' '#' expr
{
specifier_t spec = qc_set_symbol ($<spec>0, $1);
specifier_t spec = qc_set_symbol ($<spec>0, $1, ctx);
const expr_t *bi_val = expr_process ($4, ctx);
spec.is_overload |= ctx->language->always_overload;
@ -868,19 +872,19 @@ qc_nocode_func
}
| identifier '=' intrinsic
{
specifier_t spec = qc_set_symbol ($<spec>0, $1);
specifier_t spec = qc_set_symbol ($<spec>0, $1, ctx);
build_intrinsic_function (spec, $3, ctx);
}
| identifier '=' expr
{
specifier_t spec = qc_set_symbol ($<spec>0, $1);
specifier_t spec = qc_set_symbol ($<spec>0, $1, ctx);
const expr_t *expr = $3;
declare_symbol (spec, expr, current_symtab, local_expr, ctx);
}
| identifier
{
specifier_t spec = qc_set_symbol ($<spec>0, $1);
specifier_t spec = qc_set_symbol ($<spec>0, $1, ctx);
declare_symbol (spec, nullptr, current_symtab, local_expr, ctx);
}
;
@ -889,7 +893,7 @@ qc_code_func
: identifier '=' optional_state_expr
save_storage
{
specifier_t spec = qc_set_symbol ($<spec>0, $1);
specifier_t spec = qc_set_symbol ($<spec>0, $1, ctx);
auto fs = (funcstate_t) {
.function = current_func,
};
@ -971,8 +975,9 @@ notype_declarator
}
| NAME
{
$$ = $<spec>0;
$$.sym = new_symbol ($1->name);
auto spec = $<spec>0;
spec.sym = new_symbol ($1->name);
$$ = spec;
}
| NOT
{
@ -1134,9 +1139,7 @@ typespec_reserved
// for basic types, but functions need special treatment
| '.' typespec_reserved
{
// avoid find_type()
$$ = type_spec (field_type (0));
$$.type = append_type ($$.type, $2.type);
$$ = field_spec ($2);
}
;
@ -1178,9 +1181,7 @@ typespec_nonreserved
// for basic types, but functions need special treatment
| '.' typespec_nonreserved
{
// avoid find_type()
$$ = type_spec (field_type (0));
$$.type = append_type ($$.type, $2.type);
$$ = field_spec ($2);
}
;
@ -1202,10 +1203,7 @@ save_storage
function_body
: method_optional_state_expr[state]
{
specifier_t spec = $<spec>0;
if (!spec.is_generic) {
spec = default_type (spec, spec.sym);
}
specifier_t spec = spec_process ($<spec>0, ctx);
spec.is_overload |= ctx->language->always_overload;
spec.sym = function_symbol (spec, ctx);
$<spec>$ = spec;
@ -1231,7 +1229,7 @@ function_body
}
| '=' '#' expr ';'
{
specifier_t spec = $<spec>0;
specifier_t spec = spec_process ($<spec>0, ctx);
const expr_t *bi_val = expr_process ($3, ctx);
spec.is_overload |= ctx->language->always_overload;
@ -1240,7 +1238,7 @@ function_body
}
| '=' intrinsic
{
specifier_t spec = $<spec>0;
specifier_t spec = spec_process ($<spec>0, ctx);
build_intrinsic_function (spec, $2, ctx);
}
;
@ -1300,7 +1298,7 @@ generic_type
;
type_function
: type_func '(' type_param_list ')' { $$ = type_function ($1, $3); }
: type_func '(' type_param_list ')' { $$ = new_type_function ($1, $3); }
;
type_func
@ -1579,7 +1577,7 @@ components
component_declarator
: declarator
{
declare_field ($1, current_symtab);
declare_field ($1, current_symtab, ctx);
}
| declarator ':' expr
| ':' expr
@ -1630,23 +1628,23 @@ parameter_list
parameter
: declspecs_ts param_declarator
{
$$ = make_param ($2);
$$ = make_param ($2, ctx);
}
| declspecs_ts notype_declarator
{
$$ = make_param ($2);
$$ = make_param ($2, ctx);
}
| declspecs_ts absdecl
{
$$ = make_param ($2);
$$ = make_param ($2, ctx);
}
| declspecs_nosc_nots notype_declarator
{
$$ = make_param ($2);
$$ = make_param ($2, ctx);
}
| declspecs_nosc_nots absdecl
{
$$ = make_param ($2);
$$ = make_param ($2, ctx);
}
;
@ -1654,7 +1652,6 @@ absdecl
: /* empty */
{
$$ = $<spec>0;
$$.sym = new_symbol (0);
}
| absdecl1
;
@ -1716,24 +1713,11 @@ param_declarator_nostarttypename
;
typename
: declspecs_nosc absdecl
{
$$ = typename_spec ($2);
}
: declspecs_nosc absdecl { $$ = typename_spec ($2, ctx); }
;
array_decl
: '[' expr ']'
{
if (is_int_val ($2) && expr_int ($2) > 0) {
$$ = expr_int ($2);
} else if (is_uint_val ($2) && expr_uint ($2) > 0) {
$$ = expr_uint ($2);
} else {
error (0, "invalid array size");
$$ = 0;
}
}
: '[' expr ']' { $$ = $expr; }
| '[' ']' { $$ = 0; }
;
@ -1780,16 +1764,16 @@ var_initializer
compound_init
: opt_cast '{' element_list optional_comma '}'
{
auto type = resolve_type_spec ($1, ctx);
$3->compound.type = type;
auto cast = $1;
$3->compound.type_expr = cast;
$$ = $3;
}
| opt_cast '{' '}'
{
auto type = resolve_type_spec ($1, ctx);
if (type) {
auto cast = $1;
if (cast) {
auto elements = new_compound_init ();
elements->compound.type = type;
elements->compound.type_expr = cast;
$$ = elements;
} else {
$$ = nullptr;
@ -1798,8 +1782,8 @@ compound_init
;
opt_cast
: '(' typename ')' { $$ = $2; }
| /*empty*/ { $$ = (specifier_t) {}; }
: '(' typename ')' { $$ = new_decl_expr ($2, nullptr); }
| /*empty*/ { $$ = nullptr; }
;
method_optional_state_expr
@ -2156,11 +2140,8 @@ cast_expr
: '(' typename ')' cast_expr
{
auto spec = $2;
auto type_expr = spec.type_expr;
if (!type_expr) {
type_expr = new_type_expr (spec.type);
}
$$ = new_binary_expr ('C', type_expr, $4);
auto decl = new_decl_expr (spec, nullptr);
$$ = new_binary_expr ('C', decl, $4);
}
| CONSTRUCT '(' typename ',' expr_list[args] ')' //FIXME arg_expr instead?
{
@ -2635,7 +2616,7 @@ notype_ivars
ivar_declarator
: declarator
{
declare_field ($1, current_symtab);
declare_field ($1, current_symtab, ctx);
}
| declarator ':' expr
| ':' expr
@ -2747,15 +2728,15 @@ methodproto
methoddecl
: '(' typename ')' unaryselector
{
auto type = resolve_type_spec ($2, ctx);
$$ = new_method (type, $4, 0);
auto spec = resolve_type_spec ($2, ctx);
$$ = new_method (spec.type, $4, 0);
}
| unaryselector
{ $$ = new_method (&type_id, $1, 0); }
| '(' typename ')' keywordselector optional_param_list
{
auto type = resolve_type_spec ($2, ctx);
$$ = new_method (type, $4, $5);
auto spec = resolve_type_spec ($2, ctx);
$$ = new_method (spec.type, $4, $5);
}
| keywordselector optional_param_list
{ $$ = new_method (&type_id, $1, $2); }
@ -2810,18 +2791,22 @@ reserved_word
keyworddecl
: selector ':' '(' typename ')' identifier
{
auto type = resolve_type_spec ($4, ctx);
$$ = make_selector ($1->name, type, $6->name);
auto spec = resolve_type_spec ($4, ctx);
$$ = make_selector ($1->name, spec.type, $6->name);
}
| selector ':' identifier
{ $$ = make_selector ($1->name, &type_id, $3->name); }
{
$$ = make_selector ($1->name, &type_id, $3->name);
}
| ':' '(' typename ')' identifier
{
auto type = resolve_type_spec ($3, ctx);
$$ = make_selector ("", type, $5->name);
auto spec = resolve_type_spec ($3, ctx);
$$ = make_selector ("", spec.type, $5->name);
}
| ':' identifier
{ $$ = make_selector ("", &type_id, $2->name); }
{
$$ = make_selector ("", &type_id, $2->name);
}
;
obj_expr
@ -2830,8 +2815,8 @@ obj_expr
| PROTOCOL '(' identifier ')' { $$ = protocol_expr ($3->name); }
| ENCODE '(' typename ')'
{
auto type = resolve_type_spec ($3, ctx);
$$ = encode_expr (type);
auto spec = resolve_type_spec ($3, ctx);
$$ = encode_expr (spec.type);
}
| obj_string /* FIXME string object? */
;

View file

@ -214,10 +214,9 @@ function_decl (symbol_t *sym, param_t *params, const type_t *ret_type,
// use `@name` so `main` can be used (`.main` is reserved for the entry
// point)
auto fsym = new_symbol (va (0, "@%s", sym->name));
fsym->params = params;
fsym->type = parse_params (ret_type, params);
fsym->type = find_type (fsym->type);
fsym = function_symbol ((specifier_t) { .sym = fsym, }, ctx);
fsym = function_symbol ((specifier_t) {.sym = fsym, .params = params}, ctx);
auto fsym_expr = new_symbol_expr (fsym);
if (!params) {
fsym_expr = new_call_expr (fsym_expr, nullptr, nullptr);

View file

@ -291,16 +291,12 @@ declare_symbol (specifier_t spec, const expr_t *init, symtab_t *symtab,
sym->table = nullptr;
}
if (!spec.type_expr && !spec.is_function) {
spec = default_type (spec, sym);
}
spec = spec_process (spec, ctx);
if (!spec.storage) {
spec.storage = current_storage;
}
if (spec.type && (spec.is_typedef || !sym->type || !is_func (sym->type))) {
sym->type = append_type (spec.sym->type, spec.type);
}
sym->type = spec.type;
if (spec.is_typedef) {
if (init) {
@ -311,7 +307,7 @@ declare_symbol (specifier_t spec, const expr_t *init, symtab_t *symtab,
sym->type = find_type (alias_type (sym->type, sym->type, sym->name));
symtab_addsymbol (symtab, sym);
} else {
if (spec.is_function && is_func (sym->type)) {
if (is_func (sym->type)) {
if (init) {
error (0, "function %s is initialized", sym->name);
}
@ -328,10 +324,10 @@ declare_symbol (specifier_t spec, const expr_t *init, symtab_t *symtab,
}
symbol_t *
declare_field (specifier_t spec, symtab_t *symtab)
declare_field (specifier_t spec, symtab_t *symtab, rua_ctx_t *ctx)
{
symbol_t *s = spec.sym;
spec = default_type (spec, s);
spec = spec_process (spec, ctx);
s->type = find_type (append_type (s->type, spec.type));
s->sy_type = sy_offset;
s->visibility = current_visibility;

View file

@ -202,6 +202,14 @@ type_t type_param = {
.type = ev_invalid,
.meta = ty_struct,
};
static type_t type_param_pointer = {
.type = ev_ptr,
.alignment = 1,
.width = 1,
.columns = 1,
.meta = ty_basic,
.fldptr.type = &type_param,
};
type_t type_zero = {
.type = ev_invalid,
.meta = ty_struct,
@ -222,7 +230,7 @@ type_t type_xdef_pointer = {
.width = 1,
.columns = 1,
.meta = ty_basic,
{{&type_xdef}},
.fldptr.type = &type_xdef,
};
type_t type_xdefs = {
.type = ev_invalid,
@ -1668,6 +1676,10 @@ type_assignable (const type_t *dst, const type_t *src)
// any field = any field
if (dst->type == ev_field && src->type == ev_field)
return true;
if (is_pointer (dst) && is_func (src)) {
auto type = dereference_type (dst);
return type == src;
}
// pointer = array
if (is_pointer (dst) && is_array (src)) {
if (is_void (dst->fldptr.type)
@ -2063,6 +2075,7 @@ static void
chain_structural_types (void)
{
chain_type (&type_param);
chain_type (&type_param_pointer);
chain_type (&type_zero);
chain_type (&type_type_encodings);
chain_type (&type_xdef);
@ -2203,6 +2216,7 @@ init_types (void)
make_structure ("@zero", 'u', zero_struct, &type_zero);
make_structure ("@param", 'u', param_struct, &type_param);
build_vector_struct (&type_vector, false);
make_structure ("@type_encodings", 's', type_encoding_struct,
@ -2210,7 +2224,7 @@ init_types (void)
make_structure ("@xdef", 's', xdef_struct, &type_xdef);
make_structure ("@xdefs", 's', xdefs_struct, &type_xdefs);
va_list_struct[1].type = pointer_type (&type_param);
va_list_struct[1].type = &type_param_pointer;
make_structure ("@va_list", 's', va_list_struct, &type_va_list);
build_vector_struct (&type_quaternion, false);