Home Reference Source

src/stdlib/StringPrototype.js

'use strict';

const EasyObjectValue = require('../values/EasyObjectValue');
const CompletionRecord = require('../CompletionRecord');
const EmptyValue = require('../values/EmptyValue');
const ArrayValue = require('../values/ArrayValue');
const _g = require('../GenDash');

function wrapStringPrototype(name) {
	let fx = String.prototype[name];
	let genfx = function *(thiz, args, s) {
		if ( thiz instanceof EmptyValue ) {
			return yield CompletionRecord.makeTypeError(s.realm, 'called String function on null or undefined?');
		}
		let sv = yield * thiz.toStringValue(s.realm);
		var argz = new Array(args.length);
		for ( let i = 0; i < args.length; ++i ) {
			argz[i] = args[i].toNative();
		}

		let result = fx.apply(sv.toNative(), argz);

		if ( Array.isArray(result) ) {
			var vals = new Array(result.length);
			for ( let i = 0; i < vals.length; ++i ) {
				vals[i] = s.realm.fromNative(result[i]);
			}
			return ArrayValue.make(vals, s.realm);
		} else {
			let nv = s.realm.fromNative(result);
			return nv;
		}
	};
	genfx.esperLength = fx.length;
	return genfx;
}

class StringPrototype extends EasyObjectValue {
	static get length$cew() { return StringPrototype.fromNative(0); }

	static *valueOf$e(thiz) {
		if ( thiz.specTypeName === 'string' ) return thiz;
		if ( thiz.specTypeName === 'object' ) {
			let pv = thiz.primativeValue;
			if ( pv.specTypeName == 'string' ) return pv;
		}
		throw new TypeError('Couldnt get there.');
	}

	static *concat$e(thiz, args, realm) {
		let base = yield * thiz.toStringNative();
		let realArgs = yield * _g.map(args, function*(v) { return yield * v.toStringNative(); });
		let out = String.prototype.concat.apply(base, realArgs);
		return realm.fromNative(out);
	}

	//TODO: Replacement arg can be a regex.
	static *replace$e(thiz, args, realm) {
		let base = yield * thiz.toStringNative();
		let realArgs = yield * _g.map(args, function*(v) { return yield * v.toStringNative(); });
		let out = String.prototype.replace.apply(base, realArgs);
		return realm.fromNative(out);
	}

	static *padEnd$e(thiz, args, realm) {
		let base = yield * thiz.toStringNative();
		if ( args.length < 1 ) return thiz;
		let length = yield * args[0].toIntNative();
		let hasPad = args.length > 1 && args[1].jsTypeName != 'undefined';
		let pad = hasPad ? yield * args[1].toStringNative() : ' ';
		return realm.fromNative(strPad(base, length, pad, false));
	}

	static *padStart$e(thiz, args, realm) {
		let base = yield * thiz.toStringNative();
		if ( args.length < 1 ) return thiz;
		let length = yield * args[0].toIntNative();
		let hasPad = args.length > 1 && args[1].jsTypeName != 'undefined';
		let pad = hasPad ? yield * args[1].toStringNative() : ' ';
		return realm.fromNative(strPad(base, length, pad, true));
	}

	static *toString$e(thiz) {
		return yield * StringPrototype.valueOf$e(thiz);
	}
}

function strPad(base, length, pad, left) {
	if ( length <= base.length ) return base;
	let extra = length - base.length;
	let padding = new Array(1 + Math.ceil(extra / pad.length)).join(pad).substr(0, extra);
	return left ? padding + base : base + padding;

}

StringPrototype.prototype.wellKnownName = '%StringProtoype%';
StringPrototype.prototype.clazz = 'String';

StringPrototype.charAt$e = wrapStringPrototype('charAt');
StringPrototype.charCodeAt$e = wrapStringPrototype('charCodeAt');
StringPrototype.substring$e = wrapStringPrototype('substring');
StringPrototype.substr$e = wrapStringPrototype('substr');
StringPrototype.split$e = wrapStringPrototype('split');
StringPrototype.slice$e = wrapStringPrototype('slice');
StringPrototype.lastIndexOf$e = wrapStringPrototype('lastIndexOf');
StringPrototype.indexOf$e = wrapStringPrototype('indexOf');
StringPrototype.search$e = wrapStringPrototype('search');
StringPrototype.trim$e = wrapStringPrototype('trim');
StringPrototype.toUpperCase$e = wrapStringPrototype('toUpperCase');
StringPrototype.toLocaleUpperCase$e = wrapStringPrototype('toLocaleUpperCase');
StringPrototype.toLowerCase$e = wrapStringPrototype('toLowerCase');
StringPrototype.toLocaleLowerCase$e = wrapStringPrototype('toLocaleLowerCase');
StringPrototype.localeCompare$e = wrapStringPrototype('localeCompare');


module.exports = StringPrototype;