/*====================================================
* rapl_itcl_obj_type.js "A Tcl like language implementation in Javascript named WebRAPL
* (Web Rapid Application Programming Language)"
*
* RAPL itcl type implementation
*
* Released under BSD license.
* (BSD license found at <http://www.tcl.tk/software/tcltk/license.html>)
*
* Arnulf Wiedemann 2011
*/
RP.add("rapl-itcl-obj-type", function(R, name) {
function ItclObjType(interp) {
R.log('constructor called', '2.life', 'ItclObjType', true);
// kweight
var itcl_obj = this;
var constructor = itcl_obj.constructor;
ItclObjType.superclass.constructor.apply(itcl_obj, arguments);
R.Base.itcl_obj_type_oid++;
itcl_obj.oid = R.Base.itcl_obj_type_oid;
itcl_obj.interp = interp;
itcl_obj.class_type = null;
itcl_obj.class_name = null;
R.log('constructor end', '2.life', 'ItclObjType', true);
}
R.extend(ItclObjType, R.Token, {
my_name: "ItclObjType",
type_name: "itcl",
flags: 0,
/* ==================== setFromAny ================================== */
setFromAny: function(obj_ptr) {
var itcl = this;
var class_name = itcl.class_name.toString();
var class_type = itcl.class_type;
var full_class_name;
var ns_ptr;
var class_ns_ptr;
var cmd_ptr;
var tail = new Array();
var head = new Array();
var class_info;
var ret_code;
if (obj_ptr.obj_type == itcl.interp.itcl_obj_type) {
return itcl.OK;
}
/*
* check for an empty class name to avoid a crash
*/
if (itcl.interp.itcl_obj_type.class_name.getStringLength() == 0) {
itcl.interp.setResultString("invalid class name \"\"");
return itcl.ERROR;
}
if (!(class_name.charAt(0) == ':' && class_name.charAt(1) == ':')) {
class_name = itcl.interp.frame_ptr.ns_ptr.full_name+"::"+class_name
full_class_name = itcl.interp.string.obj_type.newStringObj(class_name, -1);
} else {
full_class_name = itcl.class_name;
}
full_class_name.incrRefCount();
itcl.interp.full_class_name = full_class_name.getString();
/*
* Make sure that a class with the given name does not
* already exist in the current namespace context. If a
* namespace exists, that's okay. It may have been created
* to contain stubs during a "namespace import" operation.
* We'll just replace the namespace data below with the
* proper class data.
*/
class_ns_ptr = itcl.interp.variable_obj_type.findNamespace(full_class_name.getString(), null, /* flags */ 0);
if (class_ns_ptr != null && class_ns_ptr.class_type == varbl.ITCL_CLASS) {
varbl.interp.setResultString("class \""+class_name+"\" already exists");
return varbl.ERROR;
}
/*
* Make sure that a command with the given class name does not
* already exist in the current namespace. This prevents the
* usual Tcl commands from being clobbered when a programmer
* makes a bogus call like "class info".
*/
cmd_ptr = itcl.interp.global_ns_ptr.findCommand(class_name, null, itcl.NAMESPACE_LOOKUP_ONLY);
if (cmd_ptr != null /* && !Itcl_IsStub(cmd_ptr) */) {
var str = "command \""+class_name+"\" already exists";
if (class_name.indexOf('::') < 0) {
str += " in namespace \""+itcl.interp.frame_ptr.ns_ptr.full_name+"\"";
}
varbl.interp.setResultString(str);
return varbl.ERROR;
}
/*
* Make sure that the class name does not have any goofy
* characters:
*
* . => reserved for member access like: class.publicVar
*/
tail = itcl.interp.namespace_obj_type.nsTail(class_name);
if (tail.indexOf(".") >= 0) {
varbl.interp.setResultString("bad class name \""+tail+"\"");
return TCL_ERROR;
}
itcl.class_name.incrRefCount();
/*
* Allocate class definition data.
*/
class_info = new R.ItclClass(itcl.interp, itcl.class_name, full_class_name, itcl.class_type);
itcl.interp.curr_class_info = class_info;
/*
* Initialize the heritage info--each class starts with its
* own class definition in the heritage. Base classes are
* added to the heritage from the "inherit" statement.
*/
// FIXME !! need code for inheritance here !!
/*
* Create a namespace to represent the class. Add the class
* definition info as client data for the namespace. If the
* namespace already exists, then replace any existing client
* data with the class data.
*/
var my_name = "";
if (class_name.charAt(0) == ':' && class_name.charAt(1) == ':') {
ns_ptr = itcl.interp.getCurrentNamespace();
my_name += ns_ptr.full_name;
if (ns_ptr.parent_ptr != null) {
my_name += "::";
}
}
my_name += itcl.class_name;
var name_obj_ptr = itcl.interp.string_obj_type.newStringObj(my_name, -1);
name_obj_ptr.incrRefCount();
if (class_ns_ptr != null) {
var old_cmd_ptr = itcl.interp.global_ns_ptr.findCommand(name_obj_ptr.getString(), null, 0);
if (old_cmd_ptr != null) {
// deleteCommandFromToken(old_cmd_ptr);
}
} else {
class_ns_ptr = itcl.interp.variable_obj_type.findNamespace(full_class_name.getString(), null, /* flags */ itcl.NAMESPACE_CREATE_IF_UNKNOWN);
}
if (class_ns_ptr.class_type != itcl.interp.class_type) {
class_ns_ptr.class_type = itcl.interp.class_type;
}
class_info.ns_ptr = class_ns_ptr;
/*
* Create a command in the current namespace to manage the class:
* <className>
* <className> <objName> ?<constructor-args>?
*/
itcl.interp.registerCommand(class_name, function(interp, args) {
var result = interp.itcl_obj_type.classCommand(args);
return result;
});
class_ns_ptr.setNamespaceClassCommand(class_name);
// class_ns_ptr.setVariableResolver(new TclResolve(interp, itcl.RESOLVER_TYPE_VARIABLE));
class_ns_ptr.class_type = itcl.class_type;
/*
* now build the namespace for the common private and protected variables
* public variables go directly to the class namespace
*/
var_namespace = "::itcl::internal::variables"+full_class_name.getString();
class_info.variable_namespace = itcl.interp.namespace_obj_type.createNamespace(var_namespace);
var frame_ptr = new Array();
var parse_ns_ptr = itcl.interp.variable_obj_type.findNamespace("::itcl::classdefs", itcl.interp.global_ns_ptr, itcl.NAMESPACE_CREATE_IF_UNKNOWN);
itcl.interp.namespace_obj_type.pushStackFrame(frame_ptr, parse_ns_ptr, itcl.CAL_TYPE_EVAL);
ret_code = itcl.interp.eval_statement.evalObj(obj_ptr);
itcl.interp.namespace_obj_type.popStackFrame();
if (ret_code == itcl.OK) {
/*
* At this point, parsing of the class definition has succeeded.
* Add built-in methods such as "configure" and "cget"--as long
* as they don't conflict with those defined in the class.
*/
// FIXME !! need code here !!!
obj_ptr.obj_type = itcl.interp.itcl_obj_type;
/*
* Build the name resolution tables for all data members.
*/
if (class_info.initClassCommands() == itcl.OK) {
itcl.interp.classes[itcl.escape_key(class_name)] = class_info;
return ret_code;
}
} else {
// FIXME free the allocated stuff!!
}
return ret_code;
},
/* ==================== mkMember ================================== */
mkMember: function(protection, kind, args) {
var itcl = this;
var i = 0;
var what = null;
var my_name = null;
var kind_val = null;
var class_info;
if (itcl.interp.curr_class_info == null) {
itcl.interp.setResultString("INTERNAL ERROR: missing curr_class_info");
return itcl.ERROR;
}
class_info = itcl.interp.curr_class_info;
kind_val = itcl.getItclTypeFromString(kind);
if (kind_val != null) {
kind_val = parseInt(kind_val);
}
//print("mkMember!"+protection+"!"+kind+"!"+args+"!"+kind_val+"!"+itcl.ITCL_VARIABLE+"!");
switch (kind_val) {
case itcl.ITCL_COMMON:
case itcl.ITCL_TYPE_VARIABLE:
case itcl.ITCL_VARIABLE:
case itcl.ITCL_OPTION:
case itcl.ITCL_PROC:
case itcl.ITCL_TYPEMETHOD:
case itcl.ITCL_COMPONENT:
case itcl.ITCL_TYPECOMPONENT:
case itcl.ITCL_METHOD:
if (args.length == 0) {
itcl.interp.setResultString("too few args for: \""+kind+"\"");
return itcl.ERROR;
}
my_name = args[i].toString();
i++;
break;
case itcl.ITCL_TYPE_CONSTRUCTOR:
case itcl.ITCL_CONSTRUCTOR:
case itcl.ITCL_DESTRUCTOR:
case itcl.ITCL_INHERIT:
my_name = kind;
break;
case itcl.ITCL_DELEGATE:
if (args.length < 2) {
itcl.interp.setResultString("too few args for: \""+kind+"\"");
return itcl.ERROR;
}
what = args[i];
i++;
my_name = args[i].toString();
i++;
break;
default:
itcl.interp.setResultString("funny kind: \""+kind+"\" in mkMember"+" "+kind_val);
return itcl.ERROR;
break;
}
switch (kind_val) {
case itcl.ITCL_COMMON:
case itcl.ITCL_TYPE_VARIABLE:
case itcl.ITCL_VARIABLE:
if (typeof itcl.interp.curr_class_info.variables[itcl.escape_key(my_name)] != "undefined") {
itcl.interp.setResultString(kind+" "+my_name+" is already defined for "+itcl.getItclClassTypeString(class_info.class_type)+" \""+class_info.class_name+"\"");
return itcl.ERROR;
}
var var_info = new R.ItclVariable(itcl.interp, protection, kind_val, my_name, args.slice(i), class_info);
itcl.interp.curr_class_info.variables[itcl.escape_key(my_name)] = var_info;
break;
case itcl.ITCL_PROC:
case itcl.ITCL_TYPEMETHOD:
case itcl.ITCL_METHOD:
if (typeof itcl.interp.curr_class_info.functions[itcl.escape_key(my_name)] != "undefined") {
itcl.interp.setResultString(kind+" "+my_name+" is already defined for "+itcl.getItclClassTypeString(class_info.class_type)+" \""+class_info.class_name+"\"");
return itcl.ERROR;
}
var fcn_info = new R.ItclFunction(itcl.interp, protection, kind_val, my_name, class_info);
fcn_info.storeFunctionInfo(args.slice(i));
itcl.interp.curr_class_info.functions[itcl.escape_key(my_name)] = fcn_info;
break;
case itcl.ITCL_OPTION:
if (typeof itcl.interp.curr_class_info.options[itcl.escape_key(my_name)] != "undefined") {
itcl.interp.setResultString(kind+" "+my_name+" is already defined for "+itcl.getItclClassTypeString(class_info.class_type)+" \""+class_info.class_name+"\"");
return itcl.ERROR;
}
var opt_info = new R.ItclOption(itcl.interp, protection, kind_val, my_name, args.slice(i), class_info);
itcl.interp.curr_class_info.options[itcl.escape_key(my_name)] = opt_info;
break;
case itcl.ITCL_COMPONENT:
case itcl.ITCL_TYPE_COMPONENT:
if (typeof itcl.interp.curr_class_info.components[itcl.escape_key(my_name)] != "undefined") {
itcl.interp.setResultString(kind+" "+my_name+" is already defined for "+itcl.getItclClassTypeString(class_info.class_type)+" \""+class_info.class_name+"\"");
return itcl.ERROR;
}
var comp_info = new R.ItclComponent(itcl.interp, protection, kind_val, my_name, args.slice(i), class_info);
itcl.interp.curr_class_info.components[itcl.escape_key(my_name)] = comp_info;
break;
case itcl.ITCL_TYPE_CONSTRUCTOR:
case itcl.ITCL_CONSTRUCTOR:
case itcl.ITCL_DESTRUCTOR:
if (typeof itcl.interp.curr_class_info.functions[itcl.escape_key(my_name)] != "undefined") {
itcl.interp.setResultString(kind+" "+my_name+" is already defined for "+itcl.getItclClassTypeString(class_info.class_type)+" \""+class_info.class_name+"\"");
return itcl.ERROR;
}
var fcn_info = new R.ItclFunction(itcl.interp, protection, kind_val, my_name, class_info);
switch (kind_val) {
case itcl.ITCL_CONSTRUCTOR:
fcn_info.storeConstructorInfo(args.slice(i));
itcl.interp.curr_class_info.class_constructor = fcn_info;
break;
case itcl.ITCL_DESTRUCTOR:
fcn_info.storeDestructorInfo(args.slice(i));
itcl.interp.curr_class_info.class_destructor = fcn_info;
break;
case itcl.ITCL_TYPE_CONSTRUCTOR:
fcn_info.storeTypeConstructorInfo(args.slice(i));
itcl.interp.curr_class_info.class_typeconstructor = fcn_info;
break;
}
break;
case itcl.ITCL_INHERIT:
args.unshift(protection);
args.unshift(kind);
args.unshift(name);
interp.curr_class_obj.store_inherit(args);
break;
case itcl.ITCL_DELEGATE:
args.unshift(protection);
args.unshift(kind);
args.unshift(name);
interp.curr_class_obj.store_delegate(args);
break;
default:
throw "funny kind: \""+kind+"\" in mkMember";
break;
}
return itcl.OK;
},
/* ==================== classCommand ================================== */
classCommand: function(args) {
var itcl = this;
var class_name = args[0].getString();
var cmd_name = args[1].getString();
var cmd_name_ptr;
var constructor_args = args.slice(2);
var ns_ptr;
var class_only = 0;
var class_info;
var class_object;
var object_name;
var object_namespace;
var cmd_obj;
var usage = "should be \""+class_name+" method ?arg ...?"
if (args.length == 0) {
throw usage;
}
ns_ptr = itcl.interp.global_ns_ptr.getNamespace(class_name);
class_name = ns_ptr.name;
cmd_obj = itcl.interp.global_ns_ptr.getClassCommand(ns_ptr, cmd_name, class_only);
if (cmd_obj == null) {
/* command not found seems to be creation of a class */
var re = new RegExp("(.*)(#auto)(.*)");
var res = re.exec(cmd_name);
if (res != null) {
var head = res[1];
var trailer = res[3];
class_name = class_name;
var my_class_name = class_name.substring(0,1).toLowerCase()+class_name.substring(1);
while (true) {
var cnt = ns_ptr.getAutoCount();
var cmd_obj = null;
cmd_name = head+ns_ptr.name+cnt+trailer;
try {
cmd_obj = itcl.interp.global_ns_ptr.getCommand(itcl.interp, cmd_name);
} catch(e) {
};
if (cmd_obj == null) {
break;
}
}
}
object_namespace = itcl.interp.frame_ptr.ns_ptr;
class_info = itcl.interp.classes[itcl.escape_key(ns_ptr.full_name)];
//print("object_namespace!"+object_namespace+"!"+class_info+"!"+ns_ptr.toDebugString()+"!");
if (object_namespace.full_name == "::") {
if (!(cmd_name.charAt(0) == ':' && cmd_name.charAt(1) == ':')) {
object_name = "::"+cmd_name;
} else {
object_name = cmd_name;
}
} else {
object_name = object_namespace.full_name+"::"+cmd_name;
}
class_object = new R.ItclObject(itcl.interp, object_name, class_info, args.slice(2));
itcl.interp.class_objects[itcl.escape_key(object_name)] = class_object;
itcl.interp.registerCommand(object_name, function(interp, args) {
var result;
result = interp.itcl_obj_type.classObjectCommand(ns_ptr, args);
return result;
});
} else {
itcl.interp.setResultString("direct classname function call for. \""+cmd_name+"\" not yet implemented");
return itcl.ERROR;
}
itcl.interp.setResultString(cmd_name);
return itcl.OK;
},
/* ==================== callClassCommand ========================================= */
callClassCommand: function(ns_ptr, fcn_name, args) {
var i_obj = this;
var class_only = 1;
var ret_code;
var cmd_obj = ns_ptr.getClassCommand(ns_ptr, fcn_name, class_only);
var name_ptr = i_obj.interp.string_obj_type.newStringObj(fcn_name, -1);
/* we need to add the command as the first argument !!! */
var my_args = new Array();
name_ptr.incrRefCount();
my_args.push(name_ptr);
for (var k = 0; k < args.length; k++) {
my_args.push(args[k]);
args[k].incrRefCount();
}
if (cmd_obj != null) {
cmd_obj.incrCmdRefCount();
if (cmd_obj.is_proc) {
ret_code = cmd_obj.u.proc.cmd_proc(cmd_obj, i_obj.interp.empty_obj, -1, my_args.length, my_args);
} else {
/* Check if there are too nested calls */
//print("FR!"+i_obj.intp.frame_ptr.toDebugString()+"!"+i_obj.interp.max_nesting_depth+"!");
i_obj.interp.cmd_priv_data = cmd.u.native_fcn.privdata;
retcode = cmd_obj.u.native_fcn.cmd_proc(i_obj.interp, my_args, cmd_obj);
}
cmd_obj.decrCmdRefCount();
} else {
//print("RETC!"+result+"!"+argc+"!"+argv+"!");
/* Call [unknown] */
ret_code = i_obj.interp.unknownFcn(my_args.length, my_args, i_obj.interp.empty_obj, -1);
}
name_ptr.decrRefCount();
for (var k = 0; k < args.length; k++) {
args[k].decrRefCount();
}
return ret_code;
},
/* ==================== classObjectCommand ================================== */
classObjectCommand: function(ns_ptr, args) {
var itcl = this;
var class_object = args[0];
var sub_cmd = args[1];
var my_args = args.slice(2);
var ret_code;
// print("classObjectCommand!"+ns_ptr.toDebugString()+"!"+sub_cmd+"!"+my_args+"!");
ret_code = itcl.callClassCommand(ns_ptr, sub_cmd.getString(), my_args);
return ret_code;
},
});
ItclObjType.prototype.constructor = ItclObjType;
R.ItclObjType = ItclObjType;
}, "0.0.1", {});