Skip to content

Commit

Permalink
Add a "new" keyword for constructing nullable methodmaps.
Browse files Browse the repository at this point in the history
  • Loading branch information
dvander committed Dec 1, 2014
1 parent e7e43e3 commit 9f5c8b6
Show file tree
Hide file tree
Showing 15 changed files with 130 additions and 2 deletions.
5 changes: 5 additions & 0 deletions sourcepawn/compiler/sc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -396,6 +397,7 @@ enum TokenKind {
tBEGIN,
tBREAK,
tCASE,
tCAST_TO,
tCELLSOF,
tCHAR,
tCONST,
Expand All @@ -417,6 +419,7 @@ enum TokenKind {
tGOTO,
tIF,
tINT,
tLET,
tMETHODMAP,
tNATIVE,
tNEW,
Expand All @@ -437,6 +440,8 @@ enum TokenKind {
tTHIS,
tTYPEDEF,
tUNION,
tVAR,
tVIEW_AS,
tVOID,
tWHILE,
/* compiler directives */
Expand Down
3 changes: 3 additions & 0 deletions sourcepawn/compiler/sc1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down
5 changes: 3 additions & 2 deletions sourcepawn/compiler/sc2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand Down
51 changes: 51 additions & 0 deletions sourcepawn/compiler/sc3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -2223,6 +2264,16 @@ static int hier1(value *lval1)
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;
Expand Down
3 changes: 3 additions & 0 deletions sourcepawn/compiler/sc5-in.scp
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
1 change: 1 addition & 0 deletions sourcepawn/compiler/sctracker.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ typedef struct methodmap_s

// Shortcut.
methodmap_method_t *dtor;
methodmap_method_t *ctor;
} methodmap_t;

/**
Expand Down
10 changes: 10 additions & 0 deletions sourcepawn/compiler/tests/fail-new-with-no-constructor.sp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
methodmap Handle __nullable__
{
public native ~Handle();
};

public t()
{
Handle egg = new Handle();
delete egg;
}
1 change: 1 addition & 0 deletions sourcepawn/compiler/tests/fail-new-with-no-constructor.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(8) : error 172: methodmap 'Handle' does not have a constructor
13 changes: 13 additions & 0 deletions sourcepawn/compiler/tests/fail-new-with-no-methodmap.sp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
methodmap Handle __nullable__
{
public native Handle();
public native ~Handle();
};

enum Crab {};

public t()
{
Crab egg = new Crab();
delete egg;
}
1 change: 1 addition & 0 deletions sourcepawn/compiler/tests/fail-new-with-no-methodmap.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(11) : error 116: no methodmap or class was found for Crab
11 changes: 11 additions & 0 deletions sourcepawn/compiler/tests/fail-new-with-non-nullable.sp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
methodmap Handle
{
public native Handle();
public native ~Handle();
};

public t()
{
Handle egg = new Handle();
delete egg;
}
1 change: 1 addition & 0 deletions sourcepawn/compiler/tests/fail-new-with-non-nullable.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(9) : error 171: cannot use 'new' with non-object-like methodmap 'Handle'
11 changes: 11 additions & 0 deletions sourcepawn/compiler/tests/fail-nullable-needs-new.sp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
methodmap Handle __nullable__
{
public native Handle();
public native ~Handle();
};

public t()
{
Handle egg = Handle();
delete egg;
}
1 change: 1 addition & 0 deletions sourcepawn/compiler/tests/fail-nullable-needs-new.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(9) : error 170: creating new object 'Handle' requires using 'new' before its constructor
15 changes: 15 additions & 0 deletions sourcepawn/compiler/tests/ok-new-with-nullable-methodmap.sp
Original file line number Diff line number Diff line change
@@ -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);
}

0 comments on commit 9f5c8b6

Please sign in to comment.