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
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):

View File

@ -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;

View File

@ -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 */

View File

@ -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);
}
}

View File

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

View File

@ -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);

View File

@ -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)

View File

@ -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",

View File

@ -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;