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
|
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):
|
||||||
|
@ -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;
|
||||||
|
@ -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 */
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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",
|
||||||
|
@ -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);
|
||||||
|
@ -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)
|
||||||
|
@ -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",
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user