Added Array class. Moved conversions to MetaData.

This commit is contained in:
rogerl%netscape.com 2002-10-21 03:00:21 +00:00
Родитель 2751ea016b
Коммит 7965c7bfe2
17 изменённых файлов: 1417 добавлений и 433 удалений

Просмотреть файл

@ -155,6 +155,9 @@ namespace MetaData {
for (std::vector<Frame *>::iterator fi = mFrameList.begin(), fend = mFrameList.end(); (fi != fend); fi++) {
GCMARKOBJECT(*fi);
}
for (std::vector<RegExpInstance *>::iterator ri = mRegExpList.begin(), rend = mRegExpList.end(); (ri != rend); ri++) {
GCMARKOBJECT(*ri);
}
}
}

Просмотреть файл

@ -148,12 +148,13 @@ public:
// XXX We lose StringAtom here (and is it safe to stash the address of a StringAtom?)
// - is there any way of keeping StringAtoms themselves in a bytecodeContainer?
void addRegExp(RegExpInstance *x, size_t pos) { emitOp(eRegExp, pos); addPointer(x); }
void addRegExp(RegExpInstance *x, size_t pos) { emitOp(eRegExp, pos); mRegExpList.push_back(x); addShort(mRegExpList.size() - 1); }
typedef std::vector<uint8> CodeBuffer;
CodeBuffer mBuffer;
std::vector<RegExpInstance *> mRegExpList; // gc tracking
std::vector<Multiname *> mMultinameList; // gc tracking
std::vector<Frame *> mFrameList; // gc tracking

Просмотреть файл

@ -146,7 +146,7 @@ static int readEvalPrint(FILE *in)
metadata->ValidateStmtList(parsedStatements);
js2val rval = metadata->ExecuteStmtList(RunPhase, parsedStatements);
if (!JS2VAL_IS_VOID(rval))
stdOut << *metadata->engine->toString(rval) << '\n';
stdOut << *metadata->toString(rval) << '\n';
}
}
clear(buffer);
@ -204,7 +204,7 @@ using namespace MetaData;
js2val print(JS2Metadata *meta, const js2val thisValue, js2val argv[], uint32 argc)
{
for (uint32 i = 0; i < argc; i++) {
stdOut << *metadata->engine->toString(argv[i]) << '\n';
stdOut << *metadata->toString(argv[i]) << '\n';
}
return JS2VAL_UNDEFINED;
}
@ -212,7 +212,7 @@ js2val print(JS2Metadata *meta, const js2val thisValue, js2val argv[], uint32 ar
js2val load(JS2Metadata *meta, const js2val thisValue, js2val argv[], uint32 argc)
{
if (argc)
return meta->readEvalFile(*meta->engine->toString(argv[0]));
return meta->readEvalFile(*meta->toString(argv[0]));
else
return JS2VAL_UNDEFINED;
}

852
js2/src/js2array.cpp Normal file
Просмотреть файл

@ -0,0 +1,852 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the JavaScript 2 Prototype.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
#ifdef _WIN32
// Turn off warnings about identifiers too long in browser information
#pragma warning(disable: 4786)
#pragma warning(disable: 4711)
#pragma warning(disable: 4710)
#endif
#include <algorithm>
#include <list>
#include <map>
#include "world.h"
#include "utilities.h"
#include "js2value.h"
#include "numerics.h"
#include "reader.h"
#include "parser.h"
#include "regexp.h"
#include "js2engine.h"
#include "bytecodecontainer.h"
#include "js2metadata.h"
namespace JavaScript {
namespace MetaData {
uint32 getLength(JS2Metadata *meta, JS2Object *obj)
{
Multiname mn(meta->engine->length_StringAtom, meta->publicNamespace);
LookupKind lookup(false, NULL);
uint32 length = 0;
js2val result;
if (meta->readDynamicProperty(obj, &mn, &lookup, RunPhase, &result))
length = toUInt32(meta->toInteger(result));
return length;
}
js2val setLength(JS2Metadata *meta, JS2Object *obj, uint32 length)
{
Multiname mn(meta->engine->length_StringAtom, meta->publicNamespace);
js2val result = meta->engine->allocNumber(length);
meta->writeDynamicProperty(obj, &mn, true, result, RunPhase);
return result;
}
js2val Array_Constructor(JS2Metadata *meta, const js2val /*thisValue*/, js2val *argv, uint32 argc)
{
js2val thatValue = OBJECT_TO_JS2VAL(new ArrayInstance(meta->arrayClass));
ArrayInstance *arrInst = checked_cast<ArrayInstance *>(JS2VAL_TO_OBJECT(thatValue));
if (argc > 0) {
if (argc == 1) {
if (JS2VAL_IS_NUMBER(argv[0])) {
uint32 i = (uint32)(meta->toFloat64(argv[0]));
if (i == meta->toFloat64(argv[0]))
setLength(meta, arrInst, i);
else
meta->reportError(Exception::rangeError, "Array length too large", meta->engine->errorPos());
}
else {
setLength(meta, arrInst, 1);
Multiname mn(meta->toString((int32)0), meta->publicNamespace);
meta->writeDynamicProperty(arrInst, &mn, true, argv[0], RunPhase);
delete mn.name;
}
}
else {
Multiname mn(NULL, meta->publicNamespace);
setLength(meta, arrInst, argc);
for (uint32 i = 0; i < argc; i++) {
mn.name = meta->toString(i);
meta->writeDynamicProperty(arrInst, &mn, true, argv[i], RunPhase);
delete mn.name;
}
}
}
return thatValue;
}
static js2val Array_toString(JS2Metadata *meta, const js2val thisValue, js2val * /*argv*/, uint32 /*argc*/)
{
if (meta->objectType(thisValue) != meta->arrayClass)
meta->reportError(Exception::typeError, "Array.prototype.toString called on a non Array", meta->engine->errorPos());
ArrayInstance *arrInst = checked_cast<ArrayInstance *>(JS2VAL_TO_OBJECT(thisValue));
uint32 length = getLength(meta, arrInst);
if (length == 0)
return STRING_TO_JS2VAL(meta->engine->allocString(meta->engine->Empty_StringAtom));
else {
Multiname mn(NULL, meta->publicNamespace);
LookupKind lookup(false, NULL);
js2val result;
String *s = new String();
for (uint32 i = 0; i < length; i++) {
mn.name = meta->toString(i);
if (meta->readDynamicProperty(arrInst, &mn, &lookup, RunPhase, &result)
&& !JS2VAL_IS_UNDEFINED(result))
s->append(*meta->toString(result));
if (i < (length - 1))
s->append(widenCString(","));
delete mn.name;
}
result = meta->engine->allocString(s);
delete s;
return result;
}
}
static js2val Array_toSource(JS2Metadata *meta, const js2val thisValue, js2val * /*argv*/, uint32 /*argc*/)
{
if (meta->objectType(thisValue) != meta->arrayClass)
meta->reportError(Exception::typeError, "Array.prototype.toString called on a non Array", meta->engine->errorPos());
ArrayInstance *arrInst = checked_cast<ArrayInstance *>(JS2VAL_TO_OBJECT(thisValue));
uint32 length = getLength(meta, arrInst);
if (length == 0)
return meta->engine->allocString("[]");
else {
Multiname mn(NULL, meta->publicNamespace);
LookupKind lookup(false, NULL);
js2val result;
String *s = new String();
for (uint32 i = 0; i < length; i++) {
mn.name = meta->toString(i);
if (meta->readDynamicProperty(arrInst, &mn, &lookup, RunPhase, &result)
&& !JS2VAL_IS_UNDEFINED(result))
s->append(*meta->toString(result));
if (i < (length - 1))
s->append(widenCString(","));
delete mn.name;
}
s->append(widenCString("]"));
result = meta->engine->allocString(s);
delete s;
return result;
}
}
static js2val Array_push(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc)
{
ASSERT(JS2VAL_IS_OBJECT(thisValue));
JS2Object *thisObj = JS2VAL_TO_OBJECT(thisValue);
uint32 length = getLength(meta, thisObj);
Multiname mn(NULL, meta->publicNamespace);
for (uint32 i = 0; i < argc; i++) {
mn.name = meta->toString(i);
meta->writeDynamicProperty(thisObj, &mn, true, argv[i], RunPhase);
delete mn.name;
}
return setLength(meta, thisObj, length + argc);
}
static js2val Array_pop(JS2Metadata *meta, const js2val thisValue, js2val * /*argv*/, uint32 /*argc*/)
{
ASSERT(JS2VAL_IS_OBJECT(thisValue));
JS2Object *thisObj = JS2VAL_TO_OBJECT(thisValue);
uint32 length = getLength(meta, thisObj);
if (length > 0) {
Multiname mn(meta->toString(length - 1), meta->publicNamespace);
LookupKind lookup(false, NULL);
const String *id = meta->toString(length - 1);
js2val result = JS2VAL_UNDEFINED;
bool deleteResult;
meta->readDynamicProperty(thisObj, &mn, &lookup, RunPhase, &result);
meta->deleteProperty(thisValue, &mn, &lookup, RunPhase, &deleteResult);
setLength(meta, thisObj, length - 1);
delete mn.name;
return result;
}
else
return JS2VAL_UNDEFINED;
}
js2val Array_concat(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc)
{
js2val E = thisValue;
js2val result = OBJECT_TO_JS2VAL(new ArrayInstance(meta->arrayClass));
ArrayInstance *A = checked_cast<ArrayInstance *>(JS2VAL_TO_OBJECT(result));
uint32 n = 0;
uint32 i = 0;
Multiname mn(NULL, meta->publicNamespace);
LookupKind lookup(false, NULL);
do {
if (meta->objectType(E) != meta->arrayClass) {
mn.name = meta->toString(n++);
meta->writeDynamicProperty(A, &mn, true, E, RunPhase);
delete mn.name;
}
else {
ASSERT(JS2VAL_IS_OBJECT(thisValue));
JS2Object *arrObj = JS2VAL_TO_OBJECT(E);
uint32 length = getLength(meta, arrObj);
for (uint32 k = 0; k < length; k++) {
mn.name = meta->toString(k);
js2val rval = JS2VAL_UNDEFINED;
meta->readDynamicProperty(arrObj, &mn, &lookup, RunPhase, &rval);
delete mn.name;
mn.name = meta->toString(n++);
meta->writeDynamicProperty(A, &mn, true, rval, RunPhase);
delete mn.name;
}
}
E = argv[i++];
} while (i <= argc);
return result;
}
static js2val Array_join(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc)
{
ASSERT(JS2VAL_IS_OBJECT(thisValue));
JS2Object *thisObj = JS2VAL_TO_OBJECT(thisValue);
uint32 length = getLength(meta, thisObj);
const String *separator;
if ((argc == 0) || JS2VAL_IS_UNDEFINED(argv[0]))
separator = new String(widenCString(","));
else
separator = meta->toString(argv[0]);
String *S = new String();
Multiname mn(NULL, meta->publicNamespace);
LookupKind lookup(false, NULL);
for (uint32 k = 0; k < length; k++) {
js2val result = JS2VAL_UNDEFINED;
mn.name = meta->toString(k);
meta->readDynamicProperty(thisObj, &mn, &lookup, RunPhase, &result);
if (!JS2VAL_IS_UNDEFINED(result) && !JS2VAL_IS_NULL(result))
*S += *meta->toString(result);
if (k < (length - 1))
*S += *separator;
delete mn.name;
}
return meta->engine->allocString(S);
}
static js2val Array_reverse(JS2Metadata *meta, const js2val thisValue, js2val * /*argv*/, uint32 /*argc*/)
{
ASSERT(JS2VAL_IS_OBJECT(thisValue));
JS2Object *thisObj = JS2VAL_TO_OBJECT(thisValue);
uint32 length = getLength(meta, thisObj);
Multiname mn1(NULL, meta->publicNamespace);
Multiname mn2(NULL, meta->publicNamespace);
LookupKind lookup(false, NULL);
uint32 halfway = length / 2;
for (uint32 k = 0; k < halfway; k++) {
bool deleteResult;
js2val result1 = JS2VAL_UNDEFINED;
js2val result2 = JS2VAL_UNDEFINED;
mn1.name = meta->toString(k);
mn2.name = meta->toString(length - k - 1);
if (meta->hasOwnProperty(thisObj, mn1.name)) {
if (meta->hasOwnProperty(thisObj, mn2.name)) {
meta->readDynamicProperty(thisObj, &mn1, &lookup, RunPhase, &result1);
meta->readDynamicProperty(thisObj, &mn2, &lookup, RunPhase, &result2);
meta->writeDynamicProperty(thisObj, &mn1, true, result2, RunPhase);
meta->writeDynamicProperty(thisObj, &mn2, true, result1, RunPhase);
}
else {
meta->readDynamicProperty(thisObj, &mn1, &lookup, RunPhase, &result1);
meta->writeDynamicProperty(thisObj, &mn2, true, result1, RunPhase);
meta->deleteProperty(thisValue, &mn1, &lookup, RunPhase, &deleteResult);
}
}
else {
if (meta->hasOwnProperty(thisObj, mn2.name)) {
meta->readDynamicProperty(thisObj, &mn2, &lookup, RunPhase, &result2);
meta->writeDynamicProperty(thisObj, &mn1, true, result2, RunPhase);
meta->deleteProperty(thisValue, &mn2, &lookup, RunPhase, &deleteResult);
}
else {
meta->deleteProperty(thisValue, &mn1, &lookup, RunPhase, &deleteResult);
meta->deleteProperty(thisValue, &mn2, &lookup, RunPhase, &deleteResult);
}
}
delete mn1.name;
delete mn2.name;
}
return thisValue;
}
static js2val Array_shift(JS2Metadata *meta, const js2val thisValue, js2val * /*argv*/, uint32 /*argc*/)
{
ASSERT(JS2VAL_IS_OBJECT(thisValue));
JS2Object *thisObj = JS2VAL_TO_OBJECT(thisValue);
uint32 length = getLength(meta, thisObj);
if (length == 0) {
setLength(meta, thisObj, 0);
return JS2VAL_UNDEFINED;
}
Multiname mn1(NULL, meta->publicNamespace);
Multiname mn2(NULL, meta->publicNamespace);
LookupKind lookup(false, NULL);
js2val result;
bool deleteResult;
mn1.name = meta->toString((int32)0);
meta->readDynamicProperty(thisObj, &mn1, &lookup, RunPhase, &result);
delete mn1.name;
for (uint32 k = 1; k < length; k++) {
mn1.name = meta->toString(k);
mn2.name = meta->toString(k - 1);
if (meta->hasOwnProperty(thisObj, mn1.name)) {
meta->readDynamicProperty(thisObj, &mn1, &lookup, RunPhase, &result);
meta->writeDynamicProperty(thisObj, &mn2, true, result, RunPhase);
}
else
meta->deleteProperty(thisValue, &mn2, &lookup, RunPhase, &deleteResult);
delete mn1.name;
delete mn2.name;
}
mn1.name = meta->toString(length - 1);
meta->deleteProperty(thisValue, &mn2, &lookup, RunPhase, &deleteResult);
delete mn1.name;
setLength(meta, thisObj, length - 1);
return result;
}
static js2val Array_slice(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc)
{
ASSERT(JS2VAL_IS_OBJECT(thisValue));
JS2Object *thisObj = JS2VAL_TO_OBJECT(thisValue);
js2val result = OBJECT_TO_JS2VAL(new ArrayInstance(meta->arrayClass));
ArrayInstance *A = checked_cast<ArrayInstance *>(JS2VAL_TO_OBJECT(result));
uint32 length = getLength(meta, thisObj);
uint32 start, end;
if (argc < 1)
start = 0;
else {
int32 arg0 = meta->toInteger(argv[0]);
if (arg0 < 0) {
arg0 += length;
if (arg0 < 0)
start = 0;
else
start = toUInt32(arg0);
}
else {
if (toUInt32(arg0) >= length) // cast ok since > 0
start = length;
else
start = toUInt32(arg0);
}
}
if (argc < 2)
end = length;
else {
int32 arg1 = meta->toInteger(argv[1]);
if (arg1 < 0) {
arg1 += length;
if (arg1 < 0)
end = 0;
else
end = toUInt32(arg1);
}
else {
if (toUInt32(arg1) >= length)
end = length;
else
end = toUInt32(arg1);
}
}
Multiname mn1(NULL, meta->publicNamespace);
Multiname mn2(NULL, meta->publicNamespace);
LookupKind lookup(false, NULL);
uint32 n = 0;
while (start < end) {
mn1.name = meta->toString(start);
if (meta->hasOwnProperty(thisObj, mn1.name)) {
js2val rval;
mn2.name = meta->toString(n);
meta->readDynamicProperty(thisObj, &mn1, &lookup, RunPhase, &rval);
meta->writeDynamicProperty(A, &mn2, true, rval, RunPhase);
delete mn2.name;
}
n++;
start++;
delete mn1.name;
}
setLength(meta, A, n);
return result;
}
typedef struct CompareArgs {
JS2Metadata *meta;
JS2Object *target;
} CompareArgs;
typedef struct QSortArgs {
js2val *vec;
js2val *pivot;
CompareArgs *arg;
} QSortArgs;
static int32 sort_compare(js2val *a, js2val *b, CompareArgs *arg);
static void
js_qsort_r(QSortArgs *qa, int lo, int hi)
{
js2val *pivot, *vec, *a, *b;
int i, j, lohi, hilo;
CompareArgs *arg;
pivot = qa->pivot;
vec = qa->vec;
arg = qa->arg;
while (lo < hi) {
i = lo;
j = hi;
a = vec + i;
*pivot = *a;
while (i < j) {
b = vec + j;
if (sort_compare(b, pivot, arg) >= 0) {
j--;
continue;
}
*a = *b;
while (sort_compare(a, pivot, arg) <= 0) {
i++;
a = vec + i;
if (i == j)
goto store_pivot;
}
*b = *a;
}
if (i > lo) {
store_pivot:
*a = *pivot;
}
if (i - lo < hi - i) {
lohi = i - 1;
if (lo < lohi)
js_qsort_r(qa, lo, lohi);
lo = i + 1;
} else {
hilo = i + 1;
if (hilo < hi)
js_qsort_r(qa, hilo, hi);
hi = i - 1;
}
}
}
static void js_qsort(js2val *vec, size_t nel, CompareArgs *arg)
{
js2val *pivot;
QSortArgs qa;
pivot = (js2val *)STD::malloc(nel);
qa.vec = vec;
qa.pivot = pivot;
qa.arg = arg;
js_qsort_r(&qa, 0, (int)(nel - 1));
STD::free(pivot);
}
static int32 sort_compare(js2val *a, js2val *b, CompareArgs *arg)
{
js2val av = *(const js2val *)a;
js2val bv = *(const js2val *)b;
CompareArgs *ca = (CompareArgs *) arg;
JS2Metadata *meta = ca->meta;
int32 result;
if (ca->target == NULL) {
if (JS2VAL_IS_UNDEFINED(av) || JS2VAL_IS_UNDEFINED(bv)) {
/* Put undefined properties at the end. */
result = (JS2VAL_IS_UNDEFINED(av)) ? 1 : -1;
}
else {
const String *astr = meta->toString(av);
const String *bstr = meta->toString(bv);
result = astr->compare(*bstr);
}
return result;
}
else {
js2val argv[2];
argv[0] = av;
argv[1] = bv;
js2val v = JS2VAL_UNDEFINED;// XXX = cx->invokeFunction(ca->target, kNullValue, argv, 2);
float64 f = meta->toFloat64(v);
if (JSDOUBLE_IS_NaN(f) || (f == 0))
result = 0;
else
if (f > 0)
result = 1;
else
result = -1;
return result;
}
}
static js2val Array_sort(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc)
{
CompareArgs ca;
ca.meta = meta;
ca.target = NULL;
if (argc > 0) {
if (!JS2VAL_IS_UNDEFINED(argv[0])) {
if (meta->objectType(argv[0]) != meta->functionClass)
meta->reportError(Exception::typeError, "sort needs a compare function", meta->engine->errorPos());
ca.target = JS2VAL_TO_OBJECT(argv[0]);
}
}
ASSERT(JS2VAL_IS_OBJECT(thisValue));
JS2Object *thisObj = JS2VAL_TO_OBJECT(thisValue);
uint32 length = getLength(meta, thisObj);
if (length > 0) {
uint32 i;
js2val *vec = new js2val[length];
Multiname mn(NULL, meta->publicNamespace);
LookupKind lookup(false, NULL);
for (i = 0; i < length; i++) {
mn.name = meta->toString(i);
meta->readDynamicProperty(thisObj, &mn, &lookup, RunPhase, &vec[i]);
delete mn.name;
}
js_qsort(vec, length, &ca);
for (i = 0; i < length; i++) {
mn.name = meta->toString(i);
meta->writeDynamicProperty(thisObj, &mn, true, vec[i], RunPhase);
delete mn.name;
}
delete[] mn.name;
}
return thisValue;
}
static js2val Array_splice(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc)
{
if (argc > 1) {
uint32 k;
ASSERT(JS2VAL_IS_OBJECT(thisValue));
JS2Object *thisObj = JS2VAL_TO_OBJECT(thisValue);
uint32 length = getLength(meta, thisObj);
js2val result = OBJECT_TO_JS2VAL(new ArrayInstance(meta->arrayClass));
ArrayInstance *A = checked_cast<ArrayInstance *>(JS2VAL_TO_OBJECT(result));
int32 arg0 = meta->toInteger(argv[0]);
uint32 start;
if (arg0 < 0) {
arg0 += length;
if (arg0 < 0)
start = 0;
else
start = toUInt32(arg0);
}
else {
if (toUInt32(arg0) >= length)
start = length;
else
start = toUInt32(arg0);
}
uint32 deleteCount;
int32 arg1 = meta->toInteger(argv[1]);
if (arg1 < 0)
deleteCount = 0;
else
if (toUInt32(arg1) >= (length - start))
deleteCount = length - start;
else
deleteCount = toUInt32(arg1);
Multiname mn1(NULL, meta->publicNamespace);
Multiname mn2(NULL, meta->publicNamespace);
LookupKind lookup(false, NULL);
for (k = 0; k < deleteCount; k++) {
mn1.name = meta->toString(start + k);
if (meta->hasOwnProperty(thisObj, mn1.name)) {
js2val rval;
mn2.name = meta->toString(k);
meta->readDynamicProperty(thisObj, &mn1, &lookup, RunPhase, &rval);
meta->writeDynamicProperty(A, &mn2, true, rval, RunPhase);
delete mn2.name;
}
delete mn1.name;
}
setLength(meta, A, deleteCount);
uint32 newItemCount = argc - 2;
if (newItemCount < deleteCount) {
bool deleteResult;
for (k = start; k < (length - deleteCount); k++) {
mn1.name = meta->toString(k + deleteCount);
mn2.name = meta->toString(k + newItemCount);
if (meta->hasOwnProperty(thisObj, mn1.name)) {
js2val rval;
meta->readDynamicProperty(thisObj, &mn1, &lookup, RunPhase, &rval);
meta->writeDynamicProperty(A, &mn2, true, rval, RunPhase);
}
else
meta->deleteProperty(thisValue, &mn2, &lookup, RunPhase, &deleteResult);
delete mn1.name;
delete mn2.name;
}
for (k = length; k > (length - deleteCount + newItemCount); k--) {
mn1.name = meta->toString(k - 1);
meta->deleteProperty(thisValue, &mn1, &lookup, RunPhase, &deleteResult);
delete mn1.name;
}
}
else {
if (newItemCount > deleteCount) {
for (k = length - deleteCount; k > start; k--) {
bool deleteResult;
mn1.name = meta->toString(k + deleteCount - 1);
mn1.name = meta->toString(k + newItemCount - 1);
if (meta->hasOwnProperty(thisObj, mn1.name)) {
js2val rval;
meta->readDynamicProperty(thisObj, &mn1, &lookup, RunPhase, &rval);
meta->writeDynamicProperty(A, &mn2, true, rval, RunPhase);
}
else
meta->deleteProperty(thisValue, &mn2, &lookup, RunPhase, &deleteResult);
delete mn1.name;
delete mn2.name;
}
}
}
k = start;
for (uint32 i = 2; i < argc; i++) {
mn1.name = meta->toString(k++);
meta->writeDynamicProperty(A, &mn2, true, argv[i], RunPhase);
delete mn1.name;
}
setLength(meta, thisObj, (length - deleteCount + newItemCount));
return result;
}
return JS2VAL_UNDEFINED;
}
static js2val Array_unshift(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc)
{
ASSERT(JS2VAL_IS_OBJECT(thisValue));
JS2Object *thisObj = JS2VAL_TO_OBJECT(thisValue);
uint32 length = getLength(meta, thisObj);
uint32 k;
Multiname mn1(NULL, meta->publicNamespace);
Multiname mn2(NULL, meta->publicNamespace);
LookupKind lookup(false, NULL);
for (k = length; k > 0; k--) {
bool deleteResult;
mn1.name = meta->toString(k - 1);
mn2.name = meta->toString(k + argc - 1);
if (meta->hasOwnProperty(thisObj, mn1.name)) {
js2val rval;
meta->readDynamicProperty(thisObj, &mn1, &lookup, RunPhase, &rval);
meta->writeDynamicProperty(thisObj, &mn2, true, rval, RunPhase);
}
else
meta->deleteProperty(thisValue, &mn2, &lookup, RunPhase, &deleteResult);
delete mn1.name;
delete mn2.name;
}
for (k = 0; k < argc; k++) {
mn1.name = meta->toString(k);
meta->writeDynamicProperty(thisObj, &mn1, true, argv[k], RunPhase);
delete mn1.name;
}
setLength(meta, thisObj, (length + argc));
return thisValue;
}
#if 0
// An index has to pass the test that :
// meta->toString(ToUint32(meta->toString(index))) == meta->toString(index)
//
// the 'meta->toString(index)' operation is the default behaviour of '[]'
//
// isArrayIndex() is called when we know that index is a Number
//
static bool isArrayIndex(JS2Metadata *meta, js2val index, uint32 &intIndex)
{
ASSERT(JS2VAL_IS_NUMBER(index));
js2val v = JSValue::toUInt32(cx, index);
if ((JSValue::f64(v) == JSValue::f64(index)) && (JSValue::f64(v) < two32minus1)) {
intIndex = (uint32)JSValue::f64(v);
return true;
}
return false;
}
js2val Array_GetElement(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc)
{
// the 'this' value is the first argument, then the index
if (argc != 2)
cx->reportError(Exception::referenceError, "[] only supports single dimension");
JSArrayInstance *arrInst = checked_cast<JSArrayInstance *>(JSValue::instance(thisValue));
js2val index = argv[1];
const String *name = JSValue::string(JSValue::meta->toString(cx, index));
arrInst->getProperty(cx, *name, NULL);
return cx->popValue();
}
js2val Array_SetElement(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc)
{
// the 'this' value is the first argument, then the rValue, and finally the index
if (argc != 3)
cx->reportError(Exception::referenceError, "[]= only supports single dimension");
JSArrayInstance *arrInst = checked_cast<JSArrayInstance *>(JSValue::instance(thisValue));
js2val index = argv[2];
const String *name = JSValue::string(JSValue::meta->toString(cx, index));
if (JS2VAL_IS_NUMBER(index)) {
uint32 intIndex;
if (isArrayIndex(cx, index, intIndex)) {
PropertyIterator it = arrInst->findNamespacedProperty(*name, NULL);
if (it == arrInst->mProperties.end())
arrInst->insertNewProperty(*name, NULL, Property::Enumerable, Object_Type, argv[1]);
else {
Property *prop = PROPERTY(it);
ASSERT(prop->mFlag == ValuePointer);
prop->mData.vp = argv[1];
}
if (intIndex >= arrInst->mLength)
arrInst->mLength = intIndex + 1;
}
}
else {
arrInst->setProperty(cx, *name, NULL, argv[1]);
}
return argv[0];
}
#endif
void initArrayObject(JS2Metadata *meta)
{
typedef struct {
char *name;
uint16 length;
NativeCode *code;
} PrototypeFunction;
PrototypeFunction arrayProtos[] =
{
{ "toString", 0, Array_toString },
{ "toLocaleString", 0, Array_toString }, // XXX
{ "toSource", 0, Array_toSource },
{ "push", 1, Array_push },
{ "pop", 0, Array_pop },
{ "concat", 1, Array_concat },
{ "join", 1, Array_join },
{ "reverse", 0, Array_reverse },
{ "shift", 0, Array_shift },
{ "slice", 2, Array_slice },
{ "sort", 1, Array_sort },
{ "splice", 2, Array_splice },
{ "unshift", 1, Array_unshift },
{ NULL }
};
NamespaceList publicNamespaceList;
publicNamespaceList.push_back(meta->publicNamespace);
meta->arrayClass->construct = Array_Constructor;
PrototypeFunction *pf = &arrayProtos[0];
while (pf->name) {
FixedInstance *fInst = new FixedInstance(meta->functionClass);
fInst->fWrap = new FunctionWrapper(true, new ParameterFrame(JS2VAL_INACCESSIBLE, true), pf->code);
InstanceMember *m = new InstanceMethod(fInst);
meta->defineInstanceMember(meta->arrayClass, &meta->cxt, &meta->world.identifiers[pf->name], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, m, 0);
pf++;
}
}
}
}

Просмотреть файл

@ -298,7 +298,6 @@ static int32 WeekDay(float64 t)
static float64 *Date_getProlog(JS2Metadata *meta, const js2val thisValue)
{
if (meta->objectType(thisValue) != meta->dateClass)
//|| ((checked_cast<PrototypeInstance *>(JS2VAL_TO_OBJECT(thisValue))->type != meta->dateClass)) )
meta->reportError(Exception::typeError, "You really need a date", meta->engine->errorPos());
DateInstance *dateInst = checked_cast<DateInstance *>(JS2VAL_TO_OBJECT(thisValue));
return &dateInst->ms;
@ -388,7 +387,7 @@ static js2val Date_makeTime(JS2Metadata *meta, const js2val thisValue, js2val *a
argc = maxargs; /* clamp argc */
for (i = 0; i < argc; i++) {
float64 f = meta->engine->toFloat64(argv[i]);
float64 f = meta->toFloat64(argv[i]);
if (JSDOUBLE_IS_NaN(f)) {
*date = nan;
return meta->engine->nanValue;
@ -454,7 +453,7 @@ static js2val Date_makeDate(JS2Metadata *meta, const js2val thisValue, js2val *a
argc = maxargs; /* clamp argc */
for (i = 0; i < argc; i++) {
float64 f = meta->engine->toFloat64(argv[i]);
float64 f = meta->toFloat64(argv[i]);
if (JSDOUBLE_IS_NaN(f)) {
*date = nan;
return meta->engine->nanValue;
@ -874,11 +873,11 @@ js2val Date_Constructor(JS2Metadata *meta, const js2val thisValue, js2val *argv,
if (argc == 1) {
if (!JS2VAL_IS_STRING(argv[0])) {
/* the argument is a millisecond number */
float64 d = meta->engine->toFloat64(argv[0]);
float64 d = meta->toFloat64(argv[0]);
thisInst->ms = TIMECLIP(d);
} else {
/* the argument is a string; parse it. */
const String *str = meta->engine->toString(argv[0]);
const String *str = meta->toString(argv[0]);
float64 d = date_parseString(*str);
thisInst->ms = TIMECLIP(d);
}
@ -891,7 +890,7 @@ js2val Date_Constructor(JS2Metadata *meta, const js2val thisValue, js2val *argv,
for (loop = 0; loop < MAXARGS; loop++) {
if (loop < argc) {
float64 double_arg = meta->engine->toFloat64(argv[loop]);
float64 double_arg = meta->toFloat64(argv[loop]);
/* if any arg is NaN, make a NaN date object
and return */
if (!JSDOUBLE_IS_FINITE(double_arg)) {
@ -924,7 +923,7 @@ js2val Date_Constructor(JS2Metadata *meta, const js2val thisValue, js2val *argv,
js2val Date_parse(JS2Metadata *meta, const js2val /*thisValue*/, js2val *argv, uint32 /*argc*/)
{
const String *str = meta->engine->toString(argv[0]);
const String *str = meta->toString(argv[0]);
float64 d = date_parseString(*str);
d = TIMECLIP(d);
return meta->engine->allocNumber(d);
@ -938,7 +937,7 @@ js2val Date_UTC(JS2Metadata *meta, const js2val /*thisValue*/, js2val *argv, uin
for (loop = 0; loop < MAXARGS; loop++) {
if (loop < argc) {
d = meta->engine->toFloat64(argv[loop]);
d = meta->toFloat64(argv[loop]);
if (!JSDOUBLE_IS_FINITE(d))
return meta->engine->allocNumber(d);
array[loop] = floor(d);
@ -1272,7 +1271,7 @@ static js2val Date_getUTCMilliseconds(JS2Metadata *meta, const js2val thisValue,
static js2val Date_setTime(JS2Metadata *meta, const js2val thisValue, js2val argv[], uint32 /*argc*/)
{
float64 *date = Date_getProlog(meta, thisValue);
float64 result = meta->engine->toFloat64(argv[0]);
float64 result = meta->toFloat64(argv[0]);
*date = TIMECLIP(result);
return meta->engine->allocNumber(*date);
}
@ -1286,7 +1285,7 @@ static js2val Date_setYear(JS2Metadata *meta, const js2val thisValue, js2val arg
float64 *date = Date_getProlog(meta, thisValue);
result = *date;
year = meta->engine->toFloat64(argv[0]);
year = meta->toFloat64(argv[0]);
if (!JSDOUBLE_IS_FINITE(year)) {
*date = nan;
return meta->engine->allocNumber(*date);

Просмотреть файл

@ -188,84 +188,6 @@ namespace MetaData {
return new JavaScript::String(widenCString(chrp));
}
// x is not a String
const String *JS2Engine::convertValueToString(js2val x)
{
if (JS2VAL_IS_UNDEFINED(x))
return undefined_StringAtom;
if (JS2VAL_IS_NULL(x))
return null_StringAtom;
if (JS2VAL_IS_BOOLEAN(x))
return (JS2VAL_TO_BOOLEAN(x)) ? true_StringAtom : false_StringAtom;
if (JS2VAL_IS_INT(x))
return numberToString(JS2VAL_TO_INT(x));
if (JS2VAL_IS_LONG(x)) {
float64 d;
JSLL_L2D(d, *JS2VAL_TO_LONG(x));
return numberToString(&d);
}
if (JS2VAL_IS_ULONG(x)) {
float64 d;
JSLL_UL2D(d, *JS2VAL_TO_ULONG(x));
return numberToString(&d);
}
if (JS2VAL_IS_FLOAT(x)) {
float64 d = *JS2VAL_TO_FLOAT(x);
return numberToString(&d);
}
if (JS2VAL_IS_DOUBLE(x))
return numberToString(JS2VAL_TO_DOUBLE(x));
return toString(toPrimitive(x));
}
// x is not a primitive (it is an object and not null)
js2val JS2Engine::convertValueToPrimitive(js2val x)
{
// return [[DefaultValue]] --> get property 'toString' and invoke it,
// if not available or result is not primitive then try property 'valueOf'
// if that's not available or returns a non primitive, throw a TypeError
return STRING_TO_JS2VAL(object_StringAtom);
ASSERT(false);
return JS2VAL_VOID;
}
// x is not a number
float64 JS2Engine::convertValueToDouble(js2val x)
{
if (JS2VAL_IS_UNDEFINED(x))
return nan;
if (JS2VAL_IS_NULL(x))
return 0;
if (JS2VAL_IS_BOOLEAN(x))
return (JS2VAL_TO_BOOLEAN(x)) ? 1.0 : 0.0;
if (JS2VAL_IS_STRING(x)) {
String *str = JS2VAL_TO_STRING(x);
char16 *numEnd;
return stringToDouble(str->data(), str->data() + str->length(), numEnd);
}
return toFloat64(toPrimitive(x));
}
// x is not a number, convert it to one
js2val JS2Engine::convertValueToGeneralNumber(js2val x)
{
// XXX Assuming convert to float64, rather than long/ulong
return allocNumber(toFloat64(x));
}
// x is not an Object, it needs to be wrapped in one
js2val JS2Engine::convertValueToObject(js2val x)
{
if (JS2VAL_IS_UNDEFINED(x) || JS2VAL_IS_NULL(x) || JS2VAL_IS_SPECIALREF(x))
meta->reportError(Exception::typeError, "Can't convert to Object", errorPos());
if (JS2VAL_IS_STRING(x))
return String_Constructor(meta, JS2VAL_NULL, &x, 1);
// XXX need more
return OBJECT_TO_JS2VAL(new PrototypeInstance(meta->objectClass->prototype, meta->objectClass));
}
// x is a Number, validate that it has no fractional component
int64 JS2Engine::checkInteger(js2val x)
{
@ -301,83 +223,6 @@ namespace MetaData {
return i;
}
// x is any js2val
float64 JS2Engine::toFloat64(js2val x)
{
if (JS2VAL_IS_INT(x))
return JS2VAL_TO_INT(x);
else
if (JS2VAL_IS_DOUBLE(x))
return *JS2VAL_TO_DOUBLE(x);
else
if (JS2VAL_IS_LONG(x)) {
float64 d;
JSLL_L2D(d, *JS2VAL_TO_LONG(x));
return d;
}
else
if (JS2VAL_IS_ULONG(x)) {
float64 d;
JSLL_UL2D(d, *JS2VAL_TO_ULONG(x));
return d;
}
else
if (JS2VAL_IS_FLOAT(x))
return *JS2VAL_TO_FLOAT(x);
else
return convertValueToDouble(x);
}
// x is not a bool
bool JS2Engine::convertValueToBoolean(js2val x)
{
if (JS2VAL_IS_UNDEFINED(x))
return false;
if (JS2VAL_IS_NULL(x))
return false;
if (JS2VAL_IS_INT(x))
return (JS2VAL_TO_INT(x) != 0);
if (JS2VAL_IS_LONG(x) || JS2VAL_IS_ULONG(x))
return (!JSLL_IS_ZERO(x));
if (JS2VAL_IS_FLOAT(x)) {
float64 xd = *JS2VAL_TO_FLOAT(x);
return ! (JSDOUBLE_IS_POSZERO(xd) || JSDOUBLE_IS_NEGZERO(xd) || JSDOUBLE_IS_NaN(xd));
}
if (JS2VAL_IS_DOUBLE(x)) {
float64 xd = *JS2VAL_TO_DOUBLE(x);
return ! (JSDOUBLE_IS_POSZERO(xd) || JSDOUBLE_IS_NEGZERO(xd) || JSDOUBLE_IS_NaN(xd));
}
if (JS2VAL_IS_STRING(x)) {
String *str = JS2VAL_TO_STRING(x);
return (str->length() != 0);
}
return true;
}
// x is not an int
int32 JS2Engine::convertValueToInteger(js2val x)
{
int32 i;
if (JS2VAL_IS_LONG(x)) {
JSLL_L2I(i, *JS2VAL_TO_LONG(x));
return i;
}
if (JS2VAL_IS_ULONG(x)) {
JSLL_UL2I(i, *JS2VAL_TO_ULONG(x));
return i;
}
if (JS2VAL_IS_FLOAT(x)) {
float64 f = *JS2VAL_TO_FLOAT(x);
return toInt32(f);
}
if (JS2VAL_IS_DOUBLE(x)) {
float64 d = *JS2VAL_TO_DOUBLE(x);
return toInt32(d);
}
float64 d = convertValueToDouble(x);
return toInt32(d);
}
int32 JS2Engine::toInt32(float64 d)
{
if ((d == 0.0) || !JSDOUBLE_IS_FINITE(d) )
@ -444,7 +289,8 @@ namespace MetaData {
INIT_STRINGATOM(object),
Empty_StringAtom(&world.identifiers[""]),
Dollar_StringAtom(&world.identifiers["$"]),
prototype_StringAtom(&world.identifiers["prototype"])
INIT_STRINGATOM(prototype),
INIT_STRINGATOM(length)
{
for (int i = 0; i < 256; i++)
float64Table[i] = NULL;

Просмотреть файл

@ -156,27 +156,11 @@ public:
// Use the pc map in the current bytecode container to get a source offset
size_t errorPos();
int32 toInt32(float64 f);
uint32 toUInt32(float64 f);
uint16 toUInt16(float64 f);
static int32 toInt32(float64 f);
static uint32 toUInt32(float64 f);
static uint16 toUInt16(float64 f);
const String *convertValueToString(js2val x);
js2val convertValueToPrimitive(js2val x);
float64 convertValueToDouble(js2val x);
bool convertValueToBoolean(js2val x);
int32 convertValueToInteger(js2val x);
js2val convertValueToGeneralNumber(js2val x);
js2val convertValueToObject(js2val x);
const String *toString(js2val x){ if (JS2VAL_IS_STRING(x)) return JS2VAL_TO_STRING(x); else return convertValueToString(x); }
js2val toPrimitive(js2val x) { if (JS2VAL_IS_PRIMITIVE(x)) return x; else return convertValueToPrimitive(x); }
float64 toFloat64(js2val x);
js2val toGeneralNumber(js2val x){ if (JS2VAL_IS_NUMBER(x)) return x; else return convertValueToGeneralNumber(x); }
bool toBoolean(js2val x) { if (JS2VAL_IS_BOOLEAN(x)) return JS2VAL_TO_BOOLEAN(x); else return convertValueToBoolean(x); }
int32 toInteger(js2val x) { if (JS2VAL_IS_INT(x)) return JS2VAL_TO_INT(x); else return convertValueToInteger(x); }
js2val toObject(js2val x) { if (JS2VAL_IS_OBJECT(x)) return x; else return convertValueToObject(x); }
js2val assignmentConversion(js2val val, JS2Class *type) { return val; } // XXX s'more code, please
int64 checkInteger(js2val x);
@ -236,6 +220,7 @@ public:
const String *Empty_StringAtom;
const String *Dollar_StringAtom;
const String *prototype_StringAtom;
const String *length_StringAtom;
// The activation stack, when it's empty and a return is executed, the
// interpreter quits

Просмотреть файл

@ -92,73 +92,73 @@ static js2val Math_abs(JS2Metadata *meta, const js2val /*thisValue*/, js2val *ar
if (argc == 0)
return meta->engine->nanValue;
else
return meta->engine->allocNumber(fd::fabs(meta->engine->toFloat64(argv[0])));
return meta->engine->allocNumber(fd::fabs(meta->engine->meta->toFloat64(argv[0])));
}
static js2val Math_acos(JS2Metadata *meta, const js2val /*thisValue*/, js2val *argv, uint32 argc)
{
if (argc == 0)
return meta->engine->nanValue;
return meta->engine->allocNumber(fd::acos(meta->engine->toFloat64(argv[0])));
return meta->engine->allocNumber(fd::acos(meta->engine->meta->toFloat64(argv[0])));
}
static js2val Math_asin(JS2Metadata *meta, const js2val /*thisValue*/, js2val *argv, uint32 argc)
{
if (argc == 0)
return meta->engine->nanValue;
return meta->engine->allocNumber(fd::asin(meta->engine->toFloat64(argv[0])));
return meta->engine->allocNumber(fd::asin(meta->engine->meta->toFloat64(argv[0])));
}
static js2val Math_atan(JS2Metadata *meta, const js2val /*thisValue*/, js2val *argv, uint32 argc)
{
if (argc == 0)
return meta->engine->nanValue;
return meta->engine->allocNumber(fd::atan(meta->engine->toFloat64(argv[0])));
return meta->engine->allocNumber(fd::atan(meta->engine->meta->toFloat64(argv[0])));
}
static js2val Math_atan2(JS2Metadata *meta, const js2val /*thisValue*/, js2val *argv, uint32 argc)
{
if (argc <= 1)
return meta->engine->nanValue;
float64 y = meta->engine->toFloat64(argv[0]);
float64 x = meta->engine->toFloat64(argv[1]);
float64 y = meta->engine->meta->toFloat64(argv[0]);
float64 x = meta->engine->meta->toFloat64(argv[1]);
return meta->engine->allocNumber(fd::atan2(y, x));
}
static js2val Math_ceil(JS2Metadata *meta, const js2val /*thisValue*/, js2val *argv, uint32 argc)
{
if (argc == 0)
return meta->engine->nanValue;
return meta->engine->allocNumber(fd::ceil(meta->engine->toFloat64(argv[0])));
return meta->engine->allocNumber(fd::ceil(meta->engine->meta->toFloat64(argv[0])));
}
static js2val Math_cos(JS2Metadata *meta, const js2val /*thisValue*/, js2val *argv, uint32 argc)
{
if (argc == 0)
return meta->engine->nanValue;
return meta->engine->allocNumber(fd::cos(meta->engine->toFloat64(argv[0])));
return meta->engine->allocNumber(fd::cos(meta->engine->meta->toFloat64(argv[0])));
}
static js2val Math_exp(JS2Metadata *meta, const js2val /*thisValue*/, js2val *argv, uint32 argc)
{
if (argc == 0)
return meta->engine->nanValue;
return meta->engine->allocNumber(fd::exp(meta->engine->toFloat64(argv[0])));
return meta->engine->allocNumber(fd::exp(meta->engine->meta->toFloat64(argv[0])));
}
static js2val Math_floor(JS2Metadata *meta, const js2val /*thisValue*/, js2val *argv, uint32 argc)
{
if (argc == 0)
return meta->engine->nanValue;
else
return meta->engine->allocNumber(fd::floor(meta->engine->toFloat64(argv[0])));
return meta->engine->allocNumber(fd::floor(meta->engine->meta->toFloat64(argv[0])));
}
static js2val Math_log(JS2Metadata *meta, const js2val /*thisValue*/, js2val *argv, uint32 argc)
{
if (argc == 0)
return meta->engine->nanValue;
return meta->engine->allocNumber(fd::log(meta->engine->toFloat64(argv[0])));
return meta->engine->allocNumber(fd::log(meta->engine->meta->toFloat64(argv[0])));
}
static js2val Math_max(JS2Metadata *meta, const js2val /*thisValue*/, js2val *argv, uint32 argc)
{
if (argc == 0)
return meta->engine->negInfValue;
float64 result = meta->engine->toFloat64(argv[0]);
float64 result = meta->engine->meta->toFloat64(argv[0]);
if (JSDOUBLE_IS_NaN(result)) return meta->engine->nanValue;
for (uint32 i = 1; i < argc; ++i) {
float64 arg = meta->engine->toFloat64(argv[i]);
float64 arg = meta->engine->meta->toFloat64(argv[i]);
if (JSDOUBLE_IS_NaN(arg)) return meta->engine->nanValue;
if (arg > result)
result = arg;
@ -169,10 +169,10 @@ static js2val Math_min(JS2Metadata *meta, const js2val /*thisValue*/, js2val *ar
{
if (argc == 0)
return meta->engine->posInfValue;
float64 result = meta->engine->toFloat64(argv[0]);
float64 result = meta->engine->meta->toFloat64(argv[0]);
if (JSDOUBLE_IS_NaN(result)) return meta->engine->nanValue;
for (uint32 i = 1; i < argc; ++i) {
float64 arg = meta->engine->toFloat64(argv[i]);
float64 arg = meta->engine->meta->toFloat64(argv[i]);
if (JSDOUBLE_IS_NaN(arg)) return meta->engine->nanValue;
if ((arg < result) || (JSDOUBLE_IS_POSZERO(result) && JSDOUBLE_IS_NEGZERO(arg)))
result = arg;
@ -183,7 +183,7 @@ static js2val Math_pow(JS2Metadata *meta, const js2val /*thisValue*/, js2val *ar
{
if (argc < 1)
return meta->engine->nanValue;
return meta->engine->allocNumber(fd::pow(meta->engine->toFloat64(argv[0]), meta->engine->toFloat64(argv[1])));
return meta->engine->allocNumber(fd::pow(meta->engine->meta->toFloat64(argv[0]), meta->engine->meta->toFloat64(argv[1])));
}
/*
@ -265,26 +265,26 @@ static js2val Math_round(JS2Metadata *meta, const js2val /*thisValue*/, js2val *
{
if (argc == 0)
return meta->engine->nanValue;
float64 x = meta->engine->toFloat64(argv[0]);
float64 x = meta->engine->meta->toFloat64(argv[0]);
return meta->engine->allocNumber( fd::copysign( fd::floor(x + 0.5), x ) );
}
static js2val Math_sin(JS2Metadata *meta, const js2val /*thisValue*/, js2val *argv, uint32 argc)
{
if (argc == 0)
return meta->engine->nanValue;
return meta->engine->allocNumber(fd::sin(meta->engine->toFloat64(argv[0])));
return meta->engine->allocNumber(fd::sin(meta->engine->meta->toFloat64(argv[0])));
}
static js2val Math_sqrt(JS2Metadata *meta, const js2val /*thisValue*/, js2val *argv, uint32 argc)
{
if (argc == 0)
return meta->engine->nanValue;
return meta->engine->allocNumber(fd::sqrt(meta->engine->toFloat64(argv[0])));
return meta->engine->allocNumber(fd::sqrt(meta->engine->meta->toFloat64(argv[0])));
}
static js2val Math_tan(JS2Metadata *meta, const js2val /*thisValue*/, js2val *argv, uint32 argc)
{
if (argc == 0)
return meta->engine->nanValue;
return meta->engine->allocNumber(fd::tan(meta->engine->toFloat64(argv[0])));
return meta->engine->allocNumber(fd::tan(meta->engine->meta->toFloat64(argv[0])));
}

Просмотреть файл

@ -48,6 +48,7 @@
#include "world.h"
#include "utilities.h"
#include "js2value.h"
#include "jslong.h"
#include "numerics.h"
#include "reader.h"
#include "parser.h"
@ -985,7 +986,7 @@ namespace MetaData {
VariableStmtNode *vs = checked_cast<VariableStmtNode *>(p);
VariableBinding *vb = vs->bindings;
while (vb) {
if (vb->member) {
if (vb->member) { // static or instance variable
if (vb->member->kind == Member::Variable) {
Variable *v = checked_cast<Variable *>(vb->member);
JS2Class *type = getVariableType(v, CompilePhase, p->pos);
@ -2497,53 +2498,6 @@ doUnary:
return STRING_TO_JS2VAL(meta->engine->object_StringAtom);
}
js2val RegExp_Constructor(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc)
{
// XXX Change constructors to take js2val pointer for the result (which would be an already
// rooted pointer).
RegExpInstance *thisInst = new RegExpInstance(meta->regexpClass);
JS2Object::RootIterator ri = JS2Object::addRoot(&thisInst);
js2val thatValue = OBJECT_TO_JS2VAL(thisInst);
REuint32 flags = 0;
const String *regexpStr = meta->engine->Empty_StringAtom;
const String *flagStr = meta->engine->Empty_StringAtom;
if (argc > 0) {
if (meta->objectType(argv[0]) == meta->regexpClass) {
if ((argc == 1) || JS2VAL_IS_UNDEFINED(argv[1])) {
RegExpInstance *otherInst = checked_cast<RegExpInstance *>(JS2VAL_TO_OBJECT(argv[0]));
js2val src = otherInst->getSource(meta);
ASSERT(JS2VAL_IS_STRING(src));
regexpStr = JS2VAL_TO_STRING(src);
flags = otherInst->mRegExp->flags;
}
else
meta->reportError(Exception::typeError, "Illegal RegExp constructor args", meta->engine->errorPos());
}
else
regexpStr = meta->engine->toString(argv[0]);
if ((argc > 1) && !JS2VAL_IS_UNDEFINED(argv[1])) {
flagStr = meta->engine->toString(argv[1]);
if (parseFlags(flagStr->begin(), (int32)flagStr->length(), &flags) != RE_NO_ERROR)
meta->reportError(Exception::syntaxError, "Failed to parse RegExp : '{0}'", meta->engine->errorPos(), *regexpStr + "/" + *flagStr); // XXX error message?
}
}
REState *pState = REParse(regexpStr->begin(), (int32)regexpStr->length(), flags, RE_VERSION_1);
if (pState) {
thisInst->mRegExp = pState;
// XXX ECMA spec says these are DONTENUM
thisInst->setSource(meta, STRING_TO_JS2VAL(regexpStr));
thisInst->setGlobal(meta, BOOLEAN_TO_JS2VAL((pState->flags & RE_GLOBAL) == RE_GLOBAL));
thisInst->setIgnoreCase(meta, BOOLEAN_TO_JS2VAL((pState->flags & RE_IGNORECASE) == RE_IGNORECASE));
thisInst->setLastIndex(meta, INT_TO_JS2VAL(0));
thisInst->setMultiline(meta, BOOLEAN_TO_JS2VAL((pState->flags & RE_MULTILINE) == RE_MULTILINE));
}
else
meta->reportError(Exception::syntaxError, "Failed to parse RegExp : '{0}'", meta->engine->errorPos(), "/" + *regexpStr + "/" + *flagStr); // XXX what about the RE parser error message?
JS2Object::removeRoot(ri);
return thatValue;
}
void JS2Metadata::addGlobalObjectFunction(char *name, NativeCode *code)
{
FixedInstance *fInst = new FixedInstance(functionClass);
@ -2600,6 +2554,7 @@ doUnary:
NamespaceList publicNamespaceList;
publicNamespaceList.push_back(publicNamespace);
Variable *v;
InstanceMember *m;
MAKEBUILTINCLASS(dateClass, objectClass, true, true, true, &world.identifiers["Date"]);
v = new Variable(classClass, OBJECT_TO_JS2VAL(dateClass), true);
@ -2611,6 +2566,16 @@ doUnary:
v = new Variable(classClass, OBJECT_TO_JS2VAL(regexpClass), true);
defineStaticMember(&env, &world.identifiers["RegExp"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
regexpClass->construct = RegExp_Constructor;
m = new InstanceVariable(objectClass, false, false, regexpClass->slotCount++);
defineInstanceMember(regexpClass, &cxt, &world.identifiers["source"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, m, 0);
m = new InstanceVariable(objectClass, false, false, regexpClass->slotCount++);
defineInstanceMember(regexpClass, &cxt, &world.identifiers["global"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, m, 0);
m = new InstanceVariable(objectClass, false, false, regexpClass->slotCount++);
defineInstanceMember(regexpClass, &cxt, &world.identifiers["lastIndex"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, m, 0);
m = new InstanceVariable(objectClass, false, false, regexpClass->slotCount++);
defineInstanceMember(regexpClass, &cxt, &world.identifiers["ignoreCase"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, m, 0);
m = new InstanceVariable(objectClass, false, false, regexpClass->slotCount++);
defineInstanceMember(regexpClass, &cxt, &world.identifiers["multiline"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, m, 0);
v = new Variable(classClass, OBJECT_TO_JS2VAL(stringClass), true);
defineStaticMember(&env, &world.identifiers["String"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
@ -2622,6 +2587,12 @@ doUnary:
defineStaticMember(&env, &world.identifiers["Math"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
initMathObject(this);
MAKEBUILTINCLASS(arrayClass, objectClass, true, true, true, &world.identifiers["Array"]);
v = new Variable(classClass, OBJECT_TO_JS2VAL(arrayClass), true);
defineStaticMember(&env, &world.identifiers["Array"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
// dateClass->prototype = new PrototypeInstance(NULL, dateClass);
initArrayObject(this);
}
@ -2638,7 +2609,9 @@ doUnary:
return numberClass;
if (JS2VAL_IS_STRING(objVal)) {
if (JS2VAL_TO_STRING(objVal)->length() == 1)
return characterClass;
return stringClass; // XXX characterClass; Need the connection from class Character to
// class String - i.e. access to all the functions in 'String.prototype' -
// but (some of) those routines depened on being called on a StringInstance...
else
return stringClass;
}
@ -2705,6 +2678,31 @@ doUnary:
return NULL;
}
// Return true if the object contains the property, but don't
// scan the prototype chain. Only scan dynamic properties. XXX
bool JS2Metadata::hasOwnProperty(JS2Object *obj, const String *name)
{
ASSERT(obj);
DynamicPropertyMap *dMap = NULL;
bool isPrototypeInstance = false;
if (obj->kind == DynamicInstanceKind)
dMap = &(checked_cast<DynamicInstance *>(obj))->dynamicProperties;
else
if (obj->kind == GlobalObjectKind)
dMap = &(checked_cast<GlobalObject *>(obj))->dynamicProperties;
else {
ASSERT(obj->kind == PrototypeInstanceKind);
isPrototypeInstance = true;
dMap = &(checked_cast<PrototypeInstance *>(obj))->dynamicProperties;
}
for (DynamicPropertyIterator i = dMap->begin(), end = dMap->end(); (i != end); i++) {
if (i->first == *name) {
return true;
}
}
return false;
}
// Read the property from the container given by the public id in multiname - if that exists
//
bool JS2Metadata::readDynamicProperty(JS2Object *container, Multiname *multiname, LookupKind *lookupKind, Phase phase, js2val *rval)
@ -2746,6 +2744,34 @@ doUnary:
return false; // 'None'
}
void DynamicInstance::writeProperty(JS2Metadata *meta, const String *name, js2val newValue)
{
const DynamicPropertyMap::value_type e(*name, newValue);
dynamicProperties.insert(e);
}
void ArrayInstance::writeProperty(JS2Metadata *meta, const String *name, js2val newValue)
{
// An index has to pass the test that :
// ToString(ToUint32(ToString(index))) == ToString(index)
// (we already have done the 'ToString(index)' part, so require
//
// ToString(ToUint32(name)) == name
//
const DynamicPropertyMap::value_type e(*name, newValue);
dynamicProperties.insert(e);
char16 *numEnd;
float64 f = stringToDouble(name->data(), name->data() + name->length(), numEnd);
uint32 index = JS2Engine::toUInt32(f);
if (index == f) {
uint32 length = getLength(meta, this);
if (index >= length)
setLength(meta, this, index + 1);
}
}
// Write a value to a dynamic container - inserting into the map if not already there (if createIfMissing)
bool JS2Metadata::writeDynamicProperty(JS2Object *container, Multiname *multiname, bool createIfMissing, js2val newValue, Phase phase)
{
@ -2775,8 +2801,7 @@ doUnary:
DynamicInstance *dynInst = checked_cast<DynamicInstance *>(container);
InstanceBinding *ib = resolveInstanceMemberName(dynInst->type, multiname, ReadAccess, phase);
if (ib == NULL) {
const DynamicPropertyMap::value_type e(*name, newValue);
dynInst->dynamicProperties.insert(e);
dynInst->writeProperty(this, name, newValue);
return true;
}
}
@ -2858,9 +2883,10 @@ readClassProperty:
InstanceBinding *ib = resolveInstanceMemberName(c, multiname, ReadAccess, phase);
if ((ib == NULL) && isDynamicInstance)
return readDynamicProperty(JS2VAL_TO_OBJECT(containerVal), multiname, lookupKind, phase, rval);
else
// XXX passing a primitive here ???
return readInstanceMember(containerVal, c, (ib) ? &ib->qname : NULL, phase, rval);
else {
// XXX Spec. would have us passing a primitive here ???
return readInstanceMember(toObject(containerVal), c, (ib) ? &ib->qname : NULL, phase, rval);
}
}
JS2Object *container = JS2VAL_TO_OBJECT(containerVal);
switch (container->kind) {
@ -3388,6 +3414,184 @@ deleteClassProperty:
}
// x is not a String
const String *JS2Metadata::convertValueToString(js2val x)
{
if (JS2VAL_IS_UNDEFINED(x))
return engine->undefined_StringAtom;
if (JS2VAL_IS_NULL(x))
return engine->null_StringAtom;
if (JS2VAL_IS_BOOLEAN(x))
return (JS2VAL_TO_BOOLEAN(x)) ? engine->true_StringAtom : engine->false_StringAtom;
if (JS2VAL_IS_INT(x))
return numberToString(JS2VAL_TO_INT(x));
if (JS2VAL_IS_LONG(x)) {
float64 d;
JSLL_L2D(d, *JS2VAL_TO_LONG(x));
return numberToString(&d);
}
if (JS2VAL_IS_ULONG(x)) {
float64 d;
JSLL_UL2D(d, *JS2VAL_TO_ULONG(x));
return numberToString(&d);
}
if (JS2VAL_IS_FLOAT(x)) {
float64 d = *JS2VAL_TO_FLOAT(x);
return numberToString(&d);
}
if (JS2VAL_IS_DOUBLE(x))
return numberToString(JS2VAL_TO_DOUBLE(x));
return toString(toPrimitive(x));
}
// x is not a primitive (it is an object and not null)
js2val JS2Metadata::convertValueToPrimitive(js2val x)
{
// return [[DefaultValue]] --> get property 'toString' and invoke it,
// if not available or result is not primitive then try property 'valueOf'
// if that's not available or returns a non primitive, throw a TypeError
Multiname mn(&world.identifiers["toString"], publicNamespace);
LookupKind lookup(false, NULL);
js2val result;
if (readProperty(x, &mn, &lookup, RunPhase, &result)) {
if (JS2VAL_IS_OBJECT(result)) {
JS2Object *obj = JS2VAL_TO_OBJECT(result);
if ((obj->kind == FixedInstanceKind) && (objectType(result) == functionClass)) {
FunctionWrapper *fWrap = (checked_cast<FixedInstance *>(obj))->fWrap;
if (fWrap->code) {
result = (fWrap->code)(this, result, NULL, 0);
return result;
}
}
else
if (obj->kind == MethodClosureKind) {
MethodClosure *mc = checked_cast<MethodClosure *>(obj);
FixedInstance *fInst = mc->method->fInst;
FunctionWrapper *fWrap = fInst->fWrap;
if (fWrap->code) {
result = (fWrap->code)(this, mc->thisObject, NULL, 0);
return result;
}
}
}
}
return STRING_TO_JS2VAL(engine->object_StringAtom);
}
// x is not a number
float64 JS2Metadata::convertValueToDouble(js2val x)
{
if (JS2VAL_IS_UNDEFINED(x))
return nan;
if (JS2VAL_IS_NULL(x))
return 0;
if (JS2VAL_IS_BOOLEAN(x))
return (JS2VAL_TO_BOOLEAN(x)) ? 1.0 : 0.0;
if (JS2VAL_IS_STRING(x)) {
String *str = JS2VAL_TO_STRING(x);
char16 *numEnd;
return stringToDouble(str->data(), str->data() + str->length(), numEnd);
}
return toFloat64(toPrimitive(x));
}
// x is not a number, convert it to one
js2val JS2Metadata::convertValueToGeneralNumber(js2val x)
{
// XXX Assuming convert to float64, rather than long/ulong
return engine->allocNumber(toFloat64(x));
}
// x is not an Object, it needs to be wrapped in one
js2val JS2Metadata::convertValueToObject(js2val x)
{
if (JS2VAL_IS_UNDEFINED(x) || JS2VAL_IS_NULL(x) || JS2VAL_IS_SPECIALREF(x))
reportError(Exception::typeError, "Can't convert to Object", engine->errorPos());
if (JS2VAL_IS_STRING(x))
return String_Constructor(this, JS2VAL_NULL, &x, 1);
// XXX need more
return OBJECT_TO_JS2VAL(new PrototypeInstance(objectClass->prototype, objectClass));
}
// x is any js2val
float64 JS2Metadata::toFloat64(js2val x)
{
if (JS2VAL_IS_INT(x))
return JS2VAL_TO_INT(x);
else
if (JS2VAL_IS_DOUBLE(x))
return *JS2VAL_TO_DOUBLE(x);
else
if (JS2VAL_IS_LONG(x)) {
float64 d;
JSLL_L2D(d, *JS2VAL_TO_LONG(x));
return d;
}
else
if (JS2VAL_IS_ULONG(x)) {
float64 d;
JSLL_UL2D(d, *JS2VAL_TO_ULONG(x));
return d;
}
else
if (JS2VAL_IS_FLOAT(x))
return *JS2VAL_TO_FLOAT(x);
else
return convertValueToDouble(x);
}
// x is not a bool
bool JS2Metadata::convertValueToBoolean(js2val x)
{
if (JS2VAL_IS_UNDEFINED(x))
return false;
if (JS2VAL_IS_NULL(x))
return false;
if (JS2VAL_IS_INT(x))
return (JS2VAL_TO_INT(x) != 0);
if (JS2VAL_IS_LONG(x) || JS2VAL_IS_ULONG(x))
return (!JSLL_IS_ZERO(x));
if (JS2VAL_IS_FLOAT(x)) {
float64 xd = *JS2VAL_TO_FLOAT(x);
return ! (JSDOUBLE_IS_POSZERO(xd) || JSDOUBLE_IS_NEGZERO(xd) || JSDOUBLE_IS_NaN(xd));
}
if (JS2VAL_IS_DOUBLE(x)) {
float64 xd = *JS2VAL_TO_DOUBLE(x);
return ! (JSDOUBLE_IS_POSZERO(xd) || JSDOUBLE_IS_NEGZERO(xd) || JSDOUBLE_IS_NaN(xd));
}
if (JS2VAL_IS_STRING(x)) {
String *str = JS2VAL_TO_STRING(x);
return (str->length() != 0);
}
return true;
}
// x is not an int
int32 JS2Metadata::convertValueToInteger(js2val x)
{
int32 i;
if (JS2VAL_IS_LONG(x)) {
JSLL_L2I(i, *JS2VAL_TO_LONG(x));
return i;
}
if (JS2VAL_IS_ULONG(x)) {
JSLL_UL2I(i, *JS2VAL_TO_ULONG(x));
return i;
}
if (JS2VAL_IS_FLOAT(x)) {
float64 f = *JS2VAL_TO_FLOAT(x);
return toInt32(f);
}
if (JS2VAL_IS_DOUBLE(x)) {
float64 d = *JS2VAL_TO_DOUBLE(x);
return toInt32(d);
}
float64 d = convertValueToDouble(x);
return toInt32(d);
}
/*
* Throw an exception of the specified kind, indicating the position 'pos' and

Просмотреть файл

@ -60,10 +60,14 @@ typedef js2val (Constructor)(JS2Metadata *meta, const js2val thisValue, js2val *
extern void initDateObject(JS2Metadata *meta);
extern void initStringObject(JS2Metadata *meta);
extern void initMathObject(JS2Metadata *meta);
extern void initArrayObject(JS2Metadata *meta);
extern js2val String_Constructor(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc);
extern js2val RegExp_Constructor(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc);
extern js2val RegExp_exec(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc);
extern uint32 getLength(JS2Metadata *meta, JS2Object *obj);
extern js2val setLength(JS2Metadata *meta, JS2Object *obj, uint32 length);
// OBJECT is the semantic domain of all possible objects and is defined as:
// OBJECT = UNDEFINED | NULL | BOOLEAN | FLOAT64 | LONG | ULONG | CHARACTER | STRING | NAMESPACE |
@ -514,6 +518,8 @@ public:
Slot *slots; // A set of slots that hold this instance's fixed property values
DynamicPropertyMap dynamicProperties; // A set of this instance's dynamic properties
virtual void markChildren();
virtual void writeProperty(JS2Metadata *meta, const String *name, js2val newValue);
};
// Prototype instances are represented as PROTOTYPE records. Prototype instances
@ -545,16 +551,28 @@ public:
// that contains the string data
class StringInstance : public FixedInstance {
public:
StringInstance(JS2Class *type) : FixedInstance(type) { }
StringInstance(JS2Class *type) : FixedInstance(type), mValue(NULL) { }
String *mValue;
String *mValue; // has been allocated by engine in the GC'able Pond
virtual void markChildren() { if (mValue) JS2Object::mark(mValue); }
};
// RegExp instances are fixed (not dynamic? XXX) instances created by the RegExp class, they have an extra field
// that contains the RegExp object
class RegExpInstance : public FixedInstance {
// Array instances are dynamic instances created by the Array class, they
// maintain the value of the 'length' property when 'indexable' elements
// are added.
class ArrayInstance : public DynamicInstance {
public:
RegExpInstance(JS2Class *type) : FixedInstance(type) { }
ArrayInstance(JS2Class *type) : DynamicInstance(type) { }
virtual void writeProperty(JS2Metadata *meta, const String *name, js2val newValue);
};
// RegExp instances are dynamic instances created by the RegExp class, they have an extra field
// that contains the RegExp object
class RegExpInstance : public DynamicInstance {
public:
RegExpInstance(JS2Class *type) : DynamicInstance(type) { }
void setLastIndex(JS2Metadata *meta, js2val a);
void setGlobal(JS2Metadata *meta, js2val a);
@ -922,6 +940,7 @@ public:
bool readStaticMember(StaticMember *m, Phase phase, js2val *rval);
bool readInstanceMember(js2val containerVal, JS2Class *c, QualifiedName *qname, Phase phase, js2val *rval);
JS2Object *lookupDynamicProperty(JS2Object *obj, const String *name);
bool JS2Metadata::hasOwnProperty(JS2Object *obj, const String *name);
bool writeProperty(js2val container, Multiname *multiname, LookupKind *lookupKind, bool createIfMissing, js2val newValue, Phase phase);
bool writeProperty(Frame *container, Multiname *multiname, LookupKind *lookupKind, bool createIfMissing, js2val newValue, Phase phase);
@ -941,6 +960,21 @@ public:
void reportError(Exception::Kind kind, const char *message, size_t pos, const String &name);
void reportError(Exception::Kind kind, const char *message, size_t pos, const String *name);
const String *convertValueToString(js2val x);
js2val convertValueToPrimitive(js2val x);
float64 convertValueToDouble(js2val x);
bool convertValueToBoolean(js2val x);
int32 convertValueToInteger(js2val x);
js2val convertValueToGeneralNumber(js2val x);
js2val convertValueToObject(js2val x);
const String *toString(js2val x) { if (JS2VAL_IS_STRING(x)) return JS2VAL_TO_STRING(x); else return convertValueToString(x); }
js2val toPrimitive(js2val x) { if (JS2VAL_IS_PRIMITIVE(x)) return x; else return convertValueToPrimitive(x); }
float64 toFloat64(js2val x);
js2val toGeneralNumber(js2val x) { if (JS2VAL_IS_NUMBER(x)) return x; else return convertValueToGeneralNumber(x); }
bool toBoolean(js2val x) { if (JS2VAL_IS_BOOLEAN(x)) return JS2VAL_TO_BOOLEAN(x); else return convertValueToBoolean(x); }
int32 toInteger(js2val x) { if (JS2VAL_IS_INT(x)) return JS2VAL_TO_INT(x); else return convertValueToInteger(x); }
js2val toObject(js2val x) { if (JS2VAL_IS_OBJECT(x)) return x; else return convertValueToObject(x); }
// Used for interning strings
World &world;
@ -980,6 +1014,7 @@ public:
JS2Class *dateClass;
JS2Class *regexpClass;
JS2Class *mathClass;
JS2Class *arrayClass;
Parser *mParser; // used for error reporting

Просмотреть файл

@ -130,7 +130,7 @@
LookupKind lookup(false, NULL);
indexVal = pop();
b = pop();
const String *indexStr = toString(indexVal);
const String *indexStr = meta->toString(indexVal);
Multiname mn(&meta->world.identifiers[*indexStr], meta->publicNamespace);
if (!meta->readProperty(b, &mn, &lookup, RunPhase, &a))
meta->reportError(Exception::propertyAccessError, "No property named {0}", errorPos(), mn.name);
@ -144,7 +144,7 @@
LookupKind lookup(false, NULL);
indexVal = pop();
b = pop();
const String *indexStr = toString(indexVal);
const String *indexStr = meta->toString(indexVal);
Multiname mn(&meta->world.identifiers[*indexStr], meta->publicNamespace);
bool result;
if (!meta->deleteProperty(b, &mn, &lookup, RunPhase, &result))
@ -163,7 +163,7 @@
a = pop();
indexVal = pop();
b = pop();
const String *indexStr = toString(indexVal);
const String *indexStr = meta->toString(indexVal);
Multiname mn(&meta->world.identifiers[*indexStr], meta->publicNamespace);
meta->writeProperty(b, &mn, &lookup, true, a, RunPhase);
push(a);
@ -177,7 +177,7 @@
LookupKind lookup(false, NULL);
indexVal = pop();
b = top();
const String *indexStr = toString(indexVal);
const String *indexStr = meta->toString(indexVal);
Multiname mn(&meta->world.identifiers[*indexStr], meta->publicNamespace);
if (!meta->readProperty(b, &mn, &lookup, RunPhase, &a))
meta->reportError(Exception::propertyAccessError, "No property named {0}", errorPos(), mn.name);
@ -192,7 +192,7 @@
LookupKind lookup(false, NULL);
indexVal = pop();
b = top();
const String *indexStr = toString(indexVal);
const String *indexStr = meta->toString(indexVal);
push(STRING_TO_JS2VAL(indexStr));
Multiname mn(&meta->world.identifiers[*indexStr], meta->publicNamespace);
if (!meta->readProperty(b, &mn, &lookup, RunPhase, &a))

Просмотреть файл

@ -38,7 +38,7 @@
case eMinus:
{
a = pop();
a = toGeneralNumber(a);
a = meta->toGeneralNumber(a);
if (JS2VAL_IS_LONG(a)) {
int64 v = *JS2VAL_TO_LONG(a);
if (JSLL_EQ(v, JSLL_MININT))
@ -55,22 +55,21 @@
pushLong(v);
}
else
pushNumber(-toFloat64(a));
pushNumber(-meta->toFloat64(a));
}
break;
case ePlus:
{
a = pop();
a = toGeneralNumber(a);
push(toGeneralNumber(a));
push(meta->toGeneralNumber(a));
}
break;
case eComplement:
{
a = pop();
a = toGeneralNumber(a);
a = meta->toGeneralNumber(a);
if (JS2VAL_IS_LONG(a)) {
int64 i = *JS2VAL_TO_LONG(a);
JSLL_NOT(i, i);
@ -83,7 +82,7 @@
pushULong(i);
}
else {
pushNumber(~toInteger(a));
pushNumber(~meta->toInteger(a));
}
}
}
@ -92,8 +91,8 @@
{
b = pop();
a = pop();
a = toGeneralNumber(a);
int32 count = toInteger(b);
a = meta->toGeneralNumber(a);
int32 count = meta->toInteger(b);
if (JS2VAL_IS_LONG(a)) {
int64 r;
JSLL_SHL(r, *JS2VAL_TO_LONG(a), count & 0x3F);
@ -106,15 +105,15 @@
pushULong(r);
}
else
pushNumber(toInteger(a) << (count & 0x1F));
pushNumber(meta->toInteger(a) << (count & 0x1F));
}
break;
case eRightShift:
{
b = pop();
a = pop();
a = toGeneralNumber(a);
int32 count = toInteger(b);
a = meta->toGeneralNumber(a);
int32 count = meta->toInteger(b);
if (JS2VAL_IS_LONG(a)) {
int64 r;
JSLL_SHR(r, *JS2VAL_TO_LONG(a), count & 0x3F);
@ -127,15 +126,15 @@
pushULong(r);
}
else
pushNumber(toInteger(a) >> (count & 0x1F));
pushNumber(meta->toInteger(a) >> (count & 0x1F));
}
break;
case eLogicalRightShift:
{
b = pop();
a = pop();
a = toGeneralNumber(a);
int32 count = toInteger(b);
a = meta->toGeneralNumber(a);
int32 count = meta->toInteger(b);
if (JS2VAL_IS_LONG(a)) {
int64 r;
JSLL_SHR(r, *JS2VAL_TO_LONG(a), count & 0x3F);
@ -148,15 +147,15 @@
pushULong(r);
}
else
pushNumber(toUInt32(toInteger(a)) >> (count & 0x1F));
pushNumber(toUInt32(meta->toInteger(a)) >> (count & 0x1F));
}
break;
case eBitwiseAnd:
{
b = pop();
a = pop();
a = toGeneralNumber(a);
b = toGeneralNumber(b);
a = meta->toGeneralNumber(a);
b = meta->toGeneralNumber(b);
if (JS2VAL_IS_LONG(a)) {
int64 x = *JS2VAL_TO_LONG(a);
if (JS2VAL_IS_LONG(b)) {
@ -205,7 +204,7 @@
}
}
else
pushNumber(toInteger(a) & toInteger(b));
pushNumber(meta->toInteger(a) & meta->toInteger(b));
}
}
break;
@ -213,8 +212,8 @@
{
b = pop();
a = pop();
a = toGeneralNumber(a);
b = toGeneralNumber(b);
a = meta->toGeneralNumber(a);
b = meta->toGeneralNumber(b);
if (JS2VAL_IS_LONG(a)) {
int64 x = *JS2VAL_TO_LONG(a);
if (JS2VAL_IS_LONG(b)) {
@ -263,7 +262,7 @@
}
}
else
pushNumber(toInteger(a) ^ toInteger(b));
pushNumber(meta->toInteger(a) ^ meta->toInteger(b));
}
}
break;
@ -271,8 +270,8 @@
{
b = pop();
a = pop();
a = toGeneralNumber(a);
b = toGeneralNumber(b);
a = meta->toGeneralNumber(a);
b = meta->toGeneralNumber(b);
if (JS2VAL_IS_LONG(a)) {
int64 x = *JS2VAL_TO_LONG(a);
if (JS2VAL_IS_LONG(b)) {
@ -321,7 +320,7 @@
}
}
else
pushNumber(toInteger(a) | toInteger(b));
pushNumber(meta->toInteger(a) | meta->toInteger(b));
}
}
break;
@ -330,18 +329,18 @@
{
b = pop();
a = pop();
a = toPrimitive(a);
b = toPrimitive(b);
a = meta->toPrimitive(a);
b = meta->toPrimitive(b);
if (JS2VAL_IS_STRING(a) || JS2VAL_IS_STRING(b)) {
const String *astr = toString(a);
const String *bstr = toString(b);
const String *astr = meta->toString(a);
const String *bstr = meta->toString(b);
String *c = allocStringPtr(astr);
*c += *bstr;
push(STRING_TO_JS2VAL(c));
}
else {
a = toGeneralNumber(a);
b = toGeneralNumber(b);
a = meta->toGeneralNumber(a);
b = meta->toGeneralNumber(b);
if (JS2VAL_IS_LONG(a)) {
int64 x = *JS2VAL_TO_LONG(a);
if (JS2VAL_IS_LONG(b)) {
@ -390,8 +389,8 @@
}
}
else {
float64 x = toFloat64(a);
float64 y = toFloat64(b);
float64 x = meta->toFloat64(a);
float64 y = meta->toFloat64(b);
float64 z = x + y;
if (JS2VAL_IS_FLOAT(a) || JS2VAL_IS_FLOAT(b))
pushFloat(z);
@ -407,8 +406,8 @@
{
b = pop();
a = pop();
a = toGeneralNumber(a);
b = toGeneralNumber(b);
a = meta->toGeneralNumber(a);
b = meta->toGeneralNumber(b);
if (JS2VAL_IS_LONG(a)) {
int64 x = *JS2VAL_TO_LONG(a);
if (JS2VAL_IS_LONG(b)) {
@ -457,8 +456,8 @@
}
}
else {
float64 x = toFloat64(a);
float64 y = toFloat64(b);
float64 x = meta->toFloat64(a);
float64 y = meta->toFloat64(b);
float64 z = x - y;
if (JS2VAL_IS_FLOAT(a) || JS2VAL_IS_FLOAT(b))
pushFloat(z);
@ -473,8 +472,8 @@
{
b = pop();
a = pop();
a = toGeneralNumber(a);
b = toGeneralNumber(b);
a = meta->toGeneralNumber(a);
b = meta->toGeneralNumber(b);
if (JS2VAL_IS_LONG(a)) {
int64 x = *JS2VAL_TO_LONG(a);
if (JS2VAL_IS_LONG(b)) {
@ -523,8 +522,8 @@
}
}
else {
float64 x = toFloat64(a);
float64 y = toFloat64(b);
float64 x = meta->toFloat64(a);
float64 y = meta->toFloat64(b);
float64 z = x * y;
if (JS2VAL_IS_FLOAT(a) || JS2VAL_IS_FLOAT(b))
pushFloat(z);
@ -539,8 +538,8 @@
{
b = pop();
a = pop();
a = toGeneralNumber(a);
b = toGeneralNumber(b);
a = meta->toGeneralNumber(a);
b = meta->toGeneralNumber(b);
if (JS2VAL_IS_LONG(a)) {
int64 x = *JS2VAL_TO_LONG(a);
if (JS2VAL_IS_LONG(b)) {
@ -589,8 +588,8 @@
}
}
else {
float64 x = toFloat64(a);
float64 y = toFloat64(b);
float64 x = meta->toFloat64(a);
float64 y = meta->toFloat64(b);
float64 z = x / y;
if (JS2VAL_IS_FLOAT(a) || JS2VAL_IS_FLOAT(b))
pushFloat(z);
@ -605,8 +604,8 @@
{
b = pop();
a = pop();
a = toGeneralNumber(a);
b = toGeneralNumber(b);
a = meta->toGeneralNumber(a);
b = meta->toGeneralNumber(b);
if (JS2VAL_IS_LONG(a)) {
int64 x = *JS2VAL_TO_LONG(a);
if (JS2VAL_IS_LONG(b)) {
@ -655,8 +654,8 @@
}
}
else {
float64 x = toFloat64(a);
float64 y = toFloat64(b);
float64 x = meta->toFloat64(a);
float64 y = meta->toFloat64(b);
float64 z;
#ifdef XP_PC
/* Workaround MS fmod bug where 42 % (1/0) => NaN, not 42. */
@ -678,14 +677,14 @@
{
b = pop();
a = pop();
push(BOOLEAN_TO_JS2VAL(toBoolean(a) ^ toBoolean(b)));
push(BOOLEAN_TO_JS2VAL(meta->toBoolean(a) ^ meta->toBoolean(b)));
}
break;
case eLogicalNot:
{
a = pop();
push(BOOLEAN_TO_JS2VAL(!toBoolean(a)));
push(BOOLEAN_TO_JS2VAL(!meta->toBoolean(a)));
}
break;
@ -693,13 +692,13 @@
{
b = pop();
a = pop();
a = toPrimitive(a);
b = toPrimitive(b);
a = meta->toPrimitive(a);
b = meta->toPrimitive(b);
bool rval;
if (JS2VAL_IS_STRING(a) && JS2VAL_IS_STRING(b))
rval = (*JS2VAL_TO_STRING(a) < *JS2VAL_TO_STRING(b));
else
rval = toFloat64(a) < toFloat64(b);
rval = meta->toFloat64(a) < meta->toFloat64(b);
push(BOOLEAN_TO_JS2VAL(rval));
}
break;
@ -708,13 +707,13 @@
{
b = pop();
a = pop();
a = toPrimitive(a);
b = toPrimitive(b);
a = meta->toPrimitive(a);
b = meta->toPrimitive(b);
bool rval;
if (JS2VAL_IS_STRING(a) && JS2VAL_IS_STRING(b))
rval = (*JS2VAL_TO_STRING(a) <= *JS2VAL_TO_STRING(b));
else
rval = toFloat64(a) <= toFloat64(b);
rval = meta->toFloat64(a) <= meta->toFloat64(b);
push(BOOLEAN_TO_JS2VAL(rval));
}
break;
@ -723,13 +722,13 @@
{
b = pop();
a = pop();
a = toPrimitive(a);
b = toPrimitive(b);
a = meta->toPrimitive(a);
b = meta->toPrimitive(b);
bool rval;
if (JS2VAL_IS_STRING(a) && JS2VAL_IS_STRING(b))
rval = (*JS2VAL_TO_STRING(a) > *JS2VAL_TO_STRING(b));
else
rval = toFloat64(a) > toFloat64(b);
rval = meta->toFloat64(a) > meta->toFloat64(b);
push(BOOLEAN_TO_JS2VAL(rval));
}
break;
@ -738,13 +737,13 @@
{
b = pop();
a = pop();
a = toPrimitive(a);
b = toPrimitive(b);
a = meta->toPrimitive(a);
b = meta->toPrimitive(b);
bool rval;
if (JS2VAL_IS_STRING(a) && JS2VAL_IS_STRING(b))
rval = (*JS2VAL_TO_STRING(a) >= *JS2VAL_TO_STRING(b));
else
rval = toFloat64(a) >= toFloat64(b);
rval = meta->toFloat64(a) >= meta->toFloat64(b);
push(BOOLEAN_TO_JS2VAL(rval));
}
break;
@ -762,29 +761,29 @@
if (JS2VAL_IS_BOOLEAN(b))
rval = (JS2VAL_TO_BOOLEAN(a) == JS2VAL_TO_BOOLEAN(b));
else {
b = toPrimitive(b);
b = meta->toPrimitive(b);
if (JS2VAL_IS_NULL(b) || JS2VAL_IS_UNDEFINED(b))
rval = false;
else
rval = (toFloat64(a) == toFloat64(b));
rval = (meta->toFloat64(a) == meta->toFloat64(b));
}
}
else
if (JS2VAL_IS_NUMBER(a)) {
b = toPrimitive(b);
b = meta->toPrimitive(b);
if (JS2VAL_IS_NULL(b) || JS2VAL_IS_UNDEFINED(b))
rval = false;
else
rval = (toFloat64(a) == toFloat64(b));
rval = (meta->toFloat64(a) == meta->toFloat64(b));
}
else
if (JS2VAL_IS_STRING(a)) {
b = toPrimitive(b);
b = meta->toPrimitive(b);
if (JS2VAL_IS_NULL(b) || JS2VAL_IS_UNDEFINED(b))
rval = false;
else
if (JS2VAL_IS_BOOLEAN(b) || JS2VAL_IS_NUMBER(b))
rval = (toFloat64(a) == toFloat64(b));
rval = (meta->toFloat64(a) == meta->toFloat64(b));
else
rval = (*JS2VAL_TO_STRING(a) == *JS2VAL_TO_STRING(b));
}
@ -793,31 +792,31 @@
rval = false;
else
if (JS2VAL_IS_BOOLEAN(b)) {
a = toPrimitive(a);
a = meta->toPrimitive(a);
if (JS2VAL_IS_NULL(a) || JS2VAL_IS_UNDEFINED(a))
rval = false;
else
if (JS2VAL_IS_BOOLEAN(a))
rval = (JS2VAL_TO_BOOLEAN(a) == JS2VAL_TO_BOOLEAN(b));
else
rval = (toFloat64(a) == toFloat64(b));
rval = (meta->toFloat64(a) == meta->toFloat64(b));
}
else
if (JS2VAL_IS_NUMBER(b)) {
a = toPrimitive(a);
a = meta->toPrimitive(a);
if (JS2VAL_IS_NULL(a) || JS2VAL_IS_UNDEFINED(a))
rval = false;
else
rval = (toFloat64(a) == toFloat64(b));
rval = (meta->toFloat64(a) == meta->toFloat64(b));
}
else
if (JS2VAL_IS_STRING(b)) {
a = toPrimitive(a);
a = meta->toPrimitive(a);
if (JS2VAL_IS_NULL(a) || JS2VAL_IS_UNDEFINED(a))
rval = false;
else
if (JS2VAL_IS_BOOLEAN(a) || JS2VAL_IS_NUMBER(a))
rval = (toFloat64(a) == toFloat64(b));
rval = (meta->toFloat64(a) == meta->toFloat64(b));
else
rval = (*JS2VAL_TO_STRING(a) == *JS2VAL_TO_STRING(b));
}
@ -850,7 +849,7 @@
push(a);
}
else {
float64 num = toFloat64(a);
float64 num = meta->toFloat64(a);
meta->env.lexicalWrite(meta, mn, allocNumber(num + 1.0), true, phase);
pushNumber(num);
}
@ -862,7 +861,7 @@
Multiname *mn = bCon->mMultinameList[BytecodeContainer::getShort(pc)];
pc += sizeof(short);
a = meta->env.lexicalRead(meta, mn, phase);
float64 num = toFloat64(a);
float64 num = meta->toFloat64(a);
meta->env.lexicalWrite(meta, mn, allocNumber(num - 1.0), true, phase);
pushNumber(num);
}
@ -872,7 +871,7 @@
Multiname *mn = bCon->mMultinameList[BytecodeContainer::getShort(pc)];
pc += sizeof(short);
a = meta->env.lexicalRead(meta, mn, phase);
float64 num = toFloat64(a);
float64 num = meta->toFloat64(a);
a = pushNumber(num + 1.0);
meta->env.lexicalWrite(meta, mn, a, true, phase);
}
@ -882,7 +881,7 @@
Multiname *mn = bCon->mMultinameList[BytecodeContainer::getShort(pc)];
pc += sizeof(short);
a = meta->env.lexicalRead(meta, mn, phase);
float64 num = toFloat64(a);
float64 num = meta->toFloat64(a);
a = pushNumber(num - 1.0);
meta->env.lexicalWrite(meta, mn, a, true, phase);
}
@ -896,7 +895,7 @@
baseVal = pop();
if (!meta->readProperty(baseVal, mn, &lookup, RunPhase, &a))
meta->reportError(Exception::propertyAccessError, "No property named {0}", errorPos(), mn->name);
float64 num = toFloat64(a);
float64 num = meta->toFloat64(a);
meta->writeProperty(baseVal, mn, &lookup, true, allocNumber(num + 1.0), RunPhase);
pushNumber(num);
baseVal = JS2VAL_VOID;
@ -910,7 +909,7 @@
baseVal = pop();
if (!meta->readProperty(baseVal, mn, &lookup, RunPhase, &a))
meta->reportError(Exception::propertyAccessError, "No property named {0}", errorPos(), mn->name);
float64 num = toFloat64(a);
float64 num = meta->toFloat64(a);
meta->writeProperty(baseVal, mn, &lookup, true, allocNumber(num - 1.0), RunPhase);
pushNumber(num);
baseVal = JS2VAL_VOID;
@ -924,7 +923,7 @@
baseVal = pop();
if (!meta->readProperty(baseVal, mn, &lookup, RunPhase, &a))
meta->reportError(Exception::propertyAccessError, "No property named {0}", errorPos(), mn->name);
float64 num = toFloat64(a);
float64 num = meta->toFloat64(a);
a = pushNumber(num + 1.0);
meta->writeProperty(baseVal, mn, &lookup, true, a, RunPhase);
baseVal = JS2VAL_VOID;
@ -938,7 +937,7 @@
baseVal = pop();
if (!meta->readProperty(baseVal, mn, &lookup, RunPhase, &a))
meta->reportError(Exception::propertyAccessError, "No property named {0}", errorPos(), mn->name);
float64 num = toFloat64(a);
float64 num = meta->toFloat64(a);
a = pushNumber(num - 1.0);
meta->writeProperty(baseVal, mn, &lookup, true, a, RunPhase);
baseVal = JS2VAL_VOID;
@ -950,11 +949,11 @@
LookupKind lookup(false, NULL);
indexVal = pop();
baseVal = pop();
const String *indexStr = toString(indexVal);
const String *indexStr = meta->toString(indexVal);
Multiname mn(&meta->world.identifiers[*indexStr], meta->publicNamespace);
if (!meta->readProperty(baseVal, &mn, &lookup, RunPhase, &a))
meta->reportError(Exception::propertyAccessError, "No property named {0}", errorPos(), mn.name);
float64 num = toFloat64(a);
float64 num = meta->toFloat64(a);
meta->writeProperty(baseVal, &mn, &lookup, true, allocNumber(num + 1.0), RunPhase);
pushNumber(num);
baseVal = JS2VAL_VOID;
@ -966,11 +965,11 @@
LookupKind lookup(false, NULL);
indexVal = pop();
baseVal = pop();
const String *indexStr = toString(indexVal);
const String *indexStr = meta->toString(indexVal);
Multiname mn(&meta->world.identifiers[*indexStr], meta->publicNamespace);
if (!meta->readProperty(baseVal, &mn, &lookup, RunPhase, &a))
meta->reportError(Exception::propertyAccessError, "No property named {0}", errorPos(), mn.name);
float64 num = toFloat64(a);
float64 num = meta->toFloat64(a);
meta->writeProperty(baseVal, &mn, &lookup, true, allocNumber(num - 1.0), RunPhase);
pushNumber(num);
baseVal = JS2VAL_VOID;
@ -982,11 +981,11 @@
LookupKind lookup(false, NULL);
indexVal = pop();
baseVal = pop();
const String *indexStr = toString(indexVal);
const String *indexStr = meta->toString(indexVal);
Multiname mn(&meta->world.identifiers[*indexStr], meta->publicNamespace);
if (!meta->readProperty(baseVal, &mn, &lookup, RunPhase, &a))
meta->reportError(Exception::propertyAccessError, "No property named {0}", errorPos(), mn.name);
float64 num = toFloat64(a);
float64 num = meta->toFloat64(a);
a = pushNumber(num + 1.0);
meta->writeProperty(baseVal, &mn, &lookup, true, a, RunPhase);
baseVal = JS2VAL_VOID;
@ -998,11 +997,11 @@
LookupKind lookup(false, NULL);
indexVal = pop();
baseVal = pop();
const String *indexStr = toString(indexVal);
const String *indexStr = meta->toString(indexVal);
Multiname mn(&meta->world.identifiers[*indexStr], meta->publicNamespace);
if (!meta->readProperty(baseVal, &mn, &lookup, RunPhase, &a))
meta->reportError(Exception::propertyAccessError, "No property named {0}", errorPos(), mn.name);
float64 num = toFloat64(a);
float64 num = meta->toFloat64(a);
a = pushNumber(num - 1.0);
meta->writeProperty(baseVal, &mn, &lookup, true, a, RunPhase);
baseVal = JS2VAL_VOID;

Просмотреть файл

@ -34,7 +34,7 @@
case eBranchTrue:
{
a = pop();
bool c = toBoolean(a);
bool c = meta->toBoolean(a);
if (c) {
int32 offset = BytecodeContainer::getOffset(pc);
pc += offset;
@ -47,7 +47,7 @@
case eBranchFalse:
{
a = pop();
bool c = toBoolean(a);
bool c = meta->toBoolean(a);
if (!c) {
int32 offset = BytecodeContainer::getOffset(pc);
pc += offset;
@ -82,7 +82,7 @@
case eFirst:
{
a = pop();
b = toObject(a);
b = meta->toObject(a);
ForIteratorObject *fi = new ForIteratorObject(JS2VAL_TO_OBJECT(b));
push(OBJECT_TO_JS2VAL(fi));
push(BOOLEAN_TO_JS2VAL(fi->first()));

Просмотреть файл

@ -37,12 +37,12 @@
{
uint16 argCount = BytecodeContainer::getShort(pc);
pc += sizeof(uint16);
a = top();
a = top(argCount + 1);
ASSERT(JS2VAL_IS_OBJECT(a) && !JS2VAL_IS_NULL(a));
JS2Object *obj = JS2VAL_TO_OBJECT(a);
if (obj->kind == ClassKind) {
JS2Class *c = checked_cast<JS2Class *>(obj);
a = c->construct(meta, JS2VAL_NULL, NULL, argCount);
a = c->construct(meta, JS2VAL_NULL, base(argCount), argCount);
pop(argCount + 1);
push(a);
}
@ -94,11 +94,11 @@
uint16 argCount = BytecodeContainer::getShort(pc);
pc += sizeof(uint16);
a = top(argCount + 2); // 'this'
b = top(argCount + 1); // target function
b = top(argCount + 1); // target function
if (JS2VAL_IS_PRIMITIVE(b))
meta->reportError(Exception::badValueError, "Can't call on primitive value", errorPos());
JS2Object *fObj = JS2VAL_TO_OBJECT(b);
if (fObj->kind == FixedInstanceKind) {
if ((fObj->kind == FixedInstanceKind) && (meta->objectType(b) == meta->functionClass)) {
FixedInstance *fInst = checked_cast<FixedInstance *>(fObj);
FunctionWrapper *fWrap = fInst->fWrap;
js2val compileThis = fWrap->compileFrame->thisObject;

Просмотреть файл

@ -73,6 +73,14 @@
}
break;
case eRegExp:
{
RegExpInstance *x = bCon->mRegExpList[BytecodeContainer::getShort(pc)];
push(OBJECT_TO_JS2VAL(x));
pc += sizeof(short);
}
break;
case eNull:
{
push(JS2VAL_NULL);

Просмотреть файл

@ -134,23 +134,23 @@ namespace MetaData {
if (argc > 0) {
int32 index = 0;
const String *str = meta->engine->toString(argv[0]);
const String *str = meta->engine->meta->toString(argv[0]);
js2val globalMultiline = thisInst->getMultiline(meta);
if (thisInst->getGlobal(meta)) {
js2val lastIndex = thisInst->getLastIndex(meta);
index = meta->engine->toInteger(lastIndex);
index = meta->engine->meta->toInteger(lastIndex);
}
REMatchState *match = REExecute(thisInst->mRegExp, str->begin(), index, toInt32(str->length()), meta->engine->toBoolean(globalMultiline));
REMatchState *match = REExecute(thisInst->mRegExp, str->begin(), index, toInt32(str->length()), meta->toBoolean(globalMultiline));
if (match) {
PrototypeInstance *A = new PrototypeInstance(meta->objectClass->prototype, meta->objectClass);
result = OBJECT_TO_JS2VAL(A);
js2val matchStr = meta->engine->allocString(str->substr((uint32)match->startIndex, (uint32)match->endIndex - match->startIndex));
Multiname mname(&meta->world.identifiers[*numberToString((long)0)], meta->publicNamespace);
Multiname mname(&meta->world.identifiers[*meta->toString((long)0)], meta->publicNamespace);
meta->writeDynamicProperty(A, &mname, true, matchStr, RunPhase);
for (int32 i = 0; i < match->parenCount; i++) {
Multiname mname(&meta->world.identifiers[*numberToString(i + 1)], meta->publicNamespace);
Multiname mname(&meta->world.identifiers[*meta->toString(i + 1)], meta->publicNamespace);
if (match->parens[i].index != -1) {
js2val parenStr = meta->engine->allocString(str->substr((uint32)(match->parens[i].index), (uint32)(match->parens[i].length)));
meta->writeDynamicProperty(A, &mname, true, parenStr, RunPhase);
@ -182,5 +182,52 @@ namespace MetaData {
return result;
}
js2val RegExp_Constructor(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc)
{
// XXX Change constructors to take js2val pointer for the result (which would be an already
// rooted pointer).
RegExpInstance *thisInst = new RegExpInstance(meta->regexpClass);
JS2Object::RootIterator ri = JS2Object::addRoot(&thisInst);
js2val thatValue = OBJECT_TO_JS2VAL(thisInst);
REuint32 flags = 0;
const String *regexpStr = meta->engine->Empty_StringAtom;
const String *flagStr = meta->engine->Empty_StringAtom;
if (argc > 0) {
if (meta->objectType(argv[0]) == meta->regexpClass) {
if ((argc == 1) || JS2VAL_IS_UNDEFINED(argv[1])) {
RegExpInstance *otherInst = checked_cast<RegExpInstance *>(JS2VAL_TO_OBJECT(argv[0]));
js2val src = otherInst->getSource(meta);
ASSERT(JS2VAL_IS_STRING(src));
regexpStr = JS2VAL_TO_STRING(src);
flags = otherInst->mRegExp->flags;
}
else
meta->reportError(Exception::typeError, "Illegal RegExp constructor args", meta->engine->errorPos());
}
else
regexpStr = meta->toString(argv[0]);
if ((argc > 1) && !JS2VAL_IS_UNDEFINED(argv[1])) {
flagStr = meta->toString(argv[1]);
if (parseFlags(flagStr->begin(), (int32)flagStr->length(), &flags) != RE_NO_ERROR)
meta->reportError(Exception::syntaxError, "Failed to parse RegExp : '{0}'", meta->engine->errorPos(), *regexpStr + "/" + *flagStr); // XXX error message?
}
}
REState *pState = REParse(regexpStr->begin(), (int32)regexpStr->length(), flags, RE_VERSION_1);
if (pState) {
thisInst->mRegExp = pState;
// XXX ECMA spec says these are DONTENUM
thisInst->setSource(meta, STRING_TO_JS2VAL(regexpStr));
thisInst->setGlobal(meta, BOOLEAN_TO_JS2VAL((pState->flags & RE_GLOBAL) == RE_GLOBAL));
thisInst->setIgnoreCase(meta, BOOLEAN_TO_JS2VAL((pState->flags & RE_IGNORECASE) == RE_IGNORECASE));
thisInst->setLastIndex(meta, INT_TO_JS2VAL(0));
thisInst->setMultiline(meta, BOOLEAN_TO_JS2VAL((pState->flags & RE_MULTILINE) == RE_MULTILINE));
}
else
meta->reportError(Exception::syntaxError, "Failed to parse RegExp : '{0}'", meta->engine->errorPos(), "/" + *regexpStr + "/" + *flagStr); // XXX what about the RE parser error message?
JS2Object::removeRoot(ri);
return thatValue;
}
}
}

Просмотреть файл

@ -65,9 +65,9 @@ js2val String_Constructor(JS2Metadata *meta, const js2val /*thisValue*/, js2val
StringInstance *strInst = checked_cast<StringInstance *>(JS2VAL_TO_OBJECT(thatValue));
if (argc > 0)
strInst->mValue = meta->engine->allocStringPtr(meta->engine->toString(argv[0]));
strInst->mValue = meta->engine->allocStringPtr(meta->engine->meta->toString(argv[0]));
else
strInst->mValue = meta->engine->allocStringPtr((String *)NULL);
strInst->mValue = meta->engine->allocStringPtr("");
return thatValue;
}
@ -109,7 +109,7 @@ static js2val String_valueOf(JS2Metadata *meta, const js2val thisValue, js2val *
*/
static js2val String_search(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc)
{
js2val S = STRING_TO_JS2VAL(meta->engine->toString(thisValue));
js2val S = STRING_TO_JS2VAL(meta->engine->meta->toString(thisValue));
js2val regexp = argv[0];
@ -144,7 +144,7 @@ static js2val String_search(JS2Metadata *meta, const js2val thisValue, js2val *a
static js2val String_match(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc)
{
js2val S = STRING_TO_JS2VAL(meta->engine->toString(thisValue));
js2val S = STRING_TO_JS2VAL(meta->engine->meta->toString(thisValue));
js2val regexp = argv[0];
if ((argc == 0) || (meta->objectType(thisValue) != meta->regexpClass)) {
@ -170,7 +170,7 @@ static js2val String_match(JS2Metadata *meta, const js2val thisValue, js2val *ar
else
lastIndex = match->endIndex;
js2val matchStr = meta->engine->allocString(JS2VAL_TO_STRING(S)->substr(toUInt32(match->startIndex), toUInt32(match->endIndex) - match->startIndex));
Multiname mname(&meta->world.identifiers[*numberToString(index)], meta->publicNamespace);
Multiname mname(&meta->world.identifiers[*meta->toString(index)], meta->publicNamespace);
index++;
meta->writeDynamicProperty(A, &mname, true, matchStr, RunPhase);
}
@ -179,14 +179,13 @@ static js2val String_match(JS2Metadata *meta, const js2val thisValue, js2val *ar
}
}
#if 0
static const String interpretDollar(JS2Metadata *meta, const String *replaceStr, uint32 dollarPos, const String *searchStr, REMatchState *match, uint32 &skip)
{
skip = 2;
const char16 *dollarValue = replaceStr->begin() + dollarPos + 1;
switch (*dollarValue) {
case '$':
return meta->engine->Dollar_StringAtom;
return *meta->engine->Dollar_StringAtom;
case '&':
return searchStr->substr((uint32)match->startIndex, (uint32)match->endIndex - match->startIndex);
case '`':
@ -220,7 +219,7 @@ static const String interpretDollar(JS2Metadata *meta, const String *replaceStr,
// fall thru
default:
skip = 1;
return meta->engine->Dollar_StringAtom;
return *meta->engine->Dollar_StringAtom;
}
}
@ -235,7 +234,7 @@ static const String interpretDollar(JS2Metadata *meta, const String *replaceStr,
* in the same manner as in String.prototype.match, including the update of searchValue.lastIndex. Let m
* be the number of left capturing parentheses in searchValue (NCapturingParens as specified in section 15.10.2.1).
*
* If searchValue is not a regular expression, let searchString be ToString(searchValue) and search string for the first
* If searchValue is not a regular expression, let searchString be meta->toString(searchValue) and search string for the first
* occurrence of searchString. Let m be 0.
*
* If replaceValue is a function, then for each matched substring, call the function with the following m + 3 arguments.
@ -255,19 +254,19 @@ static const String interpretDollar(JS2Metadata *meta, const String *replaceStr,
static js2val String_replace(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc)
{
const String *S = meta->engine->toString(thisValue);
const String *S = meta->engine->meta->toString(thisValue);
js2val searchValue;
js2val replaceValue;
if (argc > 0) searchValue = argv[0];
if (argc > 1) replaceValue = argv[1];
const String *replaceStr = meta->engine->toString(replaceValue);
const String *replaceStr = meta->engine->meta->toString(replaceValue);
if (meta->objectType(searchValue) != meta->regexpClass) {
REState *pState = (checked_cast<RegExpInstance *>(JS2VAL_TO_OBJECT(searchValue)))->mRegExp;
RegExpInstance *reInst = checked_cast<RegExpInstance *>(JS2VAL_TO_OBJECT(searchValue));
REState *pState = reInst->mRegExp;
REMatchState *match;
// uint32 m = pState->parenCount;
String newString;
int32 lastIndex = 0;
@ -282,7 +281,7 @@ static js2val String_replace(JS2Metadata *meta, const js2val thisValue, js2val *
if ((dollarPos != String::npos) && (dollarPos < (replaceStr->length() - 1))) {
uint32 skip;
insertString += replaceStr->substr(start, dollarPos - start);
insertString += interpretDollar(cx, replaceStr, dollarPos, S, match, skip);
insertString += interpretDollar(meta, replaceStr, dollarPos, S, match, skip);
start = dollarPos + skip;
}
else {
@ -304,11 +303,11 @@ static js2val String_replace(JS2Metadata *meta, const js2val thisValue, js2val *
}
newString += S->substr(toUInt32(lastIndex), toUInt32(S->length()) - lastIndex);
if ((pState->flags & RE_GLOBAL) == 0)
JS2VAL_TO_OBJECT(searchValue)->setProperty(cx, cx->LastIndex_StringAtom, NULL, JSValue::newNumber((float64)lastIndex));
reInst->setLastIndex(meta, meta->engine->allocNumber((float64)lastIndex));
return meta->engine->allocString(newString);
}
else {
const String *searchStr = JSValue::string(JSValue::toString(cx, searchValue));
const String *searchStr = meta->engine->meta->toString(searchValue);
REMatchState match;
uint32 pos = S->find(*searchStr, 0);
if (pos == String::npos)
@ -324,7 +323,7 @@ static js2val String_replace(JS2Metadata *meta, const js2val thisValue, js2val *
if ((dollarPos != String::npos) && (dollarPos < (replaceStr->length() - 1))) {
uint32 skip;
insertString += replaceStr->substr(start, dollarPos - start);
insertString += interpretDollar(cx, replaceStr, dollarPos, S, &match, skip);
insertString += interpretDollar(meta, replaceStr, dollarPos, S, &match, skip);
start = dollarPos + skip;
}
else {
@ -365,7 +364,7 @@ static void strSplitMatch(const String *S, uint32 q, const String *R, MatchResul
result.failure = false;
}
static void regexpSplitMatch(const String *S, uint32 q, REState *RE, MatchResult &result)
static void regexpSplitMatch(JS2Metadata *meta, const String *S, uint32 q, REState *RE, MatchResult &result)
{
result.failure = true;
result.captures = NULL;
@ -392,10 +391,11 @@ static void regexpSplitMatch(const String *S, uint32 q, REState *RE, MatchResult
static js2val String_split(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc)
{
const String *S = meta->engine->toString(thisValue);
const String *S = meta->engine->meta->toString(thisValue);
js2val result = OBJECT_TO_JS2VAL(new ArrayInstance(meta->arrayClass));
ArrayInstance *A = checked_cast<ArrayInstance *>(JS2VAL_TO_OBJECT(result));
js2val result = Array_Type->newInstance(cx);
JSArrayInstance *A = checked_cast<JSArrayInstance *>(JSValue::instance(result));
uint32 lim;
js2val separatorV = (argc > 0) ? argv[0] : JS2VAL_UNDEFINED;
js2val limitV = (argc > 1) ? argv[1] : JS2VAL_UNDEFINED;
@ -413,7 +413,7 @@ static js2val String_split(JS2Metadata *meta, const js2val thisValue, js2val *ar
if (meta->objectType(separatorV) == meta->regexpClass)
RE = (checked_cast<RegExpInstance *>(JS2VAL_TO_OBJECT(separatorV)))->mRegExp;
else
R = meta->engine->toString(separatorV);
R = meta->engine->meta->toString(separatorV);
if (lim == 0)
return result;
@ -425,15 +425,18 @@ static js2val String_split(JS2Metadata *meta, const js2val thisValue, js2val *ar
return JSValue(A);
}
*/
Multiname mn(NULL, meta->publicNamespace);
if (s == 0) {
MatchResult z;
if (RE)
regexpSplitMatch(S, 0, RE, z);
regexpSplitMatch(meta, S, 0, RE, z);
else
strSplitMatch(S, 0, R, z);
if (!z.failure)
return result;
A->setProperty(cx, widenCString("0"), NULL, STRING_TO_JS2VAL(S));
mn.name = meta->toString((int32)0);
meta->writeDynamicProperty(A, &mn, true, STRING_TO_JS2VAL(S), RunPhase);
delete mn.name;
return result;
}
@ -441,14 +444,15 @@ static js2val String_split(JS2Metadata *meta, const js2val thisValue, js2val *ar
uint32 q = p;
step11:
if (q == s) {
String *T = meta->engine->allocString(*S, p, (s - p));
js2val v = STRING_TO_JS2VAL(T);
A->setProperty(cx, *numberToString(A->mLength), NULL, v);
js2val v = meta->engine->allocString(new String(*S, p, (s - p)));
mn.name = meta->toString(getLength(meta, A));
meta->writeDynamicProperty(A, &mn, true, v, RunPhase);
delete mn.name;
return result;
}
MatchResult z;
if (RE)
regexpSplitMatch(S, q, RE, z);
regexpSplitMatch(meta, S, q, RE, z);
else
strSplitMatch(S, q, R, z);
if (z.failure) {
@ -462,27 +466,30 @@ step11:
}
String *T = meta->engine->allocStringPtr(new String(*S, p, (q - p))); // XXX
js2val v = STRING_TO_JS2VAL(T);
A->setProperty(cx, *numberToString(A->mLength), NULL, v);
if (A->mLength == lim)
mn.name = meta->toString(getLength(meta, A));
meta->writeDynamicProperty(A, &mn, true, v, RunPhase);
delete mn.name;
if (getLength(meta, A) == lim)
return result;
p = e;
for (uint32 i = 0; i < z.capturesCount; i++) {
A->setProperty(cx, *numberToString(A->mLength), NULL, z.captures[i]);
if (A->mLength == lim)
mn.name = meta->toString(getLength(meta, A));
meta->writeDynamicProperty(A, &mn, true, z.captures[i], RunPhase);
delete mn.name;
if (getLength(meta, A) == lim)
return result;
}
}
}
#endif
static js2val String_charAt(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc)
{
const String *str = meta->engine->toString(thisValue);
const String *str = meta->engine->meta->toString(thisValue);
uint32 pos = 0;
if (argc > 0)
pos = toUInt32(meta->engine->toInteger(argv[0]));
pos = toUInt32(meta->toInteger(argv[0]));
if ((pos < 0) || (pos >= str->size()))
return STRING_TO_JS2VAL(meta->engine->Empty_StringAtom);
@ -493,11 +500,11 @@ static js2val String_charAt(JS2Metadata *meta, const js2val thisValue, js2val *a
static js2val String_charCodeAt(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc)
{
const String *str = meta->engine->toString(thisValue);
const String *str = meta->toString(thisValue);
uint32 pos = 0;
if (argc > 0)
pos = toUInt32(meta->engine->toInteger(argv[0]));
pos = toUInt32(meta->toInteger(argv[0]));
if ((pos < 0) || (pos >= str->size()))
return meta->engine->nanValue;
@ -507,11 +514,11 @@ static js2val String_charCodeAt(JS2Metadata *meta, const js2val thisValue, js2va
static js2val String_concat(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc)
{
const String *str = meta->engine->toString(thisValue);
const String *str = meta->toString(thisValue);
String *result = meta->engine->allocStringPtr(str);
for (uint32 i = 0; i < argc; i++) {
*result += *meta->engine->toString(argv[i]);
*result += *meta->toString(argv[i]);
}
return STRING_TO_JS2VAL(result);
@ -522,12 +529,12 @@ static js2val String_indexOf(JS2Metadata *meta, const js2val thisValue, js2val *
if (argc == 0)
return meta->engine->allocNumber(-1.0);
const String *str = meta->engine->toString(thisValue);
const String *searchStr = meta->engine->toString(argv[0]);
const String *str = meta->toString(thisValue);
const String *searchStr = meta->toString(argv[0]);
uint32 pos = 0;
if (argc > 1) {
float64 fpos = meta->engine->toFloat64(argv[1]);
float64 fpos = meta->toFloat64(argv[1]);
if (JSDOUBLE_IS_NaN(fpos))
pos = 0;
if (fpos < 0)
@ -549,12 +556,12 @@ static js2val String_lastIndexOf(JS2Metadata *meta, const js2val thisValue, js2v
if (argc == 0)
return meta->engine->allocNumber(-1.0);
const String *str = meta->engine->toString(thisValue);
const String *searchStr = meta->engine->toString(argv[0]);
const String *str = meta->toString(thisValue);
const String *searchStr = meta->toString(argv[0]);
uint32 pos = str->size();
if (argc > 1) {
float64 fpos = meta->engine->toFloat64(argv[1]);
float64 fpos = meta->toFloat64(argv[1]);
if (JSDOUBLE_IS_NaN(fpos))
pos = str->size();
else {
@ -580,7 +587,7 @@ static js2val String_localeCompare(JS2Metadata *meta, const js2val /*thisValue*/
static js2val String_toLowerCase(JS2Metadata *meta, const js2val thisValue, js2val * /*argv*/, uint32 /*argc*/)
{
js2val S = STRING_TO_JS2VAL(meta->engine->toString(thisValue));
js2val S = STRING_TO_JS2VAL(meta->toString(thisValue));
String *result = meta->engine->allocStringPtr(JS2VAL_TO_STRING(S));
for (String::iterator i = result->begin(), end = result->end(); i != end; i++)
@ -591,7 +598,7 @@ static js2val String_toLowerCase(JS2Metadata *meta, const js2val thisValue, js2v
static js2val String_toUpperCase(JS2Metadata *meta, const js2val thisValue, js2val * /*argv*/, uint32 /*argc*/)
{
js2val S = STRING_TO_JS2VAL(meta->engine->toString(thisValue));
js2val S = STRING_TO_JS2VAL(meta->toString(thisValue));
String *result = meta->engine->allocStringPtr(JS2VAL_TO_STRING(S));
for (String::iterator i = result->begin(), end = result->end(); i != end; i++)
@ -623,13 +630,13 @@ static js2val String_toUpperCase(JS2Metadata *meta, const js2val thisValue, js2v
static js2val String_slice(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc)
{
const String *sourceString = meta->engine->toString(thisValue);
const String *sourceString = meta->toString(thisValue);
uint32 sourceLength = sourceString->size();
uint32 start, end;
if (argc > 0) {
int32 arg0 = meta->engine->toInteger(argv[0]);
int32 arg0 = meta->toInteger(argv[0]);
if (arg0 < 0) {
arg0 += sourceLength;
if (arg0 < 0)
@ -648,7 +655,7 @@ static js2val String_slice(JS2Metadata *meta, const js2val thisValue, js2val *ar
start = 0; // XXX argc must be > 1 since the length of the function is 1
if (argc > 1) {
int32 arg1 = meta->engine->toInteger(argv[1]);
int32 arg1 = meta->toInteger(argv[1]);
if (arg1 < 0) {
arg1 += sourceLength;
if (arg1 < 0)
@ -695,20 +702,20 @@ static js2val String_slice(JS2Metadata *meta, const js2val thisValue, js2val *ar
static js2val String_substring(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc)
{
const String *sourceString = meta->engine->toString(thisValue);
const String *sourceString = meta->toString(thisValue);
uint32 sourceLength = sourceString->size();
uint32 start, end;
if (argc > 0) {
float64 farg0 = meta->engine->toFloat64(argv[0]);
float64 farg0 = meta->toFloat64(argv[0]);
if (JSDOUBLE_IS_NaN(farg0) || (farg0 < 0))
start = 0;
else {
if (!JSDOUBLE_IS_FINITE(farg0))
start = sourceLength;
else {
start = meta->engine->toUInt32(farg0);
start = JS2Engine::toUInt32(farg0);
if (start > sourceLength)
start = sourceLength;
}
@ -718,14 +725,14 @@ static js2val String_substring(JS2Metadata *meta, const js2val thisValue, js2val
start = 0;
if (argc > 1) {
float64 farg1 = meta->engine->toFloat64(argv[1]);
float64 farg1 = meta->toFloat64(argv[1]);
if (JSDOUBLE_IS_NaN(farg1) || (farg1 < 0))
end = 0;
else {
if (!JSDOUBLE_IS_FINITE(farg1))
end = sourceLength;
else {
end = meta->engine->toUInt32(farg1);
end = JS2Engine::toUInt32(farg1);
if (end > sourceLength)
end = sourceLength;
}
@ -762,13 +769,11 @@ void initStringObject(JS2Metadata *meta)
{ "indexOf", 2, String_indexOf }, // XXX ECMA spec says 1, but tests want 2 XXX
{ "lastIndexOf", 2, String_lastIndexOf }, // XXX ECMA spec says 1, but tests want 2 XXX
{ "localeCompare", 1, String_localeCompare },
#if 0
{ "match", 1, String_match },
{ "replace", 2, String_replace },
{ "search", 1, String_search },
{ "slice", 2, String_slice },
{ "split", 1, String_split }, // XXX ECMA spec says 2, but tests want 1 XXX
#endif
{ "substring", 2, String_substring },
{ "toSource", 0, String_toString },
{ "toLocaleUpperCase", 0, String_toUpperCase }, // (sic)