adder-script
Version:
Python like language to execute untrusted codes in browsers and Node.js.
219 lines (181 loc) • 5.75 kB
JavaScript
"use strict";
/**
* A built-in dictionary object.
*
* Author: Ronen Ness.
* Since: 2016
*/
// include jsface for classes
var jsface = require("./../dependencies/jsface"),
Class = jsface.Class,
extend = jsface.extend;
// include errors
var Errors = require("./../errors");
// include variable
var Variable = require("./variable");
// builtin function
var BuiltinFunc = require("./builtin_func");
// require misc utils
var Utils = require("./../utils");
// include basic object type
var _Object = require("./object");
// get list object
var List = require('./list');
// make sure dictionary length is valid
function validate_len(dict) {
if (Object.keys(dict._dict).length > dict._context._interpreter._flags.maxContainersLen) {
throw new Errors.ExceedMemoryLimit("Dictionary exceeded maximum container length (" + dict._context._interpreter._flags.maxContainersLen + ")");
}
}
// all the api functions of the set
// remember - everything in a set is stored as native js and not as Variable object
var apiFuncs = {
// clone the set
clone: function()
{
// create the dictionary to return
var ret = new Dict(this._context);
// add all values
for (var key in this._dict) {
ret.set(Variable.makeVariables(this._context, key), this._dict[key]);
}
// return the new dictionary
return ret;
},
// return a list of keys
keys: function()
{
return new List(this._context, Object.keys(this._dict));
},
// return a list of values
values: function()
{
var ret = [];
for (var key in this._dict) {
ret.push(this._dict[key]);
}
return ret;
},
// return how many keys in dictionary
len: function()
{
return Object.keys(this._dict).length;
},
// return if dictionary is empty
empty: function()
{
return this.len() === 0;
},
// set value
set: function(key, value)
{
// validate key type
if (!key.isSimple) {
throw new Errors.RuntimeError("Invalid key type '" + key.type + "'. Dictionary keys can only be strings, numbers, booleans or none.");
}
// add to dictionary
this._dict[key._value] = value;
validate_len(this);
// update memory usage
this._context._interpreter.updateMemoryUsage(value._estimatedSize + key.length);
},
// get value
get: function(key, defaultVal)
{
return this._dict[key._value] || defaultVal;
},
// remove value from dictionary
remove: function(key)
{
delete this._dict[key._value];
},
// clear the dictionary
clear: function()
{
this._dict = {};
},
// return true if value exists in the dictionary
has: function(key)
{
return this._dict[key._value] !== undefined;
},
// extend set with another dictionary
extend: function(other)
{
// make sure got a dict to extend
if (other.type !== "dict") {
throw new Errors.RuntimeError("Dict 'extend()' expecting another dictionary as param ('" + other.type + "' given).");
}
// extend the dictionary
other = other._value;
for (var key in other._dict) {
this._dict[key] = other._dict[key];
}
},
}
// Dictionary class
var Dict = Class(_Object, {
// Object constructor
// @param context - context of program currently executed.
// @param startingDict - optional dictionary to put as starting data
constructor: function(context, startingDict)
{
// call parent constructor
Dict.$super.call(this, context);
// create the dictionary
this._dict = startingDict || {}
},
// iterate over object components
forEach: function(callback, obj) {
for (var key in this._dict) {
if (callback.call(obj, key) === false) {
return;
}
}
},
// dictionary api
api: {
clone: BuiltinFunc.create(apiFuncs.clone, 0, 0, false),
keys: BuiltinFunc.create(apiFuncs.keys, 0, 0, false),
values: BuiltinFunc.create(apiFuncs.values, 0, 0, false),
len: BuiltinFunc.create(apiFuncs.len, 0, 0, false),
_set: BuiltinFunc.create(apiFuncs.set, 2, 0, false),
_get: BuiltinFunc.create(apiFuncs.get, 1, 1, false),
remove: BuiltinFunc.create(apiFuncs.remove, 1, 0, false),
clear: BuiltinFunc.create(apiFuncs.clear, 0, 0, false),
empty: BuiltinFunc.create(apiFuncs.empty, 0, 0, false),
has: BuiltinFunc.create(apiFuncs.has, 1, 0, false),
extend: BuiltinFunc.create(apiFuncs.extend, 1, 0, false),
},
// convert to string
toString: function()
{
var ret = []
for (var key in this._dict) {
ret.push('"' + key + '": ' + this._dict[key].toString());
}
return ret.join(",");
},
// convert to repr
toRepr: function()
{
return "dict(" + this.toString() + ")";
},
// convert to a native javascript object
toNativeJs: function()
{
var ret = {};
for (var key in this._dict) {
ret[key] = this._dict[key].toNativeJs();
}
return ret;
},
// object identifier
name: "dict",
// object type
type: "dict",
});
// init set builtint api
_Object.initBuiltinApi(Dict);
// export the Dict class
module.exports = Dict;