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 uRETNONE 0x10
|
||||||
|
|
||||||
#define flgDEPRECATED 0x01 /* symbol is deprecated (avoid use) */
|
#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 uCOUNTOF 0x20 /* set in the "hasdefault" field of the arginfo struct */
|
||||||
#define uTAGOF 0x40 /* 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,
|
tBEGIN,
|
||||||
tBREAK,
|
tBREAK,
|
||||||
tCASE,
|
tCASE,
|
||||||
|
tCAST_TO,
|
||||||
tCELLSOF,
|
tCELLSOF,
|
||||||
tCHAR,
|
tCHAR,
|
||||||
tCONST,
|
tCONST,
|
||||||
@ -417,6 +419,7 @@ enum TokenKind {
|
|||||||
tGOTO,
|
tGOTO,
|
||||||
tIF,
|
tIF,
|
||||||
tINT,
|
tINT,
|
||||||
|
tLET,
|
||||||
tMETHODMAP,
|
tMETHODMAP,
|
||||||
tNATIVE,
|
tNATIVE,
|
||||||
tNEW,
|
tNEW,
|
||||||
@ -437,6 +440,8 @@ enum TokenKind {
|
|||||||
tTHIS,
|
tTHIS,
|
||||||
tTYPEDEF,
|
tTYPEDEF,
|
||||||
tUNION,
|
tUNION,
|
||||||
|
tVAR,
|
||||||
|
tVIEW_AS,
|
||||||
tVOID,
|
tVOID,
|
||||||
tWHILE,
|
tWHILE,
|
||||||
/* compiler directives */
|
/* 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 = addsym(map->name, 0, iPROXY, sGLOBAL, 0, 0);
|
||||||
sym->target = method->target;
|
sym->target = method->target;
|
||||||
|
method->target->flags |= flgPROXIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Current lexer position is, we've parsed "public", an optional "native", and
|
// 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)
|
if (is_dtor)
|
||||||
map->dtor = method;
|
map->dtor = method;
|
||||||
|
if (is_ctor)
|
||||||
|
map->ctor = method;
|
||||||
|
|
||||||
require_newline(is_bind || (target->usage & uNATIVE));
|
require_newline(is_bind || (target->usage & uNATIVE));
|
||||||
return method;
|
return method;
|
||||||
|
@ -1961,12 +1961,13 @@ const char *sc_tokens[] = {
|
|||||||
"...", "..", "::",
|
"...", "..", "::",
|
||||||
"assert",
|
"assert",
|
||||||
"*begin", "break",
|
"*begin", "break",
|
||||||
"case", "cellsof", "char", "const", "continue",
|
"case", "cast_to", "cellsof", "char", "const", "continue",
|
||||||
"decl", "default", "defined", "delete", "do",
|
"decl", "default", "defined", "delete", "do",
|
||||||
"else", "*end", "enum", "exit",
|
"else", "*end", "enum", "exit",
|
||||||
"for", "forward", "funcenum", "functag", "function",
|
"for", "forward", "funcenum", "functag", "function",
|
||||||
"goto",
|
"goto",
|
||||||
"if", "int",
|
"if", "int",
|
||||||
|
"let",
|
||||||
"methodmap",
|
"methodmap",
|
||||||
"native", "new", "null", "__nullable__",
|
"native", "new", "null", "__nullable__",
|
||||||
"object", "operator",
|
"object", "operator",
|
||||||
@ -1975,7 +1976,7 @@ const char *sc_tokens[] = {
|
|||||||
"sizeof", "sleep", "static", "stock", "struct", "switch",
|
"sizeof", "sleep", "static", "stock", "struct", "switch",
|
||||||
"tagof", "*then", "this", "typedef",
|
"tagof", "*then", "this", "typedef",
|
||||||
"union",
|
"union",
|
||||||
"void",
|
"var", "view_as", "void",
|
||||||
"while",
|
"while",
|
||||||
"#assert", "#define", "#else", "#elseif", "#emit", "#endif", "#endinput",
|
"#assert", "#define", "#else", "#elseif", "#emit", "#endif", "#endinput",
|
||||||
"#endscript", "#error", "#file", "#if", "#include", "#line", "#pragma",
|
"#endscript", "#error", "#file", "#if", "#include", "#line", "#pragma",
|
||||||
|
@ -1619,6 +1619,47 @@ static int hier2(value *lval)
|
|||||||
lval->constval=-lval->constval;
|
lval->constval=-lval->constval;
|
||||||
} /* if */
|
} /* if */
|
||||||
return FALSE;
|
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 */
|
case tLABEL: /* tagname override */
|
||||||
tag=pc_addtag(st);
|
tag=pc_addtag(st);
|
||||||
lval->cmptag=tag;
|
lval->cmptag=tag;
|
||||||
@ -2223,6 +2264,16 @@ restart:
|
|||||||
funcdisplayname(symname,sym->name);
|
funcdisplayname(symname,sym->name);
|
||||||
error(4,symname); /* function not defined */
|
error(4,symname); /* function not defined */
|
||||||
} /* if */
|
} /* 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);
|
callfunction(sym,implicitthis,lval1,TRUE);
|
||||||
if (lexpeek('.')) {
|
if (lexpeek('.')) {
|
||||||
lvalue = FALSE;
|
lvalue = FALSE;
|
||||||
|
@ -213,6 +213,9 @@ static const char *errmsg[] = {
|
|||||||
/*167*/ "cannot use delete, %s do not have destructors\n",
|
/*167*/ "cannot use delete, %s do not have destructors\n",
|
||||||
/*168*/ "re-tagging enums is no longer supported\n",
|
/*168*/ "re-tagging enums is no longer supported\n",
|
||||||
/*169*/ "cannot tag an enum as implicit-int\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
|
#else
|
||||||
"\315e\306\227\266k\217:\235\277bu\201fo\220\204\223\012",
|
"\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",
|
"\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.
|
// Shortcut.
|
||||||
methodmap_method_t *dtor;
|
methodmap_method_t *dtor;
|
||||||
|
methodmap_method_t *ctor;
|
||||||
} methodmap_t;
|
} 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