Merge pull request #73 from alliedmodders/nullable
Add nullable types and tighten up some new type system semantics.
This commit is contained in:
commit
97e0c84e6d
@ -73,7 +73,9 @@ class SMConfig(object):
|
||||
self.versionlib = None
|
||||
|
||||
def use_auto_versioning(self):
|
||||
return builder.backend == 'amb2' and not builder.options.disable_auto_versioning
|
||||
if builder.backend != 'amb2':
|
||||
return False
|
||||
return not getattr(builder.options, 'disable_auto_versioning', False)
|
||||
|
||||
@property
|
||||
def tag(self):
|
||||
|
@ -78,7 +78,7 @@ native Handle:CloneHandle(Handle:hndl, Handle:plugin=INVALID_HANDLE);
|
||||
/**
|
||||
* Helper for object-oriented syntax.
|
||||
*/
|
||||
methodmap Handle
|
||||
methodmap Handle __nullable__
|
||||
{
|
||||
public Clone() = CloneHandle;
|
||||
public ~Handle() = CloseHandle;
|
||||
|
@ -411,6 +411,8 @@ enum {
|
||||
tMETHODMAP,
|
||||
tNATIVE,
|
||||
tNEW,
|
||||
tNULL,
|
||||
tNULLABLE,
|
||||
tOBJECT,
|
||||
tOPERATOR,
|
||||
tPUBLIC,
|
||||
@ -675,6 +677,7 @@ SC_FUNC cell array_totalsize(symbol *sym);
|
||||
SC_FUNC int matchtag_string(int ident, int tag);
|
||||
SC_FUNC int checktag_string(value *sym1, value *sym2);
|
||||
SC_FUNC int checktags_string(int tags[], int numtags, value *sym1);
|
||||
SC_FUNC int lvalexpr(svalue *sval);
|
||||
|
||||
/* function prototypes in SC4.C */
|
||||
SC_FUNC void writeleader(symbol *root);
|
||||
@ -699,6 +702,7 @@ SC_FUNC void copyarray(symbol *sym,cell size);
|
||||
SC_FUNC void fillarray(symbol *sym,cell size,cell value);
|
||||
SC_FUNC void ldconst(cell val,regid reg);
|
||||
SC_FUNC void moveto1(void);
|
||||
SC_FUNC void move_alt(void);
|
||||
SC_FUNC void pushreg(regid reg);
|
||||
SC_FUNC void pushval(cell val);
|
||||
SC_FUNC void popreg(regid reg);
|
||||
@ -923,6 +927,7 @@ SC_VDECL int pc_tag_string; /* global String tag */
|
||||
SC_VDECL int pc_tag_void; /* global void tag */
|
||||
SC_VDECL int pc_tag_object; /* root object tag */
|
||||
SC_VDECL int pc_tag_bool; /* global bool tag */
|
||||
SC_VDECL int pc_tag_null_t; /* the null type */
|
||||
SC_VDECL int pc_anytag; /* global any tag */
|
||||
SC_VDECL int glbstringread; /* last global string read */
|
||||
SC_VDECL int sc_require_newdecls; /* only newdecls are allowed */
|
||||
|
@ -79,6 +79,7 @@ int pc_tag_string = 0;
|
||||
int pc_tag_void = 0;
|
||||
int pc_tag_object = 0;
|
||||
int pc_tag_bool = 0;
|
||||
int pc_tag_null_t = 0;
|
||||
|
||||
static void resetglobals(void);
|
||||
static void initglobals(void);
|
||||
@ -1349,6 +1350,7 @@ static void setconstants(void)
|
||||
pc_tag_void = pc_addtag_flags("void", FIXEDTAG);
|
||||
pc_tag_object = pc_addtag_flags("object", FIXEDTAG|OBJECTTAG);
|
||||
pc_tag_bool = pc_addtag("bool");
|
||||
pc_tag_null_t = pc_addtag_flags("null_t", FIXEDTAG|OBJECTTAG);
|
||||
|
||||
add_constant("true",1,sGLOBAL,1); /* boolean flags */
|
||||
add_constant("false",0,sGLOBAL,1);
|
||||
@ -3442,7 +3444,7 @@ int parse_decl(declinfo_t *decl, int flags)
|
||||
|
||||
// Otherwise, we have to eat a symbol to tell.
|
||||
if (matchsymbol(&ident)) {
|
||||
if (lexpeek(tSYMBOL) || lexpeek(tOPERATOR)) {
|
||||
if (lexpeek(tSYMBOL) || lexpeek(tOPERATOR) || lexpeek('&')) {
|
||||
// A new-style declaration only allows array dims or a symbol name, so
|
||||
// this is a new-style declaration.
|
||||
return parse_new_decl(decl, &ident.tok, flags);
|
||||
@ -3973,6 +3975,9 @@ static void domethodmap(LayoutSpec spec)
|
||||
strcpy(map->name, mapname);
|
||||
if (spec == Layout_MethodMap) {
|
||||
map->tag = pc_addtag_flags(mapname, FIXEDTAG | METHODMAPTAG);
|
||||
|
||||
if (matchtoken(tNULLABLE))
|
||||
map->nullable = TRUE;
|
||||
} else {
|
||||
constvalue *tagptr = pc_tagptr(mapname);
|
||||
if (!tagptr) {
|
||||
@ -4032,35 +4037,48 @@ static void domethodmap(LayoutSpec spec)
|
||||
// delete ::= "delete" expr
|
||||
static void dodelete()
|
||||
{
|
||||
int tag;
|
||||
symbol *sym;
|
||||
svalue sval;
|
||||
|
||||
int ident = doexpr(TRUE, FALSE, TRUE, FALSE, &tag, &sym, TRUE);
|
||||
int lcl_staging = FALSE;
|
||||
if (!staging) {
|
||||
stgset(TRUE);
|
||||
lcl_staging = TRUE;
|
||||
assert(stgidx == 0);
|
||||
}
|
||||
int lcl_stgidx = stgidx;
|
||||
|
||||
int ident = lvalexpr(&sval);
|
||||
needtoken(tTERM);
|
||||
|
||||
switch (ident) {
|
||||
case iFUNCTN:
|
||||
case iREFFUNC:
|
||||
error(115, "functions");
|
||||
return;
|
||||
goto cleanup;
|
||||
|
||||
case iARRAY:
|
||||
case iREFARRAY:
|
||||
case iARRAYCELL:
|
||||
case iARRAYCHAR:
|
||||
error(115, "arrays");
|
||||
return;
|
||||
{
|
||||
symbol *sym = sval.val.sym;
|
||||
if (!sym || sym->dim.array.level > 0) {
|
||||
error(115, "arrays");
|
||||
goto cleanup;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tag == 0) {
|
||||
if (sval.val.tag == 0) {
|
||||
error(115, "primitive types or enums");
|
||||
return;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
methodmap_t *map = methodmap_find_by_tag(tag);
|
||||
methodmap_t *map = methodmap_find_by_tag(sval.val.tag);
|
||||
if (!map) {
|
||||
error(115, pc_tagname(tag));
|
||||
return;
|
||||
error(115, pc_tagname(sval.val.tag));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
{
|
||||
@ -4076,24 +4094,53 @@ static void dodelete()
|
||||
|
||||
if (!map || !map->dtor) {
|
||||
error(115, layout_spec_name(map->spec), map->name);
|
||||
return;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Only zap non-const lvalues.
|
||||
int zap = sval.lvalue;
|
||||
if (zap && sval.val.sym && (sval.val.sym->usage & uCONST))
|
||||
zap = FALSE;
|
||||
|
||||
int popaddr = FALSE;
|
||||
if (sval.lvalue) {
|
||||
if (zap) {
|
||||
if (sval.val.ident == iARRAYCELL || sval.val.ident == iARRAYCHAR) {
|
||||
// Address is in pri so we have to save it.
|
||||
pushreg(sPRI);
|
||||
popaddr = TRUE;
|
||||
}
|
||||
}
|
||||
rvalue(&sval.val);
|
||||
}
|
||||
|
||||
// For some reason, we don't get a sysreq.n once this passes through the
|
||||
// peephole optimizer. I can't tell why. -dvander
|
||||
//
|
||||
// push.pri
|
||||
// push.c 1
|
||||
// sysreq.c N 1
|
||||
// stack 8
|
||||
pushreg(sPRI);
|
||||
markexpr(sPARM,NULL,0);
|
||||
{
|
||||
pushval(1);
|
||||
ffcall(map->dtor->target, NULL, 1);
|
||||
markusage(map->dtor->target, uREAD);
|
||||
}
|
||||
markexpr(sEXPR,NULL,0);
|
||||
|
||||
if (zap) {
|
||||
if (popaddr)
|
||||
popreg(sALT);
|
||||
|
||||
// Store 0 back.
|
||||
ldconst(0, sPRI);
|
||||
store(&sval.val);
|
||||
}
|
||||
|
||||
markexpr(sEXPR, NULL, 0);
|
||||
|
||||
cleanup:
|
||||
if (lcl_staging) {
|
||||
stgout(lcl_stgidx);
|
||||
stgset(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4113,20 +4160,44 @@ static void dofuncenum(int listmode)
|
||||
|
||||
/* get the explicit tag (required!) */
|
||||
int l = lex(&val,&str);
|
||||
if (l != tSYMBOL)
|
||||
{
|
||||
if (listmode == FALSE && l == tPUBLIC)
|
||||
{
|
||||
isNewStyle = 1;
|
||||
newStyleTag = pc_addtag(NULL);
|
||||
l = lex(&val, &str);
|
||||
if (l != tSYMBOL)
|
||||
{
|
||||
if (l != tSYMBOL) {
|
||||
if (listmode == FALSE && l == tPUBLIC) {
|
||||
isNewStyle = TRUE;
|
||||
switch (lex(&val, &str)) {
|
||||
case tOBJECT:
|
||||
newStyleTag = pc_tag_object;
|
||||
break;
|
||||
case tINT:
|
||||
newStyleTag = 0;
|
||||
break;
|
||||
case tVOID:
|
||||
newStyleTag = pc_tag_void;
|
||||
break;
|
||||
case tCHAR:
|
||||
newStyleTag = pc_tag_string;
|
||||
break;
|
||||
case tLABEL:
|
||||
newStyleTag = pc_addtag(str);
|
||||
break;
|
||||
case tSYMBOL:
|
||||
// Check whether this is new-style declaration.
|
||||
// we'll port this all to parse_decl() sometime.
|
||||
if (lexpeek('('))
|
||||
lexpush();
|
||||
else
|
||||
newStyleTag = pc_addtag(str);
|
||||
break;
|
||||
default:
|
||||
error(93);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if (!needtoken(tSYMBOL)) {
|
||||
lexclr(TRUE);
|
||||
litidx = 0;
|
||||
return;
|
||||
}
|
||||
l = tokeninfo(&val, &str);
|
||||
} else {
|
||||
error(93);
|
||||
}
|
||||
}
|
||||
|
@ -1956,7 +1956,7 @@ char *sc_tokens[] = {
|
||||
"goto",
|
||||
"if", "int",
|
||||
"methodmap",
|
||||
"native", "new",
|
||||
"native", "new", "null", "__nullable__",
|
||||
"object", "operator",
|
||||
"public",
|
||||
"return",
|
||||
|
@ -356,6 +356,23 @@ static int matchobjecttags(int formaltag, int actualtag, int flags)
|
||||
// objects never coerce to non-objects, YET.
|
||||
if ((formaltag & OBJECTTAG) && !(actualtag & OBJECTTAG))
|
||||
return obj_typeerror(132, formaltag, actualtag);
|
||||
|
||||
if (actualtag == pc_tag_null_t) {
|
||||
// All objects are nullable.
|
||||
if (formaltag & OBJECTTAG)
|
||||
return TRUE;
|
||||
|
||||
// Some methodmaps are nullable.
|
||||
methodmap_t *map = methodmap_find_by_tag(formaltag);
|
||||
for (; map; map = map->parent) {
|
||||
if (map->nullable)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
error(148, pc_tagname(formaltag));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!(formaltag & OBJECTTAG) && (actualtag & OBJECTTAG))
|
||||
return obj_typeerror(131, formaltag, actualtag);
|
||||
|
||||
@ -375,6 +392,15 @@ static int matchobjecttags(int formaltag, int actualtag, int flags)
|
||||
return obj_typeerror(133, formaltag, actualtag);
|
||||
}
|
||||
|
||||
static int matchreturntag(functag_t *t, symbol *sym)
|
||||
{
|
||||
if (t->ret_tag == sym->tag)
|
||||
return TRUE;
|
||||
if (t->ret_tag == pc_tag_void && (sym->tag == 0 && !(sym->usage & uRETVALUE)))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int matchfunctags(int formaltag, int actualtag)
|
||||
{
|
||||
if (actualtag == pc_functag || (formaltag == pc_functag && actualtag & FUNCTAG))
|
||||
@ -447,7 +473,7 @@ static int matchfunctags(int formaltag, int actualtag)
|
||||
arginfo *func_arg;
|
||||
funcarg_t *enum_arg;
|
||||
/* Check return type first. */
|
||||
if (t->ret_tag != sym->tag) {
|
||||
if (!matchreturntag(t, sym)) {
|
||||
t = t->next;
|
||||
continue;
|
||||
}
|
||||
@ -496,7 +522,7 @@ static int matchfunctags(int formaltag, int actualtag)
|
||||
}
|
||||
/* They should all be in the same order just for clarity... */
|
||||
for (i=0; i<enum_arg->tagcount; i++) {
|
||||
if (enum_arg->tags[i] != func_arg->tags[i]) {
|
||||
if (!matchtag(func_arg->tags[i], enum_arg->tags[i], MATCHTAG_SILENT|MATCHTAG_COERCE)) {
|
||||
skip = 1;
|
||||
break;
|
||||
}
|
||||
@ -954,6 +980,19 @@ static cell calc(cell left,void (*oper)(),cell right,char *boolresult)
|
||||
return 0;
|
||||
}
|
||||
|
||||
SC_FUNC int lvalexpr(svalue *sval)
|
||||
{
|
||||
memset(sval, 0, sizeof(*sval));
|
||||
|
||||
errorset(sEXPRMARK, 0);
|
||||
pushheaplist();
|
||||
sval->lvalue = hier14(&sval->val);
|
||||
popheaplist();
|
||||
errorset(sEXPRRELEASE, 0);
|
||||
|
||||
return sval->val.ident;
|
||||
}
|
||||
|
||||
SC_FUNC int expression(cell *val,int *tag,symbol **symptr,int chkfuncresult,value *_lval)
|
||||
{
|
||||
value lval={0};
|
||||
@ -2949,6 +2988,11 @@ static int constant(value *lval)
|
||||
lval->tag=sym->tag;
|
||||
lval->sym=sym;
|
||||
markusage(sym,uREAD);
|
||||
} else if (tok==tNULL) {
|
||||
lval->constval = 0;
|
||||
ldconst(lval->constval, sPRI);
|
||||
lval->ident = iCONSTEXPR;
|
||||
lval->tag = pc_tag_null_t;
|
||||
} else if (tok==tNUMBER) {
|
||||
lval->constval=val;
|
||||
ldconst(lval->constval,sPRI);
|
||||
|
@ -637,6 +637,12 @@ SC_FUNC void moveto1(void)
|
||||
code_idx+=opcodes(1)+opargs(0);
|
||||
}
|
||||
|
||||
SC_FUNC void move_alt(void)
|
||||
{
|
||||
stgwrite("\tmove.alt\n");
|
||||
code_idx+=opcodes(1)+opargs(0);
|
||||
}
|
||||
|
||||
/* Push primary or the alternate register onto the stack
|
||||
*/
|
||||
SC_FUNC void pushreg(regid reg)
|
||||
|
@ -191,6 +191,7 @@ static char *errmsg[] = {
|
||||
/*145*/ "invalid type expression\n",
|
||||
/*146*/ "#pragma newdecls must be required or optional\n",
|
||||
/*147*/ "new-style declarations are required\n",
|
||||
/*148*/ "cannot assign null to a non-nullable type\n",
|
||||
#else
|
||||
"\247\255\311\232\273k\214:\234\306bu\201fo\223\204\222\012",
|
||||
"\202l\224\251s\206g\344\352e\233\201(\242\247\323\267\202) \254 f\252low ea\277 \042c\343e\042\012",
|
||||
|
@ -92,6 +92,7 @@ typedef struct methodmap_s
|
||||
struct methodmap_s *next;
|
||||
struct methodmap_s *parent;
|
||||
int tag;
|
||||
int nullable;
|
||||
LayoutSpec spec;
|
||||
char name[sNAMEMAX+1];
|
||||
methodmap_method_t **methods;
|
||||
|
Loading…
Reference in New Issue
Block a user