From: Dale Weiler Date: Wed, 6 Feb 2013 05:30:09 +0000 (+0000) Subject: Implemented generalized attribute aliases. You can now alias functions, locals,... X-Git-Tag: before-library~147 X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=commitdiff_plain;h=e464cc1ea66ef3ab33226c58ac4ad2ed79fa6eb8 Implemented generalized attribute aliases. You can now alias functions, locals, or globals with [[alias("old_name")]] type new_name; --- diff --git a/ast.h b/ast.h index 83c700a..9b55421 100644 --- a/ast.h +++ b/ast.h @@ -151,6 +151,7 @@ typedef struct #define AST_FLAG_DEPRECATED (1<<4) #define AST_FLAG_INCLUDE_DEF (1<<5) #define AST_FLAG_IS_VARARG (1<<6) +#define AST_FLAG_ALIAS (1<<7) #define AST_FLAG_TYPE_MASK (AST_FLAG_VARIADIC | AST_FLAG_NORETURN) /* Value diff --git a/parser.c b/parser.c index d5f800c..4ba08b4 100644 --- a/parser.c +++ b/parser.c @@ -62,6 +62,7 @@ typedef struct { size_t crc_fields; ast_function *function; + ht aliases; /* All the labels the function defined... * Should they be in ast_function instead? @@ -1825,9 +1826,11 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels) /* intrinsics */ if (!strcmp(parser_tokval(parser), "__builtin_debug_typestring")) { var = (ast_expression*)intrinsic_debug_typestring; + } else { + var = (ast_expression*)parser_find_var(parser, (const char *)util_htget(parser->aliases, parser_tokval(parser))); } - else - { + + if (!var) { char *correct = NULL; size_t i; @@ -2932,8 +2935,44 @@ static bool parse_qualifiers(parser_t *parser, bool with_local, int *cvq, bool * return false; } } + else if (!strcmp(parser_tokval(parser), "alias") && !(flags & AST_FLAG_ALIAS)) { + flags |= AST_FLAG_ALIAS; + *message = NULL; + if (!parser_next(parser)) { + parseerror(parser, "parse error in attribute"); + goto argerr; + } + if (parser->tok == '(') { + if (!parser_next(parser) || parser->tok != TOKEN_STRINGCONST) { + parseerror(parser, "`alias` attribute missing parameter"); + goto argerr; + } + + *message = util_strdup(parser_tokval(parser)); + + if (!parser_next(parser)) { + parseerror(parser, "parse error in attribute"); + goto argerr; + } + + if (parser->tok != ')') { + parseerror(parser, "`alias` attribute expected `)` after parameter"); + goto argerr; + } + + if (!parser_next(parser)) { + parseerror(parser, "parse error in attribute"); + goto argerr; + } + } + + if (parser->tok != TOKEN_ATTRIBUTE_CLOSE) { + parseerror(parser, "`alias` attribute expected `]]`"); + goto argerr; + } + } else if (!strcmp(parser_tokval(parser), "deprecated") && !(flags & AST_FLAG_DEPRECATED)) { flags |= AST_FLAG_DEPRECATED; *message = NULL; @@ -3820,6 +3859,11 @@ static bool parse_function_body(parser_t *parser, ast_value *var) has_frame_think = false; old = parser->function; + if (var->expression.flags & AST_FLAG_ALIAS) { + parseerror(parser, "function aliases cannot have bodies"); + return false; + } + if (vec_size(parser->gotos) || vec_size(parser->labels)) { parseerror(parser, "gotos/labels leaking"); return false; @@ -5012,7 +5056,13 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield var->cvq = qualifier; var->expression.flags |= qflags; - if (var->expression.flags & AST_FLAG_DEPRECATED) + + /* + * store the vstring back to var for alias and + * deprecation messages. + */ + if (var->expression.flags & AST_FLAG_DEPRECATED || + var->expression.flags & AST_FLAG_ALIAS) var->desc = vstring; /* Part 1: @@ -5217,11 +5267,15 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield } } else { - parser_addglobal(parser, var->name, (ast_expression*)var); - if (isvector) { - for (i = 0; i < 3; ++i) { - parser_addglobal(parser, me[i]->name, (ast_expression*)me[i]); + if (!(var->expression.flags & AST_FLAG_ALIAS)) { + parser_addglobal(parser, var->name, (ast_expression*)var); + if (isvector) { + for (i = 0; i < 3; ++i) { + parser_addglobal(parser, me[i]->name, (ast_expression*)me[i]); + } } + } else { + util_htset(parser->aliases, var->name, (void*)var->desc); } } } else { @@ -5718,6 +5772,8 @@ bool parser_init() vec_push(parser->typedefs, util_htnew(TYPEDEF_HT_SIZE)); vec_push(parser->_blocktypedefs, 0); + parser->aliases = util_htnew(PARSER_HT_SIZE); + /* corrector */ vec_push(parser->correct_variables, correct_trie_new()); vec_push(parser->correct_variables_score, NULL); @@ -5868,6 +5924,8 @@ void parser_cleanup() ast_value_delete(parser->const_vec[1]); ast_value_delete(parser->const_vec[2]); + util_htdel(parser->aliases); + mem_d(parser); } diff --git a/tests/aliases.qc b/tests/aliases.qc new file mode 100644 index 0000000..e66d525 --- /dev/null +++ b/tests/aliases.qc @@ -0,0 +1,21 @@ +float alias_1 = 3.14; +void alias_2() { + print("alias_2\n"); +} + +[[alias("alias_2")]] void alias_2_aliased(); +[[alias("alias_1")]] float alias_1_aliased; + +// expected output +// alias_2 +// 3.14 +void main() { + alias_2_aliased(); + + print( + ftos( + alias_1_aliased + ), + "\n" + ); +} diff --git a/tests/aliases.tmpl b/tests/aliases.tmpl new file mode 100644 index 0000000..185350f --- /dev/null +++ b/tests/aliases.tmpl @@ -0,0 +1,6 @@ +I: aliases.qc +D: test aliases +T: -execute +C: -std=gmqcc +M: alias_2 +M: 3.14