Clean up bogus usertypes leftover from parse phase, during semantic analysis.
authorRyan C. Gordon <icculus@icculus.org>
Thu, 13 Jan 2011 02:50:15 -0500
changeset 976 72f121a58548
parent 975 95b03c82cf51
child 977 dc3fb84992b8
Clean up bogus usertypes leftover from parse phase, during semantic analysis.
mojoshader_compiler.c
mojoshader_parser_hlsl.lemon
--- a/mojoshader_compiler.c	Wed Jan 12 03:39:21 2011 -0500
+++ b/mojoshader_compiler.c	Thu Jan 13 02:50:15 2011 -0500
@@ -104,6 +104,7 @@
     int intrinsic_func_index;  // next function index for intrinsic functions.
 
     // Cache intrinsic types for fast lookup and consistent pointer values.
+    MOJOSHADER_astDataType dt_none;
     MOJOSHADER_astDataType dt_bool;
     MOJOSHADER_astDataType dt_int;
     MOJOSHADER_astDataType dt_uint;
@@ -1804,15 +1805,37 @@
 } // calc_ast_const_expr
 
 
-static inline const MOJOSHADER_astDataType *reduce_datatype(const MOJOSHADER_astDataType *dt)
+static const MOJOSHADER_astDataType *reduce_datatype(Context *ctx, const MOJOSHADER_astDataType *dt)
 {
     const MOJOSHADER_astDataType *retval = dt;
     while (retval && retval->type == MOJOSHADER_AST_DATATYPE_USER)
-        retval = retval->user.details;
+    {
+        // !!! FIXME: Ugh, const removal.
+        MOJOSHADER_astDataTypeUser *user = (MOJOSHADER_astDataTypeUser *) &retval->user;
+        if (user->details->type == MOJOSHADER_AST_DATATYPE_NONE)
+        {
+            // Take this opportunity to fix up some usertype stubs that were
+            //  left over from the parse phase. You HAVE to catch these in the
+            //  right scope, so be aggressive about calling reduce_datatype()
+            //  as soon as things come into view!
+            user->details = get_usertype(ctx, user->name);
+            assert(user->details != NULL);
+        } // if
+
+        retval = user->details;
+    } // while
+
     return retval;
 } // reduce_datatype
 
 
+static inline const MOJOSHADER_astDataType *sanitize_datatype(Context *ctx, const MOJOSHADER_astDataType *dt)
+{
+    reduce_datatype(ctx, dt);
+    return dt;
+} // sanitize_datatype
+
+
 static const MOJOSHADER_astDataType *build_function_datatype(Context *ctx,
                                         const MOJOSHADER_astDataType *rettype,
                                         const int paramcount,
@@ -1864,6 +1887,8 @@
     assert( (soa->isarray && soa->dimension) ||
             (!soa->isarray && !soa->dimension) );
 
+    sanitize_datatype(ctx, dt);
+
     // see if we can just reuse the exist datatype.
     if (!soa->isarray)
     {
@@ -1930,7 +1955,7 @@
 static void require_numeric_datatype(Context *ctx,
                                      const MOJOSHADER_astDataType *datatype)
 {
-    datatype = reduce_datatype(datatype);
+    datatype = reduce_datatype(ctx, datatype);
     switch (datatype->type)
     {
         case MOJOSHADER_AST_DATATYPE_BOOL:
@@ -1950,7 +1975,7 @@
 static void require_integer_datatype(Context *ctx,
                                      const MOJOSHADER_astDataType *datatype)
 {
-    datatype = reduce_datatype(datatype);
+    datatype = reduce_datatype(ctx, datatype);
     switch (datatype->type)
     {
         case MOJOSHADER_AST_DATATYPE_INT:
@@ -1966,7 +1991,7 @@
 static void require_boolean_datatype(Context *ctx,
                                      const MOJOSHADER_astDataType *datatype)
 {
-    datatype = reduce_datatype(datatype);
+    datatype = reduce_datatype(ctx, datatype);
     switch (datatype->type)
     {
         case MOJOSHADER_AST_DATATYPE_BOOL:
@@ -1984,7 +2009,7 @@
 static void require_array_datatype(Context *ctx,
                                    const MOJOSHADER_astDataType *datatype)
 {
-    datatype = reduce_datatype(datatype);
+    datatype = reduce_datatype(ctx, datatype);
     if (datatype->type == MOJOSHADER_AST_DATATYPE_ARRAY)
         return;
 
@@ -1996,7 +2021,7 @@
 static void require_struct_datatype(Context *ctx,
                                     const MOJOSHADER_astDataType *datatype)
 {
-    datatype = reduce_datatype(datatype);
+    datatype = reduce_datatype(ctx, datatype);
     if (datatype->type == MOJOSHADER_AST_DATATYPE_STRUCT)
         return;
 
@@ -2008,7 +2033,7 @@
 static int require_function_datatype(Context *ctx,
                                      const MOJOSHADER_astDataType *datatype)
 {
-    datatype = reduce_datatype(datatype);
+    datatype = reduce_datatype(ctx, datatype);
     if ((!datatype) || (datatype->type != MOJOSHADER_AST_DATATYPE_FUNCTION))
     {
         fail(ctx, "expected function");
@@ -2023,7 +2048,7 @@
 static const MOJOSHADER_astDataType *array_element_datatype(Context *ctx,
                                         const MOJOSHADER_astDataType *datatype)
 {
-    datatype = reduce_datatype(datatype);
+    datatype = reduce_datatype(ctx, datatype);
     assert(datatype->type == MOJOSHADER_AST_DATATYPE_ARRAY);
     return datatype->array.base;
 } // array_element_datatype
@@ -2043,8 +2068,8 @@
                                      const MOJOSHADER_astDataType *_rdatatype)
 {
     // !!! FIXME: this whole function is probably naive at best.
-    const MOJOSHADER_astDataType *ldatatype = reduce_datatype(_ldatatype);
-    const MOJOSHADER_astDataType *rdatatype = reduce_datatype(_rdatatype);
+    const MOJOSHADER_astDataType *ldatatype = reduce_datatype(ctx, _ldatatype);
+    const MOJOSHADER_astDataType *rdatatype = reduce_datatype(ctx, _rdatatype);
 
     if (ldatatype == rdatatype)
         return ldatatype;   // they already match, so we're done.
@@ -2173,7 +2198,7 @@
     {
         SymbolScope *item = (SymbolScope *) value;
         const MOJOSHADER_astDataType *dt = item->datatype;
-        dt = reduce_datatype(dt);
+        dt = reduce_datatype(ctx, dt);
         // there's a locally-scoped symbol with this name? It takes precedence.
         if (dt->type != MOJOSHADER_AST_DATATYPE_FUNCTION)
             return dt;
@@ -2219,7 +2244,7 @@
         failf(ctx, "No matching function named '%s'", sym);
     else
     {
-        ident->datatype = reduce_datatype(best->datatype);
+        ident->datatype = reduce_datatype(ctx, best->datatype);
         ident->index = best->index;
     } // else
 
@@ -2280,7 +2305,7 @@
         {
             const char *member = ast->derefstruct.member;
             datatype = type_check_ast(ctx, ast->derefstruct.identifier);
-            const MOJOSHADER_astDataType *reduced = reduce_datatype(datatype);
+            const MOJOSHADER_astDataType *reduced = reduce_datatype(ctx, datatype);
 
             // Is this a swizzle and not a struct deref?
             if (reduced->type == MOJOSHADER_AST_DATATYPE_VECTOR)
@@ -2437,7 +2462,7 @@
         case MOJOSHADER_AST_OP_CALLFUNC:
         {
             datatype = match_func_to_call(ctx, &ast->callfunc);
-            const MOJOSHADER_astDataType *reduced = reduce_datatype(datatype);
+            const MOJOSHADER_astDataType *reduced = reduce_datatype(ctx, datatype);
             // !!! FIXME: replace AST node with an int if this isn't a func.
             if (!require_function_datatype(ctx, reduced))
             {
@@ -2471,7 +2496,7 @@
 
         case MOJOSHADER_AST_OP_CONSTRUCTOR:
         {
-            const MOJOSHADER_astDataType *reduced = reduce_datatype(ast->constructor.datatype);
+            const MOJOSHADER_astDataType *reduced = reduce_datatype(ctx, ast->constructor.datatype);
             const MOJOSHADER_astDataType *base_dt = reduced;
             int num_params = 1;
 
@@ -2546,7 +2571,7 @@
         } // case
 
         case MOJOSHADER_AST_OP_CAST:
-            datatype = ast->cast.datatype;
+            datatype = sanitize_datatype(ctx, ast->cast.datatype);
             datatype2 = type_check_ast(ctx, ast->cast.operand);
             // you still need type coercion, since you could do a wrong cast,
             //  like "int x = (short) mychar;"
@@ -2729,6 +2754,7 @@
             for (param = ast->funcsig.params; param; param = param->next)
             {
                 assert(i <= STATICARRAYLEN(dtparams));  // laziness.
+                sanitize_datatype(ctx, param->datatype);
                 if (param->initializer != NULL)
                 {
                     datatype2 = type_check_ast(ctx, param->initializer);
@@ -3161,6 +3187,7 @@
     // !!! FIXME: this feels hacky.
     ctx->garbage = buffer_create(256*sizeof(void*),MallocBridge,FreeBridge,ctx);  // !!! FIXME: check for failure.
 
+    ctx->dt_none.type = MOJOSHADER_AST_DATATYPE_NONE;
     ctx->dt_bool.type = MOJOSHADER_AST_DATATYPE_BOOL;
     ctx->dt_int.type = MOJOSHADER_AST_DATATYPE_INT;
     ctx->dt_uint.type = MOJOSHADER_AST_DATATYPE_UINT;
--- a/mojoshader_parser_hlsl.lemon	Wed Jan 12 03:39:21 2011 -0500
+++ b/mojoshader_parser_hlsl.lemon	Thu Jan 13 02:50:15 2011 -0500
@@ -226,7 +226,7 @@
 
 // This has to be separate from struct_declaration so that the struct is in the usertypemap when parsing its members.
 %type struct_intro { const char * }
-struct_intro(A) ::= STRUCT IDENTIFIER(B). { A = B.string; push_usertype(ctx, A, &ctx->dt_int); }  // datatype is bogus until semantic analysis.
+struct_intro(A) ::= STRUCT IDENTIFIER(B). { A = B.string; push_usertype(ctx, A, &ctx->dt_none); }  // datatype is bogus until semantic analysis.
 
 %type struct_member_list { MOJOSHADER_astStructMembers * }
 %destructor struct_member_list { delete_struct_member(ctx, $$); }