Merge pull request #219 from alliedmodders/static-methods
Add support for static methods on methodmaps.
This commit is contained in:
commit
f9d92b0eba
@ -449,6 +449,21 @@ static cell_t TopMenu_AddCategory(IPluginContext *pContext, const cell_t *params
|
|||||||
return AddToTopMenu(pContext, new_params);
|
return AddToTopMenu(pContext, new_params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static cell_t TopMenu_FromHandle(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
HandleError err;
|
||||||
|
TopMenu *pMenu;
|
||||||
|
HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity());
|
||||||
|
|
||||||
|
if ((err = handlesys->ReadHandle(params[1], hTopMenuType, &sec, (void **)&pMenu))
|
||||||
|
!= HandleError_None)
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
|
||||||
|
}
|
||||||
|
|
||||||
|
return params[1];
|
||||||
|
}
|
||||||
|
|
||||||
sp_nativeinfo_t g_TopMenuNatives[] =
|
sp_nativeinfo_t g_TopMenuNatives[] =
|
||||||
{
|
{
|
||||||
{"AddToTopMenu", AddToTopMenu},
|
{"AddToTopMenu", AddToTopMenu},
|
||||||
@ -474,6 +489,7 @@ sp_nativeinfo_t g_TopMenuNatives[] =
|
|||||||
{"TopMenu.GetInfoString", GetTopMenuInfoString},
|
{"TopMenu.GetInfoString", GetTopMenuInfoString},
|
||||||
{"TopMenu.GetObjName", GetTopMenuName},
|
{"TopMenu.GetObjName", GetTopMenuName},
|
||||||
{"TopMenu.CacheTitles.set", SetTopMenuTitleCaching},
|
{"TopMenu.CacheTitles.set", SetTopMenuTitleCaching},
|
||||||
|
{"TopMenu.FromHandle", TopMenu_FromHandle},
|
||||||
|
|
||||||
{NULL, NULL},
|
{NULL, NULL},
|
||||||
};
|
};
|
||||||
|
@ -124,8 +124,10 @@ LoadBanReasons()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public OnAdminMenuReady(TopMenu topmenu)
|
public OnAdminMenuReady(Handle aTopMenu)
|
||||||
{
|
{
|
||||||
|
TopMenu topmenu = TopMenu.FromHandle(aTopMenu);
|
||||||
|
|
||||||
/* Block us from being called twice */
|
/* Block us from being called twice */
|
||||||
if (topmenu == hTopMenu)
|
if (topmenu == hTopMenu)
|
||||||
{
|
{
|
||||||
|
@ -100,8 +100,10 @@ public OnPluginStart()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public OnAdminMenuReady(TopMenu topmenu)
|
public OnAdminMenuReady(Handle aTopMenu)
|
||||||
{
|
{
|
||||||
|
TopMenu topmenu = TopMenu.FromHandle(aTopMenu);
|
||||||
|
|
||||||
/* Block us from being called twice */
|
/* Block us from being called twice */
|
||||||
if (topmenu == hTopMenu)
|
if (topmenu == hTopMenu)
|
||||||
{
|
{
|
||||||
|
@ -146,8 +146,10 @@ bool:IsClientAllowedToChangeCvar(client, const String:cvarname[])
|
|||||||
return allowed;
|
return allowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OnAdminMenuReady(TopMenu topmenu)
|
public OnAdminMenuReady(Handle aTopMenu)
|
||||||
{
|
{
|
||||||
|
TopMenu topmenu = TopMenu.FromHandle(aTopMenu);
|
||||||
|
|
||||||
/* Block us from being called twice */
|
/* Block us from being called twice */
|
||||||
if (topmenu == hTopMenu)
|
if (topmenu == hTopMenu)
|
||||||
{
|
{
|
||||||
|
@ -132,8 +132,10 @@ public OnConfigsExecuted()
|
|||||||
g_mapCount = LoadMapList(g_MapList);
|
g_mapCount = LoadMapList(g_MapList);
|
||||||
}
|
}
|
||||||
|
|
||||||
public OnAdminMenuReady(TopMenu topmenu)
|
public OnAdminMenuReady(Handle aTopMenu)
|
||||||
{
|
{
|
||||||
|
TopMenu topmenu = TopMenu.FromHandle(aTopMenu);
|
||||||
|
|
||||||
/* Block us from being called twice */
|
/* Block us from being called twice */
|
||||||
if (topmenu == hTopMenu)
|
if (topmenu == hTopMenu)
|
||||||
{
|
{
|
||||||
|
@ -258,8 +258,10 @@ public Action:Event_RoundEnd(Handle:event,const String:name[],bool:dontBroadcast
|
|||||||
KillAllDrugs();
|
KillAllDrugs();
|
||||||
}
|
}
|
||||||
|
|
||||||
public OnAdminMenuReady(TopMenu topmenu)
|
public OnAdminMenuReady(Handle aTopMenu)
|
||||||
{
|
{
|
||||||
|
TopMenu topmenu = TopMenu.FromHandle(aTopMenu);
|
||||||
|
|
||||||
/* Block us from being called twice */
|
/* Block us from being called twice */
|
||||||
if (topmenu == hTopMenu)
|
if (topmenu == hTopMenu)
|
||||||
{
|
{
|
||||||
|
@ -135,8 +135,10 @@ public OnPluginStart()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public OnAdminMenuReady(TopMenu topmenu)
|
public OnAdminMenuReady(Handle aTopMenu)
|
||||||
{
|
{
|
||||||
|
TopMenu topmenu = TopMenu.FromHandle(aTopMenu);
|
||||||
|
|
||||||
/* Block us from being called twice */
|
/* Block us from being called twice */
|
||||||
if (topmenu == hTopMenu)
|
if (topmenu == hTopMenu)
|
||||||
{
|
{
|
||||||
|
@ -65,7 +65,7 @@
|
|||||||
* @param topmenu Handle to the admin menu's TopMenu.
|
* @param topmenu Handle to the admin menu's TopMenu.
|
||||||
* @noreturn
|
* @noreturn
|
||||||
*/
|
*/
|
||||||
forward OnAdminMenuCreated(TopMenu topmenu);
|
forward OnAdminMenuCreated(Handle topmenu);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the admin menu is ready to have items added.
|
* Called when the admin menu is ready to have items added.
|
||||||
@ -73,7 +73,7 @@ forward OnAdminMenuCreated(TopMenu topmenu);
|
|||||||
* @param topmenu Handle to the admin menu's TopMenu.
|
* @param topmenu Handle to the admin menu's TopMenu.
|
||||||
* @noreturn
|
* @noreturn
|
||||||
*/
|
*/
|
||||||
forward OnAdminMenuReady(TopMenu topmenu);
|
forward OnAdminMenuReady(Handle topmenu);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the Handle to the admin top menu.
|
* Retrieves the Handle to the admin top menu.
|
||||||
|
@ -146,6 +146,11 @@ methodmap TopMenu < Handle
|
|||||||
// @return A new TopMenu.
|
// @return A new TopMenu.
|
||||||
public native TopMenu(TopMenuHandler handler);
|
public native TopMenu(TopMenuHandler handler);
|
||||||
|
|
||||||
|
// Returns a TopMenu handle from a generic handle. If the given handle is
|
||||||
|
// a TopMenu, the handle is simply casted back. Otherwise, an error is
|
||||||
|
// raised.
|
||||||
|
public static native TopMenu FromHandle(Handle handle);
|
||||||
|
|
||||||
// Re-sorts the items in a TopMenu via a configuration file.
|
// Re-sorts the items in a TopMenu via a configuration file.
|
||||||
//
|
//
|
||||||
// The format of the configuration file should be a Valve Key-Values
|
// The format of the configuration file should be a Valve Key-Values
|
||||||
|
@ -76,8 +76,10 @@ public OnPluginStart()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public OnAdminMenuReady(TopMenu topmenu)
|
public OnAdminMenuReady(Handle aTopMenu)
|
||||||
{
|
{
|
||||||
|
TopMenu topmenu = TopMenu.FromHandle(aTopMenu);
|
||||||
|
|
||||||
/* Block us from being called twice */
|
/* Block us from being called twice */
|
||||||
if (topmenu == hTopMenu)
|
if (topmenu == hTopMenu)
|
||||||
{
|
{
|
||||||
|
@ -103,6 +103,8 @@ typedef struct s_constvalue {
|
|||||||
* tag for enumeration lists */
|
* tag for enumeration lists */
|
||||||
} constvalue;
|
} constvalue;
|
||||||
|
|
||||||
|
struct methodmap_t;
|
||||||
|
|
||||||
/* Symbol table format
|
/* Symbol table format
|
||||||
*
|
*
|
||||||
* The symbol name read from the input file is stored in "name", the
|
* The symbol name read from the input file is stored in "name", the
|
||||||
@ -116,7 +118,6 @@ typedef struct s_constvalue {
|
|||||||
typedef struct s_symbol {
|
typedef struct s_symbol {
|
||||||
struct s_symbol *next;
|
struct s_symbol *next;
|
||||||
struct s_symbol *parent; /* hierarchical types */
|
struct s_symbol *parent; /* hierarchical types */
|
||||||
struct s_symbol *target; /* proxy target */
|
|
||||||
char name[sNAMEMAX+1];
|
char name[sNAMEMAX+1];
|
||||||
uint32_t hash; /* value derived from name, for quicker searching */
|
uint32_t hash; /* value derived from name, for quicker searching */
|
||||||
cell addr; /* address or offset (or value for constant, index for native function) */
|
cell addr; /* address or offset (or value for constant, index for native function) */
|
||||||
@ -151,6 +152,7 @@ typedef struct s_symbol {
|
|||||||
struct s_symbol **refer; /* referrer list, functions that "use" this symbol */
|
struct s_symbol **refer; /* referrer list, functions that "use" this symbol */
|
||||||
int numrefers; /* number of entries in the referrer list */
|
int numrefers; /* number of entries in the referrer list */
|
||||||
char *documentation; /* optional documentation string */
|
char *documentation; /* optional documentation string */
|
||||||
|
methodmap_t *methodmap; /* if ident == iMETHODMAP */
|
||||||
} symbol;
|
} symbol;
|
||||||
|
|
||||||
/* Possible entries for "ident". These are used in the "symbol", "value"
|
/* Possible entries for "ident". These are used in the "symbol", "value"
|
||||||
@ -170,8 +172,8 @@ typedef struct s_symbol {
|
|||||||
#define iFUNCTN 9
|
#define iFUNCTN 9
|
||||||
#define iREFFUNC 10
|
#define iREFFUNC 10
|
||||||
#define iVARARGS 11 /* function specified ... as argument(s) */
|
#define iVARARGS 11 /* function specified ... as argument(s) */
|
||||||
#define iPROXY 12 /* proxies to another symbol. */
|
|
||||||
#define iACCESSOR 13 /* property accessor via a methodmap_method_t */
|
#define iACCESSOR 13 /* property accessor via a methodmap_method_t */
|
||||||
|
#define iMETHODMAP 14 /* symbol defining a methodmap */
|
||||||
|
|
||||||
/* Possible entries for "usage"
|
/* Possible entries for "usage"
|
||||||
*
|
*
|
||||||
@ -227,7 +229,6 @@ typedef struct s_symbol {
|
|||||||
#define uRETNONE 0x10
|
#define uRETNONE 0x10
|
||||||
|
|
||||||
#define flgDEPRECATED 0x01 /* symbol is deprecated (avoid use) */
|
#define flgDEPRECATED 0x01 /* symbol is deprecated (avoid use) */
|
||||||
#define flgPROXIED 0x02 /* symbol has incoming proxy */
|
|
||||||
|
|
||||||
#define uCOUNTOF 0x20 /* set in the "hasdefault" field of the arginfo struct */
|
#define uCOUNTOF 0x20 /* set in the "hasdefault" field of the arginfo struct */
|
||||||
#define uTAGOF 0x40 /* set in the "hasdefault" field of the arginfo struct */
|
#define uTAGOF 0x40 /* set in the "hasdefault" field of the arginfo struct */
|
||||||
@ -246,7 +247,6 @@ struct methodmap_method_s;
|
|||||||
|
|
||||||
typedef struct value_s {
|
typedef struct value_s {
|
||||||
symbol *sym; /* symbol in symbol table, NULL for (constant) expression */
|
symbol *sym; /* symbol in symbol table, NULL for (constant) expression */
|
||||||
symbol *proxy; /* original symbol if resolved via a proxy */
|
|
||||||
cell constval; /* value of the constant expression (if ident==iCONSTEXPR)
|
cell constval; /* value of the constant expression (if ident==iCONSTEXPR)
|
||||||
* also used for the size of a literal array */
|
* also used for the size of a literal array */
|
||||||
int tag; /* tag (of the expression) */
|
int tag; /* tag (of the expression) */
|
||||||
@ -678,7 +678,7 @@ void delete_symbol(symbol *root,symbol *sym);
|
|||||||
void delete_symbols(symbol *root,int level,int del_labels,int delete_functions);
|
void delete_symbols(symbol *root,int level,int del_labels,int delete_functions);
|
||||||
int refer_symbol(symbol *entry,symbol *bywhom);
|
int refer_symbol(symbol *entry,symbol *bywhom);
|
||||||
void markusage(symbol *sym,int usage);
|
void markusage(symbol *sym,int usage);
|
||||||
symbol *findglb(const char *name,int filter,symbol **alias = NULL);
|
symbol *findglb(const char *name,int filter);
|
||||||
symbol *findloc(const char *name);
|
symbol *findloc(const char *name);
|
||||||
symbol *findconst(const char *name,int *matchtag);
|
symbol *findconst(const char *name,int *matchtag);
|
||||||
symbol *finddepend(const symbol *parent);
|
symbol *finddepend(const symbol *parent);
|
||||||
|
@ -3570,32 +3570,6 @@ static void check_void_decl(const declinfo_t *decl, int variable)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void define_constructor(methodmap_t *map, methodmap_method_t *method)
|
|
||||||
{
|
|
||||||
symbol *sym = findglb(map->name, sGLOBAL);
|
|
||||||
|
|
||||||
if (sym) {
|
|
||||||
const char *type = "__unknown__";
|
|
||||||
switch (sym->ident) {
|
|
||||||
case iVARIABLE:
|
|
||||||
case iARRAY:
|
|
||||||
case iARRAYCELL:
|
|
||||||
case iARRAYCHAR:
|
|
||||||
type = "variable";
|
|
||||||
break;
|
|
||||||
case iFUNCTN:
|
|
||||||
type = "function";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
error(113, map->name, type);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sym = addsym(map->name, 0, iPROXY, sGLOBAL, 0, 0);
|
|
||||||
sym->target = method->target;
|
|
||||||
method->target->flags |= flgPROXIED;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Current lexer position is, we've parsed "public", an optional "native", and
|
// Current lexer position is, we've parsed "public", an optional "native", and
|
||||||
// a type expression.
|
// a type expression.
|
||||||
//
|
//
|
||||||
@ -3651,7 +3625,13 @@ static void make_primitive(typeinfo_t *type, int tag)
|
|||||||
type->ident = iVARIABLE;
|
type->ident = iVARIABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
symbol *parse_inline_function(methodmap_t *map, const typeinfo_t *type, const char *name, int is_native, int is_ctor, int is_dtor)
|
symbol *parse_inline_function(methodmap_t *map,
|
||||||
|
const typeinfo_t *type,
|
||||||
|
const char *name,
|
||||||
|
int is_native,
|
||||||
|
int is_ctor,
|
||||||
|
int is_dtor,
|
||||||
|
bool is_static)
|
||||||
{
|
{
|
||||||
declinfo_t decl;
|
declinfo_t decl;
|
||||||
memset(&decl, 0, sizeof(decl));
|
memset(&decl, 0, sizeof(decl));
|
||||||
@ -3666,7 +3646,7 @@ symbol *parse_inline_function(methodmap_t *map, const typeinfo_t *type, const ch
|
|||||||
decl.type.is_new = TRUE;
|
decl.type.is_new = TRUE;
|
||||||
|
|
||||||
const int *thistag = NULL;
|
const int *thistag = NULL;
|
||||||
if (!is_ctor)
|
if (!is_ctor && !is_static)
|
||||||
thistag = &map->tag;
|
thistag = &map->tag;
|
||||||
|
|
||||||
// Build a new symbol. Construct a temporary name including the class.
|
// Build a new symbol. Construct a temporary name including the class.
|
||||||
@ -3778,7 +3758,7 @@ int parse_property_accessor(const typeinfo_t *type, methodmap_t *map, methodmap_
|
|||||||
ret_type = &voidtype;
|
ret_type = &voidtype;
|
||||||
}
|
}
|
||||||
|
|
||||||
target = parse_inline_function(map, ret_type, tmpname, is_native, FALSE, FALSE);
|
target = parse_inline_function(map, ret_type, tmpname, is_native, FALSE, FALSE, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!target)
|
if (!target)
|
||||||
@ -3877,8 +3857,12 @@ methodmap_method_t *parse_method(methodmap_t *map)
|
|||||||
int is_dtor = 0;
|
int is_dtor = 0;
|
||||||
int is_bind = 0;
|
int is_bind = 0;
|
||||||
int is_native = 0;
|
int is_native = 0;
|
||||||
|
bool is_static = false;
|
||||||
const char *spectype = layout_spec_name(map->spec);
|
const char *spectype = layout_spec_name(map->spec);
|
||||||
|
|
||||||
|
if (matchtoken(tSTATIC))
|
||||||
|
is_static = true;
|
||||||
|
|
||||||
// This stores the name of the method (for destructors, we add a ~).
|
// This stores the name of the method (for destructors, we add a ~).
|
||||||
token_ident_t ident;
|
token_ident_t ident;
|
||||||
strcpy(ident.name, "__unknown__");
|
strcpy(ident.name, "__unknown__");
|
||||||
@ -3890,7 +3874,8 @@ methodmap_method_t *parse_method(methodmap_t *map)
|
|||||||
typeinfo_t type;
|
typeinfo_t type;
|
||||||
memset(&type, 0, sizeof(type));
|
memset(&type, 0, sizeof(type));
|
||||||
|
|
||||||
if (matchtoken('~')) {
|
// Destructors cannot be static.
|
||||||
|
if (!is_static && matchtoken('~')) {
|
||||||
// We got something like "public ~Blah = X"
|
// We got something like "public ~Blah = X"
|
||||||
is_bind = TRUE;
|
is_bind = TRUE;
|
||||||
is_dtor = TRUE;
|
is_dtor = TRUE;
|
||||||
@ -3977,6 +3962,11 @@ methodmap_method_t *parse_method(methodmap_t *map)
|
|||||||
error(114, "constructor", spectype, map->name);
|
error(114, "constructor", spectype, map->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_ctor && is_static) {
|
||||||
|
// Constructors may not be static.
|
||||||
|
error(175);
|
||||||
|
}
|
||||||
|
|
||||||
symbol *target = NULL;
|
symbol *target = NULL;
|
||||||
if (is_bind) {
|
if (is_bind) {
|
||||||
// Find an existing symbol.
|
// Find an existing symbol.
|
||||||
@ -3986,7 +3976,7 @@ methodmap_method_t *parse_method(methodmap_t *map)
|
|||||||
else if (target->ident != iFUNCTN)
|
else if (target->ident != iFUNCTN)
|
||||||
error(10);
|
error(10);
|
||||||
} else {
|
} else {
|
||||||
target = parse_inline_function(map, &type, ident.name, is_native, is_ctor, is_dtor);
|
target = parse_inline_function(map, &type, ident.name, is_native, is_ctor, is_dtor, is_static);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!target)
|
if (!target)
|
||||||
@ -4024,12 +4014,15 @@ methodmap_method_t *parse_method(methodmap_t *map)
|
|||||||
method->target = target;
|
method->target = target;
|
||||||
method->getter = NULL;
|
method->getter = NULL;
|
||||||
method->setter = NULL;
|
method->setter = NULL;
|
||||||
|
method->is_static = is_static;
|
||||||
|
|
||||||
// If the symbol is a constructor, we bypass the initial argument checks.
|
// If the symbol is a constructor, we bypass the initial argument checks.
|
||||||
if (is_ctor) {
|
if (is_ctor) {
|
||||||
define_constructor(map, method);
|
if (map->ctor)
|
||||||
} else if (!check_this_tag(map, target)) {
|
error(113, map->name);
|
||||||
error(108, spectype, map->name);
|
} else if (!is_static) {
|
||||||
|
if (!check_this_tag(map, target))
|
||||||
|
error(108, spectype, map->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_dtor)
|
if (is_dtor)
|
||||||
@ -4049,7 +4042,6 @@ static void domethodmap(LayoutSpec spec)
|
|||||||
{
|
{
|
||||||
int val;
|
int val;
|
||||||
char *str;
|
char *str;
|
||||||
LayoutSpec old_spec;
|
|
||||||
methodmap_t *parent = NULL;
|
methodmap_t *parent = NULL;
|
||||||
const char *spectype = layout_spec_name(spec);
|
const char *spectype = layout_spec_name(spec);
|
||||||
|
|
||||||
@ -4062,8 +4054,9 @@ static void domethodmap(LayoutSpec spec)
|
|||||||
if (!isupper(*mapname))
|
if (!isupper(*mapname))
|
||||||
error(109, spectype);
|
error(109, spectype);
|
||||||
|
|
||||||
old_spec = deduce_layout_spec_by_name(mapname);
|
LayoutSpec old_spec = deduce_layout_spec_by_name(mapname);
|
||||||
if (!can_redef_layout_spec(spec, old_spec))
|
int can_redef = can_redef_layout_spec(spec, old_spec);
|
||||||
|
if (!can_redef)
|
||||||
error(110, mapname, layout_spec_name(old_spec));
|
error(110, mapname, layout_spec_name(old_spec));
|
||||||
|
|
||||||
if (matchtoken('<')) {
|
if (matchtoken('<')) {
|
||||||
@ -4093,6 +4086,46 @@ static void domethodmap(LayoutSpec spec)
|
|||||||
}
|
}
|
||||||
methodmap_add(map);
|
methodmap_add(map);
|
||||||
|
|
||||||
|
if (can_redef) {
|
||||||
|
symbol *sym = findglb(mapname, sGLOBAL);
|
||||||
|
if (sym && sym->ident != iMETHODMAP) {
|
||||||
|
// We should only hit this on the first pass. Assert really hard that
|
||||||
|
// we're about to kill an enum definition and not something random.
|
||||||
|
assert(sc_status == statFIRST);
|
||||||
|
assert(sym->ident == iCONSTEXPR);
|
||||||
|
assert(TAGID(map->tag) == TAGID(sym->tag));
|
||||||
|
|
||||||
|
sym->ident = iMETHODMAP;
|
||||||
|
|
||||||
|
// Kill previous enumstruct properties, if any.
|
||||||
|
if (sym->usage & uENUMROOT) {
|
||||||
|
for (constvalue *cv = sym->dim.enumlist; cv; cv = cv->next) {
|
||||||
|
symbol *csym = findglb(cv->name, sGLOBAL);
|
||||||
|
if (csym &&
|
||||||
|
csym->ident == iCONSTEXPR &&
|
||||||
|
csym->parent == sym &&
|
||||||
|
(csym->usage & uENUMFIELD))
|
||||||
|
{
|
||||||
|
csym->usage &= ~uENUMFIELD;
|
||||||
|
csym->parent = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete_consttable(sym->dim.enumlist);
|
||||||
|
free(sym->dim.enumlist);
|
||||||
|
sym->dim.enumlist = NULL;
|
||||||
|
}
|
||||||
|
} else if (!sym) {
|
||||||
|
sym = addsym(
|
||||||
|
mapname, // name
|
||||||
|
0, // addr
|
||||||
|
iMETHODMAP, // ident
|
||||||
|
sGLOBAL, // vclass
|
||||||
|
map->tag, // tag
|
||||||
|
uDEFINE); // usage
|
||||||
|
}
|
||||||
|
sym->methodmap = map;
|
||||||
|
}
|
||||||
|
|
||||||
needtoken('{');
|
needtoken('{');
|
||||||
while (!matchtoken('}')) {
|
while (!matchtoken('}')) {
|
||||||
token_t tok;
|
token_t tok;
|
||||||
@ -4587,8 +4620,8 @@ static void decl_enum(int vclass)
|
|||||||
int tag,explicittag;
|
int tag,explicittag;
|
||||||
cell increment,multiplier;
|
cell increment,multiplier;
|
||||||
constvalue *enumroot;
|
constvalue *enumroot;
|
||||||
symbol *enumsym;
|
|
||||||
LayoutSpec spec;
|
LayoutSpec spec;
|
||||||
|
symbol *enumsym = nullptr;
|
||||||
|
|
||||||
/* get an explicit tag, if any (we need to remember whether an explicit
|
/* get an explicit tag, if any (we need to remember whether an explicit
|
||||||
* tag was passed, even if that explicit tag was "_:", so we cannot call
|
* tag was passed, even if that explicit tag was "_:", so we cannot call
|
||||||
@ -4655,19 +4688,35 @@ static void decl_enum(int vclass)
|
|||||||
} /* if */
|
} /* if */
|
||||||
|
|
||||||
if (strlen(enumname)>0) {
|
if (strlen(enumname)>0) {
|
||||||
/* already create the root symbol, so the fields can have it as their "parent" */
|
if (vclass == sGLOBAL) {
|
||||||
enumsym=add_constant(enumname,0,vclass,tag);
|
if ((enumsym = findglb(enumname, vclass)) != NULL) {
|
||||||
if (enumsym!=NULL)
|
// If we were previously defined as a methodmap, don't overwrite the
|
||||||
enumsym->usage |= uENUMROOT;
|
// symbol. Otherwise, flow into add_constant where we will error.
|
||||||
/* start a new list for the element names */
|
if (enumsym->ident != iMETHODMAP)
|
||||||
if ((enumroot=(constvalue*)malloc(sizeof(constvalue)))==NULL)
|
enumsym = nullptr;
|
||||||
error(FATAL_ERROR_OOM); /* insufficient memory (fatal error) */
|
}
|
||||||
memset(enumroot,0,sizeof(constvalue));
|
}
|
||||||
|
|
||||||
|
if (!enumsym) {
|
||||||
|
/* create the root symbol, so the fields can have it as their "parent" */
|
||||||
|
enumsym=add_constant(enumname,0,vclass,tag);
|
||||||
|
if (enumsym!=NULL)
|
||||||
|
enumsym->usage |= uENUMROOT;
|
||||||
|
/* start a new list for the element names */
|
||||||
|
if ((enumroot=(constvalue*)malloc(sizeof(constvalue)))==NULL)
|
||||||
|
error(FATAL_ERROR_OOM); /* insufficient memory (fatal error) */
|
||||||
|
memset(enumroot,0,sizeof(constvalue));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
enumsym=NULL;
|
enumsym=NULL;
|
||||||
enumroot=NULL;
|
enumroot=NULL;
|
||||||
} /* if */
|
} /* if */
|
||||||
|
|
||||||
|
// If this enum is for a methodmap, forget the symbol so code below doesn't
|
||||||
|
// build an enum struct.
|
||||||
|
if (enumsym && enumsym->ident == iMETHODMAP)
|
||||||
|
enumsym = NULL;
|
||||||
|
|
||||||
needtoken('{');
|
needtoken('{');
|
||||||
/* go through all constants */
|
/* go through all constants */
|
||||||
value=0; /* default starting value */
|
value=0; /* default starting value */
|
||||||
@ -4721,7 +4770,7 @@ static void decl_enum(int vclass)
|
|||||||
matchtoken(';'); /* eat an optional ; */
|
matchtoken(';'); /* eat an optional ; */
|
||||||
|
|
||||||
/* set the enum name to the "next" value (typically the last value plus one) */
|
/* set the enum name to the "next" value (typically the last value plus one) */
|
||||||
if (enumsym!=NULL) {
|
if (enumsym) {
|
||||||
assert((enumsym->usage & uENUMROOT)!=0);
|
assert((enumsym->usage & uENUMROOT)!=0);
|
||||||
enumsym->addr=value;
|
enumsym->addr=value;
|
||||||
/* assign the constant list */
|
/* assign the constant list */
|
||||||
@ -6510,8 +6559,8 @@ static int testsymbols(symbol *root,int level,int testlabs,int testconst)
|
|||||||
error(203,sym->name); /* symbol isn't used: ... */
|
error(203,sym->name); /* symbol isn't used: ... */
|
||||||
} /* if */
|
} /* if */
|
||||||
break;
|
break;
|
||||||
case iPROXY:
|
case iMETHODMAP:
|
||||||
// Ignore usage on proxies.
|
// Ignore usage on methodmaps.
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* a variable */
|
/* a variable */
|
||||||
|
@ -2924,25 +2924,6 @@ void delete_symbols(symbol *root,int level,int delete_labels,int delete_function
|
|||||||
constvalue *stateptr;
|
constvalue *stateptr;
|
||||||
int mustdelete;
|
int mustdelete;
|
||||||
|
|
||||||
// Hack - proxies have a "target" pointer, but the target could be deleted
|
|
||||||
// already if done inside the main loop below. To get around this we do a
|
|
||||||
// precursor pass. Note that proxies can only be at the global scope.
|
|
||||||
if (origRoot == &glbtab) {
|
|
||||||
symbol *iter = root;
|
|
||||||
while (iter->next) {
|
|
||||||
sym = iter->next;
|
|
||||||
|
|
||||||
if (sym->ident != iPROXY) {
|
|
||||||
iter = sym;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
RemoveFromHashTable(sp_Globals, sym);
|
|
||||||
iter->next = sym->next;
|
|
||||||
free_symbol(sym);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* erase only the symbols with a deeper nesting level than the
|
/* erase only the symbols with a deeper nesting level than the
|
||||||
* specified nesting level */
|
* specified nesting level */
|
||||||
while (root->next!=NULL) {
|
while (root->next!=NULL) {
|
||||||
@ -2985,9 +2966,12 @@ void delete_symbols(symbol *root,int level,int delete_labels,int delete_function
|
|||||||
mustdelete=delete_functions || (sym->usage & uNATIVE)!=0;
|
mustdelete=delete_functions || (sym->usage & uNATIVE)!=0;
|
||||||
assert(sym->parent==NULL);
|
assert(sym->parent==NULL);
|
||||||
break;
|
break;
|
||||||
case iPROXY:
|
case iMETHODMAP:
|
||||||
// Original loop determined it was okay to keep.
|
// We delete methodmap symbols at the end, but since methodmaps
|
||||||
mustdelete=FALSE;
|
// themselves get wiped, we null the pointer.
|
||||||
|
sym->methodmap = nullptr;
|
||||||
|
mustdelete = delete_functions;
|
||||||
|
assert(!sym->parent);
|
||||||
break;
|
break;
|
||||||
case iARRAYCELL:
|
case iARRAYCELL:
|
||||||
case iARRAYCHAR:
|
case iARRAYCHAR:
|
||||||
@ -3143,7 +3127,7 @@ void markusage(symbol *sym,int usage)
|
|||||||
*
|
*
|
||||||
* Returns a pointer to the global symbol (if found) or NULL (if not found)
|
* Returns a pointer to the global symbol (if found) or NULL (if not found)
|
||||||
*/
|
*/
|
||||||
symbol *findglb(const char *name, int filter, symbol **alias)
|
symbol *findglb(const char *name, int filter)
|
||||||
{
|
{
|
||||||
/* find a symbol with a matching automaton first */
|
/* find a symbol with a matching automaton first */
|
||||||
symbol *sym=NULL;
|
symbol *sym=NULL;
|
||||||
@ -3168,12 +3152,6 @@ symbol *findglb(const char *name, int filter, symbol **alias)
|
|||||||
if (sym==NULL)
|
if (sym==NULL)
|
||||||
sym=FindInHashTable(sp_Globals,name,fcurrent);
|
sym=FindInHashTable(sp_Globals,name,fcurrent);
|
||||||
|
|
||||||
if (sym && sym->ident == iPROXY) {
|
|
||||||
if (alias)
|
|
||||||
*alias = sym;
|
|
||||||
return sym->target;
|
|
||||||
}
|
|
||||||
|
|
||||||
return sym;
|
return sym;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2001,6 +2001,96 @@ static int hier2(value *lval)
|
|||||||
} /* switch */
|
} /* switch */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static symbol *
|
||||||
|
fake_function_for_method(methodmap_t *map, const char *lexstr)
|
||||||
|
{
|
||||||
|
// Fetch a fake function so errors aren't as crazy.
|
||||||
|
char tmpname[METHOD_NAMEMAX + 1];
|
||||||
|
strcpy(tmpname, map->name);
|
||||||
|
strcat(tmpname, ".");
|
||||||
|
strcat(tmpname, lexstr);
|
||||||
|
tmpname[sNAMEMAX] = '\0';
|
||||||
|
return fetchfunc(tmpname);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum FieldExprResult
|
||||||
|
{
|
||||||
|
FER_Fail,
|
||||||
|
FER_Accessor,
|
||||||
|
FER_CallFunction,
|
||||||
|
FER_CallMethod
|
||||||
|
};
|
||||||
|
|
||||||
|
static FieldExprResult
|
||||||
|
field_expression(svalue &thisval, value *lval, symbol **target)
|
||||||
|
{
|
||||||
|
// Catch invalid calls early so we don't compile with a tag mismatch.
|
||||||
|
switch (thisval.val.ident) {
|
||||||
|
case iARRAY:
|
||||||
|
case iREFARRAY:
|
||||||
|
error(106);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case iFUNCTN:
|
||||||
|
case iREFFUNC:
|
||||||
|
error(107);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cell lexval;
|
||||||
|
char *lexstr;
|
||||||
|
if (!needtoken(tSYMBOL))
|
||||||
|
return FER_Fail;
|
||||||
|
tokeninfo(&lexval, &lexstr);
|
||||||
|
|
||||||
|
if (thisval.val.ident == iMETHODMAP) {
|
||||||
|
methodmap_t *map = thisval.val.sym->methodmap;
|
||||||
|
methodmap_method_t *method = methodmap_find_method(map, lexstr);
|
||||||
|
if (!method) {
|
||||||
|
error(105, map->name, lexstr);
|
||||||
|
*target = fake_function_for_method(map, lexstr);
|
||||||
|
return FER_CallFunction;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!method->is_static)
|
||||||
|
error(176, method->name, map->name);
|
||||||
|
*target = method->target;
|
||||||
|
return FER_CallFunction;
|
||||||
|
}
|
||||||
|
|
||||||
|
methodmap_t *map;
|
||||||
|
if ((map = methodmap_find_by_tag(thisval.val.tag)) == NULL) {
|
||||||
|
error(104, pc_tagname(thisval.val.tag));
|
||||||
|
return FER_Fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
methodmap_method_t *method;
|
||||||
|
if ((method = methodmap_find_method(map, lexstr)) == NULL) {
|
||||||
|
error(105, map->name, lexstr);
|
||||||
|
*target = fake_function_for_method(map, lexstr);
|
||||||
|
return FER_CallFunction;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method && (method->getter || method->setter)) {
|
||||||
|
if (thisval.lvalue)
|
||||||
|
rvalue(lval);
|
||||||
|
clear_value(lval);
|
||||||
|
lval->ident = iACCESSOR;
|
||||||
|
lval->tag = method->property_tag();
|
||||||
|
lval->accessor = method;
|
||||||
|
return FER_Accessor;
|
||||||
|
}
|
||||||
|
|
||||||
|
*target = method->target;
|
||||||
|
|
||||||
|
if (method->is_static) {
|
||||||
|
error(177, method->name, map->name, method->name);
|
||||||
|
return FER_CallFunction;
|
||||||
|
}
|
||||||
|
return FER_CallMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* hier1
|
/* hier1
|
||||||
*
|
*
|
||||||
* The highest hierarchy level: it looks for pointer and array indices
|
* The highest hierarchy level: it looks for pointer and array indices
|
||||||
@ -2025,14 +2115,27 @@ static int hier1(value *lval1)
|
|||||||
lvalue=primary(lval1);
|
lvalue=primary(lval1);
|
||||||
symtok=tokeninfo(&val,&st); /* get token read by primary() */
|
symtok=tokeninfo(&val,&st); /* get token read by primary() */
|
||||||
cursym=lval1->sym;
|
cursym=lval1->sym;
|
||||||
|
|
||||||
restart:
|
restart:
|
||||||
sym=cursym;
|
sym=cursym;
|
||||||
|
|
||||||
|
if (lval1->ident == iMETHODMAP &&
|
||||||
|
!(lexpeek('.') || lexpeek('(')))
|
||||||
|
{
|
||||||
|
// Cannot use methodmap as an rvalue/lvalue.
|
||||||
|
error(174, sym ? sym->name : "(unknown)");
|
||||||
|
|
||||||
|
lval1->ident = iCONSTEXPR;
|
||||||
|
lval1->tag = 0;
|
||||||
|
lval1->constval = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (matchtoken('[') || matchtoken('{') || matchtoken('(') || matchtoken('.')) {
|
if (matchtoken('[') || matchtoken('{') || matchtoken('(') || matchtoken('.')) {
|
||||||
|
tok=tokeninfo(&val,&st); /* get token read by matchtoken() */
|
||||||
if (lvalue && lval1->ident == iACCESSOR) {
|
if (lvalue && lval1->ident == iACCESSOR) {
|
||||||
rvalue(lval1);
|
rvalue(lval1);
|
||||||
lvalue = FALSE;
|
lvalue = FALSE;
|
||||||
}
|
}
|
||||||
tok=tokeninfo(&val,&st); /* get token read by matchtoken() */
|
|
||||||
magic_string = (sym && (sym->tag == pc_tag_string && sym->dim.array.level == 0));
|
magic_string = (sym && (sym->tag == pc_tag_string && sym->dim.array.level == 0));
|
||||||
if (sym==NULL && symtok!=tSYMBOL) {
|
if (sym==NULL && symtok!=tSYMBOL) {
|
||||||
/* we do not have a valid symbol and we appear not to have read a valid
|
/* we do not have a valid symbol and we appear not to have read a valid
|
||||||
@ -2210,59 +2313,17 @@ restart:
|
|||||||
|
|
||||||
svalue *implicitthis = NULL;
|
svalue *implicitthis = NULL;
|
||||||
if (tok == '.') {
|
if (tok == '.') {
|
||||||
methodmap_t *map;
|
switch (field_expression(thisval, lval1, &sym)) {
|
||||||
|
case FER_Fail:
|
||||||
/* Catch invalid calls early so we don't compile with a tag mismatch. */
|
case FER_CallFunction:
|
||||||
switch (thisval.val.ident) {
|
|
||||||
case iARRAY:
|
|
||||||
case iREFARRAY:
|
|
||||||
error(106);
|
|
||||||
break;
|
break;
|
||||||
|
case FER_CallMethod:
|
||||||
case iFUNCTN:
|
|
||||||
case iREFFUNC:
|
|
||||||
error(107);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((map = methodmap_find_by_tag(thisval.val.tag)) == NULL) {
|
|
||||||
error(104, pc_tagname(thisval.val.tag));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (needtoken(tSYMBOL) && map) {
|
|
||||||
cell lexval;
|
|
||||||
char *lexstr;
|
|
||||||
methodmap_method_t *method;
|
|
||||||
|
|
||||||
tokeninfo(&lexval, &lexstr);
|
|
||||||
if ((method = methodmap_find_method(map, lexstr)) == NULL)
|
|
||||||
error(105, map->name, lexstr);
|
|
||||||
|
|
||||||
if (method && (method->getter || method->setter)) {
|
|
||||||
if (lvalue)
|
|
||||||
rvalue(lval1);
|
|
||||||
clear_value(lval1);
|
|
||||||
lval1->ident = iACCESSOR;
|
|
||||||
lval1->tag = method->property_tag();
|
|
||||||
lval1->accessor = method;
|
|
||||||
lvalue = TRUE;
|
|
||||||
goto restart;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!method || !method->target) {
|
|
||||||
error(105, map->name, lexstr);
|
|
||||||
|
|
||||||
// Fetch a fake function so errors aren't as crazy.
|
|
||||||
char tmpname[METHOD_NAMEMAX + 1];
|
|
||||||
strcpy(tmpname, map->name);
|
|
||||||
strcat(tmpname, ".");
|
|
||||||
strcat(tmpname, lexstr);
|
|
||||||
tmpname[sNAMEMAX] = '\0';
|
|
||||||
sym = fetchfunc(tmpname);
|
|
||||||
} else {
|
|
||||||
implicitthis = &thisval;
|
implicitthis = &thisval;
|
||||||
sym = method->target;
|
break;
|
||||||
}
|
case FER_Accessor:
|
||||||
|
goto restart;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we don't find a '(' next, just fail to compile for now -- and
|
// If we don't find a '(' next, just fail to compile for now -- and
|
||||||
@ -2275,7 +2336,18 @@ restart:
|
|||||||
|
|
||||||
assert(tok=='(');
|
assert(tok=='(');
|
||||||
if (sym==NULL || (sym->ident!=iFUNCTN && sym->ident!=iREFFUNC)) {
|
if (sym==NULL || (sym->ident!=iFUNCTN && sym->ident!=iREFFUNC)) {
|
||||||
if (sym==NULL && sc_status==statFIRST) {
|
if (sym && sym->ident == iMETHODMAP && sym->methodmap) {
|
||||||
|
if (!sym->methodmap->ctor) {
|
||||||
|
// Immediately fatal - no function to call.
|
||||||
|
return error(172, sym->name);
|
||||||
|
}
|
||||||
|
if (sym->methodmap->nullable) {
|
||||||
|
// Keep going, this is basically a style thing.
|
||||||
|
error(170, sym->methodmap->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
sym = sym->methodmap->ctor->target;
|
||||||
|
} else if (sym==NULL && sc_status==statFIRST) {
|
||||||
/* could be a "use before declaration"; in that case, create a stub
|
/* could be a "use before declaration"; in that case, create a stub
|
||||||
* function so that the usage can be marked.
|
* function so that the usage can be marked.
|
||||||
*/
|
*/
|
||||||
@ -2285,27 +2357,13 @@ restart:
|
|||||||
markusage(sym,uREAD);
|
markusage(sym,uREAD);
|
||||||
} else {
|
} else {
|
||||||
return error(12); /* invalid function call */
|
return error(12); /* invalid function call */
|
||||||
} /* if */
|
}
|
||||||
} else if ((sym->usage & uMISSING)!=0) {
|
} else if ((sym->usage & uMISSING)!=0) {
|
||||||
char symname[2*sNAMEMAX+16]; /* allow space for user defined operators */
|
char symname[2*sNAMEMAX+16]; /* allow space for user defined operators */
|
||||||
funcdisplayname(symname,sym->name);
|
funcdisplayname(symname,sym->name);
|
||||||
error(4,symname); /* function not defined */
|
error(4,symname); /* function not defined */
|
||||||
} /* if */
|
} /* if */
|
||||||
|
|
||||||
// Check whether we're calling a constructor. This is a bit hacky, since
|
|
||||||
// we're relying on whatever the lval state is.
|
|
||||||
if ((sym->flags & flgPROXIED) &&
|
|
||||||
lval1->proxy &&
|
|
||||||
lval1->proxy->target == sym)
|
|
||||||
{
|
|
||||||
// Only constructors should be proxied, but we check anyway.
|
|
||||||
assert(!implicitthis);
|
|
||||||
if (methodmap_t *methodmap = methodmap_find_by_tag(sym->tag)) {
|
|
||||||
if (sym == methodmap->ctor->target && methodmap->nullable)
|
|
||||||
error(170, methodmap->name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
callfunction(sym,implicitthis,lval1,TRUE);
|
callfunction(sym,implicitthis,lval1,TRUE);
|
||||||
if (lexpeek('.')) {
|
if (lexpeek('.')) {
|
||||||
lvalue = FALSE;
|
lvalue = FALSE;
|
||||||
@ -2342,7 +2400,6 @@ restart:
|
|||||||
|
|
||||||
funcenum_t *fe = funcenum_for_symbol(target);
|
funcenum_t *fe = funcenum_for_symbol(target);
|
||||||
lval1->sym = NULL;
|
lval1->sym = NULL;
|
||||||
lval1->proxy = NULL;
|
|
||||||
lval1->ident = iCONSTEXPR;
|
lval1->ident = iCONSTEXPR;
|
||||||
lval1->constval = (public_index << 1) | 1;
|
lval1->constval = (public_index << 1) | 1;
|
||||||
lval1->tag = fe->tag;
|
lval1->tag = fe->tag;
|
||||||
@ -2429,8 +2486,7 @@ static int primary(value *lval)
|
|||||||
} /* if */
|
} /* if */
|
||||||
} /* if */
|
} /* if */
|
||||||
/* now try a global variable */
|
/* now try a global variable */
|
||||||
symbol *alias = NULL;
|
if ((sym = findglb(st, sSTATEVAR)) != 0) {
|
||||||
if ((sym = findglb(st, sSTATEVAR, &alias)) != 0) {
|
|
||||||
if (sym->ident==iFUNCTN || sym->ident==iREFFUNC) {
|
if (sym->ident==iFUNCTN || sym->ident==iREFFUNC) {
|
||||||
/* if the function is only in the table because it was inserted as a
|
/* if the function is only in the table because it was inserted as a
|
||||||
* stub in the first pass (i.e. it was "used" but never declared or
|
* stub in the first pass (i.e. it was "used" but never declared or
|
||||||
@ -2442,15 +2498,18 @@ static int primary(value *lval)
|
|||||||
if ((sym->usage & uDEFINE)==0)
|
if ((sym->usage & uDEFINE)==0)
|
||||||
error(17,st);
|
error(17,st);
|
||||||
lval->sym=sym;
|
lval->sym=sym;
|
||||||
lval->proxy=alias;
|
|
||||||
lval->ident=sym->ident;
|
lval->ident=sym->ident;
|
||||||
lval->tag=sym->tag;
|
lval->tag=sym->tag;
|
||||||
if (sym->ident==iARRAY || sym->ident==iREFARRAY) {
|
switch (sym->ident) {
|
||||||
address(sym,sPRI); /* get starting address in primary register */
|
case iARRAY:
|
||||||
return FALSE; /* return 0 for array (not lvalue) */
|
case iREFARRAY:
|
||||||
} else {
|
address(sym,sPRI); /* get starting address in primary register */
|
||||||
return TRUE; /* return 1 if lvalue (not function or array) */
|
return FALSE; /* return 0 for array (not lvalue) */
|
||||||
} /* if */
|
case iMETHODMAP:
|
||||||
|
return FALSE;
|
||||||
|
default:
|
||||||
|
return TRUE; /* return 1 if lvalue (not function or array) */
|
||||||
|
} /* switch */
|
||||||
} /* if */
|
} /* if */
|
||||||
} else {
|
} else {
|
||||||
if (!sc_allowproccall)
|
if (!sc_allowproccall)
|
||||||
@ -2466,7 +2525,6 @@ static int primary(value *lval)
|
|||||||
assert(sym!=NULL);
|
assert(sym!=NULL);
|
||||||
assert(sym->ident==iFUNCTN || sym->ident==iREFFUNC);
|
assert(sym->ident==iFUNCTN || sym->ident==iREFFUNC);
|
||||||
lval->sym=sym;
|
lval->sym=sym;
|
||||||
lval->proxy=alias;
|
|
||||||
lval->ident=sym->ident;
|
lval->ident=sym->ident;
|
||||||
lval->tag=sym->tag;
|
lval->tag=sym->tag;
|
||||||
return FALSE; /* return 0 for function (not an lvalue) */
|
return FALSE; /* return 0 for function (not an lvalue) */
|
||||||
@ -2482,7 +2540,6 @@ static int primary(value *lval)
|
|||||||
static void clear_value(value *lval)
|
static void clear_value(value *lval)
|
||||||
{
|
{
|
||||||
lval->sym=NULL;
|
lval->sym=NULL;
|
||||||
lval->proxy=NULL;
|
|
||||||
lval->constval=0L;
|
lval->constval=0L;
|
||||||
lval->tag=0;
|
lval->tag=0;
|
||||||
lval->ident=0;
|
lval->ident=0;
|
||||||
|
@ -156,7 +156,7 @@ static const char *errmsg[] = {
|
|||||||
/*110*/ "%s has already been defined (previously seen as %s)\n",
|
/*110*/ "%s has already been defined (previously seen as %s)\n",
|
||||||
/*111*/ "expected identifier - did you forget a type?\n",
|
/*111*/ "expected identifier - did you forget a type?\n",
|
||||||
/*112*/ "constructor function must return tag %s\n",
|
/*112*/ "constructor function must return tag %s\n",
|
||||||
/*113*/ "cannot define constructor for \"%s\"; already exists as a %s\n",
|
/*113*/ "constructor for \"%s\" already exists\n",
|
||||||
/*114*/ "missing type, or %s must have the same name as %s \"%s\"\n",
|
/*114*/ "missing type, or %s must have the same name as %s \"%s\"\n",
|
||||||
/*115*/ "cannot use delete, %s %s has no destructor\n",
|
/*115*/ "cannot use delete, %s %s has no destructor\n",
|
||||||
/*116*/ "no methodmap or class was found for %s\n",
|
/*116*/ "no methodmap or class was found for %s\n",
|
||||||
@ -217,6 +217,10 @@ static const char *errmsg[] = {
|
|||||||
/*171*/ "cannot use 'new' with non-object-like methodmap '%s'\n",
|
/*171*/ "cannot use 'new' with non-object-like methodmap '%s'\n",
|
||||||
/*172*/ "methodmap '%s' does not have a constructor\n",
|
/*172*/ "methodmap '%s' does not have a constructor\n",
|
||||||
/*173*/ "'%s' is a newly reserved keyword that may be used in the future; use a different name as an identifier\n",
|
/*173*/ "'%s' is a newly reserved keyword that may be used in the future; use a different name as an identifier\n",
|
||||||
|
/*174*/ "symbol '%s' is a type and cannot be used as a value\n",
|
||||||
|
/*175*/ "constructors cannot be static\n",
|
||||||
|
/*176*/ "non-static method or property '%s' must be called with a value of type '%s'\n",
|
||||||
|
/*177*/ "static method '%s' must be invoked via its type (try '%s.%s')\n",
|
||||||
#else
|
#else
|
||||||
"\315e\306\227\266k\217:\235\277bu\201fo\220\204\223\012",
|
"\315e\306\227\266k\217:\235\277bu\201fo\220\204\223\012",
|
||||||
"\202l\224\250s\205g\346\356e\233\201(\243\315\214\267\202) \253 f\255low ea\305 \042c\353e\042\012",
|
"\202l\224\250s\205g\346\356e\233\201(\243\315\214\267\202) \253 f\255low ea\305 \042c\353e\042\012",
|
||||||
|
@ -85,6 +85,7 @@ typedef struct methodmap_method_s
|
|||||||
symbol *target;
|
symbol *target;
|
||||||
symbol *getter;
|
symbol *getter;
|
||||||
symbol *setter;
|
symbol *setter;
|
||||||
|
bool is_static;
|
||||||
|
|
||||||
int property_tag() const {
|
int property_tag() const {
|
||||||
assert(getter || setter);
|
assert(getter || setter);
|
||||||
@ -100,10 +101,10 @@ typedef struct methodmap_method_s
|
|||||||
}
|
}
|
||||||
} methodmap_method_t;
|
} methodmap_method_t;
|
||||||
|
|
||||||
typedef struct methodmap_s
|
struct methodmap_t
|
||||||
{
|
{
|
||||||
struct methodmap_s *next;
|
methodmap_t *next;
|
||||||
struct methodmap_s *parent;
|
methodmap_t *parent;
|
||||||
int tag;
|
int tag;
|
||||||
int nullable;
|
int nullable;
|
||||||
LayoutSpec spec;
|
LayoutSpec spec;
|
||||||
@ -114,7 +115,7 @@ typedef struct methodmap_s
|
|||||||
// Shortcut.
|
// Shortcut.
|
||||||
methodmap_method_t *dtor;
|
methodmap_method_t *dtor;
|
||||||
methodmap_method_t *ctor;
|
methodmap_method_t *ctor;
|
||||||
} methodmap_t;
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pawn Structs
|
* Pawn Structs
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
(1) : error 001: expected token: "-identifier-", but found ")"
|
(1) : error 001: expected token: "-identifier-", but found ")"
|
||||||
(5) : error 140: new-style array types cannot specify dimension sizes as part of their type
|
(5) : error 140: new-style array types cannot specify dimension sizes as part of their type
|
||||||
(9) : error 001: expected token: "-identifier-", but found ":"
|
(9) : warning 238: 'int:' is an illegal cast; use view_as<int>(expression)
|
||||||
|
12
sourcepawn/compiler/tests/fail-call-non-static-on-type.sp
Normal file
12
sourcepawn/compiler/tests/fail-call-non-static-on-type.sp
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
native printnum(t);
|
||||||
|
|
||||||
|
methodmap X
|
||||||
|
{
|
||||||
|
public int GetThing() {
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public main() {
|
||||||
|
printnum(X.GetThing());
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
(11) : error 176: non-static method or property 'GetThing' must be called with a value of type 'X'
|
13
sourcepawn/compiler/tests/fail-call-static-via-instance.sp
Normal file
13
sourcepawn/compiler/tests/fail-call-static-via-instance.sp
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
native printnum(t);
|
||||||
|
|
||||||
|
methodmap X
|
||||||
|
{
|
||||||
|
public static int GetThing() {
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public main() {
|
||||||
|
X x;
|
||||||
|
printnum(x.GetThing());
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
(12) : error 177: static method 'GetThing' must be invoked via its type (try 'X.GetThing')
|
17
sourcepawn/compiler/tests/fail-methodmap-as-rvalue.sp
Normal file
17
sourcepawn/compiler/tests/fail-methodmap-as-rvalue.sp
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
native printnum(x);
|
||||||
|
|
||||||
|
enum X {
|
||||||
|
};
|
||||||
|
|
||||||
|
methodmap X {
|
||||||
|
public X(int y) {
|
||||||
|
printnum(y);
|
||||||
|
return view_as<X>(0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public main()
|
||||||
|
{
|
||||||
|
X x = X(5);
|
||||||
|
return X;
|
||||||
|
}
|
1
sourcepawn/compiler/tests/fail-methodmap-as-rvalue.txt
Normal file
1
sourcepawn/compiler/tests/fail-methodmap-as-rvalue.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
(16) : error 174: symbol 'X' is a type and cannot be used as a value
|
12
sourcepawn/compiler/tests/ok-call-static-method.sp
Normal file
12
sourcepawn/compiler/tests/ok-call-static-method.sp
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
native printnum(t);
|
||||||
|
|
||||||
|
methodmap X
|
||||||
|
{
|
||||||
|
public static int GetThing() {
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public main() {
|
||||||
|
printnum(X.GetThing());
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user