]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - parser.c
prog_leavefunction needs to take the ++st into account - otherwise INSTR_RETURN ends...
[xonotic/gmqcc.git] / parser.c
index 8bde63a2b99e9e7aa0917767f1c47f286e167d51..4105ce75ce47daa91e0abc350bc1fc6a088d6640 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -292,6 +292,8 @@ static ast_value *parser_parse_type(parser_t *parser, int basetype, bool *isfunc
         *isfunc = true;
         while (true) {
             ast_value *param;
+            ast_value *fld;
+            bool isfield = false;
             bool dummy;
 
             if (!parser_next(parser))
@@ -300,6 +302,14 @@ static ast_value *parser_parse_type(parser_t *parser, int basetype, bool *isfunc
             if (parser->tok == ')')
                 break;
 
+            if (parser->tok == '.') {
+                isfield = true;
+                if (!parser_next(parser)) {
+                    parseerror(parser, "expected field parameter type");
+                    goto on_error;
+                }
+            }
+
             temptype = parser_token(parser)->constval.t;
             if (!parser_next(parser))
                 goto on_error;
@@ -318,6 +328,12 @@ static ast_value *parser_parse_type(parser_t *parser, int basetype, bool *isfunc
                     goto on_error;
             }
 
+            if (isfield) {
+                fld = ast_value_new(ctx, param->name, TYPE_FIELD);
+                fld->expression.next = (ast_expression*)param;
+                param = fld;
+            }
+
             if (!paramlist_t_p_add(&params, param)) {
                 parseerror(parser, "Out of memory while parsing typename");
                 goto on_error;
@@ -465,10 +481,11 @@ static bool parser_sy_pop(parser_t *parser, shunt *sy)
              (CanConstFold1(A) && CanConstFold1(B))
 #define ConstV(i) (asvalue[(i)]->constval.vvec)
 #define ConstF(i) (asvalue[(i)]->constval.vfloat)
+#define ConstS(i) (asvalue[(i)]->constval.vstring)
     switch (op->id)
     {
         default:
-            parseerror(parser, "internal error: unhandled operand");
+            parseerror(parser, "internal error: unhandled operator: %s (%i)", op->op, (int)op->id);
             return false;
 
         case opid1('.'):
@@ -533,6 +550,41 @@ static bool parser_sy_pop(parser_t *parser, shunt *sy)
             }
             break;
 
+        case opid2('!','P'):
+            switch (exprs[0]->expression.vtype) {
+                case TYPE_FLOAT:
+                    if (CanConstFold1(exprs[0]))
+                        out = (ast_expression*)parser_const_float(parser, !ConstF(0));
+                    else
+                        out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_F, exprs[0]);
+                    break;
+                case TYPE_VECTOR:
+                    if (CanConstFold1(exprs[0]))
+                        out = (ast_expression*)parser_const_float(parser,
+                            (!ConstV(0).x && !ConstV(0).y && !ConstV(0).z));
+                    else
+                        out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_V, exprs[0]);
+                    break;
+                case TYPE_STRING:
+                    if (CanConstFold1(exprs[0]))
+                        out = (ast_expression*)parser_const_float(parser, !ConstS(0) || !*ConstS(0));
+                    else
+                        out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_S, exprs[0]);
+                    break;
+                /* we don't constant-fold NOT for these types */
+                case TYPE_ENTITY:
+                    out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_ENT, exprs[0]);
+                    break;
+                case TYPE_FUNCTION:
+                    out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_FNC, exprs[0]);
+                    break;
+                default:
+                parseerror(parser, "invalid types used in expression: cannot logically negate type %s",
+                           type_name[exprs[0]->expression.vtype]);
+                return false;
+            }
+            break;
+
         case opid1('+'):
             if (exprs[0]->expression.vtype != exprs[1]->expression.vtype ||
                 (exprs[0]->expression.vtype != TYPE_VECTOR && exprs[0]->expression.vtype != TYPE_FLOAT) )
@@ -949,8 +1001,12 @@ static ast_expression* parser_expression_leave(parser_t *parser, bool stopatcomm
             /* variable */
             if (opts_standard == COMPILER_GMQCC)
             {
-                if (parser->memberof == TYPE_ENTITY)
-                    var = parser_find_field(parser, parser_tokval(parser));
+                if (parser->memberof == TYPE_ENTITY) {
+                    /* still get vars first since there could be a fieldpointer */
+                    var = parser_find_var(parser, parser_tokval(parser));
+                    if (!var)
+                        var = parser_find_field(parser, parser_tokval(parser));
+                }
                 else if (parser->memberof == TYPE_VECTOR)
                 {
                     parseerror(parser, "TODO: implement effective vector member access");
@@ -2007,6 +2063,18 @@ static bool parser_do(parser_t *parser)
                 }
             }
 
+            if (isfunc) {
+                ast_value *fval;
+                fval = ast_value_new(ctx, var->name, TYPE_FUNCTION);
+                if (!fval) {
+                    ast_value_delete(var);
+                    return false;
+                }
+                fval->expression.next = (ast_expression*)var;
+                MEM_VECTOR_MOVE(&var->expression, params, &fval->expression, params);
+                var = fval;
+            }
+
             /* turn it into a field */
             fld = ast_value_new(ctx, parser_tokval(parser), TYPE_FIELD);
             fld->expression.next = (ast_expression*)var;