Allow capturing non-public functions as values.
This commit is contained in:
parent
ac4f594063
commit
8216097b2c
@ -58,7 +58,7 @@
|
|||||||
#define sDEF_LITMAX 500 /* initial size of the literal pool, in "cells" */
|
#define sDEF_LITMAX 500 /* initial size of the literal pool, in "cells" */
|
||||||
#define sDEF_AMXSTACK 4096 /* default stack size for AMX files */
|
#define sDEF_AMXSTACK 4096 /* default stack size for AMX files */
|
||||||
#define PREPROC_TERM '\x7f'/* termination character for preprocessor expressions (the "DEL" code) */
|
#define PREPROC_TERM '\x7f'/* termination character for preprocessor expressions (the "DEL" code) */
|
||||||
#define sDEF_PREFIX "sourcemod.inc" /* default prefix filename */
|
#define sDEF_PREFIX "xsourcemod.inc" /* default prefix filename */
|
||||||
#define sARGS_MAX 32 /* number of arguments a function can have, max */
|
#define sARGS_MAX 32 /* number of arguments a function can have, max */
|
||||||
#define sTAGS_MAX 16 /* maximum number of tags on an argument */
|
#define sTAGS_MAX 16 /* maximum number of tags on an argument */
|
||||||
|
|
||||||
@ -149,6 +149,7 @@ typedef struct s_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 */
|
methodmap_t *methodmap; /* if ident == iMETHODMAP */
|
||||||
|
int funcid; /* set for functions during codegen */
|
||||||
} symbol;
|
} symbol;
|
||||||
|
|
||||||
/* Possible entries for "ident". These are used in the "symbol", "value"
|
/* Possible entries for "ident". These are used in the "symbol", "value"
|
||||||
@ -757,6 +758,7 @@ void invoke_setter(struct methodmap_method_s *method, int save);
|
|||||||
void inc_pri();
|
void inc_pri();
|
||||||
void dec_pri();
|
void dec_pri();
|
||||||
void load_hidden_arg();
|
void load_hidden_arg();
|
||||||
|
void load_glbfn(symbol *sym);
|
||||||
|
|
||||||
/* Code generation functions for arithmetic operators.
|
/* Code generation functions for arithmetic operators.
|
||||||
*
|
*
|
||||||
@ -981,7 +983,7 @@ typedef struct array_info_s
|
|||||||
} array_info_t;
|
} array_info_t;
|
||||||
|
|
||||||
enum FatalError {
|
enum FatalError {
|
||||||
FIRST_FATAL_ERROR = 182,
|
FIRST_FATAL_ERROR = 183,
|
||||||
|
|
||||||
FATAL_ERROR_READ = FIRST_FATAL_ERROR,
|
FATAL_ERROR_READ = FIRST_FATAL_ERROR,
|
||||||
FATAL_ERROR_WRITE,
|
FATAL_ERROR_WRITE,
|
||||||
|
@ -3102,6 +3102,7 @@ symbol *addsym(const char *name,cell addr,int ident,int vclass,int tag,int usage
|
|||||||
entry.lnumber=fline;
|
entry.lnumber=fline;
|
||||||
entry.numrefers=1;
|
entry.numrefers=1;
|
||||||
entry.refer=refer;
|
entry.refer=refer;
|
||||||
|
entry.funcid=0;
|
||||||
|
|
||||||
/* then insert it in the list */
|
/* then insert it in the list */
|
||||||
if (vclass==sGLOBAL)
|
if (vclass==sGLOBAL)
|
||||||
|
@ -2403,31 +2403,22 @@ restart:
|
|||||||
error(76);
|
error(76);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
if (finddepend(sym)) {
|
||||||
int public_index = 0;
|
error(182);
|
||||||
symbol *target = NULL;
|
|
||||||
for (symbol *iter = glbtab.next; iter; iter = iter->next) {
|
|
||||||
if (iter->ident != iFUNCTN || iter->vclass != sGLOBAL)
|
|
||||||
continue;
|
|
||||||
if (strcmp(iter->name, lval1->sym->name) == 0) {
|
|
||||||
target = iter;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (iter->usage & uPUBLIC)
|
|
||||||
public_index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!target || !(target->usage & uPUBLIC)) {
|
|
||||||
error(76);
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
funcenum_t *fe = funcenum_for_symbol(target);
|
funcenum_t *fe = funcenum_for_symbol(sym);
|
||||||
|
|
||||||
|
// Get address into pri.
|
||||||
|
load_glbfn(sym);
|
||||||
|
|
||||||
|
// New-style "closure".
|
||||||
lval1->sym = NULL;
|
lval1->sym = NULL;
|
||||||
lval1->ident = iCONSTEXPR;
|
lval1->ident = iEXPRESSION;
|
||||||
lval1->constval = (public_index << 1) | 1;
|
lval1->constval = 0;
|
||||||
lval1->tag = fe->tag;
|
lval1->tag = fe->tag;
|
||||||
target->usage |= uREAD;
|
return FALSE;
|
||||||
} /* if */
|
} /* if */
|
||||||
return lvalue;
|
return lvalue;
|
||||||
}
|
}
|
||||||
|
@ -1503,3 +1503,17 @@ void invoke_setter(methodmap_method_t *method, int save)
|
|||||||
if (sc_status != statSKIP)
|
if (sc_status != statSKIP)
|
||||||
markusage(method->setter, uREAD);
|
markusage(method->setter, uREAD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// function value -> pri
|
||||||
|
void load_glbfn(symbol *sym)
|
||||||
|
{
|
||||||
|
assert(sym->ident == iFUNCTN);
|
||||||
|
assert(!(sym->usage & uNATIVE));
|
||||||
|
stgwrite("\tldgfn.pri ");
|
||||||
|
stgwrite(sym->name);
|
||||||
|
stgwrite("\n");
|
||||||
|
code_idx += opcodes(1) + opargs(1);
|
||||||
|
|
||||||
|
if (sc_status != statSKIP)
|
||||||
|
markusage(sym, uREAD);
|
||||||
|
}
|
||||||
|
@ -225,6 +225,7 @@ static const char *errmsg[] = {
|
|||||||
/*179*/ "cannot assign %s[] to %s[], storage classes differ\n",
|
/*179*/ "cannot assign %s[] to %s[], storage classes differ\n",
|
||||||
/*180*/ "function return type differs from prototype. expected '%s', but got '%s'\n",
|
/*180*/ "function return type differs from prototype. expected '%s', but got '%s'\n",
|
||||||
/*181*/ "function argument named '%s' differs from prototype\n",
|
/*181*/ "function argument named '%s' differs from prototype\n",
|
||||||
|
/*182*/ "functions that return arrays cannot be used as callbacks\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",
|
||||||
|
@ -37,7 +37,9 @@
|
|||||||
#include <sclinux.h>
|
#include <sclinux.h>
|
||||||
#endif
|
#endif
|
||||||
#include <am-utility.h>
|
#include <am-utility.h>
|
||||||
|
#include <am-string.h>
|
||||||
#include <smx/smx-v1.h>
|
#include <smx/smx-v1.h>
|
||||||
|
#include <smx/smx-v1-opcodes.h>
|
||||||
#include <zlib/zlib.h>
|
#include <zlib/zlib.h>
|
||||||
#include "smx-builder.h"
|
#include "smx-builder.h"
|
||||||
#include "memory-buffer.h"
|
#include "memory-buffer.h"
|
||||||
@ -232,6 +234,32 @@ static cell do_dump(Vector<cell> *buffer, char *params, cell opcode)
|
|||||||
return num * sizeof(cell);
|
return num * sizeof(cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static cell do_ldgfen(Vector<cell> *buffer, char *params, cell opcode)
|
||||||
|
{
|
||||||
|
char name[sNAMEMAX+1];
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i=0; !isspace(*params); i++,params++) {
|
||||||
|
assert(*params != '\0');
|
||||||
|
assert(i < sNAMEMAX);
|
||||||
|
name[i] = *params;
|
||||||
|
}
|
||||||
|
name[i]='\0';
|
||||||
|
|
||||||
|
symbol *sym = findglb(name, sGLOBAL);
|
||||||
|
assert(sym->ident == iFUNCTN);
|
||||||
|
assert(!(sym->usage & uNATIVE));
|
||||||
|
assert((sym->funcid & 1) == 1);
|
||||||
|
|
||||||
|
if (buffer) {
|
||||||
|
// Note: we emit const.pri for backward compatibility.
|
||||||
|
assert(opcode == sp::OP_UNGEN_LDGFN_PRI);
|
||||||
|
buffer->append(sp::OP_CONST_PRI);
|
||||||
|
buffer->append(sym->funcid);
|
||||||
|
}
|
||||||
|
return opcodes(1) + opargs(1);
|
||||||
|
}
|
||||||
|
|
||||||
static cell do_call(Vector<cell> *buffer, char *params, cell opcode)
|
static cell do_call(Vector<cell> *buffer, char *params, cell opcode)
|
||||||
{
|
{
|
||||||
char name[sNAMEMAX+1];
|
char name[sNAMEMAX+1];
|
||||||
@ -333,6 +361,7 @@ static OPCODEC opcodelist[] = {
|
|||||||
{112, "dec.pri", sIN_CSEG, parm0 },
|
{112, "dec.pri", sIN_CSEG, parm0 },
|
||||||
{115, "dec.s", sIN_CSEG, parm1 },
|
{115, "dec.s", sIN_CSEG, parm1 },
|
||||||
{ 0, "dump", sIN_DSEG, do_dump },
|
{ 0, "dump", sIN_DSEG, do_dump },
|
||||||
|
{166, "endproc", sIN_CSEG, parm0 },
|
||||||
{ 95, "eq", sIN_CSEG, parm0 },
|
{ 95, "eq", sIN_CSEG, parm0 },
|
||||||
{106, "eq.c.alt", sIN_CSEG, parm1 },
|
{106, "eq.c.alt", sIN_CSEG, parm1 },
|
||||||
{105, "eq.c.pri", sIN_CSEG, parm1 },
|
{105, "eq.c.pri", sIN_CSEG, parm1 },
|
||||||
@ -368,6 +397,7 @@ static OPCODEC opcodelist[] = {
|
|||||||
{128, "jump.pri", sIN_CSEG, parm0 }, /* version 1 */
|
{128, "jump.pri", sIN_CSEG, parm0 }, /* version 1 */
|
||||||
{ 53, "jzer", sIN_CSEG, do_jump },
|
{ 53, "jzer", sIN_CSEG, do_jump },
|
||||||
{ 31, "lctrl", sIN_CSEG, parm1 },
|
{ 31, "lctrl", sIN_CSEG, parm1 },
|
||||||
|
{167, "ldgfn.pri", sIN_CSEG, do_ldgfen },
|
||||||
{ 98, "leq", sIN_CSEG, parm0 },
|
{ 98, "leq", sIN_CSEG, parm0 },
|
||||||
{ 97, "less", sIN_CSEG, parm0 },
|
{ 97, "less", sIN_CSEG, parm0 },
|
||||||
{ 25, "lidx", sIN_CSEG, parm0 },
|
{ 25, "lidx", sIN_CSEG, parm0 },
|
||||||
@ -613,6 +643,18 @@ static int sort_by_addr(const void *a1, const void *a2)
|
|||||||
return s1->addr - s2->addr;
|
return s1->addr - s2->addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct function_entry {
|
||||||
|
symbol *sym;
|
||||||
|
AString name;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int sort_functions(const void *a1, const void *a2)
|
||||||
|
{
|
||||||
|
function_entry &f1 = *(function_entry *)a1;
|
||||||
|
function_entry &f2 = *(function_entry *)a2;
|
||||||
|
return strcmp(f1.name.chars(), f2.name.chars());
|
||||||
|
}
|
||||||
|
|
||||||
// Helper for parsing a debug string. Debug strings look like this:
|
// Helper for parsing a debug string. Debug strings look like this:
|
||||||
// L:40 10
|
// L:40 10
|
||||||
class DebugString
|
class DebugString
|
||||||
@ -835,6 +877,7 @@ static void assemble_to_buffer(MemoryBuffer *buffer, void *fin)
|
|||||||
Ref<SmxNameTable> names = new SmxNameTable(".names");
|
Ref<SmxNameTable> names = new SmxNameTable(".names");
|
||||||
|
|
||||||
Vector<symbol *> nativeList;
|
Vector<symbol *> nativeList;
|
||||||
|
Vector<function_entry> functions;
|
||||||
|
|
||||||
// Build the easy symbol tables.
|
// Build the easy symbol tables.
|
||||||
for (symbol *sym=glbtab.next; sym; sym=sym->next) {
|
for (symbol *sym=glbtab.next; sym; sym=sym->next) {
|
||||||
@ -842,10 +885,26 @@ static void assemble_to_buffer(MemoryBuffer *buffer, void *fin)
|
|||||||
if ((sym->usage & uNATIVE)!=0 && (sym->usage & uREAD)!=0 && sym->addr >= 0) {
|
if ((sym->usage & uNATIVE)!=0 && (sym->usage & uREAD)!=0 && sym->addr >= 0) {
|
||||||
// Natives require special handling, so we save them for later.
|
// Natives require special handling, so we save them for later.
|
||||||
nativeList.append(sym);
|
nativeList.append(sym);
|
||||||
} else if ((sym->usage & uPUBLIC)!=0 && (sym->usage & uDEFINE)!=0) {
|
continue;
|
||||||
sp_file_publics_t &pubfunc = publics->add();
|
}
|
||||||
pubfunc.address = sym->addr;
|
|
||||||
pubfunc.name = names->add(pool, sym->name);
|
if ((sym->usage & (uPUBLIC|uDEFINE)) == (uPUBLIC|uDEFINE) ||
|
||||||
|
(sym->usage & uREAD))
|
||||||
|
{
|
||||||
|
function_entry entry;
|
||||||
|
entry.sym = sym;
|
||||||
|
if (sym->usage & uPUBLIC) {
|
||||||
|
entry.name = sym->name;
|
||||||
|
} else {
|
||||||
|
// Create a private name.
|
||||||
|
char private_name[sNAMEMAX*3 + 1];
|
||||||
|
snprintf(private_name, sizeof(private_name), ".%d.%s", sym->addr, sym->name);
|
||||||
|
|
||||||
|
entry.name = private_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
functions.append(entry);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
} else if (sym->ident==iVARIABLE || sym->ident == iARRAY || sym->ident == iREFARRAY) {
|
} else if (sym->ident==iVARIABLE || sym->ident == iARRAY || sym->ident == iREFARRAY) {
|
||||||
if ((sym->usage & uPUBLIC)!=0 && (sym->usage & (uREAD | uWRITTEN))!=0) {
|
if ((sym->usage & uPUBLIC)!=0 && (sym->usage & (uREAD | uWRITTEN))!=0) {
|
||||||
@ -856,6 +915,23 @@ static void assemble_to_buffer(MemoryBuffer *buffer, void *fin)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The public list must be sorted.
|
||||||
|
qsort(functions.buffer(), functions.length(), sizeof(function_entry), sort_functions);
|
||||||
|
for (size_t i = 0; i < functions.length(); i++) {
|
||||||
|
function_entry &f = functions[i];
|
||||||
|
symbol *sym = f.sym;
|
||||||
|
|
||||||
|
assert(sym->addr > 0);
|
||||||
|
assert(sym->codeaddr > sym->addr);
|
||||||
|
assert(sym->usage & uDEFINE);
|
||||||
|
|
||||||
|
sp_file_publics_t &pubfunc = publics->add();
|
||||||
|
pubfunc.address = sym->addr;
|
||||||
|
pubfunc.name = names->add(pool, f.name.chars());
|
||||||
|
|
||||||
|
sym->funcid = (uint32_t(i) << 1) | 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Shuffle natives to be in address order.
|
// Shuffle natives to be in address order.
|
||||||
qsort(nativeList.buffer(), nativeList.length(), sizeof(symbol *), sort_by_addr);
|
qsort(nativeList.buffer(), nativeList.length(), sizeof(symbol *), sort_by_addr);
|
||||||
for (size_t i = 0; i < nativeList.length(); i++) {
|
for (size_t i = 0; i < nativeList.length(); i++) {
|
||||||
|
@ -129,6 +129,9 @@ class SmxListSection : public SmxSection
|
|||||||
list_.append(T());
|
list_.append(T());
|
||||||
return list_.back();
|
return list_.back();
|
||||||
}
|
}
|
||||||
|
void add(const T &t) {
|
||||||
|
list_.append(t);
|
||||||
|
}
|
||||||
bool write(ISmxBuffer *buf) KE_OVERRIDE {
|
bool write(ISmxBuffer *buf) KE_OVERRIDE {
|
||||||
return buf->write(list_.buffer(), list_.length() * sizeof(T));
|
return buf->write(list_.buffer(), list_.length() * sizeof(T));
|
||||||
}
|
}
|
||||||
|
16
sourcepawn/compiler/tests/fail-callback-returns-array.sp
Normal file
16
sourcepawn/compiler/tests/fail-callback-returns-array.sp
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
String:MyFunction()
|
||||||
|
{
|
||||||
|
new String:egg[10] = "egg";
|
||||||
|
return egg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public crab()
|
||||||
|
{
|
||||||
|
new String:egg[10];
|
||||||
|
egg = MyFunction();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Function:main()
|
||||||
|
{
|
||||||
|
return MyFunction;
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
(15) : error 182: functions that return arrays cannot be used as callbacks
|
@ -2,4 +2,4 @@
|
|||||||
(2) : error 141: natives, forwards, and public functions cannot return arrays
|
(2) : error 141: natives, forwards, and public functions cannot return arrays
|
||||||
(3) : error 143: new-style declarations should not have "new"
|
(3) : error 143: new-style declarations should not have "new"
|
||||||
(5) : error 121: cannot specify array dimensions on both type and name
|
(5) : error 121: cannot specify array dimensions on both type and name
|
||||||
(11) : error 025: function heading differs from prototype
|
(11) : error 180: function return type differs from prototype. expected 'void', but got 'int'
|
||||||
|
@ -235,6 +235,7 @@ namespace sp {
|
|||||||
_(STRADJUST_PRI, "stradjust.pri") \
|
_(STRADJUST_PRI, "stradjust.pri") \
|
||||||
_(UNGEN_STKADJUST,"stackadjust") \
|
_(UNGEN_STKADJUST,"stackadjust") \
|
||||||
_(ENDPROC, "endproc") \
|
_(ENDPROC, "endproc") \
|
||||||
|
_(UNGEN_LDGFN_PRI,"ldgfn.pri") \
|
||||||
_(FABS, "fabs") \
|
_(FABS, "fabs") \
|
||||||
_(FLOAT, "float") \
|
_(FLOAT, "float") \
|
||||||
_(FLOATADD, "float.add") \
|
_(FLOATADD, "float.add") \
|
||||||
|
Loading…
Reference in New Issue
Block a user