Merge pull request #73 from alliedmodders/nullable

Add nullable types and tighten up some new type system semantics.
This commit is contained in:
David Anderson 2014-07-06 11:45:09 -07:00
commit 97e0c84e6d
9 changed files with 165 additions and 35 deletions

View File

@ -73,7 +73,9 @@ class SMConfig(object):
self.versionlib = None self.versionlib = None
def use_auto_versioning(self): 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 @property
def tag(self): def tag(self):

View File

@ -78,7 +78,7 @@ native Handle:CloneHandle(Handle:hndl, Handle:plugin=INVALID_HANDLE);
/** /**
* Helper for object-oriented syntax. * Helper for object-oriented syntax.
*/ */
methodmap Handle methodmap Handle __nullable__
{ {
public Clone() = CloneHandle; public Clone() = CloneHandle;
public ~Handle() = CloseHandle; public ~Handle() = CloseHandle;

View File

@ -411,6 +411,8 @@ enum {
tMETHODMAP, tMETHODMAP,
tNATIVE, tNATIVE,
tNEW, tNEW,
tNULL,
tNULLABLE,
tOBJECT, tOBJECT,
tOPERATOR, tOPERATOR,
tPUBLIC, tPUBLIC,
@ -675,6 +677,7 @@ SC_FUNC cell array_totalsize(symbol *sym);
SC_FUNC int matchtag_string(int ident, int tag); SC_FUNC int matchtag_string(int ident, int tag);
SC_FUNC int checktag_string(value *sym1, value *sym2); SC_FUNC int checktag_string(value *sym1, value *sym2);
SC_FUNC int checktags_string(int tags[], int numtags, value *sym1); SC_FUNC int checktags_string(int tags[], int numtags, value *sym1);
SC_FUNC int lvalexpr(svalue *sval);
/* function prototypes in SC4.C */ /* function prototypes in SC4.C */
SC_FUNC void writeleader(symbol *root); 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 fillarray(symbol *sym,cell size,cell value);
SC_FUNC void ldconst(cell val,regid reg); SC_FUNC void ldconst(cell val,regid reg);
SC_FUNC void moveto1(void); SC_FUNC void moveto1(void);
SC_FUNC void move_alt(void);
SC_FUNC void pushreg(regid reg); SC_FUNC void pushreg(regid reg);
SC_FUNC void pushval(cell val); SC_FUNC void pushval(cell val);
SC_FUNC void popreg(regid reg); 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_void; /* global void tag */
SC_VDECL int pc_tag_object; /* root object tag */ SC_VDECL int pc_tag_object; /* root object tag */
SC_VDECL int pc_tag_bool; /* global bool 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 pc_anytag; /* global any tag */
SC_VDECL int glbstringread; /* last global string read */ SC_VDECL int glbstringread; /* last global string read */
SC_VDECL int sc_require_newdecls; /* only newdecls are allowed */ SC_VDECL int sc_require_newdecls; /* only newdecls are allowed */

View File

@ -79,6 +79,7 @@ int pc_tag_string = 0;
int pc_tag_void = 0; int pc_tag_void = 0;
int pc_tag_object = 0; int pc_tag_object = 0;
int pc_tag_bool = 0; int pc_tag_bool = 0;
int pc_tag_null_t = 0;
static void resetglobals(void); static void resetglobals(void);
static void initglobals(void); static void initglobals(void);
@ -1349,6 +1350,7 @@ static void setconstants(void)
pc_tag_void = pc_addtag_flags("void", FIXEDTAG); pc_tag_void = pc_addtag_flags("void", FIXEDTAG);
pc_tag_object = pc_addtag_flags("object", FIXEDTAG|OBJECTTAG); pc_tag_object = pc_addtag_flags("object", FIXEDTAG|OBJECTTAG);
pc_tag_bool = pc_addtag("bool"); 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("true",1,sGLOBAL,1); /* boolean flags */
add_constant("false",0,sGLOBAL,1); 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. // Otherwise, we have to eat a symbol to tell.
if (matchsymbol(&ident)) { 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 // A new-style declaration only allows array dims or a symbol name, so
// this is a new-style declaration. // this is a new-style declaration.
return parse_new_decl(decl, &ident.tok, flags); return parse_new_decl(decl, &ident.tok, flags);
@ -3973,6 +3975,9 @@ static void domethodmap(LayoutSpec spec)
strcpy(map->name, mapname); strcpy(map->name, mapname);
if (spec == Layout_MethodMap) { if (spec == Layout_MethodMap) {
map->tag = pc_addtag_flags(mapname, FIXEDTAG | METHODMAPTAG); map->tag = pc_addtag_flags(mapname, FIXEDTAG | METHODMAPTAG);
if (matchtoken(tNULLABLE))
map->nullable = TRUE;
} else { } else {
constvalue *tagptr = pc_tagptr(mapname); constvalue *tagptr = pc_tagptr(mapname);
if (!tagptr) { if (!tagptr) {
@ -4032,35 +4037,48 @@ static void domethodmap(LayoutSpec spec)
// delete ::= "delete" expr // delete ::= "delete" expr
static void dodelete() static void dodelete()
{ {
int tag; svalue sval;
symbol *sym;
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); needtoken(tTERM);
switch (ident) { switch (ident) {
case iFUNCTN: case iFUNCTN:
case iREFFUNC: case iREFFUNC:
error(115, "functions"); error(115, "functions");
return; goto cleanup;
case iARRAY: case iARRAY:
case iREFARRAY: case iREFARRAY:
case iARRAYCELL: case iARRAYCELL:
case iARRAYCHAR: 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"); 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) { if (!map) {
error(115, pc_tagname(tag)); error(115, pc_tagname(sval.val.tag));
return; goto cleanup;
} }
{ {
@ -4076,24 +4094,53 @@ static void dodelete()
if (!map || !map->dtor) { if (!map || !map->dtor) {
error(115, layout_spec_name(map->spec), map->name); 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.pri
// push.c 1 // push.c 1
// sysreq.c N 1 // sysreq.c N 1
// stack 8 // stack 8
pushreg(sPRI); pushreg(sPRI);
markexpr(sPARM,NULL,0);
{ {
pushval(1); pushval(1);
ffcall(map->dtor->target, NULL, 1); ffcall(map->dtor->target, NULL, 1);
markusage(map->dtor->target, uREAD); 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!) */ /* get the explicit tag (required!) */
int l = lex(&val,&str); int l = lex(&val,&str);
if (l != tSYMBOL) if (l != tSYMBOL) {
{ if (listmode == FALSE && l == tPUBLIC) {
if (listmode == FALSE && l == tPUBLIC) isNewStyle = TRUE;
{ switch (lex(&val, &str)) {
isNewStyle = 1; case tOBJECT:
newStyleTag = pc_addtag(NULL); newStyleTag = pc_tag_object;
l = lex(&val, &str); break;
if (l != tSYMBOL) 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); error(93);
} }
}
else if (!needtoken(tSYMBOL)) {
{ lexclr(TRUE);
litidx = 0;
return;
}
l = tokeninfo(&val, &str);
} else {
error(93); error(93);
} }
} }

View File

@ -1956,7 +1956,7 @@ char *sc_tokens[] = {
"goto", "goto",
"if", "int", "if", "int",
"methodmap", "methodmap",
"native", "new", "native", "new", "null", "__nullable__",
"object", "operator", "object", "operator",
"public", "public",
"return", "return",

View File

@ -356,6 +356,23 @@ static int matchobjecttags(int formaltag, int actualtag, int flags)
// objects never coerce to non-objects, YET. // objects never coerce to non-objects, YET.
if ((formaltag & OBJECTTAG) && !(actualtag & OBJECTTAG)) if ((formaltag & OBJECTTAG) && !(actualtag & OBJECTTAG))
return obj_typeerror(132, formaltag, actualtag); 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)) if (!(formaltag & OBJECTTAG) && (actualtag & OBJECTTAG))
return obj_typeerror(131, formaltag, actualtag); 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); 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) static int matchfunctags(int formaltag, int actualtag)
{ {
if (actualtag == pc_functag || (formaltag == pc_functag && actualtag & FUNCTAG)) if (actualtag == pc_functag || (formaltag == pc_functag && actualtag & FUNCTAG))
@ -447,7 +473,7 @@ static int matchfunctags(int formaltag, int actualtag)
arginfo *func_arg; arginfo *func_arg;
funcarg_t *enum_arg; funcarg_t *enum_arg;
/* Check return type first. */ /* Check return type first. */
if (t->ret_tag != sym->tag) { if (!matchreturntag(t, sym)) {
t = t->next; t = t->next;
continue; continue;
} }
@ -496,7 +522,7 @@ static int matchfunctags(int formaltag, int actualtag)
} }
/* They should all be in the same order just for clarity... */ /* They should all be in the same order just for clarity... */
for (i=0; i<enum_arg->tagcount; i++) { 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; skip = 1;
break; break;
} }
@ -954,6 +980,19 @@ static cell calc(cell left,void (*oper)(),cell right,char *boolresult)
return 0; 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) SC_FUNC int expression(cell *val,int *tag,symbol **symptr,int chkfuncresult,value *_lval)
{ {
value lval={0}; value lval={0};
@ -2949,6 +2988,11 @@ static int constant(value *lval)
lval->tag=sym->tag; lval->tag=sym->tag;
lval->sym=sym; lval->sym=sym;
markusage(sym,uREAD); 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) { } else if (tok==tNUMBER) {
lval->constval=val; lval->constval=val;
ldconst(lval->constval,sPRI); ldconst(lval->constval,sPRI);

View File

@ -637,6 +637,12 @@ SC_FUNC void moveto1(void)
code_idx+=opcodes(1)+opargs(0); 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 /* Push primary or the alternate register onto the stack
*/ */
SC_FUNC void pushreg(regid reg) SC_FUNC void pushreg(regid reg)

View File

@ -191,6 +191,7 @@ static char *errmsg[] = {
/*145*/ "invalid type expression\n", /*145*/ "invalid type expression\n",
/*146*/ "#pragma newdecls must be required or optional\n", /*146*/ "#pragma newdecls must be required or optional\n",
/*147*/ "new-style declarations are required\n", /*147*/ "new-style declarations are required\n",
/*148*/ "cannot assign null to a non-nullable type\n",
#else #else
"\247\255\311\232\273k\214:\234\306bu\201fo\223\204\222\012", "\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", "\202l\224\251s\206g\344\352e\233\201(\242\247\323\267\202) \254 f\252low ea\277 \042c\343e\042\012",

View File

@ -92,6 +92,7 @@ typedef struct methodmap_s
struct methodmap_s *next; struct methodmap_s *next;
struct methodmap_s *parent; struct methodmap_s *parent;
int tag; int tag;
int nullable;
LayoutSpec spec; LayoutSpec spec;
char name[sNAMEMAX+1]; char name[sNAMEMAX+1];
methodmap_method_t **methods; methodmap_method_t **methods;