/*====================================================
* 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", {});