RAPL

Artifact [bce5a7ca83]
Login

Artifact [bce5a7ca83]

Artifact bce5a7ca8377b1b20d98f029f3b084a8cafff490:


/*====================================================
 * 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) == ':')) {
      if (itcl.interp.frame_ptr.ns_ptr.full_name == "::") {
        class_name = itcl.interp.frame_ptr.ns_ptr.full_name+class_name
      } else {
        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);
    class_info.class_type = itcl.interp.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 += 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 R.Resolve(itcl.interp, itcl.RESOLVER_TYPE_VARIABLE));
    class_ns_ptr.setCommandResolver(new R.Resolve(itcl.interp, itcl.RESOLVER_TYPE_COMMAND));

    /*
     * 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_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].getString();
      i++;
      break;
    case itcl.ITCL_OPTION:
      my_name = args[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].getString();
      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, class_info);
      opt_info.storeOptionInfo(args.slice(i));
      itcl.interp.curr_class_info.options[itcl.escape_key(opt_info.option_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;
      }
      itcl.interp.curr_class_info.functions[itcl.escape_key(my_name)] = fcn_info;
      break;
    case itcl.ITCL_INHERIT:
      class_info.storeInherit(args.slice(i));
      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.length > 2 ? 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, constructor_args);
      if (class_object.initItclObject() != itcl.OK) {
        return itcl.ERROR;
      }
      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, class_object, 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, class_object, args) {
//print("callClassCommand!"+ns_ptr+"!"+fcn_name+"!"+class_object+"!"+args+"!");
    var i_obj = this;
    var class_only = 1;
    var ret_code;
    var cmd_obj;
    var my_ns_ptr;
    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();

    cmd_obj = ns_ptr.getClassCommand(ns_ptr, fcn_name, class_only);
    if (cmd_obj == null) {
      my_ns_ptr = i_obj.interp.frame_ptr.ns_ptr.getNamespace("::itcl::internal");
      cmd_obj = my_ns_ptr.getClassCommand(my_ns_ptr, fcn_name, class_only);
    }
    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) {
      i_obj.interp.frame_ptr.setClassObject(class_object);
      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_obj.u.native_fcn.privdata;
        ret_code = cmd_obj.u.native_fcn.cmd_proc(i_obj.interp, my_args, cmd_obj);
      }
      cmd_obj.decrCmdRefCount();
      i_obj.interp.frame_ptr.setClassObject(null);
    } 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, class_object, args) {
    var itcl = this;
    var class_object_name = args[0];
    var sub_cmd = args[1];
    var my_args = args.slice(2);
    var ret_code;
    var class_object = new Array();

    if (itcl.interp.getItclObject(class_object_name.getString(), class_object) != itcl.OK) {
      return itcl.ERROR;
    }
    class_object = class_object[0];
    ret_code = itcl.callClassCommand(ns_ptr, sub_cmd.getString(), class_object, my_args);
    return ret_code;
  },

  /* ==================== getSuperClasses ================================== */
  getSuperClasses: function(class_ptr, result_ptr) {
    var itcl = this;

    if (class_ptr.heritage != null) {
      for (var i = 0; i < class_ptr.heritage.length; i++) {
        result_ptr.push(class_ptr.heritage[i]);
	itcl.getSuperClasses(class_ptr.heritage[i], result_ptr);
      }
    }
    return itcl.OK;
  },

});

ItclObjType.prototype.constructor = ItclObjType;

R.ItclObjType = ItclObjType;

}, "0.0.1", {});