Home Reference Source

src/values/ArrayValue.js

'use strict';


const PrimitiveValue = require('./PrimitiveValue');
const ObjectValue = require('./ObjectValue');
const Value = require('../Value');
const GenDash = require('../GenDash');
let NumberValue;


class ArrayValue extends ObjectValue {

	constructor(realm) {
		super(realm, realm.ArrayPrototype);
	}

	*get(name, realm) {
		return yield * super.get(name, realm);
	}

	adjustLength(name, value) {
		if ( name == 'length' && this.properties.length ) {
			//TODO: 15.4.5.2 specifies more complex behavior here.
			let target = GenDash.syncGenHelper(value.toIntNative());
			let length = this.getLengthSync();
			if ( target < length ) {
				for ( let i = length - 1; i >= target; --i ) {
					delete this.properties[i];
				}
			}
		}

		if ( !isNaN(parseInt(name)) ) {
			let length = this.getLengthSync();
			if ( name >= length ) {
				this.properties.length.value = Value.fromNative(name + 1);
			}
		}
	}

	getLengthSync() {
		return this.properties.length.value.native;
	}

	set(name, v) {
		this.adjustLength(name, v);
		return super.set(name, v);
	}

	setImmediate(name, v) {
		this.adjustLength(name, v);
		return super.setImmediate(name, v);
	}


	toNative() {
		let out = new Array(this.getLengthSync());
		for ( let i of Object.keys(this.properties)) {
			if ( i === 'length' ) continue;
			let po = this.properties[i];
			if ( po && po.value ) {
				if ( !po.direct ) {
					Object.defineProperty(out, i, {
						enumerable: po.enumerable,
						writable: po.writable,
						configurable: po.configurable,
						value: po.value.toNative()
					});
				} else {
					out[i] = po.value.toNative();
				}
			}
		}
		return out;
	}

	toJS() {
		let out = new Array(this.getLengthSync());
		for ( let i of Object.keys(this.properties)) {
			if ( i === 'length' ) continue;
			let po = this.properties[i];
			out[i] = po.value.toJS();
		}
		return out;
	}

	static make(vals, realm) {

		let av = new ArrayValue(realm);

		av.setImmediate('length', Value.fromNative(0));
		av.properties.length.enumerable = false;

		for ( let i = 0; i < vals.length; ++i ) {
			let v = vals[i];
			if ( !(v instanceof Value) ) v = realm.fromNative(v);
			av.setImmediate(i, v);
		}
		return av;
	}

	get debugString() {
		if ( !this.properties.length ) return super.debugString;
		let length = this.properties.length.value.native;

		let loop = Math.min(length, 20);
		let r = new Array(loop);
		for ( let i = 0; i < loop; ++i ) {
			let po = this.properties[i];
			if ( po && po.value ) r[i] = po.value.debugString;
			else r[i] = '';
		}
		return '[' + r.join(', ') + ( loop < length ? '...' : '' ) + ']';
	}
}

ArrayValue.prototype.clazz = 'Array';

module.exports = ArrayValue;

NumberValue = require('./NumberValue');