/*====================================================
 * rapl_interp.js "A Tcl like language implementation in Javascript named RAPL 
 * (Rapid Application Programming Language)"
 *
 * an instance of an interp 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: new implementation based on Jim Tcl
 * added a lot of Tcl 8.6 syntax and itcl support
 */

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

/* =============================== Interp ================================== */

function Interp(win, start_dir) {
  R.log('constructor called', '2.life', 'Interp', true);
  
  // kweight
  var intp = this;

  intp.namespaces        = new Array();
  intp.win               = win;
  intp.global_ns_ptr     = null;
  intp.current_namespace = null;
  intp.var_frame_ptr     = null;

  R.Base.interp_oid++;
  intp.oid = R.Base.interp_oid;

  intp.array_obj_type = new R.ArrayObjType(intp);
  intp.coerced_double_obj_type = new R.CoercedDoubleObjType(intp);
  intp.command_obj_type = new R.CommandObjType(intp);
  intp.compared_string_obj_type = new R.ComparedStringObjType(intp);
  intp.dict_obj_type = new R.DictObjType(intp);
  intp.double_obj_type = new R.DoubleObjType(intp);
  intp.expr_obj_type = new R.ExprObjType(intp);
  intp.index_obj_type = new R.IndexObjType(intp);
  intp.interpolated_obj_type = new R.InterpolatedObjType(intp);
  intp.int_obj_type = new R.IntObjType(intp);
  intp.list_obj_type = new R.ListObjType(intp);
  intp.namespace_obj_type = new R.NamespaceObjType(intp);
  intp.reference_obj_type = new R.ReferenceObjType(intp);
  intp.return_code_obj_type = new R.ReturnCodeObjType(intp);
  intp.scan_fmt_string_obj_type = new R.ScanFmtStringObjType(intp);
  intp.script_line_obj_type = new R.ScriptLineObjType(intp);
  intp.script_obj_type = new R.ScriptObjType(intp);
  intp.source_obj_type = new R.SourceObjType(intp);
  intp.string_obj_type = new R.StringObjType(intp);
  intp.variable_obj_type = new R.VariableObjType(intp);

  intp.free_obj_list    = null;
  intp.live_obj_list    = null;
  intp.free_callframe_list = null;
  intp.live_callframe_list = null;
  intp.default_obj      = new R.RaplObject(intp);
  intp.empty_string_obj = intp.string_obj_type.newStringObj("", 0);
  intp.empty_string_obj.incrRefCount();
  intp.empty_obj        = intp.string_obj_type.newEmptyStringObj();
  intp.empty_obj.incrRefCount();
  intp.true_obj         = intp.int_obj_type.newIntObj(1);
  intp.true_obj.incrRefCount();
  intp.false_obj        = intp.int_obj_type.newIntObj(0);
  intp.false_obj.incrRefCount();
  intp.result           = intp.empty_obj;
  intp.result.incrRefCount();
  intp.error_proc       = intp.string_obj_type.newEmptyStringObj();
  intp.error_proc.incrRefCount();
  intp.error_flag       =  0;
  intp.error_file_name_obj = intp.string_obj_type.newEmptyStringObj();
  intp.error_file_name_obj.incrRefCount();
  intp.error_line       = -1;
  intp.stack_trace      = intp.string_obj_type.newEmptyStringObj();
  intp.stack_trace.incrRefCount();
  intp.add_stack_trace  = 0;

  intp.local_procs      = null;
  intp.max_nesting_depth = 20;
  intp.proc_epoch       = 0;
  intp.local            = false;
  intp.commands         = new Array();
  intp.procs            = new Array();
  intp.packages         = new Array();
  intp.package_names    = new Array();
  intp.class_objects    = new Object();
  intp.class_infos      = null;
  intp.curr_class_obj   = null;
  intp.unique_id        = 1;
  intp.result_vars      = new Object();
  intp.lookup_resolve_var = null;
  intp.package_obj      = null;
  intp.current_dir      = ".";
  intp.start_dir        = start_dir;
  intp.no_trace         = false;
  intp.curr_file_name   = "unknown";
  intp.curr_line_no     = -1;
  intp.last_line_no     = -1;
  intp.curr_statement   = "unknown";
  intp.aliases          = new Array();
  intp.curr_interp      = this;
  intp.error_args       = null;
  /* number of levels changed by uplevel command, relevant for info level RAPL command! */
  intp.uplevel_dist     = 0;
  intp.upvar_dist       = 0;
  intp.in_upvar         = 0;

  var constructor = intp.constructor;
  Interp.superclass.constructor.apply(intp, arguments);

  intp.eval_statement   = new R.EvalStatement(intp);
  intp.eval_expression  = new R.Expr(intp);
  intp.list_pkg         = new R.PkgList(intp);
  intp.namespace_pkg    = new R.PkgNamespace(intp);
  intp.dict_pkg         = new R.PkgDict(intp);

  R.registerCmds(intp);

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

}

R.extend(Interp, R.Token, {
  my_name: "RaplInterp",
  /* ==================== init ===================================== */
  init: function(win) {
    var intp = this;

/*
    if (win.DOMParser) {
//      this.dom_parser=new DOMParser();
//      xmlDoc=this.dom_parser.parseFromString(text,"text/xml");
    } else {
      // Internet Explorer
//      xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
//      xmlDoc.async="false";
//      xmlDoc.loadXML(text); 
    }
*/

    intp.win = win;
    intp.global_ns_ptr    = intp.namespace_obj_type.createNamespace("");
    if (intp.global_ns_ptr == null) {
      intp.panic("createInterp: can't create global namespace");
    }
    var frame_ptr = new R.Callframe(intp, /* is_proc_call_frame */ 0);
    var result = intp.namespace_obj_type.pushCallFrame(frame_ptr, intp.global_ns_ptr, /*isProcCallFrame*/ 0);
    if (result != intp.OK) {
      intp.panic("createInterp: failed to push the root stack frame");
    }
    frame_ptr.objc = 0;
    intp.frame_ptr = frame_ptr;
    intp.var_frame_ptr = frame_ptr;
    intp.root_frame_ptr = frame_ptr;

    intp.current_namespace_name = intp.global_ns_ptr.name;
    intp.current_namespace = intp.global_ns_ptr;
  },

  /* ==================== getCurrentNamespace ===================================== */
  getCurrentNamespace: function() {
    if (this.uplevel_dist == 0) {
      return this.current_namespace;
    }
    return this.namespaces[this.level-this.uplevel_dist];
  },

  /* ==================== pushNamespace ===================================== */
  pushNamespace: function(name, ns) {
    this.namespaces.push(ns);
    this.current_namespace = ns;
    this.current_namespace_name = name;
  },

  /* ==================== popNamespace ===================================== */
  popNamespace: function() {
    this.namespaces.pop();
    var idx = this.namespaces.length-1;
    var ns = this.namespaces[idx];
    this.current_namespace = ns;
    this.current_namespace_name = this.global_ns_ptr.getNamespaceName(ns);
  },

  /* ==================== setCommandNamespace ===================================== */
  setCommandNamespace: function(ns) {
    this.command_namespace = ns;
  },

  /* ==================== getVar ===================================== */
  getVar: function(name, flags) {
    var intp = this;
    var part2 = null;
    var parts;
    var var_name = name.toString();

    if (intp.matchArrayName.test(var_name)) {
      parts = intp.getArrayNameParts(var_name, var_name.length);
      var_name = parts[0];
      part2 = parts[1];
    }
    /* optimization: we check, if the variable is in the var_cache and if the variable epoch
     * R.Base.variable_oid <= callframe.variable_oid and if yes, we can use the cached variable
     */
    var var_obj = null;
//    if (part2 == null) {
      if (intp.frame_ptr.top_variable_oid == R.Base.variable_oid) {
        var my_variable_cache = intp.frame_ptr.variable_cache;
	if (typeof my_variable_cache[var_name] != "undefined") {
          var_obj = my_variable_cache[var_name];
	}
      } else {
        intp.frame_ptr.variable_cache = new Object();
	intp.frame_ptr.top_variable_oid = R.Base.variable_oid;
      }
//    }
    if (var_obj == null) {
      var create_it = 0;
//      var var_obj = intp.current_namespace.lookupVariableEx(intp, name, intp.VAR_LOOKUP_LEAVE_ERR_MSG, "", create_it, create_it);
      var var_obj = intp.current_namespace.lookupVariableEx(intp, var_name, 0, "", create_it, create_it);
      var my_variable_cache = intp.frame_ptr.variable_cache;
//      if (part2 == null) {
        intp.frame_ptr.variable_cache[var_name] = var_obj;
//      }
    } else {
//print("found!"+var_name+"!");
    }
    if (var_obj == null) {
//print("getVar cannot get variable \""+name+"\"");
      if (flags & intp.FUNCTION_FLAGS_LEAVE_ERR_MSG) {
        intp.setResultFormatted("can't read \"%#s\": no such variable", name)
      }
      return null;
    }
    var result = var_obj;
    return result;
  },

  /* ==================== getVarValue ===================================== */
  old_getVarValue: function(name) {
    var intp = this;
    var part2 = null;
    var var_obj = intp.getVar(name, intp.FUNCTION_FLAGS_LEAVE_ERR_MSG);
    if (var_obj == null) {
      return null;
    }
    var parts;
    name = name.toString();
//print("GETVARVALUE!"+name+"!"+var_obj.toDebugString()+"!");
    if (intp.matchArrayName.test(name)) {
      parts = intp.getArrayNameParts(name, name.length);
      name = parts[0];
      part2 = parts[1];
    }
    var result;
    if (part2 == null) {
        result = var_obj.getVariableValue();
    } else {
        result = var_obj.getValue(part2, "TEXT");
    }
    if (name == "this") {
      if ((result.toString().charAt(0) == ":") && (result.toString().charAt(1) == ":") && (result.toString().charAt(2) == ".")) {
        /* path for Tk widgets strip off the "::"*/
	result = result.toString().substring(2);
      }
    }
    return result;
  },

  /* ==================== setVar ===================================== */
  old_setVar: function(name, val) {
print("setVar!"+name+"!");
    var intp = this;
    var part2 = null;
    var parts;
    name = name.toString();
    if (intp.matchArrayName.test(name)) {
      parts = intp.getArrayNameParts(name, name.length);
print("SV!"+name+"!"+val+"!"+parts+"!");
      name = parts[0];
      part2 = parts[1];
    }
    /* optimization: we check, if the variable is in the var_cache and if the variable epoch
     * R.Base.variable_oid <= callframe.variable_oid and if yes, we can use the cached variable
     */
    var var_obj = null;
    if (part2 == null) {
      if (intp.eval_statement.curr_callframe.top_variable_oid == R.Base.variable_oid) {
        var my_variable_cache = intp.eval_statement.curr_callframe.variable_cache;
	if (typeof my_variable_cache[name] != "undefined") {
          var_obj = my_variable_cache[name];
	}
      } else {
        var my_variable_cache = intp.eval_statement.curr_callframe.variable_cache;
	my_variable_cache = new Object();
	intp.eval_statement.curr_callframe.top_variable_oid = R.Base.variable_oid;
      }
    }
    if (var_obj == null) {
      var create_it = 1; /* temporary FIXME */
      var var_obj = intp.global_ns_ptr.lookupVariableEx(intp, name, 0, "", create_it, create_it);
print("VA!"+name+"!"+var_obj.toDebugString()+"!");
      var my_variable_cache = intp.eval_statement.curr_callframe.variable_cache;
      if (part2 == null) {
        my_variable_cache[name] = var_obj;
      }
    }
    if (var_obj.value == val) {
      if (name == "_") {
        return var_obj;
      } else {
//print("VV!"+name+"!"+val+"!");
//        throw "setVAR! value == val for variable \""+name+"\"!";
      }
    }
    var_obj.setValue(val, part2);
    return var_obj;
  },

  /* ==================== getCommand ===================================== */
  getCommand: function(obj_ptr) {
    var intp = this;
    var cmd_name = obj_ptr.getString();
    var my_aliases = intp.aliases[intp.curr_interp];
    var cmd_obj = null;
//print("GETCMD!"+cmd_name+"!");

    for (var i = 0; i < intp.aliases.length; i++) {
      var my_alias = intp.aliases[i];
      var have_alias = my_alias.getAlias(intp.curr_interp, cmd_name);
      if (have_alias != null) {
        if (have_alias.params.length != 0) {
          /* have arguments !!! */
          throw "arguments for interp alias not yet implemented!!";
        }
        cmd_name = have_alias.target_cmd;
	break;
      }
    }
    /* optimization: we check, if the command is in the command_cache and if the command epoch
     * R.Base.command_oid <= callframe.command_oid and if yes, we can use the cached command
     */
    if ((intp.eval_statement.curr_callframe.top_command_oid == R.Base.command_oid) &&
       (intp.eval_statement.curr_callframe.top_itcl_command_oid == R.Base.itcl_command_oid) &&
       (intp.eval_statement.curr_callframe.top_class_function_oid == R.Base.class_function_oid)) {
      var my_command_cache = intp.eval_statement.curr_callframe.command_cache;
      if (typeof my_command_cache[cmd_name] != "undefined") {
        cmd_obj = my_command_cache[cmd_name];
      }
    } else {
      var my_command_cache = intp.eval_statement.curr_callframe.command_cache;
      my_command_cache = new Object();
      intp.eval_statement.curr_callframe.top_command_oid = R.Base.command_oid;
      intp.eval_statement.curr_callframe.top_itcl_command_oid = R.Base.itcl_command_oid;
      intp.eval_statement.curr_callframe.top_class_function_oid = R.Base.class_function_oid;
    }
    /* FIXME !! need to not use cache for these otherwise problems
     * have to figure out why
     */
    switch (cmd_name.toString()) {
    case "constructor":
    case "destructor":
    case "join":
    case "function":
      cmd_obj = null;
      break;
    }
    if (cmd_obj == null) {
      cmd_obj = intp.current_namespace.getCommand(intp, cmd_name);
      if (cmd_obj == null) {
        /* check if we have to load one of the tcl_pkg_*cmd packages to resolve the command */
//        cmd_obj = intp.checkStubsCommand(cmd_name);
      }
      if (cmd_obj != null) {
        var my_command_cache = intp.eval_statement.curr_callframe.command_cache;
        my_command_cache[cmd_name] = cmd_obj;
      }
    }
    if (cmd_obj == null) {
//      throw "No such command '"+cmd_name+"'";
//print("cmd_obj null!");
    } else {
//print("cmd_obj!"+cmd_obj.toDebugString()+"!");
    }
    return cmd_obj;
  },

  /* ==================== registerCommand ===================================== */
  registerCommand: function(name, func, privdata) {
if (typeof privdata != "undefined") {
if (privdata == null) {
print("interp registerCommand!"+name+"!"+privdata+"!");
} else {
print("interp registerCommand!"+name+"!"+typeof privdata+"!"+(privdata instanceof Array)+"!");
}
}
//print("registerCommand!"+name+"!"+this.current_namespace.full_name+"!");
    if (func == null) {
        throw "No such function: '"+name+"'";
    }
    var cmd_obj = new R.Command(name, func, privdata);
    cmd_obj.setCommandType(this.COMMAND_JSPROC);
    cmd_obj.is_proc = false;
    this.global_ns_ptr.registerCommand(name, cmd_obj, "NAMESPACE", "NAMESPACE_PROC");
  },

  /* ==================== registerSubCommand ===================================== */
  registerSubCommand: function(name, subcmd, func, privdata) {
    var intp = this;
    var path = name.split(" ");
    var ens;
    var top_ens;
    var cmd;
    var cmd_obj;

    if (func == null) {
      throw "No such subcommand: "+ name +" " + subcmd;
    }
    name = path.shift();
    cmd = intp.global_ns_ptr.getCommand(intp, name);
    if (cmd == null) {
      ens = new Object();
      ens["subcmds"] = new R.Command("subcmds", intp.InfoSubcommands, null);
      ens["subcmds"].setCommandType(intp.COMMAND_INFO_SUBCMDS);
      ens["subcmds"].is_proc = false;
      cmd_obj = new R.Command(name, intp.ensembleCommand, null, ens);
      cmd_obj.setCommandType(intp.COMMAND_ENSEMBLE);
      ens["subcmds"].is_proc = false;
      cmd = intp.global_ns_ptr.registerCommand(name, cmd_obj, "NAMESPACE", "NAMESPACE_PROC");
    }
    ens = intp.global_ns_ptr.getCommand(intp, name).ensemble;
    if (ens == null) {
      throw "Not an ensemble command 1: '"+name+"'";
    }
    top_ens = ens;
    // walks deeply into the subcommands tree
    while (path.length > 0) {
      name = path.shift();
      cmd = ens[name];
      if (cmd == null) {
        cmd = new R.Command(name, intp.ensembleCommand, null, new Object());
        cmd.setCommandType(intp.COMMAND_ENSEMBLE);
	cmd.is_proc = false;
        ens[name] = cmd;
        ens = cmd.ensemble;
        ens["subcmds"] = new R.Command("subcmds", intp.InfoSubcommands, null);
        ens["subcmds"].setCommandType(intp.COMMAND_INFO_SUBCMDS);
	ens["subcmds"] = false;
      } else {
        ens = cmd.ensemble;
      }
    }
    if (subcmd != null) {
      ens[subcmd] = new R.Command(subcmd, func, privdata);
      ens[subcmd].setCommandType(intp.COMMAND_ENSEMBLE_SUBCMD);
    }
    return top_ens;
  },

  /* ==================== getNamespace ===================================== */
  getNamespace: function () {
    var level = this.eval_statement.level - this.uplevel_dist;
//print("getNamespace!"+level+"!"+this.eval_statement.level+"!"+this.uplevel_dist+"!"+typeof this.eval_statement.callframes[level]+"!"+this.eval_statement.callframes.length+"!");
//print("getNamespace a!"+level+"!"+this.eval_statement.callframes[level].namespace.full_name+"!");
if (typeof this.eval_statement.callframes[level] == "undefined") {
print("CANNOT get Namespace for level!"+level+"!"+this.eval_statement.level+"!"+this.uplevel_dist+"!");
}
    return this.eval_statement.callframes[level].namespace;
  },

  /* ==================== getNamespaceName ===================================== */
  getNamespaceName: function () {
    return this.current_namespace_name;
  },

  /* ==================== setLookupResolveVar ===================================== */
  setLookupResolveVar: function (val) {
    this.lookup_resolve_var = val;
  },

  /* ==================== getLookupResolveVar ===================================== */
  getLookupResolveVar: function () {
    return this.lookup_resolve_var;
  },

  /* ==================== setClassObject ===================================== */
  setClassObject: function (name, val) {
    return this.class_objects[name] = val;
  },

  /* ==================== getClassObject ===================================== */
  getClassObject: function (name) {
    if (typeof this.class_objects[name] == "undefined") {
      if (typeof this.class_objects["::"+name] == "undefined") {
        return null;
      } else {
        return this.class_objects["::"+name];
      }
    }
    return this.class_objects[name];
  },

  /* ==================== addEnterStepTrace ===================================== */
  addEnterStepTrace: function(trace_obj) {
    this.eval_statement.enterstep_traces.push(trace_obj);
  },

  /* ==================== addLeaveStepTrace ===================================== */
  addLeaveStepTrace: function(trace_obj) {
    this.eval_statement.leavestep_traces.push(trace_obj);
  },

  /* ==================== resetEnterStepTraces ===================================== */
  resetEnterStepTraces: function() {
    this.eval_statement.enterstep_traces = new Array();
  },

  /* ==================== resetLeaveStepTraces ===================================== */
  resetLeaveStepTraces: function() {
    this.eval_statement.leavestep_traces = new Array();
  },

  /* ==================== validName ===================================== */
  validName: function(type, name_obj_ptr) {
    var intp = this;
    if (name_obj_ptr.obj_type != intp.var_obj_type) {
      var str = name_obj_ptr.getString();
      var len = intp.string_obj_type.getStringLength(name_obj_ptr);
      for (var i = 0; i < str.length; i++) {
        if (str.charAt(i) == '\0') {
	  intp.setResultFormatted(type+" name contains embedded null");
          return intp.ERROR;
	}
      }
    }
    return intp.OK;
  },

  /* ==================== incrProcEpoch ===================================== */
  incrProcEpoch: function() {
    var intp = this;
 
    intp.proc_epoch++;
  },

  /* ==================== wrongNumArgs ===================================== */
  wrongNumArgs: function(offset, argv, msg) {
    var intp = this;
    var obj_ptr;
    var list_obj_ptr;
    var arg_idx = 0;
    var result = new Array();

print("wrongNumArgs! not yet fully implemented!"+offset+"!"+argv+"!"+msg+"!");
return;
    if (intp.rewrite_name_obj) {
      offset -= intp.rewrite_name_count;
      argv_idx += intp.rewrite_name_count;
      list_obj_ptr = intp.listObjType.newListObj(result, 1);
      intp.rewrite_name_obj = result[0];
      intp.listObjType.insertElements(list_obj_ptr, -1, argc, argv_idx, argv);
    } else {
      list_obj_ptr = intp.listObjType.newListObj(result, 1);
    }
    if (msg != null) {
      intp.listObjType.listAppendElement(list_obj_ptr, intp.string_obj_type.newStringObj(msg, -1));
    }
    list_obj_ptr.incrRefCount();
    obj_ptr = intp.list_obj_type.listJoin(list_obj_ptr, " ", 1);
    list_obj_ptr.decrRefCount();
    obj_ptr.incrRefCount();
    intp.setResultFormatted("wrong # args: should be \"%#s\"", obj_ptr);
    obj_ptr.decrRefCount();
  },

  /* ==================== setEmptyResult ================================== */
  setEmptyResult: function() {
    var intp = this;

    intp.setResult(intp.empty_obj);
  },

  /* ==================== setResult ================================== */
  setResult: function(obj_ptr) {
    var intp = this;

    obj_ptr.incrRefCount();
    intp.result.decrRefCount();
    intp.result = obj_ptr;
  },

  /* ==================== setResultString ================================== */
  setResultString: function(str) {
    var intp = this;

    intp.result.decrRefCount();
    intp.result = intp.string_obj_type.newStringObj(str, -1);
    intp.result.incrRefCount();
  },

  /* ==================== setResultInt ================================== */
  setResultInt: function(val) {
    var intp = this;

    intp.setResult(intp.int_obj_type.newIntObj(val));
  },

  /* ==================== setResultFormatted ===================================== */
  /**
   * Very simple printf-like formatting, designed for error messages.
   *
   * The format may contain up to 5 '%s' or '%#s', corresponding to variable arguments.
   * The resulting string is created and set as the result.
   *
   * Each '%s' should correspond to a regular string parameter.
   * Each '%#s' should correspond to a (Rapl_Obj *) parameter.
   * Any other printf specifier is not allowed (but %% is allowed for the % character).
   *
   * e.g. setResultFormatted("Bad option \"%#s\" in proc \"%#s\"", optionObjPtr, procNamePtr);
   *
   * Note: We take advantage of the fact that printf has the same behaviour for 
   * both %s and %#s
   */
  setResultFormatted: function(format) {
    /* Initial space needed */
    var extra = 0;
    var n = 1;
    var params = new Array()
    var buf = "";
    var i;
    var start_idx = 0;
    var len = format.length;

    for (i = 0; i < len; i++) {
      var l;

      if (format.charAt(i) == "%") {
        switch (format.charAt(i + 1)) {
        case "s":
          buf += format.substring(start_idx, i);
          buf += arguments[n];
	  i += 2;
	  start_idx = i;
          break;
	case "#":
	  if (format.charAt(i + 2) == "s") {
	    var obj_ptr;

            buf += format.substring(start_idx, i);
	    obj_ptr = arguments[n];
            buf += obj_ptr.getString();
	    i += 3;
	    start_idx = i;
            break;
          } else {
	    i++;
          }
	default:
	  i++;
	}
      }
    }
    buf += format.substring(start_idx, i);
    len = buf.length;
    intp.setResult(intp.string_obj_type.newStringObjNoAlloc(buf, len));
  },

  /* ==================== getResult ===================================== */
  getResult: function() {
    var intp = this;

    return intp.result;
  },

  /* ==================== deleteLocalProcs ================================== */
  deleteLocalProcs: function() {
    var intp = this;
// FIXME to be coded !!
  },

  /* ==================== setErrorCode ===================================== */
  setErrorCode: function(args) {
    var intp = this;
print("WARNING! setErrorCode not yet implemented!! args: "+args+"!");
  },

  /* ==================== nameIsArrayName ===================================== */
  nameIsArrayName: function(str, len) {
    if (len && str.charAt([len - 1]) == ')' && str.match('.*[(].*')) {
      return true;
    }
    return false;
  },

  /* ==================== getArrayNameParts ===================================== */
  getArrayNameParts: function(str, len) {
    var intp = this;
    var parts = new Array();
    var start = 0;
    var had_LP = false;
    var had_RP = false;

    for (var i = 0; i < len; i++) {
      if (str.charAt(i) == "(") {
	if (had_RP) {
	  /* LP must be first */
          return null;
	}
	if (had_LP) {
	  /* LP must be only once */
          return null;
	}
        had_LP = true;
        parts.push(str.substring(start, i));
        start = i + 1;
      } else {
        if (str.charAt(i) == ')') {
	  if (! had_LP) {
	    /* LP must be first */
            return null;
	  }
	  if (had_RP) {
	    /* RP must be only once */
            return null;
	  }
	  if (i != len - 1) {
	    /* RP must be last character! */
            return null;
	  }
        had_RP = true;
          parts.push(str.substring(start, i));
	}
      }
    }
    if (parts.length < 2) {
      return null;
    }
    return parts;
  },

  /* ==================== unknown ===================================== */
  unknown: function(argc, argv, file_name_obj, line_no) {
    var intp = this;
print("UNKNOWN!"+argc+"!"+argv+"!"+file_name_obj+"!"+line_no+"!");

  },

  /* ==================== mkList ===================================== */
  mkList: function(x) {
    var list = new Array();
    for (var name in x) {
      list.push(name);
    }
    return list;
  },

  /* ==================== objectify ===================================== */
  objectify: function (text) {
//print("objectify1!"+typeof text+"!");
    if (text == null) {
//print("objectify2");
      text = "";
    } else {
//print("objectify3");
//print("objectify!"+typeof text+"!"+(text instanceof R.RaplObject)+"!");
      if (text instanceof R.RaplObject) {
//print("objectify3a");
        return text;
      }
    }
//print("objectify4!"+text+"!");
    var result = this.string_obj_type.newStringObj(text, -1);
//print("objectify5");
    return result;
  },

  /* ==================== eval_meta ===================================== */
  eval_meta: function (meta) {
print("eval_meta!"+meta.mySelf()+"!"+meta.statements_len+"!");
    var result;
    for (var stmt_idx = 0; stmt_idx < meta.statements_len; stmt_idx++) {
      result = meta.evalStatement(this, stmt_idx);
      if (result != meta.OK) {
print("RES1!"+stmt_idx+"!"+meta.getResultString(result)+"!");
        break;
      }
print("RES2!"+stmt_idx+"!"+meta.getResultString(result)+"!");

    }
    return result;
  },

});

Interp.prototype.constructor = Interp;

R.Interp = Interp;

}, "0.0.1", {});
