mesa: added support for GLSL 1.20 array.length() method
authorBrian Paul <brian.paul@tungstengraphics.com>
Tue, 25 Nov 2008 00:18:56 +0000 (17:18 -0700)
committerBrian Paul <brian.paul@tungstengraphics.com>
Tue, 25 Nov 2008 00:18:56 +0000 (17:18 -0700)
This is the only method supported in GLSL 1.20 so we take a few short-cuts.

src/mesa/shader/slang/library/slang_shader.syn
src/mesa/shader/slang/library/slang_shader_syn.h
src/mesa/shader/slang/slang_codegen.c
src/mesa/shader/slang/slang_compile.c
src/mesa/shader/slang/slang_compile_operation.h
src/mesa/shader/slang/slang_print.c
src/mesa/shader/slang/slang_typeinfo.c

index a02a3ac5d92cb86642aa5e7b95c3f4856c6a7216..760dfbcea7e01ef0454e549bcd3313bfa23d6145 100644 (file)
 .emtcode OP_POSTINCREMENT                           60
 .emtcode OP_POSTDECREMENT                           61
 .emtcode OP_PRECISION                               62
+.emtcode OP_METHOD                                  63
 
 /* parameter qualifier */
 .emtcode PARAM_QUALIFIER_IN                         0
@@ -342,6 +343,25 @@ integer_expression
  * <function_call> ::= <function_call_generic>
  */
 function_call
+    function_call_or_method;
+
+/*
+ * <function_call_or_method> ::= <regular_function_call>
+ *                             | <postfix_expression> "." <function_call_generic>
+ */
+function_call_or_method
+    regular_function_call .or method_call;
+
+/*
+ * <method_call> ::= <identifier> "." <function_call_generic>
+ */
+method_call
+    identifier .emit OP_METHOD .and dot .and function_call_generic .and .true .emit OP_END;
+
+/*
+ * <regular_function_call> ::= <function_call_generic>
+ */
+regular_function_call
     function_call_generic .emit OP_CALL .and .true .emit OP_END;
 
 /*
index f69571778233dfc88afd1d83f56e7c7215df47f6..42ff92b65a8c7ecc682261726e46389d13f779c5 100644 (file)
 ".emtcode OP_POSTINCREMENT 60\n"
 ".emtcode OP_POSTDECREMENT 61\n"
 ".emtcode OP_PRECISION 62\n"
+".emtcode OP_METHOD 63\n"
 ".emtcode PARAM_QUALIFIER_IN 0\n"
 ".emtcode PARAM_QUALIFIER_OUT 1\n"
 ".emtcode PARAM_QUALIFIER_INOUT 2\n"
 "integer_expression\n"
 " expression;\n"
 "function_call\n"
+" function_call_or_method;\n"
+"function_call_or_method\n"
+" regular_function_call .or method_call;\n"
+"method_call\n"
+" identifier .emit OP_METHOD .and dot .and function_call_generic .and .true .emit OP_END;\n"
+"regular_function_call\n"
 " function_call_generic .emit OP_CALL .and .true .emit OP_END;\n"
 "function_call_generic\n"
 " function_call_generic_1 .or function_call_generic_2;\n"
index f2cb75f87220352182fc093ad5dda8eb79f092cb..8d2655ec517c52f2f88fff48973a1a4b9ed05fd4 100644 (file)
@@ -2042,6 +2042,46 @@ _slang_gen_function_call_name(slang_assemble_ctx *A, const char *name,
 }
 
 
+static slang_ir_node *
+_slang_gen_method_call(slang_assemble_ctx *A, slang_operation *oper)
+{
+   slang_atom *a_length = slang_atom_pool_atom(A->atoms, "length");
+   slang_ir_node *n;
+   slang_variable *var;
+
+   /* NOTE: In GLSL 1.20, there's only one kind of method
+    * call: array.length().  Anything else is an error.
+    */
+   if (oper->a_id != a_length) {
+      slang_info_log_error(A->log,
+                           "Undefined method call '%s'", (char *) oper->a_id);
+      return NULL;
+   }
+
+   /* length() takes no arguments */
+   if (oper->num_children > 0) {
+      slang_info_log_error(A->log, "Invalid arguments to length() method");
+      return NULL;
+   }
+
+   /* lookup the object/variable */
+   var = _slang_locate_variable(oper->locals, oper->a_obj, GL_TRUE);
+   if (!var || var->type.specifier.type != SLANG_SPEC_ARRAY) {
+      slang_info_log_error(A->log,
+                           "Undefined object '%s'", (char *) oper->a_obj);
+      return NULL;
+   }
+
+   /* Create a float/literal IR node encoding the array length */
+   n = new_node0(IR_FLOAT);
+   if (n) {
+      n->Value[0] = (float) var->array_len;
+      n->Store = _slang_new_ir_storage(PROGRAM_CONSTANT, -1, 1);
+   }
+   return n;
+}
+
+
 static GLboolean
 _slang_is_constant_cond(const slang_operation *oper, GLboolean *value)
 {
@@ -3534,6 +3574,8 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper)
    case SLANG_OPER_CALL:
       return _slang_gen_function_call_name(A, (const char *) oper->a_id,
                                            oper, NULL);
+   case SLANG_OPER_METHOD:
+      return _slang_gen_method_call(A, oper);
    case SLANG_OPER_RETURN:
       return _slang_gen_return(A, oper);
    case SLANG_OPER_LABEL:
index eadc37f5150236faf2ef873ddfea346762fc9f3c..efae4e98fbefb456862dbd75b62f777ced440a4d 100644 (file)
@@ -944,6 +944,7 @@ parse_fully_specified_type(slang_parse_ctx * C, slang_output_ctx * O,
 #define OP_POSTINCREMENT 60
 #define OP_POSTDECREMENT 61
 #define OP_PRECISION 62
+#define OP_METHOD 63
 
 
 /**
@@ -1389,6 +1390,35 @@ parse_expression(slang_parse_ctx * C, slang_output_ctx * O,
          if (!handle_nary_expression(C, op, &ops, &num_ops, 2))
             RETURN0;
          break;
+      case OP_METHOD:
+         printf("******* begin OP_METHOD\n");
+         op->type = SLANG_OPER_METHOD;
+         op->a_obj = parse_identifier(C);
+         if (op->a_obj == SLANG_ATOM_NULL)
+            RETURN0;
+
+         op->a_id = parse_identifier(C);
+         if (op->a_id == SLANG_ATOM_NULL)
+            RETURN0;
+
+         while (*C->I != OP_END)
+            if (!parse_child_operation(C, O, op, 0))
+               RETURN0;
+         C->I++;
+#if 0
+         /* don't lookup the method (not yet anyway) */
+         if (!C->parsing_builtin
+             && !slang_function_scope_find_by_name(O->funs, op->a_id, 1)) {
+            const char *id;
+
+            id = slang_atom_pool_id(C->atoms, op->a_id);
+            if (!is_constructor_name(id, op->a_id, O->structs)) {
+               slang_info_log_error(C->L, "%s: undeclared function name.", id);
+               RETURN0;
+            }
+         }
+#endif
+         break;
       case OP_CALL:
          op->type = SLANG_OPER_CALL;
          op->a_id = parse_identifier(C);
index 4f92aa9a0869286b272ea0f590d82765362f920f..ec99338cb8813d28e8511eeda18a0db648362c5f 100644 (file)
@@ -94,6 +94,7 @@ typedef enum slang_operation_type_
    SLANG_OPER_SUBSCRIPT,        /* [expr] "[" [expr] "]" */
    SLANG_OPER_CALL,             /* [func name] [param] [param] [...] */
    SLANG_OPER_NON_INLINED_CALL, /* a real function call */
+   SLANG_OPER_METHOD,           /* method call, such as  v.length() */
    SLANG_OPER_FIELD,            /* i.e.: ".next" or ".xzy" or ".xxx" etc */
    SLANG_OPER_POSTINCREMENT,    /* [var] "++" */
    SLANG_OPER_POSTDECREMENT     /* [var] "--" */
@@ -115,6 +116,7 @@ typedef struct slang_operation_
    GLfloat literal[4];           /**< Used for float, int and bool values */
    GLuint literal_size;          /**< 1, 2, 3, or 4 */
    slang_atom a_id;              /**< type: asm, identifier, call, field */
+   slang_atom a_obj;             /**< object in a method call */
    slang_variable_scope *locals; /**< local vars for scope */
    struct slang_function_ *fun;  /**< If type == SLANG_OPER_CALL */
    struct slang_variable_ *var;  /**< If type == slang_oper_identier */
index b88cefc283b9e40d6839d1a8ba209f7e06602134..1194d0b4b9980c16674fef537f4c7dc036e2778a 100644 (file)
@@ -653,6 +653,11 @@ slang_print_tree(const slang_operation *op, int indent)
       printf(")\n");
       break;
 
+   case SLANG_OPER_METHOD:
+      spaces(indent);
+      printf("METHOD CALL %s.%s\n", (char *) op->a_obj, (char *) op->a_id);
+      break;
+
    case SLANG_OPER_FIELD:
       spaces(indent);
       printf("FIELD %s of\n", (char*) op->a_id);
index b2f0f149956c7deb1059b447557a9b57da5ceb57..b1afd969d9559e687aa34e5578e46398393eefa4 100644 (file)
@@ -630,6 +630,12 @@ _slang_typeof_operation_(slang_operation * op,
          }
       }
       break;
+   case SLANG_OPER_METHOD:
+      /* at this time, GLSL 1.20 only has one method: array.length()
+       * which returns an integer.
+       */
+      ti->spec.type = SLANG_SPEC_INT;
+      break;
    case SLANG_OPER_FIELD:
       {
          slang_typeinfo _ti;