glsl: pass gl_context to glcpp_parser_create()
[mesa.git] / src / compiler / glsl / glcpp / glcpp-parse.y
index d801cf8a9d74096cf94ff17675e2c4a907b788cc..4ae78fbf8f27bd248632c0fb629034cba1329ec9 100644 (file)
@@ -29,8 +29,7 @@
 #include <inttypes.h>
 
 #include "glcpp.h"
-#include "main/core.h" /* for struct gl_extensions */
-#include "main/mtypes.h" /* for gl_api enum */
+#include "main/mtypes.h"
 
 static void
 yyerror(YYLTYPE *locp, glcpp_parser_t *parser, const char *error);
@@ -175,11 +174,11 @@ add_builtin_define(glcpp_parser_t *parser, const char *name, int value);
         /* We use HASH_TOKEN, DEFINE_TOKEN and VERSION_TOKEN (as opposed to
          * HASH, DEFINE, and VERSION) to avoid conflicts with other symbols,
          * (such as the <HASH> and <DEFINE> start conditions in the lexer). */
-%token DEFINED ELIF_EXPANDED HASH_TOKEN DEFINE_TOKEN FUNC_IDENTIFIER OBJ_IDENTIFIER ELIF ELSE ENDIF ERROR_TOKEN IF IFDEF IFNDEF LINE PRAGMA UNDEF VERSION_TOKEN GARBAGE IDENTIFIER IF_EXPANDED INTEGER INTEGER_STRING LINE_EXPANDED NEWLINE OTHER PLACEHOLDER SPACE PLUS_PLUS MINUS_MINUS
+%token DEFINED ELIF_EXPANDED HASH_TOKEN DEFINE_TOKEN FUNC_IDENTIFIER OBJ_IDENTIFIER ELIF ELSE ENDIF ERROR_TOKEN IF IFDEF IFNDEF LINE PRAGMA UNDEF VERSION_TOKEN GARBAGE IDENTIFIER IF_EXPANDED INTEGER INTEGER_STRING LINE_EXPANDED NEWLINE OTHER PLACEHOLDER SPACE PLUS_PLUS MINUS_MINUS PATH
 %token PASTE
 %type <ival> INTEGER operator SPACE integer_constant version_constant
 %type <expression_value> expression
-%type <str> IDENTIFIER FUNC_IDENTIFIER OBJ_IDENTIFIER INTEGER_STRING OTHER ERROR_TOKEN PRAGMA
+%type <str> IDENTIFIER FUNC_IDENTIFIER OBJ_IDENTIFIER INTEGER_STRING OTHER ERROR_TOKEN PRAGMA PATH
 %type <string_list> identifier_list
 %type <token> preprocessing_token
 %type <token_list> pp_tokens replacement_list text_line
@@ -209,7 +208,7 @@ line:
 |      SPACE control_line
 |      text_line {
                _glcpp_parser_print_expanded_token_list (parser, $1);
-               ralloc_asprintf_rewrite_tail (&parser->output, &parser->output_length, "\n");
+               _mesa_string_buffer_append_char(parser->output, '\n');
        }
 |      expanded_line
 ;
@@ -228,20 +227,23 @@ expanded_line:
 |      LINE_EXPANDED integer_constant NEWLINE {
                parser->has_new_line_number = 1;
                parser->new_line_number = $2;
-               ralloc_asprintf_rewrite_tail (&parser->output,
-                                             &parser->output_length,
-                                             "#line %" PRIiMAX "\n",
-                                             $2);
+               _mesa_string_buffer_printf(parser->output, "#line %" PRIiMAX "\n", $2);
        }
 |      LINE_EXPANDED integer_constant integer_constant NEWLINE {
                parser->has_new_line_number = 1;
                parser->new_line_number = $2;
                parser->has_new_source_number = 1;
                parser->new_source_number = $3;
-               ralloc_asprintf_rewrite_tail (&parser->output,
-                                             &parser->output_length,
-                                             "#line %" PRIiMAX " %" PRIiMAX "\n",
-                                             $2, $3);
+               _mesa_string_buffer_printf(parser->output,
+                                          "#line %" PRIiMAX " %" PRIiMAX "\n",
+                                           $2, $3);
+       }
+|      LINE_EXPANDED integer_constant PATH NEWLINE {
+               parser->has_new_line_number = 1;
+               parser->new_line_number = $2;
+               _mesa_string_buffer_printf(parser->output,
+                                          "#line %" PRIiMAX " %s\n",
+                                           $2, $3);
        }
 ;
 
@@ -259,7 +261,7 @@ define:
 
 control_line:
        control_line_success {
-               ralloc_asprintf_rewrite_tail (&parser->output, &parser->output_length, "\n");
+               _mesa_string_buffer_append_char(parser->output, '\n');
        }
 |      control_line_error
 |      HASH_TOKEN LINE pp_tokens NEWLINE {
@@ -284,30 +286,44 @@ control_line_success:
                  *    It is an error to undefine or to redefine a built-in
                  *    (pre-defined) macro name.
                  *
-                 * The GLSL ES 1.00 spec does not contain this text.
+                 * The GLSL ES 1.00 spec does not contain this text, but
+                 * dEQP's preprocess test in GLES2 checks for it.
                  *
-                 * Section 3.3 (Preprocessor) of the GLSL 1.30 spec says:
+                 * Section 3.3 (Preprocessor) revision 7, of the GLSL 4.50
+                 * spec says:
                  *
-                 *    #define and #undef functionality are defined as is
-                 *    standard for C++ preprocessors for macro definitions
-                 *    both with and without macro parameters.
+                 *    By convention, all macro names containing two consecutive
+                 *    underscores ( __ ) are reserved for use by underlying
+                 *    software layers. Defining or undefining such a name
+                 *    in a shader does not itself result in an error, but may
+                 *    result in unintended behaviors that stem from having
+                 *    multiple definitions of the same name. All macro names
+                 *    prefixed with "GL_" (...) are also reseved, and defining
+                 *    such a name results in a compile-time error.
                  *
-                 * At least as far as I can tell GCC allow '#undef __FILE__'.
-                 * Furthermore, there are desktop OpenGL conformance tests
-                 * that expect '#undef __VERSION__' and '#undef
-                 * GL_core_profile' to work.
-                 *
-                 * Only disallow #undef of pre-defined macros on GLSL ES >=
-                 * 3.00 shaders.
+                 * The code below implements the same checks as GLSLang.
                  */
-               if (parser->is_gles &&
-                    parser->version >= 300 &&
-                    (strcmp("__LINE__", $3) == 0
-                     || strcmp("__FILE__", $3) == 0
-                     || strcmp("__VERSION__", $3) == 0
-                     || strncmp("GL_", $3, 3) == 0))
+               if (strncmp("GL_", $3, 3) == 0)
                        glcpp_error(& @1, parser, "Built-in (pre-defined)"
-                                   " macro names cannot be undefined.");
+                                   " names beginning with GL_ cannot be undefined.");
+               else if (strstr($3, "__") != NULL) {
+                       if (parser->is_gles
+                           && parser->version >= 300
+                           && (strcmp("__LINE__", $3) == 0
+                               || strcmp("__FILE__", $3) == 0
+                               || strcmp("__VERSION__", $3) == 0)) {
+                               glcpp_error(& @1, parser, "Built-in (pre-defined)"
+                                           " names cannot be undefined.");
+                       } else if (parser->is_gles && parser->version <= 300) {
+                               glcpp_error(& @1, parser,
+                                           " names containing consecutive underscores"
+                                           " are reserved.");
+                       } else {
+                               glcpp_warning(& @1, parser,
+                                             " names containing consecutive underscores"
+                                             " are reserved.");
+                       }
+               }
 
                entry = _mesa_hash_table_search (parser->defines, $3);
                if (entry) {
@@ -435,7 +451,7 @@ control_line_success:
                glcpp_parser_resolve_implicit_version(parser);
        }
 |      HASH_TOKEN PRAGMA NEWLINE {
-               ralloc_asprintf_rewrite_tail (&parser->output, &parser->output_length, "#%s", $2);
+               _mesa_string_buffer_printf(parser->output, "#%s", $2);
        }
 ;
 
@@ -453,13 +469,8 @@ control_line_error:
 
 integer_constant:
        INTEGER_STRING {
-               if (strlen ($1) >= 3 && strncmp ($1, "0x", 2) == 0) {
-                       $$ = strtoll ($1 + 2, NULL, 16);
-               } else if ($1[0] == '0') {
-                       $$ = strtoll ($1, NULL, 8);
-               } else {
-                       $$ = strtoll ($1, NULL, 10);
-               }
+               /* let strtoll detect the base */
+               $$ = strtoll ($1, NULL, 0);
        }
 |      INTEGER {
                $$ = $1;
@@ -702,6 +713,10 @@ preprocessing_token:
                $$ = _token_create_str (parser, INTEGER_STRING, $1);
                $$->location = yylloc;
        }
+|      PATH {
+               $$ = _token_create_str (parser, PATH, $1);
+               $$->location = yylloc;
+       }
 |      operator {
                $$ = _token_create_ival (parser, $1, $1);
                $$->location = yylloc;
@@ -1070,6 +1085,20 @@ _token_list_equal_ignoring_space(token_list_t *a, token_list_t *b)
 
    while (1)
    {
+      if (node_a == NULL && node_b == NULL)
+         break;
+
+      /* Ignore trailing whitespace */
+      if (node_a == NULL && node_b->token->type == SPACE) {
+         while (node_b && node_b->token->type == SPACE)
+            node_b = node_b->next;
+      }
+
+      if (node_b == NULL && node_a->token->type == SPACE) {
+         while (node_a && node_a->token->type == SPACE)
+            node_a = node_a->next;
+      }
+
       if (node_a == NULL && node_b == NULL)
          break;
 
@@ -1113,60 +1142,60 @@ _token_list_equal_ignoring_space(token_list_t *a, token_list_t *b)
 }
 
 static void
-_token_print(char **out, size_t *len, token_t *token)
+_token_print(struct _mesa_string_buffer *out, token_t *token)
 {
    if (token->type < 256) {
-      ralloc_asprintf_rewrite_tail (out, len, "%c", token->type);
+      _mesa_string_buffer_append_char(out, token->type);
       return;
    }
 
    switch (token->type) {
    case INTEGER:
-      ralloc_asprintf_rewrite_tail (out, len, "%" PRIiMAX, token->value.ival);
+      _mesa_string_buffer_printf(out, "%" PRIiMAX, token->value.ival);
       break;
    case IDENTIFIER:
    case INTEGER_STRING:
    case OTHER:
-      ralloc_asprintf_rewrite_tail (out, len, "%s", token->value.str);
+      _mesa_string_buffer_append(out, token->value.str);
       break;
    case SPACE:
-      ralloc_asprintf_rewrite_tail (out, len, " ");
+      _mesa_string_buffer_append_char(out, ' ');
       break;
    case LEFT_SHIFT:
-      ralloc_asprintf_rewrite_tail (out, len, "<<");
+      _mesa_string_buffer_append(out, "<<");
       break;
    case RIGHT_SHIFT:
-      ralloc_asprintf_rewrite_tail (out, len, ">>");
+      _mesa_string_buffer_append(out, ">>");
       break;
    case LESS_OR_EQUAL:
-      ralloc_asprintf_rewrite_tail (out, len, "<=");
+      _mesa_string_buffer_append(out, "<=");
       break;
    case GREATER_OR_EQUAL:
-      ralloc_asprintf_rewrite_tail (out, len, ">=");
+      _mesa_string_buffer_append(out, ">=");
       break;
    case EQUAL:
-      ralloc_asprintf_rewrite_tail (out, len, "==");
+      _mesa_string_buffer_append(out, "==");
       break;
    case NOT_EQUAL:
-      ralloc_asprintf_rewrite_tail (out, len, "!=");
+      _mesa_string_buffer_append(out, "!=");
       break;
    case AND:
-      ralloc_asprintf_rewrite_tail (out, len, "&&");
+      _mesa_string_buffer_append(out, "&&");
       break;
    case OR:
-      ralloc_asprintf_rewrite_tail (out, len, "||");
+      _mesa_string_buffer_append(out, "||");
       break;
    case PASTE:
-      ralloc_asprintf_rewrite_tail (out, len, "##");
+      _mesa_string_buffer_append(out, "##");
       break;
    case PLUS_PLUS:
-      ralloc_asprintf_rewrite_tail (out, len, "++");
+      _mesa_string_buffer_append(out, "++");
       break;
    case MINUS_MINUS:
-      ralloc_asprintf_rewrite_tail (out, len, "--");
+      _mesa_string_buffer_append(out, "--");
       break;
    case DEFINED:
-      ralloc_asprintf_rewrite_tail (out, len, "defined");
+      _mesa_string_buffer_append(out, "defined");
       break;
    case PLACEHOLDER:
       /* Nothing to print. */
@@ -1293,11 +1322,11 @@ _token_paste(glcpp_parser_t *parser, token_t *token, token_t *other)
 
     FAIL:
    glcpp_error (&token->location, parser, "");
-   ralloc_asprintf_rewrite_tail (&parser->info_log, &parser->info_log_length, "Pasting \"");
-   _token_print (&parser->info_log, &parser->info_log_length, token);
-   ralloc_asprintf_rewrite_tail (&parser->info_log, &parser->info_log_length, "\" and \"");
-   _token_print (&parser->info_log, &parser->info_log_length, other);
-   ralloc_asprintf_rewrite_tail (&parser->info_log, &parser->info_log_length, "\" does not give a valid preprocessing token.\n");
+   _mesa_string_buffer_append(parser->info_log, "Pasting \"");
+   _token_print(parser->info_log, token);
+   _mesa_string_buffer_append(parser->info_log, "\" and \"");
+   _token_print(parser->info_log, other);
+   _mesa_string_buffer_append(parser->info_log, "\" does not give a valid preprocessing token.\n");
 
    return token;
 }
@@ -1311,7 +1340,7 @@ _token_list_print(glcpp_parser_t *parser, token_list_t *list)
       return;
 
    for (node = list->head; node; node = node->next)
-      _token_print (&parser->output, &parser->output_length, node->token);
+      _token_print(parser->output, node->token);
 }
 
 void
@@ -1333,9 +1362,14 @@ add_builtin_define(glcpp_parser_t *parser, const char *name, int value)
    _define_object_macro(parser, NULL, name, list);
 }
 
+/* Initial output buffer size, 4096 minus ralloc() overhead. It was selected
+ * to minimize total amount of allocated memory during shader-db run.
+ */
+#define INITIAL_PP_OUTPUT_BUF_SIZE 4048
+
 glcpp_parser_t *
-glcpp_parser_create(const struct gl_extensions *extension_list,
-                    glcpp_extension_iterator extensions, void *state, gl_api api)
+glcpp_parser_create(struct gl_context *gl_ctx,
+                    glcpp_extension_iterator extensions, void *state)
 {
    glcpp_parser_t *parser;
 
@@ -1363,16 +1397,16 @@ glcpp_parser_create(const struct gl_extensions *extension_list,
    parser->lex_from_list = NULL;
    parser->lex_from_node = NULL;
 
-   parser->output = ralloc_strdup(parser, "");
-   parser->output_length = 0;
-   parser->info_log = ralloc_strdup(parser, "");
-   parser->info_log_length = 0;
+   parser->output = _mesa_string_buffer_create(parser,
+                                               INITIAL_PP_OUTPUT_BUF_SIZE);
+   parser->info_log = _mesa_string_buffer_create(parser,
+                                                 INITIAL_PP_OUTPUT_BUF_SIZE);
    parser->error = 0;
 
    parser->extensions = extensions;
-   parser->extension_list = extension_list;
+   parser->extension_list = &gl_ctx->Extensions;
    parser->state = state;
-   parser->api = api;
+   parser->api = gl_ctx->API;
    parser->version = 0;
    parser->version_set = false;
 
@@ -1815,7 +1849,8 @@ _glcpp_parser_expand_function(glcpp_parser_t *parser, token_node_t *node,
  */
 static token_list_t *
 _glcpp_parser_expand_node(glcpp_parser_t *parser, token_node_t *node,
-                          token_node_t **last, expansion_mode_t mode)
+                          token_node_t **last, expansion_mode_t mode,
+                          int line)
 {
    token_t *token = node->token;
    const char *identifier;
@@ -1832,11 +1867,14 @@ _glcpp_parser_expand_node(glcpp_parser_t *parser, token_node_t *node,
 
    /* Special handling for __LINE__ and __FILE__, (not through
     * the hash table). */
-   if (strcmp(identifier, "__LINE__") == 0)
-      return _token_list_create_with_one_integer(parser, node->token->location.first_line);
+   if (*identifier == '_') {
+      if (strcmp(identifier, "__LINE__") == 0)
+         return _token_list_create_with_one_integer(parser, line);
 
-   if (strcmp(identifier, "__FILE__") == 0)
-      return _token_list_create_with_one_integer(parser, node->token->location.source);
+      if (strcmp(identifier, "__FILE__") == 0)
+         return _token_list_create_with_one_integer(parser,
+                                                    node->token->location.source);
+   }
 
    /* Look up this identifier in the hash table. */
    entry = _mesa_hash_table_search(parser->defines, identifier);
@@ -1956,12 +1994,15 @@ _glcpp_parser_expand_token_list(glcpp_parser_t *parser, token_list_t *list,
    token_node_t *node, *last = NULL;
    token_list_t *expansion;
    active_list_t *active_initial = parser->active;
+   int line;
 
    if (list == NULL)
       return;
 
    _token_list_trim_trailing_space (list);
 
+   line = list->tail->token->location.last_line;
+
    node_prev = NULL;
    node = list->head;
 
@@ -1973,7 +2014,7 @@ _glcpp_parser_expand_token_list(glcpp_parser_t *parser, token_list_t *list,
       while (parser->active && parser->active->marker == node)
          _parser_active_list_pop (parser);
 
-      expansion = _glcpp_parser_expand_node (parser, node, &last, mode);
+      expansion = _glcpp_parser_expand_node (parser, node, &last, mode, line);
       if (expansion) {
          token_node_t *n;
 
@@ -2304,7 +2345,7 @@ _glcpp_parser_skip_stack_pop(glcpp_parser_t *parser, YYLTYPE *loc)
 
 static void
 _glcpp_parser_handle_version_declaration(glcpp_parser_t *parser, intmax_t version,
-                                         const char *es_identifier,
+                                         const char *identifier,
                                          bool explicitly_set)
 {
    if (parser->version_set)
@@ -2316,11 +2357,15 @@ _glcpp_parser_handle_version_declaration(glcpp_parser_t *parser, intmax_t versio
    add_builtin_define (parser, "__VERSION__", version);
 
    parser->is_gles = (version == 100) ||
-                     (es_identifier && (strcmp(es_identifier, "es") == 0));
+                     (identifier && (strcmp(identifier, "es") == 0));
+   bool is_compat = version >= 150 && identifier &&
+                    strcmp(identifier, "compatibility") == 0;
 
    /* Add pre-defined macros. */
    if (parser->is_gles)
       add_builtin_define(parser, "GL_ES", 1);
+   else if (is_compat)
+      add_builtin_define(parser, "GL_compatibility_profile", 1);
    else if (version >= 150)
       add_builtin_define(parser, "GL_core_profile", 1);
 
@@ -2346,15 +2391,17 @@ _glcpp_parser_handle_version_declaration(glcpp_parser_t *parser, intmax_t versio
          add_builtin_define(parser, "__have_builtin_builtin_sign64", 1);
          add_builtin_define(parser, "__have_builtin_builtin_umul64", 1);
          add_builtin_define(parser, "__have_builtin_builtin_udiv64", 1);
+         add_builtin_define(parser, "__have_builtin_builtin_umod64", 1);
          add_builtin_define(parser, "__have_builtin_builtin_idiv64", 1);
+         add_builtin_define(parser, "__have_builtin_builtin_imod64", 1);
       }
    }
 
    if (explicitly_set) {
-      ralloc_asprintf_rewrite_tail(&parser->output, &parser->output_length,
-                                   "#version %" PRIiMAX "%s%s", version,
-                                   es_identifier ? " " : "",
-                                   es_identifier ? es_identifier : "");
+      _mesa_string_buffer_printf(parser->output,
+                                 "#version %" PRIiMAX "%s%s", version,
+                                 identifier ? " " : "",
+                                 identifier ? identifier : "");
    }
 }