RAPL

Artifact [8cfc85b796]
Login

Artifact [8cfc85b796]

Artifact 8cfc85b7965f52407cc76fe17f71d87de666c29e:


/*====================================================
 * rapl_namespace.js "A Tcl like language implementation in Javascript named WebRAPL 
 * (Web Rapid Application Programming Language)"
 *
 * handling of namespaces for RAPL
 *
 * Released under the same terms as Tcl itself.
 * (BSD license found at <http://www.tcl.tk/software/tcltk/license.html>)
 *
 * Based on Picol by Salvatore Sanfilippo (<http://antirez.com/page/picol>)
 * (c) Stéphane Arnold 2007
 * Richard Suchenwirth 2007: cleanup, additions
 * Arnulf Wiedemann    2011: a lot of additions for Tcl 8.6 syntax, itcl support
 */

RP.add("rapl-namespace", function(R, name) {

/* =============================== Namespace ================================== */

function Namespace(interp, ns_name, privdata) {
  R.log('constructor called', '2.life', 'namespace', true);
  
  // kweight
  var namesp = this;
  var constructor = namesp.constructor;
  Namespace.superclass.constructor.apply(namesp, arguments);

  R.Base.namespace_oid++
  namesp.oid = R.Base.namespace_oid;

  if (ns_name == null) {
    ns_name = "";
  }

  namesp.variable_debug = 0;
  namesp.interp = interp;
  namesp.name = ns_name;
  namesp.full_name = "";
  namesp.flags = 0;
  namesp.activation_count = 0;
  namesp.ref_count = 0;
  namesp.class_command = null;
  namesp.class_type = namesp.NAMESPACE;
  namesp.parent_namespace = null;  // null means :: global namespace
  namesp.privdata = privdata;
  namesp.children = new Array();
  namesp.class_functions = new Object();
  namesp.class_variables = new Object();
  namesp.resolve_commands = new Object();
  namesp.resolve_variables = new Object();
  namesp.cmd_procs = new Object();
  namesp.variables = new Object();
  namesp.variable_resolver = null;
  namesp.command_resolver = null;
  namesp.var_lookup_msg = null;
  namesp.heritage = new Array();
  namesp.find_var_obj = null;
  namesp.qual_ns = null;
  namesp.qual_ns_alt = null;
  namesp.actual_context_ns = null;
  namesp.simple_name = null;
  namesp.err_msg = null;
  namesp.tail = null;
  namesp.auto_count = -1;
  namesp.unknown_handler = "";
  namesp.msg_bad_namespace = "parent namespace doesn't exist";
  namesp.msg_no_such_var = "no such variable";
  namesp.msg_missing_name = "missing variable name";

  R.log('constructor end', '2.life', 'Namespace', true);

}

R.extend(Namespace, R.Token, {
  my_name: "RaplNamespace",

  /* ==================== init ===================================== */
  init: function (privdata) {
//    if (typeof interp.packages["Namespace"] == "undefined") {
//      interp.Register("Namespace", "0.1");
//    }
  },

  /* ==================== getName ===================================== */
  getName: function () {
    return this.name;
  },

  /* ==================== initAutoCount ===================================== */
  initgetAutoCount: function () {
    this.auto_count = -1;
  },

  /* ==================== getAutoCount ===================================== */
  getAutoCount: function () {
    this.auto_count++;
    return this.auto_count;
  },

  /* ==================== setVariableResolver ===================================== */
  setVariableResolver: function (resolver) {
    this.variable_resolver = resolver;
  },

  /* ==================== setNamespaceType ===================================== */
  setNamespaceType: function (type) {
    this.class_type = type;
  },

  /* ==================== getNamespaceType ===================================== */
  getNamespaceType: function () {
    return this.class_type;
  },

  /* ==================== setNamespaceClassCommand ===================================== */
  setNamespaceClassCommand: function (name) {
    this.class_command = name;
  },

  /* ==================== setFullName ===================================== */
  setFullName: function (full_name) {
      this.full_name = full_name;
  },

  /* ==================== setUnknownHandler ===================================== */
  setUnknownHandler: function (script) {
      this.unknown_handler = script;
  },

  /* ==================== getUnknownHandler ===================================== */
  getUnknownHandler: function () {
      return this.unknown_handler;
  },

  /* ==================== fullName ===================================== */
  fullName: function () {
      return this.full_name;
  },

  /* ==================== ns_tail ===================================== */
  ns_tail: function (path) {
      var pos = -1;
      path = path.toString();
      pos = path.lastIndexOf(':');
      if (pos < 0) {
	return path;
      } else {
	return path.substring(pos+1);
      }
  },

  /* ==================== qualifiers ===================================== */
  qualifiers: function (path) {
      var pos;
      path = path.toString();
      pos = path.lastIndexOf(':');
      if (pos < 0) {
	return "";
      } else {
        if (path == "::") {
          return "";
        }
	return path.substring(0,pos-1);
      }
  },

  /* ==================== getNamespace ===================================== */
  getNamespace: function (name) {
    var found = 0;
    var children;
    var namesp = this;
    if (name == "::") {
      return namesp.interp.global_ns_ptr;
    }
    if (! namesp.hasNamespacePart.test(name)) {
      return namesp.interp.current_namespace;
    }
    var parts = namesp.interp.namespace_obj_type.nsGetParts(name);
    var parent = namesp.interp.global_ns_ptr;
    for (var i = 0; i < parts.length; i++) {
      var part = parts[i];
      children = parent.children;
      found = 0;
      for (var j = 0; j < children.length; j++) {
	var child = children[j];
//print("GETNS!"+child.full_name+"!"+part+"!");
	if (child.name == part) {
          parent = child;
	  found = 1;
	  break;
	}
      }
      if (!found) {
        throw "namespace not found: '"+name+"'";
      }
    }
    return parent;
  },

  /* ==================== addSuperClass ===================================== */
  addSuperClass: function (name) {
    this.heritage.push(name);
  },

  /* ==================== checkCallAllowed ===================================== */
  checkCallAllowed: function (name, cmd_ns) {
    var my_itcl_dict = new TclItclDict(this.interp);
    var my_dict = new TclDict(this.interp);
    var protection = null;
    var method_info = my_itcl_dict.getDictInfo("classFunctions", cmd_ns.full_name, name);
    if (method_info == null) {
      throw "missing method_info for. \""+cmd_ns.full_name+"\" \""+name+"\"";
    }
    protection = my_dict.get(method_info, "protection");
    switch (protection.toString()) {
    case "public":
      protection = this.PROTECTION_PUBLIC;
      break;
    case "protected":
      protection = this.PROTECTION_PROTECTED;
      break;
    case "private":
      protection = this.PROTECTION_PRIVATE;
      break;
    default:
      throw "bad protection: \""+protection+"\"";
    }
    /* check, if we are allowed to call that function from the current namespace */
    if (protection == this.PROTECTION_PROTECTED) {
      if (cmd_ns != this.interp.current_namespace) {
        /* check for cmd_ns in namespace's(classes) heritage */
        var heritage = this.interp.current_namespace.heritage;
	for (var i = 0; i < heritage.length; i++) {
          if (cmd_ns.full_name == heritage[i]) {
            return true;
          }
        }
        return false;
      }
    }
    if (protection == this.PROTECTION_PRIVATE) {
      if (cmd_ns.full_name != this.interp.current_namespace.full_name) {
        return false;
      }
    }
    return true;
  },

  /* ==================== getClassCommand ===================================== */
  getClassCommand: function (ns, name, class_only) {
    var commands = null;
    var cmd_obj;
    if (ns.class_type == this.ITCL_CLASS) {
        commands = ns.resolve_commands;
    } else {
        if (ns.class_type == this.ITCL_EXTENDED_CLASS) {
            commands = ns.resolve_commands;
        } else {
            if (ns.class_type == this.ITCL_TYPE_CLASS) {
                commands = ns.resolve_commands;
            }
        }
    }
    var value_name = this.escape_key(name);
    if (typeof commands[value_name] == "undefined") {
      if (class_only) {
        return null;
      }
      for (var i = 0; i < this.heritage.length; i++) {
        ns = this.getNamespace(this.heritage[i]);
        if (ns == null) {
          throw "heritage namespace: \""+this.heritage[i]+"\" not found";
        }
        commands = ns.resolve_commands;
        if (typeof commands[value_name] != "undefined") {
          break;
        }
      }
    }
    if (typeof commands[value_name] != "undefined") {
      cmd_obj = commands[value_name];
    } else {
      var my_ns = this.getNamespace("::itcl::internal");
      var commands = my_ns.cmd_procs;
      switch (name.toString()) {
      case "info":
      case "cget":
      case "configure":
      case "isa":
        if (commands["class"+name] != "undefined") {
          cmd_obj = commands["class"+name];
	} else {
          cmd_obj = null;
	}
        break;
      default:
        cmd_obj = null;
      }
    }
//print("getClassCommand END!"+name+"!"+ns.full_name+"!");
    return cmd_obj;
  },

  /* ==================== getCommand ===================================== */
  getCommand: function (interp, cmd_name) {
      var namesp = this;
      var ns;
      var my_qualifiers;
      var tail_name;
      var commands = null;
      var is_class = false;

      cmd_name = cmd_name.toString();
      my_qualifiers = namesp.qualifiers(cmd_name);
      ns = namesp.getNamespace(my_qualifiers);
      if (my_qualifiers.length == 0) {
        if (name.match("^::")) {
          ns = interp.global_ns_ptr;
	}
      }
      tail_name = namesp.ns_tail(cmd_name);
      if (ns.class_type == namesp.NAMESPACE) {
          commands = ns.cmd_procs;
      } else {
          is_class = true;
          if (ns.class_type == namesp.ITCL_CLASS) {
              commands = ns.resolve_commands;
          } else {
              if (ns.class_type == namesp.ITCL_EXTENDED_CLASS) {
                  commands = ns.resolve_commands;
              } else {
                  if (ns.class_type == namesp.ITCL_TYPE_CLASS) {
                      commands = ns.resolve_commands;
                  }
              }
          }
      }
   
    var value_name = namesp.escape_key(tail_name);
    if ((typeof commands[value_name] == "undefined") && (is_class == 1)) {
      var orig_namespace = ns;
      for (var i = 0; i < namesp.heritage.length; i++) {
        ns = namesp.getNamespace(namesp.heritage[i]);
        if (ns == null) {
          throw "heritage namespace: \""+namesp.heritage[i]+"\" not found";
        }
        commands = ns.resolve_commands;
        if (typeof commands[value_name] != "undefined") {
          if (!namesp.checkCallAllowed(tail_name, ns)) {
print("cannot call method:\""+tail_name.toString()+"\"");
            throw "cannot call method:\""+tail_name.toString()+"\"";
          }
          break;
        }
      }
      ns = orig_namespace;
    }
    if (typeof commands[value_name] == "undefined") {
      /* try global namespace if not there already */
      if (ns.name != "::") {
        if (is_class) {
          var my_ns = namesp.getNamespace("::");
          var commands = my_ns.cmd_procs;
          switch (tail_name) {
          case "info":
          case "cget":
          case "configure":
          case "isa":
            if (commands["__class"+tail_name] != "undefined") {
              interp.setCommandNamespace(ns);
print("setCommandNamespace!"+ns.full_name+"!");
              var cmd_obj = commands["__class"+tail_name];
              return cmd_obj;
            }
          }
        }
        ns = namesp.getNamespace("::");
        commands = ns.cmd_procs;
      }
      if (typeof commands[value_name] == "undefined") {
        return null;
      }
    }
    interp.setCommandNamespace(ns);
    var cmd_obj = commands[value_name];
    return cmd_obj;
  },


  /* ==================== registerCommand ===================================== */
  registerCommand: function (name, cmd_obj, class_type, func_type) {
    var namesp = this;
    var my_class_type = this.getItclClassTypeFromString(class_type);
//print("NSRC!"+func_type+"!");
    var my_func_type = namesp.getItclFunctionTypeFromString(func_type);
    var my_namespace;
    if (name.toString().substring(0,2) == "::") {
      var qualifiers = namesp.qualifiers(name);
      if (qualifiers == "") {
        if (name.toString().substring(0,2) == "::") {
          qualifiers = namesp.interp.global_ns_ptr.name;
        } else {
          qualifiers = namesp.interp.current_namespace_name;
        }
      }
      var parts = namesp.namespaceName2Parts(qualifiers);
      var create_it = 1;
// FIXME!! need to use createNamespace here !!!
      namesp.mkNamespace(namesp.interp.global_ns_ptr, parts, create_it);
      my_namespace = namesp.getNamespace(qualifiers);
    } else {
      my_namespace = namesp.interp.getCurrentNamespace();
    }
    if (my_namespace.full_name.indexOf("::") < 0) {
      if (my_namespace.full_name.length == 0) {
        my_namespace = namesp.interp.global_ns_ptr;
      }
    }
    name = namesp.ns_tail(name);
    cmd_obj.type = my_class_type;
    cmd_obj.func_type = my_func_type;
    var value_name = namesp.escape_key(name);
    if (my_class_type == namesp.NAMESPACE) {
      my_namespace.cmd_procs[value_name] = cmd_obj;
    } else {
      if (my_class_type == namesp.ITCL_CLASS) {
        my_namespace.resolve_commands[value_name] = cmd_obj;
      } else {
        if (my_class_type == namesp.ITCL_EXTENDED_CLASS) {
          my_namespace.resolve_commands[value_name] = cmd_obj;
        } else {
          if (my_class_type == namesp.ITCL_TYPE_CLASS) {
            my_namespace.resolve_commands[value_name] = cmd_obj;
          }
        }
      }
    }
    return cmd_obj;
  },

  /* ==================== registerSubCommand ===================================== */
  registerSubCommand: function (name, cmd_obj, class_type, func_type) {
//print("NSRSU!"+func_type+"!");
    var my_class_type = this.getItclClassTypeFromString(class_type);
    var my_func_type = this.getItclFunctionTypeFromString(func_type);
    var qualifiers = this.qualifiers(name);
    if (qualifiers == "") {
      qualifiers = interp.current_namespace_name;
    }
    var parts = this.namespaceName2Parts(qualifiers);
    var create_it = 1;
// FIXME!! need to use createNamespace here !!!
    this.mkNamespace(interp.global_ns_ptr, parts, create_it);
    var my_namespace = this.getNamespace(qualifiers);
    name = this.ns_tail(name);
    cmd_obj.type = my_class_type;
    cmd_obj.func_type = my_func_type;
    var value_name = this.escape_key(name);
    if (my_class_type == this.NAMESPACE) {
      my_namespace.cmd_procs[value_name] = cmd_obj;
    } else {
      if (my_class_type == this.ITCL_CLASS) {
        my_namespace.class_functions[value_name] = cmd_obj;
      } else {
        if (my_class_type == this.ITCL_EXTENDED_CLASS) {
          my_namespace.class_functions[value_name] = cmd_obj;
        } else {
          if (my_class_type == this.ITCL_TYPE_CLASS) {
            my_namespace.class_functions[value_name] = cmd_obj;
          }
        }
      }
    }
  },

  /* ==================== namespaceName2Parts ===================================== */
  namespaceName2Parts: function (name) {
    var ns_parts = new Array();
    var idx = 0;
    var start_idx;
    if (name == "::") {
      return ns_parts;
    }
    if (name.length > 1) {
      if ((name.charAt(0) == ":") && (name.charAt(1) == ":")) {
        idx = 2;
      }
    }
    start_idx = idx;
    while (idx < name.length) {
      while ((name.charAt(idx) != ":") && (idx < name.length)) {
        idx++;
      }
      ns_parts.push(name.substring(start_idx, idx));
      if (idx < name.length) {
        if ((name.charAt(idx) == ":") && (name.charAt(idx + 1) == ":")) {
	}
	idx += 2;
      }
    }
    return ns_parts;
  },

  /* ==================== mkNamespace ===================================== */
  mkNamespace: function (parent_ns, parts, create_it) {
    var namesp = this;
    var children;
    var child;
    var par = parent_ns;
    for(var i = 0; i < parts.length; i++) {
        var part_name = parts[i];
        var children = par.children;
        var found = 0;
	for (var j = 0; j < children.length; j++) {
	    child = children[j];
	    if (child.name == part_name) {
		found = 1;
		break;
	    }
	}
	if (!found) {
	    if (!create_it) {
              throw "no such namespace: '"+namesp.getNamespaceName(child)+"::"+part_name+"'";
	    }
	    var my_name = namesp.getNamespaceName(child)+"::"+part_name;
            child = namesp.interp.namespace_obj_type.createNamespace(my_name);
//print("CNS!"+my_name+"!"+child.full_name+"!"+child.name+"!");
//            child = new R.Namespace(namesp.interp, part_name);
//	    child.parent_namespace = par;
	    par.children.push(child);
	    var full_name = namesp.getNamespaceName(child);
	    child.setFullName(full_name);
	}
	par = child;
    }
    return par;
  },

  /* ==================== getHeritage ===================================== */
  getHeritage: function () {
    if ((this.class_type == this.ITCL_CLASS) || (this.class_type == this.ITCL_EXTENDED_CLASS)) {
      return this.heritage;
    } else {
      return null;
    }
  },

  /* ==================== getConstructor ===================================== */
  getConstructor: function (class_name) {
    var ns = this.getNamespace(class_name);
    if ((ns.class_type == this.ITCL_CLASS) || (ns.class_type == this.ITCL_EXTENDED_CLASS)) {
      return this.getClassCommand(ns, "constructor");
    } else {
      return null;
    }
  },

  /* ==================== getNamespaceName ===================================== */
  getNamespaceName: function (ns) {
    var result = new Array();
    while (1) {
        if (ns.name != "::") {
          result.push(ns.name);
	}
        ns = ns.parent_namespace;
	if (ns == null) {
          break;
	}
    }
    result = result.reverse();
    result = "::"+result.join("::");
    return result;
  },

  /* ==================== getChildNamespace ===================================== */
	  getChildNamespace: function (ns, ns_name) {
    var child;
    for (var i = 0; i < ns.children.length; i++) {
      child = ns.children[i];
    }
    for (var i = 0; i < ns.children.length; i++) {
      child = ns.children[i];
      if (child.name == ns_name) {
        return child;
      }
    }
    return null;
  },

  /* ==================== FindNamespaceVar ===================================== */
  FindNamespaceVar: function(name, context_ns, flags) {
    var namesp = this;
    /*
     * If this namespace has a variable resolver, then give it first crack at
     * the variable resolution. It may return a RaplVariable value, it may signal
     * to continue onward, or it may signal an error.
     */
  
if (namesp.variable_debug > 1) {
print("FindNamespaceVar!"+name+"!"+context_ns.full_name+"!"+flags+"!");
}
    var context_ns_ptr = new Array();
    var ns_ptr1 = new Array();
    var ns_ptr2 = new Array();
    var simple_name = new Array();
    var variable_resolver = null;
    var res_ptr;
    var result;
    var var_ptr = new Array();

    if ((flags & namesp.NAMESPACE_LOOKUP_GLOBAL_ONLY) != 0) {
      context_ns_ptr = namesp.getGlobalNamespace();
    } else {
      if (context_ns != null) {
        context_ns_ptr = context_ns;
      } else {
        context_ns_ptr = namesp.getGlobalNamespace();
      }
    }
    if (!(flags & namesp.VAR_LOOKUP_AVOID_RESOLVERS) &&
        (context_ns_ptr.variable_resolver != null || namesp.interp.variable_resolver != null)) {
      res_ptr = namesp.interp.variable_resolver;

      if (context_ns_ptr.variable_resolver != null) {
        result = context_ns_ptr.variable_resolver.resolve(namesp.interp, name, context_ns_ptr, flags);
      } else {
        result = namesp.CONTINUE;
      }
      while (result == namesp.CONTINUE && res_ptr != null) {
        if (res_ptr.variable_resolver != null) {
          result = variable_resolver.resolve(namesp.interp, name, context_ns_ptr, flags, var_ptr);
	  var_ptr = var_ptr[0];
          res_ptr = res_ptr.getNextResolver();
        }
      }
      if (result == namesp.OK) {
        return var_ptr;
      } else {
        if (result != namesp.CONTINUE) {
          return null;
        }
      }
    }
    /*
     * Find the namespace(s) that contain the variable.
     */
    namesp.getNamespaceForQualName(name, context_ns, flags, ns_ptr1, ns_ptr2, context_ns_ptr, simple_name); 
    ns_ptr1 = ns_ptr1[0];
    ns_ptr2 = ns_ptr2[0];
    context_ns_ptr = context_ns_ptr[0];
    simple_name = simple_name[0];
if (namesp.variable_debug > 1) {
print("GNFQN!"+ns_ptr1.f_name+"!"+ns_ptr2.full_name+"!");
}
    /*
     * Look for the variable in the variable table of its namespace. Be sure
     * to check both possible search paths: from the specified namespace
     * context and from the global namespace.
     */
    var_ptr = null;
    if (simple_name != name) {
if (namesp.variable_debug > 1) {
print("QUALNS!"+ns_ptr1.full_name+"!");
for (var z in ns_ptr1.variables) {
print("z!"+z+"!");
}
print("qual_ns!"+simple_name+"!"+typeof ns_ptr1.variables[simple_name]+"!");
}
    }
    
    if ((var_ptr == null) && (ns_ptr1 != null) && (simple_name != null)) {
      if (typeof ns_ptr1.variables[simple_name] != "undefined") {
        var_ptr = ns_ptr1.variables[simple_name];
      }
    }
    if ((var_ptr == null) && (ns_ptr2 != null) && (simple_name != null)) {
      if (typeof ns_ptr2.variables[simple_name] != "undefined") {
        var_ptr = ns_ptr2.variables[simple_name];
      }
    }
    if ((var_ptr == null) && (flags & namesp.VAR_LOOKUP_LEAVE_ERR_MSG)) {
      namesp.interp.setResult("unknown variable \""+name+"\"");
      namesp.interp.setErrorCode(["RAPL", "LOOKUP", "VARIABLE", name]);
    }
    return var_ptr;
  },

  /* ==================== getNamespaceForQualName ================================== */
  /*  Given a qualified name specifying a command, variable, or namespace,
   *  and a namespace in which to resolve the name, this function returns
   *  the namespace object that contains the item. A qualified name
   *  consists of the "simple" name of an item qualified by the names of an
   *  arbitrary number of containing namespace separated by "::"s. If the
   *  qualified name starts with "::", it is interpreted absolutely from the
   *  global namespace. Otherwise, it is interpreted relative to the
   *  namespace specified by context_ns if it is non-null. If context_ns is
   *  null, the name is interpreted relative to the current namespace.
   *
   *  A relative name like "foo::bar::x" can be found starting in either the
   *  current namespace or in the global namespace. So each search usually
   *  follows two tracks, and two possible namespaces are returned. If the
   *  function sets either this.qual_ns or this.qual_ns_alt to null, then that path
   *  failed.
   *
   *  If "flags" contains NAMESPACE_LOOKUP_GLOBAL_ONLY, the relative qualified name is
   *  sought only in the global :: namespace. The alternate search (also)
   *  starting from the global namespace is ignored and this.qual_ns_alt is set
   *  null.
   *
   *  If "flags" contains NAMESPACE_LOOKUP_NAMESPACE_ONLY, the relative qualified name is
   *  sought only in the namespace specified by context_ns_ptr. The alternate
   *  search starting from the global namespace is ignored and alt_ns_ptr_ptr
   *  is set null. If both NAMESPACE_LOOKUP_GLOBAL_ONLY and NAMESPACE_LOOKUP_NAMESPACE_ONLY are
   *  specified, NAMEPSACE_GLOBAL_ONLY is ignored and the search starts from the
   *  namespace specified by context_ns_ptr.
   *
   *  If "flags" contains NAMESPACE_CREATE_IF_UNKNOWN, all namespace components
   *  of the qualified name that cannot be found are automatically created
   *  within their specified parent. This makes sure that functions like
   *  createCommand always succeed. There is no alternate search path,
   *  so alt_ns_ptr_ptr is set null.
   *
   *  If "flags" contains NAMESPACE_FIND_ONLY, the qualified name is treated as
   *  a reference to a namespace, and the entire qualified name is followed.
   *  If the name is relative, the namespace is looked up only in the
   *  current namespace. The namespace is stored in ns_ptr_ptr
   *  and null is stored in simple_name. Otherwise, if NAMESPACE_FIND_ONLY
   *  is not specified, only the leading components are treated as namespace
   *  names, the simple name of the final component is
   *  stored in simple_name.
   *
   * Results:
   *  It sets ns_ptr_ptr and alt_ns_ptr_ptr to point to the two possible
   *  namespaces which represent the last (containing) namespace in the
   *  qualified name. If the function sets either ns_ptr_ptr or alt_ns_ptr_ptr
   *  to null, then the search along that path failed. The function also
   *  stores the simple name of the final component in
   *  simple_name. If the qualified name is "::" or was treated as a
   *  namespace reference (NAMESPACE_FIND_ONLY), the function stores a pointer
   *  to the namespace in ns_ptr_ptr, null in alt_ns_ptr_ptr, and sets
   *  simple_name to point to an empty string.
   *
   *  If there is an error, this function returns ERROR. If "flags"
   *  contains VAR_LOOKUP_LEAVE_ERR_MSG, an error message is returned in the
   *  interpreter's result object. Otherwise, the interpreter's result
   *  object is left unchanged.
   *  actual_context_ns_ptr is set to the actual context namespace. It is set to
   *  the input context namespace in context_ns_ptr. If context_ns_ptr is null,
   *  it is set to the current namespace context.
   */
  getNamespaceForQualName: function(qual_name, context_ns_ptr, flags, ns_ptr_ptr, alt_ns_ptr_ptr, actual_context_ptr_ptr, simple_name_ptr) {
    var namesp = this;
if (namesp.variable_debug > 1) {
print("getNamespaceForQualName!"+qual_name+"!"+(context_ns_ptr == null ? "<null>" : context_ns_ptr.full_name)+"!"+flags+"!");
}
    var ns_ptr = context_ns_ptr;
    var alt_ns_ptr = null;
    var global_ns_ptr = namesp.interp.global_ns_ptr;
    var start_idx;
    var end_idx;
    var ns_name;
    var i;
    var len;
    /*
     * Determine the context namespace ns_ptr in which to start the primary
     * search. If the qualName name starts with a "::" or NAMESPACE_LOOKUP_GLOBAL_ONLY was
     * specified, search from the global namespace. Otherwise, use the
     * namespace given in context_ns_ptr, or if that is null, use the current
     * namespace context. Note that we always treat two or more adjacent ":"s
     * as a namespace separator.
     */

    if (flags & namesp.NAMESPACE_LOOKUP_GLOBAL_ONLY) {
      ns_ptr = global_ns_ptr;
    } else {
      if (ns_ptr == null) {
        ns_ptr = namesp.interp.var_frame_ptr.ns_ptr;
      }
    }
    start_idx = 0;
    i = 0;
    if ((qual_name.charAt(0) == ":") && (qual_name.charAt(1) == ":")) {
      start_idx = 2;
      for (i = 2; i < qual_name.length; i++) {
        if (qual_name.charAt(i) != ":") {
          break;
        }
        start_idx++;
        ns_ptr = global_ns_ptr;
        if (i + 1 == qual_name.length) {  /* qualName is just two or more ":"s. */
          ns_ptr_ptr[0] = global_ns_ptr;
          alt_ns_ptr_ptr[0] = null;
          actual_context_ptr_ptr = global_ns_ptr;
          simple_name_ptr[0] = "";
          return namesp.OK;
        }
      }
    }
if (namesp.variable_debug > 1) {
print("GNFQN2!"+start_idx+"!"+ns_ptr.full_name+"!");
}
    actual_context_ptr_ptr = ns_ptr;
    /*
     * Start an alternate search path starting with the global namespace.
     * However, if the starting context is the global namespace, or if the
     * flag is set to search only the namespace context_ns_ptr, ignore the
     * alternate search path.
     */

    alt_ns_ptr = global_ns_ptr;
    if ((ns_ptr == global_ns_ptr)
       || (flags & (namesp.NAMESPACE_LOOKUP_NAMESPACE_ONLY | namesp.NAMESPACE_FIND_ONLY))) {
      alt_ns_ptr = null;
    }
    /*
     * Loop to resolve each namespace qualifier in qualName.
     */
    end_idx = start_idx;
    while (start_idx  < qual_name.length) {
      /*
       * Find the next namespace qualifier (i.e., a name ending in "::") or
       * the end of the qualified name (i.e., a name ending). Set
       * len to the number of characters, starting from start, in the name;
       * set end to point after the "::"s or at the end.
       */
      len = 0;
      for (end_idx = start_idx; end_idx < qual_name.length; end_idx++) {
        if ((qual_name.charAt(end_idx) == ':') && (qual_name.charAt(end_idx+1) == ':')) {
          end_idx += 2;         /* Skip over the initial :: */
          while (qual_name.charAt(end_idx) == ':') {
            end_idx++;          /* Skip over the subsequent : */
          }
          break;                  /* Exit for loop; end is after ::'s */
        }
        len++;
      }
      if (end_idx == qual_name.length && !(end_idx - start_idx >= 2 && qual_name.charAt(end_idx - 1) == ':' && qual_name.charAt(end_idx - 2) == ':')) {
        /*
         * qual_name ended with a simple name at start. If NAMESPACE_FIND_ONLY
         * was specified, look this up as a namespace. Otherwise, start is
         * the name of a cmd or var and we are done.
         */
  
        if (flags & namesp.NAMESPACE_FIND_ONLY) {
          ns_name = qual_name.substring(start_idx);
        } else {
          ns_ptr_ptr[0] = ns_ptr;
	  alt_ns_ptr_ptr[0] = alt_ns_ptr;
	  simple_name_ptr[0] = qual_name.substring(start_idx);
	  return namesp.OK;
        }
      } else {
        /*
         * start points to the beginning of a namespace qualifier ending
         * in "::". end points to the start of a name in that namespace
         * that might be empty. Copy the namespace qualifier to a buffer
         * so it can be null terminated. We can't modify the incoming
         * qual_name since it may be a string constant.
         */
  
         ns_name = qual_name.substring(start_idx, start_idx + len);
      }
      /*
       * Look up the namespace qualifier ns_name in the current namespace
       * context. If it isn't found but NAMESPACE_CREATE_IF_UNKNOWN is set,
       * create that qualifying namespace. This is needed for functions like
       * createCommand that cannot fail.
       */
      var entry = null;
      if (ns_ptr != null) {
        entry = namesp.getChildNamespace(ns_ptr, ns_name);
      }
      if (entry != null) {
        ns_ptr = entry;
      } else {
        if (flags & namesp.NAMESPACE_CREATE_IF_UNKNOWN) {
          var frame_ptr = new R.Callframe(namesp.interp, /* is_proc_call_frame */0);
	  namesp.interp.namespace_obj_type.pushStackFrame(frame_ptr, ns_ptr, /* is_proc_call_frame */0);
          ns_ptr = namesp.interp.namespace_obj_type.createNamespace(ns_name);
	  namesp.interp.namespace_obj_type.popStackFrame();
	  if (ns_ptr == null) {
            namesp.interp.panic("could not create namespace '"+nsname+"'");
	  }
        } else {  /* namespace not found and was not created */
          ns_ptr = null;
        }
      }
      /*
       * Look up the namespace qualifier in the alternate search path too.
       */
      if (alt_ns_ptr != null) {
        entry = namesp.getChildNamespace(alt_ns_ptr, ns_name);
      }
      if (entry != null) {
        alt_ns_ptr = entry;
      } else {
        alt_ns_ptr = null;
      }
      /*
       * If both search paths have failed, return null results
       */
      if ((ns_ptr == null) && (alt_ns_ptr == null)) {
        ns_ptr_ptr[0] = null;
        alt_ns_ptr_ptr[0] = null;
        simple_name_ptr[0] = null;
        return namesp.OK;
      }
      start_idx = end_idx;
    }
    /*
     * We ignore trailing "::"s in a namespace name, but in a command or
     * variable name, trailing "::"s refer to the cmd or var named {}.
     */
  
    if ((flags & namesp.NAMESPACE_FIND_ONLY) || (end_idx > start_idx && qual_name.charAt(end_idx - 1) != ':')) {
      simple_name_ptr[0] = null;       /* Found namespace name. */
    } else {
      simple_name_ptr[0] = qual_name.substring(end_idx); /* Found cmd/var: points to empty
                                                         * string. */
    }
    /*
     * As a special case, if we are looking for a namespace and qualName is ""
     * and the current active namespace (ns) is not the global namespace,
     * return null (no namespace was found). This is because namespaces can
     * not have empty names except for the global namespace.
     */
    if ((flags & namesp.NAMESPACE_FIND_ONLY) && (qualName.length == 0)
        && (ns_ptr != global_ns_ptr)) {
      ns_ptr = null;
    }
  
    ns_ptr_ptr[0] = ns_ptr;
    alt_ns_ptr_ptr[0] = alt_ns_ptr;
if (namesp.variable_debug > 1) {
print("QUALNS!"+ns_ptr.full_name+"!"+alt_ns_ptr_ptr[0]+"!");
}
    return namesp.OK;
  },

  /* ==================== lookupVariableEx ===================================== */
  lookupVariableEx: function (interp, name, flags, msg, create_part1, create_part2) {
    var namesp = this;
if (namesp.variable_debug) {
print("lookupVariableEx!"+name+"!lv!"+interp.eval_statement.level+"!flags!"+flags+"!msg!"+msg+"!crp1!"+create_part1+"!crp2!"+create_part2+"!");
}
    var my_name = null;
    var part1 = null;
    var part2 = null;
    var parts = null;
    var my_var_obj;
    var index_ptr = new Array();
    var err_msg_ptr = new Array();

    my_name = name.toString();
    if (namesp.matchArrayName.test(my_name)) {
      parts = namesp.getArrayNameParts(my_namemy_name.length);
      part1 = parts[0];
      part2 = parts[1];
    } else {
      part1 = my_name;
    }
    if (part1 == "this") {
      if ((namesp.class_type == namesp.ITCL_CLASS) || (namesp.class_type == namesp.ITCL_EXTENDED_CLASS)) {
        var class_obj_name = interp.eval_statement.getCallframeClassObject();
	var class_obj = interp.getClassObject(class_obj_name);
        var var_obj = class_obj.getThisVariable();
	return var_obj;
      }
    }
    my_var_obj = namesp.lookupSimpleVariable(interp, part1, flags, create_part1, err_msg_ptr, index_ptr);
if (namesp.variable_debug) {
print("lookupVariableEx2!"+name+"!"+my_var_obj+"!");
}
    if (my_var_obj == null) {
      if ((msg != null) && (flags & namesp.VAR_LOOKUP_LEAVE_ERR_MSG)) {
        namesp.VarErrMsg(interp, part1, part2, msg, namesp.var_lookup_msg, -1); 
	namesp.SetErrorCode(interp, "RAPL", "LOOKUP", "VARNAME", part1, null);
      }
      return null;
    }
    /*
     * Cache the newly found variable if possible.
     */
    if (namesp.index > 0) {
      /* An indexed local variable. */
    } else {
      if (namesp.index > -3) {
        /* A cacheable namespace or global variable. */
      } else {
      }
    }
    while (my_var_obj.link != null) {
      my_var_obj = var_obj.link;
    }
    if (part2 != null) {
      /* Array element sought: look it up. */
      /* not necessary getValue does the job */
    }
if (namesp.variable_debug) {
print("lookupVariableEx END!"+name+"!flags!"+flags+"!msg!"+msg+"!crp1!"+create_part1+"!crp2!"+create_part2+"!var_obj!"+my_var_obj+"!");
}
    return my_var_obj;
  },

  /* ==================== lookupSimpleVariable ===================================== */
  /*  This function is used by to locate a simple variable (i.e., not an
   *  array element) given its name.
    *  The return value is the variable RaplObject or if the variable could not be found
    *  and create is 1, a new as-yet-undefined (VAR_UNDEFINED) variable
    *  is created and returned
    *  If the variable isn't found and creation wasn't specified, or some
    *  other error occurs, null is returned and the corresponding error
    *  message is left in this.var_lookup_msg
    *
    *  Note: it's possible for the variable returned to be VAR_UNDEFINED even
    *  if create_part1 is 1 (this only causes the RaplVariable object to be created).
    *  For example, the variable might be a global that has been unset but is
    *  still referenced by a procedure, or a variable that has been unset but
    *  it only being kept in existence (if VAR_UNDEFINED) by a trace.
    */
  lookupSimpleVariable: function (interp, var_name, flags, create, err_msg_ptr, index_ptr) {
    var namesp = this;
if (namesp.variable_debug) {
print("lookupSimpleVariable!"+var_name+"!lv!"+interp.eval_statement.level+"!flags!"+flags+"!crp1!"+create+"!");
print("FLAGS!"+namesp.getFlagsString(flags)+"!");
}
    var ns = null;
    var resolve_obj = null;
    var var_obj = null;
    var var_frame_ptr = interp.var_frame_ptr;
    var my_var_obj;
    var result;

    if (flags & namesp.NAMESPACE_LOOKUP_GLOBAL_ONLY) {
      ns = interp.global_ns_ptr;
    } else {
      ns = interp.var_frame_ptr.ns_ptr;
    }

    /*
     * If this namespace has a variable resolver, then give it first crack at
     * the variable resolution. It may return a RaplVariable value, it may signal
     * to continue onward, or it may signal an error.
     */

if (namesp.variable_debug) {
print("NS!"+ns.full_name+"!");
}
    if ((ns.variable_resolver != null) && !(flags & namesp.VAR_LOOKUP_AVOID_RESOLVERS)) {
      interp.setLookupResolveVar(null);
      result = ns.variable_resolver.resolve(interp, var_name, ns, flags);
      var_obj = interp.getLookupResolveVar();
      interp.setLookupResolveVar(null);
    } else {
      result = namesp.CONTINUE;
    }
    while ((result == namesp.CONTINUE) && (resolve_obj != null)) {
      resolve_obj = resolve_obj.getNextResolver();
    }
    if (result == namesp.OK) {
if (namesp.variable_debug) {
print("lookupSimpleVariable ret1!"+var_name+"!");
}
      return var_obj;
    } else {
      if (result != namesp.CONTINUE) {
if (namesp.variable_debug) {
print("lookupSimpleVariable ret2!"+var_name+"!");
}
        return null;
      }
    }
    // FIXME !!! only temporary !! need to set NAMESPACE_LOOKUP_NAMESPACE_ONLY when calling!!
//    if (ns.full_name != "::") {
//      if (!(flags & namesp.NAMESPACE_LOOKUP_NAMESPACE_ONLY)) {
//        flags |= namesp.NAMESPACE_LOOKUP_NAMESPACE_ONLY;
//      }
//    }
    /*
     * Look up name. Look it up as either a namespace variable or as a
     * local variable in a procedure call frame. Interpret
     * var_name as a namespace variable if:
     *    1) so requested by a NAMESPACE_LOOKUP_GLOBAL_ONLY or NAMESPACE_LOOKUP_NAMESPACE_ONLY
     *       flag,
     *    2) there is no active frame (we're at the global :: scope),
     *    3) the active frame was pushed to define the namespace context for a
     *       "namespace eval" or "namespace inscope" command,
     *    4) the name has namespace qualifiers ("::"s).
     * Otherwise, if var_name is a local variable, search in the callframe variables
     *
     * If create and the variable isn't found, create the variable
     */
    index_ptr[0] = -3;
    if (((flags & (namesp.NAMESPACE_LOOKUP_GLOBAL_ONLY | namesp.NAMESPACE_LOOKUP_NAMESPACE_ONLY)) != 0)
      || !var_frame_ptr.hasLocalVars()
      || (var_name.match("^::") != null)) {
      var tail;
      var lookGlobal = (flags & namesp.NAMESPACE_LOOKUP_GLOBAL_ONLY)
        || (ns == interp.global_ns_ptr)
        || ((var_name.charAt(0) == ':') && (var_name.charAt(1) == ':'));
if (namesp.variable_debug > 1) {
print("lookGobal!"+lookGlobal+"!");
}
      if (lookGlobal) {
        flags = (flags | namesp.NAMESPACE_LOOKUP_GLOBAL_ONLY) & ~namesp.NAMESPACE_LOOKUP_NAMESPACE_ONLY;
	index_ptr[0] = -1;
      } else {
        if (flags & namesp.VAR_LOOKUP_AVOID_RESOLVERS) {
          flags = (flags | namesp.NAMESPACE_LOOKUP_NAMESPACE_ONLY);
        }
        if (flags & namesp.NAMESPACE_LOOKUP_NAMESPACE_ONLY) {
          index_ptr[0] = -2;
	}
      }
      /*
       * Don't pass VAR_LOOKUP_LEAVE_ERR_MSG, we may yet create the variable, or
       * otherwise generate our own error!
       */
      my_var_obj = namesp.FindNamespaceVar(var_name, ns, 
          (flags | namesp.VAR_LOOKUP_AVOID_RESOLVERS) & ~namesp.VAR_LOOKUP_LEAVE_ERR_MSG);
if (namesp.variable_debug > 1) {
print("FNV!"+my_var_obj+"!"+ns.full_name+"!"+var_name+"!");
}
      if (my_var_obj == null)  {
        if (create) {    /* Var wasn't found so create it. */
	  var var_ns_ptr = new Array();
	  var dummy1_ptr = new Array();
	  var dummy2_ptr = new Array();
	  var tail = new Array();
print("lookupSimpleVar QFN!");
          namesp.getNamespaceForQualName(var_name, ns, flags, var_ns_ptr, dummy1_ptr, dummy2_ptr, tail);
	  var_ns_ptr = var_ns_ptr[0];
	  tail= tail[0];
	  if (var_ns_ptr == null) {
            namesp.err_msg = namesp.msg_bad_namespace;
if (namesp.variable_debug) {
print("lookupSimpleVariable ret3!"+var_name+"!"+namesp.err_msg+"!"+ns.full_name+"!");
}
	    return null;
	  } else {
            if (tail == null) {
              namesp.err_msg = namesp.msg_missing_name;
if (namesp.variable_debug) {
print("lookupSimpleVariable ret4!"+var_name+"!");
}
	      return null;
	    }
	  }
	  if (tail != var_name) {
	    var_name = tail;
	  }
          var_ns_ptr.variables[var_name] = new R.Variable(interp, var_name, "VAR_NAMESPACE_VAR VAR_UNDEFINED", namesp.interp.callframe);
	  my_var_obj = var_ns_ptr.variables[var_name];
	  if (lookGlobal) {
            /*
             * The variable was created starting from the global
             * namespace: a global reference is returned even if it
             * wasn't explicitly requested.
             */
	    index_ptr[0] = -1;
	  } else {
            index_ptr[0] = -2
	  }
	} else {
          namesp.err_msg = namesp.msg_no_such_var;
if (namesp.variable_debug) {
print("lookupSimpleVariable ret5!"+var_name+"!");
}
	  return null;
	}
      }
    } else { /* Local var: look in callframe. */
      var do_create = 0;
      my_var_obj = var_frame_ptr.getVariable(var_name, do_create);
      if (my_var_obj != null) {
        if (my_var_obj.link != null) {
if (namesp.variable_debug) {
print("LINK ret!"+my_var_obj.link+"!");
}
          return my_var_obj.link;
        }
      }
      if (create) {
        my_var_obj = var_frame_ptr.getVariable(var_name, create);
      }
      if (my_var_obj == null) {
        namesp.err_msg = namesp.msg_so_such_var;
      }
    }
if (namesp.variable_debug) {
print("lookupSimpleVariable end!"+var_name+"!"+my_var_obj+"!"+(my_var_obj == null ? "null" : my_var_obj.toDebugString())+"!");
}
    return my_var_obj;
  },

  /* ==================== showNamespaceInfo ===================================== */
  showNamespaceInfo: function(parent, indent) {
    print("NS!"+parent.name+"!numChld!"+parent.children.length+"!");
    for(var i=0; i < parent.children.length; i++) {
	this.showNamespaceInfo(parent.children[i], indent+"  ");
    }
  },

  /* ==================== getFlagsString ===================================== */
  getFlagsString: function(flags) {
    var result = "";
    var sep = "";
    for (var z in this.varLookupTypes) {
      if (flags & z) {
        result += this.getVarLookupTypeString(flags & z);
	result += sep;
	sep = " | ";
      }
    }
    return result;
  }

});

Namespace.prototype.constructor = Namespace;

R.Namespace = Namespace;

}, "0.0.1", {});