]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - parser.c
Major cleanup of platform/fs stuff
[xonotic/gmqcc.git] / parser.c
index 06437436ef9c721dc4d8e4bfeafb2c5cd0e3a857..75014cb23607ab581341a36aaf424ed3d9af1b2b 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012, 2013, 2014
+ * Copyright (C) 2012, 2013, 2014, 2015
  *     Wolfgang Bumiller
  *     Dale Weiler
  *
@@ -953,6 +953,9 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
                 }
             }
             (void)check_write_to(ctx, exprs[0]);
+            /* When we're a vector of part of an entity field we use STOREP */
+            if (ast_istype(exprs[0], ast_member) && ast_istype(((ast_member*)exprs[0])->owner, ast_entfield))
+                assignop = INSTR_STOREP_F;
             out = (ast_expression*)ast_store_new(ctx, assignop, exprs[0], exprs[1]);
             break;
         case opid3('+','+','P'):
@@ -1145,6 +1148,22 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
             out = (ast_expression*)asbinstore;
             break;
 
+        case opid3('l', 'e', 'n'):
+            if (exprs[0]->vtype != TYPE_STRING && exprs[0]->vtype != TYPE_ARRAY) {
+                ast_type_to_string(exprs[0], ty1, sizeof(ty1));
+                compile_error(ast_ctx(exprs[0]), "invalid type for length operator: %s", ty1);
+                return false;
+            }
+            /* strings must be const, arrays are statically sized */
+            if (exprs[0]->vtype == TYPE_STRING &&
+                !(((ast_value*)exprs[0])->hasvalue && ((ast_value*)exprs[0])->cvq == CV_CONST))
+            {
+                compile_error(ast_ctx(exprs[0]), "operand of length operator not a valid constant expression");
+                return false;
+            }
+            out = fold_op(parser->fold, op, exprs);
+            break;
+
         case opid2('~', 'P'):
             if (exprs[0]->vtype != TYPE_FLOAT && exprs[0]->vtype != TYPE_VECTOR) {
                 ast_type_to_string(exprs[0], ty1, sizeof(ty1));
@@ -1293,7 +1312,7 @@ static bool parser_close_call(parser_t *parser, shunt *sy)
         if ((fun->flags & AST_FLAG_VARIADIC) &&
             !(/*funval->cvq == CV_CONST && */ funval->hasvalue && funval->constval.vfunc->builtin))
         {
-            call->va_count = (ast_expression*)fold_constgen_float(parser->fold, (qcfloat_t)paramcount);
+            call->va_count = (ast_expression*)fold_constgen_float(parser->fold, (qcfloat_t)paramcount, false);
         }
     }
 
@@ -1548,14 +1567,14 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels)
         return true;
     }
     else if (parser->tok == TOKEN_FLOATCONST) {
-        ast_expression *val = fold_constgen_float(parser->fold, (parser_token(parser)->constval.f));
+        ast_expression *val = fold_constgen_float(parser->fold, (parser_token(parser)->constval.f), false);
         if (!val)
             return false;
         vec_push(sy->out, syexp(parser_ctx(parser), val));
         return true;
     }
     else if (parser->tok == TOKEN_INTCONST || parser->tok == TOKEN_CHARCONST) {
-        ast_expression *val = fold_constgen_float(parser->fold, (qcfloat_t)(parser_token(parser)->constval.i));
+        ast_expression *val = fold_constgen_float(parser->fold, (qcfloat_t)(parser_token(parser)->constval.i), false);
         if (!val)
             return false;
         vec_push(sy->out, syexp(parser_ctx(parser), val));
@@ -1634,9 +1653,6 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels)
 
 
             if (!var) {
-                char *correct = NULL;
-                size_t i;
-
                 /*
                  * sometimes people use preprocessing predefs without enabling them
                  * i've done this thousands of times already myself.  Lets check for
@@ -1647,34 +1663,6 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels)
                     return false;
                 }
 
-                /*
-                 * TODO: determine the best score for the identifier: be it
-                 * a variable, a field.
-                 *
-                 * We should also consider adding correction tables for
-                 * other things as well.
-                 */
-                if (OPTS_OPTION_BOOL(OPTION_CORRECTION) && strlen(parser_tokval(parser)) <= 16) {
-                    correction_t corr;
-                    correct_init(&corr);
-
-                    for (i = 0; i < vec_size(parser->correct_variables); i++) {
-                        correct = correct_str(&corr, parser->correct_variables[i], parser_tokval(parser));
-                        if (strcmp(correct, parser_tokval(parser))) {
-                            break;
-                        } else  {
-                            mem_d(correct);
-                            correct = NULL;
-                        }
-                    }
-                    correct_free(&corr);
-
-                    if (correct) {
-                        parseerror(parser, "unexpected identifier: %s (did you mean %s?)", parser_tokval(parser), correct);
-                        mem_d(correct);
-                        return false;
-                    }
-                }
                 parseerror(parser, "unexpected identifier: %s", parser_tokval(parser));
                 return false;
             }
@@ -2026,10 +2014,6 @@ static void parser_enterblock(parser_t *parser)
     vec_push(parser->typedefs, util_htnew(TYPEDEF_HT_SIZE));
     vec_push(parser->_blocktypedefs, vec_size(parser->_typedefs));
     vec_push(parser->_block_ctx, parser_ctx(parser));
-
-    /* corrector */
-    vec_push(parser->correct_variables, correct_trie_new());
-    vec_push(parser->correct_variables_score, NULL);
 }
 
 static bool parser_leaveblock(parser_t *parser)
@@ -2043,11 +2027,8 @@ static bool parser_leaveblock(parser_t *parser)
     }
 
     util_htdel(vec_last(parser->variables));
-    correct_del(vec_last(parser->correct_variables), vec_last(parser->correct_variables_score));
 
     vec_pop(parser->variables);
-    vec_pop(parser->correct_variables);
-    vec_pop(parser->correct_variables_score);
     if (!vec_size(parser->_blocklocals)) {
         parseerror(parser, "internal error: parser_leaveblock with no block (2)");
         return false;
@@ -2082,26 +2063,12 @@ static void parser_addlocal(parser_t *parser, const char *name, ast_expression *
 {
     vec_push(parser->_locals, e);
     util_htset(vec_last(parser->variables), name, (void*)e);
-
-    /* corrector */
-    correct_add (
-         vec_last(parser->correct_variables),
-        &vec_last(parser->correct_variables_score),
-        name
-    );
 }
 
 static void parser_addglobal(parser_t *parser, const char *name, ast_expression *e)
 {
     vec_push(parser->globals, e);
     util_htset(parser->htglobals, name, e);
-
-    /* corrector */
-    correct_add (
-         parser->correct_variables[0],
-        &parser->correct_variables_score[0],
-        name
-    );
 }
 
 static ast_expression* process_condition(parser_t *parser, ast_expression *cond, bool *_ifnot)
@@ -2569,16 +2536,17 @@ static bool parse_for_go(parser_t *parser, ast_block *block, ast_expression **ou
         initexpr = parse_expression_leave(parser, false, false, false);
         if (!initexpr)
             goto onerr;
-    }
 
-    /* move on to condition */
-    if (parser->tok != ';') {
-        parseerror(parser, "expected semicolon after for-loop initializer");
-        goto onerr;
-    }
-    if (!parser_next(parser)) {
-        parseerror(parser, "expected for-loop condition");
-        goto onerr;
+        /* move on to condition */
+        if (parser->tok != ';') {
+            parseerror(parser, "expected semicolon after for-loop initializer");
+            goto onerr;
+        }
+
+        if (!parser_next(parser)) {
+            parseerror(parser, "expected for-loop condition");
+            goto onerr;
+        }
     }
 
     /* parse the condition */
@@ -3142,7 +3110,7 @@ static bool parse_switch_go(parser_t *parser, ast_block *block, ast_expression *
         if (parser->tok == TOKEN_IDENT)
             typevar = parser_find_typedef(parser, parser_tokval(parser), 0);
         if (typevar || parser->tok == TOKEN_TYPENAME) {
-            if (!parse_variable(parser, block, false, CV_NONE, typevar, false, false, 0, NULL)) {
+            if (!parse_variable(parser, block, true, CV_NONE, typevar, false, false, 0, NULL)) {
                 ast_delete(switchnode);
                 return false;
             }
@@ -3154,7 +3122,7 @@ static bool parse_switch_go(parser_t *parser, ast_block *block, ast_expression *
                 ast_delete(switchnode);
                 return false;
             }
-            if (!parse_variable(parser, block, false, cvq, NULL, noref, is_static, qflags, NULL)) {
+            if (!parse_variable(parser, block, true, cvq, NULL, noref, is_static, qflags, NULL)) {
                 ast_delete(switchnode);
                 return false;
             }
@@ -3462,7 +3430,7 @@ static bool parse_statement(parser_t *parser, ast_block *block, ast_expression *
     {
         if (cvq == CV_WRONG)
             return false;
-        return parse_variable(parser, block, true, cvq, NULL, noref, is_static, qflags, vstring);
+        return parse_variable(parser, block, false, cvq, NULL, noref, is_static, qflags, vstring);
     }
     else if (parser->tok == TOKEN_KEYWORD)
     {
@@ -4043,7 +4011,7 @@ static bool parse_function_body(parser_t *parser, ast_value *var)
             self_think     = (ast_expression*)ast_entfield_new(ctx, gbl_self, fld_think);
 
             time_plus_1    = (ast_expression*)ast_binary_new(ctx, INSTR_ADD_F,
-                             gbl_time, (ast_expression*)fold_constgen_float(parser->fold, frame_delta));
+                             gbl_time, (ast_expression*)fold_constgen_float(parser->fold, frame_delta, false));
 
             if (!self_frame || !self_nextthink || !self_think || !time_plus_1) {
                 if (self_frame)     ast_delete(self_frame);
@@ -4169,7 +4137,7 @@ static bool parse_function_body(parser_t *parser, ast_value *var)
             goto enderrfn;
         }
         func->varargs     = varargs;
-        func->fixedparams = (ast_value*)fold_constgen_float(parser->fold, vec_size(var->expression.params));
+        func->fixedparams = (ast_value*)fold_constgen_float(parser->fold, vec_size(var->expression.params), false);
     }
 
     parser->function = func;
@@ -4227,7 +4195,7 @@ static ast_expression *array_accessor_split(
 
     cmp = ast_binary_new(ctx, INSTR_LT,
                          (ast_expression*)index,
-                         (ast_expression*)fold_constgen_float(parser->fold, middle));
+                         (ast_expression*)fold_constgen_float(parser->fold, middle, false));
     if (!cmp) {
         ast_delete(left);
         ast_delete(right);
@@ -4260,7 +4228,7 @@ static ast_expression *array_setter_node(parser_t *parser, ast_value *array, ast
         if (value->expression.vtype == TYPE_FIELD && value->expression.next->vtype == TYPE_VECTOR)
             assignop = INSTR_STORE_V;
 
-        subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)fold_constgen_float(parser->fold, from));
+        subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)fold_constgen_float(parser->fold, from, false));
         if (!subscript)
             return NULL;
 
@@ -4326,7 +4294,7 @@ static ast_expression *array_field_setter_node(
         if (value->expression.vtype == TYPE_FIELD && value->expression.next->vtype == TYPE_VECTOR)
             assignop = INSTR_STOREP_V;
 
-        subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)fold_constgen_float(parser->fold, from));
+        subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)fold_constgen_float(parser->fold, from, false));
         if (!subscript)
             return NULL;
 
@@ -4389,7 +4357,7 @@ static ast_expression *array_getter_node(parser_t *parser, ast_value *array, ast
         ast_return      *ret;
         ast_array_index *subscript;
 
-        subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)fold_constgen_float(parser->fold, from));
+        subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)fold_constgen_float(parser->fold, from, false));
         if (!subscript)
             return NULL;
 
@@ -4693,12 +4661,17 @@ static ast_value *parse_parameter_list(parser_t *parser, ast_value *var)
                 }
                 if (parser->tok == TOKEN_IDENT) {
                     argcounter = util_strdup(parser_tokval(parser));
+                    ast_value_set_name(param, argcounter);
                     if (!parser_next(parser) || parser->tok != ')') {
                         parseerror(parser, "`...` must be the last parameter of a variadic function declaration");
                         goto on_error;
                     }
                 }
             }
+            if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_FTEQCC && param->name[0] == '<') {
+                parseerror(parser, "parameter name omitted");
+                goto on_error;
+            }
         }
     }
 
@@ -5160,6 +5133,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield
     bool      wasarray  = false;
 
     ast_member *me[3] = { NULL, NULL, NULL };
+    ast_member *last_me[3] = { NULL, NULL, NULL };
 
     if (!localblock && is_static)
         parseerror(parser, "`static` qualifier is not supported in global scope");
@@ -5484,22 +5458,8 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield
                             return false;
                         }
 
-                        /*
-                         * add alias to aliases table and to corrector
-                         * so corrections can apply for aliases as well.
-                         */
                         util_htset(parser->aliases, var->name, find);
 
-                        /*
-                         * add to corrector so corrections can work
-                         * even for aliases too.
-                         */
-                        correct_add (
-                             vec_last(parser->correct_variables),
-                            &vec_last(parser->correct_variables_score),
-                            var->name
-                        );
-
                         /* generate aliases for vector components */
                         if (isvector) {
                             char *buffer[3];
@@ -5515,26 +5475,6 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield
                             mem_d(buffer[0]);
                             mem_d(buffer[1]);
                             mem_d(buffer[2]);
-
-                            /*
-                             * add to corrector so corrections can work
-                             * even for aliases too.
-                             */
-                            correct_add (
-                                 vec_last(parser->correct_variables),
-                                &vec_last(parser->correct_variables_score),
-                                me[0]->name
-                            );
-                            correct_add (
-                                 vec_last(parser->correct_variables),
-                                &vec_last(parser->correct_variables_score),
-                                me[1]->name
-                            );
-                            correct_add (
-                                 vec_last(parser->correct_variables),
-                                &vec_last(parser->correct_variables_score),
-                                me[2]->name
-                            );
                         }
                     }
                 }
@@ -5557,13 +5497,6 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield
                     /* Add it to the local scope */
                     util_htset(vec_last(parser->variables), var->name, (void*)var);
 
-                    /* corrector */
-                    correct_add (
-                         vec_last(parser->correct_variables),
-                        &vec_last(parser->correct_variables_score),
-                        var->name
-                    );
-
                     /* now rename the global */
                     ln = strlen(var->name);
                     vec_append(defname, ln, var->name);
@@ -5595,13 +5528,6 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield
                         for (i = 0; i < 3; ++i) {
                             util_htset(vec_last(parser->variables), me[i]->name, (void*)(me[i]));
 
-                            /* corrector */
-                            correct_add(
-                                 vec_last(parser->correct_variables),
-                                &vec_last(parser->correct_variables_score),
-                                me[i]->name
-                            );
-
                             vec_shrinkto(defname, prefix_len);
                             ln = strlen(me[i]->name);
                             vec_append(defname, ln, me[i]->name);
@@ -5623,6 +5549,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield
                 }
             }
         }
+        memcpy(last_me, me, sizeof(me));
         me[0] = me[1] = me[2] = NULL;
         cleanvar = false;
         /* Part 2.2
@@ -5830,15 +5757,44 @@ skipvar:
         } else {
             ast_expression *cexp;
             ast_value      *cval;
+            bool            folded_const = false;
 
             cexp = parse_expression_leave(parser, true, false, false);
             if (!cexp)
                 break;
+            cval = ast_istype(cexp, ast_value) ? (ast_value*)cexp : NULL;
+
+            /* deal with foldable constants: */
+            if (localblock &&
+                var->cvq == CV_CONST && cval && cval->hasvalue && cval->cvq == CV_CONST && !cval->isfield)
+            {
+                /* remove it from the current locals */
+                if (isvector) {
+                    for (i = 0; i < 3; ++i) {
+                        vec_pop(parser->_locals);
+                        vec_pop(localblock->collect);
+                    }
+                }
+                /* do sanity checking, this function really needs refactoring */
+                if (vec_last(parser->_locals) != (ast_expression*)var)
+                    parseerror(parser, "internal error: unexpected change in local variable handling");
+                else
+                    vec_pop(parser->_locals);
+                if (vec_last(localblock->locals) != var)
+                    parseerror(parser, "internal error: unexpected change in local variable handling (2)");
+                else
+                    vec_pop(localblock->locals);
+                /* push it to the to-be-generated globals */
+                vec_push(parser->globals, (ast_expression*)var);
+                if (isvector)
+                    for (i = 0; i < 3; ++i)
+                        vec_push(parser->globals, (ast_expression*)last_me[i]);
+                folded_const = true;
+            }
 
-            if (!localblock || is_static) {
-                cval = (ast_value*)cexp;
+            if (folded_const || !localblock || is_static) {
                 if (cval != parser->nil &&
-                    (!ast_istype(cval, ast_value) || ((!cval->hasvalue || cval->cvq != CV_CONST) && !cval->isfield))
+                    (!cval || ((!cval->hasvalue || cval->cvq != CV_CONST) && !cval->isfield))
                    )
                 {
                     parseerror(parser, "initializer is non constant");
@@ -5886,6 +5842,13 @@ skipvar:
                 vec_free(sy.argc);
                 var->cvq = cvq;
             }
+            /* a constant initialized to an inexact value should be marked inexact:
+             * const float x = <inexact>; should propagate the inexact flag
+             */
+            if (var->cvq == CV_CONST && var->expression.vtype == TYPE_FLOAT) {
+                if (cval && cval->hasvalue && cval->cvq == CV_CONST)
+                    var->inexact = cval->inexact;
+            }
         }
 
 another:
@@ -5958,7 +5921,7 @@ static bool parser_global_statement(parser_t *parser)
     {
         if (cvq == CV_WRONG)
             return false;
-        return parse_variable(parser, NULL, true, cvq, NULL, noref, is_static, qflags, vstring);
+        return parse_variable(parser, NULL, false, cvq, NULL, noref, is_static, qflags, vstring);
     }
     else if (parser->tok == TOKEN_IDENT && !strcmp(parser_tokval(parser), "enum"))
     {
@@ -6101,10 +6064,6 @@ parser_t *parser_create()
 
     parser->aliases = util_htnew(PARSER_HT_SIZE);
 
-    /* corrector */
-    vec_push(parser->correct_variables, correct_trie_new());
-    vec_push(parser->correct_variables_score, NULL);
-
     empty_ctx.file   = "<internal>";
     empty_ctx.line   = 0;
     empty_ctx.column = 0;
@@ -6217,13 +6176,6 @@ static void parser_remove_ast(parser_t *parser)
     vec_free(parser->_blocklocals);
     vec_free(parser->_locals);
 
-    /* corrector */
-    for (i = 0; i < vec_size(parser->correct_variables); ++i) {
-        correct_del(parser->correct_variables[i], parser->correct_variables_score[i]);
-    }
-    vec_free(parser->correct_variables);
-    vec_free(parser->correct_variables_score);
-
     for (i = 0; i < vec_size(parser->_typedefs); ++i)
         ast_delete(parser->_typedefs[i]);
     vec_free(parser->_typedefs);