class/constructor tweaks.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4388 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2013-06-05 23:58:20 +00:00
parent 1c95764c54
commit c0bb744b88
3 changed files with 264 additions and 247 deletions

View File

@ -498,7 +498,7 @@ char *PR_ValueString (progfuncs_t *progfuncs, etype_t type, eval_t *val)
break;
case ev_entity:
fielddef = ED_FindField(progfuncs, "classname");
if (fielddef && val->edict < sv_num_edicts)
if (fielddef && (unsigned)val->edict < (unsigned)sv_num_edicts)
{
edictrun_t *ed;
string_t *v;

View File

@ -137,6 +137,8 @@ QCC_type_t *QCC_PR_FindType (QCC_type_t *type);
QCC_type_t *QCC_PR_PointerType (QCC_type_t *pointsto);
QCC_type_t *QCC_PR_FieldType (QCC_type_t *pointsto);
QCC_def_t *QCC_PR_Term (int exprflags);
QCC_def_t *QCC_PR_ParseValue (QCC_type_t *assumeclass, pbool allowarrayassign, pbool expandmemberfields);
QCC_def_t *QCC_PR_ParseArrayPointer (QCC_def_t *d, pbool allowarrayassign);
QCC_def_t *QCC_PR_GenerateFunctionCall (QCC_def_t *newself, QCC_def_t *func, QCC_def_t *arglist[], QCC_type_t *argtypelist[], int argcount);
void QCC_Marshal_Locals(int firststatement, int laststatement);
@ -1167,30 +1169,6 @@ QCC_def_t *QCC_SupplyConversion(QCC_def_t *var, etype_t wanted, pbool fatal)
extern char *basictypenames[];
int o;
if (pr_classtype && var->type->type == ev_field && wanted != ev_field)
{
if (pr_classtype)
{ //load self.var into a temp
QCC_def_t *self;
self = QCC_PR_GetDef(type_entity, "self", NULL, true, 0, false);
switch(wanted)
{
case ev_float:
return QCC_PR_Statement(pr_opcodes+OP_LOAD_F, self, var, NULL);
case ev_string:
return QCC_PR_Statement(pr_opcodes+OP_LOAD_S, self, var, NULL);
case ev_function:
return QCC_PR_Statement(pr_opcodes+OP_LOAD_FNC, self, var, NULL);
case ev_vector:
return QCC_PR_Statement(pr_opcodes+OP_LOAD_V, self, var, NULL);
case ev_entity:
return QCC_PR_Statement(pr_opcodes+OP_LOAD_ENT, self, var, NULL);
default:
QCC_Error(ERR_INTERNAL, "Inexplicit field load failed, try explicit");
}
}
}
o = QCC_ShouldConvert(var, wanted);
if (o == 0) //type already matches
@ -1652,7 +1630,7 @@ QCC_def_t *QCC_PR_Statement (QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t *var_
if (var_a)
{
var_a->references++;
var_a->references++;
QCC_FreeTemp(var_a);
}
if (var_b)
@ -3263,14 +3241,13 @@ QCC_def_t *QCC_PR_GenerateFunctionCall (QCC_def_t *newself, QCC_def_t *func, QCC
PR_ParseFunctionCall
============
*/
QCC_def_t *QCC_PR_ParseFunctionCall (QCC_def_t *func) //warning, the func could have no name set if it's a field call.
QCC_def_t *QCC_PR_ParseFunctionCall (QCC_def_t *newself, QCC_def_t *func) //warning, the func could have no name set if it's a field call.
{
QCC_def_t *e, *d, *oself, *out;
QCC_def_t *e, *d, *out;
unsigned int arg;
QCC_type_t *t, *p;
int extraparms=false;
unsigned int np;
QCC_def_t *newself = NULL;
QCC_def_t *param[MAX_PARMS+MAX_EXTRA_PARMS];
QCC_type_t *paramtypes[MAX_PARMS+MAX_EXTRA_PARMS];
@ -3684,67 +3661,128 @@ QCC_def_t *QCC_PR_ParseFunctionCall (QCC_def_t *func) //warning, the func could
}
else if (!strcmp(func->name, "spawn"))
{
QCC_def_t *old;
QCC_def_t *oldret = NULL, *oself = NULL, *result;
QCC_type_t *rettype;
if (QCC_PR_CheckToken(")"))
{
rettype = type_entity;
}
else
QCC_def_t *self = QCC_PR_GetDef(type_entity, "self", NULL, true, 0, 0);
/*
temp oldret = ret; <if ret needs to be preserved>
ret = spawn();
ret.FOO* = FOO*; <if any arguments are specified>
temp oself = self; <if spawnfunc_foo will be called>
self = ret; <if spawnfunc_foo will be called>
result = ret; <if spawnfunc_foo will be called, or ret needs to be preserved>
spawnfunc_foo(); <if spawnfunc_foo will be called>
self = oself; <if spawnfunc_foo will be called>
ret = oldret; <if ret needs to be preserved>
return result;
this exact mechanism means entities can be spawned easily via maps.
*/
if (!QCC_PR_CheckToken(")"))
{
rettype = QCC_TypeForName(QCC_PR_ParseName());
if (!rettype || rettype->type != ev_entity)
QCC_PR_ParseError(ERR_NOTANAME, "Spawn operator with undefined class");
}
else
rettype = NULL; //default, corrected to entity later
//oldret = ret;
if (def_ret.temp->used)
{
oldret = QCC_GetTemp(def_ret.type);
if (def_ret.type->size == 3)
QCC_PR_Statement(&pr_opcodes[OP_STORE_V], &def_ret, oldret, NULL);
else
QCC_PR_Statement(&pr_opcodes[OP_STORE_F], &def_ret, oldret, NULL);
QCC_UnFreeTemp(oldret);
QCC_PR_ParseWarning(WARN_FIXEDRETURNVALUECONFLICT, "Return value conflict - output is inefficient");
}
//ret = spawn()
result = QCC_PR_GenerateFunctionCall(NULL, func, NULL, NULL, 0);
if (!rettype)
rettype = type_entity;
else
{
//do field assignments.
while(QCC_PR_CheckToken(","))
{
QCC_def_t *f, *p, *v;
f = QCC_PR_ParseValue(rettype, false, false);
if (f->type->type != ev_field)
QCC_PR_ParseError(0, "Named field is not a field.");
if (QCC_PR_CheckToken("=")) //allow : or = as a separator, but throw a warning for =
QCC_PR_ParseWarning(0, "That = should be a :"); //rejecting = helps avoid qcc bugs. :P
else
QCC_PR_Expect(":");
v = QCC_PR_Expression(TOP_PRIORITY, EXPR_DISALLOW_COMMA);
p = QCC_PR_Statement(&pr_opcodes[OP_ADDRESS], result, f, NULL);
type_pointer->aux_type = f->type->aux_type;
if (v->type->size == 3)
QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_STOREP_V], v, p, NULL));
else
QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_STOREP_F], v, p, NULL));
}
QCC_PR_Expect(")");
}
if (def_ret.temp->used)
{
old = QCC_GetTemp(def_ret.type);
if (def_ret.type->size == 3)
QCC_PR_Statement(&pr_opcodes[OP_STORE_V], &def_ret, old, NULL);
else
QCC_PR_Statement(&pr_opcodes[OP_STORE_F], &def_ret, old, NULL);
QCC_UnFreeTemp(old);
QCC_UnFreeTemp(&def_ret);
QCC_PR_ParseWarning(WARN_FIXEDRETURNVALUECONFLICT, "Return value conflict - output is inefficient");
}
else
old = NULL;
/*
if (def_ret.temp->used)
QCC_PR_ParseWarning(0, "Return value conflict - output is likly to be invalid");
def_ret.temp->used = true;
*/
//tmp oself = self
if (rettype != type_entity)
{
oself = QCC_GetTemp(type_entity);
QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_STORE_ENT], self, oself, NULL));
QCC_UnFreeTemp(oself);
}
//self = ret
if (oself)
{
QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_STORE_ENT], result, self, NULL));
}
//result = ret (just in case spawnfunc_ breaks things)
if (oldret || oself)
{
QCC_def_t *tr = result;
tr = QCC_GetTemp(type_entity);
QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_STORE_ENT], result, tr, NULL));
result = tr;
QCC_UnFreeTemp(result);
}
//call the spawnfunc. this will set up the vtable as required, or its a regular spawn function and will set the .think etc. same thing.
if (oself)
{
char genfunc[2048];
sprintf(genfunc, "Class*%s", rettype->name);
sprintf(genfunc, "spawnfunc_%s", rettype->name);
func = QCC_PR_GetDef(type_function, genfunc, NULL, true, 0, false);
func->references++;
}
QCC_PR_SimpleStatement(OP_CALL0, func->ofs, 0, 0, false);
if (old)
QCC_FreeTemp(QCC_PR_GenerateFunctionCall(NULL, func, NULL, NULL, 0));
}
//self = oself
if (oself)
{
QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_STORE_ENT], oself, self, NULL));
}
//ret = oldret
if (oldret)
{
d = QCC_GetTemp(rettype);
QCC_FreeTemp(QCC_PR_Statement(pr_opcodes+OP_STORE_ENT, &def_ret, d, NULL));
if (def_ret.type->size == 3)
QCC_FreeTemp(QCC_PR_Statement(pr_opcodes+OP_STORE_V, old, &def_ret, NULL));
QCC_FreeTemp(QCC_PR_Statement(pr_opcodes+OP_STORE_V, oldret, &def_ret, NULL));
else
QCC_FreeTemp(QCC_PR_Statement(pr_opcodes+OP_STORE_F, old, &def_ret, NULL));
QCC_FreeTemp(old);
QCC_UnFreeTemp(d);
QCC_FreeTemp(QCC_PR_Statement(pr_opcodes+OP_STORE_F, oldret, &def_ret, NULL));
QCC_FreeTemp(oldret);
QCC_UnFreeTemp(&def_ret);
return d;
}
def_ret.type = rettype;
return &def_ret;
result->type = rettype;
return result;
}
else if (!strcmp(func->name, "entnum") && !QCC_PR_CheckToken(")"))
{
@ -3802,41 +3840,6 @@ QCC_def_t *QCC_PR_ParseFunctionCall (QCC_def_t *func) //warning, the func could
else
np = t->num_parms;
if (func->temp && strchr(func->name, ':'))
{
if (statements[numstatements-1].op == OP_LOAD_FNC && statements[numstatements-1].c == func->ofs)
{
if (statements[numstatements-2].op == OP_LOAD_ENT && statements[numstatements-2].c == statements[numstatements-1].a)
{
//a.b.f is tricky. the b.f load overwrites the a.b load's temp. so insert a new statement before the load_fnc so things don't get so crashy.
newself = QCC_GetTemp(type_entity);
//shift the OP_LOAD_FNC over
statements[numstatements] = statements[numstatements-1];
statement_linenums[numstatements] = statement_linenums[numstatements-1];
statements[numstatements-1] = statements[numstatements-2];
statement_linenums[numstatements-1] = statement_linenums[numstatements-2];
statements[numstatements-2].op = OP_STORE_ENT;
statements[numstatements-2].b = newself->ofs;
statements[numstatements-2].c = 0;
}
else
{
//already a global. no idea which one, but whatever
newself = (void *)qccHunkAlloc (sizeof(QCC_def_t));
newself->type = type_entity;
newself->name = "something";
newself->constant = true;
newself->initialized = 1;
newself->scope = NULL;
newself->arraysize = 0;
newself->ofs = statements[numstatements-1].a;
}
}
else
QCC_PR_ParseError(ERR_INTERNAL, "Unable to determine class for function call to %s", func->name);
}
//any temps referenced to build the parameters don't need to be locked.
if (!QCC_PR_CheckToken(")"))
{
@ -3895,34 +3898,6 @@ QCC_def_t *QCC_PR_ParseFunctionCall (QCC_def_t *func) //warning, the func could
}
}
if (pr_classtype && e->type->type == ev_field && p->type != ev_field)
{ //convert.
oself = QCC_PR_GetDef(type_entity, "self", NULL, true, 0, false);
switch(e->type->aux_type->type)
{
case ev_string:
e = QCC_PR_Statement(pr_opcodes+OP_LOAD_S, oself, e, NULL);
break;
case ev_integer:
e = QCC_PR_Statement(pr_opcodes+OP_LOAD_I, oself, e, NULL);
break;
case ev_float:
e = QCC_PR_Statement(pr_opcodes+OP_LOAD_F, oself, e, NULL);
break;
case ev_function:
e = QCC_PR_Statement(pr_opcodes+OP_LOAD_FNC, oself, e, NULL);
break;
case ev_vector:
e = QCC_PR_Statement(pr_opcodes+OP_LOAD_V, oself, e, NULL);
break;
case ev_entity:
e = QCC_PR_Statement(pr_opcodes+OP_LOAD_ENT, oself, e, NULL);
break;
default:
QCC_Error(ERR_INTERNAL, "Bad member type. Try forced expansion");
}
}
if (p)
{
if (typecmp(e->type, p))
@ -4430,19 +4405,7 @@ void QCC_PR_EmitClassFromFunction(QCC_def_t *scope, char *tname)
G_FUNCTION(scope->ofs) = df - functions;
//locals here...
ed = QCC_PR_GetDef(type_entity, "ent", pr_scope, true, 0, false);
virt = QCC_PR_GetDef(NULL, "spawn", NULL, false, 0, false);
if (!virt)
QCC_Error(ERR_INTERNAL, "spawn function was not defined\n");
QCC_PR_SimpleStatement(OP_CALL0, virt->ofs, 0, 0, false); //calling convention doesn't come into it.
def_ret.type = ed->type;
QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_STORE_ENT], &def_ret, ed, NULL));
ed->references = 1; //there may be no functions.
ed = QCC_PR_GetDef(type_entity, "self", NULL, true, 0, false);
QCC_PR_EmitClassFunctionTable(basetype, basetype, ed);
@ -4456,22 +4419,21 @@ void QCC_PR_EmitClassFromFunction(QCC_def_t *scope, char *tname)
if (constructor)
{ //self = ent;
self = QCC_PR_GetDef(type_entity, "self", NULL, false, 0, false);
oself = QCC_PR_GetDef(type_entity, "oself", scope, !constructed, 0, false);
if (!constructed)
{
QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_STORE_ENT], self, oself, NULL));
constructed = true;
}
// self = QCC_PR_GetDef(type_entity, "self", NULL, false, 0, false);
// oself = QCC_PR_GetDef(type_entity, "oself", scope, !constructed, 0, false);
// if (!constructed)
// {
// QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_STORE_ENT], self, oself, NULL));
// constructed = true;
// }
constructor->references++;
QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_STORE_ENT], ed, self, NULL)); //return to our old self. boom boom.
// QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_STORE_ENT], ed, self, NULL)); //return to our old self.
QCC_PR_SimpleStatement(OP_CALL0, constructor->ofs, 0, 0, false);
}
}
if (constructed)
QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_STORE_ENT], oself, self, NULL));
// if (constructed)
// QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_STORE_ENT], oself, self, NULL));
QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_RETURN], ed, NULL, NULL)); //apparently we do actually have to return something. *sigh*...
QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_DONE], NULL, NULL, NULL));
@ -4483,16 +4445,115 @@ void QCC_PR_EmitClassFromFunction(QCC_def_t *scope, char *tname)
df->numparms = locals_end - locals_start;
}
QCC_def_t *QCC_PR_ParseValue (QCC_type_t *assumeclass, pbool allowarrayassign);
static QCC_def_t *QCC_PR_ExpandField(QCC_def_t *ent, QCC_def_t *field)
{
QCC_def_t *r, *tmp;
if (field->type->type != ev_field || !field->type->aux_type)
{
QCC_PR_ParseWarning(ERR_INTERNAL, "QCC_PR_ExpandField: invalid field type");
QCC_PR_ParsePrintDef(ERR_INTERNAL, field);
r = QCC_PR_Statement(&pr_opcodes[OP_LOAD_FLD], ent, field, NULL);
}
else
{
switch(field->type->aux_type->type)
{
default:
QCC_PR_ParseWarning(ERR_INTERNAL, "QCC_PR_ExpandField: invalid field type");
QCC_PR_ParsePrintDef(ERR_INTERNAL, field);
break;
case ev_integer:
r = QCC_PR_Statement(&pr_opcodes[OP_LOAD_I], ent, field, NULL);
break;
case ev_pointer:
r = QCC_PR_Statement(&pr_opcodes[OP_LOAD_P], ent, field, NULL);
tmp = (void *)qccHunkAlloc (sizeof(QCC_def_t));
memset (tmp, 0, sizeof(QCC_def_t));
tmp->type = field->type->aux_type;
tmp->ofs = r->ofs;
tmp->temp = r->temp;
tmp->constant = false;
tmp->name = r->name;
r = tmp;
break;
case ev_field:
r = QCC_PR_Statement(&pr_opcodes[OP_LOAD_FLD], ent, field, NULL);
tmp = (void *)qccHunkAlloc (sizeof(QCC_def_t));
memset (tmp, 0, sizeof(QCC_def_t));
tmp->type = field->type->aux_type;
tmp->ofs = r->ofs;
tmp->temp = r->temp;
tmp->constant = false;
tmp->name = r->name;
r = tmp;
break;
case ev_float:
r = QCC_PR_Statement(&pr_opcodes[OP_LOAD_F], ent, field, NULL);
break;
case ev_string:
r = QCC_PR_Statement(&pr_opcodes[OP_LOAD_S], ent, field, NULL);
break;
case ev_vector:
r = QCC_PR_Statement(&pr_opcodes[OP_LOAD_V], ent, field, NULL);
break;
case ev_function:
//e.f.func() should call the function after switching the 'this' (aka: self) argument.
//which requires that we actually track what the new 'this' is.
//FIXME: maybe we should have a thiscall attribute instead? need to relax the check in QCC_PR_ParseField to any entity type
if (ent->type->parentclass && QCC_PR_CheckToken("("))
{
QCC_def_t *nthis = ent;
if (ent->temp)
{
//we need to make sure that d does not get clobbered by the load_fld.
//note that this is kinda inefficient as we'll be copying this value into self later on anyway.
QCC_def_t *t = QCC_GetTemp(type_entity);
nthis = QCC_PR_Statement(&pr_opcodes[OP_LOAD_ENT], nthis, t, NULL);
QCC_UnFreeTemp(nthis);
}
r = QCC_PR_Statement(&pr_opcodes[OP_LOAD_FLD], ent, field, NULL);
tmp = (void *)qccHunkAlloc (sizeof(QCC_def_t));
memset (tmp, 0, sizeof(QCC_def_t));
tmp->type = field->type->aux_type;
tmp->ofs = r->ofs;
tmp->temp = r->temp;
tmp->constant = false;
tmp->name = r->name;
r = tmp;
qcc_usefulstatement=true;
r = QCC_PR_ParseFunctionCall(nthis, r);
r = QCC_PR_ParseArrayPointer(r, true);
}
else
{
r = QCC_PR_Statement(&pr_opcodes[OP_LOAD_FNC], ent, field, NULL);
tmp = (void *)qccHunkAlloc (sizeof(QCC_def_t));
memset (tmp, 0, sizeof(QCC_def_t));
tmp->type = field->type->aux_type;
tmp->ofs = r->ofs;
tmp->temp = r->temp;
tmp->constant = false;
tmp->name = r->name;
r = tmp;
}
break;
case ev_entity:
r = QCC_PR_Statement(&pr_opcodes[OP_LOAD_ENT], ent, field, NULL);
break;
}
}
return r;
}
/*checks for <DEF>.foo an expands in a class-aware fashion
normally invoked via QCC_PR_ParseArrayPointer
*/
static QCC_def_t *QCC_PR_ParseField(QCC_def_t *d)
{
QCC_def_t *tmp;
QCC_type_t *t;
t = d->type;
if (keyword_class && t->type == ev_entity && t->parentclass && (QCC_PR_CheckToken(".") || QCC_PR_CheckToken("->")))
if (t->type == ev_entity && (QCC_PR_CheckToken(".") || QCC_PR_CheckToken("->")))
{
QCC_def_t *field;
if (QCC_PR_CheckToken("("))
@ -4501,74 +4562,13 @@ static QCC_def_t *QCC_PR_ParseField(QCC_def_t *d)
QCC_PR_Expect(")");
}
else
field = QCC_PR_ParseValue(d->type, false);
field = QCC_PR_ParseValue(d->type, false, false);
if (field->type->type == ev_field)
{
if (!field->type->aux_type)
{
QCC_PR_ParseWarning(ERR_INTERNAL, "Field with null aux_type");
d = QCC_PR_Statement(&pr_opcodes[OP_LOAD_FLD], d, field, NULL);
}
else
{
switch(field->type->aux_type->type)
{
default:
QCC_PR_ParseError(ERR_INTERNAL, "Bad field type");
break;
case ev_integer:
d = QCC_PR_Statement(&pr_opcodes[OP_LOAD_I], d, field, NULL);
break;
case ev_pointer:
d = QCC_PR_Statement(&pr_opcodes[OP_LOAD_P], d, field, NULL);
tmp = (void *)qccHunkAlloc (sizeof(QCC_def_t));
memset (tmp, 0, sizeof(QCC_def_t));
tmp->type = field->type->aux_type;
tmp->ofs = d->ofs;
tmp->temp = d->temp;
tmp->constant = false;
tmp->name = d->name;
d = tmp;
break;
case ev_field:
d = QCC_PR_Statement(&pr_opcodes[OP_LOAD_FLD], d, field, NULL);
tmp = (void *)qccHunkAlloc (sizeof(QCC_def_t));
memset (tmp, 0, sizeof(QCC_def_t));
tmp->type = field->type->aux_type;
tmp->ofs = d->ofs;
tmp->temp = d->temp;
tmp->constant = false;
tmp->name = d->name;
d = tmp;
break;
case ev_float:
d = QCC_PR_Statement(&pr_opcodes[OP_LOAD_F], d, field, NULL);
break;
case ev_string:
d = QCC_PR_Statement(&pr_opcodes[OP_LOAD_S], d, field, NULL);
break;
case ev_vector:
d = QCC_PR_Statement(&pr_opcodes[OP_LOAD_V], d, field, NULL);
break;
case ev_function:
d = QCC_PR_Statement(&pr_opcodes[OP_LOAD_FNC], d, field, NULL);
tmp = (void *)qccHunkAlloc (sizeof(QCC_def_t));
memset (tmp, 0, sizeof(QCC_def_t));
tmp->type = field->type->aux_type;
tmp->ofs = d->ofs;
tmp->temp = d->temp;
tmp->constant = false;
tmp->name = d->name;
d = tmp;
break;
case ev_entity:
d = QCC_PR_Statement(&pr_opcodes[OP_LOAD_ENT], d, field, NULL);
break;
}
}
}
d = QCC_PR_ExpandField(d, field);
else
QCC_PR_ParseError(ERR_INTERNAL, "Bad field type");
d = QCC_PR_ParseField(d);
}
return d;
}
@ -5007,7 +5007,7 @@ PR_ParseValue
Returns the global ofs for the current token
============
*/
QCC_def_t *QCC_PR_ParseValue (QCC_type_t *assumeclass, pbool allowarrayassign)
QCC_def_t *QCC_PR_ParseValue (QCC_type_t *assumeclass, pbool allowarrayassign, pbool expandmemberfields)
{
QCC_def_t *d, *od;
QCC_type_t *t;
@ -5102,13 +5102,20 @@ QCC_def_t *QCC_PR_ParseValue (QCC_type_t *assumeclass, pbool allowarrayassign)
}
if (QCC_PR_CheckToken("::"))
{
assumeclass = NULL;
expandmemberfields = false; //::classname is always usable for eg: the find builtin.
}
name = QCC_PR_ParseName ();
if (QCC_PR_CheckToken("::"))
{
expandmemberfields = false; //this::classname should also be available to the find builtin, etc. this won't affect self.classname::member nor classname::staticfunc
if (assumeclass && !strcmp(name, "super"))
t = assumeclass->parentclass;
else if (assumeclass && !strcmp(name, "this"))
t = assumeclass;
else
t = QCC_TypeForName(name);
if (!t || t->type != ev_entity)
@ -5124,6 +5131,7 @@ QCC_def_t *QCC_PR_ParseValue (QCC_type_t *assumeclass, pbool allowarrayassign)
//walk up the parents if needed, to find one that has that field
for(d = NULL, p = t; !d && p; p = p->parentclass)
{
//use static functions in preference to virtual functions. kinda needed so you can use super::func...
sprintf(membername, "%s::%s", p->name, name);
d = QCC_PR_GetDef (NULL, membername, pr_scope, false, 0, false);
if (!d)
@ -5147,7 +5155,7 @@ QCC_def_t *QCC_PR_ParseValue (QCC_type_t *assumeclass, pbool allowarrayassign)
// look through the defs
d = QCC_PR_GetDef (NULL, name, pr_scope, false, 0, false);
// 'testvar' becomes 'self::testvar'
// 'testvar' becomes 'this::testvar'
if (assumeclass && assumeclass->parentclass)
{ //try getting a member.
QCC_type_t *type;
@ -5201,23 +5209,32 @@ QCC_def_t *QCC_PR_ParseValue (QCC_type_t *assumeclass, pbool allowarrayassign)
}
}
if (pr_classtype && !strcmp(name, "self"))
if (assumeclass && pr_classtype && !strcmp(name, "self"))
{
//use 'this' instead.
QCC_def_t *t = QCC_PR_GetDef(NULL, "this", pr_scope, false, 0, false);
if (!t)
t = QCC_PR_DummyDef(pr_classtype, "this", pr_scope, 0, d->ofs, true, GDF_CONST);
d = t;
QCC_PR_ParseWarning (WARN_SELFNOTTHIS, "'self' used inside OO function, use 'this'.", pr_scope->name);
if (!pr_classtype)
QCC_PR_ParseError(ERR_NOTANAME, "Cannot use 'this' outside of an OO function\n");
d = QCC_PR_GetDef(NULL, "this", pr_scope, false, 0, false);
if (!d)
{
od = QCC_PR_GetDef(NULL, "self", NULL, true, 0, false);
d = QCC_PR_DummyDef(pr_classtype, "this", pr_scope, 0, od->ofs, true, GDF_CONST);
}
}
d = QCC_PR_ParseArrayPointer(d, allowarrayassign);
d = QCC_PR_ParseField(d);
if (pr_classtype && expandmemberfields && d->type->type == ev_field)
{
QCC_def_t *t;
if (assumeclass)
{
t = QCC_PR_GetDef(NULL, "this", pr_scope, false, 0, false);
if (!t)
t = QCC_PR_DummyDef(pr_classtype, "this", pr_scope, 0, QCC_PR_GetDef(NULL, "self", NULL, true, 0, false)->ofs, true, GDF_CONST);
}
else
t = QCC_PR_GetDef(NULL, "self", NULL, true, 0, false);
d = QCC_PR_ExpandField(t, d);
}
return d;
}
@ -5528,7 +5545,7 @@ QCC_def_t *QCC_PR_Term (int exprflags)
return e;
}
}
return QCC_PR_ParseValue (pr_classtype, !(exprflags&EXPR_DISALLOW_ARRAYASSIGN));
return QCC_PR_ParseValue (pr_classtype, !(exprflags&EXPR_DISALLOW_ARRAYASSIGN), true);
}
@ -5599,7 +5616,7 @@ QCC_def_t *QCC_PR_Expression (int priority, int exprflags)
if (QCC_PR_CheckToken ("(") )
{
qcc_usefulstatement=true;
e = QCC_PR_ParseFunctionCall (e);
e = QCC_PR_ParseFunctionCall (NULL, e);
e = QCC_PR_ParseArrayPointer(e, true);
}
if (QCC_PR_CheckToken ("?"))
@ -7167,7 +7184,7 @@ void QCC_PR_ParseAsm(void)
{
patch1 = &statements[numstatements];
a = QCC_PR_ParseValue(pr_classtype, false);
a = QCC_PR_ParseValue(pr_classtype, false, false);
QCC_PR_Statement3(&pr_opcodes[op], a, NULL, NULL, true);
if (pr_token_type == tt_name)
@ -7186,8 +7203,8 @@ void QCC_PR_ParseAsm(void)
{
patch1 = &statements[numstatements];
a = QCC_PR_ParseValue(pr_classtype, false);
b = QCC_PR_ParseValue(pr_classtype, false);
a = QCC_PR_ParseValue(pr_classtype, false, false);
b = QCC_PR_ParseValue(pr_classtype, false, false);
QCC_PR_Statement3(&pr_opcodes[op], a, b, NULL, true);
if (pr_token_type == tt_name)
@ -7206,15 +7223,15 @@ void QCC_PR_ParseAsm(void)
else
{
if (pr_opcodes[op].type_a != &type_void)
a = QCC_PR_ParseValue(pr_classtype, false);
a = QCC_PR_ParseValue(pr_classtype, false, false);
else
a=NULL;
if (pr_opcodes[op].type_b != &type_void)
b = QCC_PR_ParseValue(pr_classtype, false);
b = QCC_PR_ParseValue(pr_classtype, false, false);
else
b=NULL;
if (pr_opcodes[op].associative==ASSOC_LEFT && pr_opcodes[op].type_c != &type_void)
c = QCC_PR_ParseValue(pr_classtype, false);
c = QCC_PR_ParseValue(pr_classtype, false, false);
else
c=NULL;

View File

@ -1843,9 +1843,9 @@ int QCC_PR_FinishCompilation (void)
QCC_PR_EmitArraySetFunction(d, d->name+9);
pr_scope = NULL;
}
else if (!strncmp(d->name, "Class*", 6))
else if (!strncmp(d->name, "spawnfunc_", 10))
{
QCC_PR_EmitClassFromFunction(d, d->name+6);
QCC_PR_EmitClassFromFunction(d, d->name+10);
pr_scope = NULL;
}
else