bug 594060, r=cdleary: Reflect.parse(): make source location information optional

This commit is contained in:
Dave Herman 2010-10-19 09:00:51 -07:00
parent f03fe920ff
commit 7488e1af91
11 changed files with 208 additions and 26 deletions

View File

@ -60,6 +60,7 @@ CPPSRCS = \
testExtendedEq.cpp \
testFuncCallback.cpp \
testGCChunkAlloc.cpp \
testGetPropertyDefault.cpp \
testIntString.cpp \
testIsAboutToBeFinalized.cpp \
testLookup.cpp \

View File

@ -0,0 +1,70 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sw=4 et tw=99:
*/
#include "tests.h"
#define JSVAL_IS_FALSE(x) ((JSVAL_IS_BOOLEAN(x)) && !(JSVAL_TO_BOOLEAN(x)))
#define JSVAL_IS_TRUE(x) ((JSVAL_IS_BOOLEAN(x)) && (JSVAL_TO_BOOLEAN(x)))
static JSBool
stringToId(JSContext *cx, const char *s, jsid *idp)
{
char *buf = JS_strdup(cx, s);
if (!buf)
return false;
JSString *str = JS_NewString(cx, buf, strlen(s));
if (!str)
return false;
return JS_ValueToId(cx, STRING_TO_JSVAL(str), idp);
}
BEGIN_TEST(testGetPropertyDefault_bug594060)
{
{
// Check JS_GetPropertyDefault
JSObject *obj = JS_NewObject(cx, NULL, NULL, NULL);
CHECK(obj);
jsval v0 = JSVAL_TRUE;
CHECK(JS_SetProperty(cx, obj, "here", &v0));
jsval v1;
CHECK(JS_GetPropertyDefault(cx, obj, "here", JSVAL_FALSE, &v1));
CHECK(JSVAL_IS_TRUE(v1));
jsval v2;
CHECK(JS_GetPropertyDefault(cx, obj, "nothere", JSVAL_FALSE, &v2));
CHECK(JSVAL_IS_FALSE(v2));
}
{
// Check JS_GetPropertyByIdDefault
JSObject *obj = JS_NewObject(cx, NULL, NULL, NULL);
CHECK(obj);
jsid hereid;
CHECK(stringToId(cx, "here", &hereid));
jsid nothereid;
CHECK(stringToId(cx, "nothere", &nothereid));
jsval v0 = JSVAL_TRUE;
CHECK(JS_SetPropertyById(cx, obj, hereid, &v0));
jsval v1;
CHECK(JS_GetPropertyByIdDefault(cx, obj, hereid, JSVAL_FALSE, &v1));
CHECK(JSVAL_IS_TRUE(v1));
jsval v2;
CHECK(JS_GetPropertyByIdDefault(cx, obj, nothereid, JSVAL_FALSE, &v2));
CHECK(JSVAL_IS_FALSE(v2));
}
return true;
}
END_TEST(testGetPropertyDefault_bug594060)

View File

@ -3752,6 +3752,12 @@ JS_GetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
return obj->getProperty(cx, id, Valueify(vp));
}
JS_PUBLIC_API(JSBool)
JS_GetPropertyByIdDefault(JSContext *cx, JSObject *obj, jsid id, jsval def, jsval *vp)
{
return GetPropertyDefault(cx, obj, id, Valueify(def), Valueify(vp));
}
JS_PUBLIC_API(JSBool)
JS_GetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
{
@ -3765,6 +3771,13 @@ JS_GetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
return atom && JS_GetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
}
JS_PUBLIC_API(JSBool)
JS_GetPropertyDefault(JSContext *cx, JSObject *obj, const char *name, jsval def, jsval *vp)
{
JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
return atom && JS_GetPropertyByIdDefault(cx, obj, ATOM_TO_JSID(atom), def, vp);
}
JS_PUBLIC_API(JSBool)
JS_GetUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval *vp)
{

View File

@ -2059,9 +2059,15 @@ JS_GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, jsval *vp);
extern JS_PUBLIC_API(JSBool)
JS_GetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp);
extern JS_PUBLIC_API(JSBool)
JS_GetPropertyDefault(JSContext *cx, JSObject *obj, const char *name, jsval def, jsval *vp);
extern JS_PUBLIC_API(JSBool)
JS_GetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp);
extern JS_PUBLIC_API(JSBool)
JS_GetPropertyByIdDefault(JSContext *cx, JSObject *obj, jsid id, jsval def, jsval *vp);
extern JS_PUBLIC_API(JSBool)
JS_GetMethodById(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
jsval *vp);

View File

@ -179,6 +179,8 @@ const char *const js_common_atom_names[] = {
js_value_str, /* valueAtom */
js_test_str, /* testAtom */
"use strict", /* useStrictAtom */
"loc", /* locAtom */
"line", /* lineAtom */
#if JS_HAS_XML_SUPPORT
js_etago_str, /* etagoAtom */

View File

@ -372,6 +372,8 @@ struct JSAtomState
JSAtom *valueAtom;
JSAtom *testAtom;
JSAtom *useStrictAtom;
JSAtom *locAtom;
JSAtom *lineAtom;
#if JS_HAS_XML_SUPPORT
JSAtom *etagoAtom;

View File

@ -2907,6 +2907,23 @@ class AutoReleasePtr {
~AutoReleasePtr() { cx->free(ptr); }
};
/*
* FIXME: bug 602774: cleaner API for AutoReleaseNullablePtr
*/
class AutoReleaseNullablePtr {
JSContext *cx;
void *ptr;
AutoReleaseNullablePtr operator=(const AutoReleaseNullablePtr &other);
public:
explicit AutoReleaseNullablePtr(JSContext *cx, void *ptr) : cx(cx), ptr(ptr) {}
void reset(void *ptr2) {
if (ptr)
cx->free(ptr);
ptr = ptr2;
}
~AutoReleaseNullablePtr() { if (ptr) cx->free(ptr); }
};
class AutoLocalNameArray {
public:
explicit AutoLocalNameArray(JSContext *cx, JSFunction *fun

View File

@ -5151,6 +5151,23 @@ js_GetProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
return js_GetPropertyHelperInline(cx, obj, id, JSGET_METHOD_BARRIER, vp);
}
JSBool
js::GetPropertyDefault(JSContext *cx, JSObject *obj, jsid id, Value def, Value *vp)
{
JSProperty *prop;
JSObject *obj2;
if (js_LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop) < 0)
return false;
if (!prop) {
*vp = def;
return true;
}
obj2->dropProperty(cx, prop);
return js_GetProperty(cx, obj2, id, vp);
}
JSBool
js_GetMethod(JSContext *cx, JSObject *obj, jsid id, uintN getHow, Value *vp)
{

View File

@ -212,6 +212,13 @@ js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, const js::Value *value,
extern JSBool
js_GetProperty(JSContext *cx, JSObject *obj, jsid id, js::Value *vp);
namespace js {
extern JSBool
GetPropertyDefault(JSContext *cx, JSObject *obj, jsid id, Value def, Value *vp);
} /* namespace js */
extern JSBool
js_SetProperty(JSContext *cx, JSObject *obj, jsid id, js::Value *vp, JSBool strict);

View File

@ -61,6 +61,7 @@
#include "jsval.h"
#include "jsvalue.h"
#include "jsobjinlines.h"
#include "jsobj.h"
#include "jsarray.h"
#include "jsnum.h"
@ -160,12 +161,13 @@ typedef Vector<Value, 8> NodeVector;
class NodeBuilder
{
JSContext *cx;
char const *src; /* source filename or null */
Value srcval; /* source filename JS value or null */
bool saveLoc; /* save source location information? */
char const *src; /* source filename or null */
Value srcval; /* source filename JS value or null */
public:
NodeBuilder(JSContext *c, char const *s)
: cx(c), src(s) {
NodeBuilder(JSContext *c, bool l, char const *s)
: cx(c), saveLoc(l), src(s) {
}
bool init() {
@ -533,7 +535,7 @@ NodeBuilder::newArray(NodeVector &elts, Value *dst)
bool
NodeBuilder::setNodeLoc(JSObject *node, TokenPos *pos)
{
if (!pos)
if (!saveLoc || !pos)
return setProperty(node, "loc", NullValue());
JSObject *loc, *to;
@ -1202,7 +1204,7 @@ class ASTSerializer
{
JSContext *cx;
NodeBuilder builder;
uintN lineno;
uint32 lineno;
Value atomContents(JSAtom *atom) {
return Valueify(ATOM_TO_JSVAL(atom ? atom : cx->runtime->atomState.emptyAtom));
@ -1283,8 +1285,8 @@ class ASTSerializer
bool xml(JSParseNode *pn, Value *dst);
public:
ASTSerializer(JSContext *c, char const *src, uintN ln)
: cx(c), builder(c, src), lineno(ln) {
ASTSerializer(JSContext *c, bool l, char const *src, uint32 ln)
: cx(c), builder(c, l, src), lineno(ln) {
}
bool init() {
@ -2703,7 +2705,7 @@ bool
ASTSerializer::functionArgs(JSParseNode *pn, JSParseNode *pnargs, JSParseNode *pndestruct,
JSParseNode *pnbody, NodeVector &args)
{
uintN i = 0;
uint32 i = 0;
JSParseNode *arg = pnargs ? pnargs->pn_head : NULL;
JSParseNode *destruct = pndestruct ? pndestruct->pn_head : NULL;
Value node;
@ -2777,7 +2779,7 @@ Class js_ReflectClass = {
};
static JSBool
reflect_parse(JSContext *cx, uintN argc, jsval *vp)
reflect_parse(JSContext *cx, uint32 argc, jsval *vp)
{
if (argc < 1) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
@ -2789,18 +2791,57 @@ reflect_parse(JSContext *cx, uintN argc, jsval *vp)
if (!src)
return JS_FALSE;
const char *filename = NULL;
if (argc > 1) {
JSString *str = js_ValueToString(cx, Valueify(JS_ARGV(cx, vp)[1]));
if (!str)
return JS_FALSE;
filename = js_GetStringBytes(NULL, str);
}
char *filename = NULL;
AutoReleaseNullablePtr filenamep(cx, filename);
uint32 lineno = 1;
bool loc = true;
uintN lineno = 1;
if (argc > 2) {
if (!ValueToECMAUint32(cx, Valueify(JS_ARGV(cx, vp)[2]), &lineno))
if (argc > 1) {
Value arg = Valueify(JS_ARGV(cx, vp)[1]);
if (!arg.isObject()) {
js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_UNEXPECTED_TYPE,
JSDVG_SEARCH_STACK, arg, NULL, "not an object", NULL);
return JS_FALSE;
}
JSObject *config = &arg.toObject();
Value prop;
/* config.loc */
if (!GetPropertyDefault(cx, config, ATOM_TO_JSID(cx->runtime->atomState.locAtom),
BooleanValue(true), &prop)) {
return JS_FALSE;
}
loc = js_ValueToBoolean(prop);
if (loc) {
/* config.source */
if (!GetPropertyDefault(cx, config, ATOM_TO_JSID(cx->runtime->atomState.sourceAtom),
NullValue(), &prop)) {
return JS_FALSE;
}
if (!prop.isNullOrUndefined()) {
JSString *str = js_ValueToString(cx, prop);
if (!str)
return JS_FALSE;
filename = js_DeflateString(cx, str->chars(), str->length());
if (!filename)
return JS_FALSE;
filenamep.reset(filename);
}
/* config.line */
if (!GetPropertyDefault(cx, config, ATOM_TO_JSID(cx->runtime->atomState.lineAtom),
Int32Value(1), &prop) ||
!ValueToECMAUint32(cx, prop, &lineno)) {
return JS_FALSE;
}
}
}
const jschar *chars;
@ -2817,7 +2858,7 @@ reflect_parse(JSContext *cx, uintN argc, jsval *vp)
if (!pn)
return JS_FALSE;
ASTSerializer serialize(cx, filename, lineno);
ASTSerializer serialize(cx, loc, filename, lineno);
if (!serialize.init())
return JS_FALSE;

View File

@ -879,25 +879,31 @@ assertExpr("(<x><!-- hello, world --></x>)()", callExpr(xmlElt([xmlStartTag([xml
var withoutFileOrLine = Reflect.parse("42");
var withFile = Reflect.parse("42", "foo.js");
var withFileAndLine = Reflect.parse("42", "foo.js", 111);
var withFile = Reflect.parse("42", {source:"foo.js"});
var withFileAndLine = Reflect.parse("42", {source:"foo.js", line:111});
Pattern({ source: null, start: { line: 1, column: 0 }, end: { line: 1, column: 2 } }).match(withoutFileOrLine.loc);
Pattern({ source: "foo.js", start: { line: 1, column: 0 }, end: { line: 1, column: 2 } }).match(withFile.loc);
Pattern({ source: "foo.js", start: { line: 111, column: 0 }, end: { line: 111, column: 2 } }).match(withFileAndLine.loc);
var withoutFileOrLine2 = Reflect.parse("foo +\nbar");
var withFile2 = Reflect.parse("foo +\nbar", "foo.js");
var withFileAndLine2 = Reflect.parse("foo +\nbar", "foo.js", 111);
var withFile2 = Reflect.parse("foo +\nbar", {source:"foo.js"});
var withFileAndLine2 = Reflect.parse("foo +\nbar", {source:"foo.js", line:111});
Pattern({ source: null, start: { line: 1, column: 0 }, end: { line: 2, column: 3 } }).match(withoutFileOrLine2.loc);
Pattern({ source: "foo.js", start: { line: 1, column: 0 }, end: { line: 2, column: 3 } }).match(withFile2.loc);
Pattern({ source: "foo.js", start: { line: 111, column: 0 }, end: { line: 112, column: 3 } }).match(withFileAndLine2.loc);
var nested = Reflect.parse("(-b + sqrt(sqr(b) - 4 * a * c)) / (2 * a)", "quad.js");
var nested = Reflect.parse("(-b + sqrt(sqr(b) - 4 * a * c)) / (2 * a)", {source:"quad.js"});
var fourAC = nested.body[0].expression.left.right.arguments[0].right;
Pattern({ source: "quad.js", start: { line: 1, column: 20 }, end: { line: 1, column: 29 } }).match(fourAC.loc);
// No source location
assertEq(Reflect.parse("42", {loc:false}).loc, null);
program([exprStmt(lit(42))]).assert(Reflect.parse("42", {loc:false}));
reportCompare(true, true);