Add a "new" keyword for constructing nullable methodmaps.

This commit is contained in:
David Anderson 2014-11-30 18:38:26 -08:00
parent e7e43e38a5
commit 9f5c8b60ae
15 changed files with 130 additions and 2 deletions

View File

@ -227,6 +227,7 @@ typedef struct s_symbol {
#define uRETNONE 0x10
#define flgDEPRECATED 0x01 /* symbol is deprecated (avoid use) */
#define flgPROXIED 0x02 /* symbol has incoming proxy */
#define uCOUNTOF 0x20 /* set in the "hasdefault" field of the arginfo struct */
#define uTAGOF 0x40 /* set in the "hasdefault" field of the arginfo struct */
@ -396,6 +397,7 @@ enum TokenKind {
tBEGIN,
tBREAK,
tCASE,
tCAST_TO,
tCELLSOF,
tCHAR,
tCONST,
@ -417,6 +419,7 @@ enum TokenKind {
tGOTO,
tIF,
tINT,
tLET,
tMETHODMAP,
tNATIVE,
tNEW,
@ -437,6 +440,8 @@ enum TokenKind {
tTHIS,
tTYPEDEF,
tUNION,
tVAR,
tVIEW_AS,
tVOID,
tWHILE,
/* compiler directives */

View File

@ -3594,6 +3594,7 @@ static void define_constructor(methodmap_t *map, methodmap_method_t *method)
sym = addsym(map->name, 0, iPROXY, sGLOBAL, 0, 0);
sym->target = method->target;
method->target->flags |= flgPROXIED;
}
// Current lexer position is, we've parsed "public", an optional "native", and
@ -4034,6 +4035,8 @@ methodmap_method_t *parse_method(methodmap_t *map)
if (is_dtor)
map->dtor = method;
if (is_ctor)
map->ctor = method;
require_newline(is_bind || (target->usage & uNATIVE));
return method;

View File

@ -1961,12 +1961,13 @@ const char *sc_tokens[] = {
"...", "..", "::",
"assert",
"*begin", "break",
"case", "cellsof", "char", "const", "continue",
"case", "cast_to", "cellsof", "char", "const", "continue",
"decl", "default", "defined", "delete", "do",
"else", "*end", "enum", "exit",
"for", "forward", "funcenum", "functag", "function",
"goto",
"if", "int",
"let",
"methodmap",
"native", "new", "null", "__nullable__",
"object", "operator",
@ -1975,7 +1976,7 @@ const char *sc_tokens[] = {
"sizeof", "sleep", "static", "stock", "struct", "switch",
"tagof", "*then", "this", "typedef",
"union",
"void",
"var", "view_as", "void",
"while",
"#assert", "#define", "#else", "#elseif", "#emit", "#endif", "#endinput",
"#endscript", "#error", "#file", "#if", "#include", "#line", "#pragma",

View File

@ -1619,6 +1619,47 @@ static int hier2(value *lval)
lval->constval=-lval->constval;
} /* if */
return FALSE;
case tNEW: /* call nullable methodmap constructor */
{
tok = lex(&val, &st);
if (tok != tSYMBOL)
return error(20, st); /* illegal symbol name */
symbol *target = NULL;
methodmap_t *methodmap = methodmap_find_by_name(st);
if (!methodmap)
error(116, st);
else if (!methodmap->nullable)
error(171, methodmap->name);
else if (!methodmap->ctor)
error(172, methodmap->name);
else
target = methodmap->ctor->target;
if (!target) {
needtoken('(');
int depth = 1;
// Eat tokens until we get a newline or EOF or ')' or ';'
while (true) {
if (peek_same_line() == tEOL)
return FALSE;
if ((tok = lex(&val, &st)) == 0)
return FALSE;
if (tok == ')') {
if (--depth == 0)
return FALSE;
}
if (tok == ';')
return FALSE;
if (tok == '(')
depth++;
}
}
needtoken('(');
callfunction(target, NULL, lval, TRUE);
return FALSE;
}
case tLABEL: /* tagname override */
tag=pc_addtag(st);
lval->cmptag=tag;
@ -2223,6 +2264,16 @@ restart:
funcdisplayname(symname,sym->name);
error(4,symname); /* function not defined */
} /* if */
if (sym->flags & flgPROXIED) {
// Only constructors should be proxied, but we check anyway.
assert(!implicitthis);
if (methodmap_t *methodmap = methodmap_find_by_tag(sym->tag)) {
if (sym == methodmap->ctor->target && methodmap->nullable)
error(170, methodmap->name);
}
}
callfunction(sym,implicitthis,lval1,TRUE);
if (lexpeek('.')) {
lvalue = FALSE;

View File

@ -213,6 +213,9 @@ static const char *errmsg[] = {
/*167*/ "cannot use delete, %s do not have destructors\n",
/*168*/ "re-tagging enums is no longer supported\n",
/*169*/ "cannot tag an enum as implicit-int\n",
/*170*/ "creating new object '%s' requires using 'new' before its constructor\n",
/*171*/ "cannot use 'new' with non-object-like methodmap '%s'\n",
/*172*/ "methodmap '%s' does not have a constructor\n",
#else
"\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",

View File

@ -113,6 +113,7 @@ typedef struct methodmap_s
// Shortcut.
methodmap_method_t *dtor;
methodmap_method_t *ctor;
} methodmap_t;
/**

View File

@ -0,0 +1,10 @@
methodmap Handle __nullable__
{
public native ~Handle();
};
public t()
{
Handle egg = new Handle();
delete egg;
}

View File

@ -0,0 +1 @@
(8) : error 172: methodmap 'Handle' does not have a constructor

View File

@ -0,0 +1,13 @@
methodmap Handle __nullable__
{
public native Handle();
public native ~Handle();
};
enum Crab {};
public t()
{
Crab egg = new Crab();
delete egg;
}

View File

@ -0,0 +1 @@
(11) : error 116: no methodmap or class was found for Crab

View File

@ -0,0 +1,11 @@
methodmap Handle
{
public native Handle();
public native ~Handle();
};
public t()
{
Handle egg = new Handle();
delete egg;
}

View File

@ -0,0 +1 @@
(9) : error 171: cannot use 'new' with non-object-like methodmap 'Handle'

View File

@ -0,0 +1,11 @@
methodmap Handle __nullable__
{
public native Handle();
public native ~Handle();
};
public t()
{
Handle egg = Handle();
delete egg;
}

View File

@ -0,0 +1 @@
(9) : error 170: creating new object 'Handle' requires using 'new' before its constructor

View File

@ -0,0 +1,15 @@
native void printnum(int num);
methodmap Handle __nullable__
{
public Handle() {
return Handle:2;
}
public native ~Handle();
};
public main()
{
Handle egg = new Handle();
printnum(_:egg);
}