mirror of
https://github.com/DarkPlacesEngine/gmqcc.git
synced 2025-01-19 06:40:49 +00:00
type comparison, function prototypes
This commit is contained in:
parent
e35a26a9e1
commit
65fb4b34b5
3 changed files with 86 additions and 18 deletions
21
ast.c
21
ast.c
|
@ -156,6 +156,27 @@ static ast_expression* ast_type_copy(lex_ctx ctx, const ast_expression *ex)
|
|||
}
|
||||
}
|
||||
|
||||
bool ast_compare_type(ast_expression *a, ast_expression *b)
|
||||
{
|
||||
if (a->expression.vtype != b->expression.vtype)
|
||||
return false;
|
||||
if (!a->expression.next != !b->expression.next)
|
||||
return false;
|
||||
if (a->expression.params_count != b->expression.params_count)
|
||||
return false;
|
||||
if (a->expression.params_count) {
|
||||
size_t i;
|
||||
for (i = 0; i < a->expression.params_count; ++i) {
|
||||
if (!ast_compare_type((ast_expression*)a->expression.params[i],
|
||||
(ast_expression*)b->expression.params[i]))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (a->expression.next)
|
||||
return ast_compare_type(a->expression.next, b->expression.next);
|
||||
return true;
|
||||
}
|
||||
|
||||
ast_value* ast_value_new(lex_ctx ctx, const char *name, int t)
|
||||
{
|
||||
ast_instantiate(ast_value, ctx, ast_value_delete);
|
||||
|
|
2
ast.h
2
ast.h
|
@ -160,6 +160,8 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir);
|
|||
|
||||
bool GMQCC_WARN ast_value_params_add(ast_value*, ast_value*);
|
||||
|
||||
bool ast_compare_type(ast_expression *a, ast_expression *b);
|
||||
|
||||
/* Binary
|
||||
*
|
||||
* A value-returning binary expression.
|
||||
|
|
81
parser.c
81
parser.c
|
@ -1398,8 +1398,9 @@ static bool parser_variable(parser_t *parser, ast_block *localblock)
|
|||
return false;
|
||||
}
|
||||
|
||||
isfunc = false;
|
||||
func = NULL;
|
||||
olddecl = NULL;
|
||||
isfunc = false;
|
||||
func = NULL;
|
||||
ctx = parser_ctx(parser);
|
||||
var = parser_parse_type(parser, basetype, &isfunc);
|
||||
|
||||
|
@ -1411,18 +1412,20 @@ static bool parser_variable(parser_t *parser, ast_block *localblock)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!localblock && (olddecl = parser_find_global(parser, parser_tokval(parser)))) {
|
||||
ast_value_delete(var);
|
||||
parseerror(parser, "global %s already declared here: %s:%i\n",
|
||||
parser_tokval(parser), ast_ctx(olddecl).file, (int)ast_ctx(olddecl).line);
|
||||
return false;
|
||||
}
|
||||
if (!isfunc) {
|
||||
if (!localblock && (olddecl = parser_find_global(parser, parser_tokval(parser)))) {
|
||||
ast_value_delete(var);
|
||||
parseerror(parser, "global %s already declared here: %s:%i\n",
|
||||
parser_tokval(parser), ast_ctx(olddecl).file, (int)ast_ctx(olddecl).line);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (localblock && parser_find_local(parser, parser_tokval(parser), parser->blocklocal)) {
|
||||
ast_value_delete(var);
|
||||
parseerror(parser, "local %s already declared here: %s:%i\n",
|
||||
parser_tokval(parser), ast_ctx(olddecl).file, (int)ast_ctx(olddecl).line);
|
||||
return false;
|
||||
if (localblock && parser_find_local(parser, parser_tokval(parser), parser->blocklocal)) {
|
||||
ast_value_delete(var);
|
||||
parseerror(parser, "local %s already declared here: %s:%i\n",
|
||||
parser_tokval(parser), ast_ctx(olddecl).file, (int)ast_ctx(olddecl).line);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ast_value_set_name(var, parser_tokval(parser))) {
|
||||
|
@ -1434,6 +1437,30 @@ static bool parser_variable(parser_t *parser, ast_block *localblock)
|
|||
if (isfunc) {
|
||||
/* a function was defined */
|
||||
ast_value *fval;
|
||||
ast_value *proto = NULL;
|
||||
|
||||
if (!localblock)
|
||||
olddecl = parser_find_global(parser, parser_tokval(parser));
|
||||
else
|
||||
olddecl = parser_find_local(parser, parser_tokval(parser), parser->blocklocal);
|
||||
|
||||
if (olddecl) {
|
||||
/* we had a prototype */
|
||||
if (!ast_istype(olddecl, ast_value)) {
|
||||
/* theoretically not possible you think?
|
||||
* well:
|
||||
* vector v;
|
||||
* void() v_x = {}
|
||||
* got it?
|
||||
*/
|
||||
parseerror(parser, "cannot declare a function with the same name as a vector's member: %s",
|
||||
parser_tokval(parser));
|
||||
ast_value_delete(var);
|
||||
return false;
|
||||
}
|
||||
|
||||
proto = (ast_value*)olddecl;
|
||||
}
|
||||
|
||||
/* turn var into a value of TYPE_FUNCTION, with the old var
|
||||
* as return type
|
||||
|
@ -1450,11 +1477,29 @@ static bool parser_variable(parser_t *parser, ast_block *localblock)
|
|||
fval->expression.next = (ast_expression*)var;
|
||||
MEM_VECTOR_MOVE(&var->expression, params, &fval->expression, params);
|
||||
|
||||
if (!parser_t_functions_add(parser, func)) {
|
||||
ast_value_delete(var);
|
||||
if (fval) ast_value_delete(fval);
|
||||
if (func) ast_function_delete(func);
|
||||
return false;
|
||||
/* we compare the type late here, but it's easier than
|
||||
* messing with the parameter-vector etc. earlier
|
||||
*/
|
||||
if (proto) {
|
||||
if (!ast_compare_type((ast_expression*)proto, (ast_expression*)fval)) {
|
||||
parseerror(parser, "prototype declared at %s:%i had a different type",
|
||||
ast_ctx(fval).file, ast_ctx(fval).line);
|
||||
ast_function_delete(func);
|
||||
ast_value_delete(fval);
|
||||
return false;
|
||||
}
|
||||
ast_function_delete(func);
|
||||
ast_value_delete(fval);
|
||||
var = proto;
|
||||
func = var->constval.vfunc;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!parser_t_functions_add(parser, func)) {
|
||||
ast_function_delete(func);
|
||||
ast_value_delete(fval);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var = fval;
|
||||
|
|
Loading…
Reference in a new issue