RAPL

Artifact [885458e9f4]
Login

Artifact [885458e9f4]

Artifact 885458e9f4f3918e2c68ec137e3f3e88c7faf98e:


/*====================================================
 * rapl_dict_obj_type.js "A Tcl like language implementation in Javascript named WebRAPL 
 * (Web Rapid Application Programming Language)"
 *
 * RAPL dict type implementation
 *
 * Released under BSD license.
 * (BSD license found at <http://www.tcl.tk/software/tcltk/license.html>)
 *
 * Arnulf Wiedemann    2011
 */

RP.add("rapl-dict-obj-type", function(R, name) {

function DictObjType(interp) {
  R.log('constructor called', '2.life', 'DictObjType', true);
  // kweight
  var dict_obj = this;
  var constructor = dict_obj.constructor;
  DictObjType.superclass.constructor.apply(dict_obj, arguments);

  R.Base.dict_obj_type_oid++;
  dict_obj.oid = R.Base.dict_obj_type_oid;
  dict_obj.interp = interp;

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

R.extend(DictObjType, R.Token, {
  my_name: "DictObjType",
  type_name: "dict",
  flags: 0,

  /* ==================== setFromAny ================================== */
  setFromAny: function(obj_ptr) {
    var dct = this;
    var list_len;

    /* Get the string representation. Do this first so we don't
     * change order in case of fast conversion to dict.
     */
    obj_ptr.getString();

    /* For simplicity, convert a non-list object to a list and then to a dict */
    list_len = dct.interp.list_obj_type.listLength(obj_ptr);
    if (list_len % 2) {
      dct.interp.setResultString("invalid dictionary value: must be a list with an even number of elements", -1);
      return dct.ERROR;
    } else {
      /* Now it is easy to convert to a dict from a list, and it can't fail */
      var ht = new Object();
      var i;

      for (i = 0; i < list_len; i += 2) {
        var key_obj_ptr = new Array();
        var val_obj_ptr = new Array();

        dct.interp.list_obj_type.listIndex(obj_ptr, i, key_obj_ptr, dct.FUNCTION_FLAGS_NONE);
        dct.interp.list_obj_type.listIndex(obj_ptr, i + 1, val_obj_ptr, dct.FUNCTION_FLAGS_NONE);
        key_obj_ptr = key_obj_ptr[0];
        val_obj_ptr = val_obj_ptr[0];
        key_obj_ptr.incrRefCount();
        val_obj_ptr.incrRefCount();
        ht[key_obj_ptr.getString()] = val_obj_ptr;
        key_obj_ptr.decrRefCount();
      }
      obj_ptr.freeIntRep();
      obj_ptr.obj_type = dct.interp.dict_obj_type;
      obj_ptr.ptr(ht);
      return dct.OK;
    }
  },

  /* ==================== freeInternalRep ===================================== */
  freeInternalRep: function(obj_ptr) {
    var dct = this;
    obj_ptr.ptr(null);
  },

  /* ==================== dupInternalRep ===================================== */
  dupInternalRep: function(src_ptr, dup_ptr) {
    var dct = this;
    var ht = src_ptr.ptr();
    var dup_ht = new Object();

    for (var z in ht) {
      dup_ht[z] = ht[z];
      dup_ht[z].incrRefCount();
    }
    dup_ptr.ptr(dup_ht);
    dup_ptr.obj_type = dct.interp.dict_obj_type;
  },

  /* ==================== updateString ===================================== */
  updateString: function(obj_ptr) {
    var dct = this;
    var i;
    var buf_len;
    var real_length;
    var str_rep;
    var p;
    var quoting_type;
    var ht;
    var objc = 0;
    var objv;

    /* Turn the hash table into a flat vector of RaplObjects. */
    ht = obj_ptr.ptr();
    objv = new Array();
    i = 0;
    for (var z in ht) {
        objv.push(z);
        objv.push(ht[z]);
	objc += 2;
    }
    /* (Over) Estimate the space needed. */
    quoting_type = new Array();
    buf_len = 0;
    for (i = 0; i < objc; i++) {
      var len;

      if (typeof objv[i] == "string") {
        str_rep = objv[i];
        len = str_rep.length;
      } else {
        str_rep = objv[i].getString();
        len = objv[i].getStringLength();
      }
      quoting_type.push(dct.interp.list_obj_type.listElementQuotingType(str_rep, len));
      switch (quoting_type[i]) {
      case dct.interp.list_obj_type.LIST_ELEM_STR_SIMPLE:
        buf_len += len;
        break;
      case dct.interp.list_obj_type.LIST_ELEM_STR_BRACE:
        buf_len += len + 2;
        break;
     case dct.interp.list_obj_type.LIST_ELEM_STR_QUOTE:
        buf_len += len * 2;
        break;
      }
      buf_len++;               /* elements separator. */
    }
    buf_len++;

    /* Generate the string rep. */
    p = "";
    real_length = 0;
    for (i = 0; i < objc; i++) {
      var len;
      var qlen = new Array();
      var q;

      if (typeof objv[i] == "string") {
        str_rep = objv[i];
        len = str_rep.length;
      } else {
        str_rep = objv[i].getString();
        len = objv[i].getStringLength();
      }
      switch (quoting_type[i]) {
      case dct.interp.list_obj_type.LIST_ELEM_STR_SIMPLE:
        p += str_rep;
        real_length += len;
        break;
      case dct.interp.list_obj_type.LIST_ELEM_STR_BRACE:
	p += '{'+ str_rep+'}';
	real_length += len + 2;
        break;
      case dct.interp.list_obj_type.LIST_ELEM_STR_QUOTE:
	q = dct.interp.list_obj_type.backslashQuoteString(str_rep, len, qlen);
	p += q;
	real_length += qlen[0];
        break;
      }
      /* Add a separating space */
      if (i + 1 != objc) {
        p += ' ';
        real_length++;
      }
    }
    p += '\0';                  /* nul term. */
    obj_ptr.bytes = p;
    obj_ptr.len = real_length;
  },

  /* ==================== addElement ===================================== */
  /* Add an element to a dict. obj_ptr must be of the "dict" type.
   * The higer-level exported function is dictAddElement().
   * If an element with the specified key already exists, the value
   * associated is replaced with the new one.
   *
   * if value_obj_ptr == null, the key is instead removed if it exists. 
   */
  addElement: function(obj_ptr, key_obj_ptr, value_obj_ptr) {
    var dct = this;
    var ht = obj_ptr.ptr ();

    if (value_obj_ptr == null) {  /* unset */
        return key_obj_ptr.deleteHashEntry(ht, key_obj_ptr);
    }
    key_obj_ptr.incrRefCount();
    value_obj_ptr.incrRefCount();
    if (key_obj_ptr.addHashEntry(ht, key_obj_ptr, value_obj_ptr) != dct.OK) {
//      var he = key_obj_ptr.findHashEntry(ht, key_obj_ptr);

//      key_obj_ptr.decrRefCount();
//      he.decrRefCount();
    }
    return dct.OK;
  },

  /* ==================== dictAddElement ===================================== */
  dictAddElement: function(obj_ptr, key_obj_ptr, value_obj_ptr) {
    var dct = this;
    var ret_code;

    dct.interp.panic(obj_ptr.isShared(), "dictAddElement called with shared object");
    if (obj_ptr.obj_type != dct.interp.dict_obj_type) {
      if (dct.setFromAny(obj_ptr) != dct.OK) {
        return dct.ERROR;
      }
    }
    ret_code = dct.addElement(obj_ptr, key_obj_ptr, value_obj_ptr);
    obj_ptr.invalidateStringRep();
    return ret_code;
  },

  /* ==================== newDictObj ===================================== */
  newDictObj: function(elements, len) {
    var dct = this;
    var obj_ptr;
    var i;

    dct.interp.panic(len % 2, "newDictObj() 'len' argument must be even");
    obj_ptr = dct.interp.default_obj.newObj();
    obj_ptr.obj_type = dct.interp.dict_obj_type;
    obj_ptr.bytes = null;
    obj_ptr.ptr(new Object());
    for (i = 0; i < len; i += 2) {
      dct.addElement(obj_ptr, elements[i], elements[i + 1]);
    }
    return obj_ptr;
  },

  /* ==================== dictKey ===================================== */
  /* Return the value associated to the specified dict key
   * Note: Returns dct.OK if OK, dct.ERROR if entry not found or -1 if can't create dict value
   */

  dictKey: function(dict_ptr, key_ptr, obj_ptr_ptr, flags) {
    var dct = this;
    var he;
    var ht;

    if (dict_ptr.obj_type != dct.interp.dict_obj_type) {
      if (dct.setFromAny(dict_ptr) != dct.OK) {
        return -1;
      }
    }
    ht = dict_ptr.ptr();
    if ((he = dict_ptr.findHashEntry(ht, key_ptr)) == null) {
      if (flags & dct.FUNCTION_FLAGS_LEAVE_ERR_MSG) {
        dct.interp.setResultFormatted("key \"%#s\" not found in dictionary", key_ptr);
      }
      return dct.ERROR;
    }
    obj_ptr_ptr[0] = he;
    return dct.OK;
  },

  /* ==================== dictPairs ===================================== */
  dictPairs: function(dict_ptr, obj_ptr_ptr, flags) {
    var dct = this;
    var ht;
    var he;
    var objv;
    var i;

    if (dict_ptr.obj_type != dct.interp.dict_obj_type) {
      if (dcit_prt.setFromAny(dict_ptr) != dct.OK) {
        return dct.ERROR;
      }
    }
    ht = dict_ptr.ptr();

    /* Turn the hash table into a flat vector of RaplObjects. */
    objv = new Array();
    i = 0;
    for (var z in ht) {
      objv.push(z);
      objv.push(ht[z]);
    }
    len[0] = i;
    obj_ptr_ptr[0] = objv;
    return dct.OK;
  },

  /* ==================== dictKeysVector ===================================== */
  dictKeysVector: function(dict_ptr, keyv, obj_ptr_ptr, flags) {
    var dct = this;
    var i;

    if (keyv.length == 0) {
      ob_ptr_ptr[0] = dict_ptr;
      return dct.OK;
    }
    for (i = 0; i < keyv.length; i++) {
      var obj_ptr = new Array();

      if (dct.dictKey(dict_ptr, keyv[i], obj_ptr, flags) != dct.OK) {
        return dct.ERROR;
      }
      dict_ptr = obj_ptr[0];
    }
    obj_ptr_ptr[0] = dict_ptr;
    return dct.OK;
  },

  /* ==================== setDictKeysVector ===================================== */
  /* Modify the dict stored into the variable named 'var_name_ptr'
   * setting the element specified by the 'keyc' keys objects in 'result_ptr',
   * with the new value of the element 'new_obj_ptr'.
   *
   * If new_obj_ptr == null the operation is to remove the given key
   * from the dictionary.
   *
   * If flags & dct.FUNCTION_FLAGS_LEAVE_ERR_MSG, then failure to remove the key is considered an error
   * and dct.ERROR is returned. Otherwise it is ignored and dct.OK is returned.
   */
  setDictKeysVector: function(var_name_ptr, keyv, keyc, new_obj_ptr, flags) {
    var dct = this;
    var var_obj_ptr;
    var obj_ptr;
    var dict_obj_ptr;
    var shared;
    var i;
    var err = false;
    var my_obj_ptr;

    var_obj_ptr = dct.interp.variable_obj_type.getVariable(var_name_ptr, new_obj_ptr == null ? dct.FUNCTION_FLAGS_LEAVE_ERR_MSG : dct.FUNCTION_FLAGS_NONE);
    obj_ptr = var_obj_ptr;
    if (obj_ptr == null) {
      if (new_obj_ptr == null) { /* Cannot remove a key from non existing var */
        return dct.ERROR;
      }
      var_obj_ptr = dct.newDictObj(null, 0);
      obj_ptr = var_obj_ptr;
      if (dct.interp.variable_obj_type.setVariable(var_name_ptr, obj_ptr) != dct.OK) {
        var_obj_ptr.freeNewObj();
        return dct.ERROR;
      }
    }
    if ((shared = obj_ptr.isShared())) {
      var_obj_ptr = obj_ptr.duplicateObj();
      objPtr = var_obj_ptr;
    }
    for (i = 0; i < keyc - 1; i++) {
      dict_obj_ptr = obj_ptr;

      /* Check if it's a valid dictionary */
      if (dict_obj_ptr.obj_type != dct.interp.dict_obj_type) {
        if (dct.setFromAny(dict_obj_ptr) != dct.OK) {
          err = true;
	  break;
        }
      }
      /* Check if the given key exists. */
      dict_obj_ptr.invalidateStringRep();
      if (dct.dictKey(dict_obj_ptr, keyv[i], obj_ptr, new_obj_ptr ? dct.FUNCTION_FLAGS_NONE : dct.FUNCTION_FLAGS_LEAVE_ERR_MSG) == dct.OK) {
        /* This key exists at the current level.
         * Make sure it's not shared!. 
	 */
        if (obj_ptr.isShared()) {
          obj_ptr = obj_ptr.duplicateObj();
          dct.addElement(dict_obj_ptr, keyv[i], obj_ptr);
        }
      } else {
        /* Key not found. If it's an [unset] operation
         * this is an error. Only the last key may not
         * exist. 
	 */
        if (new_obj_ptr == null) {
          err = true;
	  break;
        }
        /* Otherwise set an empty dictionary
         * as key's value. 
	 */
        obj_ptr = dct.newDictObj(null, 0);
        dct.addElement(dict_obj_ptr, keyv[i], obj_ptr);
      }
    }
    /* Note error on unset with missing last key is OK */
    if (keyc == 1) {
      my_obj_ptr = keyv;
    } else {
      my_obj_ptr = keyv[keyc - 1];
    }
    if (dct.dictAddElement(obj_ptr, my_obj_ptr, new_obj_ptr) != dct.OK) {
      if (new_obj_ptr || (flags & dct.FUNCTION_FLAGS_LEAVE_ERR_MSG)) {
        err = true;
      }
    }
    if (!err) {
      obj_ptr.invalidateStringRep();
      var_obj_ptr.invalidateStringRep();
      if (dct.interp.variable_obj_type.setVariable(var_name_ptr, var_obj_ptr) != dct.OK) {
        err = true;
      }
    }
    if (!err) {
      dct.interp.setResult(var_obj_ptr);
      return dct.OK;
    }
    if (shared) {
      var_obj_ptr.freeNewObj();
    }
    return dct.ERROR;
  },

  /* ==================== expandArrayVariable ================================== */
  /*
   * Expands the array variable and returns the result, or null on error.
   *
   * If array_obj.FUNCTION_FLAGS_UNSHARED is set and the dictionary is shared,
   * it will be duplicated
   * and stored back to the variable before expansion.
   */
  expandArrayVariable: function(var_obj_ptr, key_obj_ptr, flags) {
    var dct = this;
    var dict_obj_ptr;
    var res_obj_ptr = new Array();
    var ret;

    dict_obj_ptr = dct.interp.variable_obj_type.getVariable(var_obj_ptr, dct.FUNCTION_FLAGS_LEAVE_ERR_MSG);
    if (!dict_obj_ptr) {
      return null;
    }
    ret = dct.interp.dict_obj_type.dictKey(dict_obj_ptr, key_obj_ptr, res_obj_ptr, dct.FUNCTION_FLAGS_NONE);
    res_obj_ptr = res_obj_ptr[0];
    if (ret != dct.OK) {
      res_obj_ptr = null;
      if (ret < 0) {
        dct.interp.setResultFormatted("can't read \"%#s(%#s)\": variable isn't array", var_obj_ptr, key_obj_ptr);
      } else {
        dct.interp.setResultFormatted("can't read \"%#s(%#s)\": no such element in array", var_obj_ptr, key_obj_ptr);
      }
    } else {
      if ((flags & dct.FUNCTION_FLAGS_UNSHARED) && dict_obj_ptr.isShared()) {
        dict_obj_ptr = dict_obj_ptr.duplicateObj();
        if (dct.interp.variable_obj_type.setVariable(var_obj_ptr, dict_obj_ptr) != dct.OK) {
          /* This can probably never happen */
          dct.interp.panic(1, "setVariable failed for FUNCTION_FLAGS_UNSHARED");
        }
        /* We know that the key exists. Get the result in the now-unshared dictionary */
        dct.interp.dict_obj_type.dictKey(dict_obj_ptr, key_obj_ptr, res_obj_ptr, dct.FUNCTION_FLAGS_NONE);
      }
    }
    return res_obj_ptr;
  },

});

DictObjType.prototype.constructor = DictObjType;

R.DictObjType = DictObjType;

}, "0.0.1", {});