mesa: added support for GLSL 1.20 array.length() method

This is the only method supported in GLSL 1.20 so we take a few short-cuts.
diff --git a/src/mesa/shader/slang/library/slang_shader.syn b/src/mesa/shader/slang/library/slang_shader.syn
index a02a3ac..760dfbc 100644
--- a/src/mesa/shader/slang/library/slang_shader.syn
+++ b/src/mesa/shader/slang/library/slang_shader.syn
@@ -251,6 +251,7 @@
 .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 @@
  * <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;
 
 /*
diff --git a/src/mesa/shader/slang/library/slang_shader_syn.h b/src/mesa/shader/slang/library/slang_shader_syn.h
index f695717..42ff92b 100644
--- a/src/mesa/shader/slang/library/slang_shader_syn.h
+++ b/src/mesa/shader/slang/library/slang_shader_syn.h
@@ -138,6 +138,7 @@
 ".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"
@@ -175,6 +176,12 @@
 "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"
diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c
index f2cb75f..8d2655e 100644
--- a/src/mesa/shader/slang/slang_codegen.c
+++ b/src/mesa/shader/slang/slang_codegen.c
@@ -2042,6 +2042,46 @@
 }
 
 
+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 @@
    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:
diff --git a/src/mesa/shader/slang/slang_compile.c b/src/mesa/shader/slang/slang_compile.c
index eadc37f..efae4e9 100644
--- a/src/mesa/shader/slang/slang_compile.c
+++ b/src/mesa/shader/slang/slang_compile.c
@@ -944,6 +944,7 @@
 #define OP_POSTINCREMENT 60
 #define OP_POSTDECREMENT 61
 #define OP_PRECISION 62
+#define OP_METHOD 63
 
 
 /**
@@ -1389,6 +1390,35 @@
          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);
diff --git a/src/mesa/shader/slang/slang_compile_operation.h b/src/mesa/shader/slang/slang_compile_operation.h
index 4f92aa9..ec99338 100644
--- a/src/mesa/shader/slang/slang_compile_operation.h
+++ b/src/mesa/shader/slang/slang_compile_operation.h
@@ -94,6 +94,7 @@
    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 @@
    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 */
diff --git a/src/mesa/shader/slang/slang_print.c b/src/mesa/shader/slang/slang_print.c
index b88cefc..1194d0b 100644
--- a/src/mesa/shader/slang/slang_print.c
+++ b/src/mesa/shader/slang/slang_print.c
@@ -653,6 +653,11 @@
       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);
diff --git a/src/mesa/shader/slang/slang_typeinfo.c b/src/mesa/shader/slang/slang_typeinfo.c
index b2f0f14..b1afd96 100644
--- a/src/mesa/shader/slang/slang_typeinfo.c
+++ b/src/mesa/shader/slang/slang_typeinfo.c
@@ -630,6 +630,12 @@
          }
       }
       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;