Add a "new" keyword for constructing nullable methodmaps.
This commit is contained in:
parent
e7e43e38a5
commit
9f5c8b60ae
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
|
@ -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",
|
||||
|
@ -113,6 +113,7 @@ typedef struct methodmap_s
|
||||
|
||||
// Shortcut.
|
||||
methodmap_method_t *dtor;
|
||||
methodmap_method_t *ctor;
|
||||
} methodmap_t;
|
||||
|
||||
/**
|
||||
|
10
sourcepawn/compiler/tests/fail-new-with-no-constructor.sp
Normal file
10
sourcepawn/compiler/tests/fail-new-with-no-constructor.sp
Normal file
@ -0,0 +1,10 @@
|
||||
methodmap Handle __nullable__
|
||||
{
|
||||
public native ~Handle();
|
||||
};
|
||||
|
||||
public t()
|
||||
{
|
||||
Handle egg = new Handle();
|
||||
delete egg;
|
||||
}
|
@ -0,0 +1 @@
|
||||
(8) : error 172: methodmap 'Handle' does not have a constructor
|
13
sourcepawn/compiler/tests/fail-new-with-no-methodmap.sp
Normal file
13
sourcepawn/compiler/tests/fail-new-with-no-methodmap.sp
Normal file
@ -0,0 +1,13 @@
|
||||
methodmap Handle __nullable__
|
||||
{
|
||||
public native Handle();
|
||||
public native ~Handle();
|
||||
};
|
||||
|
||||
enum Crab {};
|
||||
|
||||
public t()
|
||||
{
|
||||
Crab egg = new Crab();
|
||||
delete egg;
|
||||
}
|
1
sourcepawn/compiler/tests/fail-new-with-no-methodmap.txt
Normal file
1
sourcepawn/compiler/tests/fail-new-with-no-methodmap.txt
Normal file
@ -0,0 +1 @@
|
||||
(11) : error 116: no methodmap or class was found for Crab
|
11
sourcepawn/compiler/tests/fail-new-with-non-nullable.sp
Normal file
11
sourcepawn/compiler/tests/fail-new-with-non-nullable.sp
Normal file
@ -0,0 +1,11 @@
|
||||
methodmap Handle
|
||||
{
|
||||
public native Handle();
|
||||
public native ~Handle();
|
||||
};
|
||||
|
||||
public t()
|
||||
{
|
||||
Handle egg = new Handle();
|
||||
delete egg;
|
||||
}
|
1
sourcepawn/compiler/tests/fail-new-with-non-nullable.txt
Normal file
1
sourcepawn/compiler/tests/fail-new-with-non-nullable.txt
Normal file
@ -0,0 +1 @@
|
||||
(9) : error 171: cannot use 'new' with non-object-like methodmap 'Handle'
|
11
sourcepawn/compiler/tests/fail-nullable-needs-new.sp
Normal file
11
sourcepawn/compiler/tests/fail-nullable-needs-new.sp
Normal file
@ -0,0 +1,11 @@
|
||||
methodmap Handle __nullable__
|
||||
{
|
||||
public native Handle();
|
||||
public native ~Handle();
|
||||
};
|
||||
|
||||
public t()
|
||||
{
|
||||
Handle egg = Handle();
|
||||
delete egg;
|
||||
}
|
1
sourcepawn/compiler/tests/fail-nullable-needs-new.txt
Normal file
1
sourcepawn/compiler/tests/fail-nullable-needs-new.txt
Normal file
@ -0,0 +1 @@
|
||||
(9) : error 170: creating new object 'Handle' requires using 'new' before its constructor
|
15
sourcepawn/compiler/tests/ok-new-with-nullable-methodmap.sp
Normal file
15
sourcepawn/compiler/tests/ok-new-with-nullable-methodmap.sp
Normal 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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user