зеркало из https://github.com/mozilla/pjs.git
- Bumped default compile-time JS version from 1.4 to 1.5.
- Add JS1.5 getter/setter support in all its glory: * getter function SN() {return ++x} at top-level or as a closure binds an SN property getter than returns the incremented value of x. Likewise for setter function SN(y) {return y = x}. * getters and setters may be defined in an object literal: o = {p getter:function() {return ++this.x}, p setter:function(y){return this.x = y}, x:42}; * getter= and setter= operators (compound tokens) may be used to bind getter and setter properties dynamically: o = new Object; o.p getter= function() {return ++this.x}; o.p setter= function(y){return this.x = y}; o.x = 42; Waldemar is concerned that this form will collide semantically with JS2, so I am not committing to keeping it in JS1.5. I'd like to check my code in ASAP so shaver can use it, and I'd also like to see this form get used (or not) during Mozilla betas. Caveat emptor, and if you find this "dynamic" or "imperative" form necessary and hard to substitute, please let me know. If this proves important to users, then I think JS1.5 should keep it. - Cleaned up property flags (in a binary-incompatible fashion -- who cares?) by eliminating JSPROP_ASSIGNHACK and JSPROP_TINYIDHACK. - Added JS_DONT_PRETTY_PRINT flag to be ORed with the indent argument to the several JS_Decompile*() API calls. This avoids any newlines or identation in the decompiled string. - Improved and extended (for getter/setter non-reservation) scanner lookahead by using a circular (power-of-2 sized) token buffer. - Fix ECMA Edition 3 deviation where function f(){function g(){}} bound f.g by mistake (it should arrange to make a closure named g in activations of f, but it should not bind a property of function f).
This commit is contained in:
Родитель
2d9d8238ec
Коммит
4ec954edb0
|
@ -207,3 +207,4 @@ MSG_DEF(JSMSG_UNCAUGHT_EXCEPTION, 147, 1, JSEXN_NONE, "uncaught exception: {
|
|||
MSG_DEF(JSMSG_INVALID_BACKREF, 148, 0, JSEXN_SYNTAXERR, "non-octal digit in an escape sequence that doesn't match a back-reference")
|
||||
MSG_DEF(JSMSG_BAD_BACKREF, 149, 0, JSEXN_SYNTAXERR, "back-reference exceeds number of capturing parentheses")
|
||||
MSG_DEF(JSMSG_PRECISION_RANGE, 150, 1, JSEXN_RANGEERR, "precision {0} out of range")
|
||||
MSG_DEF(JSMSG_BAD_GETTER_OR_SETTER, 151, 1, JSEXN_SYNTAXERR, "invalid {0} usage")
|
||||
|
|
|
@ -869,7 +869,8 @@ JS_InitStandardClasses(JSContext *cx, JSObject *obj)
|
|||
cx->globalObject = obj;
|
||||
|
||||
#if JS_HAS_UNDEFINED
|
||||
/* Define a top-level property 'undefined' with the undefined value.
|
||||
/*
|
||||
* Define a top-level property 'undefined' with the undefined value.
|
||||
* (proposed ECMA v2.)
|
||||
*/
|
||||
if (!OBJ_DEFINE_PROPERTY(cx, obj,
|
||||
|
@ -1515,7 +1516,6 @@ JS_DefineProperties(JSContext *cx, JSObject *obj, JSPropertySpec *ps)
|
|||
if (OBJ_IS_NATIVE(obj)) {
|
||||
sprop = (JSScopeProperty *)prop;
|
||||
sprop->id = INT_TO_JSVAL(ps->tinyid);
|
||||
sprop->attrs |= JSPROP_TINYIDHACK;
|
||||
}
|
||||
OBJ_DROP_PROPERTY(cx, obj, prop);
|
||||
}
|
||||
|
@ -1547,7 +1547,6 @@ JS_DefinePropertyWithTinyId(JSContext *cx, JSObject *obj, const char *name,
|
|||
if (OBJ_IS_NATIVE(obj)) {
|
||||
sprop = (JSScopeProperty *)prop;
|
||||
sprop->id = INT_TO_JSVAL(tinyid);
|
||||
sprop->attrs |= JSPROP_TINYIDHACK;
|
||||
}
|
||||
OBJ_DROP_PROPERTY(cx, obj, prop);
|
||||
}
|
||||
|
@ -1819,7 +1818,6 @@ JS_DefineUCPropertyWithTinyId(JSContext *cx, JSObject *obj,
|
|||
if (OBJ_IS_NATIVE(obj)) {
|
||||
sprop = (JSScopeProperty *)prop;
|
||||
sprop->id = INT_TO_JSVAL(tinyid);
|
||||
sprop->attrs |= JSPROP_TINYIDHACK;
|
||||
}
|
||||
OBJ_DROP_PROPERTY(cx, obj, prop);
|
||||
}
|
||||
|
@ -2488,7 +2486,9 @@ JS_DecompileScript(JSContext *cx, JSScript *script, const char *name,
|
|||
JSString *str;
|
||||
|
||||
CHECK_REQUEST(cx);
|
||||
jp = js_NewPrinter(cx, name, indent);
|
||||
jp = js_NewPrinter(cx, name,
|
||||
indent & ~JS_DONT_PRETTY_PRINT,
|
||||
!(indent & JS_DONT_PRETTY_PRINT));
|
||||
if (!jp)
|
||||
return NULL;
|
||||
if (js_DecompileScript(jp, script))
|
||||
|
@ -2506,10 +2506,12 @@ JS_DecompileFunction(JSContext *cx, JSFunction *fun, uintN indent)
|
|||
JSString *str;
|
||||
|
||||
CHECK_REQUEST(cx);
|
||||
jp = js_NewPrinter(cx, JS_GetFunctionName(fun), indent);
|
||||
jp = js_NewPrinter(cx, JS_GetFunctionName(fun),
|
||||
indent & ~JS_DONT_PRETTY_PRINT,
|
||||
!(indent & JS_DONT_PRETTY_PRINT));
|
||||
if (!jp)
|
||||
return NULL;
|
||||
if (js_DecompileFunction(jp, fun, JS_TRUE))
|
||||
if (js_DecompileFunction(jp, fun))
|
||||
str = js_GetPrinterOutput(jp);
|
||||
else
|
||||
str = NULL;
|
||||
|
@ -2524,10 +2526,12 @@ JS_DecompileFunctionBody(JSContext *cx, JSFunction *fun, uintN indent)
|
|||
JSString *str;
|
||||
|
||||
CHECK_REQUEST(cx);
|
||||
jp = js_NewPrinter(cx, JS_GetFunctionName(fun), indent);
|
||||
jp = js_NewPrinter(cx, JS_GetFunctionName(fun),
|
||||
indent & ~JS_DONT_PRETTY_PRINT,
|
||||
!(indent & JS_DONT_PRETTY_PRINT));
|
||||
if (!jp)
|
||||
return NULL;
|
||||
if (js_DecompileFunctionBody(jp, fun, JS_TRUE))
|
||||
if (js_DecompileFunctionBody(jp, fun))
|
||||
str = js_GetPrinterOutput(jp);
|
||||
else
|
||||
str = NULL;
|
||||
|
|
|
@ -95,14 +95,16 @@ JS_BEGIN_EXTERN_C
|
|||
#define JSPROP_READONLY 0x02 /* not settable: assignment is no-op */
|
||||
#define JSPROP_PERMANENT 0x04 /* property cannot be deleted */
|
||||
#define JSPROP_EXPORTED 0x08 /* property is exported from object */
|
||||
#define JSPROP_INDEX 0x20 /* name is actually (jsint) index */
|
||||
#define JSPROP_ASSIGNHACK 0x40 /* property set by its assign method */
|
||||
#define JSPROP_TINYIDHACK 0x80 /* prop->id is tinyid, not index */
|
||||
#define JSPROP_GETTER 0x10 /* property holds getter function */
|
||||
#define JSPROP_SETTER 0x20 /* property holds setter function */
|
||||
#define JSPROP_INDEX 0x80 /* name is actually (jsint) index */
|
||||
|
||||
/* Function flags, set in JSFunctionSpec and passed to JS_NewFunction etc. */
|
||||
#define JSFUN_GETTER JSPROP_GETTER
|
||||
#define JSFUN_SETTER JSPROP_SETTER
|
||||
#define JSFUN_BOUND_METHOD 0x40 /* bind this to fun->object's parent */
|
||||
#define JSFUN_GLOBAL_PARENT 0x80 /* reparent calls to cx->globalObject */
|
||||
#define JSFUN_FLAGS_MASK 0xc0 /* overlay JSPROP_*HACK attributes */
|
||||
#define JSFUN_FLAGS_MASK 0xf0 /* overlay JSFUN_* attributes */
|
||||
|
||||
/*
|
||||
* Well-known JS values. The extern'd variables are initialized when the
|
||||
|
@ -914,6 +916,12 @@ extern JS_PUBLIC_API(JSString *)
|
|||
JS_DecompileScript(JSContext *cx, JSScript *script, const char *name,
|
||||
uintN indent);
|
||||
|
||||
/*
|
||||
* API extension: OR this into indent to avoid pretty-printing the decompiled
|
||||
* source resulting from JS_DecompileFunction{,Body}.
|
||||
*/
|
||||
#define JS_DONT_PRETTY_PRINT ((uintN)0x8000)
|
||||
|
||||
extern JS_PUBLIC_API(JSString *)
|
||||
JS_DecompileFunction(JSContext *cx, JSFunction *fun, uintN indent);
|
||||
|
||||
|
|
|
@ -66,12 +66,14 @@ char js_class_prototype_str[] = "prototype";
|
|||
char js_constructor_str[] = "constructor";
|
||||
char js_count_str[] = "__count__";
|
||||
char js_eval_str[] = "eval";
|
||||
char js_getter_str[] = "getter";
|
||||
char js_index_str[] = "index";
|
||||
char js_input_str[] = "input";
|
||||
char js_length_str[] = "length";
|
||||
char js_name_str[] = "name";
|
||||
char js_parent_str[] = "__parent__";
|
||||
char js_proto_str[] = "__proto__";
|
||||
char js_setter_str[] = "setter";
|
||||
char js_toSource_str[] = "toSource";
|
||||
char js_toString_str[] = "toString";
|
||||
char js_valueOf_str[] = "valueOf";
|
||||
|
@ -228,12 +230,14 @@ js_InitAtomState(JSContext *cx, JSAtomState *state)
|
|||
FROB(classPrototypeAtom, js_class_prototype_str);
|
||||
FROB(constructorAtom, js_constructor_str);
|
||||
FROB(countAtom, js_count_str);
|
||||
FROB(getterAtom, js_getter_str);
|
||||
FROB(indexAtom, js_index_str);
|
||||
FROB(inputAtom, js_input_str);
|
||||
FROB(lengthAtom, js_length_str);
|
||||
FROB(nameAtom, js_name_str);
|
||||
FROB(parentAtom, js_parent_str);
|
||||
FROB(protoAtom, js_proto_str);
|
||||
FROB(setterAtom, js_setter_str);
|
||||
FROB(toSourceAtom, js_toSource_str);
|
||||
FROB(toStringAtom, js_toString_str);
|
||||
FROB(valueOfAtom, js_valueOf_str);
|
||||
|
|
|
@ -115,12 +115,14 @@ struct JSAtomState {
|
|||
JSAtom *classPrototypeAtom;
|
||||
JSAtom *constructorAtom;
|
||||
JSAtom *countAtom;
|
||||
JSAtom *getterAtom;
|
||||
JSAtom *indexAtom;
|
||||
JSAtom *inputAtom;
|
||||
JSAtom *lengthAtom;
|
||||
JSAtom *nameAtom;
|
||||
JSAtom *parentAtom;
|
||||
JSAtom *protoAtom;
|
||||
JSAtom *setterAtom;
|
||||
JSAtom *toSourceAtom;
|
||||
JSAtom *toStringAtom;
|
||||
JSAtom *valueOfAtom;
|
||||
|
@ -149,12 +151,14 @@ extern char js_class_prototype_str[];
|
|||
extern char js_constructor_str[];
|
||||
extern char js_count_str[];
|
||||
extern char js_eval_str[];
|
||||
extern char js_getter_str[];
|
||||
extern char js_index_str[];
|
||||
extern char js_input_str[];
|
||||
extern char js_length_str[];
|
||||
extern char js_name_str[];
|
||||
extern char js_parent_str[];
|
||||
extern char js_proto_str[];
|
||||
extern char js_setter_str[];
|
||||
extern char js_toSource_str[];
|
||||
extern char js_toString_str[];
|
||||
extern char js_valueOf_str[];
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
* JS configuration macros.
|
||||
*/
|
||||
#ifndef JS_VERSION
|
||||
#define JS_VERSION 140
|
||||
#define JS_VERSION 150
|
||||
#endif
|
||||
|
||||
#if JS_VERSION == 100
|
||||
|
@ -72,8 +72,9 @@
|
|||
#define JS_HAS_CATCH_GUARD 0 /* has exception handling catch guard */
|
||||
#define JS_HAS_NEW_OBJ_METHODS 0 /* has Object.prototype query methods */
|
||||
#define JS_HAS_SPARSE_ARRAYS 0 /* array methods preserve empty elems */
|
||||
#define JS_HAS_DFLT_MSG_STRINGS 0 /* provides English error messages */
|
||||
#define JS_HAS_DFLT_MSG_STRINGS 1 /* provides English error messages */
|
||||
#define JS_HAS_NUMBER_FORMATS 0 /* numbers have formatting methods */
|
||||
#define JS_HAS_GETTER_SETTER 0 /* has JS2 getter/setter functions */
|
||||
|
||||
#elif JS_VERSION == 110
|
||||
|
||||
|
@ -124,8 +125,9 @@
|
|||
#define JS_HAS_CATCH_GUARD 0 /* has exception handling catch guard */
|
||||
#define JS_HAS_NEW_OBJ_METHODS 0 /* has Object.prototype query methods */
|
||||
#define JS_HAS_SPARSE_ARRAYS 0 /* array methods preserve empty elems */
|
||||
#define JS_HAS_DFLT_MSG_STRINGS 0 /* provides English error messages */
|
||||
#define JS_HAS_DFLT_MSG_STRINGS 1 /* provides English error messages */
|
||||
#define JS_HAS_NUMBER_FORMATS 0 /* numbers have formatting methods */
|
||||
#define JS_HAS_GETTER_SETTER 0 /* has JS2 getter/setter functions */
|
||||
|
||||
#elif JS_VERSION == 120
|
||||
|
||||
|
@ -176,8 +178,9 @@
|
|||
#define JS_HAS_CATCH_GUARD 0 /* has exception handling catch guard */
|
||||
#define JS_HAS_NEW_OBJ_METHODS 0 /* has Object.prototype query methods */
|
||||
#define JS_HAS_SPARSE_ARRAYS 0 /* array methods preserve empty elems */
|
||||
#define JS_HAS_DFLT_MSG_STRINGS 0 /* provides English error messages */
|
||||
#define JS_HAS_DFLT_MSG_STRINGS 1 /* provides English error messages */
|
||||
#define JS_HAS_NUMBER_FORMATS 0 /* numbers have formatting methods */
|
||||
#define JS_HAS_GETTER_SETTER 0 /* has JS2 getter/setter functions */
|
||||
|
||||
#elif JS_VERSION == 130
|
||||
|
||||
|
@ -228,8 +231,9 @@
|
|||
#define JS_HAS_CATCH_GUARD 0 /* has exception handling catch guard */
|
||||
#define JS_HAS_NEW_OBJ_METHODS 0 /* has Object.prototype query methods */
|
||||
#define JS_HAS_SPARSE_ARRAYS 0 /* array methods preserve empty elems */
|
||||
#define JS_HAS_DFLT_MSG_STRINGS 0 /* provides English error messages */
|
||||
#define JS_HAS_DFLT_MSG_STRINGS 1 /* provides English error messages */
|
||||
#define JS_HAS_NUMBER_FORMATS 0 /* numbers have formatting methods */
|
||||
#define JS_HAS_GETTER_SETTER 0 /* has JS2 getter/setter functions */
|
||||
|
||||
#elif JS_VERSION == 140
|
||||
|
||||
|
@ -246,6 +250,58 @@
|
|||
#define JS_BUG_WITH_CLOSURE 1 /* with(o)function f(){} sets o.f */
|
||||
#define JS_BUG_SET_ENUMERATE 0 /* o.p=q flags o.p JSPROP_ENUMERATE */
|
||||
|
||||
#define JS_HAS_PROP_DELETE 1 /* delete o.p removes p from o */
|
||||
#define JS_HAS_CALL_OBJECT 1 /* fun.caller is stack frame obj */
|
||||
#define JS_HAS_LABEL_STATEMENT 1 /* has break/continue to label: */
|
||||
#define JS_HAS_DO_WHILE_LOOP 1 /* has do {...} while (b) */
|
||||
#define JS_HAS_SWITCH_STATEMENT 1 /* has switch (v) {case c: ...} */
|
||||
#define JS_HAS_SOME_PERL_FUN 1 /* has array.join/reverse/sort */
|
||||
#define JS_HAS_MORE_PERL_FUN 1 /* has array.push, str.substr, etc */
|
||||
#define JS_HAS_VALUEOF_HINT 1 /* valueOf(hint) where hint is typeof */
|
||||
#define JS_HAS_LEXICAL_CLOSURE 1 /* nested functions, lexically closed */
|
||||
#define JS_HAS_APPLY_FUNCTION 1 /* has apply(fun, arg1, ... argN) */
|
||||
#define JS_HAS_CALL_FUNCTION 1 /* has fun.call(obj, arg1, ... argN) */
|
||||
#define JS_HAS_OBJ_PROTO_PROP 1 /* has o.__proto__ etc. */
|
||||
#define JS_HAS_REGEXPS 1 /* has perl r.e.s via RegExp, /pat/ */
|
||||
#define JS_HAS_SEQUENCE_OPS 1 /* has array.slice, string.concat */
|
||||
#define JS_HAS_INITIALIZERS 1 /* has var o = {'foo': 42, 'bar':3} */
|
||||
#define JS_HAS_OBJ_WATCHPOINT 1 /* has o.watch and o.unwatch */
|
||||
#define JS_HAS_EXPORT_IMPORT 1 /* has export fun; import obj.fun */
|
||||
#define JS_HAS_EVAL_THIS_SCOPE 1 /* Math.eval is same as with (Math) */
|
||||
#define JS_HAS_TRIPLE_EQOPS 1 /* has === and !== identity eqops */
|
||||
#define JS_HAS_SHARP_VARS 1 /* has #n=, #n# for object literals */
|
||||
#define JS_HAS_REPLACE_LAMBDA 1 /* has string.replace(re, lambda) */
|
||||
#define JS_HAS_SCRIPT_OBJECT 1 /* has (new Script("x++")).exec() */
|
||||
#define JS_HAS_XDR 1 /* has XDR API and object methods */
|
||||
#define JS_HAS_EXCEPTIONS 1 /* has exception handling */
|
||||
#define JS_HAS_UNDEFINED 1 /* has global "undefined" property */
|
||||
#define JS_HAS_TOSOURCE 1 /* has Object/Array toSource method */
|
||||
#define JS_HAS_IN_OPERATOR 1 /* has in operator ('p' in {p:1}) */
|
||||
#define JS_HAS_INSTANCEOF 1 /* has {p:1} instanceof Object */
|
||||
#define JS_HAS_ARGS_OBJECT 1 /* has minimal ECMA arguments object */
|
||||
#define JS_HAS_DEBUGGER_KEYWORD 1 /* has hook for debugger keyword */
|
||||
#define JS_HAS_ERROR_EXCEPTIONS 0 /* rt errors reflected as exceptions */
|
||||
#define JS_HAS_CATCH_GUARD 0 /* has exception handling catch guard */
|
||||
#define JS_HAS_NEW_OBJ_METHODS 0 /* has Object.prototype query methods */
|
||||
#define JS_HAS_SPARSE_ARRAYS 0 /* array methods preserve empty elems */
|
||||
#define JS_HAS_DFLT_MSG_STRINGS 1 /* provides English error messages */
|
||||
#define JS_HAS_GETTER_SETTER 0 /* has JS2 getter/setter functions */
|
||||
|
||||
#elif JS_VERSION == 150
|
||||
|
||||
#define JS_BUG_AUTO_INDEX_PROPS 0 /* new object o: o.p = v sets o[0] */
|
||||
#define JS_BUG_NULL_INDEX_PROPS 0 /* o[0] defaults to null, not void */
|
||||
#define JS_BUG_EMPTY_INDEX_ZERO 0 /* o[""] is equivalent to o[0] */
|
||||
#define JS_BUG_SHORT_CIRCUIT 0 /* 1 && 1 => true, 1 && 0 => 0 bug */
|
||||
#define JS_BUG_EAGER_TOSTRING 0 /* o.toString() trumps o.valueOf() */
|
||||
#define JS_BUG_VOID_TOSTRING 0 /* void 0 + 0 == "undefined0" */
|
||||
#define JS_BUG_EVAL_THIS_FUN 0 /* eval('this') in function f is f */
|
||||
#define JS_BUG_EVAL_THIS_SCOPE 0 /* Math.eval('sin(x)') vs. local x */
|
||||
#define JS_BUG_FALLIBLE_EQOPS 0 /* fallible/intransitive equality ops */
|
||||
#define JS_BUG_FALLIBLE_TONUM 0 /* fallible ValueToNumber primitive */
|
||||
#define JS_BUG_WITH_CLOSURE 1 /* with(o)function f(){} sets o.f */
|
||||
#define JS_BUG_SET_ENUMERATE 0 /* o.p=q flags o.p JSPROP_ENUMERATE */
|
||||
|
||||
#define JS_HAS_PROP_DELETE 1 /* delete o.p removes p from o */
|
||||
#define JS_HAS_CALL_OBJECT 1 /* fun.caller is stack frame obj */
|
||||
#define JS_HAS_LABEL_STATEMENT 1 /* has break/continue to label: */
|
||||
|
@ -282,6 +338,7 @@
|
|||
#define JS_HAS_SPARSE_ARRAYS 0 /* array methods preserve empty elems */
|
||||
#define JS_HAS_DFLT_MSG_STRINGS 1 /* provides English error messages */
|
||||
#define JS_HAS_NUMBER_FORMATS 1 /* numbers have formatting methods */
|
||||
#define JS_HAS_GETTER_SETTER 1 /* has JS2 getter/setter functions */
|
||||
|
||||
#else
|
||||
|
||||
|
|
|
@ -1735,8 +1735,13 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
JS_ASSERT(0);
|
||||
}
|
||||
|
||||
/* If += or similar, dup the left operand and get its value. */
|
||||
op = pn->pn_op;
|
||||
#if JS_HAS_GETTER_SETTER
|
||||
if (op == JSOP_GETTER || op == JSOP_SETTER) {
|
||||
/* We'll emit these prefix bytecodes after emitting the r.h.s. */
|
||||
} else
|
||||
#endif
|
||||
/* If += or similar, dup the left operand and get its value. */
|
||||
if (op != JSOP_NOP) {
|
||||
switch (pn2->pn_type) {
|
||||
case TOK_NAME:
|
||||
|
@ -2131,6 +2136,13 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
if (!js_EmitTree(cx, cg, pn2->pn_right))
|
||||
return JS_FALSE;
|
||||
|
||||
#if JS_HAS_GETTER_SETTER
|
||||
op = pn2->pn_op;
|
||||
if (op == JSOP_GETTER || op == JSOP_SETTER) {
|
||||
if (js_Emit1(cx, cg, op) < 0)
|
||||
return JS_FALSE;
|
||||
}
|
||||
#endif
|
||||
/* Annotate JSOP_INITELEM so we decompile 2:c and not just c. */
|
||||
if (pn3->pn_type == TOK_NUMBER) {
|
||||
if (js_NewSrcNote(cx, cg, SRC_LABEL) < 0)
|
||||
|
@ -2138,7 +2150,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
if (js_Emit1(cx, cg, JSOP_INITELEM) < 0)
|
||||
return JS_FALSE;
|
||||
} else {
|
||||
EMIT_ATOM_INDEX_OP(JSOP_INITPROP, ale->index);
|
||||
EMIT_ATOM_INDEX_OP(JSOP_INITPROP, ale->index);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1145,11 +1145,11 @@ JSClass js_FunctionClass = {
|
|||
};
|
||||
|
||||
static JSBool
|
||||
fun_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
fun_toString_sub(JSContext *cx, JSObject *obj, uint32 indent,
|
||||
uintN argc, jsval *argv, jsval *rval)
|
||||
{
|
||||
jsval fval;
|
||||
JSFunction *fun;
|
||||
uint32 indent;
|
||||
JSString *str;
|
||||
|
||||
fval = argv[-1];
|
||||
|
@ -1178,7 +1178,6 @@ fun_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|||
fun = JS_GetPrivate(cx, obj);
|
||||
if (!fun)
|
||||
return JS_TRUE;
|
||||
indent = 0;
|
||||
if (argc && !js_ValueToECMAUint32(cx, argv[0], &indent))
|
||||
return JS_FALSE;
|
||||
str = JS_DecompileFunction(cx, fun, (uintN)indent);
|
||||
|
@ -1188,6 +1187,20 @@ fun_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
fun_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
{
|
||||
return fun_toString_sub(cx, obj, 0, argc, argv, rval);
|
||||
}
|
||||
|
||||
#if JS_HAS_TOSOURCE
|
||||
static JSBool
|
||||
fun_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
{
|
||||
return fun_toString_sub(cx, obj, JS_DONT_PRETTY_PRINT, argc, argv, rval);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if JS_HAS_CALL_FUNCTION
|
||||
static JSBool
|
||||
fun_call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
|
@ -1314,7 +1327,7 @@ out:
|
|||
|
||||
static JSFunctionSpec function_methods[] = {
|
||||
#if JS_HAS_TOSOURCE
|
||||
{js_toSource_str, fun_toString, 0},
|
||||
{js_toSource_str, fun_toSource, 0},
|
||||
#endif
|
||||
{js_toString_str, fun_toString, 1},
|
||||
#if JS_HAS_APPLY_FUNCTION
|
||||
|
@ -1480,7 +1493,7 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|||
* Get the atom corresponding to the name from the tokenstream;
|
||||
* we're assured at this point that it's a valid identifier.
|
||||
*/
|
||||
atom = ts->token.t_atom;
|
||||
atom = CURRENT_TOKEN(ts).t_atom;
|
||||
if (!js_LookupProperty(cx, obj, (jsid)atom, &obj2,
|
||||
(JSProperty **)&sprop)) {
|
||||
goto bad_formal;
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "jsapi.h"
|
||||
#include "jsatom.h"
|
||||
#include "jscntxt.h"
|
||||
#include "jsconfig.h"
|
||||
#include "jsfun.h"
|
||||
#include "jsgc.h"
|
||||
#include "jsinterp.h"
|
||||
|
@ -517,6 +518,38 @@ gc_mark(JSRuntime *rt, void *thing)
|
|||
continue;
|
||||
GC_MARK_ATOM(rt, sym_atom(sym), prev);
|
||||
}
|
||||
#if JS_HAS_GETTER_SETTER
|
||||
if (sprop->attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
|
||||
#ifdef GC_MARK_DEBUG
|
||||
char buf[64];
|
||||
JSAtom *atom = sym_atom(sprop->symbols);
|
||||
const char *id = (atom && ATOM_IS_STRING(atom))
|
||||
? JS_GetStringBytes(ATOM_TO_STRING(atom))
|
||||
: "unknown",
|
||||
#endif
|
||||
|
||||
if (sprop->attrs & JSPROP_GETTER) {
|
||||
#ifdef GC_MARK_DEBUG
|
||||
PR_snprintf(buf, sizeof buf, "%s %s",
|
||||
id, js_getter_str);
|
||||
#endif
|
||||
GC_MARK(rt,
|
||||
JSVAL_TO_GCTHING((jsval)sprop->getter),
|
||||
buf,
|
||||
prev);
|
||||
}
|
||||
if (sprop->attrs & JSPROP_SETTER) {
|
||||
#ifdef GC_MARK_DEBUG
|
||||
PR_snprintf(buf, sizeof buf, "%s %s",
|
||||
id, js_setter_str);
|
||||
#endif
|
||||
GC_MARK(rt,
|
||||
JSVAL_TO_GCTHING((jsval)sprop->setter),
|
||||
buf,
|
||||
prev);
|
||||
}
|
||||
}
|
||||
#endif /* JS_HAS_GETTER_SETTER */
|
||||
}
|
||||
}
|
||||
if (!scope || scope->object == obj)
|
||||
|
|
|
@ -499,7 +499,7 @@ have_fun:
|
|||
if (fun->flags) {
|
||||
if (fun->flags & JSFUN_BOUND_METHOD)
|
||||
thisp = parent;
|
||||
else
|
||||
if (fun->flags & JSFUN_GLOBAL_PARENT)
|
||||
parent = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -528,8 +528,9 @@ have_fun:
|
|||
* "Call" objects with private data) may not be referred to by 'this'
|
||||
* as dictated by ECMA.
|
||||
*/
|
||||
if (thisp && !(OBJ_GET_CLASS(cx, thisp) == &js_CallClass &&
|
||||
JS_GetPrivate(cx, thisp) != NULL))
|
||||
if (thisp &&
|
||||
!(OBJ_GET_CLASS(cx, thisp) == &js_CallClass &&
|
||||
JS_GetPrivate(cx, thisp) != NULL))
|
||||
{
|
||||
/* Some objects (e.g., With) delegate 'this' to another object. */
|
||||
thisp = OBJ_THIS_OBJECT(cx, thisp);
|
||||
|
@ -941,7 +942,7 @@ ImportProperty(JSContext *cx, JSObject *obj, jsid id)
|
|||
} else {
|
||||
prop = NULL;
|
||||
}
|
||||
if (prop && (target == obj2)) {
|
||||
if (prop && target == obj2) {
|
||||
ok = OBJ_SET_PROPERTY(cx, target, id, &value);
|
||||
} else {
|
||||
ok = OBJ_DEFINE_PROPERTY(cx, target, id, value, NULL, NULL,
|
||||
|
@ -1011,9 +1012,12 @@ js_Interpret(JSContext *cx, jsval *result)
|
|||
JSFunction *fun2;
|
||||
JSObject *closure;
|
||||
#endif
|
||||
#if JS_HAS_EXPORT_IMPORT
|
||||
#if JS_HAS_EXPORT_IMPORT || JS_HAS_GETTER_SETTER
|
||||
uintN attrs;
|
||||
#endif
|
||||
#if JS_HAS_GETTER_SETTER
|
||||
JSPropertyOp getter, setter;
|
||||
#endif
|
||||
#if JS_HAS_EXCEPTIONS
|
||||
JSTryNote *tn;
|
||||
ptrdiff_t offset;
|
||||
|
@ -1505,7 +1509,7 @@ js_Interpret(JSContext *cx, jsval *result)
|
|||
PROPERTY_CACHE_TEST(&rt->propertyCache, obj, id, prop); \
|
||||
if (PROP_FOUND(prop) && \
|
||||
!(sprop = (JSScopeProperty *)prop, \
|
||||
sprop->attrs & (JSPROP_READONLY | JSPROP_ASSIGNHACK))) { \
|
||||
sprop->attrs & JSPROP_READONLY)) { \
|
||||
ok = SPROP_SET(cx, sprop, obj, obj, &rval); \
|
||||
if (ok) { \
|
||||
SET_ENUMERATE_ATTR(sprop); \
|
||||
|
@ -2476,10 +2480,16 @@ js_Interpret(JSContext *cx, jsval *result)
|
|||
*/
|
||||
if (fun2->atom) {
|
||||
SAVE_SP(fp);
|
||||
ok = OBJ_DEFINE_PROPERTY(cx, obj, (jsid)fun2->atom,
|
||||
OBJECT_TO_JSVAL(closure),
|
||||
NULL, NULL, JSPROP_ENUMERATE,
|
||||
NULL);
|
||||
ok = OBJ_DEFINE_PROPERTY(cx, obj, (jsid)fun2->atom,
|
||||
OBJECT_TO_JSVAL(closure),
|
||||
(fun2->flags & JSFUN_GETTER)
|
||||
? (JSPropertyOp) closure
|
||||
: NULL,
|
||||
(fun2->flags & JSFUN_SETTER)
|
||||
? (JSPropertyOp) closure
|
||||
: NULL,
|
||||
fun2->flags | JSPROP_ENUMERATE,
|
||||
NULL);
|
||||
if (!ok) {
|
||||
cx->newborn[GCX_OBJECT] = NULL;
|
||||
goto out;
|
||||
|
@ -2619,6 +2629,79 @@ js_Interpret(JSContext *cx, jsval *result)
|
|||
*vp = sp[-1];
|
||||
break;
|
||||
|
||||
#if JS_HAS_GETTER_SETTER
|
||||
case JSOP_GETTER:
|
||||
case JSOP_SETTER:
|
||||
JS_ASSERT(len == 1);
|
||||
op2 = *++pc;
|
||||
cs = &js_CodeSpec[op2];
|
||||
len = cs->length;
|
||||
switch (op2) {
|
||||
case JSOP_SETNAME2:
|
||||
case JSOP_SETPROP:
|
||||
atom = GET_ATOM(cx, script, pc);
|
||||
id = (jsid)atom;
|
||||
rval = POP();
|
||||
goto gs_pop_lval;
|
||||
|
||||
case JSOP_SETELEM:
|
||||
rval = POP();
|
||||
POP_ELEMENT_ID(id);
|
||||
gs_pop_lval:
|
||||
lval = POP();
|
||||
VALUE_TO_OBJECT(cx, lval, obj);
|
||||
break;
|
||||
|
||||
#if JS_HAS_INITIALIZERS
|
||||
case JSOP_INITPROP:
|
||||
JS_ASSERT(sp - newsp >= 2);
|
||||
rval = POP();
|
||||
atom = GET_ATOM(cx, script, pc);
|
||||
id = (jsid)atom;
|
||||
goto gs_get_lval;
|
||||
|
||||
case JSOP_INITELEM:
|
||||
JS_ASSERT(sp - newsp >= 3);
|
||||
rval = POP();
|
||||
POP_ELEMENT_ID(id);
|
||||
gs_get_lval:
|
||||
lval = sp[-1];
|
||||
JS_ASSERT(JSVAL_IS_OBJECT(lval));
|
||||
obj = JSVAL_TO_OBJECT(lval);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
JS_ASSERT(0);
|
||||
}
|
||||
if (JS_TypeOfValue(cx, rval) != JSTYPE_FUNCTION) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_GETTER_OR_SETTER,
|
||||
(op == JSOP_GETTER)
|
||||
? js_getter_str
|
||||
: js_setter_str);
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
}
|
||||
if (op == JSOP_GETTER) {
|
||||
getter = (JSPropertyOp) JSVAL_TO_OBJECT(rval);
|
||||
setter = NULL;
|
||||
attrs = JSPROP_GETTER;
|
||||
} else {
|
||||
getter = NULL;
|
||||
setter = (JSPropertyOp) JSVAL_TO_OBJECT(rval);
|
||||
attrs = JSPROP_SETTER;
|
||||
}
|
||||
attrs |= JSPROP_ENUMERATE;
|
||||
ok = OBJ_DEFINE_PROPERTY(cx, obj, id, JSVAL_VOID, getter, setter,
|
||||
attrs, NULL);
|
||||
if (!ok)
|
||||
goto out;
|
||||
if (cs->ndefs)
|
||||
PUSH_OPND(rval);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if JS_HAS_INITIALIZERS
|
||||
case JSOP_NEWINIT:
|
||||
argc = 0;
|
||||
|
|
291
js/src/jsobj.c
291
js/src/jsobj.c
|
@ -195,6 +195,10 @@ MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap)
|
|||
JSIdArray *ida;
|
||||
JSBool ok;
|
||||
jsint i, length;
|
||||
jsid id;
|
||||
JSObject *obj2;
|
||||
JSProperty *prop;
|
||||
uintN attrs;
|
||||
jsval val;
|
||||
|
||||
map = &cx->sharpObjectMap;
|
||||
|
@ -214,9 +218,39 @@ MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap)
|
|||
return NULL;
|
||||
ok = JS_TRUE;
|
||||
for (i = 0, length = ida->length; i < length; i++) {
|
||||
ok = OBJ_GET_PROPERTY(cx, obj, ida->vector[i], &val);
|
||||
if (!ok)
|
||||
break;
|
||||
id = ida->vector[i];
|
||||
#if JS_HAS_GETTER_SETTER
|
||||
ok = OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop);
|
||||
if (!ok)
|
||||
break;
|
||||
ok = OBJ_GET_ATTRIBUTES(cx, obj, id, prop, &attrs);
|
||||
if (ok) {
|
||||
if (prop &&
|
||||
OBJ_IS_NATIVE(obj2) &&
|
||||
(attrs & (JSPROP_GETTER | JSPROP_SETTER))) {
|
||||
val = JSVAL_NULL;
|
||||
if (attrs & JSPROP_GETTER)
|
||||
val = (jsval) ((JSScopeProperty *)prop)->getter;
|
||||
if (attrs & JSPROP_SETTER) {
|
||||
if (val != JSVAL_NULL) {
|
||||
/* Mark the getter here, then set val to setter. */
|
||||
ok = (MarkSharpObjects(cx, JSVAL_TO_OBJECT(val),
|
||||
NULL)
|
||||
!= NULL);
|
||||
}
|
||||
val = (jsval) ((JSScopeProperty *)prop)->setter;
|
||||
}
|
||||
} else {
|
||||
ok = OBJ_GET_PROPERTY(cx, obj, id, &val);
|
||||
}
|
||||
}
|
||||
if (prop)
|
||||
OBJ_DROP_PROPERTY(cx, obj2, prop);
|
||||
#else
|
||||
ok = OBJ_GET_PROPERTY(cx, obj, id, &val);
|
||||
#endif
|
||||
if (!ok)
|
||||
break;
|
||||
if (!JSVAL_IS_PRIMITIVE(val) &&
|
||||
!MarkSharpObjects(cx, JSVAL_TO_OBJECT(val), NULL)) {
|
||||
ok = JS_FALSE;
|
||||
|
@ -353,7 +387,7 @@ js_LeaveSharpObject(JSContext *cx, JSIdArray **idap)
|
|||
}
|
||||
}
|
||||
|
||||
#define OBJ_TOSTRING_EXTRA 2 /* for 2 GC roots */
|
||||
#define OBJ_TOSTRING_EXTRA 3 /* for 3 local GC roots */
|
||||
|
||||
#if JS_HAS_INITIALIZERS || JS_HAS_TOSOURCE
|
||||
JSBool
|
||||
|
@ -366,9 +400,15 @@ js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
|||
size_t nchars, vlength, vsharplength;
|
||||
JSBool ok;
|
||||
char *comma;
|
||||
jsint i, length;
|
||||
jsint i, j, length, valcnt;
|
||||
jsid id;
|
||||
jsval val;
|
||||
JSObject *obj2;
|
||||
JSProperty *prop;
|
||||
uintN attrs;
|
||||
jsval val[2];
|
||||
#if JS_HAS_GETTER_SETTER
|
||||
JSString *gsop[2];
|
||||
#endif
|
||||
JSString *idstr, *valstr, *str;
|
||||
|
||||
he = js_EnterSharpObject(cx, obj, &ida, &chars);
|
||||
|
@ -409,11 +449,44 @@ js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
|||
comma = NULL;
|
||||
|
||||
for (i = 0, length = ida->length; i < length; i++) {
|
||||
/* Get strings for id and val and GC-root them via argv. */
|
||||
/* Get strings for id and value and GC-root them via argv. */
|
||||
id = ida->vector[i];
|
||||
ok = OBJ_GET_PROPERTY(cx, obj, id, &val);
|
||||
#if JS_HAS_GETTER_SETTER
|
||||
ok = OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop);
|
||||
if (!ok)
|
||||
goto error;
|
||||
ok = OBJ_GET_ATTRIBUTES(cx, obj2, id, prop, &attrs);
|
||||
if (ok) {
|
||||
if (prop &&
|
||||
OBJ_IS_NATIVE(obj2) &&
|
||||
(attrs & (JSPROP_GETTER | JSPROP_SETTER))) {
|
||||
valcnt = 0;
|
||||
if (attrs & JSPROP_GETTER) {
|
||||
val[valcnt] = (jsval) ((JSScopeProperty *)prop)->getter;
|
||||
gsop[valcnt] =
|
||||
ATOM_TO_STRING(cx->runtime->atomState.getterAtom);
|
||||
valcnt++;
|
||||
}
|
||||
if (attrs & JSPROP_SETTER) {
|
||||
val[valcnt] = (jsval) ((JSScopeProperty *)prop)->setter;
|
||||
gsop[valcnt] =
|
||||
ATOM_TO_STRING(cx->runtime->atomState.setterAtom);
|
||||
valcnt++;
|
||||
}
|
||||
} else {
|
||||
valcnt = 1;
|
||||
gsop[0] = NULL;
|
||||
ok = OBJ_GET_PROPERTY(cx, obj, id, &val[0]);
|
||||
}
|
||||
}
|
||||
if (prop)
|
||||
OBJ_DROP_PROPERTY(cx, obj2, prop);
|
||||
#else
|
||||
valcnt = 1;
|
||||
ok = OBJ_GET_PROPERTY(cx, obj, id, &val[0]);
|
||||
#endif
|
||||
if (!ok)
|
||||
goto error;
|
||||
|
||||
/* Convert id to a jsval and then to a string. */
|
||||
id = js_IdToValue(id);
|
||||
|
@ -424,80 +497,94 @@ js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
|||
}
|
||||
argv[0] = STRING_TO_JSVAL(idstr);
|
||||
|
||||
/* If id is a non-identifier string, it needs to be quoted. */
|
||||
if (JSVAL_IS_STRING(id) && !js_IsIdentifier(idstr)) {
|
||||
idstr = js_QuoteString(cx, idstr, (jschar)'\'');
|
||||
if (!idstr) {
|
||||
ok = JS_FALSE;
|
||||
goto error;
|
||||
}
|
||||
argv[0] = STRING_TO_JSVAL(idstr);
|
||||
}
|
||||
/* If id is a non-identifier string, it needs to be quoted. */
|
||||
if (JSVAL_IS_STRING(id) && !js_IsIdentifier(idstr)) {
|
||||
idstr = js_QuoteString(cx, idstr, (jschar)'\'');
|
||||
if (!idstr) {
|
||||
ok = JS_FALSE;
|
||||
goto error;
|
||||
}
|
||||
argv[0] = STRING_TO_JSVAL(idstr);
|
||||
}
|
||||
|
||||
/* Convert val to its canonical source form. */
|
||||
valstr = js_ValueToSource(cx, val);
|
||||
if (!valstr) {
|
||||
ok = JS_FALSE;
|
||||
goto error;
|
||||
}
|
||||
argv[1] = STRING_TO_JSVAL(valstr);
|
||||
vchars = valstr->chars;
|
||||
vlength = valstr->length;
|
||||
for (j = 0; j < valcnt; j++) {
|
||||
/* Convert val[j] to its canonical source form. */
|
||||
valstr = js_ValueToSource(cx, val[j]);
|
||||
if (!valstr) {
|
||||
ok = JS_FALSE;
|
||||
goto error;
|
||||
}
|
||||
argv[1+j] = STRING_TO_JSVAL(valstr);
|
||||
vchars = valstr->chars;
|
||||
vlength = valstr->length;
|
||||
|
||||
/* If val is a non-sharp object, consider sharpening it. */
|
||||
vsharp = NULL;
|
||||
vsharplength = 0;
|
||||
/* If val[j] is a non-sharp object, consider sharpening it. */
|
||||
vsharp = NULL;
|
||||
vsharplength = 0;
|
||||
#if JS_HAS_SHARP_VARS
|
||||
if (!JSVAL_IS_PRIMITIVE(val) && vchars[0] != '#') {
|
||||
he = js_EnterSharpObject(cx, JSVAL_TO_OBJECT(val), NULL, &vsharp);
|
||||
if (!he) {
|
||||
ok = JS_FALSE;
|
||||
goto error;
|
||||
}
|
||||
if (IS_SHARP(he)) {
|
||||
vchars = vsharp;
|
||||
vlength = js_strlen(vchars);
|
||||
} else {
|
||||
if (vsharp) {
|
||||
vsharplength = js_strlen(vsharp);
|
||||
MAKE_SHARP(he);
|
||||
}
|
||||
js_LeaveSharpObject(cx, NULL);
|
||||
}
|
||||
}
|
||||
if (!JSVAL_IS_PRIMITIVE(val[j]) && vchars[0] != '#') {
|
||||
he = js_EnterSharpObject(cx, JSVAL_TO_OBJECT(val[j]), NULL,
|
||||
&vsharp);
|
||||
if (!he) {
|
||||
ok = JS_FALSE;
|
||||
goto error;
|
||||
}
|
||||
if (IS_SHARP(he)) {
|
||||
vchars = vsharp;
|
||||
vlength = js_strlen(vchars);
|
||||
} else {
|
||||
if (vsharp) {
|
||||
vsharplength = js_strlen(vsharp);
|
||||
MAKE_SHARP(he);
|
||||
}
|
||||
js_LeaveSharpObject(cx, NULL);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Allocate 1 + 1 at end for closing brace and terminating 0. */
|
||||
chars = realloc((ochars = chars),
|
||||
(nchars + (comma ? 2 : 0) +
|
||||
idstr->length + 1 + vsharplength + vlength +
|
||||
1 + 1) * sizeof(jschar));
|
||||
if (!chars) {
|
||||
/* Save code space on error: let JS_free ignore null vsharp. */
|
||||
JS_free(cx, vsharp);
|
||||
free(ochars);
|
||||
goto error;
|
||||
}
|
||||
/* Allocate 1 + 1 at end for closing brace and terminating 0. */
|
||||
chars = realloc((ochars = chars),
|
||||
(nchars + (comma ? 2 : 0) +
|
||||
idstr->length + 1 +
|
||||
#if JS_HAS_GETTER_SETTER
|
||||
(gsop[j] ? 1 + gsop[j]->length : 0) +
|
||||
#endif
|
||||
vsharplength + vlength +
|
||||
1 + 1) * sizeof(jschar));
|
||||
if (!chars) {
|
||||
/* Save code space on error: let JS_free ignore null vsharp. */
|
||||
JS_free(cx, vsharp);
|
||||
free(ochars);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (comma) {
|
||||
chars[nchars++] = comma[0];
|
||||
chars[nchars++] = comma[1];
|
||||
}
|
||||
comma = ", ";
|
||||
if (comma) {
|
||||
chars[nchars++] = comma[0];
|
||||
chars[nchars++] = comma[1];
|
||||
}
|
||||
comma = ", ";
|
||||
|
||||
js_strncpy(&chars[nchars], idstr->chars, idstr->length);
|
||||
nchars += idstr->length;
|
||||
chars[nchars++] = ':';
|
||||
js_strncpy(&chars[nchars], idstr->chars, idstr->length);
|
||||
nchars += idstr->length;
|
||||
#if JS_HAS_GETTER_SETTER
|
||||
if (gsop[j]) {
|
||||
chars[nchars++] = ' ';
|
||||
js_strncpy(&chars[nchars], gsop[j]->chars, gsop[j]->length);
|
||||
nchars += gsop[j]->length;
|
||||
}
|
||||
#endif
|
||||
chars[nchars++] = ':';
|
||||
|
||||
if (vsharplength) {
|
||||
js_strncpy(&chars[nchars], vsharp, vsharplength);
|
||||
nchars += vsharplength;
|
||||
}
|
||||
js_strncpy(&chars[nchars], vchars, vlength);
|
||||
nchars += vlength;
|
||||
if (vsharplength) {
|
||||
js_strncpy(&chars[nchars], vsharp, vsharplength);
|
||||
nchars += vsharplength;
|
||||
}
|
||||
js_strncpy(&chars[nchars], vchars, vlength);
|
||||
nchars += vlength;
|
||||
|
||||
if (vsharp)
|
||||
JS_free(cx, vsharp);
|
||||
if (vsharp)
|
||||
JS_free(cx, vsharp);
|
||||
}
|
||||
}
|
||||
|
||||
if (chars) {
|
||||
|
@ -1397,6 +1484,40 @@ js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
|
|||
/* Lock if object locking is required by this implementation. */
|
||||
JS_LOCK_OBJ(cx, obj);
|
||||
|
||||
#if JS_HAS_GETTER_SETTER
|
||||
/*
|
||||
* If defining a getter or setter, we must check for its counterpart and
|
||||
* update the attributes and property ops. A getter or setter is really
|
||||
* only half of a property.
|
||||
*/
|
||||
if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
|
||||
JSObject *pobj;
|
||||
|
||||
if (!js_LookupProperty(cx, obj, id, &pobj, (JSProperty **)&sprop))
|
||||
goto bad;
|
||||
if (sprop &&
|
||||
pobj == obj &&
|
||||
(sprop->attrs & (JSPROP_GETTER | JSPROP_SETTER))) {
|
||||
sprop->attrs |= attrs;
|
||||
if (attrs & JSPROP_GETTER)
|
||||
sprop->getter = getter;
|
||||
else
|
||||
sprop->setter = setter;
|
||||
if (propp)
|
||||
*propp = (JSProperty *) sprop;
|
||||
#ifdef JS_THREADSAFE
|
||||
else {
|
||||
/* Release sprop and the lock acquired by js_LookupProperty. */
|
||||
js_DropProperty(cx, obj, (JSProperty *)sprop);
|
||||
}
|
||||
#endif
|
||||
/* Release our lock on obj, in which js_LookupProperty's nested. */
|
||||
JS_UNLOCK_OBJ(cx, obj);
|
||||
return JS_TRUE;
|
||||
}
|
||||
}
|
||||
#endif /* JS_HAS_GETTER_SETTER */
|
||||
|
||||
/* Use the object's class getter and setter by default. */
|
||||
clasp = LOCKED_OBJ_GET_CLASS(obj);
|
||||
if (!getter)
|
||||
|
@ -1480,7 +1601,7 @@ js_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
|
|||
if (!sym) {
|
||||
clasp = LOCKED_OBJ_GET_CLASS(obj);
|
||||
resolve = clasp->resolve;
|
||||
if (resolve && resolve != JS_ResolveStub) {
|
||||
if (resolve != JS_ResolveStub) {
|
||||
if (clasp->flags & JSCLASS_NEW_RESOLVE) {
|
||||
newresolve = (JSNewResolveOp)resolve;
|
||||
flags = 0;
|
||||
|
@ -1793,10 +1914,30 @@ js_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
|||
if (protosym) {
|
||||
protosprop = sym_property(protosym);
|
||||
if (protosprop) {
|
||||
protoattrs = protosprop->attrs;
|
||||
#if JS_HAS_GETTER_SETTER
|
||||
if (protoattrs & JSPROP_SETTER) {
|
||||
JSBool ok;
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
JS_ATOMIC_ADDREF(&protosprop->nrefs, 1);
|
||||
#endif
|
||||
JS_UNLOCK_OBJ(cx, proto);
|
||||
|
||||
ok = SPROP_SET(cx, protosprop, obj, obj, vp);
|
||||
#ifdef JS_THREADSAFE
|
||||
JS_LOCK_OBJ_VOID(cx, proto,
|
||||
js_DropScopeProperty(cx,
|
||||
protoscope,
|
||||
protosprop));
|
||||
#endif
|
||||
return ok;
|
||||
}
|
||||
#endif /* JS_HAS_GETTER_SETTER */
|
||||
|
||||
protoid = protosprop->id;
|
||||
protogetter = protosprop->getter;
|
||||
protosetter = protosprop->setter;
|
||||
protoattrs = protosprop->attrs;
|
||||
JS_UNLOCK_OBJ(cx, proto);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include "jsscript.h"
|
||||
#include "jsstr.h"
|
||||
|
||||
char js_function_str[] = "function";
|
||||
char js_in_str[] = "in";
|
||||
char js_instanceof_str[] = "instanceof";
|
||||
char js_new_str[] = "new";
|
||||
|
@ -408,12 +409,13 @@ struct JSPrinter {
|
|||
Sprinter sprinter; /* base class state */
|
||||
JSArenaPool pool; /* string allocation pool */
|
||||
uintN indent; /* indentation in spaces */
|
||||
JSBool pretty; /* pretty-print, indent, add newlines */
|
||||
JSScript *script; /* script being printed */
|
||||
JSScope *scope; /* script function scope */
|
||||
};
|
||||
|
||||
JSPrinter *
|
||||
js_NewPrinter(JSContext *cx, const char *name, uintN indent)
|
||||
js_NewPrinter(JSContext *cx, const char *name, uintN indent, JSBool pretty)
|
||||
{
|
||||
JSPrinter *jp;
|
||||
JSStackFrame *fp;
|
||||
|
@ -426,6 +428,7 @@ js_NewPrinter(JSContext *cx, const char *name, uintN indent)
|
|||
INIT_SPRINTER(cx, &jp->sprinter, &jp->pool, 0);
|
||||
JS_InitArenaPool(&jp->pool, name, 256, 1);
|
||||
jp->indent = indent;
|
||||
jp->pretty = pretty;
|
||||
jp->script = NULL;
|
||||
jp->scope = NULL;
|
||||
fp = cx->fp;
|
||||
|
@ -469,27 +472,45 @@ js_GetPrinterOutput(JSPrinter *jp)
|
|||
}
|
||||
|
||||
int
|
||||
js_printf(JSPrinter *jp, char *format, ...)
|
||||
js_printf(JSPrinter *jp, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char *bp;
|
||||
char *bp, *fp;
|
||||
int cc;
|
||||
|
||||
if (*format == '\0')
|
||||
return 0;
|
||||
|
||||
va_start(ap, format);
|
||||
|
||||
/* Expand magic tab into a run of jp->indent spaces. */
|
||||
/* If pretty-printing, expand magic tab into a run of jp->indent spaces. */
|
||||
if (*format == '\t') {
|
||||
if (Sprint(&jp->sprinter, "%*s", jp->indent, "") < 0)
|
||||
if (jp->pretty && Sprint(&jp->sprinter, "%*s", jp->indent, "") < 0)
|
||||
return -1;
|
||||
format++;
|
||||
}
|
||||
|
||||
/* Suppress newlines (must be once per format, at the end) if not pretty. */
|
||||
fp = NULL;
|
||||
if (!jp->pretty && format[cc = strlen(format)-1] == '\n') {
|
||||
fp = JS_strdup(jp->sprinter.context, format);
|
||||
if (!fp)
|
||||
return -1;
|
||||
fp[cc] = '\0';
|
||||
format = fp;
|
||||
}
|
||||
|
||||
/* Allocate temp space, convert format, and put. */
|
||||
bp = JS_vsmprintf(format, ap); /* XXX vsaprintf */
|
||||
if (fp) {
|
||||
JS_free(jp->sprinter.context, fp);
|
||||
format = NULL;
|
||||
}
|
||||
if (!bp) {
|
||||
JS_ReportOutOfMemory(jp->sprinter.context);
|
||||
return -1;
|
||||
}
|
||||
|
||||
cc = strlen(bp);
|
||||
if (SprintPut(&jp->sprinter, bp, (size_t)cc) < 0)
|
||||
cc = -1;
|
||||
|
@ -500,7 +521,7 @@ js_printf(JSPrinter *jp, char *format, ...)
|
|||
}
|
||||
|
||||
JSBool
|
||||
js_puts(JSPrinter *jp, char *s)
|
||||
js_puts(JSPrinter *jp, const char *s)
|
||||
{
|
||||
return SprintPut(&jp->sprinter, s, strlen(s)) >= 0;
|
||||
}
|
||||
|
@ -786,6 +807,12 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
|
|||
break;
|
||||
|
||||
case 0:
|
||||
#if JS_HAS_GETTER_SETTER
|
||||
if (op == JSOP_GETTER || op == JSOP_SETTER) {
|
||||
todo = -2;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
todo = SprintPut(&ss->sprinter, cs->token, strlen(cs->token));
|
||||
break;
|
||||
|
||||
|
@ -929,11 +956,11 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
|
|||
obj = ATOM_TO_OBJECT(atom);
|
||||
fun = JS_GetPrivate(cx, obj);
|
||||
jp2 = js_NewPrinter(cx, JS_GetFunctionName(fun),
|
||||
jp->indent);
|
||||
jp->indent, jp->pretty);
|
||||
if (!jp2)
|
||||
return JS_FALSE;
|
||||
jp2->scope = jp->scope;
|
||||
if (js_DecompileFunction(jp2, fun, JS_TRUE)) {
|
||||
if (js_DecompileFunction(jp2, fun)) {
|
||||
str = js_GetPrinterOutput(jp2);
|
||||
if (str)
|
||||
js_printf(jp, "%s\n", JS_GetStringBytes(str));
|
||||
|
@ -1352,7 +1379,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
|
|||
if ((sn = js_GetSrcNote(jp->script, pc - 1)) != NULL &&
|
||||
SN_TYPE(sn) == SRC_ASSIGNOP) {
|
||||
todo = Sprint(&ss->sprinter, "%s %s= %s",
|
||||
lval, js_CodeSpec[pc[-1]].token, rval);
|
||||
lval, js_CodeSpec[lastop].token, rval);
|
||||
} else {
|
||||
sn = js_GetSrcNote(jp->script, pc);
|
||||
todo = Sprint(&ss->sprinter, "%s%s = %s",
|
||||
|
@ -1544,7 +1571,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
|
|||
SN_TYPE(sn) == SRC_ASSIGNOP) {
|
||||
todo = Sprint(&ss->sprinter, "%s.%s %s= %s",
|
||||
lval, ATOM_BYTES(atom),
|
||||
js_CodeSpec[pc[-1]].token, rval);
|
||||
js_CodeSpec[lastop].token, rval);
|
||||
} else {
|
||||
todo = Sprint(&ss->sprinter, "%s.%s = %s",
|
||||
lval, ATOM_BYTES(atom), rval);
|
||||
|
@ -1574,7 +1601,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
|
|||
SN_TYPE(sn) == SRC_ASSIGNOP) {
|
||||
todo = Sprint(&ss->sprinter, "%s[%s] %s= %s",
|
||||
lval, xval,
|
||||
js_CodeSpec[pc[-1]].token, rval);
|
||||
js_CodeSpec[lastop].token, rval);
|
||||
} else {
|
||||
todo = Sprint(&ss->sprinter, "%s[%s] = %s",
|
||||
lval, xval, rval);
|
||||
|
@ -1615,7 +1642,8 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
|
|||
todo = Sprint(&ss->sprinter, "%ld", ival);
|
||||
} else if (JSVAL_IS_DOUBLE(key)) {
|
||||
char buf[DTOSTR_STANDARD_BUFFER_SIZE];
|
||||
char *numStr = JS_dtostr(buf, sizeof buf, DTOSTR_STANDARD, 0, *JSVAL_TO_DOUBLE(key));
|
||||
char *numStr = JS_dtostr(buf, sizeof buf, DTOSTR_STANDARD,
|
||||
0, *JSVAL_TO_DOUBLE(key));
|
||||
if (!numStr) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return JS_FALSE;
|
||||
|
@ -1838,12 +1866,13 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
|
|||
do_closure:
|
||||
obj = ATOM_TO_OBJECT(atom);
|
||||
fun = JS_GetPrivate(cx, obj);
|
||||
jp2 = js_NewPrinter(cx, JS_GetFunctionName(fun), jp->indent);
|
||||
jp2 = js_NewPrinter(cx, JS_GetFunctionName(fun), jp->indent,
|
||||
jp->pretty);
|
||||
if (!jp2)
|
||||
return JS_FALSE;
|
||||
jp2->scope = jp->scope;
|
||||
todo = -1;
|
||||
if (js_DecompileFunction(jp2, fun, JS_FALSE)) {
|
||||
if (js_DecompileFunction(jp2, fun)) {
|
||||
str = js_GetPrinterOutput(jp2);
|
||||
if (str) {
|
||||
todo = SprintPut(&ss->sprinter,
|
||||
|
@ -1942,9 +1971,16 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
|
|||
xval = ATOM_BYTES(atom);
|
||||
lval = POP_STR();
|
||||
do_initprop:
|
||||
todo = Sprint(&ss->sprinter, "%s%s%s:%s",
|
||||
lval, (lval[1] != '\0') ? ", " : "",
|
||||
xval, rval);
|
||||
todo = Sprint(&ss->sprinter, "%s%s%s%s%s:%s",
|
||||
lval,
|
||||
(lval[1] != '\0') ? ", " : "",
|
||||
xval,
|
||||
(lastop == JSOP_GETTER || lastop == JSOP_SETTER)
|
||||
? " " : "",
|
||||
(lastop == JSOP_GETTER) ? js_getter_str :
|
||||
(lastop == JSOP_SETTER) ? js_setter_str :
|
||||
"",
|
||||
rval);
|
||||
break;
|
||||
|
||||
case JSOP_INITELEM:
|
||||
|
@ -2062,28 +2098,30 @@ js_DecompileScript(JSPrinter *jp, JSScript *script)
|
|||
return js_DecompileCode(jp, script, script->code, (uintN)script->length);
|
||||
}
|
||||
|
||||
static const char native_code_str[] = "\t[native code]\n";
|
||||
|
||||
JSBool
|
||||
js_DecompileFunctionBody(JSPrinter *jp, JSFunction *fun, JSBool newlines)
|
||||
js_DecompileFunctionBody(JSPrinter *jp, JSFunction *fun)
|
||||
{
|
||||
JSScript *script = fun->script;
|
||||
if (script) {
|
||||
JSScope *oldScope, *scope = NULL;
|
||||
JSBool ok;
|
||||
if (fun->object) scope = (JSScope *)fun->object->map;
|
||||
oldScope = jp->scope;
|
||||
jp->scope = scope;
|
||||
ok = js_DecompileCode(jp, script, script->code, (uintN)script->length);
|
||||
jp->scope = oldScope;
|
||||
return ok;
|
||||
}
|
||||
else {
|
||||
js_printf(jp, "\t[native code]\n");
|
||||
JSScript *script;
|
||||
JSScope *scope, *save;
|
||||
JSBool ok;
|
||||
|
||||
script = fun->script;
|
||||
if (!script) {
|
||||
js_printf(jp, native_code_str);
|
||||
return JS_TRUE;
|
||||
}
|
||||
scope = fun->object ? (JSScope *)fun->object->map : NULL;
|
||||
save = jp->scope;
|
||||
jp->scope = scope;
|
||||
ok = js_DecompileCode(jp, script, script->code, (uintN)script->length);
|
||||
jp->scope = save;
|
||||
return ok;
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_DecompileFunction(JSPrinter *jp, JSFunction *fun, JSBool newlines)
|
||||
js_DecompileFunction(JSPrinter *jp, JSFunction *fun)
|
||||
{
|
||||
JSScope *scope, *oldscope;
|
||||
JSScopeProperty *sprop, *snext;
|
||||
|
@ -2092,23 +2130,29 @@ js_DecompileFunction(JSPrinter *jp, JSFunction *fun, JSBool newlines)
|
|||
uintN indent;
|
||||
intN i;
|
||||
|
||||
if (newlines) {
|
||||
if (jp->pretty) {
|
||||
js_puts(jp, "\n");
|
||||
js_printf(jp, "\t");
|
||||
}
|
||||
js_printf(jp, "function %s(", fun->atom ? ATOM_BYTES(fun->atom) : "");
|
||||
if (fun->flags & JSFUN_GETTER)
|
||||
js_printf(jp, "%s ", js_getter_str);
|
||||
else if (fun->flags & JSFUN_SETTER)
|
||||
js_printf(jp, "%s ", js_setter_str);
|
||||
js_printf(jp, "%s %s(",
|
||||
js_function_str, fun->atom ? ATOM_BYTES(fun->atom) : "");
|
||||
|
||||
scope = NULL;
|
||||
if (fun->script && fun->object) {
|
||||
/* Print the parameters.
|
||||
/*
|
||||
* Print the parameters.
|
||||
*
|
||||
* This code is complicated by the need to handle duplicate parameter names.
|
||||
* A duplicate parameter is stored as a property with id equal to the parameter
|
||||
* number, but will not be in order in the linked list of symbols. So for each
|
||||
* parameter we search the list of symbols for the appropriately numbered
|
||||
* parameter, which we can then print.
|
||||
* This code is complicated by the need to handle duplicate parameter
|
||||
* names. A duplicate parameter is stored as a property with id equal
|
||||
* to the parameter number, but will not be in order in the linked list
|
||||
* of symbols. So for each parameter we search the list of symbols for
|
||||
* the appropriately numbered parameter, which we can then print.
|
||||
*/
|
||||
for (i=0;;i++) {
|
||||
for (i = 0; ; i++) {
|
||||
jsid id;
|
||||
atom = NULL;
|
||||
scope = (JSScope *)fun->object->map;
|
||||
|
@ -2131,7 +2175,7 @@ js_DecompileFunction(JSPrinter *jp, JSFunction *fun, JSBool newlines)
|
|||
js_printf(jp, (i > 0 ? ", %s" : "%s"), ATOM_BYTES(atom));
|
||||
}
|
||||
}
|
||||
js_puts(jp, ") {\n");
|
||||
js_printf(jp, ") {\n");
|
||||
indent = jp->indent;
|
||||
jp->indent += 4;
|
||||
if (fun->script && fun->object) {
|
||||
|
@ -2144,11 +2188,11 @@ js_DecompileFunction(JSPrinter *jp, JSFunction *fun, JSBool newlines)
|
|||
return JS_FALSE;
|
||||
}
|
||||
} else {
|
||||
js_printf(jp, "\t[native code]\n");
|
||||
js_printf(jp, native_code_str);
|
||||
}
|
||||
jp->indent -= 4;
|
||||
js_printf(jp, "\t}");
|
||||
if (newlines)
|
||||
if (jp->pretty)
|
||||
js_puts(jp, "\n");
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
@ -2303,7 +2347,7 @@ js_DecompileValueGenerator(JSContext *cx, JSBool checkStack, jsval v,
|
|||
tmp = NULL;
|
||||
}
|
||||
|
||||
jp = js_NewPrinter(cx, "js_DecompileValueGenerator", 0);
|
||||
jp = js_NewPrinter(cx, "js_DecompileValueGenerator", 0, JS_FALSE);
|
||||
if (jp && js_DecompileCode(jp, script, begin, len))
|
||||
name = js_GetPrinterOutput(jp);
|
||||
else
|
||||
|
|
|
@ -107,6 +107,7 @@ struct JSCodeSpec {
|
|||
uint32 format; /* immediate operand format */
|
||||
};
|
||||
|
||||
extern char js_function_str[];
|
||||
extern char js_in_str[];
|
||||
extern char js_instanceof_str[];
|
||||
extern char js_new_str[];
|
||||
|
@ -135,7 +136,7 @@ js_QuoteString(JSContext *cx, JSString *str, jschar quote);
|
|||
* a GC'ed string.
|
||||
*/
|
||||
extern JSPrinter *
|
||||
js_NewPrinter(JSContext *cx, const char *name, uintN indent);
|
||||
js_NewPrinter(JSContext *cx, const char *name, uintN indent, JSBool pretty);
|
||||
|
||||
extern void
|
||||
js_DestroyPrinter(JSPrinter *jp);
|
||||
|
@ -144,10 +145,10 @@ extern JSString *
|
|||
js_GetPrinterOutput(JSPrinter *jp);
|
||||
|
||||
extern int
|
||||
js_printf(JSPrinter *jp, char *format, ...);
|
||||
js_printf(JSPrinter *jp, const char *format, ...);
|
||||
|
||||
extern JSBool
|
||||
js_puts(JSPrinter *jp, char *s);
|
||||
js_puts(JSPrinter *jp, const char *s);
|
||||
|
||||
#ifdef DEBUG
|
||||
/*
|
||||
|
@ -173,10 +174,10 @@ extern JSBool
|
|||
js_DecompileScript(JSPrinter *jp, JSScript *script);
|
||||
|
||||
extern JSBool
|
||||
js_DecompileFunctionBody(JSPrinter *jp, JSFunction *fun, JSBool newlines);
|
||||
js_DecompileFunctionBody(JSPrinter *jp, JSFunction *fun);
|
||||
|
||||
extern JSBool
|
||||
js_DecompileFunction(JSPrinter *jp, JSFunction *fun, JSBool newlines);
|
||||
js_DecompileFunction(JSPrinter *jp, JSFunction *fun);
|
||||
|
||||
/*
|
||||
* Find the source expression that resulted in v, and return a new string
|
||||
|
|
|
@ -220,3 +220,11 @@ OPDEF(JSOP_EVAL, 121,"eval", NULL, 3, -1, 1, 11, JOF_UINT16
|
|||
* ECMA-compliant helper for 'for (x[i] in o)' loops.
|
||||
*/
|
||||
OPDEF(JSOP_ENUMELEM, 122,"enumelem", NULL, 1, 3, 0, 1, JOF_BYTE |JOF_ELEM|JOF_SET)
|
||||
|
||||
/*
|
||||
* Getter and setter prefix bytecodes. These modify the next bytecode, either
|
||||
* an assignment or a property initializer code, which then defines a property
|
||||
* getter or setter.
|
||||
*/
|
||||
OPDEF(JSOP_GETTER, 123,js_getter_str,js_getter_str,1, 0, 0, 0, JOF_BYTE)
|
||||
OPDEF(JSOP_SETTER, 124,js_setter_str,js_setter_str,1, 0, 0, 0, JOF_BYTE)
|
||||
|
|
398
js/src/jsparse.c
398
js/src/jsparse.c
|
@ -64,6 +64,7 @@
|
|||
|
||||
typedef JSParseNode *
|
||||
JSParser(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc);
|
||||
|
||||
typedef JSParseNode *
|
||||
JSMemberParser(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
||||
JSBool allowCallSyntax);
|
||||
|
@ -177,6 +178,39 @@ WellTerminated(JSContext *cx, JSTokenStream *ts, JSTokenType lastExprType)
|
|||
return JS_TRUE;
|
||||
}
|
||||
|
||||
#if JS_HAS_GETTER_SETTER
|
||||
static JSTokenType
|
||||
CheckGetterOrSetter(JSContext *cx, JSTokenStream *ts, JSTokenType tt)
|
||||
{
|
||||
JSAtom *atom;
|
||||
JSRuntime *rt;
|
||||
JSOp op;
|
||||
|
||||
JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_NAME);
|
||||
atom = CURRENT_TOKEN(ts).t_atom;
|
||||
rt = cx->runtime;
|
||||
if (atom == rt->atomState.getterAtom)
|
||||
op = JSOP_GETTER;
|
||||
else if (atom == rt->atomState.setterAtom)
|
||||
op = JSOP_SETTER;
|
||||
else
|
||||
return TOK_NAME;
|
||||
if (js_PeekTokenSameLine(cx, ts) != tt)
|
||||
return TOK_NAME;
|
||||
(void) js_GetToken(cx, ts);
|
||||
if (CURRENT_TOKEN(ts).t_op != JSOP_NOP) {
|
||||
js_ReportCompileErrorNumber(cx, ts, JSREPORT_ERROR,
|
||||
JSMSG_BAD_GETTER_OR_SETTER,
|
||||
(op == JSOP_GETTER)
|
||||
? js_getter_str
|
||||
: js_setter_str);
|
||||
return TOK_ERROR;
|
||||
}
|
||||
CURRENT_TOKEN(ts).t_op = op;
|
||||
return tt;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Parse a top-level JS script.
|
||||
*/
|
||||
|
@ -216,17 +250,23 @@ js_CompileTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts,
|
|||
break;
|
||||
}
|
||||
|
||||
switch (tt) {
|
||||
case TOK_FUNCTION:
|
||||
#if JS_HAS_GETTER_SETTER
|
||||
if (tt == TOK_NAME) {
|
||||
tt = CheckGetterOrSetter(cx, ts, TOK_FUNCTION);
|
||||
if (tt == TOK_ERROR) {
|
||||
ok = JS_FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (tt == TOK_FUNCTION) {
|
||||
pn = FunctionStmt(cx, ts, &cg->treeContext);
|
||||
if (pn && pn->pn_pos.end.lineno == ts->lineno) {
|
||||
ok = WellTerminated(cx, ts, TOK_FUNCTION);
|
||||
if (!ok)
|
||||
goto out;
|
||||
ok = WellTerminated(cx, ts, TOK_FUNCTION);
|
||||
if (!ok)
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
} else {
|
||||
js_UngetToken(ts);
|
||||
pn = Statement(cx, ts, &cg->treeContext);
|
||||
if (pn) {
|
||||
|
@ -234,8 +274,8 @@ js_CompileTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts,
|
|||
if (!ok)
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (pn) {
|
||||
ok = js_AllocTryNotes(cx, cg);
|
||||
if (ok)
|
||||
|
@ -249,8 +289,6 @@ out:
|
|||
ts->flags &= ~TSF_BADCOMPILE;
|
||||
cx->gcDisabled--;
|
||||
cx->fp = fp;
|
||||
if (!ok)
|
||||
CLEAR_PUSHBACK(ts);
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
@ -360,10 +398,9 @@ js_CompileFunctionBody(JSContext *cx, JSTokenStream *ts, JSFunction *fun)
|
|||
cx->gcDisabled++;
|
||||
|
||||
/* Satisfy the assertion at the top of Statements. */
|
||||
ts->token.type = TOK_LC;
|
||||
CURRENT_TOKEN(ts).type = TOK_LC;
|
||||
pn = FunctionBody(cx, ts, fun, &funcg.treeContext);
|
||||
if (!pn) {
|
||||
CLEAR_PUSHBACK(ts);
|
||||
ok = JS_FALSE;
|
||||
} else {
|
||||
ok = js_FoldConstants(cx, pn);
|
||||
|
@ -390,9 +427,10 @@ InWithStatement(JSTreeContext *tc)
|
|||
|
||||
static JSParseNode *
|
||||
FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
||||
JSBool lambda)
|
||||
JSBool lambda)
|
||||
{
|
||||
JSParseNode *pn, *pn2;
|
||||
JSOp op;
|
||||
JSAtom *funAtom, *argAtom;
|
||||
JSObject *parent;
|
||||
JSFunction *fun, *outerFun;
|
||||
|
@ -403,13 +441,14 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
|||
jsval junk;
|
||||
|
||||
/* Make a TOK_FUNCTION node. */
|
||||
pn = NewParseNode(cx, &ts->token, PN_FUNC);
|
||||
pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_FUNC);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
op = CURRENT_TOKEN(ts).t_op;
|
||||
|
||||
/* Scan the optional function name into funAtom. */
|
||||
if (js_MatchToken(cx, ts, TOK_NAME))
|
||||
funAtom = ts->token.t_atom;
|
||||
funAtom = CURRENT_TOKEN(ts).t_atom;
|
||||
else
|
||||
funAtom = NULL;
|
||||
|
||||
|
@ -418,8 +457,36 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
|||
if (!parent)
|
||||
return NULL;
|
||||
|
||||
#if JS_HAS_GETTER_SETTER
|
||||
if (op != JSOP_NOP) {
|
||||
JSPropertyOp getter, setter;
|
||||
uintN attr;
|
||||
|
||||
fun = js_NewFunction(cx, NULL, NULL, 0, 0, parent, funAtom);
|
||||
if (!fun)
|
||||
return NULL;
|
||||
if (op == JSOP_GETTER) {
|
||||
getter = (JSPropertyOp) fun->object;
|
||||
setter = NULL;
|
||||
attr = JSPROP_GETTER;
|
||||
} else {
|
||||
getter = NULL;
|
||||
setter = (JSPropertyOp) fun->object;
|
||||
attr = JSPROP_SETTER;
|
||||
}
|
||||
fun->flags |= attr;
|
||||
|
||||
if (!lambda && funAtom && !InWithStatement(tc)) {
|
||||
if (!OBJ_DEFINE_PROPERTY(cx, parent, (jsid)funAtom, JSVAL_VOID,
|
||||
getter, setter, attr | JSPROP_ENUMERATE,
|
||||
NULL)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
#if JS_HAS_LEXICAL_CLOSURE
|
||||
if (!funAtom || InWithStatement(tc)) {
|
||||
if (lambda || !funAtom || InWithStatement(tc)) {
|
||||
/* Don't name the function if enclosed by a with statement or equiv. */
|
||||
fun = js_NewFunction(cx, NULL, NULL, 0, 0, cx->fp->scopeChain,
|
||||
funAtom);
|
||||
|
@ -443,7 +510,7 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
|||
do {
|
||||
MUST_MATCH_TOKEN_THROW(TOK_NAME, JSMSG_MISSING_FORMAL,
|
||||
ok = JS_FALSE; goto out);
|
||||
argAtom = ts->token.t_atom;
|
||||
argAtom = CURRENT_TOKEN(ts).t_atom;
|
||||
pobj = NULL;
|
||||
ok = js_LookupProperty(cx, fun->object, (jsid)argAtom, &pobj,
|
||||
(JSProperty **)&sprop);
|
||||
|
@ -501,7 +568,7 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
|||
|
||||
MUST_MATCH_TOKEN_THROW(TOK_LC, JSMSG_CURLY_BEFORE_BODY,
|
||||
ok = JS_FALSE; goto out);
|
||||
pn->pn_pos.begin = ts->token.pos.begin;
|
||||
pn->pn_pos.begin = CURRENT_TOKEN(ts).pos.begin;
|
||||
|
||||
TREE_CONTEXT_INIT(&funtc);
|
||||
pn2 = FunctionBody(cx, ts, fun, &funtc);
|
||||
|
@ -512,7 +579,7 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
|||
|
||||
MUST_MATCH_TOKEN_THROW(TOK_RC, JSMSG_CURLY_AFTER_BODY,
|
||||
ok = JS_FALSE; goto out);
|
||||
pn->pn_pos.end = ts->token.pos.end;
|
||||
pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
|
||||
|
||||
pn->pn_fun = fun;
|
||||
pn->pn_body = pn2;
|
||||
|
@ -561,8 +628,8 @@ Statements(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
JSParseNode *pn, *pn2;
|
||||
JSTokenType tt;
|
||||
|
||||
JS_ASSERT(ts->token.type == TOK_LC);
|
||||
pn = NewParseNode(cx, &ts->token, PN_LIST);
|
||||
JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_LC);
|
||||
pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
PN_INIT_LIST(pn);
|
||||
|
@ -574,7 +641,7 @@ Statements(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
PN_APPEND(pn, pn2);
|
||||
}
|
||||
|
||||
pn->pn_pos.end = ts->token.pos.end;
|
||||
pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
|
||||
if (tt == TOK_ERROR)
|
||||
pn = NULL;
|
||||
return pn;
|
||||
|
@ -641,7 +708,7 @@ MatchLabel(JSContext *cx, JSTokenStream *ts, JSParseNode *pn)
|
|||
return JS_FALSE;
|
||||
if (tt == TOK_NAME) {
|
||||
(void) js_GetToken(cx, ts);
|
||||
label = ts->token.t_atom;
|
||||
label = CURRENT_TOKEN(ts).t_atom;
|
||||
} else {
|
||||
label = NULL;
|
||||
}
|
||||
|
@ -662,11 +729,11 @@ ImportExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
JSTokenType tt;
|
||||
|
||||
MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_IMPORT_NAME);
|
||||
pn = NewParseNode(cx, &ts->token, PN_NULLARY);
|
||||
pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
pn->pn_op = JSOP_NAME;
|
||||
pn->pn_atom = ts->token.t_atom;
|
||||
pn->pn_atom = CURRENT_TOKEN(ts).t_atom;
|
||||
pn->pn_slot = -1;
|
||||
|
||||
ts->flags |= TSF_REGEXP;
|
||||
|
@ -676,7 +743,7 @@ ImportExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
goto bad_import;
|
||||
|
||||
if (tt == TOK_DOT) {
|
||||
pn2 = NewParseNode(cx, &ts->token, PN_NAME);
|
||||
pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NAME);
|
||||
if (!pn2)
|
||||
return NULL;
|
||||
pn2->pn_expr = pn;
|
||||
|
@ -686,14 +753,14 @@ ImportExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
} else {
|
||||
MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NAME_AFTER_DOT);
|
||||
pn2->pn_op = JSOP_GETPROP;
|
||||
pn2->pn_atom = ts->token.t_atom;
|
||||
pn2->pn_atom = CURRENT_TOKEN(ts).t_atom;
|
||||
pn2->pn_slot = -1;
|
||||
}
|
||||
pn2->pn_pos.begin = pn->pn_pos.begin;
|
||||
pn2->pn_pos.end = ts->token.pos.end;
|
||||
pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
|
||||
} else {
|
||||
/* Make a TOK_LB node. */
|
||||
pn2 = NewParseNode(cx, &ts->token, PN_BINARY);
|
||||
pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY);
|
||||
if (!pn2)
|
||||
return NULL;
|
||||
pn3 = Expr(cx, ts, tc);
|
||||
|
@ -702,7 +769,7 @@ ImportExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
|
||||
MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_IN_INDEX);
|
||||
pn2->pn_pos.begin = pn->pn_pos.begin;
|
||||
pn2->pn_pos.end = ts->token.pos.end;
|
||||
pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
|
||||
|
||||
pn2->pn_op = JSOP_GETELEM;
|
||||
pn2->pn_left = pn;
|
||||
|
@ -752,23 +819,23 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
switch (tt) {
|
||||
#if JS_HAS_EXPORT_IMPORT
|
||||
case TOK_EXPORT:
|
||||
pn = NewParseNode(cx, &ts->token, PN_LIST);
|
||||
pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
PN_INIT_LIST(pn);
|
||||
if (js_MatchToken(cx, ts, TOK_STAR)) {
|
||||
pn2 = NewParseNode(cx, &ts->token, PN_NULLARY);
|
||||
pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY);
|
||||
if (!pn2)
|
||||
return NULL;
|
||||
PN_APPEND(pn, pn2);
|
||||
} else {
|
||||
do {
|
||||
MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_EXPORT_NAME);
|
||||
pn2 = NewParseNode(cx, &ts->token, PN_NULLARY);
|
||||
pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY);
|
||||
if (!pn2)
|
||||
return NULL;
|
||||
pn2->pn_op = JSOP_NAME;
|
||||
pn2->pn_atom = ts->token.t_atom;
|
||||
pn2->pn_atom = CURRENT_TOKEN(ts).t_atom;
|
||||
pn2->pn_slot = -1;
|
||||
PN_APPEND(pn, pn2);
|
||||
} while (js_MatchToken(cx, ts, TOK_COMMA));
|
||||
|
@ -781,7 +848,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
break;
|
||||
|
||||
case TOK_IMPORT:
|
||||
pn = NewParseNode(cx, &ts->token, PN_LIST);
|
||||
pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
PN_INIT_LIST(pn);
|
||||
|
@ -801,7 +868,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
|
||||
case TOK_IF:
|
||||
/* An IF node has three kids: condition, then, and optional else. */
|
||||
pn = NewParseNode(cx, &ts->token, PN_TERNARY);
|
||||
pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_TERNARY);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
pn1 = Condition(cx, ts, tc);
|
||||
|
@ -833,7 +900,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
JSParseNode *pn5;
|
||||
JSBool seenDefault = JS_FALSE;
|
||||
|
||||
pn = NewParseNode(cx, &ts->token, PN_BINARY);
|
||||
pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_SWITCH);
|
||||
|
@ -847,7 +914,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_SWITCH);
|
||||
|
||||
/* pn2 is a list of case nodes. The default case has pn_left == NULL */
|
||||
pn2 = NewParseNode(cx, &ts->token, PN_LIST);
|
||||
pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST);
|
||||
if (!pn2)
|
||||
return NULL;
|
||||
PN_INIT_LIST(pn2);
|
||||
|
@ -866,7 +933,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
/* fall through */
|
||||
|
||||
case TOK_CASE:
|
||||
pn3 = NewParseNode(cx, &ts->token, PN_BINARY);
|
||||
pn3 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY);
|
||||
if (!pn3)
|
||||
return NULL;
|
||||
if (tt == TOK_DEFAULT) {
|
||||
|
@ -894,7 +961,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
}
|
||||
MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_AFTER_CASE);
|
||||
|
||||
pn4 = NewParseNode(cx, &ts->token, PN_LIST);
|
||||
pn4 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST);
|
||||
if (!pn4)
|
||||
return NULL;
|
||||
pn4->pn_type = TOK_LC;
|
||||
|
@ -915,7 +982,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
|
||||
js_PopStatement(tc);
|
||||
|
||||
pn->pn_pos.end = pn2->pn_pos.end = ts->token.pos.end;
|
||||
pn->pn_pos.end = pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
|
||||
pn->pn_kid1 = pn1;
|
||||
pn->pn_kid2 = pn2;
|
||||
return pn;
|
||||
|
@ -923,7 +990,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
#endif /* JS_HAS_SWITCH_STATEMENT */
|
||||
|
||||
case TOK_WHILE:
|
||||
pn = NewParseNode(cx, &ts->token, PN_BINARY);
|
||||
pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
js_PushStatement(tc, &stmtInfo, STMT_WHILE_LOOP, -1);
|
||||
|
@ -941,7 +1008,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
|
||||
#if JS_HAS_DO_WHILE_LOOP
|
||||
case TOK_DO:
|
||||
pn = NewParseNode(cx, &ts->token, PN_BINARY);
|
||||
pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
js_PushStatement(tc, &stmtInfo, STMT_DO_LOOP, -1);
|
||||
|
@ -961,7 +1028,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
|
||||
case TOK_FOR:
|
||||
/* A FOR node is binary, left is loop control and right is the body. */
|
||||
pn = NewParseNode(cx, &ts->token, PN_BINARY);
|
||||
pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
js_PushStatement(tc, &stmtInfo, STMT_FOR_LOOP, -1);
|
||||
|
@ -1044,7 +1111,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
}
|
||||
|
||||
/* Build the RESERVED node to use as the left kid of pn. */
|
||||
pn4 = NewParseNode(cx, &ts->token, PN_TERNARY);
|
||||
pn4 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_TERNARY);
|
||||
if (!pn4)
|
||||
return NULL;
|
||||
pn4->pn_type = TOK_RESERVED;
|
||||
|
@ -1088,7 +1155,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
*
|
||||
* finally nodes are unary (just the finally expression)
|
||||
*/
|
||||
pn = NewParseNode(cx, &ts->token, PN_TERNARY);
|
||||
pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_TERNARY);
|
||||
pn->pn_op = JSOP_NOP;
|
||||
|
||||
MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_TRY);
|
||||
|
@ -1110,14 +1177,14 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
*/
|
||||
|
||||
/* catch node */
|
||||
pn2 = NewParseNode(cx, &ts->token, PN_TERNARY);
|
||||
pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_TERNARY);
|
||||
pn2->pn_op = JSOP_NOP;
|
||||
|
||||
/*
|
||||
* We use a PN_NAME for the discriminant (catchguard) node
|
||||
* with the actual discriminant code in the initializer spot
|
||||
*/
|
||||
pn3 = NewParseNode(cx, &ts->token, PN_NAME);
|
||||
pn3 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NAME);
|
||||
if (!pn2 || !pn3)
|
||||
return NULL;
|
||||
|
||||
|
@ -1125,7 +1192,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
|
||||
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_CATCH);
|
||||
MUST_MATCH_TOKEN(TOK_NAME, JSMSG_CATCH_IDENTIFIER);
|
||||
pn3->pn_atom = ts->token.t_atom;
|
||||
pn3->pn_atom = CURRENT_TOKEN(ts).t_atom;
|
||||
pn3->pn_expr = NULL;
|
||||
#if JS_HAS_CATCH_GUARD
|
||||
if (js_PeekToken(cx, ts) == TOK_COLON) {
|
||||
|
@ -1168,7 +1235,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
return pn;
|
||||
}
|
||||
case TOK_THROW:
|
||||
pn = NewParseNode(cx, &ts->token, PN_UNARY);
|
||||
pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
pn2 = Expr(cx, ts, tc);
|
||||
|
@ -1197,7 +1264,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
#endif /* JS_HAS_EXCEPTIONS */
|
||||
|
||||
case TOK_BREAK:
|
||||
pn = NewParseNode(cx, &ts->token, PN_NULLARY);
|
||||
pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
if (!MatchLabel(cx, ts, pn))
|
||||
|
@ -1226,11 +1293,11 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
}
|
||||
}
|
||||
if (label)
|
||||
pn->pn_pos.end = ts->token.pos.end;
|
||||
pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
|
||||
break;
|
||||
|
||||
case TOK_CONTINUE:
|
||||
pn = NewParseNode(cx, &ts->token, PN_NULLARY);
|
||||
pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
if (!MatchLabel(cx, ts, pn))
|
||||
|
@ -1269,11 +1336,11 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
}
|
||||
}
|
||||
if (label)
|
||||
pn->pn_pos.end = ts->token.pos.end;
|
||||
pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
|
||||
break;
|
||||
|
||||
case TOK_WITH:
|
||||
pn = NewParseNode(cx, &ts->token, PN_BINARY);
|
||||
pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_WITH);
|
||||
|
@ -1311,7 +1378,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
JSMSG_BAD_RETURN);
|
||||
return NULL;
|
||||
}
|
||||
pn = NewParseNode(cx, &ts->token, PN_UNARY);
|
||||
pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
|
||||
|
@ -1360,7 +1427,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
|
||||
case TOK_EOL:
|
||||
case TOK_SEMI:
|
||||
pn = NewParseNode(cx, &ts->token, PN_UNARY);
|
||||
pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
pn->pn_type = TOK_SEMI;
|
||||
|
@ -1371,7 +1438,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
case TOK_DEBUGGER:
|
||||
if(!WellTerminated(cx, ts, TOK_ERROR))
|
||||
return NULL;
|
||||
pn = NewParseNode(cx, &ts->token, PN_NULLARY);
|
||||
pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
pn->pn_type = TOK_DEBUGGER;
|
||||
|
@ -1382,14 +1449,13 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
return NULL;
|
||||
|
||||
default:
|
||||
lastExprType = ts->token.type;
|
||||
lastExprType = CURRENT_TOKEN(ts).type;
|
||||
js_UngetToken(ts);
|
||||
pn2 = Expr(cx, ts, tc);
|
||||
if (!pn2)
|
||||
return NULL;
|
||||
|
||||
tt = ts->pushback.type;
|
||||
if (tt == TOK_COLON) {
|
||||
if (js_PeekToken(cx, ts) == TOK_COLON) {
|
||||
if (pn2->pn_type != TOK_NAME) {
|
||||
js_ReportCompileErrorNumber(cx, ts, JSREPORT_ERROR,
|
||||
JSMSG_BAD_LABEL);
|
||||
|
@ -1403,7 +1469,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
return NULL;
|
||||
}
|
||||
}
|
||||
js_GetToken(cx, ts);
|
||||
(void) js_GetToken(cx, ts);
|
||||
|
||||
/* Push a label struct and parse the statement. */
|
||||
js_PushStatement(tc, &stmtInfo, STMT_LABEL, -1);
|
||||
|
@ -1425,7 +1491,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
!WellTerminated(cx, ts, lastExprType)) {
|
||||
return NULL;
|
||||
}
|
||||
pn = NewParseNode(cx, &ts->token, PN_UNARY);
|
||||
pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
pn->pn_type = TOK_SEMI;
|
||||
|
@ -1462,8 +1528,8 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
* We determine this by looking up the variable id in the
|
||||
* current variable scope.
|
||||
*/
|
||||
JS_ASSERT(ts->token.type == TOK_VAR);
|
||||
pn = NewParseNode(cx, &ts->token, PN_LIST);
|
||||
JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_VAR);
|
||||
pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
pn->pn_op = JSOP_NOP;
|
||||
|
@ -1490,9 +1556,9 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
currentGetter = getter;
|
||||
currentSetter = setter;
|
||||
MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_VARIABLE_NAME);
|
||||
atom = ts->token.t_atom;
|
||||
atom = CURRENT_TOKEN(ts).t_atom;
|
||||
|
||||
pn2 = NewParseNode(cx, &ts->token, PN_NAME);
|
||||
pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NAME);
|
||||
if (!pn2)
|
||||
return NULL;
|
||||
pn2->pn_op = JSOP_NAME;
|
||||
|
@ -1588,7 +1654,7 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
}
|
||||
|
||||
if (js_MatchToken(cx, ts, TOK_ASSIGN)) {
|
||||
if (ts->token.t_op != JSOP_NOP) {
|
||||
if (CURRENT_TOKEN(ts).t_op != JSOP_NOP) {
|
||||
js_ReportCompileErrorNumber(cx, ts,JSREPORT_ERROR,
|
||||
JSMSG_BAD_VAR_INIT);
|
||||
ok = JS_FALSE;
|
||||
|
@ -1642,7 +1708,7 @@ Expr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
|
||||
pn = AssignExpr(cx, ts, tc);
|
||||
if (pn && js_MatchToken(cx, ts, TOK_COMMA)) {
|
||||
pn2 = NewParseNode(cx, &ts->token, PN_LIST);
|
||||
pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST);
|
||||
if (!pn2)
|
||||
return NULL;
|
||||
pn2->pn_pos.begin = pn->pn_pos.begin;
|
||||
|
@ -1699,38 +1765,53 @@ static JSParseNode *
|
|||
AssignExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
{
|
||||
JSParseNode *pn, *pn2;
|
||||
JSTokenType tt;
|
||||
JSOp op;
|
||||
|
||||
pn = CondExpr(cx, ts, tc);
|
||||
if (pn && js_MatchToken(cx, ts, TOK_ASSIGN)) {
|
||||
op = ts->token.t_op;
|
||||
for (pn2 = pn; pn2->pn_type == TOK_RP; pn2 = pn2->pn_kid)
|
||||
;
|
||||
switch (pn2->pn_type) {
|
||||
case TOK_NAME:
|
||||
if (pn2->pn_slot >= 0) {
|
||||
JS_ASSERT(pn2->pn_op == JSOP_GETARG || pn2->pn_op == JSOP_GETVAR);
|
||||
if (pn2->pn_op == JSOP_GETARG)
|
||||
pn2->pn_op = JSOP_SETARG;
|
||||
else
|
||||
pn2->pn_op = JSOP_SETVAR;
|
||||
} else {
|
||||
pn2->pn_op = JSOP_SETNAME2;
|
||||
}
|
||||
break;
|
||||
case TOK_DOT:
|
||||
pn2->pn_op = JSOP_SETPROP;
|
||||
break;
|
||||
case TOK_LB:
|
||||
pn2->pn_op = JSOP_SETELEM;
|
||||
break;
|
||||
default:
|
||||
js_ReportCompileErrorNumber(cx, ts, JSREPORT_ERROR,
|
||||
JSMSG_BAD_LEFTSIDE_OF_ASS);
|
||||
return NULL;
|
||||
}
|
||||
pn = NewBinary(cx, TOK_ASSIGN, op, pn2, AssignExpr(cx, ts, tc));
|
||||
if (!pn)
|
||||
return NULL;
|
||||
|
||||
tt = js_GetToken(cx, ts);
|
||||
#if JS_HAS_GETTER_SETTER
|
||||
if (tt == TOK_NAME) {
|
||||
tt = CheckGetterOrSetter(cx, ts, TOK_ASSIGN);
|
||||
if (tt == TOK_ERROR)
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
if (tt != TOK_ASSIGN) {
|
||||
js_UngetToken(ts);
|
||||
return pn;
|
||||
}
|
||||
|
||||
op = CURRENT_TOKEN(ts).t_op;
|
||||
for (pn2 = pn; pn2->pn_type == TOK_RP; pn2 = pn2->pn_kid)
|
||||
;
|
||||
switch (pn2->pn_type) {
|
||||
case TOK_NAME:
|
||||
if (pn2->pn_slot >= 0) {
|
||||
JS_ASSERT(pn2->pn_op == JSOP_GETARG || pn2->pn_op == JSOP_GETVAR);
|
||||
if (pn2->pn_op == JSOP_GETARG)
|
||||
pn2->pn_op = JSOP_SETARG;
|
||||
else
|
||||
pn2->pn_op = JSOP_SETVAR;
|
||||
} else {
|
||||
pn2->pn_op = JSOP_SETNAME2;
|
||||
}
|
||||
break;
|
||||
case TOK_DOT:
|
||||
pn2->pn_op = JSOP_SETPROP;
|
||||
break;
|
||||
case TOK_LB:
|
||||
pn2->pn_op = JSOP_SETELEM;
|
||||
break;
|
||||
default:
|
||||
js_ReportCompileErrorNumber(cx, ts, JSREPORT_ERROR,
|
||||
JSMSG_BAD_LEFTSIDE_OF_ASS);
|
||||
return NULL;
|
||||
}
|
||||
pn = NewBinary(cx, TOK_ASSIGN, op, pn2, AssignExpr(cx, ts, tc));
|
||||
return pn;
|
||||
}
|
||||
|
||||
|
@ -1745,7 +1826,7 @@ CondExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
pn = OrExpr(cx, ts, tc);
|
||||
if (pn && js_MatchToken(cx, ts, TOK_HOOK)) {
|
||||
pn1 = pn;
|
||||
pn = NewParseNode(cx, &ts->token, PN_TERNARY);
|
||||
pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_TERNARY);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
#if JS_HAS_IN_OPERATOR
|
||||
|
@ -1840,7 +1921,7 @@ EqExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
|
||||
pn = RelExpr(cx, ts, tc);
|
||||
while (pn && js_MatchToken(cx, ts, TOK_EQOP)) {
|
||||
op = ts->token.t_op;
|
||||
op = CURRENT_TOKEN(ts).t_op;
|
||||
pn = NewBinary(cx, TOK_EQOP, op, pn, RelExpr(cx, ts, tc));
|
||||
}
|
||||
return pn;
|
||||
|
@ -1877,8 +1958,8 @@ RelExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
|| js_MatchToken(cx, ts, TOK_INSTANCEOF)
|
||||
#endif /* JS_HAS_INSTANCEOF */
|
||||
)) {
|
||||
tt = ts->token.type;
|
||||
op = ts->token.t_op;
|
||||
tt = CURRENT_TOKEN(ts).type;
|
||||
op = CURRENT_TOKEN(ts).t_op;
|
||||
pn = NewBinary(cx, tt, op, pn, ShiftExpr(cx, ts, tc));
|
||||
}
|
||||
#if JS_HAS_IN_OPERATOR
|
||||
|
@ -1897,7 +1978,7 @@ ShiftExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
|
||||
pn = AddExpr(cx, ts, tc);
|
||||
while (pn && js_MatchToken(cx, ts, TOK_SHOP)) {
|
||||
op = ts->token.t_op;
|
||||
op = CURRENT_TOKEN(ts).t_op;
|
||||
pn = NewBinary(cx, TOK_SHOP, op, pn, AddExpr(cx, ts, tc));
|
||||
}
|
||||
return pn;
|
||||
|
@ -1914,7 +1995,7 @@ AddExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
while (pn &&
|
||||
(js_MatchToken(cx, ts, TOK_PLUS) ||
|
||||
js_MatchToken(cx, ts, TOK_MINUS))) {
|
||||
tt = ts->token.type;
|
||||
tt = CURRENT_TOKEN(ts).type;
|
||||
op = (tt == TOK_PLUS) ? JSOP_ADD : JSOP_SUB;
|
||||
pn = NewBinary(cx, tt, op, pn, MulExpr(cx, ts, tc));
|
||||
}
|
||||
|
@ -1932,8 +2013,8 @@ MulExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
while (pn &&
|
||||
(js_MatchToken(cx, ts, TOK_STAR) ||
|
||||
js_MatchToken(cx, ts, TOK_DIVOP))) {
|
||||
tt = ts->token.type;
|
||||
op = ts->token.t_op;
|
||||
tt = CURRENT_TOKEN(ts).type;
|
||||
op = CURRENT_TOKEN(ts).t_op;
|
||||
pn = NewBinary(cx, tt, op, pn, UnaryExpr(cx, ts, tc));
|
||||
}
|
||||
return pn;
|
||||
|
@ -2023,11 +2104,11 @@ UnaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
case TOK_UNARYOP:
|
||||
case TOK_PLUS:
|
||||
case TOK_MINUS:
|
||||
pn = NewParseNode(cx, &ts->token, PN_UNARY);
|
||||
pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
pn->pn_type = TOK_UNARYOP; /* PLUS and MINUS are binary */
|
||||
pn->pn_op = ts->token.t_op;
|
||||
pn->pn_op = CURRENT_TOKEN(ts).t_op;
|
||||
pn2 = UnaryExpr(cx, ts, tc);
|
||||
if (!pn2)
|
||||
return NULL;
|
||||
|
@ -2037,7 +2118,7 @@ UnaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
|
||||
case TOK_INC:
|
||||
case TOK_DEC:
|
||||
pn = NewParseNode(cx, &ts->token, PN_UNARY);
|
||||
pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
pn2 = MemberExpr(cx, ts, tc, JS_TRUE);
|
||||
|
@ -2049,7 +2130,7 @@ UnaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
break;
|
||||
|
||||
case TOK_DELETE:
|
||||
pn = NewParseNode(cx, &ts->token, PN_UNARY);
|
||||
pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
pn2 = UnaryExpr(cx, ts, tc);
|
||||
|
@ -2074,7 +2155,7 @@ UnaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
tt = js_PeekTokenSameLine(cx, ts);
|
||||
if (tt == TOK_INC || tt == TOK_DEC) {
|
||||
(void) js_GetToken(cx, ts);
|
||||
pn2 = NewParseNode(cx, &ts->token, PN_UNARY);
|
||||
pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY);
|
||||
if (!pn2)
|
||||
return NULL;
|
||||
if (!SetIncOpKid(cx, ts, tc, pn2, pn, tt, JS_FALSE))
|
||||
|
@ -2124,7 +2205,7 @@ MemberExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
|||
if (tt == TOK_NEW) {
|
||||
(void) js_GetToken(cx, ts);
|
||||
|
||||
pn = NewParseNode(cx, &ts->token, PN_LIST);
|
||||
pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
pn2 = MemberExpr(cx, ts, tc, JS_FALSE);
|
||||
|
@ -2151,17 +2232,17 @@ MemberExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
|||
|
||||
while ((tt = js_GetToken(cx, ts)) > TOK_EOF) {
|
||||
if (tt == TOK_DOT) {
|
||||
pn2 = NewParseNode(cx, &ts->token, PN_NAME);
|
||||
pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NAME);
|
||||
if (!pn2)
|
||||
return NULL;
|
||||
MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NAME_AFTER_DOT);
|
||||
pn2->pn_pos.begin = pn->pn_pos.begin;
|
||||
pn2->pn_pos.end = ts->token.pos.end;
|
||||
pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
|
||||
pn2->pn_op = JSOP_GETPROP;
|
||||
pn2->pn_expr = pn;
|
||||
pn2->pn_atom = ts->token.t_atom;
|
||||
pn2->pn_atom = CURRENT_TOKEN(ts).t_atom;
|
||||
} else if (tt == TOK_LB) {
|
||||
pn2 = NewParseNode(cx, &ts->token, PN_BINARY);
|
||||
pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY);
|
||||
if (!pn2)
|
||||
return NULL;
|
||||
pn3 = Expr(cx, ts, tc);
|
||||
|
@ -2170,13 +2251,13 @@ MemberExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
|||
|
||||
MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_IN_INDEX);
|
||||
pn2->pn_pos.begin = pn->pn_pos.begin;
|
||||
pn2->pn_pos.end = ts->token.pos.end;
|
||||
pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
|
||||
|
||||
pn2->pn_op = JSOP_GETELEM;
|
||||
pn2->pn_left = pn;
|
||||
pn2->pn_right = pn3;
|
||||
} else if (allowCallSyntax && tt == TOK_LP) {
|
||||
pn2 = NewParseNode(cx, &ts->token, PN_LIST);
|
||||
pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST);
|
||||
if (!pn2)
|
||||
return NULL;
|
||||
pn2->pn_op = JSOP_CALL;
|
||||
|
@ -2228,6 +2309,14 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
tt = js_GetToken(cx, ts);
|
||||
ts->flags &= ~TSF_REGEXP;
|
||||
|
||||
#if JS_HAS_GETTER_SETTER
|
||||
if (tt == TOK_NAME) {
|
||||
tt = CheckGetterOrSetter(cx, ts, TOK_FUNCTION);
|
||||
if (tt == TOK_ERROR)
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (tt) {
|
||||
#if JS_HAS_LEXICAL_CLOSURE
|
||||
case TOK_FUNCTION:
|
||||
|
@ -2243,7 +2332,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
JSBool matched;
|
||||
jsint atomIndex;
|
||||
|
||||
pn = NewParseNode(cx, &ts->token, PN_LIST);
|
||||
pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
pn->pn_type = TOK_RB;
|
||||
|
@ -2271,7 +2360,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
}
|
||||
|
||||
if (tt == TOK_COMMA)
|
||||
pn2 = NewParseNode(cx, &ts->token, PN_NULLARY);
|
||||
pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY);
|
||||
else
|
||||
pn2 = AssignExpr(cx, ts, tc);
|
||||
if (!pn2)
|
||||
|
@ -2284,12 +2373,12 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
|
||||
MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_AFTER_LIST);
|
||||
}
|
||||
pn->pn_pos.end = ts->token.pos.end;
|
||||
pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
|
||||
return pn;
|
||||
}
|
||||
|
||||
case TOK_LC:
|
||||
pn = NewParseNode(cx, &ts->token, PN_LIST);
|
||||
pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
pn->pn_type = TOK_RC;
|
||||
|
@ -2304,18 +2393,20 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
|
||||
if (!js_MatchToken(cx, ts, TOK_RC)) {
|
||||
do {
|
||||
JSOp op;
|
||||
|
||||
tt = js_GetToken(cx, ts);
|
||||
switch (tt) {
|
||||
case TOK_NUMBER:
|
||||
pn3 = NewParseNode(cx, &ts->token, PN_NULLARY);
|
||||
pn3 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY);
|
||||
if (pn3)
|
||||
pn3->pn_dval = ts->token.t_dval;
|
||||
pn3->pn_dval = CURRENT_TOKEN(ts).t_dval;
|
||||
break;
|
||||
case TOK_NAME:
|
||||
case TOK_STRING:
|
||||
pn3 = NewParseNode(cx, &ts->token, PN_NULLARY);
|
||||
pn3 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY);
|
||||
if (pn3)
|
||||
pn3->pn_atom = ts->token.t_atom;
|
||||
pn3->pn_atom = CURRENT_TOKEN(ts).t_atom;
|
||||
break;
|
||||
case TOK_RC:
|
||||
goto end_obj_init;
|
||||
|
@ -2325,9 +2416,21 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_AFTER_ID);
|
||||
pn2 = NewBinary(cx, TOK_COLON, JSOP_INITPROP, pn3,
|
||||
AssignExpr(cx, ts, tc));
|
||||
tt = js_GetToken(cx, ts);
|
||||
#if JS_HAS_GETTER_SETTER
|
||||
if (tt == TOK_NAME) {
|
||||
tt = CheckGetterOrSetter(cx, ts, TOK_COLON);
|
||||
if (tt == TOK_ERROR)
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
if (tt != TOK_COLON) {
|
||||
js_ReportCompileErrorNumber(cx, ts, JSREPORT_ERROR,
|
||||
JSMSG_COLON_AFTER_ID);
|
||||
return NULL;
|
||||
}
|
||||
op = CURRENT_TOKEN(ts).t_op;
|
||||
pn2 = NewBinary(cx, TOK_COLON, op, pn3, AssignExpr(cx, ts, tc));
|
||||
if (!pn2)
|
||||
return NULL;
|
||||
PN_APPEND(pn, pn2);
|
||||
|
@ -2336,26 +2439,26 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_LIST);
|
||||
}
|
||||
end_obj_init:
|
||||
pn->pn_pos.end = ts->token.pos.end;
|
||||
pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
|
||||
return pn;
|
||||
|
||||
#if JS_HAS_SHARP_VARS
|
||||
case TOK_DEFSHARP:
|
||||
if (defsharp)
|
||||
goto badsharp;
|
||||
defsharp = NewParseNode(cx, &ts->token, PN_UNARY);
|
||||
defsharp = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY);
|
||||
if (!defsharp)
|
||||
return NULL;
|
||||
defsharp->pn_num = (jsint) ts->token.t_dval;
|
||||
defsharp->pn_num = (jsint) CURRENT_TOKEN(ts).t_dval;
|
||||
defsharp->pn_kid = NULL;
|
||||
goto again;
|
||||
|
||||
case TOK_USESHARP:
|
||||
/* Check for forward/dangling references at runtime, to allow eval. */
|
||||
pn = NewParseNode(cx, &ts->token, PN_NULLARY);
|
||||
pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
pn->pn_num = (jsint) ts->token.t_dval;
|
||||
pn->pn_num = (jsint) CURRENT_TOKEN(ts).t_dval;
|
||||
notsharp = JS_TRUE;
|
||||
break;
|
||||
#endif /* JS_HAS_SHARP_VARS */
|
||||
|
@ -2366,7 +2469,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
#if JS_HAS_IN_OPERATOR
|
||||
uintN oldflags;
|
||||
#endif
|
||||
pn = NewParseNode(cx, &ts->token, PN_UNARY);
|
||||
pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
#if JS_HAS_IN_OPERATOR
|
||||
|
@ -2387,7 +2490,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
|
||||
MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_IN_PAREN);
|
||||
pn->pn_type = TOK_RP;
|
||||
pn->pn_pos.end = ts->token.pos.end;
|
||||
pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
|
||||
pn->pn_kid = pn2;
|
||||
break;
|
||||
}
|
||||
|
@ -2399,11 +2502,11 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
/* FALL THROUGH */
|
||||
case TOK_NAME:
|
||||
case TOK_OBJECT:
|
||||
pn = NewParseNode(cx, &ts->token, PN_NULLARY);
|
||||
pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
pn->pn_op = ts->token.t_op;
|
||||
pn->pn_atom = ts->token.t_atom;
|
||||
pn->pn_op = CURRENT_TOKEN(ts).t_op;
|
||||
pn->pn_atom = CURRENT_TOKEN(ts).t_atom;
|
||||
pn->pn_slot = -1;
|
||||
if (tt == TOK_NAME) {
|
||||
if (!LookupArgOrVar(cx, pn->pn_atom, tc, &pn->pn_op, &pn->pn_slot))
|
||||
|
@ -2414,20 +2517,20 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
break;
|
||||
|
||||
case TOK_NUMBER:
|
||||
pn = NewParseNode(cx, &ts->token, PN_NULLARY);
|
||||
pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
pn->pn_dval = ts->token.t_dval;
|
||||
pn->pn_dval = CURRENT_TOKEN(ts).t_dval;
|
||||
#if JS_HAS_SHARP_VARS
|
||||
notsharp = JS_TRUE;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case TOK_PRIMARY:
|
||||
pn = NewParseNode(cx, &ts->token, PN_NULLARY);
|
||||
pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
pn->pn_op = ts->token.t_op;
|
||||
pn->pn_op = CURRENT_TOKEN(ts).t_op;
|
||||
#if JS_HAS_SHARP_VARS
|
||||
notsharp = JS_TRUE;
|
||||
#endif
|
||||
|
@ -2438,10 +2541,11 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
case TOK_IMPORT:
|
||||
#endif
|
||||
case TOK_RESERVED:
|
||||
badWord = js_DeflateString(cx, ts->token.ptr,
|
||||
(size_t) ts->token.pos.end.index - ts->token.pos.begin.index);
|
||||
js_ReportCompileErrorNumber(cx, ts, JSREPORT_ERROR,
|
||||
JSMSG_RESERVED_ID, badWord);
|
||||
badWord = js_DeflateString(cx, CURRENT_TOKEN(ts).ptr,
|
||||
(size_t) CURRENT_TOKEN(ts).pos.end.index
|
||||
- CURRENT_TOKEN(ts).pos.begin.index);
|
||||
js_ReportCompileErrorNumber(cx, ts, JSREPORT_ERROR, JSMSG_RESERVED_ID,
|
||||
badWord);
|
||||
JS_free(cx, badWord);
|
||||
return NULL;
|
||||
|
||||
|
|
|
@ -86,6 +86,7 @@ JS_BEGIN_EXTERN_C
|
|||
* <Expressions>
|
||||
* TOK_COMMA list pn_head: list of pn_count comma-separated exprs
|
||||
* TOK_ASSIGN binary pn_left: lvalue, pn_right: rvalue
|
||||
* pn_op: JSOP_ADD for +=, etc.
|
||||
* TOK_HOOK ternary pn_kid1: cond, pn_kid2: then, pn_kid3: else
|
||||
* TOK_OR binary pn_left: first in || chain, pn_right: rest of chain
|
||||
* TOK_AND binary pn_left: first in && chain, pn_right: rest of chain
|
||||
|
|
|
@ -41,6 +41,7 @@ typedef enum JSVersion {
|
|||
JSVERSION_1_2 = 120,
|
||||
JSVERSION_1_3 = 130,
|
||||
JSVERSION_1_4 = 140,
|
||||
JSVERSION_1_5 = 150,
|
||||
JSVERSION_DEFAULT = 0,
|
||||
JSVERSION_UNKNOWN = -1
|
||||
} JSVersion;
|
||||
|
|
156
js/src/jsscan.c
156
js/src/jsscan.c
|
@ -64,7 +64,7 @@ static struct keyword {
|
|||
{"export", TOK_EXPORT, JSOP_NOP, JSVERSION_1_2},
|
||||
{js_false_str, TOK_PRIMARY, JSOP_FALSE},
|
||||
{"for", TOK_FOR, JSOP_NOP},
|
||||
{"function", TOK_FUNCTION, JSOP_NOP},
|
||||
{js_function_str, TOK_FUNCTION, JSOP_NOP},
|
||||
{"if", TOK_IF, JSOP_NOP},
|
||||
{js_in_str, TOK_IN, JSOP_IN},
|
||||
{js_new_str, TOK_NEW, JSOP_NEW},
|
||||
|
@ -92,9 +92,9 @@ static struct keyword {
|
|||
#endif
|
||||
|
||||
#if JS_HAS_INSTANCEOF
|
||||
{js_instanceof_str, TOK_INSTANCEOF, JSOP_INSTANCEOF},
|
||||
{js_instanceof_str, TOK_INSTANCEOF, JSOP_INSTANCEOF,JSVERSION_1_4},
|
||||
#else
|
||||
{js_instanceof_str, TOK_RESERVED, JSOP_NOP},
|
||||
{js_instanceof_str, TOK_RESERVED, JSOP_NOP, JSVERSION_1_4},
|
||||
#endif
|
||||
|
||||
#ifdef RESERVE_JAVA_KEYWORDS
|
||||
|
@ -133,7 +133,7 @@ static struct keyword {
|
|||
#endif
|
||||
|
||||
#if JS_HAS_DEBUGGER_KEYWORD
|
||||
{"debugger", TOK_DEBUGGER, JSOP_NOP}, /* XXX version? */
|
||||
{"debugger", TOK_DEBUGGER, JSOP_NOP, JSVERSION_1_3},
|
||||
#elif defined(RESERVE_ECMA_KEYWORDS)
|
||||
{"debugger", TOK_RESERVED, JSOP_NOP, JSVERSION_1_3},
|
||||
#endif
|
||||
|
@ -150,8 +150,10 @@ js_InitScanner(JSContext *cx)
|
|||
atom = js_Atomize(cx, kw->name, strlen(kw->name), ATOM_PINNED);
|
||||
if (!atom)
|
||||
return JS_FALSE;
|
||||
atom->kwindex = (JSVERSION_IS_ECMA(cx->version)
|
||||
|| kw->version <= cx->version) ? kw - keywords : -1;
|
||||
atom->kwindex = (JSVERSION_IS_ECMA(cx->version) ||
|
||||
kw->version <= cx->version)
|
||||
? kw - keywords
|
||||
: -1;
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
@ -196,7 +198,6 @@ js_NewBufferTokenStream(JSContext *cx, const jschar *base, size_t length)
|
|||
return NULL;
|
||||
}
|
||||
memset(ts, 0, nb);
|
||||
CLEAR_PUSHBACK(ts);
|
||||
ts->lineno = 1;
|
||||
ts->linebuf.base = ts->linebuf.limit = ts->linebuf.ptr = (jschar *)(ts + 1);
|
||||
ts->userbuf.base = (jschar *)base;
|
||||
|
@ -448,6 +449,7 @@ js_ReportCompileError(JSContext *cx, JSTokenStream *ts, uintN flags,
|
|||
jschar *limit, lastc;
|
||||
JSErrorReporter onError;
|
||||
JSErrorReport report;
|
||||
jschar *tokenptr;
|
||||
JSString *linestr;
|
||||
|
||||
va_start(ap, format);
|
||||
|
@ -471,11 +473,12 @@ js_ReportCompileError(JSContext *cx, JSTokenStream *ts, uintN flags,
|
|||
report.linebuf = linestr
|
||||
? JS_GetStringBytes(linestr)
|
||||
: NULL;
|
||||
tokenptr = CURRENT_TOKEN(ts).ptr;
|
||||
report.tokenptr = linestr
|
||||
? report.linebuf + (ts->token.ptr - ts->linebuf.base)
|
||||
? report.linebuf + (tokenptr - ts->linebuf.base)
|
||||
: NULL;
|
||||
report.uclinebuf = ts->linebuf.base;
|
||||
report.uctokenptr = ts->token.ptr;
|
||||
report.uctokenptr = tokenptr;
|
||||
report.flags = flags;
|
||||
report.errorNumber = 0;
|
||||
|
||||
|
@ -505,6 +508,7 @@ js_ReportCompileErrorNumber(JSContext *cx, JSTokenStream *ts, uintN flags,
|
|||
jschar *limit, lastc;
|
||||
JSErrorReporter onError;
|
||||
JSErrorReport report;
|
||||
jschar *tokenptr;
|
||||
JSString *linestr;
|
||||
char *message;
|
||||
|
||||
|
@ -533,11 +537,13 @@ js_ReportCompileErrorNumber(JSContext *cx, JSTokenStream *ts, uintN flags,
|
|||
report.linebuf = linestr
|
||||
? JS_GetStringBytes(linestr)
|
||||
: NULL;
|
||||
/* XXXbe this whole fn duplicates a lot of JS_ReportCompileError... */
|
||||
tokenptr = CURRENT_TOKEN(ts).ptr;
|
||||
report.tokenptr = linestr
|
||||
? report.linebuf + (ts->token.ptr - ts->linebuf.base)
|
||||
? report.linebuf + (tokenptr - ts->linebuf.base)
|
||||
: NULL;
|
||||
report.uclinebuf = ts->linebuf.base;
|
||||
report.uctokenptr = ts->token.ptr;
|
||||
report.uctokenptr = tokenptr;
|
||||
report.flags = flags;
|
||||
|
||||
#if JS_HAS_ERROR_EXCEPTIONS
|
||||
|
@ -548,7 +554,7 @@ js_ReportCompileErrorNumber(JSContext *cx, JSTokenStream *ts, uintN flags,
|
|||
* exception is thrown, then the JSREPORT_EXCEPTION flag will be set in
|
||||
* report.flags. Proper behavior for error reporters is probably to
|
||||
* ignore this for all but toplevel compilation errors.
|
||||
|
||||
*
|
||||
* XXX it'd probably be best if there was only one call to this
|
||||
* function, but there seem to be two error reporter call points.
|
||||
*/
|
||||
|
@ -558,10 +564,10 @@ js_ReportCompileErrorNumber(JSContext *cx, JSTokenStream *ts, uintN flags,
|
|||
* otherwise the exception will describe only the last compile error,
|
||||
* which is likely spurious.
|
||||
*/
|
||||
if (!(ts->flags & TSF_BADCOMPILE))
|
||||
if (js_ErrorToException(cx, message, &report)) {
|
||||
if (!(ts->flags & TSF_BADCOMPILE)) {
|
||||
if (js_ErrorToException(cx, message, &report))
|
||||
ts->flags |= TSF_BADCOMPILE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Suppress any compiletime errors that don't occur at the top level.
|
||||
|
@ -597,14 +603,16 @@ js_ReportCompileErrorNumber(JSContext *cx, JSTokenStream *ts, uintN flags,
|
|||
}
|
||||
if (lastc == '\n')
|
||||
limit[-1] = lastc;
|
||||
if (message) JS_free(cx, message);
|
||||
if (message)
|
||||
JS_free(cx, message);
|
||||
if (report.messageArgs) {
|
||||
int i = 0;
|
||||
while (report.messageArgs[i])
|
||||
while (report.messageArgs[i])
|
||||
JS_free(cx, (void *)report.messageArgs[i++]);
|
||||
JS_free(cx, (void *)report.messageArgs);
|
||||
}
|
||||
if (report.ucmessage) JS_free(cx, (void *)report.ucmessage);
|
||||
if (report.ucmessage)
|
||||
JS_free(cx, (void *)report.ucmessage);
|
||||
}
|
||||
|
||||
JSTokenType
|
||||
|
@ -612,8 +620,9 @@ js_PeekToken(JSContext *cx, JSTokenStream *ts)
|
|||
{
|
||||
JSTokenType tt;
|
||||
|
||||
tt = ts->pushback.type;
|
||||
if (tt == TOK_EOF) {
|
||||
if (ts->lookahead != 0) {
|
||||
tt = ts->tokens[(ts->cursor + ts->lookahead) & NTOKENS_MASK].type;
|
||||
} else {
|
||||
tt = js_GetToken(cx, ts);
|
||||
js_UngetToken(ts);
|
||||
}
|
||||
|
@ -625,9 +634,11 @@ js_PeekTokenSameLine(JSContext *cx, JSTokenStream *ts)
|
|||
{
|
||||
JSTokenType tt;
|
||||
|
||||
SCAN_NEWLINES(ts);
|
||||
JS_ASSERT(ts->lookahead == 0 ||
|
||||
CURRENT_TOKEN(ts).pos.begin.lineno == ts->lineno);
|
||||
ts->flags |= TSF_NEWLINES;
|
||||
tt = js_PeekToken(cx, ts);
|
||||
HIDE_NEWLINES(ts);
|
||||
ts->flags &= ~TSF_NEWLINES;
|
||||
return tt;
|
||||
}
|
||||
|
||||
|
@ -674,6 +685,8 @@ AddToTokenBuf(JSContext *cx, JSTokenBuf *tb, jschar c)
|
|||
JSTokenType
|
||||
js_GetToken(JSContext *cx, JSTokenStream *ts)
|
||||
{
|
||||
JSTokenType tt;
|
||||
JSToken *tp;
|
||||
int32 c;
|
||||
JSAtom *atom;
|
||||
|
||||
|
@ -681,20 +694,22 @@ js_GetToken(JSContext *cx, JSTokenStream *ts)
|
|||
#define FINISH_TOKENBUF(tb) if (!AddToTokenBuf(cx, tb, 0)) RETURN(TOK_ERROR)
|
||||
#define TOKEN_LENGTH(tb) ((tb)->ptr - (tb)->base - 1)
|
||||
#define RETURN(tt) { if (tt == TOK_ERROR) ts->flags |= TSF_ERROR; \
|
||||
ts->token.pos.end.index = ts->linepos + \
|
||||
tp->pos.end.index = ts->linepos + \
|
||||
(ts->linebuf.ptr - ts->linebuf.base) - \
|
||||
ts->ungetpos; \
|
||||
return (ts->token.type = tt); }
|
||||
return (tp->type = tt); }
|
||||
|
||||
/* If there was a fatal error, keep returning TOK_ERROR. */
|
||||
if (ts->flags & TSF_ERROR)
|
||||
return TOK_ERROR;
|
||||
|
||||
/* Check for a pushed-back token resulting from mismatching lookahead. */
|
||||
if (ts->pushback.type != TOK_EOF) {
|
||||
ts->token = ts->pushback;
|
||||
CLEAR_PUSHBACK(ts);
|
||||
return ts->token.type;
|
||||
while (ts->lookahead != 0) {
|
||||
ts->lookahead--;
|
||||
ts->cursor = (ts->cursor + 1) & NTOKENS_MASK;
|
||||
tt = CURRENT_TOKEN(ts).type;
|
||||
if (tt != TOK_EOL || (ts->flags & TSF_NEWLINES))
|
||||
return tt;
|
||||
}
|
||||
|
||||
retry:
|
||||
|
@ -704,9 +719,11 @@ retry:
|
|||
break;
|
||||
} while (JS_ISSPACE(c));
|
||||
|
||||
ts->token.ptr = ts->linebuf.ptr - 1;
|
||||
ts->token.pos.begin.index = ts->linepos + (ts->token.ptr-ts->linebuf.base);
|
||||
ts->token.pos.begin.lineno = ts->token.pos.end.lineno = ts->lineno;
|
||||
ts->cursor = (ts->cursor + 1) & NTOKENS_MASK;
|
||||
tp = &CURRENT_TOKEN(ts);
|
||||
tp->ptr = ts->linebuf.ptr - 1;
|
||||
tp->pos.begin.index = ts->linepos + (tp->ptr - ts->linebuf.base);
|
||||
tp->pos.begin.lineno = tp->pos.end.lineno = ts->lineno;
|
||||
|
||||
if (c == EOF)
|
||||
RETURN(TOK_EOF);
|
||||
|
@ -731,11 +748,11 @@ retry:
|
|||
struct keyword *kw;
|
||||
|
||||
kw = &keywords[atom->kwindex];
|
||||
ts->token.t_op = (JSOp) kw->op;
|
||||
tp->t_op = (JSOp) kw->op;
|
||||
RETURN(kw->tokentype);
|
||||
}
|
||||
ts->token.t_op = JSOP_NAME;
|
||||
ts->token.t_atom = atom;
|
||||
tp->t_op = JSOP_NAME;
|
||||
tp->t_atom = atom;
|
||||
RETURN(TOK_NAME);
|
||||
}
|
||||
|
||||
|
@ -827,7 +844,7 @@ retry:
|
|||
RETURN(TOK_ERROR);
|
||||
}
|
||||
}
|
||||
ts->token.t_dval = dval;
|
||||
tp->t_dval = dval;
|
||||
RETURN(TOK_NUMBER);
|
||||
}
|
||||
|
||||
|
@ -901,9 +918,9 @@ retry:
|
|||
0);
|
||||
if (!atom)
|
||||
RETURN(TOK_ERROR);
|
||||
ts->token.pos.end.lineno = ts->lineno;
|
||||
ts->token.t_op = JSOP_STRING;
|
||||
ts->token.t_atom = atom;
|
||||
tp->pos.end.lineno = ts->lineno;
|
||||
tp->t_op = JSOP_STRING;
|
||||
tp->t_atom = atom;
|
||||
RETURN(TOK_STRING);
|
||||
}
|
||||
|
||||
|
@ -919,13 +936,21 @@ retry:
|
|||
case ')': c = TOK_RP; break;
|
||||
case ',': c = TOK_COMMA; break;
|
||||
case '?': c = TOK_HOOK; break;
|
||||
case ':': c = TOK_COLON; break;
|
||||
|
||||
case ':':
|
||||
/*
|
||||
* Default so compiler can modify to JSOP_GETTER if 'p getter: v' in an
|
||||
* object initializer, likewise for setter.
|
||||
*/
|
||||
tp->t_op = JSOP_NOP;
|
||||
c = TOK_COLON;
|
||||
break;
|
||||
|
||||
case '|':
|
||||
if (MatchChar(ts, c)) {
|
||||
c = TOK_OR;
|
||||
} else if (MatchChar(ts, '=')) {
|
||||
ts->token.t_op = JSOP_BITOR;
|
||||
tp->t_op = JSOP_BITOR;
|
||||
c = TOK_ASSIGN;
|
||||
} else {
|
||||
c = TOK_BITOR;
|
||||
|
@ -934,7 +959,7 @@ retry:
|
|||
|
||||
case '^':
|
||||
if (MatchChar(ts, '=')) {
|
||||
ts->token.t_op = JSOP_BITXOR;
|
||||
tp->t_op = JSOP_BITXOR;
|
||||
c = TOK_ASSIGN;
|
||||
} else {
|
||||
c = TOK_BITXOR;
|
||||
|
@ -945,7 +970,7 @@ retry:
|
|||
if (MatchChar(ts, c)) {
|
||||
c = TOK_AND;
|
||||
} else if (MatchChar(ts, '=')) {
|
||||
ts->token.t_op = JSOP_BITAND;
|
||||
tp->t_op = JSOP_BITAND;
|
||||
c = TOK_ASSIGN;
|
||||
} else {
|
||||
c = TOK_BITAND;
|
||||
|
@ -955,13 +980,13 @@ retry:
|
|||
case '=':
|
||||
if (MatchChar(ts, c)) {
|
||||
#if JS_HAS_TRIPLE_EQOPS
|
||||
ts->token.t_op = MatchChar(ts, c) ? JSOP_NEW_EQ : (JSOp)cx->jsop_eq;
|
||||
tp->t_op = MatchChar(ts, c) ? JSOP_NEW_EQ : (JSOp)cx->jsop_eq;
|
||||
#else
|
||||
ts->token.t_op = cx->jsop_eq;
|
||||
tp->t_op = cx->jsop_eq;
|
||||
#endif
|
||||
c = TOK_EQOP;
|
||||
} else {
|
||||
ts->token.t_op = JSOP_NOP;
|
||||
tp->t_op = JSOP_NOP;
|
||||
c = TOK_ASSIGN;
|
||||
}
|
||||
break;
|
||||
|
@ -969,13 +994,13 @@ retry:
|
|||
case '!':
|
||||
if (MatchChar(ts, '=')) {
|
||||
#if JS_HAS_TRIPLE_EQOPS
|
||||
ts->token.t_op = MatchChar(ts, '=') ? JSOP_NEW_NE : (JSOp)cx->jsop_ne;
|
||||
tp->t_op = MatchChar(ts, '=') ? JSOP_NEW_NE : (JSOp)cx->jsop_ne;
|
||||
#else
|
||||
ts->token.t_op = cx->jsop_ne;
|
||||
tp->t_op = cx->jsop_ne;
|
||||
#endif
|
||||
c = TOK_EQOP;
|
||||
} else {
|
||||
ts->token.t_op = JSOP_NOT;
|
||||
tp->t_op = JSOP_NOT;
|
||||
c = TOK_UNARYOP;
|
||||
}
|
||||
break;
|
||||
|
@ -991,26 +1016,26 @@ retry:
|
|||
UngetChar(ts, '!');
|
||||
}
|
||||
if (MatchChar(ts, c)) {
|
||||
ts->token.t_op = JSOP_LSH;
|
||||
tp->t_op = JSOP_LSH;
|
||||
c = MatchChar(ts, '=') ? TOK_ASSIGN : TOK_SHOP;
|
||||
} else {
|
||||
ts->token.t_op = MatchChar(ts, '=') ? JSOP_LE : JSOP_LT;
|
||||
tp->t_op = MatchChar(ts, '=') ? JSOP_LE : JSOP_LT;
|
||||
c = TOK_RELOP;
|
||||
}
|
||||
break;
|
||||
|
||||
case '>':
|
||||
if (MatchChar(ts, c)) {
|
||||
ts->token.t_op = MatchChar(ts, c) ? JSOP_URSH : JSOP_RSH;
|
||||
tp->t_op = MatchChar(ts, c) ? JSOP_URSH : JSOP_RSH;
|
||||
c = MatchChar(ts, '=') ? TOK_ASSIGN : TOK_SHOP;
|
||||
} else {
|
||||
ts->token.t_op = MatchChar(ts, '=') ? JSOP_GE : JSOP_GT;
|
||||
tp->t_op = MatchChar(ts, '=') ? JSOP_GE : JSOP_GT;
|
||||
c = TOK_RELOP;
|
||||
}
|
||||
break;
|
||||
|
||||
case '*':
|
||||
ts->token.t_op = JSOP_MUL;
|
||||
tp->t_op = JSOP_MUL;
|
||||
c = MatchChar(ts, '=') ? TOK_ASSIGN : TOK_STAR;
|
||||
break;
|
||||
|
||||
|
@ -1074,7 +1099,7 @@ skipline:
|
|||
}
|
||||
c = PeekChar(ts);
|
||||
if (JS7_ISLET(c)) {
|
||||
ts->token.ptr = ts->linebuf.ptr - 1;
|
||||
tp->ptr = ts->linebuf.ptr - 1;
|
||||
js_ReportCompileErrorNumber(cx, ts,JSREPORT_ERROR,
|
||||
JSMSG_BAD_REGEXP_FLAG);
|
||||
(void) GetChar(ts);
|
||||
|
@ -1089,38 +1114,38 @@ skipline:
|
|||
atom = js_AtomizeObject(cx, obj, 0);
|
||||
if (!atom)
|
||||
RETURN(TOK_ERROR);
|
||||
ts->token.t_op = JSOP_OBJECT;
|
||||
ts->token.t_atom = atom;
|
||||
tp->t_op = JSOP_OBJECT;
|
||||
tp->t_atom = atom;
|
||||
RETURN(TOK_OBJECT);
|
||||
}
|
||||
#endif /* JS_HAS_REGEXPS */
|
||||
|
||||
ts->token.t_op = JSOP_DIV;
|
||||
tp->t_op = JSOP_DIV;
|
||||
c = MatchChar(ts, '=') ? TOK_ASSIGN : TOK_DIVOP;
|
||||
break;
|
||||
|
||||
case '%':
|
||||
ts->token.t_op = JSOP_MOD;
|
||||
tp->t_op = JSOP_MOD;
|
||||
c = MatchChar(ts, '=') ? TOK_ASSIGN : TOK_DIVOP;
|
||||
break;
|
||||
|
||||
case '~':
|
||||
ts->token.t_op = JSOP_BITNOT;
|
||||
tp->t_op = JSOP_BITNOT;
|
||||
c = TOK_UNARYOP;
|
||||
break;
|
||||
|
||||
case '+':
|
||||
case '-':
|
||||
if (MatchChar(ts, '=')) {
|
||||
ts->token.t_op = (c == '+') ? JSOP_ADD : JSOP_SUB;
|
||||
tp->t_op = (c == '+') ? JSOP_ADD : JSOP_SUB;
|
||||
c = TOK_ASSIGN;
|
||||
} else if (MatchChar(ts, c)) {
|
||||
c = (c == '+') ? TOK_INC : TOK_DEC;
|
||||
} else if (c == '-') {
|
||||
ts->token.t_op = JSOP_NEG;
|
||||
tp->t_op = JSOP_NEG;
|
||||
c = TOK_MINUS;
|
||||
} else {
|
||||
ts->token.t_op = JSOP_POS;
|
||||
tp->t_op = JSOP_POS;
|
||||
c = TOK_PLUS;
|
||||
}
|
||||
break;
|
||||
|
@ -1147,7 +1172,7 @@ skipline:
|
|||
RETURN(TOK_ERROR);
|
||||
}
|
||||
}
|
||||
ts->token.t_dval = (jsdouble) n;
|
||||
tp->t_dval = (jsdouble) n;
|
||||
if (c == '=')
|
||||
RETURN(TOK_DEFSHARP);
|
||||
if (c == '#')
|
||||
|
@ -1176,10 +1201,11 @@ skipline:
|
|||
void
|
||||
js_UngetToken(JSTokenStream *ts)
|
||||
{
|
||||
JS_ASSERT(ts->pushback.type == TOK_EOF);
|
||||
JS_ASSERT(ts->lookahead < NTOKENS_MASK);
|
||||
if (ts->flags & TSF_ERROR)
|
||||
return;
|
||||
ts->pushback = ts->token;
|
||||
ts->lookahead++;
|
||||
ts->cursor = (ts->cursor - 1) & NTOKENS_MASK;
|
||||
}
|
||||
|
||||
JSBool
|
||||
|
|
|
@ -128,10 +128,13 @@ typedef struct JSTokenBuf {
|
|||
|
||||
#define JS_LINE_LIMIT 256 /* logical line buffer size limit --
|
||||
physical line length is unlimited */
|
||||
#define NTOKENS 4 /* 1 current + 2 lookahead, rounded */
|
||||
#define NTOKENS_MASK (NTOKENS-1) /* to power of 2 to avoid divmod by 3 */
|
||||
|
||||
struct JSTokenStream {
|
||||
JSToken token; /* last token scanned */
|
||||
JSToken pushback; /* pushed-back already-scanned token */
|
||||
JSToken tokens[NTOKENS];/* circular token buffer */
|
||||
uintN cursor; /* index of last parsed token */
|
||||
uintN lookahead; /* count of lookahead tokens */
|
||||
uintN lineno; /* current line number */
|
||||
uintN ungetpos; /* next free char slot in ungetbuf */
|
||||
jschar ungetbuf[4]; /* at most 4, for \uXXXX lookahead */
|
||||
|
@ -143,12 +146,14 @@ struct JSTokenStream {
|
|||
JSTokenBuf tokenbuf; /* current token string buffer */
|
||||
const char *filename; /* input filename or null */
|
||||
FILE *file; /* stdio stream if reading from file */
|
||||
JSPrincipals *principals; /* principals associated with given input */
|
||||
JSPrincipals *principals; /* principals associated with source */
|
||||
JSSourceHandler listener; /* callback for source; eg debugger */
|
||||
void *listenerData; /* listener 'this' data */
|
||||
void *listenerTSData;/* listener data for this TokenStream */
|
||||
};
|
||||
|
||||
#define CURRENT_TOKEN(ts) ((ts)->tokens[(ts)->cursor])
|
||||
|
||||
/* JSTokenStream flags */
|
||||
#define TSF_ERROR 0x01 /* fatal error while scanning */
|
||||
#define TSF_EOF 0x02 /* hit end of file */
|
||||
|
@ -156,25 +161,7 @@ struct JSTokenStream {
|
|||
#define TSF_REGEXP 0x08 /* looking for a regular expression */
|
||||
#define TSF_NLFLAG 0x20 /* last linebuf ended with \n */
|
||||
#define TSF_CRFLAG 0x40 /* linebuf would have ended with \r */
|
||||
#define TSF_BADCOMPILE 0x80 /* compile failed, stop throwing exns */
|
||||
|
||||
/*
|
||||
* At most one non-EOF token can be pushed back onto a TokenStream between
|
||||
* Get or successful Match operations. These macros manipulate the pushback
|
||||
* token to clear it when changing scanning modes (upon initialzation, after
|
||||
* errors, or between newline-sensitive and insensitive states).
|
||||
*/
|
||||
#define CLEAR_PUSHBACK(ts) ((ts)->pushback.type = TOK_EOF)
|
||||
#define SCAN_NEWLINES(ts) ((ts)->flags |= TSF_NEWLINES)
|
||||
#define HIDE_NEWLINES(ts) \
|
||||
JS_BEGIN_MACRO \
|
||||
(ts)->flags &= ~TSF_NEWLINES; \
|
||||
if ((ts)->pushback.type == TOK_EOL) \
|
||||
(ts)->pushback.type = TOK_EOF; \
|
||||
JS_END_MACRO
|
||||
|
||||
/* Clear ts member that might point above a released cx->tempPool mark. */
|
||||
#define RESET_TOKENBUF(ts) ((ts)->tokenbuf.base = (ts)->tokenbuf.limit = NULL)
|
||||
#define TSF_BADCOMPILE 0x80 /* compile failed, stop throwing exns */
|
||||
|
||||
/*
|
||||
* Create a new token stream, either from an input buffer or from a file.
|
||||
|
|
|
@ -82,8 +82,15 @@ struct JSScopeProperty {
|
|||
* setter might be stored apart from sprop -- say in scope->opTable[i] for
|
||||
* a compressed getter or setter index i that is stored in sprop).
|
||||
*/
|
||||
#define SPROP_GET(cx,sprop,obj,obj2,vp) ((sprop)->getter(cx,OBJ_THIS_OBJECT(cx,obj),sprop->id,vp))
|
||||
#define SPROP_SET(cx,sprop,obj,obj2,vp) ((sprop)->setter(cx,OBJ_THIS_OBJECT(cx,obj),sprop->id,vp))
|
||||
#define SPROP_GET(cx,sprop,obj,obj2,vp) \
|
||||
(((sprop)->attrs & JSPROP_GETTER) \
|
||||
? js_InternalCall(cx, obj, OBJECT_TO_JSVAL(sprop->getter), 0, 0, vp) \
|
||||
: (sprop)->getter(cx, OBJ_THIS_OBJECT(cx,obj), sprop->id, vp))
|
||||
|
||||
#define SPROP_SET(cx,sprop,obj,obj2,vp) \
|
||||
(((sprop)->attrs & JSPROP_SETTER) \
|
||||
? js_InternalCall(cx, obj, OBJECT_TO_JSVAL(sprop->setter), 1, vp, vp) \
|
||||
: (sprop)->setter(cx, OBJ_THIS_OBJECT(cx,obj), sprop->id, vp))
|
||||
|
||||
extern JSScope *
|
||||
js_GetMutableScope(JSContext *cx, JSObject *obj);
|
||||
|
|
Загрузка…
Ссылка в новой задаче